diff --git a/.clang-format b/.clang-format index da3eac14489b1..efda3f8673147 100644 --- a/.clang-format +++ b/.clang-format @@ -7,6 +7,9 @@ BasedOnStyle: Google ColumnLimit: 0 SortIncludes: false DerivePointerAlignment: false +# Avoid adding spaces between tokens in GSL_SUPPRESS arguments. +# E.g., don't change "GSL_SUPPRESS(r.11)" to "GSL_SUPPRESS(r .11)". +WhitespaceSensitiveMacros: ["GSL_SUPPRESS"] # if you want to customize when working locally see https://clang.llvm.org/docs/ClangFormatStyleOptions.html for options. # See ReformatSource.ps1 for a script to update all source according to the current options in this file. diff --git a/.gdn/.gdntsa b/.gdn/.gdntsa index 2992cab431757..e49848d116d90 100644 --- a/.gdn/.gdntsa +++ b/.gdn/.gdntsa @@ -1,3 +1,3 @@ { - "codebaseName": "onnxruntime_master" + "codebaseName": "onnxruntime_main" } \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/04-web.yml b/.github/ISSUE_TEMPLATE/04-web.yml index 15919a5983637..d84226ff5bfe1 100644 --- a/.github/ISSUE_TEMPLATE/04-web.yml +++ b/.github/ISSUE_TEMPLATE/04-web.yml @@ -55,8 +55,10 @@ body: attributes: label: Execution Provider options: - - WebGL - - WASM + - "'webgl' (WebGL)" + - "'wasm'/'cpu' (WebAssembly CPU)" + - "'xnnpack' (WebAssembly XNNPACK)" + - "'webgpu' (WebGPU)" - Other / Unknown multiple: yes validations: diff --git a/.github/workflows/cffconvert.yml b/.github/workflows/cffconvert.yml index 707a71c4b20fe..7144363717749 100644 --- a/.github/workflows/cffconvert.yml +++ b/.github/workflows/cffconvert.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out a copy of the repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Check whether the citation metadata from CITATION.cff is valid uses: citation-file-format/cffconvert-github-action@2.0.0 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 2fe66013ebbbc..d3ecf44fe5733 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -33,7 +33,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml index 07346b38b2151..03ea773a25130 100644 --- a/.github/workflows/gradle-wrapper-validation.yml +++ b/.github/workflows/gradle-wrapper-validation.yml @@ -10,5 +10,5 @@ jobs: name: "Validation" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: gradle/wrapper-validation-action@v1 diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index d1ba497f856b0..4a4e286071ff5 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -7,7 +7,7 @@ jobs: triage: runs-on: ubuntu-latest steps: - - uses: github/issue-labeler@v2.5 + - uses: github/issue-labeler@v3.2 with: repo-token: "${{ secrets.GITHUB_TOKEN }}" configuration-path: .github/labeler.yml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 83d2a4bfd69c9..432c789e943b5 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -3,8 +3,8 @@ name: Lint on: push: branches: - - master - main + - rel-* pull_request: jobs: @@ -12,7 +12,7 @@ jobs: name: Optional Lint runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: misspell # Check spellings as well uses: reviewdog/action-misspell@v1 with: @@ -34,7 +34,7 @@ jobs: name: Python format runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v4 with: @@ -100,7 +100,7 @@ jobs: name: Lint JavaScript runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: reviewdog/action-eslint@v1 with: reporter: github-pr-check diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 92ddf900d9c5e..7b314d845d9b4 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -2,18 +2,22 @@ name: Linux_CI on: push: branches: - - master - main + - rel-* pull_request: +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + jobs: Onnxruntime-TVM: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - - uses: actions/setup-python@v3 + - uses: actions/setup-python@v4 with: python-version: '3.8.x' architecture: 'x64' diff --git a/.github/workflows/publish-c-apidocs.yml b/.github/workflows/publish-c-apidocs.yml index c08363ab39369..0a3e9ed2594c1 100644 --- a/.github/workflows/publish-c-apidocs.yml +++ b/.github/workflows/publish-c-apidocs.yml @@ -6,8 +6,8 @@ on: branches: - main paths: - - include/onnxruntime/core/session - - orttraining/orttraining/training_api/include/ + - include/onnxruntime/core/session/** + - orttraining/orttraining/training_api/include/** schedule: - cron: '0 0 1 * *' workflow_dispatch: @@ -24,19 +24,19 @@ jobs: name: Generate C/C++ API docs runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Install doxygen and dependencies run: | sudo apt update sudo apt-get install libclang-dev sudo apt-get install libclang-cpp14 - wget https://www.doxygen.nl/files/doxygen-1.9.6.linux.bin.tar.gz - tar xvzf doxygen-1.9.6.linux.bin.tar.gz + wget https://www.doxygen.nl/files/doxygen-1.9.8.linux.bin.tar.gz + tar xvzf doxygen-1.9.8.linux.bin.tar.gz - name: Run doxygen run: | mkdir -p build/doxygen cd docs/c_cxx - ../../doxygen-1.9.6/bin/doxygen + ../../doxygen-1.9.8/bin/doxygen - name: Log source commit run: git rev-parse --short HEAD > build/doxygen/html/source-version.txt - name: Move C/C++ docs into site diff --git a/.github/workflows/publish-csharp-apidocs.yml b/.github/workflows/publish-csharp-apidocs.yml index 7d33a782fb488..9b9ca924bd008 100644 --- a/.github/workflows/publish-csharp-apidocs.yml +++ b/.github/workflows/publish-csharp-apidocs.yml @@ -6,7 +6,7 @@ on: branches: - main paths: - - csharp + - csharp/** schedule: - cron: '0 0 1 * *' workflow_dispatch: @@ -24,11 +24,11 @@ jobs: env: DOCFXVERSION: 2.62.2 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup .NET - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v3 with: - dotnet-version: 5.0.x + dotnet-version: 6.0.x - name: Restore dependencies run: dotnet restore csharp/ApiDocs/ApiDocs.csproj - name: Download DocFX diff --git a/.github/workflows/publish-gh-pages.yml b/.github/workflows/publish-gh-pages.yml index 5ddb1e3bb03d1..1818261b4b766 100644 --- a/.github/workflows/publish-gh-pages.yml +++ b/.github/workflows/publish-gh-pages.yml @@ -1,101 +1,16 @@ -# Sample workflow for building and deploying a Jekyll site to GitHub Pages +# This is a placeholder workflow only. Its purpose is for manual runs to show up +# in the GitHub web UI. It is not used for any automated runs. name: Publish site on: - # Runs on pushes targeting the branch where the website sources live - push: - branches: ["gh-pages"] - # Allows you to run this workflow manually from the Actions tab workflow_dispatch: -# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages -permissions: - contents: read - pages: write - id-token: write - -# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. -# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. -concurrency: - group: "pages" - cancel-in-progress: false - jobs: - # Build job - build: + placeholder: runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v3 - with: - ref: gh-pages - - - name: Setup Pages - uses: actions/configure-pages@v3 - - - name: Build with Jekyll - uses: actions/jekyll-build-pages@v1 - with: - source: ./ - destination: ./_site - - - name: Download C apidocs artifact - uses: dawidd6/action-download-artifact@v2 - with: - name: onnxruntime-c-apidocs - workflow: publish-c-apidocs.yml - branch: main - path: apidocs - - - name: Download C# apidocs artifact - uses: dawidd6/action-download-artifact@v2 - with: - name: onnxruntime-csharp-apidocs - workflow: publish-csharp-apidocs.yml - branch: main - path: apidocs - - - name: Download Java apidocs artifact - uses: dawidd6/action-download-artifact@v2 - with: - name: onnxruntime-java-apidocs - workflow: publish-java-apidocs.yml - branch: main - path: apidocs - - - name: Download Python apidocs artifact - uses: dawidd6/action-download-artifact@v2 - with: - name: onnxruntime-python-apidocs - workflow: publish-python-apidocs.yml - branch: main - path: apidocs - - - name: Move apidocs folder into place + - name: Placeholder step to have workflow included in the GitHub web UI run: | - sudo rm -rf _site/docs/api/c - sudo mv apidocs/docs/api/c _site/docs/api - sudo rm -rf _site/docs/api/csharp - sudo mv apidocs/docs/api/csharp _site/docs/api - sudo rm -rf _site/docs/api/java - sudo mv apidocs/docs/api/java _site/docs/api - sudo rm -rf _site/docs/api/python - sudo mv apidocs/docs/api/python _site/docs/api - - - name: Upload site - uses: actions/upload-pages-artifact@v1 - with: - retention-days: 21 - - # Deployment job - deploy: - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest - needs: build - steps: - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v1 + echo "Placeholder step to have workflow included in the GitHub web UI" + echo "The actual publish workflow is run from the gh-pages branch" diff --git a/.github/workflows/publish-java-apidocs.yml b/.github/workflows/publish-java-apidocs.yml index b81ea47c7fc37..9ea9bda7e7c53 100644 --- a/.github/workflows/publish-java-apidocs.yml +++ b/.github/workflows/publish-java-apidocs.yml @@ -6,7 +6,7 @@ on: branches: - main paths: - - java + - java/** schedule: - cron: '0 0 1 * *' workflow_dispatch: @@ -23,7 +23,7 @@ jobs: name: Generate Java docs runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up JDK 11 uses: actions/setup-java@v3 with: diff --git a/.github/workflows/publish-js-apidocs.yml b/.github/workflows/publish-js-apidocs.yml new file mode 100644 index 0000000000000..ba8bfd718abfa --- /dev/null +++ b/.github/workflows/publish-js-apidocs.yml @@ -0,0 +1,50 @@ +name: Update JS API Docs + +# Run when the JS API changes or every month so that the artifact does not expire +on: + push: + branches: + - main + paths: + - js/common/** + schedule: + - cron: '0 0 1 * *' + workflow_dispatch: + +concurrency: + group: "apidocs-js" + cancel-in-progress: false + +permissions: + contents: write + +jobs: + build: + name: Generate JS API docs + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: 18 + - name: Generate JS docs + run: | + cd js/ + npm ci + cd common/ + npm ci + npx typedoc + - name: Log source commit + run: git rev-parse --short HEAD > js/common/docs/source-version.txt + - name: Move JS docs into site + run: | + rm -rf _site/docs/api/js + mkdir -p _site/docs/api + mv js/common/docs _site/docs/api/js + - name: Upload docs artifact + uses: actions/upload-artifact@v3 + with: + name: onnxruntime-node-apidocs + path: _site + retention-days: 60 diff --git a/.github/workflows/publish-objectivec-apidocs.yml b/.github/workflows/publish-objectivec-apidocs.yml index 9ce6e68c5b8bb..1b327eebfa8a8 100644 --- a/.github/workflows/publish-objectivec-apidocs.yml +++ b/.github/workflows/publish-objectivec-apidocs.yml @@ -6,7 +6,7 @@ on: branches: - main paths: - - objectivec + - objectivec/** schedule: - cron: '0 0 1 * *' workflow_dispatch: @@ -21,9 +21,9 @@ permissions: jobs: build: name: Generate Objective-C API docs - runs-on: macos-12 + runs-on: macos-13 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install Jazzy run: | diff --git a/.github/workflows/publish-python-apidocs.yml b/.github/workflows/publish-python-apidocs.yml index 263dbe92299a5..ab9d4781afb83 100644 --- a/.github/workflows/publish-python-apidocs.yml +++ b/.github/workflows/publish-python-apidocs.yml @@ -6,7 +6,8 @@ on: branches: - main paths: - - onnxruntime/python + - onnxruntime/python/** + - docs/python/** schedule: - cron: '0 0 1 * *' workflow_dispatch: @@ -23,7 +24,7 @@ jobs: name: Generate Python API docs runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Install tools run: | sudo apt-get update @@ -34,19 +35,19 @@ jobs: python3 -m pip install --upgrade pip cd docs/python python3 -m pip install -r requirements.txt - python3 -m pip install -i https://aiinfra.pkgs.visualstudio.com/PublicPackages/_packaging/ORT-Nightly/pypi/simple/ ort-nightly + python3 -m pip install --pre onnxruntime-training -f https://download.onnxruntime.ai/onnxruntime_nightly_cpu.html python3 -m pip list - name: Generate Python docs with Sphinx run: | cd tools/doc ./builddoc.sh /usr/bin ../.. ../../build - name: Log source commit - run: git rev-parse --short HEAD > build/docs/inference/html/source-version.txt + run: git rev-parse --short HEAD > build/docs/html/source-version.txt - name: Move Python docs into site run: | rm -rf _site/docs/api/python - mkdir -p _site/docs/api - mv build/docs/inference/html _site/docs/api/python + mkdir -p _site/docs/api/ + mv build/docs/html _site/docs/api/python - name: Upload docs artifact uses: actions/upload-artifact@v3 with: diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index f2c61d3359df1..ba24e7eebfb03 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -2,18 +2,54 @@ name: Windows_CI on: push: branches: - - master - 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@v4 + with: + python-version: '3.11.x' + architecture: 'x64' + + - uses: actions/setup-node@v3 + 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 } + &tools\ci_build\github\windows\install_third_party_deps.ps1 -cpu_arch x64 -install_prefix D:\b\Debug\installed -build_config Debug + + # 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 + Onnxruntime-TVM: - runs-on: windows-2019 + runs-on: windows-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - - uses: actions/setup-python@v3 + - uses: actions/setup-python@v4 with: python-version: '3.8.x' architecture: 'x64' @@ -32,6 +68,14 @@ jobs: - name: 'Setup TVM EP Python requirements' run: | python3 -m pip install -r ${{ github.workspace }}/tools/ci_build/github/linux/tvm/requirements.txt + - name: 'rm gtest in conda' + shell: pwsh + run: | + Remove-Item 'C:\Miniconda\Library\lib\cmake\gtest' -Recurse -Force + Remove-Item 'C:\Miniconda\Library\lib\gmock.lib' -Force + Remove-Item 'C:\Miniconda\Library\lib\gmock_main.lib' -Force + Remove-Item 'C:\Miniconda\Library\lib\gtest.lib' -Force + Remove-Item 'C:\Miniconda\Library\lib\gtest_main.lib' -Force - name: 'Build and Test' run: | python3 ${{ github.workspace }}/tools/ci_build/build.py --build_dir build --config Release --skip_submodule_sync --parallel --enable_pybind --disable_contrib_ops --disable_ml_ops --skip_onnx_tests --use_tvm diff --git a/.gitmodules b/.gitmodules index 1319cfacc1170..7bb49e98bfec1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,16 +1,10 @@ [submodule "cmake/external/onnx"] path = cmake/external/onnx url = https://github.com/onnx/onnx.git -[submodule "cmake/external/eigen"] - path = cmake/external/eigen - url = https://gitlab.com/libeigen/eigen.git [submodule "cmake/external/libprotobuf-mutator"] path = cmake/external/libprotobuf-mutator url = https://github.com/google/libprotobuf-mutator.git [submodule "cmake/external/emsdk"] path = cmake/external/emsdk url = https://github.com/emscripten-core/emsdk.git - branch = 3.1.32 -[submodule "cmake/external/onnxruntime-extensions"] - path = cmake/external/onnxruntime-extensions - url = https://github.com/microsoft/onnxruntime-extensions.git + branch = 3.1.44 diff --git a/.lintrunner.toml b/.lintrunner.toml index daf8cc4c908aa..86be8d0d0bd38 100644 --- a/.lintrunner.toml +++ b/.lintrunner.toml @@ -64,36 +64,6 @@ init_command = [ '--dry-run={{DRYRUN}}', '--requirement=requirements-lintrunner.txt', ] - -[[linter]] -code = 'RUFF-FIX' -include_patterns = [ - '**/*.py', - '**/*.pyi', -] -exclude_patterns = [ - 'cmake/external/**', - # ignore generated flatbuffers code - 'onnxruntime/core/flatbuffers/ort_flatbuffers_py/**', -] -command = [ - 'python', - '-m', - 'lintrunner_adapters', - 'run', - 'ruff_fix_linter', - '--config=pyproject.toml', - '@{{PATHSFILE}}' -] -init_command = [ - 'python', - '-m', - 'lintrunner_adapters', - 'run', - 'pip_init', - '--dry-run={{DRYRUN}}', - '--requirement=requirements-lintrunner.txt', -] is_formatter = true @@ -184,10 +154,10 @@ exclude_patterns = [ 'java/**', # FIXME: Enable clang-format for java 'js/**', 'onnxruntime/contrib_ops/cuda/bert/tensorrt_fused_multihead_attention/**', # Contains data chunks - 'onnxruntime/core/flatbuffers/schema/ort.fbs.h', # Generated code + 'onnxruntime/core/flatbuffers/schema/*.fbs.h', # Generated code 'onnxruntime/core/graph/contrib_ops/quantization_defs.cc', 'onnxruntime/core/mlas/**', # Contains assembly code - 'winml/**', # FIXME: Enable clang-format for winml + 'winml/lib/Api.Image/shaders/**', # Contains data chunks ] command = [ 'python', diff --git a/.pipelines/OneBranch.Nuget-WindowsAI-Pipeline.Official.yml b/.pipelines/OneBranch.Nuget-WindowsAI-Pipeline.Official.yml index fa2b475fe9c1c..b9de1b79e1d51 100644 --- a/.pipelines/OneBranch.Nuget-WindowsAI-Pipeline.Official.yml +++ b/.pipelines/OneBranch.Nuget-WindowsAI-Pipeline.Official.yml @@ -351,6 +351,31 @@ extends: - script: | dir $(Build.SourcesDirectory)\unzipped\runtimes\win-x64\_native + - task: EsrpCodeSigning@2 + displayName: "Sign Nuget package" + inputs: + ConnectedServiceName: 'OnnxRuntime CodeSign 20190817' + FolderPath: $(Build.ArtifactStagingDirectory) + Pattern: '*.nupkg' + signConfigType: inlineSignParams + inlineOperation: | + [ + { + "keyCode": "CP-401405", + "operationSetCode": "NuGetSign", + "parameters": [ ], + "toolName": "sign", + "toolVersion": "1.0" + }, + { + "keyCode": "CP-401405", + "operationSetCode": "NuGetVerify", + "parameters": [ ], + "toolName": "sign", + "toolVersion": "1.0" + } + ] + - job: NuGet_Publishing pool: type: windows diff --git a/.pipelines/nuget_config/x64/packages.config b/.pipelines/nuget_config/x64/packages.config index 2ec9b577c1379..2ac650b0e6dc9 100644 --- a/.pipelines/nuget_config/x64/packages.config +++ b/.pipelines/nuget_config/x64/packages.config @@ -1,6 +1,6 @@  - + diff --git a/.pipelines/nuget_config/x86/packages.config b/.pipelines/nuget_config/x86/packages.config index 6f9e3ef4960b9..f80f96194a230 100644 --- a/.pipelines/nuget_config/x86/packages.config +++ b/.pipelines/nuget_config/x86/packages.config @@ -1,6 +1,6 @@  - + diff --git a/.pipelines/windowsai-steps.yml b/.pipelines/windowsai-steps.yml index 0b736da427261..45ebf889c5da1 100644 --- a/.pipelines/windowsai-steps.yml +++ b/.pipelines/windowsai-steps.yml @@ -80,11 +80,11 @@ jobs: # must call vsdevcmd first to add cmake to PATH - script: | - curl -O -L https://github.com/Kitware/CMake/releases/download/v3.24.3/cmake-3.24.3-windows-x86_64.zip - 7z x cmake-3.24.3-windows-x86_64.zip + curl -O -L https://github.com/Kitware/CMake/releases/download/v3.26.3/cmake-3.26.3-windows-x86_64.zip + 7z x cmake-3.26.3-windows-x86_64.zip set PYTHONHOME=$(Build.BinariesDirectory)\${{ parameters.PythonPackageName }}.3.9.7\tools set PYTHONPATH=$(Build.BinariesDirectory)\${{ parameters.PythonPackageName }}.3.9.7\tools - $(Build.BinariesDirectory)\${{ parameters.PythonPackageName }}.3.9.7\tools\python.exe "$(Build.SourcesDirectory)\tools\ci_build\build.py" --build_dir $(Build.BinariesDirectory) --build_shared_lib --enable_onnx_tests --ms_experimental --use_dml --use_winml --cmake_generator "Visual Studio 16 2019" --update --config RelWithDebInfo --enable_lto --use_telemetry --disable_rtti --enable_wcos $(BuildFlags) --cmake_extra_defines CMAKE_SYSTEM_VERSION=10.0.19041.0 --cmake_path $(Build.BinariesDirectory)\cmake-3.24.3-windows-x86_64\bin\cmake.exe --ctest_path $(Build.BinariesDirectory)\cmake-3.24.3-windows-x86_64\bin\ctest.exe + $(Build.BinariesDirectory)\${{ parameters.PythonPackageName }}.3.9.7\tools\python.exe "$(Build.SourcesDirectory)\tools\ci_build\build.py" --build_dir $(Build.BinariesDirectory) --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 $(BuildFlags) --cmake_extra_defines CMAKE_SYSTEM_VERSION=10.0.19041.0 --cmake_path $(Build.BinariesDirectory)\cmake-3.26.3-windows-x86_64\bin\cmake.exe --ctest_path $(Build.BinariesDirectory)\cmake-3.26.3-windows-x86_64\bin\ctest.exe workingDirectory: '$(Build.BinariesDirectory)' displayName: 'Generate cmake config' diff --git a/.vscode/settings.json b/.vscode/settings.json index fd28e2d7b335c..b7a1292efb2c6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -40,4 +40,3 @@ "-build/include_subdir", "-runtime/references" ] -} diff --git a/Package.swift b/Package.swift index 7f8bfe0c3c18d..f8bf33001ea24 100644 --- a/Package.swift +++ b/Package.swift @@ -21,7 +21,7 @@ import class Foundation.ProcessInfo let package = Package( name: "onnxruntime", - platforms: [.iOS(.v11)], + platforms: [.iOS(.v12)], products: [ .library(name: "onnxruntime", type: .static, @@ -32,7 +32,14 @@ let package = Package( .target(name: "OnnxRuntimeBindings", dependencies: ["onnxruntime"], path: "objectivec", - exclude: ["test", "docs", "ReadMe.md", "format_objc.sh"], + exclude: ["test", "docs", "ReadMe.md", "format_objc.sh", + "ort_checkpoint.mm", + "ort_checkpoint_internal.h", + "ort_training_session_internal.h", + "ort_training_session.mm", + "include/ort_checkpoint.h", + "include/ort_training_session.h", + "include/onnxruntime_training.h"], cxxSettings: [ .define("SPM_BUILD"), .unsafeFlags(["-std=c++17", diff --git a/README.md b/README.md index 68850f4be8ec1..22ef387f5a7cd 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,6 @@ **ONNX Runtime training** can accelerate the model training time on multi-node NVIDIA GPUs for transformer models with a one-line addition for existing PyTorch training scripts. [Learn more →](https://www.onnxruntime.ai/docs/#onnx-runtime-for-training) - ## Get Started & Resources * **General Information**: [onnxruntime.ai](https://onnxruntime.ai) @@ -17,12 +16,12 @@ * [**Upcoming Release Roadmap**](https://github.com/microsoft/onnxruntime/wiki/Upcoming-Release-Roadmap) -* **Companion sample repositories**: +* **Companion sample repositories**: - ONNX Runtime Inferencing: [microsoft/onnxruntime-inference-examples](https://github.com/microsoft/onnxruntime-inference-examples) - ONNX Runtime Training: [microsoft/onnxruntime-training-examples](https://github.com/microsoft/onnxruntime-training-examples) +## Builtin Pipeline Status -## Build Pipeline Status |System|Inference|Training| |---|---|---| |Windows|[![Build Status](https://dev.azure.com/onnxruntime/onnxruntime/_apis/build/status/Windows%20CPU%20CI%20Pipeline?label=Windows+CPU)](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=9)
[![Build Status](https://dev.azure.com/onnxruntime/onnxruntime/_apis/build/status/Windows%20GPU%20CI%20Pipeline?label=Windows+GPU)](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=10)
[![Build Status](https://dev.azure.com/onnxruntime/onnxruntime/_apis/build/status/Windows%20GPU%20TensorRT%20CI%20Pipeline?label=Windows+GPU+TensorRT)](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=47)|| @@ -33,6 +32,11 @@ |Web|[![Build Status](https://dev.azure.com/onnxruntime/onnxruntime/_apis/build/status/ONNX%20Runtime%20Web%20CI%20Pipeline?label=Web)](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=161)|| |Other|[![Build Status](https://dev.azure.com/onnxruntime/onnxruntime/_apis/build/status/onnxruntime-binary-size-checks-ci-pipeline?repoName=microsoft%2Fonnxruntime&label=Binary+Size+Check)](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=187&repoName=microsoft%2Fonnxruntime)
[![Build Status](https://dev.azure.com/onnxruntime/onnxruntime/_apis/build/status/onnxruntime-python-checks-ci-pipeline?label=Python+Checks)](https://dev.azure.com/onnxruntime/onnxruntime/_build/latest?definitionId=164)|| +## Third-party Pipeline Status + +|System|Inference|Training| +|---|---|---| +|Linux|[![Build Status](https://github.com/Ascend/onnxruntime/actions/workflows/build-and-test.yaml/badge.svg)](https://github.com/Ascend/onnxruntime/actions/workflows/build-and-test.yaml)|| ## Data/Telemetry diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index b4d981d42dfb8..700206180decd 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -5993,3 +5993,309 @@ https://github.com/tensorflow/tfjs WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +—— + +curl/curl + +https://github.com/curl + +COPYRIGHT AND PERMISSION NOTICE + +Copyright (C) Daniel Stenberg, , and many +contributors, see the THANKS file. + +All rights reserved. + +Permission to use, copy, modify, and distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright +notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of a copyright holder shall not +be used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization of the copyright holder. + +_____ + +Intel neural-compressor + +https://github.com/intel/neural-compressor + + 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 2016-2019 Intel Corporation + Copyright 2018 YANDEX LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + This distribution includes third party software ("third party programs"). + This third party software, even if included with the distribution of + the Intel software, may be governed by separate license terms, including + without limitation, third party license terms, other Intel software license + terms, and open source software license terms. These separate license terms + govern your use of the third party programs as set forth in the + "THIRD-PARTY-PROGRAMS" file. + +_____ + +FlashAttention, https://github.com/Dao-AILab/flash-attention + +BSD 3-Clause License + +Copyright (c) 2022, the respective contributors, as shown by the AUTHORS file. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* 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. + +* 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. + +_____ + +composable_kernel + +https://github.com/ROCmSoftwarePlatform/composable_kernel + +Copyright (c) 2018- , Advanced Micro Devices, Inc. (Chao Liu, Jing Zhang) +Copyright (c) 2019- , Advanced Micro Devices, Inc. (Letao Qin, Qianfeng Zhang, Liang Huang, Shaojie Wang) +Copyright (c) 2022- , Advanced Micro Devices, Inc. (Anthony Chang, Chunyu Lai, Illia Silin, Adam Osewski, Poyen Chen, Jehandad Khan) +Copyright (c) 2019-2021, Advanced Micro Devices, Inc. (Hanwen Chang) +Copyright (c) 2019-2020, Advanced Micro Devices, Inc. (Tejash Shah) +Copyright (c) 2020 , Advanced Micro Devices, Inc. (Xiaoyan Zhou) +Copyright (c) 2021-2022, Advanced Micro Devices, Inc. (Jianfeng Yan) + +SPDX-License-Identifier: MIT +Copyright (c) 2018-2023, Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/VERSION_NUMBER b/VERSION_NUMBER index 141f2e805bebd..092afa15df4df 100644 --- a/VERSION_NUMBER +++ b/VERSION_NUMBER @@ -1 +1 @@ -1.15.0 +1.17.0 diff --git a/build.amd64.1411.bat b/build.amd64.1411.bat deleted file mode 100644 index 5a289c13e0488..0000000000000 --- a/build.amd64.1411.bat +++ /dev/null @@ -1,12 +0,0 @@ -:: Copyright (c) Microsoft Corporation. All rights reserved. -:: Licensed under the MIT License. - -rem This will setup the VC env vars to use the 14.11 (VS2017 ver15.3) toolchain which is supported by CUDA 9.2 prior to running build.py. -rem It currently defaults to amd64 but that could be made configurable if that would be useful to developers running this locally. -@echo off - -rem Use 14.11 toolset -call "%VCINSTALLDIR%\Auxiliary\Build\vcvarsall.bat" amd64 -vcvars_ver=14.11 - -rem Requires a python 3.6 or higher install to be available in your PATH -python %~dp0\tools\ci_build\build.py --build_dir %~dp0\build\Windows %* \ No newline at end of file diff --git a/build.bat b/build.bat index d7f6a8513ebd1..d0c6cbcddd669 100644 --- a/build.bat +++ b/build.bat @@ -2,5 +2,9 @@ :: Licensed under the MIT License. @echo off -rem Requires a python 3.6 or higher install to be available in your PATH -python %~dp0\tools\ci_build\build.py --build_dir %~dp0\build\Windows %* \ No newline at end of file + +setlocal +set PATH=C:\Program Files\Git\usr\bin;%PATH% + +rem Requires a Python install to be available in your PATH +python "%~dp0\tools\ci_build\build.py" --build_dir "%~dp0\build\Windows" %* diff --git a/build.sh b/build.sh index 4c28facf7807a..bf799ac8b7211 100755 --- a/build.sh +++ b/build.sh @@ -18,5 +18,4 @@ elif [[ "$*" == *"--android"* ]]; then DIR_OS="Android" fi -#requires python3.6 or higher python3 $DIR/tools/ci_build/build.py --build_dir $DIR/build/$DIR_OS "$@" diff --git a/cgmanifests/cgmanifest.json b/cgmanifests/cgmanifest.json index b190fd6e8171e..2a3de3bb0ee51 100644 --- a/cgmanifests/cgmanifest.json +++ b/cgmanifests/cgmanifest.json @@ -563,6 +563,15 @@ }, "comments": "python-pillow. Implementation logic for anti-aliasing copied by Resize CPU kernel." } + }, + { + "component": { + "type": "git", + "git": { + "commitHash": "d10b27fe37736d2944630ecd7557cefa95cf87c9", + "repositoryUrl": "https://gitlab.com/libeigen/eigen.git" + } + } } ], "Version": 1 diff --git a/cgmanifests/generate_cgmanifest.py b/cgmanifests/generate_cgmanifest.py index 7d775996835da..a9eaacc6f2938 100644 --- a/cgmanifests/generate_cgmanifest.py +++ b/cgmanifests/generate_cgmanifest.py @@ -91,7 +91,7 @@ def add_github_dep(name, parsed_url): with open( - os.path.join(REPO_DIR, "tools", "ci_build", "github", "linux", "docker", "Dockerfile.manylinux2014_cuda11"), + os.path.join(REPO_DIR, "tools", "ci_build", "github", "linux", "docker", "Dockerfile.manylinux2_28_cuda11"), ) as f: for line in f: if not line.strip(): diff --git a/cgmanifests/generated/cgmanifest.json b/cgmanifests/generated/cgmanifest.json index 989756361bd07..6f1ca84e1a304 100644 --- a/cgmanifests/generated/cgmanifest.json +++ b/cgmanifests/generated/cgmanifest.json @@ -82,17 +82,7 @@ "component": { "type": "git", "git": { - "commitHash": "d10b27fe37736d2944630ecd7557cefa95cf87c9", - "repositoryUrl": "https://gitlab.com/libeigen/eigen.git" - }, - "comments": "git submodule at cmake/external/eigen" - } - }, - { - "component": { - "type": "git", - "git": { - "commitHash": "0ab19024f08c6673a713e454ef8bd95e174c807f", + "commitHash": "a896e3d066448b3530dbcaa48869fafefd738f57", "repositoryUrl": "https://github.com/emscripten-core/emsdk.git" }, "comments": "git submodule at cmake/external/emsdk" @@ -112,7 +102,7 @@ "component": { "type": "git", "git": { - "commitHash": "9b7bca2a723ff94edcd007d93b5d0cf1838591dc", + "commitHash": "e2525550194ce3d8a2c4a3af451c9d9b3ae6650e", "repositoryUrl": "https://github.com/onnx/onnx.git" }, "comments": "git submodule at cmake/external/onnx" @@ -122,17 +112,7 @@ "component": { "type": "git", "git": { - "commitHash": "81e7799c69044c745239202085eb0a98f102937b", - "repositoryUrl": "https://github.com/microsoft/onnxruntime-extensions.git" - }, - "comments": "git submodule at cmake/external/onnxruntime-extensions" - } - }, - { - "component": { - "type": "git", - "git": { - "commitHash": "8c0b94e793a66495e0b1f34a5eb26bd7dc672db0", + "commitHash": "29bf8085f3bf17b84d30e34b3d7ff8248fda404e", "repositoryUrl": "https://github.com/abseil/abseil-cpp.git" }, "comments": "abseil_cpp" @@ -152,7 +132,7 @@ "component": { "type": "git", "git": { - "commitHash": "e7e1482087f58913b80a20b04d5c58d9d6d90155", + "commitHash": "6e921e1b1d21e84a5c82416ba7ecd98e33a436d0", "repositoryUrl": "https://github.com/HowardHinnant/date.git" }, "comments": "date" @@ -212,7 +192,7 @@ "component": { "type": "git", "git": { - "commitHash": "436617053d0f39a1019a371c3a9aa599b3cb2cea", + "commitHash": "13de152c2a1cd73ff4df97bd2c406b6d15d34af3", "repositoryUrl": "https://github.com/google/nsync.git" }, "comments": "google_nsync" @@ -222,7 +202,7 @@ "component": { "type": "git", "git": { - "commitHash": "519beb0e52c842729b4b53731d27c0e0c32ab4a2", + "commitHash": "f8d7d77c06936315286eb55f8de22cd23c188571", "repositoryUrl": "https://github.com/google/googletest.git" }, "comments": "googletest" @@ -262,7 +242,7 @@ "component": { "type": "git", "git": { - "commitHash": "5f4caba4e7a9017816e47becdd918fcc872039ba", + "commitHash": "55f373e164d3f092dd6c7a56e3de6f90c4c6f3dc", "repositoryUrl": "https://github.com/microsoft/wil.git" }, "comments": "microsoft_wil" @@ -282,7 +262,7 @@ "component": { "type": "git", "git": { - "commitHash": "7bc4e1ae9b36ec8ee635c3629b59ec525bbe82b9", + "commitHash": "0a0b5fb001ce0233ae3a6f99d849c0649e5a7361", "repositoryUrl": "https://github.com/boostorg/mp11.git" }, "comments": "mp11" @@ -292,17 +272,7 @@ "component": { "type": "git", "git": { - "commitHash": "3b58938e025c41d2fcd89fa22028eefaa81a18ad", - "repositoryUrl": "https://github.com/onnx/onnx.git" - }, - "comments": "onnx" - } - }, - { - "component": { - "type": "git", - "git": { - "commitHash": "ba6a4fb34fdeaa3613bf981610c657e7b663a699", + "commitHash": "0462dc31ae78f48744b6141ae376df1f96d3f459", "repositoryUrl": "https://github.com/onnx/onnx-tensorrt.git" }, "comments": "onnx_tensorrt" @@ -352,7 +322,7 @@ "component": { "type": "git", "git": { - "commitHash": "5916273f79a21551890fd3d56fc5375a78d1598d", + "commitHash": "959002f82d7962a473d8bf301845f2af720e0aa4", "repositoryUrl": "https://github.com/pytorch/cpuinfo.git" }, "comments": "pytorch_cpuinfo" @@ -372,7 +342,7 @@ "component": { "type": "git", "git": { - "commitHash": "ff15c6ada150a5018c5ef2172401cb4529eac9c0", + "commitHash": "4cafc9196c4da9c817992b20f5253ef967685bf8", "repositoryUrl": "https://github.com/dcleblanc/SafeInt.git" }, "comments": "safeint" @@ -402,50 +372,30 @@ "component": { "type": "git", "git": { - "commitHash": "19cc035b6c6f2283573d29c7ea7f7d675cf750ce", - "repositoryUrl": "https://github.com/openssl/openssl.git" + "commitHash": "72c943dea2b9240cd09efde15191e144bc7c7d38", + "repositoryUrl": "https://github.com/protocolbuffers/utf8_range.git" }, - "comments": "openssl" + "comments": "utf8_range" } }, { "component": { "type": "git", "git": { - "commitHash": "f54b0e47a08782a6131cc3d60f94d038fa6e0a51", - "repositoryUrl": "https://github.com/Tencent/rapidjson.git" - }, - "comments": "rapidjson" - } - }, - { - "component": { - "type": "git", - "git": { - "commitHash": "da041154c6bac1a4aa98254a7d6819059e8ac0b0", - "repositoryUrl": "https://github.com/boostorg/boost.git" - }, - "comments": "boost" - } - }, - { - "component": { - "type": "git", - "git": { - "commitHash": "9a6546658657dbeb23245117b57f4e6cf6cdc3e6", - "repositoryUrl": "https://github.com/libb64/libb64.git" + "commitHash": "94142d8391c9791ec71c38336436319a2d4ac7a0", + "repositoryUrl": "https://github.com/microsoft/onnxruntime-extensions.git" }, - "comments": "b64" + "comments": "extensions" } }, { "component": { "type": "git", "git": { - "commitHash": "75a84807a019bf4961faf713df9d748f0fc83b47", - "repositoryUrl": "https://github.com/triton-inference-server/server.git" + "commitHash": "d52ec01652b7d620386251db92455968d8d90bdc", + "repositoryUrl": "https://github.com/ROCmSoftwarePlatform/composable_kernel.git" }, - "comments": "triton" + "comments": "composable_kernel" } } ] diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index dd4942caa40ce..496ca72bb1b6c 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -2,7 +2,8 @@ # Licensed under the MIT License. # Minimum CMake required -cmake_minimum_required(VERSION 3.24) +cmake_minimum_required(VERSION 3.26) + cmake_policy(SET CMP0069 NEW) set(CMAKE_POLICY_DEFAULT_CMP0069 NEW) @@ -13,17 +14,22 @@ cmake_policy(SET CMP0117 NEW) cmake_policy(SET CMP0104 OLD) # Enable Hot Reload for MSVC compilers if supported. -if (POLICY CMP0141) - if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.26.0") - cmake_policy(SET CMP0141 NEW) - else() - cmake_policy(SET CMP0141 OLD) - endif() -endif() +cmake_policy(SET CMP0141 NEW) # Project project(onnxruntime C CXX ASM) +# Disable fast-math for Intel oneAPI compiler +if("${CMAKE_CXX_COMPILER_ID}" MATCHES "IntelLLVM") + if("${CMAKE_CXX_COMPILER_ID}" MATCHES "MSVC-like") + # Using icx-cl compiler driver with MSVC-like arguments + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fp:precise") + else() + # Using icpx compiler driver + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-fast-math") + endif() +endif() + # Needed for Java set(CMAKE_C_STANDARD 99) @@ -48,14 +54,16 @@ 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 7) - message(FATAL_ERROR "GCC version must not less than 7") +if("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 8) + message(FATAL_ERROR "GCC version must be greater than or equal to 8") endif() # Options option(onnxruntime_RUN_ONNX_TESTS "Enable ONNX Compatibility Testing" OFF) option(onnxruntime_GENERATE_TEST_REPORTS "Enable test report generation" OFF) option(onnxruntime_ENABLE_STATIC_ANALYSIS "Enable static analysis" OFF) +option(onnxruntime_USE_CUSTOM_STATIC_ANALYSIS_RULES "Use a custom SDL Rule. It is mainly for our CI build" OFF) +option(onnxruntime_REDIRECT_STATIC_ANALYSIS_OUTPUTS_TO_FILE "Use a custom SDL Rule. It is mainly for our CI build" OFF) option(onnxruntime_ENABLE_PYTHON "Enable python buildings" OFF) # Enable it may cause LNK1169 error option(onnxruntime_ENABLE_MEMLEAK_CHECKER "Experimental: Enable memory leak checker in Windows debug build" OFF) @@ -68,7 +76,7 @@ option(onnxruntime_USE_QNN "Build with QNN support" OFF) 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_JS "Build with JavaScript implemented kernels support" OFF) +option(onnxruntime_USE_JSEP "Build with JavaScript implemented kernels support" 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) @@ -76,7 +84,8 @@ option(onnxruntime_USE_PREINSTALLED_EIGEN "Use pre-installed EIGEN. Need to prov option(onnxruntime_BUILD_BENCHMARKS "Build ONNXRuntime micro-benchmarks" OFF) option(onnxruntime_USE_LLVM "Build TVM with LLVM" OFF) -option(onnxruntime_USE_FLASH_ATTENTION "Build memory efficient attention kernel for scaled dot product attention" ON) +cmake_dependent_option(onnxruntime_USE_FLASH_ATTENTION "Build flash attention kernel for scaled dot product attention" ON "NOT WIN32; onnxruntime_USE_CUDA" OFF) +option(onnxruntime_USE_MEMORY_EFFICIENT_ATTENTION "Build memory efficient attention kernel for scaled dot product attention" ON) option(onnxruntime_BUILD_FOR_NATIVE_MACHINE "Enable this option for turning on optimization specific to this machine" OFF) option(onnxruntime_USE_AVX "Use AVX instructions" OFF) @@ -122,6 +131,7 @@ option(onnxruntime_TVM_CUDA_RUNTIME "Build TVM with CUDA support" OFF) option(onnxruntime_TVM_USE_LLVM "Build TVM with LLVM. Set customized path to llvm-config.exe here if need" OFF) option(onnxruntime_TVM_USE_HASH "Build ipp-crypto library for support hash algorithm. It is defined for TVM only") option(onnxruntime_USE_XNNPACK "Build with XNNPACK support. Provides an alternative math library on ARM, WebAssembly and x86." OFF) +option(onnxruntime_USE_WEBNN "Build with WebNN support. Enable hardware acceleration in web browsers." OFF) # Options related to reducing the binary size produced by the build # XNNPACK EP requires the internal NHWC contrib ops to be available, so this option must be OFF when onnxruntime_USE_XNNPACK is ON @@ -129,6 +139,7 @@ cmake_dependent_option(onnxruntime_DISABLE_CONTRIB_OPS "Disable contrib ops" OFF option(onnxruntime_DISABLE_ML_OPS "Disable traditional ML ops" OFF) option(onnxruntime_DISABLE_SPARSE_TENSORS "Disable sparse tensors data types" OFF) option(onnxruntime_DISABLE_OPTIONAL_TYPE "Disable optional type" OFF) +option(onnxruntime_DISABLE_FLOAT8_TYPES "Disable float 8 types" OFF) option(onnxruntime_MINIMAL_BUILD "Exclude as much as possible from the build. Support ORT format models. No support for ONNX format models." OFF) cmake_dependent_option(onnxruntime_DISABLE_RTTI "Disable RTTI" ON "NOT onnxruntime_ENABLE_PYTHON" OFF) # For now onnxruntime_DISABLE_EXCEPTIONS will only work with onnxruntime_MINIMAL_BUILD, more changes (ONNX, non-CPU EP, ...) are required to run this standalone @@ -162,8 +173,7 @@ option(onnxruntime_ENABLE_CPU_FP16_OPS "Build with advanced instruction sets" ON option(onnxruntime_USE_NCCL "Build with NCCL support" OFF) option(onnxruntime_USE_MPI "Build with MPI support" OFF) -# build WebAssembly -option(onnxruntime_BUILD_WEBASSEMBLY "Enable this option to create WebAssembly byte codes" OFF) +# WebAssembly options option(onnxruntime_BUILD_WEBASSEMBLY_STATIC_LIB "Enable this option to create WebAssembly static library" OFF) option(onnxruntime_ENABLE_WEBASSEMBLY_THREADS "Enable this option to create WebAssembly byte codes with multi-threads support" OFF) option(onnxruntime_ENABLE_WEBASSEMBLY_EXCEPTION_CATCHING "Enable this option to turn on exception catching" OFF) @@ -208,9 +218,13 @@ option(onnxruntime_ENABLE_CPUINFO "Enable cpuinfo" ON) # ATen fallback support option(onnxruntime_ENABLE_ATEN "Enable ATen fallback" OFF) +# Triton support +option(onnxruntime_ENABLE_TRITON "Enable Triton" OFF) + # composable kernel is managed automatically, unless user want to explicitly disable it, it should not be manually set option(onnxruntime_USE_COMPOSABLE_KERNEL "Enable composable kernel for ROCm EP" ON) option(onnxruntime_USE_ROCBLAS_EXTENSION_API "Enable rocblas tuning for ROCm EP" OFF) +option(onnxruntime_USE_TRITON_KERNEL "Enable triton compiled kernel" OFF) option(onnxruntime_BUILD_KERNEL_EXPLORER "Build Kernel Explorer for testing and profiling GPU kernels" OFF) option(onnxruntime_BUILD_CACHE "onnxruntime build with cache" OFF) @@ -218,6 +232,7 @@ option(onnxruntime_BUILD_CACHE "onnxruntime build with cache" OFF) cmake_dependent_option(MSVC_Z7_OVERRIDE "replacing /Zi and /ZI with /Z7 when using MSVC with CCache" ON "onnxruntime_BUILD_CACHE; MSVC" OFF) option(onnxruntime_USE_AZURE "Build with azure inferencing support" OFF) +option(onnxruntime_USE_LOCK_FREE_QUEUE "Build with lock-free task queue for threadpool." OFF) # ENABLE_TRAINING includes all training functionality # The following 2 entry points @@ -232,14 +247,21 @@ option(onnxruntime_USE_AZURE "Build with azure inferencing support" OFF) # Some features are only enabled when onnxruntime_ENABLE_PYTHON is ON as they are only relevant # when using python env if (onnxruntime_ENABLE_TRAINING) - set(onnxruntime_ENABLE_TRAINING_OPS ON) set(onnxruntime_ENABLE_TRAINING_APIS ON) - set(onnxruntime_ENABLE_TRAINING_TORCH_INTEROP ON) + set(onnxruntime_ENABLE_TRAINING_OPS ON) set(onnxruntime_ENABLE_ATEN ON) + set(onnxruntime_ENABLE_TRITON ON) + if (NOT APPLE) + set(onnxruntime_ENABLE_TRAINING_TORCH_INTEROP ON) + endif() endif() if (onnxruntime_ENABLE_TRAINING_APIS) set(onnxruntime_ENABLE_TRAINING_OPS ON) + if (onnxruntime_ENABLE_PYTHON AND NOT onnxruntime_ENABLE_TRAINING) + message(FATAL_ERROR "Standalone On-Device Training build is not supported with Python bindings! " + "Please use the --enable_training flag instead of the --enable_training_apis flag.") + endif() endif() if (onnxruntime_USE_CUDA) @@ -259,11 +281,14 @@ if (onnxruntime_USE_ROCM) endif() if (NOT CMAKE_HIP_ARCHITECTURES) - set(CMAKE_HIP_ARCHITECTURES "gfx906;gfx908;gfx90a;gfx1030") + set(CMAKE_HIP_ARCHITECTURES "gfx906;gfx908;gfx90a;gfx1030;gfx1100;gfx1101") endif() file(GLOB rocm_cmake_components ${onnxruntime_ROCM_HOME}/lib/cmake/*) list(APPEND CMAKE_PREFIX_PATH ${rocm_cmake_components}) + # Force cmake to accept the configured HIP compiler. Because the configured CMAKE_PREFIX_PATH does not work during + # enable_language(HIP), we might need to move configuring of CMAKE_PREFIX_PATH to build.py (in the future). + set(CMAKE_HIP_COMPILER_FORCED ON) enable_language(HIP) # NOTE: Flags -mllvm -amdgpu-early-inline-all=true are critical for gpu kernel code performance. -mllvm passes the @@ -277,7 +302,15 @@ if (onnxruntime_USE_ROCM) add_compile_options("$<$:SHELL:-x hip>") if (NOT onnxruntime_HIPIFY_PERL) - set(onnxruntime_HIPIFY_PERL ${onnxruntime_ROCM_HOME}/hip/bin/hipify-perl) + find_path(HIPIFY_PERL_PATH + NAMES hipify-perl + HINTS + ${onnxruntime_ROCM_HOME}/bin + ${onnxruntime_ROCM_HOME}/hip/bin) + if (HIPIFY_PERL_PATH-NOTFOUND) + MESSAGE(FATAL_ERROR "hipify-perl not found") + endif() + set(onnxruntime_HIPIFY_PERL ${HIPIFY_PERL_PATH}/hipify-perl) endif() # replicate strategy used by pytorch to get ROCM_VERSION @@ -336,7 +369,7 @@ function(set_msvc_c_cpp_compiler_warning_level warning_level) # only match the generator expression added by this function list(FILTER opts EXCLUDE REGEX "^\\$<\\$,\\$>:/W[0-4]>$") - list(APPEND opts "$<$,$>:${warning_flag}>") + list(APPEND opts "$<$:${warning_flag}>") set_property(DIRECTORY PROPERTY COMPILE_OPTIONS "${opts}") endif() endfunction() @@ -395,6 +428,13 @@ if (NOT (UNIX AND onnxruntime_ENABLE_PYTHON AND onnxruntime_ENABLE_TRAINING AND set(onnxruntime_ENABLE_TRAINING_TORCH_INTEROP OFF) endif() +if (NOT (UNIX AND onnxruntime_USE_CUDA AND onnxruntime_ENABLE_PYTHON AND onnxruntime_ENABLE_TRAINING AND (NOT onnxruntime_BUILD_SHARED_LIB))) + if (onnxruntime_ENABLE_TRITON) + message(WARNING "onnxruntime_ENABLE_TRITON is turned OFF because it's designed to support CUDA training on Linux only currently.") + endif() + set(onnxruntime_ENABLE_TRITON OFF) +endif() + set(onnxruntime_REQUIRE_PYTHON_EMBED_LIB OFF) if (onnxruntime_ENABLE_TRAINING_TORCH_INTEROP) add_compile_definitions(ENABLE_TRAINING_TORCH_INTEROP) @@ -405,6 +445,17 @@ if (onnxruntime_ENABLE_TRAINING_TORCH_INTEROP) endif() endif() +if (onnxruntime_ENABLE_TRITON) + # Need SetOutputMLValue. + set(onnxruntime_ENABLE_ATEN ON) + add_compile_definitions(ENABLE_TRITON) + + # Python::Python is required for building unit test executables. + if (onnxruntime_BUILD_UNIT_TESTS) + set(onnxruntime_REQUIRE_PYTHON_EMBED_LIB ON) + endif() +endif() + # General C# properties if (onnxruntime_BUILD_CSHARP) check_language(CSharp) @@ -503,6 +554,8 @@ if (WIN32) list(APPEND ORT_WARNING_FLAGS "/wd4251") # issued by thrust nonstandard extension used: nameless struct/union list(APPEND ORT_WARNING_FLAGS "/wd4201") + # structure was padded due to __declspec(align()) + list(APPEND ORT_WARNING_FLAGS "/wd4324") # warning C4800: Implicit conversion from 'X' to bool. Possible information loss if (onnxruntime_USE_OPENVINO) list(APPEND ORT_WARNING_FLAGS "/wd4800") @@ -536,30 +589,31 @@ if (WIN32) endif() else() - check_cxx_compiler_flag(-Wunused-but-set-parameter HAS_UNUSED_BUT_SET_PARAMETER) - check_cxx_compiler_flag(-Wunused-but-set-variable HAS_UNUSED_BUT_SET_VARIABLE) - check_cxx_compiler_flag(-Wunused-variable HAS_UNUSED_VARIABLE) + check_cxx_compiler_flag(-Wambiguous-reversed-operator HAS_AMBIGUOUS_REVERSED_OPERATOR) + check_cxx_compiler_flag(-Wbitwise-instead-of-logical HAS_BITWISE_INSTEAD_OF_LOGICAL) check_cxx_compiler_flag(-Wcast-function-type HAS_CAST_FUNCTION_TYPE) - check_cxx_compiler_flag(-Wparentheses HAS_PARENTHESES) - check_cxx_compiler_flag(-Wuseless-cast HAS_USELESS_CAST) - check_cxx_compiler_flag(-Wnonnull-compare HAS_NONNULL_COMPARE) - check_cxx_compiler_flag(-Wtautological-pointer-compare HAS_TAUTOLOGICAL_POINTER_COMPARE) check_cxx_compiler_flag(-Wcatch-value HAS_CATCH_VALUE) - check_cxx_compiler_flag(-Wmissing-braces HAS_MISSING_BRACES) - check_cxx_compiler_flag(-Wignored-attributes HAS_IGNORED_ATTRIBUTES) + check_cxx_compiler_flag(-Wclass-memaccess HAS_CLASS_MEMACCESS) + check_cxx_compiler_flag(-Wdeprecated-anon-enum-enum-conversion HAS_DEPRECATED_ANON_ENUM_ENUM_CONVERSION) + check_cxx_compiler_flag(-Wdeprecated-builtins HAS_DEPRECATED_BUILTINS) check_cxx_compiler_flag(-Wdeprecated-copy HAS_DEPRECATED_COPY) check_cxx_compiler_flag(-Wdeprecated-declarations HAS_DEPRECATED_DECLARATIONS) - check_cxx_compiler_flag(-Wclass-memaccess HAS_CLASS_MEMACCESS) + check_cxx_compiler_flag(-Wenum-constexpr-conversion HAS_ENUM_CONSTEXPR_CONVERSION) + check_cxx_compiler_flag(-Wformat-truncation HAS_FORMAT_TRUNCATION) + check_cxx_compiler_flag(-Wignored-attributes HAS_IGNORED_ATTRIBUTES) check_cxx_compiler_flag(-Wmaybe-uninitialized HAS_MAYBE_UNINITIALIZED) + check_cxx_compiler_flag(-Wmissing-braces HAS_MISSING_BRACES) + check_cxx_compiler_flag(-Wnonnull-compare HAS_NONNULL_COMPARE) + check_cxx_compiler_flag(-Wparentheses HAS_PARENTHESES) + check_cxx_compiler_flag(-Wshorten-64-to-32 HAS_SHORTEN_64_TO_32) check_cxx_compiler_flag(-Wstrict-aliasing HAS_STRICT_ALIASING) check_nvcc_compiler_flag(-Wstrict-aliasing NVCC_HAS_STRICT_ALIASING) - check_cxx_compiler_flag(-Wambiguous-reversed-operator HAS_AMBIGUOUS_REVERSED_OPERATOR) - check_cxx_compiler_flag(-Wdeprecated-anon-enum-enum-conversion HAS_DEPRECATED_ANON_ENUM_ENUM_CONVERSION) + check_cxx_compiler_flag(-Wtautological-pointer-compare HAS_TAUTOLOGICAL_POINTER_COMPARE) check_cxx_compiler_flag(-Wundefined-var-template HAS_UNDEFINED_VAR_TEMPLATE) - check_cxx_compiler_flag(-Wformat-truncation HAS_FORMAT_TRUNCATION) - check_cxx_compiler_flag(-Wbitwise-instead-of-logical HAS_BITWISE_INSTEAD_OF_LOGICAL) - check_cxx_compiler_flag(-Wenum-constexpr-conversion HAS_ENUM_CONSTEXPR_CONVERSION) - check_cxx_compiler_flag(-Wdeprecated-builtins HAS_DEPRECATED_BUILTINS) + check_cxx_compiler_flag(-Wunused-but-set-parameter HAS_UNUSED_BUT_SET_PARAMETER) + check_cxx_compiler_flag(-Wunused-but-set-variable HAS_UNUSED_BUT_SET_VARIABLE) + check_cxx_compiler_flag(-Wunused-variable HAS_UNUSED_VARIABLE) + check_cxx_compiler_flag(-Wuseless-cast HAS_USELESS_CAST) check_function_exists(reallocarray HAS_REALLOCARRAY) if (HAS_TAUTOLOGICAL_POINTER_COMPARE) @@ -593,6 +647,11 @@ else() target_compile_options(libprotobuf-lite PRIVATE "-Wno-enum-constexpr-conversion") endif() endif() + + # enable warning(s) that may not be on by default + if (HAS_SHORTEN_64_TO_32) + list(APPEND ORT_WARNING_FLAGS -Wshorten-64-to-32) + endif() endif() #names in this var must match the directory names under onnxruntime/core/providers @@ -610,13 +669,16 @@ if (onnxruntime_USE_CUDA) if (onnxruntime_DISABLE_CONTRIB_OPS) set(onnxruntime_USE_FLASH_ATTENTION OFF) + set(onnxruntime_USE_MEMORY_EFFICIENT_ATTENTION OFF) endif() if (CMAKE_CUDA_COMPILER_VERSION VERSION_LESS 11.6) message( STATUS "Turn off flash attention since CUDA compiler version < 11.6") set(onnxruntime_USE_FLASH_ATTENTION OFF) + set(onnxruntime_USE_MEMORY_EFFICIENT_ATTENTION OFF) endif() else() set(onnxruntime_USE_FLASH_ATTENTION OFF) + set(onnxruntime_USE_MEMORY_EFFICIENT_ATTENTION OFF) endif() if (onnxruntime_USE_CUDA) @@ -629,6 +691,11 @@ if (onnxruntime_USE_CUDA) list(APPEND ORT_PROVIDER_FLAGS -DUSE_FLASH_ATTENTION=1) list(APPEND ORT_PROVIDER_CMAKE_FLAGS -Donnxruntime_USE_FLASH_ATTENTION=1) endif() + if (onnxruntime_USE_MEMORY_EFFICIENT_ATTENTION) + message( STATUS "Enable memory efficient attention for CUDA EP") + list(APPEND ORT_PROVIDER_FLAGS -DUSE_MEMORY_EFFICIENT_ATTENTION=1) + list(APPEND ORT_PROVIDER_CMAKE_FLAGS -Donnxruntime_USE_MEMORY_EFFICIENT_ATTENTION=1) + endif() endif() if (onnxruntime_USE_VITISAI) @@ -662,9 +729,9 @@ if (onnxruntime_USE_NNAPI_BUILTIN) list(APPEND ORT_PROVIDER_CMAKE_FLAGS -Donnxruntime_USE_NNAPI_BUILTIN=1) list(APPEND ONNXRUNTIME_PROVIDER_NAMES nnapi) endif() -if (onnxruntime_USE_JS) - list(APPEND ORT_PROVIDER_FLAGS -DUSE_JS=1) - list(APPEND ORT_PROVIDER_CMAKE_FLAGS -Donnxruntime_USE_JS=1) +if (onnxruntime_USE_JSEP) + list(APPEND ORT_PROVIDER_FLAGS -DUSE_JSEP=1) + list(APPEND ORT_PROVIDER_CMAKE_FLAGS -Donnxruntime_USE_JSEP=1) list(APPEND ONNXRUNTIME_PROVIDER_NAMES js) endif() if (onnxruntime_USE_QNN) @@ -722,6 +789,11 @@ if (onnxruntime_USE_XNNPACK) list(APPEND ORT_PROVIDER_CMAKE_FLAGS -Donnxruntime_USE_XNNPACK=1) list(APPEND ONNXRUNTIME_PROVIDER_NAMES xnnpack) endif() +if (onnxruntime_USE_WEBNN) + list(APPEND ORT_PROVIDER_FLAGS -DUSE_WEBNN=1) + list(APPEND ORT_PROVIDER_CMAKE_FLAGS -Donnxruntime_USE_WEBNN=1) + list(APPEND ONNXRUNTIME_PROVIDER_NAMES webnn) +endif() if (onnxruntime_USE_CANN) list(APPEND ORT_PROVIDER_FLAGS -DUSE_CANN=1) list(APPEND ORT_PROVIDER_CMAKE_FLAGS -Donnxruntime_USE_CANN=1) @@ -732,7 +804,9 @@ if (onnxruntime_USE_AZURE) list(APPEND ORT_PROVIDER_CMAKE_FLAGS -Donnxruntime_USE_AZURE=1) list(APPEND ONNXRUNTIME_PROVIDER_NAMES azure) endif() - +if (onnxruntime_USE_LOCK_FREE_QUEUE) + add_compile_definitions(USE_LOCK_FREE_QUEUE) +endif() if (onnxruntime_ENABLE_LAZY_TENSOR) # To support LazyTensor, ORT needs to call Python function from C/C++. @@ -763,7 +837,7 @@ function(onnxruntime_set_compile_flags target_name) if(UNIX) target_compile_definitions(${target_name} PRIVATE PLATFORM_POSIX) endif() - target_compile_definitions(${target_name} PUBLIC EIGEN_USE_THREADS) + target_compile_definitions(${target_name} PRIVATE EIGEN_USE_THREADS) if (onnxruntime_DISABLE_CONTRIB_OPS) target_compile_definitions(${target_name} PRIVATE DISABLE_CONTRIB_OPS) endif() @@ -779,18 +853,25 @@ function(onnxruntime_set_compile_flags target_name) if (onnxruntime_DISABLE_OPTIONAL_TYPE) target_compile_definitions(${target_name} PRIVATE DISABLE_OPTIONAL_TYPE) endif() + + if (onnxruntime_DISABLE_FLOAT8_TYPES) + target_compile_definitions(${target_name} PRIVATE DISABLE_FLOAT8_TYPES) + endif() + if (onnxruntime_ENABLE_ATEN) target_compile_definitions(${target_name} PRIVATE ENABLE_ATEN) endif() set_target_properties(${target_name} PROPERTIES COMPILE_WARNING_AS_ERROR ON) if (onnxruntime_USE_CUDA) # Suppress a "conversion_function_not_usable" warning in gsl/span - target_compile_options(${target_name} PRIVATE "$<$:SHELL:--diag-suppress 554>") + target_compile_options(${target_name} PRIVATE "$<$:SHELL:-Xcudafe \"--diag_suppress=conversion_function_not_usable\">") + target_compile_definitions(${target_name} PRIVATE -DDISABLE_CUSPARSE_DEPRECATED) endif() if (MSVC) foreach(CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORY ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES}) - target_compile_options(${target_name} PRIVATE "$<$,$>:/external:I${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORY}>") + target_compile_options(${target_name} PRIVATE "$<$:/external:I${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORY}>") endforeach() + foreach(onnxruntime_external_lib IN LISTS onnxruntime_EXTERNAL_LIBRARIES) #TODO: the list contains cmake keywords like "debug". We should exclude them. if(TARGET ${onnxruntime_external_lib}) @@ -800,26 +881,39 @@ function(onnxruntime_set_compile_flags target_name) if(onnxruntime_external_lib_include_dir MATCHES "^\\$]+)>$") string(REGEX REPLACE "^\\$]+)>$" "\\1" onnxruntime_external_lib_include_dir_cmake "${onnxruntime_external_lib_include_dir}") cmake_path(NATIVE_PATH onnxruntime_external_lib_include_dir_cmake NORMALIZE onnxruntime_external_lib_include_dir_native) - target_compile_options(${target_name} PRIVATE "$<$,$>:/external:I${onnxruntime_external_lib_include_dir_native}>") + target_compile_options(${target_name} PRIVATE "$<$:/external:I${onnxruntime_external_lib_include_dir_native}>") endif() else() cmake_path(NATIVE_PATH onnxruntime_external_lib_include_dir NORMALIZE onnxruntime_external_lib_include_dir_native) - target_compile_options(${target_name} PRIVATE "$<$,$>:/external:I${onnxruntime_external_lib_include_dir_native}>") + target_compile_options(${target_name} PRIVATE "$<$:/external:I${onnxruntime_external_lib_include_dir_native}>") endif() endforeach() endif() endforeach() - target_compile_definitions(${target_name} PUBLIC -DPLATFORM_WINDOWS -DNOGDI -DNOMINMAX -D_USE_MATH_DEFINES -D_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS) + target_compile_definitions(${target_name} PRIVATE -DPLATFORM_WINDOWS -DNOGDI -DNOMINMAX -D_USE_MATH_DEFINES -D_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS) if (onnxruntime_ENABLE_MEMLEAK_CHECKER) - target_compile_definitions(${target_name} PUBLIC -DONNXRUNTIME_ENABLE_MEMLEAK_CHECK) + target_compile_definitions(${target_name} PRIVATE -DONNXRUNTIME_ENABLE_MEMLEAK_CHECK) endif() - target_compile_options(${target_name} PRIVATE "$<$:SHELL:--compiler-options /utf-8>" "$<$,$>:/utf-8>") - target_compile_options(${target_name} PRIVATE "$<$:SHELL:--compiler-options /sdl>" "$<$,$>:/sdl>") + target_compile_options(${target_name} PRIVATE "$<$:SHELL:--compiler-options /utf-8>" "$<$:/utf-8>") + target_compile_options(${target_name} PRIVATE "$<$:SHELL:--compiler-options /sdl>" "$<$:/sdl>") set_target_properties(${target_name} PROPERTIES VS_GLOBAL_CAExcludePath "${ORT_BINARY_DIR};${ORT_SOURCE_DIR}") + # We do not treat warnings from 3rd-party libraries as errors. In order to do that, we need to add their header files locations to /external:I. + target_compile_options(${target_name} PRIVATE "$<$:/experimental:external>" "$<$:SHELL:--compiler-options /experimental:external>") + target_compile_options(${target_name} PRIVATE "$<$:/external:W0>" "$<$:SHELL:--compiler-options /external:W0>") + target_compile_options(${target_name} PRIVATE "$<$:/external:templates->" "$<$:SHELL:--compiler-options /external:templates->") + target_compile_options(${target_name} PRIVATE "$<$:/external:I${CMAKE_CURRENT_SOURCE_DIR}>" "$<$:SHELL:--compiler-options /external:I${CMAKE_CURRENT_SOURCE_DIR}>") + target_compile_options(${target_name} PRIVATE "$<$:/external:I${CMAKE_CURRENT_BINARY_DIR}>" "$<$:SHELL:--compiler-options /external:I${CMAKE_CURRENT_BINARY_DIR}>") if (onnxruntime_ENABLE_STATIC_ANALYSIS) - target_compile_options(${target_name} PRIVATE "$<$:SHELL:--compiler-options /analyze>" "$<$,$>:/analyze>") - target_compile_options(${target_name} PRIVATE "$<$:SHELL:--compiler-options /analyze:external->" "$<$,$>:/analyze:external->") + target_compile_options(${target_name} PRIVATE "$<$:SHELL:--compiler-options /analyze>" "$<$:/analyze>") + if (onnxruntime_REDIRECT_STATIC_ANALYSIS_OUTPUTS_TO_FILE) + target_compile_options(${target_name} PRIVATE "$<$:SHELL:--compiler-options /analyze:autolog:ext.sarif>" "$<$:/analyze:autolog:ext.sarif>") + endif() + target_compile_options(${target_name} PRIVATE "$<$:SHELL:--compiler-options /analyze:external->" "$<$:/analyze:external->") + target_compile_options(${target_name} PRIVATE "$<$:SHELL:--compiler-options /wd6385>" ) + # There are many such warnings from STL: + # include\list(148): warning C6011: Dereferencing NULL pointer '_Mycont'. : Lines: 146, 147, 148 + target_compile_options(${target_name} PRIVATE "$<$:SHELL:--compiler-options /wd6011>" ) endif() else() # Enable warning @@ -858,6 +952,7 @@ function(onnxruntime_set_compile_flags target_name) # 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) # some #pragma unroll will fail, do not treat them as error # #warning must not be treated as error @@ -887,12 +982,11 @@ function(onnxruntime_configure_target target_name) target_link_directories(${target_name} PRIVATE ${onnxruntime_LINK_DIRS}) onnxruntime_set_compile_flags(${target_name}) onnxruntime_set_source_file_properties(${target_name}) - #Uncomment the following three lines to reproduce static analysis errors locally - #if(WIN32 AND onnxruntime_ENABLE_STATIC_ANALYSIS) - # set_target_properties(${target_name} PROPERTIES VS_USER_PROPS ${PROJECT_SOURCE_DIR}/EnableVisualStudioCodeAnalysis.props) - #endif() + if(WIN32 AND onnxruntime_ENABLE_STATIC_ANALYSIS AND onnxruntime_USE_CUSTOM_STATIC_ANALYSIS_RULES) + set_target_properties(${target_name} PROPERTIES VS_USER_PROPS ${PROJECT_SOURCE_DIR}/EnableVisualStudioCodeAnalysis.props) + endif() target_include_directories(${target_name} PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${ONNXRUNTIME_ROOT} ${abseil_cpp_SOURCE_DIR}) - if (onnxruntime_ENABLE_TRAINING_APIS) + if (onnxruntime_ENABLE_TRAINING_OPS) target_include_directories(${target_name} PRIVATE ${ORTTRAINING_ROOT}) endif() if (onnxruntime_ENABLE_LTO) @@ -936,7 +1030,16 @@ function(onnxruntime_add_shared_library_module target_name) endif() onnxruntime_configure_target(${target_name}) - if (MSVC AND onnxruntime_target_platform STREQUAL "x86" AND NOT onnxruntime_BUILD_WEBASSEMBLY) + if (MSVC AND onnxruntime_target_platform STREQUAL "x86") + target_link_options(${target_name} PRIVATE /SAFESEH) + endif() +endfunction() + +function(onnxruntime_add_object_library target_name) + add_library(${target_name} OBJECT ${ARGN}) + + onnxruntime_configure_target(${target_name}) + if (MSVC AND onnxruntime_target_platform STREQUAL "x86") target_link_options(${target_name} PRIVATE /SAFESEH) endif() endfunction() @@ -944,7 +1047,7 @@ endfunction() function(onnxruntime_add_executable target_name) add_executable(${target_name} ${ARGN}) onnxruntime_configure_target(${target_name}) - if (MSVC AND onnxruntime_target_platform STREQUAL "x86" AND NOT onnxruntime_BUILD_WEBASSEMBLY) + if (MSVC AND onnxruntime_target_platform STREQUAL "x86") target_link_options(${target_name} PRIVATE /SAFESEH) endif() endfunction() @@ -1139,17 +1242,19 @@ if (onnxruntime_USE_OPENVINO) elseif ($ENV{INTEL_OPENVINO_DIR} MATCHES "2022.3") set(OPENVINO_VERSION "2022.3") add_definitions(-DOPENVINO_2022_3=1) + elseif ($ENV{INTEL_OPENVINO_DIR} MATCHES "2023.0") + set(OPENVINO_VERSION "2023.0") + add_definitions(-DOPENVINO_2023_0=1) + elseif ($ENV{INTEL_OPENVINO_DIR} MATCHES "2023.1") + set(OPENVINO_VERSION "2023.1") + add_definitions(-DOPENVINO_2023_1=1) elseif ($ENV{INTEL_OPENVINO_DIR} MATCHES "openvino") - set(OPENVINO_VERSION "2022.3") - add_definitions(-DOPENVINO_2022_3=1) + set(OPENVINO_VERSION "2023.1") + add_definitions(-DOPENVINO_2023_1=1) else() message(FATAL_ERROR "Unsupported OpenVINO version: ${INTEL_OPENVINO_DIR}") endif() - if (onnxruntime_USE_OPENVINO_MYRIAD) - add_definitions(-DOPENVINO_CONFIG_MYRIAD=1) - endif() - if (onnxruntime_USE_OPENVINO_GPU_FP32) add_definitions(-DOPENVINO_CONFIG_GPU_FP32=1) endif() @@ -1166,17 +1271,12 @@ if (onnxruntime_USE_OPENVINO) add_definitions(-DOPENVINO_CONFIG_CPU_FP16=1) endif() - if (onnxruntime_USE_OPENVINO_VAD_M) - add_definitions(-DOPENVINO_CONFIG_VAD_M=1) + if (onnxruntime_USE_OPENVINO_VPUX_FP16) + add_definitions(-DOPENVINO_CONFIG_VPUX_FP16=1) endif() - if (onnxruntime_USE_OPENVINO_VAD_F) - add_definitions(-DOPENVINO_CONFIG_VAD_F=1) - endif() - - if (onnxruntime_USE_OPENVINO_MYRIAD_NP) - add_definitions(-DOPENVINO_CONFIG_MYRIAD=1) - add_definitions(-DOPENVINO_DISABLE_GRAPH_PARTITION=1) + if (onnxruntime_USE_OPENVINO_VPUX_U8) + add_definitions(-DOPENVINO_CONFIG_VPUX_U8=1) endif() if (onnxruntime_USE_OPENVINO_GPU_FP32_NP) @@ -1199,13 +1299,13 @@ if (onnxruntime_USE_OPENVINO) add_definitions(-DOPENVINO_DISABLE_GRAPH_PARTITION=1) endif() - if (onnxruntime_USE_OPENVINO_VAD_M_NP) - add_definitions(-DOPENVINO_CONFIG_VAD_M=1) + if (onnxruntime_USE_OPENVINO_VPUX_FP32_NP) + add_definitions(-DOPENVINO_CONFIG_VPUX_FP32=1) add_definitions(-DOPENVINO_DISABLE_GRAPH_PARTITION=1) endif() - if (onnxruntime_USE_OPENVINO_VAD_F_NP) - add_definitions(-DOPENVINO_CONFIG_VAD_F=1) + if (onnxruntime_USE_OPENVINO_VPUX_FP16_NP) + add_definitions(-DOPENVINO_CONFIG_VPUX_FP16=1) add_definitions(-DOPENVINO_DISABLE_GRAPH_PARTITION=1) endif() @@ -1231,17 +1331,27 @@ if (onnxruntime_USE_OPENVINO) endif() if (onnxruntime_USE_VITISAI) - if (WIN32) - message(FATAL_ERROR "Vitis-AI execution provider is not supported on Windows.") - else() - include(pyxir) - list(APPEND onnxruntime_EXTERNAL_LIBRARIES pyxir) - list(APPEND onnxruntime_EXTERNAL_DEPENDENCIES pyxir) - endif() -endif() - + set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_LIST_DIR}") +endif() + +set(ORT_BUILD_INFO "ORT Build Info: ") +find_package(Git) +if (Git_FOUND) + execute_process(COMMAND ${GIT_EXECUTABLE} log -1 --format=%h + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE ORT_GIT_COMMIT) + string(STRIP "${ORT_GIT_COMMIT}" ORT_GIT_COMMIT) + execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE ORT_GIT_BRANCH) + string(STRIP "${ORT_GIT_BRANCH}" ORT_GIT_BRANCH) + string(APPEND ORT_BUILD_INFO "git-branch=${ORT_GIT_BRANCH}, git-commit-id=${ORT_GIT_COMMIT}, ") +endif() +string(APPEND ORT_BUILD_INFO "build type=${CMAKE_BUILD_TYPE}") +string(APPEND ORT_BUILD_INFO ", cmake cxx flags: ${CMAKE_CXX_FLAGS}") configure_file(onnxruntime_config.h.in ${CMAKE_CURRENT_BINARY_DIR}/onnxruntime_config.h) -if (WIN32) +get_property(onnxruntime_GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if (onnxruntime_GENERATOR_IS_MULTI_CONFIG) configure_file(../requirements.txt.in ${CMAKE_CURRENT_BINARY_DIR}/Debug/requirements.txt) configure_file(../requirements.txt.in ${CMAKE_CURRENT_BINARY_DIR}/Release/requirements.txt) configure_file(../requirements.txt.in ${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo/requirements.txt) @@ -1271,9 +1381,9 @@ if (onnxruntime_USE_CUDA) set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -gencode=arch=compute_30,code=sm_30") # K series endif() 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 + # 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() 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 @@ -1390,6 +1500,7 @@ if (UNIX AND onnxruntime_USE_MPI) find_path(NCCL_INCLUDE_DIR NAMES ${NCCL_LIBNAME}.h HINTS + ${onnxruntime_NCCL_HOME}/include/rccl ${onnxruntime_NCCL_HOME}/include $ENV{CUDA_ROOT}/include) @@ -1556,7 +1667,7 @@ if (onnxruntime_BUILD_CSHARP) list(APPEND ONNXRUNTIME_CMAKE_FILES onnxruntime_csharp) endif() -if (onnxruntime_BUILD_WEBASSEMBLY) +if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") message(STATUS "WebAssembly Build is enabled") list(APPEND ONNXRUNTIME_CMAKE_FILES onnxruntime_webassembly) @@ -1627,3 +1738,31 @@ if (onnxruntime_ENABLE_EXTERNAL_CUSTOM_OP_SCHEMAS) COMMENT "Installing protobuf" ) endif() + +if(TARGET onnxruntime) +# Install + include(GNUInstallDirs) + include(CMakePackageConfigHelpers) + set(PROJECT_CONFIG_CONTENT "@PACKAGE_INIT@\n") + string(APPEND PROJECT_CONFIG_CONTENT + "include(\"\${CMAKE_CURRENT_LIST_DIR}/${PROJECT_NAME}Targets.cmake\")") + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/PROJECT_CONFIG_FILE" ${PROJECT_CONFIG_CONTENT}) + install(EXPORT ${PROJECT_NAME}Targets + NAMESPACE ${PROJECT_NAME}:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) +# Create config for find_package() + configure_package_config_file( + "${CMAKE_CURRENT_BINARY_DIR}/PROJECT_CONFIG_FILE" ${PROJECT_NAME}Config.cmake + INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") + + write_basic_package_version_file( + "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" + VERSION ${ORT_VERSION} + COMPATIBILITY SameMajorVersion) + + install( + FILES + "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") +endif() diff --git a/cmake/Sdl.ruleset b/cmake/Sdl.ruleset index 7ca26ad5d28ad..5ab2341f6a1df 100644 --- a/cmake/Sdl.ruleset +++ b/cmake/Sdl.ruleset @@ -184,7 +184,6 @@ - diff --git a/cmake/adjust_global_compile_flags.cmake b/cmake/adjust_global_compile_flags.cmake index 58a9271d26e7f..e825bfeaea952 100644 --- a/cmake/adjust_global_compile_flags.cmake +++ b/cmake/adjust_global_compile_flags.cmake @@ -15,7 +15,7 @@ if (NOT MSVC AND NOT onnxruntime_ENABLE_BITCODE) string(APPEND CMAKE_C_FLAGS " -ffunction-sections -fdata-sections") endif() -if (onnxruntime_BUILD_WEBASSEMBLY) +if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") string(APPEND CMAKE_C_FLAGS " -s STRICT=1 -s DEFAULT_TO_CXX=1") string(APPEND CMAKE_CXX_FLAGS " -s STRICT=1 -s DEFAULT_TO_CXX=1") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s ALLOW_UNIMPLEMENTED_SYSCALLS=1") @@ -51,10 +51,8 @@ if (onnxruntime_BUILD_WEBASSEMBLY) # Build WebAssembly with multi-threads support. if (onnxruntime_ENABLE_WEBASSEMBLY_THREADS) - string(APPEND CMAKE_C_FLAGS " -pthread") - string(APPEND CMAKE_CXX_FLAGS " -pthread") - string(APPEND CMAKE_C_FLAGS " -s USE_PTHREADS=1 -Wno-pthreads-mem-growth") - string(APPEND CMAKE_CXX_FLAGS " -s USE_PTHREADS=1 -Wno-pthreads-mem-growth") + string(APPEND CMAKE_C_FLAGS " -pthread -Wno-pthreads-mem-growth") + string(APPEND CMAKE_CXX_FLAGS " -pthread -Wno-pthreads-mem-growth") endif() endif() @@ -222,27 +220,30 @@ endmacro() #Set global compile flags for all the source code(including third_party code like protobuf) #This section must be before any add_subdirectory, otherwise build may fail because /MD,/MT mismatch if (MSVC) - enable_language(ASM_MASM) - if (CMAKE_GENERATOR_PLATFORM) + if (CMAKE_VS_PLATFORM_NAME) # Multi-platform generator - set(onnxruntime_target_platform ${CMAKE_GENERATOR_PLATFORM}) + set(onnxruntime_target_platform ${CMAKE_VS_PLATFORM_NAME}) else() set(onnxruntime_target_platform ${CMAKE_SYSTEM_PROCESSOR}) endif() if (onnxruntime_target_platform STREQUAL "ARM64") set(onnxruntime_target_platform "ARM64") + enable_language(ASM_MARMASM) elseif (onnxruntime_target_platform STREQUAL "ARM64EC") - set(onnxruntime_target_platform "ARM64EC") + enable_language(ASM_MARMASM) elseif (onnxruntime_target_platform STREQUAL "ARM" OR CMAKE_GENERATOR MATCHES "ARM") set(onnxruntime_target_platform "ARM") + enable_language(ASM_MARMASM) elseif (onnxruntime_target_platform STREQUAL "x64" OR onnxruntime_target_platform STREQUAL "x86_64" OR onnxruntime_target_platform STREQUAL "AMD64" OR CMAKE_GENERATOR MATCHES "Win64") set(onnxruntime_target_platform "x64") + enable_language(ASM_MASM) elseif (onnxruntime_target_platform STREQUAL "Win32" OR onnxruntime_target_platform STREQUAL "x86" OR onnxruntime_target_platform STREQUAL "i386" OR onnxruntime_target_platform STREQUAL "i686") set(onnxruntime_target_platform "x86") - if (NOT onnxruntime_BUILD_WEBASSEMBLY) - message("Enabling SAFESEH for x86 build") - set(CMAKE_ASM_MASM_FLAGS "${CMAKE_ASM_MASM_FLAGS} /safeseh") - endif() + enable_language(ASM_MASM) + message("Enabling SAFESEH for x86 build") + set(CMAKE_ASM_MASM_FLAGS "${CMAKE_ASM_MASM_FLAGS} /safeseh") + else() + message(FATAL_ERROR "Unknown CMAKE_SYSTEM_PROCESSOR: ${CMAKE_SYSTEM_PROCESSOR}") endif() @@ -254,10 +255,7 @@ if (MSVC) string(APPEND CMAKE_CXX_FLAGS " /wd26812") string(APPEND CMAKE_C_FLAGS " /wd26812") endif() - # We do not treat 3rd-party libraries' warnings as errors. In order to do that, we need to add their header files locations to /external:I. - # However, if a 3rd-party library was installed to a non-standard location and cmake find it and use it from there, you may see build errors - # like: "error C2220: the following warning is treated as an error" - string(APPEND CMAKE_CXX_FLAGS " /experimental:external /external:W0 /external:templates- /external:I ${CMAKE_CURRENT_SOURCE_DIR} /external:I ${CMAKE_CURRENT_BINARY_DIR}") + if (onnxruntime_USE_AVX) string(APPEND CMAKE_CXX_FLAGS " /arch:AVX") string(APPEND CMAKE_C_FLAGS " /arch:AVX") @@ -321,6 +319,11 @@ else() string(APPEND CMAKE_CXX_FLAGS " -g -O0 --coverage ") string(APPEND CMAKE_C_FLAGS " -g -O0 --coverage ") endif() + if("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") + # suppress warnings from flatbuffers + string(APPEND CMAKE_CXX_FLAGS " -Wno-restrict ") + string(APPEND CMAKE_C_FLAGS " -Wno-restrict ") + endif() # Check support for AVX and f16c. include(CheckCXXCompilerFlag) check_cxx_compiler_flag("-mf16c" COMPILER_SUPPORT_MF16C) @@ -354,14 +357,12 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") #For Mac compliance message("Adding flags for Mac builds") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fstack-protector-strong") -endif() - -if (WIN32) +elseif (WIN32) # parallel build # These compiler opitions cannot be forwarded to NVCC, so cannot use add_compiler_options string(APPEND CMAKE_CXX_FLAGS " /MP") # required to be set explicitly to enable Eigen-Unsupported SpecialFunctions string(APPEND CMAKE_CXX_FLAGS " -DEIGEN_HAS_C99_MATH") -elseif(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin") +else() add_compile_definitions("_GNU_SOURCE") endif() diff --git a/cmake/deps.txt b/cmake/deps.txt index d0a5cf7aa4800..279b5ca649dba 100644 --- a/cmake/deps.txt +++ b/cmake/deps.txt @@ -5,42 +5,43 @@ #URLs can be either https URLs or local file paths in cmake-style(directory separator is a forward slash character). #SHA1 hashes can be generated by running sha1sum command. #If you need to change abseil's version to a different one, you may also want to update external\abseil-cpp.natvis -#since the file contains a version string: "lts_20220623". However, the file is for debugging purposes only and would +#since the file contains a version string: "lts_20230802". However, the file is for debugging purposes only and would #not affect built binaries. -abseil_cpp;https://github.com/abseil/abseil-cpp/archive/refs/tags/20220623.1.zip;50c137c88965cba015dfcc8fd5d9b46d23146751 +abseil_cpp;https://github.com/abseil/abseil-cpp/archive/refs/tags/20230802.0.zip;04271dfbfac59269b6939e1e9d5faf0d18a7ba91 cxxopts;https://github.com/jarro2783/cxxopts/archive/3c73d91c0b04e2b59462f0a741be8c07024c1bc0.zip;6c6ca7f8480b26c8d00476e0e24b7184717fe4f0 -date;https://github.com/HowardHinnant/date/archive/refs/tags/v2.4.1.zip;ea99f021262b1d804a872735c658860a6a13cc98 +date;https://github.com/HowardHinnant/date/archive/refs/tags/v3.0.1.zip;2dac0c81dc54ebdd8f8d073a75c053b04b56e159 dlpack;https://github.com/dmlc/dlpack/archive/refs/tags/v0.6.zip;4d565dd2e5b31321e5549591d78aa7f377173445 +eigen;https://gitlab.com/libeigen/eigen/-/archive/3.4/eigen-3.4.zip;ee201b07085203ea7bd8eb97cbcb31b07cfa3efb flatbuffers;https://github.com/google/flatbuffers/archive/refs/tags/v1.12.0.zip;ba0a75fd12dbef8f6557a74e611b7a3d0c5fe7bf fp16;https://github.com/Maratyszcza/FP16/archive/0a92994d729ff76a58f692d3028ca1b64b145d91.zip;b985f6985a05a1c03ff1bb71190f66d8f98a1494 fxdiv;https://github.com/Maratyszcza/FXdiv/archive/63058eff77e11aa15bf531df5dd34395ec3017c8.zip;a5658f4036402dbca7cebee32be57fb8149811e1 google_benchmark;https://github.com/google/benchmark/archive/refs/tags/v1.7.0.zip;e97c368b176e8614e3f1bf13dd9abcf6a7ad9908 -google_nsync;https://github.com/google/nsync/archive/refs/tags/1.23.0.zip;f3233450cf7156fc0bedd1b0e884eddec264897c -googletest;https://github.com/google/googletest/archive/519beb0e52c842729b4b53731d27c0e0c32ab4a2.zip;4b3c37972e4c1bef1185d46f702082f8772ee73f +google_nsync;https://github.com/google/nsync/archive/refs/tags/1.26.0.zip;5e7c00ef6bf5b787386fc040067903ec774e2752 +googletest;https://github.com/google/googletest/archive/refs/tags/v1.14.0.zip;0ac421f2ec11af38b0fff0f1992184032731a8bc googlexnnpack;https://github.com/google/XNNPACK/archive/003c580e696a774afdc984996ee909b7c8d8128c.zip;9f192e3f15e1e37ae9c78d53eeea47e45c5eb31c json;https://github.com/nlohmann/json/archive/refs/tags/v3.10.5.zip;f257f8dc27c5b8c085dc887b40cddd18ae1f725c microsoft_gsl;https://github.com/microsoft/GSL/archive/refs/tags/v4.0.0.zip;cf368104cd22a87b4dd0c80228919bb2df3e2a14 -microsoft_wil;https://github.com/microsoft/wil/archive/5f4caba4e7a9017816e47becdd918fcc872039ba.zip;fd119887d0d17c37adf1fc227b054befa28158ad +microsoft_wil;https://github.com/microsoft/wil/archive/refs/tags/v1.0.230629.1.zip;e4a542a323c070376f7c2d1973d0f7ddbc1d2fa5 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.79.0.zip;c8f04e378535ededbe5af52c8f969d2dedbe73d5 -onnx;https://github.com/onnx/onnx/archive/3b58938e025c41d2fcd89fa22028eefaa81a18ad.zip;e0e5dda9eea5cd5ecae3bd8be86e477016b6be02 -#use the last commit of 8.6-EA branch (https://github.com/onnx/onnx-tensorrt/commit/ba6a4fb34fdeaa3613bf981610c657e7b663a699) -onnx_tensorrt;https://github.com/onnx/onnx-tensorrt/archive/ba6a4fb34fdeaa3613bf981610c657e7b663a699.zip;5a474ed86e2c4ee4085d3daeff8222866e933dc0 +mp11;https://github.com/boostorg/mp11/archive/refs/tags/boost-1.82.0.zip;9bc9e01dffb64d9e0773b2e44d2f22c51aace063 +onnx;https://github.com/onnx/onnx/archive/e2525550194ce3d8a2c4a3af451c9d9b3ae6650e.zip;782f23d788185887f520a90535513e244218e928 +#use the commit of supporting all the plugins and TRT 8.6-GA (https://github.com/onnx/onnx-tensorrt/commit/0462dc31ae78f48744b6141ae376df1f96d3f459) +onnx_tensorrt;https://github.com/onnx/onnx-tensorrt/archive/0462dc31ae78f48744b6141ae376df1f96d3f459.zip;5ff086361956cceb81ed17453a1fd8db2aa4328d 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 +protoc_linux_x64;https://github.com/protocolbuffers/protobuf/releases/download/v21.12/protoc-21.12-linux-x86_64.zip;338462004aa5be9fba45b35b5b4be43f69b47a90 +protoc_linux_x86;https://github.com/protocolbuffers/protobuf/releases/download/v21.12/protoc-21.12-linux-x86_32.zip;61fdbe7d6360e065ec6fea23bca2cca673115fb8 +protoc_linux_aarch64;https://github.com/protocolbuffers/protobuf/releases/download/v21.12/protoc-21.12-linux-aarch_64.zip;df9d45470b0b8cf939dd2f0ec6b88e9cafc4d617 +protoc_mac_universal;https://github.com/protocolbuffers/protobuf/releases/download/v21.12/protoc-21.12-osx-universal_binary.zip;23710c3d1c2036d8d65a6a22234372fa2d7af9ef psimd;https://github.com/Maratyszcza/psimd/archive/072586a71b55b7f8c584153d223e95687148a900.zip;1f5454b01f06f9656b77e4a5e2e31d7422487013 pthreadpool;https://github.com/Maratyszcza/pthreadpool/archive/1787867f6183f056420e532eec640cba25efafea.zip;e43e80781560c5ab404a4da20f34d846f5f5d101 pybind11;https://github.com/pybind/pybind11/archive/refs/tags/v2.10.1.zip;769b6aa67a77f17a770960f604b727645b6f6a13 -pytorch_cpuinfo;https://github.com/pytorch/cpuinfo/archive/5916273f79a21551890fd3d56fc5375a78d1598d.zip;2be4d2ae321fada97cb39eaf4eeba5f8c85597cf +pytorch_cpuinfo;https://github.com/pytorch/cpuinfo/archive/959002f82d7962a473d8bf301845f2af720e0aa4.zip;85da3caa60eb2b148613b443fbc2bfdc30689965 re2;https://github.com/google/re2/archive/refs/tags/2022-06-01.zip;aa77313b76e91b531ee7f3e45f004c6a502a5374 -safeint;https://github.com/dcleblanc/SafeInt/archive/ff15c6ada150a5018c5ef2172401cb4529eac9c0.zip;913a4046e5274d329af2806cb53194f617d8c0ab +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.0.0.zip;0f95b3c1fc1bd1175c4a90b2c9e39074d1bccefd -# below are deps introduced by triton client, might remove after 1.14 release -openssl;https://github.com/openssl/openssl/archive/refs/tags/openssl-3.0.7.zip;dda8fc81308555410505eb4a9eab3e1da0436a1d -rapidjson;https://github.com/Tencent/rapidjson/archive/refs/tags/v1.1.0.zip;0fe7b4f7b83df4b3d517f4a202f3a383af7a0818 -boost;https://github.com/boostorg/boost/archive/refs/tags/boost-1.81.0.zip;f6ab0da855f825b4eb1abd949967d01a4c5e4e1b -b64;https://github.com/libb64/libb64/archive/refs/tags/v2.0.0.1.zip;815b6d31d50d9e63df55b25ce555e7b787153c28 -pthread;https://sourceforge.net/projects/pthreads4w/files/pthreads4w-code-v3.0.0.zip;3b9e417e4474c34542b76ad40529e396ac109fb4 -triton;https://github.com/triton-inference-server/server/archive/refs/tags/v2.28.0.zip;4b305570aa1e889946e20e36050b6770e4108fee -# above are deps introduced by triton client, might remove after 1.14 release -extensions;https://github.com/microsoft/onnxruntime-extensions/archive/81e7799c69044c745239202085eb0a98f102937b.zip;d53487035174a046628359289ad27aa0ac0380c9 +utf8_range;https://github.com/protocolbuffers/utf8_range/archive/72c943dea2b9240cd09efde15191e144bc7c7d38.zip;9925739c9debc0efa2adcb194d371a35b6a03156 +extensions;https://github.com/microsoft/onnxruntime-extensions/archive/94142d8391c9791ec71c38336436319a2d4ac7a0.zip;4365ac5140338b4cb75a39944a4be276e3829b3c +composable_kernel;https://github.com/ROCmSoftwarePlatform/composable_kernel/archive/d52ec01652b7d620386251db92455968d8d90bdc.zip;6b5ce8edf3625f8817086c194fbf94b664e1b0e0 \ No newline at end of file diff --git a/cmake/external/abseil-cpp.cmake b/cmake/external/abseil-cpp.cmake index 54d2f9c5c19df..3bcd4109e2888 100644 --- a/cmake/external/abseil-cpp.cmake +++ b/cmake/external/abseil-cpp.cmake @@ -6,15 +6,20 @@ include(FetchContent) # Pass to build set(ABSL_PROPAGATE_CXX_STD 1) set(BUILD_TESTING 0) - +set(ABSL_BUILD_TESTING OFF) +set(ABSL_BUILD_TEST_HELPERS OFF) +set(ABSL_USE_EXTERNAL_GOOGLETEST ON) if(Patch_FOUND AND WIN32) set(ABSL_PATCH_COMMAND ${Patch_EXECUTABLE} --binary --ignore-whitespace -p1 < ${PROJECT_SOURCE_DIR}/patches/abseil/absl_windows.patch) else() set(ABSL_PATCH_COMMAND "") endif() - +if(WIN32 AND NOT Patch_FOUND) + #see https://github.com/google/re2/issues/425 and https://github.com/google/re2/issues/436 + set(ABSL_ENABLE_INSTALL ON) +endif() # NB! Advancing Abseil version changes its internal namespace, -# currently absl::lts_20211102 which affects abseil-cpp.natvis debugger +# currently absl::lts_20230125 which affects abseil-cpp.natvis debugger # visualization file, that must be adjusted accordingly, unless we eliminate # that namespace at build time. FetchContent_Declare( @@ -22,6 +27,7 @@ FetchContent_Declare( URL ${DEP_URL_abseil_cpp} URL_HASH SHA1=${DEP_SHA1_abseil_cpp} PATCH_COMMAND ${ABSL_PATCH_COMMAND} + FIND_PACKAGE_ARGS NAMES absl ) onnxruntime_fetchcontent_makeavailable(abseil_cpp) @@ -37,8 +43,26 @@ if (GDK_PLATFORM) target_compile_definitions(absl_symbolize PRIVATE WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP) endif() -if(NOT onnxruntime_DISABLE_ABSEIL) - set(ABSEIL_LIBS absl::inlined_vector absl::flat_hash_set - absl::flat_hash_map absl::node_hash_set absl::node_hash_map absl::base absl::throw_delegate absl::raw_hash_set - absl::hash absl::city absl::low_level_hash absl::raw_logging_internal) -endif() \ No newline at end of file +# TODO: since multiple ORT's dependencies depend on Abseil, the list below would vary from version to version. +# We'd better to not manually manage the list. +set(ABSEIL_LIBS absl::base +absl::city +absl::core_headers +absl::fixed_array +absl::flags +absl::flat_hash_map +absl::flat_hash_set +absl::hash +absl::inlined_vector +absl::low_level_hash +absl::node_hash_map +absl::node_hash_set +absl::optional +absl::raw_hash_set +absl::raw_logging_internal +absl::span +absl::str_format +absl::strings +absl::synchronization +absl::throw_delegate +absl::time) diff --git a/cmake/external/abseil-cpp.natvis b/cmake/external/abseil-cpp.natvis index e0294ba6f7b55..e923d5862ec2e 100644 --- a/cmake/external/abseil-cpp.natvis +++ b/cmake/external/abseil-cpp.natvis @@ -1,6 +1,6 @@ - + @@ -24,7 +24,7 @@ - + empty {{ size={size_} }} @@ -44,7 +44,7 @@ - + {{ {value.first}:{value.second} }} value.first diff --git a/cmake/external/composable_kernel.cmake b/cmake/external/composable_kernel.cmake index fe57a5b5325e2..7168cd1a22c53 100644 --- a/cmake/external/composable_kernel.cmake +++ b/cmake/external/composable_kernel.cmake @@ -1,23 +1,24 @@ -set(composable_kernel_URL https://github.com/ROCmSoftwarePlatform/composable_kernel.git) -set(composable_kernel_TAG ed3a2e52265e11daa366f47b082141a652b67c58) # 2023-04-10 21:02:17 +0800 - set(PATCH ${PROJECT_SOURCE_DIR}/patches/composable_kernel/Fix_Clang_Build.patch) include(FetchContent) FetchContent_Declare(composable_kernel - GIT_REPOSITORY ${composable_kernel_URL} - GIT_TAG ${composable_kernel_TAG} - PATCH_COMMAND git apply --reverse --check ${PATCH} || git apply --ignore-space-change --ignore-whitespace ${PATCH} + URL ${DEP_URL_composable_kernel} + URL_HASH SHA1=${DEP_SHA1_composable_kernel} + PATCH_COMMAND ${Patch_EXECUTABLE} --binary --ignore-whitespace -p1 < ${PATCH} ) FetchContent_GetProperties(composable_kernel) if(NOT composable_kernel_POPULATED) FetchContent_Populate(composable_kernel) set(BUILD_DEV OFF CACHE BOOL "Disable -Weverything, otherwise, error: 'constexpr' specifier is incompatible with C++98 [-Werror,-Wc++98-compat]" FORCE) + # Exclude i8 device gemm instances due to excessive long compilation time and not being used + set(DTYPES fp32 fp16 bf16) + set(INSTANCES_ONLY ON) add_subdirectory(${composable_kernel_SOURCE_DIR} ${composable_kernel_BINARY_DIR} EXCLUDE_FROM_ALL) add_library(onnxruntime_composable_kernel_includes INTERFACE) target_include_directories(onnxruntime_composable_kernel_includes INTERFACE ${composable_kernel_SOURCE_DIR}/include ${composable_kernel_SOURCE_DIR}/library/include) + target_compile_definitions(onnxruntime_composable_kernel_includes INTERFACE __fp32__ __fp16__ __bf16__) endif() diff --git a/cmake/external/cutlass.cmake b/cmake/external/cutlass.cmake index 18ac668bb1592..8c5d81d638ced 100644 --- a/cmake/external/cutlass.cmake +++ b/cmake/external/cutlass.cmake @@ -1,4 +1,4 @@ -if (onnxruntime_USE_FLASH_ATTENTION) +if (onnxruntime_USE_FLASH_ATTENTION OR onnxruntime_USE_MEMORY_EFFICIENT_ATTENTION) include(FetchContent) FetchContent_Declare( cutlass diff --git a/cmake/external/dml.cmake b/cmake/external/dml.cmake index 78813fa4498cc..5d25b9529e030 100644 --- a/cmake/external/dml.cmake +++ b/cmake/external/dml.cmake @@ -20,6 +20,7 @@ set(onnxruntime_USE_CUSTOM_DIRECTML OFF CACHE BOOL "Depend on a custom/internal build of DirectML.") set(dml_EXTERNAL_PROJECT OFF CACHE BOOL "Build DirectML as a source dependency.") +set(DML_SHARED_LIB DirectML.dll) if (NOT onnxruntime_USE_CUSTOM_DIRECTML) if (NOT(MSVC) OR NOT(WIN32)) @@ -40,8 +41,7 @@ if (NOT onnxruntime_USE_CUSTOM_DIRECTML) set(NUGET_CONFIG ${PROJECT_SOURCE_DIR}/../NuGet.config) set(PACKAGES_CONFIG ${PROJECT_SOURCE_DIR}/../packages.config) get_filename_component(PACKAGES_DIR ${CMAKE_CURRENT_BINARY_DIR}/../packages ABSOLUTE) - set(DML_PACKAGE_DIR ${PACKAGES_DIR}/Microsoft.AI.DirectML.1.10.1) - set(DML_SHARED_LIB DirectML.dll) + set(DML_PACKAGE_DIR ${PACKAGES_DIR}/Microsoft.AI.DirectML.1.12.1) # Restore nuget packages, which will pull down the DirectML redist package. add_custom_command( @@ -72,12 +72,12 @@ else() if (dml_EXTERNAL_PROJECT) set(dml_preset_config $,debug,release>) set(dml_preset_name ${onnxruntime_target_platform}-win-redist-${dml_preset_config}) - + target_compile_definitions(DirectML INTERFACE DML_TARGET_VERSION_USE_LATEST=1) include(ExternalProject) ExternalProject_Add( directml_repo GIT_REPOSITORY https://dev.azure.com/microsoft/WindowsAI/_git/DirectML - GIT_TAG 2290bd6495fdf8c35822816213516d13f3742cc9 + GIT_TAG d460f0f46967bea878786f1bed69487692c779bf GIT_SHALLOW OFF # not allowed when GIT_TAG is a commit SHA, which is preferred (it's stable, unlike branches) GIT_PROGRESS ON BUILD_IN_SOURCE ON @@ -89,11 +89,13 @@ else() # Target that consumers can use to link with the internal build of DirectML. set(directml_install_path ${CMAKE_BINARY_DIR}/directml_repo-prefix/src/directml_repo/build/${dml_preset_name}/install) + set(DML_PACKAGE_DIR ${directml_install_path}) add_library(DirectML INTERFACE) target_link_libraries(DirectML INTERFACE ${directml_install_path}/lib/DirectML.lib) add_dependencies(DirectML directml_repo-install) include_directories(BEFORE ${directml_install_path}/include) else() - include_directories(${dml_INCLUDE_DIR}) + include_directories(BEFORE ${dml_INCLUDE_DIR}) + set(DML_PACKAGE_DIR ${dml_INCLUDE_DIR}/..) endif() endif() diff --git a/cmake/external/eigen b/cmake/external/eigen deleted file mode 160000 index d10b27fe37736..0000000000000 --- a/cmake/external/eigen +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d10b27fe37736d2944630ecd7557cefa95cf87c9 diff --git a/cmake/external/eigen.cmake b/cmake/external/eigen.cmake index 266dd534af64a..c0f7ddc50eb98 100644 --- a/cmake/external/eigen.cmake +++ b/cmake/external/eigen.cmake @@ -6,15 +6,17 @@ if (onnxruntime_USE_PREINSTALLED_EIGEN) else () if (onnxruntime_USE_ACL) FetchContent_Declare( - eigen - URL https://gitlab.com/libeigen/eigen/-/archive/d10b27fe37736d2944630ecd7557cefa95cf87c9/eigen-d10b27fe37736d2944630ecd7557cefa95cf87c9.zip - PATCH_COMMAND ${Patch_EXECUTABLE} --ignore-space-change --ignore-whitespace < ${PROJECT_SOURCE_DIR}/patches/eigen/Fix_Eigen_Build_Break.patch - ) + eigen + URL ${DEP_URL_eigen} + URL_HASH SHA1=${DEP_SHA1_eigen} + PATCH_COMMAND ${Patch_EXECUTABLE} --ignore-space-change --ignore-whitespace < ${PROJECT_SOURCE_DIR}/patches/eigen/Fix_Eigen_Build_Break.patch + ) else() FetchContent_Declare( - eigen - URL https://gitlab.com/libeigen/eigen/-/archive/d10b27fe37736d2944630ecd7557cefa95cf87c9/eigen-d10b27fe37736d2944630ecd7557cefa95cf87c9.zip - ) + eigen + URL ${DEP_URL_eigen} + URL_HASH SHA1=${DEP_SHA1_eigen} + ) endif() FetchContent_Populate(eigen) set(eigen_INCLUDE_DIRS "${eigen_SOURCE_DIR}") diff --git a/cmake/external/emsdk b/cmake/external/emsdk index 0ab19024f08c6..a896e3d066448 160000 --- a/cmake/external/emsdk +++ b/cmake/external/emsdk @@ -1 +1 @@ -Subproject commit 0ab19024f08c6673a713e454ef8bd95e174c807f +Subproject commit a896e3d066448b3530dbcaa48869fafefd738f57 diff --git a/cmake/external/extensions.cmake b/cmake/external/extensions.cmake index 5039929062445..68796ad02d982 100644 --- a/cmake/external/extensions.cmake +++ b/cmake/external/extensions.cmake @@ -22,7 +22,8 @@ if (onnxruntime_REDUCED_OPS_BUILD) endif() if (onnxruntime_WEBASSEMBLY_DEFAULT_EXTENSION_FLAGS) - set(OCOS_ENABLE_SPM_TOKENIZER ON CACHE INTERNAL "") + #The generated protobuf files in ORT-extension needs be updated to work with the current protobuf version ORT is using. + set(OCOS_ENABLE_SPM_TOKENIZER OFF CACHE INTERNAL "") set(OCOS_ENABLE_GPT2_TOKENIZER ON CACHE INTERNAL "") set(OCOS_ENABLE_WORDPIECE_TOKENIZER ON CACHE INTERNAL "") set(OCOS_ENABLE_BERT_TOKENIZER ON CACHE INTERNAL "") @@ -54,9 +55,11 @@ endif() target_include_directories(ocos_operators PRIVATE ${RE2_INCLUDE_DIR} ${json_SOURCE_DIR}/include) target_include_directories(ortcustomops PUBLIC ${onnxruntime_EXTENSIONS_PATH}/includes) if(OCOS_ENABLE_SPM_TOKENIZER) - onnxruntime_add_include_to_target(sentencepiece-static ${PROTOBUF_LIB}) + onnxruntime_add_include_to_target(sentencepiece-static ${PROTOBUF_LIB} ${ABSEIL_LIBS}) endif() -onnxruntime_add_include_to_target(ocos_operators ${PROTOBUF_LIB}) +onnxruntime_add_include_to_target(ocos_operators ${PROTOBUF_LIB} ${ABSEIL_LIBS}) +onnxruntime_add_include_to_target(noexcep_operators ${PROTOBUF_LIB} ${ABSEIL_LIBS}) + add_dependencies(ocos_operators ${onnxruntime_EXTERNAL_DEPENDENCIES}) add_dependencies(ortcustomops ${onnxruntime_EXTERNAL_DEPENDENCIES}) diff --git a/cmake/external/onnx b/cmake/external/onnx index 9b7bca2a723ff..e2525550194ce 160000 --- a/cmake/external/onnx +++ b/cmake/external/onnx @@ -1 +1 @@ -Subproject commit 9b7bca2a723ff94edcd007d93b5d0cf1838591dc +Subproject commit e2525550194ce3d8a2c4a3af451c9d9b3ae6650e diff --git a/cmake/external/onnx_minimal.cmake b/cmake/external/onnx_minimal.cmake index cf9429c185b46..65ff3fb148b11 100644 --- a/cmake/external/onnx_minimal.cmake +++ b/cmake/external/onnx_minimal.cmake @@ -27,18 +27,6 @@ target_compile_definitions(onnx_proto PUBLIC $ + + {{ { *(std::string*)((uintptr_t)(ptr_) & ~0x3) } }} + + + + - {{ {key_.tagged_ptr_}:{value_.tagged_ptr_} }} + {{ {_impl_.key_.tagged_ptr_}:{_impl_.value_.tagged_ptr_} }} - key_.tagged_ptr_ - value_.tagged_ptr_ + _impl_.key_.tagged_ptr_ + _impl_.value_.tagged_ptr_ - + - {{ tensor_name={tensor_name_.tagged_ptr_} }} + {{ tensor_name={_impl_.tensor_name_.tagged_ptr_} }} - tensor_name_.tagged_ptr_ - quant_parameter_tensor_names_ + _impl_.tensor_name_.tagged_ptr_ + _impl_.quant_parameter_tensor_names_ - - {{ name={name_.tagged_ptr_} }} + + {{ name={_impl_.name_.tagged_ptr_} }} - name_.tagged_ptr_ - type_ + _impl_.name_.tagged_ptr_ + _impl_.type_ _has_type() - {{ domain={ domain_.tagged_ptr_ }, version={ version_ } }} + {{ domain={ _impl_.domain_.tagged_ptr_ }, version={ _impl_.version_ } }} - - - - - {{ name={ name_.tagged_ptr_ }, type={ (AttributeProto_AttributeType)type_ } }} + + + + + {{ name={ _impl_.name_.tagged_ptr_ }, type={ (AttributeProto_AttributeType)_impl_.type_ } }} - name_.tagged_ptr_ - (AttributeProto_AttributeType)type_ - i_ - ints_ - f_ - floats_ - s_.tagged_ptr_ - strings_ - t_ - tensors_ - t_ - graphs_ - t_ - type_protos_ - sparse_tensor_ - sparse_tensors_ - ref_attr_name_.tagged_ptr_ - doc_string_.tagged_ptr_ + _impl_.name_.tagged_ptr_ + (AttributeProto_AttributeType)_impl_.type_ + _impl_.i_ + _impl_.ints_ + _impl_.f_ + _impl_.floats_ + _impl_.s_.tagged_ptr_ + _impl_.strings_ + _impl_.t_ + _impl_.tensors_ + _impl_.g_ + _impl_.graphs_ + _impl_.tp_ + _impl_.type_protos_ + _impl_.sparse_tensor_ + _impl_.sparse_tensors_ + _impl_.ref_attr_name_.tagged_ptr_ + _impl_.doc_string_.tagged_ptr_ _has_tensor() _has_graph() _has_type_proto() @@ -102,188 +108,191 @@ - {{ name={ name_.tagged_ptr_ }, domain={ domain_.tagged_ptr_ } }} + {{ name={ _impl_.name_.tagged_ptr_ }, domain={ _impl_.domain_.tagged_ptr_ } }} - name_.tagged_ptr_ - domain_.tagged_ptr_ - op_type_.tagged_ptr_ - input_ - output_ - attribute_ + _impl_.name_.tagged_ptr_ + _impl_.domain_.tagged_ptr_ + _impl_.op_type_.tagged_ptr_ + _impl_.input_ + _impl_.output_ + _impl_.attribute_ - + - {{ name={ name_.tagged_ptr_ }, domain={ domain_.tagged_ptr_ } }} + {{ name={ _impl_.name_.tagged_ptr_ } }} - opset_import_ - input_ - output_ - node_ - doc_string_.tagged_ptr_ + _impl_.input_ + _impl_.output_ + _impl_.node_ + _impl_.attribute_ + _impl_.attribute_proto_ + _impl_.doc_string_.tagged_ptr_ + _impl_.opset_import_ + _impl_.domain_.tagged_ptr_ - + - {{ name={ name_.tagged_ptr_ } }} + {{ name={ _impl_.name_.tagged_ptr_ } }} - name_.tagged_ptr_ - value_info_ - input_ - output_ - node_ - initializer_ - sparse_initializer_ - doc_string_.tagged_ptr_ + _impl_.name_.tagged_ptr_ + _impl_.value_info_ + _impl_.input_ + _impl_.output_ + _impl_.node_ + _impl_.initializer_ + _impl_.sparse_initializer_ + _impl_.doc_string_.tagged_ptr_ - + - {{ producer={producer_name_.tagged_ptr_}, domain={ domain_.tagged_ptr_ } }} + {{ producer={_impl_.producer_name_.tagged_ptr_}, domain={ _impl_.domain_.tagged_ptr_ } }} - opset_import_ - metadata_props_ - producer_version_.tagged_ptr_ - ir_version_ - model_version_ - doc_string_.tagged_ptr_ - graph_ + _impl_.opset_import_ + _impl_.metadata_props_ + _impl_.producer_version_.tagged_ptr_ + _impl_.ir_version_ + _impl_.model_version_ + _impl_.doc_string_.tagged_ptr_ + _impl_.graph_ - + - empty - {{ v = {value_.dim_value_} }} - {{ p = {value_.dim_param_.tagged_ptr_} }} + empty + {{ v = {_impl_.value_.dim_value_} }} + {{ p = {_impl_.value_.dim_param_.tagged_ptr_} }} - {{ size={ dim_.current_size_ } }} + {{ size={ _impl_.dim_.current_size_ } }} - dim_ + _impl_.dim_ - + - {{ type={ (ValueCase)*_oneof_case_ } }} + {{ type={ (ValueCase)*_impl_._oneof_case_ } }} - (ValueCase)*_oneof_case_ - value_.tensor_type_ - value_.sequence_type_ - value_.map_type_ - value_.sparse_tensor_type_ - value_.optional_type_ - denotation_.tagged_ptr_ + (ValueCase)*_impl_._oneof_case_ + _impl_.value_.tensor_type_ + _impl_.value_.sequence_type_ + _impl_.value_.map_type_ + _impl_.value_.sparse_tensor_type_ + _impl_.value_.optional_type_ + _impl_.denotation_.tagged_ptr_ - + - - {{ elem_type={ (TensorProto_DataType)elem_type_ } }} + + {{ elem_type={ (TensorProto_DataType)_impl_.elem_type_ } }} - (TensorProto_DataType)elem_type_ - shape_ + (TensorProto_DataType)_impl_.elem_type_ + _impl_.shape_ _has_shape() - + - - {{ elem_type={ *elem_type_ } }} + + {{ elem_type={ *_impl_.elem_type_ } }} - elem_type_ + _impl_.elem_type_ _has_element_type() - + - - {{ key_type={ (TensorProto_DataType)key_type_ } }} + + {{ key_type={ (TensorProto_DataType)_impl_.key_type_ } }} - (TensorProto_DataType)key_type_ - value_type_ + (TensorProto_DataType)_impl_.key_type_ + _impl_.value_type_ _has_value_type() - - {{ elem_type={ (TensorProto_DataType)elem_type_ } }} + + {{ elem_type={ (TensorProto_DataType)_impl_.elem_type_ } }} - (TensorProto_DataType)elem_type_ - shape_ + (TensorProto_DataType)_impl_.elem_type_ + _impl_.shape_ _has_shape() - - {{ elem_type={ *elem_type_ } }} + + {{ elem_type={ *_impl_.elem_type_ } }} - elem_type_ + _impl_.elem_type_ _has_element_type() - {{ begin={ begin_ }, end={ end_ } }} + {{ begin={ _impl_.begin_ }, end={ _impl_.end_ } }} - + - - - - - + + + + + - {{ name={name_.tagged_ptr_}, data_type={ (TensorProto_DataType)data_type_ } }} + {{ name={_impl_.name_.tagged_ptr_}, data_type={ (TensorProto_DataType)_impl_.data_type_ } }} - name_.tagged_ptr_ - (TensorProto_DataType)data_type_ + _impl_.name_.tagged_ptr_ + (TensorProto_DataType)_impl_.data_type_ 1 _shape_size_1() _shape_size_2() _shape_size_3() _shape_size_4() _shape_size_5() - dims_ - float_data_ - int32_data_ - int32_data_ - int32_data_ - int32_data_ - int64_data_ - int64_data_ - uint64_data_ - double_data_ - string_data_ - (std::string*)(raw_data_.tagged_ptr_.ptr_) - (TensorProto_DataLocation) data_location_ - external_data_ + _impl_.dims_ + _impl_.float_data_ + _impl_.int32_data_ + _impl_.int32_data_ + _impl_.int32_data_ + _impl_.int32_data_ + _impl_.int64_data_ + _impl_.int64_data_ + _impl_.uint64_data_ + _impl_.double_data_ + _impl_.string_data_ + _impl_.raw_data_.tagged_ptr_ + (TensorProto_DataLocation) _impl_.data_location_ + _impl_.external_data_ _has_raw_data() _has_data_location() _has_segment() - + - - + + {{ SparseTensorProto }} - dims_ - values_ - indices_ + _impl_.dims_ + _impl_.values_ + _impl_.indices_ _has_values() _has_indices() diff --git a/cmake/external/onnxruntime-extensions b/cmake/external/onnxruntime-extensions deleted file mode 160000 index 81e7799c69044..0000000000000 --- a/cmake/external/onnxruntime-extensions +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 81e7799c69044c745239202085eb0a98f102937b diff --git a/cmake/external/onnxruntime_external_deps.cmake b/cmake/external/onnxruntime_external_deps.cmake index 0c0dea7df2a82..e1671bcf43ed9 100644 --- a/cmake/external/onnxruntime_external_deps.cmake +++ b/cmake/external/onnxruntime_external_deps.cmake @@ -19,11 +19,10 @@ endforeach() message("Loading Dependencies ...") # ABSL should be included before protobuf because protobuf may use absl -if(NOT onnxruntime_DISABLE_ABSEIL) - include(external/abseil-cpp.cmake) -endif() +include(external/abseil-cpp.cmake) set(RE2_BUILD_TESTING OFF CACHE BOOL "" FORCE) + FetchContent_Declare( re2 URL ${DEP_URL_re2} @@ -34,19 +33,17 @@ FetchContent_Declare( if (onnxruntime_BUILD_UNIT_TESTS) # WebAssembly threading support in Node.js is still an experimental feature and # not working properly with googletest suite. - if (onnxruntime_BUILD_WEBASSEMBLY) + if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") set(gtest_disable_pthreads ON) endif() set(INSTALL_GTEST OFF CACHE BOOL "" FORCE) - if(NOT onnxruntime_DISABLE_ABSEIL) - # It uses both ABSL and re2 - set(GTEST_HAS_ABSL OFF CACHE BOOL "" FORCE) - endif() + # Set it to ON will cause crashes in onnxruntime_test_all when onnxruntime_USE_CUDA is ON + set(GTEST_HAS_ABSL OFF CACHE BOOL "" FORCE) # gtest and gmock FetchContent_Declare( googletest URL ${DEP_URL_googletest} - FIND_PACKAGE_ARGS NAMES GTest + FIND_PACKAGE_ARGS 1.14.0...<2.0.0 NAMES GTest URL_HASH SHA1=${DEP_SHA1_googletest} ) endif() @@ -84,22 +81,74 @@ FetchContent_Declare( # Flatbuffers # 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 onnxruntime_BUILD_WEBASSEMBLY) +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) endif() set(FLATBUFFERS_BUILD_TESTS OFF CACHE BOOL "FLATBUFFERS_BUILD_TESTS" FORCE) set(FLATBUFFERS_INSTALL OFF CACHE BOOL "FLATBUFFERS_INSTALL" FORCE) set(FLATBUFFERS_BUILD_FLATHASH OFF CACHE BOOL "FLATBUFFERS_BUILD_FLATHASH" FORCE) set(FLATBUFFERS_BUILD_FLATLIB ON CACHE BOOL "FLATBUFFERS_BUILD_FLATLIB" FORCE) +if(Patch_FOUND) + set(ONNXRUNTIME_FLATBUFFERS_PATCH_COMMAND ${Patch_EXECUTABLE} --binary --ignore-whitespace -p1 < ${PROJECT_SOURCE_DIR}/patches/flatbuffers/flatbuffers.patch) +else() + set(ONNXRUNTIME_FLATBUFFERS_PATCH_COMMAND "") +endif() #flatbuffers 1.11.0 does not have flatbuffers::IsOutRange, therefore we require 1.12.0+ FetchContent_Declare( flatbuffers URL ${DEP_URL_flatbuffers} URL_HASH SHA1=${DEP_SHA1_flatbuffers} + PATCH_COMMAND ${ONNXRUNTIME_FLATBUFFERS_PATCH_COMMAND} FIND_PACKAGE_ARGS 1.12.0...<2.0.0 NAMES Flatbuffers ) +# Download a protoc binary from Internet if needed +if(CMAKE_CROSSCOMPILING AND NOT ONNX_CUSTOM_PROTOC_EXECUTABLE) + # This part of code is only for users' convenience. The code couldn't handle all cases. Users always can manually + # download protoc from Protobuf's Github release page and pass the local path to the ONNX_CUSTOM_PROTOC_EXECUTABLE + # variable. + message("CMAKE_HOST_SYSTEM_NAME: ${CMAKE_HOST_SYSTEM_NAME}") + if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") + if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "AMD64") + FetchContent_Declare(protoc_binary URL ${DEP_URL_protoc_win64} URL_HASH SHA1=${DEP_SHA1_protoc_win64}) + FetchContent_Populate(protoc_binary) + elseif(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86") + FetchContent_Declare(protoc_binary URL ${DEP_URL_protoc_win32} URL_HASH SHA1=${DEP_SHA1_protoc_win32}) + FetchContent_Populate(protoc_binary) + endif() + if(protoc_binary_SOURCE_DIR) + message("Use prebuilt protoc") + set(ONNX_CUSTOM_PROTOC_EXECUTABLE ${protoc_binary_SOURCE_DIR}/bin/protoc.exe) + set(PROTOC_EXECUTABLE ${ONNX_CUSTOM_PROTOC_EXECUTABLE}) + endif() + elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") + if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "^(x86_64|amd64)$") + FetchContent_Declare(protoc_binary URL ${DEP_URL_protoc_linux_x64} URL_HASH SHA1=${DEP_SHA1_protoc_linux_x64}) + FetchContent_Populate(protoc_binary) + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(i.86|x86?)$") + FetchContent_Declare(protoc_binary URL ${DEP_URL_protoc_linux_x86} URL_HASH SHA1=${DEP_SHA1_protoc_linux_x86}) + FetchContent_Populate(protoc_binary) + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^aarch64.*") + FetchContent_Declare(protoc_binary URL ${DEP_URL_protoc_linux_aarch64} URL_HASH SHA1=${DEP_SHA1_protoc_linux_aarch64}) + FetchContent_Populate(protoc_binary) + endif() + if(protoc_binary_SOURCE_DIR) + message("Use prebuilt protoc") + set(ONNX_CUSTOM_PROTOC_EXECUTABLE ${protoc_binary_SOURCE_DIR}/bin/protoc) + set(PROTOC_EXECUTABLE ${ONNX_CUSTOM_PROTOC_EXECUTABLE}) + endif() + elseif ((CMAKE_SYSTEM_NAME STREQUAL "Emscripten" OR CMAKE_SYSTEM_NAME STREQUAL "Android" OR CMAKE_SYSTEM_NAME STREQUAL "iOS") AND CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin") + FetchContent_Declare(protoc_binary URL ${DEP_URL_protoc_mac_universal} URL_HASH SHA1=${DEP_SHA1_protoc_mac_universal}) + FetchContent_Populate(protoc_binary) + if(protoc_binary_SOURCE_DIR) + message("Use prebuilt protoc") + set(ONNX_CUSTOM_PROTOC_EXECUTABLE ${protoc_binary_SOURCE_DIR}/bin/protoc) + set(PROTOC_EXECUTABLE ${ONNX_CUSTOM_PROTOC_EXECUTABLE}) + endif() + endif() +endif() + #Here we support two build mode: #1. if ONNX_CUSTOM_PROTOC_EXECUTABLE is set, build Protobuf from source, except protoc.exe. This mode is mainly # for cross-compiling @@ -109,6 +158,19 @@ if(Patch_FOUND) else() set(ONNXRUNTIME_PROTOBUF_PATCH_COMMAND "") endif() + +FetchContent_Declare( + utf8_range + URL ${DEP_URL_utf8_range} + URL_HASH SHA1=${DEP_SHA1_utf8_range} + 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) + + +#Protobuf depends on absl and utf8_range FetchContent_Declare( Protobuf URL ${DEP_URL_protobuf} @@ -116,7 +178,15 @@ FetchContent_Declare( PATCH_COMMAND ${ONNXRUNTIME_PROTOBUF_PATCH_COMMAND} FIND_PACKAGE_ARGS 3.21.12 NAMES Protobuf ) + set(protobuf_BUILD_TESTS OFF CACHE BOOL "Build protobuf tests" FORCE) +#TODO: we'd better to turn the following option off. However, it will cause +# ".\build.bat --config Debug --parallel --skip_submodule_sync --update" fail with an error message: +# install(EXPORT "ONNXTargets" ...) includes target "onnx_proto" which requires target "libprotobuf-lite" that is +# not in any export set. +#set(protobuf_INSTALL OFF CACHE BOOL "Install protobuf binaries and files" FORCE) +set(protobuf_USE_EXTERNAL_GTEST ON CACHE BOOL "" FORCE) + if (CMAKE_SYSTEM_NAME STREQUAL "Android") set(protobuf_BUILD_PROTOC_BINARIES OFF CACHE BOOL "Build protobuf tests" FORCE) set(protobuf_WITH_ZLIB OFF CACHE BOOL "Build with zlib support" FORCE) @@ -132,14 +202,13 @@ set(ENABLE_DATE_TESTING OFF CACHE BOOL "" FORCE) set(USE_SYSTEM_TZ_DB ON CACHE BOOL "" FORCE) FetchContent_Declare( - date - URL ${DEP_URL_date} - URL_HASH SHA1=${DEP_SHA1_date} - ) + date + URL ${DEP_URL_date} + URL_HASH SHA1=${DEP_SHA1_date} + FIND_PACKAGE_ARGS 3...<4 NAMES date +) onnxruntime_fetchcontent_makeavailable(date) - - FetchContent_Declare( mp11 URL ${DEP_URL_mp11} @@ -174,7 +243,7 @@ if (onnxruntime_ENABLE_CPUINFO) else() # if xnnpack is enabled in a wasm build it needs clog from cpuinfo, but we won't internally use cpuinfo # so we don't set CPUINFO_SUPPORTED in the CXX flags below. - if (onnxruntime_BUILD_WEBASSEMBLY AND NOT onnxruntime_USE_XNNPACK) + if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten" AND NOT onnxruntime_USE_XNNPACK) set(CPUINFO_SUPPORTED FALSE) else() set(CPUINFO_SUPPORTED TRUE) @@ -200,6 +269,20 @@ else() set(CPUINFO_SUPPORTED FALSE) endif() +# xnnpack depends on clog +# Android build should use the system's log library instead of clog +if ((CPUINFO_SUPPORTED OR onnxruntime_USE_XNNPACK) AND NOT ANDROID) + set(CLOG_BUILD_TESTS OFF CACHE BOOL "" FORCE) + FetchContent_Declare( + pytorch_clog + URL ${DEP_URL_pytorch_cpuinfo} + URL_HASH SHA1=${DEP_SHA1_pytorch_cpuinfo} + SOURCE_SUBDIR deps/clog + ) + set(ONNXRUNTIME_CLOG_PROJ pytorch_clog) + set(ONNXRUNTIME_CLOG_TARGET_NAME clog) +endif() + if (CPUINFO_SUPPORTED) if (CMAKE_SYSTEM_NAME STREQUAL "iOS") set(IOS ON CACHE INTERNAL "") @@ -208,7 +291,7 @@ if (CPUINFO_SUPPORTED) # if this is a wasm build with xnnpack (only type of wasm build where cpuinfo is involved) # we do not use cpuinfo in ORT code, so don't define CPUINFO_SUPPORTED. - if (NOT onnxruntime_BUILD_WEBASSEMBLY) + if (NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") string(APPEND CMAKE_CXX_FLAGS " -DCPUINFO_SUPPORTED") endif() @@ -224,7 +307,7 @@ if (CPUINFO_SUPPORTED) URL_HASH SHA1=${DEP_SHA1_pytorch_cpuinfo} FIND_PACKAGE_ARGS NAMES cpuinfo ) - + set(ONNXRUNTIME_CPUINFO_PROJ pytorch_cpuinfo) endif() @@ -264,8 +347,14 @@ FetchContent_Declare( URL_HASH SHA1=${DEP_SHA1_safeint} ) +# use fetch content rather than makeavailable because safeint only includes unconditional test targets +FetchContent_Populate(safeint) # The next line will generate an error message "fatal: not a git repository", but it is ok. It is from flatbuffers -onnxruntime_fetchcontent_makeavailable(Protobuf nlohmann_json mp11 re2 safeint GSL flatbuffers) +onnxruntime_fetchcontent_makeavailable(utf8_range) +# protobuf's cmake/utf8_range.cmake has the following line +include_directories(${utf8_range_SOURCE_DIR}) + +onnxruntime_fetchcontent_makeavailable(Protobuf nlohmann_json mp11 re2 GSL flatbuffers ${ONNXRUNTIME_CPUINFO_PROJ} ${ONNXRUNTIME_CLOG_PROJ}) if(NOT flatbuffers_FOUND) if(NOT TARGET flatbuffers::flatbuffers) add_library(flatbuffers::flatbuffers ALIAS flatbuffers) @@ -361,15 +450,7 @@ FetchContent_Declare( ) -if (CPUINFO_SUPPORTED) - onnxruntime_fetchcontent_makeavailable(pytorch_cpuinfo) - if (pytorch_cpuinfo_SOURCE_DIR) - # shouldn't need to define these aliases after we use a version of cpuinfo with this commit: - # https://github.com/pytorch/cpuinfo/commit/082deffc80ce517f81dc2f3aebe6ba671fcd09c9 - add_library(cpuinfo::cpuinfo ALIAS cpuinfo) - add_library(cpuinfo::clog ALIAS clog) - endif() -endif() + @@ -410,7 +491,7 @@ endif() #onnxruntime_EXTERNAL_LIBRARIES could contain onnx, onnx_proto,libprotobuf, cuda/cudnn, # dnnl/mklml, onnxruntime_codegen_tvm, tvm and pthread # pthread is always at the last -set(onnxruntime_EXTERNAL_LIBRARIES ${onnxruntime_EXTERNAL_LIBRARIES_XNNPACK} WIL::WIL nlohmann_json::nlohmann_json onnx onnx_proto ${PROTOBUF_LIB} re2::re2 Boost::mp11 safeint_interface flatbuffers::flatbuffers ${GSL_TARGET} ${ABSEIL_LIBS} date_interface) +set(onnxruntime_EXTERNAL_LIBRARIES ${onnxruntime_EXTERNAL_LIBRARIES_XNNPACK} ${WIL_TARGET} nlohmann_json::nlohmann_json onnx onnx_proto ${PROTOBUF_LIB} re2::re2 Boost::mp11 safeint_interface flatbuffers::flatbuffers ${GSL_TARGET} ${ABSEIL_LIBS} date::date ${ONNXRUNTIME_CLOG_TARGET_NAME}) # The source code of onnx_proto is generated, we must build this lib first before starting to compile the other source code that uses ONNX protobuf types. # The other libs do not have the problem. All the sources are already there. We can compile them in any order. set(onnxruntime_EXTERNAL_DEPENDENCIES onnx_proto flatbuffers::flatbuffers) @@ -477,6 +558,3 @@ endif() FILE(TO_NATIVE_PATH ${CMAKE_BINARY_DIR} ORT_BINARY_DIR) FILE(TO_NATIVE_PATH ${PROJECT_SOURCE_DIR} ORT_SOURCE_DIR) -if (onnxruntime_USE_AZURE) - include(triton) -endif() diff --git a/cmake/external/protobuf_function.cmake b/cmake/external/protobuf_function.cmake index 81458d7123c54..82aa5a3d2dcef 100644 --- a/cmake/external/protobuf_function.cmake +++ b/cmake/external/protobuf_function.cmake @@ -33,6 +33,7 @@ #sed -i 's/protobuf_generate/onnxruntime_protobuf_generate/g' protobuf-config.cmake.orig #replace 'protobuf::protoc' with ${PROTOC_EXECUTABLE} and ${PROTOC_DEPS} #remove OUTDIR +#add compile options to generated C++ source files to work around warnings function(onnxruntime_protobuf_generate) include(CMakeParseArguments) @@ -166,6 +167,30 @@ function(onnxruntime_protobuf_generate) endforeach() set_source_files_properties(${_generated_srcs_all} PROPERTIES GENERATED TRUE) + + if(onnxruntime_protobuf_generate_LANGUAGE STREQUAL cpp) + # work around warnings from protobuf generated C++ code + # TODO remove these if possible when upgrading protobuf. hopefully we don't need to add to them. + + set(_warning_options) + + if(MSVC) + # google\protobuf\has_bits.h(74,0): Warning C4267: 'argument': conversion from 'size_t' to 'int', possible loss of data + list(APPEND _warning_options "/wd4267") + else() + # TODO remove when we upgrade to a protobuf version where this is fixed (looks like it is addressed in version 22.0+) + # google/protobuf/parse_context.h:328:47: error: implicit conversion loses integer precision: 'long' to 'int' [-Werror,-Wshorten-64-to-32] + # int chunk_size = buffer_end_ + kSlopBytes - ptr; + if(HAS_SHORTEN_64_TO_32) + list(APPEND _warning_options "-Wno-error=shorten-64-to-32") + endif() + endif() + + if(_warning_options) + set_source_files_properties(${_generated_srcs_all} PROPERTIES COMPILE_OPTIONS ${_warning_options}) + endif() + endif() + if(onnxruntime_protobuf_generate_OUT_VAR) set(${onnxruntime_protobuf_generate_OUT_VAR} ${_generated_srcs_all} PARENT_SCOPE) endif() diff --git a/cmake/external/triton.cmake b/cmake/external/triton.cmake deleted file mode 100644 index b24768bd89afd..0000000000000 --- a/cmake/external/triton.cmake +++ /dev/null @@ -1,105 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -include(ExternalProject) - -if (WIN32) - - function(get_vcpkg) - ExternalProject_Add(vcpkg - GIT_REPOSITORY https://github.com/microsoft/vcpkg.git - GIT_TAG 2022.11.14 - PREFIX vcpkg - SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/_deps/vcpkg-src - BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/_deps/vcpkg-build - CONFIGURE_COMMAND "" - INSTALL_COMMAND "" - UPDATE_COMMAND "" - BUILD_COMMAND "/bootstrap-vcpkg.bat") - - ExternalProject_Get_Property(vcpkg SOURCE_DIR) - set(VCPKG_SRC ${SOURCE_DIR} PARENT_SCOPE) - set(VCPKG_DEPENDENCIES "vcpkg" PARENT_SCOPE) - endfunction() - - function(vcpkg_install PACKAGE_NAME) - add_custom_command( - OUTPUT ${VCPKG_SRC}/packages/${PACKAGE_NAME}_${onnxruntime_target_platform}-windows/BUILD_INFO - COMMAND ${VCPKG_SRC}/vcpkg install ${PACKAGE_NAME}:${onnxruntime_target_platform}-windows - WORKING_DIRECTORY ${VCPKG_SRC} - DEPENDS vcpkg) - - add_custom_target(get${PACKAGE_NAME} - ALL - DEPENDS ${VCPKG_SRC}/packages/${PACKAGE_NAME}_${onnxruntime_target_platform}-windows/BUILD_INFO) - - list(APPEND VCPKG_DEPENDENCIES "get${PACKAGE_NAME}") - set(VCPKG_DEPENDENCIES ${VCPKG_DEPENDENCIES} PARENT_SCOPE) - endfunction() - - get_vcpkg() - vcpkg_install(openssl) - vcpkg_install(openssl-windows) - vcpkg_install(rapidjson) - vcpkg_install(re2) - vcpkg_install(boost-interprocess) - vcpkg_install(boost-stacktrace) - vcpkg_install(zlib) - vcpkg_install(pthread) - vcpkg_install(b64) - - add_dependencies(getb64 getpthread) - add_dependencies(getpthread getzlib) - add_dependencies(getzlib getboost-stacktrace) - add_dependencies(getboost-stacktrace getboost-interprocess) - add_dependencies(getboost-interprocess getre2) - add_dependencies(getre2 getrapidjson) - add_dependencies(getrapidjson getopenssl-windows) - add_dependencies(getopenssl-windows getopenssl) - - ExternalProject_Add(triton - GIT_REPOSITORY https://github.com/triton-inference-server/client.git - GIT_TAG r22.12 - PREFIX triton - SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/_deps/triton-src - BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/_deps/triton-build - CMAKE_ARGS -DVCPKG_TARGET_TRIPLET=${onnxruntime_target_platform}-windows -DCMAKE_TOOLCHAIN_FILE=${VCPKG_SRC}/scripts/buildsystems/vcpkg.cmake -DCMAKE_INSTALL_PREFIX=binary -DTRITON_ENABLE_CC_HTTP=ON - INSTALL_COMMAND "" - UPDATE_COMMAND "") - - add_dependencies(triton ${VCPKG_DEPENDENCIES}) - -else() - - ExternalProject_Add(rapidjson - GIT_REPOSITORY https://github.com/Tencent/rapidjson.git - GIT_TAG v1.1.0 - PREFIX rapidjson - SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/_deps/rapidjson-src - BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/_deps/rapidjson-build - CMAKE_ARGS -DRAPIDJSON_BUILD_TESTS=OFF -DRAPIDJSON_BUILD_DOC=OFF -DRAPIDJSON_BUILD_EXAMPLES=OFF) - - ExternalProject_Get_Property(rapidjson source_dir) - set(RAPIDJSON_INCLUDE_DIR ${source_dir}/include) - include_directories(${RAPIDJSON_INCLUDE_DIR}) - - ExternalProject_Add(triton - GIT_REPOSITORY https://github.com/triton-inference-server/client.git - GIT_TAG r22.12 - PREFIX triton - SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/_deps/triton-src - BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/_deps/triton-build - CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=binary -DTRITON_ENABLE_CC_HTTP=ON - INSTALL_COMMAND "" - UPDATE_COMMAND "") - - add_dependencies(triton rapidjson) - -endif() #if (WIN32) - -ExternalProject_Get_Property(triton SOURCE_DIR) -set(TRITON_SRC ${SOURCE_DIR}) - -ExternalProject_Get_Property(triton BINARY_DIR) -set(TRITON_BIN ${BINARY_DIR}/binary) -set(TRITON_THIRD_PARTY ${BINARY_DIR}/third-party) \ No newline at end of file diff --git a/cmake/external/wil.cmake b/cmake/external/wil.cmake index d38535c4a173b..120e986ebb552 100644 --- a/cmake/external/wil.cmake +++ b/cmake/external/wil.cmake @@ -4,19 +4,13 @@ set(WIL_BUILD_PACKAGING OFF CACHE BOOL "" FORCE) set(WIL_BUILD_TESTS OFF CACHE BOOL "" FORCE) FetchContent_Declare( - microsoft_wil - URL ${DEP_URL_microsoft_wil} - URL_HASH SHA1=${DEP_SHA1_microsoft_wil} - FIND_PACKAGE_ARGS NAMES wil + microsoft_wil + URL ${DEP_URL_microsoft_wil} + URL_HASH SHA1=${DEP_SHA1_microsoft_wil} + FIND_PACKAGE_ARGS NAMES wil ) -#We can not use FetchContent_MakeAvailable(microsoft_wil) at here, since their cmake file -#always executes install command without conditions. -FetchContent_Populate(microsoft_wil) -if(NOT wil_FOUND) - add_library(WIL INTERFACE) - add_library(WIL::WIL ALIAS WIL) - # The interface's include directory. - target_include_directories(WIL INTERFACE - $) -endif() \ No newline at end of file +if(WIN32) + onnxruntime_fetchcontent_makeavailable(microsoft_wil) + set(WIL_TARGET "WIL::WIL") +endif() diff --git a/cmake/external/xnnpack.cmake b/cmake/external/xnnpack.cmake index 1fc2c6ccdc9fa..7455584f1a625 100644 --- a/cmake/external/xnnpack.cmake +++ b/cmake/external/xnnpack.cmake @@ -35,7 +35,7 @@ set(XNNPACK_INCLUDE_DIR ${XNNPACK_DIR}/include) set(onnxruntime_EXTERNAL_LIBRARIES_XNNPACK XNNPACK pthreadpool) # the XNNPACK CMake setup doesn't include the WASM kernels so we have to manually set those up -if(onnxruntime_BUILD_WEBASSEMBLY) +if(CMAKE_SYSTEM_NAME STREQUAL "Emscripten") file(READ "${XNNPACK_DIR}/BUILD.bazel" xnnpack_bazel_config) # Replace newlines with semicolon so that it is treated as a list by CMake diff --git a/cmake/onnxruntime.cmake b/cmake/onnxruntime.cmake index 9f34d1f46751d..59ebf8eca4306 100644 --- a/cmake/onnxruntime.cmake +++ b/cmake/onnxruntime.cmake @@ -18,15 +18,37 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "iOS") set(OUTPUT_STYLE xcode) endif() +set(ONNXRUNTIME_PUBLIC_HEADERS + "${REPO_ROOT}/include/onnxruntime/core/session/onnxruntime_c_api.h" + "${REPO_ROOT}/include/onnxruntime/core/session/onnxruntime_cxx_api.h" + "${REPO_ROOT}/include/onnxruntime/core/session/onnxruntime_float16.h" + "${REPO_ROOT}/include/onnxruntime/core/session/onnxruntime_cxx_inline.h" + "${REPO_ROOT}/include/onnxruntime/core/session/onnxruntime_session_options_config_keys.h" + "${REPO_ROOT}/include/onnxruntime/core/session/onnxruntime_run_options_config_keys.h" +) + +if (onnxruntime_ENABLE_TRAINING_APIS) + list(APPEND ${_HEADERS} "${REPO_ROOT}/orttraining/orttraining/training_api/include/onnxruntime_training_c_api.h") + list(APPEND ${_HEADERS} "${REPO_ROOT}/orttraining/orttraining/training_api/include/onnxruntime_training_cxx_api.h") + list(APPEND ${_HEADERS} "${REPO_ROOT}/orttraining/orttraining/training_api/include/onnxruntime_training_cxx_inline.h") +endif() + # This macro is to get the path of header files for mobile packaging, for iOS and Android macro(get_mobile_api_headers _HEADERS) # include both c and cxx api set(${_HEADERS} "${REPO_ROOT}/include/onnxruntime/core/session/onnxruntime_c_api.h" "${REPO_ROOT}/include/onnxruntime/core/session/onnxruntime_cxx_api.h" + "${REPO_ROOT}/include/onnxruntime/core/session/onnxruntime_float16.h" "${REPO_ROOT}/include/onnxruntime/core/session/onnxruntime_cxx_inline.h" ) + if (onnxruntime_ENABLE_TRAINING_APIS) + list(APPEND ${_HEADERS} "${REPO_ROOT}/orttraining/orttraining/training_api/include/onnxruntime_training_c_api.h") + list(APPEND ${_HEADERS} "${REPO_ROOT}/orttraining/orttraining/training_api/include/onnxruntime_training_cxx_api.h") + list(APPEND ${_HEADERS} "${REPO_ROOT}/orttraining/orttraining/training_api/include/onnxruntime_training_cxx_inline.h") + endif() + # need to add header files for enabled EPs foreach(f ${ONNXRUNTIME_PROVIDER_NAMES}) file(GLOB _provider_headers CONFIGURE_DEPENDS @@ -98,7 +120,7 @@ else() endif() add_dependencies(onnxruntime onnxruntime_generate_def ${onnxruntime_EXTERNAL_DEPENDENCIES}) -target_include_directories(onnxruntime PRIVATE ${ONNXRUNTIME_ROOT}) +target_include_directories(onnxruntime PRIVATE ${ONNXRUNTIME_ROOT} PUBLIC "$") target_compile_definitions(onnxruntime PRIVATE VER_MAJOR=${VERSION_MAJOR_PART}) target_compile_definitions(onnxruntime PRIVATE VER_MINOR=${VERSION_MINOR_PART}) @@ -130,7 +152,7 @@ if (NOT WIN32) else() set_target_properties(onnxruntime PROPERTIES INSTALL_RPATH "@loader_path") endif() - elseif (NOT onnxruntime_BUILD_WEBASSEMBLY) + elseif (NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-rpath='$ORIGIN'") endif() endif() @@ -182,9 +204,9 @@ set(onnxruntime_INTERNAL_LIBRARIES ${PROVIDERS_SNPE} ${PROVIDERS_TVM} ${PROVIDERS_RKNPU} - ${PROVIDERS_ROCM} ${PROVIDERS_VITISAI} ${PROVIDERS_XNNPACK} + ${PROVIDERS_WEBNN} ${PROVIDERS_AZURE} ${PROVIDERS_INTERNAL_TESTING} ${onnxruntime_winml} @@ -206,6 +228,13 @@ if (onnxruntime_ENABLE_LANGUAGE_INTEROP_OPS) ) endif() +if (onnxruntime_USE_EXTENSIONS) + list(APPEND onnxruntime_INTERNAL_LIBRARIES + onnxruntime_extensions + ocos_operators + ) +endif() + # If you are linking a new library, please add it to the list onnxruntime_INTERNAL_LIBRARIES or onnxruntime_EXTERNAL_LIBRARIES, # Please do not add a library directly to the target_link_libraries command target_link_libraries(onnxruntime PRIVATE @@ -214,18 +243,21 @@ target_link_libraries(onnxruntime PRIVATE ) set_property(TARGET onnxruntime APPEND_STRING PROPERTY LINK_FLAGS ${ONNXRUNTIME_SO_LINK_FLAG} ${onnxruntime_DELAYLOAD_FLAGS}) -set_target_properties(onnxruntime PROPERTIES LINK_DEPENDS ${SYMBOL_FILE}) - - -set_target_properties(onnxruntime PROPERTIES VERSION ${ORT_VERSION}) +set_target_properties(onnxruntime PROPERTIES + PUBLIC_HEADER "${ONNXRUNTIME_PUBLIC_HEADERS}" + LINK_DEPENDS ${SYMBOL_FILE} + VERSION ${ORT_VERSION} + FOLDER "ONNXRuntime" +) install(TARGETS onnxruntime + EXPORT ${PROJECT_NAME}Targets + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR} FRAMEWORK DESTINATION ${CMAKE_INSTALL_BINDIR}) -set_target_properties(onnxruntime PROPERTIES FOLDER "ONNXRuntime") if (WIN32 AND NOT CMAKE_CXX_STANDARD_LIBRARIES MATCHES kernel32.lib) # Workaround STL bug https://github.com/microsoft/STL/issues/434#issuecomment-921321254 diff --git a/cmake/onnxruntime_common.cmake b/cmake/onnxruntime_common.cmake index 0410d3361cb60..43d5fa9bdee34 100644 --- a/cmake/onnxruntime_common.cmake +++ b/cmake/onnxruntime_common.cmake @@ -22,8 +22,8 @@ set(onnxruntime_common_src_patterns "${ONNXRUNTIME_ROOT}/core/platform/telemetry.cc" "${ONNXRUNTIME_ROOT}/core/platform/logging/make_platform_default_log_sink.h" "${ONNXRUNTIME_ROOT}/core/platform/logging/make_platform_default_log_sink.cc" - "$(ONNXRUNTIME_ROOT}/core/quantization/*.h" - "$(ONNXRUNTIME_ROOT}/core/quantization/*.cc" + "${ONNXRUNTIME_ROOT}/core/quantization/*.h" + "${ONNXRUNTIME_ROOT}/core/quantization/*.cc" ) if(WIN32) @@ -86,7 +86,12 @@ endif() source_group(TREE ${REPO_ROOT} FILES ${onnxruntime_common_src}) onnxruntime_add_static_library(onnxruntime_common ${onnxruntime_common_src}) - +if(WIN32) + if("cxx_std_23" IN_LIST CMAKE_CXX_COMPILE_FEATURES) + set_property(TARGET onnxruntime_common PROPERTY CXX_STANDARD 23) + target_compile_options(onnxruntime_common PRIVATE "/Zc:char8_t-") + endif() +endif() if (onnxruntime_USE_TELEMETRY) set_target_properties(onnxruntime_common PROPERTIES COMPILE_FLAGS "/FI${ONNXRUNTIME_INCLUDE_DIR}/core/platform/windows/TraceLoggingConfigPrivate.h") endif() @@ -107,7 +112,16 @@ if(NOT onnxruntime_DISABLE_ABSEIL) endif() endif() -onnxruntime_add_include_to_target(onnxruntime_common date_interface WIL::WIL) +if (MSVC) + set(EIGEN_NATVIS_FILE ${eigen_SOURCE_DIR}/debug/msvc/eigen.natvis) + if (EXISTS ${EIGEN_NATVIS_FILE}) + target_sources( + onnxruntime_common + INTERFACE $) + endif() +endif() + +onnxruntime_add_include_to_target(onnxruntime_common date::date ${WIL_TARGET}) target_include_directories(onnxruntime_common PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${ONNXRUNTIME_ROOT} ${eigen_INCLUDE_DIRS} # propagate include directories of dependencies that are part of public interface @@ -119,7 +133,6 @@ target_link_libraries(onnxruntime_common PUBLIC safeint_interface ${GSL_TARGET} add_dependencies(onnxruntime_common ${onnxruntime_EXTERNAL_DEPENDENCIES}) -install(DIRECTORY ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/common DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/core) set_target_properties(onnxruntime_common PROPERTIES LINKER_LANGUAGE CXX) set_target_properties(onnxruntime_common PROPERTIES FOLDER "ONNXRuntime") @@ -153,7 +166,7 @@ elseif(APPLE) if(CMAKE_OSX_ARCHITECTURES_LEN LESS_EQUAL 1) set(X64 TRUE) endif() -elseif(NOT onnxruntime_BUILD_WEBASSEMBLY) +elseif(NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") if (CMAKE_SYSTEM_NAME STREQUAL "Android") if (CMAKE_ANDROID_ARCH_ABI STREQUAL "armeabi-v7a") set(ARM TRUE) @@ -195,13 +208,14 @@ if (ARM64 OR ARM OR X86 OR X64 OR X86_64) # Its functionality in detecting x86 cpu features are lacking, so is support for Windows. if (CPUINFO_SUPPORTED) onnxruntime_add_include_to_target(onnxruntime_common cpuinfo::cpuinfo) - list(APPEND onnxruntime_EXTERNAL_LIBRARIES cpuinfo::cpuinfo cpuinfo::clog) + list(APPEND onnxruntime_EXTERNAL_LIBRARIES cpuinfo::cpuinfo ${ONNXRUNTIME_CLOG_TARGET_NAME}) endif() endif() endif() if (NOT onnxruntime_BUILD_SHARED_LIB) - install(TARGETS onnxruntime_common + install(DIRECTORY ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/common DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/core) + install(TARGETS onnxruntime_common ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} diff --git a/cmake/onnxruntime_compile_triton_kernel.cmake b/cmake/onnxruntime_compile_triton_kernel.cmake new file mode 100644 index 0000000000000..f59cc6de108bc --- /dev/null +++ b/cmake/onnxruntime_compile_triton_kernel.cmake @@ -0,0 +1,33 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +find_package(Python3 COMPONENTS Interpreter REQUIRED) + +# set all triton kernel ops that need to be compiled +set(triton_kernel_scripts + "onnxruntime/core/providers/rocm/math/softmax_triton.py" + "onnxruntime/contrib_ops/rocm/diffusion/group_norm_triton.py" +) + +function(compile_triton_kernel out_triton_kernel_obj_file out_triton_kernel_header_dir) + # compile triton kernel, generate .a and .h files + set(triton_kernel_compiler "${REPO_ROOT}/tools/ci_build/compile_triton.py") + set(out_dir "${CMAKE_CURRENT_BINARY_DIR}/triton_kernels") + set(out_obj_file "${out_dir}/triton_kernel_infos.a") + set(header_file "${out_dir}/triton_kernel_infos.h") + + list(TRANSFORM triton_kernel_scripts PREPEND "${REPO_ROOT}/") + + add_custom_command( + OUTPUT ${out_obj_file} ${header_file} + COMMAND Python3::Interpreter ${triton_kernel_compiler} + --header ${header_file} + --script_files ${triton_kernel_scripts} + --obj_file ${out_obj_file} + DEPENDS ${triton_kernel_scripts} ${triton_kernel_compiler} + COMMENT "Triton compile generates: ${out_obj_file}" + ) + add_custom_target(onnxruntime_triton_kernel DEPENDS ${out_obj_file} ${header_file}) + set(${out_triton_kernel_obj_file} ${out_obj_file} PARENT_SCOPE) + set(${out_triton_kernel_header_dir} ${out_dir} PARENT_SCOPE) +endfunction() diff --git a/cmake/onnxruntime_config.h.in b/cmake/onnxruntime_config.h.in index 44d4788acb0a4..2aef9dcf209e0 100644 --- a/cmake/onnxruntime_config.h.in +++ b/cmake/onnxruntime_config.h.in @@ -3,22 +3,24 @@ #pragma once -#cmakedefine HAS_UNUSED_BUT_SET_PARAMETER -#cmakedefine HAS_UNUSED_BUT_SET_VARIABLE -#cmakedefine HAS_UNUSED_VARIABLE +#cmakedefine HAS_BITWISE_INSTEAD_OF_LOGICAL #cmakedefine HAS_CAST_FUNCTION_TYPE -#cmakedefine HAS_PARENTHESES -#cmakedefine HAS_USELESS_CAST -#cmakedefine HAS_NONNULL_COMPARE -#cmakedefine HAS_TAUTOLOGICAL_POINTER_COMPARE #cmakedefine HAS_CATCH_VALUE -#cmakedefine HAS_MISSING_BRACES -#cmakedefine HAS_IGNORED_ATTRIBUTES -#cmakedefine HAS_DEPRECATED_COPY #cmakedefine HAS_CLASS_MEMACCESS -#cmakedefine HAS_MAYBE_UNINITIALIZED +#cmakedefine HAS_DEPRECATED_COPY #cmakedefine HAS_DEPRECATED_DECLARATIONS #cmakedefine HAS_FORMAT_TRUNCATION -#cmakedefine HAS_BITWISE_INSTEAD_OF_LOGICAL +#cmakedefine HAS_IGNORED_ATTRIBUTES +#cmakedefine HAS_MAYBE_UNINITIALIZED +#cmakedefine HAS_MISSING_BRACES +#cmakedefine HAS_NONNULL_COMPARE +#cmakedefine HAS_PARENTHESES #cmakedefine HAS_REALLOCARRAY -#cmakedefine ORT_VERSION "@ORT_VERSION@" +#cmakedefine HAS_SHORTEN_64_TO_32 +#cmakedefine HAS_TAUTOLOGICAL_POINTER_COMPARE +#cmakedefine HAS_UNUSED_BUT_SET_PARAMETER +#cmakedefine HAS_UNUSED_BUT_SET_VARIABLE +#cmakedefine HAS_UNUSED_VARIABLE +#cmakedefine HAS_USELESS_CAST +#cmakedefine ORT_BUILD_INFO u8"@ORT_BUILD_INFO@" +#cmakedefine ORT_VERSION u8"@ORT_VERSION@" diff --git a/cmake/onnxruntime_framework.cmake b/cmake/onnxruntime_framework.cmake index 5c947a52b7838..c9bf2ac5c3dc6 100644 --- a/cmake/onnxruntime_framework.cmake +++ b/cmake/onnxruntime_framework.cmake @@ -8,12 +8,31 @@ file(GLOB_RECURSE onnxruntime_framework_srcs CONFIGURE_DEPENDS ) if (onnxruntime_ENABLE_TRAINING_TORCH_INTEROP) -file(GLOB_RECURSE onnxruntime_training_framework_torch_srcs CONFIGURE_DEPENDS - "${ORTTRAINING_SOURCE_DIR}/core/framework/torch/*.h" - "${ORTTRAINING_SOURCE_DIR}/core/framework/torch/*.cc" -) - + file(GLOB_RECURSE onnxruntime_training_framework_torch_srcs CONFIGURE_DEPENDS + "${ORTTRAINING_SOURCE_DIR}/core/framework/torch/*.h" + "${ORTTRAINING_SOURCE_DIR}/core/framework/torch/*.cc" + ) list(APPEND onnxruntime_framework_srcs ${onnxruntime_training_framework_torch_srcs}) + if (onnxruntime_ENABLE_TRITON) + file(GLOB_RECURSE onnxruntime_training_framework_triton_srcs CONFIGURE_DEPENDS + "${ORTTRAINING_SOURCE_DIR}/core/framework/triton/*.h" + "${ORTTRAINING_SOURCE_DIR}/core/framework/triton/*.cc" + ) + list(APPEND onnxruntime_framework_srcs ${onnxruntime_training_framework_triton_srcs}) + endif() +elseif(onnxruntime_ENABLE_TRITON) + # Triton executor shares some code from torch_interop, such as python and dlpack related code files. + # When torch_interop is enabled, all these dependencies are already included. + # But if not, we need to include them explicitly. + file(GLOB_RECURSE onnxruntime_training_framework_triton_srcs CONFIGURE_DEPENDS + "${ORTTRAINING_SOURCE_DIR}/core/framework/torch/dlpack_python.h" + "${ORTTRAINING_SOURCE_DIR}/core/framework/torch/dlpack_python.cc" + "${ORTTRAINING_SOURCE_DIR}/core/framework/torch/gil.h" + "${ORTTRAINING_SOURCE_DIR}/core/framework/torch/python_common.h" + "${ORTTRAINING_SOURCE_DIR}/core/framework/triton/*.h" + "${ORTTRAINING_SOURCE_DIR}/core/framework/triton/*.cc" + ) + list(APPEND onnxruntime_framework_srcs ${onnxruntime_training_framework_triton_srcs}) endif() if (onnxruntime_MINIMAL_BUILD) @@ -37,26 +56,12 @@ source_group(TREE ${REPO_ROOT} FILES ${onnxruntime_framework_srcs}) onnxruntime_add_static_library(onnxruntime_framework ${onnxruntime_framework_srcs}) -if (onnxruntime_USE_AZURE) - - add_dependencies(onnxruntime_framework triton) - target_include_directories(onnxruntime_framework PRIVATE ${TRITON_BIN}/include) - link_directories(${TRITON_BIN}/lib ${TRITON_BIN}/lib64 ${TRITON_THIRD_PARTY}/curl/lib ${TRITON_THIRD_PARTY}/curl/lib64) - - if (WIN32) - - link_directories(${VCPKG_SRC}/installed/${onnxruntime_target_platform}-windows/lib) - target_link_libraries(onnxruntime_framework PRIVATE libcurl httpclient_static ws2_32 crypt32 Wldap32 zlib) - - else() - - find_package(ZLIB REQUIRED) - find_package(OpenSSL REQUIRED) - target_link_libraries(onnxruntime_framework PRIVATE httpclient_static curl ZLIB::ZLIB OpenSSL::Crypto OpenSSL::SSL) - - endif() #if (WIN32) - -endif() #if (onnxruntime_USE_AZURE) +if (MSVC) + set(ORT_FRAMEWORK_NATVIS_FILE "onnxruntime_framework.natvis") + target_sources( + onnxruntime_framework + INTERFACE $) +endif() if(onnxruntime_ENABLE_INSTRUMENT) target_compile_definitions(onnxruntime_framework PRIVATE ONNXRUNTIME_ENABLE_INSTRUMENT) @@ -71,7 +76,7 @@ endif() # Needed for the provider interface, as it includes training headers when training is enabled if (onnxruntime_ENABLE_TRAINING_OPS) target_include_directories(onnxruntime_framework PRIVATE ${ORTTRAINING_ROOT}) - if (onnxruntime_ENABLE_TRAINING_TORCH_INTEROP) + if (onnxruntime_ENABLE_TRAINING_TORCH_INTEROP OR onnxruntime_ENABLE_TRITON) onnxruntime_add_include_to_target(onnxruntime_framework Python::Module) target_include_directories(onnxruntime_framework PRIVATE ${dlpack_SOURCE_DIR}/include) endif() @@ -91,7 +96,7 @@ if (onnxruntime_USE_MIMALLOC) target_link_libraries(onnxruntime_framework mimalloc-static) endif() -if (onnxruntime_BUILD_WEBASSEMBLY) +if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") target_link_libraries(onnxruntime_framework ${ABSEIL_LIBS}) endif() @@ -103,18 +108,14 @@ add_dependencies(onnxruntime_framework ${onnxruntime_EXTERNAL_DEPENDENCIES}) # For the shared onnxruntime library, this is set in onnxruntime.cmake through CMAKE_SHARED_LINKER_FLAGS # But our test files don't use the shared library so this must be set for them. # For Win32 it generates an absolute path for shared providers based on the location of the executable/onnxruntime.dll -if (UNIX AND NOT APPLE AND NOT onnxruntime_MINIMAL_BUILD AND NOT onnxruntime_BUILD_WEBASSEMBLY) +if (UNIX AND NOT APPLE AND NOT onnxruntime_MINIMAL_BUILD AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath='$ORIGIN'") endif() if (onnxruntime_DEBUG_NODE_INPUTS_OUTPUTS_ENABLE_DUMP_TO_SQLDB) - find_package (SQLite3) - if (SQLITE3_FOUND) - include_directories(${SQLite3_INCLUDE_DIR}) - target_link_libraries (onnxruntime_framework ${SQLite3_LIBRARY}) - else() - message( FATAL_ERROR "Could not locate SQLite3 package." ) - endif (SQLITE3_FOUND) + find_package (SQLite3 REQUIRED) + include_directories(${SQLite3_INCLUDE_DIR}) + target_link_libraries (onnxruntime_framework ${SQLite3_LIBRARY}) target_compile_definitions(onnxruntime_framework PRIVATE DEBUG_NODE_INPUTS_OUTPUTS_ENABLE_DUMP_TO_SQLDB) endif() @@ -123,11 +124,10 @@ if (WIN32) endif() if (NOT onnxruntime_BUILD_SHARED_LIB) - install(TARGETS onnxruntime_framework + install(DIRECTORY ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/framework DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/core) + install(TARGETS onnxruntime_framework ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} FRAMEWORK DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() - -install(DIRECTORY ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/framework DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/core) diff --git a/cmake/onnxruntime_framework.natvis b/cmake/onnxruntime_framework.natvis new file mode 100644 index 0000000000000..75328e9aac3af --- /dev/null +++ b/cmake/onnxruntime_framework.natvis @@ -0,0 +1,47 @@ + + + + + + + + + + + + + {{val={ val }}} + + _negative() + true + _is_finite() + _is_normal() + val + _exponent() + _biased_exponent() + _significand() + + + + + + + + + + + + + {{val={ val }}} + + _negative() + _is_normal() + true + _is_finite() + val + _exponent() + _biased_exponent() + _significand() + + + \ No newline at end of file diff --git a/cmake/onnxruntime_graph.cmake b/cmake/onnxruntime_graph.cmake index 4785d3ed3a87f..735c86956ec4f 100644 --- a/cmake/onnxruntime_graph.cmake +++ b/cmake/onnxruntime_graph.cmake @@ -87,7 +87,7 @@ endif() onnxruntime_add_static_library(onnxruntime_graph ${onnxruntime_graph_lib_src}) add_dependencies(onnxruntime_graph onnx_proto flatbuffers::flatbuffers) -onnxruntime_add_include_to_target(onnxruntime_graph onnxruntime_common WIL::WIL onnx onnx_proto ${PROTOBUF_LIB} flatbuffers::flatbuffers safeint_interface Boost::mp11) +onnxruntime_add_include_to_target(onnxruntime_graph onnxruntime_common ${WIL_TARGET} onnx onnx_proto ${PROTOBUF_LIB} flatbuffers::flatbuffers safeint_interface Boost::mp11) if (MSVC) set(ONNX_PROTOBUF_NATVIS_FILE "onnx_protobuf.natvis") @@ -98,7 +98,7 @@ if (MSVC) endif() if(NOT MSVC) - target_compile_options(onnxruntime_graph PRIVATE "-Wno-parentheses") + target_compile_options(onnxruntime_graph PRIVATE "-Wno-parentheses" "-Wno-deprecated-declarations") endif() if (onnxruntime_ENABLE_TRAINING) #TODO: the graph library should focus on ONNX IR, it shouldn't depend on math libraries like MKLML/OpenBlas @@ -118,7 +118,6 @@ endif() set_target_properties(onnxruntime_graph PROPERTIES FOLDER "ONNXRuntime") set_target_properties(onnxruntime_graph PROPERTIES LINKER_LANGUAGE CXX) -install(DIRECTORY ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/graph DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/core) source_group(TREE ${REPO_ROOT} FILES ${onnxruntime_graph_src} ${onnxruntime_ir_defs_src}) if (onnxruntime_ENABLE_TRAINING_OPS) source_group(TREE ${ORTTRAINING_ROOT} FILES ${orttraining_graph_src}) @@ -148,7 +147,8 @@ if (onnxruntime_ENABLE_ATEN) endif() if (NOT onnxruntime_BUILD_SHARED_LIB) - install(TARGETS onnxruntime_graph + install(DIRECTORY ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/graph DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/core) + install(TARGETS onnxruntime_graph ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} diff --git a/cmake/onnxruntime_kernel_explorer.cmake b/cmake/onnxruntime_kernel_explorer.cmake index d4ae88a1f65df..856fed40abdba 100644 --- a/cmake/onnxruntime_kernel_explorer.cmake +++ b/cmake/onnxruntime_kernel_explorer.cmake @@ -19,6 +19,9 @@ elseif(onnxruntime_USE_ROCM) if (onnxruntime_USE_COMPOSABLE_KERNEL) include(composable_kernel) endif() + if (onnxruntime_USE_HIPBLASLT) + find_package(hipblaslt REQUIRED) + endif() set(BERT_DIR ${ONNXRUNTIME_ROOT}/contrib_ops/rocm/bert) endif() @@ -66,6 +69,17 @@ elseif (onnxruntime_USE_ROCM) target_compile_definitions(kernel_explorer PRIVATE USE_COMPOSABLE_KERNEL) target_link_libraries(kernel_explorer PRIVATE onnxruntime_composable_kernel_includes) endif() + if (onnxruntime_USE_TRITON_KERNEL) + target_compile_definitions(kernel_explorer PRIVATE USE_TRITON_KERNEL) + endif() + if (onnxruntime_USE_HIPBLASLT) + target_compile_definitions(kernel_explorer PRIVATE USE_HIPBLASLT) + endif() + if (onnxruntime_USE_ROCBLAS_EXTENSION_API) + target_compile_definitions(kernel_explorer PRIVATE USE_ROCBLAS_EXTENSION_API) + target_compile_definitions(kernel_explorer PRIVATE ROCBLAS_NO_DEPRECATED_WARNINGS) + target_compile_definitions(kernel_explorer PRIVATE ROCBLAS_BETA_FEATURES_API) + endif() endif() add_dependencies(kernel_explorer onnxruntime_pybind11_state) diff --git a/cmake/onnxruntime_mlas.cmake b/cmake/onnxruntime_mlas.cmake index 6828dfd07610a..e0ccc504d7b27 100644 --- a/cmake/onnxruntime_mlas.cmake +++ b/cmake/onnxruntime_mlas.cmake @@ -3,28 +3,6 @@ set(MLAS_SRC_DIR ${ONNXRUNTIME_ROOT}/core/mlas/lib) - -set(MLAS_AMX_SUPPORTED FALSE) - -if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 11) - # match assembler version, AMX instructions are supported from 2.38 - if (CMAKE_ASM_COMPILER_ID STREQUAL "GNU") - execute_process( - COMMAND as --version - OUTPUT_VARIABLE _as_version - ) - # 2.38 or later - if (_as_version MATCHES "GNU.[Aa]ssembler.*(2\\.38|2\\.39|2\\.[4-9][0-9]|[3-9]\\.[0-9][0-9])") - set(MLAS_AMX_SUPPORTED TRUE) - endif() - endif() -endif() - -if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - set(MLAS_AMX_SUPPORTED TRUE) -endif() - - # # All hardware agnostic source files here # hardware specific files would cause trouble in @@ -57,10 +35,11 @@ onnxruntime_add_static_library(onnxruntime_mlas ${MLAS_SRC_DIR}/qdwconv_kernelsize.cpp ) -if(MLAS_AMX_SUPPORTED) - target_compile_definitions(onnxruntime_mlas PRIVATE MLAS_AMX_SUPPORTED) -else() - message(WARNING "AMX instructions NOT supported due to lack of compiler tool chain!") +if (NOT onnxruntime_ORT_MINIMAL_BUILD) + target_sources(onnxruntime_mlas PRIVATE + ${MLAS_SRC_DIR}/q4_dq.cpp + ${MLAS_SRC_DIR}/q4gemm.cpp + ) endif() set(ONNXRUNTIME_MLAS_LIBS onnxruntime_mlas) @@ -153,6 +132,10 @@ function(setup_mlas_source_for_windows) target_sources(onnxruntime_mlas PRIVATE ${MLAS_SRC_DIR}/arm/sgemmc.cpp ) + # it should be removed after Visual Stuio is upgraded to 17.7 + if (MSVC) + add_compile_options("-d2SSAOptimizer-") + endif() elseif(onnxruntime_target_platform STREQUAL "x64") file(GLOB_RECURSE mlas_platform_srcs_avx CONFIGURE_DEPENDS @@ -210,6 +193,12 @@ function(setup_mlas_source_for_windows) ${MLAS_SRC_DIR}/amd64/TanhKernelFma3.asm ${MLAS_SRC_DIR}/amd64/ErfKernelFma3.asm ) + if (NOT onnxruntime_ORT_MINIMAL_BUILD) + target_sources(onnxruntime_mlas PRIVATE + ${MLAS_SRC_DIR}/q4gemm_avx512.cpp + ) + endif() + else() target_sources(onnxruntime_mlas PRIVATE ${MLAS_SRC_DIR}/qgemm_kernel_sse.cpp @@ -220,7 +209,7 @@ function(setup_mlas_source_for_windows) endif() endfunction() -if (onnxruntime_BUILD_WEBASSEMBLY) +if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") if (onnxruntime_ENABLE_WEBASSEMBLY_SIMD) file(GLOB_RECURSE mlas_platform_srcs "${MLAS_SRC_DIR}/wasm_simd/*.cpp" @@ -550,15 +539,23 @@ else() ${mlas_platform_srcs_avx512core} ) - if(MLAS_AMX_SUPPORTED) + if (NOT onnxruntime_ORT_MINIMAL_BUILD) set(mlas_platform_srcs ${mlas_platform_srcs} - ${MLAS_SRC_DIR}/qgemm_kernel_amx.cpp - ${MLAS_SRC_DIR}/x86_64/QgemmU8S8KernelAmx.S + ${MLAS_SRC_DIR}/q4gemm_avx512.cpp ) - set_source_files_properties(${MLAS_SRC_DIR}/qgemm_kernel_amx.cpp PROPERTIES COMPILE_FLAGS "-mamx-tile -mamx-int8 -mavx2 -mavx512bw -mavx512dq -mavx512vl") - set_source_files_properties(${MLAS_SRC_DIR}/x86_64/QgemmU8S8KernelAmx.S PROPERTIES COMPILE_FLAGS "-mamx-tile -mamx-int8 -mavx2 -mavx512bw -mavx512dq -mavx512vl") + set_source_files_properties(${MLAS_SRC_DIR}/q4gemm_avx512.cpp PROPERTIES COMPILE_FLAGS "-mfma -mavx512vnni -mavx512bw -mavx512dq -mavx512vl -mavx512f") endif() + if(NOT APPLE) + set(mlas_platform_srcs + ${mlas_platform_srcs} + ${MLAS_SRC_DIR}/x86_64/QgemmU8S8KernelAmxCommon.S + ${MLAS_SRC_DIR}/qgemm_kernel_amx.cpp + ${MLAS_SRC_DIR}/x86_64/QgemmU8S8KernelAmx.S + ) + set_source_files_properties(${MLAS_SRC_DIR}/qgemm_kernel_amx.cpp PROPERTIES COMPILE_FLAGS "-mavx2 -mavx512bw -mavx512dq -mavx512vl -mavx512f") + set_source_files_properties(${MLAS_SRC_DIR}/x86_64/QgemmU8S8KernelAmx.S PROPERTIES COMPILE_FLAGS "-mavx2 -mavx512bw -mavx512dq -mavx512vl -mavx512f") + endif() if(ONNXRUNTIME_MLAS_MULTI_ARCH) onnxruntime_add_static_library(onnxruntime_mlas_x86_64 ${mlas_platform_srcs}) @@ -584,7 +581,7 @@ set_target_properties(onnxruntime_mlas PROPERTIES FOLDER "ONNXRuntime") if (WIN32) target_compile_options(onnxruntime_mlas PRIVATE "$<$:/wd6385>" "$<$:/wd4127>") if (onnxruntime_ENABLE_STATIC_ANALYSIS) - target_compile_options(onnxruntime_mlas PRIVATE "$<$:/analyze:stacksize 131072">) + target_compile_options(onnxruntime_mlas PRIVATE "$<$:/analyze:stacksize" 131072>) endif() endif() @@ -595,3 +592,46 @@ if (NOT onnxruntime_BUILD_SHARED_LIB) RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} FRAMEWORK DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() + + +if (NOT onnxruntime_ORT_MINIMAL_BUILD) + + # + # Command line tool for quantization and de-quantization of 2-D fp32 tensors + # based on block-wise quantization of int4 + # + + onnxruntime_add_executable(onnxruntime_mlas_q4dq + ${MLAS_SRC_DIR}/q4_dq_cli.cpp + ) + target_include_directories(onnxruntime_mlas_q4dq PRIVATE ${ONNXRUNTIME_ROOT}/core/mlas/inc ${MLAS_SRC_DIR}) + set_target_properties(onnxruntime_mlas_q4dq PROPERTIES FOLDER "ONNXRuntimeTest") + + target_link_libraries(onnxruntime_mlas_q4dq PRIVATE ${ONNXRUNTIME_MLAS_LIBS} onnxruntime_common) + if (CPUINFO_SUPPORTED AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") + target_link_libraries(onnxruntime_mlas_q4dq PRIVATE cpuinfo) + endif() + if(NOT WIN32) + target_link_libraries(onnxruntime_mlas_q4dq PRIVATE nsync::nsync_cpp ${CMAKE_DL_LIBS}) + endif() + if (CMAKE_SYSTEM_NAME STREQUAL "Android") + target_link_libraries(onnxruntime_mlas_q4dq PRIVATE ${android_shared_libs}) + endif() + + if(WIN32) + target_link_libraries(onnxruntime_mlas_q4dq PRIVATE debug Dbghelp Advapi32) + endif() + if (onnxruntime_LINK_LIBATOMIC) + target_link_libraries(onnxruntime_mlas_q4dq PRIVATE atomic) + endif() + target_link_libraries(onnxruntime_mlas_q4dq PRIVATE Threads::Threads) + + if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") + if (onnxruntime_ENABLE_WEBASSEMBLY_THREADS) + set_target_properties(onnxruntime_mlas_q4dq PROPERTIES LINK_FLAGS "-s ALLOW_MEMORY_GROWTH=1 -s PROXY_TO_PTHREAD=1 -s EXIT_RUNTIME=1") + else() + set_target_properties(onnxruntime_mlas_q4dq PROPERTIES LINK_FLAGS "-s ALLOW_MEMORY_GROWTH=1") + endif() + endif() + +endif() diff --git a/cmake/onnxruntime_nodejs.cmake b/cmake/onnxruntime_nodejs.cmake index 7b4ad950dc50a..6053b9d1088cd 100644 --- a/cmake/onnxruntime_nodejs.cmake +++ b/cmake/onnxruntime_nodejs.cmake @@ -60,6 +60,20 @@ else() endif() endif() +# setup providers +if (onnxruntime_USE_CUDA) + set(NODEJS_BINDING_USE_CUDA "--use_cuda") +endif() +if (onnxruntime_USE_DML) + set(NODEJS_BINDING_USE_DML "--use_dml") +endif() +if (onnxruntime_USE_TENSORRT) + set(NODEJS_BINDING_USE_TENSORRT "--use_tensorrt") +endif() +if (onnxruntime_USE_COREML) + set(NODEJS_BINDING_USE_COREML "--use_coreml") +endif() + if(NOT onnxruntime_ENABLE_STATIC_ANALYSIS) # add custom target add_custom_target(js_npm_ci ALL @@ -74,7 +88,9 @@ add_custom_target(js_common_npm_ci ALL add_custom_target(nodejs_binding_wrapper ALL COMMAND ${NPM_CLI} ci - COMMAND ${NPM_CLI} run build -- --onnxruntime-build-dir=${CMAKE_CURRENT_BINARY_DIR} --config=${CMAKE_BUILD_TYPE} --arch=${NODEJS_BINDING_ARCH} + COMMAND ${NPM_CLI} run build -- --onnxruntime-build-dir=${CMAKE_CURRENT_BINARY_DIR} --config=${CMAKE_BUILD_TYPE} + --arch=${NODEJS_BINDING_ARCH} ${NODEJS_BINDING_USE_CUDA} ${NODEJS_BINDING_USE_DML} ${NODEJS_BINDING_USE_TENSORRT} + ${NODEJS_BINDING_USE_COREML} WORKING_DIRECTORY ${JS_NODE_ROOT} COMMENT "Using cmake-js to build OnnxRuntime Node.js binding") diff --git a/cmake/onnxruntime_objectivec.cmake b/cmake/onnxruntime_objectivec.cmake index 10516077319d1..4be2f51a96ebc 100644 --- a/cmake/onnxruntime_objectivec.cmake +++ b/cmake/onnxruntime_objectivec.cmake @@ -40,6 +40,19 @@ file(GLOB onnxruntime_objc_srcs CONFIGURE_DEPENDS "${OBJC_ROOT}/*.m" "${OBJC_ROOT}/*.mm") +if(NOT onnxruntime_ENABLE_TRAINING_APIS) + list(REMOVE_ITEM onnxruntime_objc_headers + "${OBJC_ROOT}/include/ort_checkpoint.h" + "${OBJC_ROOT}/include/ort_training_session.h") + + list(REMOVE_ITEM onnxruntime_objc_srcs + "${OBJC_ROOT}/ort_checkpoint_internal.h" + "${OBJC_ROOT}/ort_checkpoint.mm" + "${OBJC_ROOT}/ort_training_session_internal.h" + "${OBJC_ROOT}/ort_training_session.mm") +endif() + + source_group(TREE "${OBJC_ROOT}" FILES ${onnxruntime_objc_headers} ${onnxruntime_objc_srcs}) @@ -61,6 +74,13 @@ if(onnxruntime_USE_COREML) "${ONNXRUNTIME_INCLUDE_DIR}/core/providers/coreml") endif() +if (onnxruntime_ENABLE_TRAINING_APIS) + target_include_directories(onnxruntime_objc + PRIVATE + "${ORTTRAINING_SOURCE_DIR}/training_api/include/") + +endif() + find_library(FOUNDATION_LIB Foundation REQUIRED) target_link_libraries(onnxruntime_objc @@ -105,6 +125,14 @@ if(onnxruntime_BUILD_UNIT_TESTS) "${OBJC_ROOT}/test/*.m" "${OBJC_ROOT}/test/*.mm") + if(NOT onnxruntime_ENABLE_TRAINING_APIS) + list(REMOVE_ITEM onnxruntime_objc_test_srcs + "${OBJC_ROOT}/test/ort_checkpoint_test.mm" + "${OBJC_ROOT}/test/ort_training_session_test.mm" + "${OBJC_ROOT}/test/ort_training_utils_test.mm") + + endif() + source_group(TREE "${OBJC_ROOT}" FILES ${onnxruntime_objc_test_srcs}) xctest_add_bundle(onnxruntime_objc_test onnxruntime_objc @@ -124,6 +152,7 @@ if(onnxruntime_BUILD_UNIT_TESTS) add_custom_command(TARGET onnxruntime_objc_test POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory "${OBJC_ROOT}/test/testdata" + "${ONNXRUNTIME_ROOT}/test/testdata/training_api" "$/Resources") xctest_add_test(XCTest.onnxruntime_objc_test onnxruntime_objc_test) diff --git a/cmake/onnxruntime_optimizer.cmake b/cmake/onnxruntime_optimizer.cmake index 84e64b634a38e..3da4198573d54 100644 --- a/cmake/onnxruntime_optimizer.cmake +++ b/cmake/onnxruntime_optimizer.cmake @@ -42,12 +42,18 @@ if (onnxruntime_MINIMAL_BUILD) "${ONNXRUNTIME_ROOT}/core/optimizer/selectors_actions/selector_action_transformer_apply_contexts.h" "${ONNXRUNTIME_ROOT}/core/optimizer/selectors_actions/selector_action_transformer.cc" "${ONNXRUNTIME_ROOT}/core/optimizer/selectors_actions/selector_action_transformer.h" - "${ONNXRUNTIME_ROOT}/core/optimizer/transpose_optimizer/optimizer_api_impl.cc" - "${ONNXRUNTIME_ROOT}/core/optimizer/transpose_optimizer/optimizer_api.h" - "${ONNXRUNTIME_ROOT}/core/optimizer/transpose_optimizer/optimizer_utils.h" - "${ONNXRUNTIME_ROOT}/core/optimizer/transpose_optimizer/ort_transpose_optimizer.cc" - "${ONNXRUNTIME_ROOT}/core/optimizer/transpose_optimizer/ort_transpose_optimizer.h" - "${ONNXRUNTIME_ROOT}/core/optimizer/transpose_optimizer/transpose_optimizer.cc" + # files required for layout transformation + "${ONNXRUNTIME_ROOT}/core/optimizer/layout_transformation/layout_transformation.h" + "${ONNXRUNTIME_ROOT}/core/optimizer/layout_transformation/layout_transformation.cc" + "${ONNXRUNTIME_ROOT}/core/optimizer/layout_transformation/layout_transformation_potentially_added_ops.h" + # files required for transpose optimization post-layout transformation + "${ONNXRUNTIME_ROOT}/core/optimizer/transpose_optimization/optimizer_api.h" + "${ONNXRUNTIME_ROOT}/core/optimizer/transpose_optimization/onnx_transpose_optimization.h" + "${ONNXRUNTIME_ROOT}/core/optimizer/transpose_optimization/onnx_transpose_optimization.cc" + "${ONNXRUNTIME_ROOT}/core/optimizer/transpose_optimization/ort_optimizer_api_impl.cc" + "${ONNXRUNTIME_ROOT}/core/optimizer/transpose_optimization/ort_optimizer_utils.h" + "${ONNXRUNTIME_ROOT}/core/optimizer/transpose_optimization/ort_transpose_optimization.h" + "${ONNXRUNTIME_ROOT}/core/optimizer/transpose_optimization/ort_transpose_optimization.cc" "${ONNXRUNTIME_ROOT}/core/optimizer/utils.cc" "${ONNXRUNTIME_ROOT}/core/optimizer/utils.h" ) @@ -59,6 +65,8 @@ else() "${ONNXRUNTIME_ROOT}/core/optimizer/*.cc" "${ONNXRUNTIME_ROOT}/core/optimizer/compute_optimizer/*.h" "${ONNXRUNTIME_ROOT}/core/optimizer/compute_optimizer/*.cc" + "${ONNXRUNTIME_ROOT}/core/optimizer/layout_transformation/*.h" + "${ONNXRUNTIME_ROOT}/core/optimizer/layout_transformation/*.cc" "${ONNXRUNTIME_ROOT}/core/optimizer/qdq_transformer/*.h" "${ONNXRUNTIME_ROOT}/core/optimizer/qdq_transformer/*.cc" "${ONNXRUNTIME_ROOT}/core/optimizer/qdq_transformer/selectors_actions/*.h" @@ -67,14 +75,12 @@ else() "${ONNXRUNTIME_ROOT}/core/optimizer/qdq_transformer/selectors_actions/shared/utils.cc" "${ONNXRUNTIME_ROOT}/core/optimizer/selectors_actions/*.h" "${ONNXRUNTIME_ROOT}/core/optimizer/selectors_actions/*.cc" - "${ONNXRUNTIME_ROOT}/core/optimizer/transpose_optimizer/*.h" - "${ONNXRUNTIME_ROOT}/core/optimizer/transpose_optimizer/*.cc" + "${ONNXRUNTIME_ROOT}/core/optimizer/transpose_optimization/*.h" + "${ONNXRUNTIME_ROOT}/core/optimizer/transpose_optimization/*.cc" ) endif() -if (onnxruntime_ENABLE_TRAINING_APIS) - # we need optimizers for both full build as well as training api only build. - # Using onnxruntime_ENABLE_TRAINING_APIS since it is always ON in a full training build. +if (onnxruntime_ENABLE_TRAINING) list(APPEND onnxruntime_optimizer_src_patterns "${ORTTRAINING_SOURCE_DIR}/core/optimizer/*.h" "${ORTTRAINING_SOURCE_DIR}/core/optimizer/*.cc" @@ -99,17 +105,21 @@ endif() onnxruntime_add_static_library(onnxruntime_optimizer ${onnxruntime_optimizer_srcs}) -install(DIRECTORY ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/optimizer DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/core) onnxruntime_add_include_to_target(onnxruntime_optimizer onnxruntime_common onnxruntime_framework onnx onnx_proto ${PROTOBUF_LIB} flatbuffers::flatbuffers Boost::mp11 safeint_interface) target_include_directories(onnxruntime_optimizer PRIVATE ${ONNXRUNTIME_ROOT}) -if (onnxruntime_ENABLE_TRAINING_APIS) +if (onnxruntime_ENABLE_TRAINING) target_include_directories(onnxruntime_optimizer PRIVATE ${ORTTRAINING_ROOT}) endif() +if (onnxruntime_ENABLE_TRITON) + target_link_libraries(onnxruntime_optimizer PRIVATE nlohmann_json::nlohmann_json) + onnxruntime_add_include_to_target(onnxruntime_optimizer Python::Module) +endif() add_dependencies(onnxruntime_optimizer ${onnxruntime_EXTERNAL_DEPENDENCIES}) set_target_properties(onnxruntime_optimizer PROPERTIES FOLDER "ONNXRuntime") if (NOT onnxruntime_BUILD_SHARED_LIB) - install(TARGETS onnxruntime_optimizer + install(DIRECTORY ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/optimizer DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/core) + install(TARGETS onnxruntime_optimizer ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} diff --git a/cmake/onnxruntime_providers.cmake b/cmake/onnxruntime_providers.cmake index c253b6b9c7197..b9e7873132089 100644 --- a/cmake/onnxruntime_providers.cmake +++ b/cmake/onnxruntime_providers.cmake @@ -93,6 +93,11 @@ file(GLOB_RECURSE onnxruntime_rocm_contrib_ops_cu_srcs CONFIGURE_DEPENDS "${ONNXRUNTIME_ROOT}/contrib_ops/rocm/*.cuh" ) +file(GLOB_RECURSE onnxruntime_js_contrib_ops_cc_srcs CONFIGURE_DEPENDS + "${ONNXRUNTIME_ROOT}/contrib_ops/js/*.h" + "${ONNXRUNTIME_ROOT}/contrib_ops/js/*.cc" +) + file(GLOB onnxruntime_providers_common_srcs CONFIGURE_DEPENDS "${ONNXRUNTIME_ROOT}/core/providers/*.h" "${ONNXRUNTIME_ROOT}/core/providers/*.cc" @@ -114,7 +119,7 @@ endif() if(onnxruntime_USE_NNAPI_BUILTIN) set(PROVIDERS_NNAPI onnxruntime_providers_nnapi) endif() -if(onnxruntime_USE_JS) +if(onnxruntime_USE_JSEP) set(PROVIDERS_JS onnxruntime_providers_js) endif() if(onnxruntime_USE_QNN) @@ -147,6 +152,9 @@ endif() if (onnxruntime_USE_XNNPACK) set(PROVIDERS_XNNPACK onnxruntime_providers_xnnpack) endif() +if(onnxruntime_USE_WEBNN) + set(PROVIDERS_WEBNN onnxruntime_providers_webnn) +endif() if(onnxruntime_USE_SNPE) include(onnxruntime_snpe_provider.cmake) endif() @@ -201,6 +209,8 @@ if (onnxruntime_ENABLE_TRAINING_OPS AND NOT onnxruntime_ENABLE_TRAINING) "${ORTTRAINING_SOURCE_DIR}/training_ops/cpu/tensorboard/*.h" "${ORTTRAINING_SOURCE_DIR}/training_ops/cpu/torch/*.cc" "${ORTTRAINING_SOURCE_DIR}/training_ops/cpu/torch/*.h" + "${ORTTRAINING_SOURCE_DIR}/training_ops/cpu/triton/triton_op.cc" + "${ORTTRAINING_SOURCE_DIR}/training_ops/cpu/triton/triton_op.h" ) list(REMOVE_ITEM onnxruntime_providers_src ${onnxruntime_cpu_full_training_only_srcs}) @@ -230,6 +240,8 @@ if (onnxruntime_ENABLE_TRAINING) file(GLOB_RECURSE onnxruntime_training_framework_excude_srcs CONFIGURE_DEPENDS "${ORTTRAINING_SOURCE_DIR}/core/framework/torch/*.h" "${ORTTRAINING_SOURCE_DIR}/core/framework/torch/*.cc" + "${ORTTRAINING_SOURCE_DIR}/core/framework/triton/*.h" + "${ORTTRAINING_SOURCE_DIR}/core/framework/triton/*.cc" ) list(REMOVE_ITEM onnxruntime_cpu_training_ops_srcs ${onnxruntime_training_framework_excude_srcs}) @@ -300,7 +312,7 @@ endif() if (onnxruntime_ENABLE_TRAINING) add_dependencies(onnxruntime_providers tensorboard) onnxruntime_add_include_to_target(onnxruntime_providers tensorboard) - if (onnxruntime_ENABLE_TRAINING_TORCH_INTEROP) + if (onnxruntime_ENABLE_TRAINING_TORCH_INTEROP OR onnxruntime_ENABLE_TRITON) onnxruntime_add_include_to_target(onnxruntime_providers Python::Module) endif() @@ -309,14 +321,14 @@ if (onnxruntime_ENABLE_TRAINING) endif() endif() -install(DIRECTORY ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/providers/cpu DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/core/providers) +install(FILES ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/providers/cpu/cpu_provider_factory.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/) 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" - AND NOT (CMAKE_SYSTEM_NAME STREQUAL "Android") - AND NOT onnxruntime_BUILD_WEBASSEMBLY) + AND NOT CMAKE_SYSTEM_NAME STREQUAL "Android" + AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") file(GLOB onnxruntime_providers_shared_cc_srcs CONFIGURE_DEPENDS "${ONNXRUNTIME_ROOT}/core/providers/shared/*.h" "${ONNXRUNTIME_ROOT}/core/providers/shared/*.cc" @@ -354,7 +366,7 @@ if (NOT onnxruntime_MINIMAL_BUILD AND NOT onnxruntime_EXTENDED_MINIMAL_BUILD install(TARGETS onnxruntime_providers_shared ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR} ) endif() @@ -424,12 +436,12 @@ if (onnxruntime_USE_CUDA) "${ORTTRAINING_SOURCE_DIR}/training_ops/cuda/controlflow/wait.cc" "${ORTTRAINING_SOURCE_DIR}/training_ops/cuda/controlflow/wait.h" "${ORTTRAINING_SOURCE_DIR}/training_ops/cuda/controlflow/yield.cc" - "${ORTTRAINING_SOURCE_DIR}/training_ops/cuda/controlflow/yield.h" "${ORTTRAINING_SOURCE_DIR}/training_ops/cuda/gist/*.cc" "${ORTTRAINING_SOURCE_DIR}/training_ops/cuda/gist/*.h" "${ORTTRAINING_SOURCE_DIR}/training_ops/cuda/gist/*.cu" "${ORTTRAINING_SOURCE_DIR}/training_ops/cuda/torch/*.cc" "${ORTTRAINING_SOURCE_DIR}/training_ops/cuda/torch/*.h" + "${ORTTRAINING_SOURCE_DIR}/training_ops/cuda/triton/triton_op.cc" ) list(REMOVE_ITEM onnxruntime_providers_cuda_src ${onnxruntime_cuda_full_training_only_srcs}) @@ -448,125 +460,148 @@ if (onnxruntime_USE_CUDA) if (onnxruntime_REDUCED_OPS_BUILD) substitute_op_reduction_srcs(onnxruntime_providers_cuda_src) endif() - onnxruntime_add_shared_library_module(onnxruntime_providers_cuda ${onnxruntime_providers_cuda_src}) - if (onnxruntime_REDUCED_OPS_BUILD) - add_op_reduction_include_dirs(onnxruntime_providers_cuda) - endif() - - #target_compile_options(onnxruntime_providers_cuda PRIVATE "$<$:SHELL:-Xcompiler \"/analyze:stacksize 131072\">") - if (HAS_GUARD_CF) - target_compile_options(onnxruntime_providers_cuda PRIVATE "$<$:SHELL:-Xcompiler /guard:cf>") - endif() - if (HAS_QSPECTRE) - target_compile_options(onnxruntime_providers_cuda PRIVATE "$<$:SHELL:-Xcompiler /Qspectre>") - endif() - foreach(ORT_FLAG ${ORT_WARNING_FLAGS}) - target_compile_options(onnxruntime_providers_cuda PRIVATE "$<$:SHELL:-Xcompiler \"${ORT_FLAG}\">") - endforeach() - # CUDA 11.3+ supports parallel compilation - # https://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html#options-for-guiding-compiler-driver-threads - if (CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL 11.3) - target_compile_options(onnxruntime_providers_cuda PRIVATE "$<$:SHELL:--threads \"${onnxruntime_NVCC_THREADS}\">") - endif() - if (UNIX) - target_compile_options(onnxruntime_providers_cuda PRIVATE "$<$:SHELL:-Xcompiler -Wno-reorder>" - "$<$>:-Wno-reorder>") - target_compile_options(onnxruntime_providers_cuda PRIVATE "$<$:SHELL:-Xcompiler -Wno-error=sign-compare>" - "$<$>:-Wno-error=sign-compare>") - else() - #mutex.cuh(91): warning C4834: discarding return value of function with 'nodiscard' attribute - target_compile_options(onnxruntime_providers_cuda PRIVATE "$<$:SHELL:-Xcompiler /wd4834>") - target_compile_options(onnxruntime_providers_cuda PRIVATE "$<$:SHELL:-Xcompiler /wd4127>") - endif() + # cuda_provider_interface.cc is removed from the object target: onnxruntime_providers_cuda_obj and + # add to the lib onnxruntime_providers_cuda separatedly. + # onnxruntime_providers_cuda_ut can share all the object files with onnxruntime_providers_cuda except cuda_provider_interface.cc. + set(cuda_provider_interface_src ${ONNXRUNTIME_ROOT}/core/providers/cuda/cuda_provider_interface.cc) + list(REMOVE_ITEM onnxruntime_providers_cuda_src ${cuda_provider_interface_src}) + onnxruntime_add_object_library(onnxruntime_providers_cuda_obj ${onnxruntime_providers_cuda_src}) + onnxruntime_add_shared_library_module(onnxruntime_providers_cuda ${cuda_provider_interface_src} $) + # config_cuda_provider_shared_module can be used to config onnxruntime_providers_cuda_obj, onnxruntime_providers_cuda & onnxruntime_providers_cuda_ut. + # This function guarantees that all 3 targets have the same configurations. + function(config_cuda_provider_shared_module target) + if (onnxruntime_REDUCED_OPS_BUILD) + add_op_reduction_include_dirs(${target}) + endif() - onnxruntime_add_include_to_target(onnxruntime_providers_cuda onnxruntime_common onnxruntime_framework onnx onnx_proto ${PROTOBUF_LIB} flatbuffers::flatbuffers) - if (onnxruntime_ENABLE_TRAINING_OPS) - onnxruntime_add_include_to_target(onnxruntime_providers_cuda onnxruntime_training) - if (onnxruntime_ENABLE_TRAINING) - target_link_libraries(onnxruntime_providers_cuda PRIVATE onnxruntime_training) + if (HAS_GUARD_CF) + target_compile_options(${target} PRIVATE "$<$:SHELL:-Xcompiler /guard:cf>") endif() - if (onnxruntime_ENABLE_TRAINING_TORCH_INTEROP) - onnxruntime_add_include_to_target(onnxruntime_providers_cuda Python::Module) + if (HAS_QSPECTRE) + target_compile_options(${target} PRIVATE "$<$:SHELL:-Xcompiler /Qspectre>") + endif() + foreach(ORT_FLAG ${ORT_WARNING_FLAGS}) + target_compile_options(${target} PRIVATE "$<$:SHELL:-Xcompiler \"${ORT_FLAG}\">") + endforeach() + # CUDA 11.3+ supports parallel compilation + # https://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html#options-for-guiding-compiler-driver-threads + if (CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL 11.3) + target_compile_options(${target} PRIVATE "$<$:SHELL:--threads \"${onnxruntime_NVCC_THREADS}\">") + endif() + if (UNIX) + target_compile_options(${target} PRIVATE "$<$:SHELL:-Xcompiler -Wno-reorder>" + "$<$>:-Wno-reorder>") + target_compile_options(${target} PRIVATE "$<$:SHELL:-Xcompiler -Wno-error=sign-compare>" + "$<$>:-Wno-error=sign-compare>") + else() + #mutex.cuh(91): warning C4834: discarding return value of function with 'nodiscard' attribute + target_compile_options(${target} PRIVATE "$<$:SHELL:-Xcompiler /wd4834>") + target_compile_options(${target} PRIVATE "$<$:SHELL:-Xcompiler /wd4127>") endif() - endif() - add_dependencies(onnxruntime_providers_cuda onnxruntime_providers_shared ${onnxruntime_EXTERNAL_DEPENDENCIES}) - target_link_libraries(onnxruntime_providers_cuda PRIVATE cublasLt cublas cudnn curand cufft ${ABSEIL_LIBS} ${ONNXRUNTIME_PROVIDERS_SHARED} Boost::mp11 safeint_interface) - if(onnxruntime_CUDNN_HOME) - target_include_directories(onnxruntime_providers_cuda PRIVATE ${onnxruntime_CUDNN_HOME}/include) - target_link_directories(onnxruntime_providers_cuda PRIVATE ${onnxruntime_CUDNN_HOME}/lib) - endif() + onnxruntime_add_include_to_target(${target} onnxruntime_common onnxruntime_framework onnx onnx_proto ${PROTOBUF_LIB} flatbuffers::flatbuffers) + if (onnxruntime_ENABLE_TRAINING_OPS) + onnxruntime_add_include_to_target(${target} onnxruntime_training) + if (onnxruntime_ENABLE_TRAINING) + target_link_libraries(${target} PRIVATE onnxruntime_training) + endif() + if (onnxruntime_ENABLE_TRAINING_TORCH_INTEROP OR onnxruntime_ENABLE_TRITON) + onnxruntime_add_include_to_target(${target} Python::Module) + endif() + endif() - if (onnxruntime_USE_FLASH_ATTENTION) - include(cutlass) - target_include_directories(onnxruntime_providers_cuda PRIVATE ${cutlass_SOURCE_DIR}/include ${cutlass_SOURCE_DIR}/examples) - endif() + add_dependencies(${target} onnxruntime_providers_shared ${onnxruntime_EXTERNAL_DEPENDENCIES}) + target_link_libraries(${target} PRIVATE cublasLt cublas cudnn curand cufft ${ABSEIL_LIBS} ${ONNXRUNTIME_PROVIDERS_SHARED} Boost::mp11 safeint_interface) + if(onnxruntime_CUDNN_HOME) + target_include_directories(${target} PRIVATE ${onnxruntime_CUDNN_HOME}/include) + target_link_directories(${target} PRIVATE ${onnxruntime_CUDNN_HOME}/lib) + endif() - target_include_directories(onnxruntime_providers_cuda PRIVATE ${ONNXRUNTIME_ROOT} ${CMAKE_CURRENT_BINARY_DIR} ${eigen_INCLUDE_DIRS} ${TVM_INCLUDES} PUBLIC ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES}) - # ${CMAKE_CURRENT_BINARY_DIR} is so that #include "onnxruntime_config.h" inside tensor_shape.h is found - set_target_properties(onnxruntime_providers_cuda PROPERTIES LINKER_LANGUAGE CUDA) - set_target_properties(onnxruntime_providers_cuda PROPERTIES FOLDER "ONNXRuntime") + if (onnxruntime_USE_TRITON_KERNEL) + # compile triton kernel, generate .a and .h files + include(onnxruntime_compile_triton_kernel.cmake) + compile_triton_kernel(triton_kernel_obj_file triton_kernel_header_dir) + add_dependencies(${target} onnxruntime_triton_kernel) + target_compile_definitions(${target} PRIVATE USE_TRITON_KERNEL) + target_include_directories(${target} PRIVATE ${triton_kernel_header_dir}) + target_link_libraries(${target} PUBLIC -Wl,--whole-archive ${triton_kernel_obj_file} -Wl,--no-whole-archive) + # lib cuda needed by cuLaunchKernel + target_link_libraries(${target} PRIVATE cuda) + endif() - if (onnxruntime_ENABLE_CUDA_PROFILING) # configure cupti for cuda profiling - target_include_directories(onnxruntime_providers_cuda PRIVATE ${onnxruntime_CUDA_HOME}/extras/CUPTI/include) - target_link_directories(onnxruntime_providers_cuda PRIVATE ${onnxruntime_CUDA_HOME}/extras/CUPTI/lib64) - target_link_libraries(onnxruntime_providers_cuda PRIVATE cupti) - endif() + if (onnxruntime_USE_FLASH_ATTENTION OR onnxruntime_USE_MEMORY_EFFICIENT_ATTENTION) + include(cutlass) + target_include_directories(${target} PRIVATE ${cutlass_SOURCE_DIR}/include ${cutlass_SOURCE_DIR}/examples) + endif() - if (onnxruntime_ENABLE_NVTX_PROFILE) - target_link_libraries(onnxruntime_providers_cuda PRIVATE nvToolsExt) - endif() + target_include_directories(${target} PRIVATE ${ONNXRUNTIME_ROOT} ${CMAKE_CURRENT_BINARY_DIR} ${eigen_INCLUDE_DIRS} ${TVM_INCLUDES} PUBLIC ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES}) + # ${CMAKE_CURRENT_BINARY_DIR} is so that #include "onnxruntime_config.h" inside tensor_shape.h is found + set_target_properties(${target} PROPERTIES LINKER_LANGUAGE CUDA) + set_target_properties(${target} PROPERTIES FOLDER "ONNXRuntime") - if (onnxruntime_ENABLE_TRAINING_OPS) - target_include_directories(onnxruntime_providers_cuda PRIVATE ${ORTTRAINING_ROOT} ${MPI_CXX_INCLUDE_DIRS}) - endif() + if (onnxruntime_ENABLE_CUDA_PROFILING) # configure cupti for cuda profiling + target_include_directories(${target} PRIVATE ${onnxruntime_CUDA_HOME}/extras/CUPTI/include) + target_link_directories(${target} PRIVATE ${onnxruntime_CUDA_HOME}/extras/CUPTI/lib64) + target_link_libraries(${target} PRIVATE cupti) + endif() - if(onnxruntime_USE_MPI) - target_link_libraries(onnxruntime_providers_cuda PRIVATE ${MPI_LIBRARIES} ${MPI_CXX_LINK_FLAGS}) - endif() + if (onnxruntime_ENABLE_NVTX_PROFILE AND NOT WIN32) + target_link_libraries(${target} PRIVATE nvToolsExt) + endif() - if (onnxruntime_USE_NCCL) - target_include_directories(onnxruntime_providers_cuda PRIVATE ${NCCL_INCLUDE_DIRS}) - target_link_libraries(onnxruntime_providers_cuda PRIVATE ${NCCL_LIBRARIES}) - endif() + if (onnxruntime_ENABLE_TRAINING_OPS) + target_include_directories(${target} PRIVATE ${ORTTRAINING_ROOT} ${MPI_CXX_INCLUDE_DIRS}) + endif() - if (WIN32) - # *.cu cannot use PCH - if (NOT onnxruntime_BUILD_CACHE) - target_precompile_headers(onnxruntime_providers_cuda PUBLIC - "${ONNXRUNTIME_ROOT}/core/providers/cuda/cuda_pch.h" - "${ONNXRUNTIME_ROOT}/core/providers/cuda/cuda_pch.cc" - ) + if(onnxruntime_USE_MPI) + target_link_libraries(${target} PRIVATE ${MPI_LIBRARIES} ${MPI_CXX_LINK_FLAGS}) endif() - # minimize the Windows includes. - # this avoids an issue with CUDA 11.6 where 'small' is defined in the windows and cuda headers. - target_compile_definitions(onnxruntime_providers_cuda PRIVATE "WIN32_LEAN_AND_MEAN") + if (onnxruntime_USE_NCCL) + target_include_directories(${target} PRIVATE ${NCCL_INCLUDE_DIRS}) + target_link_libraries(${target} PRIVATE ${NCCL_LIBRARIES}) + endif() - # disable a warning from the CUDA headers about unreferenced local functions - #target_compile_options(onnxruntime_providers_cuda PRIVATE /wd4505) - set(onnxruntime_providers_cuda_static_library_flags - -IGNORE:4221 # LNK4221: This object file does not define any previously undefined public symbols, so it will not be used by any link operation that consumes this library - ) - set_target_properties(onnxruntime_providers_cuda PROPERTIES - STATIC_LIBRARY_FLAGS "${onnxruntime_providers_cuda_static_library_flags}") - endif() + if (WIN32) + # *.cu cannot use PCH + if (NOT onnxruntime_BUILD_CACHE) + target_precompile_headers(${target} PUBLIC + "${ONNXRUNTIME_ROOT}/core/providers/cuda/cuda_pch.h" + "${ONNXRUNTIME_ROOT}/core/providers/cuda/cuda_pch.cc" + ) + endif() - if(APPLE) - set_property(TARGET onnxruntime_providers_cuda APPEND_STRING PROPERTY LINK_FLAGS "-Xlinker -exported_symbols_list ${ONNXRUNTIME_ROOT}/core/providers/cuda/exported_symbols.lst") - target_link_libraries(onnxruntime_providers_cuda PRIVATE nsync::nsync_cpp) - elseif(UNIX) - set_property(TARGET onnxruntime_providers_cuda APPEND_STRING PROPERTY LINK_FLAGS "-Xlinker --version-script=${ONNXRUNTIME_ROOT}/core/providers/cuda/version_script.lds -Xlinker --gc-sections") - target_link_libraries(onnxruntime_providers_cuda PRIVATE nsync::nsync_cpp) - elseif(WIN32) - set_property(TARGET onnxruntime_providers_cuda APPEND_STRING PROPERTY LINK_FLAGS "-DEF:${ONNXRUNTIME_ROOT}/core/providers/cuda/symbols.def") - else() - message(FATAL_ERROR "onnxruntime_providers_cuda unknown platform, need to specify shared library exports for it") - endif() + # minimize the Windows includes. + # this avoids an issue with CUDA 11.6 where 'small' is defined in the windows and cuda headers. + target_compile_definitions(${target} PRIVATE "WIN32_LEAN_AND_MEAN") - if (onnxruntime_ENABLE_ATEN) - target_compile_definitions(onnxruntime_providers_cuda PRIVATE ENABLE_ATEN) - endif() + # disable a warning from the CUDA headers about unreferenced local functions + #target_compile_options(${target} PRIVATE /wd4505) + set(onnxruntime_providers_cuda_static_library_flags + -IGNORE:4221 # LNK4221: This object file does not define any previously undefined public symbols, so it will not be used by any link operation that consumes this library + ) + set_target_properties(${target} PROPERTIES + STATIC_LIBRARY_FLAGS "${onnxruntime_providers_cuda_static_library_flags}") + endif() + + if(APPLE) + set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS "-Xlinker -exported_symbols_list ${ONNXRUNTIME_ROOT}/core/providers/cuda/exported_symbols.lst") + target_link_libraries(${target} PRIVATE nsync::nsync_cpp) + elseif(UNIX) + set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS "-Xlinker --version-script=${ONNXRUNTIME_ROOT}/core/providers/cuda/version_script.lds -Xlinker --gc-sections") + target_link_libraries(${target} PRIVATE nsync::nsync_cpp) + elseif(WIN32) + set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS "-DEF:${ONNXRUNTIME_ROOT}/core/providers/cuda/symbols.def") + else() + message(FATAL_ERROR "${target} unknown platform, need to specify shared library exports for it") + endif() + + if (onnxruntime_ENABLE_ATEN) + target_compile_definitions(${target} PRIVATE ENABLE_ATEN) + endif() + endfunction() + config_cuda_provider_shared_module(onnxruntime_providers_cuda_obj) + config_cuda_provider_shared_module(onnxruntime_providers_cuda) install(TARGETS onnxruntime_providers_cuda ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} @@ -594,8 +629,9 @@ if (onnxruntime_USE_DNNL) add_dependencies(onnxruntime_providers_dnnl onnxruntime_providers_shared project_dnnl ${onnxruntime_EXTERNAL_DEPENDENCIES}) target_include_directories(onnxruntime_providers_dnnl PRIVATE ${ONNXRUNTIME_ROOT} ${eigen_INCLUDE_DIRS} ${DNNL_INCLUDE_DIR} ${DNNL_OCL_INCLUDE_DIR}) # ${CMAKE_CURRENT_BINARY_DIR} is so that #include "onnxruntime_config.h" inside tensor_shape.h is found - target_link_libraries(onnxruntime_providers_dnnl PRIVATE dnnl ${ONNXRUNTIME_PROVIDERS_SHARED} Boost::mp11 ${ABSEIL_LIBS} ${GSL_TARGET}) - install(DIRECTORY ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/providers/dnnl DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/core/providers) + target_link_libraries(onnxruntime_providers_dnnl PRIVATE dnnl ${ONNXRUNTIME_PROVIDERS_SHARED} Boost::mp11 ${ABSEIL_LIBS} ${GSL_TARGET} safeint_interface) + install(FILES ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/providers/dnnl/dnnl_provider_options.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/) set_target_properties(onnxruntime_providers_dnnl PROPERTIES FOLDER "ONNXRuntime") set_target_properties(onnxruntime_providers_dnnl PROPERTIES LINKER_LANGUAGE CXX) @@ -658,6 +694,13 @@ if (onnxruntime_USE_TENSORRT) 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() + if (onnxruntime_USE_TENSORRT_BUILTIN_PARSER) # Add TensorRT library find_path(TENSORRT_INCLUDE_DIR NvInfer.h @@ -686,6 +729,7 @@ if (onnxruntime_USE_TENSORRT) onnxruntime_fetchcontent_makeavailable(onnx_tensorrt) include_directories(${onnx_tensorrt_SOURCE_DIR}) set(CMAKE_CXX_FLAGS ${OLD_CMAKE_CXX_FLAGS}) + set(CUDA_INCLUDE_DIR ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES}) # onnx-tensorrt repo needs this variable to build if ( CMAKE_COMPILER_IS_GNUCC ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter") endif() @@ -714,6 +758,8 @@ if (onnxruntime_USE_TENSORRT) "${ONNXRUNTIME_ROOT}/core/providers/shared_library/*.cc" "${ONNXRUNTIME_ROOT}/core/providers/cuda/cuda_stream_handle.h" "${ONNXRUNTIME_ROOT}/core/providers/cuda/cuda_stream_handle.cc" + "${ONNXRUNTIME_ROOT}/core/providers/cuda/cuda_graph.h" + "${ONNXRUNTIME_ROOT}/core/providers/cuda/cuda_graph.cc" ) source_group(TREE ${ONNXRUNTIME_ROOT}/core FILES ${onnxruntime_providers_tensorrt_cc_srcs}) @@ -731,7 +777,7 @@ if (onnxruntime_USE_TENSORRT) endif() # ${CMAKE_CURRENT_BINARY_DIR} is so that #include "onnxruntime_config.h" inside tensor_shape.h is found - install(DIRECTORY ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/providers/tensorrt DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/core/providers) + set_target_properties(onnxruntime_providers_tensorrt PROPERTIES PUBLIC_HEADER ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/providers/tensorrt/tensorrt_provider_factory.h) set_target_properties(onnxruntime_providers_tensorrt PROPERTIES LINKER_LANGUAGE CUDA) set_target_properties(onnxruntime_providers_tensorrt PROPERTIES FOLDER "ONNXRuntime") target_compile_definitions(onnxruntime_providers_tensorrt PRIVATE ONNXIFI_BUILD_LIBRARY=1) @@ -762,28 +808,53 @@ if (onnxruntime_USE_TENSORRT) endif() install(TARGETS onnxruntime_providers_tensorrt + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif() if (onnxruntime_USE_VITISAI) - file(GLOB_RECURSE onnxruntime_providers_vitisai_cc_srcs CONFIGURE_DEPENDS - "${ONNXRUNTIME_ROOT}/core/providers/vitisai/*.h" + if ("${GIT_COMMIT_ID}" STREQUAL "") + execute_process( + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMAND git rev-parse HEAD + OUTPUT_VARIABLE GIT_COMMIT_ID + OUTPUT_STRIP_TRAILING_WHITESPACE) + endif() + configure_file(${ONNXRUNTIME_ROOT}/core/providers/vitisai/imp/version_info.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/VitisAI/version_info.h) + file(GLOB onnxruntime_providers_vitisai_cc_srcs CONFIGURE_DEPENDS "${ONNXRUNTIME_ROOT}/core/providers/vitisai/*.cc" + "${ONNXRUNTIME_ROOT}/core/providers/vitisai/*.h" + "${ONNXRUNTIME_ROOT}/core/providers/vitisai/imp/*.cc" + "${ONNXRUNTIME_ROOT}/core/providers/vitisai/imp/*.h" ) - + list(REMOVE_ITEM onnxruntime_providers_vitisai_cc_srcs "${ONNXRUNTIME_ROOT}/core/providers/vitisai/onnxruntime_vitisai_ep_stub.cc") source_group(TREE ${ONNXRUNTIME_ROOT}/core FILES ${onnxruntime_providers_vitisai_cc_srcs}) onnxruntime_add_static_library(onnxruntime_providers_vitisai ${onnxruntime_providers_vitisai_cc_srcs}) - onnxruntime_add_include_to_target(onnxruntime_providers_vitisai - onnxruntime_common onnxruntime_framework onnx onnx_proto ${PROTOBUF_LIB} flatbuffers::flatbuffers Boost::mp11 safeint_interface - ) - add_dependencies(onnxruntime_providers_vitisai ${onnxruntime_EXTERNAL_DEPENDENCIES}) + onnxruntime_add_include_to_target(onnxruntime_providers_vitisai onnxruntime_common onnxruntime_framework onnx onnx_proto) + onnxruntime_add_shared_library(onnxruntime_vitisai_ep ${ONNXRUNTIME_ROOT}/core/providers/vitisai/onnxruntime_vitisai_ep_stub.cc) + onnxruntime_add_include_to_target(onnxruntime_vitisai_ep onnxruntime_common) + target_include_directories(onnxruntime_vitisai_ep PRIVATE "${ONNXRUNTIME_ROOT}" "${ONNXRUNTIME_ROOT}/core/providers/vitisai/include") + target_link_libraries(onnxruntime_providers_vitisai PUBLIC onnxruntime_vitisai_ep PRIVATE onnx protobuf::libprotobuf nlohmann_json::nlohmann_json ) + target_compile_definitions(onnxruntime_vitisai_ep + PRIVATE "-DONNXRUNTIME_VITISAI_EP_STUB=1" "-DONNXRUNTIME_VITISAI_EP_EXPORT_DLL=1") + if(NOT MSVC) + target_compile_options(onnxruntime_providers_vitisai PUBLIC $<$:-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0>) + endif(NOT MSVC) + + target_include_directories(onnxruntime_providers_vitisai PRIVATE "${ONNXRUNTIME_ROOT}/core/providers/vitisai/include" ${XRT_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}/VitisAI) + if(MSVC) + target_compile_options(onnxruntime_providers_vitisai PRIVATE "/Zc:__cplusplus") + # for dll interface warning. + target_compile_options(onnxruntime_providers_vitisai PRIVATE "/wd4251") + # for unused formal parameter + target_compile_options(onnxruntime_providers_vitisai PRIVATE "/wd4100") + else(MSVC) + target_compile_options(onnxruntime_providers_vitisai PRIVATE -Wno-unused-parameter) + endif(MSVC) + set_target_properties(onnxruntime_providers_vitisai PROPERTIES FOLDER "ONNXRuntime") - target_include_directories(onnxruntime_providers_vitisai PRIVATE ${ONNXRUNTIME_ROOT} ${eigen_INCLUDE_DIRS} ${VITISAI_INCLUDE_DIR}) - install(DIRECTORY ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/providers/vitisai - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/core/providers - ) set_target_properties(onnxruntime_providers_vitisai PROPERTIES LINKER_LANGUAGE CXX) if (NOT onnxruntime_BUILD_SHARED_LIB) @@ -834,14 +905,15 @@ if (onnxruntime_USE_OPENVINO) source_group(TREE ${ONNXRUNTIME_ROOT}/core FILES ${onnxruntime_providers_openvino_cc_srcs}) onnxruntime_add_shared_library_module(onnxruntime_providers_openvino ${onnxruntime_providers_openvino_cc_srcs} "${ONNXRUNTIME_ROOT}/core/dll/onnxruntime.rc") onnxruntime_add_include_to_target(onnxruntime_providers_openvino onnxruntime_common onnx) - install(DIRECTORY ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/providers/openvino DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/core/providers) + install(FILES ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/providers/openvino/openvino_provider_factory.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/) set_target_properties(onnxruntime_providers_openvino PROPERTIES LINKER_LANGUAGE CXX) set_target_properties(onnxruntime_providers_openvino PROPERTIES FOLDER "ONNXRuntime") if(NOT MSVC) target_compile_options(onnxruntime_providers_openvino PRIVATE "-Wno-parentheses") endif() add_dependencies(onnxruntime_providers_openvino onnxruntime_providers_shared ${onnxruntime_EXTERNAL_DEPENDENCIES}) - target_include_directories(onnxruntime_providers_openvino SYSTEM PUBLIC ${ONNXRUNTIME_ROOT} ${CMAKE_CURRENT_BINARY_DIR} ${eigen_INCLUDE_DIRS} ${OpenVINO_INCLUDE_DIR} ${OPENVINO_INCLUDE_DIR_LIST} ${PYTHON_INCLUDE_DIRS} $ENV{OPENCL_INCS}) + target_include_directories(onnxruntime_providers_openvino SYSTEM PUBLIC ${ONNXRUNTIME_ROOT} ${CMAKE_CURRENT_BINARY_DIR} ${eigen_INCLUDE_DIRS} ${OpenVINO_INCLUDE_DIR} ${OPENVINO_INCLUDE_DIR_LIST} ${PYTHON_INCLUDE_DIRS} $ENV{OPENCL_INCS} $ENV{OPENCL_INCS}/../../cl_headers/) target_link_libraries(onnxruntime_providers_openvino ${ONNXRUNTIME_PROVIDERS_SHARED} Boost::mp11 ${OPENVINO_LIB_LIST} ${ABSEIL_LIBS}) target_compile_definitions(onnxruntime_providers_openvino PRIVATE VER_MAJOR=${VERSION_MAJOR_PART}) @@ -983,6 +1055,31 @@ if (onnxruntime_USE_COREML) endif() endif() +if (onnxruntime_USE_WEBNN) + if (onnxruntime_MINIMAL_BUILD AND NOT onnxruntime_EXTENDED_MINIMAL_BUILD) + message(FATAL_ERROR "WebNN EP can not be used in a basic minimal build. Please build with '--minimal_build extended'") + endif() + + add_compile_definitions(USE_WEBNN=1) + if (onnxruntime_ENABLE_WEBASSEMBLY_THREADS) + add_definitions(-DENABLE_WEBASSEMBLY_THREADS=1) + endif() + file(GLOB_RECURSE onnxruntime_providers_webnn_cc_srcs CONFIGURE_DEPENDS + "${ONNXRUNTIME_ROOT}/core/providers/webnn/*.h" + "${ONNXRUNTIME_ROOT}/core/providers/webnn/*.cc" + "${ONNXRUNTIME_ROOT}/core/providers/shared/utils/utils.h" + "${ONNXRUNTIME_ROOT}/core/providers/shared/utils/utils.cc" + ) + + source_group(TREE ${REPO_ROOT} FILES ${onnxruntime_providers_webnn_cc_srcs}) + onnxruntime_add_static_library(onnxruntime_providers_webnn ${onnxruntime_providers_webnn_cc_srcs}) + onnxruntime_add_include_to_target(onnxruntime_providers_webnn onnxruntime_common onnx onnx_proto flatbuffers::flatbuffers Boost::mp11 safeint_interface) + + add_dependencies(onnxruntime_providers_webnn onnx ${onnxruntime_EXTERNAL_DEPENDENCIES}) + set_target_properties(onnxruntime_providers_webnn PROPERTIES FOLDER "ONNXRuntime") + set_target_properties(onnxruntime_providers_webnn PROPERTIES LINKER_LANGUAGE CXX) +endif() + if (onnxruntime_USE_NNAPI_BUILTIN) if (onnxruntime_MINIMAL_BUILD AND NOT onnxruntime_EXTENDED_MINIMAL_BUILD) message(FATAL_ERROR "NNAPI can not be used in a basic minimal build. Please build with '--minimal_build extended'") @@ -1067,20 +1164,24 @@ if (onnxruntime_USE_NNAPI_BUILTIN) endif() endif() -if (onnxruntime_USE_JS) - add_compile_definitions(USE_JS=1) +if (onnxruntime_USE_JSEP) + add_compile_definitions(USE_JSEP=1) file(GLOB_RECURSE onnxruntime_providers_js_cc_srcs "${ONNXRUNTIME_ROOT}/core/providers/js/*.h" "${ONNXRUNTIME_ROOT}/core/providers/js/*.cc" ) + if(NOT onnxruntime_DISABLE_CONTRIB_OPS) + source_group(TREE ${ONNXRUNTIME_ROOT} FILES ${onnxruntime_js_contrib_ops_cc_srcs}) + list(APPEND onnxruntime_providers_js_cc_srcs ${onnxruntime_js_contrib_ops_cc_srcs}) + endif() - source_group(TREE ${ONNXRUNTIME_ROOT}/core FILES ${onnxruntime_providers_js_cc_srcs}) + source_group(TREE ${ONNXRUNTIME_ROOT} FILES ${onnxruntime_providers_js_cc_srcs}) onnxruntime_add_static_library(onnxruntime_providers_js ${onnxruntime_providers_js_cc_srcs}) onnxruntime_add_include_to_target(onnxruntime_providers_js onnxruntime_common onnxruntime_framework onnx onnx_proto ${PROTOBUF_LIB} flatbuffers Boost::mp11 ) - + target_include_directories(onnxruntime_providers_js PRIVATE ${eigen_INCLUDE_DIRS}) add_dependencies(onnxruntime_providers_js ${onnxruntime_EXTERNAL_DEPENDENCIES}) endif() @@ -1183,14 +1284,17 @@ if (onnxruntime_USE_DML) source_group(TREE ${ONNXRUNTIME_ROOT}/core FILES ${onnxruntime_providers_dml_cc_srcs}) onnxruntime_add_static_library(onnxruntime_providers_dml ${onnxruntime_providers_dml_cc_srcs}) onnxruntime_add_include_to_target(onnxruntime_providers_dml - onnxruntime_common onnxruntime_framework onnx onnx_proto ${PROTOBUF_LIB} flatbuffers::flatbuffers Boost::mp11 safeint_interface WIL::WIL + onnxruntime_common onnxruntime_framework onnx onnx_proto ${PROTOBUF_LIB} flatbuffers::flatbuffers Boost::mp11 safeint_interface ${WIL_TARGET} ) add_dependencies(onnxruntime_providers_dml ${onnxruntime_EXTERNAL_DEPENDENCIES}) target_include_directories(onnxruntime_providers_dml PRIVATE ${ONNXRUNTIME_ROOT} ) - add_definitions(-DDML_TARGET_VERSION_USE_LATEST=1) + target_compile_definitions(onnxruntime_providers_dml PRIVATE DML_TARGET_VERSION_USE_LATEST=1) + if(WIN32) + target_compile_options(onnxruntime_providers_dml PRIVATE "/wd4100" "/wd4238" "/wd4189" "/wd4702") + endif() if (NOT onnxruntime_USE_CUSTOM_DIRECTML) foreach(file "DirectML.dll" "DirectML.pdb" "DirectML.Debug.dll" "DirectML.Debug.pdb") @@ -1246,8 +1350,8 @@ if (onnxruntime_USE_DML) target_compile_options(onnxruntime_providers_dml PRIVATE "/W3") endif() - install(DIRECTORY ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/providers/dml - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/core/providers + install(FILES ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/providers/dml/dml_provider_factory.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/ ) set_target_properties(onnxruntime_providers_dml PROPERTIES LINKER_LANGUAGE CXX) @@ -1305,7 +1409,6 @@ if (onnxruntime_USE_MIGRAPHX) add_dependencies(onnxruntime_providers_migraphx onnxruntime_providers_shared ${onnxruntime_EXTERNAL_DEPENDENCIES}) target_link_libraries(onnxruntime_providers_migraphx PRIVATE ${migraphx_libs} ${ONNXRUNTIME_PROVIDERS_SHARED} onnx flatbuffers::flatbuffers Boost::mp11 safeint_interface) target_include_directories(onnxruntime_providers_migraphx PRIVATE ${ONNXRUNTIME_ROOT} ${CMAKE_CURRENT_BINARY_DIR}) - install(DIRECTORY ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/providers/migraphx DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/core/providers) set_target_properties(onnxruntime_providers_migraphx PROPERTIES LINKER_LANGUAGE CXX) set_target_properties(onnxruntime_providers_migraphx PROPERTIES FOLDER "ONNXRuntime") target_compile_definitions(onnxruntime_providers_migraphx PRIVATE ONNXIFI_BUILD_LIBRARY=1) @@ -1350,8 +1453,8 @@ if (onnxruntime_USE_ACL) PRIVATE ${ONNXRUNTIME_ROOT} ${eigen_INCLUDE_DIRS} ${onnxruntime_ACL_HOME} ${onnxruntime_ACL_HOME}/include ) - install(DIRECTORY ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/providers/acl - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/core/providers + install(FILES ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/providers/acl/acl_provider_factory.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/ ) set_target_properties(onnxruntime_providers_acl PROPERTIES LINKER_LANGUAGE CXX) @@ -1383,9 +1486,9 @@ if (onnxruntime_USE_ARMNN) ${ONNXRUNTIME_ROOT} ${eigen_INCLUDE_DIRS} ${onnxruntime_ARMNN_HOME} ${onnxruntime_ARMNN_HOME}/include ${onnxruntime_ACL_HOME} ${onnxruntime_ACL_HOME}/include ) - install(DIRECTORY ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/providers/armnn - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/core/providers - ) + install(FILES ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/providers/armnn/armnn_provider_factory.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/) + set_target_properties(onnxruntime_providers_armnn PROPERTIES LINKER_LANGUAGE CXX) if (NOT onnxruntime_BUILD_SHARED_LIB) @@ -1401,7 +1504,7 @@ if (onnxruntime_USE_ROCM) add_definitions(-DUSE_ROCM=1) include(onnxruntime_rocm_hipify.cmake) - list(APPEND CMAKE_PREFIX_PATH ${onnxruntime_ROCM_HOME}/rccl ${onnxruntime_ROCM_HOME}/roctracer) + list(APPEND CMAKE_PREFIX_PATH ${onnxruntime_ROCM_HOME}) find_package(HIP) find_package(hiprand REQUIRED) @@ -1410,12 +1513,21 @@ if (onnxruntime_USE_ROCM) # MIOpen version if(NOT DEFINED ENV{MIOPEN_PATH}) - set(MIOPEN_PATH ${onnxruntime_ROCM_HOME}/miopen) + set(MIOPEN_PATH ${onnxruntime_ROCM_HOME}) else() set(MIOPEN_PATH $ENV{MIOPEN_PATH}) endif() + find_path(MIOPEN_VERSION_H_PATH + NAMES version.h + HINTS + ${MIOPEN_PATH}/include/miopen + ${MIOPEN_PATH}/miopen/include) + if (MIOPEN_VERSION_H_PATH-NOTFOUND) + MESSAGE(FATAL_ERROR "miopen version.h not found") + endif() + MESSAGE(STATUS "Found miopen version.h at ${MIOPEN_VERSION_H_PATH}") - file(READ ${MIOPEN_PATH}/include/miopen/version.h MIOPEN_HEADER_CONTENTS) + file(READ ${MIOPEN_VERSION_H_PATH}/version.h MIOPEN_HEADER_CONTENTS) string(REGEX MATCH "define MIOPEN_VERSION_MAJOR * +([0-9]+)" MIOPEN_VERSION_MAJOR "${MIOPEN_HEADER_CONTENTS}") string(REGEX REPLACE "define MIOPEN_VERSION_MAJOR * +([0-9]+)" "\\1" @@ -1535,7 +1647,6 @@ if (onnxruntime_USE_ROCM) PUBLIC ${onnxruntime_ROCM_HOME}/include ${onnxruntime_ROCM_HOME}/include/roctracer) - install(DIRECTORY ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/providers/rocm DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/core/providers) set_target_properties(onnxruntime_providers_rocm PROPERTIES LINKER_LANGUAGE CXX) set_target_properties(onnxruntime_providers_rocm PROPERTIES FOLDER "ONNXRuntime") @@ -1565,6 +1676,16 @@ if (onnxruntime_USE_ROCM) target_compile_definitions(onnxruntime_providers_rocm PRIVATE USE_HIPBLASLT) endif() + if (onnxruntime_USE_TRITON_KERNEL) + # compile triton kernel, generate .a and .h files + include(onnxruntime_compile_triton_kernel.cmake) + compile_triton_kernel(triton_kernel_obj_file triton_kernel_header_dir) + add_dependencies(onnxruntime_providers_rocm onnxruntime_triton_kernel) + target_compile_definitions(onnxruntime_providers_rocm PRIVATE USE_TRITON_KERNEL) + target_include_directories(onnxruntime_providers_rocm PRIVATE ${triton_kernel_header_dir}) + target_link_libraries(onnxruntime_providers_rocm PUBLIC -Wl,--whole-archive ${triton_kernel_obj_file} -Wl,--no-whole-archive) + endif() + if (onnxruntime_USE_COMPOSABLE_KERNEL) include(composable_kernel) target_link_libraries(onnxruntime_providers_rocm PRIVATE @@ -1576,6 +1697,8 @@ if (onnxruntime_USE_ROCM) device_gemm_instance device_gemm_add_fastgelu_instance device_gemm_fastgelu_instance + device_gemm_splitk_instance + device_gemm_streamk_instance device_batched_gemm_instance device_softmax_instance ) @@ -1652,7 +1775,8 @@ if (onnxruntime_USE_TVM) endif() target_compile_definitions(onnxruntime_providers_tvm PUBLIC DMLC_USE_LOGGING_LIBRARY=) - install(DIRECTORY ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/providers/tvm DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/core/providers) + install(FILES ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/providers/tvm/tvm_provider_factory.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/) if (NOT onnxruntime_BUILD_SHARED_LIB) install(TARGETS onnxruntime_providers_tvm @@ -1678,16 +1802,12 @@ if (onnxruntime_USE_XNNPACK) source_group(TREE ${REPO_ROOT} FILES ${onnxruntime_providers_xnnpack_cc_srcs}) onnxruntime_add_static_library(onnxruntime_providers_xnnpack ${onnxruntime_providers_xnnpack_cc_srcs}) onnxruntime_add_include_to_target(onnxruntime_providers_xnnpack - onnxruntime_common onnxruntime_framework onnx onnx_proto ${PROTOBUF_LIB} XNNPACK pthreadpool Boost::mp11 safeint_interface + onnxruntime_common onnxruntime_framework onnx onnx_proto ${PROTOBUF_LIB} XNNPACK pthreadpool flatbuffers::flatbuffers Boost::mp11 safeint_interface ) add_dependencies(onnxruntime_providers_xnnpack onnx ${onnxruntime_EXTERNAL_DEPENDENCIES}) set_target_properties(onnxruntime_providers_xnnpack PROPERTIES FOLDER "ONNXRuntime") - install(DIRECTORY ${ONNXRUNTIME_INCLUDE_DIR}/core/providers/xnnpack - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/core/providers - ) - set_target_properties(onnxruntime_providers_xnnpack PROPERTIES LINKER_LANGUAGE CXX) if (NOT onnxruntime_BUILD_SHARED_LIB) @@ -1697,6 +1817,12 @@ if (onnxruntime_USE_XNNPACK) RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} FRAMEWORK DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() + + # TODO fix shorten-64-to-32 warnings + # there are some in builds where sizeof(size_t) != sizeof(int64_t), e.g., in 'ONNX Runtime Web CI Pipeline' + if (HAS_SHORTEN_64_TO_32 AND NOT CMAKE_SIZEOF_VOID_P EQUAL 8) + target_compile_options(onnxruntime_providers_xnnpack PRIVATE -Wno-error=shorten-64-to-32) + endif() endif() if (onnxruntime_USE_CANN) diff --git a/cmake/onnxruntime_python.cmake b/cmake/onnxruntime_python.cmake index c39960e401652..bf9adbaefabcc 100644 --- a/cmake/onnxruntime_python.cmake +++ b/cmake/onnxruntime_python.cmake @@ -20,10 +20,6 @@ file(GLOB onnxruntime_pybind_srcs CONFIGURE_DEPENDS ${onnxruntime_pybind_srcs_pattern} ) -if(NOT onnxruntime_PYBIND_EXPORT_OPSCHEMA) - list(REMOVE_ITEM onnxruntime_pybind_srcs ${ONNXRUNTIME_ROOT}/python/onnxruntime_pybind_schema.cc) -endif() - if(onnxruntime_ENABLE_TRAINING) list(REMOVE_ITEM onnxruntime_pybind_srcs ${ONNXRUNTIME_ROOT}/python/onnxruntime_pybind_module.cc) endif() @@ -116,7 +112,7 @@ if (onnxruntime_USE_NCCL) endif() if(APPLE) - set(ONNXRUNTIME_SO_LINK_FLAG "-Xlinker -exported_symbols_list ${ONNXRUNTIME_ROOT}/python/exported_symbols.lst") + set(ONNXRUNTIME_SO_LINK_FLAG "-Xlinker -exported_symbols_list -Xlinker ${ONNXRUNTIME_ROOT}/python/exported_symbols.lst") elseif(UNIX) if (onnxruntime_ENABLE_EXTERNAL_CUSTOM_OP_SCHEMAS) set(ONNXRUNTIME_SO_LINK_FLAG "-Xlinker --version-script=${ONNXRUNTIME_ROOT}/python/version_script_expose_onnx_protobuf.lds -Xlinker --gc-sections") @@ -227,7 +223,7 @@ if (MSVC) # Explicitly use the release version of the python library to make the project file consistent with this. target_link_libraries(onnxruntime_pybind11_state PRIVATE ${Python_LIBRARY_RELEASE}) elseif (APPLE) - set_target_properties(onnxruntime_pybind11_state PROPERTIES LINK_FLAGS "${ONNXRUNTIME_SO_LINK_FLAG} -undefined dynamic_lookup") + set_target_properties(onnxruntime_pybind11_state PROPERTIES LINK_FLAGS "${ONNXRUNTIME_SO_LINK_FLAG} -Xlinker -undefined -Xlinker dynamic_lookup") set_target_properties(onnxruntime_pybind11_state PROPERTIES INSTALL_RPATH "@loader_path" BUILD_WITH_INSTALL_RPATH TRUE @@ -286,7 +282,13 @@ if (WIN32) endif() get_filename_component(CUDNN_DLL_NAME ${CUDNN_DLL_PATH} NAME_WE) string(REPLACE "cudnn64_" "" CUDNN_VERSION "${CUDNN_DLL_NAME}") - + if(NOT onnxruntime_CUDA_VERSION) + message("Reading json file ${onnxruntime_CUDA_HOME}/version.json") + set(CUDA_SDK_JSON_FILE_PATH "${onnxruntime_CUDA_HOME}/version.json") + file(READ ${CUDA_SDK_JSON_FILE_PATH} CUDA_SDK_JSON_CONTENT) + string(JSON onnxruntime_CUDA_VERSION GET ${CUDA_SDK_JSON_CONTENT} "cuda" "version") + message("onnxruntime_CUDA_VERSION=${onnxruntime_CUDA_VERSION}") + endif() file(APPEND "${VERSION_INFO_FILE}" "cuda_version = \"${onnxruntime_CUDA_VERSION}\"\n" "cudnn_version = \"${CUDNN_VERSION}\"\n" @@ -385,8 +387,17 @@ if (onnxruntime_ENABLE_TRAINING) file(GLOB onnxruntime_python_ortmodule_torch_cpp_ext_fused_ops_srcs CONFIGURE_DEPENDS "${ORTTRAINING_SOURCE_DIR}/python/training/ortmodule/torch_cpp_extensions/cuda/fused_ops/*" ) + file(GLOB onnxruntime_python_ort_triton_srcs CONFIGURE_DEPENDS + "${ORTTRAINING_SOURCE_DIR}/python/training/ort_triton/*.py" + ) + file(GLOB onnxruntime_python_ort_triton_kernel_srcs CONFIGURE_DEPENDS + "${ORTTRAINING_SOURCE_DIR}/python/training/ort_triton/kernel/*.py" + ) + file(GLOB onnxruntime_python_utils_srcs CONFIGURE_DEPENDS + "${ORTTRAINING_SOURCE_DIR}/python/training/utils/*.py" + ) file(GLOB onnxruntime_python_utils_data_srcs CONFIGURE_DEPENDS - "${ORTTRAINING_SOURCE_DIR}/python/training/utils/data/*" + "${ORTTRAINING_SOURCE_DIR}/python/training/utils/data/*" ) file(GLOB onnxruntime_python_utils_hooks_srcs CONFIGURE_DEPENDS "${ORTTRAINING_SOURCE_DIR}/python/training/utils/hooks/*" @@ -455,6 +466,9 @@ file(GLOB onnxruntime_python_transformers_models_bert_src CONFIGURE_DEPENDS file(GLOB onnxruntime_python_transformers_models_gpt2_src CONFIGURE_DEPENDS "${ONNXRUNTIME_ROOT}/python/tools/transformers/models/gpt2/*.py" ) +file(GLOB onnxruntime_python_transformers_models_llama_src CONFIGURE_DEPENDS + "${ONNXRUNTIME_ROOT}/python/tools/transformers/models/llama/*.py" +) file(GLOB onnxruntime_python_transformers_models_longformer_src CONFIGURE_DEPENDS "${ONNXRUNTIME_ROOT}/python/tools/transformers/models/longformer/*.py" ) @@ -464,6 +478,9 @@ file(GLOB onnxruntime_python_transformers_models_stable_diffusion_src CONFIGURE_ file(GLOB onnxruntime_python_transformers_models_t5_src CONFIGURE_DEPENDS "${ONNXRUNTIME_ROOT}/python/tools/transformers/models/t5/*.py" ) +file(GLOB onnxruntime_python_transformers_models_whisper_src CONFIGURE_DEPENDS + "${ONNXRUNTIME_ROOT}/python/tools/transformers/models/whisper/*.py" +) file(GLOB onnxruntime_python_datasets_srcs CONFIGURE_DEPENDS "${ONNXRUNTIME_ROOT}/python/datasets/*.py" ) @@ -499,6 +516,12 @@ file(GLOB onnxruntime_qdq_helper_srcs CONFIGURE_DEPENDS ${REPO_ROOT}/tools/python/util/qdq_helpers/*.py ) +if (onnxruntime_USE_OPENVINO) + file(GLOB onnxruntime_python_openvino_python_srcs CONFIGURE_DEPENDS + ${REPO_ROOT}/tools/python/util/add_openvino_win_libs.py + ) +endif() + set(build_output_target onnxruntime_common) if(NOT onnxruntime_ENABLE_STATIC_ANALYSIS) add_custom_command( @@ -517,9 +540,11 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E make_directory $/onnxruntime/transformers/models/bart COMMAND ${CMAKE_COMMAND} -E make_directory $/onnxruntime/transformers/models/bert COMMAND ${CMAKE_COMMAND} -E make_directory $/onnxruntime/transformers/models/gpt2 + COMMAND ${CMAKE_COMMAND} -E make_directory $/onnxruntime/transformers/models/llama COMMAND ${CMAKE_COMMAND} -E make_directory $/onnxruntime/transformers/models/longformer COMMAND ${CMAKE_COMMAND} -E make_directory $/onnxruntime/transformers/models/stable_diffusion COMMAND ${CMAKE_COMMAND} -E make_directory $/onnxruntime/transformers/models/t5 + COMMAND ${CMAKE_COMMAND} -E make_directory $/onnxruntime/transformers/models/whisper COMMAND ${CMAKE_COMMAND} -E make_directory $/onnxruntime/quantization COMMAND ${CMAKE_COMMAND} -E make_directory $/onnxruntime/quantization/operators COMMAND ${CMAKE_COMMAND} -E make_directory $/onnxruntime/quantization/CalTableFlatBuffers @@ -607,6 +632,9 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E copy ${onnxruntime_python_transformers_models_gpt2_src} $/onnxruntime/transformers/models/gpt2/ + COMMAND ${CMAKE_COMMAND} -E copy + ${onnxruntime_python_transformers_models_llama_src} + $/onnxruntime/transformers/models/llama/ COMMAND ${CMAKE_COMMAND} -E copy ${onnxruntime_python_transformers_models_longformer_src} $/onnxruntime/transformers/models/longformer/ @@ -616,11 +644,23 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E copy ${onnxruntime_python_transformers_models_t5_src} $/onnxruntime/transformers/models/t5/ + COMMAND ${CMAKE_COMMAND} -E copy + ${onnxruntime_python_transformers_models_whisper_src} + $/onnxruntime/transformers/models/whisper/ COMMAND ${CMAKE_COMMAND} -E copy ${REPO_ROOT}/VERSION_NUMBER $ ) +if (onnxruntime_USE_OPENVINO) + add_custom_command( + TARGET onnxruntime_pybind11_state POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${onnxruntime_python_openvino_python_srcs} + $/onnxruntime/tools/ + ) +endif() + if (onnxruntime_ENABLE_EXTERNAL_CUSTOM_OP_SCHEMAS) add_custom_command( TARGET onnxruntime_pybind11_state POST_BUILD @@ -639,9 +679,9 @@ endif() if (NOT onnxruntime_MINIMAL_BUILD AND NOT onnxruntime_EXTENDED_MINIMAL_BUILD AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin|iOS" - AND NOT (CMAKE_SYSTEM_NAME STREQUAL "Android") + AND NOT CMAKE_SYSTEM_NAME STREQUAL "Android" AND NOT onnxruntime_USE_ROCM - AND NOT onnxruntime_BUILD_WEBASSEMBLY) + AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") add_custom_command( TARGET onnxruntime_pybind11_state POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy @@ -701,6 +741,9 @@ if (onnxruntime_ENABLE_TRAINING) COMMAND ${CMAKE_COMMAND} -E make_directory $/onnxruntime/training/ortmodule/torch_cpp_extensions/cpu/torch_interop_utils COMMAND ${CMAKE_COMMAND} -E make_directory $/onnxruntime/training/ortmodule/torch_cpp_extensions/cuda/torch_gpu_allocator COMMAND ${CMAKE_COMMAND} -E make_directory $/onnxruntime/training/ortmodule/torch_cpp_extensions/cuda/fused_ops + COMMAND ${CMAKE_COMMAND} -E make_directory $/onnxruntime/training/ort_triton + COMMAND ${CMAKE_COMMAND} -E make_directory $/onnxruntime/training/ort_triton/kernel + COMMAND ${CMAKE_COMMAND} -E make_directory $/onnxruntime/training/utils COMMAND ${CMAKE_COMMAND} -E make_directory $/onnxruntime/training/utils/data/ COMMAND ${CMAKE_COMMAND} -E make_directory $/onnxruntime/training/utils/hooks/ COMMAND ${CMAKE_COMMAND} -E copy @@ -751,6 +794,15 @@ if (onnxruntime_ENABLE_TRAINING) COMMAND ${CMAKE_COMMAND} -E copy ${onnxruntime_python_ortmodule_torch_cpp_ext_fused_ops_srcs} $/onnxruntime/training/ortmodule/torch_cpp_extensions/cuda/fused_ops/ + COMMAND ${CMAKE_COMMAND} -E copy + ${onnxruntime_python_ort_triton_srcs} + $/onnxruntime/training/ort_triton/ + COMMAND ${CMAKE_COMMAND} -E copy + ${onnxruntime_python_ort_triton_kernel_srcs} + $/onnxruntime/training/ort_triton/kernel/ + COMMAND ${CMAKE_COMMAND} -E copy + ${onnxruntime_python_utils_srcs} + $/onnxruntime/training/utils/ COMMAND ${CMAKE_COMMAND} -E copy ${onnxruntime_python_utils_data_srcs} $/onnxruntime/training/utils/data/ @@ -777,7 +829,6 @@ if (onnxruntime_ENABLE_TRAINING) COMMAND ${CMAKE_COMMAND} -E copy ${onnxruntime_python_api_srcs} $/onnxruntime/training/api/ - ) endif() endif() @@ -897,10 +948,15 @@ if (onnxruntime_USE_TVM) endif() if (onnxruntime_USE_DML) + if (NOT onnxruntime_USE_CUSTOM_DIRECTML) + set(dml_shared_lib_path ${DML_PACKAGE_DIR}/bin/${onnxruntime_target_platform}-win/${DML_SHARED_LIB}) + else() + set(dml_shared_lib_path ${DML_PACKAGE_DIR}/bin/${DML_SHARED_LIB}) + endif() add_custom_command( TARGET onnxruntime_pybind11_state POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy - ${DML_PACKAGE_DIR}/bin/${onnxruntime_target_platform}-win/${DML_SHARED_LIB} + ${dml_shared_lib_path} $/onnxruntime/capi/ ) endif() diff --git a/cmake/onnxruntime_rocm_hipify.cmake b/cmake/onnxruntime_rocm_hipify.cmake index caaa89c84f5cd..cf71b6bcf7c7d 100644 --- a/cmake/onnxruntime_rocm_hipify.cmake +++ b/cmake/onnxruntime_rocm_hipify.cmake @@ -10,6 +10,9 @@ set(contrib_ops_excluded_files "bert/attention_impl.cu" "bert/attention_softmax.h" "bert/attention_softmax.cu" + "bert/attention_prepare_qkv.cu" + "bert/decoder_attention_impl.h" + "bert/decoder_attention_impl.cu" "bert/decoder_masked_multihead_attention.h" "bert/decoder_masked_multihead_attention.cc" "bert/decoder_masked_self_attention.h" @@ -37,6 +40,10 @@ set(contrib_ops_excluded_files "bert/packed_attention.cc" "bert/packed_attention_impl.h" "bert/packed_attention_impl.cu" + "bert/packed_multihead_attention.h" + "bert/packed_multihead_attention.cc" + "bert/packed_multihead_attention_impl.h" + "bert/packed_multihead_attention_impl.cu" "diffusion/group_norm.cc" "diffusion/group_norm_impl.cu" "diffusion/group_norm_impl.h" @@ -88,8 +95,6 @@ set(contrib_ops_excluded_files "tensor/image_scaler.h" "tensor/image_scaler_impl.cu" "tensor/image_scaler_impl.h" - "transformers/beam_search.cc" - "transformers/beam_search.h" "transformers/greedy_search.cc" "transformers/greedy_search.h" "conv_transpose_with_dynamic_pads.cc" @@ -109,8 +114,6 @@ endif() set(provider_excluded_files "atomic/common.cuh" - "controlflow/if.cc" - "controlflow/if.h" "controlflow/loop.cc" "controlflow/loop.h" "controlflow/scan.cc" @@ -199,6 +202,10 @@ set(training_ops_excluded_files "reduction/reduction_ops.cc" # no double type support "cuda_training_kernels.cc" "cuda_training_kernels.h" + "nn/conv_shared.cc" + "nn/conv_shared.h" + "nn/conv_transpose_grad.cc" + "nn/conv_transpose_grad.h" ) function(auto_set_source_files_hip_language) diff --git a/cmake/onnxruntime_session.cmake b/cmake/onnxruntime_session.cmake index 5120517acf9e7..79bee3bdb65d6 100644 --- a/cmake/onnxruntime_session.cmake +++ b/cmake/onnxruntime_session.cmake @@ -30,7 +30,6 @@ endif() source_group(TREE ${REPO_ROOT} FILES ${onnxruntime_session_srcs}) onnxruntime_add_static_library(onnxruntime_session ${onnxruntime_session_srcs}) -install(DIRECTORY ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/session DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/core) onnxruntime_add_include_to_target(onnxruntime_session onnxruntime_common onnxruntime_framework onnx onnx_proto ${PROTOBUF_LIB} flatbuffers::flatbuffers Boost::mp11 safeint_interface nlohmann_json::nlohmann_json) if(onnxruntime_ENABLE_INSTRUMENT) target_compile_definitions(onnxruntime_session PUBLIC ONNXRUNTIME_ENABLE_INSTRUMENT) @@ -63,6 +62,7 @@ if (onnxruntime_ENABLE_TRAINING_TORCH_INTEROP) endif() if (NOT onnxruntime_BUILD_SHARED_LIB) + install(DIRECTORY ${PROJECT_SOURCE_DIR}/../include/onnxruntime/core/session DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/onnxruntime/core) install(TARGETS onnxruntime_session ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} diff --git a/cmake/onnxruntime_training.cmake b/cmake/onnxruntime_training.cmake index 01f143867e44f..f9ba2b341f741 100644 --- a/cmake/onnxruntime_training.cmake +++ b/cmake/onnxruntime_training.cmake @@ -22,6 +22,8 @@ file(GLOB_RECURSE onnxruntime_training_srcs file(GLOB_RECURSE onnxruntime_training_framework_excluded_srcs CONFIGURE_DEPENDS "${ORTTRAINING_SOURCE_DIR}/core/framework/torch/*.h" "${ORTTRAINING_SOURCE_DIR}/core/framework/torch/*.cc" + "${ORTTRAINING_SOURCE_DIR}/core/framework/triton/*.h" + "${ORTTRAINING_SOURCE_DIR}/core/framework/triton/*.cc" ) list(REMOVE_ITEM onnxruntime_training_srcs ${onnxruntime_training_framework_excluded_srcs}) diff --git a/cmake/onnxruntime_unittests.cmake b/cmake/onnxruntime_unittests.cmake index c0c50e0e11b08..ec83eb2095071 100644 --- a/cmake/onnxruntime_unittests.cmake +++ b/cmake/onnxruntime_unittests.cmake @@ -23,7 +23,6 @@ function(AddTest) else() onnxruntime_add_executable(${_UT_TARGET} ${_UT_SOURCES}) endif() - if (_UT_DEPENDS) list(REMOVE_DUPLICATES _UT_DEPENDS) endif(_UT_DEPENDS) @@ -40,6 +39,9 @@ function(AddTest) endif() if (MSVC) target_compile_options(${_UT_TARGET} PRIVATE "/wd6330") + #Abseil has a lot of C4127/C4324 warnings. + target_compile_options(${_UT_TARGET} PRIVATE "/wd4127") + target_compile_options(${_UT_TARGET} PRIVATE "/wd4324") endif() set_target_properties(${_UT_TARGET} PROPERTIES FOLDER "ONNXRuntimeTest") @@ -61,7 +63,7 @@ function(AddTest) target_link_libraries(${_UT_TARGET} PRIVATE ${_UT_LIBS} GTest::gtest GTest::gmock ${onnxruntime_EXTERNAL_LIBRARIES}) endif() - onnxruntime_add_include_to_target(${_UT_TARGET} date_interface flatbuffers::flatbuffers) + onnxruntime_add_include_to_target(${_UT_TARGET} date::date flatbuffers::flatbuffers) target_include_directories(${_UT_TARGET} PRIVATE ${TEST_INC_DIR}) if (onnxruntime_USE_CUDA) target_include_directories(${_UT_TARGET} PRIVATE ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES} ${onnxruntime_CUDNN_HOME}/include) @@ -113,7 +115,7 @@ function(AddTest) set(TEST_ARGS ${_UT_TEST_ARGS}) if (onnxruntime_GENERATE_TEST_REPORTS) # generate a report file next to the test program - if (onnxruntime_BUILD_WEBASSEMBLY) + if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") # WebAssembly use a memory file system, so we do not use full path list(APPEND TEST_ARGS "--gtest_output=xml:$.$.results.xml") @@ -147,7 +149,7 @@ function(AddTest) else() target_link_libraries(${_UT_TARGET}_xc PRIVATE ${_UT_LIBS} GTest::gtest GTest::gmock ${onnxruntime_EXTERNAL_LIBRARIES}) endif() - onnxruntime_add_include_to_target(${_UT_TARGET}_xc date_interface flatbuffers::flatbuffers) + onnxruntime_add_include_to_target(${_UT_TARGET}_xc date::date flatbuffers::flatbuffers) target_include_directories(${_UT_TARGET}_xc PRIVATE ${TEST_INC_DIR}) get_target_property(${_UT_TARGET}_DEFS ${_UT_TARGET} COMPILE_DEFINITIONS) target_compile_definitions(${_UT_TARGET}_xc PRIVATE ${_UT_TARGET}_DEFS) @@ -162,7 +164,7 @@ function(AddTest) xctest_add_test(xctest.${_UT_TARGET} ${_UT_TARGET}_xc) else() - if (onnxruntime_BUILD_WEBASSEMBLY) + if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") # We might have already executed the following "find_program" code when we build ORT nodejs binding. # Then the program is found the result is stored in the variable and the search will not be repeated. find_program(NPM_CLI @@ -202,11 +204,15 @@ function(AddTest) WORKING_DIRECTORY $ ) endif() + # Set test timeout to 3 hours. + set_tests_properties(${_UT_TARGET} PROPERTIES TIMEOUT 7200) 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) endif() endif() endfunction(AddTest) @@ -280,22 +286,33 @@ if((NOT onnxruntime_MINIMAL_BUILD OR onnxruntime_EXTENDED_MINIMAL_BUILD) endif() file(GLOB onnxruntime_test_training_src + "${ORTTRAINING_SOURCE_DIR}/test/model/*.h" "${ORTTRAINING_SOURCE_DIR}/test/model/*.cc" + "${ORTTRAINING_SOURCE_DIR}/test/gradient/*.h" "${ORTTRAINING_SOURCE_DIR}/test/gradient/*.cc" + "${ORTTRAINING_SOURCE_DIR}/test/graph/*.h" "${ORTTRAINING_SOURCE_DIR}/test/graph/*.cc" + "${ORTTRAINING_SOURCE_DIR}/test/session/*.h" "${ORTTRAINING_SOURCE_DIR}/test/session/*.cc" + "${ORTTRAINING_SOURCE_DIR}/test/optimizer/*.h" "${ORTTRAINING_SOURCE_DIR}/test/optimizer/*.cc" "${ORTTRAINING_SOURCE_DIR}/test/framework/*.cc" + "${ORTTRAINING_SOURCE_DIR}/test/distributed/*.h" "${ORTTRAINING_SOURCE_DIR}/test/distributed/*.cc" ) -if (onnxruntime_ENABLE_TRAINING_APIS) - file(GLOB onnxruntime_test_training_api_src - "${ORTTRAINING_SOURCE_DIR}/test/training_api/common/*.cc" - "${ORTTRAINING_SOURCE_DIR}/test/training_api/common/*.h" - "${ORTTRAINING_SOURCE_DIR}/test/training_api/core/*.cc" - "${ORTTRAINING_SOURCE_DIR}/test/training_api/core/*.h" - ) +# TODO (baijumeswani): Remove the minimal build check here. +# The training api tests should be runnable even on a minimal build. +# This requires converting all the *.onnx files to ort format. +if (NOT onnxruntime_MINIMAL_BUILD) + if (onnxruntime_ENABLE_TRAINING_APIS) + file(GLOB onnxruntime_test_training_api_src + "${ORTTRAINING_SOURCE_DIR}/test/training_api/common/*.cc" + "${ORTTRAINING_SOURCE_DIR}/test/training_api/common/*.h" + "${ORTTRAINING_SOURCE_DIR}/test/training_api/core/*.cc" + "${ORTTRAINING_SOURCE_DIR}/test/training_api/core/*.h" + ) + endif() endif() if(WIN32) @@ -351,7 +368,7 @@ endif() list(APPEND onnxruntime_test_providers_src ${onnxruntime_test_providers_cpu_src}) if (onnxruntime_USE_CUDA AND NOT onnxruntime_MINIMAL_BUILD AND NOT onnxruntime_REDUCED_OPS_BUILD) - file(GLOB_RECURSE onnxruntime_test_providers_cuda_src CONFIGURE_DEPENDS + file(GLOB onnxruntime_test_providers_cuda_src CONFIGURE_DEPENDS "${TEST_SRC_DIR}/providers/cuda/*" ) list(APPEND onnxruntime_test_providers_src ${onnxruntime_test_providers_cuda_src}) @@ -364,26 +381,29 @@ if (onnxruntime_USE_CANN) list(APPEND onnxruntime_test_providers_src ${onnxruntime_test_providers_cann_src}) endif() -if (onnxruntime_ENABLE_TRAINING_APIS) - file(GLOB_RECURSE orttraining_test_trainingops_cpu_src CONFIGURE_DEPENDS - "${ORTTRAINING_SOURCE_DIR}/test/training_ops/compare_provider_test_utils.cc" - "${ORTTRAINING_SOURCE_DIR}/test/training_ops/function_op_test_utils.cc" - "${ORTTRAINING_SOURCE_DIR}/test/training_ops/cpu/*" - ) - - if (NOT onnxruntime_ENABLE_TRAINING) - list(REMOVE_ITEM orttraining_test_trainingops_cpu_src - "${ORTTRAINING_SOURCE_DIR}/test/training_ops/cpu/tensorboard/summary_op_test.cc" +# Disable training ops test for minimal build as a lot of these depend on loading an onnx model. +if (NOT onnxruntime_MINIMAL_BUILD) + if (onnxruntime_ENABLE_TRAINING_OPS) + file(GLOB_RECURSE orttraining_test_trainingops_cpu_src CONFIGURE_DEPENDS + "${ORTTRAINING_SOURCE_DIR}/test/training_ops/compare_provider_test_utils.cc" + "${ORTTRAINING_SOURCE_DIR}/test/training_ops/function_op_test_utils.cc" + "${ORTTRAINING_SOURCE_DIR}/test/training_ops/cpu/*" ) - endif() - list(APPEND onnxruntime_test_providers_src ${orttraining_test_trainingops_cpu_src}) + if (NOT onnxruntime_ENABLE_TRAINING) + list(REMOVE_ITEM orttraining_test_trainingops_cpu_src + "${ORTTRAINING_SOURCE_DIR}/test/training_ops/cpu/tensorboard/summary_op_test.cc" + ) + endif() - if (onnxruntime_USE_CUDA OR onnxruntime_USE_ROCM) - file(GLOB_RECURSE orttraining_test_trainingops_cuda_src CONFIGURE_DEPENDS - "${ORTTRAINING_SOURCE_DIR}/test/training_ops/cuda/*" - ) - list(APPEND onnxruntime_test_providers_src ${orttraining_test_trainingops_cuda_src}) + list(APPEND onnxruntime_test_providers_src ${orttraining_test_trainingops_cpu_src}) + + if (onnxruntime_USE_CUDA OR onnxruntime_USE_ROCM) + file(GLOB_RECURSE orttraining_test_trainingops_cuda_src CONFIGURE_DEPENDS + "${ORTTRAINING_SOURCE_DIR}/test/training_ops/cuda/*" + ) + list(APPEND onnxruntime_test_providers_src ${orttraining_test_trainingops_cuda_src}) + endif() endif() endif() @@ -417,7 +437,6 @@ endif() set (ONNXRUNTIME_SHARED_LIB_TEST_SRC_DIR "${TEST_SRC_DIR}/shared_lib") set (ONNXRUNTIME_GLOBAL_THREAD_POOLS_TEST_SRC_DIR "${TEST_SRC_DIR}/global_thread_pools") -set (ONNXRUNTIME_API_TESTS_WITHOUT_ENV_SRC_DIR "${TEST_SRC_DIR}/api_tests_without_env") set (ONNXRUNTIME_CUSTOM_OP_REGISTRATION_TEST_SRC_DIR "${TEST_SRC_DIR}/custom_op_registration") set (ONNXRUNTIME_LOGGING_APIS_TEST_SRC_DIR "${TEST_SRC_DIR}/logging_apis") @@ -447,9 +466,6 @@ set (onnxruntime_global_thread_pools_test_SRC ${ONNXRUNTIME_GLOBAL_THREAD_POOLS_TEST_SRC_DIR}/test_main.cc ${ONNXRUNTIME_GLOBAL_THREAD_POOLS_TEST_SRC_DIR}/test_inference.cc) -set (onnxruntime_api_tests_without_env_SRC - ${ONNXRUNTIME_API_TESTS_WITHOUT_ENV_SRC_DIR}/test_apis_without_env.cc) - # tests from lowest level library up. # the order of libraries should be maintained, with higher libraries being added first in the list @@ -504,7 +520,7 @@ if(onnxruntime_USE_NNAPI_BUILTIN) list(APPEND onnxruntime_test_providers_dependencies onnxruntime_providers_nnapi) endif() -if(onnxruntime_USE_JS) +if(onnxruntime_USE_JSEP) list(APPEND onnxruntime_test_providers_dependencies onnxruntime_providers_js) endif() @@ -556,6 +572,7 @@ set(ONNXRUNTIME_TEST_LIBS # CUDA, ROCM, TENSORRT, MIGRAPHX, DNNL, and OpenVINO are dynamically loaded at runtime ${PROVIDERS_NNAPI} ${PROVIDERS_JS} + ${PROVIDERS_VITISAI} ${PROVIDERS_QNN} ${PROVIDERS_SNPE} ${PROVIDERS_RKNPU} @@ -609,7 +626,7 @@ if(onnxruntime_USE_NNAPI_BUILTIN) list(APPEND onnxruntime_test_providers_libs onnxruntime_providers_nnapi) endif() -if(onnxruntime_USE_JS) +if(onnxruntime_USE_JSEP) list(APPEND onnxruntime_test_framework_src_patterns ${TEST_SRC_DIR}/providers/js/*) list(APPEND onnxruntime_test_framework_libs onnxruntime_providers_js) list(APPEND onnxruntime_test_providers_dependencies onnxruntime_providers_js) @@ -705,6 +722,7 @@ add_dependencies(onnxruntime_test_utils ${onnxruntime_EXTERNAL_DEPENDENCIES}) target_include_directories(onnxruntime_test_utils PUBLIC "${TEST_SRC_DIR}/util/include" PRIVATE ${eigen_INCLUDE_DIRS} ${ONNXRUNTIME_ROOT}) set_target_properties(onnxruntime_test_utils PROPERTIES FOLDER "ONNXRuntimeTest") +source_group(TREE ${TEST_SRC_DIR} FILES ${onnxruntime_test_utils_src}) set(onnx_test_runner_src_dir ${TEST_SRC_DIR}/onnx) file(GLOB onnx_test_runner_common_srcs CONFIGURE_DEPENDS @@ -737,13 +755,22 @@ set_target_properties(onnx_test_runner_common PROPERTIES FOLDER "ONNXRuntimeTest set(all_tests ${onnxruntime_test_common_src} ${onnxruntime_test_ir_src} ${onnxruntime_test_optimizer_src} ${onnxruntime_test_framework_src} ${onnxruntime_test_providers_src} ${onnxruntime_test_quantiztion_src}) -if(NOT TARGET onnxruntime AND NOT onnxruntime_BUILD_WEBASSEMBLY) +if(NOT TARGET onnxruntime AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") list(APPEND all_tests ${onnxruntime_shared_lib_test_SRC}) endif() if (onnxruntime_USE_CUDA) onnxruntime_add_static_library(onnxruntime_test_cuda_ops_lib ${ONNXRUNTIME_SHARED_LIB_TEST_SRC_DIR}/cuda_ops.cu) list(APPEND onnxruntime_test_common_libs onnxruntime_test_cuda_ops_lib) + file(GLOB onnxruntime_test_providers_cuda_ut_src CONFIGURE_DEPENDS + "${TEST_SRC_DIR}/providers/cuda/test_cases/*" + ) + # onnxruntime_providers_cuda_ut is only for unittests. + onnxruntime_add_shared_library_module(onnxruntime_providers_cuda_ut ${onnxruntime_test_providers_cuda_ut_src} $) + config_cuda_provider_shared_module(onnxruntime_providers_cuda_ut) + onnxruntime_add_include_to_target(onnxruntime_providers_cuda_ut GTest::gtest GTest::gmock) + target_link_libraries(onnxruntime_providers_cuda_ut PRIVATE GTest::gtest GTest::gmock) + list(APPEND onnxruntime_test_providers_dependencies onnxruntime_providers_cuda_ut) endif() set(all_dependencies ${onnxruntime_test_providers_dependencies} ) @@ -771,7 +798,7 @@ if(WIN32) list(APPEND onnxruntime_test_providers_libs Advapi32) endif() -if (onnxruntime_BUILD_WEBASSEMBLY) +if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") if (NOT onnxruntime_ENABLE_WEBASSEMBLY_THREADS) list(REMOVE_ITEM all_tests "${TEST_SRC_DIR}/framework/execution_frame_test.cc" @@ -814,6 +841,18 @@ else() target_compile_options(onnxruntime_test_all PRIVATE "-Wno-parentheses") endif() +# TODO fix shorten-64-to-32 warnings +# there are some in builds where sizeof(size_t) != sizeof(int64_t), e.g., in 'ONNX Runtime Web CI Pipeline' +if (HAS_SHORTEN_64_TO_32 AND NOT CMAKE_SIZEOF_VOID_P EQUAL 8) + target_compile_options(onnxruntime_test_all PRIVATE -Wno-error=shorten-64-to-32) +endif() + +if (UNIX AND onnxruntime_USE_TENSORRT) + # The test_main.cc includes NvInfer.h where it has many deprecated declarations + # simply ignore them for TensorRT EP build + set_property(TARGET onnxruntime_test_all APPEND_STRING PROPERTY COMPILE_FLAGS "-Wno-deprecated-declarations") +endif() + if (MSVC AND onnxruntime_ENABLE_STATIC_ANALYSIS) # attention_op_test.cc: Function uses '49152' bytes of stack: exceeds /analyze:stacksize '16384'.. target_compile_options(onnxruntime_test_all PRIVATE "/analyze:stacksize 131072") @@ -845,15 +884,22 @@ endif() if (onnxruntime_ENABLE_TRAINING_TORCH_INTEROP) target_link_libraries(onnxruntime_test_all PRIVATE Python::Python) endif() -if (onnxruntime_BUILD_WEBASSEMBLY) +if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") set_target_properties(onnxruntime_test_all PROPERTIES LINK_DEPENDS ${TEST_SRC_DIR}/wasm/onnxruntime_test_all_adapter.js) - set_target_properties(onnxruntime_test_all PROPERTIES LINK_FLAGS "-s STACK_SIZE=1048576 -s ALLOW_MEMORY_GROWTH=1 --pre-js \"${TEST_SRC_DIR}/wasm/onnxruntime_test_all_adapter.js\" -s \"EXPORTED_RUNTIME_METHODS=['FS']\" --preload-file ${CMAKE_CURRENT_BINARY_DIR}/testdata@/testdata -s EXIT_RUNTIME=1") + set_target_properties(onnxruntime_test_all PROPERTIES LINK_FLAGS "-s STACK_SIZE=5242880 -s ALLOW_MEMORY_GROWTH=1 --pre-js \"${TEST_SRC_DIR}/wasm/onnxruntime_test_all_adapter.js\" -s \"EXPORTED_RUNTIME_METHODS=['FS']\" --preload-file ${CMAKE_CURRENT_BINARY_DIR}/testdata@/testdata -s EXIT_RUNTIME=1 -s DEMANGLE_SUPPORT=1") if (onnxruntime_ENABLE_WEBASSEMBLY_THREADS) - set_property(TARGET onnxruntime_test_all APPEND_STRING PROPERTY LINK_FLAGS " -s USE_PTHREADS=1 -s PROXY_TO_PTHREAD=1") + set_property(TARGET onnxruntime_test_all APPEND_STRING PROPERTY LINK_FLAGS " -s DEFAULT_PTHREAD_STACK_SIZE=131072 -s PROXY_TO_PTHREAD=1") endif() - if (onnxruntime_USE_JS) + if (onnxruntime_USE_JSEP) set_property(TARGET onnxruntime_test_all APPEND_STRING PROPERTY LINK_FLAGS " --pre-js \"${ONNXRUNTIME_ROOT}/wasm/js_internal_api.js\"") endif() + + ### + ### if you want to investigate or debug a test failure in onnxruntime_test_all, replace the following line. + ### those flags slow down the CI test significantly, so we don't use them by default. + ### + # set_property(TARGET onnxruntime_test_all APPEND_STRING PROPERTY LINK_FLAGS " -s ASSERTIONS=2 -s SAFE_HEAP=1 -s STACK_OVERFLOW_CHECK=2") + set_property(TARGET onnxruntime_test_all APPEND_STRING PROPERTY LINK_FLAGS " -s ASSERTIONS=0 -s SAFE_HEAP=0 -s STACK_OVERFLOW_CHECK=1") endif() if (onnxruntime_ENABLE_ATEN) @@ -866,12 +912,6 @@ onnxruntime_add_static_library(onnx_test_data_proto ${TEST_SRC_DIR}/proto/tml.pr add_dependencies(onnx_test_data_proto onnx_proto ${onnxruntime_EXTERNAL_DEPENDENCIES}) #onnx_proto target should mark this definition as public, instead of private target_compile_definitions(onnx_test_data_proto PRIVATE "-DONNX_API=") -if(WIN32) - target_compile_options(onnx_test_data_proto PRIVATE "/wd4100" "/wd4125" "/wd4127" "/wd4267" "/wd4456" "/wd4800" "/wd6011" "/wd6387" "/wd28182") -else() - #Once we upgrade protobuf to 3.17.3+, we can remove this - target_compile_options(onnx_test_data_proto PRIVATE "-Wno-unused-parameter") -endif() onnxruntime_add_include_to_target(onnx_test_data_proto onnx_proto) target_include_directories(onnx_test_data_proto PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) set_target_properties(onnx_test_data_proto PROPERTIES FOLDER "ONNXRuntimeTest") @@ -1002,9 +1042,9 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "iOS") XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "NO" ) endif() -if (onnxruntime_BUILD_WEBASSEMBLY) +if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") if (onnxruntime_ENABLE_WEBASSEMBLY_THREADS) - set_target_properties(onnx_test_runner PROPERTIES LINK_FLAGS "-s NODERAWFS=1 -s ALLOW_MEMORY_GROWTH=1 -s USE_PTHREADS=1 -s PROXY_TO_PTHREAD=1 -s EXIT_RUNTIME=1") + set_target_properties(onnx_test_runner PROPERTIES LINK_FLAGS "-s NODERAWFS=1 -s ALLOW_MEMORY_GROWTH=1 -s PROXY_TO_PTHREAD=1 -s EXIT_RUNTIME=1") else() set_target_properties(onnx_test_runner PROPERTIES LINK_FLAGS "-s NODERAWFS=1 -s ALLOW_MEMORY_GROWTH=1") endif() @@ -1087,7 +1127,7 @@ if (NOT onnxruntime_ENABLE_TRAINING_TORCH_INTEROP) else() target_link_libraries(onnxruntime_mlas_benchmark PRIVATE nsync::nsync_cpp ${CMAKE_DL_LIBS}) endif() - if (CPUINFO_SUPPORTED AND NOT onnxruntime_BUILD_WEBASSEMBLY) + if (CPUINFO_SUPPORTED AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") target_link_libraries(onnxruntime_mlas_benchmark PRIVATE cpuinfo) endif() set_target_properties(onnxruntime_mlas_benchmark PROPERTIES FOLDER "ONNXRuntimeTest") @@ -1097,7 +1137,7 @@ if (NOT onnxruntime_ENABLE_TRAINING_TORCH_INTEROP) target_compile_options(onnx_test_runner_common PRIVATE -D_CRT_SECURE_NO_WARNINGS) endif() - if (NOT onnxruntime_REDUCED_OPS_BUILD AND NOT onnxruntime_BUILD_WEBASSEMBLY) + if (NOT onnxruntime_REDUCED_OPS_BUILD AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") add_test(NAME onnx_test_pytorch_converted COMMAND onnx_test_runner ${onnx_SOURCE_DIR}/onnx/backend/test/data/pytorch-converted) add_test(NAME onnx_test_pytorch_operator @@ -1211,6 +1251,9 @@ if (NOT onnxruntime_ENABLE_TRAINING_TORCH_INTEROP) list(APPEND onnxruntime_shared_lib_test_LIBS onnxruntime_providers_snpe) endif() endif() + if (CPUINFO_SUPPORTED AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") + list(APPEND onnxruntime_shared_lib_test_LIBS cpuinfo) + endif() if (onnxruntime_USE_CUDA) list(APPEND onnxruntime_shared_lib_test_LIBS onnxruntime_test_cuda_ops_lib cudart) endif() @@ -1244,6 +1287,12 @@ if (NOT onnxruntime_ENABLE_TRAINING_TORCH_INTEROP) $/testdata) endif() + if (UNIX AND onnxruntime_USE_TENSORRT) + # The test_main.cc includes NvInfer.h where it has many deprecated declarations + # simply ignore them for TensorRT EP build + set_property(TARGET onnxruntime_shared_lib_test APPEND_STRING PROPERTY COMPILE_FLAGS "-Wno-deprecated-declarations") + endif() + # test inference using global threadpools if (NOT CMAKE_SYSTEM_NAME MATCHES "Android|iOS" AND NOT onnxruntime_MINIMAL_BUILD) AddTest(DYN @@ -1253,16 +1302,6 @@ if (NOT onnxruntime_ENABLE_TRAINING_TORCH_INTEROP) DEPENDS ${all_dependencies} ) endif() - - # A separate test is needed to test the APIs that don't rely on the env being created first. - if (NOT CMAKE_SYSTEM_NAME MATCHES "Android|iOS") - AddTest(DYN - TARGET onnxruntime_api_tests_without_env - SOURCES ${onnxruntime_api_tests_without_env_SRC} - LIBS ${onnxruntime_shared_lib_test_LIBS} - DEPENDS ${all_dependencies} - ) - endif() endif() # the debug node IO functionality uses static variables, so it is best tested @@ -1274,7 +1313,14 @@ if (NOT onnxruntime_ENABLE_TRAINING_TORCH_INTEROP) "${TEST_SRC_DIR}/debug_node_inputs_outputs/debug_node_inputs_outputs_utils_test.cc" "${TEST_SRC_DIR}/framework/TestAllocatorManager.cc" "${TEST_SRC_DIR}/framework/test_utils.cc" - "${TEST_SRC_DIR}/providers/provider_test_utils.cc" + "${TEST_SRC_DIR}/providers/base_tester.h" + "${TEST_SRC_DIR}/providers/base_tester.cc" + "${TEST_SRC_DIR}/providers/checkers.h" + "${TEST_SRC_DIR}/providers/checkers.cc" + "${TEST_SRC_DIR}/providers/op_tester.h" + "${TEST_SRC_DIR}/providers/op_tester.cc" + "${TEST_SRC_DIR}/providers/provider_test_utils.h" + "${TEST_SRC_DIR}/providers/tester_types.h" ${onnxruntime_unittest_main_src} LIBS ${onnxruntime_test_providers_libs} ${onnxruntime_test_common_libs} DEPENDS ${all_dependencies} @@ -1327,7 +1373,7 @@ if (NOT onnxruntime_ENABLE_TRAINING_TORCH_INTEROP) target_include_directories(onnxruntime_mlas_test PRIVATE ${ONNXRUNTIME_ROOT}/core/mlas/inc ${ONNXRUNTIME_ROOT} ${CMAKE_CURRENT_BINARY_DIR}) target_link_libraries(onnxruntime_mlas_test PRIVATE GTest::gtest GTest::gmock ${ONNXRUNTIME_MLAS_LIBS} onnxruntime_common) - if (CPUINFO_SUPPORTED AND NOT onnxruntime_BUILD_WEBASSEMBLY) + if (CPUINFO_SUPPORTED AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") target_link_libraries(onnxruntime_mlas_test PRIVATE cpuinfo) endif() if(NOT WIN32) @@ -1346,16 +1392,21 @@ if (NOT onnxruntime_ENABLE_TRAINING_TORCH_INTEROP) target_link_libraries(onnxruntime_mlas_test PRIVATE Threads::Threads) set_target_properties(onnxruntime_mlas_test PROPERTIES FOLDER "ONNXRuntimeTest") - if (onnxruntime_BUILD_WEBASSEMBLY) + if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") if (onnxruntime_ENABLE_WEBASSEMBLY_THREADS) - set_target_properties(onnxruntime_mlas_test PROPERTIES LINK_FLAGS "-s ALLOW_MEMORY_GROWTH=1 -s USE_PTHREADS=1 -s PROXY_TO_PTHREAD=1 -s EXIT_RUNTIME=1") + set_target_properties(onnxruntime_mlas_test PROPERTIES LINK_FLAGS "-s ALLOW_MEMORY_GROWTH=1 -s PROXY_TO_PTHREAD=1 -s EXIT_RUNTIME=1") else() set_target_properties(onnxruntime_mlas_test PROPERTIES LINK_FLAGS "-s ALLOW_MEMORY_GROWTH=1") endif() endif() # Training API Tests - if (onnxruntime_ENABLE_TRAINING_APIS) + # Disabling training_api_test_trainer. CXXOPT generates a ton of warnings because of which nuget pipeline is failing. + # TODO(askhade): Fix the warnings. + # This has no impact on the release as the release package and the pipeline, both do not use this. + # This is used by devs for testing training apis. + #if (onnxruntime_ENABLE_TRAINING_APIS) + if (0) # Only files in the trainer and common folder will be compiled into test trainer. file(GLOB training_api_test_trainer_src "${ORTTRAINING_SOURCE_DIR}/test/training_api/common/*.cc" @@ -1407,20 +1458,41 @@ if (NOT onnxruntime_ENABLE_TRAINING_TORCH_INTEROP) endif() endif() -if (NOT onnxruntime_BUILD_WEBASSEMBLY) +if (NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") + + set(custom_op_src_patterns + "${TEST_SRC_DIR}/testdata/custom_op_library/*.h" + "${TEST_SRC_DIR}/testdata/custom_op_library/*.cc" + "${TEST_SRC_DIR}/testdata/custom_op_library/cpu/cpu_ops.*" + ) + + set(custom_op_lib_include ${REPO_ROOT}/include) + set(custom_op_lib_option) + set(custom_op_lib_link ${GSL_TARGET}) + if (onnxruntime_USE_CUDA) - onnxruntime_add_shared_library(custom_op_library ${ONNXRUNTIME_SHARED_LIB_TEST_SRC_DIR}/cuda_ops.cu - ${TEST_SRC_DIR}/testdata/custom_op_library/custom_op_library.cc) - target_include_directories(custom_op_library PRIVATE ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES}) + list(APPEND custom_op_src_patterns + "${ONNXRUNTIME_SHARED_LIB_TEST_SRC_DIR}/cuda_ops.cu" + "${TEST_SRC_DIR}/testdata/custom_op_library/cuda/cuda_ops.*") + list(APPEND custom_op_lib_include ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES} ${onnxruntime_CUDNN_HOME}/include) if (HAS_QSPECTRE) - target_compile_options(custom_op_library PRIVATE "$<$:SHELL:-Xcompiler /Qspectre>") + list(APPEND custom_op_lib_option "$<$:SHELL:-Xcompiler /Qspectre>") endif() - else() - onnxruntime_add_shared_library(custom_op_library ${TEST_SRC_DIR}/testdata/custom_op_library/custom_op_library.cc) endif() - target_include_directories(custom_op_library PRIVATE ${REPO_ROOT}/include) - target_link_libraries(custom_op_library PRIVATE ${GSL_TARGET}) + if (onnxruntime_USE_ROCM) + list(APPEND custom_op_src_patterns + "${ONNXRUNTIME_SHARED_LIB_TEST_SRC_DIR}/rocm_ops.hip" + "${TEST_SRC_DIR}/testdata/custom_op_library/rocm/rocm_ops.*") + list(APPEND custom_op_lib_include ${onnxruntime_ROCM_HOME}/include) + list(APPEND custom_op_lib_option "-D__HIP_PLATFORM_AMD__=1 -D__HIP_PLATFORM_HCC__=1") + endif() + + file(GLOB custom_op_src ${custom_op_src_patterns}) + onnxruntime_add_shared_library(custom_op_library ${custom_op_src}) + target_compile_options(custom_op_library PRIVATE ${custom_op_lib_option}) + target_include_directories(custom_op_library PRIVATE ${REPO_ROOT}/include ${custom_op_lib_include}) + target_link_libraries(custom_op_library PRIVATE ${GSL_TARGET} ${custom_op_lib_link}) if(UNIX) if (APPLE) @@ -1480,6 +1552,12 @@ if (NOT onnxruntime_BUILD_WEBASSEMBLY) ${ONNXRUNTIME_CUSTOM_OP_REGISTRATION_TEST_SRC_DIR}/test_registercustomops.cc) set(onnxruntime_customopregistration_test_LIBS custom_op_library onnxruntime_common onnxruntime_test_utils) + if (NOT WIN32) + list(APPEND onnxruntime_customopregistration_test_LIBS nsync::nsync_cpp) + endif() + if (CPUINFO_SUPPORTED AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") + list(APPEND onnxruntime_customopregistration_test_LIBS cpuinfo) + endif() if (onnxruntime_USE_TENSORRT) list(APPEND onnxruntime_customopregistration_test_LIBS ${TENSORRT_LIBRARY_INFER}) endif() @@ -1497,11 +1575,18 @@ if (NOT onnxruntime_BUILD_WEBASSEMBLY) ${TEST_DATA_SRC} $/testdata) endif() + + if (UNIX AND onnxruntime_USE_TENSORRT) + # The test_main.cc includes NvInfer.h where it has many deprecated declarations + # simply ignore them for TensorRT EP build + set_property(TARGET onnxruntime_customopregistration_test APPEND_STRING PROPERTY COMPILE_FLAGS "-Wno-deprecated-declarations") + endif() + endif() endif() # Build custom op library that returns an error OrtStatus when the exported RegisterCustomOps function is called. -if (NOT onnxruntime_BUILD_WEBASSEMBLY AND (NOT onnxruntime_MINIMAL_BUILD OR onnxruntime_MINIMAL_BUILD_CUSTOM_OPS)) +if (NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten" AND (NOT onnxruntime_MINIMAL_BUILD OR onnxruntime_MINIMAL_BUILD_CUSTOM_OPS)) onnxruntime_add_shared_library_module(custom_op_invalid_library ${TEST_SRC_DIR}/testdata/custom_op_invalid_library/custom_op_library.h ${TEST_SRC_DIR}/testdata/custom_op_invalid_library/custom_op_library.cc) @@ -1524,7 +1609,7 @@ if (NOT onnxruntime_BUILD_WEBASSEMBLY AND (NOT onnxruntime_MINIMAL_BUILD OR onnx ${ONNXRUNTIME_CUSTOM_OP_INVALID_LIB_LINK_FLAG}) endif() -if (NOT onnxruntime_BUILD_WEBASSEMBLY AND (NOT onnxruntime_MINIMAL_BUILD OR onnxruntime_MINIMAL_BUILD_CUSTOM_OPS)) +if (NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten" AND (NOT onnxruntime_MINIMAL_BUILD OR onnxruntime_MINIMAL_BUILD_CUSTOM_OPS)) file(GLOB_RECURSE custom_op_get_const_input_test_library_src "${TEST_SRC_DIR}/testdata/custom_op_get_const_input_test_library/custom_op_lib.cc" @@ -1555,7 +1640,7 @@ if (NOT onnxruntime_BUILD_WEBASSEMBLY AND (NOT onnxruntime_MINIMAL_BUILD OR onnx ${ONNXRUNTIME_CUSTOM_OP_GET_CONST_INPUT_TEST_LIB_LINK_FLAG}) endif() -if (onnxruntime_BUILD_SHARED_LIB AND NOT onnxruntime_BUILD_WEBASSEMBLY AND NOT onnxruntime_MINIMAL_BUILD) +if (onnxruntime_BUILD_SHARED_LIB AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten" AND NOT onnxruntime_MINIMAL_BUILD) set (onnxruntime_logging_apis_test_SRC ${ONNXRUNTIME_LOGGING_APIS_TEST_SRC_DIR}/test_logging_apis.cc) @@ -1573,7 +1658,7 @@ if (onnxruntime_BUILD_SHARED_LIB AND NOT onnxruntime_BUILD_WEBASSEMBLY AND NOT o ) endif() -if (NOT onnxruntime_BUILD_WEBASSEMBLY AND onnxruntime_USE_OPENVINO AND (NOT onnxruntime_MINIMAL_BUILD OR +if (NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten" AND onnxruntime_USE_OPENVINO AND (NOT onnxruntime_MINIMAL_BUILD OR onnxruntime_MINIMAL_BUILD_CUSTOM_OPS)) onnxruntime_add_shared_library_module(custom_op_openvino_wrapper_library ${TEST_SRC_DIR}/testdata/custom_op_openvino_wrapper_library/custom_op_lib.cc @@ -1601,8 +1686,8 @@ 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" - AND NOT (CMAKE_SYSTEM_NAME STREQUAL "Android") - AND NOT onnxruntime_BUILD_WEBASSEMBLY + AND NOT CMAKE_SYSTEM_NAME STREQUAL "Android" + AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten" AND NOT onnxruntime_USE_ROCM) file(GLOB_RECURSE test_execution_provider_srcs "${REPO_ROOT}/onnxruntime/test/testdata/custom_execution_provider_library/*.h" diff --git a/cmake/onnxruntime_webassembly.cmake b/cmake/onnxruntime_webassembly.cmake index 80a44ffb3fa63..c6510c97a617e 100644 --- a/cmake/onnxruntime_webassembly.cmake +++ b/cmake/onnxruntime_webassembly.cmake @@ -110,6 +110,7 @@ if (onnxruntime_BUILD_WEBASSEMBLY_STATIC_LIB) onnxruntime_providers ${PROVIDERS_JS} ${PROVIDERS_XNNPACK} + ${PROVIDERS_WEBNN} onnxruntime_session onnxruntime_util re2::re2 @@ -186,6 +187,7 @@ else() onnxruntime_providers ${PROVIDERS_JS} ${PROVIDERS_XNNPACK} + ${PROVIDERS_WEBNN} onnxruntime_session onnxruntime_util re2::re2 @@ -194,13 +196,17 @@ else() target_link_libraries(onnxruntime_webassembly PRIVATE XNNPACK) endif() + if(onnxruntime_USE_WEBNN) + target_link_libraries(onnxruntime_webassembly PRIVATE onnxruntime_providers_webnn) + endif() + if (onnxruntime_ENABLE_TRAINING) target_link_libraries(onnxruntime_webassembly PRIVATE tensorboard) endif() set(EXPORTED_RUNTIME_METHODS "['stackAlloc','stackRestore','stackSave','UTF8ToString','stringToUTF8','lengthBytesUTF8']") - if (onnxruntime_USE_JS) - set(EXPORTED_FUNCTIONS "_malloc,_free,_JsepOutput") + if (onnxruntime_USE_JSEP) + set(EXPORTED_FUNCTIONS "_malloc,_free,_JsepOutput,_JsepGetNodeName") else() set(EXPORTED_FUNCTIONS "_malloc,_free") endif() @@ -219,17 +225,18 @@ else() --no-entry ) - if (onnxruntime_USE_JS) + if (onnxruntime_USE_JSEP) # NOTE: "-s ASYNCIFY=1" is required for JSEP to work with WebGPU # This flag allows async functions to be called from sync functions, in the cost of binary size and # build time. See https://emscripten.org/docs/porting/asyncify.html for more details. - target_compile_definitions(onnxruntime_webassembly PRIVATE USE_JS=1) + target_compile_definitions(onnxruntime_webassembly PRIVATE USE_JSEP=1) target_link_options(onnxruntime_webassembly PRIVATE --pre-js "${ONNXRUNTIME_ROOT}/wasm/js_internal_api.js" "SHELL:-s ASYNCIFY=1" "SHELL:-s ASYNCIFY_STACK_SIZE=65536" ) + set_target_properties(onnxruntime_webassembly PROPERTIES LINK_DEPENDS ${ONNXRUNTIME_ROOT}/wasm/js_internal_api.js) endif() if (onnxruntime_EMSCRIPTEN_SETTINGS) @@ -242,7 +249,7 @@ else() target_link_options(onnxruntime_webassembly PRIVATE "SHELL:-s ASSERTIONS=2" "SHELL:-s SAFE_HEAP=1" - "SHELL:-s STACK_OVERFLOW_CHECK=1" + "SHELL:-s STACK_OVERFLOW_CHECK=2" "SHELL:-s DEMANGLE_SUPPORT=1" ) else() @@ -255,6 +262,10 @@ else() ) endif() + if (onnxruntime_USE_WEBNN) + set_property(TARGET onnxruntime_webassembly APPEND_STRING PROPERTY LINK_FLAGS " --bind -sWASM_BIGINT") + endif() + # Set link flag to enable exceptions support, this will override default disabling exception throwing behavior when disable exceptions. target_link_options(onnxruntime_webassembly PRIVATE "SHELL:-s DISABLE_EXCEPTION_THROWING=0") @@ -265,21 +276,31 @@ else() if (onnxruntime_ENABLE_WEBASSEMBLY_THREADS) target_link_options(onnxruntime_webassembly PRIVATE "SHELL:-s EXPORT_NAME=ortWasmThreaded" - "SHELL:-s USE_PTHREADS=1" + "SHELL:-s DEFAULT_PTHREAD_STACK_SIZE=131072" ) - if (onnxruntime_ENABLE_WEBASSEMBLY_SIMD) - set_target_properties(onnxruntime_webassembly PROPERTIES OUTPUT_NAME "ort-wasm-simd-threaded") - else() - set_target_properties(onnxruntime_webassembly PROPERTIES OUTPUT_NAME "ort-wasm-threaded") - endif() else() target_link_options(onnxruntime_webassembly PRIVATE "SHELL:-s EXPORT_NAME=ortWasm" ) - if (onnxruntime_ENABLE_WEBASSEMBLY_SIMD) - set_target_properties(onnxruntime_webassembly PROPERTIES OUTPUT_NAME "ort-wasm-simd") - else() - set_target_properties(onnxruntime_webassembly PROPERTIES OUTPUT_NAME "ort-wasm") - endif() endif() + + set(target_name_list ort) + + if (onnxruntime_ENABLE_TRAINING_APIS) + list(APPEND target_name_list "training") + endif() + + list(APPEND target_name_list "wasm") + + if (onnxruntime_ENABLE_WEBASSEMBLY_SIMD) + list(APPEND target_name_list "simd") + endif() + + if (onnxruntime_ENABLE_WEBASSEMBLY_THREADS) + list(APPEND target_name_list "threaded") + endif() + + list(JOIN target_name_list "-" target_name) + + set_target_properties(onnxruntime_webassembly PROPERTIES OUTPUT_NAME ${target_name}) endif() diff --git a/cmake/patches/composable_kernel/Fix_Clang_Build.patch b/cmake/patches/composable_kernel/Fix_Clang_Build.patch index ae2a015c1d0ea..d564ffba914fe 100644 --- a/cmake/patches/composable_kernel/Fix_Clang_Build.patch +++ b/cmake/patches/composable_kernel/Fix_Clang_Build.patch @@ -1,5 +1,5 @@ diff --git a/CMakeLists.txt b/CMakeLists.txt -index f861e3020..f0b6bceae 100644 +index 514b98fde..59c8a568a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ @@ -11,7 +11,7 @@ index f861e3020..f0b6bceae 100644 list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") -@@ -41,27 +41,6 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) +@@ -94,27 +94,6 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) message("CMAKE_CXX_COMPILER_ID: ${CMAKE_CXX_COMPILER_ID}") @@ -39,7 +39,7 @@ index f861e3020..f0b6bceae 100644 ## HIP find_package(HIP REQUIRED) # Override HIP version in config.h, if necessary. -@@ -83,8 +62,6 @@ if( DEFINED CK_OVERRIDE_HIP_VERSION_PATCH ) +@@ -136,8 +115,6 @@ if( DEFINED CK_OVERRIDE_HIP_VERSION_PATCH ) message(STATUS "CK_HIP_VERSION_PATCH overriden with ${CK_OVERRIDE_HIP_VERSION_PATCH}") endif() message(STATUS "Build with HIP ${HIP_VERSION}") @@ -48,17 +48,7 @@ index f861e3020..f0b6bceae 100644 ## tidy include(EnableCompilerWarnings) -@@ -273,9 +250,6 @@ rocm_package_setup_component(profiler - ) - - add_subdirectory(library) --add_subdirectory(example) --add_subdirectory(test) --add_subdirectory(profiler) - - #Create an interface target for the include only files and call it "composablekernels" - include(CMakePackageConfigHelpers) -@@ -301,11 +275,3 @@ rocm_install(FILES +@@ -391,11 +368,3 @@ rocm_install(FILES set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") set(CPACK_RPM_PACKAGE_LICENSE "MIT") @@ -71,7 +61,7 @@ index f861e3020..f0b6bceae 100644 - HEADER_ONLY -) diff --git a/library/src/tensor_operation_instance/gpu/CMakeLists.txt b/library/src/tensor_operation_instance/gpu/CMakeLists.txt -index c206c4dc0..b283eeb64 100644 +index 1d54a141b..4edd7dbfb 100644 --- a/library/src/tensor_operation_instance/gpu/CMakeLists.txt +++ b/library/src/tensor_operation_instance/gpu/CMakeLists.txt @@ -1,7 +1,13 @@ diff --git a/cmake/patches/flatbuffers/flatbuffers.patch b/cmake/patches/flatbuffers/flatbuffers.patch new file mode 100644 index 0000000000000..fb2678ef1bdce --- /dev/null +++ b/cmake/patches/flatbuffers/flatbuffers.patch @@ -0,0 +1,36 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 3987eac9..5e5462f1 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -223,7 +223,7 @@ elseif(CMAKE_COMPILER_IS_GNUCXX) + "${CMAKE_CXX_FLAGS} -std=c++0x") + endif(CYGWIN) + set(CMAKE_CXX_FLAGS +- "${CMAKE_CXX_FLAGS} -Wall -pedantic -Werror -Wextra -Werror=shadow") ++ "${CMAKE_CXX_FLAGS} -Wall -pedantic -Werror -Wextra -Werror=shadow -Wno-error=stringop-overflow") + set(FLATBUFFERS_PRIVATE_CXX_FLAGS "-Wold-style-cast") + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.4) + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0) +diff --git a/src/idl_gen_rust.cpp b/src/idl_gen_rust.cpp +index 55b8439b..dc03e8a8 100644 +--- a/src/idl_gen_rust.cpp ++++ b/src/idl_gen_rust.cpp +@@ -406,7 +406,8 @@ class RustGenerator : public BaseGenerator { + // example: f(A, D::E) -> super::D::E + // does not include leaf object (typically a struct type). + +- size_t i = 0; ++ // fix unused but set variable warning ++ //size_t i = 0; + std::stringstream stream; + + auto s = src->components.begin(); +@@ -417,7 +418,7 @@ class RustGenerator : public BaseGenerator { + if (*s != *d) { break; } + ++s; + ++d; +- ++i; ++ //++i; + } + + for (; s != src->components.end(); ++s) { stream << "super::"; } diff --git a/cmake/patches/onnx/onnx.patch b/cmake/patches/onnx/onnx.patch index d261a178c6b3d..155d153019f85 100644 --- a/cmake/patches/onnx/onnx.patch +++ b/cmake/patches/onnx/onnx.patch @@ -35,25 +35,45 @@ diff --git a/onnx/onnx_pb.h b/onnx/onnx_pb.h index 0aab3e26..0f859267 100644 --- a/onnx/onnx_pb.h +++ b/onnx/onnx_pb.h -@@ -47,10 +47,21 @@ +@@ -47,10 +47,28 @@ #define ONNX_API ONNX_IMPORT #endif - -+// onnx/onnx-operators-ml.pb.h:1178:25: required from here -+// protobuf/src/google/protobuf/repeated_ptr_field.h:752:66: error: unused parameter ‘prototype’ [-Werror=unused-parameter] + +#if defined(__GNUC__) +#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wunused-parameter" ++ ++// In file included from onnx/onnx-ml.pb.h:30: ++// In file included from google/protobuf/extension_set.h:53: ++// google/protobuf/parse_context.h:328:47: error: implicit conversion loses integer precision: 'long' to 'int' [-Werror,-Wshorten-64-to-32] ++#if defined(__has_warning) ++#if __has_warning("-Wshorten-64-to-32") ++#pragma GCC diagnostic ignored "-Wshorten-64-to-32" +#endif ++#endif // defined(__has_warning) ++ ++#endif // defined(__GNUC__) + #ifdef ONNX_ML #include "onnx/onnx-ml.pb.h" #else #include "onnx/onnx.pb.h" #endif - + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + #endif // ! ONNX_ONNX_PB_H +diff --git a/onnx/checker.cc b/onnx/checker.cc +index 8fdaf037..1beb1b88 100644 +--- a/onnx/checker.cc ++++ b/onnx/checker.cc +@@ -190,7 +190,7 @@ void check_tensor(const TensorProto& tensor, const CheckerContext& ctx) { + } + std::string data_path = path_join(ctx.get_model_dir(), relative_path); + // use stat64 to check whether the file exists +-#ifdef __APPLE__ ++#if defined(__APPLE__) || defined(__wasm__) + struct stat buffer; // APPLE does not have stat64 + if (stat((data_path).c_str(), &buffer) != 0) { + #else diff --git a/cmake/patches/xnnpack/AddEmscriptenAndIosSupport.patch b/cmake/patches/xnnpack/AddEmscriptenAndIosSupport.patch index 7296f2f30f286..37bdbf9fb53f6 100644 --- a/cmake/patches/xnnpack/AddEmscriptenAndIosSupport.patch +++ b/cmake/patches/xnnpack/AddEmscriptenAndIosSupport.patch @@ -1,8 +1,8 @@ diff --git a/CMakeLists.txt b/CMakeLists.txt -index d53c48aa1..4c987bd7a 100755 +index d53c48aa1..77c3cf983 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt -@@ -105,7 +105,7 @@ ENDIF() +@@ -105,22 +105,12 @@ ENDIF() IF(NOT CMAKE_SYSTEM_NAME) MESSAGE(FATAL_ERROR "CMAKE_SYSTEM_NAME not defined") @@ -11,7 +11,22 @@ index d53c48aa1..4c987bd7a 100755 MESSAGE(FATAL_ERROR "Unrecognized CMAKE_SYSTEM_NAME = ${CMAKE_SYSTEM_NAME}") ENDIF() -@@ -7108,6 +7108,10 @@ IF(MSVC) + # ---[ Download deps + IF(NOT XNNPACK_USE_SYSTEM_LIBS) +- IF(NOT DEFINED CLOG_SOURCE_DIR) +- MESSAGE(STATUS "Downloading clog to ${CMAKE_BINARY_DIR}/clog-source (define CLOG_SOURCE_DIR to avoid it)") +- CONFIGURE_FILE(cmake/DownloadCLog.cmake "${CMAKE_BINARY_DIR}/clog-download/CMakeLists.txt") +- EXECUTE_PROCESS(COMMAND "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" . +- WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/clog-download") +- EXECUTE_PROCESS(COMMAND "${CMAKE_COMMAND}" --build . +- WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/clog-download") +- SET(CLOG_SOURCE_DIR "${CMAKE_BINARY_DIR}/clog-source" CACHE STRING "clog source directory") +- ENDIF() +- + IF(NOT DEFINED CPUINFO_SOURCE_DIR) + MESSAGE(STATUS "Downloading cpuinfo to ${CMAKE_BINARY_DIR}/cpuinfo-source (define CPUINFO_SOURCE_DIR to avoid it)") + CONFIGURE_FILE(cmake/DownloadCpuinfo.cmake "${CMAKE_BINARY_DIR}/cpuinfo-download/CMakeLists.txt") +@@ -7108,6 +7098,10 @@ IF(MSVC) SET_PROPERTY(SOURCE ${ALL_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS "$<$>: /O2 >") SET_PROPERTY(SOURCE ${HOT_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS "$<$>: /O2 >") SET_PROPERTY(SOURCE ${COLD_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS "$<$>: /O1 >") @@ -22,3 +37,30 @@ index d53c48aa1..4c987bd7a 100755 ELSE() SET_PROPERTY(SOURCE ${ALL_MICROKERNEL_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS "$<$>: -O2 >") SET_PROPERTY(SOURCE ${HOT_SRCS} APPEND_STRING PROPERTY COMPILE_FLAGS "$<$>: -O2 >") +@@ -7142,26 +7136,6 @@ IF(LIBM) + TARGET_LINK_LIBRARIES(indirection PRIVATE ${LIBM}) + ENDIF() + +-# ---[ Configure clog +-IF(NOT TARGET clog) +- IF(NOT XNNPACK_USE_SYSTEM_LIBS) +- SET(CLOG_BUILD_TESTS OFF CACHE BOOL "") +- SET(CLOG_RUNTIME_TYPE "${CPUINFO_RUNTIME_TYPE}" CACHE STRING "") +- ADD_SUBDIRECTORY( +- "${CLOG_SOURCE_DIR}/deps/clog" +- "${CMAKE_BINARY_DIR}/clog") +- # We build static version of clog but a dynamic library may indirectly depend on it +- SET_PROPERTY(TARGET clog PROPERTY POSITION_INDEPENDENT_CODE ON) +- ELSE() +- ADD_LIBRARY(clog STATIC IMPORTED) +- FIND_LIBRARY(CLOG_LIBRARY clog) +- IF(NOT CLOG_LIBRARY) +- MESSAGE(FATAL_ERROR "Cannot find clog") +- ENDIF() +- SET_PROPERTY(TARGET clog PROPERTY IMPORTED_LOCATION "${CLOG_LIBRARY}") +- ENDIF() +-ENDIF() +- + # ---[ Configure cpuinfo + IF(NOT TARGET cpuinfo) + IF(NOT XNNPACK_USE_SYSTEM_LIBS) diff --git a/cmake/winml.cmake b/cmake/winml.cmake index 4186cbefacf74..395996f0fa4b9 100644 --- a/cmake/winml.cmake +++ b/cmake/winml.cmake @@ -202,7 +202,7 @@ add_dependencies(winml_lib_telemetry winml_api_native) add_dependencies(winml_lib_telemetry winml_api_native_internal) # Link libraries -target_link_libraries(winml_lib_telemetry PRIVATE WIL::WIL) +target_link_libraries(winml_lib_telemetry PRIVATE ${WIL_TARGET}) ########################### # Add winml_lib_ort @@ -282,7 +282,7 @@ add_dependencies(winml_lib_ort winml_api_native_internal) if (onnxruntime_USE_DML) target_add_dml(winml_lib_ort) endif() -target_link_libraries(winml_lib_ort PRIVATE WIL::WIL) +target_link_libraries(winml_lib_ort PRIVATE ${WIL_TARGET}) target_link_libraries(winml_lib_ort INTERFACE winml_lib_api) target_link_libraries(winml_lib_ort INTERFACE winml_lib_telemetry) @@ -339,7 +339,7 @@ set_target_properties(winml_adapter ${target_folder}) # Link libraries -target_link_libraries(winml_adapter PRIVATE WIL::WIL) +target_link_libraries(winml_adapter PRIVATE ${WIL_TARGET}) if (onnxruntime_USE_DML) target_add_dml(winml_adapter) endif() @@ -423,7 +423,7 @@ add_dependencies(winml_lib_image winml_api_native) add_dependencies(winml_lib_image winml_api_native_internal) # Link libraries -target_link_libraries(winml_lib_image PRIVATE dxgi d3d11 d3d12 WIL::WIL winml_lib_common) +target_link_libraries(winml_lib_image PRIVATE dxgi d3d11 d3d12 ${WIL_TARGET} winml_lib_common) get_target_property(winml_lib_image_include_directories winml_lib_image INCLUDE_DIRECTORIES) @@ -531,7 +531,7 @@ add_dependencies(winml_lib_api winml_api_native) add_dependencies(winml_lib_api winml_api_native_internal) # Link libraries -target_link_libraries(winml_lib_api PRIVATE WIL::WIL winml_lib_telemetry) +target_link_libraries(winml_lib_api PRIVATE ${WIL_TARGET} winml_lib_telemetry) if (onnxruntime_USE_DML) target_add_dml(winml_lib_api) endif(onnxruntime_USE_DML) @@ -619,7 +619,7 @@ add_dependencies(winml_lib_api_experimental winml_api_native_internal) add_dependencies(winml_lib_api_experimental winml_api_experimental) # Link libraries -target_link_libraries(winml_lib_api_experimental PRIVATE WIL::WIL winml_lib_telemetry) +target_link_libraries(winml_lib_api_experimental PRIVATE ${WIL_TARGET} winml_lib_telemetry) if (onnxruntime_USE_DML) target_add_dml(winml_lib_api_experimental) endif(onnxruntime_USE_DML) @@ -648,7 +648,7 @@ onnxruntime_add_static_library(winml_lib_common set_target_properties(winml_lib_common PROPERTIES CXX_STANDARD 17) set_target_properties(winml_lib_common PROPERTIES CXX_STANDARD_REQUIRED ON) target_compile_options(winml_lib_common PRIVATE /GR- /await /bigobj /wd4238) -target_link_libraries(winml_lib_common PRIVATE WIL::WIL) +target_link_libraries(winml_lib_common PRIVATE ${WIL_TARGET}) target_include_directories(winml_lib_common PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/winml_api) # Compiler flags @@ -786,7 +786,7 @@ add_dependencies(winml_dll winml_api_native_internal) # Link libraries target_link_libraries(winml_dll PRIVATE re2) -target_link_libraries(winml_dll PRIVATE WIL::WIL) +target_link_libraries(winml_dll PRIVATE ${WIL_TARGET}) target_link_libraries(winml_dll PRIVATE winml_lib_api) if (NOT winml_is_inbox) target_link_libraries(winml_dll PRIVATE winml_lib_api_experimental) diff --git a/cmake/winml_unittests.cmake b/cmake/winml_unittests.cmake index 561bd005dc383..b655e60a8aec9 100644 --- a/cmake/winml_unittests.cmake +++ b/cmake/winml_unittests.cmake @@ -49,7 +49,10 @@ function(add_winml_test) if (_UT_DEPENDS) add_dependencies(${_UT_TARGET} ${_UT_DEPENDS}) endif() - target_link_libraries(${_UT_TARGET} PRIVATE ${_UT_LIBS} gtest winml_google_test_lib ${onnxruntime_EXTERNAL_LIBRARIES} winml_lib_common onnxruntime windowsapp.lib) + target_link_libraries(${_UT_TARGET} PRIVATE ${_UT_LIBS} GTest::gtest winml_google_test_lib ${onnxruntime_EXTERNAL_LIBRARIES} winml_lib_common onnxruntime windowsapp.lib) + #Abseil has a lot of C4127/C4324 warnings. + target_compile_options(${_UT_TARGET} PRIVATE "/wd4127") + target_compile_options(${_UT_TARGET} PRIVATE "/wd4324") target_compile_options(${_UT_TARGET} PRIVATE /wd5205) # workaround cppwinrt SDK bug https://github.com/microsoft/cppwinrt/issues/584 # if building inbox @@ -174,15 +177,18 @@ target_compile_options(winml_test_common PRIVATE /wd5205) # workaround cppwinrt if (onnxruntime_WINML_NAMESPACE_OVERRIDE STREQUAL "Windows") target_compile_definitions(winml_test_common PRIVATE "BUILD_INBOX=1") endif() +#Abseil has a lot of C4127/C4324 warnings. +target_compile_options(winml_test_common PRIVATE "/wd4127") +target_compile_options(winml_test_common PRIVATE "/wd4324") add_dependencies(winml_test_common onnx winml_api winml_dll ) -onnxruntime_add_include_to_target(winml_test_common onnx_proto gtest ${PROTOBUF_LIB} WIL::WIL safeint_interface ${GSL_TARGET}) +onnxruntime_add_include_to_target(winml_test_common onnx_proto GTest::gtest ${PROTOBUF_LIB} ${WIL_TARGET} safeint_interface ${GSL_TARGET}) onnxruntime_add_static_library(winml_google_test_lib ${WINML_TEST_SRC_DIR}/common/googletest/main.cpp) -onnxruntime_add_include_to_target(winml_google_test_lib gtest) +onnxruntime_add_include_to_target(winml_google_test_lib GTest::gtest) set_winml_target_properties(winml_google_test_lib) set_winml_target_properties(winml_test_common) diff --git a/csharp/.clang-format b/csharp/.clang-format index f2748cf3abccd..f440737ccfdd6 100644 --- a/csharp/.clang-format +++ b/csharp/.clang-format @@ -1,15 +1,22 @@ --- # clang-format settings for the C# code -BasedOnStyle: Microsoft +BasedOnStyle: Microsoft + +# Setting ColumnLimit to 0 so developer choices about where to break lines are maintained. +# Developers are responsible for adhering to the 120 character maximum. +ColumnLimit: 0 BreakBeforeBraces: Custom BraceWrapping: - AfterCaseLabel: true - BeforeWhile: true + AfterCaseLabel: true + BeforeWhile: true SplitEmptyFunction: false SplitEmptyRecord: false - # unfortunately there's no config option for handling the 'get' or 'set' of properties + # unfortunately there's no config option for handling the 'get' or 'set' of properties IndentCaseLabels: true KeepEmptyLinesAtTheStartOfBlocks: false -SpacesInContainerLiterals: false \ No newline at end of file +NamespaceIndentation: All +SpacesInContainerLiterals: false +SortIncludes: CaseSensitive +SortUsingDeclarations: LexicographicNumeric diff --git a/csharp/ApiDocs/ApiDocs.csproj b/csharp/ApiDocs/ApiDocs.csproj index a56e6050222d6..994e57913cf47 100644 --- a/csharp/ApiDocs/ApiDocs.csproj +++ b/csharp/ApiDocs/ApiDocs.csproj @@ -1,8 +1,9 @@  - net5.0 + net6.0 enable + true diff --git a/csharp/ApiDocs/docfx.json b/csharp/ApiDocs/docfx.json index 9f458497e5933..c3ed49b563019 100644 --- a/csharp/ApiDocs/docfx.json +++ b/csharp/ApiDocs/docfx.json @@ -4,14 +4,22 @@ "src": [ { "files": [ - "src/Microsoft.ML.OnnxRuntime/**.cs" + "src/Microsoft.ML.OnnxRuntime/Microsoft.ML.OnnxRuntime.csproj" ], "src": "../" } ], "dest": "api", "disableGitFeatures": false, - "disableDefaultFilter": false + "disableDefaultFilter": false, + "properties": { + "AllowUnsafeBlocks": true, + "TargetFramework" : "net6.0", + "Nullable" : "enable", + "LangVersion": "8.0", + "EnableTrainingApis": "true" + }, + "filter": "filterConfig.yml" } ], "build": { diff --git a/csharp/ApiDocs/filterConfig.yml b/csharp/ApiDocs/filterConfig.yml new file mode 100644 index 0000000000000..33a12e7262b16 --- /dev/null +++ b/csharp/ApiDocs/filterConfig.yml @@ -0,0 +1,5 @@ +apiRules: +- exclude: + uidRegex: ^Microsoft\.ML\.OnnxRuntime\.OrtApi +- exclude: + uidRegex: ^Microsoft\.ML\.OnnxRuntime\.OrtTrainingApi diff --git a/csharp/Nuget.CSharp.config b/csharp/NuGet.CSharp.config similarity index 100% rename from csharp/Nuget.CSharp.config rename to csharp/NuGet.CSharp.config diff --git a/csharp/OnnxRuntime.CSharp.proj b/csharp/OnnxRuntime.CSharp.proj index 5473246e8be3f..0288d752d8749 100644 --- a/csharp/OnnxRuntime.CSharp.proj +++ b/csharp/OnnxRuntime.CSharp.proj @@ -16,6 +16,7 @@ CMake creates a target to this project nuget x64 false + false None @@ -77,6 +78,7 @@ CMake creates a target to this project $([System.DateTime]::UtcNow.ToString(yyyyMMdd)) $([System.DateTime]::UtcNow.ToString(hhmm)) @(MajorVersionNumber) + $(PackageVersion)$(ReleaseVersionSuffix) $(PackageVersion) $(PackageVersion)-dev-$(CurrentDate)-$(CurrentTime)-$(GitCommitHashShort) diff --git a/csharp/readme.md b/csharp/readme.md index ad71348b2993b..74572b5f17505 100644 --- a/csharp/readme.md +++ b/csharp/readme.md @@ -2,7 +2,7 @@ The solution files here are used to produce nuget packages for the C# bindings. -Note that the project naming is currently confusing and needs updating. +Note that the project naming is currently confusing and needs updating. - The Microsoft.ML.OnnxRuntime project produces the Microsoft.ML.OnnxRuntime.**Managed** nuget package. - The Microsoft.ML.OnnxRuntime nuget package contains the native (i.e. C++) code for various platforms. @@ -10,17 +10,19 @@ Note that the project naming is currently confusing and needs updating. ## Solution files The main solution file is OnnxRuntime.CSharp.sln. This includes desktop and Xamarin mobile projects. -OnnxRuntime.DesktopOnly.CSharp.sln is a copy of that with all the mobile projects removed. This is -due to there being no way to selectively exclude a csproj from the sln if Xamarin isn't available. +OnnxRuntime.DesktopOnly.CSharp.sln is a copy of that with all the mobile projects removed. This is +due to there being no way to selectively exclude a csproj from the sln if Xamarin isn't available. If changes are required, either update the main solution first and copy the relevant changes across, -or copy the entire file and remove the mobile projects (anything with iOS, Android or Droid in the name). +or copy the entire file and remove the mobile projects (anything with iOS, Android or Droid in the name). ## Development setup: ### Requirements: -NOTE: The usage of this solution is primarily for ORT developers creating the managed Microsoft.ML.OnnxRuntime.Managed +#### Windows + +NOTE: The usage of this solution is primarily for ORT developers creating the managed Microsoft.ML.OnnxRuntime.Managed nuget package. Due to that, the requirements are quite specific. Visual Studio 2022 v17.2.4 or later, with Xamarin workloads @@ -29,24 +31,42 @@ Visual Studio 2022 v17.2.4 or later, with Xamarin workloads - untested There's no good way to use Visual Studio 2022 17.3 Preview in a CI, so we currently have to build pre-.net6 targets -using VS, and .net6 targets using dotnet. We can't build them all using dotnet as the xamarin targets require msbuild. +using VS, and .net6 targets using dotnet. We can't build them all using dotnet as the xamarin targets require msbuild. We can't package them using dotnet as that also requires msbuild. -Once the official VS 2022 release supports .net6 and is available in the CI we can revert to the original simple +Once the official VS 2022 release supports .net6 and is available in the CI we can revert to the original simple setup of building everything using msbuild. -To test packaging locally you will also need nuget.exe. -Download from https://www.nuget.org/downloads. +To test packaging locally you will also need nuget.exe. +Download from https://www.nuget.org/downloads. Put in a folder (e.g. C:\Program Files (x86)\NuGet). -Add that folder to your PATH. +Add that folder to your PATH. + +#### Linux + +1. Install [.Net SDK](https://dotnet.microsoft.com/download). +2. Install Mono. + ```bash + wget http://download.mono-project.com/repo/xamarin.gpg && sudo apt-key add xamarin.gpg && rm xamarin.gpg + echo "deb https://download.mono-project.com/repo/ubuntu stable-bionic main" | sudo tee /etc/apt/sources.list.d/mono-official-stable.list + sudo apt update -y && apt install -y mono-devel + ``` +3. Install `nupkg.exe` + ```bash + wget https://dist.nuget.org/win-x86-commandline/latest/nuget.exe && sudo mv nuget.exe /usr/local/bin/nuget.exe + echo 'mono /usr/local/bin/nuget.exe $@' | sudo tee /usr/local/bin/nuget + chmod a+x /usr/local/bin/nuget + ``` ### Magic incantations to build the nuget managed package locally: +#### Windows + If we're starting with VS 2022 17.2.4 we should have dotnet sdk 6.0.301 Make sure all the required workloads are installed `dotnet workload install android ios maccatalyst macos` - - original example from [here](https://github.com/Sweekriti91/maui-samples/blob/swsat/devops/6.0/Apps/WeatherTwentyOne/devops/AzureDevOps/azdo_windows.yml): + - original example from [here](https://github.com/Sweekriti91/maui-samples/blob/swsat/devops/6.0/Apps/WeatherTwentyOne/devops/AzureDevOps/azdo_windows.yml): - `dotnet workload install android ios maccatalyst macos maui --source https://aka.ms/dotnet6/nuget/index.json --source https://api.nuget.org/v3/index.json` - don't need 'maui' in this list until we update the sample/test apps - didn't seem to need --source arg/s for local build. YMMV. @@ -55,12 +75,12 @@ Build pre-net6 targets `msbuild -t:restore .\src\Microsoft.ML.OnnxRuntime\Microsoft.ML.OnnxRuntime.csproj -p:SelectedTargets=PreNet6` `msbuild -t:build .\src\Microsoft.ML.OnnxRuntime\Microsoft.ML.OnnxRuntime.csproj -p:SelectedTargets=PreNet6` - Need to run msbuild twice - once to restore which creates some json configs that are needed like + Need to run msbuild twice - once to restore which creates some json configs that are needed like Microsoft.ML.OnnxRuntime\obj\project.assets.json, and once to build using the configs. Build net6 targets `dotnet build .\src\Microsoft.ML.OnnxRuntime\Microsoft.ML.OnnxRuntime.csproj -p:SelectedTargets=Net6` - + The dotnet build does the restore internally. Create project.assets.json in obj dir with all targets so the nuget package creation includes them all @@ -68,3 +88,32 @@ Create project.assets.json in obj dir with all targets so the nuget package crea Create nuget package `msbuild .\OnnxRuntime.CSharp.proj -t:CreatePackage -p:OrtPackageId=Microsoft.ML.OnnxRuntime -p:Configuration=Debug -p:Platform="Any CPU"` + +#### Linux + +For example, to build a CUDA GPU package, just run: +```bash +./build.sh \ + --config="Release" \ + --cmake_generator Ninja \ + --use_cuda \ + --cuda_home=/usr/local/cuda \ + --cudnn_home=/usr \ + --build_nuget \ + --msbuild_extra_options \ + /p:SelectedTargets=Net6 \ + /p:Net6Targets=net6.0 \ + /p:TargetFrameworks=netstandard2.0 \ + /p:IsLinuxBuild=true +``` +**Note**: to build a pure CPU development package, you need to add `/p:OrtPackageId="Microsoft.ML.OnnxRuntime"` +to `--msbuild_extra_options`. Otherwise, it will try to create Xamarin mobile targets which may not be properly configured on your devbox. + +A `.nupkg` file will be produced at you build root, say, `build/Release`. + +To consume the package, in your .net project, +```bash +nuget add -Source ./packages/ +dotnet add package microsoft.ml.onnxruntime.managed -s ./packages --prerelease +dotnet add package microsoft.ml.onnxruntime.gpu -s ./packages --prerelease +``` diff --git a/csharp/sample/InferenceSample/Microsoft.ML.OnnxRuntime.InferenceSample.Forms.Android/Microsoft.ML.OnnxRuntime.InferenceSample.Forms.Android.csproj b/csharp/sample/InferenceSample/Microsoft.ML.OnnxRuntime.InferenceSample.Forms.Android/Microsoft.ML.OnnxRuntime.InferenceSample.Forms.Android.csproj index ec9e60710fedd..5fa0349e0f9a3 100644 --- a/csharp/sample/InferenceSample/Microsoft.ML.OnnxRuntime.InferenceSample.Forms.Android/Microsoft.ML.OnnxRuntime.InferenceSample.Forms.Android.csproj +++ b/csharp/sample/InferenceSample/Microsoft.ML.OnnxRuntime.InferenceSample.Forms.Android/Microsoft.ML.OnnxRuntime.InferenceSample.Forms.Android.csproj @@ -100,7 +100,7 @@ - + libs\arm64-v8a\libonnxruntime.so @@ -115,4 +115,4 @@ - \ No newline at end of file + diff --git a/csharp/sample/InferenceSample/Microsoft.ML.OnnxRuntime.InferenceSample.Forms.iOS/Microsoft.ML.OnnxRuntime.InferenceSample.Forms.iOS.csproj b/csharp/sample/InferenceSample/Microsoft.ML.OnnxRuntime.InferenceSample.Forms.iOS/Microsoft.ML.OnnxRuntime.InferenceSample.Forms.iOS.csproj index ce261096c1a00..1b50a2842f242 100644 --- a/csharp/sample/InferenceSample/Microsoft.ML.OnnxRuntime.InferenceSample.Forms.iOS/Microsoft.ML.OnnxRuntime.InferenceSample.Forms.iOS.csproj +++ b/csharp/sample/InferenceSample/Microsoft.ML.OnnxRuntime.InferenceSample.Forms.iOS/Microsoft.ML.OnnxRuntime.InferenceSample.Forms.iOS.csproj @@ -147,7 +147,7 @@ - + Framework True @@ -160,4 +160,4 @@ - \ No newline at end of file + diff --git a/csharp/sample/InferenceSample/Microsoft.ML.OnnxRuntime.InferenceSample.NetCoreApp/Properties/launchSettings.json b/csharp/sample/InferenceSample/Microsoft.ML.OnnxRuntime.InferenceSample.NetCoreApp/Properties/launchSettings.json new file mode 100644 index 0000000000000..33504c948ad25 --- /dev/null +++ b/csharp/sample/InferenceSample/Microsoft.ML.OnnxRuntime.InferenceSample.NetCoreApp/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "WSL": { + "commandName": "WSL2", + "distributionName": "" + } + } +} \ No newline at end of file diff --git a/csharp/sample/InferenceSample/Microsoft.ML.OnnxRuntime.InferenceSample/InferenceSampleApi.cs b/csharp/sample/InferenceSample/Microsoft.ML.OnnxRuntime.InferenceSample/InferenceSampleApi.cs index f48f9a9e3816e..05baa872a0ece 100644 --- a/csharp/sample/InferenceSample/Microsoft.ML.OnnxRuntime.InferenceSample/InferenceSampleApi.cs +++ b/csharp/sample/InferenceSample/Microsoft.ML.OnnxRuntime.InferenceSample/InferenceSampleApi.cs @@ -1,7 +1,8 @@ -using System; +using Microsoft.ML.OnnxRuntime.Tensors; +using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; -using Microsoft.ML.OnnxRuntime.Tensors; namespace Microsoft.ML.OnnxRuntime.InferenceSample { @@ -9,10 +10,10 @@ public class InferenceSampleApi : IDisposable { public InferenceSampleApi() { - model = LoadModelFromEmbeddedResource("TestData.squeezenet.onnx"); + _model = LoadModelFromEmbeddedResource("TestData.squeezenet.onnx"); // this is the data for only one input tensor for this model - var inputTensor = LoadTensorFromEmbeddedResource("TestData.bench.in"); + var inputData = LoadTensorFromEmbeddedResource("TestData.bench.in"); // create default session with default session options // Creating an InferenceSession and loading the model is an expensive operation, so generally you would @@ -20,13 +21,21 @@ public InferenceSampleApi() CreateInferenceSession(); // setup sample input data - inputData = new List(); - var inputMeta = inferenceSession.InputMetadata; + var inputMeta = _inferenceSession.InputMetadata; + _inputData = new List(inputMeta.Count); + _orderedInputNames = new List(inputMeta.Count); + foreach (var name in inputMeta.Keys) { - // note: DenseTensor takes a copy of the provided data - var tensor = new DenseTensor(inputTensor, inputMeta[name].Dimensions); - inputData.Add(NamedOnnxValue.CreateFromTensor(name, tensor)); + // We create an OrtValue in this case over the buffer of potentially different shapes. + // It is Okay as long as the specified shape does not exceed the actual length of the buffer + var shape = Array.ConvertAll(inputMeta[name].Dimensions, Convert.ToInt64); + Debug.Assert(ShapeUtils.GetSizeForShape(shape) <= inputData.LongLength); + + var ortValue = OrtValue.CreateTensorValueFromMemory(inputData, shape); + _inputData.Add(ortValue); + + _orderedInputNames.Add(name); } } @@ -40,30 +49,47 @@ public void CreateInferenceSession(SessionOptions options = null) options = new SessionOptions { LogId = "Sample" }; } - inferenceSession = new InferenceSession(model, options); + _inferenceSession = new InferenceSession(_model, options); } public void Execute() { // Run the inference - // 'results' is an IDisposableReadOnlyCollection container - using (var results = inferenceSession.Run(inputData)) + // 'results' is an IDisposableReadOnlyCollection container + using (var results = _inferenceSession.Run(null, _orderedInputNames, _inputData, _inferenceSession.OutputNames)) { // dump the results - foreach (var r in results) + for (int i = 0; i < results.Count; ++i) { - Console.WriteLine("Output for {0}", r.Name); - Console.WriteLine(r.AsTensor().GetArrayString()); + var name = _inferenceSession.OutputNames[i]; + Console.WriteLine("Output for {0}", name); + // We can now access the native buffer directly from the OrtValue, no copy is involved. + // Spans are structs and are stack allocated. They do not add any GC pressure. + ReadOnlySpan span = results[i].GetTensorDataAsSpan(); + Console.Write($"Input {i} results:"); + for(int k = 0; k < span.Length; ++k) + { + Console.Write($" {span[k]}"); + } + Console.WriteLine(); } } } protected virtual void Dispose(bool disposing) { - if (disposing && inferenceSession != null) + if (disposing && !_disposed) { - inferenceSession.Dispose(); - inferenceSession = null; + _inferenceSession?.Dispose(); + _inferenceSession = null; + + if (_inputData != null) + foreach(var v in _inputData) + { + v?.Dispose(); + } + + _disposed = true; } } @@ -110,8 +136,10 @@ static byte[] LoadModelFromEmbeddedResource(string path) return model; } - private readonly byte[] model; - private readonly List inputData; - private InferenceSession inferenceSession; + private bool _disposed = false; + private readonly byte[] _model; + private readonly List _orderedInputNames; + private readonly List _inputData; + private InferenceSession _inferenceSession; } } diff --git a/csharp/sample/InferenceSample/Microsoft.ML.OnnxRuntime.InferenceSample/Microsoft.ML.OnnxRuntime.InferenceSample.csproj b/csharp/sample/InferenceSample/Microsoft.ML.OnnxRuntime.InferenceSample/Microsoft.ML.OnnxRuntime.InferenceSample.csproj index a59bf5bdff45c..0efb8cc7a3a23 100644 --- a/csharp/sample/InferenceSample/Microsoft.ML.OnnxRuntime.InferenceSample/Microsoft.ML.OnnxRuntime.InferenceSample.csproj +++ b/csharp/sample/InferenceSample/Microsoft.ML.OnnxRuntime.InferenceSample/Microsoft.ML.OnnxRuntime.InferenceSample.csproj @@ -2,6 +2,7 @@ netstandard2.0 + True diff --git a/csharp/src/Microsoft.AI.MachineLearning/Microsoft.AI.MachineLearning.targets b/csharp/src/Microsoft.AI.MachineLearning/Microsoft.AI.MachineLearning.targets index 2f100fd75a28a..c1bddfa1adf47 100644 --- a/csharp/src/Microsoft.AI.MachineLearning/Microsoft.AI.MachineLearning.targets +++ b/csharp/src/Microsoft.AI.MachineLearning/Microsoft.AI.MachineLearning.targets @@ -32,7 +32,7 @@ - + diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/DisposableNamedOnnxValue.shared.cs b/csharp/src/Microsoft.ML.OnnxRuntime/DisposableNamedOnnxValue.shared.cs index 34e71074d9d9d..6d69f58d20413 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/DisposableNamedOnnxValue.shared.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/DisposableNamedOnnxValue.shared.cs @@ -4,6 +4,8 @@ using Microsoft.ML.OnnxRuntime.Tensors; using System; using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; namespace Microsoft.ML.OnnxRuntime { @@ -11,7 +13,7 @@ namespace Microsoft.ML.OnnxRuntime /// Return immutable collection of results /// /// - public interface IDisposableReadOnlyCollection : IReadOnlyCollection, IDisposable + public interface IDisposableReadOnlyCollection : IReadOnlyCollection, IReadOnlyList, IDisposable { } @@ -19,13 +21,21 @@ public interface IDisposableReadOnlyCollection : IReadOnlyCollection, IDis internal class DisposableList : List, IDisposableReadOnlyCollection where T : IDisposable { + private bool _disposed; public DisposableList() { } public DisposableList(int count) : base(count) { } + public DisposableList(IEnumerable collection) : base(collection) { } + #region IDisposable Support protected virtual void Dispose(bool disposing) { + if (_disposed) + { + return; + } + if (disposing) { // Dispose in the reverse order. @@ -39,6 +49,7 @@ protected virtual void Dispose(bool disposing) this[i]?.Dispose(); } this.Clear(); + _disposed = true; } } @@ -53,6 +64,9 @@ public void Dispose() } /// + /// This is a legacy class that is kept for backward compatibility. + /// Use OrtValue based API. + /// /// This class serves as a container for model run output values including /// tensors, sequences of tensors, sequences and maps. /// The class must be disposed of. @@ -63,7 +77,7 @@ public void Dispose() public class DisposableNamedOnnxValue : NamedOnnxValue, IDisposable { private IOrtValueOwner _ortValueHolder; - private bool _disposed = false; + private bool _disposed; /// /// Ctor @@ -119,179 +133,181 @@ private DisposableNamedOnnxValue(string name, Object value, MapHelper mapHelper, public TensorElementType ElementType { get; } /// - /// Overrides the base class method. Since the instance already owns underlying OrtValue handle, - /// it returns an instance of OrtValue that does not own the raw handle - /// that to the output onnxValue. With respect to pinnedMemoryHandle, it has no operation + /// Overrides the base class method. With respect to pinnedMemoryHandle, it has no operation /// to do, as this class maintains a native buffer via _ortValueHolder and the memory will be /// disposed by it. This is the case when we are dealing with an OrtValue that is backed by native memory /// and not by pinned managed memory. /// /// This class is generally used for outputs to be created on top of the output OrtValue, - /// but the interface (derived from NamedOnnxValue) allows it to be passed as input and one of the test + /// but the interface (derived from NamedOnnxValue) allows it to be passed as output and one of the test /// cases does it. Unless we deprecate and re-do the interface, we must support it. /// /// always set to null - /// An instance of OrtValue that does not own underlying memory - internal override OrtValue InputToOrtValue(NodeMetadata metadata, out IDisposable memoryHolder) + /// Native OrtValue handle + internal override IntPtr InputToOrtValueHandle(NodeMetadata metadata, out IDisposable memoryHolder) { if (_ortValueHolder == null) { - throw new InvalidOperationException("The instance of this class does not own any OrtValues"); + throw new InvalidOperationException("The instance of this class does not own an OrtValue"); } // PinnedMemoryHandle holds the default value as DisposableNamedOnnxValue // doesn't hold any managed buffer (that needs to be pinned) memoryHolder = null; // Return non-owning instance of OrtValue - return _ortValueHolder.Value; + return _ortValueHolder.Value.Handle; } /// /// Generally, this class is created on top of the values that are returned by the model run. - /// So, this method is not expected to be called. However, if it is called (an instance fed as output), - /// it will return the OrtValue that was previously created, since the caller must understand what they are doing. + /// However, there is a test case that uses this value for output + /// It will return the OrtValue that was previously created, since the caller must understand what they are doing. /// /// /// /// - internal override OrtValue OutputToOrtValue(NodeMetadata metadata, out IDisposable memoryOwner) + internal override IntPtr OutputToOrtValueHandle(NodeMetadata metadata, out IDisposable memoryOwner) { - return InputToOrtValue(metadata, out memoryOwner); + return InputToOrtValueHandle(metadata, out memoryOwner); } - internal static DisposableNamedOnnxValue CreateFromOrtValue(string name, OrtValue ortValue) + /// + /// This function takes ortValue and constructs an instance of DisposableNamedOnnxValue. + /// The new instance takes ownership of the OrtValue and will dispose of it when it is disposed of. + /// + /// + /// becomes null on success. + /// an instance of DisposableNamedOnnxValue + internal static DisposableNamedOnnxValue CreateFromOrtValue(string name, ref OrtValue ortValue) { - return CreateFromOrtValue(name, ortValue, OrtAllocator.DefaultInstance); + return CreateFromOrtValue(name, ref ortValue, OrtAllocator.DefaultInstance); } - internal static DisposableNamedOnnxValue CreateFromOrtValue(string name, OrtValue ortValue, OrtAllocator allocator) + /// + /// This function takes ortValue and constructs an instance of DisposableNamedOnnxValue. + /// The new instance takes ownership of the OrtValue and will dispose of it when it is disposed of. + /// + /// + /// becomes null on success. + /// + /// an instance of DisposableNamedOnnxValue + /// + internal static DisposableNamedOnnxValue CreateFromOrtValue(string name, ref OrtValue ortValue, OrtAllocator allocator) { - DisposableNamedOnnxValue result = null; + DisposableNamedOnnxValue result; - IntPtr valueType; - NativeApiStatus.VerifySuccess(NativeMethods.OrtGetValueType(ortValue.Handle, out valueType)); - OnnxValueType onnxValueType = (OnnxValueType)valueType; + var onnxValueType = ortValue.OnnxType; switch (onnxValueType) { case OnnxValueType.ONNX_TYPE_TENSOR: - result = FromNativeTensor(name, ortValue); + result = FromNativeTensor(name, ref ortValue); break; case OnnxValueType.ONNX_TYPE_SEQUENCE: - result = FromNativeSequence(name, ortValue, allocator); + result = FromNativeSequence(name, ref ortValue, allocator); break; case OnnxValueType.ONNX_TYPE_MAP: - result = FromNativeMap(name, ortValue, allocator); + result = FromNativeMap(name, ref ortValue, allocator); break; default: - throw new NotSupportedException("OnnxValueType : " + onnxValueType + " is not supported"); + throw new NotSupportedException($"OnnxValueType : {onnxValueType} is not supported"); } return result; } /// - /// Creates an instance of DisposableNamedOnnxValue and takes ownership of ortValueElement + /// Creates an instance of DisposableNamedOnnxValue and takes ownership of ortValue. /// on success. /// /// name of the value - /// underlying OrtValue + /// Underlying OrtValue. This becomes null on successful return. /// - private static DisposableNamedOnnxValue FromNativeTensor(string name, OrtValue ortValue) + private static DisposableNamedOnnxValue FromNativeTensor(string name, ref OrtValue ortValue) { - DisposableNamedOnnxValue result = null; - - /* Get Tensor element type */ //TODO: Assumed value is Tensor, need to support non-tensor types in future - IntPtr typeAndShape = IntPtr.Zero; - NativeApiStatus.VerifySuccess(NativeMethods.OrtGetTensorTypeAndShape(ortValue.Handle, out typeAndShape)); - TensorElementType elemType = TensorElementType.DataTypeMax; - try - { - IntPtr el_type; - NativeApiStatus.VerifySuccess(NativeMethods.OrtGetTensorElementType(typeAndShape, out el_type)); - elemType = (TensorElementType)el_type; - } - finally - { - NativeMethods.OrtReleaseTensorTypeAndShapeInfo(typeAndShape); - } + DisposableNamedOnnxValue result; - switch (elemType) + var typeShape = ortValue.GetTensorTypeAndShape(); + switch (typeShape.ElementDataType) { case TensorElementType.Float: - result = FromNativeTensor(name, ortValue); + result = FromNativeTensor(name, ref ortValue); break; case TensorElementType.Double: - result = FromNativeTensor(name, ortValue); + result = FromNativeTensor(name, ref ortValue); break; case TensorElementType.Int16: - result = FromNativeTensor(name, ortValue); + result = FromNativeTensor(name, ref ortValue); break; case TensorElementType.UInt16: - result = FromNativeTensor(name, ortValue); + result = FromNativeTensor(name, ref ortValue); break; case TensorElementType.Int32: - result = FromNativeTensor(name, ortValue); + result = FromNativeTensor(name, ref ortValue); break; case TensorElementType.UInt32: - result = FromNativeTensor(name, ortValue); + result = FromNativeTensor(name, ref ortValue); break; case TensorElementType.Int64: - result = FromNativeTensor(name, ortValue); + result = FromNativeTensor(name, ref ortValue); break; case TensorElementType.UInt64: - result = FromNativeTensor(name, ortValue); + result = FromNativeTensor(name, ref ortValue); break; case TensorElementType.UInt8: - result = FromNativeTensor(name, ortValue); + result = FromNativeTensor(name, ref ortValue); break; case TensorElementType.Int8: - result = FromNativeTensor(name, ortValue); + result = FromNativeTensor(name, ref ortValue); break; case TensorElementType.String: - result = FromNativeTensor(name, ortValue); + { + var shape = Array.ConvertAll(typeShape.Shape, Convert.ToInt32); + result = FromNativeStringTensor(name, shape, ref ortValue); + } break; case TensorElementType.Bool: - result = FromNativeTensor(name, ortValue); + result = FromNativeTensor(name, ref ortValue); break; case TensorElementType.Float16: - result = FromNativeTensor(name, ortValue); + result = FromNativeTensor(name, ref ortValue); break; case TensorElementType.BFloat16: - result = FromNativeTensor(name, ortValue); + result = FromNativeTensor(name, ref ortValue); break; default: - throw new NotSupportedException("Tensor of element type: " + elemType + " is not supported"); + throw new NotSupportedException($"Tensor of element type: {typeShape.ElementDataType} is not supported"); } return result; } + private static DisposableNamedOnnxValue FromNativeStringTensor(string name, int[] shape, ref OrtValue ortValue) + { + var dt = new DenseTensor(ortValue.GetStringTensorAsArray(), shape); + // still need to hold on to ortValue in case we need this for input handles + var result = new DisposableNamedOnnxValue(name, dt, TensorElementType.String, ortValue); + ortValue = null; + return result; + } + + /// /// This method creates an instance of DisposableNamedOnnxValue that has possession of ortValueElement - /// native memory Tensor and returns it to the caller. The original ortValueElement argument looses - /// ownership of the native ortValueElement handle, however, the caller is still responsible for disposing them - /// on exception. Disposing of OrtValue that has no ownership is a no-op and fine. + /// native memory Tensor and returns it to the caller. /// /// data type /// name of the output - /// native tensor + /// native tensor. Becomes null on successful return. /// DisposableNamedOnnxValue instance - private static DisposableNamedOnnxValue FromNativeTensor(string name, OrtValue ortValue) + private static DisposableNamedOnnxValue FromNativeTensor(string name, ref OrtValue ortValue) { - var ortValueTensor = new OrtValueTensor(ortValue); + Debug.Assert(typeof(T) != typeof(string), "Use FromNativeStringTensor for strings"); + var ortValueTensor = new OrtValueTensor(ref ortValue); try { - if (typeof(T) == typeof(string)) - { - var dt = new DenseTensor(ortValueTensor.GetBytesAsStringMemory(), ortValueTensor.Dimensions); - return new DisposableNamedOnnxValue(name, dt, ortValueTensor.ElementType, ortValueTensor); - } - else - { - DenseTensor dt = new DenseTensor(ortValueTensor.Memory, ortValueTensor.Dimensions); - return new DisposableNamedOnnxValue(name, dt, ortValueTensor.ElementType, ortValueTensor); - } + var dt = new DenseTensor(ortValueTensor.Memory, ortValueTensor.Dimensions); + return new DisposableNamedOnnxValue(name, dt, ortValueTensor.ElementType, ortValueTensor); } catch (Exception) { @@ -308,231 +324,216 @@ private static DisposableNamedOnnxValue FromNativeTensor(string name, OrtValu /// ortValueElement that has native sequence /// used allocator /// DisposableNamedOnnxValue - private static DisposableNamedOnnxValue FromNativeSequence(string name, OrtValue ortValueSequence, OrtAllocator allocator) + private static DisposableNamedOnnxValue FromNativeSequence(string name, ref OrtValue ortValueSequence, OrtAllocator allocator) { - DisposableNamedOnnxValue result = null; - IntPtr count; - NativeApiStatus.VerifySuccess(NativeMethods.OrtGetValueCount(ortValueSequence.Handle, out count)); - var sequence = new DisposableList(count.ToInt32()); + var valueCount = ortValueSequence.GetValueCount(); + var sequence = new DisposableList(valueCount); try { - for (int i = 0; i < count.ToInt32(); i++) + for (int i = 0; i < valueCount; i++) { - IntPtr nativeOnnxValueSeq; - NativeApiStatus.VerifySuccess(NativeMethods.OrtGetValue(ortValueSequence.Handle, i, allocator.Pointer, out nativeOnnxValueSeq)); - using (var ortValueElement = new OrtValue(nativeOnnxValueSeq)) + var ortValueElement = ortValueSequence.GetValue(i, allocator); + try { // Will take ownership or throw - sequence.Add(CreateFromOrtValue(string.Empty, ortValueElement, allocator)); + sequence.Add(CreateFromOrtValue(string.Empty, ref ortValueElement, allocator)); + } + finally + { + ortValueElement?.Dispose(); } } // NativeOrtValueCollectionOwner will take ownership of ortValueSequence and will make sure sequence // is also disposed. - var nativeCollectionManager = new NativeOrtValueCollectionOwner(ortValueSequence, sequence); - result = new DisposableNamedOnnxValue(name, sequence, OnnxValueType.ONNX_TYPE_SEQUENCE, nativeCollectionManager); + var nativeCollectionManager = new NativeOrtValueCollectionOwner(ref ortValueSequence, sequence); + return new DisposableNamedOnnxValue(name, sequence, OnnxValueType.ONNX_TYPE_SEQUENCE, nativeCollectionManager); } catch (Exception) { sequence.Dispose(); throw; } - return result; } /// /// Will extract keys and values from the map and create a DisposableNamedOnnxValue from it /// /// name of the output - /// ortValue that represents a map. - /// This function does not take ownership of the map as it we copy all keys an values into a dictionary. We let the caller dispose of it + /// ortValue that represents a map. Becomes null on success /// /// DisposableNamedOnnxValue - private static DisposableNamedOnnxValue FromNativeMap(string name, OrtValue ortValueMap, OrtAllocator allocator) + private static DisposableNamedOnnxValue FromNativeMap(string name, ref OrtValue ortValueMap, OrtAllocator allocator) { DisposableNamedOnnxValue result = null; - // Map processing is currently not recursing. It is assumed to contain + // Map processing is not recursive. It is assumed to contain // only primitive types and strings tensors. No sequences or maps. // The data is being copied to a dictionary and all ortValues are being disposed. // not mapped for client consumption. - using (var cleanUpList = new DisposableList()) + + // Keys in element 0, values in element 1 + Span valSpan = new OrtValue[2]; + var disposer = new DisposableArray(valSpan); + try { - IntPtr nativeOnnxValueMapKeys = IntPtr.Zero; - NativeApiStatus.VerifySuccess(NativeMethods.OrtGetValue(ortValueMap.Handle, 0, allocator.Pointer, out nativeOnnxValueMapKeys)); - var ortValueKeys = new OrtValue(nativeOnnxValueMapKeys); - cleanUpList.Add(ortValueKeys); - - var typeAndShape = IntPtr.Zero; - NativeApiStatus.VerifySuccess(NativeMethods.OrtGetTensorTypeAndShape(nativeOnnxValueMapKeys, out typeAndShape)); - TensorElementType keyElemType; - try - { - IntPtr el_type; - NativeApiStatus.VerifySuccess(NativeMethods.OrtGetTensorElementType(typeAndShape, out el_type)); - keyElemType = (TensorElementType)el_type; - } - finally - { - NativeMethods.OrtReleaseTensorTypeAndShapeInfo(typeAndShape); - } + valSpan[0] = ortValueMap.GetValue(0, allocator); + valSpan[1] = ortValueMap.GetValue(1, allocator); - IntPtr nativeOnnxValueMapValues = IntPtr.Zero; - NativeApiStatus.VerifySuccess(NativeMethods.OrtGetValue(ortValueMap.Handle, 1, allocator.Pointer, out nativeOnnxValueMapValues)); - var ortValueValues = new OrtValue(nativeOnnxValueMapValues); - cleanUpList.Add(ortValueValues); + var keysTypeShape = valSpan[0].GetTensorTypeAndShape(); + var valsTypeInfo = valSpan[1].GetTensorTypeAndShape(); - typeAndShape = IntPtr.Zero; - NativeApiStatus.VerifySuccess(NativeMethods.OrtGetTensorTypeAndShape(nativeOnnxValueMapValues, out typeAndShape)); - TensorElementType valueElemType; - try - { - IntPtr el_type; - NativeApiStatus.VerifySuccess(NativeMethods.OrtGetTensorElementType(typeAndShape, out el_type)); - valueElemType = (TensorElementType)el_type; - } - finally - { - NativeMethods.OrtReleaseTensorTypeAndShapeInfo(typeAndShape); - } + int[] intKeyShape = Array.ConvertAll(keysTypeShape.Shape, Convert.ToInt32); + int[] intValsShape = Array.ConvertAll(valsTypeInfo.Shape, Convert.ToInt32); // The supported combinations of key and value types are taken from the ORT C API. - switch (keyElemType) + switch (keysTypeShape.ElementDataType) { case TensorElementType.Int64: - switch (valueElemType) + switch (valsTypeInfo.ElementDataType) { case TensorElementType.Float: - result = FromNativeMapElements(name, ortValueMap, ortValueKeys, ortValueValues); + result = FromNativeMapElements(name, ref ortValueMap, + intKeyShape, ref valSpan[0], intValsShape, ref valSpan[1]); break; case TensorElementType.Double: - result = FromNativeMapElements(name, ortValueMap, ortValueKeys, ortValueValues); + result = FromNativeMapElements(name, ref ortValueMap, + intKeyShape, ref valSpan[0], intValsShape, ref valSpan[1]); break; case TensorElementType.Int64: - result = FromNativeMapElements(name, ortValueMap, ortValueKeys, ortValueValues); + result = FromNativeMapElements(name, ref ortValueMap, + intKeyShape, ref valSpan[0], intValsShape, ref valSpan[1]); break; case TensorElementType.String: - result = FromNativeMapElements(name, ortValueMap, ortValueKeys, ortValueValues); + result = FromNativeMapElements(name, ref ortValueMap, + intKeyShape, ref valSpan[0], intValsShape, ref valSpan[1]); break; default: - break; + throw new NotSupportedException($"Map value type: {valsTypeInfo.ElementDataType} is not supported"); } break; case TensorElementType.String: - switch (valueElemType) + switch (valsTypeInfo.ElementDataType) { case TensorElementType.Float: - result = FromNativeMapElements(name, ortValueMap, ortValueKeys, ortValueValues); + result = FromNativeMapElements(name, ref ortValueMap, + intKeyShape, ref valSpan[0], intValsShape, ref valSpan[1]); break; case TensorElementType.Double: - result = FromNativeMapElements(name, ortValueMap, ortValueKeys, ortValueValues); + result = FromNativeMapElements(name, ref ortValueMap, + intKeyShape, ref valSpan[0], intValsShape, ref valSpan[1]); break; case TensorElementType.Int64: - result = FromNativeMapElements(name, ortValueMap, ortValueKeys, ortValueValues); + result = FromNativeMapElements(name, ref ortValueMap, + intKeyShape, ref valSpan[0], intValsShape, ref valSpan[1]); break; case TensorElementType.String: - result = FromNativeMapElements(name, ortValueMap, ortValueKeys, ortValueValues); + result = FromNativeMapElements(name, ref ortValueMap, + intKeyShape, ref valSpan[0], intValsShape, ref valSpan[1]); break; default: - break; + throw new NotSupportedException($"Map value type: {valsTypeInfo.ElementDataType} is not supported"); } break; default: - throw new NotSupportedException("Map key type: " + keyElemType + " is not supported"); + throw new NotSupportedException($"Map key type: {keysTypeShape.ElementDataType} is not supported"); } } + finally + { + // Any values that are taken possession of + // will be null, others, like string tensors, will be disposed + disposer.Dispose(); + } + return result; } /// - /// This method maps keys and values of the map and copies them into a Dictionary - /// and returns as an instance of DisposableNamedOnnxValue that does not own or dispose - /// any onnx/ortValueElement. The method takes possession of ortValueTensorKeys and ortValueTensorValues - /// and disposes of them. The original ortValueElement looses ownership of the Tensor. The caller is still responsible - /// for disposing these arguments. Disposing ortValueElement that does not have ownership is a no-op, however, either - /// of the arguments may still need to be disposed on exception. + /// This method maps keys and values of the map and copies them into a managed Dictionary + /// and returns as an instance of DisposableNamedOnnxValue. The method takes possession of ortValueMap, + /// ortValueTensorKeys and ortValueTensorValues and disposes of them. /// - /// key type - /// value type - /// name of the output parameter - /// tensor with map keys. - /// tensor with map values - /// instance of DisposableNamedOnnxValue with Dictionary - private static DisposableNamedOnnxValue FromNativeMapElements(string name, OrtValue ortValueMap, - OrtValue ortValueTensorKeys, OrtValue ortValueTensorValues) + /// + /// + /// + /// becomes null on success return + /// keys shape in ints + /// becomes null on success + /// values shape in ints + /// becomes null on success + /// + private static DisposableNamedOnnxValue FromNativeMapElements(string name, ref OrtValue ortValueMap, + int[] keysShape, ref OrtValue ortValueTensorKeys, + int[] valsShape, ref OrtValue ortValueTensorValues) { - var listOfKeysValues = new DisposableList(); - var collOwner = new NativeOrtValueCollectionOwner(ortValueMap, listOfKeysValues); - try + if (typeof(K) == typeof(string)) { - var tensorKeys = new OrtValueTensor(ortValueTensorKeys); - listOfKeysValues.Add(ortValueTensorKeys); - var tensorValues = new OrtValueTensor(ortValueTensorValues); - listOfKeysValues.Add(ortValueTensorValues); + var denseTensorKeys = new DenseTensor(ortValueTensorKeys.GetStringTensorAsArray(), keysShape); - MapHelper mapHelper = null; - if (typeof(K) == typeof(string)) + if (typeof(V) == typeof(string)) { - var denseTensorKeys = new DenseTensor(tensorKeys.GetBytesAsStringMemory(), tensorKeys.Dimensions); - - if (typeof(V) == typeof(string)) + var denseTensorValues = new DenseTensor(ortValueTensorValues.GetStringTensorAsArray(), valsShape); + var map = Enumerable.Range(0, (int)denseTensorKeys.Length).ToDictionary(i => denseTensorKeys[i], i => denseTensorValues[i]); + var mapHelper = new MapHelper(denseTensorKeys, denseTensorValues); + var result = new DisposableNamedOnnxValue(name, map, mapHelper, ortValueMap); + ortValueMap = null; + return result; + } + else + { + var tensorValues = new OrtValueTensor(ref ortValueTensorValues); + try { - var map = new Dictionary(); - var denseTensorValues = new DenseTensor(tensorValues.GetBytesAsStringMemory(), tensorValues.Dimensions); - for (var i = 0; i < denseTensorKeys.Length; i++) - { - map.Add(denseTensorKeys.GetValue(i), denseTensorValues.GetValue(i)); - } - mapHelper = new MapHelper(denseTensorKeys, denseTensorValues); - return new DisposableNamedOnnxValue(name, map, mapHelper, collOwner); + var denseTensorValues = new DenseTensor(tensorValues.Memory, tensorValues.Dimensions); + return FromMapDenseTensors(name, ref ortValueMap, denseTensorKeys, denseTensorValues, tensorValues); } - else + catch (Exception) { - var map = new Dictionary(); - var denseTensorValues = new DenseTensor(tensorValues.Memory, tensorValues.Dimensions); - for (var i = 0; i < denseTensorKeys.Length; i++) - { - map.Add(denseTensorKeys.GetValue(i), denseTensorValues.GetValue(i)); - } - mapHelper = new MapHelper(denseTensorKeys, denseTensorValues); - return new DisposableNamedOnnxValue(name, map, mapHelper, collOwner); + tensorValues.Dispose(); + throw; } } - else + } + else + { + var disposer = new DisposableList(2); + try { + var tensorKeys = new OrtValueTensor(ref ortValueTensorKeys); + disposer.Add(tensorKeys); var denseTensorKeys = new DenseTensor(tensorKeys.Memory, tensorKeys.Dimensions); if (typeof(V) == typeof(string)) { - var map = new Dictionary(); - var denseTensorValues = new DenseTensor(tensorValues.GetBytesAsStringMemory(), tensorValues.Dimensions); - for (var i = 0; i < denseTensorKeys.Length; i++) - { - map.Add(denseTensorKeys.GetValue(i), denseTensorValues.GetValue(i)); - } - mapHelper = new MapHelper(denseTensorKeys, denseTensorValues); - return new DisposableNamedOnnxValue(name, map, mapHelper, collOwner); + var denseTensorValues = new DenseTensor(ortValueTensorValues.GetStringTensorAsArray(), valsShape); + return FromMapDenseTensors(name, ref ortValueMap, denseTensorKeys, denseTensorValues, disposer); } else { + var tensorValues = new OrtValueTensor(ref ortValueTensorValues); + disposer.Add(tensorValues); var denseTensorValues = new DenseTensor(tensorValues.Memory, tensorValues.Dimensions); - var map = new Dictionary(); - for (var i = 0; i < denseTensorKeys.Length; i++) - { - map.Add(denseTensorKeys.GetValue(i), denseTensorValues.GetValue(i)); - } - mapHelper = new MapHelper(denseTensorKeys, denseTensorValues); - return new DisposableNamedOnnxValue(name, map, mapHelper, collOwner); + return FromMapDenseTensors(name, ref ortValueMap, denseTensorKeys, denseTensorValues, disposer); } } - } - catch (Exception) - { - collOwner.Dispose(); - throw; + catch (Exception) + { + disposer.Dispose(); + throw; + } } } #region IDisposable Support + private static DisposableNamedOnnxValue FromMapDenseTensors(string name, ref OrtValue ortValueMap, + DenseTensor keys, DenseTensor values, IDisposable disposables) + { + var map = Enumerable.Range(0, (int)keys.Length).ToDictionary(i => keys[i], i => values[i]); + var mapHelper = new MapHelper(keys, values); + var collOwner = new NativeOrtValueCollectionOwner(ref ortValueMap, disposables); + return new DisposableNamedOnnxValue(name, map, mapHelper, collOwner); + } + /// /// IDisposable implementation /// diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/Exceptions.shared.cs b/csharp/src/Microsoft.ML.OnnxRuntime/Exceptions.shared.cs index f748ffe08035d..098a18b7444cf 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/Exceptions.shared.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/Exceptions.shared.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Text; namespace Microsoft.ML.OnnxRuntime { diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/FixedBufferOnnxValue.shared.cs b/csharp/src/Microsoft.ML.OnnxRuntime/FixedBufferOnnxValue.shared.cs index 1572d0fca96cf..3a29eea1bdae8 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/FixedBufferOnnxValue.shared.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/FixedBufferOnnxValue.shared.cs @@ -3,25 +3,26 @@ using Microsoft.ML.OnnxRuntime.Tensors; using System; -using System.Buffers; namespace Microsoft.ML.OnnxRuntime { /// + /// This is a legacy class that is kept for backward compatibility. + /// Use OrtValue based API. + /// /// Represents an OrtValue with its underlying buffer pinned /// public class FixedBufferOnnxValue : IDisposable { private bool _disposed = false; - internal MemoryHandle PinnedMemory { get; private set; } internal OrtValue Value { get; private set; } internal OnnxValueType OnnxValueType { get; private set; } internal TensorElementType ElementType { get; private set; } - private FixedBufferOnnxValue(MemoryHandle pinnedMemory, OrtValue ortValue, OnnxValueType onnxValueType, TensorElementType elementType) + private FixedBufferOnnxValue(ref OrtValue ortValue, OnnxValueType onnxValueType, TensorElementType elementType) { - PinnedMemory = pinnedMemory; Value = ortValue; + ortValue = null; OnnxValueType = onnxValueType; ElementType = elementType; } @@ -34,19 +35,8 @@ private FixedBufferOnnxValue(MemoryHandle pinnedMemory, OrtValue ortValue, OnnxV /// a disposable instance of FixedBufferOnnxValue public static FixedBufferOnnxValue CreateFromTensor(Tensor value) { - MemoryHandle? memHandle; - var ortValue = OrtValue.CreateFromTensorObject(value, out memHandle, out TensorElementType elementType); - // memHandle will have a value when CreateFromTensorObject() pins managed memory and that will have to be - /// disposed (unpinned) when all is said is done. This is the case for blittable types but does not - /// happen for string type where each element has its own allocation. - if (memHandle.HasValue) - { - return new FixedBufferOnnxValue((MemoryHandle)memHandle, ortValue, OnnxValueType.ONNX_TYPE_TENSOR, elementType); - } - else - { - return new FixedBufferOnnxValue(default(MemoryHandle), ortValue, OnnxValueType.ONNX_TYPE_TENSOR, elementType); - } + var ortValue = OrtValue.CreateFromTensorObject(value, out TensorElementType elementType); + return new FixedBufferOnnxValue(ref ortValue, OnnxValueType.ONNX_TYPE_TENSOR, elementType); } /// @@ -99,30 +89,21 @@ public static FixedBufferOnnxValue CreateFromTensor(Tensor value) /// \endcode /// public static FixedBufferOnnxValue CreateFromMemory(OrtMemoryInfo memoryInfo, Memory memory, - TensorElementType elementType, long[] shape, long bytesSize) + TensorElementType elementType, long[] shape, long bytesSize) where T : unmanaged { if(elementType == TensorElementType.String) { throw new ArgumentException("String data type is not supported"); } - var memHandle = memory.Pin(); + var ortValue = OrtValue.CreateTensorValueFromMemory(memoryInfo, memory, shape); try { - IntPtr memPtr; - unsafe - { - memPtr = (IntPtr)memHandle.Pointer; - } - var ortValue = OrtValue.CreateTensorValueWithData(memoryInfo, - elementType, - shape, - memPtr, bytesSize); - return new FixedBufferOnnxValue(memHandle, ortValue, OnnxValueType.ONNX_TYPE_TENSOR, elementType); + return new FixedBufferOnnxValue(ref ortValue, OnnxValueType.ONNX_TYPE_TENSOR, elementType); } catch (Exception) { - memHandle.Dispose(); + ortValue?.Dispose(); throw; } } @@ -143,7 +124,6 @@ protected virtual void Dispose(bool disposing) if (disposing) { Value.Dispose(); - PinnedMemory.Dispose(); } _disposed = true; } diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/InferenceSession.shared.cs b/csharp/src/Microsoft.ML.OnnxRuntime/InferenceSession.shared.cs index 0716822471f65..b21d036f61be9 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/InferenceSession.shared.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/InferenceSession.shared.cs @@ -1,14 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using Microsoft.ML.OnnxRuntime.Tensors; using System; -using System.Runtime.InteropServices; using System.Collections.Generic; -using System.IO; -using System.Linq; -using Microsoft.ML.OnnxRuntime.Tensors; -using System.Buffers; using System.Diagnostics; +using System.Linq; +using System.Net.NetworkInformation; +using System.Runtime.InteropServices; +using System.Threading.Tasks; namespace Microsoft.ML.OnnxRuntime { @@ -18,7 +18,7 @@ namespace Microsoft.ML.OnnxRuntime /// using either a explicit call to Dispose() method or /// a pattern of using() block. If this is a member of another /// class that class must also become IDisposable and it must - /// dispose of InferfenceSession in its Dispose() method. + /// dispose of InferenceSession in its Dispose() method. /// public class InferenceSession : IDisposable { @@ -247,14 +247,26 @@ public IDisposableReadOnlyCollection Run(IReadOnlyColl IReadOnlyCollection outputNames, RunOptions options) { - using (var cleanupList = new DisposableList()) - { - var inputNamesArray = LookupUtf8Names(inputs, v => v.Name, LookupInputMetadata); - var inputValuesArray = GetOrtValuesHandles(inputs, LookupInputMetadata, ExtractOrtValueForInput, cleanupList); - var outputNamesArray = LookupUtf8Names(outputNames, n => n, LookupOutputMetadata); + var inputNamesArray = LookupUtf8Names(inputs, v => v.Name, LookupInputMetadata); + var outputNamesArray = LookupUtf8Names(outputNames, n => n, LookupOutputMetadata); - var ortValues = RunImpl(options, inputNamesArray, inputValuesArray, outputNamesArray, cleanupList); - return CreateDisposableResult(ortValues, outputNames); + var inputValuesArray = GetOrtValuesHandles(inputs, LookupInputMetadata, + ExtractOrtValueHandleForInput, out DisposableArray inputsDisposer); + try + { + var outputsDisposer = RunImpl(options, inputNamesArray, inputValuesArray, outputNamesArray); + try + { + return CreateDisposableResult(outputsDisposer.Span, outputNames); + } + finally + { + outputsDisposer.Dispose(); + } + } + finally + { + inputsDisposer.Dispose(); } } @@ -305,15 +317,18 @@ public IDisposableReadOnlyCollection Run( throw new ArgumentException($"Length of {nameof(inputNames)} ({inputNames.Count}) must match that of {nameof(inputValues)} ({inputValues.Count})."); } - using (var cleanupList = new DisposableList()) - { - var inputNamesArray = LookupUtf8Names(inputNames, n => n, LookupInputMetadata); - IntPtr[] inputValuesArray = GetOrtValuesHandles(inputValues, true); - var outputNamesArray = LookupUtf8Names(outputNames, n => n, LookupOutputMetadata); - + var inputNamesArray = LookupUtf8Names(inputNames, n => n, LookupInputMetadata); + IntPtr[] inputValuesArray = GetOrtValuesHandles(inputValues, true); + var outputNamesArray = LookupUtf8Names(outputNames, n => n, LookupOutputMetadata); - var ortValues = RunImpl(options, inputNamesArray, inputValuesArray, outputNamesArray, cleanupList); - return CreateDisposableResult(ortValues, outputNames); + var disposableHandles = RunImpl(options, inputNamesArray, inputValuesArray, outputNamesArray); + try + { + return CreateDisposableResult(disposableHandles.Span, outputNames); + } + finally + { + disposableHandles.Dispose(); } } @@ -361,27 +376,24 @@ public void Run( throw new ArgumentException($"Length of {nameof(outputNames)} ({outputNames.Count}) must match that of {nameof(outputValues)} ({outputValues.Count})."); } - using (var cleanupList = new DisposableList()) - { - // prepare inputs - var inputNamesArray = LookupUtf8Names(inputNames, n => n, LookupInputMetadata); - IntPtr[] inputValuesArray = GetOrtValuesHandles(inputValues, true); + // prepare inputs + var inputNamesArray = LookupUtf8Names(inputNames, n => n, LookupInputMetadata); + IntPtr[] inputValuesArray = GetOrtValuesHandles(inputValues, true); - // prepare outputs - var outputNamesArray = LookupUtf8Names(outputNames, n => n, LookupOutputMetadata); - IntPtr[] outputValuesArray = GetOrtValuesHandles(outputValues, false); + // prepare outputs + var outputNamesArray = LookupUtf8Names(outputNames, n => n, LookupOutputMetadata); + IntPtr[] outputValuesArray = GetOrtValuesHandles(outputValues, false); - NativeApiStatus.VerifySuccess(NativeMethods.OrtRun( - _nativeHandle, - options.Handle, - inputNamesArray, - inputValuesArray, - (UIntPtr)inputNames.Count, - outputNamesArray, - (UIntPtr)outputNames.Count, - outputValuesArray /* pointers to Pre-allocated OrtValue instances */ - )); - } + NativeApiStatus.VerifySuccess(NativeMethods.OrtRun( + _nativeHandle, + options.Handle, + inputNamesArray, + inputValuesArray, + (UIntPtr)inputNames.Count, + outputNamesArray, + (UIntPtr)outputNames.Count, + outputValuesArray /* pointers to Pre-allocated OrtValue instances */ + )); } /// @@ -412,24 +424,38 @@ public void Run( IReadOnlyCollection outputs, RunOptions options) { - using (var cleanupList = new DisposableList()) - { - var inputNamesArray = LookupUtf8Names(inputs, i => i.Name, LookupInputMetadata); - var inputValuesArray = GetOrtValuesHandles(inputs, LookupInputMetadata, ExtractOrtValueForInput, cleanupList); + var inputNamesArray = LookupUtf8Names(inputs, i => i.Name, LookupInputMetadata); + var outputNamesArray = LookupUtf8Names(outputs, o => o.Name, LookupOutputMetadata); - var outputNamesArray = LookupUtf8Names(outputs, o => o.Name, LookupOutputMetadata); - var outputValuesArray = GetOrtValuesHandles(outputs, LookupOutputMetadata, ExtractOrtValueForOutput, cleanupList); + var inputValuesArray = GetOrtValuesHandles(inputs, LookupInputMetadata, ExtractOrtValueHandleForInput, + out DisposableArray inputDisposer); - NativeApiStatus.VerifySuccess(NativeMethods.OrtRun( - _nativeHandle, - options.Handle, - inputNamesArray, - inputValuesArray, - (UIntPtr)inputs.Count, - outputNamesArray, - (UIntPtr)outputs.Count, - outputValuesArray /* pointers to Pre-allocated OrtValue instances */ - )); + try + { + var outputValuesArray = GetOrtValuesHandles(outputs, LookupOutputMetadata, ExtractOrtValueHandleForOutput, + out DisposableArray outputDisposer); + + try + { + NativeApiStatus.VerifySuccess(NativeMethods.OrtRun( + _nativeHandle, + options.Handle, + inputNamesArray, + inputValuesArray, + (UIntPtr)inputs.Count, + outputNamesArray, + (UIntPtr)outputs.Count, + outputValuesArray /* pointers to Pre-allocated OrtValue instances */ + )); + } + finally + { + outputDisposer.Dispose(); + } + } + finally + { + inputDisposer.Dispose(); } } @@ -469,16 +495,15 @@ public void Run( throw new ArgumentException($"Length of {nameof(outputNames)} ({outputNames.Count}) must match that of {nameof(outputValues)} ({outputValues.Count})."); } - using (var cleanupList = new DisposableList()) - { - // prepare inputs - var inputNamesArray = LookupUtf8Names(inputs, i => i.Name, LookupInputMetadata); - var inputValuesArray = GetOrtValuesHandles(inputs, LookupInputMetadata, ExtractOrtValueForInput, cleanupList); + var inputNamesArray = LookupUtf8Names(inputs, i => i.Name, LookupInputMetadata); + var outputNamesArray = LookupUtf8Names(outputNames, n => n, LookupOutputMetadata); + var outputValuesArray = GetOrtValuesHandles(outputValues, false); - // prepare outputs - var outputNamesArray = LookupUtf8Names(outputNames, n => n, LookupOutputMetadata); - var outputValuesArray = GetOrtValuesHandles(outputValues, false); + var inputValuesArray = GetOrtValuesHandles(inputs, LookupInputMetadata, ExtractOrtValueHandleForInput, + out DisposableArray inputsDisposer); + try + { NativeApiStatus.VerifySuccess(NativeMethods.OrtRun( _nativeHandle, options.Handle, @@ -490,6 +515,10 @@ public void Run( outputValuesArray /* pointers to Pre-allocated OrtValue instances */ )); } + finally + { + inputsDisposer.Dispose(); + } } /// @@ -530,16 +559,17 @@ public void Run( throw new ArgumentException($"Length of {nameof(inputNames)} ({inputNames.Count}) must match that of {nameof(inputValues)} ({inputValues.Count})."); } - using (var cleanupList = new DisposableList()) - { - // prepare inputs - var inputNamesArray = LookupUtf8Names(inputNames, n => n, LookupInputMetadata); - var inputValuesArray = GetOrtValuesHandles(inputValues, true); + // prepare inputs + var inputNamesArray = LookupUtf8Names(inputNames, n => n, LookupInputMetadata); + var inputValuesArray = GetOrtValuesHandles(inputValues, true); - // prepare outputs - var outputNamesArray = LookupUtf8Names(outputs, o => o.Name, LookupOutputMetadata); - var outputValuesArray = GetOrtValuesHandles(outputs, LookupOutputMetadata, ExtractOrtValueForOutput, cleanupList); + // prepare outputs + var outputNamesArray = LookupUtf8Names(outputs, o => o.Name, LookupOutputMetadata); + var outputValuesArray = GetOrtValuesHandles(outputs, LookupOutputMetadata, ExtractOrtValueHandleForOutput, + out DisposableArray outputsDisposer); + try + { NativeApiStatus.VerifySuccess(NativeMethods.OrtRun( _nativeHandle, options.Handle, @@ -551,6 +581,155 @@ public void Run( outputValuesArray /* pointers to Pre-allocated OrtValue instances */ )); } + finally + { + outputsDisposer.Dispose(); + } + } + + /// + /// The API runs the inference taking a collection of OrtValues as input and + /// returning a collection of output OrtValues. + /// + /// runOptions + /// A collection of input names. + /// To supply all names, use InputNames property + /// Input OrtValues. The size of the collection must match the size and the order of the inputNames + /// Output names requested. To supply all names, use OutputNames property. + /// A disposable collection of disposable OrtValues + /// + public IDisposableReadOnlyCollection Run(RunOptions runOptions, IReadOnlyCollection inputNames, + IReadOnlyCollection inputValues, IReadOnlyCollection outputNames) + { + if (inputNames.Count != inputValues.Count) + { + throw new ArgumentException($"Length of {nameof(inputNames)} ({inputNames.Count}) must match that of {nameof(inputValues)} ({inputValues.Count})."); + } + + var inputNamesArray = LookupUtf8Names(inputNames, n => n, LookupInputMetadata); + var inputHandlesArray = inputValues.Select(v => v.Handle).ToArray(); + + var outputNamesArray = LookupUtf8Names(outputNames, n => n, LookupOutputMetadata); + + var disposableHandles = RunImpl(runOptions, inputNamesArray, inputHandlesArray, outputNamesArray); + try + { + return CreateDisposableResult(disposableHandles); + } + finally + { + disposableHandles.Dispose(); + } + } + + /// + /// This API takes inputs as a dictionary of input names paired with input OrtValues + /// + /// It returns a disposable collection of OrtValues for outputs that were designated by outputNames + /// + /// + /// Dictionary of name/value pairs + /// requested outputs. To request all outputs, use OutputNames property of this sessions + /// A disposable collection of outputs + public IDisposableReadOnlyCollection Run(RunOptions runOptions, IReadOnlyDictionary inputs, + IReadOnlyCollection outputNames) + { + IntPtr[] inputNamesArray = new IntPtr[inputs.Count]; + IntPtr[] inputHandlesArray = new IntPtr[inputs.Count]; + + int count = 0; + foreach (var input in inputs) + { + inputNamesArray[count] = LookupInputMetadata(input.Key).ZeroTerminatedName; + inputHandlesArray[count] = input.Value.Handle; + ++count; + } + + var outputNamesArray = LookupUtf8Names(outputNames, n => n, LookupOutputMetadata); + var disposableHandles = RunImpl(runOptions, inputNamesArray, inputHandlesArray, outputNamesArray); + try + { + return CreateDisposableResult(disposableHandles); + } + finally + { + disposableHandles.Dispose(); + } + } + + private static IDisposableReadOnlyCollection CreateDisposableResult(DisposableOrtValueHandleArray disposableHandles) + { + var outputValues = new DisposableList(disposableHandles.Span.Length); + try + { + for (int i = 0; i < disposableHandles.Span.Length; i++) + { + outputValues.Add(new OrtValue(disposableHandles.Span[i])); + disposableHandles.Span[i] = IntPtr.Zero; + } + return outputValues; + } + catch (Exception) + { + outputValues.Dispose(); + throw; + } + } + + /// + /// The API takes collections of inputNames/inputValues and collections of outputNames/outputValues. + /// The sizes of the corresponding collections must match. + /// + /// The output OrtValues are pre-allocated and the API will fill the data into the OrtValues. + /// These MUST be tensors. The API does not support non-tensor types for output values. + /// + /// The API is useful when the output values are tensors and their shapes are known, and you + /// prefer the output to go to the pre-allocated memory. In such a case, you create + /// output OrtValues over those pre-allocated buffers and pass them to the API. + /// + /// runOptions, if null the defaults are used + /// collection of input names. + /// collection of input OrtValues. Must match the order and the number of input names. + /// Requested output names. + /// Pre-allocated output values. + /// The order and the number must match the specified output names. Shapes must match actual output values. + /// + public void Run(RunOptions runOptions, IReadOnlyCollection inputNames, IReadOnlyCollection inputValues, + IReadOnlyCollection outputNames, IReadOnlyCollection outputValues) + { + if (inputNames.Count != inputValues.Count) + { + throw new ArgumentException( + $"Length of {nameof(inputNames)} ({inputNames.Count}) must match that of {nameof(inputValues)} ({inputValues.Count})."); + } + + if (outputNames.Count != outputValues.Count) + { + throw new ArgumentException( + $"Length of {nameof(outputNames)} ({outputNames.Count}) must match that of {nameof(outputValues)} ({outputValues.Count})."); + } + + if (runOptions is null) + { + runOptions = _builtInRunOptions; + } + + var inputNamesArray = LookupUtf8Names(inputNames, n => n, LookupInputMetadata); + var inputHandlesArray = inputValues.Select(v => v.Handle).ToArray(); + + var outputNamesArray = LookupUtf8Names(outputNames, n => n, LookupOutputMetadata); + var outputHandlesArray = outputValues.Select(v => v.Handle).ToArray(); + + NativeApiStatus.VerifySuccess(NativeMethods.OrtRun( + _nativeHandle, + runOptions.Handle, + inputNamesArray, + inputHandlesArray, + (UIntPtr)inputNames.Count, + outputNamesArray, + (UIntPtr)outputNames.Count, + outputHandlesArray /* pointers to Pre-allocated OrtValue instances */ + )); } /// @@ -578,10 +757,27 @@ public void RunWithBinding(RunOptions runOptions, OrtIoBinding ioBinding) NativeApiStatus.VerifySuccess(NativeMethods.OrtRunWithBinding(Handle, runOptions.Handle, ioBinding.Handle)); } + /// + /// This method runs inference on the OrtIoBinding instance. It returns a collection of OrtValues. + /// This method is useful when it is impossible to bind outputs to pre-allocated buffers, because + /// the output shape is not known in advance. In this case, the OrtValues returned by this method + /// are allocated and owned by ORT. The caller is responsible for disposing the collection. + /// + /// RunOptions + /// Binding instance + /// A disposable collection of OrtValues + public IDisposableReadOnlyCollection RunWithBoundResults(RunOptions runOptions, OrtIoBinding ioBinding) + { + NativeApiStatus.VerifySuccess(NativeMethods.OrtRunWithBinding(Handle, runOptions.Handle, ioBinding.Handle)); + return ioBinding.GetOutputValues(); + } + /// /// This method return a collection of DisposableNamedOnnxValue as in other interfaces /// Query names from OrtIoBinding object and pair then with the array of OrtValues returned - /// from OrtIoBinding.GetOutputValues() + /// from OrtIoBinding.GetOutputValues(). + /// + /// This API will be deprecated in favor of the API that returns a collection of OrtValues. /// /// /// RunOptions @@ -593,37 +789,38 @@ public void RunWithBinding(RunOptions runOptions, OrtIoBinding ioBinding) /// A disposable collection of DisposableNamedOnnxValue that encapsulate output OrtValues public IDisposableReadOnlyCollection RunWithBindingAndNames(RunOptions runOptions, OrtIoBinding ioBinding, string[] names = null) { - NativeApiStatus.VerifySuccess(NativeMethods.OrtRunWithBinding(Handle, runOptions.Handle, ioBinding.Handle)); - using (var ortValues = ioBinding.GetOutputValues()) + string[] outputNames = names; + if (outputNames == null || names.Length == 0) { - string[] outputNames = names; - if (outputNames == null) - { - outputNames = ioBinding.GetOutputNames(); - } - - if (outputNames.Length != ortValues.Count) - { - throw new OnnxRuntimeException(ErrorCode.InvalidArgument, - "Number of specified names: " + names.Length + " does not match the output number: " + - ortValues.Count); - } + outputNames = ioBinding.GetOutputNames(); + } - var result = new DisposableList(outputNames.Length); + NativeApiStatus.VerifySuccess(NativeMethods.OrtRunWithBinding(Handle, runOptions.Handle, ioBinding.Handle)); + var ortValues = ioBinding.GetOutputOrtValues(); + var dispValues = new DisposableArray(ortValues); + try + { + var result = new DisposableList(ortValues.Length); try { for (int i = 0; i < outputNames.Length; ++i) { - var ortValue = ortValues.ElementAt(i); - result.Add(DisposableNamedOnnxValue.CreateFromOrtValue(outputNames[i], ortValue)); + result.Add(DisposableNamedOnnxValue.CreateFromOrtValue(outputNames[i], ref ortValues[i])); } + return result; } catch (Exception) { result.Dispose(); throw; } - return result; + } + finally + { + // On success ortValues would contain nulls that will be + // ignored. On failure, ortValues would contain at least + // some valid OrtValue instances that need to be disposed. + dispValues.Dispose(); } } @@ -644,7 +841,7 @@ public string EndProfiling() private delegate string NameExtractor(TInput input); // delegate to fetch input/output OrtValue - private delegate OrtValue OrtValueExtractor(NamedOnnxValue value, NodeMetadata metadata, out IDisposable memOwner); + private delegate IntPtr OrtValueHandleExtractor(NamedOnnxValue value, NodeMetadata metadata, out IDisposable memOwner); // Delegate to lookup metadata for input/initializers/output private delegate NodeMetadata MetadataLookup(string nodeName); @@ -659,8 +856,7 @@ public string EndProfiling() /// private NodeMetadata LookupInputMetadata(string nodeName) { - NodeMetadata meta; - if (!_inputMetadata.TryGetValue(nodeName, out meta) && + if (!_inputMetadata.TryGetValue(nodeName, out NodeMetadata meta) && !_overridableInitializerMetadata.TryGetValue(nodeName, out meta)) { throw new OnnxRuntimeException(ErrorCode.InvalidArgument, $"Input name: '{nodeName}' is not in the metadata"); @@ -676,8 +872,7 @@ private NodeMetadata LookupInputMetadata(string nodeName) /// private NodeMetadata LookupOutputMetadata(string nodeName) { - NodeMetadata meta; - if (!_outputMetadata.TryGetValue(nodeName, out meta)) + if (!_outputMetadata.TryGetValue(nodeName, out NodeMetadata meta)) { throw new OnnxRuntimeException(ErrorCode.InvalidArgument, $"Output name: '{nodeName}' is not in the metadata"); } @@ -691,9 +886,9 @@ private NodeMetadata LookupOutputMetadata(string nodeName) /// /// /// - private static OrtValue ExtractOrtValueForInput(NamedOnnxValue input, NodeMetadata metadata, out IDisposable memOwner) + private static IntPtr ExtractOrtValueHandleForInput(NamedOnnxValue input, NodeMetadata metadata, out IDisposable memOwner) { - return input.InputToOrtValue(metadata, out memOwner); + return input.InputToOrtValueHandle(metadata, out memOwner); } /// @@ -703,9 +898,9 @@ private static OrtValue ExtractOrtValueForInput(NamedOnnxValue input, NodeMetada /// /// /// May return null if the onnx value type does not support pre-creation of output OrtValues - private static OrtValue ExtractOrtValueForOutput(NamedOnnxValue output, NodeMetadata metadata, out IDisposable memOwner) + private static IntPtr ExtractOrtValueHandleForOutput(NamedOnnxValue output, NodeMetadata metadata, out IDisposable memOwner) { - return output.OutputToOrtValue(metadata, out memOwner); + return output.OutputToOrtValueHandle(metadata, out memOwner); } /// @@ -714,9 +909,8 @@ private static OrtValue ExtractOrtValueForOutput(NamedOnnxValue output, NodeMeta /// names to convert to zero terminated utf8 and pin /// extractor functor that helps extracting names from inputs /// inputs/outputs metadata - /// list to add pinned memory to for later disposal /// - private IntPtr[] LookupUtf8Names(IReadOnlyCollection values, NameExtractor nameExtractor, + private static IntPtr[] LookupUtf8Names(IReadOnlyCollection values, NameExtractor nameExtractor, MetadataLookup metaLookup) { var result = new IntPtr[values.Count]; @@ -738,37 +932,36 @@ private IntPtr[] LookupUtf8Names(IReadOnlyCollection values, NameExtractor /// /// a collection of NamedOnnxValues /// Metadata lookup function (input/initializers/output) - /// list to cleanup in an exception safe manner /// - private IntPtr[] GetOrtValuesHandles(IReadOnlyCollection values, MetadataLookup metaLookup, - OrtValueExtractor ortValueExtractor, - DisposableList cleanupList) - { - cleanupList.Capacity += values.Count * 2; - IntPtr[] result = new IntPtr[values.Count]; - for (int valueIndex = 0; valueIndex < values.Count; ++valueIndex) - { - var value = values.ElementAt(valueIndex); - var meta = metaLookup(value.Name); - var ortValue = ortValueExtractor(value, meta, out IDisposable memHolder); - if (memHolder != null) - { - cleanupList.Add(memHolder); - } - if (ortValue != null) - { - cleanupList.Add(ortValue); - result[valueIndex] = ortValue.Handle; - } - else + private static IntPtr[] GetOrtValuesHandles(IReadOnlyCollection values, MetadataLookup metaLookup, + OrtValueHandleExtractor ortValueExtractor, out DisposableArray disposer) + { + IDisposable[] memHolders = new IDisposable[values.Count]; + var disp = new DisposableArray(memHolders); + try + { + IntPtr[] result = new IntPtr[values.Count]; + for (int valueIndex = 0; valueIndex < values.Count; ++valueIndex) { - result[valueIndex] = IntPtr.Zero; + var value = values.ElementAt(valueIndex); + var meta = metaLookup(value.Name); + result[valueIndex] = ortValueExtractor(value, meta, out IDisposable memHolder); + if (memHolder != null) + { + memHolders[valueIndex] = memHolder; + } } + disposer = disp; + return result; + } + catch (Exception) + { + disp.Dispose(); + throw; } - return result; } - private IntPtr[] GetOrtValuesHandles(IReadOnlyCollection values, bool input) + private static IntPtr[] GetOrtValuesHandles(IReadOnlyCollection values, bool input) { var valuesArray = new IntPtr[values.Count]; for (int index = 0; index < values.Count; ++index) @@ -783,14 +976,8 @@ private IntPtr[] GetOrtValuesHandles(IReadOnlyCollection v return valuesArray; } - - private DisposableList RunImpl(RunOptions options, IntPtr[] inputNames, IntPtr[] inputValues, IntPtr[] outputNames, - DisposableList cleanupList) + private DisposableOrtValueHandleArray RunImpl(RunOptions options, IntPtr[] inputNames, IntPtr[] inputValues, IntPtr[] outputNames) { - cleanupList.Capacity += 1; - var ortValues = new DisposableList(outputNames.Length + 1); - cleanupList.Add(ortValues); - IntPtr[] outputValuesArray = new IntPtr[outputNames.Length]; NativeApiStatus.VerifySuccess(NativeMethods.OrtRun( _nativeHandle, @@ -802,23 +989,21 @@ private DisposableList RunImpl(RunOptions options, IntPtr[] inputNames (UIntPtr)outputNames.Length, outputValuesArray /* Empty array is passed in to receive output OrtValue pointers */ )); - - foreach (var v in outputValuesArray) - { - ortValues.Add(new OrtValue(v)); - } - return ortValues; + return new DisposableOrtValueHandleArray(outputValuesArray); } - IDisposableReadOnlyCollection CreateDisposableResult(List ortValues, + private static IDisposableReadOnlyCollection CreateDisposableResult(Span valueHandles, IReadOnlyCollection outputNames) { - var result = new DisposableList(outputNames.Count); + Debug.Assert(valueHandles.Length == outputNames.Count, "Handles and names sizes must match"); + var result = new DisposableList(valueHandles.Length); try { - for (int i = 0; i < ortValues.Count; i++) + for (int i = 0; i < valueHandles.Length; i++) { - result.Add(DisposableNamedOnnxValue.CreateFromOrtValue(outputNames.ElementAt(i), ortValues[i])); + var ortValue = new OrtValue(valueHandles[i]); + result.Add(DisposableNamedOnnxValue.CreateFromOrtValue(outputNames.ElementAt(i), ref ortValue)); + valueHandles[i] = IntPtr.Zero; // Prevent double disposal } } catch (OnnxRuntimeException) @@ -861,6 +1046,131 @@ public ulong ProfilingStartTimeNs } } + private static void OrtCallback(IntPtr userData, IntPtr[] ouputs, uint numOutputs, IntPtr status) + { + var hostHdl = GCHandle.FromIntPtr(userData); + CallbackHost host = (CallbackHost)hostHdl.Target; + try + { + host.callback(host.outputValues, status); + } + finally + { + hostHdl.Free(); + } + } + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate void OrtCallbackDelegate(IntPtr userData, IntPtr[] outputs, uint numOutputs, IntPtr status); + + private static OrtCallbackDelegate ortCallback = new OrtCallbackDelegate(OrtCallback); + + private delegate void UserCallbackDelegate(IReadOnlyCollection outputs, IntPtr status); + + private class CallbackHost + { + public IReadOnlyCollection inputNames { get; } + public IReadOnlyCollection inputValues { get; } + public IReadOnlyCollection outputNames { get; } + public IReadOnlyCollection outputValues { get; } + public UserCallbackDelegate callback { get; } + + public IntPtr[] rawInputNames { get; } + public IntPtr[] rawInputValues { get; } + public IntPtr[] rawOutputNames { get; } + public IntPtr[] rawOutputValues { get; } + + public CallbackHost(InferenceSession session, + IReadOnlyCollection cbInputNames, + IReadOnlyCollection cbinputValues, + IReadOnlyCollection cbOutputNames, + IReadOnlyCollection cbOutputValues, + UserCallbackDelegate userCallback) + { + + inputNames = cbInputNames; + inputValues = cbinputValues; + outputNames = cbOutputNames; + outputValues = cbOutputValues; + callback = userCallback; + + rawInputNames = LookupUtf8Names(inputNames, n => n, session.LookupInputMetadata); + rawInputValues = inputValues.Select(v => v.Handle).ToArray(); + + rawOutputNames = LookupUtf8Names(outputNames, n => n, session.LookupOutputMetadata); + rawOutputValues = outputValues.Select(v => v.Handle).ToArray(); + } + } + + private void RunAsyncInternal(RunOptions options, + IReadOnlyCollection inputNames, + IReadOnlyCollection inputValues, + IReadOnlyCollection outputNames, + IReadOnlyCollection outputValues, + UserCallbackDelegate callback) + { + CallbackHost host = new CallbackHost(this, inputNames, inputValues, outputNames, outputValues, callback); + var host_hdl = GCHandle.Alloc(host, GCHandleType.Normal); + + try + { + NativeApiStatus.VerifySuccess(NativeMethods.OrtRunAsync( + _nativeHandle, + options == null ? (IntPtr)null : options.Handle, + host.rawInputNames, + host.rawInputValues, + (UIntPtr)host.rawInputNames.Length, + host.rawOutputNames, + (UIntPtr)host.rawOutputNames.Length, + host.rawOutputValues, + Marshal.GetFunctionPointerForDelegate(ortCallback), + GCHandle.ToIntPtr(host_hdl) + )); + } + catch (OnnxRuntimeException) + { + host_hdl.Free(); + throw; + } + } + + /// + /// Run inference asynchronous in a thread of intra-op thread pool + /// + /// run option, can be null + /// name of inputs + /// input ort values + /// name of outputs + /// output of ort values + /// task to be awaited + /// + public async Task> RunAsync(RunOptions options, + IReadOnlyCollection inputNames, + IReadOnlyCollection inputValues, + IReadOnlyCollection outputNames, + IReadOnlyCollection outputValues) + { + var promise = new TaskCompletionSource>(); + RunAsyncInternal(options, + inputNames, + inputValues, + outputNames, + outputValues, + (IReadOnlyCollection outputs, IntPtr status) => + { + try + { + NativeApiStatus.VerifySuccess(status); + promise.SetResult(outputs); + } + catch (Exception ex) + { + promise.SetException(ex); + } + }); + return await promise.Task; + } + #endregion #region private methods @@ -1650,18 +1960,23 @@ internal ModelMetadata(InferenceSession session) // The OrtAllocator will finally free the customMetadataMapKeysHandle try { + Span keysHandles; + unsafe + { + keysHandles = new Span(customMetadataMapKeysHandle.ToPointer(), (int)numKeys); + } + using (var ortAllocationKeys = new DisposableList((int)numKeys)) { // Put all the handles to each key in the DisposableList to be disposed off in an exception-safe manner - for (int i = 0; i < (int)numKeys; ++i) + foreach (var keyHandle in keysHandles) { - ortAllocationKeys.Add(new OrtMemoryAllocation(allocator, Marshal.ReadIntPtr(customMetadataMapKeysHandle, IntPtr.Size * i), 0)); + ortAllocationKeys.Add(new OrtMemoryAllocation(allocator, keyHandle, 0)); } // Process each key via the stored key handles - foreach (var allocation in ortAllocationKeys) + foreach (var keyHandle in keysHandles) { - IntPtr keyHandle = allocation.Pointer; NativeApiStatus.VerifySuccess(NativeMethods.OrtModelMetadataLookupCustomMetadataMap(modelMetadataHandle, allocator.Pointer, keyHandle, out IntPtr valueHandle)); @@ -1672,7 +1987,10 @@ internal ModelMetadata(InferenceSession session) } } } - finally { allocator.FreeMemory(customMetadataMapKeysHandle); } + finally + { + allocator.FreeMemory(customMetadataMapKeysHandle); + } } finally { diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/ManagedProjections.shared.cs b/csharp/src/Microsoft.ML.OnnxRuntime/ManagedProjections.shared.cs index 664ba21cfd1bb..e512a8c2612ae 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/ManagedProjections.shared.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/ManagedProjections.shared.cs @@ -3,7 +3,6 @@ using Microsoft.ML.OnnxRuntime.Tensors; using System; -using System.Buffers; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -19,48 +18,15 @@ namespace Microsoft.ML.OnnxRuntime /// For example, a sequence instance would contain a list of NamedOnnxValue instances /// that in turn may represent tensors or other ONNX values. /// - internal class ManagedTypeProjection : IDisposable + internal class ManagedTypeProjection { - readonly DisposableList _disposables; - readonly OrtValue _ortValue; - bool _disposed = false; - - /// - /// Provides access to non-owning instance of OrtValue - /// - /// Provides access to the OrtValue to be used as input - internal OrtValue Value { get { return new OrtValue(_ortValue.Handle, false); } } - - /// - /// Constructor to create an input OrtValue projection from managed data - /// - /// - /// - /// - internal ManagedTypeProjection(NamedOnnxValue namedOnnxValue, NodeMetadata metadata) - { - int requiredCapacity = 32; - var disposables = new DisposableList(requiredCapacity); - try - { - _ortValue = CreateDispatchProjection(namedOnnxValue, metadata, disposables); - } - catch (Exception) - { - disposables.Dispose(); - throw; - } - _disposables = disposables; - } - /// /// Dispatches the creation of the projection /// /// /// - /// - /// - private OrtValue CreateDispatchProjection(NamedOnnxValue namedOnnxValue, NodeMetadata metadata, DisposableList disposables) + /// OrtValye created accoding to the metadata + internal static OrtValue CreateProjection(NamedOnnxValue namedOnnxValue, NodeMetadata metadata) { OrtValue result; @@ -81,13 +47,13 @@ private OrtValue CreateDispatchProjection(NamedOnnxValue namedOnnxValue, NodeMet switch (namedOnnxValue.ValueType) { case OnnxValueType.ONNX_TYPE_TENSOR: - result = CreateTensorProjection(namedOnnxValue, meta, disposables); + result = CreateTensorProjection(namedOnnxValue, meta); break; case OnnxValueType.ONNX_TYPE_SEQUENCE: - result = CreateSequenceProjection(namedOnnxValue, meta, disposables); + result = CreateSequenceProjection(namedOnnxValue, meta); break; case OnnxValueType.ONNX_TYPE_MAP: - result = CreateMapProjection(namedOnnxValue, meta, disposables); + result = CreateMapProjection(namedOnnxValue, meta); break; default: throw new OnnxRuntimeException(ErrorCode.InvalidArgument, "ManagedTypeProjection can only project tensors, sequences, maps and optional types"); @@ -99,56 +65,44 @@ private OrtValue CreateDispatchProjection(NamedOnnxValue namedOnnxValue, NodeMet /// The function creates OrtValue objects for each element of the sequence /// and then creates an OrtValue for the whole sequence. /// - /// NamedOnnxValue containing a IEnumeralbe + /// NamedOnnxValue containing a IEnumerable /// sequence metadata - /// cleanup list - /// + /// OrtValue that represents a sequence /// - private OrtValue CreateSequenceProjection(NamedOnnxValue namedOnnxValue, NodeMetadata metadata, DisposableList disposables) + private static OrtValue CreateSequenceProjection(NamedOnnxValue namedOnnxValue, NodeMetadata metadata) { - OrtValue result = null; var elementMeta = metadata.AsSequenceMetadata().ElementMeta; var elementOnnxValue = elementMeta.OnnxValueType; - var seqContainer = namedOnnxValue.AsEnumerable(); - - if (seqContainer is null) - { + var seqContainer = namedOnnxValue.AsEnumerable() ?? throw new OnnxRuntimeException(ErrorCode.InvalidArgument, $"NamedOnnxValue: {namedOnnxValue.Name} sequence does not contain NamedOnnxValue elements"); - } - int capacity = 0; - if (seqContainer is ICollection) + if (seqContainer is ICollection collection) { - capacity = ((ICollection)seqContainer).Count; + capacity = collection.Count; } - // Record all the ortValues belonging to the sequence locally - var sequenceOrtValues = new List(capacity); - foreach (var element in seqContainer) + DisposableList sequenceOrtValues = new(capacity); + try { - if (elementOnnxValue != element.ValueType) + foreach (var element in seqContainer) { - throw new OnnxRuntimeException(ErrorCode.InvalidArgument, - $"NamedOnnxValue: {namedOnnxValue.Name} sequence element expected to be {elementOnnxValue}, received {element.ValueType}"); - } + if (elementOnnxValue != element.ValueType) + { + throw new OnnxRuntimeException(ErrorCode.InvalidArgument, + $"NamedOnnxValue: {namedOnnxValue.Name} sequence element expected to be {elementOnnxValue}, received {element.ValueType}"); + } - sequenceOrtValues.Add(CreateDispatchProjection(element, elementMeta, disposables)); + sequenceOrtValues.Add(CreateProjection(element, elementMeta)); + } + return OrtValue.CreateSequence(ref sequenceOrtValues); } - - IntPtr[] ortValHandles = new IntPtr[sequenceOrtValues.Count]; - for (int i = 0; i < sequenceOrtValues.Count; i++) + catch(Exception) { - ortValHandles[i] = sequenceOrtValues[i].Handle; + sequenceOrtValues?.Dispose(); + throw; } - - NativeApiStatus.VerifySuccess(NativeMethods.OrtCreateValue(ortValHandles, - (UIntPtr)sequenceOrtValues.Count, (IntPtr)OnnxValueType.ONNX_TYPE_SEQUENCE, out IntPtr sequenceHandle)); - result = new OrtValue(sequenceHandle); - disposables.Add(result); - - return result; } /// @@ -157,13 +111,11 @@ private OrtValue CreateSequenceProjection(NamedOnnxValue namedOnnxValue, NodeMet /// /// /// - /// /// OrtValue /// - private OrtValue CreateMapProjection(NamedOnnxValue node, NodeMetadata elementMeta, DisposableList disposables) + private static OrtValue CreateMapProjection(NamedOnnxValue node, NodeMetadata elementMeta) { - OrtValue result = null; - var mapMeta = elementMeta.AsMapMetadata(); + MapMetadata mapMeta = elementMeta.AsMapMetadata(); Debug.Assert(mapMeta != null); // Maps currently support only primitive types expressed as two parallel tensors and not nested Sequences or Maps @@ -174,104 +126,69 @@ private OrtValue CreateMapProjection(NamedOnnxValue node, NodeMetadata elementMe $"Node: {node.Name} onnxruntime only supports maps with primitive types values"); } - - var keys = node.GetDictionaryKeys(); - var ortValueKeys = OrtValue.CreateFromTensorObject(keys, - out MemoryHandle? memoryHandleKeys, out TensorElementType elementTypeKeys); - disposables.Add(ortValueKeys); - - if (memoryHandleKeys.HasValue) + Span ortValues = new OrtValue[2]; + var disposableGuard = new DisposableArray(ortValues); + try { - disposables.Add(memoryHandleKeys); - } + TensorBase keys = node.GetDictionaryKeys(); + ortValues[0] = OrtValue.CreateFromTensorObject(keys, out TensorElementType elementTypeKeys); - if (elementTypeKeys != mapMeta.KeyDataType) - { - throw new OnnxRuntimeException(ErrorCode.InvalidArgument, - $"Map key data type supplied: {elementTypeKeys} metadata expected: {mapMeta.KeyDataType}"); - } + if (elementTypeKeys != mapMeta.KeyDataType) + { + throw new OnnxRuntimeException(ErrorCode.InvalidArgument, + $"Map key data type supplied: {elementTypeKeys} metadata expected: {mapMeta.KeyDataType}"); + } - var values = node.GetDictionaryValues(); - var ortValueValues = OrtValue.CreateFromTensorObject(values, - out MemoryHandle? memoryHandleValues, out TensorElementType elementTypeValues); + TensorBase values = node.GetDictionaryValues(); + ortValues[1] = OrtValue.CreateFromTensorObject(values, out TensorElementType elementTypeValues); + if (elementTypeValues != mapValuesMeta.ElementDataType) + { + throw new OnnxRuntimeException(ErrorCode.InvalidArgument, + $"Map value data type supplied: {elementTypeValues} metadata expected: {mapValuesMeta.ElementDataType}"); + } - disposables.Add(ortValueValues); - if (memoryHandleValues.HasValue) - { - disposables.Add(memoryHandleValues); + // Create Map OrtValue + return OrtValue.CreateMap(ref ortValues[0], ref ortValues[1]); } - - if (elementTypeValues != mapValuesMeta.ElementDataType) + catch (Exception) { - throw new OnnxRuntimeException(ErrorCode.InvalidArgument, - $"Map value data type supplied: {elementTypeValues} metadata expected: {mapValuesMeta.ElementDataType}"); + disposableGuard.Dispose(); + throw; } - - // Create Map OrtValue - IntPtr[] ortValHandles = { ortValueKeys.Handle, ortValueValues.Handle }; - NativeApiStatus.VerifySuccess(NativeMethods.OrtCreateValue(ortValHandles, (UIntPtr)2, - (IntPtr)OnnxValueType.ONNX_TYPE_MAP, out IntPtr ortValueMap)); - result = new OrtValue(ortValueMap); - disposables.Add(result); - return result; } - /// /// This pins memory that is contained within DenseTensor. /// /// NodeOnnxValue containing DenseTensor /// - /// cleanup list /// /// - private OrtValue CreateTensorProjection(NamedOnnxValue node, NodeMetadata elementMeta, DisposableList disposables) + private static OrtValue CreateTensorProjection(NamedOnnxValue node, NodeMetadata elementMeta) { - var ortValue = OrtValue.CreateFromTensorObject(node.Value, - out MemoryHandle? memoryHandle, out TensorElementType elementType); - disposables.Add(ortValue); - - if (memoryHandle.HasValue) - { - disposables.Add(memoryHandle); - } - - if (elementType != elementMeta.ElementDataType) + if (node.Value is not TensorBase) { throw new OnnxRuntimeException(ErrorCode.InvalidArgument, - $"Tensor element data type discovered: {elementType} metadata expected: {elementMeta.ElementDataType}"); + $"NamedOnnxValue contains: {node.Value.GetType()}, expecting a Tensor"); } - return ortValue; - } - - #region IDisposable - /// - /// IDisposable implementation - /// - /// true if invoked by Dispose() - protected virtual void Dispose(bool disposing) - { - if (_disposed) + OrtValue ortValue = OrtValue.CreateFromTensorObject(node.Value as TensorBase, out TensorElementType elementType); + try { - return; + if (elementType != elementMeta.ElementDataType) + { + throw new OnnxRuntimeException(ErrorCode.InvalidArgument, + $"Tensor element data type discovered: {elementType} metadata expected: {elementMeta.ElementDataType}"); + } } - - // dispose managed state (managed objects). - if (disposing) + catch (Exception) { - _disposables.Dispose(); + ortValue.Dispose(); + throw; } - _disposed = true; - } - - public void Dispose() - { - Dispose(true); + return ortValue; } - - #endregion IDisposable } } diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/Microsoft.ML.OnnxRuntime.csproj b/csharp/src/Microsoft.ML.OnnxRuntime/Microsoft.ML.OnnxRuntime.csproj index 8f5663a478c64..29ccf55f081d5 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/Microsoft.ML.OnnxRuntime.csproj +++ b/csharp/src/Microsoft.ML.OnnxRuntime/Microsoft.ML.OnnxRuntime.csproj @@ -21,7 +21,7 @@ --> PreNet6 - netstandard1.1;netstandard2.0;net5.0;netcoreapp3.1 + netstandard2.0;netcoreapp3.1;net6.0 net6.0;net6.0-android;net6.0-ios;net6.0-macos + + net6.0;net6.0-android + + - $(BaseTargets);$(XamarinTargets) + $(BaseTargets);$(XamarinTargets);$(XamarinTargetsForTraining) - $(Net6Targets) + $(Net6Targets);$(Net6TargetsForTrainingPackage) - $(BaseTargets);$(XamarinTargets);$(Net6Targets) + $(BaseTargets);$(XamarinTargets);$(XamarinTargetsForTraining);$(Net6Targets);$(Net6TargetsForTrainingPackage) AnyCPU;x86 - 7.3 + default true true ..\..\OnnxRuntime.snk @@ -178,7 +188,7 @@ + @@ -314,13 +331,13 @@ - + - + diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/NamedOnnxValue.shared.cs b/csharp/src/Microsoft.ML.OnnxRuntime/NamedOnnxValue.shared.cs index 5f08daf73806a..d73c471bb9d7c 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/NamedOnnxValue.shared.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/NamedOnnxValue.shared.cs @@ -18,16 +18,19 @@ namespace Microsoft.ML.OnnxRuntime /// internal class MapHelper { - internal MapHelper(object keys, object values) + internal MapHelper(TensorBase keys, TensorBase values) { Keys = keys; Values = values; } - internal Object Keys { get; } // DenseTensor - internal Object Values { get; } // DenseTensor + internal TensorBase Keys { get; } // DenseTensor + internal TensorBase Values { get; } // DenseTensor } /// + /// This is a legacy class that is kept for backward compatibility. + /// Use OrtValue based API. + /// /// The class associates a name with an Object. /// The name of the class is a misnomer, it does not hold any Onnx values, /// just managed representation of them. @@ -36,7 +39,7 @@ internal MapHelper(object keys, object values) /// disposable, it can not hold on to any native objects. /// /// When used as input, we temporarily create OrtValues that map managed inputs - /// directly. Thus we are able to avoid copying. + /// directly. Thus we are able to avoid copying of contiguous data. /// /// For outputs, tensor buffers works the same as input, providing it matches /// the expected output shape. For other types (maps and sequences) we create a copy of the data. @@ -44,7 +47,7 @@ internal MapHelper(object keys, object values) /// the underlying OrtValues that must be destroyed before Run() returns. /// /// To avoid data copying on output, use DisposableNamedOnnxValue class that is returned from Run() methods. - /// This provides access to the native memory and avoids copying. + /// This provides access to the native memory tensors and avoids copying. /// /// It is a recursive structure that may contain Tensors (base case) /// Other sequences and maps. Although the OnnxValueType is exposed, @@ -162,12 +165,14 @@ public static NamedOnnxValue CreateFromMap(string name, IDictionary // The order in which Keys and Values are unspecified, // but it is guaranteed to be the same order // These tensors are 1-D - var keysMemory = new Memory(value.Keys.ToArray()); - var keysTensor = new DenseTensor(keysMemory, new int[1] { keysMemory.Length }); + return CreateFromMap(name, value.Keys, value.Values); + } - var valuesMemory = new Memory(value.Values.ToArray()); - var valuesTensor = new DenseTensor(valuesMemory, new int[1] { valuesMemory.Length }); - return new NamedOnnxValue(name, value, new MapHelper(keysTensor, valuesTensor)); + internal static NamedOnnxValue CreateFromMap(string name, ICollection keys, ICollection values) + { + var keysTensor = new DenseTensor(keys.ToArray(), new int[1] { keys.Count }); + var valuesTensor = new DenseTensor(values.ToArray(), new int[1] { values.Count }); + return new NamedOnnxValue(name, values, new MapHelper(keysTensor, valuesTensor)); } /// @@ -221,12 +226,12 @@ public IDictionary AsDictionary() /// both OrtValue and pinnedMemoryHandle /// /// dispose after returned OrtValus is disposed - /// an instance of OrtValue. The lifespan of OrtValue must overlap pinnedMemoryHandle - internal virtual OrtValue InputToOrtValue(NodeMetadata metadata, out IDisposable memoryOwner) + /// The native OrtValue handle + internal virtual IntPtr InputToOrtValueHandle(NodeMetadata metadata, out IDisposable memoryOwner) { - var projection = new ManagedTypeProjection(this, metadata); + var projection = ManagedTypeProjection.CreateProjection(this, metadata); memoryOwner = projection; - return projection.Value; + return projection.Handle; } /// @@ -239,15 +244,15 @@ internal virtual OrtValue InputToOrtValue(NodeMetadata metadata, out IDisposable /// /// /// - internal virtual OrtValue OutputToOrtValue(NodeMetadata metadata, out IDisposable memoryOwner) + internal virtual IntPtr OutputToOrtValueHandle(NodeMetadata metadata, out IDisposable memoryOwner) { // For NamedOnnxValue for output we only allow to produce OrtValue for tensors // or optional type that may contain a tensor if (metadata.OnnxValueType == OnnxValueType.ONNX_TYPE_TENSOR) { - var projection = new ManagedTypeProjection(this, metadata); + var projection = ManagedTypeProjection.CreateProjection(this, metadata); memoryOwner = projection; - return projection.Value; + return projection.Handle; } if (metadata.OnnxValueType == OnnxValueType.ONNX_TYPE_OPTIONAL) @@ -255,9 +260,9 @@ internal virtual OrtValue OutputToOrtValue(NodeMetadata metadata, out IDisposabl var meta = metadata.AsOptionalMetadata().ElementMeta; if (meta.OnnxValueType == OnnxValueType.ONNX_TYPE_TENSOR) { - var projection = new ManagedTypeProjection(this, meta); + var projection = ManagedTypeProjection.CreateProjection(this, metadata); memoryOwner = projection; - return projection.Value; + return projection.Handle; } } @@ -273,7 +278,7 @@ internal virtual OrtValue OutputToOrtValue(NodeMetadata metadata, out IDisposabl /// /// /// DenseTensor" - internal Object GetDictionaryKeys() + internal TensorBase GetDictionaryKeys() { if (ValueType != OnnxValueType.ONNX_TYPE_MAP) { @@ -289,7 +294,7 @@ internal Object GetDictionaryKeys() /// /// /// DenseTensor" - internal Object GetDictionaryValues() + internal TensorBase GetDictionaryValues() { if (ValueType != OnnxValueType.ONNX_TYPE_MAP) { @@ -299,8 +304,5 @@ internal Object GetDictionaryValues() Debug.Assert(_mapHelper != null); return _mapHelper.Values; } - - // may expose different types of getters in future - } } diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/NativeApiStatus.shared.cs b/csharp/src/Microsoft.ML.OnnxRuntime/NativeApiStatus.shared.cs index 699cf4ebbd4c9..7071d0409e121 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/NativeApiStatus.shared.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/NativeApiStatus.shared.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.Runtime.CompilerServices; namespace Microsoft.ML.OnnxRuntime { @@ -20,6 +21,7 @@ private static string GetErrorMessage(IntPtr /*(ONNXStatus*)*/status) /// /// /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void VerifySuccess(IntPtr nativeStatus) { if (nativeStatus != IntPtr.Zero) diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/NativeMethods.shared.cs b/csharp/src/Microsoft.ML.OnnxRuntime/NativeMethods.shared.cs index 4926cd47525fb..2ba837be22041 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/NativeMethods.shared.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/NativeMethods.shared.cs @@ -286,6 +286,14 @@ public struct OrtApi public IntPtr CastTypeInfoToOptionalTypeInfo; public IntPtr GetOptionalContainedTypeInfo; public IntPtr GetResizedStringTensorElementBuffer; + public IntPtr KernelContext_GetAllocator; + public IntPtr GetBuildInfoString; + public IntPtr CreateROCMProviderOptions; + public IntPtr UpdateROCMProviderOptions; + public IntPtr GetROCMProviderOptionsAsString; + public IntPtr ReleaseROCMProviderOptions; + public IntPtr CreateAndRegisterAllocatorV2; + public IntPtr RunAsync; } internal static class NativeMethods @@ -305,7 +313,7 @@ static NativeMethods() DOrtGetApi OrtGetApi = (DOrtGetApi)Marshal.GetDelegateForFunctionPointer(OrtGetApiBase().GetApi, typeof(DOrtGetApi)); // TODO: Make this save the pointer, and not copy the whole structure across - api_ = (OrtApi)OrtGetApi(4 /*ORT_API_VERSION*/); + api_ = (OrtApi)OrtGetApi(14 /*ORT_API_VERSION*/); OrtGetVersionString = (DOrtGetVersionString)Marshal.GetDelegateForFunctionPointer(OrtGetApiBase().GetVersionString, typeof(DOrtGetVersionString)); OrtCreateEnv = (DOrtCreateEnv)Marshal.GetDelegateForFunctionPointer(api_.CreateEnv, typeof(DOrtCreateEnv)); @@ -361,6 +369,7 @@ static NativeMethods() OrtSetIntraOpNumThreads = (DOrtSetIntraOpNumThreads)Marshal.GetDelegateForFunctionPointer(api_.SetIntraOpNumThreads, typeof(DOrtSetIntraOpNumThreads)); OrtSetSessionGraphOptimizationLevel = (DOrtSetSessionGraphOptimizationLevel)Marshal.GetDelegateForFunctionPointer(api_.SetSessionGraphOptimizationLevel, typeof(DOrtSetSessionGraphOptimizationLevel)); OrtRegisterCustomOpsLibrary = (DOrtRegisterCustomOpsLibrary)Marshal.GetDelegateForFunctionPointer(api_.RegisterCustomOpsLibrary, typeof(DOrtRegisterCustomOpsLibrary)); + OrtRegisterCustomOpsLibrary_V2 = (DOrtRegisterCustomOpsLibrary_V2)Marshal.GetDelegateForFunctionPointer(api_.RegisterCustomOpsLibrary_V2, typeof(DOrtRegisterCustomOpsLibrary_V2)); OrtAddSessionConfigEntry = (DOrtAddSessionConfigEntry)Marshal.GetDelegateForFunctionPointer(api_.AddSessionConfigEntry, typeof(DOrtAddSessionConfigEntry)); OrtAddInitializer = (DOrtAddInitializer)Marshal.GetDelegateForFunctionPointer(api_.AddInitializer, typeof(DOrtAddInitializer)); SessionOptionsAppendExecutionProvider_TensorRT = (DSessionOptionsAppendExecutionProvider_TensorRT)Marshal.GetDelegateForFunctionPointer( @@ -421,6 +430,7 @@ static NativeMethods() OrtCreateAndRegisterAllocator = (DOrtCreateAndRegisterAllocator)Marshal.GetDelegateForFunctionPointer(api_.CreateAndRegisterAllocator, typeof(DOrtCreateAndRegisterAllocator)); OrtSetLanguageProjection = (DOrtSetLanguageProjection)Marshal.GetDelegateForFunctionPointer(api_.SetLanguageProjection, typeof(DOrtSetLanguageProjection)); + OrtHasValue = (DOrtHasValue)Marshal.GetDelegateForFunctionPointer(api_.HasValue, typeof(DOrtHasValue)); OrtGetValue = (DOrtGetValue)Marshal.GetDelegateForFunctionPointer(api_.GetValue, typeof(DOrtGetValue)); OrtGetValueCount = (DOrtGetValueCount)Marshal.GetDelegateForFunctionPointer(api_.GetValueCount, typeof(DOrtGetValueCount)); OrtCreateValue = (DOrtCreateValue)Marshal.GetDelegateForFunctionPointer(api_.CreateValue, typeof(DOrtCreateValue)); @@ -429,11 +439,15 @@ static NativeMethods() OrtGetTypeInfo = (DOrtGetTypeInfo)Marshal.GetDelegateForFunctionPointer(api_.GetTypeInfo, typeof(DOrtGetTypeInfo)); OrtCreateTensorAsOrtValue = (DOrtCreateTensorAsOrtValue)Marshal.GetDelegateForFunctionPointer(api_.CreateTensorAsOrtValue, typeof(DOrtCreateTensorAsOrtValue)); OrtCreateTensorWithDataAsOrtValue = (DOrtCreateTensorWithDataAsOrtValue)Marshal.GetDelegateForFunctionPointer(api_.CreateTensorWithDataAsOrtValue, typeof(DOrtCreateTensorWithDataAsOrtValue)); + OrtValueIsTensor = (DOrtValueIsTensor)Marshal.GetDelegateForFunctionPointer(api_.IsTensor, typeof(DOrtValueIsTensor)); + OrtValueIsSparseTensor = (DOrtValueIsSparseTensor)Marshal.GetDelegateForFunctionPointer(api_.IsSparseTensor, typeof(DOrtValueIsSparseTensor)); OrtGetTensorMutableData = (DOrtGetTensorMutableData)Marshal.GetDelegateForFunctionPointer(api_.GetTensorMutableData, typeof(DOrtGetTensorMutableData)); OrtFillStringTensor = (DOrtFillStringTensor)Marshal.GetDelegateForFunctionPointer(api_.FillStringTensor, typeof(DOrtFillStringTensor)); OrtGetResizedStringTensorElementBuffer = (DOrtGetResizedStringTensorElementBuffer)Marshal.GetDelegateForFunctionPointer(api_.GetResizedStringTensorElementBuffer, typeof(DOrtGetResizedStringTensorElementBuffer)); OrtGetStringTensorContent = (DOrtGetStringTensorContent)Marshal.GetDelegateForFunctionPointer(api_.GetStringTensorContent, typeof(DOrtGetStringTensorContent)); OrtGetStringTensorDataLength = (DOrtGetStringTensorDataLength)Marshal.GetDelegateForFunctionPointer(api_.GetStringTensorDataLength, typeof(DOrtGetStringTensorDataLength)); + OrtGetStringTensorElementLength = (DOrtGetStringTensorElementLength)Marshal.GetDelegateForFunctionPointer(api_.GetStringTensorElementLength, typeof(DOrtGetStringTensorElementLength)); + OrtGetStringTensorElement = (DOrtGetStringTensorElement)Marshal.GetDelegateForFunctionPointer(api_.GetStringTensorElement, typeof(DOrtGetStringTensorElement)); OrtCastTypeInfoToTensorInfo = (DOrtCastTypeInfoToTensorInfo)Marshal.GetDelegateForFunctionPointer(api_.CastTypeInfoToTensorInfo, typeof(DOrtCastTypeInfoToTensorInfo)); OrtGetTensorTypeAndShape = (DOrtGetTensorTypeAndShape)Marshal.GetDelegateForFunctionPointer(api_.GetTensorTypeAndShape, typeof(DOrtGetTensorTypeAndShape)); OrtReleaseTensorTypeAndShapeInfo = (DOrtReleaseTensorTypeAndShapeInfo)Marshal.GetDelegateForFunctionPointer(api_.ReleaseTensorTypeAndShapeInfo, typeof(DOrtReleaseTensorTypeAndShapeInfo)); @@ -442,6 +456,7 @@ static NativeMethods() OrtGetDimensions = (DOrtGetDimensions)Marshal.GetDelegateForFunctionPointer(api_.GetDimensions, typeof(DOrtGetDimensions)); OrtGetSymbolicDimensions = (DOrtGetSymbolicDimensions)Marshal.GetDelegateForFunctionPointer(api_.GetSymbolicDimensions, typeof(DOrtGetSymbolicDimensions)); OrtGetTensorShapeElementCount = (DOrtGetTensorShapeElementCount)Marshal.GetDelegateForFunctionPointer(api_.GetTensorShapeElementCount, typeof(DOrtGetTensorShapeElementCount)); + OrtGetTensorMemoryInfo = (DOrtGetTensorMemoryInfo)Marshal.GetDelegateForFunctionPointer(api_.GetTensorMemoryInfo, typeof(DOrtGetTensorMemoryInfo)); // MapTypeInfo OrtGetMapKeyType = (DGetMapKeyType)Marshal.GetDelegateForFunctionPointer(api_.GetMapKeyType, typeof(DGetMapKeyType)); OrtCastTypeInfoToMapTypeInfo = (DCastTypeInfoToMapTypeInfo)Marshal.GetDelegateForFunctionPointer(api_.CastTypeInfoToMapTypeInfo, typeof(DCastTypeInfoToMapTypeInfo)); @@ -491,23 +506,29 @@ static NativeMethods() api_.SessionOptionsAppendExecutionProvider, typeof(DSessionOptionsAppendExecutionProvider)); OrtUpdateEnvWithCustomLogLevel = (DOrtUpdateEnvWithCustomLogLevel)Marshal.GetDelegateForFunctionPointer(api_.UpdateEnvWithCustomLogLevel, typeof(DOrtUpdateEnvWithCustomLogLevel)); + SessionOptionsAppendExecutionProvider_ROCM = (DSessionOptionsAppendExecutionProvider_ROCM)Marshal.GetDelegateForFunctionPointer( + api_.SessionOptionsAppendExecutionProvider_ROCM, typeof(DSessionOptionsAppendExecutionProvider_ROCM)); + OrtCreateROCMProviderOptions = (DOrtCreateROCMProviderOptions)Marshal.GetDelegateForFunctionPointer(api_.CreateROCMProviderOptions, typeof(DOrtCreateROCMProviderOptions)); + OrtUpdateROCMProviderOptions = (DOrtUpdateROCMProviderOptions)Marshal.GetDelegateForFunctionPointer(api_.UpdateROCMProviderOptions, typeof(DOrtUpdateROCMProviderOptions)); + OrtGetROCMProviderOptionsAsString = (DOrtGetROCMProviderOptionsAsString)Marshal.GetDelegateForFunctionPointer(api_.GetROCMProviderOptionsAsString, typeof(DOrtGetROCMProviderOptionsAsString)); + OrtReleaseROCMProviderOptions = (DOrtReleaseROCMProviderOptions)Marshal.GetDelegateForFunctionPointer(api_.ReleaseROCMProviderOptions, typeof(DOrtReleaseROCMProviderOptions)); + OrtCreateAndRegisterAllocatorV2 = (DCreateAndRegisterAllocatorV2)Marshal.GetDelegateForFunctionPointer(api_.CreateAndRegisterAllocatorV2, typeof(DCreateAndRegisterAllocatorV2)); + OrtRunAsync = (DOrtRunAsync)Marshal.GetDelegateForFunctionPointer(api_.RunAsync, typeof(DOrtRunAsync)); } internal class NativeLib { #if __ANDROID__ - // define the library name required for android - internal const string DllName = "libonnxruntime.so"; + // define the library name required for android + internal const string DllName = "libonnxruntime.so"; #elif __IOS__ - // define the library name required for iOS - internal const string DllName = "__Internal"; + // define the library name required for iOS + internal const string DllName = "__Internal"; #else internal const string DllName = "onnxruntime"; #endif - // TODO: Does macos need special handling or will 'onnxruntime' -> libonnxruntime.dylib? } - [DllImport(NativeLib.DllName, CharSet = CharSet.Ansi)] public static extern ref OrtApiBase OrtGetApiBase(); @@ -659,6 +680,51 @@ internal class NativeLib [UnmanagedFunctionPointer(CallingConvention.Winapi)] public delegate void DOrtReleaseCUDAProviderOptions(IntPtr /*(OrtCUDAProviderOptions*)*/ cudaProviderOptionsInstance); public static DOrtReleaseCUDAProviderOptions OrtReleaseCUDAProviderOptions; + + /// + /// Creates native OrtROCMProviderOptions instance + /// + /// (output) native instance of OrtROCMProviderOptions + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + public delegate IntPtr /* OrtStatus* */DOrtCreateROCMProviderOptions( + out IntPtr /*(OrtROCMProviderOptions**)*/ rocmProviderOptionsInstance); + public static DOrtCreateROCMProviderOptions OrtCreateROCMProviderOptions; + + /// + /// Updates native OrtROCMProviderOptions instance using given key/value pairs + /// + /// native instance of OrtROCMProviderOptions + /// configuration keys of OrtROCMProviderOptions + /// configuration values of OrtROCMProviderOptions + /// number of configuration keys + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + public delegate IntPtr /* OrtStatus* */DOrtUpdateROCMProviderOptions( + IntPtr /*(OrtROCMProviderOptions*)*/ rocmProviderOptionsInstance, + IntPtr[] /*(const char* const *)*/ providerOptionsKeys, + IntPtr[] /*(const char* const *)*/ providerOptionsValues, + UIntPtr /*(size_t)*/ numKeys); + public static DOrtUpdateROCMProviderOptions OrtUpdateROCMProviderOptions; + + /// + /// Get native OrtROCMProviderOptions in serialized string + /// + /// instance of OrtAllocator + /// is a UTF-8 null terminated string allocated using 'allocator' + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + public delegate IntPtr /* OrtStatus* */DOrtGetROCMProviderOptionsAsString( + IntPtr /*(OrtROCMProviderOptions**)*/ rocmProviderOptionsInstance, + IntPtr /*(OrtAllocator*)*/ allocator, + out IntPtr /*(char**)*/ptr); + public static DOrtGetROCMProviderOptionsAsString OrtGetROCMProviderOptionsAsString; + + /// + /// Releases native OrtROCMProviderOptions instance + /// + /// native instance of OrtROCMProviderOptions to be released + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + public delegate void DOrtReleaseROCMProviderOptions(IntPtr /*(OrtROCMProviderOptions*)*/ rocmProviderOptionsInstance); + public static DOrtReleaseROCMProviderOptions OrtReleaseROCMProviderOptions; + #endregion #region Status API @@ -854,6 +920,32 @@ IntPtr[] outputValues /* An array of output value pointers. Array must be alloca out UIntPtr /*(ulong* out)*/ startTime); public static DOrtSessionGetProfilingStartTimeNs OrtSessionGetProfilingStartTimeNs; + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + public delegate IntPtr /*(ONNStatus*)*/ DCreateAndRegisterAllocatorV2( + IntPtr /* (OrtEnv*) */ environment, + IntPtr /*(char*)*/ provider_type, + IntPtr /*(OrtMemoryInfo*)*/ mem_info, + IntPtr /*(OrtArenaCfg*)*/ arena_cfg, + IntPtr /*(char**)*/ provider_options_keys, + IntPtr /*(char**)*/ provider_options_values, + UIntPtr /*(size_t)*/num_keys); + public static DCreateAndRegisterAllocatorV2 OrtCreateAndRegisterAllocatorV2; + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + public delegate IntPtr /*(ONNStatus*)*/ DOrtRunAsync( + IntPtr /*(OrtSession*)*/ session, + IntPtr /*(OrtSessionRunOptions*)*/ runOptions, // can be null to use the default options + IntPtr[] /*(char**)*/ inputNames, + IntPtr[] /*(OrtValue*[])*/ inputValues, + UIntPtr /*(size_t)*/ inputCount, + IntPtr[] /*(char**)*/ outputNames, + UIntPtr /*(size_t)*/ outputCount, + IntPtr[] /*(OrtValue*[])*/ outputValues, + IntPtr /*(void (*RunAsyncCallbackFn)(void* user_data, OrtValue** outputs, size_t num_outputs, OrtStatusPtr status))*/ callback, // callback function + IntPtr /*(void*)*/ user_data + ); + public static DOrtRunAsync OrtRunAsync; + #endregion InferenceSession API #region SessionOptions API @@ -1040,6 +1132,18 @@ IntPtr[] outputValues /* An array of output value pointers. Array must be alloca public static DSessionOptionsAppendExecutionProvider_CUDA_V2 SessionOptionsAppendExecutionProvider_CUDA_V2; + /// + /// Append a ROCm EP instance (configured based on given provider options) to the native OrtSessionOptions instance + /// + /// Native OrtSessionOptions instance + /// Native OrtROCMProviderOptions instance + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + public delegate IntPtr /*(OrtStatus*)*/DSessionOptionsAppendExecutionProvider_ROCM( + IntPtr /*(OrtSessionOptions*)*/ options, + IntPtr /*(const OrtROCMProviderOptions*)*/ rocmProviderOptions); + + public static DSessionOptionsAppendExecutionProvider_ROCM SessionOptionsAppendExecutionProvider_ROCM; + /// /// Free Dimension override (by denotation) /// @@ -1079,6 +1183,17 @@ IntPtr[] outputValues /* An array of output value pointers. Array must be alloca public static DOrtRegisterCustomOpsLibrary OrtRegisterCustomOpsLibrary; + /// + /// Register custom op library. ORT will manage freeing the library. + /// + /// Native SessionOptions instance + /// Library path + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + public delegate IntPtr /*(OrtStatus*)*/DOrtRegisterCustomOpsLibrary_V2(IntPtr /*(OrtSessionOptions*) */ options, + byte[] /*(const ORTCHAR_T*)*/ libraryPath); + + public static DOrtRegisterCustomOpsLibrary_V2 OrtRegisterCustomOpsLibrary_V2; + /// /// Add initializer that is shared across Sessions using this SessionOptions (by denotation) /// @@ -1644,7 +1759,6 @@ IntPtr[] outputValues /* An array of output value pointers. Array must be alloca public static DOrtModelMetadataLookupCustomMetadataMap OrtModelMetadataLookupCustomMetadataMap; - /// /// Frees ModelMetadata instance /// @@ -1656,7 +1770,12 @@ IntPtr[] outputValues /* An array of output value pointers. Array must be alloca #endregion ModelMetadata API - #region Tensor/OnnxValue API + #region OrtValue API + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + public delegate IntPtr /*(OrtStatus*)*/ DOrtHasValue(IntPtr /*(OrtValue*)*/ value, out IntPtr /*(int*)*/ hasValue); + + public static DOrtHasValue OrtHasValue; [UnmanagedFunctionPointer(CallingConvention.Winapi)] public delegate IntPtr /*(OrtStatus*)*/ DOrtGetValue(IntPtr /*(OrtValue*)*/ value, @@ -1688,7 +1807,7 @@ IntPtr[] outputValues /* An array of output value pointers. Array must be alloca public static DOrtCreateValue OrtCreateValue; [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr /*(OrtStatus*)*/ DOrtGetTypeInfo(IntPtr /*(OrtValue*)*/ value, IntPtr /*(OrtValue**)*/ typeInfo); + public delegate IntPtr /*(OrtStatus*)*/ DOrtGetTypeInfo(IntPtr /*(OrtValue*)*/ value, out IntPtr /*(OrtValue**)*/ typeInfo); public static DOrtGetTypeInfo OrtGetTypeInfo; @@ -1714,6 +1833,16 @@ IntPtr[] outputValues /* An array of output value pointers. Array must be alloca public static DOrtCreateTensorWithDataAsOrtValue OrtCreateTensorWithDataAsOrtValue; + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + public delegate IntPtr /* OrtStatus */ DOrtValueIsTensor(IntPtr /*(OrtValue*)*/ ortValue, out IntPtr val); + + public static DOrtValueIsTensor OrtValueIsTensor; + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + public delegate IntPtr /* OrtStatus */ DOrtValueIsSparseTensor(IntPtr /*(OrtValue*)*/ ortValue, out IntPtr val); + + public static DOrtValueIsSparseTensor OrtValueIsSparseTensor; + /// This function doesn't work with string tensor /// this is a no-copy method whose pointer is only valid until the backing OrtValue* is free'd. [UnmanagedFunctionPointer(CallingConvention.Winapi)] @@ -1756,6 +1885,21 @@ out IntPtr /* char** */ buffer public static DOrtGetStringTensorDataLength OrtGetStringTensorDataLength; + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + public delegate IntPtr /*(OrtStatus*)*/ DOrtGetStringTensorElementLength(IntPtr /*(OrtValue*)*/ value, + UIntPtr /*(size_t)*/ index, + out UIntPtr /*(size_t*)*/ len); + + public static DOrtGetStringTensorElementLength OrtGetStringTensorElementLength; + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + public delegate IntPtr /*(OrtStatus*)*/ DOrtGetStringTensorElement(IntPtr /*(OrtValue*)*/ value, + UIntPtr /*(size_t)*/ bufferLength, + UIntPtr /*(size_t)*/ elementIndex, + byte[] buffer); + + public static DOrtGetStringTensorElement OrtGetStringTensorElement; + [UnmanagedFunctionPointer(CallingConvention.Winapi)] public delegate IntPtr /*(OrtStatus*)*/ DOrtCastTypeInfoToTensorInfo(IntPtr /*(struct OrtTypeInfo*)*/ typeInfo, out IntPtr /*(const struct OrtTensorTypeAndShapeInfo**)*/ typeAndShapeInfo); @@ -1819,10 +1963,19 @@ out IntPtr /* char** */ buffer * [-1,3,4] -> -1 */ [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr /*(OrtStatus*)*/ DOrtGetTensorShapeElementCount(IntPtr /*(const struct OrtTensorTypeAndShapeInfo*)*/ typeAndShapeInfo, out IntPtr /*(long*)*/ output); + public delegate IntPtr /*(OrtStatus*)*/ DOrtGetTensorShapeElementCount(IntPtr /*(const struct OrtTensorTypeAndShapeInfo*)*/ typeAndShapeInfo, + out UIntPtr /* size_t */ output); public static DOrtGetTensorShapeElementCount OrtGetTensorShapeElementCount; + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + // The out ortMemoryInfo must not be destroyed/deallocated. The pointer points to an object owned by + // the contained Tensor/SparseTensor. + public delegate IntPtr /*(OrtStatus*)*/ DOrtGetTensorMemoryInfo(IntPtr /* const OrtValue* */ ortValue, + out IntPtr /* const OrtMemoryInfo** */ ortMemoryInfo); + + public static DOrtGetTensorMemoryInfo OrtGetTensorMemoryInfo; + /// Map Type API [UnmanagedFunctionPointer(CallingConvention.Winapi)] public delegate IntPtr /*(OrtStatus*)*/ DCastTypeInfoToMapTypeInfo(IntPtr /*(const struct OrtTypeInfo*)*/ typeInfo, out IntPtr /*const OrtMapTypeInfo** */ mapTypeInfo); @@ -1865,6 +2018,7 @@ out IntPtr /* char** */ buffer #endregion + #region Misc API /// @@ -1907,4 +2061,27 @@ out IntPtr /* char** */ buffer #endregion } //class NativeMethods + + // onnxruntime-extensions helpers to make usage simpler. + // The onnxruntime-extensions nuget package containing the native library can be optionally added to the app. + // If added, SessionOptions.RegisterOrtExtensions can be called to add the custom ops to the session options. + // We handle the DllImport and platform specific aspects so the user code doesn't require that. + // adjust the library name based on platform. + internal static class OrtExtensionsNativeMethods + { +#if __ANDROID__ + internal const string ExtensionsDllName = "libortextensions.so"; +#elif __IOS__ + internal const string ExtensionsDllName = "__Internal"; +#else + internal const string ExtensionsDllName = "ortextensions"; +#endif + + [DllImport(ExtensionsDllName, CharSet = CharSet.Ansi, + CallingConvention = CallingConvention.Winapi)] + public static extern IntPtr /* OrtStatus* */ RegisterCustomOps(IntPtr /* OrtSessionOptions* */ sessionOptions, + ref OrtApiBase /* OrtApiBase* */ ortApiBase); + + + } } //namespace diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/NativeOnnxValueHelper.shared.cs b/csharp/src/Microsoft.ML.OnnxRuntime/NativeOnnxValueHelper.shared.cs index 0376d83fdaa8f..96afb48fcc352 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/NativeOnnxValueHelper.shared.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/NativeOnnxValueHelper.shared.cs @@ -3,11 +3,11 @@ using Microsoft.ML.OnnxRuntime.Tensors; using System; -using System.Runtime.InteropServices; -using System.Text; using System.Collections.Generic; -using System.Linq; using System.Diagnostics; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; namespace Microsoft.ML.OnnxRuntime { @@ -38,38 +38,20 @@ internal static byte[] StringToZeroTerminatedUtf8(string s) /// must match the required size and can be obtained in advance with /// System.Text.Encoding.UTF8.GetByteCount(s). /// - /// The function is helpful when we populate native string tensor buffers directly where - /// the elements stored do not have zero terminator. /// - /// managed string - /// natively allocated buffer - /// pre-allocated buffer size - internal static void StringToUtf8NativeMemory(string s, IntPtr ptr, int totalBytesToWrite) + /// fixed char* ptr + /// string length + /// Native buffer to write + /// + /// + internal unsafe static void StringToUtf8NativeMemory(char* strPtr, int strLength, IntPtr ptr, int nativeBufferSize) { - // We throw here, because we are expecting the caller to properly calculate and allocate the right size buffer - unsafe + // total bytes to write is size of native memory buffer + var bytesWritten = Encoding.UTF8.GetBytes(strPtr, strLength, (byte*)ptr, nativeBufferSize); + if (bytesWritten != nativeBufferSize) { -#if NETSTANDARD1_1 - var utf8Bytes = (s.Length != 0) ? Encoding.UTF8.GetBytes(s) : ArrayUtilities.GetEmpty(); - if (totalBytesToWrite != utf8Bytes.Length) - { - throw new OnnxRuntimeException(ErrorCode.RuntimeException, - $"Failed to convert to UTF8. Expected bytes: {totalBytesToWrite}, converted to UTF-8: {utf8Bytes.Length}"); - } - Span destination = new Span((ptr).ToPointer(), utf8Bytes.Length); - utf8Bytes.AsSpan(0, utf8Bytes.Length).CopyTo(destination); -#else - fixed (char* c = s) // create char pointer to start of managed string. - { - var nativeBytes = (byte*)ptr; // get managed byte* from native intptr - var bytesWritten = Encoding.UTF8.GetBytes(c, s.Length, nativeBytes, totalBytesToWrite); // total bytes to write is size of native memory buffer - if (bytesWritten != totalBytesToWrite) - { - throw new OnnxRuntimeException(ErrorCode.RuntimeException, - $"Failed to convert to UTF8. Expected bytes: {totalBytesToWrite}, written: {bytesWritten}"); - } - } -#endif + throw new OnnxRuntimeException(ErrorCode.RuntimeException, + $"Failed to convert to UTF8. Expected bytes: {nativeBufferSize}, written: {bytesWritten}"); } } @@ -93,15 +75,8 @@ internal static string StringFromNativeUtf8(IntPtr nativeUtf8, OrtAllocator allo { return string.Empty; } -#if NETSTANDARD1_1 - var src = new Span((nativeUtf8).ToPointer(), len); - byte[] buffer = new byte[len]; - src.CopyTo(buffer); - return Encoding.UTF8.GetString(buffer, 0, buffer.Length); -#else var nativeBytes = (byte*)nativeUtf8; return Encoding.UTF8.GetString(nativeBytes, len); -#endif } } finally @@ -146,16 +121,8 @@ internal static void StringAndUtf8FromNative(OrtAllocator allocator, IntPtr nati var dest = new Span((utf8).ToPointer(), len + 1); src.CopyTo(dest); dest[len] = 0; -#if NETSTANDARD1_1 - // For .NET Standard 1.1, we need to copy the bytes to a managed buffer - // before conversion - byte[] buffer = new byte[len]; - src.CopyTo(buffer); - str = Encoding.UTF8.GetString(buffer, 0, len); -#else var nativeBytes = (byte*)nativeUtf8; str = Encoding.UTF8.GetString(nativeBytes, len); -#endif } catch (Exception) { @@ -185,24 +152,44 @@ internal static byte[] GetPlatformSerializedString(string str) } } - internal static class TensorElementTypeConverter + // Guards an array of disposable objects on stack and disposes them in reverse order + internal ref struct DisposableArray where T : IDisposable { - public static bool GetTypeAndWidth(TensorElementType elemType, out Type type, out int width) + internal Span Span { get; private set; } + internal DisposableArray(Span disposables) { - bool result = true; - TensorElementTypeInfo typeInfo = TensorBase.GetElementTypeInfo(elemType); - if (typeInfo != null) + Span = disposables; + } + + public void Dispose() + { + // Dispose in the reverse order in case there are dependencies + // between objects created later. + for (int i = Span.Length - 1; i >= 0; --i) { - type = typeInfo.TensorType; - width = typeInfo.TypeSize; + Span[i]?.Dispose(); } - else + } + } + + internal ref struct DisposableOrtValueHandleArray + { + internal Span Span { get; private set; } + internal DisposableOrtValueHandleArray(Span handles) + { + Span = handles; + } + + public void Dispose() + { + // Dispose in the reverse order in case there are dependencies + for (int i = Span.Length - 1; i >= 0; --i) { - type = null; - width = 0; - result = false; + if (Span[i] != IntPtr.Zero) + { + NativeMethods.OrtReleaseValue(Span[i]); + } } - return result; } } diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/OrtAllocator.shared.cs b/csharp/src/Microsoft.ML.OnnxRuntime/OrtAllocator.shared.cs index 688bdf630fb70..3f918fc2ad6c8 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/OrtAllocator.shared.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/OrtAllocator.shared.cs @@ -102,9 +102,8 @@ public class OrtMemoryInfo : SafeHandle private static OrtMemoryInfo CreateCpuMemoryInfo() { - IntPtr memoryInfo = IntPtr.Zero; // Returns OrtMemoryInfo instance that needs to be disposed - NativeApiStatus.VerifySuccess(NativeMethods.OrtCreateCpuMemoryInfo(OrtAllocatorType.DeviceAllocator, OrtMemType.Cpu, out memoryInfo)); + NativeApiStatus.VerifySuccess(NativeMethods.OrtCreateCpuMemoryInfo(OrtAllocatorType.DeviceAllocator, OrtMemType.Cpu, out IntPtr memoryInfo)); return new OrtMemoryInfo(memoryInfo, true); } @@ -163,6 +162,16 @@ internal OrtMemoryInfo(IntPtr allocInfo, bool owned) /// public static readonly byte[] allocatorCUDA_PINNED = Encoding.UTF8.GetBytes("CudaPinned" + Char.MinValue); /// + /// Predefined utf8 encoded allocator names. Use them to construct an instance of + /// OrtMemoryInfo to avoid UTF-16 to UTF-8 conversion costs. + /// + public static readonly byte[] allocatorHIP = Encoding.UTF8.GetBytes("Hip" + Char.MinValue); + /// + /// Predefined utf8 encoded allocator names. Use them to construct an instance of + /// OrtMemoryInfo to avoid UTF-16 to UTF-8 conversion costs. + /// + public static readonly byte[] allocatorHIP_PINNED = Encoding.UTF8.GetBytes("HipPinned" + Char.MinValue); + /// /// Create an instance of OrtMemoryInfo according to the specification /// Memory info instances are usually used to get a handle of a native allocator /// that is present within the current inference session object. That, in turn, depends @@ -216,8 +225,7 @@ public int Id { get { - int id = 0; - NativeApiStatus.VerifySuccess(NativeMethods.OrtMemoryInfoGetId(handle, out id)); + NativeApiStatus.VerifySuccess(NativeMethods.OrtMemoryInfoGetId(handle, out int id)); return id; } } @@ -230,8 +238,7 @@ public int Id /// OrtMemoryType for the instance public OrtMemType GetMemoryType() { - OrtMemType memoryType = OrtMemType.Default; - NativeApiStatus.VerifySuccess(NativeMethods.OrtMemoryInfoGetMemType(handle, out memoryType)); + NativeApiStatus.VerifySuccess(NativeMethods.OrtMemoryInfoGetMemType(handle, out OrtMemType memoryType)); return memoryType; } @@ -241,8 +248,7 @@ public OrtMemType GetMemoryType() /// Returns allocator type public OrtAllocatorType GetAllocatorType() { - OrtAllocatorType allocatorType = OrtAllocatorType.ArenaAllocator; - NativeApiStatus.VerifySuccess(NativeMethods.OrtMemoryInfoGetType(handle, out allocatorType)); + NativeApiStatus.VerifySuccess(NativeMethods.OrtMemoryInfoGetType(handle, out OrtAllocatorType allocatorType)); return allocatorType; } @@ -253,8 +259,7 @@ public OrtAllocatorType GetAllocatorType() /// true if obj is an instance of OrtMemoryInfo and is equal to this public override bool Equals(object obj) { - var other = obj as OrtMemoryInfo; - if (other == null) + if (!(obj is OrtMemoryInfo other)) { return false; } @@ -272,8 +277,7 @@ public bool Equals(OrtMemoryInfo other) { return true; } - int result = -1; - NativeApiStatus.VerifySuccess(NativeMethods.OrtCompareMemoryInfo(handle, other.Pointer, out result)); + NativeApiStatus.VerifySuccess(NativeMethods.OrtCompareMemoryInfo(handle, other.Pointer, out int result)); return (result == 0); } @@ -315,6 +319,7 @@ protected override bool ReleaseHandle() /// The memory is assumed to be pinned if necessary and usable immediately /// in the native code. /// + [Obsolete("Create OrtValue over an arbitrary piece of memory and use it where appropriate.")] public class OrtExternalAllocation { /// @@ -327,22 +332,18 @@ public class OrtExternalAllocation /// size of the allocation in bytes public OrtExternalAllocation(OrtMemoryInfo memInfo, long[] shape, Tensors.TensorElementType elementType, IntPtr pointer, long sizeInBytes) { - Type type; - int width; - if (!TensorElementTypeConverter.GetTypeAndWidth(elementType, out type, out width)) - { - throw new OnnxRuntimeException(ErrorCode.InvalidArgument, - "Unable to query type information for data type: " + elementType.ToString()); - } - if (elementType == TensorElementType.String) + var typeInfo = TensorBase.GetElementTypeInfo(elementType) ?? throw new OnnxRuntimeException(ErrorCode.InvalidArgument, + $"Tensor element type: {elementType} is not supported"); + + if (typeInfo.IsString) { throw new OnnxRuntimeException(ErrorCode.InvalidArgument, "Strings are not supported by this API"); } - var shapeSize = ArrayUtilities.GetSizeForShape(shape); - var requiredBufferSize = shapeSize * width; + var shapeSize = ShapeUtils.GetSizeForShape(shape); + var requiredBufferSize = shapeSize * typeInfo.TypeSize; if (requiredBufferSize > sizeInBytes) { var message = String.Format("Shape of {0} elements requires a buffer of at least {1} bytes. Provided: {2} bytes", @@ -467,8 +468,7 @@ public class OrtAllocator : SafeHandle private static OrtAllocator GetDefaultCpuAllocator() { - IntPtr allocator = IntPtr.Zero; - NativeApiStatus.VerifySuccess(NativeMethods.OrtGetAllocatorWithDefaultOptions(out allocator)); + NativeApiStatus.VerifySuccess(NativeMethods.OrtGetAllocatorWithDefaultOptions(out IntPtr allocator)); // Instance of default cpu allocator is a native singleton // Do not dispose of return new OrtAllocator(allocator, false); @@ -533,8 +533,7 @@ public OrtMemoryInfo Info { get { - IntPtr memoryInfo = IntPtr.Zero; - NativeApiStatus.VerifySuccess(NativeMethods.OrtAllocatorGetInfo(handle, out memoryInfo)); + NativeApiStatus.VerifySuccess(NativeMethods.OrtAllocatorGetInfo(handle, out IntPtr memoryInfo)); // This serves as an exposure of memory_info owned by the allocator return new OrtMemoryInfo(memoryInfo, false); } @@ -547,8 +546,7 @@ public OrtMemoryInfo Info /// Instance of OrtMemoryAllocation public OrtMemoryAllocation Allocate(uint size) { - IntPtr allocation = IntPtr.Zero; - NativeApiStatus.VerifySuccess(NativeMethods.OrtAllocatorAlloc(handle, (UIntPtr)size, out allocation)); + NativeApiStatus.VerifySuccess(NativeMethods.OrtAllocatorAlloc(handle, (UIntPtr)size, out IntPtr allocation)); return new OrtMemoryAllocation(this, allocation, size); } diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/OrtEnv.shared.cs b/csharp/src/Microsoft.ML.OnnxRuntime/OrtEnv.shared.cs index 2df16ccae0323..1a03338298fa9 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/OrtEnv.shared.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/OrtEnv.shared.cs @@ -276,7 +276,7 @@ public static OrtEnv Instance() /// /// /// if the singleton has already been created - public static OrtEnv CreateInstanceWithOptions(EnvironmentCreationOptions options) + public static OrtEnv CreateInstanceWithOptions(ref EnvironmentCreationOptions options) { // Non-thread safe, best effort hopefully helpful check. // Environment is usually created once per process, so this should be fine. diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/OrtFloat16.shared.cs b/csharp/src/Microsoft.ML.OnnxRuntime/OrtFloat16.shared.cs new file mode 100644 index 0000000000000..20be2acacfc5f --- /dev/null +++ b/csharp/src/Microsoft.ML.OnnxRuntime/OrtFloat16.shared.cs @@ -0,0 +1,1372 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// Portions of this code are from System.Half struct dotnet runtime. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace Microsoft.ML.OnnxRuntime +{ + // Utilities class created to fill in the gaps + // of functionality that is absent in BitConverter class in NETSTANDARD 2.0 + // as well as some Single precision bit constants. + internal class BitOpsUtils + { + // Lifted from .NET source code internal code + // Constants for Single precision format + // https://source.dot.net/#System.Private.CoreLib/src/libraries/System.Private.CoreLib/src/System/Single.cs,dda909df0f8d2fd0 + internal const uint SingleBiasedExponentMask = 0x7F80_0000; + internal const int SingleBiasedExponentShift = 23; + + internal const uint SingleSignMask = 0x8000_0000; + internal const int SingleSignShift = 31; + + // Most significant significand bit + internal const uint SingleMostSignificantSigBit = 0x400000; + internal const uint SingleTrailingSignificandMask = 0x007F_FFFF; + + /// + /// Required because BitOperations are not available in NETSTANDARD 2.0. + /// There are more efficient ways with bit twiddling, but this one has clarity. + /// + /// value + /// number of leading zeros. Useful to compute log2 as well. + internal static int LeadingZeroCount(uint num) + { + if (num == 0) + { + return 32; + } + + int count = 0; + while ((num & 0xF000_0000) == 0) + { + count += 4; + num <<= 4; + } + + while ((num & 0x8000_0000) == 0) + { + count += 1; + num <<= 1; + } + return count; + } + + /// + /// Extracts single precision number bit representation as uint + /// so its bits can be manipulated. + /// + /// This API is the reverse of UInt32BitsToSingle(). + /// + /// + /// float value + /// + internal static uint SingleToUInt32Bits(float single) + { + uint result; + unsafe + { + Buffer.MemoryCopy(&single, &result, sizeof(uint), sizeof(uint)); + } + return result; + } + + /// + /// Needed because BitConverter impl is not available until + /// later versions. This API is the reverse of SingleToUInt32Bits(). + /// + /// For the exact bit representation of float see IEEE 754 standard for single precision. + /// + /// + /// bit representation of float either obtained from + /// SingleToUInt32Bits or assembled using bitwise operators + /// + internal static float UInt32BitsToSingle(uint singleBits) + { + float result; + unsafe + { + Buffer.MemoryCopy(&singleBits, &result, sizeof(uint), sizeof(uint)); + } + return result; + } + + /// + /// Converts single precision bits representation which can be obtained using + /// SingleToUInt32Bits() or manually constructed according to IEEE 754 standard. + /// + /// + /// bits representation of a single precision number (float) + /// + internal static ushort SingleBitsToBFloat16Bits(uint singleBits) + { + if (!BitConverter.IsLittleEndian) + { + return (ushort)(singleBits & 0xFFFF); + } + else + { + return (ushort)(singleBits >> 16); + } + } + + /// + /// Converts bfloat16 ushort bits representation to single precision bits which then in turn can be + /// manipulated or converted to float using UInt32BitsToSingle() + /// + /// ushort bits representation of bfloat16 + /// + internal static uint BFloat16BitsToSingleBits(ushort bfloatBits) + { + if (!BitConverter.IsLittleEndian) + { + return bfloatBits; + } + else + { + return (uint)bfloatBits << 16; + } + } + + /// + /// Creates float NaN with the given sign and fp16 significand shifted << 54 + /// + /// true for negative + /// should be shifted 54 bits left before calling the function + /// so only 8 bits of signidicand remains + /// + internal static float CreateSingleNaN(bool sign, ulong significand) + { + // We need to set at least on bit in NaN significant + const uint NaNBits = SingleBiasedExponentMask | SingleMostSignificantSigBit; + + uint signInt = (sign ? 1U : 0U) << SingleSignShift; + uint sigInt = (uint)(significand >> 41); + uint singleBits = signInt | NaNBits | sigInt; + + return UInt32BitsToSingle(singleBits); + } + + /// + /// Creates float from sign, exponent and significand + /// + /// true if negative + /// exponent + /// significand + /// + internal static float CreateSingle(bool sign, byte exponent, uint significand) + { + uint signInt = (sign ? 1U : 0U) << SingleSignShift; + uint expInt = ((uint)exponent << SingleBiasedExponentShift) + significand; + uint singleBits = signInt + expInt; + + return UInt32BitsToSingle(singleBits); + } + } + + + /// + /// This value type represents A Float16 value + /// it is blittable as defined in https://docs.microsoft.com/en-us/dotnet/framework/interop/blittable-and-non-blittable-types + /// and as such, represented the same way in managed and native memories. This means that arrays of this type + /// do not have to be copied to be passed to native memory but simply pinned and read by native code. Thus, + /// one can create a Tensor on top of an array of these structures and feed it directly to Onnxruntime library. + /// Binary wise, it is the same as ushort[] (uint16_t in C++). However, we would like a separate type for type dispatching. + /// + /// The implementation is derived from + /// https://source.dot.net/#System.Private.CoreLib/src/libraries/System.Private.CoreLib/src/System/Half.cs,7895d5942d33f974 + /// + [StructLayout(LayoutKind.Sequential)] + public readonly struct Float16 : + IComparable, + IComparable, + IEquatable + { + internal const ushort SignMask = 0x8000; + internal const int SignShift = 15; + internal const byte ShiftedSignMask = SignMask >> SignShift; + + internal const ushort BiasedExponentMask = 0x7C00; // 0b0_111_1100_0000_0000; + internal const int BiasedExponentShift = 10; + internal const byte ShiftedBiasedExponentMask = BiasedExponentMask >> BiasedExponentShift; + + internal const ushort TrailingSignificandMask = 0x03FF; // 0b0_000_0011_1111_1111; + + internal const byte MinSign = 0; + internal const byte MaxSign = 1; + + internal const byte MinBiasedExponent = 0x00; + internal const byte MaxBiasedExponent = 0x1F; + + internal const byte ExponentBias = 15; + + internal const sbyte MinExponent = -14; + internal const sbyte MaxExponent = +15; + + // Constants representing the private bit-representation for various default values + + private const ushort PositiveZeroBits = 0x0000; + private const ushort NegativeZeroBits = 0x8000; + + private const ushort OneBits = 0x3C00; + + private const ushort EpsilonBits = 0x0400; + + private const ushort PositiveInfinityBits = 0x7C00; + private const ushort NegativeInfinityBits = 0xFC00; + + private const ushort PositiveQNaNBits = 0x7E00; + private const ushort NegativeQNaNBits = 0xFE00; + + private const ushort MinValueBits = 0xFBFF; + private const ushort MaxValueBits = 0x7BFF; + + private const ushort PositiveOneBits = 0x3C00; + private const ushort NegativeOneBits = 0xBC00; + + private const ushort EBits = 0x4170; + private const ushort PiBits = 0x4248; + private const ushort TauBits = 0x4648; + + // Well-defined and commonly used values + + /// + /// Float16 Epsilon value + /// + public static Float16 Epsilon => new Float16(EpsilonBits); // 5.9604645E-08 + + /// + /// Float16 Pi value + /// + public static Float16 Pi => new Float16(PiBits); // 3.14159265358979323846 + + /// + /// Float16 Positive Infinity value + /// + public static Float16 PositiveInfinity => new Float16(PositiveInfinityBits); // 1.0 / 0.0; + + /// + /// Float16 Negative Infinity value + /// + public static Float16 NegativeInfinity => new Float16(NegativeInfinityBits); // -1.0 / 0.0 + + /// + /// Float16 NaN + /// + public static Float16 NaN => new Float16(NegativeQNaNBits); // 0.0 / 0.0 + + /// + /// Float16 Zero value + /// + public static Float16 Zero => new Float16(PositiveZeroBits); // 0.0 + + /// + /// Float16 One value + /// + public static Float16 One => new Float16(OneBits); // 1.0 + + /// + /// Float16 Negative Zero value + /// + public static Float16 NegativeZero => new Float16(NegativeZeroBits); // -0.0 + + /// + /// Float16 Min value + /// + public static Float16 MinValue => new Float16(MinValueBits); // 64,511 + + /// + /// Float16 Max value + /// + public static Float16 MaxValue => new Float16(MaxValueBits); // 31,743 + + /// + /// float16 representation bits + /// + public readonly ushort value; + + /// + /// Ctor from ushort bits, no conversion is done + /// + /// + public Float16(ushort v) + { + value = v; + } + + private Float16(bool sign, ushort exp, ushort sig) => + value = (ushort)(((sign ? 1 : 0) << SignShift) + (exp << BiasedExponentShift) + sig); + + internal byte BiasedExponent + { + get + { + ushort bits = value; + return ExtractBiasedExponentFromBits(bits); + } + } + + internal sbyte Exponent + { + get + { + return (sbyte)(BiasedExponent - ExponentBias); + } + } + + internal ushort Significand + { + get + { + return (ushort)(TrailingSignificand | ((BiasedExponent != 0) ? (1U << BiasedExponentShift) : 0U)); + } + } + + internal ushort TrailingSignificand + { + get + { + ushort bits = value; + return ExtractTrailingSignificandFromBits(bits); + } + } + + internal static byte ExtractBiasedExponentFromBits(ushort bits) + { + return (byte)((bits >> BiasedExponentShift) & ShiftedBiasedExponentMask); + } + + internal static ushort ExtractTrailingSignificandFromBits(ushort bits) + { + return (ushort)(bits & TrailingSignificandMask); + } + + /// + /// Compares values of two Float16 + /// + /// + /// left hand side + /// right hand side + /// returns true if left is less than right according to IEEE + public static bool operator <(Float16 left, Float16 right) + { + if (IsNaN(left) || IsNaN(right)) + { + // IEEE defines that NaN is unordered with respect to everything, including itself. + return false; + } + + bool leftIsNegative = IsNegative(left); + + if (leftIsNegative != IsNegative(right)) + { + // When the signs of left and right differ, we know that left is less than right if it is + // the negative value. The exception to this is if both values are zero, in which case IEEE + // says they should be equal, even if the signs differ. + return leftIsNegative && !AreZero(left, right); + } + + return (left.value != right.value) && ((left.value < right.value) ^ leftIsNegative); + } + + /// + /// Compares values of two Float16 + /// + /// + /// left hand side + /// right hand side + /// returns true if left is greater than right according to IEEE + public static bool operator >(Float16 left, Float16 right) + { + return right < left; + } + + /// + /// Compares values of two Float16 + /// + /// + /// left hand side + /// right hand side + /// returns true if left is less or equal than right according to IEEE + public static bool operator <=(Float16 left, Float16 right) + { + if (IsNaN(left) || IsNaN(right)) + { + // IEEE defines that NaN is unordered with respect to everything, including itself. + return false; + } + + bool leftIsNegative = IsNegative(left); + + if (leftIsNegative != IsNegative(right)) + { + // When the signs of left and right differ, we know that left is less than right if it is + // the negative value. The exception to this is if both values are zero, in which case IEEE + // says they should be equal, even if the signs differ. + return leftIsNegative || AreZero(left, right); + } + + return (left.value == right.value) || ((left.value < right.value) ^ leftIsNegative); + } + + /// + /// Compares values of two Float16 + /// + /// + /// left hand side + /// right hand side + /// returns true if left is greater or equal than right according to IEEE + /// + public static bool operator >=(Float16 left, Float16 right) + { + return right <= left; + } + + /// + /// Compares values of two Float16 for binary equality. + /// If either of the values is NaN, this will return false. + /// + /// + /// left hand side + /// right hand side + /// true if values are equal according to IEEE + public static bool operator ==(Float16 left, Float16 right) + { + if (IsNaN(left) || IsNaN(right)) + { + // IEEE defines that NaN is not equal to anything, including itself. + return false; + } + + return left.value == right.value; + } + + /// + /// Compares values of two Float16 for binary inequality + /// + /// + /// + /// true if values are not equal according to IEEE + public static bool operator !=(Float16 left, Float16 right) + { + return !(left == right); + } + + /// + /// Determines whether the specified value is finite (zero, subnormal, or normal). + /// + /// Float16 instance. + /// true if the value is finite + public static bool IsFinite(Float16 value) + { + return StripSign(value) < PositiveInfinityBits; + } + + /// + /// Determines whether the specified value is infinite. + /// + /// Float16 instance. + /// true if the value is infinite + public static bool IsInfinity(Float16 value) + { + return StripSign(value) == PositiveInfinityBits; + } + + /// + /// Determines whether the specified value is NaN. + /// + /// + /// Float16 instance + /// true if the value is not a number + public static bool IsNaN(Float16 value) + { + return StripSign(value) > PositiveInfinityBits; + } + + /// + /// Determines whether the specified value is negative. + /// + /// Float16 instance + /// true if the value is negative + public static bool IsNegative(Float16 value) + { + return (short)(value.value) < 0; + } + + /// + /// Determines whether the specified value is negative infinity. + /// + /// + /// Float16 instance + /// true if the value is negative infinity + public static bool IsNegativeInfinity(Float16 value) + { + return value.value == NegativeInfinityBits; + } + + + /// + /// Determines whether the specified value is normal + /// + /// + /// true or false + public static bool IsNormal(Float16 value) + { + uint absValue = StripSign(value); + return (absValue < PositiveInfinityBits) // is finite + && (absValue != 0) // is not zero + && ((absValue & BiasedExponentMask) != 0); // is not subnormal (has a non-zero exponent) + } + + + /// + /// Determines whether the specified value is positive infinity. + /// + /// Float16 instance + /// + public static bool IsPositiveInfinity(Float16 value) + { + return value.value == PositiveInfinityBits; + } + + /// + /// Determines whether the specified value is subnormal. + /// + /// Float16 instance + /// true if the value is subnormal + public static bool IsSubnormal(Float16 value) + { + uint absValue = StripSign(value); + return (absValue < PositiveInfinityBits) // is finite + && (absValue != 0) // is not zero + && ((absValue & BiasedExponentMask) == 0); // is subnormal (has a zero exponent) + } + + /// + /// Compares this object to another object, returning an integer that indicates the relationship. + /// + /// + /// Object to compare to + /// A value less than zero if this is less than , + /// zero if this is equal to , or a value greater than zero + /// if this is greater than . + /// + /// Thrown when is not of type . + public int CompareTo(object obj) + { + if (!(obj is Float16)) + { + return (obj is null) ? 1 : throw new ArgumentException("Object must be of type Float16"); + } + return CompareTo((Float16)(obj)); + } + + /// + /// Compares this object to another object, returning an integer that indicates the relationship. + /// + /// Object to compare to + /// A value less than zero if this is less than , + /// zero if this is equal to , + /// or a value greater than zero if this is greater than . + public int CompareTo(Float16 other) + { + if (this < other) + { + return -1; + } + + if (this > other) + { + return 1; + } + + if (this == other) + { + return 0; + } + + if (IsNaN(this)) + { + return IsNaN(other) ? 0 : -1; + } + + Debug.Assert(IsNaN(other)); + return 1; + } + + /// + /// Returns a value indicating whether this instance and other Float16 represent the same value. + /// + /// A Float16 object to compare to this instance. + /// true if other.value is equal to this instance; otherwise, false. + public bool Equals(Float16 other) + { + return value == other.value + || AreZero(this, other) + || (IsNaN(this) && IsNaN(other)); + } + + /// + /// Returns a value indicating whether this instance and a specified System.Object + /// represent the same type and value. + /// + /// An System.Object. + /// true if obj is Float16 and its value is equal to this instance; otherwise, false. + public override bool Equals(object obj) + { + return (obj is Float16 other) && Equals(other); + } + + /// + /// Returns the hash code for this instance. + /// + /// A 32-bit signed integer hash code. + public override int GetHashCode() + { + if (IsNaNOrZero(this)) + { + // All NaNs should have the same hash code, as should both Zeros. + return value & PositiveInfinityBits; + } + return value; + } + + /// + /// Returns a string representation of the current value. + /// + /// Text representation of Float16 + public override string ToString() + { + return $"{value} : {ToFloat()}"; + } + + /// + /// Explicit conversion + /// + /// single precision value converted from Float16 + public float ToFloat() + { + return (float)this; + } + + /// Explicitly converts a value to its nearest representable half-precision floating-point value. + /// The value to convert. + /// converted to its nearest representable half-precision floating-point value. + public static explicit operator Float16(float value) + { + const int SingleMaxExponent = 0xFF; + + uint floatInt = BitOpsUtils.SingleToUInt32Bits(value); + bool sign = (floatInt & BitOpsUtils.SingleSignMask) >> BitOpsUtils.SingleSignShift != 0; + int exp = (int)(floatInt & BitOpsUtils.SingleBiasedExponentMask) >> BitOpsUtils.SingleBiasedExponentShift; + uint sig = floatInt & BitOpsUtils.SingleTrailingSignificandMask; + + if (exp == SingleMaxExponent) + { + if (sig != 0) // NaN + { + return CreateFloat16NaN(sign, (ulong)sig << 41); // Shift the significand bits to the left end + } + return sign ? NegativeInfinity : PositiveInfinity; + } + + uint sigHalf = sig >> 9 | ((sig & 0x1FFU) != 0 ? 1U : 0U); // RightShiftJam + + if ((exp | (int)sigHalf) == 0) + { + return new Float16(sign, 0, 0); + } + + return new Float16(RoundPackToFloat16(sign, (short)(exp - 0x71), (ushort)(sigHalf | 0x4000))); + } + + /// Explicitly converts a half-precision floating-point value to its nearest representable value. + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator float(Float16 value) + { + bool sign = IsNegative(value); + int exp = value.BiasedExponent; + uint sig = value.TrailingSignificand; + + if (exp == MaxBiasedExponent) + { + if (sig != 0) + { + // Shift sig left so only 8 bits of it remains + return BitOpsUtils.CreateSingleNaN(sign, (ulong)sig << 54); + } + return sign ? float.NegativeInfinity : float.PositiveInfinity; + } + + if (exp == 0) + { + if (sig == 0) + { + // Positive / Negative zero + return (sign) ? -0.0f : 0.0f; + } + (exp, sig) = NormSubnormalF16Sig(sig); + exp -= 1; + } + + return BitOpsUtils.CreateSingle(sign, (byte)(exp + 0x70), sig << 13); + } + + /// + /// Flips the sign. NaNs are not affected. + /// IEEE 754 specifies NaNs to be propagated + /// + /// + /// + public static Float16 Negate(Float16 value) + { + return IsNaN(value) ? value : new Float16((ushort)(value.value ^ SignMask)); + } + + #region Utilities + + private static bool AreZero(Float16 left, Float16 right) + { + // IEEE defines that positive and negative zero are equal, this gives us a quick equality check + // for two values by or'ing the private bits together and stripping the sign. They are both zero, + // and therefore equivalent, if the resulting value is still zero. + return (ushort)((left.value | right.value) & ~SignMask) == 0; + } + + /// + /// The function returns true if the value is either NaN or zero. + /// + /// instance of Float16 + /// true if NaN or zero. + public static bool IsNaNOrZero(Float16 value) + { + uint abs = StripSign(value); + return (abs == 0 || abs > PositiveInfinityBits); + } + + private static uint StripSign(Float16 value) + { + return (ushort)(value.value & ~SignMask); + } + + private static (int Exp, uint Sig) NormSubnormalF16Sig(uint sig) + { + int shiftDist = BitOpsUtils.LeadingZeroCount(sig) - 16 - 5; + return (1 - shiftDist, sig << shiftDist); + } + + + // Significand bits should be shifted towards to the left end before calling these methods + // Creates Quiet NaN if significand == 0 + private static Float16 CreateFloat16NaN(bool sign, ulong significand) + { + const ushort NaNBits = BiasedExponentMask | 0x200; // Most significant significand bit + + uint signInt = (sign ? 1U : 0U) << SignShift; + ushort sigInt = (ushort)(significand >> 54); + + ushort ushortBits = (ushort)(signInt | NaNBits | sigInt); + return new Float16(ushortBits); + } + + private static ushort RoundPackToFloat16(bool sign, short exp, ushort sig) + { + const int RoundIncrement = 0x8; // Depends on rounding mode but it's always towards closest / ties to even + int roundBits = sig & 0xF; + + if ((uint)exp >= 0x1D) + { + if (exp < 0) + { + sig = (ushort)ShiftRightJam(sig, -exp); + exp = 0; + roundBits = sig & 0xF; + } + else if (exp > 0x1D || sig + RoundIncrement >= 0x8000) // Overflow + { + return sign ? NegativeInfinityBits : PositiveInfinityBits; + } + } + + sig = (ushort)((sig + RoundIncrement) >> 4); + sig &= (ushort)~(((roundBits ^ 8) != 0 ? 0 : 1) & 1); + + if (sig == 0) + { + exp = 0; + } + + return new Float16(sign, (ushort)exp, sig).value; + } + + // If any bits are lost by shifting, "jam" them into the LSB. + // if dist > bit count, Will be 1 or 0 depending on i + // (unlike bitwise operators that masks the lower 5 bits) + private static uint ShiftRightJam(uint i, int dist) => dist < 31 ? (i >> dist) | (i << (-dist & 31) != 0 ? 1U : 0U) : (i != 0 ? 1U : 0U); + + private static ulong ShiftRightJam(ulong l, int dist) => dist < 63 ? (l >> dist) | (l << (-dist & 63) != 0 ? 1UL : 0UL) : (l != 0 ? 1UL : 0UL); + + #endregion + } + + /// + /// This value type represents A BFloat16 value. + /// See https://cloud.google.com/blog/products/ai-machine-learning/bfloat16-the-secret-to-high-performance-on-cloud-tpus + /// for details. + /// it is blittable as defined in https://docs.microsoft.com/en-us/dotnet/framework/interop/blittable-and-non-blittable-types + /// and as such, represented the same way in managed and native memories. This means that arrays of this type + /// do not have to be copied to be passed to native memory but simply pinnned and read by native code. Thus, + /// one can create a Tensor on top of an array of these structures and feed it directly to Onnxruntime library. + /// Binary wise, it is the same as ushort[] (uint16_t in C++). However, we would like a separate type for type dispatching. + /// + [StructLayout(LayoutKind.Sequential)] + public readonly struct BFloat16 : + IComparable, + IComparable, + IEquatable + { + internal const ushort SignMask = 0x8000; + internal const int SignShift = 15; + internal const byte ShiftedSignMask = SignMask >> SignShift; + + internal const ushort BiasedExponentMask = 0x7F80; // 0b_0111_1111_1000_0000; + internal const int BiasedExponentShift = 7; + internal const byte ShiftedBiasedExponentMask = BiasedExponentMask >> BiasedExponentShift; + + internal const ushort TrailingSignificandMask = 0x007F; // 0b_0000_0000_0111_1111; + + internal const byte MinSign = 0; + internal const byte MaxSign = 1; + + internal const byte MinBiasedExponent = 0x00; + internal const byte MaxBiasedExponent = 0xFF; + + internal const byte ExponentBias = 127; + + internal const sbyte MinExponent = -126; + internal const sbyte MaxExponent = +127; + + // Constants representing the private bit-representation for various default values + + private const ushort PositiveZeroBits = 0x0000; + private const ushort NegativeZeroBits = 0x8000; + + private const ushort OneBits = 0x3F80; // 0b0_01111111_0000000 + + private const ushort PositiveInfinityBits = 0x7F80; + private const ushort NegativeInfinityBits = 0xFF80; + + private const ushort PositiveQNaNBits = 0x7FC1; + private const ushort NegativeQNaNBits = 0xFFC1; + + private const ushort MinValueBits = 0xFF7F; // 1b0_11111110_1111111 + private const ushort MaxValueBits = 0x7F7F; // 0b0_11111110_1111111 + + private const ushort EpsilonBits = 0x0080; // the smallest positive normal value + + private const ushort PiBits = 0x4049; // 0b0_10000000_1001001 + + // Used for rounding subnormal values + private const uint RoundingBase = 0x7FFF; + + // Well-defined and commonly used values + + /// + /// BFloat16 Epsilon value + /// + public static BFloat16 Epsilon => new BFloat16(EpsilonBits); + + /// + /// BFloat16 Pi value + /// + public static BFloat16 Pi => new BFloat16(PiBits); + + /// + /// BFloat16 Positive infinity value + /// + public static BFloat16 PositiveInfinity => new BFloat16(PositiveInfinityBits); + + /// + /// BFloat16 Negative infinity value + /// + public static BFloat16 NegativeInfinity => new BFloat16(NegativeInfinityBits); + + /// + /// BFloat16 NaN + /// + public static BFloat16 NaN => new BFloat16(NegativeQNaNBits); + + /// + /// BFloat16 Positive Zero + /// + public static BFloat16 Zero => new BFloat16(PositiveZeroBits); // 0.0 + + /// + /// BFloat16 One + /// + public static BFloat16 One => new BFloat16(OneBits); // 1.0 + + /// + /// BFloat16 Negative Zero + /// + public static BFloat16 NegativeZero => new BFloat16(NegativeZeroBits); // -0.0 + + /// + /// BFloat16 Min value + /// + public static BFloat16 MinValue => new BFloat16(MinValueBits); // 65,407 + + /// + /// BFloat16 Max value + /// + + public static BFloat16 MaxValue => new BFloat16(MaxValueBits); // 32,639 + + /// + /// bfloat16 representation bits + /// + public readonly ushort value; + + /// + /// Constructor from ushort, no conversion takes place. The value + /// is assumed to be converted + /// + /// bfloat16 representation bits + public BFloat16(ushort v) + { + value = v; + } + + // Extracts biased exponent bits + internal byte BiasedExponent + { + get + { + ushort bits = value; + return ExtractBiasedExponentFromBits(bits); + } + } + + // Extracts all the Significand bits + internal ushort TrailingSignificand + { + get + { + ushort bits = value; + return ExtractTrailingSignificandFromBits(bits); + } + } + + internal static byte ExtractBiasedExponentFromBits(ushort bits) + { + return (byte)((bits >> BiasedExponentShift) & ShiftedBiasedExponentMask); + } + + internal static ushort ExtractTrailingSignificandFromBits(ushort bits) + { + return (ushort)(bits & TrailingSignificandMask); + } + + /// + /// Compares two BFloat16 instances. + /// + /// + /// + /// true if the left is less than right according to IEEE + public static bool operator <(BFloat16 left, BFloat16 right) + { + if (IsNaN(left) || IsNaN(right)) + { + // IEEE defines that NaN is unordered with respect to everything, including itself. + return false; + } + + bool leftIsNegative = IsNegative(left); + + if (leftIsNegative != IsNegative(right)) + { + // When the signs of left and right differ, we know that left is less than right if it is + // the negative value. The exception to this is if both values are zero, in which case IEEE + // says they should be equal, even if the signs differ. + return leftIsNegative && !AreZero(left, right); + } + + return (left.value != right.value) && ((left.value < right.value) ^ leftIsNegative); + } + + /// + /// Compares two BFloat16 instances. + /// + /// + /// + /// true if the left is greater than right according to IEEE + public static bool operator >(BFloat16 left, BFloat16 right) + { + return right < left; + } + + /// + /// Compares two BFloat16 instances. + /// + /// + /// + /// true if the left is less or equal than right according to IEEE + public static bool operator <=(BFloat16 left, BFloat16 right) + { + if (IsNaN(left) || IsNaN(right)) + { + // IEEE defines that NaN is unordered with respect to everything, including itself. + return false; + } + + bool leftIsNegative = IsNegative(left); + + if (leftIsNegative != IsNegative(right)) + { + // When the signs of left and right differ, we know that left is less than right if it is + // the negative value. The exception to this is if both values are zero, in which case IEEE + // says they should be equal, even if the signs differ. + return leftIsNegative || AreZero(left, right); + } + + return (left.value == right.value) || ((left.value < right.value) ^ leftIsNegative); + } + + /// + /// Compares two BFloat16 instances. + /// + /// + /// + /// true if the left is greater or equal than right according to IEEE + public static bool operator >=(BFloat16 left, BFloat16 right) + { + return right <= left; + } + + /// + /// Compares values of two BFloat16 for binary equality. + /// If either of the values is NaN, this will return false. + /// + /// + /// left hand side + /// right hand side + /// result of value comparisons + public static bool operator ==(BFloat16 left, BFloat16 right) + { + if (IsNaN(left) || IsNaN(right)) + { + // IEEE defines that NaN is not equal to anything, including itself. + return false; + } + + return left.value == right.value; + } + + /// + /// Compares values of two BFloat16 for binary inequality + /// If either of the values is NaN it would return true. + /// + /// + /// + /// result of value comparisons + public static bool operator !=(BFloat16 left, BFloat16 right) + { + return !(left == right); + } + + /// + /// Determines whether the specified value is finite (zero, subnormal, or normal). + /// + /// BFloat16 instance. + /// true if the value is finite + public static bool IsFinite(BFloat16 value) + { + return StripSign(value) < PositiveInfinityBits; + } + + /// + /// Determines whether the specified value is infinite. + /// + /// BFloat16 instance. + /// true if the value is infinite + public static bool IsInfinity(BFloat16 value) + { + return StripSign(value) == PositiveInfinityBits; + } + + /// + /// Determines whether the specified value is NaN. + /// + /// + /// BFloat16 instance + /// true if the value is not a number + public static bool IsNaN(BFloat16 value) + { + return StripSign(value) > PositiveInfinityBits; + } + + /// + /// Determines whether the specified value is negative. + /// + /// BFloat16 instance + /// true if the value is negative + public static bool IsNegative(BFloat16 value) + { + return (short)(value.value) < 0; + } + + /// + /// Determines whether the specified value is negative infinity. + /// + /// + /// BFloat16 instance + /// true if the value is negative infinity + public static bool IsNegativeInfinity(BFloat16 value) + { + return value.value == NegativeInfinityBits; + } + + /// + /// Determines whether the specified value is normal + /// + /// + /// true or false + public static bool IsNormal(BFloat16 value) + { + uint absValue = StripSign(value); + return (absValue < PositiveInfinityBits) // is finite + && (absValue != 0) // is not zero + && ((absValue & BiasedExponentMask) != 0); // is not subnormal (has a non-zero exponent) + } + + /// + /// Determines whether the specified value is positive infinity. + /// + /// BFloat16 instance + /// + public static bool IsPositiveInfinity(BFloat16 value) + { + return value.value == PositiveInfinityBits; + } + + /// + /// Determines whether the specified value is subnormal. + /// + /// BFloat16 instance + /// true if the value is subnormal + public static bool IsSubnormal(BFloat16 value) + { + uint absValue = StripSign(value); + return (absValue < PositiveInfinityBits) // is finite + && (absValue != 0) // is not zero + && ((absValue & BiasedExponentMask) == 0); // is subnormal (has a zero exponent) + } + + /// + /// Compares this object to another object, returning an integer that indicates the relationship. + /// + /// + /// Object to compare to + /// A value less than zero if this is less than , + /// zero if this is equal to , or a value greater than zero + /// if this is greater than . + /// + /// Thrown when is not of type . + public int CompareTo(object obj) + { + if (!(obj is BFloat16)) + { + return (obj is null) ? 1 : throw new ArgumentException("Object must be of type BFloat16"); + } + return CompareTo((BFloat16)(obj)); + } + + /// + /// Compares this object to another object, returning an integer that indicates the relationship. + /// + /// Object to compare to + /// A value less than zero if this is less than , + /// zero if this is equal to , + /// or a value greater than zero if this is greater than . + public int CompareTo(BFloat16 other) + { + if (this < other) + { + return -1; + } + + if (this > other) + { + return 1; + } + + if (this == other) + { + return 0; + } + + if (IsNaN(this)) + { + return IsNaN(other) ? 0 : -1; + } + + Debug.Assert(IsNaN(other)); + return 1; + } + + /// + /// Returns a value indicating whether this instance and other BFloat16 represent the same value. + /// + /// A BFloat16 object to compare to this instance. + /// true if other.value is equal to this instance; otherwise, false. + public bool Equals(BFloat16 other) + { + return value == other.value + || AreZero(this, other) + || (IsNaN(this) && IsNaN(other)); + } + + /// + /// Returns a value indicating whether this instance and a specified System.Object + /// represent the same type and value. + /// + /// An System.Object. + /// true if obj is BFloat16 its value is equal to this instance; otherwise, false. + public override bool Equals(object obj) + { + return (obj is BFloat16 other) && Equals(other); + } + + /// + /// Returns the hash code for this instance. + /// + /// A 32-bit signed integer hash code. + public override int GetHashCode() + { + if (IsNaNOrZero(this)) + { + // All NaNs should have the same hash code, as should both Zeros. + return value & PositiveInfinityBits; + } + return value; + } + + /// + /// Returns a string representation of the current value. + /// + /// Text representation of BFloat16 + public override string ToString() + { + return $"{value} : {ToFloat()}"; + } + + /// + /// Explicit conversion + /// + /// single precision value converted from Float16 + public float ToFloat() + { + return (float)this; + } + + /// Explicitly converts a value to its nearest representable bfloat16 value. + /// The value to convert. + /// converted to its nearest representable half-precision floating-point value. + public static explicit operator BFloat16(float value) + { + if (float.IsNaN(value)) + { + return NaN; + } + + uint singleBits = BitOpsUtils.SingleToUInt32Bits(value); + ushort bfloatBits = BitOpsUtils.SingleBitsToBFloat16Bits(singleBits); + + // Round this up. Implement the same logic pytorch uses for rounding. + // We use RoundingBase that is 0x7FFF + (1), so we carry the 1 to the next bit. + // either the last bfloat bit is 1 or singleBits have some bits set. + singleBits += ((uint)bfloatBits & 1) + RoundingBase; + bfloatBits = BitOpsUtils.SingleBitsToBFloat16Bits(singleBits); + return new BFloat16(bfloatBits); + } + + /// + /// Explicitly converts a BFloat16 value to its nearest representable value. + /// + /// The value to convert. + /// converted to its nearest representable value. + public static explicit operator float(BFloat16 value) + { + bool sign = IsNegative(value); + int exp = value.BiasedExponent; + uint sig = value.TrailingSignificand; + + if (exp == MaxBiasedExponent) + { + if (sig != 0) + { + // Shift sig left 54 bits to get a 64-bit integer + // to cut off all but 8 bits of the significant + return BitOpsUtils.CreateSingleNaN(sign, (ulong)sig << 56); + } + return sign ? float.NegativeInfinity : float.PositiveInfinity; + } + + if (exp == 0 && sig == 0) + { + // Positive / Negative zero + return (sign) ? -0.0f : 0.0f; + } + + // All subnormal numbers in BFloat16 would be also subnormal in FP32 because they + // share the exponent. + uint singleBits = BitOpsUtils.BFloat16BitsToSingleBits(value.value); + return BitOpsUtils.UInt32BitsToSingle(singleBits); + } + + /// + /// Flips the sign. NaNs are not affected. + /// IEEE 754 specifies NaNs to be propagated + /// + /// + /// + public static BFloat16 Negate(BFloat16 value) + { + return IsNaN(value) ? value : new BFloat16((ushort)(value.value ^ SignMask)); + } + + /// + /// The function returns true if the value is either NaN or zero. + /// + /// instance of BFloat16 + /// true if NaN or zero. + public static bool IsNaNOrZero(BFloat16 value) + { + uint abs = StripSign(value); + return (abs == 0 || abs > PositiveInfinityBits); + } + + #region Utilities + + private static bool AreZero(BFloat16 left, BFloat16 right) + { + // IEEE defines that positive and negative zero are equal, this gives us a quick equality check + // for two values by or'ing the private bits together and stripping the sign. They are both zero, + // and therefore equivalent, if the resulting value is still zero. + return (ushort)((left.value | right.value) & ~SignMask) == 0; + } + + private static uint StripSign(BFloat16 value) + { + return (ushort)(value.value & ~SignMask); + } + + #endregion + } +} \ No newline at end of file diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/OrtIoBinding.shared.cs b/csharp/src/Microsoft.ML.OnnxRuntime/OrtIoBinding.shared.cs index 04d563ad74f52..557a2c88ef9b2 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/OrtIoBinding.shared.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/OrtIoBinding.shared.cs @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using Microsoft.ML.OnnxRuntime.Tensors; using System; +using System.Diagnostics; using System.Runtime.InteropServices; using System.Text; @@ -22,9 +22,15 @@ namespace Microsoft.ML.OnnxRuntime /// at the time of the binding, not at run time. This means, that if your input data required a copy, /// your further input modifications would not be seen by onnxruntime unless you rebind it, even if it is /// the same buffer. If you require the scenario where data is copied, OrtIOBinding may not be the best match - /// for your use case. - /// - /// The fact that data copy is not made during runtime also has performance implications. + /// for your use case. The fact that data copy is not made during runtime also has performance implications. + /// + /// Making OrtValue first class citizen in ORT C# API practically obsoletes all of the existing overloads + /// because OrtValue can be created on top of the all other types of memory. No need to designate it as external + /// or Ort allocation or wrap it in FixedBufferOnnxValue. The latter does not support rebinding or memory other than + /// CPU anyway. + /// + /// In fact, one can now create OrtValues over arbitrary pieces of memory, managed, native, stack and device(gpu) + /// and feed them to the model and achieve the same effect without using IOBinding class. /// public class OrtIoBinding : SafeHandle { @@ -52,6 +58,21 @@ internal IntPtr Handle /// returns true if handle is equal to Zero public override bool IsInvalid { get { return handle == IntPtr.Zero; } } + + /// + /// This is the preferable and universal way to bind input to OrtValue. + /// This way you retain control over the original value, can modify the data + /// using OrtValue interfaces between the runs. + /// + /// You can also create OrtValue on all kinds of memory, managed, native, stack and device(gpu). + /// + /// input name + /// + public void BindInput(string name, OrtValue ortValue) + { + BindInputOrOutput(name, ortValue.Handle, true); + } + /// /// Bind a piece of pre-allocated native memory as a OrtValue Tensor with a given shape /// to an input with a given name. The model will read the specified input from that memory @@ -75,6 +96,7 @@ public void BindInput(string name, Tensors.TensorElementType elementType, long[] /// /// name /// non ort allocated memory + [Obsolete("This BindInput overload is deprecated. Create OrtValue over an arbitrary piece of memory.")] public void BindInput(string name, OrtExternalAllocation allocation) { BindExternalAllocation(name, allocation, true); @@ -86,6 +108,7 @@ public void BindInput(string name, OrtExternalAllocation allocation) /// /// name of input /// + [Obsolete("This BindInput overload is deprecated. Use of OrtValue based overload is recommended.")] public void BindInput(string name, FixedBufferOnnxValue fixedValue) { if (fixedValue.OnnxValueType != OnnxValueType.ONNX_TYPE_TENSOR) @@ -104,6 +127,19 @@ public void SynchronizeBoundInputs() NativeApiStatus.VerifySuccess(NativeMethods.OrtSynchronizeBoundInputs(handle)); } + /// + /// This is the preferable and universal way to bind output via OrtValue. + /// This way you retain control over the original value, can modify the data + /// using OrtValue interfaces between the runs, rebind output to input if you + /// are feeding data circular. + /// + /// output name + /// OrtValue to bind + public void BindOutput(string name, OrtValue ortValue) + { + BindInputOrOutput(name, ortValue.Handle, false); + } + /// /// Bind model output to an OrtValue as Tensor with a given type and shape. An instance of OrtMemoryAllocaiton /// owns the memory and should be alive for the time of execution. @@ -125,6 +161,7 @@ public void BindOutput(string name, Tensors.TensorElementType elementType, long[ /// /// name /// non ort allocated memory + [Obsolete("This BindOutput overload is deprecated. Create OrtValue over an arbitrary piece of memory.")] public void BindOutput(string name, OrtExternalAllocation allocation) { BindExternalAllocation(name, allocation, false); @@ -136,6 +173,7 @@ public void BindOutput(string name, OrtExternalAllocation allocation) /// /// of the output /// + [Obsolete("This BindOutput overload is deprecated. Use of OrtValue based overload is recommended.")] public void BindOutput(string name, FixedBufferOnnxValue fixedValue) { if (fixedValue.OnnxValueType != OnnxValueType.ONNX_TYPE_TENSOR) @@ -192,6 +230,9 @@ private void BindOrtAllocation(string name, Tensors.TensorElementType elementTyp /// name /// non ort allocated memory /// whether this is an input or output + + // Disable obsolete warning for this method until we remove the code +#pragma warning disable 0618 private void BindExternalAllocation(string name, OrtExternalAllocation allocation, bool isInput) { using (var ortValue = OrtValue.CreateTensorValueWithData(allocation.Info, @@ -201,7 +242,7 @@ private void BindExternalAllocation(string name, OrtExternalAllocation allocatio allocation.Size)) BindInputOrOutput(name, ortValue.Handle, isInput); } - +#pragma warning restore 0618 /// /// Internal helper @@ -232,34 +273,34 @@ public string[] GetOutputNames() NativeApiStatus.VerifySuccess(NativeMethods.OrtGetBoundOutputNames(handle, allocator.Pointer, out IntPtr buffer, out IntPtr lengths, out UIntPtr count)); - if (count.Equals(UIntPtr.Zero)) + if ((ulong)count == 0) { - return new string[0]; + return Array.Empty(); } - try + int outputCount = (int)count; + Span lenSpan; + unsafe { - int outputCount = (int)count; - var lens = new int[outputCount]; - int totalLength = 0; - for (int i = 0; i < outputCount; ++i) - { - var len = (int)Marshal.ReadIntPtr(lengths, IntPtr.Size * i); - lens[i] = len; - totalLength += len; - } + lenSpan = new Span(lengths.ToPointer(), outputCount); + } - var stringData = new byte[totalLength]; - Marshal.Copy(buffer, stringData, 0, stringData.Length); + try + { + var result = new string[outputCount]; - string[] result = new string[outputCount]; int readOffset = 0; for (int i = 0; i < outputCount; ++i) { - var strLen = lens[i]; - result[i] = Encoding.UTF8.GetString(stringData, readOffset, strLen); + var strLen = (int)lenSpan[i]; + unsafe + { + var strStart = new IntPtr(buffer.ToInt64() + readOffset); + result[i] = Encoding.UTF8.GetString((byte*)strStart.ToPointer(), strLen); + } readOffset += strLen; } + return result; } finally @@ -274,36 +315,53 @@ public string[] GetOutputNames() /// /// IDisposableReadOnlyCollection public IDisposableReadOnlyCollection GetOutputValues() + { + var ortValues = GetOutputOrtValues(); + return new DisposableList(ortValues); + } + + internal OrtValue[] GetOutputOrtValues() { var allocator = OrtAllocator.DefaultInstance; NativeApiStatus.VerifySuccess(NativeMethods.OrtGetBoundOutputValues(handle, allocator.Pointer, out IntPtr ortValues, out UIntPtr count)); - if (count.Equals(UIntPtr.Zero)) + if ((ulong)count == 0) { - return new DisposableList(); + return Array.Empty(); + } + + int outputCount = (int)count; + Span srcSpan; + unsafe + { + srcSpan = new Span(ortValues.ToPointer(), outputCount); } try { - int outputCount = (int)count; - var ortList = new DisposableList(outputCount); - try + OrtValue[] result = new OrtValue[outputCount]; + + for (int i = 0; i < outputCount; ++i) { - for (int i = 0; i < outputCount; ++i) - { - IntPtr ortValue = Marshal.ReadIntPtr(ortValues, IntPtr.Size * i); - ortList.Add(new OrtValue(ortValue)); - } + result[i] = new OrtValue(srcSpan[i]); } - catch (Exception) + + return result; + } + catch (Exception) + { + // There is a very little chance that we throw + for (int i = 0; i < srcSpan.Length; ++i) { - ortList.Dispose(); - throw; + NativeMethods.OrtReleaseValue(srcSpan[i]); } - return ortList; + throw; + } + finally + { + allocator.FreeMemory(ortValues); } - finally { allocator.FreeMemory(ortValues); } } /// diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/OrtTypeInfo.shared.cs b/csharp/src/Microsoft.ML.OnnxRuntime/OrtTypeInfo.shared.cs new file mode 100644 index 0000000000000..cbb42f5222cd9 --- /dev/null +++ b/csharp/src/Microsoft.ML.OnnxRuntime/OrtTypeInfo.shared.cs @@ -0,0 +1,271 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + + +using Microsoft.ML.OnnxRuntime.Tensors; +using System; + +namespace Microsoft.ML.OnnxRuntime +{ + /// + /// This class retrieves Type Information for input/outputs of the model. + /// + public class OrtTypeInfo + { + private OrtTensorTypeAndShapeInfo? _tensorTypeAndShape; + private OrtSequenceOrOptionalTypeInfo? _sequenceOrOptional; + private OrtMapTypeInfo? _mapTypeInfo; + + internal OrtTypeInfo(IntPtr handle) + { + NativeApiStatus.VerifySuccess(NativeMethods.OrtGetOnnxTypeFromTypeInfo(handle, out IntPtr onnxType)); + OnnxType = (OnnxValueType)onnxType; + + switch (OnnxType) + { + case OnnxValueType.ONNX_TYPE_TENSOR: + case OnnxValueType.ONNX_TYPE_SPARSETENSOR: + { + NativeApiStatus.VerifySuccess(NativeMethods.OrtCastTypeInfoToTensorInfo(handle, out IntPtr tensorInfo)); + if (tensorInfo == IntPtr.Zero) + { + throw new OnnxRuntimeException(ErrorCode.Fail, + "Type Information indicates a tensor, but casting to TensorInfo fails"); + } + _tensorTypeAndShape = new OrtTensorTypeAndShapeInfo(tensorInfo); + } + break; + case OnnxValueType.ONNX_TYPE_SEQUENCE: + { + NativeApiStatus.VerifySuccess(NativeMethods.OrtCastTypeInfoToSequenceTypeInfo(handle, out IntPtr sequenceInfo)); + if (sequenceInfo == IntPtr.Zero) + { + throw new OnnxRuntimeException(ErrorCode.InvalidArgument, + "TypeInfo cast to SequenceTypeInfo failed. The object does not represent a sequence"); + } + _sequenceOrOptional = new OrtSequenceOrOptionalTypeInfo(sequenceInfo); + } + break; + case OnnxValueType.ONNX_TYPE_MAP: + { + NativeApiStatus.VerifySuccess(NativeMethods.OrtCastTypeInfoToMapTypeInfo(handle, out IntPtr mapInfo)); + if (mapInfo == IntPtr.Zero) + { + throw new OnnxRuntimeException(ErrorCode.InvalidArgument, + "TypeInfo cast to MapTypeInfo failed. The object does not represent a map"); + } + _mapTypeInfo = new OrtMapTypeInfo(mapInfo); + } + break; + case OnnxValueType.ONNX_TYPE_OPTIONAL: + { + NativeApiStatus.VerifySuccess(NativeMethods.OrtCastTypeInfoToOptionalTypeInfo(handle, out IntPtr optionalInfo)); + if (optionalInfo == IntPtr.Zero) + { + throw new OnnxRuntimeException(ErrorCode.InvalidArgument, + "TypeInfo cast to OptionalTypeInfo failed. The object does not represent a optional"); + } + _sequenceOrOptional = new OrtSequenceOrOptionalTypeInfo(optionalInfo); + } + break; + default: + throw new OnnxRuntimeException(ErrorCode.NotImplemented, $"OnnxValueType: {OnnxType} is not supported here"); + } + } + + /// + /// Represents OnnxValueType of the OrtTypeInfo + /// + /// OnnxValueType + public OnnxValueType OnnxType { get; private set; } + + /// + /// This property returns the tensor type and shape information from the OrtTypeInfo + /// iff this OrtTypeInfo represents a tensor. + /// + /// + /// Instance of OrtTensorTypeAndShapeInfo + public OrtTensorTypeAndShapeInfo TensorTypeAndShapeInfo + { + get + { + if (OnnxType != OnnxValueType.ONNX_TYPE_TENSOR && + OnnxType != OnnxValueType.ONNX_TYPE_SPARSETENSOR) + { + throw new OnnxRuntimeException(ErrorCode.InvalidArgument, "TypeInfo does not represent a tensor/sparsetensor"); + } + return _tensorTypeAndShape.Value; + } + } + + /// + /// Sequence type information from the OrtTypeInfo iff this OrtTypeInfo represents a sequence. + /// + /// Instance of OrtSequenceTypeInfo + /// + public OrtSequenceOrOptionalTypeInfo SequenceTypeInfo + { + get + { + if (OnnxType != OnnxValueType.ONNX_TYPE_SEQUENCE) + { + throw new OnnxRuntimeException(ErrorCode.InvalidArgument, "TypeInfo does not represent a sequence"); + } + return _sequenceOrOptional.Value; + } + } + + /// + /// Represents MapTypeInfo from the OrtTypeInfo iff this OrtTypeInfo represents a map. + /// + /// Instance of MapTypeInfo + /// + public OrtMapTypeInfo MapTypeInfo + { + get + { + if (OnnxType != OnnxValueType.ONNX_TYPE_MAP) + { + throw new OnnxRuntimeException(ErrorCode.InvalidArgument, "TypeInfo does not represent a map"); + } + return _mapTypeInfo.Value; + } + } + + /// + /// Fetches OptionalTypeInfo from the OrtTypeInfo iff this OrtTypeInfo represents a optional type. + /// + /// Instance of OptionalTypeInfo + /// + public OrtSequenceOrOptionalTypeInfo OptionalTypeInfo + { + get + { + if (OnnxType != OnnxValueType.ONNX_TYPE_OPTIONAL) + { + throw new OnnxRuntimeException(ErrorCode.InvalidArgument, "TypeInfo does not represent a optional"); + } + return _sequenceOrOptional.Value; + } + } + } + + /// + /// This struct represents type and shape information for a tensor. + /// It may describe a tensor type that is a model input or output or + /// an information that can be extracted from a tensor in OrtValue. + /// + /// + public struct OrtTensorTypeAndShapeInfo + { + internal OrtTensorTypeAndShapeInfo(IntPtr handle) + { + NativeApiStatus.VerifySuccess(NativeMethods.OrtGetTensorElementType(handle, out IntPtr elementType)); + ElementDataType = (TensorElementType)elementType; + + NativeApiStatus.VerifySuccess(NativeMethods.OrtGetTensorShapeElementCount(handle, out UIntPtr count)); + ElementCount = (long)count; + + NativeApiStatus.VerifySuccess(NativeMethods.OrtGetDimensionsCount(handle, out UIntPtr dimCount)); + + Shape = new long[(uint)dimCount]; + NativeApiStatus.VerifySuccess(NativeMethods.OrtGetDimensions(handle, Shape, dimCount)); + } + + /// + /// Fetches tensor element data type + /// + /// enum value for the data type + public TensorElementType ElementDataType { get; private set; } + + /// + /// Returns true if this data element is a string + /// + public bool IsString + { + get + { + return ElementDataType == TensorElementType.String; + } + } + + /// + /// Fetches tensor element count based on the shape information. + /// + /// number of typed tensor elements + public long ElementCount { get; private set; } + + /// + /// Fetches shape dimension count (rank) for the tensor. + /// + /// dim count + public int DimensionsCount { get { return Shape.Length; } } + + /// + /// Tensor dimensions. + /// + /// array of dims + public long[] Shape { get; private set; } + } + + /// + /// Represents Sequence type information. + /// + public struct OrtSequenceOrOptionalTypeInfo + { + internal OrtSequenceOrOptionalTypeInfo(IntPtr handle) + { + NativeApiStatus.VerifySuccess(NativeMethods.OrtGetSequenceElementType(handle, out IntPtr typeInfo)); + try + { + ElementType = new OrtTypeInfo(typeInfo); + } + finally + { + NativeMethods.OrtReleaseTypeInfo(typeInfo); + } + } + + /// + /// Returns type information for the element type of the sequence + /// + /// OrtTypeInfo + public OrtTypeInfo ElementType { get; private set; } + } + + /// + /// Represents Map input/output information. + /// + /// Maps are represented at run time by a tensor of primitive types + /// and values are represented either by Tensor/Sequence/Optional or another map. + /// + public struct OrtMapTypeInfo + { + internal OrtMapTypeInfo(IntPtr handle) + { + NativeApiStatus.VerifySuccess(NativeMethods.OrtGetMapKeyType(handle, out IntPtr tensorElementType)); + KeyType = (TensorElementType)tensorElementType; + NativeApiStatus.VerifySuccess(NativeMethods.OrtGetMapValueType(handle, out IntPtr typeInfo)); + try + { + ValueType = new OrtTypeInfo(typeInfo); + } + finally + { + NativeMethods.OrtReleaseTypeInfo(typeInfo); + } + } + + /// + /// Returns KeyType which is the data type of the keys tensor + /// + /// OrtTypeInfo + public TensorElementType KeyType { get; private set; } + + /// + /// Returns an instance of OrtTypeInfo describing the value type for the map + /// + /// OrtTypeInfo + public OrtTypeInfo ValueType { get; private set; } + } +} diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/OrtValue.shared.cs b/csharp/src/Microsoft.ML.OnnxRuntime/OrtValue.shared.cs index 187996251c2a6..86b44a6784817 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/OrtValue.shared.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/OrtValue.shared.cs @@ -4,8 +4,10 @@ using Microsoft.ML.OnnxRuntime.Tensors; using System; using System.Buffers; +using System.Collections.Generic; using System.Diagnostics; using System.Runtime.InteropServices; +using System.Text; namespace Microsoft.ML.OnnxRuntime { @@ -26,153 +28,622 @@ public enum OnnxValueType /// /// Represents a disposable OrtValue. /// This class exposes a native instance of OrtValue. - /// The class implements IDisposable via SafeHandle and must - /// be disposed. + /// The class implements IDisposable and must + /// be disposed of, otherwise native resources will leak + /// and will eventually cause the application to slow down or crash. + /// + /// If the OrtValue instance is constructed over a managed memory, and it is not + /// disposed properly, the pinned memory will continue to be pinned and interfere + /// with GC operation. /// - public class OrtValue : SafeHandle + public class OrtValue : IOrtValueOwner, IDisposable { + // OrtValues that are members of Sequences or Maps that map. They potentially map managed memory and we need to keep them around. + // this exists only when we deal with compose ML types. + private DisposableList _compositeMembers; + private IntPtr _handle; + private MemoryHandle? _memHandle; // Present when the OrtValue is created on top of managed memory + private bool _disposed; + + internal OrtValue(IntPtr handle) + { + _handle = handle; + InitOnnxType(); + } + + /// + /// Constructor. The newly constructed OrtValue takes ownership of the native OrtValue instance + /// + /// + /// + /// thrown when onnxValue type is not known + internal OrtValue(IntPtr handle, OnnxValueType onnxValueType) + { + if (onnxValueType == OnnxValueType.ONNX_TYPE_UNKNOWN) + { + throw new ArgumentException("onnxValueType argument is passed as unknown"); + } + + _handle = handle; + OnnxType = onnxValueType; + } + + /// + /// Constructor. The newly constructed OrtValue takes ownership of the native OrtValue instance + /// and disposes of it when the OrtValue instance is disposed. The instance will take ownership and will + /// dispose of compositeMembers instances. + /// + /// This constructor can only throw if OnnxType is not specified. + /// + /// native ortValue handle + /// must one of the valid types + /// For composite types this contains dependent ortValues such as members of a sequence + /// or keys/values for the map, that may have been created on top of the managed memory and must be disposed + /// with the new ortValue. This container will be taken the ownership of and the argument will be set to null. + /// throws when onnxValueType is not specified + internal OrtValue(IntPtr handle, OnnxValueType onnxValueType, ref DisposableList compositeMembers) + { + if (onnxValueType == OnnxValueType.ONNX_TYPE_UNKNOWN) + { + throw new ArgumentException("onnxValueType argument is passed as unknown"); + } + + _handle = handle; + OnnxType = onnxValueType; + _compositeMembers = compositeMembers; + compositeMembers = null; + } + /// - /// Use factory methods to instantiate this class + /// Constructor to construct OrtValue over managed memory. + /// We pin the memory and unpin it at the disposal time. + /// The newly constructed OrtValue takes ownership of the native OrtValue instance + /// and disposes of it when the OrtValue instance is disposed. /// /// Pointer to a native instance of OrtValue - /// Default true, own the raw handle. Otherwise, the handle is owned by another instance - /// However, we use this class to expose OrtValue that is owned by DisposableNamedOnnxValue + /// memory handle to a pinned user supplied (usually managed) memory + /// It is disposed of (unpinned) when OrtValue is disposed. /// - internal OrtValue(IntPtr handle, bool owned = true) - : base(handle, true) + private OrtValue(IntPtr handle, MemoryHandle memHandle) { - IsOwned = owned; + _handle = handle; + _memHandle = memHandle; + // OrtValue on top of the pinned memory is always a tensor + OnnxType = OnnxValueType.ONNX_TYPE_TENSOR; } - internal IntPtr Handle { get { return handle; } } + /// + /// Native handle to OrtValue for internal use. + /// + internal IntPtr Handle { get { return _handle; } } /// - /// Overrides SafeHandle.IsInvalid + /// Implement IOrtValueOwner interface /// - /// returns true if handle is equal to Zero - public override bool IsInvalid { get { return handle == IntPtr.Zero; } } + /// returns this + public OrtValue Value => this; - #region NamedOnnxValue/DisposableOnnxValue accommodations + /// + /// Fetches OrtValue type if it has one. + /// + /// OnnxValueType + public OnnxValueType OnnxType { get; private set; } + + private void InitOnnxType() + { + NativeApiStatus.VerifySuccess(NativeMethods.OrtGetValueType(Handle, out IntPtr onnxType)); + OnnxType = (OnnxValueType)onnxType; + } /// - /// This internal interface is used to transfer ownership elsewhere. - /// This instance must still be disposed in case there are other native - /// objects still owned. This is a convenience method to ensure that an underlying - /// OrtValue is disposed exactly once when exception is thrown. + /// Returns true if OrtValue contains a tensor /// - /// - internal IntPtr Disown() + /// true if tensor + public bool IsTensor { - var ret = Handle; - handle = IntPtr.Zero; - IsOwned = false; - return ret; + get + { + return OnnxType == OnnxValueType.ONNX_TYPE_TENSOR; + } } - internal bool IsOwned { get; private set; } + /// + /// Returns true if OrtValue contains a sparse tensor + /// + /// true if sparse tensor + public bool IsSparseTensor + { + get + { + return OnnxType == OnnxValueType.ONNX_TYPE_SPARSETENSOR; + } + } - #endregion + /// + /// Valid for composite ML types like map, sequence. + /// Returns 2 for map (keys, values) and N for sequence, where N is the number of elements + /// in the sequence. + /// + /// Element count + public int GetValueCount() + { + NativeApiStatus.VerifySuccess(NativeMethods.OrtGetValueCount(Handle, out IntPtr count)); + return (int)count; + } + + /// + /// For non tensors return OrtValue element at the specified index. + /// For maps only indices 0 and 1 are valid. For sequences, [0..N) are valid. + /// See GetValueCount() to determine the valid range. + /// + /// + /// allocator to use + /// OrtValue disposable instance that points to the corresponding element of the composite type + public OrtValue GetValue(int index, OrtAllocator allocator) + { + NativeApiStatus.VerifySuccess(NativeMethods.OrtGetValue(Handle, index, + allocator.Pointer, out IntPtr ortValueHandle)); + return new OrtValue(ortValueHandle); + } + + /// + /// Returns a ReadOnlySpan over tensor native buffer that + /// provides a read-only view. + /// + /// Note, that the memory may be device allocated and, therefore, not accessible from the CPU. + /// To get memory descriptor use GetTensorMemoryInfo(). + /// + /// OrtValue must contain a non-string tensor. + /// The span is valid as long as the OrtValue instance is alive (not disposed). + /// + /// + /// ReadOnlySpan + /// + public ReadOnlySpan GetTensorDataAsSpan() where T : unmanaged + { + var byteSpan = GetTensorBufferRawData(typeof(T)); + return MemoryMarshal.Cast(byteSpan); + } + + /// + /// Returns a Span over tensor native buffer. + /// This enables you to safely and efficiently modify the underlying + /// native buffer in a type-safe manner. This is useful for example in IOBinding scenarios + /// where you want to modify results of the inference and feed it back as input. + /// + /// Note, that the memory may be device allocated. + /// To get memory descriptor use GetTensorMemoryInfo(). + /// + /// OrtValue must contain a non-string tensor. + /// The span is valid as long as the OrtValue instance is alive (not disposed). + /// + /// + /// Typed Span over the native buffer + public Span GetTensorMutableDataAsSpan() where T : unmanaged + { + var byteSpan = GetTensorBufferRawData(typeof(T)); + return MemoryMarshal.Cast(byteSpan); + } + + /// + /// Provides mutable raw native buffer access. + /// + /// Span over the native buffer bytes + public Span GetTensorMutableRawData() + { + return GetTensorBufferRawData(typeof(byte)); + } + + /// + /// Fetch string tensor element buffer pointer at the specified index, + /// convert/copy to UTF-16 char[] and return a ReadOnlyMemory instance. + /// + /// Obtain TensorTypeAndShape to get shape and element count. + /// + /// flat string tensor element index + /// ReadOnlyMemory backed by a managed char[]. Its lifespan is not + /// tied to the native buffer of OrtValue. + public ReadOnlyMemory GetStringElementAsMemory(int index) + { + var chars = GetStringTensorElementChars(index); + if (chars.Length == 0) + { + return ReadOnlyMemory.Empty; + } + return new ReadOnlyMemory(chars); + } + + /// + /// Fetch string tensor element buffer pointer at the specified index, + /// copy/convert UTF-8 into a UTF-16 string and return it. + /// + /// Obtain TensorTypeAndShape to get shape and element count. + /// + /// flat string tensor element index + /// UTF-16 string instance + public string GetStringElement(int index) + { + var chars = GetStringTensorElementChars(index); + if (chars.Length == 0) + { + return string.Empty; + } + return new string(chars); + } + + + /// + /// Get a span over the native memory of the string tensor element. + /// The span is valid as long as the OrtValue is valid. + /// + /// This is useful if you want to perform your own UTF-8 decoding or + /// you do not care about decoding. + /// Obtain TensorTypeAndShape to get shape and element count. + /// + /// flat element index + /// ReadOnlySpan over UTF-8 bytes of the string tensor element + public ReadOnlySpan GetStringElementAsSpan(int index) + { + GetStringTensorElementBuffer((UIntPtr)index, out uint bytesLen, out IntPtr bufferPtr); + if (bytesLen == 0) + { + return ReadOnlySpan.Empty; + } + unsafe + { + return new ReadOnlySpan((bufferPtr).ToPointer(), (int)bytesLen); + } + } + + /// + /// Convenience method to obtain all string tensor elements as a string array. + /// + /// string[] + /// + public string[] GetStringTensorAsArray() + { + GetTensorElementTypeAndCount(out long count, out TensorElementType elementType); + if (elementType != TensorElementType.String) + { + throw new OnnxRuntimeException( + ErrorCode.Fail, + $"GetStringTensorAsArray() is only supported for string tensors. This OrtValue contains a {elementType} tensor."); + } + + var strings = new string[count]; + for (int i = 0; i < count; i++) + { + strings[i] = GetStringElement(i); + } + return strings; + } + + /// + /// Creates and fetches Type information about the contained OnnxValue. + /// + /// a disposable instance of OrtTypeInfo + public OrtTypeInfo GetTypeInfo() + { + NativeApiStatus.VerifySuccess(NativeMethods.OrtGetTypeInfo(Handle, out IntPtr typeInfo)); + try + { + return new OrtTypeInfo(typeInfo); + } + finally + { + NativeMethods.OrtReleaseTypeInfo(typeInfo); + } + } + + /// + /// Obtains Tensor And Type Information from the OrtValue iff it contains a tensor. + /// Valid only for OrtValues that contain a tensor. + /// + /// A disposable instance of OrtTensorTypeAndShapeInfo + public OrtTensorTypeAndShapeInfo GetTensorTypeAndShape() + { + var onnxType = OnnxType; + if (onnxType != OnnxValueType.ONNX_TYPE_TENSOR && + onnxType != OnnxValueType.ONNX_TYPE_SPARSETENSOR) + { + throw new OnnxRuntimeException(ErrorCode.InvalidArgument, + $"This OrtValue type contains: {onnxType}, not a tensor or sparse tensor"); + } + + NativeMethods.OrtGetTensorTypeAndShape(Handle, out IntPtr typeAndShapeInfo); + try + { + return new OrtTensorTypeAndShapeInfo(typeAndShapeInfo); + } + finally + { + NativeMethods.OrtReleaseTensorTypeAndShapeInfo(typeAndShapeInfo); + } + } + + /// + /// Returns OrtMemoryInfo iff this OrtValue contains a tensor or a sparse tensor. + /// + /// OrtMemoryInfo that describes the underlying memory allocation + /// + public OrtMemoryInfo GetTensorMemoryInfo() + { + var onnxType = OnnxType; + if (onnxType != OnnxValueType.ONNX_TYPE_TENSOR && + onnxType != OnnxValueType.ONNX_TYPE_SPARSETENSOR) + { + throw new OnnxRuntimeException(ErrorCode.InvalidArgument, + $"This OrtValue type contains: {onnxType}, not a tensor or sparse tensor"); + } + NativeMethods.OrtGetTensorMemoryInfo(Handle, out IntPtr memoryInfo); + return new OrtMemoryInfo(memoryInfo, false); + } + + private void GetTensorElementTypeAndCount(out long count, out TensorElementType elementType) + { + NativeApiStatus.VerifySuccess(NativeMethods.OrtGetTensorTypeAndShape(Handle, out IntPtr typeAndShapeInfo)); + try + { + NativeApiStatus.VerifySuccess(NativeMethods.OrtGetTensorElementType(typeAndShapeInfo, out IntPtr elType)); + NativeApiStatus.VerifySuccess(NativeMethods.OrtGetTensorShapeElementCount(typeAndShapeInfo, out UIntPtr cnt)); + elementType = (TensorElementType)elType; + count = (long)cnt; + } + finally + { + NativeMethods.OrtReleaseTensorTypeAndShapeInfo(typeAndShapeInfo); + } + } + + private char[] GetStringTensorElementChars(int index) + { + GetStringTensorElementBuffer((UIntPtr)index, out uint bytesLen, out IntPtr bufferPtr); + if (bytesLen == 0) + { + return Array.Empty(); + } + + unsafe + { + int charCount = Encoding.UTF8.GetCharCount((byte*)(bufferPtr).ToPointer(), (int)bytesLen); + var chars = new char[charCount]; + fixed (char* ch = chars) + { + Encoding.UTF8.GetChars((byte*)(bufferPtr).ToPointer(), (int)bytesLen, (char*)ch, charCount); + } + return chars; + } + } + + private void GetStringTensorElementBuffer(UIntPtr index, out uint bytesLen, out IntPtr bufferPtr) + { + // Length is in UTF-8 bytes. Strings are not zero terminated, so length is required. + NativeApiStatus.VerifySuccess(NativeMethods.OrtGetStringTensorElementLength(Handle, index, out UIntPtr bufferLen)); + + bytesLen = (uint)bufferLen; + + if (bytesLen == 0) + { + bufferPtr = IntPtr.Zero; + return; + } + + // XXX: We lack the API (at the moment) that simply gives access to string element buffer. So we get the resized one + // to the same length which leaves it unchanged. + NativeApiStatus.VerifySuccess(NativeMethods.OrtGetResizedStringTensorElementBuffer(Handle, + (UIntPtr)index, bufferLen, out bufferPtr)); + } + + private Span GetTensorBufferRawData(Type requestedType) + { + if (OnnxType != OnnxValueType.ONNX_TYPE_TENSOR) + { + throw new OnnxRuntimeException(ErrorCode.InvalidArgument, + $"This OrtValue type contains: {OnnxType}, not a tensor"); + } + + GetTensorElementTypeAndCount(out long count, out TensorElementType elementType); + + if (elementType == TensorElementType.String) + { + throw new OnnxRuntimeException(ErrorCode.InvalidArgument, "Strings are not supported by this API"); + } + + var typeInfo = TensorBase.GetElementTypeInfo(elementType) ?? + throw new OnnxRuntimeException(ErrorCode.InvalidArgument, $"Element type: {elementType} is not registered type."); + + // We are always Ok with byte + if (requestedType != typeof(byte) && requestedType != typeInfo.TensorType) + { + throw new OnnxRuntimeException(ErrorCode.InvalidArgument, + $"Requested type: {requestedType} does not match the actual type: {typeInfo.TensorType}"); + } + + if (count == 0) + { + return Span.Empty; + } + + NativeApiStatus.VerifySuccess(NativeMethods.OrtGetTensorMutableData(Handle, out IntPtr tensorData)); + + var bufferLenInBytes = count * typeInfo.TypeSize; + + unsafe + { + return new Span(tensorData.ToPointer(), (int)bufferLenInBytes); + } + } /// /// Factory method to construct an OrtValue of Tensor type on top of pre-allocated memory. - /// This can be a piece of native memory allocated by OrtAllocator (possibly on a device) - /// or a piece of pinned managed memory. + /// This can be a piece of arbitrary memory that may be allocated by OrtAllocator (possibly on a device), + /// a chunk of managed memory (must be pinned for the duration of OrtValue lifetime) or a memory that is allocated + /// natively allocated using Marshal.AllocHGlobal(), stackalloc or other means (may be on a device). /// /// The resulting OrtValue does not own the underlying memory buffer and will not attempt to - /// deallocate it. + /// deallocate it. The caller must make sure that the memory remains valid for the duration of OrtValue lifetime. /// - /// Memory Info. For managed memory it is a default cpu. - /// For Native memory must be obtained from the allocator or OrtMemoryAllocation instance + /// Memory Info. For managed memory its default is cpu. + /// For other kinds of memory, one must construct as appropriate. /// DataType for the Tensor - /// Tensor shape - /// Pointer to a raw memory buffer - /// Buffer length in bytes + /// shape of the tensor to create. The size required by the shape + /// must be less of equal of the memory.Length + /// Pointer to a raw memory buffer which may reside on a device + /// Buffer length in bytes /// A disposable instance of OrtValue public static OrtValue CreateTensorValueWithData(OrtMemoryInfo memInfo, TensorElementType elementType, long[] shape, - IntPtr dataBuffer, - long bufferLength) + IntPtr dataBufferPtr, + long bufferLengthInBytes) { - Type type; - int width; - if (!TensorElementTypeConverter.GetTypeAndWidth(elementType, out type, out width)) + var typeInfo = TensorBase.GetElementTypeInfo(elementType) ?? throw new OnnxRuntimeException(ErrorCode.InvalidArgument, + $"Tensor element type: {elementType} is not supported"); + if (typeInfo.IsString) { throw new OnnxRuntimeException(ErrorCode.InvalidArgument, - "Unable to query type information for data type: " + elementType.ToString()); + "Cannot map managed strings buffer to native OrtValue. Use string specific interfaces"); } - if (elementType == TensorElementType.String) - { - throw new OnnxRuntimeException(ErrorCode.InvalidArgument, - "Cannot map managed strings buffer to native OrtValue"); - } + var shapeSize = ShapeUtils.GetSizeForShape(shape); + var requiredBufferSizeInBytes = shapeSize * typeInfo.TypeSize; - var shapeSize = ArrayUtilities.GetSizeForShape(shape); - var requiredBufferSize = shapeSize * width; - if (requiredBufferSize > bufferLength) + // We allow creating a tensor over part of the buffer + if (requiredBufferSizeInBytes > bufferLengthInBytes) { - var message = String.Format("Shape of: {0} elements requires a buffer of at least {1} bytes. Provided: {2} bytes", - shapeSize, requiredBufferSize, bufferLength); - throw new OnnxRuntimeException(ErrorCode.InvalidArgument, message); + throw new OnnxRuntimeException(ErrorCode.InvalidArgument, + $"Shape: {shape} has: {shapeSize} elements requires a buffer of at least {requiredBufferSizeInBytes} bytes. Provided: {bufferLengthInBytes} bytes"); } - IntPtr ortValueHandle = IntPtr.Zero; NativeApiStatus.VerifySuccess(NativeMethods.OrtCreateTensorWithDataAsOrtValue( memInfo.Pointer, - dataBuffer, - (UIntPtr)bufferLength, + dataBufferPtr, + (UIntPtr)bufferLengthInBytes, shape, (UIntPtr)shape.Length, elementType, - out ortValueHandle + out IntPtr ortValueHandle )); - return new OrtValue(ortValueHandle); + return new OrtValue(ortValueHandle, OnnxValueType.ONNX_TYPE_TENSOR); } /// - /// This is a factory method creates a native Onnxruntime OrtValue containing a tensor. - /// The method will attempt to pin managed memory so no copying occurs when data is passed down - /// to native code. + /// This is a factory method that creates an OrtValue of Tensor type on top of Memory memory. + /// The API pins the memory for the duration of the OrtValue lifetime. + /// It is unpinned at disposal time. /// - /// Tensor object - /// For all tensor types but string tensors we endeavor to use managed memory - /// to avoid additional allocation and copy. This out parameter represents a chunk of pinned memory which will need - /// to be disposed when no longer needed. The lifespan of memoryHandle should eclipse the lifespan of the corresponding - /// OrtValue. - /// - /// discovered tensor element type - /// And instance of OrtValue constructed on top of the object - public static OrtValue CreateFromTensorObject(Object value, out MemoryHandle? memoryHandle, - out TensorElementType elementType) + /// T must be one of the supported types + /// Memory information that describes memory location + /// contiguous region of memory + /// shape of the tensor to create. The size required by the shape + /// must be less of equal of the memory.Length + /// A disposable OrtValue instance + /// + public static OrtValue CreateTensorValueFromMemory(OrtMemoryInfo memoryInfo, Memory memory, long[] shape) + where T : unmanaged { - // Check if this is a Tensor - if (!(value is TensorBase)) + var typeInfo = TensorBase.GetTypeInfo(typeof(T)) ?? + throw new OnnxRuntimeException(ErrorCode.InvalidArgument, $"Tensor of type: {typeof(T)} is not supported"); + + if (typeInfo.IsString) { - throw new NotSupportedException("The inference value " + nameof(value) + " is not of a supported type"); + throw new OnnxRuntimeException(ErrorCode.InvalidArgument, + "Cannot map managed strings buffer to native OrtValue. Use string specific interfaces."); } - var tensorBase = value as TensorBase; - var typeInfo = tensorBase.GetTypeInfo(); - if (typeInfo == null) + var shapeSize = ShapeUtils.GetSizeForShape(shape); + // We allow creating a tensor over part of the buffer + if (shapeSize > memory.Length) { - throw new OnnxRuntimeException(ErrorCode.RequirementNotRegistered, "BUG Check"); + throw new OnnxRuntimeException(ErrorCode.InvalidArgument, + $"Managed memory size: {memory.Length} elements is less than shape size: {shapeSize} elements"); } - MemoryHandle? memHandle; + var bufferLengthInBytes = memory.Length * typeInfo.TypeSize; + var memoryHandle = memory.Pin(); + try + { + IntPtr bufferPtr; + unsafe + { + bufferPtr = new IntPtr(memoryHandle.Pointer); + } + + NativeApiStatus.VerifySuccess(NativeMethods.OrtCreateTensorWithDataAsOrtValue( + memoryInfo.Pointer, + bufferPtr, + (UIntPtr)bufferLengthInBytes, + shape, + (UIntPtr)shape.Length, + typeInfo.ElementType, + out IntPtr ortValueHandle + )); + return new OrtValue(ortValueHandle, memoryHandle); + } + catch (Exception) + { + memoryHandle.Dispose(); + throw; + } + + } + + /// + /// This is a factory method that creates an OrtValue of Tensor type on top managed data array. + /// The API pins the memory for the duration of the OrtValue lifetime. + /// It is unpinned at disposal time. + /// + /// + /// managed data buffer + /// shape that describes the buffer + /// A disposable OrtValue instance + public static OrtValue CreateTensorValueFromMemory(T[] data, long[] shape) where T : unmanaged + { + return OrtValue.CreateTensorValueFromMemory(OrtMemoryInfo.DefaultInstance, new Memory(data), shape); + } + + /// + /// The factory API creates an OrtValue with memory allocated using the given allocator + /// according to the specified shape and element type. The memory will be released when OrtValue + /// is disposed. Use GetTensorMutableDataAsSpan<T>() API to fill in the data. + /// + /// + /// + /// + /// A disposable OrtValue + public static OrtValue CreateAllocatedTensorValue(OrtAllocator allocator, TensorElementType elementType, + long[] shape) + { + NativeApiStatus.VerifySuccess(NativeMethods.OrtCreateTensorAsOrtValue(allocator.Pointer, shape, + (UIntPtr)shape.Length, elementType, out IntPtr ortValueHandle)); + return new OrtValue(ortValueHandle, OnnxValueType.ONNX_TYPE_TENSOR); + } + + /// + /// This is a factory method creates a native Onnxruntime OrtValue containing a tensor. + /// The method will attempt to pin managed memory so no copying occurs when data is passed down + /// to native code. + /// + /// Tensor object + /// discovered tensor element type + /// And instance of OrtValue constructed on top of the object + internal static OrtValue CreateFromTensorObject(TensorBase value, out TensorElementType elementType) + { + var typeInfo = value.GetTypeInfo(); OrtValue ortValue = null; - int dataBufferLength = 0; - long[] shape = null; - int rank = 0; TensorElementType elType = typeInfo.ElementType; var typeSize = typeInfo.TypeSize; if (typeInfo.IsString) { - ortValue = CreateStringTensor(value as Tensor); - memHandle = null; + ortValue = CreateFromStringTensor(value as Tensor); } else { + int dataBufferLength; + long[] shape; + int rank; + + MemoryHandle memHandle; switch (elType) { case TensorElementType.Float: @@ -241,14 +712,12 @@ public static OrtValue CreateFromTensorObject(Object value, out MemoryHandle? me try { - Debug.Assert(memHandle.HasValue); IntPtr dataBufferPointer = IntPtr.Zero; unsafe { - dataBufferPointer = (IntPtr)((MemoryHandle)memHandle).Pointer; + dataBufferPointer = (IntPtr)memHandle.Pointer; } - IntPtr nativeValue; NativeApiStatus.VerifySuccess(NativeMethods.OrtCreateTensorWithDataAsOrtValue( OrtMemoryInfo.DefaultInstance.Pointer, dataBufferPointer, @@ -256,124 +725,583 @@ public static OrtValue CreateFromTensorObject(Object value, out MemoryHandle? me shape, (UIntPtr)rank, elType, - out nativeValue)); + out IntPtr nativeValue)); - ortValue = new OrtValue(nativeValue); + ortValue = new OrtValue(nativeValue, memHandle); } catch (Exception) { - memHandle?.Dispose(); + memHandle.Dispose(); throw; } } - memoryHandle = memHandle; + elementType = elType; return ortValue; } - private static void PinAsTensor( - Tensor tensor, - int elementSize, - out MemoryHandle? pinnedHandle, - out int dataBufferLength, - out long[] shape, - out int rank) + /// + /// Creates an OrtValue that contains a string tensor of specified shape, and + /// containing empty strings. String tensors are always on CPU. + /// Use StringTensorSetElementAt to assign individual elements values. + /// + /// + /// disposable OrtValue + /// tensor shape + public static OrtValue CreateTensorWithEmptyStrings(OrtAllocator allocator, long[] shape) + { + // allocate the native tensor + NativeApiStatus.VerifySuccess(NativeMethods.OrtCreateTensorAsOrtValue( + allocator.Pointer, + shape, + (UIntPtr)(shape.Length), + TensorElementType.String, + out IntPtr valueHandle + )); + return new OrtValue(valueHandle, OnnxValueType.ONNX_TYPE_TENSOR); + } + + /// + /// Converts the string argument represented by ReadOnlySpan to UTF-8, + /// allocates space in the native tensor and copies it into the native tensor memory. + /// Typically, this is used to populate a new empty string tensor element. + /// + /// The number of elements is according to the shape supplied to CreateTensorWithEmptyStrings(). + /// However, this API can also be used to overwrite any existing element within the string tensor. + /// + /// In general, to obtain the number of elements for any tensor, use GetTensorTypeAndShape() which + /// would return a disposable instance of TensorTypeAndShapeInfo. + /// Then call GetElementCount() or GetShape(). + /// + /// ReadOnlySpan over chars + /// index of the string element within the tensor + /// must be within bounds of [0, N) + public void StringTensorSetElementAt(ReadOnlySpan str, int index) + { + unsafe + { + fixed (char* strPtr = str) + { + FillStringTensorElement(strPtr, str.Length, index); + } + } + } + + /// + /// Converts the string argument represented by ReadOnlyMemory to UTF-8, + /// allocates space in the native tensor and copies it into the native tensor memory. + /// Typically, this is used to populate a new empty string tensor element. + /// + /// The number of elements is according to the shape supplied to CreateTensorWithEmptyStrings(). + /// However, this API can also be used to overwrite any existing element within the string tensor. + /// + /// In general, to obtain the number of elements for any tensor, use GetTensorTypeAndShape() which + /// would return a disposable instance of TensorTypeAndShapeInfo. + /// Then call GetElementCount() or GetShape(). + /// + /// + /// ReadOnlyMemory instance over an array of chars + /// index of the string element within the tensor + /// must be within bounds of [0, N) + public void StringTensorSetElementAt(ReadOnlyMemory rom, int index) + { + StringTensorSetElementAt(rom.Span, index); + } + + /// + /// This API resizes String Tensor element to the requested amount of bytes (UTF-8) + /// and copies the bytes from the supplied ReadOnlySpan into the native tensor memory (resized buffer). + /// + /// The API is useful for quick loading of utf8 data into the native tensor memory. + /// + /// read only span of bytes + /// flat index of the element in the string tensor + public void StringTensorSetElementAt(ReadOnlySpan utf8Bytes, int index) + { + NativeApiStatus.VerifySuccess(NativeMethods.OrtGetResizedStringTensorElementBuffer(Handle, + (UIntPtr)index, (UIntPtr)utf8Bytes.Length, out IntPtr buffer)); + + if (utf8Bytes.Length == 0) + { + return; + } + + unsafe + { + var destSpan = new Span(buffer.ToPointer(), utf8Bytes.Length); + utf8Bytes.CopyTo(destSpan); + } + } + + /// + /// Creates an OrtValue that contains a string tensor. + /// String tensors are always allocated on CPU. + /// String data will be converted to UTF-8 and copied to native memory. + /// + /// Note, this is different from creating an OrtValue from other primitive data types + /// where memory is pinned (if necessary) and the OrtValue points to that chunk of memory. + /// + /// Tensor + /// A disposable OrtValue instance + /// + public static OrtValue CreateFromStringTensor(Tensor tensor) { if (tensor == null) { - throw new OnnxRuntimeException(ErrorCode.Fail, "Cast to Tensor failed. BUG check!"); + throw new OnnxRuntimeException(ErrorCode.InvalidArgument, "Expecting a valid string tensor"); } - if (tensor.IsReversedStride) + long[] shape = Array.ConvertAll(tensor.Dimensions.ToArray(), Convert.ToInt64); + + var ortValue = CreateTensorWithEmptyStrings(OrtAllocator.DefaultInstance, shape); + try { - //TODO: not sure how to support reverse stride. may be able to calculate the shape differently - throw new NotSupportedException(nameof(Tensor) + " of reverseStride is not supported"); + var len = tensor.Length; + for (int i = 0; i < len; ++i) + { + var str = tensor.GetValue(i) ?? throw new ArgumentNullException($"Tensor contains null reference at index:{i}"); + unsafe + { + fixed (char* strPtr = str) + { + ortValue.FillStringTensorElement(strPtr, str.Length, i); + } + } + } } + catch (Exception) + { + ortValue.Dispose(); + throw; + } + return ortValue; + } - DenseTensor dt = null; - if (tensor is DenseTensor) + /// + /// Creates a sequence of OrtValues from a collection of OrtValues. + /// All OrtValues in the collection must be of the same Onnx type. + /// I.e. (Tensor, SparseTensor, Map, Sequence, etc.) + /// + /// The ortValues that are passed as argument are taken possession of by the newly + /// created OrtValue. The caller should not dispose them, unless this call fails. + /// + /// The ortValues would be empty on successful return. + /// + /// a collection of OrtValues. On success the ortValues contained in the list + /// are taken ownership of and the list is cleared. + /// A disposable instance of OrtValues + /// + public static OrtValue CreateSequence(ICollection ortValues) + { + if (ortValues is null) { - dt = tensor as DenseTensor; + throw new ArgumentNullException(nameof(ortValues)); } - else + + if (ortValues.IsReadOnly) { - dt = tensor.ToDenseTensor(); + throw new ArgumentException("ortValues argument can not be a readonly collection"); } - pinnedHandle = dt.Buffer.Pin(); - dataBufferLength = dt.Buffer.Length * elementSize; - shape = new long[dt.Dimensions.Length]; - for (int i = 0; i < dt.Dimensions.Length; ++i) + var compositeMembers = new DisposableList(ortValues); + try { - shape[i] = dt.Dimensions[i]; + var result = CreateSequence(ref compositeMembers); + Debug.Assert(compositeMembers is null, "Must be null on success"); + ortValues.Clear(); + return result; + } + catch (Exception) + { + // The caller is responsible for disposing the ortValues + compositeMembers?.Clear(); + throw; } - rank = dt.Rank; } - private static OrtValue CreateStringTensor(Tensor tensor) + /// + /// Creates a sequence from the values in compositeMembers + /// The argument is taken possession of and is nullified on successful return. + /// + /// sequence ortValues + /// OrtValue instance representing a Sequence + internal static OrtValue CreateSequence(ref DisposableList compositeMembers) { - if (tensor == null) + var handles = new IntPtr[compositeMembers.Count]; + for (int i = 0; i < compositeMembers.Count; i++) { - throw new OnnxRuntimeException(ErrorCode.Fail, "Cast to Tensor failed. BUG check!"); + handles[i] = compositeMembers[i].Handle; } - long[] shape = new long[tensor.Dimensions.Length]; - for (int i = 0; i < tensor.Dimensions.Length; i++) + NativeApiStatus.VerifySuccess(NativeMethods.OrtCreateValue(handles, + (UIntPtr)handles.Length, (IntPtr)OnnxValueType.ONNX_TYPE_SEQUENCE, + out IntPtr sequenceHandle)); + + return new OrtValue(sequenceHandle, OnnxValueType.ONNX_TYPE_SEQUENCE, ref compositeMembers); + } + + /// + /// A delegate type that is expected to process each OrtValue in a sequence. + /// + /// OrtValue that holds sequence element + /// ordinal of the value + public delegate void SequenceElementVisitor(OrtValue ortValue, int index); + + /// + /// Feeds each OrtValue in a sequence to the visitor delegate. + /// This helps users to avoid dealing each value life-span + /// + /// visitor delegate + /// allocator to use for intermediate ort values + /// + public void ProcessSequence(SequenceElementVisitor visitor, OrtAllocator allocator) + { + if (OnnxType != OnnxValueType.ONNX_TYPE_SEQUENCE) { - shape[i] = tensor.Dimensions[i]; + throw new OnnxRuntimeException(ErrorCode.InvalidArgument, + $"OrtValue.OnnxType of {OnnxType} is not a sequence"); } - // allocate the native tensor - NativeApiStatus.VerifySuccess(NativeMethods.OrtCreateTensorAsOrtValue( - OrtAllocator.DefaultInstance.Pointer, - shape, - (UIntPtr)(shape.Length), - TensorElementType.String, - out IntPtr valueHandle - )); + int count = GetValueCount(); + for (int i = 0; i < count; i++) + { + using var ortValue = GetValue(i, allocator); + visitor(ortValue, i); + } + } - // We must take possession of valueHande, so we can dispose of it if we fail - var ortValue = new OrtValue(valueHandle); + /// + /// Creates a map OrtValue with keys and values. + /// On a high level the Onnxruntime representation of the map always consists of two + /// OrtValues, keys and values. + /// + /// According to ONNX standard map keys can be unmanaged types only (or strings). + /// Those keys are contained in a single tensor within OrtValue keys. + /// + /// Map values, on the other hand, can be composite types. The values parameter + /// can either contain a single tensor with unmanaged map values with the same number of + /// elements as the keys, or it can be a sequence of OrtValues, + /// each of those can be a composite type (tensor, sequence, map). If it is a sequence, + /// then the number of elements must match the number of elements in keys. + /// + /// Keys and values must be in the same order. + /// + /// ORT supports only a subset of types for keys and values, however, this API does not + /// restrict it. + /// + /// The ortValues that are passed as argument are taken possession of by the newly + /// created OrtValue. The caller should not dispose them, unless this call fails. + /// + /// Keys and values arguments will be set to null on success. + /// + /// Contains keys + /// Contains values + /// A disposable OrtValue + /// + public static OrtValue CreateMap(ref OrtValue keys, ref OrtValue values) + { + if (keys is null || values is null) + { + throw new ArgumentNullException("keys or/and values are null"); + } + + IntPtr[] handles = { keys.Handle, values.Handle }; + NativeApiStatus.VerifySuccess( + NativeMethods.OrtCreateValue(handles, (UIntPtr)handles.Length, (IntPtr)OnnxValueType.ONNX_TYPE_MAP, + out IntPtr mapHandle)); + + var compositeMembers = new DisposableList + { + keys, + values + }; + + keys = null; + values = null; + + // This constructor will not throw. + return new OrtValue(mapHandle, OnnxValueType.ONNX_TYPE_MAP, ref compositeMembers); + } + + /// + /// This API helps to quickly creates a map OrtValue with unmanaged (primitive) keys and values specified as arrays. + /// This helps the user not to create OrtValues for keys and values separately and deal only with the final result. + /// The map would consist of two tensors, one for keys and one for values. + /// + /// The OrtValues would be created on top of the managed memory arrays and use it directly. + /// The number of elements in keys and values must be the same and they must be in order. + /// + /// The types must be unmanaged. + /// + /// keys type + /// values type + /// array of keys of K type + /// array of values of V type + /// OrtValue instance + /// + /// + public static OrtValue CreateMap(K[] keys, V[] values) where K : unmanaged where V : unmanaged + { + if (keys is null || values is null) + { + throw new ArgumentNullException("Keys or/and values are null"); + } + + if (keys.Length != values.Length) + { + throw new ArgumentException("Expecting keys and values same len. " + + $"Received keys: {keys.Length}, Values: {values.Length}"); + } + + long[] shape = { keys.Length }; + Span ortValues = new OrtValue[2]; + var disposableGuard = new DisposableArray(ortValues); try { - var len = tensor.Length; - for(int i = 0; i < len; ++i) + ortValues[0] = CreateTensorValueFromMemory(keys, shape); + ortValues[1] = CreateTensorValueFromMemory(values, shape); + return CreateMap(ref ortValues[0], ref ortValues[1]); + } + catch (Exception) + { + disposableGuard.Dispose(); + throw; + } + } + + /// + /// Creates a map OrtValue with string keys and non-string values. + /// This helps the user not to create OrtValues for keys and values separately. + /// The number of elements in keys and values must be the same and they must be in order. + /// The map would consist of two tensors, one for keys and one for values. + /// + /// string keys would be converted to UTF-8 encoding and copied to an allocated native memory. + /// The OrtValue for values would be created on top of the managed memory using it directly. + /// + /// The values type must be unmanaged. + /// + /// + /// Collection of strings + /// + /// OrtValue instance + /// + /// + public static OrtValue CreateMapWithStringKeys(IReadOnlyCollection keys, V[] values) where V : unmanaged + { + if (keys is null || values is null) + { + throw new ArgumentNullException("Keys or/and values are null"); + } + + if (keys.Count != values.Length) + { + throw new ArgumentException("Expecting keys and values same len. " + + $"Received keys: {keys.Count}, Values: {values.Length}"); + } + + long[] shape = { keys.Count }; + + Span ortValues = new OrtValue[2]; + var disposableGuard = new DisposableArray(ortValues); + try + { + ortValues[0] = CreateTensorWithEmptyStrings(OrtAllocator.DefaultInstance, shape); + int count = 0; + foreach (var key in keys) { - var str = tensor.GetValue(i); - var bytesCount = System.Text.Encoding.UTF8.GetByteCount(str); - NativeApiStatus.VerifySuccess(NativeMethods.OrtGetResizedStringTensorElementBuffer(valueHandle, - (UIntPtr)i, (UIntPtr)bytesCount, out IntPtr buffer)); - NativeOnnxValueHelper.StringToUtf8NativeMemory(str, buffer, bytesCount); + ortValues[0].StringTensorSetElementAt(key.AsSpan(), count++); } + + ortValues[1] = CreateTensorValueFromMemory(values, shape); + return CreateMap(ref ortValues[0], ref ortValues[1]); } catch (Exception) { - ortValue.Dispose(); + disposableGuard.Dispose(); throw; } - return ortValue; } - #region SafeHandle /// - /// Overrides SafeHandle.ReleaseHandle() to properly dispose of - /// the native instance of OrtValue + /// Creates a map OrtValue with non-string keys and string values. + /// + /// This helps the user not to create OrtValues for keys and values separately. + /// The number of elements in keys and values must be the same and they must be in order. + /// + /// The OrtValue for keys would be created on top of the managed memory using it directly. + /// string values would be converted to UTF-8 encoding and copied to an allocated native memory. + /// /// - /// always returns true - protected override bool ReleaseHandle() + /// unmanaged type of keys + /// + /// collection of string values + /// Instance of OrtValue + /// + /// + public static OrtValue CreateMapWithStringValues(K[] keys, IReadOnlyCollection values) where K : unmanaged { - // We have to surrender ownership to some legacy classes - // Or we never had that ownership to begin with - if (IsOwned) + if (keys is null || values is null) { - NativeMethods.OrtReleaseValue(handle); - IsOwned = false; + throw new ArgumentNullException("Keys or/and values are null"); + } + + if (keys.Length != values.Count) + { + throw new ArgumentException("Expecting keys and values same len. " + + $"Received keys: {keys.Length}, Values: {values.Count}"); + } + + long[] shape = { keys.Length }; + Span ortValues = new OrtValue[2]; + var disposableGuard = new DisposableArray(ortValues); + try + { + ortValues[0] = CreateTensorValueFromMemory(keys, shape); + ortValues[1] = CreateTensorWithEmptyStrings(OrtAllocator.DefaultInstance, shape); + int count = 0; + foreach (var value in values) + { + ortValues[1].StringTensorSetElementAt(value.AsSpan(), count++); + } + return CreateMap(ref ortValues[0], ref ortValues[1]); + } + catch (Exception) + { + disposableGuard.Dispose(); + throw; } - // Prevent use after disposal - handle = IntPtr.Zero; - return true; } - // No need for the finalizer + + /// + /// A public delegate that will be invoked once with map keys and values. + /// The delegate helps not to deal with the lifespan of intermediate OrtValues. + /// Typically, when one uses GetValue() API, it creates a copy of OrtValue + /// that points to the same buffer as keys or values. This API helps to deal with those + /// temporary instances and avoid leaks. + /// + /// According to ONNX standard map keys can be unmanaged types only (or strings). + /// Those keys are contained in a single tensor within OrtValue keys. So you can query those + /// directly from keys argument. + /// + /// Map values, on the other hand, can be composite types. The values parameter + /// can either contain a single tensor with unmanaged map values with the same number of + /// elements as the keys, or it can be a sequence of OrtValues, + /// each of those can be a composite type (tensor, sequence, map). If it is a sequence, + /// then the number of elements must match the number of elements in keys. + /// + /// Depending on the structure of the values, one will either directly query a single tensor + /// from values, or will have to iterate over the sequence of OrtValues and visit each of those + /// resulting in a recursive visitation. + /// + /// This would always represent a tensor + /// Can be any of the Onnx types, but they would all reduce to tensors eventually + public delegate void MapVisitor(OrtValue keys, OrtValue values); + + /// + /// This API helps the user to process a map OrtValue without + /// having to deal with the lifespan of intermediate OrtValues. + /// + /// each API value is fed to the vistor functor. + /// + /// visitor function + /// Allocator to use for intermediate values + /// + public void ProcessMap(MapVisitor visitor, OrtAllocator allocator) + { + if (OnnxType != OnnxValueType.ONNX_TYPE_MAP) + { + throw new OnnxRuntimeException(ErrorCode.InvalidArgument, "This OrtValue does not represent a map"); + } + + using var keys = GetValue(0, allocator); + using var values = GetValue(1, allocator); + visitor(keys, values); + } + + private unsafe void FillStringTensorElement(char* strPtr, int strLength, int index) + { + IntPtr buffer; + if (strLength == 0) + { + NativeApiStatus.VerifySuccess(NativeMethods.OrtGetResizedStringTensorElementBuffer(Handle, + (UIntPtr)index, UIntPtr.Zero, out buffer)); + return; + } + + var bytesCount = Encoding.UTF8.GetByteCount(strPtr, strLength); + NativeApiStatus.VerifySuccess(NativeMethods.OrtGetResizedStringTensorElementBuffer(Handle, + (UIntPtr)index, (UIntPtr)bytesCount, out buffer)); + NativeOnnxValueHelper.StringToUtf8NativeMemory(strPtr, strLength, buffer, bytesCount); + } + + private static void PinAsTensor( + Tensor tensor, + int elementSize, + out MemoryHandle pinnedHandle, + out int dataBufferLength, + out long[] shape, + out int rank) + { + if (tensor == null) + { + throw new OnnxRuntimeException(ErrorCode.Fail, "Cast to Tensor failed. BUG check!"); + } + + if (tensor.IsReversedStride) + { + //TODO: not sure how to support reverse stride. may be able to calculate the shape differently + throw new NotSupportedException(nameof(Tensor) + " of reverseStride is not supported"); + } + + DenseTensor dt = tensor as DenseTensor ?? tensor.ToDenseTensor(); + shape = Array.ConvertAll(dt.Dimensions.ToArray(), Convert.ToInt64); + rank = dt.Rank; + + dataBufferLength = dt.Buffer.Length * elementSize; + pinnedHandle = dt.Buffer.Pin(); + } + + #region IDisposable Support + + ~OrtValue() + { + Dispose(false); + } + + /// + /// IDisposable implementation + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// IDisposable implementation + /// + /// true if invoked from Dispose() method + protected virtual void Dispose(bool disposing) + { + if (_disposed) + { + return; + } + + if (disposing) + { + _memHandle?.Dispose(); + _memHandle = null; + _compositeMembers?.Dispose(); + _compositeMembers = null; + } + + Debug.Assert(_handle != IntPtr.Zero); + NativeMethods.OrtReleaseValue(_handle); + _handle = IntPtr.Zero; + _disposed = true; + } + #endregion } } diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/OrtValueTensor.shared.cs b/csharp/src/Microsoft.ML.OnnxRuntime/OrtValueTensor.shared.cs index ba7cacd54f233..1a7f24c48b920 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/OrtValueTensor.shared.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/OrtValueTensor.shared.cs @@ -4,9 +4,6 @@ using Microsoft.ML.OnnxRuntime.Tensors; using System; using System.Buffers; -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Text; namespace Microsoft.ML.OnnxRuntime { @@ -23,25 +20,31 @@ internal interface IOrtValueOwner : IDisposable /// This class is used in conjunction with DisposableNamedOnnxValue to /// own native collection OrtValue and dispose of it along with any DisposableNamedOnnxValues /// - internal class NativeOrtValueCollectionOwner : IOrtValueOwner, IDisposable - where T : IDisposable + internal class NativeOrtValueCollectionOwner : IOrtValueOwner, IDisposable { private OrtValue _ortValue; - private DisposableList _disposables; + private IDisposable _disposables; bool _disposed = false; - internal NativeOrtValueCollectionOwner(OrtValue ortValue, DisposableList disposables) + /// + /// _Ctor. Takes ownership of ortValue and sets it to null on success. + /// + /// becomes null on success + /// A collection of disposables that support composed types. + /// We stick them here and dispose them when this instance is disposed. + /// + internal NativeOrtValueCollectionOwner(ref OrtValue ortValue, IDisposable disposables) { - Debug.Assert(ortValue.IsOwned); - _ortValue = new OrtValue(ortValue.Disown()); + _ortValue = ortValue; + ortValue = null; _disposables = disposables; } #region IOrtValueOwner /// - /// Returns a non-owning ortValue + /// Returns OrtValue that is owned by this instance /// - public OrtValue Value { get { return new OrtValue(_ortValue.Handle, false); } } + public OrtValue Value { get { return _ortValue; } } #endregion IOrtValueOwner #region Disposable @@ -85,113 +88,51 @@ public void Dispose() /// It is easy to expose as a Tensor as DenseTensor can take Memory Mapping from /// this. /// - /// This class is disposable because of the MemoryManager inheritance + /// This class is disposable because of the MemoryManager inheritance. Because this class + /// always backs exactly only one DenseTensor instance, it does + /// not implement ref-counting for Pin/Unpin. /// /// internal class OrtValueTensor : MemoryManager, IOrtValueOwner { private OrtValue _ortValue; // Disposable private readonly IntPtr _dataBufferPointer; // pointer to mutable tensor data in native memory - private readonly string[] _dataBufferAsString; // string tensor values copied into managed memory /// /// Constructs an instance and takes ownership of ortValue on success /// - /// ortValue that is a Tensor - public OrtValueTensor(OrtValue ortValue) + /// ortValue that is a Tensor. It becomes null on successful return. + public OrtValueTensor(ref OrtValue ortValue) { - Type type = null; - int width = 0; - IntPtr typeAndShape = IntPtr.Zero; - NativeApiStatus.VerifySuccess(NativeMethods.OrtGetTensorTypeAndShape(ortValue.Handle, out typeAndShape)); - try - { - TensorElementType elemType; - { - IntPtr el_type; - NativeApiStatus.VerifySuccess(NativeMethods.OrtGetTensorElementType(typeAndShape, out el_type)); - elemType = (TensorElementType)el_type; - } + var typeAndShapeInfo = ortValue.GetTensorTypeAndShape(); + TensorElementType elemType = typeAndShapeInfo.ElementDataType; - if (!TensorElementTypeConverter.GetTypeAndWidth(elemType, out type, out width)) - { - throw new OnnxRuntimeException(ErrorCode.InvalidArgument, - "Unable to query type information for data type: " + elemType.ToString()); - } + var typeInfo = TensorBase.GetElementTypeInfo(elemType) ?? throw new OnnxRuntimeException(ErrorCode.InvalidArgument, + $"Unable to query type information for data type: {elemType}"); - if (typeof(T) != type) - { - var message = String.Format("The OrtValueTensor type being instantiated for T = : {0} while supplied OrtValue contains T = {1}", - typeof(T), type); - throw new OnnxRuntimeException(ErrorCode.InvalidArgument, message); - } - - ElementType = elemType; - ElementWidth = width; - UIntPtr dimension; - long count; - NativeApiStatus.VerifySuccess(NativeMethods.OrtGetDimensionsCount(typeAndShape, out dimension)); - { - IntPtr el_count; - NativeApiStatus.VerifySuccess(NativeMethods.OrtGetTensorShapeElementCount(typeAndShape, out el_count)); // count can be negative. - count = (long)el_count; - } - if (count < 0) - { - throw new NotSupportedException("Symbolic dimensions in the tensor is not supported"); - } - - long[] shape = new long[dimension.ToUInt64()]; - NativeApiStatus.VerifySuccess(NativeMethods.OrtGetDimensions(typeAndShape, shape, dimension)); //Note: shape must be alive during the call - - Count = (int)count; - Dimensions = new int[dimension.ToUInt64()]; - for (ulong i = 0; i < dimension.ToUInt64(); i++) - { - Dimensions[i] = (int)shape[i]; - } + if (typeof(T) != typeInfo.TensorType) + { + throw new OnnxRuntimeException(ErrorCode.InvalidArgument, + $"The OrtValueTensor type being instantiated for T = [{typeof(T)}] while supplied OrtValue contains T = [{typeInfo.TensorType}]"); + } - if (elemType != TensorElementType.String) - { - NativeApiStatus.VerifySuccess(NativeMethods.OrtGetTensorMutableData(ortValue.Handle, out _dataBufferPointer)); - } - else - { - var offsets = new UIntPtr[Count]; - NativeApiStatus.VerifySuccess(NativeMethods.OrtGetStringTensorDataLength(ortValue.Handle, out UIntPtr strLen)); - var dataBuffer = new byte[strLen.ToUInt64()]; + ElementType = elemType; + ElementWidth = typeInfo.TypeSize; + Count = (int)typeAndShapeInfo.ElementCount; - NativeApiStatus.VerifySuccess( - NativeMethods.OrtGetStringTensorContent( - ortValue.Handle, dataBuffer, strLen, - offsets, - (UIntPtr)Count)); + Dimensions = Array.ConvertAll(typeAndShapeInfo.Shape, Convert.ToInt32); - _dataBufferAsString = new string[Count]; + NativeApiStatus.VerifySuccess(NativeMethods.OrtGetTensorMutableData(ortValue.Handle, out _dataBufferPointer)); - for (var i = 0; i < offsets.Length; i++) - { - var length = (i == offsets.Length - 1) - ? strLen.ToUInt64() - offsets[i].ToUInt64() - : offsets[i + 1].ToUInt64() - offsets[i].ToUInt64(); - // ORT API specifies strings always in UTF-8, no trailing null, no leading BOM - _dataBufferAsString[i] = Encoding.UTF8.GetString(dataBuffer, (int)offsets[i], (int)length); - } - } - // Transfer ownership - _ortValue = new OrtValue(ortValue.Disown()); - } - finally - { - NativeMethods.OrtReleaseTensorTypeAndShapeInfo(typeAndShape); - } + // Transfer ownership + _ortValue = ortValue; + ortValue = null; } /// - /// Returns a non-owning copy of OrtValue so the - /// result can not release native memory + /// Returns OrtValue that is owned by this instance /// - public OrtValue Value { get { return new OrtValue(_ortValue.Handle, false); } } + public OrtValue Value { get { return _ortValue; } } public bool IsDisposed { get; private set; } = false; @@ -206,13 +147,11 @@ public OrtValueTensor(OrtValue ortValue) public Tensors.TensorElementType ElementType { get; } /// - /// Used by MemoryManager to produce Memory Property + /// Returns Span that is a view into the underlying native Tensor memory /// /// SpanT public override Span GetSpan() { - if (IsDisposed) - throw new ObjectDisposedException(nameof(OrtValueTensor)); Span span = null; unsafe { @@ -221,25 +160,14 @@ public override Span GetSpan() return span; } - public Memory GetBytesAsStringMemory() - { - if (IsDisposed) - throw new ObjectDisposedException(nameof(OrtValueTensor)); - - if (typeof(T) != typeof(string)) - throw new NotSupportedException(nameof(OrtValueTensor.GetBytesAsStringMemory) + ": T must be byte"); - - return (_dataBufferAsString == null) ? new Memory() : new Memory(_dataBufferAsString); - } /// - /// Satisfy MemoryManager abstract implementation + /// Satisfy MemoryManager abstract implementation. /// - /// + /// required for override /// public override MemoryHandle Pin(int elementIndex = 0) { - //Note: always pin the full buffer and return unsafe { if (elementIndex >= Count) diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/ProviderOptions.shared.cs b/csharp/src/Microsoft.ML.OnnxRuntime/ProviderOptions.shared.cs index da46c5f9430ff..e2c8a44d92dc7 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/ProviderOptions.shared.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/ProviderOptions.shared.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Runtime.InteropServices; namespace Microsoft.ML.OnnxRuntime @@ -46,7 +45,7 @@ public string GetOptions() { var allocator = OrtAllocator.DefaultInstance; // Process provider options string - NativeApiStatus.VerifySuccess(NativeMethods.OrtGetTensorRTProviderOptionsAsString(handle, + NativeApiStatus.VerifySuccess(NativeMethods.OrtGetTensorRTProviderOptionsAsString(handle, allocator.Pointer, out IntPtr providerOptions)); return NativeOnnxValueHelper.StringFromNativeUtf8(providerOptions, allocator); } @@ -151,7 +150,7 @@ public string GetOptions() { var allocator = OrtAllocator.DefaultInstance; // Process provider options string - NativeApiStatus.VerifySuccess(NativeMethods.OrtGetCUDAProviderOptionsAsString(handle, + NativeApiStatus.VerifySuccess(NativeMethods.OrtGetCUDAProviderOptionsAsString(handle, allocator.Pointer, out IntPtr providerOptions)); return NativeOnnxValueHelper.StringFromNativeUtf8(providerOptions, allocator); } @@ -206,6 +205,92 @@ protected override bool ReleaseHandle() } + /// + /// Holds the options for configuring a ROCm Execution Provider instance + /// + public class OrtROCMProviderOptions : SafeHandle + { + internal IntPtr Handle + { + get + { + return handle; + } + } + + + #region Constructor + + /// + /// Constructs an empty OrtROCMroviderOptions instance + /// + public OrtROCMProviderOptions() : base(IntPtr.Zero, true) + { + NativeApiStatus.VerifySuccess(NativeMethods.OrtCreateROCMProviderOptions(out handle)); + } + + #endregion + + #region Public Methods + + /// + /// Get ROCm EP provider options + /// + /// return C# UTF-16 encoded string + public string GetOptions() + { + var allocator = OrtAllocator.DefaultInstance; + // Process provider options string + NativeApiStatus.VerifySuccess(NativeMethods.OrtGetROCMProviderOptionsAsString(handle, + allocator.Pointer, out IntPtr providerOptions)); + return NativeOnnxValueHelper.StringFromNativeUtf8(providerOptions, allocator); + } + + private static IntPtr UpdateROCMProviderOptions(IntPtr handle, IntPtr[] keys, IntPtr[] values, UIntPtr count) + { + return NativeMethods.OrtUpdateROCMProviderOptions(handle, keys, values, count); + } + + /// + /// Updates the configuration knobs of OrtROCMProviderOptions that will eventually be used to configure a ROCm EP + /// Please refer to the following on different key/value pairs to configure a ROCm EP and their meaning: + /// https://onnxruntime.ai/docs/execution-providers/ROCm-ExecutionProvider.html + /// + /// key/value pairs used to configure a ROCm Execution Provider + public void UpdateOptions(Dictionary providerOptions) + { + ProviderOptionsUpdater.Update(providerOptions, handle, UpdateROCMProviderOptions); + } + + #endregion + + #region Public Properties + + /// + /// Overrides SafeHandle.IsInvalid + /// + /// returns true if handle is equal to Zero + public override bool IsInvalid { get { return handle == IntPtr.Zero; } } + + #endregion + + #region SafeHandle + /// + /// Overrides SafeHandle.ReleaseHandle() to properly dispose of + /// the native instance of OrtROCMProviderOptions + /// + /// always returns true + protected override bool ReleaseHandle() + { + NativeMethods.OrtReleaseROCMProviderOptions(handle); + handle = IntPtr.Zero; + return true; + } + + #endregion + } + + /// /// This helper class contains methods to handle values of provider options /// diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/SessionOptions.shared.cs b/csharp/src/Microsoft.ML.OnnxRuntime/SessionOptions.shared.cs index 7590299000f2d..7a68246c9b67a 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/SessionOptions.shared.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/SessionOptions.shared.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Runtime.InteropServices; using System.Text; @@ -66,8 +65,16 @@ public static SessionOptions MakeSessionOptionWithCudaProvider(int deviceId = 0) { CheckCudaExecutionProviderDLLs(); SessionOptions options = new SessionOptions(); - options.AppendExecutionProvider_CUDA(deviceId); - return options; + try + { + options.AppendExecutionProvider_CUDA(deviceId); + return options; + } + catch (Exception) + { + options.Dispose(); + throw; + } } /// @@ -148,9 +155,16 @@ public static SessionOptions MakeSessionOptionWithTensorrtProvider(OrtTensorRTPr public static SessionOptions MakeSessionOptionWithTvmProvider(String settings = "") { SessionOptions options = new SessionOptions(); - options.AppendExecutionProvider_Tvm(settings); - - return options; + try + { + options.AppendExecutionProvider_Tvm(settings); + return options; + } + catch (Exception) + { + options.Dispose(); + throw; + } } /// @@ -161,9 +175,40 @@ public static SessionOptions MakeSessionOptionWithTvmProvider(String settings = /// A SessionsOptions() object configured for execution on deviceId public static SessionOptions MakeSessionOptionWithRocmProvider(int deviceId = 0) { + CheckRocmExecutionProviderDLLs(); SessionOptions options = new SessionOptions(); - options.AppendExecutionProvider_ROCM(deviceId); - return options; + try + { + options.AppendExecutionProvider_ROCm(deviceId); + return options; + } + catch (Exception) + { + options.Dispose(); + throw; + } + } + + /// + /// A helper method to construct a SessionOptions object for ROCm execution provider. + /// Use only if ROCm is installed and you have the onnxruntime package specific to this Execution Provider. + /// + /// ROCm EP provider options + /// A SessionsOptions() object configured for execution on provider options + public static SessionOptions MakeSessionOptionWithRocmProvider(OrtROCMProviderOptions rocmProviderOptions) + { + CheckRocmExecutionProviderDLLs(); + SessionOptions options = new SessionOptions(); + try + { + options.AppendExecutionProvider_ROCm(rocmProviderOptions); + return options; + } + catch (Exception) + { + options.Dispose(); + throw; + } } #endregion @@ -276,7 +321,7 @@ public void AppendExecutionProvider_Tensorrt(OrtTensorRTProviderOptions trtProvi /// Use only if you have the onnxruntime package specific to this Execution Provider. /// /// Device Id - public void AppendExecutionProvider_ROCM(int deviceId = 0) + public void AppendExecutionProvider_ROCm(int deviceId = 0) { #if __MOBILE__ throw new NotSupportedException("The ROCM Execution Provider is not supported in this build"); @@ -286,6 +331,20 @@ public void AppendExecutionProvider_ROCM(int deviceId = 0) #endif } + /// + /// Append a ROCm EP instance (based on specified configuration) to the SessionOptions instance. + /// Use only if you have the onnxruntime package specific to this Execution Provider. + /// + /// ROCm EP provider options + public void AppendExecutionProvider_ROCm(OrtROCMProviderOptions rocmProviderOptions) + { +#if __MOBILE__ + throw new NotSupportedException("The ROCm Execution Provider is not supported in this build"); +#else + NativeApiStatus.VerifySuccess(NativeMethods.SessionOptionsAppendExecutionProvider_ROCM(handle, rocmProviderOptions.Handle)); +#endif + } + /// /// Use only if you have the onnxruntime package specific to this Execution Provider. /// @@ -375,10 +434,10 @@ public IntPtr Appender(IntPtr handle, IntPtr[] optKeys, IntPtr[] optValues, UInt /// Optional key/value pairs to specify execution provider options. public void AppendExecutionProvider(string providerName, Dictionary providerOptions = null) { - if (providerName != "SNPE" && providerName != "XNNPACK" && providerName != "QNN") + if (providerName != "SNPE" && providerName != "XNNPACK" && providerName != "QNN" && providerName != "AZURE") { throw new NotSupportedException( - "Only QNN, SNPE and XNNPACK execution providers can be enabled by this method."); + "Only QNN, SNPE, XNNPACK and AZURE execution providers can be enabled by this method."); } if (providerOptions == null) @@ -394,19 +453,22 @@ public void AppendExecutionProvider(string providerName, Dictionary - /// (Deprecated) Loads a DLL named 'libraryPath' and looks for this entry point: - /// OrtStatus* RegisterCustomOps(OrtSessionOptions* options, const OrtApiBase* api); + /// Loads a DLL named 'libraryPath' and looks for this entry point: + /// OrtStatus* RegisterCustomOps(OrtSessionOptions* options, const OrtApiBase* api); /// It then passes in the provided session options to this function along with the api base. - /// Deprecated in favor of RegisterCustomOpLibraryV2() because it provides users with the library handle - /// to release when all sessions relying on it are destroyed + /// + /// Prior to v1.15 this leaked the library handle and RegisterCustomOpLibraryV2 + /// was added to resolve that. + /// + /// From v1.15 on ONNX Runtime will manage the lifetime of the handle. /// /// path to the custom op library - [ObsoleteAttribute("RegisterCustomOpLibrary(...) is obsolete. Use RegisterCustomOpLibraryV2(...) instead.", false)] public void RegisterCustomOpLibrary(string libraryPath) { - var utf8Path = NativeOnnxValueHelper.StringToZeroTerminatedUtf8(libraryPath); - // The handle is leaking in this version - NativeApiStatus.VerifySuccess(NativeMethods.OrtRegisterCustomOpsLibrary(handle, utf8Path, out IntPtr libraryHandle)); + NativeApiStatus.VerifySuccess( + NativeMethods.OrtRegisterCustomOpsLibrary_V2( + handle, NativeOnnxValueHelper.GetPlatformSerializedString(libraryPath)) + ); } /// @@ -422,8 +484,41 @@ public void RegisterCustomOpLibrary(string libraryPath) /// out parameter, library handle public void RegisterCustomOpLibraryV2(string libraryPath, out IntPtr libraryHandle) { + // NOTE: This is confusing due to the history. + // SessionOptions.RegisterCustomOpLibrary initially called NativeMethods.OrtRegisterCustomOpsLibrary + // and leaked the handle. + // SessionOptions.RegisterCustomOpLibraryV2 was added to resolve that by returning the handle. + // Later, NativeMethods.OrtRegisterCustomOpsLibrary_V2 was added with ORT owning the handle. + // + // End result of that is + // SessionOptions.RegisterCustomOpLibrary calls NativeMethods.OrtRegisterCustomOpsLibrary_V2 + // SessionOptions.RegisterCustomOpLibraryV2 calls NativeMethods.OrtRegisterCustomOpsLibrary var utf8Path = NativeOnnxValueHelper.StringToZeroTerminatedUtf8(libraryPath); - NativeApiStatus.VerifySuccess(NativeMethods.OrtRegisterCustomOpsLibrary(handle, utf8Path, out libraryHandle)); + NativeApiStatus.VerifySuccess(NativeMethods.OrtRegisterCustomOpsLibrary(handle, utf8Path, + out libraryHandle)); + } + + /// + /// Register the custom operators from the Microsoft.ML.OnnxRuntime.Extensions NuGet package. + /// A reference to Microsoft.ML.OnnxRuntime.Extensions must be manually added to your project. + /// + /// Throws if the extensions library is not found. + public void RegisterOrtExtensions() + { + try + { + var ortApiBase = NativeMethods.OrtGetApiBase(); + NativeApiStatus.VerifySuccess( + OrtExtensionsNativeMethods.RegisterCustomOps(this.handle, ref ortApiBase) + ); + } + catch (DllNotFoundException) + { + throw new OnnxRuntimeException( + ErrorCode.NoSuchFile, + "The ONNX Runtime extensions library was not found. The Microsoft.ML.OnnxRuntime.Extensions " + + "NuGet package must be referenced by the project to use 'OrtExtensions.RegisterCustomOps."); + } } /// @@ -797,6 +892,16 @@ private static bool CheckTensorrtExecutionProviderDLLs() } return true; } + + private static bool CheckRocmExecutionProviderDLLs() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + throw new NotSupportedException("ROCm Execution Provider is not currently supported on Windows."); + } + return true; + } + #endregion #region SafeHandle diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/ShapeUtils.shared.cs b/csharp/src/Microsoft.ML.OnnxRuntime/ShapeUtils.shared.cs new file mode 100644 index 0000000000000..f58dde8509a1a --- /dev/null +++ b/csharp/src/Microsoft.ML.OnnxRuntime/ShapeUtils.shared.cs @@ -0,0 +1,82 @@ +using System.Diagnostics; +using System; + +namespace Microsoft.ML.OnnxRuntime.Tensors +{ + /// + /// This class contains utilities for useful calculations with shape. + /// + public static class ShapeUtils + { + /// + /// Returns a number of elements in the tensor from the given shape + /// + /// + /// size + /// + public static long GetSizeForShape(ReadOnlySpan shape) + { + long product = 1; + foreach (var dim in shape) + { + if (dim < 0) + { + throw new ArgumentOutOfRangeException($"Shape must not have negative elements: {dim}"); + } + checked + { + product *= dim; + } + } + return product; + } + + /// + /// Gets the set of strides that can be used to calculate the offset of n-dimensions in a 1-dimensional layout + /// + /// + /// an array of strides + public static long[] GetStrides(ReadOnlySpan dimensions) + { + long[] strides = new long[dimensions.Length]; + + if (dimensions.Length == 0) + { + return strides; + } + + long stride = 1; + for (int i = strides.Length - 1; i >= 0; i--) + { + strides[i] = stride; + if (dimensions[i] < 0) + { + throw new ArgumentException($"Dimension {i} is negative"); + } + stride *= dimensions[i]; + } + + return strides; + } + + /// + /// Calculates the 1-d index for n-d indices in layout specified by strides. + /// + /// pre-calculated strides + /// Indices. Must have the same length as strides + /// + /// A 1-d index into the tensor buffer + public static long GetIndex(ReadOnlySpan strides, ReadOnlySpan indices, int startFromDimension = 0) + { + Debug.Assert(strides.Length == indices.Length); + + long index = 0; + for (int i = startFromDimension; i < indices.Length; i++) + { + index += strides[i] * indices[i]; + } + + return index; + } + } +} \ No newline at end of file diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/Tensors/ArrayUtilities.shared.cs b/csharp/src/Microsoft.ML.OnnxRuntime/Tensors/ArrayUtilities.shared.cs index 325acdf37cc50..025c1331ce54d 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/Tensors/ArrayUtilities.shared.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/Tensors/ArrayUtilities.shared.cs @@ -11,8 +11,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Diagnostics; using System; +using System.Diagnostics; namespace Microsoft.ML.OnnxRuntime.Tensors { @@ -20,20 +20,6 @@ internal static class ArrayUtilities { public const int StackallocMax = 16; - public static long GetSizeForShape(long[] shape) - { - long product = 1; - foreach (var dim in shape) - { - if (dim < 0) - { - throw new ArgumentOutOfRangeException("Shape must not have negative elements:" + dim); - } - product *= dim; - } - return product; - } - public static long GetProduct(ReadOnlySpan dimensions, int startIndex = 0) { long product = 1; @@ -162,7 +148,7 @@ public static int GetIndex(int[] strides, ReadOnlySpan indices, int startFr } /// - /// Calculates the n-d indices from the 1-d index in a layout specificed by strides + /// Calculates the n-d indices from the 1-d index in a layout specified by strides /// /// /// diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/Tensors/Tensor.shared.cs b/csharp/src/Microsoft.ML.OnnxRuntime/Tensors/Tensor.shared.cs index 0bc5ca7240e66..e927b8105c6c9 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/Tensors/Tensor.shared.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/Tensors/Tensor.shared.cs @@ -44,174 +44,6 @@ public enum TensorElementType DataTypeMax = 17 } - /// - /// This value type represents A Float16 value - /// it is blittable as defined in https://docs.microsoft.com/en-us/dotnet/framework/interop/blittable-and-non-blittable-types - /// and as such, represented the same way in managed and native memories. This means that arrays of this type - /// do not have to be copied to be passed to native memory but simply pinnned and read by native code. Thus, - /// one can create a Tensor on top of an array of these structures and feed it directly to Onnxruntime library. - /// Binary wise, it is the same as ushort[] (uint16_t in C++). However, we would like a separate type for type dispatching. - /// - public struct Float16 - { - /// - /// float16 representation bits - /// - public ushort value; - /// - /// Ctor - /// - /// - public Float16(ushort v) - { - value = v; - } - /// - /// Converts to ushort - /// - /// instance of Float16 - /// value member - public static implicit operator ushort(Float16 f) { return f.value; } - /// - /// Converts a 16-bit unsigned integer to a Float16. - /// - /// A 16-bit unsigned integer. - /// A Float16 that represents the converted 16-bit unsigned integer. - public static implicit operator Float16(ushort value) { return new Float16(value); } - /// - /// Compares values of two Float16 for binary equality - /// - /// - /// - /// result of value comparisons - public static bool operator ==(Float16 lhs, Float16 rhs) { return lhs.value == rhs.value; } - /// - /// Compares values of two Float16 for binary inequality - /// - /// - /// - /// result of value comparisons - public static bool operator !=(Float16 lhs, Float16 rhs) { return lhs.value != rhs.value; } - /// - /// Returns a value indicating whether this instance and other Float16 represent the same value. - /// - /// A Float16 object to compare to this instance. - /// true if other.value is equal to this instance; otherwise, false. - public bool Equals(Float16 other) - { - return (other == this); - } - /// - /// Returns a value indicating whether this instance and a specified System.Object - /// represent the same type and value. - /// - /// An System.Object. - /// true if obj is Float16 and its value is equal to this instance; otherwise, false. - public override bool Equals(object obj) - { - bool result = false; - if (obj is Float16) - { - Float16 fl16 = (Float16)obj; - result = (fl16 == this); - } - return result; - } - /// - /// Returns the hash code for this instance. - /// - /// A 32-bit signed integer hash code. - public override int GetHashCode() - { - return value.GetHashCode(); - } - } - - /// - /// This value type represents A BFloat16 value - /// it is blittable as defined in https://docs.microsoft.com/en-us/dotnet/framework/interop/blittable-and-non-blittable-types - /// and as such, represented the same way in managed and native memories. This means that arrays of this type - /// do not have to be copied to be passed to native memory but simply pinnned and read by native code. Thus, - /// one can create a Tensor on top of an array of these structures and feed it directly to Onnxruntime library. - /// Binary wise, it is the same as ushort[] (uint16_t in C++). However, we would like a separate type for type dispatching. - /// - public struct BFloat16 - { - /// - /// bfloat16 representation bits - /// - public ushort value; - /// - /// Ctor - /// - /// - public BFloat16(ushort v) - { - value = v; - } - /// - /// Converts to ushort - /// - /// instance of BFloat16 - /// value member - public static implicit operator ushort(BFloat16 bf) { return bf.value; } - /// - /// Converts a 16-bit unsigned integer to a BFloat16. - /// - /// A 16-bit unsigned integer. - /// A BFloat16 that represents the converted 16-bit unsigned integer. - public static implicit operator BFloat16(ushort value) { return new BFloat16(value); } - /// - /// Compares values of two BFloat16 for binary equality - /// - /// - /// - /// result of value comparisons - public static bool operator ==(BFloat16 lhs, BFloat16 rhs) { return lhs.value == rhs.value; } - /// - /// Compares values of two BFloat16 for binary inequality - /// - /// - /// - /// result of value comparisons - public static bool operator !=(BFloat16 lhs, BFloat16 rhs) { return lhs.value != rhs.value; } - - /// - /// Returns a value indicating whether this instance and other BFloat16 represent the same value. - /// - /// A BFloat16 object to compare to this instance. - /// true if other.value is equal to this instance; otherwise, false. - public bool Equals(BFloat16 other) - { - return (other == this); - } - - /// - /// Returns a value indicating whether this instance and a specified System.Object - /// represent the same type and value. - /// - /// An System.Object. - /// true if obj is BFloat16 its value is equal to this instance; otherwise, false. - public override bool Equals(object obj) - { - bool result = false; - if (obj is BFloat16) - { - BFloat16 bfl16 = (BFloat16)obj; - result = (bfl16 == this); - } - return result; - } - /// - /// Returns the hash code for this instance. - /// - /// A 32-bit signed integer hash code. - public override int GetHashCode() - { - return value.GetHashCode(); - } - } - /// /// Helps typecasting. Holds Tensor element type traits. /// @@ -660,17 +492,21 @@ protected Tensor(int length) : base(typeof(T)) } /// - /// Initialize an n-dimensional tensor with the specified dimensions and layout. ReverseStride=true gives a stride of 1-element width to the first dimension (0). ReverseStride=false gives a stride of 1-element width to the last dimension (n-1). + /// Initialize an n-dimensional tensor with the specified dimensions and layout. + /// ReverseStride=true gives a stride of 1-element width to the first dimension (0). + /// ReverseStride=false gives a stride of 1-element width to the last dimension (n-1). /// - /// An span of integers that represent the size of each dimension of the Tensor to create. - /// False (default) to indicate that the first dimension is most major (farthest apart) and the last dimension is most minor (closest together): akin to row-major in a rank-2 tensor. True to indicate that the last dimension is most major (farthest apart) and the first dimension is most minor (closest together): akin to column-major in a rank-2 tensor. + /// + /// An span of integers that represent the size of each dimension of the Tensor to create. + /// + /// False (default) to indicate that the first dimension is most major (farthest apart) and the last dimension + /// is most minor (closest together): akin to row-major in a rank-2 tensor. + /// True to indicate that the last dimension is most major (farthest apart) and the first dimension is most + /// minor (closest together): akin to column-major in a rank-2 tensor. + /// If you pass `null` for dimensions it will implicitly convert to an empty ReadOnlySpan, which is + /// equivalent to the dimensions for a scalar value. protected Tensor(ReadOnlySpan dimensions, bool reverseStride) : base(typeof(T)) { - if (dimensions == null) - { - throw new ArgumentNullException(nameof(dimensions)); - } - this.dimensions = new int[dimensions.Length]; long size = 1; for (int i = 0; i < dimensions.Length; i++) diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/Training/CheckpointState.shared.cs b/csharp/src/Microsoft.ML.OnnxRuntime/Training/CheckpointState.shared.cs index f775f3ad497be..659c6303702ac 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/Training/CheckpointState.shared.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/Training/CheckpointState.shared.cs @@ -7,7 +7,16 @@ namespace Microsoft.ML.OnnxRuntime { #if __ENABLE_TRAINING_APIS__ /// - /// Holds the Checkpoint State as generated/consumed by on-device training APIs + /// Holds the state of the training session. + /// This class holds the entire training session state that includes model parameters, their gradients, + /// optimizer parameters, and user properties. The TrainingSession leverages the CheckpointState + /// by accessing and updating the contained training state. + /// + /// Note that the training session created with a checkpoint state uses this state to store the entire + /// training state (including model parameters, its gradients, the optimizer states and the properties). + /// The TrainingSession does not hold a copy of the CheckpointState and as a result, it is required + /// that the checkpoint state outlives the lifetime of the training session. + /// /// public class CheckpointState : SafeHandle { @@ -19,21 +28,32 @@ internal IntPtr Handle } } - /// - /// Creates CheckpointState by loading state from path. - /// absolute path to checkpoint file. - /// - public CheckpointState(string checkpointPath) - : base(IntPtr.Zero, true) + private CheckpointState(IntPtr checkpointHandle) + : base(checkpointHandle, true) { - if (NativeTrainingMethods.TrainingEnabled()) - { - var envHandle = OrtEnv.Instance().Handle; // just so it is initialized - LoadCheckpoint(checkpointPath); - } - else + } + + internal enum PropertyType : long + { + Int = 0, + Float = 1, + String = 2 + } + + private void AddPropertyImpl(string propertyName, PropertyType propertyType, T propertyValue) + { + var propertyNameUtf8 = NativeOnnxValueHelper.StringToZeroTerminatedUtf8(propertyName); + T[] value = new T[1]; + value[0] = propertyValue; + Memory memory = value; + using (var memHandle = memory.Pin()) { - throw new InvalidOperationException("Training is disabled in the current build. Please build ONNXRuntime from source with the build flags enable_training_apis. \n"); + IntPtr memPtr; + unsafe + { + memPtr = (IntPtr)memHandle.Pointer; + } + NativeApiStatus.VerifySuccess(NativeTrainingMethods.OrtAddProperty(handle, propertyNameUtf8, propertyType, memPtr)); } } @@ -44,22 +64,132 @@ public CheckpointState(string checkpointPath) public override bool IsInvalid { get { return handle == IntPtr.Zero; } } /// - /// Loads Checkpoint state from path + /// Load a checkpoint state from a directory on disk into checkpoint_state. + /// + /// This function will parse a checkpoint directory, pull relevant files and load the training + /// state into the checkpoint_state. This checkpoint state can then be used to create the + /// training session by instantiating the TrainingSession. By doing so, the training + /// session will begin or resume training from the given checkpoint state. + /// + /// Absolute path to the checkpoint directory. + /// CheckpointState object which holds the state of the training session parameters. + public static CheckpointState LoadCheckpoint(string checkpointPath) + { + if (!NativeTrainingMethods.TrainingEnabled()) + { + throw new InvalidOperationException("This package does not contain the training API. Please install the Microsoft.ML.OnnxRuntime.Training NuGet package.\n"); + } + + var envHandle = OrtEnv.Instance().Handle; // just so it is initialized + IntPtr checkpointHandle = IntPtr.Zero; + NativeApiStatus.VerifySuccess(NativeTrainingMethods.OrtLoadCheckpoint(NativeOnnxValueHelper.GetPlatformSerializedString(checkpointPath), out checkpointHandle)); + + return new CheckpointState(checkpointHandle); + } + + /// + /// Save the given state to a checkpoint directory on disk. + /// + /// This function serializes the provided checkpoint state to a directory on disk. + /// This checkpoint can later be loaded by invoking CheckpointState.LoadCheckpoint to begin or resume + /// training from this snapshot of the state. + /// + /// The checkpoint state to save. + /// Absolute path to the checkpoint directory. + /// Flag to indicate whether to save the optimizer state or not. + public static void SaveCheckpoint(CheckpointState state, string checkpointPath, bool includeOptimizerState = false) + { + NativeApiStatus.VerifySuccess(NativeTrainingMethods.OrtSaveCheckpoint(state.Handle, NativeOnnxValueHelper.GetPlatformSerializedString(checkpointPath), includeOptimizerState)); + } + + /// + /// Adds the given int property to the checkpoint state. + /// + /// Runtime properties that are ints such as epoch, training step, and others can be added to the checkpoint + /// state by the user if they desire by calling this function with the appropriate property name and + /// value. The given property name must be unique to be able to successfully add the property. /// - /// absolute path to checkpoint - private void LoadCheckpoint(string checkpointPath) + /// Unique name of the property being added. + /// Property value associated with the given name. + public void AddProperty(string propertyName, long propertyValue) { - NativeApiStatus.VerifySuccess(NativeTrainingMethods.OrtLoadCheckpoint(NativeOnnxValueHelper.GetPlatformSerializedString(checkpointPath), out handle)); + AddPropertyImpl(propertyName, PropertyType.Int, propertyValue); } /// - /// Saves the checkpoint - /// absolute path to the checkpoint file. - /// absolute path to the checkpoint file. + /// Adds the given float property to the checkpoint state. + /// + /// Runtime properties that are floats such as loss, best score, and others can be added to the checkpoint + /// state by the user if they desire by calling this function with the appropriate property name and + /// value. The given property name must be unique to be able to successfully add the property. /// - public void SaveCheckpoint(string checkpointPath, bool includeOptimizerState = false) + /// Unique name of the property being added. + /// Property value associated with the given name. + public void AddProperty(string propertyName, float propertyValue) { - NativeApiStatus.VerifySuccess(NativeTrainingMethods.OrtSaveCheckpoint(handle, NativeOnnxValueHelper.GetPlatformSerializedString(checkpointPath), includeOptimizerState)); + AddPropertyImpl(propertyName, PropertyType.Float, propertyValue); + } + + /// + /// Adds the given string property to the checkpoint state. + /// + /// Runtime properties that are strings such as parameter names, custom strings, and others can be added + /// to the checkpoint state by the user if they desire by calling this function with the appropriate property + /// name and value. The given property name must be unique to be able to successfully add the property. + /// + /// Unique name of the property being added. + /// Property value associated with the given name. + public void AddProperty(string propertyName, string propertyValue) + { + var propertyNameUtf8 = NativeOnnxValueHelper.StringToZeroTerminatedUtf8(propertyName); + var propertyValueUtf8 = NativeOnnxValueHelper.StringToZeroTerminatedUtf8(propertyValue); + + IntPtr unmanagedPointer = Marshal.AllocHGlobal(propertyValueUtf8.Length); + try + { + Marshal.Copy(propertyValueUtf8, 0, unmanagedPointer, propertyValueUtf8.Length); + NativeApiStatus.VerifySuccess(NativeTrainingMethods.OrtAddProperty(handle, propertyNameUtf8, PropertyType.String, unmanagedPointer)); + } + finally + { + Marshal.FreeHGlobal(unmanagedPointer); + } + } + + /// + /// Gets the property value associated with the given name from the checkpoint state. + /// + /// Gets the property value from an existing entry in the checkpoint state. The property must + /// exist in the checkpoint state to be able to retrieve it successfully. + /// + /// Unique name of the property being retrieved. + /// Property value associated with the given property name. + public object GetProperty(string propertyName) + { + var propertyNameUtf8 = NativeOnnxValueHelper.StringToZeroTerminatedUtf8(propertyName); + var allocator = OrtAllocator.DefaultInstance; + IntPtr propertyValue = IntPtr.Zero; + NativeApiStatus.VerifySuccess(NativeTrainingMethods.OrtGetProperty(handle, propertyNameUtf8, allocator.Pointer, out PropertyType propertyType, out propertyValue)); + + if (propertyType == PropertyType.Int) + { + var longPropertyValue = Marshal.ReadInt64(propertyValue); + allocator.FreeMemory(propertyValue); + return longPropertyValue; + } + else if (propertyType == PropertyType.Float) + { + float[] value = new float[1]; + Marshal.Copy(propertyValue, value, 0, 1); + allocator.FreeMemory(propertyValue); + return value[0]; + } + else if (propertyType == PropertyType.String) + { + return NativeOnnxValueHelper.StringFromNativeUtf8(propertyValue, allocator); + } + + throw new ArgumentException("Expected the property type to be one of long, float or string. Unknown type retrieved " + propertyValue.ToString()); } #region SafeHandle diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/Training/NativeTrainingMethods.shared.cs b/csharp/src/Microsoft.ML.OnnxRuntime/Training/NativeTrainingMethods.shared.cs index 5df0720022651..1868ff509bfc3 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/Training/NativeTrainingMethods.shared.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/Training/NativeTrainingMethods.shared.cs @@ -15,6 +15,7 @@ public struct OrtTrainingApi public IntPtr LoadCheckpoint; public IntPtr SaveCheckpoint; public IntPtr CreateTrainingSession; + public IntPtr CreateTrainingSessionFromBuffer; public IntPtr TrainingSessionGetTrainingModelOutputCount; public IntPtr TrainingSessionGetEvalModelOutputCount; public IntPtr TrainingSessionGetTrainingModelOutputName; @@ -40,6 +41,7 @@ public struct OrtTrainingApi public IntPtr TrainingSessionGetEvalModelInputName; public IntPtr AddProperty; public IntPtr GetProperty; + public IntPtr LoadCheckpointFromBuffer; } internal static class NativeTrainingMethods @@ -60,10 +62,10 @@ static NativeTrainingMethods() DOrtGetApi OrtGetApi = (DOrtGetApi)Marshal.GetDelegateForFunctionPointer(NativeMethods.OrtGetApiBase().GetApi, typeof(DOrtGetApi)); // TODO: Make this save the pointer, and not copy the whole structure across - api_ = (OrtApi)OrtGetApi(13 /*ORT_API_VERSION*/); + api_ = (OrtApi)OrtGetApi(17 /*ORT_API_VERSION*/); OrtGetTrainingApi = (DOrtGetTrainingApi)Marshal.GetDelegateForFunctionPointer(api_.GetTrainingApi, typeof(DOrtGetTrainingApi)); - trainingApiPtr = OrtGetTrainingApi(13 /*ORT_API_VERSION*/); + trainingApiPtr = OrtGetTrainingApi(17 /*ORT_API_VERSION*/); if (trainingApiPtr != IntPtr.Zero) { trainingApi_ = (OrtTrainingApi)Marshal.PtrToStructure(trainingApiPtr, typeof(OrtTrainingApi)); @@ -82,6 +84,9 @@ static NativeTrainingMethods() OrtOptimizerStep = (DOrtOptimizerStep)Marshal.GetDelegateForFunctionPointer(trainingApi_.OptimizerStep, typeof(DOrtOptimizerStep)); OrtRegisterLinearLRScheduler = (DOrtRegisterLinearLRScheduler)Marshal.GetDelegateForFunctionPointer(trainingApi_.RegisterLinearLRScheduler, typeof(DOrtRegisterLinearLRScheduler)); OrtSchedulerStep = (DOrtSchedulerStep)Marshal.GetDelegateForFunctionPointer(trainingApi_.SchedulerStep, typeof(DOrtSchedulerStep)); + OrtGetParametersSize = (DOrtGetParametersSize)Marshal.GetDelegateForFunctionPointer(trainingApi_.GetParametersSize, typeof(DOrtGetParametersSize)); + OrtCopyParametersToBuffer = (DOrtCopyParametersToBuffer)Marshal.GetDelegateForFunctionPointer(trainingApi_.CopyParametersToBuffer, typeof(DOrtCopyParametersToBuffer)); + OrtCopyBufferToParameters = (DOrtCopyBufferToParameters)Marshal.GetDelegateForFunctionPointer(trainingApi_.CopyBufferToParameters, typeof(DOrtCopyBufferToParameters)); OrtReleaseTrainingSession = (DOrtReleaseTrainingSession)Marshal.GetDelegateForFunctionPointer(trainingApi_.ReleaseTrainingSession, typeof(DOrtReleaseTrainingSession)); OrtReleaseCheckpointState = (DOrtReleaseCheckpointState)Marshal.GetDelegateForFunctionPointer(trainingApi_.ReleaseCheckpointState, typeof(DOrtReleaseCheckpointState)); OrtExportModelForInferencing = (DOrtExportModelForInferencing)Marshal.GetDelegateForFunctionPointer(trainingApi_.ExportModelForInferencing, typeof(DOrtExportModelForInferencing)); @@ -248,6 +253,30 @@ float learningRate ); public static DOrtSchedulerStep OrtSchedulerStep; + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + public delegate IntPtr /*(OrtStatus*)*/ DOrtGetParametersSize( + IntPtr /*(OrtTrainingSession*)*/ session, + out UIntPtr buffer_size, + bool only_trainable + ); + public static DOrtGetParametersSize OrtGetParametersSize; + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + public delegate IntPtr /*(OrtStatus*)*/ DOrtCopyParametersToBuffer( + IntPtr /*(OrtTrainingSession*)*/ session, + IntPtr /*(OrtValue*)*/ buffer, + bool only_trainable + ); + public static DOrtCopyParametersToBuffer OrtCopyParametersToBuffer; + + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + public delegate IntPtr /*(OrtStatus*)*/ DOrtCopyBufferToParameters( + IntPtr /*(OrtTrainingSession*)*/ session, + IntPtr /*(OrtValue*)*/ buffer, + bool only_trainable + ); + public static DOrtCopyBufferToParameters OrtCopyBufferToParameters; + [UnmanagedFunctionPointer(CallingConvention.Winapi)] public delegate void DOrtReleaseTrainingSession(IntPtr /*(OrtTrainingSession*)*/session); public static DOrtReleaseTrainingSession OrtReleaseTrainingSession; @@ -312,8 +341,8 @@ out UIntPtr inputCount [UnmanagedFunctionPointer(CallingConvention.Winapi)] public delegate IntPtr /*(OrtStatus*)*/ DOrtAddProperty( IntPtr /*(OrtCheckpointState*)*/ checkpointState, - IntPtr /*(const char*)*/ propertyName, - OrtPropertyType propertyType, + byte[] /*(const char*)*/ propertyName, + CheckpointState.PropertyType propertyType, IntPtr /*(const void*)*/ propertyValue ); @@ -322,9 +351,9 @@ out UIntPtr inputCount [UnmanagedFunctionPointer(CallingConvention.Winapi)] public delegate IntPtr /*(OrtStatus*)*/ DOrtGetProperty( IntPtr /*(OrtCheckpointState*)*/ checkpointState, - IntPtr /*(const char*)*/ propertyName, + byte[] /*(const char*)*/ propertyName, IntPtr /*(OrtAllocator*)*/ allocator, - out OrtPropertyType propertyType, + out CheckpointState.PropertyType propertyType, out IntPtr /*(const void**)*/ propertyValue ); diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/Training/OrtPropertyType.shared.cs b/csharp/src/Microsoft.ML.OnnxRuntime/Training/OrtPropertyType.shared.cs deleted file mode 100644 index 17505d6a27a51..0000000000000 --- a/csharp/src/Microsoft.ML.OnnxRuntime/Training/OrtPropertyType.shared.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -namespace Microsoft.ML.OnnxRuntime -{ -#if __ENABLE_TRAINING_APIS__ - /// - /// Property types - /// - public enum OrtPropertyType - { - OrtIntProperty = 0, - OrtFloatProperty = 1, - OrtStringProperty = 2, - } -#endif -} diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/Training/TrainingSession.shared.cs b/csharp/src/Microsoft.ML.OnnxRuntime/Training/TrainingSession.shared.cs index 9874863e9141f..33993c2be135b 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/Training/TrainingSession.shared.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/Training/TrainingSession.shared.cs @@ -4,21 +4,48 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Linq.Expressions; using System.Runtime.InteropServices; namespace Microsoft.ML.OnnxRuntime { #if __ENABLE_TRAINING_APIS__ + /// + /// This class defines utility methods for training. + /// + public class TrainingUtils + { + /// + /// Use this function to generate reproducible results. It should be noted that completely + /// reproducible results are not guaranteed. + /// + /// Manual seed to use for random number generation. + public static void SetSeed(long seed) + { + NativeApiStatus.VerifySuccess(NativeTrainingMethods.OrtSetSeed(seed)); + } + } + enum LRScheduler { None = 0, Constant = 1, Linear = 2 } + /// - /// Represents a Training Session on an ONNX Model. - /// This is a IDisposable class and it must be disposed of - /// using either a explicit call to Dispose() method or + /// Trainer class that provides training, evaluation and optimizer methods for training an ONNX model. + /// + /// The training session requires four training artifacts + /// - The training onnx model + /// - The evaluation onnx model (optional) + /// - The optimizer onnx model + /// - The checkpoint directory + /// + /// These artifacts can be generated using the `onnxruntime-training` python [utility](https://github.com/microsoft/onnxruntime/blob/main/orttraining/orttraining/python/training/onnxblock/README.md). + /// + /// This is an IDisposable class and it must be disposed of + /// using either an explicit call to Dispose() method or /// a pattern of using() block. If this is a member of another /// class that class must also become IDisposable and it must /// dispose of TrainingSession in its Dispose() method. @@ -26,7 +53,7 @@ enum LRScheduler public class TrainingSession : IDisposable { /// - /// A pointer to a underlying native instance of OrtTrainingSession + /// A pointer to an underlying native instance of OrtTrainingSession /// private IntPtr _nativeHandle; @@ -34,66 +61,81 @@ public class TrainingSession : IDisposable private ulong _evalOutputCount; private List _trainOutputNames; private List _evalOutputNames; + private List _trainInputNames; + private List _evalInputNames; private SessionOptions _builtInSessionOptions = null; private RunOptions _builtInRunOptions = null; private LRScheduler _scheduler = LRScheduler.None; private bool _disposed = false; - #region Public API + #region Public API /// - /// Creates TrainingSession from the model and checkpoint in . + /// Create a training session that can be used to begin or resume training. + /// + /// This constructor instantiates the training session based on the env and session options provided that can + /// begin or resume training from a given checkpoint state for the given onnx models. + /// The checkpoint state represents the parameters of the training session which will be moved + /// to the device specified by the user through the session options (if necessary). /// - /// Model checkpoint loaded into . - /// Specify path to training model graph. - /// Specify path to eval model graph. - /// Specify path to optimizer model graph. + /// Training states that the training session uses as a starting point for training. + /// Model to be used to perform training. + /// Model to be used to perform evaluation. + /// Model to be used to perform weight update. public TrainingSession(CheckpointState state, string trainModelPath, string evalModelPath, string optimizerModelPath) { Init(null, state, NativeOnnxValueHelper.GetPlatformSerializedString(trainModelPath), NativeOnnxValueHelper.GetPlatformSerializedString(evalModelPath), NativeOnnxValueHelper.GetPlatformSerializedString(optimizerModelPath)); } /// - /// Creates TrainingSession from the model and checkpoint in . + /// Create a training session that can be used to begin or resume training. + /// + /// This constructor instantiates the training session based on the env and session options provided that can + /// begin or resume training from a given checkpoint state for the given onnx models. + /// The checkpoint state represents the parameters of the training session which will be moved + /// to the device specified by the user through the session options (if necessary). /// - /// Model checkpoint loaded into . - /// Specify path to training model graph. - /// Specify path to optimizer model graph. + /// Training states that the training session uses as a starting point for training. + /// Model to be used to perform training. + /// Model to be used to perform weight update. public TrainingSession(CheckpointState state, string trainModelPath, string optimizerModelPath) { Init(null, state, NativeOnnxValueHelper.GetPlatformSerializedString(trainModelPath), null, NativeOnnxValueHelper.GetPlatformSerializedString(optimizerModelPath)); } /// - /// Creates TrainingSession from the model and checkpoint in . - /// - /// Model checkpoint loaded into . - /// Specify path to training model graph. - public TrainingSession(CheckpointState state, string trainModelPath) - { - Init(null, state, NativeOnnxValueHelper.GetPlatformSerializedString(trainModelPath), null, null); - } - - - /// - /// Creates TrainingSession from the model and checkpoint in . + /// Create a training session that can be used to begin or resume training. + /// + /// This constructor instantiates the training session based on the env and session options provided that can + /// begin or resume training from a given checkpoint state for the given onnx models. + /// The checkpoint state represents the parameters of the training session which will be moved + /// to the device specified by the user through the session options (if necessary). /// - /// Session options - /// Model checkpoint loaded into . - /// Specify path to training model graph. - /// Specify path to eval model graph. - /// Specify path to optimizer model graph. + /// SessionOptions that the user can customize for this training session. + /// Training states that the training session uses as a starting point for training. + /// Model to be used to perform training. + /// Model to be used to perform evaluation. + /// Model to be used to perform weight update. public TrainingSession(SessionOptions options, CheckpointState state, string trainModelPath, string evalModelPath, string optimizerModelPath) { Init(options, state, NativeOnnxValueHelper.GetPlatformSerializedString(trainModelPath), NativeOnnxValueHelper.GetPlatformSerializedString(evalModelPath), NativeOnnxValueHelper.GetPlatformSerializedString(optimizerModelPath)); } /// - /// Runs a train step on the loaded model for the given inputs. + /// Computes the outputs of the training model and the gradients of the trainable parameters for the given inputs + /// + /// This function performs a training step that computes the outputs of the training model and the gradients + /// of the trainable parameters for the given inputs. The train step is performed based on the training model + /// that was provided to the training session. + /// The TrainStep method is equivalent of running forward propagation and backward propagation in a single + /// step. + /// The gradients computed are stored inside the training session state so they can be later consumed + /// by the OptimizerStep function. + /// The gradients can be lazily reset by invoking the LazyResetGrad function. /// - /// Specify a collection of that indicates the input values. - /// Specify a collection of that indicates the output values. + /// Specify a collection of that indicates the input values to the training model. + /// Specify a collection of that indicates the output values of the training model. public void TrainStep( IReadOnlyCollection inputValues, IReadOnlyCollection outputValues) @@ -102,17 +144,26 @@ public void TrainStep( } /// - /// Runs a train step on the loaded model for the given inputs. Uses the given RunOptions for this run. + /// Computes the outputs of the training model and the gradients of the trainable parameters for the given inputs + /// + /// This function performs a training step that computes the outputs of the training model and the gradients + /// of the trainable parameters for the given inputs. The train step is performed based on the training model + /// that was provided to the training session. + /// The TrainStep method is equivalent of running forward propagation and backward propagation in a single + /// step. + /// The gradients computed are stored inside the training session state so they can be later consumed + /// by the OptimizerStep function. + /// The gradients can be lazily reset by invoking the LazyResetGrad function. /// /// Specify for step. - /// Specify a collection of that indicates the input values. - /// Specify a collection of that indicates the output values. + /// Specify a collection of that indicates the input values to the training model. + /// Specify a collection of that indicates the output values of the training model. public void TrainStep( RunOptions options, IReadOnlyCollection inputValues, IReadOnlyCollection outputValues) { - if (_trainOutputCount!= (ulong)outputValues.Count()) + if (_trainOutputCount != (ulong)outputValues.Count()) { throw new ArgumentException($"Length of {nameof(outputValues)} ({outputValues.Count}) must match that of train model ({_trainOutputCount})."); } @@ -124,32 +175,41 @@ public void TrainStep( } /// - /// Runs the loaded model for the given inputs, and fetches the graph outputs. + /// Computes the outputs of the training model and the gradients of the trainable parameters for the given inputs + /// + /// This function performs a training step that computes the outputs of the training model and the gradients + /// of the trainable parameters for the given inputs. The train step is performed based on the training model + /// that was provided to the training session. + /// The TrainStep method is equivalent of running forward propagation and backward propagation in a single + /// step. + /// The gradients computed are stored inside the training session state so they can be later consumed + /// by the OptimizerStep function. + /// The gradients can be lazily reset by invoking the LazyResetGrad function. /// - /// Specify a collection of that indicates the input values. + /// Specify a collection of that indicates the input values to the training model. /// Output Tensors in a Collection of NamedOnnxValue. User must dispose the output. public IDisposableReadOnlyCollection TrainStep( IReadOnlyCollection inputValues) { - using (var ortValues = new DisposableList((int)_trainOutputCount)) - { - IntPtr[] inputValuesArray = GetOrtValuesHandles(inputValues, true); - IntPtr[] outputValuesArray = new IntPtr[(int)_trainOutputCount]; + IntPtr[] inputValuesArray = GetOrtValuesHandles(inputValues, true); + IntPtr[] outputValuesArray = new IntPtr[(int)_trainOutputCount]; - NativeApiStatus.VerifySuccess(NativeTrainingMethods.OrtTrainStep(_nativeHandle, _builtInRunOptions.Handle, (UIntPtr)inputValues.Count, - inputValuesArray, (UIntPtr)_trainOutputCount, outputValuesArray)); - foreach (var v in outputValuesArray) - { - ortValues.Add(new OrtValue(v)); - } + NativeApiStatus.VerifySuccess(NativeTrainingMethods.OrtTrainStep(_nativeHandle, _builtInRunOptions.Handle, (UIntPtr)inputValues.Count, + inputValuesArray, (UIntPtr)_trainOutputCount, outputValuesArray)); + // On success ortValues would contain nulls that will be + // ignored. On failure, ortValues would contain at least + // some valid OrtValue instances that need to be disposed. + // It would be nice to use using() clause, but we need to upgrade to C# 8.0 for that. + var ortValueDisposer = ConvertNativeHandlesToOrtValues(outputValuesArray); + try + { var result = new DisposableList(_trainOutputNames.Count); try { - for (int i = 0; i < ortValues.Count; i++) + for (int i = 0; i < ortValueDisposer.Span.Length; i++) { - var ortValue = ortValues[i]; - result.Add(DisposableNamedOnnxValue.CreateFromOrtValue(_trainOutputNames[i], ortValue)); + result.Add(DisposableNamedOnnxValue.CreateFromOrtValue(_trainOutputNames[i], ref ortValueDisposer.Span[i])); } } catch (OnnxRuntimeException) @@ -159,37 +219,54 @@ public IDisposableReadOnlyCollection TrainStep( } return result; } + finally + { + // On success ortValues would contain nulls that will be + // ignored. On failure, ortValues would contain at least + // some valid OrtValue instances that need to be disposed. + ortValueDisposer.Dispose(); + } } /// - /// Runs the loaded model for the given inputs, and fetches the specified outputs in . Uses the given RunOptions for this run. + /// Computes the outputs of the training model and the gradients of the trainable parameters for the given inputs + /// + /// This function performs a training step that computes the outputs of the training model and the gradients + /// of the trainable parameters for the given inputs. The train step is performed based on the training model + /// that was provided to the training session. + /// The TrainStep method is equivalent of running forward propagation and backward propagation in a single + /// step. + /// The gradients computed are stored inside the training session state so they can be later consumed + /// by the OptimizerStep function. + /// The gradients can be lazily reset by invoking the LazyResetGrad function. /// /// Specify for step. - /// Specify a collection of that indicates the input values. + /// Specify a collection of that indicates the input values to the training model. /// Output Tensors in a Collection of NamedOnnxValue. User must dispose the output. public IDisposableReadOnlyCollection TrainStep( RunOptions options, IReadOnlyCollection inputValues) { - using (var ortValues = new DisposableList((int)_trainOutputCount)) - { - IntPtr[] inputValuesArray = GetOrtValuesHandles(inputValues, true); - IntPtr[] outputValuesArray = new IntPtr[(int)_trainOutputCount]; + IntPtr[] inputValuesArray = GetOrtValuesHandles(inputValues, true); + IntPtr[] outputValuesArray = new IntPtr[(int)_trainOutputCount]; + + NativeApiStatus.VerifySuccess(NativeTrainingMethods.OrtTrainStep(_nativeHandle, options.Handle, (UIntPtr)inputValues.Count, + inputValuesArray, (UIntPtr)_trainOutputCount, outputValuesArray)); - NativeApiStatus.VerifySuccess(NativeTrainingMethods.OrtTrainStep(_nativeHandle, options.Handle, (UIntPtr)inputValues.Count, - inputValuesArray, (UIntPtr)_trainOutputCount, outputValuesArray)); - foreach (var v in outputValuesArray) - { - ortValues.Add(new OrtValue(v)); - } + // On success ortValues would contain nulls that will be + // ignored. On failure, ortValues would contain at least + // some valid OrtValue instances that need to be disposed. + // It would be nice to use using() clause, but we need to upgrade to C# 8.0 for that. + var ortValueDisposer = ConvertNativeHandlesToOrtValues(outputValuesArray); + try + { var result = new DisposableList(_trainOutputNames.Count); try { - for (int i = 0; i < ortValues.Count; i++) + for (int i = 0; i < ortValueDisposer.Span.Length; i++) { - var ortValue = ortValues[i]; - result.Add(DisposableNamedOnnxValue.CreateFromOrtValue(_trainOutputNames[i], ortValue)); + result.Add(DisposableNamedOnnxValue.CreateFromOrtValue(_trainOutputNames[i], ref ortValueDisposer.Span[i])); } } catch (OnnxRuntimeException) @@ -199,11 +276,55 @@ public IDisposableReadOnlyCollection TrainStep( } return result; } + finally + { + ortValueDisposer.Dispose(); + } } /// - /// Sets the reset grad flag on the training graph. The gradient buffers will be reset while executing the - /// next train step. + /// Convert native OrtValue handles to OrtValue instances + /// in an exceptions safe manner. + /// + /// + /// + private DisposableArray ConvertNativeHandlesToOrtValues(IntPtr[] nativeHandles) + { + var diposableArray = new DisposableOrtValueHandleArray(nativeHandles); + try + { + var ortValues = new OrtValue[nativeHandles.Length]; + var ortValueDisposer = new DisposableArray(ortValues); + try + { + for (int i = 0; i < nativeHandles.Length; i++) + { + ortValues[i] = new OrtValue(nativeHandles[i]); + nativeHandles[i] = IntPtr.Zero; + } + return ortValueDisposer; + } + catch (Exception) + { + // ortValues is the result, dispose only on exception + ortValueDisposer.Dispose(); + throw; + } + } + catch (Exception) + { + // No need to dispose on exception since the ownership is transferred to ortValues + diposableArray.Dispose(); + throw; + } + } + + /// + /// Reset the gradients of all trainable parameters to zero lazily. + /// + /// This function sets the internal state of the training session such that the gradients of the trainable + /// parameters in the OrtCheckpointState will be scheduled to be reset just before the new gradients are + /// computed on the next invocation of the next TrainStep. /// public void LazyResetGrad() { @@ -211,10 +332,12 @@ public void LazyResetGrad() } /// - /// Runs an eval step on the loaded model for the given inputs. The eval graph must be passed while TrainingSession creation. + /// Computes the outputs for the eval model for the given inputs + /// This function performs an eval step that computes the outputs of the eval model for the given inputs. + /// The eval step is performed based on the eval model that was provided to the training session. /// - /// Specify a collection of that indicates the input values. - /// Specify a collection of that indicates the output values. + /// Specify a collection of that indicates the input values to the eval model. + /// Specify a collection of that indicates the output values of the eval model. public void EvalStep( IReadOnlyCollection inputValues, IReadOnlyCollection outputValues) @@ -223,11 +346,13 @@ public void EvalStep( } /// - /// Runs an eval step on the loaded model for the given inputs. The eval graph must be passed while TrainingSession creation. + /// Computes the outputs for the eval model for the given inputs + /// This function performs an eval step that computes the outputs of the eval model for the given inputs. + /// The eval step is performed based on the eval model that was provided to the training session. /// /// Specify for step. - /// Specify a collection of that indicates the input values. - /// Specify a collection of that indicates the output values. + /// Specify a collection of that indicates the input values to the eval model. + /// Specify a collection of that indicates the output values of the eval model. public void EvalStep( RunOptions options, IReadOnlyCollection inputValues, @@ -240,15 +365,27 @@ public void EvalStep( IntPtr[] inputValuesArray = GetOrtValuesHandles(inputValues, true); IntPtr[] outputValuesArray = GetOrtValuesHandles(outputValues, false); /* pointers to Pre-allocated OrtValue instances */ - NativeApiStatus.VerifySuccess(NativeTrainingMethods.OrtTrainStep(_nativeHandle, options.Handle, (UIntPtr)inputValues.Count, + NativeApiStatus.VerifySuccess(NativeTrainingMethods.OrtEvalStep(_nativeHandle, options.Handle, (UIntPtr)inputValues.Count, inputValuesArray, (UIntPtr)outputValues.Count, outputValuesArray)); } /// - /// Sets a constant learning rate for the session. LR must be controlled by either this method - /// or by registering a LR scheduler. + /// Sets the learning rate for this training session. + /// + /// This function allows users to set the learning rate for the training session. The current + /// learning rate is maintained by the training session and can be overwritten by invoking + /// this function with the desired learning rate. This function should not be used when a valid + /// learning rate scheduler is registered. It should be used either to set the learning rate + /// derived from a custom learning rate scheduler or to set a constant learning rate to be used + /// throughout the training session. + /// + /// Please note that this function does not set the initial learning rate that may be needed + /// by the predefined learning rate schedulers. To set the initial learning rate for learning + /// rate schedulers, please look at the function RegisterLinearLRScheduler. + /// /// + /// Desired learning rate to be set. public void SetLearningRate(float learningRate) { if (_scheduler != LRScheduler.None && _scheduler != LRScheduler.Constant) @@ -260,8 +397,13 @@ public void SetLearningRate(float learningRate) } /// - /// Gets the current learning rate for the session. + /// Gets the current learning rate for this training session. + /// + /// This function allows users to get the learning rate for the training session. The current + /// learning rate is maintained by the training session, and users can query it for the purpose + /// of implementing their own learning rate schedulers. /// + /// float representing the current learning rate. public float GetLearningRate() { NativeApiStatus.VerifySuccess(NativeTrainingMethods.OrtGetLearningRate(_nativeHandle, out float lr)); @@ -269,12 +411,16 @@ public float GetLearningRate() } /// - /// Registers a linear learning rate scheduler for the session. LR must be controlled by either - /// the SetLearningRate method or by registering a LR scheduler. + /// Registers a linear learning rate scheduler for the training session. + /// + /// Register a linear learning rate scheduler that decays the learning rate by linearly updated + /// multiplicative factor from the initial learning rate set on the training session to 0. The decay + /// is performed after the initial warm up phase where the learning rate is linearly incremented + /// from 0 to the initial learning rate provided. + /// /// Number of warmup steps /// Number of total steps /// Initial learning rate - /// public void RegisterLinearLRScheduler(long warmupStepCount, long totalStepCount, float initialLearningRate) @@ -284,12 +430,19 @@ public void RegisterLinearLRScheduler(long warmupStepCount, throw new InvalidOperationException("Cannot set LR scheduler while using constant LR."); } - NativeApiStatus.VerifySuccess(NativeTrainingMethods.OrtRegisterLinearLRScheduler(_nativeHandle, warmupStepCount,totalStepCount, initialLearningRate)); + NativeApiStatus.VerifySuccess(NativeTrainingMethods.OrtRegisterLinearLRScheduler(_nativeHandle, warmupStepCount, totalStepCount, initialLearningRate)); _scheduler = LRScheduler.Linear; } /// - /// Runs a LR scheduler step. There must be a valid LR scheduler registered for the training session. + /// Update the learning rate based on the registered learning rate scheduler. + /// + /// Takes a scheduler step that updates the learning rate that is being used by the training session. + /// This function should typically be called before invoking the optimizer step for each round, + /// or as determined necessary to update the learning rate being used by the training session. + /// + /// Please note that a valid predefined learning rate scheduler must be first registered to invoke this function. + /// /// public void SchedulerStep() { @@ -301,7 +454,13 @@ public void SchedulerStep() } /// - /// Runs an optimizer step on the loaded model for the given inputs. The optimizer graph must be passed while TrainingSession creation. + /// Performs the weight updates for the trainable parameters using the optimizer model. + /// + /// This function performs the weight update step that updates the trainable parameters such that they + /// take a step in the direction of their gradients (gradient descent). The optimizer step is performed + /// based on the optimizer model that was provided to the training session. + /// The updated parameters are stored inside the training state so that they can be used by the next + /// TrainStep function call. /// public void OptimizerStep() { @@ -309,24 +468,133 @@ public void OptimizerStep() } /// - /// Runs an eval step on the loaded model for the given inputs. The eval graph must be passed while TrainingSession creation. + /// Performs the weight updates for the trainable parameters using the optimizer model. + /// + /// This function performs the weight update step that updates the trainable parameters such that they + /// take a step in the direction of their gradients (gradient descent). The optimizer step is performed + /// based on the optimizer model that was provided to the training session. + /// The updated parameters are stored inside the training state so that they can be used by the next + /// TrainStep function call. /// /// Specify for step. - /// Specify a collection of that indicates the output values. public void OptimizerStep(RunOptions options) { NativeApiStatus.VerifySuccess(NativeTrainingMethods.OrtOptimizerStep(_nativeHandle, options.Handle)); } - #endregion - #region private methods + /// + /// Export a model that can be used for inferencing. + /// If the training session was provided with an eval model, the training session can generate + /// an inference model if it knows the inference graph outputs. The input inference graph outputs + /// are used to prune the eval model so that the inference model's outputs align with the provided outputs. + /// The exported model is saved at the path provided and can be used for inferencing with InferenceSession. + /// Note that the function re-loads the eval model from the path provided to TrainingSession + /// and expects that this path still be valid. + /// + /// Path where the inference model should be serialized to. + /// Names of the outputs that are needed in the inference model. + public void ExportModelForInferencing(string inferenceModelPath, IReadOnlyCollection graphOutputNames) + { + using (var cleanupList = new DisposableList()) + { + var outputNamesArray = ConvertNamesToUtf8(graphOutputNames, cleanupList); + NativeApiStatus.VerifySuccess(NativeTrainingMethods.OrtExportModelForInferencing( + _nativeHandle, NativeOnnxValueHelper.GetPlatformSerializedString(inferenceModelPath), + (UIntPtr)graphOutputNames.Count, outputNamesArray)); + } + } + + /// + /// Returns a contiguous buffer that holds a copy of all training state parameters + /// + /// Whether to only copy trainable parameters or to copy all parameters. + public FixedBufferOnnxValue ToBuffer(bool onlyTrainable) + { + UIntPtr bufferSize = UIntPtr.Zero; + NativeApiStatus.VerifySuccess(NativeTrainingMethods.OrtGetParametersSize(_nativeHandle, out bufferSize, onlyTrainable)); + + float[] bufferMemory = new float[bufferSize.ToUInt64()]; + + var memInfo = OrtMemoryInfo.DefaultInstance; // CPU + var shape = new long[] { (long)bufferSize.ToUInt64() }; + var buffer = FixedBufferOnnxValue.CreateFromMemory(memInfo, bufferMemory, Tensors.TensorElementType.Float, shape, (long)bufferSize.ToUInt64() * sizeof(float)); + + NativeApiStatus.VerifySuccess(NativeTrainingMethods.OrtCopyParametersToBuffer(_nativeHandle, buffer.Value.Handle, onlyTrainable)); + + return buffer; + } + + /// + /// Loads the training session model parameters from a contiguous buffer + /// + /// Contiguous buffer to load the parameters from. + public void FromBuffer(FixedBufferOnnxValue buffer) + { + if (buffer.OnnxValueType != OnnxValueType.ONNX_TYPE_TENSOR) + { + throw new ArgumentException("Incorrect buffer received. Expected a tensor buffer."); + } + + IntPtr typeAndShapeInfo = IntPtr.Zero; + NativeApiStatus.VerifySuccess(NativeMethods.OrtGetTensorTypeAndShape(buffer.Value.Handle, out typeAndShapeInfo)); + UIntPtr numDimensions = UIntPtr.Zero; + NativeApiStatus.VerifySuccess(NativeMethods.OrtGetDimensionsCount(typeAndShapeInfo, out numDimensions)); + if (numDimensions.ToUInt64() != 1) + { + string errorMessage = "Incorrect buffer shape received. Expected a contiguous tensor buffer. Expected number of dimensions: 1, Actual: " + numDimensions.ToString(); + throw new ArgumentException(errorMessage); + } + + // Here buffer size represents the number of elements in the buffer + NativeApiStatus.VerifySuccess(NativeMethods.OrtGetTensorShapeElementCount(typeAndShapeInfo, out UIntPtr bufferSize)); + + // OrtGetParametersSize returns the total number of elements in the model's parameters. + UIntPtr numElementsTrainingOnly = UIntPtr.Zero; + NativeApiStatus.VerifySuccess(NativeTrainingMethods.OrtGetParametersSize(_nativeHandle, out numElementsTrainingOnly, true)); + if ((ulong)bufferSize == (ulong)numElementsTrainingOnly) + { + NativeApiStatus.VerifySuccess(NativeTrainingMethods.OrtCopyBufferToParameters(_nativeHandle, buffer.Value.Handle, true)); + return; + } + + UIntPtr numElements = UIntPtr.Zero; + NativeApiStatus.VerifySuccess(NativeTrainingMethods.OrtGetParametersSize(_nativeHandle, out numElements, false)); + if ((ulong)bufferSize != (ulong)numElements) + { + string errorMessage = "Incorrect buffer size received. Expected size to be one of " + numElementsTrainingOnly.ToString() + " (training only) or " + numElements.ToString() + " (all parameters). Actual size: " + bufferSize.ToString(); + throw new ArgumentException(errorMessage); + } + + NativeApiStatus.VerifySuccess(NativeTrainingMethods.OrtCopyBufferToParameters(_nativeHandle, buffer.Value.Handle, false)); + } + + /// + /// Retrieves the names of the user outputs for the training and eval models. + /// + /// Whether the training model output names are requested or eval model output names. + public List OutputNames(bool training) + { + return training ? _trainOutputNames : _evalOutputNames; + } + + /// + /// Retrieves the names of the user inputs for the training and eval models. + /// + /// Whether the training model input names are requested or eval model input names. + public List InputNames(bool training) + { + return training ? _trainInputNames : _evalInputNames; + } + + #endregion + #region private methods private void Init(SessionOptions sessOptions, CheckpointState state, byte[] trainModelPath, byte[] evalModelPath, byte[] optimizerModelPath) { if (!NativeTrainingMethods.TrainingEnabled()) { - throw new InvalidOperationException("Training is disabled in the current build. Please build ONNXRuntime from source with the build flags enable_training_apis. \n"); + throw new InvalidOperationException("This package does not contain the training API. Please install the Microsoft.ML.OnnxRuntime.Training NuGet package.\n"); } var options = sessOptions; if (sessOptions == null) @@ -351,6 +619,14 @@ private void Init(SessionOptions sessOptions, CheckpointState state, byte[] trai _trainOutputNames.Add(GetOutputName(i, true)); } + _trainInputNames = new List(); + UIntPtr inputCount = UIntPtr.Zero; + NativeApiStatus.VerifySuccess(NativeTrainingMethods.OrtGetTrainingModelInputCount(_nativeHandle, out inputCount)); + for (ulong i = 0; i < inputCount.ToUInt64(); i++) + { + _trainInputNames.Add(GetInputName(i, true)); + } + if (evalModelPath != null) { outputCount = UIntPtr.Zero; @@ -361,6 +637,14 @@ private void Init(SessionOptions sessOptions, CheckpointState state, byte[] trai { _evalOutputNames.Add(GetOutputName(i, false)); } + + _evalInputNames = new List(); + inputCount = UIntPtr.Zero; + NativeApiStatus.VerifySuccess(NativeTrainingMethods.OrtGetEvalModelInputCount(_nativeHandle, out inputCount)); + for (ulong i = 0; i < inputCount.ToUInt64(); i++) + { + _evalInputNames.Add(GetInputName(i, false)); + } } _builtInRunOptions = new RunOptions(); // create a default built-in run option, and avoid creating a new one every run() call @@ -395,6 +679,29 @@ private string GetOutputName(ulong index, bool training) return NativeOnnxValueHelper.StringFromNativeUtf8(nameHandle, allocator); } + private string GetInputName(ulong index, bool training) + { + var allocator = OrtAllocator.DefaultInstance; + IntPtr nameHandle; + if (training) + { + NativeApiStatus.VerifySuccess(NativeTrainingMethods.OrtGetTrainingModelInputName( + _nativeHandle, + (UIntPtr)index, + allocator.Pointer, + out nameHandle)); + } + else + { + NativeApiStatus.VerifySuccess(NativeTrainingMethods.OrtGetEvalModelInputName( + _nativeHandle, + (UIntPtr)index, + allocator.Pointer, + out nameHandle)); + } + return NativeOnnxValueHelper.StringFromNativeUtf8(nameHandle, allocator); + } + private IntPtr[] GetOrtValuesHandles(IReadOnlyCollection values, bool input) { var valuesArray = new IntPtr[values.Count]; @@ -410,6 +717,24 @@ private IntPtr[] GetOrtValuesHandles(IReadOnlyCollection v return valuesArray; } + private IntPtr[] ConvertNamesToUtf8(IReadOnlyCollection names, DisposableList cleanupList) + { + cleanupList.Capacity += names.Count; + var result = new IntPtr[names.Count]; + for (int i = 0; i < names.Count; ++i) + { + var name = names.ElementAt(i); + var utf8Name = NativeOnnxValueHelper.StringToZeroTerminatedUtf8(name); + var pinnedHandle = new Memory(utf8Name).Pin(); + unsafe + { + result[i] = (IntPtr)pinnedHandle.Pointer; + } + cleanupList.Add(pinnedHandle); + } + return result; + } + /// /// Other classes access /// @@ -421,9 +746,9 @@ internal IntPtr Handle } } - #endregion + #endregion - #region IDisposable + #region IDisposable /// /// Finalizer. @@ -481,7 +806,7 @@ private void CleanupHelper(bool disposing) } } - #endregion + #endregion } #endif } 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 f44db30afdc98..1c9827c5bac62 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 @@ -6,11 +6,12 @@ AnyCPU bin\$(Configuration)\ - 1.9.0 + 1.15.0 Microsoft.ML.OnnxRuntime true true true + default True true ..\..\OnnxRuntime.snk @@ -47,9 +48,10 @@ - - - + + + + @@ -102,4 +104,5 @@ + diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/runtest.sh b/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/runtest.sh index f56fdc802cd40..39f0ff1c2f85e 100755 --- a/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/runtest.sh +++ b/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/runtest.sh @@ -40,6 +40,9 @@ if [ $RunTestCsharp = "true" ]; then exit 1 fi dotnet test -p:DefineConstants=USE_TENSORRT $BUILD_SOURCESDIRECTORY/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/Microsoft.ML.OnnxRuntime.EndToEndTests.csproj --no-restore --verbosity detailed + elif [ $PACKAGENAME = "Microsoft.ML.OnnxRuntime.ROCm" ]; then + export TESTONGPU=ON + dotnet test -p:DefineConstants=USE_ROCM $BUILD_SOURCESDIRECTORY/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/Microsoft.ML.OnnxRuntime.EndToEndTests.csproj --no-restore --verbosity detailed else dotnet test $BUILD_SOURCESDIRECTORY/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/Microsoft.ML.OnnxRuntime.EndToEndTests.csproj --no-restore --verbosity detailed fi diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/EqualityComparers.cs b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/EqualityComparers.cs new file mode 100644 index 0000000000000..44a9f8acf0b7e --- /dev/null +++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/EqualityComparers.cs @@ -0,0 +1,80 @@ +using Microsoft.ML.OnnxRuntime.Tensors; +using System; +using System.Collections.Generic; + +namespace Microsoft.ML.OnnxRuntime.Tests +{ + internal class FloatComparer : IEqualityComparer + { + private float atol = 1e-3f; + private float rtol = 1.7e-2f; + + public bool Equals(float x, float y) + { + return Math.Abs(x - y) <= (atol + rtol * Math.Abs(y)); + } + public int GetHashCode(float x) + { + return x.GetHashCode(); + } + } + + internal class DoubleComparer : IEqualityComparer + { + private double atol = 1e-3; + private double rtol = 1.7e-2; + + public bool Equals(double x, double y) + { + return Math.Abs(x - y) <= (atol + rtol * Math.Abs(y)); + } + public int GetHashCode(double x) + { + return x.GetHashCode(); + } + } + + internal class ExactComparer : IEqualityComparer + { + public bool Equals(T x, T y) + { + return x.Equals(y); + } + public int GetHashCode(T x) + { + return x.GetHashCode(); + } + } + + /// + /// Use it to compare Float16 + /// + internal class Float16Comparer : IEqualityComparer + { + public ushort tolerance = 0; + public bool Equals(Float16 x, Float16 y) + { + return Math.Abs(x.value - y.value) <= (tolerance + y.value); + } + public int GetHashCode(Float16 x) + { + return x.GetHashCode(); + } + } + + /// + /// Use it to compare Bloat16 + /// + internal class BFloat16Comparer : IEqualityComparer + { + public ushort tolerance = 0; + public bool Equals(BFloat16 x, BFloat16 y) + { + return Math.Abs(x.value - y.value) <= (tolerance + y.value); + } + public int GetHashCode(BFloat16 x) + { + return x.GetHashCode(); + } + } +} diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/InferenceTest.cs b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/InferenceTest.cs index 61205b741282e..fd8feda359f90 100644 --- a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/InferenceTest.cs +++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/InferenceTest.cs @@ -5,7 +5,12 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Linq.Expressions; +using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; +using System.Text.RegularExpressions; +using System.Threading; using System.Threading.Tasks; using Xunit; using Xunit.Abstractions; @@ -92,6 +97,11 @@ public void TestSessionOptions() var ex = Assert.Throws(() => { opt.AddSessionConfigEntry("", "invalid key"); }); Assert.Contains("[ErrorCode:InvalidArgument] Config key is empty", ex.Message); + // 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); + #if USE_CUDA opt.AppendExecutionProvider_CUDA(0); #endif @@ -103,7 +113,19 @@ public void TestSessionOptions() var directml_dll_path = AppDomain.CurrentDomain.BaseDirectory; SetDllDirectory(directml_dll_path); - opt.AppendExecutionProvider_DML(0); + + try + { + opt.AppendExecutionProvider_DML(0); + } + catch (OnnxRuntimeException ortException) + { + // if we run on a CI machine with the incorrect hardware we might get an error due to that. + // allow that as the call made it through to the DML EP so the C# layer is working correctly. + // any other exception type or error message is considered a failure. + Assert.Contains("The specified device interface or feature level is not supported on this system.", + ortException.Message); + } // Restore the default dll search order SetDllDirectory(null); @@ -130,7 +152,7 @@ public void TestSessionOptions() #endif #if USE_ROCM - opt.AppendExecutionProvider_ROCM(0); + opt.AppendExecutionProvider_ROCm(0); #endif #if USE_TENSORRT @@ -268,9 +290,9 @@ private void CanRunInferenceOnAModel(GraphOptimizationLevel graphOptimizationLev { // Set the graph optimization level for this session. SessionOptions options = new SessionOptions(); + cleanUp.Add(options); options.GraphOptimizationLevel = graphOptimizationLevel; if (enableParallelExecution) options.ExecutionMode = ExecutionMode.ORT_PARALLEL; - cleanUp.Add(options); var session = new InferenceSession(model, options); cleanUp.Add(session); @@ -345,8 +367,8 @@ private void CanRunInferenceOnAModel(GraphOptimizationLevel graphOptimizationLev var inputName = inputNames[0]; Assert.Equal(typeof(float), inputMeta[inputName].ElementType); Assert.True(inputMeta[inputName].IsTensor); - var longShape = Array.ConvertAll(inputMeta[inputName].Dimensions, d => d); - var byteSize = longShape.Aggregate(1L, (a, b) => a * b) * sizeof(float); + var longShape = Array.ConvertAll(inputMeta[inputName].Dimensions, Convert.ToInt64); + var byteSize = ShapeUtils.GetSizeForShape(longShape); pinnedInputs.Add(FixedBufferOnnxValue.CreateFromMemory(memInfo, inputData, TensorElementType.Float, longShape, byteSize)); @@ -357,8 +379,8 @@ private void CanRunInferenceOnAModel(GraphOptimizationLevel graphOptimizationLev var outputName = outputNames[0]; Assert.Equal(typeof(float), outputMeta[outputName].ElementType); Assert.True(outputMeta[outputName].IsTensor); - longShape = Array.ConvertAll(outputMeta[outputName].Dimensions, d => d); - byteSize = longShape.Aggregate(1L, (a, b) => a * b) * sizeof(float); + longShape = Array.ConvertAll(outputMeta[outputName].Dimensions, Convert.ToInt64); + byteSize = ShapeUtils.GetSizeForShape(longShape); float[] outputBuffer = new float[expectedOutput.Length]; pinnedOutputs.Add(FixedBufferOnnxValue.CreateFromMemory(memInfo, outputBuffer, TensorElementType.Float, longShape, byteSize)); @@ -421,43 +443,100 @@ private void CanRunInferenceOnAModel(GraphOptimizationLevel graphOptimizationLev } } - [Fact(DisplayName = "InferenceSessionManualDisposeAfterUse")] - public void InferenceSessionManualDisposeAfterUse() + [Fact(DisplayName = "RunInferenceUsingPreAllocatedOutputsAndDictionary")] + public void RunInferenceUsingPreAllocatedOutputsAndDictionary() { var model = TestDataLoader.LoadModelFromEmbeddedResource("squeezenet.onnx"); + using (var cleanUp = new DisposableListTest()) + { + var runOptions = new RunOptions(); + cleanUp.Add(runOptions); + var session = new InferenceSession(model); + cleanUp.Add(session); - // Set the graph optimization level for this session. - SessionOptions options = new SessionOptions(); - options.ProfileOutputPathPrefix = "Ort_P_"; - options.EnableProfiling = true; - var session = new InferenceSession(model, options); + var inputMeta = session.InputMetadata; + Assert.Single(inputMeta.Keys); + var inputNames = inputMeta.Keys.ToList().AsReadOnly(); + Assert.Equal(TensorElementType.Float, inputMeta[inputNames[0]].ElementDataType); + Assert.True(inputMeta[inputNames[0]].IsTensor); + var inputShape = Array.ConvertAll(inputMeta[inputNames[0]].Dimensions, Convert.ToInt64); - var inputMeta = session.InputMetadata; - var container = new List(); - float[] inputData = TestDataLoader.LoadTensorFromEmbeddedResource("bench.in"); // this is the data for only one input tensor for this model + var outputMeta = session.OutputMetadata; + var expectedOutputNames = new List { "softmaxout_1" }.AsReadOnly(); + Assert.Contains(expectedOutputNames[0], outputMeta.Keys); + long[] expectedShape = { 1, 1000, 1, 1 }; // hardcoded for the test data - foreach (var name in inputMeta.Keys) - { - Assert.Equal(typeof(float), inputMeta[name].ElementType); - Assert.True(inputMeta[name].IsTensor); - var tensor = new DenseTensor(inputData, inputMeta[name].Dimensions); - container.Add(NamedOnnxValue.CreateFromTensor(name, tensor)); + // this is the data for only one input tensor for this model + float[] inputData = TestDataLoader.LoadTensorFromEmbeddedResource("bench.in"); + float[] expectedOutput = TestDataLoader.LoadTensorFromEmbeddedResource("bench.expected_out"); + + // Allocate input OrtValue on top of the inputData + // Input should stay pinned for the entire duration of the inference + var inputOrtValue = OrtValue.CreateTensorValueFromMemory(inputData, inputShape); + cleanUp.Add(inputOrtValue); + + // Create OrtValue and pre-allocate output buffer using the expected output shape + using (var outputOrtValue = OrtValue.CreateAllocatedTensorValue(OrtAllocator.DefaultInstance, + TensorElementType.Float, expectedShape)) + { + // Run inference + var inputValues = new List { inputOrtValue }.AsReadOnly(); + var outputValues = new List { outputOrtValue }.AsReadOnly(); + session.Run(runOptions, inputNames, inputValues, + expectedOutputNames, outputValues); + ValidateRunResult(outputOrtValue, expectedOutput, expectedShape); + } + + //Let's run this again with an interface that takes a Dictionary of name/OrtValue + var inputDict = new Dictionary(); + inputDict.Add(inputNames[0], inputOrtValue); + using (var results = session.Run(runOptions, inputDict, expectedOutputNames)) + { + Assert.Single(results); + var outputOrtValue = results[0]; + ValidateRunResult(outputOrtValue, expectedOutput, expectedShape); + } } + } - // Run inference with named inputs and outputs created with in Run() - using (var results = session.Run(container)) // results is an IReadOnlyList container + [Fact(DisplayName = "InferenceSessionDisposed")] + public void InferenceSessionDisposed() + { + var model = TestDataLoader.LoadModelFromEmbeddedResource("squeezenet.onnx"); + + // Set the graph optimization level for this session. + using (SessionOptions options = new SessionOptions()) { - ValidateRunResults(results); - } + options.ProfileOutputPathPrefix = "Ort_P_"; + options.EnableProfiling = true; + using (var session = new InferenceSession(model, options)) + { + var inputMeta = session.InputMetadata; + var container = new List(); - string profile_file = session.EndProfiling(); + float[] inputData = TestDataLoader.LoadTensorFromEmbeddedResource("bench.in"); // this is the data for only one input tensor for this model - // Profile file should have the output path prefix in it - Assert.Contains("Ort_P_", profile_file); + foreach (var name in inputMeta.Keys) + { + Assert.Equal(typeof(float), inputMeta[name].ElementType); + Assert.True(inputMeta[name].IsTensor); + var tensor = new DenseTensor(inputData, inputMeta[name].Dimensions); + container.Add(NamedOnnxValue.CreateFromTensor(name, tensor)); + } - // Should be able to dispose the session manually - session.Dispose(); + // Run inference with named inputs and outputs created with in Run() + using (var results = session.Run(container)) // results is an IReadOnlyList container + { + ValidateRunResults(results); + } + + string profile_file = session.EndProfiling(); + + // Profile file should have the output path prefix in it + Assert.Contains("Ort_P_", profile_file); + } + } } [Fact(DisplayName = "InferenceSessionGetProfilingStartTimeNs")] @@ -556,6 +635,19 @@ private void ValidateRunResultData(Tensor resultTensor, float[] expectedO Assert.Equal(expectedOutput, resultArray, new FloatComparer()); } + private static void ValidateRunResult(OrtValue resultTensor, ReadOnlySpan expectedOutput, long[] expectedShape) + { + Assert.True(resultTensor.IsTensor); + + var typeShape = resultTensor.GetTensorTypeAndShape(); + Assert.Equal(TensorElementType.Float, typeShape.ElementDataType); + + Assert.Equal(typeShape.Shape, expectedShape); + var resultSpan = resultTensor.GetTensorDataAsSpan().ToArray(); + var expectedSpan = expectedOutput.ToArray(); + Assert.Equal(expectedSpan, resultSpan, new FloatComparer()); + } + [Fact(DisplayName = "ThrowWrongInputName")] private void ThrowWrongInputName() { @@ -1232,12 +1324,13 @@ private void TestModelInputUINT64() private void TestModelInputFLOAT16() { // model takes 1x5 input of fixed type, echoes back + Float16[] modelInput = { new Float16(15360), new Float16(16384), new Float16(16896), new Float16(17408), new Float16(17664) }; + int[] inputShape = { 1, 5 }; var model = TestDataLoader.LoadModelFromEmbeddedResource("test_types_FLOAT16.onnx"); using (var session = new InferenceSession(model)) { var container = new List(); - var tensorIn = new DenseTensor( - new Float16[] { 15360, 16384, 16896, 17408, 17664 }, new int[] { 1, 5 }); + var tensorIn = new DenseTensor(modelInput, inputShape); var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn); container.Add(nov); using (var res = session.Run(container)) @@ -1254,13 +1347,15 @@ private void TestModelInputFLOAT16() [Fact(DisplayName = "TestModelInputBFLOAT16")] private void TestModelInputBFLOAT16() { + BFloat16[] modelInput = { new BFloat16(16256), new BFloat16(16384), + new BFloat16(16448), new BFloat16(16512), new BFloat16(16544) }; + int[] inputShape = { 1, 5 }; // model takes 1x5 input of fixed type, echoes back var model = TestDataLoader.LoadModelFromEmbeddedResource("test_types_BFLOAT16.onnx"); using (var session = new InferenceSession(model)) { var container = new List(); - var tensorIn = new DenseTensor( - new BFloat16[] { 16256, 16384, 16448, 16512, 16544 }, new int[] { 1, 5 }); + var tensorIn = new DenseTensor(modelInput, inputShape); var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn); container.Add(nov); using (var res = session.Run(container)) @@ -1429,7 +1524,7 @@ private void TestModelSequenceOfMapStringFloat() var outNode0 = outputs.ElementAtOrDefault(0); Assert.Equal("label", outNode0.Name); Assert.Equal(OnnxValueType.ONNX_TYPE_TENSOR, outNode0.ValueType); - Assert.Equal(TensorElementType.String, (TensorElementType)outNode0.ElementType); + Assert.Equal(TensorElementType.String, outNode0.ElementType); // try-cast as a tensor var outLabelTensor = outNode0.AsTensor(); @@ -1638,9 +1733,9 @@ void TestCUDAAllocatorInternal(InferenceSession session) void TestROCMAllocatorInternal(InferenceSession session) { int device_id = 0; - using (var info_rocm = new OrtMemoryInfo(OrtMemoryInfo.allocatorROCM, OrtAllocatorType.ArenaAllocator, device_id, OrtMemType.Default)) + using (var info_rocm = new OrtMemoryInfo(OrtMemoryInfo.allocatorHIP, OrtAllocatorType.ArenaAllocator, device_id, OrtMemType.Default)) { - Assert.Equal("Rocm", info_rocm.Name); + Assert.Equal("Hip", info_rocm.Name); Assert.Equal(device_id, info_rocm.Id); Assert.Equal(OrtAllocatorType.ArenaAllocator, info_rocm.GetAllocatorType()); Assert.Equal(OrtMemType.Default, info_rocm.GetMemoryType()); @@ -1673,7 +1768,7 @@ private void TestAllocator() #endif #if USE_ROCM - options.AppendExecutionProvider_ROCM(0); + options.AppendExecutionProvider_ROCm(0); #endif using (var session = new InferenceSession(model, options)) @@ -1690,91 +1785,6 @@ private void TestAllocator() } } - [Fact(DisplayName = "TestIOBinding")] - private void TestIOBinding() - { - var inputName = "data_0"; - var outputName = "softmaxout_1"; - var allocator = OrtAllocator.DefaultInstance; - // From the model - using (var dispList = new DisposableListTest()) - { - var tuple = OpenSessionSqueezeNet(); - var session = tuple.Item1; - var inputData = tuple.Item2; - var inputTensor = tuple.Item3; - var outputData = tuple.Item4; - dispList.Add(session); - var runOptions = new RunOptions(); - dispList.Add(runOptions); - - var inputMeta = session.InputMetadata; - var outputMeta = session.OutputMetadata; - var outputTensor = new DenseTensor(outputData, outputMeta[outputName].Dimensions); - - var ioBinding = session.CreateIoBinding(); - dispList.Add(ioBinding); - - var ortAllocationOutput = allocator.Allocate((uint)outputData.Length * sizeof(float)); - dispList.Add(ortAllocationOutput); - - // Test GetOutputNames, bind two output names - { - var cyrName = "несуществующийВыход"; - var longShape = Array.ConvertAll(outputMeta[outputName].Dimensions, i => i); - ioBinding.BindOutput(outputName, TensorElementType.Float, longShape, ortAllocationOutput); - ioBinding.BindOutput(cyrName, TensorElementType.Float, longShape, ortAllocationOutput); - string[] outputs = ioBinding.GetOutputNames(); - Assert.Equal(2, outputs.Length); - Assert.Equal(outputName, outputs[0]); - Assert.Equal(cyrName, outputs[1]); - ioBinding.ClearBoundOutputs(); - } - - // Test 1. Bind input to fixed, Bind Output to Fixed. - using (FixedBufferOnnxValue fixeInputBuffer = FixedBufferOnnxValue.CreateFromTensor(inputTensor), - fixedOutputBuffer = FixedBufferOnnxValue.CreateFromTensor(outputTensor)) - { - ioBinding.BindInput(inputName, fixeInputBuffer); - ioBinding.BindOutput(outputName, fixedOutputBuffer); - ioBinding.SynchronizeBoundInputs(); - using (var outputs = session.RunWithBindingAndNames(runOptions, ioBinding)) - { - ioBinding.SynchronizeBoundOutputs(); - Assert.Equal(1, outputs.Count); - var output = outputs.First(); - Assert.Equal(outputName, output.Name); - var tensor = output.AsTensor(); - Assert.True(tensor.IsFixedSize); - Assert.Equal(outputData, tensor.ToArray(), new FloatComparer()); - } - } - - // Test 2. Bind input to preallocated buffer. Output to a device so the allocation would happen - // automatically - using (FixedBufferOnnxValue fixedInputBuffer = FixedBufferOnnxValue.CreateFromTensor(inputTensor)) - { - ioBinding.BindInput(inputName, fixedInputBuffer); - ioBinding.BindOutputToDevice(outputName, allocator.Info); - ioBinding.SynchronizeBoundInputs(); - using (var outputs = session.RunWithBindingAndNames(runOptions, ioBinding)) - { - ioBinding.SynchronizeBoundOutputs(); - Assert.Equal(1, outputs.Count); - var output = outputs.First(); - Assert.Equal(outputName, output.Name); - var tensor = output.AsTensor(); - Assert.True(tensor.IsFixedSize); - Assert.Equal(outputData, tensor.ToArray(), new FloatComparer()); - } - } - - // Rebinding would happen without these but we want run them. - ioBinding.ClearBoundInputs(); - ioBinding.ClearBoundOutputs(); - } - } - [Fact(DisplayName = "TestSharingOfInitializerAndItsPrepackedVersion")] private void TestSharingOfInitializerAndItsPrepackedVersion() { @@ -1988,7 +1998,7 @@ internal static Tuple, float[]> Op #endif var session = (deviceId.HasValue) ? new InferenceSession(model, option) - : new InferenceSession(model); + : new InferenceSession(model); float[] inputData = TestDataLoader.LoadTensorFromEmbeddedResource("bench.in"); float[] expectedOutput = TestDataLoader.LoadTensorFromEmbeddedResource("bench.expected_out"); var inputMeta = session.InputMetadata; @@ -1997,77 +2007,6 @@ internal static Tuple, float[]> Op } } - internal class FloatComparer : IEqualityComparer - { - private float atol = 1e-3f; - private float rtol = 1.7e-2f; - - public bool Equals(float x, float y) - { - return Math.Abs(x - y) <= (atol + rtol * Math.Abs(y)); - } - public int GetHashCode(float x) - { - return x.GetHashCode(); - } - } - - internal class DoubleComparer : IEqualityComparer - { - private double atol = 1e-3; - private double rtol = 1.7e-2; - - public bool Equals(double x, double y) - { - return Math.Abs(x - y) <= (atol + rtol * Math.Abs(y)); - } - public int GetHashCode(double x) - { - return x.GetHashCode(); - } - } - - class ExactComparer : IEqualityComparer - { - public bool Equals(T x, T y) - { - return x.Equals(y); - } - public int GetHashCode(T x) - { - return x.GetHashCode(); - } - } - - /// - /// Use it to compare Float16 and BFloat16 - /// - internal class Float16Comparer : IEqualityComparer - { - public ushort tolerance = 0; - public bool Equals(Float16 x, Float16 y) - { - return Math.Abs(x - y) <= (tolerance + y); - } - public int GetHashCode(Float16 x) - { - return x.GetHashCode(); - } - } - - internal class BFloat16Comparer : IEqualityComparer - { - public ushort tolerance = 0; - public bool Equals(BFloat16 x, BFloat16 y) - { - return Math.Abs(x - y) <= (tolerance + y); - } - public int GetHashCode(BFloat16 x) - { - return x.GetHashCode(); - } - } - private class GpuFact : FactAttribute { public GpuFact() @@ -2091,48 +2030,104 @@ public SkipNonPackageTests() } } } - } - // Copy of the class that is internal in the main package - internal class DisposableListTest : List, IDisposableReadOnlyCollection - where T : IDisposable - { - public DisposableListTest() { } - public DisposableListTest(int count) : base(count) { } + [Fact(DisplayName = "TestModelRunAsyncTask")] + private async void TestModelRunAsyncTask() + { + Float16[] inputData = { new Float16(15360), new Float16(16384), new Float16(16896), new Float16(17408), new Float16(17664) }; + long[] shape = { 1, 5 }; - #region IDisposable Support - private bool disposedValue = false; // To detect redundant calls + var inputNames = new List { "input" }; + var inputValues = new List { OrtValue.CreateTensorValueFromMemory(inputData, shape) }; - protected virtual void Dispose(bool disposing) - { - if (!disposedValue) + var outputNames = new List { "output" }; + var outputValues = new List { OrtValue.CreateAllocatedTensorValue(OrtAllocator.DefaultInstance, + TensorElementType.Float16, shape) }; + + var model = TestDataLoader.LoadModelFromEmbeddedResource("test_types_FLOAT16.onnx"); + using (SessionOptions opt = new SessionOptions()) { - if (disposing) + opt.IntraOpNumThreads = 2; + using (var session = new InferenceSession(model, opt)) { - // Dispose in the reverse order. - // Objects should typically be destroyed/disposed - // in the reverse order of its creation - // especially if the objects created later refer to the - // objects created earlier. For homogeneous collections of objects - // it would not matter. - for (int i = this.Count - 1; i >= 0; --i) + try + { + var task = session.RunAsync(null, inputNames, inputValues, outputNames, outputValues); + var outputs = await task; + var valueOut = outputs.ElementAt(0); + var float16s = valueOut.GetTensorDataAsSpan().ToArray(); + Assert.Equal(new Float16(16896), float16s[2]); + } + catch { - this[i]?.Dispose(); + Assert.True(false); } - this.Clear(); } + } + } + + [Fact(DisplayName = "TestModelRunAsyncTaskFail")] + private async void TestModelRunAsyncTaskFail() + { + Float16[] inputData = { new Float16(15360), new Float16(16384), new Float16(16896), new Float16(17408), new Float16(17664) }; + long[] shape = { 1, 5 }; - disposedValue = true; + var inputNames = new List { "input" }; + var inputValues = new List { OrtValue.CreateTensorValueFromMemory(inputData, shape) }; + + var outputNames = new List { "output" }; + var outputValues = new List { OrtValue.CreateAllocatedTensorValue(OrtAllocator.DefaultInstance, + TensorElementType.Float16, shape) }; + + var model = TestDataLoader.LoadModelFromEmbeddedResource("test_types_FLOAT16.onnx"); + using (SessionOptions opt = new SessionOptions()) + { + opt.IntraOpNumThreads = 1; // this will make RunAsync fail + string err = ""; + using (var session = new InferenceSession(model, opt)) + { + try + { + var task = session.RunAsync(null, inputNames, inputValues, outputNames, outputValues); + var outputs = await task; + } + catch (Exception ex) + { + err = ex.Message; + } + finally + { + Assert.Contains("intra op thread pool must have at least one thread for RunAsync", err); + } + } } } - // This code added to correctly implement the disposable pattern. - public void Dispose() +#if USE_AZURE + [Fact(DisplayName = "TestLoadAzureEP")] + private void TestLoadAzureEP() { - // Do not change this code. Put cleanup code in Dispose(bool disposing) above. - Dispose(true); - GC.SuppressFinalize(this); + var model = TestDataLoader.LoadModelFromEmbeddedResource("mul_1.onnx"); + + using (var memInfo = new OrtMemoryInfo(OrtMemoryInfo.allocatorCPU, + OrtAllocatorType.ArenaAllocator, 0, OrtMemType.Default)) + using (var arenaCfg = new OrtArenaCfg(0, -1, -1, -1)) + { + using (var sessionOptions = new SessionOptions()) + { + sessionOptions.AppendExecutionProvider("AZURE"); + try { + using (var session1 = new InferenceSession(model, sessionOptions)) + { + + } + } + catch (Exception) { + Assert.True(false); + } + } + } } - #endregion +#endif } } diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/Microsoft.ML.OnnxRuntime.Tests.Common.csproj b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/Microsoft.ML.OnnxRuntime.Tests.Common.csproj index cc4cc5ea65ae0..ee81ab77432d1 100644 --- a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/Microsoft.ML.OnnxRuntime.Tests.Common.csproj +++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/Microsoft.ML.OnnxRuntime.Tests.Common.csproj @@ -1,18 +1,20 @@  - netstandard2.0 + + netstandard2.0;net6.0 false $(ProjectDir)..\.. - AnyCPU;x86 + AnyCPU bin\$(Configuration)\ - true - true - true - $(OnnxRuntimeCsharpRoot)\..\cmake\external\onnx;\..\cmake\external\onnx\onnx + true + true + true + $(OnnxRuntimeCsharpRoot)\..\cmake\external\onnx - - 7.2 + + default True true ..\..\OnnxRuntime.snk @@ -49,6 +51,9 @@ + + + @@ -75,10 +80,11 @@ - - - + + + + @@ -92,9 +98,27 @@ TextTemplatingFileGenerator TensorOperations.cs - + + + + + PreserveNewest + false + + + + PreserveNewest + false + + + + PreserveNewest + false + + + @@ -106,11 +130,11 @@ - + - + @@ -137,4 +161,4 @@ - \ No newline at end of file + diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/OnnxMl.cs b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/OnnxMl.cs index 72686b3775277..510097e2f4c29 100644 --- a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/OnnxMl.cs +++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/OnnxMl.cs @@ -71,7 +71,7 @@ static OnnxMlReflection() { "X2luZm8YDSADKAsyFC5vbm54LlZhbHVlSW5mb1Byb3RvEjcKF3F1YW50aXph", "dGlvbl9hbm5vdGF0aW9uGA4gAygLMhYub25ueC5UZW5zb3JBbm5vdGF0aW9u", "SgQIAxAESgQIBBAFSgQIBhAKUgppcl92ZXJzaW9uUhBwcm9kdWNlcl92ZXJz", - "aW9uUgxwcm9kdWNlcl90YWdSBmRvbWFpbiK4BQoLVGVuc29yUHJvdG8SDAoE", + "aW9uUgxwcm9kdWNlcl90YWdSBmRvbWFpbiKCBgoLVGVuc29yUHJvdG8SDAoE", "ZGltcxgBIAMoAxIRCglkYXRhX3R5cGUYAiABKAUSKgoHc2VnbWVudBgDIAEo", "CzIZLm9ubnguVGVuc29yUHJvdG8uU2VnbWVudBIWCgpmbG9hdF9kYXRhGAQg", "AygCQgIQARIWCgppbnQzMl9kYXRhGAUgAygFQgIQARITCgtzdHJpbmdfZGF0", @@ -81,46 +81,50 @@ static OnnxMlReflection() { "bxI1Cg1kYXRhX2xvY2F0aW9uGA4gASgOMh4ub25ueC5UZW5zb3JQcm90by5E", "YXRhTG9jYXRpb24SFwoLZG91YmxlX2RhdGEYCiADKAFCAhABEhcKC3VpbnQ2", "NF9kYXRhGAsgAygEQgIQARolCgdTZWdtZW50Eg0KBWJlZ2luGAEgASgDEgsK", - "A2VuZBgCIAEoAyLaAQoIRGF0YVR5cGUSDQoJVU5ERUZJTkVEEAASCQoFRkxP", + "A2VuZBgCIAEoAyKkAgoIRGF0YVR5cGUSDQoJVU5ERUZJTkVEEAASCQoFRkxP", "QVQQARIJCgVVSU5UOBACEggKBElOVDgQAxIKCgZVSU5UMTYQBBIJCgVJTlQx", "NhAFEgkKBUlOVDMyEAYSCQoFSU5UNjQQBxIKCgZTVFJJTkcQCBIICgRCT09M", "EAkSCwoHRkxPQVQxNhAKEgoKBkRPVUJMRRALEgoKBlVJTlQzMhAMEgoKBlVJ", "TlQ2NBANEg0KCUNPTVBMRVg2NBAOEg4KCkNPTVBMRVgxMjgQDxIMCghCRkxP", - "QVQxNhAQIikKDERhdGFMb2NhdGlvbhILCgdERUZBVUxUEAASDAoIRVhURVJO", - "QUwQASJoChFTcGFyc2VUZW5zb3JQcm90bxIhCgZ2YWx1ZXMYASABKAsyES5v", - "bm54LlRlbnNvclByb3RvEiIKB2luZGljZXMYAiABKAsyES5vbm54LlRlbnNv", - "clByb3RvEgwKBGRpbXMYAyADKAMilQEKEFRlbnNvclNoYXBlUHJvdG8SLQoD", - "ZGltGAEgAygLMiAub25ueC5UZW5zb3JTaGFwZVByb3RvLkRpbWVuc2lvbhpS", - "CglEaW1lbnNpb24SEwoJZGltX3ZhbHVlGAEgASgDSAASEwoJZGltX3BhcmFt", - "GAIgASgJSAASEgoKZGVub3RhdGlvbhgDIAEoCUIHCgV2YWx1ZSKlBQoJVHlw", - "ZVByb3RvEi0KC3RlbnNvcl90eXBlGAEgASgLMhYub25ueC5UeXBlUHJvdG8u", - "VGVuc29ySAASMQoNc2VxdWVuY2VfdHlwZRgEIAEoCzIYLm9ubnguVHlwZVBy", - "b3RvLlNlcXVlbmNlSAASJwoIbWFwX3R5cGUYBSABKAsyEy5vbm54LlR5cGVQ", - "cm90by5NYXBIABIxCg1vcHRpb25hbF90eXBlGAkgASgLMhgub25ueC5UeXBl", - "UHJvdG8uT3B0aW9uYWxIABI6ChJzcGFyc2VfdGVuc29yX3R5cGUYCCABKAsy", - "HC5vbm54LlR5cGVQcm90by5TcGFyc2VUZW5zb3JIABItCgtvcGFxdWVfdHlw", - "ZRgHIAEoCzIWLm9ubnguVHlwZVByb3RvLk9wYXF1ZUgAEhIKCmRlbm90YXRp", - "b24YBiABKAkaQgoGVGVuc29yEhEKCWVsZW1fdHlwZRgBIAEoBRIlCgVzaGFw", - "ZRgCIAEoCzIWLm9ubnguVGVuc29yU2hhcGVQcm90bxouCghTZXF1ZW5jZRIi", - "CgllbGVtX3R5cGUYASABKAsyDy5vbm54LlR5cGVQcm90bxo8CgNNYXASEAoI", - "a2V5X3R5cGUYASABKAUSIwoKdmFsdWVfdHlwZRgCIAEoCzIPLm9ubnguVHlw", - "ZVByb3RvGi4KCE9wdGlvbmFsEiIKCWVsZW1fdHlwZRgBIAEoCzIPLm9ubngu", - "VHlwZVByb3RvGkgKDFNwYXJzZVRlbnNvchIRCgllbGVtX3R5cGUYASABKAUS", - "JQoFc2hhcGUYAiABKAsyFi5vbm54LlRlbnNvclNoYXBlUHJvdG8aJgoGT3Bh", - "cXVlEg4KBmRvbWFpbhgBIAEoCRIMCgRuYW1lGAIgASgJQgcKBXZhbHVlIjUK", - "Ek9wZXJhdG9yU2V0SWRQcm90bxIOCgZkb21haW4YASABKAkSDwoHdmVyc2lv", - "bhgCIAEoAyLlAQoNRnVuY3Rpb25Qcm90bxIMCgRuYW1lGAEgASgJEg0KBWlu", - "cHV0GAQgAygJEg4KBm91dHB1dBgFIAMoCRIRCglhdHRyaWJ1dGUYBiADKAkS", - "HQoEbm9kZRgHIAMoCzIPLm9ubnguTm9kZVByb3RvEhIKCmRvY19zdHJpbmcY", - "CCABKAkSLgoMb3BzZXRfaW1wb3J0GAkgAygLMhgub25ueC5PcGVyYXRvclNl", - "dElkUHJvdG8SDgoGZG9tYWluGAogASgJSgQIAhADSgQIAxAEUg1zaW5jZV92", - "ZXJzaW9uUgZzdGF0dXMq5AEKB1ZlcnNpb24SEgoOX1NUQVJUX1ZFUlNJT04Q", - "ABIZChVJUl9WRVJTSU9OXzIwMTdfMTBfMTAQARIZChVJUl9WRVJTSU9OXzIw", - "MTdfMTBfMzAQAhIYChRJUl9WRVJTSU9OXzIwMTdfMTFfMxADEhgKFElSX1ZF", - "UlNJT05fMjAxOV8xXzIyEAQSGAoUSVJfVkVSU0lPTl8yMDE5XzNfMTgQBRIY", - "ChRJUl9WRVJTSU9OXzIwMTlfOV8xORAGEhcKE0lSX1ZFUlNJT05fMjAyMF81", - "XzgQBxIOCgpJUl9WRVJTSU9OEAgqLgoOT3BlcmF0b3JTdGF0dXMSEAoMRVhQ", - "RVJJTUVOVEFMEAASCgoGU1RBQkxFEAFCAkgDYgZwcm90bzM=")); + "QVQxNhAQEhAKDEZMT0FUOEU0TTNGThAREhIKDkZMT0FUOEU0TTNGTlVaEBIS", + "DgoKRkxPQVQ4RTVNMhATEhIKDkZMT0FUOEU1TTJGTlVaEBQiKQoMRGF0YUxv", + "Y2F0aW9uEgsKB0RFRkFVTFQQABIMCghFWFRFUk5BTBABImgKEVNwYXJzZVRl", + "bnNvclByb3RvEiEKBnZhbHVlcxgBIAEoCzIRLm9ubnguVGVuc29yUHJvdG8S", + "IgoHaW5kaWNlcxgCIAEoCzIRLm9ubnguVGVuc29yUHJvdG8SDAoEZGltcxgD", + "IAMoAyKVAQoQVGVuc29yU2hhcGVQcm90bxItCgNkaW0YASADKAsyIC5vbm54", + "LlRlbnNvclNoYXBlUHJvdG8uRGltZW5zaW9uGlIKCURpbWVuc2lvbhITCglk", + "aW1fdmFsdWUYASABKANIABITCglkaW1fcGFyYW0YAiABKAlIABISCgpkZW5v", + "dGF0aW9uGAMgASgJQgcKBXZhbHVlIqUFCglUeXBlUHJvdG8SLQoLdGVuc29y", + "X3R5cGUYASABKAsyFi5vbm54LlR5cGVQcm90by5UZW5zb3JIABIxCg1zZXF1", + "ZW5jZV90eXBlGAQgASgLMhgub25ueC5UeXBlUHJvdG8uU2VxdWVuY2VIABIn", + "CghtYXBfdHlwZRgFIAEoCzITLm9ubnguVHlwZVByb3RvLk1hcEgAEjEKDW9w", + "dGlvbmFsX3R5cGUYCSABKAsyGC5vbm54LlR5cGVQcm90by5PcHRpb25hbEgA", + "EjoKEnNwYXJzZV90ZW5zb3JfdHlwZRgIIAEoCzIcLm9ubnguVHlwZVByb3Rv", + "LlNwYXJzZVRlbnNvckgAEi0KC29wYXF1ZV90eXBlGAcgASgLMhYub25ueC5U", + "eXBlUHJvdG8uT3BhcXVlSAASEgoKZGVub3RhdGlvbhgGIAEoCRpCCgZUZW5z", + "b3ISEQoJZWxlbV90eXBlGAEgASgFEiUKBXNoYXBlGAIgASgLMhYub25ueC5U", + "ZW5zb3JTaGFwZVByb3RvGi4KCFNlcXVlbmNlEiIKCWVsZW1fdHlwZRgBIAEo", + "CzIPLm9ubnguVHlwZVByb3RvGjwKA01hcBIQCghrZXlfdHlwZRgBIAEoBRIj", + "Cgp2YWx1ZV90eXBlGAIgASgLMg8ub25ueC5UeXBlUHJvdG8aLgoIT3B0aW9u", + "YWwSIgoJZWxlbV90eXBlGAEgASgLMg8ub25ueC5UeXBlUHJvdG8aSAoMU3Bh", + "cnNlVGVuc29yEhEKCWVsZW1fdHlwZRgBIAEoBRIlCgVzaGFwZRgCIAEoCzIW", + "Lm9ubnguVGVuc29yU2hhcGVQcm90bxomCgZPcGFxdWUSDgoGZG9tYWluGAEg", + "ASgJEgwKBG5hbWUYAiABKAlCBwoFdmFsdWUiNQoST3BlcmF0b3JTZXRJZFBy", + "b3RvEg4KBmRvbWFpbhgBIAEoCRIPCgd2ZXJzaW9uGAIgASgDIpQCCg1GdW5j", + "dGlvblByb3RvEgwKBG5hbWUYASABKAkSDQoFaW5wdXQYBCADKAkSDgoGb3V0", + "cHV0GAUgAygJEhEKCWF0dHJpYnV0ZRgGIAMoCRItCg9hdHRyaWJ1dGVfcHJv", + "dG8YCyADKAsyFC5vbm54LkF0dHJpYnV0ZVByb3RvEh0KBG5vZGUYByADKAsy", + "Dy5vbm54Lk5vZGVQcm90bxISCgpkb2Nfc3RyaW5nGAggASgJEi4KDG9wc2V0", + "X2ltcG9ydBgJIAMoCzIYLm9ubnguT3BlcmF0b3JTZXRJZFByb3RvEg4KBmRv", + "bWFpbhgKIAEoCUoECAIQA0oECAMQBFINc2luY2VfdmVyc2lvblIGc3RhdHVz", + "Kv4BCgdWZXJzaW9uEhIKDl9TVEFSVF9WRVJTSU9OEAASGQoVSVJfVkVSU0lP", + "Tl8yMDE3XzEwXzEwEAESGQoVSVJfVkVSU0lPTl8yMDE3XzEwXzMwEAISGAoU", + "SVJfVkVSU0lPTl8yMDE3XzExXzMQAxIYChRJUl9WRVJTSU9OXzIwMTlfMV8y", + "MhAEEhgKFElSX1ZFUlNJT05fMjAxOV8zXzE4EAUSGAoUSVJfVkVSU0lPTl8y", + "MDE5XzlfMTkQBhIXChNJUl9WRVJTSU9OXzIwMjBfNV84EAcSGAoUSVJfVkVS", + "U0lPTl8yMDIxXzdfMzAQCBIOCgpJUl9WRVJTSU9OEAkqLgoOT3BlcmF0b3JT", + "dGF0dXMSEAoMRVhQRVJJTUVOVEFMEAASCgoGU1RBQkxFEAFCAkgDYgZwcm90", + "bzM=")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, new pbr::FileDescriptor[] { }, new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Onnx.Version), typeof(global::Onnx.OperatorStatus), }, null, new pbr::GeneratedClrTypeInfo[] { @@ -142,7 +146,7 @@ static OnnxMlReflection() { new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.TypeProto.Types.SparseTensor), global::Onnx.TypeProto.Types.SparseTensor.Parser, new[]{ "ElemType", "Shape" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.TypeProto.Types.Opaque), global::Onnx.TypeProto.Types.Opaque.Parser, new[]{ "Domain", "Name" }, null, null, null, null)}), new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.OperatorSetIdProto), global::Onnx.OperatorSetIdProto.Parser, new[]{ "Domain", "Version" }, null, null, null, null), - new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.FunctionProto), global::Onnx.FunctionProto.Parser, new[]{ "Name", "Input", "Output", "Attribute", "Node", "DocString", "OpsetImport", "Domain" }, null, null, null, null) + new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.FunctionProto), global::Onnx.FunctionProto.Parser, new[]{ "Name", "Input", "Output", "Attribute", "AttributeProto", "Node", "DocString", "OpsetImport", "Domain" }, null, null, null, null) })); } #endregion @@ -216,13 +220,19 @@ public enum Version { /// [pbr::OriginalName("IR_VERSION_2020_5_8")] IrVersion202058 = 7, /// - /// IR VERSION 8 published on <TBD> + /// IR VERSION 8 published on July 30, 2021 /// Introduce TypeProto.SparseTensor /// Introduce TypeProto.Optional /// Added a list of FunctionProtos local to the model /// Deprecated since_version and operator status from FunctionProto /// - [pbr::OriginalName("IR_VERSION")] IrVersion = 8, + [pbr::OriginalName("IR_VERSION_2021_7_30")] IrVersion2021730 = 8, + /// + /// IR VERSION 9 published on TBD + /// Added AttributeProto to FunctionProto so that default attribute values can be set. + /// Added FLOAT8E4M3FN, FLOAT8E4M3FNUZ, FLOAT8E5M2, FLOAT8E5M2FNUZ. + /// + [pbr::OriginalName("IR_VERSION")] IrVersion = 9, } /// @@ -3860,11 +3870,11 @@ public int DataType { = pb::FieldCodec.ForInt32(42); private readonly pbc::RepeatedField int32Data_ = new pbc::RepeatedField(); /// - /// For int32, uint8, int8, uint16, int16, bool, and float16 values - /// float16 values must be bit-wise converted to an uint16_t prior + /// For int32, uint8, int8, uint16, int16, bool, float8, and float16 values + /// float16 and float8 values must be bit-wise converted to an uint16_t prior /// to writing to the buffer. /// When this field is present, the data_type field MUST be - /// INT32, INT16, INT8, UINT16, UINT8, BOOL, FLOAT16 or BFLOAT16 + /// INT32, INT16, INT8, UINT16, UINT8, BOOL, FLOAT16, BFLOAT16, FLOAT8E4M3FN, FLOAT8E4M3FNUZ, FLOAT8E5M2, FLOAT8E5M2FNUZ /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] @@ -4486,6 +4496,27 @@ public enum DataType { /// This format has 1 sign bit, 8 exponent bits, and 7 mantissa bits. /// [pbr::OriginalName("BFLOAT16")] Bfloat16 = 16, + /// + /// Non-IEEE floating-point format based on papers + /// FP8 Formats for Deep Learning, https://arxiv.org/abs/2209.05433, + /// 8-bit Numerical Formats For Deep Neural Networks, https://arxiv.org/pdf/2206.02915.pdf. + /// Operators supported FP8 are Cast, CastLike, QuantizeLinear, DequantizeLinear. + /// The computation usually happens inside a block quantize / dequantize + /// fused by the runtime. + /// + [pbr::OriginalName("FLOAT8E4M3FN")] Float8E4M3Fn = 17, + /// + /// float 8, mostly used for coefficients, supports nan, not inf, no negative zero + /// + [pbr::OriginalName("FLOAT8E4M3FNUZ")] Float8E4M3Fnuz = 18, + /// + /// follows IEEE 754, supports nan, inf, mostly used for gradients + /// + [pbr::OriginalName("FLOAT8E5M2")] Float8E5M2 = 19, + /// + /// follows IEEE 754, supports nan, inf, mostly used for gradients, no negative zero + /// + [pbr::OriginalName("FLOAT8E5M2FNUZ")] Float8E5M2Fnuz = 20, } /// @@ -7743,6 +7774,7 @@ public FunctionProto(FunctionProto other) : this() { input_ = other.input_.Clone(); output_ = other.output_.Clone(); attribute_ = other.attribute_.Clone(); + attributeProto_ = other.attributeProto_.Clone(); node_ = other.node_.Clone(); docString_ = other.docString_; opsetImport_ = other.opsetImport_.Clone(); @@ -7804,7 +7836,8 @@ public string Name { = pb::FieldCodec.ForString(50); private readonly pbc::RepeatedField attribute_ = new pbc::RepeatedField(); /// - /// The attributes of the function. + /// The attribute parameters of the function. + /// It is for function parameters without default values. /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] @@ -7812,6 +7845,23 @@ public string Name { get { return attribute_; } } + /// Field number for the "attribute_proto" field. + public const int AttributeProtoFieldNumber = 11; + private static readonly pb::FieldCodec _repeated_attributeProto_codec + = pb::FieldCodec.ForMessage(90, global::Onnx.AttributeProto.Parser); + private readonly pbc::RepeatedField attributeProto_ = new pbc::RepeatedField(); + /// + /// The attribute protos of the function. + /// It is for function attributes with default values. + /// A function attribute shall be represented either as + /// a string attribute or an AttributeProto, not both. + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public pbc::RepeatedField AttributeProto { + get { return attributeProto_; } + } + /// Field number for the "node" field. public const int NodeFieldNumber = 7; private static readonly pb::FieldCodec _repeated_node_codec @@ -7887,6 +7937,7 @@ public bool Equals(FunctionProto other) { if(!input_.Equals(other.input_)) return false; if(!output_.Equals(other.output_)) return false; if(!attribute_.Equals(other.attribute_)) return false; + if(!attributeProto_.Equals(other.attributeProto_)) return false; if(!node_.Equals(other.node_)) return false; if (DocString != other.DocString) return false; if(!opsetImport_.Equals(other.opsetImport_)) return false; @@ -7902,6 +7953,7 @@ public override int GetHashCode() { hash ^= input_.GetHashCode(); hash ^= output_.GetHashCode(); hash ^= attribute_.GetHashCode(); + hash ^= attributeProto_.GetHashCode(); hash ^= node_.GetHashCode(); if (DocString.Length != 0) hash ^= DocString.GetHashCode(); hash ^= opsetImport_.GetHashCode(); @@ -7941,6 +7993,7 @@ public void WriteTo(pb::CodedOutputStream output) { output.WriteRawTag(82); output.WriteString(Domain); } + attributeProto_.WriteTo(output, _repeated_attributeProto_codec); if (_unknownFields != null) { _unknownFields.WriteTo(output); } @@ -7968,6 +8021,7 @@ public void WriteTo(pb::CodedOutputStream output) { output.WriteRawTag(82); output.WriteString(Domain); } + attributeProto_.WriteTo(ref output, _repeated_attributeProto_codec); if (_unknownFields != null) { _unknownFields.WriteTo(ref output); } @@ -7984,6 +8038,7 @@ public int CalculateSize() { size += input_.CalculateSize(_repeated_input_codec); size += output_.CalculateSize(_repeated_output_codec); size += attribute_.CalculateSize(_repeated_attribute_codec); + size += attributeProto_.CalculateSize(_repeated_attributeProto_codec); size += node_.CalculateSize(_repeated_node_codec); if (DocString.Length != 0) { size += 1 + pb::CodedOutputStream.ComputeStringSize(DocString); @@ -8010,6 +8065,7 @@ public void MergeFrom(FunctionProto other) { input_.Add(other.input_); output_.Add(other.output_); attribute_.Add(other.attribute_); + attributeProto_.Add(other.attributeProto_); node_.Add(other.node_); if (other.DocString.Length != 0) { DocString = other.DocString; @@ -8065,6 +8121,10 @@ public void MergeFrom(pb::CodedInputStream input) { Domain = input.ReadString(); break; } + case 90: { + attributeProto_.AddEntriesFrom(input, _repeated_attributeProto_codec); + break; + } } } #endif @@ -8112,6 +8172,10 @@ public void MergeFrom(pb::CodedInputStream input) { Domain = input.ReadString(); break; } + case 90: { + attributeProto_.AddEntriesFrom(ref input, _repeated_attributeProto_codec); + break; + } } } } diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/OrtEnvTests.cs b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/OrtEnvTests.cs index 63ddf51116794..229d683c162fd 100644 --- a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/OrtEnvTests.cs +++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/OrtEnvTests.cs @@ -80,7 +80,7 @@ public void TestUpdatingEnvWithCustomLogLevel() logLevel = OrtLoggingLevel.ORT_LOGGING_LEVEL_FATAL }; - ortEnvInstance = OrtEnv.CreateInstanceWithOptions(envOptions); + ortEnvInstance = OrtEnv.CreateInstanceWithOptions(ref envOptions); Assert.True(OrtEnv.IsCreated); Assert.Equal(OrtLoggingLevel.ORT_LOGGING_LEVEL_FATAL, ortEnvInstance.EnvLogLevel); @@ -92,7 +92,7 @@ public void TestUpdatingEnvWithCustomLogLevel() logId = "CSharpOnnxRuntimeTestLogid" }; - ortEnvInstance = OrtEnv.CreateInstanceWithOptions(envOptions); + ortEnvInstance = OrtEnv.CreateInstanceWithOptions(ref envOptions); Assert.Equal(OrtLoggingLevel.ORT_LOGGING_LEVEL_WARNING, ortEnvInstance.EnvLogLevel); // Change and see if this takes effect @@ -118,7 +118,7 @@ public void TestUpdatingEnvWithThreadingOptions() }; // Make sure we start anew - var env = OrtEnv.CreateInstanceWithOptions(envOptions); + var env = OrtEnv.CreateInstanceWithOptions(ref envOptions); Assert.True(OrtEnv.IsCreated); } } @@ -148,7 +148,6 @@ protected static void CustomLoggingFunction(IntPtr param, [Collection("Ort Inference Tests")] public class OrtEnvWithCustomLogger : CustomLoggingFunctionTestBase { - [Fact(DisplayName = "TesEnvWithCustomLogger")] public void TesEnvWithCustomLogger() { @@ -165,14 +164,15 @@ public void TesEnvWithCustomLogger() LoggingInvokes = 0; - var env = OrtEnv.CreateInstanceWithOptions(envOptions); + var env = OrtEnv.CreateInstanceWithOptions(ref envOptions); Assert.True(OrtEnv.IsCreated); var model = TestDataLoader.LoadModelFromEmbeddedResource("squeezenet.onnx"); // Trigger some logging // Empty stmt intentional using (var session = new InferenceSession(model)) - ; + { } + Assert.True(LoggingInvokes > 0); } } @@ -199,14 +199,15 @@ public void TestEnvWithCustomLoggerAndThredingOptions() LoggingInvokes = 0; - var env = OrtEnv.CreateInstanceWithOptions(envOptions); + var env = OrtEnv.CreateInstanceWithOptions(ref envOptions); Assert.True(OrtEnv.IsCreated); var model = TestDataLoader.LoadModelFromEmbeddedResource("squeezenet.onnx"); // Trigger some logging // Empty stmt intentional - using (var session = new InferenceSession(model)) - ; + using (var session = new InferenceSession(model)) + { } + Assert.True(LoggingInvokes > 0); } } diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/OrtFloat16Tests.cs b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/OrtFloat16Tests.cs new file mode 100644 index 0000000000000..5fe338f19ea46 --- /dev/null +++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/OrtFloat16Tests.cs @@ -0,0 +1,533 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using Xunit; + +namespace Microsoft.ML.OnnxRuntime.Tests +{ + [Collection("Ort Float16 tests")] + public class OrtFloat16Tests + { + const float oneThird = 1 / 3.0f; + const float oneSeventh = 1 / 7.0f; + const float oneTenth = 1 / 10.0f; + + [Fact(DisplayName = "ConvertFloatToFloat16")] + public void ConvertFloatToFloat16() + { + // Generate integer floats and insert between them + // fractions. This will test the rounding logic. + float start = -10; + + var floatValues = new float[21 * 4]; + for (int i = 0; i < floatValues.Length; i += 4) + { + floatValues[i] = start; + floatValues[i + 1] = start + oneThird; + floatValues[i + 2] = start + oneSeventh; + floatValues[i + 3] = start + oneTenth; + start += 1; + } + + var f16Converted = Array.ConvertAll(floatValues, f => (Float16)f); + var backConverted = Array.ConvertAll(f16Converted, f16 => (float)f16); + Assert.Equal(floatValues, backConverted, new FloatComparer()); + } + + [Fact(DisplayName = "TestZeros")] + public void TestZeros() + { + var positiveZero = new Float16(0); + Assert.False(Float16.IsNegative(positiveZero)); + Assert.True(Float16.IsNaNOrZero(positiveZero)); + + float singlePositiveZero = (float)positiveZero; + Assert.Equal(+0.0f, singlePositiveZero); +#if NET6_0_OR_GREATER + Assert.False(float.IsNegative(singlePositiveZero)); +#endif + + var negativeZero = Float16.Negate(positiveZero); + Assert.True(Float16.IsNegative(negativeZero)); + Assert.True(Float16.IsNaNOrZero(negativeZero)); + + float singleNegativeZero = (float)negativeZero; + Assert.Equal(-0.0f, singleNegativeZero); +#if NET6_0_OR_GREATER + Assert.True(float.IsNegative(singleNegativeZero)); +#endif + } + + [Fact(DisplayName = "TestComparisonOperators")] + public void TestComparisonOperators() + { + Float16 left = (Float16)(float)-33.33f; + Float16 leftSame = (Float16)(float)-33.33f; + Float16 right = (Float16)(float)66.66f; + Float16 rightSame = (Float16)(float)66.66f; + + Assert.False(Float16.IsNaNOrZero(left)); + Assert.False(Float16.IsNaNOrZero(right)); + + Assert.True(right > Float16.Epsilon); + + Assert.True(left == leftSame); + Assert.False(left == Float16.Negate(leftSame)); + + Assert.True(right == rightSame); + Assert.False(right == Float16.Negate(rightSame)); + + Assert.True(left < right); + Assert.True(left > Float16.Negate(right)); + Assert.True(Float16.Negate(left) < right); + + Assert.True(left <= right); + Assert.True(left >= Float16.Negate(right)); + Assert.False(left > right); + Assert.False(left >= right); + Assert.True(Float16.Negate(left) <= right); + Assert.False(left == right); + Assert.False(right == left); + Assert.True(left != right); + Assert.True(right != left); + } + + [Fact(DisplayName = "TestNAN")] + public void TestNAN() + { + Float16 fp16NANFromSingle = (Float16)float.NaN; + Assert.True(Float16.IsNaN(fp16NANFromSingle)); + Assert.Equal(Float16.NaN, fp16NANFromSingle); + Assert.True(Float16.IsNaNOrZero(fp16NANFromSingle)); + + float NanFromFloat16 = fp16NANFromSingle.ToFloat(); + Assert.True(float.IsNaN(NanFromFloat16)); + + // IEqualityComparable returns true, because it tests + // objects, not numbers. + Assert.Equal(fp16NANFromSingle, Float16.NaN); + + Assert.Equal(Float16.NaN, Float16.Negate(Float16.NaN)); + } + + [Fact(DisplayName = "TestNANComparision")] + public void TestNANComparisionOperators() + { + // NaN is not ordered with respect to anything + // including itself + + // IEqualityComparable returns true, because it tests + // objects, not numbers. + Assert.Equal(Float16.NaN, Float16.NaN); + Assert.False(Float16.NaN < Float16.NaN); + Assert.False(Float16.NaN > Float16.NaN); + Assert.False(Float16.NaN <= Float16.NaN); + Assert.False(Float16.NaN >= Float16.NaN); + Assert.False(Float16.NaN == Float16.NaN); + + // IEqualityComparable returns false, because it tests + // objects, not numbers. + Assert.NotEqual(Float16.NaN, Float16.MaxValue); + + Assert.False(Float16.NaN < Float16.MaxValue); + Assert.False(Float16.MaxValue < Float16.NaN); + Assert.False(Float16.NaN == Float16.MaxValue); + Assert.False(Float16.MaxValue == Float16.NaN); + Assert.False(Float16.NaN > Float16.MinValue); + Assert.False(Float16.MaxValue > Float16.NaN); + Assert.False(Float16.NaN == Float16.MinValue); + Assert.False(Float16.MaxValue == Float16.NaN); + Assert.True(Float16.MinValue < Float16.MaxValue); + } + + [Fact(DisplayName = "TestInfinity")] + public void TestInfinity() + { + Assert.False(Float16.IsInfinity(Float16.MinValue)); + Assert.False(Float16.IsInfinity(Float16.MaxValue)); + + Float16 posInfinityFromSingle = (Float16)float.PositiveInfinity; + Assert.True(Float16.IsPositiveInfinity(posInfinityFromSingle)); + Assert.Equal(Float16.PositiveInfinity, posInfinityFromSingle); + Assert.False(Float16.IsFinite(posInfinityFromSingle)); + Assert.True(Float16.IsInfinity(posInfinityFromSingle)); + Assert.True(Float16.IsPositiveInfinity(posInfinityFromSingle)); + Assert.False(Float16.IsNegativeInfinity(posInfinityFromSingle)); + + Assert.False(Float16.IsPositiveInfinity(Float16.MinValue)); + Assert.False(Float16.IsPositiveInfinity(Float16.MaxValue)); + + + Assert.Equal(float.PositiveInfinity < 0, Float16.IsNegative(posInfinityFromSingle)); + + Float16 negInfinityFromSingle = (Float16)float.NegativeInfinity; + Assert.True(Float16.IsNegativeInfinity(negInfinityFromSingle)); + Assert.Equal(Float16.NegativeInfinity, negInfinityFromSingle); + Assert.False(Float16.IsFinite(negInfinityFromSingle)); + Assert.True(Float16.IsInfinity(negInfinityFromSingle)); + Assert.True(Float16.IsNegativeInfinity(negInfinityFromSingle)); + Assert.False(Float16.IsPositiveInfinity(negInfinityFromSingle)); + + Assert.False(Float16.IsNegativeInfinity(Float16.MinValue)); + Assert.False(Float16.IsNegativeInfinity(Float16.MaxValue)); + + + Assert.Equal(float.NegativeInfinity < 0, Float16.IsNegative(negInfinityFromSingle)); + + // Convert infinity to float and test the fact + float infFromFloat16 = (float)Float16.PositiveInfinity; + Assert.True(float.IsInfinity(infFromFloat16)); + Assert.True(float.IsPositiveInfinity(infFromFloat16)); + } + + + [Fact(DisplayName = "TestNormalSubnormal")] + public void TestNormalSubnormal() + { + Float16 fp16FromSingleMaxValue = (Float16)float.MaxValue; + + // Float MaxValue is outside Float16 range. This is different + // from BFloat16 that retains sufficient range. + Assert.True(Float16.IsInfinity(fp16FromSingleMaxValue)); + Assert.False(Float16.IsNormal(fp16FromSingleMaxValue)); + + Assert.False(Float16.IsNormal(Float16.PositiveInfinity)); + Assert.True(Float16.IsNormal((Float16)45.6f)); + Assert.False(Float16.IsSubnormal((Float16)45.6f)); + + Assert.False(Float16.IsSubnormal(fp16FromSingleMaxValue)); + Assert.False(Float16.IsSubnormal(Float16.PositiveInfinity)); + + // 0b0_00000_0000000001 => 5.9604645E-08 + const ushort minSubnormalBits = 0x0001; + const float smallestF16Subnormal = 5.9604645E-08f; + Float16 smallestSubnormal = new Float16(minSubnormalBits); + Assert.True(Float16.IsSubnormal(smallestSubnormal)); + Assert.False(Float16.IsNormal(smallestSubnormal)); + + // 0b0_00000_1111111111 => 6.09755516E-05 + const float largestF16Subnormal = 6.09755516E-05f; + const ushort maxSubnormalBits = 0x03FF; + Float16 largestSubnormal = new Float16(maxSubnormalBits); + Assert.True(Float16.IsSubnormal(largestSubnormal)); + Assert.False(Float16.IsNormal(largestSubnormal)); + + // Convert subnormal to float and see if we match + float convertedFromSmallestSubnormal = (float)smallestSubnormal; + Assert.Equal(smallestF16Subnormal, convertedFromSmallestSubnormal, 6); + + float convertedFromLargestSubnormal = (float)largestSubnormal; + Assert.Equal(largestF16Subnormal, convertedFromLargestSubnormal, 6); + } + + [Fact(DisplayName = "TestEqual")] + public void TestEqual() + { + // Box it + object obj_1 = Float16.MaxValue; + object obj_2 = new Float16(Float16.MaxValue.value); + Assert.True(obj_1.Equals(obj_2)); + + + Assert.NotEqual(0, obj_1.GetHashCode()); + Assert.Equal(obj_1.GetHashCode(), obj_2.GetHashCode()); + Assert.True(Float16.NaN.Equals(Float16.NaN)); + + Float16 fp16Zero = (Float16)0.0f; + const ushort ushortZero = 0; + Float16 fp16FromUshortZero = (Float16)ushortZero; + + Assert.True(fp16Zero.Equals(fp16FromUshortZero)); + + // Should have the same hash code constant + Assert.Equal(fp16Zero.GetHashCode(), fp16FromUshortZero.GetHashCode()); + Assert.Equal(Float16.NaN.GetHashCode(), Float16.NaN.GetHashCode()); + } + + [Fact(DisplayName = "TestCompare")] + public void TestCompare() + { + object objMaxValue = new Float16(Float16.MaxValue.value); + Assert.Equal(0, Float16.MaxValue.CompareTo(objMaxValue)); + + Float16 one = (Float16)1.0f; + Assert.Equal(-1, Float16.MinValue.CompareTo(one)); + Assert.Equal(1, Float16.MaxValue.CompareTo(one)); + + // one is bigger than NaN + Assert.Equal(-1, Float16.NaN.CompareTo(one)); + // Two NaNs are equal according to CompareTo() + Assert.Equal(0, Float16.NaN.CompareTo((Float16)float.NaN)); + Assert.Equal(1, one.CompareTo(Float16.NaN)); + + // Compare to null + Assert.Equal(1, one.CompareTo(null)); + + // Make sure it throws + var obj = new object(); + Assert.Throws(() => one.CompareTo(obj)); + } + } + + [Collection("Ort BFloat16 tests")] + public class OrtBFloat16Tests + { + const float oneThird = 1 / 3.0f; + const float oneSeventh = 1 / 7.0f; + const float oneTenth = 1 / 10.0f; + + [Fact(DisplayName = "ConvertFloatToBFloat16")] + public void ConvertFloatToBFloat16() + { + // Generate integer floats and insert between them + // fractions. This will test the rounding logic. + float start = -10; + + var floatValues = new float[21 * 4]; + for (int i = 0; i < floatValues.Length; i += 4) + { + floatValues[i] = start; + floatValues[i + 1] = start + oneThird; + floatValues[i + 2] = start + oneSeventh; + floatValues[i + 3] = start + oneTenth; + start += 1; + } + + var f16Converted = Array.ConvertAll(floatValues, f => (BFloat16)f); + var backConverted = Array.ConvertAll(f16Converted, f16 => (float)f16); + Assert.Equal(floatValues, backConverted, new FloatComparer()); + } + + [Fact(DisplayName = "TestZeros")] + public void TestZeros() + { + var positiveZero = new BFloat16(0); + Assert.False(BFloat16.IsNegative(positiveZero)); + Assert.True(BFloat16.IsNaNOrZero(positiveZero)); + float singlePositiveZero = (float)positiveZero; + Assert.Equal(+0.0f, singlePositiveZero); +#if NET6_0_OR_GREATER + Assert.False(float.IsNegative(singlePositiveZero)); +#endif + + var negativeZero = BFloat16.Negate(positiveZero); + Assert.True(BFloat16.IsNegative(negativeZero)); + Assert.True(BFloat16.IsNaNOrZero(negativeZero)); + + float singleNegativeZero = (float)negativeZero; + Assert.Equal(-0.0f, singleNegativeZero); +#if NET6_0_OR_GREATER + Assert.True(float.IsNegative(singleNegativeZero)); +#endif + } + + [Fact(DisplayName = "TestComparisonOperators")] + public void TestComparisionOperators() + { + BFloat16 left = (BFloat16)(float)-33.33f; + BFloat16 leftSame = (BFloat16)(float)-33.33f; + BFloat16 right = (BFloat16)(float)66.66f; + BFloat16 rightSame = (BFloat16)(float)66.66f; + + Assert.False(BFloat16.IsNaNOrZero(left)); + Assert.False(BFloat16.IsNaNOrZero(right)); + + Assert.True(right > BFloat16.Epsilon); + + Assert.True(left == leftSame); + Assert.False(left == BFloat16.Negate(leftSame)); + + Assert.True(right == rightSame); + Assert.False(right == BFloat16.Negate(rightSame)); + + Assert.True(left < right); + Assert.True(left > BFloat16.Negate(right)); + Assert.True(BFloat16.Negate(left) < right); + + Assert.True(left <= right); + Assert.True(left >= BFloat16.Negate(right)); + Assert.False(left > right); + Assert.False(left >= right); + Assert.True(BFloat16.Negate(left) <= right); + Assert.False(left == right); + Assert.False(right == left); + Assert.True(left != right); + Assert.True(right != left); + } + + [Fact(DisplayName = "TestNAN")] + public void TestNAN() + { + BFloat16 fp16NANFromSingle = (BFloat16)float.NaN; + Assert.True(BFloat16.IsNaN(fp16NANFromSingle)); + Assert.Equal(BFloat16.NaN, fp16NANFromSingle); + Assert.True(BFloat16.IsNaNOrZero(fp16NANFromSingle)); + + float NanFromBFloat16 = fp16NANFromSingle.ToFloat(); + Assert.True(float.IsNaN(NanFromBFloat16)); + + // IEqualityComparable returns true, because it tests + // objects, not numbers. + Assert.Equal(fp16NANFromSingle, BFloat16.NaN); + Assert.Equal(BFloat16.NaN, BFloat16.Negate(BFloat16.NaN)); + + Assert.False(BFloat16.IsNaN(BFloat16.MaxValue)); + } + + [Fact(DisplayName = "TestNANComparision")] + public void TestNANComparisionOperators() + { + // NaN is not ordered with respect to anything + // including itself + + // IEqualityComparable returns true, because it tests + // objects, not numbers. + Assert.Equal(BFloat16.NaN, BFloat16.NaN); + Assert.False(BFloat16.NaN < BFloat16.NaN); + Assert.False(BFloat16.NaN > BFloat16.NaN); + Assert.False(BFloat16.NaN <= BFloat16.NaN); + Assert.False(BFloat16.NaN >= BFloat16.NaN); + Assert.False(BFloat16.NaN == BFloat16.NaN); + + // IEqualityComparable returns false, because it tests + // objects, not numbers. + Assert.NotEqual(BFloat16.NaN, BFloat16.MaxValue); + + Assert.False(BFloat16.NaN < BFloat16.MaxValue); + Assert.False(BFloat16.MaxValue < BFloat16.NaN); + Assert.False(BFloat16.NaN == BFloat16.MaxValue); + Assert.False(BFloat16.MaxValue == BFloat16.NaN); + Assert.False(BFloat16.NaN > BFloat16.MinValue); + Assert.False(BFloat16.MaxValue > BFloat16.NaN); + Assert.False(BFloat16.NaN == BFloat16.MinValue); + Assert.False(BFloat16.MaxValue == BFloat16.NaN); + Assert.True(BFloat16.MinValue < BFloat16.MaxValue); + } + + [Fact(DisplayName = "TestInfinity")] + public void TestInfinity() + { + Assert.False(BFloat16.IsInfinity(BFloat16.MinValue)); + Assert.False(BFloat16.IsInfinity(BFloat16.MaxValue)); + + BFloat16 posInfinityFromSingle = (BFloat16)float.PositiveInfinity; + Assert.True(BFloat16.IsPositiveInfinity(posInfinityFromSingle)); + Assert.Equal(BFloat16.PositiveInfinity, posInfinityFromSingle); + Assert.False(BFloat16.IsFinite(posInfinityFromSingle)); + Assert.True(BFloat16.IsInfinity(posInfinityFromSingle)); + Assert.True(BFloat16.IsPositiveInfinity(posInfinityFromSingle)); + Assert.False(BFloat16.IsNegativeInfinity(posInfinityFromSingle)); + + Assert.False(BFloat16.IsPositiveInfinity(BFloat16.MinValue)); + Assert.False(BFloat16.IsPositiveInfinity(BFloat16.MaxValue)); + + + Assert.Equal(float.PositiveInfinity < 0, BFloat16.IsNegative(posInfinityFromSingle)); + + BFloat16 negInfinityFromSingle = (BFloat16)float.NegativeInfinity; + Assert.True(BFloat16.IsNegativeInfinity(negInfinityFromSingle)); + Assert.Equal(BFloat16.NegativeInfinity, negInfinityFromSingle); + Assert.False(BFloat16.IsFinite(negInfinityFromSingle)); + Assert.True(BFloat16.IsInfinity(negInfinityFromSingle)); + Assert.True(BFloat16.IsNegativeInfinity(negInfinityFromSingle)); + Assert.False(BFloat16.IsPositiveInfinity(negInfinityFromSingle)); + + Assert.False(BFloat16.IsNegativeInfinity(BFloat16.MinValue)); + Assert.False(BFloat16.IsNegativeInfinity(BFloat16.MaxValue)); + + + Assert.True(BFloat16.IsNegative(negInfinityFromSingle)); + + // Convert infinity to float and test the fact + float infFromBFloat16 = (float)BFloat16.PositiveInfinity; + Assert.True(float.IsInfinity(infFromBFloat16)); + Assert.True(float.IsPositiveInfinity(infFromBFloat16)); + } + + [Fact(DisplayName = "TestNormalSubnormal")] + public void TestNormalSubnormal() + { + BFloat16 fp16FromSingleMaxValue = (BFloat16)float.MaxValue; + + Assert.True(BFloat16.IsInfinity(fp16FromSingleMaxValue)); + Assert.False(BFloat16.IsNormal(fp16FromSingleMaxValue)); + + + Assert.False(BFloat16.IsNormal(BFloat16.PositiveInfinity)); + Assert.True(BFloat16.IsNormal((BFloat16)45.6f)); + Assert.False(BFloat16.IsSubnormal((BFloat16)45.6f)); + + Assert.False(BFloat16.IsSubnormal(fp16FromSingleMaxValue)); + Assert.False(BFloat16.IsSubnormal(BFloat16.PositiveInfinity)); + + // 0b0_0000_0000_000_0001 + const ushort minSubnormalBits = 0x0001; + BFloat16 smallestSubnormal = new BFloat16(minSubnormalBits); + Assert.True(BFloat16.IsSubnormal(smallestSubnormal)); + Assert.False(BFloat16.IsNormal(smallestSubnormal)); +#if NET6_0_OR_GREATER + float singleSmallestSubnormal = (float)smallestSubnormal; + Assert.True(float.IsSubnormal(singleSmallestSubnormal)); +#endif + + const ushort maxSubnormalBits = 0x007F; // 0b0_0000_0000_111_1111; + BFloat16 largestSubnormal = new BFloat16(maxSubnormalBits); + Assert.True(BFloat16.IsSubnormal(largestSubnormal)); + Assert.False(BFloat16.IsNormal(largestSubnormal)); +#if NET6_0_OR_GREATER + float singleLargestSubnornal = (float)largestSubnormal; + Assert.True(float.IsSubnormal(singleLargestSubnornal)); +#endif + } + + [Fact(DisplayName = "TestEqual")] + public void TestEqual() + { + // Box it + object obj_1 = BFloat16.MaxValue; + object obj_2 = new BFloat16(BFloat16.MaxValue.value); + Assert.True(obj_1.Equals(obj_2)); + + + Assert.NotEqual(0, obj_1.GetHashCode()); + Assert.Equal(obj_1.GetHashCode(), obj_2.GetHashCode()); + Assert.True(BFloat16.NaN.Equals(BFloat16.NaN)); + + BFloat16 fp16Zero = (BFloat16)0.0f; + const ushort ushortZero = 0; + BFloat16 fp16FromUshortZero = (BFloat16)ushortZero; + + Assert.True(fp16Zero.Equals(fp16FromUshortZero)); + + // Should have the same hash code constant + Assert.Equal(fp16Zero.GetHashCode(), fp16FromUshortZero.GetHashCode()); + Assert.Equal(BFloat16.NaN.GetHashCode(), BFloat16.NaN.GetHashCode()); + } + + [Fact(DisplayName = "TestCompare")] + public void TestCompare() + { + object objMaxValue = new BFloat16(BFloat16.MaxValue.value); + Assert.Equal(0, BFloat16.MaxValue.CompareTo(objMaxValue)); + + BFloat16 one = (BFloat16)1.0f; + Assert.Equal(-1, BFloat16.MinValue.CompareTo(one)); + Assert.Equal(1, BFloat16.MaxValue.CompareTo(one)); + + // one is bigger than NaN + Assert.Equal(-1, BFloat16.NaN.CompareTo(one)); + // Two NaNs are equal according to CompareTo() + Assert.Equal(0, BFloat16.NaN.CompareTo((BFloat16)float.NaN)); + Assert.Equal(1, one.CompareTo(BFloat16.NaN)); + + // Compare to null + Assert.Equal(1, one.CompareTo(null)); + + // Make sure it throws + var obj = new object(); + Assert.Throws(() => one.CompareTo(obj)); + } + } +} \ No newline at end of file diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/OrtIoBindingAllocationTest.cs b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/OrtIoBindingAllocationTest.cs index c6312b65f751b..b07bcdeeb3b11 100644 --- a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/OrtIoBindingAllocationTest.cs +++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/OrtIoBindingAllocationTest.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. using Microsoft.ML.OnnxRuntime.Tensors; -using Microsoft.Win32.SafeHandles; using System; using System.Linq; using System.Runtime.InteropServices; @@ -11,36 +10,138 @@ namespace Microsoft.ML.OnnxRuntime.Tests { - public class OrtIoBindingAllocationTest + [Collection("OrtBinding Tests")] + public class OrtIoBindingAllocationTests : IDisposable { + private const string _inputName = "data_0"; + private const string _outputName = "softmaxout_1"; + private static readonly OrtAllocator _allocator = OrtAllocator.DefaultInstance; + + private readonly RunOptions _runOptions; + private readonly InferenceSession _session; + private readonly float[] _inputData; + private readonly float[] _outputData; + + private readonly long[] _inputShape; + private readonly long _inputSizeInBytes; + private readonly long[] _outputShape; + private readonly long _outputSizeInBytes; + + private readonly OrtSafeMemoryHandle _inputNativeAllocation; + private readonly OrtSafeMemoryHandle _outputNativeAllocation; + + private readonly DisposableListTest _dispList = new DisposableListTest(); + + private bool _disposed = false; + + public OrtIoBindingAllocationTests() + { + var tuple = OpenSessionSqueezeNet(); + _session = tuple.Item1; + _dispList.Add(_session); + _runOptions = new RunOptions(); + _dispList.Add(_runOptions); + + _inputData = tuple.Item2; + _outputData = tuple.Item4; + + var inputMeta = _session.InputMetadata; + var outputMeta = _session.OutputMetadata; + + _inputShape = Array.ConvertAll(inputMeta[_inputName].Dimensions, Convert.ToInt64); + _outputShape = Array.ConvertAll(outputMeta[_outputName].Dimensions, Convert.ToInt64); + + var inputShapeSize = ShapeUtils.GetSizeForShape(_inputShape); + Assert.Equal(inputShapeSize, _inputData.Length); + + var outputShapeSize = ShapeUtils.GetSizeForShape(_outputShape); + Assert.Equal(outputShapeSize, _outputData.Length); + + _inputSizeInBytes = inputShapeSize * sizeof(float); + IntPtr allocPtr = Marshal.AllocHGlobal((int)_inputSizeInBytes); + _inputNativeAllocation = new OrtSafeMemoryHandle(allocPtr); + _dispList.Add(_inputNativeAllocation); + + PopulateNativeBuffer(allocPtr, _inputData); + + _outputSizeInBytes = outputShapeSize * sizeof(float); + allocPtr = Marshal.AllocHGlobal((int)_outputSizeInBytes); + _outputNativeAllocation = new OrtSafeMemoryHandle(allocPtr); + } + + // Probably redundant as we have no native resources + ~OrtIoBindingAllocationTests() + { + Dispose(false); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (_disposed) + { + return; + } + + if (disposing) + { + _dispList.Dispose(); + } + _disposed = true; + } + /// /// This works only for allocations accessible from host memory /// /// /// - private static void PopulateNativeBufferFloat(OrtMemoryAllocation buffer, float[] elements) + private static void PopulateNativeBuffer(OrtMemoryAllocation buffer, T[] elements) + { + PopulateNativeBuffer(buffer.Pointer, elements); + } + + private static void PopulateNativeBuffer(IntPtr buffer, T[] elements) { - if (buffer.Size < elements.Length * sizeof(float)) + Span bufferSpan; + unsafe { - Assert.True(false); + bufferSpan = new Span(buffer.ToPointer(), elements.Length); } + elements.CopyTo(bufferSpan); + } - PopulateNativeBuffer(buffer.Pointer, elements); + /// + /// Checks that the contents of the native buffer matches the expected output. + /// + private void CheckOutput(IntPtr resultBuffer) + { + Span bufferSpan; + unsafe + { + bufferSpan = new Span(resultBuffer.ToPointer(), (int)_outputSizeInBytes); + } + var outputSpan = MemoryMarshal.Cast(bufferSpan); + Assert.Equal(_outputData, outputSpan.ToArray(), new FloatComparer()); } - private static void PopulateNativeBuffer(IntPtr buffer, float[] elements) + private void ClearOutput() { + Span bufferSpan; unsafe { - float* p = (float*)buffer; - for (int i = 0; i < elements.Length; ++i) - { - *p++ = elements[i]; - } + bufferSpan = new Span(_outputNativeAllocation.Handle.ToPointer(), (int)_outputSizeInBytes); } + bufferSpan.Clear(); } + /// - /// Use to free globally allocated memory + /// Use to free globally allocated memory. Could not find + /// a framework class. /// class OrtSafeMemoryHandle : SafeHandle { @@ -48,6 +149,8 @@ public OrtSafeMemoryHandle(IntPtr allocPtr) : base(allocPtr, true) { } public override bool IsInvalid => handle == IntPtr.Zero; + public IntPtr Handle => handle; + protected override bool ReleaseHandle() { Marshal.FreeHGlobal(handle); @@ -56,125 +159,231 @@ protected override bool ReleaseHandle() } } - [Fact(DisplayName = "TestIOBindingWithOrtAllocation")] - public void TestIOBindingWithOrtAllocation() + [Fact(DisplayName = "TestIOBindingWithOrtValues")] + public void TestIOBindingWithOrtValues() { - var inputName = "data_0"; - var outputName = "softmaxout_1"; - var allocator = OrtAllocator.DefaultInstance; - // From the model - using (var dispList = new DisposableListTest()) + ClearOutput(); + + using (var ioBinding = _session.CreateIoBinding()) { - var tuple = OpenSessionSqueezeNet(); - var session = tuple.Item1; - var inputData = tuple.Item2; - var inputTensor = tuple.Item3; - var outputData = tuple.Item4; - dispList.Add(session); - var runOptions = new RunOptions(); - dispList.Add(runOptions); + // Input OrtValue on top if input buffer + using (var tensor = OrtValue.CreateTensorValueWithData(OrtMemoryInfo.DefaultInstance, + TensorElementType.Float, + _inputShape, _inputNativeAllocation.Handle, _inputSizeInBytes)) + { + ioBinding.BindInput(_inputName, tensor); + } - var inputMeta = session.InputMetadata; - var outputMeta = session.OutputMetadata; - var outputTensor = new DenseTensor(outputData, outputMeta[outputName].Dimensions); + // Output OrtValue on top if output buffer + using (var tensor = OrtValue.CreateTensorValueWithData(OrtMemoryInfo.DefaultInstance, + TensorElementType.Float, + _outputShape, _outputNativeAllocation.Handle, _outputSizeInBytes)) + { + ioBinding.BindOutput(_outputName, tensor); + } - var ioBinding = session.CreateIoBinding(); - dispList.Add(ioBinding); + ioBinding.SynchronizeBoundInputs(); - var ortAllocationInput = allocator.Allocate((uint)inputData.Length * sizeof(float)); - dispList.Add(ortAllocationInput); - var inputShape = Array.ConvertAll(inputMeta[inputName].Dimensions, d => d); - var shapeSize = ArrayUtilities.GetSizeForShape(inputShape); - Assert.Equal(shapeSize, inputData.Length); - PopulateNativeBufferFloat(ortAllocationInput, inputData); + using (var results = _session.RunWithBoundResults(_runOptions, ioBinding)) + { + ioBinding.SynchronizeBoundOutputs(); + Assert.Single(results); + var res = results.First(); + Assert.True(res.IsTensor); - // Create an external allocation for testing OrtExternalAllocation - var cpuMemInfo = OrtMemoryInfo.DefaultInstance; - var sizeInBytes = shapeSize * sizeof(float); - IntPtr allocPtr = Marshal.AllocHGlobal((int)sizeInBytes); - dispList.Add(new OrtSafeMemoryHandle(allocPtr)); - PopulateNativeBuffer(allocPtr, inputData); + var typeAndShape = res.GetTensorTypeAndShape(); + Assert.Equal(_outputData.LongLength, typeAndShape.ElementCount); - var ortAllocationOutput = allocator.Allocate((uint)outputData.Length * sizeof(float)); - dispList.Add(ortAllocationOutput); + var dataSpan = res.GetTensorDataAsSpan(); + Assert.Equal(_outputData, dataSpan.ToArray(), new FloatComparer()); - var outputShape = Array.ConvertAll(outputMeta[outputName].Dimensions, i => i); + // The result is good, but we want to make sure that the result actually is + // in the output memory, not some other place + CheckOutput(_outputNativeAllocation.Handle); + } + + var outputNames = ioBinding.GetOutputNames(); + Assert.Single(outputNames); + Assert.Equal(_outputName, outputNames[0]); + } + } - // Test 1. Bind the output to OrtAllocated buffer - using (FixedBufferOnnxValue fixedInputBuffer = FixedBufferOnnxValue.CreateFromTensor(inputTensor)) + [Fact(DisplayName = "TestIOBindingWithDeviceBoundOutput")] + public void TestIOBindingWithDeviceBoundOutput() + { + ClearOutput(); + + using (var ioBinding = _session.CreateIoBinding()) + { + // Input OrtValue on top if input buffer + using (var tensor = OrtValue.CreateTensorValueWithData(OrtMemoryInfo.DefaultInstance, + TensorElementType.Float, + _inputShape, _inputNativeAllocation.Handle, _inputSizeInBytes)) { - ioBinding.BindInput(inputName, fixedInputBuffer); - ioBinding.BindOutput(outputName, Tensors.TensorElementType.Float, outputShape, ortAllocationOutput); - ioBinding.SynchronizeBoundInputs(); - using (var outputs = session.RunWithBindingAndNames(runOptions, ioBinding)) - { - ioBinding.SynchronizeBoundOutputs(); - Assert.Equal(1, outputs.Count); - var output = outputs.ElementAt(0); - Assert.Equal(outputName, output.Name); - var tensor = output.AsTensor(); - Assert.True(tensor.IsFixedSize); - Assert.Equal(outputData, tensor.ToArray(), new FloatComparer()); - } + ioBinding.BindInput(_inputName, tensor); } - // Test 2. Bind the input to memory allocation and output to a fixedBuffer + // The output will go into the Ort allocated OrtValue + ioBinding.BindOutputToDevice(_outputName, OrtMemoryInfo.DefaultInstance); + ioBinding.SynchronizeBoundInputs(); + + using (var results = _session.RunWithBoundResults(_runOptions, ioBinding)) { - ioBinding.BindInput(inputName, Tensors.TensorElementType.Float, inputShape, ortAllocationInput); - ioBinding.BindOutput(outputName, Tensors.TensorElementType.Float, outputShape, ortAllocationOutput); - ioBinding.SynchronizeBoundInputs(); - using (var outputs = session.RunWithBindingAndNames(runOptions, ioBinding)) - { - ioBinding.SynchronizeBoundOutputs(); - Assert.Equal(1, outputs.Count); - var output = outputs.ElementAt(0); - Assert.Equal(outputName, output.Name); - var tensor = output.AsTensor(); - Assert.True(tensor.IsFixedSize); - Assert.Equal(outputData, tensor.ToArray(), new FloatComparer()); - } + ioBinding.SynchronizeBoundOutputs(); + Assert.Single(results); + var res = results.First(); + Assert.True(res.IsTensor); + + var typeAndShape = res.GetTensorTypeAndShape(); + Assert.Equal(_outputData.LongLength, typeAndShape.ElementCount); + + var dataSpan = res.GetTensorDataAsSpan(); + Assert.Equal(_outputData, dataSpan.ToArray(), new FloatComparer()); } - // 3. Test external allocation + } + } + + [Fact(DisplayName = "TestIOBindingToOrtAllocatedBuffer")] + public void TestIOBindingToOrtAllocatedBuffer() + { + var ortAllocationInput = _allocator.Allocate((uint)_inputSizeInBytes); + _dispList.Add(ortAllocationInput); + PopulateNativeBuffer(ortAllocationInput, _inputData); + + var ortAllocationOutput = _allocator.Allocate((uint)_outputSizeInBytes); + _dispList.Add(ortAllocationOutput); + + using (var ioBinding = _session.CreateIoBinding()) + { + // Still supporting OrtAllocations overload + ioBinding.BindInput(_inputName, Tensors.TensorElementType.Float, _inputShape, ortAllocationInput); + ioBinding.BindOutput(_outputName, Tensors.TensorElementType.Float, _outputShape, ortAllocationOutput); + ioBinding.SynchronizeBoundInputs(); + using (var outputs = _session.RunWithBoundResults(_runOptions, ioBinding)) { - var externalInputAllocation = new OrtExternalAllocation(cpuMemInfo, inputShape, - Tensors.TensorElementType.Float, allocPtr, sizeInBytes); + ioBinding.SynchronizeBoundOutputs(); + Assert.Single(outputs); + var res = outputs.First(); + Assert.True(res.IsTensor); - ioBinding.BindInput(inputName, externalInputAllocation); - ioBinding.BindOutput(outputName, Tensors.TensorElementType.Float, outputShape, ortAllocationOutput); - ioBinding.SynchronizeBoundInputs(); - using (var outputs = session.RunWithBindingAndNames(runOptions, ioBinding)) - { - ioBinding.SynchronizeBoundOutputs(); - Assert.Equal(1, outputs.Count); - var output = outputs.ElementAt(0); - Assert.Equal(outputName, output.Name); - var tensor = output.AsTensor(); - Assert.True(tensor.IsFixedSize); - Assert.Equal(outputData, tensor.ToArray(), new FloatComparer()); - } + var typeAndShape = res.GetTensorTypeAndShape(); + Assert.Equal(_outputData.LongLength, typeAndShape.ElementCount); + + var dataSpan = res.GetTensorDataAsSpan(); + Assert.Equal(_outputData, dataSpan.ToArray(), new FloatComparer()); + CheckOutput(ortAllocationOutput.Pointer); } - // 4. Some negative tests for external allocation + } + } + } + + [Collection("OrtBinding Tests")] + public class OrtBidingCircularTest + { + [Fact(DisplayName = "TestIOBinding Demonstrate Circular")] + public void TestIOBindingDemonstrateCircular() + { + // This model has input and output of the same shape, so we can easily feed + // output to input using binding, or not using one. The example makes use of + // the binding to demonstrate the circular feeding. + // With the OrtValue API exposed, one create OrtValues over arbitrary buffers and feed them to the model using + // OrtValues based Run APIs. Thus, the Binding is not necessary any longer + // + // However, here is the demonstration by popular request. + var model = TestDataLoader.LoadModelFromEmbeddedResource("mul_1.onnx"); + + const string inputName = "X"; + const string outputName = "Y"; + + long[] inputOutputShape = { 3, 2 }; + float[] input = { 1.0F, 2.0F, 3.0F, 4.0F, 5.0F, 6.0F }; + var inputOutputShapeSize = ShapeUtils.GetSizeForShape(inputOutputShape); + Assert.Equal(inputOutputShapeSize, input.LongLength); + + var memInput = new Memory(input); + IntPtr inputPtr; + + // Output data on the first iteration + float[] firstIterExpectedOutput = { 1.0F, 4.0F, 9.0F, 16.0F, 25.0F, 36.0F }; + Assert.Equal(inputOutputShapeSize, firstIterExpectedOutput.LongLength); + + using (var cleanUp = new DisposableListTest()) + { + var runOptions = new RunOptions(); + cleanUp.Add(runOptions); + + var session = new InferenceSession(model); + cleanUp.Add(session); + + var ioBinding = session.CreateIoBinding(); + cleanUp.Add(ioBinding); + + + + var pinInput = memInput.Pin(); + cleanUp.Add(pinInput); + + // This can be a ptr to arbitrary buffer, not necessarily a pinned one + unsafe { - // Small buffer size - Action smallBuffer = delegate () - { - new OrtExternalAllocation(cpuMemInfo, inputShape, - Tensors.TensorElementType.Float, allocPtr, sizeInBytes - 10); - }; + inputPtr = (IntPtr)pinInput.Pointer; + } - Assert.Throws(smallBuffer); + // Bind the input + using (var ortInput = OrtValue.CreateTensorValueWithData(OrtMemoryInfo.DefaultInstance, + TensorElementType.Float, inputOutputShape, inputPtr, input.Length * sizeof(float))) + { + ioBinding.BindInput(inputName, ortInput); + } - Action stringType = delegate () - { - new OrtExternalAllocation(cpuMemInfo, inputShape, - Tensors.TensorElementType.String, allocPtr, sizeInBytes); - }; + // We could have bound the output as well, but we simply bind it to a device in this case. + // Just check the result the first time around. + ioBinding.BindOutputToDevice(outputName, OrtMemoryInfo.DefaultInstance); + + ioBinding.SynchronizeBoundInputs(); + + // We dispose the output after we rebind it to the input because it will be copied during binding. + using (var results = session.RunWithBoundResults(runOptions, ioBinding)) + { + ioBinding.SynchronizeBoundOutputs(); + Assert.Single(results); // One output + + var res = results.First(); + Assert.True(res.IsTensor); + + var typeShape = res.GetTensorTypeAndShape(); + Assert.Equal(TensorElementType.Float, typeShape.ElementDataType); + Assert.Equal(inputOutputShape, typeShape.Shape); + Assert.Equal(inputOutputShapeSize, typeShape.ElementCount); - Assert.Throws(stringType); + // First time around the output should match the expected + Assert.Equal(firstIterExpectedOutput, res.GetTensorDataAsSpan().ToArray()); + // Now we rebind the output to the input + // It is the same name, so the OrtValue would be replaced. + ioBinding.BindInput(inputName, res); } + // Let's do it 2 more times. + const int iterations = 2; + for (int i = 0; i < iterations; ++i) + { + using (var results = session.RunWithBoundResults(runOptions, ioBinding)) + { + ioBinding.SynchronizeBoundOutputs(); + Assert.Single(results); // One output + var res = results.First(); + Assert.True(res.IsTensor); + var typeShape = res.GetTensorTypeAndShape(); + Assert.Equal(TensorElementType.Float, typeShape.ElementDataType); + Assert.Equal(inputOutputShapeSize, typeShape.ElementCount); + Assert.Equal(inputOutputShape, typeShape.Shape); + + ioBinding.BindInput(inputName, res); + } + } } + } } } \ No newline at end of file diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/OrtValueTests.cs b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/OrtValueTests.cs new file mode 100644 index 0000000000000..e028e88ee30dc --- /dev/null +++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/OrtValueTests.cs @@ -0,0 +1,345 @@ +using Microsoft.ML.OnnxRuntime.Tensors; +using System; +using System.Runtime.InteropServices; +using System.Text; +using Xunit; + +namespace Microsoft.ML.OnnxRuntime.Tests +{ + [Collection("OrtValueTests")] + public class OrtValueTests + { + public OrtValueTests() + { + } + + [Fact(DisplayName = "PopulateAndReadStringTensor")] + public void PopulateAndReadStringTensor() + { + OrtEnv.Instance(); + + string[] strsRom = { "HelloR", "OrtR", "WorldR" }; + string[] strs = { "Hello", "Ort", "World" }; + long[] shape = { 1, 1, 3 }; + var elementsNum = ShapeUtils.GetSizeForShape(shape); + Assert.Equal(elementsNum, strs.Length); + Assert.Equal(elementsNum, strsRom.Length); + + using (var strTensor = OrtValue.CreateTensorWithEmptyStrings(OrtAllocator.DefaultInstance, shape)) + { + Assert.True(strTensor.IsTensor); + Assert.False(strTensor.IsSparseTensor); + Assert.Equal(OnnxValueType.ONNX_TYPE_TENSOR, strTensor.OnnxType); + var typeShape = strTensor.GetTensorTypeAndShape(); + { + Assert.True(typeShape.IsString); + Assert.Equal(shape.Length, typeShape.DimensionsCount); + var fetchedShape = typeShape.Shape; + Assert.Equal(shape.Length, fetchedShape.Length); + Assert.Equal(shape, fetchedShape); + Assert.Equal(elementsNum, typeShape.ElementCount); + } + + using (var memInfo = strTensor.GetTensorMemoryInfo()) + { + Assert.Equal("Cpu", memInfo.Name); + Assert.Equal(OrtMemType.Default, memInfo.GetMemoryType()); + Assert.Equal(OrtAllocatorType.DeviceAllocator, memInfo.GetAllocatorType()); + } + + // Verify that everything is empty now. + for (int i = 0; i < elementsNum; ++i) + { + var str = strTensor.GetStringElement(i); + Assert.Empty(str); + + var rom = strTensor.GetStringElementAsMemory(i); + Assert.Equal(0, rom.Length); + + var bytes = strTensor.GetStringElementAsSpan(i); + Assert.Equal(0, bytes.Length); + } + + // Let's populate the tensor with strings. + for (int i = 0; i < elementsNum; ++i) + { + // First populate via ROM + strTensor.StringTensorSetElementAt(strsRom[i].AsMemory(), i); + Assert.Equal(strsRom[i], strTensor.GetStringElement(i)); + Assert.Equal(strsRom[i], strTensor.GetStringElementAsMemory(i).ToString()); + Assert.Equal(Encoding.UTF8.GetBytes(strsRom[i]), strTensor.GetStringElementAsSpan(i).ToArray()); + + // Fill via Span + strTensor.StringTensorSetElementAt(strs[i].AsSpan(), i); + Assert.Equal(strs[i], strTensor.GetStringElement(i)); + Assert.Equal(strs[i], strTensor.GetStringElementAsMemory(i).ToString()); + Assert.Equal(Encoding.UTF8.GetBytes(strs[i]), strTensor.GetStringElementAsSpan(i).ToArray()); + } + } + } + + [Fact(DisplayName = "PopulateAndReadStringTensorViaTensor")] + public void PopulateAndReadStringTensorViaTensor() + { + OrtEnv.Instance(); + + string[] strs = { "Hello", "Ort", "World" }; + int[] shape = { 1, 1, 3 }; + + var tensor = new DenseTensor(strs, shape); + + using (var strTensor = OrtValue.CreateFromStringTensor(tensor)) + { + Assert.True(strTensor.IsTensor); + Assert.False(strTensor.IsSparseTensor); + Assert.Equal(OnnxValueType.ONNX_TYPE_TENSOR, strTensor.OnnxType); + var typeShape = strTensor.GetTensorTypeAndShape(); + { + Assert.True(typeShape.IsString); + Assert.Equal(shape.Length, typeShape.DimensionsCount); + var fetchedShape = typeShape.Shape; + Assert.Equal(shape.Length, fetchedShape.Length); + Assert.Equal(strs.Length, typeShape.ElementCount); + } + + using (var memInfo = strTensor.GetTensorMemoryInfo()) + { + Assert.Equal("Cpu", memInfo.Name); + Assert.Equal(OrtMemType.Default, memInfo.GetMemoryType()); + Assert.Equal(OrtAllocatorType.DeviceAllocator, memInfo.GetAllocatorType()); + } + + for (int i = 0; i < strs.Length; ++i) + { + // Fill via Span + Assert.Equal(strs[i], strTensor.GetStringElement(i)); + Assert.Equal(strs[i], strTensor.GetStringElementAsMemory(i).ToString()); + Assert.Equal(Encoding.UTF8.GetBytes(strs[i]), strTensor.GetStringElementAsSpan(i).ToArray()); + } + } + } + static void VerifyTensorCreateWithData(OrtValue tensor, TensorElementType dataType, long[] shape, + ReadOnlySpan originalData) where T : unmanaged + { + // Verify invocation + var dataTypeInfo = TensorBase.GetTypeInfo(typeof(T)); + Assert.NotNull(dataTypeInfo); + Assert.Equal(dataType, dataTypeInfo.ElementType); + + var elementsNum = ShapeUtils.GetSizeForShape(shape); + + Assert.True(tensor.IsTensor); + Assert.False(tensor.IsSparseTensor); + Assert.Equal(OnnxValueType.ONNX_TYPE_TENSOR, tensor.OnnxType); + + var typeInfo = tensor.GetTypeInfo(); + { + Assert.Equal(OnnxValueType.ONNX_TYPE_TENSOR, typeInfo.OnnxType); + var typeShape = typeInfo.TensorTypeAndShapeInfo; + Assert.Equal(shape.Length, typeShape.DimensionsCount); + + var fetchedShape = typeShape.Shape; + Assert.Equal(shape.Length, fetchedShape.Length); + Assert.Equal(shape, fetchedShape); + Assert.Equal(elementsNum, typeShape.ElementCount); + } + + using (var memInfo = tensor.GetTensorMemoryInfo()) + { + Assert.Equal("Cpu", memInfo.Name); + Assert.Equal(OrtMemType.CpuOutput, memInfo.GetMemoryType()); + Assert.Equal(OrtAllocatorType.DeviceAllocator, memInfo.GetAllocatorType()); + } + + // Verify contained data + Assert.Equal(originalData.ToArray(), tensor.GetTensorDataAsSpan().ToArray()); + } + + [Fact(DisplayName = "CreateTensorOverManagedBuffer")] + public void CreateTensorOverManagedBuffer() + { + int[] data = { 1, 2, 3 }; + var mem = new Memory(data); + long[] shape = { 1, 1, 3 }; + var elementsNum = ShapeUtils.GetSizeForShape(shape); + Assert.Equal(elementsNum, data.Length); + + + var typeInfo = TensorBase.GetElementTypeInfo(TensorElementType.Int32); + Assert.NotNull(typeInfo); + + // The tensor will be created on top of the managed memory. No copy is made. + // The memory should stay pinned until the OrtValue instance is disposed. This means + // stayed pinned until the end of Run() method when you are actually running inference. + using (var tensor = OrtValue.CreateTensorValueFromMemory(data, shape)) + { + VerifyTensorCreateWithData(tensor, TensorElementType.Int32, shape, data); + } + } + + // One can do create an OrtValue over a device memory and used as input. + // Just make sure that OrtMemoryInfo is created for GPU. + [Fact(DisplayName = "CreateTensorOverUnManagedBuffer")] + public void CreateTensorOverUnmangedBuffer() + { + const int Elements = 3; + // One can use stackalloc as well + var bufferLen = Elements * sizeof(int); + var dataPtr = Marshal.AllocHGlobal(bufferLen); + try + { + // Use span to populate chunk of native memory + Span data; + unsafe + { + data = new Span(dataPtr.ToPointer(), Elements); + } + data[0] = 1; + data[1] = 2; + data[2] = 3; + + long[] shape = { 1, 1, 3 }; + var elementsNum = ShapeUtils.GetSizeForShape(shape); + Assert.Equal(elementsNum, Elements); + + using (var tensor = OrtValue.CreateTensorValueWithData(OrtMemoryInfo.DefaultInstance, TensorElementType.Int32, + shape, dataPtr, bufferLen)) + { + VerifyTensorCreateWithData(tensor, TensorElementType.Int32, shape, data); + } + } + finally + { + Marshal.FreeHGlobal(dataPtr); + } + } + + private static void PopulateAndCheck(T[] data) where T : unmanaged + { + var typeInfo = TensorBase.GetTypeInfo(typeof(T)); + Assert.NotNull(typeInfo); + + long[] shape = { data.LongLength }; + + using (var ortValue = OrtValue.CreateAllocatedTensorValue(OrtAllocator.DefaultInstance, + typeInfo.ElementType, shape)) + { + var dst = ortValue.GetTensorMutableDataAsSpan(); + Assert.Equal(data.Length, dst.Length); + + var src = new Span(data); + src.CopyTo(dst); + Assert.Equal(data, ortValue.GetTensorDataAsSpan().ToArray()); + } + } + + // Create Tensor with allocated memory so we can test copying of the data + [Fact(DisplayName = "CreateAllocatedTensor")] + public void CreateAllocatedTensor() + { + float[] float_data = { 1, 2, 3, 4, 5, 6, 7, 8 }; + int[] int_data = { 1, 2, 3, 4, 5, 6, 7, 8 }; + ushort[] ushort_data = { 1, 2, 3, 4, 5, 6, 7, 8 }; + double[] dbl_data = { 1, 2, 3, 4, 5, 6, 7, 8 }; + var fp16_data = Array.ConvertAll(ushort_data, sh => new Float16(sh)); + + PopulateAndCheck(float_data); + PopulateAndCheck(int_data); + PopulateAndCheck(ushort_data); + PopulateAndCheck(dbl_data); + PopulateAndCheck(fp16_data); + } + + private static readonly long[] ml_data_1 = { 1, 2 }; + private static readonly long[] ml_data_2 = { 3, 4 }; + + // Use this utility method to create two tensors for Map and Sequence tests + private static void CreateTwoTensors(out OrtValue val1, out OrtValue val2) + { + const int ml_data_dim = 2; + // For map tensors they must be single dimensional + long[] shape = { ml_data_dim }; + + val1 = OrtValue.CreateTensorValueFromMemory(ml_data_1, shape); + val2 = OrtValue.CreateTensorValueFromMemory(ml_data_2, shape); + } + + [Fact(DisplayName = "CreateMapFromValues")] + public void CreateMapFromValues() + { + CreateTwoTensors(out OrtValue keys, out OrtValue values); + using var map = OrtValue.CreateMap(ref keys, ref values); + Assert.Equal(OnnxValueType.ONNX_TYPE_MAP, map.OnnxType); + var typeInfo = map.GetTypeInfo(); + var mapInfo = typeInfo.MapTypeInfo; + Assert.Equal(TensorElementType.Int64, mapInfo.KeyType); + Assert.Equal(OnnxValueType.ONNX_TYPE_TENSOR, mapInfo.ValueType.OnnxType); + + // Must return always 2 for map since we have two ort values + Assert.Equal(2, map.GetValueCount()); + + map.ProcessMap((keys, values) => { + Assert.Equal(OnnxValueType.ONNX_TYPE_TENSOR, keys.OnnxType); + Assert.Equal(OnnxValueType.ONNX_TYPE_TENSOR, values.OnnxType); + Assert.Equal(ml_data_1, keys.GetTensorDataAsSpan().ToArray()); + Assert.Equal(ml_data_2, values.GetTensorDataAsSpan().ToArray()); + + }, OrtAllocator.DefaultInstance); + } + + [Fact(DisplayName = "CreateMapFromArraysUnmanaged")] + public void CreateMapFromArraysUnmanaged() + { + long[] keys = { 1, 2, 3 }; + float[] vals = { 1, 2, 3 }; + using var map = OrtValue.CreateMap(keys, vals); + } + + [Fact(DisplayName = "CreateMapWithStringKeys")] + public void CreateMapWithStringKeys() + { + string[] keys = { "one", "two", "three" }; + float[] vals = { 1, 2, 3 }; + using var map = OrtValue.CreateMapWithStringKeys(keys, vals); + } + + [Fact(DisplayName = "CreateMapWithStringValues")] + public void CreateMapWithStringValues() + { + long[] keys = { 1, 2, 3 }; + string[] values = { "one", "two", "three" }; + using var map = OrtValue.CreateMapWithStringValues(keys, values); + } + + [Fact(DisplayName = "CreateSequence")] + public void CreateSequence() + { + CreateTwoTensors(out OrtValue val1, out OrtValue val2); + using var seqVals = new DisposableListTest { val1, val2 }; + using var seq = OrtValue.CreateSequence(seqVals); + + Assert.Equal(OnnxValueType.ONNX_TYPE_SEQUENCE, seq.OnnxType); + var typeInfo = seq.GetTypeInfo(); + var seqInfo = typeInfo.SequenceTypeInfo; + Assert.Equal(OnnxValueType.ONNX_TYPE_TENSOR, seqInfo.ElementType.OnnxType); + + // Will return 2 because we put 2 values in the sequence + Assert.Equal(2, seq.GetValueCount()); + + // Visit each element in the sequence + seq.ProcessSequence((ortValue, index) => + { + // We know both elements are tensors of long + Assert.Equal(OnnxValueType.ONNX_TYPE_TENSOR, ortValue.OnnxType); + if (index == 0) + { + Assert.Equal(ml_data_1, ortValue.GetTensorDataAsSpan().ToArray()); + } + else + { + Assert.Equal(ml_data_2, ortValue.GetTensorDataAsSpan().ToArray()); + } + }, OrtAllocator.DefaultInstance); + } + } +} \ No newline at end of file diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/Tensors/ArrayTensorExtensionsTests.cs b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/Tensors/ArrayTensorExtensionsTests.cs index 5e1e82f80902c..1dcf2b4c6f087 100644 --- a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/Tensors/ArrayTensorExtensionsTests.cs +++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/Tensors/ArrayTensorExtensionsTests.cs @@ -101,5 +101,48 @@ public void ConstructFrom5D() Assert.Equal(expectedDims, tensor.Dimensions.ToArray()); CheckValues(array.Cast(), tensor); } + + [Fact] + public void TestLongStrides() + { + long[] emptyStrides = ShapeUtils.GetStrides(Array.Empty()); + Assert.Empty(emptyStrides); + + long[] negativeDims = { 2, -3, 4, 5 }; + Assert.Throws(() => ShapeUtils.GetStrides(negativeDims)); + + ReadOnlySpan goodDims = stackalloc long[] { 2, 3, 4, 5 }; + long[] expectedStrides = { 60, 20, 5, 1 }; + Assert.Equal(expectedStrides, ShapeUtils.GetStrides(goodDims)); + } + + [Fact] + public void TestLongGetIndex() + { + ReadOnlySpan dims = stackalloc long[] { 2, 3, 4, 5 }; + long size = ShapeUtils.GetSizeForShape(dims); + Assert.Equal(120, size); + + ReadOnlySpan strides = ShapeUtils.GetStrides(dims); + + static void IncDims(ReadOnlySpan dims, Span indices) + { + for (int i = dims.Length - 1; i >= 0; i--) + { + indices[i]++; + if (indices[i] < dims[i]) + break; + indices[i] = 0; + } + } + + Span indices = stackalloc long[] { 0, 0, 0, 0 }; + for (long i = 0; i < size; i++) + { + long index = ShapeUtils.GetIndex(strides, indices); + Assert.Equal(i, index); + IncDims(dims, indices); + } + } } } diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/Tensors/NativeMemory.cs b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/Tensors/NativeMemory.cs index 019c3d58cd663..d014dc0766111 100644 --- a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/Tensors/NativeMemory.cs +++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/Tensors/NativeMemory.cs @@ -38,10 +38,14 @@ public unsafe NativeMemory(void* memory, int length) this.length = length; } + // A finalizer to allow debugging in test code is allowable. + // https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2015 +#pragma warning disable CA2015 ~NativeMemory() { Dispose(false); } +#pragma warning restore CA2015 public static NativeMemory Allocate(int length) { diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/Tensors/TensorTests.cs b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/Tensors/TensorTests.cs index 7816babf482fd..c3a6b1059ad86 100644 --- a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/Tensors/TensorTests.cs +++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/Tensors/TensorTests.cs @@ -11,11 +11,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Collections; using System.Collections.Generic; using System.Linq; using Xunit; -using System; namespace Microsoft.ML.OnnxRuntime.Tensors.Tests { @@ -159,7 +159,12 @@ public void ConstructFromDimensions(TensorConstructor tensorConstructor) Assert.Equal(24, tensor.Length); Assert.Equal(tensorConstructor.IsReversedStride, tensor.IsReversedStride); - Assert.Throws("dimensions", () => tensorConstructor.CreateFromDimensions(dimensions: null)); + // The null is converted to a 'null' ReadOnlySpan which is a valid instance with length zero. + // https://learn.microsoft.com/en-us/dotnet/api/system.readonlyspan-1.-ctor?view=netstandard-2.1#system-readonlyspan-1-ctor(-0()) + // Such a span is valid as dimensions as it represents a scalar. + // If we need to differentiate between the two we'd need to change the Tensor ctor to accept a + // nullable span in order to tell the user that's invalid. + // Assert.Throws("dimensions", () => tensorConstructor.CreateFromDimensions(dimensions: null)); Assert.Throws("dimensions", () => tensorConstructor.CreateFromDimensions(dimensions: new[] { 1, -1 })); // ensure dimensions are immutable diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/TestDataLoader.cs b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/TestDataLoader.cs index 42a780b3287ef..9e5e2b6203790 100644 --- a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/TestDataLoader.cs +++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/TestDataLoader.cs @@ -1,15 +1,82 @@ -using System; +using Microsoft.ML.OnnxRuntime.Tensors; +using System; +using System.Buffers; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; -using System.Net.NetworkInformation; -using Google.Protobuf; -using Microsoft.ML.OnnxRuntime.Tensors; +using System.Runtime.InteropServices; +using System.Text; using Xunit; namespace Microsoft.ML.OnnxRuntime.Tests { + // Copy of the class that is internal in the main package + public class DisposableListTest : List, IDisposableReadOnlyCollection + where T : IDisposable + { + public DisposableListTest() + { } + + public DisposableListTest(IEnumerable enumerable) : base(enumerable) + { } + + public DisposableListTest(int count) + : base(count) + { } + + #region IDisposable Support + private bool disposedValue = false; // To detect redundant calls + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + // Dispose in the reverse order. + // Objects should typically be destroyed/disposed + // in the reverse order of its creation + // especially if the objects created later refer to the + // objects created earlier. For homogeneous collections of objects + // it would not matter. + for (int i = this.Count - 1; i >= 0; --i) + { + this[i]?.Dispose(); + } + this.Clear(); + } + + disposedValue = true; + } + } + + // This code added to correctly implement the disposable pattern. + public void Dispose() + { + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + Dispose(true); + GC.SuppressFinalize(this); + } + #endregion + } + + internal struct DisposableTestPair : IDisposable + where TValue : IDisposable + { + public string Key; + public TValue Value; + public DisposableTestPair(string key, TValue value) + { + Key = key; + Value = value; + } + public void Dispose() + { + Value?.Dispose(); + } + } + internal static class TestDataLoader { internal static byte[] LoadModelFromEmbeddedResource(string path) @@ -30,7 +97,6 @@ internal static byte[] LoadModelFromEmbeddedResource(string path) return model; } - internal static float[] LoadTensorFromEmbeddedResource(string path) { var tensorData = new List(); @@ -39,7 +105,7 @@ internal static float[] LoadTensorFromEmbeddedResource(string path) var resourceName = assembly.GetManifestResourceNames().Single(p => p.EndsWith("." + path)); using (StreamReader inputFile = new StreamReader(assembly.GetManifestResourceStream(resourceName))) { - inputFile.ReadLine(); //skip the input name + inputFile.ReadLine(); // skip the input name string[] dataStr = inputFile.ReadLine().Split(new char[] { ',', '[', ']' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < dataStr.Length; i++) { @@ -55,14 +121,14 @@ static NamedOnnxValue LoadTensorPb(Onnx.TensorProto tensor, string nodeName, Nod if (nodeMeta.OnnxValueType != OnnxValueType.ONNX_TYPE_TENSOR) { throw new InvalidDataException($"Metadata for: '{nodeName}' has a type: '{nodeMeta.OnnxValueType}'" + - $" but loading as tensor: '{tensor.Name}'"); + $" but loading as tensor: '{tensor.Name}'"); } var protoDt = (Tensors.TensorElementType)tensor.DataType; var metaElementType = nodeMeta.ElementDataType; if (!((protoDt == metaElementType) || - (protoDt == TensorElementType.UInt16 && - (metaElementType == TensorElementType.BFloat16 || metaElementType == TensorElementType.Float16)))) + (protoDt == TensorElementType.UInt16 && + (metaElementType == TensorElementType.BFloat16 || metaElementType == TensorElementType.Float16)))) throw new InvalidDataException($"For node: '{nodeName}' metadata expects: '{metaElementType}' but loaded loaded tensor type: '{protoDt}'"); // Tensors within Sequences may have no dimensions as the standard allows @@ -70,7 +136,7 @@ static NamedOnnxValue LoadTensorPb(Onnx.TensorProto tensor, string nodeName, Nod if (nodeMeta.Dimensions.Length > 0 && nodeMeta.Dimensions.Length != tensor.Dims.Count) { throw new InvalidDataException($"node: '{nodeName}' nodeMeta.Dim.Length: {nodeMeta.Dimensions.Length} " + - $"is expected to be equal to tensor.Dims.Count {tensor.Dims.Count}"); + $"is expected to be equal to tensor.Dims.Count {tensor.Dims.Count}"); } var intDims = new int[tensor.Dims.Count]; @@ -83,7 +149,7 @@ static NamedOnnxValue LoadTensorPb(Onnx.TensorProto tensor, string nodeName, Nod { if ((nodeMeta.Dimensions[i] != -1) && (nodeMeta.Dimensions[i] != tensor.Dims[i])) throw new InvalidDataException($"Node: '{nodeName}' dimension at idx {i} is {nodeMeta.Dimensions}[{i}] " + - $"is expected to either be -1 or {tensor.Dims[i]}"); + $"is expected to either be -1 or {tensor.Dims[i]}"); } // element type for Float16 and BFloat16 in the loaded tensor would always be uint16, so @@ -91,39 +157,40 @@ static NamedOnnxValue LoadTensorPb(Onnx.TensorProto tensor, string nodeName, Nod if (protoDt == TensorElementType.String) return CreateNamedOnnxValueFromStringTensor(tensor.StringData, nodeName, intDims); - return CreateNamedOnnxValueFromTensorRawData(nodeName, tensor.RawData.ToArray(), metaElementType, intDims); + return CreateNamedOnnxValueFromTensorRawData(nodeName, tensor.RawData.Span, metaElementType, intDims); } - internal static NamedOnnxValue CreateNamedOnnxValueFromTensorRawData(string nodeName, byte[] rawData, TensorElementType elementType, int[] intDims) + internal static NamedOnnxValue CreateNamedOnnxValueFromTensorRawData(string nodeName, ReadOnlySpan rawData, + TensorElementType elementType, int[] intDims) { switch (elementType) { case TensorElementType.Float: - return CreateNamedOnnxValueFromRawData(nodeName, rawData, sizeof(float), intDims); + return CreateNamedOnnxValueFromRawData(nodeName, rawData, intDims); case TensorElementType.Double: - return CreateNamedOnnxValueFromRawData(nodeName, rawData, sizeof(double), intDims); + return CreateNamedOnnxValueFromRawData(nodeName, rawData, intDims); case TensorElementType.Int32: - return CreateNamedOnnxValueFromRawData(nodeName, rawData, sizeof(int), intDims); + return CreateNamedOnnxValueFromRawData(nodeName, rawData, intDims); case TensorElementType.UInt32: - return CreateNamedOnnxValueFromRawData(nodeName, rawData, sizeof(uint), intDims); + return CreateNamedOnnxValueFromRawData(nodeName, rawData, intDims); case TensorElementType.Int16: - return CreateNamedOnnxValueFromRawData(nodeName, rawData, sizeof(short), intDims); + return CreateNamedOnnxValueFromRawData(nodeName, rawData, intDims); case TensorElementType.UInt16: - return CreateNamedOnnxValueFromRawData(nodeName, rawData, sizeof(ushort), intDims); + return CreateNamedOnnxValueFromRawData(nodeName, rawData, intDims); case TensorElementType.Int64: - return CreateNamedOnnxValueFromRawData(nodeName, rawData, sizeof(long), intDims); + return CreateNamedOnnxValueFromRawData(nodeName, rawData, intDims); case TensorElementType.UInt64: - return CreateNamedOnnxValueFromRawData(nodeName, rawData, sizeof(ulong), intDims); + return CreateNamedOnnxValueFromRawData(nodeName, rawData, intDims); case TensorElementType.UInt8: - return CreateNamedOnnxValueFromRawData(nodeName, rawData, sizeof(byte), intDims); + return CreateNamedOnnxValueFromRawData(nodeName, rawData, intDims); case TensorElementType.Int8: - return CreateNamedOnnxValueFromRawData(nodeName, rawData, sizeof(sbyte), intDims); + return CreateNamedOnnxValueFromRawData(nodeName, rawData, intDims); case TensorElementType.Bool: - return CreateNamedOnnxValueFromRawData(nodeName, rawData, sizeof(bool), intDims); + return CreateNamedOnnxValueFromRawData(nodeName, rawData, intDims); case TensorElementType.Float16: - return CreateNamedOnnxValueFromRawData(nodeName, rawData, sizeof(ushort), intDims); + return CreateNamedOnnxValueFromRawData(nodeName, rawData, intDims); case TensorElementType.BFloat16: - return CreateNamedOnnxValueFromRawData(nodeName, rawData, sizeof(ushort), intDims); + return CreateNamedOnnxValueFromRawData(nodeName, rawData, intDims); case TensorElementType.String: throw new ArgumentException("For string tensors of type use: CreateNamedOnnxValueFromStringTensor."); default: @@ -148,8 +215,8 @@ internal static NamedOnnxValue LoadTensorFromEmbeddedResourcePb(string path, str internal static NamedOnnxValue LoadOnnxValueFromFilePb(string fullFilename, string nodeName, NodeMetadata nodeMeta) { // No sparse tensor support yet - //Set buffer size to 4MB - int readBufferSize = 4194304; + // Set buffer size to 4MB + const int readBufferSize = 4194304; using (var file = new FileStream(fullFilename, FileMode.Open, FileAccess.Read, FileShare.Read, readBufferSize)) { switch (nodeMeta.OnnxValueType) @@ -166,8 +233,8 @@ internal static NamedOnnxValue LoadOnnxValueFromFilePb(string fullFilename, stri } case OnnxValueType.ONNX_TYPE_MAP: { - var map = Onnx.MapProto.Parser.ParseFrom(file); - return CreateNamedOnnxValueFromMap(map, nodeName, nodeMeta); + throw new NotImplementedException( + "Map test data format requires clarification: https://github.com/onnx/onnx/issues/5072"); } case OnnxValueType.ONNX_TYPE_OPTIONAL: @@ -181,15 +248,51 @@ internal static NamedOnnxValue LoadOnnxValueFromFilePb(string fullFilename, stri } } + internal static DisposableTestPair LoadOrtValueFromFilePb(string fullFilename, string nodeName, NodeMetadata nodeMeta) + { + // No sparse tensor support yet + // Set buffer size to 4MB + const int readBufferSize = 4194304; + using (var file = new FileStream(fullFilename, FileMode.Open, FileAccess.Read, FileShare.Read, readBufferSize)) + { + switch (nodeMeta.OnnxValueType) + { + case OnnxValueType.ONNX_TYPE_TENSOR: + { + var tensor = Onnx.TensorProto.Parser.ParseFrom(file); + return new DisposableTestPair(nodeName, LoadOrValueTensorPb(tensor, nodeName, nodeMeta)); + } + case OnnxValueType.ONNX_TYPE_SEQUENCE: + { + var sequence = Onnx.SequenceProto.Parser.ParseFrom(file); + return new DisposableTestPair(nodeName, CreateOrtValueFromSequence(sequence, nodeName, nodeMeta)); + } + case OnnxValueType.ONNX_TYPE_MAP: + { + throw new NotImplementedException( + "Map test data format requires clarification: https://github.com/onnx/onnx/issues/5072"); + } + + case OnnxValueType.ONNX_TYPE_OPTIONAL: + { + var opt = Onnx.OptionalProto.Parser.ParseFrom(file); + return new DisposableTestPair(nodeName, CreateOrtValueFromOptional(opt, nodeName, nodeMeta)); + } + default: + throw new NotImplementedException($"Unable to load value type: {nodeMeta.OnnxValueType} not implemented"); + } + } + } + private static void SequenceCheckMatchOnnxType(string nodeName, SequenceMetadata meta, - OnnxValueType onnxType) + OnnxValueType onnxType) { if (meta.ElementMeta.OnnxValueType == onnxType) return; throw new InvalidDataException($"Sequence node: '{nodeName}' " + - $"has element type: '{onnxType}'" + - $" expected: '{meta.ElementMeta.OnnxValueType}'"); + $"has element type: '{onnxType}'" + + $" expected: '{meta.ElementMeta.OnnxValueType}'"); } private static string MakeSequenceElementName(string nodeName, string seqName, int seqNum) @@ -256,145 +359,170 @@ internal static NamedOnnxValue CreateNamedOnnxValueFromSequence(Onnx.SequencePro } default: throw new NotImplementedException($"Sequence test data loading does not support element type: " + - $"'{seqElemType}'"); + $"'{seqElemType}'"); } - + } + internal static NamedOnnxValue CreateNamedOnnxValueFromMap(Onnx.MapProto map, string nodeName, NodeMetadata nodeMetadata) + { + // See GH issue https://github.com/onnx/onnx/issues/5072 + throw new NotImplementedException($"Loading map node: '{nodeName}' not implemented yet"); } - internal static NamedOnnxValue CastAndCreateFromMapKeys(string name, TensorElementType elementType, IList keys) + internal static NamedOnnxValue CreateNamedOnnxValueFromOptional(Onnx.OptionalProto optional, string nodeName, NodeMetadata nodeMetadata) { - switch (elementType) + var meta = nodeMetadata.AsOptionalMetadata().ElementMeta; + switch ((Onnx.OptionalProto.Types.DataType)optional.ElemType) { - case TensorElementType.Float: - return CastAndCreateTensor(name, keys); - case TensorElementType.Double: - return CastAndCreateTensor(name, keys); - case TensorElementType.Int32: - return CastAndCreateTensor(name, keys); - case TensorElementType.UInt32: - return CastAndCreateTensor(name, keys); - case TensorElementType.Int16: - return CastAndCreateTensor(name, keys); - case TensorElementType.UInt16: - return CastAndCreateTensor(name, keys); - case TensorElementType.Int64: - return CastAndCreateTensor(name, keys); - case TensorElementType.UInt64: - return CastAndCreateTensor(name, keys); - case TensorElementType.UInt8: - return CastAndCreateTensor(name, keys); - case TensorElementType.Int8: - return CastAndCreateTensor(name, keys); - case TensorElementType.Bool: - return CastAndCreateTensor(name, keys); - case TensorElementType.Float16: - return CastAndCreateTensor(name, keys); - case TensorElementType.BFloat16: - return CastAndCreateTensor(name, keys); + case Onnx.OptionalProto.Types.DataType.Tensor: + { + var tensor = optional.TensorValue; + return LoadTensorPb(tensor, nodeName, meta); + } + case Onnx.OptionalProto.Types.DataType.Sequence: + { + var sequence = optional.SequenceValue; + return CreateNamedOnnxValueFromSequence(sequence, nodeName, meta); + } + case Onnx.OptionalProto.Types.DataType.Map: + { + var map = optional.MapValue; + return CreateNamedOnnxValueFromMap(map, nodeName, meta); + } + case Onnx.OptionalProto.Types.DataType.Optional: + throw new NotImplementedException($"Unable to load '{nodeName}' optional contained within optional"); default: - throw new NotImplementedException($"Tensors of type: " + elementType.ToString() + - " not currently supported here, use: CreateNamedOnnxValueFromStringTensor."); + // Test data contains OptionalProto with the contained element type undefined. + // the premise is, if the element is not fed as an input, we should not care + // what Onnx type it is. However, we do not need to support AFAIK such inputs + // since the value for them could never be supplied. + throw new NotImplementedException($"Unable to load '{nodeName}' optional element type of: {(Onnx.OptionalProto.Types.DataType)optional.ElemType} type"); } } - /// - /// All the keys in maps are stored as an array of longs, so - /// to create a real tensor we need to cast to create a continuous buffer - /// essentially packing it as a raw data. - /// - /// - /// - /// - /// - /// - /// - internal static NamedOnnxValue CastAndCreateTensor(string name, IList elements) + internal static NamedOnnxValue CreateNamedOnnxValueFromRawData(string name, ReadOnlySpan rawData, + int[] dimensions) + where T : struct + { + var typedSrcSpan = MemoryMarshal.Cast(rawData); + var dt = new DenseTensor(typedSrcSpan.ToArray(), dimensions); + return NamedOnnxValue.CreateFromTensor(name, dt); + } + + static OrtValue LoadOrValueTensorPb(Onnx.TensorProto tensor, string nodeName, NodeMetadata nodeMeta) { - // Create raw data - T[] castKeys = new T[elements.Count]; - if (typeof(T) == typeof(Float16) || typeof(T) == typeof(BFloat16)) + if (nodeMeta.OnnxValueType != OnnxValueType.ONNX_TYPE_TENSOR) { - for (int i = 0; i < elements.Count; i++) - { - var obj = Convert.ChangeType(elements[i], typeof(ushort)); - if (obj == null) - { - throw new InvalidDataException($"Conversion from long to {typeof(T)} failed"); - } - castKeys[i] = (T)obj; - } + throw new InvalidDataException($"Metadata for: '{nodeName}' has a type: '{nodeMeta.OnnxValueType}'" + + $" but loading as tensor: {tensor.Name}"); } - else + + var protoDt = (Tensors.TensorElementType)tensor.DataType; + var metaElementType = nodeMeta.ElementDataType; + if (!((protoDt == metaElementType) || + (protoDt == TensorElementType.UInt16 && + (metaElementType == TensorElementType.BFloat16 || metaElementType == TensorElementType.Float16)))) + throw new InvalidDataException($"For node: '{nodeName}' metadata expects: '{metaElementType}' but loaded loaded tensor type: '{protoDt}'"); + + // Tensors within Sequences may have no dimensions as the standard allows + // different dimensions for each tensor element of the sequence + if (nodeMeta.Dimensions.Length > 0 && nodeMeta.Dimensions.Length != tensor.Dims.Count) { - for (int i = 0; i < elements.Count; i++) - { - var obj = (T)Convert.ChangeType(elements[i], typeof(T)); - if (obj == null) - { - throw new InvalidDataException($"Conversion from long to {typeof(T)} failed"); - } - castKeys[i] = (T)obj; - } + throw new InvalidDataException($"node: '{nodeName}' nodeMeta.Dim.Length: {nodeMeta.Dimensions.Length} " + + $"is expected to be equal to tensor.Dims.Count {tensor.Dims.Count}"); + } + + var shape = tensor.Dims.ToArray(); + + for (int i = 0; i < nodeMeta.Dimensions.Length; i++) + { + if ((nodeMeta.Dimensions[i] != -1) && (nodeMeta.Dimensions[i] != shape[i])) + throw new InvalidDataException($"Node: '{nodeName}' dimension at idx {i} is {nodeMeta.Dimensions}[{i}] " + + $"is expected to either be -1 or {shape[i]}"); } - var tensor = new DenseTensor(castKeys, new int[] { elements.Count }); - return NamedOnnxValue.CreateFromTensor(name, tensor); + + // element type for Float16 and BFloat16 in the loaded tensor would always be uint16, so + // we want to use element type from metadata + if (protoDt == TensorElementType.String) + return CreateOrtValueFromStringTensor(tensor.StringData, shape); + + return CreateOrtValueFromRawData(OrtAllocator.DefaultInstance, tensor.RawData.Span, metaElementType, shape); } - internal static NamedOnnxValue CreateNamedOnnxValueFromMap(Onnx.MapProto map, string nodeName, NodeMetadata nodeMetadata) + internal static OrtValue CreateOrtValueFromSequence(Onnx.SequenceProto sequence, string nodeName, NodeMetadata nodeMeta) { - // See GH issue https://github.com/onnx/onnx/issues/5072 - throw new NotImplementedException($"Loading map node: '{nodeName}' not implemented yet"); + var sequenceMeta = nodeMeta.AsSequenceMetadata(); + var elemMeta = sequenceMeta.ElementMeta; - //var mapMeta = nodeMetadata.AsMapMetadata(); - - //if ((TensorElementType)map.KeyType != mapMeta.KeyDataType) - //{ - // throw new InvalidDataException($"Node: '{nodeName}' map key type expected: " + - // $"'{mapMeta.KeyDataType}', loaded from test data: '{(TensorElementType)map.KeyType}'"); - //} - - //// temp non-generic(!) container - //NamedOnnxValue keysTensor; - //if (mapMeta.KeyDataType == TensorElementType.String) - //{ - // keysTensor = CreateNamedOnnxValueFromStringTensor(map.StringKeys, nodeName, new int[] { map.StringKeys.Count }); - //} - //else - //{ - // keysTensor = CastAndCreateFromMapKeys(nodeName, mapMeta.KeyDataType, map.Keys); - //} - - //switch ((Onnx.SequenceProto.Types.DataType)map.Values.ElemType) - //{ - // case Onnx.SequenceProto.Types.DataType.Tensor: - // var tensorCount = map.Values.TensorValues.Count; - // break; - // default: - // throw new NotImplementedException("Does not support map value type other than a tensor"); - //} - - //return new NamedOnnxValue(string.Empty, new Object(), OnnxValueType.ONNX_TYPE_UNKNOWN); + int seqNum = 0; + var seqElemType = (Onnx.SequenceProto.Types.DataType)sequence.ElemType; + switch (seqElemType) + { + case Onnx.SequenceProto.Types.DataType.Tensor: + { + SequenceCheckMatchOnnxType(nodeName, sequenceMeta, OnnxValueType.ONNX_TYPE_TENSOR); + using DisposableListTest sequenceOfTensors = new(sequence.TensorValues.Count); + foreach (var tensor in sequence.TensorValues) + { + var element = LoadOrValueTensorPb(tensor, sequence.Name, elemMeta); + sequenceOfTensors.Add(element); + } + // Will take possession of ortValues in the sequence and will clear this container + return OrtValue.CreateSequence(sequenceOfTensors); + } + case Onnx.SequenceProto.Types.DataType.Sequence: // Sequence of sequences + { + SequenceCheckMatchOnnxType(nodeName, sequenceMeta, OnnxValueType.ONNX_TYPE_SEQUENCE); + using DisposableListTest seqOfSequences = new(sequence.TensorValues.Count); + foreach (var s in sequence.SequenceValues) + { + var elemName = MakeSequenceElementName(nodeName, sequence.Name, seqNum++); + var ortValue = CreateOrtValueFromSequence(s, elemName, elemMeta); + seqOfSequences.Add(ortValue); + } + return OrtValue.CreateSequence(seqOfSequences); + } + case Onnx.SequenceProto.Types.DataType.Map: + { + throw new NotImplementedException( + "Test data format for maps is under investigation"); + } + case Onnx.SequenceProto.Types.DataType.Optional: + { + SequenceCheckMatchOnnxType(nodeName, sequenceMeta, OnnxValueType.ONNX_TYPE_OPTIONAL); + using DisposableListTest seqOfSequences = new(sequence.TensorValues.Count); + foreach (var opt in sequence.OptionalValues) + { + var elemName = MakeSequenceElementName(nodeName, sequence.Name, seqNum++); + var ortValue = CreateOrtValueFromOptional(opt, elemName, elemMeta); + seqOfSequences.Add(ortValue); + } + return OrtValue.CreateSequence(seqOfSequences); + } + default: + throw new NotImplementedException($"Sequence test data loading does not support element type: " + + $"'{seqElemType}'"); + } } - internal static NamedOnnxValue CreateNamedOnnxValueFromOptional(Onnx.OptionalProto optional, string nodeName, NodeMetadata nodeMetadata) + internal static OrtValue CreateOrtValueFromOptional(Onnx.OptionalProto optional, string nodeName, NodeMetadata nodeMetadata) { var meta = nodeMetadata.AsOptionalMetadata().ElementMeta; - switch((Onnx.OptionalProto.Types.DataType)optional.ElemType) + switch ((Onnx.OptionalProto.Types.DataType)optional.ElemType) { case Onnx.OptionalProto.Types.DataType.Tensor: { var tensor = optional.TensorValue; - return LoadTensorPb(tensor, nodeName, meta); + return LoadOrValueTensorPb(tensor, nodeName, meta); } case Onnx.OptionalProto.Types.DataType.Sequence: { var sequence = optional.SequenceValue; - return CreateNamedOnnxValueFromSequence(sequence, nodeName, meta); + return CreateOrtValueFromSequence(sequence, nodeName, meta); } case Onnx.OptionalProto.Types.DataType.Map: { - var map = optional.MapValue; - return CreateNamedOnnxValueFromMap(map, nodeName, meta); + throw new NotImplementedException( + "Test data format for maps is under investigation"); } case Onnx.OptionalProto.Types.DataType.Optional: throw new NotImplementedException($"Unable to load '{nodeName}' optional contained within optional"); @@ -407,41 +535,69 @@ internal static NamedOnnxValue CreateNamedOnnxValueFromOptional(Onnx.OptionalPro } } - internal static NamedOnnxValue CreateNamedOnnxValueFromRawData(string name, byte[] rawData, int elemWidth, int[] dimensions) + internal static OrtValue CreateOrtValueFromRawData(OrtAllocator allocator, ReadOnlySpan rawData, TensorElementType elementType, long[] shape) { - T[] typedArr = new T[rawData.Length / elemWidth]; - var typeOf = typeof(T); - if (typeOf == typeof(Float16) || typeOf == typeof(BFloat16)) + Debug.Assert(elementType != TensorElementType.String, "Does not support strings"); + var typeInfo = TensorBase.GetElementTypeInfo(elementType); + Assert.NotNull(typeInfo); + + // ArrayUtilities not accessible in all builds + var shapeSize = ShapeUtils.GetSizeForShape(shape); + var inferredSize = rawData.Length / typeInfo.TypeSize; + Assert.Equal(shapeSize, inferredSize); + Assert.Equal(0, rawData.Length % typeInfo.TypeSize); + + var ortValue = OrtValue.CreateAllocatedTensorValue(allocator, elementType, shape); + try { - using (var memSrcHandle = new Memory(rawData).Pin()) - using (var memDstHandle = new Memory(typedArr).Pin()) - { - unsafe - { - Buffer.MemoryCopy(memSrcHandle.Pointer, memDstHandle.Pointer, typedArr.Length * elemWidth, rawData.Length); - } - } + // The endianess data in protobuf is little endian. + // We simply copy raw memory into the tensor raw data. + var span = ortValue.GetTensorMutableRawData(); + Assert.Equal(rawData.Length, span.Length); + rawData.CopyTo(span); + return ortValue; } - else + catch (Exception) { - Buffer.BlockCopy(rawData, 0, typedArr, 0, rawData.Length); + ortValue.Dispose(); + throw; } - var dt = new DenseTensor(typedArr, dimensions); - return NamedOnnxValue.CreateFromTensor(name, dt); } internal static NamedOnnxValue CreateNamedOnnxValueFromStringTensor(IList strings, - string nodeName, int[] dimensions) + string nodeName, int[] dimensions) { string[] strArray = new string[strings.Count]; for (int i = 0; i < strings.Count; ++i) { - strArray[i] = System.Text.Encoding.UTF8.GetString(strings[i].ToByteArray()); +#if NET6_0_OR_GREATER + strArray[i] = Encoding.UTF8.GetString(strings[i].Span); +#else + strArray[i] = Encoding.UTF8.GetString(strings[i].ToByteArray()); +#endif } var dt = new DenseTensor(strArray, dimensions); return NamedOnnxValue.CreateFromTensor(nodeName, dt); } + internal static OrtValue CreateOrtValueFromStringTensor(IList strings, + long[] shape) + { + var ortValue = OrtValue.CreateTensorWithEmptyStrings(OrtAllocator.DefaultInstance, shape); + try + { + for (int i = 0; i < strings.Count; ++i) + { + ortValue.StringTensorSetElementAt(strings[i].Span, i); + } + return ortValue; + } + catch (Exception) + { + ortValue.Dispose(); + throw; + } + } internal static float[] LoadTensorFromFile(string filename, bool skipheader = true) { @@ -451,7 +607,7 @@ internal static float[] LoadTensorFromFile(string filename, bool skipheader = tr using (var inputFile = new System.IO.StreamReader(filename)) { if (skipheader) - inputFile.ReadLine(); //skip the input name + inputFile.ReadLine(); // skip the input name string[] dataStr = inputFile.ReadLine().Split(new char[] { ',', '[', ']', ' ' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < dataStr.Length; i++) { @@ -462,4 +618,4 @@ internal static float[] LoadTensorFromFile(string filename, bool skipheader = tr return tensorData.ToArray(); } } -} \ No newline at end of file +} diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/TrainingTest.cs b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/TrainingTest.cs index 0d16203dbc93b..ea2b6d7dbc118 100644 --- a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/TrainingTest.cs +++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Common/TrainingTest.cs @@ -1,14 +1,17 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using Microsoft.ML.OnnxRuntime.Tensors; using System; -using System.Collections.Generic; using System.IO; -using System.Linq; using Xunit; using Xunit.Abstractions; +#if __TRAINING_ENABLED_NATIVE_BUILD__ +using Microsoft.ML.OnnxRuntime.Tensors; +using System.Collections.Generic; +using System.Linq; +#endif + // This runs in a separate package built from EndToEndTests // and for this reason it can not refer to non-public members // of Onnxruntime package @@ -28,8 +31,8 @@ public TrainingTest(ITestOutputHelper o) public void TestLoadCheckpointThrows() { string path = Path.Combine(Directory.GetCurrentDirectory(), "checkpoint.ckpt"); - var ex = Assert.Throws(() => { var opt = new CheckpointState(path); }); - Assert.Contains("Training is disabled in the current build.", ex.Message); + var ex = Assert.Throws(() => { var opt = CheckpointState.LoadCheckpoint(path); }); + Assert.Contains("Please install the Microsoft.ML.OnnxRuntime.Training NuGet package.", ex.Message); } #endif @@ -38,7 +41,7 @@ public void TestLoadCheckpointThrows() public void TestLoadCheckpoint() { string path = Path.Combine(Directory.GetCurrentDirectory(), "checkpoint.ckpt"); - using (var opt = new CheckpointState(path)) + using (var opt = CheckpointState.LoadCheckpoint(path)) { Assert.NotNull(opt); } @@ -50,12 +53,13 @@ public void TestCreateTrainingSession() string checkpointPath = Path.Combine(Directory.GetCurrentDirectory(), "checkpoint.ckpt"); using (var cleanUp = new DisposableListTest()) { - var state = new CheckpointState(checkpointPath); + var state = CheckpointState.LoadCheckpoint(checkpointPath); cleanUp.Add(state); Assert.NotNull(state); string trainingPath = Path.Combine(Directory.GetCurrentDirectory(), "training_model.onnx"); + string optimizerPath = Path.Combine(Directory.GetCurrentDirectory(), "adamw.onnx"); - var trainingSession = new TrainingSession(state, trainingPath); + var trainingSession = new TrainingSession(state, trainingPath, optimizerPath); cleanUp.Add(trainingSession); } } @@ -66,12 +70,13 @@ public void TestTrainingSessionTrainStep() string checkpointPath = Path.Combine(Directory.GetCurrentDirectory(), "checkpoint.ckpt"); using (var cleanUp = new DisposableListTest()) { - var state = new CheckpointState(checkpointPath); + var state = CheckpointState.LoadCheckpoint(checkpointPath); cleanUp.Add(state); Assert.NotNull(state); string trainingPath = Path.Combine(Directory.GetCurrentDirectory(), "training_model.onnx"); + string optimizerPath = Path.Combine(Directory.GetCurrentDirectory(), "adamw.onnx"); - var trainingSession = new TrainingSession(state, trainingPath); + var trainingSession = new TrainingSession(state, trainingPath, optimizerPath); cleanUp.Add(trainingSession); float[] expectedOutput = TestDataLoader.LoadTensorFromFile("loss_1.out"); @@ -149,12 +154,13 @@ public void TestTrainingSessionTrainStepOrtOutput() string checkpointPath = Path.Combine(Directory.GetCurrentDirectory(), "checkpoint.ckpt"); using (var cleanUp = new DisposableListTest()) { - var state = new CheckpointState(checkpointPath); + var state = CheckpointState.LoadCheckpoint(checkpointPath); cleanUp.Add(state); Assert.NotNull(state); string trainingPath = Path.Combine(Directory.GetCurrentDirectory(), "training_model.onnx"); + string optimizerPath = Path.Combine(Directory.GetCurrentDirectory(), "adamw.onnx"); - var trainingSession = new TrainingSession(state, trainingPath); + var trainingSession = new TrainingSession(state, trainingPath, optimizerPath); cleanUp.Add(trainingSession); RunTrainStep(trainingSession); } @@ -167,21 +173,22 @@ public void TestSaveCheckpoint() string checkpointPath = Path.Combine(Directory.GetCurrentDirectory(), "checkpoint.ckpt"); using (var cleanUp = new DisposableListTest()) { - var state = new CheckpointState(checkpointPath); + var state = CheckpointState.LoadCheckpoint(checkpointPath); cleanUp.Add(state); Assert.NotNull(state); string trainingPath = Path.Combine(Directory.GetCurrentDirectory(), "training_model.onnx"); - var trainingSession = new TrainingSession(state, trainingPath); + string optimizerPath = Path.Combine(Directory.GetCurrentDirectory(), "adamw.onnx"); + var trainingSession = new TrainingSession(state, trainingPath, optimizerPath); cleanUp.Add(trainingSession); // Save checkpoint string savedCheckpointPath = Path.Combine(Directory.GetCurrentDirectory(), "saved_checkpoint.ckpt"); - state.SaveCheckpoint(savedCheckpointPath, true); + CheckpointState.SaveCheckpoint(state, savedCheckpointPath, true); // Load checkpoint and run train step - var loadedState = new CheckpointState(savedCheckpointPath); + var loadedState = CheckpointState.LoadCheckpoint(savedCheckpointPath); cleanUp.Add(loadedState); - var newTrainingSession = new TrainingSession(loadedState, trainingPath); + var newTrainingSession = new TrainingSession(loadedState, trainingPath, optimizerPath); cleanUp.Add(newTrainingSession); RunTrainStep(newTrainingSession); } @@ -193,7 +200,7 @@ public void TestTrainingSessionOptimizerStep() string checkpointPath = Path.Combine(Directory.GetCurrentDirectory(), "checkpoint.ckpt"); using (var cleanUp = new DisposableListTest()) { - var state = new CheckpointState(checkpointPath); + var state = CheckpointState.LoadCheckpoint(checkpointPath); cleanUp.Add(state); Assert.NotNull(state); string trainingPath = Path.Combine(Directory.GetCurrentDirectory(), "training_model.onnx"); @@ -252,7 +259,7 @@ public void TestTrainingSessionSetLearningRate() string checkpointPath = Path.Combine(Directory.GetCurrentDirectory(), "checkpoint.ckpt"); using (var cleanUp = new DisposableListTest()) { - var state = new CheckpointState(checkpointPath); + var state = CheckpointState.LoadCheckpoint(checkpointPath); cleanUp.Add(state); Assert.NotNull(state); string trainingPath = Path.Combine(Directory.GetCurrentDirectory(), "training_model.onnx"); @@ -274,7 +281,7 @@ public void TestTrainingSessionLinearLRScheduler() string checkpointPath = Path.Combine(Directory.GetCurrentDirectory(), "checkpoint.ckpt"); using (var cleanUp = new DisposableListTest()) { - var state = new CheckpointState(checkpointPath); + var state = CheckpointState.LoadCheckpoint(checkpointPath); cleanUp.Add(state); Assert.NotNull(state); string trainingPath = Path.Combine(Directory.GetCurrentDirectory(), "training_model.onnx"); @@ -301,6 +308,228 @@ public void TestTrainingSessionLinearLRScheduler() } } + [Fact(DisplayName = "TestTrainingSessionExportModelForInferencing")] + public void TestTrainingSessionExportModelForInferencing() + { + string checkpointPath = Path.Combine(Directory.GetCurrentDirectory(), "checkpoint.ckpt"); + using (var cleanUp = new DisposableListTest()) + { + var state = CheckpointState.LoadCheckpoint(checkpointPath); + cleanUp.Add(state); + Assert.NotNull(state); + string trainingPath = Path.Combine(Directory.GetCurrentDirectory(), "training_model.onnx"); + string evalPath = Path.Combine(Directory.GetCurrentDirectory(), "eval_model.onnx"); + string optimizerPath = Path.Combine(Directory.GetCurrentDirectory(), "adamw.onnx"); + + var trainingSession = new TrainingSession(state, trainingPath, evalPath, optimizerPath); + cleanUp.Add(trainingSession); + + var graphOutputs = new List(){"output-0"}; + + string inferencePath = Path.Combine(Directory.GetCurrentDirectory(), "inference_model.onnx"); + + trainingSession.ExportModelForInferencing(inferencePath, graphOutputs); + Assert.True(File.Exists(inferencePath)); + } + } + + [Fact(DisplayName = "TestCheckpointStateAddProperty")] + public void TestCheckpointStateAddProperty() + { + string checkpointPath = Path.Combine(Directory.GetCurrentDirectory(), "checkpoint.ckpt"); + using (var cleanUp = new DisposableListTest()) + { + var state = CheckpointState.LoadCheckpoint(checkpointPath); + cleanUp.Add(state); + Assert.NotNull(state); + + string propertyName = "days in a week"; + state.AddProperty(propertyName, (long)7); + + var value = state.GetProperty(propertyName); + Assert.True(value is long); + Assert.Equal((long)7, value); + } + } + + [Fact(DisplayName = "TestCheckpointStateAddFloatProperty")] + public void TestCheckpointStateAddFloatProperty() + { + string checkpointPath = Path.Combine(Directory.GetCurrentDirectory(), "checkpoint.ckpt"); + using (var cleanUp = new DisposableListTest()) + { + var state = CheckpointState.LoadCheckpoint(checkpointPath); + cleanUp.Add(state); + Assert.NotNull(state); + + string propertyName = "pi"; + state.AddProperty(propertyName, (float)3.14); + + var value = state.GetProperty(propertyName); + Assert.True(value is float); + Assert.Equal((float)3.14, value); + } + } + + [Fact(DisplayName = "TestCheckpointStateAddStringProperty")] + public void TestCheckpointStateAddStringProperty() + { + string checkpointPath = Path.Combine(Directory.GetCurrentDirectory(), "checkpoint.ckpt"); + using (var cleanUp = new DisposableListTest()) + { + var state = CheckpointState.LoadCheckpoint(checkpointPath); + cleanUp.Add(state); + Assert.NotNull(state); + + string propertyName = "best ai framework"; + state.AddProperty(propertyName, "onnxruntime"); + + var value = state.GetProperty(propertyName); + Assert.True(value is string); + Assert.Equal("onnxruntime", value); + } + } + + [Fact(DisplayName = "TestTrainModelInputNames")] + public void TestTrainModelInputNames() + { + string checkpointPath = Path.Combine(Directory.GetCurrentDirectory(), "checkpoint.ckpt"); + using (var cleanUp = new DisposableListTest()) + { + var state = CheckpointState.LoadCheckpoint(checkpointPath); + cleanUp.Add(state); + Assert.NotNull(state); + string trainingPath = Path.Combine(Directory.GetCurrentDirectory(), "training_model.onnx"); + string optimizerPath = Path.Combine(Directory.GetCurrentDirectory(), "adamw.onnx"); + var trainingSession = new TrainingSession(state, trainingPath, optimizerPath); + cleanUp.Add(trainingSession); + + var inputNames = trainingSession.InputNames(true); + + Assert.True(inputNames.Count == 2); + Assert.Equal("input-0", inputNames[0]); + Assert.Equal("labels", inputNames[1]); + } + } + + [Fact(DisplayName = "TestEvalModelInputNames")] + public void TestEvalModelInputNames() + { + string checkpointPath = Path.Combine(Directory.GetCurrentDirectory(), "checkpoint.ckpt"); + using (var cleanUp = new DisposableListTest()) + { + var state = CheckpointState.LoadCheckpoint(checkpointPath); + cleanUp.Add(state); + Assert.NotNull(state); + string trainingPath = Path.Combine(Directory.GetCurrentDirectory(), "training_model.onnx"); + string evalPath = Path.Combine(Directory.GetCurrentDirectory(), "eval_model.onnx"); + string optimizerPath = Path.Combine(Directory.GetCurrentDirectory(), "adamw.onnx"); + + var trainingSession = new TrainingSession(state, trainingPath, evalPath, optimizerPath); + cleanUp.Add(trainingSession); + + var inputNames = trainingSession.InputNames(false); + + Assert.True(inputNames.Count == 2); + Assert.Equal("input-0", inputNames[0]); + Assert.Equal("labels", inputNames[1]); + } + } + + [Fact(DisplayName = "TestTrainModelOutputNames")] + public void TestTrainModelOutputNames() + { + string checkpointPath = Path.Combine(Directory.GetCurrentDirectory(), "checkpoint.ckpt"); + using (var cleanUp = new DisposableListTest()) + { + var state = CheckpointState.LoadCheckpoint(checkpointPath); + cleanUp.Add(state); + Assert.NotNull(state); + string trainingPath = Path.Combine(Directory.GetCurrentDirectory(), "training_model.onnx"); + string optimizerPath = Path.Combine(Directory.GetCurrentDirectory(), "adamw.onnx"); + var trainingSession = new TrainingSession(state, trainingPath, optimizerPath); + cleanUp.Add(trainingSession); + + var outputNames = trainingSession.OutputNames(true); + + Assert.Single(outputNames); + Assert.Equal("onnx::loss::21273", outputNames[0]); + } + } + + [Fact(DisplayName = "TestEvalModelOutputNames")] + public void TestEvalModelOutputNames() + { + string checkpointPath = Path.Combine(Directory.GetCurrentDirectory(), "checkpoint.ckpt"); + using (var cleanUp = new DisposableListTest()) + { + var state = CheckpointState.LoadCheckpoint(checkpointPath); + cleanUp.Add(state); + Assert.NotNull(state); + string trainingPath = Path.Combine(Directory.GetCurrentDirectory(), "training_model.onnx"); + string evalPath = Path.Combine(Directory.GetCurrentDirectory(), "eval_model.onnx"); + string optimizerPath = Path.Combine(Directory.GetCurrentDirectory(), "adamw.onnx"); + + var trainingSession = new TrainingSession(state, trainingPath, evalPath, optimizerPath); + cleanUp.Add(trainingSession); + + var outputNames = trainingSession.OutputNames(false); + + Assert.Single(outputNames); + Assert.Equal("onnx::loss::21273", outputNames[0]); + } + } + + [Fact(DisplayName = "TestToBuffer")] + public void TestToBuffer() + { + string checkpointPath = Path.Combine(Directory.GetCurrentDirectory(), "checkpoint.ckpt"); + using (var cleanUp = new DisposableListTest()) + { + var state = CheckpointState.LoadCheckpoint(checkpointPath); + cleanUp.Add(state); + Assert.NotNull(state); + string trainingPath = Path.Combine(Directory.GetCurrentDirectory(), "training_model.onnx"); + string evalPath = Path.Combine(Directory.GetCurrentDirectory(), "eval_model.onnx"); + string optimizerPath = Path.Combine(Directory.GetCurrentDirectory(), "adamw.onnx"); + + var trainingSession = new TrainingSession(state, trainingPath, evalPath, optimizerPath); + cleanUp.Add(trainingSession); + + var buffer = trainingSession.ToBuffer(true); + cleanUp.Add(buffer); + } + } + + [Fact(DisplayName = "TestFromBuffer")] + public void TestFromBuffer() + { + string checkpointPath = Path.Combine(Directory.GetCurrentDirectory(), "checkpoint.ckpt"); + using (var cleanUp = new DisposableListTest()) + { + var state = CheckpointState.LoadCheckpoint(checkpointPath); + cleanUp.Add(state); + Assert.NotNull(state); + string trainingPath = Path.Combine(Directory.GetCurrentDirectory(), "training_model.onnx"); + string evalPath = Path.Combine(Directory.GetCurrentDirectory(), "eval_model.onnx"); + string optimizerPath = Path.Combine(Directory.GetCurrentDirectory(), "adamw.onnx"); + + var trainingSession = new TrainingSession(state, trainingPath, evalPath, optimizerPath); + cleanUp.Add(trainingSession); + + var buffer = trainingSession.ToBuffer(true); + cleanUp.Add(buffer); + + trainingSession.FromBuffer(buffer); + } + } + + [Fact(DisplayName = "TestSetSeed")] + public void TestSetSeed() + { + TrainingUtils.SetSeed(8888); + } + internal class FloatComparer : IEqualityComparer { private float atol = 1e-3f; diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Droid/Microsoft.ML.OnnxRuntime.Tests.Droid.csproj b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Droid/Microsoft.ML.OnnxRuntime.Tests.Droid.csproj index b2a20e3d4ea63..11855032584a3 100644 --- a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Droid/Microsoft.ML.OnnxRuntime.Tests.Droid.csproj +++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.Droid/Microsoft.ML.OnnxRuntime.Tests.Droid.csproj @@ -27,7 +27,7 @@ Xamarin.Android.Net.AndroidClientHandler true ..\..\OnnxRuntime.snk - armeabi-v7a;arm64-v8a + armeabi-v7a;arm64-v8a;x86;x86_64 True @@ -65,7 +65,6 @@ true true r8 - arm64-v8a;armeabi-v7a;x86 Microsoft.ML.OnnxRuntime.Tests.Common;Microsoft.ML.OnnxRuntime.Tests.Devices; @@ -152,7 +151,7 @@ - + libs\arm64-v8a\libonnxruntime.so @@ -174,4 +173,4 @@ --> - \ No newline at end of file + 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 1495bcc4594af..715aed7e1d64f 100644 --- a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.NetCoreApp/InferenceTest.netcore.cs +++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.NetCoreApp/InferenceTest.netcore.cs @@ -1,10 +1,10 @@ -using System; +using Microsoft.ML.OnnxRuntime.Tensors; +using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text.RegularExpressions; -using Microsoft.ML.OnnxRuntime.Tensors; using Xunit; namespace Microsoft.ML.OnnxRuntime.Tests @@ -28,6 +28,7 @@ public static bool Contains(this String str, String substring, return str.IndexOf(substring, comp) >= 0; } } + public partial class InferenceTest { private const string module = "onnxruntime.dll"; @@ -67,19 +68,26 @@ public void CanCreateAndDisposeSessionWithModelPath() } #if USE_CUDA - [Fact(DisplayName = "TestCUDAProviderOptions")] private void TestCUDAProviderOptions() { string modelPath = Path.Combine(Directory.GetCurrentDirectory(), "squeezenet.onnx"); + string defaultDeviceId = "0"; + string deviceIdFromEnv = System.Environment.GetEnvironmentVariable("OnnxruntimeTestGpuDeviceId"); + if (!string.IsNullOrEmpty(deviceIdFromEnv) && int.TryParse(deviceIdFromEnv, out int deviceId) && deviceId >= 0) + { + defaultDeviceId = deviceIdFromEnv; + output.WriteLine($"Parsed ID: {deviceIdFromEnv}"); + } + using (var cleanUp = new DisposableListTest()) { var cudaProviderOptions = new OrtCUDAProviderOptions(); cleanUp.Add(cudaProviderOptions); var providerOptionsDict = new Dictionary(); - providerOptionsDict["device_id"] = "0"; + providerOptionsDict["device_id"] = defaultDeviceId; // 256MB providerOptionsDict["gpu_mem_limit"] = "268435456"; providerOptionsDict["arena_extend_strategy"] = "kSameAsRequested"; @@ -137,10 +145,18 @@ private void TestCUDAProviderOptions() private void CanRunInferenceOnAModelWithTensorRT() { string modelPath = Path.Combine(Directory.GetCurrentDirectory(), "squeezenet.onnx"); + + int deviceId = 0; + string deviceIdStr = System.Environment.GetEnvironmentVariable("ONNXRUNTIME_TEST_GPU_DEVICE_ID"); + if (!string.IsNullOrEmpty(deviceIdStr) && int.TryParse(deviceIdStr, out int parsedValue) && parsedValue >= 0) + { + deviceId = parsedValue; + output.WriteLine($"Parsed ID: {parsedValue}"); + } using (var cleanUp = new DisposableListTest()) { - SessionOptions options = SessionOptions.MakeSessionOptionWithTensorrtProvider(0); + SessionOptions options = SessionOptions.MakeSessionOptionWithTensorrtProvider(deviceId); cleanUp.Add(options); var session = new InferenceSession(modelPath, options); @@ -172,6 +188,13 @@ private void TestTensorRTProviderOptions() string calTablePath = "squeezenet_calibration.flatbuffers"; string enginePath = "./"; string engineDecrptLibPath = "engine_decryp"; + string defaultDeviceId = "0"; + string deviceIdFromEnv = System.Environment.GetEnvironmentVariable("OnnxruntimeTestGpuDeviceId"); + if (!string.IsNullOrEmpty(deviceIdFromEnv) && int.TryParse(deviceIdFromEnv, out int deviceId) && deviceId >= 0) + { + defaultDeviceId = deviceIdFromEnv; + output.WriteLine($"Parsed ID: {deviceIdFromEnv}"); + } using (var cleanUp = new DisposableListTest()) { @@ -179,7 +202,7 @@ private void TestTensorRTProviderOptions() cleanUp.Add(trtProviderOptions); var providerOptionsDict = new Dictionary(); - providerOptionsDict["device_id"] = "0"; + providerOptionsDict["device_id"] = defaultDeviceId; providerOptionsDict["trt_fp16_enable"] = "1"; providerOptionsDict["trt_int8_enable"] = "1"; providerOptionsDict["trt_int8_calibration_table_name"] = calTablePath; @@ -195,7 +218,7 @@ private void TestTensorRTProviderOptions() // test provider options configuration string value; value = resultProviderOptionsDict["device_id"]; - Assert.Equal("0", value); + Assert.Equal(defaultDeviceId, value); value = resultProviderOptionsDict["trt_fp16_enable"]; Assert.Equal("1", value); value = resultProviderOptionsDict["trt_int8_enable"]; @@ -273,18 +296,6 @@ private static Dictionary GetSkippedModels(DirectoryInfo modelsD { "test_mul_uint8", "Could not find an implementation for Mul(14) node with name" }, - { "test_cast_STRING_to_FLOAT", "Output mismatch"}, - { "test_cast_BFLOAT16_to_FLOAT", "Output mismatch"}, - { "test_cast_FLOAT_to_STRING", "Output strings can not be compared exactly"}, - { "test_castlike_STRING_to_FLOAT", "Output mismatch"}, - { "test_castlike_STRING_to_FLOAT_expanded", "Output mismatch"}, - { "test_castlike_BFLOAT16_to_FLOAT", "Length is expected to be equal to Count (metadata and expected data mismatch) "}, - { "test_castlike_BFLOAT16_to_FLOAT_expanded", "Length is expected to be equal to Count metadata and expected data mismatch"}, - { "test_castlike_FLOAT_to_BFLOAT16", "Length is expected to be equal to Count. Testdata dims length do not match that of model metadata"}, - { "test_castlike_FLOAT_to_BFLOAT16_expanded", "Length is expected to be equal to Count"}, - { "test_castlike_FLOAT_to_STRING", "string comparison does not match due to float rounding"}, - { "test_castlike_FLOAT_to_STRING_expanded", "string comparison does not match due to float rounding"}, - { "test_bitshift_right_uint16", "Could not find an implementation for BitShift(11) nodeMeta with name ''"}, { "test_bitshift_left_uint16", "Could not find an implementation for BitShift(11)"}, @@ -308,7 +319,7 @@ private static Dictionary GetSkippedModels(DirectoryInfo modelsD // the expansion of Softplus uses Exp(1). ORT has a Softplus kernel, so testing the expansion is // unnecessary and fails as ORT support for Exp started at opset 6 (as ORT didn't exist until opset 7). - + { "test_clip_default_int8_max_expanded", "Could not find an implementation for Less(13) nodeMeta with name ''" }, { "test_softplus_expanded", "Could not find an implementation for Exp(1) node with name ''"}, { "test_softplus_example_expanded", "Could not find an implementation for Exp(1) node with name ''"}, @@ -337,6 +348,8 @@ private static Dictionary GetSkippedModels(DirectoryInfo modelsD { "test_adagrad", "ai.onnx.preview.training:Adagrad(-1) is not a registered function/op"}, { "test_adagrad_multiple", "ai.onnx.preview.training:Adagrad(-1) is not a registered function/op"}, + + { "test_zfnet512", "skip it as ZFNET-512"}, }; // The following models fails on nocontribops win CI @@ -543,10 +556,188 @@ private string MatchBertSquadOutputs(string fileName) return nodeName; } + private const string keras_prelu_ImageNet_small_nodeName_Input = "p_re_lu_3_input"; + private const string keras_prelu_ImageNet_small_nodeName_Output = "p_re_lu_3/add:0"; + + private void LoadInputData(string opset, string modelName, + DirectoryInfo testDataDir, + InferenceSession session, + IList inputContainer, + Func loader) + { + var inMeta = session.InputMetadata; + foreach (var f in testDataDir.EnumerateFiles("input_*.pb")) + { + if (modelName == "keras_prelu_ImageNet_small" && opset == "opset9") + { + // The model has 1 input, match all file names (they are different in each data set) + // to the same input + var nodeName = keras_prelu_ImageNet_small_nodeName_Input; + var nodeMeta = inMeta[nodeName]; + inputContainer.Add(loader(f.FullName, nodeName, nodeMeta)); + } + else if (modelName == "test_BERT_Squad" && opset == "opset8") + { + string nodeName = MatchBertSquadInputs(f.Name); + var nodeMeta = inMeta[nodeName]; + inputContainer.Add(loader(f.FullName, nodeName, nodeMeta)); + } + else + { + var nodeName = MatchInputOutputWithFile(f.Name, session, true, out NodeMetadata nodeMeta); + inputContainer.Add(loader(f.FullName, nodeName, nodeMeta)); + } + } + } + + private void LoadOutputData(string opset, string modelName, + DirectoryInfo testDataDir, + InferenceSession session, + IList outputContainer, + Func loader) + { + var outMeta = session.OutputMetadata; + foreach (var f in testDataDir.EnumerateFiles("output_*.pb")) + { + if (modelName == "keras_prelu_ImageNet_small" && opset == "opset9") + { + // The model has 1 output, match all file names (they are different in each data set) + // to the same output + var nodeName = keras_prelu_ImageNet_small_nodeName_Output; + var nodeMeta = outMeta[nodeName]; + outputContainer.Add(loader(f.FullName, nodeName, nodeMeta)); + } + else if (modelName == "test_BERT_Squad" && opset == "opset8") + { + string nodeName = MatchBertSquadOutputs(f.Name); + var nodeMeta = outMeta[nodeName]; + outputContainer.Add(loader(f.FullName, nodeName, nodeMeta)); + } + else + { + // Otherwise, just match trailing filename number to the input name -> metadata + var nodeName = MatchInputOutputWithFile(f.Name, session, false, out NodeMetadata nodeMeta); + outputContainer.Add(loader(f.FullName, nodeName, nodeMeta)); + } + } + } + + private void RunPretrainedModel(InferenceSession session, + IReadOnlyList inputContainer, IReadOnlyList outputContainer) + { + var outMeta = session.OutputMetadata; + + var orderedOutputNames = new List(outputContainer.Count); + foreach (var output in outputContainer) + { + orderedOutputNames.Add(output.Name); + } + + using (var resultCollection = session.Run(inputContainer, orderedOutputNames)) + { + Assert.Equal(outputContainer.Count, resultCollection.Count); + for (int i = 0; i < resultCollection.Count; ++i) + { + var result = resultCollection[i]; + var outputValue = outputContainer[i]; + + Assert.NotNull(outputValue); + Assert.Equal(result.Name, outputValue.Name); + + var outputMeta = outMeta[outputValue.Name]; + if (outputMeta.OnnxValueType == OnnxValueType.ONNX_TYPE_OPTIONAL) + { + outputMeta = outputMeta.AsOptionalMetadata().ElementMeta; + } + + Assert.Equal(outputValue.ValueType, outputMeta.OnnxValueType); + + switch (outputValue.ValueType) + { + case OnnxValueType.ONNX_TYPE_TENSOR: // Only Dense tensors now + { + VerifyTensorResults(outputMeta.ElementDataType, result, outputValue); + } + break; + case OnnxValueType.ONNX_TYPE_SEQUENCE: + { + VerifySequenceResults(result, outputValue, outputMeta); + } + break; + default: + Assert.True(false, $"TestPreTrainedModels cannot handle Onnxtype: {outputValue.ValueType}"); + break; + } + } + } + } + + private void RunPretrainedModel(InferenceSession session, RunOptions runOptions, + IReadOnlyList> inputContainer, + IReadOnlyList> outputContainer) + { + var outMeta = session.OutputMetadata; + + var orderedInputNames = new List(inputContainer.Count); + var orderdedInputs = new List(inputContainer.Count); + foreach(var pair in inputContainer) + { + orderedInputNames.Add(pair.Key); + orderdedInputs.Add(pair.Value); + } + + var orderedOutputNames = new List(outputContainer.Count); + var orderedOutputs = new List(outputContainer.Count); + foreach (var pair in outputContainer) + { + orderedOutputNames.Add(pair.Key); + orderedOutputs.Add(pair.Value); + } + + using (var results = session.Run(runOptions, orderedInputNames, orderdedInputs, orderedOutputNames)) + { + Assert.Equal(outMeta.Count, results.Count); + Assert.Equal(outputContainer.Count, results.Count); + + for (int i = 0; i < outputContainer.Count; ++i) + { + var resultValue = results[i]; + var expectedValue = outputContainer[i].Value; + + var outputMeta = outMeta[orderedOutputNames[i]]; + if (outputMeta.OnnxValueType == OnnxValueType.ONNX_TYPE_OPTIONAL) + { + outputMeta = outputMeta.AsOptionalMetadata().ElementMeta; + } + + if (outputMeta.OnnxValueType == OnnxValueType.ONNX_TYPE_TENSOR) + { + VerifyTensorResults(outputMeta.ElementDataType, resultValue, expectedValue); + } + else if (outputMeta.OnnxValueType == OnnxValueType.ONNX_TYPE_SEQUENCE) + { + VerifySequenceResults(resultValue, expectedValue, outputMeta); + } + else + { + Assert.True(false, $"TestPreTrainedModels cannot handle Onnxtype: {outputMeta.OnnxValueType}"); + } + } + } + } + + [Theory(DisplayName = "TestPretrainedModelsWithOrtValue")] + [MemberData(nameof(GetModelsForTest))] + [MemberData(nameof(GetSkippedModelForTest), Skip = "Skipped due to Error, please fix the error and enable the test")] + public void TestPretrainedModelsWithOrtValue(string opsetDir, string modelName) + { + TestPreTrainedModels(opsetDir, modelName, true); + } + [Theory(DisplayName = "TestPreTrainedModels")] [MemberData(nameof(GetModelsForTest))] [MemberData(nameof(GetSkippedModelForTest), Skip = "Skipped due to Error, please fix the error and enable the test")] - private void TestPreTrainedModels(string opsetDir, string modelName) + private void TestPreTrainedModels(string opsetDir, string modelName, bool useOrtValueAPIs = false) { var opsetDirInfo = new DirectoryInfo(opsetDir); var opset = opsetDirInfo.Name; @@ -581,10 +772,9 @@ private void TestPreTrainedModels(string opsetDir, string modelName) throw new Exception($"Opset {opset} Model {modelName}. Can't determine model file name. Found these :{modelNamesList}"); } + using(var runOptions = new RunOptions()) using (var session = new InferenceSession(onnxModelFileName)) { - var inMeta = session.InputMetadata; - var outMeta = session.OutputMetadata; string testDataDirNamePattern = "test_data*"; if (opset == "opset9" && modelName == "LSTM_Seq_lens_unpacked") { @@ -592,96 +782,23 @@ private void TestPreTrainedModels(string opsetDir, string modelName) } foreach (var testDataDir in modelDir.EnumerateDirectories(testDataDirNamePattern)) { - var inputContainer = new List(inMeta.Count); - var outputContainer = new List(outMeta.Count); - foreach (var f in testDataDir.EnumerateFiles("input_*.pb")) + if (useOrtValueAPIs) { - if (modelName == "keras_prelu_ImageNet_small" && opset == "opset9") + using (var inputOrtValues = new DisposableListTest>(session.InputMetadata.Count)) + using (var outputOrtValues = new DisposableListTest>(session.OutputMetadata.Count)) { - // The model has 1 input, match all file names (they are different in each data set) - // to the same input - var nodeName = "p_re_lu_3_input"; - var nodeMeta = inMeta[nodeName]; - inputContainer.Add(TestDataLoader.LoadOnnxValueFromFilePb(f.FullName, nodeName, nodeMeta)); - } - else if (modelName == "test_BERT_Squad" && opset == "opset8") - { - string nodeName = MatchBertSquadInputs(f.Name); - var nodeMeta = inMeta[nodeName]; - inputContainer.Add(TestDataLoader.LoadOnnxValueFromFilePb(f.FullName, nodeName, nodeMeta)); - } - else - { - var nodeName = MatchInputOutputWithFile(f.Name, session, true, out NodeMetadata nodeMeta); - inputContainer.Add(TestDataLoader.LoadOnnxValueFromFilePb(f.FullName, nodeName, nodeMeta)); + LoadInputData(opset, modelName, testDataDir, session, inputOrtValues, TestDataLoader.LoadOrtValueFromFilePb); + LoadOutputData(opset, modelName, testDataDir, session, outputOrtValues, TestDataLoader.LoadOrtValueFromFilePb); + RunPretrainedModel(session, runOptions, inputOrtValues, outputOrtValues); } } - foreach (var f in testDataDir.EnumerateFiles("output_*.pb")) + else { - if (modelName == "keras_prelu_ImageNet_small" && opset == "opset9") - { - // The model has 1 output, match all file names (they are different in each data set) - // to the same output - var nodeName = "p_re_lu_3/add:0"; - var nodeMeta = outMeta[nodeName]; - outputContainer.Add(TestDataLoader.LoadOnnxValueFromFilePb(f.FullName, nodeName, nodeMeta)); - } - else if (modelName == "test_BERT_Squad" && opset == "opset8") - { - string nodeName = MatchBertSquadOutputs(f.Name); - var nodeMeta = outMeta[nodeName]; - outputContainer.Add(TestDataLoader.LoadOnnxValueFromFilePb(f.FullName, nodeName, nodeMeta)); - } - else - { - // Otherwise, just match trailing filename number to the input name -> metadata - var nodeName = MatchInputOutputWithFile(f.Name, session, false, out NodeMetadata nodeMeta); - outputContainer.Add(TestDataLoader.LoadOnnxValueFromFilePb(f.FullName, nodeName, nodeMeta)); - } - } - - using (var resultCollection = session.Run(inputContainer)) - { - foreach (var result in resultCollection) - { - Assert.True(session.OutputMetadata.ContainsKey(result.Name)); - NamedOnnxValue outputValue = null; - foreach (var o in outputContainer) - { - if (o.Name == result.Name) - { - outputValue = o; - break; - } - } - - Assert.NotNull(outputValue); - - var outputMeta = session.OutputMetadata[result.Name]; - if (outputMeta.OnnxValueType == OnnxValueType.ONNX_TYPE_OPTIONAL) - { - outputMeta = outputMeta.AsOptionalMetadata().ElementMeta; - } - - Assert.Equal(outputValue.ValueType, outputMeta.OnnxValueType); - - switch (outputValue.ValueType) - { - case OnnxValueType.ONNX_TYPE_TENSOR: // Only Dense tensors now - { - VerifyTensorResults(outputMeta.ElementDataType, result, outputValue); - } - break; - case OnnxValueType.ONNX_TYPE_SEQUENCE: - { - VerifySequenceResults(result, outputValue, outputMeta); - } - break; - default: - Assert.True(false, $"TestPreTrainedModels cannot handle Onnxtype: {outputValue.ValueType}"); - break; - } - } + var inputContainer = new List(session.InputMetadata.Count); + LoadInputData(opset, modelName, testDataDir, session, inputContainer, TestDataLoader.LoadOnnxValueFromFilePb); + var outputContainer = new List(session.OutputMetadata.Count); + LoadOutputData(opset, modelName, testDataDir, session, outputContainer, TestDataLoader.LoadOnnxValueFromFilePb); + RunPretrainedModel(session, inputContainer, outputContainer); } } } @@ -704,7 +821,7 @@ private void TestPreTrainedModels(string opsetDir, string modelName) } } - private void VerifySequenceResults(NamedOnnxValue result, NamedOnnxValue expectedValue, NodeMetadata metaData) + private static void VerifySequenceResults(NamedOnnxValue result, NamedOnnxValue expectedValue, NodeMetadata metaData) { var meta = metaData.AsSequenceMetadata(); var resultSequence = result.AsEnumerable(); @@ -733,51 +850,51 @@ private void VerifySequenceResults(NamedOnnxValue result, NamedOnnxValue expecte } } - private void VerifyTensorResults(TensorElementType elementType, NamedOnnxValue result, NamedOnnxValue outputValue) + private static void VerifyTensorResults(TensorElementType elementType, NamedOnnxValue result, NamedOnnxValue expectedValue) { switch (elementType) { case TensorElementType.Float: - Assert.Equal(result.AsTensor(), outputValue.AsTensor(), new FloatComparer()); + Assert.Equal(expectedValue.AsTensor(), result.AsTensor(), new FloatComparer()); break; case TensorElementType.Double: - Assert.Equal(result.AsTensor(), outputValue.AsTensor(), new DoubleComparer()); + Assert.Equal(expectedValue.AsTensor(), result.AsTensor(), new DoubleComparer()); break; case TensorElementType.Int32: - Assert.Equal(result.AsTensor(), outputValue.AsTensor(), new ExactComparer()); + Assert.Equal(expectedValue.AsTensor(), result.AsTensor(), new ExactComparer()); break; case TensorElementType.UInt32: - Assert.Equal(result.AsTensor(), outputValue.AsTensor(), new ExactComparer()); + Assert.Equal(expectedValue.AsTensor(), result.AsTensor(), new ExactComparer()); break; case TensorElementType.Int16: - Assert.Equal(result.AsTensor(), outputValue.AsTensor(), new ExactComparer()); + Assert.Equal(expectedValue.AsTensor(), result.AsTensor(), new ExactComparer()); break; case TensorElementType.UInt16: - Assert.Equal(result.AsTensor(), outputValue.AsTensor(), new ExactComparer()); + Assert.Equal(expectedValue.AsTensor(), result.AsTensor(), new ExactComparer()); break; case TensorElementType.Int64: - Assert.Equal(result.AsTensor(), outputValue.AsTensor(), new ExactComparer()); + Assert.Equal(expectedValue.AsTensor(), result.AsTensor(), new ExactComparer()); break; case TensorElementType.UInt64: - Assert.Equal(result.AsTensor(), outputValue.AsTensor(), new ExactComparer()); + Assert.Equal(expectedValue.AsTensor(), result.AsTensor(), new ExactComparer()); break; case TensorElementType.UInt8: - Assert.Equal(result.AsTensor(), outputValue.AsTensor(), new ExactComparer()); + Assert.Equal(expectedValue.AsTensor(), result.AsTensor(), new ExactComparer()); break; case TensorElementType.Int8: - Assert.Equal(result.AsTensor(), outputValue.AsTensor(), new ExactComparer()); + Assert.Equal(result.AsTensor(), result.AsTensor(), new ExactComparer()); break; case TensorElementType.Bool: - Assert.Equal(result.AsTensor(), outputValue.AsTensor(), new ExactComparer()); + Assert.Equal(expectedValue.AsTensor(), result.AsTensor(), new ExactComparer()); break; case TensorElementType.Float16: - Assert.Equal(result.AsTensor(), outputValue.AsTensor(), new Float16Comparer { tolerance = 2 }); + Assert.Equal(expectedValue.AsTensor(), result.AsTensor(), new Float16Comparer { tolerance = 2 }); break; case TensorElementType.BFloat16: - Assert.Equal(result.AsTensor(), outputValue.AsTensor(), new BFloat16Comparer { tolerance = 2 }); + Assert.Equal(expectedValue.AsTensor(), result.AsTensor(), new BFloat16Comparer { tolerance = 2 }); break; case TensorElementType.String: - Assert.Equal(result.AsTensor(), outputValue.AsTensor(), new ExactComparer()); + Assert.Equal(expectedValue.AsTensor(), result.AsTensor(), new ExactComparer()); break; default: Assert.True(false, "TestPreTrainedModels does not yet support output of type: " + elementType.ToString()); @@ -785,6 +902,187 @@ private void VerifyTensorResults(TensorElementType elementType, NamedOnnxValue r } } + private static void VerifySequenceResults(OrtValue resultSequence, OrtValue expectedSequence, NodeMetadata metaData) + { + var allocator = OrtAllocator.DefaultInstance; + Assert.Equal(OnnxValueType.ONNX_TYPE_SEQUENCE, resultSequence.OnnxType); + Assert.Equal(OnnxValueType.ONNX_TYPE_SEQUENCE, expectedSequence.OnnxType); + + var elementMeta = metaData.AsSequenceMetadata().ElementMeta; + + var resultCount = resultSequence.GetValueCount(); + Assert.Equal(expectedSequence.GetValueCount(), resultCount); + + using (var cleanUp = new DisposableListTest()) + { + for (int i = 0; i < resultCount; ++i) + { + var resultItem = resultSequence.GetValue(i, allocator); + cleanUp.Add(resultItem); + + var expectedItem = expectedSequence.GetValue(i, allocator); + cleanUp.Add(expectedItem); + + Assert.Equal(elementMeta.OnnxValueType, expectedItem.OnnxType); + Assert.Equal(elementMeta.OnnxValueType, resultItem.OnnxType); + + switch (elementMeta.OnnxValueType) + { + case OnnxValueType.ONNX_TYPE_TENSOR: + VerifyTensorResults(elementMeta.ElementDataType, resultItem, expectedItem); + break; + case OnnxValueType.ONNX_TYPE_SEQUENCE: + { + VerifySequenceResults(resultItem, expectedItem, elementMeta); + } + break; + default: + Assert.True(false, $"VerifySequenceResults cannot handle Onnxtype: {elementMeta.OnnxValueType}"); + break; + } + } + } + } + + private static void VerifyTensorResults(TensorElementType expectedElementType, OrtValue result, OrtValue expectedValue) + { + Assert.True(result.IsTensor); + Assert.True(expectedValue.IsTensor); + + var resultTypeShape = result.GetTensorTypeAndShape(); + var expectedTypeShape = expectedValue.GetTensorTypeAndShape(); + Assert.Equal(expectedElementType, resultTypeShape.ElementDataType); + Assert.Equal(expectedElementType, expectedTypeShape.ElementDataType); + Assert.Equal(expectedTypeShape.Shape, resultTypeShape.Shape); + + if (expectedElementType == TensorElementType.String) + { + var resStrings = result.GetStringTensorAsArray(); + var expStrings = expectedValue.GetStringTensorAsArray(); + Assert.Equal(expStrings, resStrings); + return; + } + + switch (expectedElementType) + { + case TensorElementType.Float: + Assert.Equal(expectedValue.GetTensorDataAsSpan().ToArray(), result.GetTensorDataAsSpan().ToArray(), + new FloatComparer()); + break; + case TensorElementType.Double: + Assert.Equal(expectedValue.GetTensorDataAsSpan().ToArray(), result.GetTensorDataAsSpan().ToArray(), + new DoubleComparer()); + break; + case TensorElementType.Int32: + Assert.Equal(expectedValue.GetTensorDataAsSpan().ToArray(), result.GetTensorDataAsSpan().ToArray(), new ExactComparer()); + break; + case TensorElementType.UInt32: + Assert.Equal(expectedValue.GetTensorDataAsSpan().ToArray(), result.GetTensorDataAsSpan().ToArray(), new ExactComparer()); + break; + case TensorElementType.Int16: + Assert.Equal(expectedValue.GetTensorDataAsSpan().ToArray(), result.GetTensorDataAsSpan().ToArray(), new ExactComparer()); + break; + case TensorElementType.UInt16: + Assert.Equal(expectedValue.GetTensorDataAsSpan().ToArray(), result.GetTensorDataAsSpan().ToArray(), new ExactComparer()); + break; + case TensorElementType.Int64: + Assert.Equal(expectedValue.GetTensorDataAsSpan().ToArray(), result.GetTensorDataAsSpan().ToArray(), new ExactComparer()); + break; + case TensorElementType.UInt64: + Assert.Equal(expectedValue.GetTensorDataAsSpan().ToArray(), result.GetTensorDataAsSpan().ToArray(), new ExactComparer()); + break; + case TensorElementType.UInt8: + Assert.Equal(expectedValue.GetTensorDataAsSpan().ToArray(), result.GetTensorDataAsSpan().ToArray(), new ExactComparer()); + break; + case TensorElementType.Int8: + Assert.Equal(expectedValue.GetTensorDataAsSpan().ToArray(), result.GetTensorDataAsSpan().ToArray(), new ExactComparer()); + break; + case TensorElementType.Bool: + Assert.Equal(expectedValue.GetTensorDataAsSpan().ToArray(), result.GetTensorDataAsSpan().ToArray(), new ExactComparer()); + break; + case TensorElementType.Float16: + Assert.Equal(expectedValue.GetTensorDataAsSpan().ToArray(), result.GetTensorDataAsSpan().ToArray(), + new Float16Comparer { tolerance = 2 }); + break; + case TensorElementType.BFloat16: + Assert.Equal(expectedValue.GetTensorDataAsSpan().ToArray(), result.GetTensorDataAsSpan().ToArray(), + new BFloat16Comparer { tolerance = 2 }); + break; + default: + Assert.True(false, "VerifyTensorResults cannot handle ElementType: " + expectedElementType.ToString()); + break; + } + } + + private static void VerifyContainerContent(IReadOnlyList results, + IReadOnlyList expectedValues) + { + Assert.Equal(results.Count, expectedValues.Count); + + for (int i = 0; i < expectedValues.Count; ++i) + { + var result = results[i]; + + var resultTypeShape = result.GetTensorTypeAndShape(); + + var expectedValue = expectedValues[i]; + Assert.Equal(OnnxValueType.ONNX_TYPE_TENSOR, expectedValue.ValueType); + + switch (resultTypeShape.ElementDataType) + { + case TensorElementType.Float: + Assert.Equal(result.GetTensorDataAsSpan().ToArray(), expectedValue.AsTensor().ToArray(), + new ExactComparer()); + break; + case TensorElementType.Double: + Assert.Equal(result.GetTensorDataAsSpan().ToArray(), expectedValue.AsTensor().ToArray(), + new DoubleComparer()); + break; + case TensorElementType.Int32: + Assert.Equal(result.GetTensorDataAsSpan().ToArray(), expectedValue.AsTensor().ToArray(), new ExactComparer()); + break; + case TensorElementType.UInt32: + Assert.Equal(result.GetTensorDataAsSpan().ToArray(), expectedValue.AsTensor().ToArray(), new ExactComparer()); + break; + case TensorElementType.Int16: + Assert.Equal(result.GetTensorDataAsSpan().ToArray(), expectedValue.AsTensor().ToArray(), new ExactComparer()); + break; + case TensorElementType.UInt16: + Assert.Equal(result.GetTensorDataAsSpan().ToArray(), expectedValue.AsTensor().ToArray(), new ExactComparer()); + break; + case TensorElementType.Int64: + Assert.Equal(result.GetTensorDataAsSpan().ToArray(), expectedValue.AsTensor().ToArray(), new ExactComparer()); + break; + case TensorElementType.UInt64: + Assert.Equal(result.GetTensorDataAsSpan().ToArray(), expectedValue.AsTensor().ToArray(), new ExactComparer()); + break; + case TensorElementType.UInt8: + Assert.Equal(result.GetTensorDataAsSpan().ToArray(), expectedValue.AsTensor().ToArray(), new ExactComparer()); + break; + case TensorElementType.Int8: + Assert.Equal(result.GetTensorDataAsSpan().ToArray(), expectedValue.AsTensor().ToArray(), new ExactComparer()); + break; + case TensorElementType.Bool: + Assert.Equal(result.GetTensorDataAsSpan().ToArray(), expectedValue.AsTensor().ToArray(), new ExactComparer()); + break; + case TensorElementType.Float16: + Assert.Equal(result.GetTensorDataAsSpan().ToArray(), expectedValue.AsTensor().ToArray(), + new Float16Comparer { tolerance = 2 }); + break; + case TensorElementType.BFloat16: + Assert.Equal(result.GetTensorDataAsSpan().ToArray(), expectedValue.AsTensor().ToArray(), + new BFloat16Comparer { tolerance = 2 }); + break; + case TensorElementType.String: + Assert.Equal(result.GetStringTensorAsArray(), expectedValue.AsTensor().ToArray(), new ExactComparer()); + break; + default: + Assert.True(false, $"VerifyTensorResults cannot handle ElementType: { resultTypeShape.ElementDataType}"); + break; + } + } + } + // Hint: .NET Core 3.1 has a 'NativeLibrary' class that can be used to free the library handle private void UnloadLibrary(IntPtr libraryHandle) { @@ -805,28 +1103,110 @@ private void UnloadLibrary(IntPtr libraryHandle) } } + private string GetCustomOpLibFullPath() + { + string libName = "custom_op_library.dll"; + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + libName = "custom_op_library.dll"; + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + libName = "libcustom_op_library.so"; + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + libName = "libcustom_op_library.dylib"; + } + + string libFullPath = Path.Combine(Directory.GetCurrentDirectory(), libName); + Assert.True(File.Exists(libFullPath), $"Expected lib {libFullPath} does not exist."); + + return libFullPath; + } + + private void ValidateModelWithCustomOps(SessionOptions options) + { + string modelPath = "custom_op_test.onnx"; + + using (var session = new InferenceSession(modelPath, options)) + { + var inputContainer = new List(); + inputContainer.Add(NamedOnnxValue.CreateFromTensor("input_1", + new DenseTensor( + new float[] + { + 1.1f, 2.2f, 3.3f, 4.4f, 5.5f, + 6.6f, 7.7f, 8.8f, 9.9f, 10.0f, + 11.1f, 12.2f, 13.3f, 14.4f, 15.5f + }, + new int[] { 3, 5 } + ))); + + inputContainer.Add(NamedOnnxValue.CreateFromTensor("input_2", + new DenseTensor( + new float[] + { + 15.5f, 14.4f, 13.3f, 12.2f, 11.1f, + 10.0f, 9.9f, 8.8f, 7.7f, 6.6f, + 5.5f, 4.4f, 3.3f, 2.2f, 1.1f + }, + new int[] { 3, 5 } + ))); + + using (var result = session.Run(inputContainer)) + { + Assert.Equal("output", result.First().Name); + var tensorOut = result.First().AsTensor(); + + var expectedOut = new DenseTensor( + new int[] + { + 17, 17, 17, 17, 17, + 17, 18, 18, 18, 17, + 17, 17, 17, 17, 17 + }, + new int[] { 3, 5 } + ); + Assert.True(tensorOut.SequenceEqual(expectedOut)); + } + } + } + [SkipNonPackageTests(DisplayName = "TestRegisterCustomOpLibrary")] private void TestRegisterCustomOpLibrary() { using (var option = new SessionOptions()) { - string libName = "custom_op_library.dll"; - string modelPath = "custom_op_test.onnx"; - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + string libFullPath = GetCustomOpLibFullPath(); + + try { - libName = "custom_op_library.dll"; + option.RegisterCustomOpLibrary(libFullPath); } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + catch (Exception ex) { - libName = "libcustom_op_library.so"; + var msg = $"Failed to load custom op library {libFullPath}, error = {ex.Message}"; + throw new Exception(msg + "\n" + ex.StackTrace); } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + + var ortEnvInstance = OrtEnv.Instance(); + string[] providers = ortEnvInstance.GetAvailableProviders(); + if (Array.Exists(providers, provider => provider == "CUDAExecutionProvider")) { - libName = "libcustom_op_library.dylib"; + option.AppendExecutionProvider_CUDA(0); } - string libFullPath = Path.Combine(Directory.GetCurrentDirectory(), libName); - Assert.True(File.Exists(libFullPath), $"Expected lib {libFullPath} does not exist."); + ValidateModelWithCustomOps(option); + } + } + + [SkipNonPackageTests(DisplayName = "TestRegisterCustomOpLibraryV2")] + private void TestRegisterCustomOpLibraryV2() + { + using (var option = new SessionOptions()) + { + string libFullPath = GetCustomOpLibFullPath(); var ortEnvInstance = OrtEnv.Instance(); string[] providers = ortEnvInstance.GetAvailableProviders(); @@ -846,49 +1226,7 @@ private void TestRegisterCustomOpLibrary() throw new Exception(msg + "\n" + ex.StackTrace); } - - using (var session = new InferenceSession(modelPath, option)) - { - var inputContainer = new List(); - inputContainer.Add(NamedOnnxValue.CreateFromTensor("input_1", - new DenseTensor( - new float[] - { - 1.1f, 2.2f, 3.3f, 4.4f, 5.5f, - 6.6f, 7.7f, 8.8f, 9.9f, 10.0f, - 11.1f, 12.2f, 13.3f, 14.4f, 15.5f - }, - new int[] { 3, 5 } - ))); - - inputContainer.Add(NamedOnnxValue.CreateFromTensor("input_2", - new DenseTensor( - new float[] - { - 15.5f, 14.4f, 13.3f, 12.2f, 11.1f, - 10.0f, 9.9f, 8.8f, 7.7f, 6.6f, - 5.5f, 4.4f, 3.3f, 2.2f, 1.1f - }, - new int[] { 3, 5 } - ))); - - using (var result = session.Run(inputContainer)) - { - Assert.Equal("output", result.First().Name); - var tensorOut = result.First().AsTensor(); - - var expectedOut = new DenseTensor( - new int[] - { - 17, 17, 17, 17, 17, - 17, 18, 18, 18, 17, - 17, 17, 17, 17, 17 - }, - new int[] { 3, 5 } - ); - Assert.True(tensorOut.SequenceEqual(expectedOut)); - } - } + ValidateModelWithCustomOps(option); // Safe to unload the custom op shared library now UnloadLibrary(libraryHandle); @@ -913,8 +1251,10 @@ private void TestModelSerialization() } } - // TestGpu() will test the CUDA EP on CUDA enabled builds and - // the DML EP on DML enabled builds + // TestGpu() will test + // - the CUDA EP on CUDA enabled builds + // - the DML EP on DML enabled builds + // - the ROCm EP on ROCm enabled builds [GpuFact(DisplayName = "TestGpu")] private void TestGpu() { diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.NetCoreApp/Microsoft.ML.OnnxRuntime.Tests.NetCoreApp.csproj b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.NetCoreApp/Microsoft.ML.OnnxRuntime.Tests.NetCoreApp.csproj index 4f99be48828fd..9886f050fbd6b 100644 --- a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.NetCoreApp/Microsoft.ML.OnnxRuntime.Tests.NetCoreApp.csproj +++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.NetCoreApp/Microsoft.ML.OnnxRuntime.Tests.NetCoreApp.csproj @@ -1,7 +1,7 @@  - netcoreapp3.1 + net6.0 false $(ProjectDir)..\.. AnyCPU;x86 @@ -11,7 +11,7 @@ true $(OnnxSourceDirectory)\onnx - 7.2 + default True true ..\..\OnnxRuntime.snk @@ -53,13 +53,39 @@ - + + - + + PreserveNewest + false + + + + PreserveNewest + false + + + PreserveNewest false @@ -93,24 +119,8 @@ - - OrtEnvTests.cs - - - InferenceTest.cs - - - OrtIoBindingAllocationTest.cs - - - TensorTests.cs - - - ArrayTensorExtensionsTests.cs - - - TrainingTest.cs - + + diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.iOS/Microsoft.ML.OnnxRuntime.Tests.iOS.csproj b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.iOS/Microsoft.ML.OnnxRuntime.Tests.iOS.csproj index 6df666f25cd4f..352de5db00920 100644 --- a/csharp/test/Microsoft.ML.OnnxRuntime.Tests.iOS/Microsoft.ML.OnnxRuntime.Tests.iOS.csproj +++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests.iOS/Microsoft.ML.OnnxRuntime.Tests.iOS.csproj @@ -103,7 +103,7 @@ 5.0.0.2083 - + 0.22.2 @@ -205,4 +205,4 @@ - \ No newline at end of file + diff --git a/csharp/tools/MauiModelTester/App.xaml b/csharp/tools/MauiModelTester/App.xaml new file mode 100644 index 0000000000000..43db05cabf542 --- /dev/null +++ b/csharp/tools/MauiModelTester/App.xaml @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/csharp/tools/MauiModelTester/App.xaml.cs b/csharp/tools/MauiModelTester/App.xaml.cs new file mode 100644 index 0000000000000..6fce0251cfa7d --- /dev/null +++ b/csharp/tools/MauiModelTester/App.xaml.cs @@ -0,0 +1,11 @@ +namespace MauiModelTester; + +public partial class App : Application +{ + public App() + { + InitializeComponent(); + + MainPage = new AppShell(); + } +} diff --git a/csharp/tools/MauiModelTester/AppShell.xaml b/csharp/tools/MauiModelTester/AppShell.xaml new file mode 100644 index 0000000000000..986fcf907de9d --- /dev/null +++ b/csharp/tools/MauiModelTester/AppShell.xaml @@ -0,0 +1,14 @@ + + + + + + diff --git a/csharp/tools/MauiModelTester/AppShell.xaml.cs b/csharp/tools/MauiModelTester/AppShell.xaml.cs new file mode 100644 index 0000000000000..15b1485511217 --- /dev/null +++ b/csharp/tools/MauiModelTester/AppShell.xaml.cs @@ -0,0 +1,9 @@ +namespace MauiModelTester; + +public partial class AppShell : Shell +{ + public AppShell() + { + InitializeComponent(); + } +} diff --git a/csharp/tools/MauiModelTester/MainPage.xaml b/csharp/tools/MauiModelTester/MainPage.xaml new file mode 100644 index 0000000000000..3e34fa67d86e7 --- /dev/null +++ b/csharp/tools/MauiModelTester/MainPage.xaml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + [pbr::OriginalName("IR_VERSION_2020_5_8")] IrVersion202058 = 7, /// - /// IR VERSION 8 published on <TBD> + /// IR VERSION 8 published on July 30, 2021 /// Introduce TypeProto.SparseTensor /// Introduce TypeProto.Optional /// Added a list of FunctionProtos local to the model /// Deprecated since_version and operator status from FunctionProto /// - [pbr::OriginalName("IR_VERSION")] IrVersion = 8, + [pbr::OriginalName("IR_VERSION_2021_7_30")] IrVersion2021730 = 8, + /// + /// IR VERSION 9 published on TBD + /// Added AttributeProto to FunctionProto so that default attribute values can be set. + /// Added FLOAT8E4M3FN, FLOAT8E4M3FNUZ, FLOAT8E5M2, FLOAT8E5M2FNUZ. + /// + [pbr::OriginalName("IR_VERSION")] IrVersion = 9, } /// @@ -3860,11 +3870,11 @@ public int DataType { = pb::FieldCodec.ForInt32(42); private readonly pbc::RepeatedField int32Data_ = new pbc::RepeatedField(); /// - /// For int32, uint8, int8, uint16, int16, bool, and float16 values - /// float16 values must be bit-wise converted to an uint16_t prior + /// For int32, uint8, int8, uint16, int16, bool, float8, and float16 values + /// float16 and float8 values must be bit-wise converted to an uint16_t prior /// to writing to the buffer. /// When this field is present, the data_type field MUST be - /// INT32, INT16, INT8, UINT16, UINT8, BOOL, or FLOAT16 + /// INT32, INT16, INT8, UINT16, UINT8, BOOL, FLOAT16, BFLOAT16, FLOAT8E4M3FN, FLOAT8E4M3FNUZ, FLOAT8E5M2, FLOAT8E5M2FNUZ /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] @@ -4486,6 +4496,27 @@ public enum DataType { /// This format has 1 sign bit, 8 exponent bits, and 7 mantissa bits. /// [pbr::OriginalName("BFLOAT16")] Bfloat16 = 16, + /// + /// Non-IEEE floating-point format based on papers + /// FP8 Formats for Deep Learning, https://arxiv.org/abs/2209.05433, + /// 8-bit Numerical Formats For Deep Neural Networks, https://arxiv.org/pdf/2206.02915.pdf. + /// Operators supported FP8 are Cast, CastLike, QuantizeLinear, DequantizeLinear. + /// The computation usually happens inside a block quantize / dequantize + /// fused by the runtime. + /// + [pbr::OriginalName("FLOAT8E4M3FN")] Float8E4M3Fn = 17, + /// + /// float 8, mostly used for coefficients, supports nan, not inf, no negative zero + /// + [pbr::OriginalName("FLOAT8E4M3FNUZ")] Float8E4M3Fnuz = 18, + /// + /// follows IEEE 754, supports nan, inf, mostly used for gradients + /// + [pbr::OriginalName("FLOAT8E5M2")] Float8E5M2 = 19, + /// + /// follows IEEE 754, supports nan, inf, mostly used for gradients, no negative zero + /// + [pbr::OriginalName("FLOAT8E5M2FNUZ")] Float8E5M2Fnuz = 20, } /// @@ -7743,6 +7774,7 @@ public FunctionProto(FunctionProto other) : this() { input_ = other.input_.Clone(); output_ = other.output_.Clone(); attribute_ = other.attribute_.Clone(); + attributeProto_ = other.attributeProto_.Clone(); node_ = other.node_.Clone(); docString_ = other.docString_; opsetImport_ = other.opsetImport_.Clone(); @@ -7804,7 +7836,8 @@ public string Name { = pb::FieldCodec.ForString(50); private readonly pbc::RepeatedField attribute_ = new pbc::RepeatedField(); /// - /// The attributes of the function. + /// The attribute parameters of the function. + /// It is for function parameters without default values. /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] @@ -7812,6 +7845,23 @@ public string Name { get { return attribute_; } } + /// Field number for the "attribute_proto" field. + public const int AttributeProtoFieldNumber = 11; + private static readonly pb::FieldCodec _repeated_attributeProto_codec + = pb::FieldCodec.ForMessage(90, global::Onnx.AttributeProto.Parser); + private readonly pbc::RepeatedField attributeProto_ = new pbc::RepeatedField(); + /// + /// The attribute protos of the function. + /// It is for function attributes with default values. + /// A function attribute shall be represented either as + /// a string attribute or an AttributeProto, not both. + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public pbc::RepeatedField AttributeProto { + get { return attributeProto_; } + } + /// Field number for the "node" field. public const int NodeFieldNumber = 7; private static readonly pb::FieldCodec _repeated_node_codec @@ -7887,6 +7937,7 @@ public bool Equals(FunctionProto other) { if(!input_.Equals(other.input_)) return false; if(!output_.Equals(other.output_)) return false; if(!attribute_.Equals(other.attribute_)) return false; + if(!attributeProto_.Equals(other.attributeProto_)) return false; if(!node_.Equals(other.node_)) return false; if (DocString != other.DocString) return false; if(!opsetImport_.Equals(other.opsetImport_)) return false; @@ -7902,6 +7953,7 @@ public override int GetHashCode() { hash ^= input_.GetHashCode(); hash ^= output_.GetHashCode(); hash ^= attribute_.GetHashCode(); + hash ^= attributeProto_.GetHashCode(); hash ^= node_.GetHashCode(); if (DocString.Length != 0) hash ^= DocString.GetHashCode(); hash ^= opsetImport_.GetHashCode(); @@ -7941,6 +7993,7 @@ public void WriteTo(pb::CodedOutputStream output) { output.WriteRawTag(82); output.WriteString(Domain); } + attributeProto_.WriteTo(output, _repeated_attributeProto_codec); if (_unknownFields != null) { _unknownFields.WriteTo(output); } @@ -7968,6 +8021,7 @@ public void WriteTo(pb::CodedOutputStream output) { output.WriteRawTag(82); output.WriteString(Domain); } + attributeProto_.WriteTo(ref output, _repeated_attributeProto_codec); if (_unknownFields != null) { _unknownFields.WriteTo(ref output); } @@ -7984,6 +8038,7 @@ public int CalculateSize() { size += input_.CalculateSize(_repeated_input_codec); size += output_.CalculateSize(_repeated_output_codec); size += attribute_.CalculateSize(_repeated_attribute_codec); + size += attributeProto_.CalculateSize(_repeated_attributeProto_codec); size += node_.CalculateSize(_repeated_node_codec); if (DocString.Length != 0) { size += 1 + pb::CodedOutputStream.ComputeStringSize(DocString); @@ -8010,6 +8065,7 @@ public void MergeFrom(FunctionProto other) { input_.Add(other.input_); output_.Add(other.output_); attribute_.Add(other.attribute_); + attributeProto_.Add(other.attributeProto_); node_.Add(other.node_); if (other.DocString.Length != 0) { DocString = other.DocString; @@ -8065,6 +8121,10 @@ public void MergeFrom(pb::CodedInputStream input) { Domain = input.ReadString(); break; } + case 90: { + attributeProto_.AddEntriesFrom(input, _repeated_attributeProto_codec); + break; + } } } #endif @@ -8112,6 +8172,10 @@ public void MergeFrom(pb::CodedInputStream input) { Domain = input.ReadString(); break; } + case 90: { + attributeProto_.AddEntriesFrom(ref input, _repeated_attributeProto_codec); + break; + } } } } diff --git a/dockerfiles/Dockerfile.arm32v7 b/dockerfiles/Dockerfile.arm32v7 deleted file mode 100644 index 285f790598061..0000000000000 --- a/dockerfiles/Dockerfile.arm32v7 +++ /dev/null @@ -1,17 +0,0 @@ -# -------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. -# -------------------------------------------------------------- -# Dockerfile to run ONNXRuntime with source build for CPU - -FROM arm32v7/fedora:34 -MAINTAINER Changming Sun "chasun@microsoft.com" -ADD . /code - -RUN /code/dockerfiles/scripts/install_fedora_arm32.sh -RUN cd /code && ./build.sh --allow_running_as_root --skip_submodule_sync --config Release --build_wheel --update --build --parallel --cmake_extra_defines ONNXRUNTIME_VERSION=$(cat ./VERSION_NUMBER) - -FROM arm64v8/centos:7 -COPY --from=0 /code/build/Linux/Release/dist /root -COPY --from=0 /code/dockerfiles/LICENSE-IMAGE.txt /code/LICENSE-IMAGE.txt -RUN yum install -y python3-wheel python3-pip && python3 -m pip install --upgrade pip && python3 -m pip install /root/*.whl && rm -rf /root/*.whl diff --git a/dockerfiles/Dockerfile.arm64 b/dockerfiles/Dockerfile.arm64 deleted file mode 100644 index 06ce9c1e38040..0000000000000 --- a/dockerfiles/Dockerfile.arm64 +++ /dev/null @@ -1,17 +0,0 @@ -# -------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. -# -------------------------------------------------------------- -# Dockerfile to run ONNXRuntime with source build for CPU - -FROM arm64v8/centos:7 -MAINTAINER Changming Sun "chasun@microsoft.com" -ADD . /code - - -RUN /code/dockerfiles/scripts/install_centos_arm64.sh && cd /code && CC=/opt/rh/devtoolset-10/root/usr/bin/gcc CXX=/opt/rh/devtoolset-10/root/usr/bin/g++ ./build.sh --allow_running_as_root --skip_submodule_sync --config Release --build_wheel --update --build --parallel --cmake_extra_defines ONNXRUNTIME_VERSION=$(cat ./VERSION_NUMBER) - -FROM arm64v8/centos:7 -COPY --from=0 /code/build/Linux/Release/dist /root -COPY --from=0 /code/dockerfiles/LICENSE-IMAGE.txt /code/LICENSE-IMAGE.txt -RUN yum install -y python3-wheel python3-pip && python3 -m pip install --upgrade pip && python3 -m pip install /root/*.whl && rm -rf /root/*.whl diff --git a/dockerfiles/Dockerfile.cuda b/dockerfiles/Dockerfile.cuda index 89d0661170105..a03a6b0a6dcdc 100644 --- a/dockerfiles/Dockerfile.cuda +++ b/dockerfiles/Dockerfile.cuda @@ -5,17 +5,18 @@ # Dockerfile to run ONNXRuntime with CUDA, CUDNN integration # nVidia cuda 11.4 Base Image -FROM nvcr.io/nvidia/cuda:11.4.2-cudnn8-devel-ubuntu20.04 +FROM nvcr.io/nvidia/cuda:12.1.1-cudnn8-devel-ubuntu22.04 ENV DEBIAN_FRONTEND=noninteractive MAINTAINER Changming Sun "chasun@microsoft.com" ADD . /code ENV PATH /usr/local/nvidia/bin:/usr/local/cuda/bin:${PATH} -RUN apt-get update && apt-get install -y --no-install-recommends python3-dev ca-certificates g++ python3-numpy gcc make git python3-setuptools python3-wheel python3-packaging python3-pip aria2 && aria2c -q -d /tmp -o cmake-3.24.3-linux-x86_64.tar.gz https://github.com/Kitware/CMake/releases/download/v3.24.3/cmake-3.24.3-linux-x86_64.tar.gz && tar -zxf /tmp/cmake-3.24.3-linux-x86_64.tar.gz --strip=1 -C /usr +RUN apt-get update && apt-get install -y --no-install-recommends python3-dev ca-certificates g++ python3-numpy gcc make git python3-setuptools python3-wheel python3-packaging python3-pip aria2 && aria2c -q -d /tmp -o cmake-3.27.3-linux-x86_64.tar.gz https://github.com/Kitware/CMake/releases/download/v3.27.3/cmake-3.27.3-linux-x86_64.tar.gz && tar -zxf /tmp/cmake-3.27.3-linux-x86_64.tar.gz --strip=1 -C /usr -RUN cd /code && /bin/bash ./build.sh --allow_running_as_root --skip_submodule_sync --cuda_home /usr/local/cuda --cudnn_home /usr/lib/x86_64-linux-gnu/ --use_cuda --config Release --build_wheel --update --build --parallel --cmake_extra_defines ONNXRUNTIME_VERSION=$(cat ./VERSION_NUMBER) 'CMAKE_CUDA_ARCHITECTURES=52;60;61;70;75;86' +RUN cd /code && python3 -m pip install -r tools/ci_build/github/linux/docker/inference/x64/python/cpu/scripts/requireme\ +nts.txt && /bin/bash ./build.sh --allow_running_as_root --skip_submodule_sync --cuda_home /usr/local/cuda --cudnn_home /usr/lib/x86_64-linux-gnu/ --use_cuda --config Release --build_wheel --update --build --parallel --cmake_extra_defines ONNXRUNTIME_VERSION=$(cat ./VERSION_NUMBER) 'CMAKE_CUDA_ARCHITECTURES=52;60;61;70;75;86' -FROM nvcr.io/nvidia/cuda:11.4.2-cudnn8-runtime-ubuntu20.04 +FROM nvcr.io/nvidia/cuda:12.1.1-cudnn8-runtime-ubuntu22.04 ENV DEBIAN_FRONTEND=noninteractive COPY --from=0 /code/build/Linux/Release/dist /root COPY --from=0 /code/dockerfiles/LICENSE-IMAGE.txt /code/LICENSE-IMAGE.txt diff --git a/dockerfiles/Dockerfile.migraphx b/dockerfiles/Dockerfile.migraphx index e3bd39a219896..bc513a8e8ba6d 100644 --- a/dockerfiles/Dockerfile.migraphx +++ b/dockerfiles/Dockerfile.migraphx @@ -30,14 +30,14 @@ RUN apt-get update &&\ apt-get install -y sudo git bash build-essential rocm-dev python3-dev python3-pip miopen-hip \ rocblas half aria2 libnuma-dev pkg-config -RUN aria2c -q -d /tmp -o cmake-3.24.3-linux-x86_64.tar.gz \ -https://github.com/Kitware/CMake/releases/download/v3.24.3/cmake-3.24.3-linux-x86_64.tar.gz &&\ -tar -zxf /tmp/cmake-3.24.3-linux-x86_64.tar.gz --strip=1 -C /usr +RUN aria2c -q -d /tmp -o cmake-3.27.3-linux-x86_64.tar.gz \ +https://github.com/Kitware/CMake/releases/download/v3.27.3/cmake-3.27.3-linux-x86_64.tar.gz &&\ +tar -zxf /tmp/cmake-3.27.3-linux-x86_64.tar.gz --strip=1 -C /usr # Install rbuild RUN pip3 install https://github.com/RadeonOpenCompute/rbuild/archive/master.tar.gz numpy yapf==0.28.0 -ENV PATH /opt/miniconda/bin:/code/cmake-3.24.3-linux-x86_64/bin:${PATH} +ENV PATH /opt/miniconda/bin:/code/cmake-3.27.3-linux-x86_64/bin:${PATH} # Install MIGraphX from source RUN mkdir -p /migraphx diff --git a/dockerfiles/Dockerfile.openvino b/dockerfiles/Dockerfile.openvino index 0d88e3ce1a2a6..78d04a51ba162 100644 --- a/dockerfiles/Dockerfile.openvino +++ b/dockerfiles/Dockerfile.openvino @@ -1,9 +1,9 @@ #------------------------------------------------------------------------- -# Copyright(C) 2021 Intel Corporation. +# Copyright(C) 2021-2023 Intel Corporation. # SPDX-License-Identifier: MIT #-------------------------------------------------------------------------- -ARG OPENVINO_VERSION=2022.3.0 +ARG OPENVINO_VERSION=2023.0.0 # Build stage diff --git a/dockerfiles/Dockerfile.openvino-centos7 b/dockerfiles/Dockerfile.openvino-centos7 index 9970fbe408e82..697db44801e3b 100755 --- a/dockerfiles/Dockerfile.openvino-centos7 +++ b/dockerfiles/Dockerfile.openvino-centos7 @@ -31,9 +31,9 @@ RUN yum update -y && \ yum clean packages && yum clean all && rm -rf /var/cache/yum && \ # Install cmake cd $MY_ROOT && \ - wget https://github.com/Kitware/CMake/releases/download/v3.24.3/cmake-3.24.3.tar.gz && \ - tar -zxvf cmake-3.24.3.tar.gz && rm -rf cmake-3.24.3.tar.gz && \ - cd cmake-3.24.3 && \ + wget https://github.com/Kitware/CMake/releases/download/v3.27.3/cmake-3.27.3.tar.gz && \ + tar -zxvf cmake-3.27.3.tar.gz && rm -rf cmake-3.27.3.tar.gz && \ + cd cmake-3.27.3 && \ ./bootstrap && \ make && \ make install && \ diff --git a/dockerfiles/Dockerfile.openvino-csharp b/dockerfiles/Dockerfile.openvino-csharp index baeeceed58ee6..2529ef4b73209 100644 --- a/dockerfiles/Dockerfile.openvino-csharp +++ b/dockerfiles/Dockerfile.openvino-csharp @@ -1,9 +1,9 @@ #------------------------------------------------------------------------- -# Copyright(C) 2021 Intel Corporation. +# Copyright(C) 2021-2023 Intel Corporation. # SPDX-License-Identifier: MIT #-------------------------------------------------------------------------- -ARG OPENVINO_VERSION=2022.3.0 +ARG OPENVINO_VERSION=2023.0.0 # Build stage FROM openvino/ubuntu20_runtime:${OPENVINO_VERSION} AS base diff --git a/dockerfiles/Dockerfile.rocm b/dockerfiles/Dockerfile.rocm index 60d6999fa9e00..35a676383337b 100644 --- a/dockerfiles/Dockerfile.rocm +++ b/dockerfiles/Dockerfile.rocm @@ -12,7 +12,7 @@ ARG ONNXRUNTIME_BRANCH=main WORKDIR /code -ENV PATH /opt/miniconda/bin:/code/cmake-3.24.3-linux-x86_64/bin:${PATH} +ENV PATH /opt/miniconda/bin:/code/cmake-3.27.3-linux-x86_64/bin:${PATH} # Prepare onnxruntime repository & build onnxruntime RUN git clone --single-branch --branch ${ONNXRUNTIME_BRANCH} --recursive ${ONNXRUNTIME_REPO} onnxruntime &&\ diff --git a/dockerfiles/Dockerfile.source b/dockerfiles/Dockerfile.source index 88360d9cc489f..110e484e77d21 100644 --- a/dockerfiles/Dockerfile.source +++ b/dockerfiles/Dockerfile.source @@ -4,17 +4,17 @@ # -------------------------------------------------------------- # Dockerfile to run ONNXRuntime with source build for CPU -FROM ubuntu:18.04 +FROM mcr.microsoft.com/cbl-mariner/base/python:3 MAINTAINER Changming Sun "chasun@microsoft.com" ADD . /code -ENV DEBIAN_FRONTEND=noninteractive -RUN apt-get update && apt-get install -y --no-install-recommends python3-dev ca-certificates g++ python3-numpy gcc make git python3-setuptools python3-wheel python3-pip aria2 && aria2c -q -d /tmp -o cmake-3.24.3-linux-x86_64.tar.gz https://github.com/Kitware/CMake/releases/download/v3.24.3/cmake-3.24.3-linux-x86_64.tar.gz && tar -zxf /tmp/cmake-3.24.3-linux-x86_64.tar.gz --strip=1 -C /usr +RUN tdnf install -y tar ca-certificates build-essential python3-numpy cmake python3-setuptools python3-wheel python3-pip curl python3-devel +RUN /code/dockerfiles/scripts/install_cmake.sh # Prepare onnxruntime repository & build onnxruntime -RUN cd /code && /bin/bash ./build.sh --allow_running_as_root --skip_submodule_sync --config Release --build_wheel --update --build --parallel --cmake_extra_defines ONNXRUNTIME_VERSION=$(cat ./VERSION_NUMBER) +RUN cd /code && python3 -m pip install -r tools/ci_build/github/linux/docker/inference/x64/python/cpu/scripts/requirements.txt && /bin/bash ./build.sh --allow_running_as_root --skip_submodule_sync --config Release --build_wheel --update --build --parallel --cmake_extra_defines ONNXRUNTIME_VERSION=$(cat ./VERSION_NUMBER) -FROM ubuntu:18.04 +FROM mcr.microsoft.com/cbl-mariner/base/python:3 COPY --from=0 /code/build/Linux/Release/dist /root COPY --from=0 /code/dockerfiles/LICENSE-IMAGE.txt /code/LICENSE-IMAGE.txt -RUN apt-get update && apt-get install -y --no-install-recommends libstdc++6 ca-certificates python3-setuptools python3-wheel python3-pip unattended-upgrades && unattended-upgrade && python3 -m pip install /root/*.whl && rm -rf /root/*.whl +RUN tdnf install -y ca-certificates python3-setuptools python3-wheel python3-pip && python3 -m pip install /root/*.whl && rm -rf /root/*.whl diff --git a/dockerfiles/Dockerfile.tensorrt b/dockerfiles/Dockerfile.tensorrt index ab6173aca02d3..ef51d41c5ff1b 100644 --- a/dockerfiles/Dockerfile.tensorrt +++ b/dockerfiles/Dockerfile.tensorrt @@ -17,7 +17,7 @@ RUN apt-get update &&\ RUN unattended-upgrade WORKDIR /code -ENV PATH /usr/local/nvidia/bin:/usr/local/cuda/bin:/code/cmake-3.24.3-linux-x86_64/bin:/opt/miniconda/bin:${PATH} +ENV PATH /usr/local/nvidia/bin:/usr/local/cuda/bin:/code/cmake-3.27.3-linux-x86_64/bin:/opt/miniconda/bin:${PATH} # Prepare onnxruntime repository & build onnxruntime with TensorRT RUN git clone --single-branch --branch ${ONNXRUNTIME_BRANCH} --recursive ${ONNXRUNTIME_REPO} onnxruntime &&\ diff --git a/dockerfiles/Dockerfile.vitisai b/dockerfiles/Dockerfile.vitisai index 85b9d8c5b7e6a..e11ab70a61332 100644 --- a/dockerfiles/Dockerfile.vitisai +++ b/dockerfiles/Dockerfile.vitisai @@ -22,7 +22,7 @@ RUN apt-get update && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* -ENV PATH /code/cmake-3.24.3-linux-x86_64/bin:$PATH +ENV PATH /code/cmake-3.27.3-linux-x86_64/bin:$PATH ENV LD_LIBRARY_PATH /opt/xilinx/xrt/lib:$LD_LIBRARY_PATH WORKDIR /code @@ -41,4 +41,4 @@ RUN . $VAI_ROOT/conda/etc/profile.d/conda.sh &&\ /bin/sh ./build.sh --allow_running_as_root --config RelWithDebInfo --enable_pybind --build_wheel --use_vitisai --parallel --update --build --build_shared_lib &&\ pip install /code/onnxruntime/build/Linux/RelWithDebInfo/dist/*-linux_x86_64.whl &&\ cd .. &&\ - rm -rf onnxruntime cmake-3.24.3-linux-x86_64 + rm -rf onnxruntime cmake-3.27.3-linux-x86_64 diff --git a/dockerfiles/README.md b/dockerfiles/README.md index 41017e3a888df..f226ebfe8b193 100644 --- a/dockerfiles/README.md +++ b/dockerfiles/README.md @@ -7,10 +7,6 @@ - OpenVINO: [Dockerfile](Dockerfile.openvino), [Instructions](#openvino) - TensorRT: [Dockerfile](Dockerfile.tensorrt), [Instructions](#tensorrt) - VitisAI: [Dockerfile](Dockerfile.vitisai) - -**Platforms** -- ARM 32v7: [Dockerfile](Dockerfile.arm32v7), [Instructions](#arm-3264) -- ARM 64: [Dockerfile](Dockerfile.arm64), [Instructions](#arm-3264) - NVIDIA Jetson TX1/TX2/Nano/Xavier: [Dockerfile](Dockerfile.jetson), [Instructions](#nvidia-jetson-tx1tx2nanoxavier) **Other** @@ -22,38 +18,36 @@ # Instructions ## CPU -**Ubuntu 18.04, CPU, Python Bindings** +**Mariner 2.0, CPU, Python Bindings** -1. Update submodules -``` -git submodule update --init -``` -2. Build the docker image from the Dockerfile in this repository. - ``` +1. Build the docker image from the Dockerfile in this repository. + ```bash docker build -t onnxruntime-source -f Dockerfile.source .. ``` -3. Run the Docker image +2. Run the Docker image - ``` + ```bash docker run -it onnxruntime-source ``` -## CUDA -**Ubuntu 20.04, CUDA 11.4, CuDNN 8** +The docker file supports both x86_64 and ARM64(aarch64). You may use docker's "--platform" parameter to explictly specify which CPU architecture you want to build. For example: -1. Update submodules -``` -git submodule update --init +```bash + docker build --platform linux/arm64/v8 -f Dockerfile.source ``` +However, we cannot build the code for 32-bit ARM in such a way since a 32-bit compiler/linker might not have enough memory to generate the binaries. -2. Build the docker image from the Dockerfile in this repository. +## CUDA +**Ubuntu 22.04, CUDA 12.1, CuDNN 8** + +1. Build the docker image from the Dockerfile in this repository. ``` docker build -t onnxruntime-cuda -f Dockerfile.cuda .. ``` -3. Run the Docker image +2. Run the Docker image ``` docker run --gpus all -it onnxruntime-cuda diff --git a/dockerfiles/scripts/install_centos_arm64.sh b/dockerfiles/scripts/install_centos_arm64.sh deleted file mode 100755 index 9cce676559e50..0000000000000 --- a/dockerfiles/scripts/install_centos_arm64.sh +++ /dev/null @@ -1,23 +0,0 @@ -yum-config-manager --enable extras -yum -y install centos-release-scl-rh -# EPEL support (for yasm) -if ! rpm -q --quiet epel-release ; then - yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm -fi -yum install -y devtoolset-10-binutils devtoolset-10-gcc devtoolset-10-gcc-c++ devtoolset-10-gcc aria2 python3-pip python3-wheel git python3-devel -ARCH=`uname -m` -if [ "$ARCH" = "aarch64" ]; then - aria2c -q -d /tmp -o cmake-3.24.3-linux-aarch64.tar.gz https://github.com/Kitware/CMake/releases/download/v3.24.3/cmake-3.24.3-linux-aarch64.tar.gz && tar -zxf /tmp/cmake-3.24.3-linux-aarch64.tar.gz --strip=1 -C /usr -else - aria2c -q -d /tmp https://github.com/Kitware/CMake/releases/download/v3.24.3/cmake-3.24.3.tar.gz - cd /tmp - mkdir cmake - cd cmake - tar --strip=1 -zxvf /tmp/cmake-3.24.3.tar.gz - ./configure --prefix=/usr --parallel=$(nproc) - make -j$(nproc) - make install -fi -python3 -m pip install --upgrade pip -python3 -m pip install numpy -python3 -m pip install packaging diff --git a/dockerfiles/scripts/install_cmake.sh b/dockerfiles/scripts/install_cmake.sh new file mode 100755 index 0000000000000..e89c323460ac4 --- /dev/null +++ b/dockerfiles/scripts/install_cmake.sh @@ -0,0 +1,11 @@ +#!/bin/bash +set -e -x +mkdir -p /tmp/src +cd /tmp/src + +echo "Installing cmake" +CPU_ARCH=`uname -m` +CMAKE_VERSION='3.27.3' +curl https://github.com/Kitware/CMake/releases/download/v$CMAKE_VERSION/cmake-$CMAKE_VERSION-linux-$CPU_ARCH.tar.gz -sSL --retry 5 -o /tmp/src/cmake.tar.gz +tar -zxf /tmp/src/cmake.tar.gz --strip=1 -C /usr +rm -f /tmp/src/cmake.tar.gz diff --git a/dockerfiles/scripts/install_common_deps.sh b/dockerfiles/scripts/install_common_deps.sh index 5ba12b3c12ab9..786a6f076a71b 100644 --- a/dockerfiles/scripts/install_common_deps.sh +++ b/dockerfiles/scripts/install_common_deps.sh @@ -21,6 +21,6 @@ pip install "wheel>=0.35.1" rm -rf /opt/miniconda/pkgs # Dependencies: cmake -wget --quiet https://github.com/Kitware/CMake/releases/download/v3.24.3/cmake-3.24.3-linux-x86_64.tar.gz -tar zxf cmake-3.24.3-linux-x86_64.tar.gz -rm -rf cmake-3.24.3-linux-x86_64.tar.gz +wget --quiet https://github.com/Kitware/CMake/releases/download/v3.27.3/cmake-3.27.3-linux-x86_64.tar.gz +tar zxf cmake-3.27.3-linux-x86_64.tar.gz +rm -rf cmake-3.27.3-linux-x86_64.tar.gz diff --git a/dockerfiles/scripts/install_fedora_arm32.sh b/dockerfiles/scripts/install_fedora_arm32.sh deleted file mode 100755 index c32859e696c1e..0000000000000 --- a/dockerfiles/scripts/install_fedora_arm32.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -set -e -dnf install -y binutils gcc gcc-c++ aria2 python3-pip python3-wheel git python3-devel cmake -python3 -m pip install --upgrade pip -python3 -m pip install numpy diff --git a/docs/Coding_Conventions_and_Standards.md b/docs/Coding_Conventions_and_Standards.md index 47555ba9f0dd4..e8e1e7dc9ccd8 100644 --- a/docs/Coding_Conventions_and_Standards.md +++ b/docs/Coding_Conventions_and_Standards.md @@ -167,7 +167,13 @@ If you want to see what lintrunner init will install, run To lint local changes: ```bash -lintrunner -m main +lintrunner +``` + +To format files and apply suggestions: + +```bash +lintrunner -a ``` To lint all files: @@ -176,10 +182,10 @@ To lint all files: lintrunner --all-files ``` -To format files: +To show help text: ```bash -lintrunner -a --all-files +lintrunner -h ``` To read more about lintrunner, see [wiki](https://github.com/pytorch/pytorch/wiki/lintrunner). @@ -230,6 +236,7 @@ e.g. `test_method_x_raises_error_when_dims_is_not_a_sequence` ## Objective-C/C++ Code Style -Please follow the [Google Objective-C/C++ Style Guide](https://google.github.io/styleguide/objcguide.html). +Please follow the [Google Objective-C/C++ Style Guide](https://google.github.io/styleguide/objcguide.html) with the following alteration(s): +- The maximum line length is 120 for consistency with the C++ code. Clang-format can be used to format Objective-C/C++ code. The `.clang-format` file is in the repository root directory. diff --git a/docs/ContribOperators.md b/docs/ContribOperators.md index 45b2f8da5f18f..95dc8c3cde46c 100644 --- a/docs/ContribOperators.md +++ b/docs/ContribOperators.md @@ -44,6 +44,7 @@ Do not modify directly.* * com.microsoft.Inverse * com.microsoft.Irfft * com.microsoft.LongformerAttention + * com.microsoft.MatMulFpQ4 * com.microsoft.MatMulInteger16 * com.microsoft.MatMulIntegerToFloat * com.microsoft.MaxpoolWithMask @@ -55,6 +56,7 @@ Do not modify directly.* * com.microsoft.NhwcFusedConv * com.microsoft.NhwcMaxPool * com.microsoft.PackedAttention + * com.microsoft.PackedMultiHeadAttention * com.microsoft.Pad * com.microsoft.QAttention * com.microsoft.QGemm @@ -428,11 +430,11 @@ This version of the operator has been available since version 1 of the 'com.micr
Size of the vocabulary. If not provided, it will be inferred from the decoder subgraph's output shape
-#### Inputs (5 - 10) +#### Inputs (5 - 12)
input_ids : F
-
The sequence used as a prompt for the generation. Shape is (batch_size, sequence_length)
+
The sequence used as a prompt for the generation in the encoder subgraph. Shape is (batch_size, sequence_length)
max_length : I
The maximum length of the sequence to be generated. Shape is (1)
min_length (optional) : I
@@ -451,6 +453,10 @@ This version of the operator has been available since version 1 of the 'com.micr
Mask of vocabulary for first step. Words that masked with 0 are not allowed to be generated, and 1 is allowed. Shape is (batch_size, vocab_size)
attention_mask (optional) : I
Custom attention mask. Shape is (batch_size, sequence_length)
+
decoder_input_ids (optional) : I
+
The forced input id sequence for the decoder subgraph. Shape is (batch_size, initial_sequence_length)
+
logits_processor (optional) : I
+
Specific logits processor for different types of beamsearch models. Default value 0 means no specific logit processor. Accepts value >= 0. Shape is (1)
#### Outputs (1 - 3) @@ -1130,14 +1136,14 @@ This version of the operator has been available since version 1 of the 'com.micr
Custom scale will be used if specified. Default value is 1/sqrt(head_size)
-#### Inputs (3 - 10) +#### Inputs (1 - 11)
query : T
-
Query with shape (batch_size, 1, hidden_size)
-
key : T
+
Query with shape (batch_size, 1, hidden_size) or packed QKV with shape (batch_size, 1, 2 * hidden_size + v_hidden_size)
+
key (optional) : T
Key with shape (batch_size, 1, hidden_size) for self attention or past_key with shape (batch_size, num_heads, kv_sequence_length, head_size) for cross attention
-
value : T
+
value (optional) : T
Value with shape (batch_size, 1, v_hidden_size) for self attention or past_value with shape (batch_size, num_heads, kv_sequence_length, head_size) for cross attention
mask_index (optional) : M
Mask values of shape (batch_size, total_sequence_length) or (batch_size, kv_sequence_length)
@@ -1153,6 +1159,8 @@ This version of the operator has been available since version 1 of the 'com.micr
The beam width that is being used while decoding.If not provided, the beam width will be assumed to be 1.
cache_indirection (optional) : M
A buffer of shape [batch_size, beam_width, max_output_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
+
bias (optional) : T
+
Bias tensor with shape (hidden_size + hidden_size + v_hidden_size) from input projection
#### Outputs (1 - 3) @@ -1200,6 +1208,8 @@ This version of the operator has been available since version 1 of the 'com.micr #### Attributes
+
do_rotary : int
+
Whether to use rotary position embedding. Default value is 0.
mask_filter_value : float
The value to be filled in the attention mask. Default value is -10000.0f
num_heads : int (required)
@@ -1320,15 +1330,15 @@ This version of the operator has been available since version 1 of the 'com.micr
The axis along which same quantization parameters are applied. It's optional.If it's not specified, it means per-tensor quantization and input 'x_scale' and 'x_zero_point' must be scalars.If it's specified, it means per 'axis' quantization and input 'x_scale' and 'x_zero_point' must be 1-D tensors.
-#### Inputs +#### Inputs (2 - 3)
x : T1
N-D quantized Input tensor to be de-quantized.
x_scale : T2
-
Scale for input 'x'. It could be a scalar or a 1-D tensor, which means a per-tensor or per-axis quantization.If it's a 1-D tensor, its number of elements should be equal to the dimension value of 'axis' dimension of input 'x'.
-
x_zero_point : T1
-
Zero point for input 'x'. It could be a scalar or a 1-D tensor, which means a per-tensor or per-axis quantization.If it's a 1-D tensor, its number of elements should be equal to the dimension value of 'axis' dimension of input 'x'.
+
Scale for input 'x'. It can be a scalar, which means a per-tensor/layer dequantization, or a 1-D tensor for per-axis dequantization.
+
x_zero_point (optional) : T1
+
Zero point for input 'x'. Shape must match x_scale. It's optional. Zero point is 0 when it's not specified.
#### Outputs @@ -1341,8 +1351,8 @@ This version of the operator has been available since version 1 of the 'com.micr #### Type Constraints
-
T1 : tensor(int8), tensor(uint8)
-
Constrain 'x' and 'x_zero_point' to 8-bit integer tensors.
+
T1 : tensor(int8), tensor(uint8), tensor(int16), tensor(uint16), tensor(int32)
+
Constrain 'x' and 'x_zero_point' to 8-bit integer tensors, 16-bit integer tensors, or 32-bit signed integer tensors.
T2 : tensor(float16), tensor(float)
Constrain 'y', 'x_scale' to float tensors.
@@ -1527,6 +1537,8 @@ This version of the operator has been available since version 1 of the 'com.micr
epsilon : float
The epsilon value to use to avoid division by zero.
+
mask_index_type : int
+
The mask index tensor type for shape inference (0: None, 1: 1D mask_index)
#### Inputs (7 - 9) @@ -1552,12 +1564,12 @@ This version of the operator has been available since version 1 of the 'com.micr
2D position ids with shape (batch_size, sequence_length) or (1, sequence_length)
-#### Outputs (2 - 3) +#### Outputs (1 - 3)
output : T
3D output tensor with shape (batch_size, sequence_length, hidden_size)
-
mask_index : T1
+
mask_index (optional) : T1
1D mask_index tensor with shape (batch_size)
embedding_sum (optional) : T
sum of word_embedding and position_embedding without layer normalization
@@ -1875,11 +1887,11 @@ This version of the operator has been available since version 1 of the 'com.micr
Number of attention heads
-#### Inputs +#### Inputs (6 - 7)
query_layer : T
-
tensor with shape (batch_size, seq_len, num_heads x head_size)
+
tensor with shape (batch_size, seq_len, num_heads x head_size) or (token_count, num_heads x head_size)
query_bias : T
1-d tensor with shape (num_heads x head_size)
rel_pos : T
@@ -1890,6 +1902,8 @@ This version of the operator has been available since version 1 of the 'com.micr
bias for the gated_ur_linear, shape (D)
eco_a : T
tensor of shape (1, num_heads, 1, 1)
+
token_offset (optional) : M
+
offset of each token with shape (batch_size, seq_len)
#### Outputs @@ -1904,6 +1918,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 types to float tensors.
+
M : tensor(int32)
+
Constrain token_offset to integer types
@@ -2166,6 +2182,8 @@ This version of the operator has been available since version 1 of the 'com.micr
activation : int (required)
Activation after group normalization: 0 for None, 1 for Swish
+
channels_last : int
+
1 if the input and output are in the NHWC layout, 0 if it is in the NCHW layout. Defaults to 1.
epsilon : float
The epsilon value to use to avoid division by zero
groups : int (required)
@@ -2176,7 +2194,7 @@ This version of the operator has been available since version 1 of the 'com.micr
X : T
-
Input data tensor. Dimensions are (N x H x W x C), where N is the batch size, C is the number of channels, and H and W are the height and width of the data
+
Input data tensor. Dimensions are (N x H x W x C) when channels_last is 1 or (N x C x H x W) otherwise, where N is the batch size, C is the number of channels, and H and W are the height and width of the data
gamma : M
1D gamma tensor for normalization with shape (C), where C is number of channels
beta : M
@@ -2195,7 +2213,7 @@ This version of the operator has been available since version 1 of the 'com.micr
T : tensor(float16), tensor(float)
Constrain input X and output Y types to float tensors.
-
M : tensor(float)
+
M : tensor(float16), tensor(float)
Constrain gamma and beta to float tensors.
@@ -2230,6 +2248,8 @@ This version of the operator has been available since version 1 of the 'com.micr ### **com.microsoft.Irfft** + This function computes the inverse of the one-dimensional n-point RFFT computed in 'com.microsoft.rfft'. + #### Version This version of the operator has been available since version 1 of the 'com.microsoft' operator set. @@ -2238,25 +2258,25 @@ This version of the operator has been available since version 1 of the 'com.micr
normalized : int
-
+
must be 0, normalization currently not supported
onesided : int
-
+
must be 1, only one sided FFTs supported
signal_ndim : int (required)
-
+
number of dimensions comprising the signal
#### Inputs
X : T
-
input tensor
+
input tensor with size (n//2 + 1) in the signal dim and 2 in the last dimension for the real and complex parts
#### Outputs
Y : T
-
output tensor
+
output tensor with size n in the signal dim
#### Type Constraints @@ -2327,6 +2347,57 @@ This version of the operator has been available since version 1 of the 'com.micr
+### **com.microsoft.MatMulFpQ4** + + Matrix product with right hand matrix being pre-packed and quantized int4 data blob. + During quantization, the matrix is divided into blocks, where each block is a + continguous subset inside each column. Each block is quantized into a + sequence of 4b integers with a scaling factor and an optional offset. + Currently 3 quantization types are supported: + (0): block size 32, no offset, (1): block size 32, with offset, (2): block size 64, + no offset + +#### Version + +This version of the operator has been available since version 1 of the 'com.microsoft' operator set. + +#### Attributes + +
+
blk_quant_type : int
+
Quantization type
+
+ +#### Inputs + +
+
A : T1
+
N-dimensional matrix A
+
B : T2
+
1-dimensional data blob
+
B_shape : T3
+
Shape information of B
+
+ +#### Outputs + +
+
Y : T1
+
Matrix multiply results from A * B
+
+ +#### Type Constraints + +
+
T1 : tensor(float)
+
Constrain input matrix data types as single precision float tensor
+
T2 : tensor(uint8)
+
Constrain input B data types as data blob
+
T3 : tensor(int64)
+
Constrain shape of B must be int64 tensor.
+
+ + ### **com.microsoft.MatMulInteger16** Matrix product that behaves like numpy.matmul: https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.matmul.html. @@ -2871,6 +2942,81 @@ This version of the operator has been available since version 1 of the 'com.micr
+### **com.microsoft.PackedMultiHeadAttention** + + This is the packed version of MultiHeadAttention. + + Sequences in one batch usually don't have same length and they are padded to have same length, + e.g., below is a batch with 3 sequences and * is padding token. + Sequence_0: 0, 1*, 2*, 3* + Sequence_1: 4, 5, 6*, 7* + Sequence_2: 8, 9, 10, 11 + + PackedMultiHeadAttention is designed to takes in packed input, i.e., only the real tokens without padding. + An input as above will be packed into 3 tensors like below: + - query ([q0, q4, q5, q8, q9, q10, q11]) + - key ([k0, k4, k5, k8, k9, k10, k11]) + - value ([v0, v4, v5, v8, v9, v10, v11]) + - token_offset: 0, 4, 5, 8, 9, 10, 11, 1*, 2*, 3*, 6*, 7* + - cumulative_sequence_length: 0, 1, 1+2, 1+2+4 + + The query, key and value tensors contain result of hidden embedding of real tokens after input projections. + Token_offset records the offset of token in the unpacked input. + cumulative_sequence_length records cumulated length of each sequnces length. + + The operator only supports BERT like model with padding on right now. + +#### Version + +This version of the operator has been available since version 1 of the 'com.microsoft' operator set. + +#### Attributes + +
+
mask_filter_value : float
+
The value to be filled in the attention mask. Default value is -10000.0f
+
num_heads : int (required)
+
Number of attention heads
+
scale : float
+
Custom scale will be used if specified. Default value is 1/sqrt(head_size)
+
+ +#### Inputs (6 - 7) + +
+
query : T
+
Query with shape (token_count, hidden_size) or packed qkv with shape (token_count, num_heads, 3, head_size)
+
key (optional) : T
+
Key with shape (token_count, hidden_size)
+
value (optional) : T
+
Value with shape (token_count, v_hidden_size)
+
bias (optional) : T
+
Bias tensor with shape (hidden_size + hidden_size + v_hidden_size) from input projection
+
token_offset : M
+
Offset of each token before packing, with shape (batch_size, sequence_length).
+
cumulative_sequence_length : M
+
A tensor with shape (batch_size + 1). It specifies the cumulative sequence length.
+
relative_position_bias (optional) : T
+
It specifies the additional bias to QxK'. The shape is (batch_size, num_heads, sequence_length, sequence_length) or (1, num_heads, sequence_length, sequence_length)
+
+ +#### Outputs + +
+
output : T
+
output tensor with shape (token_count, v_hidden_size)
+
+ +#### Type Constraints + +
+
T : tensor(float), tensor(float16)
+
Constrain input and output to float tensors.
+
M : tensor(int32)
+
Constrain mask, offset and sequence length to integer types
+
+ + ### **com.microsoft.Pad** Given `data` tensor, pads, mode, and value. @@ -4048,8 +4194,9 @@ This version of the operator has been available since version 1 of the 'com.micr ### **com.microsoft.QuantizeLinear** The linear quantization operator. It consumes a full precision data, a scale, a zero point to compute the low precision / quantized tensor. - The quantization formula is y = saturate ((x / y_scale) + y_zero_point).For saturation, it saturates to [0, 255] if it's uint8, or [-128, 127] if it's int8. - For (x / y_scale), it's rounding to nearest ties to even. Refer to https://en.wikipedia.org/wiki/Rounding for details. + The quantization formula is y = saturate ((x / y_scale) + y_zero_point). For saturation, it saturates to [0, 255] if it's uint8, [-128, 127] if it's int8, + [0, 65,535] if it's uint16, and [-32,768, 32,767] if it's int16. For (x / y_scale), it's rounding to nearest ties to even. + Refer to https://en.wikipedia.org/wiki/Rounding for details. Scale and zero point must have same shape. They must be either scalar (per tensor) or 1-D tensor (per 'axis'). #### Version @@ -4063,15 +4210,15 @@ This version of the operator has been available since version 1 of the 'com.micr
The axis along which same quantization parameters are applied. It's optional.If it's not specified, it means per-tensor quantization and input 'x_scale' and 'x_zero_point' must be scalars.If it's specified, it means per 'axis' quantization and input 'x_scale' and 'x_zero_point' must be 1-D tensors.
-#### Inputs +#### Inputs (2 - 3)
x : T1
N-D full precision Input tensor to be quantized.
y_scale : T1
-
Scale for doing quantization to get 'y'. It could be a scalar or a 1-D tensor,which means a per-tensor or per-axis quantization. If it's a 1-D tensor, its number of elements should be equal to the dimension value of 'axis' dimension of input 'x'.
-
y_zero_point : T2
-
Zero point for doing quantization to get 'y'. It could be a scalar or a 1-D tensor, which means a per-tensoror per-axis quantization. If it's a 1-D tensor, its number of elements should be equal to the dimension value of 'axis' dimension of input 'x'.
+
Scale for doing quantization to get 'y'. It can be a scalar, which means per-tensor/layer quantization, or a 1-D tensor for per-axis quantization.
+
y_zero_point (optional) : T2
+
Zero point for doing quantization to get 'y'. Shape must match y_scale. Default is uint8 with zero point of 0 if it's not specified.
#### Outputs @@ -4086,8 +4233,8 @@ This version of the operator has been available since version 1 of the 'com.micr
T1 : tensor(float16), tensor(float)
Constrain 'x', 'y_scale' to float tensors.
-
T2 : tensor(int8), tensor(uint8)
-
Constrain 'y_zero_point' and 'y' to 8-bit integer tensors.
+
T2 : tensor(int8), tensor(uint8), tensor(int16), tensor(uint16)
+
Constrain 'y_zero_point' and 'y' to 8-bit and 16-bit integer tensors.
@@ -4382,6 +4529,8 @@ This version of the operator has been available since version 1 of the 'com.micr ### **com.microsoft.Rfft** + This function computes the n-point one dimensional Fourier transform for a real-valued input where n is an even number. + #### Version This version of the operator has been available since version 1 of the 'com.microsoft' operator set. @@ -4390,25 +4539,25 @@ This version of the operator has been available since version 1 of the 'com.micr
normalized : int
-
+
must be 0, normalization currently not supported
onesided : int
-
+
must be 1, only one sided FFTs supported
signal_ndim : int
-
+
number of dimensions comprising the signal, collected in reverse order (e.g. 1 = last dimension is the signal)
#### Inputs
X : T
-
input tensor
+
input tensor of size n in the signal dim
#### Outputs
Y : T
-
output tensor
+
output tensor of size (n//2 + 1) in the signal dim and 2 in the last dimension for the real and complex parts
#### Type Constraints @@ -4555,7 +4704,7 @@ This version of the operator has been available since version 1 of the 'com.micr
input : T
3D input tensor with shape (batch_size, sequence_length, hidden_size)
skip : T
-
3D skip tensor with shape (batch_size, sequence_length, hidden_size)
+
3D skip tensor with shape (batch_size, sequence_length, hidden_size) or (1, sequence_length, hidden_size) or (sequence_length, hidden_size)
gamma : T
1D input tensor with shape (hidden_size)
beta (optional) : T
diff --git a/docs/ORTModule_Convergence_Notes.md b/docs/ORTModule_Convergence_Notes.md index be28ef23d4dc3..791b6c32c9b48 100644 --- a/docs/ORTModule_Convergence_Notes.md +++ b/docs/ORTModule_Convergence_Notes.md @@ -18,7 +18,8 @@ Before looking into this further, we should clarify a few things (if possible): ## 2. Collect Activation Statistics -### Add a few lines of code, run script to collect statistics: + +### 2.1 Use `GlobalSubscriberManager` to collect `nn.Module` forward() outputs @@ -29,12 +30,11 @@ Before looking into this further, we should clarify a few things (if possible): \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", @@ -729,29 +781,29 @@ ], "text/plain": [ " Latency(ms) Latency_P75 Latency_P90 Latency_P99 Throughput(QPS) \\\n", - "0 54.26 56.05 60.32 109.21 18.43 \n", - "1 55.80 56.74 59.67 73.62 17.92 \n", - "2 56.19 61.29 71.69 80.15 17.80 \n", - "3 57.66 58.50 61.96 65.12 17.34 \n", - "4 59.90 59.72 65.16 116.16 16.70 \n", - "5 62.84 67.05 69.07 75.99 15.91 \n", - "6 63.72 64.17 69.44 73.10 15.69 \n", - "7 65.31 65.35 80.70 177.94 15.31 \n", - "8 69.29 69.04 70.68 85.03 14.43 \n", - "9 82.44 83.20 89.64 98.80 12.13 \n", - "10 119.64 119.07 122.62 135.67 8.36 \n", - "11 223.21 223.22 226.83 249.08 4.48 \n", + "0 52.26 52.92 60.94 88.51 19.14 \n", + "1 52.67 52.73 54.06 60.48 18.99 \n", + "2 54.57 55.05 56.52 59.62 18.32 \n", + "3 58.62 65.86 71.94 79.38 17.06 \n", + "4 59.80 61.09 65.72 72.79 16.72 \n", + "5 63.12 61.92 77.47 129.26 15.84 \n", + "6 64.72 65.94 68.54 75.00 15.45 \n", + "7 73.72 80.43 86.39 92.95 13.56 \n", + "8 88.76 96.30 101.13 109.78 11.27 \n", + "9 91.14 99.14 104.41 110.69 10.97 \n", + "10 119.80 119.78 123.66 130.64 8.35 \n", + "11 225.06 227.11 229.45 252.40 4.44 \n", "\n", " intra_op_num_threads \n", "0 12 \n", "1 11 \n", - "2 6 \n", - "3 9 \n", - "4 5 \n", - "5 8 \n", - "6 4 \n", - "7 10 \n", - "8 7 \n", + "2 10 \n", + "3 6 \n", + "4 8 \n", + "5 9 \n", + "6 7 \n", + "7 5 \n", + "8 4 \n", "9 3 \n", "10 2 \n", "11 1 " @@ -782,7 +834,16 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## 6. Additional Info\n", + "## 6. Quantization\n", + "\n", + "Please see example in [BERT quantization notebook](https://github.com/microsoft/onnxruntime-inference-examples/blob/main/quantization/notebooks/bert/Bert-GLUE_OnnxRuntime_quantization.ipynb)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 7. Additional Info\n", "\n", "Note that running Jupyter Notebook has slight impact on performance result since Jupyter Notebook is using system resources like CPU and memory etc. It is recommended to close Jupyter Notebook and other applications, then run the performance test tool in a console to get more accurate performance numbers.\n", "\n", @@ -805,12 +866,12 @@ "text": [ "{\n", " \"gpu\": {\n", - " \"driver_version\": \"470.14\",\n", + " \"driver_version\": \"472.88\",\n", " \"devices\": [\n", " {\n", - " \"memory_total\": 8589934592,\n", - " \"memory_available\": 6782619648,\n", - " \"name\": \"NVIDIA GeForce GTX 1070\"\n", + " \"memory_total\": 12884901888,\n", + " \"memory_available\": 12732858368,\n", + " \"name\": \"NVIDIA GeForce RTX 3060\"\n", " }\n", " ]\n", " },\n", @@ -818,106 +879,37 @@ " \"brand\": \"Intel(R) Core(TM) i7-8700 CPU @ 3.20GHz\",\n", " \"cores\": 6,\n", " \"logical_cores\": 12,\n", - " \"hz\": \"3.1920 GHz\",\n", - " \"l2_cache\": \"1536 KB\",\n", - " \"flags\": [\n", - " \"3dnow\",\n", - " \"3dnowprefetch\",\n", - " \"abm\",\n", - " \"acpi\",\n", - " \"adx\",\n", - " \"aes\",\n", - " \"apic\",\n", - " \"avx\",\n", - " \"avx2\",\n", - " \"bmi1\",\n", - " \"bmi2\",\n", - " \"clflush\",\n", - " \"clflushopt\",\n", - " \"cmov\",\n", - " \"cx16\",\n", - " \"cx8\",\n", - " \"de\",\n", - " \"dtes64\",\n", - " \"dts\",\n", - " \"erms\",\n", - " \"est\",\n", - " \"f16c\",\n", - " \"fma\",\n", - " \"fpu\",\n", - " \"fxsr\",\n", - " \"hle\",\n", - " \"ht\",\n", - " \"hypervisor\",\n", - " \"ia64\",\n", - " \"invpcid\",\n", - " \"lahf_lm\",\n", - " \"mca\",\n", - " \"mce\",\n", - " \"mmx\",\n", - " \"movbe\",\n", - " \"mpx\",\n", - " \"msr\",\n", - " \"mtrr\",\n", - " \"osxsave\",\n", - " \"pae\",\n", - " \"pat\",\n", - " \"pbe\",\n", - " \"pcid\",\n", - " \"pclmulqdq\",\n", - " \"pdcm\",\n", - " \"pge\",\n", - " \"pni\",\n", - " \"popcnt\",\n", - " \"pse\",\n", - " \"pse36\",\n", - " \"rdrnd\",\n", - " \"rdseed\",\n", - " \"rtm\",\n", - " \"sep\",\n", - " \"serial\",\n", - " \"sgx\",\n", - " \"sgx_lc\",\n", - " \"smap\",\n", - " \"smep\",\n", - " \"ss\",\n", - " \"sse\",\n", - " \"sse2\",\n", - " \"sse4_1\",\n", - " \"sse4_2\",\n", - " \"ssse3\",\n", - " \"tm\",\n", - " \"tm2\",\n", - " \"tsc\",\n", - " \"tscdeadline\",\n", - " \"vme\",\n", - " \"x2apic\",\n", - " \"xsave\",\n", - " \"xtpr\"\n", - " ],\n", + " \"hz\": \"3192000000,0\",\n", + " \"l2_cache\": 1572864,\n", + " \"flags\": \"3dnow,3dnowprefetch,abm,acpi,adx,aes,apic,avx,avx2,bmi1,bmi2,clflush,clflushopt,cmov,cx16,cx8,de,dtes64,dts,erms,est,f16c,fma,fpu,fxsr,hle,ht,hypervisor,ia64,invpcid,lahf_lm,mca,mce,mmx,monitor,movbe,mpx,msr,mtrr,osxsave,pae,pat,pbe,pcid,pclmulqdq,pdcm,pge,pni,popcnt,pse,pse36,rdrnd,rdseed,rtm,sep,serial,sgx,sgx_lc,smap,smep,ss,sse,sse2,sse4_1,sse4_2,ssse3,tm,tm2,tsc,tscdeadline,vme,x2apic,xsave,xtpr\",\n", " \"processor\": \"Intel64 Family 6 Model 158 Stepping 10, GenuineIntel\"\n", " },\n", " \"memory\": {\n", " \"total\": 16977195008,\n", - " \"available\": 6085459968\n", + " \"available\": 5000630272\n", + " },\n", + " \"os\": \"Windows-10-10.0.22621-SP0\",\n", + " \"python\": \"3.10.12.final.0 (64 bit)\",\n", + " \"packages\": {\n", + " \"flatbuffers\": \"23.5.26\",\n", + " \"numpy\": \"1.25.2\",\n", + " \"onnx\": \"1.14.0\",\n", + " \"onnxruntime\": \"1.15.1\",\n", + " \"protobuf\": \"4.23.4\",\n", + " \"sympy\": \"1.12\",\n", + " \"torch\": \"2.0.1\",\n", + " \"transformers\": \"4.18.0\"\n", " },\n", - " \"python\": \"3.6.10.final.0 (64 bit)\",\n", - " \"os\": \"Windows-10-10.0.21390-SP0\",\n", " \"onnxruntime\": {\n", - " \"version\": \"1.8.1\",\n", + " \"version\": \"1.15.1\",\n", " \"support_gpu\": false\n", " },\n", - " \"onnxruntime_tools\": null,\n", " \"pytorch\": {\n", - " \"version\": \"1.9.0+cpu\",\n", + " \"version\": \"2.0.1+cpu\",\n", " \"support_gpu\": false,\n", " \"cuda\": null\n", " },\n", - " \"tensorflow\": {\n", - " \"version\": \"2.3.0\",\n", - " \"git_version\": \"v2.3.0-rc2-23-gb36436b087\",\n", - " \"support_gpu\": true\n", - " }\n", + " \"tensorflow\": null\n", "}\n" ] }, @@ -925,8 +917,8 @@ "name": "stderr", "output_type": "stream", "text": [ - "2021-07-13 14:41:45.376756: W tensorflow/stream_executor/platform/default/dso_loader.cc:59] Could not load dynamic library 'cudart64_101.dll'; dlerror: cudart64_101.dll not found\n", - "2021-07-13 14:41:45.376780: I tensorflow/stream_executor/cuda/cudart_stub.cc:29] Ignore above cudart dlerror if you do not have a GPU set up on your machine.\n" + "f:\\anaconda3\\envs\\cpu_env\\lib\\site-packages\\onnxruntime\\transformers\\machine_info.py:127: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html\n", + " import pkg_resources\n" ] } ], @@ -951,9 +943,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.10" + "version": "3.10.12" } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } diff --git a/onnxruntime/python/tools/transformers/notebooks/PyTorch_Bert-Squad_OnnxRuntime_GPU.ipynb b/onnxruntime/python/tools/transformers/notebooks/PyTorch_Bert-Squad_OnnxRuntime_GPU.ipynb index 74b81fc7c867f..43c31e1ea45ac 100644 --- a/onnxruntime/python/tools/transformers/notebooks/PyTorch_Bert-Squad_OnnxRuntime_GPU.ipynb +++ b/onnxruntime/python/tools/transformers/notebooks/PyTorch_Bert-Squad_OnnxRuntime_GPU.ipynb @@ -33,19 +33,20 @@ "\n", "#### GPU Environment Setup using AnaConda\n", "\n", - "First, we install [AnaConda](https://www.anaconda.com/distribution/) in a target machine and open an AnaConda prompt window when it is done. Then run the following commands to create a conda environment. This notebook is tested with PyTorch 1.5.0 and OnnxRuntime 1.3.0.\n", + "First, we install [AnaConda](https://www.anaconda.com/distribution/) in a target machine and open an AnaConda prompt window when it is done. Then run the following commands to create a conda environment. This notebook is tested with PyTorch 2.0.1 and OnnxRuntime 1.16.0.\n", "\n", "```console\n", - "conda create -n gpu_env python=3.6\n", + "conda create -n gpu_env python=3.10\n", "conda activate gpu_env\n", - "conda install -c anaconda ipykernel\n", + "pip install jupyterlab\n", + "conda install ipykernel\n", "conda install -c conda-forge ipywidgets\n", - "python -m ipykernel install --user --name=gpu_env\n", - "jupyter notebook\n", + "ipython kernel install --user --name gpu_env\n", + "jupyter-lab\n", "```\n", "Finally, launch Jupyter Notebook and you can choose gpu_env as kernel to run this notebook.\n", "\n", - "Onnxruntime-gpu need specified version of CUDA and cuDNN. You can find the Requirements [here](https://onnxruntime.ai/docs/install/). Remember to add the directories to PATH environment variable (See [CUDA and cuDNN Path](#CUDA-and-cuDNN-Path) below)." + "Onnxruntime-gpu need specified version of CUDA and cuDNN. You can find the Requirements [here](https://onnxruntime.ai/docs/execution-providers/CUDA-ExecutionProvider.html#requirements). Remember to add the directories to PATH environment variable (See [CUDA and cuDNN Path](#CUDA-and-cuDNN-Path) below)." ] }, { @@ -56,18 +57,19 @@ "source": [ "import sys\n", "\n", - "run_install = False # Only need install once\n", - "if run_install:\n", - " if sys.platform in ['linux', 'win32']: # Linux or Windows\n", - " !{sys.executable} -m pip install torch==1.9.0+cu111 torchvision==0.10.0+cu111 torchaudio===0.9.0 -f https://download.pytorch.org/whl/torch_stable.html\n", - " else: # Mac\n", - " print(\"PyTorch 1.9 MacOS Binaries do not support CUDA, install from source instead\")\n", - "\n", - " !{sys.executable} -m pip install onnxruntime-gpu==1.8.1 onnx==1.9.0 onnxconverter_common==1.8.1\n", - "\n", - " # Install other packages used in this notebook.\n", - " !{sys.executable} -m pip install transformers==4.8.2\n", - " !{sys.executable} -m pip install psutil pytz pandas py-cpuinfo py3nvml coloredlogs wget netron sympy" + "if sys.platform in ['linux', 'win32']: # Linux or Windows\n", + " !{sys.executable} -m pip install torch --index-url https://download.pytorch.org/whl/cu118 -q\n", + " !{sys.executable} -m pip install onnxruntime-gpu onnx transformers psutil pandas py-cpuinfo py3nvml coloredlogs wget netron sympy protobuf==3.20.3 -q\n", + "else: # Mac\n", + " print(\"CUDA is not available on MacOS\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### CUDA and cuDNN Path\n", + "onnxruntime-gpu has dependency on [CUDA](https://developer.nvidia.com/cuda-downloads) and [cuDNN](https://developer.nvidia.com/cudnn). Required CUDA version can be found [here](https://onnxruntime.ai/docs/execution-providers/CUDA-ExecutionProvider.html#requirements) If you import torch before onnxruntime, onnxruntime might use the CUDA and cuDNN DLLs that loaded by PyTorch." ] }, { @@ -79,10 +81,10 @@ "name": "stdout", "output_type": "stream", "text": [ - "pytorch: 1.9.0+cu111\n", - "onnxruntime: 1.8.1\n", - "onnx: 1.9.0\n", - "transformers: 4.8.2\n" + "pytorch: 2.0.1+cu118\n", + "onnxruntime: 1.16.0\n", + "onnx: 1.14.1\n", + "transformers: 4.33.1\n" ] } ], @@ -191,9 +193,12 @@ "name": "stderr", "output_type": "stream", "text": [ - "100%|██████████| 48/48 [00:03<00:00, 14.24it/s]\n", - "convert squad examples to features: 100%|██████████| 1000/1000 [00:08<00:00, 112.67it/s]\n", - "add example index and unique id: 100%|██████████| 1000/1000 [00:00<00:00, 836518.55it/s]\n" + "Some weights of the model checkpoint at bert-large-uncased-whole-word-masking-finetuned-squad were not used when initializing BertForQuestionAnswering: ['bert.pooler.dense.bias', 'bert.pooler.dense.weight']\n", + "- This IS expected if you are initializing BertForQuestionAnswering from the checkpoint of a model trained on another task or with another architecture (e.g. initializing a BertForSequenceClassification model from a BertForPreTraining model).\n", + "- This IS NOT expected if you are initializing BertForQuestionAnswering from the checkpoint of a model that you expect to be exactly identical (initializing a BertForSequenceClassification model from a BertForSequenceClassification model).\n", + "100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 48/48 [00:02<00:00, 16.27it/s]\n", + "convert squad examples to features: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1000/1000 [00:03<00:00, 256.11it/s]\n", + "add example index and unique id: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1000/1000 [00:00\n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", "
-```diff -+ from onnxruntime.training.utils.hooks import SubscriberManager, -+ StatisticsSubscriber -+ sub_m = SubscriberManager() -+ sub_m.subscribe(model, [StatisticsSubscriber(output_dir="pt_out", -+ override_output_dir=True)]) +```python +from onnxruntime.training.utils.hooks import GlobalSubscriberManager, StatisticsSubscriber +GlobalSubscriberManager.subscribe( + model, [StatisticsSubscriber(output_dir="pt_out", override_output_dir=True)] +) ``` @@ -42,13 +42,12 @@ Before looking into this further, we should clarify a few things (if possible): -```diff +```python model = ORTModule(model) -+ from onnxruntime.training.utils.hooks import SubscriberManager, -+ StatisticsSubscriber -+ sub_m = SubscriberManager() -+ sub_m.subscribe(model, [StatisticsSubscriber(output_dir="ort_out", -+ override_output_dir=True)]) +from onnxruntime.training.utils.hooks import GlobalSubscriberManager, StatisticsSubscriber +GlobalSubscriberManager.subscribe( + model, [StatisticsSubscriber(output_dir="ort_out", override_output_dir=True)] +) ``` @@ -77,16 +76,65 @@ model = ORTModule(model) Arguments: - output_dir: the directory in all activation statistics files will be stored. -- start_step [optional]: the first step that runs subscriber actions. -- end_step [optional]: the end step (exclusively) that runs subscriber actions. -- override_output_dir: whether `output_dir` can be overridden if it already exists. +- `start_step` [optional]: the first step that runs subscriber actions. +- `end_step` [optional]: the end step (exclusively) that runs subscriber actions. +- `override_output_dir`: whether `output_dir` can be overridden if it already exists. +- `run_on_cpu`: whether to run the subscriber actions on CPU, this should be the last resort when inserted + inspector node affects memory peak causing the original recipe run to fail with OOM. +- `bucket_size`: the size of the bucket to split the statistic calculation. + +### 2.2 Use `inspect_activation` to collect intermediate tensors in a `nn.Module` forward() + +The limitation of `GlobalSubscriberManager` is, only 'nn.Module's forward output tensors will be dumped, if you want to +dump the intermediate tensors in a `nn.Module`'s forward function, refer to the following example: + +```diff ++ from onnxruntime.training.utils import inspect_activation +class BloomForCausalLM(BloomPreTrainedModel): + def __init__(self, config: BloomConfig): + ... + + def forward(self, input_ids, ...): + ... + transformer_outputs = self.transformer(...) + hidden_states = transformer_outputs[0] + lm_logits = self.lm_head(hidden_states) ++ lm_logits = inspect_activation("lm_logits", lm_logits) + # Shift so that tokens < n predict n + shift_logits = lm_logits[..., :-1, :].contiguous() ++ shift_logits = inspect_activation("shift_logits", shift_logits) + shift_labels = labels[..., 1:].contiguous() + batch_size, seq_length, vocab_size = shift_logits.shape + # Flatten the tokens + loss_fct = CrossEntropyLoss() + loss = loss_fct( + shift_logits.view(batch_size * seq_length, vocab_size), shift_labels.view(batch_size * seq_length) + ) + + return loss +``` + +Be noted, make sure the activation name (as the first argument of `inspect_activation`) is unique, otherwise +stat file using the activation name will be overwritten by the last write. The dumped data are stored in the `output_dir`. + + +### 2.3 Collect on multiple ranks + +`GlobalSubscriberManager` does not explicitly handle the racing condition when multiple ranks write into the same file path, +here is the example if you want to collect statistics on multiple ranks: + +```python +from onnxruntime.training.utils.hooks import GlobalSubscriberManager, StatisticsSubscriber +GlobalSubscriberManager.subscribe(model, [StatisticsSubscriber(output_dir="ort_out_" + str(torch.distributed.get_rank()), + override_output_dir=True)]) +``` -Check [StatisticsSubscriber implementation](../orttraining/orttraining/python/training/utils/hooks/_statistics_subscriber.py) for more information. +Check [StatisticsSubscriber implementation](../orttraining/orttraining/python/training/utils/hooks/_statistics_subscriber.py) for more information. -### Run command to generate per-step summary +### 2.4 Run command to generate per-step summary ```bash python -m onnxruntime.training.utils.hooks.merge_activation_summary --pt_dir pt_out --ort_dir ort_out --output_dir /tmp/output ``` -### Manually compare the generated per-step summary to find the first big diff. +### 2.5 Manually compare the generated per-step summary to find the first big diff. diff --git a/docs/ORTModule_ModuleWithLoss_Wrapper.md b/docs/ORTModule_ModuleWithLoss_Wrapper.md new file mode 100644 index 0000000000000..6c4242643a7ac --- /dev/null +++ b/docs/ORTModule_ModuleWithLoss_Wrapper.md @@ -0,0 +1,102 @@ +# ONNX Runtime ModuleWithLoss Wrapper + +This document provides instructions on implementing a wrapper similar to the ModuleWithLoss Wrapper in Optimum. By implementing this wrapper, you can compute the loss inside ONNX Runtime (ORT), enabling you to leverage additional optimizations such as label sparsity optimization. + +**Note: The adaptation described below is not necessary for all cases. It is only needed in specific scenarios, which we will clarify below:** + +1. When the loss is not computed in the model's forward path. +2. When the model's forward path computes the loss but also returns other outputs that are not needed for subsequent computations. + +In the first case, if the loss is not computed in the model's forward pass, ONNX Runtime (ORT) cannot track the loss computation in the ONNX graph. + +In the second case, if the model's forward pass computes the loss but also returns additional tensors that are not needed for subsequent computations, using the original model directly with the ORT wrapper can lead to unnecessary memory usage on the CUDA device during backward computations. + +## Implementation Steps + +Follow these steps to create your own ModuleWithLoss for computing loss inside ONNX Runtime: + +Certainly! Here are the steps to fit the provided example: + +### Step 1: Define `ModuleWithLoss` Class + +1. Create a class named `ModuleWithLoss` that extends `nn.Module`. +2. Implement the `__init__` method to initialize the wrapper with the original model. +3. Implement the `forward` method to perform the forward pass of the model and compute the loss. +4. Use the model's `forward` method to compute the logits. +5. Compute the loss between the logits and the labels. +6. Return the computed loss. + +```python +class ModuleWithLoss(nn.Module): + def __init__(self, model): + super().__init__() + self.model = model + + def forward(self, inputs, labels): + # Perform the forward pass of the model + lm_logits = self.model(inputs) + + # Compute the cross-entropy loss + loss = nn.CrossEntropyLoss()(lm_logits, labels) + return loss +``` +### Step 2: Define a sample training script + +#### Define `PretrainedModel` Class + +1. Implement the `PretrainedModel` class by extending `nn.Module`. +2. Define the `forward` method inside `PretrainedModel` to perform the forward pass of the model. +3. Use the model's transformer layers and head layers to compute the logits. +4. Return the logits as the output of the `forward` method. + +#### Training Loop + +1. Create an instance of `PretrainedModel` as the original model. +2. Create an instance of `ModuleWithLoss` by passing the original model as an argument. +3. Initialize the optimizer for training. +4. Enter the training loop and iterate over the training data. +5. Zero the gradients of the optimizer. +6. Compute the forward pass and cross-entropy loss by calling the `forward` method of the `ModuleWithLoss` instance and passing the inputs and labels. +7. Perform the backward pass by calling `loss.backward()` and optimization step by calling `optimizer.step()`. + +Make sure to fill in the appropriate details and customize the code as per your specific requirements and implementation. + +```python +# Define the model architecture +class PretrainedModel(nn.Module): + ... + + def forward(self, input_ids, attention_mask): + ... + transformer_outputs = self.transformer( + input_ids, + attention_mask=attention_mask, + ... + ) + hidden_states = transformer_outputs[0] + lm_logits = self.lm_head(hidden_states) + return lm_logits + +# Training loop +model = PretrainedModel(...) +model = ModuleWithLoss(model) + +optimizer = torch.optim.Adam(model.parameters(), lr=0.001) + +model = ORTModule(model) + +for inputs, labels in dataloader: + optimizer.zero_grad() + + # Compute the forward pass and cross-entropy loss + loss = model(inputs, labels) + + # Backward pass and optimization step + loss.backward() + optimizer.step() + +``` + +By following these steps, you can create a wrapper that computes the loss inside ONNX Runtime (ORT) using the `ModuleWithLoss` class and the `compute_loss` function. Make sure to customize the code snippets according to your specific codebase and requirements. + +Please note that the steps provided above are specific to the example I provided, and you may need to adapt them based on your own implementation and requirements. diff --git a/docs/ORTModule_Training_Guidelines.md b/docs/ORTModule_Training_Guidelines.md index b41bde2d28a69..5350988b20964 100644 --- a/docs/ORTModule_Training_Guidelines.md +++ b/docs/ORTModule_Training_Guidelines.md @@ -47,7 +47,7 @@ More options for **developers**. + from onnxruntime.training.ortmodule import ORTModule, DebugOptions, LogLevel + model = ORTModule(model, DebugOptions(save_onnx=True, log_level=LogLevel.VERBOSE, onnx_prefix="model_name")) ``` -Check [DebugOptions implementation](../orttraining/orttraining/python/training/ortmodule/debug_options.py) for more details. +Check [DebugOptions implementation](../orttraining/orttraining/python/training/ortmodule/options.py) for more details. ### 2.1 Environment Variables @@ -99,12 +99,13 @@ The output directory of the onnx models by default is set to the current working > Overall users should be aware that ORT performance boost might be trivial when they explicitly allow it. -#### ORTMODULE_DISABLE_CUSTOM_AUTOGRAD_SUPPORT +#### ORTMODULE_ENABLE_CUSTOM_AUTOGRAD - **Feature Area**: *ORTMODULE/PythonOp (torch.autograd.Function)* - **Description**: By default, all torch.autograd.Function classes will be exported to ORT PythonOp. There are some cases where you might consider disable it. For example, if you confirmed those torch.autograd.Function classes defined computations that could be inline exported by PyTorch, and it is safe to use the inline exported ONNX graph to train, then you can disable it, as a result, ORT has more opportunities to optimize more. ```bash - export ORTMODULE_DISABLE_CUSTOM_AUTOGRAD_SUPPORT=1 + export ORTMODULE_ENABLE_CUSTOM_AUTOGRAD=1 # Enable + export ORTMODULE_ENABLE_CUSTOM_AUTOGRAD=0 # Disable ``` An alternative to disable without using environment variable: @@ -114,39 +115,74 @@ The output directory of the onnx models by default is set to the current working enable_custom_autograd_support(False) ``` -#### ORTMODULE_SKIPPED_AUTOGRAD_FUNCTIONS -- **Feature Area**: *ORTMODULE/PythonOp (torch.autograd.Function)* -- **Description**: By default, this is empty. When user model's setup depends on libraries who might define multiple torch.autograd.Function classes of same name, though their python import paths (e.g. 'namespace') are different, while due to limitation of PyTorch exporter (https://github.com/microsoft/onnx-converters-private/issues/115), ORT backend cannot infer which one to call. So an exception will be thrown for this case. -Before full qualified name can be got from exporter, this environment variables can be used to specify which torch.autograd.Function classes can be ignored. An example as below, be noted, full qualified name is needed here. If there are multiple classes to be ignored, use comma as the separator. - - ```bash - export ORTMODULE_SKIPPED_AUTOGRAD_FUNCTIONS="megatron.fp16.fp16.fused_kernels.GELUFunction" - ``` #### ORTMODULE_ENABLE_COMPUTE_OPTIMIZER - **Feature Area**: *ORTMODULE/Optimizations* - **Description**: By default, this is enabled then some computation can be saved. This env var can be used for disabling the optimization to guarantee exactly same compute with baseline (for example PyTorch, when doing convergence parity -debugging). Disable it with following command: +debugging). ```bash - export ORTMODULE_ENABLE_COMPUTE_OPTIMIZER=0 + export ORTMODULE_ENABLE_COMPUTE_OPTIMIZER=1 # Enable + export ORTMODULE_ENABLE_COMPUTE_OPTIMIZER=0 # Disable ``` - There are fine-grained flags to control different optimizations, but only applied when `ORTMODULE_ENABLE_COMPUTE_OPTIMIZER` is enabled. - - `ORTMODULE_ENABLE_LABEL_SPARSITY_OPT` is used to enable the optimization leveraging label sparsity. +#### ORTMODULE_ENABLE_SPARSE_OPTIMIZER + +- **Feature Area**: *ORTMODULE/Optimizations* +- **Description**: By default, this is enabled. This env var can be used for enabling or disabling the input data sparsity +based performance optimizations, including embedding sparsity and label sparsity. +This optimization is applicable when using optimum, which has an implementation of the ModuleWithLoss class that wraps the HuggingFace Training that allows loss computation inside ONNX Runtime (ORT). +If you're not using optimum but want to implement a similar wrapper in your codebase to compute the loss inside ONNX Runtime (ORT), you can refer to this [Link](ORTModule_ModuleWithLoss_Wrapper.md) for detailed steps and guidelines on how to achieve this. + + ```bash + export ORTMODULE_ENABLE_SPARSE_OPTIMIZER=1 # Enable + export ORTMODULE_ENABLE_SPARSE_OPTIMIZER=0 # Disable + ``` -#### ORTMODULE_ENABLE_INPUT_DENSITY_INSPECTOR +#### ORTMODULE_PRINT_INPUT_DENSITY -- **Feature Area**: *ORTMODULE/Runtime inspector* -- **Description**: By default, this is disabled. This env var can be used for enabling the input data sparsity -inspection. Training users or our dev could leverage this info for improving perf accordingly. Enable it with following -command: +- **Feature Area**: *ORTMODULE/RuntimeInspector* +- **Description**: By default, this is disabled. This env var can be used for printing the input data sparsity +inspection results to standard outputs. ```bash - export ORTMODULE_ENABLE_INPUT_DENSITY_INSPECTOR=1 + export ORTMODULE_PRINT_INPUT_DENSITY=1 # Enable + export ORTMODULE_PRINT_INPUT_DENSITY=0 # Disable + ``` + +#### ORTMODULE_PRINT_MEMORY_STATS + +- **Feature Area**: *ORTMODULE/RuntimeInspector* +- **Description**: By default, this is disabled. This env var can be used for printing the memory inspection results +to standard outputs. + + ```bash + export ORTMODULE_PRINT_MEMORY_STATS=1 # Enable + export ORTMODULE_PRINT_MEMORY_STATS=0 # Disable + ``` + +#### ORTMODULE_ENABLE_EMBEDDING_SPARSE_OPTIMIZER + +- **Feature Area**: *ORTMODULE/Optimizations* +- **Description**: By default, this is disabled. This env var can be used for enabling or disabling the embedding input +data sparsity based performance optimizations. + + ```bash + export ORTMODULE_ENABLE_EMBEDDING_SPARSE_OPTIMIZER=1 # Enable + export ORTMODULE_ENABLE_EMBEDDING_SPARSE_OPTIMIZER=0 # Disable + ``` + +#### ORTMODULE_CACHE_DIR + +- **Feature Area**: *ORTMODULE/RuntimeOptions* +- **Description**: By default, this is disabled. This env vars can be used to cache the exported model for future runs. This optimization is intended to reduce experimentation time by re-using the PyTorch->ONNX exported model architecture when available. + + ```bash + export ORTMODULE_CACHE_DIR="/path/to/cache_dir" # Enable + unset ORTMODULE_CACHE_DIR # Disable ``` ### 2.2 Memory Optimization @@ -234,7 +270,60 @@ Check [FP16_Optimizer implementation](../orttraining/orttraining/python/training ``` -## 6. One More Thing - `LoadBalancingDistributedBatchSampler` + +## 6. Use OpenAI Triton to Compute ONNX Sub-graph + +`ORTModule` provides a way to switch to OpenAI Triton for executing some Ops to further accelerate training. + +### 6.1 Environment Variables + +#### ORTMODULE_USE_TRITON + +- **Feature Area**: *ORTMODULE/TritonOp* +- **Description**: By default, this is disabled. This env var can be used for enabling Triton optimization. + + ```bash + export ORTMODULE_USE_TRITON=1 + ``` + +#### ORTMODULE_ENABLE_TUNING + +- **Feature Area**: *ORTMODULE/TritonOp* +- **Description**: By default, this is disabled. This env var can be used for enabling online Op tuning for those Ops that have multiple implementations on target EP. + + ```bash + export ORTMODULE_ENABLE_TUNING=1 + ``` + +#### ORTMODULE_MAX_TUNING_DURATION_MS + +- **Feature Area**: *ORTMODULE/TritonOp* +- **Description**: When `ORTMODULE_ENABLE_TUNING` is enabled, this env var can be used to set max tuning duration in ms to avoid long tuning time. + + ```bash + export ORTMODULE_MAX_TUNING_DURATION_MS=9999 + ``` + +#### ORTMODULE_TUNING_RESULTS_PATH + +- **Feature Area**: *ORTMODULE/TritonOp* +- **Description**: When `ORTMODULE_ENABLE_TUNING` is enabled, this env var can be used to specify where the online Op tuning results be saved for later use. By default the results will not be saved. When `ORTMODULE_ENABLE_TUNING` is NOT enabled, this env var can be used to specify where Op tuning results can be fetched as offline tuning results. + + ```bash + export ORTMODULE_TUNING_RESULTS_PATH=/tmp/tuning_results + ``` + +#### ORTMODULE_TRITON_DEBUG + +- **Feature Area**: *ORTMODULE/TritonOp* +- **Description**: By default, this is disabled. This env var can be used for enabling Triton debug mode. All original and processed sub-graphs and corresponding generated Triton codes will be saved into a triton_debug folder under working directory. + + ```bash + export ORTMODULE_TRITON_DEBUG=1 + ``` + + +## 7. One More Thing - `LoadBalancingDistributedBatchSampler` `LoadBalancingDistributedBatchSampler` balances the data load across workers based on the sample's complexity. This is useful in scenarios like speech and NLP, where each batch has variable length and distributed training suffers from **straggler problem**. In such scenarios, the complexity function could be defined to return the length of the input sample sequence. The usage is similar to `torch.utils.data.DistributedSampler`, where each process loads a subset of the original dataset that is exclusive to it. diff --git a/docs/ORT_Use_Trtion_Kernel.md b/docs/ORT_Use_Trtion_Kernel.md new file mode 100644 index 0000000000000..6a38606ebf224 --- /dev/null +++ b/docs/ORT_Use_Trtion_Kernel.md @@ -0,0 +1,104 @@ +## Description + +In some scenarios, the Triton written kernels are more performant than CK or other handwritten kernels, so we implement a framework that enables onnxruntime to use these Triton written kernels. + +Here we use `softmax` op as an example to show how to integrate a Triton written kernel into onnxruntime CUDA/ROCm EP. + +### Write and compile Triton kernel + +We have implemented a softmax kernel using Triton at `onnxruntime/core/providers/rocm/math/softmax_triton.py` + +```python +@triton.jit +def softmax_kernel( + output_ptr, input_ptr, input_row_stride, output_row_stride, n_cols, + BLOCK_SIZE: tl.constexpr +): + # softmax implementations + ... + ... +``` + +This is a very simple implementation. The `n_cols` parameter should be smaller than `BLOCK_SIZE`. And `BLOCK_SIZE` MUST be determined at compile time. + +In order to support different input shapes, we compile multiple kernels with different `BLOCK_SIZE`s. + +Each kernel with different `BLOCK_SIZE` generates different `num_warps` and shared memory usage, we call them `metadata`, and these metadata are needed when launching kernels in onnxruntime. + +We develop a script `tools/ci_build/compile_triton.py` to compile kernel and generate metadata for kernel launching. + +To generate metadata for softmax, we need to add description info and implement a `get_function_table` function in `softmax_triton.py`: + +```python +# kernel dtype and BLOCK_SIZE to generate. +dtypes = ['fp32', 'fp16'] +blocks = [1024, 2048, 4096, 8192, 16384] +name_pattern = 'softmax_{}_{}' +sig_pattern = '*{},*{},i32,i32,i32' +group_pattern = 'softmax_{}' + +""" +SHOULD implement a function that returns a metadata list with format: + +function_table = [ + { + 'name': xx, + 'group': yy, + 'func': func, + 'sig': sig, + 'kwargs': kwargs + } +] + +The kwargs is a dict of {string: int} which is used for kernel constants. For example, BLOCK_SIZE of softmax. +""" + +def get_function_table(): + ... +``` + +When compiling onnxruntime with `--use_triton_kernel` flag, this softmax kernel will be compiled and combined into `libonnxruntime_providers_rocm.so` for ROCm or `libonnxruntime_providers_cuda.so` for CUDA. + +### onnxruntime C++ code modification + +To use the Triton kernels in onnxruntime, we need to implement a C++ op that calls these Triton kernels. + +Similar with CK, we implement a function that returns all possible Triton kernels, and the `TunableOp` will select the best one. + +```cpp +template +auto GetSoftmaxTritonOps() { + std::vector>>> ret; + auto group_name = GetSoftmaxTritonGroupName(); + // here use group_name to get all kernel with same group_name + // for example, 'softmax_fp16' represents a group of kernels with different BLOCK_SIZE for float16 softmax + auto *kernel_list = GetOrtTritonKernelByGroup(group_name); + if (kernel_list == nullptr) { + return ret; + } + + for (auto i : *kernel_list) { + // check params match + ... + } + return ret; +} +``` + +### Test + +Using kernel_explorer, we can test this softmax kernel like: + +```bash +export KERNEL_EXPLORER_BUILD_DIR= + +python onnxruntime/python/tools/kernel_explorer/kernels/softmax_test.py +``` + +and the result shows that `TunableOp` selects `softmax_fp16_2048` which is a Triton written kernel and better than others. + +```text +SoftmaxTunable float16 batch_count=1 softmax_elements=2048 is_log_softmax=0 4.27 us, 1.92 GB/s +softmax_fp16_2048 float16 batch_count=1 softmax_elements=2048 is_log_softmax=0 4.48 us, 1.83 GB/s +... +``` diff --git a/docs/OperatorKernels.md b/docs/OperatorKernels.md index cfd15f5cc2935..33c187a28b62e 100644 --- a/docs/OperatorKernels.md +++ b/docs/OperatorKernels.md @@ -36,7 +36,8 @@ Do not modify directly.* |Asinh|*in* input:**T**
*out* output:**T**|9+|**T** = tensor(float)| |Atan|*in* input:**T**
*out* output:**T**|7+|**T** = tensor(float)| |Atanh|*in* input:**T**
*out* output:**T**|9+|**T** = tensor(float)| -|AveragePool|*in* X:**T**
*out* Y:**T**|11+|**T** = tensor(float)| +|AveragePool|*in* X:**T**
*out* Y:**T**|19+|**T** = tensor(float)| +|||[11, 18]|**T** = tensor(float)| |||10|**T** = tensor(float)| |||[7, 9]|**T** = tensor(float)| |BatchNormalization|*in* X:**T**
*in* scale:**T**
*in* B:**T**
*in* input_mean:**U**
*in* input_var:**U**
*out* Y:**T**
*out* running_mean:**U**
*out* running_var:**U**

or

*in* X:**T**
*in* scale:**T**
*in* B:**T**
*in* mean:**T**
*in* var:**T**
*out* Y:**T**
*out* mean:**T**
*out* var:**T**
*out* saved_mean:**T**
*out* saved_var:**T**

or

*in* X:**T**
*in* scale:**T1**
*in* B:**T1**
*in* input_mean:**T2**
*in* input_var:**T2**
*out* Y:**T**
*out* running_mean:**T2**
*out* running_var:**T2**|15+|**T** = tensor(double), tensor(float)
**T1** = tensor(double), tensor(float)
**T2** = tensor(double), tensor(float)| @@ -49,8 +50,9 @@ Do not modify directly.* |BitwiseOr|*in* A:**T**
*in* B:**T**
*out* C:**T**|18+|**T** = tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |BitwiseXor|*in* A:**T**
*in* B:**T**
*out* C:**T**|18+|**T** = tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |BlackmanWindow|*in* size:**T1**
*out* output:**T2**|17+|**T1** = tensor(int32), tensor(int64)
**T2** = tensor(double), tensor(float), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| -|Cast|*in* input:**T1**
*out* output:**T2**|13+|**T1** = 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)
**T2** = 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)| -|||[6, 12]|**T1** = 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)
**T2** = 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)| +|Cast|*in* input:**T1**
*out* output:**T2**|19+|**T1** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(float8e4m3fn), tensor(float8e4m3fnuz), tensor(float8e5m2), tensor(float8e5m2fnuz), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**T2** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(float8e4m3fn), tensor(float8e4m3fnuz), tensor(float8e5m2), tensor(float8e5m2fnuz), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|||[13, 18]|**T1** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(float8e4m3fn), tensor(float8e4m3fnuz), tensor(float8e5m2), tensor(float8e5m2fnuz), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**T2** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(float8e4m3fn), tensor(float8e4m3fnuz), tensor(float8e5m2), tensor(float8e5m2fnuz), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|||[6, 12]|**T1** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(float8e4m3fn), tensor(float8e4m3fnuz), tensor(float8e5m2), tensor(float8e5m2fnuz), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**T2** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(float8e4m3fn), tensor(float8e4m3fnuz), tensor(float8e5m2), tensor(float8e5m2fnuz), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |Ceil|*in* X:**T**
*out* Y:**T**|13+|**T** = tensor(double), tensor(float)| |||[6, 12]|**T** = tensor(double), tensor(float)| |Celu|*in* X:**T**
*out* Y:**T**|12+|**T** = tensor(float)| @@ -80,7 +82,8 @@ Do not modify directly.* |DepthToSpace|*in* input:**T**
*out* output:**T**|13+|**T** = tensor(double), tensor(float)| |||[11, 12]|**T** = tensor(double), tensor(float)| |||[1, 10]|**T** = tensor(double), tensor(float)| -|DequantizeLinear|*in* x:**T**
*in* x_scale:**tensor(float)**
*in* x_zero_point:**T**
*out* y:**tensor(float)**

or

*in* x:**T1**
*in* x_scale:**T2**
*in* x_zero_point:**T1**
*out* y:**T2**|13+|**T** = tensor(int32), tensor(int8), tensor(uint8)| +|DequantizeLinear|*in* x:**T**
*in* x_scale:**tensor(float)**
*in* x_zero_point:**T**
*out* y:**tensor(float)**

or

*in* x:**T1**
*in* x_scale:**T2**
*in* x_zero_point:**T1**
*out* y:**T2**|19+|**T1** = tensor(float8e4m3fn), tensor(float8e4m3fnuz), tensor(float8e5m2), tensor(float8e5m2fnuz), tensor(int32), tensor(int8), tensor(uint8)
**T2** = tensor(float), tensor(float16)| +|||[13, 18]|**T** = tensor(int32), tensor(int8), tensor(uint8)| |||[10, 12]|**T** = tensor(int32), tensor(int8), tensor(uint8)| |Det|*in* X:**T**
*out* Y:**T**|11+|**T** = tensor(float)| |Div|*in* A:**T**
*in* B:**T**
*out* C:**T**|14+|**T** = tensor(double), tensor(float), tensor(int32), tensor(int64)| @@ -94,7 +97,8 @@ Do not modify directly.* |DynamicSlice|*in* data:**T**
*in* starts:**Tind**
*in* ends:**Tind**
*in* axes:**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)| |Einsum|*in* Inputs:**T**
*out* Output:**T**|12+|**T** = tensor(double), tensor(float), tensor(int32), tensor(int64)| |Elu|*in* X:**T**
*out* Y:**T**|6+|**T** = tensor(float)| -|Equal|*in* A:**T**
*in* B:**T**
*out* C:**T1**|13+|**T** = tensor(bool), tensor(double), tensor(float), tensor(int32), tensor(int64)
**T1** = tensor(bool)| +|Equal|*in* A:**T**
*in* B:**T**
*out* C:**T1**|19+|**T** = tensor(bool), tensor(double), tensor(float), tensor(int32), tensor(int64), tensor(string)
**T1** = tensor(bool)| +|||[13, 18]|**T** = tensor(bool), tensor(double), tensor(float), tensor(int32), tensor(int64)
**T1** = tensor(bool)| |||[11, 12]|**T** = tensor(bool), tensor(double), tensor(float), tensor(int32), tensor(int64)
**T1** = tensor(bool)| |||[7, 10]|**T** = tensor(bool), tensor(double), tensor(float), tensor(int32), tensor(int64)
**T1** = tensor(bool)| |Erf|*in* input:**T**
*out* output:**T**|13+|**T** = tensor(float)| @@ -139,11 +143,13 @@ Do not modify directly.* |Hardmax|*in* input:**T**
*out* output:**T**|13+|**T** = tensor(float)| |||[11, 12]|**T** = tensor(float)| |||[1, 10]|**T** = tensor(float)| -|Identity|*in* input:**T**
*out* output:**T**

or

*in* input:**V**
*out* output:**V**|16+|**V** = optional(seq(tensor(bfloat16))), optional(seq(tensor(bool))), optional(seq(tensor(double))), optional(seq(tensor(float))), optional(seq(tensor(float16))), optional(seq(tensor(int16))), optional(seq(tensor(int32))), optional(seq(tensor(int64))), optional(seq(tensor(int8))), optional(seq(tensor(string))), optional(seq(tensor(uint16))), optional(seq(tensor(uint32))), optional(seq(tensor(uint64))), optional(seq(tensor(uint8))), optional(tensor(bfloat16)), optional(tensor(bool)), optional(tensor(double)), optional(tensor(float)), optional(tensor(float16)), optional(tensor(int16)), optional(tensor(int32)), optional(tensor(int64)), optional(tensor(int8)), optional(tensor(string)), optional(tensor(uint16)), optional(tensor(uint32)), optional(tensor(uint64)), optional(tensor(uint8)), seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), 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)| +|Identity|*in* input:**T**
*out* output:**T**

or

*in* input:**V**
*out* output:**V**|19+|**V** = optional(seq(tensor(bfloat16))), optional(seq(tensor(bool))), optional(seq(tensor(double))), optional(seq(tensor(float))), optional(seq(tensor(float16))), optional(seq(tensor(int16))), optional(seq(tensor(int32))), optional(seq(tensor(int64))), optional(seq(tensor(int8))), optional(seq(tensor(string))), optional(seq(tensor(uint16))), optional(seq(tensor(uint32))), optional(seq(tensor(uint64))), optional(seq(tensor(uint8))), optional(tensor(bfloat16)), optional(tensor(bool)), optional(tensor(double)), optional(tensor(float)), optional(tensor(float16)), optional(tensor(int16)), optional(tensor(int32)), optional(tensor(int64)), optional(tensor(int8)), optional(tensor(string)), optional(tensor(uint16)), optional(tensor(uint32)), optional(tensor(uint64)), optional(tensor(uint8)), seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(float8e4m3fn)), seq(tensor(float8e4m3fnuz)), seq(tensor(float8e5m2)), seq(tensor(float8e5m2fnuz)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(float8e4m3fn), tensor(float8e4m3fnuz), tensor(float8e5m2), tensor(float8e5m2fnuz), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|||[16, 18]|**V** = optional(seq(tensor(bfloat16))), optional(seq(tensor(bool))), optional(seq(tensor(double))), optional(seq(tensor(float))), optional(seq(tensor(float16))), optional(seq(tensor(int16))), optional(seq(tensor(int32))), optional(seq(tensor(int64))), optional(seq(tensor(int8))), optional(seq(tensor(string))), optional(seq(tensor(uint16))), optional(seq(tensor(uint32))), optional(seq(tensor(uint64))), optional(seq(tensor(uint8))), optional(tensor(bfloat16)), optional(tensor(bool)), optional(tensor(double)), optional(tensor(float)), optional(tensor(float16)), optional(tensor(int16)), optional(tensor(int32)), optional(tensor(int64)), optional(tensor(int8)), optional(tensor(string)), optional(tensor(uint16)), optional(tensor(uint32)), optional(tensor(uint64)), optional(tensor(uint8)), seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), 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)| |||[14, 15]|**V** = seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), 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)| |||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)| |||[1, 12]|**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)| -|If|*in* cond:**B**
*out* outputs:**V**|16+|**B** = tensor(bool)
**V** = optional(seq(tensor(bfloat16))), optional(seq(tensor(bool))), optional(seq(tensor(double))), optional(seq(tensor(float))), optional(seq(tensor(float16))), optional(seq(tensor(int16))), optional(seq(tensor(int32))), optional(seq(tensor(int64))), optional(seq(tensor(int8))), optional(seq(tensor(string))), optional(seq(tensor(uint16))), optional(seq(tensor(uint32))), optional(seq(tensor(uint64))), optional(seq(tensor(uint8))), optional(tensor(bfloat16)), optional(tensor(bool)), optional(tensor(double)), optional(tensor(float)), optional(tensor(float16)), optional(tensor(int16)), optional(tensor(int32)), optional(tensor(int64)), optional(tensor(int8)), optional(tensor(string)), optional(tensor(uint16)), optional(tensor(uint32)), optional(tensor(uint64)), optional(tensor(uint8)), seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), 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)| +|If|*in* cond:**B**
*out* outputs:**V**|19+|**B** = tensor(bool)
**V** = optional(seq(tensor(bfloat16))), optional(seq(tensor(bool))), optional(seq(tensor(double))), optional(seq(tensor(float))), optional(seq(tensor(float16))), optional(seq(tensor(int16))), optional(seq(tensor(int32))), optional(seq(tensor(int64))), optional(seq(tensor(int8))), optional(seq(tensor(string))), optional(seq(tensor(uint16))), optional(seq(tensor(uint32))), optional(seq(tensor(uint64))), optional(seq(tensor(uint8))), optional(tensor(bfloat16)), optional(tensor(bool)), optional(tensor(double)), optional(tensor(float)), optional(tensor(float16)), optional(tensor(int16)), optional(tensor(int32)), optional(tensor(int64)), optional(tensor(int8)), optional(tensor(string)), optional(tensor(uint16)), optional(tensor(uint32)), optional(tensor(uint64)), optional(tensor(uint8)), seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(float8e4m3fn)), seq(tensor(float8e4m3fnuz)), seq(tensor(float8e5m2)), seq(tensor(float8e5m2fnuz)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(float8e4m3fn), tensor(float8e4m3fnuz), tensor(float8e5m2), tensor(float8e5m2fnuz), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|||[16, 18]|**B** = tensor(bool)
**V** = optional(seq(tensor(bfloat16))), optional(seq(tensor(bool))), optional(seq(tensor(double))), optional(seq(tensor(float))), optional(seq(tensor(float16))), optional(seq(tensor(int16))), optional(seq(tensor(int32))), optional(seq(tensor(int64))), optional(seq(tensor(int8))), optional(seq(tensor(string))), optional(seq(tensor(uint16))), optional(seq(tensor(uint32))), optional(seq(tensor(uint64))), optional(seq(tensor(uint8))), optional(tensor(bfloat16)), optional(tensor(bool)), optional(tensor(double)), optional(tensor(float)), optional(tensor(float16)), optional(tensor(int16)), optional(tensor(int32)), optional(tensor(int64)), optional(tensor(int8)), optional(tensor(string)), optional(tensor(uint16)), optional(tensor(uint32)), optional(tensor(uint64)), optional(tensor(uint8)), seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), 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)| |||[13, 15]|**B** = tensor(bool)
**V** = seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), 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)| |||[11, 12]|**B** = tensor(bool)
**V** = 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)| |||[1, 10]|**B** = tensor(bool)
**V** = 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)| @@ -170,7 +176,8 @@ Do not modify directly.* |LogSoftmax|*in* input:**T**
*out* output:**T**|13+|**T** = tensor(double), tensor(float)| |||[11, 12]|**T** = tensor(double), tensor(float)| |||[1, 10]|**T** = tensor(double), tensor(float)| -|Loop|*in* M:**I**
*in* cond:**B**
*in* v_initial:**V**
*out* v_final_and_scan_outputs:**V**|16+|**B** = tensor(bool)
**I** = tensor(int64)
**V** = optional(seq(tensor(bfloat16))), optional(seq(tensor(bool))), optional(seq(tensor(double))), optional(seq(tensor(float))), optional(seq(tensor(float16))), optional(seq(tensor(int16))), optional(seq(tensor(int32))), optional(seq(tensor(int64))), optional(seq(tensor(int8))), optional(seq(tensor(string))), optional(seq(tensor(uint16))), optional(seq(tensor(uint32))), optional(seq(tensor(uint64))), optional(seq(tensor(uint8))), optional(tensor(bfloat16)), optional(tensor(bool)), optional(tensor(double)), optional(tensor(float)), optional(tensor(float16)), optional(tensor(int16)), optional(tensor(int32)), optional(tensor(int64)), optional(tensor(int8)), optional(tensor(string)), optional(tensor(uint16)), optional(tensor(uint32)), optional(tensor(uint64)), optional(tensor(uint8)), seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), 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)| +|Loop|*in* M:**I**
*in* cond:**B**
*in* v_initial:**V**
*out* v_final_and_scan_outputs:**V**|19+|**B** = tensor(bool)
**I** = tensor(int64)
**V** = optional(seq(tensor(bfloat16))), optional(seq(tensor(bool))), optional(seq(tensor(double))), optional(seq(tensor(float))), optional(seq(tensor(float16))), optional(seq(tensor(int16))), optional(seq(tensor(int32))), optional(seq(tensor(int64))), optional(seq(tensor(int8))), optional(seq(tensor(string))), optional(seq(tensor(uint16))), optional(seq(tensor(uint32))), optional(seq(tensor(uint64))), optional(seq(tensor(uint8))), optional(tensor(bfloat16)), optional(tensor(bool)), optional(tensor(double)), optional(tensor(float)), optional(tensor(float16)), optional(tensor(int16)), optional(tensor(int32)), optional(tensor(int64)), optional(tensor(int8)), optional(tensor(string)), optional(tensor(uint16)), optional(tensor(uint32)), optional(tensor(uint64)), optional(tensor(uint8)), seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(float8e4m3fn)), seq(tensor(float8e4m3fnuz)), seq(tensor(float8e5m2)), seq(tensor(float8e5m2fnuz)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(float8e4m3fn), tensor(float8e4m3fnuz), tensor(float8e5m2), tensor(float8e5m2fnuz), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|||[16, 18]|**B** = tensor(bool)
**I** = tensor(int64)
**V** = optional(seq(tensor(bfloat16))), optional(seq(tensor(bool))), optional(seq(tensor(double))), optional(seq(tensor(float))), optional(seq(tensor(float16))), optional(seq(tensor(int16))), optional(seq(tensor(int32))), optional(seq(tensor(int64))), optional(seq(tensor(int8))), optional(seq(tensor(string))), optional(seq(tensor(uint16))), optional(seq(tensor(uint32))), optional(seq(tensor(uint64))), optional(seq(tensor(uint8))), optional(tensor(bfloat16)), optional(tensor(bool)), optional(tensor(double)), optional(tensor(float)), optional(tensor(float16)), optional(tensor(int16)), optional(tensor(int32)), optional(tensor(int64)), optional(tensor(int8)), optional(tensor(string)), optional(tensor(uint16)), optional(tensor(uint32)), optional(tensor(uint64)), optional(tensor(uint8)), seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), 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)| |||[13, 15]|**B** = tensor(bool)
**I** = tensor(int64)
**V** = seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), 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)| |||[11, 12]|**B** = tensor(bool)
**I** = tensor(int64)
**V** = 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)| |||[1, 10]|**B** = tensor(bool)
**I** = tensor(int64)
**V** = 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)| @@ -225,7 +232,8 @@ Do not modify directly.* |PRelu|*in* X:**T**
*in* slope:**T**
*out* Y:**T**|16+|**T** = tensor(float)| |||[9, 15]|**T** = tensor(float)| |||[7, 8]|**T** = tensor(float)| -|Pad|*in* data:**T**
*in* pads:**tensor(int64)**
*in* constant_value:**T**
*in* axes:**Tind**
*out* output:**T**

or

*in* data:**T**
*in* pads:**tensor(int64)**
*in* constant_value:**T**
*out* output:**T**

or

*in* data:**T**
*out* output:**T**|18+|**T** = tensor(bool), tensor(double), tensor(float), tensor(int32), tensor(int64), tensor(int8), tensor(uint32), tensor(uint64), tensor(uint8)| +|Pad|*in* data:**T**
*in* pads:**tensor(int64)**
*in* constant_value:**T**
*in* axes:**Tind**
*out* output:**T**

or

*in* data:**T**
*in* pads:**tensor(int64)**
*in* constant_value:**T**
*out* output:**T**

or

*in* data:**T**
*out* output:**T**|19+|**T** = tensor(bool), tensor(double), tensor(float), tensor(int32), tensor(int64), tensor(int8), tensor(uint32), tensor(uint64), tensor(uint8)| +|||18|**T** = tensor(bool), tensor(double), tensor(float), tensor(int32), tensor(int64), tensor(int8), tensor(uint32), tensor(uint64), tensor(uint8)| |||[13, 17]|**T** = tensor(bool), tensor(double), tensor(float), tensor(int32), tensor(int64), tensor(int8), tensor(uint32), tensor(uint64), tensor(uint8)| |||[11, 12]|**T** = tensor(double), tensor(float), tensor(int32), tensor(int64), tensor(int8), tensor(uint32), tensor(uint64), tensor(uint8)| |||[2, 10]|**T** = tensor(double), tensor(float)| @@ -236,7 +244,8 @@ Do not modify directly.* |||[7, 11]|**T** = tensor(double), tensor(float)| |QLinearConv|*in* x:**T1**
*in* x_scale:**tensor(float)**
*in* x_zero_point:**T1**
*in* w:**T2**
*in* w_scale:**tensor(float)**
*in* w_zero_point:**T2**
*in* y_scale:**tensor(float)**
*in* y_zero_point:**T3**
*in* B:**T4**
*out* y:**T3**|10+|**T1** = tensor(int8), tensor(uint8)
**T2** = tensor(int8), tensor(uint8)
**T3** = tensor(int8), tensor(uint8)
**T4** = tensor(int32)| |QLinearMatMul|*in* a:**T1**
*in* a_scale:**tensor(float)**
*in* a_zero_point:**T1**
*in* b:**T2**
*in* b_scale:**tensor(float)**
*in* b_zero_point:**T2**
*in* y_scale:**tensor(float)**
*in* y_zero_point:**T3**
*out* y:**T3**|10+|**T1** = tensor(int8), tensor(uint8)
**T2** = tensor(int8), tensor(uint8)
**T3** = tensor(int8), tensor(uint8)| -|QuantizeLinear|*in* x:**T1**
*in* y_scale:**T1**
*in* y_zero_point:**T2**
*out* y:**T2**

or

*in* x:**T1**
*in* y_scale:**tensor(float)**
*in* y_zero_point:**T2**
*out* y:**T2**|13+|**T1** = tensor(float)
**T2** = tensor(int8), tensor(uint8)| +|QuantizeLinear|*in* x:**T1**
*in* y_scale:**T1**
*in* y_zero_point:**T2**
*out* y:**T2**

or

*in* x:**T1**
*in* y_scale:**tensor(float)**
*in* y_zero_point:**T2**
*out* y:**T2**|19+|**T1** = tensor(float), tensor(float16)
**T2** = tensor(float8e4m3fn), tensor(float8e4m3fnuz), tensor(float8e5m2), tensor(float8e5m2fnuz), tensor(int8), tensor(uint8)| +|||[13, 18]|**T1** = tensor(float)
**T2** = tensor(int8), tensor(uint8)| |||[10, 12]|**T1** = tensor(float)
**T2** = tensor(int8), tensor(uint8)| |RNN|*in* X:**T**
*in* W:**T**
*in* R:**T**
*in* B:**T**
*in* sequence_lens:**T1**
*in* initial_h:**T**
*out* Y:**T**
*out* Y_h:**T**|14+|**T** = tensor(float)
**T1** = tensor(int32)| |||[7, 13]|**T** = tensor(float)
**T1** = tensor(int32)| @@ -291,11 +300,13 @@ Do not modify directly.* |Relu|*in* X:**T**
*out* Y:**T**|14+|**T** = tensor(double), tensor(float), tensor(int32), tensor(int8)| |||13|**T** = tensor(double), tensor(float)| |||[6, 12]|**T** = tensor(double), tensor(float)| -|Reshape|*in* data:**T**
*in* shape:**tensor(int64)**
*out* reshaped:**T**

or

*in* data:**T**
*out* reshaped:**T**|14+|**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)
**shape** = tensor(int64)| +|Reshape|*in* data:**T**
*in* shape:**tensor(int64)**
*out* reshaped:**T**

or

*in* data:**T**
*out* reshaped:**T**|19+|**T** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(float8e4m3fn), tensor(float8e4m3fnuz), tensor(float8e5m2), tensor(float8e5m2fnuz), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**shape** = tensor(int64)| +|||[14, 18]|**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)
**shape** = tensor(int64)| |||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)
**shape** = tensor(int64)| |||[5, 12]|**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)
**shape** = tensor(int64)| |||[1, 4]|**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)| -|Resize|*in* X:**T**
*in* scales:**tensor(float)**
*out* Y:**T**

or

*in* X:**T1**
*in* roi:**T2**
*in* scales:**tensor(float)**
*in* sizes:**tensor(int64)**
*out* Y:**T1**|18+|**T1** = tensor(float), tensor(int32), tensor(int8), tensor(uint8)| +|Resize|*in* X:**T**
*in* scales:**tensor(float)**
*out* Y:**T**

or

*in* X:**T1**
*in* roi:**T2**
*in* scales:**tensor(float)**
*in* sizes:**tensor(int64)**
*out* Y:**T1**|19+|**T1** = tensor(float), tensor(int32), tensor(int8), tensor(uint8)| +|||18|**T1** = tensor(float), tensor(int32), tensor(int8), tensor(uint8)| |||[13, 17]|**T1** = tensor(float), tensor(int32), tensor(int8), tensor(uint8)| |||[11, 12]|**T1** = tensor(float), tensor(int32), tensor(int8), tensor(uint8)| |||10|**T** = tensor(float), tensor(int32), tensor(int8), tensor(uint8)| @@ -306,7 +317,8 @@ Do not modify directly.* |STFT|*in* signal:**T1**
*in* frame_step:**T2**
*in* window:**T1**
*in* frame_length:**T2**
*out* output:**T1**|17+|**T1** = tensor(double), tensor(float)
**T2** = tensor(int32), tensor(int64)| |Scale|*in* input:**T**
*out* output:**T**|1+|**T** = tensor(float)| |ScaledTanh|*in* input:**T**
*out* output:**T**|1+|**T** = tensor(float)| -|Scan|*in* initial_state_and_scan_inputs:**V**
*out* final_state_and_scan_outputs:**V**

or

*in* sequence_lens:**I**
*in* initial_state_and_scan_inputs:**V**
*out* final_state_and_scan_outputs:**V**|16+|**V** = 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)| +|Scan|*in* initial_state_and_scan_inputs:**V**
*out* final_state_and_scan_outputs:**V**

or

*in* sequence_lens:**I**
*in* initial_state_and_scan_inputs:**V**
*out* final_state_and_scan_outputs:**V**|19+|**V** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(float8e4m3fn), tensor(float8e4m3fnuz), tensor(float8e5m2), tensor(float8e5m2fnuz), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|||[16, 18]|**V** = 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)| |||[11, 15]|**V** = 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)| |||[9, 10]|**V** = 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)| |||8|**I** = tensor(int64)
**V** = 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)| @@ -326,7 +338,8 @@ Do not modify directly.* |SequenceErase|*in* input_sequence:**S**
*in* position:**I**
*out* output_sequence:**S**|11+|**I** = tensor(int32), tensor(int64)
**S** = seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8))| |SequenceInsert|*in* input_sequence:**S**
*in* tensor:**T**
*in* position:**I**
*out* output_sequence:**S**|11+|**I** = tensor(int32), tensor(int64)
**S** = seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8))| |SequenceLength|*in* input_sequence:**S**
*out* length:**I**|11+|**I** = tensor(int64)
**S** = seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8))| -|Shape|*in* data:**T**
*out* shape:**T1**|15+|**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)| +|Shape|*in* data:**T**
*out* shape:**T1**|19+|**T** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(float8e4m3fn), tensor(float8e4m3fnuz), tensor(float8e5m2), tensor(float8e5m2fnuz), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**T1** = tensor(int64)| +|||[15, 18]|**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)| |||[13, 14]|**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)| |||[1, 12]|**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)| |Shrink|*in* input:**T**
*out* output:**T**|9+|**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)| @@ -337,7 +350,8 @@ Do not modify directly.* |SimplifiedLayerNormalization|*in* X:**T**
*in* scale:**V**
*out* Y:**V**
*out* inv_std_var:**U**|1+|**T** = tensor(double), tensor(float)
**U** = tensor(double), tensor(float)
**V** = tensor(double), tensor(float)| |Sin|*in* input:**T**
*out* output:**T**|7+|**T** = tensor(double), tensor(float)| |Sinh|*in* input:**T**
*out* output:**T**|9+|**T** = tensor(float)| -|Size|*in* data:**T**
*out* size:**T1**|13+|**T** = tensor(bool), tensor(double), tensor(float), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**T1** = tensor(int64)| +|Size|*in* data:**T**
*out* size:**T1**|19+|**T** = tensor(bool), tensor(double), tensor(float), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**T1** = tensor(int64)| +|||[13, 18]|**T** = tensor(bool), tensor(double), tensor(float), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**T1** = tensor(int64)| |||[1, 12]|**T** = tensor(bool), tensor(double), tensor(float), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**T1** = tensor(int64)| |Slice|*in* data:**T**
*in* starts:**Tind**
*in* ends:**Tind**
*in* axes:**Tind**
*in* steps:**Tind**
*out* output:**T**

or

*in* data:**T**
*out* output:**T**|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)
**Tind** = tensor(int32), tensor(int64)| |||[11, 12]|**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)| @@ -381,7 +395,7 @@ Do not modify directly.* |Transpose|*in* data:**T**
*out* transposed:**T**|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)| |||[1, 12]|**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)| |Trilu|*in* input:**T**
*in* k:**tensor(int64)**
*out* output:**T**|14+|**T** = tensor(double), tensor(float), tensor(int64)| -|Unique|*in* X:**T**
*out* Y:**T**
*out* indices:**tensor(int64)**
*out* inverse_indices:**tensor(int64)**
*out* counts:**tensor(int64)**|11+|**T** = tensor(float), tensor(int64), tensor(int8), tensor(string)| +|Unique|*in* X:**T**
*out* Y:**T**
*out* indices:**tensor(int64)**
*out* inverse_indices:**tensor(int64)**
*out* counts:**tensor(int64)**|11+|**T** = tensor(double), tensor(float), tensor(int64), tensor(int8), tensor(string)| |Unsqueeze|*in* data:**T**
*in* axes:**tensor(int64)**
*out* expanded:**T**

or

*in* data:**T**
*out* expanded:**T**|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)| |||[11, 12]|**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)| |||[1, 10]|**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)| @@ -419,13 +433,13 @@ Do not modify directly.* |**Operator Domain:** *com.microsoft*|||| |Attention|*in* input:**T**
*in* weights:**T**
*in* bias:**T**
*in* mask_index:**M**
*in* past:**T**
*in* relative_position_bias:**T**
*in* past_sequence_length:**M**
*out* output:**T**
*out* present:**T**|1+|**T** = tensor(float)| |AttnLSTM|*in* X:**T**
*in* W:**T**
*in* R:**T**
*in* B:**T**
*in* sequence_lens:**T1**
*in* initial_h:**T**
*in* initial_c:**T**
*in* P:**T**
*in* QW:**T**
*in* MW:**T**
*in* V:**T**
*in* M:**T**
*in* memory_seq_lens:**T1**
*in* AW:**T**
*out* Y:**T**
*out* Y_h:**T**
*out* Y_c:**T**|1+|**T** = tensor(double), tensor(float)
**T1** = tensor(int32)| -|BeamSearch|*in* input_ids:**F**
*in* max_length:**I**
*in* min_length:**I**
*in* num_beams:**I**
*in* num_return_sequences:**I**
*in* length_penalty:**T**
*in* repetition_penalty:**T**
*in* vocab_mask:**M**
*in* prefix_vocab_mask:**M**
*in* attention_mask:**I**
*out* sequences:**I**
*out* sequences_scores:**T**
*out* scores:**T**|1+|**T** = tensor(float)| +|BeamSearch|*in* input_ids:**F**
*in* max_length:**I**
*in* min_length:**I**
*in* num_beams:**I**
*in* num_return_sequences:**I**
*in* length_penalty:**T**
*in* repetition_penalty:**T**
*in* vocab_mask:**M**
*in* prefix_vocab_mask:**M**
*in* attention_mask:**I**
*in* decoder_input_ids:**I**
*in* logits_processor:**I**
*out* sequences:**I**
*out* sequences_scores:**T**
*out* scores:**T**|1+|**T** = tensor(float)| |BiasGelu|*in* A:**T**
*in* B:**T**
*out* C:**T**|1+|**T** = tensor(float)| |BifurcationDetector|*in* src_tokens:**T**
*in* cur_tokens:**T**
*in* prev_suffix_match_idx:**T**
*in* pred_tokens:**T**
*out* tokens:**T**
*out* suffix_match_idx:**T**|1+|**T** = tensor(int64)| |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)| -|DequantizeLinear|*in* x:**T1**
*in* x_scale:**T2**
*in* x_zero_point:**T1**
*out* y:**T2**|1+|**T1** = tensor(int8), tensor(uint8)
**T2** = 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(int8), tensor(uint16), 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)| |EmbedLayerNormalization|*in* input_ids:**T1**
*in* segment_ids:**T1**
*in* word_embedding:**T**
*in* position_embedding:**T**
*in* segment_embedding:**T**
*in* gamma:**T**
*in* beta:**T**
*in* mask:**T1**
*in* position_ids:**T1**
*out* output:**T**
*out* mask_index:**T1**
*out* embedding_sum:**T**|1+|**T** = tensor(float)| @@ -439,6 +453,7 @@ 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)| |GridSample|*in* X:**T1**
*in* Grid:**T1**
*out* Y:**T2**|1+|**T1** = tensor(float)
**T2** = tensor(float)| |Inverse|*in* X:**T**
*out* Y:**T**|1+|**T** = tensor(double), tensor(float), tensor(float16)| +|MatMulFpQ4|*in* A:**T1**
*in* B:**T2**
*in* B_shape:**T3**
*out* Y:**T1**|1+|**T1** = tensor(float)
**T2** = tensor(uint8)
**T3** = tensor(int64)| |MatMulInteger16|*in* A:**T1**
*in* B:**T2**
*out* Y:**T3**|1+|**T1** = tensor(int16)
**T2** = tensor(int16)
**T3** = tensor(int32)| |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)| |MaxpoolWithMask|*in* X:**T**
*in* M:**tensor(int32)**
*out* Y:**T**|1+|**T** = tensor(float)| @@ -457,7 +472,7 @@ Do not modify directly.* |QLinearSigmoid|*in* X:**T**
*in* X_scale:**tensor(float)**
*in* X_zero_point:**T**
*in* Y_scale:**tensor(float)**
*in* Y_zero_point:**T**
*out* Y:**T**|1+|**T** = tensor(int8), tensor(uint8)| |QLinearSoftmax|*in* X:**T**
*in* X_scale:**tensor(float)**
*in* x_zero_point:**T**
*in* y_scale:**tensor(float)**
*in* y_zero_point:**T**
*out* Y:**T**|1+|**T** = tensor(int8), tensor(uint8)| |QLinearWhere|*in* condition:**B**
*in* X:**T**
*in* x_scale:**TF**
*in* x_zero_point:**T**
*in* Y:**T**
*in* y_scale:**TF**
*in* y_zero_point:**T**
*in* z_scale:**TF**
*in* z_zero_point:**T**
*out* Z:**T**|1+|**T** = tensor(int8), tensor(uint8)| -|QuantizeLinear|*in* x:**T1**
*in* y_scale:**T1**
*in* y_zero_point:**T2**
*out* y:**T2**|1+|**T1** = tensor(float)
**T2** = tensor(int8), tensor(uint8)| +|QuantizeLinear|*in* x:**T1**
*in* y_scale:**T1**
*in* y_zero_point:**T2**
*out* y:**T2**|1+|**T1** = tensor(float)
**T2** = tensor(int16), tensor(int8), tensor(uint16), tensor(uint8)| |QuickGelu|*in* X:**T**
*out* Y:**T**|1+|**T** = tensor(float)| |Range|*in* start:**T**
*in* limit:**T**
*in* delta:**T**
*out* Y:**T**|1+|**T** = tensor(double), tensor(float), tensor(int16), tensor(int32), tensor(int64)| |SampleOp|*in* X:**T**
*out* Y:**T**|1+|**T** = tensor(float)| @@ -509,9 +524,10 @@ Do not modify directly.* |||14|**T** = tensor(double), tensor(float), tensor(float16)
**U** = tensor(double), tensor(float), tensor(float16)| |||[9, 13]|**T** = tensor(double), tensor(float), tensor(float16)| |||[7, 8]|**T** = tensor(double), tensor(float), tensor(float16)| -|Cast|*in* input:**T1**
*out* output:**T2**|13+|**T1** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**T2** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| -|||[9, 12]|**T1** = tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**T2** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| -|||[6, 8]|**T1** = tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**T2** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|Cast|*in* input:**T1**
*out* output:**T2**|19+|**T1** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(float8e4m3fn), tensor(float8e5m2), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**T2** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(float8e4m3fn), tensor(float8e5m2), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|||[13, 18]|**T1** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**T2** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(float8e4m3fn), tensor(float8e5m2), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|||[9, 12]|**T1** = tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**T2** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(float8e4m3fn), tensor(float8e5m2), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|||[6, 8]|**T1** = tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**T2** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(float8e4m3fn), tensor(float8e5m2), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |Ceil|*in* X:**T**
*out* Y:**T**|13+|**T** = tensor(double), tensor(float), tensor(float16)| |||[6, 12]|**T** = tensor(double), tensor(float), tensor(float16)| |Clip|*in* input:**T**
*in* min:**T**
*in* max:**T**
*out* output:**T**

or

*in* input:**T**
*out* output:**T**|13+|**T** = tensor(double), tensor(float), tensor(float16), tensor(int64), tensor(int8), tensor(uint64), tensor(uint8)| @@ -536,7 +552,9 @@ Do not modify directly.* |DepthToSpace|*in* input:**T**
*out* output:**T**|13+|**T** = tensor(double), tensor(float), tensor(float16)| |||[11, 12]|**T** = tensor(double), tensor(float), tensor(float16)| |||[1, 10]|**T** = tensor(double), tensor(float), tensor(float16)| -|DequantizeLinear|*in* x:**T**
*in* x_scale:**tensor(float)**
*in* x_zero_point:**T**
*out* y:**tensor(float)**

or

*in* x:**T1**
*in* x_scale:**T2**
*in* x_zero_point:**T1**
*out* y:**T2**|10+|**T** = tensor(int8), tensor(uint8)| +|DequantizeLinear|*in* x:**T**
*in* x_scale:**tensor(float)**
*in* x_zero_point:**T**
*out* y:**tensor(float)**

or

*in* x:**T1**
*in* x_scale:**T2**
*in* x_zero_point:**T1**
*out* y:**T2**|19+|**T1** = tensor(float8e4m3fn), tensor(float8e5m2), tensor(int8), tensor(uint8)
**T2** = tensor(float), tensor(float16)| +|||[13, 18]|**T** = tensor(int8), tensor(uint8)| +|||[10, 12]|**T** = tensor(int8), tensor(uint8)| |Div|*in* A:**T**
*in* B:**T**
*out* C:**T**|14+|**T** = tensor(bfloat16), tensor(double), tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| |||13|**T** = tensor(bfloat16), tensor(double), tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| |||[7, 12]|**T** = tensor(double), tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| @@ -585,10 +603,12 @@ Do not modify directly.* |GreaterOrEqual|*in* A:**T**
*in* B:**T**
*out* C:**T1**|16+|**T** = tensor(double), tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)
**T1** = tensor(bool)| |||[12, 15]|**T** = tensor(double), tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)
**T1** = tensor(bool)| |HardSigmoid|*in* X:**T**
*out* Y:**T**|6+|**T** = tensor(double), tensor(float), tensor(float16)| -|Identity|*in* input:**T**
*out* output:**T**

or

*in* input:**V**
*out* output:**V**|14+|**V** = seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|Identity|*in* input:**T**
*out* output:**T**

or

*in* input:**V**
*out* output:**V**|19+|**V** = seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(float8e4m3fn)), seq(tensor(float8e4m3fnuz)), seq(tensor(float8e5m2)), seq(tensor(float8e5m2fnuz)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(float8e4m3fn), tensor(float8e4m3fnuz), tensor(float8e5m2), tensor(float8e5m2fnuz), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|||[14, 18]|**V** = seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), tensor(bfloat16), tensor(bool), 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(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |||[1, 12]|**T** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| -|If|*in* cond:**B**
*out* outputs:**V**|13+|**B** = tensor(bool)
**V** = seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), 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)| +|If|*in* cond:**B**
*out* outputs:**V**|19+|**B** = tensor(bool)
**V** = seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(float8e4m3fn)), seq(tensor(float8e4m3fnuz)), seq(tensor(float8e5m2)), seq(tensor(float8e5m2fnuz)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(float8e4m3fn), tensor(float8e4m3fnuz), tensor(float8e5m2), tensor(float8e5m2fnuz), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|||[13, 18]|**B** = tensor(bool)
**V** = seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), 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)| |||[11, 12]|**B** = tensor(bool)
**V** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |||[1, 10]|**B** = tensor(bool)
**V** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |ImageScaler|*in* input:**T**
*out* output:**T**|1+|**T** = tensor(double), tensor(float), tensor(float16)| @@ -611,7 +631,8 @@ Do not modify directly.* |LogSoftmax|*in* input:**T**
*out* output:**T**|13+|**T** = tensor(double), tensor(float), tensor(float16)| |||[11, 12]|**T** = tensor(double), tensor(float), tensor(float16)| |||[1, 10]|**T** = tensor(double), tensor(float), tensor(float16)| -|Loop|*in* M:**I**
*in* cond:**B**
*in* v_initial:**V**
*out* v_final_and_scan_outputs:**V**|13+|**B** = tensor(bool)
**I** = tensor(int64)
**V** = seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), 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)| +|Loop|*in* M:**I**
*in* cond:**B**
*in* v_initial:**V**
*out* v_final_and_scan_outputs:**V**|19+|**B** = tensor(bool)
**I** = tensor(int64)
**V** = seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(float8e4m3fn)), seq(tensor(float8e4m3fnuz)), seq(tensor(float8e5m2)), seq(tensor(float8e5m2fnuz)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(float8e4m3fn), tensor(float8e4m3fnuz), tensor(float8e5m2), tensor(float8e5m2fnuz), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|||[13, 18]|**B** = tensor(bool)
**I** = tensor(int64)
**V** = seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), 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)| |||[11, 12]|**B** = tensor(bool)
**I** = tensor(int64)
**V** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |||[1, 10]|**B** = tensor(bool)
**I** = tensor(int64)
**V** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |MatMul|*in* A:**T**
*in* B:**T**
*out* Y:**T**|13+|**T** = tensor(bfloat16), tensor(double), tensor(float), tensor(float16)| @@ -626,8 +647,8 @@ Do not modify directly.* |||10|**I** = tensor(int64)
**T** = tensor(double), tensor(float), tensor(float16)| |||[8, 9]|**I** = tensor(int64)
**T** = tensor(double), tensor(float), tensor(float16)| |||[1, 7]|**T** = tensor(double), tensor(float), tensor(float16)| -|MemcpyFromHost|*in* X:**T**
*out* Y:**T**|1+|**T** = seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| -|MemcpyToHost|*in* X:**T**
*out* Y:**T**|1+|**T** = seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|MemcpyFromHost|*in* X:**T**
*out* Y:**T**|1+|**T** = seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(float8e4m3fn)), seq(tensor(float8e4m3fnuz)), seq(tensor(float8e5m2)), seq(tensor(float8e5m2fnuz)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(float8e4m3fn), tensor(float8e4m3fnuz), tensor(float8e5m2), tensor(float8e5m2fnuz), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|MemcpyToHost|*in* X:**T**
*out* Y:**T**|1+|**T** = seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(float8e4m3fn)), seq(tensor(float8e4m3fnuz)), seq(tensor(float8e5m2)), seq(tensor(float8e5m2fnuz)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(float8e4m3fn), tensor(float8e4m3fnuz), tensor(float8e5m2), tensor(float8e5m2fnuz), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |Min|*in* data_0:**T**
*out* min:**T**|13+|**T** = tensor(bfloat16), tensor(double), tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| |||12|**T** = tensor(bfloat16), tensor(double), tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| |||[6, 11]|**T** = tensor(bfloat16), tensor(double), tensor(float), tensor(float16)| @@ -654,7 +675,9 @@ Do not modify directly.* |||[13, 14]|**T** = tensor(double), tensor(float), tensor(float16), tensor(int32), tensor(int64)
**T1** = tensor(double), tensor(float), tensor(float16), tensor(int32), tensor(int64)| |||12|**T** = tensor(double), tensor(float), tensor(float16), tensor(int32), tensor(int64)
**T1** = tensor(double), tensor(float), tensor(float16), tensor(int32), tensor(int64)| |||[7, 11]|**T** = tensor(double), tensor(float), tensor(float16)| -|QuantizeLinear|*in* x:**T1**
*in* y_scale:**T1**
*in* y_zero_point:**T2**
*out* y:**T2**

or

*in* x:**T1**
*in* y_scale:**tensor(float)**
*in* y_zero_point:**T2**
*out* y:**T2**|10+|**T1** = tensor(float)
**T2** = tensor(int8), tensor(uint8)| +|QuantizeLinear|*in* x:**T1**
*in* y_scale:**T1**
*in* y_zero_point:**T2**
*out* y:**T2**

or

*in* x:**T1**
*in* y_scale:**tensor(float)**
*in* y_zero_point:**T2**
*out* y:**T2**|19+|**T1** = tensor(float), tensor(float16)
**T2** = tensor(float8e4m3fn), tensor(float8e5m2), tensor(int8), tensor(uint8)| +|||[13, 18]|**T1** = tensor(float)
**T2** = tensor(int8), tensor(uint8)| +|||[10, 12]|**T1** = tensor(float)
**T2** = tensor(int8), tensor(uint8)| |RNN|*in* X:**T**
*in* W:**T**
*in* R:**T**
*in* B:**T**
*in* sequence_lens:**T1**
*in* initial_h:**T**
*out* Y:**T**
*out* Y_h:**T**|14+|**T** = tensor(double), tensor(float), tensor(float16)
**T1** = tensor(int32)| |||[7, 13]|**T** = tensor(double), tensor(float), tensor(float16)
**T1** = tensor(int32)| |RandomNormal|*out* output:**T**|1+|**T** = tensor(double), tensor(float), tensor(float16)| @@ -700,7 +723,8 @@ Do not modify directly.* |Relu|*in* X:**T**
*out* Y:**T**|14+|**T** = tensor(bfloat16), tensor(double), tensor(float), tensor(float16)| |||13|**T** = tensor(bfloat16), tensor(double), tensor(float), tensor(float16)| |||[6, 12]|**T** = tensor(double), tensor(float), tensor(float16)| -|Reshape|*in* data:**T**
*in* shape:**tensor(int64)**
*out* reshaped:**T**

or

*in* data:**T**
*out* reshaped:**T**|14+|**T** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**shape** = tensor(int64)| +|Reshape|*in* data:**T**
*in* shape:**tensor(int64)**
*out* reshaped:**T**

or

*in* data:**T**
*out* reshaped:**T**|19+|**T** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(float8e4m3fn), tensor(float8e4m3fnuz), tensor(float8e5m2), tensor(float8e5m2fnuz), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**shape** = tensor(int64)| +|||[14, 18]|**T** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**shape** = tensor(int64)| |||13|**T** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**shape** = tensor(int64)| |||[5, 12]|**T** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**shape** = tensor(int64)| |||[1, 4]|**T** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| @@ -711,7 +735,8 @@ Do not modify directly.* |RoiAlign|*in* X:**T1**
*in* rois:**T1**
*in* batch_indices:**T2**
*out* Y:**T1**|10+|**T1** = tensor(double), tensor(float)
**T2** = tensor(int64)| |Round|*in* X:**T**
*out* Y:**T**|11+|**T** = tensor(double), tensor(float), tensor(float16)| |ScaledTanh|*in* input:**T**
*out* output:**T**|1+|**T** = tensor(double), tensor(float), tensor(float16)| -|Scan|*in* initial_state_and_scan_inputs:**V**
*out* final_state_and_scan_outputs:**V**

or

*in* sequence_lens:**I**
*in* initial_state_and_scan_inputs:**V**
*out* final_state_and_scan_outputs:**V**|16+|**V** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|Scan|*in* initial_state_and_scan_inputs:**V**
*out* final_state_and_scan_outputs:**V**

or

*in* sequence_lens:**I**
*in* initial_state_and_scan_inputs:**V**
*out* final_state_and_scan_outputs:**V**|19+|**V** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(float8e4m3fn), tensor(float8e4m3fnuz), tensor(float8e5m2), tensor(float8e5m2fnuz), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|||[16, 18]|**V** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |||[11, 15]|**V** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |||[9, 10]|**V** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |||8|**I** = tensor(int64)
**V** = 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)| @@ -727,12 +752,14 @@ Do not modify directly.* |SequenceErase|*in* input_sequence:**S**
*in* position:**I**
*out* output_sequence:**S**|11+|**I** = tensor(int32), tensor(int64)
**S** = seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8))| |SequenceInsert|*in* input_sequence:**S**
*in* tensor:**T**
*in* position:**I**
*out* output_sequence:**S**|11+|**I** = tensor(int32), tensor(int64)
**S** = seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8))| |SequenceLength|*in* input_sequence:**S**
*out* length:**I**|11+|**I** = tensor(int64)
**S** = seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8))| -|Shape|*in* data:**T**
*out* shape:**T1**|15+|**T** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**T1** = tensor(int64)| +|Shape|*in* data:**T**
*out* shape:**T1**|19+|**T** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(float8e4m3fn), tensor(float8e4m3fnuz), tensor(float8e5m2), tensor(float8e5m2fnuz), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**T1** = tensor(int64)| +|||[15, 18]|**T** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**T1** = tensor(int64)| |||[13, 14]|**T** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**T1** = tensor(int64)| |||[1, 12]|**T** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**T1** = tensor(int64)| |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)| |SimplifiedLayerNormalization|*in* X:**T**
*in* scale:**V**
*out* Y:**V**
*out* inv_std_var:**U**|1+|**T** = tensor(double), tensor(float), tensor(float16)
**U** = tensor(double), tensor(float)
**V** = 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)| @@ -787,7 +814,7 @@ Do not modify directly.* | | |**Operator Domain:** *com.microsoft*|||| |Attention|*in* input:**T**
*in* weights:**T**
*in* bias:**T**
*in* mask_index:**M**
*in* past:**T**
*in* relative_position_bias:**T**
*in* past_sequence_length:**M**
*out* output:**T**
*out* present:**T**|1+|**T** = tensor(float), tensor(float16)| -|BeamSearch|*in* input_ids:**F**
*in* max_length:**I**
*in* min_length:**I**
*in* num_beams:**I**
*in* num_return_sequences:**I**
*in* length_penalty:**T**
*in* repetition_penalty:**T**
*in* vocab_mask:**M**
*in* prefix_vocab_mask:**M**
*in* attention_mask:**I**
*out* sequences:**I**
*out* sequences_scores:**T**
*out* scores:**T**|1+|**T** = tensor(float), tensor(float16)| +|BeamSearch|*in* input_ids:**F**
*in* max_length:**I**
*in* min_length:**I**
*in* num_beams:**I**
*in* num_return_sequences:**I**
*in* length_penalty:**T**
*in* repetition_penalty:**T**
*in* vocab_mask:**M**
*in* prefix_vocab_mask:**M**
*in* attention_mask:**I**
*in* decoder_input_ids:**I**
*in* logits_processor:**I**
*out* sequences:**I**
*out* sequences_scores:**T**
*out* scores:**T**|1+|**T** = tensor(float), tensor(float16)| |BiasAdd|*in* X:**T**
*in* bias:**T**
*in* skip:**T**
*out* Y:**T**|1+|**T** = tensor(float), tensor(float16)| |BiasDropout|*in* data:**T**
*in* bias:**T**
*in* residual:**T**
*in* ratio:**T1**
*in* training_mode:**T2**
*out* output:**T**
*out* mask:**T2**|1+|**T** = tensor(bfloat16), tensor(double), tensor(float), tensor(float16)
**T1** = tensor(bfloat16), tensor(double), tensor(float), tensor(float16)
**T2** = tensor(bool)| |BiasGelu|*in* A:**T**
*in* B:**T**
*out* C:**T**|1+|**T** = tensor(bfloat16), tensor(double), tensor(float), tensor(float16)| @@ -799,7 +826,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* relative_position_bias:**T**
*in* past_key:**T**
*in* past_value:**T**
*in* past_sequence_length:**M**
*in* beam_width:**M**
*in* cache_indirection:**M**
*out* output:**T**
*out* present_key:**T**
*out* present_value:**T**|1+|**T** = tensor(float), tensor(float16)| +|DecoderMaskedMultiHeadAttention|*in* query:**T**
*in* key:**T**
*in* value:**T**
*in* mask_index:**M**
*in* relative_position_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**|1+|**T** = tensor(float), tensor(float16)| |DecoderMaskedSelfAttention|*in* input:**T**
*in* weights:**T**
*in* bias:**T**
*in* mask_index:**M**
*in* past:**T**
*in* relative_position_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)| @@ -807,7 +834,7 @@ Do not modify directly.* |FastGelu|*in* X:**T**
*in* bias:**T**
*out* Y:**T**|1+|**T** = tensor(bfloat16), tensor(float), tensor(float16)| |FusedConv|*in* X:**T**
*in* W:**T**
*in* B:**T**
*in* Z:**T**
*out* Y:**T**|1+|**T** = tensor(float)| |FusedMatMul|*in* A:**T**
*in* B:**T**
*out* Y:**T**|1+|**T** = tensor(bfloat16), tensor(double), tensor(float), tensor(float16)| -|GatedRelativePositionBias|*in* query_layer:**T**
*in* query_bias:**T**
*in* rel_pos:**T**
*in* weight:**T**
*in* bias:**T**
*in* eco_a:**T**
*out* output:**T**|1+|**T** = tensor(float), tensor(float16)| +|GatedRelativePositionBias|*in* query_layer:**T**
*in* query_bias:**T**
*in* rel_pos:**T**
*in* weight:**T**
*in* bias:**T**
*in* eco_a:**T**
*in* token_offset:**M**
*out* output:**T**|1+|**T** = tensor(float), tensor(float16)| |Gelu|*in* X:**T**
*out* Y:**T**|1+|**T** = tensor(double), tensor(float), tensor(float16)| |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)| @@ -819,6 +846,7 @@ Do not modify directly.* |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* relative_position_bias:**T**
*out* output:**T**|1+|**T** = tensor(float), tensor(float16)| +|PackedMultiHeadAttention|*in* query:**T**
*in* key:**T**
*in* value:**T**
*in* bias:**T**
*in* token_offset:**M**
*in* cumulative_sequence_length:**M**
*in* relative_position_bias:**T**
*out* output:**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)
**T2** = tensor(int8)
**T3** = tensor(float), tensor(float16)
**T4** = tensor(int32)| |QOrderedAttention|*in* input:**Q**
*in* scale_input:**S**
*in* scale_Q_gemm:**S**
*in* scale_K_gemm:**S**
*in* scale_V_gemm:**S**
*in* Q_weight:**Q**
*in* K_weight:**Q**
*in* V_weight:**Q**
*in* scale_Q_weight:**S**
*in* scale_K_weight:**S**
*in* scale_V_weight:**S**
*in* Q_bias:**S**
*in* K_bias:**S**
*in* V_bias:**S**
*in* scale_QKT_gemm:**S**
*in* scale_QKT_softmax:**S**
*in* scale_values_gemm:**S**
*in* mask_index:**G**
*in* past:**Q**
*in* relative_position_bias:**S**
*out* output:**Q**|1+|**G** = tensor(int32)
**Q** = tensor(int8)
**S** = tensor(float)| |QOrderedGelu|*in* X:**Q**
*in* scale_X:**S**
*in* scale_Y:**S**
*out* Y:**Q**|1+|**Q** = tensor(int8)
**S** = tensor(float)| @@ -877,6 +905,10 @@ Do not modify directly.* |||9+|**T** = tensor(float), tensor(float16)| |||7+|**T** = tensor(float), tensor(float16)| |BitShift|*in* X:**T**
*in* Y:**T**
*out* Z:**T**|11+|**T** = tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|BitwiseAnd|*in* A:**T**
*in* B:**T**
*out* C:**T**|18+|**T** = tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|BitwiseNot|*in* X:**T**
*out* Y:**T**|18+|**T** = tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|BitwiseOr|*in* A:**T**
*in* B:**T**
*out* C:**T**|18+|**T** = tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|BitwiseXor|*in* A:**T**
*in* B:**T**
*out* C:**T**|18+|**T** = tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |Cast|*in* input:**T1**
*out* output:**T2**|13+|**T1** = tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**T2** = tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |||9+|**T1** = tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**T2** = tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |||6+|**T1** = tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**T2** = tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| @@ -909,9 +941,9 @@ Do not modify directly.* |||1+|**T** = tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |DequantizeLinear|*in* x:**T**
*in* x_scale:**tensor(float)**
*in* x_zero_point:**T**
*out* y:**tensor(float)**

or

*in* x:**T1**
*in* x_scale:**T2**
*in* x_zero_point:**T1**
*out* y:**T2**|13+|**T** = tensor(int32), tensor(int8), tensor(uint8)| |||10+|**T** = tensor(int32), tensor(int8), tensor(uint8)| -|Div|*in* A:**T**
*in* B:**T**
*out* C:**T**|14+|**T** = tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint8)| -|||13+|**T** = tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint8)| -|||7+|**T** = tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint8)| +|Div|*in* A:**T**
*in* B:**T**
*out* C:**T**|14+|**T** = tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|||13+|**T** = tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|||7+|**T** = tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |Dropout|*in* data:**T**
*in* ratio:**T1**
*in* training_mode:**T2**
*out* output:**T**
*out* mask:**T2**

or

*in* data:**T**
*out* output:**T**
*out* mask:**T**

or

*in* data:**T**
*out* output:**T**
*out* mask:**T1**|7+|**T** = tensor(float), tensor(float16)| |DynamicQuantizeLinear|*in* x:**T1**
*out* y:**T2**
*out* y_scale:**tensor(float)**
*out* y_zero_point:**T2**|11+|**T1** = tensor(float)
**T2** = tensor(uint8)| |Einsum|*in* Inputs:**T**
*out* Output:**T**|12+|**T** = tensor(float), tensor(float16)| @@ -954,6 +986,7 @@ Do not modify directly.* |||7+|**T** = tensor(float), tensor(float16)
**T1** = tensor(bool)| |GreaterOrEqual|*in* A:**T**
*in* B:**T**
*out* C:**T1**|16+|**T** = tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**T1** = tensor(bool)| |||12+|**T** = tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**T1** = tensor(bool)| +|GridSample|*in* X:**T1**
*in* grid:**T2**
*out* Y:**T1**|16+|**T1** = tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**T2** = tensor(float), tensor(float16)| |HardSigmoid|*in* X:**T**
*out* Y:**T**|6+|**T** = tensor(float), tensor(float16)| |Hardmax|*in* input:**T**
*out* output:**T**|13+|**T** = tensor(float), tensor(float16)| |||11+|**T** = tensor(float), tensor(float16)| @@ -962,6 +995,11 @@ Do not modify directly.* |||14+|**V** = tensor(bool), 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(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |||1+|**T** = tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|If|*in* cond:**B**
*out* outputs:**V**|19+|**B** = tensor(bool)
**V** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(float8e4m3fn), tensor(float8e4m3fnuz), tensor(float8e5m2), tensor(float8e5m2fnuz), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|||16+|**B** = tensor(bool)
**V** = 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)| +|||13+|**B** = tensor(bool)
**V** = 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)| +|||11+|**B** = tensor(bool)
**V** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|||7+|**B** = tensor(bool)
**V** = tensor(bfloat16), tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |ImageScaler|*in* input:**T**
*out* output:**T**|1+|**T** = tensor(float), tensor(float16)| |InstanceNormalization|*in* input:**T**
*in* scale:**T**
*in* B:**T**
*out* output:**T**|6+|**T** = tensor(float), tensor(float16)| |IsInf|*in* X:**T1**
*out* Y:**T2**|10+|**T1** = tensor(float)
**T2** = tensor(bool)| @@ -1023,16 +1061,21 @@ Do not modify directly.* |||7+|**T** = tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |Neg|*in* X:**T**
*out* Y:**T**|13+|**T** = tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8)| |||6+|**T** = tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8)| -|NonZero|*in* X:**T**
*out* Y:**tensor(int64)**|13+|**T** = tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint8)| -|||9+|**T** = tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint8)| +|NonZero|*in* X:**T**
*out* Y:**tensor(int64)**|13+|**T** = tensor(bool), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint8)| +|||9+|**T** = tensor(bool), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint8)| |Not|*in* X:**T**
*out* Y:**T**|1+|**T** = tensor(bool)| |OneHot|*in* indices:**T1**
*in* depth:**T2**
*in* values:**T3**
*out* output:**T3**|11+|**T1** = tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)
**T2** = tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**T3** = tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |||9+|**T1** = tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)
**T2** = tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)
**T3** = tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|OptionalGetElement|*in* input:**O**
*out* output:**V**|18+|**O** = optional(seq(tensor(bfloat16))), optional(seq(tensor(bool))), optional(seq(tensor(double))), optional(seq(tensor(float))), optional(seq(tensor(float16))), optional(seq(tensor(int16))), optional(seq(tensor(int32))), optional(seq(tensor(int64))), optional(seq(tensor(int8))), optional(seq(tensor(string))), optional(seq(tensor(uint16))), optional(seq(tensor(uint32))), optional(seq(tensor(uint64))), optional(seq(tensor(uint8))), optional(tensor(bfloat16)), optional(tensor(bool)), optional(tensor(double)), optional(tensor(float)), optional(tensor(float16)), optional(tensor(int16)), optional(tensor(int32)), optional(tensor(int64)), optional(tensor(int8)), optional(tensor(string)), optional(tensor(uint16)), optional(tensor(uint32)), optional(tensor(uint64)), optional(tensor(uint8)), seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), 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)
**V** = seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), 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)| +|||15+|**O** = optional(seq(tensor(bfloat16))), optional(seq(tensor(bool))), optional(seq(tensor(double))), optional(seq(tensor(float))), optional(seq(tensor(float16))), optional(seq(tensor(int16))), optional(seq(tensor(int32))), optional(seq(tensor(int64))), optional(seq(tensor(int8))), optional(seq(tensor(string))), optional(seq(tensor(uint16))), optional(seq(tensor(uint32))), optional(seq(tensor(uint64))), optional(seq(tensor(uint8))), optional(tensor(bfloat16)), optional(tensor(bool)), optional(tensor(double)), optional(tensor(float)), optional(tensor(float16)), optional(tensor(int16)), optional(tensor(int32)), optional(tensor(int64)), optional(tensor(int8)), optional(tensor(string)), optional(tensor(uint16)), optional(tensor(uint32)), optional(tensor(uint64)), optional(tensor(uint8))
**V** = seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), 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)| +|OptionalHasElement|*in* input:**O**
*out* output:**B**|18+|**B** = tensor(bool)
**O** = optional(seq(tensor(bfloat16))), optional(seq(tensor(bool))), optional(seq(tensor(double))), optional(seq(tensor(float))), optional(seq(tensor(float16))), optional(seq(tensor(int16))), optional(seq(tensor(int32))), optional(seq(tensor(int64))), optional(seq(tensor(int8))), optional(seq(tensor(string))), optional(seq(tensor(uint16))), optional(seq(tensor(uint32))), optional(seq(tensor(uint64))), optional(seq(tensor(uint8))), optional(tensor(bfloat16)), optional(tensor(bool)), optional(tensor(double)), optional(tensor(float)), optional(tensor(float16)), optional(tensor(int16)), optional(tensor(int32)), optional(tensor(int64)), optional(tensor(int8)), optional(tensor(string)), optional(tensor(uint16)), optional(tensor(uint32)), optional(tensor(uint64)), optional(tensor(uint8)), seq(tensor(bfloat16)), seq(tensor(bool)), seq(tensor(double)), seq(tensor(float)), seq(tensor(float16)), seq(tensor(int16)), seq(tensor(int32)), seq(tensor(int64)), seq(tensor(int8)), seq(tensor(string)), seq(tensor(uint16)), seq(tensor(uint32)), seq(tensor(uint64)), seq(tensor(uint8)), 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)| +|||15+|**B** = tensor(bool)
**O** = optional(seq(tensor(bfloat16))), optional(seq(tensor(bool))), optional(seq(tensor(double))), optional(seq(tensor(float))), optional(seq(tensor(float16))), optional(seq(tensor(int16))), optional(seq(tensor(int32))), optional(seq(tensor(int64))), optional(seq(tensor(int8))), optional(seq(tensor(string))), optional(seq(tensor(uint16))), optional(seq(tensor(uint32))), optional(seq(tensor(uint64))), optional(seq(tensor(uint8))), optional(tensor(bfloat16)), optional(tensor(bool)), optional(tensor(double)), optional(tensor(float)), optional(tensor(float16)), optional(tensor(int16)), optional(tensor(int32)), optional(tensor(int64)), optional(tensor(int8)), optional(tensor(string)), optional(tensor(uint16)), optional(tensor(uint32)), optional(tensor(uint64)), optional(tensor(uint8))| |Or|*in* A:**T**
*in* B:**T**
*out* C:**T1**|7+|**T** = tensor(bool)| |PRelu|*in* X:**T**
*in* slope:**T**
*out* Y:**T**|16+|**T** = tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int8)| |||9+|**T** = tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int8)| |||7+|**T** = tensor(float), tensor(float16)| -|Pad|*in* data:**T**
*in* pads:**tensor(int64)**
*in* constant_value:**T**
*in* axes:**Tind**
*out* output:**T**

or

*in* data:**T**
*in* pads:**tensor(int64)**
*in* constant_value:**T**
*out* output:**T**

or

*in* data:**T**
*out* output:**T**|13+|**T** = tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|Pad|*in* data:**T**
*in* pads:**tensor(int64)**
*in* constant_value:**T**
*in* axes:**Tind**
*out* output:**T**

or

*in* data:**T**
*in* pads:**tensor(int64)**
*in* constant_value:**T**
*out* output:**T**

or

*in* data:**T**
*out* output:**T**|18+|**T** = tensor(bool), 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(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |||11+|**T** = tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |||2+|**T** = tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |ParametricSoftplus|*in* X:**T**
*out* Y:**T**|1+|**T** = tensor(float), tensor(float16)| @@ -1049,36 +1092,45 @@ Do not modify directly.* |Range|*in* start:**T**
*in* limit:**T**
*in* delta:**T**
*out* output:**T**|11+|**T** = tensor(float), tensor(int16), tensor(int32), tensor(int64)| |Reciprocal|*in* X:**T**
*out* Y:**T**|13+|**T** = tensor(float), tensor(float16)| |||6+|**T** = tensor(float), tensor(float16)| -|ReduceL1|*in* data:**T**
*in* axes:**tensor(int64)**
*out* reduced:**T**

or

*in* data:**T**
*out* reduced:**T**|13+|**T** = tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| +|ReduceL1|*in* data:**T**
*in* axes:**tensor(int64)**
*out* reduced:**T**

or

*in* data:**T**
*out* reduced:**T**|18+|**T** = tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| +|||13+|**T** = tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| |||11+|**T** = tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| |||1+|**T** = tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| -|ReduceL2|*in* data:**T**
*in* axes:**tensor(int64)**
*out* reduced:**T**

or

*in* data:**T**
*out* reduced:**T**|13+|**T** = tensor(float), tensor(float16)| +|ReduceL2|*in* data:**T**
*in* axes:**tensor(int64)**
*out* reduced:**T**

or

*in* data:**T**
*out* reduced:**T**|18+|**T** = tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| +|||13+|**T** = tensor(float), tensor(float16)| |||11+|**T** = tensor(float), tensor(float16)| |||1+|**T** = tensor(float), tensor(float16)| -|ReduceLogSum|*in* data:**T**
*in* axes:**tensor(int64)**
*out* reduced:**T**

or

*in* data:**T**
*out* reduced:**T**|13+|**T** = tensor(float), tensor(float16)| +|ReduceLogSum|*in* data:**T**
*in* axes:**tensor(int64)**
*out* reduced:**T**

or

*in* data:**T**
*out* reduced:**T**|18+|**T** = tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| +|||13+|**T** = tensor(float), tensor(float16)| |||11+|**T** = tensor(float), tensor(float16)| |||1+|**T** = tensor(float), tensor(float16)| -|ReduceLogSumExp|*in* data:**T**
*in* axes:**tensor(int64)**
*out* reduced:**T**

or

*in* data:**T**
*out* reduced:**T**|13+|**T** = tensor(float), tensor(float16)| +|ReduceLogSumExp|*in* data:**T**
*in* axes:**tensor(int64)**
*out* reduced:**T**

or

*in* data:**T**
*out* reduced:**T**|18+|**T** = tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| +|||13+|**T** = tensor(float), tensor(float16)| |||11+|**T** = tensor(float), tensor(float16)| |||1+|**T** = tensor(float), tensor(float16)| -|ReduceMax|*in* data:**T**
*in* axes:**tensor(int64)**
*out* reduced:**T**

or

*in* data:**T**
*out* reduced:**T**|13+|**T** = tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|ReduceMax|*in* data:**T**
*in* axes:**tensor(int64)**
*out* reduced:**T**

or

*in* data:**T**
*out* reduced:**T**|18+|**T** = tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| +|||13+|**T** = tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |||12+|**T** = tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |||11+|**T** = tensor(float), tensor(float16)| |||1+|**T** = tensor(float), tensor(float16)| -|ReduceMean|*in* data:**T**
*in* axes:**tensor(int64)**
*out* reduced:**T**

or

*in* data:**T**
*out* reduced:**T**|13+|**T** = tensor(float), tensor(float16)| +|ReduceMean|*in* data:**T**
*in* axes:**tensor(int64)**
*out* reduced:**T**

or

*in* data:**T**
*out* reduced:**T**|18+|**T** = tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| +|||13+|**T** = tensor(float), tensor(float16)| |||11+|**T** = tensor(float), tensor(float16)| |||1+|**T** = tensor(float), tensor(float16)| -|ReduceMin|*in* data:**T**
*in* axes:**tensor(int64)**
*out* reduced:**T**

or

*in* data:**T**
*out* reduced:**T**|13+|**T** = tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|ReduceMin|*in* data:**T**
*in* axes:**tensor(int64)**
*out* reduced:**T**

or

*in* data:**T**
*out* reduced:**T**|18+|**T** = tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| +|||13+|**T** = tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |||12+|**T** = tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |||11+|**T** = tensor(float), tensor(float16)| |||1+|**T** = tensor(float), tensor(float16)| -|ReduceProd|*in* data:**T**
*in* axes:**tensor(int64)**
*out* reduced:**T**

or

*in* data:**T**
*out* reduced:**T**|13+|**T** = tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| +|ReduceProd|*in* data:**T**
*in* axes:**tensor(int64)**
*out* reduced:**T**

or

*in* data:**T**
*out* reduced:**T**|18+|**T** = tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| +|||13+|**T** = tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| |||11+|**T** = tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| |||1+|**T** = tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| |ReduceSum|*in* data:**T**
*in* axes:**tensor(int64)**
*out* reduced:**T**

or

*in* data:**T**
*out* reduced:**T**|13+|**T** = tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| |||11+|**T** = tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| |||1+|**T** = tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| -|ReduceSumSquare|*in* data:**T**
*in* axes:**tensor(int64)**
*out* reduced:**T**

or

*in* data:**T**
*out* reduced:**T**|13+|**T** = tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| +|ReduceSumSquare|*in* data:**T**
*in* axes:**tensor(int64)**
*out* reduced:**T**

or

*in* data:**T**
*out* reduced:**T**|18+|**T** = tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| +|||13+|**T** = tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| |||11+|**T** = tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| |||1+|**T** = tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)| |Relu|*in* X:**T**
*out* Y:**T**|14+|**T** = tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int8)| @@ -1091,7 +1143,8 @@ Do not modify directly.* |||11+|**T1** = tensor(float), tensor(float16)
**T2** = tensor(float), tensor(float16)| |||10+|**T** = tensor(float), tensor(float16)| |ReverseSequence|*in* input:**T**
*in* sequence_lens:**tensor(int64)**
*out* Y:**T**|10+|**T** = tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| -|RoiAlign|*in* X:**T1**
*in* rois:**T1**
*in* batch_indices:**T2**
*out* Y:**T1**|10+|**T1** = tensor(float), tensor(float16)
**T2** = tensor(int32), tensor(int64)| +|RoiAlign|*in* X:**T1**
*in* rois:**T1**
*in* batch_indices:**T2**
*out* Y:**T1**|16+|**T1** = tensor(float), tensor(float16)
**T2** = tensor(int32), tensor(int64)| +|||10+|**T1** = tensor(float), tensor(float16)
**T2** = tensor(int32), tensor(int64)| |Round|*in* X:**T**
*out* Y:**T**|11+|**T** = tensor(float), tensor(float16)| |STFT|*in* signal:**T1**
*in* frame_step:**T2**
*in* window:**T1**
*in* frame_length:**T2**
*out* output:**T1**|17+|**T1** = tensor(float), tensor(float16)
**T2** = tensor(int32), tensor(int64)| |ScaledTanh|*in* input:**T**
*out* output:**T**|1+|**T** = tensor(float), tensor(float16)| @@ -1134,7 +1187,8 @@ Do not modify directly.* |Softsign|*in* input:**T**
*out* output:**T**|1+|**T** = tensor(float), tensor(float16)| |SpaceToDepth|*in* input:**T**
*out* output:**T**|13+|**T** = tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |||1+|**T** = tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| -|Split|*in* input:**T**
*in* split:**T**
*out* outputs...:**T**

or

*in* input:**T**
*in* split:**tensor(int64)**
*out* outputs:**T**

or

*in* input:**T**
*out* outputs:**T**|13+|**T** = tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| +|Split|*in* input:**T**
*in* split:**T**
*out* outputs...:**T**

or

*in* input:**T**
*in* split:**tensor(int64)**
*out* outputs:**T**

or

*in* input:**T**
*out* outputs:**T**|18+|**T** = tensor(bool), 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(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |||11+|**T** = tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |||2+|**T** = tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)| |Sqrt|*in* X:**T**
*out* Y:**T**|13+|**T** = tensor(float), tensor(float16)| @@ -1178,16 +1232,17 @@ Do not modify directly.* |BiasGelu|*in* A:**T**
*in* B:**T**
*out* C:**T**|1+|**T** = tensor(float), tensor(float16)| |BiasSplitGelu|*in* X:**T**
*in* bias:**T**
*out* Y:**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), tensor(float16)| -|DequantizeLinear|*in* x:**T1**
*in* x_scale:**T2**
*in* x_zero_point:**T1**
*out* y:**T2**|1+|**T1** = tensor(float)
**T2** = tensor(uint8)| +|DequantizeLinear|*in* x:**T1**
*in* x_scale:**T2**
*in* x_zero_point:**T1**
*out* y:**T2**|1+|**T1** = tensor(int32), tensor(int8), tensor(uint8)
**T2** = tensor(float), tensor(float16)| |EmbedLayerNormalization|*in* input_ids:**T1**
*in* segment_ids:**T1**
*in* word_embedding:**T**
*in* position_embedding:**T**
*in* segment_embedding:**T**
*in* gamma:**T**
*in* beta:**T**
*in* mask:**T1**
*in* position_ids:**T1**
*out* output:**T**
*out* mask_index:**T1**
*out* embedding_sum:**T**|1+|**T** = tensor(float), tensor(float16)| |FusedMatMul|*in* A:**T**
*in* B:**T**
*out* Y:**T**|1+|**T** = tensor(float), tensor(float16)| |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)| +|MultiHeadAttention|*in* query:**T**
*in* key:**T**
*in* value:**T**
*in* bias:**T**
*in* key_padding_mask:**M**
*in* relative_position_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)| |NhwcConv|*in* X:**T**
*in* W:**T**
*in* B:**T**
*out* Y:**T**|1+|**T** = tensor(float), tensor(float16)| |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)| |QLinearSigmoid|*in* X:**T**
*in* X_scale:**tensor(float)**
*in* X_zero_point:**T**
*in* Y_scale:**tensor(float)**
*in* Y_zero_point:**T**
*out* Y:**T**|1+|**T** = tensor(int8), tensor(uint8)| -|QuantizeLinear|*in* x:**T1**
*in* y_scale:**T1**
*in* y_zero_point:**T2**
*out* y:**T2**|1+|**T1** = tensor(float)
**T2** = tensor(uint8)| +|QuantizeLinear|*in* x:**T1**
*in* y_scale:**T1**
*in* y_zero_point:**T2**
*out* y:**T2**|1+|**T1** = tensor(float), tensor(float16), tensor(int32)
**T2** = tensor(int8), tensor(uint8)| |QuickGelu|*in* X:**T**
*out* Y:**T**|1+|**T** = tensor(float), tensor(float16)| |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(float), tensor(float16)| | | diff --git a/docs/TVM_EP.md b/docs/TVM_EP.md index f0062094aeb6b..df59d5c05855c 100644 --- a/docs/TVM_EP.md +++ b/docs/TVM_EP.md @@ -160,7 +160,7 @@ build.bat --config Release --enable_pybind --build_wheel --skip_tests --parallel ``` build.bat --config Release --enable_pybind --build_wheel --skip_tests --parallel --use_tvm --skip_onnx_tests --cmake_generator "Visual Studio 17 2022" --llvm_config /build/Release/bin/llvm-config.exe --use_cuda --cudnn_home “C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.*” --cuda_home “C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.*” ``` -In both cases (CPU, GPU) there are the following options for cmake generator: "Visual Studio 15 2017", "Visual Studio 16 2019", "Visual Studio 17 2022" and "Ninja". Also handshake mechanism can be switched on by `--use_tvm_hash` flag. At the latter case ipp-crypto library is built with dependencies, see details above. +In both cases (CPU, GPU) there are the following options for cmake generator: "Visual Studio 17 2022" and "Ninja". Also handshake mechanism can be switched on by `--use_tvm_hash` flag. At the latter case ipp-crypto library is built with dependencies, see details above. - Install python wheel package for ONNX Runtime:
Default path to the package is `/build/Windows/Release/Release/dist`. Note that it is different in comparison with path to the package on Linux. Before installation check names of wheel packages and use corresponding one. It can be looked like the following: ```cmd @@ -224,7 +224,7 @@ Currently, only precompiled models are supported in C# (see the related section ```CSharp SessionOptions session_options = new SessionOptions{}; -string tvm_ep_options = +string tvm_ep_options = $"executor: {tvm_executor_type}, " + $"so_folder: {folder_with_pretuned_files}, " + $"check_hash: {check_hash}, " + @@ -286,7 +286,7 @@ It is also possible to use a precompiled model. The compiled model can be obtained using the [OctoML platform](https://onnx.octoml.ai) or compiled directly (see **Support precompiled model** section in -[Sample notebook for ResNet50 inference with TVM EP](https://github.com/microsoft/onnxruntime/blob/main/docs/python/inference/notebooks/onnxruntime-tvm-tutorial.ipynb) +[Sample notebook for ResNet50 inference with TVM EP](https://github.com/microsoft/onnxruntime/blob/main/docs/python/notebooks/onnxruntime-tvm-tutorial.ipynb) for more information on model compilation). In order to use the precompiled model, only need to pass two options: @@ -302,7 +302,7 @@ You can read more about these options in section [Configuration options](#config ## Samples -- [Sample notebook for ResNet50 inference with TVM EP](https://github.com/microsoft/onnxruntime/blob/main/docs/python/inference/notebooks/onnxruntime-tvm-tutorial.ipynb) +- [Sample notebook for ResNet50 inference with TVM EP](https://github.com/microsoft/onnxruntime/blob/main/docs/python/notebooks/onnxruntime-tvm-tutorial.ipynb) ## Known issues - At this moment, the TVM EP has only been verified on UNIX/Linux and Windows systems. diff --git a/docs/c_cxx/Doxyfile b/docs/c_cxx/Doxyfile index 94b39d2045f69..aedb1fdcfee75 100644 --- a/docs/c_cxx/Doxyfile +++ b/docs/c_cxx/Doxyfile @@ -1,4 +1,4 @@ -# Doxyfile 1.9.2 +# Doxyfile 1.9.8 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -12,6 +12,16 @@ # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). +# +# Note: +# +# Use doxygen to compare the used configuration file with the template +# configuration file: +# doxygen -x [configFile] +# Use doxygen to compare the used configuration file with the template +# configuration file without replacing the environment variables or CMake type +# replacement variables: +# doxygen -x_noenv [configFile] #--------------------------------------------------------------------------- # Project related configuration options @@ -60,16 +70,28 @@ PROJECT_LOGO = "../images/ONNX_Runtime_logo - Docs.png" OUTPUT_DIRECTORY = ../../build/doxygen -# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- -# directories (in 2 levels) under the output directory of each output format and -# will distribute the generated files over these directories. Enabling this +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096 +# sub-directories (in 2 levels) under the output directory of each output format +# and will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes -# performance problems for the file system. +# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to +# control the number of sub-directories. # The default value is: NO. CREATE_SUBDIRS = NO +# Controls the number of sub-directories that will be created when +# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every +# level increment doubles the number of directories, resulting in 4096 +# directories at level 8 which is the default and also the maximum value. The +# sub-directories are organized in 2 levels, the first level always has a fixed +# number of 16 directories. +# Minimum value: 0, maximum value: 8, default value: 8. +# This tag requires that the tag CREATE_SUBDIRS is set to YES. + +CREATE_SUBDIRS_LEVEL = 8 + # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode @@ -81,14 +103,14 @@ ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. -# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, -# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), -# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, -# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, -# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, -# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, -# Ukrainian and Vietnamese. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian, +# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English +# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek, +# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with +# English messages), Korean, Korean-en (Korean with English messages), Latvian, +# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, +# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, +# Swedish, Turkish, Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English @@ -341,6 +363,17 @@ MARKDOWN_SUPPORT = YES TOC_INCLUDE_HEADINGS = 5 +# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to +# generate identifiers for the Markdown headings. Note: Every identifier is +# unique. +# Possible values are: DOXYGEN use a fixed 'autotoc_md' string followed by a +# sequence number starting at 0 and GITHUB use the lower case version of title +# with any whitespace replaced by '-' and punctuation characters removed. +# The default value is: DOXYGEN. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +MARKDOWN_ID_STYLE = DOXYGEN + # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by putting a % sign in front of the word or @@ -437,7 +470,7 @@ INLINE_SIMPLE_STRUCTS = NO # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. -TYPEDEF_HIDES_STRUCT = YES +TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be @@ -452,7 +485,7 @@ TYPEDEF_HIDES_STRUCT = YES LOOKUP_CACHE_SIZE = 0 -# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use +# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use # during processing. When set to 0 doxygen will based this on the number of # cores available in the system. You can set it explicitly to a value larger # than 0 to get more control over the balance between CPU load and processing @@ -465,6 +498,14 @@ LOOKUP_CACHE_SIZE = 0 NUM_PROC_THREADS = 1 +# If the TIMESTAMP tag is set different from NO then each generated page will +# contain the date or date and time when the page was generated. Setting this to +# NO can help when comparing the output of multiple runs. +# Possible values are: YES, NO, DATETIME and DATE. +# The default value is: NO. + +TIMESTAMP = NO + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- @@ -546,7 +587,8 @@ HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO, these classes will be included in the various overviews. This option -# has no effect if EXTRACT_ALL is enabled. +# will also hide undocumented C++ concepts if enabled. This option has no effect +# if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO @@ -577,14 +619,15 @@ INTERNAL_DOCS = NO # filesystem is case sensitive (i.e. it supports files in the same directory # whose names only differ in casing), the option must be set to YES to properly # deal with such files in case they appear in the input. For filesystems that -# are not case sensitive the option should be be set to NO to properly deal with +# are not case sensitive the option should be set to NO to properly deal with # output files written for symbols that only differ in casing, such as for two # classes, one named CLASS and the other named Class, and to also support # references to files without having to specify the exact matching casing. On # Windows (including Cygwin) and MacOS, users should typically set this option # to NO, whereas on Linux or other Unix flavors it should typically be set to # YES. -# The default value is: system dependent. +# Possible values are: SYSTEM, NO and YES. +# The default value is: SYSTEM. CASE_SENSE_NAMES = NO @@ -836,11 +879,26 @@ WARN_IF_INCOMPLETE_DOC = YES WARN_NO_PARAMDOC = YES +# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about +# undocumented enumeration values. If set to NO, doxygen will accept +# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: NO. + +WARN_IF_UNDOC_ENUM_VAL = NO + # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when # a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS # then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but # at the end of the doxygen process doxygen will return with a non-zero status. -# Possible values are: NO, YES and FAIL_ON_WARNINGS. +# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then doxygen behaves +# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined doxygen will not +# write the warning messages in between other messages but write them at the end +# of a run, in case a WARN_LOGFILE is defined the warning messages will be +# besides being in the defined file also be shown at the end of a run, unless +# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case +# the behavior will remain as with the setting FAIL_ON_WARNINGS. +# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT. # The default value is: NO. WARN_AS_ERROR = YES @@ -851,13 +909,27 @@ WARN_AS_ERROR = YES # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) +# See also: WARN_LINE_FORMAT # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" +# In the $text part of the WARN_FORMAT command it is possible that a reference +# to a more specific place is given. To make it easier to jump to this place +# (outside of doxygen) the user can define a custom "cut" / "paste" string. +# Example: +# WARN_LINE_FORMAT = "'vi $file +$line'" +# See also: WARN_FORMAT +# The default value is: at line $line of file $file. + +WARN_LINE_FORMAT = "at line $line of file $file" + # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard -# error (stderr). +# error (stderr). In case the file specified cannot be opened for writing the +# warning and error messages are written to standard error. When as file - is +# specified the warning and error messages are written to standard output +# (stdout). WARN_LOGFILE = @@ -881,10 +953,21 @@ INPUT = ../../include/onnxruntime/core/session/onnxruntime_c_ap # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: # https://www.gnu.org/software/libiconv/) for the list of possible encodings. +# See also: INPUT_FILE_ENCODING # The default value is: UTF-8. INPUT_ENCODING = UTF-8 +# This tag can be used to specify the character encoding of the source files +# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify +# character encoding on a per file pattern basis. Doxygen will compare the file +# name with each pattern and apply the encoding instead of the default +# INPUT_ENCODING) if there is a match. The character encodings are a list of the +# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding +# "INPUT_ENCODING" for further information on supported encodings. + +INPUT_FILE_ENCODING = + # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. @@ -896,18 +979,21 @@ INPUT_ENCODING = UTF-8 # Note the list of default checked file patterns might differ from the list of # default file extension mappings. # -# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, -# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, -# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, -# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C -# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, -# *.vhdl, *.ucf, *.qsf and *.ice. +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cxxm, +# *.cpp, *.cppm, *.c++, *.c++m, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, +# *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, *.h++, *.ixx, *.l, *.cs, *.d, *.php, +# *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be +# provided as doxygen C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = *.c \ *.cc \ *.cxx \ + *.cxxm \ *.cpp \ + *.cppm \ *.c++ \ + *.c++m \ *.java \ *.ii \ *.ixx \ @@ -922,6 +1008,8 @@ FILE_PATTERNS = *.c \ *.hxx \ *.hpp \ *.h++ \ + *.ixx \ + *.l \ *.cs \ *.d \ *.php \ @@ -984,10 +1072,7 @@ EXCLUDE_PATTERNS = # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories use the pattern */test/* +# ANamespace::AClass, ANamespace::*Test EXCLUDE_SYMBOLS = @@ -1032,6 +1117,11 @@ IMAGE_PATH = # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. # +# Note that doxygen will use the data processed and written to standard output +# for further processing, therefore nothing else, like debug statements or used +# commands (so in case of a Windows batch file always use @echo OFF), should be +# written to standard output. +# # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. @@ -1073,6 +1163,15 @@ FILTER_SOURCE_PATTERNS = USE_MDFILE_AS_MAINPAGE = +# The Fortran standard specifies that for fixed formatted Fortran code all +# characters from position 72 are to be considered as comment. A common +# extension is to allow longer lines before the automatic comment starts. The +# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can +# be processed before the automatic comment starts. +# Minimum value: 7, maximum value: 10000, default value: 72. + +FORTRAN_COMMENT_AFTER = 72 + #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- @@ -1210,10 +1309,11 @@ CLANG_DATABASE_PATH = ALPHABETICAL_INDEX = YES -# In case all classes in a project start with a common prefix, all classes will -# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag -# can be used to specify a prefix (or a list of prefixes) that should be ignored -# while generating the index headers. +# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes) +# that should be ignored while generating the index headers. The IGNORE_PREFIX +# tag works for classes, function and member names. The entity will be placed in +# the alphabetical list under the first letter of the entity name that remains +# after removing the prefix. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = @@ -1292,7 +1392,12 @@ HTML_STYLESHEET = # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra style sheet files is of importance (e.g. the last # style sheet in the list overrules the setting of the previous ones in the -# list). For an example see the documentation. +# list). +# Note: Since the styling of scrollbars can currently not be overruled in +# Webkit/Chromium, the styling will be left out of the default doxygen.css if +# one or more extra stylesheets have been specified. So if scrollbar +# customization is desired it has to be added explicitly. For an example see the +# documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = @@ -1307,6 +1412,19 @@ HTML_EXTRA_STYLESHEET = HTML_EXTRA_FILES = +# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output +# should be rendered with a dark or light theme. +# Possible values are: LIGHT always generate light mode output, DARK always +# generate dark mode output, AUTO_LIGHT automatically set the mode according to +# the user preference, use light mode if no preference is set (the default), +# AUTO_DARK automatically set the mode according to the user preference, use +# dark mode if no preference is set and TOGGLE allow to user to switch between +# light and dark mode via a button. +# The default value is: AUTO_LIGHT. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE = AUTO_LIGHT + # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a color-wheel, see @@ -1337,15 +1455,6 @@ HTML_COLORSTYLE_SAT = 100 HTML_COLORSTYLE_GAMMA = 80 -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting this -# to YES can help to show when doxygen was last run and thus if the -# documentation is up to date. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_TIMESTAMP = NO - # If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML # documentation will contain a main index with vertical navigation menus that # are dynamically created via JavaScript. If disabled, the navigation index will @@ -1365,6 +1474,13 @@ HTML_DYNAMIC_MENUS = YES HTML_DYNAMIC_SECTIONS = NO +# If the HTML_CODE_FOLDING tag is set to YES then classes and functions can be +# dynamically folded and expanded in the generated HTML source code. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_CODE_FOLDING = YES + # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to @@ -1401,6 +1517,13 @@ GENERATE_DOCSET = NO DOCSET_FEEDNAME = "Doxygen generated docs" +# This tag determines the URL of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDURL = + # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. @@ -1488,6 +1611,16 @@ BINARY_TOC = NO TOC_EXPAND = NO +# The SITEMAP_URL tag is used to specify the full URL of the place where the +# generated documentation will be placed on the server by the user during the +# deployment of the documentation. The generated sitemap is called sitemap.xml +# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL +# is specified no sitemap is generated. For information about the sitemap +# protocol see https://www.sitemaps.org +# This tag requires that the tag GENERATE_HTML is set to YES. + +SITEMAP_URL = + # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help @@ -1605,7 +1738,7 @@ GENERATE_TREEVIEW = YES # area (value NO) or if it should extend to the full height of the window (value # YES). Setting this to YES gives a layout similar to # https://docs.readthedocs.io with more room for contents, but less room for the -# project logo, title, and description. If either GENERATOR_TREEVIEW or +# project logo, title, and description. If either GENERATE_TREEVIEW or # DISABLE_INDEX is set to NO, this option has no effect. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1636,6 +1769,13 @@ TREEVIEW_WIDTH = 250 EXT_LINKS_IN_WINDOW = NO +# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email +# addresses. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +OBFUSCATE_EMAILS = YES + # If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg # tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see # https://inkscape.org) to generate formulas as SVG images instead of PNGs for @@ -1969,9 +2109,16 @@ PDF_HYPERLINKS = YES USE_PDFLATEX = YES -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode -# command to the generated LaTeX files. This will instruct LaTeX to keep running -# if errors occur, instead of asking the user for help. +# The LATEX_BATCHMODE tag signals the behavior of LaTeX in case of an error. +# Possible values are: NO same as ERROR_STOP, YES same as BATCH, BATCH In batch +# mode nothing is printed on the terminal, errors are scrolled as if is +# hit at every error; missing files that TeX tries to input or request from +# keyboard input (\read on a not open input stream) cause the job to abort, +# NON_STOP In nonstop mode the diagnostic message will appear on the terminal, +# but there is no possibility of user interaction just like in batch mode, +# SCROLL In scroll mode, TeX will stop only for missing files to input or if +# keyboard input is necessary and ERROR_STOP In errorstop mode, TeX will stop at +# each error, asking for user intervention. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1992,14 +2139,6 @@ LATEX_HIDE_INDICES = NO LATEX_BIB_STYLE = plain -# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated -# page will contain the date and time when the page was generated. Setting this -# to NO can help when comparing the output of multiple runs. -# The default value is: NO. -# This tag requires that the tag GENERATE_LATEX is set to YES. - -LATEX_TIMESTAMP = NO - # The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) # path from which the emoji images will be read. If a relative path is entered, # it will be relative to the LATEX_OUTPUT directory. If left blank the @@ -2165,7 +2304,7 @@ DOCBOOK_OUTPUT = docbook #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an -# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures +# AutoGen Definitions (see https://autogen.sourceforge.net/) file that captures # the structure of the code including all documentation. Note that this feature # is still experimental and incomplete at the moment. # The default value is: NO. @@ -2176,6 +2315,28 @@ GENERATE_AUTOGEN_DEF = NO # Configuration options related to Sqlite3 output #--------------------------------------------------------------------------- +# If the GENERATE_SQLITE3 tag is set to YES doxygen will generate a Sqlite3 +# database with symbols found by doxygen stored in tables. +# The default value is: NO. + +GENERATE_SQLITE3 = NO + +# The SQLITE3_OUTPUT tag is used to specify where the Sqlite3 database will be +# put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put +# in front of it. +# The default directory is: sqlite3. +# This tag requires that the tag GENERATE_SQLITE3 is set to YES. + +SQLITE3_OUTPUT = sqlite3 + +# The SQLITE3_OVERWRITE_DB tag is set to YES, the existing doxygen_sqlite3.db +# database file will be recreated with each doxygen run. If set to NO, doxygen +# will warn if an a database file is already found and not modify it. +# The default value is: YES. +# This tag requires that the tag GENERATE_SQLITE3 is set to YES. + +SQLITE3_RECREATE_DB = YES + #--------------------------------------------------------------------------- # Configuration options related to the Perl module output #--------------------------------------------------------------------------- @@ -2250,7 +2411,8 @@ SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by the -# preprocessor. +# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of +# RECURSIVE has no effect here. # This tag requires that the tag SEARCH_INCLUDES is set to YES. # onnxruntime-training and onnxruntime core headers are in different directories. @@ -2324,15 +2486,15 @@ TAGFILES = GENERATE_TAGFILE = -# If the ALLEXTERNALS tag is set to YES, all external class will be listed in -# the class index. If set to NO, only the inherited external classes will be -# listed. +# If the ALLEXTERNALS tag is set to YES, all external classes and namespaces +# will be listed in the class and namespace index. If set to NO, only the +# inherited external classes will be listed. # The default value is: NO. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will be +# in the topic index. If set to NO, only the current project's groups will be # listed. # The default value is: YES. @@ -2346,16 +2508,9 @@ EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES #--------------------------------------------------------------------------- -# Configuration options related to the dot tool +# Configuration options related to diagram generator tools #--------------------------------------------------------------------------- -# You can include diagrams made with dia in doxygen documentation. Doxygen will -# then run dia to produce the diagram and insert it in the documentation. The -# DIA_PATH tag allows you to specify the directory where the dia binary resides. -# If left empty dia is assumed to be found in the default search path. - -DIA_PATH = - # If set to YES the inheritance and collaboration graphs will hide inheritance # and usage relations if the target is undocumented or is not a class. # The default value is: YES. @@ -2364,7 +2519,7 @@ HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz (see: -# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent # Bell Labs. The other options in this section have no effect if this option is # set to NO # The default value is: NO. @@ -2381,32 +2536,73 @@ HAVE_DOT = NO DOT_NUM_THREADS = 0 -# By default doxygen will tell dot to use the default font as specified with -# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set -# the path where dot can find it using this tag. +# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of +# subgraphs. When you want a differently looking font in the dot files that +# doxygen generates you can specify fontname, fontcolor and fontsize attributes. +# For details please see Node, +# Edge and Graph Attributes specification You need to make sure dot is able +# to find the font, which can be done by putting it in a standard location or by +# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. Default graphviz fontsize is 14. +# The default value is: fontname=Helvetica,fontsize=10. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10" + +# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can +# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. Complete documentation about +# arrows shapes. +# The default value is: labelfontname=Helvetica,labelfontsize=10. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10" + +# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes +# around nodes set 'shape=plain' or 'shape=plaintext' Shapes specification +# The default value is: shape=box,height=0.2,width=0.4. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4" + +# You can set the path where dot can find font specified with fontname in +# DOT_COMMON_ATTR and others dot attributes. # This tag requires that the tag HAVE_DOT is set to YES. DOT_FONTPATH = -# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for -# each documented class showing the direct and indirect inheritance relations. -# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. +# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then doxygen will +# generate a graph for each documented class showing the direct and indirect +# inheritance relations. In case the CLASS_GRAPH tag is set to YES or GRAPH and +# HAVE_DOT is enabled as well, then dot will be used to draw the graph. In case +# the CLASS_GRAPH tag is set to YES and HAVE_DOT is disabled or if the +# CLASS_GRAPH tag is set to BUILTIN, then the built-in generator will be used. +# If the CLASS_GRAPH tag is set to TEXT the direct and indirect inheritance +# relations will be shown as texts / links. +# Possible values are: NO, YES, TEXT, GRAPH and BUILTIN. # The default value is: YES. -# This tag requires that the tag HAVE_DOT is set to YES. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a # graph for each documented class showing the direct and indirect implementation # dependencies (inheritance, containment, and class references variables) of the -# class with other documented classes. +# class with other documented classes. Explicit enabling a collaboration graph, +# when COLLABORATION_GRAPH is set to NO, can be accomplished by means of the +# command \collaborationgraph. Disabling a collaboration graph can be +# accomplished by means of the command \hidecollaborationgraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for -# groups, showing the direct groups dependencies. +# groups, showing the direct groups dependencies. Explicit enabling a group +# dependency graph, when GROUP_GRAPHS is set to NO, can be accomplished by means +# of the command \groupgraph. Disabling a directory graph can be accomplished by +# means of the command \hidegroupgraph. See also the chapter Grouping in the +# manual. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2466,7 +2662,9 @@ TEMPLATE_RELATIONS = NO # If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to # YES then doxygen will generate a graph for each documented file showing the # direct and indirect include dependencies of the file with other documented -# files. +# files. Explicit enabling an include graph, when INCLUDE_GRAPH is is set to NO, +# can be accomplished by means of the command \includegraph. Disabling an +# include graph can be accomplished by means of the command \hideincludegraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2475,7 +2673,10 @@ INCLUDE_GRAPH = YES # If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are # set to YES then doxygen will generate a graph for each documented file showing # the direct and indirect include dependencies of the file with other documented -# files. +# files. Explicit enabling an included by graph, when INCLUDED_BY_GRAPH is set +# to NO, can be accomplished by means of the command \includedbygraph. Disabling +# an included by graph can be accomplished by means of the command +# \hideincludedbygraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2515,16 +2716,26 @@ GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the # dependencies a directory has on other directories in a graphical way. The # dependency relations are determined by the #include relations between the -# files in the directories. +# files in the directories. Explicit enabling a directory graph, when +# DIRECTORY_GRAPH is set to NO, can be accomplished by means of the command +# \directorygraph. Disabling a directory graph can be accomplished by means of +# the command \hidedirectorygraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. DIRECTORY_GRAPH = YES +# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels +# of child directories generated in directory dependency graphs by dot. +# Minimum value: 1, maximum value: 25, default value: 1. +# This tag requires that the tag DIRECTORY_GRAPH is set to YES. + +DIR_GRAPH_MAX_DEPTH = 1 + # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. For an explanation of the image formats see the section # output formats in the documentation of the dot tool (Graphviz (see: -# http://www.graphviz.org/)). +# https://www.graphviz.org/)). # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order # to make the SVG files visible in IE 9+ (other browsers do not have this # requirement). @@ -2561,11 +2772,12 @@ DOT_PATH = DOTFILE_DIRS = -# The MSCFILE_DIRS tag can be used to specify one or more directories that -# contain msc files that are included in the documentation (see the \mscfile -# command). +# You can include diagrams made with dia in doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. -MSCFILE_DIRS = +DIA_PATH = # The DIAFILE_DIRS tag can be used to specify one or more directories that # contain dia files that are included in the documentation (see the \diafile @@ -2574,10 +2786,10 @@ MSCFILE_DIRS = DIAFILE_DIRS = # When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the -# path where java can find the plantuml.jar file. If left blank, it is assumed -# PlantUML is not used or called during a preprocessing step. Doxygen will -# generate a warning when it encounters a \startuml command in this case and -# will not generate output for the diagram. +# path where java can find the plantuml.jar file or to the filename of jar file +# to be used. If left blank, it is assumed PlantUML is not used or called during +# a preprocessing step. Doxygen will generate a warning when it encounters a +# \startuml command in this case and will not generate output for the diagram. PLANTUML_JAR_PATH = @@ -2627,6 +2839,8 @@ DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page # explaining the meaning of the various boxes and arrows in the dot generated # graphs. +# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal +# graphical representation for inheritance and collaboration diagrams is used. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2640,3 +2854,19 @@ GENERATE_LEGEND = YES # The default value is: YES. DOT_CLEANUP = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. If the MSCGEN_TOOL tag is left empty (the default), then doxygen will +# use a built-in version of mscgen tool to produce the charts. Alternatively, +# the MSCGEN_TOOL tag can also specify the name an external tool. For instance, +# specifying prog as the value, doxygen will call the tool as prog -T +# -o . The external tool should support +# output file formats "png", "eps", "svg", and "ismap". + +MSCGEN_TOOL = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the \mscfile +# command). + +MSCFILE_DIRS = diff --git a/docs/c_cxx/doxygen-header.html b/docs/c_cxx/doxygen-header.html index 364f76f7f0580..6d95bf57ff98f 100644 --- a/docs/c_cxx/doxygen-header.html +++ b/docs/c_cxx/doxygen-header.html @@ -16,7 +16,7 @@ - + $treeview $search $mathjax diff --git a/docs/onnxruntime_extensions.md b/docs/onnxruntime_extensions.md index 9f716065e1460..b10cb42e0d9e6 100644 --- a/docs/onnxruntime_extensions.md +++ b/docs/onnxruntime_extensions.md @@ -6,7 +6,7 @@ ONNXRuntime Extensions is a comprehensive package to extend the capability of th onnxruntime-extensions supports many useful custom operators to enhance the text processing capability of ONNXRuntime, which include some widely used **string operators** and popular **tokenizers**. For custom operators supported and how to use them, please check the documentation [custom operators](https://github.com/microsoft/onnxruntime-extensions/blob/main/docs/custom_text_ops.md). ## Build ONNXRuntime with Extensions -We have supported build onnxruntime-extensions as a static library and link it into ONNXRuntime. To enable custom operators from onnxruntime-extensions, you should add argument `--use_extensions`, which will use onnxruntime-extensions from git submodule in path cmake/external/onnxruntime-extensions **by default**. +We have supported build onnxruntime-extensions as a static library and link it into ONNXRuntime. To enable custom operators from onnxruntime-extensions, you should add argument `--use_extensions`, which will fetch onnxruntime-extensions and build it as static library from https://github.com/microsoft/onnxruntime-extensions **by default**. If you want to build ONNXRuntime with a pre-pulled onnxruntime-extensions, pass extra argument `--extensions_overridden_path `. diff --git a/docs/python/inference/ONNX_Runtime_icon.png b/docs/python/ONNX_Runtime_icon.png similarity index 100% rename from docs/python/inference/ONNX_Runtime_icon.png rename to docs/python/ONNX_Runtime_icon.png diff --git a/docs/python/README.rst b/docs/python/README.rst index f5f162b1d42eb..32bb3729e01d0 100644 --- a/docs/python/README.rst +++ b/docs/python/README.rst @@ -8,6 +8,16 @@ For more information on ONNX Runtime, please see `aka.ms/onnxruntime `_ on a variety of Intel® hardware such as: - Intel® CPUs - Intel® integrated GPUs - - Intel® Movidius™ Vision Processing Units - referred to as VPU. - + - Intel® discrete GPUs + - Intel® integrated VPUs Installation ------------ @@ -16,31 +16,27 @@ Requirements ^^^^^^^^^^^^ - Ubuntu 18.04, 20.04, RHEL(CPU only) or Windows 10 - 64 bit -- Python 3.7, 3.8 or 3.9 for Linux and only Python3.9 for Windows +- Python 3.8 or 3.9 or 3.10 for Linux and only Python3.10 for Windows This package supports: - Intel® CPUs - Intel® integrated GPUs - - Intel® Movidius™ Vision Processing Units (VPUs). - -Please Note for VAD-M use Docker installation / Build from Source for Linux. + - Intel® discrete GPUs + - Intel® integrated VPUs -``pip3 install onnxruntime-openvino==1.13.1`` +``pip3 install onnxruntime-openvino`` Please install OpenVINO™ PyPi Package separately for Windows. For installation instructions on Windows please refer to `OpenVINO™ Execution Provider for ONNX Runtime for Windows `_. -**OpenVINO™ Execution Provider for ONNX Runtime** Linux Wheels comes with pre-built libraries of OpenVINO™ version 2022.2.0 eliminating the need to install OpenVINO™ separately. The OpenVINO™ libraries are prebuilt with CXX11_ABI flag set to 0. - -The package also includes module that is used by torch-ort-inference to accelerate inference for PyTorch models with OpenVINO Execution Provider. -See `torch-ort-inference `_ for more details. +**OpenVINO™ Execution Provider for ONNX Runtime** Linux Wheels comes with pre-built libraries of OpenVINO™ version 2023.0.0 eliminating the need to install OpenVINO™ separately. The OpenVINO™ libraries are prebuilt with CXX11_ABI flag set to 0. For more details on build and installation please refer to `Build `_. Usage ^^^^^ -By default, Intel® CPU is used to run inference. However, you can change the default option to either Intel® integrated GPU or Intel® VPU for AI inferencing. +By default, Intel® CPU is used to run inference. However, you can change the default option to either Intel® integrated or discrete GPU. Invoke `the provider config device type argument `_ to change the hardware on which inferencing is done. For more API calls and environment variables, see `Usage `_. diff --git a/docs/python/_common/onnx_sphinx.py b/docs/python/_common/onnx_sphinx.py index 9e72648618120..7562d23289d90 100644 --- a/docs/python/_common/onnx_sphinx.py +++ b/docs/python/_common/onnx_sphinx.py @@ -882,7 +882,7 @@ def _generate_op_doc(app): def setup(app): """ Sphinx extension `onnx_sphinx` displays documentation - on ONN Operators. + of all ONNX Operators. """ import sphinx diff --git a/docs/python/inference/api_summary.rst b/docs/python/api_summary.rst similarity index 100% rename from docs/python/inference/api_summary.rst rename to docs/python/api_summary.rst diff --git a/docs/python/inference/conf.py b/docs/python/conf.py similarity index 94% rename from docs/python/inference/conf.py rename to docs/python/conf.py index bca894c31de3c..065149441b72c 100644 --- a/docs/python/inference/conf.py +++ b/docs/python/conf.py @@ -10,8 +10,6 @@ import shutil # noqa: F401 import sys -import onnxruntime - sys.path.append(os.path.join(os.path.dirname(__file__), "..", "_common")) # import recommonmark @@ -21,13 +19,10 @@ project = "Python API" copyright = "2018-2023, Microsoft" author = "Microsoft" -version = onnxruntime.__version__ -release = version # -- General configuration --------------------------------------------------- extensions = [ - "alabaster", "sphinx.ext.intersphinx", "sphinx.ext.imgmath", "sphinx.ext.ifconfig", @@ -38,9 +33,7 @@ "sphinx.ext.graphviz", "pyquickhelper.sphinxext.sphinx_runpython_extension", "sphinxcontrib.googleanalytics", - "sphinx_exec_code", - "sphinx_tabs.tabs", - "onnx_sphinx", + "sphinx.ext.napoleon", ] templates_path = ["_templates"] @@ -100,7 +93,11 @@ # -- Options for intersphinx extension --------------------------------------- # Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {"https://docs.python.org/": None} +intersphinx_mapping = { + "python": ("https://docs.python.org/3", None), + "numpy": ("https://numpy.org/doc/stable", None), + "torch": ("https://pytorch.org/docs/stable/", None), +} # -- Options for Sphinx Gallery ---------------------------------------------- diff --git a/docs/python/inference/examples/README.txt b/docs/python/examples/README.txt similarity index 100% rename from docs/python/inference/examples/README.txt rename to docs/python/examples/README.txt diff --git a/docs/python/inference/examples/Sannosawa1.jpg b/docs/python/examples/Sannosawa1.jpg similarity index 100% rename from docs/python/inference/examples/Sannosawa1.jpg rename to docs/python/examples/Sannosawa1.jpg diff --git a/docs/python/inference/examples/plot_backend.py b/docs/python/examples/plot_backend.py similarity index 100% rename from docs/python/inference/examples/plot_backend.py rename to docs/python/examples/plot_backend.py diff --git a/docs/python/inference/examples/plot_common_errors.py b/docs/python/examples/plot_common_errors.py similarity index 100% rename from docs/python/inference/examples/plot_common_errors.py rename to docs/python/examples/plot_common_errors.py diff --git a/docs/python/inference/examples/plot_convert_pipeline_vectorizer.py b/docs/python/examples/plot_convert_pipeline_vectorizer.py similarity index 100% rename from docs/python/inference/examples/plot_convert_pipeline_vectorizer.py rename to docs/python/examples/plot_convert_pipeline_vectorizer.py diff --git a/docs/python/inference/examples/plot_load_and_predict.py b/docs/python/examples/plot_load_and_predict.py similarity index 100% rename from docs/python/inference/examples/plot_load_and_predict.py rename to docs/python/examples/plot_load_and_predict.py diff --git a/docs/python/inference/examples/plot_metadata.py b/docs/python/examples/plot_metadata.py similarity index 100% rename from docs/python/inference/examples/plot_metadata.py rename to docs/python/examples/plot_metadata.py diff --git a/docs/python/inference/examples/plot_pipeline.py b/docs/python/examples/plot_pipeline.py similarity index 100% rename from docs/python/inference/examples/plot_pipeline.py rename to docs/python/examples/plot_pipeline.py diff --git a/docs/python/inference/examples/plot_profiling.py b/docs/python/examples/plot_profiling.py similarity index 100% rename from docs/python/inference/examples/plot_profiling.py rename to docs/python/examples/plot_profiling.py diff --git a/docs/python/inference/examples/plot_train_convert_predict.py b/docs/python/examples/plot_train_convert_predict.py similarity index 100% rename from docs/python/inference/examples/plot_train_convert_predict.py rename to docs/python/examples/plot_train_convert_predict.py diff --git a/docs/python/inference/examples_md.rst b/docs/python/examples_md.rst similarity index 100% rename from docs/python/inference/examples_md.rst rename to docs/python/examples_md.rst diff --git a/docs/python/inference/index.rst b/docs/python/index.rst similarity index 54% rename from docs/python/inference/index.rst rename to docs/python/index.rst index c99edda46abcd..a1de70ecbf9da 100644 --- a/docs/python/inference/index.rst +++ b/docs/python/index.rst @@ -8,8 +8,22 @@ or the `Github project `_. .. toctree:: :maxdepth: 1 + :caption: Inference tutorial api_summary - auto_examples/index - operators/index + +.. toctree:: + :maxdepth: 1 + :caption: LARGE MODEL TRAINING + + ortmodule/overview + ortmodule/api + +.. toctree:: + :maxdepth: 1 + :caption: ON-DEVICE TRAINING + + on_device_training/overview + on_device_training/training_artifacts + on_device_training/training_api diff --git a/docs/python/inference/notebooks/onnx-inference-byoc-gpu-cpu-aks.ipynb b/docs/python/notebooks/onnx-inference-byoc-gpu-cpu-aks.ipynb similarity index 100% rename from docs/python/inference/notebooks/onnx-inference-byoc-gpu-cpu-aks.ipynb rename to docs/python/notebooks/onnx-inference-byoc-gpu-cpu-aks.ipynb diff --git a/docs/python/inference/notebooks/onnxruntime-tvm-tutorial.ipynb b/docs/python/notebooks/onnxruntime-tvm-tutorial.ipynb similarity index 100% rename from docs/python/inference/notebooks/onnxruntime-tvm-tutorial.ipynb rename to docs/python/notebooks/onnxruntime-tvm-tutorial.ipynb diff --git a/docs/python/notebooks/quantization_f8.ipynb b/docs/python/notebooks/quantization_f8.ipynb new file mode 100644 index 0000000000000..ee3d35a6b7d39 --- /dev/null +++ b/docs/python/notebooks/quantization_f8.ipynb @@ -0,0 +1,800 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "c6b4f765", + "metadata": {}, + "source": [ + "# Quantization\n", + "\n", + "The notebooks compare quantization types." + ] + }, + { + "cell_type": "markdown", + "id": "9333e48c", + "metadata": {}, + "source": [ + "## One matrix\n", + "\n", + "Taken from [MobileNet](https://github.com/onnx/models/tree/main/vision/classification/mobilenet)." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "e26ddb92", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "download 'mobilenetv2-12.onnx'\n", + "done\n", + "model size 13964571 bytes\n" + ] + } + ], + "source": [ + "import os\n", + "import urllib\n", + "\n", + "url = \"https://github.com/onnx/models/raw/main/vision/classification/mobilenet/model/mobilenetv2-12.onnx\"\n", + "destination = \"mobilenetv2-12.onnx\"\n", + "\n", + "if not os.path.exists(destination) or os.stat(destination).st_size < 10000:\n", + " print(f\"download {destination!r}\")\n", + " g = urllib.request.urlopen(url)\n", + " with open(destination, \"wb\") as f:\n", + " f.write(g.read())\n", + " print(\"done\")\n", + "else:\n", + " print(f\"already downloaded {destination!r}\")\n", + "print(f\"model size {os.stat(destination).st_size} bytes\")" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "f75c988a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "model size: 13964571\n" + ] + } + ], + "source": [ + "from onnx import load\n", + "\n", + "with open(destination, \"rb\") as f:\n", + " onx = load(f)\n", + " print(f\"model size: {len(onx.SerializeToString())}\")" + ] + }, + { + "cell_type": "markdown", + "id": "d8581d42", + "metadata": {}, + "source": [ + "Let's take one of the biggest matrix of coefficients:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "358217f6", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(614421, '616')\n", + "(614421, '619')\n", + "(1228821, '625')\n", + "(1638421, '628')\n", + "(5120034, 'classifier.1.weight')\n" + ] + } + ], + "source": [ + "initializers = []\n", + "for init in onx.graph.initializer:\n", + " initializers.append((len(init.SerializeToString()), init.name, init))\n", + "\n", + "initializers.sort()\n", + "\n", + "for init in initializers[-5:]:\n", + " print(init[:2])" + ] + }, + { + "cell_type": "code", + "execution_count": 86, + "id": "3cd9fc33", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "((160, 960, 1, 1), dtype('float32'))" + ] + }, + "execution_count": 86, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from onnx.numpy_helper import to_array\n", + "\n", + "coef = to_array(initializers[-5][-1])\n", + "coef.shape, coef.dtype" + ] + }, + { + "cell_type": "markdown", + "id": "b044ce26", + "metadata": {}, + "source": [ + "## Distributions" + ] + }, + { + "cell_type": "code", + "execution_count": 87, + "id": "374652c6", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA0cAAAGKCAYAAADHUzrAAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAA9hAAAPYQGoP6dpAABxcklEQVR4nO3dd1gUV9sG8Hspu9QFC0UREbFilyhiw4Kiwd5LFI01wRYTjSTGGoPRKBq7JmpiDxp7L1hBIyp2jRq7FOuiqCBwvj/8dl4WdoGlLeL9u665lDNnZp4zuzuzz56ZMzIhhAAREREREdFHzsjQARARERERERUETI6IiIiIiIjA5IiIiIiIiAgAkyMiIiIiIiIATI6IiIiIiIgAMDkiIiIiIiICwOSIiIiIiIgIAJMjIiIiIiIiAEyOiIiIiIiIADA5ony2Z88e1KxZE2ZmZpDJZHjx4gUAYNWqVahUqRJMTU1ha2sLAGjSpAmaNGmi9zZkMhkmTZqUazEXVIcPH4ZMJsPhw4fzfFuTJk2CTCbTKJPJZBg2bFiebxsAVq5cCZlMhjt37uTL9ogob9y5cwcymQwrV66UyrQdX/JK2vOK+ji6cePGfNl+v379UKZMmXzZVmr53U6iDxmTo4/QrVu3MGTIEJQtWxZmZmZQKpVo0KAB5s6dizdv3uTZdp8+fYpu3brB3NwcCxYswKpVq2BpaYlr166hX79+cHNzw7Jly7B06dI8iyG3rF27FnPmzMm19am/MKgnU1NTFC9eHPXr18d3332He/fu5dq2fvrpJ2zZsiXX1pebCnJsRHnt4sWL6NKlC1xcXGBmZgYnJye0aNEC8+bNM3RoBc6jR48wadIkREZGGjqUdApybLkpLCwMkyZNkn7kLKy2bduG2rVrw8zMDKVLl8bEiRORlJSUa+t//fo1Jk2apNcPnSkpKZgxYwZcXV1hZmaG6tWrY926dVle/sWLFxg8eDDs7OxgaWmJpk2b4uzZs1rrZqX9UVFRGDduHJo2bQpra+tMf7gNCwtDw4YNYWFhAUdHR4wYMQKvXr3Kcvx5TtBHZceOHcLc3FzY2tqKESNGiKVLl4r58+eLHj16CFNTUzFo0KA82/bu3bsFALF//36N8kWLFgkA4saNGxrlCQkJIiEhQe/tvHnzRrx79y5HsWbGz89PuLi45Nr6bt++LQCInj17ilWrVok//vhDzJkzR/Tu3VuYm5sLCwsLsW7dOo1lkpOTxZs3b0RycrJe27K0tBT+/v56LfPu3Tvx5s0bjTIAIiAgQK/1ZEZXbElJSeLNmzciJSUlV7dHVFCcOHFCyOVyUa5cOTF16lSxbNkyMWHCBNGyZUvh5uZm6PByjfpYt2LFCqlM2/ElM6dPn063nqxIe14JDQ0VAERISIhe68lubImJieLt27e5tq2syot2zpw5UwAQt2/fzrV1FjS7du0SMplMNG3aVCxdulQMHz5cGBkZiaFDh+baNh4/fiwAiIkTJ2Z5mXHjxgkAYtCgQWLp0qXCz89PAEj3PUGb5ORkUb9+fWFpaSkmTZok5s+fL9zd3YW1tbX4999/Nepmtf3q91f58uWFl5eXACBCQ0O1bv/cuXPCzMxM1KpVSyxatEh8//33QqFQiFatWmW5/XnNxAD5GBnI7du30aNHD7i4uODQoUMoUaKENC8gIAA3b97Ezp0782z7sbGxACBdNpdZuVwuz9Z2zMzMsrVcQVC7dm189tlnGmV3795Fy5Yt4e/vj8qVK6NGjRoAACMjozxva3x8PCwtLWFiYgITE8MdLoyNjWFsbGyw7RPltWnTpsHGxganT5/WeYwsrPLj+PL69WtYWFhk+7ySW0xNTQ26fdLPN998g+rVq2Pfvn3Se1SpVOKnn37CyJEjUalSpXyP6eHDh5g1axYCAgIwf/58AMDAgQPh7e2NMWPGoGvXrhmeLzdu3IiwsDCEhISgS5cuAIBu3bqhQoUKmDhxItauXSvVzWr7PTw88PTpUxQtWhQbN25E165ddW7/u+++Q5EiRXD48GEolUoAQJkyZTBo0CDs27cPLVu2zNkOyg2Gzs4o/wwdOlQAECdOnMhS/Xfv3okpU6aIsmXLCrlcLlxcXERgYKDWX7127dolGjZsKCwsLISVlZX49NNPxaVLl6T53t7eAoDG5O/vL1xcXNKVq3898fb2Ft7e3hrbefPmjZg4caIoX768UCgUwtHRUXTs2FHcvHlTqgMtv8A8ePBA9O/fX9jb2wu5XC7c3d3F77//rlFH/cvHhg0bxI8//iicnJyEQqEQzZo10+jV0taW1L1Iv/76q3B3d5d66Dw8PMSaNWsy3NfqX1NnzpypdX5YWJgAIHr16pUu3tS/zvz777+iU6dOwsHBQSgUCuHk5CS6d+8uXrx4Ie0bba+DEEJMnDhRABCXL18WPXv2FLa2tqJmzZoa81LD//ccrV69WlSoUEEoFApRu3ZtceTIEY166tc5rbTrzCi2FStWaP2FcsGCBcLd3V3I5XJRokQJ8eWXX4rnz59r1PH29hZVqlQRly9fFk2aNBHm5uaiZMmS4ueff9a6r4kMoWLFiqJJkyZZqrt8+XLRtGlTYWdnJ+RyuahcubJYuHBhunouLi7Cz89PhIaGCg8PD2FmZiaqVq0qHTM2bdokqlatKn12z549m24dV69eFZ07dxZFihQRCoVCeHh4iK1bt2YpzufPnwt/f3+hVCqFjY2N6Nu3rzh37ly6XhVtx5d9+/aJBg0aCBsbG2FpaSkqVKggAgMDhRD/O/alndTrVH/mIyIiRKNGjYS5ubkYOXKkNC/1eUW9rvXr14vAwEDh4OAgLCwsRNu2bcW9e/fS7U9tPdup15lZbNqOh69evRKjR48WpUqVEnK5XFSoUEHMnDkzXU+5+pi7efNmUaVKFelctnv37kxfC33aKYQQJ0+eFL6+vkKpVApzc3PRuHFjcfz4cWm++jVLO92+fVt07NhR1KpVS2N9bdq0EQA03jsnT54UAMSuXbuksufPn4uRI0dK+8LNzU1Mnz493RUSycnJIjg4WLi7uwuFQiHs7e3F4MGDxbNnzzTqqT8Dx44dE3Xq1BEKhUK4urqKP/74I9N9dvnyZQFALFiwQKP84cOHAoCYOnVqpuvIrD3qc7+u70HaLFiwQDpXp7Z27VoBQBw7dizDmLp27SocHBzS7dPBgwcLCwsL6TtedtsfEhKis+dIpVIJExMTMWbMGI3yhIQEYWVlJQYMGJBh7PmFPUcfke3bt6Ns2bKoX79+luoPHDgQf/zxB7p06YKvv/4ap06dQlBQEK5evYrNmzdL9VatWgV/f3/4+vri559/xuvXr7Fo0SI0bNgQ586dQ5kyZfD999+jYsWKWLp0KaZMmQJXV1e4ubmhQ4cO+PPPP7F582YsWrQIVlZWqF69utZ4kpOT0aZNGxw8eBA9evTAyJEj8fLlS+zfvx+XLl2Cm5ub1uViYmJQr149aQABOzs77N69GwMGDEBcXBxGjRqlUX/69OkwMjLCN998A5VKhRkzZqB37944deoUAOD777+HSqXCgwcPEBwcDACwsrICACxbtgwjRoxAly5dMHLkSLx9+xYXLlzAqVOn0KtXryztd228vLzg5uaG/fv366yTmJgIX19fJCQkYPjw4XB0dMTDhw+xY8cOvHjxAjY2Nli1ahUGDhyIunXrYvDgwQCQbr917doV5cuXx08//QQhRIZxHTlyBBs2bMCIESOgUCiwcOFCtGrVCv/88w+qVq2qVxuzEltqkyZNwuTJk+Hj44MvvvgC169fx6JFi3D69GmcOHFC4xfa58+fo1WrVujUqRO6deuGjRs34ttvv0W1atXQunVrveIkygsuLi4IDw/HpUuXMv3sLFq0CFWqVEG7du1gYmKC7du348svv0RKSgoCAgI06t68eRO9evXCkCFD8Nlnn+GXX35B27ZtsXjxYnz33Xf48ssvAQBBQUHo1q0brl+/DiOj97cjX758GQ0aNICTkxPGjRsHS0tL/PXXX+jQoQM2bdqEjh076oxRCIH27dvj+PHjGDp0KCpXrozNmzfD398/031x+fJltGnTBtWrV8eUKVOgUChw8+ZNnDhxAgBQuXJlTJkyBRMmTMDgwYPRqFEjANA4tz19+hStW7dGjx498Nlnn8HBwSHDbU6bNg0ymQzffvstYmNjMWfOHPj4+CAyMhLm5uaZxqyWldhSE0KgXbt2CA0NxYABA1CzZk3s3bsXY8aMwcOHD6VzjNrx48fx999/48svv4S1tTV+/fVXdO7cGffu3UOxYsUyjS8r7Tx06BBat24NDw8PTJw4EUZGRlixYgWaNWuGY8eOoW7duujUqRP+/fdfrFu3DsHBwShevDgAwM7ODo0aNcLWrVsRFxcHpVIJIQROnDgBIyMjHDt2DO3atQMAHDt2DEZGRmjQoAGA97173t7eePjwIYYMGYLSpUsjLCwMgYGBiIqK0rjPd8iQIVi5ciX69++PESNG4Pbt25g/fz7OnTuX7vh/8+ZNdOnSBQMGDIC/vz+WL1+Ofv36wcPDA1WqVNG5r86dOwcA+OSTTzTKS5YsiVKlSknzdclKe+zs7LBo0SJ88cUX6NixIzp16gQAOr8HqeOytLRE5cqVNcrr1q0rzW/YsGGGy9euXVv6nKdefunSpfj3339RrVq1HLdfm4sXLyIpKSndOuVyOWrWrJmtdeYJw+ZmlF9UKpUAINq3b5+l+pGRkQKAGDhwoEb5N998IwCIQ4cOCSGEePnypbC1tU13r1J0dLSwsbHRKFf/+n/69GmNuupfoB4/fqxRnvYXvuXLlwsAYvbs2eniTf0LG9L86jJgwABRokQJ8eTJE41levToIWxsbMTr16+FEP/7Za1y5coa16TPnTtXABAXL16UynTdc9S+fXtRpUqVdOWZyaznSL1uAEKlUmnEq/51Rv2LbGbXlOu6r0f9OvTs2VPnvNTw/79wRURESGV3794VZmZmomPHjlJZVnuOMootbc9RbGyskMvlomXLlhq/fs2fP18AEMuXL5fK1D19f/75p1SWkJAgHB0dRefOndNti8gQ9u3bJ4yNjYWxsbHw8vISY8eOFXv37hWJiYnp6qqPWan5+vqKsmXLapSpe+bDwsKksr179woAwtzcXNy9e1cqX7JkSbpfe5s3by6qVaumcbVASkqKqF+/vihfvnyG7dmyZYsAIGbMmCGVJSUliUaNGmXacxQcHKz1nJBaRvf1qD/zixcv1jpPW8+Rk5OTiIuLk8r/+usvAUDMnTtXKstKz1FmsaU9Hqr3048//qhRr0uXLkImk6W7KkIul2uUnT9/XgAQ8+bNS7et1LLazpSUFFG+fHnh6+urcV59/fq1cHV1FS1atJDKdN1zpG6/ukfowoULAoDo2rWr8PT0lOq1a9dOo4dp6tSpwtLSMt19L+PGjRPGxsZSD9exY8cEgHRXZOzZsyddufozcPToUaksNjZWKBQK8fXXX2e4z9Tt09azVqdOHVGvXr0Ml89qe/S958jPzy/dZ10IIeLj4wUAMW7cuAyXt7S0FJ9//nm68p07dwoAYs+ePUKI7Lc/o54j9bzUr4da165dhaOjY4ax5xeOVveRiIuLAwBYW1tnqf6uXbsAAKNHj9Yo//rrrwFAujdp//79ePHiBXr27IknT55Ik7GxMTw9PREaGppbTcCmTZtQvHhxDB8+PN08XcPACiGwadMmtG3bFkIIjRh9fX2hUqnSjdDSv39/jevS1b/8/ffff5nGaGtriwcPHuD06dP6NC1L1L1TL1++1DrfxsYGALB37168fv0629sZOnRolut6eXnBw8ND+rt06dJo37499u7di+Tk5GzHkJkDBw4gMTERo0aN0vj1a9CgQVAqlenunbOystK4l0sul6Nu3bpZek2J8kOLFi0QHh6Odu3a4fz585gxYwZ8fX3h5OSEbdu2adRN3ZOhUqnw5MkTeHt747///oNKpdKo6+7uDi8vL+lvT09PAECzZs1QunTpdOXqz8SzZ89w6NAhdOvWDS9fvpSOm0+fPoWvry9u3LiBhw8f6mzPrl27YGJigi+++EIqMzY21nr8Tkt9z9XWrVuRkpKSaX1tFAoF+vfvn+X6ffv21Tg/dunSBSVKlJDOhXll165dMDY2xogRIzTKv/76awghsHv3bo1yHx8fjR716tWrQ6lUZvlYllk7IyMjcePGDfTq1QtPnz6VXvf4+Hg0b94cR48ezfQ1qVWrFqysrHD06FEA73uISpUqhb59++Ls2bN4/fo1hBA4fvy4dH4FgJCQEDRq1AhFihTROFf7+PggOTlZWl9ISAhsbGzQokULjXoeHh6wsrJK973D3d1dYzt2dnaoWLFipvtMPXqvQqFIN8/MzCzT0X2z2h59vXnzRmdMqePO6fI5bb+ubef2OvMCL6v7SKhvetP1xTqtu3fvwsjICOXKldMod3R0hK2tLe7evQsAuHHjBoD3J9qMtpsbbt26hYoVK+p14+7jx4/x4sULLF26VOcQ4Wlvdk79hQEAihQpAuD9pVmZ+fbbb3HgwAHUrVsX5cqVQ8uWLdGrVy/psoGcUA9zqSvBdXV1xejRozF79mysWbMGjRo1Qrt27fDZZ59JiVNWuLq6Zrlu+fLl05VVqFABr1+/xuPHj+Ho6JjldelD/f6rWLGiRrlcLkfZsmWl+WqlSpVKl0AXKVIEFy5cyJP4iLKjTp06+Pvvv5GYmIjz589j8+bNCA4ORpcuXRAZGQl3d3cAwIkTJzBx4kSEh4en+yFEpVJpfN7THs/U85ydnbWWq49zN2/ehBACP/zwA3744Qet8cbGxsLJyUnrvLt376JEiRLSjzpqaT+z2nTv3h2//fYbBg4ciHHjxqF58+bo1KkTunTpku5SIF2cnJz0Gnwh7bFMJpOhXLlyef5stbt376JkyZLpjuvqS6bSHsvSvp7A+2NZVs5PQObtVJ/TM7r8UaVSSedFbYyNjeHl5YVjx44BeJ8cNWrUCA0bNkRycjJOnjwJBwcHPHv2TCNpuXHjBi5cuAA7Ozut61Wfq2/cuAGVSgV7e/sM66lld5+pf4RISEhIN+/t27eZXm6Z1fboy9zcXGdM6vm5sXxO269r27m9zrzA5OgjoVQqUbJkSVy6dEmv5TJ7MJ/6F6RVq1Zp/SJsyBHOgP/F99lnn+k82Ke9tlfXKC8ik/tvgPcntOvXr2PHjh3Ys2cPNm3ahIULF2LChAmYPHmyntFrunTpEuzt7TNMOGfNmoV+/fph69at2LdvH0aMGIGgoCCcPHkSpUqVytJ2cvvgpOs9lJc9S2nl5DUlym9yuRx16tRBnTp1UKFCBfTv3x8hISGYOHEibt26hebNm6NSpUqYPXs2nJ2dIZfLsWvXLgQHB6f7VV/Xez+zz4R6Pd988w18fX211k3741luMTc3x9GjRxEaGoqdO3diz5492LBhA5o1a4Z9+/ZlaeTKvPiSldGxLL9G08zrY5n6dZ85cyZq1qyptU7ahFebhg0bYtq0aXj79i2OHTuG77//Hra2tqhatSqOHTsm3QOWOjlKSUlBixYtMHbsWK3rrFChglTP3t4ea9as0VovbTKS3X2mHtE3Kioq3Y8JUVFR0j0+umS1PfoqUaIEQkNDIYTQeE9GRUUBeH9PUGbLq+umlnb5nLZf17ZTbyvtOjOLPb8wOfqItGnTBkuXLkV4eLjGZRbauLi4ICUlBTdu3NC46S8mJgYvXryAi4sLgP/dMG9vbw8fH5+8C/7/t3Xq1Cm8e/cuy8Oh2tnZwdraGsnJybkaX0ZJo6WlJbp3747u3bsjMTERnTp1wrRp0xAYGJjtobfDw8Nx69atdMN8a1OtWjVUq1YN48ePR1hYGBo0aIDFixfjxx9/zDR2fal/ZUzt33//hYWFhXSCKlKkiNaHBKb9RVSf2NTvv+vXr6Ns2bJSeWJiIm7fvp3n70Wi/KK+cVn9ZWL79u1ISEjAtm3bNH4Rz81LmAFInytTU9NsfZ5cXFxw8OBBvHr1SuPL9PXr17O0vJGREZo3b47mzZtj9uzZ+Omnn/D9998jNDQUPj4+uXocA9Ify4QQuHnzpsaPZxkdy1Ifh/SJzcXFBQcOHMDLly81eo+uXbsmzc9NmbVTfU5XKpWZvu4ZtbNRo0ZITEzEunXr8PDhQykJaty4sZQcVahQQWOgDDc3N7x69SrT7bq5ueHAgQNo0KBBnvY0qJPDiIgIjUTg0aNHePDggTRwUEZxZqU9+r6Xa9asid9++w1Xr16VepMBSING6UpqUy9/7NgxpKSkaPTEnjp1ChYWFlLSltP2a1O1alWYmJggIiIC3bp1k8oTExMRGRmpUWZIvOfoIzJ27FhYWlpi4MCBiImJSTf/1q1bmDt3LgDg008/BQCN0WEAYPbs2QAAPz8/AICvr6805v27d+/SrfPx48e5Fn/nzp3x5MkTaVz/1HT9AmRsbIzOnTtj06ZNWnvNshufpaVlumv7gfcjJKUml8vh7u4OIYTW/ZMVd+/eRb9+/SCXyzFmzBid9eLi4tI9tbpatWowMjLS6MK2tLTMtSeah4eHa9yzdf/+fWzduhUtW7aUfq1zc3ODSqXSuIQtKipKY8RDfWPz8fGBXC7Hr7/+qvHa//7771CpVNL7k+hDof4lOC31vSDqy9HUn6vUdVUqFVasWJGr8djb26NJkyZYsmSJ1l95Mzt2fvrpp0hKSsKiRYuksuTkZMybNy/TbT979ixdmfqLmvpYZmlpCQC5diz7888/NS4737hxI6KiojRGs3Rzc8PJkyeRmJgole3YsQP379/XWJc+sX366adITk5Od14LDg6GTCbL9dE0M2unh4cH3Nzc8Msvv0iXcqeW+nXPqJ2enp4wNTXFzz//jKJFi0qjwjVq1AgnT57EkSNHNHqNgPfP2gkPD8fevXvTre/FixfS+a1bt25ITk7G1KlT09VLSkrKtfdElSpVUKlSJSxdulTjSodFixZBJpNJzwjSJavtsbCwkMqyon379jA1NcXChQulMiEEFi9eDCcnJ42REaOionDt2jWN7x9dunRBTEwM/v77b6nsyZMnCAkJQdu2baX7gXLafm1sbGzg4+OD1atXa7wPV61ahVevXmX4fKT8xJ6jj4ibmxvWrl2L7t27o3Llyujbty+qVq2KxMRE6YFg/fr1AwDUqFED/v7+WLp0KV68eAFvb2/8888/+OOPP9ChQwc0bdoUwPtflxYtWoQ+ffqgdu3a6NGjB+zs7HDv3j3s3LkTDRo00JrMZEffvn3x559/YvTo0fjnn3/QqFEjxMfH48CBA/jyyy/Rvn17rctNnz4doaGh8PT0xKBBg+Du7o5nz57h7NmzOHDggNYTcWY8PDywYcMGjB49GnXq1IGVlRXatm2Lli1bwtHREQ0aNICDgwOuXr2K+fPnw8/PL0uDYZw9exarV69GSkoKXrx4gdOnT2PTpk2QyWRYtWpVhsN7Hjp0CMOGDUPXrl1RoUIFJCUlYdWqVVKCmDr2AwcOYPbs2ShZsiRcXV2lm7H1VbVqVfj6+moM5Q1A4xLCHj164Ntvv0XHjh0xYsQIaaj3ChUqpBsMI6ux2dnZITAwEJMnT0arVq3Qrl07XL9+HQsXLkSdOnWy1MNGVJAMHz4cr1+/RseOHVGpUiXpuLxhwwaUKVNGGlygZcuWkMvlaNu2LYYMGYJXr15h2bJlsLe315rE5MSCBQvQsGFDVKtWDYMGDULZsmURExOD8PBwPHjwAOfPn9e5bNu2bdGgQQOMGzcOd+7cgbu7O/7++2+tPyqlNWXKFBw9ehR+fn5wcXFBbGwsFi5ciFKlSklDFLu5ucHW1haLFy+GtbU1LC0t4enpqdc9k6kVLVoUDRs2RP/+/RETE4M5c+agXLlyGDRokFRn4MCB2LhxI1q1aoVu3brh1q1bWL16dbpHDugTW9u2bdG0aVN8//33uHPnDmrUqIF9+/Zh69atGDVqVIaPM8iLdhoZGeG3335D69atUaVKFfTv3x9OTk54+PAhQkNDoVQqsX37dgCQBuP5/vvv0aNHD5iamqJt27awtLSEhYUFPDw8cPLkSbRt21bqHWncuDHi4+MRHx+fLjkaM2YMtm3bhjZt2khDbcfHx+PixYvYuHEj7ty5g+LFi8Pb2xtDhgxBUFAQIiMj0bJlS5iamuLGjRsICQnB3Llzs/XFXZuZM2eiXbt2aNmyJXr06IFLly5h/vz5GDhwYLqhtNPKanvMzc3h7u6ODRs2oEKFCihatCiqVq2qc0j/UqVKYdSoUZg5cybevXuHOnXqYMuWLTh27BjWrFmjcRlhYGAg/vjjD9y+fRtlypQB8D45qlevHvr3748rV66gePHiWLhwIZKTk9Nd/q9P+9VXp1y+fBnA+4Tn+PHjAIDx48dL9aZNm4b69evD29sbgwcPxoMHDzBr1iy0bNkSrVq1ysKrkg/yeXQ8KgD+/fdfMWjQIFGmTBkhl8uFtbW1aNCggZg3b57GkK3v3r0TkydPFq6ursLU1FQ4OzvrfAhsaGio8PX1FTY2NsLMzEy4ubmJfv36aQzznNOhvIV4P5zo999/L8Xk6OgounTpIm7duiXVgZYhMWNiYkRAQIBwdnaWlmvevLlYunSpRhugZShs9TDbqYdlffXqlejVq5ewtbUVSPUQ2CVLlojGjRuLYsWKCYVCIdzc3MSYMWOk4bd1SfsgOBMTE1G0aFHh6ekpAgMDNYbcTRuverjM//77T3z++efCzc1NmJmZiaJFi4qmTZuKAwcOaCx37do10bhxY2Fubi6g5SGw2obPzewhsOqH8taqVUvr8J379u0TVatWFXK5XFSsWFGsXr1a6zp1xabrIbDz588XlSpVEqampsLBwUF88cUXOh8Cm5auIcaJDGH37t3i888/F5UqVRJWVlZCLpeLcuXKieHDh4uYmBiNutu2bRPVq1cXZmZmokyZMuLnn3+WHnWQ+jOifgBmWurPbmq6Hidw69Yt0bdvX+Ho6ChMTU2Fk5OTaNOmjdi4cWOmbXr69Kno06eP9BDYPn36ZOkhsAcPHhTt27cXJUuWFHK5XJQsWVL07Nkz3ZDIW7duFe7u7sLExERjnbo+8+p52obyXrdunQgMDBT29vbC3Nxc+Pn5aT3uzpo1S3pAeIMGDURERITWc5Wu2LQdd16+fCm++uorUbJkSWFqairKly+f4UNg09I1xHhq+rbz3LlzolOnTtK5zMXFRXTr1k0cPHhQo97UqVOFk5OTMDIySvf+GzNmjACQ7oHb5cqVEwA0ztup90VgYKAoV66ckMvlonjx4qJ+/fril19+STes/dKlS4WHh4cwNzcX1tbWolq1amLs2LHi0aNHGvtG22dA22umy+bNm0XNmjWFQqEQpUqVEuPHj9c6xL42WW1PWFiY8PDwEHK5PEvDeicnJ4uffvpJuLi4CLlcLqpUqSJWr16drp6/v7/Wc+ezZ8/EgAEDRLFixYSFhYXw9vZO991M3/an/g6Tdkrr2LFjon79+sLMzEzY2dmJgIAAjSHmDU0mBO9IJiIiIiIi4j1HREREREREYHJEREREREQEgMkRERERERERACZHREREREREAJgcERERERERAWByRFSozJs3D6tWrdJ7uXfv3mH69OnS8yuIiOjDlJPjuUqlwpQpU3Ds2LE8iIzow8DkiHKkSZMmaNKkSZbr6nqoGeXcvHnzMGXKFNSrV0+j/M6dO5DJZFi5cqXOZceNG4fffvst3bJERPRh0XU8P3z4MGQyGQ4fPqxz2QEDBmD37t345JNP8jhKooKLyRHlqkePHmHSpEmIjIzM9XXv27cPAwYMQNWqVWFsbCw97TktdTKgbVq/fr1G3WXLlsHb2xsODg5QKBRwdXVF//79cefOHa3rjomJwZAhQ+Dk5AQzMzOUKVMGAwYMSFfv4cOH6NatG2xtbaFUKtG+fXv8999/Wtf5+++/o3LlyjAzM0P58uUxb948vfYLAJw+fRoTJkzA9u3bUb58eb2W3bp1K1avXo09e/bAzs5O723ntytXrmDSpEk6XyMiorzSr18/necXmUyGhw8fSnV/+ukn1KtXD3Z2dtLxfdSoUXj8+HG69UZFRWHw4MFwdXWFubk53NzcMHr0aDx9+lSv+HJyPJ87dy4uXLiA7du3w9zcXK9lDSEsLAyTJk3CixcvDB0KFTImhg6APmz79u3T+PvRo0eYPHkyypQpg5o1a+bqttauXYsNGzagdu3aKFmyZKb1e/bsiU8//VSjzMvLS+Pvc+fOwdXVFe3atUORIkVw+/ZtLFu2DDt27MD58+c1tnP//n00aNAAADB06FA4OTnh0aNH+OeffzTW+erVKzRt2hQqlQrfffcdTE1NERwcDG9vb0RGRqJYsWJS3SVLlmDo0KHo3LkzRo8ejWPHjmHEiBF4/fo1vv322yzvm8uXL2PTpk3Z6vm5c+cOdu/ejXLlyum9rCFcuXIFkydPRpMmTXQmyEREeWHIkCHw8fHRKBNCYOjQoShTpgycnJyk8jNnzqBmzZro0aMHrK2tcfXqVSxbtgw7d+5EZGQkLC0tAbw/Z3h5eSE+Ph5ffvklnJ2dcf78ecyfPx+hoaE4c+YMjIyy9lt2do/niYmJiI+Px549e1C8eHG9ljWUsLAwTJ48Gf369YOtra2hw6HCRBDlotOnTwsAYsWKFenmeXt7iypVqmR73Q8fPhSJiYlCCCH8/PyEi4uL1nq3b98WAMTMmTOztZ2IiAgBQAQFBWmUt27dWri6uoonT55kuPzPP/8sAIh//vlHKrt69aowNjYWgYGBUtnr169FsWLFhJ+fn8byvXv3FpaWluLZs2fZij8t9f7Q9pp8iEJCQgQAERoaauhQiIjEsWPHBAAxbdq0TOtu3LhRABDr1q2TytasWSMAiB07dmjUnTBhggAgzp49mytxhoaGFqpj58yZMwUAcfv2bUOHQoUML6sjXLhwATKZDNu2bZPKzpw5A5lMhtq1a2vUbd26NTw9PaW/U99zdPjwYdSpUwcA0L9/f+kyg7T3uly5cgVNmzaFhYUFnJycMGPGjCzFWbJkSZiamurVtvj4eCQmJuq1jLo3InVX/bVr17B7926MGTMGxYoVw9u3b/Hu3Tuty2/cuBF16tSR9gUAVKpUCc2bN8dff/0llYWGhuLp06f48ssvNZYPCAhAfHw8du7cmWmsDx8+xOeffy5dFlilShUsX748S+28du0aunTpgqJFi8LMzAyffPKJxnsAAFauXAmZTIbjx49jxIgRsLOzg62tLYYMGYLExES8ePECffv2RZEiRVCkSBGMHTsWQgiNdaSkpGDOnDmoUqUKzMzM4ODggCFDhuD58+ca9cqUKYM2bdrg+PHjqFu3LszMzFC2bFn8+eefGvF07doVANC0aVPpPaa+hj4iIgK+vr4oXrw4zM3N4erqis8//zxL+4OIKDvWrl0LmUyGXr16ZVpX2/klLi4OAODg4KBRt0SJEgCQpUvcsnI81+XUqVNo1aoVbGxsYGFhAW9vb5w4cUKjzqRJkyCTyfDvv//is88+g42NDezs7PDDDz9ACIH79++jffv2UCqVcHR0xKxZs9JtJyEhARMnTkS5cuWgUCjg7OyMsWPHIiEhQaOeTCbDsGHDsGXLFlStWlU6t+3Zs0cjnjFjxgAAXF1dpXOB+nLr/fv3o2HDhrC1tYWVlRUqVqyI7777Lkv7g4jJEaFq1aqwtbXF0aNHpbJjx47ByMgI58+flw7cKSkpCAsLQ+PGjbWup3LlypgyZQoAYPDgwVi1ahVWrVqlUf/58+do1aoVatSogVmzZqFSpUr49ttvsXv37lxv1+TJk2FlZQUzMzPUqVMn3SWAqT19+hSxsbGIiIhA//79AQDNmzeX5h84cADA+5NX8+bNYW5uDnNzc7Ru3Vrj3peUlBRcuHBB682sdevWxa1bt/Dy5UsA7y/pA5CuroeHB4yMjKT5usTExKBevXo4cOAAhg0bhrlz56JcuXIYMGAA5syZk+Gyly9fRr169XD16lWMGzcOs2bNgqWlJTp06IDNmzenqz98+HDcuHEDkydPRrt27bB06VL88MMPaNu2LZKTk/HTTz+hYcOGmDlzZrrR8oYMGYIxY8agQYMGmDt3Lvr37481a9bA19c3XYJ58+ZNdOnSBS1atMCsWbNQpEgR9OvXD5cvXwYANG7cGCNGjAAAfPfdd9J7rHLlyoiNjUXLli1x584djBs3DvPmzUPv3r1x8uTJDPcFEVF2vXv3Dn/99Rfq16+v9TJfIQSePHmC6Oho6bJpY2NjjYGMGjduDCMjI4wcORInT57EgwcPsGvXLkybNg0dOnRApUqVMoxB3+N5aocOHULjxo0RFxeHiRMn4qeffsKLFy/QrFmzdJeMA0D37t2RkpKC6dOnw9PTEz/++CPmzJmDFi1awMnJCT///DPKlSuHb775RuM7RUpKCtq1a4dffvkFbdu2xbx589ChQwcEBweje/fu6bZz/PhxfPnll+jRowdmzJiBt2/fonPnztI9WJ06dULPnj0BAMHBwdK5wM7ODpcvX0abNm2QkJCAKVOmYNasWWjXrl26hI9IJwP3XFEB4efnJ+rWrSv93alTJ9GpUydhbGwsdu/eLYQQ4uzZswKA2Lp1q1TP29tbeHt7S39ndlkdAPHnn39KZQkJCcLR0VF07txZ73h1XVZ39+5d0bJlS7Fo0SKxbds2MWfOHFG6dGlhZGSU7rIFNYVCIQAIAKJYsWLi119/1Zg/YsQIaV6rVq3Ehg0bxMyZM4WVlZVwc3MT8fHxQgghHj9+LACIKVOmpNvGggULBABx7do1IYQQAQEBwtjYWGs8dnZ2okePHhnugwEDBogSJUqku8yvR48ewsbGRrx+/VoIof2yuubNm4tq1aqJt2/fSmUpKSmifv36onz58lLZihUrBADh6+srUlJSpHIvLy8hk8nE0KFDpbKkpCRRqlQpjfeD+nKTNWvWaMS4Z8+edOUuLi4CgDh69KhUFhsbKxQKhfj666+lMl2X1W3evFkAEKdPn85otxER5Zrt27cLAGLhwoVa50dFRUnnFgCiVKlSYsOGDenq/fbbb8LW1lajrr+/v3j37l2mMWT1eJ72srqUlBRRvnz5dMf3169fC1dXV9GiRQupbOLEiQKAGDx4sFSmPubLZDIxffp0qfz58+fC3Nxc+Pv7S2WrVq0SRkZG4tixYxqxL168WAAQJ06ckMoACLlcLm7evCmVnT9/XgAQ8+bNk8p0XVYXHBwsAIjHjx9ntuuItGLPEQEAGjVqhLNnzyI+Ph7A+19tPv30U9SsWVN63sGxY8cgk8nQsGHDbG/HysoKn332mfS3XC5H3bp1dY7klh2lS5fG3r17MXToULRt2xYjR47EuXPnYGdnh6+//lrrMrt378auXbswa9YslC5dWtoPaq9evQIAODo6YufOnejWrRu++eYbLFu2DLdu3cLatWsBAG/evAEAKBSKdNswMzPTqPPmzRvI5XKt8ZiZmUn1tBFCYNOmTWjbtq30y6R68vX1hUqlwtmzZ7Uu++zZMxw6dAjdunXDy5cvpeWePn0KX19f3LhxQ2PEJeD98K4ymUz629PTE0IIjZH6jI2N8cknn2i8liEhIbCxsUGLFi00YvTw8ICVlRVCQ0M1tuPu7o5GjRpJf9vZ2aFixYpZen+ob8jdsWOHzkseiYhy09q1a2Fqaopu3bppnV+0aFHs378f27dvx5QpU1C8eHHpfJKak5MT6tatizlz5mDz5s0YPXo01qxZg3HjxmW4/ewcz9UiIyNx48YN9OrVC0+fPpWWjY+PR/PmzXH06FGkpKRoLDNw4EDp/+pjftpzga2tbbrjdkhICCpXroxKlSppnAuaNWsGAOnOBT4+PnBzc5P+rl69OpRKpV7ngq1bt6aLnygrOFodAXifHCUlJSE8PBzOzs6IjY1Fo0aNcPnyZY3kyN3dHUWLFs32dkqVKqXxJRsAihQpggsXLuQo/swULVoU/fv3x/Tp0/HgwQOUKlVKY37Tpk0BvL+nqn379qhatSqsrKwwbNgwAP+75rtbt24aowZ17doVffr0QVhYGAYOHCjVS3sNNQC8fftWY13m5uY674d6+/ZthteZP378GC9evMDSpUuxdOlSrXViY2O1lt+8eRNCCPzwww/44YcfdC6betSl0qVLa8y3sbEBADg7O6crT30v0Y0bN6BSqWBvb5+lGNNuB3j//kh7f5I23t7e6Ny5MyZPnozg4GA0adIEHTp0QK9evbQmq0REOfHq1Sts3boVvr6+GqOQpiaXy6XR7dq0aYPmzZujQYMGsLe3R5s2bQAAJ06cQJs2bXDy5EnpMusOHTpAqVRi8uTJ+Pzzz+Hu7q51/dk5nqvduHEDAODv76+zjSqVCkWKFJH+1nYuMDMzSzfCnY2NjcYw5Ddu3MDVq1d1Di+em+eC7t2747fffsPAgQMxbtw4NG/eHJ06dUKXLl2yPOoffdyYHBGA9/e9mJmZ4ejRoyhdujTs7e1RoUIFNGrUCAsXLkRCQgKOHTuGjh075mg7xsbGWstFmpv484L6i/yzZ8/SJUepubm5oVatWlizZo2UHKmH9E57w6yxsTGKFSsmHbCLFi0KhUKBqKiodOtVl6nXVaJECSQnJyM2NlYjeUhMTMTTp08zHK5c/WvYZ599pvPEVr169QyX/eabb+Dr66u1TtphYHW9btrKU7+WKSkpsLe3x5o1a7Qun/ZEmZP3h0wmw8aNG3Hy5Els374de/fuxeeff45Zs2bh5MmTsLKyynQdRERZtWXLFrx+/Rq9e/fO8jL169dHiRIlsGbNGik5WrJkCRwcHNLdf9quXTtMmjQJYWFhOpOj7BzP0y47c+ZMnY/eSHvc1HaMzspxOyUlBdWqVcPs2bO11k37Q1tOzgXm5uY4evQoQkNDsXPnTuzZswcbNmxAs2bNsG/fPp3rJlJjckQA/nd527Fjx1C6dGnp0qZGjRohISEBa9asQUxMjM7BGNTS9goVJOru+Kw8GO/NmzcavT8eHh4AkO7yhMTERDx58kRap5GREapVq4aIiIh06zx16hTKli0La2trAJBORhERERrPY4qIiEBKSkqGz4mys7ODtbU1kpOT0z1zIzNly5YFAJiamuq9rL7c3Nxw4MABNGjQINceKpjZe6xevXqoV68epk2bhrVr16J3795Yv369xuUgREQ5tWbNGlhZWaFdu3Z6Lff27VuoVCrp75iYGCQnJ6erp748OCkpSee6cnI8V1+2plQq8+VccP78eTRv3jzXvidktB4jIyM0b94czZs3x+zZs/HTTz/h+++/R2hoaJ63lT587F8kSaNGjXDq1CmEhoZKyVHx4sVRuXJl/Pzzz1KdjKgfamfIJ1Zre/r4w4cPsXz5clSvXl0aHjUpKUlrF/0///yDixcvavyK16RJE6kHRH15HPB+aOnk5GS0aNFCKuvSpQtOnz6tkSBdv34dhw4dkoahBoBmzZqhaNGiWLRokcb2Fy1aBAsLC/j5+elso7GxMTp37oxNmzbh0qVLWdoHavb29mjSpAmWLFmitYcro2X11a1bNyQnJ2Pq1Knp5iUlJWXrfaLrPfb8+fN0vyqqE0xtlzkSEWXX48ePceDAAXTs2BEWFhbp5sfHx+P169fpyjdt2oTnz59rnF8qVKiAmJgY6ZEEauvWrQMA1KpVS2ccOTmee3h4wM3NDb/88ovW+6By+1zw8OFDLFu2LN28N2/epLvPNyt0nQuePXuWri7PBaQP9hyRpFGjRpg2bRru37+vkQQ1btwYS5YsQZkyZTK8HA14/+uQra0tFi9eDGtra1haWsLT0xOurq45ju/ChQvScxtu3rwJlUqFH3/8EQBQo0YNtG3bFgAwduxY3Lp1C82bN0fJkiVx584dLFmyBPHx8Zg7d660vlevXsHZ2Rndu3dHlSpVYGlpiYsXL2LFihWwsbHRuH5boVBg5syZ8Pf3R+PGjdGnTx/cu3cPc+fORaNGjdCpUyep7pdffolly5bBz88P33zzDUxNTTF79mw4ODhoDAhhbm6OqVOnIiAgAF27doWvry+OHTuG1atXY9q0aZne2zV9+nSEhobC09MTgwYNgru7O549e4azZ8/iwIEDWk8QagsWLEDDhg1RrVo1DBo0CGXLlkVMTAzCw8Px4MEDnD9/Xo9XRjdvb28MGTIEQUFBiIyMRMuWLWFqaoobN24gJCQEc+fORZcuXfRaZ82aNWFsbIyff/4ZKpUKCoUCzZo1w9q1a7Fw4UJ07NgRbm5uePnyJZYtWwalUqnRM0dElFMbNmxAUlKSzkvqbty4AR8fH3Tv3h2VKlWCkZERIiIisHr1apQpUwYjR46U6g4bNgwrVqxA27ZtMXz4cLi4uODIkSNYt24dWrRoofFsQW2yezw3MjLCb7/9htatW6NKlSro378/nJyc8PDhQ4SGhkKpVGL79u3Z30mp9OnTB3/99ReGDh2K0NBQNGjQAMnJybh27Rr++usv7N27V+sjMDKivqLj+++/R48ePWBqaoq2bdtiypQpOHr0KPz8/ODi4oLY2FgsXLgQpUqVytGAUvQRMcwgeVQQxcXFCWNjY2FtbS2SkpKk8tWrVwsAok+fPumWSTuUtxBCbN26Vbi7uwsTExONIaS9vb1FlSpV0q3D399f57DcqamHldY2pR4ydO3ataJx48bCzs5OmJiYiOLFi4uOHTuKM2fOaKwvISFBjBw5UlSvXl0olUphamoqXFxcxIABA3Q+cXvdunWiRo0aQqFQCAcHBzFs2DARFxeXrt79+/dFly5dhFKpFFZWVqJNmzbixo0bWte5dOlSUbFiRSGXy4Wbm5sIDg7WGFY1IzExMSIgIEA4OzsLU1NT4ejoKJo3by6WLl0q1dE2lLcQQty6dUv07dtXODo6ClNTU+Hk5CTatGkjNm7cKNVR7/O0w2Orh3VNO1Sqv7+/sLS01NpGDw8PYW5uLqytrUW1atXE2LFjxaNHj6Q6Li4uws/PL92y2t5jy5YtE2XLlhXGxsbS0LRnz54VPXv2FKVLlxYKhULY29uLNm3aiIiIiEz3IxGRPurVqyfs7e01zpWpPX78WAwePFhUqlRJWFpaCrlcLsqXLy9GjRqldYjpa9euiS5dukjHchcXF/HNN99Ij4nITFaO52mH8lY7d+6c6NSpkyhWrJhQKBTCxcVFdOvWTRw8eFCqo+8xX9v5PjExUfz888+iSpUqQqFQiCJFiggPDw8xefJkoVKppHoAREBAQLp1uri4aJzrhRBi6tSpwsnJSRgZGUnDeh88eFC0b99elCxZUsjlclGyZEnRs2dP8e+//2a6H4mEEEImRD7cCU9ERERERFTA8Z4jIiIiIiIiMDkiIiIiIiICwOSIiIiIiIgIAJMjIiIiIiIiAEyOiIiIiIiIAHygzzlKSUnBo0ePYG1tnWtPWiYioswJIfDy5UuULFkSRkb8fS01npuIiAwjN89NH2Ry9OjRIzg7Oxs6DCKij9b9+/czfSj0x4bnJiIiw8qNc9MHmRxZW1sDeL8DlEqlgaMhIvp4xMXFwdnZWToO0//w3EREZBi5eW76IJMj9eUKSqWSJyAiIgPgZWPp8dxERGRYuXFu4gXjREREREREYHJEREREREQEgMkRERERERERACZHREREREREAJgcERERERERAWByREREREREBIDJEREREREREQAmR0RERERERACYHBERUSE3ffp0yGQyjBo1KsN6ISEhqFSpEszMzFCtWjXs2rUrfwIkIqICg8kREREVWqdPn8aSJUtQvXr1DOuFhYWhZ8+eGDBgAM6dO4cOHTqgQ4cOuHTpUj5FSkREBQGTIyIiKpRevXqF3r17Y9myZShSpEiGdefOnYtWrVphzJgxqFy5MqZOnYratWtj/vz5+RQtEREVBEyOiIioUAoICICfnx98fHwyrRseHp6unq+vL8LDw3Uuk5CQgLi4OI2JiIg+bCaGDoCIiCi3rV+/HmfPnsXp06ezVD86OhoODg4aZQ4ODoiOjta5TFBQECZPnpyjOImIqGBhzxERERUq9+/fx8iRI7FmzRqYmZnl2XYCAwOhUqmk6f79+3m2LSIiyh/sOSIiokLlzJkziI2NRe3ataWy5ORkHD16FPPnz0dCQgKMjY01lnF0dERMTIxGWUxMDBwdHXVuR6FQQKFQ5G7wRERkUOw5IiKiQqV58+a4ePEiIiMjpemTTz5B7969ERkZmS4xAgAvLy8cPHhQo2z//v3w8vLKr7CJiKgAYM8REREVKtbW1qhatapGmaWlJYoVKyaV9+3bF05OTggKCgIAjBw5Et7e3pg1axb8/Pywfv16REREYOnSpfkePxERGQ57joiI6KNz7949REVFSX/Xr18fa9euxdKlS1GjRg1s3LgRW7ZsSZdkERFR4SYTQghDB6GvuLg42NjYQKVSQalUGjocIqKPBo+/unHfEBEZRm4ef9lzREREREREBCZHREREREREAJgcEX0wyozbaegQiIiIiAo1JkdERERERERgckRUoLG3iIiIiCj/MDkiIiIiIiICkyOiAou9RkRERET5i8kRUQHDpIiIiIjIMJgcERERERERgckRERERERERACZHRB8EXmpHRERElPeYHBERERERESGHydH06dMhk8kwatQoqezt27cICAhAsWLFYGVlhc6dOyMmJkZjuXv37sHPzw8WFhawt7fHmDFjkJSUlJNQiIiIiIiIciTbydHp06exZMkSVK9eXaP8q6++wvbt2xESEoIjR47g0aNH6NSpkzQ/OTkZfn5+SExMRFhYGP744w+sXLkSEyZMyH4riIiIiIiIcihbydGrV6/Qu3dvLFu2DEWKFJHKVSoVfv/9d8yePRvNmjWDh4cHVqxYgbCwMJw8eRIAsG/fPly5cgWrV69GzZo10bp1a0ydOhULFixAYmKi1u0lJCQgLi5OYyIiIiIiIspN2UqOAgIC4OfnBx8fH43yM2fO4N27dxrllSpVQunSpREeHg4ACA8PR7Vq1eDg4CDV8fX1RVxcHC5fvqx1e0FBQbCxsZEmZ2fn7IRNRERERESkk97J0fr163H27FkEBQWlmxcdHQ25XA5bW1uNcgcHB0RHR0t1UidG6vnqedoEBgZCpVJJ0/379/UNm+iDwFHpiIiIiAzHRJ/K9+/fx8iRI7F//36YmZnlVUzpKBQKKBSKfNseUUHChImIiIgof+jVc3TmzBnExsaidu3aMDExgYmJCY4cOYJff/0VJiYmcHBwQGJiIl68eKGxXExMDBwdHQEAjo6O6UavU/+trkP0sWNCRERERJT/9EqOmjdvjosXLyIyMlKaPvnkE/Tu3Vv6v6mpKQ4ePCgtc/36ddy7dw9eXl4AAC8vL1y8eBGxsbFSnf3790OpVMLd3T2XmkVERERERKQfvS6rs7a2RtWqVTXKLC0tUaxYMal8wIABGD16NIoWLQqlUonhw4fDy8sL9erVAwC0bNkS7u7u6NOnD2bMmIHo6GiMHz8eAQEBvHSOiIiIiIgMRq/kKCuCg4NhZGSEzp07IyEhAb6+vli4cKE039jYGDt27MAXX3wBLy8vWFpawt/fH1OmTMntUIiIiIiIiLJMJoQQhg5CX3FxcbCxsYFKpYJSqTR0OES5JrN7je5M98unSIi04/FXN+4bIiLDyM3jb7aec0RERERERFTYMDkiIiIiIiICkyMiIiIiIiIATI6IiKiQWbRoEapXrw6lUgmlUgkvLy/s3r1bZ/2VK1dCJpNpTPn5oHMiIio4mBwRfWD4gFiijJUqVQrTp0/HmTNnEBERgWbNmqF9+/a4fPmyzmWUSiWioqKk6e7du/kYMRERFRS5PpQ3EemvzLidHImOKJe0bdtW4+9p06Zh0aJFOHnyJKpUqaJ1GZlMBkdHx/wIj4iICjD2HBERUaGVnJyM9evXIz4+Hl5eXjrrvXr1Ci4uLnB2ds60l0ktISEBcXFxGhMREX3YmBwRfaB4eR2RbhcvXoSVlRUUCgWGDh2KzZs3w93dXWvdihUrYvny5di6dStWr16NlJQU1K9fHw8ePMhwG0FBQbCxsZEmZ2fnvGgKERHlIyZHRERU6FSsWBGRkZE4deoUvvjiC/j7++PKlSta63p5eaFv376oWbMmvL298ffff8POzg5LlizJcBuBgYFQqVTSdP/+/bxoChER5SPec0RkYOoeoKz0BLG3iChr5HI5ypUrBwDw8PDA6dOnMXfu3EwTHgAwNTVFrVq1cPPmzQzrKRQKKBSKXImXiIgKBvYcERFRoZeSkoKEhIQs1U1OTsbFixdRokSJPI6KiIgKGvYcERFRoRIYGIjWrVujdOnSePnyJdauXYvDhw9j7969AIC+ffvCyckJQUFBAIApU6agXr16KFeuHF68eIGZM2fi7t27GDhwoCGbQUREBsDkiIiICpXY2Fj07dsXUVFRsLGxQfXq1bF37160aNECAHDv3j0YGf3vwonnz59j0KBBiI6ORpEiReDh4YGwsDCdAzgQEVHhxeSIiIgKld9//z3D+YcPH9b4Ozg4GMHBwXkYERERfSh4zxERERERERGYHBEVChzFjoiIiCjnmBwRERERERGByRFRvmIPDxEREVHBxeSIyACYJBEREREVPEyOiIiIiIiIwOSIiIiIiIgIAJMjIiIiIiIiAEyOiIiIiIiIADA5IiIiIiIiAsDkiOiDxNHuiIiIiHIfkyMiA2KSQ0RERFRwMDkiymNMgIiIiIg+DEyOiPIZkyUiIiKigonJEREREREREZgcEeUL9hYRERERFXxMjog+YEy6iIiIiHIPkyMiIiIiIiIwOSIqdNibRERERJQ9TI6IiIiIiIjA5IioUGLvEREREZH+mBwRERERERGByRGRwbB3h4iIiKhgYXJEREREREQEJkdEHzz2QBERERHlDiZHREREREREYHJElG/Yw0OUPxYtWoTq1atDqVRCqVTCy8sLu3fvznCZkJAQVKpUCWZmZqhWrRp27dqVT9ESEVFBwuSIiIgKlVKlSmH69Ok4c+YMIiIi0KxZM7Rv3x6XL1/WWj8sLAw9e/bEgAEDcO7cOXTo0AEdOnTApUuX8jlyIiIyNCZHRIUEe6aI3mvbti0+/fRTlC9fHhUqVMC0adNgZWWFkydPaq0/d+5ctGrVCmPGjEHlypUxdepU1K5dG/Pnz89wOwkJCYiLi9OYiIjow8bkiIiICq3k5GSsX78e8fHx8PLy0lonPDwcPj4+GmW+vr4IDw/PcN1BQUGwsbGRJmdn51yLm4iIDIPJERERFToXL16ElZUVFAoFhg4dis2bN8Pd3V1r3ejoaDg4OGiUOTg4IDo6OsNtBAYGQqVSSdP9+/dzLX4iIjIME0MHQERElNsqVqyIyMhIqFQqbNy4Ef7+/jhy5IjOBCk7FAoFFApFrq2PiIgMj8kREREVOnK5HOXKlQMAeHh44PTp05g7dy6WLFmSrq6joyNiYmI0ymJiYuDo6JgvsRIRUcHBy+qIiKjQS0lJQUJCgtZ5Xl5eOHjwoEbZ/v37dd6jREREhRd7jogKEY5YR/T+XqDWrVujdOnSePnyJdauXYvDhw9j7969AIC+ffvCyckJQUFBAICRI0fC29sbs2bNgp+fH9avX4+IiAgsXbrUkM0gIiIDYHJERESFSmxsLPr27YuoqCjY2NigevXq2Lt3L1q0aAEAuHfvHoyM/nfhRP369bF27VqMHz8e3333HcqXL48tW7agatWqhmoCEREZCJMjIiIqVH7//fcM5x8+fDhdWdeuXdG1a9c8ioiIiD4UvOeIiIiIiIgITI6I8gzv/yEiIiL6sDA5IirkmKQRERERZQ2TI6KPCBMlIiIiIt2YHBEREREREUHP5GjRokWoXr06lEollEolvLy8sHv3bmn+27dvERAQgGLFisHKygqdO3dO99Txe/fuwc/PDxYWFrC3t8eYMWOQlJSUO60hIiIiIiLKJr2So1KlSmH69Ok4c+YMIiIi0KxZM7Rv3x6XL18GAHz11VfYvn07QkJCcOTIETx69AidOnWSlk9OToafnx8SExMRFhaGP/74AytXrsSECRNyt1VERERERER60is5atu2LT799FOUL18eFSpUwLRp02BlZYWTJ09CpVLh999/x+zZs9GsWTN4eHhgxYoVCAsLw8mTJwEA+/btw5UrV7B69WrUrFkTrVu3xtSpU7FgwQIkJibmSQOJ8hvv6yEiIiL6MGX7nqPk5GSsX78e8fHx8PLywpkzZ/Du3Tv4+PhIdSpVqoTSpUsjPDwcABAeHo5q1arBwcFBquPr64u4uDip90mbhIQExMXFaUxERERERES5Se/k6OLFi7CysoJCocDQoUOxefNmuLu7Izo6GnK5HLa2thr1HRwcEB0dDQCIjo7WSIzU89XzdAkKCoKNjY00OTs76xs2Ub5i7xERERHRh0fv5KhixYqIjIzEqVOn8MUXX8Df3x9XrlzJi9gkgYGBUKlU0nT//v083R4REREREX18TPRdQC6Xo1y5cgAADw8PnD59GnPnzkX37t2RmJiIFy9eaPQexcTEwNHREQDg6OiIf/75R2N96tHs1HW0USgUUCgU+oZKRERERESUZTl+zlFKSgoSEhLg4eEBU1NTHDx4UJp3/fp13Lt3D15eXgAALy8vXLx4EbGxsVKd/fv3Q6lUwt3dPaehEJEOvMyPiIiIKHN69RwFBgaidevWKF26NF6+fIm1a9fi8OHD2Lt3L2xsbDBgwACMHj0aRYsWhVKpxPDhw+Hl5YV69eoBAFq2bAl3d3f06dMHM2bMQHR0NMaPH4+AgAD2DBERERERkUHplRzFxsaib9++iIqKgo2NDapXr469e/eiRYsWAIDg4GAYGRmhc+fOSEhIgK+vLxYuXCgtb2xsjB07duCLL76Al5cXLC0t4e/vjylTpuRuq4iIiIiIiPSkV3L0+++/ZzjfzMwMCxYswIIFC3TWcXFxwa5du/TZLBERERERUZ7L8T1HRKSbIe/14X1GRERERPphckRERERERAQmR0RERERERACYHBHlGl7GRkRERPRhY3JEREREREQEJkdEREREREQAmBwREREREREBYHJEVKilvg+K90QRERERZYzJEREREREREZgcERFRIRMUFIQ6derA2toa9vb26NChA65fv57hMitXroRMJtOYzMzM8iliIiIqKJgcERFRoXLkyBEEBATg5MmT2L9/P969e4eWLVsiPj4+w+WUSiWioqKk6e7du/kUMRERFRQmhg6AiIgoN+3Zs0fj75UrV8Le3h5nzpxB48aNdS4nk8ng6OiY1+EREVEBxp4jIiIq1FQqFQCgaNGiGdZ79eoVXFxc4OzsjPbt2+Py5csZ1k9ISEBcXJzGREREHzYmR0REVGilpKRg1KhRaNCgAapWraqzXsWKFbF8+XJs3boVq1evRkpKCurXr48HDx7oXCYoKAg2NjbS5OzsnBdNICKifMTkiIiICq2AgABcunQJ69evz7Cel5cX+vbti5o1a8Lb2xt///037OzssGTJEp3LBAYGQqVSSdP9+/dzO3wiIspnvOeIiIgKpWHDhmHHjh04evQoSpUqpdeypqamqFWrFm7evKmzjkKhgEKhyGmYRERUgLDniCgH+GBVooJHCIFhw4Zh8+bNOHToEFxdXfVeR3JyMi5evIgSJUrkQYRERFRQseeIiIgKlYCAAKxduxZbt26FtbU1oqOjAQA2NjYwNzcHAPTt2xdOTk4ICgoCAEyZMgX16tVDuXLl8OLFC8ycORN3797FwIEDDdYOIiLKf+w5IvrIsLeLCrtFixZBpVKhSZMmKFGihDRt2LBBqnPv3j1ERUVJfz9//hyDBg1C5cqV8emnnyIuLg5hYWFwd3c3RBOIiMhA2HNERESFihAi0zqHDx/W+Ds4OBjBwcF5FBEREX0o2HNEREREREQEJkdEREREREQAmBwREREREREBYHJEREREREQEgMkRERERERERACZHRLmCw2MTERERffiYHBEREREREYHJEREREREREQAmR0S5ipfXEREREX24mBwRERERERGByREREREREREAJkdEREREREQAmBwRfbR4fxQRERGRJiZHRMREiYiIiAhMjog+SkyGiIiIiNJjckRERERERAQmR0RERERERACYHBEREREREQFgckRERERERASAyREREREREREAJkdEOcaR34iIiIgKByZHREREREREYHJEpLcy43ayt4iIiIioEGJyRJRNTJCIiIiIChcmR0RERERERGByREREREREBIDJERERFTJBQUGoU6cOrK2tYW9vjw4dOuD69euZLhcSEoJKlSrBzMwM1apVw65du/IhWiIiKkiYHBERUaFy5MgRBAQE4OTJk9i/fz/evXuHli1bIj4+XucyYWFh6NmzJwYMGIBz586hQ4cO6NChAy5dupSPkRMRkaGZGDoAIiKi3LRnzx6Nv1euXAl7e3ucOXMGjRs31rrM3Llz0apVK4wZMwYAMHXqVOzfvx/z58/H4sWL8zxmIiIqGNhzRKSHwj5CXWFvH32cVCoVAKBo0aI664SHh8PHx0ejzNfXF+Hh4TqXSUhIQFxcnMZEREQfNiZHRB8xJkNU2KWkpGDUqFFo0KABqlatqrNedHQ0HBwcNMocHBwQHR2tc5mgoCDY2NhIk7Ozc67FnZXP5ofw+TVkjIV9/+RF+3JrnanXk511fgivnb70aVNhaP+H3AYmR0REVGgFBATg0qVLWL9+fa6vOzAwECqVSpru37+f69sgIqL8xXuOiIioUBo2bBh27NiBo0ePolSpUhnWdXR0RExMjEZZTEwMHB0ddS6jUCigUChyJVYiIioY2HNE9JFTd31/yF3gRKkJITBs2DBs3rwZhw4dgqura6bLeHl54eDBgxpl+/fvh5eXV16FSUREBRB7joiIqFAJCAjA2rVrsXXrVlhbW0v3DdnY2MDc3BwA0LdvXzg5OSEoKAgAMHLkSHh7e2PWrFnw8/PD+vXrERERgaVLlxqsHURElP/Yc0SURexZIfowLFq0CCqVCk2aNEGJEiWkacOGDVKde/fuISoqSvq7fv36WLt2LZYuXYoaNWpg48aN2LJlS4aDOBARUeHDniMiIipUhBCZ1jl8+HC6sq5du6Jr1655EBEREX0o9Oo5CgoKQp06dWBtbQ17e3t06NAB169f16jz9u1bBAQEoFixYrCyskLnzp3T3eR67949+Pn5wcLCAvb29hgzZgySkpJy3hqiPMAeIyIiIqKPg17J0ZEjRxAQEICTJ09i//79ePfuHVq2bIn4+HipzldffYXt27cjJCQER44cwaNHj9CpUydpfnJyMvz8/JCYmIiwsDD88ccfWLlyJSZMmJB7rSIiIiIiItKTXpfV7dmzR+PvlStXwt7eHmfOnEHjxo2hUqnw+++/Y+3atWjWrBkAYMWKFahcuTJOnjyJevXqYd++fbhy5QoOHDgABwcH1KxZE1OnTsW3336LSZMmQS6X517riIiIiIiIsihHAzKoVCoAQNGiRQEAZ86cwbt37+Dj4yPVqVSpEkqXLo3w8HAAQHh4OKpVq6bxJHJfX1/ExcXh8uXLWreTkJCAuLg4jYmIiIiIiCg3ZTs5SklJwahRo9CgQQNpNJ/o6GjI5XLY2tpq1HVwcJCGUo2OjtZIjNTz1fO0CQoKgo2NjTQ5OztnN2wiIiIiIiKtsp0cBQQE4NKlS1i/fn1uxqNVYGAgVCqVNN2/fz/Pt0lERERERB+XbA3lPWzYMOzYsQNHjx5FqVKlpHJHR0ckJibixYsXGr1HMTExcHR0lOr8888/GutTj2anrpOWQqGAQqHITqhERERERERZolfPkRACw4YNw+bNm3Ho0CG4urpqzPfw8ICpqSkOHjwolV2/fh337t2Dl5cXAMDLywsXL15EbGysVGf//v1QKpVwd3fPSVuIiIiIiIiyTa+eo4CAAKxduxZbt26FtbW1dI+QjY0NzM3NYWNjgwEDBmD06NEoWrQolEolhg8fDi8vL9SrVw8A0LJlS7i7u6NPnz6YMWMGoqOjMX78eAQEBLB3iIiIiIiIDEav5GjRokUAgCZNmmiUr1ixAv369QMABAcHw8jICJ07d0ZCQgJ8fX2xcOFCqa6xsTF27NiBL774Al5eXrC0tIS/vz+mTJmSs5YQERERERHlgF7JkRAi0zpmZmZYsGABFixYoLOOi4sLdu3apc+miYiIiIiI8lSOnnNE9LEoM26noUMgIiIiojzG5IiIiIiIiAhMjoiIiIiIiAAwOSIiIiIiIgLA5IiIiIiIiAgAkyMiIiIiIiIATI6IiIiIiIgAMDkiIiIiIiICwOSIiNIoM24nn+tEREREHyUmR0RERERERGByRJShj7kHhT1IRERE9LFhckRERERERAQmR0RERERERACYHBEREREREQFgckRERERERASAyRERERVCR48eRdu2bVGyZEnIZDJs2bIlw/qHDx+GTCZLN0VHR+dPwEREVCAwOSLSgSO1EX244uPjUaNGDSxYsECv5a5fv46oqChpsre3z6MIiYioIDIxdABERES5rXXr1mjdurXey9nb28PW1jZLdRMSEpCQkCD9HRcXp/f2iIioYGHPERER0f+rWbMmSpQogRYtWuDEiRMZ1g0KCoKNjY00OTs751OURESUV5gcERHRR69EiRJYvHgxNm3ahE2bNsHZ2RlNmjTB2bNndS4TGBgIlUolTffv38/HiImIKC/wsjoiIvroVaxYERUrVpT+rl+/Pm7duoXg4GCsWrVK6zIKhQIKhSK/QiQionzAniOiNDgQAxEBQN26dXHz5k1Dh0FERPmIyREREZEWkZGRKFGihKHDICKifMTL6ohSYa8RUeHw6tUrjV6f27dvIzIyEkWLFkXp0qURGBiIhw8f4s8//wQAzJkzB66urqhSpQrevn2L3377DYcOHcK+ffsM1QQiIjIAJkdERFToREREoGnTptLfo0ePBgD4+/tj5cqViIqKwr1796T5iYmJ+Prrr/Hw4UNYWFigevXqOHDggMY6iIio8GNyREREhU6TJk0ghNA5f+XKlRp/jx07FmPHjs3jqIiIqKDjPUdERERERERgckRERERERASAyREREREREREAJkdElEUcyY+IiIgKOyZHRJRlTJCIiIioMGNyREREREREBCZHREREREREAJgcERERERERAWByREREREREBIDJEZFWHHiAiIiI6OPD5IiIiIiIiAhMjoiIiIiIiAAwOSKiTPASQyIiIvpYMDkiIiIiIiICkyMiCXtIiIiIiD5uTI6IiIiIiIjA5IiIiIiIiAgAkyMiALykjoiIiIiYHBEREREREQFgckRERERERASAyRERZQMvQyQiIqLCiMkRERERERERmBwRURawp4iIiIg+BkyOiEgvTJSIiIiosDIxdABEhsQv+kRERESkxp4jIiIqdI4ePYq2bduiZMmSkMlk2LJlS6bLHD58GLVr14ZCoUC5cuWwcuXKPI+TiIgKFiZHRERU6MTHx6NGjRpYsGBBlurfvn0bfn5+aNq0KSIjIzFq1CgMHDgQe/fuzeNIiYioIOFldUREVOi0bt0arVu3znL9xYsXw9XVFbNmzQIAVK5cGcePH0dwcDB8fX3zKkwiIipg2HNEREQfvfDwcPj4+GiU+fr6Ijw8XOcyCQkJiIuL05iIiOjDxuSIiIg+etHR0XBwcNAoc3BwQFxcHN68eaN1maCgINjY2EiTs7NznsZYZtxOnYPIZDQvbZ3UdVP/m3r5tOvS9XdWy7NKn/Zpq5tRnawsr898bfFlpf2Z7busxJTV2LJTT9v/07YvJzFmZd9kRXbiyep7SFsbMnu/ZfX1z2j5zOpkFGtWtqXPvs9oP2T0uc9sn2rbVkHD5IiIiCgbAgMDoVKppOn+/fuGDomIiHJI7+QosxGAhBCYMGECSpQoAXNzc/j4+ODGjRsadZ49e4bevXtDqVTC1tYWAwYMwKtXr3LUECIiouxydHRETEyMRllMTAyUSiXMzc21LqNQKKBUKjUmIiL6sOmdHGU2AtCMGTPw66+/YvHixTh16hQsLS3h6+uLt2/fSnV69+6Ny5cvY//+/dixYweOHj2KwYMHZ78VREREOeDl5YWDBw9qlO3fvx9eXl4GioiIiAxB7+SodevW+PHHH9GxY8d084QQmDNnDsaPH4/27dujevXq+PPPP/Ho0SOph+nq1avYs2cPfvvtN3h6eqJhw4aYN28e1q9fj0ePHuW4QUSUPwr6NcP0cXv16hUiIyMRGRkJ4P1Q3ZGRkbh37x6A95fE9e3bV6o/dOhQ/Pfffxg7diyuXbuGhQsX4q+//sJXX31liPCJiMhAcvWeo9u3byM6OlpjxB8bGxt4enpKI/6Eh4fD1tYWn3zyiVTHx8cHRkZGOHXqlNb1ckQgIiLSR0REBGrVqoVatWoBAEaPHo1atWphwoQJAICoqCgpUQIAV1dX7Ny5E/v370eNGjUwa9Ys/PbbbxzGm4joI5OrzzmKjo4GAK0j/qjnRUdHw97eXjMIExMULVpUqpNWUFAQJk+enJuhEhFRIdakSRMIIXTOX7lypdZlzp07l4dRERFRQfdBjFbHEYGIiIiIiCiv5Wpy5OjoCABaR/xRz3N0dERsbKzG/KSkJDx79kyqkxZHBCIiIiIioryWq8mRq6srHB0dNUb8iYuLw6lTp6QRf7y8vPDixQucOXNGqnPo0CGkpKTA09MzN8MhIiIiIiLKMr3vOXr16hVu3rwp/a0eAaho0aIoXbo0Ro0ahR9//BHly5eHq6srfvjhB5QsWRIdOnQAAFSuXBmtWrXCoEGDsHjxYrx79w7Dhg1Djx49ULJkyVxrGBERERERkT70To4iIiLQtGlT6e/Ro0cDAPz9/bFy5UqMHTsW8fHxGDx4MF68eIGGDRtiz549MDMzk5ZZs2YNhg0bhubNm8PIyAidO3fGr7/+mgvNISIiIiIiyh69k6PMRgCSyWSYMmUKpkyZorNO0aJFsXbtWn03TZSr+JweIiIiIkrtgxitjog+DEw4iYiI6EPG5IiIso3JEBERERUmTI6IiIiIiIjA5Ig+EuzhICIiIqLMMDmijwqTpLzHfUxEREQfKiZHREREREREYHJEREREREQEgMkRfQR4mRcRERERZQWTIyIiIiIiIjA5oo8Ue5OIiIiIKC0mR/TRYWJERERERNowOSKiXMGkk4iIiD50TI6IKEeYFBEREVFhweSIiIiIiIgITI6IiIiIiIgAMDkiojzAS+2IiIjoQ8TkiIhyTFsyxASJiIiIPjRMjoiIiIiIiMDkiD4i7MkgIiIioowwOSIiIiIiIgKTIyrk2FtUsPD1oPy0YMEClClTBmZmZvD09MQ///yjs+7KlSshk8k0JjMzs3yMloiICgImR1Ro8Ys40cdrw4YNGD16NCZOnIizZ8+iRo0a8PX1RWxsrM5llEoloqKipOnu3bv5GDERERUETI6IiKjQmT17NgYNGoT+/fvD3d0dixcvhoWFBZYvX65zGZlMBkdHR2lycHDIx4iJiKggYHJERESFSmJiIs6cOQMfHx+pzMjICD4+PggPD9e53KtXr+Di4gJnZ2e0b98ely9fznA7CQkJiIuL05iIiOjDxuSIiIgKlSdPniA5OTldz4+DgwOio6O1LlOxYkUsX74cW7duxerVq5GSkoL69evjwYMHOrcTFBQEGxsbaXJ2ds7VdhARUf5jckRERB89Ly8v9O3bFzVr1oS3tzf+/vtv2NnZYcmSJTqXCQwMhEqlkqb79+/nY8RERJQXTAwdAFFu40AMBYf6tbgz3c/AkdDHpHjx4jA2NkZMTIxGeUxMDBwdHbO0DlNTU9SqVQs3b97UWUehUEChUOQoViIiKljYc0RERIWKXC6Hh4cHDh48KJWlpKTg4MGD8PLyytI6kpOTcfHiRZQoUSKvwiQiogKIyREVGuwxIiK10aNHY9myZfjjjz9w9epVfPHFF4iPj0f//v0BAH379kVgYKBUf8qUKdi3bx/+++8/nD17Fp999hnu3r2LgQMHGqoJRERkALysjoiICp3u3bvj8ePHmDBhAqKjo1GzZk3s2bNHGqTh3r17MDL63++Dz58/x6BBgxAdHY0iRYrAw8MDYWFhcHd3N1QTiIjIAJgcERFRoTRs2DAMGzZM67zDhw9r/B0cHIzg4OB8iIqIiAoyXlZHRHku9SWPvPyRiIiICiomR0SUL5gUERERUUHH5Ig+ePzS/eHha0ZEREQFEZMjIiIiIiIiMDkiIiIiIiICwOSIChlerkVERERE2cXkiIiIiIiICEyOqJBgj9GHh68ZERERFTRMjojIYJggERERUUHC5Ig+KGXG7ZS+UPOLNRERERHlJiZH9EFiYlR4pE54iYiIiAyJyRERERERERGYHNEHjj0OhRdfWyIiIspvTI6IiIiIiIgAmBg6ACKi1NhjRERERIbCniMiIiIiIiIwOaIPCHsUCje+vkRERGRoTI6IqMBiwkRERET5ickRFUhpvxTzS/LHga8zERERGRKTIypwmBhRRvh+ICIiorzC5IgKLH4JJoDvAyIiIso/TI6I6IPBRImIiIjyEpMjKtD4ZZjU+F4gIiKivMbkiPKVri+4ZcbtlCaitDJ6X2ibx/cRERERZQeTIzIIJkKUV/i+IiIiouxickS5Tt8vp/wyS/pKm1yr/5/Ze4nvNSIiIsqIQZOjBQsWoEyZMjAzM4Onpyf++ecfQ4ZDuSwrX0T5ZZWI8oq+55iQkBBUqlQJZmZmqFatGnbt2pVPkRIRUUFhsORow4YNGD16NCZOnIizZ8+iRo0a8PX1RWxsrKFCIj1ldK9H6n91/cpPlFMZva+0vRf1XSd9uPQ9x4SFhaFnz54YMGAAzp07hw4dOqBDhw64dOlSPkdORESGZGKoDc+ePRuDBg1C//79AQCLFy/Gzp07sXz5cowbN06jbkJCAhISEqS/VSoVACAuLi7/Av5IVZ24F5cm+6YrU1O/Bup6KQmvda6r9FcheRMkkQ7q91xcXJz03kz7nk0rJeG1tJy2+R879f4TQhg4kozpc44BgLlz56JVq1YYM2YMAGDq1KnYv38/5s+fj8WLF2vdRl6em1ISXqdbT9r3cOo6aefpWmdq6s+Fts9H2u3r+juzcm3t0Lfdutqnax/p2ieZtSmrseiqq5ZZu7O6z/VZNqdtyCymtO3LbF2p6+qz3/V53+i7D/R5D2mLXZ/3W2Z1dS2f2f+zuw+yUlfb66StPRntx6wuo+9xISty9dwkDCAhIUEYGxuLzZs3a5T37dtXtGvXLl39iRMnCgCcOHHixKmATPfv38+nM4b+9D3HCCGEs7OzCA4O1iibMGGCqF69us7t8NzEiRMnTgVryo1zk0F6jp48eYLk5GQ4ODholDs4OODatWvp6gcGBmL06NHS3ykpKXj27BmKFSsGmUyWo1ji4uLg7OyM+/fvQ6lU5mhdBVFhbl9hbhvA9n3ICnPbhBB4+fIlSpYsaehQdNL3HAMA0dHRWutHR0fr3E5unZsK8/slqz72fcD2f9ztB7gPctr+3Dw3GeyyOn0oFAooFAqNMltb21zdhlKpLNRvxsLcvsLcNoDt+5AV1rbZ2NgYOoQCIbfPTYX1/aKPj30fsP0fd/sB7oOctD+3zk0GGZChePHiMDY2RkxMjEZ5TEwMHB0dDRESEREVEtk5xzg6OvKcREREhkmO5HI5PDw8cPDgQaksJSUFBw8ehJeXlyFCIiKiQiI75xgvLy+N+gCwf/9+npOIiD4yBrusbvTo0fD398cnn3yCunXrYs6cOYiPj5dGFsovCoUCEydOTHdpRGFRmNtXmNsGsH0fssLctg9FZueYvn37wsnJCUFBQQCAkSNHwtvbG7NmzYKfnx/Wr1+PiIgILF26NM9j5fuF+4Dt/7jbD3AfFKT2y4Qw3His8+fPx8yZMxEdHY2aNWvi119/haenp6HCISKiQiSjc0yTJk1QpkwZrFy5UqofEhKC8ePH486dOyhfvjxmzJiBTz/91EDRExGRIRg0OSIiIiIiIiooDHLPERERERERUUHD5IiIiIiIiAhMjoiIiIiIiAAwOSIiIiIiIgLwkSZHz549Q+/evaFUKmFra4sBAwbg1atXmS4XHh6OZs2awdLSEkqlEo0bN8abN2/yIeKsy27bAEAIgdatW0Mmk2HLli15G2g26du+Z8+eYfjw4ahYsSLMzc1RunRpjBgxAiqVKh+j1m3BggUoU6YMzMzM4OnpiX/++SfD+iEhIahUqRLMzMxQrVo17Nq1K58izR592rds2TI0atQIRYoUQZEiReDj45Pp/jAkfV87tfXr10Mmk6FDhw55GyDlmdz+3AohMGHCBJQoUQLm5ubw8fHBjRs3NOpk5dh34cIFNGrUCGZmZnB2dsaMGTNyp8FpFMT2Hz58GO3bt0eJEiVgaWmJmjVrYs2aNbnX6DQK4j5I7ebNm7C2toatrW2O2qlLQW2/EAK//PILKlSoAIVCAScnJ0ybNi13Gp1KQW3/3r17Ua9ePVhbW8POzg6dO3fGnTt3cqXNaRliH0ybNg3169eHhYWFzvf2vXv34OfnBwsLC9jb22PMmDFISkrSr3HiI9SqVStRo0YNcfLkSXHs2DFRrlw50bNnzwyXCQsLE0qlUgQFBYlLly6Ja9euiQ0bNoi3b9/mU9RZk522qc2ePVu0bt1aABCbN2/O20CzSd/2Xbx4UXTq1Els27ZN3Lx5Uxw8eFCUL19edO7cOR+j1m79+vVCLpeL5cuXi8uXL4tBgwYJW1tbERMTo7X+iRMnhLGxsZgxY4a4cuWKGD9+vDA1NRUXL17M58izRt/29erVSyxYsECcO3dOXL16VfTr10/Y2NiIBw8e5HPkmdO3bWq3b98WTk5OolGjRqJ9+/b5Eyzlqrz43E6fPl3Y2NiILVu2iPPnz4t27doJV1dX8ebNG6lOZsc+lUolHBwcRO/evcWlS5fEunXrhLm5uViyZMlH0f5p06aJ8ePHixMnToibN2+KOXPmCCMjI7F9+/ZcbX9B3gdqiYmJ4pNPPhGtW7cWNjY2H1X7hw8fLipWrCi2bt0q/vvvPxERESH27dv3UbT/v//+EwqFQgQGBoqbN2+KM2fOiMaNG4tatWrlavsNuQ8mTJggZs+eLUaPHq31vZ2UlCSqVq0qfHx8xLlz58SuXbtE8eLFRWBgoF7t++iSoytXrggA4vTp01LZ7t27hUwmEw8fPtS5nKenpxg/fnx+hJht2W2bEEKcO3dOODk5iaioqAKbHOWkfan99ddfQi6Xi3fv3uVFmFlWt25dERAQIP2dnJwsSpYsKYKCgrTW79atm/Dz89Mo8/T0FEOGDMnTOLNL3/allZSUJKytrcUff/yRVyFmW3balpSUJOrXry9+++034e/vz+ToA5Xbn9uUlBTh6OgoZs6cKc1/8eKFUCgUYt26dUKIrB37Fi5cKIoUKSISEhKkOt9++62oWLFiDlusqaC2X5tPP/1U9O/fX/9GZqKg74OxY8eKzz77TKxYsSJPkqOC2v4rV64IExMTce3atdxpqA4Ftf0hISHCxMREJCcnS3W2bdsmZDKZSExMzGGrNRliH6Sm6729a9cuYWRkJKKjo6WyRYsWCaVSqXFszMxHd1ldeHg4bG1t8cknn0hlPj4+MDIywqlTp7QuExsbi1OnTsHe3h7169eHg4MDvL29cfz48fwKO0uy0zYAeP36NXr16oUFCxbA0dExP0LNluy2Ly2VSgWlUgkTE5O8CDNLEhMTcebMGfj4+EhlRkZG8PHxQXh4uNZlwsPDNeoDgK+vr876hpSd9qX1+vVrvHv3DkWLFs2rMLMlu22bMmUK7O3tMWDAgPwIk/JAXnxub9++jejoaI06NjY28PT0lOpk5dgXHh6Oxo0bQy6Xa2zn+vXreP78eQ5b/l5Bbr82KpUq148fBX0fHDp0CCEhIViwYEHOG6tFQW7/9u3bUbZsWezYsQOurq4oU6YMBg4ciGfPnuVO41Gw2+/h4QEjIyOsWLECycnJUKlUWLVqFXx8fGBqapo7OwCG2wdZER4ejmrVqsHBwUFjO3Fxcbh8+XKW1/PRJUfR0dGwt7fXKDMxMUHRokURHR2tdZn//vsPADBp0iQMGjQIe/bsQe3atdG8efN010MaUnbaBgBfffUV6tevj/bt2+d1iDmS3fal9uTJE0ydOhWDBw/OixCz7MmTJ0hOTtb4AAOAg4ODzrZER0frVd+QstO+tL799luULFky3QHV0LLTtuPHj+P333/HsmXL8iNEyiN58blV/5tZncyOfbq2k3obOVWQ25/WX3/9hdOnT6N///5ZbF3WFOR98PTpU/Tr1w8rV66EUqnMZgszVpDb/99//+Hu3bsICQnBn3/+iZUrV+LMmTPo0qVLNlubXkFuv6urK/bt24fvvvsOCoUCtra2ePDgAf76669stlY7Q+2DrMit42ChSY7GjRsHmUyW4XTt2rVsrTslJQUAMGTIEPTv3x+1atVCcHAwKlasiOXLl+dmM7TKy7Zt27YNhw4dwpw5c3I3aD3kZftSi4uLg5+fH9zd3TFp0qScB055Zvr06Vi/fj02b94MMzMzQ4eTIy9fvkSfPn2wbNkyFC9e3NDhEBV6oaGh6N+/P5YtW4YqVaoYOpx8M2jQIPTq1QuNGzc2dCgGkZKSgoSEBPz5559o1KgRmjRpgt9//x2hoaG4fv26ocPLc9HR0Rg0aBD8/f1x+vRpHDlyBHK5HF26dIEQwtDhfVAMd11RLvv666/Rr1+/DOuULVsWjo6OiI2N1ShPSkrCs2fPdF5SVqJECQCAu7u7RnnlypVx79697AedRXnZtkOHDuHWrVvpRv3o3LkzGjVqhMOHD+cg8qzJy/apvXz5Eq1atYK1tTU2b96cq13M2VG8eHEYGxsjJiZGozwmJkZnWxwdHfWqb0jZaZ/aL7/8gunTp+PAgQOoXr16XoaZLfq27datW7hz5w7atm0rlal/cDExMcH169fh5uaWt0FTrsiLz63635iYGOlco/67Zs2aUp3Mjn26tpN6GzlVkNuvduTIEbRt2xbBwcHo27ev/o3MREHeB4cOHcK2bdvwyy+/AHg/+ldKSgpMTEywdOlSfP7559ls9f8U5PaXKFECJiYmqFChglSncuXKAN6PYFaxYkV9m5tOQW7/ggULYGNjozFK5erVq+Hs7IxTp06hXr162WhxeobaB1nh6OiYbtS87BwHC03PkZ2dHSpVqpThJJfL4eXlhRcvXuDMmTPSsocOHUJKSgo8PT21rrtMmTIoWbJkul8e/v33X7i4uORpu4C8bdu4ceNw4cIFREZGShMABAcHY8WKFXneNiBv2we87zFq2bIl5HI5tm3bViB6IuRyOTw8PHDw4EGpLCUlBQcPHoSXl5fWZby8vDTqA8D+/ft11jek7LQPAGbMmIGpU6diz549GtdWFyT6tq1SpUq4ePGixmesXbt2aNq0KSIjI+Hs7Jyf4VMO5MXn1tXVFY6Ojhp14uLicOrUKalOVo59Xl5eOHr0KN69e6exnYoVK6JIkSI5bPl7Bbn9wPvhvP38/PDzzz/n2aXTBXkfhIeHaxxnpkyZAmtra0RGRqJjx46Fvv0NGjRAUlISbt26JdX5999/ASDXvqsV5Pa/fv0aRkaaX+uNjY2lGHOLofZBVnh5eeHixYsaieT+/fuhVCrTdXBkKMtDNxQirVq1ErVq1RKnTp0Sx48fF+XLl9cYDvHBgweiYsWK4tSpU1JZcHCwUCqVIiQkRNy4cUOMHz9emJmZiZs3bxqiCTplp21poYCOVieE/u1TqVTC09NTVKtWTdy8eVNERUVJU1JSkqGaIYR4PxSmQqEQK1euFFeuXBGDBw8Wtra20igrffr0EePGjZPqnzhxQpiYmIhffvlFXL16VUycOLHAD+WtT/umT58u5HK52Lhxo8br9PLlS0M1QSd925YWR6v7cOXF53b69OnC1tZWbN26VVy4cEG0b99e6zC+GR37Xrx4IRwcHESfPn3EpUuXxPr164WFhUWeDOVdENt/6NAhYWFhIQIDAzWOH0+fPs3V9hfkfZBWXo1WV1Dbn5ycLGrXri0aN24szp49KyIiIoSnp6do0aLFR9H+gwcPCplMJiZPniz+/fdfcebMGeHr6ytcXFzE69evC8U+uHv3rjh37pyYPHmysLKyEufOnRPnzp2Tvieoh/Ju2bKliIyMFHv27BF2dnYcyjsrnj59Knr27CmsrKyEUqkU/fv31/gCdvv2bQFAhIaGaiwXFBQkSpUqJSwsLISXl5c4duxYPkeeuey2LbWCnBzp277Q0FABQOt0+/ZtwzQilXnz5onSpUsLuVwu6tatK06ePCnN8/b2Fv7+/hr1//rrL1GhQgUhl8tFlSpVxM6dO/M5Yv3o0z4XFxetr9PEiRPzP/As0Pe1S43J0Ycttz+3KSkp4ocffhAODg5CoVCI5s2bi+vXr2vUyezYJ4QQ58+fFw0bNhQKhUI4OTmJ6dOn527D/19BbL+/v7/W44e3t3eut1+IgrkP0sqr5EiIgtv+hw8fik6dOgkrKyvh4OAg+vXrlycJckFt/7p160StWrWEpaWlsLOzE+3atRNXr17N3cb/P0PsA12f89Tfae/cuSNat24tzM3NRfHixcXXX3+t96NbZELwLi0iIiIiIqJCc88RERERERFRTjA5IiIiIiIiApMjIiIiIiIiAEyOiIiIiIiIADA5IiIiIiIiAsDkiIiIiIiICACTIyIiIiIiIgBMjoiIiIiIiAAwOSIiIiIiIgLA5IiIiIiIiAgAkyMiIiIiIiIAwP8B7UqzB85O0zEAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "cf = coef.ravel()\n", + "cf01 = cf[(cf >= 0) & (cf <= 0.001)]\n", + "\n", + "fig, axs = plt.subplots(1, 2, figsize=(10, 4))\n", + "axs[0].hist(cf, bins=2048)\n", + "axs[0].set_title(\n", + " f\"Coefficients Distribution\\nwith {cf.size} éléments\"\n", + ")\n", + "axs[1].hist(cf01, bins=2048)\n", + "axs[1].set_title(f\"Same distribution between 0 et {cf01.max():.4f}\\n{cf01.size} éléments\");" + ] + }, + { + "cell_type": "markdown", + "id": "083b75c0", + "metadata": {}, + "source": [ + "Distribution of float 8." + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "id": "544a61de", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "254" + ] + }, + "execution_count": 88, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import numpy\n", + "from onnx.numpy_helper import float8e4m3_to_float32\n", + "\n", + "float8 = [float8e4m3_to_float32(i) for i in range(0, 256)]\n", + "no_nan8 = [f for f in float8 if not numpy.isnan(f)]\n", + "len(no_nan8)" + ] + }, + { + "cell_type": "code", + "execution_count": 89, + "id": "217b5762", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA1QAAAF2CAYAAABpmtlJAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAA9hAAAPYQGoP6dpAAB7QUlEQVR4nO3deVwU9f8H8NeC7i6IgIqwgiioJHliIIh5JolXiqmp+Uvka1p5i2liCl6Jt5ipZOWRaZAdaGYYkXRJHih5mxqKhotXsIoJCp/fH8bEyi7srsCCvJ6Pxz50P/Oez7xnXGf2vTPzGZkQQoCIiIiIiIiMZmHuBIiIiIiIiKoqFlREREREREQmYkFFRERERERkIhZUREREREREJmJBRUREREREZCIWVERERERERCZiQUVERERERGQiFlREREREREQmYkFFRERERERkIhZUVMzcuXMhk8kqZFndunVDt27dpPdJSUmQyWT4/PPPK2T5o0aNgpubW4Usy1R37tzBq6++CpVKBZlMhilTpuiNffDgAWbMmAFXV1dYWFggKCgIACCTyTB37twKyZeIiKquzZs3QyaT4eLFiwbHHj58uPwTq4SM+c5SFb5vkOlYUD3hCnd2hS+lUglnZ2cEBgbi3Xffxe3bt8tkORkZGZg7dy5SU1PLpL+yVJlzM8SiRYuwefNmvPHGG9i6dSteeeUVvbEbN27EsmXLMHjwYGzZsgVTp06tkBxN2cbnzp3DsGHD0LBhQ1hbW8PT0xPz58/H3bt3S5131KhRWp/rRz/j+mzbtg0ymQw2NjbFpnXr1g0ymQweHh46501ISJCWUfTgefLkSQwZMgRNmjSBtbU1HBwc0KVLF3z99dd6l6HrdebMGQD/HaBlMhlSUlJ0rruu/Ino8R0/fhyDBw9G48aNoVQq4eLigueffx5r1qwxd2pmtW7dOmzevNncaRBVWjXMnQBVjPnz58Pd3R3379+HWq1GUlISpkyZgpUrV2LXrl1o06aNFDt79mzMnDnTqP4zMjIwb948uLm5wcvLy+D5vvvuO6OWY4qScvvggw9QUFBQ7jk8jh9++AEdOnRARESEQbEuLi5YtWpVBWT2H2P//S9fvgxfX1/Y2dlhwoQJqFu3LpKTkxEREYGUlBTs3Lmz1D4UCgU+/PDDYu2WlpY64+/cuYMZM2agVq1aevtUKpU4f/48Dh48CF9fX61p27Ztg1KpxL1797TaL126hNu3byM4OBjOzs64e/cuvvjiC/Tv3x/vv/8+xo4dqxXfsGFDREZGFlu2s7Nzsba5c+fqLMyIqOzt378f3bt3R6NGjTBmzBioVCpcvnwZv/32G1avXo2JEyeaO8UK8corr2DYsGFQKBRS27p16+Dg4IBRo0aZL7Eqrip83yDTsaCqJnr37g0fHx/pfVhYGH744Qf069cP/fv3x+nTp2FlZQUAqFGjBmrUKN+Pxt27d2FtbQ25XF6uyylNzZo1zbp8Q1y7dg0tWrQwONbe3r58EyoDW7duRVZWFn755Re0bNkSADB27FgUFBTg448/xt9//406deqU2EeNGjXwf//3fwYvc+HChahduza6d++OuLg4nTFNmzbFgwcP8Omnn2oVVPfu3cNXX32Fvn374osvvtCap0+fPujTp49W24QJE+Dt7Y2VK1cWK6js7OwMytvLywu7d+/GkSNH8Mwzzxi4lkRkqnfeeQd2dnY4dOhQsf3otWvXzJOUGVhaWur9YepJcu/ePcjlclhYVMzFWlXh+waZjpf8VWPPPfcc5syZg0uXLuGTTz6R2nXdQ5WQkIBOnTrB3t4eNjY2aN68OWbNmgXg4SVK7du3BwCEhIRIlysVXh7QrVs3tGrVCikpKejSpQusra2leR+9h6pQfn4+Zs2aBZVKhVq1aqF///64fPmyVoybm5vOX8uK9llabrquac7JycG0adPg6uoKhUKB5s2bY/ny5RBCaMXJZDJMmDABcXFxaNWqFRQKBVq2bIn4+HjdG/wR165dw+jRo+Hk5ASlUom2bdtiy5Yt0vTCS7/S0tLwzTffSLnruq794sWLkMlk2LdvH06ePCnFJiUl6V3+0aNH0bt3b9ja2sLGxgY9evTAb7/9phVz69YtvPnmm2jdujVsbGxga2uL3r174/fff9fKs6RtrItGowEAODk5abU3aNAAFhYWZV5onzt3DqtWrcLKlStL/bFg+PDhiI2N1fol8euvv8bdu3fx0ksvGbQ8S0tLuLq6Iisry+ScJ06ciDp16vDeN6IKcuHCBbRs2VLnj1KOjo5a7zdt2oTnnnsOjo6OUCgUaNGiBdavX19sPjc3N/Tr1w9JSUnw8fGBlZUVWrduLe2bv/zyS7Ru3RpKpRLe3t44evRosT7OnDmDwYMHo27dulAqlfDx8cGuXbtKXZ9nnnkGL774olZb69atIZPJcOzYMaktNjYWMpkMp0+fBlD8Hio3NzecPHkSP/74o7R/f/S4nZubi9DQUNSvXx+1atXCwIEDcf369VJzLLyEOT09Hf369YONjQ1cXFywdu1aAA8vwXzuuedQq1YtNG7cGNu3by/Wx59//okhQ4agbt26sLa2RocOHfDNN99oxRQeT2NiYjB79my4uLjA2tpaOhYdOHAAvXr1gp2dHaytrdG1a1f8+uuvpeZfyJDvLI9+3yg8bi9fvhwbNmxA06ZNoVAo0L59exw6dEhrXrVajZCQEDRs2BAKhQINGjTAgAEDDLrPjSoGC6pqrvB+nJIuvTt58iT69euH3NxczJ8/HytWrED//v2lnc3TTz+N+fPnA3h4lmHr1q3YunUrunTpIvVx8+ZN9O7dG15eXoiKikL37t1LzOudd97BN998g7feeguTJk1CQkICAgIC8M8//xi1fobkVpQQAv3798eqVavQq1cvrFy5Es2bN8f06dMRGhpaLP6XX37BuHHjMGzYMCxduhT37t3DoEGDcPPmzRLz+ueff9CtWzds3boVI0aMwLJly2BnZ4dRo0Zh9erVUu5bt26Fg4MDvLy8pNzr169frL/69etj69at8PT0RMOGDaXYp59+WufyT548ic6dO+P333/HjBkzMGfOHKSlpaFbt244cOCAFPfnn38iLi4O/fr1w8qVKzF9+nQcP34cXbt2RUZGhknbGIB0MB49ejRSU1Nx+fJlxMbGYv369Zg0aVKJl+UVdePGjWKvwgNkUVOmTEH37t2LnUnS5eWXX8bVq1e1itHt27ejR48exb5UFZWTk4MbN27gwoULWLVqFb799lv06NGjWFx+fn6xnO/cuVMsztbWFlOnTsXXX3+NI0eOlJo3ET2exo0bIyUlBSdOnCg1dv369WjcuDFmzZqFFStWwNXVFePGjZMKgaLOnz+Pl19+GS+88AIiIyPx999/44UXXsC2bdswdepU/N///R/mzZuHCxcu4KWXXtL6MefkyZPo0KEDTp8+jZkzZ2LFihWoVasWgoKC8NVXX5WYY+fOnfHLL79I72/duoWTJ0/CwsICP//8s9T+888/o379+nqPF1FRUWjYsCE8PT2l/fvbb7+tFTNx4kT8/vvviIiIwBtvvIGvv/4aEyZMKHU7Ag/3ib1794arqyuWLl0KNzc3TJgwAZs3b0avXr3g4+ODJUuWoHbt2hg5ciTS0tKkeTMzM9GxY0fs3bsX48aNwzvvvIN79+6hf//+OrfPggUL8M033+DNN9/EokWLIJfL8cMPP6BLly7QaDSIiIjAokWLkJWVheeeew4HDx40aB0e5zvL9u3bsWzZMrz22mtYuHAhLl68iBdffBH379+XYgYNGoSvvvoKISEhWLduHSZNmoTbt28jPT3doPyoAgh6om3atEkAEIcOHdIbY2dnJ9q1aye9j4iIEEU/GqtWrRIAxPXr1/X2cejQIQFAbNq0qdi0rl27CgAiOjpa57SuXbtK7/ft2ycACBcXF6HRaKT2zz77TAAQq1evltoaN24sgoODS+2zpNyCg4NF48aNpfdxcXECgFi4cKFW3ODBg4VMJhPnz5+X2gAIuVyu1fb7778LAGLNmjXFllVUVFSUACA++eQTqS0vL0/4+/sLGxsbrXVv3Lix6Nu3b4n9Feratato2bJlsXYAIiIiQnofFBQk5HK5uHDhgtSWkZEhateuLbp06SK13bt3T+Tn52v1lZaWJhQKhZg/f77UVtI21mfBggXCyspKAJBeb7/9tkHzBgcHa81X9BUYGKgVu3v3blGjRg1x8uRJad5atWoV67PotvPx8RGjR48WQgjx999/C7lcLrZs2SJ9Pnfs2FFs/tdee03KwcLCQgwePFjcunWr2DJ05Vz0c1x0GVlZWaJOnTqif//+WuuuK38iejzfffedsLS0FJaWlsLf31/MmDFD7N27V+Tl5RWLvXv3brG2wMBA0aRJE622xo0bCwBi//79UtvevXsFAGFlZSUuXboktb///vsCgNi3b5/U1qNHD9G6dWtx7949qa2goEB07NhReHh4lLg+O3bsEADEqVOnhBBC7Nq1SygUCtG/f38xdOhQKa5NmzZi4MCB0vvC7w1paWlSW8uWLbWOq4/GBgQEiIKCAql96tSpwtLSUmRlZZWYY+G+fNGiRVLb33//LaysrIRMJhMxMTFS+5kzZ4ody6ZMmSIAiJ9//llqu337tnB3dxdubm7S8atwv9qkSROtf7uCggLh4eEhAgMDtfK/e/eucHd3F88//3yJ+RvzneXR7xtpaWkCgKhXr57WsWLnzp0CgPj666+l7QFALFu2rMRcyLx4hopgY2NT4mh/hZc/7Ny50+QbKhUKBUJCQgyOHzlyJGrXri29Hzx4MBo0aIA9e/aYtHxD7dmzB5aWlpg0aZJW+7Rp0yCEwLfffqvVHhAQgKZNm0rv27RpA1tbW/z555+lLkelUmH48OFSW82aNTFp0iTcuXMHP/74YxmsjW75+fn47rvvEBQUhCZNmkjtDRo0wMsvv4xffvlFOsujUCik68vz8/Nx8+ZN6ZLPxz1r4ubmhi5dumDDhg344osv8L///Q+LFi3Ce++9Z9D8SqUSCQkJxV6LFy+WYvLy8jB16lS8/vrrBt+HBjw8S/Xll18iLy8Pn3/+OSwtLTFw4MAS55kyZQoSEhKwZcsW9O7dG/n5+cjLy9O53o/mPGPGDJ192tnZYcqUKdi1a5fOS4GIqOw8//zzSE5ORv/+/fH7779j6dKlCAwMhIuLS7FL7ArvOQaA7Oxs3LhxA127dsWff/6J7OxsrdgWLVrA399feu/n5wfg4WX3jRo1KtZeePy4desWfvjhB7z00ku4ffu2dEb75s2bCAwMxLlz5/DXX3/pXZ/OnTsDAH766ScAD89EtW/fHs8//7x0hiorKwsnTpyQYk01duxYrVsFOnfujPz8fFy6dMmg+V999VXp7/b29mjevDlq1aqldZl18+bNYW9vr3V83bNnD3x9fdGpUyepzcbGBmPHjsXFixdx6tQpreUEBwdr/dulpqbi3LlzePnll3Hz5k1pG+fk5KBHjx746aefDPre8zjfWYYOHap1z3Dhv0XhelpZWUEulyMpKQl///13qf2ReXBQCsKdO3dKvJRp6NCh+PDDD/Hqq69i5syZ6NGjB1588UUMHjzY4Js5XVxcjLov5tGhq2UyGZo1a1bu1wtfunQJzs7OWjtGANKlEI8eHIoeDAvVqVOn1J3epUuX4OHhUWz76VtOWbp+/Tru3r2L5s2bF5v29NNPo6CgAJcvX0bLli1RUFCA1atXY926dUhLS0N+fr4UW69ePZNziImJwdixY/HHH3+gYcOGAIAXX3wRBQUFeOuttzB8+PBS+7e0tERAQECJMatWrcKNGzcwb948o/IbNmwY3nzzTXz77bfYtm0b+vXrV+wz8ShPT094enoCeHhw7dmzJ1544QUcOHBA64tGrVq1Ss27qMmTJ2PVqlWYO3euQaMfEpHp2rdvL/2Y8vvvv+Orr77CqlWrMHjwYKSmpko/zPz666+IiIhAcnJysUc9ZGdnw87OTnr/6HGicJqrq6vO9sLjx/nz5yGEwJw5czBnzhyd+V67dg0uLi46pzk5OcHDwwM///wzXnvtNfz888/o3r07unTpgokTJ+LPP//E6dOnUVBQ8NgF1aPrWFggGFIAKJXKYpey29nZoWHDhsXu57azs9Pq89KlS1IhWlTRY2mrVq2kdnd3d624c+fOAXhYaOmTnZ1d6iBJj/OdpbRtp1AosGTJEkybNg1OTk7o0KED+vXrh5EjR0KlUpXaP1UMFlTV3JUrV5CdnY1mzZrpjbGyssJPP/2Effv24ZtvvkF8fDxiY2Px3HPP4bvvvjNoNKCivwiVFX0PH87Pz6+wEYr0LUc8MoBFVbVo0SLMmTMH//vf/7BgwQLUrVsXFhYWmDJlymMN/7pu3Tq0a9dOKqYK9e/fH5s3b8bRo0eNKjp0yc7OxsKFCzFu3DhoNBrprNudO3cghMDFixdhbW2t88eEBg0aoFu3blixYgV+/fXXYiP7GWLw4MF47bXX8Mcff+gsXg1VeJZq7ty5PEtFVEHkcjnat2+P9u3b46mnnkJISAh27NiBiIgIXLhwAT169ICnpydWrlwJV1dXyOVy7NmzB6tWrSq2b9R3nCjt+FHYz5tvvonAwECdsSUduwGgU6dOSExMxD///IOUlBSEh4ejVatWsLe3x88//4zTp0/DxsYG7dq1K7Gf0jzOsdDU7WOKR7+LFG7jZcuW6X3kR3k/98+Q9ZwyZQpeeOEFxMXFYe/evZgzZw4iIyPxww8/PPa/HZUNFlTV3NatWwFA7866kIWFBXr06IEePXpg5cqVWLRoEd5++23s27cPAQEBeosbUxX+alRICIHz589rPS+rTp06OkdRu3TpktalbMbk1rhxY3z//fe4ffu21hmJwoeuNm7c2OC+SlvOsWPHUFBQoHWWqqyXo0v9+vVhbW2Ns2fPFpt25swZWFhYSL+cfv755+jevTs++ugjrbisrCw4ODhI743998/MzNT5i1/hTbgPHjwwqj9d/v77b9y5cwdLly7F0qVLi013d3fHgAED9A6h/vLLL+PVV1+Fvb29QYNZPKrwZuRHL/8xxZQpUxAVFYV58+ZViWHxiZ4khY8cuXr1KoCHo37m5uZi165dWmcX9u3bV6bLLTyO1axZ0+QfmDp37oxNmzYhJiYG+fn56NixIywsLNCpUyepoOrYsWOpP0KW9TG+rDRu3FjvsaxwekkKL9m3tbV9rB/xDPnO8riaNm2KadOmYdq0aTh37hy8vLywYsUKrVGayXx4D1U19sMPP2DBggVwd3fHiBEj9MbdunWrWFvhLzm5ubkAII3K9jjDRBf18ccfa93X9fnnn+Pq1avo3bu31Na0aVP89ttvWvep7N69u9hQpcbk1qdPH+Tn5xe7j2fVqlWQyWRay38cffr0gVqtRmxsrNT24MEDrFmzBjY2NujatWuZLEcXS0tL9OzZEzt37tS6HCEzMxPbt29Hp06dYGtrK8U++mvgjh07il23b+y//1NPPYWjR4/ijz/+0Gr/9NNPYWFhUSYHIUdHR3z11VfFXt27d4dSqcRXX32FsLAwvfMPHjwYERERWLduXYmXq+p6Ps39+/fx8ccfw8rKyqh7t/QpPEu1c+dOpKamPnZ/RFTcvn37dJ79KLwPpvBMc2HxUTQ2OzsbmzZtKtN8HB0d0a1bN7z//vtSMVeUIcOSF17Kt2TJErRp00a6rLBz585ITEzE4cOHDbrcr1atWmV2fC9Lffr0wcGDB5GcnCy15eTkYMOGDXBzcyt1/+vt7Y2mTZti+fLlOkdbNWQbA4Z9ZzHV3bt3iz1QvmnTpqhdu7b0HYzMj2eoqolvv/0WZ86cwYMHD5CZmYkffvgBCQkJaNy4MXbt2gWlUql33vnz5+Onn35C37590bhxY1y7dg3r1q1Dw4YNpRtBmzZtCnt7e0RHR6N27dqoVasW/Pz8il2vbKi6deuiU6dOCAkJQWZmJqKiotCsWTOMGTNGinn11Vfx+eefo1evXnjppZdw4cIFfPLJJ1qDRBib2wsvvIDu3bvj7bffxsWLF9G2bVt899132LlzJ6ZMmVKsb1ONHTsW77//PkaNGoWUlBS4ubnh888/x6+//oqoqKhS79d5XAsXLpSeLTZu3DjUqFED77//PnJzc7XO5vTr1w/z589HSEgIOnbsiOPHj2Pbtm1aZwAB4//9p0+fjm+//RadO3fGhAkTUK9ePezevRvffvstXn31VTg7O5e6Dg8ePND7y9zAgQOloYUfFRcXh4MHD+qcVpSdnZ1Bz4B67bXXoNFo0KVLF7i4uECtVmPbtm04c+YMVqxYUWaXixTeS/X7778bPKw8ERlu4sSJuHv3LgYOHAhPT0/k5eVh//79iI2NhZubmzSwUs+ePSGXy/HCCy/gtddew507d/DBBx/A0dFRZ+HzONauXYtOnTqhdevWGDNmDJo0aYLMzEwkJyfjypUrWs8E1KVZs2ZQqVQ4e/YsJk6cKLV36dIFb731FgAYVFB5e3tj/fr1WLhwIZo1awZHR0c899xzj7dyZWDmzJn49NNP0bt3b0yaNAl169bFli1bkJaWhi+++KLU+7wtLCzw4Ycfonfv3mjZsiVCQkLg4uKCv/76C/v27YOtrS2+/vrrUvMw5DuLqf744w/06NEDL730Elq0aIEaNWrgq6++QmZmJoYNG/bY/VMZMcvYglRhCoc0LXzJ5XKhUqnE888/L1avXq01zGehR4dNT0xMFAMGDBDOzs5CLpcLZ2dnMXz4cPHHH39ozbdz507RokULUaNGDa0htPUN5V04Tdew6Z9++qkICwsTjo6OwsrKSvTt21dreNlCK1asEC4uLkKhUIhnn31WHD58uFifJeX26DCmQjwccnXq1KnC2dlZ1KxZU3h4eIhly5ZpDakqxMOhyMePH18sJ33DuT8qMzNThISECAcHByGXy0Xr1q11DjteHsOmCyHEkSNHRGBgoLCxsRHW1taie/fuWkP7CvFw2PRp06aJBg0aCCsrK/Hss8+K5ORko7axPgcOHBC9e/cWKpVK1KxZUzz11FPinXfeEffv3y91PUsaNh2PDPera97Shk3XR9ew6Z9++qkICAgQTk5OokaNGqJOnToiICBA7Ny5s8yWUajw/yaHTScqe99++6343//+Jzw9PYWNjY2Qy+WiWbNmYuLEiSIzM1MrdteuXaJNmzZCqVQKNzc3sWTJErFx48Zi+x99+29dx4/CYbQfHR77woULYuTIkdK+0sXFRfTr1098/vnnBq3XkCFDBAARGxsrteXl5Qlra2shl8vFP//8oxWva9h0tVot+vbtK2rXri0ASPt/fY9mKdyPFR0CXhdj98e6tueFCxfE4MGDhb29vVAqlcLX11fs3r1bZz669qtCCHH06FHx4osvinr16gmFQiEaN24sXnrpJZGYmFhi/sZ8Z9E3bLqu4dCLHrNv3Lghxo8fLzw9PUWtWrWEnZ2d8PPzE5999lmJuVHFkgnxhNw9T0REREREVMF4DxUREREREZGJWFARERERERGZiAUVERERERGRiVhQERERERERmYgFFRERERERkYlYUBEREREREZmID/YtoqCgABkZGahduzZkMpm50yEiqjaEELh9+zacnZ1LfRhndcNjExGReRh6bGJBVURGRgZcXV3NnQYRUbV1+fJlNGzY0NxpVCo8NhERmVdpxyYWVEXUrl0bwMONZmtra+ZsiIiqD41GA1dXV2k/TP/hsYmIyDwMPTaxoCqi8FIKW1tbHrSIiMyAl7QVx2MTEZF5lXZs4oXqREREREREJmJBRUREREREZCIWVERERERERCbiPVREREYqKChAXl6eudOocuRyOYdEJyIqJ/n5+bh//76506hSatasCUtLy8fux6SCau3atVi2bBnUajXatm2LNWvWwNfXV2/8jh07MGfOHFy8eBEeHh5YsmQJ+vTpAwC4f/8+Zs+ejT179uDPP/+EnZ0dAgICsHjxYjg7O0t93Lp1CxMnTsTXX38NCwsLDBo0CKtXr4aNjY0Uc+zYMYwfPx6HDh1C/fr1MXHiRMyYMcOUVSQi0ikvLw9paWkoKCgwdypVjoWFBdzd3SGXy82dChHRE0MIAbVajaysLHOnUiXZ29tDpVI91qBIRhdUsbGxCA0NRXR0NPz8/BAVFYXAwECcPXsWjo6OxeL379+P4cOHIzIyEv369cP27dsRFBSEI0eOoFWrVrh79y6OHDmCOXPmoG3btvj7778xefJk9O/fH4cPH5b6GTFiBK5evYqEhATcv38fISEhGDt2LLZv3w7g4bCGPXv2REBAAKKjo3H8+HH873//g729PcaOHWvyBiIiKiSEwNWrV2FpaQlXV1eebTFC4cNpr169ikaNGnE0PyKiMlJYTDk6OsLa2pr7VwMJIXD37l1cu3YNANCgQQOT+5IJIYQxM/j5+aF9+/Z47733ADw8SLq6umLixImYOXNmsfihQ4ciJycHu3fvlto6dOgALy8vREdH61zGoUOH4Ovri0uXLqFRo0Y4ffo0WrRogUOHDsHHxwcAEB8fjz59+uDKlStwdnbG+vXr8fbbb0OtVku/fs6cORNxcXE4c+aMQeum0WhgZ2eH7OxsDk1LRMXcv38f58+fh7OzM+zs7MydTpWTnZ2NjIwMNGvWDDVr1tSaxv2vftw2RKRPfn4+/vjjDzg6OqJevXrmTqdKunnzJq5du4annnqq2OV/hu5/jfp5NS8vDykpKQgICPivAwsLBAQEIDk5Wec8ycnJWvEAEBgYqDceeHjQlclksLe3l/qwt7eXiikACAgIgIWFBQ4cOCDFdOnSRetSksIzZ3///bcxq0lEpFN+fj4A8JI1ExVut8LtSEREj6fwnilra2szZ1J1FW67x7n/zKiC6saNG8jPz4eTk5NWu5OTE9Rqtc551Gq1UfH37t3DW2+9heHDh0uVoFqtLnY5YY0aNVC3bl2pH33LKZymS25uLjQajdaLiKg0vJzCNNxuRETlg/tX05XFtqtUNwDcv38fL730EoQQWL9+fbkvLzIyEnZ2dtLL1dW13JdJRERERERPDqMKKgcHB1haWiIzM1OrPTMzEyqVSuc8KpXKoPjCYurSpUtISEjQuk5RpVJJN4wVevDgAW7duiX1o285hdN0CQsLQ3Z2tvS6fPmyvlUnIqqyhBAYO3Ys6tatC5lMhtTUVHOnRERE1dyTdGwyapQ/uVwOb29vJCYmIigoCMDDQSkSExMxYcIEnfP4+/sjMTERU6ZMkdoSEhLg7+8vvS8sps6dO4d9+/YVu6nO398fWVlZSElJgbe3NwDghx9+QEFBAfz8/KSYt99+G/fv35dudk5ISEDz5s1Rp04dnbkpFAooFApjNgERUTGrEv6o0OVNff4po+Lj4+OxefNmJCUloUmTJqhTpw7mzJmDTz75BGq1Gs7Ozhg1ahRmz57Ny0aIiJ4QPDZVHKOHTQ8NDUVwcDB8fHzg6+uLqKgo5OTkICQkBAAwcuRIuLi4IDIyEgAwefJkdO3aFStWrEDfvn0RExODw4cPY8OGDQAeFlODBw/GkSNHsHv3buTn50v3PNWtWxdyuRxPP/00evXqhTFjxiA6Ohr379/HhAkTMGzYMOlZVS+//DLmzZuH0aNH46233sKJEyewevVqrFq1qkw2FFFFeNydn7E7M6oeLly4gAYNGqBjx44AgEWLFmH9+vXYsmULWrZsicOHDyMkJAR2dnaYNGmSmbMloifNqoQ/eHyiYp6kY5PRBdXQoUNx/fp1hIeHQ61Ww8vLC/Hx8dIAEOnp6VrPZunYsSO2b9+O2bNnY9asWfDw8EBcXBxatWoFAPjrr7+wa9cuAICXl5fWsvbt24du3boBALZt24YJEyagR48e0oN93333XSnWzs4O3333HcaPHw9vb284ODggPDycz6Aiompt1KhR2LJlC4CHN942btwYrVq1woABA9C3b18AgJubGz799FMcPHjQnKkSEVE18aQdm4wuqABgwoQJei/xS0pKKtY2ZMgQDBkyRGe8m5sbDHkUVt26daWH+OrTpk0b/Pzzz6X2RURUXaxevRpNmzbFhg0bcOjQIVhaWuKDDz7Ahg0b8Mcff+Cpp57C77//jl9++QUrV640d7pERFQNPGnHJpMKKiIiqhrs7OxQu3ZtWFpaSgP0zJw5ExqNBp6enrC0tER+fj7eeecdjBgxwszZEhFRdfCkHZtYUBERVTOfffYZtm3bhu3bt6Nly5ZITU3FlClT4OzsjODgYHOnR0RE1VBVPjaxoCIiqmamT5+OmTNnYtiwYQCA1q1b49KlS4iMjKz0By0iInoyVeVjEwsqoicIRwkkQ9y9e1dr8CAAsLS0REFBgZkyIiKi6q4qH5tYUBERVTMvvPAC3nnnHTRq1AgtW7bE0aNHsXLlSvzvf/8zd2pERFRNVeVjEwsqIqJqZs2aNZgzZw7GjRuHa9euwdnZGa+99hrCw8PNnRoREVVTVfnYJBOGjFleTWg0GtjZ2SE7Oxu2trbmToeqoYp+qvmjeMlfye7du4e0tDS4u7tDqVSaO50qp6Ttx/2vftw2VNXxwb7lh8elx1cWxyYLvVOIiIiIiIioRCyoiIiI/rV27Vq4ublBqVTCz88PBw8eNGi+mJgYyGQyBAUFabULIRAeHo4GDRrAysoKAQEBOHfuXDlkTkRE5sKCioiICEBsbCxCQ0MRERGBI0eOoG3btggMDMS1a9dKnO/ixYt488030blz52LTli5dinfffRfR0dE4cOAAatWqhcDAQNy7d6+8VoOo0liV8IfZL2UnqggsqIiIiACsXLkSY8aMQUhICFq0aIHo6GhYW1tj48aNeufJz8/HiBEjMG/ePDRp0kRrmhACUVFRmD17NgYMGIA2bdrg448/RkZGBuLi4sp5bYiIqKKwoCIiomovLy8PKSkpCAgIkNosLCwQEBCA5ORkvfPNnz8fjo6OGD16dLFpaWlpUKvVWn3a2dnBz8+vxD5zc3Oh0Wi0XkREVHmxoCIiomrvxo0byM/Ph5OTk1a7k5MT1Gq1znl++eUXfPTRR/jggw90Ti+cz5g+ASAyMhJ2dnbSy9XV1ZhVISKiCsaCioiIyEi3b9/GK6+8gg8++AAODg5l2ndYWBiys7Ol1+XLl8u0fyIiKlt8sC8REVV7Dg4OsLS0RGZmplZ7ZmYmVCpVsfgLFy7g4sWLeOGFF6S2goICAECNGjVw9uxZab7MzEw0aNBAq08vLy+9uSgUCigUisdZHSIiqkA8Q0VERNWeXC6Ht7c3EhMTpbaCggIkJibC39+/WLynpyeOHz+O1NRU6dW/f390794dqampcHV1hbu7O1QqlVafGo0GBw4c0NknERFVTTxDRUREBCA0NBTBwcHw8fGBr68voqKikJOTg5CQEADAyJEj4eLigsjISCiVSrRq1Uprfnt7ewDQap8yZQoWLlwIDw8PuLu7Y86cOXB2di72vCoiIqq6WFARET2ufZEVu7zuYUaFjxo1Clu2bEFkZCRmzpwptcfFxWHgwIEQQpR1hlXS0KFDcf36dYSHh0OtVsPLywvx8fHSoBLp6emwsDDuwo4ZM2YgJycHY8eORVZWFjp16oT4+HgolcryWAUiov/w2FRhWFAREVUDSqUSS5YswWuvvYY6deqYO51Ka8KECZgwYYLOaUlJSSXOu3nz5mJtMpkM8+fPx/z588sgOyKiJ8uTcmziPVRERNVAQEAAVCoVIiMr+BdLIiIiPZ6UYxMLKiKiasDS0hKLFi3CmjVrcOXKFXOnQ0RE9MQcm1hQERFVEwMHDoSXlxciIiLMnQoRERGAJ+PYxIKKiKgaWbJkCbZs2YLTp0+bOxUiIiIAVf/YxIKKiKga6dKlCwIDAxEWZtxoTEREROWlqh+bOMofEVE1s3jxYnh5eaF58+bmToWIiAhA1T428QwVEVE107p1a4wYMQLvvvuuuVMhIiICULWPTSYVVGvXroWbmxuUSiX8/Pxw8ODBEuN37NgBT09PKJVKtG7dGnv27NGa/uWXX6Jnz56oV68eZDIZUlNTtaZfvHgRMplM52vHjh1SnK7pMTExpqwiEdETbf78+SgoKDB3GkRERJKqemwy+pK/2NhYhIaGIjo6Gn5+foiKikJgYCDOnj0LR0fHYvH79+/H8OHDERkZiX79+mH79u0ICgrCkSNH0KpVKwBATk4OOnXqhJdeegljxowp1oerqyuuXr2q1bZhwwYsW7YMvXv31mrftGkTevXqJb23t7c3dhWJiIxj5NPhK5quB866ubkhNze34pMhIqKKwWNThTG6oFq5ciXGjBmDkJAQAEB0dDS++eYbbNy4ETNnziwWv3r1avTq1QvTp08HACxYsAAJCQl47733EB0dDQB45ZVXADw8E6WLpaUlVCqVVttXX32Fl156CTY2Nlrt9vb2xWKJiIiIiIjKg1GX/OXl5SElJQUBAQH/dWBhgYCAACQnJ+ucJzk5WSseAAIDA/XGGyIlJQWpqakYPXp0sWnjx4+Hg4MDfH19sXHjRgghTF4OERERERFRSYw6Q3Xjxg3k5+fDyclJq93JyQlnzpzROY9ardYZr1arjUz1Px999BGefvppdOzYUat9/vz5eO6552BtbY3vvvsO48aNw507dzBp0iSd/eTm5mqdVtRoNCbnRERERERE1U+VGzb9n3/+wfbt2zFnzpxi04q2tWvXDjk5OVi2bJnegioyMhLz5s0rt1yJiIiIiOjJZtQlfw4ODrC0tERmZqZWe2Zmpt77llQqlVHxpfn8889x9+5djBw5stRYPz8/XLlyRe/NbWFhYcjOzpZely9fNiknIiIiIiKqnowqqORyOby9vZGYmCi1FRQUIDExEf7+/jrn8ff314oHgISEBL3xpfnoo4/Qv39/1K9fv9TY1NRU1KlTBwqFQud0hUIBW1tbrRcREREREZGhjL7kLzQ0FMHBwfDx8YGvry+ioqKQk5Mjjfo3cuRIuLi4IDIyEgAwefJkdO3aFStWrEDfvn0RExODw4cPY8OGDVKft27dQnp6OjIyMgAAZ8+eBfDw7FbRM1nnz5/HTz/9VOw5VgDw9ddfIzMzEx06dIBSqURCQgIWLVqEN99809hVJCIiIiIiMojRBdXQoUNx/fp1hIeHQ61Ww8vLC/Hx8dLAE+np6bCw+O/EV8eOHbF9+3bMnj0bs2bNgoeHB+Li4qRnUAHArl27pIIMAIYNGwYAiIiIwNy5c6X2jRs3omHDhujZs2exvGrWrIm1a9di6tSpEEKgWbNm0hDvRERERERE5UEmOK64RKPRwM7ODtnZ2bz8j8xiVcIfZl3+1OefMuvyK7t79+4hLS0N7u7uUCqV5k6nyilp+3H/qx+3DVVVRY9pPL6UDx6XHl9ZHJuMuoeKiIiefNevX4enpycsLS3xxRdfmDsdIiKiSn1sqnLDphMRVTbrUtdV6PLGeY0zKn7UqFHYsmULIiMjMXPmTKk9Li4OAwcO1HoA+u3bt9G7d284ODhgxIgRGDFiBOzt7dGjRw+tPtevX4/169fj4sWLAICWLVsiPDwcvXv3Nn3FiIiozPDYVHHHJhZURETVgFKpxJIlS/Daa6+hTp06OmNyc3MxYMAA1KlTB3FxcahVqxYcHBzw4osvIjExET4+PlJsw4YNsXjxYnh4eEAIgS1btmDAgAE4evQoWrZsWVGrRUREVdiTcmziJX9ERNVAQEAAVCqVNALro/Lz8zF8+HDY2Nhg9+7dqFWrFgDgjTfewJo1a/DCCy9II7ACwAsvvIA+ffrAw8MDTz31FN555x3Y2Njgt99+q5D1ISKiqu9JOTaxoCIiqgYsLS2xaNEirFmzBleuXNE5/csvv8SuXbuKPbtv5MiRuHr1Kpo3b66z7/z8fMTExCAnJ8fkZwwSEVH186Qcm1hQERFVEwMHDoSXlxciIiLKpL/jx4/DxsYGCoUCr7/+Or766iu0aNGiTPo2l7Vr18LNzQ1KpRJ+fn44ePCg3tgvv/wSPj4+sLe3R61ateDl5YWtW7dqxYwaNQoymUzr1atXr/JeDSKiKuNJODaxoCIiqkaWLFmCLVu24PTp04/dV/PmzZGamooDBw7gjTfeQHBwME6dOlUGWZpHbGwsQkNDERERgSNHjqBt27YIDAzEtWvXdMbXrVsXb7/9NpKTk3Hs2DGEhIQgJCQEe/fu1Yrr1asXrl69Kr0+/fTTilgdIqIqo6ofm1hQERFVI126dEFgYCDCwsIeuy+5XI5mzZrB29sbkZGRaNu2LVavXl0GWZpH4cPgQ0JC0KJFC0RHR8Pa2hobN27UGd+tWzcMHDgQTz/9NJo2bYrJkyejTZs2+OWXX7TiFAoFVCqV9NJ34zURUXVV1Y9NLKiIiKqZxYsX4+uvv0ZycnKZ9ltQUIDc3Nwy7bOi5OXlISUlBQEBAVKbhYUFAgICDNpOQggkJibi7Nmz6NKli9a0pKQkODo6onnz5njjjTdw8+bNMs+fiKiqq8rHJg6bTkRUzbRu3RojRozAu+++a3IfYWFh6N27Nxo1aoTbt29j+/btSEpKKna5W1Vx48YN5Ofnw8nJSavdyckJZ86c0TtfdnY2XFxckJubC0tLS6xbtw7PP/+8NL1Xr1548cUX4e7ujgsXLmDWrFno3bs3kpOTYWlpqbPP3NxcrYO/RqN5zLUjIqr8qvKxiQUVEVE1NH/+fMTGxpo8/7Vr16QRluzs7NCmTRvs3btXq5ioDmrXro3U1FTcuXMHiYmJCA0NRZMmTdCtWzcAwLBhw6TY1q1bo02bNmjatCmSkpKKPZCyUGRkJObNm1cR6RMRVSpV9djEgoqI6DEZ+3T4irZ58+ZibW5ubo91CcRHH330GBlVPg4ODrC0tERmZqZWe2ZmJlQqld75LCws0KxZMwCAl5cXTp8+jcjISKmgelSTJk3g4OCA8+fP6y2owsLCEBoaKr3XaDRwdXU1co2IqLrjsani8B4qIiKq9uRyOby9vZGYmCi1FRQUIDEx0ajnl5R2rf6VK1dw8+ZNNGjQQG+MQqGAra2t1ouIiCovnqEiIiICEBoaiuDgYPj4+MDX1xdRUVHIyclBSEgIgIcPkXRxcUFkZCSAh5fm+fj4oGnTpsjNzcWePXuwdetWrF+/HgBw584dzJs3D4MGDYJKpcKFCxcwY8YMNGvWDIGBgWZbTyIiKlssqIiIiAAMHToU169fR3h4ONRqNby8vBAfHy8NVJGeng4Li/8u7MjJycG4ceNw5coVWFlZwdPTE5988gmGDh0KALC0tMSxY8ewZcsWZGVlwdnZGT179sSCBQugUCjMso5ERFT2WFARERH9a8KECZgwYYLOaUlJSVrvFy5ciIULF+rty8rKqsqOekhERIbjPVREREYSQpg7hSqJ242IqHxw/2q6sth2LKiIiAxU+NygvLw8M2dSNRVuN33PXyIiIuPUrFkTAHD37l0zZ1J1FW67wm1pCl7yR0RkoBo1asDa2hrXr19HzZo1te6noZIVFBTg+vXrsLa2Ro0aPPQQEZUFS0tL2Nvb49q1awAAa2tryGQyM2dVNQghcPfuXVy7dg329vaP9WMfj2pERAaSyWRo0KAB0tLScOnSJXOnU+VYWFigUaNGPNgTEZWhwmflFRZVZBx7e/sSnzdoCBZURERGkMvl8PDw4GV/JpDL5TyrR0RUxgp/7HN0dMT9+/fNnU6VUrNmzTK5DJ0FFRGRkSwsLKBUKs2dBhERkcTS0pL3qJoJfyokIiIiIiIyEQsqIiIiIiIiE7GgIiIiIiIiMhELKiIiIiIiIhOZVFCtXbsWbm5uUCqV8PPzw8GDB0uM37FjBzw9PaFUKtG6dWvs2bNHa/qXX36Jnj17ol69epDJZEhNTS3WR7du3SCTybRer7/+ulZMeno6+vbtC2trazg6OmL69Ol48OCBKatIRERERERUKqMLqtjYWISGhiIiIgJHjhxB27ZtERgYqHfs+/3792P48OEYPXo0jh49iqCgIAQFBeHEiRNSTE5ODjp16oQlS5aUuOwxY8bg6tWr0mvp0qXStPz8fPTt2xd5eXnYv38/tmzZgs2bNyM8PNzYVSQiIiIiIjKI0QXVypUrMWbMGISEhKBFixaIjo6GtbU1Nm7cqDN+9erV6NWrF6ZPn46nn34aCxYswDPPPIP33ntPinnllVcQHh6OgICAEpdtbW0NlUolvWxtbaVp3333HU6dOoVPPvkEXl5e6N27NxYsWIC1a9fyeTFERERERFQujCqo8vLykJKSolX4WFhYICAgAMnJyTrnSU5OLlYoBQYG6o0vybZt2+Dg4IBWrVohLCwMd+/e1VpO69at4eTkpLUcjUaDkydPGr0sIiIiIiKi0hj1YN8bN24gPz9fq2gBACcnJ5w5c0bnPGq1Wme8Wq02KtGXX34ZjRs3hrOzM44dO4a33noLZ8+exZdfflnicgqn6ZKbm4vc3FzpvUajMSonIiIiIiKq3owqqMxp7Nix0t9bt26NBg0aoEePHrhw4QKaNm1qUp+RkZGYN29eWaVIRERERETVjFGX/Dk4OMDS0hKZmZla7ZmZmVCpVDrnUalURsUbys/PDwBw/vz5EpdTOE2XsLAwZGdnS6/Lly8/Vk5ERERERFS9GFVQyeVyeHt7IzExUWorKChAYmIi/P39dc7j7++vFQ8ACQkJeuMNVTi0eoMGDaTlHD9+XGu0wYSEBNja2qJFixY6+1AoFLC1tdV6ERERERERGcroS/5CQ0MRHBwMHx8f+Pr6IioqCjk5OQgJCQEAjBw5Ei4uLoiMjAQATJ48GV27dsWKFSvQt29fxMTE4PDhw9iwYYPU561bt5Ceno6MjAwAwNmzZwFAGs3vwoUL2L59O/r06YN69erh2LFjmDp1Krp06YI2bdoAAHr27IkWLVrglVdewdKlS6FWqzF79myMHz8eCoXi8bYSERERERGRDkYXVEOHDsX169cRHh4OtVoNLy8vxMfHSwNApKenw8LivxNfHTt2xPbt2zF79mzMmjULHh4eiIuLQ6tWraSYXbt2SQUZAAwbNgwAEBERgblz50Iul+P777+XijdXV1cMGjQIs2fPluaxtLTE7t278cYbb8Df3x+1atVCcHAw5s+fb/xWISIiIiIiMoBMCCHMnURlodFoYGdnh+zsbF7+R2axKuEPsy5/6vNPmXX5VH1x/6sftw1VVUWPaTy+UFVk6P7X6Af7EhERERER0UMsqIiIiIiIiEzEgoqIiIiIiMhELKiIiIj+tXbtWri5uUGpVMLPzw8HDx7UG/vll1/Cx8cH9vb2qFWrFry8vLB161atGCEEwsPD0aBBA1hZWSEgIADnzp0r79UgIqIKxIKKiIgIQGxsLEJDQxEREYEjR46gbdu2CAwM1Hq+YVF169bF22+/jeTkZBw7dgwhISEICQnB3r17pZilS5fi3XffRXR0NA4cOIBatWohMDAQ9+7dq6jVIiKicsaCioiICMDKlSsxZswYhISEoEWLFoiOjoa1tTU2btyoM75bt24YOHAgnn76aTRt2hSTJ09GmzZt8MsvvwB4eHYqKioKs2fPxoABA9CmTRt8/PHHyMjIQFxcXAWuGRERlScWVEREVO3l5eUhJSUFAQEBUpuFhQUCAgKQnJxc6vxCCCQmJuLs2bPo0qULACAtLQ1qtVqrTzs7O/j5+RnUJxERVQ1GP9iXiIjoSXPjxg3k5+dLD6kv5OTkhDNnzuidLzs7Gy4uLsjNzYWlpSXWrVuH559/HgCgVqulPh7ts3CaLrm5ucjNzZXeazQao9eHiIgqDgsqIiIiE9WuXRupqam4c+cOEhMTERoaiiZNmqBbt24m9xkZGYl58+aVXZJERFSueMkfERFVew4ODrC0tERmZqZWe2ZmJlQqld75LCws0KxZM3h5eWHatGkYPHgwIiMjAUCaz9g+w8LCkJ2dLb0uX75s6moREVEFYEFFRETVnlwuh7e3NxITE6W2goICJCYmwt/f3+B+CgoKpMv13N3doVKptPrUaDQ4cOBAiX0qFArY2tpqvYiIqPLiJX9EREQAQkNDERwcDB8fH/j6+iIqKgo5OTkICQkBAIwcORIuLi7SGajIyEj4+PigadOmyM3NxZ49e7B161asX78eACCTyTBlyhQsXLgQHh4ecHd3x5w5c+Ds7IygoCBzrSYREZUxFlREREQAhg4diuvXryM8PBxqtRpeXl6Ij4+XBpVIT0+HhcV/F3bk5ORg3LhxuHLlCqysrODp6YlPPvkEQ4cOlWJmzJiBnJwcjB07FllZWejUqRPi4+OhVCorfP2IiKh8yIQQwtxJVBYajQZ2dnbIzs7mJRZkFqsS/jDr8qc+/5RZl0/VF/e/+nHbUFVV9JjG4wtVRYbuf3kPFRERERERkYlYUBEREREREZmIBRUREREREZGJWFARERERERGZiAUVERERERGRiVhQERERERERmYgFFRERERERkYlYUBEREREREZmIBRUREREREZGJWFARERERERGZqIa5EyAi4x3RxJZLv+tS65VZX+O8xpVZX0RERESVFc9QERERERERmcikgmrt2rVwc3ODUqmEn58fDh48WGL8jh074OnpCaVSidatW2PPnj1a07/88kv07NkT9erVg0wmQ2pqqtb0W7duYeLEiWjevDmsrKzQqFEjTJo0CdnZ2VpxMpms2CsmJsaUVSQiIiIiIiqV0QVVbGwsQkNDERERgSNHjqBt27YIDAzEtWvXdMbv378fw4cPx+jRo3H06FEEBQUhKCgIJ06ckGJycnLQqVMnLFmyRGcfGRkZyMjIwPLly3HixAls3rwZ8fHxGD16dLHYTZs24erVq9IrKCjI2FUkIiIiIiIyiNH3UK1cuRJjxoxBSEgIACA6OhrffPMNNm7ciJkzZxaLX716NXr16oXp06cDABYsWICEhAS89957iI6OBgC88sorAICLFy/qXGarVq3wxRdfSO+bNm2Kd955B//3f/+HBw8eoEaN/1bD3t4eKpXK2NUiIiIiIiIymlFnqPLy8pCSkoKAgID/OrCwQEBAAJKTk3XOk5ycrBUPAIGBgXrjDZWdnQ1bW1utYgoAxo8fDwcHB/j6+mLjxo0QQjzWcoiIiIiIiPQx6gzVjRs3kJ+fDycnJ612JycnnDlzRuc8arVaZ7xarTYyVe08FixYgLFjx2q1z58/H8899xysra3x3XffYdy4cbhz5w4mTZqks5/c3Fzk5uZK7zUajck5ERERERFR9VPlhk3XaDTo27cvWrRogblz52pNmzNnjvT3du3aIScnB8uWLdNbUEVGRmLevHnlmS4RERERET3BjLrkz8HBAZaWlsjMzNRqz8zM1HvfkkqlMiq+JLdv30avXr1Qu3ZtfPXVV6hZs2aJ8X5+frhy5YrWWaiiwsLCkJ2dLb0uX75sdE5ERERERFR9GVVQyeVyeHt7IzExUWorKChAYmIi/P39dc7j7++vFQ8ACQkJeuP10Wg06NmzJ+RyOXbt2gWlUlnqPKmpqahTpw4UCoXO6QqFAra2tlovIiIiIiIiQxl9yV9oaCiCg4Ph4+MDX19fREVFIScnRxr1b+TIkXBxcUFkZCQAYPLkyejatStWrFiBvn37IiYmBocPH8aGDRukPm/duoX09HRkZGQAAM6ePQvg4dktlUolFVN3797FJ598Ao1GI93vVL9+fVhaWuLrr79GZmYmOnToAKVSiYSEBCxatAhvvvnm420hIiIiIiIiPYwuqIYOHYrr168jPDwcarUaXl5eiI+PlwaeSE9Ph4XFfye+OnbsiO3bt2P27NmYNWsWPDw8EBcXh1atWkkxu3btkgoyABg2bBgAICIiAnPnzsWRI0dw4MABAECzZs208klLS4Obmxtq1qyJtWvXYurUqRBCoFmzZtIQ70REREREROVBJjiuuESj0cDOzk4akp2ooq1K+MOguCOa2HJZvn/TemXW1zivcWXWFz35uP/Vj9uGqqqix7Spzz9lxkyITGPo/teoe6iIiIiIiIjoPyyoiIiI/rV27Vq4ublBqVTCz88PBw8e1Bv7wQcfoHPnzqhTpw7q1KmDgICAYvGjRo2CTCbTevXq1au8V4OIiCoQCyoiIiIAsbGxCA0NRUREBI4cOYK2bdsiMDAQ165d0xmflJSE4cOHY9++fUhOToarqyt69uyJv/76SyuuV69euHr1qvT69NNPK2J1iIiogrCgIiIiAqSBjEJCQtCiRQtER0fD2toaGzdu1Bm/bds2jBs3Dl5eXvD09MSHH34oPUqkKIVCIY1aq1KpUKdOnYpYHSIiqiAsqIiIqNrLy8tDSkoKAgICpDYLCwsEBAQgOTnZoD7u3r2L+/fvo27dulrtSUlJcHR0RPPmzfHGG2/g5s2bJfaTm5srPR6k6GNCiIiocmJBRURE1d6NGzeQn58vPQKkkJOTE9RqtUF9vPXWW3B2dtYqynr16oWPP/4YiYmJWLJkCX788Uf07t0b+fn5evuJjIyEnZ2d9HJ1dTVtpYiIqEIY/RwqIiIi0rZ48WLExMQgKSkJSqVSai98riIAtG7dGm3atEHTpk2RlJSEHj166OwrLCwMoaGh0nuNRsOiioioEuMZKiIiqvYcHBxgaWmJzMxMrfbMzEyoVKoS512+fDkWL16M7777Dm3atCkxtkmTJnBwcMD58+f1xigUCtja2mq9iIio8mJBRURE1Z5cLoe3t7fWgBKFA0z4+/vrnW/p0qVYsGAB4uPj4ePjU+pyrly5gps3b6JBgwZlkjcREZkfCyoiIiIAoaGh+OCDD7BlyxacPn0ab7zxBnJychASEgIAGDlyJMLCwqT4JUuWYM6cOdi4cSPc3NygVquhVqtx584dAMCdO3cwffp0/Pbbb7h48SISExMxYMAANGvWDIGBgWZZRyIiKnu8h4qIiAjA0KFDcf36dYSHh0OtVsPLywvx8fHSQBXp6emwsPjvd8j169cjLy8PgwcP1uonIiICc+fOhaWlJY4dO4YtW7YgKysLzs7O6NmzJxYsWACFQlGh60ZEROWHBRUREdG/JkyYgAkTJuiclpSUpPX+4sWLJfZlZWWFvXv3llFmRERUWfGSPyIiIiIiIhOxoCIiIiIiIjIRCyoiIiIiIiITsaAiIiIiIiIyEQsqIiIiIiIiE7GgIiIiIiIiMhELKiIiIiIiIhOxoCIiIiIiIjIRCyoiIiIiIiITsaAiIiIiIiIyEQsqIiIiIiIiE7GgIiIiIiIiMhELKiIiIiIiIhOxoCIiIiIiIjKRSQXV2rVr4ebmBqVSCT8/Pxw8eLDE+B07dsDT0xNKpRKtW7fGnj17tKZ/+eWX6NmzJ+rVqweZTIbU1NRifdy7dw/jx49HvXr1YGNjg0GDBiEzM1MrJj09HX379oW1tTUcHR0xffp0PHjwwJRVJCIiIiIiKpXRBVVsbCxCQ0MRERGBI0eOoG3btggMDMS1a9d0xu/fvx/Dhw/H6NGjcfToUQQFBSEoKAgnTpyQYnJyctCpUycsWbJE73KnTp2Kr7/+Gjt27MCPP/6IjIwMvPjii9L0/Px89O3bF3l5edi/fz+2bNmCzZs3Izw83NhVJCIiIiIiMohMCCGMmcHPzw/t27fHe++9BwAoKCiAq6srJk6ciJkzZxaLHzp0KHJycrB7926prUOHDvDy8kJ0dLRW7MWLF+Hu7o6jR4/Cy8tLas/Ozkb9+vWxfft2DB48GABw5swZPP3000hOTkaHDh3w7bffol+/fsjIyICTkxMAIDo6Gm+99RauX78OuVxe6rppNBrY2dkhOzsbtra2xmwWojKxKuEPg+KOaGLLZfn+TeuVWV/jvMaVWV/05OP+Vz9uG6qqih7Tpj7/lBkzITKNoftfo85Q5eXlISUlBQEBAf91YGGBgIAAJCcn65wnOTlZKx4AAgMD9cbrkpKSgvv372v14+npiUaNGkn9JCcno3Xr1lIxVbgcjUaDkydPGrwsIiIiIiIiQ9UwJvjGjRvIz8/XKloAwMnJCWfOnNE5j1qt1hmvVqsNXq5arYZcLoe9vb3efvQtp3CaLrm5ucjNzZXeazQag3MiIiIiIiKq1qP8RUZGws7OTnq5urqaOyUiIiIiIqpCjCqoHBwcYGlpWWx0vczMTKhUKp3zqFQqo+L19ZGXl4esrCy9/ehbTuE0XcLCwpCdnS29Ll++bHBORERERERERhVUcrkc3t7eSExMlNoKCgqQmJgIf39/nfP4+/trxQNAQkKC3nhdvL29UbNmTa1+zp49i/T0dKkff39/HD9+XGu0wYSEBNja2qJFixY6+1UoFLC1tdV6ERERERERGcqoe6gAIDQ0FMHBwfDx8YGvry+ioqKQk5ODkJAQAMDIkSPh4uKCyMhIAMDkyZPRtWtXrFixAn379kVMTAwOHz6MDRs2SH3eunUL6enpyMjIAPCwWAIenllSqVSws7PD6NGjERoairp168LW1hYTJ06Ev78/OnToAADo2bMnWrRogVdeeQVLly6FWq3G7NmzMX78eCgUisfbSkRERERERDoYXVANHToU169fR3h4ONRqNby8vBAfHy8NAJGeng4Li/9OfHXs2BHbt2/H7NmzMWvWLHh4eCAuLg6tWrWSYnbt2iUVZAAwbNgwAEBERATmzp0LAFi1ahUsLCwwaNAg5ObmIjAwEOvWrZPmsbS0xO7du/HGG2/A398ftWrVQnBwMObPn2/sKhIRERERERnE6OdQPcn4rA8yNz6HiqqryrL/Xbt2LZYtWwa1Wo22bdtizZo18PX11Rn7wQcf4OOPP5YeVO/t7Y1FixZpxQshEBERgQ8++ABZWVl49tlnsX79enh4eBicU2XZNkTG4nOoqKorl+dQERERPaliY2MRGhqKiIgIHDlyBG3btkVgYKDWvblFJSUlYfjw4di3bx+Sk5Ph6uqKnj174q+//pJili5dinfffRfR0dE4cOAAatWqhcDAQNy7d6+iVouIiMoZCyoiIiIAK1euxJgxYxASEoIWLVogOjoa1tbW2Lhxo874bdu2Ydy4cfDy8oKnpyc+/PBDaaAm4OHZqaioKMyePRsDBgxAmzZt8PHHHyMjIwNxcXEVuGZERFSeWFAREVG1l5eXh5SUFAQEBEhtFhYWCAgIQHJyskF93L17F/fv30fdunUBAGlpaVCr1Vp92tnZwc/Pr8Q+c3NzodFotF5ERFR5saAiIqJq78aNG8jPz5cGWCrk5OQEtVptUB9vvfUWnJ2dpQKqcD5j++RD54mIqhYWVERERI9p8eLFiImJwVdffQWlUvlYffGh80REVYvRw6YTERE9aRwcHGBpaYnMzEyt9szMTKhUqhLnXb58ORYvXozvv/8ebdq0kdoL58vMzESDBg20+vTy8tLbn0Kh4PMTiYiqEJ6hIiKiak8ul8Pb21saUAKANMCEv7+/3vmWLl2KBQsWID4+Hj4+PlrT3N3doVKptPrUaDQ4cOBAiX0SEVHVwjNUREREAEJDQxEcHAwfHx/4+voiKioKOTk50oPnR44cCRcXF0RGRgIAlixZgvDwcGzfvh1ubm7SfVE2NjawsbGBTCbDlClTsHDhQnh4eMDd3R1z5syBs7MzgoKCzLWaRERUxlhQERERARg6dCiuX7+O8PBwqNVqeHl5IT4+XhpUIj09HRYW/13YsX79euTl5WHw4MFa/URERGDu3LkAgBkzZiAnJwdjx45FVlYWOnXqhPj4+Me+z4qIiCoPFlRERET/mjBhAiZMmKBzWlJSktb7ixcvltqfTCbD/PnzMX/+/DLIjoiIKiPeQ0VERERERGQiFlREREREREQmYkFFRERERERkIhZUREREREREJmJBRUREREREZCIWVERERERERCZiQUVERERERGQiFlREREREREQmYkFFRERERERkIhZUREREREREJmJBRUREREREZCIWVERERERERCaqYe4EiIiIiOjJdEQTCwBYl1oPADDOa5w50yEqFzxDRUREREREZCIWVERERERERCZiQUVERERERGQiFlREREREREQmMqmgWrt2Ldzc3KBUKuHn54eDBw+WGL9jxw54enpCqVSidevW2LNnj9Z0IQTCw8PRoEEDWFlZISAgAOfOnZOmJyUlQSaT6XwdOnQIAHDx4kWd03/77TdTVpGIiIiIiKhURhdUsbGxCA0NRUREBI4cOYK2bdsiMDAQ165d0xm/f/9+DB8+HKNHj8bRo0cRFBSEoKAgnDhxQopZunQp3n33XURHR+PAgQOoVasWAgMDce/ePQBAx44dcfXqVa3Xq6++Cnd3d/j4+Ggt7/vvv9eK8/b2NnYViYiIiIiIDGJ0QbVy5UqMGTMGISEhaNGiBaKjo2FtbY2NGzfqjF+9ejV69eqF6dOn4+mnn8aCBQvwzDPP4L333gPw8OxUVFQUZs+ejQEDBqBNmzb4+OOPkZGRgbi4OACAXC6HSqWSXvXq1cPOnTsREhICmUymtbx69eppxdasWdPYVSQiIiIiIjKIUQVVXl4eUlJSEBAQ8F8HFhYICAhAcnKyznmSk5O14gEgMDBQik9LS4NardaKsbOzg5+fn94+d+3ahZs3byIkJKTYtP79+8PR0RGdOnXCrl27Slyf3NxcaDQarRcREREREZGhjCqobty4gfz8fDg5OWm1Ozk5Qa1W65xHrVaXGF/4pzF9fvTRRwgMDETDhg2lNhsbG6xYsQI7duzAN998g06dOiEoKKjEoioyMhJ2dnbSy9XVVW8sERERERHRo2qYOwFjXblyBXv37sVnn32m1e7g4IDQ0FDpffv27ZGRkYFly5ahf//+OvsKCwvTmkej0bCoIiIiIiIigxl1hsrBwQGWlpbIzMzUas/MzIRKpdI5j0qlKjG+8E9D+9y0aRPq1aunt0gqys/PD+fPn9c7XaFQwNbWVutFRERERERkKKMKKrlcDm9vbyQmJkptBQUFSExMhL+/v855/P39teIBICEhQYp3d3eHSqXSitFoNDhw4ECxPoUQ2LRpE0aOHGnQYBOpqalo0KCBwetHRETVmzGPBTl58iQGDRoENzc3yGQyREVFFYuZO3duscd5eHp6luMaEBFRRTP6kr/Q0FAEBwfDx8cHvr6+iIqKQk5OjjRAxMiRI+Hi4oLIyEgAwOTJk9G1a1esWLECffv2RUxMDA4fPowNGzYAAGQyGaZMmYKFCxfCw8MD7u7umDNnDpydnREUFKS17B9++AFpaWl49dVXi+W1ZcsWyOVytGvXDgDw5ZdfYuPGjfjwww+NXUUiIqqGCh8LEh0dDT8/P0RFRSEwMBBnz56Fo6Njsfi7d++iSZMmGDJkCKZOnaq335YtW+L777+X3teoUeWuticiohIYvVcfOnQorl+/jvDwcKjVanh5eSE+Pl4aVCI9PR0WFv+d+OrYsSO2b9+O2bNnY9asWfDw8EBcXBxatWolxcyYMQM5OTkYO3YssrKy0KlTJ8THx0OpVGot+6OPPkLHjh31/rq3YMECXLp0CTVq1ICnpydiY2MxePBgY1eRiIiqoaKPBQGA6OhofPPNN9i4cSNmzpxZLL59+/Zo3749AOicXqhGjRp6L4snIqKqz6SfySZMmIAJEybonJaUlFSsbciQIRgyZIje/mQyGebPn4/58+eXuNzt27frnRYcHIzg4OAS5yciItKl8LEgYWFhUltpjwUx1Llz5+Ds7AylUgl/f39ERkaiUaNGeuNzc3ORm5srvecjPYiIKjejH+xLRET0pDHlsSCG8PPzw+bNmxEfH4/169cjLS0NnTt3xu3bt/XOw0d6EBFVLSyoiIiIyknv3r0xZMgQtGnTBoGBgdizZw+ysrKKPfqjqLCwMGRnZ0uvy5cvV2DGRERkLN4ZS0RE1Z4pjwUxhb29PZ566qlSH+mhUCjKbJlERFS+eIaKiIiqPVMeC2KKO3fu4MKFC3ykBxHRE4RnqIiIiGD8Y0Hy8vJw6tQp6e9//fUXUlNTYWNjg2bNmgEA3nzzTbzwwgto3LgxMjIyEBERAUtLSwwfPtw8K0lERGWOBRURERGMfyxIRkaG9OxDAFi+fDmWL1+Orl27SiPeXrlyBcOHD8fNmzdRv359dOrUCb/99hvq169foetGRETlhwUVERHRv4x5LIibmxuEECX2FxMTU1apERFRJcV7qIiIiIiIiEzEgoqIiIiIiMhELKiIiIiIiIhMxIKKiIiIiIjIRCyoiIiIiIiITMSCioiIiIiIyEQsqIiIiIiIiEzEgoqIiIiIiMhELKiIiIiIiIhMxIKKiIiIiIjIRCyoiIiIiIiITMSCioiIiIiIyEQsqIiIiIiIiEzEgoqIiIiIiMhELKiIiIiIiIhMxIKKiIiIiIjIRCyoiIiIiIiITMSCioiIiIiIyEQsqIiIiIiIiExkUkG1du1auLm5QalUws/PDwcPHiwxfseOHfD09IRSqUTr1q2xZ88erelCCISHh6NBgwawsrJCQEAAzp07pxXj5uYGmUym9Vq8eLFWzLFjx9C5c2colUq4urpi6dKlpqweERERERGRQYwuqGJjYxEaGoqIiAgcOXIEbdu2RWBgIK5du6Yzfv/+/Rg+fDhGjx6No0ePIigoCEFBQThx4oQUs3TpUrz77ruIjo7GgQMHUKtWLQQGBuLevXtafc2fPx9Xr16VXhMnTpSmaTQa9OzZE40bN0ZKSgqWLVuGuXPnYsOGDcauIhERERERkUGMLqhWrlyJMWPGICQkBC1atEB0dDSsra2xceNGnfGrV69Gr169MH36dDz99NNYsGABnnnmGbz33nsAHp6dioqKwuzZszFgwAC0adMGH3/8MTIyMhAXF6fVV+3ataFSqaRXrVq1pGnbtm1DXl4eNm7ciJYtW2LYsGGYNGkSVq5caewqEhERERERGcSogiovLw8pKSkICAj4rwMLCwQEBCA5OVnnPMnJyVrxABAYGCjFp6WlQa1Wa8XY2dnBz8+vWJ+LFy9GvXr10K5dOyxbtgwPHjzQWk6XLl0gl8u1lnP27Fn8/fffOnPLzc2FRqPRehERERERERnKqILqxo0byM/Ph5OTk1a7k5MT1Gq1znnUanWJ8YV/ltbnpEmTEBMTg3379uG1117DokWLMGPGjFKXU3QZj4qMjISdnZ30cnV11bvuRET05DPmHuGTJ09i0KBB0j2+UVFRj90nERFVPVVmlL/Q0FB069YNbdq0weuvv44VK1ZgzZo1yM3NNbnPsLAwZGdnS6/Lly+XYcZERFSVGHuP8N27d9GkSRMsXrwYKpWqTPokIqKqx6iCysHBAZaWlsjMzNRqz8zM1HswUalUJcYX/mlMnwDg5+eHBw8e4OLFiyUup+gyHqVQKGBra6v1IiKi6snYe4Tbt2+PZcuWYdiwYVAoFGXSJxERVT1GFVRyuRze3t5ITEyU2goKCpCYmAh/f3+d8/j7+2vFA0BCQoIU7+7uDpVKpRWj0Whw4MABvX0CQGpqKiwsLODo6Cgt56effsL9+/e1ltO8eXPUqVPHmNUkIqJqxpR7hM3RJxERVT5GX/IXGhqKDz74AFu2bMHp06fxxhtvICcnByEhIQCAkSNHIiwsTIqfPHky4uPjsWLFCpw5cwZz587F4cOHMWHCBACATCbDlClTsHDhQuzatQvHjx/HyJEj4ezsjKCgIAAPB5yIiorC77//jj///BPbtm3D1KlT8X//939SsfTyyy9DLpdj9OjROHnyJGJjY7F69WqEhoY+7jYiIqInnCn3CJdXnxwwiYioaqlh7AxDhw7F9evXER4eDrVaDS8vL8THx0sHjPT0dFhY/FendezYEdu3b8fs2bMxa9YseHh4IC4uDq1atZJiZsyYgZycHIwdOxZZWVno1KkT4uPjoVQqATy8NC8mJgZz585Fbm4u3N3dMXXqVK1iyc7ODt999x3Gjx8Pb29vODg4IDw8HGPHjjV54xAREVW0yMhIzJs3z9xpEBGRgYwuqABgwoQJ0hmmRyUlJRVrGzJkCIYMGaK3P5lMhvnz52P+/Pk6pz/zzDP47bffSs2rTZs2+Pnnn0uNIyIiKsqUe4TLq8+wsDCtHww1Gg1HoSUiqsSqzCh/RERE5cWUe4TLq08OmEREVLWYdIaKiIjoSRMaGorg4GD4+PjA19cXUVFRxe4RdnFxQWRkJICHg06cOnVK+vtff/2F1NRU2NjYoFmzZgb1SUREVR8LKiIiIhh/j3BGRgbatWsnvV++fDmWL1+Orl27Spe/l9YnERFVfSyoiIiI/mXMPcJubm4QQjxWn0REVPXxHioiIiIiIiITsaAiIiIiIiIyES/5I6os9kWiQ/pNg0KvWZwHAFyx9S7PjIiIiIioFDxDRUREREREZCKeoSKqRhpqUkoOSLPSfu/eufySISIiInoC8AwVERERERGRiVhQERERERERmYgFFRERERERkYl4DxURlZ20n//7+9/Zpcd3Dyu/XIiIiIgqAAsqIkPtizQuvgKKhVIHmajsjN2mAIswIiIiqlRYUNGToxIWPERERET0ZGNBRVReTDn7QkRERERVCgsqokesS12ne0LWsXJf9mWLf8p9GURERERUdjjKHxERERERkYl4hoqqL32X5FXAmagqo+iofZUF75UjIqr0ViX8ofU++cJNAMA4LzMkQ1TOeIaKiIiIiIjIRCyoiIiIiIiITMSCioiIiIiIyEQsqIiIiIiIiEzEgoqIiIiIiMhELKiIiIiIiIhMxGHTqWIYO9Q1EREREVEVYNIZqrVr18LNzQ1KpRJ+fn44ePBgifE7duyAp6cnlEolWrdujT179mhNF0IgPDwcDRo0gJWVFQICAnDu3Dlp+sWLFzF69Gi4u7vDysoKTZs2RUREBPLy8rRiZDJZsddvv/1myioSERERERGVyuiCKjY2FqGhoYiIiMCRI0fQtm1bBAYG4tq1azrj9+/fj+HDh2P06NE4evQogoKCEBQUhBMnTkgxS5cuxbvvvovo6GgcOHAAtWrVQmBgIO7duwcAOHPmDAoKCvD+++/j5MmTWLVqFaKjozFr1qxiy/v+++9x9epV6eXt7W3sKhIRERERERlEJoQQxszg5+eH9u3b47333gMAFBQUwNXVFRMnTsTMmTOLxQ8dOhQ5OTnYvXu31NahQwd4eXkhOjoaQgg4Oztj2rRpePPNNwEA2dnZcHJywubNmzFs2DCdeSxbtgzr16/Hn3/+CeDhGSp3d3ccPXoUXl5exqySRKPRwM7ODtnZ2bC1tTWpD9KjCl3yty7rmNmWfTnrH7MtGwBc7a3KrK9x9m3KrK8K1T3M3BlUS5Vl/7t27VosW7YMarUabdu2xZo1a+Dr66s3fseOHZgzZw4uXrwIDw8PLFmyBH369JGmjxo1Clu2bNGaJzAwEPHx8QbnVFm2DZExViX8AQA4oonVat86aI450iEyiaH7X6POUOXl5SElJQUBAQH/dWBhgYCAACQnJ+ucJzk5WSseeHgwKYxPS0uDWq3WirGzs4Ofn5/ePoGHRVfdunWLtffv3x+Ojo7o1KkTdu3aVeL65ObmQqPRaL2IiKh6Ko8rMACgV69eWldOfPrppxWxOkREVEGMGpTixo0byM/Ph5OTk1a7k5MTzpw5o3MetVqtM16tVkvTC9v0xTzq/PnzWLNmDZYvXy612djYYMWKFXj22WdhYWGBL774AkFBQYiLi0P//v119hMZGYl58+aVsMZEVO0YezaVZ7SeGCtXrsSYMWMQEhICAIiOjsY333yDjRs36rwCY/Xq1ejVqxemT58OAFiwYAESEhLw3nvvITo6WopTKBRQqVQVsxJERFThqtwof3/99Rd69eqFIUOGYMyYMVK7g4MDQkNDpfft27dHRkYGli1bpregCgsL05pHo9HA1dW1/JInIqJKqfAKjLCw/wpkQ67AKHoMAR5egREXF6fVlpSUBEdHR9SpUwfPPfccFi5ciHr16pX5OhBVButS1wEAjmhumjkToopj1CV/Dg4OsLS0RGZmplZ7Zmam3l/fVCpVifGFfxrSZ0ZGBrp3746OHTtiw4YNpebr5+eH8+fP652uUChga2ur9SIiouqnpCsw9F0tUdoVGMDDy/0+/vhjJCYmYsmSJfjxxx/Ru3dv5Ofn682Fl6MTEVUtRhVUcrkc3t7eSExMlNoKCgqQmJgIf39/nfP4+/trxQNAQkKCFO/u7g6VSqUVo9FocODAAa0+//rrL3Tr1g3e3t7YtGkTLCxKTz01NRUNGjQwZhWJiIjKzLBhw9C/f3+0bt0aQUFB2L17Nw4dOoSkpCS980RGRsLOzk568coJIqLKzehL/kJDQxEcHAwfHx/4+voiKioKOTk50jXnI0eOhIuLCyIjH96HMHnyZHTt2hUrVqxA3759ERMTg8OHD0tnmGQyGaZMmYKFCxfCw8MD7u7umDNnDpydnREUFATgv2KqcePGWL58Oa5fvy7lU3gWa8uWLZDL5WjXrh0A4Msvv8TGjRvx4Ycfmr51iIhKY8oIlrzvqtIpjyswdGnSpAkcHBxw/vx59OjRQ2cML0cnIqpajC6ohg4diuvXryM8PBxqtRpeXl6Ij4+XLntIT0/XOnvUsWNHbN++HbNnz8asWbPg4eGBuLg4tGrVSoqZMWMGcnJyMHbsWGRlZaFTp06Ij4+HUqkE8PCM1vnz53H+/Hk0bNhQK5+io74vWLAAly5dQo0aNeDp6YnY2FgMHjzY2FUkIqJqpugVGIU/5hVegTFhwgSd8xRegTFlyhSpregVGLpcuXIFN2/eLPHqCYVCAYVCYdJ6EBFRxTP6OVRPMj7rwwhV6LlSxuJzqMpGlX0OVUXgGapiKsP+NzY2FsHBwXj//felKzA+++wznDlzBk5OTsWuwNi/fz+6du2KxYsXS1dgLFq0CEeOHEGrVq1w584dzJs3D4MGDYJKpcKFCxcwY8YM3L59G8ePHze4aKoM24bIUIWDUiRf0D0oBZ9DRVWJofvfKjfKHxERUXko6yswLC0tcezYMWzZsgVZWVlwdnZGz549sWDBAp6BIiJ6grCgIiIi+teECRP0XuKnayCJIUOGYMiQITrjrayssHfv3rJMj4iIKiGjRvkjIiIiIiKi/7CgIiIiIiIiMhEv+SMqY+YeWOJxPG7uZTmoBREREVFVwDNUREREREREJuIZKnroCR4GnajSMfb/G4dZJ6IqYFXCHzii0T1cetGYQlOff6q8UyKqECyoiIgqOxZgRERElRYv+SMiIiIiIjIRz1A9qXgJHxERERFRuWNBRUT0pOElgkRUSR3RxEp/X5daD+O8xpkxG6KywYKqKuDZJiIiIiKiSokFFRGVi3VZx8ydQqnG2bcxdwpERERUxbGgIiKq7niJIBGZaF3qOunvpQ2ZTvSkYkFF9IjLWf+YO4Uq63G2nau9VRlmQkRERFQxWFARERERkVkUPcMFgINUUJXE51ARERERERGZiGeoygJH4TNYVRiogIiIiIjIUCyoiIiIiKhUqxL+KNb2OANRJF8oPm/u9f+WMfX5p0zum6gisaAiIiLjmHJWniMDEj0Rij6Yt7z754N/qapgQUWVzuOOssfR4qonUz43ybf++3XUv0m9skyHiKhKqmyDRFS2fIh0YUFFTxwOe141mePfbZfFeenvR7P+qvDlG4IPHyYiIqrcWFDp8tMKoJbS3FkQERERlZtHz/6UFlMZHtyrK2eetSJzY0FFRETlr7T7rnLuVUweRNWYIQXUk4CXCVJFY0FVSSX/afyvQEUvX3rc+4h42RxVN+b+zD/O/1lT9hdF8f6xqqlwxDVTRkJblfBHhc8HGJ9rafPpm17SfKWtg77phuRi6nyF0w35e2nzFc1lXeo6JF+4Cf+m//0f1zWyXmmKzm8OpeWcfGGB1vtH1zf5wgKpLfnCTWwdNAeA9r+Zrn8/fdMf/TtQtp/R8pjv0byN7bMy/b8v6/kK532cUSVZUBERVWKGPLvtssXjFYOPe/8Y7/OiKmlfZPmOPlne/etQeGbmiOYm1n11CnDvXKHLryq0thNHEqQyYFJBtXbtWixbtgxqtRpt27bFmjVr4Ovrqzd+x44dmDNnDi5evAgPDw8sWbIEffr0kaYLIRAREYEPPvgAWVlZePbZZ7F+/Xp4eHhIMbdu3cLEiRPx9ddfw8LCAoMGDcLq1athY2MjxRw7dgzjx4/HoUOHUL9+fUycOBEzZswwZRWLqegH0j7uFyQiIjKeOY5vJtkXCWBQCdNQ4pf5DukbACw3KLbCGVqIlLQNStAhfQOwr5QzLuVVDD3S77rUddJ9SetS6wEIKHF26VK2tJ9xLesfXLH1xrqvTkl/969ftmeSGmpScMXWu9S2x+kfgP7+0n4G3DvrXWaZ5JL2M9al/YwjBS3+/Tf4T2HB9ejfO6T/+fAz1D0MHdI34LdGY/V2//D/GgAsNzynfZHokH5Tu9+SPpO6ppmhoC83huynTNwf6OyncDn7IgHv8QbNZnRBFRsbi9DQUERHR8PPzw9RUVEIDAzE2bNn4ejoWCx+//79GD58OCIjI9GvXz9s374dQUFBOHLkCFq1agUAWLp0Kd59911s2bIF7u7umDNnDgIDA3Hq1CkolQ8HhxgxYgSuXr2KhIQE3L9/HyEhIRg7diy2b98OANBoNOjZsycCAgIQHR2N48eP43//+x/s7e0xdqz+D7ouBy/eQi0rhVZbVStwzH35EhEZx5z/Zx932UWHnzdVzj+5j93H4zLX8a1CFP1Cout+NmO/fBXG6/uiU3QZ/06TCpmiX1Z0zVvaMvVYl7pO+gJ+RHMTz9gONWo9Cn84PVLQAussTmHcI+tQ+HwkrS/daT8//PPfZWpNyzoG/FswNdSkYF1qT6mt6PwNNQ+LIaT9jA63/vx3wnJ0SN+AdfZ2WJdaTyq6/O+c0kq/oSYFKOVy4YaaFCDNSutsldEFyr/r2VDzj87YkgobU4qewkKrtHUzZFlSX+ipHZz2M4AWpXf672eqqF0W5x+e2U9dh8sW5/Ho3mHdV8OleS7/ezvG0SJtD/1bPJv4o4bWfWJZx1B4jk1vgVdYcOj4f1RiUfhvcWdUQfhov7rW8XF/zDHqh5ci9O6r9BRjP60wKB2ZEEIYFPkvPz8/tG/fHu+99x4AoKCgAK6urpg4cSJmzpxZLH7o0KHIycnB7t27pbYOHTrAy8sL0dHREELA2dkZ06ZNw5tvvgkAyM7OhpOTEzZv3oxhw4bh9OnTaNGiBQ4dOgQfHx8AQHx8PPr06YMrV67A2dkZ69evx9tvvw21Wg25XA4AmDlzJuLi4nDmzBmD1k2j0cDOzg5T1/aBwqqmMZuFiIgeQ+4/97Fq/B5kZ2fD1tbWLDmY4/hmiMJjk7Rt/v0CUHjvnP/of7/oPFrkFNLRlvznTeneuUevwNB5Cee/X0JWJfyBqTW+0NtvScsDDLhf75EirfCeCMWdCO04985A2s/SjwGu7f79svzvF3+pvfAL+b/xcO+My0e/K/GexctZ/+icnlzQAg01Kf8tq8jyis1XuDxduehYXuH0outz+eh3Wu1XbL3hb3FK73xFpycXtJD+/uj6PPoDStGiSJ/C+Uv68eWKrXexPoq2PbocXdMezUPfckvrV9pO//57S325d354T5mObXM565+H/7a6/k0LPzf//tsX/QwZ8+9bmBPw8F6uhpqUEue7Yust3fs17u9soHsYkj96E781GgtF/e//C34kZwCIdPMrVsCsejBI+v9b9P+9znV45DNcuB2KLk9rX6HjB5bkjx7u94za16Dk/cW6OnZa61u0j1UPHhZF0j7KCKseDHp4D9Uj+y5Nzj3YvTC/1GOTUQVVXl4erK2t8fnnnyMoKEhqDw4ORlZWFnbu3FlsnkaNGiE0NBRTpkyR2iIiIhAXF4fff/8df/75J5o2bYqjR4/Cy8tLiunatSu8vLywevVqbNy4EdOmTcPff/8tTX/w4AGUSiV27NiBgQMHYuTIkdBoNIiLi5Ni9u3bh+eeew63bt1CnTp1iuWWm5uL3Nz/fhXNzs5Go0aNMG758yyoiIgqUO4/97HuzQRkZWXBzs6uwpdvruObLvqOTQs39IfS+r9j01/ZD78EzW3kozX/B9kntd6PsWtZbPpf2f/Axc7IgVAa++Ng2i34WpwtNQ6XkrWaCnM1dpmlzadveknzlbbu+qYbkoup8xVON+Tvpc33aC6P5lUYa4yifVUkU5b7V20vrc+oodtG17+f1NbYH38d+0HvfEX7L5aPCZ/R8pjv0byN7dPo/YUB/VaW+Qrn1TXfvbv3MXvsrlKPTUZd8nfjxg3k5+fDyclJq93JyUnvWSC1Wq0zXq1WS9ML20qKefRyixo1aqBu3bpaMe7u7sX6KJymq6CKjIzEvHnzirWvezNB57oQEVH5unnzplkKKnMd33TRd2yaPXaXzvhV2KO3LwB4E8b/Wqvbw34+MzCOyDz2GPAZNRY/09Xd7du3y66getKEhYUhNDRUep+VlYXGjRsjPT3dLAd0Y2k0Gri6uuLy5ctmu0TGGMy3fDHf8sV8y1fhWZi6deuaOxWze/TYVFBQgFu3bqFevXqQyWRmzKzqfa4qCreLftw2unG76FeZto0QArdv34azs3OJcUYVVA4ODrC0tERmZqZWe2ZmJlQqlc55VCpVifGFf2ZmZqJBgwZaMYWXSKhUKly7dk2rjwcPHuDWrVta/ehaTtFlPEqhUEChUBRrt7OzM/s/oDFsbW2ZbzlivuWL+ZavqpavhYWFWZZrruObLrqOTfb29oauSoWoap+risLtoh+3jW7cLvpVlm1jyEkWo45ccrkc3t7eSExMlNoKCgqQmJgIf39/nfP4+/trxQNAQkKCFO/u7g6VSqUVo9FocODAASnG398fWVlZSEn570bFH374AQUFBfDz85NifvrpJ9y/f19rOc2bN9d5uR8REVEhcx3fiIjoCSCMFBMTIxQKhdi8ebM4deqUGDt2rLC3txdqtVoIIcQrr7wiZs6cKcX/+uuvokaNGmL58uXi9OnTIiIiQtSsWVMcP35cilm8eLGwt7cXO3fuFMeOHRMDBgwQ7u7u4p9//pFievXqJdq1aycOHDggfvnlF+Hh4SGGDx8uTc/KyhJOTk7ilVdeESdOnBAxMTHC2tpavP/++wavW3Z2tgAgsrOzjd0sZsF8yxfzLV/Mt3wxX+OZ6/hWlVSGf6fKiNtFP24b3bhd9KuK28bogkoIIdasWSMaNWok5HK58PX1Fb/99ps0rWvXriI4OFgr/rPPPhNPPfWUkMvlomXLluKbb77Rml5QUCDmzJkjnJychEKhED169BBnz57Virl586YYPny4sLGxEba2tiIkJETcvn1bK+b3338XnTp1EgqFQri4uIjFixcbtV737t0TERER4t69e0bNZy7Mt3wx3/LFfMsX8zWNOY5vVUll+XeqbLhd9OO20Y3bRb+quG2Mfg4VERERERERPWSeu3+JiIiIiIieACyoiIiIiIiITMSCioiIiIiIyEQsqIiIiIiIiExULQuqixcvYvTo0XB3d4eVlRWaNm2KiIgI5OXlacUdO3YMnTt3hlKphKurK5YuXVqsrx07dsDT0xNKpRKtW7fGnj17yjzfd955Bx07doS1tbXehzvKZLJir5iYGK2YpKQkPPPMM1AoFGjWrBk2b95c5rkak3N6ejr69u0La2trODo6Yvr06Xjw4IHZci7Kzc2t2PZcvHixVowhn4+KtHbtWri5uUGpVMLPzw8HDx40az4AMHfu3GLb0dPTU5p+7949jB8/HvXq1YONjQ0GDRpU7EGp5e2nn37CCy+8AGdnZ8hkMsTFxWlNF0IgPDwcDRo0gJWVFQICAnDu3DmtmFu3bmHEiBGwtbWFvb09Ro8ejTt37pgl31GjRhXb5r169TJLvpGRkWjfvj1q164NR0dHBAUF4ezZs1oxhnwGDNlXUMXJzc2Fl5cXZDIZUlNTtaZVtv1ieSvL7xNPosp4XKpoZbUffNItXrwYMpkMU6ZMkdqq1HYx8yiDZvHtt9+KUaNGib1794oLFy6InTt3CkdHRzFt2jQpJjs7Wzg5OYkRI0aIEydOiE8//VRYWVlpPdfq119/FZaWlmLp0qXi1KlTYvbs2cWeQVIWwsPDxcqVK0VoaKiws7PTGQNAbNq0SVy9elV6FX3OyZ9//imsra1FaGioOHXqlFizZo2wtLQU8fHxZZqroTk/ePBAtGrVSgQEBIijR4+KPXv2CAcHBxEWFma2nItq3LixmD9/vtb2vHPnjjTdkM9HRYqJiRFyuVxs3LhRnDx5UowZM0bY29uLzMxMs+RTKCIiQrRs2VJrO16/fl2a/vrrrwtXV1eRmJgoDh8+LDp06CA6duxYoTnu2bNHvP322+LLL78UAMRXX32lNX3x4sXCzs5OxMXFid9//130799f53Py2rZtK3777Tfx888/i2bNmmk9J68i8w0ODha9evXS2ua3bt3SiqmofAMDA8WmTZvEiRMnRGpqqujTp49o1KiR1v+l0j4DhuwrqGJNmjRJ9O7dWwAQR48eldor236xIpTV94knUWU9LlW0stgPPukOHjwo3NzcRJs2bcTkyZOl9qq0XaplQaXL0qVLhbu7u/R+3bp1ok6dOiI3N1dqe+utt0Tz5s2l9y+99JLo27evVj9+fn7itddeK5ccN23aVGJB9egXq6JmzJghWrZsqdU2dOhQERgYWIYZFqcv5z179ggLCwvpgZlCCLF+/Xpha2srbXNz5SzEw4Jq1apVeqcb8vmoSL6+vmL8+PHS+/z8fOHs7CwiIyPNkk+hiIgI0bZtW53TsrKyRM2aNcWOHTukttOnTwsAIjk5uYIy1Pbo/6OCggKhUqnEsmXLpLasrCyhUCjEp59+KoQQ4tSpUwKAOHTokBTz7bffCplMJv76668KzVeIhwXVgAED9M5jznyvXbsmAIgff/xRCGHYZ8CQfQVVnD179ghPT09x8uTJYgVVZdsvmosp3yeeRJX1uGRupuwHn2S3b98WHh4eIiEhQXTt2lUqqKradqmWl/zpkp2djbp160rvk5OT0aVLF8jlcqktMDAQZ8+exd9//y3FBAQEaPUTGBiI5OTkikn6EePHj4eDgwN8fX2xceNGiCKPGKtsuSYnJ6N169ZwcnLSykej0eDkyZNSjDlzXrx4MerVq4d27dph2bJlWpcYGfL5qCh5eXlISUnR2lYWFhYICAgw279vUefOnYOzszOaNGmCESNGID09HQCQkpKC+/fva+Xt6emJRo0aVYq8ASAtLQ1qtVorRzs7O/j5+Uk5Jicnw97eHj4+PlJMQEAALCwscODAgQrPGXh4qayjoyOaN2+ON954Azdv3pSmmTPf7OxsAJD2tYZ8BgzZV1DFyMzMxJgxY7B161ZYW1sXm16Z9ovmZMr3iSdNZT8umZMp+8En2fjx49G3b99i3/eq2napYe4EKoPz589jzZo1WL58udSmVqvh7u6uFVd4QFer1ahTpw7UarXWQb4wRq1Wl3/Sj5g/fz6ee+45WFtb47vvvsO4ceNw584dTJo0ScpZV64ajQb//PMPrKysKjRfffkUTisppiJynjRpEp555hnUrVsX+/fvR1hYGK5evYqVK1dKuZX2+agoN27cQH5+vs5tdebMmQrLQxc/Pz9s3rwZzZs3x9WrVzFv3jx07twZJ06cgFqthlwuL3aPnbn+D+lSmEdJ/8/VajUcHR21pteoUQN169Y1y3r06tULL774Itzd3XHhwgXMmjULvXv3RnJyMiwtLc2Wb0FBAaZMmYJnn30WrVq1AgCDPgOG7Cuo/AkhMGrUKLz++uvw8fHBxYsXi8VUpv2iuZj6feJJU5mPS+Zk6n7wSRUTE4MjR47g0KFDxaZVte3yRJ2hmjlzps7BGYq+Hv2P/Ndff6FXr14YMmQIxowZU6lzLcmcOXPw7LPPol27dnjrrbcwY8YMLFu2rFLnXNGMyT80NBTdunVDmzZt8Prrr2PFihVYs2YNcnNzzbwWVUvv3r0xZMgQtGnTBoGBgdizZw+ysrLw2WefmTu1J9awYcPQv39/tG7dGkFBQdi9ezcOHTqEpKQks+Y1fvx4nDhxothgOWRehu4X16xZg9u3byMsLMzcKVeIqvR9gqoO7gf/c/nyZUyePBnbtm2DUqk0dzqP7Yk6QzVt2jSMGjWqxJgmTZpIf8/IyED37t3RsWNHbNiwQStOpVIVG0mk8L1KpSoxpnB6WeZqLD8/PyxYsAC5ublQKBR6c7W1tTX4TE9Z5qxSqYqN9mPo9jUm56IeJ38/Pz88ePAAFy9eRPPmzQ36fFQUBwcHWFpamvxZrEj29vZ46qmncP78eTz//PPIy8tDVlaW1i9QlSnvwjwyMzPRoEEDqT0zMxNeXl5SzLVr17Tme/DgAW7dulUp1qNJkyZwcHDA+fPn0aNHD7PkO2HCBOzevRs//fQTGjZsKLWrVKpSPwOG7CvIdIbuF3/44QckJydDoVBoTfPx8cGIESOwZcuWSrVffFwV/X3iSVOVjksV5XH2g0+ilJQUXLt2Dc8884zUlp+fj59++gnvvfce9u7dW7W2i7lv4jKXK1euCA8PDzFs2DDx4MGDYtMLbyLNy8uT2sLCwooNStGvXz+t+fz9/c0yKMWjFi5cKOrUqSO9nzFjhmjVqpVWzPDhw80+KEXR0X7ef/99YWtrK+7du2fWnHX55JNPhIWFhTRamiGfj4rk6+srJkyYIL3Pz88XLi4ule7m39u3b4s6deqI1atXSzecfv7559L0M2fOVMpBKZYvXy61ZWdn6xyU4vDhw1LM3r17zTYoxaMuX74sZDKZ2LlzpxCiYvMtKCgQ48ePF87OzuKPP/4oNt2Qz4Ah+woqf5cuXRLHjx+XXnv37hUAxOeffy4uX74shKh8+8WKUhbfJ55EVeW4VN7KYj/4JNJoNFr7lOPHjwsfHx/xf//3f+L48eNVbrtUy4LqypUrolmzZqJHjx7iypUrWsMLF8rKyhJOTk7ilVdeESdOnBAxMTHC2tq62LDpNWrUEMuXLxenT58WERER5TJs+qVLl8TRo0fFvHnzhI2NjTh69Kg4evSouH37thBCiF27dokPPvhAHD9+XJw7d06sW7dOWFtbi/DwcKmPwiHIp0+fLk6fPi3Wrl1brkOQl5Zz4VDIPXv2FKmpqSI+Pl7Ur19f57DpFZVzof3794tVq1aJ1NRUceHCBfHJJ5+I+vXri5EjR0oxhnw+KlJMTIxQKBRi8+bN4tSpU2Ls2LHC3t5ea2Q0c5g2bZpISkoSaWlp4tdffxUBAQHCwcFBXLt2TQjxcEjURo0aiR9++EEcPnxY+Pv7C39//wrN8fbt29LnE4BYuXKlOHr0qLh06ZIQ4uGw6fb29mLnzp3i2LFjYsCAATqHTW/Xrp04cOCA+OWXX4SHh0e5DZteUr63b98Wb775pkhOThZpaWni+++/F88884zw8PDQKj4qKt833nhD2NnZiaSkJK397N27d6WY0j4DhuwrqOKlpaUVG+Wvsu0XK0JZfZ94ElXW41JFK4v9YHVRdJQ/IarWdqmWBdWmTZsEAJ2von7//XfRqVMnoVAohIuLi1i8eHGxvj777DPx1FNPCblcLlq2bCm++eabMs83ODhYZ6779u0TQjwc8tjLy0vY2NiIWrVqibZt24ro6GiRn5+v1c++ffuEl5eXkMvlokmTJmLTpk1lnquhOQshxMWLF0Xv3r2FlZWVcHBwENOmTRP37983W86FUlJShJ+fn7CzsxNKpVI8/fTTYtGiRcV+DTfk81GR1qxZIxo1aiTkcrnw9fUVv/32m1nzEeLhMPcNGjQQcrlcuLi4iKFDh4rz589L0//55x8xbtw4UadOHWFtbS0GDhyo9UWkIuzbt0/nZzU4OFgI8fDXxTlz5ggnJyehUChEjx49xNmzZ7X6uHnzphg+fLiwsbERtra2IiQkRPrxoCLzvXv3rujZs6eoX7++qFmzpmjcuLEYM2ZMsS8wFZWvvv1s0f/HhnwGDNlXUMXSVVAJUfn2i+WtLL9PPIkq43GpopXVfrA6eLSgqkrbRSZEkbG1iYiIiIiIyGBP1Ch/REREREREFYkFFRERERERkYlYUBEREREREZmIBRUREREREZGJWFARERERERGZiAUVERERERGRiVhQERERERERmYgFFRERERERkYlYUBEREREREZmIBRUREREREZGJWFARERERERGZiAUVERERERGRif4fqFvp3JghnXkAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "p = 3\n", + "gauss = numpy.random.normal(size=len(no_nan8) * 20)\n", + "scale1 = numpy.std(no_nan8) / numpy.std(gauss)\n", + "scalep = numpy.std(no_nan8) / numpy.std(gauss**p)\n", + "\n", + "\n", + "fig, axs = plt.subplots(1, 2, figsize=(10, 4))\n", + "axs[0].hist(float8, bins=50, alpha=0.5, label=\"f8\", density=True)\n", + "axs[0].hist(gauss * scale1, bins=50, alpha=0.5, label=\"N\", density=True)\n", + "axs[0].hist(gauss**p * scalep, bins=50, alpha=0.5, label=f\"N^{p}\", density=True)\n", + "axs[0].set_xlim([-200, 200])\n", + "axs[0].set_title(\"Distribution of float 8 E4M3FN\")\n", + "axs[0].legend()\n", + "\n", + "axs[1].hist(float8, bins=2000, alpha=0.5, label=\"f8\", density=True)\n", + "axs[1].hist(gauss * scale1, bins=2000, alpha=0.5, label=\"N\", density=True)\n", + "axs[1].hist(gauss**p * scalep, bins=2000, alpha=0.5, label=f\"N^{p}\", density=True)\n", + "axs[1].set_xlim([-50, 50])\n", + "axs[1].set_title(\"Same with more bins\")\n", + "axs[1].legend();" + ] + }, + { + "cell_type": "markdown", + "id": "cbbf27bc", + "metadata": {}, + "source": [ + "Curve `N^3` is gaussian at power 3. It was added to show that E4M3FN distribution is closer to $X^3$ than $X$ ($X$ is gaussian)." + ] + }, + { + "cell_type": "code", + "execution_count": 90, + "id": "a64efc70", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(0.004002655570437662, -0.0)" + ] + }, + "execution_count": 90, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "scale_f8p, zero_f8p = estimation_quantization_scale(coef, method=\"power\")\n", + "scale_f8p, zero_f8p" + ] + }, + { + "cell_type": "markdown", + "id": "0c029522", + "metadata": {}, + "source": [ + "## Scale estimation\n", + "\n", + "Very basic:\n", + "\n", + "* ratio of standard deviation for float 8\n", + "* quantile at 5% for uint 8" + ] + }, + { + "cell_type": "code", + "execution_count": 91, + "id": "61dc7741", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(0.0009081294882681465, -0.0)" + ] + }, + "execution_count": 91, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from onnx import TensorProto\n", + "\n", + "\n", + "def estimation_quantization_scale(\n", + " coef: numpy.array, to: int = TensorProto.FLOAT8E4M3FN, method: str = \"naive\"\n", + ") -> tuple[float, float]:\n", + " \"\"\"\n", + " Estimates the scale parameter for the quantization to float 8 assuming\n", + " the distribution of the coefficients is gaussian.\n", + " \"\"\"\n", + " if to == TensorProto.FLOAT8E4M3FN:\n", + " float8 = [float8e4m3_to_float32(i) for i in range(0, 256)]\n", + " quant_float = [f for f in float8 if not numpy.isnan(f)]\n", + " if method == \"naive\":\n", + " std_coef = numpy.std(coef.ravel())\n", + " std_quant = numpy.std(numpy.array(quant_float, dtype=numpy.float32))\n", + " elif method == \"power\":\n", + " cr = coef.ravel()\n", + " ca = numpy.abs(cr)\n", + " std_coef = numpy.std(ca ** (1.0 / 3.0) * cr / ca)\n", + " std_quant = numpy.std(numpy.array(quant_float, dtype=numpy.float32))\n", + " else:\n", + " raise ValueError(f\"Unexpected quantization method {method!r}.\")\n", + " zero = 0.0\n", + " scale = std_quant / std_coef\n", + " elif to == TensorProto.UINT8:\n", + " uint8 = [i for i in range(0, 256)]\n", + " qu = numpy.quantile(coef.ravel(), [1 - 0.99999, 0.99999])\n", + " scale = 255 / (qu[1] - qu[0])\n", + " zero = qu[0] * scale\n", + " else:\n", + " raise ValueError(f\"Unexpected quantization type for to={to}.\")\n", + "\n", + " return 1.0 / scale, -zero\n", + "\n", + "\n", + "scale_f8, zero_f8 = estimation_quantization_scale(coef)\n", + "scale_f8, zero_f8" + ] + }, + { + "cell_type": "code", + "execution_count": 92, + "id": "2bfef061", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(0.004002655570437662, -0.0)" + ] + }, + "execution_count": 92, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "scale_f8p, zero_f8p = estimation_quantization_scale(coef, method=\"power\")\n", + "scale_f8p, zero_f8p" + ] + }, + { + "cell_type": "code", + "execution_count": 93, + "id": "e86fa67a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(0.003963413028773201, 131.88381712385316)" + ] + }, + "execution_count": 93, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "scale_u8, zero_u8 = estimation_quantization_scale(coef, to=TensorProto.UINT8)\n", + "scale_u8, zero_u8" + ] + }, + { + "cell_type": "markdown", + "id": "13ce5145", + "metadata": {}, + "source": [ + "## QDQ\n", + "\n", + "Let's compare the square loss with two operators [QuantizeLinear](https://onnx.ai/onnx/operators/onnx__QuantizeLinear.html) + [DequantizeLinear](https://onnx.ai/onnx/operators/onnx__DequantizeLinear.html) ~ Identity." + ] + }, + { + "cell_type": "code", + "execution_count": 94, + "id": "04cd02c0", + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ 0.05448777, 0.06538533, -0.00590284, ..., 0.01997885,\n", + " 0.00590284, 0.21795107], dtype=float32)" + ] + }, + "execution_count": 94, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from onnx.helper import (\n", + " make_node,\n", + " make_graph,\n", + " make_model,\n", + " make_tensor_value_info,\n", + " make_operatorsetid,\n", + " make_tensor,\n", + ")\n", + "from onnx.reference import ReferenceEvaluator\n", + "\n", + "X = make_tensor_value_info(\"X\", TensorProto.FLOAT, [None])\n", + "Scale = make_tensor_value_info(\"Scale\", TensorProto.FLOAT, [1])\n", + "Y = make_tensor_value_info(\"Y\", TensorProto.FLOAT, [None])\n", + "\n", + "model_f8 = make_model(\n", + " make_graph(\n", + " [\n", + " make_node(\n", + " \"Constant\",\n", + " [],\n", + " [\"Zero\"],\n", + " value=make_tensor(\"Zero\", TensorProto.FLOAT8E4M3FN, [1], [0.0]),\n", + " ),\n", + " make_node(\"QuantizeLinear\", [\"X\", \"Scale\", \"Zero\"], [\"Q\"], axis=0),\n", + " make_node(\"DequantizeLinear\", [\"Q\", \"Scale\"], [\"Y\"], axis=0),\n", + " ],\n", + " \"quf8\",\n", + " [X, Scale],\n", + " [Y],\n", + " ),\n", + " opset_imports=[make_operatorsetid(\"\", 19)],\n", + ")\n", + "\n", + "ref_f8 = ReferenceEvaluator(model_f8)\n", + "qu_f8 = ref_f8.run(\n", + " None, {\"X\": coef.ravel(), \"Scale\": numpy.array([scale_f8], dtype=numpy.float32)}\n", + ")[0]\n", + "qu_f8" + ] + }, + { + "cell_type": "code", + "execution_count": 95, + "id": "459cf5fd", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ 0.05603718, 0.0720478 , -0.00600398, ..., 0.02001328,\n", + " 0.00550365, 0.20813808], dtype=float32)" + ] + }, + "execution_count": 95, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "qu_f8p = ref_f8.run(\n", + " None, {\"X\": coef.ravel(), \"Scale\": numpy.array([scale_f8p], dtype=numpy.float32)}\n", + ")[0]\n", + "qu_f8p" + ] + }, + { + "cell_type": "code", + "execution_count": 96, + "id": "95fe22fe", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ 0.05548779, 0.06737802, -0.00396341, ..., 0.01981707,\n", + " 0.00396341, 0.2140243 ], dtype=float32)" + ] + }, + "execution_count": 96, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model_u8 = make_model(\n", + " make_graph(\n", + " [\n", + " make_node(\n", + " \"Constant\",\n", + " [],\n", + " [\"Zero\"],\n", + " value=make_tensor(\"Zero\", TensorProto.UINT8, [1], [int(zero_u8)]),\n", + " ),\n", + " make_node(\"QuantizeLinear\", [\"X\", \"Scale\", \"Zero\"], [\"Q\"], axis=0),\n", + " make_node(\"DequantizeLinear\", [\"Q\", \"Scale\", \"Zero\"], [\"Y\"], axis=0),\n", + " ],\n", + " \"quu8\",\n", + " [X, Scale],\n", + " [Y],\n", + " ),\n", + " opset_imports=[make_operatorsetid(\"\", 19)],\n", + ")\n", + "\n", + "ref_u8 = ReferenceEvaluator(model_u8)\n", + "qu_u8 = ref_u8.run(\n", + " None, {\"X\": coef.ravel(), \"Scale\": numpy.array([scale_u8], dtype=numpy.float32)}\n", + ")[0]\n", + "qu_u8" + ] + }, + { + "cell_type": "code", + "execution_count": 97, + "id": "e9e49f1b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(6.497171816517831e-06, 6.141178007996629e-06, 3.0187591841210397e-06)" + ] + }, + "execution_count": 97, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "err_f8 = ((coef.ravel() - qu_f8) ** 2).sum() ** 0.5 / coef.size\n", + "err_f8p = ((coef.ravel() - qu_f8p) ** 2).sum() ** 0.5 / coef.size\n", + "err_u8 = ((coef.ravel() - qu_u8) ** 2).sum() ** 0.5 / coef.size\n", + "err_f8, err_f8p, err_u8" + ] + }, + { + "cell_type": "markdown", + "id": "797aac3e", + "metadata": {}, + "source": [ + "Plots" + ] + }, + { + "cell_type": "code", + "execution_count": 98, + "id": "ee4b9887", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA/IAAAPeCAYAAACvDCF1AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzdd1RU19oG8GdAYIYuICAKgmJUbEQs2BsKRo0NNUQFjFGTGMv1RqNJFFvsPZaoMWos0RijJubaSySxo6bYoiiiQbBRBJS6vz/4ZsJhZmCow8DzW+ssZZ+295R3zj5nF5kQQoCIiIiIiIiIDIKRvjNARERERERERLpjRZ6IiIiIiIjIgLAiT0RERERERGRAWJEnIiIiIiIiMiCsyBMREREREREZEFbkiYiIiIiIiAwIK/JEREREREREBoQVeSIiIiIiIiIDwoo8ERERERERkQFhRZ4qlAsXLsDU1BT379/Xd1aK5csvv4SbmxvS0tL0nRUiqgTKKna+9dZbGDRoUKmeg4gqhk6dOqFTp076zgZRuVWpK/LXrl3D0KFDUaNGDZiZmcHFxQVDhw7F9evX1bbdvHkzZDKZapHL5XBxcYG/vz9WrlyJFy9eaD3Pb7/9hn79+sHJyQlmZmZwd3fHe++9hwcPHuiUz1OnTknOnXfZuXOnxv0SEhLg6OgImUyG77//Xmt5fv31V7V9hRBwdXWFTCZDr169JOv+85//oFmzZrCzs4O5uTkaNGiAGTNmIDk5Od/XLPcyZcoU1Xbu7u6QyWQYO3as1rLnzb82n376KYKCglCrVi2dti+vQkNDkZ6ejnXr1uk7K2UqPT0dc+fORf369SGXy+Hk5ISePXvi4cOHBe6r7bM2f/78Es9nQkICRo0ahWrVqsHCwgKdO3fG5cuXNW774sULTJ48GR4eHjAzM0ONGjUQGBiI1NTUEs9XWWHsZOzMLSYmBkOHDkW9evVgZWUFW1tbtGzZElu2bIEQQrLtxx9/jD179uD3338v9HkMWVxcHEaPHo0aNWpALpfD3d0dI0aMKHC/5ORkhIWFISAgAHZ2dpDJZNi8eXOB+2VkZMDLywsymQyLFy8ugRKo27hxIxo0aAC5XI66deviiy++0Lrtrl270Lp1a1hYWMDW1hZt2rTBiRMnSiVflZWhxOWysmPHDixfvlzn7bOzs/Hll1/C29sblpaWcHJyQo8ePXDmzJnSy2Q5cu3aNQwcOBC1a9eGubk5HBwc0KFDB/z00086H0OXa6Nnz55h0aJF6NChA6pVqwZbW1v4+vpi165dJV0kADnv68KFC+Hh4QG5XI4mTZrg22+/1brt2rVr4e3tDYVCAXt7e3Tp0qVc/15V0XcG9OWHH35AUFAQ7OzsMGLECHh4eCAqKgobN27E999/j127dqFPnz5q+82aNQseHh7IyMhAbGwsTp06hQkTJmDp0qX48ccf0aRJE8n2X3zxBcaPH4/atWtj7NixqF69Om7cuIGvvvoKu3btwsGDB+Hr66tTnseNG4cWLVqopbdu3Vrj9tOnTy+wsiCXy7Fjxw60a9dOkv7LL7/g4cOHMDMzU9vn4sWLaN++PYYPHw65XI4rV65g/vz5OHbsGE6fPg0jI+n9IeVrllujRo3UjrthwwZMnToVLi4u+eZZm6tXr+LYsWMVIujK5XKEhIRg6dKlGDt2LGQymb6zVOoyMjLQs2dPnDlzBiNHjkSTJk0QHx+P8+fPIzExETVr1izwGN26dUNwcLAk7fXXXy/RfGZnZ6Nnz574/fffMWnSJDg4OGDNmjXo1KkTIiIiULduXdW2iYmJ6NixIx4+fIhRo0bB09MTT548QXh4ONLS0mBubl6ieSsLjJ05GDv/9fTpUzx8+BCBgYFwc3NDRkYGjh49itDQUNy6dQtz585Vbfv666+jefPmWLJkCb755psinc/QPHjwAG3btgUAvPfee6hRowZiYmJw4cKFAvd9+vQpZs2aBTc3NzRt2hSnTp3S6ZxffPEFoqOji5PtfK1btw7vvfceBgwYgIkTJyI8PBzjxo1DamoqPv74Y8m2M2bMwKxZsxAYGIjQ0FBkZGTgr7/+wj///FNq+atsDDEu6+LIkSNF3nfHjh3466+/MGHCBJ22nzRpEpYuXYqhQ4figw8+QEJCAtatW4eOHTvit99+Q8uWLYucF0Nw//59vHjxAiEhIXBxcUFqair27NmDN998E+vWrcOoUaPy3V/Xa6OzZ8/i008/xRtvvIHPPvsMVapUwZ49e/DWW2/h+vXrmDlzZomW69NPP8X8+fMxcuRItGjRAvv378fbb78NmUyGt956S7LtO++8g+3btyM4OBgffvghUlJScOXKFTx+/LhE81SiRCV0584dYW5uLurXry8eP34sWffkyRNRv359YWlpKe7evatK37RpkwAgLl68qHa848ePC4VCIWrVqiVSU1NV6b/++qswMjIS7du3FykpKWp5cHJyEi4uLiI+Pj7f/J48eVIAELt379a5jH/++aeoUqWKmDVrlsZ9leXp37+/cHBwEBkZGZL1I0eOFD4+PqJWrVqiZ8+eBZ5v8eLFAoA4e/as2jk0vWa51apVSzRs2FBUqVJFjB07VrKuMGUfN26ccHNzE9nZ2QVuawguXbokAIjjx4/rOysqycnJWtfl/YwX1oIFC4SJiYk4f/58kfYHIMaMGVOsPOhi165dap/Jx48fC1tbWxEUFCTZ9v333xe2traSWGLIGDsZOwujV69ewsLCQmRmZkrSFy9eLCwsLMSLFy9K9HzFoS22ZWVliZcvXxbr2D169BAeHh7i6dOnhd731atX4tGjR0IIIS5evCgAiE2bNuW7T1xcnLCxsVF9hhctWlSUbGuVmpoq7O3t1T7fQ4YMERYWFuL58+eqtLNnzwqZTCaWLl1aonmgfxlaXC4rPXv2FLVq1dJp24yMDKFQKERgYKAk/e7duwKAGDduXCnksPCys7Ml70luL1++FFlZWSV6vszMTNG0aVNRr169ArfV9dro7t27IioqSrJvdna26NKlizAzM8v3OrOwHj58KExMTCTXhtnZ2aJ9+/aiZs2akt8mZf5/+OGHEjt/WaiUTesXLVqE1NRUrF+/HtWqVZOsc3BwwLp165CcnIxFixbpdLwuXbpg2rRpuH//PrZt26ZKnz17NmQyGbZs2aL25K1OnTpYuHAhYmJisH79+uIXKo/x48ejX79+aN++fb7bBQUF4dmzZzh69KgqLT09Hd9//z3efvttnc/n7u4OIKdZTVG4u7sjODgYGzZsQExMTJGOsW/fPnTp0kXt6fWlS5fg7+8PBwcHKBQKeHh44J133pFss3jxYrRp0wb29vZQKBTw8fHR2CRVJpPhww8/xO7du+Hl5QWFQoHWrVvjzz//BJDzlMLT0xNyuRydOnVCVFSU2jHOnz+PgIAA2NjYwNzcXHW3Ny8fHx/Y2dlh//79RXo98nPz5k0EBgbCzs4OcrkczZs3x48//ijZRtn07pdffsEHH3wAR0dH1VPxTp06oVGjRoiIiECHDh1gbm6OTz75pMj5yc7OxooVK9CvXz+0bNkSmZmZRW56/vLlS7x69SrfbXR9DzT5/vvv4eTkhP79+6vSqlWrhkGDBmH//v2qcQ0SEhKwadMmjBo1Ch4eHkhPTzf4MQ8YO/9VGWKnu7s7evXqhSNHjsDb2xtyuRxeXl744YcfdM5bamoq0tPTJendunVDSkqK5LUrKQcPHkT79u1hYWEBKysr9OzZE9euXZNsExoaCktLS0RGRuKNN96AlZUVhgwZAuDfGL99+3Y0bNgQZmZmOHToUJHzc/PmTRw8eBCTJk2Cvb09Xr16hYyMDJ33NzMzg7Ozc6HOOWXKFNSrVw9Dhw7Vuk1CQgImTJgAV1dXmJmZwdPTEwsWLEB2dnaBxz958iSePXuGDz74QJI+ZswYpKSk4Oeff1alLV++HM7Ozhg/fjyEEGrdSKj4DC0uz5gxQ2MrQ+U1R+7rprx95JVdhr777jt8/vnnqFmzJuRyObp27Yo7d+5I9vv5559x//59VfcBZazVJCMjAy9fvoSTk5Mk3dHREUZGRlAoFPmWqbCys7OxfPlyNGzYUNWNcPTo0YiPj5dsp4zBhw8fRvPmzaFQKLBu3TrV67Bz50589tlnqFGjBszNzZGUlFSi+TQ2Noarq6tOv0+6Xht5eHiodeGSyWTo27cv0tLScPfuXcm6f/75B++8846qK0fDhg3x9ddf65T//fv3IyMjQxKrZDIZ3n//fTx8+BBnz55VpS9duhQtW7ZEv379kJ2djZSUFJ3OoW+VsiL/008/wd3dXeuFWocOHeDu7l6ofiHDhg0D8G8zoNTUVBw/fhzt27dXaxqpNHjwYJiZmel8nhcvXuDp06dqi8jTB3H37t04c+YMFi5cWOAx3d3d0bp1a0l/kYMHDyIxMVGtyUlumZmZePr0KWJiYnDkyBF89tlnsLKy0tj0KDExUS3Pmnz66afIzMwsUp/mf/75B9HR0WjWrJkk/fHjx+jevTuioqIwZcoUfPHFFxgyZAjOnTsn2W7FihV4/fXXMWvWLMydOxdVqlTBwIEDJRckSuHh4fjvf/+LkJAQzJgxAzdu3ECvXr2wevVqrFy5Eh988AEmTZqEs2fPqt0wOHHiBDp06ICkpCSEhYVh7ty5SEhIQJcuXTQ2s2zWrJnOFUxdXbt2Db6+vrhx4wamTJmCJUuWwMLCAn379sXevXvVtv/ggw9w/fp1TJ8+XdI/99mzZ+jRowe8vb2xfPlydO7cGUBOn05Nn9O8S2JioupY169fR0xMDJo0aYJRo0bBwsICFhYWaNKkCU6ePKlz2TZv3gwLCwsoFAp4eXlhx44datsU9j3I68qVK2jWrJlaM+iWLVsiNTUVf//9NwDg119/xatXr+Dp6YnAwECYm5tDoVCgbdu2uHr1qs5lKk8YO/9V0WOn0u3btzF48GD06NED8+bNU8VGTZXwly9f4unTp4iKisKWLVuwadMmtG7dWu0iWHkTtKRj29atW9GzZ09YWlpiwYIFmDZtGq5fv4527dqp3VTNzMyEv78/HB0dsXjxYgwYMEC17sSJE/jPf/6DwYMHY8WKFaoKQHx8vE6xLfdNyGPHjgEAnJyc0LVrVygUCigUCvTo0UPjjd7iunDhArZs2YLly5dr7ZKVmpqKjh07Ytu2bQgODsbKlSvRtm1bTJ06FRMnTizwHFeuXAEANG/eXJLu4+MDIyMj1XoAOH78OFq0aIGVK1eiWrVqsLKyQvXq1bFq1apilJJyM9S4XBzz58/H3r178dFHH2Hq1Kk4d+6c6mYckBMTvb294eDggK1bt2Lr1q359pdXKBRo1aoVNm/ejO3btyM6Ohp//PEHQkNDUbVq1QKblRfW6NGjMWnSJLRt2xYrVqzA8OHDsX37dvj7+6vd6Lt16xaCgoLQrVs3rFixAt7e3qp1s2fPxs8//4yPPvoIc+fOhampKbKzs3WKU0+fPtV4UzElJQVPnz5FZGQkli1bhoMHD6Jr164FlknXayNtYmNjAeTcfFKKi4uDr68vjh07hg8//BArVqyAp6cnRowYodP4B1euXIGFhQUaNGigliflegBISkrChQsX0KJFC3zyySewsbGBpaUlateuje+++67A8+iVnlsElLmEhAQBQPTp0yff7d58800BQCQlJQkhdGvqaGNjI15//XUhhBBXr14VAMT48ePzPU+TJk2EnZ1dvtsom0hqW5TN7oTIafLm5uYmpk6dKtlXW/PQixcvilWrVgkrKytVc52BAweKzp07CyGE1uahZ8+eleShXr164uTJkxrPoWnJLfc5hg8fLuRyuYiJick3/3kdO3ZMABA//fSTJH3v3r06NVHN21QpPT1dNGrUSHTp0kWSDkCYmZmJe/fuqdLWrVsnAAhnZ2fV50UIIaZOnSoAqLbNzs4WdevWFf7+/pImrKmpqcLDw0N069ZNLV+jRo0SCoUi37wXVteuXUXjxo3Fq1evVGnZ2dmiTZs2om7duqo05fvXrl07taaxHTt2FADEl19+qXb8kJCQfD+vyqVjx46qfX744QcBQNjb24u6deuKTZs2iU2bNom6desKU1NT8fvvvxdYrjZt2ojly5eL/fv3i7Vr14pGjRoJAGLNmjWSchb2PcjLwsJCvPPOO2rpP//8swAgDh06JIQQYunSpaoytWzZUmzfvl2sWbNGODk5iapVq6o+44aCsVOolacix07l8QGIPXv2qNISExNF9erVVe9XbvPmzZPktWvXriI6OlrjeV977TXRo0ePfPNWGC9evBC2trZi5MiRkvTY2FhhY2MjSVfGqClTpqgdB4AwMjIS165dU1unfD0KWsLCwlT7jBs3ThUHAgICxK5du8SiRYuEpaWlqFOnTqG6JBXUtD47O1u0bNlS1Yz13r17GpvWz549W1hYWIi///5bkj5lyhRhbGys9T1TGjNmjDA2Nta4rlq1auKtt94SQgjx/PlzVdktLS3FokWLxK5du0RAQIDW3w8qHEOMy2FhYWqxLHeecl9fdezYUXKtoIxrDRo0EGlpaar0FStWCADizz//VKUVpmm9EELcvn1bNGvWTPJdrl27trh586bOx9BFeHi4ACC2b98uST906JBaujLmKK8rlJSvQ+3atdWuX5Xfe12WvL89QggxevRo1XojIyMRGBgo6S6jja7XRpo8e/ZMODo6ivbt20vSR4wYIapXr67WLemtt94SNjY2WrsZKPXs2VPUrl1bLT0lJUXyG3D58mVVrHJychJr1qwR27dvFy1bthQymUwcPHgw3/PoU6Ub7E45EqeVlVW+2ynXv3jxosBtlSwtLVXHL8x58hsdNLfp06drvONqZ2en+v/8+fORkZFRqGbOgwYNwoQJE3DgwAEEBATgwIEDWLlyZb77eHl54ejRo0hJScGZM2dw7NgxrU3mVq9ejddee02nvHz22WfYunUr5s+fjxUrVuhchmfPngEAqlatKkm3tbUFABw4cABNmzaFiYmJxv1zPzGKj49HVlYW2rdvr3Fky65du0qaaLVq1QoAMGDAAMn7rUy/e/cu3N3dcfXqVdy+fRufffaZKr+5j7l161ZkZ2dL7mZWrVoVL1++RGpqaokMjPb8+XOcOHECs2bNwosXLySfPX9/f4SFheGff/5BjRo1VOkjR46EsbGx2rHMzMwwfPhwtfTJkyfn26RTKfd7pfzsvHjxAleuXIGrqyuAnCZ+np6eWLhwoaSJnyZ5n+6988478PHxwSeffILQ0FAoFIoivQd5vXz5UuNAZnK5XLU+d5lkMhmOHz8OS0tLADmDfbVu3RqrV6/GnDlz8i1TecLYqa4ix04lFxcX9OvXT/W3tbU1goODsWDBAsTGxkqafQcFBaF58+Z48uQJDhw4gLi4ONX3Ia+qVatqbWFQFEePHkVCQgKCgoIkxzU2NkarVq00tux5//33NR6rY8eO8PLyUkvfvn271vLkVrt2bdX/le+ts7Mzfv75Z1VsqVmzJoKCgrBjxw68++67BR5TF5s3b8aff/5Z4EwFu3fvRvv27dXeAz8/P8yfPx+nT5+WPN3M6+XLlzA1NdW4Ti6Xq8XAZ8+eYefOnRg8eDAAIDAwEI0bN8acOXMwevToQpWRpAw5LhfH8OHDJZ9BZXy/e/euxgFBdWFlZYWGDRuidevW6Nq1K2JjYzF//nz07dsX4eHhkifFxbF7927Y2NigW7duku+fj48PLC0tcfLkSUn3LA8PD/j7+2s8VkhIiFqLJ2dnZ527LTVt2lQtbcKECQgMDERMTAy+++47ZGVlqXWP0kTXa6O8srOzMWTIECQkJEhmvhBCYM+ePRg0aBCEEJLXyt/fHzt37sTly5dVA4kWJ0+5Y9W5c+dU1+9vvvkmPDw8MGfOHAQEBORbfn2pdBX53MEsPy9evIBMJivUFzc5ORmOjo6FPo9yn4I0btwYfn5+WtdHRUVh0aJFWL16tarSoItq1arBz88PO3bsQGpqKrKyshAYGJjvPtbW1qq89OnTBzt27ECfPn1w+fJltcDQsmVLtSZ42tSuXRvDhg3D+vXrJc24dSXyNJXt2LEjBgwYgJkzZ2LZsmXo1KkT+vbti7ffflvy5T5w4ADmzJmDq1evSvoxa2qa6ObmJvnbxsYGAFSVz7zpyj5Pt2/fBpATeLVJTEyUXFAry5PfqPXJycmSioCxsbFaPzmlO3fuQAiBadOmYdq0aRq3efz4saQir60ZXY0aNTRezHl5eWm8CM6P8oeobdu2ktfRzc0N7dq1K9Jo2qampvjwww/x3nvvISIiAu3atdP5PbCwsMDz588l6dWqVYOxsTEUCoXGvu7KfvnKsij/7d27t+T76OvrCw8PD4ObXYGxU11Fjp1Knp6eavFHeXMhKipKUpGvVauWqu9jUFAQRo0aBT8/P9y6dUvtYlMIUeBsHM+fP5dcQCoUClVczUv53e7SpYvG9dbW1pK/q1SponUmDG0xL78LRm2U5R40aJDkBuHAgQMxbNgwnDlzpkQq8klJSZg6dSomTZqk9luU1+3bt/HHH39o/Z1QjtD85MkTZGVlqdItLS1haWkJhUKh9cL+1atXajHQxMRE8r0wMjLC4MGDERYWhujoaLXfVNKdIcfl4sj7mVFeN+XtY66rzMxM+Pn5oVOnTpLKpJ+fHxo2bIhFixZhwYIFWvdXNgtXsrGx0dqv/vbt20hMTNT6OuUdIV1bPNK2Ti6X5/t7V5D69eujfv36AIDg4GB0794dvXv3xvnz5/ON2bpeG+U1duxYHDp0CN98843kN/DJkydISEjA+vXrtY67oHyttL3+hb1e8/DwUFXigZyY17t3b2zbtg2ZmZmoUqX8VZvLX45KmY2NDVxcXPDHH3/ku90ff/yBmjVrar3rnNfDhw+RmJgIT09PAEDdunVRpUqVfM+TlpaGW7duldiUFtOnT0eNGjUkg6wpP9xPnjxBVFQU3NzcND5tfPvttzFy5EjExsaiR48eqifZuurfvz+GDRuGnTt3arzDVxiffvoptm7digULFqBv37467WNvbw9APYgr51E+d+4cfvrpJxw+fBjvvPMOlixZgnPnzsHS0hLh4eF488030aFDB6xZswbVq1eHiYkJNm3apLGPtaan0/mlKy+QlYMILVq0SNLHKbe8lYj4+HhV32ptFi9eLJmuo1atWlr7Xirz8NFHH2m9w6v8DCtpO7e29MTERJ2eWpmamqqeiCqnzco70AyQM9hM7j6XhaG8oFVWynV9D3777TdVn3+le/fuwd3dHdWrV8ejR4/U9lOmKctSUJmKesGhL4ydlSt2loTAwEBs2LABp0+fVos38fHxkqkaNenfvz9++eUX1d8hISFa51BXfre3bt2qcXC4vBdgZmZmWlveaItteSu22igrvID2OGBsbAx7e/sSe90XL16M9PR0DB48WPUZfvjwIYCc1zoqKgouLi6qPrTdunXD5MmTNR5LeaOmRYsWuH//vio9LCwMM2bMQPXq1ZGVlYXHjx9LKiPp6el49uyZqszKwVRtbW3Vfh+V+8XHx7MiXwyGGJe1VQZ1+W4pFXS9VVinT5/GX3/9haVLl0rS69atiwYNGhQ4nkf16tUlf2/atAmhoaEat83OzoajoyO2b9+ucX3eG2z5Xf9pWpeVlYUnT57km18lOzu7Aj8TgYGBGD16NP7++2/Uq1dP63a6XhvlNnPmTKxZswbz589XjcugpIzpQ4cO1frwRTk9orbXv3r16jh58qTajePCXq9lZGQgJSVF641kfap0FXkg5wnZunXr8Ouvv6rNAQzkDGYWFRWl06AvSlu3bgUA1cWKubk5unbtimPHjuH+/ftqIzQCwHfffYe0tDQMHDiwiCWRio6Oxp07dyTN+pSUIzbGx8drvNDs168fRo8ejXPnzmHXrl2FPndaWhqys7MlA5gVVZ06dTB06FCsW7dOcmcsP8q7h/fu3dO43tfXF76+vvj888+xY8cODBkyBDt37sS7776LPXv2QC6X4/Dhw5Kn9Js2bSp2WXKrU6cOAOkTuYLcu3dPbZCOvIKDgyWf4/yCvvKzYWJiUqw7tvkZP348tmzZUuB2HTt2VM2J3LhxY5iYmGicVzgmJkbrk6OCKEc/Ve6v63vQtGlTtaZpysqBt7c3wsPD1Zrgnz9/Hubm5qqLYB8fHwDQWiblZ9aQMHbaqq2v6LFT2Yon90WQctCi/EaBBv5ttpi3bJmZmXjw4AHefPPNfPdfsmSJpKKr6UJQSfnddnR0LLXYlrdiq42ywgtojwPp6el4+vRpkWNbXtHR0YiPj0fDhg3V1s2dOxdz587FlStX4O3tjTp16iA5ObnA1ylvVwLl90N5E/TSpUt44403VOsvXbqE7Oxs1XojIyN4e3vj4sWLSE9Pl1QYlDMslFT5KzNDi8vKp+cJCQmSmKrLd6swCmrxk1tcXBwAzTcTMjIykJmZme/+ea8XNH0PlerUqYNjx46hbdu2JT4aPgA8ePAg36f4uZ08eVIyK4Am2uJ4XrpeGymtXr0aM2bMwIQJE/Dxxx+rHU85OGZWVlaBsUrb6+/t7Y2vvvoKN27ckLQUPX/+vGo9kPPb4uzsrPV6TS6X69wlpczpqW++Xt2+fVuYm5sLLy8vtQEUnj17Jry8vIS1tXWh59z08PCQzDcbHh4ujIyMRKdOndQGZLh7965wdnYWrq6uJTYXcnh4uNi7d69kmT17tgAgJk+eLPbu3SvS09O1lmfz5s1ixowZkrzmHbApPj5edYzclHMhb9y4UZVWmLmQ8w4KdefOHWFsbCy8vb11KrsQQri6uophw4ZJ0p4/f642N/K1a9cEALFq1SohhBATJ04U5ubmkkGH7t27J8zNzdUGZAHU5yrXNqBQ3vctKytL1KlTR9StW1fj/Ml5538VQgg7Ozu1+aGLq1OnTsLOzk7jYGu585Df+9exY0fRsGFDjce/du2aOHr0aIHLpUuXJPv16dNHGBsbixs3bqjSrl+/LoyNjcUHH3ygSktJSRE3btwQT5480ZhvpaSkJFGnTh3h4OCgGhSnKO9BXjt37lT7TD558kTY2tqKwYMHS7Zt2rSpsLa2luT18OHDAoBYuHBhgecqbxg7K0/sVB4fWga78/b2VqVp+9707t1byGQycfv2bUn677//rnbc4kpMTBTW1taiY8eOGl/n3HkMCQkRFhYWGo+jKcYr/frrrzrFtsjISNU+r169Eo6OjqJ27dqSz7hykNTvvvtOlfbkyRNx48YNrQPg5TfYXUREhNpnWHmO0NBQsXfvXpGQkCCEEGLGjBlaB5+Kj48XGRkZGs+vlJqaKuzs7ESvXr0k6UOHDhXm5ubi2bNnqrRly5YJAGL9+vWqtJcvX4ratWsLLy+vfM9DujG0uHzgwAEBQOzfv1+VlpycLNzc3HQe7C5vXFNeh+X+bgwePFjY2trmmxelS5cuCQAiJCREkh4RESGMjIzEe++9p9NxdHHq1CkBQDWwam4ZGRmS10/boKn5/ba9fPlSpzh19OhRySB2cXFxasdKT08XzZo1EwqFQnLNFBMTI27cuCGJtYW5Ntq5c6cwMjISQ4YMUbtGzy00NFSYmppKBjFU0uV67cGDB1rnka9Ro4ZkIOfx48cLAOLIkSOS/FtbW4s33nijwHPpS6V8Iu/p6YlvvvkGQUFBaNy4MUaMGAEPDw9ERUVh48aNiI+Px86dOzXe0Tp48CBu3ryJzMxMxMXF4cSJEzh69Chq1aqFH3/8UTWAAgC0a9cOy5Ytw4QJE9CkSRNVM4+bN29iw4YNMDIywr59+3RuihkeHq5xfuwmTZqgSZMmGu/EKo/dokWLApta5tdvWOnUqVMYN24cAgMDUbduXaSnpyM8PBw//PADmjdvrtMgZ7pQPlnS5cmuUp8+fbB3717J06MtW7ZgzZo16NevH+rUqYMXL15gw4YNsLa2Vj1J6NmzJ5YuXYqAgAC8/fbbePz4MVavXg1PT88Cm6sVhpGREb766iv06NEDDRs2xPDhw1GjRg38888/OHnyJKytrSXTtkREROD58+fo06dPieUByLkL2q5dOzRu3BgjR45E7dq1ERcXh7Nnz+Lhw4f4/fffi3X8ovSRB3KeGh0/fhxdunTBuHHjAAArV66EnZ2dZACyCxcuoHPnzpKnXqtXr8a+ffvQu3dvuLm54dGjR/j6668RHR2NrVu3qp4EFfY90CQwMBC+vr4YPnw4rl+/DgcHB6xZswZZWVmSLg4AsGzZMnTr1g3t2rXD6NGjkZiYiKVLl+K1117TOtBWecbYqVlFjJ1Kr732GkaMGIGLFy/CyckJX3/9NeLi4iQtlj7//HP89ttvCAgIgJubG54/f449e/bg4sWLGDt2rFp3naNHj8Lc3BzdunUrXmFzsba2xtq1azFs2DA0a9YMb731FqpVq4bo6Gj8/PPPaNu2bbGnPCtKH3kzMzMsWrQIISEh6NChA4YNG4bo6GisWLEC7du3l8y5vGrVKsycOVPtKdmqVauQkJCgeor9008/qZrNjx07FjY2NmjWrJnaFILKJvYNGzaUfIYnTZqEH3/8Eb169UJoaCh8fHyQkpKiGigvKioq377UCoUCs2fPxpgxYzBw4ED4+/sjPDwc27Ztw+effy4ZRHL06NH46quvMGbMGPz9999wc3PD1q1bcf/+/TKZpqwyMLS43L17d7i5uWHEiBGYNGkSjI2N8fXXX6u+ryXFx8cHu3btwsSJE9GiRQtVf2dt23br1g1btmxBUlISunfvjkePHuGLL76AQqHAhAkTSixfHTt2xOjRozFv3jxcvXoV3bt3h4mJCW7fvo3du3djxYoVBY61kp+i9pEfPXo0kpKS0KFDB9SoUQOxsbHYvn07bt68iSVLlki6fk6dOhVbtmxRdTkEdL82unDhAoKDg2Fvb4+uXbuqdTFo06aNqvXP/PnzcfLkSbRq1QojR46El5cXnj9/jsuXL+PYsWNqYxnlVbNmTUyYMAGLFi1CRkYGWrRogX379iE8PBzbt2+XdNGYOnUqvvvuOwwYMAATJ06EjY0NvvzyS2RkZGDu3LmFfj3LjL7vJOjTn3/+Kd5++23h7OwsjIyMBAAhl8s1TjuTdzogU1NT4ezsLLp16yZWrFghmXYsr/DwcNGnTx/h4OAgZDKZACAcHR0lUx/lp6AplHJPdaNt3/ymUMpP3ruBd+7cEcHBwaJ27dpCoVAIuVwuGjZsKMLCwkRycnKJnEPp9u3bwtjYWOenSsrpI8LDwyVpQUFBws3NTZiZmQlHR0fRq1cvtafBGzduFHXr1hVmZmaifv36YtOmTRqnSEExnsgrXblyRfTv31/Y29sLMzMzUatWLTFo0CBx/PhxyXYff/yxcHNzy/duZVFFRkaK4OBg4ezsLExMTESNGjVEr169xPfff6/apqhP5IsjIiJC+Pn5CQsLC2FlZSX69OmjNkWS8nXN/bk/cuSI6Natm6o8tra2onv37mqvqZKu74E2z58/FyNGjBD29vbC3NxcdOzYUevn/OjRo8LX11fI5XJhZ2cnhg0bpvN3v7xi7Kz4sTP38Q8fPiyaNGmiio95j3nkyBHRq1cv4eLiIkxMTISVlZVo27at2LRpk8b41apVKzF06NAC81UUJ0+eFP7+/sLGxkbI5XJRp04dERoaKon5RX0iXxzffvutaNq0qTAzMxNOTk7iww8/VPvsK39z8k4Jld+0d7mfXual7bdJiJzp+qZOnSo8PT2FqampcHBwEG3atBGLFy/W2KJBk/Xr14t69eoJU1NTUadOHbFs2TKN73dcXJwICQkRdnZ2wszMTLRq1SrfqaioaAwlLguR81vfqlUrYWpqKtzc3MTSpUsLNf2cLk/kk5OTxdtvvy1sbW0FgAKnoktNTRWzZs0SXl5eQqFQCBsbG9GrVy9x5coVnctVGOvXrxc+Pj5CoVAIKysr0bhxYzF58mRJa8miPJEvqm+//Vb4+fkJJycnUaVKFVG1alXh5+cnaTmhpJzCM2/80eXaKL/pVfO+h0LkxI8xY8YIV1dXYWJiIpydnUXXrl0lrXzyk5WVJebOnStq1aolTE1NRcOGDcW2bds0bhsZGSn69esnrK2thUKhEF26dBEXLlzQ6Tz6Uqkr8nlt2bJFyGQyjU0MS9KsWbMEAPHpp5+W6nkqoy5dupTaBWJZevXqlXB2dhbLly/Xd1aICsTYafg0xU5tF5HFceXKFSGTyUrt4piIcjAuE1V8rMjnMX/+fK19V0rSe++9JwCIdevWlep5Kptz584JExMTERUVpe+sFMvatWuFq6urePXqlb6zQqQTxk7Dpil2lkZFfvDgwWLgwIElekwi0oxxmahikwlRxLkaiIiIqMJyd3dHo0aNcODAAX1nhYiIiPLQPIkqEREREREREZVLfCJPREREREREZED4RJ6IiIiIiIjIgLAiT0RERERERGRAqug7A+VRdnY2YmJiYGVlBZlMpu/sEJEBEkLgxYsXcHFxgZFRxblnyvhIRMXF+EhEpFlh4iMr8hrExMTA1dVV39kgogrgwYMHqFmzpr6zUWIYH4mopDA+EhFppkt8ZEVeAysrKwA5L6C1tbWec0NEhigpKQmurq6qeFJRMD4SUXExPhIRaVaY+MiKvAbK5lDW1tYMxERULBWteSXjIxGVFMZHIiLNdImPFadjEhEREREREVElwIo8ERERERERkQFhRZ6IiIiIiIjIgLCPPJGBy8rKQkZGhr6zUemYmJjA2NhY39kgonwwPuoH4yNR+cSYqH8lGR9ZkScyUEIIxMbGIiEhQd9ZqbRsbW3h7Oxc4QZsIjJ0jI/6x/hIVH4wJpYvJRUfWZEnMlDKgOzo6Ahzc3NeLJUhIQRSU1Px+PFjAED16tX1nCMiyo3xUX8YH4nKH8bE8qGk4yMr8kQGKCsrSxWQ7e3t9Z2dSkmhUAAAHj9+DEdHRzYjJSonGB/1j/GRqPxgTCxfSjI+crA7IgOk7N9kbm6u55xUbsrXn/3NiMoPxsfygfGRqHxgTCx/Sio+6rUif/r0afTu3RsuLi6QyWTYt2+fZH1oaChkMplkCQgIKPC4q1evhru7O+RyOVq1aoULFy6UUgmI9ItNo/SLrz9R+cXvp37x9ScqX/idLD9K6r3Qa0U+JSUFTZs2xerVq7VuExAQgEePHqmWb7/9Nt9j7tq1CxMnTkRYWBguX76Mpk2bwt/fX9UXgYiIiIiIiMiQ6bUi36NHD8yZMwf9+vXTuo2ZmRmcnZ1VS9WqVfM95tKlSzFy5EgMHz4cXl5e+PLLL2Fubo6vv/66pLNPROXQzZs34evrC7lcDm9vb31nh4ioXGGMJCLKYejxsNwPdnfq1Ck4OjqiatWq6NKlC+bMmaN1oIb09HRERERg6tSpqjQjIyP4+fnh7NmzZZVlIr1advTvMjvXf7q9Vmbn0lVYWBgsLCxw69YtWFpa6js7RFSOlGV8BBgjiaj8Yjw0/HhYrivyAQEB6N+/Pzw8PBAZGYlPPvkEPXr0wNmzZzWO8Pf06VNkZWXByclJku7k5ISbN29qPU9aWhrS0tJUfyclJZVcIYioTEVGRqJnz56oVauWvrNSITA+ElUsjJElh/GRyLAZejws16PWv/XWW3jzzTfRuHFj9O3bFwcOHMDFixdx6tSpEj3PvHnzYGNjo1pcXV1L9PhE9K/s7GwsXLgQnp6eMDMzg5ubGz7//HMAwJ9//okuXbpAoVDA3t4eo0aNQnJysmT/r776Cg0aNIBcLkf9+vWxZs0a1TqZTIaIiAjMmjULMpkMM2bMKMuiVUiMj0RlizHScDA+EpUuxsP8leuKfF61a9eGg4MD7ty5o3G9g4MDjI2NERcXJ0mPi4uDs7Oz1uNOnToViYmJquXBgwclmm8i+tfUqVMxf/58TJs2DdevX8eOHTvg5OSElJQU+Pv7o2rVqrh48SJ2796NY8eO4cMPP1Ttu337dkyfPh2ff/45bty4gblz52LatGnYsmULAODRo0do2LAh/vvf/+LRo0f46KOP9FXMCoPxkahsMUYaDsZHotLFeJi/ct20Pq+HDx/i2bNnqF69usb1pqam8PHxwfHjx9G3b18AOXdyjh8/Lnlj8zIzM4OZmVlpZJmIcnnx4gVWrFiBVatWISQkBABQp04dtGvXDhs2bMCrV6/wzTffwMLCAgCwatUq9O7dGwsWLICTkxPCwsKwZMkS9O/fHwDg4eGB69evY926dQgJCYGzszOqVKkCS0vLfG/eke4YH4nKDmOkYWF8JCo9jIcF02tFPjk5WfJ0/d69e7h69Srs7OxgZ2eHmTNnYsCAAXB2dkZkZCQmT54MT09P+Pv7q/bp2rUr+vXrp6qoT5w4ESEhIWjevDlatmyJ5cuXIyUlBcOHDy/z8hGR1I0bN5CWloauXbtqXNe0aVNVQAaAtm3bIjs7WzUISWRkJEaMGIGRI0eqtsnMzISNjU2Z5J+IqDQxRhIR5WA8LJheK/KXLl1C586dVX9PnDgRABASEoK1a9fijz/+wJYtW5CQkAAXFxd0794ds2fPltz9jIyMxNOnT1V/Dx48GE+ePMH06dMRGxsLb29vHDp0SG0APCIqewqFosj7Kvs9bdiwAa1atZKs0zT4JRGRoWGMJCLKwXhYML1W5Dt16gQhhNb1hw8fLvAYUVFRamkffvhhvk3piUg/6tatC4VCgePHj+Pdd9+VrGvQoAE2b96MlJQU1R3W3377DUZGRqhXrx6cnJzg4uKCu3fvYsiQIfrIPhFRqWKMJCLKwXhYMIPqI09Ehk0ul+Pjjz/G5MmTYWpqirZt2+LJkye4du0ahgwZgrCwMISEhGDGjBl48uQJxo4di2HDhqla1MycORPjxo2DjY0NAgICkJaWhkuXLiE+Pl7VooeIyFAxRhIR5WA8LBgr8kRUpqZNm4YqVapg+vTpiImJQfXq1fHee+/B3Nwchw8fxvjx49GiRQuYm5tjwIABWLp0qWrfd999F+bm5li0aBEmTZoECwsLNG7cGBMmTNBfgYiIShBjJBFRDsbD/MlEfm3bK6mkpCTY2NggMTER1tbW+s4OkZpXr17h3r178PDwgFwu13d2Kq383oeKGkcqarmo4mB8LB8YHytOuciwMSaWPyUVHw1qHnkiIiIiIiKiyo4VeSIiIiIiIiIDwoo8ERERERERkQFhRZ6IiIiIiIjIgLAiT0RERERERGRAWJEnIiIiIiIiMiCsyBMREREREREZEFbkiYiIiIiIiAwIK/JEREREREREBoQVeSIq99zd3bF8+fISO97Nmzfh6+sLuVwOb2/vEjsuEZE+MEYSEeUo6XhYnlXRdwaIqISdnFd25+o8tezOVYLCwsJgYWGBW7duwdLSEgDw999/Y9KkSfjtt9+Qnp6OJk2aYPbs2ejcubOec0tEJaYs4yPAGElE5RfjYYk5fPgwwsLCcO3aNcjlcnTo0AFLliyBu7t7qZ6XT+SJqNKJjIxEu3btUKtWLdjb2wMAevXqhczMTJw4cQIRERFo2rQpevXqhdjYWD3nloiobDFGEhHp5t69e+jTpw+6dOmCq1ev4vDhw3j69Cn69+9f6udmRZ6IylRKSgqCg4NhaWmJ6tWrY8mSJejUqRMmTJgAAHj8+DF69+4NhUIBDw8PbN++Xe0Yt2/fRocOHSCXy+Hl5YWjR49CJpNh3759BZ5fJpMhIiICs2bNgkwmw4wZM/D06VPcvn0bU6ZMQZMmTVC3bl3Mnz8fqamp+Ouvv0r4FSAi0o4xkogoh77j4alTpyCTyZCQkKBKu3r1KmQyGaKiogAAERERyMrKwpw5c1CnTh00a9YMH330Ea5evYqMjIwSeBW0Y9N6IipTkyZNwi+//IL9+/fD0dERn3zyCS5fvqzqhxkaGoqYmBicPHkSJiYmGDduHB4/fqzaPzs7G/3794eTkxPOnz+PxMREVUDXxaNHj+Dn54eAgAB89NFHsLS0hIWFBerVq4dvvvkGzZo1g5mZGdatWwdHR0f4+PiU8CtARKQdYyQRUQ59x0Nd+Pj4wMjICJs2bUJoaCiSk5OxdetW+Pn5wcTEpETPlRcr8kRUZpKTk7Fx40Zs27YNXbt2BQBs2bIFNWvWBJDTB/PgwYO4cOECWrRoAQDYuHEjGjRooDrGsWPHcPPmTRw+fBguLi4AgLlz56JHjx465cHZ2RlVqlSBpaUlnJ2dJcft27cvrKysYGRkBEdHRxw6dAhVq1YtkbITERWEMZKIKEd5iIe68PDwwJEjRzBo0CCMHj0aWVlZaN26Nf73v/+V2Dm0YdN6IiozkZGRSE9PR6tWrVRpdnZ2qFevHgDgxo0bqFKliuQJT/369WFra6v6+8aNG3B1dVUFZABo3bp1sfIlhMCYMWPg6OiI8PBwXLhwAX379kXv3r3x6NGjYh2biEhXjJFERDnKazzMKzY2FiNHjkRISAguXryIX375BaampggMDIQQokTPlRefyBNRpXfixAkcOHAA8fHxsLa2BgCsWbMGR48exZYtWzBlyhQ955CISH8YI4moMjIyynnmnbtCnrff++rVq2FjY4OFCxeq0rZt2wZXV1ecP38evr6+pZe/UjuyDk6fPo3evXvDxcVFbdCBjIwMfPzxx2jcuDEsLCzg4uKC4OBgxMTE5HvMGTNmQCaTSZb69euXckmISBd16tSBiYkJzp8/r0qLj4/H33//DSDnTmpmZiYiIiJU62/duiUZZKRBgwZ48OCB5CnQuXPnipWv1NRUAP8GbCUjIyNkZ2cX69hERLpijCQiylEe4mG1atUAQLL/1atXJdukpqaqxUZjY2MAKPX4qNeKfEpKCpo2bYrVq1errUtNTcXly5cxbdo0XL58GT/88ANu3bqFN998s8DjNmzYEI8ePVItv/76a2lkn4gKydLSEiNGjMCkSZNw4sQJ/PXXXwgNDVUFwHr16iEgIACjR4/G+fPnERERgXfffRcKhUJ1DD8/P7z22msICQnB77//jvDwcHz66afFylfr1q1RtWpV1TGV8yXfu3cPPXv2LNaxiYh0xRhJRJSjPMRDT09PuLq6YsaMGbh9+zZ+/vlnLFmyRLJNz549cfHiRcyaNQu3b9/G5cuXMXz4cNSqVQuvv/56ybwYWui1It+jRw/MmTMH/fr1U1tnY2ODo0ePYtCgQahXrx58fX2xatUqREREIDo6Ot/jVqlSBc7OzqrFwcGhtIpARIW0aNEitG/fHr1794afnx/atWsn6d+0adMmuLi4oGPHjujfvz9GjRoFR0dH1XojIyPs3bsXL1++RMuWLfHuu+/i888/L1aeHBwccOjQISQnJ6NLly5o3rw5fv31V+zfvx9NmzYt1rGJiAqDMZKIKIe+46GJiQm+/fZb3Lx5E02aNMGCBQswZ84cyTZdunTBjh07sG/fPrz++usICAiAmZkZDh06JLmpUBpkorR74etIJpNh79696Nu3r9Ztjh07hu7duyMhIUHVRyuvGTNmYNGiRbCxsYFcLkfr1q0xb948uLm56ZyXpKQk2NjYIDExUet5iPTp1atXuHfvHjw8PCCXy/WdnWLr1KkTvL29sXz58iIfQ5cYUtLyex8qahypqOWiiqOixUfAMGMk42PFKRcZtooWEw0xHuZVUvHRYAa7e/XqFT7++GMEBQXlW6hWrVph8+bNqFevHh49eoSZM2eiffv2+Ouvv2BlZaVxn7S0NKSlpan+TkpKKvH8ExEZIsZHIiLNGB+JSJ8MYvq5jIwMDBo0CEIIrF27Nt9te/TogYEDB6JJkybw9/fH//73PyQkJOC7777Tus+8efNgY2OjWlxdXUu6CERURubOnQtLS0uNS0nOG1pZMD4SVSyMkSWH8ZHIsBl6PCz3TeuVlfi7d+/ixIkTsLe3L/SxW7RoAT8/P8ybN0/jek13VF1dXdk0isqtitZMqiQ9f/4cz58/17hOoVCgRo0aJXauytB0lPGRDA3jY/7KKkYyPhpuuahiYUzUriyvGXOrFE3rlZX427dv4+TJk0WqxCcnJyMyMhLDhg3Tuo2ZmRnMzMyKk1UiKifs7OxgZ2en72xUGIyPRBULY2TJYXwkMmyGHg/12rQ+OTkZV69eVc3Hd+/ePVy9ehXR0dHIyMhAYGAgLl26hO3btyMrKwuxsbGIjY1Fenq66hhdu3bFqlWrVH9/9NFH+OWXXxAVFYUzZ86gX79+MDY2RlBQUFkXj4iIiIiIiKjE6fWJ/KVLl9C5c2fV3xMnTgQAhISEYMaMGfjxxx8BAN7e3pL9Tp48iU6dOgEAIiMj8fTpU9W6hw8fIigoCM+ePUO1atXQrl07nDt3DtWqVSvdwhDpQXZ2tr6zUKnx9Scqv/j91C++/kTlC7+T5UdJvRd6rch36tQJ+XXR16X7flRUlOTvnTt3FjdbROWeqakpjIyMEBMTg2rVqsHU1BQymUzf2ao0hBBIT0/HkydPYGRkBFNTU31niYj+H+OjfjE+EpUvjInlR0nHx3LdR56INDMyMoKHhwcePXqEmJgYfWen0jI3N4ebmxuMjAxiAhCiSoHxsXxgfCQqHxgTy5+Sio+syBMZKFNTU7i5uSEzMxNZWVn6zk6lY2xsjCpVqvCuNlE5xPioX4yPROULY2L5UZLxkRV5IgMmk8lgYmICExMTfWeFiKhcYXwkIvoXY2LFw/ZORERERERERAaEFXkiIiIiIiIiA8KKPBEREREREZEBYUWeiIiIiIiIyICwIk9ERERERERkQFiRJyIiIiIiIjIgrMgTERERERERGRBW5ImIiIiIiIgMCCvyRERERERERAaEFXkiIiIiIiIiA8KKPBEREREREZEBYUWeiIiIiIiIyICwIk9ERERERERkQFiRJyIiIiIiIjIgrMgTERERERERGRBW5ImIiIiIiIgMCCvyRERERERERAZErxX506dPo3fv3nBxcYFMJsO+ffsk64UQmD59OqpXrw6FQgE/Pz/cvn27wOOuXr0a7u7ukMvlaNWqFS5cuFBKJSAiIiIiIiIqW3qtyKekpKBp06ZYvXq1xvULFy7EypUr8eWXX+L8+fOwsLCAv78/Xr16pfWYu3btwsSJExEWFobLly+jadOm8Pf3x+PHj0urGERERERERERlpkQq8vfu3UNmZmah9+vRowfmzJmDfv36qa0TQmD58uX47LPP0KdPHzRp0gTffPMNYmJi1J7c57Z06VKMHDkSw4cPh5eXF7788kuYm5vj66+/LnT+iIiIiIiIiMqbEqnI16tXT6cm74Vx7949xMbGws/PT5VmY2ODVq1a4ezZsxr3SU9PR0REhGQfIyMj+Pn5ad0HANLS0pCUlCRZiIiI8ZGISBvGRyLSpyqF2bh///4a07OysjBu3DhYWVkBAH744YdiZyw2NhYA4OTkJEl3cnJSrcvr6dOnyMrK0rjPzZs3tZ5r3rx5mDlzZjFzTERU8TA+EhFpxvhIRPpUqCfy+/btw/Pnz2FjYyNZAMDS0lLytyGZOnUqEhMTVcuDBw/0nSUionKB8ZGISDPGRyLSp0I9kd+xYwcmTZqEkJAQDB8+XJW+bds2fP755/Dy8iqxjDk7OwMA4uLiUL16dVV6XFwcvL29Ne7j4OAAY2NjxMXFSdLj4uJUx9PEzMwMZmZmxc80EVEFw/hIRKQZ4yMR6VOhnsi/9dZbCA8Px8aNGzFgwADEx8eXVr7g4eEBZ2dnHD9+XJWWlJSE8+fPo3Xr1hr3MTU1hY+Pj2Sf7OxsHD9+XOs+RERERERERIak0IPdubu74/Tp02jUqBGaNm2Kw4cPQyaTFenkycnJuHr1Kq5evQogZ4C7q1evIjo6GjKZDBMmTMCcOXPw448/4s8//0RwcDBcXFzQt29f1TG6du2KVatWqf6eOHEiNmzYgC1btuDGjRt4//33kZKSImlBQERERERERGSoCtW0XsnIyAgzZ85Et27dEBwcjKysrCKd/NKlS+jcubPq74kTJwIAQkJCsHnzZkyePBkpKSkYNWoUEhIS0K5dOxw6dAhyuVy1T2RkJJ4+far6e/DgwXjy5AmmT5+O2NhYeHt749ChQ2oD4BEREREREREZIpkQQhTnAMnJyYiMjET9+vUrTD+hpKQk2NjYIDExEdbW1vrODhEZoIoaRypquYio7FTUOFJRy0VEZacwcaTY88ibmJjA0tKyuIchIiIiIiIiIh0UqiK/efNmnD17FgDw6tUrjBgxAhYWFnjttddgaWmJ9957D2lpaaWSUSIiIiIiIiIqZEV+1qxZMDLK2WXatGk4ceIEdu/ejWvXruH777/HyZMnMW3atFLJKBEREREREREVcrC7mJgY1ZzuP/74I9auXYuAgAAAQP369VG1alUMGzYMCxcuLPmcEhEREREREVHhnsg7OzsjMjISAJCSkgIHBwfJ+mrVquHZs2cllzsiIiIiIiIikihURX7IkCH49NNPkZCQgGHDhmHWrFlITk4GAKSmpmLGjBlo27ZtqWSUiIiIiIiIiArZtD4sLAx//fUXateujebNmyM8PBxOTk6oUaMGYmJiYG9vj6NHj5ZWXomIiIiIiIgqvUJV5E1NTbF//34cOnQIP/30E4yNjZGdnY3q1aujbdu2ePvtt2FhYVFaeSUiIiIiIiKq9ApVkVcKCAhQDXJHRERERERERGWnUH3kiYiIiIiIiEi/ilyR79mzJx49eqT2fyIiIiIiIiIqPUWuyJ8+fRovX75U+z8RERERERERlR42rSciIiIiIiIyIKzIExERERERERkQVuSJiIiIiIiIDAgr8kREREREREQGhBV5IiIiIiIiIgPCijwRERERERGRASlyRb5WrVowMTFR+z8RERERERERlZ4qRd3xr7/+0vh/IiIiIiIiIio95b5pvbu7O2QymdoyZswYjdtv3rxZbVu5XF7GuSYiIiIiIiIqHUWqyG/ZsgU///yz6u/JkyfD1tYWbdq0wf3790sscwBw8eJFPHr0SLUcPXoUADBw4ECt+1hbW0v2Kek8EREREREREelLkSryc+fOhUKhAACcPXsWq1evxsKFC+Hg4ID//Oc/JZrBatWqwdnZWbUcOHAAderUQceOHbXuI5PJJPs4OTmVaJ6IiIiIiIiI9KVIfeQfPHgAT09PAMC+ffswYMAAjBo1Cm3btkWnTp1KMn8S6enp2LZtGyZOnAiZTKZ1u+TkZNSqVQvZ2dlo1qwZ5s6di4YNG2rdPi0tDWlpaaq/k5KSSjTfRESGivGRiEgzxkci0qciPZG3tLTEs2fPAABHjhxBt27dAAByuRwvX74sudzlsW/fPiQkJCA0NFTrNvXq1cPXX3+N/fv3Y9u2bcjOzkabNm3w8OFDrfvMmzcPNjY2qsXV1bUUck9EZHgYH4mINGN8JCJ9kgkhRGF3GjJkCG7evInXX38d3377LaKjo2Fvb48ff/wRn3zySamNYu/v7w9TU1P89NNPOu+TkZGBBg0aICgoCLNnz9a4jaY7qq6urkhMTIS1tXWx801ElU9SUhJsbGwMPo4wPhJRSWN8JCLSrDDxsUhN61evXo3PPvsMDx48wJ49e2Bvbw8AiIiIQFBQUFEOWaD79+/j2LFj+OGHHwq1n4mJCV5//XXcuXNH6zZmZmYwMzMrbhaJiCocxkciIs0YH4lIn4pUkbe1tcWqVavU0mfOnFnsDGmzadMmODo6omfPnoXaLysrC3/++SfeeOONUsoZERERERERUdkpUkUeABISEnDhwgU8fvwY2dnZqnSZTIZhw4aVSOaUsrOzsWnTJoSEhKBKFWmWg4ODUaNGDcybNw8AMGvWLPj6+sLT0xMJCQlYtGgR7t+/j3fffbdE80RERERERESkD0WqyP/0008YMmQIkpOTYW1tLRlBvjQq8seOHUN0dDTeeecdtXXR0dEwMvp3zL74+HiMHDkSsbGxqFq1Knx8fHDmzBl4eXmVaJ6IiIiIiIiI9KFIg9299tpreOONNzB37lyYm5uXRr70qqIMwkJE+lNR40hFLRcRlZ2KGkcqarmIqOwUJo4Uafq5f/75B+PGjauQlXgiIiIiIiKi8qxIFXl/f39cunSppPNCRERERERERAUoUh/5nj17YtKkSbh+/ToaN24MExMTyfo333yzRDJHRERERERERFJFqsiPHDkSQM4I8XnJZDJkZWUVL1dEREREREREpFGRKvK5p5sjIiIiIiIiorJTpD7yRERERERERKQfOj+RX7lyJUaNGgW5XI6VK1fmu+24ceOKnTEiIiIiIiIiUqdzRX7ZsmUYMmQI5HI5li1bpnU7mUzGijwRERERERFRKdG5In/v3j2N/xdCAMipwBMRERERERFR6SpyH/mNGzeiUaNGkMvlkMvlaNSoEb766quSzBsRERERERER5VGkUeunT5+OpUuXYuzYsWjdujUA4OzZs/jPf/6D6OhojdPSEREREREREVHxFakiv3btWmzYsAFBQUGqtDfffBNNmjTB2LFjWZEnIiIiIiIiKiVFalqfkZGB5s2bq6X7+PggMzOz2JkiIiIiIiIiIs2KVJEfNmwY1q5dq5a+fv16DBkypNiZIiIiIiIiIiLNdG5aP3HiRNX/ZTIZvvrqKxw5cgS+vr4AgPPnzyM6OhrBwcEln0siIiIiIiIiAlCIivyVK1ckf/v4+AAAIiMjAQAODg5wcHDAtWvXSjB7RERERERERJSbzhX5kydPlmY+iIiIiIiIiEgHRZ5HnoiIiIiIiIjKHivyRERERERERAaEFXkiIiIiIiIiA1KuK/IzZsyATCaTLPXr1893n927d6N+/fqQy+Vo3Lgx/ve//5VRbomIiIiIiIhKX7muyANAw4YN8ejRI9Xy66+/at32zJkzCAoKwogRI3DlyhX07dsXffv2xV9//VWGOSYiIiIiIiIqPeW+Il+lShU4OzurFgcHB63brlixAgEBAZg0aRIaNGiA2bNno1mzZli1alUZ5piIiIiIiIio9JT7ivzt27fh4uKC2rVrY8iQIYiOjta67dmzZ+Hn5ydJ8/f3x9mzZ/M9R1paGpKSkiQLERExPhIRacP4SET6VK4r8q1atcLmzZtx6NAhrF27Fvfu3UP79u3x4sULjdvHxsbCyclJkubk5ITY2Nh8zzNv3jzY2NioFldX1xIrAxGRIWN8JCLSjPGRiPSpXFfke/TogYEDB6JJkybw9/fH//73PyQkJOC7774r0fNMnToViYmJquXBgwclenwiIkPF+EhEpBnjIxHpUxV9Z6AwbG1t8dprr+HOnTsa1zs7OyMuLk6SFhcXB2dn53yPa2ZmBjMzsxLLJxFRRcH4SESkGeMjEelTuX4in1dycjIiIyNRvXp1jetbt26N48ePS9KOHj2K1q1bl0X2iKROzstZiIiIiIiISlC5fiL/0UcfoXfv3qhVqxZiYmIQFhYGY2NjBAUFAQCCg4NRo0YNzJuXU1kaP348OnbsiCVLlqBnz57YuXMnLl26hPXr1+uzGERERJRX7hudnafqLx9EREQGqFxX5B8+fIigoCA8e/YM1apVQ7t27XDu3DlUq1YNABAdHQ0jo38bFbRp0wY7duzAZ599hk8++QR169bFvn370KhRI30VgYiIiIiISDf5tebkTU/KpVxX5Hfu3Jnv+lOnTqmlDRw4EAMHDiylHBHlogy0uYPq/6edvfvs37S7H6n+e85tFP7T7TXt+xMRVXDLjv4NAPCN1hwnW9e2Z1wkokpp2dG/pbExj9adyzAzVO4ZVB95IiIiIiIiosquXD+RJyIiIiIiqtD+v5Vmfk/jifJiRZ6oBGhsKkpEVJlp6moEwLcQ+6qwqT0RVUC8fqTiYEWeqAz5Rq/H2Y3SNPZ3IiL6V+6Kf+va9nrMCRFR+XJ2o5Zxl6hSYkWeiIiIiIiorLApPZUAVuSJiIiIiIgMiG/0euDk/7daYvejSokVeaIiyD09yLnMv/WcGyKi8oN9PomItCtoijkiXbEiT1RMvtHri7W/8qJXif2diIhyKPvLK2+YquJj7sHw+CSKiCqp3DGS14+VDyvyREREVHgcWZ6IiEhvWJEnKoi+nvwoz8uLYyIiIiLDxgHuqISxIk9UjkgGLiEiIiIiItKAFXkiIiIiIiIDpfYgiK05KwVW5Il0kHfAJSIi+tfZu88YH4mINOBMHlRaWJEnKmeUNw2UWnfWU0aIiMqZvBfErWuzKxIRESC9fuQo9pUDK/JEelbc6euIiMoDxjIiIqKyw4o8UXnH+ZKJqJLjTQIiMkgn57FJPZUaVuSJtMk7RzIRERERUTknGfyOD4EqLCN9Z4CIiIiIiIiIdMeKPBEREREREZEBYdN6Ii3yjh6vLxyFlIjKm2VH/y4X/T7zTnvH+EhE+qacXQPQ75RzeadOZnyseMr1E/l58+ahRYsWsLKygqOjI/r27Ytbt27lu8/mzZshk8kki1wuL6McExEREREREZWucv1E/pdffsGYMWPQokULZGZm4pNPPkH37t1x/fp1WFhYaN3P2tpaUuGXyWRlkV2qCDjAHREREREVBUeppzJUrivyhw4dkvy9efNmODo6IiIiAh06dNC6n0wmg7Ozc2lnj4iIiIiIqNxSTd950p4j2Fcw5boin1diYiIAwM7OLt/tkpOTUatWLWRnZ6NZs2aYO3cuGjZsqHX7tLQ0pKWlqf5OSkoqmQxThcO5jKmyYXwkItKM8ZGI9Klc95HPLTs7GxMmTEDbtm3RqFEjrdvVq1cPX3/9Nfbv349t27YhOzsbbdq0wcOHD7XuM2/ePNjY2KgWV1fX0igCEZHBYXwkItKM8ZGI9EkmhBD6zoQu3n//fRw8eBC//voratasqfN+GRkZaNCgAYKCgjB79myN22i6o+rq6orExERYW1sXO+9kGHJGYS7fT9zPuY36d9RRZX9+NpMql5KSkmBjY2PwcYTxkQDpKMxK5SVennMbpfo/R2U2DIyPVJFIR6kvH3FRk9a12bTeEBQmPhpE0/oPP/wQBw4cwOnTpwtViQcAExMTvP7667hz547WbczMzGBmZlbcbBKVCeUPhm/0s5ygTFSKGB/JkOS94cCKPZUmxkcCynflPTdO11nxlOuKvBACY8eOxd69e3Hq1Cl4eHgU+hhZWVn4888/8cYbb5RCDomIiCqP8njBmjdPuZ/QExERVVTluiI/ZswY7NixA/v374eVlRViY2MBADY2NlAoFACA4OBg1KhRA/Pm5TQznjVrFnx9feHp6YmEhAQsWrQI9+/fx7vvvqu3chAREREREemT5MYnR7E3eOW6Ir927VoAQKdOnSTpmzZtQmhoKAAgOjoaRkb/jtkXHx+PkSNHIjY2FlWrVoWPjw/OnDkDLy+vsso2ERERERERUakp1xV5XcbhO3XqlOTvZcuWYdmyZaWUIyIiIiIiIiL9Mpjp54iIiIiIiIionD+RJypNmqZTIiKq1P5/Wsuzd59Jkn31kZciYh9QIiptZzd+pO8sELEiT2TIOJUIEZF2Z+8+A+7mXHCrputkxZ6IiNeQFQAr8lS5/P/TphwD9JYNIiIiIiJ9kk7fuVhv+aCiYUWeKi1l8DL0OYfVmpEq8akTEREREVGFxMHuiIiIiIiIiAwIn8hTpbHs6N/wjX5W8IZERJUQYyQRkWYc3I7KI1bkqeL7/37xFeECVdqXSV3ukabPZf7NgUuIiP6fMj4qB3difCQi+lfu2ZwYHw0DK/JEFZRv9Pp/+8yzvzwRERERacGB7wwP+8gTERERERERGRA+kadKr6Dm6kREREREROUJK/JERESV1f+PIQJUjHFEiIhKTK74SFQesSJPFdfJeZLB3yojVfnv5oy22noE+zwRUY7KOkq9shXW2Y05f59zGwWAgzsR0b8qa3xUyjtKP68fyyf2kSciIiIiIiIyIHwiT0REVFmwKT0RkXYVaMpiqvhYkacKJW9TIMojd38vTklHVKlU9qai2qgGPD1pz7hIVEkp51BnjNSC14/lEivyRJVI7jEDWnfWY0aIqPTkHaCJF106OXv3Gc5l/q36m33miYhy5L5+PJf5N+NjOcGKPBk+jipaNLy7SlQ5sKkoEZFmjI9kwFiRJ4PGpqJFx7urRBVbZZ+1oyhUzeyRM6o9R7QnqpjYlL7ofKPXc9aPcoIVeTJcJ+cxAJc0PqUnIlKR9J8HGBeJKgJeP5YYxkj9MoiK/OrVq7Fo0SLExsaiadOm+OKLL9CyZUut2+/evRvTpk1DVFQU6tatiwULFuCNN94owxxTicpVuVyWOUD1fwbhkpW3dQP70BMZFj5hKj3K1g3KPvSqp08cj4DIYDBGlp7cMZJP58tOua/I79q1CxMnTsSXX36JVq1aYfny5fD398etW7fg6Oiotv2ZM2cQFBSEefPmoVevXtixYwf69u2Ly5cvo1GjRnooARXJ/18cqTUNddNDXiorTWMP8CKVqFxRXphS2VB7+kRE5Vbu+OgbvR6+esxLZeEbvZ5P58tQua/IL126FCNHjsTw4cMBAF9++SV+/vlnfP3115gyZYra9itWrEBAQAAmTZoEAJg9ezaOHj2KVatW4csvvyzTvJOO2Jy7XNLUv1YyonOVPf+u4PtGpDe5+3VT2dA2/oDaE3si0g82n9cbVXy8+++U0Mq+9ADjY0kq1xX59PR0REREYOrUfysJRkZG8PPzw9mzZzXuc/bsWUycOFGS5u/vj3379mk9T1paGtLS0lR/JyYmAgCSkpKKkXvS6PQSXIh6jos1h6uSWjyMUf3/YuJltbTcXqUkq/6f8jJN4zZUeMrXtaDXNPfrfyzXe9TS5/+/K6eX/Ltxh/+WXAYNkDJ+CCH0nJPiYXwsI///3bkQ9RwA8sTITVp3awwgpVQzRoXR+NYXAIBjt6Tv4ZguntL4CFTqGMn4SEWx+sSdfOMhlV/K2AjkxMfcWgZ/Xsa5Kd8KFR9FOfbPP/8IAOLMmTOS9EmTJomWLVtq3MfExETs2LFDkrZ69Wrh6Oio9TxhYWECABcuXLiU+PLgwYPiB0M9YnzkwoVLaS2Mj1y4cOGiedElPpbrJ/JlZerUqZKn+NnZ2Xj+/Dns7e0hk8n0mLP8JSUlwdXVFQ8ePIC1tbW+s1MiKlqZKlp5AJZJV0IIvHjxAi4uLiVyPH1hfCw/WKbyr6KVB2B8zI+hxkeg4n1WK1p5AJbJEOg7PpbriryDgwOMjY0RFxcnSY+Li4Ozs7PGfZydnQu1PQCYmZnBzMxMkmZra1u0TOuBtbV1hfgy5FbRylTRygOwTLqwsbEpsWPpC+Nj+cMylX8VrTwA46Mmhh4fgYr3Wa1o5QFYJkOgr/hoVGJnLAWmpqbw8fHB8ePHVWnZ2dk4fvw4WrdurXGf1q1bS7YHgKNHj2rdnoiIiIiIiMiQlOsn8gAwceJEhISEoHnz5mjZsiWWL1+OlJQU1Sj2wcHBqFGjBubNyxn5fPz48ejYsSOWLFmCnj17YufOnbh06RLWr+eovkRERERERGT4yn1FfvDgwXjy5AmmT5+O2NhYeHt749ChQ3BycgIAREdHw8jo34YFbdq0wY4dO/DZZ5/hk08+Qd26dbFv374KOYe8mZkZwsLC1Jp1GbKKVqaKVh6AZSLDUBHfU5ap/Kto5QEqZpmo4r2vFa08AMtkCPRdHpkQBj73BxEREREREVElUq77yBMRERERERGRFCvyRERERERERAaEFXkiIiIiIiIiA8KKPBEREREREZEBYUWeiIiIiIiIyICwIk9ERERERERkQFiRJyIiIiIiIjIgrMgTERERERERGRBW5ImIiIiIiIgMCCvyRERERERERAaEFXkiIiIiIiIiA8KKPFUoFy5cgKmpKe7fv6/vrBTLl19+CTc3N6Slpek7K0RUCZRV7HzrrbcwaNCgUj0HEVUMnTp1QqdOnfSdDaJyq1JX5K9du4ahQ4eiRo0aMDMzg4uLC4YOHYrr16+rbbt582bIZDLVIpfL4eLiAn9/f6xcuRIvXrzQep7ffvsN/fr1g5OTE8zMzODu7o733nsPDx480Cmfp06dkpw777Jz506N+yUkJMDR0REymQzff/+91vL8+uuvavsKIeDq6gqZTIZevXpJ1v3nP/9Bs2bNYGdnB3NzczRo0AAzZsxAcnJyvq9Z7mXKlCmq7dzd3SGTyTB27FitZc+bf20+/fRTBAUFoVatWjptX16FhoYiPT0d69at03dWylR6ejrmzp2L+vXrQy6Xw8nJCT179sTDhw8L3FfbZ23+/Pklns+EhASMGjUK1apVg4WFBTp37ozLly9r3PbFixeYPHkyPDw8YGZmhho1aiAwMBCpqaklnq+ywtjJ2JlbTEwMhg4dinr16sHKygq2trZo2bIltmzZAiGEZNuPP/4Ye/bswe+//17o8xiyuLg4jB49GjVq1IBcLoe7uztGjBhR4H7JyckICwtDQEAA7OzsIJPJsHnz5gL3y8jIgJeXF2QyGRYvXlwCJVC3ceNGNGjQAHK5HHXr1sUXX3yhddtdu3ahdevWsLCwgK2tLdq0aYMTJ06USr4qK0OJy2Vlx44dWL58uc7bZ2dn48svv4S3tzcsLS3h5OSEHj164MyZM6WXyXLk2rVrGDhwIGrXrg1zc3M4ODigQ4cO+Omnn3Q+hi7XRs+ePcOiRYvQoUMHVKtWDba2tvD19cWuXbtKukgAct7XhQsXwsPDA3K5HE2aNMG3336rddu1a9fC29sbCoUC9vb26NKlS7n+vaqi7wzoyw8//ICgoCDY2dlhxIgR8PDwQFRUFDZu3Ijvv/8eu3btQp8+fdT2mzVrFjw8PJCRkYHY2FicOnUKEyZMwNKlS/Hjjz+iSZMmku2/+OILjB8/HrVr18bYsWNRvXp13LhxA1999RV27dqFgwcPwtfXV6c8jxs3Di1atFBLb926tcbtp0+fXmBlQS6XY8eOHWjXrp0k/ZdffsHDhw9hZmamts/FixfRvn17DB8+HHK5HFeuXMH8+fNx7NgxnD59GkZG0vtDytcst0aNGqkdd8OGDZg6dSpcXFzyzbM2V69exbFjxypE0JXL5QgJCcHSpUsxduxYyGQyfWep1GVkZKBnz544c+YMRo4ciSZNmiA+Ph7nz59HYmIiatasWeAxunXrhuDgYEna66+/XqL5zM7ORs+ePfH7779j0qRJcHBwwJo1a9CpUydERESgbt26qm0TExPRsWNHPHz4EKNGjYKnpyeePHmC8PBwpKWlwdzcvETzVhYYO3Mwdv7r6dOnePjwIQIDA+Hm5oaMjAwcPXoUoaGhuHXrFubOnava9vXXX0fz5s2xZMkSfPPNN0U6n6F58OAB2rZtCwB47733UKNGDcTExODChQsF7vv06VPMmjULbm5uaNq0KU6dOqXTOb/44gtER0cXJ9v5WrduHd577z0MGDAAEydORHh4OMaNG4fU1FR8/PHHkm1nzJiBWbNmITAwEKGhocjIyMBff/2Ff/75p9TyV9kYYlzWxZEjR4q8744dO/DXX39hwoQJOm0/adIkLF26FEOHDsUHH3yAhIQErFu3Dh07dsRvv/2Gli1bFjkvhuD+/ft48eIFQkJC4OLigtTUVOzZswdvvvkm1q1bh1GjRuW7v67XRmfPnsWnn36KN954A5999hmqVKmCPXv24K233sL169cxc+bMEi3Xp59+ivnz52PkyJFo0aIF9u/fj7fffhsymQxvvfWWZNt33nkH27dvR3BwMD788EOkpKTgypUrePz4cYnmqUSJSujOnTvC3Nxc1K9fXzx+/Fiy7smTJ6J+/frC0tJS3L17V5W+adMmAUBcvHhR7XjHjx8XCoVC1KpVS6SmpqrSf/31V2FkZCTat28vUlJS1PLg5OQkXFxcRHx8fL75PXnypAAgdu/erXMZ//zzT1GlShUxa9Ysjfsqy9O/f3/h4OAgMjIyJOtHjhwpfHx8RK1atUTPnj0LPN/ixYsFAHH27Fm1c2h6zXKrVauWaNiwoahSpYoYO3asZF1hyj5u3Djh5uYmsrOzC9zWEFy6dEkAEMePH9d3VlSSk5O1rsv7GS+sBQsWCBMTE3H+/Pki7Q9AjBkzplh50MWuXbvUPpOPHz8Wtra2IigoSLLt+++/L2xtbSWxxJAxdjJ2FkavXr2EhYWFyMzMlKQvXrxYWFhYiBcvXpTo+YpDW2zLysoSL1++LNaxe/ToITw8PMTTp08Lve+rV6/Eo0ePhBBCXLx4UQAQmzZtynefuLg4YWNjo/oML1q0qCjZ1io1NVXY29urfb6HDBkiLCwsxPPnz1VpZ8+eFTKZTCxdurRE80D/MrS4XFZ69uwpatWqpdO2GRkZQqFQiMDAQEn63bt3BQAxbty4Ushh4WVnZ0vek9xevnwpsrKySvR8mZmZomnTpqJevXoFbqvrtdHdu3dFVFSUZN/s7GzRpUsXYWZmlu91ZmE9fPhQmJiYSK4Ns7OzRfv27UXNmjUlv03K/P/www8ldv6yUCmb1i9atAipqalYv349qlWrJlnn4OCAdevWITk5GYsWLdLpeF26dMG0adNw//59bNu2TZU+e/ZsyGQybNmyRe3JW506dbBw4ULExMRg/fr1xS9UHuPHj0e/fv3Qvn37fLcLCgrCs2fPcPToUVVaeno6vv/+e7z99ts6n8/d3R1ATrOaonB3d0dwcDA2bNiAmJiYIh1j37596NKli9rT60uXLsHf3x8ODg5QKBTw8PDAO++8I9lm8eLFaNOmDezt7aFQKODj46OxSapMJsOHH36I3bt3w8vLCwqFAq1bt8aff/4JIOcphaenJ+RyOTp16oSoqCi1Y5w/fx4BAQGwsbGBubm56m5vXj4+PrCzs8P+/fuL9Hrk5+bNmwgMDISdnR3kcjmaN2+OH3/8UbKNsundL7/8gg8++ACOjo6qp+KdOnVCo0aNEBERgQ4dOsDc3ByffPJJkfOTnZ2NFStWoF+/fmjZsiUyMzOL3PT85cuXePXqVb7b6PoeaPL999/DyckJ/fv3V6VVq1YNgwYNwv79+1XjGiQkJGDTpk0YNWoUPDw8kJ6ebvBjHjB2/qsyxE53d3f06tULR44cgbe3N+RyOby8vPDDDz/onLfU1FSkp6dL0rt164aUlBTJa1dSDh48iPbt28PCwgJWVlbo2bMnrl27JtkmNDQUlpaWiIyMxBtvvAErKysMGTIEwL8xfvv27WjYsCHMzMxw6NChIufn5s2bOHjwICZNmgR7e3u8evUKGRkZOu9vZmYGZ2fnQp1zypQpqFevHoYOHap1m4SEBEyYMAGurq4wMzODp6cnFixYgOzs7AKPf/LkSTx79gwffPCBJH3MmDFISUnBzz//rEpbvnw5nJ2dMX78eAgh1LqRUPEZWlyeMWOGxlaGymuO3NdNefvIK7sMfffdd/j8889Rs2ZNyOVydO3aFXfu3JHs9/PPP+P+/fuq7gPKWKtJRkYGXr58CScnJ0m6o6MjjIyMoFAo8i1TYWVnZ2P58uVo2LChqhvh6NGjER8fL9lOGYMPHz6M5s2bQ6FQYN26darXYefOnfjss89Qo0YNmJubIykpqUTzaWxsDFdXV51+n3S9NvLw8FDrwiWTydC3b1+kpaXh7t27knX//PMP3nnnHVVXjoYNG+Lrr7/WKf/79+9HRkaGJFbJZDK8//77ePjwIc6ePatKX7p0KVq2bIl+/fohOzsbKSkpOp1D3yplRf6nn36Cu7u71gu1Dh06wN3dvVD9QoYNGwbg32ZAqampOH78ONq3b6/WNFJp8ODBMDMz0/k8L168wNOnT9UWkacP4u7du3HmzBksXLiwwGO6u7ujdevWkv4iBw8eRGJiolqTk9wyMzPx9OlTxMTE4MiRI/jss89gZWWlselRYmKiWp41+fTTT5GZmVmkPs3//PMPoqOj0axZM0n648eP0b17d0RFRWHKlCn44osvMGTIEJw7d06y3YoVK/D6669j1qxZmDt3LqpUqYKBAwdKLkiUwsPD8d///hchISGYMWMGbty4gV69emH16tVYuXIlPvjgA0yaNAlnz55Vu2Fw4sQJdOjQAUlJSQgLC8PcuXORkJCALl26aGxm2axZM50rmLq6du0afH19cePGDUyZMgVLliyBhYUF+vbti71796pt/8EHH+D69euYPn26pH/us2fP0KNHD3h7e2P58uXo3LkzgJw+nZo+p3mXxMRE1bGuX7+OmJgYNGnSBKNGjYKFhQUsLCzQpEkTnDx5Uueybd68GRYWFlAoFPDy8sKOHTvUtinse5DXlStX0KxZM7Vm0C1btkRqair+/vtvAMCvv/6KV69ewdPTE4GBgTA3N4dCoUDbtm1x9epVnctUnjB2/quix06l27dvY/DgwejRowfmzZunio2aKuEvX77E06dPERUVhS1btmDTpk1o3bq12kWw8iZoSce2rVu3omfPnrC0tMSCBQswbdo0XL9+He3atVO7qZqZmQl/f384Ojpi8eLFGDBggGrdiRMn8J///AeDBw/GihUrVBWA+Ph4nWJb7puQx44dAwA4OTmha9euUCgUUCgU6NGjh8YbvcV14cIFbNmyBcuXL9faJSs1NRUdO3bEtm3bEBwcjJUrV6Jt27aYOnUqJk6cWOA5rly5AgBo3ry5JN3HxwdGRkaq9QBw/PhxtGjRAitXrkS1atVgZWWF6tWrY9WqVcUoJeVmqHG5OObPn4+9e/fio48+wtSpU3Hu3DnVzTggJyZ6e3vDwcEBW7duxdatW/PtL69QKNCqVSts3rwZ27dvR3R0NP744w+EhoaiatWqBTYrL6zRo0dj0qRJaNu2LVasWIHhw4dj+/bt8Pf3V7vRd+vWLQQFBaFbt25YsWIFvL29Vetmz56Nn3/+GR999BHmzp0LU1NTZGdn6xSnnj59qvGmYkpKCp4+fYrIyEgsW7YMBw8eRNeuXQssk67XRtrExsYCyLn5pBQXFwdfX18cO3YMH374IVasWAFPT0+MGDFCp/EPrly5AgsLCzRo0EAtT8r1AJCUlIQLFy6gRYsW+OSTT2BjYwNLS0vUrl0b3333XYHn0Ss9twgocwkJCQKA6NOnT77bvfnmmwKASEpKEkLo1tTRxsZGvP7660IIIa5evSoAiPHjx+d7niZNmgg7O7t8t1E2kdS2KJvdCZHT5M3NzU1MnTpVsq+25qEXL14Uq1atElZWVqrmOgMHDhSdO3cWQgitzUPPnj0ryUO9evXEyZMnNZ5D05Jb7nMMHz5cyOVyERMTk2/+8zp27JgAIH766SdJ+t69e3Vqopq3qVJ6erpo1KiR6NKliyQdgDAzMxP37t1Tpa1bt04AEM7OzqrPixBCTJ06VQBQbZudnS3q1q0r/P39JU1YU1NThYeHh+jWrZtavkaNGiUUCkW+eS+srl27isaNG4tXr16p0rKzs0WbNm1E3bp1VWnK969du3ZqTWM7duwoAIgvv/xS7fghISH5fl6VS8eOHVX7/PDDDwKAsLe3F3Xr1hWbNm0SmzZtEnXr1hWmpqbi999/L7Bcbdq0EcuXLxf79+8Xa9euFY0aNRIAxJo1ayTlLOx7kJeFhYV455131NJ//vlnAUAcOnRICCHE0qVLVWVq2bKl2L59u1izZo1wcnISVatWVX3GDQVjp1ArT0WOncrjAxB79uxRpSUmJorq1aur3q/c5s2bJ8lr165dRXR0tMbzvvbaa6JHjx755q0wXrx4IWxtbcXIkSMl6bGxscLGxkaSroxRU6ZMUTsOAGFkZCSuXbumtk75ehS0hIWFqfYZN26cKg4EBASIXbt2iUWLFglLS0tRp06dQnVJKqhpfXZ2tmjZsqWqGeu9e/c0Nq2fPXu2sLCwEH///bckfcqUKcLY2Fjre6Y0ZswYYWxsrHFdtWrVxFtvvSWEEOL58+eqsltaWopFixaJXbt2iYCAAK2/H1Q4hhiXw8LC1GJZ7jzlvr7q2LGj5FpBGdcaNGgg0tLSVOkrVqwQAMSff/6pSitM03ohhLh9+7Zo1qyZ5Ltcu3ZtcfPmTZ2PoYvw8HABQGzfvl2SfujQIbV0ZcxRXlcoKV+H2rVrq12/Kr/3uix5f3uEEGL06NGq9UZGRiIwMFDSXUYbXa+NNHn27JlwdHQU7du3l6SPGDFCVK9eXa1b0ltvvSVsbGy0djNQ6tmzp6hdu7ZaekpKiuQ34PLly6pY5eTkJNasWSO2b98uWrZsKWQymTh48GC+59GnSjfYnXIkTisrq3y3U65/8eJFgdsqWVpaqo5fmPPkNzpobtOnT9d4x9XOzk71//nz5yMjI6NQzZwHDRqECRMm4MCBAwgICMCBAwewcuXKfPfx8vLC0aNHkZKSgjNnzuDYsWNam8ytXr0ar732mk55+eyzz7B161bMnz8fK1as0LkMz549AwBUrVpVkm5rawsAOHDgAJo2bQoTExON++d+YhQfH4+srCy0b99e48iWXbt2lTTRatWqFQBgwIABkvdbmX737l24u7vj6tWruH37Nj777DNVfnMfc+vWrcjOzpbczaxatSpevnyJ1NTUEhkY7fnz5zhx4gRmzZqFFy9eSD57/v7+CAsLwz///IMaNWqo0keOHAljY2O1Y5mZmWH48OFq6ZMnT863SadS7vdK+dl58eIFrly5AldXVwA5Tfw8PT2xcOFCSRM/TfI+3XvnnXfg4+ODTz75BKGhoVAoFEV6D/J6+fKlxoHM5HK5an3uMslkMhw/fhyWlpYAcgb7at26NVavXo05c+bkW6byhLFTXUWOnUouLi7o16+f6m9ra2sEBwdjwYIFiI2NlTT7DgoKQvPmzfHkyRMcOHAAcXFxqu9DXlWrVtXawqAojh49ioSEBAQFBUmOa2xsjFatWmls2fP+++9rPFbHjh3h5eWllr59+3at5cmtdu3aqv8r31tnZ2f8/PPPqthSs2ZNBAUFYceOHXj33XcLPKYuNm/ejD///LPAmQp2796N9u3bq70Hfn5+mD9/Pk6fPi15upnXy5cvYWpqqnGdXC5Xi4HPnj3Dzp07MXjwYABAYGAgGjdujDlz5mD06NGFKiNJGXJcLo7hw4dLPoPK+H737l2NA4LqwsrKCg0bNkTr1q3RtWtXxMbGYv78+ejbty/Cw8MlT4qLY/fu3bCxsUG3bt0k3z8fHx9YWlri5MmTku5ZHh4e8Pf313iskJAQtRZPzs7OOndbatq0qVrahAkTEBgYiJiYGHz33XfIyspS6x6lia7XRnllZ2djyJAhSEhIkMx8IYTAnj17MGjQIAghJK+Vv78/du7cicuXL6sGEi1OnnLHqnPnzqmu39988014eHhgzpw5CAgIyLf8+lLpKvK5g1l+Xrx4AZlMVqgvbnJyMhwdHQt9HuU+BWncuDH8/Py0ro+KisKiRYuwevVqVaVBF9WqVYOfnx927NiB1NRUZGVlITAwMN99rK2tVXnp06cPduzYgT59+uDy5ctqgaFly5ZqTfC0qV27NoYNG4b169dLmnHrSuRpKtuxY0cMGDAAM2fOxLJly9CpUyf07dsXb7/9tuTLfeDAAcyZMwdXr16V9GPW1DTRzc1N8reNjQ0AqCqfedOVfZ5u374NICfwapOYmCi5oFaWJ79R65OTkyUVAWNjY7V+ckp37tyBEALTpk3DtGnTNG7z+PFjSUVeWzO6GjVqaLyY8/Ly0ngRnB/lD1Hbtm0lr6ObmxvatWtXpNG0TU1N8eGHH+K9995DREQE2rVrp/N7YGFhgefPn0vSq1WrBmNjYygUCo193ZX98pVlUf7bu3dvyffR19cXHh4eBje7AmOnuoocO5U8PT3V4o/y5kJUVJSkIl+rVi1V38egoCCMGjUKfn5+uHXrltrFphCiwNk4nj9/LrmAVCgUqrial/K73aVLF43rra2tJX9XqVJF60wY2mJefheM2ijLPWjQIMkNwoEDB2LYsGE4c+ZMiVTkk5KSMHXqVEyaNEnttyiv27dv448//tD6O6EcofnJkyfIyspSpVtaWsLS0hIKhULrhf2rV6/UYqCJiYnke2FkZITBgwcjLCwM0dHRar+ppDtDjsvFkfczo7xuytvHXFeZmZnw8/NDp06dJJVJPz8/NGzYEIsWLcKCBQu07q9sFq5kY2OjtV/97du3kZiYqPV1yjtCurZ4pG2dXC7P9/euIPXr10f9+vUBAMHBwejevTt69+6N8+fP5xuzdb02ymvs2LE4dOgQvvnmG8lv4JMnT5CQkID169drHXdB+Vppe/0Le73m4eGhqsQDOTGvd+/e2LZtGzIzM1GlSvmrNpe/HJUyGxsbuLi44I8//sh3uz/++AM1a9bUetc5r4cPHyIxMRGenp4AgLp166JKlSr5nictLQ23bt0qsSktpk+fjho1akgGWVN+uJ88eYKoqCi4ublpfNr49ttvY+TIkYiNjUWPHj1UT7J11b9/fwwbNgw7d+7UeIevMD799FNs3boVCxYsQN++fXXax97eHoB6EFfOo3zu3Dn89NNPOHz4MN555x0sWbIE586dg6WlJcLDw/Hmm2+iQ4cOWLNmDapXrw4TExNs2rRJYx9rTU+n80tXXiArBxFatGiRpI9TbnkrEfHx8aq+1dosXrxYMl1HrVq1tPa9VObho48+0nqHV/kZVtJ2bm3piYmJOj21MjU1VT0RVU6blXegGSBnsJncfS4LQ3lBq6yU6/oe/Pbbb6o+/0r37t2Du7s7qlevjkePHqntp0xTlqWgMhX1gkNfGDsrV+wsCYGBgdiwYQNOnz6tFm/i4+MlUzVq0r9/f/zyyy+qv0NCQrTOoa78bm/dulXj4HB5L8DMzMy0trzRFtvyVmy1UVZ4Ae1xwNjYGPb29iX2ui9evBjp6ekYPHiw6jP88OFDADmvdVRUFFxcXFR9aLt164bJkydrPJbyRk2LFi1w//59VXpYWBhmzJiB6tWrIysrC48fP5ZURtLT0/Hs2TNVmZWDqdra2qr9Pir3i4+PZ0W+GAwxLmurDOry3VIq6HqrsE6fPo2//voLS5culaTXrVsXDRo0KHA8j+rVq0v+3rRpE0JDQzVum52dDUdHR2zfvl3j+rw32PK7/tO0LisrC0+ePMk3v0p2dnYFfiYCAwMxevRo/P3336hXr57W7XS9Nspt5syZWLNmDebPn68al0FJGdOHDh2q9eGLcnpEba9/9erVcfLkSbUbx4W9XsvIyEBKSorWG8n6VOkq8kDOE7J169bh119/VZsDGMgZzCwqKkqnQV+Utm7dCgCqixVzc3N07doVx44dw/3799VGaASA7777DmlpaRg4cGARSyIVHR2NO3fuSJr1KSlHbIyPj9d4odmvXz+MHj0a586dw65duwp97rS0NGRnZ0sGMCuqOnXqYOjQoVi3bp3kzlh+lHcP7927p3G9r68vfH198fnnn2PHjh0YMmQIdu7ciXfffRd79uyBXC7H4cOHJU/pN23aVOyy5FanTh0A0idyBbl3757aIB15BQcHSz7H+QV95WfDxMSkWHds8zN+/Hhs2bKlwO06duyomhO5cePGMDEx0TivcExMjNYnRwVRjn6q3F/X96Bp06ZqTdOUlQNvb2+Eh4erNcE/f/48zM3NVRfBPj4+AKC1TMrPrCFh7LRVW1/RY6eyFU/uiyDloEX5jQIN/NtsMW/ZMjMz8eDBA7z55pv57r9kyRJJRVfThaCS8rvt6OhYarEtb8VWG2WFF9AeB9LT0/H06dMix7a8oqOjER8fj4YNG6qtmzt3LubOnYsrV67A29sbderUQXJycoGvU96uBMrvh/Im6KVLl/DGG2+o1l+6dAnZ2dmq9UZGRvD29sbFixeRnp4uqTAoZ1goqfJXZoYWl5VPzxMSEiQxVZfvVmEU1OInt7i4OACabyZkZGQgMzMz3/3zXi9o+h4q1alTB8eOHUPbtm1LfDR8AHjw4EG+T/FzO3nypGRWAE20xfG8dL02Ulq9ejVmzJiBCRMm4OOPP1Y7nnJwzKysrAJjlbbX39vbG1999RVu3LghaSl6/vx51Xog57fF2dlZ6/WaXC7XuUtKmdNT33y9un37tjA3NxdeXl5qAyg8e/ZMeHl5CWtr60LPuenh4SGZbzY8PFwYGRmJTp06qQ3IcPfuXeHs7CxcXV1LbC7k8PBwsXfvXskye/ZsAUBMnjxZ7N27V6Snp2stz+bNm8WMGTMkec07YFN8fLzqGLkp50LeuHGjKq0wcyHnHRTqzp07wtjYWHh7e+tUdiGEcHV1FcOGDZOkPX/+XG1u5GvXrgkAYtWqVUIIISZOnCjMzc0lgw7du3dPmJubqw3IAqjPVa5tQKG871tWVpaoU6eOqFu3rsb5k/PO/yqEEHZ2dmrzQxdXp06dhJ2dncbB1nLnIb/3r2PHjqJhw4Yaj3/t2jVx9OjRApdLly5J9uvTp48wNjYWN27cUKVdv35dGBsbiw8++ECVlpKSIm7cuCGePHmiMd9KSUlJok6dOsLBwUE1KE5R3oO8du7cqfaZfPLkibC1tRWDBw+WbNu0aVNhbW0tyevhw4cFALFw4cICz1XeMHZWntipPD60DHbn7e2tStP2vendu7eQyWTi9u3bkvTff/9d7bjFlZiYKKytrUXHjh01vs658xgSEiIsLCw0HkdTjFf69ddfdYptkZGRqn1evXolHB0dRe3atSWfceUgqd99950q7cmTJ+LGjRtaB8DLb7C7iIgItc+w8hyhoaFi7969IiEhQQghxIwZM7QOPhUfHy8yMjI0nl8pNTVV2NnZiV69eknShw4dKszNzcWzZ89UacuWLRMAxPr161VpL1++FLVr1xZeXl75nod0Y2hx+cCBAwKA2L9/vyotOTlZuLm56TzYXd64prwOy/3dGDx4sLC1tc03L0qXLl0SAERISIgkPSIiQhgZGYn33ntPp+Po4tSpUwKAamDV3DIyMiSvn7ZBU/P7bXv58qVOcero0aOSQezi4uLUjpWeni6aNWsmFAqF5JopJiZG3LhxQxJrC3NttHPnTmFkZCSGDBmido2eW2hoqDA1NZUMYqiky/XagwcPtM4jX6NGDclAzuPHjxcAxJEjRyT5t7a2Fm+88UaB59KXSvlE3tPTE9988w2CgoLQuHFjjBgxAh4eHoiKisLGjRsRHx+PnTt3aryjdfDgQdy8eROZmZmIi4vDiRMncPToUdSqVQs//vijagAFAGjXrh2WLVuGCRMmoEmTJqpmHjdv3sSGDRtgZGSEffv26dwUMzw8XOP82E2aNEGTJk003olVHrtFixYFNrXMr9+w0qlTpzBu3DgEBgaibt26SE9PR3h4OH744Qc0b95cp0HOdKF8sqTLk12lPn36YO/evZKnR1u2bMGaNWvQr18/1KlTBy9evMCGDRtgbW2tepLQs2dPLF26FAEBAXj77bfx+PFjrF69Gp6engU2VysMIyMjfPXVV+jRowcaNmyI4cOHo0aNGvjnn39w8uRJWFtbS6ZtiYiIwPPnz9GnT58SywOQcxe0Xbt2aNy4MUaOHInatWsjLi4OZ8+excOHD/H7778X6/hF6SMP5Dw1On78OLp06YJx48YBAFauXAk7OzvJAGQXLlxA586dJU+9Vq9ejX379qF3795wc3PDo0eP8PXXXyM6Ohpbt25VPQkq7HugSWBgIHx9fTF8+HBcv34dDg4OWLNmDbKysiRdHABg2bJl6NatG9q1a4fRo0cjMTERS5cuxWuvvaZ1oK3yjLFTs4oYO5Vee+01jBgxAhcvXoSTkxO+/vprxMXFSVosff755/jtt98QEBAANzc3PH/+HHv27MHFixcxduxYte46R48ehbm5Obp161a8wuZibW2NtWvXYtiwYWjWrBneeustVKtWDdHR0fj555/Rtm3bYk95VpQ+8mZmZli0aBFCQkLQoUMHDBs2DNHR0VixYgXat28vmXN51apVmDlzptpTslWrViEhIUH1FPunn35SNZsfO3YsbGxs0KxZM7UpBJVN7Bs2bCj5DE+aNAk//vgjevXqhdDQUPj4+CAlJUU1UF5UVFS+fakVCgVmz56NMWPGYODAgfD390d4eDi2bduGzz//XDKI5OjRo/HVV19hzJgx+Pvvv+Hm5oatW7fi/v37ZTJNWWVgaHG5e/fucHNzw4gRIzBp0iQYGxvj66+/Vn1fS4qPjw927dqFiRMnokWLFqr+ztq27datG7Zs2YKkpCR0794djx49whdffAGFQoEJEyaUWL46duyI0aNHY968ebh69Sq6d+8OExMT3L59G7t378aKFSsKHGslP0XtIz969GgkJSWhQ4cOqFGjBmJjY7F9+3bcvHkTS5YskXT9nDp1KrZs2aLqcgjofm104cIFBAcHw97eHl27dlXrYtCmTRtV65/58+fj5MmTaNWqFUaOHAkvLy88f/4cly9fxrFjx9TGMsqrZs2amDBhAhYtWoSMjAy0aNEC+/btQ3h4OLZv3y7pojF16lR89913GDBgACZOnAgbGxt8+eWXyMjIwNy5cwv9epYZfd9J0Kc///xTvP3228LZ2VkYGRkJAEIul2ucdibvdECmpqbC2dlZdOvWTaxYsUIy7Vhe4eHhok+fPsLBwUHIZDIBQDg6OkqmPspPQVMo5Z7qRtu++U2hlJ+8dwPv3LkjgoODRe3atYVCoRByuVw0bNhQhIWFieTk5BI5h9Lt27eFsbGxzk+VlNNHhIeHS9KCgoKEm5ubMDMzE46OjqJXr15qT4M3btwo6tatK8zMzET9+vXFpk2bNE6RgmI8kVe6cuWK6N+/v7C3txdmZmaiVq1aYtCgQeL48eOS7T7++GPh5uaW793KooqMjBTBwcHC2dlZmJiYiBo1aohevXqJ77//XrVNUZ/IF0dERITw8/MTFhYWwsrKSvTp00dtiiTl65r7c3/kyBHRrVs3VXlsbW1F9+7d1V5TJV3fA22eP38uRowYIezt7YW5ubno2LGj1s/50aNHha+vr5DL5cLOzk4MGzZM5+9+ecXYWfFjZ+7jHz58WDRp0kQVH/Me88iRI6JXr17CxcVFmJiYCCsrK9G2bVuxadMmjfGrVatWYujQoQXmqyhOnjwp/P39hY2NjZDL5aJOnToiNDRUEvOL+kS+OL799lvRtGlTYWZmJpycnMSHH36o9tlX/ubknRIqv2nvcj+9zEvbb5MQOdP1TZ06VXh6egpTU1Ph4OAg2rRpIxYvXqyxRYMm69evF/Xq1ROmpqaiTp06YtmyZRrf77i4OBESEiLs7OyEmZmZaNWqVb5TUVHRGEpcFiLnt75Vq1bC1NRUuLm5iaVLlxZq+jldnsgnJyeLt99+W9ja2goABU5Fl5qaKmbNmiW8vLyEQqEQNjY2olevXuLKlSs6l6sw1q9fL3x8fIRCoRBWVlaicePGYvLkyZLWkkV5Il9U3377rfDz8xNOTk6iSpUqomrVqsLPz0/SckJJOYVn3vijy7VRftOr5n0PhciJH2PGjBGurq7CxMREODs7i65du0pa+eQnKytLzJ07V9SqVUuYmpqKhg0bim3btmncNjIyUvTr109YW1sLhUIhunTpIi5cuKDTefSlUlfk89qyZYuQyWQamxiWpFmzZgkA4tNPPy3V81RGXbp0KbULxLL06tUr4ezsLJYvX67vrBAViLHT8GmKndouIovjypUrQiaTldrFMRHlYFwmqvhYkc9j/vz5WvuulKT33ntPABDr1q0r1fNUNufOnRMmJiYiKipK31kplrVr1wpXV1fx6tUrfWeFSCeMnYZNU+wsjYr84MGDxcCBA0v0mESkGeMyUcUmE6KIczUQERFRheXu7o5GjRrhwIED+s4KERER5aF5ElUiIiIiIiIiKpf4RJ6IiIiIiIjIgPCJPBEREREREZEBYUWeiIiIiIiIyIBU0XcGyqPs7GzExMTAysoKMplM39khIgMkhMCLFy/g4uICI6OKc8+U8ZGIiovxkYhIs8LER1bkNYiJiYGrq6u+s0FEFcCDBw9Qs2ZNfWejxDA+ElFJYXwkItJMl/jIirwGVlZWAHJeQGtraz3nhogMUVJSElxdXVXxpKJgfCSi4mJ8JCLSrDDxkRV5DZTNoaytrRmIiahYKlrzSsZHIiopjI9ERJrpEh8rTsckIiIiIiIiokqAFXkiIiIiIiIiA8KKPBEREREREZEBYR95IgOXlZWFjIwMfWej0jExMYGxsbG+s0FE+WB81A/GR6LyiTFR/0oyPrIiT2SghBCIjY1FQkKCvrNSadna2sLZ2bnCDdhEZOgYH/WP8ZGo/GBMLF9KKj6yIk9koJQB2dHREebm5rxYKkNCCKSmpuLx48cAgOrVq+s5R0SUG+Oj/jA+EpU/jInlQ0nHR1bkiQxQVlaWKiDb29vrOzuVkkKhAAA8fvwYjo6ObEZKVE4wPuof4yNR+cGYWL6UZHzkYHdEBkjZv8nc3FzPOanclK8/+5sRlR+Mj+UD4yNR+cCYWP6UVHzUa0X+9OnT6N27N1xcXCCTybBv3z7J+tDQUMhkMskSEBBQ4HFXr14Nd3d3yOVytGrVChcuXCilEhDpF5tG6Rdff6Lyi99P/eLrT1S+8DtZfpTUe6HXinxKSgqaNm2K1atXa90mICAAjx49Ui3ffvttvsfctWsXJk6ciLCwMFy+fBlNmzaFv7+/qi8CERERERERkSHTa0W+R48emDNnDvr166d1GzMzMzg7O6uWqlWr5nvMpUuXYuTIkRg+fDi8vLzw5ZdfwtzcHF9//XVJZ5+IyqGbN2/C19cXcrkc3t7e+s4OEVG5whhJRJTD0ONhuR/s7tSpU3B0dETVqlXRpUsXzJkzR+tADenp6YiIiMDUqVNVaUZGRvDz88PZs2fLKstEerXs6N9ldq7/dHutzM6lq7CwMFhYWODWrVuwtLTUd3aIqBwpy/gIMEYSUfnFeGj48bBcV+QDAgLQv39/eHh4IDIyEp988gl69OiBs2fPahzh7+nTp8jKyoKTk5Mk3cnJCTdv3tR6nrS0NKSlpan+TkpKKrlCEFGZioyMRM+ePVGrVi19Z6VCYHwkqlgYI0sO4yORYTP0eFiuR61/66238Oabb6Jx48bo27cvDhw4gIsXL+LUqVMlep558+bBxsZGtbi6upbo8YnoX9nZ2Vi4cCE8PT1hZmYGNzc3fP755wCAP//8E126dIFCoYC9vT1GjRqF5ORkyf5fffUVGjRoALlcjvr162PNmjWqdTKZDBEREZg1axZkMhlmzJhRlkWrkBgficoWY6ThYHwkKl2Mh/kr1xX5vGrXrg0HBwfcuXNH43oHBwcYGxsjLi5Okh4XFwdnZ2etx506dSoSExNVy4MHD0o030T0r6lTp2L+/PmYNm0arl+/jh07dsDJyQkpKSnw9/dH1apVcfHiRezevRvHjh3Dhx9+qNp3+/btmD59Oj7//HPcuHEDc+fOxbRp07BlyxYAwKNHj9CwYUP897//xaNHj/DRRx/pq5gVBuMjUdlijDQcjI9EpYvxMH/luml9Xg8fPsSzZ89QvXp1jetNTU3h4+OD48ePo2/fvgBy7uQcP35c8sbmZWZmBjMzs9LIMhHl8uLFC6xYsQKrVq1CSEgIAKBOnTpo164dNmzYgFevXuGbb76BhYUFAGDVqlXo3bs3FixYACcnJ4SFhWHJkiXo378/AMDDwwPXr1/HunXrEBISAmdnZ1SpUgWWlpb53rwj3TE+EpUdxkjDwvhIVHoYDwum14p8cnKy5On6vXv3cPXqVdjZ2cHOzg4zZ87EgAED4OzsjMjISEyePBmenp7w9/dX7dO1a1f069dPVVGfOHEiQkJC0Lx5c7Rs2RLLly9HSkoKhg8fXublIyKpGzduIC0tDV27dtW4rmnTpqqADABt27ZFdna2ahCSyMhIjBgxAiNHjlRtk5mZCRsbmzLJPxFRaWKMJCLKwXhYML1W5C9duoTOnTur/p44cSIAICQkBGvXrsUff/yBLVu2ICEhAS4uLujevTtmz54tufsZGRmJp0+fqv4ePHgwnjx5gunTpyM2Nhbe3t44dOiQ2gB4RFT2FApFkfdV9nvasGEDWrVqJVmnafBLIiJDwxhJRJSD8bBgeq3Id+rUCUIIresPHz5c4DGioqLU0j788MN8m9ITkX7UrVsXCoUCx48fx7vvvitZ16BBA2zevBkpKSmqO6y//fYbjIyMUK9ePTg5OcHFxQV3797FkCFD9JF9IqJSxRhJRJSD8bBgBtVHnogMm1wux8cff4zJkyfD1NQUbdu2xZMnT3Dt2jUMGTIEYWFhCAkJwYwZM/DkyROMHTsWw4YNU7WomTlzJsaNGwcbGxsEBAQgLS0Nly5dQnx8vKpFDxGRoWKMJCLKwXhYMFbkiahMTZs2DVWqVMH06dMRExOD6tWr47333oO5uTkOHz6M8ePHo0WLFjA3N8eAAQOwdOlS1b7vvvsuzM3NsWjRIkyaNAkWFhZo3LgxJkyYoL8CERGVIMZIIqIcjIf5k4n82rZXUklJSbCxsUFiYiKsra31nR0iNa9evcK9e/fg4eEBuVyu7+xUWvm9DxU1jlTUclHFwfhYPjA+VpxykWFjTCx/Sio+GtQ88kRERERERESVHSvyRERERERERAaEFXkiIiIiIiIiA8KKPBEREREREZEBYUWeiIiIiIiIyICwIk9ERERERERkQFiRJyIiIiIiIjIgrMgTERERERERGRBW5ImIiIiIiIgMCCvyRFTuubu7Y/ny5SV2vJs3b8LX1xdyuRze3t4ldlwiIn1gjCQiylHS8bA8q6LvDBBRCTs5r+zO1Xlq2Z2rBIWFhcHCwgK3bt2CpaUlAODvv//GpEmT8NtvvyE9PR1NmjTB7Nmz0blzZz3nlohKTFnGR4AxkojKL8bDEnP48GGEhYXh2rVrkMvl6NChA5YsWQJ3d/dSPS+fyBNRpRMZGYl27dqhVq1asLe3BwD06tULmZmZOHHiBCIiItC0aVP06tULsbGxes4tEVHZYowkItLNvXv30KdPH3Tp0gVXr17F4cOH8fTpU/Tv37/Uz82KPBGVqZSUFAQHB8PS0hLVq1fHkiVL0KlTJ0yYMAEA8PjxY/Tu3RsKhQIeHh7Yvn272jFu376NDh06QC6Xw8vLC0ePHoVMJsO+ffsKPL9MJkNERARmzZoFmUyGGTNm4OnTp7h9+zamTJmCJk2aoG7dupg/fz5SU1Px119/lfArQESkHWMkEVEOfcfDU6dOQSaTISEhQZV29epVyGQyREVFAQAiIiKQlZWFOXPmoE6dOmjWrBk++ugjXL16FRkZGSXwKmjHpvVEVKYmTZqEX375Bfv374ejoyM++eQTXL58WdUPMzQ0FDExMTh58iRMTEwwbtw4PH78WLV/dnY2+vfvDycnJ5w/fx6JiYmqgK6LR48ewc/PDwEBAfjoo49gaWkJCwsL1KtXD9988w2aNWsGMzMzrFu3Do6OjvDx8SnhV4CISDvGSCKiHPqOh7rw8fGBkZERNm3ahNDQUCQnJ2Pr1q3w8/ODiYlJiZ4rL1bkiajMJCcnY+PGjdi2bRu6du0KANiyZQtq1qwJIKcP5sGDB3HhwgW0aNECALBx40Y0aNBAdYxjx47h5s2bOHz4MFxcXAAAc+fORY8ePXTKg7OzM6pUqQJLS0s4OztLjtu3b19YWVnByMgIjo6OOHToEKpWrVoiZSciKghjJBFRjvIQD3Xh4eGBI0eOYNCgQRg9ejSysrLQunVr/O9//yuxc2jDpvVEVGYiIyORnp6OVq1aqdLs7OxQr149AMCNGzdQpUoVyROe+vXrw9bWVvX3jRs34OrqqgrIANC6deti5UsIgTFjxsDR0RHh4eG4cOEC+vbti969e+PRo0fFOjYRka4YI4mIcpTXeJhXbGwsRo4ciZCQEFy8eBG//PILTE1NERgYCCFEiZ4rLz6RJ6JK78SJEzhw4ADi4+NhbW0NAFizZg2OHj2KLVu2YMqUKXrOIRGR/jBGElFlZGSU88w7d4U8b7/31atXw8bGBgsXLlSlbdu2Da6urjh//jx8fX1LL3+ldmQdnD59Gr1794aLi4vaoAMZGRn4+OOP0bhxY1hYWMDFxQXBwcGIiYnJ95gzZsyATCaTLPXr1y/lkhD9H3v3HdbU+fYB/BsQE4aggIAoCI66FcUB7o0WW7V1lKqgdbV1lqqVDnfFjVp366qj2qV2WlGxasWF2rfuiWgVNyCgrDzvH/ySEpJAAoEMvp/rOpfmzPtk3Jz7PM85h3RRs2ZN2NjY4MSJE8pxz549w9WrVwHknknNzs5GXFyccvqVK1dUbjJSr1493LlzR6UV6Pjx48WKKz09HcB/CVvBysoKcrm8WOsmItIVcyQRUS5TyIeVK1cGAJXlz507pzJPenq6Wm60trYGgBLPj0Yt5NPS0tCkSROsXLlSbVp6ejrOnDmDzz77DGfOnMGPP/6IK1eu4PXXXy90vQ0aNMD9+/eVw9GjR0sifCLSk4ODA4YPH47Jkyfj4MGDOH/+PIYOHapMgHXq1EGPHj0wevRonDhxAnFxcRgxYgRsbW2V6+jatSteeeUVhIWF4e+//8aRI0fwySefFCuuwMBAVKpUSblOxfOSb926heDg4GKtm4hIV8yRRES5TCEf1qpVC15eXpgxYwauXbuGX3/9FYsXL1aZJzg4GKdOncKsWbNw7do1nDlzBsOGDUP16tXRtGlTw7wZWhi1kO/ZsyfmzJmDvn37qk1zcnJCdHQ0BgwYgDp16iAgIAArVqxAXFwcEhISClxvuXLl4OHhoRxcXV1LaheISE8LFy5Eu3bt8Nprr6Fr165o27atyvVNGzduhKenJzp06IA33ngDo0aNgpubm3K6lZUVdu3ahRcvXqBly5YYMWIEPv/882LF5Orqir179yI1NRWdO3dG8+bNcfToUezZswdNmjQp1rqJiPTBHElElMvY+dDGxgbffPMNLl++jMaNG2P+/PmYM2eOyjydO3fG9u3bsXv3bjRt2hQ9evSAVCrF3r17VU4qlASJKOmr8HUkkUiwa9cu9OnTR+s8+/fvR/fu3ZGUlKS8Riu/GTNmYOHChXBycoJMJkNgYCAiIyPh7e2tcywpKSlwcnJCcnKy1u0QGdPLly9x69Yt+Pr6QiaTGTucYuvYsSP8/PywdOnSIq9DlxxiaAV9DpaaRyx1v8hyWFp+BMwzRzI/Ws5+kXmztJxojvkwP0PlR7O52d3Lly/x0UcfISQkpMCdatWqFTZt2oQ6derg/v37mDlzJtq1a4fz58+jQoUKGpfJyMhARkaG8nVKSorB4yciMkfMj0REmjE/EpExmcXj57KysjBgwAAIIbB69eoC5+3Zsyf69++Pxo0bIygoCL/99huSkpLw7bffal0mMjISTk5OysHLy8vQu0BEpWTu3LlwcHDQOBjyuaFlBfMjkWVhjjQc5kci82bu+dDku9YrivibN2/i4MGDcHFx0XvdLVq0QNeuXREZGalxuqYzql5eXuwaRSbL0rpJGdLTp0/x9OlTjdNsbW1RtWpVg22rLHQdZX4kc8P8WLDSypHMj+a7X2RZmBO1K81jxrzKRNd6RRF/7do1xMTEFKmIT01NxY0bNzBkyBCt80ilUkil0uKESkQmwtnZGc7OzsYOw2IwPxJZFuZIw2F+JDJv5p4Pjdq1PjU1FefOnVM+j+/WrVs4d+4cEhISkJWVhX79+uH06dPYtm0bcnJykJiYiMTERGRmZirX0aVLF6xYsUL5etKkSfjzzz8RHx+PY8eOoW/fvrC2tkZISEhp7x4RERERERGRwRm1Rf706dPo1KmT8nV4eDgAICwsDDNmzMBPP/0EAPDz81NZLiYmBh07dgQA3LhxA48fP1ZOu3v3LkJCQvDkyRNUrlwZbdu2xfHjx1G5cuWS3RkiI5DL5cYOoUzj+09kuvj7NC6+/0Smhb9J02Goz8KohXzHjh1R0CX6uly+Hx8fr/J6x44dxQ2LyOSVL18eVlZWuHfvHipXrozy5ctDIpEYO6wyQwiBzMxMPHr0CFZWVihfvryxQyKi/2F+NC7mRyLTwpxoOgydH036Gnki0szKygq+vr64f/8+7t27Z+xwyiw7Ozt4e3vDysosHgBCVCYwP5oG5kci08CcaHoMlR9ZyBOZqfLly8Pb2xvZ2dnIyckxdjhljrW1NcqVK8ez2kQmiPnRuJgfiUwLc6LpMGR+ZCFPZMYkEglsbGxgY2Nj7FCIiEwK8yMR0X+YEy0P+zsRERERERERmREW8kRERERERERmhIU8ERERERERkRlhIU9ERERERERkRljIExEREREREZkRFvJEREREREREZoSFPBEREREREZEZYSFPREREREREZEZYyBMRERERERGZERbyRERERERERGaEhTwRERERERGRGWEhT0RERERERGRGWMgTERERERERmREW8kRERERERERmhIU8ERERERERkRnRu5D/5ZdfMG3aNPz1118AgIMHD+LVV19Fjx49sG7dOoMHSERERERERET/0auQX7t2Lfr27YvffvsNr776KrZu3Yo+ffqgatWq8PHxwcSJE7Fs2bKSipWIiIiIiIiozNOrkF++fDlWrVqF06dPY/fu3Rg5ciTmzZuHL7/8EmvWrMGqVauwdu1andd3+PBhvPbaa/D09IREIsHu3btVpgshMG3aNFSpUgW2trbo2rUrrl27Vuh6V65cCR8fH8hkMrRq1QonT57UZzeJiIiIiIiITJZehfytW7cQFBQEAOjUqRNycnLQvn175fSOHTvi9u3bOq8vLS0NTZo0wcqVKzVOX7BgAZYvX441a9bgxIkTsLe3R1BQEF6+fKl1nTt37kR4eDimT5+OM2fOoEmTJggKCsLDhw91jouIiIiIiIjIVOlVyLu4uCgL9Xv37iE7OxsJCQnK6bdv34azs7PO6+vZsyfmzJmDvn37qk0TQmDp0qX49NNP0bt3bzRu3Bhff/017t27p9Zyn9eSJUswcuRIDBs2DPXr18eaNWtgZ2eHDRs26L6jRERERERERCaqnD4z9+7dG8OHD0dYWBh++uknhIaG4sMPP4SVlRUkEgkmT56M7t27GySwW7duITExEV27dlWOc3JyQqtWrRAbG4u33npLbZnMzEzExcUhIiJCOc7Kygpdu3ZFbGysQeIiIiIiIiIiMia9Cvn58+cjMzMTO3bsQOvWrfHFF19g+fLl6N27N7KystChQwdERkYaJLDExEQAgLu7u8p4d3d35bT8Hj9+jJycHI3LXL58Weu2MjIykJGRoXydkpJS1LCJiCwK8yMRkWbMj0RkTHp1rbe3t8e6devwzz//YO3atShfvjwmTZqE5ORkJCcnIyYmBm5ubiUVa4mJjIyEk5OTcvDy8jJ2SEREJoH5kYhIM+ZHIjImvZ8jr4lMJkOFChUMsSolDw8PAMCDBw9Uxj948EA5LT9XV1dYW1vrtQwAREREKE9GJCcn486dO8WMnojIMjA/EhFpxvxIRMakdyF///59bN26Fb/99hsyMzNVpqWlpWHWrFkGCczX1xceHh44cOCAclxKSgpOnDiBwMBAjcuUL18e/v7+KsvI5XIcOHBA6zIAIJVK4ejoqDIQERHzIxGRNsyPRGRMehXyp06dQv369TFmzBj069cPDRo0wIULF5TTU1NTMXPmTJ3Xl5qainPnzuHcuXMAcm9wd+7cOSQkJEAikWDixImYM2cOfvrpJ/zzzz8IDQ2Fp6cn+vTpo1xHly5dsGLFCuXr8PBwfPnll9i8eTMuXbqE9957D2lpaRg2bJg+u0pERERERERkkvS62d3HH3+Mvn374quvvkJaWho++ugjdOjQAdHR0WjatKneGz99+jQ6deqkfB0eHg4ACAsLw6ZNmzBlyhSkpaVh1KhRSEpKQtu2bbF3717IZDLlMjdu3MDjx4+VrwcOHIhHjx5h2rRpSExMhJ+fH/bu3at2AzwiIiIiIiIicyQRQghdZ3Z2dsbx48fxyiuvKMfNmzcPCxYswB9//AFvb294enoiJyenRIItLSkpKXByckJycjK7SRFRkVhqHrHU/SKi0mOpecRS94uISo8+eUSvFnkAePnypcrrqVOnoly5cujevTs2bNig7+qIiIiIiIiISA96FfINGzbEsWPH0LhxY5XxkyZNglwuR0hIiEGDIyIiIiIiIiJVet3sLjQ0FH/99ZfGaVOmTMHMmTPh7e1tkMCIiIiIiIiISJ1ehfyIESOwZcsWrdM/+ugj3Lp1q9hBEREREREREZFmej9HnoiIiIiIiIiMx6CF/KVLl1CjRg1DrpKIiIiIiIiI8jBoIZ+ZmYnbt28bcpVERERERERElIded60PDw8vcPqjR4+KFQwRERERERERFUyvQn7ZsmXw8/PT+nD61NRUgwRFRERERERERJrpVcjXqlULH3zwAQYPHqxx+rlz5+Dv72+QwIiIiIiIiIhInV7XyDdv3hxxcXFap0skEgghih0UEREREREREWmmV4v84sWLkZGRoXV6kyZNIJfLix0UEREREREREWmmVyHv4eFRUnEQERERERERkQ4M+vg5IiIiIiIiIipZRS7kg4ODcf/+fbX/ExEREREREVHJKXIhf/jwYbx48ULt/0RERERERERUcti1noiIiIiIiMiMsJAnIiIiIiIiMiMs5ImIiIiIiIjMCAt5IiIiIiIiIjNi8oW8j48PJBKJ2jBmzBiN82/atEltXplMVspRExEREREREZWMcsYOoDCnTp1CTk6O8vX58+fRrVs39O/fX+syjo6OuHLlivK1RCIp0RiJiIiIiIiISkuRC/nq1avDxsZG7f+GVrlyZZXX8+bNQ82aNdGhQwety0gkEnh4eJRIPERERERERETGVORC/vz58xr/X5IyMzOxdetWhIeHF9jKnpqaiurVq0Mul6NZs2aYO3cuGjRooHX+jIwMZGRkKF+npKQYNG4iInPF/EhEpBnzIxEZk8lfI5/X7t27kZSUhKFDh2qdp06dOtiwYQP27NmDrVu3Qi6Xo3Xr1rh7967WZSIjI+Hk5KQcvLy8SiB6IiLzw/xIRKQZ8yMRGZNECCH0XWjz5s1wdXVFcHAwAGDKlClYt24d6tevj2+++QbVq1c3eKAAEBQUhPLly+Pnn3/WeZmsrCzUq1cPISEhmD17tsZ5NJ1R9fLyQnJyMhwdHYsdNxGVPSkpKXBycjL7PML8SESGxvxIRKSZPvmxSC3yc+fOha2tLQAgNjYWK1euxIIFC+Dq6ooPPvigKKss1O3bt7F//36MGDFCr+VsbGzQtGlTXL9+Xes8UqkUjo6OKgMRETE/EhFpw/xIRMZUpGvk79y5g1q1agHI7e7+5ptvYtSoUWjTpg06duxoyPiUNm7cCDc3N2UvAF3l5OTgn3/+wauvvloicRERERERERGVpiK1yDs4OODJkycAgH379qFbt24AAJlMhhcvXhguuv+Ry+XYuHEjwsLCUK6c6rmH0NBQREREKF/PmjUL+/btw82bN3HmzBkMHjwYt2/f1rsln4iIiIiIiMgUFalFvlu3bhgxYgSaNm2Kq1evKlu7L1y4AB8fH0PGBwDYv38/EhIS8M4776hNS0hIgJXVf+cjnj17hpEjRyIxMRGVKlWCv78/jh07hvr16xs8LiIiIiIiIqLSVqRCfuXKlfj0009x584d/PDDD3BxcQEAxMXFISQkxKABAkD37t2h7Z58hw4dUnkdFRWFqKgog8dAREREREREZAqKVMhXrFgRK1asUBs/c+bMYgdERERERERERNoVqZAHgKSkJJw8eRIPHz6EXC5XjpdIJBgyZIhBgiMiIiIiIiIiVUUq5H/++WcMGjQIqampcHR0hEQiUU5jIU9ERERERERUcop01/oPP/wQ77zzDlJTU5GUlIRnz54ph6dPnxo6RiIiIiIiIiL6nyIV8v/++y/Gjx8POzs7Q8dDRERERERERAUoUiEfFBSE06dPGzoWIiIiIiIiIipEka6RDw4OxuTJk3Hx4kU0atQINjY2KtNff/11gwRHRERERERERKqKVMiPHDkSADBr1iy1aRKJBDk5OcWLioiIiIiIiIg0KlIhn/dxc0RERERERERUeop0jTwRERERERERGYfOLfLLly/HqFGjIJPJsHz58gLnHT9+fLEDIyIiIiIiIiJ1OhfyUVFRGDRoEGQyGaKiorTOJ5FIWMgTERERERERlRCdC/lbt25p/L8QAkBuAU9EREREREREJavI18ivX78eDRs2hEwmg0wmQ8OGDfHVV18ZMjYiIiIiIiIiyqdId62fNm0alixZgnHjxiEwMBAAEBsbiw8++AAJCQkaH0tHRERERERERMVXpEJ+9erV+PLLLxESEqIc9/rrr6Nx48YYN24cC3kiIiIiIiKiElKkrvVZWVlo3ry52nh/f39kZ2cXOygiIiIiIiIi0qxIhfyQIUOwevVqtfHr1q3DoEGDih0UEREREREREWmmc9f68PBw5f8lEgm++uor7Nu3DwEBAQCAEydOICEhAaGhoYaPkoiIiIiIiIgA6FHInz17VuW1v78/AODGjRsAAFdXV7i6uuLChQsGDI+IiIhIi5hIoFOEsaMgIiIqdToX8jExMSUZh0YzZszAzJkzVcbVqVMHly9f1rrMd999h88++wzx8fGoXbs25s+fj1dffbWkQyUiIiJDi4nM/ZfFOhERkYoiP0e+tDRo0AD3799XDkePHtU677FjxxASEoLhw4fj7Nmz6NOnD/r06YPz58+XYsREREREREREJcfkC/ly5crBw8NDObi6umqdd9myZejRowcmT56MevXqYfbs2WjWrBlWrFhRihETERERERERlRyTL+SvXbsGT09P1KhRA4MGDUJCQoLWeWNjY9G1a1eVcUFBQYiNjS1wGxkZGUhJSVEZiIiI+ZEMICbyvy7yRBaE+ZGIjMmkC/lWrVph06ZN2Lt3L1avXo1bt26hXbt2eP78ucb5ExMT4e7urjLO3d0diYmJBW4nMjISTk5OysHLy8tg+0BlDA9WycIwP1KhWKhTGcX8SETGZNKFfM+ePdG/f380btwYQUFB+O2335CUlIRvv/3WoNuJiIhAcnKycrhz545B109EZK6YH6lE8SQAmTHmRyIyJp3vWm8KKlasiFdeeQXXr1/XON3DwwMPHjxQGffgwQN4eHgUuF6pVAqpVGqwOImU+GgkMnPMj0REmjE/EpExmXSLfH6pqam4ceMGqlSponF6YGAgDhw4oDIuOjoagYGBpREelVX6tCix5YmISDu20BMR5WIupEKYdCE/adIk/Pnnn4iPj8exY8fQt29fWFtbIyQkBAAQGhqKiIj/WjsnTJiAvXv3YvHixbh8+TJmzJiB06dPY+zYscbaBSrjYm8+QVT0Ve0zMEkTURkVFX0VsTefGDsMIiKTw/xIujDpQv7u3bsICQlBnTp1MGDAALi4uOD48eOoXLkyACAhIQH3799Xzt+6dWts374d69atQ5MmTfD9999j9+7daNiwobF2gSxdQYV4nmkFFvNERGVJvlb3Qk94EhGVUbHrJyF2/SRjh0EmyqSvkd+xY0eB0w8dOqQ2rn///ujfv38JRUSkv4CEdQCAqOhRCEh4gsBORg6IiMgERUVfzc2RNVyMHQoRkUlRFPOBwxcZORIyJSZdyBOZtAJa4xUHpHqthzfFI6IyQNld1Nu4cRARmZrc48d1CDB2IGQWWMgTGVDszSc4nq25i6iiZZ6IqCxSdJ9XHKAyJxIR5VK0uLOAJ32Y9DXyRJYoKvpq7gGtphZ93vyOiMqggIR1ysKeN3giItIsdv0k3lOElFjIExEREREREZkRdq0nKoa8LUfHs68iALp3F1Usyxs7EZElUnalT9D/mnjFsh/wKIWILJTienh9BSSsQ+x64Lj3KHzQ7ZUSiIzMBVvkiYiIiIiISktMZLHvExKQsI6XZJZxLOSJjCz25hNeE0pEpAHzIxGRdrE3n/A582UYO60RmaqYSD6SjogsBu9ST0QEtqKTwbBFnkhXeRJvVPRVg7cSlcQ6iYhKm/LJHCa+TiIiYyiJnkbMj2UTC3kiIiIiIiIzxevlyyZ2rScqTL6W+OLSq3spu9cTkRlhqxARkWa8lp0MjYU8ERERGRyviSciIio5LOSp7FG0sJtoSzefn0xEpJkyP/LZyUREKmJvPgFuTkJgDReTPcYlw2KpQERERAZTEi3xinUe9x5l8HUTEZUoXrtOJYSFPJEOlHcX9TbCxk28BwERUezNJziezevjiYjy4xOJqKSwkKeyrbCbyRnxLKoi8QfWcNF9IRb9RGQkhmyJL2xdvASJiEgzZRf74YuMHQqVMD5+jkgbDUW8Sd68KSaS3baIiIiITA2Pz6gEsZAnKoTJdIniHwMiMjFR0VdLNUcGJKwzzROqRET5lHZ+pLKHndKITEz+g9QidbEnIioDFNfm8y72RESqFM+tZxd7y8UWeSIDYSsRERERERGVBpMu5CMjI9GiRQtUqFABbm5u6NOnD65cuVLgMps2bYJEIlEZZDJZKUVMFsGUrzk31biIiIiIKFdMpOk08JjycS0Vi0l3rf/zzz8xZswYtGjRAtnZ2fj444/RvXt3XLx4Efb29lqXc3R0VCn4JRJJaYRLFsbUrmtSdrHvZORAiKjMU9w13lQo72LPLvZEZGRR0VcRkGA6x5A8frRcJl3I7927V+X1pk2b4Obmhri4OLRv317rchKJBB4eHiUdHpmbwh41p5iHiIiIiEhfMZEmVcSTZTPprvX5JScnAwCcnZ0LnC81NRXVq1eHl5cXevfujQsXLhQ4f0ZGBlJSUlQGIpNX2EkHnpQgA2B+JG14B3kq65gfyazwuNDimE0hL5fLMXHiRLRp0wYNGzbUOl+dOnWwYcMG7NmzB1u3boVcLkfr1q1x9+5drctERkbCyclJOXh5eZXELpCZiL35xOS61edlal1aybIxP1JeUdFXTToHmXp8ZFmYHykvU3/cXOzNJ8yPFsZsCvkxY8bg/Pnz2LFjR4HzBQYGIjQ0FH5+fujQoQN+/PFHVK5cGWvXrtW6TEREBJKTk5XDnTt3DB0+EZFZYn4kItKM+ZHyYg8lKm0mfY28wtixY/HLL7/g8OHDqFatml7L2tjYoGnTprh+/brWeaRSKaRSaXHDJHOl6GpU2PXzRGUQ8yPlZwoHq6YQAxHzIxEZk0kX8kIIjBs3Drt27cKhQ4fg6+ur9zpycnLwzz//4NVXXy2BCMmSmNpdRnXC652IqBSYcnfM/EX9ce9RRoqEiMoiRX4MMHIcughIWAfEuLDxykKYdCE/ZswYbN++HXv27EGFChWQmJgIAHBycoKtrS0AIDQ0FFWrVkVkZG5BM2vWLAQEBKBWrVpISkrCwoULcfv2bYwYMcJo+0GkC31amBQnHQJruJRgREREqsylJZyPoyOi0mIueVEh9uYTHM++yvxoAUy6kF+9ejUAoGPHjirjN27ciKFDhwIAEhISYGX136X+z549w8iRI5GYmIhKlSrB398fx44dQ/369UsrbDIzyhuTeBs3DiIio8t3qZEpt8QTERmTObXEk2Uy6UJeCFHoPIcOHVJ5HRUVhaioqBKKiMj8zrwSERWqLFymk/9+KLw/ChEVgzkfD7KLvWUwm7vWE+mtDByY6vWovDLwfhBRyTDXZ8azRwERkWZ8HJ35M+kWeSIiIjIecyzeFTHzpndERAXLzZeLjB0GFRELeSIiIrI4/52E4EEqERFZHhbyVGaZ5ePmiIhKAW/iRESkXez6ScYOgYiFPJU9lniXeuWjRPiLJqJisMT8qHwUHfMjERWTJRbwin0KHM7eS+aGf9bIssRE8g6cRESFKeSO7eZ4bbw2yn2p4aJ5Bt69noiIzBDvWk9kQXS+iz3vYE9EZYxeT/kgIipjeAd788MWeSIiIiIiIm3KQAMIny1vfljIU5mhuI6cN28iIlLH1moiIs2YH8kUsWs9kQWKir7KPzpERBpERV9lF1IiIg1ibz6xyBv6WSq2yJPF42OUiIi046M4iYg0y82PlnPzT7IsbJEn8xcTWSauXSqKQlue+N4RlQ38ravRePM7vk9ERIhdP4kt82aALfJERERERER5xUSytxKZNBbyZNF4HWQuRdfZwE7GjoSITIXiBqBlnaJVnvmRiAAAMZG8z9D/KFrlA4cvMnIkpAm71pP5YvdHIiLt2E28+PgeEhExD5ooFvJkkXjXds14zTwRMT9qxveFiGLXT2Ie0CD25hP2cjVB7FpPFoVdRYmINGN+JCLSjE84KlxAwjogxgXoFGHsUOh/2CJP5oMtxQaj09nmvO8333si88GeNcXClieisicgYR0fM6cD5XPm+TfGJLBFnkxbTGSBZ/7yPv/4ePZVnknVg/IGeDVcjB0KEZUAxQm749l8TnxRaMyRioNXtkgRmTU+H754Ym8+AW5O4k3wjIwt8kRlXLFan9jyR2R8/B2WqAJ7MPG9JzI/MZEs4g2Ez5s3LrMo5FeuXAkfHx/IZDK0atUKJ0+eLHD+7777DnXr1oVMJkOjRo3w22+/lVKkVCR6HAQpbtbGmxIZHt9TIvOWNzfyt2xYhd4olIhMnqLoZH40PBb0xmHyhfzOnTsRHh6O6dOn48yZM2jSpAmCgoLw8OFDjfMfO3YMISEhGD58OM6ePYs+ffqgT58+OH/+fClHTobEIrP0KFroeZ0okYnI3+qroRWY+bF0KE6SqBX2mj4jIjIJUdFXWWSWEuXJEr7fpcLkr5FfsmQJRo4ciWHDhgEA1qxZg19//RUbNmzA1KlT1eZftmwZevTogcmTJwMAZs+ejejoaKxYsQJr1qwp1dhJg0KueVdQ3j00gXdZNjbldaKd9FhIx8+ZiPLR8RrsvHeg5/XvxqM4gaLXvUZ4nT1Ricp//Tvvn2QcimI+sAbvdF9STLqQz8zMRFxcHCIi/vvwrays0LVrV8TGxmpcJjY2FuHh4SrjgoKCsHv3bq3bycjIQEZGhvJ1cnIyACAlJaUY0ZdhhxcD7T/UPC3tJfC/93XlwesAgBZ37+FU8hnNs7/IwMu0VLX/532d9iL3s1P8X9/5FfK/NlV59y//eG3vhWL+/O9N3vnzrlPTexm5W/0zanH3HgAoP78xnWv9b2P/fc4qDi/O/Vfb98OCKPKHEMLIkRQP86OBFfYbSHsJAFiZ5/eW/3emeK3pd5v3tUJhv3VNy1gyQ7xP+V/vv6D+GeX/u6aSHwHNObKMYH6k4lAcPwJAi7sb1aY3ApBWivFQwfZfuAdcGFfgPKeqDfsvR5ZxeuVHYcL+/fdfAUAcO3ZMZfzkyZNFy5YtNS5jY2Mjtm/frjJu5cqVws3NTet2pk+fLgBw4MCBg8GHO3fuFD8ZGhHzIwcOHEpqYH7kwIEDB82DLvnRpFvkS0tERIRKK75cLsfTp0/h4uICiURixMgKlpKSAi8vL9y5cweOjo7GDscgLG2fLG1/AO6TroQQeP78OTw9PQ2yPmNhfjQd3CfTZ2n7AzA/FsRc8yNged9VS9sfgPtkDoydH026kHd1dYW1tTUePHigMv7Bgwfw8PDQuIyHh4de8wOAVCqFVCpVGVexYsWiBW0Ejo6OFvFjyMvS9snS9gfgPunCycnJYOsyFuZH08N9Mn2Wtj8A86Mm5p4fAcv7rlra/gDcJ3NgrPxo0netL1++PPz9/XHgwAHlOLlcjgMHDiAwMFDjMoGBgSrzA0B0dLTW+YmIiIiIiIjMiUm3yANAeHg4wsLC0Lx5c7Rs2RJLly5FWlqa8i72oaGhqFq1KiIjc+8CO2HCBHTo0AGLFy9GcHAwduzYgdOnT2PdunUFbYaIiIiIiIjILJh8IT9w4EA8evQI06ZNQ2JiIvz8/LB37164u7sDABISEmBl9V/HgtatW2P79u349NNP8fHHH6N27drYvXs3GjZsaKxdKDFSqRTTp09X69ZlzixtnyxtfwDuE5kHS/xMuU+mz9L2B7DMfSLL+1wtbX8A7pM5MPb+SIQw82d/EBEREREREZUhJn2NPBERERERERGpYiFPREREREREZEZYyBMRERERERGZERbyRERERERERGaEhTwRERERERGRGWEhT0RERERERGRGWMgTERERERERmREW8kRERERERERmhIU8ERERERERkRlhIU9ERERERERkRljIExEREREREZkRFvJkUU6ePIny5cvj9u3bxg6lWNasWQNvb29kZGQYOxQiKgNKK3e+9dZbGDBgQIlug4gsQ8eOHdGxY0djh0Fkssp0IX/hwgUMHjwYVatWhVQqhaenJwYPHoyLFy+qzbtp0yZIJBLlIJPJ4OnpiaCgICxfvhzPnz/Xup2//voLffv2hbu7O6RSKXx8fPDuu+/izp07OsV56NAhlW3nH3bs2KFxuaSkJLi5uUEikeD777/Xuj9Hjx5VW1YIAS8vL0gkEvTq1Utl2gcffIBmzZrB2dkZdnZ2qFevHmbMmIHU1NQC37O8w9SpU5Xz+fj4QCKRYNy4cVr3PX/82nzyyScICQlB9erVdZrfVA0dOhSZmZlYu3atsUMpVZmZmZg7dy7q1q0LmUwGd3d3BAcH4+7du4Uuq+27Nm/ePIPHmZSUhFGjRqFy5cqwt7dHp06dcObMGY3zPn/+HFOmTIGvry+kUimqVq2Kfv36IT093eBxlRbmTubOvO7du4fBgwejTp06qFChAipWrIiWLVti8+bNEEKozPvRRx/hhx9+wN9//633dszZgwcPMHr0aFStWhUymQw+Pj4YPnx4oculpqZi+vTp6NGjB5ydnSGRSLBp06ZCl8vKykL9+vUhkUiwaNEiA+yBuvXr16NevXqQyWSoXbs2vvjiC63z7ty5E4GBgbC3t0fFihXRunVrHDx4sETiKqvMJS+Xlu3bt2Pp0qU6zy+Xy7FmzRr4+fnBwcEB7u7u6NmzJ44dO1ZyQZqQCxcuoH///qhRowbs7Ozg6uqK9u3b4+eff9Z5HbocGz158gQLFy5E+/btUblyZVSsWBEBAQHYuXOnoXcJQO7numDBAvj6+kImk6Fx48b45ptvtM67evVq+Pn5wdbWFi4uLujcubNJ/70qZ+wAjOXHH39ESEgInJ2dMXz4cPj6+iI+Ph7r16/H999/j507d6J3795qy82aNQu+vr7IyspCYmIiDh06hIkTJ2LJkiX46aef0LhxY5X5v/jiC0yYMAE1atTAuHHjUKVKFVy6dAlfffUVdu7cid9//x0BAQE6xTx+/Hi0aNFCbXxgYKDG+adNm1ZosSCTybB9+3a0bdtWZfyff/6Ju3fvQiqVqi1z6tQptGvXDsOGDYNMJsPZs2cxb9487N+/H4cPH4aVler5IcV7llfDhg3V1vvll18iIiICnp6eBcaszblz57B//36LSLoymQxhYWFYsmQJxo0bB4lEYuyQSlxWVhaCg4Nx7NgxjBw5Eo0bN8azZ89w4sQJJCcno1q1aoWuo1u3bggNDVUZ17RpU4PGKZfLERwcjL///huTJ0+Gq6srVq1ahY4dOyIuLg61a9dWzpucnIwOHTrg7t27GDVqFGrVqoVHjx7hyJEjyMjIgJ2dnUFjKw3MnbmYO//z+PFj3L17F/369YO3tzeysrIQHR2NoUOH4sqVK5g7d65y3qZNm6J58+ZYvHgxvv766yJtz9zcuXMHbdq0AQC8++67qFq1Ku7du4eTJ08Wuuzjx48xa9YseHt7o0mTJjh06JBO2/ziiy+QkJBQnLALtHbtWrz77rt48803ER4ejiNHjmD8+PFIT0/HRx99pDLvjBkzMGvWLPTr1w9Dhw5FVlYWzp8/j3///bfE4itrzDEv62Lfvn1FXnb79u04f/48Jk6cqNP8kydPxpIlSzB48GC8//77SEpKwtq1a9GhQwf89ddfaNmyZZFjMQe3b9/G8+fPERYWBk9PT6Snp+OHH37A66+/jrVr12LUqFEFLq/rsVFsbCw++eQTvPrqq/j0009Rrlw5/PDDD3jrrbdw8eJFzJw506D79cknn2DevHkYOXIkWrRogT179uDtt9+GRCLBW2+9pTLvO++8g23btiE0NBRjx45FWloazp49i4cPHxo0JoMSZdD169eFnZ2dqFu3rnj48KHKtEePHom6desKBwcHcfPmTeX4jRs3CgDi1KlTaus7cOCAsLW1FdWrVxfp6enK8UePHhVWVlaiXbt2Ii0tTS0Gd3d34enpKZ49e1ZgvDExMQKA+O6773Tex3/++UeUK1dOzJo1S+Oyiv154403hKurq8jKylKZPnLkSOHv7y+qV68ugoODC93eokWLBAARGxurtg1N71le1atXFw0aNBDlypUT48aNU5mmz76PHz9eeHt7C7lcXui85uD06dMCgDhw4ICxQ1FKTU3VOi3/d1xf8+fPFzY2NuLEiRNFWh6AGDNmTLFi0MXOnTvVvpMPHz4UFStWFCEhISrzvvfee6JixYoqucScMXcyd+qjV69ewt7eXmRnZ6uMX7RokbC3txfPnz836PaKQ1tuy8nJES9evCjWunv27Cl8fX3F48eP9V725cuX4v79+0IIIU6dOiUAiI0bNxa4zIMHD4STk5PyO7xw4cKihK1Venq6cHFxUft+Dxo0SNjb24unT58qx8XGxgqJRCKWLFli0BjoP+aWl0tLcHCwqF69uk7zZmVlCVtbW9GvXz+V8Tdv3hQAxPjx40sgQv3J5XKVzySvFy9eiJycHINuLzs7WzRp0kTUqVOn0Hl1PTa6efOmiI+PV1lWLpeLzp07C6lUWuBxpr7u3r0rbGxsVI4N5XK5aNeunahWrZrK3yZF/D/++KPBtl8aymTX+oULFyI9PR3r1q1D5cqVVaa5urpi7dq1SE1NxcKFC3VaX+fOnfHZZ5/h9u3b2Lp1q3L87NmzIZFIsHnzZrWWt5o1a2LBggW4d+8e1q1bV/ydymfChAno27cv2rVrV+B8ISEhePLkCaKjo5XjMjMz8f333+Ptt9/WeXs+Pj4AcrvVFIWPjw9CQ0Px5Zdf4t69e0Vax+7du9G5c2e11uvTp08jKCgIrq6usLW1ha+vL9555x2VeRYtWoTWrVvDxcUFtra28Pf319glVSKRYOzYsfjuu+9Qv3592NraIjAwEP/88w+A3FaKWrVqQSaToWPHjoiPj1dbx4kTJ9CjRw84OTnBzs5OebY3P39/fzg7O2PPnj1Fej8KcvnyZfTr1w/Ozs6QyWRo3rw5fvrpJ5V5FF3v/vzzT7z//vtwc3NTtop37NgRDRs2RFxcHNq3bw87Ozt8/PHHRY5HLpdj2bJl6Nu3L1q2bIns7Owidz1/8eIFXr58WeA8un4Gmnz//fdwd3fHG2+8oRxXuXJlDBgwAHv27FHe1yApKQkbN27EqFGj4Ovri8zMTLO/5wFz53/KQu708fFBr169sG/fPvj5+UEmk6F+/fr48ccfdY4tPT0dmZmZKuO7deuGtLQ0lffOUH7//Xe0a9cO9vb2qFChAoKDg3HhwgWVeYYOHQoHBwfcuHEDr776KipUqIBBgwYB+C/Hb9u2DQ0aNIBUKsXevXuLHM/ly5fx+++/Y/LkyXBxccHLly+RlZWl8/JSqRQeHh56bXPq1KmoU6cOBg8erHWepKQkTJw4EV5eXpBKpahVqxbmz58PuVxe6PpjYmLw5MkTvP/++yrjx4wZg7S0NPz666/KcUuXLoWHhwcmTJgAIYTaZSRUfOaWl2fMmKGxl6HimCPvcVP+a+QVlwx9++23+Pzzz1GtWjXIZDJ06dIF169fV1nu119/xe3bt5WXDyhyrSZZWVl48eIF3N3dVca7ubnBysoKtra2Be6TvuRyOZYuXYoGDRooLyMcPXo0nj17pjKfIgf/8ccfaN68OWxtbbF27Vrl+7Bjxw58+umnqFq1Kuzs7JCSkmLQOK2treHl5aXT3yddj418fX3VLuGSSCTo06cPMjIycPPmTZVp//77L9555x3lpRwNGjTAhg0bdIp/z549yMrKUslVEokE7733Hu7evYvY2Fjl+CVLlqBly5bo27cv5HI50tLSdNqGsZXJQv7nn3+Gj4+P1gO19u3bw8fHR6/rQoYMGQLgv25A6enpOHDgANq1a6fWNVJh4MCBkEqlOm/n+fPnePz4sdog8l2D+N133+HYsWNYsGBBoev08fFBYGCgyvUiv//+O5KTk9W6nOSVnZ2Nx48f4969e9i3bx8+/fRTVKhQQWPXo+TkZLWYNfnkk0+QnZ1dpGua//33XyQkJKBZs2Yq4x8+fIju3bsjPj4eU6dOxRdffIFBgwbh+PHjKvMtW7YMTZs2xaxZszB37lyUK1cO/fv3VzkgUThy5Ag+/PBDhIWFYcaMGbh06RJ69eqFlStXYvny5Xj//fcxefJkxMbGqp0wOHjwINq3b4+UlBRMnz4dc+fORVJSEjp37qyxm2WzZs10LjB1deHCBQQEBODSpUuYOnUqFi9eDHt7e/Tp0we7du1Sm//999/HxYsXMW3aNJXrc588eYKePXvCz88PS5cuRadOnQDkXtOp6Xuaf0hOTlau6+LFi7h37x4aN26MUaNGwd7eHvb29mjcuDFiYmJ03rdNmzbB3t4etra2qF+/PrZv3642j76fQX5nz55Fs2bN1LpBt2zZEunp6bh69SoA4OjRo3j58iVq1aqFfv36wc7ODra2tmjTpg3OnTun8z6ZEubO/1h67lS4du0aBg4ciJ49eyIyMlKZGzUV4S9evMDjx48RHx+PzZs3Y+PGjQgMDFQ7CFacBDV0btuyZQuCg4Ph4OCA+fPn47PPPsPFixfRtm1btZOq2dnZCAoKgpubGxYtWoQ333xTOe3gwYP44IMPMHDgQCxbtkxZADx79kyn3Jb3JOT+/fsBAO7u7ujSpQtsbW1ha2uLnj17ajzRW1wnT57E5s2bsXTpUq2XZKWnp6NDhw7YunUrQkNDsXz5crRp0wYREREIDw8vdBtnz54FADRv3lxlvL+/P6ysrJTTAeDAgQNo0aIFli9fjsqVK6NChQqoUqUKVqxYUYy9pLzMNS8Xx7x587Br1y5MmjQJEREROH78uPJkHJCbE/38/ODq6ootW7Zgy5YtBV4vb2tri1atWmHTpk3Ytm0bEhIS8H//938YOnQoKlWqVGi3cn2NHj0akydPRps2bbBs2TIMGzYM27ZtQ1BQkNqJvitXriAkJATdunXDsmXL4Ofnp5w2e/Zs/Prrr5g0aRLmzp2L8uXLQy6X65SnHj9+rPGkYlpaGh4/fowbN24gKioKv//+O7p06VLoPul6bKRNYmIigNyTTwoPHjxAQEAA9u/fj7Fjx2LZsmWoVasWhg8frtP9D86ePQt7e3vUq1dPLSbFdABISUnByZMn0aJFC3z88cdwcnKCg4MDatSogW+//bbQ7RiVkXsElLqkpCQBQPTu3bvA+V5//XUBQKSkpAghdOvq6OTkJJo2bSqEEOLcuXMCgJgwYUKB22ncuLFwdnYucB5FF0ltg6LbnRC5Xd68vb1FRESEyrLauoeeOnVKrFixQlSoUEHZXad///6iU6dOQgihtXtobGysSgx16tQRMTExGrehacgr7zaGDRsmZDKZuHfvXoHx57d//34BQPz8888q43ft2qVTF9X8XZUyMzNFw4YNRefOnVXGAxBSqVTcunVLOW7t2rUCgPDw8FB+X4QQIiIiQgBQziuXy0Xt2rVFUFCQShfW9PR04evrK7p166YW16hRo4StrW2BseurS5cuolGjRuLly5fKcXK5XLRu3VrUrl1bOU7x+bVt21ata2yHDh0EALFmzRq19YeFhRX4fVUMHTp0UC7z448/CgDCxcVF1K5dW2zcuFFs3LhR1K5dW5QvX178/fffhe5X69atxdKlS8WePXvE6tWrRcOGDQUAsWrVKpX91PczyM/e3l688847auN//fVXAUDs3btXCCHEkiVLlPvUsmVLsW3bNrFq1Srh7u4uKlWqpPyOmwvmTqG2P5acOxXrByB++OEH5bjk5GRRpUoV5eeVV2RkpEqsXbp0EQkJCRq3+8orr4iePXsWGJs+nj9/LipWrChGjhypMj4xMVE4OTmpjFfkqKlTp6qtB4CwsrISFy5cUJumeD8KG6ZPn65cZvz48co80KNHD7Fz506xcOFC4eDgIGrWrKnXJUmFda2Xy+WiZcuWym6st27d0ti1fvbs2cLe3l5cvXpVZfzUqVOFtbW11s9MYcyYMcLa2lrjtMqVK4u33npLCCHE06dPlfvu4OAgFi5cKHbu3Cl69Oih9e8H6ccc8/L06dPVclnemPIeX3Xo0EHlWEGR1+rVqycyMjKU45ctWyYAiH/++Uc5Tp+u9UIIce3aNdGsWTOV33KNGjXE5cuXdV6HLo4cOSIAiG3btqmM37t3r9p4Rc5RHFcoKN6HGjVqqB2/Kn73ugz5//YIIcTo0aOV062srES/fv1ULpfRRtdjI02ePHki3NzcRLt27VTGDx8+XFSpUkXtsqS33npLODk5ab3MQCE4OFjUqFFDbXxaWprK34AzZ84oc5W7u7tYtWqV2LZtm2jZsqWQSCTi999/L3A7xlTmbnanuBNnhQoVCpxPMf358+eFzqvg4OCgXL8+2yno7qB5TZs2TeMZV2dnZ+X/582bh6ysLL26OQ8YMAATJ07EL7/8gh49euCXX37B8uXLC1ymfv36iI6ORlpaGo4dO4b9+/dr7TK3cuVKvPLKKzrF8umnn2LLli2YN28eli1bpvM+PHnyBABQqVIllfEVK1YEAPzyyy9o0qQJbGxsNC6ft8Xo2bNnyMnJQbt27TTe2bJLly4qXbRatWoFAHjzzTdVPm/F+Js3b8LHxwfnzp3DtWvX8OmnnyrjzbvOLVu2QC6Xq5zNrFSpEl68eIH09HSD3Bjt6dOnOHjwIGbNmoXnz5+rfPeCgoIwffp0/Pvvv6hatapy/MiRI2Ftba22LqlUimHDhqmNnzJlSoFdOhXyflaK787z589x9uxZeHl5Acjt4lerVi0sWLBApYufJvlb99555x34+/vj448/xtChQ2Fra1ukzyC/Fy9eaLyRmUwmU07Pu08SiQQHDhyAg4MDgNybfQUGBmLlypWYM2dOgftkSpg71Vly7lTw9PRE3759la8dHR0RGhqK+fPnIzExUaXbd0hICJo3b45Hjx7hl19+wYMHD5S/h/wqVaqktYdBUURHRyMpKQkhISEq67W2tkarVq009ux57733NK6rQ4cOqF+/vtr4bdu2ad2fvGrUqKH8v+Kz9fDwwK+//qrMLdWqVUNISAi2b9+OESNGFLpOXWzatAn//PNPoU8q+O6779CuXTu1z6Br166YN28eDh8+rNK6md+LFy9Qvnx5jdNkMplaDnzy5Al27NiBgQMHAgD69euHRo0aYc6cORg9erRe+0iqzDkvF8ewYcNUvoOK/H7z5k2NNwTVRYUKFdCgQQMEBgaiS5cuSExMxLx589CnTx8cOXJEpaW4OL777js4OTmhW7duKr8/f39/ODg4ICYmRuXyLF9fXwQFBWlcV1hYmFqPJw8PD50vW2rSpInauIkTJ6Jfv364d+8evv32W+Tk5KhdHqWJrsdG+cnlcgwaNAhJSUkqT74QQuCHH37AgAEDIIRQea+CgoKwY8cOnDlzRnkj0eLElDdXHT9+XHn8/vrrr8PX1xdz5sxBjx49Ctx/YylzhXzeZFaQ58+fQyKR6PXDTU1NhZubm97bUSxTmEaNGqFr165ap8fHx2PhwoVYuXKlsmjQReXKldG1a1ds374d6enpyMnJQb9+/QpcxtHRURlL7969sX37dvTu3RtnzpxRSwwtW7ZU64KnTY0aNTBkyBCsW7dOpRu3rkS+rrIdOnTAm2++iZkzZyIqKgodO3ZEnz598Pbbb6v8uH/55RfMmTMH586dU7mOWVPXRG9vb5XXTk5OAKAsPvOPV1zzdO3aNQC5iVeb5ORklQNqxf4UdNf61NRUlULA2tpa7To5hevXr0MIgc8++wyfffaZxnkePnyoUshr60ZXtWpVjQdz9evX13gQXBDFH6I2bdqovI/e3t5o27Ztke6mXb58eYwdOxbvvvsu4uLi0LZtW50/A3t7ezx9+lRlfOXKlWFtbQ1bW1uN17orrstX7Ivi39dee03l9xgQEABfX1+ze7oCc6c6S86dCrVq1VLLP4qTC/Hx8SqFfPXq1ZXXPoaEhGDUqFHo2rUrrly5onawKYQo9GkcT58+VTmAtLW1VebV/BS/7c6dO2uc7ujoqPK6XLlyWp+EoS3nFXTAqI1ivwcMGKBygrB///4YMmQIjh07ZpBCPiUlBREREZg8ebLa36L8rl27hv/7v//T+ndCcYfmR48eIScnRznewcEBDg4OsLW11Xpg//LlS7UcaGNjo/K7sLKywsCBAzF9+nQkJCSo/U0l3ZlzXi6O/N8ZxXFT/mvMdZWdnY2uXbuiY8eOKsVk165d0aBBAyxcuBDz58/XuryiW7iCk5OT1uvqr127huTkZK3vU/47pGvLR9qmyWSyAv/eFaZu3bqoW7cuACA0NBTdu3fHa6+9hhMnThSYs3U9Nspv3Lhx2Lt3L77++muVv4GPHj1CUlIS1q1bp/W+C4r3Stv7r+/xmq+vr7KIB3Jz3muvvYatW7ciOzsb5cqZXtlsehGVMCcnJ3h6euL//u//Cpzv//7v/1CtWjWtZ53zu3v3LpKTk1GrVi0AQO3atVGuXLkCt5ORkYErV64Y7JEW06ZNQ9WqVVVusqb4cj969Ajx8fHw9vbW2Nr49ttvY+TIkUhMTETPnj2VLdm6euONNzBkyBDs2LFD4xk+fXzyySfYsmUL5s+fjz59+ui0jIuLCwD1JK54jvLx48fx888/448//sA777yDxYsX4/jx43BwcMCRI0fw+uuvo3379li1ahWqVKkCGxsbbNy4UeM11ppapwsarzhAVtxEaOHChSrXOOWVv4h49uyZ8tpqbRYtWqTyuI7q1atrvfZSEcOkSZO0nuFVfIcVtG1b2/jk5GSdWq3Kly+vbBFVPDYr/41mgNybzeS95lIfigNaRVGu62fw119/Ka/5V7h16xZ8fHxQpUoV3L9/X205xTjFvhS2T0U94DAW5s6ylTsNoV+/fvjyyy9x+PBhtXzz7NkzlUc1avLGG2/gzz//VL4OCwvT+gx1xW97y5YtGm8Ol/8ATCqVau15oy235S9stVEUvID2PGBtbQ0XFxeDve+LFi1CZmYmBg4cqPwO3717F0Duex0fHw9PT0/lNbTdunXDlClTNK5LcaKmRYsWuH37tnL89OnTMWPGDFSpUgU5OTl4+PChSjGSmZmJJ0+eKPdZcTPVihUrqv19VCz37NkzFvLFYI55WVsxqMtvS6Gw4y19HT58GOfPn8eSJUtUxteuXRv16tUr9H4eVapUUXm9ceNGDB06VOO8crkcbm5u2LZtm8bp+U+wFXT8p2laTk4OHj16VGC8Cs7OzoV+J/r164fRo0fj6tWrqFOnjtb5dD02ymvmzJlYtWoV5s2bp7wvg4Iipw8ePFhr44vi8Yja3v8qVaogJiZG7cSxvsdrWVlZSEtL03oi2ZjKXCEP5LaQrV27FkePHlV7BjCQezOz+Ph4nW76orBlyxYAUB6s2NnZoUuXLti/fz9u376tdodGAPj222+RkZGB/v37F3FPVCUkJOD69esq3foUFHdsfPbsmcYDzb59+2L06NE4fvw4du7cqfe2MzIyIJfLVW5gVlQ1a9bE4MGDsXbtWpUzYwVRnD28deuWxukBAQEICAjA559/ju3bt2PQoEHYsWMHRowYgR9++AEymQx//PGHSiv9xo0bi70vedWsWROAaotcYW7duqV2k478QkNDVb7HBSV9xXfDxsamWGdsCzJhwgRs3ry50Pk6dOigfCZyo0aNYGNjo/G5wvfu3dPaclQYxd1PFcvr+hk0adJErWuaojjw8/PDkSNH1LrgnzhxAnZ2dsqDYH9/fwDQuk+K76w5Ye6sqDbd0nOnohdP3oMgxU2LCroLNPBft8X8+5adnY07d+7g9ddfL3D5xYsXqxS6mg4EFRS/bTc3txLLbfkLW20UBS+gPQ9kZmbi8ePHRc5t+SUkJODZs2do0KCB2rS5c+di7ty5OHv2LPz8/FCzZk2kpqYW+j7lv5RA8ftQnAQ9ffo0Xn31VeX006dPQy6XK6dbWVnBz88Pp06dQmZmpkrBoHjCgqH2vywzt7ysaD1PSkpSyam6/Lb0UViPn7wePHgAQPPJhKysLGRnZxe4fP7jBU2/Q4WaNWti//79aNOmjcHvhg8Ad+7cKbAVP6+YmBiVpwJooi2P56frsZHCypUrMWPGDEycOBEfffSR2voUN8fMyckpNFdpe//9/Pzw1Vdf4dKlSyo9RU+cOKGcDuT+bfHw8NB6vCaTyXS+JKXUGenafKO6du2asLOzE/Xr11e7gcKTJ09E/fr1haOjo97P3PT19VV53uyRI0eElZWV6Nixo9oNGW7evCk8PDyEl5eXwZ6FfOTIEbFr1y6VYfbs2QKAmDJliti1a5fIzMzUuj+bNm0SM2bMUIk1/w2bnj17plxHXopnIa9fv145Tp9nIee/KdT169eFtbW18PPz02nfhRDCy8tLDBkyRGXc06dP1Z6NfOHCBQFArFixQgghRHh4uLCzs1O56dCtW7eEnZ2d2g1ZAPVnlWu7oVD+zy0nJ0fUrFlT1K5dW+Pzk/M//1UIIZydndWeD11cHTt2FM7OzhpvtpY3hoI+vw4dOogGDRpoXP+FCxdEdHR0ocPp06dVluvdu7ewtrYWly5dUo67ePGisLa2Fu+//75yXFpamrh06ZJ49OiRxrgVUlJSRM2aNYWrq6vypjhF+Qzy27Fjh9p38tGjR6JixYpi4MCBKvM2adJEODo6qsT6xx9/CABiwYIFhW7L1DB3lp3cqVg/tNzszs/PTzlO2+/mtddeExKJRFy7dk1l/N9//6223uJKTk4Wjo6OokOHDhrf57wxhoWFCXt7e43r0ZTjFY4ePapTbrtx44ZymZcvXwo3NzdRo0YNle+44iap3377rXLco0ePxKVLl7TeAK+gm93FxcWpfYcV2xg6dKjYtWuXSEpKEkIIMWPGDK03n3r27JnIysrSuH2F9PR04ezsLHr16qUyfvDgwcLOzk48efJEOS4qKkoAEOvWrVOOe/HihahRo4aoX79+gdsh3ZhbXv7ll18EALFnzx7luNTUVOHt7a3zze7y5zXFcVje38bAgQNFxYoVC4xF4fTp0wKACAsLUxkfFxcnrKysxLvvvqvTenRx6NAhAUB5Y9W8srKyVN4/bTdNLehv24sXL3TKU9HR0So3sXvw4IHaujIzM0WzZs2Era2tyjHTvXv3xKVLl1RyrT7HRjt27BBWVlZi0KBBasfoeQ0dOlSUL19e5SaGCrocr925c0frc+SrVq2qciPnCRMmCABi3759KvE7OjqKV199tdBtGUuZbJGvVasWvv76a4SEhKBRo0YYPnw4fH19ER8fj/Xr1+PZs2fYsWOHxjNav//+Oy5fvozs7Gw8ePAABw8eRHR0NKpXr46ffvpJeQMFAGjbti2ioqIwceJENG7cWNnN4/Lly/jyyy9hZWWF3bt369wV88iRIxqfj924cWM0btxY45lYxbpbtGhRaFfLgq4bVjh06BDGjx+Pfv36oXbt2sjMzMSRI0fw448/onnz5jrd5EwXipYlXVp2FXr37o1du3aptB5t3rwZq1atQt++fVGzZk08f/4cX375JRwdHZUtCcHBwViyZAl69OiBt99+Gw8fPsTKlStRq1atQrur6cPKygpfffUVevbsiQYNGmDYsGGoWrUq/v33X8TExMDR0VHlsS1xcXF4+vQpevfubbAYgNyzoG3btkWjRo0wcuRI1KhRAw8ePEBsbCzu3r2Lv//+u1jrL8o18kBuq9GBAwfQuXNnjB8/HgCwfPlyODs7q9yA7OTJk+jUqZNKq9fKlSuxe/duvPbaa/D29sb9+/exYcMGJCQkYMuWLcqWIH0/A0369euHgIAADBs2DBcvXoSrqytWrVqFnJwclUscACAqKgrdunVD27ZtMXr0aCQnJ2PJkiV45ZVXtN5oy5Qxd2pmiblT4ZVXXsHw4cNx6tQpuLu7Y8OGDXjw4IFKj6XPP/8cf/31F3r06AFvb288ffoUP/zwA06dOoVx48apXa4THR0NOzs7dOvWrXg7m4ejoyNWr16NIUOGoFmzZnjrrbdQuXJlJCQk4Ndff0WbNm2K/cizolwjL5VKsXDhQoSFhaF9+/YYMmQIEhISsGzZMrRr107lmcsrVqzAzJkz1VrJVqxYgaSkJGUr9s8//6zsNj9u3Dg4OTmhWbNmao8QVHSxb9Cggcp3ePLkyfjpp5/Qq1cvDB06FP7+/khLS1PeKC8+Pr7Aa6ltbW0xe/ZsjBkzBv3790dQUBCOHDmCrVu34vPPP1e5ieTo0aPx1VdfYcyYMbh69Sq8vb2xZcsW3L59u1QeU1YWmFte7t69O7y9vTF8+HBMnjwZ1tbW2LBhg/L3aij+/v7YuXMnwsPD0aJFC+X1ztrm7datGzZv3oyUlBR0794d9+/fxxdffAFbW1tMnDjRYHF16NABo0ePRmRkJM6dO4fu3bvDxsYG165dw3fffYdly5YVeq+VghT1GvnRo0cjJSUF7du3R9WqVZGYmIht27bh8uXLWLx4scqlnxEREdi8ebPykkNA92OjkydPIjQ0FC4uLujSpYvaJQatW7dW9v6ZN28eYmJi0KpVK4wcORL169fH06dPcebMGezfv1/tXkb5VatWDRMnTsTChQuRlZWFFi1aYPfu3Thy5Ai2bdumcolGREQEvv32W7z55psIDw+Hk5MT1qxZg6ysLMydO1fv97PUGPtMgjH9888/4u233xYeHh7CyspKABAymUzjY2fyPw6ofPnywsPDQ3Tr1k0sW7ZM5bFj+R05ckT07t1buLq6ColEIgAINzc3lUcfFaSwRyjlfdSNtmULeoRSQfKfDbx+/boIDQ0VNWrUELa2tkImk4kGDRqI6dOni9TUVINsQ+HatWvC2tpa51YlxeMjjhw5ojIuJCREeHt7C6lUKtzc3ESvXr3UWoPXr18vateuLaRSqahbt67YuHGjxkekoBgt8gpnz54Vb7zxhnBxcRFSqVRUr15dDBgwQBw4cEBlvo8++kh4e3sXeLayqG7cuCFCQ0OFh4eHsLGxEVWrVhW9evUS33//vXKeorbIF0dcXJzo2rWrsLe3FxUqVBC9e/dWe0SS4n3N+73ft2+f6Natm3J/KlasKLp37672niro+hlo8/TpUzF8+HDh4uIi7OzsRIcOHbR+z6Ojo0VAQICQyWTC2dlZDBkyROffvqli7rT83Jl3/X/88Ydo3LixMj/mX+e+fftEr169hKenp7CxsREVKlQQbdq0ERs3btSYv1q1aiUGDx5caFxFERMTI4KCgoSTk5OQyWSiZs2aYujQoSo5v6gt8sXxzTffiCZNmgipVCrc3d3F2LFj1b77ir85+R8JVdBj7/K2Xuan7W+TELmP64uIiBC1atUS5cuXF66urqJ169Zi0aJFGns0aLJu3TpRp04dUb58eVGzZk0RFRWl8fN+8OCBCAsLE87OzkIqlYpWrVoV+CgqKhpzyctC5P6tb9WqlShfvrzw9vYWS5Ys0evxc7q0yKempoq3335bVKxYUQAo9FF06enpYtasWaJ+/frC1tZWODk5iV69eomzZ8/qvF/6WLdunfD39xe2traiQoUKolGjRmLKlCkqvSWL0iJfVN98843o2rWrcHd3F+XKlROVKlUSXbt2Vek5oaB4hGf+/KPLsVFBj1fN/xkKkZs/xowZI7y8vISNjY3w8PAQXbp0UenlU5CcnBwxd+5cUb16dVG+fHnRoEEDsXXrVo3z3rhxQ/Tt21c4OjoKW1tb0blzZ3Hy5EmdtmMsZbqQz2/z5s1CIpFo7GJoSLNmzRIAxCeffFKi2ymLOnfuXGIHiKXp5cuXwsPDQyxdutTYoRAVirnT/GnKndoOIovj7NmzQiKRlNjBMRHlYl4msnws5POZN2+e1mtXDOndd98VAMTatWtLdDtlzfHjx4WNjY2Ij483dijFsnr1auHl5SVevnxp7FCIdMLcad405c6SKOQHDhwo+vfvb9B1EpFmzMtElk0iRBGf1UBEREQWy8fHBw0bNsQvv/xi7FCIiIgoH80PUSUiIiIiIiIik8QWeSIiIiIiIiIzwhZ5IiIiIiIiIjPCQp6IiIiIiIjIjJQzdgCmSC6X4969e6hQoQIkEomxwyEiMySEwPPnz+Hp6QkrK8s5Z8r8SETFxfxIRKSZPvmRhbwG9+7dg5eXl7HDICILcOfOHVSrVs3YYRgM8yMRGQrzIxGRZrrkRxbyGlSoUAFA7hvo6Oho5GiIyBylpKTAy8tLmU8sBfMjERUX8yMRkWb65EcW8hooukM5OjoyERNRsVha90rmRyIyFOZHIiLNdMmPlnNhEhEREREREVEZwEKeiIiIiIiIyIywkCciIiIiIiIyI7xGnsjM5eTkICsry9hhlDk2NjawtrY2dhhEVADmR+NgfiQyTcyJxmfI/MhCnshMCSGQmJiIpKQkY4dSZlWsWBEeHh4Wd8MmInPH/Gh8zI9EpoM50bQYKj+ykCcyU4qE7ObmBjs7Ox4slSIhBNLT0/Hw4UMAQJUqVYwcERHlxfxoPMyPRKaHOdE0GDo/spAnMkM5OTnKhOzi4mLscMokW1tbAMDDhw/h5ubGbqREJoL50fiYH4lMB3OiaTFkfuTN7ojMkOL6Jjs7OyNHUrYp3n9eb0ZkOpgfTQPzI5FpYE40PYbKj0Yt5A8fPozXXnsNnp6ekEgk2L17t8r0oUOHQiKRqAw9evQodL0rV66Ej48PZDIZWrVqhZMnT5bQHhAZF7tGGRfffyLTxd+ncfH9JzIt/E2aDkN9FkYt5NPS0tCkSROsXLlS6zw9evTA/fv3lcM333xT4Dp37tyJ8PBwTJ8+HWfOnEGTJk0QFBSkvBaBiIiIiIiIyJwZtZDv2bMn5syZg759+2qdRyqVwsPDQzlUqlSpwHUuWbIEI0eOxLBhw1C/fn2sWbMGdnZ22LBhg6HDJyITdPnyZQQEBEAmk8HPz8/Y4RARmRTmSCKiXOaeD03+ZneHDh2Cm5sbKlWqhM6dO2POnDlab9SQmZmJuLg4REREKMdZWVmha9euiI2NLa2QiYwqKvpqqW3rg26vlNq2dDV9+nTY29vjypUrcHBwMHY4RGRCSjM/AsyRRGS6mA/NPx+adCHfo0cPvPHGG/D19cWNGzfw8ccfo2fPnoiNjdV4h7/Hjx8jJycH7u7uKuPd3d1x+fJlrdvJyMhARkaG8nVKSorhdoKIStWNGzcQHByM6tWrGzsUi8D8SGRZmCMNh/mRyLyZez406bvWv/XWW3j99dfRqFEj9OnTB7/88gtOnTqFQ4cOGXQ7kZGRcHJyUg5eXl4GXT8R/Ucul2PBggWoVasWpFIpvL298fnnnwMA/vnnH3Tu3Bm2trZwcXHBqFGjkJqaqrL8V199hXr16kEmk6Fu3bpYtWqVcppEIkFcXBxmzZoFiUSCGTNmlOauWSTmR6LSxRxpPpgfiUoW82HBTLqQz69GjRpwdXXF9evXNU53dXWFtbU1Hjx4oDL+wYMH8PDw0LreiIgIJCcnK4c7d+4YNG4i+k9ERATmzZuHzz77DBcvXsT27dvh7u6OtLQ0BAUFoVKlSjh16hS+++477N+/H2PHjlUuu23bNkybNg2ff/45Ll26hLlz5+Kzzz7D5s2bAQD3799HgwYN8OGHH+L+/fuYNGmSsXbTYjA/EpUu5kjzwfxIVLKYDwtm0l3r87t79y6ePHmCKlWqaJxevnx5+Pv748CBA+jTpw+A3DM5Bw4cUPlg85NKpZBKpSURMhHl8fz5cyxbtgwrVqxAWFgYAKBmzZpo27YtvvzyS7x8+RJff/017O3tAQArVqzAa6+9hvnz58Pd3R3Tp0/H4sWL8cYbbwAAfH19cfHiRaxduxZhYWHw8PBAuXLl4ODgUODJO9Id8yNR6WGONC/Mj0Qlh/mwcEYt5FNTU1Va12/duoVz587B2dkZzs7OmDlzJt588014eHjgxo0bmDJlCmrVqoWgoCDlMl26dEHfvn2VhXp4eDjCwsLQvHlztGzZEkuXLkVaWhqGDRtW6vtHRKouXbqEjIwMdOnSReO0Jk2aKBMyALRp0wZyuVx5E5IbN25g+PDhGDlypHKe7OxsODk5lUr8REQliTmSiCgX82HhjFrInz59Gp06dVK+Dg8PBwCEhYVh9erV+L//+z9s3rwZSUlJ8PT0RPfu3TF79myVs583btzA48ePla8HDhyIR48eYdq0aUhMTISfnx/27t2rdgM8Iip9tra2RV5Wcd3Tl19+iVatWqlM03TzSyIic8McSUSUi/mwcEYt5Dt27AghhNbpf/zxR6HriI+PVxs3duzYArvSE5Fx1K5dG7a2tjhw4ABGjBihMq1evXrYtGkT0tLSlGdY//rrL1hZWaFOnTpwd3eHp6cnbt68iUGDBhkjfCKiEsUcSUSUi/mwcGZ1jTwRmTeZTIaPPvoIU6ZMQfny5dGmTRs8evQIFy5cwKBBgzB9+nSEhYVhxowZePToEcaNG4chQ4Yoe9TMnDkT48ePh5OTE3r06IGMjAycPn0az549U/boISIyV8yRRES5mA8Lx0KeiErVZ599hnLlymHatGm4d+8eqlSpgnfffRd2dnb4448/MGHCBLRo0QJ2dnZ48803sWTJEuWyI0aMgJ2dHRYuXIjJkyfD3t4ejRo1wsSJE423Q0REBsQcSUSUi/mwYBJRUN/2MiolJQVOTk5ITk6Go6OjscMhUvPy5UvcunULvr6+kMlkxg6nzCroc7DUPGKp+0WWg/nRNDA/Ws5+kXljTjQ9hsqPZvUceSIiIiIiIqKyjoU8ERERERERkRlhIU9ERERERERkRljIExEREREREZkRFvJEREREREREZoSFPBEREREREZEZYSFPREREREREZEZYyBMRERERERGZERbyRERERERERGaEhTwRmTwfHx8sXbrUYOu7fPkyAgICIJPJ4OfnZ7D1EhEZA3MkEVEuQ+dDU1bO2AEQkYHFRJbetjpFlN62DGj69Omwt7fHlStX4ODgAAC4evUqJk+ejL/++guZmZlo3LgxZs+ejU6dOhk5WiIymNLMjwBzJBGZLuZDg/njjz8wffp0XLhwATKZDO3bt8fixYvh4+NTottlizwRlTk3btxA27ZtUb16dbi4uAAAevXqhezsbBw8eBBxcXFo0qQJevXqhcTERCNHS0RUupgjiYh0c+vWLfTu3RudO3fGuXPn8Mcff+Dx48d44403SnzbLOSJqFSlpaUhNDQUDg4OqFKlChYvXoyOHTti4sSJAICHDx/itddeg62tLXx9fbFt2za1dVy7dg3t27eHTCZD/fr1ER0dDYlEgt27dxe6fYlEgri4OMyaNQsSiQQzZszA48ePce3aNUydOhWNGzdG7dq1MW/ePKSnp+P8+fMGfgeIiLRjjiQiymXsfHjo0CFIJBIkJSUpx507dw4SiQTx8fEAgLi4OOTk5GDOnDmoWbMmmjVrhkmTJuHcuXPIysoywLugHbvWE1Gpmjx5Mv7880/s2bMHbm5u+Pjjj3HmzBnldZhDhw7FvXv3EBMTAxsbG4wfPx4PHz5ULi+Xy/HGG2/A3d0dJ06cQHJysjKh6+L+/fvo2rUrevTogUmTJsHBwQH29vaoU6cOvv76azRr1gxSqRRr166Fm5sb/P39DfwOEBFpxxxJRJTL2PlQF/7+/rCyssLGjRsxdOhQpKamYsuWLejatStsbGwMuq38WMgTUalJTU3F+vXrsXXrVnTp0gUAsHnzZlSrVg1A7jWYv//+O06ePIkWLVoAANavX4969eop17F//35cvnwZf/zxBzw9PQEAc+fORc+ePXWKwcPDA+XKlYODgwM8PDxU1tunTx9UqFABVlZWcHNzw969e1GpUiWD7DsRUWGYI4mIcplCPtSFr68v9u3bhwEDBmD06NHIyclBYGAgfvvtN4NtQxt2rSeiUnPjxg1kZmaiVatWynHOzs6oU6cOAODSpUsoV66cSgtP3bp1UbFiReXrS5cuwcvLS5mQASAwMLBYcQkhMGbMGLi5ueHIkSM4efIk+vTpg9deew33798v1rqJiHTFHElElMtU82F+iYmJGDlyJMLCwnDq1Cn8+eefKF++PPr16wchhEG3lR9b5ImozDt48CB++eUXPHv2DI6OjgCAVatWITo6Gps3b8bUqVONHCERkfEwRxJRWWRlldvmnbcgz3/d+8qVK+Hk5IQFCxYox23duhVeXl44ceIEAgICSi6+EluzDg4fPozXXnsNnp6eajcdyMrKwkcffYRGjRrB3t4enp6eCA0Nxb179wpc54wZMyCRSFSGunXrlvCeEJEuatasCRsbG5w4cUI57tmzZ7h69SqA3DOp2dnZiIuLU06/cuWKyk1G6tWrhzt37qi0Ah0/frxYcaWnpwP4L2ErWFlZQS6XF2vdRES6Yo4kIsplCvmwcuXKAKCy/Llz51TmSU9PV8uN1tbWAFDi+dGohXxaWhqaNGmClStXqk1LT0/HmTNn8Nlnn+HMmTP48ccfceXKFbz++uuFrrdBgwa4f/++cjh69GhJhE9EenJwcMDw4cMxefJkHDx4EOfPn8fQoUOVCbBOnTro0aMHRo8ejRMnTiAuLg4jRoyAra2tch1du3bFK6+8grCwMPz99984cuQIPvnkk2LFFRgYiEqVKinXqXhe8q1btxAcHFysdRMR6Yo5kogolynkw1q1asHLywszZszAtWvX8Ouvv2Lx4sUq8wQHB+PUqVOYNWsWrl27hjNnzmDYsGGoXr06mjZtapg3QwujFvI9e/bEnDlz0LdvX7VpTk5OiI6OxoABA1CnTh0EBARgxYoViIuLQ0JCQoHrLVeuHDw8PJSDq6trSe0CEelp4cKFaNeuHV577TV07doVbdu2Vbm+aePGjfD09ESHDh3wxhtvYNSoUXBzc1NOt7Kywq5du/DixQu0bNkSI0aMwOeff16smFxdXbF3716kpqaic+fOaN68OY4ePYo9e/agSZMmxVo3EZE+mCOJiHIZOx/a2Njgm2++weXLl9G4cWPMnz8fc+bMUZmnc+fO2L59O3bv3o2mTZuiR48ekEql2Lt3r8pJhZIgESV9Fb6OJBIJdu3ahT59+midZ//+/ejevTuSkpKU12jlN2PGDCxcuBBOTk6QyWQIDAxEZGQkvL29dY4lJSUFTk5OSE5O1rodImN6+fIlbt26BV9fX8hkMmOHU2wdO3aEn58fli5dWuR16JJDDK2gz8FS84il7hdZDkvLj4B55kjmR8vZLzJvlpYTzTEf5meo/Gg2N7t7+fIlPvroI4SEhBS4U61atcKmTZtQp04d3L9/HzNnzkS7du1w/vx5VKhQQeMyGRkZyMjIUL5OSUkxePxEROaI+ZGISDPmRyIyJrN4/FxWVhYGDBgAIQRWr15d4Lw9e/ZE//790bhxYwQFBeG3335DUlISvv32W63LREZGwsnJSTl4eXkZeheIqJTMnTsXDg4OGgdDPje0rGB+JLIszJGGw/xIZN7MPR+afNd6RRF/8+ZNHDx4EC4uLnqvu0WLFujatSsiIyM1Ttd0RtXLy4tdo8hkWVo3KUN6+vQpnj59qnGara0tqlatarBtlYWuo8yPZG6YHwtWWjmS+dF894ssC3OidqV5zJhXmeharyjir127hpiYmCIV8ampqbhx4waGDBmidR6pVAqpVFqcUInIRDg7O8PZ2dnYYVgM5kciy8IcaTjMj0TmzdzzoVG71qempuLcuXPK5/HdunUL586dQ0JCArKystCvXz+cPn0a27ZtQ05ODhITE5GYmIjMzEzlOrp06YIVK1YoX0+aNAl//vkn4uPjcezYMfTt2xfW1tYICQkp7d0jIiIiIiIiMjijtsifPn0anTp1Ur4ODw8HAISFhWHGjBn46aefAAB+fn4qy8XExKBjx44AgBs3buDx48fKaXfv3kVISAiePHmCypUro23btjh+/DgqV65csjtDZAQmcmVMmcX3n8h08fdpXHz/iUwLf5Omw1CfhVEL+Y4dOxa4I7rsZHx8vMrrHTt2FDcsIpNnY2MDAEhPTy/xZ1SSdunp6QD++zyIyPiYH00D8yORaWBOND2Gyo8mfY08EWlmbW2NihUr4uHDhwAAOzs7SCQSI0dVdgghkJ6ejocPH6JixYqwtrY2dkhE9D/Mj8bF/EhkWpgTTYeh8yMLeSIz5eHhAQDKxEylr2LFisrPgYhMB/Oj8TE/EpkO5kTTYqj8yEKeyExJJBJUqVIFbm5uyMrKMnY4ZY6NjQ1bmohMFPOjcTE/EpkW5kTTYcj8yEKeyMxZW1vzgImISAPmRyKi/zAnWhajPn6OiIiIiIiIiPTDQp6IiIiIiIjIjLCQJyIiIiIiIjIjLOSJiIiIiIiIzAgLeSIiIiIiIiIzwkKeiIiIiIiIyIywkCciIiIiIiIyIyzkiYiIiIiIiMwIC3kiIiIiIiIiM8JCnoiIiIiIiMiMsJAnIiIiIiIiMiMs5ImIiIiIiIjMCAt5IiIiIiIiIjPCQp6IiIiIiIjIjJTTZ+aMjAxYWVnBxsYGAHDjxg1s2LABCQkJqF69OoYPHw5fX98SCZSIiIiIiIiI9GyRDwoKwp49ewAAf/31Fxo0aIBffvkFWVlZ+O2339CwYUPExsaWSKBEREREREREpGchf/bsWTRp0gQA8Mknn+D999/H33//jR07duDMmTMIDw/H5MmTdV7f4cOH8dprr8HT0xMSiQS7d+9WmS6EwLRp01ClShXY2tqia9euuHbtWqHrXblyJXx8fCCTydCqVSucPHlSn90kIiIiIiIiMll6FfI5OTnIyckBAFy+fBlhYWEq04cOHYq///5b5/WlpaWhSZMmWLlypcbpCxYswPLly7FmzRqcOHEC9vb2CAoKwsuXL7Wuc+fOnQgPD8f06dNx5swZNGnSBEFBQXj48KHOcRERERERERGZKr0K+VatWuHnn38GANSsWVOtaD937hycnZ11Xl/Pnj0xZ84c9O3bV22aEAJLly7Fp59+it69e6Nx48b4+uuvce/ePbWW+7yWLFmCkSNHYtiwYahfvz7WrFkDOzs7bNiwQee4iIiIiIiIiEyVXje7mzNnDnr27Im0tDSEhITgww8/xLVr11CvXj1cuXIFy5cvR0REhEECu3XrFhITE9G1a1flOCcnJ7Rq1QqxsbF466231JbJzMxEXFycSgxWVlbo2rUrr90nIiIiIiIii6BXIR8YGIjff/8d4eHhOHHiBADg888/BwB4enpixowZmDBhgkECS0xMBAC4u7urjHd3d1dOy+/x48fIycnRuMzly5e1bisjIwMZGRnK1ykpKUUNm4jIojA/EhFpxvxIRMakVyEP5BbzsbGxePToEW7evAm5XI4qVarAx8enBMIrHZGRkZg5c6axwyAiMjnMj0REmjE/EpEx6XWNfF6VK1dGq1atEBgYWCJFvIeHBwDgwYMHKuMfPHignJafq6srrK2t9VoGACIiIpCcnKwc7ty5U8zoiYgsA/MjEZFmzI9EZEx6t8jnlZaWhm+//RbXr19HlSpVEBISAhcXF4ME5uvrCw8PDxw4cAB+fn4AcrssnThxAu+9957GZcqXLw9/f38cOHAAffr0AQDI5XIcOHAAY8eO1botqVQKqVRqkLiJiCwJ8yMRkWbMj0RkTHoV8vXr18fRo0fh7OyMO3fuoF27dkhKSsIrr7yCGzduYPbs2Th+/Dh8fX11Wl9qaiquX7+ufH3r1i3lne+9vb0xceJEzJkzB7Vr14avry8+++wzeHp6Kot0AOjSpQv69u2rLNTDw8MRFhaG5s2bo2XLlli6dCnS0tIwbNgwfXaViIiIiIiIyCTpVchfvnwZ2dnZAHK7E1WtWhV///03nJyckJqair59++KTTz7B9u3bdVrf6dOn0alTJ+Xr8PBwAEBYWBg2bdqEKVOmIC0tDaNGjUJSUhLatm2LvXv3QiaTKZe5ceMGHj9+rHw9cOBAPHr0CNOmTUNiYiL8/Pywd+9etRvgEREREREREZkjiRBC6DqzlZUVEhMT4ebmhpo1a2LNmjXo1q2bcvqxY8fw1ltvISEhoUSCLS0pKSlwcnJCcnIyHB0djR0OEZkhS80jlrpfRFR6LDWPWOp+EVHp0SeP6H2zO4lEAgB4+fIlqlSpojKtatWqePTokb6rJCIiIiIiIiId6X2zuy5duqBcuXJISUnBlStX0LBhQ+W027dvG+xmd0RERERERESkTq9Cfvr06SqvHRwcVF7//PPPaNeuXfGjIiIiIiIiIiKNilXI57dw4cJiBUNEREREREREBdP7GnkiIiIiIiIiMh69C/m///4bc+bMwapVq1Qe+wbk3mXvnXfeMVhwRERERERERKRKr0J+3759aNmyJXbs2IH58+ejbt26iImJUU5/8eIFNm/ebPAgiYiIiIiIiCiXXoX8jBkzMGnSJJw/fx7x8fGYMmUKXn/9dezdu7ek4iMiIiIiIiKiPPS62d2FCxewZcsWALnPk58yZQqqVauGfv36YceOHWjRokWJBElEREREREREufQq5KVSKZKSklTGvf3227CyssLAgQOxePFiQ8ZGRERERERERPnoVcj7+fkhJiYG/v7+KuPfeustCCEQFhZm0OCIiIiIiIiISJVehfx7772Hw4cPa5wWEhICIQS+/PJLgwRGREREREREROr0KuT79u2Lvn37ap3+9ttv4+233y52UERERERERESkmd7PkSciIiIiIiIi4ylyIR8cHIz79++r/Z+IiIiIiIiISk6RC/nDhw/jxYsXav8nIiIiIiIiopLDrvVEREREREREZoSFPBEREREREZEZYSFPREREREREZEZYyBMRERERERGZEZMv5H18fCCRSNSGMWPGaJx/06ZNavPKZLJSjpqIiIiIiIioZJQzdgCFOXXqFHJycpSvz58/j27duqF///5al3F0dMSVK1eUryUSSYnGSERERERERFRailzIV69eHTY2Nmr/N7TKlSurvJ43bx5q1qyJDh06aF1GIpHAw8OjROIhIiIiIiIiMqYiF/Lnz5/X+P+SlJmZia1btyI8PLzAVvbU1FRUr14dcrkczZo1w9y5c9GgQQOt82dkZCAjI0P5OiUlxaBxk4WIiQQ6RRg7CqJSxfxIRKQZ8yMRGZPJXyOf1+7du5GUlIShQ4dqnadOnTrYsGED9uzZg61bt0Iul6N169a4e/eu1mUiIyPh5OSkHLy8vEogeiIi88P8SESkGfMjERmTRAgh9F1o8+bNcHV1RXBwMABgypQpWLduHerXr49vvvkG1atXN3igABAUFITy5cvj559/1nmZrKws1KtXDyEhIZg9e7bGeTSdUfXy8kJycjIcHR2LHTdZCLbIkx5SUlLg5ORk9nmE+ZGIDI35kYhIM33yY5Fa5OfOnQtbW1sAQGxsLFauXIkFCxbA1dUVH3zwQVFWWajbt29j//79GDFihF7L2djYoGnTprh+/brWeaRSKRwdHVUGIiJifiQi0ob5kYiMqUjXyN+5cwe1atUCkNvd/c0338SoUaPQpk0bdOzY0ZDxKW3cuBFubm7KXgC6ysnJwT///INXX321ROKiMiIm0tgREBERERERAShii7yDgwOePHkCANi3bx+6desGAJDJZHjx4oXhovsfuVyOjRs3IiwsDOXKqZ57CA0NRUTEf92dZ82ahX379uHmzZs4c+YMBg8ejNu3b+vdkk9kEngCgYiIiIiI8ilSi3y3bt0wYsQING3aFFevXlW2dl+4cAE+Pj6GjA8AsH//fiQkJOCdd95Rm5aQkAArq//ORzx79gwjR45EYmIiKlWqBH9/fxw7dgz169c3eFxEREREREREpa1IhfzKlSvx6aef4s6dO/jhhx/g4uICAIiLi0NISIhBAwSA7t27Q9s9+Q4dOqTyOioqClFRUQaPgYiIiIiIiMgUFKmQr1ixIlasWKE2fubMmcUOiKjE8e7zRETmgzmbiIhITZEKeQBISkrCyZMn8fDhQ8jlcuV4iUSCIUOGGCQ4IiIiIiIiIlJVpEL+559/xqBBg5CamgpHR0dIJBLlNBbyRERERERERCWnSHet//DDD/HOO+8gNTUVSUlJePbsmXJ4+vSpoWMkIt69noiIiIiI/qdIhfy///6L8ePHw87OztDxEBEREREREVEBilTIBwUF4fTp04aOhYgMga33RGRqmJeIiIgMqkjXyAcHB2Py5Mm4ePEiGjVqBBsbG5Xpr7/+ukGCIzI63i2ZiIiIiIhMTJEK+ZEjRwIAZs2apTZNIpEgJyeneFERke54soGIiIiIqEwpUiGf93FzRERERERERFR6inSNPBEZAa8xJSIiIiIi6NEiv3z5cowaNQoymQzLly8vcN7x48cXOzAiIiIiIiIiUqdzIR8VFYVBgwZBJpMhKipK63wSiYSFPBEREREREVEJ0bmQv3Xrlsb/CyEA5BbwRGQAvHkdEREREREVoMjXyK9fvx4NGzaETCaDTCZDw4YN8dVXXxkyNiIiIiIiIiLKp0h3rZ82bRqWLFmCcePGITAwEAAQGxuLDz74AAkJCRofS0dERERERERExVekQn716tX48ssvERISohz3+uuvo3Hjxhg3bhwLeSIiIiIiIqISUqSu9VlZWWjevLnaeH9/f2RnZxc7KCKj4mPeiIiMhzmYiIioUEUq5IcMGYLVq1erjV+3bh0GDRpU7KCIiIiIiIiISDOdu9aHh4cr/y+RSPDVV19h3759CAgIAACcOHECCQkJCA0NNXyURERERERERARAj0L+7NmzKq/9/f0BADdu3AAAuLq6wtXVFRcuXDBgeESljF06iYj0Y8xHZvJxnUREVEbpXMjHxMSUZBwazZgxAzNnzlQZV6dOHVy+fFnrMt999x0+++wzxMfHo3bt2pg/fz5effXVkg6ViIiIiIiIqFQU+TnypaVBgwa4f/++cjh69KjWeY8dO4aQkBAMHz4cZ8+eRZ8+fdCnTx+cP3++FCMmIiIiIiIiKjkmX8iXK1cOHh4eysHV1VXrvMuWLUOPHj0wefJk1KtXD7Nnz0azZs2wYsWKUoyYiIioDOClSEREREZj8oX8tWvX4OnpiRo1amDQoEFISEjQOm9sbCy6du2qMi4oKAixsbEFbiMjIwMpKSkqAxERMT8SEWnD/EhExmTShXyrVq2wadMm7N27F6tXr8atW7fQrl07PH/+XOP8iYmJcHd3Vxnn7u6OxMTEArcTGRkJJycn5eDl5WWwfaAyJiaSrVRkUZgfqcQxZ5KZYn4kImMy6UK+Z8+e6N+/Pxo3boygoCD89ttvSEpKwrfffmvQ7URERCA5OVk53Llzx6DrJ1LBg1YyI8yPVCKYB8kCMD8SkTHpfNd6U1CxYkW88soruH79usbpHh4eePDggcq4Bw8ewMPDo8D1SqVSSKVSg8VJpMRHI5GZY36kEsWCnswY8yMRGZNJt8jnl5qaihs3bqBKlSoapwcGBuLAgQMq46KjoxEYGFga4VFZVUh3+qjoq6UYDBFRCTNg8R1784nB1kVEZEli108ydghk4ky6kJ80aRL+/PNPxMfH49ixY+jbty+sra0REhICAAgNDUVExH+tnRMmTMDevXuxePFiXL58GTNmzMDp06cxduxYY+0CmYsSbhViMU9EpFmRinm25BNRGaAs5pnzSAOTLuTv3r2LkJAQ1KlTBwMGDICLiwuOHz+OypUrAwASEhJw//595fytW7fG9u3bsW7dOjRp0gTff/89du/ejYYNGxprF4gQkLAOwP+KeW2JmAmaiMyZAXJYsU54MocSkQVj7yXSxKSvkd+xY0eB0w8dOqQ2rn///ujfv38JRUSUTyEHj4rEG5CwDse9R5X69omITFXebqNR0Vf/d9JzUfFWyvuSEJEFiIq+ioD//Z9d7Ekbk26RJzI3isI9Kvqqbq1LLMSJqIxQ5MSo6KtsXSIiykNRrMeun4TY9ZOUvTlV8JiR8mEhT2RgBR2gFnrwyiRNRBbsv5Z37dOJiMqiwlreeQKU8mMhT1RURSy61RIxi3ciMiVGzkk8WCUi0ix2/SSj52gyHSzkiQxA3wNPtjoRUVnBfEdEpFlRrn9XHnOyoC/zWMgTFVPe6+LzKqj7aP5liYiMqoQOCBV5sbBcpylf8gQAEVm0/+Xdot7MjseQxEKeSF95DniLk0R5kEpElqw4OY75kYgsHY8hqbhYyBOVEm0t9LE3nyD25hMmZSKyeLr0VMpLcYd7g+TH/L0O2C2ViMyUIpdGRV/l4+nKMBbyZLl4kKaK7wcRFUcxc4i+RTwRkUWKiTTYMRnzatnGQp6oCPgcZCIizaKirxa5Bd1gB6U8cUlEJkrRE9OgmPPKJBbyRCaEJweIyOQU4wCxqIU5b35HRKQ7Hj+WTSzkifRkqGTJ7lBERAVjniQiS8Lr2cmQWMgT6YEtQkRE2mnKkYYoxou8DnY3JSITUeJFvCLfMe+VGSzkiXRUWt2WeAd7IjJHefNWSbWkF+f6eyIiYymNlvjYm0/Y4l/GsJAnMlE8WCUic1aS3eJ5PSgRkWbMj2UHC3kiIiIyiICEdSVWwPN6eSIiov+wkCciIiIiIioJvGadSggLeaJCFKWLu6Fajtg9iohMXWnmqby5lZcfEZGpM9Y167xWvmxgIU+kA2MW1DxYJSKD06WFSI9WpNibT4zS9V2n3GzgfSUi0oexjiFZzFs+FvJERERUJDzRSESkGfMjlTQW8kRmgF3siYhy5W/558EyEZkiU7hBZ+z6SexxZMFMupCPjIxEixYtUKFCBbi5uaFPnz64cuVKgcts2rQJEolEZZDJZKUUMVkaUyqgTSkWIiJTykmmFAsRkSmdYGR+tFwmXcj/+eefGDNmDI4fP47o6GhkZWWhe/fuSEtLK3A5R0dH3L9/Xzncvn27lCImS2JKSZiIyJQwPxIRaRa7fpJJtMaT5Stn7AAKsnfvXpXXmzZtgpubG+Li4tC+fXuty0kkEnh4eJR0eERERFRCeCBMRGQgMZFApwhjR0EGZtIt8vklJycDAJydnQucLzU1FdWrV4eXlxd69+6NCxcuFDh/RkYGUlJSVAYq20y1tclU4yLLxfxI+ZlqN82o6KsmGxtZJuZHys9U7xQfe/MJjyEtkNkU8nK5HBMnTkSbNm3QsGFDrfPVqVMHGzZswJ49e7B161bI5XK0bt0ad+/e1bpMZGQknJyclIOXl1dJ7AIRkdlhfiQi0oz5kVSY+E3l2MvJ8phNIT9mzBicP38eO3bsKHC+wMBAhIaGws/PDx06dMCPP/6IypUrY+3atVqXiYiIQHJysnK4c+eOocMnM2LqLTo8o0qlifmR8jKH/GMOMZJlYH6kvEz9+BFgfrQ0Jn2NvMLYsWPxyy+/4PDhw6hWrZpey9rY2KBp06a4fv261nmkUimkUmlxwyQLUJwkrM+ZTp4VJXPB/EgKsTefAN7GjoLIdDA/hAzfSgAAa7RJREFUkoKpdqnPL/f4c5GxwyADMekWeSEExo4di127duHgwYPw9fXVex05OTn4559/UKVKlRKIkCyJOZ2lNKdYicj8mVvOMYeWMSKyDOaWH80tXtLOpAv5MWPGYOvWrdi+fTsqVKiAxMREJCYm4sWLF8p5QkNDERHx310YZ82ahX379uHmzZs4c+YMBg8ejNu3b2PEiBHG2AUqDSZ+TZLJ4/tHVDbwt05EVOaxV6jlMOlCfvXq1UhOTkbHjh1RpUoV5bBz507lPAkJCbh//77y9bNnzzBy5EjUq1cPr776KlJSUnDs2DHUr1/fGLtAZoKtN0REmpW5/MgTHkSko6joqyyMyWhM+hp5IUSh8xw6dEjldVRUFKKiokooIrJEUdFXEWDsIIogKvoqPjDpXzARmTtzzY8AcyQRlazY9ZPMNj/Grp+EwOG8Vt7cmXSLPBEVrMy1lBERERFRsZnLDfpIOxbyVKZZwg0/WMwTUUmwhNxiCftARFRSLOE4uCxjIU9ERERERKQrC7mXBq/vN28s5IksAM+oEhFpVqxWeQs5WCci0oZd7M0XC3kqk6Kir1pc8WuJ+0RExVSEQjT25hOLyyVR0VfZzZ6IDCJ2/SSLyyeWlvPLChbyVOZYWvI1KLY+EZVpPJgjItLOUluvAxLW8RjQDLGQJyIiIiIiKggLXTIxLOSpTCkLrU3scUBERVEW8mNZ2EciKhmWfnxl6ftniVjIU5lRlg7gytK+EhHpg/mRiPRlqV3q8ysr+2kpWMgTERERERFpwi71ZKJYyJP5KEYiLYstMMXeZ/7hIiozylqXyrL4N4GIiqas5cfY9ZN4DGgmWMiTaTNAIinLB2wG23cmdCLzoefvtazmyLJ2cE5E+mN+JFPGQp7IwpXVP0JERIXROz/ypCZR2fC/33pAwjojB2I8vF7e9JUzdgBEJYlFbK6o6KsISHiCwE7GjoSITAXzYy7mRyLKL/bmE+AmC1lFMR84fJGRIyFN2CJPFovdgtQZ/MCdrVNEZon5UR1PbBARwJZoTZgfTRMLebJITDja8b0hsjC8Jt5g2NWeqGxjEa9ZQMI6vjcmiF3ryaLwAJWISLPYm09wPJs5sjCxN9nNnqisyb3EpuxeD6+rqOir+KDbK8YOg/6HLfJkMVjE607xXvE9Iyob+FvXj+L94iUIRJYvdv0kFvE6ytsyz78rxsdCnsxe7M0nTCZFkPc94/tHZEb06M7N/Fh0xepmzy73RCYvKvoqu4sXUd6TH/wbYzzsWk9mS5E4Aowch7mLvfkE8DZ2FERUoJhIoFOEzrMzPxoOu5ISWRZFN3rmx+KLXT/pf+8j72pvDGbRIr9y5Ur4+PhAJpOhVatWOHnyZIHzf/fdd6hbty5kMhkaNWqE3377rZQipdIQFX2VZ/9KgEHfU7ZGERlFVPRVdgcvAcyPRBYgJpLXwpcQ9mwwDpNvkd+5cyfCw8OxZs0atGrVCkuXLkVQUBCuXLkCNzc3tfmPHTuGkJAQREZGolevXti+fTv69OmDM2fOoGHDhkbYAzIExXN+eaOmkpX3ZliK95stUUSlSM+WdwWe3Cx5mv4OfWDyR1FElLd4DwCL+JKSv5jns+dLnsn/CVqyZAlGjhyJYcOGAQDWrFmDX3/9FRs2bMDUqVPV5l+2bBl69OiByZMnAwBmz56N6OhorFixAmvWrCnV2KnolN1CWbwbXd6DVxb1RKYhb+EekMDLY4wl78lPFvVEpiF/qzu70BuHorA/7j2Kx48lxKT/7GRmZiIuLg4REf+1TlhZWaFr166IjY3VuExsbCzCw8NVxgUFBWH37t1at5ORkYGMjAzl6+TkZABASkpKMaKnwqw8eB1jOtfCyoPXtc6T9iIDL9NS1f6vbZ6ijleMS3uR+z3Iv8284/OPMxRdt58/7vzji/N+FPb/yN1nVJZtcfceTiWfUX6OYzrX+t9KXwKafj+HFwPtP9R9vBlT5A8hhJEjKR7mxxJQ0Pf9f7+d/PlR8VtT/P9lNe2/eX1+0wUto8+/xqBPbHnHFbTPBf2/sNf7831Giv8D+C83AtrzI2CRuVAT5kcqjrz5scXdjWrTGwFIK/2wSItGV77A/iuap52qNkz9GLKM0ys/ChP277//CgDi2LFjKuMnT54sWrZsqXEZGxsbsX37dpVxK1euFG5ublq3M336dAGAAwcOHAw+3Llzp/jJ0IiYHzlw4FBSA/MjBw4cOGgedMmPJt0iX1oiIiJUWvHlcjmePn0KFxcXSCQSI0ZWsJSUFHh5eeHOnTtwdHQ0djgGYWn7ZGn7A3CfdCWEwPPnz+Hp6WmQ9RkL86Pp4D6ZPkvbH4D5sSDmmh8By/uuWtr+ANwnc2Ds/GjShbyrqyusra3x4MEDlfEPHjyAh4eHxmU8PDz0mh8ApFIppFKpyriKFSsWLWgjcHR0tIgfQ16Wtk+Wtj8A90kXTk5OBluXsTA/mh7uk+mztP0BmB81Mff8CFjed9XS9gfgPpkDY+VHk378XPny5eHv748DBw4ox8nlchw4cACBgYEalwkMDFSZHwCio6O1zk9ERERERERkTky6RR4AwsPDERYWhubNm6Nly5ZYunQp0tLSlHexDw0NRdWqVREZmftc1gkTJqBDhw5YvHgxgoODsWPHDpw+fRrr1vFxE0RERERERGT+TL6QHzhwIB49eoRp06YhMTERfn5+2Lt3L9zd3QEACQkJsLL6r2NB69atsX37dnz66af4+OOPUbt2bezevdsinyEvlUoxffp0tW5d5szS9snS9gfgPpF5sMTPlPtk+ixtfwDL3CeyvM/V0vYH4D6ZA2Pvj0QIM3/2BxEREREREVEZYtLXyBMRERERERGRKhbyRERERERERGaEhTwRERERERGRGWEhT0RERERERGRGWMgTERERERERmREW8kRERERERERmhIU8ERERERERkRlhIU9ERERERERkRljIExEREREREZkRFvJEREREREREZoSFPBEREREREZEZYSFPFuXkyZMoX748bt++bexQimXNmjXw9vZGRkaGsUMhojKgtHLnW2+9hQEDBpToNojIMnTs2BEdO3Y0dhhEJqtMF/IXLlzA4MGDUbVqVUilUnh6emLw4MG4ePGi2rybNm2CRCJRDjKZDJ6enggKCsLy5cvx/Plzrdv566+/0LdvX7i7u0MqlcLHxwfvvvsu7ty5o1Ochw4dUtl2/mHHjh0al0tKSoKbmxskEgm+//57rftz9OhRtWWFEPDy8oJEIkGvXr1Upn3wwQdo1qwZnJ2dYWdnh3r16mHGjBlITU0t8D3LO0ydOlU5n4+PDyQSCcaNG6d13/PHr80nn3yCkJAQVK9eXaf5TdXQoUORmZmJtWvXGjuUUpWZmYm5c+eibt26kMlkcHd3R3BwMO7evVvostq+a/PmzTN4nElJSRg1ahQqV64Me3t7dOrUCWfOnNE47/PnzzFlyhT4+vpCKpWiatWq6NevH9LT0w0eV2lh7mTuzOvevXsYPHgw6tSpgwoVKqBixYpo2bIlNm/eDCGEyrwfffQRfvjhB/z99996b8ecPXjwAKNHj0bVqlUhk8ng4+OD4cOHF7pcamoqpk+fjh49esDZ2RkSiQSbNm0qdLmsrCzUr18fEokEixYtMsAeqFu/fj3q1asHmUyG2rVr44svvtA6786dOxEYGAh7e3tUrFgRrVu3xsGDB0skrrLKXPJyadm+fTuWLl2q8/xyuRxr1qyBn58fHBwc4O7ujp49e+LYsWMlF6QJuXDhAvr3748aNWrAzs4Orq6uaN++PX7++Wed16HLsdGTJ0+wcOFCtG/fHpUrV0bFihUREBCAnTt3GnqXAOR+rgsWLICvry9kMhkaN26Mb775Ruu8q1evhp+fH2xtbeHi4oLOnTub9N+rcsYOwFh+/PFHhISEwNnZGcOHD4evry/i4+Oxfv16fP/999i5cyd69+6tttysWbPg6+uLrKwsJCYm4tChQ5g4cSKWLFmCn376CY0bN1aZ/4svvsCECRNQo0YNjBs3DlWqVMGlS5fw1VdfYefOnfj9998REBCgU8zjx49HixYt1MYHBgZqnH/atGmFFgsymQzbt29H27ZtVcb/+eefuHv3LqRSqdoyp06dQrt27TBs2DDIZDKcPXsW8+bNw/79+3H48GFYWameH1K8Z3k1bNhQbb1ffvklIiIi4OnpWWDM2pw7dw779++3iKQrk8kQFhaGJUuWYNy4cZBIJMYOqcRlZWUhODgYx44dw8iRI9G4cWM8e/YMJ06cQHJyMqpVq1boOrp164bQ0FCVcU2bNjVonHK5HMHBwfj7778xefJkuLq6YtWqVejYsSPi4uJQu3Zt5bzJycno0KED7t69i1GjRqFWrVp49OgRjhw5goyMDNjZ2Rk0ttLA3JmLufM/jx8/xt27d9GvXz94e3sjKysL0dHRGDp0KK5cuYK5c+cq523atCmaN2+OxYsX4+uvvy7S9szNnTt30KZNGwDAu+++i6pVq+LevXs4efJkocs+fvwYs2bNgre3N5o0aYJDhw7ptM0vvvgCCQkJxQm7QGvXrsW7776LN998E+Hh4Thy5AjGjx+P9PR0fPTRRyrzzpgxA7NmzUK/fv0wdOhQZGVl4fz58/j3339LLL6yxhzzsi727dtX5GW3b9+O8+fPY+LEiTrNP3nyZCxZsgSDBw/G+++/j6SkJKxduxYdOnTAX3/9hZYtWxY5FnNw+/ZtPH/+HGFhYfD09ER6ejp++OEHvP7661i7di1GjRpV4PK6HhvFxsbik08+wauvvopPP/0U5cqVww8//IC33noLFy9exMyZMw26X5988gnmzZuHkSNHokWLFtizZw/efvttSCQSvPXWWyrzvvPOO9i2bRtCQ0MxduxYpKWl4ezZs3j48KFBYzIoUQZdv35d2NnZibp164qHDx+qTHv06JGoW7eucHBwEDdv3lSO37hxowAgTp06pba+AwcOCFtbW1G9enWRnp6uHH/06FFhZWUl2rVrJ9LS0tRicHd3F56enuLZs2cFxhsTEyMAiO+++07nffznn39EuXLlxKxZszQuq9ifN954Q7i6uoqsrCyV6SNHjhT+/v6ievXqIjg4uNDtLVq0SAAQsbGxatvQ9J7lVb16ddGgQQNRrlw5MW7cOJVp+uz7+PHjhbe3t5DL5YXOaw5Onz4tAIgDBw4YOxSl1NRUrdPyf8f1NX/+fGFjYyNOnDhRpOUBiDFjxhQrBl3s3LlT7Tv58OFDUbFiRRESEqIy73vvvScqVqyokkvMGXMnc6c+evXqJezt7UV2drbK+EWLFgl7e3vx/Plzg26vOLTltpycHPHixYtirbtnz57C19dXPH78WO9lX758Ke7fvy+EEOLUqVMCgNi4cWOByzx48EA4OTkpv8MLFy4sSthapaenCxcXF7Xv96BBg4S9vb14+vSpclxsbKyQSCRiyZIlBo2B/mNuebm0BAcHi+rVq+s0b1ZWlrC1tRX9+vVTGX/z5k0BQIwfP74EItSfXC5X+UzyevHihcjJyTHo9rKzs0WTJk1EnTp1Cp1X12Ojmzdvivj4eJVl5XK56Ny5s5BKpQUeZ+rr7t27wsbGRuXYUC6Xi3bt2olq1aqp/G1SxP/jjz8abPuloUx2rV+4cCHS09Oxbt06VK5cWWWaq6sr1q5di9TUVCxcuFCn9XXu3BmfffYZbt++ja1btyrHz549GxKJBJs3b1ZreatZsyYWLFiAe/fuYd26dcXfqXwmTJiAvn37ol27dgXOFxISgidPniA6Olo5LjMzE99//z3efvttnbfn4+MDILdbTVH4+PggNDQUX375Je7du1ekdezevRudO3dWa70+ffo0goKC4OrqCltbW/j6+uKdd95RmWfRokVo3bo1XFxcYGtrC39/f41dUiUSCcaOHYvvvvsO9evXh62tLQIDA/HPP/8AyG2lqFWrFmQyGTp27Ij4+Hi1dZw4cQI9evSAk5MT7OzslGd78/P394ezszP27NlTpPejIJcvX0a/fv3g7OwMmUyG5s2b46efflKZR9H17s8//8T7778PNzc3Zat4x44d0bBhQ8TFxaF9+/aws7PDxx9/XOR45HI5li1bhr59+6Jly5bIzs4uctfzFy9e4OXLlwXOo+tnoMn3338Pd3d3vPHGG8pxlStXxoABA7Bnzx7lfQ2SkpKwceNGjBo1Cr6+vsjMzDT7ex4wd/6nLOROHx8f9OrVC/v27YOfnx9kMhnq16+PH3/8UefY0tPTkZmZqTK+W7duSEtLU3nvDOX3339Hu3btYG9vjwoVKiA4OBgXLlxQmWfo0KFwcHDAjRs38Oqrr6JChQoYNGgQgP9y/LZt29CgQQNIpVLs3bu3yPFcvnwZv//+OyZPngwXFxe8fPkSWVlZOi8vlUrh4eGh1zanTp2KOnXqYPDgwVrnSUpKwsSJE+Hl5QWpVIpatWph/vz5kMvlha4/JiYGT548wfvvv68yfsyYMUhLS8Ovv/6qHLd06VJ4eHhgwoQJEEKoXUZCxWdueXnGjBkaexkqjjnyHjflv0ZeccnQt99+i88//xzVqlWDTCZDly5dcP36dZXlfv31V9y+fVt5+YAi12qSlZWFFy9ewN3dXWW8m5sbrKysYGtrW+A+6Usul2Pp0qVo0KCB8jLC0aNH49mzZyrzKXLwH3/8gebNm8PW1hZr165Vvg87duzAp59+iqpVq8LOzg4pKSkGjdPa2hpeXl46/X3S9djI19dX7RIuiUSCPn36ICMjAzdv3lSZ9u+//+Kdd95RXsrRoEEDbNiwQaf49+zZg6ysLJVcJZFI8N577+Hu3buIjY1Vjl+yZAlatmyJvn37Qi6XIy0tTadtGFuZLOR//vln+Pj4aD1Qa9++PXx8fPS6LmTIkCEA/usGlJ6ejgMHDqBdu3ZqXSMVBg4cCKlUqvN2nj9/jsePH6sNIt81iN999x2OHTuGBQsWFLpOHx8fBAYGqlwv8vvvvyM5OVmty0le2dnZePz4Me7du4d9+/bh008/RYUKFTR2PUpOTlaLWZNPPvkE2dnZRbqm+d9//0VCQgKaNWumMv7hw4fo3r074uPjMXXqVHzxxRcYNGgQjh8/rjLfsmXL0LRpU8yaNQtz585FuXLl0L9/f5UDEoUjR47gww8/RFhYGGbMmIFLly6hV69eWLlyJZYvX473338fkydPRmxsrNoJg4MHD6J9+/ZISUnB9OnTMXfuXCQlJaFz584au1k2a9ZM5wJTVxcuXEBAQAAuXbqEqVOnYvHixbC3t0efPn2wa9cutfnff/99XLx4EdOmTVO5PvfJkyfo2bMn/Pz8sHTpUnTq1AlA7jWdmr6n+Yfk5GTlui5evIh79+6hcePGGDVqFOzt7WFvb4/GjRsjJiZG533btGkT7O3tYWtri/r162P79u1q8+j7GeR39uxZNGvWTK0bdMuWLZGeno6rV68CAI4ePYqXL1+iVq1a6NevH+zs7GBra4s2bdrg3LlzOu+TKWHu/I+l506Fa9euYeDAgejZsyciIyOVuVFTEf7ixQs8fvwY8fHx2Lx5MzZu3IjAwEC1g2DFSVBD57YtW7YgODgYDg4OmD9/Pj777DNcvHgRbdu2VTupmp2djaCgILi5uWHRokV48803ldMOHjyIDz74AAMHDsSyZcuUBcCzZ890ym15T0Lu378fAODu7o4uXbrA1tYWtra26Nmzp8YTvcV18uRJbN68GUuXLtV6SVZ6ejo6dOiArVu3IjQ0FMuXL0ebNm0QERGB8PDwQrdx9uxZAEDz5s1Vxvv7+8PKyko5HQAOHDiAFi1aYPny5ahcuTIqVKiAKlWqYMWKFcXYS8rLXPNyccybNw+7du3CpEmTEBERgePHjytPxgG5OdHPzw+urq7YsmULtmzZUuD18ra2tmjVqhU2bdqEbdu2ISEhAf/3f/+HoUOHolKlSoV2K9fX6NGjMXnyZLRp0wbLli3DsGHDsG3bNgQFBamd6Lty5QpCQkLQrVs3LFu2DH5+fspps2fPxq+//opJkyZh7ty5KF++PORyuU556vHjxxpPKqalpeHx48e4ceMGoqKi8Pvvv6NLly6F7pOux0baJCYmAsg9+aTw4MEDBAQEYP/+/Rg7diyWLVuGWrVqYfjw4Trd/+Ds2bOwt7dHvXr11GJSTAeAlJQUnDx5Ei1atMDHH38MJycnODg4oEaNGvj2228L3Y5RGblHQKlLSkoSAETv3r3/v707D6uq2vsA/j2MB0RARCYDRVRyJjURJxxQMGdzyEzQFO2+mpk3K7o5m1qmVq9oajnkkOUttWtdFQ3TEifUnBURRBNwQEFQEWG9f/ieHZszMB040/fzPPvRs8e1zuH89v6dtfbaOtfr37+/ACBycnKEEGXr6uji4iJeeOEFIYQQp06dEgDEW2+9pfM4LVu2FG5ubjrXUXWR1Daput0J8azLm5+fn4iJiZFtq6176LFjx8SyZctEzZo1pe46Q4cOFd26dRNCCK3dQxMSEmRlCAwMFPHx8RqPoWkqrvgxxowZI5RKpbh586bO8pe0d+9eAUD85z//kc3ftm1bmbqoluyq9OTJE9G8eXPRvXt32XwAwt7eXqSkpEjzVq5cKQAILy8v6e9FCCFiYmIEAGndoqIi0ahRIxEeHi7rwvrw4UPh7+8vevbsqVau8ePHCwcHB51lL68ePXqIFi1aiMePH0vzioqKRIcOHUSjRo2kearPr1OnTmpdY0NDQwUA8eWXX6rtPyoqSuffq2oKDQ2Vtvnxxx8FAFG7dm3RqFEjsXbtWrF27VrRqFEjYWdnJ/78889S69WhQwfx2WefiR07dogVK1aI5s2bCwBi+fLlsnqW9zMoqUaNGuL1119Xm//zzz8LAGLXrl1CCCGWLFki1aldu3Zi06ZNYvny5cLT01PUqlVL+hs3FYydQq0+5hw7VfsHIH744QdpXnZ2tvD29pY+r+IWLFggK2uPHj1EWlqaxuM2btxY9O7dW2fZyuPBgwfC1dVVREdHy+ZnZGQIFxcX2XxVjHr//ffV9gNAWFlZiXPnzqktU70fpU0zZ86Utpk8ebIUByIiIsR3330nFi1aJJycnERAQEC5bkkqrWt9UVGRaNeundSNNSUlRWPX+rlz54oaNWqIy5cvy+a///77wtraWutnpjJx4kRhbW2tcVmdOnXEK6+8IoQQIisrS6q7k5OTWLRokfjuu+9ERESE1vMHlY8pxuWZM2eqxbLiZSp+fRUaGiq7VlDFtSZNmoj8/Hxp/ueffy4AiDNnzkjzytO1XgghkpKSROvWrWXf5QYNGoiLFy+WeR9lcfDgQQFAbNq0STZ/165davNVMUd1XaGieh8aNGigdv2q+t6XZSp57hFCiAkTJkjLraysxJAhQ2S3y2hT1msjTe7evSs8PDxE586dZfPHjh0rvL291W5LeuWVV4SLi4vW2wxU+vTpIxo0aKA2Py8vT3YOOHHihBSrPD09xfLly8WmTZtEu3bthEKhEP/97391HseQLG6wO9VInDVr1tS5nmr5gwcPSl1XxcnJSdp/eY6ja3TQ4mbMmKHxF1c3Nzfp/wsXLkRBQUG5ujkPGzYMU6ZMwc6dOxEREYGdO3fiiy++0LlN06ZNERcXh7y8PBw6dAh79+7V2mUuNjYWjRs3LlNZPvzwQ2zYsAELFy7E559/XuY63L17FwBQq1Yt2XxXV1cAwM6dO9GqVSvY2tpq3L54i9G9e/dQWFiIzp07axzZskePHrIuWsHBwQCAl19+WfZ5q+ZfvXoV9evXx6lTp5CUlIQPP/xQKm/xfW7YsAFFRUWyXzNr1aqFR48e4eHDh3oZGC0rKwu//vor5syZgwcPHsj+9sLDwzFz5kz89ddfqFu3rjQ/Ojoa1tbWavuyt7fHmDFj1Oa/++67Ort0qhT/rFR/Ow8ePMDJkyfh6+sL4FkXv4YNG+KTTz6RdfHTpGTr3uuvv442bdrggw8+wOjRo+Hg4FChz6CkR48eaRzITKlUSsuL10mhUGDfvn1wcnIC8Gywr5CQEMTGxmLevHk662RMGDvVmXPsVPHx8cGgQYOk187OzoiMjMTHH3+MjIwMWbfvESNGoG3btrh9+zZ27tyJzMxM6ftQUq1atbT2MKiIuLg43L9/HyNGjJDt19raGsHBwRp79vzjH//QuK/Q0FA0bdpUbf6mTZu01qe4Bg0aSP9XfbZeXl74+eefpdjy3HPPYcSIEdi8eTPGjRtX6j7LYt26dThz5kypTyrYunUrOnfurPYZhIWFYeHChThw4ICsdbOkR48ewc7OTuMypVKpFgPv3r2LLVu2YPjw4QCAIUOGoEWLFpg3bx4mTJhQrjqSnCnH5coYM2aM7G9QFd+vXr2qcUDQsqhZsyaaNWuGkJAQ9OjRAxkZGVi4cCEGDhyIgwcPylqKK2Pr1q1wcXFBz549Zd+/Nm3awMnJCfHx8bLbs/z9/REeHq5xX1FRUWo9nry8vMp821KrVq3U5k2ZMgVDhgzBzZs38f3336OwsFDt9ihNynptVFJRURFGjhyJ+/fvy558IYTADz/8gGHDhkEIIXuvwsPDsWXLFpw4cUIaSLQyZSoeqw4fPixdv/fv3x/+/v6YN28eIiIidNbfUCwukS8ezHR58OABFApFub64ubm58PDwKPdxVNuUpkWLFggLC9O6PDU1FYsWLUJsbKyUNJRFnTp1EBYWhs2bN+Phw4coLCzEkCFDdG7j7OwslWXAgAHYvHkzBgwYgBMnTqgFhnbt2ql1wdOmQYMGGDVqFFatWiXrxl1WokRX2dDQULz88suYPXs2li5diq5du2LgwIF49dVXZV/unTt3Yt68eTh16pTsPmZNXRP9/Pxkr11cXABASj5Lzlfd85SUlATgWeDVJjs7W3ZBraqPrlHrc3NzZYmAtbW12n1yKleuXIEQAtOnT8f06dM1rnPr1i1ZIq+tG13dunU1Xsw1bdpU40WwLqoTUceOHWXvo5+fHzp16lSh0bTt7OwwadIkvPHGG0hMTESnTp3K/BnUqFEDWVlZsvl16tSBtbU1HBwcNN7rrrovX1UX1b/9+vWTfR/bt28Pf39/k3u6AmOnOnOOnSoNGzZUiz+qHxdSU1NliXy9evWkex9HjBiB8ePHIywsDJcuXVK72BRClPo0jqysLNkFpIODgxRXS1J9t7t3765xubOzs+y1jY2N1idhaIt5ui4YtVHVe9iwYbIfCIcOHYpRo0bh0KFDeknkc3JyEBMTg2nTpqmdi0pKSkrC6dOntZ4nVCM03759G4WFhdJ8JycnODk5wcHBQeuF/ePHj9VioK2trex7YWVlheHDh2PmzJlIS0tTO6dS2ZlyXK6Mkn8zquumkveYl9XTp08RFhaGrl27ypLJsLAwNGvWDIsWLcLHH3+sdXtVt3AVFxcXrffVJyUlITs7W+v7VHKEdG3xSNsypVKp83xXmueffx7PP/88ACAyMhK9evVCv379cOTIEZ0xu6zXRiW9+eab2LVrF7755hvZOfD27du4f/8+Vq1apXXcBdV7pe39L+/1mr+/v5TEA89iXr9+/bBx40Y8ffoUNjbGlzYbX4mqmIuLC3x8fHD69Gmd650+fRrPPfec1l+dS7px4ways7PRsGFDAECjRo1gY2Oj8zj5+fm4dOmS3h5pMWPGDNStW1c2yJrqj/v27dtITU2Fn5+fxtbGV199FdHR0cjIyEDv3r2lluyyGjx4MEaNGoUtW7Zo/IWvPP71r39hw4YN+PjjjzFw4MAybVO7dm0A6kFc9Rzlw4cP4z//+Q92796N119/HYsXL8bhw4fh5OSEgwcPon///ujSpQuWL18Ob29v2NraYu3atRrvsdbUOq1rvuoCWTWI0KJFi2T3OBVXMom4d++edG+1Np9++qnscR316tXTeu+lqgzvvPOO1l94VX/DKtqOrW1+dnZ2mVqt7OzspBZR1WOzSg40AzwbbKb4PZflobqgVSXlZf0M/vjjD+mef5WUlBTUr18f3t7eSE9PV9tONU9Vl9LqVNELDkNh7LSs2KkPQ4YMwerVq3HgwAG1eHPv3j3Zoxo1GTx4MH777TfpdVRUlNZnqKu+2xs2bNA4OFzJCzB7e3utPW+0xbaSia02qoQX0B4HrK2tUbt2bb29759++imePHmC4cOHS3/DN27cAPDsvU5NTYWPj490D23Pnj3x7rvvatyX6oeaF198EdeuXZPmz5w5E7NmzYK3tzcKCwtx69YtWTLy5MkT3L17V6qzajBVV1dXtfOjart79+4xka8EU4zL2pLBsny3VEq73iqvAwcO4OzZs1iyZIlsfqNGjdCkSZNSx/Pw9vaWvV67di1Gjx6tcd2ioiJ4eHhg06ZNGpeX/IFN1/WfpmWFhYW4ffu2zvKquLm5lfo3MWTIEEyYMAGXL19GYGCg1vXKem1U3OzZs7F8+XIsXLhQGpdBRRXTX3vtNa2NL6rHI2p7/729vREfH6/2w3F5r9cKCgqQl5en9YdkQ7K4RB541kK2cuVK/P7772rPAAaeDWaWmppapkFfVDZs2AAA0sWKo6MjevTogb179+LatWtqIzQCwPfff4/8/HwMHTq0gjWRS0tLw5UrV2Td+lRUIzbeu3dP44XmoEGDMGHCBBw+fBjfffdduY+dn5+PoqIi2QBmFRUQEIDXXnsNK1eulP0ypovq18OUlBSNy9u3b4/27dvjo48+wubNmzFy5Ehs2bIF48aNww8//AClUondu3fLWunXrl1b6boUFxAQAEDeIlealJQUtUE6SoqMjJT9HesK+qq/DVtb20r9YqvLW2+9hfXr15e6XmhoqPRM5BYtWsDW1lbjc4Vv3rypteWoNKrRT1Xbl/UzaNWqlVrXNFVyEBQUhIMHD6p1wT9y5AgcHR2li+A2bdoAgNY6qf5mTQljp6vacnOPnapePMUvglSDFukaBRr4u9tiybo9ffoU169fR//+/XVuv3jxYlmiq+lCUEX13fbw8Kiy2FYysdVGlfAC2uPAkydPcOfOnQrHtpLS0tJw7949NGvWTG3Z/PnzMX/+fJw8eRJBQUEICAhAbm5uqe9TyVsJVN8P1Y+gx48fx0svvSQtP378OIqKiqTlVlZWCAoKwrFjx/DkyRNZwqB6woK+6m/JTC0uq1rP79+/L4upZflulUdpPX6Ky8zMBKD5x4SCggI8ffpU5/Ylrxc0fQ9VAgICsHfvXnTs2FHvo+EDwPXr13W24hcXHx8veyqAJtrieEllvTZSiY2NxaxZszBlyhS89957avtTDY5ZWFhYaqzS9v4HBQXhq6++woULF2Q9RY8cOSItB56dW7y8vLRerymVyjLfklLtDHRvvkElJSUJR0dH0bRpU7UBFO7evSuaNm0qnJ2dy/3MTX9/f9nzZg8ePCisrKxE165d1QZkuHr1qvDy8hK+vr56exbywYMHxbZt22TT3LlzBQDx7rvvim3btoknT55orc+6devErFmzZGUtOWDTvXv3pH0Up3oW8tdffy3NK8+zkEsOCnXlyhVhbW0tgoKCylR3IYTw9fUVo0aNks3LyspSezbyuXPnBACxbNkyIYQQU6dOFY6OjrJBh1JSUoSjo6PagCyA+rPKtQ0oVPJzKywsFAEBAaJRo0Yan59c8vmvQgjh5uam9nzoyuratatwc3PTONha8TLo+vxCQ0NFs2bNNO7/3LlzIi4urtTp+PHjsu0GDBggrK2txYULF6R558+fF9bW1uJ//ud/pHl5eXniwoUL4vbt2xrLrZKTkyMCAgKEu7u7NChORT6DkrZs2aL2N3n79m3h6uoqhg8fLlu3VatWwtnZWVbW3bt3CwDik08+KfVYxoax03Jip2r/0DLYXVBQkDRP2/emX79+QqFQiKSkJNn8P//8U22/lZWdnS2cnZ1FaGioxve5eBmjoqJEjRo1NO5HU4xX+f3338sU25KTk6VtHj9+LDw8PESDBg1kf+OqQVK///57ad7t27fFhQsXtA6Ap2uwu8TERLW/YdUxRo8eLbZt2ybu378vhBBi1qxZWgefunfvnigoKNB4fJWHDx8KNzc30bdvX9n81157TTg6Ooq7d+9K85YuXSoAiFWrVknzHj16JBo0aCCaNm2q8zhUNqYWl3fu3CkAiB07dkjzcnNzhZ+fX5kHuysZ11TXYcW/G8OHDxeurq46y6Jy/PhxAUBERUXJ5icmJgorKyvxxhtvlGk/ZbF//34BQBpYtbiCggLZ+6dt0FRd57ZHjx6VKU7FxcXJBrHLzMxU29eTJ09E69athYODg+ya6ebNm+LChQuyWFuea6MtW7YIKysrMXLkSLVr9OJGjx4t7OzsZIMYqpTleu369etanyNft25d2UDOb731lgAg9uzZIyu/s7OzeOmll0o9lqFYZIt8w4YN8c0332DEiBFo0aIFxo4dC39/f6SmpuLrr7/GvXv3sGXLFo2/aP33v//FxYsX8fTpU2RmZuLXX39FXFwc6tWrh59++kkaQAEAOnXqhKVLl2LKlClo2bKl1M3j4sWLWL16NaysrLB9+/Yyd8U8ePCgxudjt2zZEi1bttT4S6xq3y+++GKpXS113Tessn//fkyePBlDhgxBo0aN8OTJExw8eBA//vgj2rZtW6ZBzspC1bJUlpZdlQEDBmDbtm2y1qP169dj+fLlGDRoEAICAvDgwQOsXr0azs7OUktCnz59sGTJEkRERODVV1/FrVu3EBsbi4YNG5baXa08rKys8NVXX6F3795o1qwZxowZg7p16+Kvv/5CfHw8nJ2dZY9tSUxMRFZWFgYMGKC3MgDPfgXt1KkTWrRogejoaDRo0ACZmZlISEjAjRs38Oeff1Zq/xW5Rx541mq0b98+dO/eHZMnTwYAfPHFF3Bzc5MNQHb06FF069ZN1uoVGxuL7du3o1+/fvDz80N6ejrWrFmDtLQ0bNiwQWoJKu9noMmQIUPQvn17jBkzBufPn4e7uzuWL1+OwsJC2S0OALB06VL07NkTnTp1woQJE5CdnY0lS5agcePGWgfaMmaMnZqZY+xUady4McaOHYtjx47B09MTa9asQWZmpqzH0kcffYQ//vgDERER8PPzQ1ZWFn744QccO3YMb775ptrtOnFxcXB0dETPnj0rV9linJ2dsWLFCowaNQqtW7fGK6+8gjp16iAtLQ0///wzOnbsWOlHnlXkHnl7e3ssWrQIUVFR6NKlC0aNGoW0tDR8/vnn6Ny5s+yZy8uWLcPs2bPVWsmWLVuG+/fvS63Y//nPf6Ru82+++SZcXFzQunVrtUcIqrrYN2vWTPY3PG3aNPz000/o27cvRo8ejTZt2iAvL08aKC81NVXnvdQODg6YO3cuJk6ciKFDhyI8PBwHDx7Exo0b8dFHH8kGkZwwYQK++uorTJw4EZcvX4afnx82bNiAa9euVctjyiyBqcXlXr16wc/PD2PHjsW0adNgbW2NNWvWSN9XfWnTpg2+++47TJ06FS+++KJ0v7O2dXv27In169cjJycHvXr1Qnp6Ov73f/8XDg4OmDJlit7KFRoaigkTJmDBggU4deoUevXqBVtbWyQlJWHr1q34/PPPSx1rRZeK3iM/YcIE5OTkoEuXLqhbty4yMjKwadMmXLx4EYsXL5bd+hkTE4P169dLtxwCZb82Onr0KCIjI1G7dm306NFD7RaDDh06SL1/Fi5ciPj4eAQHByM6OhpNmzZFVlYWTpw4gb1796qNZVTSc889hylTpmDRokUoKCjAiy++iO3bt+PgwYPYtGmT7BaNmJgYfP/993j55ZcxdepUuLi44Msvv0RBQQHmz59f7vez2hj6lwRDOnPmjHj11VeFl5eXsLKyEgCEUqnU+NiZko8DsrOzE15eXqJnz57i888/lz12rKSDBw+KAQMGCHd3d6FQKAQA4eHhIXv0kS6lPUKp+KNutG2r6xFKupT8NfDKlSsiMjJSNGjQQDg4OAilUimaNWsmZs6cKXJzc/VyDJWkpCRhbW1d5lYl1eMjDh48KJs3YsQI4efnJ+zt7YWHh4fo27evWmvw119/LRo1aiTs7e3F888/L9auXavxESmoRIu8ysmTJ8XgwYNF7dq1hb29vahXr54YNmyY2Ldvn2y99957T/j5+en8tbKikpOTRWRkpPDy8hK2traibt26om/fvuLf//63tE5FW+QrIzExUYSFhYkaNWqImjVrigEDBqg9Ikn1vhb/u9+zZ4/o2bOnVB9XV1fRq1cvtfdUpayfgTZZWVli7Nixonbt2sLR0VGEhoZq/TuPi4sT7du3F0qlUri5uYlRo0aV+btvrBg7zT92Ft//7t27RcuWLaX4WHKfe/bsEX379hU+Pj7C1tZW1KxZU3Ts2FGsXbtWY/wKDg4Wr732Wqnlqoj4+HgRHh4uXFxchFKpFAEBAWL06NGymF/RFvnK+Pbbb0WrVq2Evb298PT0FJMmTVL721edc0o+EkrXY++Kt16WpO3cJMSzx/XFxMSIhg0bCjs7O+Hu7i46dOggPv30U409GjRZtWqVCAwMFHZ2diIgIEAsXbpU4+edmZkpoqKihJubm7C3txfBwcE6H0VFFWMqcVmIZ+f64OBgYWdnJ/z8/MSSJUvK9fi5srTI5+bmildffVW4uroKAKU+iu7hw4dizpw5omnTpsLBwUG4uLiIvn37ipMnT5a5XuWxatUq0aZNG+Hg4CBq1qwpWrRoId59911Zb8mKtMhX1LfffivCwsKEp6ensLGxEbVq1RJhYWGynhMqqkd4low/Zbk20vV41ZKfoRDP4sfEiROFr6+vsLW1FV5eXqJHjx6yXj66FBYWivnz54t69eoJOzs70axZM7Fx40aN6yYnJ4tBgwYJZ2dn4eDgILp37y6OHj1apuMYikUn8iWtX79eKBQKjV0M9WnOnDkCgPjXv/5VpcexRN27d6+yC8Tq9PjxY+Hl5SU+++wzQxeFqFSMnaZPU+zUdhFZGSdPnhQKhaLKLo6J6BnGZSLzx0S+hIULF2q9d0Wf3njjDQFArFy5skqPY2kOHz4sbG1tRWpqqqGLUikrVqwQvr6+4vHjx4YuClGZMHaaNk2xsyoS+eHDh4uhQ4fqdZ9EpBnjMpF5UwhRwWc1EBERkdmqX78+mjdvjp07dxq6KERERFSC5oeoEhEREREREZFRYos8ERERERERkQlhizwRERERERGRCWEiT0RERERERGRCbAxdAGNUVFSEmzdvombNmlAoFIYuDhGZICEEHjx4AB8fH1hZmc9vpoyPRFRZjI9ERJqVJz4ykdfg5s2b8PX1NXQxiMgMXL9+Hc8995yhi6E3jI9EpC+Mj0REmpUlPjKR16BmzZoAnr2Bzs7OBi4NEZminJwc+Pr6SvHEXDA+ElFlMT4SEWlWnvjIRF4DVXcoZ2dnBmIiqhRz617J+EhE+sL4SESkWVnio/ncmERERERERERkAZjIExEREREREZkQJvJEREREREREJoT3yFdCYWEhCgoKDF0Mi2NnZ2dWj6shIqKqwfO0Ydja2sLa2trQxSCiEhgTDU+f8ZGJfAUIIZCRkYH79+8buigWycrKCv7+/rCzszN0UYiIyAjxPG14rq6u8PLyMrsB7YhMEWOicdFXfGQiXwGqL4KHhwccHR15kqpGRUVFuHnzJtLT0+Hn58f3noiI1PA8bThCCDx8+BC3bt0CAHh7exu4RETEmGgc9B0fmciXU2FhofRFqF27tqGLY5Hq1KmDmzdv4unTp7C1tTV0cYiIyIjwPG14Dg4OAIBbt27Bw8OD3eyJDIgx0bjoMz7yRuNyUt1X4ujoaOCSWC5Vl/rCwkIDl4SIiIwNz9PGQfX+835cIsNiTDQ++oqPBk3kDxw4gH79+sHHxwcKhQLbt2+XLR89ejQUCoVsioiIKHW/sbGxqF+/PpRKJYKDg3H06FG9l51dUgyH7z0REZWG5wrD4vtPZFz4nTQe+vosDJrI5+XloVWrVoiNjdW6TkREBNLT06Xp22+/1bnP7777DlOnTsXMmTNx4sQJtGrVCuHh4dK9CERERERERESmzKCJfO/evTFv3jwMGjRI6zr29vbw8vKSplq1aunc55IlSxAdHY0xY8agadOm+PLLL+Ho6Ig1a9bou/hUwsWLF9G+fXsolUoEBQUZujhERERUAs/VRETPmHo8NPrB7vbv3w8PDw/UqlUL3bt3x7x587QO1PDkyRMkJiYiJiZGmmdlZYWwsDAkJCRUeVmXxl2u8mOovN2zcbUdq6xmzpyJGjVq4NKlS3BycjJ0cfQvfgHQLab09YiIyChV53ka4LmaiIwX46Hpx0OjTuQjIiIwePBg+Pv7Izk5GR988AF69+6NhIQEjSP83blzB4WFhfD09JTN9/T0xMWLF7UeJz8/H/n5+dLrnJwc/VXCgiQnJ6NPnz6oV6+eoYtCRHrC+EhkXniu1h/GRyLTZurx0KhHrX/llVfQv39/tGjRAgMHDsTOnTtx7Ngx7N+/X6/HWbBgAVxcXKTJ19dXr/s3FkVFRfjkk0/QsGFD2Nvbw8/PDx999BEA4MyZM+jevTscHBxQu3ZtjB8/Hrm5ubLtv/rqKzRp0gRKpRLPP/88li9fLi1TKBRITEzEnDlzoFAoMGvWrOqsGhFVEUuJj0TGgudq08H4SFS1GA91M+pEvqQGDRrA3d0dV65c0bjc3d0d1tbWyMzMlM3PzMyEl5eX1v3GxMQgOztbmq5fv67XchuLmJgYLFy4ENOnT8f58+exefNmeHp6Ii8vD+Hh4ahVqxaOHTuGrVu3Yu/evZg0aZK07aZNmzBjxgx89NFHuHDhAubPn4/p06dj/fr1AID09HQ0a9YM//znP5Geno533nnHUNUkIj2ylPhIZCx4rjYdjI9EVYvxUDej7lpf0o0bN3D37l14e3trXG5nZ4c2bdpg3759GDhwIIBnv+Ts27dP9sGWZG9vD3t7+6oostF48OABPv/8cyxbtgxRUVEAgICAAHTq1AmrV6/G48eP8c0336BGjRoAgGXLlqFfv374+OOP4enpiZkzZ2Lx4sUYPHgwAMDf3x/nz5/HypUrERUVBS8vL9jY2MDJyUnnjyZEZFosIT4SGQueq00L4yNR1WE8LJ1BE/nc3FxZ63pKSgpOnToFNzc3uLm5Yfbs2Xj55Zfh5eWF5ORkvPvuu2jYsCHCw8OlbXr06IFBgwZJifrUqVMRFRWFtm3bol27dvjss8+Ql5eHMWPGVHv9jMmFCxeQn5+PHj16aFzWqlUr6YsAAB07dkRRUZE0+ENycjLGjh2L6OhoaZ2nT5/CxcWlWspPRERk7niuJiJ6hvGwdAZN5I8fP45u3bpJr6dOnQoAiIqKwooVK3D69GmsX78e9+/fh4+PD3r16oW5c+fKfv1MTk7GnTt3pNfDhw/H7du3MWPGDGRkZCAoKAi7du1SGwDP0jg4OFR4W9X9JqtXr0ZwcLBsmaZBB4mIiKj8eK4mInqG8bB0Bk3ku3btCiGE1uW7d+8udR+pqalq8yZNmqSzK70latSoERwcHLBv3z6MGzdOtqxJkyZYt24d8vLypF+2/vjjD1hZWSEwMBCenp7w8fHB1atXMXLkSEMUn4iIyOzxXE1E9AzjYelM6h55qjilUon33nsP7777Luzs7NCxY0fcvn0b586dw8iRIzFz5kxERUVh1qxZuH37Nt58802MGjVK6skwe/ZsTJ48GS4uLoiIiEB+fj6OHz+Oe/fuST0pqArw2fVERBaD52oiomcYD0vHRN6CTJ8+HTY2NpgxYwZu3rwJb29vvPHGG3B0dMTu3bvx1ltv4cUXX4SjoyNefvllLFmyRNp23LhxcHR0xKJFizBt2jTUqFEDLVq0wJQpUwxXISIiIjPDczUR0TOMh7ophK6+7RYqJycHLi4uyM7OhrOzs2zZ48ePkZKSAn9/fyiVSgOV0LIZ7DMwROs4W+RNlq44YsrMtV5kPnieNg66PgdzjSPmWi8ybYyJxkdf8dGkniNPREREREREZOmYyBMRERERERGZECbyRERERERERCaEiTwRERERERGRCWEiT0RERERERGRCmMgTERERERERmRAm8kREREREREQmhIk8ERERERERkQlhIk9ERERERERkQpjIk07169fHZ599prf9Xbx4Ee3bt4dSqURQUJDe9ktERGSpeK4mInpG3/HQmNkYugBmJX5B9R2rW0z1HUuPZs6ciRo1auDSpUtwcnICAFy+fBnTpk3DH3/8gSdPnqBly5aYO3cuunXrZuDSEhGRWanO8zTAczURGS/GQ73ZvXs3Zs6ciXPnzkGpVKJLly5YvHgx6tevX6XHZYs8Vavk5GR06tQJ9erVQ+3atQEAffv2xdOnT/Hrr78iMTERrVq1Qt++fZGRkWHg0hIREVkenquJiMomJSUFAwYMQPfu3XHq1Cns3r0bd+7cweDBg6v82EzkLUheXh4iIyPh5OQEb29vLF68GF27dsWUKVMAALdu3UK/fv3g4OAAf39/bNq0SW0fSUlJ6NKlC5RKJZo2bYq4uDgoFAps37691OMrFAokJiZizpw5UCgUmDVrFu7cuYOkpCS8//77aNmyJRo1aoSFCxfi4cOHOHv2rJ7fASIiIuPGczUR0TOGjof79++HQqHA/fv3pXmnTp2CQqFAamoqACAxMRGFhYWYN28eAgIC0Lp1a7zzzjs4deoUCgoK9PAuaMeu9RZk2rRp+O2337Bjxw54eHjggw8+wIkTJ6T730aPHo2bN28iPj4etra2mDx5Mm7duiVtX1RUhMGDB8PT0xNHjhxBdna29EUqi/T0dISFhSEiIgLvvPMOnJycUKNGDQQGBuKbb75B69atYW9vj5UrV8LDwwNt2rTR8ztARERk3HiuJiJ6xtDxsCzatGkDKysrrF27FqNHj0Zubi42bNiAsLAw2Nra6vVYJTGRtxC5ubn4+uuvsXHjRvTo0QMAsH79ejz33HMAnt379t///hdHjx7Fiy++CAD4+uuv0aRJE2kfe/fuxcWLF7F79274+PgAAObPn4/evXuXqQxeXl6wsbGBk5MTvLy8ZPsdOHAgatasCSsrK3h4eGDXrl2oVauWXupORERkCniuJiJ6xhjiYVn4+/tjz549GDZsGCZMmIDCwkKEhITgl19+0dsxtGHXeguRnJyMJ0+eIDg4WJrn5uaGwMBAAMCFCxdgY2Mj+2X9+eefh6urq/T6woUL8PX1lb4IABASElKpcgkhMHHiRHh4eODgwYM4evQoBg4ciH79+iE9Pb1S+yYiIjIlPFcTET1jrPGwpIyMDERHRyMqKgrHjh3Db7/9Bjs7OwwZMgRCCL0eqyS2yJNB/frrr9i5cyfu3bsHZ2dnAMDy5csRFxeH9evX4/333zdwCYmIiCwbz9VEZImsrJ61eRdPyEve9x4bGwsXFxd88skn0ryNGzfC19cXR44cQfv27auufFW25zI4cOAA+vXrBx8fH7VBBwoKCvDee++hRYsWqFGjBnx8fBAZGYmbN2/q3OesWbOgUChk0/PPP1/FNTF+AQEBsLW1xZEjR6R59+7dw+XLlwE8+wXr6dOnSExMlJZfunRJNrhDkyZNcP36ddmv74cPH65UuR4+fAjg7y+KipWVFYqKiiq1b72o7kdzEBGRxeK5mojoGWOIh3Xq1AEA2fanTp2SrfPw4UO12GhtbQ0AVR4fDZrI5+XloVWrVoiNjVVb9vDhQ5w4cQLTp0/HiRMn8OOPP+LSpUvo379/qftt1qwZ0tPTpen333+viuKbFCcnJ4wdOxbTpk3Dr7/+irNnz2L06NHSH15gYCAiIiIwYcIEHDlyBImJiRg3bhwcHBykfYSFhaFx48aIiorCn3/+iYMHD+Jf//pXpcoVEhKCWrVqSftUPac2JSUFffr0qdS+iYiITAnP1UREzxhDPGzYsCF8fX0xa9YsJCUl4eeff8bixYtl6/Tp0wfHjh3DnDlzkJSUhBMnTmDMmDGoV68eXnjhBf28GVoYNJHv3bs35s2bh0GDBqktc3FxQVxcHIYNG4bAwEC0b98ey5YtQ2JiItLS0nTu18bGBl5eXtLk7u5eVVUwKYsWLULnzp3Rr18/hIWFoVOnTrL7StauXQsfHx+EhoZi8ODBGD9+PDw8PKTlVlZW2LZtGx49eoR27dph3Lhx+OijjypVJnd3d+zatQu5ubno3r072rZti99//x07duxAq1atKrVvIiIiU8NzNRHRM4aOh7a2tvj2229x8eJFtGzZEh9//DHmzZsnW6d79+7YvHkztm/fjhdeeAERERGwt7fHrl27ZD8qVAWTukc+OzsbCoVCNoiBJklJSfDx8YFSqURISAgWLFgAPz+/qi9gt5iqP0YlODk5YcOGDdiwYYM07+eff5b+7+XlhZ07d8q2GTVqlOx148aNcfDgwQqXoWR3FABo27Ytdu/eXeF9EhERlYmRn6cBnquJqJowHpZJx44dcfr0adm8koPYvfLKK3jllVcqfIyKMplE/vHjx3jvvfcwYsQIaaAVTYKDg7Fu3ToEBgYiPT0ds2fPRufOnXH27FnUrFlT4zb5+fnIz8+XXufk5Oi9/EREpojxkYhIM8ZHIjIkk3j8XEFBAYYNGwYhBFasWKFz3d69e2Po0KFo2bIlwsPD8csvv+D+/fv4/vvvtW6zYMECuLi4SJOvr6++q2AR5s+fDycnJ42TPp/XSETVh/GRyLzwXK0/jI9Eps3U46HRt8irkvhr167h119/1dkar4mrqysaN26MK1euaF0nJiYGU6dOlV7n5ORYTDDev39/pfeh6l7SpUsXDBs2TOM6VX2PiEWIX2AS3aDIvFhyfCQyFjxXGyfGR6Lqx3j4N6NO5FVJfFJSEuLj41G7du1y7yM3NxfJyclq90sUZ29vD3t7+8oUlQC4ubnBzc3N0MUgIj1ifCQyLzxX6w/jI5FpM/V4aNCu9bm5uTh16pQ0qEpKSgpOnTqFtLQ0FBQUYMiQITh+/Dg2bdqEwsJCZGRkICMjA0+ePJH20aNHDyxbtkx6/c477+C3335DamoqDh06hEGDBsHa2hojRoyo7uoRERERERER6Z1BW+SPHz+Obt26Sa9V3ZOioqIwa9Ys/PTTTwCAoKAg2Xbx8fHo2rUrACA5ORl37tyRlt24cQMjRozA3bt3UadOHXTq1AmHDx9GnTp19Fr2kqMVUvXhe09ERKXhucKw+P4TGRd+J42Hvj4LgybyXbt21VmRslQyNTVV9nrLli2VLZZOtra2AICHDx+axL0T5kjVI8Pa2trAJakivBeeiKjCeJ42Dg8fPgTw9+dBRIbBmGh89BUfjfoeeWNkbW0NV1dX3Lp1CwDg6OgIhUJh4FJZjqKiIty+fRuOjo6wseGfLxERyfE8bVhCCDx8+BC3bt2Cq6ur+f7oTmQiGBONh77jIzOhCvDy8gIA6QtB1cvKygp+fn4MQkREpBHP04bn6uoqfQ5EZFiMicZFX/GRiXwFKBQKeHt7w8PDAwUFBYYujsWxs7ODlZVBx2kkIiIjxvO0Ydna2rIlnsiIMCYaD33GRybylWBtbc0TFRERkZHieZqI6G+MieaFzZpEREREREREJoSJPBEREREREZEJYSJPREREREREZEKYyBMRERERERGZECbyRCXFLzB0CYiIiIiIiLRiIk9ERERERERkQpjIExEREREREZkQJvJEREREREREJoSJPBEREREREZEJYSJPREREREREZEKYyBMREVHF8UkfRERE1Y6JPBEREREREZEJYSJPREREREREZEKYyBMRERERERGZkAol8jdu3EBubq7a/IKCAhw4cKDShSIiIiIiIiIizcqVyKenp6Ndu3aoV68eXF1dERkZKUvos7Ky0K1bN70XkoiIiIwMB7kjIiIymHIl8u+//z6srKxw5MgR7Nq1C+fPn0e3bt1w7949aR0hRJn3d+DAAfTr1w8+Pj5QKBTYvn27bLkQAjNmzIC3tzccHBwQFhaGpKSkUvcbGxuL+vXrQ6lUIjg4GEePHi1zmYiIiIiIiIiMWbkS+b179+KLL75A27ZtERYWhj/++APe3t7o3r07srKyAAAKhaLM+8vLy0OrVq0QGxurcfknn3yCL774Al9++SWOHDmCGjVqIDw8HI8fP9a6z++++w5Tp07FzJkzceLECbRq1Qrh4eG4detWeapKREREREREZJTKlchnZ2ejVq1a0mt7e3v8+OOPqF+/Prp161buZLl3796YN28eBg0apLZMCIHPPvsMH374IQYMGICWLVvim2++wc2bN9Va7otbsmQJoqOjMWbMGDRt2hRffvklHB0dsWbNmnKVjYiIiIiIiMgYlSuRb9CgAU6fPi2bZ2Njg61bt6JBgwbo27ev3gqWkpKCjIwMhIWFSfNcXFwQHByMhIQEjds8efIEiYmJsm2srKwQFhamdRsiIiIiIiIiU1KuRL53795YtWqV2nxVMh8UFKSvciEjIwMA4OnpKZvv6ekpLSvpzp07KCwsLNc2AJCfn4+cnBzZREREjI9ERNowPhKRIZUrkf/oo4+wdetWjctsbGzwww8/4OrVq3opWHVasGABXFxcpMnX19fQRSIiMgqMj0REmjE+EpEhlSuRt7GxgbOzs87l9erVq3ShAMDLywsAkJmZKZufmZkpLSvJ3d0d1tbW5doGAGJiYpCdnS1N169fr2TpiYjMA+MjEZFmjI9EZEjlSuRLc/36dbz++ut62Ze/vz+8vLywb98+aV5OTg6OHDmCkJAQjdvY2dmhTZs2sm2Kioqwb98+rdsAzwbtc3Z2lk1ERMT4SESkDeMjERmSXhP5rKwsrF+/vszr5+bm4tSpUzh16hSAZwPcnTp1CmlpaVAoFJgyZQrmzZuHn376CWfOnEFkZCR8fHwwcOBAaR89evTAsmXLpNdTp07F6tWrsX79ely4cAH/+Mc/kJeXhzFjxuirmkREREREREQGY1OelX/66Sedy8t7f/zx48fRrVs36fXUqVMBAFFRUVi3bh3effdd5OXlYfz48bh//z46deqEXbt2QalUStskJyfjzp070uvhw4fj9u3bmDFjBjIyMhAUFIRdu3apDYBHpFfxC4BuMYYuBRERERERWYByJfIDBw6EQqGAEELrOgqFosz769q1a6n7mjNnDubMmaN1ndTUVLV5kyZNwqRJk8pcDiIiIiIiIiJTUa6u9d7e3vjxxx9RVFSkcTpx4kRVlZOIiIiIiIiIUM5Evk2bNkhMTNS6vLTWeiKjFb/A0CUgIiIiIlLH61TSoFyJ/LRp09ChQwetyxs2bIj4+PhKF4rI4jBAExERERFRGZXrHvnOnTvrXF6jRg2EhoZWqkBEREREREREpJ1eHz9HRERERERERFWrXIn8rVu3ZK9PnTqFqKgodOzYEUOGDMH+/fv1WTYiIiIiIiIiKqHco9arkvlDhw6hXbt2uHbtGjp27IicnBz07NkTBw4cqJKCEhERERERmR2OlUQVUK575IuPSD9r1iyMGjUKX3/9tTRvypQpmD17Nvbt26e/EhIREREREZk7VULfLUbzMk3zyWJV+B75s2fPIjo6WjYvOjoap0+frnShiIiIiIiILBJb6KkMytUiDwAPHjyAUqmEUqmEvb29bJlSqcTDhw/1VjgiIiIiIiIikit3i3zjxo1Rq1YtpKam4vjx47Jl586dg4+Pj94KR2TU+GspEREREekDryupnMrVIh8fHy977e3tLXudkpKC8ePHV75UREREZBi8D5OIiMjolSuRDw0N1bn8rbfeqlRhiIiIiIiIqBT80dXiVXiwOyIiIiIiIiKqfhVO5Pv06YP09HS1/xMRERERERFR1alwIn/gwAE8evRI7f9ERERkYjjIEhFR9WLcpUpi13oiIiIiIiIiE8JEnoiIiIiIiMiEMJEnIiIi88durERkLhjPCEzkiYiIiIiIiEyK0Sfy9evXh0KhUJsmTpyocf1169apratUKqu51ERERERERBroq0WdLfMWzcbQBSjNsWPHUFhYKL0+e/YsevbsiaFDh2rdxtnZGZcuXZJeKxSKKi0jERERERERUXWpcCJfr1492Nraqv1f3+rUqSN7vXDhQgQEBCA0NFTrNgqFAl5eXlVSHiIiIiIiogphKzrpSYW71p89exa+vr5q/69KT548wcaNG/H666/rbGXPzc1FvXr14OvriwEDBuDcuXNVXjYiIiIiIiKi6mD098gXt337dty/fx+jR4/Wuk5gYCDWrFmDHTt2YOPGjSgqKkKHDh1w48YNrdvk5+cjJydHNhEREeMjmSi2eFE1YHwkIkOqUCK/fv16/Pzzz9Lrd999F66urujQoQOuXbumt8KV9PXXX6N3797w8fHRuk5ISAgiIyMRFBSE0NBQ/Pjjj6hTpw5WrlypdZsFCxbAxcVFmqqjdwERkSlgfCQi0ozxkYgMqUKJ/Pz58+Hg4AAASEhIQGxsLD755BO4u7vj7bff1msBVa5du4a9e/di3Lhx5drO1tYWL7zwAq5cuaJ1nZiYGGRnZ0vT9evXK1tcotKxxYhMAOMjEZFmjI9EZEgVGuzu+vXraNiwIYBn3d1ffvlljB8/Hh07dkTXrl31WT7J2rVr4eHhgT59+pRru8LCQpw5cwYvvfSS1nXs7e1hb29f2SISEZkdxkciIs0YH4nIkCrUIu/k5IS7d+8CAPbs2YOePXsCAJRKJR49eqS/0v2/oqIirF27FlFRUbCxkf/2EBkZiZiYGOn1nDlzsGfPHly9ehUnTpzAa6+9hmvXrpW7JZ+IiIj0hD2QiIiI9KpCiXzPnj0xbtw4jBs3DpcvX5Zau8+dO4f69evrs3wAgL179yItLQ2vv/662rK0tDSkp6dLr+/du4fo6Gg0adIEL730EnJycnDo0CE0bdpU7+UiIiKiasAfAoiIdFPFScZLi1GhrvWxsbH48MMPcf36dfzwww+oXbs2ACAxMREjRozQawEBoFevXhBCaFy2f/9+2eulS5di6dKlei8DERERmZj4BUC3mNLXIyKqSoxFVAUqlMi7urpi2bJlavNnz55d6QIRERGRidPnRStbl4iIiNRUKJEHgPv37+Po0aO4desWioqKpPkKhQKjRo3SS+GIiIiIiIioDPjDp0WpUCL/n//8ByNHjkRubi6cnZ2hUCikZUzkiYiIiIiIiKpOhQa7++c//4nXX38dubm5uH//Pu7duydNWVlZ+i4jEREREREREf2/CiXyf/31FyZPngxHR0d9l4eIiIhMWVV17WSXUSIiIkmFEvnw8HAcP35c32UhIiIiIiIyH/wRkqpIhe6R79OnD6ZNm4bz58+jRYsWsLW1lS3v37+/XgpHRERERERERHIVSuSjo6MBAHPmzFFbplAoUFhYWLlSEREREZXEZzETEREBqGAiX/xxc0RERERERFQCu9VTFarQPfJEREREZoMX20REZGLK3CL/xRdfYPz48VAqlfjiiy90rjt58uRKF4yIiIiIiIiI1JU5kV+6dClGjhwJpVKJpUuXal1PoVAwkSciIjJ1vB+diIjIaJU5kU9JSdH4fyEEgGcJPBERERERERFVrQrfI//111+jefPmUCqVUCqVaN68Ob766it9lo2IiIjMUWXuSef97EREZcN4adYqNGr9jBkzsGTJErz55psICQkBACQkJODtt99GWlqaxsfSERERERERUTXibVJmq0KJ/IoVK7B69WqMGDFCmte/f3+0bNkSb775JhN5IiIiIiIioipSoa71BQUFaNu2rdr8Nm3a4OnTp5UuFBERERERERFpVqFEftSoUVixYoXa/FWrVmHkyJGVLhQRERERERERaVbmrvVTp06V/q9QKPDVV19hz549aN++PQDgyJEjSEtLQ2RkpP5LSUREREREZOx4TzpVkzIn8idPnpS9btOmDQAgOTkZAODu7g53d3ecO3dOj8UjIiIii8SLYSIiIq3KnMjHx8dXZTk0mjVrFmbPni2bFxgYiIsXL2rdZuvWrZg+fTpSU1PRqFEjfPzxx3jppZequqhERERERETGhz+MmqUKP0e+ujRr1gzp6enS9Pvvv2td99ChQxgxYgTGjh2LkydPYuDAgRg4cCDOnj1bjSUm+n8ln93JZ3kSEREREZEeGH0ib2NjAy8vL2lyd3fXuu7nn3+OiIgITJs2DU2aNMHcuXPRunVrLFu2rBpLTEREREREFoeNNlSNjD6RT0pKgo+PDxo0aICRI0ciLS1N67oJCQkICwuTzQsPD0dCQoLOY+Tn5yMnJ0c2ERER4yMRkTaMj0RkSEadyAcHB2PdunXYtWsXVqxYgZSUFHTu3BkPHjzQuH5GRgY8PT1l8zw9PZGRkaHzOAsWLICLi4s0+fr66q0OZIH4ayyZEcZHIiLNGB9Jhtd/VM2MOpHv3bs3hg4dipYtWyI8PBy//PIL7t+/j++//16vx4mJiUF2drY0Xb9+Xa/7JwvCIE5mhvGR9I5xkswE4yMRGVKZR603Bq6urmjcuDGuXLmicbmXlxcyMzNl8zIzM+Hl5aVzv/b29rC3t9dbOYmIzAXjI1UpjqRMJozxkYgMyahb5EvKzc1FcnIyvL29NS4PCQnBvn37ZPPi4uIQEhJSHcUjUrM07jKWxl2Wz2RrFBERlsZdRsLVu4YuBhGRUdJ4DUlUjFEn8u+88w5+++03pKam4tChQxg0aBCsra0xYsQIAEBkZCRiYv7+Jf+tt97Crl27sHjxYly8eBGzZs3C8ePHMWnSJENVgQgAGIiJiLRgfCQiIio/o07kb9y4gREjRiAwMBDDhg1D7dq1cfjwYdSpUwcAkJaWhvT0dGn9Dh06YPPmzVi1ahVatWqFf//739i+fTuaN29uqCqQJdHS0t4+bRUAsOWJiEgHJvRERJrxGpI0Mep75Lds2aJz+f79+9XmDR06FEOHDq2iEhGVXcLVu4CfoUtBRGR8Eq7eRXuskl4ziSci0mxp3GW0N3QhyCgZdYs8kalSXZSqWuNLzicisjSq+FeyZYlxkogsnSouJly9q7P1nfGRimMiT6RH7PpEREbLCAba5EUoEZFm1XYNaQTnAtIPJvJEelbeQMwLWyIyZ+WJcSXXNUh85EUuEVUTbTFO07Wkah6vG0mFiTxRNUu4epePXSIi0oEXqkREuvE6kpjIE1WStvs+iyt5DygRkSUoS3wkIjJZlejBY9AWdvY8MgtM5In0oKIXqcUvctkCRUSWqn3aKrUfPMs6+BMRkUEwGSYDM+rHzxEZs4Srd3H4afmSb7bME5El0BYfGQOJiIj0gy3yREREVOXKk8Qz4Scic6WPHkbF91HhHp3sUWDymMgTVUBVdYNn93oiMnWVvUhlEk9ERFQ6JvJERERkFHQl8bxPnohMnb4HAOUj6SwbE3kiIiIiIqKyYrd0MgIc7I6ojCoyuF1ljvN2z8ZVfiwiIn1aGncZ7Q1dCCIiI8RWc9I3tsgTERGRSWA3UiIizYo/spMsAxN5IiIiqjQm10REmjG5pqrARJ7ISPGimIgqzQzv4+QFMRGRZoyPloX3yBMREVGFVdf4IUREpoaJNVUltsgTERERERGZCfbqtAxM5IlKYchgmHD1bvUe3wy74RJR1TFkfFwad5kXq0RktAwdn8p1fF7/mSQm8kRlYFLBmIjIgjA+EhHpAZN5k8NEnkgH3ttERKQZ4yMRWRQTTXQZq82XUSfyCxYswIsvvoiaNWvCw8MDAwcOxKVLl3Rus27dOigUCtmkVCqrqcRERERERESGxyTevBl1Iv/bb79h4sSJOHz4MOLi4lBQUIBevXohLy9P53bOzs5IT0+XpmvXrlVTicmcGFt3TQZjIjIWxhYfja08RETGhNeQ5smoHz+3a9cu2et169bBw8MDiYmJ6NKli9btFAoFvLy8qrp4ZMZ4UUhEpJkxx8elcZfxds/Ghi4GEZmbcnSrN9ZHcpYpPsYvALrFVE+BqNKMOpEvKTs7GwDg5uamc73c3FzUq1cPRUVFaN26NebPn49mzZppXT8/Px/5+fnS65ycHP0UmIjIxDE+EhFpxvhIRIZk1F3riysqKsKUKVPQsWNHNG/eXOt6gYGBWLNmDXbs2IGNGzeiqKgIHTp0wI0bN7Rus2DBAri4uEiTr69vVVSBLEj7tFVVsl9jbgkj88T4SKZCFR8ZJ6m6MD5aiHK2xhszxkfzYjKJ/MSJE3H27Fls2bJF53ohISGIjIxEUFAQQkND8eOPP6JOnTpYuXKl1m1iYmKQnZ0tTdevX9d38clELI27bPRBmKg6MT5ScbwIJPob4yMVx+tHqm4m0bV+0qRJ2LlzJw4cOIDnnnuuXNva2trihRdewJUrV7SuY29vD3t7+8oWk6oa79sBwHtAqXoxPhIRacb4SESGZNQt8kIITJo0Cdu2bcOvv/4Kf3//cu+jsLAQZ86cgbe3dxWUkMwJW5pKMNHnpRJR1TClGMmWMSKqToyPZAhGnchPnDgRGzduxObNm1GzZk1kZGQgIyMDjx49ktaJjIxETMzfrbRz5szBnj17cPXqVZw4cQKvvfYarl27hnHjxhmiCkRVotpPGEzqiYiIiIiMhlF3rV+xYgUAoGvXrrL5a9euxejRowEAaWlpsLL6+/eIe/fuITo6GhkZGahVqxbatGmDQ4cOoWnTptVVbNKnaupOn3D1LuBX5YchIjI5ptTSVNzSuMt426ivcojI1Bnro+ZKk3D1LkIa1DZ0MaiSjPoUJ4QodZ39+/fLXi9duhRLly6tohIRGQ/VxTXvlyeiqmKqSXyV4VgtRPT/zL6LOuOd0TPqrvVE1cHUL1RNvfxERFXF7C+0iYjIYjGRJyIiIiIiUrGAsYESrt4tvTHIAt4HU8ZEniyaubRmm0s9iMh4mEtrNuMjEVElMJk3WkzkicwEL1aJiDRjfCQiInPDRJ4sztK4y9JkbsyxTkRUfZbGXS5bd0sTZC49DIioipXSAm1u8dHc6mNJmMgTUcWxuxURERGZizIm8eb2w6C51cdSMJEnIiIiIiIiMiFM5ImIiMgisAspEVWUubdam3v9zBETebIY5npffEmWUEci0j9LiR2WUk8i0h9LSXItpZ7mgok8kRnihSoRERER6VX8Ao6PZESYyJNFsMTE1hLrTEQVY2mtMJbSQ4uIKo/xkYwVE3kye5YcjCy57kRUNpYcJyy57kSEUluYLTlGWNoPGKaIiTwREZEFYquLnhVPBtj1lMikJVy9y/ioC2OcUWAiT2aNQZjvAZFZ4EUTERFVs4Srd0tvmef5yWCYyJPZYgL7N7a8EVFxjAd/Wxp3mV1IiUjCeKCO5wzjZGPoAhDpG4ONdqr35u2ejav2QPELgG4xVXsMIio3xkftpPjIKyMii8UknkwJW+TJrPAilYhIM16gEhFRRem8xmb3eoPg785EFmhp3OWqb5UnIjJBCVfv4vDTvy9Y9R4r2WOJyDBUyWaJ71/x73z76i6TiSn+g/DhpyWuJRnbqh1b5Mnkqe7/Zmt8+aneM753ROaL8ZGISDP2VKoibKGvFkzkyWTx4rRySibxfC+JzAsHcdMPnmuIzA+/1/qh8zzDZL7KmUQiHxsbi/r160OpVCI4OBhHjx7Vuf7WrVvx/PPPQ6lUokWLFvjll1+qqaRUHRh4iYg04w9zRET/r1giqUo4+Xz4qsFk3jCM/h757777DlOnTsWXX36J4OBgfPbZZwgPD8elS5fg4eGhtv6hQ4cwYsQILFiwAH379sXmzZsxcOBAnDhxAs2bNzdADUhfit/DxCBcNWT3iaXdVb//iYgqrwruIyweExkfq8bSuMtSXASq4ekfRFRxJZJ4qnrFryE1Pv1DyxgFVHFG3yK/ZMkSREdHY8yYMWjatCm+/PJLODo6Ys2aNRrX//zzzxEREYFp06ahSZMmmDt3Llq3bo1ly5ZVc8mpMlRdnlS/nDIIG07xblP8HIiMC+Oj4ZQcn4W3MRAZSPwCjS2/bH03HFXvh+KfAWOk/hl1i/yTJ0+QmJiImJi/f7mxsrJCWFgYEhISNG6TkJCAqVOnyuaFh4dj+/btWo+Tn5+P/Px86XV2djYAICcnpxKlp7KK/fWK1mV5j/LxOC9X7f/6pu04uo5fcll5PM7LLfcxq7L+KrqOvWD7CQCQ/gWAF2/cxLHsE5jYvWGJHT0GLPz7o4ofQggDl6RyGB+rQBm+H6q4OLF7Q8T+ekX6rpX7UGWMIZrWKy3maFtPFQ81zSsv1f41zddFU9nKW//S1ituwfYTeLFYnHzxxk20a5OD2F+v6Cc+HlgMdPln+bYxYoyPVGEHFuNoahaOPTdGFh8ByGKkal5ZY5Om6zlDzSu5zFjLWZ55qhi599zf142xv17BRJsdz1YqHt8OLFafZ0HKFR+FEfvrr78EAHHo0CHZ/GnTpol27dpp3MbW1lZs3rxZNi82NlZ4eHhoPc7MmTMFAE6cOHHS+3T9+vXKB0MDYnzkxIlTVU2Mj5w4ceKkeSpLfDTqFvnqEhMTI2vFLyoqQlZWFmrXrg2FQmHAkumWk5MDX19fXL9+Hc7OzoYujl6YW53MrT4A61RWQgg8ePAAPj4+etmfoTA+Gg/WyfiZW30AxkddTDU+Aub3t2pu9QFYJ1Ng6Pho1Im8u7s7rK2tkZmZKZufmZkJLy8vjdt4eXmVa30AsLe3h729vWyeq6trxQptAM7OzmbxZSjO3OpkbvUBWKeycHFx0du+DIXx0fiwTsbP3OoDMD5qYurxETC/v1Vzqw/AOpkCQ8VHox7szs7ODm3atMG+ffukeUVFRdi3bx9CQkI0bhMSEiJbHwDi4uK0rk9ERERERERkSoy6RR4Apk6diqioKLRt2xbt2rXDZ599hry8PIwZMwYAEBkZibp162LBgmejVb711lsIDQ3F4sWL0adPH2zZsgXHjx/HqlWrDFkNIiIiIiIiIr0w+kR++PDhuH37NmbMmIGMjAwEBQVh165d8PT0BACkpaXByurvjgUdOnTA5s2b8eGHH+KDDz5Ao0aNsH37drN8hry9vT1mzpyp1q3LlJlbncytPgDrRKbBHD9T1sn4mVt9APOsE5nf52pu9QFYJ1Ng6PoohDDxZ38QERERERERWRCjvkeeiIiIiIiIiOSYyBMRERERERGZECbyRERERERERCaEiTwRERERERGRCWEib8SysrIwcuRIODs7w9XVFWPHjkVubq7Obbp27QqFQiGb3njjDdk6aWlp6NOnDxwdHeHh4YFp06bh6dOnVVkVSXnrlJWVhTfffBOBgYFwcHCAn58fJk+ejOzsbNl6JeusUCiwZcuWKqlDbGws6tevD6VSieDgYBw9elTn+lu3bsXzzz8PpVKJFi1a4JdffpEtF0JgxowZ8Pb2hoODA8LCwpCUlFQlZdemPHVavXo1OnfujFq1aqFWrVoICwtTW3/06NFqn0dERERVV0NSnvqsW7dOraxKpVK2jjF8RqTO3GIk4yPjY3VhjDR/5hYfAdOPkYyPjI96/5wEGa2IiAjRqlUrcfjwYXHw4EHRsGFDMWLECJ3bhIaGiujoaJGeni5N2dnZ0vKnT5+K5s2bi7CwMHHy5Enxyy+/CHd3dxETE1PV1RFClL9OZ86cEYMHDxY//fSTuHLliti3b59o1KiRePnll2XrARBr166V1fvRo0d6L/+WLVuEnZ2dWLNmjTh37pyIjo4Wrq6uIjMzU+P6f/zxh7C2thaffPKJOH/+vPjwww+Fra2tOHPmjLTOwoULhYuLi9i+fbv4888/Rf/+/YW/v3+VlF8fdXr11VdFbGysOHnypLhw4YIYPXq0cHFxETdu3JDWiYqKEhEREbLPIysryyjrs3btWuHs7Cwra0ZGhmwdQ39GpJm5xUjGR8bH6sAYaRnMLT4KYdoxkvGR8bEqPicm8kbq/PnzAoA4duyYNO+///2vUCgU4q+//tK6XWhoqHjrrbe0Lv/ll1+ElZWV7I9sxYoVwtnZWeTn5+ul7NpUtE4lff/998LOzk4UFBRI8wCIbdu26bO4GrVr105MnDhRel1YWCh8fHzEggULNK4/bNgw0adPH9m84OBgMWHCBCGEEEVFRcLLy0ssWrRIWn7//n1hb28vvv322yqogbry1qmkp0+fipo1a4r169dL86KiosSAAQP0XdQyKW991q5dK1xcXLTuzxg+I1JnbjGS8fEZxseqxxhp/swtPgph+jGS8VEd42PlPyd2rTdSCQkJcHV1Rdu2baV5YWFhsLKywpEjR3Ruu2nTJri7u6N58+aIiYnBw4cPZftt0aIFPD09pXnh4eHIycnBuXPn9F+RYipTp+Kys7Ph7OwMGxsb2fyJEyfC3d0d7dq1w5o1ayCE0FvZAeDJkydITExEWFiYNM/KygphYWFISEjQuE1CQoJsfeDZ+61aPyUlBRkZGbJ1XFxcEBwcrHWf+lSROpX08OFDFBQUwM3NTTZ///798PDwQGBgIP7xj3/g7t27ei27JhWtT25uLurVqwdfX18MGDBA9l0w9GdEmplbjGR8fIbxsWoxRloGc4uPqmObaoxkfNSM8bHyn5NN6auQIWRkZMDDw0M2z8bGBm5ubsjIyNC63auvvop69erBx8cHp0+fxnvvvYdLly7hxx9/lPZbPAADkF7r2q8+VLROxd25cwdz587F+PHjZfPnzJmD7t27w9HREXv27MH//M//IDc3F5MnT9Zb+e/cuYPCwkKN79/Fixc1bqPt/VbVV/WvrnWqUkXqVNJ7770HHx8fWZCKiIjA4MGD4e/vj+TkZHzwwQfo3bs3EhISYG1trdc6FFeR+gQGBmLNmjVo2bIlsrOz8emnn6JDhw44d+4cnnvuOYN/RqSZucVIxse/12d8rDqMkZbB3OKjav+mGiMZHzVjfKz858REvpq9//77+Pjjj3Wuc+HChQrvv3hwatGiBby9vdGjRw8kJycjICCgwvvVparrpJKTk4M+ffqgadOmmDVrlmzZ9OnTpf+/8MILyMvLw6JFi/R6oUrqFi5ciC1btmD//v2ywT1eeeUV6f8tWrRAy5YtERAQgP3796NHjx6GKKpWISEhCAkJkV536NABTZo0wcqVKzF37lwDlswymVuMZHy0XOYQHwHGSGNibvERYIy0VIyP+sFEvpr985//xOjRo3Wu06BBA3h5eeHWrVuy+U+fPkVWVha8vLzKfLzg4GAAwJUrVxAQEAAvLy+10RczMzMBoFz7La466vTgwQNERESgZs2a2LZtG2xtbXWuHxwcjLlz5yI/Px/29vZlqkdp3N3dYW1tLb1fKpmZmVrL7+XlpXN91b+ZmZnw9vaWrRMUFKSXcutSkTqpfPrpp1i4cCH27t2Lli1b6ly3QYMGcHd3x5UrV6o0EFemPiq2trZ44YUXcOXKFQCG/4wsjbnFSMZHxkdjiY8AY6SpM7f4CFhGjGR8lGN81OPnVOm77KlKqAb1OH78uDRv9+7d5R7U4/fffxcAxJ9//imE+HugkuKjL65cuVI4OzuLx48f668CGlS0TtnZ2aJ9+/YiNDRU5OXllelY8+bNE7Vq1ap0mUtq166dmDRpkvS6sLBQ1K1bV+dgJX379pXNCwkJURus5NNPP5WWZ2dnV/tgJeWpkxBCfPzxx8LZ2VkkJCSU6RjXr18XCoVC7Nixo9LlLU1F6lPc06dPRWBgoHj77beFEMbxGZE6c4uRjI/PMD5WPcZI82du8VEI04+RjI/PMD7q93NiIm/EIiIixAsvvCCOHDkifv/9d9GoUSPZYzZu3LghAgMDxZEjR4QQQly5ckXMmTNHHD9+XKSkpIgdO3aIBg0aiC5dukjbqB4d0qtXL3Hq1Cmxa9cuUadOnWp9dEh56pSdnS2Cg4NFixYtxJUrV2SPd3j69KkQQoiffvpJrF69Wpw5c0YkJSWJ5cuXC0dHRzFjxgy9l3/Lli3C3t5erFu3Tpw/f16MHz9euLq6SiO4jho1Srz//vvS+n/88YewsbERn376qbhw4YKYOXOmxseHuLq6ih07dojTp0+LAQMGVPvjQ8pTp4ULFwo7Ozvx73//W/Z5PHjwQAghxIMHD8Q777wjEhISREpKiti7d69o3bq1aNSoUZWf6CtSn9mzZ4vdu3eL5ORkkZiYKF555RWhVCrFuXPnZHU25GdEmplbjGR8ZHw0xjoxRpomc4uPFamTMcVIxkfGx6r4nJjIG7G7d++KESNGCCcnJ+Hs7CzGjBkj/bELIURKSooAIOLj44UQQqSlpYkuXboINzc3YW9vLxo2bCimTZsmewaoEEKkpqaK3r17CwcHB+Hu7i7++c9/yh7DYUx1io+PFwA0TikpKUKIZ48fCQoKEk5OTqJGjRqiVatW4ssvvxSFhYVVUof//d//FX5+fsLOzk60a9dOHD58WFoWGhoqoqKiZOt///33onHjxsLOzk40a9ZM/Pzzz7LlRUVFYvr06cLT01PY29uLHj16iEuXLlVJ2bUpT53q1aun8fOYOXOmEEKIhw8fil69eok6deoIW1tbUa9ePREdHa32XE1jqc+UKVOkdT09PcVLL70kTpw4IdufMXxGpM7cYiTjI+OjMdaJMdI0mVt8rEidjC1GMj4yPur7c1IIoedn0BARERERERFRleFz5ImIiIiIiIhMCBN5IiIiIiIiIhPCRJ6IiIiIiIjIhDCRJyIiIiIiIjIhTOSJiIiIiIiITAgTeSIiIiIiIiITwkSeiIiIiIiIyIQwkSciIiIiIiIyIUzkiYiIiIiIiEwIE3kiIiIiIiIiE8JEnoiIiIiIiMiEMJEnIiIiIiIiMiH/BxE/dG6eT5ivAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig, axs = plt.subplots(4, 3, figsize=(12, 12), sharey=True, sharex=True)\n", + "for i, bins in [(0, 64), (1, 128), (2, 256), (3, 512)]:\n", + " axs[i, 0].set_ylabel(f\"bins={bins}\")\n", + " axs[i, 0].hist(coef.ravel(), bins=bins, density=True, label=\"coef\", alpha=0.5)\n", + " axs[i, 0].hist(qu_f8, bins=bins, alpha=0.5, label=\"qdq_f8\", density=True)\n", + " axs[i, 0].legend()\n", + " axs[i, 0].set_title(f\"QDQ E4M3FN (same) - err={err_f8:1.3g}\")\n", + "\n", + " axs[i, 1].hist(coef.ravel(), bins=bins, density=True, label=\"coef\", alpha=0.5)\n", + " axs[i, 1].hist(qu_f8p, bins=bins, alpha=0.5, label=\"qdq_f8\", density=True)\n", + " axs[i, 1].legend()\n", + " axs[i, 1].set_title(f\"QDQ E4M3FN (p3) - err={err_f8p:1.3g}\")\n", + "\n", + " axs[i, 2].hist(coef.ravel(), bins=bins, density=True, label=\"coef\", alpha=0.5)\n", + " axs[i, 2].hist(qu_u8, bins=bins, alpha=0.5, label=\"qdq_u8\", density=True)\n", + " axs[i, 2].legend()\n", + " axs[i, 2].set_title(f\"QDQ uint 8 - err={err_u8:1.3g}\");" + ] + }, + { + "cell_type": "markdown", + "id": "8b9b6aa7", + "metadata": {}, + "source": [ + "## Other scales" + ] + }, + { + "cell_type": "code", + "execution_count": 103, + "id": "1efabcbe", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100%|██████████████████████████████████████████████████████████████████████████████████| 10/10 [00:08<00:00, 1.15it/s]\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
scaleerr
00.0001470.122887
10.0004400.025486
20.0007330.007755
30.0010270.006265
40.0013200.006142
50.0016140.006165
60.0019070.006151
70.0022000.006154
80.0024940.006152
90.0027870.006161
\n", + "
" + ], + "text/plain": [ + " scale err\n", + "0 0.000147 0.122887\n", + "1 0.000440 0.025486\n", + "2 0.000733 0.007755\n", + "3 0.001027 0.006265\n", + "4 0.001320 0.006142\n", + "5 0.001614 0.006165\n", + "6 0.001907 0.006151\n", + "7 0.002200 0.006154\n", + "8 0.002494 0.006152\n", + "9 0.002787 0.006161" + ] + }, + "execution_count": 103, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from pandas import DataFrame\n", + "from tqdm import tqdm\n", + "\n", + "a = 0.00014669707383747942\n", + "h = 0.00014669707383747942 * 2\n", + "\n", + "data = []\n", + "for scale in tqdm([a + h * i for i in range(10)]):\n", + " got = ref_f8.run(\n", + " None, {\"X\": coef.ravel(), \"Scale\": numpy.array([scale], dtype=numpy.float32)}\n", + " )[0]\n", + " err = ((coef.ravel() - got) ** 2).sum() ** 0.5 / coef.size\n", + " obs = dict(scale=scale, err=err*1000)\n", + " data.append(obs)\n", + " \n", + "df = DataFrame(data)\n", + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 105, + "id": "53fbc33d", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAi4AAAGwCAYAAACOzu5xAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAA9hAAAPYQGoP6dpAAAyd0lEQVR4nO3deXxV9Z3/8fe5N8lNAtkgJGEJ+6IRDIsRUTRQopS6dNPpz1/HWtuHVk07OnSmo/NrsXbGoeM2fYyNS32My/w6U7eOy6+AFVFkEZEtioay7yEJIWQhgSz3fn9/JPeSkABJuPeee+59PR+PlMs92+d+i8k755zv51jGGCMAAAAHcNldAAAAQG8RXAAAgGMQXAAAgGMQXAAAgGMQXAAAgGMQXAAAgGMQXAAAgGPE2V1AsPl8PpWXlyslJUWWZdldDgAA6AVjjBoaGjRs2DC5XGc/rxJ1waW8vFy5ubl2lwEAAPrh4MGDGjFixFmXR11wSUlJkdT+wVNTU22uBgAA9EZ9fb1yc3MDP8fPJuqCi//yUGpqKsEFAACHOd9tHtycCwAAHIPgAgAAHIPgAgAAHCPq7nEBACCSeL1etba22l2G7eLj4+V2uy94PwQXAABCwBijiooK1dbW2l1KxEhPT1dOTs4F9VkjuAAAEAL+0JKVlaXk5OSYbopqjFFTU5OqqqokSUOHDu33vgguAAAEmdfrDYSWwYMH211OREhKSpIkVVVVKSsrq9+Xjbg5FwCAIPPf05KcnGxzJZHFPx4Xcs8PwQUAgBCJ5ctDPQnGeBBcAACAYxBcAACAYxBcAACAYxBceskYo79U1KumscXuUgAAiFkEl1665/eb9dXfrNaSz8vtLgUAgIhgjFFbW1u391taQvdLPsGll6aMSJMkfbTjqM2VAACcyBijppY2W76MMb2u0+fzafHixRozZoySkpKUn5+vN954Q5K0cuVKWZalZcuWacaMGfJ4PFqzZo3mzJmjH//4x7r//vuVmZmp+fPnh2oYaUDXW3MmDdFjf96uj3cfU3ObV564C3/eAgAgdpxs9Spv0Z9tOXbZr+YrOaF3P/IXL16s3//+93r22Wc1YcIErVq1Sn/913+tIUOGBNZ54IEH9Pjjj2vs2LHKyMiQJL388su65557tHbt2pB8Bj+CSy/lDU1VVopHVQ3N2rD3uGZPyLS7JAAAgqq5uVn/8i//ovfff1+zZs2SJI0dO1Zr1qzRc889p7vuukuS9Ktf/UrXXnttl20nTJigRx99NOQ1Elx6ybIsFU4cotc3HdJHO6oILgCAPkmKd6vsV6G7hHK+Y/fGrl271NTU1C2UtLS0aNq0aYG/X3bZZd22nTFjxoUV2UsElz4onNQeXFZuP6r/c73d1QAAnMSyrF5frrHLiRMnJElLlizR8OHDuyzzeDzavXu3JGnAgAHdtu3pvVCI7BGMMFePHyKXJe2sOqHDtSc1PD3J7pIAAAiavLw8eTweHThwQIWFhd2W+4OLnQgufZCWHK/pIzO0cf9xrdxepe/OHGV3SQAABE1KSor+7u/+Tn/7t38rn8+n2bNnq66uTmvXrlVqaqpGjbL/5x7BpY8KJw7Rxv3H9dH2owQXAEDU+ad/+icNGTJEixcv1p49e5Senq7p06frH//xH+Xz+ewuj+DSV3MmZemJ5Tu0dle1Wtp8SoijFQ4AIHpYlqX77rtP9913X4/Le+oJs3LlyhBXdRo/dfvokmGpyhyYoMYWrzbur7G7HAAAYgrBpY9cLkvXTGhvwkMXXQAAwovg0g+FkzqCy3aCCwAA4URw6YdrJrRPi/5LRYOO1J20uxwAQITqyzOCYkEwxoPg0g8ZAxKUn5suSVrF5SIAwBni4+MlSU1NTTZXEln84+Efn/5gVlE/FU4coi0HarVy+1F9p2Ck3eUAACKI2+1Wenq6qqqqJEnJycmyLMvmquxjjFFTU5OqqqqUnp4ut7v/DyomuPTTnElZ+s37O7VmZ7VavT7Fuzl5BQA4LScnR5IC4QVSenp6YFz6i+DST5cOT9OgAQmqaWzR5v3HNXPsYLtLAgBEEMuyNHToUGVlZam1tdXucmwXHx9/QWda/Agu/eRyWbp6QqbeLi3XRzuOElwAAD1yu91B+YGNdhF5feOb3/ymMjIydPPNN9tdyjnN6ZgWvZJp0QAAhEVEBpf77rtP//mf/2l3Ged1zYQhsiyp7Ei9qupP2V0OAABRLyKDy5w5c5SSkmJ3Gec1eKBHlw5Pk0QXXQAAwqHPwWXVqlW68cYbNWzYMFmWpbfeeqvbOiUlJRo9erQSExM1c+ZMffrpp8GoNSIVTuy4XERwAQAg5PocXBobG5Wfn6+SkpIel7/66qtauHChHnroIW3evFn5+fmaP39+l+lgU6dO1eTJk7t9lZeX9/kDNDc3q76+vstXOBVOypIkrd5xVG1e+x/3DQBANOvzrKIFCxZowYIFZ13+5JNP6s4779Qdd9whSXr22We1ZMkSvfDCC3rggQckSaWlpf2rtgeLFy/Www8/HLT99dXU3HSlJcWr7mSrSg/W6rLRg2yrBQCAaBfUe1xaWlq0adMmFRUVnT6Ay6WioiKtW7cumIcKePDBB1VXVxf4OnjwYEiOczbujmnREve5AAAQakENLtXV1fJ6vcrOzu7yfnZ2tioqKnq9n6KiIt1yyy1aunSpRowYcc7Q4/F4lJqa2uUr3OZ0XC5iWjQAAKEVkQ3o3n//fbtL6JNrJrafcdl6uE5HG5o1JMVjc0UAAESnoJ5xyczMlNvtVmVlZZf3KysrL/jZBJEsKyVRlwxrP9OzeidnXQAACJWgBpeEhATNmDFDK1asCLzn8/m0YsUKzZo1K5iHijh00QUAIPT6HFxOnDih0tLSwMygvXv3qrS0VAcOHJAkLVy4UM8//7xefvllbdu2Tffcc48aGxsDs4yilf8+l1U7j8rrMzZXAwBAdOrzPS4bN27U3LlzA39fuHChJOn222/XSy+9pO985zs6evSoFi1apIqKCk2dOlXvvvtutxt2o8203HSlJMaptqlVnx+q1bSRGXaXBABA1LGMMVF1eqC+vl5paWmqq6sL+wyje/9rk5ZurdB98ybob6+dGNZjAwDgZL39+R2RzypyqjkTO6ZF088FAICQILgEUWHHDbqfH6rVsRPNNlcDAED0IbgEUXZqoi7KSZEx0ppd1XaXAwBA1Ima4FJSUqK8vDwVFBTYWgdddAEACJ2oCS7FxcUqKyvThg0bbK3D389l1Y6j8jEtGgCAoIqa4BIpZozK0EBPnI41tuiL8jq7ywEAIKoQXIIs3u3SVeMHS+JyEQAAwUZwCYHT97lU2VwJAADRheASAoUT2+9zKT1Yq9qmFpurAQAgehBcQmBYepImZg+Uz0irdzItGgCAYCG4hAjTogEACD6CS4jM6bhc9BHTogEACBqCS4jMGJ2h5AS3qk80q+xIvd3lAAAQFQguIeKJc+vKcZmS2s+6AACAC0dwCSF/F12mRQMAEBwElxDyT4vefKBWdSdbba4GAADni5rgEikPWewsd1Cyxg0ZIK/PaC1PiwYA4IJFTXCJlIcsnokuugAABE/UBJdI5b/P5aMdR2UM06IBALgQBJcQKxg9SEnxblXWN+svFQ12lwMAgKMRXEIsMd6tWeN4WjQAAMFAcAkDpkUDABAcBJcw8E+L3rT/uBpOMS0aAID+IriEwajBAzQmc4DafEZrdx2zuxwAAByL4BImhYGHLnK5CACA/iK4hElgWvR2pkUDANBfBJcwuWLsYHniXCqvO6WdVSfsLgcAAEciuIRJYrxbV4z1T4vmchEAAP1BcAmj09Oi6ecCAEB/EFzCyH+D7oZ9NWpsbrO5GgAAnIfgEkZjMgdo5KBktXqNPt7NtGgAAPoqaoJLSUmJ8vLyVFBQYHcpZ2VZFl10AQC4AFETXIqLi1VWVqYNGzbYXco5ne7nwrRoAAD6KmqCi1PMGjdYCW6XDh0/qd1HG+0uBwAARyG4hFlyQpxmjh0kictFAAD0FcHFBp0vFwEAgN4juNjAf4Pu+j01amphWjQAAL1FcLHBuCEDNTw9SS1enz7Zw7RoAAB6i+Big67TorlcBABAbxFcbMJ9LgAA9B3BxSZXjs9UvNvS/mNN2lvNtGgAAHqD4GKTgZ44FYxmWjQAAH1BcLERl4sAAOgbgouN5kzKkiSt231Mp1q9NlcDAEDkI7jYaGL2QA1NS1RzG9OiAQDoDYKLjZgWDQBA3xBcbOa/z2UV97kAAHBeBBebXTU+U3EuS3uqG3XgWJPd5QAAENGiJriUlJQoLy9PBQUFdpfSJymJ8ZoxKkOStHIH06IBADiXqAkuxcXFKisr04YNG+wupc8KO+5z+Yj7XAAAOKeoCS5ONmdi+7Toj5kWDQDAORFcIsDFQ1OUnerRyVavNuyrsbscAAAiFsElAliWFZhdxLRoAADOjuASIQo7LhfR/h8AgLMjuESI2RMy5XZZ2lV1QoeOMy0aAICeEFwiRFpSvKaPTJfE5SIAAM6G4BJBeFo0AADnRnCJIP6nRX+8q1otbT6bqwEAIPIQXCJI3tBUZQ70qLHFq41MiwYAoBuCSwRxuSxdMzFTEpeLAADoCcElwvgvF3GDLgAA3RFcIsw1EzLlsqTtlQ0qrz1pdzkAAEQUgkuESU9O0NTcdElcLgIA4EwElwgU6KLL5SIAALoguESgOZPa+7ms3VWtVi/TogEA8CO4RKApw9M0aECCGprbtGn/cbvLAQAgYhBcIpDLZemaCUyLBgDgTASXCMW0aAAAuiO4RKirJ2TKsqRtR+pVWX/K7nIAAIgIURNcSkpKlJeXp4KCArtLCYrBAz26dHiaJC4XAQDgFzXBpbi4WGVlZdqwYYPdpQRN4SSmRQMA0FnUBJdo5J8WvXrnUbUxLRoAAIJLJMsfka705HjVn2rTloO1dpcDAIDtCC4RzO2ydPWE9rMuXC4CAIDgEvHmTGwPLit3VNlcCQAA9iO4RLhrOoLLF4frVdXAtGgAQGwjuES4ISkeTR6eKklavaPa5moAALAXwcUB5nQ8LXol/VwAADGO4OIAnadFe33G5moAALAPwcUBpuamKzUxTrVNrSplWjQAIIYRXBwgzu06PS2ay0UAgBhGcHGIwkn+fi5MiwYAxC6Ci0P4+7l8frhOx04021wNAAD2ILg4RFZqoi4emipjpNU7mRYNAIhNBBcH8c8uWsnlIgBAjCK4OIj/ctGqndXyMS0aABCDCC4OMn1UhlI8cappbNHWw3V2lwMAQNgRXBwk3u3SVeMzJUkreVo0ACAGEVwcJnCfC0+LBgDEIIKLw/j7uZQerNXxxhabqwEAILwILg4zNC1Jk7JT2qdF72JaNAAgthBcHIhp0QCAWEVwcSD/5aJVO44yLRoAEFMILg502ahBGpDgVvWJFpUdqbe7HAAAwiZqgktJSYny8vJUUFBgdykhlxDn0pWBadFcLgIAxI6oCS7FxcUqKyvThg0b7C4lLE7f50I/FwBA7Iia4BJrCjva/28+cFx1Ta02VwMAQHgQXBxqREayxmcNlM9Ia5gWDQCIEQQXB/M/dJH7XAAAsYLg4mBzJmVJkj7acVTGMC0aABD9CC4OVjAmQ0nxblU1NGvbkQa7ywEAIOQILg7miXPrynGDJfHQRQBAbCC4OBzTogEAsYTg4nCFE9vvc9m8/7jqTzEtGgAQ3QguDjdycLLGZg5Qm8/oY6ZFAwCiHMElChRyuQgAECMILlGgcOLp4MK0aABANCO4RIErxg6WJ86livpT2lF5wu5yAAAIGYJLFEiMd2uWf1o0XXQBAFGM4BIl5kzkPhcAQPQjuESJwo72/xv31+hEc5vN1QAAEBoElygxJnOARg1OVquXadEAgOhFcIkigctFO7hcBACITgSXKOLv5/IR06IBAFGK4BJFZo3NVEKcS4drT2r3UaZFAwCiD8EliiQluDVzzCBJzC4CAEQngkuUmdMxu4jgAgCIRgSXKONv///p3ho1tTAtGgAQXQguUWbckAEakZGkFq9P63Yfs7scAACCiuASZSzL0hyeFg0AiFIElyhUOLHjPpcdVUyLBgBEFYJLFLpy3GAluF06WHNSe6sb7S4HAICgIbhEoQGeOBWMyZDE5SIAQHQhuESpQtr/AwCiEMElSvn7uazfc0ynWr02VwMAQHAQXKLUhKyBGpaWqOY2n9btYVo0ACA6RE1wKSkpUV5engoKCuwuJSJYlqXCjrMuH3GfCwAgSkRNcCkuLlZZWZk2bNhgdykRw3+fy0fc5wIAiBJRE1zQ3VXjByvOZWlvdaP2H2NaNADA+QguUSwlMV6XjWZaNAAgehBcopy/iy6XiwAA0YDgEuX8zy36eHc106IBAI5HcIlyF+WkKDvVo1OtPn26t8bucgAAuCAElyhnWdbpLrrc5wIAcDiCSwzwd9H9aEeVzZUAAHBhCC4x4KrxmXK7LO0+2qiDNU12lwMAQL8RXGJAWlK8ZozsmBbN7CIAgIMRXGJEYcfsItr/AwCcjOASI/w36H68u1rNbUyLBgA4E8ElRlwyLFVDUjxqavFq477jdpcDAEC/EFxihGVZumaCf1o0s4sAAM5EcIkh/i66tP8HADgVwSWGXD0hUy5L2lF5QuW1J+0uBwCAPiO4xJD05ARNG8nTogEAzkVwiTFzOy4XLfviiM2VAADQdwSXGHNT/nBJ0ppd1VwuAgA4DsElxowcnKyZYwbJGOnNLYftLgcAgD4huMSgm2eMkCS9semQjDE2VwMAQO8RXGLQ16YMVXKCW3urG7X5AM3oAADOQXCJQQM8cVoweaik9rMuAAA4BcElRvkvF/3psyM62cKziwAAzkBwiVEzxwxS7qAkNTS36b2yCrvLAQCgVwguMcrlsvTt6adv0gUAwAkILjHMH1zW7KrWYXq6AAAcgOASw3IHJeuKsR09XTZz1gUAEPkILjHu5hm5kujpAgBwBoJLjFswOUfJCW7tO9akTfvp6QIAiGwElxg3wBOnr02hpwsAwBkILjjd0+VzeroAACIbwQW6fPQgjRyUrBPNbfrzl/R0AQBELoIL6OkCAHAMggskSd+aPlyStHY3PV0AAJGL4AJJ7T1dZo0dLGOk/+GsCwAgQhFcEOC/SfeNzfR0AQBEJoILAhZMydGABLf2H2vSRnq6AAAiEMEFAckJnXq6bORyEQAg8hBc0IX/ctGSrUfU1NJmczUAAHRFcEEXl4+hpwsAIHIRXNCFZVmnb9JldhEAIMIQXNCNv6fLx7uP6dDxJpurAQDgNIILuhmRkawrx3X0dNl82O5yAAAIILigR50vF9HTBQAQKaImuJSUlCgvL08FBQV2lxIVvjq5vafLgZombdhHTxcAQGSImuBSXFyssrIybdiwwe5SokJyQpyuv7Sjp8umgzZXAwBAu6gJLgi+m2fkSpKWfE5PFwBAZCC44KwKRmdo1OBkNbZ49e4X9HQBANiP4IKzsixLN0+npwsAIHIQXHBO35oxQpbV3tPlYA09XQAA9iK44JyGpyfpynGDJdHTBQBgP4ILzivQ02XzQfl89HQBANiH4ILzmn9JjgZ64nSw5qQ27KuxuxwAQAwjuOC8khPidP0Uf08XbtIFANiH4IJeufmy9stFS7YeUWMzPV0AAPYguKBXLhuVodGDk9VETxcAgI0ILugVy7K6PHgRAAA7EFzQa9+c3t7TZd0eeroAAOxBcEGvDU9P0lXjMiVJf9zMWRcAQPgRXNAn/stFf9x8iJ4uAICwI7igTzr3dPmUni4AgDAjuKBPkhLcuuFSeroAAOxBcEGf+S8XLaWnCwAgzAgu6LMZozI0JnOAmlq8WkZPFwBAGBFc0Gdde7octLkaAEAsIbigX745bbgsS/pkT40OHKOnCwAgPAgu6Jdh6UmaPZ6eLgCA8CK4oN/o6QIACDeCC/rturwcpXjidOj4Sa3fS08XAEDoEVzQb0kJbt2QT08XAED4EFxwQfyXi5Z9QU8XAEDoEVxwQaaPzNDYjp4uS7cesbscAECUI7jggliWpW8HerpwuQgAEFoEF1ywb01v7+myfi89XQAAoUVwwQUbmna6p8sb9HQBAIQQwQVBEejpsomeLgCA0CG4ICjmX9Le0+Vw7Ul9sveY3eUAAKIUwQVBkRjv1g35wyRxky4AIHQILgiaQE+XrRU6QU8XAEAIEFwQNNNHpmvskAE62UpPFwBAaBBcEDSWZQXOunC5CAAQCgQXBNW3po2Qy5I+3Vuj/cca7S4HABBlCC4Iqpy0RM2eMERS+9RoAACCieCCoAv0dNl8mJ4uAICgIrgg6K7Ly1ZKYkdPlz30dAEABA/BBUGXGO/WjfR0AQCEAMEFIeG/XLT0iyNqONVqczUAgGhBcEFITMtN17ghA3Sq1adlWyvsLgcAECUILgiJ9p4uuZK4XAQACB6CC0Lmm9OGt/d02VejfdX0dAEAXDiCC0ImJy1RV/t7umzmrAsA4MIRXBBSgZ4umw7R0wUAcMEILgipazt6upTXndI6eroAAC4QwQUhlRjv1k30dAEABAnBBSHnv1y0jJ4uAIALRHBByE3NTdf4rIE61erT0q1H7C4HAOBgBBeEXHtPl/azLlwuAgBcCIILwsLf02XDvuP0dAEA9BvBBWGRnZqoaya293ThrAsAoL8ILgibQE+XzYfkpacLAKAfCC4Im6KLs5WaGKcjdae0bjc9XQAAfUdwQdgkxrt101R/T5eDNlcDAHAiggvCyv/E6He/rFA9PV0AAH1EcEFY5Y9I0wR/T5fP6ekCAOgbggvCip4uAIALQXBB2Pl7umzcf1x76ekCAOgDggvCLis1UYWBni7cpAsA6D2CC2zhv0n3fzYfpqcLAKDXCC6wxbyLs5SWFK8jdaf08e5qu8sBADgEwQW2SIx366Z8f08XbtIFAPQOwQW28c8uevcLeroAAHqH4ALbXDoiTROzB6q5zacl9HQBAPQCwQW2oacLAKCvCC6w1TemDpfbZWnT/uPac/SE3eUAACIcwQW26trThbMuAIBzI7jAdv7LRfR0AQCcT8QFl4MHD2rOnDnKy8vTpZdeqtdff93ukhBi/p4uFfWntHYXPV0AAGcXccElLi5Ov/nNb1RWVqb33ntP999/vxobeZ5NNPPEufX1qfR0AQCcX8QFl6FDh2rq1KmSpJycHGVmZqqmpsbeohBy/stFf/6yQnUn6ekCAOhZn4PLqlWrdOONN2rYsGGyLEtvvfVWt3VKSko0evRoJSYmaubMmfr000/7VdymTZvk9XqVm5vbr+3hHFOG09MFAHB+fQ4ujY2Nys/PV0lJSY/LX331VS1cuFAPPfSQNm/erPz8fM2fP19VVVWBdaZOnarJkyd3+yovLw+sU1NTo+9973v63e9+d856mpubVV9f3+ULzmNZlm7pePAiT4wGAJyNZYzp9zQOy7L05ptv6hvf+EbgvZkzZ6qgoEC//e1vJUk+n0+5ubn6yU9+ogceeKBX+21ubta1116rO++8U7fddts51/3lL3+phx9+uNv7dXV1Sk1N7f2Hge2qGk5p1uIP5PUZrfhpocYNGWh3SQCAMKmvr1daWtp5f34H9R6XlpYWbdq0SUVFRacP4HKpqKhI69at69U+jDH6/ve/r6985SvnDS2S9OCDD6quri7wdfAgv607VVZKoubQ0wUAcA5BDS7V1dXyer3Kzs7u8n52drYqKip6tY+1a9fq1Vdf1VtvvaWpU6dq6tSp2rp161nX93g8Sk1N7fIF5zrd0+UQPV0AAN3E2V3AmWbPni2fz2d3GbDJVy7OUnpyvCrrm7VmV3Wgqy4AAFKQz7hkZmbK7XarsrKyy/uVlZXKyckJ5qEQpTxxbn09n54uAICeBTW4JCQkaMaMGVqxYkXgPZ/PpxUrVmjWrFnBPBSi2M0ds4vo6QIAOFOfg8uJEydUWlqq0tJSSdLevXtVWlqqAwcOSJIWLlyo559/Xi+//LK2bdume+65R42NjbrjjjuCWjii1+ThqZqUnaKWNp/+9Hn5+TcAAMSMPgeXjRs3atq0aZo2bZqk9qAybdo0LVq0SJL0ne98R48//rgWLVqkqVOnqrS0VO+++263G3aBs7EsS7dc1n6TLpeLAACdXVAfl0jU23ngiGxHG5p1xeIV8vqM3l9YqPFZ9HQBgGhmSx8XIFiGpHg0dxI9XQAAXRFcELH8PV3e3EJPFwBAO4ILItZXLspWRkdPl9U7j9pdDgAgAkRNcCkpKVFeXp4KCgrsLgVBkhDn0tenDpfE5SIAQLuoCS7FxcUqKyvThg0b7C4FQeS/XPReWaXqmujpAgCxLmqCC6LTJcNSdVFOe0+X/0dPFwCIeQQXRDTLsgJnXbhcBAAguCDifWPacMW5LJUerNWuqga7ywEA2IjggoiXOdCjOZOyJEmvc9YFAGIawQWOEOjpsvmw2rw+m6sBANiF4AJH+MpFWcpIjldVQ7NW76q2uxwAgE0ILnAEeroAACSCCxzEf7lo+Zf0dAGAWEVwgWMEerp4fXqHni4AEJMILnAMy7J0y2W5krhcBACxiuACR/n61GGKc1n67GCtdlbS0wUAYk3UBBceshgbMgd6NPei9p4unHUBgNgTNcGFhyzGDv9Nuv+zhZ4uABBroia4IHbMnZSlQQMSdLShWat30tMFAGIJwQWO097TZZgk6b5XtujJ97breGOLzVUBAMKB4AJH+tE14zQha6DqT7Xp3z/Ypav+9QP985/KVFl/yu7SAAAhZBljjN1FBFN9fb3S0tJUV1en1NRUu8tBCHl9Rn/+skIlH+7Sl+X1kqQEt0vfnjFC9xSO08jByTZXCADord7+/Ca4wPGMMfpox1GVfLhLG/YdlyS5LOmm/GG6Z854TcpJsblCAMD5EFwILjHp0701Kvlwlz7acTTw3nV52SqeO175uen2FQYAOCeCC8Elpn1xuE4lH+7Su19WyP8v/OoJmbp3znhdMXaQLMuyt0AAQBcEF4ILJO2qatAzK/fordLD8vra/6lPH5mu4rnj9ZWLsggwABAhCC4EF3RysKZJv1u1R69uPKiWtvamdRflpKh47nh9bcpQuV0EGACwE8GF4IIeVDWc0n+s3qvff7JfjS1eSdKYzAG6u3CsvjlthBLi6BAAAHYguBBccA61TS16+eP9evHjvaptapUkDU1L1F3XjNX/KhippAS3zRUCQGwhuBBc0AuNzW367/UH9PzqPapqaJYkDR6QoB/MHqPbZo1SamK8zRUCQGwguBBc0AenWr364+ZDevaj3TpYc1KSlJIYp9tnjdYdV43W4IEemysEgOgWc8GlpKREJSUl8nq92rFjB8EF/dLm9en/fV6upz/crZ1VJyRJifEu3Xr5SN11zVgNTUuyuUIAiE4xF1z8OOOCYPD5jN4rq1TJh7u09XCdJCnebenb00fo7sJxGp05wOYKASC6EFwILggCY4zW7KrWbz/YpfV7ayS1P07g+kuH6d4543TxUP6NAUAwEFwILgiyjftq9PTK3frgL1WB94ouztK9c8dr+sgMGysDAOcjuBBcECJfltfp6ZW7tXTrkcDjBGaNHawff2W8rhw3mG68ANAPBBeCC0Jsz9ETemblbr255bDaOh4nkJ+brh/PHa95F2XJRTdeAOg1ggvBBWFyuPaknl+1R3/49ICaOx4nMCk7RffOHafrpwxVnJtuvABwPgQXggvC7GhDs15Yu1f/d91+nWhukySNGpysuwvH6VvTh8sTRzdeADgbggvBBTapO9mq/7tun/5jzV4d73icQHaqR3dePVb/e+ZIJSfE2VwhAEQeggvBBTZramnTHz49qOdX7VFF/SlJUkZyvH5w1Rh9b9ZopSXzOAEA8CO4EFwQIZrbvHpz82E989Fu7T/WJEka6InTX18xSj+cPUZDUnicAAAQXAguiDBtXp+WbD2ipz/cre2VDZIkT5xL/6sgV1eNz1RyQpySEtwa4HErOf7068Q4NzOUAEQ9ggvBBRHK5zNa8Zcq/fbDXfrsYG2vtkmKbw8xSQntoSbZ41ZygltJ8XHtQafT6/Z13Er2xCk5wd3x1f11UoJbCW4XfWcARITe/vzmLkEgzFwuS9fmZavo4iyt231M/7luvyobTulki1eNLW062eJVU8eX38lWr062es+x1/6Jc1ntQSfBrQEdZ3zODDcDznh95jqdX7tdlnzGyGfU/qev02tjZAKvJa/PyJjuy72+7uueb1++jm38y02nY5xvX11raP9TkqyO/3FZlixJVqfXsiy5LMmSJctqX9d/VszqYZv299vfc1kdr63T71kd+2pf1mm//m1cp9+TOvZ/xjYKvO60zzMy6Zm/pnb7u85cbs65vKd9nLnW+Y9x5vK+/S7d8f9I9/fPksfPFdPPnuGDdwwj/2c2gc/uf890vNf+99Pj0GWZOT2GxnSMVrdt/fs9/Z461g0s6/T3cx6v09/VafvCiUM0eXjaOT5p6BBcAJtYlqUrx2fqyvGZPS73+YxOtXWEmGavmlrbTr9uadPJVq8a/a9bvGps8epkS1vHn+3vd37tD0MnW7xq8bb3m2nzGTWcalPDqTZJzWH89ACcLD05nuACoCuXy+o4kxEnDQzuvlu9vkCI6XyWp+sZH39Q6viz9fTr9tDU+XV7aPKZ9jMK/jMCLpclt2XJ6jhD4bJOnxVwu6yu61pW4HX7stPrBrZ1dd5P5+3at+l6nK776rzu+fYlqctvm/6zMP6zM/7fRn2dfnP2rxf4DTXw2r9N1/d62kbqWLfjPf9rSYEzR/7ffn1Ggd+0z9ym82/Xnc8KdDsTcMYpgzOXn3lGofvys2/ffdtz7+x8xz7T2W5y6PHts67bfUGf9qvuZ6XOva7/jFr3s22SpMCyzmfdTi/3j0nXbU///fQ6VqdlXc/WBfbXQx0dJZze3xlnFU+vY2nckCB/U+oDggsQg+LdLqUluZSWxJRsAM5CL3IAAOAYURNcSkpKlJeXp4KCArtLAQAAIcJ0aAAAYLve/vyOmjMuAAAg+hFcAACAYxBcAACAYxBcAACAYxBcAACAYxBcAACAYxBcAACAYxBcAACAYxBcAACAYxBcAACAYxBcAACAY8TZXUCw+R+9VF9fb3MlAACgt/w/t8/3CMWoCy4NDQ2SpNzcXJsrAQAAfdXQ0KC0tLSzLo+6p0P7fD6Vl5crJSVFlmXZXY6j1dfXKzc3VwcPHuRJ20HCmIYG4xp8jGnwMabnZoxRQ0ODhg0bJpfr7HeyRN0ZF5fLpREjRthdRlRJTU3lP7IgY0xDg3ENPsY0+BjTszvXmRY/bs4FAACOQXABAACOQXDBWXk8Hj300EPyeDx2lxI1GNPQYFyDjzENPsY0OKLu5lwAABC9OOMCAAAcg+ACAAAcg+ACAAAcg+ACAAAcg+ASRUpKSjR69GglJiZq5syZ+vTTT8+5/uuvv66LLrpIiYmJmjJlipYuXdpluTFGixYt0tChQ5WUlKSioiLt3Lmzyzo1NTX67ne/q9TUVKWnp+uHP/yhTpw4EVi+b98+WZbV7euTTz4J3gcPITvG9JFHHtGVV16p5ORkpaen93icAwcO6Prrr1dycrKysrL093//92pra7ugzxoukTqmPf07feWVVy7os4ZTuMd13759+uEPf6gxY8YoKSlJ48aN00MPPaSWlpYu+/n888919dVXKzExUbm5uXr00UeD96FDLBLH1OnfU4PCICq88sorJiEhwbzwwgvmyy+/NHfeeadJT083lZWVPa6/du1a43a7zaOPPmrKysrMz3/+cxMfH2+2bt0aWOfXv/61SUtLM2+99Zb57LPPzE033WTGjBljTp48GVjnq1/9qsnPzzeffPKJWb16tRk/fry59dZbA8v37t1rJJn333/fHDlyJPDV0tISusEIErvGdNGiRebJJ580CxcuNGlpad2O09bWZiZPnmyKiorMli1bzNKlS01mZqZ58MEHgz4GwRapY2qMMZLMiy++2OXfaed9RDI7xnXZsmXm+9//vvnzn/9sdu/ebd5++22TlZVlfvrTnwb2UVdXZ7Kzs813v/td88UXX5g//OEPJikpyTz33HOhHZAgiNQxdfL31GAhuESJyy+/3BQXFwf+7vV6zbBhw8zixYt7XP+v/uqvzPXXX9/lvZkzZ5of/ehHxhhjfD6fycnJMY899lhgeW1trfF4POYPf/iDMcaYsrIyI8ls2LAhsM6yZcuMZVnm8OHDxpjT/5Ft2bIlKJ8znOwY085efPHFHn/ILl261LhcLlNRURF475lnnjGpqammubm5T58x3CJ1TI1pDy5vvvlmHz9RZLB7XP0effRRM2bMmMDfn376aZORkdHl3+U//MM/mEmTJvXtA9ogUsfUyd9Tg4VLRVGgpaVFmzZtUlFRUeA9l8uloqIirVu3rsdt1q1b12V9SZo/f35g/b1796qioqLLOmlpaZo5c2ZgnXXr1ik9PV2XXXZZYJ2ioiK5XC6tX7++y75vuukmZWVlafbs2XrnnXcu7AOHgV1j2hvr1q3TlClTlJ2d3eU49fX1+vLLL3u9n3CL5DH1Ky4uVmZmpi6//HK98MILMg5ocxVJ41pXV6dBgwZ1Oc4111yjhISELsfZvn27jh8/3rcPGkaRPKZ+TvueGkwElyhQXV0tr9fb5QeZJGVnZ6uioqLHbSoqKs65vv/P862TlZXVZXlcXJwGDRoUWGfgwIF64okn9Prrr2vJkiWaPXu2vvGNb0T8f2h2jWlvnO04nY8RiSJ5TCXpV7/6lV577TUtX75c3/72t3Xvvffqqaee6tM+7BAp47pr1y499dRT+tGPfnTe43Q+RiSK5DF16vfUYIq6p0MjsmRmZmrhwoWBvxcUFKi8vFyPPfaYbrrpJhsrA7r6xS9+EXg9bdo0NTY26rHHHtPf/M3f2FiVMxw+fFhf/epXdcstt+jOO++0u5yocLYx5XsqZ1yiQmZmptxutyorK7u8X1lZqZycnB63ycnJOef6/j/Pt05VVVWX5W1tbaqpqTnrcSVp5syZ2rVrVy8+mX3sGtPeONtxOh8jEkXymPZk5syZOnTokJqbmy9oP6Fm97iWl5dr7ty5uvLKK/W73/2uV8fpfIxIFMlj2hMnfE8NJoJLFEhISNCMGTO0YsWKwHs+n08rVqzQrFmzetxm1qxZXdaXpOXLlwfWHzNmjHJycrqsU19fr/Xr1wfWmTVrlmpra7Vp06bAOh988IF8Pp9mzpx51npLS0s1dOjQvn/QMLJrTHtj1qxZ2rp1a5fQuHz5cqWmpiovL6/X+wm3SB7TnpSWliojIyPiH4hn57gePnxYc+bM0YwZM/Tiiy/K5er6I2XWrFlatWqVWltbuxxn0qRJysjI6P+HDrFIHtOeOOF7alDZfXcwguOVV14xHo/HvPTSS6asrMzcddddJj09PTDz5LbbbjMPPPBAYP21a9eauLg48/jjj5tt27aZhx56qMepe+np6ebtt982n3/+ufn617/e43ToadOmmfXr15s1a9aYCRMmdJkO/dJLL5n//u//Ntu2bTPbtm0zjzzyiHG5XOaFF14Iw6hcGLvGdP/+/WbLli3m4YcfNgMHDjRbtmwxW7ZsMQ0NDcaY09Ohr7vuOlNaWmreffddM2TIEMdMh47EMX3nnXfM888/b7Zu3Wp27txpnn76aZOcnGwWLVoUppG5MHaM66FDh8z48ePNvHnzzKFDh7pMzfWrra012dnZ5rbbbjNffPGFeeWVV0xycrJjpkNH4pg6+XtqsBBcoshTTz1lRo4caRISEszll19uPvnkk8CywsJCc/vtt3dZ/7XXXjMTJ040CQkJ5pJLLjFLlizpstzn85lf/OIXJjs723g8HjNv3jyzffv2LuscO3bM3HrrrWbgwIEmNTXV3HHHHYEfBsa0/0d28cUXm+TkZJOammouv/xy8/rrrwf/w4eIHWN6++23G0ndvj788MPAOvv27TMLFiwwSUlJJjMz0/z0pz81ra2tQf/8oRCJY7ps2TIzdepUM3DgQDNgwACTn59vnn32WeP1ekMyBqEQ7nF98cUXexzTM38f/uyzz8zs2bONx+Mxw4cPN7/+9a+D/+FDJBLH1OnfU4PBMsYB8/0AAADEPS4AAMBBCC4AAMAxCC4AAMAxCC4AAMAxCC4AAMAxCC4AAMAxCC4AAMAxCC4AAMAxCC4AosJLL72k9PR0u8sAEGIEFwAA4BgEFwAA4BgEFwBh9cYbb2jKlClKSkrS4MGDVVRUpMbGRknSCy+8oEsuuUQej0dDhw7Vj3/848B2Tz75pKZMmaIBAwYoNzdX9957r06cOHHOY7399tuaPn26EhMTNXbsWD388MNqa2sL6ecDEFoEFwBhc+TIEd166636wQ9+oG3btmnlypX61re+JWOMnnnmGRUXF+uuu+7S1q1b9c4772j8+PGBbV0ul/793/9dX375pV5++WV98MEH+tnPfnbWY61evVrf+973dN9996msrEzPPfecXnrpJT3yyCPh+KgAQoSnQwMIm82bN2vGjBnat2+fRo0a1WXZ8OHDdccdd+if//mfe7WvN954Q3fffbeqq6sltd+ce//996u2tlaSVFRUpHnz5unBBx8MbPP73/9eP/vZz1ReXh6cDwQg7OLsLgBA7MjPz9e8efM0ZcoUzZ8/X9ddd51uvvlmtba2qry8XPPmzTvrtu+//74WL16sv/zlL6qvr1dbW5tOnTqlpqYmJScnd1v/s88+09q1a7ucYfF6vefcBkDk41IRgLBxu91avny5li1bpry8PD311FOaNGmSKisrz7ndvn37dMMNN+jSSy/VH//4R23atEklJSWSpJaWlh63OXHihB5++GGVlpYGvrZu3aqdO3cqMTEx6J8NQHhwxgVAWFmWpauuukpXXXWVFi1apFGjRmn58uUaPXq0VqxYoblz53bbZtOmTfL5fHriiSfkcrX/vvXaa6+d8zjTp0/X9u3bu9wnA8D5CC4Awmb9+vVasWKFrrvuOmVlZWn9+vU6evSoLr74Yv3yl7/U3XffraysLC1YsEANDQ1au3atfvKTn2j8+PFqbW3VU089pRtvvFFr167Vs88+e85jLVq0SDfccINGjhypm2++WS6XS5999pm++OKLXt9HAyDycKkIQNikpqZq1apV+trXvqaJEyfq5z//uZ544gktWLBAt99+u37zm9/o6aef1iWXXKIbbrhBO3fulNR+b8yTTz6pf/3Xf9XkyZP1X//1X1q8ePE5jzV//nz96U9/0nvvvaeCggJdccUV+rd/+7duNwUDcBZmFQEAAMfgjAsAAHAMggsAAHAMggsAAHAMggsAAHAMggsAAHAMggsAAHAMggsAAHAMggsAAHAMggsAAHAMggsAAHAMggsAAHCM/w+aUWNapNVxNQAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "df.plot(x=\"scale\", y=\"err\", logy=True);" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e7e555ce", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.4" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/python/on_device_training/overview.rst b/docs/python/on_device_training/overview.rst new file mode 100644 index 0000000000000..cd68f9992cae6 --- /dev/null +++ b/docs/python/on_device_training/overview.rst @@ -0,0 +1,11 @@ +Overview +========= + +`On-Device Training` refers to the process of training a model on an edge device, such as mobile phones, embedded devices, gaming consoles, web browsers, etc. This is in contrast to training a model on a server or a cloud. Training on the edge is useful when the data is sensitive and cannot be shared with a server or a cloud. It is also useful for the task of personalization where the model needs to be trained on the user's device. + +`onnxruntime-training` offers an easy way to efficiently train and infer a wide range of ONNX models on edge devices. The training process is divided into two phases: + +- The offline phase: In this phase, training artifacts are prepared on a server, cloud or a desktop. These artifacts can be generated by using the `onnxruntime-training`'s :doc:`artifact generation python tools`. +- The training phase: Once these artifacts are generated, they can be deployed on an edge device. The onnxruntime-training's :doc:`training API` can be used to train a model on the edge device. + +Once training on the edge device is complete, an inference-ready onnx model can be generated on the edge device itself. This model can then be used with ONNX Runtime for inferencing. diff --git a/docs/python/on_device_training/training_api.rst b/docs/python/on_device_training/training_api.rst new file mode 100644 index 0000000000000..64f81f3f18142 --- /dev/null +++ b/docs/python/on_device_training/training_api.rst @@ -0,0 +1,69 @@ +Train the Model on the Device +============================== + +Once the training artifacts are generated, the model can be trained on the device using the onnxruntime training python API. + +The expected training artifacts are: + +1. The training onnx model +2. The checkpoint state +3. The optimizer onnx model +4. The eval onnx model (optional) + +Sample usage: + +.. code-block:: python + + from onnxruntime.training.api import CheckpointState, Module, Optimizer + + # Load the checkpoint state + state = CheckpointState.load_checkpoint(path_to_the_checkpoint_artifact) + + # Create the module + module = Module(path_to_the_training_model, + state, + path_to_the_eval_model, + device="cpu") + + optimizer = Optimizer(path_to_the_optimizer_model, module) + + # Training loop + for ...: + module.train() + training_loss = module(...) + optimizer.step() + module.lazy_reset_grad() + + # Eval + module.eval() + eval_loss = module(...) + + # Save the checkpoint + CheckpointState.save_checkpoint(state, path_to_the_checkpoint_artifact) + + +.. autoclass:: onnxruntime.training.api.CheckpointState + :members: + :show-inheritance: + :member-order: bysource + :inherited-members: + :special-members: __getitem__, __setitem__, __contains__ + +.. autoclass:: onnxruntime.training.api.Module + :members: + :show-inheritance: + :member-order: bysource + :inherited-members: + :special-members: __call__ + +.. autoclass:: onnxruntime.training.api.Optimizer + :members: + :show-inheritance: + :member-order: bysource + :inherited-members: + +.. autoclass:: onnxruntime.training.api.LinearLRScheduler + :members: + :show-inheritance: + :member-order: bysource + :inherited-members: diff --git a/docs/python/on_device_training/training_artifacts.rst b/docs/python/on_device_training/training_artifacts.rst new file mode 100644 index 0000000000000..a6f5ae2e31822 --- /dev/null +++ b/docs/python/on_device_training/training_artifacts.rst @@ -0,0 +1,141 @@ +Prepare for training +===================== + +Before the training can start on edge devices, the training artifacts need to be generated in an offline step. + +These artifacts include: + +1. The training onnx model +2. The checkpoint state +3. The optimizer onnx model +4. The eval onnx model (optional) + +It is assumed that the an forward only onnx model is already available. This model can be generated by exporting the PyTorch model using the :func:`torch.onnx.export` API if using PyTorch. + +.. note:: + If using PyTorch to export the model, please use the following export arguments so training artifact generation can be successful: + + - ``export_params``: ``True`` + - ``do_constant_folding``: ``False`` + - ``training``: ``torch.onnx.TrainingMode.TRAINING`` + + +Once the forward only onnx model is available, the training artifacts can be generated using the :func:`onnxruntime.training.artifacts.generate_artifacts` API. + +Sample usage: + +.. code-block:: python + + from onnxruntime.training import artifacts + + # Load the forward only onnx model + model = onnx.load(path_to_forward_only_onnx_model) + + # Generate the training artifacts + artifacts.generate_artifacts(model, + requires_grad = ["parameters", "needing", "gradients"], + frozen_params = ["parameters", "not", "needing", "gradients"], + loss = artifacts.LossType.CrossEntropyLoss, + optimizer = artifacts.OptimType.AdamW, + artifact_directory = path_to_output_artifact_directory) + +.. autoclass:: onnxruntime.training.artifacts.LossType + :members: + :member-order: bysource + :undoc-members: + +.. autoclass:: onnxruntime.training.artifacts.OptimType + :members: + :member-order: bysource + :undoc-members: + +.. autofunction:: onnxruntime.training.artifacts.generate_artifacts + +Custom Loss +++++++++++++ + +If a custom loss is needed, the user can provide a custom loss function to the :func:`onnxruntime.training.artifacts.generate_artifacts` API. +This is done by inheriting from the :class:`onnxruntime.training.onnxblock.Block` class and implementing the `build` method. + +The following example shows how to implement a custom loss function: + +Let's assume, we want to use a custom loss function with a model. For this example, we assume that our model generates +two outputs. And the custom loss function must apply a loss function on each of the outputs and perform a weighted average +on the output. Mathematically, + +.. code-block:: python + + loss = 0.4 * mse_loss1(output1, target1) + 0.6 * mse_loss2(output2, target2) + +Since this is a custom loss function, this loss type is not exposed as an enum by `LossType` enum. + +For this, we make use of `onnxblock`. + +.. code-block:: python + + import onnxruntime.training.onnxblock as onnxblock + from onnxruntime.training import artifacts + + # Define a custom loss block that takes in two inputs + # and performs a weighted average of the losses from these + # two inputs. + class WeightedAverageLoss(onnxblock.Block): + def __init__(self): + self._loss1 = onnxblock.loss.MSELoss() + self._loss2 = onnxblock.loss.MSELoss() + self._w1 = onnxblock.blocks.Constant(0.4) + self._w2 = onnxblock.blocks.Constant(0.6) + self._add = onnxblock.blocks.Add() + self._mul = onnxblock.blocks.Mul() + + def build(self, loss_input_name1, loss_input_name2): + # The build method defines how the block should be stacked on top of + # loss_input_name1 and loss_input_name2 + + # Returns weighted average of the two losses + return self._add( + self._mul(self._w1(), self._loss1(loss_input_name1, target_name="target1")), + self._mul(self._w2(), self._loss2(loss_input_name2, target_name="target2")) + ) + + my_custom_loss = WeightedAverageLoss() + + # Load the onnx model + model_path = "model.onnx" + base_model = onnx.load(model_path) + + # Define the parameters that need their gradient computed + requires_grad = ["weight1", "bias1", "weight2", "bias2"] + frozen_params = ["weight3", "bias3"] + + # Now, we can invoke generate_artifacts with this custom loss function + artifacts.generate_artifacts(base_model, requires_grad = requires_grad, frozen_params = frozen_params, + loss = my_custom_loss, optimizer = artifacts.OptimType.AdamW) + + # Successful completion of the above call will generate 4 files in the current working directory, + # one for each of the artifacts mentioned above (training_model.onnx, eval_model.onnx, checkpoint, optimizer_model.onnx) + +.. autoclass:: onnxruntime.training.onnxblock.Block + :members: + :show-inheritance: + :member-order: bysource + :inherited-members: + +Advanced Usage ++++++++++++++++ + +`onnxblock` is a library that can be used to build complex onnx models by stacking simple blocks on top of each other. An example of this is the ability to build a custom loss function as shown above. + +`onnxblock` also provides a way to build a custom forward only or training (forward + backward) onnx model through the :class:`onnxruntime.training.onnxblock.ForwardBlock` and :class:`onnxruntime.training.onnxblock.TrainingBlock` classes respectively. These blocks inherit from the base :class:`onnxruntime.training.onnxblock.Block` class and provide additional functionality to build inference and training models. + +.. autoclass:: onnxruntime.training.onnxblock.ForwardBlock + :members: + :show-inheritance: + :member-order: bysource + :inherited-members: + +.. autoclass:: onnxruntime.training.onnxblock.TrainingBlock + :members: + :show-inheritance: + :member-order: bysource + :inherited-members: diff --git a/docs/python/ortmodule/api.rst b/docs/python/ortmodule/api.rst new file mode 100644 index 0000000000000..08b05ef96cc0e --- /dev/null +++ b/docs/python/ortmodule/api.rst @@ -0,0 +1,8 @@ +API +=== + +.. autoclass:: onnxruntime.training.ORTModule + :members: + :show-inheritance: + :member-order: bysource + :inherited-members: diff --git a/docs/python/ortmodule/overview.rst b/docs/python/ortmodule/overview.rst new file mode 100644 index 0000000000000..8c2eebf30aa0c --- /dev/null +++ b/docs/python/ortmodule/overview.rst @@ -0,0 +1,37 @@ +Overview +========= + +`onnxruntime-training`'s `ORTModule` offers a high performance training engine for models defined using the `PyTorch` frontend. `ORTModule` is designed to accelerate the training of large models without needing to change either the model definition or the training code. + +The aim of `ORTModule` is to provide a drop-in replacement for one or more `torch.nn.Module` objects in a user's `PyTorch` program, and execute the forward and backward passes of those modules using ORT. + +As a result, the user will be able to accelerate their training script using ORT, +without having to modify their training loop. + +Users will be able to use standard PyTorch debugging techniques for convergence issues, e.g. by probing the computed gradients on the model's parameters. + +The following code example illustrates how ORTModule would be used in a user's training script, in the simple case where the entire model can be offloaded to ONNX Runtime: + +.. code-block:: python + + from onnxruntime.training import ORTModule + + # Original PyTorch model + class NeuralNet(torch.nn.Module): + def __init__(self, input_size, hidden_size, num_classes): + ... + def forward(self, x): + ... + + model = NeuralNet(input_size=784, hidden_size=500, num_classes=10) + model = ORTModule(model) # The only change to the original PyTorch script + criterion = torch.nn.CrossEntropyLoss() + optimizer = torch.optim.SGD(model.parameters(), lr=1e-4) + + # Training Loop is unchanged + for data, target in data_loader: + optimizer.zero_grad() + output = model(data) + loss = criterion(output, target) + loss.backward() + optimizer.step() diff --git a/docs/python/requirements.txt b/docs/python/requirements.txt index a6c7290790e47..0caedaf44a0c8 100644 --- a/docs/python/requirements.txt +++ b/docs/python/requirements.txt @@ -7,6 +7,7 @@ sphinx-gallery sphinxcontrib.imagesvg sphinxcontrib.googleanalytics sphinx_rtd_theme +furo pyquickhelper pandas pydot @@ -17,3 +18,8 @@ packaging protobuf sympy onnx +sphinx_exec_code +sphinx_tabs +furo +-f https://download.pytorch.org/whl/torch/ +torch diff --git a/docs/python/training/conf.py b/docs/python/training/conf.py deleted file mode 100644 index 5dd0f60506433..0000000000000 --- a/docs/python/training/conf.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -# -*- coding: utf-8 -*- -# -# Configuration file for the Sphinx documentation builder. - -# -- Project information ----------------------------------------------------- - -project = "ORTModule" -copyright = "2018-2021, Microsoft" -author = "Microsoft" -version = "0.1" # TODO: Should use `onnxruntime.__version__` instead? -release = version - -# -- General configuration --------------------------------------------------- - -extensions = ["sphinx.ext.autodoc", "sphinx.ext.intersphinx"] -templates_path = ["_templates"] -exclude_patterns = [] -autoclass_content = "both" - -# -- Options for HTML output ------------------------------------------------- - -html_theme = "sphinx_rtd_theme" -html_static_path = ["_static"] - -# -- Options for intersphinx extension --------------------------------------- - -intersphinx_mapping = { - "python": ("https://docs.python.org/3", None), - "numpy": ("https://numpy.org/doc/stable", None), - "torch": ("https://pytorch.org/docs/stable/", None), -} diff --git a/docs/python/training/content.rst b/docs/python/training/content.rst deleted file mode 100644 index 595a4259a2d08..0000000000000 --- a/docs/python/training/content.rst +++ /dev/null @@ -1,54 +0,0 @@ -This document describes ORTModule PyTorch frontend API for the ONNX Runtime (aka ORT) training acelerator. - -What is new -=========== - -Version 0.1 ------------ - -#. Initial version - -Overview -======== -The aim of ORTModule is to provide a drop-in replacement for one or more torch.nn.Module objects in a user’s PyTorch program, -and execute the forward and backward passes of those modules using ORT. - -As a result, the user will be able to accelerate their training script gradually using ORT, -without having to modify their training loop. - -Users will be able to use standard PyTorch debugging techniques for convergence issues, -e.g. by probing the computed gradients on the model’s parameters. - -The following code example illustrates how ORTModule would be used in a user’s training script, -in the simple case where the entire model can be offloaded to ONNX Runtime: - -.. code-block:: python - - # Original PyTorch model - class NeuralNet(torch.nn.Module): -     def __init__(self, input_size, hidden_size, num_classes): -         ... -     def forward(self, x):  -         ... - - model = NeuralNet(input_size=784, hidden_size=500, num_classes=10) - model = ORTModule(model) # Only change to original PyTorch script - criterion = torch.nn.CrossEntropyLoss() - optimizer = torch.optim.SGD(model.parameters(), lr=1e-4) - - # Training Loop is unchanged - for data, target in data_loader: -     optimizer.zero_grad() -     output = model(data) -     loss = criterion(output, target) -     loss.backward() -     optimizer.step() - -API -=== - -.. automodule:: onnxruntime.training.ortmodule.ortmodule - :members: - :show-inheritance: - :member-order: bysource - :inherited-members: diff --git a/docs/python/training/index.rst b/docs/python/training/index.rst deleted file mode 100644 index c56050169df7f..0000000000000 --- a/docs/python/training/index.rst +++ /dev/null @@ -1,24 +0,0 @@ -.. ORTModule documentation master file, created by - sphinx-quickstart on Thu Mar 11 10:21:00 2021. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -ORTModule documentation -======================= - -ORTModule is a PyTorch frontend API for `ONNX Runtime `_, -a cross-platform inferencing and training accelerator. - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - content - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/python/inference/tutorial.rst b/docs/python/tutorial.rst similarity index 100% rename from docs/python/inference/tutorial.rst rename to docs/python/tutorial.rst diff --git a/include/onnxruntime/core/common/eigen_common_wrapper.h b/include/onnxruntime/core/common/eigen_common_wrapper.h index 4515f80ffd2b2..57599e04037dc 100644 --- a/include/onnxruntime/core/common/eigen_common_wrapper.h +++ b/include/onnxruntime/core/common/eigen_common_wrapper.h @@ -41,6 +41,14 @@ #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #endif +// eigen-src/unsupported/Eigen/CXX11/src/ThreadPool/EventCount.h:231:56: error: implicit conversion loses integer +// precision: 'uint64_t' (aka 'unsigned long long') to 'size_t' (aka 'unsigned long') [-Werror,-Wshorten-64-to-32] +// next = wnext == kStackMask ? nullptr : &waiters_[wnext]; +// ~~~~~~~~ ^~~~~ +#ifdef HAS_SHORTEN_64_TO_32 +#pragma GCC diagnostic ignored "-Wshorten-64-to-32" +#endif + #elif defined(_MSC_VER) // build\windows\debug\external\eigen3\unsupported\eigen\cxx11\src/Tensor/Tensor.h(76): // warning C4554: '&': check operator precedence for possible error; use parentheses to clarify precedence diff --git a/include/onnxruntime/core/common/logging/capture.h b/include/onnxruntime/core/common/logging/capture.h index 811744d2c03c0..2af050918706a 100644 --- a/include/onnxruntime/core/common/logging/capture.h +++ b/include/onnxruntime/core/common/logging/capture.h @@ -77,7 +77,7 @@ class Capture { char SeverityPrefix() const noexcept { // Carefully setup so severity_ is a valid index - GSL_SUPPRESS(bounds .2) { + GSL_SUPPRESS(bounds.2) { return logging::SEVERITY_PREFIX[static_cast(severity_)]; } } diff --git a/include/onnxruntime/core/common/narrow.h b/include/onnxruntime/core/common/narrow.h index 15bcf167db8c9..49dfbf3c45953 100644 --- a/include/onnxruntime/core/common/narrow.h +++ b/include/onnxruntime/core/common/narrow.h @@ -35,18 +35,13 @@ namespace detail { // narrow() : a checked version of narrow_cast() that terminates if the cast changed the value template ::value>::type* = nullptr> -// clang-format off -GSL_SUPPRESS(type.1) // NO-FORMAT: attribute - // clang-format on - constexpr T narrow(U u) noexcept { +GSL_SUPPRESS(type.1) constexpr T narrow(U u) noexcept { constexpr const bool is_different_signedness = (std::is_signed::value != std::is_signed::value); - // clang-format off -GSL_SUPPRESS(es.103) // NO-FORMAT: attribute // don't overflow -GSL_SUPPRESS(es.104) // NO-FORMAT: attribute // don't underflow -GSL_SUPPRESS(p.2) // NO-FORMAT: attribute // don't rely on undefined behavior - // clang-format on + GSL_SUPPRESS(es.103) // don't overflow + GSL_SUPPRESS(es.104) // don't underflow + GSL_SUPPRESS(p.2) // don't rely on undefined behavior const T t = gsl::narrow_cast(u); // While this is technically undefined behavior in some cases (i.e., if the source value is of floating-point type // and cannot fit into the destination integral type), the resultant behavior is benign on the platforms // that we target (i.e., no hardware trap representations are hit). @@ -59,10 +54,7 @@ GSL_SUPPRESS(p.2) // NO-FORMAT: attribute // don't rely on undefined behavior } template ::value>::type* = nullptr> -// clang-format off -GSL_SUPPRESS(type.1) // NO-FORMAT: attribute - // clang-format on - constexpr T narrow(U u) noexcept { +GSL_SUPPRESS(type.1) constexpr T narrow(U u) noexcept { const T t = gsl::narrow_cast(u); if (static_cast(t) != u) { diff --git a/include/onnxruntime/core/common/span_utils.h b/include/onnxruntime/core/common/span_utils.h index 82aa59f0d01bc..b2d1aefee9c04 100644 --- a/include/onnxruntime/core/common/span_utils.h +++ b/include/onnxruntime/core/common/span_utils.h @@ -4,6 +4,7 @@ #pragma once #include +#include #include "core/common/gsl.h" @@ -78,6 +79,10 @@ template return gsl::span(reinterpret_cast(src.data()), src.size_bytes() / sizeof(U)); } +[[nodiscard]] inline gsl::span AsByteSpan(const void* data, size_t length) { + return gsl::span(reinterpret_cast(data), length); +} + template [[nodiscard]] inline bool SpanEq(gsl::span a, gsl::span b) { static_assert(std::is_same_v, std::remove_const_t>, diff --git a/include/onnxruntime/core/common/status.h b/include/onnxruntime/core/common/status.h index 6ccd2f0bc94fa..8f171daabbb1e 100644 --- a/include/onnxruntime/core/common/status.h +++ b/include/onnxruntime/core/common/status.h @@ -19,7 +19,6 @@ limitations under the License. #ifdef _WIN32 #include #endif -#include "core/common/gsl.h" namespace onnxruntime { namespace common { @@ -121,10 +120,8 @@ class [[nodiscard]] Status { Status(StatusCategory category, int code); - GSL_SUPPRESS(r .11) Status(const Status& other) : state_((other.state_ == nullptr) ? nullptr : new State(*other.state_)) {} - GSL_SUPPRESS(r .11) Status& operator=(const Status& other) { if (state_ != other.state_) { if (other.state_ == nullptr) { diff --git a/include/onnxruntime/core/framework/allocator.h b/include/onnxruntime/core/framework/allocator.h index de3b35f305921..cbc2208b6bbd7 100644 --- a/include/onnxruntime/core/framework/allocator.h +++ b/include/onnxruntime/core/framework/allocator.h @@ -8,6 +8,7 @@ #include "core/session/onnxruntime_c_api.h" #include "ortdevice.h" #include "ortmemoryinfo.h" +#include // This configures the arena based allocator used by ORT // See docs/C_API.md for details on what these mean and how to choose these values @@ -16,20 +17,24 @@ struct OrtArenaCfg { arena_extend_strategy(-1), initial_chunk_size_bytes(-1), max_dead_bytes_per_chunk(-1), - initial_growth_chunk_size_bytes(-1) {} + initial_growth_chunk_size_bytes(-1), + max_power_of_two_extend_bytes(-1) {} OrtArenaCfg(size_t max_mem, int arena_extend_strategy, int initial_chunk_size_bytes, - int max_dead_bytes_per_chunk, int initial_growth_chunk_size_bytes) + int max_dead_bytes_per_chunk, int initial_growth_chunk_size_bytes, + int64_t max_power_of_two_extend_bytes) : max_mem(max_mem), arena_extend_strategy(arena_extend_strategy), initial_chunk_size_bytes(initial_chunk_size_bytes), max_dead_bytes_per_chunk(max_dead_bytes_per_chunk), - initial_growth_chunk_size_bytes(initial_growth_chunk_size_bytes) {} - - size_t max_mem; // use 0 to allow ORT to choose the default - int arena_extend_strategy; // use -1 to allow ORT to choose the default, 0 = kNextPowerOfTwo, 1 = kSameAsRequested - int initial_chunk_size_bytes; // use -1 to allow ORT to choose the default - int max_dead_bytes_per_chunk; // use -1 to allow ORT to choose the default - int initial_growth_chunk_size_bytes; // use -1 to allow ORT to choose the default + initial_growth_chunk_size_bytes(initial_growth_chunk_size_bytes), + max_power_of_two_extend_bytes(max_power_of_two_extend_bytes) {} + + size_t max_mem; // use 0 to allow ORT to choose the default + int arena_extend_strategy; // use -1 to allow ORT to choose the default, 0 = kNextPowerOfTwo, 1 = kSameAsRequested + int initial_chunk_size_bytes; // use -1 to allow ORT to choose the default + int max_dead_bytes_per_chunk; // use -1 to allow ORT to choose the default + int initial_growth_chunk_size_bytes; // use -1 to allow ORT to choose the default + int64_t max_power_of_two_extend_bytes; // use -1 to allow ORT to choose the default }; namespace onnxruntime { @@ -43,6 +48,7 @@ constexpr const char* HIP = "Hip"; constexpr const char* HIP_PINNED = "HipPinned"; constexpr const char* OpenVINO_CPU = "OpenVINO_CPU"; constexpr const char* OpenVINO_GPU = "OpenVINO_GPU"; +constexpr const char* WEBGPU_BUFFER = "WebGPU_Buffer"; constexpr size_t kAllocAlignment = 256; @@ -168,6 +174,24 @@ class IAllocator { [allocator = std::move(allocator)](T* p) { allocator->Free(p); }}; } + template + static IAllocatorUniquePtr MakeUniquePtrFromOrtAllocator(OrtAllocator* ort_allocator, size_t count_or_bytes) { + if (!ort_allocator) return nullptr; + + size_t alloc_size = count_or_bytes; + // if T is not void, 'count_or_bytes' == number of items so allow for that + if constexpr (!std::is_void::value) { + // sizeof(void) isn't valid, but the compiler isn't smart enough to ignore that this line isn't + // reachable if T is void. use std::conditional to 'use' void* in the sizeof call + if (!CalcMemSizeForArray( + count_or_bytes, sizeof(typename std::conditional::value, void*, T>::type), &alloc_size)) { + return nullptr; + } + } + T* p = static_cast(ort_allocator->Alloc(ort_allocator, count_or_bytes)); + return IAllocatorUniquePtr{p, [ort_allocator](T* p) { ort_allocator->Free(ort_allocator, p); }}; + } + private: OrtMemoryInfo memory_info_; }; @@ -188,6 +212,7 @@ class CPUAllocator : public IAllocator { }; using AllocatorPtr = std::shared_ptr; +using AllocatorMap = std::map; void* AllocatorDefaultAlloc(size_t size); void AllocatorDefaultFree(void* p); diff --git a/include/onnxruntime/core/framework/data_types.h b/include/onnxruntime/core/framework/data_types.h index b63526832e0d1..f3942128077de 100644 --- a/include/onnxruntime/core/framework/data_types.h +++ b/include/onnxruntime/core/framework/data_types.h @@ -13,15 +13,10 @@ #include "core/common/common.h" #include "core/common/exceptions.h" #include "core/framework/endian.h" +#include "core/framework/float8.h" #include "core/framework/float16.h" +#include "core/graph/onnx_protobuf.h" #include "core/framework/to_tensor_proto_element_type.h" -#if !defined(ORT_MINIMAL_BUILD) -#include "onnx/defs/schema.h" -#else -#include "onnx/defs/data_type_utils.h" -#endif -#include "onnx/onnx_pb.h" -#include "onnx/onnx-operators_pb.h" struct OrtValue; @@ -207,19 +202,49 @@ class DataTypeImpl { static void RegisterDataType(MLDataType); static MLDataType GetDataType(const std::string&); - static const std::vector& AllTensorTypes(); - static const std::vector& AllFixedSizeTensorTypes(); - static const std::vector& AllSequenceTensorTypes(); - static const std::vector& AllFixedSizeSequenceTensorTypes(); - static const std::vector& AllNumericTensorTypes(); - static const std::vector& AllIEEEFloatTensorTypes(); - static const std::vector& AllFixedSizeTensorExceptHalfTypes(); - static const std::vector& AllIEEEFloatTensorExceptHalfTypes(); - static const std::vector& AllTensorAndSequenceTensorTypes(); - static const std::vector& AllOptionalAndTensorAndSequenceTensorTypes(); - static const std::vector& AllFixedSizeTensorAndSequenceTensorTypes(); - static const std::vector& AllOptionalTypes(); - static const std::vector& AllTensorAndSequenceTensorAndOptionalTypes(); + // IR4: includes all float types, includes float16, bfloat16 + // IR9: includes float 8 types as well + static const std::vector& AllTensorTypes(); // up to IR4 (no float 8), deprecated + static const std::vector& AllTensorTypesIRv4(); + static const std::vector& AllTensorTypesIRv9(); + + static const std::vector& AllFixedSizeTensorTypes(); // up to IR4 (no float 8), deprecated + static const std::vector& AllFixedSizeTensorTypesIRv4(); + static const std::vector& AllFixedSizeTensorTypesIRv9(); + + static const std::vector& AllSequenceTensorTypes(); // up to IR4 (no float 8), deprecated + static const std::vector& AllSequenceTensorTypesIRv4(); + static const std::vector& AllSequenceTensorTypesIRv9(); + + static const std::vector& AllFixedSizeSequenceTensorTypes(); // up to IR4 (no float 8), deprecated + static const std::vector& AllFixedSizeSequenceTensorTypesIRv4(); + static const std::vector& AllFixedSizeSequenceTensorTypesIRv9(); + + static const std::vector& AllNumericTensorTypes(); // up to IR4 (no float 8), deprecated + static const std::vector& AllNumericTensorTypesIRv4(); + static const std::vector& AllNumericTensorTypesIRv9(); + + static const std::vector& AllIEEEFloatTensorTypes(); // float16, float, double + + static const std::vector& AllTensorAndSequenceTensorTypes(); // up to IR4 (no float 8), deprecated + static const std::vector& AllTensorAndSequenceTensorTypesIRv4(); + static const std::vector& AllTensorAndSequenceTensorTypesIRv9(); + + static const std::vector& AllOptionalAndTensorAndSequenceTensorTypes(); // up to IR4 (no float 8), deprecated + static const std::vector& AllOptionalAndTensorAndSequenceTensorTypesIRv4(); + static const std::vector& AllOptionalAndTensorAndSequenceTensorTypesIRv9(); + + static const std::vector& AllFixedSizeTensorAndSequenceTensorTypes(); // up to IR4 (no float 8), deprecated + static const std::vector& AllFixedSizeTensorAndSequenceTensorTypesIRv4(); + static const std::vector& AllFixedSizeTensorAndSequenceTensorTypesIRv9(); + + static const std::vector& AllOptionalTypes(); // up to IR4 (no float 8), deprecated + static const std::vector& AllOptionalTypesIRv4(); + static const std::vector& AllOptionalTypesIRv9(); + + static const std::vector& AllTensorAndSequenceTensorAndOptionalTypes(); // up to IR4 (no float 8), deprecated + static const std::vector& AllTensorAndSequenceTensorAndOptionalTypesIRv4(); + static const std::vector& AllTensorAndSequenceTensorAndOptionalTypesIRv9(); }; std::ostream& operator<<(std::ostream& out, MLDataType data_type); @@ -255,7 +280,12 @@ struct IsAnyOf { template struct IsTensorContainedType : public IsAnyOf { + double, uint32_t, uint64_t, BFloat16 +#if !defined(DISABLE_FLOAT8_TYPES) + , + Float8E4M3FN, Float8E4M3FNUZ, Float8E5M2, Float8E5M2FNUZ +#endif + > { }; #if !defined(DISABLE_SPARSE_TENSORS) @@ -265,7 +295,12 @@ struct IsTensorContainedType : public IsAnyOf struct IsSparseTensorContainedType : public IsAnyOf { + double, uint32_t, uint64_t, BFloat16 +#if !defined(DISABLE_FLOAT8_TYPES) + , + Float8E4M3FN, Float8E4M3FNUZ, Float8E5M2, Float8E5M2FNUZ +#endif + > { }; #endif diff --git a/include/onnxruntime/core/framework/data_types_internal.h b/include/onnxruntime/core/framework/data_types_internal.h index 3f585d21a3d0c..fbeee8a2aedc5 100644 --- a/include/onnxruntime/core/framework/data_types_internal.h +++ b/include/onnxruntime/core/framework/data_types_internal.h @@ -17,13 +17,7 @@ #ifndef SHARED_PROVIDER #include "core/common/type_list.h" #include "core/framework/data_types.h" -#if !defined(ORT_MINIMAL_BUILD) -#include "onnx/defs/schema.h" -#else -#include "onnx/defs/data_type_utils.h" -#endif -#include "onnx/onnx_pb.h" -#include "onnx/onnx-operators_pb.h" +#include "core/graph/onnx_protobuf.h" #endif namespace onnxruntime { @@ -41,6 +35,8 @@ namespace utils { // Invoking DataTypeImpl::GetType() for switching on input types is discouraged and should be avoided. // Every primitive type carries with it an integer constant that can be used for quick switching on types. +#if !defined(DISABLE_FLOAT8_TYPES) + #define DispatchOnTensorType(tensor_type, function, ...) \ switch (tensor_type->AsPrimitiveDataType()->GetDataType()) { \ case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: \ @@ -85,6 +81,18 @@ namespace utils { case ONNX_NAMESPACE::TensorProto_DataType_BFLOAT16: \ function(__VA_ARGS__); \ break; \ + case ONNX_NAMESPACE::TensorProto_DataType_FLOAT8E4M3FN: \ + function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_FLOAT8E4M3FNUZ: \ + function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_FLOAT8E5M2: \ + function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_FLOAT8E5M2FNUZ: \ + function(__VA_ARGS__); \ + break; \ default: \ ORT_ENFORCE(false, "Unknown tensor type of ", tensor_type); \ } @@ -133,10 +141,122 @@ namespace utils { case ONNX_NAMESPACE::TensorProto_DataType_BFLOAT16: \ retval = function(__VA_ARGS__); \ break; \ + case ONNX_NAMESPACE::TensorProto_DataType_FLOAT8E4M3FN: \ + retval = function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_FLOAT8E4M3FNUZ: \ + retval = function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_FLOAT8E5M2: \ + retval = function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_FLOAT8E5M2FNUZ: \ + retval = function(__VA_ARGS__); \ + break; \ default: \ ORT_ENFORCE(false, "Unknown tensor type of ", tensor_type); \ } +#else + +#define DispatchOnTensorType(tensor_type, function, ...) \ + switch (tensor_type->AsPrimitiveDataType()->GetDataType()) { \ + case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: \ + function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_BOOL: \ + function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_DOUBLE: \ + function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_STRING: \ + function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_INT8: \ + function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_UINT8: \ + function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_INT16: \ + function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_UINT16: \ + function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_INT32: \ + function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_UINT32: \ + function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_INT64: \ + function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_UINT64: \ + function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_FLOAT16: \ + function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_BFLOAT16: \ + function(__VA_ARGS__); \ + break; \ + default: \ + ORT_ENFORCE(false, "Unknown tensor type of ", tensor_type); \ + } + +#define DispatchOnTensorTypeWithReturn(tensor_type, retval, function, ...) \ + switch (tensor_type->AsPrimitiveDataType()->GetDataType()) { \ + case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: \ + retval = function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_BOOL: \ + retval = function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_DOUBLE: \ + retval = function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_STRING: \ + retval = function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_INT8: \ + retval = function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_UINT8: \ + retval = function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_UINT16: \ + retval = function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_INT16: \ + retval = function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_INT32: \ + retval = function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_UINT32: \ + retval = function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_INT64: \ + retval = function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_UINT64: \ + retval = function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_FLOAT16: \ + retval = function(__VA_ARGS__); \ + break; \ + case ONNX_NAMESPACE::TensorProto_DataType_BFLOAT16: \ + retval = function(__VA_ARGS__); \ + break; \ + default: \ + ORT_ENFORCE(false, "Unknown tensor type of ", tensor_type); \ + } + +#endif + //////////////////////////////////////////////////////////////////////////////// /// Use the following primitives if you have a few types to switch on so you // can write a short sequence of if/else statements. diff --git a/include/onnxruntime/core/framework/execution_provider.h b/include/onnxruntime/core/framework/execution_provider.h index a65e5af72365d..ea4f52f99649d 100644 --- a/include/onnxruntime/core/framework/execution_provider.h +++ b/include/onnxruntime/core/framework/execution_provider.h @@ -26,7 +26,7 @@ class Node; #include "core/common/basic_types.h" #include "core/common/profiler_common.h" -#include "core/framework/allocatormgr.h" +#include "core/framework/allocator_utils.h" #include "core/framework/func_api.h" #include "core/framework/provider_options.h" #include "core/framework/framework_provider_common.h" @@ -60,26 +60,22 @@ enum class DataLayout { class IExecutionProvider { protected: IExecutionProvider(const std::string& type, bool use_metadef_id_creator = false) - : type_{type} { + : IExecutionProvider(type, OrtDevice(), use_metadef_id_creator) {} + + IExecutionProvider(const std::string& type, OrtDevice device, bool use_metadef_id_creator = false) + : default_device_(device), type_{type} { if (use_metadef_id_creator) { metadef_id_generator_ = std::make_unique(); } } - public: - virtual ~IExecutionProvider() = default; - - /** - Get all IAllocators for <*this> execution provider. + /* + default device for this ExecutionProvider */ - const std::vector& GetAllocators() const { - return allocator_list_; - } + const OrtDevice default_device_; - /** - * Get an allocator with specified device id and MemType. Return nullptr if it doesn't exist - */ - virtual AllocatorPtr GetAllocator(OrtMemType mem_type) const; + public: + virtual ~IExecutionProvider() = default; /** * Returns a data transfer object that implements methods to copy to and @@ -226,9 +222,6 @@ class IExecutionProvider { */ virtual common::Status OnSessionInitializationEnd() { return Status::OK(); } - void InsertAllocator(AllocatorPtr allocator); - void ReplaceAllocator(AllocatorPtr allocator); - struct FusedNodeAndGraph { const std::reference_wrapper fused_node; // GraphViewer that filters the full graph to the nodes that are covered by 'node' @@ -294,12 +287,6 @@ class IExecutionProvider { */ virtual int GenerateMetaDefId(const onnxruntime::GraphViewer& graph_viewer, HashValue& model_hash) const; - /** - Register allocators for EP, potentially re-using existing allocators for a device from allocator_manager. - If the EP implements this it should generally delay creating any allocators until this is called. - */ - virtual void RegisterAllocator(AllocatorManager& /*allocator_manager*/); - virtual std::unique_ptr GetProfiler() { return {}; } @@ -310,7 +297,7 @@ class IExecutionProvider { return DataLayout::NCHW; } - virtual void RegisterStreamHandlers(IStreamCommandHandleRegistry& /*stream_handle_registry*/) const {} + virtual void RegisterStreamHandlers(IStreamCommandHandleRegistry& /*stream_handle_registry*/, AllocatorMap&) const {} /** Does the EP support concurrent calls to InferenceSession::Run to execute the model. */ @@ -323,21 +310,27 @@ class IExecutionProvider { return nullptr; } + /** + * Return the appropriate OrtDevice object given OrtMemType. + */ + virtual OrtDevice GetOrtDeviceByMemType(OrtMemType mem_type) const { + if (mem_type == OrtMemTypeCPUInput || mem_type == OrtMemTypeCPUOutput) { + return OrtDevice(); // default return CPU device. + } + return default_device_; + }; + + /** + * Create Preferred allocators for the current Execution Provider + * This function is a stateless function which creates new instances of Allocator, without storing them in EP. + */ + virtual std::vector CreatePreferredAllocators() { return std::vector(); }; + private: const std::string type_; - // allocator lookup is done by combining the device id and OrtMemType. - // there's also an implicit connection to the underlying OrtDevice involved that is dependent on the EP. - // e.g. for a CPU based EP, 'default' memory is a CPU device, and for a GPU based EP 'default' memory is a - // GPU device. - using AllocatorMap = std::unordered_map; - AllocatorMap allocators_; - // It will be set when this object is registered to a session const logging::Logger* logger_ = nullptr; - // convenience list of the allocators so GetAllocatorList doesn't have to build a new vector each time - // contains the same instances as allocators_ - std::vector allocator_list_; // helper to generate ids that are unique to model and deterministic, even if the execution provider is shared across // multiple sessions. diff --git a/include/onnxruntime/core/framework/float16.h b/include/onnxruntime/core/framework/float16.h index 9401ea3965fc5..2d289d6febb8d 100644 --- a/include/onnxruntime/core/framework/float16.h +++ b/include/onnxruntime/core/framework/float16.h @@ -2,6 +2,8 @@ // Licensed under the MIT License. #pragma once +#include + #include "endian.h" #if defined(CUDA_VERSION) && CUDA_VERSION >= 11000 #include "cuda_bf16.h" @@ -13,6 +15,8 @@ #include "core/common/common.h" +#include "core/session/onnxruntime_float16.h" + namespace onnxruntime { #if defined(__CUDACC__) || defined(__HIPCC__) @@ -22,25 +26,69 @@ namespace onnxruntime { #endif // MLFloat16 -struct MLFloat16 { - uint16_t val{0}; +struct MLFloat16 : onnxruntime_float16::Float16Impl { + private: + explicit constexpr MLFloat16(uint16_t x) noexcept { val = x; } + + public: + using Base = onnxruntime_float16::Float16Impl; MLFloat16() = default; - explicit constexpr MLFloat16(uint16_t x) : val(x) {} - explicit MLFloat16(float f); - float ToFloat() const; + constexpr static MLFloat16 FromBits(uint16_t x) noexcept { return MLFloat16(x); } - operator float() const { return ToFloat(); } -}; + // Using inherited implementation instead of math floatToHalf allows us to use this + // in other shared providers without having to implement the bridge + explicit MLFloat16(float v) noexcept { val = Base::ToUint16Impl(v); } + + static const MLFloat16 NaN; + static const MLFloat16 NegativeNaN; + static const MLFloat16 Infinity; + static const MLFloat16 NegativeInfinity; + static const MLFloat16 Epsilon; + static const MLFloat16 MinValue; + static const MLFloat16 MaxValue; + static const MLFloat16 Zero; + static const MLFloat16 One; + static const MLFloat16 MinusOne; + + // Using inherited implementation instead of math halfToFloat allows us to use this + // in other shared providers without having to implement the bridge + float ToFloat() const noexcept { return Base::ToFloatImpl(); } + + using Base::IsNegative; + + using Base::IsNaN; + + using Base::IsFinite; + + using Base::IsPositiveInfinity; + + using Base::IsNegativeInfinity; + + using Base::IsInfinity; + + using Base::IsNaNOrZero; + + using Base::IsNormal; + + using Base::IsSubnormal; + + using Base::Abs; + + using Base::Negate; -inline bool operator==(const MLFloat16& left, const MLFloat16& right) { return left.val == right.val; } -inline bool operator!=(const MLFloat16& left, const MLFloat16& right) { return left.val != right.val; } -inline bool operator<(const MLFloat16& left, const MLFloat16& right) { return left.val < right.val; } + operator float() const noexcept { return ToFloat(); } + + using Base::operator==; + using Base::operator!=; + using Base::operator<; +}; // BFloat16 -struct BFloat16 { - uint16_t val{0}; +struct BFloat16 : onnxruntime_float16::BFloat16Impl { + using Base = onnxruntime_float16::BFloat16Impl; + #if defined(__HIP__) ORT_HOST_DEVICE BFloat16() = default; #else @@ -48,10 +96,14 @@ struct BFloat16 { #endif struct FromBitsT {}; - static constexpr ORT_HOST_DEVICE FromBitsT FromBits() { return FromBitsT(); } - constexpr ORT_HOST_DEVICE BFloat16(unsigned short bits, FromBitsT) : val(bits) {} + static constexpr ORT_HOST_DEVICE FromBitsT FromBits() noexcept { return FromBitsT(); } + constexpr ORT_HOST_DEVICE BFloat16(unsigned short bits, FromBitsT) noexcept { val = bits; } + + static constexpr ORT_HOST_DEVICE BFloat16 FromBits(uint16_t bits) noexcept { + return BFloat16(bits, FromBits()); + } - inline ORT_HOST_DEVICE BFloat16(float v) { + inline ORT_HOST_DEVICE BFloat16(float v) noexcept { #if defined(CUDA_VERSION) && CUDA_VERSION >= 11000 && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 800 val = __bfloat16_as_ushort(__float2bfloat16(v)); #elif defined(__HIP__) @@ -69,15 +121,34 @@ struct BFloat16 { val = static_cast((U32 + rounding_bias) >> 16); } #else - if constexpr (endian::native == endian::little) { - std::memcpy(&val, reinterpret_cast(&v) + sizeof(uint16_t), sizeof(uint16_t)); + + // Use C isnan to work both in host and device + if (::isnan(v)) { + val = kPositiveQNaNBits; } else { - std::memcpy(&val, &v, sizeof(uint16_t)); + auto get_msb_half = [](float fl) { + uint16_t result; + if constexpr (onnxruntime_float16::detail::endian::native == onnxruntime_float16::detail::endian::little) { + std::memcpy(&result, reinterpret_cast(&fl) + sizeof(uint16_t), sizeof(uint16_t)); + } else { + std::memcpy(&result, &fl, sizeof(uint16_t)); + } + return result; + }; + + uint16_t upper_bits = get_msb_half(v); + union { + uint32_t U32; + float F32; + }; + F32 = v; + U32 += (upper_bits & 1) + kRoundToNearest; + val = get_msb_half(F32); } #endif } - inline ORT_HOST_DEVICE float ToFloat() const { + inline ORT_HOST_DEVICE float ToFloat() const noexcept { #if defined(CUDA_VERSION) && CUDA_VERSION >= 11000 return __bfloat162float(*reinterpret_cast(&val)); #elif defined(__HIP__) @@ -89,55 +160,129 @@ struct BFloat16 { result = *tempRes; return result; #else - float result; + + if (IsNaNHostDevice()) { + return std::numeric_limits::quiet_NaN(); + } + + float result = 0; char* const first = reinterpret_cast(&result); - char* const second = first + sizeof(uint16_t); if constexpr (endian::native == endian::little) { - std::memset(first, 0, sizeof(uint16_t)); + char* const second = first + sizeof(uint16_t); std::memcpy(second, &val, sizeof(uint16_t)); } else { std::memcpy(first, &val, sizeof(uint16_t)); - std::memset(second, 0, sizeof(uint16_t)); } return result; #endif } - inline ORT_HOST_DEVICE operator float() const { return ToFloat(); } + static const BFloat16 NaN; + static const BFloat16 NegativeNaN; + static const BFloat16 Infinity; + static const BFloat16 NegativeInfinity; + static const BFloat16 Epsilon; + static const BFloat16 MinValue; + static const BFloat16 MaxValue; + static const BFloat16 Zero; + static const BFloat16 One; + static const BFloat16 MinusOne; + + using Base::IsNegative; + + using Base::IsNaN; + + using Base::IsFinite; + + using Base::IsPositiveInfinity; + + using Base::IsNegativeInfinity; + + using Base::IsInfinity; + + using Base::IsNaNOrZero; + + using Base::IsNormal; + + using Base::IsSubnormal; + + using Base::Abs; + + using Base::Negate; + + ORT_HOST_DEVICE operator float() const noexcept { return ToFloat(); } #if defined(CUDA_VERSION) && CUDA_VERSION >= 11000 ORT_HOST_DEVICE BFloat16(const __nv_bfloat16& value) { val = *reinterpret_cast(&value); } explicit ORT_HOST_DEVICE operator __nv_bfloat16() const { return *reinterpret_cast(&val); } #endif -}; -inline ORT_HOST_DEVICE bool operator==(const BFloat16& left, const BFloat16& right) { return left.val == right.val; } -inline ORT_HOST_DEVICE bool operator!=(const BFloat16& left, const BFloat16& right) { return left.val != right.val; } -inline ORT_HOST_DEVICE bool operator<(const BFloat16& left, const BFloat16& right) { return left.val < right.val; } + ORT_HOST_DEVICE bool operator==(const BFloat16& rhs) const noexcept { + if (IsNaNHostDevice() || rhs.IsNaNHostDevice()) { + // IEEE defines that NaN is not equal to anything, including itself. + return false; + } + return val == rhs.val; + } + + ORT_HOST_DEVICE bool operator!=(const BFloat16& rhs) const noexcept { + return !(*this == rhs); + } + + ORT_HOST_DEVICE bool operator<(const BFloat16& rhs) const noexcept { + if (IsNaNHostDevice() || rhs.IsNaNHostDevice()) { + // IEEE defines that NaN is unordered with respect to everything, including itself. + return false; + } + + const bool left_is_negative = IsNegativeHostDevice(); + if (left_is_negative != rhs.IsNegativeHostDevice()) { + // When the signs of left and right differ, we know that left is less than right if it is + // the negative value. The exception to this is if both values are zero, in which case IEEE + // says they should be equal, even if the signs differ. + return left_is_negative && !AreZeroHostDevice(*this, rhs); + } + return (val != rhs.val) && ((val < rhs.val) ^ left_is_negative); + } + + ORT_HOST_DEVICE bool IsNegativeHostDevice() const noexcept { + return (val & kSignMask) != 0; + } + + ORT_HOST_DEVICE bool IsNaNHostDevice() const noexcept { + return static_cast(val & ~kSignMask) > kPositiveInfinityBits; + } + + ORT_HOST_DEVICE static bool AreZeroHostDevice(const BFloat16Impl& lhs, const BFloat16Impl& rhs) noexcept { + // IEEE defines that positive and negative zero are equal, this gives us a quick equality check + // for two values by or'ing the private bits together and stripping the sign. They are both zero, + // and therefore equivalent, if the resulting value is still zero. + return static_cast((lhs.val | rhs.val) & ~kSignMask) == 0; + } +}; // User defined suffixes to make it easier to declare // initializers with MLFloat16 and BFloat16 from unsigned short // E.g 10_f16 or 10_b16 #if !defined(__CUDACC__) && !defined(__HIPCC__) -inline MLFloat16 operator"" _f16(unsigned long long int v) { - return MLFloat16(narrow(v)); +inline MLFloat16 operator"" _f16(unsigned long long int v) noexcept { + return MLFloat16::FromBits(narrow(v)); } -inline MLFloat16 operator"" _fp16(long double v) { +inline MLFloat16 operator"" _fp16(long double v) noexcept { return MLFloat16(static_cast(v)); } -inline BFloat16 operator"" _b16(unsigned long long int v) { - return BFloat16(narrow(v), BFloat16::FromBits()); +inline BFloat16 operator"" _b16(unsigned long long int v) noexcept { + return BFloat16::FromBits((narrow(v))); } -inline BFloat16 operator"" _bfp16(long double v) { +inline BFloat16 operator"" _bfp16(long double v) noexcept { return BFloat16(static_cast(v)); } - #endif -inline void BFloat16ToFloat(const BFloat16* blf, float* flt, size_t size) { +inline void BFloat16ToFloat(const BFloat16* blf, float* flt, size_t size) noexcept { auto src = blf; auto d = flt; for (; size != 0; ++src, ++d, --size) { @@ -149,7 +294,7 @@ inline void FloatToBFloat16(const float* flt, BFloat16* blf, size_t size) { auto src = flt; auto d = blf; for (; size != 0; ++src, ++d, --size) { - new (d) BFloat16(*src); + *d = BFloat16(*src); } } diff --git a/include/onnxruntime/core/framework/float8.h b/include/onnxruntime/core/framework/float8.h new file mode 100644 index 0000000000000..0fd04f28d44b7 --- /dev/null +++ b/include/onnxruntime/core/framework/float8.h @@ -0,0 +1,647 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#if !defined(DISABLE_FLOAT8_TYPES) + +#include "endian.h" +#if defined(CUDA_VERSION) && CUDA_VERSION >= 11080 +#include "cuda_fp8.h" +#endif + +#if !defined(__CUDACC__) && !defined(__HIPCC__) +#include "core/common/narrow.h" +#endif + +#include "core/common/common.h" + +namespace onnxruntime { + +#if defined(__CUDACC__) || defined(__HIPCC__) +#define ORT_HOST_DEVICE __host__ __device__ +#else +#define ORT_HOST_DEVICE +#endif + +// Float8E4M3FN +struct Float8E4M3FN { + uint8_t val{0}; +#if defined(__HIP__) + ORT_HOST_DEVICE Float8E4M3FN() = default; +#else + Float8E4M3FN() = default; +#endif + struct FromBitsT {}; + static constexpr ORT_HOST_DEVICE FromBitsT FromBits() { return FromBitsT(); } + constexpr ORT_HOST_DEVICE Float8E4M3FN(unsigned char bits, FromBitsT) : val(bits) {} + + inline explicit ORT_HOST_DEVICE Float8E4M3FN(float v, bool saturate = true) { +#if defined(CUDA_VERSION) && CUDA_VERSION >= 11080 + val = __nv_cvt_float_to_fp8(v, saturate ? __NV_SATFINITE : __NV_NOSAT, __NV_E4M3); +#else + uint32_t b; + std::memcpy(&b, &v, sizeof(b)); + + val = static_cast((b & 0x80000000) >> 24); // sign + if ((b & 0x7fffffff) == 0x7f800000) { // infinity + if (saturate) { + val |= 126; + } else { + val |= 0x7f; + } + } else if ((b & 0x7F800000) == 0x7F800000) { // NaN + val |= 0x7f; + } else { + uint8_t e = static_cast((b & 0x7F800000) >> 23); // exponent + uint32_t m = static_cast(b & 0x007FFFFF); // mantissa + if (e != 0) { + if (e < 117) { + } else if (e < 121) { + // denormalized number + auto d = 120 - e; + if (d < 3) { + val |= 1 << (2 - d); + val |= m >> (21 + d); + } else if (m > 0) { + val |= 1; + } + auto mask = 1 << (20 + d); + if ((m & mask) && ((val & 1) || ((m & (mask - 1)) > 0) || ((m & mask) && (m & (mask << 1)) && ((m & (mask - 1)) == 0)))) { + // rounding + val += 1; + } + } else if (e < 136) { + // normalized number + auto ex = e - 120; + if (ex == 0) { + val |= 0x4; + val |= m >> 21; + } else { + val |= ex << 3; + val |= m >> 20; + if ((val & 0x7F) == 0x7F) { + val &= 0xFE; + } + } + if ((m & 0x80000) && ((m & 0x100000) || (m & 0x7FFFF))) { + if ((val & 0x7F) < 0x7E) { + // rounding + val += 1; + } else if (!saturate) { + val |= 0x7F; + } + } + } else if (saturate) { + val |= 126; // 0b01111110 + } else { + val |= 0x7F; + } + } + } +#endif + } + + inline ORT_HOST_DEVICE float ToFloat() const { +#if defined(CUDA_VERSION) && CUDA_VERSION >= 11080 + return __half2float(__nv_cvt_fp8_to_halfraw(val, __NV_E4M3)); +#else + uint32_t res; + if (val == 255) { + res = 0xffc00000; + } else if (val == 127) { + res = 0x7fc00000; + } else { + uint32_t expo = (val & 0x78) >> 3; + uint32_t mant = val & 0x07; + uint32_t sign = val & 0x80; + res = sign << 24; + if (expo == 0) { + if (mant > 0) { + expo = 0x7F - 7; + if ((mant & 0x4) == 0) { + mant &= 0x3; + mant <<= 1; + expo -= 1; + } + if ((mant & 0x4) == 0) { + mant &= 0x3; + mant <<= 1; + expo -= 1; + } + res |= (mant & 0x3) << 21; + res |= expo << 23; + } + } else { + res |= mant << 20; + expo -= 0x7; + expo += 0x7F; + res |= expo << 23; + } + } + float float_res; + std::memcpy(&float_res, &res, sizeof(float)); + return float_res; +#endif + } + + inline ORT_HOST_DEVICE operator float() const { return ToFloat(); } + +#if defined(CUDA_VERSION) && CUDA_VERSION >= 11080 + explicit ORT_HOST_DEVICE Float8E4M3FN(const __nv_fp8_e4m3& value) { val = *reinterpret_cast(&value); } + explicit ORT_HOST_DEVICE operator __nv_fp8_e4m3() const { return *reinterpret_cast(&val); } +#endif +}; + +inline ORT_HOST_DEVICE bool operator==(const Float8E4M3FN& left, const Float8E4M3FN& right) { return left.val == right.val; } +inline ORT_HOST_DEVICE bool operator!=(const Float8E4M3FN& left, const Float8E4M3FN& right) { return left.val != right.val; } +inline ORT_HOST_DEVICE bool operator<(const Float8E4M3FN& left, const Float8E4M3FN& right) { return left.val < right.val; } + +// User defined suffixes to make it easier to declare +// initializers with MLFloat8E4M3FN and Float8E4M3FN from unsigned char +#if !defined(__CUDACC__) && !defined(__HIPCC__) + +inline Float8E4M3FN operator"" _f8e4m3fn(unsigned long long int v) { + return Float8E4M3FN(narrow(v), Float8E4M3FN::FromBits()); +} + +inline Float8E4M3FN operator"" _f8e4m3fnp8(long double v) { + return Float8E4M3FN(static_cast(v), true); +} + +#endif + +inline void Float8E4M3FNToFloat(const Float8E4M3FN* blf, float* flt, size_t size) { + auto src = blf; + auto d = flt; + for (; size != 0; ++src, ++d, --size) { + *d = src->ToFloat(); + } +} + +inline void FloatToFloat8E4M3FN(const float* flt, Float8E4M3FN* blf, size_t size, bool saturate) { + auto src = flt; + auto d = blf; + for (; size != 0; ++src, ++d, --size) { + new (d) Float8E4M3FN(*src, saturate); + } +} + +// Float8E4M3FNUZ +struct Float8E4M3FNUZ { + uint8_t val{0}; +#if defined(__HIP__) + ORT_HOST_DEVICE Float8E4M3FNUZ() = default; +#else + Float8E4M3FNUZ() = default; +#endif + + struct FromBitsT {}; + static constexpr ORT_HOST_DEVICE FromBitsT FromBits() { return FromBitsT(); } + constexpr ORT_HOST_DEVICE Float8E4M3FNUZ(unsigned char bits, FromBitsT) : val(bits) {} + + inline explicit ORT_HOST_DEVICE Float8E4M3FNUZ(float v, bool saturate = true) { + // This type does not exist on CUDA. + uint32_t b; + std::memcpy(&b, &v, sizeof(b)); + + val = static_cast((b & 0x80000000) >> 24); // sign + if ((b & 0x7fffffff) == 0x7f800000) { // infinity + if (saturate) { + val |= 0x7F; + } else { + // infinity + val = 0x80; + } + } else if ((b & 0x7F800000) == 0x7F800000) { // NaN + val = 0x80; + } else { + uint8_t e = static_cast((b & 0x7F800000) >> 23); // exponent + uint32_t m = static_cast(b & 0x007FFFFF); // mantissa + if (e != 0) { + if (e < 116) { + } else if (e < 120) { + // denormalized number + auto d = 119 - e; + if (d < 3) { + val |= 1 << (2 - d); + val |= m >> (21 + d); + } else if (m > 0) { + val |= 1; + } + auto mask = 1 << (20 + d); + if ((m & mask) && ((val & 1) || ((m & (mask - 1)) > 0) || ((m & mask) && (m & (mask << 1)) && ((m & (mask - 1)) == 0)))) { + // rounding + val += 1; + } + } else if (e < 135) { + // normalized number + auto ex = e - 119; + if (ex == 0) { + val |= 0x4; + val |= m >> 21; + } else { + val |= ex << 3; + val |= m >> 20; + } + if ((m & 0x80000) && ((m & 0x100000) || (m & 0x7FFFF))) { + if ((val & 0x7F) < 0x7F) { + // rounding + val += 1; + } else if (!saturate) { + val = 0x80; + } + } + } else if (saturate) { + val |= 0x7F; + } else { + val = 0x80; + } + } else if (m == 0) { + // -0 + val = 0; + } + } + } + + inline ORT_HOST_DEVICE float ToFloat() const { + // This type does not exist on CUDA. + uint32_t res; + if (val == 0x80) { + res = 0xffc00000; + } else { + uint32_t expo = (val & 0x78) >> 3; + uint32_t mant = val & 0x07; + uint32_t sign = val & 0x80; + res = sign << 24; + if (expo == 0) { + if (mant > 0) { + expo = 0x7F - 8; + if ((mant & 0x4) == 0) { + mant &= 0x3; + mant <<= 1; + expo -= 1; + } + if ((mant & 0x4) == 0) { + mant &= 0x3; + mant <<= 1; + expo -= 1; + } + res |= (mant & 0x3) << 21; + res |= expo << 23; + } + } else { + res |= mant << 20; + expo -= 8; + expo += 0x7F; + res |= expo << 23; + } + } + float float_res; + std::memcpy(&float_res, &res, sizeof(float)); + return float_res; + } + + inline ORT_HOST_DEVICE operator float() const { return ToFloat(); } +}; + +inline ORT_HOST_DEVICE bool operator==(const Float8E4M3FNUZ& left, const Float8E4M3FNUZ& right) { return left.val == right.val; } +inline ORT_HOST_DEVICE bool operator!=(const Float8E4M3FNUZ& left, const Float8E4M3FNUZ& right) { return left.val != right.val; } +inline ORT_HOST_DEVICE bool operator<(const Float8E4M3FNUZ& left, const Float8E4M3FNUZ& right) { return left.val < right.val; } + +// User defined suffixes to make it easier to declare +// initializers with MLFloat8E4M3FN and Float8E4M3FN from unsigned char +#if !defined(__CUDACC__) && !defined(__HIPCC__) + +inline Float8E4M3FNUZ operator"" _f8e4m3p8fnuz(unsigned long long int v) { + return Float8E4M3FNUZ(narrow(v), Float8E4M3FNUZ::FromBits()); +} + +inline Float8E4M3FNUZ operator"" _f8e4m3fnuzp8(long double v) { + return Float8E4M3FNUZ(static_cast(v), true); +} + +#endif + +inline void Float8E4M3FNUZToFloat(const Float8E4M3FNUZ* blf, float* flt, size_t size) { + auto src = blf; + auto d = flt; + for (; size != 0; ++src, ++d, --size) { + *d = src->ToFloat(); + } +} + +inline void FloatToFloat8E4M3FNUZ(const float* flt, Float8E4M3FNUZ* blf, size_t size, bool saturate) { + auto src = flt; + auto d = blf; + for (; size != 0; ++src, ++d, --size) { + new (d) Float8E4M3FNUZ(*src, saturate); + } +} + +// Float8E5M2 +struct Float8E5M2 { + uint8_t val{0}; +#if defined(__HIP__) + ORT_HOST_DEVICE Float8E5M2() = default; +#else + Float8E5M2() = default; +#endif + + struct FromBitsT {}; + static constexpr ORT_HOST_DEVICE FromBitsT FromBits() { return FromBitsT(); } + constexpr ORT_HOST_DEVICE Float8E5M2(unsigned char bits, FromBitsT) : val(bits) {} + + inline explicit ORT_HOST_DEVICE Float8E5M2(float v, bool saturate = true) { +#if defined(CUDA_VERSION) && CUDA_VERSION >= 11080 + val = __nv_cvt_float_to_fp8(v, saturate ? __NV_SATFINITE : __NV_NOSAT, __NV_E5M2); +#else + uint32_t b; + std::memcpy(&b, &v, sizeof(b)); + + val = (b & 0x80000000) >> 24; // sign + if ((b & 0x7FFFFFFF) == 0x7F800000) { // inf + if (saturate) { + val |= 0x7B; + } else { + val |= 0x7C; + } + } else if ((b & 0x7F800000) == 0x7F800000) { // NaN + val |= 0x7f; + } else { + uint32_t e = (b & 0x7F800000) >> 23; // exponent + uint32_t m = b & 0x007FFFFF; // mantissa + + if (e != 0) { + if (e < 110) { + } else if (e < 113) { + // denormalized number + auto d = 112 - e; + if (d < 2) { + val |= 1 << (1 - d); + val |= m >> (22 + d); + } else if (m > 0) { + val |= 1; + } + auto mask = 1 << (21 + d); + if ((m & mask) && ((val & 1) || ((m & (mask - 1)) > 0) || ((m & mask) && (m & (mask << 1)) && ((m & (mask - 1)) == 0)))) { + // rounding + val += 1; + } + } else if (e < 143) { // 127 + 15 + 1 + auto ex = e - 112; // 127 - 15 + val |= ex << 2; + val |= m >> 21; + if ((m & 0x100000) && ((m & 0xFFFFF) || (m & 0x200000))) { + if ((val & 0x7F) < 0x7B) { + // rounding + val += 1; + } else if (saturate) { + val |= 0x7B; + } else { + val |= 0x7C; + } + } + } else if (saturate) { + val |= 0x7B; + } else { + val |= 0x7C; + } + } + } +#endif + } + + inline ORT_HOST_DEVICE float ToFloat() const { +#if defined(CUDA_VERSION) && CUDA_VERSION >= 11080 + return __half2float(__nv_cvt_fp8_to_halfraw(val, __NV_E5M2)); +#else + uint32_t res; + if (val >= 253) { + res = 0xffc00000; + } else if (val >= 125 && val <= 127) { + res = 0x7fc00000; + } else if (val == 252) { + res = 0xff800000; + } else if (val == 124) { + res = 0x7f800000; + } else { + uint32_t expo = (val & 0x7C) >> 2; + uint32_t mant = val & 0x03; + uint32_t sign = val & 0x80; + res = sign << 24; + if (expo == 0) { + if (mant > 0) { + expo = 0x7F - 15; + if ((mant & 0x2) == 0) { + mant &= 0x1; + mant <<= 1; + expo -= 1; + } + res |= (mant & 0x1) << 22; + res |= expo << 23; + } + } else { + res |= mant << 21; + expo -= 15; + expo += 0x7F; + res |= expo << 23; + } + } + + float float_res; + std::memcpy(&float_res, &res, sizeof(float)); + return float_res; +#endif + } + + inline ORT_HOST_DEVICE operator float() const { return ToFloat(); } + +#if defined(CUDA_VERSION) && CUDA_VERSION >= 11080 + ORT_HOST_DEVICE Float8E5M2(const __nv_fp8_e5m2& value) { val = *reinterpret_cast(&value); } + explicit ORT_HOST_DEVICE operator __nv_fp8_e5m2() const { return *reinterpret_cast(&val); } +#endif +}; + +inline ORT_HOST_DEVICE bool operator==(const Float8E5M2& left, const Float8E5M2& right) { return left.val == right.val; } +inline ORT_HOST_DEVICE bool operator!=(const Float8E5M2& left, const Float8E5M2& right) { return left.val != right.val; } +inline ORT_HOST_DEVICE bool operator<(const Float8E5M2& left, const Float8E5M2& right) { return left.val < right.val; } + +// User defined suffixes to make it easier to declare +// initializers with MLFloat8E5M2 and Float8E5M2 from unsigned char +#if !defined(__CUDACC__) && !defined(__HIPCC__) + +inline Float8E5M2 operator"" _f8e5m2fn(unsigned long long int v) { + return Float8E5M2(narrow(v), Float8E5M2::FromBits()); +} + +inline Float8E5M2 operator"" _f8e5m2fnp8(long double v) { + return Float8E5M2(static_cast(v), true); +} + +#endif + +inline void Float8E5M2ToFloat(const Float8E5M2* blf, float* flt, size_t size) { + auto src = blf; + auto d = flt; + for (; size != 0; ++src, ++d, --size) { + *d = src->ToFloat(); + } +} + +inline void FloatToFloat8E5M2(const float* flt, Float8E5M2* blf, size_t size, bool saturate) { + auto src = flt; + auto d = blf; + for (; size != 0; ++src, ++d, --size) { + new (d) Float8E5M2(*src, saturate); + } +} + +// Float8E5M2FNUZ +struct Float8E5M2FNUZ { + uint8_t val{0}; +#if defined(__HIP__) + ORT_HOST_DEVICE Float8E5M2FNUZ() = default; +#else + Float8E5M2FNUZ() = default; +#endif + + struct FromBitsT {}; + static constexpr ORT_HOST_DEVICE FromBitsT FromBits() { return FromBitsT(); } + constexpr ORT_HOST_DEVICE Float8E5M2FNUZ(unsigned char bits, FromBitsT) : val(bits) {} + + inline explicit ORT_HOST_DEVICE Float8E5M2FNUZ(float v, bool saturate = true) { + // This type does not exist on CUDA. + uint32_t b; + std::memcpy(&b, &v, sizeof(b)); + + val = (b & 0x80000000) >> 24; // sign + if ((b & 0x7FFFFFFF) == 0x7F800000) { // inf + if (saturate) { + val |= 0x7F; + } else { + val = 0x80; + } + } else if ((b & 0x7F800000) == 0x7F800000) { // NaN + val = 0x80; + } else { + uint32_t e = (b & 0x7F800000) >> 23; // exponent + uint32_t m = b & 0x007FFFFF; // mantissa + + if (e != 0) { + if (e < 109) { + } else if (e < 112) { + // denormalized number + auto d = 111 - e; + if (d < 2) { + val |= 1 << (1 - d); + val |= m >> (22 + d); + } else if (m > 0) { + val |= 1; + } + auto mask = 1 << (21 + d); + if ((m & mask) && ((val & 1) || ((m & (mask - 1)) > 0) || ((m & mask) && (m & (mask << 1)) && ((m & (mask - 1)) == 0)))) { + // rounding + val += 1; + } + } else if (e < 143) { + // normalized number + auto ex = e - 111; + val |= ex << 2; + val |= m >> 21; + if ((m & 0x100000) && ((m & 0xFFFFF) || (m & 0x200000))) { + if ((val & 0x7F) < 0x7F) { + // rounding + val += 1; + } else if (!saturate) { + val = 0x80; + } + } + } else if ((e == 255) && (m == 0)) { + val = 0x80; + } else if (saturate) { + val |= 0x7F; + } else { + val = 0x80; + } + } else if (m == 0) { + // -0 + val = 0; + } + } + } + + inline ORT_HOST_DEVICE float ToFloat() const { + // This type does not exist on CUDA. + uint32_t res; + if (val == 0x80) { + res = 0xffc00000; + } else { + uint32_t expo = (val & 0x7C) >> 2; + uint32_t mant = val & 0x03; + uint32_t sign = val & 0x80; + res = sign << 24; + if (expo == 0) { + if (mant > 0) { + expo = 0x7F - 16; + if ((mant & 0x2) == 0) { + mant &= 0x1; + mant <<= 1; + expo -= 1; + } + res |= (mant & 0x1) << 22; + res |= expo << 23; + } + } else { + res |= mant << 21; + expo -= 16; + expo += 0x7F; + res |= expo << 23; + } + } + + float float_res; + std::memcpy(&float_res, &res, sizeof(float)); + return float_res; + } + + inline ORT_HOST_DEVICE operator float() const { return ToFloat(); } +}; + +inline ORT_HOST_DEVICE bool operator==(const Float8E5M2FNUZ& left, const Float8E5M2FNUZ& right) { return left.val == right.val; } +inline ORT_HOST_DEVICE bool operator!=(const Float8E5M2FNUZ& left, const Float8E5M2FNUZ& right) { return left.val != right.val; } +inline ORT_HOST_DEVICE bool operator<(const Float8E5M2FNUZ& left, const Float8E5M2FNUZ& right) { return left.val < right.val; } + +// User defined suffixes to make it easier to declare +// initializers with MLFloat8E5M2 and Float8E5M2 from unsigned char +#if !defined(__CUDACC__) && !defined(__HIPCC__) + +inline Float8E5M2FNUZ operator"" _f8e5m2fnuz(unsigned long long int v) { + return Float8E5M2FNUZ(narrow(v), Float8E5M2FNUZ::FromBits()); +} + +inline Float8E5M2FNUZ operator"" _f8e5m2fnuzp8(long double v) { + return Float8E5M2FNUZ(static_cast(v), true); +} + +#endif + +inline void Float8E5M2FNUZToFloat(const Float8E5M2FNUZ* blf, float* flt, size_t size) { + auto src = blf; + auto d = flt; + for (; size != 0; ++src, ++d, --size) { + *d = src->ToFloat(); + } +} + +inline void FloatToFloat8E5M2FNUZ(const float* flt, Float8E5M2FNUZ* blf, size_t size, bool saturate) { + auto src = flt; + auto d = blf; + for (; size != 0; ++src, ++d, --size) { + new (d) Float8E5M2FNUZ(*src, saturate); + } +} + +} // namespace onnxruntime + +#endif // DISABLE_FLOAT8_TYPES diff --git a/include/onnxruntime/core/framework/kernel_def_builder.h b/include/onnxruntime/core/framework/kernel_def_builder.h index 2892439f17f6d..de5a3a52f5be7 100644 --- a/include/onnxruntime/core/framework/kernel_def_builder.h +++ b/include/onnxruntime/core/framework/kernel_def_builder.h @@ -43,11 +43,9 @@ class KernelDef { *end = op_since_version_end_; } -#ifdef onnxruntime_PYBIND_EXPORT_OPSCHEMA const std::pair SinceVersion() const { return std::pair(op_since_version_start_, op_since_version_end_); } -#endif onnxruntime::ProviderType Provider() const { return provider_type_; diff --git a/include/onnxruntime/core/framework/kernel_registry.h b/include/onnxruntime/core/framework/kernel_registry.h index dc5499d0a71d9..7b3d04ee66d9e 100644 --- a/include/onnxruntime/core/framework/kernel_registry.h +++ b/include/onnxruntime/core/framework/kernel_registry.h @@ -44,6 +44,25 @@ class KernelRegistry { const TypeConstraintMap& type_constraints, const KernelCreateInfo** out) const; + /** + * @brief Find out whether a kernel is registered, without a node. + * This should be useful in graph optimizers, to check whether + * the node it is about to generate, is supported or not. + * @param exec_provider + * @param op_type + * @param domain + * @param version + * @param type_constraints + * @param out + * @return + */ + Status TryFindKernel(ProviderType exec_provider, + std::string_view op_type, + std::string_view domain, + int version, + const KernelRegistry::TypeConstraintMap& type_constraints, + const KernelCreateInfo** out) const; + static bool HasImplementationOf(const KernelRegistry& r, const Node& node, ProviderType exec_provider, const IKernelTypeStrResolver& kernel_type_str_resolver) { @@ -54,12 +73,10 @@ class KernelRegistry { bool IsEmpty() const { return kernel_creator_fn_map_.empty(); } -#ifdef onnxruntime_PYBIND_EXPORT_OPSCHEMA // This is used by the opkernel doc generator to enlist all registered operators for a given provider's opkernel const KernelCreateMap& GetKernelCreateMap() const { return kernel_creator_fn_map_; } -#endif private: // TryFindKernel implementation. Either kernel_type_str_resolver or type_constraints is provided. diff --git a/include/onnxruntime/core/framework/op_kernel.h b/include/onnxruntime/core/framework/op_kernel.h index ed712cf00e096..94c6d81ee9326 100644 --- a/include/onnxruntime/core/framework/op_kernel.h +++ b/include/onnxruntime/core/framework/op_kernel.h @@ -11,25 +11,20 @@ #ifndef SHARED_PROVIDER #include + #include "core/common/exceptions.h" #include "core/common/logging/logging.h" #include "core/common/status.h" #include "core/framework/execution_provider.h" #include "core/framework/kernel_def_builder.h" -#include "core/framework/ort_value.h" #include "core/framework/op_kernel_info.h" #include "core/framework/op_node_proto_helper.h" -#include "core/framework/tensor.h" +#include "core/framework/ort_value.h" #include "core/framework/sparse_tensor.h" +#include "core/framework/tensor.h" #include "core/graph/constants.h" #include "core/graph/graph_viewer.h" -#if !defined(ORT_MINIMAL_BUILD) -#include "onnx/defs/schema.h" -#else -#include "onnx/defs/data_type_utils.h" -#endif -#include "onnx/onnx_pb.h" -#include "onnx/onnx-operators_pb.h" +#include "core/graph/onnx_protobuf.h" #include "core/common/gsl.h" namespace onnxruntime { class OpKernelContext; @@ -121,7 +116,9 @@ class OpKernel { // @param prepacked_buffers: The pre-packed buffers to be used by this kernel for the provided input index // (Sometimes a single constant initializer may have multiple pre-packed buffers associated // with it and it upto the kernel developer to store it in any order of their choice in PrePack() - // and must use the same order for retrieval in UseSharedPrePackedBuffers(). + // and must use the same order for retrieval in UseSharedPrePackedBuffers(). Though each element + // of this vector is a BufferUniquePtr, the deleter of the BufferUniquePtr is NULL. So actually they + // are raw pointers. // @param input_idx: The input index of the tensor in this kernel // @param used_shared_buffers: Boolean flag set by the kernel implementation indicating // that the provided weight has been used by the kernel. @@ -132,7 +129,7 @@ class OpKernel { return Status::OK(); } - const OrtMemoryInfo& Allocator(OrtMemType mem_type) const; + const OrtDevice GetDevice(OrtMemType mem_type) const; const OpKernelInfo& Info() const { return *op_kernel_info_; } @@ -185,6 +182,13 @@ KernelCreateInfo BuildKernelCreateInfo(); } // namespace cuda } // namespace contrib +namespace contrib { +namespace js { +template +KernelCreateInfo BuildKernelCreateInfo(); +} // namespace js +} // namespace contrib + namespace contrib { namespace rocm { template diff --git a/include/onnxruntime/core/framework/op_kernel_context.h b/include/onnxruntime/core/framework/op_kernel_context.h index 5f9eee9d23cce..ac22d9130983a 100644 --- a/include/onnxruntime/core/framework/op_kernel_context.h +++ b/include/onnxruntime/core/framework/op_kernel_context.h @@ -184,7 +184,7 @@ class OpKernelContext { Returns Allocator from a specific OrtMemoryInfo object. TODO(leca): Replace GetTempSpaceAllocator() and GetTempSpaceCPUAllocator() with this API in the future */ - AllocatorPtr GetAllocator(const OrtMemoryInfo& memory_info) const; + AllocatorPtr GetAllocator(const OrtDevice& device) const; protected: OpKernelContext(concurrency::ThreadPool* threadpool, const logging::Logger& logger, Stream* stream); diff --git a/include/onnxruntime/core/framework/op_kernel_info.h b/include/onnxruntime/core/framework/op_kernel_info.h index 55afd5778db7b..b31c85e32f80c 100644 --- a/include/onnxruntime/core/framework/op_kernel_info.h +++ b/include/onnxruntime/core/framework/op_kernel_info.h @@ -27,11 +27,12 @@ class OpKernelInfo : public OpNodeProtoHelper { const IExecutionProvider& execution_provider, const std::unordered_map& constant_initialized_tensors, const OrtValueNameIdxMap& mlvalue_name_idx_map, - const DataTransferManager& data_transfer_mgr); + const DataTransferManager& data_transfer_mgr, + const AllocatorMap& allocators = {}); OpKernelInfo(const OpKernelInfo& other); - const OrtMemoryInfo& GetMemoryInfo(OrtMemType mem_type) const; + const OrtDevice GetDevice(OrtMemType mem_type) const; AllocatorPtr GetAllocator(OrtMemType mem_type) const; @@ -47,6 +48,8 @@ class OpKernelInfo : public OpNodeProtoHelper { bool TryGetConstantInput(int input_index, const OrtValue** constant_input_value) const; + const AllocatorMap& GetAllocators() const { return allocators_; } + private: ORT_DISALLOW_MOVE(OpKernelInfo); ORT_DISALLOW_ASSIGNMENT(OpKernelInfo); @@ -60,6 +63,7 @@ class OpKernelInfo : public OpNodeProtoHelper { const OrtValueNameIdxMap& ort_value_name_idx_map_; const DataTransferManager& data_transfer_mgr_; ProtoHelperNodeContext proto_helper_context_; + const AllocatorMap& allocators_; }; } // namespace onnxruntime diff --git a/include/onnxruntime/core/framework/ort_value.h b/include/onnxruntime/core/framework/ort_value.h index 48c4e4320dfd7..a071f3182faad 100644 --- a/include/onnxruntime/core/framework/ort_value.h +++ b/include/onnxruntime/core/framework/ort_value.h @@ -68,11 +68,7 @@ struct OrtValue { } bool IsSparseTensor() const { -#if !defined(DISABLE_SPARSE_TENSORS) return (type_ != nullptr && type_->IsSparseTensorType()); -#else - ORT_THROW("Sparse tensor is not supported in this build."); -#endif } onnxruntime::MLDataType Type() const { diff --git a/include/onnxruntime/core/framework/ortdevice.h b/include/onnxruntime/core/framework/ortdevice.h index 77f7c3e1743f0..f15543f22f21d 100644 --- a/include/onnxruntime/core/framework/ortdevice.h +++ b/include/onnxruntime/core/framework/ortdevice.h @@ -4,6 +4,7 @@ #pragma once #include +#include "core/common/hash_combine.h" // Struct to represent a physical device. struct OrtDevice { @@ -54,15 +55,33 @@ struct OrtDevice { return ostr.str(); } + // This is to make OrtDevice a valid key in hash tables + size_t Hash() const { + auto h = std::hash()(device_type); + onnxruntime::HashCombine(memory_type, h); + onnxruntime::HashCombine(device_id, h); + return h; + } + + // To make OrtDevice become a valid key in std map + bool operator<(const OrtDevice& other) const { + if (device_type != other.device_type) + return device_type < other.device_type; + if (memory_type != other.memory_type) + return memory_type < other.memory_type; + + return device_id < other.device_id; + } + private: // Device type. - DeviceType device_type; + int32_t device_type : 8; // Memory type. - MemoryType memory_type; + int32_t memory_type : 8; // Device index. - DeviceId device_id; + int32_t device_id : 16; }; inline bool operator==(const OrtDevice& left, const OrtDevice& other) { @@ -72,3 +91,12 @@ inline bool operator==(const OrtDevice& left, const OrtDevice& other) { inline bool operator!=(const OrtDevice& left, const OrtDevice& other) { return !(left == other); } + +namespace std { +template <> +struct hash { + size_t operator()(const OrtDevice& i) const { + return i.Hash(); + } +}; +} // namespace std diff --git a/include/onnxruntime/core/framework/stream_handles.h b/include/onnxruntime/core/framework/stream_handles.h index 95a59e2d3eca9..c235ee904762e 100644 --- a/include/onnxruntime/core/framework/stream_handles.h +++ b/include/onnxruntime/core/framework/stream_handles.h @@ -96,6 +96,10 @@ class Stream { } } + virtual void* GetResource(int /*version*/, int /*id*/) const { + return nullptr; + } + private: StreamHandle handle_; const OrtDevice& device_; diff --git a/include/onnxruntime/core/framework/to_tensor_proto_element_type.h b/include/onnxruntime/core/framework/to_tensor_proto_element_type.h index 0be55f0036fd7..21253eb4a6e83 100644 --- a/include/onnxruntime/core/framework/to_tensor_proto_element_type.h +++ b/include/onnxruntime/core/framework/to_tensor_proto_element_type.h @@ -7,9 +7,10 @@ #include #ifndef SHARED_PROVIDER -#include "onnx/onnx_pb.h" +#include "core/graph/onnx_protobuf.h" #endif +#include "core/framework/float8.h" #include "core/framework/float16.h" namespace onnxruntime { @@ -75,5 +76,27 @@ template <> constexpr ONNX_NAMESPACE::TensorProto_DataType ToTensorProtoElementType() { return ONNX_NAMESPACE::TensorProto_DataType_BFLOAT16; } + +#if !defined(DISABLE_FLOAT8_TYPES) + +template <> +constexpr ONNX_NAMESPACE::TensorProto_DataType ToTensorProtoElementType() { + return ONNX_NAMESPACE::TensorProto_DataType_FLOAT8E4M3FN; +} +template <> +constexpr ONNX_NAMESPACE::TensorProto_DataType ToTensorProtoElementType() { + return ONNX_NAMESPACE::TensorProto_DataType_FLOAT8E4M3FNUZ; +} +template <> +constexpr ONNX_NAMESPACE::TensorProto_DataType ToTensorProtoElementType() { + return ONNX_NAMESPACE::TensorProto_DataType_FLOAT8E5M2; +} +template <> +constexpr ONNX_NAMESPACE::TensorProto_DataType ToTensorProtoElementType() { + return ONNX_NAMESPACE::TensorProto_DataType_FLOAT8E5M2FNUZ; +} + +#endif + } // namespace utils } // namespace onnxruntime diff --git a/include/onnxruntime/core/graph/constants.h b/include/onnxruntime/core/graph/constants.h index 6fc9ef6e1c8c3..7e59aad80cc47 100644 --- a/include/onnxruntime/core/graph/constants.h +++ b/include/onnxruntime/core/graph/constants.h @@ -48,6 +48,7 @@ constexpr const char* kJsExecutionProvider = "JsExecutionProvider"; constexpr const char* kSnpeExecutionProvider = "SNPEExecutionProvider"; constexpr const char* kTvmExecutionProvider = "TvmExecutionProvider"; constexpr const char* kXnnpackExecutionProvider = "XnnpackExecutionProvider"; +constexpr const char* kWebNNExecutionProvider = "WebNNExecutionProvider"; constexpr const char* kCannExecutionProvider = "CANNExecutionProvider"; constexpr const char* kAzureExecutionProvider = "AzureExecutionProvider"; diff --git a/include/onnxruntime/core/graph/graph.h b/include/onnxruntime/core/graph/graph.h index dc6c7d271343c..f153e88909b8d 100644 --- a/include/onnxruntime/core/graph/graph.h +++ b/include/onnxruntime/core/graph/graph.h @@ -16,28 +16,25 @@ #pragma warning(disable : 4244) #endif -#if !defined(ORT_MINIMAL_BUILD) -#include "onnx/defs/schema.h" -#include "core/common/inlined_containers.h" -#else -#include "onnx/defs/data_type_utils.h" -#endif -#include "onnx/onnx_pb.h" -#include "onnx/onnx-operators_pb.h" - #ifdef _WIN32 #pragma warning(pop) #endif +#include "flatbuffers/flatbuffers.h" + #include "core/common/gsl.h" #include "core/common/common.h" #include "core/common/const_pointer_container.h" +#if !defined(ORT_MINIMAL_BUILD) +#include "core/common/inlined_containers.h" +#endif #include "core/common/inlined_containers_fwd.h" #include "core/common/path.h" #include "core/common/span_utils.h" #include "core/common/status.h" #include "core/common/logging/logging.h" +#include "core/graph/onnx_protobuf.h" #include "core/graph/basic_types.h" #include "core/graph/constants.h" #include "core/graph/function.h" @@ -48,12 +45,6 @@ #include "core/graph/node_arg.h" #include "core/graph/ort_format_load_options.h" -namespace flatbuffers { -class FlatBufferBuilder; -template -struct Offset; -} // namespace flatbuffers - namespace onnxruntime { class Graph; struct IndexedSubGraph; @@ -895,12 +886,11 @@ class Graph { @returns NodeArg reference. */ NodeArg& GetOrCreateNodeArg(const std::string& name, const ONNX_NAMESPACE::TypeProto* p_arg_type) { - auto iter = node_args_.find(name); - if (iter != node_args_.end()) { - return *(iter->second); + auto insert_result = node_args_.emplace(name, nullptr); + if (insert_result.second) { + insert_result.first->second = std::make_unique(name, p_arg_type); } - auto result = node_args_.insert(std::make_pair(name, std::make_unique(name, p_arg_type))); - return *(result.first->second); + return *(insert_result.first->second); } #if !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) @@ -1121,6 +1111,7 @@ class Graph { @returns GraphProto serialization of the graph. */ ONNX_NAMESPACE::GraphProto ToGraphProtoWithExternalInitializers(const std::string& external_file_name, + const PathString& file_path, size_t initializer_size_threshold) const; /** Gets the ISchemaRegistry instances being used with this Graph. */ @@ -1144,6 +1135,7 @@ class Graph { /** Directly insert the nodes in the function Node provided into this Graph. + The Graph needs to be Resolve()d after this call. @param node Node with Node::Type of Node::Type::Fused @returns Status indicating success or providing an error message. */ diff --git a/include/onnxruntime/core/graph/indexed_sub_graph.h b/include/onnxruntime/core/graph/indexed_sub_graph.h index 935ada88c6c88..c57db41254159 100644 --- a/include/onnxruntime/core/graph/indexed_sub_graph.h +++ b/include/onnxruntime/core/graph/indexed_sub_graph.h @@ -8,13 +8,7 @@ #include #include "core/graph/basic_types.h" -#if !defined(ORT_MINIMAL_BUILD) -#include "onnx/defs/schema.h" -#else -#include "onnx/defs/data_type_utils.h" -#endif -#include "onnx/onnx_pb.h" -#include "onnx/onnx-operators_pb.h" +#include "core/graph/onnx_protobuf.h" namespace onnxruntime { diff --git a/include/onnxruntime/core/graph/schema_registry.h b/include/onnxruntime/core/graph/schema_registry.h index 9982ac943463c..b128e91afa9ae 100644 --- a/include/onnxruntime/core/graph/schema_registry.h +++ b/include/onnxruntime/core/graph/schema_registry.h @@ -7,10 +7,8 @@ #include #include -#include "onnx/onnx_pb.h" -#include "onnx/onnx-operators_pb.h" +#include "core/graph/onnx_protobuf.h" #include "onnx/defs/schema.h" - #include "core/graph/constants.h" #include "core/common/common.h" #include "core/common/status.h" diff --git a/include/onnxruntime/core/optimizer/graph_transformer.h b/include/onnxruntime/core/optimizer/graph_transformer.h index 331ef5b53061e..0af84f17abb88 100644 --- a/include/onnxruntime/core/optimizer/graph_transformer.h +++ b/include/onnxruntime/core/optimizer/graph_transformer.h @@ -6,6 +6,7 @@ #include "core/common/common.h" #include "core/common/inlined_containers.h" +#include "core/framework/data_types.h" #include "core/graph/graph_viewer.h" #include "core/optimizer/graph_transformer_level.h" @@ -69,4 +70,27 @@ class GraphTransformer { const std::string name_; const InlinedHashSet compatible_provider_types_; }; + +/** + * @brief Immutable object to identify a kernel registration. + * + * This data structure is used by the graph transformers to check whether + * a kernel is registered with the execution provider (i.e. has an + * implementation). If not, the transformer can not generate a node with + * such kernel. + */ +struct OpKernelRegistryId { + const std::string op_type_; + const std::string domain_; + const int version_; + const InlinedHashMap type_constraints_; + + OpKernelRegistryId( + const std::basic_string_view& op, + const std::basic_string_view& domain, + const int version, + const std::initializer_list>& init_list) + : op_type_(op), domain_(domain), version_(version), type_constraints_(init_list) {} +}; + } // namespace onnxruntime diff --git a/include/onnxruntime/core/platform/EigenNonBlockingThreadPool.h b/include/onnxruntime/core/platform/EigenNonBlockingThreadPool.h index d3cc80596574b..a57385f6e23f1 100644 --- a/include/onnxruntime/core/platform/EigenNonBlockingThreadPool.h +++ b/include/onnxruntime/core/platform/EigenNonBlockingThreadPool.h @@ -27,6 +27,13 @@ #ifdef HAS_CLASS_MEMACCESS #pragma GCC diagnostic ignored "-Wclass-memaccess" #endif +// eigen-src/unsupported/Eigen/CXX11/src/ThreadPool/EventCount.h:231:56: error: implicit conversion loses integer +// precision: 'uint64_t' (aka 'unsigned long long') to 'size_t' (aka 'unsigned long') [-Werror,-Wshorten-64-to-32] +// next = wnext == kStackMask ? nullptr : &waiters_[wnext]; +// ~~~~~~~~ ^~~~~ +#ifdef HAS_SHORTEN_64_TO_32 +#pragma GCC diagnostic ignored "-Wshorten-64-to-32" +#endif #elif defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 4127) @@ -44,6 +51,7 @@ #include "core/common/inlined_containers_fwd.h" #include "core/common/spin_pause.h" #include "core/platform/ort_mutex.h" +#include "core/platform/ort_spin_lock.h" #include "core/platform/Barrier.h" // ORT thread pool overview @@ -449,7 +457,11 @@ class RunQueue { // PushBack adds w at the end of the queue. // If queue is full returns w, otherwise returns default-constructed Work. Work PushBack(Work w) { +#ifdef USE_LOCK_FREE_QUEUE + std::lock_guard mtx(spin_lock_); +#else std::lock_guard lock(mutex_); +#endif unsigned back = back_.load(std::memory_order_relaxed); Elem& e = array_[(back - 1) & kMask]; ElemState s = e.state.load(std::memory_order_relaxed); @@ -469,7 +481,11 @@ class RunQueue { // with w_idx. Typically the tag will be a per-thread ID to distinguish work // submitted from different threads. PushResult PushBackWithTag(Work w, Tag tag, unsigned& w_idx) { +#ifdef USE_LOCK_FREE_QUEUE + std::lock_guard mtx(spin_lock_); +#else std::lock_guard lock(mutex_); +#endif unsigned back = back_.load(std::memory_order_relaxed); w_idx = (back - 1) & kMask; Elem& e = array_[w_idx]; @@ -490,7 +506,11 @@ class RunQueue { Work PopBack() { if (Empty()) return Work(); +#ifdef USE_LOCK_FREE_QUEUE + std::lock_guard mtx(spin_lock_); +#else std::lock_guard lock(mutex_); +#endif unsigned back; Elem* e; ElemState s; @@ -532,7 +552,11 @@ class RunQueue { bool RevokeWithTag(Tag tag, unsigned w_idx) { bool revoked = false; +#ifdef USE_LOCK_FREE_QUEUE + std::lock_guard mtx(spin_lock_); +#else std::lock_guard lock(mutex_); +#endif Elem& e = array_[w_idx]; ElemState s = e.state.load(std::memory_order_relaxed); @@ -604,7 +628,11 @@ class RunQueue { Work w; }; +#ifdef USE_LOCK_FREE_QUEUE + OrtSpinLock spin_lock_; +#else OrtMutex mutex_; +#endif // Low log(kSize) + 1 bits in front_ and back_ contain rolling index of // front/back, respectively. The remaining bits contain modification counters @@ -729,7 +757,7 @@ class ThreadPoolTempl : public onnxruntime::concurrency::ExtendedThreadPoolInter return v_; } - bool operator==(Tag& other) const { + bool operator==(const Tag& other) const { return v_ == other.v_; } diff --git a/include/onnxruntime/core/platform/ort_spin_lock.h b/include/onnxruntime/core/platform/ort_spin_lock.h new file mode 100644 index 0000000000000..db80abe1ee2fe --- /dev/null +++ b/include/onnxruntime/core/platform/ort_spin_lock.h @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +#pragma once +#include "core/common/spin_pause.h" +#include + +namespace onnxruntime { +/* +OrtSpinLock implemented mutex semantic "lock-freely", +calling thread will not be put to sleep on blocked, +which reduces cpu usage on context switching. +*/ +struct OrtSpinLock { + using LockState = enum { Locked = 0, + Unlocked }; + + void lock() noexcept { + LockState state = Unlocked; + while (!state_.compare_exchange_weak(state, Locked, std::memory_order_acq_rel, std::memory_order_relaxed)) { + state = Unlocked; + concurrency::SpinPause(); // pause and retry + } + } + bool try_lock() noexcept { + LockState state = Unlocked; + return state_.compare_exchange_weak(state, Locked, std::memory_order_acq_rel, std::memory_order_relaxed); + } + void unlock() noexcept { + state_.store(Unlocked, std::memory_order_release); + } + + private: + std::atomic state_{Unlocked}; +}; +} // namespace onnxruntime \ No newline at end of file diff --git a/include/onnxruntime/core/providers/coreml/coreml_provider_factory.h b/include/onnxruntime/core/providers/coreml/coreml_provider_factory.h index f7857a3cdc75a..03715eb5b78b2 100644 --- a/include/onnxruntime/core/providers/coreml/coreml_provider_factory.h +++ b/include/onnxruntime/core/providers/coreml/coreml_provider_factory.h @@ -24,9 +24,13 @@ enum COREMLFlags { // Please note, enable this option does not guarantee the entire model to be executed using ANE only COREML_FLAG_ONLY_ENABLE_DEVICE_WITH_ANE = 0x004, - // Keep COREML_FLAG_MAX at the end of the enum definition + // Only allow CoreML EP to take nodes with inputs with static shapes. By default it will also allow inputs with + // dynamic shapes. However, the performance may be negatively impacted if inputs have dynamic shapes. + COREML_FLAG_ONLY_ALLOW_STATIC_INPUT_SHAPES = 0x008, + + // Keep COREML_FLAG_LAST at the end of the enum definition // And assign the last COREMLFlag to it - COREML_FLAG_LAST = COREML_FLAG_ONLY_ENABLE_DEVICE_WITH_ANE, + COREML_FLAG_LAST = COREML_FLAG_ONLY_ALLOW_STATIC_INPUT_SHAPES, }; #ifdef __cplusplus diff --git a/include/onnxruntime/core/providers/cuda/cuda_context.h b/include/onnxruntime/core/providers/cuda/cuda_context.h new file mode 100644 index 0000000000000..13c176dad3cc5 --- /dev/null +++ b/include/onnxruntime/core/providers/cuda/cuda_context.h @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +#pragma once + +#define ORT_CUDA_CTX + +#include "cuda_resource.h" +#include "core/providers/custom_op_context.h" +#include +#include +#include +#include + +namespace Ort { + +namespace Custom { + +struct CudaContext : public CustomOpContext { + cudaStream_t cuda_stream = {}; + cudnnHandle_t cudnn_handle = {}; + cublasHandle_t cublas_handle = {}; + + void Init(const OrtKernelContext& kernel_ctx) override { + const auto& ort_api = Ort::GetApi(); + void* resource = {}; + OrtStatus* status = nullptr; + + status = ort_api.KernelContext_GetResource(&kernel_ctx, ORT_CUDA_RESOUCE_VERSION, CudaResource::cuda_stream_t, &resource); + if (status) { + ORT_CXX_API_THROW("failed to fetch cuda stream", OrtErrorCode::ORT_RUNTIME_EXCEPTION); + } + cuda_stream = reinterpret_cast(resource); + + resource = {}; + status = ort_api.KernelContext_GetResource(&kernel_ctx, ORT_CUDA_RESOUCE_VERSION, CudaResource::cudnn_handle_t, &resource); + if (status) { + ORT_CXX_API_THROW("failed to fetch cudnn handle", OrtErrorCode::ORT_RUNTIME_EXCEPTION); + } + cudnn_handle = reinterpret_cast(resource); + + resource = {}; + status = ort_api.KernelContext_GetResource(&kernel_ctx, ORT_CUDA_RESOUCE_VERSION, CudaResource::cublas_handle_t, &resource); + if (status) { + ORT_CXX_API_THROW("failed to fetch cublas handle", OrtErrorCode::ORT_RUNTIME_EXCEPTION); + } + cublas_handle = reinterpret_cast(resource); + } +}; + +} // namespace Custom +} // namespace Ort diff --git a/include/onnxruntime/core/providers/cuda/cuda_provider_options.h b/include/onnxruntime/core/providers/cuda/cuda_provider_options.h index 52d522b312a3c..eaf0e5337b8b6 100644 --- a/include/onnxruntime/core/providers/cuda/cuda_provider_options.h +++ b/include/onnxruntime/core/providers/cuda/cuda_provider_options.h @@ -14,19 +14,22 @@ /// User can only get the instance of OrtCUDAProviderOptionsV2 via CreateCUDAProviderOptions. /// struct OrtCUDAProviderOptionsV2 { - int device_id; // cuda device id. - int has_user_compute_stream; // indicator of user specified CUDA compute stream. - void* user_compute_stream; // user specified CUDA compute stream. - int do_copy_in_default_stream; // flag specifying if the default stream is to be used for copying. - OrtCudnnConvAlgoSearch cudnn_conv_algo_search; // cudnn algo search enum. - size_t gpu_mem_limit; // BFC Arena memory limit for CUDA. - // (will be overridden by contents of `default_memory_arena_cfg` is it exists) - onnxruntime::ArenaExtendStrategy arena_extend_strategy; // BFC Arena extension strategy. - // (will be overridden by contents of `default_memory_arena_cfg` is it exists) - OrtArenaCfg* default_memory_arena_cfg; // BFC Arena config flags. - int cudnn_conv_use_max_workspace; // flag specifying if maximum workspace can be used in cudnn conv algo search. - int enable_cuda_graph; // flag specifying if the CUDA graph is to be captured for the model. - int cudnn_conv1d_pad_to_nc1d; // flag specifying if pad Conv1D's input [N,C,D] to [N,C,1,D] or [N,C,D,1]. - int tunable_op_enable; // flag specifying if TunableOp is enabled. - int tunable_op_tuning_enable; // flag specifying if TunableOp is enabled for tuning, this relies on TunableOp is enabled. + int device_id = 0; // cuda device id. + int has_user_compute_stream = 0; // indicator of user specified CUDA compute stream. + void* user_compute_stream = nullptr; // user specified CUDA compute stream. + int do_copy_in_default_stream = 1; // flag specifying if the default stream is to be used for copying. + OrtCudnnConvAlgoSearch cudnn_conv_algo_search = OrtCudnnConvAlgoSearchExhaustive; // cudnn algo search enum. + size_t gpu_mem_limit = std::numeric_limits::max(); // BFC Arena memory limit for CUDA. + // (will be overridden by contents of `default_memory_arena_cfg` is it exists) + onnxruntime::ArenaExtendStrategy arena_extend_strategy = onnxruntime::ArenaExtendStrategy::kNextPowerOfTwo; // BFC Arena extension strategy. + // (will be overridden by contents of `default_memory_arena_cfg` is it exists) + OrtArenaCfg* default_memory_arena_cfg = nullptr; // BFC Arena config flags. + int cudnn_conv_use_max_workspace = 1; // flag specifying if maximum workspace can be used in cudnn conv algo search. + int enable_cuda_graph = 0; // flag specifying if the CUDA graph is to be captured for the model. + int cudnn_conv1d_pad_to_nc1d = 0; // flag specifying if pad Conv1D's input [N,C,D] to [N,C,1,D] or [N,C,D,1]. + int tunable_op_enable = 0; // flag specifying if TunableOp is enabled. + int tunable_op_tuning_enable = 0; // flag specifying if TunableOp is enabled for tuning, this relies on TunableOp is enabled. + int tunable_op_max_tuning_duration_ms = 0; // Max tuning duration time limit for TunableOp. + int enable_skip_layer_norm_strict_mode = 0; // flag specifying if SkipLayerNorm is in strict mode. If true, use LayerNormalization kernel. + // The strict mode has better accuracy but lower performance. }; diff --git a/include/onnxruntime/core/providers/cuda/cuda_resource.h b/include/onnxruntime/core/providers/cuda/cuda_resource.h new file mode 100644 index 0000000000000..e46fc5b4219dd --- /dev/null +++ b/include/onnxruntime/core/providers/cuda/cuda_resource.h @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/providers/resource.h" + +#define ORT_CUDA_RESOUCE_VERSION 1 + +enum CudaResource : int { + cuda_stream_t = cuda_resource_offset, + cudnn_handle_t, + cublas_handle_t +}; \ No newline at end of file diff --git a/include/onnxruntime/core/providers/custom_op_context.h b/include/onnxruntime/core/providers/custom_op_context.h new file mode 100644 index 0000000000000..547f9a90aff85 --- /dev/null +++ b/include/onnxruntime/core/providers/custom_op_context.h @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include + +// CustomOpContext defines an interface allowing a custom op to access ep-specific resources. +struct CustomOpContext { + CustomOpContext() = default; + virtual ~CustomOpContext(){}; + virtual void Init(const OrtKernelContext&){}; +}; \ No newline at end of file diff --git a/include/onnxruntime/core/providers/openvino/openvino_provider_factory.h b/include/onnxruntime/core/providers/openvino/openvino_provider_factory.h index 26184c83aa0b5..a33a8de485b77 100644 --- a/include/onnxruntime/core/providers/openvino/openvino_provider_factory.h +++ b/include/onnxruntime/core/providers/openvino/openvino_provider_factory.h @@ -13,7 +13,7 @@ extern "C" { /** * \param device_type openvino device type and precision. Could be any of - * CPU_FP32, CPU_FP16, GPU_FP32, GPU_FP16, MYRIAD_FP16, VAD-M_FP16 or VAD-F_FP32. + * CPU_FP32, CPU_FP16, GPU_FP32, GPU_FP16 */ ORT_API_STATUS(OrtSessionOptionsAppendExecutionProvider_OpenVINO, _In_ OrtSessionOptions* options, _In_ const char* device_type); diff --git a/include/onnxruntime/core/providers/resource.h b/include/onnxruntime/core/providers/resource.h new file mode 100644 index 0000000000000..bd123e1cd41c2 --- /dev/null +++ b/include/onnxruntime/core/providers/resource.h @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +enum ResourceOffset { + cpu_resource_offset = 0, + cuda_resource_offset = 10000, + dml_resource_offset = 20000, + rocm_resource_offset = 30000, + // offsets for other ort eps + custom_ep_resource_offset = 10000000, + // offsets for customized eps +}; \ No newline at end of file diff --git a/include/onnxruntime/core/providers/rocm/rocm_context.h b/include/onnxruntime/core/providers/rocm/rocm_context.h new file mode 100644 index 0000000000000..ff62094f3f439 --- /dev/null +++ b/include/onnxruntime/core/providers/rocm/rocm_context.h @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#define ORT_ROCM_CTX + +#include "rocm_resource.h" +#include "core/providers/custom_op_context.h" +#include +#include +#include + +namespace Ort { + +namespace Custom { + +struct RocmContext : public CustomOpContext { + hipStream_t hip_stream = {}; + miopenHandle_t miopen_handle = {}; + rocblas_handle rblas_handle = {}; + + void Init(const OrtKernelContext& kernel_ctx) override { + const auto& ort_api = Ort::GetApi(); + void* resource = {}; + OrtStatus* status = nullptr; + + status = ort_api.KernelContext_GetResource(&kernel_ctx, ORT_ROCM_RESOUCE_VERSION, RocmResource::hip_stream_t, &resource); + if (status) { + ORT_CXX_API_THROW("failed to fetch hip stream", OrtErrorCode::ORT_RUNTIME_EXCEPTION); + } + hip_stream = reinterpret_cast(resource); + + resource = {}; + status = ort_api.KernelContext_GetResource(&kernel_ctx, ORT_ROCM_RESOUCE_VERSION, RocmResource::miopen_handle_t, &resource); + if (status) { + ORT_CXX_API_THROW("failed to fetch miopen handle", OrtErrorCode::ORT_RUNTIME_EXCEPTION); + } + miopen_handle = reinterpret_cast(resource); + + resource = {}; + status = ort_api.KernelContext_GetResource(&kernel_ctx, ORT_ROCM_RESOUCE_VERSION, RocmResource::rocblas_handle_t, &resource); + if (status) { + ORT_CXX_API_THROW("failed to fetch rocblas handle", OrtErrorCode::ORT_RUNTIME_EXCEPTION); + } + rblas_handle = reinterpret_cast(resource); + } +}; + +} // namespace Custom +} // namespace Ort diff --git a/include/onnxruntime/core/providers/rocm/rocm_resource.h b/include/onnxruntime/core/providers/rocm/rocm_resource.h new file mode 100644 index 0000000000000..53f26c13e93e0 --- /dev/null +++ b/include/onnxruntime/core/providers/rocm/rocm_resource.h @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/providers/resource.h" + +#define ORT_ROCM_RESOUCE_VERSION 1 + +enum RocmResource : int { + hip_stream_t = rocm_resource_offset, + miopen_handle_t, + rocblas_handle_t +}; diff --git a/include/onnxruntime/core/providers/tensorrt/tensorrt_provider_options.h b/include/onnxruntime/core/providers/tensorrt/tensorrt_provider_options.h index 1c9f7ecd09119..e7d0f9f03ade9 100644 --- a/include/onnxruntime/core/providers/tensorrt/tensorrt_provider_options.h +++ b/include/onnxruntime/core/providers/tensorrt/tensorrt_provider_options.h @@ -36,9 +36,13 @@ struct OrtTensorRTProviderOptionsV2 { int trt_detailed_build_log; // Enable detailed build step logging on TensorRT EP with timing for each engine build. Default 0 = false, nonzero = true int trt_build_heuristics_enable; // Build engine using heuristics to reduce build time. Default 0 = false, nonzero = true int trt_sparsity_enable; // Control if sparsity can be used by TRT. Default 0 = false, 1 = true - int trt_builder_optimization_level; // Set the builder optimization level. WARNING: levels below 2 do not guarantee good engine performance, but greatly improve build time. Default 2, valid range [0-4] + int trt_builder_optimization_level; // 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; // 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; // pecify 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; // specify extra TensorRT plugin library paths + const char* trt_profile_min_shapes; // Specify the range of the input shapes to build the engine with + const char* trt_profile_max_shapes; // Specify the range of the input shapes to build the engine with + const char* trt_profile_opt_shapes; // Specify the range of the input shapes to build the engine with + int trt_cuda_graph_enable; // Enable CUDA graph in ORT TRT }; diff --git a/include/onnxruntime/core/providers/vitisai/vitisai_provider_factory.h b/include/onnxruntime/core/providers/vitisai/vitisai_provider_factory.h deleted file mode 100644 index a7ee4ec1365b6..0000000000000 --- a/include/onnxruntime/core/providers/vitisai/vitisai_provider_factory.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Xilinx Inc. -// Licensed under the MIT License. - -#include "onnxruntime_c_api.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \param use_arena zero: false. non-zero: true. - */ -ORT_API_STATUS(OrtSessionOptionsAppendExecutionProvider_VITISAI, _In_ OrtSessionOptions* options, - const char* backend_type, int device_id, const char* export_runtime_module, - const char* load_runtime_module); - -#ifdef __cplusplus -} -#endif diff --git a/include/onnxruntime/core/session/environment.h b/include/onnxruntime/core/session/environment.h index cc511ccad569c..20c7cace152d5 100644 --- a/include/onnxruntime/core/session/environment.h +++ b/include/onnxruntime/core/session/environment.h @@ -81,6 +81,13 @@ class Environment { Environment() = default; + /** + * Create and register an allocator, specified by provider_type, for sharing between multiple sessions. + * Return an error if an allocator with the same OrtMemoryInfo is already registered. + * For provider_type please refer core/graph/constants.h + */ + Status CreateAndRegisterAllocatorV2(const std::string& provider_type, const OrtMemoryInfo& mem_info, const std::unordered_map& options, const OrtArenaCfg* arena_cfg = nullptr); + private: ORT_DISALLOW_COPY_ASSIGNMENT_AND_MOVE(Environment); Status Initialize(std::unique_ptr logging_manager, diff --git a/include/onnxruntime/core/session/onnxruntime_c_api.h b/include/onnxruntime/core/session/onnxruntime_c_api.h index 39c7b2618fdc9..e483c67a0cfe6 100644 --- a/include/onnxruntime/core/session/onnxruntime_c_api.h +++ b/include/onnxruntime/core/session/onnxruntime_c_api.h @@ -5,11 +5,11 @@ /** \mainpage ONNX Runtime * - * ONNX Runtime is a high-performance inference and training graph execution engine for deeplearning models. + * ONNX Runtime is a high-performance inference and training graph execution engine for deep learning models. * * ONNX Runtime's C, C++ APIs offer an easy to use interface to onboard and execute onnx models. * - \subpage c_cpp_api "Core C, C++ APIs" - * - \subpage training_c_cpp_api "Training C, C++ APIs for learning on the edge" + * - \subpage training_c_cpp_api "Training C, C++ APIs for on-device training" * * \page c_cpp_api Core C, C++ APIs *

C

@@ -37,7 +37,7 @@ * * This value is used by some API functions to behave as this version of the header expects. */ -#define ORT_API_VERSION 15 +#define ORT_API_VERSION 17 #ifdef __cplusplus extern "C" { @@ -61,6 +61,8 @@ extern "C" { #define _Check_return_ #define _Outptr_result_maybenull_ #define _In_reads_(X) +#define _Inout_updates_(X) +#define _Out_writes_(X) #define _Inout_updates_all_(X) #define _Out_writes_bytes_all_(X) #define _Out_writes_all_(X) @@ -95,11 +97,16 @@ extern "C" { #define ORTCHAR_T char #endif +/// ORTCHAR_T, ORT_TSTR are reserved specifically for path handling. +/// All other strings are UTF-8 encoded, use char and std::string #ifndef ORT_TSTR #ifdef _WIN32 #define ORT_TSTR(X) L##X +// When X is a macro, L##X is not defined. In this case, we need to use ORT_TSTR_ON_MACRO. +#define ORT_TSTR_ON_MACRO(X) L"" X #else #define ORT_TSTR(X) X +#define ORT_TSTR_ON_MACRO(X) X #endif #endif @@ -183,7 +190,12 @@ typedef enum ONNXTensorElementDataType { ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT64, // maps to c type uint64_t ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX64, // complex with float32 real and imaginary components ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX128, // complex with float64 real and imaginary components - ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16 // Non-IEEE floating-point format based on IEEE754 single-precision + ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16, // Non-IEEE floating-point format based on IEEE754 single-precision + // float 8 types were introduced in onnx 1.14, see https://onnx.ai/onnx/technical/float8.html + ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FN, // Non-IEEE floating-point format based on IEEE754 single-precision + ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FNUZ, // Non-IEEE floating-point format based on IEEE754 single-precision + ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2, // Non-IEEE floating-point format based on IEEE754 single-precision + ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2FNUZ // Non-IEEE floating-point format based on IEEE754 single-precision } ONNXTensorElementDataType; // Synced with onnx TypeProto oneof @@ -396,7 +408,8 @@ typedef struct OrtCUDAProviderOptions { user_compute_stream{}, default_memory_arena_cfg{}, tunable_op_enable{false}, - tunable_op_tuning_enable{false} {} + tunable_op_tuning_enable{false}, + tunable_op_max_tuning_duration_ms{} {} #endif /** \brief CUDA device Id @@ -459,6 +472,11 @@ typedef struct OrtCUDAProviderOptions { */ int tunable_op_tuning_enable; + /** \brief Max tuning duration time limit for each instance of TunableOp. + * Defaults to 0 to disable the limit. + */ + int tunable_op_max_tuning_duration_ms; + } OrtCUDAProviderOptions; /** \brief ROCM Provider Options @@ -477,7 +495,8 @@ typedef struct OrtROCMProviderOptions { user_compute_stream{}, default_memory_arena_cfg{}, tunable_op_enable{false}, - tunable_op_tuning_enable{false} {} + tunable_op_tuning_enable{false}, + tunable_op_max_tuning_duration_ms{} {} #endif /** \brief ROCM device Id @@ -539,6 +558,11 @@ typedef struct OrtROCMProviderOptions { */ int tunable_op_tuning_enable; + /** \brief Max tuning duration time limit for each instance of TunableOp. + * Defaults to 0 to disable the limit. + */ + int tunable_op_max_tuning_duration_ms; + } OrtROCMProviderOptions; /** \brief TensorRT Provider Options @@ -596,7 +620,7 @@ typedef struct OrtOpenVINOProviderOptions { #endif /** \brief Device type string * - * Valid settings are one of: "CPU_FP32", "CPU_FP16", "GPU_FP32", "GPU_FP16", "MYRIAD_FP16", "VAD-M_FP16" or "VAD-F_FP32" + * Valid settings are one of: "CPU_FP32", "CPU_FP16", "GPU_FP32", "GPU_FP16" */ const char* device_type; unsigned char enable_vpu_fast_compile; ///< 0 = disabled, nonzero = enabled @@ -624,10 +648,19 @@ struct OrtApiBase { * \param[in] version Must be ::ORT_API_VERSION * \return The ::OrtApi for the version requested, nullptr will be returned if this version is unsupported, for example when using a runtime * older than the version created with this header file. + * + * One can call GetVersionString() to get the version of the Onnxruntime library for logging + * and error reporting purposes. */ const OrtApi*(ORT_API_CALL* GetApi)(uint32_t version)NO_EXCEPTION; - const char*(ORT_API_CALL* GetVersionString)(void)NO_EXCEPTION; ///< Returns a null terminated string of the version of the Onnxruntime library (eg: "1.8.1") + + /** \brief Returns a null terminated string of the version of the Onnxruntime library (eg: "1.8.1") + * + * \return UTF-8 encoded version string. Do not deallocate the returned buffer. + */ + const char*(ORT_API_CALL* GetVersionString)(void)NO_EXCEPTION; }; + typedef struct OrtApiBase OrtApiBase; /** \brief The Onnxruntime library's entry point to access the C API @@ -663,6 +696,15 @@ typedef void (*OrtCustomJoinThreadFn)(OrtCustomThreadHandle ort_custom_thread_ha typedef OrtStatus*(ORT_API_CALL* RegisterCustomOpsFn)(OrtSessionOptions* options, const OrtApiBase* api); +/** \brief Callback function for RunAsync + * + * \param[in] user_data User specific data that passed back to the callback + * \param[out] outputs On succeed, outputs host inference results, on error, the value will be nullptr + * \param[out] num_outputs Number of outputs, on error, the value will be zero + * \param[out] status On error, status will provide details + */ +typedef void (*RunAsyncCallbackFn)(void* user_data, OrtValue** outputs, size_t num_outputs, OrtStatusPtr status); + /** \brief The C API * * All C API functions are defined inside this structure as pointers to functions. @@ -945,7 +987,7 @@ struct OrtApi { /** \brief Set the optimization level to apply when loading a graph * - * Please see https://onnxruntime.ai/docs/performance/graph-optimizations.html for an in-depth explanation + * Please see https://onnxruntime.ai/docs/performance/model-optimizations/graph-optimizations.html for an in-depth explanation * \param[in,out] options The session options object * \param[in] graph_optimization_level The optimization level * @@ -2714,6 +2756,10 @@ struct OrtApi { * crossing which the current chunk is chunked into 2. * "initial_growth_chunk_size_bytes": (Possible) Size of the second allocation in the arena. * Only relevant if arena strategy is `kNextPowerOfTwo`. Use -1 to allow ORT to choose the default. + * "max_power_of_two_extend_bytes": The maximum enxtend size if arena strategy is `kNextPowerOfTwo`. + * It is not an allocation limit, it is only a limit for extention when requested byte is less than the limit. + * When requested bytes is more than the limit, allocator will still return as requested. + * Use -1 to allow ORT to choose the default 1GB for max_power_of_two_extend_bytes. * Ultimately, the allocation size is determined by the allocation memory request. * Further allocation sizes are governed by the arena extend strategy. * @@ -3482,16 +3528,16 @@ struct OrtApi { */ ORT_API2_STATUS(CreateOp, _In_ const OrtKernelInfo* info, - _In_ const char* op_name, - _In_ const char* domain, - _In_ int version, - _In_opt_ const char** type_constraint_names, - _In_opt_ const ONNXTensorElementDataType* type_constraint_values, - _In_opt_ int type_constraint_count, - _In_opt_ const OrtOpAttr* const* attr_values, - _In_opt_ int attr_count, - _In_ int input_count, - _In_ int output_count, + _In_z_ const char* op_name, + _In_z_ const char* domain, + int version, + _In_reads_(type_constraint_count) const char** type_constraint_names, + _In_reads_(type_constraint_count) const ONNXTensorElementDataType* type_constraint_values, + int type_constraint_count, + _In_reads_(attr_count) const OrtOpAttr* const* attr_values, + int attr_count, + int input_count, + int output_count, _Outptr_ OrtOp** ort_op); /** \brief: Invoke the operator created by OrtApi::CreateOp @@ -3539,8 +3585,13 @@ struct OrtApi { * * QNN supported keys: * "backend_path": file path to QNN backend library. - * "profiling_level": QNN profiling level, options: "basic", "detailed". + * "qnn_context_cache_enable": 1 to enable QNN graph creation from cached QNN context file. If it's enabled: QNN EP will + * load from cached QNN context binary if it exist. It will generate a context binary file if it's not exist + * "qnn_context_cache_path": explicitly provide the QNN context cache file. Default to model_file.onnx.bin if not provided. + * "profiling_level": QNN profiling level, options: "off", "basic", "detailed". Default to off. * "rpc_control_latency": QNN RPC control latency. + * "htp_performance_mode": QNN performance mode, options: "burst", "balanced", "default", "high_performance", + * "high_power_saver", "low_balanced", "low_power_saver", "power_saver", "sustained_high_performance". Default to "default". * * SNPE supported keys: * "runtime": SNPE runtime engine, options: "CPU", "CPU_FLOAT32", "GPU", "GPU_FLOAT32_16_HYBRID", "GPU_FLOAT16", @@ -3554,6 +3605,7 @@ struct OrtApi { * "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: @@ -4177,7 +4229,7 @@ struct OrtApi { */ ORT_API2_STATUS(GetResizedStringTensorElementBuffer, _Inout_ OrtValue* value, _In_ size_t index, _In_ size_t length_in_bytes, _Inout_ char** buffer); - /** \brief Get Allocator from KernelContext for a specific memoryInfo. + /** \brief Get Allocator from KernelContext for a specific memoryInfo. Please use C API ReleaseAllocator to release out object * * \param[in] context OrtKernelContext instance * \param[in] mem_info OrtMemoryInfo instance @@ -4188,6 +4240,179 @@ struct OrtApi { * \since Version 1.15. */ ORT_API2_STATUS(KernelContext_GetAllocator, _In_ const OrtKernelContext* context, _In_ const OrtMemoryInfo* mem_info, _Outptr_ OrtAllocator** out); + + /** \brief Returns a null terminated string of the build info including git info and cxx flags + * + * \return UTF-8 encoded version string. Do not deallocate the returned buffer. + * + * \since Version 1.15. + */ + const char*(ORT_API_CALL* GetBuildInfoString)(void); + + /// \name OrtROCMProviderOptions + /// @{ + + /** \brief Create an OrtROCMProviderOptions + * + * \param[out] out Newly created ::OrtROCMProviderOptions. Must be released with OrtApi::ReleaseROCMProviderOptions + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.16. + */ + ORT_API2_STATUS(CreateROCMProviderOptions, _Outptr_ OrtROCMProviderOptions** out); + + /** \brief Set options in a ROCm Execution Provider. + * + * Please refer to https://onnxruntime.ai/docs/execution-providers/ROCm-ExecutionProvider.html + * to know the available keys and values. Key should be in null terminated string format of the member of + * ::OrtROCMProviderOptions and value should be its related range. + * + * For example, key="device_id" and value="0" + * + * \param[in] rocm_options + * \param[in] provider_options_keys Array of UTF-8 null-terminated string for provider options keys + * \param[in] provider_options_values Array of UTF-8 null-terminated string for provider options values + * \param[in] num_keys Number of elements in the `provider_option_keys` and `provider_options_values` arrays + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.16. + */ + ORT_API2_STATUS(UpdateROCMProviderOptions, _Inout_ OrtROCMProviderOptions* rocm_options, + _In_reads_(num_keys) const char* const* provider_options_keys, + _In_reads_(num_keys) const char* const* provider_options_values, + _In_ size_t num_keys); + + /** + * Get serialized ROCm provider options string. + * + * For example, "device_id=0;arena_extend_strategy=0;......" + * + * \param rocm_options - OrtROCMProviderOptions instance + * \param allocator - a ptr to an instance of OrtAllocator obtained with CreateAllocator() or GetAllocatorWithDefaultOptions() + * the specified allocator will be used to allocate continuous buffers for output strings and lengths. + * \param ptr - is a UTF-8 null terminated string allocated using 'allocator'. The caller is responsible for using the same allocator to free it. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + * \since Version 1.16. + */ + ORT_API2_STATUS(GetROCMProviderOptionsAsString, _In_ const OrtROCMProviderOptions* rocm_options, _Inout_ OrtAllocator* allocator, _Outptr_ char** ptr); + + /** \brief Release an ::OrtROCMProviderOptions + * + * \note This is an exception in the naming convention of other Release* functions, as the name of the method does not have the V2 suffix, but the type does + * + * \since Version 1.16. + */ + void(ORT_API_CALL* ReleaseROCMProviderOptions)(_Frees_ptr_opt_ OrtROCMProviderOptions* input); + + /** \brief Create an allocator with specific type and register it with the ::OrtEnv + * This API enhance CreateAndRegisterAllocator that it can create an allocator with specific type, not just CPU allocator + * Enables sharing the allocator between multiple sessions that use the same env instance. + * Lifetime of the created allocator will be valid for the duration of the environment. + * Returns an error if an allocator with the same ::OrtMemoryInfo is already registered. + * \param[in] env OrtEnv instance + * \param[in] provider_type ExecutionProvider type + * \param[in] mem_info OrtMemoryInfo instance + * \param[in] arena_cfg Arena configuration + * \param[in] provider_options_keys key of the provider options map + * \param[in] provider_options_values value of the provider options map + * \param[in] num_keys Length of the provider options map + */ + ORT_API2_STATUS(CreateAndRegisterAllocatorV2, _Inout_ OrtEnv* env, _In_ const char* provider_type, _In_ const OrtMemoryInfo* mem_info, _In_ const OrtArenaCfg* arena_cfg, + _In_reads_(num_keys) const char* const* provider_options_keys, _In_reads_(num_keys) const char* const* provider_options_values, _In_ size_t num_keys); + + /** \brief Run the model asynchronously in a thread owned by intra op thread pool + * + * \param[in] session + * \param[in] run_options If nullptr, will use a default ::OrtRunOptions + * \param[in] input_names Array of null terminated UTF8 encoded strings of the input names + * \param[in] input Array of ::OrtValue%s of the input values + * \param[in] input_len Number of elements in the input_names and inputs arrays + * \param[in] output_names Array of null terminated UTF8 encoded strings of the output names + * \param[in] output_names_len Number of elements in the output_names and outputs array + * \param[out] output OrtValue* array of size output_names_len. + * On calling RunAsync, output[i] could either be a null or a pointer to a preallocated OrtValue. + * Later, the output array will be passed to run_async_callback with all null(s) filled with valid + * OrtValue pointer(s) allocated by onnxruntime. + * NOTE: it is customer's duty to finally release the output array and each of its member, + * regardless of whether the member (OrtValue*) is allocated by onnxruntime or preallocated by the customer. + * \param[in] run_async_callback Callback function on model run completion + * \param[in] user_data User data that pass back to run_async_callback + */ + ORT_API2_STATUS(RunAsync, _Inout_ OrtSession* session, _In_opt_ const OrtRunOptions* run_options, + _In_reads_(input_len) const char* const* input_names, + _In_reads_(input_len) const OrtValue* const* input, size_t input_len, + _In_reads_(output_names_len) const char* const* output_names, size_t output_names_len, + _Inout_updates_all_(output_names_len) OrtValue** output, + _In_ RunAsyncCallbackFn run_async_callback, _In_opt_ void* user_data); + + /** + * Update TensorRT EP provider option where its data type is pointer, for example 'user_compute_stream'. + * If the data type of the provider option can be represented by string please use UpdateTensorRTProviderOptions. + * + * Note: It's caller's responsibility to properly manage the lifetime of the instance pointed by this pointer. + * + * \param tensorrt_options - OrtTensorRTProviderOptionsV2 instance + * \param key - Name of the provider option + * \param value - A pointer to the instance that will be assigned to this provider option + * + * \since Version 1.16. + */ + ORT_API2_STATUS(UpdateTensorRTProviderOptionsWithValue, _Inout_ OrtTensorRTProviderOptionsV2* tensorrt_options, _In_ const char* key, _In_ void* value); + + /** + * Get TensorRT EP provider option where its data type is pointer. + * If the data type of the provider option can be represented by string please use GetTensorRTProviderOptionsAsString. + * + * \param tensorrt_options - OrtTensorRTProviderOptionsV2 instance + * \param key - Name of the provider option + * \param ptr - A pointer to the instance that is kept by the provider option + * + * \since Version 1.16. + */ + ORT_API2_STATUS(GetTensorRTProviderOptionsByName, _In_ const OrtTensorRTProviderOptionsV2* tensorrt_options, _In_ const char* key, _Outptr_ void** ptr); + + /** + * Update CUDA EP provider option where its data type is pointer, for example 'user_compute_stream'. + * If the data type of the provider option can be represented by string please use UpdateCUDAProviderOptions. + * + * Note: It's caller's responsibility to properly manage the lifetime of the instance pointed by this pointer. + * + * \param cuda_options - OrtCUDAProviderOptionsV2 instance + * \param key - Name of the provider option + * \param value - A pointer to the instance that will be assigned to this provider option + * + * \since Version 1.16. + */ + ORT_API2_STATUS(UpdateCUDAProviderOptionsWithValue, _Inout_ OrtCUDAProviderOptionsV2* cuda_options, _In_ const char* key, _In_ void* value); + + /** + * Get CUDA EP provider option where its data type is pointer. + * If the data type of the provider option can be represented by string please use GetCUDAProviderOptionsAsString. + * + * \param cuda_options - OrtCUDAProviderOptionsV2 instance + * \param key - Name of the provider option + * \param ptr - A pointer to the instance that is kept by the provider option + * + * \since Version 1.16. + */ + ORT_API2_STATUS(GetCUDAProviderOptionsByName, _In_ const OrtCUDAProviderOptionsV2* cuda_options, _In_ const char* key, _Outptr_ void** ptr); + + /** + * Get a EP resoure. + * E.g. a cuda stream or a cublas handle + * + * \param context - Kernel context + * \param resouce_version - Version of the resource + * \param resource_id - Type of resource + * \param resource - A pointer to returned resource + * + * \since Version 1.16. + */ + ORT_API2_STATUS(KernelContext_GetResource, _In_ const OrtKernelContext* context, _In_ int resouce_version, _In_ int resource_id, _Outptr_ void** resource); }; /* @@ -4218,7 +4443,10 @@ typedef enum OrtCustomOpInputOutputCharacteristic { struct OrtCustomOp { uint32_t version; // Must be initialized to ORT_API_VERSION - // This callback creates the kernel, which is a user defined parameter that is passed to the Kernel* callbacks below. + // This callback creates the kernel, which is a user defined + // parameter that is passed to the Kernel* callbacks below. It is + // recommended to use CreateKernelV2 which allows for a safe error + // propagation by returning an OrtStatusPtr. void*(ORT_API_CALL* CreateKernel)(_In_ const struct OrtCustomOp* op, _In_ const OrtApi* api, _In_ const OrtKernelInfo* info); @@ -4234,7 +4462,9 @@ struct OrtCustomOp { ONNXTensorElementDataType(ORT_API_CALL* GetOutputType)(_In_ const struct OrtCustomOp* op, _In_ size_t index); size_t(ORT_API_CALL* GetOutputTypeCount)(_In_ const struct OrtCustomOp* op); - // Op kernel callbacks + // Perform a computation step. It is recommended to use + // KernelComputeV2 which allows for a safe error propagation by + // returning an OrtStatusPtr. void(ORT_API_CALL* KernelCompute)(_In_ void* op_kernel, _In_ OrtKernelContext* context); void(ORT_API_CALL* KernelDestroy)(_In_ void* op_kernel); @@ -4266,6 +4496,14 @@ struct OrtCustomOp { // and false (zero) otherwise. // Applicable only for custom ops that have a variadic output. int(ORT_API_CALL* GetVariadicOutputHomogeneity)(_In_ const struct OrtCustomOp* op); + + // Create the kernel state which is passed to each compute call. + OrtStatusPtr(ORT_API_CALL* CreateKernelV2)(_In_ const struct OrtCustomOp* op, _In_ const OrtApi* api, + _In_ const OrtKernelInfo* info, + _Out_ void** kernel); + + // Perform the computation step. + OrtStatusPtr(ORT_API_CALL* KernelComputeV2)(_In_ void* op_kernel, _In_ OrtKernelContext* context); }; /* @@ -4276,6 +4514,16 @@ struct OrtCustomOp { */ ORT_API_STATUS(OrtSessionOptionsAppendExecutionProvider_CUDA, _In_ OrtSessionOptions* options, int device_id); +/* + * This is the old way to add the ROCm provider to the session, please use + * SessionOptionsAppendExecutionProvider_ROCM above to access the latest functionality + * This function always exists, but will only succeed if Onnxruntime was built with + * HIP support and the ROCm provider shared library exists + * + * \param device_id HIP device id, starts from zero. + */ +ORT_API_STATUS(OrtSessionOptionsAppendExecutionProvider_ROCM, _In_ OrtSessionOptions* options, int device_id); + /* * This is the old way to add the MIGraphX provider to the session, please use * SessionOptionsAppendExecutionProvider_MIGraphX above to access the latest functionality diff --git a/include/onnxruntime/core/session/onnxruntime_cxx_api.h b/include/onnxruntime/core/session/onnxruntime_cxx_api.h index 0c8170b7d6011..47356c3fe3608 100644 --- a/include/onnxruntime/core/session/onnxruntime_cxx_api.h +++ b/include/onnxruntime/core/session/onnxruntime_cxx_api.h @@ -24,6 +24,8 @@ #pragma once #include "onnxruntime_c_api.h" +#include "onnxruntime_float16.h" + #include #include #include @@ -127,6 +129,13 @@ inline const OrtApi& GetApi() noexcept { return *Global::api_; } /// version string major.minor.rev std::string GetVersionString(); +/// +/// This function returns the onnxruntime build information: including git branch, +/// git commit id, build type(Debug/Release/RelWithDebInfo) and cmake cpp flags. +/// +/// string +std::string GetBuildInfoString(); + /// /// This is a C++ wrapper for OrtApi::GetAvailableProviders() and /// returns a vector of strings representing the available execution providers. @@ -135,74 +144,358 @@ std::string GetVersionString(); std::vector GetAvailableProviders(); /** \brief IEEE 754 half-precision floating point data type - * \details It is necessary for type dispatching to make use of C++ API - * The type is implicitly convertible to/from uint16_t. - * The size of the structure should align with uint16_t and one can freely cast - * uint16_t buffers to/from Ort::Float16_t to feed and retrieve data. - * - * Generally, you can feed any of your types as float16/blfoat16 data to create a tensor - * on top of it, providing it can form a continuous buffer with 16-bit elements with no padding. - * And you can also feed a array of uint16_t elements directly. For example, * - * \code{.unparsed} - * uint16_t values[] = { 15360, 16384, 16896, 17408, 17664}; - * constexpr size_t values_length = sizeof(values) / sizeof(values[0]); - * std::vector dims = {values_length}; // one dimensional example - * Ort::MemoryInfo info("Cpu", OrtDeviceAllocator, 0, OrtMemTypeDefault); - * // Note we are passing bytes count in this api, not number of elements -> sizeof(values) - * auto float16_tensor = Ort::Value::CreateTensor(info, values, sizeof(values), - * dims.data(), dims.size(), ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16); - * \endcode + * \details This struct is used for converting float to float16 and back + * so the user could feed inputs and fetch outputs using these type. * - * Here is another example, a little bit more elaborate. Let's assume that you use your own float16 type and you want to use - * a templated version of the API above so the type is automatically set based on your type. You will need to supply an extra - * template specialization. + * The size of the structure should align with uint16_t and one can freely cast + * uint16_t buffers to/from Ort::Float16_t to feed and retrieve data. * * \code{.unparsed} - * namespace yours { struct half {}; } // assume this is your type, define this: - * namespace Ort { - * template<> - * struct TypeToTensorType { static constexpr ONNXTensorElementDataType type = ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16; }; - * } //namespace Ort + * // This example demonstrates converion from float to float16 + * constexpr float values[] = {1.f, 2.f, 3.f, 4.f, 5.f}; + * std::vector fp16_values; + * fp16_values.reserve(std::size(values)); + * std::transform(std::begin(values), std::end(values), std::back_inserter(fp16_values), + * [](float value) { return Ort::Float16_t(value); }); * - * std::vector values; - * std::vector dims = {values.size()}; // one dimensional example - * Ort::MemoryInfo info("Cpu", OrtDeviceAllocator, 0, OrtMemTypeDefault); - * // Here we are passing element count -> values.size() - * auto float16_tensor = Ort::Value::CreateTensor(info, values.data(), values.size(), dims.data(), dims.size()); - * - * \endcode + * \endcode */ -struct Float16_t { - uint16_t value; - constexpr Float16_t() noexcept : value(0) {} - constexpr Float16_t(uint16_t v) noexcept : value(v) {} - constexpr operator uint16_t() const noexcept { return value; } - constexpr bool operator==(const Float16_t& rhs) const noexcept { return value == rhs.value; }; - constexpr bool operator!=(const Float16_t& rhs) const noexcept { return value != rhs.value; }; +struct Float16_t : onnxruntime_float16::Float16Impl { + private: + /// + /// Constructor from a 16-bit representation of a float16 value + /// No conversion is done here. + /// + /// 16-bit representation + constexpr explicit Float16_t(uint16_t v) noexcept { val = v; } + + public: + using Base = onnxruntime_float16::Float16Impl; + + /// + /// Default constructor + /// + Float16_t() = default; + + /// + /// Explicit conversion to uint16_t representation of float16. + /// + /// uint16_t bit representation of float16 + /// new instance of Float16_t + constexpr static Float16_t FromBits(uint16_t v) noexcept { return Float16_t(v); } + + /// + /// __ctor from float. Float is converted into float16 16-bit representation. + /// + /// float value + explicit Float16_t(float v) noexcept { val = Base::ToUint16Impl(v); } + + /// + /// Converts float16 to float + /// + /// float representation of float16 value + float ToFloat() const noexcept { return Base::ToFloatImpl(); } + + /// + /// Checks if the value is negative + /// + /// true if negative + using Base::IsNegative; + + /// + /// Tests if the value is NaN + /// + /// true if NaN + using Base::IsNaN; + + /// + /// Tests if the value is finite + /// + /// true if finite + using Base::IsFinite; + + /// + /// Tests if the value represents positive infinity. + /// + /// true if positive infinity + using Base::IsPositiveInfinity; + + /// + /// Tests if the value represents negative infinity + /// + /// true if negative infinity + using Base::IsNegativeInfinity; + + /// + /// Tests if the value is either positive or negative infinity. + /// + /// True if absolute value is infinity + using Base::IsInfinity; + + /// + /// Tests if the value is NaN or zero. Useful for comparisons. + /// + /// True if NaN or zero. + using Base::IsNaNOrZero; + + /// + /// Tests if the value is normal (not zero, subnormal, infinite, or NaN). + /// + /// True if so + using Base::IsNormal; + + /// + /// Tests if the value is subnormal (denormal). + /// + /// True if so + using Base::IsSubnormal; + + /// + /// Creates an instance that represents absolute value. + /// + /// Absolute value + using Base::Abs; + + /// + /// Creates a new instance with the sign flipped. + /// + /// Flipped sign instance + using Base::Negate; + + /// + /// IEEE defines that positive and negative zero are equal, this gives us a quick equality check + /// for two values by or'ing the private bits together and stripping the sign. They are both zero, + /// and therefore equivalent, if the resulting value is still zero. + /// + /// first value + /// second value + /// True if both arguments represent zero + using Base::AreZero; + + /// + /// User defined conversion operator. Converts Float16_t to float. + /// + explicit operator float() const noexcept { return ToFloat(); } + + using Base::operator==; + using Base::operator!=; + using Base::operator<; }; static_assert(sizeof(Float16_t) == sizeof(uint16_t), "Sizes must match"); /** \brief bfloat16 (Brain Floating Point) data type - * \details It is necessary for type dispatching to make use of C++ API - * The type is implicitly convertible to/from uint16_t. + * + * \details This struct is used for converting float to bfloat16 and back + * so the user could feed inputs and fetch outputs using these type. + * * The size of the structure should align with uint16_t and one can freely cast * uint16_t buffers to/from Ort::BFloat16_t to feed and retrieve data. * - * See also code examples for Float16_t above. + * \code{.unparsed} + * // This example demonstrates converion from float to float16 + * constexpr float values[] = {1.f, 2.f, 3.f, 4.f, 5.f}; + * std::vector bfp16_values; + * bfp16_values.reserve(std::size(values)); + * std::transform(std::begin(values), std::end(values), std::back_inserter(bfp16_values), + * [](float value) { return Ort::BFloat16_t(value); }); + * + * \endcode */ -struct BFloat16_t { - uint16_t value; - constexpr BFloat16_t() noexcept : value(0) {} - constexpr BFloat16_t(uint16_t v) noexcept : value(v) {} - constexpr operator uint16_t() const noexcept { return value; } - constexpr bool operator==(const BFloat16_t& rhs) const noexcept { return value == rhs.value; }; - constexpr bool operator!=(const BFloat16_t& rhs) const noexcept { return value != rhs.value; }; +struct BFloat16_t : onnxruntime_float16::BFloat16Impl { + private: + /// + /// Constructor from a uint16_t representation of bfloat16 + /// used in FromBits() to escape overload resolution issue with + /// constructor from float. + /// No conversion is done. + /// + /// 16-bit bfloat16 value + constexpr explicit BFloat16_t(uint16_t v) noexcept { val = v; } + + public: + using Base = onnxruntime_float16::BFloat16Impl; + + BFloat16_t() = default; + + /// + /// Explicit conversion to uint16_t representation of bfloat16. + /// + /// uint16_t bit representation of bfloat16 + /// new instance of BFloat16_t + static constexpr BFloat16_t FromBits(uint16_t v) noexcept { return BFloat16_t(v); } + + /// + /// __ctor from float. Float is converted into bfloat16 16-bit representation. + /// + /// float value + explicit BFloat16_t(float v) noexcept { val = Base::ToUint16Impl(v); } + + /// + /// Converts bfloat16 to float + /// + /// float representation of bfloat16 value + float ToFloat() const noexcept { return Base::ToFloatImpl(); } + + /// + /// Checks if the value is negative + /// + /// true if negative + using Base::IsNegative; + + /// + /// Tests if the value is NaN + /// + /// true if NaN + using Base::IsNaN; + + /// + /// Tests if the value is finite + /// + /// true if finite + using Base::IsFinite; + + /// + /// Tests if the value represents positive infinity. + /// + /// true if positive infinity + using Base::IsPositiveInfinity; + + /// + /// Tests if the value represents negative infinity + /// + /// true if negative infinity + using Base::IsNegativeInfinity; + + /// + /// Tests if the value is either positive or negative infinity. + /// + /// True if absolute value is infinity + using Base::IsInfinity; + + /// + /// Tests if the value is NaN or zero. Useful for comparisons. + /// + /// True if NaN or zero. + using Base::IsNaNOrZero; + + /// + /// Tests if the value is normal (not zero, subnormal, infinite, or NaN). + /// + /// True if so + using Base::IsNormal; + + /// + /// Tests if the value is subnormal (denormal). + /// + /// True if so + using Base::IsSubnormal; + + /// + /// Creates an instance that represents absolute value. + /// + /// Absolute value + using Base::Abs; + + /// + /// Creates a new instance with the sign flipped. + /// + /// Flipped sign instance + using Base::Negate; + + /// + /// IEEE defines that positive and negative zero are equal, this gives us a quick equality check + /// for two values by or'ing the private bits together and stripping the sign. They are both zero, + /// and therefore equivalent, if the resulting value is still zero. + /// + /// first value + /// second value + /// True if both arguments represent zero + using Base::AreZero; + + /// + /// User defined conversion operator. Converts BFloat16_t to float. + /// + explicit operator float() const noexcept { return ToFloat(); } + + // We do not have an inherited impl for the below operators + // as the internal class implements them a little differently + bool operator==(const BFloat16_t& rhs) const noexcept; + bool operator!=(const BFloat16_t& rhs) const noexcept { return !(*this == rhs); } + bool operator<(const BFloat16_t& rhs) const noexcept; }; static_assert(sizeof(BFloat16_t) == sizeof(uint16_t), "Sizes must match"); +/** \brief float8e4m3fn (Float8 Floating Point) data type + * \details It is necessary for type dispatching to make use of C++ API + * The type is implicitly convertible to/from uint8_t. + * See https://onnx.ai/onnx/technical/float8.html for further details. + */ +struct Float8E4M3FN_t { + uint8_t value; + constexpr Float8E4M3FN_t() noexcept : value(0) {} + constexpr Float8E4M3FN_t(uint8_t v) noexcept : value(v) {} + constexpr operator uint8_t() const noexcept { return value; } + // nan values are treated like any other value for operator ==, != + constexpr bool operator==(const Float8E4M3FN_t& rhs) const noexcept { return value == rhs.value; }; + constexpr bool operator!=(const Float8E4M3FN_t& rhs) const noexcept { return value != rhs.value; }; +}; + +static_assert(sizeof(Float8E4M3FN_t) == sizeof(uint8_t), "Sizes must match"); + +/** \brief float8e4m3fnuz (Float8 Floating Point) data type + * \details It is necessary for type dispatching to make use of C++ API + * The type is implicitly convertible to/from uint8_t. + * See https://onnx.ai/onnx/technical/float8.html for further details. + */ +struct Float8E4M3FNUZ_t { + uint8_t value; + constexpr Float8E4M3FNUZ_t() noexcept : value(0) {} + constexpr Float8E4M3FNUZ_t(uint8_t v) noexcept : value(v) {} + constexpr operator uint8_t() const noexcept { return value; } + // nan values are treated like any other value for operator ==, != + constexpr bool operator==(const Float8E4M3FNUZ_t& rhs) const noexcept { return value == rhs.value; }; + constexpr bool operator!=(const Float8E4M3FNUZ_t& rhs) const noexcept { return value != rhs.value; }; +}; + +static_assert(sizeof(Float8E4M3FNUZ_t) == sizeof(uint8_t), "Sizes must match"); + +/** \brief float8e5m2 (Float8 Floating Point) data type + * \details It is necessary for type dispatching to make use of C++ API + * The type is implicitly convertible to/from uint8_t. + * See https://onnx.ai/onnx/technical/float8.html for further details. + */ +struct Float8E5M2_t { + uint8_t value; + constexpr Float8E5M2_t() noexcept : value(0) {} + constexpr Float8E5M2_t(uint8_t v) noexcept : value(v) {} + constexpr operator uint8_t() const noexcept { return value; } + // nan values are treated like any other value for operator ==, != + constexpr bool operator==(const Float8E5M2_t& rhs) const noexcept { return value == rhs.value; }; + constexpr bool operator!=(const Float8E5M2_t& rhs) const noexcept { return value != rhs.value; }; +}; + +static_assert(sizeof(Float8E5M2_t) == sizeof(uint8_t), "Sizes must match"); + +/** \brief float8e5m2fnuz (Float8 Floating Point) data type + * \details It is necessary for type dispatching to make use of C++ API + * The type is implicitly convertible to/from uint8_t. + * See https://onnx.ai/onnx/technical/float8.html for further details. + */ +struct Float8E5M2FNUZ_t { + uint8_t value; + constexpr Float8E5M2FNUZ_t() noexcept : value(0) {} + constexpr Float8E5M2FNUZ_t(uint8_t v) noexcept : value(v) {} + constexpr operator uint8_t() const noexcept { return value; } + // nan values are treated like any other value for operator ==, != + constexpr bool operator==(const Float8E5M2FNUZ_t& rhs) const noexcept { return value == rhs.value; }; + constexpr bool operator!=(const Float8E5M2FNUZ_t& rhs) const noexcept { return value != rhs.value; }; +}; + +static_assert(sizeof(Float8E5M2FNUZ_t) == sizeof(uint8_t), "Sizes must match"); + namespace detail { // This is used internally by the C++ API. This macro is to make it easy to generate overloaded methods for all of the various OrtRelease* functions for every Ort* type // This can't be done in the C API since C doesn't have function overloading. @@ -426,6 +719,8 @@ struct Env : detail::Base { Env& UpdateEnvWithCustomLogLevel(OrtLoggingLevel log_severity_level); ///< Wraps OrtApi::UpdateEnvWithCustomLogLevel Env& CreateAndRegisterAllocator(const OrtMemoryInfo* mem_info, const OrtArenaCfg* arena_cfg); ///< Wraps OrtApi::CreateAndRegisterAllocator + + Env& CreateAndRegisterAllocatorV2(const std::string& provider_type, const OrtMemoryInfo* mem_info, const std::unordered_map& options, const OrtArenaCfg* arena_cfg); ///< Wraps OrtApi::CreateAndRegisterAllocatorV2 }; /** \brief Custom Op Domain @@ -772,6 +1067,28 @@ struct SessionImpl : ConstSessionImpl { void Run(const RunOptions& run_options, const IoBinding&); ///< Wraps OrtApi::RunWithBinding + /** \brief Run the model asynchronously in a thread owned by intra op thread pool + * + * Wraps OrtApi::RunAsync + * + * \param[in] run_options + * \param[in] input_names Array of null terminated UTF8 encoded strings of the input names + * \param[in] input_values Array of Value objects of length input_count + * \param[in] input_count Number of elements in the input_names and inputs arrays + * \param[in] output_names Array of null terminated UTF8 encoded strings of the output names + * \param[out] output_values Array of provided Values to be filled with outputs. + * On calling RunAsync, output_values[i] could either be initialized by a null pointer or a preallocated OrtValue*. + * Later, on invoking the callback, each output_values[i] of null will be filled with an OrtValue* allocated by onnxruntime. + * Then, an OrtValue** pointer will be casted from output_values, and pass to the callback. + * NOTE: it is customer's duty to finally release output_values and each of its member, + * regardless of whether the member (Ort::Value) is allocated by onnxruntime or preallocated by the customer. + * \param[in] output_count Number of elements in the output_names and outputs array + * \param[in] callback Callback function on model run completion + * \param[in] user_data User data that pass back to the callback + */ + void RunAsync(const RunOptions& run_options, const char* const* input_names, const Value* input_values, size_t input_count, + const char* const* output_names, Value* output_values, size_t output_count, RunAsyncCallbackFn callback, void* user_data); + /** \brief End profiling and return a copy of the profiling file name. * * \param allocator to allocate memory for the copy of the string returned @@ -1310,6 +1627,7 @@ struct Value : detail::ValueImpl { 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. + * * \param info Memory description of where the p_data buffer resides (CPU vs GPU etc). * \param p_data Pointer to the data buffer. * \param p_data_byte_count The number of bytes in the data buffer. @@ -1320,7 +1638,12 @@ struct Value : detail::ValueImpl { 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 using a supplied OrtAllocator. Wraps OrtApi::CreateTensorAsOrtValue. + /** \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. + * 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. + * * \tparam T The numeric datatype. This API is not suitable for strings. * \param allocator The allocator to use. * \param shape Pointer to the tensor shape dimensions. @@ -1329,7 +1652,12 @@ struct Value : detail::ValueImpl { template static Value CreateTensor(OrtAllocator* allocator, const int64_t* shape, size_t shape_len); - /** \brief Creates a tensor using a supplied OrtAllocator. Wraps OrtApi::CreateTensorAsOrtValue. + /** \brief Creates an OrtValue with a tensor using the supplied OrtAllocator. + * Wraps OrtApi::CreateTensorAsOrtValue. + * 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. + * * \param allocator The allocator to use. * \param shape Pointer to the tensor shape dimensions. * \param shape_len The number of tensor shape dimensions. @@ -1337,11 +1665,35 @@ struct Value : detail::ValueImpl { */ static Value CreateTensor(OrtAllocator* allocator, const int64_t* shape, size_t shape_len, ONNXTensorElementDataType type); - static Value CreateMap(Value& keys, Value& values); ///< Wraps OrtApi::CreateValue - static Value CreateSequence(std::vector& values); ///< Wraps OrtApi::CreateValue + /** \brief Creates an OrtValue with a Map Onnx type representation. + * The API would ref-count the supplied OrtValues and they will be released + * when the returned OrtValue is released. The caller may release keys and values after the call + * returns. + * + * \param keys an OrtValue containing a tensor with primitive data type keys. + * \param values an OrtValue that may contain a tensor. Ort currently supports only primitive data type values. + */ + static Value CreateMap(const Value& keys, const Value& values); ///< Wraps OrtApi::CreateValue + + /** \brief Creates an OrtValue with a Sequence Onnx type representation. + * The API would ref-count the supplied OrtValues and they will be released + * when the returned OrtValue is released. The caller may release the values after the call + * returns. + * + * \param values a vector of OrtValues that must have the same Onnx value type. + */ + static Value CreateSequence(const std::vector& values); ///< Wraps OrtApi::CreateValue + /** \brief Creates an OrtValue wrapping an Opaque type. + * This is used for experimental support of non-tensor types. + * + * \tparam T - the type of the value. + * \param domain - zero terminated utf-8 string. Domain of the type. + * \param type_name - zero terminated utf-8 string. Name of the type. + * \param value - the value to be wrapped. + */ template - static Value CreateOpaque(const char* domain, const char* type_name, const T&); ///< Wraps OrtApi::CreateOpaqueValue + static Value CreateOpaque(const char* domain, const char* type_name, const T& value); ///< Wraps OrtApi::CreateOpaqueValue #if !defined(DISABLE_SPARSE_TENSORS) /// @@ -1803,196 +2155,10 @@ struct Op : detail::Base { size_t output_count); }; -/// -/// This entire structure is deprecated, but we not marking -/// it as a whole yet since we want to preserve for the next release. -/// -struct CustomOpApi { - CustomOpApi(const OrtApi& api) : api_(api) {} - - /** \deprecated use Ort::Value::GetTensorTypeAndShape() - * [[deprecated]] - * This interface produces a pointer that must be released. Not exception safe. - */ - [[deprecated("use Ort::Value::GetTensorTypeAndShape()")]] OrtTensorTypeAndShapeInfo* GetTensorTypeAndShape(_In_ const OrtValue* value); - - /** \deprecated use Ort::TensorTypeAndShapeInfo::GetElementCount() - * [[deprecated]] - * This interface is redundant. - */ - [[deprecated("use Ort::TensorTypeAndShapeInfo::GetElementCount()")]] size_t GetTensorShapeElementCount(_In_ const OrtTensorTypeAndShapeInfo* info); - - /** \deprecated use Ort::TensorTypeAndShapeInfo::GetElementType() - * [[deprecated]] - * This interface is redundant. - */ - [[deprecated("use Ort::TensorTypeAndShapeInfo::GetElementType()")]] ONNXTensorElementDataType GetTensorElementType(const OrtTensorTypeAndShapeInfo* info); - - /** \deprecated use Ort::TensorTypeAndShapeInfo::GetDimensionsCount() - * [[deprecated]] - * This interface is redundant. - */ - [[deprecated("use Ort::TensorTypeAndShapeInfo::GetDimensionsCount()")]] size_t GetDimensionsCount(_In_ const OrtTensorTypeAndShapeInfo* info); - - /** \deprecated use Ort::TensorTypeAndShapeInfo::GetShape() - * [[deprecated]] - * This interface is redundant. - */ - [[deprecated("use Ort::TensorTypeAndShapeInfo::GetShape()")]] void GetDimensions(_In_ const OrtTensorTypeAndShapeInfo* info, _Out_ int64_t* dim_values, size_t dim_values_length); - - /** \deprecated - * [[deprecated]] - * This interface sets dimensions to TensorTypeAndShapeInfo, but has no effect on the OrtValue. - */ - [[deprecated("Do not use")]] void SetDimensions(OrtTensorTypeAndShapeInfo* info, _In_ const int64_t* dim_values, size_t dim_count); - - /** \deprecated use Ort::Value::GetTensorMutableData() - * [[deprecated]] - * This interface is redundant. - */ - template - [[deprecated("use Ort::Value::GetTensorMutableData()")]] T* GetTensorMutableData(_Inout_ OrtValue* value); - - /** \deprecated use Ort::Value::GetTensorData() - * [[deprecated]] - * This interface is redundant. - */ - template - [[deprecated("use Ort::Value::GetTensorData()")]] const T* GetTensorData(_Inout_ const OrtValue* value); - - /** \deprecated use Ort::Value::GetTensorMemoryInfo() - * [[deprecated]] - * This interface is redundant. - */ - [[deprecated("use Ort::Value::GetTensorMemoryInfo()")]] const OrtMemoryInfo* GetTensorMemoryInfo(_In_ const OrtValue* value); - - /** \deprecated use Ort::TensorTypeAndShapeInfo::GetShape() - * [[deprecated]] - * This interface is redundant. - */ - [[deprecated("use Ort::TensorTypeAndShapeInfo::GetShape()")]] std::vector GetTensorShape(const OrtTensorTypeAndShapeInfo* info); - - /** \deprecated use TensorTypeAndShapeInfo instances for automatic ownership. - * [[deprecated]] - * This interface is not exception safe. - */ - [[deprecated("use TensorTypeAndShapeInfo")]] void ReleaseTensorTypeAndShapeInfo(OrtTensorTypeAndShapeInfo* input); - - /** \deprecated use Ort::KernelContext::GetInputCount - * [[deprecated]] - * This interface is redundant. - */ - [[deprecated("use Ort::KernelContext::GetInputCount")]] size_t KernelContext_GetInputCount(const OrtKernelContext* context); - - /** \deprecated use Ort::KernelContext::GetInput - * [[deprecated]] - * This interface is redundant. - */ - [[deprecated("use Ort::KernelContext::GetInput")]] const OrtValue* KernelContext_GetInput(const OrtKernelContext* context, _In_ size_t index); - - /** \deprecated use Ort::KernelContext::GetOutputCount - * [[deprecated]] - * This interface is redundant. - */ - [[deprecated("use Ort::KernelContext::GetOutputCount")]] size_t KernelContext_GetOutputCount(const OrtKernelContext* context); - - /** \deprecated use Ort::KernelContext::GetOutput - * [[deprecated]] - * This interface is redundant. - */ - [[deprecated("use Ort::KernelContext::GetOutput")]] OrtValue* KernelContext_GetOutput(OrtKernelContext* context, _In_ size_t index, _In_ const int64_t* dim_values, size_t dim_count); - - /** \deprecated use Ort::KernelContext::GetGPUComputeStream - * [[deprecated]] - * This interface is redundant. - */ - [[deprecated("use Ort::KernelContext::GetGPUComputeStream")]] void* KernelContext_GetGPUComputeStream(const OrtKernelContext* context); - - /** \deprecated use Ort::ThrowOnError() - * [[deprecated]] - * This interface is redundant. - */ - [[deprecated("use Ort::ThrowOnError()")]] void ThrowOnError(OrtStatus* result); - - /** \deprecated use Ort::OpAttr - * [[deprecated]] - * This interface is not exception safe. - */ - [[deprecated("use Ort::OpAttr")]] OrtOpAttr* CreateOpAttr(_In_ const char* name, - _In_ const void* data, - _In_ int len, - _In_ OrtOpAttrType type); - - /** \deprecated use Ort::OpAttr - * [[deprecated]] - * This interface is not exception safe. - */ - [[deprecated("use Ort::OpAttr")]] void ReleaseOpAttr(_Frees_ptr_opt_ OrtOpAttr* op_attr); - - /** \deprecated use Ort::Op - * [[deprecated]] - * This interface is not exception safe. - */ - [[deprecated("use Ort::Op")]] OrtOp* CreateOp(_In_ const OrtKernelInfo* info, - _In_ const char* op_name, - _In_ const char* domain, - _In_ int version, - _In_opt_ const char** type_constraint_names, - _In_opt_ const ONNXTensorElementDataType* type_constraint_values, - _In_opt_ int type_constraint_count, - _In_opt_ const OrtOpAttr* const* attr_values, - _In_opt_ int attr_count, - _In_ int input_count, - _In_ int output_count); - - /** \deprecated use Ort::Op::Invoke - * [[deprecated]] - * This interface is redundant - */ - [[deprecated("use Ort::Op::Invoke")]] void InvokeOp(_In_ const OrtKernelContext* context, - _In_ const OrtOp* ort_op, - _In_ const OrtValue* const* input_values, - _In_ int input_count, - _Inout_ OrtValue* const* output_values, - _In_ int output_count); - - /** \deprecated use Ort::Op for automatic lifespan management. - * [[deprecated]] - * This interface is not exception safe. - */ - [[deprecated("use Ort::Op")]] void ReleaseOp(_Frees_ptr_opt_ OrtOp* ort_op); - - /** \deprecated use Ort::KernelInfo for automatic lifespan management or for - * querying attributes - * [[deprecated]] - * This interface is redundant - */ - template // T is only implemented for std::vector, std::vector, float, int64_t, and string - [[deprecated("use Ort::KernelInfo::GetAttribute")]] T KernelInfoGetAttribute(_In_ const OrtKernelInfo* info, _In_ const char* name); - - /** \deprecated use Ort::KernelInfo::Copy - * querying attributes - * [[deprecated]] - * This interface is not exception safe - */ - [[deprecated("use Ort::KernelInfo::Copy")]] OrtKernelInfo* CopyKernelInfo(_In_ const OrtKernelInfo* info); - - /** \deprecated use Ort::KernelInfo for lifespan management - * querying attributes - * [[deprecated]] - * This interface is not exception safe - */ - [[deprecated("use Ort::KernelInfo")]] void ReleaseKernelInfo(_Frees_ptr_opt_ OrtKernelInfo* info_copy); - - private: - const OrtApi& api_; -}; - -template +template struct CustomOpBase : OrtCustomOp { CustomOpBase() { OrtCustomOp::version = ORT_API_VERSION; - OrtCustomOp::CreateKernel = [](const OrtCustomOp* this_, const OrtApi* api, const OrtKernelInfo* info) { return static_cast(this_)->CreateKernel(*api, info); }; OrtCustomOp::GetName = [](const OrtCustomOp* this_) { return static_cast(this_)->GetName(); }; OrtCustomOp::GetExecutionProviderType = [](const OrtCustomOp* this_) { return static_cast(this_)->GetExecutionProviderType(); }; @@ -2004,7 +2170,6 @@ struct CustomOpBase : OrtCustomOp { OrtCustomOp::GetOutputTypeCount = [](const OrtCustomOp* this_) { return static_cast(this_)->GetOutputTypeCount(); }; OrtCustomOp::GetOutputType = [](const OrtCustomOp* this_, size_t index) { return static_cast(this_)->GetOutputType(index); }; - OrtCustomOp::KernelCompute = [](void* op_kernel, OrtKernelContext* context) { static_cast(op_kernel)->Compute(context); }; #if defined(_MSC_VER) && !defined(__clang__) #pragma warning(push) #pragma warning(disable : 26409) @@ -2020,6 +2185,26 @@ struct CustomOpBase : OrtCustomOp { OrtCustomOp::GetVariadicInputHomogeneity = [](const OrtCustomOp* this_) { return static_cast(static_cast(this_)->GetVariadicInputHomogeneity()); }; OrtCustomOp::GetVariadicOutputMinArity = [](const OrtCustomOp* this_) { return static_cast(this_)->GetVariadicOutputMinArity(); }; OrtCustomOp::GetVariadicOutputHomogeneity = [](const OrtCustomOp* this_) { return static_cast(static_cast(this_)->GetVariadicOutputHomogeneity()); }; +#ifdef __cpp_if_constexpr + if constexpr (WithStatus) { +#else + if (WithStatus) { +#endif + OrtCustomOp::CreateKernelV2 = [](const OrtCustomOp* this_, const OrtApi* api, const OrtKernelInfo* info, void** op_kernel) -> OrtStatusPtr { + return static_cast(this_)->CreateKernelV2(*api, info, op_kernel); + }; + OrtCustomOp::KernelComputeV2 = [](void* op_kernel, OrtKernelContext* context) -> OrtStatusPtr { + return static_cast(op_kernel)->ComputeV2(context); + }; + } else { + OrtCustomOp::CreateKernelV2 = nullptr; + OrtCustomOp::KernelComputeV2 = nullptr; + + OrtCustomOp::CreateKernel = [](const OrtCustomOp* this_, const OrtApi* api, const OrtKernelInfo* info) { return static_cast(this_)->CreateKernel(*api, info); }; + OrtCustomOp::KernelCompute = [](void* op_kernel, OrtKernelContext* context) { + static_cast(op_kernel)->Compute(context); + }; + } } // Default implementation of GetExecutionProviderType that returns nullptr to default to the CPU provider diff --git a/include/onnxruntime/core/session/onnxruntime_cxx_inline.h b/include/onnxruntime/core/session/onnxruntime_cxx_inline.h index 25dd033369ca1..22172832cde8e 100644 --- a/include/onnxruntime/core/session/onnxruntime_cxx_inline.h +++ b/include/onnxruntime/core/session/onnxruntime_cxx_inline.h @@ -7,6 +7,8 @@ // These are the inline implementations of the C++ header APIs. They're in this separate file as to not clutter // the main C++ file with implementation details. +#include + namespace Ort { namespace detail { @@ -114,6 +116,47 @@ struct TypeToTensorType { static constexpr ONNXTensorElementDataType type = ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL; }; +template <> +struct TypeToTensorType { + static constexpr ONNXTensorElementDataType type = ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FN; +}; +template <> +struct TypeToTensorType { + static constexpr ONNXTensorElementDataType type = ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FNUZ; +}; +template <> +struct TypeToTensorType { + static constexpr ONNXTensorElementDataType type = ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2; +}; +template <> +struct TypeToTensorType { + static constexpr ONNXTensorElementDataType type = ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2FNUZ; +}; + +inline bool BFloat16_t::operator==(const BFloat16_t& rhs) const noexcept { + if (IsNaN() || rhs.IsNaN()) { + // IEEE defines that NaN is not equal to anything, including itself. + return false; + } + return val == rhs.val; +} + +inline bool BFloat16_t::operator<(const BFloat16_t& rhs) const noexcept { + if (IsNaN() || rhs.IsNaN()) { + // IEEE defines that NaN is unordered with respect to everything, including itself. + return false; + } + + const bool left_is_negative = IsNegative(); + if (left_is_negative != rhs.IsNegative()) { + // When the signs of left and right differ, we know that left is less than right if it is + // the negative value. The exception to this is if both values are zero, in which case IEEE + // says they should be equal, even if the signs differ. + return left_is_negative && !AreZero(*this, rhs); + } + return (val != rhs.val) && ((val < rhs.val) ^ left_is_negative); +} + inline MemoryAllocation::MemoryAllocation(OrtAllocator* allocator, void* p, size_t size) : allocator_(allocator), p_(p), size_(size) { } @@ -472,6 +515,21 @@ inline Env& Env::CreateAndRegisterAllocator(const OrtMemoryInfo* mem_info, const return *this; } +inline Env& Env::CreateAndRegisterAllocatorV2(const std::string& provider_type, const OrtMemoryInfo* mem_info, const std::unordered_map& options, const OrtArenaCfg* arena_cfg) { + std::vector keys, values; + auto num_entries = options.size(); + if (num_entries > 0) { + keys.reserve(num_entries); + values.reserve(num_entries); + for (const auto& entry : options) { + keys.push_back(entry.first.c_str()); + values.push_back(entry.second.c_str()); + } + } + ThrowOnError(GetApi().CreateAndRegisterAllocatorV2(p_, provider_type.c_str(), mem_info, arena_cfg, keys.data(), values.data(), num_entries)); + return *this; +} + inline CustomOpDomain::CustomOpDomain(const char* domain) { ThrowOnError(GetApi().CreateCustomOpDomain(domain, &p_)); } @@ -914,6 +972,16 @@ inline void SessionImpl::Run(const RunOptions& run_options, const IoBinding& ThrowOnError(GetApi().RunWithBinding(this->p_, run_options, io_binding)); } +template +inline void SessionImpl::RunAsync(const RunOptions& run_options, const char* const* input_names, const Value* input_values, size_t input_count, + const char* const* output_names, Value* output_values, size_t output_count, RunAsyncCallbackFn callback, void* user_data) { + auto ort_input_values = reinterpret_cast(input_values); + auto ort_output_values = reinterpret_cast(output_values); + ThrowOnError(GetApi().RunAsync(this->p_, run_options, input_names, + ort_input_values, input_count, output_names, output_count, + ort_output_values, callback, user_data)); +} + template inline AllocatedStringPtr SessionImpl::EndProfilingAllocated(OrtAllocator* allocator) { char* out = nullptr; @@ -1434,16 +1502,16 @@ inline Value Value::CreateSparseTensor(OrtAllocator* allocator, const Shape& den } #endif // !defined(DISABLE_SPARSE_TENSORS) -inline Value Value::CreateMap(Value& keys, Value& values) { +inline Value Value::CreateMap(const Value& keys, const Value& values) { OrtValue* out; - OrtValue* inputs[2] = {keys, values}; + const OrtValue* inputs[2] = {keys, values}; ThrowOnError(GetApi().CreateValue(inputs, 2, ONNX_TYPE_MAP, &out)); return Value{out}; } -inline Value Value::CreateSequence(std::vector& values) { +inline Value Value::CreateSequence(const std::vector& values) { OrtValue* out; - std::vector values_ort{values.data(), values.data() + values.size()}; + std::vector values_ort{values.data(), values.data() + values.size()}; ThrowOnError(GetApi().CreateValue(values_ort.data(), values_ort.size(), ONNX_TYPE_SEQUENCE, &out)); return Value{out}; } @@ -1770,226 +1838,12 @@ inline void Op::Invoke(const OrtKernelContext* context, output_values, static_cast(output_count))); } -inline void CustomOpApi::ThrowOnError(OrtStatus* status) { - Ort::ThrowOnError(status); -} - -template <> -inline float CustomOpApi::KernelInfoGetAttribute(_In_ const OrtKernelInfo* info, _In_ const char* name) { - float out; - Ort::ThrowOnError(api_.KernelInfoGetAttribute_float(info, name, &out)); - return out; -} - -template <> -inline int64_t CustomOpApi::KernelInfoGetAttribute(_In_ const OrtKernelInfo* info, _In_ const char* name) { - int64_t out; - Ort::ThrowOnError(api_.KernelInfoGetAttribute_int64(info, name, &out)); - return out; -} - -template <> -inline std::string CustomOpApi::KernelInfoGetAttribute(_In_ const OrtKernelInfo* info, _In_ const char* name) { - size_t size = 0; - std::string out; - - // Feed nullptr for the data buffer to query the true size of the string attribute - OrtStatus* status = api_.KernelInfoGetAttribute_string(info, name, nullptr, &size); - - if (status == nullptr) { - out.resize(size); - Ort::ThrowOnError(api_.KernelInfoGetAttribute_string(info, name, &out[0], &size)); - out.resize(size - 1); // remove the terminating character '\0' - } else { - Ort::ThrowOnError(status); - } - return out; -} - -template <> -inline std::vector CustomOpApi::KernelInfoGetAttribute(_In_ const OrtKernelInfo* info, _In_ const char* name) { - size_t size = 0; - std::vector out; - - // Feed nullptr for the data buffer to query the true size of the attribute - OrtStatus* status = api_.KernelInfoGetAttributeArray_float(info, name, nullptr, &size); - - if (status == nullptr) { - out.resize(size); - Ort::ThrowOnError(api_.KernelInfoGetAttributeArray_float(info, name, out.data(), &size)); - } else { - Ort::ThrowOnError(status); - } - return out; -} - -template <> -inline std::vector CustomOpApi::KernelInfoGetAttribute(_In_ const OrtKernelInfo* info, _In_ const char* name) { - size_t size = 0; - std::vector out; - - // Feed nullptr for the data buffer to query the true size of the attribute - OrtStatus* status = api_.KernelInfoGetAttributeArray_int64(info, name, nullptr, &size); - - if (status == nullptr) { - out.resize(size); - Ort::ThrowOnError(api_.KernelInfoGetAttributeArray_int64(info, name, out.data(), &size)); - } else { - Ort::ThrowOnError(status); - } - return out; -} -inline OrtTensorTypeAndShapeInfo* CustomOpApi::GetTensorTypeAndShape(_In_ const OrtValue* value) { - OrtTensorTypeAndShapeInfo* out; - Ort::ThrowOnError(api_.GetTensorTypeAndShape(value, &out)); - return out; -} - -inline size_t CustomOpApi::GetTensorShapeElementCount(_In_ const OrtTensorTypeAndShapeInfo* info) { - size_t out; - Ort::ThrowOnError(api_.GetTensorShapeElementCount(info, &out)); - return out; -} - -inline ONNXTensorElementDataType CustomOpApi::GetTensorElementType(const OrtTensorTypeAndShapeInfo* info) { - ONNXTensorElementDataType out; - Ort::ThrowOnError(api_.GetTensorElementType(info, &out)); - return out; -} - -inline size_t CustomOpApi::GetDimensionsCount(_In_ const OrtTensorTypeAndShapeInfo* info) { - size_t out; - Ort::ThrowOnError(api_.GetDimensionsCount(info, &out)); - return out; -} - -inline void CustomOpApi::GetDimensions(_In_ const OrtTensorTypeAndShapeInfo* info, _Out_ int64_t* dim_values, size_t dim_values_length) { - Ort::ThrowOnError(api_.GetDimensions(info, dim_values, dim_values_length)); -} - -inline void CustomOpApi::SetDimensions(OrtTensorTypeAndShapeInfo* info, _In_ const int64_t* dim_values, size_t dim_count) { - Ort::ThrowOnError(api_.SetDimensions(info, dim_values, dim_count)); -} - -template -inline T* CustomOpApi::GetTensorMutableData(_Inout_ OrtValue* value) { - T* data; - Ort::ThrowOnError(api_.GetTensorMutableData(value, reinterpret_cast(&data))); - return data; -} - -inline const OrtMemoryInfo* CustomOpApi::GetTensorMemoryInfo(_In_ const OrtValue* value) { - const OrtMemoryInfo* mem_info; - Ort::ThrowOnError(api_.GetTensorMemoryInfo(value, &mem_info)); - return mem_info; -} - -template -inline const T* CustomOpApi::GetTensorData(_Inout_ const OrtValue* value) { - T* data = nullptr; - Ort::ThrowOnError(api_.GetTensorMutableData(const_cast(value), reinterpret_cast(&data))); - return data; -} - -inline std::vector CustomOpApi::GetTensorShape(const OrtTensorTypeAndShapeInfo* info) { - size_t out; - Ort::ThrowOnError(api_.GetDimensionsCount(info, &out)); - std::vector output(out); - Ort::ThrowOnError(api_.GetDimensions(info, output.data(), out)); - return output; -} - -inline void CustomOpApi::ReleaseTensorTypeAndShapeInfo(OrtTensorTypeAndShapeInfo* input) { - api_.ReleaseTensorTypeAndShapeInfo(input); -} - -inline size_t CustomOpApi::KernelContext_GetInputCount(const OrtKernelContext* context) { - size_t out; - Ort::ThrowOnError(api_.KernelContext_GetInputCount(context, &out)); - return out; -} - -inline const OrtValue* CustomOpApi::KernelContext_GetInput(const OrtKernelContext* context, _In_ size_t index) { - const OrtValue* out; - Ort::ThrowOnError(api_.KernelContext_GetInput(context, index, &out)); - return out; -} - -inline size_t CustomOpApi::KernelContext_GetOutputCount(const OrtKernelContext* context) { - size_t out; - Ort::ThrowOnError(api_.KernelContext_GetOutputCount(context, &out)); - return out; -} - -inline OrtValue* CustomOpApi::KernelContext_GetOutput(OrtKernelContext* context, _In_ size_t index, - _In_ const int64_t* dim_values, size_t dim_count) { - OrtValue* out; - Ort::ThrowOnError(api_.KernelContext_GetOutput(context, index, dim_values, dim_count, &out)); - return out; -} - -inline void* CustomOpApi::KernelContext_GetGPUComputeStream(const OrtKernelContext* context) { - void* out; - Ort::ThrowOnError(api_.KernelContext_GetGPUComputeStream(context, &out)); - return out; -} - -inline OrtOpAttr* CustomOpApi::CreateOpAttr(_In_ const char* name, - _In_ const void* data, - _In_ int len, - _In_ OrtOpAttrType type) { - OrtOpAttr* op_attr{}; - Ort::ThrowOnError(api_.CreateOpAttr(name, data, len, type, &op_attr)); - return op_attr; -} - -inline void CustomOpApi::ReleaseOpAttr(_Frees_ptr_opt_ OrtOpAttr* op_attr) { - api_.ReleaseOpAttr(op_attr); -} - -inline OrtOp* CustomOpApi::CreateOp(_In_ const OrtKernelInfo* info, - _In_ const char* op_name, - _In_ const char* domain, - _In_ int version, - _In_opt_ const char** type_constraint_names, - _In_opt_ const ONNXTensorElementDataType* type_constraint_values, - _In_opt_ int type_constraint_count, - _In_opt_ const OrtOpAttr* const* attr_values, - _In_opt_ int attr_count, - _In_ int input_count, - _In_ int output_count) { - OrtOp* ort_op{}; - Ort::ThrowOnError(api_.CreateOp(info, op_name, domain, version, type_constraint_names, type_constraint_values, - type_constraint_count, attr_values, attr_count, input_count, output_count, &ort_op)); - return ort_op; -} - -inline void CustomOpApi::InvokeOp(_In_ const OrtKernelContext* context, - _In_ const OrtOp* ort_op, - _In_ const OrtValue* const* input_values, - _In_ int input_count, - _Inout_ OrtValue* const* output_values, - _In_ int output_count) { - Ort::ThrowOnError(api_.InvokeOp(context, ort_op, input_values, input_count, output_values, output_count)); -} - -inline void CustomOpApi::ReleaseOp(_Frees_ptr_opt_ OrtOp* ort_op) { - api_.ReleaseOp(ort_op); -} - -inline OrtKernelInfo* CustomOpApi::CopyKernelInfo(_In_ const OrtKernelInfo* info) { - OrtKernelInfo* info_copy{}; - Ort::ThrowOnError(api_.CopyKernelInfo(info, &info_copy)); - return info_copy; -} - -inline void CustomOpApi::ReleaseKernelInfo(_Frees_ptr_opt_ OrtKernelInfo* info_copy) { - api_.ReleaseKernelInfo(info_copy); +inline std::string GetVersionString() { + return OrtGetApiBase()->GetVersionString(); } -inline std::string GetVersionString() { - std::string result = OrtGetApiBase()->GetVersionString(); - return result; +inline std::string GetBuildInfoString() { + return GetApi().GetBuildInfoString(); } inline std::vector GetAvailableProviders() { @@ -2011,9 +1865,9 @@ inline std::vector GetAvailableProviders() { return available_providers; } -template -void CustomOpBase::GetSessionConfigs(std::unordered_map& out, - ConstSessionOptions options) const { +template +void CustomOpBase::GetSessionConfigs(std::unordered_map& out, + ConstSessionOptions options) const { const TOp* derived = static_cast(this); std::vector keys = derived->GetSessionConfigKeys(); diff --git a/include/onnxruntime/core/session/onnxruntime_float16.h b/include/onnxruntime/core/session/onnxruntime_float16.h new file mode 100644 index 0000000000000..0b066a9cc9ad1 --- /dev/null +++ b/include/onnxruntime/core/session/onnxruntime_float16.h @@ -0,0 +1,540 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include +#include +#include +#include + +namespace onnxruntime_float16 { + +namespace detail { + +enum class endian { +#if defined(_WIN32) + little = 0, + big = 1, + native = little, +#elif defined(__GNUC__) || defined(__clang__) + little = __ORDER_LITTLE_ENDIAN__, + big = __ORDER_BIG_ENDIAN__, + native = __BYTE_ORDER__, +#else +#error onnxruntime_float16::detail::endian is not implemented in this environment. +#endif +}; + +static_assert( + endian::native == endian::little || endian::native == endian::big, + "Only little-endian or big-endian native byte orders are supported."); + +} // namespace detail + +/// +/// Shared implementation between public and internal classes. CRTP pattern. +/// +template +struct Float16Impl { + protected: + /// + /// Converts from float to uint16_t float16 representation + /// + /// + /// + constexpr static uint16_t ToUint16Impl(float v) noexcept; + + /// + /// Converts float16 to float + /// + /// float representation of float16 value + float ToFloatImpl() const noexcept; + + /// + /// Creates an instance that represents absolute value. + /// + /// Absolute value + uint16_t AbsImpl() const noexcept { + return static_cast(val & ~kSignMask); + } + + /// + /// Creates a new instance with the sign flipped. + /// + /// Flipped sign instance + uint16_t NegateImpl() const noexcept { + return IsNaN() ? val : static_cast(val ^ kSignMask); + } + + public: + // uint16_t special values + static constexpr uint16_t kSignMask = 0x8000U; + static constexpr uint16_t kBiasedExponentMask = 0x7C00U; + static constexpr uint16_t kPositiveInfinityBits = 0x7C00U; + static constexpr uint16_t kNegativeInfinityBits = 0xFC00U; + static constexpr uint16_t kPositiveQNaNBits = 0x7E00U; + static constexpr uint16_t kNegativeQNaNBits = 0xFE00U; + static constexpr uint16_t kEpsilonBits = 0x4170U; + static constexpr uint16_t kMinValueBits = 0xFBFFU; // Minimum normal number + static constexpr uint16_t kMaxValueBits = 0x7BFFU; // Largest normal number + static constexpr uint16_t kOneBits = 0x3C00U; + static constexpr uint16_t kMinusOneBits = 0xBC00U; + + uint16_t val{0}; + + Float16Impl() = default; + + /// + /// Checks if the value is negative + /// + /// true if negative + bool IsNegative() const noexcept { + return static_cast(val) < 0; + } + + /// + /// Tests if the value is NaN + /// + /// true if NaN + bool IsNaN() const noexcept { + return AbsImpl() > kPositiveInfinityBits; + } + + /// + /// Tests if the value is finite + /// + /// true if finite + bool IsFinite() const noexcept { + return AbsImpl() < kPositiveInfinityBits; + } + + /// + /// Tests if the value represents positive infinity. + /// + /// true if positive infinity + bool IsPositiveInfinity() const noexcept { + return val == kPositiveInfinityBits; + } + + /// + /// Tests if the value represents negative infinity + /// + /// true if negative infinity + bool IsNegativeInfinity() const noexcept { + return val == kNegativeInfinityBits; + } + + /// + /// Tests if the value is either positive or negative infinity. + /// + /// True if absolute value is infinity + bool IsInfinity() const noexcept { + return AbsImpl() == kPositiveInfinityBits; + } + + /// + /// Tests if the value is NaN or zero. Useful for comparisons. + /// + /// True if NaN or zero. + bool IsNaNOrZero() const noexcept { + auto abs = AbsImpl(); + return (abs == 0 || abs > kPositiveInfinityBits); + } + + /// + /// Tests if the value is normal (not zero, subnormal, infinite, or NaN). + /// + /// True if so + bool IsNormal() const noexcept { + auto abs = AbsImpl(); + return (abs < kPositiveInfinityBits) // is finite + && (abs != 0) // is not zero + && ((abs & kBiasedExponentMask) != 0); // is not subnormal (has a non-zero exponent) + } + + /// + /// Tests if the value is subnormal (denormal). + /// + /// True if so + bool IsSubnormal() const noexcept { + auto abs = AbsImpl(); + return (abs < kPositiveInfinityBits) // is finite + && (abs != 0) // is not zero + && ((abs & kBiasedExponentMask) == 0); // is subnormal (has a zero exponent) + } + + /// + /// Creates an instance that represents absolute value. + /// + /// Absolute value + Derived Abs() const noexcept { return Derived::FromBits(AbsImpl()); } + + /// + /// Creates a new instance with the sign flipped. + /// + /// Flipped sign instance + Derived Negate() const noexcept { return Derived::FromBits(NegateImpl()); } + + /// + /// IEEE defines that positive and negative zero are equal, this gives us a quick equality check + /// for two values by or'ing the private bits together and stripping the sign. They are both zero, + /// and therefore equivalent, if the resulting value is still zero. + /// + /// first value + /// second value + /// True if both arguments represent zero + static bool AreZero(const Float16Impl& lhs, const Float16Impl& rhs) noexcept { + return static_cast((lhs.val | rhs.val) & ~kSignMask) == 0; + } + + bool operator==(const Float16Impl& rhs) const noexcept { + if (IsNaN() || rhs.IsNaN()) { + // IEEE defines that NaN is not equal to anything, including itself. + return false; + } + return val == rhs.val; + } + + bool operator!=(const Float16Impl& rhs) const noexcept { return !(*this == rhs); } + + bool operator<(const Float16Impl& rhs) const noexcept { + if (IsNaN() || rhs.IsNaN()) { + // IEEE defines that NaN is unordered with respect to everything, including itself. + return false; + } + + const bool left_is_negative = IsNegative(); + if (left_is_negative != rhs.IsNegative()) { + // When the signs of left and right differ, we know that left is less than right if it is + // the negative value. The exception to this is if both values are zero, in which case IEEE + // says they should be equal, even if the signs differ. + return left_is_negative && !AreZero(*this, rhs); + } + return (val != rhs.val) && ((val < rhs.val) ^ left_is_negative); + } +}; + +// The following Float16_t conversions are based on the code from +// Eigen library. + +// The conversion routines are Copyright (c) Fabian Giesen, 2016. +// The original license follows: +// +// Copyright (c) Fabian Giesen, 2016 +// All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted. +// 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. + +namespace detail { +union float32_bits { + unsigned int u; + float f; +}; +} // namespace detail + +template +inline constexpr uint16_t Float16Impl::ToUint16Impl(float v) noexcept { + detail::float32_bits f{}; + f.f = v; + + constexpr detail::float32_bits f32infty = {255 << 23}; + constexpr detail::float32_bits f16max = {(127 + 16) << 23}; + constexpr detail::float32_bits denorm_magic = {((127 - 15) + (23 - 10) + 1) << 23}; + constexpr unsigned int sign_mask = 0x80000000u; + uint16_t val = static_cast(0x0u); + + unsigned int sign = f.u & sign_mask; + f.u ^= sign; + + // NOTE all the integer compares in this function can be safely + // compiled into signed compares since all operands are below + // 0x80000000. Important if you want fast straight SSE2 code + // (since there's no unsigned PCMPGTD). + + if (f.u >= f16max.u) { // result is Inf or NaN (all exponent bits set) + val = (f.u > f32infty.u) ? 0x7e00 : 0x7c00; // NaN->qNaN and Inf->Inf + } else { // (De)normalized number or zero + if (f.u < (113 << 23)) { // resulting FP16 is subnormal or zero + // use a magic value to align our 10 mantissa bits at the bottom of + // the float. as long as FP addition is round-to-nearest-even this + // just works. + f.f += denorm_magic.f; + + // and one integer subtract of the bias later, we have our final float! + val = static_cast(f.u - denorm_magic.u); + } else { + unsigned int mant_odd = (f.u >> 13) & 1; // resulting mantissa is odd + + // update exponent, rounding bias part 1 + // Equivalent to `f.u += ((unsigned int)(15 - 127) << 23) + 0xfff`, but + // without arithmetic overflow. + f.u += 0xc8000fffU; + // rounding bias part 2 + f.u += mant_odd; + // take the bits! + val = static_cast(f.u >> 13); + } + } + + val |= static_cast(sign >> 16); + return val; +} + +template +inline float Float16Impl::ToFloatImpl() const noexcept { + constexpr detail::float32_bits magic = {113 << 23}; + constexpr unsigned int shifted_exp = 0x7c00 << 13; // exponent mask after shift + detail::float32_bits o{}; + + o.u = (val & 0x7fff) << 13; // exponent/mantissa bits + unsigned int exp = shifted_exp & o.u; // just the exponent + o.u += (127 - 15) << 23; // exponent adjust + + // handle exponent special cases + if (exp == shifted_exp) { // Inf/NaN? + o.u += (128 - 16) << 23; // extra exp adjust + } else if (exp == 0) { // Zero/Denormal? + o.u += 1 << 23; // extra exp adjust + o.f -= magic.f; // re-normalize + } + + // Attempt to workaround the Internal Compiler Error on ARM64 + // for bitwise | operator, including std::bitset +#if (defined _MSC_VER) && (defined _M_ARM || defined _M_ARM64 || defined _M_ARM64EC) + if (IsNegative()) { + return -o.f; + } +#else + // original code: + o.u |= (val & 0x8000U) << 16U; // sign bit +#endif + return o.f; +} + +/// Shared implementation between public and internal classes. CRTP pattern. +template +struct BFloat16Impl { + protected: + /// + /// Converts from float to uint16_t float16 representation + /// + /// + /// + static uint16_t ToUint16Impl(float v) noexcept; + + /// + /// Converts bfloat16 to float + /// + /// float representation of bfloat16 value + float ToFloatImpl() const noexcept; + + /// + /// Creates an instance that represents absolute value. + /// + /// Absolute value + uint16_t AbsImpl() const noexcept { + return static_cast(val & ~kSignMask); + } + + /// + /// Creates a new instance with the sign flipped. + /// + /// Flipped sign instance + uint16_t NegateImpl() const noexcept { + return IsNaN() ? val : static_cast(val ^ kSignMask); + } + + public: + // uint16_t special values + static constexpr uint16_t kSignMask = 0x8000U; + static constexpr uint16_t kBiasedExponentMask = 0x7F80U; + static constexpr uint16_t kPositiveInfinityBits = 0x7F80U; + static constexpr uint16_t kNegativeInfinityBits = 0xFF80U; + static constexpr uint16_t kPositiveQNaNBits = 0x7FC1U; + static constexpr uint16_t kNegativeQNaNBits = 0xFFC1U; + static constexpr uint16_t kSignaling_NaNBits = 0x7F80U; + static constexpr uint16_t kEpsilonBits = 0x0080U; + static constexpr uint16_t kMinValueBits = 0xFF7FU; + static constexpr uint16_t kMaxValueBits = 0x7F7FU; + static constexpr uint16_t kRoundToNearest = 0x7FFFU; + static constexpr uint16_t kOneBits = 0x3F80U; + static constexpr uint16_t kMinusOneBits = 0xBF80U; + + uint16_t val{0}; + + BFloat16Impl() = default; + + /// + /// Checks if the value is negative + /// + /// true if negative + bool IsNegative() const noexcept { + return static_cast(val) < 0; + } + + /// + /// Tests if the value is NaN + /// + /// true if NaN + bool IsNaN() const noexcept { + return AbsImpl() > kPositiveInfinityBits; + } + + /// + /// Tests if the value is finite + /// + /// true if finite + bool IsFinite() const noexcept { + return AbsImpl() < kPositiveInfinityBits; + } + + /// + /// Tests if the value represents positive infinity. + /// + /// true if positive infinity + bool IsPositiveInfinity() const noexcept { + return val == kPositiveInfinityBits; + } + + /// + /// Tests if the value represents negative infinity + /// + /// true if negative infinity + bool IsNegativeInfinity() const noexcept { + return val == kNegativeInfinityBits; + } + + /// + /// Tests if the value is either positive or negative infinity. + /// + /// True if absolute value is infinity + bool IsInfinity() const noexcept { + return AbsImpl() == kPositiveInfinityBits; + } + + /// + /// Tests if the value is NaN or zero. Useful for comparisons. + /// + /// True if NaN or zero. + bool IsNaNOrZero() const noexcept { + auto abs = AbsImpl(); + return (abs == 0 || abs > kPositiveInfinityBits); + } + + /// + /// Tests if the value is normal (not zero, subnormal, infinite, or NaN). + /// + /// True if so + bool IsNormal() const noexcept { + auto abs = AbsImpl(); + return (abs < kPositiveInfinityBits) // is finite + && (abs != 0) // is not zero + && ((abs & kBiasedExponentMask) != 0); // is not subnormal (has a non-zero exponent) + } + + /// + /// Tests if the value is subnormal (denormal). + /// + /// True if so + bool IsSubnormal() const noexcept { + auto abs = AbsImpl(); + return (abs < kPositiveInfinityBits) // is finite + && (abs != 0) // is not zero + && ((abs & kBiasedExponentMask) == 0); // is subnormal (has a zero exponent) + } + + /// + /// Creates an instance that represents absolute value. + /// + /// Absolute value + Derived Abs() const noexcept { return Derived::FromBits(AbsImpl()); } + + /// + /// Creates a new instance with the sign flipped. + /// + /// Flipped sign instance + Derived Negate() const noexcept { return Derived::FromBits(NegateImpl()); } + + /// + /// IEEE defines that positive and negative zero are equal, this gives us a quick equality check + /// for two values by or'ing the private bits together and stripping the sign. They are both zero, + /// and therefore equivalent, if the resulting value is still zero. + /// + /// first value + /// second value + /// True if both arguments represent zero + static bool AreZero(const BFloat16Impl& lhs, const BFloat16Impl& rhs) noexcept { + // IEEE defines that positive and negative zero are equal, this gives us a quick equality check + // for two values by or'ing the private bits together and stripping the sign. They are both zero, + // and therefore equivalent, if the resulting value is still zero. + return static_cast((lhs.val | rhs.val) & ~kSignMask) == 0; + } +}; + +template +inline uint16_t BFloat16Impl::ToUint16Impl(float v) noexcept { + uint16_t result; + if (std::isnan(v)) { + result = kPositiveQNaNBits; + } else { + auto get_msb_half = [](float fl) { + uint16_t result; +#ifdef __cpp_if_constexpr + if constexpr (detail::endian::native == detail::endian::little) { +#else + if (detail::endian::native == detail::endian::little) { +#endif + std::memcpy(&result, reinterpret_cast(&fl) + sizeof(uint16_t), sizeof(uint16_t)); + } else { + std::memcpy(&result, &fl, sizeof(uint16_t)); + } + return result; + }; + + uint16_t upper_bits = get_msb_half(v); + union { + uint32_t U32; + float F32; + }; + F32 = v; + U32 += (upper_bits & 1) + kRoundToNearest; + result = get_msb_half(F32); + } + return result; +} + +template +inline float BFloat16Impl::ToFloatImpl() const noexcept { + if (IsNaN()) { + return std::numeric_limits::quiet_NaN(); + } + float result; + char* const first = reinterpret_cast(&result); + char* const second = first + sizeof(uint16_t); +#ifdef __cpp_if_constexpr + if constexpr (detail::endian::native == detail::endian::little) { +#else + if (detail::endian::native == detail::endian::little) { +#endif + std::memset(first, 0, sizeof(uint16_t)); + std::memcpy(second, &val, sizeof(uint16_t)); + } else { + std::memcpy(first, &val, sizeof(uint16_t)); + std::memset(second, 0, sizeof(uint16_t)); + } + return result; +} + +} // namespace onnxruntime_float16 diff --git a/include/onnxruntime/core/session/onnxruntime_lite_custom_op.h b/include/onnxruntime/core/session/onnxruntime_lite_custom_op.h new file mode 100644 index 0000000000000..fd42824e81a56 --- /dev/null +++ b/include/onnxruntime/core/session/onnxruntime_lite_custom_op.h @@ -0,0 +1,742 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// Summary +// The header has APIs to save custom op authors the trouble of defining schemas, +// which will be inferred by functions' signature, as long as their argument list has types supported here. +// Input could be: +// 1. Tensor of onnx data types. +// 2. Span of onnx data types. +// 3. Scalar of onnx data types. +// A input could be optional if indicated as std::optional<...>. +// For an output, it must be a tensor of onnx data types. +// Further, the header also has utility for a simple custom struct, where resources could be kept, to be registered as a custom op. +// For concrete examples, please search keyword "LiteCustomOpTest" under "/onnxruntime/test/". +// Note - all APIs in this header are ABI. + +#pragma once +#include "onnxruntime_cxx_api.h" +#include +#include +#include + +namespace Ort { +namespace Custom { + +class TensorBase { + public: + TensorBase(OrtKernelContext* ctx) : ctx_(ctx) {} + virtual ~TensorBase() {} + operator bool() const { + return shape_.has_value(); + } + + protected: + struct KernelContext ctx_; + std::optional> shape_; +}; + +template +struct Span { + const T* data_ = {}; + size_t size_ = {}; + void Assign(const T* data, size_t size) { + data_ = data; + size_ = size; + } + size_t size() const { return size_; } + T operator[](size_t indice) const { + return data_[indice]; + } +}; + +template +class Tensor : public TensorBase { + public: + using TT = typename std::remove_reference::type; + Tensor(OrtKernelContext* ctx, size_t indice, bool is_input) : TensorBase(ctx), indice_(indice), is_input_(is_input) { + if (is_input_) { + if (indice >= ctx_.GetInputCount()) { + ORT_CXX_API_THROW("invalid indice for Ort::Custom::Tensor", OrtErrorCode::ORT_INVALID_ARGUMENT); + } + const_value_ = ctx_.GetInput(indice); + auto type_shape_info = const_value_.GetTensorTypeAndShapeInfo(); + shape_ = type_shape_info.GetShape(); + } + } + const std::vector& Shape() const { + if (!shape_.has_value()) { + ORT_CXX_API_THROW("tensor shape is not yet initialized", OrtErrorCode::ORT_RUNTIME_EXCEPTION); + } + return shape_.value(); + } + int64_t NumberOfElement() const { + if (shape_.has_value()) { + return std::accumulate(shape_->begin(), shape_->end(), 1LL, std::multiplies()); + } else { + return 0; + } + } + const TT* Data() const { + return reinterpret_cast(const_value_.GetTensorRawData()); + } + TT* Allocate(const std::vector& shape) { + shape_ = shape; + if (!data_) { + shape_ = shape; + data_ = ctx_.GetOutput(indice_, shape).template GetTensorMutableData(); + } + return data_; + } + static TT GetT() { return (TT)0; } + const Span& AsSpan() { + if (!shape_.has_value() || shape_->size() != 1) { + ORT_CXX_API_THROW("invalid shape while trying to get a span out of Ort::Custom::Tensor", + OrtErrorCode::ORT_RUNTIME_EXCEPTION); + } + span_.Assign(Data(), static_cast((*shape_)[0])); + return span_; + } + const T& AsScalar() { + if (!shape_.has_value() || shape_->size() != 1 || (*shape_)[0] != 1) { + ORT_CXX_API_THROW("invalid shape while trying to get a scalar from Ort::Custom::Tensor", + OrtErrorCode::ORT_RUNTIME_EXCEPTION); + } + return *Data(); + } + + private: + size_t indice_; + bool is_input_; + ConstValue const_value_; // for input + TT* data_{}; // for output + Span span_; +}; + +template <> +class Tensor : public TensorBase { + public: + using strings = std::vector; + + Tensor(OrtKernelContext* ctx, size_t indice, bool is_input) : TensorBase(ctx), indice_(indice), is_input_(is_input) { + if (is_input_) { + if (indice >= ctx_.GetInputCount()) { + ORT_CXX_API_THROW("invalid indice for Ort::Custom::Tensor", OrtErrorCode::ORT_INVALID_ARGUMENT); + } + auto const_value = ctx_.GetInput(indice); + auto type_shape_info = const_value.GetTensorTypeAndShapeInfo(); + shape_ = type_shape_info.GetShape(); + auto num_chars = const_value.GetStringTensorDataLength(); + // note - there will be copy ... + auto num_strings = static_cast(NumberOfElement()); + if (num_strings) { + std::vector chars(num_chars + 1, '\0'); + std::vector offsets(num_strings); + const_value.GetStringTensorContent(static_cast(chars.data()), num_chars, offsets.data(), offsets.size()); + auto upper_bound = num_strings - 1; + input_strings_.resize(num_strings); + for (size_t i = upper_bound;; --i) { + if (i < upper_bound) { + chars[offsets[i + 1]] = '\0'; + } + input_strings_[i] = chars.data() + offsets[i]; + if (0 == i) { + break; + } + } + } + } + } + int64_t NumberOfElement() const { + if (shape_.has_value()) { + return std::accumulate(shape_->begin(), shape_->end(), 1ULL, std::multiplies()); + } else { + return 0; + } + } + const strings& Data() const { + return input_strings_; + } + void SetStringOutput(const strings& ss, const std::vector& dims) { + shape_ = dims; + std::vector raw; + for (const auto& s : ss) { + raw.push_back(s.data()); + } + auto output = ctx_.GetOutput(indice_, dims.data(), dims.size()); + // note - there will be copy ... + output.FillStringTensor(raw.data(), raw.size()); + } + const Span& AsSpan() { + ORT_CXX_API_THROW("span for TensorT of string not implemented", OrtErrorCode::ORT_RUNTIME_EXCEPTION); + } + const std::string& AsScalar() { + if (input_strings_.size() != 1) { + ORT_CXX_API_THROW("invalid shape while trying to get a scalar string from Ort::Custom::Tensor", + OrtErrorCode::ORT_RUNTIME_EXCEPTION); + } + return input_strings_[0]; + } + + private: + size_t indice_; + bool is_input_; + std::vector input_strings_; // for input +}; + +template <> +class Tensor : public TensorBase { + public: + using strings = std::vector; + using string_views = std::vector; + + Tensor(OrtKernelContext* ctx, size_t indice, bool is_input) : TensorBase(ctx), indice_(indice), is_input_(is_input) { + if (is_input_) { + if (indice >= ctx_.GetInputCount()) { + ORT_CXX_API_THROW("invalid indice for Ort::Custom::Tensor", OrtErrorCode::ORT_INVALID_ARGUMENT); + } + auto const_value = ctx_.GetInput(indice); + auto type_shape_info = const_value.GetTensorTypeAndShapeInfo(); + shape_ = type_shape_info.GetShape(); + auto num_chars = const_value.GetStringTensorDataLength(); + chars_.resize(num_chars + 1, '\0'); + auto num_strings = static_cast(NumberOfElement()); + if (num_strings) { + std::vector offsets(num_strings); + const_value.GetStringTensorContent(static_cast(chars_.data()), num_chars, offsets.data(), offsets.size()); + offsets.push_back(num_chars); + for (size_t i = 0; i < num_strings; ++i) { + input_string_views_.emplace_back(chars_.data() + offsets[i], offsets[i + 1] - offsets[i]); + } + } + } + } + int64_t NumberOfElement() const { + if (shape_.has_value()) { + return std::accumulate(shape_->begin(), shape_->end(), 1ULL, std::multiplies()); + } else { + return 0; + } + } + const string_views& Data() const { + return input_string_views_; + } + void SetStringOutput(const strings& ss, const std::vector& dims) { + shape_ = dims; + std::vector raw; + for (const auto& s : ss) { + raw.push_back(s.data()); + } + auto output = ctx_.GetOutput(indice_, dims.data(), dims.size()); + // note - there will be copy ... + output.FillStringTensor(raw.data(), raw.size()); + } + const Span& AsSpan() { + ORT_CXX_API_THROW("span for TensorT of string view not implemented", OrtErrorCode::ORT_RUNTIME_EXCEPTION); + } + std::string_view AsScalar() { + if (input_string_views_.size() != 1) { + ORT_CXX_API_THROW("invalid shape while trying to get a scalar string view from Ort::Custom::Tensor", + OrtErrorCode::ORT_RUNTIME_EXCEPTION); + } + return input_string_views_[0]; + } + + private: + size_t indice_; + bool is_input_; + std::vector chars_; // for input + std::vector input_string_views_; // for input +}; + +using TensorPtr = std::unique_ptr; + +//////////////////////////// OrtLiteCustomOp //////////////////////////////// + +struct OrtLiteCustomOp : public OrtCustomOp { + using ConstOptionalFloatTensor = std::optional&>; + using OptionalFloatTensor = std::optional>; + + // CreateTuple + template + static typename std::enable_if>::type + CreateTuple(OrtKernelContext*, std::vector&, size_t, size_t, const std::string&) { + return std::make_tuple(); + } + + template + static typename std::enable_if::value, std::tuple>::type + CreateTuple(OrtKernelContext* context, std::vector& tensors, size_t num_input, size_t num_output, const std::string& ep) { + std::tuple current = std::tuple{context}; + auto next = CreateTuple(context, tensors, num_input, num_output, ep); + return std::tuple_cat(current, next); + } + + template + static typename std::enable_if::value, std::tuple>::type + CreateTuple(OrtKernelContext* context, std::vector& tensors, size_t num_input, size_t num_output, const std::string& ep) { + std::tuple current = std::tuple{*context}; + auto next = CreateTuple(context, tensors, num_input, num_output, ep); + return std::tuple_cat(current, next); + } + +#ifdef ORT_CUDA_CTX + template + static typename std::enable_if::value, std::tuple>::type + CreateTuple(OrtKernelContext* context, std::vector& tensors, size_t num_input, size_t num_output, const std::string& ep) { + thread_local CudaContext cuda_context; + cuda_context.Init(*context); + std::tuple current = std::tuple{cuda_context}; + auto next = CreateTuple(context, tensors, num_input, num_output, ep); + return std::tuple_cat(current, next); + } +#endif + +#ifdef ORT_ROCM_CTX + template + static typename std::enable_if::value, std::tuple>::type + CreateTuple(OrtKernelContext* context, std::vector& tensors, size_t num_input, size_t num_output, const std::string& ep) { + thread_local RocmContext rocm_context; + rocm_context.Init(*context); + std::tuple current = std::tuple{rocm_context}; + auto next = CreateTuple(context, tensors, num_input, num_output, ep); + return std::tuple_cat(current, next); + } +#endif + +#define CREATE_TUPLE_INPUT(data_type) \ + template \ + static typename std::enable_if*>::value, std::tuple>::type \ + CreateTuple(OrtKernelContext* context, std::vector& tensors, size_t num_input, size_t num_output, const std::string& ep) { \ + tensors.push_back(std::make_unique>(context, ith_input, true)); \ + std::tuple current = std::tuple{reinterpret_cast(tensors.back().get())}; \ + auto next = CreateTuple(context, tensors, num_input, num_output, ep); \ + return std::tuple_cat(current, next); \ + } \ + template \ + static typename std::enable_if&>::value, std::tuple>::type \ + CreateTuple(OrtKernelContext* context, std::vector& tensors, size_t num_input, size_t num_output, const std::string& ep) { \ + tensors.push_back(std::make_unique>(context, ith_input, true)); \ + std::tuple current = std::tuple{reinterpret_cast(*tensors.back().get())}; \ + auto next = CreateTuple(context, tensors, num_input, num_output, ep); \ + return std::tuple_cat(current, next); \ + } \ + template \ + static typename std::enable_if*>>::value, std::tuple>::type \ + CreateTuple(OrtKernelContext* context, std::vector& tensors, size_t num_input, size_t num_output, const std::string& ep) { \ + if (ith_input < num_input) { \ + tensors.push_back(std::make_unique>(context, ith_input, true)); \ + std::tuple current = std::tuple{reinterpret_cast*>(tensors.back().get())}; \ + auto next = CreateTuple(context, tensors, num_input, num_output, ep); \ + return std::tuple_cat(current, next); \ + } else { \ + std::tuple current = std::tuple{}; \ + auto next = CreateTuple(context, tensors, num_input, num_output, ep); \ + return std::tuple_cat(current, next); \ + } \ + } \ + template \ + static typename std::enable_if*>::value, std::tuple>::type \ + CreateTuple(OrtKernelContext* context, std::vector& tensors, size_t num_input, size_t num_output, const std::string& ep) { \ + if ("CPUExecutionProvider" != ep) { \ + ORT_CXX_API_THROW("span input could only be applied to CPU EP", OrtErrorCode::ORT_RUNTIME_EXCEPTION); \ + } \ + tensors.push_back(std::make_unique>(context, ith_input, true)); \ + std::tuple current = std::tuple{&reinterpret_cast*>(tensors.back().get())->AsSpan()}; \ + auto next = CreateTuple(context, tensors, num_input, num_output, ep); \ + return std::tuple_cat(current, next); \ + } \ + template \ + static typename std::enable_if&>::value, std::tuple>::type \ + CreateTuple(OrtKernelContext* context, std::vector& tensors, size_t num_input, size_t num_output, const std::string& ep) { \ + if ("CPUExecutionProvider" != ep) { \ + ORT_CXX_API_THROW("span input could only be applied to CPU EP", OrtErrorCode::ORT_RUNTIME_EXCEPTION); \ + } \ + tensors.push_back(std::make_unique>(context, ith_input, true)); \ + std::tuple current = std::tuple{reinterpret_cast*>(tensors.back().get())->AsSpan()}; \ + auto next = CreateTuple(context, tensors, num_input, num_output, ep); \ + return std::tuple_cat(current, next); \ + } \ + template \ + static typename std::enable_if*>>::value, std::tuple>::type \ + CreateTuple(OrtKernelContext* context, std::vector& tensors, size_t num_input, size_t num_output, const std::string& ep) { \ + if (ith_input < num_input) { \ + if ("CPUExecutionProvider" != ep) { \ + ORT_CXX_API_THROW("span input could only be applied to CPU EP", OrtErrorCode::ORT_RUNTIME_EXCEPTION); \ + } \ + tensors.push_back(std::make_unique>(context, ith_input, true)); \ + std::tuple current = std::tuple{&reinterpret_cast*>(tensors.back().get())->AsSpan()}; \ + auto next = CreateTuple(context, tensors, num_input, num_output, ep); \ + return std::tuple_cat(current, next); \ + } else { \ + std::tuple current = std::tuple{}; \ + auto next = CreateTuple(context, tensors, num_input, num_output, ep); \ + return std::tuple_cat(current, next); \ + } \ + } \ + template \ + static typename std::enable_if::value, std::tuple>::type \ + CreateTuple(OrtKernelContext* context, std::vector& tensors, size_t num_input, size_t num_output, const std::string& ep) { \ + if ("CPUExecutionProvider" != ep) { \ + ORT_CXX_API_THROW("scalar input could only be applied to CPU EP", OrtErrorCode::ORT_RUNTIME_EXCEPTION); \ + } \ + tensors.push_back(std::make_unique>(context, ith_input, true)); \ + std::tuple current = std::tuple{reinterpret_cast*>(tensors.back().get())->AsScalar()}; \ + auto next = CreateTuple(context, tensors, num_input, num_output, ep); \ + return std::tuple_cat(current, next); \ + } \ + template \ + static typename std::enable_if>::value, std::tuple>::type \ + CreateTuple(OrtKernelContext* context, std::vector& tensors, size_t num_input, size_t num_output, const std::string& ep) { \ + if (ith_input < num_input) { \ + if ("CPUExecutionProvider" != ep) { \ + ORT_CXX_API_THROW("scalar input could only be applied to CPU EP", OrtErrorCode::ORT_RUNTIME_EXCEPTION); \ + } \ + tensors.push_back(std::make_unique>(context, ith_input, true)); \ + std::tuple current = std::tuple{reinterpret_cast*>(tensors.back().get())->AsScalar()}; \ + auto next = CreateTuple(context, tensors, num_input, num_output, ep); \ + return std::tuple_cat(current, next); \ + } else { \ + std::tuple current = std::tuple{}; \ + auto next = CreateTuple(context, tensors, num_input, num_output, ep); \ + return std::tuple_cat(current, next); \ + } \ + } +#define CREATE_TUPLE_OUTPUT(data_type) \ + template \ + static typename std::enable_if*>::value, std::tuple>::type \ + CreateTuple(OrtKernelContext* context, std::vector& tensors, size_t num_input, size_t num_output, const std::string& ep) { \ + tensors.push_back(std::make_unique>(context, ith_output, false)); \ + std::tuple current = std::tuple{reinterpret_cast(tensors.back().get())}; \ + auto next = CreateTuple(context, tensors, num_input, num_output, ep); \ + return std::tuple_cat(current, next); \ + } \ + template \ + static typename std::enable_if&>::value, std::tuple>::type \ + CreateTuple(OrtKernelContext* context, std::vector& tensors, size_t num_input, size_t num_output, const std::string& ep) { \ + tensors.push_back(std::make_unique>(context, ith_output, false)); \ + std::tuple current = std::tuple{reinterpret_cast(*tensors.back().get())}; \ + auto next = CreateTuple(context, tensors, num_input, num_output, ep); \ + return std::tuple_cat(current, next); \ + } \ + template \ + static typename std::enable_if*>>::value, std::tuple>::type \ + CreateTuple(OrtKernelContext* context, std::vector& tensors, size_t num_input, size_t num_output, const std::string& ep) { \ + if (ith_output < num_output) { \ + tensors.push_back(std::make_unique>(context, ith_output, false)); \ + std::tuple current = std::tuple{reinterpret_cast*>(tensors.back().get())}; \ + auto next = CreateTuple(context, tensors, num_input, num_output, ep); \ + return std::tuple_cat(current, next); \ + } else { \ + std::tuple current = std::tuple{}; \ + auto next = CreateTuple(context, tensors, num_input, num_output, ep); \ + return std::tuple_cat(current, next); \ + } \ + } +#define CREATE_TUPLE(data_type) \ + CREATE_TUPLE_INPUT(data_type) \ + CREATE_TUPLE_OUTPUT(data_type) + + CREATE_TUPLE(bool) + CREATE_TUPLE(float) + CREATE_TUPLE(Ort::Float16_t) + CREATE_TUPLE(Ort::BFloat16_t) + CREATE_TUPLE(double) + CREATE_TUPLE(int8_t) + CREATE_TUPLE(int16_t) + CREATE_TUPLE(int32_t) + CREATE_TUPLE(int64_t) + CREATE_TUPLE(uint8_t) + CREATE_TUPLE(uint16_t) + CREATE_TUPLE(uint32_t) + CREATE_TUPLE(uint64_t) + CREATE_TUPLE(std::string) + CREATE_TUPLE_INPUT(std::string_view) + CREATE_TUPLE(Ort::Float8E4M3FN_t) + CREATE_TUPLE(Ort::Float8E4M3FNUZ_t) + CREATE_TUPLE(Ort::Float8E5M2_t) + CREATE_TUPLE(Ort::Float8E5M2FNUZ_t) + + // ParseArgs ... + template + static typename std::enable_if<0 == sizeof...(Ts)>::type + ParseArgs(std::vector&, std::vector&) { + } + + template + static typename std::enable_if<0 <= sizeof...(Ts) && std::is_same::value>::type + ParseArgs(std::vector& input_types, std::vector& output_types) { + ParseArgs(input_types, output_types); + } + + template + static typename std::enable_if<0 <= sizeof...(Ts) && std::is_same::value>::type + ParseArgs(std::vector& input_types, std::vector& output_types) { + ParseArgs(input_types, output_types); + } + +#ifdef ORT_CUDA_CTX + template + static typename std::enable_if<0 <= sizeof...(Ts) && std::is_same::value>::type + ParseArgs(std::vector& input_types, std::vector& output_types) { + ParseArgs(input_types, output_types); + } +#endif + +#ifdef ORT_ROCM_CTX + template + static typename std::enable_if<0 <= sizeof...(Ts) && std::is_same::value>::type + ParseArgs(std::vector& input_types, std::vector& output_types) { + ParseArgs(input_types, output_types); + } +#endif + +#define PARSE_INPUT_BASE(pack_type, onnx_type) \ + template \ + static typename std::enable_if<0 <= sizeof...(Ts) && std::is_same::value>::type \ + ParseArgs(std::vector& input_types, std::vector& output_types) { \ + input_types.push_back(onnx_type); \ + ParseArgs(input_types, output_types); \ + } \ + template \ + static typename std::enable_if<0 <= sizeof...(Ts) && std::is_same>::value>::type \ + ParseArgs(std::vector& input_types, std::vector& output_types) { \ + input_types.push_back(onnx_type); \ + ParseArgs(input_types, output_types); \ + } + +#define PARSE_INPUT(data_type, onnx_type) \ + PARSE_INPUT_BASE(const Custom::Tensor*, onnx_type) \ + PARSE_INPUT_BASE(const Custom::Tensor&, onnx_type) \ + PARSE_INPUT_BASE(const Custom::Span*, onnx_type) \ + PARSE_INPUT_BASE(const Custom::Span&, onnx_type) \ + PARSE_INPUT_BASE(data_type, onnx_type) + +#define PARSE_OUTPUT(data_type, onnx_type) \ + template \ + static typename std::enable_if<0 <= sizeof...(Ts) && std::is_same*>::value>::type \ + ParseArgs(std::vector& input_types, std::vector& output_types) { \ + output_types.push_back(onnx_type); \ + ParseArgs(input_types, output_types); \ + } \ + template \ + static typename std::enable_if<0 <= sizeof...(Ts) && std::is_same&>::value>::type \ + ParseArgs(std::vector& input_types, std::vector& output_types) { \ + output_types.push_back(onnx_type); \ + ParseArgs(input_types, output_types); \ + } \ + template \ + static typename std::enable_if<0 <= sizeof...(Ts) && std::is_same*>>::value>::type \ + ParseArgs(std::vector& input_types, std::vector& output_types) { \ + output_types.push_back(onnx_type); \ + ParseArgs(input_types, output_types); \ + } + +#define PARSE_ARGS(data_type, onnx_type) \ + PARSE_INPUT(data_type, onnx_type) \ + PARSE_OUTPUT(data_type, onnx_type) + + PARSE_ARGS(bool, ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL) + PARSE_ARGS(float, ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT) + PARSE_ARGS(Ort::Float16_t, ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16) + PARSE_ARGS(Ort::BFloat16_t, ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16) + PARSE_ARGS(double, ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE) + PARSE_ARGS(int8_t, ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8) + PARSE_ARGS(int16_t, ONNX_TENSOR_ELEMENT_DATA_TYPE_INT16) + PARSE_ARGS(int32_t, ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32) + PARSE_ARGS(int64_t, ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64) + PARSE_ARGS(uint8_t, ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8) + PARSE_ARGS(uint16_t, ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT16) + PARSE_ARGS(uint32_t, ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT32) + PARSE_ARGS(uint64_t, ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT64) + PARSE_ARGS(std::string, ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING) + PARSE_ARGS(std::string_view, ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING) // todo - remove string_view output + PARSE_ARGS(Ort::Float8E4M3FN_t, ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FN) + PARSE_ARGS(Ort::Float8E4M3FNUZ_t, ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FNUZ) + PARSE_ARGS(Ort::Float8E5M2_t, ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2) + PARSE_ARGS(Ort::Float8E5M2FNUZ_t, ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2FNUZ) + + OrtLiteCustomOp(const char* op_name, + const char* execution_provider) : op_name_(op_name), + execution_provider_(execution_provider) { + OrtCustomOp::version = ORT_API_VERSION; + + OrtCustomOp::GetName = [](const OrtCustomOp* op) { return static_cast(op)->op_name_.c_str(); }; + OrtCustomOp::GetExecutionProviderType = [](const OrtCustomOp* op) { return ((OrtLiteCustomOp*)op)->execution_provider_.c_str(); }; + OrtCustomOp::GetInputMemoryType = [](const OrtCustomOp*, size_t) { return OrtMemTypeDefault; }; + + OrtCustomOp::GetInputTypeCount = [](const OrtCustomOp* op) { + auto self = reinterpret_cast(op); + return self->input_types_.size(); + }; + + OrtCustomOp::GetInputType = [](const OrtCustomOp* op, size_t indice) { + auto self = reinterpret_cast(op); + return self->input_types_[indice]; + }; + + OrtCustomOp::GetOutputTypeCount = [](const OrtCustomOp* op) { + auto self = reinterpret_cast(op); + return self->output_types_.size(); + }; + + OrtCustomOp::GetOutputType = [](const OrtCustomOp* op, size_t indice) { + auto self = reinterpret_cast(op); + return self->output_types_[indice]; + }; + + OrtCustomOp::GetInputCharacteristic = [](const OrtCustomOp*, size_t) { + return INPUT_OUTPUT_OPTIONAL; + }; + + OrtCustomOp::GetOutputCharacteristic = [](const OrtCustomOp*, size_t) { + return INPUT_OUTPUT_OPTIONAL; + }; + + OrtCustomOp::GetVariadicInputMinArity = [](const OrtCustomOp*) { return 0; }; + OrtCustomOp::GetVariadicInputHomogeneity = [](const OrtCustomOp*) { return 0; }; + OrtCustomOp::GetVariadicOutputMinArity = [](const OrtCustomOp*) { return 0; }; + OrtCustomOp::GetVariadicOutputHomogeneity = [](const OrtCustomOp*) { return 0; }; + } + + const std::string op_name_; + const std::string execution_provider_; + + std::vector input_types_; + std::vector output_types_; +}; + +//////////////////////////// OrtLiteCustomFunc //////////////////////////////// +// The struct is to implement function-as-op. +// E.g. a function might be defined as: +// void Filter(const Ort::Custom::Tensor& floats_in, Ort::Custom::Tensor& floats_out) { ... } +// It could be registered this way: +// Ort::CustomOpDomain v2_domain{"v2"}; +// std::unique_ptr fil_op_ptr{Ort::Custom::CreateLiteCustomOp("Filter", "CPUExecutionProvider", Filter)}; +// v2_domain.Add(fil_op_ptr.get()); +// session_options.Add(v2_domain); +// For the complete example, please search keyword "LiteCustomOpTest" under "/onnxruntime/test/". +template +struct OrtLiteCustomFunc : public OrtLiteCustomOp { + using ComputeFn = void (*)(Args...); + using MyType = OrtLiteCustomFunc; + + struct Kernel { + size_t num_input_{}; + size_t num_output_{}; + ComputeFn compute_fn_{}; + std::string ep_{}; + }; + + OrtLiteCustomFunc(const char* op_name, + const char* execution_provider, + ComputeFn compute_fn) : OrtLiteCustomOp(op_name, execution_provider), + compute_fn_(compute_fn) { + ParseArgs(input_types_, output_types_); + + OrtCustomOp::KernelCompute = [](void* op_kernel, OrtKernelContext* context) { + auto kernel = reinterpret_cast(op_kernel); + std::vector tensors; + auto t = CreateTuple<0, 0, Args...>(context, tensors, kernel->num_input_, kernel->num_output_, kernel->ep_); + std::apply([kernel](Args const&... t_args) { kernel->compute_fn_(t_args...); }, t); + }; + + OrtCustomOp::CreateKernel = [](const OrtCustomOp* this_, const OrtApi* ort_api, const OrtKernelInfo* info) { + auto kernel = std::make_unique(); + kernel->compute_fn_ = static_cast(this_)->compute_fn_; + Ort::ThrowOnError(ort_api->KernelInfo_GetInputCount(info, &kernel->num_input_)); + Ort::ThrowOnError(ort_api->KernelInfo_GetOutputCount(info, &kernel->num_output_)); + auto self = static_cast(this_); + kernel->ep_ = self->execution_provider_; + return reinterpret_cast(kernel.release()); + }; + + OrtCustomOp::KernelDestroy = [](void* op_kernel) { + delete reinterpret_cast(op_kernel); + }; + } + + ComputeFn compute_fn_; +}; // struct OrtLiteCustomFunc + +/////////////////////////// OrtLiteCustomStruct /////////////////////////// +// The struct is to implement struct-as-op. +// E.g. a struct might be defined as: +// struct Merge { +// Merge(const OrtApi* ort_api, const OrtKernelInfo* info) {...} +// void Compute(const Ort::Custom::Tensor& strings_in, +// std::string_view string_in, +// Ort::Custom::Tensor* strings_out) {...} +// bool reverse_ = false; +// }; +// It could be registered this way: +// Ort::CustomOpDomain v2_domain{"v2"}; +// std::unique_ptr mrg_op_ptr{Ort::Custom::CreateLiteCustomOp("Merge", "CPUExecutionProvider")}; +// v2_domain.Add(mrg_op_ptr.get()); +// session_options.Add(v2_domain); +// For the complete example, please search keyword "LiteCustomOpTest" under "/onnxruntime/test/". +template +struct OrtLiteCustomStruct : public OrtLiteCustomOp { + template + using CustomComputeFn = void (CustomOp::*)(Args...); + using MyType = OrtLiteCustomStruct; + + struct Kernel { + size_t num_input_{}; + size_t num_output_{}; + std::unique_ptr custom_op_; + std::string ep_{}; + }; + + OrtLiteCustomStruct(const char* op_name, + const char* execution_provider) : OrtLiteCustomOp(op_name, + execution_provider) { + init(&CustomOp::Compute); + } + + template + void init(CustomComputeFn) { + ParseArgs(input_types_, output_types_); + + OrtCustomOp::KernelCompute = [](void* op_kernel, OrtKernelContext* context) { + auto kernel = reinterpret_cast(op_kernel); + std::vector tensors; + auto t = CreateTuple<0, 0, Args...>(context, tensors, kernel->num_input_, kernel->num_output_, kernel->ep_); + std::apply([kernel](Args const&... t_args) { kernel->custom_op_->Compute(t_args...); }, t); + }; + + OrtCustomOp::CreateKernel = [](const OrtCustomOp* this_, const OrtApi* ort_api, const OrtKernelInfo* info) { + auto kernel = std::make_unique(); + Ort::ThrowOnError(ort_api->KernelInfo_GetInputCount(info, &kernel->num_input_)); + Ort::ThrowOnError(ort_api->KernelInfo_GetOutputCount(info, &kernel->num_output_)); + kernel->custom_op_ = std::make_unique(ort_api, info); + auto self = static_cast(this_); + kernel->ep_ = self->execution_provider_; + return reinterpret_cast(kernel.release()); + }; + + OrtCustomOp::KernelDestroy = [](void* op_kernel) { + delete reinterpret_cast(op_kernel); + }; + } +}; // struct OrtLiteCustomStruct + +/////////////////////////// CreateLiteCustomOp //////////////////////////// + +template +OrtLiteCustomOp* CreateLiteCustomOp(const char* op_name, + const char* execution_provider, + void (*custom_compute_fn)(Args...)) { + using LiteOp = OrtLiteCustomFunc; + return std::make_unique(op_name, execution_provider, custom_compute_fn).release(); +} + +template +OrtLiteCustomOp* CreateLiteCustomOp(const char* op_name, + const char* execution_provider) { + using LiteOp = OrtLiteCustomStruct; + return std::make_unique(op_name, execution_provider).release(); +} + +} // namespace Custom +} // namespace Ort 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 896f1efd7817c..37545f41b43dd 100644 --- a/include/onnxruntime/core/session/onnxruntime_session_options_config_keys.h +++ b/include/onnxruntime/core/session/onnxruntime_session_options_config_keys.h @@ -44,7 +44,7 @@ static const char* const kOrtSessionOptionsConfigSetDenormalAsZero = "session.se // It controls to run quantization model in QDQ (QuantizelinearDeQuantizelinear) format or not. // "0": enable. ORT does fusion logic for QDQ format. // "1": disable. ORT doesn't do fusion logic for QDQ format. -// Its default value is "0" +// Its default value is "0" unless the DirectML execution provider is registered, in which case it defaults to "1". static const char* const kOrtSessionOptionsDisableQuantQDQ = "session.disable_quant_qdq"; // It controls whether to enable Double QDQ remover and Identical Children Consolidation @@ -165,6 +165,11 @@ static const char* const kOrtSessionOptionsConfigForceSpinningStop = "session.fo // May be useful to expose bugs in models. static const char* const kOrtSessionOptionsConfigStrictShapeTypeInference = "session.strict_shape_type_inference"; +// "1": every model using a more recent opset than the latest released one will fail +// "0": the model may or may not work if onnxruntime cannot find an implementation, this option +// is used for development purpose. +static const char* const kOrtSessionOptionsConfigStrictAllowReleasedOpsetsOnly = "session.allow_released_opsets_only"; + // The file saves configuration for partitioning node among logic streams static const char* const kNodePartitionConfigFile = "session.node_partition_config_file"; @@ -197,3 +202,26 @@ static const char* const kOrtSessionOptionsConfigIntraOpThreadAffinities = "sess // 3) after the L1 transformers are applied to the updated graph. // The model will be saved to filename post_layout_transform_step_.onnx. static const char* const kDebugLayoutTransformation = "session.debug_layout_transformation"; + +// Graph nodes that are not supported by the execution providers (EPs) explicitly added to the session are +// assigned (i.e., "fallback") to the CPU EP by default. +// +// This option allows the user to disable the fallback of unsupported graph nodes to the CPU EP. +// If this option is set to "1", session creation will fail if the execution providers other than the CPU EP cannot +// fully support all of the nodes in the graph. +// +// It is invalid to set this option and explicitly add the CPU EP to the session. In this case, session creation +// will also fail with an error. +// +// Option values: +// - "0": CPU EP fallback is not disabled. [DEFAULT] +// - "1": CPU EP fallback is disabled. +static const char* const kOrtSessionOptionsDisableCPUEPFallback = "session.disable_cpu_ep_fallback"; + +// Use this config when serializing a large model after optimization to specify an external initializers file +static const char* const kOrtSessionOptionsOptimizedModelExternalInitializersFileName = + "session.optimized_model_external_initializers_file_name"; + +// Use this config to control the minimum size of the initializer when externalizing it during serialization +static const char* const kOrtSessionOptionsOptimizedModelExternalInitializersMinSizeInBytes = + "session.optimized_model_external_initializers_min_size_in_bytes"; diff --git a/java/build-android.gradle b/java/build-android.gradle index 3b1da3cb221b3..6f0dfa0a4f12c 100644 --- a/java/build-android.gradle +++ b/java/build-android.gradle @@ -8,6 +8,7 @@ def publishDir = System.properties['publishDir'] def minSdkVer = System.properties['minSdkVer'] def targetSdkVer = System.properties['targetSdkVer'] def buildVariant = System.properties['buildVariant'] ?: "Full" +boolean enableTrainingApis = (System.properties['ENABLE_TRAINING_APIS'] ?: "0") == "1" boolean isMobileBuild = (buildVariant == "Mobile") // Since Android requires a higher numbers indicating more recent versions @@ -26,7 +27,8 @@ project.buildDir = buildDir project.version = rootProject.file('../VERSION_NUMBER').text.trim() project.group = "com.microsoft.onnxruntime" -def mavenArtifactId = isMobileBuild ? project.name + '-mobile' : project.name + '-android' +def tmpArtifactId = enableTrainingApis ? project.name + "-training" : project.name +def mavenArtifactId = isMobileBuild ? tmpArtifactId + '-mobile' : tmpArtifactId + '-android' def mobileDescription = 'The ONNX Runtime Mobile package is a size optimized inference library for executing ONNX ' + '(Open Neural Network Exchange) models on Android. This package is built from the open source inference engine ' + 'but with reduced disk footprint targeting mobile platforms. To minimize binary size this library supports a ' + @@ -37,6 +39,10 @@ def defaultDescription = 'ONNX Runtime is a performance-focused inference engine 'Exchange) models. This package contains the Android (aar) build of ONNX Runtime. It includes support for all ' + 'types and operators, for ONNX format models. All standard ONNX models can be executed with this package. ' + 'As such the binary size and memory usage will be larger than the onnxruntime-mobile package.' +def trainingDescription = 'The onnxruntime-training android package is designed to efficiently train and infer a ' + + 'wide range of ONNX models on edge devices, such as mobile phones, tablets, and other portable devices with ' + + 'a focus on minimizing resource usage and maximizing accuracy.' + + 'See https://github.com/microsoft/onnxruntime-training-examples/tree/master/on_device_training for more details.' buildscript { repositories { @@ -92,6 +98,9 @@ android { sourceSets { main { jniLibs.srcDirs = [jniLibsDir] + java { + srcDirs = ['src/main/java', 'src/main/android'] + } } } @@ -137,8 +146,8 @@ publishing { artifact sourcesJar pom { - name = 'onnx-runtime' - description = isMobileBuild ? mobileDescription : defaultDescription + name = enableTrainingApis ? 'onnxruntime-training' : 'onnx-runtime' + description = isMobileBuild ? mobileDescription : enableTrainingApis ? trainingDescription : defaultDescription url = 'https://microsoft.github.io/onnxruntime/' licenses { license { diff --git a/java/build.gradle b/java/build.gradle index dffa264801886..c0a75f8165f7f 100644 --- a/java/build.gradle +++ b/java/build.gradle @@ -19,7 +19,7 @@ version = rootProject.file('../VERSION_NUMBER').text.trim() def cmakeBuildDir = System.properties['cmakeBuildDir'] def useCUDA = System.properties['USE_CUDA'] def useROCM = System.properties['USE_ROCM'] -def enableTrainingApis = System.properties['ENABLE_TRAINING_APIS'] +boolean enableTrainingApis = (System.properties['ENABLE_TRAINING_APIS'] ?: "0") == "1" def cmakeJavaDir = "${cmakeBuildDir}/java" def cmakeNativeLibDir = "${cmakeJavaDir}/native-lib" def cmakeNativeJniDir = "${cmakeJavaDir}/native-jni" @@ -29,9 +29,14 @@ def cmakeBuildOutputDir = "${cmakeJavaDir}/build" def mavenUser = System.properties['mavenUser'] def mavenPwd = System.properties['mavenPwd'] -def tmpArtifactId = enableTrainingApis == null ? project.name : project.name + "-training" +def tmpArtifactId = enableTrainingApis ? project.name + "-training" : project.name def mavenArtifactId = (useCUDA == null && useROCM == null) ? tmpArtifactId : tmpArtifactId + "_gpu" +def defaultDescription = 'ONNX Runtime is a performance-focused inference engine for ONNX (Open Neural Network Exchange) models.' +def trainingDescription = 'ONNX Runtime Training is a training and inference package for ONNX ' + + '(Open Neural Network Exchange) models. This package is targeted for Learning on The Edge aka On-Device Training ' + + 'See https://github.com/microsoft/onnxruntime-training-examples/tree/master/on_device_training for more details.' + java { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 @@ -97,6 +102,10 @@ compileTestJava { } } +sourceSets.main.java { + srcDirs = ['src/main/java', 'src/main/jvm'] +} + sourceSets.test { // add test resource files resources.srcDirs += [ @@ -176,7 +185,7 @@ test { if (cmakeBuildDir != null) { workingDir cmakeBuildDir } - systemProperties System.getProperties().subMap(['USE_CUDA', 'USE_ROCM', 'USE_TENSORRT', 'USE_DNNL', 'USE_OPENVINO', 'JAVA_FULL_TEST', 'ENABLE_TRAINING_APIS']) + systemProperties System.getProperties().subMap(['USE_CUDA', 'USE_ROCM', 'USE_TENSORRT', 'USE_DNNL', 'USE_OPENVINO', 'USE_COREML', 'JAVA_FULL_TEST', 'ENABLE_TRAINING_APIS']) testLogging { events "passed", "skipped", "failed" showStandardStreams = true @@ -201,8 +210,8 @@ publishing { from components.java pom { - name = 'onnx-runtime' - description = 'ONNX Runtime is a performance-focused inference engine for ONNX (Open Neural Network Exchange) models.' + name = enableTrainingApis ? 'onnxruntime-training' : 'onnx-runtime' + description = enableTrainingApis ? trainingDescription : defaultDescription url = 'https://microsoft.github.io/onnxruntime/' licenses { license { diff --git a/java/src/main/android/ai/onnxruntime/platform/Fp16Conversions.java b/java/src/main/android/ai/onnxruntime/platform/Fp16Conversions.java new file mode 100644 index 0000000000000..dd7dd07fc1f5d --- /dev/null +++ b/java/src/main/android/ai/onnxruntime/platform/Fp16Conversions.java @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Licensed under the MIT License. + */ +package ai.onnxruntime.platform; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; +import java.nio.ShortBuffer; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** * Conversions between fp16, bfloat16 and fp32. */ +public final class Fp16Conversions { + private static final Logger logger = Logger.getLogger(Fp16Conversions.class.getName()); + + /** + * Rounds a buffer of floats into a buffer containing fp16 values (stored as shorts in Java). + * + *

Respects the position and limit of the input buffer. + * + * @param buf The buffer of floats. + * @return A buffer of fp16 values stored as shorts. + */ + public static ShortBuffer convertFloatBufferToFp16Buffer(FloatBuffer buf) { + int pos = buf.position(); + int remaining = buf.remaining(); + ShortBuffer output = + ByteBuffer.allocateDirect(remaining * 2).order(ByteOrder.nativeOrder()).asShortBuffer(); + for (int i = 0; i < remaining; i++) { + output.put(i, floatToFp16(buf.get(i + pos))); + } + return output; + } + + /** + * Casts a buffer of fp16 values stored as shorts into a buffer of floats. + * + *

Respects the position and limit of the input buffer. + * + * @param buf The buffer of fp16 values stored as shorts. + * @return A buffer of float values. + */ + public static FloatBuffer convertFp16BufferToFloatBuffer(ShortBuffer buf) { + int pos = buf.position(); + int remaining = buf.remaining(); + FloatBuffer output = + ByteBuffer.allocateDirect(remaining * 4).order(ByteOrder.nativeOrder()).asFloatBuffer(); + for (int i = 0; i < remaining; i++) { + output.put(i, fp16ToFloat(buf.get(i + pos))); + } + return output; + } + + /** + * Rounds a buffer of floats into a buffer containing bf16 values (stored as shorts in Java). + * + *

Respects the position and limit of the input buffer. + * + * @param buf The buffer of floats. + * @return A buffer of bf16 values stored as shorts. + */ + public static ShortBuffer convertFloatBufferToBf16Buffer(FloatBuffer buf) { + int pos = buf.position(); + int remaining = buf.remaining(); + ShortBuffer output = + ByteBuffer.allocateDirect(remaining * 2).order(ByteOrder.nativeOrder()).asShortBuffer(); + for (int i = 0; i < remaining; i++) { + output.put(i, floatToBf16(buf.get(i + pos))); + } + return output; + } + + /** + * Casts a buffer of bf16 values stored as shorts into a buffer of floats. + * + *

Respects the position and limit of the input buffer. + * + * @param buf The buffer of bf16 values stored as shorts. + * @return A buffer of float values. + */ + public static FloatBuffer convertBf16BufferToFloatBuffer(ShortBuffer buf) { + int pos = buf.position(); + int remaining = buf.remaining(); + FloatBuffer output = + ByteBuffer.allocateDirect(remaining * 4).order(ByteOrder.nativeOrder()).asFloatBuffer(); + for (int i = 0; i < remaining; i++) { + output.put(i, bf16ToFloat(buf.get(i + pos))); + } + return output; + } + + /** + * Converts a fp16 value stored in a short into a float value. + * + *

On Android this is an alias for {@link #mlasFp16ToFloat(short)}. + * + * @param input The fp16 value. + * @return The float value. + */ + public static float fp16ToFloat(short input) { + return mlasFp16ToFloat(input); + } + + /** + * Converts a float value into a fp16 value stored in a short. + * + *

On Android this is an alias for {@link #mlasFloatToFp16(float)}. + * + * @param input The float value. + * @return The fp16 value. + */ + public static short floatToFp16(float input) { + return mlasFloatToFp16(input); + } + + /** + * Upcasts a fp16 value to a float. Mirrors the conversion in MLAS. + * + * @param input A uint16_t representing an IEEE half precision float. + * @return A float. + */ + public static float mlasFp16ToFloat(short input) { + // Port of MLAS_Half2Float from onnxruntime/core/mlas/inc/mlas_float16.h + final int MAGIC = 113 << 23; + // exponent mask after shift + final int SHIFTED_EXP = 0x7c00 << 13; + + // exponent/mantissa bits + int bits = (input & 0x7fff) << 13; + // just the exponent + final int exp = SHIFTED_EXP & bits; + // exponent adjust + bits += (127 - 15) << 23; + + // handle exponent special cases + if (exp == SHIFTED_EXP) { + // Inf/NaN? + // extra exp adjust + bits += (128 - 16) << 23; + } else if (exp == 0) { + // Zero/Denormal? + // extra exp adjust + bits += (1 << 23); + // renormalize + float tmp = Float.intBitsToFloat(bits) - Float.intBitsToFloat(MAGIC); + bits = Float.floatToIntBits(tmp); + } + + // sign bit + bits |= (input & 0x8000) << 16; + + return Float.intBitsToFloat(bits); + } + + /** + * Rounds a float value to fp16. Mirrors the conversion in MLAS. + * + * @param input A float value. + * @return The value rounded to an IEEE half precision value. + */ + public static short mlasFloatToFp16(float input) { + // Port of MLAS_Float2Half from onnxruntime/core/mlas/inc/mlas_float16.h + int bits = Float.floatToIntBits(input); + final int F32_INFINITY = Float.floatToIntBits(Float.POSITIVE_INFINITY); + final int F16_MAX = (127 + 16) << 23; + final int DENORM_MAGIC = ((127 - 15) + (23 - 10) + 1) << 23; + final int SIGN_MASK = 0x80000000; + final int ROUNDING_CONST = ((15 - 127) << 23) + 0xfff; + + int sign = bits & SIGN_MASK; + // mask out sign bit + bits ^= sign; + + short output; + if (bits >= F16_MAX) { + // Inf or NaN (all exponent bits set) + output = (bits > F32_INFINITY) ? (short) 0x7e00 : (short) 0x7c00; + } else { + if (bits < (113 << 23)) { + // Subnormal or zero + // use a magic value to align our 10 mantissa bits at the bottom of + // the float. as long as FP addition is round-to-nearest-even this + // just works. + float tmp = Float.intBitsToFloat(bits) + Float.intBitsToFloat(DENORM_MAGIC); + + // and one integer subtract of the bias later, we have our final float! + output = (short) (Float.floatToIntBits(tmp) - DENORM_MAGIC); + } else { + int mant_odd = (bits >> 13) & 1; // resulting mantissa is odd + + // update exponent, rounding bias part 1 + bits += ROUNDING_CONST; + // rounding bias part 2 + bits += mant_odd; + // take the bits! + output = (short) (bits >> 13); + } + } + + // Add the sign back in + output = (short) (output | ((short) (sign >> 16))); + + return output; + } + + /** + * Converts a bf16 value stored in a short into a float value. + * + * @param input A uint16_t representing a bfloat16 value. + * @return A float. + */ + public static float bf16ToFloat(short input) { + int bits = input << 16; + return Float.intBitsToFloat(bits); + } + + /** + * Converts a float into bf16. May not produce correct values for subnormal floats. + * + *

Rounds to nearest even. + * + * @param input The float input. + * @return A bfloat16 value which is closest to the float. + */ + public static short floatToBf16(float input) { + int bits = Float.floatToIntBits(input); + int lsb = (bits >> 16) & 1; + int roundingBias = 0x7fff + lsb; + bits += roundingBias; + return (short) (bits >> 16); + } +} diff --git a/java/src/main/android/ai/onnxruntime/platform/package-info.java b/java/src/main/android/ai/onnxruntime/platform/package-info.java new file mode 100644 index 0000000000000..0899c4f283311 --- /dev/null +++ b/java/src/main/android/ai/onnxruntime/platform/package-info.java @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Licensed under the MIT License. + */ + +/** + * A package of platform specific code, used to swap out Java implementations which don't run on Android. + * + *

Classes in this package should always have the same public methods. + * + *

This is the Android version of the package. + */ +package ai.onnxruntime.platform; \ No newline at end of file diff --git a/java/src/main/java/ai/onnxruntime/OnnxJavaType.java b/java/src/main/java/ai/onnxruntime/OnnxJavaType.java index 12b720327f3ea..24bf6ad4b95fa 100644 --- a/java/src/main/java/ai/onnxruntime/OnnxJavaType.java +++ b/java/src/main/java/ai/onnxruntime/OnnxJavaType.java @@ -1,34 +1,53 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. * Licensed under the MIT License. */ package ai.onnxruntime; import ai.onnxruntime.TensorInfo.OnnxTensorType; -/** An enum representing onnxruntime supported Java primitive types (and String). */ +/** An enum representing ONNX Runtime supported Java primitive types (and String). */ public enum OnnxJavaType { + /** A 32-bit floating point value. */ FLOAT(1, float.class, 4), + /** A 64-bit floating point value. */ DOUBLE(2, double.class, 8), + /** An 8-bit signed integer value. */ INT8(3, byte.class, 1), + /** A 16-bit signed integer value. */ INT16(4, short.class, 2), + /** A 32-bit signed integer value. */ INT32(5, int.class, 4), + /** A 64-bit signed integer value. */ INT64(6, long.class, 8), + /** A boolean value stored in a single byte. */ BOOL(7, boolean.class, 1), + /** A UTF-8 string. */ STRING(8, String.class, 4), + /** A 8-bit unsigned integer value. */ UINT8(9, byte.class, 1), + /** A IEEE 16-bit floating point value. */ + FLOAT16(10, short.class, 2), + /** A non-IEEE 16-bit floating point value, with 8 exponent bits and 7 mantissa bits. */ + BFLOAT16(11, short.class, 2), + /** An unknown type used as an error condition or a sentinel. */ UNKNOWN(0, Object.class, 0); - private static final OnnxJavaType[] values = new OnnxJavaType[10]; + private static final OnnxJavaType[] values; static { - for (OnnxJavaType ot : OnnxJavaType.values()) { + OnnxJavaType[] tmpValues = OnnxJavaType.values(); + values = new OnnxJavaType[tmpValues.length]; + for (OnnxJavaType ot : tmpValues) { values[ot.value] = ot; } } + /** The native value of the enum. */ public final int value; + /** The Java side type used as the carrier. */ public final Class clazz; + /** The number of bytes used by a single value of this type. */ public final int size; OnnxJavaType(int value, Class clazz, int size) { @@ -76,6 +95,9 @@ public static OnnxJavaType mapFromOnnxTensorType(OnnxTensorType onnxValue) { case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64: return OnnxJavaType.INT64; case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16: + return OnnxJavaType.FLOAT16; + case ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16: + return OnnxJavaType.BFLOAT16; case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT: return OnnxJavaType.FLOAT; case ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE: @@ -87,7 +109,6 @@ public static OnnxJavaType mapFromOnnxTensorType(OnnxTensorType onnxValue) { case ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED: case ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX64: case ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX128: - case ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16: default: return OnnxJavaType.UNKNOWN; } diff --git a/java/src/main/java/ai/onnxruntime/OnnxMap.java b/java/src/main/java/ai/onnxruntime/OnnxMap.java index 53e9e64432be1..354ebec61274d 100644 --- a/java/src/main/java/ai/onnxruntime/OnnxMap.java +++ b/java/src/main/java/ai/onnxruntime/OnnxMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. * Licensed under the MIT License. */ package ai.onnxruntime; @@ -12,8 +12,8 @@ /** * A container for a map returned by {@link OrtSession#run(Map)}. * - *

Supported types are those mentioned in "onnxruntime_c_api.h", keys: String and Long, values: - * String, Long, Float, Double. + *

Supported types are those mentioned in {@code onnxruntime_c_api.h}, keys: String and Long, + * values: String, Long, Float, Double. */ public class OnnxMap implements OnnxValue { @@ -27,11 +27,17 @@ public class OnnxMap implements OnnxValue { /** An enum representing the Java type of the values stored in an {@link OnnxMap}. */ public enum OnnxMapValueType { + /** An invalid Map value type. */ INVALID(0), + /** A String value. */ STRING(1), + /** A 64-bit signed integer value. */ LONG(2), + /** A 32-bit floating point value. */ FLOAT(3), + /** A 64-bit floating point value. */ DOUBLE(4); + /** The native enum value. */ final int value; OnnxMapValueType(int value) { @@ -89,8 +95,10 @@ public static OnnxMapValueType mapFromOnnxJavaType(OnnxJavaType type) { } } + /** The native pointer. */ final long nativeHandle; + /** The pointer to the allocator used by this {@code OnnxMap}. */ final long allocatorHandle; private final MapInfo info; diff --git a/java/src/main/java/ai/onnxruntime/OnnxRuntime.java b/java/src/main/java/ai/onnxruntime/OnnxRuntime.java index c58401f3c8a1b..ed739dd9729d9 100644 --- a/java/src/main/java/ai/onnxruntime/OnnxRuntime.java +++ b/java/src/main/java/ai/onnxruntime/OnnxRuntime.java @@ -1,9 +1,5 @@ /* -<<<<<<< HEAD * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. -======= - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. ->>>>>>> 98b8e2e31 (More fixes, tests now pass.) * Licensed under the MIT License. */ package ai.onnxruntime; @@ -438,7 +434,7 @@ private static String mapLibraryName(String library) { * *

Throws IllegalArgumentException if a provider isn't recognised (note this exception should * only happen during development of ONNX Runtime, if it happens at any other point, file an issue - * on Github). + * on GitHub). * * @param ortApiHandle The API Handle. * @return The enum set. diff --git a/java/src/main/java/ai/onnxruntime/OnnxSequence.java b/java/src/main/java/ai/onnxruntime/OnnxSequence.java index ff58a862cb50f..93e1be21588b4 100644 --- a/java/src/main/java/ai/onnxruntime/OnnxSequence.java +++ b/java/src/main/java/ai/onnxruntime/OnnxSequence.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. * Licensed under the MIT License. */ package ai.onnxruntime; @@ -33,6 +33,7 @@ public class OnnxSequence implements OnnxValue { } } + /** The native pointer. */ final long nativeHandle; private final long allocatorHandle; diff --git a/java/src/main/java/ai/onnxruntime/OnnxSparseTensor.java b/java/src/main/java/ai/onnxruntime/OnnxSparseTensor.java index 668e6e07ceccd..53bd4c7f9b3e6 100644 --- a/java/src/main/java/ai/onnxruntime/OnnxSparseTensor.java +++ b/java/src/main/java/ai/onnxruntime/OnnxSparseTensor.java @@ -1,11 +1,10 @@ /* - * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. * Licensed under the MIT License. */ package ai.onnxruntime; -import static ai.onnxruntime.OnnxTensor.fp16ToFloat; - +import ai.onnxruntime.platform.Fp16Conversions; import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -111,6 +110,16 @@ public static OnnxSparseTensor createSparseTensor( return createSparseTensor(env, env.defaultAllocator, tensor); } + /** + * Creates a Sparse Tensor in ORT from the Java side representation. + * + * @param env The OrtEnvironment. + * @param allocator The memory allocator. + * @param tensor The Java side representation. + * @param The buffer type. + * @return The sparse tensor in ORT. + * @throws OrtException If the tensor could not be created or was invalid. + */ static OnnxSparseTensor createSparseTensor( OrtEnvironment env, OrtAllocator allocator, SparseTensor tensor) throws OrtException { if (!allocator.isClosed()) { @@ -315,26 +324,23 @@ public Buffer getValuesBuffer() { getValuesBuffer(OnnxRuntime.ortApiHandle, nativeHandle).order(ByteOrder.nativeOrder()); switch (info.type) { case FLOAT: - if (info.onnxType == TensorInfo.OnnxTensorType.ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16) { - ShortBuffer shortBuffer = buffer.asShortBuffer(); - int bufferCap = shortBuffer.capacity(); - FloatBuffer output = FloatBuffer.allocate(bufferCap); - for (int i = 0; i < bufferCap; i++) { - output.put(fp16ToFloat(shortBuffer.get(i))); - } - output.rewind(); - return output; - } else if (info.onnxType - == TensorInfo.OnnxTensorType.ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16) { - throw new IllegalArgumentException("BFloat16 is not supported."); - } else { - // regular fp32 + { FloatBuffer floatBuf = buffer.asFloatBuffer(); FloatBuffer output = FloatBuffer.allocate(floatBuf.capacity()); output.put(floatBuf); output.rewind(); return output; } + case FLOAT16: + { + ShortBuffer shortBuffer = buffer.asShortBuffer(); + return Fp16Conversions.convertFp16BufferToFloatBuffer(shortBuffer); + } + case BFLOAT16: + { + ShortBuffer shortBuffer = buffer.asShortBuffer(); + return Fp16Conversions.convertBf16BufferToFloatBuffer(shortBuffer); + } case DOUBLE: { DoubleBuffer doubleBuf = buffer.asDoubleBuffer(); @@ -605,6 +611,8 @@ public static SparseTensorType mapFromInt(int value) { * *

Will be sealed to {@link COOTensor}, {@link CSRCTensor} and {@link BlockSparseTensor} one * day. + * + * @param The type of the indices buffer. */ public abstract static class SparseTensor { private final long[] indicesShape; @@ -613,7 +621,9 @@ public abstract static class SparseTensor { private final OnnxJavaType type; private final long numNonZero; + /** The buffer holding the indices. */ final T indices; + /** The buffer holding the values. */ final Buffer values; SparseTensor( diff --git a/java/src/main/java/ai/onnxruntime/OnnxTensor.java b/java/src/main/java/ai/onnxruntime/OnnxTensor.java index 5703fb9c48495..09d2cefbb8224 100644 --- a/java/src/main/java/ai/onnxruntime/OnnxTensor.java +++ b/java/src/main/java/ai/onnxruntime/OnnxTensor.java @@ -4,6 +4,7 @@ */ package ai.onnxruntime; +import ai.onnxruntime.platform.Fp16Conversions; import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -18,6 +19,7 @@ * returned as outputs. */ public class OnnxTensor extends OnnxTensorLike { + /** * This reference is held for OnnxTensors backed by a Java nio buffer to ensure the buffer does * not go out of scope while the OnnxTensor exists. @@ -70,6 +72,12 @@ public Object getValue() throws OrtException { return getBool(OnnxRuntime.ortApiHandle, nativeHandle); case STRING: return getString(OnnxRuntime.ortApiHandle, nativeHandle); + case FLOAT16: + return Fp16Conversions.fp16ToFloat( + getShort(OnnxRuntime.ortApiHandle, nativeHandle, info.onnxType.value)); + case BFLOAT16: + return Fp16Conversions.bf16ToFloat( + getShort(OnnxRuntime.ortApiHandle, nativeHandle, info.onnxType.value)); case UNKNOWN: default: throw new OrtException("Extracting the value of an invalid Tensor."); @@ -126,30 +134,28 @@ public ByteBuffer getByteBuffer() { /** * Returns a copy of the underlying OnnxTensor as a FloatBuffer if it can be losslessly converted - * into a float (i.e. it's a float or fp16), otherwise it returns null. + * into a float (i.e. it's a float, fp16 or bf16), otherwise it returns null. * * @return A FloatBuffer copy of the OnnxTensor. */ public FloatBuffer getFloatBuffer() { if (info.type == OnnxJavaType.FLOAT) { - if (info.onnxType == TensorInfo.OnnxTensorType.ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16) { - // if it's fp16 we need to copy it out by hand. - ShortBuffer buffer = getBuffer().asShortBuffer(); - int bufferCap = buffer.capacity(); - FloatBuffer output = FloatBuffer.allocate(bufferCap); - for (int i = 0; i < bufferCap; i++) { - output.put(fp16ToFloat(buffer.get(i))); - } - output.rewind(); - return output; - } else { - // if it's fp32 use the efficient copy. - FloatBuffer buffer = getBuffer().asFloatBuffer(); - FloatBuffer output = FloatBuffer.allocate(buffer.capacity()); - output.put(buffer); - output.rewind(); - return output; - } + // if it's fp32 use the efficient copy. + FloatBuffer buffer = getBuffer().asFloatBuffer(); + FloatBuffer output = FloatBuffer.allocate(buffer.capacity()); + output.put(buffer); + output.rewind(); + return output; + } else if (info.type == OnnxJavaType.FLOAT16) { + // if it's fp16 we need to copy it out by hand. + ByteBuffer buf = getBuffer(); + ShortBuffer buffer = buf.asShortBuffer(); + return Fp16Conversions.convertFp16BufferToFloatBuffer(buffer); + } else if (info.type == OnnxJavaType.BFLOAT16) { + // if it's bf16 we need to copy it out by hand. + ByteBuffer buf = getBuffer(); + ShortBuffer buffer = buf.asShortBuffer(); + return Fp16Conversions.convertBf16BufferToFloatBuffer(buffer); } else { return null; } @@ -174,13 +180,15 @@ public DoubleBuffer getDoubleBuffer() { } /** - * Returns a copy of the underlying OnnxTensor as a ShortBuffer if the underlying type is int16 or - * uint16, otherwise it returns null. + * Returns a copy of the underlying OnnxTensor as a ShortBuffer if the underlying type is int16, + * uint16, fp16 or bf16, otherwise it returns null. * * @return A ShortBuffer copy of the OnnxTensor. */ public ShortBuffer getShortBuffer() { - if (info.type == OnnxJavaType.INT16) { + if ((info.type == OnnxJavaType.INT16) + || (info.type == OnnxJavaType.FLOAT16) + || (info.type == OnnxJavaType.BFLOAT16)) { ShortBuffer buffer = getBuffer().asShortBuffer(); ShortBuffer output = ShortBuffer.allocate(buffer.capacity()); output.put(buffer); @@ -270,19 +278,6 @@ private native void getArray(long apiHandle, long nativeHandle, Object carrier) private native void close(long apiHandle, long nativeHandle); - /** - * Mirrors the conversion in the C code. It's not precise if there are subnormal values, nor does - * it preserve all the different kinds of NaNs (which aren't representable in Java anyway). - * - * @param input A uint16_t representing an IEEE half precision float. - * @return A float. - */ - static float fp16ToFloat(short input) { - int output = - ((input & 0x8000) << 16) | (((input & 0x7c00) + 0x1C000) << 13) | ((input & 0x03FF) << 13); - return Float.intBitsToFloat(output); - } - /** * Create a Tensor from a Java primitive, primitive multidimensional array or String * multidimensional array. The shape is inferred from the object using reflection. The default diff --git a/java/src/main/java/ai/onnxruntime/OnnxTensorLike.java b/java/src/main/java/ai/onnxruntime/OnnxTensorLike.java index d0c874c4a1e15..c2989fe296dc2 100644 --- a/java/src/main/java/ai/onnxruntime/OnnxTensorLike.java +++ b/java/src/main/java/ai/onnxruntime/OnnxTensorLike.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. * Licensed under the MIT License. */ package ai.onnxruntime; @@ -19,10 +19,13 @@ public abstract class OnnxTensorLike implements OnnxValue { } } + /** The native pointer. */ protected final long nativeHandle; + /** The pointer to the native memory allocator. */ protected final long allocatorHandle; + /** The size and shape information for this tensor. */ protected final TensorInfo info; /** diff --git a/java/src/main/java/ai/onnxruntime/OnnxValue.java b/java/src/main/java/ai/onnxruntime/OnnxValue.java index 8de6b9c58b1f5..752a0e74267d3 100644 --- a/java/src/main/java/ai/onnxruntime/OnnxValue.java +++ b/java/src/main/java/ai/onnxruntime/OnnxValue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023 Oracle and/or its affiliates. All rights reserved. * Licensed under the MIT License. */ package ai.onnxruntime; @@ -15,12 +15,19 @@ public interface OnnxValue extends AutoCloseable { /** The type of the {@link OnnxValue}, mirroring the id in the C API. */ public enum OnnxValueType { + /** An unknown OrtValue type. */ ONNX_TYPE_UNKNOWN(0), + /** A tensor. */ ONNX_TYPE_TENSOR(1), + /** A sequence of tensors or maps. */ ONNX_TYPE_SEQUENCE(2), + /** A map. */ ONNX_TYPE_MAP(3), + /** An opaque type not accessible from Java. */ ONNX_TYPE_OPAQUE(4), + /** A sparse tensor. */ ONNX_TYPE_SPARSETENSOR(5), + /** An optional input value. */ ONNX_TYPE_OPTIONAL(6); /** The id number of this type in the C API. */ diff --git a/java/src/main/java/ai/onnxruntime/OrtAllocator.java b/java/src/main/java/ai/onnxruntime/OrtAllocator.java index 901531159ac33..dca0dbdbb0507 100644 --- a/java/src/main/java/ai/onnxruntime/OrtAllocator.java +++ b/java/src/main/java/ai/onnxruntime/OrtAllocator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. * Licensed under the MIT License. */ package ai.onnxruntime; @@ -17,6 +17,7 @@ class OrtAllocator implements AutoCloseable { } } + /** The native pointer. */ final long handle; private final boolean isDefault; @@ -53,7 +54,7 @@ public boolean isDefault() { } /** - * Closes the allocator, must be done after all it's child objects have been closed. + * Closes the allocator, must be done after all its child objects have been closed. * *

The default allocator is not closeable, and this operation is a no-op on that allocator. * diff --git a/java/src/main/java/ai/onnxruntime/OrtEnvironment.java b/java/src/main/java/ai/onnxruntime/OrtEnvironment.java index 22014f44e2199..26137e88478b5 100644 --- a/java/src/main/java/ai/onnxruntime/OrtEnvironment.java +++ b/java/src/main/java/ai/onnxruntime/OrtEnvironment.java @@ -12,8 +12,9 @@ import java.util.logging.Logger; /** - * The host object for the onnx-runtime system. Can create {@link OrtSession}s which encapsulate - * specific models. + * The host object for the ONNX Runtime system. Can create {@link OrtSession}s which encapsulate + * specific models. This object should be instantiated before any other ONNX Runtime classes are + * created. * *

There can be at most one OrtEnvironment object created in a JVM lifetime. This class * implements {@link AutoCloseable} as before for backwards compatibility with 1.10 and earlier, but @@ -24,6 +25,7 @@ public final class OrtEnvironment implements AutoCloseable { private static final Logger logger = Logger.getLogger(OrtEnvironment.class.getName()); + /** The default name for ORT environments constructed from Java. */ public static final String DEFAULT_NAME = "ort-java"; static { @@ -357,7 +359,7 @@ public boolean isTrainingEnabled() { /** * Turns on or off the telemetry. * - * @param sendTelemetry If true then send telemetry on onnxruntime usage. + * @param sendTelemetry If true then send telemetry on ONNX Runtime usage. * @throws OrtException If the call failed. */ public void setTelemetry(boolean sendTelemetry) throws OrtException { diff --git a/java/src/main/java/ai/onnxruntime/OrtException.java b/java/src/main/java/ai/onnxruntime/OrtException.java index b6ba837d483df..5ec58ea137124 100644 --- a/java/src/main/java/ai/onnxruntime/OrtException.java +++ b/java/src/main/java/ai/onnxruntime/OrtException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. * Licensed under the MIT License. */ package ai.onnxruntime; @@ -8,6 +8,7 @@ public class OrtException extends Exception { private static final long serialVersionUID = 1L; + /** The OrtErrorCode for this exception. */ private final OrtErrorCode errorCode; /** @@ -51,22 +52,35 @@ public OrtErrorCode getCode() { } /** - * Maps the OrtErrorCode struct in "onnxruntime_c_api.h" with an additional entry for Java side - * errors. + * Maps the {@code OrtErrorCode} struct in {@code onnxruntime_c_api.h} with an additional entry + * for Java side errors. */ public enum OrtErrorCode { + /** An unknown error occurred in the Java API. */ ORT_JAVA_UNKNOWN(-1), + /** The operation completed without error. */ ORT_OK(0), + /** The operation failed. */ ORT_FAIL(1), + /** The operation received an invalid argument. */ ORT_INVALID_ARGUMENT(2), + /** The operation could not load the required file. */ ORT_NO_SUCHFILE(3), + /** The operation could not use the model. */ ORT_NO_MODEL(4), + /** There is an internal error in the ORT engine. */ ORT_ENGINE_ERROR(5), + /** The operation threw a runtime exception. */ ORT_RUNTIME_EXCEPTION(6), + /** The provided protobuf was invalid. */ ORT_INVALID_PROTOBUF(7), + /** The model was loaded. */ ORT_MODEL_LOADED(8), + /** The requested operation has not been implemented. */ ORT_NOT_IMPLEMENTED(9), + /** The ONNX graph is invalid. */ ORT_INVALID_GRAPH(10), + /** The ORT execution provider failed. */ ORT_EP_FAIL(11); private final int value; diff --git a/java/src/main/java/ai/onnxruntime/OrtLoggingLevel.java b/java/src/main/java/ai/onnxruntime/OrtLoggingLevel.java index 1e0fc60cbe474..fbeafdc03b5bf 100644 --- a/java/src/main/java/ai/onnxruntime/OrtLoggingLevel.java +++ b/java/src/main/java/ai/onnxruntime/OrtLoggingLevel.java @@ -1,17 +1,22 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. * Licensed under the MIT License. */ package ai.onnxruntime; import java.util.logging.Logger; -/** The logging level for messages from the environment and session. */ +/** The logging severity level. */ public enum OrtLoggingLevel { + /** Print all log messages. */ ORT_LOGGING_LEVEL_VERBOSE(0), + /** Print info and higher level log messages. */ ORT_LOGGING_LEVEL_INFO(1), + /** Print warning and higher level log messages. */ ORT_LOGGING_LEVEL_WARNING(2), + /** Print error log messages. */ ORT_LOGGING_LEVEL_ERROR(3), + /** Print only fatal log messages. */ ORT_LOGGING_LEVEL_FATAL(4); private final int value; diff --git a/java/src/main/java/ai/onnxruntime/OrtProvider.java b/java/src/main/java/ai/onnxruntime/OrtProvider.java index cb35bf4f507f5..ae9cb9f908629 100644 --- a/java/src/main/java/ai/onnxruntime/OrtProvider.java +++ b/java/src/main/java/ai/onnxruntime/OrtProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. * Licensed under the MIT License. */ package ai.onnxruntime; @@ -9,21 +9,38 @@ /** The execution providers available through the Java API. */ public enum OrtProvider { + /** The CPU execution provider. */ CPU("CPUExecutionProvider"), + /** CUDA execution provider for Nvidia GPUs. */ CUDA("CUDAExecutionProvider"), + /** The Intel Deep Neural Network Library execution provider. */ DNNL("DnnlExecutionProvider"), + /** The OpenVINO execution provider. */ OPEN_VINO("OpenVINOExecutionProvider"), + /** The AMD/Xilinx VitisAI execution provider. */ VITIS_AI("VitisAIExecutionProvider"), + /** The TensorRT execution provider for Nvidia GPUs. */ TENSOR_RT("TensorrtExecutionProvider"), + /** The Android NNAPI execution provider. */ NNAPI("NnapiExecutionProvider"), + /** The RockChip NPU execution provider. */ RK_NPU("RknpuExecutionProvider"), + /** The Windows DirectML execution provider. */ DIRECT_ML("DmlExecutionProvider"), + /** The AMD MIGraphX execution provider. */ MI_GRAPH_X("MIGraphXExecutionProvider"), + /** The ARM Compute Library execution provider. */ ACL("ACLExecutionProvider"), + /** The ARM NN execution provider. */ ARM_NN("ArmNNExecutionProvider"), + /** The AMD ROCm execution provider. */ ROCM("ROCMExecutionProvider"), + /** The Apple CoreML execution provider. */ CORE_ML("CoreMLExecutionProvider"), - XNNPACK("XnnpackExecutionProvider"); + /** The XNNPACK execution provider. */ + XNNPACK("XnnpackExecutionProvider"), + /** The Azure remote endpoint execution provider. */ + AZURE("AzureExecutionProvider"); private static final Map valueMap = new HashMap<>(values().length); diff --git a/java/src/main/java/ai/onnxruntime/OrtProviderOptions.java b/java/src/main/java/ai/onnxruntime/OrtProviderOptions.java index 63dcb525efea4..39a5121fad7a2 100644 --- a/java/src/main/java/ai/onnxruntime/OrtProviderOptions.java +++ b/java/src/main/java/ai/onnxruntime/OrtProviderOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. * Licensed under the MIT License. */ package ai.onnxruntime; @@ -18,6 +18,7 @@ public abstract class OrtProviderOptions implements AutoCloseable { } } + /** The native pointer. */ protected final long nativeHandle; /** diff --git a/java/src/main/java/ai/onnxruntime/OrtSession.java b/java/src/main/java/ai/onnxruntime/OrtSession.java index 536fd99598e46..435f86daa5fe2 100644 --- a/java/src/main/java/ai/onnxruntime/OrtSession.java +++ b/java/src/main/java/ai/onnxruntime/OrtSession.java @@ -472,11 +472,25 @@ public static class SessionOptions implements AutoCloseable { /** * The optimisation level to use. Needs to be kept in sync with the GraphOptimizationLevel enum * in the C API. + * + *

See Graph + * Optimizations for more details. */ public enum OptLevel { + /** Apply no optimizations to the ONNX graph. */ NO_OPT(0), + /** + * Apply basic optimizations such as constant folding, redundant computation elimination and + * node fusions to the ONNX graph. + */ BASIC_OPT(1), + /** + * Applies all the basic optimizations plus more complex node fusion operations to the ONNX + * graph. + */ EXTENDED_OPT(2), + /** Applies all available optimizations to the ONNX graph. */ ALL_OPT(99); private final int id; @@ -499,7 +513,14 @@ public int getID() { * The execution mode to use. Needs to be kept in sync with the ExecutionMode enum in the C API. */ public enum ExecutionMode { + /** + * Executes all nodes sequentially. + * + *

This is the default, and usually provides the most speedup as intra-op parallelism + * provides the most benefit. + */ SEQUENTIAL(0), + /** Executes some nodes in parallel. */ PARALLEL(1); private final int id; @@ -517,6 +538,14 @@ public int getID() { } } + static { + try { + OnnxRuntime.init(); + } catch (IOException e) { + throw new RuntimeException("Failed to load onnx-runtime library", e); + } + } + private final long nativeHandle; private final List customLibraryHandles; @@ -785,6 +814,54 @@ public Map getConfigEntries() { return Collections.unmodifiableMap(configEntries); } + /** + * Adds in the supplied externally loaded initializers. + * + *

Note the initializers are copied into the session once it has been created, and the native + * references are removed from this {@code SessionOptions}. Once the session has been created + * those initializers can be closed. This is a different lifetime to initializers added via + * {@link #addInitializer(String, OnnxTensorLike)}. The initializers must be created from {@link + * java.nio.Buffer} objects. + * + * @param initializers The map of names to initializers. + * @throws OrtException If the initializers could not be loaded. + */ + public void addExternalInitializers(Map initializers) + throws OrtException { + checkClosed(); + if (initializers.isEmpty()) { + return; + } + String[] names = new String[initializers.size()]; + long[] handles = new long[initializers.size()]; + int i = 0; + for (Map.Entry e : initializers.entrySet()) { + names[i] = e.getKey(); + handles[i] = e.getValue().nativeHandle; + i++; + } + addExternalInitializers(OnnxRuntime.ortApiHandle, nativeHandle, names, handles); + } + + /** + * Adds an initializer to override one from the ONNX model. + * + *

Note the initializer lifetime must outlive the session and session options. This is a + * different lifetime to initializers added via {@link #addExternalInitializers(Map)}. The + * initializers must be created from {@link java.nio.Buffer} objects. + * + * @param name The initializer name. + * @param initializer The initializer value. + * @throws OrtException If the initializer could not be loaded into the session options. + */ + public void addInitializer(String name, OnnxTensorLike initializer) throws OrtException { + checkClosed(); + if (name.trim().isEmpty()) { + throw new IllegalArgumentException("Initializer name was blank"); + } + addInitializer(OnnxRuntime.ortApiHandle, nativeHandle, name, initializer.getNativeHandle()); + } + /** * Add CUDA as an execution backend, using device 0. * @@ -1088,6 +1165,13 @@ private native void addFreeDimensionOverrideByName( long apiHandle, long nativeHandle, String dimensionName, long dimensionValue) throws OrtException; + private native void addExternalInitializers( + long apiHandle, long nativeHandle, String[] names, long[] tensorHandles) + throws OrtException; + + private native void addInitializer( + long apiHandle, long nativeHandle, String name, long tensorHandle) throws OrtException; + private native void disablePerSessionThreads(long apiHandle, long nativeHandle) throws OrtException; @@ -1164,6 +1248,14 @@ private native void addExecutionProvider( /** Used to control logging and termination of a call to {@link OrtSession#run}. */ public static class RunOptions implements AutoCloseable { + static { + try { + OnnxRuntime.init(); + } catch (IOException e) { + throw new RuntimeException("Failed to load onnx-runtime library", e); + } + } + private final long nativeHandle; private boolean closed = false; diff --git a/java/src/main/java/ai/onnxruntime/OrtTrainingSession.java b/java/src/main/java/ai/onnxruntime/OrtTrainingSession.java index 51641cc97d911..8c03c5b80433c 100644 --- a/java/src/main/java/ai/onnxruntime/OrtTrainingSession.java +++ b/java/src/main/java/ai/onnxruntime/OrtTrainingSession.java @@ -221,6 +221,72 @@ public Set getEvalOutputNames() { return evalOutputNames; } + /** + * Adds a float property to this training session checkpoint. + * + * @param name The property name. + * @param value The property value. + * @throws OrtException If the call failed. + */ + public void addProperty(String name, float value) throws OrtException { + checkpoint.addProperty(name, value); + } + + /** + * Adds a int property to this training session checkpoint. + * + * @param name The property name. + * @param value The property value. + * @throws OrtException If the call failed. + */ + public void addProperty(String name, int value) throws OrtException { + checkpoint.addProperty(name, value); + } + + /** + * Adds a String property to this training session checkpoint. + * + * @param name The property name. + * @param value The property value. + * @throws OrtException If the call failed. + */ + public void addProperty(String name, String value) throws OrtException { + checkpoint.addProperty(name, value); + } + + /** + * Gets a float property from this training session checkpoint. + * + * @param name The property name. + * @return The property value. + * @throws OrtException If the property does not exist, or is of the wrong type. + */ + public float getFloatProperty(String name) throws OrtException { + return checkpoint.getFloatProperty(allocator, name); + } + + /** + * Gets a int property from this training session checkpoint. + * + * @param name The property name. + * @return The property value. + * @throws OrtException If the property does not exist, or is of the wrong type. + */ + public int getIntProperty(String name) throws OrtException { + return checkpoint.getIntProperty(allocator, name); + } + + /** + * Gets a String property from this training session checkpoint. + * + * @param name The property name. + * @return The property value. + * @throws OrtException If the property does not exist, or is of the wrong type. + */ + public String getStringProperty(String name) throws OrtException { + return checkpoint.getStringProperty(allocator, name); + } + /** Checks if the OrtTrainingSession is closed, if so throws {@link IllegalStateException}. */ private void checkClosed() { if (closed) { @@ -927,6 +993,93 @@ public void saveCheckpoint(Path outputPath, boolean saveOptimizer) throws OrtExc saveOptimizer); } + /** + * Adds a float property to this checkpoint. + * + * @param name The property name. + * @param value The property value. + * @throws OrtException If the call failed. + */ + public void addProperty(String name, float value) throws OrtException { + addProperty( + OnnxRuntime.ortApiHandle, OnnxRuntime.ortTrainingApiHandle, nativeHandle, name, value); + } + + /** + * Adds a int property to this checkpoint. + * + * @param name The property name. + * @param value The property value. + * @throws OrtException If the call failed. + */ + public void addProperty(String name, int value) throws OrtException { + addProperty( + OnnxRuntime.ortApiHandle, OnnxRuntime.ortTrainingApiHandle, nativeHandle, name, value); + } + + /** + * Adds a String property to this checkpoint. + * + * @param name The property name. + * @param value The property value. + * @throws OrtException If the call failed. + */ + public void addProperty(String name, String value) throws OrtException { + addProperty( + OnnxRuntime.ortApiHandle, OnnxRuntime.ortTrainingApiHandle, nativeHandle, name, value); + } + + /** + * Gets a float property from this checkpoint. + * + * @param allocator The allocator. + * @param name The property name. + * @return The property value. + * @throws OrtException If the property does not exist, or is of the wrong type. + */ + public float getFloatProperty(OrtAllocator allocator, String name) throws OrtException { + return getFloatProperty( + OnnxRuntime.ortApiHandle, + OnnxRuntime.ortTrainingApiHandle, + nativeHandle, + allocator.handle, + name); + } + + /** + * Gets a int property from this checkpoint. + * + * @param allocator The allocator. + * @param name The property name. + * @return The property value. + * @throws OrtException If the property does not exist, or is of the wrong type. + */ + public int getIntProperty(OrtAllocator allocator, String name) throws OrtException { + return getIntProperty( + OnnxRuntime.ortApiHandle, + OnnxRuntime.ortTrainingApiHandle, + nativeHandle, + allocator.handle, + name); + } + + /** + * Gets a String property from this checkpoint. + * + * @param allocator The allocator. + * @param name The property name. + * @return The property value. + * @throws OrtException If the property does not exist, or is of the wrong type. + */ + public String getStringProperty(OrtAllocator allocator, String name) throws OrtException { + return getStringProperty( + OnnxRuntime.ortApiHandle, + OnnxRuntime.ortTrainingApiHandle, + nativeHandle, + allocator.handle, + name); + } + @Override public void close() { close(OnnxRuntime.ortTrainingApiHandle, nativeHandle); @@ -969,6 +1122,88 @@ private native void saveCheckpoint( long apiHandle, long trainingHandle, long nativeHandle, String path, boolean saveOptimizer) throws OrtException; + /* \brief Adds the given property to the checkpoint state. + * + * Runtime properties such as epoch, training step, best score, and others can be added to the checkpoint + * state by the user if they desire by calling this function with the appropriate property name and + * value. The given property name must be unique to be able to successfully add the property. + * + * \param[in] checkpoint_state The checkpoint state which should hold the property. + * \param[in] property_name Unique name of the property being added. + * \param[in] property_type Type of the property associated with the given name. + * \param[in] property_value Property value associated with the given name. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + ORT_API2_STATUS(AddProperty, _Inout_ OrtCheckpointState* checkpoint_state, + _In_ const char* property_name, _In_ enum OrtPropertyType property_type, + _In_ void* property_value); + */ + private native void addProperty( + long apiHandle, + long trainingHandle, + long nativeHandle, + String propertyName, + int propertyValue) + throws OrtException; + + private native void addProperty( + long apiHandle, + long trainingHandle, + long nativeHandle, + String propertyName, + float propertyValue) + throws OrtException; + + private native void addProperty( + long apiHandle, + long trainingHandle, + long nativeHandle, + String propertyName, + String propertyValue) + throws OrtException; + + /* \brief Gets the property value associated with the given name from the checkpoint state. + * + * Gets the property value from an existing entry in the checkpoint state. The property must + * exist in the checkpoint state to be able to retrieve it successfully. + * + * \param[in] checkpoint_state The checkpoint state that is currently holding the property. + * \param[in] property_name Unique name of the property being retrieved. + * \param[in] allocator Allocator used to allocate the memory for the property_value. + * \param[out] property_type Type of the property associated with the given name. + * \param[out] property_value Property value associated with the given name. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + ORT_API2_STATUS(GetProperty, _In_ const OrtCheckpointState* checkpoint_state, + _In_ const char* property_name, _Inout_ OrtAllocator* allocator, + _Out_ enum OrtPropertyType* property_type, _Outptr_ void** property_value); + */ + private native int getIntProperty( + long apiHandle, + long trainingHandle, + long nativeHandle, + long allocatorHandle, + String propertyName) + throws OrtException; + + private native float getFloatProperty( + long apiHandle, + long trainingHandle, + long nativeHandle, + long allocatorHandle, + String propertyName) + throws OrtException; + + private native String getStringProperty( + long apiHandle, + long trainingHandle, + long nativeHandle, + long allocatorHandle, + String propertyName) + throws OrtException; + private native void close(long trainingApiHandle, long nativeHandle); } } diff --git a/java/src/main/java/ai/onnxruntime/OrtUtil.java b/java/src/main/java/ai/onnxruntime/OrtUtil.java index eb27d1dafd5f2..5b2e9b2efac4c 100644 --- a/java/src/main/java/ai/onnxruntime/OrtUtil.java +++ b/java/src/main/java/ai/onnxruntime/OrtUtil.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ package ai.onnxruntime; @@ -15,9 +16,11 @@ import java.nio.ShortBuffer; import java.util.ArrayList; import java.util.Arrays; +import java.util.logging.Logger; /** Util code for interacting with Java arrays. */ public final class OrtUtil { + private static final Logger logger = Logger.getLogger(OrtUtil.class.getName()); /** Private constructor for static util class. */ private OrtUtil() {} @@ -85,8 +88,6 @@ public static long[] transformShape(int[] shape) { /** * Creates a new primitive boolean array of up to 8 dimensions, using the supplied shape. * - *

- * * @param shape The shape of array to create. * @return A boolean array. */ @@ -98,8 +99,6 @@ public static Object newBooleanArray(long[] shape) { /** * Creates a new primitive byte array of up to 8 dimensions, using the supplied shape. * - *

- * * @param shape The shape of array to create. * @return A byte array. */ @@ -111,8 +110,6 @@ public static Object newByteArray(long[] shape) { /** * Creates a new primitive short array of up to 8 dimensions, using the supplied shape. * - *

- * * @param shape The shape of array to create. * @return A short array. */ @@ -124,8 +121,6 @@ public static Object newShortArray(long[] shape) { /** * Creates a new primitive int array of up to 8 dimensions, using the supplied shape. * - *

- * * @param shape The shape of array to create. * @return A int array. */ @@ -137,8 +132,6 @@ public static Object newIntArray(long[] shape) { /** * Creates a new primitive long array of up to 8 dimensions, using the supplied shape. * - *

- * * @param shape The shape of array to create. * @return A long array. */ @@ -150,8 +143,6 @@ public static Object newLongArray(long[] shape) { /** * Creates a new primitive float array of up to 8 dimensions, using the supplied shape. * - *

- * * @param shape The shape of array to create. * @return A float array. */ @@ -163,8 +154,6 @@ public static Object newFloatArray(long[] shape) { /** * Creates a new primitive double array of up to 8 dimensions, using the supplied shape. * - *

- * * @param shape The shape of array to create. * @return A double array. */ @@ -176,8 +165,6 @@ public static Object newDoubleArray(long[] shape) { /** * Creates a new String array of up to 8 dimensions, using the supplied shape. * - *

- * * @param shape The shape of array to create. * @return A double array. */ @@ -493,6 +480,9 @@ static int capacityFromSize(int size) { * @return The prepared buffer tuple. */ static BufferTuple prepareBuffer(Buffer data, OnnxJavaType type) { + if (type == OnnxJavaType.STRING || type == OnnxJavaType.UNKNOWN) { + throw new IllegalStateException("Cannot create a " + type + " tensor from a buffer"); + } int bufferPos; long bufferSizeLong = data.remaining() * (long) type.size; if (bufferSizeLong > (Integer.MAX_VALUE - (8 * type.size))) { @@ -522,12 +512,15 @@ static BufferTuple prepareBuffer(Buffer data, OnnxJavaType type) { case DOUBLE: tmp = buffer.asDoubleBuffer().put((DoubleBuffer) data); break; + case BOOL: case UINT8: case INT8: // buffer is already a ByteBuffer, no cast needed. tmp = buffer.put((ByteBuffer) data); break; case INT16: + case FLOAT16: + case BFLOAT16: tmp = buffer.asShortBuffer().put((ShortBuffer) data); break; case INT32: @@ -536,12 +529,10 @@ static BufferTuple prepareBuffer(Buffer data, OnnxJavaType type) { case INT64: tmp = buffer.asLongBuffer().put((LongBuffer) data); break; - case BOOL: - case STRING: - case UNKNOWN: default: throw new IllegalStateException( - "Impossible to reach here, managed to cast a buffer as an incorrect type"); + "Impossible to reach here, managed to cast a buffer as an incorrect type, found " + + type); } data.position(origPosition); tmp.rewind(); diff --git a/java/src/main/java/ai/onnxruntime/TensorInfo.java b/java/src/main/java/ai/onnxruntime/TensorInfo.java index 613fcd61ea476..34d635b5c40f8 100644 --- a/java/src/main/java/ai/onnxruntime/TensorInfo.java +++ b/java/src/main/java/ai/onnxruntime/TensorInfo.java @@ -16,31 +16,61 @@ public class TensorInfo implements ValueInfo { /** The native element types supported by the ONNX runtime. */ public enum OnnxTensorType { + /** An undefined element type. */ ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED(0), + /** An 8-bit unsigned integer. */ ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8(1), // maps to c type uint8_t + /** An 8-bit signed integer. */ ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8(2), // maps to c type int8_t + /** A 16-bit unsigned integer. */ ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT16(3), // maps to c type uint16_t + /** A 16-bit signed integer. */ ONNX_TENSOR_ELEMENT_DATA_TYPE_INT16(4), // maps to c type int16_t + /** A 32-bit unsigned integer. */ ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT32(5), // maps to c type uint32_t + /** A 32-bit signed integer. */ ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32(6), // maps to c type int32_t + /** A 64-bit unsigned integer. */ ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT64(7), // maps to c type uint64_t + /** A 64-bit signed integer. */ ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64(8), // maps to c type int64_t + /** An IEEE 16-bit floating point number. */ ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16(9), // stored as a uint16_t + /** An IEEE 32-bit floating point number. */ ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT(10), // maps to c type float + /** An IEEE 64-bit floating point number. */ ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE(11), // maps to c type double + /** A UTF-8 string. */ ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING(12), // maps to c++ type std::string + /** A boolean value stored in a byte. */ ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL(13), + /** A 64-bit complex number, stored as 2 32-bit values. Not accessible from Java. */ ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX64( 14), // complex with float32 real and imaginary components + /** A 128-bit complex number, stored as 2 64-bit values. Not accessible from Java. */ ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX128( 15), // complex with float64 real and imaginary components + /** + * A non-IEEE 16-bit floating point value with 8 exponent bits and 7 mantissa bits. + * + *

See Bfloat16 on + * Wikipedia for more details. + */ ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16( - 16); // Non-IEEE floating-point format based on IEEE754 single-precision + 16), // Non-IEEE floating-point format based on IEEE754 single-precision + ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FN( + 17), // Non-IEEE floating-point format based on IEEE754 single-precision + ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FNUZ( + 18), // Non-IEEE floating-point format based on IEEE754 single-precision + ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2( + 19), // Non-IEEE floating-point format based on IEEE754 single-precision + ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2FNUZ( + 20); // Non-IEEE floating-point format based on IEEE754 single-precision /** The int id on the native side. */ public final int value; - private static final OnnxTensorType[] values = new OnnxTensorType[17]; + private static final OnnxTensorType[] values = new OnnxTensorType[21]; static { for (OnnxTensorType ot : OnnxTensorType.values()) { @@ -92,6 +122,10 @@ public static OnnxTensorType mapFromJavaType(OnnxJavaType type) { return OnnxTensorType.ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL; case STRING: return OnnxTensorType.ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING; + case FLOAT16: + return OnnxTensorType.ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16; + case BFLOAT16: + return OnnxTensorType.ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16; case UNKNOWN: default: return OnnxTensorType.ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED; @@ -99,6 +133,7 @@ public static OnnxTensorType mapFromJavaType(OnnxJavaType type) { } } + /** The shape of the tensor. */ final long[] shape; /** The Java type of this tensor. */ @@ -321,15 +356,20 @@ public static TensorInfo constructFromBuffer(Buffer buffer, long[] shape, OnnxJa long bufferRemaining = buffer.remaining(); + // Check if size matches if (elementCount != bufferRemaining) { - throw new OrtException( - "Shape " - + Arrays.toString(shape) - + ", requires " - + elementCount - + " elements but the buffer has " - + bufferRemaining - + " elements."); + // if not it could be a ByteBuffer passed in, so check how many bytes there are + long elemRemaining = bufferRemaining / type.size; + if (elementCount != elemRemaining) { + throw new OrtException( + "Shape " + + Arrays.toString(shape) + + ", requires " + + elementCount + + " elements but the buffer has " + + bufferRemaining + + " elements."); + } } return new TensorInfo( diff --git a/java/src/main/java/ai/onnxruntime/providers/CoreMLFlags.java b/java/src/main/java/ai/onnxruntime/providers/CoreMLFlags.java index 7a9db43081b20..eb124decf75f3 100644 --- a/java/src/main/java/ai/onnxruntime/providers/CoreMLFlags.java +++ b/java/src/main/java/ai/onnxruntime/providers/CoreMLFlags.java @@ -1,15 +1,22 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. * Licensed under the MIT License. */ package ai.onnxruntime.providers; /** Flags for the CoreML provider. */ public enum CoreMLFlags implements OrtFlags { + /** + * Use only the CPU, disables the GPU and Apple Neural Engine. Only recommended for developer + * usage as it significantly impacts performance. + */ CPU_ONLY(1), // COREML_FLAG_USE_CPU_ONLY(0x001) + /** Enables CoreML on subgraphs. */ ENABLE_ON_SUBGRAPH(2), // COREML_FLAG_ENABLE_ON_SUBGRAPH(0x002) + /** Only enable usage of CoreML if the device has an Apple Neural Engine. */ ONLY_ENABLE_DEVICE_WITH_ANE(4); // COREML_FLAG_ONLY_ENABLE_DEVICE_WITH_ANE(0x004), + /** The native value of the enum. */ public final int value; CoreMLFlags(int value) { diff --git a/java/src/main/java/ai/onnxruntime/providers/NNAPIFlags.java b/java/src/main/java/ai/onnxruntime/providers/NNAPIFlags.java index 696ecb9bd88cd..eeaf6cc8d53bc 100644 --- a/java/src/main/java/ai/onnxruntime/providers/NNAPIFlags.java +++ b/java/src/main/java/ai/onnxruntime/providers/NNAPIFlags.java @@ -1,16 +1,30 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. * Licensed under the MIT License. */ package ai.onnxruntime.providers; /** Flags for the NNAPI provider. */ public enum NNAPIFlags implements OrtFlags { + /** Enables fp16 support. */ USE_FP16(1), // NNAPI_FLAG_USE_FP16(0x001) + /** + * Uses channels first format. Only recommended for developer usage to validate code changes to + * the execution provider implementation. + */ USE_NCHW(2), // NNAPI_FLAG_USE_NCHW(0x002) + /** + * Disables NNAPI from using CPU. If an operator could be assigned to NNAPI, but NNAPI only has a + * CPU implementation of that operator on the current device, model load will fail. + */ CPU_DISABLED(4), // NNAPI_FLAG_CPU_DISABLED(0x004) + /** + * NNAPI will only use CPU. Only recommended for developer usage as it significantly impacts + * performance. + */ CPU_ONLY(8); // NNAPI_FLAG_CPU_ONLY(0x008) + /** The native value of the enum. */ public final int value; NNAPIFlags(int value) { diff --git a/java/src/main/java/ai/onnxruntime/providers/StringConfigProviderOptions.java b/java/src/main/java/ai/onnxruntime/providers/StringConfigProviderOptions.java index 617da5326a0f8..02207b2949e54 100644 --- a/java/src/main/java/ai/onnxruntime/providers/StringConfigProviderOptions.java +++ b/java/src/main/java/ai/onnxruntime/providers/StringConfigProviderOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. * Licensed under the MIT License. */ package ai.onnxruntime.providers; @@ -15,6 +15,7 @@ * Abstract base class for provider options which are configured solely by key value string pairs. */ abstract class StringConfigProviderOptions extends OrtProviderOptions { + /** A Java side copy of the options. */ protected final Map options; protected StringConfigProviderOptions(long nativeHandle) { @@ -38,7 +39,7 @@ public void add(String key, String value) throws OrtException { } /** - * Parses the output of {@link #getOptionsString()} and adds those options to this options + * Parses the output of {@code getOptionsString()} and adds those options to this options * instance. * * @param serializedForm The serialized form to parse. diff --git a/java/src/main/jvm/ai/onnxruntime/platform/Fp16Conversions.java b/java/src/main/jvm/ai/onnxruntime/platform/Fp16Conversions.java new file mode 100644 index 0000000000000..fce872688aa1f --- /dev/null +++ b/java/src/main/jvm/ai/onnxruntime/platform/Fp16Conversions.java @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Licensed under the MIT License. + */ +package ai.onnxruntime.platform; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; +import java.nio.ShortBuffer; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** Conversions between fp16, bfloat16 and fp32. */ +public final class Fp16Conversions { + private static final Logger logger = Logger.getLogger(Fp16Conversions.class.getName()); + private static final MethodHandle fp16ToFp32; + private static final MethodHandle fp32ToFp16; + + static { + MethodHandle tmp16 = null; + MethodHandle tmp32 = null; + MethodHandles.Lookup lookup = MethodHandles.lookup(); + try { + // Attempt to lookup the Java 20 fp16 conversion methods which can use SIMD intrinsics. + tmp16 = + lookup.findStatic( + Float.class, "float16ToFloat", MethodType.methodType(float.class, short.class)); + tmp32 = + lookup.findStatic( + Float.class, "floatToFloat16", MethodType.methodType(short.class, float.class)); + } catch (IllegalAccessException | NoSuchMethodException e) { + // Must be on Java 19 or earlier, create handles for our methods. + try { + tmp16 = + lookup.findStatic( + Fp16Conversions.class, + "mlasFp16ToFloat", + MethodType.methodType(float.class, short.class)); + tmp32 = + lookup.findStatic( + Fp16Conversions.class, + "mlasFloatToFp16", + MethodType.methodType(short.class, float.class)); + } catch (IllegalAccessException | NoSuchMethodException ex) { + // Should not happen + logger.log(Level.SEVERE, "Failed to find fp16 conversion methods on OnnxTensor", e); + } + } + fp16ToFp32 = tmp16; + fp32ToFp16 = tmp32; + } + + /** + * Rounds a buffer of floats into a buffer containing fp16 values (stored as shorts in Java). + * + *

Respects the position and limit of the input buffer. + * + * @param buf The buffer of floats. + * @return A buffer of fp16 values stored as shorts. + */ + public static ShortBuffer convertFloatBufferToFp16Buffer(FloatBuffer buf) { + int pos = buf.position(); + int remaining = buf.remaining(); + ShortBuffer output = + ByteBuffer.allocateDirect(remaining * 2).order(ByteOrder.nativeOrder()).asShortBuffer(); + for (int i = 0; i < remaining; i++) { + output.put(i, floatToFp16(buf.get(i + pos))); + } + return output; + } + + /** + * Casts a buffer of fp16 values stored as shorts into a buffer of floats. + * + *

Respects the position and limit of the input buffer. + * + * @param buf The buffer of fp16 values stored as shorts. + * @return A buffer of float values. + */ + public static FloatBuffer convertFp16BufferToFloatBuffer(ShortBuffer buf) { + int pos = buf.position(); + int remaining = buf.remaining(); + FloatBuffer output = + ByteBuffer.allocateDirect(remaining * 4).order(ByteOrder.nativeOrder()).asFloatBuffer(); + for (int i = 0; i < remaining; i++) { + output.put(i, fp16ToFloat(buf.get(i + pos))); + } + return output; + } + + /** + * Rounds a buffer of floats into a buffer containing bf16 values (stored as shorts in Java). + * + *

Respects the position and limit of the input buffer. + * + * @param buf The buffer of floats. + * @return A buffer of bf16 values stored as shorts. + */ + public static ShortBuffer convertFloatBufferToBf16Buffer(FloatBuffer buf) { + int pos = buf.position(); + int remaining = buf.remaining(); + ShortBuffer output = + ByteBuffer.allocateDirect(remaining * 2).order(ByteOrder.nativeOrder()).asShortBuffer(); + for (int i = 0; i < remaining; i++) { + output.put(i, floatToBf16(buf.get(i + pos))); + } + return output; + } + + /** + * Casts a buffer of bf16 values stored as shorts into a buffer of floats. + * + *

Respects the position and limit of the input buffer. + * + * @param buf The buffer of bf16 values stored as shorts. + * @return A buffer of float values. + */ + public static FloatBuffer convertBf16BufferToFloatBuffer(ShortBuffer buf) { + int pos = buf.position(); + int remaining = buf.remaining(); + FloatBuffer output = + ByteBuffer.allocateDirect(remaining * 4).order(ByteOrder.nativeOrder()).asFloatBuffer(); + for (int i = 0; i < remaining; i++) { + output.put(i, bf16ToFloat(buf.get(i + pos))); + } + return output; + } + + /** + * Converts a fp16 value stored in a short into a float value. + * + *

Note on Java 20 or newer this uses {@code Float.float16ToFloat} which may use CPU specific + * instructions for the conversion, otherwise it uses the conversion operation from ORT's native + * implementation. + * + * @param input The fp16 value. + * @return The float value. + */ + public static float fp16ToFloat(short input) { + try { + float ret = (float) fp16ToFp32.invokeExact(input); + return ret; + } catch (Throwable e) { + throw new AssertionError("Should not reach here", e); + } + } + + /** + * Converts a float value into a fp16 value stored in a short. + * + *

Note on Java 20 or newer this uses {@code Float.floatToFloat16} which may use CPU specific + * instructions for the conversion, otherwise it uses the conversion operation from ORT's native + * implementation. + * + * @param input The float value. + * @return The fp16 value. + */ + public static short floatToFp16(float input) { + try { + short ret = (short) fp32ToFp16.invokeExact(input); + return ret; + } catch (Throwable e) { + throw new AssertionError("Should not reach here", e); + } + } + + /** + * Upcasts a fp16 value to a float. Mirrors the conversion in MLAS. + * + * @param input A uint16_t representing an IEEE half precision float. + * @return A float. + */ + public static float mlasFp16ToFloat(short input) { + // Port of MLAS_Half2Float from onnxruntime/core/mlas/inc/mlas_float16.h + final int MAGIC = 113 << 23; + // exponent mask after shift + final int SHIFTED_EXP = 0x7c00 << 13; + + // exponent/mantissa bits + int bits = (input & 0x7fff) << 13; + // just the exponent + final int exp = SHIFTED_EXP & bits; + // exponent adjust + bits += (127 - 15) << 23; + + // handle exponent special cases + if (exp == SHIFTED_EXP) { + // Inf/NaN? + // extra exp adjust + bits += (128 - 16) << 23; + } else if (exp == 0) { + // Zero/Denormal? + // extra exp adjust + bits += (1 << 23); + // renormalize + float tmp = Float.intBitsToFloat(bits) - Float.intBitsToFloat(MAGIC); + bits = Float.floatToIntBits(tmp); + } + + // sign bit + bits |= (input & 0x8000) << 16; + + return Float.intBitsToFloat(bits); + } + + /** + * Rounds a float value to fp16. Mirrors the conversion in MLAS. + * + * @param input A float value. + * @return The value rounded to an IEEE half precision value. + */ + public static short mlasFloatToFp16(float input) { + // Port of MLAS_Float2Half from onnxruntime/core/mlas/inc/mlas_float16.h + int bits = Float.floatToIntBits(input); + final int F32_INFINITY = Float.floatToIntBits(Float.POSITIVE_INFINITY); + final int F16_MAX = (127 + 16) << 23; + final int DENORM_MAGIC = ((127 - 15) + (23 - 10) + 1) << 23; + final int SIGN_MASK = 0x80000000; + final int ROUNDING_CONST = ((15 - 127) << 23) + 0xfff; + + int sign = bits & SIGN_MASK; + // mask out sign bit + bits ^= sign; + + short output; + if (bits >= F16_MAX) { + // Inf or NaN (all exponent bits set) + output = (bits > F32_INFINITY) ? (short) 0x7e00 : (short) 0x7c00; + } else { + if (bits < (113 << 23)) { + // Subnormal or zero + // use a magic value to align our 10 mantissa bits at the bottom of + // the float. as long as FP addition is round-to-nearest-even this + // just works. + float tmp = Float.intBitsToFloat(bits) + Float.intBitsToFloat(DENORM_MAGIC); + + // and one integer subtract of the bias later, we have our final float! + output = (short) (Float.floatToIntBits(tmp) - DENORM_MAGIC); + } else { + int mant_odd = (bits >> 13) & 1; // resulting mantissa is odd + + // update exponent, rounding bias part 1 + bits += ROUNDING_CONST; + // rounding bias part 2 + bits += mant_odd; + // take the bits! + output = (short) (bits >> 13); + } + } + + // Add the sign back in + output = (short) (output | ((short) (sign >> 16))); + + return output; + } + + /** + * Converts a bf16 value stored in a short into a float value. + * + * @param input A uint16_t representing a bfloat16 value. + * @return A float. + */ + public static float bf16ToFloat(short input) { + int bits = input << 16; + return Float.intBitsToFloat(bits); + } + + /** + * Converts a float into bf16. May not produce correct values for subnormal floats. + * + *

Rounds to nearest even. + * + * @param input The float input. + * @return A bfloat16 value which is closest to the float. + */ + public static short floatToBf16(float input) { + int bits = Float.floatToIntBits(input); + int lsb = (bits >> 16) & 1; + int roundingBias = 0x7fff + lsb; + bits += roundingBias; + return (short) (bits >> 16); + } +} diff --git a/java/src/main/jvm/ai/onnxruntime/platform/package-info.java b/java/src/main/jvm/ai/onnxruntime/platform/package-info.java new file mode 100644 index 0000000000000..ef52c500642f7 --- /dev/null +++ b/java/src/main/jvm/ai/onnxruntime/platform/package-info.java @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Licensed under the MIT License. + */ + +/** + * A package of platform specific code, used to swap out Java implementations which don't run on + * Android. + * + *

Classes in this package should always have the same public methods. + * + *

This is the Java version of the package. + */ +package ai.onnxruntime.platform; diff --git a/java/src/main/native/OrtJniUtil.c b/java/src/main/native/OrtJniUtil.c index de49edf07b882..879ba8a310618 100644 --- a/java/src/main/native/OrtJniUtil.c +++ b/java/src/main/native/OrtJniUtil.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023 Oracle and/or its affiliates. All rights reserved. * Licensed under the MIT License. */ #include @@ -146,6 +146,14 @@ jint convertFromONNXDataFormat(ONNXTensorElementDataType type) { return 15; case ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16: // Non-IEEE floating-point format based on IEEE754 single-precision return 16; + case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FN: + return 17; + case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FNUZ: + return 18; + case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2: + return 19; + case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2FNUZ: + return 20; default: return -1; } @@ -190,6 +198,14 @@ ONNXTensorElementDataType convertToONNXDataFormat(jint type) { return ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX128; // complex with float64 real and imaginary components case 16: return ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16; // Non-IEEE floating-point format based on IEEE754 single-precision + case 17: + return ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FN; + case 18: + return ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FNUZ; + case 19: + return ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2; + case 20: + return ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2FNUZ; default: return ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED; } @@ -200,10 +216,15 @@ size_t onnxTypeSize(ONNXTensorElementDataType type) { case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8: // maps to c type uint8_t case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8: // maps to c type int8_t case ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL: + case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FN: + case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FNUZ: + case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2: + case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2FNUZ: return 1; case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT16: // maps to c type uint16_t case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT16: // maps to c type int16_t case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16: + case ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16: // Non-IEEE floating-point format based on IEEE754 single-precision return 2; case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT32: // maps to c type uint32_t case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32: // maps to c type int32_t @@ -215,7 +236,6 @@ size_t onnxTypeSize(ONNXTensorElementDataType type) { return 8; case ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING: // maps to c++ type std::string case ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED: - case ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16: // Non-IEEE floating-point format based on IEEE754 single-precision case ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX64: // complex with float32 real and imaginary components case ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX128: // complex with float64 real and imaginary components default: @@ -259,6 +279,12 @@ jfloat convertHalfToFloat(const uint16_t half) { return output.floatVal; } +jfloat convertBF16ToFloat(const uint16_t bf16) { + FP32 output; + output.intVal = bf16 << 16; + return output.floatVal; +} + jobject convertToValueInfo(JNIEnv *jniEnv, const OrtApi * api, const OrtTypeInfo * info) { ONNXType type = ONNX_TYPE_UNKNOWN; OrtErrorCode code = checkOrtStatus(jniEnv, api, api->GetOnnxTypeFromTypeInfo(info, &type)); @@ -486,6 +512,7 @@ int64_t copyJavaToPrimitiveArray(JNIEnv* jniEnv, ONNXTensorElementDataType onnxT (*jniEnv)->GetLongArrayRegion(jniEnv, typedArr, 0, inputLength, (jlong * )outputTensor); return consumedSize; } + case ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16: // Non-IEEE floating-point format based on IEEE754 single-precision case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16: { throwOrtException(jniEnv, convertErrorCode(ORT_NOT_IMPLEMENTED), "16-bit float not supported."); return -1; @@ -522,7 +549,6 @@ int64_t copyJavaToPrimitiveArray(JNIEnv* jniEnv, ONNXTensorElementDataType onnxT } case ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX64: // complex with float32 real and imaginary components case ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX128: // complex with float64 real and imaginary components - case ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16: // Non-IEEE floating-point format based on IEEE754 single-precision case ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED: default: { throwOrtException(jniEnv, convertErrorCode(ORT_INVALID_ARGUMENT), "Invalid outputTensor element type."); @@ -600,6 +626,21 @@ int64_t copyPrimitiveArrayToJava(JNIEnv *jniEnv, ONNXTensorElementDataType onnxT free(floatArr); return consumedSize; } + case ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16: { // stored as a uint16_t + jfloat *floatArr = malloc(sizeof(jfloat) * outputLength); + if (floatArr == NULL) { + throwOrtException(jniEnv, 1, "Not enough memory"); + return -1; + } + uint16_t *bf16Arr = (uint16_t *)inputTensor; + for (int32_t i = 0; i < outputLength; i++) { + floatArr[i] = convertBF16ToFloat(bf16Arr[i]); + } + jfloatArray typedArr = (jfloatArray)outputArray; + (*jniEnv)->SetFloatArrayRegion(jniEnv, typedArr, 0, outputLength, floatArr); + free(floatArr); + return consumedSize; + } case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT: { // maps to c type float jfloatArray typedArr = (jfloatArray)outputArray; (*jniEnv)->SetFloatArrayRegion(jniEnv, typedArr, 0, outputLength, (jfloat * )inputTensor); @@ -630,11 +671,6 @@ int64_t copyPrimitiveArrayToJava(JNIEnv *jniEnv, ONNXTensorElementDataType onnxT throwOrtException(jniEnv, convertErrorCode(ORT_NOT_IMPLEMENTED), "Invalid inputTensor element type ONNX_TENSOR_ELEMENT_DATA_TYPE_COMPLEX128."); return -1; } - case ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16: { - // Non-IEEE floating-point format based on IEEE754 single-precision - throwOrtException(jniEnv, convertErrorCode(ORT_NOT_IMPLEMENTED), "Invalid inputTensor element type ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16."); - return -1; - } case ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED: default: { throwOrtException(jniEnv, convertErrorCode(ORT_NOT_IMPLEMENTED), "Invalid inputTensor element type ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED."); diff --git a/java/src/main/native/OrtJniUtil.h b/java/src/main/native/OrtJniUtil.h index 9c3be7135906a..023bc0c739583 100644 --- a/java/src/main/native/OrtJniUtil.h +++ b/java/src/main/native/OrtJniUtil.h @@ -44,6 +44,8 @@ OrtErrorCode getTensorTypeShape(JNIEnv * jniEnv, JavaTensorTypeShape * output, c jfloat convertHalfToFloat(uint16_t half); +jfloat convertBF16ToFloat(uint16_t half); + jobject convertToValueInfo(JNIEnv *jniEnv, const OrtApi * api, const OrtTypeInfo * info); jobject convertToTensorInfo(JNIEnv *jniEnv, const OrtApi * api, const OrtTensorTypeAndShapeInfo * info); diff --git a/java/src/main/native/ai_onnxruntime_OnnxRuntime.c b/java/src/main/native/ai_onnxruntime_OnnxRuntime.c index d0c4be87d9414..659f34e1fb66f 100644 --- a/java/src/main/native/ai_onnxruntime_OnnxRuntime.c +++ b/java/src/main/native/ai_onnxruntime_OnnxRuntime.c @@ -76,8 +76,7 @@ JNIEXPORT jobjectArray JNICALL Java_ai_onnxruntime_OnnxRuntime_getAvailableProvi JNIEXPORT jstring JNICALL Java_ai_onnxruntime_OnnxRuntime_initialiseVersion (JNIEnv * jniEnv, jclass clazz) { (void)clazz; // required JNI parameter not needed by functions which don't access their host class. - const char* version = OrtGetApiBase()->GetVersionString(); + const char* version = ORT_VERSION; assert(version != NULL); - jstring versionStr = (*jniEnv)->NewStringUTF(jniEnv, version); - return versionStr; + return (*jniEnv)->NewStringUTF(jniEnv, version); } diff --git a/java/src/main/native/ai_onnxruntime_OnnxTensor.c b/java/src/main/native/ai_onnxruntime_OnnxTensor.c index 1656b4043cfe9..b694f57357bb5 100644 --- a/java/src/main/native/ai_onnxruntime_OnnxTensor.c +++ b/java/src/main/native/ai_onnxruntime_OnnxTensor.c @@ -246,14 +246,7 @@ JNIEXPORT jfloat JNICALL Java_ai_onnxruntime_OnnxTensor_getFloat (void) jobj; // Required JNI parameter not needed by functions which don't need to access their host object. const OrtApi* api = (const OrtApi*) apiHandle; ONNXTensorElementDataType onnxType = convertToONNXDataFormat(onnxTypeInt); - if (onnxType == ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16) { - uint16_t* arr = NULL; - OrtErrorCode code = checkOrtStatus(jniEnv, api, api->GetTensorMutableData((OrtValue*)handle, (void**)&arr)); - if (code == ORT_OK) { - jfloat floatVal = convertHalfToFloat(*arr); - return floatVal; - } - } else if (onnxType == ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT) { + if (onnxType == ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT) { jfloat* arr = NULL; OrtErrorCode code = checkOrtStatus(jniEnv, api, api->GetTensorMutableData((OrtValue*)handle, (void**)&arr)); if (code == ORT_OK) { @@ -311,7 +304,10 @@ JNIEXPORT jshort JNICALL Java_ai_onnxruntime_OnnxTensor_getShort (void) jobj; // Required JNI parameter not needed by functions which don't need to access their host object. const OrtApi* api = (const OrtApi*) apiHandle; ONNXTensorElementDataType onnxType = convertToONNXDataFormat(onnxTypeInt); - if ((onnxType == ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT16) || (onnxType == ONNX_TENSOR_ELEMENT_DATA_TYPE_INT16)) { + if ((onnxType == ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT16) || + (onnxType == ONNX_TENSOR_ELEMENT_DATA_TYPE_INT16) || + (onnxType == ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16) || + (onnxType == ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16)) { uint16_t* arr = NULL; OrtErrorCode code = checkOrtStatus(jniEnv, api, api->GetTensorMutableData((OrtValue*)handle, (void**)&arr)); if (code == ORT_OK) { diff --git a/java/src/main/native/ai_onnxruntime_OrtSession_SessionOptions.c b/java/src/main/native/ai_onnxruntime_OrtSession_SessionOptions.c index 330ed3fa3c98c..d3239c7442c80 100644 --- a/java/src/main/native/ai_onnxruntime_OrtSession_SessionOptions.c +++ b/java/src/main/native/ai_onnxruntime_OrtSession_SessionOptions.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023 Oracle and/or its affiliates. All rights reserved. * Licensed under the MIT License. */ #include @@ -350,6 +350,85 @@ JNIEXPORT void JNICALL Java_ai_onnxruntime_OrtSession_00024SessionOptions_addFre (*jniEnv)->ReleaseStringUTFChars(jniEnv,dimensionName,cName); } +/* + * Class: ai_onnxruntime_OrtSession_SessionOptions + * Method: addExternalInitializers + * Signature: (JJ[Ljava/lang/String;[J)V + */ +JNIEXPORT void JNICALL Java_ai_onnxruntime_OrtSession_00024SessionOptions_addExternalInitializers + (JNIEnv * jniEnv, jobject jobj, jlong apiHandle, jlong optionsHandle, jobjectArray namesArray, jlongArray handlesArray) { + (void) jobj; // Required JNI parameter not needed by functions which don't need to access their host object. + const OrtApi* api = (const OrtApi*)apiHandle; + OrtSessionOptions* options = (OrtSessionOptions*) optionsHandle; + + size_t arrLength = (*jniEnv)->GetArrayLength(jniEnv, handlesArray); + + const char** names = allocarray(arrLength, sizeof(char*)); + if (names == NULL) { + // Nothing to cleanup, return and throw exception + throwOrtException(jniEnv, 1, "Not enough memory"); + return; + } + jobject* javaNameStrings = allocarray(arrLength, sizeof(jobject)); + if (javaNameStrings == NULL) { + goto cleanup_names; + } + const OrtValue** initializers = allocarray(arrLength, sizeof(OrtValue*)); + if (initializers == NULL) { + goto cleanup_java_input_strings; + } + + // Extract a C array of longs which are pointers to the input tensors. + // The Java-side objects store native pointers as 64-bit longs, and on 32-bit systems + // we cannot cast the long array to a pointer array as they are different sizes, + // so we copy the longs applying the appropriate cast. + jlong* initializersArr = (*jniEnv)->GetLongArrayElements(jniEnv, handlesArray, NULL); + + for (size_t i = 0; i < arrLength; i++) { + // Extract the string chars and cast the tensor + javaNameStrings[i] = (*jniEnv)->GetObjectArrayElement(jniEnv, namesArray, (jint) i); + names[i] = (*jniEnv)->GetStringUTFChars(jniEnv, javaNameStrings[i], NULL); + initializers[i] = (const OrtValue*) initializersArr[i]; + } + + checkOrtStatus(jniEnv,api,api->AddExternalInitializers(options,names,initializers,arrLength)); + + // Release the java array copy of pointers to the tensors. + (*jniEnv)->ReleaseLongArrayElements(jniEnv, handlesArray, initializersArr, JNI_ABORT); + free(initializers); +cleanup_java_input_strings: + // Release the Java strings + for (size_t i = 0; i < arrLength; i++) { + (*jniEnv)->ReleaseStringUTFChars(jniEnv, javaNameStrings[i], names[i]); + } + free(javaNameStrings); +cleanup_names: + free(names); +} + +/* + * Class: ai_onnxruntime_OrtSession_SessionOptions + * Method: addInitializer + * Signature: (JJLjava/lang/String;J)V + */ +JNIEXPORT void JNICALL Java_ai_onnxruntime_OrtSession_00024SessionOptions_addInitializer + (JNIEnv * jniEnv, jobject jobj, jlong apiHandle, jlong optionsHandle, jstring name, jlong tensorHandle) { + (void) jobj; // Required JNI parameter not needed by functions which don't need to access their host object. + const OrtApi* api = (const OrtApi*)apiHandle; + OrtSessionOptions* options = (OrtSessionOptions*) optionsHandle; + + // Extract the string chars + const char* cName = (*jniEnv)->GetStringUTFChars(jniEnv, name, NULL); + + // Cast the onnx value + const OrtValue* tensor = (const OrtValue*) tensorHandle; + + checkOrtStatus(jniEnv,api,api->AddInitializer(options,cName,tensor)); + + // Release the string chars + (*jniEnv)->ReleaseStringUTFChars(jniEnv,name,cName); +} + /* * Class: ai_onnxruntime_OrtSession_SessionOptions * Method: disablePerSessionThreads @@ -600,7 +679,7 @@ JNIEXPORT void JNICALL Java_ai_onnxruntime_OrtSession_00024SessionOptions_addArm JNIEXPORT void JNICALL Java_ai_onnxruntime_OrtSession_00024SessionOptions_addCoreML (JNIEnv * jniEnv, jobject jobj, jlong apiHandle, jlong handle, jint coreMLFlags) { (void)jobj; - #ifdef USE_CORE_ML + #ifdef USE_COREML checkOrtStatus(jniEnv,(const OrtApi*)apiHandle,OrtSessionOptionsAppendExecutionProvider_CoreML((OrtSessionOptions*) handle, (uint32_t) coreMLFlags)); #else (void)apiHandle;(void)handle;(void)coreMLFlags; // Parameters used when CoreML is defined. diff --git a/java/src/main/native/ai_onnxruntime_OrtTrainingSession.c b/java/src/main/native/ai_onnxruntime_OrtTrainingSession.c index 938eb1c9444b7..b3b530a8b15aa 100644 --- a/java/src/main/native/ai_onnxruntime_OrtTrainingSession.c +++ b/java/src/main/native/ai_onnxruntime_OrtTrainingSession.c @@ -666,12 +666,6 @@ JNIEXPORT void JNICALL Java_ai_onnxruntime_OrtTrainingSession_schedulerStep * Method: exportModelForInference * Signature: (JJJJLjava/lang/String;[Ljava/lang/String;)V */ -#ifdef _MSC_VER -#pragma warning(push) -// C4090: 'operation' : different 'modifier' qualifiers -// Freeing 'outputNames' erroneously triggers this warning, it is fixed in VC 2022 and can be removed when that is the baseline compiler. -#pragma warning(disable : 4090) -#endif // _MSC_VER JNIEXPORT void JNICALL Java_ai_onnxruntime_OrtTrainingSession_exportModelForInference (JNIEnv * jniEnv, jobject jobj, jlong apiHandle, jlong trainApiHandle, jlong nativeHandle, jstring outputPath, jlong numOutputs, jobjectArray outputNamesArr) { (void)jobj; // Required JNI parameter not needed by functions which don't need to access their host object. @@ -721,6 +715,3 @@ JNIEXPORT void JNICALL Java_ai_onnxruntime_OrtTrainingSession_exportModelForInfe free(javaOutputStrings); free(outputNames); } -#ifdef _MSC_VER -#pragma warning(pop) -#endif // _MSC_VER diff --git a/java/src/main/native/ai_onnxruntime_OrtTrainingSession_OrtCheckpointState.c b/java/src/main/native/ai_onnxruntime_OrtTrainingSession_OrtCheckpointState.c index 0e7ddeb356533..c625052b8a05c 100644 --- a/java/src/main/native/ai_onnxruntime_OrtTrainingSession_OrtCheckpointState.c +++ b/java/src/main/native/ai_onnxruntime_OrtTrainingSession_OrtCheckpointState.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. * Licensed under the MIT License. */ #include @@ -81,6 +81,158 @@ JNIEXPORT void JNICALL Java_ai_onnxruntime_OrtTrainingSession_00024OrtCheckpoint #endif } +/* + * Class: ai_onnxruntime_OrtTrainingSession_OrtCheckpointState + * Method: addProperty + * Signature: (JJJLjava/lang/String;I)V + */ +JNIEXPORT void JNICALL Java_ai_onnxruntime_OrtTrainingSession_00024OrtCheckpointState_addProperty__JJJLjava_lang_String_2I + (JNIEnv * jniEnv, jobject jobj, jlong apiHandle, jlong trainingApiHandle, jlong nativeHandle, jstring propName, jint propValue) { + (void) jobj; // Required JNI parameters not needed by functions which don't need to access their host object. + const OrtApi* api = (const OrtApi*) apiHandle; + const OrtTrainingApi* trainApi = (const OrtTrainingApi*) trainingApiHandle; + + OrtCheckpointState* checkpointState = (OrtCheckpointState*) nativeHandle; + + const char* cPropName = (*jniEnv)->GetStringUTFChars(jniEnv, propName, NULL); + checkOrtStatus(jniEnv, api, trainApi->AddProperty(checkpointState, cPropName, OrtIntProperty, &propValue)); + (*jniEnv)->ReleaseStringUTFChars(jniEnv, propName, cPropName); +} + +/* + * Class: ai_onnxruntime_OrtTrainingSession_OrtCheckpointState + * Method: addProperty + * Signature: (JJJLjava/lang/String;F)V + */ +JNIEXPORT void JNICALL Java_ai_onnxruntime_OrtTrainingSession_00024OrtCheckpointState_addProperty__JJJLjava_lang_String_2F + (JNIEnv * jniEnv, jobject jobj, jlong apiHandle, jlong trainingApiHandle, jlong nativeHandle, jstring propName, jfloat propValue) { + (void) jobj; // Required JNI parameters not needed by functions which don't need to access their host object. + const OrtApi* api = (const OrtApi*) apiHandle; + const OrtTrainingApi* trainApi = (const OrtTrainingApi*) trainingApiHandle; + + OrtCheckpointState* checkpointState = (OrtCheckpointState*) nativeHandle; + + const char* cPropName = (*jniEnv)->GetStringUTFChars(jniEnv, propName, NULL); + checkOrtStatus(jniEnv, api, trainApi->AddProperty(checkpointState, cPropName, OrtFloatProperty, &propValue)); + (*jniEnv)->ReleaseStringUTFChars(jniEnv, propName, cPropName); +} + +/* + * Class: ai_onnxruntime_OrtTrainingSession_OrtCheckpointState + * Method: addProperty + * Signature: (JJJLjava/lang/String;Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_ai_onnxruntime_OrtTrainingSession_00024OrtCheckpointState_addProperty__JJJLjava_lang_String_2Ljava_lang_String_2 + (JNIEnv * jniEnv, jobject jobj, jlong apiHandle, jlong trainingApiHandle, jlong nativeHandle, jstring propName, jstring propValue) { + (void) jobj; // Required JNI parameters not needed by functions which don't need to access their host object. + const OrtApi* api = (const OrtApi*) apiHandle; + const OrtTrainingApi* trainApi = (const OrtTrainingApi*) trainingApiHandle; + + OrtCheckpointState* checkpointState = (OrtCheckpointState*) nativeHandle; + + const char* cPropName = (*jniEnv)->GetStringUTFChars(jniEnv, propName, NULL); + const char* cPropValue = (*jniEnv)->GetStringUTFChars(jniEnv, propValue, NULL); + checkOrtStatus(jniEnv, api, trainApi->AddProperty(checkpointState, cPropName, OrtStringProperty, (void*)cPropValue)); + (*jniEnv)->ReleaseStringUTFChars(jniEnv, propName, cPropName); + (*jniEnv)->ReleaseStringUTFChars(jniEnv, propValue, cPropValue); +} + +/* + * Class: ai_onnxruntime_OrtTrainingSession_OrtCheckpointState + * Method: getIntProperty + * Signature: (JJJJLjava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_ai_onnxruntime_OrtTrainingSession_00024OrtCheckpointState_getIntProperty + (JNIEnv * jniEnv, jobject jobj, jlong apiHandle, jlong trainingApiHandle, jlong nativeHandle, jlong allocatorHandle, jstring propName) { + (void) jobj; // Required JNI parameters not needed by functions which don't need to access their host object. + const OrtApi* api = (const OrtApi*) apiHandle; + const OrtTrainingApi* trainApi = (const OrtTrainingApi*) trainingApiHandle; + + OrtCheckpointState* checkpointState = (OrtCheckpointState*) nativeHandle; + + OrtAllocator* allocator = (OrtAllocator*) allocatorHandle; + + const char* cPropName = (*jniEnv)->GetStringUTFChars(jniEnv, propName, NULL); + enum OrtPropertyType type; + int* propValue = NULL; + OrtErrorCode code = checkOrtStatus(jniEnv, api, trainApi->GetProperty(checkpointState, cPropName, allocator, &type, (void**)&propValue)); + (*jniEnv)->ReleaseStringUTFChars(jniEnv, propName, cPropName); + if (code == ORT_OK) { + if (type == OrtIntProperty) { + int output = *propValue; + checkOrtStatus(jniEnv, api, api->AllocatorFree(allocator, propValue)); + return output; + } else { + throwOrtException(jniEnv, 2, "Requested an int property but this property is not an int"); + } + } + return 0; +} + +/* + * Class: ai_onnxruntime_OrtTrainingSession_OrtCheckpointState + * Method: getFloatProperty + * Signature: (JJJJLjava/lang/String;)F + */ +JNIEXPORT jfloat JNICALL Java_ai_onnxruntime_OrtTrainingSession_00024OrtCheckpointState_getFloatProperty + (JNIEnv * jniEnv, jobject jobj, jlong apiHandle, jlong trainingApiHandle, jlong nativeHandle, jlong allocatorHandle, jstring propName) { + (void) jobj; // Required JNI parameters not needed by functions which don't need to access their host object. + const OrtApi* api = (const OrtApi*) apiHandle; + const OrtTrainingApi* trainApi = (const OrtTrainingApi*) trainingApiHandle; + + OrtCheckpointState* checkpointState = (OrtCheckpointState*) nativeHandle; + + OrtAllocator* allocator = (OrtAllocator*) allocatorHandle; + + const char* cPropName = (*jniEnv)->GetStringUTFChars(jniEnv, propName, NULL); + enum OrtPropertyType type; + float* propValue = NULL; + OrtErrorCode code = checkOrtStatus(jniEnv, api, trainApi->GetProperty(checkpointState, cPropName, allocator, &type, (void**)&propValue)); + (*jniEnv)->ReleaseStringUTFChars(jniEnv, propName, cPropName); + if (code == ORT_OK) { + if (type == OrtFloatProperty) { + float output = *propValue; + checkOrtStatus(jniEnv, api, api->AllocatorFree(allocator, propValue)); + return output; + } else { + throwOrtException(jniEnv, 2, "Requested a float property but this property is not a float"); + } + } + return 0.0f; +} + +/* + * Class: ai_onnxruntime_OrtTrainingSession_OrtCheckpointState + * Method: getStringProperty + * Signature: (JJJJLjava/lang/String;)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_ai_onnxruntime_OrtTrainingSession_00024OrtCheckpointState_getStringProperty + (JNIEnv * jniEnv, jobject jobj, jlong apiHandle, jlong trainingApiHandle, jlong nativeHandle, jlong allocatorHandle, jstring propName) { + (void) jobj; // Required JNI parameters not needed by functions which don't need to access their host object. + const OrtApi* api = (const OrtApi*) apiHandle; + const OrtTrainingApi* trainApi = (const OrtTrainingApi*) trainingApiHandle; + + OrtCheckpointState* checkpointState = (OrtCheckpointState*) nativeHandle; + + OrtAllocator* allocator = (OrtAllocator*) allocatorHandle; + + const char* cPropName = (*jniEnv)->GetStringUTFChars(jniEnv, propName, NULL); + enum OrtPropertyType type; + char* propValue = NULL; + OrtErrorCode code = checkOrtStatus(jniEnv, api, trainApi->GetProperty(checkpointState, cPropName, allocator, &type, (void**)&propValue)); + (*jniEnv)->ReleaseStringUTFChars(jniEnv, propName, cPropName); + if (code == ORT_OK) { + if (type == OrtStringProperty) { + jstring output = (*jniEnv)->NewStringUTF(jniEnv, propValue); + checkOrtStatus(jniEnv, api, api->AllocatorFree(allocator, propValue)); + return output; + } else { + throwOrtException(jniEnv, 2, "Requested a string property but this property is not a string"); + } + } + return (jstring) 0; +} + /* * Class: ai_onnxruntime_OrtTrainingSession_OrtCheckpointState * Method: close diff --git a/java/src/test/java/ai/onnxruntime/InferenceTest.java b/java/src/test/java/ai/onnxruntime/InferenceTest.java index 8fc5fe2daf488..08d2a5698d579 100644 --- a/java/src/test/java/ai/onnxruntime/InferenceTest.java +++ b/java/src/test/java/ai/onnxruntime/InferenceTest.java @@ -632,6 +632,12 @@ public void testXNNPACK() throws OrtException { runProvider(OrtProvider.XNNPACK); } + @Test + @EnabledIfSystemProperty(named = "USE_COREML", matches = "1") + public void testCoreML() throws OrtException { + runProvider(OrtProvider.CORE_ML); + } + private void runProvider(OrtProvider provider) throws OrtException { EnumSet providers = OrtEnvironment.getAvailableProviders(); assertTrue(providers.size() > 1); @@ -650,7 +656,12 @@ private void runProvider(OrtProvider provider) throws OrtException { OnnxValue resultTensor = result.get(0); float[] resultArray = TestHelpers.flattenFloat(resultTensor.getValue()); assertEquals(expectedOutput.length, resultArray.length); - assertArrayEquals(expectedOutput, resultArray, 1e-6f); + if (provider == OrtProvider.CORE_ML) { + // CoreML gives slightly different answers on a 2020 13" M1 MBP + assertArrayEquals(expectedOutput, resultArray, 1e-2f); + } else { + assertArrayEquals(expectedOutput, resultArray, 1e-6f); + } } catch (OrtException e) { throw new IllegalStateException("Failed to execute a scoring operation", e); } @@ -658,6 +669,86 @@ private void runProvider(OrtProvider provider) throws OrtException { } } + @Test + public void testExternalInitializers() throws IOException, OrtException { + String modelPath = TestHelpers.getResourcePath("/java-external-matmul.onnx").toString(); + + // Run by loading the external initializer from disk + // initializer is 1...16 in a 4x4 matrix. + try (SessionOptions options = new SessionOptions()) { + try (OrtSession session = env.createSession(modelPath, options)) { + try (OnnxTensor t = OnnxTensor.createTensor(env, new float[][] {{1, 2, 3, 4}}); + OrtSession.Result res = session.run(Collections.singletonMap("input", t))) { + OnnxTensor output = (OnnxTensor) res.get(0); + float[][] outputArr = (float[][]) output.getValue(); + assertArrayEquals(new float[] {90, 100, 110, 120}, outputArr[0]); + } + } + } + // Run by overriding the initializer with the identity matrix + try (SessionOptions options = new SessionOptions()) { + OnnxTensor tensor = TestHelpers.makeIdentityMatrixBuf(env, 4); + options.addExternalInitializers(Collections.singletonMap("tensor", tensor)); + try (OrtSession session = env.createSession(modelPath, options)) { + try (OnnxTensor t = OnnxTensor.createTensor(env, new float[][] {{1, 2, 3, 4}}); + OrtSession.Result res = session.run(Collections.singletonMap("input", t))) { + OnnxTensor output = (OnnxTensor) res.get(0); + float[][] outputArr = (float[][]) output.getValue(); + assertArrayEquals(new float[] {1, 2, 3, 4}, outputArr[0]); + } + } + tensor.close(); + } + // Run by overriding the initializer with the identity matrix loaded from a byte array + byte[] modelBytes = + Files.readAllBytes(TestHelpers.getResourcePath("/java-external-matmul.onnx")); + try (SessionOptions options = new SessionOptions()) { + OnnxTensor tensor = TestHelpers.makeIdentityMatrixBuf(env, 4); + options.addExternalInitializers(Collections.singletonMap("tensor", tensor)); + try (OrtSession session = env.createSession(modelBytes, options)) { + try (OnnxTensor t = OnnxTensor.createTensor(env, new float[][] {{1, 2, 3, 4}}); + OrtSession.Result res = session.run(Collections.singletonMap("input", t))) { + OnnxTensor output = (OnnxTensor) res.get(0); + float[][] outputArr = (float[][]) output.getValue(); + assertArrayEquals(new float[] {1, 2, 3, 4}, outputArr[0]); + } + } + tensor.close(); + } + } + + @Test + public void testOverridingInitializer() throws OrtException { + String modelPath = TestHelpers.getResourcePath("/java-matmul.onnx").toString(); + + // Run with the normal initializer + // initializer is 1...16 in a 4x4 matrix. + try (SessionOptions options = new SessionOptions()) { + try (OrtSession session = env.createSession(modelPath, options)) { + try (OnnxTensor t = OnnxTensor.createTensor(env, new float[][] {{1, 2, 3, 4}}); + OrtSession.Result res = session.run(Collections.singletonMap("input", t))) { + OnnxTensor output = (OnnxTensor) res.get(0); + float[][] outputArr = (float[][]) output.getValue(); + assertArrayEquals(new float[] {90, 100, 110, 120}, outputArr[0]); + } + } + } + // Run by overriding the initializer with the identity matrix + try (SessionOptions options = new SessionOptions()) { + OnnxTensor tensor = TestHelpers.makeIdentityMatrixBuf(env, 4); + options.addInitializer("tensor", tensor); + try (OrtSession session = env.createSession(modelPath, options)) { + try (OnnxTensor t = OnnxTensor.createTensor(env, new float[][] {{1, 2, 3, 4}}); + OrtSession.Result res = session.run(Collections.singletonMap("input", t))) { + OnnxTensor output = (OnnxTensor) res.get(0); + float[][] outputArr = (float[][]) output.getValue(); + assertArrayEquals(new float[] {1, 2, 3, 4}, outputArr[0]); + } + } + tensor.close(); + } + } + private static File getTestModelsDir() throws IOException { // get build directory, append downloaded models location String cwd = System.getProperty("user.dir"); @@ -1168,8 +1259,11 @@ public void testModelInputBOOL() throws OrtException { OrtSession session = env.createSession(modelPath, options)) { String inputName = session.getInputNames().iterator().next(); Map container = new HashMap<>(); + long[] shape = new long[] {1, 5}; + + // Test array input boolean[] flatInput = new boolean[] {true, false, true, false, true}; - Object tensorIn = OrtUtil.reshape(flatInput, new long[] {1, 5}); + Object tensorIn = OrtUtil.reshape(flatInput, shape); OnnxTensor ov = OnnxTensor.createTensor(env, tensorIn); container.put(inputName, ov); try (OrtSession.Result res = session.run(container)) { @@ -1177,6 +1271,41 @@ public void testModelInputBOOL() throws OrtException { assertArrayEquals(flatInput, resultArray); } OnnxValue.close(container); + container.clear(); + + // Test direct buffer input + ByteBuffer dirBuf = ByteBuffer.allocateDirect(5).order(ByteOrder.nativeOrder()); + dirBuf.put((byte) 1); + dirBuf.put((byte) 0); + dirBuf.put((byte) 1); + dirBuf.put((byte) 0); + dirBuf.put((byte) 1); + dirBuf.rewind(); + ov = OnnxTensor.createTensor(env, dirBuf, shape, OnnxJavaType.BOOL); + container.put(inputName, ov); + try (OrtSession.Result res = session.run(container)) { + boolean[] resultArray = TestHelpers.flattenBoolean(res.get(0).getValue()); + assertArrayEquals(flatInput, resultArray); + } + OnnxValue.close(container); + container.clear(); + + // Test non-direct buffer input + ByteBuffer buf = ByteBuffer.allocate(5); + buf.put((byte) 1); + buf.put((byte) 0); + buf.put((byte) 1); + buf.put((byte) 0); + buf.put((byte) 1); + buf.rewind(); + ov = OnnxTensor.createTensor(env, buf, shape, OnnxJavaType.BOOL); + container.put(inputName, ov); + try (OrtSession.Result res = session.run(container)) { + boolean[] resultArray = TestHelpers.flattenBoolean(res.get(0).getValue()); + assertArrayEquals(flatInput, resultArray); + } + OnnxValue.close(container); + container.clear(); } } diff --git a/java/src/test/java/ai/onnxruntime/ModelGenerators.java b/java/src/test/java/ai/onnxruntime/ModelGenerators.java new file mode 100644 index 0000000000000..90fda4c5cf610 --- /dev/null +++ b/java/src/test/java/ai/onnxruntime/ModelGenerators.java @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Licensed under the MIT License. + */ +package ai.onnxruntime; + +import ai.onnxruntime.OnnxMl.StringStringEntryProto; +import ai.onnxruntime.OnnxMl.TensorProto.DataLocation; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Arrays; + +/** Methods to generate test models. */ +public final class ModelGenerators { + private ModelGenerators() {} + + public static OnnxMl.TensorShapeProto getShapeProto( + long[] dimensions, String[] dimensionOverrides) { + OnnxMl.TensorShapeProto.Builder builder = OnnxMl.TensorShapeProto.newBuilder(); + for (int i = 0; i < dimensions.length; i++) { + if (dimensions[i] == -1) { + builder.addDim( + OnnxMl.TensorShapeProto.Dimension.newBuilder() + .setDimParam(dimensionOverrides[i]) + .build()); + } else { + builder.addDim( + OnnxMl.TensorShapeProto.Dimension.newBuilder().setDimValue(dimensions[i]).build()); + } + } + return builder.build(); + } + + public static OnnxMl.TypeProto buildTensorTypeNode( + long[] dimensions, String[] dimensionOverrides, OnnxMl.TensorProto.DataType type) { + OnnxMl.TypeProto.Builder builder = OnnxMl.TypeProto.newBuilder(); + + OnnxMl.TypeProto.Tensor.Builder tensorBuilder = OnnxMl.TypeProto.Tensor.newBuilder(); + tensorBuilder.setElemType(type.getNumber()); + tensorBuilder.setShape(getShapeProto(dimensions, dimensionOverrides)); + builder.setTensorType(tensorBuilder.build()); + + return builder.build(); + } + + public void generateExternalMatMul() throws IOException { + OnnxMl.GraphProto.Builder graph = OnnxMl.GraphProto.newBuilder(); + graph.setName("ort-test-matmul"); + + // Add placeholders + OnnxMl.ValueInfoProto.Builder input = OnnxMl.ValueInfoProto.newBuilder(); + input.setName("input"); + OnnxMl.TypeProto inputType = + buildTensorTypeNode( + new long[] {-1, 4}, + new String[] {"batch_size", null}, + OnnxMl.TensorProto.DataType.FLOAT); + input.setType(inputType); + graph.addInput(input); + OnnxMl.ValueInfoProto.Builder output = OnnxMl.ValueInfoProto.newBuilder(); + output.setName("output"); + OnnxMl.TypeProto outputType = + buildTensorTypeNode( + new long[] {-1, 4}, + new String[] {"batch_size", null}, + OnnxMl.TensorProto.DataType.FLOAT); + output.setType(outputType); + graph.addOutput(output); + + // Add initializers + OnnxMl.TensorProto.Builder tensor = OnnxMl.TensorProto.newBuilder(); + tensor.addDims(4); + tensor.addDims(4); + tensor.setDataLocation(DataLocation.EXTERNAL); + tensor.addExternalData( + StringStringEntryProto.newBuilder() + .setKey("location") + .setValue("external-matmul.out") + .build()); + tensor.addExternalData( + StringStringEntryProto.newBuilder().setKey("offset").setValue("0").build()); + tensor.addExternalData( + StringStringEntryProto.newBuilder().setKey("length").setValue("64").build()); + float[] floats = + new float[] {1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f, 10f, 11f, 12f, 13f, 14f, 15f, 16f}; + ByteBuffer buf = ByteBuffer.allocate(64).order(ByteOrder.LITTLE_ENDIAN); + FloatBuffer floatBuf = buf.asFloatBuffer(); + floatBuf.put(floats); + floatBuf.rewind(); + buf.rewind(); + try (OutputStream os = + Files.newOutputStream(Paths.get("src", "test", "resources", "external-matmul.out"))) { + os.write(buf.array()); + } + tensor.setDataType(OnnxMl.TensorProto.DataType.FLOAT.getNumber()); + tensor.setName("tensor"); + graph.addInitializer(tensor); + + // Add operations + OnnxMl.NodeProto.Builder matmul = OnnxMl.NodeProto.newBuilder(); + matmul.setName("matmul-0"); + matmul.setOpType("MatMul"); + matmul.addInput("input"); + matmul.addInput("tensor"); + matmul.addOutput("output"); + graph.addNode(matmul); + + // Build model + OnnxMl.ModelProto.Builder model = OnnxMl.ModelProto.newBuilder(); + model.setGraph(graph); + model.setDocString("ORT matmul test"); + model.setModelVersion(0); + model.setIrVersion(8); + model.setDomain("ai.onnxruntime.test"); + model.addOpsetImport(OnnxMl.OperatorSetIdProto.newBuilder().setVersion(18).build()); + try (OutputStream os = + Files.newOutputStream(Paths.get("src", "test", "resources", "java-external-matmul.onnx"))) { + model.build().writeTo(os); + } + } + + public void generateMatMul() throws IOException { + OnnxMl.GraphProto.Builder graph = OnnxMl.GraphProto.newBuilder(); + graph.setName("ort-test-matmul"); + + // Add placeholders + OnnxMl.ValueInfoProto.Builder input = OnnxMl.ValueInfoProto.newBuilder(); + input.setName("input"); + OnnxMl.TypeProto inputType = + buildTensorTypeNode( + new long[] {-1, 4}, + new String[] {"batch_size", null}, + OnnxMl.TensorProto.DataType.FLOAT); + input.setType(inputType); + graph.addInput(input); + OnnxMl.ValueInfoProto.Builder output = OnnxMl.ValueInfoProto.newBuilder(); + output.setName("output"); + OnnxMl.TypeProto outputType = + buildTensorTypeNode( + new long[] {-1, 4}, + new String[] {"batch_size", null}, + OnnxMl.TensorProto.DataType.FLOAT); + output.setType(outputType); + graph.addOutput(output); + + // Add initializers + OnnxMl.TensorProto.Builder tensor = OnnxMl.TensorProto.newBuilder(); + tensor.addDims(4); + tensor.addDims(4); + Float[] floats = + new Float[] {1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f, 10f, 11f, 12f, 13f, 14f, 15f, 16f}; + tensor.addAllFloatData(Arrays.asList(floats)); + tensor.setDataType(OnnxMl.TensorProto.DataType.FLOAT.getNumber()); + tensor.setName("tensor"); + graph.addInitializer(tensor); + + // Add operations + OnnxMl.NodeProto.Builder matmul = OnnxMl.NodeProto.newBuilder(); + matmul.setName("matmul-0"); + matmul.setOpType("MatMul"); + matmul.addInput("input"); + matmul.addInput("tensor"); + matmul.addOutput("output"); + graph.addNode(matmul); + + // Build model + OnnxMl.ModelProto.Builder model = OnnxMl.ModelProto.newBuilder(); + model.setGraph(graph); + model.setDocString("ORT matmul test"); + model.setModelVersion(0); + model.setIrVersion(8); + model.setDomain("ai.onnxruntime.test"); + model.addOpsetImport(OnnxMl.OperatorSetIdProto.newBuilder().setVersion(18).build()); + try (OutputStream os = + Files.newOutputStream(Paths.get("src", "test", "resources", "java-matmul.onnx"))) { + model.build().writeTo(os); + } + } + + private static void genCast( + String name, + OnnxMl.TensorProto.DataType inputDataType, + OnnxMl.TensorProto.DataType outputDataType) + throws IOException { + OnnxMl.GraphProto.Builder graph = OnnxMl.GraphProto.newBuilder(); + graph.setName("ort-test-" + name); + + // Add placeholders + OnnxMl.ValueInfoProto.Builder input = OnnxMl.ValueInfoProto.newBuilder(); + input.setName("input"); + OnnxMl.TypeProto inputType = + buildTensorTypeNode(new long[] {-1, 5}, new String[] {"batch_size", null}, inputDataType); + input.setType(inputType); + graph.addInput(input); + OnnxMl.ValueInfoProto.Builder output = OnnxMl.ValueInfoProto.newBuilder(); + output.setName("output"); + OnnxMl.TypeProto outputType = + buildTensorTypeNode(new long[] {-1, 5}, new String[] {"batch_size", null}, outputDataType); + output.setType(outputType); + graph.addOutput(output); + + // Add operations + OnnxMl.NodeProto.Builder cast = OnnxMl.NodeProto.newBuilder(); + cast.setName("cast-0"); + cast.setOpType("Cast"); + cast.addInput("input"); + cast.addOutput("output"); + cast.addAttribute( + OnnxMl.AttributeProto.newBuilder() + .setName("to") + .setType(OnnxMl.AttributeProto.AttributeType.INT) + .setI(outputDataType.getNumber()) + .build()); + graph.addNode(cast); + + // Build model + OnnxMl.ModelProto.Builder model = OnnxMl.ModelProto.newBuilder(); + model.setGraph(graph); + model.setDocString("ORT " + name + " test"); + model.setModelVersion(0); + model.setIrVersion(8); + model.setDomain("ai.onnxruntime.test"); + model.addOpsetImport(OnnxMl.OperatorSetIdProto.newBuilder().setVersion(18).build()); + try (OutputStream os = + Files.newOutputStream( + Paths.get( + "..", "..", "..", "java", "src", "test", "resources", "java-" + name + ".onnx"))) { + model.build().writeTo(os); + } + } + + public void generateFp16Fp32Cast() throws IOException { + genCast("fp16-to-fp32", OnnxMl.TensorProto.DataType.FLOAT16, OnnxMl.TensorProto.DataType.FLOAT); + } + + public void generateFp32Fp16Cast() throws IOException { + genCast("fp32-to-fp16", OnnxMl.TensorProto.DataType.FLOAT, OnnxMl.TensorProto.DataType.FLOAT16); + } + + public void generateBf16Fp32Cast() throws IOException { + genCast( + "bf16-to-fp32", OnnxMl.TensorProto.DataType.BFLOAT16, OnnxMl.TensorProto.DataType.FLOAT); + } + + public void generateFp32Bf16Cast() throws IOException { + genCast( + "fp32-to-bf16", OnnxMl.TensorProto.DataType.FLOAT, OnnxMl.TensorProto.DataType.BFLOAT16); + } +} diff --git a/java/src/test/java/ai/onnxruntime/OnnxTensorTest.java b/java/src/test/java/ai/onnxruntime/OnnxTensorTest.java new file mode 100644 index 0000000000000..fcb4590717fea --- /dev/null +++ b/java/src/test/java/ai/onnxruntime/OnnxTensorTest.java @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Licensed under the MIT License. + */ +package ai.onnxruntime; + +import ai.onnxruntime.platform.Fp16Conversions; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; +import java.nio.ShortBuffer; +import java.util.Collections; +import java.util.SplittableRandom; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class OnnxTensorTest { + + @Test + public void testScalarCreation() throws OrtException { + OrtEnvironment env = OrtEnvironment.getEnvironment(); + String[] stringValues = new String[] {"true", "false"}; + for (String s : stringValues) { + try (OnnxTensor t = OnnxTensor.createTensor(env, s)) { + Assertions.assertEquals(s, t.getValue()); + } + } + + boolean[] boolValues = new boolean[] {true, false}; + for (boolean b : boolValues) { + try (OnnxTensor t = OnnxTensor.createTensor(env, b)) { + Assertions.assertEquals(b, t.getValue()); + } + } + + int[] intValues = + new int[] {-1, 0, 1, 12345678, -12345678, Integer.MAX_VALUE, Integer.MIN_VALUE}; + for (int i : intValues) { + try (OnnxTensor t = OnnxTensor.createTensor(env, i)) { + Assertions.assertEquals(i, t.getValue()); + } + } + + long[] longValues = + new long[] {-1L, 0L, 1L, 12345678L, -12345678L, Long.MAX_VALUE, Long.MIN_VALUE}; + for (long l : longValues) { + try (OnnxTensor t = OnnxTensor.createTensor(env, l)) { + Assertions.assertEquals(l, t.getValue()); + } + } + + float[] floatValues = + new float[] { + -1.0f, + 0.0f, + -0.0f, + 1.0f, + 1234.5678f, + -1234.5678f, + (float) Math.PI, + (float) Math.E, + Float.MAX_VALUE, + Float.MIN_VALUE + }; + for (float f : floatValues) { + try (OnnxTensor t = OnnxTensor.createTensor(env, f)) { + Assertions.assertEquals(f, t.getValue()); + } + } + + double[] doubleValues = + new double[] { + -1.0, + 0.0, + -0.0, + 1.0, + 1234.5678, + -1234.5678, + Math.PI, + Math.E, + Double.MAX_VALUE, + Double.MIN_VALUE + }; + for (double d : doubleValues) { + try (OnnxTensor t = OnnxTensor.createTensor(env, d)) { + Assertions.assertEquals(d, t.getValue()); + } + } + } + + @Test + public void testStringCreation() throws OrtException { + OrtEnvironment env = OrtEnvironment.getEnvironment(); + String[] arrValues = new String[] {"this", "is", "a", "single", "dimensional", "string"}; + try (OnnxTensor t = OnnxTensor.createTensor(env, arrValues)) { + Assertions.assertArrayEquals(new long[] {6}, t.getInfo().shape); + String[] output = (String[]) t.getValue(); + Assertions.assertArrayEquals(arrValues, output); + } + + String[][] stringValues = + new String[][] {{"this", "is", "a"}, {"multi", "dimensional", "string"}}; + try (OnnxTensor t = OnnxTensor.createTensor(env, stringValues)) { + Assertions.assertArrayEquals(new long[] {2, 3}, t.getInfo().shape); + String[][] output = (String[][]) t.getValue(); + Assertions.assertArrayEquals(stringValues, output); + } + + String[][][] deepStringValues = + new String[][][] { + {{"this", "is", "a"}, {"multi", "dimensional", "string"}}, + {{"with", "lots", "more"}, {"dimensions", "than", "before"}} + }; + try (OnnxTensor t = OnnxTensor.createTensor(env, deepStringValues)) { + Assertions.assertArrayEquals(new long[] {2, 2, 3}, t.getInfo().shape); + String[][][] output = (String[][][]) t.getValue(); + Assertions.assertArrayEquals(deepStringValues, output); + } + } + + @Test + public void testUint8Creation() throws OrtException { + OrtEnvironment env = OrtEnvironment.getEnvironment(); + byte[] buf = new byte[] {0, 1}; + ByteBuffer data = ByteBuffer.wrap(buf); + long[] shape = new long[] {2}; + try (OnnxTensor t = OnnxTensor.createTensor(env, data, shape, OnnxJavaType.UINT8)) { + Assertions.assertArrayEquals(buf, (byte[]) t.getValue()); + } + } + + @Test + public void testEmptyTensor() throws OrtException { + OrtEnvironment env = OrtEnvironment.getEnvironment(); + FloatBuffer buf = FloatBuffer.allocate(0); + long[] shape = new long[] {4, 0}; + try (OnnxTensor t = OnnxTensor.createTensor(env, buf, shape)) { + Assertions.assertArrayEquals(shape, t.getInfo().getShape()); + float[][] output = (float[][]) t.getValue(); + Assertions.assertEquals(4, output.length); + Assertions.assertEquals(0, output[0].length); + FloatBuffer fb = t.getFloatBuffer(); + Assertions.assertEquals(0, fb.remaining()); + } + shape = new long[] {0, 4}; + try (OnnxTensor t = OnnxTensor.createTensor(env, buf, shape)) { + Assertions.assertArrayEquals(shape, t.getInfo().getShape()); + float[][] output = (float[][]) t.getValue(); + Assertions.assertEquals(0, output.length); + } + } + + @Test + public void testBf16ToFp32() throws OrtException { + OrtEnvironment env = OrtEnvironment.getEnvironment(); + String modelPath = TestHelpers.getResourcePath("/java-bf16-to-fp32.onnx").toString(); + SplittableRandom rng = new SplittableRandom(1); + + float[][] input = new float[10][5]; + ByteBuffer buf = ByteBuffer.allocateDirect(2 * 10 * 5).order(ByteOrder.nativeOrder()); + ShortBuffer shortBuf = buf.asShortBuffer(); + + // Generate data + for (int i = 0; i < input.length; i++) { + for (int j = 0; j < input[0].length; j++) { + short bits = (short) rng.nextInt(); + input[i][j] = Fp16Conversions.bf16ToFloat(bits); + shortBuf.put(bits); + } + } + shortBuf.rewind(); + + try (OrtSession.SessionOptions opts = new OrtSession.SessionOptions(); + OrtSession session = env.createSession(modelPath, opts); + OnnxTensor tensor = + OnnxTensor.createTensor(env, buf, new long[] {10, 5}, OnnxJavaType.BFLOAT16); + OrtSession.Result result = session.run(Collections.singletonMap("input", tensor))) { + OnnxTensor output = (OnnxTensor) result.get(0); + float[][] outputArr = (float[][]) output.getValue(); + for (int i = 0; i < input.length; i++) { + Assertions.assertArrayEquals(input[i], outputArr[i]); + } + } + } + + @Test + public void testFp16ToFp32() throws OrtException { + OrtEnvironment env = OrtEnvironment.getEnvironment(); + String modelPath = TestHelpers.getResourcePath("/java-fp16-to-fp32.onnx").toString(); + SplittableRandom rng = new SplittableRandom(1); + + float[][] input = new float[10][5]; + ByteBuffer buf = ByteBuffer.allocateDirect(2 * 10 * 5).order(ByteOrder.nativeOrder()); + ShortBuffer shortBuf = buf.asShortBuffer(); + + // Generate data + for (int i = 0; i < input.length; i++) { + for (int j = 0; j < input[0].length; j++) { + short bits = (short) rng.nextInt(); + input[i][j] = Fp16Conversions.fp16ToFloat(bits); + shortBuf.put(bits); + } + } + shortBuf.rewind(); + + try (OrtSession.SessionOptions opts = new OrtSession.SessionOptions(); + OrtSession session = env.createSession(modelPath, opts); + OnnxTensor tensor = + OnnxTensor.createTensor(env, buf, new long[] {10, 5}, OnnxJavaType.FLOAT16); + OrtSession.Result result = session.run(Collections.singletonMap("input", tensor))) { + OnnxTensor output = (OnnxTensor) result.get(0); + float[][] outputArr = (float[][]) output.getValue(); + for (int i = 0; i < input.length; i++) { + Assertions.assertArrayEquals(input[i], outputArr[i]); + } + } + } + + @Test + public void testFp32ToFp16() throws OrtException { + OrtEnvironment env = OrtEnvironment.getEnvironment(); + String modelPath = TestHelpers.getResourcePath("/java-fp32-to-fp16.onnx").toString(); + SplittableRandom rng = new SplittableRandom(1); + + float[][] input = new float[10][5]; + FloatBuffer floatBuf = + ByteBuffer.allocateDirect(4 * 10 * 5).order(ByteOrder.nativeOrder()).asFloatBuffer(); + ShortBuffer shortBuf = ShortBuffer.allocate(10 * 5); + + // Generate data + for (int i = 0; i < input.length; i++) { + for (int j = 0; j < input[0].length; j++) { + int bits = rng.nextInt(); + input[i][j] = Float.intBitsToFloat(bits); + floatBuf.put(input[i][j]); + shortBuf.put(Fp16Conversions.floatToFp16(input[i][j])); + } + } + floatBuf.rewind(); + shortBuf.rewind(); + + try (OrtSession.SessionOptions opts = new OrtSession.SessionOptions(); + OrtSession session = env.createSession(modelPath, opts); + OnnxTensor tensor = OnnxTensor.createTensor(env, floatBuf, new long[] {10, 5}); + OrtSession.Result result = session.run(Collections.singletonMap("input", tensor))) { + OnnxTensor output = (OnnxTensor) result.get(0); + + // Check outbound Java side cast to fp32 works + FloatBuffer castOutput = output.getFloatBuffer(); + float[] expectedFloatArr = new float[10 * 5]; + Fp16Conversions.convertFp16BufferToFloatBuffer(shortBuf).get(expectedFloatArr); + float[] actualFloatArr = new float[10 * 5]; + castOutput.get(actualFloatArr); + Assertions.assertArrayEquals(expectedFloatArr, actualFloatArr); + + // Check bits are correct + ShortBuffer outputBuf = output.getShortBuffer(); + short[] expectedShortArr = new short[10 * 5]; + shortBuf.get(expectedShortArr); + short[] actualShortArr = new short[10 * 5]; + outputBuf.get(actualShortArr); + Assertions.assertArrayEquals(expectedShortArr, actualShortArr); + } + } + + @Test + public void testFp32ToBf16() throws OrtException { + OrtEnvironment env = OrtEnvironment.getEnvironment(); + String modelPath = TestHelpers.getResourcePath("/java-fp32-to-bf16.onnx").toString(); + SplittableRandom rng = new SplittableRandom(1); + + float[][] input = new float[10][5]; + FloatBuffer floatBuf = + ByteBuffer.allocateDirect(4 * 10 * 5).order(ByteOrder.nativeOrder()).asFloatBuffer(); + ShortBuffer shortBuf = ShortBuffer.allocate(10 * 5); + + // Generate data + for (int i = 0; i < input.length; i++) { + for (int j = 0; j < input[0].length; j++) { + int bits = rng.nextInt(); + input[i][j] = Float.intBitsToFloat(bits); + floatBuf.put(input[i][j]); + shortBuf.put(Fp16Conversions.floatToBf16(input[i][j])); + } + } + floatBuf.rewind(); + shortBuf.rewind(); + + try (OrtSession.SessionOptions opts = new OrtSession.SessionOptions(); + OrtSession session = env.createSession(modelPath, opts); + OnnxTensor tensor = OnnxTensor.createTensor(env, floatBuf, new long[] {10, 5}); + OrtSession.Result result = session.run(Collections.singletonMap("input", tensor))) { + OnnxTensor output = (OnnxTensor) result.get(0); + + // Check outbound Java side cast to fp32 works + FloatBuffer castOutput = output.getFloatBuffer(); + float[] expectedFloatArr = new float[10 * 5]; + Fp16Conversions.convertBf16BufferToFloatBuffer(shortBuf).get(expectedFloatArr); + float[] actualFloatArr = new float[10 * 5]; + castOutput.get(actualFloatArr); + Assertions.assertArrayEquals(expectedFloatArr, actualFloatArr); + + // Check bits are correct + ShortBuffer outputBuf = output.getShortBuffer(); + short[] expectedShortArr = new short[10 * 5]; + shortBuf.get(expectedShortArr); + short[] actualShortArr = new short[10 * 5]; + outputBuf.get(actualShortArr); + Assertions.assertArrayEquals(expectedShortArr, actualShortArr); + } + } + + @Test + public void testFp16RoundTrip() { + for (int i = 0; i < 0xffff; i++) { + // Round trip every value + short curVal = (short) (0xffff & i); + float upcast = Fp16Conversions.mlasFp16ToFloat(curVal); + short output = Fp16Conversions.mlasFloatToFp16(upcast); + if (!Float.isNaN(upcast)) { + // We coerce NaNs to the same value. + Assertions.assertEquals( + curVal, + output, + "Expected " + curVal + " received " + output + ", intermediate float was " + upcast); + } + } + } + + @Test + public void testBf16RoundTrip() { + for (int i = 0; i < 0xffff; i++) { + // Round trip every value + short curVal = (short) (0xffff & i); + float upcast = Fp16Conversions.bf16ToFloat(curVal); + short output = Fp16Conversions.floatToBf16(upcast); + if (!Float.isNaN(upcast)) { + // We coerce NaNs to the same value. + Assertions.assertEquals( + curVal, + output, + "Expected " + curVal + " received " + output + ", intermediate float was " + upcast); + } + } + } +} diff --git a/java/src/test/java/ai/onnxruntime/SparseTensorTest.java b/java/src/test/java/ai/onnxruntime/SparseTensorTest.java index 9b0533f5c4687..99e55874f3675 100644 --- a/java/src/test/java/ai/onnxruntime/SparseTensorTest.java +++ b/java/src/test/java/ai/onnxruntime/SparseTensorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. * Licensed under the MIT License. */ package ai.onnxruntime; @@ -31,7 +31,7 @@ public void testCSRC() throws OrtException { try (OrtSession session = env.createSession(modelPath, options)) { Map inputMap = new HashMap<>(); - OnnxTensor denseIdMatrix = makeIdentityMatrix(env, 3); + OnnxTensor denseIdMatrix = TestHelpers.makeIdentityMatrix(env, 3); long[] shape = new long[] {3, 3}; /* * Sparse matrix: @@ -152,7 +152,7 @@ public void testCSRC() throws OrtException { inputMap.clear(); denseIdMatrix.close(); - denseIdMatrix = makeIdentityMatrix(env, 4); + denseIdMatrix = TestHelpers.makeIdentityMatrix(env, 4); long[] vectorShape = new long[] {1, 4}; /* * Sparse matrix: @@ -212,7 +212,7 @@ public void testCOO() throws OrtException { try (OrtSession session = env.createSession(modelPath, options)) { Map inputMap = new HashMap<>(); - OnnxTensor denseIdMatrix = makeIdentityMatrix(env, 3); + OnnxTensor denseIdMatrix = TestHelpers.makeIdentityMatrix(env, 3); long[] shape = new long[] {3, 3}; /* * Sparse matrix: @@ -341,7 +341,7 @@ public void testCOO() throws OrtException { inputMap.clear(); denseIdMatrix.close(); - denseIdMatrix = makeIdentityMatrix(env, 4); + denseIdMatrix = TestHelpers.makeIdentityMatrix(env, 4); long[] vectorShape = new long[] {1, 4}; /* * Sparse matrix: @@ -439,13 +439,4 @@ public void testCOOOutput() throws OrtException { } } } - - private static OnnxTensor makeIdentityMatrix(OrtEnvironment env, int size) throws OrtException { - float[][] values = new float[size][size]; - for (int i = 0; i < values.length; i++) { - values[i][i] = 1.0f; - } - - return OnnxTensor.createTensor(env, values); - } } diff --git a/java/src/test/java/ai/onnxruntime/TensorCreationTest.java b/java/src/test/java/ai/onnxruntime/TensorCreationTest.java deleted file mode 100644 index bd3209279f11a..0000000000000 --- a/java/src/test/java/ai/onnxruntime/TensorCreationTest.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. - * Licensed under the MIT License. - */ -package ai.onnxruntime; - -import java.nio.ByteBuffer; -import java.nio.FloatBuffer; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -public class TensorCreationTest { - - @Test - public void testScalarCreation() throws OrtException { - OrtEnvironment env = OrtEnvironment.getEnvironment(); - String[] stringValues = new String[] {"true", "false"}; - for (String s : stringValues) { - try (OnnxTensor t = OnnxTensor.createTensor(env, s)) { - Assertions.assertEquals(s, t.getValue()); - } - } - - boolean[] boolValues = new boolean[] {true, false}; - for (boolean b : boolValues) { - try (OnnxTensor t = OnnxTensor.createTensor(env, b)) { - Assertions.assertEquals(b, t.getValue()); - } - } - - int[] intValues = - new int[] {-1, 0, 1, 12345678, -12345678, Integer.MAX_VALUE, Integer.MIN_VALUE}; - for (int i : intValues) { - try (OnnxTensor t = OnnxTensor.createTensor(env, i)) { - Assertions.assertEquals(i, t.getValue()); - } - } - - long[] longValues = - new long[] {-1L, 0L, 1L, 12345678L, -12345678L, Long.MAX_VALUE, Long.MIN_VALUE}; - for (long l : longValues) { - try (OnnxTensor t = OnnxTensor.createTensor(env, l)) { - Assertions.assertEquals(l, t.getValue()); - } - } - - float[] floatValues = - new float[] { - -1.0f, - 0.0f, - -0.0f, - 1.0f, - 1234.5678f, - -1234.5678f, - (float) Math.PI, - (float) Math.E, - Float.MAX_VALUE, - Float.MIN_VALUE - }; - for (float f : floatValues) { - try (OnnxTensor t = OnnxTensor.createTensor(env, f)) { - Assertions.assertEquals(f, t.getValue()); - } - } - - double[] doubleValues = - new double[] { - -1.0, - 0.0, - -0.0, - 1.0, - 1234.5678, - -1234.5678, - Math.PI, - Math.E, - Double.MAX_VALUE, - Double.MIN_VALUE - }; - for (double d : doubleValues) { - try (OnnxTensor t = OnnxTensor.createTensor(env, d)) { - Assertions.assertEquals(d, t.getValue()); - } - } - } - - @Test - public void testStringCreation() throws OrtException { - OrtEnvironment env = OrtEnvironment.getEnvironment(); - String[] arrValues = new String[] {"this", "is", "a", "single", "dimensional", "string"}; - try (OnnxTensor t = OnnxTensor.createTensor(env, arrValues)) { - Assertions.assertArrayEquals(new long[] {6}, t.getInfo().shape); - String[] output = (String[]) t.getValue(); - Assertions.assertArrayEquals(arrValues, output); - } - - String[][] stringValues = - new String[][] {{"this", "is", "a"}, {"multi", "dimensional", "string"}}; - try (OnnxTensor t = OnnxTensor.createTensor(env, stringValues)) { - Assertions.assertArrayEquals(new long[] {2, 3}, t.getInfo().shape); - String[][] output = (String[][]) t.getValue(); - Assertions.assertArrayEquals(stringValues, output); - } - - String[][][] deepStringValues = - new String[][][] { - {{"this", "is", "a"}, {"multi", "dimensional", "string"}}, - {{"with", "lots", "more"}, {"dimensions", "than", "before"}} - }; - try (OnnxTensor t = OnnxTensor.createTensor(env, deepStringValues)) { - Assertions.assertArrayEquals(new long[] {2, 2, 3}, t.getInfo().shape); - String[][][] output = (String[][][]) t.getValue(); - Assertions.assertArrayEquals(deepStringValues, output); - } - } - - @Test - public void testUint8Creation() throws OrtException { - OrtEnvironment env = OrtEnvironment.getEnvironment(); - byte[] buf = new byte[] {0, 1}; - ByteBuffer data = ByteBuffer.wrap(buf); - long[] shape = new long[] {2}; - try (OnnxTensor t = OnnxTensor.createTensor(env, data, shape, OnnxJavaType.UINT8)) { - Assertions.assertArrayEquals(buf, (byte[]) t.getValue()); - } - } - - @Test - public void testEmptyTensor() throws OrtException { - OrtEnvironment env = OrtEnvironment.getEnvironment(); - FloatBuffer buf = FloatBuffer.allocate(0); - long[] shape = new long[] {4, 0}; - try (OnnxTensor t = OnnxTensor.createTensor(env, buf, shape)) { - Assertions.assertArrayEquals(shape, t.getInfo().getShape()); - float[][] output = (float[][]) t.getValue(); - Assertions.assertEquals(4, output.length); - Assertions.assertEquals(0, output[0].length); - FloatBuffer fb = t.getFloatBuffer(); - Assertions.assertEquals(0, fb.remaining()); - } - shape = new long[] {0, 4}; - try (OnnxTensor t = OnnxTensor.createTensor(env, buf, shape)) { - Assertions.assertArrayEquals(shape, t.getInfo().getShape()); - float[][] output = (float[][]) t.getValue(); - Assertions.assertEquals(0, output.length); - } - } -} diff --git a/java/src/test/java/ai/onnxruntime/TestHelpers.java b/java/src/test/java/ai/onnxruntime/TestHelpers.java index b82cb07aeefb6..7d41918b1c6c7 100644 --- a/java/src/test/java/ai/onnxruntime/TestHelpers.java +++ b/java/src/test/java/ai/onnxruntime/TestHelpers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. * Licensed under the MIT License. */ package ai.onnxruntime; @@ -13,6 +13,8 @@ import java.io.InputStream; import java.io.UncheckedIOException; import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -411,6 +413,25 @@ static StringTensorPair loadTensorFromFilePb( return new StringTensorPair(nodeName, onnxTensor); } + public static OnnxTensor makeIdentityMatrix(OrtEnvironment env, int size) throws OrtException { + float[][] values = new float[size][size]; + for (int i = 0; i < values.length; i++) { + values[i][i] = 1.0f; + } + + return OnnxTensor.createTensor(env, values); + } + + public static OnnxTensor makeIdentityMatrixBuf(OrtEnvironment env, int size) throws OrtException { + FloatBuffer buf = + ByteBuffer.allocateDirect(size * size * 4).order(ByteOrder.LITTLE_ENDIAN).asFloatBuffer(); + for (int i = 0; i < size; i++) { + buf.put(i * size + i, 1.0f); + } + + return OnnxTensor.createTensor(env, buf, new long[] {size, size}); + } + private static class TypeWidth { public final OnnxJavaType type; public final int width; diff --git a/java/src/test/java/ai/onnxruntime/TrainingTest.java b/java/src/test/java/ai/onnxruntime/TrainingTest.java index 487fd64540299..a02f5a88b2ac5 100644 --- a/java/src/test/java/ai/onnxruntime/TrainingTest.java +++ b/java/src/test/java/ai/onnxruntime/TrainingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. * Licensed under the MIT License. */ package ai.onnxruntime; @@ -45,15 +45,34 @@ public void testCreateTrainingSession() throws OrtException { Assertions.assertNotNull(trainingSession); Set inputNames = trainingSession.getTrainInputNames(); Assertions.assertFalse(inputNames.isEmpty()); + Assertions.assertTrue(inputNames.contains("input-0")); Set outputNames = trainingSession.getTrainOutputNames(); Assertions.assertFalse(outputNames.isEmpty()); + Assertions.assertTrue(outputNames.contains("onnx::loss::21273")); + } + } + + @Test + public void testCreateTrainingSessionWithEval() throws OrtException { + String ckptPath = TestHelpers.getResourcePath("/checkpoint.ckpt").toString(); + String trainPath = TestHelpers.getResourcePath("/training_model.onnx").toString(); + String evalPath = TestHelpers.getResourcePath("/eval_model.onnx").toString(); + try (OrtTrainingSession trainingSession = + env.createTrainingSession(ckptPath, trainPath, evalPath, null)) { + Assertions.assertNotNull(trainingSession); + Set inputNames = trainingSession.getEvalInputNames(); + Assertions.assertFalse(inputNames.isEmpty()); + Assertions.assertTrue(inputNames.contains("input-0")); + Set outputNames = trainingSession.getEvalOutputNames(); + Assertions.assertFalse(outputNames.isEmpty()); + Assertions.assertTrue(outputNames.contains("onnx::loss::21273")); } } // this test is not enabled as ORT Java doesn't support supplying an output buffer @Disabled @Test - public void TestTrainingSessionTrainStep() throws OrtException { + public void testTrainingSessionTrainStep() throws OrtException { String checkpointPath = TestHelpers.getResourcePath("/checkpoint.ckpt").toString(); String trainingPath = TestHelpers.getResourcePath("/training_model.onnx").toString(); float[] expectedOutput = @@ -134,7 +153,7 @@ void runTrainStep(OrtTrainingSession trainingSession) throws OrtException { } @Test - public void TestTrainingSessionTrainStepOrtOutput() throws OrtException { + public void testTrainingSessionTrainStepOrtOutput() throws OrtException { String checkpointPath = TestHelpers.getResourcePath("/checkpoint.ckpt").toString(); String trainingPath = TestHelpers.getResourcePath("/training_model.onnx").toString(); try (OrtTrainingSession trainingSession = @@ -144,21 +163,22 @@ public void TestTrainingSessionTrainStepOrtOutput() throws OrtException { } @Test - public void TestSaveCheckpoint() throws IOException, OrtException { + public void testSaveCheckpoint() throws IOException, OrtException { String checkpointPath = TestHelpers.getResourcePath("/checkpoint.ckpt").toString(); String trainingPath = TestHelpers.getResourcePath("/training_model.onnx").toString(); Path tmpPath = Files.createTempDirectory("ort-java-training-test"); + Path tmpCheckpointPath = tmpPath.resolve("checkpoint.ckpt"); try { try (OrtTrainingSession trainingSession = env.createTrainingSession(checkpointPath, trainingPath, null, null)) { // Save checkpoint - trainingSession.saveCheckpoint(tmpPath, false); + trainingSession.saveCheckpoint(tmpCheckpointPath, false); } try (OrtTrainingSession trainingSession = - env.createTrainingSession(tmpPath.toString(), trainingPath, null, null)) { + env.createTrainingSession(tmpCheckpointPath.toString(), trainingPath, null, null)) { // Load saved checkpoint into new session and run train step runTrainStep(trainingSession); } @@ -168,7 +188,7 @@ public void TestSaveCheckpoint() throws IOException, OrtException { } @Test - public void TestTrainingSessionOptimizerStep() throws OrtException { + public void testTrainingSessionOptimizerStep() throws OrtException { String checkpointPath = TestHelpers.getResourcePath("/checkpoint.ckpt").toString(); String trainingPath = TestHelpers.getResourcePath("/training_model.onnx").toString(); String optimizerPath = TestHelpers.getResourcePath("/adamw.onnx").toString(); @@ -214,7 +234,7 @@ public void TestTrainingSessionOptimizerStep() throws OrtException { } @Test - public void TestTrainingSessionSetLearningRate() throws OrtException { + public void testTrainingSessionSetLearningRate() throws OrtException { String checkpointPath = TestHelpers.getResourcePath("/checkpoint.ckpt").toString(); String trainingPath = TestHelpers.getResourcePath("/training_model.onnx").toString(); String optimizerPath = TestHelpers.getResourcePath("/adamw.onnx").toString(); @@ -229,7 +249,7 @@ public void TestTrainingSessionSetLearningRate() throws OrtException { } @Test - public void TestTrainingSessionLinearLRScheduler() throws OrtException { + public void testTrainingSessionLinearLRScheduler() throws OrtException { String checkpointPath = TestHelpers.getResourcePath("/checkpoint.ckpt").toString(); String trainingPath = TestHelpers.getResourcePath("/training_model.onnx").toString(); String optimizerPath = TestHelpers.getResourcePath("/adamw.onnx").toString(); @@ -253,4 +273,100 @@ public void TestTrainingSessionLinearLRScheduler() throws OrtException { Assertions.assertEquals(0.0f, trainingSession.getLearningRate()); } } + + @Test + public void testTrainingSessionExportModelForInferencing() throws IOException, OrtException { + + String ckptPath = TestHelpers.getResourcePath("/checkpoint.ckpt").toString(); + String trainPath = TestHelpers.getResourcePath("/training_model.onnx").toString(); + String evalPath = TestHelpers.getResourcePath("/eval_model.onnx").toString(); + try (OrtTrainingSession trainingSession = + env.createTrainingSession(ckptPath, trainPath, evalPath, null)) { + String[] graphOutputs = new String[] {"output-0"}; + + Path inferencePath = Files.createTempFile("inference_model", ".onnx"); + + trainingSession.exportModelForInference(inferencePath, graphOutputs); + Assertions.assertTrue(inferencePath.toFile().exists()); + inferencePath.toFile().delete(); + } + } + + @Test + public void testCheckpointStateAddIntProperty() throws OrtException { + Path ckptPath = TestHelpers.getResourcePath("/checkpoint.ckpt"); + try (OrtCheckpointState ckpt = OrtCheckpointState.loadCheckpoint(ckptPath)) { + String propertyName = "days in a week"; + ckpt.addProperty(propertyName, 7); + + int value = ckpt.getIntProperty(env.defaultAllocator, propertyName); + Assertions.assertEquals(7, value); + + try { + String strVal = ckpt.getStringProperty(env.defaultAllocator, propertyName); + Assertions.fail("Should have thrown"); + } catch (OrtException e) { + // pass + } + + try { + float floatVal = ckpt.getFloatProperty(env.defaultAllocator, propertyName); + Assertions.fail("Should have thrown"); + } catch (OrtException e) { + // pass + } + } + } + + @Test + public void testCheckpointStateAddFloatProperty() throws OrtException { + Path ckptPath = TestHelpers.getResourcePath("/checkpoint.ckpt"); + try (OrtCheckpointState ckpt = OrtCheckpointState.loadCheckpoint(ckptPath)) { + String propertyName = "pi"; + ckpt.addProperty(propertyName, 3.14f); + + float value = ckpt.getFloatProperty(env.defaultAllocator, propertyName); + Assertions.assertEquals(3.14f, value); + + try { + String strVal = ckpt.getStringProperty(env.defaultAllocator, propertyName); + Assertions.fail("Should have thrown"); + } catch (OrtException e) { + // pass + } + + try { + int intVal = ckpt.getIntProperty(env.defaultAllocator, propertyName); + Assertions.fail("Should have thrown"); + } catch (OrtException e) { + // pass + } + } + } + + @Test + public void testCheckpointStateAddStringProperty() throws OrtException { + Path ckptPath = TestHelpers.getResourcePath("/checkpoint.ckpt"); + try (OrtCheckpointState ckpt = OrtCheckpointState.loadCheckpoint(ckptPath)) { + String propertyName = "best ai framework"; + ckpt.addProperty(propertyName, "onnxruntime"); + + String value = ckpt.getStringProperty(env.defaultAllocator, propertyName); + Assertions.assertEquals("onnxruntime", value); + + try { + float floatVal = ckpt.getFloatProperty(env.defaultAllocator, propertyName); + Assertions.fail("Should have thrown"); + } catch (OrtException e) { + // pass + } + + try { + int intVal = ckpt.getIntProperty(env.defaultAllocator, propertyName); + Assertions.fail("Should have thrown"); + } catch (OrtException e) { + // pass + } + } + } } diff --git a/java/src/test/resources/external-matmul.out b/java/src/test/resources/external-matmul.out new file mode 100644 index 0000000000000..bbed3159335c2 Binary files /dev/null and b/java/src/test/resources/external-matmul.out differ diff --git a/java/src/test/resources/java-bf16-to-fp32.onnx b/java/src/test/resources/java-bf16-to-fp32.onnx new file mode 100644 index 0000000000000..e5c3181f530d1 --- /dev/null +++ b/java/src/test/resources/java-bf16-to-fp32.onnx @@ -0,0 +1,14 @@ +"ai.onnxruntime.test2ORT bf16-to-fp32 test: +( +inputoutputcast-0"Cast* +toort-test-bf16-to-fp32Z! +input + +  +batch_size +b" +output + +  +batch_size +B \ No newline at end of file diff --git a/java/src/test/resources/java-external-matmul.onnx b/java/src/test/resources/java-external-matmul.onnx new file mode 100644 index 0000000000000..d0f31853d1ac1 --- /dev/null +++ b/java/src/test/resources/java-external-matmul.onnx @@ -0,0 +1,18 @@ +"ai.onnxruntime.test2ORT matmul test: +) +input +tensoroutputmatmul-0"MatMulort-test-matmul*L +Btensorj +locationexternal-matmul.outj +offset0j +length64pZ! +input + +  +batch_size +b" +output + +  +batch_size +B \ No newline at end of file diff --git a/java/src/test/resources/java-fp16-to-fp32.onnx b/java/src/test/resources/java-fp16-to-fp32.onnx new file mode 100644 index 0000000000000..0579dd4e0fc48 --- /dev/null +++ b/java/src/test/resources/java-fp16-to-fp32.onnx @@ -0,0 +1,15 @@ +"ai.onnxruntime.test2ORT fp16-to-fp32 test: +( +inputoutputcast-0"Cast* +toort-test-fp16-to-fp32Z! +input + + +  +batch_size +b" +output + +  +batch_size +B \ No newline at end of file diff --git a/java/src/test/resources/java-fp32-to-bf16.onnx b/java/src/test/resources/java-fp32-to-bf16.onnx new file mode 100644 index 0000000000000..a9d495459f88e --- /dev/null +++ b/java/src/test/resources/java-fp32-to-bf16.onnx @@ -0,0 +1,14 @@ +"ai.onnxruntime.test2ORT fp32-to-bf16 test: +( +inputoutputcast-0"Cast* +toort-test-fp32-to-bf16Z! +input + +  +batch_size +b" +output + +  +batch_size +B \ No newline at end of file diff --git a/java/src/test/resources/java-fp32-to-fp16.onnx b/java/src/test/resources/java-fp32-to-fp16.onnx new file mode 100644 index 0000000000000..8294e53a404d0 --- /dev/null +++ b/java/src/test/resources/java-fp32-to-fp16.onnx @@ -0,0 +1,16 @@ +"ai.onnxruntime.test2ORT fp32-to-fp16 test: +( +inputoutputcast-0"Cast* +to +ort-test-fp32-to-fp16Z! +input + +  +batch_size +b" +output + + +  +batch_size +B \ No newline at end of file diff --git a/java/src/test/resources/java-matmul.onnx b/java/src/test/resources/java-matmul.onnx new file mode 100644 index 0000000000000..2deeeebd1321a Binary files /dev/null and b/java/src/test/resources/java-matmul.onnx differ diff --git a/js/.eslintrc.js b/js/.eslintrc.js index 519284617f428..e13cabae9ed45 100644 --- a/js/.eslintrc.js +++ b/js/.eslintrc.js @@ -5,7 +5,7 @@ module.exports = { root: true, - ignorePatterns: ['**/*.js', 'node_modules/', 'types/', 'dist/'], + ignorePatterns: ['**/*.js', 'ort-schema/', 'common/test/type-tests/', 'node_modules/', 'types/', 'dist/'], env: { 'es6': true }, parser: '@typescript-eslint/parser', parserOptions: { 'project': 'tsconfig.json', 'sourceType': 'module' }, @@ -121,6 +121,12 @@ module.exports = { 'jsdoc/check-indentation': 'error', 'jsdoc/newline-after-description': 'error', } + }, { + files: ['common/test/**/*.ts'], + rules: { + '@typescript-eslint/naming-convention': 'off', + 'import/no-extraneous-dependencies': 'off', + } }, { files: ['node/script/**/*.ts', 'node/test/**/*.ts', 'web/script/**/*.ts', 'web/test/**/*.ts'], rules: { '@typescript-eslint/naming-convention': 'off', diff --git a/js/.prettierignore b/js/.prettierignore new file mode 100644 index 0000000000000..5571721a7a4fd --- /dev/null +++ b/js/.prettierignore @@ -0,0 +1,23 @@ +# ignore generated docs +web/docs/ + +# this JSON file is too large, so it takes too long to format it. +node/test/testdata/squeezenet.input0.json + +# ignore dist folder +dist/ + +# ignore file types that handled by clang-format +**/*.cc +**/*.cpp +**/*.h +**/*.js +**/*.mjs +**/*.cjs +**/*.jsx +**/*.ts +**/*.mts +**/*.cts +**/*.tsx +**/*.java +**/*.mm diff --git a/js/.prettierrc b/js/.prettierrc new file mode 100644 index 0000000000000..0b909ca02d823 --- /dev/null +++ b/js/.prettierrc @@ -0,0 +1 @@ +{ "printWidth": 120, "endOfLine": "auto", "singleQuote": false } diff --git a/js/.vscode/launch.json b/js/.vscode/launch.json index 5c986ec6c9972..3f4ec74b7de58 100644 --- a/js/.vscode/launch.json +++ b/js/.vscode/launch.json @@ -5,9 +5,30 @@ "version": "0.2.0", "configurations": [ { + "name": "[common] Launch Unit Tests", + "args": ["-u", "bdd", "--timeout", "999999", "--colors", "${workspaceFolder}/common/test/**/*.js"], + "internalConsoleOptions": "openOnSessionStart", + "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", + "cwd": "${workspaceFolder}/common", + "request": "launch", + "skipFiles": ["/**"], + "type": "node", + "sourceMaps": true, + "preLaunchTask": "tsc: build - common/test/tsconfig.json" + }, + { + "name": "[web] Launch Test Runner", + "program": "${workspaceFolder}/web/script/test-runner-cli.js", + "request": "launch", + "skipFiles": ["/**"], + "type": "node", + "cwd": "${workspaceFolder}/web", + "args": ["suite1"] + }, + { + "name": "[web] Attach to Chrome", "type": "chrome", "request": "attach", - "name": "Attach to Chrome", "port": 9333, "webRoot": "${workspaceFolder}", "sourceMapPathOverrides": { @@ -18,7 +39,7 @@ "smartStep": true }, { - "name": "Remote Browser via Webkit Adaptor", + "name": "[web] Remote Browser via Webkit Adaptor", "type": "chrome", "request": "attach", "port": 9000, diff --git a/js/.vscode/settings.json b/js/.vscode/settings.json index 3efa8770d360f..4948899ec671b 100644 --- a/js/.vscode/settings.json +++ b/js/.vscode/settings.json @@ -3,6 +3,10 @@ "editor.formatOnSave": true, "editor.defaultFormatter": "xaver.clang-format" }, + "[json]": { + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, "[jsonc]": { "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode" @@ -11,6 +15,10 @@ "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode" }, + "[javascript]": { + "editor.formatOnSave": true, + "editor.defaultFormatter": "xaver.clang-format" + }, "[typescript]": { "editor.formatOnSave": true, "editor.defaultFormatter": "xaver.clang-format" @@ -37,5 +45,12 @@ "./types": true }, "typescript.tsdk": "node_modules/typescript/lib", - "git.detectSubmodules": false + "git.detectSubmodules": false, + "cmake.configureOnOpen": false, + "json.schemas": [ + { + "fileMatch": ["web/test/data/ops/*.jsonc"], + "url": "./web/test/op-test-schema.json" + } + ] } diff --git a/js/README.md b/js/README.md index dfb1aa3d4cc31..7e6681e6bd897 100644 --- a/js/README.md +++ b/js/README.md @@ -249,13 +249,13 @@ By default, the WebAssembly artifacts from onnxruntime-web package allows use of By default, the main bundle file `ort.min.js` of ONNX Runtime Web contains all features. However, its size is over 500kB and for some scenarios we want a smaller sized bundle file, if we don't use all the features. The following table lists all available bundles with their support status of features. -|bundle file name|file size|file size (gzipped)|WebGL|WASM-core|WASM-proxy|WASM-threads|ES5 backward compatibility| -|-|-|-|-|------|-----|---|-| -|ort.es5.min.js|594.15KB|134.25KB|O|O|O|O|O| -|ort.min.js|526.02KB|125.07KB|O|O|O|O|X| -|ort.webgl.min.js|385.25KB|83.83KB|O|X|X|X|X| -|ort.wasm.min.js|148.56|44KB|X|O|O|O|X| -|ort.wasm-core.min.js|40.56KB|12.74KB|X|O|X|X|X| +| bundle file name | file size | file size (gzipped) | WebGL | WASM-core | WASM-proxy | WASM-threads | ES5 backward compatibility | +| -------------------- | --------- | ------------------- | ----- | --------- | ---------- | ------------ | -------------------------- | +| ort.es5.min.js | 594.15KB | 134.25KB | O | O | O | O | O | +| ort.min.js | 526.02KB | 125.07KB | O | O | O | O | X | +| ort.webgl.min.js | 385.25KB | 83.83KB | O | X | X | X | X | +| ort.wasm.min.js | 148.56 | 44KB | X | O | O | O | X | +| ort.wasm-core.min.js | 40.56KB | 12.74KB | X | O | X | X | X | #### Build ONNX Runtime as a WebAssembly static library @@ -304,19 +304,20 @@ From ORT v1.13 onwards the 'full' ONNX Runtime package is used. It supports both 3. In ``, run the below python script to build the ONNX Runtime Android archive file. On a Windows machine, this requires an admin account to build. - You can build a 'full' package that supports all operators and types, or a reduced size 'mobile' package that supports a limited set of operators and types based on your model/s to miminize the binary size. + You can build a 'full' package that supports all operators and types, or a reduced size 'mobile' package that supports a limited set of operators and types based on your model/s to miminize the binary size. See [here](https://onnxruntime.ai/docs/build/custom.html) for information about how the reduced build works, including creating the configuration file using your model/s. + Full build: - Full build: - ```sh - python tools/ci_build/github/android/build_aar_package.py tools/ci_build/github/android/default_full_aar_build_settings.json --config Release --android_sdk_path --android_ndk_path --build_dir - ``` + ```sh + python tools/ci_build/github/android/build_aar_package.py tools/ci_build/github/android/default_full_aar_build_settings.json --config Release --android_sdk_path --android_ndk_path --build_dir + ``` - Reduced size build with configuration file generated from your model/s. Note that either Release or MinSizeRel could be used as the config, depending on your priorities: - ```sh - python tools/ci_build/github/android/build_aar_package.py tools/ci_build/github/android/default_mobile_aar_build_settings.json --config MinSizeRel --android_sdk_path --android_ndk_path --build_dir --include_ops_by_config --enable_reduced_operator_type_support - ``` + Reduced size build with configuration file generated from your model/s. Note that either Release or MinSizeRel could be used as the config, depending on your priorities: + + ```sh + python tools/ci_build/github/android/build_aar_package.py tools/ci_build/github/android/default_mobile_aar_build_settings.json --config MinSizeRel --android_sdk_path --android_ndk_path --build_dir --include_ops_by_config --enable_reduced_operator_type_support + ``` 4. Move the generated ONNX Runtime Android archive file to `/js/react_native/android/libs/`. @@ -326,7 +327,6 @@ From ORT v1.13 onwards the 'full' ONNX Runtime package is used. It supports both Reduced size build: Copy `/aar_out/MinSizeRel/com/microsoft/onnxruntime/onnxruntime-mobile//onnxruntime-mobile-.aar` into `/js/react_native/android/libs` directory and update to dependencies in [js/react_native/android/build.gradle](https://github.com/microsoft/onnxruntime/blob/365a01397dbd1293e0c2773380c57fd271432b72/js/react_native/android/build.gradle#L136-L137) to use onnxruntime-mobile instead of onnxruntime-android. - 5. To verify, open the Android Emulator and run this command from `/js/react_native/android` ```sh @@ -342,23 +342,27 @@ From ORT v1.13 onwards the 'full' ONNX Runtime package is used. It supports both 3. Build a fat ONNX Runtime Mobile Framework for iOS and iOS simulator from `` using this command: Full build: + ```sh python tools/ci_build/github/apple/build_ios_framework.py tools/ci_build/github/apple/default_full_ios_framework_build_settings.json --config Release ``` Reduced size build: + ```sh python tools/ci_build/github/apple/build_ios_framework.py tools/ci_build/github/apple/default_mobile_ios_framework_build_settings.json --config MinSizeRel --include_ops_by_config --enable_reduced_operator_type_support ``` - The build creates `Headers`, `LICENSE`, and `onnxruntime.xcframework` in `build/iOS_framework/framework_out` directory. From `framework_out` directory, create an archive file named `onnxruntime-c.zip` for a full build or `onnxruntime-mobile-c.zip` for a reduced size build and copy to `/js/react_native/local_pods` directory. + The build creates `Headers`, `LICENSE`, and `onnxruntime.xcframework` in `build/iOS_framework/framework_out` directory. From `framework_out` directory, create an archive file named `onnxruntime-c.zip` for a full build or `onnxruntime-mobile-c.zip` for a reduced size build and copy to `/js/react_native/local_pods` directory. Full build: + ```sh zip -r onnxruntime-c.zip . ``` Reduced size build: + ```sh zip -r onnxruntime-mobile-c.zip . ``` @@ -366,9 +370,10 @@ From ORT v1.13 onwards the 'full' ONNX Runtime package is used. It supports both 4. To verify, open the iOS Simulator and run the below command from `/js/react_native/ios`. Change the destination argument as needed to specify a running iOS Simulator. If using the reduced size build it is necessary to first update some configuration to use the mobile ORT package: - - replace `onnxruntime/onnxruntime.framework` with `onnxruntime-mobile/onnxruntime.framework` in /js/react_native/ios/OnnxruntimeModule.xcodeproj/project.pbxproj - - replace `onnxruntime-c` with `onnxruntime-mobile-c` in /js/react_native/ios/Podfile - - For reference, [this PR](https://github.com/microsoft/onnxruntime/pull/13037) shows the changes made to switch from using the 'mobile' ORT package to the 'full' package. + + - replace `onnxruntime/onnxruntime.framework` with `onnxruntime-mobile/onnxruntime.framework` in /js/react_native/ios/OnnxruntimeModule.xcodeproj/project.pbxproj + - replace `onnxruntime-c` with `onnxruntime-mobile-c` in /js/react_native/ios/Podfile + - For reference, [this PR](https://github.com/microsoft/onnxruntime/pull/13037) shows the changes made to switch from using the 'mobile' ORT package to the 'full' package. ```sh pod install @@ -394,74 +399,82 @@ From ORT v1.13 onwards the 'full' ONNX Runtime package is used. It supports both When testing with a custom built ONNX Runtime iOS package, copy `onnxruntime-[mobile-]c.zip` into the `/js/react_native/local_pods` directory. If using the reduced size build it is necessary to update some configuration to use the mobile ORT package: - - replace `com.microsoft.onnxruntime:onnxruntime-android` with `com.microsoft.onnxruntime:onnxruntime-mobile` in /js/react_native/e2e/android/app/build.gradle - - replace `onnxruntime-c` with `onnxruntime-mobile-c` in /js/react_native/e2e/ios/Podfile - - Run E2E Testing with Detox framework + - replace `com.microsoft.onnxruntime:onnxruntime-android` with `com.microsoft.onnxruntime:onnxruntime-mobile` in /js/react_native/e2e/android/app/build.gradle + - replace `onnxruntime-c` with `onnxruntime-mobile-c` in /js/react_native/e2e/ios/Podfile - When testing with integrated [Detox](https://wix.github.io/Detox/docs/next/introduction/getting-started) framework for Android and iOS e2e apps: - - Detox prerequisites: +- Run E2E Testing with Detox framework - Install detox command line tools: - ``` - yarn global add detox-cli - ``` - Install applesimutils which is required by Detox to work with iOS simulators. (Requires a MacOS device) - ``` - brew tap wix/brew - brew install applesimutils - ``` - Main Detox project files: - - `.detoxrc.js` -Detox config file; - - `e2e/jest.config.js` -Jest configuration; - - `e2e/OnnxruntimeModuleExample.test.js` - initial react native onnxruntimemodule e2e detox test. - - Build the detox e2e testing app. + When testing with integrated [Detox](https://wix.github.io/Detox/docs/next/introduction/getting-started) framework for Android and iOS e2e apps: - From `/js/react_native/e2e`, run the command to build the e2e testing app. Before that ensure you have android emulator/ios simulator started locally. + - Detox prerequisites: - iOS (Debug): + Install detox command line tools: - ``` - detox build --configuration ios.sim.debug - ``` - - Android (Debug): + ``` + yarn global add detox-cli + ``` - ``` - detox build --configuration android.emu.debug - ``` - - * Note: If names of local testing android/ios devices do not match the default setting in `.detoxrc.js` file, + Install applesimutils which is required by Detox to work with iOS simulators. (Requires a MacOS device) + + ``` + brew tap wix/brew + brew install applesimutils + ``` + + Main Detox project files: + + - `.detoxrc.js` -Detox config file; + - `e2e/jest.config.js` -Jest configuration; + - `e2e/OnnxruntimeModuleExample.test.js` - initial react native onnxruntimemodule e2e detox test. + + - Build the detox e2e testing app. + + From `/js/react_native/e2e`, run the command to build the e2e testing app. Before that ensure you have android emulator/ios simulator started locally. + + iOS (Debug): + + ``` + detox build --configuration ios.sim.debug + ``` + + Android (Debug): + + ``` + detox build --configuration android.emu.debug + ``` + + - Note: If names of local testing android/ios devices do not match the default setting in `.detoxrc.js` file, modify the device name in config files accordingly to match local device name otherwise would cause a build failure. - - Run the detox e2e tests. - - In a debug configuration, you need to have React Native packager running in parallel before you start Detox tests: + - Run the detox e2e tests. - ``` - npm start + In a debug configuration, you need to have React Native packager running in parallel before you start Detox tests: - > react-native start - ``` - - From `/js/react_native/e2e`, run Detox tests using the following command: + ``` + npm start - iOS (Debug): + > react-native start + ``` - ``` - detox test --configuration ios.sim.debug - ``` + From `/js/react_native/e2e`, run Detox tests using the following command: - Android (Debug): + iOS (Debug): - ``` - detox test --configuration android.emu.debug - ``` + ``` + detox test --configuration ios.sim.debug + ``` + + Android (Debug): + + ``` + detox test --configuration android.emu.debug + ``` - 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.*** + 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._** 5. Run Android and iOS apps. @@ -469,6 +482,7 @@ From ORT v1.13 onwards the 'full' ONNX Runtime package is used. It supports both yarn e2e android yarn e2e ios ``` + ### NPM Packaging 1. Update a version using `npm version ` from `/js/react_native` folder. If it's for a dev, use `npm version -dev.` diff --git a/js/build_jsep.bat b/js/build_jsep.bat new file mode 100644 index 0000000000000..02f1170ecb067 --- /dev/null +++ b/js/build_jsep.bat @@ -0,0 +1,91 @@ +@echo off + +rem build_jsep.bat --- build onnxruntime-web with JSEP +rem +rem Usage: +rem build_jsep.bat config threaded [clean] +rem +rem Options: +rem config Build configuration, "d" or "r" +rem threaded Build with threading support, "st" or "mt" +rem clean Perform a clean build, "clean" or empty + +setlocal enabledelayedexpansion + +set ROOT=%~dp0..\ + +:arg1 +if ["%~1"]==["d"] ( + set CONFIG=Debug + set CONFIG_EXTRA_FLAG=--enable_wasm_debug_info + goto :arg2 +) +if ["%~1"]==["r"] ( + set CONFIG=Release + set CONFIG_EXTRA_FLAG= + goto :arg2 +) +echo Invalid configuration "%~1", must be "d"(Debug) or "r"(Release) +exit /b 1 + +:arg2 +if ["%~2"]==["st"] ( + set BUILD_DIR=%ROOT%build_jsep_st + set THREADED_EXTRA_FLAG= + set TARGET_FILE_PREFIX=ort-wasm-simd + goto :arg3 +) +if ["%~2"]==["mt"] ( + set BUILD_DIR=%ROOT%build_jsep_mt + set THREADED_EXTRA_FLAG=--enable_wasm_threads + set TARGET_FILE_PREFIX=ort-wasm-simd-threaded + goto :arg3 +) +echo Invalid threading option "%~2", must be "st" or "mt" +exit /b 1 + +:arg3 +if ["%~3"]==["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% %THREADED_EXTRA_FLAG%^ + --skip_submodule_sync --build_wasm --skip_tests --enable_wasm_simd --use_jsep --target onnxruntime_webassembly --build_dir %BUILD_DIR% + +IF NOT "%ERRORLEVEL%" == "0" ( + exit /b %ERRORLEVEL% +) + +copy /Y %BUILD_DIR%\%CONFIG%\%TARGET_FILE_PREFIX%.js %ROOT%js\web\lib\wasm\binding\%TARGET_FILE_PREFIX%.jsep.js +copy /Y %BUILD_DIR%\%CONFIG%\%TARGET_FILE_PREFIX%.wasm %ROOT%js\web\dist\%TARGET_FILE_PREFIX%.jsep.wasm diff --git a/js/common/.gitignore b/js/common/.gitignore index 9d573ceeb98b9..e5cc35f3cbe77 100644 --- a/js/common/.gitignore +++ b/js/common/.gitignore @@ -2,4 +2,7 @@ node_modules/ dist/ docs/ +/test/**/*.js +/test/**/*.js.map + tsconfig.tsbuildinfo diff --git a/js/common/.npmignore b/js/common/.npmignore index 64e6b50c6fd79..03cc37ddcd87b 100644 --- a/js/common/.npmignore +++ b/js/common/.npmignore @@ -1,8 +1,11 @@ /.vscode/ +build.js webpack.config.js typedoc.json tsconfig.json **/*.tsbuildinfo +/test/ + *.tgz diff --git a/js/common/build.js b/js/common/build.js new file mode 100644 index 0000000000000..cf459f5efa812 --- /dev/null +++ b/js/common/build.js @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +'use strict'; + +import {execSync} from 'node:child_process'; +import {writeFileSync} from 'node:fs'; +import {resolve, dirname} from 'node:path'; +import {fileURLToPath} from 'node:url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +// build the following folders: +// - dist/cjs +// - dist/esm +execSync('npm run build:cjs', {shell: true, stdio: 'inherit', cwd: __dirname}); +execSync('npm run build:esm', {shell: true, stdio: 'inherit', cwd: __dirname}); + +// generate package.json files under each of the dist folders for commonJS and ESModule +// this trick allows typescript to import this package as different module type +// see also: https://evertpot.com/universal-commonjs-esm-typescript-packages/ +writeFileSync(resolve(__dirname, './dist/cjs', 'package.json'), '{"type": "commonjs"}'); +writeFileSync(resolve(__dirname, './dist/esm', 'package.json'), '{"type": "module"}'); + +// launch webpack to generate bundles +execSync('npm run build:bundles', {shell: true, stdio: 'inherit', cwd: __dirname}); diff --git a/js/common/lib/backend-impl.ts b/js/common/lib/backend-impl.ts index 49e363e398679..75feba1d0ae08 100644 --- a/js/common/lib/backend-impl.ts +++ b/js/common/lib/backend-impl.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import {Backend} from './backend'; +import {Backend} from './backend.js'; interface BackendInfo { backend: Backend; @@ -12,7 +12,7 @@ interface BackendInfo { aborted?: boolean; } -const backends: {[name: string]: BackendInfo} = {}; +const backends: Map = new Map(); const backendsSortedByPriority: string[] = []; /** @@ -23,13 +23,13 @@ const backendsSortedByPriority: string[] = []; * @param priority - an integer indicating the priority of the backend. Higher number means higher priority. if priority * < 0, it will be considered as a 'beta' version and will not be used as a fallback backend by default. * - * @internal + * @ignore */ export const registerBackend = (name: string, backend: Backend, priority: number): void => { if (backend && typeof backend.init === 'function' && typeof backend.createSessionHandler === 'function') { - const currentBackend = backends[name]; + const currentBackend = backends.get(name); if (currentBackend === undefined) { - backends[name] = {backend, priority}; + backends.set(name, {backend, priority}); } else if (currentBackend.priority > priority) { // same name is already registered with a higher priority. skip registeration. return; @@ -46,7 +46,7 @@ export const registerBackend = (name: string, backend: Backend, priority: number } for (let i = 0; i < backendsSortedByPriority.length; i++) { - if (backends[backendsSortedByPriority[i]].priority <= priority) { + if (backends.get(backendsSortedByPriority[i])!.priority <= priority) { backendsSortedByPriority.splice(i, 0, name); return; } @@ -65,13 +65,13 @@ export const registerBackend = (name: string, backend: Backend, priority: number * @param backendHints - a list of execution provider names to lookup. If omitted use registered backends as list. * @returns a promise that resolves to the backend. * - * @internal + * @ignore */ export const resolveBackend = async(backendHints: readonly string[]): Promise => { const backendNames = backendHints.length === 0 ? backendsSortedByPriority : backendHints; const errors = []; for (const backendName of backendNames) { - const backendInfo = backends[backendName]; + const backendInfo = backends.get(backendName); if (backendInfo) { if (backendInfo.initialized) { return backendInfo.backend; diff --git a/js/common/lib/backend.ts b/js/common/lib/backend.ts index 3f1bbc9fa7159..804f33f00d103 100644 --- a/js/common/lib/backend.ts +++ b/js/common/lib/backend.ts @@ -1,11 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import {InferenceSession} from './inference-session'; -import {OnnxValue} from './onnx-value'; +import {InferenceSession} from './inference-session.js'; +import {OnnxValue} from './onnx-value.js'; /** - * @internal + * @ignore */ export declare namespace SessionHandler { type FeedsType = {[name: string]: OnnxValue}; @@ -16,7 +16,7 @@ export declare namespace SessionHandler { /** * Represent a handler instance of an inference session. * - * @internal + * @ignore */ export interface SessionHandler { dispose(): Promise; @@ -34,7 +34,7 @@ export interface SessionHandler { /** * Represent a backend that provides implementation of model inferencing. * - * @internal + * @ignore */ export interface Backend { /** @@ -46,4 +46,4 @@ export interface Backend { Promise; } -export {registerBackend} from './backend-impl'; +export {registerBackend} from './backend-impl.js'; diff --git a/js/common/lib/env-impl.ts b/js/common/lib/env-impl.ts index f4f3f447b4c1a..c3e96d864dcfe 100644 --- a/js/common/lib/env-impl.ts +++ b/js/common/lib/env-impl.ts @@ -1,18 +1,19 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import {Env} from './env'; +import {Env} from './env.js'; +import {version} from './version.js'; type LogLevelType = Env['logLevel']; -export class EnvImpl implements Env { - constructor() { - this.wasm = {}; - this.webgl = {}; - this.webgpu = {}; - this.logLevelInternal = 'warning'; - } - // TODO standadize the getter and setter convention in env for other fields. +let logLevelValue: Required = 'warning'; + +export const env: Env = { + wasm: {} as Env.WebAssemblyFlags, + webgl: {} as Env.WebGLFlags, + webgpu: {} as Env.WebGpuFlags, + versions: {common: version}, + set logLevel(value: LogLevelType) { if (value === undefined) { return; @@ -20,19 +21,12 @@ export class EnvImpl implements Env { if (typeof value !== 'string' || ['verbose', 'info', 'warning', 'error', 'fatal'].indexOf(value) === -1) { throw new Error(`Unsupported logging level: ${value}`); } - this.logLevelInternal = value; - } - get logLevel(): LogLevelType { - return this.logLevelInternal; - } - - debug?: boolean; - - wasm: Env.WebAssemblyFlags; - webgl: Env.WebGLFlags; - webgpu: Env.WebGpuFlags; - - [name: string]: unknown; + logLevelValue = value; + }, + get logLevel(): Required { + return logLevelValue; + }, +}; - private logLevelInternal: Required; -} +// set property 'logLevel' so that they can be correctly transferred to worker by `postMessage()`. +Object.defineProperty(env, 'logLevel', {enumerable: true}); diff --git a/js/common/lib/env.ts b/js/common/lib/env.ts index 8d75a4c99a65f..525272294c587 100644 --- a/js/common/lib/env.ts +++ b/js/common/lib/env.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import {EnvImpl} from './env-impl'; +import {env as envImpl} from './env-impl.js'; export declare namespace Env { export type WasmPrefixOrFilePaths = string|{ @@ -61,6 +61,10 @@ export declare namespace Env { * @defaultValue `'webgl2'` */ contextId?: 'webgl'|'webgl2'; + /** + * Get the WebGL rendering context. + */ + readonly context: WebGLRenderingContext; /** * Set or get the maximum batch size for matmul. 0 means to disable batching. * @@ -88,7 +92,19 @@ export declare namespace Env { } export interface WebGpuFlags { + /** + * Set or get the profiling mode. + */ profilingMode?: 'off'|'default'; + /** + * Get the device for WebGPU. + * + * When use with TypeScript, the type of this property is `GPUDevice` defined in "@webgpu/types". + * Use `const device = env.webgpu.device as GPUDevice;` in TypeScript to access this property with correct type. + * + * see comments on {@link GpuBufferType} for more details about why not use types defined in "@webgpu/types". + */ + readonly device: unknown; } } @@ -106,20 +122,31 @@ export interface Env { */ debug?: boolean; + /** + * Get version of the current package. + */ + readonly versions: { + readonly common: string; + readonly web?: string; + readonly node?: string; + // eslint-disable-next-line @typescript-eslint/naming-convention + readonly 'react-native'?: string; + }; + /** * Represent a set of flags for WebAssembly */ - wasm: Env.WebAssemblyFlags; + readonly wasm: Env.WebAssemblyFlags; /** * Represent a set of flags for WebGL */ - webgl: Env.WebGLFlags; + readonly webgl: Env.WebGLFlags; /** * Represent a set of flags for WebGPU */ - webgpu: Env.WebGpuFlags; + readonly webgpu: Env.WebGpuFlags; [name: string]: unknown; } @@ -127,4 +154,4 @@ export interface Env { /** * Represent a set of flags as a global singleton. */ -export const env: Env = new EnvImpl(); +export const env: Env = envImpl; diff --git a/js/common/lib/index.ts b/js/common/lib/index.ts index 81d380354bc1c..85df1747f8576 100644 --- a/js/common/lib/index.ts +++ b/js/common/lib/index.ts @@ -17,8 +17,8 @@ * @packageDocumentation */ -export * from './backend'; -export * from './env'; -export * from './inference-session'; -export * from './tensor'; -export * from './onnx-value'; +export * from './backend.js'; +export * from './env.js'; +export * from './inference-session.js'; +export * from './tensor.js'; +export * from './onnx-value.js'; diff --git a/js/common/lib/inference-session-impl.ts b/js/common/lib/inference-session-impl.ts index c43ea7e419b11..06949b4a26c0d 100644 --- a/js/common/lib/inference-session-impl.ts +++ b/js/common/lib/inference-session-impl.ts @@ -1,11 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import {SessionHandler} from './backend'; -import {resolveBackend} from './backend-impl'; -import {InferenceSession as InferenceSessionInterface} from './inference-session'; -import {OnnxValue} from './onnx-value'; -import {Tensor} from './tensor'; +import {resolveBackend} from './backend-impl.js'; +import {SessionHandler} from './backend.js'; +import {InferenceSession as InferenceSessionInterface} from './inference-session.js'; +import {OnnxValue} from './onnx-value.js'; +import {Tensor} from './tensor.js'; type SessionOptions = InferenceSessionInterface.SessionOptions; type RunOptions = InferenceSessionInterface.RunOptions; @@ -109,12 +109,21 @@ export class InferenceSession implements InferenceSessionInterface { const returnValue: {[name: string]: OnnxValue} = {}; for (const key in results) { if (Object.hasOwnProperty.call(results, key)) { - returnValue[key] = new Tensor(results[key].type, results[key].data, results[key].dims); + const result = results[key]; + if (result instanceof Tensor) { + returnValue[key] = result; + } else { + returnValue[key] = new Tensor(result.type, result.data, result.dims); + } } } return returnValue; } + async release(): Promise { + return this.handler.dispose(); + } + static create(path: string, options?: SessionOptions): Promise; static create(buffer: ArrayBufferLike, options?: SessionOptions): Promise; static create(buffer: ArrayBufferLike, byteOffset: number, byteLength?: number, options?: SessionOptions): diff --git a/js/common/lib/inference-session.ts b/js/common/lib/inference-session.ts index 638cb90f36716..71a5912df2464 100644 --- a/js/common/lib/inference-session.ts +++ b/js/common/lib/inference-session.ts @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import {InferenceSession as InferenceSessionImpl} from './inference-session-impl'; -import {OnnxValue} from './onnx-value'; +import {InferenceSession as InferenceSessionImpl} from './inference-session-impl.js'; +import {OnnxValue, OnnxValueDataLocation} from './onnx-value.js'; /* eslint-disable @typescript-eslint/no-redeclare */ @@ -66,6 +66,13 @@ export declare namespace InferenceSession { */ interOpNumThreads?: number; + /** + * The free dimension override. + * + * This setting is available only in ONNXRuntime (Node.js binding and react-native) or WebAssembly backend + */ + freeDimensionOverrides?: {readonly [dimensionName: string]: number}; + /** * The optimization level. * @@ -138,6 +145,14 @@ export declare namespace InferenceSession { */ logVerbosityLevel?: number; + /** + * Specify string as a preferred data location for all outputs, or an object that use output names as keys and a + * preferred data location as corresponding values. + * + * This setting is available only in ONNXRuntime Web for WebGL and WebGPU EP. + */ + preferredOutputLocation?: OnnxValueDataLocation|{readonly [outputName: string]: OnnxValueDataLocation}; + /** * Store configurations for a session. See * https://github.com/microsoft/onnxruntime/blob/main/include/onnxruntime/core/session/ @@ -165,14 +180,20 @@ export declare namespace InferenceSession { // Currently, we have the following backends to support execution providers: // Backend Node.js binding: supports 'cpu' and 'cuda'. - // Backend WebAssembly: supports 'cpu', 'wasm' and 'xnnpack'. + // Backend WebAssembly: supports 'cpu', 'wasm', 'xnnpack' and 'webnn'. // Backend ONNX.js: supports 'webgl'. + // Backend React Native: supports 'cpu', 'xnnpack', 'coreml' (iOS), 'nnapi' (Android). interface ExecutionProviderOptionMap { cpu: CpuExecutionProviderOption; + coreml: CoreMlExecutionProviderOption; cuda: CudaExecutionProviderOption; + dml: DmlExecutionProviderOption; + tensorrt: TensorRtExecutionProviderOption; wasm: WebAssemblyExecutionProviderOption; webgl: WebGLExecutionProviderOption; xnnpack: XnnpackExecutionProviderOption; + webnn: WebNNExecutionProviderOption; + nnapi: NnapiExecutionProviderOption; } type ExecutionProviderName = keyof ExecutionProviderOptionMap; @@ -190,6 +211,18 @@ export declare namespace InferenceSession { readonly name: 'cuda'; deviceId?: number; } + export interface CoreMlExecutionProviderOption extends ExecutionProviderOption { + readonly name: 'coreml'; + coreMlFlags?: number; + } + export interface DmlExecutionProviderOption extends ExecutionProviderOption { + readonly name: 'dml'; + deviceId?: number; + } + export interface TensorRtExecutionProviderOption extends ExecutionProviderOption { + readonly name: 'tensorrt'; + deviceId?: number; + } export interface WebAssemblyExecutionProviderOption extends ExecutionProviderOption { readonly name: 'wasm'; } @@ -200,6 +233,24 @@ export declare namespace InferenceSession { export interface XnnpackExecutionProviderOption extends ExecutionProviderOption { readonly name: 'xnnpack'; } + export interface WebNNExecutionProviderOption extends ExecutionProviderOption { + readonly name: 'webnn'; + deviceType?: 'cpu'|'gpu'; + powerPreference?: 'default'|'low-power'|'high-performance'; + } + export interface CoreMLExecutionProviderOption extends ExecutionProviderOption { + readonly name: 'coreml'; + useCPUOnly?: boolean; + enableOnSubgraph?: boolean; + onlyEnableDeviceWithANE?: boolean; + } + export interface NnapiExecutionProviderOption extends ExecutionProviderOption { + readonly name: 'nnapi'; + useFP16?: boolean; + useNCHW?: boolean; + cpuDisabled?: boolean; + cpuOnly?: boolean; + } // #endregion // #endregion @@ -300,6 +351,15 @@ export interface InferenceSession { // #endregion + // #region release() + + /** + * Release the inference session and the underlying resources. + */ + release(): Promise; + + // #endregion + // #region profiling /** diff --git a/js/common/lib/onnx-value.ts b/js/common/lib/onnx-value.ts index 53c493dc3337e..a16a30d25d839 100644 --- a/js/common/lib/onnx-value.ts +++ b/js/common/lib/onnx-value.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import {Tensor} from './tensor'; +import {Tensor} from './tensor.js'; type NonTensorType = never; @@ -11,3 +11,8 @@ type NonTensorType = never; * NOTE: currently not support non-tensor */ export type OnnxValue = Tensor|NonTensorType; + +/** + * Type OnnxValueDataLocation represents the location of the data of an OnnxValue. + */ +export type OnnxValueDataLocation = Tensor.DataLocation; diff --git a/js/common/lib/tensor-conversion-impl.ts b/js/common/lib/tensor-conversion-impl.ts new file mode 100644 index 0000000000000..22397321e8c6b --- /dev/null +++ b/js/common/lib/tensor-conversion-impl.ts @@ -0,0 +1,192 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import {TensorToDataUrlOptions, TensorToImageDataOptions} from './tensor-conversion.js'; +import {Tensor} from './tensor.js'; + +/** + * implementation of Tensor.toDataURL() + */ +export const tensorToDataURL = (tensor: Tensor, options?: TensorToDataUrlOptions): string => { + const canvas = document.createElement('canvas'); + canvas.width = tensor.dims[3]; + canvas.height = tensor.dims[2]; + const pixels2DContext = canvas.getContext('2d'); + + if (pixels2DContext != null) { + // Default values for height and width & format + let width: number; + let height: number; + if (options?.tensorLayout !== undefined && options.tensorLayout === 'NHWC') { + width = tensor.dims[2]; + height = tensor.dims[3]; + } else { // Default layout is NCWH + width = tensor.dims[3]; + height = tensor.dims[2]; + } + + const inputformat = options?.format !== undefined ? options.format : 'RGB'; + + const norm = options?.norm; + let normMean: [number, number, number, number]; + let normBias: [number, number, number, number]; + if (norm === undefined || norm.mean === undefined) { + normMean = [255, 255, 255, 255]; + } else { + if (typeof (norm.mean) === 'number') { + normMean = [norm.mean, norm.mean, norm.mean, norm.mean]; + } else { + normMean = [norm.mean[0], norm.mean[1], norm.mean[2], 0]; + if (norm.mean[3] !== undefined) { + normMean[3] = norm.mean[3]; + } + } + } + if (norm === undefined || norm.bias === undefined) { + normBias = [0, 0, 0, 0]; + } else { + if (typeof (norm.bias) === 'number') { + normBias = [norm.bias, norm.bias, norm.bias, norm.bias]; + } else { + normBias = [norm.bias[0], norm.bias[1], norm.bias[2], 0]; + if (norm.bias[3] !== undefined) { + normBias[3] = norm.bias[3]; + } + } + } + + const stride = height * width; + // Default pointer assignments + let rTensorPointer = 0, gTensorPointer = stride, bTensorPointer = stride * 2, aTensorPointer = -1; + + // Updating the pointer assignments based on the input image format + if (inputformat === 'RGBA') { + rTensorPointer = 0; + gTensorPointer = stride; + bTensorPointer = stride * 2; + aTensorPointer = stride * 3; + } else if (inputformat === 'RGB') { + rTensorPointer = 0; + gTensorPointer = stride; + bTensorPointer = stride * 2; + } else if (inputformat === 'RBG') { + rTensorPointer = 0; + bTensorPointer = stride; + gTensorPointer = stride * 2; + } + + for (let i = 0; i < height; i++) { + for (let j = 0; j < width; j++) { + const R = ((tensor.data[rTensorPointer++] as number) - normBias[0]) * normMean[0]; // R value + const G = ((tensor.data[gTensorPointer++] as number) - normBias[1]) * normMean[1]; // G value + const B = ((tensor.data[bTensorPointer++] as number) - normBias[2]) * normMean[2]; // B value + const A = aTensorPointer === -1 ? + 255 : + ((tensor.data[aTensorPointer++] as number) - normBias[3]) * normMean[3]; // A value + // eslint-disable-next-line @typescript-eslint/restrict-plus-operands + pixels2DContext.fillStyle = 'rgba(' + R + ',' + G + ',' + B + ',' + A + ')'; + pixels2DContext.fillRect(j, i, 1, 1); + } + } + return canvas.toDataURL(); + } else { + throw new Error('Can not access image data'); + } +}; + +/** + * implementation of Tensor.toImageData() + */ +export const tensorToImageData = (tensor: Tensor, options?: TensorToImageDataOptions): ImageData => { + const pixels2DContext = document.createElement('canvas').getContext('2d'); + let image: ImageData; + if (pixels2DContext != null) { + // Default values for height and width & format + let width: number; + let height: number; + let channels: number; + if (options?.tensorLayout !== undefined && options.tensorLayout === 'NHWC') { + width = tensor.dims[2]; + height = tensor.dims[1]; + channels = tensor.dims[3]; + } else { // Default layout is NCWH + width = tensor.dims[3]; + height = tensor.dims[2]; + channels = tensor.dims[1]; + } + const inputformat = options !== undefined ? (options.format !== undefined ? options.format : 'RGB') : 'RGB'; + + const norm = options?.norm; + let normMean: [number, number, number, number]; + let normBias: [number, number, number, number]; + if (norm === undefined || norm.mean === undefined) { + normMean = [255, 255, 255, 255]; + } else { + if (typeof (norm.mean) === 'number') { + normMean = [norm.mean, norm.mean, norm.mean, norm.mean]; + } else { + normMean = [norm.mean[0], norm.mean[1], norm.mean[2], 255]; + if (norm.mean[3] !== undefined) { + normMean[3] = norm.mean[3]; + } + } + } + if (norm === undefined || norm.bias === undefined) { + normBias = [0, 0, 0, 0]; + } else { + if (typeof (norm.bias) === 'number') { + normBias = [norm.bias, norm.bias, norm.bias, norm.bias]; + } else { + normBias = [norm.bias[0], norm.bias[1], norm.bias[2], 0]; + if (norm.bias[3] !== undefined) { + normBias[3] = norm.bias[3]; + } + } + } + + const stride = height * width; + if (options !== undefined) { + if (options.format !== undefined && (channels === 4 && options.format !== 'RGBA') || + (channels === 3 && (options.format !== 'RGB' && options.format !== 'BGR'))) { + throw new Error('Tensor format doesn\'t match input tensor dims'); + } + } + + // Default pointer assignments + const step = 4; + let rImagePointer = 0, gImagePointer = 1, bImagePointer = 2, aImagePointer = 3; + let rTensorPointer = 0, gTensorPointer = stride, bTensorPointer = stride * 2, aTensorPointer = -1; + + // Updating the pointer assignments based on the input image format + if (inputformat === 'RGBA') { + rTensorPointer = 0; + gTensorPointer = stride; + bTensorPointer = stride * 2; + aTensorPointer = stride * 3; + } else if (inputformat === 'RGB') { + rTensorPointer = 0; + gTensorPointer = stride; + bTensorPointer = stride * 2; + } else if (inputformat === 'RBG') { + rTensorPointer = 0; + bTensorPointer = stride; + gTensorPointer = stride * 2; + } + + image = pixels2DContext.createImageData(width, height); + + for (let i = 0; i < height * width; + rImagePointer += step, gImagePointer += step, bImagePointer += step, aImagePointer += step, i++) { + image.data[rImagePointer] = ((tensor.data[rTensorPointer++] as number) - normBias[0]) * normMean[0]; // R value + image.data[gImagePointer] = ((tensor.data[gTensorPointer++] as number) - normBias[1]) * normMean[1]; // G value + image.data[bImagePointer] = ((tensor.data[bTensorPointer++] as number) - normBias[2]) * normMean[2]; // B value + image.data[aImagePointer] = aTensorPointer === -1 ? + 255 : + ((tensor.data[aTensorPointer++] as number) - normBias[3]) * normMean[3]; // A value + } + + } else { + throw new Error('Can not access image data'); + } + return image; +}; diff --git a/js/common/lib/tensor-conversion.ts b/js/common/lib/tensor-conversion.ts new file mode 100644 index 0000000000000..4542b3b4a773c --- /dev/null +++ b/js/common/lib/tensor-conversion.ts @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import {OptionsFormat, OptionsNormalizationParameters, OptionsTensorLayout} from './tensor-factory.js'; + +export interface TensorToDataUrlOptions extends OptionsTensorLayout, OptionsFormat, OptionsNormalizationParameters {} + +export interface TensorToImageDataOptions extends OptionsTensorLayout, OptionsFormat, OptionsNormalizationParameters {} + +export interface ConversionUtils { + /** + * creates a DataURL instance from tensor + * + * @param options - An optional object representing options for creating a DataURL instance from the tensor. + * + * The following default settings will be applied: + * - `format`: `'RGB'` + * - `tensorLayout`: `'NCHW'` + * @returns a DataURL string representing the image converted from tensor data + */ + toDataURL(options?: TensorToDataUrlOptions): string; + + /** + * creates an ImageData instance from tensor + * + * @param options - An optional object representing options for creating an ImageData instance from the tensor. + * + * The following default settings will be applied: + * - `format`: `'RGB'` + * - `tensorLayout`: `'NCHW'` + * @returns an ImageData instance representing the image converted from tensor data + */ + toImageData(options?: TensorToImageDataOptions): ImageData; +} diff --git a/js/common/lib/tensor-factory-impl.ts b/js/common/lib/tensor-factory-impl.ts new file mode 100644 index 0000000000000..7228c4a97055b --- /dev/null +++ b/js/common/lib/tensor-factory-impl.ts @@ -0,0 +1,264 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import {OptionsDimensions, OptionsFormat, OptionsNormalizationParameters, OptionsTensorFormat, OptionsTensorLayout, TensorFromGpuBufferOptions, TensorFromImageBitmapOptions, TensorFromImageDataOptions, TensorFromImageElementOptions, TensorFromTextureOptions, TensorFromUrlOptions} from './tensor-factory.js'; +import {Tensor} from './tensor-impl.js'; +import {Tensor as TensorInterface} from './tensor.js'; + +interface BufferToTensorOptions extends OptionsDimensions, OptionsTensorLayout, OptionsNormalizationParameters, + OptionsFormat, OptionsTensorFormat {} + +/** + * Create a new tensor object from image object + * + * @param buffer - Extracted image buffer data - assuming RGBA format + * @param imageFormat - input image configuration - required configurations height, width, format + * @param tensorFormat - output tensor configuration - Default is RGB format + */ +export const bufferToTensor = (buffer: Uint8ClampedArray|undefined, options: BufferToTensorOptions): Tensor => { + if (buffer === undefined) { + throw new Error('Image buffer must be defined'); + } + if (options.height === undefined || options.width === undefined) { + throw new Error('Image height and width must be defined'); + } + if (options.tensorLayout === 'NHWC') { + throw new Error('NHWC Tensor layout is not supported yet'); + } + + const {height, width} = options; + + const norm = options.norm ?? {mean: 255, bias: 0}; + let normMean: [number, number, number, number]; + let normBias: [number, number, number, number]; + + if (typeof (norm.mean) === 'number') { + normMean = [norm.mean, norm.mean, norm.mean, norm.mean]; + } else { + normMean = [norm.mean![0], norm.mean![1], norm.mean![2], norm.mean![3] ?? 255]; + } + + if (typeof (norm.bias) === 'number') { + normBias = [norm.bias, norm.bias, norm.bias, norm.bias]; + } else { + normBias = [norm.bias![0], norm.bias![1], norm.bias![2], norm.bias![3] ?? 0]; + } + + const inputformat = options.format !== undefined ? options.format : 'RGBA'; + // default value is RGBA since imagedata and HTMLImageElement uses it + + const outputformat = + options.tensorFormat !== undefined ? (options.tensorFormat !== undefined ? options.tensorFormat : 'RGB') : 'RGB'; + const stride = height * width; + const float32Data = outputformat === 'RGBA' ? new Float32Array(stride * 4) : new Float32Array(stride * 3); + + // Default pointer assignments + let step = 4, rImagePointer = 0, gImagePointer = 1, bImagePointer = 2, aImagePointer = 3; + let rTensorPointer = 0, gTensorPointer = stride, bTensorPointer = stride * 2, aTensorPointer = -1; + + // Updating the pointer assignments based on the input image format + if (inputformat === 'RGB') { + step = 3; + rImagePointer = 0; + gImagePointer = 1; + bImagePointer = 2; + aImagePointer = -1; + } + + // Updating the pointer assignments based on the output tensor format + if (outputformat === 'RGBA') { + aTensorPointer = stride * 3; + } else if (outputformat === 'RBG') { + rTensorPointer = 0; + bTensorPointer = stride; + gTensorPointer = stride * 2; + } else if (outputformat === 'BGR') { + bTensorPointer = 0; + gTensorPointer = stride; + rTensorPointer = stride * 2; + } + + for (let i = 0; i < stride; + i++, rImagePointer += step, bImagePointer += step, gImagePointer += step, aImagePointer += step) { + float32Data[rTensorPointer++] = (buffer[rImagePointer] + normBias[0]) / normMean[0]; + float32Data[gTensorPointer++] = (buffer[gImagePointer] + normBias[1]) / normMean[1]; + float32Data[bTensorPointer++] = (buffer[bImagePointer] + normBias[2]) / normMean[2]; + if (aTensorPointer !== -1 && aImagePointer !== -1) { + float32Data[aTensorPointer++] = (buffer[aImagePointer] + normBias[3]) / normMean[3]; + } + } + + // Float32Array -> ort.Tensor + const outputTensor = outputformat === 'RGBA' ? new Tensor('float32', float32Data, [1, 4, height, width]) : + new Tensor('float32', float32Data, [1, 3, height, width]); + return outputTensor; +}; + +/** + * implementation of Tensor.fromImage(). + */ +export const tensorFromImage = async( + image: ImageData|HTMLImageElement|ImageBitmap|string, + options?: TensorFromImageDataOptions|TensorFromImageElementOptions|TensorFromImageBitmapOptions| + TensorFromUrlOptions): Promise => { + // checking the type of image object + const isHTMLImageEle = typeof (HTMLImageElement) !== 'undefined' && image instanceof HTMLImageElement; + const isImageDataEle = typeof (ImageData) !== 'undefined' && image instanceof ImageData; + const isImageBitmap = typeof (ImageBitmap) !== 'undefined' && image instanceof ImageBitmap; + const isString = typeof image === 'string'; + + let data: Uint8ClampedArray|undefined; + let bufferToTensorOptions: BufferToTensorOptions = options ?? {}; + + // filling and checking image configuration options + if (isHTMLImageEle) { + // HTMLImageElement - image object - format is RGBA by default + const canvas = document.createElement('canvas'); + canvas.width = image.width; + canvas.height = image.height; + const pixels2DContext = canvas.getContext('2d'); + + if (pixels2DContext != null) { + let height = image.height; + let width = image.width; + if (options !== undefined && options.resizedHeight !== undefined && options.resizedWidth !== undefined) { + height = options.resizedHeight; + width = options.resizedWidth; + } + + if (options !== undefined) { + bufferToTensorOptions = options; + if (options.tensorFormat !== undefined) { + throw new Error('Image input config format must be RGBA for HTMLImageElement'); + } else { + bufferToTensorOptions.tensorFormat = 'RGBA'; + } + bufferToTensorOptions.height = height; + bufferToTensorOptions.width = width; + } else { + bufferToTensorOptions.tensorFormat = 'RGBA'; + bufferToTensorOptions.height = height; + bufferToTensorOptions.width = width; + } + + pixels2DContext.drawImage(image, 0, 0); + data = pixels2DContext.getImageData(0, 0, width, height).data; + } else { + throw new Error('Can not access image data'); + } + } else if (isImageDataEle) { + let height: number; + let width: number; + + if (options !== undefined && options.resizedWidth !== undefined && options.resizedHeight !== undefined) { + height = options.resizedHeight; + width = options.resizedWidth; + } else { + height = image.height; + width = image.width; + } + + if (options !== undefined) { + bufferToTensorOptions = options; + } + bufferToTensorOptions.format = 'RGBA'; + bufferToTensorOptions.height = height; + bufferToTensorOptions.width = width; + + if (options !== undefined) { + const tempCanvas = document.createElement('canvas'); + + tempCanvas.width = width; + tempCanvas.height = height; + + const pixels2DContext = tempCanvas.getContext('2d'); + + if (pixels2DContext != null) { + pixels2DContext.putImageData(image, 0, 0); + data = pixels2DContext.getImageData(0, 0, width, height).data; + } else { + throw new Error('Can not access image data'); + } + } else { + data = image.data; + } + } else if (isImageBitmap) { + // ImageBitmap - image object - format must be provided by user + if (options === undefined) { + throw new Error('Please provide image config with format for Imagebitmap'); + } + + const canvas = document.createElement('canvas'); + canvas.width = image.width; + canvas.height = image.height; + const pixels2DContext = canvas.getContext('2d'); + + if (pixels2DContext != null) { + const height = image.height; + const width = image.width; + pixels2DContext.drawImage(image, 0, 0, width, height); + data = pixels2DContext.getImageData(0, 0, width, height).data; + bufferToTensorOptions.height = height; + bufferToTensorOptions.width = width; + return bufferToTensor(data, bufferToTensorOptions); + } else { + throw new Error('Can not access image data'); + } + } else if (isString) { + return new Promise((resolve, reject) => { + const canvas = document.createElement('canvas'); + const context = canvas.getContext('2d'); + if (!image || !context) { + return reject(); + } + const newImage = new Image(); + newImage.crossOrigin = 'Anonymous'; + newImage.src = image; + newImage.onload = () => { + canvas.width = newImage.width; + canvas.height = newImage.height; + context.drawImage(newImage, 0, 0, canvas.width, canvas.height); + const img = context.getImageData(0, 0, canvas.width, canvas.height); + + bufferToTensorOptions.height = canvas.height; + bufferToTensorOptions.width = canvas.width; + resolve(bufferToTensor(img.data, bufferToTensorOptions)); + }; + }); + } else { + throw new Error('Input data provided is not supported - aborted tensor creation'); + } + + if (data !== undefined) { + return bufferToTensor(data, bufferToTensorOptions); + } else { + throw new Error('Input data provided is not supported - aborted tensor creation'); + } +}; + +/** + * implementation of Tensor.fromTexture(). + */ +export const tensorFromTexture = ( + texture: TensorInterface.TextureType, options: TensorFromTextureOptions): Tensor => { + const {width, height, download, dispose} = options; + // Always assume RGBAF32. TODO: support different texture format + const dims = [1, height, width, 4]; + return new Tensor({location: 'texture', type: 'float32', texture, dims, download, dispose}); +}; + +/** + * implementation of Tensor.fromGpuBuffer(). + */ +export const tensorFromGpuBuffer = ( + gpuBuffer: TensorInterface.GpuBufferType, options: TensorFromGpuBufferOptions): Tensor => { + const {dataType, dims, download, dispose} = options; + return new Tensor({location: 'gpu-buffer', type: dataType ?? 'float32', gpuBuffer, dims, download, dispose}); +}; + +/** + * implementation of Tensor.fromPinnedBuffer(). + */ +export const tensorFromPinnedBuffer = ( + type: T, buffer: TensorInterface.DataTypeMap[T], dims?: readonly number[]): Tensor => + new Tensor({location: 'cpu-pinned', type, data: buffer, dims: dims ?? [buffer.length]}); diff --git a/js/common/lib/tensor-factory.ts b/js/common/lib/tensor-factory.ts new file mode 100644 index 0000000000000..6e19d7fb898a3 --- /dev/null +++ b/js/common/lib/tensor-factory.ts @@ -0,0 +1,320 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import {Tensor, TypedTensor} from './tensor.js'; + +export type ImageFormat = 'RGB'|'RGBA'|'BGR'|'RBG'; +export type ImageTensorLayout = 'NHWC'|'NCHW'; + +// the following region contains type definitions for constructing tensor from a specific location. + +// #region types for constructing a tensor from a specific location + +/** + * represent common properties of the parameter for constructing a tensor from a specific location. + */ +interface CommonConstructorParameters extends Pick { + /** + * Specify the data type of the tensor. + */ + readonly type: T; +} + +/** + * represent the parameter for constructing a tensor from a GPU resource. + */ +interface GpuResourceConstructorParameters { + /** + * an optional callback function to download data from GPU to CPU. + * + * If not provided, the tensor treat the GPU data as external resource. + */ + download?(): Promise; + + /** + * an optional callback function that will be called when the tensor is disposed. + * + * If not provided, the tensor treat the GPU data as external resource. + */ + dispose?(): void; +} + +/** + * represent the parameter for constructing a tensor from a pinned CPU buffer + */ +export interface CpuPinnedConstructorParameters extends + CommonConstructorParameters { + /** + * Specify the location of the data to be 'cpu-pinned'. + */ + readonly location: 'cpu-pinned'; + /** + * Specify the CPU pinned buffer that holds the tensor data. + */ + readonly data: Tensor.DataTypeMap[T]; +} + +/** + * represent the parameter for constructing a tensor from a WebGL texture + */ +export interface TextureConstructorParameters extends + CommonConstructorParameters, GpuResourceConstructorParameters { + /** + * Specify the location of the data to be 'texture'. + */ + readonly location: 'texture'; + /** + * Specify the WebGL texture that holds the tensor data. + */ + readonly texture: Tensor.TextureType; +} + +/** + * represent the parameter for constructing a tensor from a WebGPU buffer + */ +export interface GpuBufferConstructorParameters extends + CommonConstructorParameters, GpuResourceConstructorParameters { + /** + * Specify the location of the data to be 'gpu-buffer'. + */ + readonly location: 'gpu-buffer'; + /** + * Specify the WebGPU buffer that holds the tensor data. + */ + readonly gpuBuffer: Tensor.GpuBufferType; +} + +// #endregion + +// the following region contains type definitions of each individual options. +// the tensor factory functions use a composition of those options as the parameter type. + +// #region Options fields + +export interface OptionsFormat { + /** + * Describes the image format represented in RGBA color space. + */ + format?: ImageFormat; +} + +export interface OptionsTensorFormat { + /** + * Describes the image format of the tensor. + * + * NOTE: this is different from option 'format'. While option 'format' represents the original image, 'tensorFormat' + * represents the target format of the tensor. A transpose will be performed if they are different. + */ + tensorFormat?: ImageFormat; +} + +export interface OptionsTensorDataType { + /** + * Describes the data type of the tensor. + */ + dataType?: 'float32'|'uint8'; +} + +export interface OptionsTensorLayout { + /** + * Describes the tensor layout when representing data of one or more image(s). + */ + tensorLayout?: ImageTensorLayout; +} + +export interface OptionsDimensions { + /** + * Describes the image height in pixel + */ + height?: number; + /** + * Describes the image width in pixel + */ + width?: number; +} + +export interface OptionResizedDimensions { + /** + * Describes the resized height. If omitted, original height will be used. + */ + resizedHeight?: number; + /** + * Describes resized width - can be accessed via tensor dimensions as well + */ + resizedWidth?: number; +} + +export interface OptionsNormalizationParameters { + /** + * Describes normalization parameters when preprocessing the image as model input. + * + * Data element are ranged from 0 to 255. + */ + norm?: { + /** + * The 'bias' value for image normalization. + * - If omitted, use default value 0. + * - If it's a single number, apply to each channel + * - If it's an array of 3 or 4 numbers, apply element-wise. Number of elements need to match the number of channels + * for the corresponding image format + */ + bias?: number|[number, number, number]|[number, number, number, number]; + /** + * The 'mean' value for image normalization. + * - If omitted, use default value 255. + * - If it's a single number, apply to each channel + * - If it's an array of 3 or 4 numbers, apply element-wise. Number of elements need to match the number of channels + * for the corresponding image format + */ + mean?: number | [number, number, number] | [number, number, number, number]; + }; +} + +// #endregion + +// #region Options composition + +export interface TensorFromImageDataOptions extends OptionResizedDimensions, OptionsTensorFormat, OptionsTensorLayout, + OptionsTensorDataType, OptionsNormalizationParameters {} + +export interface TensorFromImageElementOptions extends OptionResizedDimensions, OptionsTensorFormat, + OptionsTensorLayout, OptionsTensorDataType, + OptionsNormalizationParameters {} + +export interface TensorFromUrlOptions extends OptionsDimensions, OptionResizedDimensions, OptionsTensorFormat, + OptionsTensorLayout, OptionsTensorDataType, + OptionsNormalizationParameters {} + +export interface TensorFromImageBitmapOptions extends OptionResizedDimensions, OptionsTensorFormat, OptionsTensorLayout, + OptionsTensorDataType, OptionsNormalizationParameters {} + +export interface TensorFromTextureOptions extends + Required, OptionsFormat, GpuResourceConstructorParameters/* TODO: add more */ {} + +export interface TensorFromGpuBufferOptions extends + Pick, GpuResourceConstructorParameters { + /** + * Describes the data type of the tensor. + */ + dataType?: T; +} + +// #endregion + +/** + * type TensorFactory defines the factory functions of 'Tensor' to create tensor instances from existing data or + * resources. + */ +export interface TensorFactory { + /** + * create a tensor from an ImageData object + * + * @param imageData - the ImageData object to create tensor from + * @param options - An optional object representing options for creating tensor from ImageData. + * + * The following default settings will be applied: + * - `tensorFormat`: `'RGB'` + * - `tensorLayout`: `'NCHW'` + * - `dataType`: `'float32'` + * @returns A promise that resolves to a tensor object + */ + fromImage(imageData: ImageData, options?: TensorFromImageDataOptions): + Promise|TypedTensor<'uint8'>>; + + /** + * create a tensor from a HTMLImageElement object + * + * @param imageElement - the HTMLImageElement object to create tensor from + * @param options - An optional object representing options for creating tensor from HTMLImageElement. + * + * The following default settings will be applied: + * - `tensorFormat`: `'RGB'` + * - `tensorLayout`: `'NCHW'` + * - `dataType`: `'float32'` + * @returns A promise that resolves to a tensor object + */ + fromImage(imageElement: HTMLImageElement, options?: TensorFromImageElementOptions): + Promise|TypedTensor<'uint8'>>; + + /** + * create a tensor from URL + * + * @param urlSource - a string as a URL to the image or a data URL containing the image data. + * @param options - An optional object representing options for creating tensor from URL. + * + * The following default settings will be applied: + * - `tensorFormat`: `'RGB'` + * - `tensorLayout`: `'NCHW'` + * - `dataType`: `'float32'` + * @returns A promise that resolves to a tensor object + */ + fromImage(urlSource: string, options?: TensorFromUrlOptions): Promise|TypedTensor<'uint8'>>; + + /** + * create a tensor from an ImageBitmap object + * + * @param bitMap - the ImageBitmap object to create tensor from + * @param options - An optional object representing options for creating tensor from URL. + * + * The following default settings will be applied: + * - `tensorFormat`: `'RGB'` + * - `tensorLayout`: `'NCHW'` + * - `dataType`: `'float32'` + * @returns A promise that resolves to a tensor object + */ + fromImage(bitmap: ImageBitmap, options: TensorFromImageBitmapOptions): + Promise|TypedTensor<'uint8'>>; + + /** + * create a tensor from a WebGL texture + * + * @param texture - the WebGLTexture object to create tensor from + * @param options - An optional object representing options for creating tensor from WebGL texture. + * + * The options include following properties: + * - `width`: the width of the texture. Required. + * - `height`: the height of the texture. Required. + * - `format`: the format of the texture. If omitted, assume 'RGBA'. + * - `download`: an optional function to download the tensor data from GPU to CPU. If omitted, the GPU data + * will not be able to download. Usually, this is provided by a GPU backend for the inference outputs. Users don't + * need to provide this function. + * - `dispose`: an optional function to dispose the tensor data on GPU. If omitted, the GPU data will not be disposed. + * Usually, this is provided by a GPU backend for the inference outputs. Users don't need to provide this function. + * + * @returns a tensor object + */ + fromTexture( + texture: Tensor.TextureType, options: TensorFromTextureOptions): TypedTensor<'float32'>; + + /** + * create a tensor from a WebGPU buffer + * + * @param buffer - the GPUBuffer object to create tensor from + * @param options - An optional object representing options for creating tensor from WebGPU buffer. + * + * The options include following properties: + * - `dataType`: the data type of the tensor. If omitted, assume 'float32'. + * - `dims`: the dimension of the tensor. Required. + * - `download`: an optional function to download the tensor data from GPU to CPU. If omitted, the GPU data + * will not be able to download. Usually, this is provided by a GPU backend for the inference outputs. Users don't + * need to provide this function. + * - `dispose`: an optional function to dispose the tensor data on GPU. If omitted, the GPU data will not be disposed. + * Usually, this is provided by a GPU backend for the inference outputs. Users don't need to provide this function. + * + * @returns a tensor object + */ + fromGpuBuffer( + buffer: Tensor.GpuBufferType, options: TensorFromGpuBufferOptions): TypedTensor; + + /** + * create a tensor from a pre-allocated buffer. The buffer will be used as a pinned buffer. + * + * @param type - the tensor element type. + * @param buffer - a TypedArray corresponding to the type. + * @param dims - specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. + * + * @returns a tensor object + */ + fromPinnedBuffer>( + type: T, buffer: Tensor.DataTypeMap[T], dims?: readonly number[]): TypedTensor; +} diff --git a/js/common/lib/tensor-impl-type-mapping.ts b/js/common/lib/tensor-impl-type-mapping.ts new file mode 100644 index 0000000000000..c4a43ea27fea1 --- /dev/null +++ b/js/common/lib/tensor-impl-type-mapping.ts @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import {Tensor} from './tensor.js'; + +export type SupportedTypedArrayConstructors = Float32ArrayConstructor|Uint8ArrayConstructor|Int8ArrayConstructor| + Uint16ArrayConstructor|Int16ArrayConstructor|Int32ArrayConstructor|BigInt64ArrayConstructor|Uint8ArrayConstructor| + Float64ArrayConstructor|Uint32ArrayConstructor|BigUint64ArrayConstructor; +export type SupportedTypedArray = InstanceType; + +// a runtime map that maps type string to TypedArray constructor. Should match Tensor.DataTypeMap. +export const NUMERIC_TENSOR_TYPE_TO_TYPEDARRAY_MAP = new Map([ + ['float32', Float32Array], + ['uint8', Uint8Array], + ['int8', Int8Array], + ['uint16', Uint16Array], + ['float16', Uint16Array], + ['int16', Int16Array], + ['int32', Int32Array], + ['bool', Uint8Array], + ['float64', Float64Array], + ['uint32', Uint32Array], +]); + +// a runtime map that maps type string to TypedArray constructor. Should match Tensor.DataTypeMap. +export const NUMERIC_TENSOR_TYPEDARRAY_TO_TYPE_MAP = new Map([ + [Float32Array, 'float32'], + [Uint8Array, 'uint8'], + [Int8Array, 'int8'], + [Uint16Array, 'uint16'], + [Int16Array, 'int16'], + [Int32Array, 'int32'], + [Float64Array, 'float64'], + [Uint32Array, 'uint32'], +]); + +// the following code allows delaying execution of BigInt checking. This allows lazy initialization for +// NUMERIC_TENSOR_TYPE_TO_TYPEDARRAY_MAP and NUMERIC_TENSOR_TYPEDARRAY_TO_TYPE_MAP, which allows BigInt polyfill +// if available. +let isBigIntChecked = false; +export const checkBigInt = () => { + if (!isBigIntChecked) { + isBigIntChecked = true; + const isBigInt64ArrayAvailable = typeof BigInt64Array !== 'undefined' && typeof BigInt64Array.from === 'function'; + const isBigUint64ArrayAvailable = + typeof BigUint64Array !== 'undefined' && typeof BigUint64Array.from === 'function'; + + if (isBigInt64ArrayAvailable) { + NUMERIC_TENSOR_TYPE_TO_TYPEDARRAY_MAP.set('int64', BigInt64Array); + NUMERIC_TENSOR_TYPEDARRAY_TO_TYPE_MAP.set(BigInt64Array, 'int64'); + } + if (isBigUint64ArrayAvailable) { + NUMERIC_TENSOR_TYPE_TO_TYPEDARRAY_MAP.set('uint64', BigUint64Array); + NUMERIC_TENSOR_TYPEDARRAY_TO_TYPE_MAP.set(BigUint64Array, 'uint64'); + } + } +}; diff --git a/js/common/lib/tensor-impl.ts b/js/common/lib/tensor-impl.ts index 81c3c0674e128..e3e2b9c728556 100644 --- a/js/common/lib/tensor-impl.ts +++ b/js/common/lib/tensor-impl.ts @@ -1,532 +1,421 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import {Tensor as TensorInterface, TensorFromImageOptions, TensorToImageDataOptions} from './tensor'; +import {tensorToDataURL, tensorToImageData} from './tensor-conversion-impl.js'; +import {TensorToDataUrlOptions, TensorToImageDataOptions} from './tensor-conversion.js'; +import {tensorFromGpuBuffer, tensorFromImage, tensorFromPinnedBuffer, tensorFromTexture} from './tensor-factory-impl.js'; +import {CpuPinnedConstructorParameters, GpuBufferConstructorParameters, TensorFromGpuBufferOptions, TensorFromImageBitmapOptions, TensorFromImageDataOptions, TensorFromImageElementOptions, TensorFromTextureOptions, TensorFromUrlOptions, TextureConstructorParameters} from './tensor-factory.js'; +import {checkBigInt, NUMERIC_TENSOR_TYPE_TO_TYPEDARRAY_MAP, NUMERIC_TENSOR_TYPEDARRAY_TO_TYPE_MAP, SupportedTypedArray, SupportedTypedArrayConstructors} from './tensor-impl-type-mapping.js'; +import {calculateSize, tensorReshape} from './tensor-utils-impl.js'; +import {Tensor as TensorInterface} from './tensor.js'; + +// type aliases for those exported from Tensor interface type TensorType = TensorInterface.Type; type TensorDataType = TensorInterface.DataType; - -type SupportedTypedArrayConstructors = Float32ArrayConstructor|Uint8ArrayConstructor|Int8ArrayConstructor| - Uint16ArrayConstructor|Int16ArrayConstructor|Int32ArrayConstructor|BigInt64ArrayConstructor|Uint8ArrayConstructor| - Float64ArrayConstructor|Uint32ArrayConstructor|BigUint64ArrayConstructor; -type SupportedTypedArray = InstanceType; - -// a runtime map that maps type string to TypedArray constructor. Should match Tensor.DataTypeMap. -const NUMERIC_TENSOR_TYPE_TO_TYPEDARRAY_MAP = new Map([ - ['float32', Float32Array], - ['uint8', Uint8Array], - ['int8', Int8Array], - ['uint16', Uint16Array], - ['int16', Int16Array], - ['int32', Int32Array], - ['bool', Uint8Array], - ['float64', Float64Array], - ['uint32', Uint32Array], -]); - -// a runtime map that maps type string to TypedArray constructor. Should match Tensor.DataTypeMap. -const NUMERIC_TENSOR_TYPEDARRAY_TO_TYPE_MAP = new Map([ - [Float32Array, 'float32'], - [Uint8Array, 'uint8'], - [Int8Array, 'int8'], - [Uint16Array, 'uint16'], - [Int16Array, 'int16'], - [Int32Array, 'int32'], - [Float64Array, 'float64'], - [Uint32Array, 'uint32'], -]); - -// the following code allows delaying execution of BigInt checking. This allows lazy initialization for -// NUMERIC_TENSOR_TYPE_TO_TYPEDARRAY_MAP and NUMERIC_TENSOR_TYPEDARRAY_TO_TYPE_MAP, which allows BigInt polyfill -// if available. -let isBigIntChecked = false; -const checkBigInt = () => { - if (!isBigIntChecked) { - isBigIntChecked = true; - const isBigInt64ArrayAvailable = typeof BigInt64Array !== 'undefined' && typeof BigInt64Array.from === 'function'; - const isBigUint64ArrayAvailable = - typeof BigUint64Array !== 'undefined' && typeof BigUint64Array.from === 'function'; - - if (isBigInt64ArrayAvailable) { - NUMERIC_TENSOR_TYPE_TO_TYPEDARRAY_MAP.set('int64', BigInt64Array); - NUMERIC_TENSOR_TYPEDARRAY_TO_TYPE_MAP.set(BigInt64Array, 'int64'); - } - if (isBigUint64ArrayAvailable) { - NUMERIC_TENSOR_TYPE_TO_TYPEDARRAY_MAP.set('uint64', BigUint64Array); - NUMERIC_TENSOR_TYPEDARRAY_TO_TYPE_MAP.set(BigUint64Array, 'uint64'); - } - } -}; +type TensorDataLocation = TensorInterface.DataLocation; +type TensorTextureType = TensorInterface.TextureType; +type TensorGpuBufferType = TensorInterface.GpuBufferType; /** - * calculate size from dims. + * the implementation of Tensor interface. * - * @param dims the dims array. May be an illegal input. + * @ignore */ -const calculateSize = (dims: readonly unknown[]): number => { - let size = 1; - for (let i = 0; i < dims.length; i++) { - const dim = dims[i]; - if (typeof dim !== 'number' || !Number.isSafeInteger(dim)) { - throw new TypeError(`dims[${i}] must be an integer, got: ${dim}`); - } - if (dim < 0) { - throw new RangeError(`dims[${i}] must be a non-negative integer, got: ${dim}`); - } - size *= dim; - } - return size; -}; - export class Tensor implements TensorInterface { // #region constructors - constructor(type: TensorType, data: TensorDataType|readonly number[]|readonly boolean[], dims?: readonly number[]); - constructor(data: TensorDataType|readonly boolean[], dims?: readonly number[]); + + /** + * Construct a new CPU tensor object from the given type, data and dims. + */ constructor( - arg0: TensorType|TensorDataType|readonly boolean[], arg1?: TensorDataType|readonly number[]|readonly boolean[], - arg2?: readonly number[]) { + type: TensorType, data: TensorDataType|readonly string[]|readonly number[]|readonly boolean[], + dims?: readonly number[]); + /** + * Construct a new CPU tensor object from the given data and dims. Type is inferred from data. + */ + constructor(data: TensorDataType|readonly string[]|readonly boolean[], dims?: readonly number[]); + /** + * Construct a new tensor object from the pinned CPU data with the given type and dims. + * + * Tensor's location will be set to 'cpu-pinned'. + * + * @param params - Specify the parameters to construct the tensor. + */ + constructor(params: CpuPinnedConstructorParameters); + /** + * Construct a new tensor object from the WebGL texture with the given type and dims. + * + * Tensor's location will be set to 'texture'. + * + * @param params - Specify the parameters to construct the tensor. + */ + constructor(params: TextureConstructorParameters); + /** + * Construct a new tensor object from the WebGPU buffer with the given type and dims. + * + * Tensor's location will be set to 'gpu-buffer'. + * + * @param params - Specify the parameters to construct the tensor. + */ + constructor(params: GpuBufferConstructorParameters); + + /** + * implementation. + */ + constructor( + arg0: TensorType|TensorDataType|readonly string[]|readonly boolean[]|CpuPinnedConstructorParameters| + TextureConstructorParameters|GpuBufferConstructorParameters, + arg1?: TensorDataType|readonly number[]|readonly string[]|readonly boolean[], arg2?: readonly number[]) { + // perform one-time check for BigInt support checkBigInt(); let type: TensorType; - let data: TensorDataType; - let dims: typeof arg1|typeof arg2; - // check whether arg0 is type or data - if (typeof arg0 === 'string') { + let dims: readonly number[]; + + if (typeof arg0 === 'object' && 'location' in arg0) { // - // Override: constructor(type, data, ...) + // constructing tensor from specific location // - type = arg0; - dims = arg2; - if (arg0 === 'string') { - // string tensor - if (!Array.isArray(arg1)) { - throw new TypeError('A string tensor\'s data must be a string array.'); + this.dataLocation = arg0.location; + type = arg0.type; + dims = arg0.dims; + switch (arg0.location) { + case 'cpu-pinned': { + const expectedTypedArrayConstructor = NUMERIC_TENSOR_TYPE_TO_TYPEDARRAY_MAP.get(type); + if (!expectedTypedArrayConstructor) { + throw new TypeError(`unsupported type "${type}" to create tensor from pinned buffer`); + } + if (!(arg0.data instanceof expectedTypedArrayConstructor)) { + throw new TypeError(`buffer should be of type ${expectedTypedArrayConstructor.name}`); + } + this.cpuData = arg0.data; + break; } - // we don't check whether every element in the array is string; this is too slow. we assume it's correct and - // error will be populated at inference - data = arg1; - } else { - // numeric tensor - const typedArrayConstructor = NUMERIC_TENSOR_TYPE_TO_TYPEDARRAY_MAP.get(arg0); - if (typedArrayConstructor === undefined) { - throw new TypeError(`Unsupported tensor type: ${arg0}.`); + case 'texture': { + if (type !== 'float32') { + throw new TypeError(`unsupported type "${type}" to create tensor from texture`); + } + this.gpuTextureData = arg0.texture; + this.downloader = arg0.download; + this.disposer = arg0.dispose; + break; } - if (Array.isArray(arg1)) { - // use 'as any' here because TypeScript's check on type of 'SupportedTypedArrayConstructors.from()' produces - // incorrect results. - // 'typedArrayConstructor' should be one of the typed array prototype objects. - // eslint-disable-next-line @typescript-eslint/no-explicit-any - data = (typedArrayConstructor as any).from(arg1); - } else if (arg1 instanceof typedArrayConstructor) { - data = arg1; - } else { - throw new TypeError(`A ${type} tensor's data must be type of ${typedArrayConstructor}`); + case 'gpu-buffer': { + if ((type !== 'float32' && type !== 'float16' && type !== 'int32' && type !== 'int64' && type !== 'uint32' && + type !== 'bool')) { + throw new TypeError(`unsupported type "${type}" to create tensor from gpu buffer`); + } + this.gpuBufferData = arg0.gpuBuffer; + this.downloader = arg0.download; + this.disposer = arg0.dispose; + break; } + default: + throw new Error(`Tensor constructor: unsupported location '${this.dataLocation}'`); } } else { // - // Override: constructor(data, ...) + // constructing tensor of location 'cpu' // - dims = arg1; - if (Array.isArray(arg0)) { - // only boolean[] and string[] is supported - if (arg0.length === 0) { - throw new TypeError('Tensor type cannot be inferred from an empty array.'); - } - const firstElementType = typeof arg0[0]; - if (firstElementType === 'string') { - type = 'string'; - data = arg0; - } else if (firstElementType === 'boolean') { - type = 'bool'; - // 'arg0' is of type 'boolean[]'. Uint8Array.from(boolean[]) actually works, but typescript thinks this is - // wrong type. We use 'as any' to make it happy. - // eslint-disable-next-line @typescript-eslint/no-explicit-any - data = Uint8Array.from(arg0 as any[]); + let data: TensorDataType; + let maybeDims: typeof arg1|typeof arg2; + // check whether arg0 is type or data + if (typeof arg0 === 'string') { + // + // Override: constructor(type, data, ...) + // + type = arg0; + maybeDims = arg2; + if (arg0 === 'string') { + // string tensor + if (!Array.isArray(arg1)) { + throw new TypeError('A string tensor\'s data must be a string array.'); + } + // we don't check whether every element in the array is string; this is too slow. we assume it's correct and + // error will be populated at inference + data = arg1; } else { - throw new TypeError(`Invalid element type of data array: ${firstElementType}.`); + // numeric tensor + const typedArrayConstructor = NUMERIC_TENSOR_TYPE_TO_TYPEDARRAY_MAP.get(arg0); + if (typedArrayConstructor === undefined) { + throw new TypeError(`Unsupported tensor type: ${arg0}.`); + } + if (Array.isArray(arg1)) { + if (arg0 === 'float16') { + // Throw error here because when user try to use number array as data, + // e.g. new Tensor('float16', [1, 2, 3, 4], dims)), it will actually call + // Uint16Array.from(arg1) which generates wrong data. + throw new TypeError( + 'Creating a float16 tensor from number array is not supported. Please use Uint16Array as data.'); + } else if (arg0 === 'uint64' || arg0 === 'int64') { + // use 'as any' here because: + // 1. TypeScript's check on type of 'Array.isArray()' does not work with readonly arrays. + // see https://github.com/microsoft/TypeScript/issues/17002 + // 2. TypeScript's check on union type of '(BigInt64ArrayConstructor|BigUint64ArrayConstructor).from()' + // does not accept parameter mapFn. + // 3. parameters of 'SupportedTypedArrayConstructors.from()' does not match the requirement of the union + // type. + + // assume 'arg1' is of type "readonly number[]|readonly bigint[]" here. + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + data = (typedArrayConstructor as any).from(arg1, BigInt); + } else { + // assume 'arg1' is of type "readonly number[]" here. + // eslint-disable-next-line @typescript-eslint/no-explicit-any + data = (typedArrayConstructor as any).from(arg1); + } + } else if (arg1 instanceof typedArrayConstructor) { + data = arg1; + } else { + throw new TypeError(`A ${type} tensor's data must be type of ${typedArrayConstructor}`); + } } } else { - // get tensor type from TypedArray - const mappedType = - NUMERIC_TENSOR_TYPEDARRAY_TO_TYPE_MAP.get(arg0.constructor as SupportedTypedArrayConstructors); - if (mappedType === undefined) { - throw new TypeError(`Unsupported type for tensor data: ${arg0.constructor}.`); + // + // Override: constructor(data, ...) + // + maybeDims = arg1; + if (Array.isArray(arg0)) { + // only boolean[] and string[] is supported + if (arg0.length === 0) { + throw new TypeError('Tensor type cannot be inferred from an empty array.'); + } + const firstElementType = typeof arg0[0]; + if (firstElementType === 'string') { + type = 'string'; + data = arg0; + } else if (firstElementType === 'boolean') { + type = 'bool'; + // 'arg0' is of type 'boolean[]'. Uint8Array.from(boolean[]) actually works, but typescript thinks this is + // wrong type. We use 'as any' to make it happy. + // eslint-disable-next-line @typescript-eslint/no-explicit-any + data = Uint8Array.from(arg0 as any[]); + } else { + throw new TypeError(`Invalid element type of data array: ${firstElementType}.`); + } + } else { + // get tensor type from TypedArray + const mappedType = + NUMERIC_TENSOR_TYPEDARRAY_TO_TYPE_MAP.get(arg0.constructor as SupportedTypedArrayConstructors); + if (mappedType === undefined) { + throw new TypeError(`Unsupported type for tensor data: ${arg0.constructor}.`); + } + type = mappedType; + data = arg0 as SupportedTypedArray; } - type = mappedType; - data = arg0 as SupportedTypedArray; } - } - // type and data is processed, now processing dims - if (dims === undefined) { - // assume 1-D tensor if dims omitted - dims = [data.length]; - } else if (!Array.isArray(dims)) { - throw new TypeError('A tensor\'s dims must be a number array'); + // type and data is processed, now processing dims + if (maybeDims === undefined) { + // assume 1-D tensor if dims omitted + maybeDims = [data.length]; + } else if (!Array.isArray(maybeDims)) { + throw new TypeError('A tensor\'s dims must be a number array'); + } + dims = maybeDims as readonly number[]; + + this.cpuData = data; + this.dataLocation = 'cpu'; } - // perform check + // perform check on dims const size = calculateSize(dims); - if (size !== data.length) { - throw new Error(`Tensor's size(${size}) does not match data length(${data.length}).`); + // if data is on CPU, check whether data length matches tensor size + if (this.cpuData && size !== this.cpuData.length) { + throw new Error(`Tensor's size(${size}) does not match data length(${this.cpuData.length}).`); } - this.dims = dims as readonly number[]; this.type = type; - this.data = data; + this.dims = dims; this.size = size; } // #endregion - /** - * Create a new tensor object from image object - * - * @param buffer - Extracted image buffer data - assuming RGBA format - * @param imageFormat - input image configuration - required configurations height, width, format - * @param tensorFormat - output tensor configuration - Default is RGB format - */ - private static bufferToTensor(buffer: Uint8ClampedArray|undefined, options: TensorFromImageOptions): Tensor { - if (buffer === undefined) { - throw new Error('Image buffer must be defined'); - } - if (options.height === undefined || options.width === undefined) { - throw new Error('Image height and width must be defined'); - } - const {height, width} = options; + // #region factory + static async fromImage( + image: ImageData|HTMLImageElement|ImageBitmap|string, + options?: TensorFromImageDataOptions|TensorFromImageElementOptions|TensorFromImageBitmapOptions| + TensorFromUrlOptions): Promise { + return tensorFromImage(image, options); + } - const norm = options.norm; - let normMean: number; - let normBias: number; - if (norm === undefined || norm.mean === undefined) { - normMean = 255; - } else { - normMean = norm.mean; - } - if (norm === undefined || norm.bias === undefined) { - normBias = 0; - } else { - normBias = norm.bias; - } + static fromTexture( + texture: TensorTextureType, options: TensorFromTextureOptions): TensorInterface { + return tensorFromTexture(texture, options); + } - const inputformat = options.bitmapFormat !== undefined ? options.bitmapFormat : 'RGBA'; - // default value is RGBA since imagedata and HTMLImageElement uses it - - const outputformat = options.tensorFormat !== undefined ? - (options.tensorFormat !== undefined ? options.tensorFormat : 'RGB') : - 'RGB'; - const offset = height * width; - const float32Data = outputformat === 'RGBA' ? new Float32Array(offset * 4) : new Float32Array(offset * 3); - - // Default pointer assignments - let step = 4, rImagePointer = 0, gImagePointer = 1, bImagePointer = 2, aImagePointer = 3; - let rTensorPointer = 0, gTensorPointer = offset, bTensorPointer = offset * 2, aTensorPointer = -1; - - // Updating the pointer assignments based on the input image format - if (inputformat === 'RGB') { - step = 3; - rImagePointer = 0; - gImagePointer = 1; - bImagePointer = 2; - aImagePointer = -1; - } + static fromGpuBuffer( + gpuBuffer: TensorGpuBufferType, options: TensorFromGpuBufferOptions): TensorInterface { + return tensorFromGpuBuffer(gpuBuffer, options); + } - // Updating the pointer assignments based on the output tensor format - if (outputformat === 'RGBA') { - aTensorPointer = offset * 3; - } else if (outputformat === 'RBG') { - rTensorPointer = 0; - bTensorPointer = offset; - gTensorPointer = offset * 2; - } else if (outputformat === 'BGR') { - bTensorPointer = 0; - gTensorPointer = offset; - rTensorPointer = offset * 2; - } + static fromPinnedBuffer( + type: T, buffer: TensorInterface.DataTypeMap[T], dims?: readonly number[]): Tensor { + return tensorFromPinnedBuffer(type, buffer, dims); + } - for (let i = 0; i < offset; - i++, rImagePointer += step, bImagePointer += step, gImagePointer += step, aImagePointer += step) { - float32Data[rTensorPointer++] = (buffer[rImagePointer] + normBias) / normMean; - float32Data[gTensorPointer++] = (buffer[gImagePointer] + normBias) / normMean; - float32Data[bTensorPointer++] = (buffer[bImagePointer] + normBias) / normMean; - if (aTensorPointer !== -1 && aImagePointer !== -1) { - float32Data[aTensorPointer++] = (buffer[aImagePointer] + normBias) / normMean; - } - } + // #endregion - // Float32Array -> ort.Tensor - const outputTensor = outputformat === 'RGBA' ? new Tensor('float32', float32Data, [1, 4, height, width]) : - new Tensor('float32', float32Data, [1, 3, height, width]); - return outputTensor; + // #region conversions + toDataURL(options?: TensorToDataUrlOptions): string { + return tensorToDataURL(this, options); } - // #region factory - static async fromImage(imageData: ImageData, options?: TensorFromImageOptions): Promise; - static async fromImage(imageElement: HTMLImageElement, options?: TensorFromImageOptions): Promise; - static async fromImage(bitmap: ImageBitmap, options: TensorFromImageOptions): Promise; - static async fromImage(url: string, options?: TensorFromImageOptions): Promise; - - static async fromImage(image: ImageData|HTMLImageElement|ImageBitmap|string, options?: TensorFromImageOptions): - Promise { - // checking the type of image object - const isHTMLImageEle = typeof (HTMLImageElement) !== 'undefined' && image instanceof HTMLImageElement; - const isImageDataEle = typeof (ImageData) !== 'undefined' && image instanceof ImageData; - const isImageBitmap = typeof (ImageBitmap) !== 'undefined' && image instanceof ImageBitmap; - const isURL = typeof (String) !== 'undefined' && (image instanceof String || typeof image === 'string'); - - let data: Uint8ClampedArray|undefined; - let tensorConfig: TensorFromImageOptions = {}; - - // filling and checking image configuration options - if (isHTMLImageEle) { - // HTMLImageElement - image object - format is RGBA by default - const canvas = document.createElement('canvas'); - canvas.width = image.width; - canvas.height = image.height; - const pixels2DContext = canvas.getContext('2d'); - - if (pixels2DContext != null) { - let height = image.height; - let width = image.width; - if (options !== undefined && options.resizedHeight !== undefined && options.resizedWidth !== undefined) { - height = options.resizedHeight; - width = options.resizedWidth; - } - - if (options !== undefined) { - tensorConfig = options; - if (options.tensorFormat !== undefined) { - throw new Error('Image input config format must be RGBA for HTMLImageElement'); - } else { - tensorConfig.tensorFormat = 'RGBA'; - } - if (options.height !== undefined && options.height !== height) { - throw new Error('Image input config height doesn\'t match HTMLImageElement height'); - } else { - tensorConfig.height = height; - } - if (options.width !== undefined && options.width !== width) { - throw new Error('Image input config width doesn\'t match HTMLImageElement width'); - } else { - tensorConfig.width = width; - } - } else { - tensorConfig.tensorFormat = 'RGBA'; - tensorConfig.height = height; - tensorConfig.width = width; - } + toImageData(options?: TensorToImageDataOptions): ImageData { + return tensorToImageData(this, options); + } + // #endregion - pixels2DContext.drawImage(image, 0, 0); - data = pixels2DContext.getImageData(0, 0, width, height).data; - } else { - throw new Error('Can not access image data'); - } + // #region public fields + readonly dims: readonly number[]; + readonly type: TensorType; + readonly size: number; + // #endregion - } else if (isImageDataEle) { - // ImageData - image object - format is RGBA by default - const format = 'RGBA'; - let height: number; - let width: number; + // #region private fields - if (options !== undefined && options.resizedWidth !== undefined && options.resizedHeight !== undefined) { - height = options.resizedHeight; - width = options.resizedWidth; - } else { - height = image.height; - width = image.width; - } + /** + * stores the location of the data. + */ + private dataLocation: TensorDataLocation; - if (options !== undefined) { - tensorConfig = options; - if (options.bitmapFormat !== undefined && options.bitmapFormat !== format) { - throw new Error('Image input config format must be RGBA for ImageData'); - } else { - tensorConfig.bitmapFormat = 'RGBA'; - } - } else { - tensorConfig.bitmapFormat = 'RGBA'; - } + /** + * stores the data on CPU, if location is 'cpu' or 'cpu-pinned'. otherwise empty. + */ + private cpuData?: TensorDataType; - tensorConfig.height = height; - tensorConfig.width = width; + /** + * stores the underlying texture when location is 'texture'. otherwise empty. + */ + private gpuTextureData?: TensorTextureType; - if (options !== undefined) { - const tempCanvas = document.createElement('canvas'); + /** + * stores the underlying GPU buffer when location is 'gpu-buffer'. otherwise empty. + */ + private gpuBufferData?: TensorGpuBufferType; - tempCanvas.width = width; - tempCanvas.height = height; + /** + * stores an optional downloader function to download data from GPU to CPU. + */ + private downloader?(): Promise; - const pixels2DContext = tempCanvas.getContext('2d'); + /** + * a flag indicating whether the data is being downloaded from GPU to CPU. + */ + private isDownloading?: boolean; - if (pixels2DContext != null) { - pixels2DContext.putImageData(image, 0, 0); - data = pixels2DContext.getImageData(0, 0, width, height).data; - } else { - throw new Error('Can not access image data'); - } - } else { - data = image.data; - } + /** + * stores an optional disposer function to dispose the underlying data. + */ + private disposer?(): void; + // #endregion - } else if (isImageBitmap) { - // ImageBitmap - image object - format must be provided by user - if (options === undefined) { - throw new Error('Please provide image config with format for Imagebitmap'); - } - if (options.bitmapFormat !== undefined) { - throw new Error('Image input config format must be defined for ImageBitmap'); - } + // #region properties + get data(): TensorDataType { + this.ensureValid(); + if (!this.cpuData) { + throw new Error( + 'The data is not on CPU. Use `getData()` to download GPU data to CPU, ' + + 'or use `texture` or `gpuBuffer` property to access the GPU data directly.'); + } + return this.cpuData; + } - const pixels2DContext = document.createElement('canvas').getContext('2d'); - - if (pixels2DContext != null) { - const height = image.height; - const width = image.width; - pixels2DContext.drawImage(image, 0, 0, width, height); - data = pixels2DContext.getImageData(0, 0, width, height).data; - if (options !== undefined) { - // using square brackets to avoid TS error - type 'never' - if (options.height !== undefined && options.height !== height) { - throw new Error('Image input config height doesn\'t match ImageBitmap height'); - } else { - tensorConfig.height = height; - } - // using square brackets to avoid TS error - type 'never' - if (options.width !== undefined && options.width !== width) { - throw new Error('Image input config width doesn\'t match ImageBitmap width'); - } else { - tensorConfig.width = width; - } - } else { - tensorConfig.height = height; - tensorConfig.width = width; - } - return Tensor.bufferToTensor(data, tensorConfig); - } else { - throw new Error('Can not access image data'); - } + get location(): TensorDataLocation { + return this.dataLocation; + } - } else if (isURL) { - return new Promise((resolve, reject) => { - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - if (!image || !context) { - return reject(); - } - const newImage = new Image(); - newImage.crossOrigin = 'Anonymous'; - newImage.src = image as string; - newImage.onload = () => { - canvas.width = newImage.width; - canvas.height = newImage.height; - context.drawImage(newImage, 0, 0, canvas.width, canvas.height); - const img = context.getImageData(0, 0, canvas.width, canvas.height); - if (options !== undefined) { - // using square brackets to avoid TS error - type 'never' - if (options.height !== undefined && options.height !== canvas.height) { - throw new Error('Image input config height doesn\'t match ImageBitmap height'); - } else { - tensorConfig.height = canvas.height; - } - // using square brackets to avoid TS error - type 'never' - if (options.width !== undefined && options.width !== canvas.width) { - throw new Error('Image input config width doesn\'t match ImageBitmap width'); - } else { - tensorConfig.width = canvas.width; - } - } else { - tensorConfig.height = canvas.height; - tensorConfig.width = canvas.width; - } - resolve(Tensor.bufferToTensor(img.data, tensorConfig)); - }; - }); - } else { - throw new Error('Input data provided is not supported - aborted tensor creation'); + get texture(): TensorTextureType { + this.ensureValid(); + if (!this.gpuTextureData) { + throw new Error('The data is not stored as a WebGL texture.'); } + return this.gpuTextureData; + } - if (data !== undefined) { - return Tensor.bufferToTensor(data, tensorConfig); - } else { - throw new Error('Input data provided is not supported - aborted tensor creation'); + get gpuBuffer(): TensorGpuBufferType { + this.ensureValid(); + if (!this.gpuBufferData) { + throw new Error('The data is not stored as a WebGPU buffer.'); } + return this.gpuBufferData; } + // #endregion - toImageData(options?: TensorToImageDataOptions): ImageData { - const pixels2DContext = document.createElement('canvas').getContext('2d'); - let image: ImageData; - if (pixels2DContext != null) { - // Default values for height and width & format - const width = this.dims[3]; - const height = this.dims[2]; - const channels = this.dims[1]; - - const inputformat = options !== undefined ? (options.format !== undefined ? options.format : 'RGB') : 'RGB'; - const normMean = options !== undefined ? (options.norm?.mean !== undefined ? options.norm.mean : 255) : 255; - const normBias = options !== undefined ? (options.norm?.bias !== undefined ? options.norm.bias : 0) : 0; - const offset = height * width; - - if (options !== undefined) { - if (options.height !== undefined && options.height !== height) { - throw new Error('Image output config height doesn\'t match tensor height'); - } - if (options.width !== undefined && options.width !== width) { - throw new Error('Image output config width doesn\'t match tensor width'); + // #region methods + + async getData(releaseData?: boolean): Promise { + this.ensureValid(); + switch (this.dataLocation) { + case 'cpu': + case 'cpu-pinned': + return this.data; + case 'texture': + case 'gpu-buffer': { + if (!this.downloader) { + throw new Error('The current tensor is not created with a specified data downloader.'); } - if (options.format !== undefined && (channels === 4 && options.format !== 'RGBA') || - (channels === 3 && (options.format !== 'RGB' && options.format !== 'BGR'))) { - throw new Error('Tensor format doesn\'t match input tensor dims'); + if (this.isDownloading) { + throw new Error('The current tensor is being downloaded.'); } - } - - // Default pointer assignments - const step = 4; - let rImagePointer = 0, gImagePointer = 1, bImagePointer = 2, aImagePointer = 3; - let rTensorPointer = 0, gTensorPointer = offset, bTensorPointer = offset * 2, aTensorPointer = -1; - - // Updating the pointer assignments based on the input image format - if (inputformat === 'RGBA') { - rTensorPointer = 0; - gTensorPointer = offset; - bTensorPointer = offset * 2; - aTensorPointer = offset * 3; - } else if (inputformat === 'RGB') { - rTensorPointer = 0; - gTensorPointer = offset; - bTensorPointer = offset * 2; - } else if (inputformat === 'RBG') { - rTensorPointer = 0; - bTensorPointer = offset; - gTensorPointer = offset * 2; - } + try { + this.isDownloading = true; + const data = await this.downloader(); + this.downloader = undefined; + this.dataLocation = 'cpu'; + this.cpuData = data; + + if (releaseData && this.disposer) { + this.disposer(); + this.disposer = undefined; + } - image = pixels2DContext.createImageData(width, height); + return data; - for (let i = 0; i < height * width; - rImagePointer += step, gImagePointer += step, bImagePointer += step, aImagePointer += step, i++) { - image.data[rImagePointer] = ((this.data[rTensorPointer++] as number) - normBias) * normMean; // R value - image.data[gImagePointer] = ((this.data[gTensorPointer++] as number) - normBias) * normMean; // G value - image.data[bImagePointer] = ((this.data[bTensorPointer++] as number) - normBias) * normMean; // B value - image.data[aImagePointer] = - aTensorPointer === -1 ? 255 : ((this.data[aTensorPointer++] as number) - normBias) * normMean; // A value + } finally { + this.isDownloading = false; + } } + default: + throw new Error(`cannot get data from location: ${this.dataLocation}`); + } + } - } else { - throw new Error('Can not access image data'); + dispose(): void { + if (this.isDownloading) { + throw new Error('The current tensor is being downloaded.'); } - return image; + + if (this.disposer) { + this.disposer(); + this.disposer = undefined; + } + this.cpuData = undefined; + this.gpuTextureData = undefined; + this.gpuBufferData = undefined; + this.downloader = undefined; + this.isDownloading = undefined; + + this.dataLocation = 'none'; } - // #region fields - readonly dims: readonly number[]; - readonly type: TensorType; - readonly data: TensorDataType; - readonly size: number; // #endregion // #region tensor utilities - reshape(dims: readonly number[]): Tensor { - return new Tensor(this.type, this.data, dims); + private ensureValid(): void { + if (this.dataLocation === 'none') { + throw new Error('The tensor is disposed.'); + } + } + + reshape(dims: readonly number[]): TensorInterface { + this.ensureValid(); + if (this.downloader || this.disposer) { + throw new Error('Cannot reshape a tensor that owns GPU resource.'); + } + return tensorReshape(this, dims); } // #endregion } diff --git a/js/common/lib/tensor-utils-impl.ts b/js/common/lib/tensor-utils-impl.ts new file mode 100644 index 0000000000000..bd3080b724651 --- /dev/null +++ b/js/common/lib/tensor-utils-impl.ts @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import {CpuPinnedConstructorParameters, GpuBufferConstructorParameters, TextureConstructorParameters} from './tensor-factory.js'; +import {Tensor} from './tensor-impl.js'; + +/** + * calculate size from dims. + * + * @param dims the dims array. May be an illegal input. + */ +export const calculateSize = (dims: readonly unknown[]): number => { + let size = 1; + for (let i = 0; i < dims.length; i++) { + const dim = dims[i]; + if (typeof dim !== 'number' || !Number.isSafeInteger(dim)) { + throw new TypeError(`dims[${i}] must be an integer, got: ${dim}`); + } + if (dim < 0) { + throw new RangeError(`dims[${i}] must be a non-negative integer, got: ${dim}`); + } + size *= dim; + } + return size; +}; + +/** + * implementation of Tensor.reshape() + */ +export const tensorReshape = (tensor: Tensor, dims: readonly number[]): Tensor => { + switch (tensor.location) { + case 'cpu': + return new Tensor(tensor.type, tensor.data, dims); + case 'cpu-pinned': + return new Tensor({ + location: 'cpu-pinned', + data: tensor.data as CpuPinnedConstructorParameters['data'], + type: tensor.type as CpuPinnedConstructorParameters['type'], + dims, + }); + case 'texture': + return new Tensor({ + location: 'texture', + texture: tensor.texture, + type: tensor.type as TextureConstructorParameters['type'], + dims, + }); + case 'gpu-buffer': + return new Tensor({ + location: 'gpu-buffer', + gpuBuffer: tensor.gpuBuffer, + type: tensor.type as GpuBufferConstructorParameters['type'], + dims, + }); + default: + throw new Error(`tensorReshape: tensor location ${tensor.location} is not supported`); + } +}; diff --git a/js/common/lib/tensor-utils.ts b/js/common/lib/tensor-utils.ts index f6459687dfc44..b24075aad2953 100644 --- a/js/common/lib/tensor-utils.ts +++ b/js/common/lib/tensor-utils.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import {Tensor, TensorToImageDataOptions, TypedTensor} from './tensor'; +import {ConversionUtils} from './tensor-conversion.js'; +import {Tensor, TypedTensor} from './tensor.js'; interface Properties { /** @@ -19,14 +20,12 @@ export interface TypedShapeUtils { reshape(dims: readonly number[]): TypedTensor; } -// TODO: add more tensor utilities -export interface TypedTensorUtils extends Properties, TypedShapeUtils { - /** - * creates an ImageData instance from tensor - * - * @param tensorFormat - Interface describing tensor instance - Defaults: RGB, 3 channels, 0-255, NHWC - * 0-255, NHWC - * @returns An ImageData instance which can be used to draw on canvas - */ - toImageData(options?: TensorToImageDataOptions): ImageData; -} +/** + * interface `TensorUtils` includes all utility members that does not use the type parameter from their signature. + */ +export interface TensorUtils extends Properties, ConversionUtils {} + +/** + * interface `TypedShapeUtils` includes all utility members that uses the type parameter from their signature. + */ +export interface TypedTensorUtils extends TensorUtils, TypedShapeUtils {} diff --git a/js/common/lib/tensor.ts b/js/common/lib/tensor.ts index 0b88cdf7070c2..6c08d1fe8e057 100644 --- a/js/common/lib/tensor.ts +++ b/js/common/lib/tensor.ts @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import {Tensor as TensorImpl} from './tensor-impl'; -import {TypedTensorUtils} from './tensor-utils'; +import {TensorFactory} from './tensor-factory.js'; +import {Tensor as TensorImpl} from './tensor-impl.js'; +import {TypedTensorUtils} from './tensor-utils.js'; /* eslint-disable @typescript-eslint/no-redeclare */ @@ -20,8 +21,46 @@ interface TypedTensorBase { readonly type: T; /** * Get the buffer data of the tensor. + * + * If the data is not on CPU (eg. it's in the form of WebGL texture or WebGPU buffer), throw error. */ readonly data: Tensor.DataTypeMap[T]; + /** + * Get the location of the data. + */ + readonly location: Tensor.DataLocation; + /** + * Get the WebGL texture that holds the tensor data. + * + * If the data is not on GPU as WebGL texture, throw error. + */ + readonly texture: Tensor.TextureType; + /** + * Get the WebGPU buffer that holds the tensor data. + * + * If the data is not on GPU as WebGPU buffer, throw error. + */ + readonly gpuBuffer: Tensor.GpuBufferType; + + /** + * Get the buffer data of the tensor. + * + * If the data is on CPU, returns the data immediately. + * If the data is on GPU, downloads the data and returns the promise. + * + * @param releaseData - whether release the data on GPU. Ignore if data is already on CPU. + */ + getData(releaseData?: boolean): Promise; + + /** + * Dispose the tensor data. + * + * If the data is on CPU, remove its internal reference to the underlying data. + * If the data is on GPU, release the data on GPU. + * + * After calling this function, the tensor is considered no longer valid. Its location will be set to 'none'. + */ + dispose(): void; } export declare namespace Tensor { @@ -35,7 +74,7 @@ export declare namespace Tensor { int64: BigInt64Array; string: string[]; bool: Uint8Array; - float16: never; // hold on using Uint16Array before we have a concrete solution for float 16 + float16: Uint16Array; // Keep using Uint16Array until we have a concrete solution for float 16. float64: Float64Array; uint32: Uint32Array; uint64: BigUint64Array; @@ -54,7 +93,7 @@ export declare namespace Tensor { int64: bigint; string: string; bool: boolean; - float16: never; // hold on before we have a concret solution for float 16 + float16: number; // Keep using Uint16Array until we have a concrete solution for float 16. float64: number; uint32: number; uint64: bigint; @@ -66,6 +105,43 @@ export declare namespace Tensor { type DataType = DataTypeMap[Type]; type ElementType = ElementTypeMap[Type]; + /** + * supported data types for constructing a tensor from a pinned CPU buffer + */ + export type CpuPinnedDataTypes = Exclude; + + /** + * type alias for WebGL texture + */ + export type TextureType = WebGLTexture; + + /** + * supported data types for constructing a tensor from a WebGL texture + */ + export type TextureDataTypes = 'float32'; + + /** + * type alias for WebGPU buffer + * + * The reason why we don't use type "GPUBuffer" defined in webgpu.d.ts from @webgpu/types is because "@webgpu/types" + * requires "@types/dom-webcodecs" as peer dependency when using TypeScript < v5.1 and its version need to be chosen + * carefully according to the TypeScript version being used. This means so far there is not a way to keep every + * TypeScript version happy. It turns out that we will easily broke users on some TypeScript version. + * + * for more info see https://github.com/gpuweb/types/issues/127 + */ + export type GpuBufferType = {size: number; mapState: 'unmapped' | 'pending' | 'mapped'}; + + /** + * supported data types for constructing a tensor from a WebGPU buffer + */ + export type GpuBufferDataTypes = 'float32'|'float16'|'int32'|'int64'|'uint32'|'bool'; + + /** + * represent where the tensor data is stored + */ + export type DataLocation = 'none'|'cpu'|'cpu-pinned'|'texture'|'gpu-buffer'; + /** * represent the data type of a tensor */ @@ -81,13 +157,16 @@ export interface TypedTensor extends TypedTensorBase, */ export interface Tensor extends TypedTensorBase, TypedTensorUtils {} +/** + * type TensorConstructor defines the constructors of 'Tensor' to create CPU tensor instances. + */ export interface TensorConstructor { - // #region specify element type + // #region CPU tensor - specify element type /** * Construct a new string tensor object from the given type, data and dims. * * @param type - Specify the element type. - * @param data - Specify the tensor data + * @param data - Specify the CPU tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ new(type: 'string', data: Tensor.DataTypeMap['string']|readonly string[], @@ -97,28 +176,39 @@ export interface TensorConstructor { * Construct a new bool tensor object from the given type, data and dims. * * @param type - Specify the element type. - * @param data - Specify the tensor data + * @param data - Specify the CPU tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ new(type: 'bool', data: Tensor.DataTypeMap['bool']|readonly boolean[], dims?: readonly number[]): TypedTensor<'bool'>; + /** + * Construct a new 64-bit integer typed tensor object from the given type, data and dims. + * + * @param type - Specify the element type. + * @param data - Specify the CPU tensor data. + * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. + */ + new( + type: T, data: Tensor.DataTypeMap[T]|readonly bigint[]|readonly number[], + dims?: readonly number[]): TypedTensor; + /** * Construct a new numeric tensor object from the given type, data and dims. * * @param type - Specify the element type. - * @param data - Specify the tensor data + * @param data - Specify the CPU tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ - new>( + new>( type: T, data: Tensor.DataTypeMap[T]|readonly number[], dims?: readonly number[]): TypedTensor; // #endregion - // #region infer element types + // #region CPU tensor - infer element types /** * Construct a new float32 tensor object from the given data and dims. * - * @param data - Specify the tensor data + * @param data - Specify the CPU tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ new(data: Float32Array, dims?: readonly number[]): TypedTensor<'float32'>; @@ -126,7 +216,7 @@ export interface TensorConstructor { /** * Construct a new int8 tensor object from the given data and dims. * - * @param data - Specify the tensor data + * @param data - Specify the CPU tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ new(data: Int8Array, dims?: readonly number[]): TypedTensor<'int8'>; @@ -134,7 +224,7 @@ export interface TensorConstructor { /** * Construct a new uint8 tensor object from the given data and dims. * - * @param data - Specify the tensor data + * @param data - Specify the CPU tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ new(data: Uint8Array, dims?: readonly number[]): TypedTensor<'uint8'>; @@ -142,7 +232,7 @@ export interface TensorConstructor { /** * Construct a new uint16 tensor object from the given data and dims. * - * @param data - Specify the tensor data + * @param data - Specify the CPU tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ new(data: Uint16Array, dims?: readonly number[]): TypedTensor<'uint16'>; @@ -150,7 +240,7 @@ export interface TensorConstructor { /** * Construct a new int16 tensor object from the given data and dims. * - * @param data - Specify the tensor data + * @param data - Specify the CPU tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ new(data: Int16Array, dims?: readonly number[]): TypedTensor<'int16'>; @@ -158,7 +248,7 @@ export interface TensorConstructor { /** * Construct a new int32 tensor object from the given data and dims. * - * @param data - Specify the tensor data + * @param data - Specify the CPU tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ new(data: Int32Array, dims?: readonly number[]): TypedTensor<'int32'>; @@ -166,7 +256,7 @@ export interface TensorConstructor { /** * Construct a new int64 tensor object from the given data and dims. * - * @param data - Specify the tensor data + * @param data - Specify the CPU tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ new(data: BigInt64Array, dims?: readonly number[]): TypedTensor<'int64'>; @@ -174,7 +264,7 @@ export interface TensorConstructor { /** * Construct a new string tensor object from the given data and dims. * - * @param data - Specify the tensor data + * @param data - Specify the CPU tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ new(data: readonly string[], dims?: readonly number[]): TypedTensor<'string'>; @@ -182,7 +272,7 @@ export interface TensorConstructor { /** * Construct a new bool tensor object from the given data and dims. * - * @param data - Specify the tensor data + * @param data - Specify the CPU tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ new(data: readonly boolean[], dims?: readonly number[]): TypedTensor<'bool'>; @@ -190,7 +280,7 @@ export interface TensorConstructor { /** * Construct a new float64 tensor object from the given data and dims. * - * @param data - Specify the tensor data + * @param data - Specify the CPU tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ new(data: Float64Array, dims?: readonly number[]): TypedTensor<'float64'>; @@ -198,7 +288,7 @@ export interface TensorConstructor { /** * Construct a new uint32 tensor object from the given data and dims. * - * @param data - Specify the tensor data + * @param data - Specify the CPU tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ new(data: Uint32Array, dims?: readonly number[]): TypedTensor<'uint32'>; @@ -206,152 +296,34 @@ export interface TensorConstructor { /** * Construct a new uint64 tensor object from the given data and dims. * - * @param data - Specify the tensor data + * @param data - Specify the CPU tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ new(data: BigUint64Array, dims?: readonly number[]): TypedTensor<'uint64'>; // #endregion - // #region fall back to non-generic tensor type declaration + // #region CPU tensor - fall back to non-generic tensor type declaration /** * Construct a new tensor object from the given type, data and dims. * * @param type - Specify the element type. - * @param data - Specify the tensor data + * @param data - Specify the CPU tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ - new(type: Tensor.Type, data: Tensor.DataType|readonly number[]|readonly boolean[], dims?: readonly number[]): Tensor; + new(type: Tensor.Type, data: Tensor.DataType|readonly number[]|readonly string[]|readonly bigint[]|readonly boolean[], + dims?: readonly number[]): Tensor; /** * Construct a new tensor object from the given data and dims. * - * @param data - Specify the tensor data + * @param data - Specify the CPU tensor data. * @param dims - Specify the dimension of the tensor. If omitted, a 1-D tensor is assumed. */ new(data: Tensor.DataType, dims?: readonly number[]): Tensor; // #endregion } -/** - * Specify the image format. Assume 'RGBA' if omitted. - */ -export type ImageFormat = 'RGB'|'RGBA'|'BGR'|'RBG'; - -/** - * Describes Tensor configuration to an image data. - */ -export interface TensorToImageDataOptions { - /** - * Describes Tensor channels order. - */ - format?: ImageFormat; - /** - * Tensor channel layout - default is 'NHWC' - */ - tensorLayout?: 'NHWC'|'NCHW'; - /** - * Describes Tensor Height - can be accessed via tensor dimensions as well - */ - height?: number; - /** - * Describes Tensor Width - can be accessed via tensor dimensions as well - */ - width?: number; - /** - * Describes normalization parameters to ImageData conversion from tensor - default values - Bias: 0, Mean: 255 - */ - norm?: { - bias?: number; // Todo add support - |[number,number,number]|[number,number,number,number]; - mean?: number; // Todo add support - |[number,number,number]|[number,number,number,number]; - }; -} -/** - * Describes Tensor and Image configuration to an image data. - */ -export interface TensorFromImageOptions { - /** - * Describes image data format - will be used only in the case of ImageBitMap - */ - bitmapFormat?: ImageFormat; - /** - * Describes Tensor channels order - can differ from original image - */ - tensorFormat?: ImageFormat; - /** - * Tensor data type - default is 'float32' - */ - dataType?: 'float32'|'uint8'; - /** - * Tensor channel layout - default is 'NHWC' - */ - tensorLayout?: 'NHWC'|'NCHW'; - /** - * Describes Image Height - Required only in the case of ImageBitMap - */ - height?: number; - /** - * Describes Image Width - Required only in the case of ImageBitMap - */ - width?: number; - /** - * Describes resized height - can be accessed via tensor dimensions as well - */ - resizedHeight?: number; - /** - * Describes resized width - can be accessed via tensor dimensions as well - */ - resizedWidth?: number; - /** - * Describes normalization parameters to tensor conversion from image data - default values - Bias: 0, Mean: 255 - */ - norm?: { - bias?: number; // Todo add support - |[number,number,number]|[number,number,number,number]; - mean?: number; // Todo add support - |[number,number,number]|[number,number,number,number]; - }; -} -export interface TensorFactory { - /** - * create a tensor from image object - HTMLImageElement, ImageData, ImageBitmap, URL - * - * @param imageData - {ImageData} - composed of: Uint8ClampedArray, width. height - uses known pixel format RGBA - * @param options - Optional - Interface describing input image & output tensor - - * Input Defaults: RGBA, 3 channels, 0-255, NHWC - Output Defaults: same as input parameters - * @returns A promise that resolves to a tensor object - */ - fromImage(imageData: ImageData, options?: TensorFromImageOptions): Promise; - - /** - * create a tensor from image object - HTMLImageElement, ImageData, ImageBitmap, URL - * - * @param imageElement - {HTMLImageElement} - since the data is stored as ImageData no need for format parameter - * @param options - Optional - Interface describing input image & output tensor - - * Input Defaults: RGBA, 3 channels, 0-255, NHWC - Output Defaults: same as input parameters - * @returns A promise that resolves to a tensor object - */ - fromImage(imageElement: HTMLImageElement, options?: TensorFromImageOptions): Promise; - - /** - * create a tensor from image object - HTMLImageElement, ImageData, ImageBitmap, URL - * - * @param url - {string} - Assuming the string is a URL to an image - * @param options - Optional - Interface describing input image & output tensor - - * Input Defaults: RGBA, 3 channels, 0-255, NHWC - Output Defaults: same as input parameters - * @returns A promise that resolves to a tensor object - */ - fromImage(url: string, options?: TensorFromImageOptions): Promise; - - /** - * create a tensor from image object - HTMLImageElement, ImageData, ImageBitmap, URL - * - * @param bitMap - {ImageBitmap} - since the data is stored as ImageData no need for format parameter - * @param options - NOT Optional - Interface describing input image & output tensor - - * Output Defaults: same as input parameters - * @returns A promise that resolves to a tensor object - */ - fromImage(bitmap: ImageBitmap, options: TensorFromImageOptions): Promise; -} - // eslint-disable-next-line @typescript-eslint/naming-convention -export const Tensor = TensorImpl as TensorConstructor; +export const Tensor = TensorImpl as (TensorConstructor & TensorFactory); diff --git a/js/common/lib/version.ts b/js/common/lib/version.ts new file mode 100644 index 0000000000000..96c2361cceabe --- /dev/null +++ b/js/common/lib/version.ts @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// This file is generated by /js/scripts/update-version.ts +// Do not modify file content manually. + +export const version = '1.17.0'; diff --git a/js/common/package-lock.json b/js/common/package-lock.json index 1d956b5888384..84f6dba83fa59 100644 --- a/js/common/package-lock.json +++ b/js/common/package-lock.json @@ -1,12 +1,12 @@ { "name": "onnxruntime-common", - "version": "1.15.0", + "version": "1.17.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "onnxruntime-common", - "version": "1.15.0", + "version": "1.17.0", "license": "MIT", "devDependencies": { "typedoc": "^0.23.22" diff --git a/js/common/package.json b/js/common/package.json index 39e9e356e399d..beab7d29be263 100644 --- a/js/common/package.json +++ b/js/common/package.json @@ -1,27 +1,34 @@ { "license": "MIT", - "unpkg": "dist/ort-common.min.js", + "type": "module", "name": "onnxruntime-common", + "version": "1.17.0", "repository": { "url": "https://github.com/Microsoft/onnxruntime.git", "type": "git" }, "author": "fs-eire", - "module": "dist/lib/index.js", - "version": "1.15.0", - "jsdelivr": "dist/ort-common.min.js", "scripts": { - "prepare": "tsc && webpack" + "build:cjs": "tsc --module commonjs --outDir ./dist/cjs", + "build:esm": "tsc", + "build:bundles": "webpack", + "build": "node ./build.js", + "prepare": "npm run build", + "pretest": "tsc --build ./test", + "test": "mocha ./test/**/*.js --timeout 30000" + }, + "devDependencies": { + "typedoc": "^0.23.22" + }, + "main": "dist/cjs/index.js", + "exports": { + "require": "./dist/cjs/index.js", + "import": "./dist/esm/index.js" }, "keywords": [ "ONNX", "ONNXRuntime", "ONNX Runtime" ], - "devDependencies": { - "typedoc": "^0.23.22" - }, - "main": "dist/ort-common.node.js", - "types": "dist/lib/index.d.ts", "description": "ONNXRuntime JavaScript API library" } diff --git a/js/common/test/tsconfig.json b/js/common/test/tsconfig.json new file mode 100644 index 0000000000000..2e4927ac3b325 --- /dev/null +++ b/js/common/test/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.tools.json", + "exclude": ["type-tests/**/*.ts"], + "compilerOptions": { + "module": "ES2022", + "sourceMap": true + } +} diff --git a/js/common/test/type-tests.ts b/js/common/test/type-tests.ts new file mode 100644 index 0000000000000..afa53a694514d --- /dev/null +++ b/js/common/test/type-tests.ts @@ -0,0 +1,152 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import globby from 'globby'; +import assert from 'node:assert'; +import {readFileSync} from 'node:fs'; +import {dirname, join, normalize, relative} from 'node:path'; +import {fileURLToPath} from 'node:url'; +import npmlog from 'npmlog'; +import typescript from 'typescript'; + +/** + * @fileoverview + * + * This file is used to run TypeScript type tests. + * + * The type tests are located under `common/test/type-tests/` folder. Each test file is a simple typescrit source file. + * In each test file, any expected failure are marked as comments in the following format: + * + * "// {type-tests}|fail||" + * + * - comments should always start with "// {type-tests}|fail|" + * - is the line number offset from the comment line + * - is the error code of the expected failure + * + * For example: + * + * ```ts + * // {type-tests}|fail|1|2348 + * const t0 = ort.Tensor('xxx'); + * ``` + * + * In this example, the comments indicate that the line number of the expected failure is 1 line after the comment line, + * and the error code is 2348. + * + * The test runner will compile each test file and check if the actual error code matches the expected error code. If + * there is no expected failure, the test runner will check if the test file can be compiled successfully. + */ + +// the root folder of type tests +const TYPE_TESTS_DIR = join(dirname(fileURLToPath(import.meta.url)), './type-tests'); + +/** + * aggregate test files: `*.ts` under folder `common/test/type-tests/` + * + * @returns list of test files + */ +const prepareTestFileList = () => + // + globby.sync('**/*.ts', { + cwd: TYPE_TESTS_DIR, + absolute: true, + }); + +/** + * Run typescript compiler on the given files. + */ +const compileTypeScriptFiles = (filepaths: string[]): readonly typescript.Diagnostic[] => { + // TypeScript compiler options, base URL is reset to `TYPE_TESTS_DIR`. + const compilerOptions = + JSON.parse(readFileSync(new URL('./type-tests/tsconfig.json', import.meta.url), 'utf-8')).compilerOptions as + typescript.CompilerOptions; + compilerOptions.baseUrl = TYPE_TESTS_DIR; + + // Run TypeScript compiler + const program = typescript.createProgram({ + rootNames: filepaths, + options: compilerOptions, + }); + + return typescript.getPreEmitDiagnostics(program); +}; + +/** + * Prepare test cases for TypeScript type tests. + * @returns list of test cases. Each test case data contains the test title and a function to run the test. + */ +const prepareTestCases = () => { + npmlog.info('PrepareTestCases', 'Preparing test file lists...'); + const testFiles = prepareTestFileList(); + npmlog.info('PrepareTestCases', `Preparing test file lists... DONE, ${testFiles.length} file(s) in total.`); + + npmlog.info('PrepareTestCases', 'Running TypeScript Compiler...'); + const compileResult = compileTypeScriptFiles(testFiles).map( + diagnostic => ({ + fileName: normalize(diagnostic.file?.fileName ?? ''), + line: diagnostic.file?.getLineAndCharacterOfPosition(diagnostic.start!)?.line ?? -1, + code: diagnostic.code, + })); + npmlog.info('PrepareTestCases', 'Running TypeScript Compiler... DONE.'); + + npmlog.info('PrepareTestCases', 'Parsing test source files for expected failures...'); + const testCases = testFiles.map(filepath => { + const normalizedFilePath = normalize(filepath); + const normalizedRelativePath = normalize(relative(TYPE_TESTS_DIR, filepath)); + + const fileAllLines = readFileSync(filepath, 'utf-8').split('\n').map(line => line.trim()); + const expectedFailures: Array<{line: number; code: number}> = []; + fileAllLines.forEach((line, i) => { + if (line.startsWith('// {type-tests}|fail|')) { + const splitted = line.split('|'); + assert(splitted.length === 4, `invalid expected failure comment: ${line}`); + const lineOffset = Number.parseInt(splitted[2], 10); + const code = Number.parseInt(splitted[3], 10); + expectedFailures.push({line: i + lineOffset, code}); + } + }); + + const actualFailures: typeof compileResult = []; + + return {filepath: normalizedFilePath, relativePath: normalizedRelativePath, expectedFailures, actualFailures}; + }); + npmlog.info('PrepareTestCases', 'Parsing test source files for expected failures... DONE.'); + + // now check if file names is matched + const filePathToTestCaseMap = new Map(testCases.map(testCase => [testCase.filepath, testCase])); + for (const error of compileResult) { + // check file name exists + assert(error.fileName, 'Each compile error should have a file name. Please check TypeScript compiler options.'); + + // check file name is in test cases + const testCase = filePathToTestCaseMap.get(error.fileName); + assert(testCase, `unexpected error file name: ${error.fileName}`); + + testCase.actualFailures.push(error); + } + + return testCases.map(testCase => { + const {relativePath, expectedFailures, actualFailures} = testCase; + const testFunction = () => { + if (expectedFailures.length === 0) { + assert.equal(actualFailures.length, 0, `expected to pass but failed: ${JSON.stringify(actualFailures)}`); + } else { + actualFailures.forEach(error => { + const {line, code} = error; + const foundIndex = expectedFailures.findIndex(f => f.line === line && f.code === code); + assert.notEqual(foundIndex, -1, `unexpected failure: line=${line}, code=${code}`); + expectedFailures.splice(foundIndex, 1); + }); + assert.equal(expectedFailures.length, 0, `expected to fail but passed: ${JSON.stringify(expectedFailures)}`); + } + }; + + return {title: relativePath, testBody: testFunction}; + }); +}; + +describe('TypeScript type tests', () => { + for (const {title, testBody} of prepareTestCases()) { + it(title, testBody); + } +}); diff --git a/js/common/test/type-tests/tensor/create-new-bool.ts b/js/common/test/type-tests/tensor/create-new-bool.ts new file mode 100644 index 0000000000000..8692af97bd07a --- /dev/null +++ b/js/common/test/type-tests/tensor/create-new-bool.ts @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import {Tensor, TypedTensor} from 'onnxruntime-common'; + +// construct from type, data (boolean array) and shape (number array) +// +// {type-tests}|pass +new Tensor('bool', [true, true, false, false], [2, 2]) as TypedTensor<'bool'>; + +// construct from type and data (boolean array) +// +// {type-tests}|pass +new Tensor('bool', [true, true, false, false]) as TypedTensor<'bool'>; + +// construct from type, data (Uint8Array) and shape (number array) +// +// {type-tests}|pass +new Tensor('bool', new Uint8Array([1, 1, 0, 0]), [2, 2]) as TypedTensor<'bool'>; + +// construct from type and data (Uint8Array) +// +// {type-tests}|pass +new Tensor('bool', new Uint8Array([1, 1, 0, 0])) as TypedTensor<'bool'>; + +// construct from data (boolean array) +// +// {type-tests}|pass +new Tensor([true, true, false, false]) as TypedTensor<'bool'>; + +// construct from data (Uint8Array) - type is inferred as 'uint8' +// +// "Conversion of type 'TypedTensor<"uint8">' to type 'TypedTensor<"bool">' may be a mistake because ..." +// +// {type-tests}|fail|1|2352 +new Tensor(new Uint8Array([1, 1, 0, 0])) as TypedTensor<'bool'>; diff --git a/js/common/test/type-tests/tensor/create-new-f32.ts b/js/common/test/type-tests/tensor/create-new-f32.ts new file mode 100644 index 0000000000000..af24a3e8aaf3c --- /dev/null +++ b/js/common/test/type-tests/tensor/create-new-f32.ts @@ -0,0 +1,62 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import {Tensor, TypedTensor} from 'onnxruntime-common'; + +// construct from type, data (number array) and shape (number array) +// +// {type-tests}|pass +new Tensor('float32', [1, 2, 3, 4], [2, 2]) as TypedTensor<'float32'>; + +// construct from type and data (number array) +// +// {type-tests}|pass +new Tensor('float32', [1, 2, 3, 4]) as TypedTensor<'float32'>; + +// construct from type, data (Float32Array) and shape (number array) +// +// {type-tests}|pass +new Tensor('float32', new Float32Array([1, 2, 3, 4]), [2, 2]) as TypedTensor<'float32'>; + +// construct from type and data (Float32Array) +// +// {type-tests}|pass +new Tensor('float32', new Float32Array([1, 2, 3, 4])) as TypedTensor<'float32'>; + +// construct from data (Float32Array) +// +// {type-tests}|pass +new Tensor(new Float32Array([1, 2, 3, 4])) as TypedTensor<'float32'>; + +// construct from data (Float32Array) and shape (number array) +// +// {type-tests}|pass +new Tensor(new Float32Array([1, 2, 3, 4]), [2, 2]) as TypedTensor<'float32'>; + +// construct (no params) - need params +// +// "Expected 1-3 arguments, but got 0." +// +// {type-tests}|fail|1|2554 +new Tensor(); + +// construct from type - need data +// +// "No overload matches this call." +// +// {type-tests}|fail|1|2769 +new Tensor('float32'); + +// construct from data (number array) - type cannot be inferred. +// +// "No overload matches this call." +// +// {type-tests}|fail|1|2769 +new Tensor([1, 2, 3, 4]); + +// construct from data (Float32Array) and shape (number) - type mismatch. +// +// "No overload matches this call." +// +// {type-tests}|fail|1|2769 +new Tensor(new Float32Array([1, 2, 3, 4]), 2); diff --git a/js/common/test/type-tests/tensor/create-new-string.ts b/js/common/test/type-tests/tensor/create-new-string.ts new file mode 100644 index 0000000000000..d8c2870f7a879 --- /dev/null +++ b/js/common/test/type-tests/tensor/create-new-string.ts @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import {Tensor, TypedTensor} from 'onnxruntime-common'; + +// construct from type, data (string array) and shape (number array) +// +// {type-tests}|pass +new Tensor('string', ['a', 'b', 'c', 'd'], [2, 2]) as TypedTensor<'string'>; + +// construct from type and data (string array) +// +// {type-tests}|pass +new Tensor('string', ['a', 'b', 'c', 'd']) as TypedTensor<'string'>; + +// construct from data (string array) +// +// {type-tests}|pass +new Tensor(['a', 'b', 'c', 'd']) as TypedTensor<'string'>; diff --git a/js/common/test/type-tests/tensor/create-no-new.ts b/js/common/test/type-tests/tensor/create-no-new.ts new file mode 100644 index 0000000000000..e971851c20157 --- /dev/null +++ b/js/common/test/type-tests/tensor/create-no-new.ts @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import * as ort from 'onnxruntime-common'; + +// calling ort.Tensor() - creating tensor without 'new' is not allowed. +// +// "Value of type 'TensorConstructor & TensorFactory' is not callable. Did you mean to include 'new'?" +// +// {type-tests}|fail|1|2348 +ort.Tensor('float32', [1, 2, 3, 4], [2, 2]); diff --git a/js/common/test/type-tests/tsconfig.json b/js/common/test/type-tests/tsconfig.json new file mode 100644 index 0000000000000..105e0611743f3 --- /dev/null +++ b/js/common/test/type-tests/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "module": "ES2020", + "target": "ES2020", + "baseUrl": ".", + "paths": { + "onnxruntime-common": ["../../lib/index.ts"] + }, + "strict": true + } +} diff --git a/js/common/test/unit-tests/common.ts b/js/common/test/unit-tests/common.ts new file mode 100644 index 0000000000000..49ebe872880a2 --- /dev/null +++ b/js/common/test/unit-tests/common.ts @@ -0,0 +1,61 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import assert from 'assert/strict'; +import {Tensor} from 'onnxruntime-common'; + +/** + * A list of numerical types that are compatible with JavaScript 'number' value. + * + * 3 elements in each list are: + * - type: a string representing the type name, + * - typedArrayConstructor: the built-in typed array constructor for the type, + * - canBeInferredFromType: whether the type can be inferred from the type name. + */ +export const NUMBER_COMPATIBLE_NUMERICAL_TYPES = [ + ['int8', Int8Array, true] as const, + ['uint8', Uint8Array, true] as const, + ['int16', Int16Array, true] as const, + ['uint16', Uint16Array, true] as const, + ['int32', Int32Array, true] as const, + ['uint32', Uint32Array, true] as const, + ['float32', Float32Array, true] as const, + ['float64', Float64Array, true] as const, +]; + +/** + * Big integer types + */ +export const BIGINT_TYPES = [ + ['int64', BigInt64Array, true] as const, + ['uint64', BigUint64Array, true] as const, +]; + +/** + * float16 type, data represented by Uint16Array + */ +export const FLOAT16_TYPE = ['float16', Uint16Array, false] as const; + +/** + * A list of all numerical types. + * + * not including string and bool. + */ +export const ALL_NUMERICAL_TYPES = [...NUMBER_COMPATIBLE_NUMERICAL_TYPES, ...BIGINT_TYPES, FLOAT16_TYPE]; + +/** + * a helper function to assert that a value is an array of a certain type + */ +export const assertIsArrayOf = (value: unknown, type: 'string'|'number'|'boolean'): void => { + assert(Array.isArray(value), 'array should be an array'); + for (let i = 0; i < value.length; i++) { + assert.equal(typeof value[i], type, `array should be an array of ${type}s`); + } +}; + +/** + * the 'TensorAny' is a type allows skip typescript type checking for Tensor. + * + * This allows to write test code to pass invalid parameters to Tensor constructor and check the behavior. + */ +export const TensorAny = Tensor as unknown as {new (...args: unknown[]): Tensor}; diff --git a/js/common/test/unit-tests/tensor/constructor-type.ts b/js/common/test/unit-tests/tensor/constructor-type.ts new file mode 100644 index 0000000000000..891b457006ba8 --- /dev/null +++ b/js/common/test/unit-tests/tensor/constructor-type.ts @@ -0,0 +1,102 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import assert from 'assert/strict'; +import {Tensor} from 'onnxruntime-common'; + +import {ALL_NUMERICAL_TYPES, assertIsArrayOf, BIGINT_TYPES, NUMBER_COMPATIBLE_NUMERICAL_TYPES, TensorAny} from '../common.js'; + +describe('Tensor Constructor Tests - check types', () => { + for (const [type, typedArrayConstructor, canBeInferredFromType] of ALL_NUMERICAL_TYPES) { + it(`[${type}] new Tensor(type, typedArray, dims): "tensor.type" should match type passed in`, () => { + const tensor = new Tensor(type, new typedArrayConstructor(4), [2, 2]); + assert.equal(tensor.type, type, `tensor.type should be '${type}'`); + }); + + it(`[${type}] new Tensor(type, typedArray, dims): "tensor.data" should be instance of expected typed array`, () => { + const tensor = new Tensor(type, new typedArrayConstructor(4), [2, 2]); + assert( + tensor.data instanceof typedArrayConstructor, + `tensor.data should be an instance of '${typedArrayConstructor.name}'`); + }); + + if (canBeInferredFromType) { + it(`[${type}] new Tensor(typedArray, dims): "tensor.type" should match inferred type`, () => { + const tensor = new Tensor(new typedArrayConstructor(4), [2, 2]); + assert.equal(tensor.type, type, `tensor.type should be '${type}'`); + }); + } + + it(`[${type}] new Tensor(type, {}, dims): expect to throw because data is invalid`, () => { + assert.throws(() => new TensorAny(type, {}, [2, 2]), TypeError); + }); + + it(`[${type}] new Tensor(type, arrayBuffer, dims): expect to throw because data is invalid`, () => { + assert.throws(() => new TensorAny(type, new ArrayBuffer(100), [2, 2]), TypeError); + }); + } + + for (const [type, ] of NUMBER_COMPATIBLE_NUMERICAL_TYPES) { + it(`[${type}] new Tensor(type, numbers, dims): tensor can be constructed from number array`, () => { + const tensor = new Tensor(type, [1, 2, 3, 4], [2, 2]); + assert.equal(tensor.type, type, `tensor.type should be '${type}'`); + }); + } + + for (const [type, ] of BIGINT_TYPES) { + it(`[${type}] new Tensor(type, numbers, dims): tensor can be constructed from number array`, () => { + const tensor = new Tensor(type, [1, 2, 3, 4], [2, 2]); + assert.equal(tensor.type, type, `tensor.type should be '${type}'`); + }); + + it(`[${type}] new Tensor(type, bigints, dims): tensor can be constructed from bigint array`, () => { + const tensor = new Tensor(type, [1n, 2n, 3n, 4n], [2, 2]); + assert.equal(tensor.type, type, `tensor.type should be '${type}'`); + }); + } + + it('[string] new Tensor(\'string\', strings, dims): "tensor.type" should match type passed in', () => { + const tensor = new Tensor('string', ['a', 'b', 'c', 'd'], [2, 2]); + assert.equal(tensor.type, 'string', 'tensor.type should be \'string\''); + }); + + it('[string] new Tensor(strings, dims): "tensor.data" should match inferred type', () => { + const tensor = new Tensor(['a', 'b', 'c', 'd'], [2, 2]); + assert.equal(tensor.type, 'string', 'tensor.type should be \'string\''); + }); + + it('[string] new Tensor(\'string\', strings, dims): "tensor.data" should be a string array', () => { + const tensor = new Tensor('string', ['a', 'b', 'c', 'd'], [2, 2]); + assertIsArrayOf(tensor.data, 'string'); + }); + + it('[bool] new Tensor(\'bool\', booleans, dims): "tensor.type" should match type passed in', () => { + const tensor = new Tensor('bool', [true, false, true, false], [2, 2]); + assert.equal(tensor.type, 'bool', 'tensor.type should be \'bool\''); + }); + + it('[bool] new Tensor(\'bool\', uint8Array, dims): tensor can be constructed from Uint8Array', () => { + const tensor = new Tensor('bool', new Uint8Array([1, 0, 1, 0]), [2, 2]); + assert.equal(tensor.type, 'bool', 'tensor.type should be \'bool\''); + }); + + it('[bool] new Tensor(booleans, dims): "tensor.data" should match inferred type', () => { + const tensor = new Tensor([true, false, true, false], [2, 2]); + assert.equal(tensor.type, 'bool', 'tensor.type should be \'bool\''); + }); + + it('[bool] new Tensor(\'bool\', booleans, dims): "tensor.data" should be a boolean array', () => { + const tensor = new Tensor('bool', [true, false, true, false], [2, 2]); + assert(tensor.data instanceof Uint8Array, 'tensor.data should be an instance of \'Uint8Array\''); + }); + + it('[float16] new Tensor(\'float16\', numbers, dims): ' + + 'expect to throw because it\'s not allowed to construct \'float16\' tensor from number array', + () => { + assert.throws(() => new Tensor('float16', [1, 2, 3, 4], [2, 2]), TypeError); + }); + + it('[badtype] new Tensor(\'a\', numbers, dims): expect to throw because \'a\' is an invalid type', () => { + assert.throws(() => new TensorAny('a', [1, 2, 3, 4], [2, 2]), TypeError); + }); +}); diff --git a/js/common/tsconfig.json b/js/common/tsconfig.json index 9e1ac941c493f..4751cd7564f5d 100644 --- a/js/common/tsconfig.json +++ b/js/common/tsconfig.json @@ -1,9 +1,11 @@ { "extends": "../tsconfig.json", "compilerOptions": { - "outDir": "dist/lib", + "outDir": "./dist/esm", + "declaration": true, + "declarationMap": true, "esModuleInterop": false, - "noUnusedParameters": true, + "noUnusedParameters": true }, "include": ["lib"] } diff --git a/js/common/typedoc.json b/js/common/typedoc.json index a86219130d919..088c7ba4053e6 100644 --- a/js/common/typedoc.json +++ b/js/common/typedoc.json @@ -1,7 +1,5 @@ { - "entryPoints": [ - "lib/index.ts" - ], + "entryPoints": ["lib/index.ts"], "excludeInternal": true, "name": "ONNX Runtime JavaScript API", "readme": "none", diff --git a/js/common/webpack.config.js b/js/common/webpack.config.js index e5c4e417bc454..b9d1536f4b99c 100644 --- a/js/common/webpack.config.js +++ b/js/common/webpack.config.js @@ -3,98 +3,65 @@ 'use strict'; -const path = require('path'); -const webpack = require('webpack'); -const TerserPlugin = require("terser-webpack-plugin"); - -function terserEcmaVersionFromWebpackTarget(target) { - switch (target) { - case 'es5': - return 5; - case 'es6': - case 'es2015': - return 2015; - case 'es2017': - return 2017; - default: - throw new RangeError(`not supported ECMA version: ${target}`); - } -} - -function addCopyrightBannerPlugin(mode, target) { - const VERSION = require(path.join(__dirname, 'package.json')).version; - const COPYRIGHT_BANNER = `/*! - * ONNX Runtime Common v${VERSION} - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. - */`; - - if (mode === 'production') { - return new TerserPlugin({ - extractComments: false, - terserOptions: { - ecma: terserEcmaVersionFromWebpackTarget(target), - format: { - preamble: COPYRIGHT_BANNER, - comments: false, - }, - compress: { - passes: 2 - } - } - }); - } else { - return new webpack.BannerPlugin({ banner: COPYRIGHT_BANNER, raw: true }); - } -} +import webpack from 'webpack'; +import {resolve} from 'node:path'; +import {DEFAULT_ES_VERSION, addCopyrightBannerPlugin} from '../webpack.shared.mjs'; function buildConfig({ - suffix = '', - format = 'umd', - target = 'es2017', - mode = 'production', - devtool = 'source-map' + suffix = '.js', // '.js', '.min.js', ... + format = 'umd', // 'umd', 'commonjs' + target = 'web', // 'web', 'node' + esVersion = DEFAULT_ES_VERSION, // 'es5', 'es6', ... + mode = 'production', // 'development', 'production' + devtool = 'source-map' // 'inline-source-map', 'source-map' }) { + // output file name + const filename = `ort-common${suffix}`; + + // variable name of the exported object. + // - set to 'ort' when building 'umd' format. + // - set to undefined when building other formats (commonjs/module) + const exportName = format === 'umd' ? 'ort' : undefined; + return { - target: [format === 'commonjs' ? 'node' : 'web', target], - entry: path.resolve(__dirname, 'lib/index.ts'), + target: [target, esVersion], + entry: resolve('./lib/index.ts'), output: { - path: path.resolve(__dirname, 'dist'), - filename: `ort-common${suffix}.js`, - library: { - name: format === 'commonjs' ? undefined : 'ort', - type: format - } + path: resolve('./dist'), + filename, + library: {name: exportName, type: format}, + }, + resolve: { + extensions: ['.ts', '.js'], + extensionAlias: {'.js': ['.ts', '.js']}, }, - resolve: { extensions: ['.ts', '.js'] }, plugins: [ - new webpack.WatchIgnorePlugin({ paths: [/\.js$/, /\.d\.ts$/] }), - addCopyrightBannerPlugin(mode, target), + new webpack.WatchIgnorePlugin({paths: [/\.js$/, /\.d\.ts$/]}), + addCopyrightBannerPlugin(mode, 'common', esVersion), ], module: { rules: [{ - test: /\.tsx?$/, - use: [ - { - loader: 'ts-loader', - options: { - compilerOptions: { target } - } - } - ] + test: /\.ts$/, + use: [{ + loader: 'ts-loader', + options: {compilerOptions: {target: esVersion}}, + }] }] }, - mode: mode, - devtool: devtool, + mode, + devtool, }; } -module.exports = (env, argv) => { +export default (env, argv) => { return [ - buildConfig({ suffix: '.es5.min', target: 'es5' }), - buildConfig({ suffix: '.es6.min', target: 'es6' }), - buildConfig({ suffix: '.min' }), - buildConfig({ mode: 'development', devtool: 'inline-source-map' }), - buildConfig({ format: 'commonjs', suffix: '.node' }), + buildConfig({suffix: '.es5.min.js', target: 'web', esVersion: 'es5'}), + buildConfig({suffix: '.min.js'}), + buildConfig({mode: 'development', devtool: 'inline-source-map'}), + buildConfig({ + suffix: '.node.cjs', + target: 'node', + format: 'commonjs', + }), ]; }; diff --git a/js/node/CMakeLists.txt b/js/node/CMakeLists.txt index 5557440f431af..c3898fbad7401 100644 --- a/js/node/CMakeLists.txt +++ b/js/node/CMakeLists.txt @@ -28,8 +28,29 @@ endif() # include dirs include_directories(${CMAKE_JS_INC}) include_directories(${CMAKE_SOURCE_DIR}/../../include/onnxruntime/core/session) +include_directories(${CMAKE_SOURCE_DIR}/../../include/onnxruntime) +include_directories(${CMAKE_SOURCE_DIR}/../../onnxruntime) include_directories(${CMAKE_SOURCE_DIR}/node_modules/node-addon-api) +# optional providers +option(USE_DML "Build with DirectML support" OFF) +option(USE_CUDA "Build with CUDA support" OFF) +option(USE_TENSORRT "Build with TensorRT support" OFF) +option(USE_COREML "Build with CoreML support" OFF) + +if(USE_DML) + add_compile_definitions(USE_DML=1) +endif() +if(USE_CUDA) + add_compile_definitions(USE_CUDA=1) +endif() +if(USE_TENSORRT) + add_compile_definitions(USE_TENSORRT=1) +endif() +if(USE_COREML) + add_compile_definitions(USE_COREML=1) +endif() + # source files file(GLOB ORT_NODEJS_BINDING_SOURCE_FILES ${CMAKE_SOURCE_DIR}/src/*.cc) @@ -77,6 +98,14 @@ if (WIN32) ${ONNXRUNTIME_BUILD_DIR}/${CMAKE_BUILD_TYPE}/onnxruntime.dll ${dist_folder} ) + if (USE_DML) + add_custom_command( + TARGET onnxruntime_binding POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${ONNXRUNTIME_BUILD_DIR}/${CMAKE_BUILD_TYPE}/DirectML.dll + ${dist_folder} + ) + endif () if (CMAKE_BUILD_TYPE STREQUAL "Debug") add_custom_command( TARGET onnxruntime_binding POST_BUILD diff --git a/js/node/README.md b/js/node/README.md index 24995e0012c45..98b2ea66de2a8 100644 --- a/js/node/README.md +++ b/js/node/README.md @@ -24,6 +24,10 @@ Following platforms are supported with pre-built binaries: To use on platforms without pre-built binaries, you can build Node.js binding from source and consume it by `npm install /js/node/`. See also [instructions](https://www.onnxruntime.ai/docs/how-to/build.html#apis-and-language-bindings) for building ONNX Runtime Node.js binding locally. +# GPU Support + +Right now, the Windows version supports only the DML provider. Linux x64 can use CUDA and TensorRT. + ## License License information can be found [here](https://github.com/microsoft/onnxruntime/blob/main/README.md#license). diff --git a/js/node/lib/backend.ts b/js/node/lib/backend.ts index 32f71c6a76661..d3680f9d44236 100644 --- a/js/node/lib/backend.ts +++ b/js/node/lib/backend.ts @@ -69,3 +69,4 @@ class OnnxruntimeBackend implements Backend { } export const onnxruntimeBackend = new OnnxruntimeBackend(); +export const listSupportedBackends = binding.listSupportedBackends; diff --git a/js/node/lib/binding.ts b/js/node/lib/binding.ts index ca6cf51804d19..8a0ce89abfa64 100644 --- a/js/node/lib/binding.ts +++ b/js/node/lib/binding.ts @@ -33,11 +33,18 @@ export declare namespace Binding { export interface InferenceSessionConstructor { new(): InferenceSession; } + + export interface SupportedBackend { + name: string; + bundled: boolean; + } } // export native binding export const binding = // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires - require(`../bin/napi-v3/${process.platform}/${process.arch}/onnxruntime_binding.node`) as - // eslint-disable-next-line @typescript-eslint/naming-convention - {InferenceSession: Binding.InferenceSessionConstructor}; + require(`../bin/napi-v3/${process.platform}/${process.arch}/onnxruntime_binding.node`) as { + // eslint-disable-next-line @typescript-eslint/naming-convention + InferenceSession: Binding.InferenceSessionConstructor; + listSupportedBackends: () => Binding.SupportedBackend[]; +}; diff --git a/js/node/lib/index.ts b/js/node/lib/index.ts index e455f69a8f876..69b1ef1d96af6 100644 --- a/js/node/lib/index.ts +++ b/js/node/lib/index.ts @@ -2,7 +2,14 @@ // Licensed under the MIT License. export * from 'onnxruntime-common'; -import {registerBackend} from 'onnxruntime-common'; -import {onnxruntimeBackend} from './backend'; +export {listSupportedBackends} from './backend'; +import {registerBackend, env} from 'onnxruntime-common'; +import {version} from './version'; +import {onnxruntimeBackend, listSupportedBackends} from './backend'; -registerBackend('cpu', onnxruntimeBackend, 100); +const backends = listSupportedBackends(); +for (const backend of backends) { + registerBackend(backend.name, onnxruntimeBackend, 100); +} + +Object.defineProperty(env.versions, 'node', {value: version, enumerable: true}); diff --git a/js/node/lib/version.ts b/js/node/lib/version.ts new file mode 100644 index 0000000000000..96c2361cceabe --- /dev/null +++ b/js/node/lib/version.ts @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// This file is generated by /js/scripts/update-version.ts +// Do not modify file content manually. + +export const version = '1.17.0'; diff --git a/js/node/package-lock.json b/js/node/package-lock.json index 688e434121992..ce390aa88c0aa 100644 --- a/js/node/package-lock.json +++ b/js/node/package-lock.json @@ -1,12 +1,12 @@ { "name": "onnxruntime-node", - "version": "1.15.0", + "version": "1.17.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "onnxruntime-node", - "version": "1.15.0", + "version": "1.17.0", "license": "MIT", "os": [ "win32", @@ -18,17 +18,16 @@ }, "devDependencies": { "@types/minimist": "^1.2.2", - "@types/mocha": "^10.0.1", "cmake-js": "^7.2.1", "jsonc": "^2.0.0", "minimist": "^1.2.8", - "mocha": "^10.2.0", "node-addon-api": "^6.0.0", "onnx-proto": "^8.0.1" } }, "../common": { - "version": "1.15.0", + "name": "onnxruntime-common", + "version": "1.17.0", "license": "MIT", "devDependencies": { "typedoc": "^0.23.22" @@ -110,27 +109,12 @@ "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", "dev": true }, - "node_modules/@types/mocha": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz", - "integrity": "sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==", - "dev": true - }, "node_modules/@types/node": { "version": "18.14.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz", "integrity": "sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA==", "dev": true }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -155,19 +139,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", @@ -187,12 +158,6 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "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 - }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -210,115 +175,6 @@ "proxy-from-env": "^1.1.0" } }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "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, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "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/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, "node_modules/chownr": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", @@ -408,12 +264,6 @@ "node": ">= 0.8" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, "node_modules/console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", @@ -437,18 +287,6 @@ } } }, - "node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -473,15 +311,6 @@ "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", "dev": true }, - "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -506,61 +335,12 @@ "node": ">=6" } }, - "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, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/fast-safe-stringify": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", "dev": true }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "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, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "bin": { - "flat": "cli.js" - } - }, "node_modules/follow-redirects": { "version": "1.15.2", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", @@ -633,26 +413,6 @@ "node": ">=8" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/gauge": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", @@ -681,100 +441,18 @@ "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "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" - }, - "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, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", "dev": true }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -793,27 +471,6 @@ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "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, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -823,66 +480,12 @@ "node": ">=8" } }, - "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, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "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, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, - "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, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "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", @@ -918,43 +521,12 @@ "graceful-fs": "^4.1.6" } }, - "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, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", "dev": true }, - "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, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/long": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", @@ -1003,18 +575,6 @@ "node": ">= 0.6" } }, - "node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", @@ -1070,99 +630,12 @@ "mkdirp": "bin/cmd.js" } }, - "node_modules/mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", - "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", - "dev": true, - "dependencies": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha.js" - }, - "engines": { - "node": ">= 14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" - } - }, - "node_modules/mocha/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/mocha/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 - }, - "node_modules/mocha/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/node-addon-api": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.0.0.tgz", @@ -1175,15 +648,6 @@ "integrity": "sha512-YsjmaKGPDkmhoNKIpkChtCsPVaRE0a274IdERKnuc/E8K1UJdBZ4/mvI006OijlQZHCfpRNOH3dfHQs92se8gg==", "dev": true }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/npmlog": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", @@ -1199,15 +663,6 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, "node_modules/onnx-proto": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/onnx-proto/-/onnx-proto-8.0.1.tgz", @@ -1221,36 +676,6 @@ "resolved": "../common", "link": true }, - "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, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -1264,40 +689,10 @@ "node": ">=4" } }, - "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, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/protobufjs": { - "version": "6.11.3", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", - "integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==", + "version": "6.11.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz", + "integrity": "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -1326,15 +721,6 @@ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "dev": true }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -1373,18 +759,6 @@ "node": ">= 6" } }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -1424,18 +798,9 @@ }, "bin": { "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" + }, + "engines": { + "node": ">=10" } }, "node_modules/set-blocking": { @@ -1506,21 +871,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "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, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, "node_modules/tar": { "version": "6.1.13", "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz", @@ -1550,18 +900,6 @@ "node": ">=10" } }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, "node_modules/universalify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", @@ -1607,12 +945,6 @@ "string-width": "^1.0.2 || 2 || 3 || 4" } }, - "node_modules/workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true - }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -1630,12 +962,6 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -1669,30 +995,6 @@ "node": ">=12" } }, - "node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "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/node_modules/yargs-parser": { "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", @@ -1701,18 +1003,6 @@ "engines": { "node": ">=12" } - }, - "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==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } } }, "dependencies": { @@ -1792,24 +1082,12 @@ "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", "dev": true }, - "@types/mocha": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz", - "integrity": "sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==", - "dev": true - }, "@types/node": { "version": "18.14.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz", "integrity": "sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA==", "dev": true }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -1825,16 +1103,6 @@ "color-convert": "^2.0.1" } }, - "anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, "aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", @@ -1851,12 +1119,6 @@ "readable-stream": "^3.6.0" } }, - "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 - }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -1874,85 +1136,6 @@ "proxy-from-env": "^1.1.0" } }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true - }, - "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, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - } - }, "chownr": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", @@ -2021,12 +1204,6 @@ "delayed-stream": "~1.0.0" } }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", @@ -2042,12 +1219,6 @@ "ms": "2.1.2" } }, - "decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true - }, "deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -2066,12 +1237,6 @@ "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", "dev": true }, - "diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true - }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -2093,43 +1258,12 @@ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", "dev": true }, - "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 - }, "fast-safe-stringify": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", "dev": true }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "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, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true - }, "follow-redirects": { "version": "1.15.2", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", @@ -2178,19 +1312,6 @@ } } }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, "gauge": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", @@ -2213,84 +1334,18 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, - "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "requires": { - "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" - }, - "dependencies": { - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - } - } - }, - "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, - "requires": { - "is-glob": "^4.0.1" - } - }, "graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, "has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", "dev": true }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -2309,69 +1364,18 @@ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true - }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, - "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, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true - }, - "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 - }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, - "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, - "requires": { - "argparse": "^2.0.1" - } - }, "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", @@ -2402,31 +1406,12 @@ "universalify": "^2.0.0" } }, - "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, - "requires": { - "p-locate": "^5.0.0" - } - }, "lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", "dev": true }, - "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, - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - } - }, "long": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", @@ -2466,15 +1451,6 @@ "mime-db": "1.52.0" } }, - "minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - }, "minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", @@ -2517,81 +1493,12 @@ "minimist": "^1.2.6" } }, - "mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", - "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", - "dev": true, - "requires": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "dependencies": { - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "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 - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - } - } - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true - }, "node-addon-api": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.0.0.tgz", @@ -2604,12 +1511,6 @@ "integrity": "sha512-YsjmaKGPDkmhoNKIpkChtCsPVaRE0a274IdERKnuc/E8K1UJdBZ4/mvI006OijlQZHCfpRNOH3dfHQs92se8gg==", "dev": true }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, "npmlog": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", @@ -2622,15 +1523,6 @@ "set-blocking": "^2.0.0" } }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "requires": { - "wrappy": "1" - } - }, "onnx-proto": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/onnx-proto/-/onnx-proto-8.0.1.tgz", @@ -2646,24 +1538,6 @@ "typedoc": "^0.23.22" } }, - "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, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "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, - "requires": { - "p-limit": "^3.0.2" - } - }, "parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -2674,28 +1548,10 @@ "json-parse-better-errors": "^1.0.1" } }, - "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 - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, "protobufjs": { - "version": "6.11.3", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", - "integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==", + "version": "6.11.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz", + "integrity": "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==", "dev": true, "requires": { "@protobufjs/aspromise": "^1.1.2", @@ -2719,15 +1575,6 @@ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "dev": true }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, "rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -2759,15 +1606,6 @@ "util-deprecate": "^1.0.1" } }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -2789,15 +1627,6 @@ "lru-cache": "^6.0.0" } }, - "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -2851,15 +1680,6 @@ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, - "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, - "requires": { - "has-flag": "^4.0.0" - } - }, "tar": { "version": "6.1.13", "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz", @@ -2882,15 +1702,6 @@ } } }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, "universalify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", @@ -2927,12 +1738,6 @@ "string-width": "^1.0.2 || 2 || 3 || 4" } }, - "workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true - }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -2944,12 +1749,6 @@ "strip-ansi": "^6.0.0" } }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -2984,30 +1783,6 @@ "dev": true } } - }, - "yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true - }, - "yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "requires": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - } - }, - "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==", - "dev": true } } } diff --git a/js/node/package.json b/js/node/package.json index 8bad9d2a21089..0f8f0e9d2260c 100644 --- a/js/node/package.json +++ b/js/node/package.json @@ -13,7 +13,7 @@ 3 ] }, - "version": "1.15.0", + "version": "1.17.0", "dependencies": { "onnxruntime-common": "file:../common" }, @@ -35,11 +35,9 @@ ], "devDependencies": { "@types/minimist": "^1.2.2", - "@types/mocha": "^10.0.1", "cmake-js": "^7.2.1", "jsonc": "^2.0.0", "minimist": "^1.2.8", - "mocha": "^10.2.0", "node-addon-api": "^6.0.0", "onnx-proto": "^8.0.1" }, diff --git a/js/node/script/build.ts b/js/node/script/build.ts index 3453bda398a1c..dfa88821a8d09 100644 --- a/js/node/script/build.ts +++ b/js/node/script/build.ts @@ -25,6 +25,14 @@ if (ARCH !== 'x64' && ARCH !== 'ia32' && ARCH !== 'arm64' && ARCH !== 'arm') { const ONNXRUNTIME_BUILD_DIR = buildArgs['onnxruntime-build-dir']; // --rebuild const REBUILD = !!buildArgs.rebuild; +// --use_dml +const USE_DML = !!buildArgs.use_dml; +// --use_cuda +const USE_CUDA = !!buildArgs.use_cuda; +// --use_tensorrt +const USE_TENSORRT = !!buildArgs.use_tensorrt; +// --use_coreml +const USE_COREML = !!buildArgs.use_coreml; // build path const ROOT_FOLDER = path.join(__dirname, '..'); @@ -41,12 +49,24 @@ const args = [ 'cmake-js', (REBUILD ? 'reconfigure' : 'configure'), `--arch=${ARCH}`, - '--CDnapi_build_version=3', + '--CDnapi_build_version=6', `--CDCMAKE_BUILD_TYPE=${CONFIG}`, ]; if (ONNXRUNTIME_BUILD_DIR && typeof ONNXRUNTIME_BUILD_DIR === 'string') { args.push(`--CDONNXRUNTIME_BUILD_DIR=${ONNXRUNTIME_BUILD_DIR}`); } +if (USE_DML) { + args.push('--CDUSE_DML=ON'); +} +if (USE_CUDA) { + args.push('--CDUSE_CUDA=ON'); +} +if (USE_TENSORRT) { + args.push('--CDUSE_TENSORRT=ON'); +} +if (USE_COREML) { + args.push('--CDUSE_COREML=ON'); +} // set CMAKE_OSX_ARCHITECTURES for macOS build if (os.platform() === 'darwin') { diff --git a/js/node/script/prepack.ts b/js/node/script/prepack.ts index be86c5687bec0..4c5941d8dae12 100644 --- a/js/node/script/prepack.ts +++ b/js/node/script/prepack.ts @@ -11,7 +11,7 @@ function updatePackageJson() { const packageCommon = fs.readJSONSync(commonPackageJsonPath); const packageSelf = fs.readJSONSync(selfPackageJsonPath); const version = packageCommon.version; - packageSelf.dependencies['onnxruntime-common'] = `~${version}`; + packageSelf.dependencies['onnxruntime-common'] = `${version}`; fs.writeJSONSync(selfPackageJsonPath, packageSelf, {spaces: 2}); console.log('=== finished updating package.json.'); } diff --git a/js/node/src/directml_load_helper.cc b/js/node/src/directml_load_helper.cc new file mode 100644 index 0000000000000..7017f627fd3d7 --- /dev/null +++ b/js/node/src/directml_load_helper.cc @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifdef _WIN32 +#include "common.h" +#include "windows.h" + +void LoadDirectMLDll(Napi::Env env) { + DWORD pathLen = MAX_PATH; + std::wstring path(pathLen, L'\0'); + HMODULE moduleHandle = nullptr; + + GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + reinterpret_cast(&LoadDirectMLDll), &moduleHandle); + + DWORD getModuleFileNameResult = GetModuleFileNameW(moduleHandle, const_cast(path.c_str()), pathLen); + while (getModuleFileNameResult == 0 || getModuleFileNameResult == pathLen) { + int ret = GetLastError(); + if (ret == ERROR_INSUFFICIENT_BUFFER && pathLen < 32768) { + pathLen *= 2; + path.resize(pathLen); + getModuleFileNameResult = GetModuleFileNameW(moduleHandle, const_cast(path.c_str()), pathLen); + } else { + ORT_NAPI_THROW_ERROR(env, "Failed getting path to load DirectML.dll, error code: ", ret); + } + } + + path.resize(path.rfind(L'\\') + 1); + path.append(L"DirectML.dll"); + HMODULE libraryLoadResult = LoadLibraryW(path.c_str()); + + if (!libraryLoadResult) { + int ret = GetLastError(); + ORT_NAPI_THROW_ERROR(env, "Failed loading bundled DirectML.dll, error code: ", ret); + } +} +#endif diff --git a/js/node/src/directml_load_helper.h b/js/node/src/directml_load_helper.h new file mode 100644 index 0000000000000..074a4f95ed476 --- /dev/null +++ b/js/node/src/directml_load_helper.h @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#if defined(USE_DML) && defined(_WIN32) +void LoadDirectMLDll(Napi::Env env); +#endif diff --git a/js/node/src/inference_session_wrap.cc b/js/node/src/inference_session_wrap.cc index 78f32ec09250b..c409fdc8895f7 100644 --- a/js/node/src/inference_session_wrap.cc +++ b/js/node/src/inference_session_wrap.cc @@ -4,19 +4,27 @@ #include "onnxruntime_cxx_api.h" #include "common.h" +#include "directml_load_helper.h" #include "inference_session_wrap.h" #include "run_options_helper.h" #include "session_options_helper.h" #include "tensor_helper.h" +#include Napi::FunctionReference InferenceSessionWrap::constructor; -Ort::Env *InferenceSessionWrap::ortEnv; Napi::Object InferenceSessionWrap::Init(Napi::Env env, Napi::Object exports) { +#if defined(USE_DML) && defined(_WIN32) + LoadDirectMLDll(env); +#endif // create ONNX runtime env Ort::InitApi(); - ortEnv = new Ort::Env{ORT_LOGGING_LEVEL_WARNING, "onnxruntime-node"}; - + ORT_NAPI_THROW_ERROR_IF( + Ort::Global::api_ == nullptr, env, + "Failed to initialize ONNX Runtime API. It could happen when this nodejs binding was built with a higher version " + "ONNX Runtime but now runs with a lower version ONNX Runtime DLL(or shared library)."); + auto ortEnv = new Ort::Env{ORT_LOGGING_LEVEL_WARNING, "onnxruntime-node"}; + env.SetInstanceData(ortEnv); // initialize binding Napi::HandleScope scope(env); @@ -28,8 +36,11 @@ Napi::Object InferenceSessionWrap::Init(Napi::Env env, Napi::Object exports) { constructor = Napi::Persistent(func); constructor.SuppressDestruct(); - exports.Set("InferenceSession", func); + + Napi::Function listSupportedBackends = Napi::Function::New(env, InferenceSessionWrap::ListSupportedBackends); + exports.Set("listSupportedBackends", listSupportedBackends); + return exports; } @@ -54,7 +65,7 @@ Napi::Value InferenceSessionWrap::LoadModel(const Napi::CallbackInfo &info) { Napi::String value = info[0].As(); ParseSessionOptions(info[1].As(), sessionOptions); - this->session_.reset(new Ort::Session(OrtEnv(), + this->session_.reset(new Ort::Session(*env.GetInstanceData(), #ifdef _WIN32 reinterpret_cast(value.Utf16Value().c_str()), #else @@ -68,9 +79,10 @@ Napi::Value InferenceSessionWrap::LoadModel(const Napi::CallbackInfo &info) { int64_t bytesOffset = info[1].As().Int64Value(); int64_t bytesLength = info[2].As().Int64Value(); - ParseSessionOptions(info[1].As(), sessionOptions); - this->session_.reset( - new Ort::Session(OrtEnv(), reinterpret_cast(buffer) + bytesOffset, bytesLength, sessionOptions)); + ParseSessionOptions(info[3].As(), sessionOptions); + this->session_.reset(new Ort::Session(*env.GetInstanceData(), + reinterpret_cast(buffer) + bytesOffset, bytesLength, + sessionOptions)); } else { ORT_NAPI_THROW_TYPEERROR( env, @@ -151,6 +163,7 @@ Napi::Value InferenceSessionWrap::Run(const Napi::CallbackInfo &info) { std::vector reuseOutput; size_t inputIndex = 0; size_t outputIndex = 0; + OrtMemoryInfo *memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault).release(); try { for (auto &name : inputNames_) { @@ -158,7 +171,7 @@ Napi::Value InferenceSessionWrap::Run(const Napi::CallbackInfo &info) { inputIndex++; inputNames_cstr.push_back(name.c_str()); auto value = feed.Get(name); - inputValues.push_back(NapiValueToOrtValue(env, value)); + inputValues.push_back(NapiValueToOrtValue(env, value, memory_info)); } } for (auto &name : outputNames_) { @@ -167,7 +180,7 @@ Napi::Value InferenceSessionWrap::Run(const Napi::CallbackInfo &info) { outputNames_cstr.push_back(name.c_str()); auto value = fetch.Get(name); reuseOutput.push_back(!value.IsNull()); - outputValues.emplace_back(value.IsNull() ? Ort::Value{nullptr} : NapiValueToOrtValue(env, value)); + outputValues.emplace_back(value.IsNull() ? Ort::Value{nullptr} : NapiValueToOrtValue(env, value, memory_info)); } } @@ -195,3 +208,33 @@ Napi::Value InferenceSessionWrap::Run(const Napi::CallbackInfo &info) { ORT_NAPI_THROW_ERROR(env, e.what()); } } + +Napi::Value InferenceSessionWrap::ListSupportedBackends(const Napi::CallbackInfo &info) { + Napi::Env env = info.Env(); + Napi::EscapableHandleScope scope(env); + Napi::Array result = Napi::Array::New(env); + + auto createObject = [&env](const std::string &name, const bool bundled) -> Napi::Object { + Napi::Object result = Napi::Object::New(env); + result.Set("name", name); + result.Set("bundled", bundled); + return result; + }; + + result.Set(uint32_t(0), createObject("cpu", true)); + +#ifdef USE_DML + result.Set(result.Length(), createObject("dml", true)); +#endif +#ifdef USE_CUDA + result.Set(result.Length(), createObject("cuda", false)); +#endif +#ifdef USE_TENSORRT + result.Set(result.Length(), createObject("tensorrt", false)); +#endif +#ifdef USE_COREML + result.Set(result.Length(), createObject("coreml", true)); +#endif + + return scope.Escape(result); +} diff --git a/js/node/src/inference_session_wrap.h b/js/node/src/inference_session_wrap.h index 8298819288947..9eee45b72dcb1 100644 --- a/js/node/src/inference_session_wrap.h +++ b/js/node/src/inference_session_wrap.h @@ -15,6 +15,12 @@ class InferenceSessionWrap : public Napi::ObjectWrap { InferenceSessionWrap(const Napi::CallbackInfo &info); private: + /** + * [sync] list supported backend list + * @returns array with objects { "name": "cpu", requirementsInstalled: true } + */ + static Napi::Value ListSupportedBackends(const Napi::CallbackInfo &info); + /** * [sync] create the session. * @param arg0 either a string (file path) or a Uint8Array @@ -54,10 +60,6 @@ class InferenceSessionWrap : public Napi::ObjectWrap { // persistent constructor static Napi::FunctionReference constructor; - // global env - static Ort::Env *ortEnv; - static Ort::Env &OrtEnv() { return *ortEnv; } - // session objects bool initialized_; std::unique_ptr session_; diff --git a/js/node/src/session_options_helper.cc b/js/node/src/session_options_helper.cc index 55825a4a2baac..70e63da7cefa7 100644 --- a/js/node/src/session_options_helper.cc +++ b/js/node/src/session_options_helper.cc @@ -9,6 +9,19 @@ #include "common.h" #include "session_options_helper.h" +#ifdef USE_CUDA +#include "core/providers/cuda/cuda_provider_options.h" +#endif +#ifdef USE_DML +#include "core/providers/dml/dml_provider_factory.h" +#endif +#ifdef USE_TENSORRT +#include "core/providers/tensorrt/tensorrt_provider_factory.h" +#include "core/providers/tensorrt/tensorrt_provider_options.h" +#endif +#ifdef USE_COREML +#include "core/providers/coreml/coreml_provider_factory.h" +#endif const std::unordered_map GRAPH_OPT_LEVEL_NAME_TO_ID_MAP = { {"disabled", ORT_DISABLE_ALL}, @@ -23,6 +36,8 @@ void ParseExecutionProviders(const Napi::Array epList, Ort::SessionOptions &sess for (uint32_t i = 0; i < epList.Length(); i++) { Napi::Value epValue = epList[i]; std::string name; + int deviceId = 0; + int coreMlFlags = 0; if (epValue.IsString()) { name = epValue.As().Utf8Value(); } else if (!epValue.IsObject() || epValue.IsNull() || !epValue.As().Has("name") || @@ -30,14 +45,43 @@ void ParseExecutionProviders(const Napi::Array epList, Ort::SessionOptions &sess ORT_NAPI_THROW_TYPEERROR(epList.Env(), "Invalid argument: sessionOptions.executionProviders[", i, "] must be either a string or an object with property 'name'."); } else { - name = epValue.As().Get("name").As().Utf8Value(); + auto obj = epValue.As(); + name = obj.Get("name").As().Utf8Value(); + if (obj.Has("deviceId")) { + deviceId = obj.Get("deviceId").As(); + } + if (obj.Has("coreMlFlags")) { + coreMlFlags = obj.Get("coreMlFlags").As(); + } } // CPU execution provider if (name == "cpu") { // TODO: handling CPU EP options +#ifdef USE_CUDA } else if (name == "cuda") { - // TODO: handling Cuda EP options + OrtCUDAProviderOptionsV2 *options; + Ort::GetApi().CreateCUDAProviderOptions(&options); + options->device_id = deviceId; + sessionOptions.AppendExecutionProvider_CUDA_V2(*options); + Ort::GetApi().ReleaseCUDAProviderOptions(options); +#endif +#ifdef USE_TENSORRT + } else if (name == "tensorrt") { + OrtTensorRTProviderOptionsV2 *options; + Ort::GetApi().CreateTensorRTProviderOptions(&options); + options->device_id = deviceId; + sessionOptions.AppendExecutionProvider_TensorRT_V2(*options); + Ort::GetApi().ReleaseTensorRTProviderOptions(options); +#endif +#ifdef USE_DML + } else if (name == "dml") { + Ort::ThrowOnError(OrtSessionOptionsAppendExecutionProvider_DML(sessionOptions, deviceId)); +#endif +#ifdef USE_COREML + } else if (name == "coreml") { + Ort::ThrowOnError(OrtSessionOptionsAppendExecutionProvider_CoreML(sessionOptions, coreMlFlags)); +#endif } else { ORT_NAPI_THROW_ERROR(epList.Env(), "Invalid argument: sessionOptions.executionProviders[", i, "] is unsupported: '", name, "'."); diff --git a/js/node/src/tensor_helper.cc b/js/node/src/tensor_helper.cc index a082448aa8f01..1c0b141e6a44f 100644 --- a/js/node/src/tensor_helper.cc +++ b/js/node/src/tensor_helper.cc @@ -106,7 +106,7 @@ const std::unordered_map DATA_TYPE_NAME_ {"uint64", ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT64}}; // currently only support tensor -Ort::Value NapiValueToOrtValue(Napi::Env env, Napi::Value value) { +Ort::Value NapiValueToOrtValue(Napi::Env env, Napi::Value value, OrtMemoryInfo *memory_info) { ORT_NAPI_THROW_TYPEERROR_IF(!value.IsObject(), env, "Tensor must be an object."); // check 'dims' @@ -180,7 +180,6 @@ Ort::Value NapiValueToOrtValue(Napi::Env env, Napi::Value value) { "Tensor.data must be a typed array (", DATA_TYPE_TYPEDARRAY_MAP[elemType], ") for ", tensorTypeString, " tensors, but got typed array (", typedArrayType, ")."); - auto memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault); char *buffer = reinterpret_cast(tensorDataTypedArray.ArrayBuffer().Data()); size_t bufferByteOffset = tensorDataTypedArray.ByteOffset(); // there is a bug in TypedArray::ElementSize(): https://github.com/nodejs/node-addon-api/pull/705 diff --git a/js/node/src/tensor_helper.h b/js/node/src/tensor_helper.h index 019e5e8231bd7..d5e8ef709f53e 100644 --- a/js/node/src/tensor_helper.h +++ b/js/node/src/tensor_helper.h @@ -9,7 +9,7 @@ #include "onnxruntime_cxx_api.h" // convert a Javascript OnnxValue object to an OrtValue object -Ort::Value NapiValueToOrtValue(Napi::Env env, Napi::Value value); +Ort::Value NapiValueToOrtValue(Napi::Env env, Napi::Value value, OrtMemoryInfo *memory_info); // convert an OrtValue object to a Javascript OnnxValue object Napi::Value OrtValueToNapiValue(Napi::Env env, Ort::Value &value); diff --git a/js/node/test/test-runner.ts b/js/node/test/test-runner.ts index 5d9cf61c8d45b..06ed0acfca36c 100644 --- a/js/node/test/test-runner.ts +++ b/js/node/test/test-runner.ts @@ -112,6 +112,14 @@ export function run(testDataRoot: string): void { }); } } + + if (!skipModel) { + after(async () => { + if (session !== null) { + await session.release(); + } + }); + } }); } } diff --git a/js/node/test/testdata/squeezenet.input0.json b/js/node/test/testdata/squeezenet.input0.json index 94bae787255fb..032d336f7bd85 100644 --- a/js/node/test/testdata/squeezenet.input0.json +++ b/js/node/test/testdata/squeezenet.input0.json @@ -1 +1,18822 @@ -[1.7640523911,0.4001572132,0.9787380099,2.2408931255,1.8675580025,-0.9772778749,0.9500884414,-0.1513572037,-0.1032188535,0.4105985165,0.1440435648,1.4542734623,0.7610377073,0.1216750145,0.4438632429,0.3336743414,1.4940791130,-0.2051582634,0.3130677044,-0.8540957570,-2.5529897213,0.6536185741,0.8644362092,-0.7421650290,2.2697546482,-1.4543657303,0.0457585156,-0.1871838570,1.5327792168,1.4693588018,0.1549474299,0.3781625330,-0.8877857327,-1.9807964563,-0.3479121625,0.1563489735,1.2302906513,1.2023798227,-0.3873268068,-0.3023027480,-1.0485529900,-1.4200179577,-1.7062702179,1.9507753849,-0.5096521974,-0.4380742908,-1.2527953386,0.7774903774,-1.6138978004,-0.2127402872,-0.8954665661,0.3869025111,-0.5108051300,-1.1806322336,-0.0281822290,0.4283318818,0.0665172189,0.3024719059,-0.6343221068,-0.3627411723,-0.6724604368,-0.3595531583,-0.8131462932,-1.7262825966,0.1774261445,-0.4017809331,-1.6301983595,0.4627822638,-0.9072983861,0.0519453958,0.7290905714,0.1289829165,1.1394007206,-1.2348258495,0.4023416340,-0.6848101020,-0.8707971573,-0.5788496733,-0.3115525246,0.0561653413,-1.1651498079,0.9008265138,0.4656624496,-1.5362436771,1.4882521629,1.8958891630,1.1787796021,-0.1799248308,-1.0707526207,1.0544517040,-0.4031769335,1.2224450111,0.2082749754,0.9766390324,0.3563663960,0.7065731883,0.0105000203,1.7858705521,0.1269120872,0.4019893706,1.8831506968,-1.3477590084,-1.2704850435,0.9693967104,-1.1731233597,1.9436211586,-0.4136189818,-0.7474548221,1.9229420424,1.4805147648,1.8675589561,0.9060446620,-0.8612256646,1.9100649357,-0.2680033743,0.8024563789,0.9472519755,-0.1550100893,0.6140793562,0.9222066998,0.3764255345,-1.0994007587,0.2982381880,1.3263858557,-0.6945678592,-0.1496345401,-0.4351535439,1.8492637873,0.6722947359,0.4074618220,-0.7699160576,0.5392491817,-0.6743326783,0.0318305567,-0.6358460784,0.6764332652,0.5765908360,-0.2082987577,0.3960067034,-1.0930615664,-1.4912575483,0.4393917024,0.1666734964,0.6350314617,2.3831448555,0.9444794655,-0.9128222466,1.1170163155,-1.3159073591,-0.4615845978,-0.0682416037,1.7133426666,-0.7447548509,-0.8264385462,-0.0984525234,-0.6634783149,1.1266359091,-1.0799314976,-1.1474686861,-0.4378200471,-0.4980324507,1.9295320511,0.9494208097,0.0875512436,-1.2254354954,0.8443629742,-1.0002152920,-1.5447710752,1.1880297661,0.3169426024,0.9208588004,0.3187276423,0.8568305969,-0.6510255933,-1.0342428684,0.6815944910,-0.8034096360,-0.6895498037,-0.4555324912,0.0174791589,-0.3539939225,-1.3749512434,-0.6436184049,-2.2234032154,0.6252314448,-1.6020576954,-1.1043833494,0.0521650799,-0.7395629883,1.5430146456,-1.2928569317,0.2670508623,-0.0392828174,-1.1680934429,0.5232766867,-0.1715463251,0.7717905641,0.8235041499,2.1632359028,1.3365279436,-0.3691818416,-0.2393791825,1.0996595621,0.6552637219,0.6401315331,-1.6169559956,-0.0243261252,-0.7380309105,0.2799246013,-0.0981503874,0.9101788998,0.3172182143,0.7863279581,-0.4664191008,-0.9444462657,-0.4100497067,-0.0170204137,0.3791517317,2.2593090534,-0.0422571525,-0.9559450150,-0.3459817767,-0.4635959864,0.4814814627,-1.5407969952,0.0632619932,0.1565065384,0.2321810424,-0.5973160863,-0.2379217297,-1.4240609407,-0.4933198690,-0.5428614616,0.4160500467,-1.1561824083,0.7811980844,1.4944845438,-2.0699849129,0.4262587428,0.6769080162,-0.6374370456,-0.3972718120,-0.1328805834,-0.2977908850,-0.3090129793,-1.6760038137,1.1523315907,1.0796185732,-0.8133642673,-1.4664243460,0.5210648775,-0.5757879615,0.1419531703,-0.3193284273,0.6915387511,0.6947491169,-0.7255973816,-1.3833639622,-1.5829384327,0.6103793979,-1.1888592243,-0.5068163276,-0.5963140130,-0.0525672957,-1.9362797737,0.1887785941,0.5238910317,0.0884220898,-0.3108861744,0.0974001661,0.3990463316,-2.7725927830,1.9559123516,0.3900933266,-0.6524085999,-0.3909533620,0.4937417805,-0.1161039397,-2.0306844711,2.0644929409,-0.1105406582,1.0201727152,-0.6920498610,1.5363770723,0.2863436937,0.6088438630,-1.0452533960,1.2111452818,0.6898181438,1.3018462658,-0.6280875802,-0.4810271263,2.3039166927,-1.0600157976,-0.1359497011,1.1368913651,0.0977249667,0.5829536915,-0.3994490206,0.3700558841,-1.3065268993,1.6581306458,-0.1181640476,-0.6801782250,0.6663830876,-0.4607197940,-1.3342584372,-1.3467174768,0.6937731504,-0.1595734358,-0.1337015629,1.0777437687,-1.1268258095,-0.7306777239,-0.3848797977,0.0943515897,-0.0421714522,-0.2868871987,-0.0616264008,-0.1073052734,-0.7196043730,-0.8129929900,0.2745163441,-0.8909150958,-1.1573553085,-0.3122922480,-0.1576670110,2.2567234039,-0.7047002912,0.9432607293,0.7471883297,-1.1889449358,0.7732529640,-1.1838806868,-2.6591722965,0.6063195467,-1.7558906078,0.4509344697,-0.6840109229,1.6595507860,1.0685093403,-0.4533858001,-0.6878376007,-1.2140773535,-0.4409226179,-0.2803554833,-0.3646935523,0.1567038596,0.5785214901,0.3496544659,-0.7641439438,-1.4377914667,1.3645318747,-0.6894491911,-0.6522936225,-0.5211893320,-1.8430695534,-0.4779739976,-0.4796558022,0.6203582883,0.6984571218,0.0037708890,0.9318483472,0.3399649858,-0.0156821124,0.1609281749,-0.1906534880,-0.3948495090,-0.2677335441,-1.1280113459,0.2804417014,-0.9931235909,0.8416312933,-0.2494585812,0.0494949818,0.4938367903,0.6433144808,-1.5706233978,-0.2069036812,0.8801789284,-1.6981058121,0.3872804642,-2.2555642128,-1.0225068331,0.0386305526,-1.6567151546,-0.9855107665,-1.4718350172,1.6481349468,0.1642277539,0.5672903061,-0.2226751000,-0.3534317613,-1.6164741516,-0.2918373644,-0.7614921927,0.8579239249,1.1411018372,1.4665787220,0.8525519371,-0.5986539125,-1.1158969402,0.7666631937,0.3562928140,-1.7685384750,0.3554818034,0.8145198226,0.0589255877,-0.1850536764,-0.8076484799,-1.4465347528,0.8002979755,-0.3091144562,-0.2334666550,1.7327212095,0.6845011115,0.3708249927,0.1420617998,1.5199948549,1.7195893526,0.9295051098,0.5822246075,-2.0946030617,0.1237219125,-0.1301069558,0.0939532295,0.9430460930,-2.7396771908,-0.5693120360,0.2699043453,-0.4668455422,-1.4169061184,0.8689634800,0.2768719196,-0.9711045623,0.3148171902,0.8215857148,0.0052926461,0.8005648255,0.0782601759,-0.3952289820,-1.1594204903,-0.0859307647,0.1942929327,0.8758327365,-0.1151074693,0.4574156106,-0.9646120071,-0.7826291323,-0.1103892997,-1.0546284914,0.8202478290,0.4631303251,0.2790957689,0.3389041126,2.0210435390,-0.4688642025,-2.2014412880,0.1993001997,-0.0506035425,-0.5175190568,-0.9788298607,-0.4391895235,0.1813384295,-0.5028166771,2.4124536514,-0.9605043530,-0.7931173444,-2.2886199951,0.2514844239,-2.0164065361,-0.5394546390,-0.2756705284,-0.7097279429,1.7388726473,0.9943943620,1.3191368580,-0.8824188113,1.1285940409,0.4960009456,0.7714059353,1.0294388533,-0.9087632298,-0.4243176281,0.8625960350,-2.6556191444,1.5133280754,0.5531320572,-0.0457039624,0.2205076516,-1.0299352407,-0.3499433696,1.1002843380,1.2980220318,2.6962239742,-0.0739246681,-0.6585529447,-0.5142339468,-1.0180418491,-0.0778547525,0.3827324212,-0.0342422798,1.0963468552,-0.2342157960,-0.3474506438,-0.5812684894,-1.6326345205,-1.5677677393,-1.1791579723,1.3014280796,0.8952602744,1.3749641180,-1.3322116137,-1.9686247110,-0.6600562930,0.1758189499,0.4986902773,1.0479722023,0.2842796743,1.7426687479,-0.2226056755,-0.9130792022,-1.6812182665,-0.8889713287,0.2421179563,-0.8887202740,0.9367424846,1.4123276472,-2.3695869446,0.8640522957,-2.2396039963,0.4014990628,1.2248705626,0.0648561046,-1.2796891928,-0.5854312181,-0.2616454363,-0.1822447777,-0.2028968334,-0.1098827794,0.2134800553,-1.2085736990,-0.2420198321,1.5182611942,-0.3846454322,-0.4438360929,1.0781973600,-2.5591845512,1.1813786030,-0.6319037676,0.1639285684,0.0963213593,0.9424681067,-0.2675947547,-0.6780257821,1.2978458405,-2.3641738892,0.0203341823,-1.3479254246,-0.7615733743,2.0112566948,-0.0445954278,0.1950697005,-1.7815628052,-0.7290446758,0.1965574026,0.3547576964,0.6168865561,0.0086278990,0.5270041823,0.4537819028,-1.8297404051,0.0370057225,0.7679024339,0.5898798108,-0.3638588190,-0.8056265116,-1.1183118820,-0.1310540140,1.1330798864,-1.9518041611,-0.6598917246,-1.1398024559,0.7849575281,-0.5543096066,-0.4706376493,-0.2169495672,0.4453932643,-0.3923889995,-3.0461430550,0.5433118939,0.4390429556,-0.2195410281,-1.0840365887,0.3517801166,0.3792355359,-0.4700328708,-0.2167314738,-0.9301565289,-0.1785890907,-1.5504293442,0.4173188210,-0.9443684816,0.2381031513,-1.4059629440,-0.5900576711,-0.1104894057,-1.6606998444,0.1151478738,-0.3791475594,-1.7423561811,-1.3032428026,0.6051200628,0.8955559731,-0.1319086403,0.4047618210,0.2238435596,0.3296229839,1.2859840393,-1.5069984198,0.6764607430,-0.3820089698,-0.2242589295,-0.3022497296,-0.3751471043,-1.2261961699,0.1833391935,1.6709430218,-0.0561330207,-0.0013850428,-0.6872990131,-0.1174745485,0.4661664367,-0.3702424467,-0.4538040459,0.4032645524,-0.9180047512,0.2524966300,0.8203217983,1.3599485159,-0.0903820097,1.3675972223,1.0344098806,-0.9962126613,-1.2179385424,-0.3049636483,1.0289355516,-0.0722870082,-0.6006575823,1.5522432327,0.2869044840,-2.3205943108,0.3171606362,0.5200406313,0.2256086618,0.4497120976,-0.0672756061,-1.3183958530,-0.3707039952,-0.9456157684,-0.9327409267,-1.2630683184,0.4524890780,0.0978961438,-0.4481653571,-0.6493379474,-0.0234231055,1.0791947842,-2.0042157173,0.3768765330,-0.5457119942,-1.8845858574,-1.9457030296,-0.9127835035,0.2195095569,0.3930629194,-0.9389815927,1.0170209408,1.4229835272,0.3960865736,-0.5914026499,1.1244192123,0.7553957105,0.8674074411,-0.6564636827,-2.8345544338,2.1167910099,-1.6108783484,-0.0357680731,2.3807454109,0.3305767477,0.9492464662,-1.5023965836,-1.7776669264,-0.5327028036,1.0907497406,-0.3462494612,-0.7946363091,0.1979672909,1.0819351673,-1.4449402094,-1.2105430365,-0.7886692286,1.0946383476,0.2348215282,2.1321535110,0.9364457130,-0.0350951776,1.2650778294,0.2114970088,-0.7049213648,0.6799748540,-0.6963266730,-0.2903971076,1.3277827501,-0.1012814865,-0.8031414151,-0.4643376768,1.0217906237,-0.5525406599,-0.3868708611,-0.5102927685,0.1839254946,-0.3854897618,-1.6018360853,-0.8871809244,-0.9327890277,1.2433193922,0.8126740456,0.5872593522,-0.5053583384,-0.8157915473,-0.5075175762,-1.0518801212,2.4972004890,-2.2453217506,0.5640085340,-1.2845523357,-0.1043434888,-0.9880019426,-1.1776289940,-1.1401963234,1.7549861670,-0.1329884231,-0.7657021880,0.5557869673,0.0103493147,0.7200337648,-1.8242566586,0.3036039174,0.7726948261,-1.6615983248,0.4481952786,1.6961815357,-0.0148577038,0.8214059472,0.6705704331,-0.7075057030,0.0397667363,-1.5669946671,-0.4513030350,0.2656879723,0.7231004834,0.0246121250,0.7199837565,-1.1029062271,-0.1016972736,0.0192793850,1.8495912552,-0.2141666561,-0.4990166426,0.0213512238,-0.9191134572,0.1927538514,-0.3650552034,-1.7913275957,-0.0585865527,-0.3175430894,-1.6324232817,-0.0671341568,1.4893559217,0.5213037729,0.6119272113,-1.3414967060,0.4768983722,0.1484495848,0.5290452242,0.4226286113,-1.3597806692,-0.0414008126,-0.7578708529,-0.0500840954,-0.8974009156,1.3124703169,-0.8589723706,-0.8989421725,0.0745864064,-1.0770990849,-0.4246633053,-0.8299645782,1.4111720324,0.7858038545,-0.0574695170,-0.3912170529,0.9409176111,0.4052040875,0.4980524182,-0.0261922367,-1.6882300377,-0.1124659851,-0.5324898958,0.6450552940,1.0118424892,-0.6579510570,0.4683852196,1.7358789444,-0.6677127481,1.6819217205,-0.8525858521,0.0229597557,-0.0111456122,0.0114989001,-0.8376780152,-0.5911831260,-0.6677202582,0.3269625902,0.3300351202,2.2259442806,1.3709889650,-0.5098432302,0.3248696029,0.9971179962,0.0306018237,-0.0696415752,0.0515749417,0.8672766089,-0.8483205438,-0.3256694674,0.4704331458,0.3114470840,0.2395827621,-0.3698011637,0.9725357890,2.1338682175,0.4064154923,-0.1931767017,0.7557402849,-0.5391326547,-0.7496903539,0.0328087471,-2.5827965736,-1.1539503336,-0.3479618430,-1.3533889055,-1.0326430798,-0.4367483258,-1.6429653168,-0.4060717821,-0.5352701545,0.0254052076,1.1541839838,0.1725044101,0.0210620221,0.0994544551,0.2273927778,-1.0167386532,-0.1147753224,0.3087512553,-1.3707599640,0.8656529188,1.0813760757,-0.6313759685,-0.2413377911,-0.8781903386,0.6993804574,-1.0612223148,-0.2224770039,-0.8589199185,0.0509542786,-1.7942292690,1.3264616728,-0.9646064043,0.0598946847,-0.2125230432,-0.7621145248,-0.8877801299,0.9363985658,-0.5256406069,0.2711701989,-0.8014968634,-0.6471814513,0.4722471535,0.9304084778,-0.1753164083,-1.4219198227,1.9979560375,-0.8565493226,-1.5415873528,2.5944244862,-0.4040322900,-1.4617327452,-0.6834397912,0.3675448895,0.1903115511,-0.8517292142,1.8227236271,-0.5215796828,-1.1846865416,0.9606934190,1.3290628195,-0.8174930811,-1.4013472795,1.0304383039,-2.0473237038,-1.2266216278,0.9674461484,-0.0553525463,-0.2639373541,0.3528166115,-0.1527744234,-1.2986867428,1.2760753632,1.3250139952,0.2053325623,0.0451340154,2.3396248817,-0.2764328420,-0.2595769763,0.3644812405,1.4713219404,1.5927706957,-0.2585726380,0.3083312511,-1.3780834675,-0.3119761050,-0.8402903676,-1.0068317652,1.6815767288,-0.7922866344,-0.5316058993,0.3658487797,1.2978252172,0.4811151326,2.7593550682,-0.0746679753,0.2587164342,0.2756006718,1.4350494146,0.5072389245,-0.1162296981,-0.9474886060,0.2444434613,1.4013447762,-0.4103817940,0.5289435983,0.2461477816,0.8635196686,-0.8047537208,2.3466470242,-1.2791610956,-0.3655510843,0.9380925298,0.2967331707,0.8299861550,-0.4961023331,-0.0748049840,0.0122319832,1.5692596436,0.6904290318,0.7966721058,-0.6579260826,0.9688826203,0.2255816609,1.3891453743,2.0140602589,-0.3067657650,-0.4063031375,-0.8640449643,-0.1435795128,-0.3820254505,0.3595044017,-0.1445668191,-0.3615992665,1.0645850897,-0.9378802180,0.4331079423,-0.4059417248,0.7243685126,1.3852615356,-0.3030982614,0.4410329163,0.1787928641,-0.7994223833,0.2407875061,0.2891204953,0.4128708243,-0.1983989030,0.0941923037,-1.1476109028,-0.3581140637,0.5559626818,0.8924738765,-0.4223148227,0.1047140285,0.2280533314,0.2014799416,0.5407735705,-1.8180776834,-0.0493240692,0.2390335947,-1.0003303289,1.6739857197,0.1615592688,1.5634047985,-0.7905229926,-0.9073001146,0.2242522240,-1.6786884069,0.2149655968,0.0972192287,1.0156652927,0.7010413408,-0.4174773395,-1.0974966288,1.7123051882,-0.7921150327,-1.0455245972,-1.0848560333,1.1173052788,-0.5189002156,-0.7537044883,0.1376898289,-0.2069447041,-0.6780954599,0.7539914846,1.0653154850,0.9853175282,0.7669196725,0.4026255310,-1.7758879662,1.6692508459,0.3019891977,0.6081564426,1.1149623394,1.4333524704,0.4183980227,0.4355461597,-0.5992242694,0.0330897495,-0.8541612625,-0.7199405432,-0.8935744166,-0.1560238898,1.0490932465,3.1709747314,0.1894996315,-1.3484131098,1.2649832964,-0.3007838726,-0.6606085896,0.2098494768,-1.2406245470,0.2224631608,-0.0883755237,0.0983779058,0.3814162612,0.0674922541,0.0163380839,0.2843145132,0.4154006243,-1.0314824581,-1.4299912453,-0.0616380535,-1.4327354431,0.0875314698,0.9387468696,0.6071116924,-1.0481704473,-0.8602624536,0.3283012807,-0.4012978077,-0.3166553080,0.5969064832,-0.9872866869,-0.4012347162,-0.8000825047,-1.0431294441,-0.8570781946,0.6774621606,0.0518203899,-0.8791606426,-0.2311016023,-1.6388072968,-0.7333127856,2.1495745182,-0.0902438462,0.7316589355,-0.0654883757,0.3481692374,0.6632580757,-1.1046166420,-0.0309362579,1.5788651705,-0.7955005765,-0.5664398670,-0.3076912761,0.2690240741,0.5249178410,1.2674117088,0.4994982481,-0.0620531254,1.2591670752,0.7041110396,-1.4956794977,2.5263681412,1.7699214220,-0.1682142168,0.3779101074,1.3243587017,-0.1722007990,0.7303518057,1.1045784950,-1.0148259401,-0.6023318768,0.9214084148,0.4608144760,0.9237965345,-0.1325680166,-0.2890052199,-1.9986394644,-1.1460003853,0.0470660962,0.8245572448,0.5311783552,-0.1282419711,-0.2717715800,0.2171796262,0.0782111809,1.4045455456,0.1464407742,-1.4812459946,-1.2725580931,1.5187593699,-1.1711604595,0.7644974589,-0.2683727443,-0.1697582901,-0.1341327876,1.2213850021,-0.1928418279,-0.0333192833,-1.5308034420,0.2066905051,0.5310425162,0.2391455770,1.3978962898,0.0551713556,0.2989774644,1.6485040188,-1.5500141382,-0.4558253586,1.4261587858,0.9361291528,0.6783800721,0.8326507211,0.3270662129,1.6315973997,0.3777591586,0.2398671061,0.1589586735,0.1928639561,-1.1570172310,0.7706730366,-0.1304397285,1.8219151497,-0.0756504685,0.4209182858,0.2466021925,-0.6255570054,0.9921368361,1.9050636292,-0.0147772199,-0.3004787862,-0.3550287187,-1.8923618793,-0.1778131425,0.2509981096,1.0547579527,0.9600477219,-0.4164990783,-0.2768229842,1.1239053011,-0.1734638959,-0.5100295544,1.3925184011,1.0375856161,0.0187917911,-0.5937774181,-2.0118803978,0.5897036195,-0.8963696957,-1.9627319574,1.5848205090,0.6479678154,-1.1390081644,-1.2144013643,0.8709617853,-0.8779706359,1.2961498499,0.6164593101,0.5365965366,0.4046954513,0.1914508790,0.8805112243,-0.4540803730,0.0859519765,0.7519465685,0.5629897118,-1.1949868202,-0.5004096627,0.2528035045,-0.4080147147,1.7746585608,-0.3931531906,-0.1622184515,0.7694301605,0.3305327296,-0.1452744603,-0.7564935088,0.3015140593,1.0390964746,0.4790952206,-0.7781835198,1.7367749214,-1.4465779066,-1.5826855898,0.9605572224,0.2258404791,-0.5494985580,-1.0985707045,2.3207998276,0.1170908734,0.5342011452,0.3178851008,0.4348079562,0.5400944352,0.7324240208,-0.3752224147,-0.2916419804,-1.7410228252,-0.7803044319,0.2711127996,1.0450233221,0.5990395546,-0.3406923413,-1.2631728649,-2.7773592472,1.1517339945,-0.5892289877,-0.4484650195,0.1315739751,-1.4055600166,-0.3497821689,2.0234718323,0.5053869486,0.3592491448,-1.5824944973,2.2436017990,-1.4227949381,1.9223247766,-2.1150560379,1.4053654671,1.6180542707,-0.8244091272,0.4225803614,0.5474805832,-0.8137944937,-1.4491176605,-1.3177173138,0.5410082340,-0.0851156041,-0.5643010139,0.9667680264,0.5080679059,-0.7554627061,-1.2012015581,0.5232617259,-0.5375833511,0.0992048606,1.5762989521,0.5023282170,-0.8622670174,0.1606611907,-0.9526449442,1.6085221767,-0.5615787506,0.2072707415,0.3077325821,0.1592504680,-1.9585489035,-1.4464210272,-0.4523502886,0.3194318414,-0.1377792209,-0.9571474791,-1.3484243155,-0.4015575349,-0.4684760571,0.5128364563,-0.3263184726,0.6027076840,-0.5946497917,-0.2559576631,-0.3480463922,-0.7823669910,0.6251186728,-0.8135960102,-0.5216414928,-0.0731196478,-1.2973796129,-0.3249349594,-0.7113063335,-0.3881541789,-0.0599280037,-0.7999136448,-0.2200757861,1.3086687326,-0.0257985573,1.1452621222,0.3464944363,0.7741606236,-0.7744589448,0.1049071625,0.1339129210,-0.6126257181,-0.8228283525,-1.4902653694,1.4961396456,-0.9724028707,1.3462210894,-0.4674931765,-0.8624932766,0.6225191355,-0.6311919689,0.5684589148,-0.3328117728,0.4804244936,-0.9681860805,0.8313510418,0.4879726768,-0.9196506739,2.6429357529,0.5401230454,2.2904670238,1.6002677679,-0.1888347864,-0.4122717679,-0.4034591913,-1.8300285339,-0.6958351135,0.2467660308,1.5259575844,-0.7727718949,0.8820565939,-1.2525933981,-0.5863200426,-0.4576405883,0.3718110919,0.4573096335,0.9623417258,0.7708369493,0.2431682199,0.3903649449,1.5885306597,-0.5109261870,0.7747282982,-1.8081439734,0.4113342464,-0.4832495451,0.0025711823,1.0400862694,0.1646438092,0.8851875663,1.4737647772,0.3890939653,1.1710410118,-0.3265609741,-0.0082098823,-0.5226194263,1.0429775715,0.4140913486,-0.5072344542,0.1546688378,1.0415683985,-0.0392679907,-0.9489328265,0.1319117546,-1.9805655479,0.7687706351,-0.4213275909,-0.4693107307,0.8756957054,-1.3651628494,1.9470986128,-0.4802420437,-0.5232509375,1.0212247372,0.7086952925,2.4512298107,-0.2112059891,-0.1204066351,-1.4793159962,-0.3321022689,-0.7214313149,-0.4487670064,-1.7441877127,1.6606075764,-1.4166034460,-2.8022027016,-1.1884244680,-0.6038395762,-1.1495540142,1.0983035564,-0.1378391832,0.0253856052,0.6103917360,0.2860125303,0.9785673022,-1.1094775200,-0.5475180745,0.6659671664,-2.5345544815,-1.3751845360,0.5009922385,-0.4802490473,0.9361075759,0.8091803193,-1.1980929375,0.4066570997,1.2016978264,0.1474343985,-0.9774648547,0.8793899417,0.6354245543,0.5426107645,0.7159388661,-2.9946129322,0.8809375763,1.8081318140,0.4366384745,0.1927289963,0.6964386702,0.3382254839,0.6517812610,0.0014710003,-0.7667048573,-1.0043227673,-0.9981917143,-1.3730425835,-1.0677419901,1.7612661123,0.7540956736,-0.6250274181,-0.3903926909,0.1125575304,-0.6555450559,0.0675168559,0.7776041627,-0.0357427336,0.3360157311,0.8864915371,-0.2721317708,0.2847906053,-0.3093775809,-0.0285288692,-0.3247302771,-0.5288698673,0.1737118512,0.5665453076,0.1463044435,0.4987269640,-0.7379317880,-1.2037352324,0.4170435071,0.6878814101,0.0498572662,1.3480358124,0.9076988101,2.6805708408,-0.2008085102,-0.9988487959,-0.7401368022,-0.5654978156,0.4760313928,-2.1580686569,1.3185510635,-0.2392965853,-0.2467935532,-1.0793431997,-0.1142255515,0.0132397674,-0.1219449267,0.3390592635,-0.5896320343,-0.8958157897,0.5483281016,0.0986674502,0.1971810609,1.0590271950,-1.0225644112,-0.8552404642,1.2572196722,-1.4828833342,-1.3094121218,0.8178618550,0.2382001877,0.1052321345,-0.0916594118,0.0312675461,-0.0921121165,1.3554426432,-0.3981481194,-0.1613735408,1.7944488525,0.0275097024,2.2320163250,-0.1049797013,1.3674149513,-1.6553440094,0.1536444575,-1.5844736099,0.8444542885,-1.2128678560,0.2837695479,-0.2821958661,-1.1582032442,-1.6193599701,-0.5110404491,1.7406294346,-0.2934850454,0.9172215462,-0.0570428669,0.8767267466,-1.8269113302,-0.4031883180,0.9494055510,-0.1632549465,-0.0864552855,-0.4304619133,1.1493793726,0.2975143492,0.0440222770,0.6430545449,0.5882249475,0.2125870436,1.5470315218,-0.0602875352,0.2780810595,-0.6429525614,0.1501152217,1.5877615213,-0.6432576180,-1.1335928440,0.9967596531,-0.1487661451,0.0960042030,-0.0451133028,0.0791217238,0.8505306840,-0.8391242027,-1.0117740631,0.0849681348,-1.6064397097,-1.3730535507,1.8666831255,0.7574683428,-0.0100564715,1.2380069494,-1.0405992270,-0.3156031370,0.6234536171,0.8906716704,0.5129168630,-2.5412387848,-0.9680821300,0.4770680964,-0.3559514880,2.5402317047,0.9265583158,0.5580818653,-1.1169495583,-0.0352967381,0.2412039638,1.1277836561,0.8811311126,1.0329891443,-0.9239119887,1.4121516943,-1.3804306984,-0.5359145403,0.4307711422,-0.1498915851,-1.0060368776,-0.8215498328,-1.5482543707,0.5319746137,1.2605688572,-0.1003935039,-0.4003488123,-1.4723229408,0.9132019281,2.2113044262,-1.7974557877,-1.0634329319,-0.6795930266,-0.5643178821,0.2273459435,1.6142495871,1.0085972548,0.5275973678,-0.7239286900,-1.1196281910,-0.7967752814,1.5480668545,-0.0617433004,-0.4468362629,-0.1837557256,0.8246182203,-1.3128496408,1.4148740768,0.1564762592,-0.2163439840,0.4428461194,0.2183970660,-0.3441964686,-0.2527106702,-0.8688625693,0.6563907266,-0.5319938064,-0.9562584162,0.1658635288,1.3291412592,-0.0483446233,-0.6081012487,0.4038960338,1.9367125034,-1.4519054890,0.3822027743,0.2050866187,1.1615338326,0.9909091592,-0.1867091060,-1.6845172644,0.8065637946,-0.8351926804,-0.9467403889,1.1483505964,-0.9108504057,1.4028447866,0.3358447254,0.3191184103,0.3072647750,-1.6384236813,-1.7763886452,0.2155530602,0.5680073500,0.0826110318,-0.8215345144,0.0189221036,-0.0820341557,-0.9571580887,1.0139721632,-1.7302761078,0.5887424350,0.3843234181,1.0097118616,-1.0053118467,0.1014071479,2.1711649895,0.6620742679,0.1005812064,0.5391612649,0.0861768425,2.1908979416,0.9836362004,-0.0856149569,0.2523314357,-0.3907980025,1.2098500729,-1.4061048031,-1.6047384739,1.4587147236,2.1531198025,0.4683049023,0.1127379388,0.6572676897,-0.6470535398,0.1712435484,0.0389087051,0.6265642643,-1.5579985380,-0.5070347786,0.8449956179,-0.6755938530,-0.9933613539,2.0420720577,0.0381180011,-0.5789181590,-1.6923704147,0.7293463349,0.6991361380,-0.2987596095,-1.1022301912,-0.0245494228,-0.8358560801,-0.9420936108,-0.1032127514,-1.0513904095,0.2466489524,0.6079925299,-0.8396324515,-1.3682451248,1.5612796545,-0.9402702451,-0.6599426866,0.2130171657,0.5993693471,-0.2563169003,0.4607943296,-0.4009861648,-0.9711706638,1.4263168573,2.4884417057,1.6959695816,0.1418066323,1.8334354162,0.3557035029,-0.4772862792,0.4663795829,-0.0943925083,-0.9831181765,-0.8983219862,0.8020517230,-1.8465319872,0.6041367650,-1.6295835972,-2.1211764812,-1.8388465643,1.9667639732,-0.1962339580,0.0865831822,1.4192550182,0.9341797233,-1.3915052414,0.8690063357,0.1841812581,-0.3416780829,0.0242909137,1.2798119783,-0.8859664798,0.4008856714,-0.0096572367,-1.7971645594,-0.8022531867,0.1932135522,1.2973420620,1.0013309717,0.5972124934,-0.8152756691,1.8012139797,0.2152404636,-1.0063655376,-0.1829049736,0.8962484002,0.0076174983,0.8868646622,1.1036939621,0.4005306959,-0.8577026129,0.1354546696,0.0451658554,1.8593463898,-1.6263219118,-0.1348224580,-0.5840935707,0.3351056278,-2.4375643730,1.1149245501,0.0137484875,-1.8447011709,-0.3611131310,0.6089623570,-1.5914478302,0.0032222164,-1.0574736595,-0.5559850335,0.0267383829,0.1834502518,-0.4707424939,0.2727963924,0.8179776073,-0.2789142728,1.4315677881,1.4622141123,-0.4287020564,-0.6378405690,-1.6641730070,-0.1265693307,-0.3634377718,0.7790512443,-1.5096615553,-0.2773914039,0.9687443972,-0.7303571105,-0.7623615265,-1.4469403028,2.6205737591,-0.7474731803,-1.3003468513,-0.8038504124,-0.7742950916,-0.2693897784,0.8253722191,-0.2983231544,-0.9228233099,-1.4513385296,0.0218573585,0.0425390750,1.5309323072,0.0924477354,-0.0990083143,-1.0506538153,-0.3059525788,-0.4384744465,-0.3701641560,-0.9592553973,0.5383296013,-0.1424454153,-0.2003534734,-1.7140461206,0.4936440885,0.4870153368,-0.8391293883,0.9901213646,-1.3647582531,-0.0218699090,-0.2712073326,-1.3171747923,0.1897026151,1.7025702000,0.0676342323,-0.4630217552,0.4470241666,0.1057199985,0.0277621318,-0.4255422056,1.4219756126,0.4563633502,-0.5286706686,-0.1080038399,-0.7408667207,-0.6082911491,-0.6407257318,-1.1343115568,0.7772769928,-0.2910414636,0.5541275740,-0.6701259017,-0.0603624955,-0.7110406160,0.7196681499,-0.2484192997,-0.7308735847,-1.6417032480,0.2756665349,-0.7083850503,-0.0157792177,-0.4917300940,0.9541895986,0.5441447496,0.4472121000,-0.6161211133,0.4662900567,1.7148315907,-0.8321860433,0.1723391414,-1.6492170095,1.3985620737,-0.3979120851,0.7825788856,-1.7232282162,1.7975393534,-0.3568715155,0.5456573367,0.1508181989,-0.2554707825,1.6857923269,-1.6480462551,0.2987136543,0.9106456637,-0.0298561212,-0.1181707829,-0.1426877081,-1.2276364565,0.0381273851,0.5127175450,0.0685992241,-0.2722761035,-0.4897250235,-0.2792966664,1.2577441931,-2.0866348743,0.0400714576,-0.3277549148,1.4558079243,0.0554922260,1.4849256277,-2.1238899231,0.4595848918,0.2800578475,1.3905339241,-1.6413486004,-0.1550358087,0.0660602599,-0.4957954884,1.2165777683,-0.3386821747,2.0347626209,1.0541778803,0.9508336782,0.5592989922,-1.0636955500,-0.4310963452,0.5727513433,0.6775570512,1.3071838617,-0.4674410224,-0.8601533771,0.8591042161,-0.8096265793,0.8733118176,1.1997361183,0.4561530352,-0.3575790226,0.0410822257,0.5934659243,0.0101855183,2.1982963085,-0.9906709194,-1.0026686192,-0.9768953919,-0.5895799398,-2.1789314747,-0.6296504140,-0.6532847285,0.0785140246,0.4178005755,-1.2402163744,0.9000542164,1.8022422791,-0.2082851082,1.5743712187,0.1989894956,1.9887318611,1.1172834635,-1.5639046431,0.0186273698,1.0543249846,0.0305465814,-0.0368835293,1.2697647810,-0.7098541856,0.0175156128,0.3236257732,-0.3337909579,-0.0201291032,0.7750232816,0.4328376353,-0.8087175488,-1.1041239500,-0.7891021967,0.0012484558,-0.1599397808,-0.8319575191,-0.5981504321,-1.5200393200,0.4178537130,-0.0400187261,-1.2597873211,0.0286205038,1.3426220417,-0.7399358749,1.3151376247,-0.3234574795,0.1978281736,0.0977508053,1.4015234709,0.1584338397,-1.1419013739,-1.3109704256,-1.5329210758,-1.7119702101,0.0461350605,-0.9583745003,-0.0808116123,-0.7038590312,-0.7707843184,-0.4808453321,0.7035855651,0.9291451573,0.3711725473,-0.9898225665,0.6436312795,0.6888966560,0.2746472061,-0.6036204100,0.7088595629,0.4228185713,-3.1168565750,0.6444520354,-1.9137426615,0.6635615826,-0.1540724039,1.1936116219,-0.0981612131,-0.8866142631,-0.1473536640,1.0598063469,0.0262466185,-0.1143351570,0.7435535192,0.2103593647,-0.0059274058,1.3660600185,1.5551140308,0.6133262515,-0.2859591544,1.4969110489,1.1831195354,0.7188971639,-1.2160766125,0.1406719089,-0.7436721921,-0.1590122581,0.2400569320,0.1001594067,-0.4751751125,1.2729537487,-1.6961312294,0.7301835418,-1.8574832678,0.3825981319,-0.8869042993,0.8783037663,0.0864525214,0.2477063835,-1.0182793140,-0.6545701623,0.2072173953,0.5835699439,2.9290962219,0.2228583246,0.9760375023,-1.5569338799,-1.3298919201,-0.3554947674,-1.1974277496,1.4863992929,-0.4102186859,1.3821818829,1.4867824316,0.0427797213,0.5017997622,-0.0560994744,0.5384370089,0.4833418429,-0.1236496270,0.5049699545,1.7236962318,0.7130162120,0.3257996142,0.1247695237,-1.0126731396,-1.0272969007,0.3233565390,-1.3693910837,-0.7663276196,1.2815113068,1.9142297506,-1.6659560204,1.6266496181,-0.2114382982,-0.0150050875,-0.1134116277,1.0805441141,-1.6076766253,0.4561636150,-0.9448701739,0.5707885027,1.5427963734,-0.0004173264,0.3741550744,0.4095517695,-0.7995935082,1.5116393566,1.7064682245,0.7017833591,0.0732854307,-0.4618938267,-0.6264902353,1.7108365297,1.4144150019,-0.0636614859,-1.5799305439,-2.8320119381,-1.0834267139,-0.1306203902,1.4006890059,-0.6516562104,0.5048154593,1.3031809330,0.1285363138,-0.1424478740,-1.3087635040,-1.2024753094,0.4160996377,-0.2009075284,0.1225313172,-0.0472777151,0.6641440392,-0.7846873999,-0.3355806470,1.8961821795,-0.7997861505,-0.2815754414,-0.5893867016,0.4447813630,1.0223922729,-0.4982116222,-0.4314143360,-0.2789815962,0.5298337936,-0.7393953204,-0.3759599626,-2.3721938133,-1.3817449808,-0.1124437526,0.8978641629,0.2950757742,-1.0987684727,-1.4002561569,0.1746800989,-1.6528036594,1.0659267902,0.0638961941,-1.6073201895,-0.9659538865,-0.7243112922,-0.7731925249,-1.4899330139,-0.8746625185,-0.6844015718,-0.7112857699,1.1279566288,0.1048278064,-0.9932572246,-0.3346216083,-0.8795570731,-0.3000066578,0.8755091429,0.2522707880,2.2856011391,0.3759274185,-0.9135944843,0.8097407222,1.0799312592,1.0941669941,-1.0942409039,-0.1476374120,1.1318119764,-1.6847289801,-0.4994167686,-1.4269376993,-0.9325702190,-1.0124571323,1.2505698204,-0.2345380336,-0.8633555770,-1.0356057882,0.1416671723,-0.0111356275,1.3440743685,0.5000166893,-1.4317977428,-0.6289806962,1.0700725317,-0.6210827231,1.7345721722,-1.0982894897,0.5726133585,-0.8612155318,-0.5095951557,1.0985816717,-0.1270671636,0.8134522438,0.4732905924,0.7538656592,-0.8881881833,-0.2215743959,0.4242526293,-0.8490728736,1.6295000315,-0.7772280574,-0.3000035882,-1.0065590143,-2.1433081627,1.7969185114,-0.2043389380,-0.4479148388,-0.1987150609,1.4198639393,-0.9651066065,0.6795678735,-0.4237882495,-0.5966708660,0.5670582056,0.9882405996,-0.5139029622,-0.7688491344,-1.1690957546,1.1035038233,-0.5752559900,-1.8491307497,1.4099521637,-1.3698594570,0.7794605494,0.1834286451,0.2879154384,-0.5843752623,0.3655914664,-1.6677799225,0.5880377293,1.5570100546,0.8840271831,-2.0195400715,-0.9842090011,-0.1877949238,0.4869373143,-0.1066526771,-0.4932143986,0.5953003168,1.1641517878,-0.2322940081,0.7289298773,-2.5790507793,-0.9375093579,-0.3212589324,-0.4885662198,0.3327982128,1.0137505531,0.5066690445,-0.6222254634,-1.5227681398,0.5569640994,-1.8381767273,0.6530373096,-0.1884490848,-1.1758350134,0.2872573137,-0.0028761027,-0.0365972929,-0.0842233002,0.4195241034,0.9244340062,0.4966152012,1.0121332407,-0.0441397205,1.6184593439,0.5711098313,-0.5436940193,-1.0938950777,0.2057968080,-1.3065215349,-0.9733759761,0.2390870750,-0.6078874469,-0.9333162308,-0.0344750471,0.0726778954,-0.2058340311,-0.3775469065,0.8546427488,0.3424273431,-0.2234261185,2.4643218517,0.1938317418,1.1320050955,-0.5609809756,-1.3629409075,-0.7917565107,-0.2680097818,-0.4966081977,1.3363862038,-0.1200411245,0.4614688754,-0.0464811549,-0.4335543215,0.0379960127,1.7140514851,-0.7679485679,0.7669904232,-1.0260072947,-0.4596264362,0.0035832059,0.3263750970,1.4831286669,-0.0500826426,-0.8436155915,0.6500419974,-0.3641698062,0.2386815697,-0.1162224412,-1.9434568882,0.5082991719,0.5833680034,0.9266047478,1.8004627228,-1.1951037645,0.5165074468,0.4092949927,-0.4190819860,0.3971062303,0.4996469617,-1.2186838388,0.2462227643,-0.9179843068,-0.6518564820,-1.7747448683,-0.4733609259,-0.2035706788,0.5498568416,0.0008999266,-1.5422881842,0.8621480465,-0.1185866222,0.4883705974,0.9659361243,1.4226047993,1.9612269402,-0.0722387582,0.3111244440,-1.0783610344,1.0616002083,-1.1848874092,-1.8052517176,0.8303859830,-0.5216965079,0.7776072621,0.4080746472,-1.6300026178,-2.7196793556,-1.0966017246,0.0164914876,-1.2217763662,-0.6527614594,-1.4589407444,0.1698779613,0.0908259302,-0.4813926220,1.3970652819,1.4977149963,0.5652672052,-1.7997711897,-1.1046901941,0.4071303308,-0.6285575628,-0.4870914221,0.8989673853,0.5108748078,1.3141543865,-0.4292092919,1.3752254248,-0.5541312695,1.4994914532,0.1058346406,-0.8605097532,-1.6312195063,-0.3014723063,-0.2562327087,0.8576619029,-0.1105905026,-0.4324319661,1.0770374537,-0.2248265594,-0.5762417912,0.5746089220,-0.4898282290,0.6588021517,-0.5969170928,-0.2229591757,0.1521769762,-0.3741263151,-0.0134514691,0.8154719472,0.4106017947,0.4809698462,-0.6354304552,0.8528297544,0.6695623398,1.0044192076,-0.7263658047,-0.1724586040,0.6335338950,-0.6088151336,-0.2261224687,1.9258056879,1.9517610073,1.2399405241,0.9385851622,-1.0192511082,0.5125622153,-0.3591165841,-1.0585719347,-0.5090058446,0.1156650707,-0.5473555923,-0.5507994294,0.7920414805,0.1441064924,0.2334580868,0.1118723974,-0.6757031679,-1.3705719709,0.3105646968,-0.5070366263,-2.0107822418,-0.3925672472,-1.0922179222,0.6986502409,0.5216252208,0.4968931377,-0.6650416255,0.7315515876,0.3196497858,-0.4098545313,-0.4533374310,0.8927081823,-0.4736040533,0.3036564589,1.0339570045,1.9093426466,1.6638730764,0.9008227587,-1.5059113503,-0.6890484095,-0.5480871797,1.6531498432,-0.6993179321,0.3861663640,0.1008670628,-0.9351271987,0.3818240166,0.3982960880,-1.2557748556,1.2228775024,-2.0865099430,-0.5907571316,0.9719703197,-1.1932578087,0.3502659202,-1.2963603735,-0.0930241421,-2.3137731552,-0.8425716758,-1.5429214239,-0.4017637372,-0.4152314067,-0.6736641526,0.7979131937,-0.8868796229,0.6343866587,1.6292757988,0.1390641481,-0.8576701880,-1.2493385077,-0.7097851038,0.7046427131,0.1555907279,0.9367952347,0.7703309059,0.1408106536,0.4734882712,1.8552461863,1.4156562090,-0.3027460277,0.9896794558,0.5858508348,1.1363880634,0.6716165543,-0.9741674066,-1.6196845770,0.5726270080,1.9026181698,-0.7756640911,-0.1880897433,-1.0357477665,1.1778295040,-2.3051669598,-2.2636601925,0.3750199080,-0.0823436454,-0.4796230197,-0.3010948002,0.5369879007,-0.4138039947,-1.0969250202,-0.9273629189,0.8883388638,-0.5247419477,-1.3852776289,0.1021783277,0.5049947500,1.3289607763,0.2179033905,-0.6597112417,0.4740078747,0.7271748781,-0.0389053077,-0.0445993915,0.2601329088,-0.0698564947,0.2501139045,-1.0219132900,-1.1504377127,-0.8361113667,0.6422109604,0.2587975562,1.0402389765,-0.1866909266,-1.1436413527,1.1445535421,-0.0187670551,1.2834550142,0.5979464650,2.1886186600,-0.2197729796,0.9007239342,0.8913640976,-0.5551263690,-0.1724823117,-1.4617383480,-1.5487961769,0.1265687943,0.7930070758,0.6380240321,0.3400245905,0.8630171418,-0.5896977782,-0.2725327611,0.7375215292,0.4331187308,-0.2101888210,1.3207943439,-1.2920012474,-0.5186786652,-0.2833977640,0.8165348768,0.0023851979,-1.2614917755,0.5140041709,1.0875463486,0.7393045425,0.6191549301,-1.8743134737,-0.8998864889,0.4820806086,-0.0548881851,0.5225576162,-1.2663426399,-0.0614947639,-1.3897809982,-1.9536786079,0.2957790792,0.8425887823,0.2456164211,-0.0329964794,-1.5620143414,1.0061070919,-0.0440448970,1.9595620632,0.9423143268,-2.0051255226,0.7550497055,-1.3965352774,-0.7594954967,-0.2507566810,-0.0940624475,0.3975652158,-1.0228550434,-1.1506919861,0.6006051898,-0.0132502681,0.1743730456,-2.1936833858,-0.1771373898,-0.8907291889,-0.9206264019,0.9219347835,-1.0956711769,-1.0928965807,-0.3310106099,0.4502888322,-0.8840147257,1.2341440916,1.4498475790,-0.8814470768,-0.2450817525,-0.7786754966,-1.6853821278,0.3030110598,0.7335948944,2.0118641853,-0.8974094987,1.3362350464,1.3423537016,0.1978533119,0.6021634936,0.8732730746,1.9740999937,0.4778085649,-0.0601378866,-0.8661687970,0.3053207695,1.0241649151,0.2446103543,-0.7799232602,0.0890762061,-0.1291534752,0.2647387683,-1.6618484259,0.5507886410,0.5954231620,0.4448534250,-0.0037628172,-1.8059362173,-0.0193227921,1.0607149601,-0.8601288795,-1.9892694950,-1.5405579805,0.3140257001,0.3728760183,0.8862931728,-0.0552589968,-1.5003284216,-0.8185041547,0.8188393712,0.1404959112,0.6498296261,0.4347887933,-0.2049605548,-0.1740068346,1.8571022749,0.4146742523,-0.1285875440,0.4554199874,0.2229058146,-2.1573562622,0.6500844955,1.8209393024,-0.7802798748,1.4540357590,-0.2568697035,0.2934713960,1.0703600645,-0.7200014591,1.2424938679,-1.2142173052,-0.8751547337,-0.5935203433,0.6620053649,-0.3408744037,-1.5199744701,-0.2165328711,-0.7842214108,0.7312936187,-0.3432350457,0.0707740784,-0.4054724574,0.4339389801,-0.1835907698,0.3251987100,-2.5933885574,0.0972508788,0.4139136672,-0.1992800534,0.6693924665,0.7386070490,1.3042138815,0.1048116088,-1.9138007164,-2.2854993343,-1.6018409729,-0.0379070602,-0.1573052853,0.2762398422,-0.6252459288,-0.7364911437,0.5550479293,0.6559244394,-0.2566501498,-0.0384766571,0.4043143392,0.5043435693,-1.1439807415,-0.7195738554,-1.2305459976,-0.5069066286,0.8123335838,0.5462718606,-1.0980979204,0.5122667551,0.0858431086,-0.4939267039,-1.4064596891,-0.1748233736,0.6799439788,-2.1630976200,-0.3961232007,2.2542836666,0.6726367474,0.2598325014,-0.7371851802,-0.6783298254,-0.0832883939,1.6028636694,0.4655891955,-0.8721584082,1.1767870188,-0.2925941944,1.6973464489,-0.5666030049,-1.0032657385,0.1746295840,0.9823269844,1.0374448299,0.1591917723,-0.9880967140,-0.5053406954,-2.0182819366,-0.9131215215,-0.1784568131,0.3890021443,-0.3394543231,-0.0569790564,-0.3961854577,0.7510253191,-0.8991129398,0.8375478983,1.9608807564,0.4727896452,-0.5270916224,-0.5362701416,1.2098371983,-1.1265894175,-0.9538044333,-1.1644484997,-1.2785137892,-1.0448163748,0.7899049520,1.1022825241,-0.6970731020,0.2073340416,0.7591567039,0.1005642042,-0.9549427629,-1.4704017639,1.0104275942,0.4961794019,0.5769559145,-1.1076469421,0.2349771857,0.6289995909,0.3140338361,-0.7450231910,1.0122605562,-1.5276319981,0.9287419319,1.0810559988,1.5723303556,-0.3424921930,-0.9994300008,0.7938803434,-0.6992152929,0.0439955108,-0.3174622059,-0.9020719528,0.3209994733,-1.3920159340,0.5922057033,-0.9669311047,-1.7317312956,-0.0501074605,0.4316338599,0.5769345760,0.8183537126,-2.3536403179,-1.0051444769,0.1066522971,1.5190032721,0.7837445140,1.9013400078,-0.5249394178,0.2744169831,-1.0999708176,-0.4043522179,-0.7352957129,-0.6339886785,-0.3934491277,0.0027175399,0.0222126637,0.5434534550,0.1399884671,-0.3440456390,-0.5225785375,-0.3071317077,-0.4490371346,0.4909710586,0.8655251861,1.2740445137,-0.7977027893,0.4693722129,-1.3946796656,0.3731747270,1.0826722383,-0.1495895088,1.0726360083,-1.1385679245,-0.8886452913,-0.1358098388,1.0222103596,-0.4174294472,-0.4535531104,-0.9916283488,0.2028810382,1.2466951609,0.7006801367,0.6966506839,-0.2069744766,-0.5633093715,0.6772459149,-0.0319110751,-0.1736082286,0.8982406259,-0.1977874488,-0.8377762437,0.9091885090,0.0807198882,-1.0370293856,-1.1129058599,0.0954118744,2.3374097347,-0.3928205967,-0.3362738490,1.5237711668,-0.0572811998,-1.4484668970,-1.5727964640,1.2266639471,0.6663545370,0.8261256814,-0.0577565581,-0.7267120481,-0.2171631157,0.1360312104,-0.8383111358,0.5614498854,-1.2595961094,-0.3327587545,-0.2040078789,-0.6910198331,-2.2055053711,0.4478696585,-0.7557507753,1.3257079124,-0.3419822752,-0.5413596034,0.0915219486,1.0534397364,-0.5634076595,1.0147377253,1.4403036833,0.9903228283,1.6264314651,1.2926460505,1.5148823261,1.6043263674,0.2080695331,-0.4292238951,-2.2622437477,-1.3227331638,-0.4482828081,-0.3817350864,-0.1527944654,-1.0007604361,-1.5957776308,-0.1302231699,-0.1894179285,-0.8075540662,-0.7421521544,-0.9401565790,-0.3965237439,-0.8563027978,1.2598752975,0.2409967333,-0.9723179340,-0.2804477811,-1.1802855730,1.0121682882,1.3841867447,1.2520020008,-1.1446926594,-0.0912670195,-0.4015706778,0.5620130897,-1.0079097748,-0.6758916974,-0.4132170379,0.1532884687,0.6941286922,-0.3287276924,0.6639650464,0.8220763803,-0.2132152319,-1.2456581593,-1.1711903811,0.5917269588,-0.4762244225,-1.7126293182,0.6129523516,0.1295545250,-1.4059671164,1.1794199944,0.8366360068,0.1387452483,-1.2743194103,-1.4023305178,-0.3070684969,-1.7139153481,0.4050802588,-1.4108233452,0.1649127305,-0.2881314456,0.7117852569,-0.9379475713,0.2737294436,-1.3948402405,0.7955495715,-0.1149617657,0.4958506823,-1.3205252886,0.4990842640,0.3062033951,0.3636978865,0.3126339614,-0.1934638768,1.2412992716,-0.1558979899,-0.7391691804,-0.0587261915,-0.9505179524,-0.4639964104,-0.1772466153,-0.3795541227,0.1993970722,1.9457614422,0.5709498525,1.0723006725,-0.5037094355,-0.5870162845,-0.3781780601,0.8528891206,-2.1481184959,-1.0331647396,0.1023358479,-0.2240923643,1.9677296877,0.4476832151,-0.6621914506,-1.5776070356,-0.3405600488,-1.3032200336,0.4667506516,0.1611063182,0.3200319409,2.0791766644,-0.9074659944,-0.1924042106,-1.2125157118,-0.0805985183,1.5932736397,0.5687224269,-0.1144870445,0.2516302466,-1.2108556032,-0.3937337101,0.0852525756,0.0994219854,-1.5306162834,0.3276231885,0.2791965008,-0.3770512044,0.0041749990,-1.4834915400,-1.4797955751,0.1346872598,-0.6677231789,-0.0115555199,0.8394906521,-0.1739299297,-2.8106679916,-0.1506536454,-0.4810440242,-0.2346943617,0.8997308016,-1.5785301924,0.2439566255,1.5703039169,-0.6259431243,0.4723278880,0.9663057923,0.2102314383,-0.6850969791,-0.7095209956,0.7438001633,0.5921490788,-0.7864683867,-1.1764731407,-1.2808066607,1.6616518497,-0.0679451227,2.3602285385,0.5555456281,0.4395223260,0.3062724769,0.9991498590,-0.9660632014,2.1600131989,-0.1003017053,-0.7034000754,0.3025610149,1.0923389196,-1.0075548887,0.5668693781,-0.7164441347,-0.5062735081,-0.4894824326,0.7635414600,-1.1090726852,0.1926161051,-0.3434178531,-0.8472101688,-1.2135236263,-1.2028883696,-1.6337959766,0.8961672187,-0.2416531593,0.1586519331,1.1781893969,-1.2201172113,-0.9415456653,0.2547155321,-1.8240795135,-0.5787085295,-0.9248930812,0.3295224309,-0.4258158803,2.0081493855,0.9378913641,-0.8532384634,-0.3873134255,-0.3475845158,3.3065743446,-1.5101996660,0.2035396993,-2.0844321251,-0.0069374414,1.9098905325,-0.4084554315,1.1045544147,-0.0661152229,-0.4224987030,-0.2516563535,-0.5869026184,-0.6260582805,-1.3301943541,1.5068007708,-0.3930763900,0.2937743068,-0.8765318394,1.1169905663,-0.2735557854,-0.0910326689,-1.8289766312,0.3959762156,1.8115056753,-0.8690775633,-0.4582291543,-1.1383239031,0.1291621774,0.0640241951,0.7050811052,0.5514735579,-0.8125160336,0.2249480486,-0.3283011019,-1.0910329819,-0.1268558800,3.8016602993,2.3151705265,0.1398265958,1.7388571501,-0.0453833640,-0.0531383380,-1.9495717287,-0.9601055384,-0.7834992409,0.1075190306,0.0139845349,-0.5789423585,-0.5888131857,-0.1661531329,-1.3814116716,-0.6126385331,-0.3812898695,-1.2489489317,-0.3302378953,-0.8348071575,1.2353824377,-0.2438037992,-0.1895456612,0.4280281067,0.5569683313,-1.7362418175,-0.3767841160,-0.9090323448,-0.1451702416,-0.5363325477,0.1570694596,-0.9804592729,-0.5677672625,-0.5911596417,1.0825914145,0.3680036664,0.3688887060,-0.2863182724,-0.3847178519,0.5610029101,0.7774339318,0.0151467854,1.1416479349,1.2741550207,-1.6646980047,0.4303788841,-0.0426019281,0.3882888258,1.1159765720,-0.9205381870,-1.6202740669,1.1061915159,-0.9984846711,-0.6862195134,0.2046208978,-0.6861017942,-1.5922106504,0.0341897681,-0.7814846635,0.5978598595,-0.5060765743,-0.6884461641,-0.2100005448,1.0521534681,0.9079040885,-1.0932261944,2.7997076511,-0.3257763386,-1.1524157524,0.8882319927,-0.3616724610,2.1537194252,0.8474083543,-0.1987198442,1.5753068924,0.8491151929,-1.2288951874,0.8883941174,-0.5164874196,-0.0833262876,0.1310544461,-0.8790960312,-1.3333423138,0.3677840233,-1.3882335424,-2.5752027035,-0.8361055851,0.3310924172,-0.2698811293,1.2671309710,0.1837534904,-0.7663096786,-0.4395835400,-1.4365413189,1.0857971907,-1.3811000586,-0.9204076529,-0.1602862179,0.0023532645,-1.5026503801,-0.9055358171,0.2650406063,1.1297233105,0.3490035534,-0.0258097611,-1.5624086857,-0.6173423529,0.5214942694,1.0809466839,0.8893759251,0.1380716413,1.2046004534,2.8814606667,-0.5938619375,-0.7631158233,1.5184829235,0.2354645282,0.1123076901,0.3923743367,-0.6544864774,-1.0347952843,-0.7771475315,1.2459462881,-1.4366406202,0.4986546338,-0.5576874614,-0.3533668816,0.7429509759,0.8439888954,0.3429765403,-1.8731197119,1.5709646940,1.3101965189,0.0914368331,0.0102578169,1.8014491796,0.9472242594,-0.0292944033,-0.2923386693,-0.1935371161,1.1772320271,1.0399917364,-1.6134229898,0.4646424055,0.8641213179,-1.5064631701,-0.0029647513,-1.7770435810,0.1294928342,-2.0832345486,-0.6817455292,-0.6110659242,-0.7088498473,1.4515280724,0.5355105400,-0.3995688558,-0.9330778122,-0.2387763113,-1.0291129351,0.9730799794,1.9967659712,1.0531998873,0.3316903412,-0.1656287760,-0.4051062763,1.7452845573,-0.5759356022,1.5610985756,-1.1315392256,-0.2962316573,-1.7140566111,0.1592341959,-1.2637276649,1.6650494337,0.4122722745,0.5373967290,0.2826784551,-1.0925408602,0.1241182908,1.8370807171,0.0085549261,-1.0170161724,-1.8523426056,-0.7133269906,-1.7622288465,0.8305173516,0.7811672688,-0.8756818175,0.6139813066,-0.5764546394,-0.0456142835,0.3719555438,-0.4439600110,0.4182033539,-1.6857280731,0.1174749881,-0.0349520221,-2.0463931561,-1.8096902370,-1.8595236540,0.4143068194,0.1239596233,0.2739575803,-1.3263784647,1.1389738321,0.9828411937,-0.7669630647,1.1760603189,-0.2509224117,-1.7762050629,-1.6326947212,0.7337234616,-0.1040488109,0.8812249303,-0.0883731246,0.2676708996,2.1235263348,1.3968490362,-0.4328272641,0.3749687374,0.4944454432,0.7613911629,0.0710088089,-0.4935318530,-0.0036228173,-0.4802871048,1.6833672523,1.2407262325,-0.2036150247,0.4282922745,-0.1654592603,1.1932411194,1.0488804579,0.5686108470,0.8712642789,0.6605708003,1.1740618944,0.5311313868,0.1519005299,-0.5772256255,-1.5717507601,-0.0278483797,-0.7410555482,0.0600090660,1.1404883862,0.1728246808,-0.4150016606,-0.8531286120,-1.4301352501,1.3328052759,-1.7766909599,-0.9347830415,-2.3132019043,-0.3161415756,-0.3422845602,-0.4042944312,-0.0631299019,-0.8212651014,-0.9136556387,1.8178263903,-0.3340629339,0.9076586366,-0.8367710710,1.6127285957,1.5141820908,0.2310186774,-1.0995316505,0.0870013833,0.0473044999,0.2396239191,-0.9782206416,-1.5230001211,0.1623630375,-0.0102913165,0.0020750219,1.0268006325,-1.4751604795,1.0106936693,-0.7432275414,-0.3952220678,-0.8257793784,0.0896198601,-1.9058178663,-0.5680857301,-0.5157565475,1.2639302015,0.1506981403,0.6955183148,0.0059388145,-1.0489003658,0.9072048664,-0.8454413414,-0.5262433290,0.1820997745,0.9455388188,-0.2013845444,1.5105247498,-0.5714784265,0.6655892730,0.0036163009,1.5466718674,0.2144060135,-1.8773127794,1.0883351564,-0.0815485120,-0.5530619025,1.2229647636,-0.3313086331,0.5999867320,-0.7683833241,-0.8361301422,1.8105818033,-0.7870327234,-0.5847709179,-1.7083207369,1.6299822330,0.3979983330,0.2377796322,0.9751384258,-1.3293365240,-0.5410467982,-0.0914377347,-1.5484710932,1.3114271164,-0.0184290502,-0.3232886493,0.2362254858,-0.7525823116,0.0451130047,3.4275386333,0.6046820283,1.6683111191,-0.3550831079,-0.7515689731,0.3097035885,-1.3417049646,-2.3069577217,0.7315924764,0.6413381696,0.8338512182,0.0281698741,1.9783726931,-0.0873281881,-0.5539647341,-3.0064988136,-0.0471658669,0.8318777680,0.0068611987,1.1242216825,2.2948811054,-0.1733502150,1.2312535048,-1.5858526230,1.0313191414,0.0634904802,-0.2213905007,-0.1633989215,-0.1563034654,-0.3088029027,0.1986729652,-0.1742921323,-1.1557924747,0.4170538783,-0.6078679562,1.0479866266,-0.0338269658,0.1270239502,-2.0492320061,-1.2566801310,0.9396144152,-0.7338167429,-0.5324376822,-0.2779399753,1.3637425900,0.3741379976,1.3102645874,-0.2677477896,0.2131762654,-1.2032434940,1.1780312061,0.1086482033,0.0441290997,0.3383155465,1.4467921257,-0.2144951075,1.6630389690,-0.8515225649,0.4221846163,2.0092184544,-0.4898147285,0.2452558577,0.8775050640,-0.1378996968,-1.5003532171,-1.0559593439,0.5809326172,0.8915153146,0.7845553160,1.1464320421,0.0719851926,0.2082331777,-1.5188686848,0.3173289597,0.6126807928,-0.5832113028,0.6440017223,-1.8158888817,0.7510995865,0.3002843261,2.1106085777,1.4130855799,1.5069802999,0.8173971176,0.6466156244,-1.1816313267,-0.3350912929,1.8267284632,-1.4561644793,-0.4502818286,-1.4192340374,1.4509518147,-0.5657813549,1.5445343256,-0.4137624800,-0.5041320920,1.2785291672,0.9388317466,-2.7162802219,0.4511407912,0.6001668572,0.2098069340,-0.6576579809,0.0284084454,-0.3980614841,0.2113230228,-0.2023942620,-0.6219281554,0.1637704521,0.8024389148,0.2890059054,-0.5536423922,0.3362540305,1.0697923899,1.5954041481,1.2075525522,0.5373802185,-1.0091240406,-1.3655527830,-0.2023812085,-1.4091848135,-0.7847847342,-0.1701223105,-0.4842104316,-0.3279180527,-1.3280045986,0.2314667553,0.9965080619,-0.5481374860,0.7257553339,2.6627266407,-0.0918110311,0.6512100101,0.1967700869,0.9696237445,-1.7186498642,-1.0569567680,0.1434639245,0.8869625926,0.1305240244,-1.6645731926,-0.8236132860,-0.7947061062,0.3889919519,-0.7620389462,-0.6808071136,1.0847475529,1.3353163004,-0.4132747948,0.4249026775,-1.8814837933,0.1983270645,1.1899780035,0.5267816782,0.1010608450,-0.3886429667,-0.6467919946,-0.1790824085,-1.5514411926,1.6104589701,0.5642106533,-0.1024370342,-0.6198047996,-0.0703396201,0.7977949381,1.0114479065,-0.9036909342,-0.9735287428,2.0782299042,1.1365928650,0.7085199356,-0.1386462450,0.9240203500,-1.2732331753,1.5317684412,-0.0357722230,0.7908614874,0.6462177634,-0.1315709054,-0.1753663570,1.2215831280,1.0264973640,-1.7722311020,-1.6924057007,-0.9462206364,-0.8935453892,-1.1185258627,0.2721106410,-0.4637044370,1.2061246634,1.4528777599,-0.0286832377,1.6834579706,0.0242143106,-0.4347906411,0.0647857413,0.9448599815,-1.6144609451,-0.2085993290,0.2974056602,0.3630846739,-0.3684363365,0.4887857437,0.2921216190,-0.5919080973,2.1815986633,0.4395501912,-0.3311833441,-0.5717190504,1.0294089317,0.1020597890,2.5481126308,-0.4359241128,-1.2426069975,-0.0276984591,0.1750674546,-2.1184506416,-0.3091685176,-0.3684154451,-0.3687635362,-0.6302257180,-1.3431925774,0.7580380440,-0.5838408470,-1.0237014294,-0.7599342465,-0.4723232388,0.1086471230,0.6683390141,-0.9531794786,-0.4792973995,-1.3455077410,-3.3922998905,0.1557939351,1.5200035572,0.5220832825,-0.5070599318,0.0964791402,-1.1748200655,-0.1222923547,-0.4277092516,-0.8527142406,0.4056522250,2.5998671055,1.6654495001,-0.0720730200,0.8841146827,0.8627074361,-0.6475380063,0.6439040899,-1.4409921169,-0.8052983880,0.2387528718,-0.4147876501,1.7564786673,0.6480404139,-0.3820381165,-0.4705797136,0.1869706064,-1.0555312634,0.5956119299,-1.3753019571,0.6230102181,-0.1645947248,0.4146135151,-1.0125858784,0.2449852079,2.4123477936,-0.4572167397,0.3173998594,1.5055669546,0.7617041469,0.4318854809,-1.0136892796,-1.2775883675,0.0534324422,-0.4632358551,-0.0190582145,0.2056566775,-0.6764278412,0.4941030145,1.8585561514,-1.0093410015,-0.4695463479,-0.0496106595,1.1404596567,-1.1863820553,-1.0651481152,-2.1636610031,-0.4403622150,0.6801457405,1.0652247667,0.3571536541,-0.6009569764,0.7064716220,0.2043185979,-1.9207055569,-1.2280948162,1.5118652582,0.3222050965,-1.3747943640,0.8199530840,1.0614349842,-0.4350340366,0.6576821208,-3.7401006222,0.9735767841,1.1751554012,-1.1247026920,0.2820853889,-0.3381205499,-0.1025294811,-0.4248804450,-1.3322954178,1.8904037476,-0.3103108406,0.1047550440,-1.0094006062,-1.0368671417,0.4125984013,0.5263921022,0.8779241443,1.1037739515,-0.2102075368,-0.4442030787,0.7468138337,-0.6374391913,0.8717585206,0.3745002747,1.1550264359,0.6703916788,-1.0544458628,-0.8656336665,0.7324852943,1.9070558548,-1.3228117228,0.0232116040,0.2816745639,-1.5257774591,0.4781250060,-0.0931227952,-2.0965573788,1.6217279434,-0.8632082343,-1.2825033665,0.4201416075,0.5574867725,0.7364113927,-0.3860033751,-0.0109143378,-0.7308067679,-1.3101973534,1.0791306496,-0.1027626842,-0.1823142618,-1.9992675781,-0.1783711016,-0.8424944878,-0.1746136546,-0.2192441523,-0.4464647770,0.9388386607,0.4470541477,1.1271544695,-1.3248273134,-0.6489559412,-0.0402808189,-0.4066389799,-0.0792577267,-1.1821033955,-0.7161780596,-1.6415539980,-0.8900255561,0.6941767335,-0.2142068893,1.5057532787,-0.5955338478,0.1190710813,-1.2132523060,2.6006717682,-0.1786205918,0.8296298385,0.4133850336,-0.5838788152,-1.3309012651,0.1561431289,-0.5567897558,-0.1555043012,0.6513020396,0.0782411546,0.3771162927,0.1500465721,-1.4672492743,1.3960622549,1.1758522987,-1.1361649036,0.5053006411,-0.6620242596,-0.7469163537,-0.0048416615,1.7476682663,1.0579575300,0.6052213311,-1.1506056786,2.5544493198,0.8737310171,-2.3488373756,0.3994743228,-0.4886947274,0.4099823534,0.4006403685,-0.9185190797,1.8258857727,0.1997846216,0.9413478971,1.3514236212,-0.7381575704,-0.9117684960,1.1219073534,1.3928374052,-1.3770185709,2.0112431049,-0.2355033159,0.6917845011,0.5643882155,-0.9713423252,-0.8640481234,-2.0835924149,-1.1511501074,-1.4824759960,0.0401905142,1.3694021702,-0.0271449313,0.3388541639,0.7780035138,0.6797094345,-0.3858315051,-1.4633450508,-0.4298055172,0.0629593581,-0.8716452122,0.3619607091,-0.2927120924,0.6218215227,-0.8032394648,-0.9219676852,1.7740563154,0.0287562385,0.5529638529,-1.0984222889,-0.3772644699,0.6821694970,1.5656158924,-0.7244850993,-0.8029174209,-0.0226689409,-1.5243951082,-0.0301333070,-0.0647283867,0.7247491479,1.4146097898,0.5698443055,0.7415510416,0.0522789508,-0.3597445786,-1.9959769249,-0.8862208128,0.2172666788,-1.6455937624,0.2428898215,-0.4008347094,-1.0215598345,-0.4700243175,0.7287815213,0.8855010867,-1.9370213747,-0.1494840086,0.9138846397,-0.2578948736,0.1088152677,-1.4954109192,-0.4800336659,1.8287754059,-0.7880680561,-1.4406323433,0.1494717598,0.7886293530,1.1938104630,-0.5177226663,0.2224755734,0.5443548560,0.6492105126,-0.5472027659,1.7127249241,-0.6872970462,0.7078721523,-0.0219112355,-0.5872185826,-0.6428512931,-0.5863469243,-0.4468710721,-1.0188856125,0.6974096894,-0.7035152912,-0.6150208712,0.4886905849,-0.1079619452,-1.4219036102,-0.9360095263,-0.1965572387,-0.5749878287,0.7504825592,-0.7644020319,-0.9671270847,-1.0105462074,0.4066572487,0.4834717214,-1.6724445820,0.6220752001,0.8609732985,-1.6909977198,-0.6904314160,1.4288923740,1.0061017275,0.0247926600,0.5012493730,2.1120195389,0.5027969480,-1.2208088636,1.3649389744,-0.8709388971,0.9939022064,0.6562706828,0.8895135522,1.5409330130,-1.4659143686,-0.0695885569,1.9460494518,0.9763817191,0.1771583408,-1.0231730938,0.1067204922,-0.9118813276,-1.4683669806,0.5764787197,0.0653056055,-0.7735127807,0.3949481845,-0.5038898587,1.7795591354,-0.0305724442,1.5770882368,-0.8128020763,0.6133491397,1.8436999321,0.2710909843,1.1364476681,-1.7383319139,0.7071347237,0.0303861313,0.7650019526,0.8676652312,-2.2562501431,-0.4436027408,-0.6700232625,0.1521641910,-1.9405333996,-1.0905086994,1.0019207001,0.1768924445,-1.0880144835,-0.2532173693,1.0982730389,-1.8395668268,-0.2114286125,-0.2296632379,0.1869794130,0.5037794709,1.9103424549,0.5537812114,-0.5874814391,1.2579499483,-0.8586683869,0.4361870885,1.5714631081,1.0773148537,0.8110896945,-2.2315375805,-0.1010025144,-0.5873750448,1.3248683214,0.8406484723,0.2611061931,0.7944416404,-0.6496164799,0.6342844963,0.0950026661,-1.6832067966,0.3440461457,0.7071580291,1.1934145689,0.5273885131,1.0067039728,-1.7323273420,-0.3734121621,-0.1425103992,-0.3297423720,-0.0890421197,-0.5773962736,0.7361654639,-0.9912055731,0.1251746118,0.0731527135,0.1439372301,-0.9477243423,1.3992298841,-0.2261237204,-1.4388542175,0.8013010025,-0.0033314459,-0.0969415605,-0.0958714485,0.3954369724,-0.0532430410,-0.7734996080,-1.4191855192,0.3034519255,-1.5182067156,1.1197077036,-0.9538609385,-0.8496140242,-0.9818996787,-1.3630776405,-0.7725985646,-0.2836254537,-2.3276040554,-2.4452273846,-0.7158649564,0.8833968639,-1.3004398346,-0.0763390809,1.4305567741,-1.3234086037,-0.4383561611,-0.7431524992,0.8919675946,0.4638727605,0.6176608205,2.4964170456,1.6294752359,-0.0990447029,-0.2019919604,-1.4488258362,-1.7141647339,-0.0496415719,-1.2993954420,0.6253554225,-0.7917193174,-0.5829433799,-1.5526804924,2.1101534367,0.7588295341,-0.7099302411,0.1511470377,1.3230912685,-0.9278250933,1.9065986872,-1.0321749449,-0.1773614883,-1.6503783464,-2.5385110378,1.0100908279,0.0857020915,-1.7338609695,-1.6406011581,1.1453614235,-0.1505951136,1.4314432144,0.6365867853,-0.0665628463,0.0323299803,-0.5550736189,0.0977861062,-0.0609849803,0.8375166655,-0.1634184420,0.8235554695,0.9206323028,0.1807626039,-1.3129683733,-0.1604766995,-1.9060746431,-1.2066216469,0.7304183245,0.4948927760,-0.0032088785,-0.3024331629,-0.7394009233,-0.5128120780,0.9652515054,0.4766792655,-1.3712165356,0.1988528371,0.1399628371,1.6486734152,-1.7575517893,-0.7831295133,0.9736258388,-1.1109322309,2.3856215477,-1.1789442301,0.0291221458,0.5595475435,0.8810371161,0.7152084708,-0.4620775282,0.9132069945,-0.7546525002,-0.5349771380,0.4566424489,1.5095769167,-0.2281712443,-0.8903415203,1.2097718716,-1.2648000717,1.8381814957,-0.9840826988,0.6409484744,0.9266912341,0.7850340605,0.2270026356,0.0495295525,-1.6531804800,-0.7808196545,0.7246446609,0.6633691788,-1.0378812551,0.3469790220,0.2520309985,1.7509188652,-0.4184011519,-0.5198572874,-0.9234429598,-0.9992784858,0.3749483526,-0.7043411136,1.0747038126,-0.6272990704,1.5339956284,0.4177254438,0.2583836317,-1.1504285336,0.3291141987,0.0455219783,0.6320825815,-0.5108472705,-1.4536298513,0.2752215862,0.1397872418,0.2438923568,1.0056501627,-0.9396406412,-2.3817501068,0.4750269949,0.4059125185,-0.4770562947,0.1705982089,-1.0477807522,-2.1061971188,-1.6929115057,0.0423611403,1.3827104568,-0.3895183802,0.8139379025,-0.5943319798,-0.0554390214,0.7965607047,0.1331798881,-0.5416783690,-0.8653023839,-0.0925281271,1.1821020842,-1.5706546307,0.8593307734,0.2836470008,-0.9691122770,-0.0183737297,-0.2040354460,-0.9477403760,-0.5394350886,-1.2562873363,-2.0715236664,0.1512364447,1.0444895029,1.6333490610,-1.1113785505,2.1473650932,1.5263067484,1.4234750271,-0.7856664062,-0.5622516274,-1.9383574724,0.1911592335,-0.3936029375,0.1617906839,-0.8345180154,0.6728704572,0.3431881070,-1.1441230774,-0.0458879471,0.2846845090,2.0084414482,0.0957808495,-0.9404090047,-0.3162630498,-0.0312234666,-0.1335952878,-1.8414719105,-0.3315768838,-0.6933088899,-0.2605129480,2.1209623814,-0.8322905898,1.4379409552,1.1606181860,0.6834978461,0.0031104183,0.6543934345,-0.4499197900,-0.5464591384,-0.7478616834,0.2739015818,-0.2097705752,-0.2395850718,1.4202288389,-0.7047485113,0.7353649139,-0.5219275951,-1.5921950340,-1.4259504080,-0.4915523827,0.6296114922,0.6417863965,-0.2406871468,0.6184217334,0.0762631074,-0.2614903152,0.8547312617,1.1878938675,1.0160274506,-0.3068729639,0.5677075982,-2.1292457581,0.1950669289,0.3610023558,0.1519751996,-0.2222727239,1.3047732115,-0.0932376981,-0.1395379305,-0.2409367412,1.0341054201,-0.2924596369,-0.8343493938,-0.1087585390,1.7077137232,-0.3006861210,0.6157716513,-0.2781107426,-0.2767468095,-0.5608413815,-1.2163040638,-0.1097816303,0.7184557319,1.5761929750,0.4418694973,-0.8168610930,0.7455046177,0.4540291727,1.3983632326,2.0896103382,1.2146077156,-0.3927581906,-0.1592295468,1.1579405069,-0.5076931119,-0.1404834688,0.6343402267,1.0706061125,0.2229107618,-2.8925197124,0.3393659592,-0.3120492101,-0.9759209752,0.0241301656,1.1204642057,-1.1298772097,1.5899230242,0.9787300825,0.9341636300,-0.8147085905,-0.2512424588,-0.3828348815,0.0003409579,-0.0622048005,-0.3173488677,-0.1779273450,-0.2116203159,0.2674838603,-1.6518170834,0.4865783453,1.6972717047,1.0725008249,-0.9458972216,1.0446079969,2.2896277905,-0.2425562590,0.7210319042,2.2993803024,1.0302956104,1.5507205725,-1.0952255726,0.2356208563,0.3919691145,0.5642871261,0.7895075679,0.1561750621,-1.3123941422,1.0662723780,0.3788603246,-1.1786166430,0.7589958310,0.5529800057,0.5370345712,-0.2868351936,1.6344056129,0.5712266564,-0.7899540663,-1.5427579880,-0.7673321962,-2.3696231842,-0.2605598569,0.1289570481,-1.2076663971,-0.5454435945,1.5532826185,0.1072913334,1.5353435278,-0.1849514097,-0.1767827123,-2.1992540359,0.7292887568,1.1005582809,-0.3423680365,-0.3103042245,0.8130363822,-0.7362970710,-0.7823243141,0.3170981705,-0.6062513590,0.6110578775,-0.9203095436,1.5095089674,0.6564636827,0.0658511817,-0.8736306429,-1.0577539206,-0.8972370028,-1.4322032928,1.3404302597,0.3420748413,1.0706282854,1.7390650511,1.3066060543,0.4496167898,-0.4110504389,0.7492995262,0.2111377716,-0.2606511414,-0.5151983500,1.0792167187,1.4774627686,-0.2751087248,-0.4370077252,0.6981697679,-0.6351764202,0.6036766768,1.7369296551,-0.4178344309,0.0245132316,1.9896930456,-0.3731683195,0.1410367340,-0.9418154955,-0.7028346062,-1.3788369894,2.9252495766,0.5717520118,-0.0458755493,-1.0570642948,-1.8246930838,0.2417382896,-0.1451518238,0.5019926429,0.6923288703,1.0122750998,-0.0421771109,0.6220104694,-0.4075361192,-0.8514463902,-0.3381832540,0.7689677477,0.6064976454,-0.0126131419,0.3224277198,1.6075083017,-1.8024101257,-1.2550679445,-0.0130337598,0.7003573179,-0.2152732313,0.9030884504,-3.0074372292,-2.3304672241,-0.5678032637,2.6673221588,-0.0000683526,-2.2414488792,-0.3600297272,0.6174938679,0.9622223973,0.4705488980,-0.2358042002,0.6787893176,1.1536179781,-0.5547327995,-0.1236007586,-0.1360976994,-1.7055424452,-1.2570964098,-2.3186249733,0.0843379274,-0.2976732552,-0.3390328884,-0.0344037488,0.5192691684,-0.6725831032,1.1736112833,-1.5922294855,-0.0136492010,-0.0983454883,0.8498770595,-0.4949856997,1.0687308311,-0.2338664085,-0.1018051058,-0.1490771621,0.6980962157,0.8531481624,-0.6047407985,-1.4088909626,-0.9811016321,0.1651830673,-0.0166458562,0.1409326643,-0.7251721025,0.7957408428,-0.1764385402,-1.6334345341,0.1553497761,0.5474259853,0.1437603086,0.1302209795,0.2271719575,-1.0537291765,1.5317530632,-0.3264935911,1.4668451548,-0.5541288853,0.9666754007,0.2401796430,0.1003144309,-0.9387914538,1.2058185339,0.4189720154,-0.0902500674,1.2073749304,0.0885801986,2.2098054886,1.0166771412,-0.3307090700,1.3583818674,0.0608563833,2.0058913231,0.0816583633,-0.0792093650,0.0939683020,0.3995066881,1.5493112803,0.2928569317,-0.1067149267,-0.4934600294,0.7856813073,-0.5543451309,-1.1688302755,-0.9422464371,-0.4649276137,-0.1244343743,1.0531721115,-0.5772435665,1.1971284151,-1.6377062798,2.6346027851,-1.5864238739,0.1980870366,-0.2175800204,-0.7853147388,0.6764087081,1.0572141409,-0.1721861064,1.2093849182,0.0640576929,-1.0637799501,-0.0791875049,-0.5274960399,0.4602147639,-0.3991668820,-0.0741831958,-1.0853574276,1.0693564415,-0.3556284308,-1.0694770813,2.6314742565,-1.4129743576,0.5074303150,-2.1636655331,0.3085227609,0.1881135255,-0.2523779571,-1.3635439873,-0.8585309386,-0.8065607548,-1.1741236448,-0.9480458498,1.4351259470,0.3912090063,1.3308275938,-0.9888421297,-0.4313032329,-1.7370495796,-1.1904556751,-0.2911131382,-0.4206063449,1.7773537636,0.1080465764,-0.2650998831,0.4594625831,0.0268785525,-1.0857034922,-0.6268877387,1.3989568949,1.3037877083,0.2572353184,1.0194852352,1.6428092718,-0.4417257011,0.1843148470,0.2210908979,-0.8268135190,0.4464316368,-1.1436780691,0.1022599861,-0.2689138949,0.4295471311,-1.3548612595,-0.5210994482,1.8831641674,-0.1348460466,0.0681441575,-0.6695713997,0.0453709252,0.3797713816,-0.4755639732,-0.2494962960,-0.1664597243,0.2957374454,1.1305173635,-0.6693257093,0.8059806824,0.8046057224,0.2548323572,1.0816518068,0.0990683660,0.1078162864,-0.1735524535,-0.2703637779,-0.2104981542,-1.8608211279,0.6002736688,-0.3222564161,-1.4688658714,0.9703220129,-0.9755422473,0.8594921231,-0.7415559888,0.9588875771,1.8989210129,-1.5950626135,-0.2549622059,0.9568085670,0.2796890736,0.2816965282,0.9156034589,-0.7888602614,-1.2830469608,-0.7138097882,1.3335521221,-0.7639064789,-1.5349581242,1.1567809582,-0.5121814013,-0.4490087628,-1.3938723803,0.5303887129,0.5679660439,-0.5504558682,-1.1937325001,-1.8920999765,0.5680583119,2.5964953899,0.4043229222,0.6083219051,0.1465612203,0.3495765924,-0.2330164611,0.2941886485,-0.8010068536,-1.2406933308,0.1112386584,0.0981622413,-1.1744223833,-0.5514314175,-0.3500730395,0.7157834768,0.1586675495,-0.1676100791,-1.5922158957,0.2704105675,0.5291992426,2.1981124878,0.4463334382,0.9241107106,0.9336605668,-1.8127021790,-0.1246180162,-0.1696453393,-0.4599695206,0.8565337658,1.6267207861,-0.9244696498,-0.1559941918,0.4249975085,-0.7795513868,-2.1165361404,-0.2150630206,-1.1040906906,-1.9384589195,0.9018970132,1.6354812384,0.5289262533,0.4159639180,0.4340830147,-0.0776079670,0.4491689801,-0.1313019097,-0.7509349585,1.2776517868,0.7487615347,2.6572730541,-0.8186072707,-1.4451512098,1.3417631388,-0.1051895544,1.3567872047,2.0140140057,-1.3726296425,-0.8574283719,-1.6812884808,-0.1505986601,-0.7210639715,-1.9408824444,0.0999050587,1.2818363905,-0.9700794220,1.2453765869,0.6968713999,-0.0645520166,-1.0578403473,-0.4692222774,2.1283955574,-0.3892408013,0.5696129203,-0.2742994726,-1.0984168053,0.6897208691,1.6492482424,1.0651326180,1.6090450287,0.1430166811,-0.0025570951,0.5276804566,-0.2226212621,-0.4914850295,-1.5938395262,1.0183731318,0.0496852174,-1.6018487215,-1.8184107542,1.7716566324,1.0756032467,0.3834027946,-1.4669975042,-0.2647817731,-1.0320789814,-0.3644350767,-0.2168742120,-0.7252820730,-1.3937695026,0.7387053370,0.2493469417,0.5485517979,1.1348981857,1.1029473543,1.6632301807,0.9258661866,0.4591159523,-0.4123454392,-1.2897313833,0.5902590156,-0.2920606136,1.9976263046,-0.5045529604,0.2800785005,0.2846641541,-1.4732339382,-0.7650971413,-1.9866602421,0.2745036185,0.1866807640,0.7437629700,-0.7251886725,-1.0595256090,-0.3219626844,0.4132559597,-1.0829941034,0.3818486631,0.4902530909,0.8203164935,-0.3574656546,0.0871377513,1.2285019159,-0.6999685168,-0.0382436216,2.0060265064,0.3040466607,0.9432737231,0.3004783690,1.0069338083,0.4846802950,-0.2194198221,-0.2402843833,-0.2284196168,0.6577883959,0.0243720971,-0.0167382881,0.0804451779,0.2744990885,1.5632476807,-0.9265797138,1.0785713196,-0.4262202978,-0.3350518346,-0.1482925713,-1.3545845747,-0.6348443031,-0.1358720660,-0.5967708230,1.2970815897,-0.8241472840,-0.1672525704,-0.6040331125,1.2512923479,-1.3428666592,0.4152507782,1.1968697309,1.4077038765,0.1768872589,1.7283319235,-0.9516835809,-0.5515766740,-0.5391194224,0.2572713494,-2.1139318943,0.9485329390,1.2312760353,-0.2881865203,1.2581969500,0.5737562180,-0.9768746495,-0.6910295486,-0.5072914362,0.3287530839,0.9405872822,0.6720070243,-0.6202755570,0.1128496304,-0.6132038236,1.5822707415,-0.3844380975,-0.0673749968,-0.2834100127,-1.1995179653,-0.0790346786,0.8218730092,-0.1707502753,-1.6510307789,-0.2086256593,-0.7109470963,0.0523468554,0.9653596878,-0.7002084851,-0.1555075496,0.0463614166,-1.4276753664,0.3529338241,-0.2941586375,-0.9563120008,-1.3457732201,-0.0424981080,0.8205020428,0.4909951687,-1.1780422926,-0.3410792053,0.4586801231,1.1928086281,1.5076155663,0.2159299105,1.0762003660,-1.3993560076,0.5086227655,1.5924257040,-0.0414426811,1.3759416342,1.3556041718,0.6253252029,1.6755017042,-0.2901961207,-0.2289954126,1.5246464014,0.3891948462,-1.2429443598,0.0270989761,2.9799761772,-2.3688035011,1.3221940994,-0.5086752772,0.5284387469,0.8252167106,-1.3484315872,-1.5581241846,-0.8698654771,-0.0978383347,-1.6825011969,0.6562595367,0.5922316909,0.2983350754,0.2247846574,-1.3188779354,-0.3159044385,0.0416775160,0.7735174298,0.1309816986,1.6671591997,0.6244473457,0.0545613840,0.4523994327,1.6147964001,-1.1268408298,-0.3600841165,-0.3496910334,-0.6707585454,-0.9565799832,0.5979391932,-0.4567743838,0.6110959649,-0.4604537189,-1.2620191574,1.1980472803,1.7984120846,0.2246788591,0.5230852962,1.7367670536,0.5086534619,1.1650388241,0.7131203413,1.3199769258,0.3111094236,0.2989323735,0.6086726785,-1.3495463133,-0.8733163476,1.3610419035,1.4206547737,0.4303741753,-0.9519916773,1.2027678490,0.0799262673,-1.1702611446,0.6195428371,0.8924890161,0.8761147857,-0.3095809221,-0.5196042657,-1.3068716526,1.5195988417,0.2128613889,1.5664979219,-0.2589054108,1.7114889622,-1.8208161592,0.1634945124,-0.8131170273,-0.6053546071,-1.3275238276,-0.6441715956,1.9088834524,-0.5635452867,1.0824725628,-1.9519108534,2.4412162304,-0.0172850862,0.9122820497,1.2396584749,-0.5733674169,0.4248894751,-0.2712600231,-0.6835675240,-1.5374375582,-0.1013744250,0.7466657162,0.9291818142,0.2294180095,0.4144058824,0.3097238243,-0.7374562025,-1.5369198322,-0.5622548461,-1.5995111465,0.8243899345,2.4914863110,1.0118551254,-0.2812379301,0.0167065077,1.1539196968,-0.6009150147,0.1329372674,-2.1699743271,-1.1165589094,-0.5693680048,0.6362667084,-0.7676492333,0.6184794903,0.1831612140,1.8593512774,-1.0755146742,-2.0192196369,-2.4374644756,-0.1485635042,1.1511514187,0.1853233874,0.6584609151,-0.0495361015,0.2373988479,-1.5115803480,1.9323703051,0.4824220240,-1.3157830238,-1.9636150599,0.5330681801,-0.1093232185,-0.2831834257,1.4337438345,-0.5686172247,-0.8498464823,0.7244464755,0.6058983207,-1.2902585268,0.7894331217,1.9609137774,-0.3355398178,-0.6076121926,-0.7272418737,0.8514086604,0.8884165883,-1.1113233566,1.1378443241,1.2755492926,0.2945994139,-2.1856794357,0.7923774719,-1.6250413656,0.7398307323,1.0142691135,0.9582080841,-2.6153709888,-0.7281308174,0.7424984574,-0.0821439624,-1.5249018669,-0.4381790459,-0.0053916587,-1.7120848894,1.7055863142,0.8111898899,0.1493609101,-0.7354556918,-0.3129665256,-0.6534162164,-0.9912257195,0.1489663869,1.1033235788,-0.1900487989,-0.4122638702,0.1786202043,0.7816811800,-0.5246403813,-1.3810967207,0.9454761744,-1.3616911173,0.5349876285,-0.0959592983,-0.8964068890,1.3871814013,0.9973930717,0.5764676332,0.4400008321,0.4754700959,-0.9835773110,-0.5619937181,-1.6410032511,0.2922827303,1.4331048727,-0.3837113082,0.2374925911,-0.5327551961,-0.4711798429,-0.3400845230,-1.4632056952,1.1385982037,-0.0050248299,0.9715877175,0.3023412228,-0.8062357306,-0.3169119358,-1.5868651867,0.7886871099,0.1372247785,-0.7851805091,-1.5065702200,-0.5764098167,-1.1072884798,0.1352825314,-1.0527776480,2.0522935390,0.9853089452,-0.3728401065,-1.4862358570,-0.1116613746,-1.9596153498,1.0607012510,0.7912979722,1.4486447573,-0.5566545129,0.8055643439,1.3840409517,-0.4356646836,-0.7338418365,1.3481131792,0.1454764307,0.4252978861,-0.0880398229,-1.2484735250,1.1045972109,-2.0293858051,0.9979759455,-0.2792384624,-0.1876324564,-0.5325407982,0.5268504620,0.4087450206,1.6114984751,-0.1840722412,-0.1820611060,-0.3537951708,0.1039311066,-0.4489805400,1.1552664042,1.3704001904,-1.9223861694,-1.2888606787,-1.0187835693,0.6616163254,-0.8920385242,0.5518894196,1.3713300228,0.7708854675,-1.0448182821,-1.1999044418,-2.6680612564,0.4900120795,-1.2550389767,0.0423943661,0.2307881862,-1.3097743988,0.9433927536,-1.0359666348,-0.5941559672,-1.1822756529,0.0490396470,-0.6646436453,2.2700588703,-0.6435940862,0.1863738149,-0.2803147733,0.8866586089,0.0039090207,-1.4617713690,0.1988759339,0.4399749041,-1.2791353464,-1.0427937508,-0.6556071043,0.2571541965,-0.3568092585,-2.2522468567,-0.7602754831,1.1351559162,0.6326811314,0.6538631916,-0.0560684986,2.1729958057,-0.0687307790,-0.2313192934,-0.4723461866,-0.3986878395,0.7822806239,-2.0840001106,-1.1852180958,1.4007776976,-0.7757635117,-1.1275815964,-0.1672484130,-0.7482985854,0.2928707302,-1.1963318586,1.4991011620,-1.3109302521,-0.0839465857,0.0558208153,0.2463919818,-0.0606065616,-0.0057793492,-0.0700023621,1.3056834936,-0.1253987551,0.9635531902,-0.7322648168,-0.0024187912,-0.1301703900,1.0004709959,-0.5866019130,-0.6917225122,-0.1560804099,-0.0212033875,-2.1023504734,-0.8584808111,1.1101720333,-0.2545737624,-0.2416257262,0.5702453852,0.5405352712,1.7392754555,0.6312438250,-0.4402846098,0.0550365932,0.7741043568,0.9616689086,-0.9026238322,0.6697832346,1.7671315670,-0.1734208614,0.0113102626,-0.9254624844,-1.0618740320,0.0115344757,0.7880923748,-0.2987428606,1.1056511402,0.9078025818,-0.3661470115,0.7300938368,-0.1293408722,0.0929499343,1.0738584995,2.4386839867,-1.3962153196,-0.3303312063,1.1602600813,-0.2442411035,-0.4293623567,1.6676892042,-0.0608364716,0.7872980833,-0.3093358874,-1.5586376190,-0.5111013651,0.6837660074,0.1929822713,-0.7978610992,2.0638716221,0.1178953871,-0.9953600168,1.2995123863,0.9166028500,-0.5599343181,0.6541744471,0.7905471325,0.4623413086,0.1298543960,-1.7680779696,-0.3233806193,-0.0529145338,-0.5833628178,-0.3562459648,0.7015071511,-0.4987028837,-1.6961719990,-0.6258285046,-0.5355837345,-0.1618913412,-1.2267602682,-0.3106380999,-0.8768603802,0.7795471549,-0.1935388297,0.5475685596,0.2768119276,-1.2845706940,-0.0423595309,1.6698843241,-1.6108504534,0.9478467703,0.0986463651,-1.5106642246,0.5734161735,1.0034544468,-0.0609908327,0.3071651459,1.8223924637,-0.6054177284,1.8280153275,1.6417883635,-1.3252933025,0.1235409901,0.0669323280,1.2934104204,1.1690789461,1.5101593733,-1.6193233728,1.3771556616,0.5679165125,-1.8386728764,1.3130825758,-1.1070921421,0.7729588747,-0.5860818624,-0.2058396339,0.4436039925,-0.2096983939,-1.4521727562,0.3058028519,-1.1525199413,0.5443555713,-1.2522698641,0.1393335462,0.3642078936,2.0137174129,-1.9375973940,0.3161602020,-1.2603361607,0.4786128998,-0.1122477651,0.7691808939,1.4161857367,-0.3374640048,-0.0133701405,0.9041422606,-0.5291411281,0.4031642973,0.8388589621,-1.0761878490,-1.5249725580,0.1757129133,0.8767262697,-1.5049668550,0.4910938144,-0.3653927147,-0.1716035455,1.0316590071,0.1405045390,-0.8550847769,-0.0122549757,-0.2336222380,-0.2811496854,1.1793352365,-0.6546878815,-0.7931123972,0.2504535615,0.6389125586,-0.1338374466,-1.2315516472,0.1087464318,2.4242548943,0.5663132668,-1.6622200012,-0.9516454935,0.0935006887,0.5418270230,-0.6956735849,2.1641728878,0.5378525257,0.3326438665,1.2569468021,0.2456189245,-1.9654610157,-0.3942227066,-0.6392866969,-0.3373064399,0.1140286326,0.6925070286,-0.7737633586,-0.7652257681,-0.0776397437,0.5756703019,0.5510339737,0.6002933979,1.1095582247,-0.3609852493,1.1201286316,0.3345442414,0.1578962952,1.8014444113,-0.3187448680,-0.7662656307,1.4651508331,-0.0448592342,1.1052986383,0.3984775245,-1.7524188757,0.2810229659,0.6246092319,-0.0725462735,0.6233510375,1.1921753883,1.4715322256,0.7919710279,-0.8447570801,0.1241444349,-0.7139037251,-0.4604227841,-0.4756816626,-0.0533989593,0.2218795717,2.0838932991,0.2475150228,1.7827460766,-0.0134890378,0.7679715157,-0.3554916978,0.0362120308,-0.7166433930,0.6927425265,-0.7791339755,-0.2974212468,0.2203360796,0.4349841774,0.5249035358,-0.4737904668,-1.3593201637,-2.2599756718,-0.8934810758,-0.6567152739,-0.6929903626,-0.8416537046,0.4606203735,-0.2749021649,-0.1371530890,-0.7862843871,1.6317793131,-0.2760257423,-2.3511528969,-0.7772335410,-1.3283784389,-1.4011971951,0.4626928866,2.3816864491,-1.2089858055,-0.4188674390,-0.7853214145,-2.1645514965,1.1445811987,-0.9505017996,0.7641232014,1.3194897175,-0.1203246713,-1.0543094873,-2.7589275837,0.6597554088,2.1434054375,-0.4508769512,0.4651074708,-0.3877440095,-0.6067355871,1.5365588665,0.1711568981,0.0135632185,0.1285218298,0.1237851009,-1.6126866341,-0.1699062586,1.7187911272,0.7952760458,-0.5621861815,0.1939502656,1.2603075504,0.3326231539,2.4959945679,0.3348725140,0.2440851331,-1.0814745426,-1.6712106466,1.0294514894,-0.3955523074,-0.7647819519,0.5640015006,-0.6139293313,0.7056366205,0.2410723269,-0.6252645254,0.2575959563,-1.4764999151,0.4396305084,-0.5134104490,-0.0369065218,1.2340645790,0.0310939327,-0.6546210647,0.9864290953,-0.0455574021,1.2032821178,-0.7458623052,-0.2978456020,-0.9822353125,-1.3218252659,0.1633568257,-0.6249672174,-0.7417123914,0.1362227798,-1.0594494343,-0.0809739381,-0.5245481730,1.8382658958,-0.8360715508,-1.3591579199,-0.5534932017,0.1547365636,-0.8778612614,-0.5545231104,-1.2758891582,-0.8472756147,0.3394901454,0.8867839575,0.3970008194,0.9629596472,-0.0797268972,0.6448428035,0.4046718478,-0.0212829933,-2.4381325245,-0.1657105386,0.9223551154,-0.8054891229,1.8176586628,0.8265794516,1.5185177326,1.7634532452,-2.1006796360,0.9573124051,0.2478752732,1.1825718880,0.9785193205,-0.5731644034,-0.9844460487,-0.9941863418,0.1693080962,-0.9317142963,-0.9543631673,-0.6126065254,0.3264756799,-0.8015695214,1.0485463142,-0.7815785408,1.3674834967,-1.0214259624,-0.2009140849,0.1025521085,-0.9636093974,-0.7346326113,0.2468834966,-0.4661616087,-0.5672651529,-0.4167720973,0.1828022152,-0.8394173384,1.6634211540,-1.8836456537,0.0390705056,-0.1487848461,-0.3561755717,-1.4013719559,0.6198907495,-1.6715638638,0.5220121145,-0.1027402878,-0.5389942527,-1.2783858776,-0.7213203311,-2.3513112068,0.6171727777,0.1380944103,0.5125414729,-1.2011198997,-0.5964149833,0.5951352715,0.2339069694,1.1006313562,0.4247358143,0.3372429609,0.1389364749,1.4059437513,-0.4783534110,-0.6449186206,0.0131500335,-0.0374759957,-0.2436141372,0.8794044256,0.3872634768,-0.5042549968,2.1577014923,-0.5692856908,0.5889863968,-0.8519099355,-0.5406209826,-0.3512584567,1.8592058420,0.1071278453,0.1881214976,-1.4387773275,0.2278479040,-1.0301718712,-0.6761962175,0.4439955652,-0.4711591303,1.5134398937,1.2920711040,0.1850506514,0.0724349618,-0.1809644252,0.3238140941,0.4700443745,-0.2543262243,-1.1642212868,0.2567294538,0.1768714786,-0.6741221547,-0.0544025823,-0.8167592883,0.6026630402,0.1571673602,0.1848359108,0.7246237993,2.1916341782,0.0395292416,0.5885300040,1.0862364769,-0.0933451578,0.8974225521,1.2546049356,0.0124170966,2.8417673111,-1.7472499609,-0.7727107406,-1.1648753881,1.1488866806,0.2784065306,-0.7488279343,0.7987616062,-0.2916001379,2.6300568581,-0.5040947199,1.0890872478,-1.0070320368,0.5389986038,-0.4499021173,-1.3006299734,-2.0500237942,-0.2852370441,0.9818706512,0.0392058752,-1.4161587954,1.4106215239,0.4247548580,0.7822275162,0.4471131861,2.5369141102,0.1805239916,-0.8006153703,1.0798196793,-2.1828672886,0.2883101404,-0.3787364364,1.2829811573,0.0463522710,-0.7552426457,0.1391619742,-1.3081711531,1.8474140167,-0.2298999429,0.6889461875,-0.6292168498,0.4396181107,-0.0836468861,1.9265546799,-1.4717415571,-0.4133013189,-0.5089668632,-1.2310500145,-0.1285655946,0.8536369801,-0.7277516723,-0.0126291113,0.4544115961,0.5498104095,-0.5179764032,-2.4123616219,-0.4469912946,2.0694754124,-0.9394243360,-1.0521241426,0.2036963105,0.0071311919,-0.6870504022,-0.0155820046,-0.1647448540,0.3724843860,0.4417797029,-1.0829602480,0.6957066059,-0.2200885266,-0.6384267211,1.0450456142,-0.0275342409,-0.3599655032,-0.2629359663,0.5287644267,0.1829177290,0.6768316031,-1.8263455629,1.1303802729,-0.0842294767,0.5546888709,1.3973606825,1.3698474169,-1.3730745316,1.0151197910,0.2647194564,1.0315226316,-1.5784586668,-0.9907632470,0.2567261159,-0.8996278048,-0.3867754042,1.4097727537,2.2299740314,-0.1896184236,0.9524666071,0.1702094078,0.9398848414,0.5321618915,-1.2387745380,1.2894320488,-0.8582060337,-1.3007978201,1.1981871128,-0.3366500735,0.8419474363,0.5433722734,-0.9629876018,-1.6009552479,1.7573373318,0.6935952902,1.4654803276,-0.1797384024,1.2437579632,1.7125695944,-0.2490044981,-0.2686403692,0.0930381417,-0.0375618339,-2.6600220203,-0.9509128332,0.2806393504,0.2936806977,0.2567313313,-0.3014256954,-2.0332870483,0.1230432019,0.2137270868,-0.9075357318,0.3526922762,0.2563580275,-0.5407764316,-0.1236735359,0.8370244503,0.2930872738,-0.9313671589,1.5671607256,1.1615507603,-0.8167613149,-0.7182096839,-0.6333760023,0.5856393576,0.6780885458,0.5890313983,0.7123593092,-1.2848955393,-0.5609303117,-1.9114166498,0.8378915191,1.0157173872,1.0953134298,-0.4000841677,0.3343574703,0.3863209784,1.5166685581,-1.9124687910,0.7424203753,-0.3382374644,-0.3509818017,0.6303770542,0.4310825765,-0.8497053981,0.5221378803,0.4046062231,1.6502557993,0.2492208332,0.7841585279,-1.4824200869,-0.4545456767,-0.9722738266,-0.0509347804,1.7074534893,-1.7254183292,-0.3090017140,-0.0453792103,-0.5058189034,1.3871597052,1.1207715273,1.0124270916,-0.3037402928,-0.1054088175,0.5237683654,0.1429743320,-0.8187479973,0.7458306551,-2.1103670597,1.0728235245,1.7312847376,0.3593048155,0.8765829206,-0.0282392837,-1.0374023914,1.3495305777,-0.8798107505,2.2148194313,-0.3535363674,0.0634836853,0.0064468719,0.4102476537,-0.5776757598,-0.3282352984,1.2123632431,-1.4314142466,-0.6823901534,-0.8864627481,-0.1065689325,0.0673301294,-0.2074949145,0.2912158370,0.9534795880,0.7978639603,-0.1701406687,0.2286783755,-0.8701025844,1.3222193718,0.1815055162,-2.4394092560,-0.3474123180,-0.9069854021,0.9881507158,-0.5943987966,-0.6776933074,-0.5054681301,-1.7560210228,-1.4633255005,0.5323156714,-0.8000277877,1.1683307886,-1.0447676182,0.0635707676,-0.3356823921,-1.1476477385,0.1429802775,-0.6482725739,0.0072258324,0.4359221756,-0.8878523707,2.4653964043,-0.5865577459,0.7874836326,-0.0772186443,0.0906665623,0.1741325259,-0.7149444222,-0.0434522107,0.0239767432,0.1674236953,-0.3820293546,-0.0326141678,-1.2816491127,-0.2897256017,-0.5946949720,0.0430568755,0.3749506772,0.0121182492,1.7634828091,-1.3510473967,1.1881501675,0.4915170074,0.0009339975,-1.8913590908,0.4536544681,-0.3723362088,0.2312607020,-1.4136934280,-0.5840505362,-0.1064425334,1.3762027025,-0.4251186252,-1.9075818062,0.2827370465,1.4952538013,-0.2975981832,-0.7461140156,0.3224439025,-1.4082685709,0.1460434049,-0.1548788100,-0.2577507496,-0.2077642530,-0.6747339964,-0.5161724687,-0.7427644134,0.2661053836,0.0695588514,-0.4860402048,0.5244890451,0.4730707407,1.7623431683,0.8991122842,-0.0184322987,-1.0504052639,0.2551665604,-1.1870924234,0.6593571305,-0.3136428595,1.2176970243,-1.0874655247,-0.0515389442,0.2061298043,-0.6265270710,1.3921668530,2.8257706165,1.0335572958,-0.8086478114,-1.0901274681,-0.3106675744,-0.1632628441,-0.4603413045,-1.3341411352,0.5154522061,-0.4899453223,0.3032837510,2.4529964924,-1.8736343384,-0.0681086928,0.0572270155,0.0044212798,-0.0653590336,0.2338360548,-1.1391998529,-0.0103998687,-0.5209394097,-1.0892212391,-0.3462033272,-1.8454072475,-2.5989222527,0.1982216686,-0.4841802418,0.2070287764,0.7549870610,1.3594202995,0.6960720420,0.6822013855,-0.0112141585,1.3447604179,-0.8314924240,-0.4079718292,-1.3308038712,0.3525986075,-0.5378847718,0.3934444189,0.2865182757,2.0425362587,-0.9194611907,0.1146700308,-0.1374237090,1.3655269146,-0.2616383433,-1.2862409353,-1.6546574831,0.0372327417,1.2703013420,-0.1432766169,0.7952552438,-0.0720724761,-0.7424240112,1.2256538868,-2.2053880692,-0.5306376219,0.1682143807,-0.9688461423,0.3096540272,0.9401078820,-0.1633903384,-0.3208823204,-0.4034307897,-0.6640667319,-0.1162874550,-0.4164044857,-0.2106245607,2.6117999554,-0.8170961142,0.2296934575,0.1352863908,2.0153095722,-0.9835947752,-0.0398398787,-0.7099856138,0.2519035935,1.0100510120,-0.7469947338,-0.2271399647,0.8424672484,-0.0028453339,0.0573192686,-0.7911548018,1.5115075111,-0.4292039275,-0.2814901173,-0.2986505032,0.9713628888,1.1659340858,-0.1845057160,0.0065851845,0.5065482855,0.1957827955,0.7852159739,1.0992507935,-0.6381587982,-0.2258110791,-0.0518908724,-0.4910358787,-2.2459900379,-0.7985108495,-0.8093937039,0.2404313385,0.4376957715,0.3021634221,0.2768120170,-0.9123110771,-1.4636436701,0.8011099696,-1.4775968790,1.9602862597,0.2919983566,0.1149028838,0.3892951906,-0.4618502259,0.7220209837,-0.1333760023,-0.8379451632,0.4440839589,2.7235734463,-1.1158251762,-0.2277544439,1.3317129612,-0.4921458066,1.3590461016,1.0847727060,0.0156160211,-0.1734282523,0.9402840137,-0.7774642706,0.7608965039,1.4017525911,1.2316533327,1.0011581182,-0.9780515432,0.6779560447,-0.0694640726,-1.0573610067,-0.1401209533,-1.4334952831,-0.1790812165,-0.1230426356,0.5381953716,1.0654780865,-1.4013202190,-1.3276036978,-2.0463159084,0.8385336399,-0.6869310737,-0.5620132089,-0.0442883112,-0.0047367625,0.6841859221,-2.1602709293,-0.1973593086,-1.2325326204,1.6918396950,0.5312877893,0.3519688249,2.1720921993,-0.1462069154,0.8961949944,-1.4612011909,0.2014119923,2.2746560574,0.4980108440,-0.7518550158,-0.9755960107,-1.5738663673,0.4436374903,0.8610516787,0.1271061748,-0.8113466501,0.2418205291,-0.6867427826,1.2207347155,-0.4108690321,-0.8827690482,-0.5456284881,0.3868001401,-1.2304912806,0.6670293212,-0.2712611258,0.0818201751,-0.1299658567,2.2640588284,-0.1695053726,0.8452254534,2.4532289505,0.4257523119,1.8475958109,0.0974547565,0.7967066169,-0.5887081027,-1.1121789217,-0.9687710404,-0.0241551120,0.2857384086,-1.1169031858,-1.3783563375,-1.8767281771,2.1267092228,0.1075932160,-2.1452682018,-0.0090910634,-0.1592708379,-1.3771734238,1.1593115330,-0.4573624432,0.0412932597,-0.2843123376,0.0463854149,1.0175329447,0.6056706309,-0.4518868327,1.5754882097,1.5401930809,-1.4632025957,-1.1145495176,-0.6111642122,1.5250842571,-0.1827131957,-0.5719213486,-0.0339936987,-0.2241427749,-0.1559786499,-1.0696374178,-0.7931587696,-0.2671611905,1.3815757036,1.2891613245,0.9156867266,0.3633261919,-2.6118755341,1.7803673744,1.1180121899,-0.3693193495,-0.6483833790,0.1860720217,0.0447100475,-0.6926733851,1.4939805269,-0.6550534368,0.2498712093,-1.2042515278,-0.2552892864,1.0822662115,0.0425696447,-0.5869133472,-1.9481761456,-0.3409913480,-0.3546536267,0.7333459258,1.3222188950,-1.2185709476,0.8016905785,-0.9687362313,1.1493378878,-0.4367955327,0.5572791100,1.5488294363,-1.7036701441,0.1468585730,1.5773946047,0.7791216373,2.1659414768,-0.4962480664,1.0852104425,0.7184401751,0.0505882911,-1.0123195648,0.2237323672,1.9337600470,1.2498807907,0.4884160757,-0.4939172566,-1.4075125456,-0.1990298480,-0.9089871049,-0.3559097946,1.1026279926,1.2252410650,1.0871775150,0.5441542268,-0.5297963619,0.4389980137,-1.7267080545,1.1040461063,-1.0993429422,1.3341366053,-0.6335446239,2.2331142426,-0.2638579607,-0.1156971976,0.7624002099,-1.3418661356,0.2185997516,-1.0052831173,0.6768507361,0.4997563660,0.2243302017,1.2361823320,0.1434970349,-2.1947665215,-0.7532163262,-0.9595815539,0.6633858681,-0.2023599595,-0.6430290341,-0.8134525418,-0.3416174352,0.4218400717,0.8895066977,0.0375063010,-0.4428788722,0.0392513834,-1.2110996246,-0.4579227865,1.4286129475,1.0722044706,2.2364633083,-0.7332018614,2.6002426147,-0.5068512559,-0.6531524062,0.2969976068,0.4913036525,0.1942404211,-0.0775747150,2.0618264675,-1.1979434490,-1.0965492725,0.2128379345,-0.0973059759,0.0509134494,2.3178815842,1.6716791391,0.6432677507,-0.7658655047,0.2551034093,-1.7418290377,-0.8488428593,0.7497497201,-0.9394742846,-0.6140592098,0.2242153883,-2.9374637604,0.2126290649,0.3135212660,0.5678259730,1.6826602221,-0.5162865520,-0.2058548182,-0.7859453559,-0.6208847761,-0.7223044038,-0.7193372250,-1.9608685970,-1.1417084932,0.7958766818,-0.3401833475,-0.4921501875,-0.4349618852,0.3137913048,-1.3271640539,0.9106199145,-2.0794861317,1.0177873373,0.4266745448,-2.0590798855,0.0865664855,0.3999687433,-1.1941734552,-0.0655964836,-1.5167351961,0.8678767085,0.7040355206,-0.0141630126,-2.5513372421,-0.0591046214,-0.1782632917,-0.6721311212,-1.4577360153,-0.8415274024,-0.4924280941,-0.1054591313,0.6587065458,0.6277593970,0.2027057856,-1.0286164284,0.1998594999,0.6571788192,0.6904782057,0.9589516521,-2.3220672607,-1.4431536198,-0.3931055367,0.7838268876,0.8431079388,-0.6274953485,2.0802054405,-1.8623497486,-0.3251871765,0.6918599010,-0.4644671977,-0.9389165044,1.2123388052,-0.1305605322,0.2123090029,1.2012878656,-0.7994313240,0.2028683871,-0.4153151810,-1.1983784437,1.0681349039,0.5389846563,0.2846174240,0.0825485736,1.4062007666,-2.5803592205,-0.2879975736,-1.4541510344,0.2424149364,1.2237983942,-0.8512282968,1.5265872478,0.3694509864,0.7817362547,0.8075862527,0.3952428102,-0.9362884760,-0.7247197032,-0.0328013301,-0.4716132581,0.5637686849,-2.2679274082,0.3426539898,-0.0979672372,-0.2402446121,-0.0963036716,-2.1943864822,0.6942761540,0.0291213989,2.4530353546,0.7187931538,0.2133912891,-1.0874562263,-0.8873418570,-0.9403048158,1.9221187830,-0.8266971707,-1.5223639011,0.9220241308,0.8729629517,-0.1005499288,0.9404553771,0.2749381661,-1.2735220194,2.1069967747,-2.2149572372,-0.3422880471,1.4668304920,1.9702908993,-0.9250925183,-0.0060714148,-0.9882918596,1.4887702465,0.2804108858,-0.3489108682,0.5542525649,-1.5422412157,-1.2575305700,0.2715023756,1.2902284861,-0.2465406358,0.3424791992,-1.0304328203,1.7649421692,0.8475595117,1.3346787691,1.6747332811,-0.2368809879,-0.3557014465,-2.0324966908,-0.4428349435,0.6714438796,1.0843613148,0.2764685154,-0.1155481040,0.9883731008,0.4112939835,-0.6270067096,-0.1460562497,0.2729308009,-1.0989434719,-2.7572638988,0.7561358213,-0.9827682972,0.9108489156,0.6604135036,-0.1289324462,1.8280123472,0.6759609580,-0.3519555330,1.6215261221,-1.0882657766,-2.5271363258,-0.3571330607,0.9479765892,0.4368820190,-0.2717285156,0.6993663907,-0.7780221701,-1.1863687038,-0.5583704710,-0.7359765768,-1.0251901150,-0.1638904214,1.2510455847,-0.3172542751,-0.9209412932,-0.5378237963,-0.2243570387,0.5573434830,0.7788372636,1.7665655613,-0.5648117661,0.5073568821,-0.1877584457,-1.0030902624,0.0020168158,-2.2090637684,-0.3919711113,-0.0892934874,-0.2768075466,-0.7382922173,0.4781686962,-0.5271230936,-0.8565163016,-0.0114886239,-0.3409681022,0.9220369458,0.4548239112,1.1105103493,-0.8540458679,-0.5342381001,-0.1587235928,0.3786576390,1.6225638390,-2.4055118561,-0.9667271376,0.7057707906,0.2168771327,-1.8539066315,-1.3120892048,-1.1653203964,-0.5374454856,-0.4951444268,0.6106092930,1.4650698900,0.2833453417,0.0034100253,-0.4601604939,-0.7077453732,-0.1619891524,-0.3710734546,1.2191070318,1.4806418419,-1.0868707895,-2.0648705959,-0.9124275446,-1.9892864227,0.8951463103,0.8109661341,0.7963710427,0.7626373172,0.6699028611,1.3099942207,0.1779273599,0.3980103135,-0.2223629951,0.7420293093,-2.4057607651,0.7425398827,0.7739811540,1.8070101738,-1.3846660852,0.1880014688,-0.1909513474,-1.5174038410,1.2443370819,0.4424822032,0.7484818697,-1.8359574080,-1.0961536169,-0.5201159716,-0.4773720503,-2.1213893890,-0.7915535569,-0.1687713414,-0.3899119198,0.2895978987,-0.3511215150,-1.3487813473,-0.0930239484,0.3696572185,-0.3927856386,0.1512555778,2.9449841976,1.6288179159,-0.3464185596,-1.0187661648,0.1346620172,-0.1407055557,-0.2609769702,0.8170487881,0.0737538487,0.5982130170,0.1496603042,2.7200851440,-1.6137839556,1.5230054855,-2.3850162029,0.9167109132,-1.0846986771,0.1835428476,1.8487994671,0.3989471197,0.8919633031,1.2315006256,-0.0234141331,-0.7482023239,0.1487952620,0.4381481707,0.3836542070,1.5491355658,-0.7265835404,0.9751958847,-1.2847875357,2.1041853428,0.2272570580,-1.1291662455,-0.2813319564,-0.7394167185,-2.5843210220,-1.1766476631,0.9712014198,-1.2400223017,0.6785711646,0.7806016803,0.9310101867,0.2308028489,-0.9521868229,-1.0569379330,0.0101044821,1.2908110619,0.8434351683,-1.0314128399,-1.3817199469,-0.0570717938,0.4098027349,0.7228524089,-0.1619416177,-0.1127954870,-1.3605376482,1.6959846020,-0.1019152254,1.0857456923,-0.1930623353,0.5130358338,0.2026667893,0.7818601727,-0.5955975056,0.1939072609,-0.2461180836,-0.2952910960,1.1024920940,0.4419107437,-1.1785167456,-0.1340370774,-0.3758517504,0.1165554896,-1.1369833946,0.9722950459,0.1699508727,-1.1497621536,-0.5577647090,2.4325559139,2.0300633907,0.3172180355,1.0420550108,1.3970026970,-1.3860317469,0.6756493449,-0.2088022530,0.0416123271,-0.3647925854,-1.3826622963,0.0327142030,-1.7300449610,-0.6120365262,1.1658670902,0.7848781943,-0.5333843231,1.3701926470,-0.6063991785,-0.9086737037,2.2848854065,0.6883058548,0.6623967290,0.8888964653,0.5443738699,-0.7265207171,-0.6869468093,0.3359093666,0.4884953499,0.9215206504,-0.1096334979,1.8479670286,-1.3251534700,1.9301359653,1.4032901525,0.3269095421,0.3069120944,-0.2451367527,-0.8169812560,-0.4496933222,0.4065041840,2.2406930923,0.8854416013,-1.4401488304,-0.9977304935,0.9404314756,0.0276801270,-1.0297243595,-0.9591946602,-1.1910470724,1.7555153370,-0.0457942411,-0.0153770149,-0.3424043953,-0.6024621725,-1.5076104403,0.3168259561,1.2989704609,-0.3437852859,0.3600607812,1.1474263668,0.8276595473,-0.7948626280,-0.3214859068,0.1499467790,1.6915059090,1.2442883253,-0.1117230430,-1.8866000175,-0.0652765781,-0.8484117389,0.9157932997,-0.8810158968,-0.6766892672,0.0717540085,-0.0943662152,-0.8810151219,1.5139248371,-1.0652790070,-3.0692067146,-1.7233544588,0.2145391554,-0.0761685669,-1.6524933577,-1.8591082096,0.0064446605,1.4435199499,0.4387893379,-0.8295137882,0.4456272721,-0.8297645450,-2.2846164703,0.3067142367,0.2384975702,0.9313440919,0.7382943034,-0.0273835473,0.7648501396,-0.8317270875,-1.4108572006,-1.7982788086,-0.6981588006,0.6069019437,0.8501870036,-0.8509014845,0.4383669794,0.6248463988,0.8739450574,0.3806868494,-0.9634509683,-0.1053313464,-1.0504844189,-1.2173187733,1.4710108042,0.6670583487,0.0257385876,-0.9211400151,-0.5374246240,-0.0370455347,0.9016004801,0.6242956519,-0.0050148740,0.8383492231,-0.6565697193,1.8286083937,0.5789019465,-2.3177831173,-0.5858536363,-0.3403774202,1.7211940289,-0.0403645262,-0.0005720349,0.9837250710,1.1704604626,-2.0550563335,0.5990749598,-1.3058104515,-0.1033330113,-0.3316901922,0.9040453434,2.9563987255,-1.5847589970,0.4970963597,1.2656636238,-0.1820234358,-0.6379039288,1.7642017603,-0.3535215557,-0.3904646635,0.0819236487,-0.4960451722,0.6401004791,-1.1532803774,-0.7206152678,-0.4024859965,0.7426589727,0.6694399714,1.4347842932,-0.3065627217,0.3679106236,1.2681542635,0.0654527098,0.8345687985,-1.1156513691,0.8476576805,0.2385712713,-0.4635876119,-1.1457544565,-0.0187508408,0.5387160778,0.2548680007,-0.0915771574,1.0684789419,1.0852134228,-0.8394083977,-0.1809697300,-0.3924306929,0.1450937837,-0.0587084554,0.6864700913,-1.0417679548,0.2963407636,2.9507956505,-1.9250681400,-0.1433570832,-1.1863735914,0.1866655797,0.9594634175,0.3174482286,1.4533431530,0.5670638084,1.3095489740,0.1332997233,-0.9662900567,0.3597651422,0.1602782160,0.2071735710,0.8496370912,-0.7209706306,0.1189359799,-0.7544926405,0.8743216991,-0.6681683660,0.3383395374,-1.1891311407,-0.0207240880,0.3600969017,1.0823884010,0.4390854836,0.6673156023,-0.1929547191,-0.0451419055,-0.4575970769,0.2687020898,0.5414130688,0.5603662729,0.4634231329,1.2978063822,-0.2309095711,1.7121770382,0.2484276593,-0.7386830449,0.3304316700,-0.0578057617,-0.0305827893,0.9412934780,-0.5984822512,-0.9803550243,0.2070207894,-0.6550219059,0.1320174783,0.7900218964,-1.3689039946,0.9380484223,0.4847313464,0.2433396876,-1.4307051897,-1.0672821999,-0.7570881248,-0.4750105143,0.0807691738,1.2956811190,0.5300829411,-0.4246348143,-0.6007465720,1.3769870996,0.4140109718,1.0277614594,-0.8248614073,0.2571107447,-0.7096899748,-0.1520026624,-0.6228904128,-0.1400981396,-0.1943059713,-1.3681163788,-1.1639925241,0.4308236837,0.1339069456,-0.8116710186,-0.5282785296,0.4628006220,1.3132369518,0.8331753016,-0.2018923014,0.0933108181,-1.0099724531,0.4170527160,0.4332081079,-0.2000631541,-0.4819248021,0.0526755936,0.5904321671,0.4194876850,1.4380538464,-0.2091670036,0.1405492425,0.8455461264,-0.1576862335,0.7914052606,0.5603117347,0.6225966215,-0.6495121121,1.6057735682,-1.4565155506,-0.1592467129,0.9452735782,-1.1509324312,1.1862341166,-0.9232009053,-1.4868230820,1.2887068987,-0.5039800406,-0.9293571115,1.4114164114,-1.3048022985,-0.5259607434,0.1474925727,-0.6388627291,-0.4544603229,1.6006817818,1.8981077671,1.2952227592,-0.6770508885,-0.0343132466,0.0424407683,0.0593665354,0.1125282869,0.1721530408,0.2323742956,1.0071390867,1.1618844271,2.0738105774,-1.5517368317,0.5792925358,-1.5301368237,-0.9412553906,1.5477662086,-0.1588866711,-0.5141246915,-0.1607577950,0.5885755420,0.7499521375,-1.0819777250,0.2867581248,-0.8426262140,-0.4466435015,-0.7166017890,1.5151894093,-0.3630546331,-1.2952378988,0.2233130634,0.7022958398,1.2997992039,-0.2185886055,-0.3559314013,0.9324097633,-1.1729716063,0.8698990941,0.3515312672,0.5347394347,0.5843375325,-0.9044497013,0.2044183016,-1.1293611526,1.0726300478,-0.5822884440,1.2378178835,0.2893677652,-1.0045837164,-1.0325323343,-0.9010717869,-0.5148781538,0.4178542495,-2.0488326550,-0.9897443652,-0.3382941782,1.5038264990,-0.2582089603,-0.1545956433,-1.6558270454,-0.0935545862,-1.0900809765,0.7780081630,2.1689538956,0.5874821544,-1.1014442444,0.6476220489,-0.8646059036,-0.3191539943,0.1379110068,1.2473257780,0.1051613837,0.5986577272,0.0665234625,0.6185915470,-0.1027515382,1.2281802893,-1.4339200258,-0.7613863945,-1.1129082441,-0.6932907701,-0.9792848229,0.4943833947,-0.6510017514,-0.0364130028,-0.5350659490,-0.7569305301,0.1001948863,-1.3082510233,-1.0891143084,-1.6640188694,-0.7002798915,-0.0759273991,1.1599098444,-0.8365039229,1.5821044445,-0.1271798313,0.4336561263,0.1694084853,0.5724648237,1.8298932314,1.4186511040,-0.9776277542,-0.4195668101,0.4297143519,-1.0633279085,0.3911823630,-0.0747859403,-0.9993607402,0.3444029987,0.9736811519,-0.9430867434,1.6025952101,0.2376157790,-0.1281956732,0.3923225701,-2.5928940773,0.7752914429,0.2649167776,-0.4567572176,0.3371549845,0.4049337804,-1.0609476566,0.0936940014,-1.5922925472,1.8138062954,-0.1034576967,-0.3052410781,-1.4047080278,-0.3657502234,-0.0972745717,0.2751365006,-1.5588892698,-0.3687875867,0.7465646267,0.3279536366,0.1500969678,0.6712778807,-0.3980213404,-0.8001051545,-0.5537888408,0.7133117318,0.8906948566,0.0045022634,-0.9853961468,-0.1782789230,0.9238131642,0.7145440578,-1.0212540627,0.2322989702,-0.1549165547,-0.3999933898,-2.6583871841,-1.0034289360,1.3892837763,-0.0713517517,0.1388881058,-0.0967622548,0.4031153023,0.6281492114,0.5679972768,1.1819807291,0.4587058425,1.7037755251,1.5106276274,0.0188147873,-1.2132136822,-1.1595399380,-0.9960440993,0.1820143163,-1.2581967115,-0.0109062744,1.2203755379,0.6200798154,-0.2033996284,-0.0597796105,-1.1121650934,0.3698798716,0.2429883182,-1.4556866884,0.2045957595,0.2362975627,-0.2086562663,-0.8186010122,-0.2720654607,-0.5458545089,-1.2913902998,1.2412921190,1.4953358173,-0.2214281559,0.5088971257,-1.5477359295,-0.7341091037,-0.0617847852,-0.9167001843,1.7482943535,0.6113579273,0.1244715825,-1.7654695511,-0.8131557107,-0.2266721576,-0.2433164567,-0.9586618543,-0.3598257303,-0.1786702126,-1.8549596071,0.4828202128,-0.2374148220,-0.2234849483,-0.7928118110,-0.0088003566,-0.1138385981,-1.1613034010,0.5579746366,-1.1964149475,1.2761023045,-0.5428506732,-0.7676082253,-2.0380215645,-0.8374180794,1.8076927662,0.6725515127,-0.4143821895,0.0190587919,0.6254171133,-0.2820325494,0.8748767376,-0.5163024068,-1.0898655653,0.1275738180,-0.1395269185,-1.5575122833,0.4249118268,-0.1607739925,1.3152391911,-0.7662281394,-0.1419369578,-1.1442737579,0.5419403315,-0.0603652373,0.0115801683,-0.4260250032,-0.8693335056,0.3321054876,-0.2232301235,0.1859180033,0.0755599067,0.4812561274,0.0805540904,-0.1881784499,-1.3111925125,-0.0887244120,1.5127700567,0.5737081766,-0.5410040021,0.1011774912,0.9945519567,0.0187130310,0.2556715012,-0.7111772299,1.1038419008,0.7498760223,-0.6901777387,-0.6161143184,-0.8754807711,1.3833988905,-1.4642595053,-1.2905743122,-1.1369878054,-1.8163366318,-2.0593073368,-1.5773495436,-0.1809103638,2.6330025196,-0.8738535047,0.4626492262,0.5717197657,-0.5768548846,-0.3781278729,-0.1874432266,0.1967199296,0.3621532023,-1.7878540754,1.1232843399,2.2314839363,-0.2592034340,0.4197042882,0.3647200167,-0.4982883036,0.8533704281,0.6698650122,1.4574915171,0.1867191195,3.0060515404,0.0711427107,-0.2154966444,0.0293234326,-0.0889864117,0.1243936792,0.0645327345,-0.2294944078,-1.0487772226,0.1695384383,-0.4823871255,-0.2830505073,-1.2472976446,0.1283144057,0.4478857815,-0.6975439787,0.1654880643,-0.3362832665,-0.1657265425,-0.6748378277,-0.6607167721,-1.2857440710,0.2204591036,-1.4501774311,-0.0336493291,0.8193687797,-0.7773550153,1.2970961332,-0.5298593044,-0.2872518003,-0.0863314644,0.3339187801,0.3005096018,0.9379919171,-0.4672140777,1.9484413862,-0.3087449372,-2.0272562504,0.2302280813,0.1488207579,3.2926943302,-0.5023747087,0.9368308187,0.4223787189,-1.2146153450,-0.3633534908,-1.0163754225,0.8161545992,-2.6420648098,-0.9995900393,-0.6842966676,-1.3786201477,-0.1166622937,-0.5009272099,1.3049273491,-1.1700606346,0.4273369908,-0.4868766069,-0.9399681091,0.1936713308,-0.1304665208,1.6364108324,-1.2473168373,0.4555480182,0.7874873281,1.0548788309,1.4028953314,-0.3403153718,-0.7662428617,0.7910608053,-0.5680841804,-1.6864377260,1.7951066494,-0.5170757771,1.3853578568,-0.4875607193,0.9538254142,-0.4127383828,1.2545660734,0.9811357856,2.5652039051,0.4855013788,-1.6319627762,-1.9827576876,0.7196250558,0.3306773603,-0.3879871368,1.6143678427,-1.7628905773,-0.2992368042,-0.2816053331,-0.4913335741,0.1062109917,0.6110439897,0.4482290745,0.8110507131,-0.0504925326,-1.0317854881,0.5823349357,0.8444985747,-0.3849413693,-1.3550829887,0.6306875348,0.3171112239,0.0095400224,0.8568302989,1.8019857407,-0.9952394366,3.2118475437,-0.1661012471,1.7766364813,-0.3340893090,-0.2285335511,-0.0810918510,-1.7271569967,0.4434600174,-0.7047592402,0.5324918628,0.4588414729,0.6069088578,-1.1168786287,-0.4205290377,-0.4082236588,0.9159150720,0.0197826736,-0.9659548998,-0.0031386658,-1.1092762947,1.1993969679,-0.9169333577,-0.3250979185,-0.6554597020,1.0403012037,-0.8468415141,-0.0201100614,1.0483227968,1.3847842216,0.2876734436,0.3542454243,0.4986132979,-0.2432114482,-0.1372609735,0.5234652758,-1.2656041384,0.4806742072,3.0031232834,-0.1512721330,-0.7243952751,0.0387897491,-0.1198186129,0.8208485842,-1.0074971914,-0.6677929163,0.0483032688,0.1750379354,0.2083159089,-1.9190596342,0.9766510725,1.8913180828,0.4273438454,-1.3285946846,-0.1469343305,-1.3562725782,-0.3669628799,0.1919582635,1.3829925060,-1.0648114681,-0.2708503604,2.7610263824,0.6004490256,1.3111655712,0.9766030908,-0.1186602041,-0.4448900223,-1.0978698730,-0.4263503253,-0.2740243077,-0.1068669632,1.0883152485,-2.9813721180,-1.1545959711,-0.0348202735,0.2651986182,-0.4033118188,-0.8410776854,1.0309700966,0.4036042690,0.1645698398,-0.4990791678,0.8270534277,-3.1262013912,0.2744820118,0.8101330996,0.7581610084,-0.7181271911,-1.3808708191,-0.5076599717,0.0838778764,-0.8853391409,0.6123282313,-0.1626137942,0.2677460611,-1.4126522541,-0.4442411065,-1.2625015974,1.5032956600,0.6110239029,-0.4633914828,-0.2613438368,1.8707574606,0.6762051582,-0.3888108432,-1.0406956673,-2.4245371819,0.4552400112,-0.4199117124,2.0087494850,0.6389307380,-0.3146655858,-0.0531506911,-0.1081308648,-0.8942368627,-0.2720023394,1.1744161844,-0.5152111053,-1.5052090883,-1.3972624540,-0.0511602834,-0.0412393324,-0.2354413718,-1.2756769657,0.1774501950,-0.1988486648,0.8698195815,0.4150623381,-1.1867893934,-1.2666206360,1.5865522623,0.0610986762,-0.1770948023,-0.5854319930,-0.4385347962,0.0175962076,1.3314625025,1.5840754509,-0.3236637712,2.3411216736,-0.6135569811,0.9249237180,-0.2237814665,0.8911208510,0.1451560408,0.2448153049,0.3776126504,2.0296990871,0.6324076653,0.3589432240,0.4496875703,-0.3058456481,1.1094084978,0.4872805178,-0.3038507998,-1.4573172331,-0.9205236435,0.6826651692,-0.3554729223,0.3927389085,-0.3810762763,-1.7063821554,-0.1602554619,-1.6169706583,0.6162632704,2.4065866470,0.3152024150,1.2607896328,0.3310032785,-1.3002210855,0.5527735353,-0.7645601630,-1.6030761003,0.2826044559,0.1884256005,-1.1052546501,-0.0256252103,-1.4617702961,2.3069312572,0.1014108062,-0.5887804627,-0.0482289307,0.7604926825,0.7126061320,-1.1288833618,0.3887622952,-0.2175828516,1.4924032688,-0.1203889251,-0.4008507431,-0.4998865426,-0.9092680812,-1.4348453283,-1.2464061975,0.4905832410,-0.4584877491,-1.7624422312,-1.2848756313,0.1869234592,1.6680623293,1.4857335091,-1.3092820644,-0.4001376033,-0.6902616024,-0.2851842344,0.5611698031,-0.2224484831,0.1025903299,-1.3632470369,-0.5505031347,0.9418570399,0.4167126417,1.5588051081,-0.4624279737,-0.3520548344,0.6923726201,-1.3459591866,-1.3967781067,-1.2523069382,1.1929949522,-0.8578463793,0.2459804118,1.1848936081,-1.6676170826,0.3219023943,0.1425884366,0.8878026605,1.3843916655,-2.0635306835,0.4181311429,-1.6780023575,2.8656015396,-0.6755149364,-1.2139745951,-1.7235435247,-0.0115590412,-1.2834458351,0.6609151959,-0.1157040447,0.3007107079,-0.9618673921,0.6788420677,0.4106647968,0.7691630721,-1.8603491783,-0.2602683008,-0.6554810405,0.8151291013,-1.1044774055,-0.0258444790,-0.6846947670,0.7430288196,0.0927735269,-1.8108327389,1.4642354250,2.1097369194,0.5113024712,0.9214703441,-0.7961116433,0.1557842940,1.6264904737,1.6839746237,-0.1017777249,-0.0270002671,-0.5560973883,-0.3349419832,0.4305644631,-0.3148517013,0.5323333144,0.4808635712,0.6366700530,1.1908731461,1.2183773518,-0.0871770829,0.1331706196,0.0532641746,-1.2944794893,-0.6270956993,1.0332086086,0.8411585093,-1.1188211441,0.9106353521,2.4634940624,1.3054764271,-0.5078490973,0.6401654482,-2.0949027538,-1.5359004736,-2.1329395771,-1.2214189768,-0.0510937348,-0.6269537807,0.9085376859,-1.7701388597,0.1271123588,0.2025357783,0.2193867266,-0.1419527531,0.4712587297,-1.1216319799,0.2348901033,0.2660713494,0.1221213117,-0.0339588486,-0.4119123518,0.2396080047,0.4450393617,0.1456137896,0.1783765703,-0.8795627356,0.0829178467,0.2220709324,-0.2598603666,1.2970924377,-1.6507456303,0.6115096807,-0.3253150582,0.1117031053,0.7479269505,0.4571745992,0.1007617787,1.4383536577,-1.4001889229,-1.9547203779,-0.7588565350,0.1194262281,0.7364101410,-0.6658715010,-0.0521111190,0.1420148462,-1.2008237839,-0.0141287912,0.1722817719,1.0185024738,0.3625552952,-0.2192810923,0.6853411794,1.0109658241,0.0720389709,-0.5317717195,-0.2604891360,-0.2174306065,0.9860923290,0.3199743629,-0.0393218994,1.5142209530,-1.8734128475,-0.8563058972,0.7394201159,0.9219983816,-0.8890936971,-0.5466315150,0.5607649684,0.8172806501,-0.2346559316,1.4355891943,-0.5468201041,0.1247638464,-0.6282752156,-0.2512498796,0.0405594669,0.4966886342,0.7192645073,-0.5121807456,0.2786832452,2.3277153969,1.7324640751,-0.1355056465,0.9407029152,1.7785062790,2.0651509762,1.1749883890,0.0644653961,0.3345230818,-0.2759347260,-0.9038693905,0.0737935454,1.7145204544,-0.0049464516,-0.4580802917,0.8939317465,-1.5609588623,1.1997606754,-1.3571116924,0.2147751749,0.6041502953,-0.4827028811,0.4263130724,0.3580539525,2.0956006050,-0.2793421745,-1.6219590902,-0.2702989280,1.0025880337,0.7011756897,0.1722511351,-0.1773850620,0.7790995240,0.8636000752,-1.0049010515,0.6323234439,-0.7638198137,0.3079225421,-0.3288014233,0.3946300745,0.8784893751,-0.1306656599,3.0949795246,-1.4146577120,0.3331373334,1.1519114971,-0.1283607334,-0.6941428185,0.1147115529,-0.0274392385,-1.7293875217,2.3312771320,1.6542543173,-1.7632293701,-1.9415524006,-1.1907383204,-0.0048493538,0.4222418964,0.0341976583,1.5213152170,-0.1766054034,0.2243996412,0.7282629609,0.1159321964,-1.4154875278,0.3165683150,0.8783222437,-1.1561028957,0.5572648644,1.5004160404,-0.8511629105,-0.5939493179,-1.1936300993,0.6819807291,-0.0313347243,-0.0286470875,0.8888990283,1.0018740892,-0.1425251812,0.2556823492,0.7652249932,0.1631320864,-0.2498634607,-1.5008529425,-2.9273338318,0.6607398987,0.1327477843,0.5937239528,0.1125463098,-1.6437536478,1.5341486931,2.1285750866,-1.0796158314,-0.2879979610,-2.2914717197,-0.8244517446,0.4066144824,0.6147168875,-0.5193148851,-0.7325679660,0.4611653090,-0.4268031120,-1.1843461990,-0.1097135618,-1.1662861109,1.3328620195,-1.4928250313,-0.2382298410,-1.2711412907,-1.0696352720,0.6976164579,0.3925410211,1.2439258099,-0.3567233384,1.2630944252,0.0982297659,-0.5787029862,-1.2956535816,0.8188961744,0.4646765888,1.2062302828,-0.0755145028,0.2233940512,0.0219676215,-0.2262375951,0.8005526662,0.2583341599,0.0134167904,-0.9566358328,0.6107801199,-0.3282876909,-0.5326413512,0.3580334187,1.6714169979,1.4230730534,-0.5663484335,-0.7258203030,0.5634755492,-0.4356320798,-0.1045525447,-2.3212728500,-0.2140943706,0.5434054136,-0.5374541283,-0.3802753389,0.2654729187,-0.1454317421,0.3900747597,-0.1429263800,-0.0141180474,-0.5412923098,0.9153400064,0.7681113482,0.1016348004,0.8094421029,0.0004556435,-0.2267173529,1.2817173004,-0.0734994039,1.0696345568,0.7920151949,0.3397075832,0.6335131526,-0.3126899004,0.3656824529,0.3227659762,-0.1339740306,0.3025370538,-1.6606614590,0.1812739521,-0.3153503239,-1.0073664188,-0.7484238744,-1.7166824341,-0.1572054476,0.8618949652,-0.9956087470,-1.1582169533,1.3176295757,-1.6233000755,0.1798952520,0.6858589053,0.0602968559,-0.6038802266,1.0489137173,-2.2571678162,-0.0584337749,-0.1138860956,0.0855550766,-0.7688744068,-1.2541327477,-1.4902909994,0.1294953823,0.0926831588,-0.5188183784,-0.7847260237,-1.0042928457,-0.0707495660,-1.5369973183,-0.8811527491,-0.9041975737,0.7040268183,1.1990603209,1.8376708031,1.3268336058,-0.1728139222,-0.1250518411,-1.5261913538,-1.8103522062,0.3975400925,1.7494088411,1.7238782644,-1.3281983137,0.1908317953,-0.8550479412,0.1436198354,-0.3308296800,0.1347103268,-0.5981942415,-0.9036156535,0.8448509574,-0.5984261632,-0.3971627057,-0.1978619695,-1.2565414906,-0.4385175109,-0.6725533009,-0.5639172792,0.0460369922,-1.9070044756,0.4588394463,-0.4961534441,0.5328682065,0.2758805752,1.0665974617,-0.1897082031,-1.0725839138,0.9363661408,1.1084721088,-0.3609683514,-0.6044198275,0.7308124304,-0.2895660102,0.9214672446,1.1936705112,0.1420208365,0.9903038144,1.0248546600,0.7819829583,-1.5155851841,-0.1204732060,-0.2646034360,-0.4781559408,-1.2578017712,-0.8879620433,0.8834035993,0.3680997789,-0.3455525041,-0.1083529815,0.8362635970,-0.8118629456,-0.8376584053,1.3152875900,-0.3645234704,1.9935706854,1.5848784447,-2.1046626568,-2.5531182289,-1.2426662445,0.2019866556,-0.3053317666,-1.1955868006,-1.5779031515,0.8499122262,0.3275901377,-0.0016695884,-0.0355634280,-0.4892515540,1.9304982424,-0.2626447082,0.8259323239,-0.6432670355,-0.8289811015,-0.2027345747,-0.2578664720,0.0708145201,0.9978447556,0.2600807250,0.9250656366,1.4760758877,-1.8792523146,-0.7825285196,-1.4022051096,-1.4552857876,-1.1523354053,0.0965485498,0.2922802567,0.8867214322,0.1132206246,-0.0294816475,0.2782558203,0.9704330564,-1.4312628508,-1.4022347927,-0.1946246922,-0.5354971290,0.6042767167,-1.4157117605,-0.9723172784,1.0312830210,1.4538744688,0.2337075174,1.3080239296,0.7617688179,0.5921661854,-1.2361630201,-0.9084081650,-0.7632186413,-0.8020383716,-1.3764209747,-1.5502327681,-0.1663934290,0.7598895431,-0.2875463068,-0.3408353031,-0.4380674958,0.1424137503,-0.2995167673,-2.1005253792,2.4057154655,0.3382180035,0.3632414639,0.3133047223,0.4243564308,0.1828026623,0.4043556750,2.5423345566,-0.3791434169,-0.1495744288,-0.8346999884,-0.7742741108,1.2149647474,0.7606167197,0.3171077371,-0.1672189832,0.1230465323,-0.5340057015,-0.0623281896,0.4993795156,-0.6112615466,0.2279778421,-1.2632958889,-1.0773020983,0.3607445359,-0.2576623857,0.7818472981,-0.4763545990,1.3054454327,0.6843120456,0.4527694881,-2.4472017288,0.6361515522,-0.5922811031,-0.1407441050,-1.1186494827,-0.2712420821,0.3353216648,0.9042813778,-2.1890122890,-0.3902392983,-1.2158573866,-1.4680877924,-0.2748048902,0.8750464320,-1.0083405972,-0.4647849798,-0.1865984648,-2.0889463425,-0.5600870848,-1.3486815691,-0.3641701937,1.1793979406,0.1997187734,1.6865342855,-1.0752303600,0.5811572075,0.3023730814,-0.5949453712,1.3834298849,0.3260892630,-1.5045257807,-0.6118640304,0.1986764967,1.0946094990,0.9827951193,-0.0680601895,-1.0457265377,-1.7469846010,-0.5958772302,-0.3935099542,0.7819852829,0.1315787882,1.3365695477,1.2137441635,0.4329839945,0.7754896283,1.2031998634,-0.4921071529,3.0196695328,0.6024559140,0.2277309895,0.5269126296,-0.1516455263,-0.2588847578,-0.5245341063,0.2717128098,-0.8874869943,-0.8964639902,-0.1968666464,0.0911976174,-0.8873035908,-1.8681821823,-0.0760981515,-0.7805968523,0.4802442491,0.0320365019,-0.7067071795,-0.4631549716,-1.1735436916,0.5445239544,-1.3017100096,0.3699762821,-0.0850021094,-0.7237022519,-0.7464592457,0.2509557009,-2.1246905327,1.6723703146,-0.7169879079,-0.5348271132,0.3575956225,-0.2395388484,1.9923259020,0.1982047707,-1.4630272388,-0.5053290725,0.8650518656,-1.3065795898,-0.6528154612,1.7014002800,0.2201984078,-1.6176035404,-0.5858163238,0.3461747766,1.7925175428,-0.8658657074,0.0194235109,-0.2472789586,-0.9830157757,-1.2460169792,-1.4011884928,-2.3403863907,-0.7892500758,-0.1878778636,-0.0241079796,-1.2374361753,0.4444930553,1.4464956522,-0.6280738115,0.0667637363,0.6859157681,1.8527070284,1.5816912651,0.0943878442,-0.6667955518,0.6660448313,0.5320387483,-1.0508078337,-0.5289185643,-1.9789937735,-0.0936506018,-0.5537081361,0.1577619612,0.3714364469,0.4536406696,1.1362136602,0.4127557874,0.0746068135,1.4729266167,-0.0521894582,-0.3334014714,-0.2249729484,-0.5179290175,-1.0466347933,0.9848658442,-0.0994437635,1.7418688536,1.1313471794,1.5630669594,-1.0602076054,1.6669305563,-1.4789799452,-1.9057705402,0.3552731574,-0.7447243929,0.1306759268,0.9287368655,-0.1092540473,0.3579307199,0.0620544627,0.9341294169,-1.3217412233,-0.1887846887,0.5450025797,1.1946133375,0.1155479774,-0.0156681519,0.0818186924,0.3128174245,-0.5175796747,-0.9493309259,-0.5009193420,0.3581947982,-0.6916647553,0.7086075544,1.2116622925,-0.5839709044,-0.1023268700,-0.4031613171,-0.0775697455,-0.1116259247,0.5571227670,0.6536220312,0.1175153852,-1.2265955210,0.2845886052,-0.3341941833,-0.9034729004,0.3816067576,-0.0520795807,1.3590296507,0.2401977628,-0.5103403926,1.4039888382,1.0099010468,-0.4682047069,-0.1903148890,0.2275711149,0.3296707869,1.3139348030,0.3545247018,1.6756818295,-0.4598955214,0.0968695879,0.9012082815,-0.6129329205,0.5607587099,1.7570564747,0.6849796176,-0.1868782192,-0.4102973640,-1.4443739653,-0.0522584990,2.2450199127,0.1798616350,0.7548625469,1.1856045723,0.2843368649,-0.4107406437,0.4364345074,1.2590898275,-0.3064253330,0.7047862411,0.4805850387,-0.1725681275,-1.0563880205,1.0208398104,0.9267752767,0.1891755462,-0.3822020590,-1.4817459583,1.2379530668,-1.5762476921,-0.8821061850,1.7232716084,-0.5654813051,-0.0660265014,-1.1681851149,-0.6628458500,0.7722485662,0.2607228458,2.2022979259,-0.7688165307,0.0033735237,-0.1173261702,-0.9136849642,0.3267530501,-0.1441042274,-1.2224164009,0.8834843636,-0.6588438749,-0.2248045206,-0.8135863543,-1.1237211227,-1.0655337572,0.4619101584,-0.7503932118,0.3477369547,0.2655709982,0.8278338909,-1.2869812250,0.3188256621,-0.8562581539,0.7813947797,0.6154556870,0.6575708389,0.1797037572,-2.2783794403,-1.3994863033,0.7637216449,-0.6022380590,1.0573459864,-1.2417126894,0.8444338441,0.4190975428,0.5408490300,0.1426850855,-0.9931777120,-0.3794707060,0.5953972340,-0.8911392093,1.2549008131,1.0709406137,1.3681180477,0.7540420294,-1.3617898226,0.2148898542,0.7666696310,-0.5721467137,-0.9326041937,-1.3463188410,-1.0583540201,0.3082196116,0.1263058931,1.4746549129,0.0198656376,-0.1533403397,0.5427250266,-0.8982430696,1.0728341341,0.9212007523,-1.0459827185,0.2398848087,-0.2399872392,0.2015265524,1.0953737497,-0.7641457319,-1.0590814352,0.9709772468,-2.7245488167,0.0263428781,0.0311356522,-0.1787093282,0.4194993079,-0.8683885336,0.4747060835,-0.4976926148,-0.6131805778,-0.8993081450,-0.6951372623,0.2548579872,2.4627816677,1.2880226374,1.3663511276,-2.0841400623,1.0545402765,-0.6584460735,0.7016707063,-1.4842098951,0.7018342018,-0.7367026210,-1.1353683472,0.8034266233,1.9471383095,0.2818152010,0.6163467169,1.6901090145,-1.7596832514,-0.0940287039,-1.5356237888,-0.4820639789,-0.2813972235,1.9129413366,0.1789698899,0.2698389292,-0.4756282866,-0.0582442805,0.6104027033,-0.1537651569,-0.3071576655,0.0031420253,-1.1825238466,-1.8446222544,-1.3169915676,0.1479340047,-0.6539691091,-0.3660846055,-0.5772585273,-0.5850701928,-0.2924168110,-1.8485302925,-0.1489338130,-0.7512722015,-0.7153009772,1.0778415203,0.6231737137,-1.6968379021,-0.8516989946,-0.9225254059,0.9233241081,-0.3950044215,0.7099353671,-0.0429341830,-0.6496396065,-0.3185375035,-1.8720908165,0.0721271336,0.2912057340,-0.2783482969,0.6049549580,0.6706092954,0.7283976674,1.3359290361,-0.8727504015,-0.1820479333,-0.2766488492,0.5385487080,-1.2421909571,-0.6489337087,-0.8941696286,0.1014679298,-0.0520993546,-0.6106041670,-2.9797456264,-0.6892374754,-2.2069187164,-0.4327895939,-0.6774798036,0.1662548184,-0.1374444216,-0.7766288519,0.4023796916,-1.8384613991,-0.7337769270,-2.0104799271,-0.8689224720,-0.0495265275,-1.3442329168,0.0602338761,-1.7688345909,-0.8403044939,-1.0115302801,1.9035303593,-1.2843977213,-0.4898892343,0.7581721544,1.1472157240,-1.3688549995,0.6080808640,-0.5300948024,-0.6094548702,1.0624125004,-0.0401498191,-0.2764210701,1.5775593519,0.2636820376,1.2670412064,1.1847480536,0.6004807949,0.6627605557,-0.9631214142,-0.0651835725,0.3965368867,1.2247297764,-1.5966616869,-0.9161520600,2.0568938255,0.1804197133,-0.0667092502,-0.0283539798,0.4848047495,0.8173012137,0.8953057528,-0.7625162601,1.4375944138,1.1974359751,-0.6648783088,0.4911331534,0.4361787140,2.4836254120,1.2508749962,-0.8652247190,-1.1523828506,-2.5317647457,0.6768011451,-0.8235494494,-0.0016548608,-0.2926580310,-1.7133356333,0.2775128782,-0.4684120715,-1.0212373734,0.3111077845,-0.5543714166,-0.5277050734,0.0934340209,0.0553637892,0.1839600801,1.0744355917,-0.8088902831,0.0177089591,-1.0553754568,0.0537255295,0.8920047283,-0.1436830014,0.5428864956,2.6151807308,0.9089220762,-0.6701074243,0.1462989897,-0.4177500904,-0.3071745634,0.2703181803,0.0061454624,-0.0414125137,1.2520478964,-0.5853372216,0.0183674395,-0.3882516623,1.1016137600,1.8874223232,-0.6500365734,1.4510560036,0.2006217688,0.1075251549,0.4110045135,0.2201270163,-0.9558433890,-0.0729107559,-0.2200553864,-0.1955879778,-0.3888328075,-0.1492266357,0.2064908445,-0.4907214046,1.3380523920,1.0333486795,-0.3924434781,0.2761882544,-0.0500014015,0.2783436775,-0.2208845317,0.4076091349,-1.6868382692,-1.1322995424,-0.4491987824,-1.6285598278,-0.0747513771,-0.9900171757,-0.5021103621,-0.0169003569,0.6617447734,0.5219373107,0.0710919797,-0.1033318341,-0.1241831928,0.5050722957,1.7465324402,-0.9384755492,-0.2050182074,-1.4408466816,2.0659956932,-1.2176458836,1.0436911583,-1.6367999315,-0.8311728239,0.0383930989,-1.4327731133,1.6502213478,-0.0957067087,2.2228686810,0.3076825440,-1.7243221998,-1.6951988935,0.2783026695,0.9383012056,-0.8741029501,-1.1462081671,-0.6457691789,-0.8208730817,1.1436293125,1.4125794172,0.2804195881,-1.6822501421,-0.4242359996,0.6605323553,-0.0331386216,-0.0384374969,-0.8116567135,0.1741831154,1.4778373241,-0.2192885429,-0.5614511967,-0.8825250864,-1.2342511415,1.1353919506,0.8536889553,0.6619521379,0.1940427870,1.2519853115,1.4540354013,-1.4876911640,-0.5286277533,-0.5613620281,0.4594193399,0.4614850581,-0.8415557742,-2.4047565460,-1.4944550991,-2.2047286034,-0.7104699612,-0.6865041256,0.4871855676,0.9703326821,0.0191650800,0.0305574350,2.1260392666,0.3825403750,0.1017763391,1.2437696457,0.0841875896,0.0260246377,-0.3963061869,0.2071161419,-0.4882599413,-0.1168544292,-0.9286617041,1.1061260700,-0.2454181761,-0.0635446012,-1.3290656805,-0.2628045976,1.4840424061,0.5852842927,-0.6792443991,-0.4082862735,-0.3425306380,-0.5310598016,-0.2525795102,1.2393785715,-0.6161656976,-0.8743874431,-1.1418819427,-0.5788629055,2.3537743092,1.3391598463,0.7086358070,1.0133312941,-0.6402965188,-0.4752223790,1.2483383417,-0.0412226953,-0.3494254649,1.2869471312,-1.3261907101,1.0926253796,0.3833552301,-0.6908642054,-0.0721437111,0.4729478657,-0.4645186067,0.8151687384,-0.7450098395,0.3585434854,-1.3225007057,-0.5362467766,0.0556739420,-0.5106480718,-1.4202176332,1.1659399271,0.7442878485,-0.6453229189,0.4733515680,-1.0344504118,1.7793974876,-0.7470325828,1.7667423487,1.0275626183,0.0522043034,-1.9739670753,-1.1114044189,-0.3246097863,-0.3506036103,-0.3710768819,-1.9017586708,2.0592153072,0.1685639471,0.0427768752,-1.3544977903,0.5274385810,-0.8166235089,-0.6331622601,-0.0177748725,1.5376009941,1.5840349197,-1.5073336363,0.0665762797,0.3779613674,0.9021579623,0.0178753231,-0.1060614064,0.9497752786,1.1455736160,1.1762216091,-0.8378641009,-0.5064931512,-0.5005347729,0.0742226392,0.5423977971,0.6719839573,0.3955279887,0.1929187477,-0.0416823812,0.5823065639,0.4075008333,0.9344403744,1.6156861782,-0.4030669630,-0.5414798856,0.3706814051,-0.4143368900,1.2245029211,-1.7612340450,0.0220842361,0.0963661671,-0.9343460202,-2.0305268764,-0.6361606717,-0.4195115566,0.7116051316,0.6106399894,-0.2644272745,0.4211940169,-1.1107473373,-0.6500771642,-0.1556589901,1.8477299213,-1.4575940371,0.4544501007,0.5361469388,-1.8324573040,0.0428999849,0.5673006773,-0.3812290132,0.1586058289,-0.7432076335,-2.3003587723,-3.0178782940,-0.4192528725,0.3673498631,-0.3779532313,0.3696709871,0.7667483687,1.1323468685,0.1713690609,1.9920309782,1.0371128321,0.7972601652,-1.5348200798,-0.2240379602,-0.7211647630,1.2391200066,-0.5251198411,0.3672321141,-0.2873863578,0.1083054766,-0.3605248034,0.0712789819,0.9799603820,0.6624241471,-1.7817859650,-1.0848448277,0.5504264832,-0.4166675508,1.6126602888,-0.2049243599,-1.0211094618,0.3455152214,-0.5317375660,-0.7377064824,-0.4188673496,0.8521258235,0.2819546163,0.8450640440,-1.0280054808,0.9755204916,-0.0629693344,-0.6170272827,-1.3914250135,1.1874107122,0.1367413551,0.4460196495,-1.2611466646,0.0386255011,-0.9642368555,0.4145136178,-0.1752219051,-2.5754177570,-1.6540249586,-0.0349275842,0.0448959023,-0.4018982351,-0.7180095911,-0.0794271529,-1.0193690062,0.0466088690,1.0369007587,-0.4155933261,-0.6224948168,0.2363770604,2.0348365307,-1.3155070543,1.4027558565,0.7323297858,1.2334948778,1.3659120798,-0.0808410868,0.5328992605,-0.0881688148,-1.8309184313,-0.5434551239,0.6239242554,0.8248231411,-0.5365520716,-1.2415540218,0.7438274026,1.1258167028,0.1619975269,0.2171468437,-0.0945205837,-0.7705362439,-0.2652542293,0.3964420557,-1.0244829655,1.4870411158,-0.1595176905,-2.5220484734,0.8388492465,-1.2317235470,-0.9562405944,-0.6581323147,-0.2054009885,0.0864707008,-1.5467650890,-0.0167100113,0.0975208133,-1.6225047112,-0.6531865597,1.1103789806,0.1780981272,1.4125519991,0.6659147143,0.7821815014,-2.0617392063,0.8627902269,-0.3878584504,-0.1652761549,0.0142101552,0.0475623906,0.8808799386,0.0930731744,1.9853578806,0.2075347602,0.0492352843,1.8051396608,-0.5307197571,-1.1836994886,2.3241052628,-0.3693919778,-0.0356154442,1.7207887173,-0.0219147708,-1.0829179287,-1.5767006874,-0.1409223974,1.3477866650,-0.1534931064,-1.1728582382,-0.7144800425,-0.2241252959,0.3540037870,-0.1153135300,-0.9265352488,0.1685252041,-0.6477338076,-0.5638371706,0.1049879938,-0.0841720998,-0.5061149597,-1.2376722097,-1.2302114964,-0.2418429554,-0.0475620590,0.3470554650,-0.7907449603,0.0829786956,-0.9652466774,-0.8953530192,0.7561290264,0.4937201738,-0.3596648276,0.9256682992,1.1828033924,-1.1108970642,0.6139956713,1.3882287741,-0.2518001795,-0.7563911080,-0.9352231622,0.9392328858,0.5460475087,0.9603745937,-0.9488556385,-0.4981226325,-0.4026987553,0.5920459032,0.0090565272,-0.8863218427,0.0490998067,-0.1781470776,0.2800677419,-0.9707691669,1.3887768984,-0.6077256203,-0.2242699414,1.9329805374,-0.8913836479,0.0187778343,1.3015447855,1.3718682528,0.5478003025,-1.0495789051,-2.1708903313,1.3192451000,-0.9026982784,-1.4011514187,2.0441510677,-2.0233173370,-0.0080679497,-1.6217567921,0.4429032803,0.0473358221,0.9135802388,-0.0456274971,0.0288143251,-0.5566142201,-0.1602125764,0.7894438505,-2.3435871601,-0.8936960697,-0.6324608922,1.4873902798,-0.7355272770,0.0185255464,0.2910588682,1.8088326454,-1.2172501087,-1.4750502110,-0.5276563764,2.0352544785,0.4579901695,0.0531067401,0.1881678998,-0.8126240969,-1.0810470581,0.6841163635,1.4170793295,0.4437287152,-0.0769727081,-1.0915343761,-0.4374568164,1.6740102768,-2.9241530895,1.6825302839,-0.1471130699,-0.3678592145,0.1373748779,-0.2201071382,-2.5014238358,-0.6038212180,0.7263562083,1.2062644958,-1.0378527641,-0.2458584905,-1.3896532059,-0.0786310136,0.9795127511,-0.2071323991,-0.4947267771,-1.6725231409,0.2150016129,-0.6723101735,-0.2168543935,-0.9003168344,-1.2477769852,-0.1771844625,-0.6590757966,1.1977955103,-1.5937381983,-0.7925133109,-0.6221466660,-1.6597610712,0.4350447357,-2.5738360882,-0.6248568296,0.3362247050,1.0735864639,-1.4852718115,-0.2946455479,-0.3111856580,1.2795861959,1.4509670734,-0.9087712765,-0.8750560880,-0.6453881860,-2.5647492409,0.2437494695,0.5734773278,1.1027342081,-0.7475714684,2.0953369141,-1.3439731598,-1.2973996401,1.1596117020,-0.9503767490,0.0014978965,0.1826970875,0.1884649992,0.3975955248,-0.6645811200,-0.1333314031,-2.8415510654,0.4180964828,-2.7764372826,0.2658073008,0.2275587916,1.4011553526,1.5555111170,0.8428824544,0.9028973579,0.3212300241,-0.5996940136,-1.0242420435,-0.6158038378,1.6927067041,0.2687541246,-0.3995000422,-0.3005733490,0.2216373682,-0.2204890847,0.6902763247,-1.4169993401,-0.8151863813,-1.9904801846,0.4423972666,0.6706801057,0.7185264826,-0.2972773910,1.1108764410,-0.8177000284,-0.5754866600,1.1977572441,-2.6281495094,1.5867403746,1.4161043167,0.7671688199,0.1658380479,0.8150725961,-1.6277327538,0.3003188074,1.3336789608,0.8292962313,-0.4848930836,0.1618258804,-0.5849781632,-0.6967284083,-1.1470516920,0.7196304798,-0.9395693541,-1.2485228777,0.9772579670,-0.9749694467,-0.9194549322,0.1552649140,-1.3407961130,1.0570300817,-0.0778691396,1.7038300037,-0.2739207745,-0.3102475405,-1.7548904419,0.4191471636,1.2825931311,-0.5296666622,1.0294588804,0.1527706832,-0.8580433726,0.4660653174,0.2710532248,-0.7573392987,1.7085819244,0.2593532801,0.2727315128,0.0305096321,0.6543181539,0.7176415920,-0.2725006044,1.1646317244,-0.1886187494,0.6548362374,0.7484856248,1.5596144199,-1.2608844042,-0.6304160357,0.6321176887,0.2912154496,-0.8312640786,-0.2090908885,-0.7051216364,-1.5571593046,1.7400833368,-1.1747038364,-0.3725011945,-0.3637978733,0.4852464497,-1.6679120064,-0.4092452228,0.4874619842,-0.0685126632,-0.2348806113,0.1828349084,1.0253461599,-0.3952368796,-1.0767440796,-0.4530940652,-0.5046754479,-0.4909371436,-0.3833635449,-1.8254991770,-1.1022430658,0.3569259942,-0.2243722230,-1.7885184288,0.9822217226,-1.4025393724,0.8213406801,0.3869772255,-1.1860983372,-1.2052828074,-0.1533375829,1.8314754963,0.8154265881,-1.0724186897,0.8384286761,-2.0999834538,0.2436810583,-0.0349125080,0.7932613492,1.1110419035,2.4974799156,-2.8381979465,-1.0605124235,1.0589070320,0.9585606456,0.8247618079,-2.5230290890,1.5672498941,-0.2026850730,2.0308806896,-0.0637612268,0.5324293375,0.9650161266,-0.3561647236,-2.2441608906,0.5721330643,-0.0420632027,0.8333802819,-0.1294799000,0.2182023227,0.3625458479,-0.3400902748,-1.3537571430,-1.2952094078,0.7723783255,-0.0648406297,-1.2400768995,1.6827946901,1.1401575804,-1.5258969069,0.8159262538,-1.1959249973,-1.5505919456,-0.6034004092,-0.6083353758,-1.0715056658,-0.1194637045,0.0140260626,-0.9964612126,-0.1172712520,-0.5439452529,-1.6995549202,-0.0008625090,-0.9978842139,0.3596127033,-0.7026296854,-0.5324466825,-0.7600529194,-1.3232053518,-0.5340525508,-2.1644289494,0.4067259431,-1.6405332088,-0.3487933874,1.1609245539,0.2904104888,-0.1469300389,-1.5347036123,0.2856205404,0.0134263178,-2.1771950722,1.0045795441,0.8746539354,1.1157619953,-0.0907416940,1.4753232002,0.5067855716,-0.7191897631,-0.3575884700,-0.1088900194,-0.4578658938,1.6910647154,-0.3512211740,-0.3477337062,-0.0016170363,1.6011307240,0.8124353886,0.1603957415,-0.3600437343,-0.2487288564,-0.5773665905,0.8298076391,-0.4896481931,-0.7197877765,-0.0610746816,-0.3374556005,-1.5635737181,-0.6105449796,0.5172725320,-1.2310928106,0.6385520101,0.2386399955,1.5264911652,0.5826241374,-0.6799334288,-0.5346289873,-0.2036975175,-0.7439308763,0.4147465229,0.0078077312,-1.0435984135,-1.2097308636,-0.3265855610,-0.8725820184,1.7610948086,-0.9714349508,1.5349853039,0.2814086676,1.2379722595,0.4718837142,1.1676279306,-1.2804001570,-1.5776510239,0.4372701347,-1.1033475399,0.6475730538,0.4473706782,-0.1467706263,0.7794570923,-0.6803262234,0.9622517824,-0.8587225080,1.2174996138,0.2897004187,-2.5981965065,-1.5418102741,0.0819696561,1.5873248577,-0.7349403501,0.7290760875,0.9269818664,0.7080751061,-1.2577210665,1.1770211458,-1.9203807116,0.7047927976,-1.0936950445,-0.2829663157,0.6887729168,1.2502661943,0.1848202497,0.4263668954,0.0182026662,-1.5792089701,-0.3927980363,0.8779292107,-0.4019509554,0.4690700173,-1.5016077757,0.3696859777,-0.9097312689,0.7302269340,-0.7808380723,0.5710436702,-0.6982168555,1.8683104515,0.0536289178,2.7342181206,0.9965337515,-1.3732835054,0.5279285312,-1.5946539640,0.5114824772,-0.0093094138,-1.9116069078,0.5795866251,-1.3237437010,-0.9147019386,-0.5839483142,-0.1468760073,0.9125059247,-0.1213563755,0.6303017139,-0.4348902702,1.0431065559,-0.3461530209,1.0725315809,0.9376847744,-0.6338280439,-1.7862892151,-0.8356691003,0.4631983340,-1.3741754293,-0.1512538940,0.4590940177,-0.7534619570,-0.8041709065,-0.1798563600,-0.2793759406,1.3496509790,0.9117848277,0.6284425855,-0.1181348413,0.5227888823,-0.8071405888,-1.4427751303,-0.5251013637,-0.4712083340,-0.4328814149,-0.0625080392,0.2701307237,-1.2395265102,1.9819504023,0.5889578462,0.7082515955,0.1354319900,-0.4342207611,0.8350552917,-1.5380432606,2.2015075684,-1.2920140028,1.6503757238,0.4370865226,-0.6922412515,-1.8327370882,-0.1175616831,0.0189046878,-0.1070931181,-1.7652977705,0.5713495612,-0.8332467079,0.3077534735,-0.5451762676,0.5432214737,0.9431089759,0.2331315875,0.4595543742,0.6053746343,-0.5241636634,0.6633955836,-0.5136868358,0.3695436716,2.5949618816,-1.8505828381,1.3736778498,-0.2972381115,-1.7225773335,0.3269241452,-0.9890488386,1.9549521208,0.5292824507,0.6432071328,0.2097698003,-0.3138158023,0.0110373385,-0.8368542790,0.6338981390,2.1725356579,-1.3096066713,0.5576665401,-0.8026767373,-0.0024915286,0.7201132178,1.1928230524,0.2271231711,-0.0062309671,-2.3676698208,-0.2402453274,-0.5720393062,0.8346250057,0.1938629746,0.6820136905,-0.1138827205,0.0992246643,0.6323102713,-1.8433687687,-0.2471316308,0.8616644144,0.6367298365,0.6539236307,0.5544044971,-0.3177534342,-0.7643328905,0.5900797844,0.7913125157,0.7577337623,0.7785899639,-1.0440396070,-0.6633660197,1.5012997389,-0.0091627706,0.7560212016,0.8975538015,-0.9736179709,-0.2276934981,0.9973939657,-0.3334585130,-0.8088312745,-0.3517300487,2.3488607407,0.6854371428,0.3064183891,-0.4391704798,2.6296787262,0.2384973019,-0.9323630333,-0.1401946098,-0.8720086813,0.7077708244,-0.3136989176,-0.0932615995,0.6460273266,-0.4569582045,1.7222473621,0.2486722022,-0.5947818756,-0.5724456310,-1.2928011417,0.3518567085,-0.2768443227,0.1744876951,0.7715813518,-0.3155222535,-0.6012001038,-0.0778921768,0.6547526121,-1.5268802643,-0.8698882461,-0.2165810913,1.1484020948,0.6043649912,-0.7420395613,-0.0446573719,-1.3837007284,0.5973103046,-1.2017232180,-0.4692558944,1.0996962786,0.4843816459,0.3924929500,0.5177378058,2.1317279339,1.7797539234,1.8023210764,0.5402734876,1.6492481232,-1.1998282671,-1.1383824348,-1.3544220924,1.0511277914,-0.3663887382,-0.0666134506,-1.7126017809,-0.1563147753,-1.6851294041,-1.6602188349,-1.3355588913,-0.2164773196,1.3588712215,-0.7749710679,-0.5971747041,-1.5134319067,0.6159718633,-1.0240488052,0.4399787486,-0.2938184738,1.3824003935,0.9063398838,1.7439777851,-0.8023254871,0.7868092656,0.0004580946,0.4446972311,1.3736970425,-0.3319808543,1.6903849840,-0.8114499450,1.7070233822,0.3595496714,-0.1166067645,0.6463969350,2.5515398979,-0.9076561928,-0.1777824014,-2.1957619190,-1.9981634617,0.4334587753,-0.7519865036,-1.0104613304,-0.7528412342,-0.2588641346,-1.2371978760,-0.0698891729,0.2212488353,0.4128143191,0.5448367596,-0.3559421003,0.1989956051,-0.7013852000,-0.6775157452,-0.4674378335,1.0175814629,-0.9423191547,-1.4644925594,1.0119210482,-0.5379062891,2.3790464401,-0.7766230702,-0.2486738861,-1.7352688313,-0.0490255542,0.3822934031,0.7362163663,0.7763320208,-0.1527945995,1.2485646009,0.2239975333,0.6150395274,0.1295638382,0.0960831046,-0.1421104372,0.6133358479,0.8356537819,0.7742197514,0.1762249768,0.1703704149,-0.3257652521,0.5471190810,-1.5459822416,-1.5104633570,-0.3404698074,1.1019839048,0.8252863288,-0.2277154028,-0.4301207066,-0.0688877627,0.8002319932,1.4292235374,0.4345422983,-1.4420714378,0.1606875360,0.3235762119,0.1411382407,0.1357653439,-0.4222933948,-1.0847389698,1.8023097515,-1.3667072058,1.5778913498,-0.0131876403,0.3190685511,0.8450273871,1.1641961336,-0.7162372470,0.3938809037,-0.3219540715,-1.7239831686,-1.1850391626,-0.2674075663,1.1804103851,-0.9732410312,0.1530347764,-0.5131613612,0.5818021894,-0.1796519756,-0.3842805624,0.4687068462,-0.3080357015,0.6460461020,-1.9881218672,-1.7341786623,0.0405684933,-1.2557553053,1.1959751844,-0.2807148993,-1.1054583788,-0.9994213581,1.3731906414,0.5248828530,1.1866965294,-0.8613355756,-0.2546068728,-0.4799605608,-1.8969695568,0.2036823183,0.0273817368,-1.9169287682,-0.9908143878,0.1783454567,0.4995328784,-0.3635697961,-0.0450246893,1.6701726913,-0.1013248339,1.0435426235,-0.8696965575,-1.1632086039,0.1831671149,0.6457328796,0.2006639540,1.5764163733,1.4348359108,0.4867582619,0.0998035371,0.2122234851,-0.0686026067,-0.2263608724,0.3516403437,0.7742586732,-0.3687585294,-1.5238984823,-1.5085883141,0.2777234614,-0.3668000698,0.1228307188,-0.8946448565,-0.5748972893,-0.0552437901,0.1306430250,0.4406910539,2.4174592495,-0.9714004993,-0.5191168785,-0.5188544393,1.3178100586,0.1041980833,1.2463740110,-0.0790428743,0.6186703444,1.2864513397,-0.8152043819,0.4917009175,-1.1067799330,0.0927638784,-0.1811284125,-0.4697842598,0.3500574529,0.3294185996,0.1947860867,0.8966708183,1.9381089211,-0.9195051193,0.7260957956,0.8662853837,-0.5145770311,0.1757200509,-0.8238931298,0.1056567132,-0.1374659091,-1.2861822844,0.5849096775,1.8646203279,-1.6820768118,-0.9834036827,1.3807744980,-1.2435959578,-1.6130899191,-0.7388973832,2.2242629528,-0.4154294133,-1.7480731010,-0.2249363214,-0.7993203402,0.6460397840,0.1766046137,-1.6437238455,-0.0110550970,-1.4476402998,-0.2804417014,1.2617326975,-0.2355776876,-1.6873000860,0.8121863008,-1.6272295713,0.7626906633,0.1414132714,-0.9910776615,0.8963002563,1.4895867109,-0.7519250512,-0.1140206978,-0.2397381216,1.8317588568,0.9710619450,-2.1389555931,-1.1381371021,-0.7534425259,-1.2349971533,-0.9838739634,0.7869290113,0.7393561602,-0.9010815024,-0.1183883175,-1.5193796158,1.0234062672,0.4929726720,-0.5983226299,-0.8546621799,-0.9928486943,0.8580879569,0.8566496372,0.3198273480,-0.2430842817,0.2529213130,-0.4792161882,-1.4864950180,1.4555321932,1.3306303024,1.2000240088,-1.2556482553,0.4722168446,0.7385764122,-0.3788935244,-0.4737539589,0.9722071290,-0.9189504981,0.6632404923,-0.1334913969,-1.5663703680,-1.7486513853,-1.1225919724,0.7985507846,-0.0880931318,-0.2178262472,0.3675931692,-2.1636779308,1.5768371820,0.0332911499,-0.6151152849,0.7404027581,0.7260823846,-0.8314467072,0.6558555365,-0.3027761579,-1.3855255842,0.0839681327,-0.8914278150,-1.5680286884,-0.6328111887,-0.1193251312,0.2832503319,0.2091138959,0.0765040293,1.0707458258,1.1313108206,0.6235074401,1.1784594059,-1.4363331795,-0.4905205369,0.1248268560,0.3911684453,0.2099477947,-1.4990891218,0.5412989259,-1.1710778475,1.2187296152,0.6991159916,1.2686791420,0.0984257534,0.1025270298,1.6023763418,0.3297880888,-0.9317253828,-1.2777259350,1.5729357004,0.7261555195,-2.7456653118,2.2690129280,-0.4050147533,1.7808687687,1.9016879797,-0.3218570054,-0.2043680102,0.1489765644,-1.4593832493,-1.5017405748,-0.8670356870,0.2126237601,1.3351058960,1.6312758923,1.6304445267,-0.4380942583,-1.3650913239,-1.4511771202,1.0316030979,0.8142898679,-1.6095172167,0.7330580950,-0.3812020123,0.5772187114,-1.0423914194,-1.7273218632,-0.0568555333,1.2256610394,1.6008268595,0.4206520319,-0.5724737048,-0.2653441727,0.5704436898,-0.2628526688,-0.7718463540,-0.1277451515,1.1820430756,0.4724800885,1.4606692791,0.0491502918,0.4095941186,-0.5304942131,1.3007168770,-1.6952812672,-0.3756690323,0.3484024704,-1.6185001135,-0.1921009719,0.0708475932,2.4357285500,0.9716811776,-0.9329621792,2.8652036190,-1.7920479774,0.5449343920,2.4494490623,0.0170834791,-1.3960881233,0.5912993550,0.7908234000,-0.2101195306,1.0908360481,0.9109295607,0.1053518280,0.9273505211,0.8930205107,0.5378038287,-0.6903609633,-1.1878529787,-0.4941872358,1.1770657301,1.0582617521,0.5110420585,0.5188018084,1.3615533113,-0.2138238251,0.4488541186,1.4647057056,-0.3835515380,0.7276459932,1.1939560175,0.2122646570,-1.0129065514,-0.5653158426,0.1305658966,0.2739067674,0.7412998080,0.0615668334,-0.4668753147,2.5491123199,1.0991567373,0.6903136969,0.6747993231,-0.4939589202,-1.8001532555,-0.2043026686,0.0035368698,-0.0057333200,1.0612637997,-1.4626442194,0.4315978885,-0.6228010058,1.2404770851,0.1704462916,1.9868983030,0.1113011688,1.2096550465,-0.4573297799,0.9231835008,1.3255188465,-0.9531663656,-0.6781297922,0.3340995908,-0.7549282312,-0.3883825243,-0.6265756488,-1.3064211607,-0.0384958498,0.1435673833,-0.7890736461,-0.0985037014,-1.4528664351,-0.9478659630,-0.8695787191,-0.3055172861,-0.6051473618,0.2248205394,-1.0384724140,0.7718191743,-0.4800092876,1.8347450495,-0.1087654233,0.4544749856,0.0987093523,-0.4583054483,-0.8570440412,-0.7744029760,0.7087873220,0.0184736028,-0.1040805802,-0.2348577380,-0.2509063482,-0.9627502561,0.4934051633,2.1330499649,0.9838882685,-1.8092817068,0.0423588157,0.5168721676,-0.0329206921,1.2981114388,-0.2021170259,-0.8332309723,1.7336002588,0.1906490028,-0.1778104007,-1.0850250721,0.9722623229,1.4314717054,-0.2450730503,-0.6232538223,-0.3959988654,-1.3585224152,1.3226025105,0.0034439384,-0.0001967701,1.5337039232,-0.7730822563,-0.4012549520,-0.1153567657,1.0115554333,1.5132355690,0.9170686007,0.7288931012,0.5520321727,-2.8032341003,-0.3960531652,-0.7131436467,1.3008337021,-0.5528658032,2.0708973408,-0.3659083247,-0.8976300359,1.4449365139,0.1729418486,0.2826884985,1.0908695459,-0.2013481557,-0.6806857586,0.8032750487,-0.3421638310,-0.4724888504,-0.6922569275,-0.0466712639,-0.6195800900,0.8695260286,-0.1468828470,0.3280917704,-1.3630435467,0.8078343272,0.6606640220,0.7788500190,1.5073202848,0.3795762062,0.6519295573,0.3520001471,-0.4837388992,-0.1357428730,-0.1349714249,1.0053361654,-0.8543254733,-1.7947654724,0.9829106331,0.8027749658,-0.4673963487,-1.4142329693,-1.1199934483,0.8871966600,0.0762820542,1.2231287956,-0.6656363010,-0.3412737548,-0.5046559572,0.3275733590,1.1423867941,0.7465314269,1.7910561562,-0.0725371093,1.2476819754,0.0711429790,-1.8477734327,1.9659148455,-0.2410738766,-0.1578042954,0.5254576206,-1.9116709232,0.9348053932,0.8459461927,0.1184646636,0.5029144883,-0.1982770860,0.7655358315,0.9073389769,0.1973911673,1.3738481998,-0.9893300533,-0.9891023636,-2.4769854546,0.7702542543,-0.0861265808,-0.8576679826,0.6391736269,-0.2472003400,0.2333795726,0.8708141446,0.6738551855,1.6272670031,0.7516965270,-0.7883411646,-0.8082208037,-1.3736037016,-0.4045992196,1.0280630589,-1.5187823772,-0.4838001728,0.6150732040,0.8216204643,0.1266588718,0.5752500296,2.1062376499,0.8944895864,-0.7871508598,-1.3972195387,0.3273196220,0.7946544290,-0.4160199165,0.7112743855,-0.0405380018,-1.7044556141,0.5837534666,-1.0075877905,0.7251850963,0.9467189312,0.5067328811,1.6449491978,0.5131101012,0.3260095119,0.5165187716,0.1619718522,1.9142762423,0.6852089763,2.6714634895,-1.2615832090,0.0633755252,-0.6122508645,0.7064356208,-0.1490675062,0.3214509189,-0.3426703811,0.3457258642,-0.4682802856,0.2918916047,0.4650507569,0.1249749437,0.5599335432,0.6786236167,-0.4045546353,0.6692442298,0.4938224852,1.2209396362,0.1036879346,0.6975646615,-0.6695911288,-1.2909108400,0.1948612928,0.1942252070,-0.6748269200,-1.9970334768,2.4057705402,0.6200784445,0.3772981763,1.5525032282,-1.4655271769,0.3644940555,-0.0155226057,1.1985623837,-0.4178135395,-1.6951625347,0.8210743666,-1.7736728191,-1.0594503880,0.7284531593,1.1591846943,0.2815538645,-0.3945144117,-1.9853501320,-0.4423422217,-0.9395880699,-0.3203176856,-0.9223166108,-0.5297619700,1.6634757519,-2.5264670849,-2.2690434456,0.5216883421,-0.3797107339,-1.0727113485,-1.2990864515,0.1797483265,0.2679230273,0.7701867223,1.3195123672,-0.4258531332,0.0932302922,-0.1008663177,-0.0527959503,-0.2420887053,-1.2358770370,0.2188131213,0.2474349886,0.0911240950,0.9356385469,0.6642363667,-1.7988439798,-0.9775348902,1.0068738461,-0.4412638247,0.2630724311,-0.2938269973,1.2398545742,0.1530414075,0.0919402540,-1.4946030378,-1.6424170732,-0.3924821019,0.9380593896,-0.7755195498,1.4306209087,-0.5973093510,0.4153765142,-0.4966987967,0.4551673830,1.3969449997,0.9603327513,1.6694878340,-0.7250531912,-1.1356847286,-1.2331088781,-0.2271185815,-1.2854925394,-0.9318059087,-0.7606769800,3.2205018997,0.2209428847,-0.0629122630,-0.6298869848,-1.0732094049,0.0010558150,-1.0177214146,-1.5743277073,-1.6354320049,1.7043139935,-0.6617698073,-1.6599169970,-0.3333908916,0.6777613759,-0.0104675246,-1.1323215961,-0.0904404595,-0.5879105926,1.0276099443,1.4621688128,0.2452373505,-1.8568937778,-0.2075275332,0.0924542099,-0.5434443355,-0.5015999079,0.3858227134,0.5888552666,1.1586396694,-0.7475170493,-0.2434626371,-0.1310633272,0.2667567730,0.5259755254,0.1121224090,-0.5332795978,0.8407949805,1.0488711596,1.6149709225,0.9318397045,-2.2712433338,-0.7382249832,0.0473290794,0.1856919378,-1.3058172464,-0.7064233422,-0.1791879386,0.5038546920,-0.6263046265,-0.0282821339,-0.7154991627,0.4878412187,-0.0843407884,1.7737895250,-0.4433949292,-1.0820724964,-0.5127086639,-0.4460237324,1.8900141716,1.3373774290,0.3039647639,-0.1128789261,-2.2114961147,-0.7659804821,0.0121604325,-0.5553606749,1.8555424213,0.9179546237,0.2352409810,0.8584582210,-1.1751790047,1.6242084503,2.2770774364,-0.1804874986,0.5590753555,-0.1992742270,-0.5453976393,0.5759513974,1.1652381420,1.6872155666,1.8794616461,-1.1923128366,-0.3455305696,-0.0926098600,0.0298121963,-2.2340764999,-0.0128461355,1.7809996605,-1.7698057890,-0.1657604724,-0.2962538302,0.3984484971,-0.2784538865,-0.7657407522,0.5881029963,-0.0268511921,1.2491877079,0.5969085693,0.8053591251,1.2250876427,-1.6654818058,0.7458550334,0.1767183840,-1.0294940472,-0.3047012985,-0.8348066211,-0.5481224656,-0.2275418341,-0.3919983208,1.7537639141,-0.4548853040,-0.2024148703,-0.7957806587,0.7550222874,0.5483199358,-0.6040002108,-1.0742310286,-0.2339738905,-0.7312679887,0.6031473279,-1.9090847969,-0.4644692838,1.8127008677,0.5727068782,-1.1307305098,-0.2126340717,0.9141866565,1.0289263725,-0.9336540699,0.9685837030,-0.4468255639,-1.3155292273,0.9664657712,-0.1305926740,-0.1409974098,-0.2777955234,0.1934855133,0.2790493965,-1.0827175379,-0.6172372103,-0.9062939882,1.6249476671,-0.8238903284,0.6574448943,1.3339018822,-0.7396215200,0.0353739858,-0.9580649734,-0.1081325933,-0.5253806114,0.8399999738,-0.6203387976,-0.1352863312,1.8578811884,-0.9981376529,1.3206781149,-0.0126401605,0.5569839478,-0.1270247847,0.4880434573,0.5574302673,-0.4547669888,-0.6072672606,-1.0674308538,-0.5023055673,-0.4857284427,-0.0919217393,-0.9623599648,-0.0035295901,-0.0758933797,0.0933261737,1.2281299829,-0.0178553499,-0.4720449448,0.2214139700,1.4468604326,0.4306001961,1.0677331686,-1.6240931749,-1.1872859001,-1.1063474417,1.1893283129,-1.3409972191,0.7507525086,0.2144597620,0.3168707788,1.2522690296,0.9644386172,2.1303524971,-0.7632300258,1.7955607176,-0.3486187458,-0.3859466910,0.2825184762,-1.0904860497,0.2479778975,-0.3009818196,0.4486035109,0.9551592469,1.4568217993,-0.6479675770,-0.3713506460,1.0168209076,1.2009193897,1.0800970793,-0.3941484392,-0.1019895002,-2.3731226921,-0.3524095416,-1.0711951256,0.5553830862,-1.7090671062,-0.6871978641,0.0623640977,0.0408379324,0.4368767738,-0.9474046826,1.3001302481,1.1587718725,0.4988572299,0.2281088084,-0.6101936698,-1.8242050409,-0.0441021472,2.4481766224,0.9330115318,-0.1531505287,0.0430765450,1.4130680561,1.1317970753,-0.8838879466,-0.4641161561,0.8401603103,-0.1360720992,0.7551409602,0.9949775338,-1.5624421835,-0.3360073268,0.2582748532,0.6022772789,0.1784233600,0.7269070745,1.0488575697,-0.3621068895,0.6744479537,-0.4786558449,-0.2334593087,0.4071067572,0.2839189470,0.7738007903,0.4134279788,-0.1320126951,1.0825728178,-0.8175003529,1.4486014843,1.0853774548,-0.2358137816,-1.6589474678,1.1178635359,1.0709910393,-0.3829950988,-0.1981175393,-1.3988100290,-0.0638643652,-0.1147952601,-0.3831200600,-0.8857003450,-0.8296794295,1.4530539513,-1.6511634588,-2.5654265881,-1.1252266169,0.3472560346,0.9780961275,-0.7914997339,1.9477938414,0.3580872715,0.1118140593,-0.2804694772,0.4610228837,0.6023619175,-0.5335633159,0.0542477593,-1.7664861679,-0.0508076660,1.9950895309,1.5672857761,1.4353256226,-0.5908765197,-1.2080715895,-0.6752406359,-0.7683525085,0.2406216562,-0.8646903634,-1.6352556944,1.7879844904,0.3776165843,1.5704457760,-1.4466234446,0.8425059319,-1.2013957500,-0.3469410837,-0.7660391331,-0.6346268058,1.6559984684,-0.6233503819,0.4907566309,0.8447885513,-0.9813486338,-1.4458115101,0.6337310076,-0.5561428070,-0.5065686107,0.1102068424,-0.5101391673,-1.1948239803,0.7441099882,0.0857115984,0.0515982620,1.1483319998,0.7804873586,0.5419780016,1.2188420296,2.0769410133,-2.4862742424,-0.4223719239,1.0099729300,-0.7526311874,0.0810160041,0.5616210103,-0.4127331972,0.1325272769,-0.5238465071,-0.3826581836,0.0631827638,0.2585388422,-1.0420076847,-0.4863687158,0.0387250669,-0.4188231528,0.0140505927,-0.9987033606,-0.8189831972,0.2218448222,-0.5424128175,-1.5457696915,-0.4346087873,0.4255478680,-0.2396979183,-1.6252154112,0.3310910463,-2.3621444702,0.2520245612,-0.2275166214,0.3297084570,0.9491755962,-0.0028857999,0.3958771825,-0.3808728158,-0.7215411067,0.9620351195,-0.9630186558,-0.4433543384,1.2981798649,0.0506372303,1.3202215433,-0.0137817934,-2.1586008072,-0.2851150930,1.0693598986,-0.4877946377,1.0574339628,-0.5105757713,-0.5830003619,1.8261824846,-1.2577497959,2.4384016991,-1.2908158302,-1.2552080154,-1.0708709955,0.3558755517,2.2702765465,1.6279611588,0.9271426201,0.4194103479,0.6996855140,0.2764927447,0.0600915737,-0.2719833255,-0.0216664709,-1.0817744732,0.2898022234,-0.7958546281,-0.5543126464,0.0587645993,0.2073607743,1.6387189627,0.9563472271,-0.1144778430,0.4083743691,0.3125553429,-0.0443716496,-1.4478203058,-1.4528867006,-1.0498052835,-1.0768823624,-0.9817907810,1.0057474375,2.1739764214,-0.1706229895,-0.3973425627,-0.8106067777,-0.3117626309,1.7385970354,0.4636293352,-0.3924411833,-0.5573529005,-1.3127901554,-0.0500530154,-0.3318820298,0.6395338178,0.1124192551,1.6188535690,1.5975137949,0.7731382847,0.1306872517,-1.3235602379,-0.4722246826,-0.2985983193,-0.4397483170,0.9028589129,0.7685422301,0.9230428934,1.6842801571,1.4418077469,-2.5131144524,0.4086238444,0.0655701682,-0.3320867121,1.7466781139,0.3734170496,-0.2728291750,-1.6017853022,0.7018960714,0.4604117274,2.3683567047,0.4982431233,-0.3625016212,-1.7402305603,-1.1604846716,-0.0124342721,-0.0771125332,1.2629164457,0.2355280519,-1.0599642992,-1.4503680468,0.1968804300,-0.3745819032,-0.6852248907,1.8013814688,0.4930929840,0.7483561039,2.1840589046,0.0830427632,-0.6732596159,1.0215715170,-0.5686770678,0.8424426913,-1.9740310907,0.6989012957,0.0312862769,1.7320979834,1.0707975626,-1.0670249462,-0.2167563587,1.7714269161,-0.2345068604,2.4865136147,0.2414270341,1.7394777536,0.4267886877,-0.6875585318,1.1192632914,2.2618951797,-0.1167902946,0.4676852822,1.3006483316,2.9003543854,1.5146406889,-1.1470533609,-1.2451536655,-0.5879987478,0.5812782645,2.1253869534,-0.0506866947,0.4011137187,0.7882096171,-0.6160338521,-1.2647396326,-0.2363180667,-1.5727478266,-0.0531756170,-0.5144679546,0.2395006865,-0.8833888769,0.2919378281,0.2528843284,1.3525061607,0.1802900583,-0.9587054849,-0.1820952743,3.0571014881,1.5167911053,-1.0126098394,-0.1719368100,0.4079130590,0.1754129082,0.3528579772,-0.2692727149,-0.8049977422,0.0460437089,-0.0798596963,1.0721807480,-1.1028991938,-0.6041131616,3.4571788311,-0.4846538603,-0.6901526451,1.0774567127,0.1411880702,-0.4632414579,0.1769790202,0.8287273049,-0.7865691185,-0.8834164739,0.8981291056,-0.3418011665,0.4376186132,-0.8193335533,0.7731699347,0.3516902030,2.3642060757,-1.3887287378,-0.3825967014,0.6642029285,-0.8499180079,0.8090372682,-0.0887294859,-0.7657515407,0.4094007313,-0.2589460313,-0.0710417926,-0.2994653583,0.1474562585,-0.0265487880,1.6107178926,-0.8812941909,0.0249902233,-0.3142261505,-1.5077643394,-0.5018021464,1.0165740252,-0.0183646958,0.3615891039,0.7975444198,1.2121458054,-0.6506839395,0.3548581898,0.2484272867,-0.2789663076,0.5858780742,2.3015351295,1.2746146917,1.0363812447,0.7774479985,1.1028864384,-0.1068114564,0.1970036775,0.1932538748,-0.3952465057,1.1583861113,1.4059976339,2.1219327450,-1.8358495235,-1.2085362673,-1.3249143362,0.4205504954,1.1037262678,0.9093187451,1.4752906561,-0.8287338018,1.0169249773,-0.6972437501,-1.4810217619,-0.7408619523,-0.6186295152,0.5369817615,-0.2822094262,-0.1443003863,-0.7923364043,-0.6148132086,-0.0632172227,0.1186423898,0.3373407423,-1.3994134665,0.5843821168,0.1835361719,-1.3693171740,0.6581259370,-2.2536697388,-0.7097249627,-0.2993446589,-0.7744182944,-0.7150697708,2.7478237152,-0.4464194179,-0.5393986702,0.5048452020,0.0309016295,0.7893177271,0.8253213167,-0.1216339916,0.8358047605,-0.5530250072,-0.6232783794,0.1180848405,-0.5877562761,0.3572616875,0.6083747149,-1.6882966757,0.3013758063,-0.9361636639,0.6878786087,-0.5113450289,1.3853739500,0.2846948504,0.4329951406,0.1250179708,-0.8994542956,0.2352239043,-1.2032506466,-1.7193822861,0.5931987762,-0.9778930545,0.2653068602,0.5067004561,0.5289206505,-0.8424483538,0.3913740814,-1.1664303541,1.4980700016,-2.3028693199,1.2116063833,-0.2439048588,-1.2052580118,-0.2917331755,0.0616047978,-0.6883229017,0.6314316392,0.2147449553,-0.4651604891,0.0913353115,-0.6877609491,2.5887622833,2.2688219547,1.6409702301,0.7080410123,-1.6533527374,-1.6032719612,1.0296443701,-0.1468841136,0.7079297900,0.7750738263,-0.5503200889,-0.1952609122,2.2069025040,-0.3737757802,1.3544288874,-0.1811147928,0.1393500119,-0.1114728898,1.0114481449,-0.6935762763,0.2787633538,-2.0546996593,-0.5709084868,-0.3062367737,-0.3156863749,-0.8897069693,-2.3231439590,0.4797623754,0.0417126454,0.0786912814,0.8310974240,-1.6643717289,-2.1256644726,1.2952638865,-0.9766326547,0.1436393559,-0.7110436559,-1.1480141878,-1.1452629566,-0.8019243479,1.5351486206,2.1707282066,0.7657800317,1.5620862246,0.1756275594,-1.3503173590,1.7917487621,0.7160843611,-0.1938566267,-0.4526286423,0.2835141718,-1.2592515945,0.3630310297,0.3490190506,0.4931244850,-0.8836598992,-1.2861914635,0.6278840899,0.5298740864,-1.4413779974,-0.2835259736,-0.5337915421,-0.5376721621,0.2081073076,0.9799979329,2.2777760029,1.2127616405,0.5642753243,0.0354485251,-1.0789268017,0.1125210300,-0.2152985483,1.7759253979,0.9840850234,-0.0767186433,0.6679525375,-1.0115307570,-1.5240343809,0.1609255522,0.8578897119,-1.6950411797,1.2214843035,-0.1197355837,0.9035636783,-0.2301980704,1.8057299852,0.0134482170,-0.8037886024,0.4452606440,0.1248501688,-0.5301916599,-0.8451347947,1.1502391100,-0.1114130989,1.0182909966,0.1798265725,0.0725538880,-0.0725682154,0.6086733341,0.6504692435,-0.0388825051,0.6453584433,1.5192260742,-1.3471193314,0.3118595779,-0.6958822012,-0.8889675736,-1.8208668232,0.3896815777,-0.2915764749,-0.0712015107,0.4959938824,0.5245856643,0.1248565987,2.2854576111,-0.3773034513,-0.4099958241,0.2611141205,-1.1319282055,-0.8118616939,-0.0755043477,0.8247570395,-0.2658351064,-0.5308529735,-0.5981125236,0.5713994503,0.1442613006,-0.0215171184,-1.5180338621,-1.9154884815,0.9877078533,-0.2374628782,1.3302844763,0.1467256844,-0.2150432318,0.6785774827,-0.7292082906,-0.2542716265,0.4539424479,-0.0867115185,-1.2298870087,-1.1490353346,0.9752449989,-0.1623965055,-2.7027933598,1.0214067698,-1.6213696003,0.4340440631,1.3481116295,-1.2926946878,0.3220206499,-0.6569662094,1.6419132948,0.1643116474,-0.0132283932,-1.8333109617,-0.9346026182,-0.9406163096,-0.9235872626,0.6504324079,0.1044687778,1.2268142700,-0.2209423184,-0.2384083420,-1.2015172243,-0.5316178203,0.1752220094,0.6893568635,0.2345945686,0.4606382847,-0.6025770903,-0.8063659668,-0.5693377852,-1.8322895765,-0.4588719010,-0.4438908696,1.3813488483,-0.7166424394,-1.3205441236,1.6986227036,-0.9610489607,0.7402990460,0.5968779325,-2.0013959408,1.5075762272,-0.0389403030,0.4936818480,-0.3687821925,-0.3875725567,1.2237678766,0.3262037039,0.8998846412,2.1900782585,1.2703543901,2.1951560974,0.2156772017,-1.5663990974,-2.2078025341,0.0685291588,-1.5581027269,-1.0036827326,-1.3702378273,0.1694180816,-0.9137530327,1.0961093903,-0.1972991228,-0.8759288788,-0.5241637230,0.4103074372,0.1449525803,-0.7451390624,0.2333553135,1.1782257557,0.1412797421,-1.4361449480,-0.3597810268,-0.8911457658,-2.2995569706,0.0269727893,-0.5035428405,-1.4560674429,1.7810405493,-1.3310171366,-1.8869807720,-0.2242967784,0.7271280885,0.7559499741,1.4708317518,-0.0475333333,-0.5505061150,-1.2091144323,1.0972720385,0.1798228621,0.0975974947,0.6015082598,-1.5747113228,-2.3804230690,0.2242878824,0.4144230783,-2.0694725513,0.0689833388,-0.8785431981,-0.2263758332,0.2870897055,-0.1257645935,-0.5280503631,-0.6401610374,-0.9018902183,0.6883198023,-0.2870998979,2.0648100376,2.5321288109,-0.1234981641,0.3702547550,1.3969179392,-0.2872636020,-0.5175419450,0.1475308388,0.0770351812,1.0055582523,1.4378954172,-0.5518070459,-0.0454276241,-0.9547314644,-1.7417740822,0.5516366959,1.4494178295,1.2299993038,0.0344757847,0.8050377369,0.1586563140,-1.4417908192,0.8038492203,-0.4616938531,-1.5563237667,-0.2434473038,0.8458123803,-0.3156723976,-0.9523938298,-0.3382590115,0.1520356685,0.3631040454,1.6726390123,-0.6849400997,1.6337143183,0.3757461905,-1.1149408817,-0.1292464733,0.5845023394,2.7107896805,0.1954807341,2.0079009533,-0.3136621714,-1.4966130257,-0.4827790260,-0.5490916967,0.8668015599,-0.4425382912,-0.3470218480,-0.0106614679,0.1458479911,0.9882314205,1.5065393448,1.0266677141,-1.6985048056,-1.2251684666,-0.0537470914,0.6280582547,-2.1100039482,0.0921582580,2.0108947754,0.1368566453,0.2666280866,0.5259639025,-0.5141676664,-0.1254386157,-1.9846127033,-0.6376038194,0.1830519587,-1.3448629379,1.7952604294,-0.6953235269,-0.4445840120,-0.2850975990,-0.6821460128,-0.6116260290,-0.0420884788,-1.1017171144,0.6697148681,-0.3835142255,-0.1298492849,-0.4696798623,1.4395703077,0.0283602029,0.4346496761,0.9028067589,-1.2745651007,-0.8085855246,0.2151665688,1.1069250107,1.0683196783,-1.1012074947,-0.2108737677,1.0316549540,0.0220382344,0.1956191957,-0.0308300909,0.9818850160,-0.9788653851,-0.4604631364,0.7173712850,-2.1900360584,-0.0521114245,0.0403597429,1.2453624010,0.5835828185,1.4235873222,0.9640865326,0.2892068624,0.2281533778,0.1888966411,-0.6644412875,-0.3662932515,-0.4654232264,-0.1265579760,-0.5279335380,-0.2821264863,0.5741770267,-0.9894772768,-1.6030364037,0.5362505317,-0.0642012283,-0.5990480185,-0.3981341720,-0.4884864092,0.8829444051,-0.9191870689,-3.5971634388,-1.1088981628,-0.2825691402,0.0801857784,2.0061070919,0.5381712317,-0.6989403963,-0.6342703104,0.6783562303,-1.7275750637,0.1030801684,-1.1218008995,-0.8425818682,-0.2069326192,-1.2354469299,-0.6567828059,0.1083241701,0.8044376969,0.2656084299,-1.1283918619,-0.7726039886,-0.2678033710,-0.8238725662,-0.7397587299,0.3420245945,0.6743623018,1.0771563053,-1.1560052633,-0.3988094032,-0.2347034961,-2.5536952019,-0.4352763295,-0.7365463376,0.6908099055,1.7416143417,-0.8961228728,1.1003487110,1.5549330711,0.7204515338,0.2944574058,-0.5237665772,-1.2406834364,0.1910576522,-0.5132317543,-0.1078897566,0.2912856638,-0.1775024086,-0.4434978366,-1.6129906178,-0.8831277490,2.1223089695,0.5924318433,-0.1580628008,-1.5093832016,-0.1052221730,0.4946533144,1.3044494390,-0.5286353827,0.5293801427,-0.0658370033,-2.1142232418,-1.6638370752,0.1901883334,0.0722268820,1.6248866320,-0.1596909165,0.9091033936,0.0457334258,-0.1473118365,-1.2650078535,1.2293517590,-2.2262835503,0.8036817908,-1.5079095364,-0.3022215068,-0.5339203477,-0.0028147821,0.9604151249,1.0207607746,-1.7765924931,0.3125726283,-0.5199762583,-0.7035210133,-1.5594059229,-0.9711892009,-0.8094975352,-0.2992601693,0.1038063467,0.4899407625,-0.4866145849,-0.4270956218,-0.1204021871,0.0000380513,-0.7106295824,-1.1571166515,1.2584540844,-0.9098292589,0.4606101811,-0.8967497349,-0.7487707734,1.1330285072,-0.2487686425,0.0485689640,0.9908419251,1.7194275856,1.1388652325,0.4050374627,0.7197656035,-0.0095453719,-1.7850903273,0.2807362080,0.3113456666,-0.4148780704,-0.5144474506,2.3370497227,-0.9018598795,-0.0432650372,0.6294213533,-1.2214990854,-0.3480480611,0.4941302836,-0.8427708745,-1.0920269489,1.1331650019,0.5445849895,-1.9988650084,-0.5136639476,1.5669808388,-1.4852890968,1.1697503328,0.1714032292,-0.1498004496,-1.7167567015,0.2077475339,-0.2835475206,0.6810171008,0.1799054295,-0.3234174848,1.2285729647,-0.2494829297,0.4951613247,1.2835344076,-0.2153073847,-1.5655417442,1.0642517805,-0.4465774298,0.6258028150,-0.4518454075,-0.6958141923,-0.4009466767,-0.7438731194,-1.0151065588,0.2284471691,-0.5200065970,1.7738699913,-0.9808174372,1.6659055948,-1.2655656338,0.1619434059,0.5714436173,0.8214023709,-0.7151944041,-0.7368196845,-0.5527368784,-0.4281289577,-1.3470569849,0.2309796363,-1.1804646254,-0.1970812082,-0.6844750047,0.1222466752,-0.5097717047,1.0388318300,-0.0032982610,-0.9455435276,0.0521331877,0.9406508803,1.4224059582,0.7051896453,-0.0485493839,0.0030716613,-0.0828417838,0.3621097505,1.1506960392,-1.2411286831,0.6016132236,-1.8681024313,-0.2948068678,-0.5459722877,-1.3271028996,0.0146063436,0.0820118934,1.1872184277,0.0226242170,0.5577337146,-0.6835659146,-0.3828615844,-0.0172030423,-0.3059270680,-1.1533372402,0.2937498689,-1.1304335594,-1.5362212658,1.1067888737,-1.7159109116,0.1627099216,3.4915504456,0.8252794743,-0.6337646246,-0.6024153829,0.2472287565,0.0888550505,0.3549385667,0.6885216832,0.0299285725,-0.0664129481,-0.6327346563,-0.1739193201,-0.8258158565,0.1949875653,-0.2163696438,1.0570889711,-0.7573488951,-1.5297939777,0.3537744582,0.3407221437,1.3309781551,0.7501005530,-1.1971751451,0.3842400312,0.1106487289,0.9332572222,1.2433928251,1.0489282608,-0.7144296765,0.3993691802,-1.1924867630,-1.6388714314,0.6282942295,-0.3221462667,2.2317204475,-1.0032519102,2.5989425182,0.7262270451,1.8382234573,1.0665451288,0.6297884583,-1.7966475487,0.2026394159,-0.6314821839,-2.0691819191,-0.3227912486,-0.6972043514,-0.0853688121,-0.7535147667,0.3925627172,-1.5193345547,-0.2938063443,0.3562227488,-0.9631296992,-0.3119919896,-3.0219933987,-1.2542766333,0.3058491051,-0.0131095555,-0.0122315139,-0.0387849845,-1.0967736244,0.5564718246,-0.6666582227,0.3884274662,1.9603561163,-0.5804669857,0.8530720472,-0.3293070197,-0.7811429501,0.5486994982,-0.2156431228,0.4974171817,1.8149178028,-0.0831253380,-0.2076419592,0.4824213386,0.2035827041,0.2575459778,-1.2080625296,-0.9822015166,-0.8012655377,1.1425778866,0.7922763228,1.2311615944,-1.5688765049,0.7047674060,0.2851555347,2.2098674774,1.0570685863,-0.0321040228,-0.1283721030,0.3590631783,-1.3702954054,-1.4281027317,-0.2610388696,0.6530545950,0.4184088409,0.2936683297,-0.1556836814,0.9377830029,-0.1359964013,-0.8170792460,-1.2400767803,-0.4732416570,-1.1670972109,-0.8413016200,-1.4027423859,1.0371077061,-0.8688614964,-0.5326256752,0.5555218458,-1.4648450613,-1.0836731195,1.8800867796,-0.8621342778,0.5107352138,1.9502209425,0.6216194034,0.4190502167,2.2297959328,-0.8208199739,-1.7991086245,-0.6422991753,-0.7526358366,-0.0102676786,-0.6219030619,0.9146863818,0.6332815886,-1.3110525608,0.8213313818,-0.1096853018,-2.4599967003,0.6964056492,-1.6533551216,1.4545164108,-0.0317682959,-0.2366403639,0.8078718185,0.1043894738,1.0441939831,0.5735760927,-0.3592137694,1.6438568830,-2.3127036095,-0.6342550516,-1.0091156960,-0.3238717020,0.1599443555,0.0075996816,1.2957876921,0.1138323396,0.8152285218,-0.6953651309,-0.7397205830,0.2354884744,-0.0152770123,1.1379036903,-0.4955999851,0.6735898852,0.1157289371,1.3253082037,-0.0473974869,0.0749195814,1.1126670837,-1.3454822302,0.5657912493,-0.3173732460,-0.6623814106,0.9390728474,-0.3503127098,0.5224634409,1.7018532753,1.1917303801,2.5286018848,-0.9827714562,-1.7515311241,0.3258644044,1.1894116402,0.2793818414,-2.5151178837,0.2461755723,-0.0248270202,0.8610759377,-1.4125248194,0.9993839264,-1.4585593939,-1.2222012281,-2.5958955288,1.7636417150,-2.3849341869,0.8637584448,-0.1760935038,-0.3307088912,1.3145556450,0.5149357915,0.5830872655,2.3947978020,1.3304606676,2.7539777756,-1.1339077950,-1.7897496223,0.0805313960,0.2522512376,0.2491337359,0.6630885005,0.2543898225,-0.1769705266,0.5460646749,-0.1675920635,0.6434882879,1.2286797762,-2.2995398045,-0.2927011251,0.6443910599,-1.0067539215,1.6835182905,0.9931317568,0.4729190767,-1.1432638168,-0.7436600327,-0.2560135126,0.9444711208,0.7911326289,1.6346222162,-0.1302263737,-1.0289372206,0.0085418718,-1.3331294060,1.1780107021,-0.9500072598,0.6754372716,1.0067199469,-0.8243820071,-1.0483652353,-1.9091670513,0.0497869141,0.2428957224,0.0930123553,0.1747187376,-0.2940579355,-1.8441371918,-0.6564555764,-1.3747949600,-0.2950574458,-0.5911638141,-0.9996911287,-1.0452963114,-0.8234270215,-1.3071545362,0.4519526660,1.1589044333,-0.5272555947,0.4144105017,0.9806813598,1.7847551107,-1.0145297050,0.5712207556,-0.5980527401,0.5029620528,-0.0612854436,0.7624505162,-1.3226306438,-0.4346112013,0.6056466103,-0.0498499461,-0.3783754706,-1.5018903017,0.0628009811,0.6265262365,0.8333978653,0.3140480220,0.0424722657,-1.9600057602,1.5053578615,-1.9780138731,-0.5857676268,0.6841420531,0.6114683747,-1.3019052744,0.2540067136,0.9127832651,0.4417865276,1.2836414576,0.1039965823,1.2140318155,-0.5549297333,-0.4985508621,0.6292501092,0.3685869873,1.1157144308,1.5523375273,-2.3205018044,0.5883346796,-1.6743589640,-1.3808029890,-1.1486417055,-0.4540960789,-0.2932817936,-1.0938034058,1.2470657825,0.1483083218,-1.3925426006,-0.8331165314,-0.2666631341,1.5057089329,-0.8068805933,-1.0885897875,2.3916010857,-0.4042384028,-0.4770764112,-0.1564542800,-0.6575467587,0.2871340513,-0.0035539989,-0.1058869883,0.1488221437,0.3605379760,-2.4916563034,-1.5001876354,0.4150368869,0.8202406168,-1.4984824657,1.2506990433,-0.9239646792,-0.9689198732,-0.6747028232,-0.9625166059,0.0919773877,1.7888215780,-0.3183748126,-1.5616273880,0.7808475494,-0.0725234970,0.7236689329,-0.8480882049,0.4332070053,-0.7184300423,-0.5073258877,-0.7155088782,0.1922626346,-1.8225835562,-1.5416775942,-0.4609018862,-0.4596909881,0.2107827514,-2.0516586304,1.5195232630,0.8270009756,-0.3949391544,1.2474613190,1.3624265194,-2.0977537632,0.3367308080,1.3497856855,-0.1149254441,-0.1106928810,-0.6452971697,0.4695451558,0.0963989571,-0.2132138759,1.3956539631,-0.4724814594,-0.8594051600,1.8760187626,-0.1349168271,-0.3604379296,0.4938758314,0.2165178359,-1.3356113434,1.1783431768,0.1670271158,-0.0458714627,0.2959707677,-0.8548012972,-0.2733450532,0.4309072495,0.5981340408,-0.6337695718,0.1154701039,-0.1036763787,0.8955789804,0.3470619619,0.3223627806,0.6703640819,0.3695249259,-1.2931357622,2.0881593227,-0.3163700700,-0.0996335223,-0.0413534530,-1.4175074100,-0.5930390954,0.4457131326,-0.1496128440,-0.1687347889,0.3874080181,-0.8589089513,-0.5768976808,1.7151972055,-0.6996167898,-0.2785257995,-1.0260729790,1.3125190735,0.2768625617,0.7143705487,-0.2726789117,-0.0571496300,-0.0628784820,-0.7734673023,-1.7554893494,1.3222324848,0.8918345571,1.3041300774,-1.3633157015,0.0353974849,0.3286035955,0.6159794331,1.3449649811,-0.0227691717,1.6639068127,-1.9228399992,0.5120229125,-1.0251792669,0.6372367144,1.5930398703,-0.6409438252,1.4217171669,0.0658135042,1.8625446558,0.6787316203,-0.4409461915,0.1394979209,-0.7030583620,0.7338191271,-0.7291454673,-0.3782072663,-2.8154554367,-0.8627194762,-0.8333143592,1.2222462893,0.8411992788,0.3509971201,0.2359188348,0.9166232944,0.0066510001,1.5729032755,0.4003543556,-0.4913519323,0.8445338607,0.0200802702,1.0654255152,1.3981710672,-1.6055946350,0.0228539519,0.8410942554,-1.5818178654,-0.3087835014,-0.7839787602,0.8243343234,-0.9782735705,-0.1291076690,-1.1661448479,1.2579156160,0.3912162185,-0.1826521456,-1.5388045311,0.0681304187,0.7006773353,0.0295840409,0.1992514282,0.2526450753,-1.8144961596,-1.1816760302,-0.9918892384,0.6096387506,0.2016691118,-0.6762703657,-1.3589177132,0.7350046039,-0.1993409395,-2.6887750626,-1.2836247683,1.9510684013,0.1622150093,-1.4023469687,1.4098094702,0.0630933121,1.0961402655,-0.8833422065,1.8702621460,-0.1089891195,-0.3058429062,-0.7081920505,-0.3911435902,-0.7089096308,1.9077292681,-0.5598803759,0.9991017580,0.7150085568,-0.3869202733,-0.9710565805,-0.0675847158,1.1329613924,0.6529337764,1.2304496765,1.1190041304,-0.9004789591,-0.0169585124,1.5388683081,-1.9974298477,-0.0319209136,0.2239657640,0.9455083609,0.4229235351,-1.1756800413,-0.2048513144,0.9564954638,1.5861339569,0.7912840247,-0.5508337021,-0.6716780066,-0.6968273520,-1.3961554766,-0.5600498915,0.3246770799,1.4076087475,-0.0798354521,0.2515286505,0.4909705818,0.3263372183,1.4774889946,1.0507353544,-0.5025584698,-2.5827465057,-1.3963918686,0.3938339055,0.1324110627,0.6092009544,-0.6405442357,1.0710233450,0.9779106975,0.9465399981,-0.9084601998,-1.0478686094,-0.1336563677,-0.9601236582,-0.2246695161,-1.3933295012,1.6808741093,-0.8732835054,-0.4315283000,-1.2740129232,0.4324110150,1.1807173491,2.5027995110,-1.1592706442,2.4850172997,1.2996827364,-0.1811547577,-0.4567832351,0.0583423376,0.4886063039,1.9107813835,-0.4104271531,0.7122089863,0.1199572161,0.7052668929,0.1382817328,1.1929559708,-0.1740968972,0.9283349514,-0.7982419729,-0.6423220634,1.1604852676,-1.0541092157,0.7567608356,-0.1418243349,-1.3702803850,2.9446048737,-1.4440181255,-0.0868617892,-0.4741066694,-0.8283151984,0.9016938806,-0.1963388175,-0.6778028607,1.1174887419,0.2317363173,-1.0282225609,-0.2005127370,-2.2192344666,0.2017867267,0.0493783355,1.3375517130,0.4729900658,-0.7144607306,-0.9983495474,0.6037179828,-1.8254740238,0.2400026470,0.2330179662,2.5256221294,-1.4175472260,-0.3735436201,1.6245576143,0.2052359134,0.6497414112,0.4077384174,-0.2230141908,-0.7564809322,-0.0916129127,1.0873105526,-0.2665374875,-0.5684608221,-0.7968423367,-1.6703445911,-0.8607365489,0.3183925450,-0.9658346176,0.0435120389,-0.5150961280,-1.1097168922,0.1698560864,2.9419577122,-2.3477473259,-1.3247072697,-0.4962736666,-0.1773999929,-0.0164038111,2.5538542271,1.7659779787,-0.0989361107,0.3340937793,2.1344652176,-0.4907274842,0.1163907647,-0.2446371317,-1.2983027697,-1.7936493158,-0.6849700809,0.8144246340,0.3181484938,1.9092911482,0.8085999489,0.7802957892,-0.0886350796,-0.2588721514,0.0695181787,0.3667381108,-0.3762246370,0.2074953020,-0.3414714932,0.1384399831,-0.7856284976,0.5178771019,1.3630260229,-0.6483896375,0.8072376847,-0.3309074640,0.2732403576,0.5953650475,0.4950374961,0.4725801349,-0.8133680820,0.4031637311,-0.8463309407,-1.2494440079,-0.7790490985,-0.3001246750,0.7606703043,-2.6036124229,0.2312413156,0.0621792115,1.3174229860,-0.5900319219,1.1107158661,1.0482529402,-0.2892859876,0.2211965621,-0.8559523225,0.0115584433,-0.9336676002,1.9462053776,-2.1260342598,0.2948924899,1.2464601994,-1.7223078012,0.8161273599,-1.0551950932,-1.0623240471,0.6164644957,0.6140427589,0.7598878741,1.3047753572,1.5473181009,-1.1017062664,0.3287614584,0.5281797051,2.5536885262,0.2077630758,-2.2922198772,-1.4933623075,-0.2370071262,-0.7327952385,2.1606707573,-1.1783447266,-1.3211505413,-0.7479308844,-0.5706911087,-2.5351402760,1.1879647970,-0.6937165260,0.0836460069,-0.5761220455,0.9647812843,0.3790502846,-0.5369278193,-0.9889282584,-0.0713329986,-1.9731627703,0.0177028272,-0.0183720831,0.3783574998,0.0163121391,-1.3108023405,1.7357823849,0.8464573026,-0.3903010786,-0.3368534148,0.4967666566,-2.7908391953,-0.3965183496,-0.3624084890,0.4881130457,-0.1702686101,-1.1690906286,-1.8261866570,-0.4230371714,0.4788505435,0.4658548534,0.2310337573,0.0985355750,0.4738362134,-0.7344447970,1.2384089231,-2.6306266785,-1.5320723057,-1.2753394842,1.5467416048,1.6379555464,1.0030064583,0.9898139834,0.0424625278,-0.4771284163,1.1298083067,0.6710648537,-0.3274264336,0.7314128876,-0.8347561955,-0.2209829986,0.8305916786,-0.1107638553,-1.0064861774,-0.7868315578,0.2856790125,-1.1872032881,-2.6854472160,1.1837202311,-0.5017939806,-0.7630453706,-0.7599319220,-1.7406020164,-0.3569377363,-0.3295323551,0.1544053108,-1.6152344942,-0.7816680670,0.9302698374,-0.4331679344,-1.4746901989,-1.2758826017,-0.8955430388,1.1119370461,-0.4404303133,-0.2563897967,-1.3007929325,-1.0545949936,1.7923588753,0.5344469547,-0.1055984795,1.2540366650,-0.1275109500,0.1339087486,-0.2487187982,-0.4006001949,-0.2114236802,1.1732668877,0.5091586113,-0.1582694799,0.6916762590,-0.1102267802,0.2098225951,-0.2684221864,-0.2210887969,1.4088248014,-0.4681519568,-1.2454816103,-0.7584915161,-0.5442646742,1.2987605333,-0.0903712809,-0.7038058043,-1.8618180752,1.3913886547,-2.0506701469,1.0668116808,1.0024168491,-0.9046353698,-0.3053961098,-0.2314878851,-0.1263826787,-0.8304456472,-0.8061316013,-0.2422748208,-1.9520103931,-0.7236518860,0.4473903477,0.1257790476,0.6045052409,-1.0181647539,-0.2301247269,1.0518794060,0.2211459726,-2.1039614677,0.4767338634,-0.5758100748,-0.7040908337,-1.3656538725,-0.9187939167,0.1141875982,-0.0630888268,0.9285331964,-2.3116347790,-2.1702721119,0.6343227625,-1.6013319492,-0.2154222429,1.5275949240,-0.6772807837,1.9274326563,0.7861020565,-0.2652913034,-0.8883908987,0.2253436595,-0.5352017879,-0.5620777011,0.5740081668,0.3111010194,1.5274264812,-0.3963585198,-0.2029903829,1.3392060995,0.4060575068,-1.0550361872,-1.0509568453,-1.0039232969,-1.6214109659,-1.1161359549,-0.5431999564,-1.6879911423,2.1472158432,-0.5342582464,-1.1732395887,0.2828506827,0.6968113184,-0.3553364873,-1.3209646940,1.4841766357,1.4951782227,-0.0843770579,-1.1510633230,0.2676264048,-1.9190896749,1.3373588324,1.0322799683,0.4293705821,-1.0973135233,1.1228461266,-0.1259989738,-0.3956427276,0.5731127858,-0.7413690686,0.0254712421,-0.1747244149,-0.6090978980,-2.3484940529,-0.8988916278,1.0013848543,-0.6178749800,3.2145085335,1.7016453743,-0.1834490895,0.3850836754,2.8780665398,-0.3341577053,-0.3734532297,-0.1130664498,0.1813558340,-0.5761479735,-0.5341535807,1.4379769564,0.0405320339,-0.6183389425,0.4018271565,0.3525454700,-0.6058232188,-0.5648207068,0.0922305062,0.1551928073,1.5452309847,-0.9681372643,-0.5784638524,0.3552555740,0.4516860843,-1.9098737240,0.2499908358,-0.8666939139,0.8051800728,-0.8144145608,-0.2480166554,0.1575364619,0.2941561341,-0.1956454664,-0.3580013514,-0.9503346086,-0.6282243133,-1.3779340982,1.5391281843,0.0974658281,-1.5649412870,0.6169933677,-1.5744905472,-0.8908445835,-0.0382696539,-1.0136801004,-0.2685077190,0.4745731056,-1.8531562090,1.5317523479,0.6800500154,-0.6525881886,2.0080859661,-1.0958909988,1.0522122383,-0.3234107196,1.9245126247,0.3289987743,-0.1973149925,-0.1600109935,-0.1019958928,-0.1369468868,-0.3338777125,-0.4217321277,-0.6276172996,-0.0088310521,0.2495359033,0.6251870394,0.2042882591,-0.0481986813,-0.4357247949,0.1891266406,0.1527542472,-0.3866901100,1.0209299326,0.6823812127,-0.6945874095,-0.7691562772,-0.5777331591,0.0130191892,-0.8398479819,-0.2155789435,0.4451689422,-0.2670453787,0.1741062254,-0.5216994882,-0.8992028236,0.3179417849,-1.7559511662,2.4414460659,-1.0115315914,-0.7715908289,-0.3075437844,-0.6755710244,-0.6566454768,0.3051428497,-0.1559470147,-0.4731896818,-1.5133440495,-0.9692866802,0.1147779524,0.1330191642,-1.4187124968,-0.2106103599,-2.4852890968,0.3849193454,-0.4459509850,1.0283155441,0.4236266315,1.1467685699,-0.4037198126,-0.0717719048,-0.8492287993,0.8758452535,0.1124814972,-0.1776066273,1.2060687542,-1.8546257019,1.0201659203,-0.8215023279,0.0630850345,-1.8618688583,0.1551971585,-0.7597349882,-1.1710904837,1.4031120539,-1.3759285212,-0.4247080982,0.4434662163,0.4800909758,-1.3437353373,-0.3794100285,1.7216287851,-0.4607748687,1.8423278332,0.3057335317,0.5179230571,-2.2636806965,-0.4333676398,1.2896549702,-0.4285718203,-0.8006920815,-0.4375852048,0.5202440023,-0.9587842822,-0.5118048191,-0.9421377182,-1.1184242964,1.6118689775,-1.2746709585,0.7071536779,0.1218064204,1.1981039047,0.6363534331,-0.0728155077,0.9757786393,-0.4173601270,-0.0015435452,-0.7620249391,-0.5343719125,0.4405129850,-1.3240416050,1.4426378012,0.4065026343,1.5632677078,0.0156175345,-0.4524750710,1.0752927065,1.2035952806,-0.8711138964,0.2041112036,0.2468991578,-0.1774842441,-1.1503459215,-1.2382020950,2.4137120247,1.1750917435,1.5967836380,-1.6567083597,-2.3314807415,1.3394186497,-1.0232579708,0.9828591347,0.6385476589,0.6664152741,-0.1034429669,1.0297343731,0.2680951357,-0.5350618362,-0.4283976257,-1.2094867229,-0.1973341703,0.5106055737,1.0990395546,-0.3337288201,-0.4588372409,-0.8280749917,-0.2634945810,-0.7192752361,-0.0046136426,-0.2803740203,1.8313490152,-0.2697892189,1.5935767889,-0.6038568020,-0.1862212420,-0.2486424148,-0.1683999300,-1.2148817778,-0.4478370547,0.3814966083,0.3098362982,0.3672737181,-0.5108301640,-1.1260827780,0.4522577822,-2.3199803829,1.2764129639,0.0071071084,0.8953126073,-0.1732992828,-0.8343470693,1.2000719309,0.6027942300,0.0065583684,-0.5235270262,1.4073104858,1.5511393547,-0.6028784513,-0.6788135171,-0.4255207181,-1.2978883982,-0.2149679661,0.1982887536,-1.8132313490,-0.7148556709,0.9376966953,0.0934126228,-2.2183358669,0.2135851234,0.9191421866,1.0439063311,0.9127506614,-0.5701822042,-0.5769571066,-0.3889191747,0.8824122548,-1.0307428837,-0.6692697406,0.4454301298,-0.3818296790,-1.5339218378,0.3329823315,1.0650533438,-0.7414758205,-0.1798739582,-0.3133811057,0.0330814943,0.8718146086,0.3320226669,-0.5496357679,-0.6352506876,0.4852578044,-1.3856655359,-1.0167318583,0.3205580413,0.4294673502,-0.7857626677,-0.1906618029,1.4213653803,-1.3946044445,0.0078004524,-1.0760178566,1.2182247639,-1.1788051128,-0.3671139181,-0.1223488450,-0.6729784608,-0.3291174173,-0.0389075093,0.5921736956,-1.6977338791,-0.2491133809,-0.4006183147,-0.3961207867,1.5913404226,-0.5850166082,0.9393358827,0.4974382520,-0.4705432653,0.4906757176,0.0837168992,0.3925708830,-0.5851889253,1.0661809444,-0.4824724197,-0.2261067629,1.2158709764,-0.1601240784,-0.0983043760,0.5352964401,1.6688851118,-0.5516088605,0.1419655532,0.3875458241,-0.3246272802,-0.5487880707,1.0352808237,-0.3842982948,1.4187676907,-1.3117232323,0.2935632169,0.6130684614,0.4549064040,-0.8751249909,-1.3332929611,-0.8147768974,1.0529824495,1.2756927013,-0.5867362618,2.0169563293,-0.2070715725,0.8094360828,-0.0061388025,-0.2174635977,0.9481768608,1.2745907307,1.1427247524,0.0107475081,0.3241678476,0.3622403741,2.0765511990,-0.8151247501,-0.0743439496,-0.9019891024,-0.0548304245,-0.4506755173,0.7100703716,-1.0151324272,1.8718290329,0.6454366446,-1.4716508389,-0.7614647150,-0.6045665145,-1.5807316303,1.3683742285,-0.7087847590,-0.5360591412,-1.1137635708,0.0546837524,-0.2155482918,0.0912592858,0.5711795092,-0.5264383554,-0.2848584652,-0.9425686598,-2.4303109646,-0.1181594357,-1.4667463303,0.9932658076,0.1965706199,0.3686066270,-0.3189594448,-1.3668688536,1.0229911804,0.3237343132,-1.1159375906,1.0948339701,-0.7159814239,0.9033344984,0.6435657144,-0.1155977696,1.0557695627,0.6256161332,-1.8282810450,0.8863859773,2.2530357838,0.9894797206,0.0942059904,0.0559607707,-0.6437538266,-0.5194265246,-0.1113528311,-0.5954051018,0.0305511039,2.0396575928,-0.9323299527,1.1999788284,-0.1505632401,-0.0716161281,-0.1202129871,1.6836475134,-0.3819015920,1.0422122478,1.2395704985,-1.1008722782,0.3359590769,0.3583621979,0.3088277578,-0.7779789567,0.2468801737,-0.0547442622,-1.1857970953,-0.7717460394,-0.6387051344,0.5602406263,1.7625153065,-0.0663885921,-1.3087264299,-0.6310637593,-0.0381813124,-0.6173859835,0.3789446056,-0.2139604241,-1.1707614660,1.3018363714,0.7095224261,-0.0035795420,0.1458305418,0.0410517007,0.2223228961,-1.1324160099,1.3681198359,1.0462281704,-1.5376925468,-1.6998412609,1.1517218351,-0.2828924060,-0.1268702596,0.0175452475,0.6152723432,2.9246551991,0.0550507084,-0.4084461927,-0.4082174003,-0.0883197784,-0.6834801435,0.1403120756,-0.0701343417,-0.5488973260,-0.7441422343,0.0780278295,-0.5865127444,-1.9822689295,-0.5372510552,-0.1041933000,-1.2280911207,0.8918114901,0.8050571680,0.7902606726,0.1689276099,0.8103792071,-0.3139070272,-1.0741906166,0.8703773618,1.0449312925,-1.3065792322,-0.3290812373,0.0967386067,1.6248611212,1.0085247755,0.7625691891,-0.6881162524,-0.0375259668,-0.1837271601,-0.5998256207,-0.6495984197,1.8604087830,-0.3011618555,0.7878006101,0.3329676390,0.0409335904,-0.9390720725,1.2049945593,-0.1606714725,0.6641917229,1.1545108557,-0.4691017270,0.9510985017,0.3453378379,0.6326152682,0.8411407471,3.3795402050,-0.5579387546,-2.2784161568,1.2684965134,-0.1679872721,0.5747269988,-1.2267564535,2.6995685101,1.2447136641,2.0237715244,-1.2390452623,-1.2545794249,1.7316627502,-2.1253314018,0.3927900195,0.7085506320,-0.8432416916,-0.0852408782,1.6294378042,-0.6161226034,0.9238883257,2.0524621010,0.8227902055,0.4947157800,0.8637558222,-0.2730913460,0.8136610985,-0.3739970922,0.4879109561,1.6569792032,0.3815992177,-1.2899910212,1.9640835524,-0.0580297746,-0.1557988226,-0.6913321614,-1.4017077684,0.3727024496,-0.6369473934,-0.6303749084,-2.6259300709,-0.0493691675,-0.9832947254,1.0024470091,-0.3762393594,1.3069745302,-1.2268050909,-0.7823822498,-0.0879970342,-0.1371357441,-2.0683543682,1.3137185574,-0.5420494080,-1.8690586090,-0.4229525030,1.2428137064,-2.0199379921,1.1582741737,0.3339900672,-0.1540900767,-0.3291948736,0.5431203246,0.5548845530,0.8049129844,-0.9914619923,-0.2426926792,0.4396611750,1.1291645765,1.5539902449,0.0206491835,3.1093180180,-0.6115761995,0.6421800256,0.3549148440,-0.5587056279,1.3602957726,0.8574593067,2.1869783401,-2.0839545727,-0.1410952508,-0.2207788825,0.3456647098,1.7722004652,0.2104642242,-0.0937629715,-0.6939895749,-1.4438390732,-1.4316949844,1.3473109007,1.1719737053,0.1000234857,-2.5027976036,0.5600686669,-1.7411983013,0.6763187647,1.1642938852,0.1111669838,1.0283162594,-0.9822398424,-1.5453110933,-0.8225803375,-0.6440979242,-0.0711455941,1.9552521706,-0.3010765314,-2.1804435253,-0.4159669280,-0.2086515576,0.0323335044,0.7367733121,-0.1938336194,0.0218441971,-0.6198917031,-1.2360179424,0.0325217918,-0.1815406382,-0.8679505587,-1.2398601770,2.7161452770,0.8557375073,0.0299651753,-0.4124097824,1.7006686926,-1.1124067307,0.0908856541,-0.1516654342,-0.2011841089,-0.8780253530,0.1487515718,-0.1081603616,-2.6986460686,-0.6502318382,-1.3820240498,1.3549199104,0.2082520574,1.0158964396,-0.3602983356,1.0314747095,0.7706522346,-1.4677193165,0.4941012859,0.4933527708,-0.7369694710,0.5938832760,-0.9388635159,0.3698066771,0.1977473944,2.0577509403,1.8244630098,-0.6621942520,0.9831089973,1.8373091221,-1.7026886940,-0.0270229913,-0.7254310846,-0.5342456102,-0.2495466620,0.9207409024,1.1019066572,1.4010708332,-0.4718470275,0.7765082717,-0.2912778556,0.3498292863,-2.7129755020,0.3319345415,-0.4187539518,1.3095924854,1.1868669987,0.8806769252,0.3419238627,0.3971645832,-0.5310337543,1.2703276873,1.2536746264,-0.2384586930,0.7138925791,-0.6958540082,1.0730539560,1.0104210377,-0.2720271051,2.4342498779,-0.1827040464,-1.1780284643,1.5289424658,0.2870815396,1.0993279219,1.0624066591,0.9699524045,-1.5428931713,-0.3731743395,-0.9524514675,1.6522585154,-0.6506668925,1.8939784765,0.7598444223,-1.4891389608,0.2364653498,-0.4037335515,-0.3316952884,0.4112060368,-0.4684414566,-1.5352321863,0.7067044377,-0.2318485826,-1.1240425110,1.5368109941,-0.1835157275,-0.4744376838,0.3413875699,-0.6717487574,0.7119252682,-0.2505222857,-1.0557770729,-1.3723297119,-0.3597370386,-0.4294839501,0.7981411219,0.1716908067,0.7857249975,-0.2756601572,1.3481935263,0.1696635783,0.4440221786,-0.8391209245,0.4513442814,-1.5586638451,-0.3483391404,-0.8522367477,1.5907986164,-0.3074297011,0.2480690479,0.7581233382,-0.5760253668,-1.8630077839,1.0422192812,-1.7398986816,1.2222512960,0.5329426527,-0.5442413092,-0.4942600429,-0.8551141620,0.0436583534,-0.5721877813,0.6107054353,0.3239576817,-0.7967873216,-0.6653596759,-0.9299156070,0.5174583197,2.7006502151,0.0948338807,0.5206369758,-0.3405960500,-1.6355158091,-1.1801077127,-1.0089060068,0.8826825023,0.8409978151,0.5379786491,-0.8869519234,-0.6959516406,0.8970693350,1.1439201832,0.2837764323,0.6520831585,1.5538183451,0.9409436584,1.6984336376,-0.2489234060,-0.4934352338,1.1103788614,-0.0425555967,-0.2637329102,2.3317098618,0.1342730075,-1.1002831459,-0.3531531394,-0.9949698448,-1.2437766790,-0.3254702687,-0.2078438252,0.6164678335,1.4852756262,-0.6047641039,-1.6532808542,0.4184491634,-1.6963517666,-0.2338368893,-0.7228124738,-0.1625349373,-0.4308318496,0.0099216374,0.4700077772,-1.2281514406,-2.7309982777,0.3110759258,0.4845410585,-0.2558689415,-0.7635210752,-0.3534634411,0.9853637815,2.0035877228,0.1427997351,0.3458914757,1.1226363182,-0.4557880163,-0.7759872675,1.3420548439,0.0752204135,-1.5103042126,-0.0915874243,-1.2788894176,-0.2196186185,0.2062564492,0.2331690490,0.2155169100,-0.5119232535,0.2016098946,-0.2278685421,-0.6937284470,-1.1732790470,-0.2774077356,-1.6016391516,1.0906006098,-1.1602990627,1.1262484789,-1.0025730133,0.0271053445,-0.2579020560,0.4614878893,-0.1589870751,0.1840162426,-0.6898531318,0.0125418641,-0.4625565112,-0.8035131097,-0.2153994441,-1.3669756651,-0.3434249461,0.2921564877,-1.1370795965,1.9588086605,0.8582231998,1.3342782259,-0.1519452184,-0.1291483045,-0.6357197165,-1.1396441460,0.8062340021,-1.2459180355,-0.9046903849,-1.2425501347,-2.1115393639,-0.4970543683,-0.8733558655,1.1578514576,1.0069839954,0.4968858361,0.3666149080,0.6556609273,-0.3875073791,-0.5488761067,-0.0836496875,2.0249290466,-1.0677149296,0.3628509939,0.3246399462,-1.1875450611,0.2687779069,-1.0852653980,0.7550567389,-0.4066241086,1.2095012665,-0.1736595035,-0.3596734703,-0.6551199555,0.3217178881,0.3877495825,-0.5331507921,-0.5281913877,1.2084648609,-1.3032892942,0.7628052235,-0.1079162583,0.4455998242,1.1350136995,-0.1589067131,-0.6414845586,-0.6046472192,0.9702689648,0.7563495636,1.1022398472,0.9599217772,0.3824656308,-0.2513045669,1.9816982746,-0.1709746271,2.5292274952,-0.0726553649,0.8528701663,-0.2167818695,-1.1923350096,0.7861623168,-0.1764873415,0.5312441587,-0.6337814927,0.5093117952,-0.6839939952,0.5782969594,1.6045950651,0.8131929040,-0.7173815370,-0.3780921400,1.3238222599,-0.5112685561,0.0101344641,-0.2775341272,-0.5660531521,1.0679335594,0.1818200201,0.0210486110,0.2730336189,0.9373193383,-0.5658476949,-2.9819197655,-0.7312950492,-0.6392739415,0.3130269647,1.3852910995,-1.7225570679,-0.1778837144,-0.2917789519,2.5960144997,-2.0717620850,-0.5658675432,-0.1349422485,-0.6983388066,0.0349466354,1.1256330013,-1.4770747423,-0.5363630056,-0.2403480560,-1.1767562628,0.1195749193,-0.2448243648,0.5246302485,1.8328498602,-1.3843655586,-0.0110265408,-0.0536559224,-0.0643325523,0.1795994788,-0.9816644192,0.3176301122,-0.1802364588,0.9853456616,-1.1633157730,0.0661375895,0.1401054561,1.1376334429,-0.4585750997,1.6170740128,-0.8622001410,0.0746508464,-2.0770630836,0.9686267972,0.2395104170,0.7997642159,-0.7137439251,-0.4591530561,1.0764036179,0.7686495185,1.0426416397,-1.1665842533,-0.0190958213,0.2914540172,-0.7461980581,-1.0264773369,1.1318042278,-0.6412966847,0.4828600883,0.4435411096,-0.2497335821,0.7211852670,-0.9790833592,-0.1474432647,0.5849481821,0.3871085644,-1.6994421482,-0.9294052720,-0.4046594501,0.0394828208,-2.2656846046,0.8610637188,-0.5293418169,-0.9234024286,-0.7983475924,0.3869788647,-0.0125233578,-0.6018054485,-1.5917366743,-0.6404822469,-0.8488659859,0.3502156138,-1.9618258476,0.4609496295,0.7993075252,-1.2686504126,-2.0727105141,0.4813488722,2.2085037231,-0.1328210086,-0.1219409853,0.7389209867,-1.2908295393,-0.6629701853,0.0689686611,-1.8911678791,-0.0095606102,2.2362875938,-0.2920475602,-0.4304375947,0.6180891395,0.3166204989,-0.2677041590,0.7496351600,-1.5953862667,1.6120036840,-1.2561944723,-0.2658331990,-1.6532055140,0.3250307441,0.2280231416,-1.7944575548,0.9863104820,0.9655084610,-1.2732337713,0.8295410872,1.7446888685,0.4547727108,0.9031069279,-0.0009527904,0.1082891300,0.0627697557,-0.7638112903,0.1184428260,-0.6439966559,-0.6934063435,-0.6369379759,0.0757776573,-0.3329806030,-0.8138238192,0.6588058472,0.0405100137,-0.7962877154,0.1916862875,1.6392009258,1.5568352938,-0.2725393474,0.4475654662,-1.8609107733,0.2686832845,0.5630605221,-0.8181628585,0.7510074973,0.5397127867,0.1188118681,-1.5726583004,1.1463209391,-0.1599459797,-1.5908477306,1.1402555704,0.0534986258,0.6712822318,-0.2257112414,0.2104907334,1.2600893974,-0.8423901200,0.4301144779,0.0580476858,-0.1085274071,0.2783560753,-0.1843588799,1.1259652376,-0.9875113368,-1.3340691328,-0.2070790976,1.1330128908,-0.5045336485,-0.0493099913,-0.9911766052,-1.0161695480,0.6145914793,0.2172343433,0.8915202618,0.7863522172,-1.5050923824,-0.4608986676,-0.9159309268,-1.0463711023,-0.4841423333,1.4623806477,0.9499843121,0.1457133293,-0.0732988268,0.4994755089,0.0105162933,-0.9202109575,-1.7985740900,-1.8778783083,0.1385161132,-0.1998910755,-0.6571277976,1.3705222607,-0.0393945649,-0.6115819812,0.1122607738,1.7633579969,1.1450352669,0.0145209311,0.4134386480,1.0941917896,-0.7587047219,0.1511386931,0.8067439795,0.3308694363,0.8130151629,-0.4325229824,-0.3996813297,0.7124310136,0.5596027970,1.2407661676,-1.5103613138,-0.7653915286,0.4409960806,-1.3893051147,0.2526411414,-1.5413987637,2.1944396496,0.6292828321,-0.8632075787,0.2486867309,-0.4590431452,-0.9867677093,0.3626977801,-1.0730080605,-1.6345175505,0.2953622937,0.2162745744,-0.2574618161,-1.3549469709,-0.6115554571,0.7602116466,1.9480760098,0.9903740883,-0.2730256915,-0.9925105572,1.0541404486,0.2880633175,-1.1912264824,0.8099787831,-0.1467864662,-1.1243214607,0.2368906140,-1.0483739376,1.5535750389,1.7349170446,1.7200393677,0.4215571284,-0.5391463637,0.7642809749,-1.4886449575,0.7880499363,-0.1383967400,0.2078452259,1.2732071877,-1.3002576828,0.4559438527,-1.1586076021,-2.5392279625,-0.1181192771,-0.1082064211,0.5446758866,-0.0360974520,0.7261715531,2.2089526653,0.2038448453,1.1848708391,0.0747086108,-0.3506720662,-1.0089811087,0.4365611374,0.2272382379,-1.2056691647,0.1030338556,0.8712006807,-1.4377597570,1.3927700520,-1.1165030003,0.1298575550,-1.0141154528,0.0596608967,-1.4940531254,-0.2160215676,-0.0512839481,0.9271569848,-0.4844455123,-0.2318405509,0.6599657536,-1.7151789665,0.7706661224,0.0119470004,0.9035109282,-0.1867048591,0.0665158778,0.8442751765,-0.0485997386,0.5673190951,-0.2960724831,-0.1498709619,-0.4024744630,-1.2394433022,1.5663323402,-1.0304254293,-1.6466841698,-0.8810069561,-1.1049762964,-0.4639779627,-1.5220855474,0.2335274220,2.7803463936,0.0539885126,0.9135933518,-0.9690374732,-0.1095990017,0.1958942860,1.7529040575,1.5590376854,1.5509411097,0.8768229485,-1.7840468884,-0.1732115000,-0.6301497221,0.3956625164,2.3877656460,-0.0268936399,0.5478615761,-0.5379067659,2.1843235493,-0.5380644202,-0.5254244804,0.5818068981,-0.7079021335,1.3369965553,0.8060417771,-1.6658140421,-0.5134732127,0.7067216635,0.8297515512,-0.4131700397,-0.2021587193,-0.5879874229,-0.7992437482,-1.0584437847,-0.8227606416,0.3689611852,-1.1542803049,-0.0566550530,1.3873462677,0.6274378896,1.1806343794,-0.0127347568,0.7829507589,-1.7611320019,-1.8452315331,-0.4864417017,-1.2627916336,-0.9706924558,0.1326923072,-0.0447083339,-1.2672939301,0.5071989894,0.1937571317,-0.4156983495,-0.7045055032,1.5209288597,1.0463624001,0.2856897712,-0.2598487735,0.3661739826,0.5295231938,-1.4221961498,-0.8767566085,0.6296004653,-0.0801178962,0.6200874448,-0.5689187050,0.1718118489,-0.3422384560,-0.9554112554,-0.2749791145,1.5549792051,0.0348670818,-0.6264494061,0.4486315846,0.1790567935,-2.0919644833,1.0272736549,-0.3224200904,1.3721137047,0.0656904429,0.1180860549,0.1220767125,-0.1829499155,0.5675747991,0.8053595424,1.9218912125,-0.7440114021,0.0348815545,-1.8749556541,-1.4344085455,-1.3828809261,-0.0116490088,-0.9548451304,0.2953458726,-1.4136312008,-0.9416632056,-0.5594043136,0.6049207449,1.0211660862,0.2590726018,0.9106184840,-0.2311110795,-1.2518192530,-0.7415366769,0.4421019256,1.1234837770,1.3203134537,0.6332851052,0.5463161469,0.2642716169,-0.5631567836,0.2989800274,0.3328503370,-0.4342570901,-0.8483982682,-1.7796927691,0.0795050189,0.7186124921,-0.6157069802,0.1147888228,0.0838786140,-0.2524175644,2.8837597370,0.8444882035,-1.9462414980,0.7658838034,-0.4896616936,-1.7648249865,-0.3483499885,0.8363187313,1.1675939560,0.7815184593,-0.5237451196,0.0220253151,0.6432757378,0.2756863832,-1.3450036049,0.0794675127,-0.4446147978,0.4111537635,-2.1214573383,-0.7913644910,0.6275324225,-0.1632787734,0.3176547289,1.3256460428,1.9135844707,-0.3551263511,-0.1786167324,0.6787138581,0.2391502708,1.0172373056,-1.8531953096,0.3468162119,-1.4673253298,-0.2697222829,-0.7077001333,-0.6697863340,-1.4380449057,-2.5307970047,0.8736237884,1.1434020996,0.6140899062,-0.1727177799,0.5524320006,-1.1338095665,0.3060199618,-0.3793222308,1.4749680758,0.8436607718,1.7927627563,-0.3670867682,0.2940903902,0.6996473074,0.1865092516,0.2714602351,-1.1878365278,0.0535032712,-0.3654344380,-2.1078500748,-0.8450355530,0.7202682495,0.6847658157,-1.5380316973,0.1071202233,-1.4377793074,0.5285930634,1.1309717894,-0.2409960181,1.1711474657,0.0241652615,0.1474795640,1.0787435770,-0.2041695267,1.1821421385,0.7134022713,-0.1815098971,0.6097062826,-0.7310802937,1.3213235140,-0.4690505266,-0.1206440702,-1.9621025324,0.0792470798,-0.9037244320,-0.6727975011,-0.5813845992,0.7638904452,-0.7982986569,-1.1170951128,-0.0278148465,0.7436719537,-0.0349298790,-1.5607745647,-3.6942853928,0.2392628640,1.6242785454,0.1078562513,0.8389151692,-1.0812578201,-1.3334944248,-0.3950431943,0.1764431298,-1.5741150379,-0.2641482949,-0.5769725442,0.0579043850,1.6284952164,1.3821072578,-0.1604852676,0.5396218896,0.3823760748,-0.5413639545,0.3832670748,0.3760714531,0.6530348063,0.7082789540,1.6361300945,-0.8255808353,0.4770345092,0.7754092813,0.5997623801,-1.0650105476,-0.1005972773,-0.6563813090,-0.4330505729,0.2436604351,-0.1934807748,0.4373670518,-0.1382869184,-0.0957607403,-0.9223588109,0.2641588449,0.4486901760,0.7179651260,-0.2507312000,-0.3429058492,2.7186050415,-0.0031434130,-1.7863855362,-0.1491491944,-2.4144194126,1.8584879637,1.0816385746,-0.0691355243,0.0412137210,-0.1214653924,0.8756392598,0.6263403296,-0.2714163363,2.5999414921,0.0031115902,-0.6093174219,0.8194519281,0.2598125339,-1.5010932684,-0.3467047811,-0.5145673156,0.8833550811,1.5528534651,1.1378787756,0.4535325766,-0.2141902596,-1.0113316774,-0.0475542098,-1.9863569736,-0.0898115486,0.8721480370,0.6683921218,1.5094119310,-0.5674828291,-0.2722056508,1.1545054913,0.9233204722,1.7845782042,-1.1065726280,0.8899226189,1.1991003752,0.3537445962,2.0520317554,0.4479960799,-2.4655239582,1.1212525368,-1.6055749655,-0.5201081634,0.5299128890,2.2476568222,-0.7108030319,-0.0680756792,1.3571964502,-1.8943730593,0.6292427778,-1.0711674690,-1.9200879335,-0.0095262108,-0.0612300560,0.3710441887,0.9317353368,0.2323822975,1.5968242884,1.2942872047,-0.7865222692,-0.0996802449,-0.2432516068,-1.8798357248,1.6190136671,-0.4560818374,1.0802834034,-0.3977110982,0.9913378954,-0.4810326695,1.1207609177,0.3215666711,0.6868842244,0.7012643814,0.3027723134,-0.5669187307,-0.8218886256,2.1448388100,1.5178095102,0.3204951584,1.2383538485,-0.6073427796,0.1993925571,-1.6000400782,-0.7605104446,-0.1507879049,-0.1515130103,0.1344979405,-1.3684259653,0.0471347682,0.0774593130,0.2506715953,0.7475439310,-0.5684504509,-1.4915621281,0.4500528872,0.3627835214,0.2907096446,1.4360669851,0.2089084089,0.7776738405,0.0575551018,0.1220124662,-0.5838123560,-0.0324958488,0.2039363533,0.3325089812,1.3271270990,1.4291518927,1.6142344475,-0.2566379309,0.0891720057,1.0746363401,0.0611726567,1.3872996569,-2.3101968765,1.5936372280,-0.6907869577,-0.0694889277,-0.2972775698,0.8311193585,-0.1777330637,2.0184845924,0.5656145811,-0.2051413357,0.9329389334,0.6280627251,-0.1737667471,1.2492796183,0.8439475298,1.2072235346,-1.0259077549,-0.2974030375,-0.4043617547,0.8485488892,1.0105415583,1.0167632103,-0.3439735472,-0.7064131498,-0.3029172421,1.4635292292,1.8002523184,0.4651216567,-0.3715837598,-0.2971130908,0.3571931124,-2.6784129143,0.3649374545,-0.3777738512,-0.7590556741,-0.0151699381,-0.8821194172,0.5951886773,-0.0852708519,0.9750209451,-2.0264630318,0.3239995539,-1.5468266010,-0.6036015749,1.2733149529,-0.5170837641,1.3886284828,2.0128860474,0.6841310859,0.5642735362,-1.7078286409,-0.1220685244,0.8022543192,2.9402222633,-0.5440009236,0.5440354347,-0.3028250933,-0.1236471310,1.0711059570,0.1711559743,-1.1677023172,-1.5948584080,1.1498628855,1.7074403763,-1.7957524061,-0.3149690032,0.1568339318,-0.3114894927,0.0211651828,0.1890159994,0.9555293322,-0.2745038271,2.7662432194,0.4147194326,-0.4034470320,0.3713617623,0.3691652417,-0.8164408803,-0.0419991501,0.8501044512,0.4174660742,-0.4661606550,0.7105901837,-0.1279045492,0.3523364067,-0.2073855847,-1.1988571882,-0.0351843536,0.1673676521,2.1629037857,2.3720927238,0.5707538724,-1.2859030962,-1.7754752636,-2.2168619633,2.3724796772,0.0648849458,0.4216980040,-0.4210457206,-1.1706908941,1.2849756479,0.0288783815,0.0029941904,-0.2512137294,1.0792390108,0.0430316254,-0.1150320619,1.3237221241,1.2466740608,-0.7737157941,0.3568372130,-0.7242242694,2.0552656651,0.5782729983,-2.1194407940,-0.4371688962,0.5964887738,-0.1009557024,-0.2599818408,-0.5893468261,1.4360679388,-1.2596794367,1.6888058186,0.1015370265,1.0656791925,0.5520688295,-0.1842226237,0.3630548120,0.3245004416,-1.7664282322,-0.6189075708,0.8789561391,-0.0498849228,0.1388183832,-0.6309426427,-1.2514204979,-0.9320270419,-1.3813583851,1.6924980879,0.4783075154,-0.2157701105,-0.4409082532,1.7098357677,-0.0066842828,-0.6266974807,0.3062791824,0.8604946733,0.3906947374,0.6621009707,-0.3415372968,-0.1327738911,0.1090027690,0.5395166278,1.3441191912,0.3890197575,-1.5003491640,-1.6765406132,1.0947563648,-0.4194751680,2.2247760296,1.4415625334,-0.7291014791,-1.1591322422,0.0448737144,0.1642017961,-0.4120277464,-1.0800826550,0.0302338228,-0.1979196072,0.2417976409,-0.4217292070,2.8807368279,-0.2916334867,-0.1119498610,1.4483487606,1.3079737425,3.1414964199,1.9990832806,1.3666808605,-0.4089882970,-1.9430245161,0.1383289248,-0.2756088376,-0.3302395046,0.3767584264,-0.1456294358,-0.0736739188,-0.2632665634,-1.0246253014,-0.0997517109,1.4146862030,0.3474251032,-0.3105725646,-0.6983625293,0.1704372913,0.5889595151,0.3045978248,-0.9002690315,-1.0737453699,0.9776275754,-0.8216294050,-1.4059617519,-0.8584246039,-0.9430308342,0.0863835663,0.4300649464,1.0046936274,-0.1960627437,-0.9061456323,-1.2908878326,-0.8379617333,-1.2833580971,-0.4425460398,0.8820519447,1.7542774677,-0.9453480244,0.4118882418,-1.1179608107,0.1755656004,-0.6019179821,-0.2438964695,1.4608323574,0.6031800508,0.4058443010,1.3704522848,-0.8749694824,-0.2395764142,0.3866791129,1.1813465357,1.0303496122,0.4329538345,0.6799361706,0.1898843944,0.5167849064,1.3488928080,-0.9842775464,-0.9970665574,0.4313078225,1.4899312258,0.2684113979,-0.8607005477,1.5387905836,-0.2373507470,0.1182171926,-1.9649727345,0.1285471916,0.7161492705,0.0362120271,0.9534409046,-0.9433271289,-0.9471279979,0.4125443995,1.5807524920,-0.6251024604,0.0839564353,-1.3108118773,0.8444495201,-0.9436219931,0.2464914024,0.1501429230,-0.9166177511,0.8560885191,-1.7652616501,1.0727841854,-1.1108458042,2.2795565128,0.9886731505,0.7996646166,-0.7582955360,0.5232353806,-0.5892561674,-0.4959479570,0.5991611481,-0.9851461053,0.5707060695,-1.1462754011,0.0037861473,0.3931219280,0.6216490269,0.6596783400,0.8396199942,0.1782273948,-0.4145593047,-0.1143532768,1.4198349714,0.4542442262,1.0489712954,0.1573176235,1.6916421652,0.2117508501,0.6056104302,-0.8419842720,0.8234154582,0.9980833530,1.0220810175,0.6612729430,-1.0162453651,-0.6721482277,-1.0239974260,0.7389633656,0.6064419150,0.4327298105,0.4807211161,0.1548499912,-0.1756894737,-0.4154034555,-0.5601374507,-0.6286499500,1.0796920061,0.5231323838,1.2025828362,2.7605485916,0.9448372126,0.4897510409,0.3005301058,-0.3569986224,1.4894896746,1.0769951344,0.9457442164,1.3836812973,-1.2388128042,-0.9194841981,0.6592172980,1.1811634302,0.1504609138,1.1520256996,0.7040884495,-0.7302854657,-0.7238515019,0.6783299446,0.5535770059,-1.1894803047,0.1862907112,-0.7157256007,-1.6877734661,0.2565253377,0.9417484403,-1.1264679432,0.3717091382,-0.6848784089,0.8496810794,0.5500252247,1.2373111248,0.5267019868,-0.3370111287,1.7402325869,0.6208246946,0.1496523172,-0.0145279448,-1.0990328789,1.0914890766,0.3146514297,-0.2327844501,-0.9927524328,0.2801242769,-0.8725679517,-0.3057530224,-1.4110640287,0.0511594787,0.0009446123,0.4381587207,1.0378230810,-0.8866230845,0.1709326804,-0.2147371024,-0.5751985908,-0.4123259783,0.3231201470,-1.2464450598,-0.1151144356,1.0316728354,-1.7826942205,-0.2277909219,0.2456097901,-0.1247552261,1.1718108654,-0.9280160069,-0.8763661385,-0.9531322718,0.3050051033,0.9160202742,1.1899218559,-0.3139192462,-0.5719921589,0.2692719996,0.6695338488,-1.4176100492,-0.1810361296,0.8919016123,0.3253822625,0.2102392316,1.1510844231,-0.2731625140,0.9161008596,-0.3529846966,0.7246912122,0.3719465435,-0.6608036757,-0.7025949955,-0.2617565691,-1.5062785149,-0.2983382642,0.7757444978,0.5407574773,-0.8948160410,-0.3278140426,-0.2843683064,0.3198806047,0.7847097516,1.0833867788,-1.1843409538,0.9079430699,0.7242349982,-0.1339356005,0.4209992290,0.3426757455,1.3023025990,-0.1115856692,1.1961381435,-0.6273810863,0.5569947362,-2.0751523972,0.4874547124,0.0112005575,-1.9131480455,-1.6525598764,-0.9860039949,-0.4189216495,-0.2969622314,-0.4724214971,-0.2920680940,-0.6366106868,1.4640799761,0.0001000688,0.6696881056,0.3056806624,0.2199319601,0.5476730466,0.2989024222,-0.3060296178,1.5866267681,-0.1923424900,-0.7535434961,2.4642388821,1.4206904173,-1.3298442364,-1.6729069948,-0.2089457661,0.1286960840,0.2165742069,-1.2509105206,-1.2517259121,0.0144478939,-0.5250476003,-1.4943634272,1.7899401188,0.7980135083,-0.2467044145,0.1137525737,-0.8360635042,-1.0790261030,-1.4593545198,0.6329082251,-0.1951130778,0.2109565586,-0.6452851892,1.3813667297,0.3914685845,2.4400918484,0.8632235527,0.4989744127,0.4575488269,0.6004958153,1.4023209810,-0.9147142768,0.3939240277,-0.2197887301,-0.9745028019,-0.8095402122,-0.1595830917,0.3253418505,-0.9514853954,-1.2631294727,-1.9905785322,-0.1589462757,-0.2686427534,-1.0362379551,-0.5929874182,2.1278758049,0.6741823554,-0.3402375579,-0.8575452566,0.1285680085,-0.1974782944,1.3091429472,-0.0491636656,-0.8006293774,-1.9171167612,-1.6133759022,0.6724346280,0.2764676511,-1.0947827101,0.7140973806,-0.4589699209,-0.5040537119,-2.6571507454,0.4938603342,-0.1112184599,-1.1413344145,0.3065828979,-0.0351181589,-0.2077741474,-1.2007638216,1.3442721367,-0.2882195115,0.7794566751,-0.0357597359,-0.4914976358,-0.6510698795,0.4476221204,-0.2434361875,0.3303336501,-0.1247829944,0.9456844330,0.3387642205,-0.0858657435,0.0836824849,0.3197313249,-0.5224598050,0.0667929351,0.9599102736,-1.2944271564,-1.6121833324,-0.4610219300,-0.0686687902,-0.6209889054,-0.5094255805,-1.3296127319,-0.6519948840,0.3874265552,0.2548698485,0.6057342887,-1.1156878471,1.7558230162,1.3769574165,-0.5067620277,-0.2540018559,0.1169501916,1.4090871811,-0.2061688751,-0.3826217651,0.0744053125,-1.0701073408,0.2666794658,0.0159707237,-1.0801004171,0.3020006120,-1.1221276522,-0.0603687689,0.4302231073,0.8030367494,0.3813634813,-0.5177665949,-0.5745231509,-1.2133439779,1.0359526873,-1.0773680210,-1.0581761599,-0.7194543481,0.7911873460,0.3575147688,0.4734067023,1.3755928278,-0.3413253725,-0.7216416001,1.4161067009,-1.0657318830,-0.5758734345,-0.0554632656,-0.5676805973,1.0491763353,-0.5460031033,0.0000377406,-0.1134769619,-0.1902130544,1.1122241020,0.0361957811,-0.5202575326,-0.9287207723,0.4673231840,0.2076914012,-0.5268574357,-1.4158695936,0.9209938049,-1.2451177835,0.3177010119,1.3631247282,-0.6694192886,-0.5273765922,0.1168278307,-0.1416368484,1.0902903080,-1.5505670309,0.8457047343,1.2713711262,0.8615369797,-0.6803045273,-0.9436883330,-0.8042429686,1.2764884233,-1.4393085241,0.6460635662,0.1760231256,0.6022271514,-0.6289021969,0.2052420974,-0.9054312110,-2.2867314816,-0.5080083013,-0.3702924848,-0.3562673926,1.6888591051,1.0248645544,1.2868249416,-1.4498550892,0.4269231856,0.7690059543,1.2068730593,2.2509765625,-1.3853080273,-0.0437916964,0.5083934665,-0.1405894905,-1.9240996838,-0.0695686266,1.0290793180,-0.6863524318,1.5921109915,-0.5149906874,0.4313142598,1.2325224876,0.7381823063,0.0506481752,0.2718752027,-0.0458972342,-0.2813476324,0.1470736563,1.1240963936,-0.4729631841,0.3032023907,-0.0378687717,0.7551904321,0.2726889551,0.8062175512,-0.9914822578,-1.3461425304,1.3953132629,-0.3963041306,-0.1348937005,0.1861299574,-0.1282923222,1.3191727400,-1.3927209377,1.6524684429,-1.4570862055,0.1970746368,0.7873681784,-1.5872268677,0.7789785862,0.7257158160,0.9104884863,-1.0458092690,0.1311151236,0.0523036309,-0.5617845058,0.6315040588,-0.8047713637,-0.7324396968,0.5472825766,-1.1248081923,0.7605649233,1.9306453466,-0.8998404741,-0.9145870209,0.7737373114,-0.7555955052,-0.0085799778,0.6102102995,1.0703949928,0.0122935213,1.7418897152,-0.8565835357,-0.1485811919,2.5863671303,0.2296967655,0.4921732545,-0.2157451808,1.7708336115,1.4435811043,0.3088599741,0.3821006119,0.7828531265,0.8288940787,1.2654770613,0.5320999622,1.6035956144,0.0555833168,-0.7808041573,-0.4768952131,0.0609117076,-0.4685634375,0.0401823297,-0.7980151772,-0.1980319172,0.3622185290,-0.0124242250,0.0019212270,-1.8690266609,-0.6661810875,1.2603762150,0.3925990760,-0.9471579790,0.9259031415,-0.6989381909,-0.5957267284,0.8059161305,-0.0204536505,-0.7605403066,-0.8714606762,-0.0785574615,0.2176924050,-0.0952641219,-0.6237257719,0.8928356767,0.0207476560,-0.8050456643,-1.1606603861,-2.1986162663,0.5743509531,-0.3747348487,-0.9865067601,0.6025411487,-1.6260415316,0.4241379201,-1.5761916637,-0.5231423378,-1.2368144989,1.3236354589,-0.2628894150,0.9006096721,-0.5883111954,0.9315660596,0.3901229501,0.3613577783,-0.9036842585,0.6531979442,-0.5237332582,-0.4377007186,1.2412061691,-1.8077656031,1.0896279812,-0.5850965977,0.9993878603,0.9793956280,1.7526859045,-0.1627811193,0.0789898112,-0.6008516550,0.6423956156,-1.3718004227,0.8177475333,0.1333660483,-0.7116602659,-0.7372015715,0.0193281416,0.5816512108,0.6322121620,-0.9512215257,-2.3198320866,-0.1225626543,-0.7548299432,1.7849982977,-0.4172134101,1.1810698509,-0.6830892563,0.9388549328,-1.2363265753,-0.6732035279,-1.1739046574,-0.3762327731,-2.2701492310,-1.8741184473,-0.9467853308,0.1845830977,0.0290970095,-1.1332253218,1.5481897593,0.6677289009,1.6565377712,-0.1813921779,-1.4472157955,-0.9493680596,-2.3203413486,-0.1047000363,-0.5362039208,0.1503630877,-0.2119492143,0.1951975077,0.3594886661,1.1071165800,0.5541626215,-2.2391679287,-0.0982199907,0.1499948204,-0.2038379759,-0.3641252220,1.2327725887,-1.0428520441,-1.1857684851,-0.3758674860,-0.7437927723,-0.5258880258,1.6090214252,-0.5477022529,-0.5831058025,-0.7693243027,0.9592191577,0.7612723112,0.6288821697,0.4854650795,-1.0746076107,1.0054817200,0.0261112470,-1.3465268612,0.8569097519,-0.8402596116,-1.0034821033,0.0340053290,0.6326579452,0.0624723062,-0.8272801638,0.9872714877,-0.6493257880,-0.0124687888,-0.0510785058,-1.0020663738,1.7653633356,0.6531934738,1.7806649208,-1.2149158716,0.1973568499,1.2248632908,-0.6891977787,-0.5806148648,-1.4091354609,-1.4452899694,-0.1621054560,0.2553484142,0.5607942939,-0.3715134859,-1.2819964886,0.1613192409,0.7283805609,0.9018242955,-0.4699330330,0.7522509694,0.0473475978,-1.4565970898,0.2873678505,0.6105089188,2.3087093830,-0.4378469586,1.5861054659,-0.0902395621,0.2450557947,1.6665794849,-0.2875549495,-0.6267389655,-1.1200077534,-0.1176927686,-0.9884122014,0.0998817012,-0.3104116321,1.6640614271,1.8047343493,1.7079073191,-0.2945924997,1.4536072016,-0.9042026997,-1.5250431299,-1.2416226864,0.9511591196,1.6640285254,0.9149685502,0.5348483920,0.0271247104,-0.4100965559,-0.4923259616,-0.5284524560,0.7326970100,-0.6320443749,-0.1361745298,1.7820904255,-0.4102703035,0.1149579212,0.4176089168,0.5615858436,-0.1241502464,-0.2711972296,0.8339188695,-0.3911842406,0.8035120964,0.4347385466,0.3256336153,-1.0912731886,-1.1064262390,-1.0023913383,-0.0014343157,0.6572046876,1.1768506765,-0.1612158120,0.2430538386,-0.4206996262,-0.6818819046,-1.5458599329,-0.4415317476,0.8601318598,0.5682681799,0.5093677044,0.6739342213,0.2802112103,1.0092612505,0.5739693046,0.4783741236,-0.7188705802,-0.7555210590,-1.2773789167,0.9673935771,0.7169851065,0.6318838596,-0.3510349393,-0.2784935236,0.9245770574,0.1456117630,0.8596948385,0.5870320201,0.3222205639,-1.1058843136,0.1310071945,0.1351862252,1.4976658821,0.0642576590,0.9805966020,-0.2625622451,-2.0229084492,-0.2577911317,0.8459518552,-0.9816684127,0.0494478457,0.1633282155,0.8872380853,0.2346172631,-1.4553668499,-1.2075823545,0.9899796247,-0.7265192866,-0.1070689112,0.4315021932,1.5511058569,1.0648895502,1.2513504028,-1.6179898977,-0.1960540712,-1.1174563169,-0.0627279058,0.3648060262,0.4943988621,0.4699738920,1.5897046328,0.4787073135,-0.2594979405,0.9839239120,-1.1296446323,-0.2151689082,1.8668168783,1.2359091043,-0.7876203656,2.2410216331,-0.6001842618,0.6790406108,1.9386615753,-0.2716152966,-2.4987998009,0.7988651395,-1.7352396250,-0.8488154411,-0.2405159175,0.0022603455,-0.8565176725,-1.7655363083,0.0227796603,1.1678682566,1.5977461338,0.6137763858,-0.1560899615,-1.2249263525,1.0691320896,0.8002671003,0.9079485536,-0.5812396407,-0.6096565127,0.8414008021,0.8574656844,0.8194988966,1.9166227579,-1.2481331825,0.1276202202,1.2027217150,0.6284421086,1.8388808966,0.7530941367,-0.5810328126,-0.1983797401,2.4699819088,0.5870167613,-0.3973526657,0.4335496426,0.5002970695,1.2368345261,-1.0192248821,-0.4722243547,0.1429932714,-0.6643745303,0.9991702437,-0.7230226994,-0.9242684245,-0.6563588977,1.8147925138,1.0481163263,0.5963919759,0.3161043823,-1.5705043077,-3.0482473373,-1.4911568165,-0.5620017052,-1.5762267113,-0.2792216539,-0.0183045566,-0.3427428901,0.4325659573,0.0841940790,-1.5596717596,-2.3954472542,0.6650484204,0.9164831638,-0.6995766759,0.7592606544,1.9653995037,2.1778728962,1.3679281473,0.3184723258,-1.3753741980,-0.5408719778,-1.3242262602,-0.0486250222,-1.4743169546,-1.9059720039,0.4585015178,-1.3563024998,-2.1027057171,-1.6160247326,-0.8111845851,0.6833175421,0.3431516886,1.0679210424,0.3967325985,1.3747622967,-1.9252409935,-1.5621434450,0.3567034006,0.1609219313,-0.4597774446,-1.5141679049,0.2331478596,-1.2618752718,-0.7512057424,-1.0166230202,-0.5066205263,1.9142640829,1.3055176735,-0.3582405448,0.3410398662,0.7159633636,-0.9026330709,0.9061701894,-1.3593796492,0.2564473748,0.6371505260,0.4507238567,2.0558533669,0.4674500823,0.4008921087,1.1421283484,-0.7805560827,0.8754662871,1.1091470718,-0.4740432799,-1.0471091270,0.5696887374,1.4610911608,0.2937921584,-1.3595267534,0.5948380232,-0.5259676576,0.6979746819,2.6188032627,1.7860373259,1.3816629648,0.3645930588,0.6413857937,-0.3179526329,-0.6694340110,0.8531759977,-0.5612838268,0.6540765762,-0.7173810005,0.7171044946,-0.3337262869,-1.2696685791,-0.3191621602,-0.0951602459,1.6437281370,0.4104022980,-0.6791217327,-0.5343052149,0.1236637682,-0.6867526770,0.4327032268,-0.9899078012,0.3520361781,-0.0372290350,0.0954944342,0.8924535513,-1.3897480965,0.2908154130,0.1433742046,-1.2002483606,-1.1578544378,0.2018009126,-1.7330788374,-0.3900980949,0.3442434072,0.5612210035,-2.3735797405,0.4677275121,-0.8755277395,0.3840200901,0.7140026093,-0.0161184259,-0.2327160239,-1.3661100864,1.8017098904,0.1095980778,-0.9140314460,-2.1166992188,1.5349193811,1.5171842575,-0.7831214070,0.8759396672,-0.3350074291,-0.6258761287,1.1088163853,0.1659310460,0.3859133720,2.1467437744,-1.4819864035,-0.1044765934,0.0227515679,-1.3247855902,-0.0460397489,-0.2199831605,0.3223781884,-1.8705461025,-0.2860034704,1.3835725784,0.0756484866,0.7798700333,1.1855169535,1.0793471336,1.5322893858,0.4833815396,0.7111821175,1.2975721359,0.5630246401,1.6598074436,-0.3058865666,1.0004166365,0.2399135530,2.0036790371,-1.0272872448,-0.2898159623,0.3397452831,-0.5536059141,0.1857142448,-0.8085384965,-1.5434528589,-0.0007162808,1.0881972313,0.6845315695,-1.8424415588,0.6105918884,1.3732216358,-1.0601470470,1.1996201277,-1.2230579853,1.1186140776,-0.6385557652,1.1005522013,-1.8498262167,1.9758620262,0.3748421669,0.9024031758,0.6665591598,-0.5407711267,-1.1386766434,0.8666719794,-0.7272105813,-0.5572866797,0.3335200846,0.2419228256,0.1356631666,0.0634459481,0.5071093440,-0.1976352483,-0.1633360833,3.0307579041,-0.6317493916,-0.2643266618,-1.2277452946,-1.0420066118,-0.2836993039,0.8368556499,-1.4368258715,-0.4121444225,-0.1726893187,-2.3277754784,-0.5735732317,0.4645721018,-0.1024918482,0.9124009013,-0.9102084637,1.3875967264,0.7080764174,-1.5910292864,0.1935648620,0.8600574136,0.3366048932,0.4506984651,0.6514768600,-0.0764857233,-0.5673771501,-0.2962603569,-1.1983201504,1.0930721760,-0.4548245668,0.9074430466,0.0770448744,0.8746569753,-0.2766015828,1.2379782200,-0.0664854795,-1.2437325716,-0.4574719965,0.7507360578,0.6556258202,-0.2704447210,-1.5917396545,0.9173870087,-1.8183697462,-0.6614665389,1.0413696766,1.2564733028,-0.5287645459,-0.7868911624,0.4760374725,1.4004799128,-0.3912179172,-0.3319635987,-0.1274384409,-0.3486401141,-0.5874551535,-0.4041832685,-1.2626019716,-0.2735873163,-1.8302440643,1.1272053719,-0.9103027582,0.9363489151,1.7044332027,-1.4405498505,0.1213527992,-0.7432028651,-0.3949774206,-0.6219618917,-1.0270428658,0.3988615274,-1.2037241459,0.0879646614,-1.0123245716,2.2703430653,-0.1986519694,1.0142803192,-0.5765676498,-0.1850306988,0.9218153358,-1.4215303659,-0.3045988679,0.8781455755,0.4839467108,0.3406828046,0.1385729313,0.5530541539,-0.2178639174,0.6572006345,-0.7660921216,-0.1504787654,-0.6955124736,-0.8039906025,0.1935697198,-0.6107688546,1.4775750637,2.1482009888,1.2706098557,0.8919548392,0.5517945290,0.4745905995,-1.3749998808,-1.9628106356,-0.2441599369,-0.2756695151,2.3750700951,-1.0125036240,2.3627867699,-1.0484228134,0.0202945489,-1.6291437149,1.5460455418,-0.2626701891,-1.3716934919,1.7448372841,-1.9003964663,0.7340160608,-0.9719927907,0.4878770411,0.8426557183,-0.0036995597,1.1608890295,-0.1446119249,-0.3867310584,-1.2060709000,-1.8427013159,-2.1762900352,0.5401457548,-0.5232191682,0.6863697767,1.7252759933,0.9453377724,-1.2271872759,-0.5287625194,-0.5573931336,1.1400207281,0.8531771302,-0.7874594331,1.4860290289,-0.3966833353,-0.8653481603,0.6682871580,-1.3460118771,1.1101393700,2.5374398232,1.5781009197,-0.2074164003,1.1810634136,1.3876578808,0.4343869984,1.0187358856,-0.3469872475,-0.0697899982,0.6849715710,-0.7938639522,1.0810682774,-0.7873340249,0.4875499606,-0.5890196562,0.6428114176,-0.5371803641,-0.0320537537,-0.6355226636,0.2840048969,-0.7231734991,1.6757985353,-1.3749076128,-0.1871342212,-0.5509265661,0.2247584015,0.0963228941,0.5343322754,0.4177618623,-1.0538265705,1.7033421993,-0.1041369513,-0.5689711571,0.1449021250,1.5101170540,-0.8077566624,0.1635077000,0.3681793809,-1.3697288036,-0.9026447535,0.1419233531,-0.4355032146,1.4709450006,-1.2994558811,-0.1398774087,0.4056711495,-0.9279340506,-0.4008336663,-0.1832318157,-0.4932772815,1.1810588837,-0.4294885397,0.2586955130,-0.6026366353,-1.6949310303,-2.4281458855,0.3360414505,0.0007651557,0.6452424526,0.0013740991,1.2619608641,-0.6294914484,1.0755714178,-1.6946045160,0.4138219059,-0.9013427496,-0.9153943658,0.2750778496,-1.7745633125,1.2423049212,1.4853067398,0.6582362056,-0.4944946170,0.8580268025,-2.5256597996,-0.4416845739,0.0358854383,0.2637412548,0.1396094710,-0.2113924474,-1.0850139856,0.8667337894,0.6863631606,-0.7880696058,0.2563993931,0.6276249886,0.5765470862,1.0376647711,-0.8950424194,-0.7374470830,-0.5733580589,1.5468299389,1.0180302858,-1.3552303314,1.5083237886,-1.5015984774,-0.4331097603,-0.7236114740,-1.2652302980,1.8355219364,-0.9491904974,0.7845528722,-0.1004951149,-0.9171906114,-0.6248505712,-0.5434099436,0.2936888933,0.7476300597,-0.1759679466,0.7415206432,0.1636239588,0.3913640082,-1.0406374931,1.5966686010,1.7157511711,-0.9193367362,-0.5155612230,0.3866383433,0.3502348959,0.6012752652,-0.2728933096,1.0108480453,-0.3607590199,-0.9352738857,0.0113944160,-1.0877426863,-1.2035589218,-0.5796896815,0.0864668638,-0.7101565599,0.0531113632,-0.7170058489,-0.0952148288,0.3925267458,-1.0388872623,1.1641366482,0.4681651592,1.2697256804,0.5855969787,0.8054180145,0.5459367037,-0.0193008948,-0.0799392536,-0.7031532526,-0.3332782388,0.8763495684,-0.3275536895,-0.0899465531,-0.7804068923,1.5976791382,-0.0845693126,-0.8380930424,1.2919481993,0.3801421523,1.0650464296,-0.4915513992,0.3796888292,0.3082422614,-1.2515425682,0.8574884534,0.0453626625,-0.8994646668,0.1817809045,-0.3982611299,-0.4245830178,0.4759723842,-0.5196942091,0.9084286094,-0.2574448586,0.6669890881,1.4542843103,0.6965520978,-0.4026068151,0.4368975759,-0.1450076252,-0.7213081121,-1.9050275087,0.1893024594,2.1357374191,1.5123866796,1.4541821480,-1.6385452747,-1.5910087824,-0.6939245462,-0.8785220981,-0.8075929880,-0.3812121153,0.8093725443,0.2798313498,0.5270179510,-2.3664381504,0.5130461454,0.0916117877,0.6262785792,-0.7436412573,0.3277203441,-0.7760006785,-2.5068039894,0.4759555757,-0.9010194540,0.0145629812,0.8987622857,0.3353192210,0.9606677890,-0.2874678075,-2.9939599037,1.2504578829,-1.1720881462,-1.0356649160,0.6958131194,0.4948087037,-0.4572609365,-1.6435623169,1.5744616985,-0.0300552286,-1.0009658337,-0.9311393499,1.0732966661,-0.2361930311,0.2371501774,-0.5839691758,0.8537157774,-0.2181455344,1.7659276724,0.2091579586,1.5832922459,-0.1612836719,-0.6309607625,-1.7614916563,-0.5587900877,-1.0242021084,0.0377286524,0.4732848704,-0.1918084174,-0.0163135994,0.2189601362,-0.9728784561,-2.5277113914,-2.9586434364,0.6248936653,0.9954282641,0.9903995395,2.0193979740,0.4239855707,0.8024560809,-0.2874479592,0.2707243562,-0.7016677856,0.3606193960,-0.3674240112,1.8943160772,2.4282639027,1.5565392971,0.8108466268,-0.4795611799,-1.8067957163,1.3225959539,-1.4695440531,-0.4730064571,-0.1111553162,-0.1633212417,0.7373108864,0.0697204918,0.1390757263,-0.5723037124,0.1945779175,0.4934951663,0.8671396375,0.0400937945,-0.8754099011,0.3754470050,-0.1142536923,-0.4761653841,1.7966411114,-0.2497129291,-1.3456119299,-0.2531846464,-0.0173894931,-0.8581447005,-0.8182291985,-1.2103476524,-1.8957642317,-0.5462412238,-0.3278253973,0.4181403518,-0.8027678132,-0.1248840615,0.3669672012,-0.4320286512,-0.6431820393,-0.3669171929,-0.4180790484,-1.1114394665,1.5662413836,0.4966558814,-1.5271258354,1.6809345484,0.9452425838,0.7926274538,-0.1260183305,-0.3414977193,1.1150146723,0.7628927231,0.7186394930,2.0608656406,-1.1427087784,-0.6720955968,0.4238626957,-0.2674430609,-0.1200173497,1.1119060516,0.2046580315,-0.1742334217,-0.6899335980,0.4895804822,0.5928009152,-0.6894159913,-0.7927412987,-1.3092082739,0.6599462032,1.1592344046,-0.6471576691,-0.8530796766,0.2530079484,-1.2349803448,-0.4698171914,0.6378022432,0.0646075532,1.2665129900,-0.0035302599,-0.4264021516,1.9557579756,0.3368331194,0.1942038685,0.2976615727,-0.2447934896,-1.1720229387,0.0022187224,-0.5681318045,-0.0083157700,-0.2423404306,0.4079694450,-0.4025951028,-1.6668678522,1.1076716185,1.1742789745,0.8371176124,-1.2049195766,0.8989720941,0.5069872141,1.2650052309,0.5479833484,-0.6105635166,-0.7324912548,-0.7606137395,2.3526127338,0.3232249618,-0.0974526554,0.4910657406,-0.3990236223,1.5860863924,0.8555051684,-0.1618283838,1.5360722542,-0.0187115595,0.4534055293,0.5044534802,-0.2699193060,0.7831186056,-0.0310493931,-1.5355266333,0.1740212291,-0.5708485842,-1.2032914162,1.0133572817,-0.9925648570,0.6193821430,-0.5009004474,-0.0948746130,0.5210202932,1.4905010462,-0.0342098996,-0.7431033850,-0.1009846702,1.3803369999,2.7175147533,-1.6663825512,-0.6393872499,0.2210241407,-1.6114358902,-2.2916140556,-0.1636691839,-0.5086622238,1.3264782429,-0.7173157334,-0.6772971153,-0.3950392008,1.3992792368,0.4134455919,0.9333790541,0.8993307948,0.2048672885,-0.2898763120,-1.4870306253,-0.0224908516,-0.6100093722,-0.0982251316,1.4243254662,-1.5467219353,-0.3993415534,1.2259448767,0.1247667298,-1.8018198013,0.4228524268,-0.2830335796,0.2086140662,-1.8642035723,0.2794917822,0.8912532330,0.4764015675,1.1169859171,-0.8097556233,0.6917906404,-0.5510755181,-0.1711165160,0.7242781520,-0.1862911284,-0.8004393578,0.1734851003,-2.3327710629,1.0729398727,-0.0054144766,-0.6906583905,0.1949700415,1.1526728868,0.6277722120,-0.4168083966,-0.4985950589,-0.4415447414,0.4759062827,-0.9995189905,-0.0556426719,-0.8905441165,1.5150352716,-0.4012076855,-0.5104394555,-0.3579500318,-0.8876761198,-0.1260623485,1.2100745440,0.3163279593,0.1174208298,-1.0488599539,0.8006420732,0.8193587065,-1.4236061573,0.0530269407,0.8419333100,-2.3811285496,0.3123259842,2.0316591263,-0.1334241331,0.9566749930,0.3105371296,-0.0280005373,0.1698162705,-0.6434794068,1.4687440395,0.8223428726,0.5253647566,-0.9414321780,0.2501220703,-1.4306063652,0.4417558610,-1.3391911983,-2.1790165901,-0.6563906074,1.6905251741,-1.0324158669,0.0105966255,-0.4265025556,0.1774287373,1.1015805006,-1.2504085302,1.9962170124,-0.7548727989,-0.4495831132,-0.1260795742,-0.9168621898,-0.5386515260,0.4052873552,-1.6897302866,-1.1016709805,0.3024735451,1.5943657160,-1.4092345238,2.6607553959,1.1071485281,0.2390423715,0.4573163390,-0.1807434261,-1.9098607302,-0.3015142679,-0.5953611135,0.1685141623,0.3814010024,-0.0196545552,0.1171996817,0.5379750729,0.0300317835,-0.7584958076,2.2050728798,0.7647278309,1.4125244617,-0.6500667930,0.7842895389,0.6472234130,0.1368263811,2.1448404789,-0.4679664671,-0.3690626025,-0.8305638433,0.4829550087,-0.4260619879,2.0036153793,0.8908524513,-0.4578307271,-0.4667037129,0.5653272867,-0.2103756368,0.0654499233,-1.0563793182,0.8389202952,-0.9145900011,-3.0074131489,0.8634305596,-0.3165632188,1.3181333542,0.7771042585,-0.3728661537,-0.9975465536,1.3015630245,0.5809165835,-0.1991985440,0.4615896344,1.6888397932,-0.9476919770,-1.0568165779,0.6325836182,-0.2203704268,1.1994246244,0.2282462716,0.7648639679,-0.6254203916,0.0122858062,-0.1240646094,-0.3559269309,0.5451278687,1.2897644043,-0.1418277174,-0.0237832293,2.4164583683,0.3128513694,1.2583760023,-0.0183320828,-0.2904647887,1.1263755560,-0.1271803826,-0.6991423368,0.4350317717,-0.9930130839,-0.0732888058,-0.0096755922,0.6082351208,-1.4622994661,0.3734008372,-0.2516731918,-0.5549135208,0.2704532146,0.8839444518,0.9480336905,-1.7732236385,-0.3400033414,1.0801545382,0.4076742530,1.1092234850,-0.5090354085,0.0154662654,0.8081864119,0.1444585472,0.4838244617,0.4002939761,-1.8577429056,0.0833002552,0.1059778705,0.7952242494,0.0375305712,-0.0192010757,0.5708048940,-0.6749990582,0.6472918987,-0.5778470635,0.5768222213,2.3813226223,-0.8882810473,-0.0370802470,-1.5818849802,-0.5403636694,0.9223807454,0.8768610954,1.6823604107,0.4641687870,0.5547270775,-0.7476307750,-0.1079692096,-0.5736877918,-1.1933667660,0.2192575037,-0.1325137913,0.0294413287,-0.7202627063,0.0728821531,-1.4440402985,1.1075712442,-1.7380994558,-0.3122649789,0.5126811862,0.0520603210,-1.6752490997,-0.4572330117,-1.4403076172,0.3279295862,-2.2079944611,-0.2930724025,1.5250643492,-0.7436814904,0.1235063225,-0.9559509754,-0.7831512690,-1.1331845522,2.1102159023,1.4193875790,0.7471066713,-0.1063024849,-1.9626525640,-0.8340319991,1.9938367605,-0.6666597724,0.9762901664,-0.8030210733,1.0035098791,0.4384184480,1.1932302713,-0.2671444714,1.6537593603,-0.0300932750,1.7405285835,1.1974927187,-0.2730903327,-0.4148294330,-0.9199048877,0.9715379477,0.2495393604,1.9860477448,0.3632284403,1.0493472815,-1.7863451242,0.4960638881,-0.5253154039,1.2082391977,0.7166950703,-0.1228279471,0.5477110147,-1.1976144314,-0.4063251615,0.1708601564,-0.5023768544,1.9816210270,1.4944957495,1.3486838341,0.1301545054,2.2598488331,1.0608019829,0.6828438640,-0.1969961673,-0.0942310393,-0.1965968609,-0.0145343514,-0.4977135956,1.4621585608,-0.5365141630,-0.1809267700,0.0045570266,0.5690778494,0.7586371899,0.2046857178,-0.2727931440,1.0885236263,-1.1514253616,0.0665233359,-1.5880743265,0.8120266795,-0.0526654460,0.0728608370,-0.0096358024,-0.1773585379,0.8013668060,1.6797046661,-0.2765279710,-0.5227367282,0.4652282894,1.0062574148,-1.0238008499,-0.3171005249,2.1590240002,0.1793651879,0.2974379659,-1.7805523872,0.2365886420,0.5838900805,0.8689589500,-0.1619296968,-1.8251862526,1.0525997877,-0.7366934419,0.2232283652,-0.2124611437,1.1224877834,-0.5253707170,0.8429335952,-0.4547739327,0.2139290422,-0.3529743552,-0.4005251527,-0.3588286340,0.5342850089,1.0697213411,0.3627375960,-0.6180936098,0.7206230760,2.3563475609,0.7881179452,-0.1104493737,-0.1020342410,0.9928730726,0.8416631222,-0.2109418511,0.0594552308,0.1714573205,0.9736061096,-0.2536408901,-0.5090725422,0.2091951966,-0.3952316642,0.6734473705,1.8492509127,0.5406158566,2.1666073799,-0.4017258286,-1.0504158735,-0.5410004258,-0.1275609881,-0.8653998375,-0.7439379096,1.7201974392,-0.3531041741,1.3364866972,-0.6355758905,1.0752155781,0.1554413140,0.8499841690,0.2878955901,1.3831596375,1.0869204998,-1.9145219326,-0.6446622014,-0.6476334333,0.5867015719,-0.1330263019,0.3355934322,-1.0635930300,1.1624379158,-0.2087804228,0.9965528846,0.4709334671,-0.7888488173,-0.9004927874,-1.5506350994,-1.1885224581,0.0462546945,-0.2447022200,0.3237609267,0.5815305710,-0.0116930585,1.9005151987,1.5096068382,1.0625275373,-2.6801900864,-1.4928581715,2.7504143715,1.5735440254,0.1196702197,0.2730636895,-0.6364715099,-1.6727474928,-0.6743252873,1.0582365990,-1.6658549309,1.0274500847,0.8210723996,-0.3279028535,-0.5612089634,-0.8480519056,-1.2279438972,-0.6800284386,0.9341332912,-0.0853653327,-0.6074674726,-0.5700142980,1.1554375887,-1.6881010532,0.8331784606,1.5076262951,1.9043989182,1.4181431532,0.6705791354,-0.2154797763,-0.1985649318,0.8634696603,-0.2186039984,-0.7260090709,0.8744863868,1.0869740248,-1.0211362839,-0.4984046817,0.0550192371,0.1830883920,0.8126010299,0.8161264658,-0.8569269180,-0.1854367256,0.9796576500,-1.7851219177,-0.4285949469,1.2304253578,1.0196049213,0.1956699491,-0.9608377814,0.0585650690,0.5979899764,-1.1106897593,-1.0379048586,-1.7021956444,0.2371710539,1.3618772030,0.1308800131,1.5423973799,0.0521697253,0.3295921087,-0.3451442122,0.0585741326,0.2526168227,0.1740647852,0.0335522965,0.6994304657,1.5105129480,-0.4503269196,-0.4363505542,1.3006982803,0.8859831691,0.6783366203,0.7363558412,-1.7234025002,1.4570312500,0.8774670362,-0.6389059424,-1.0063931942,-0.4606885016,-0.7491079569,-0.4581098258,0.0056097927,0.3033953905,-0.5941976905,1.0164443254,-0.1951033771,-2.0242991447,0.9950196743,-1.6479471922,-0.2919598818,-0.4742799997,0.8809318542,2.0386807919,-0.1976701617,-0.3874321282,0.1774139851,-1.5380210876,0.7691081166,0.2360260338,0.1340331733,-2.0685832500,-0.4424262941,-0.2943103015,0.7442401648,0.5301663876,0.0796818957,0.8675574064,0.1207659021,0.4363836944,0.3957124650,0.4611773193,0.6354420781,-0.6371799707,-0.3056533039,0.4651468992,-0.1246628910,1.1826097965,-0.0713501945,0.4811518490,0.0363793969,-0.4016169012,-0.2674632967,0.3393284678,0.5643074512,-0.9851466417,0.5367643237,0.8051172495,-0.7623518109,0.3541601598,1.1396274567,0.7583637238,0.4819799662,0.5493212342,-0.2779793739,-0.5416448116,-1.0729044676,2.4494299889,-0.4952209592,-0.9134637713,1.0599906445,0.6519761086,-1.1102234125,0.3736817837,1.1824181080,1.0432199240,-0.1811021417,0.3057804704,1.5537210703,-0.3224816918,0.3417883515,-0.7627717257,0.3877569437,-0.5905166268,3.1262331009,-0.0636707246,0.2948612869,0.8857660294,-1.3919001818,-2.0759520531,2.0139601231,0.5181505084,0.2192502469,-0.4590292275,-0.7326875925,-0.0743509084,0.2777031064,-0.0589995608,0.7715876698,-0.1587277502,-0.5620646477,0.3577314913,0.3553095162,1.7608978748,0.3887453675,0.2869249582,-1.5057801008,0.1353569478,-1.1386996508,-1.7352130413,-1.0972082615,-0.8925606608,1.0090011358,0.4416737258,-0.1895652562,0.5086488128,1.2149100304,-0.5647054315,1.0612516403,-0.0578660406,0.3708175421,-0.0541841723,1.8225225210,0.3027867377,1.0238395929,-2.0085389614,0.0481917150,0.3897301257,0.2223383039,1.1534072161,0.8207922578,0.0908544362,-1.3841704130,-1.4576156139,-1.2129918337,-0.9277918935,0.1623429805,-1.0262908936,3.5983099937,0.6017745733,0.5672770739,0.6544624567,-0.9301851392,0.1682607383,1.4109365940,-2.0551912785,0.9204959273,0.0109659592,-0.0355977714,0.1439855695,-0.2296297550,0.9706581235,1.0231167078,-1.0316967964,1.8201168776,-0.2633411586,0.4973664284,-0.8761262298,-0.7698000073,0.9660003185,0.2249306291,0.2809285223,-0.9330500364,0.4547836483,0.5424904823,0.0041835858,0.8023304343,-0.3718265891,1.3409324884,-1.7307722569,-0.0929673240,-0.1464788914,0.6054271460,-0.3584529757,1.1562112570,0.3190774918,0.9031167030,1.1098406315,0.3319199085,-0.7225655913,0.0292326510,-0.6798599958,-1.0965301991,0.8027890325,-0.2196585387,-0.6784861684,-0.6861836314,-0.9749602675,0.6559276581,-0.2036371380,-0.5718295574,0.2653274238,0.3244380057,-0.0364570580,1.8394060135,-0.8206712008,0.5605004430,0.3706909716,-0.8948367238,-0.1099870428,0.9826195836,-1.8920612335,0.8355630040,1.1913090944,-1.7892980576,0.8185464144,1.1664609909,-0.6384063363,1.4365177155,1.8991087675,1.4480994940,0.5353578925,-0.1014933810,0.2317328602,-0.0489891469,0.2788106799,-0.3530018032,0.7007697225,0.8251960874,0.5446463823,-0.2403146476,-0.2228565663,0.6680720448,-0.9187930822,-0.0626189634,0.3346115947,-0.0144286985,-0.9312236905,-0.1410451829,-0.1779760569,-1.4948040247,-0.8491395712,-0.6012837887,-1.1472615004,-1.0493052006,0.9051018953,-0.8528327942,-0.8717535138,-0.8167239428,2.2011229992,0.5912480354,0.7781169415,-0.8884767890,-1.3819385767,-1.1633492708,1.2937792540,0.3712132275,0.1289652586,1.7088830471,-0.1212667525,2.0375425816,0.2414857298,0.5944365263,0.6591821313,1.2509437799,0.8774040341,0.0764976963,1.6224048138,0.2065740824,-0.8375450373,0.3608026505,-0.7311544418,1.8801552057,-1.2250365019,0.7259657383,1.4483156204,-1.5710409880,0.8928659558,-0.1776217222,0.5828669071,-1.1092414856,1.0693781376,1.7471616268,-0.0638344735,-0.2843283713,0.1209072024,1.7735556364,-1.4085712433,1.3586884737,-1.7795503139,-0.5770805478,1.8389601707,1.5333522558,2.2969801426,0.6170276403,0.5831583142,0.0016300381,-1.4345458746,-0.3312624991,0.7281045914,-0.0612430722,0.1704209596,-0.7399250865,-0.9588273764,1.4042122364,2.0758225918,-0.7547942400,0.0572688095,-0.9924984574,1.1447558403,2.0738089085,0.4144458771,-0.4910028577,0.8720424771,2.1747357845,-0.3411389589,1.1494208574,0.3893336654,-0.2615806162,-0.1336776763,0.3566448390,-0.1948368698,-1.1085442305,0.0452541150,-1.6467444897,-1.0986956358,-0.4581389427,0.9293973446,-0.9444404840,2.2482736111,-1.8937467337,-1.0940096378,-1.5336623192,0.9742526412,-3.2672441006,0.5969296098,-0.4229683280,1.9410246611,0.3461483121,-0.1929189414,0.8508393764,-0.8942077756,-0.0658058375,-0.9040490985,-1.6763790846,1.9827840328,0.4141021073,0.7216985822,0.3340985775,0.4529460371,0.3948349059,-0.3916791081,-0.6501089931,-0.1761995107,-0.4910579920,-0.9518061280,0.5322595835,-1.1581377983,-0.7828429937,-0.8784741163,-0.7512039542,0.2515104711,-0.7926872373,0.9031017423,-0.6620030403,0.2099865377,0.1103555858,-0.3409232199,0.3346741498,-0.5610801578,-0.6902984977,0.6454124451,2.1148784161,-0.1916747689,-0.5036607981,1.3881807327,-1.2380584478,1.7191636562,0.3221949041,1.5209794044,0.3738695681,-0.7806591988,-0.4377743006,-0.3996760845,0.9527902007,-0.1983201355,0.2340738177,-0.3172970414,1.4159215689,0.7529594898,0.7795801163,-0.2162986398,-0.1358234584,-0.9613436460,-1.3732218742,1.2092061043,0.6537166238,0.0339915529,1.4929498434,1.3207374811,-0.7652394176,-1.0177652836,-0.6362911463,1.2755696774,0.0088382503,1.0899994373,1.2225722075,0.7833430767,0.4043075442,1.7909801006,-0.3479894698,0.7831335664,-1.4179023504,-0.1100483984,1.2900805473,0.2464116067,0.9515271783,-0.3098686337,-0.3669249713,0.0978010669,0.8864583969,-0.1877962053,0.5702041388,-0.1159990877,-0.3501803577,1.9029144049,0.3099996150,-0.5302504897,-0.6566003561,-0.4687570930,0.9224168062,2.4704847336,0.0035063766,1.6607170105,-1.1333860159,0.1573023349,0.1733097583,0.3055340052,-0.1416791677,0.3056150079,-0.5185316205,-0.2780053914,1.1015346050,-0.9035406113,-0.4951810241,0.8598588109,1.0429813862,0.2664982677,-0.0298852306,0.8533706069,0.0039714552,0.9565080404,-1.5921889544,-0.8913908601,2.3364353180,-1.1469471455,0.0677223578,-0.9267605543,-0.2041192949,0.3063176572,0.2214103341,1.0146539211,-0.2558603883,-1.3943849802,0.1468503773,1.3297446966,-0.8142588139,-0.2132356614,2.4995143414,0.0899943933,0.0429980233,-0.1537914723,-0.4266037941,0.8056005836,1.1891802549,0.2974522412,-0.1454759538,0.1457174271,-0.0381532684,-1.4634613991,-1.3462141752,0.0664003119,-0.7865975499,-0.9306924939,0.3232910931,1.3516124487,-1.3557263613,-0.5764961243,0.2937407792,0.7960445285,0.2003103644,0.3335437179,0.1145793125,-1.4473557472,-0.3551094532,-1.2691313028,-0.1487769932,0.1636830419,0.9360257983,-0.7665287256,0.5842079520,1.2309166193,-0.8302861452,1.6384637356,-1.6886717081,0.7259944081,-0.9984105229,1.0805730820,-0.4680268466,-0.3358856142,-1.3471429348,-2.3989200592,-0.8478084207,0.1898977607,0.7270219326,1.8451247215,-1.4518831968,-0.1755070686,-1.7972141504,-0.3209051192,-0.2535520792,-1.1991846561,-1.0366666317,-0.3719597459,-1.2335456610,-1.3254798651,1.1153312922,-0.5936127305,-1.2354867458,0.4393461049,1.6991671324,1.6203832626,-0.0244100485,-0.3054488301,0.9963783026,0.5320534706,1.1051325798,-0.3606890440,0.4809477031,-0.6204119921,0.6224191785,-0.9839615822,-1.0425922871,0.8285560012,0.6690504551,-0.5170633793,0.1227343306,-0.5366504192,-0.4230706096,0.4494740963,0.0801548958,0.3285671473,-1.4552829266,-0.0545614995,0.3951006234,0.8749583364,0.7818165421,-0.7438398004,-0.3983262479,0.0770372972,0.1963945776,0.9916386604,-1.0397281647,-2.1135330200,0.2499190867,0.8048771620,-0.0107534034,0.6105771065,-1.0989814997,-1.4957785606,0.5590358973,-0.4976819456,0.0038733780,-3.1699786186,-0.5023010969,-1.2277863026,0.9048526287,-0.3307199180,0.3236357868,-0.3506893814,-1.8465671539,0.2423798144,-0.8711999059,0.5552427173,-1.0252454281,-0.9851835370,-1.0336141586,-0.3072377741,-0.3015651107,0.9300719500,-1.1634535789,1.5237438679,0.4603967071,0.9846302271,0.7602651715,1.2697321177,-0.3905704618,-1.4983217716,-1.4723336697,-0.7304906845,-0.2598758936,0.8250431418,0.7544211149,0.6444281936,-0.8383622766,0.2967797518,0.7523125410,-0.7764243484,0.7958608270,1.2056927681,-0.9662641287,-0.9335420132,-0.1679661572,0.2740947604,-1.5847927332,-0.7598161101,0.0663753822,0.4885937572,1.4334609509,0.1223380715,1.2751848698,-0.5594834089,0.4535132945,1.4081346989,-0.4110103846,-0.4689775407,0.1422861069,-0.0778675601,0.6395888329,-0.5474281907,-0.1878197789,-0.5766133666,-1.8732328415,-0.1212131009,-0.0612858348,-0.1527992487,1.8027352095,1.4275883436,0.4526786506,-0.0216174275,0.7622801661,-0.1540553421,0.4228228629,-1.2467342615,-0.5674841404,1.2695670128,-0.8308476210,-1.9346109629,-0.5754521489,0.2582443655,1.0578256845,-0.4269259870,-0.4187313020,-0.5974100828,0.7509816289,1.0372412205,1.2170906067,-0.0723076239,-0.9454078078,-0.2535687983,-0.0566087402,-0.1577985138,0.7568653226,1.4414137602,0.4087726176,-1.5048319101,0.4968555868,1.2993911505,-0.9232976437,-0.4792942405,0.6598887444,1.9238653183,0.0458117649,1.7594987154,-0.2377487421,1.2578010559,0.0903284103,-1.4757454395,-0.7747513652,0.1500543505,0.5281760097,-1.5053366423,1.3702644110,-1.5342292786,-1.8576005697,-1.5551402569,-0.8589060307,2.2405879498,1.4200407267,-0.2279152572,1.5842866898,-0.5206685662,0.5317901969,0.8036642671,-1.5581449270,0.5541169643,0.3074723184,1.3566111326,-0.6996374130,-0.2088235170,-0.2496134192,-1.2829433680,1.9111602306,-0.0551519729,2.0919880867,-0.6781550050,0.1923809499,-1.1128199100,0.3574016094,-0.1978608668,0.6969423294,0.9032924175,0.1589456499,-0.4350588024,-0.3512411118,-0.0519459359,0.9904433489,1.2984777689,0.6284416914,-1.1503527164,-1.1220369339,0.3831738234,1.0778528452,0.3843923211,0.4374722242,0.7809922099,-0.0230867900,0.9145608544,-0.5255103707,-0.8014039993,-0.5153968334,-0.8046190143,0.9278858304,0.6122110486,-1.8956546783,-0.9318542480,-0.4475701451,-1.4089059830,0.5044367313,1.0466452837,-0.4882206023,1.6315196753,-0.6935045719,3.4683833122,0.6756458282,0.4363811016,-0.0252611358,0.7786549926,-1.3182072639,0.5751082301,2.3058328629,1.3533002138,-1.3967939615,-0.3641127944,-1.0209269524,0.2126713246,0.4525144398,0.2537213862,0.1484848112,-0.8377807140,-0.3130927086,-2.0773918629,0.8348540664,0.4066103995,-1.7121460438,0.4686309993,0.9460710883,1.7069529295,-0.6233937740,-0.8569788337,0.0303167701,-0.5756971240,0.1500440240,-0.2254502177,0.5234786868,0.7500634193,-1.2132166624,0.2510019243,0.2570083737,1.0357878208,-0.6433942318,1.4982335567,-0.9077165723,1.4716104269,-1.7842148542,1.1447430849,-0.6266376376,-2.2693505287,0.3182332516,-1.0613924265,0.6442693472,-0.5000963807,-2.0452585220,1.4310381413,1.8100054264,-0.6701334715,1.5482307673,-0.5137092471,0.5081887245,-1.3406304121,1.3682693243,1.2737818956,-0.3865059316,-0.4780690670,0.7779576182,-1.7476885319,-1.1008824110,0.0263148081,1.8815983534,0.3323176205,0.2674674392,-1.3087997437,2.1118044853,0.2675665617,-0.4922035635,1.7720580101,-0.7110042572,0.1589149386,-0.4881309569,-1.5783791542,-0.0925537944,0.5986972451,-2.1295366287,1.7461127043,-0.9785813689,0.3955598176,0.6764844060,-0.9934566617,0.7253823876,2.6917986870,-0.5455944538,0.4043146968,0.3411338329,-0.3855164051,1.6743670702,0.5616671443,1.5067958832,0.2787322402,0.8779776096,-1.8535884619,-1.3119099140,-1.4514750242,-0.3689820766,-0.6068240404,-2.3265423775,-0.2324558496,1.0002081394,-0.6160846949,0.0170312542,-0.2363373041,1.9653319120,-0.2599737346,-1.2773052454,0.4339766502,-0.6928628683,-1.0053579807,-0.1896031797,0.6886450052,-1.9172238111,0.4927026331,0.5296412110,0.2830281556,2.3585255146,0.1015405208,0.1898712814,-0.3793027103,0.2264746577,-0.1147489175,-1.2718250751,0.5322838426,-0.1509367973,-1.0796653032,0.2211570591,-1.6349580288,0.7289609909,-0.0924888924,1.2654665709,-0.7704129219,0.3740957081,-0.6158271432,-0.6735936403,-0.7281390429,-0.1193343252,0.7776176333,0.4423677027,1.3741822243,-0.4074907601,-0.1957744956,0.4908902943,-0.7967771888,-1.5564359426,0.6080636978,1.1600704193,-0.3984555602,-0.1730147898,2.0433011055,0.9244021177,1.0907392502,-0.1569561809,-0.9651011229,-1.5164184570,-0.0046005156,1.8511489630,2.0630350113,-1.8583544493,1.2922915220,-1.0781641006,0.3176600039,-1.4096624851,-0.6563232541,-0.1117633730,0.6297587752,1.2154203653,0.2888377905,0.7956738472,0.3510543406,-1.1075544357,2.0214886665,0.9916204810,0.5647026300,0.5993618965,0.5231040120,-0.8116585612,0.6569921374,-1.8315339088,-0.6885490417,0.3351188302,-0.0013942909,0.8267314434,-1.9799656868,-0.6828018427,0.7968899012,-0.2808510363,0.0512608960,0.1743437499,-0.7116479874,-1.9787137508,0.5628860593,-0.6114267111,-0.4011185169,-0.2396005392,1.0169463158,-0.8091300130,-1.1353332996,0.0133572351,1.0202590227,0.2226665467,1.1409810781,-1.5810728073,-0.3684642911,-0.1554839909,-2.3100559711,1.0542657375,1.6269677877,-1.7038469315,-1.2879344225,1.0403683186,2.2401287556,0.1703069061,-0.5179620385,1.0845952034,0.4455762208,0.2167074829,-0.4839757085,0.9151929021,-0.5111671090,-1.0387377739,0.8055750728,-0.5076743960,0.0328205563,-1.5801910162,-0.4398359656,-1.1315128803,0.2544636726,-0.6623916626,-1.1471446753,0.2642677724,-0.1311631501,0.1489771158,0.8975483775,-0.2278074473,0.1106519401,-0.4545907676,0.0902820975,-0.3923905790,-0.7976117730,-0.0126832854,-0.3523421884,-0.1040960327,-0.2254287302,-0.4944473207,0.5934621096,1.1226073503,-2.1177215576,0.6347402334,0.1774308234,0.1942605078,-0.0195572022,-0.1038614362,-1.2880922556,-1.8354381323,-1.0152963400,-1.4097815752,1.7686097622,0.6368556619,-0.1358798593,0.7228752971,-0.9184829593,0.2026240230,-1.6902302504,-0.7515771389,-1.4603588581,0.1438691318,-2.3376917839,0.8028458357,-1.7040096521,0.8609021902,1.7478538752,-1.3853265047,-1.2477948666,-0.5389990807,0.7780463696,1.2358132601,-0.9333853126,-0.4348754883,-1.2053111792,0.2426356375,1.0397968292,-1.2316269875,0.6959838867,-1.7544223070,-0.6464222670,-0.4856535196,-0.3731232882,-2.0051338673,0.2533751428,-1.3090395927,0.8500843644,0.5513440371,1.5281857252,0.9997274876,0.7820481658,-0.4565566182,-1.1126084328,0.5382915139,-1.1646991968,0.3164305091,-2.3938493729,-1.0044484138,0.4640351832,-1.2155511379,0.1764370948,-0.8172885180,-1.2739762068,-1.3600958586,0.8626067638,-0.9916674495,-1.2624299526,0.9874475598,-0.2145728320,-0.5082772970,-1.6458400488,-0.3702574968,-0.9768534303,0.2904407978,1.3255532980,1.2100210190,0.1227659956,0.2595930994,-0.4679057598,0.4274121821,-1.3154900074,0.1236572117,-0.9854791760,0.5440257788,-0.5402190685,-1.1039479971,-0.9907112122,-1.3060643673,-0.5652656555,0.9776216745,0.2473392487,0.8499594331,0.7057187557,-1.3080376387,1.0187844038,-0.0227408782,0.6088210940,-0.6433678865,0.6544898748,0.9204548597,-2.7137091160,0.7325530052,0.0752336457,0.8366841078,0.9279086590,-1.1596821547,0.3568362594,-0.2196850330,-0.2727072835,0.5928372145,-0.1771852970,-0.2883036137,1.1079210043,-1.0769922733,0.4753883481,0.3450099528,-0.3523810506,1.4889559746,-0.2710278332,0.2396248132,0.6586426497,1.0482380390,0.3379995525,-0.4739660025,1.6513723135,-0.8296175599,-1.3067449331,-0.6117827892,-1.7295495272,-0.9451754689,-0.6887831688,0.4632112086,0.0821003988,-1.1309273243,-0.1603619158,-0.5950310230,0.3923758268,-1.5252598524,0.4210940599,-1.5164136887,-1.2393224239,-1.7814563513,-0.2897252738,-2.1949856281,2.8120102882,-0.8257092834,0.1937599629,1.0681219101,-0.8102371693,1.1713981628,0.3316555321,-1.2564464808,-1.2102553844,-1.8110905886,-0.3118630052,-0.6994720697,-1.5547536612,2.2070877552,-0.5162882209,1.3778606653,-0.7898684740,0.2299599946,0.1487733722,-0.8022645116,0.5625656247,-0.8308770061,-1.2218902111,0.7719486356,1.6793210506,0.6410716176,0.5552347302,-0.6866862774,-2.3685967922,-0.5928680897,-1.2760992050,-2.5390007496,1.2587535381,0.4895009398,0.1038385183,0.5110086799,0.3381683230,0.7548806071,0.1276102215,0.6869242191,1.2325774431,-0.6868656874,-0.8387863636,-0.8901911378,-0.8299873471,0.6570521593,-0.8497098088,-1.9196294546,0.1074195951,0.9909681082,1.0813125372,1.2957479954,0.7512951493,0.6021413803,-1.1488620043,0.6352616549,0.0198759958,0.9322074652,-1.4032728672,-0.5972887278,-1.1572170258,-0.1391252577,-0.0026114394,-1.2078139782,-0.6075099111,-0.1559657305,1.2921199799,-0.6285111904,-0.5723410845,-0.0440929458,2.2640471458,1.1017858982,0.1785074621,-0.4585222602,-1.4878432751,-0.4616599381,2.7842957973,-0.8562133312,-0.8348052502,0.5125629306,-1.6848424673,1.6984417439,0.4297846258,0.6659538746,-1.0364086628,-0.8324087262,0.2216985375,0.5052349567,-0.4887041748,-0.1160030439,0.7263070941,1.2204111814,0.1790825576,1.0658636093,0.2977754474,-0.5876668096,-0.7762431502,-0.5158827305,0.2565769553,0.8809493780,0.8431380987,-0.4027089179,-0.1782636046,-0.1587935835,1.3338432312,-1.4606239796,-2.0378668308,-0.1473344862,1.1285791397,-0.4220150411,1.2866398096,-0.2262062728,-0.6299557686,-0.7837253809,0.7857016325,-0.2874922752,-0.7144582868,-1.5693187714,0.4702760875,1.3465423584,1.0922623873,0.3292343020,-0.3397429287,-1.1707133055,-0.8345708847,0.1053590998,-0.9551098943,-0.0158422422,-0.6733519435,0.5780305862,0.7031232715,-0.0393282436,-0.9383910894,0.3805969954,0.7196177244,0.2210744172,0.5715443492,0.2615196705,1.4784181118,-0.0361505449,-0.9886692762,-2.5481803417,1.3661826849,-0.3472016156,-1.6215758324,-2.0042810440,0.2201344520,-0.1717495918,0.6369396448,1.3920063972,1.8210952282,-0.6172340512,0.1448362023,-0.4834059179,1.1414402723,1.8423522711,1.4584639072,2.5065975189,-0.4695457816,-0.2602095008,-0.5626283288,1.9504405260,0.4526340365,0.4930631518,0.6368220448,-0.7115779519,0.9143373370,1.0674004555,-1.4705325365,-0.1610876769,0.0818736106,0.1498768330,1.6491193771,0.0072635375,0.7203763723,1.1762765646,0.2638449371,1.9991233349,1.0177111626,0.3286144733,-1.2706656456,-0.1446818113,1.7641743422,0.8927143812,0.4896416962,-0.9942132235,0.9834810495,0.1882795244,0.7997056246,-0.6269438267,-0.7839465141,-0.7389545441,0.7751408219,0.7793362141,0.5096878409,0.2314013690,-1.4001361132,-1.2783879042,0.3915791214,-1.6315677166,1.2537792921,-0.7252321839,0.9186237454,-0.5066030622,0.5364947319,0.3846390545,-0.7608844638,-0.9879293442,1.0536998510,0.1239340007,-0.6024615765,0.7722412348,0.6044166684,-0.1003129780,0.7670496702,-0.5458506942,-1.4519466162,0.2771151066,0.3518697321,0.0249520000,2.6057703495,-0.9137113690,0.5218591094,0.0153903477,2.6444854736,1.3167178631,0.3327669799,0.6593927741,0.2390110046,-1.4895582199,0.6340134144,-1.6390534639,-1.2675498724,1.0433050394,1.2519178391,0.3263645172,-0.1726632714,0.5519032478,-0.1143158376,0.2162200809,0.9341704249,0.3033621013,-0.5463930368,0.8753668070,1.3833848238,0.8291720152,-1.2218199968,0.5906565189,-0.7905145288,-1.7524110079,0.3663987815,2.1609265804,0.8671112657,-0.5826405287,0.1804178357,0.6935610771,-0.6312169433,-0.2545692325,0.1374749988,-1.4491913319,-0.0883082896,-0.0105298012,-1.2318902016,-0.8289853930,-0.3602082729,-0.8703395128,-0.7262350917,-0.6620940566,0.6471897364,0.0936652049,-1.3356847763,-1.9162960052,-0.1310082227,0.8927040696,-1.8789820671,-0.6941149831,-0.8801056743,-2.4179081917,-0.3510309160,1.0250413418,-2.0253155231,-0.2171654552,-0.6943956614,0.4614755809,-0.2940581143,1.0993890762,-0.4676396549,-1.0508223772,1.7287107706,-0.6683145165,-0.1298807859,2.1324386597,0.9666262865,0.8443111181,-0.6013779640,0.7276886106,1.0302677155,-1.2724297047,0.9751001000,-0.1170990020,-0.2573932111,0.0356474034,-0.5298755169,-0.9047068954,-0.1097842306,0.8076342344,-0.3035034239,0.7364196777,-0.1532740593,-1.5517117977,1.3448683023,0.9069454074,-1.1535201073,-1.1836688519,0.0531910323,-0.9787717462,-0.8477154970,1.5395288467,0.1366031617,1.1396311522,2.3474342823,-0.0828050002,0.5587758422,-0.1701462269,0.2563884556,0.4576572180,-0.5936612487,-0.0666432232,-1.2495532036,-1.7759221792,-1.0503594875,1.4247668982,0.3914461732,0.0761216953,0.2842491865,0.6038943529,1.2931584120,-0.2688145936,0.6839090586,-0.0863594636,0.1521898508,-2.1591539383,0.3447727859,-0.4143142998,0.3156183362,0.1544964314,1.3025699854,-0.0636318251,0.6497617364,0.5397651196,-0.2517716885,-0.9968451858,0.2427535653,-1.6707130671,0.4256668091,0.4201525450,1.6644111872,-0.1637274027,-1.0096265078,-0.7501395345,0.3889355659,-0.3280121088,0.0683555230,-0.2293541282,0.0059699183,-1.2834771872,-1.4719812870,1.0352134705,-0.1490982920,0.2533560693,-1.1749132872,0.5028715730,-0.2666368186,0.7678294182,0.5390011072,0.1143793166,0.0369447507,-2.1100959778,-0.1035841182,0.1734765768,-0.5206263065,-1.5388579369,0.2944219708,-0.5542598367,0.3960934281,-0.5660918951,-0.5781425238,-0.4664564431,0.0804147124,0.4390437007,-0.0616029091,0.7003066540,0.6478360295,-0.2125269622,0.9341881275,-0.9784104824,0.4180209339,-0.6914352179,0.7919614911,-1.1545484066,-0.0029162788,0.8164563775,-2.1450593472,-0.7141282558,-0.1273373812,0.9063172936,0.7292864323,-1.4445300102,-0.5211780071,0.7087510228,1.8131198883,-1.2041488886,1.4940724373,-1.3090559244,1.7167582512,-1.7583614588,0.3108649254,-1.5711164474,-0.6901423931,-1.0158981085,0.4401728809,1.6992042065,1.7186495066,0.5683168769,0.7231294513,0.0740922242,-0.3422453701,-0.4967070222,0.7054743171,1.3211479187,0.2724389136,0.6408790946,-0.9621573091,-0.3153292537,-1.3749207258,0.6791490316,-0.7940768600,-1.0095255375,-1.3924701214,-0.2026451379,0.0677531809,-0.1508983523,0.5414183140,0.7144338489,-0.6705932021,-1.3298588991,-1.3412828445,-0.5634455681,-0.2916662991,0.7729437947,1.5142472982,-0.0278050378,-0.5018460751,0.6177078485,0.0424504094,0.2765903771,0.6403551698,-0.5025407672,0.5923534632,0.6478619576,-1.5444386005,-1.2579747438,1.2809257507,0.6353840828,0.4131743014,0.3158742487,1.1801162958,-0.4564170837,0.4091522694,-1.4798978567,1.2729399204,-0.8004751205,-0.4432139397,0.3686844409,0.7507426739,0.9426909089,1.6492742300,-1.5455055237,-1.2340234518,-0.9009966254,-1.2735397816,-0.0615484640,1.8640985489,-0.3493136168,0.2173888832,-2.4374730587,-0.0383728780,-0.2510394156,-0.7139562964,0.8909270167,1.3366739750,-0.0830413997,2.5130395889,0.0980813131,-0.8486409783,0.4998627305,-0.4094617665,0.5458596945,-0.4862162173,-2.0455002785,1.0393195152,0.1168493107,-1.7165883780,-1.1070877314,0.2518376708,-1.2448687553,0.5589826107,1.7770667076,-1.5959331989,1.5407427549,-0.5897306204,-1.8142468929,0.1698196530,-0.1295103729,0.5277545452,0.2446128577,-0.3235076964,1.2561858892,0.7550396919,0.1513881832,-0.4214838743,0.8148363829,1.4301729202,0.1300896555,0.4603887796,-0.8699390888,-0.0237311311,-1.1238359213,0.1377335340,0.2441793680,-1.7290854454,-0.4972402155,1.3003982306,-0.5680015087,0.5945675373,0.7442512512,-0.2569022775,-0.9850519896,0.2363358736,0.3354244232,-2.0168704987,0.6541719437,0.1009543091,0.0797480121,1.6220499277,1.1278858185,1.5643399954,1.7326484919,0.0972388163,-0.0682537928,0.5457283258,-1.9053533077,1.7635300159,-1.5515018702,-1.2203807831,-0.1801347584,-2.6934776306,0.1715345532,0.6029487848,0.0573038310,2.3573427200,-0.2083336562,-0.4516532719,-0.2417075187,0.4663243592,-0.6326389909,0.1208775267,0.2149387449,1.3439264297,1.2751500607,-0.4505316317,-0.5756392479,1.4063438177,-1.4878020287,-0.5038126111,0.9840235710,-1.0844315290,-0.2784172595,0.4415511191,-0.1162850186,0.1757821590,0.7411425710,-0.3668819070,-0.7205744386,-0.5024018884,0.2062256783,0.7241781950,1.5902775526,0.0932773799,-0.6890472174,-1.9990137815,-0.4262224734,-1.1738171577,1.1300529242,0.4181618392,-2.3131039143,0.5922805667,-0.3001381159,1.7097831964,-1.1595673561,-2.1293334961,-0.3307192922,1.2602394819,-0.7109816670,1.7607816458,-0.6528120637,1.6467469931,-0.9482585788,-0.8347230554,-0.6540571451,-0.3115817606,-1.6141192913,-1.0731090307,0.0426733084,-1.0998947620,1.0489722490,1.4080376625,-0.3871131837,0.2852624655,1.3540599346,0.5000309348,-0.0193734169,1.1629503965,1.7707066536,-0.7773700953,0.8161155581,-0.6074299812,1.9348500967,-0.7318091393,0.9646677375,0.4912351668,0.5005277395,-0.1886811703,0.6468701959,-0.6115835905,-1.4020545483,-0.2524648607,0.0008449311,-0.3852461576,0.2591911256,-0.2682701349,-1.5723091364,0.3320451081,3.2006881237,0.6155536175,0.8023455739,0.1190806627,0.1179326773,-0.0133221503,-0.1462981254,0.0558719449,0.0060142102,0.7527711987,0.2324405760,0.5915004611,-1.0211442709,0.1468193084,0.9947727323,-0.1153474972,-2.2038846016,-0.3664562106,0.8300547600,0.7540668845,-1.2107092142,0.2661699057,1.3505961895,1.9395216703,-0.1923337281,-0.5798934102,1.1088138819,-0.5727385283,0.6018813848,1.7457513809,-0.7539621592,0.3392607570,-1.8162858486,0.4703977704,-1.6360388994,0.5180320740,0.3072411418,-0.3721626103,1.7841976881,1.7781287432,0.7256065607,-0.5469256043,-1.1149164438,-1.2010357380,-0.0934013724,-0.4959301949,-0.2157954574,-2.6348752975,-0.7417191863,-0.5041836500,-1.9211819172,-0.4793742895,-1.3138118982,-0.6303048134,-0.8648637533,-1.5271095037,1.2077393532,1.3537611961,-1.0298615694,0.2516765296,-1.1857849360,-1.2759015560,-0.1323886216,0.0077520325,-1.1594430208,0.1734642833,-0.8420557976,-0.1126872674,-0.4606709182,-1.1694540977,2.2664411068,0.4393515587,0.8670080304,-0.6363406777,1.0128105879,0.5352993011,1.2980554104,-0.3366172612,0.7446729541,0.0706164017,0.5329166055,1.5777875185,-0.7912862301,-2.4273786545,-0.0999521613,0.4401312470,-0.2123771459,-0.8119220734,-1.1485599279,-0.4177002013,-0.1898192316,-1.5691518784,0.7123882771,-0.4033349156,0.1992595643,-1.0107963085,-0.7487183809,-0.3474726081,0.5490239859,-1.3117270470,0.4529985487,1.2649879456,-1.3282953501,2.2694823742,-1.9726030827,-0.1417467296,2.0489106178,0.6848044991,-1.1864144802,0.0095336009,0.5513510108,0.4967232049,-0.5022209287,0.7636085153,0.7493492961,0.9887427092,1.0534604788,-0.5208474398,1.5930726528,1.1946299076,-1.1940947771,-0.6941130757,-0.2753409147,0.3418467939,-0.3992665112,0.0144357430,-0.1594496369,-0.4563882053,1.4027935266,0.2411439270,0.0072475886,-0.8765354753,0.4561424851,-0.0980236828,-1.0085912943,-1.3533272743,-0.8581139445,0.8061968088,-1.0639472008,-0.1058177575,0.4276168644,-0.8239603639,1.8089847565,-1.5798636675,-0.0302213319,-0.3193961382,0.5277996659,-1.4658607244,0.5939242244,-0.8696262836,0.3683566749,0.4510522187,0.5968563557,-1.1456565857,-0.0630941987,-0.0725090280,-0.6521866322,1.9407103062,-1.9997001886,-0.4733425677,-0.6821983457,-2.0067911148,-0.1969090551,0.0117811309,0.8634021282,0.5490431786,0.5036259890,0.8777194619,-0.5009964108,-0.2476846427,0.7691996694,-0.4389582276,0.7626179457,-0.9946994185,-0.9002199769,-0.2358198315,0.5558941364,-0.5835582614,0.0424835086,0.5476747155,0.4497909844,2.0062038898,0.5630492568,-0.4302353561,-0.3927549124,0.6127817035,-0.3549419045,-0.0465914086,0.7972400188,-0.0291995928,-0.1873065531,-0.2666181028,-0.5908914208,0.4490607083,0.4655361474,1.3770449162,0.3744198084,2.0639455318,-0.5035088062,2.2640516758,0.8200385571,0.3762246370,0.1349862367,-0.7485954762,-0.6919678450,-1.5081450939,-0.8550764918,-0.3346778750,-0.2704392374,0.7448489666,0.6368254423,1.1909401417,-0.3652415872,0.0266696922,0.1857023090,-2.1289024353,-0.0612011552,-0.1647111028,1.5982892513,0.3783888221,-0.8879693747,0.1596832424,0.9702088833,-0.4322770238,0.7622994184,-0.9912603498,-0.0206081625,-1.8675857782,1.3297318220,-0.2855650485,0.4054629803,-0.6809203625,-0.5133872032,-1.8930710554,-0.0781741962,-0.4591271281,1.4383069277,0.9537320733,-0.9098660350,-0.5606174469,-1.1290600300,1.0253957510,-1.3523454666,0.3395365477,0.7096471786,-0.4674813449,-1.6451238394,0.8107517362,1.7173854113,-0.0553687960,0.3889346719,-1.2086811066,-0.0176033434,1.2727808952,-2.3618505001,-0.0911023468,-0.6099271774,1.4351190329,-0.2916943431,0.2546273768,1.4699568748,-0.0347926132,1.3543151617,0.0582686812,0.7119902968,1.3041653633,-0.2682042718,-0.3871650100,1.2333360910,-1.1758619547,-1.5743108988,0.2008384019,1.6558495760,1.3954097033,0.2431987077,0.6873512268,-1.5398448706,-2.1012260914,-0.8874242306,1.0868637562,-0.8933115005,-2.3817610741,-0.2322047204,0.5744912624,1.1864047050,2.0981147289,-1.0142970085,-0.2725763023,1.1405632496,-0.3188109994,-1.6895825863,-0.9098422527,-0.9992399812,0.2970742285,0.4739212394,-0.3946261406,0.9657480121,0.1714322120,-0.4725795090,0.0793206245,-1.2109538317,-0.9714989066,-1.4903097153,0.5481170416,-1.3274215460,0.1033664346,0.3240928352,-0.0927641466,-0.7859684229,-0.4100660086,0.1349842697,-0.6123028398,-0.4821889997,-0.0113635045,-0.6305410862,-0.6447528601,0.9588113427,2.0857424736,1.6361919641,-0.0809310004,0.4175556898,0.5576475263,1.1547952890,-0.9088178873,-1.3321971893,-0.6993666887,0.8384341002,-0.0056715696,0.0963145494,-2.0406420231,-0.5699337721,0.2109227180,0.1758637279,-0.1132779494,-0.1388639659,-0.5674633980,-1.0927742720,0.4664836824,1.3453660011,0.9642984271,0.1735391319,-0.6066111326,-1.8372893333,0.0989775285,-1.0595743656,-1.7484507561,1.3843749762,0.0083545428,0.3311144710,-0.2330202758,-0.4341944754,-0.3969227970,-0.7791808248,1.1586873531,-0.7870743871,-1.3215303421,0.5297895074,-0.5042585731,-1.6013978720,0.6434103251,-1.1106889248,1.0323313475,0.0253233518,-0.5326119661,-0.7091501355,1.1146080494,0.3246107399,0.4328122735,0.1061507687,0.9968009591,-1.5700018406,0.9111320972,-0.1880164742,0.0720187649,-0.1722674072,-1.2956403494,0.1623233408,0.9533376098,0.8453432918,1.0247024298,0.8314163089,0.2169153392,-1.1605566740,0.6202650666,0.7922874093,-1.1443600655,-0.1555470228,0.2054934651,-0.0696882978,1.5672497749,-0.6392518878,0.6004613042,0.2808816433,0.9697634578,1.3994048834,-0.9369864464,-1.0598493814,0.6915630698,0.0257297009,0.5673299432,-1.9622377157,-0.7675710917,0.3625481427,0.7994940281,-0.0520695336,0.0688188747,0.7390265465,0.2610666752,-1.5965384245,0.3458299041,-0.7521305680,-1.3208951950,0.5133634806,0.6769243479,0.8414777517,1.7870870829,0.5016800761,0.6279888749,-0.0259170141,0.0858539417,-0.1149455160,-0.9918748140,1.3966687918,0.5319203734,0.0872511491,1.2238022089,-0.6457444429,0.6148810387,-0.2943848968,-0.7676346898,-1.9957956076,0.0006206976,-0.4282977879,-0.3669142425,-0.2334992588,-0.1813053340,2.3843736649,0.0274813995,-0.2801706195,0.0149513474,-0.2649163604,0.2022246122,-0.3847317100,-1.1576153040,1.6478676796,0.5820747018,-0.2079120427,-0.1404580623,0.9750667810,-0.6656797528,-1.0515507460,-0.5181403160,-0.0723514110,0.9246936440,1.0558516979,-0.2617908716,0.0100078853,1.4384540319,-1.5206338167,0.7696095109,-0.7830299139,-0.6658165455,0.8587329984,0.0302361734,0.7325266004,0.6763762832,-0.9670042396,0.5436664820,-0.0928966329,0.2728548050,0.7476511598,0.8182846308,0.0401502326,0.0703607574,0.7100747228,-1.1809411049,0.1525679231,-1.4360591173,-0.9362903833,0.6512863636,2.5559821129,-0.4898336828,-0.5570479035,0.3082244098,-0.1268011928,-0.1690266579,1.1079031229,0.5577710867,1.2079291344,0.3057589829,1.4704600573,-1.5299013853,-0.4372470081,-0.1838792264,0.4103325903,-0.0079925116,-1.4350907803,3.0050628185,1.9440249205,-0.5308479667,0.7670062780,-0.1695310771,-0.4937400520,-1.0065364838,-0.3335910738,0.2164574564,2.0567500591,1.0385917425,-0.9172860384,0.1360678822,-1.4758296013,0.2109170258,-0.6283934116,0.4619432986,1.2396088839,-1.2901101112,-0.4787948728,-0.0482119285,-1.3737345934,0.3587618470,-0.1970571727,-1.1884554625,-0.3847505152,-0.4059247375,-0.8413720131,-0.2346312255,-0.5250424743,-0.8797713518,-2.2436685562,-0.1204453632,-0.9047447443,0.1623364985,-0.1249333546,-0.4604585767,-0.1806154251,-1.5818452835,0.7564077377,-0.3526729941,-0.5011270642,-0.4888699055,0.2328237146,-0.8190051317,-0.8744320869,-1.6677303314,1.3656442165,1.3829454184,-0.1329779178,0.6396308541,-1.6524884701,0.8636744618,-0.6694845557,0.8651663661,-0.9834919572,0.9883199930,-1.2616648674,0.2136829346,-1.4948030710,-0.5576620698,-2.1199064255,-2.6051251888,0.8021505475,0.2092306316,0.8647927046,-1.0634721518,-1.7716604471,0.1749333441,-1.3047918081,0.8585357666,-0.0653507933,0.8114531040,-0.8026093245,-0.2348457277,-0.1972251832,-0.1731291860,-0.9763115644,-0.4425777495,0.1876048744,0.2390181720,0.5495560765,-0.4430482984,0.5191142559,0.3313212991,-0.2732692659,-0.1305333972,-0.3552298546,-1.2423542738,-0.4154689610,-0.5192009211,-1.0146884918,0.0872632042,1.0132828951,0.7355144620,-0.8626582026,-0.9035837650,-0.1659100503,-0.4304459989,0.8710014820,0.2093449235,1.7577981949,-1.4495869875,0.3389512897,0.3277698159,-1.3833289146,-1.0309791565,0.5938034654,0.3381133080,-0.7506350279,0.5864959955,0.6818603873,0.9190769792,-0.9943068027,0.7560220361,-0.2823075950,0.4619690776,-1.0569438934,-1.6896722317,2.2968416214,0.1863039136,-0.4671124518,-1.7164677382,-0.0640422776,-0.9713795185,0.9030221105,-1.0318793058,0.7022774220,-2.5937387943,0.9347560406,-0.0407111496,-0.0842949972,2.1857056618,0.8122920990,-0.1597754359,-1.2797119617,-2.5321006775,-0.9836844802,-0.3681376874,1.4671288729,-2.6063854694,0.1413185447,1.1272912025,-0.3143338859,0.2970275581,-0.9995012879,0.3840419352,-0.8541126847,0.1262938529,0.8874447942,3.3216011524,-0.0434766375,-0.2402396351,-1.7334960699,-1.1922539473,0.0395632051,0.3123318255,1.5156829357,0.1709397286,0.4083366990,-0.2023052424,1.5522542000,-0.4802343547,1.6968504190,1.4456083775,0.2222046554,-1.3635166883,0.4523965716,-0.1486860216,-1.3813056946,0.2926163673,-1.4815069437,0.0460004359,0.0685515702,0.8657517433,-0.4926210642,0.3616339266,0.2384285331,-0.5062540174,0.9793159366,-0.3106910288,1.4108459949,1.4620524645,0.2490852475,1.3678778410,-0.6981250644,1.0042148829,0.9979116917,0.4013634026,-0.5294713378,-0.9604782462,0.7616765499,1.0867910385,2.4451165199,0.5009768009,0.5941057801,2.1568233967,-0.2864334583,-0.7203481793,0.2201959938,0.0211936776,0.2499561757,-0.5913699269,0.4207766056,0.5149331689,-2.2674925327,-1.3170949221,0.0806484967,1.6441719532,-1.6811925173,-0.7950924039,-0.5914666057,-0.4738128781,1.3944123983,-1.1955771446,-1.4249742031,0.6435713768,-1.5451512337,-0.0101473620,2.2087171078,-0.9800808430,-1.4776380062,0.7782774568,-0.7789295912,-0.0102034928,-0.0880911723,-0.4840727150,0.7514572740,0.0549944900,-2.4430112839,2.1914079189,-1.0618168116,1.4040321112,-0.2890518904,-1.8754194975,-0.4907815754,-0.0630276427,-0.7582322359,-1.1303482056,-0.7832784057,-0.5160414577,0.0700457245,0.6622155905,1.1924040318,1.4414311647,0.6065171361,-0.4135439694,-0.1386700422,-1.0272814035,0.4866032004,0.1530758739,-0.3026266694,0.2846779227,0.0424417257,0.5401003361,-0.7115367651,1.5831142664,-0.2675635815,-0.0213743374,-0.0043467307,-1.5642577410,0.9680214524,-1.3408775330,0.1488857120,0.2985931039,-0.5775466561,-0.7951164246,-0.4007186294,-0.5162972808,0.4733025432,0.2995747328,0.8256702423,1.2272002697,-0.0659088045,0.4785670638,-1.1270323992,-0.5993215442,-1.5867478848,0.1878347248,-1.2973229885,2.1392738819,-0.5237012506,0.4061898589,0.1321331561,0.1819093823,0.3166199625,0.1830487847,1.1566855907,-0.9360304475,-0.1669008881,-0.5197641850,0.7517486811,0.0689731315,-0.3164053559,0.2283985317,-0.4720411599,0.3385706842,0.4731729925,0.4821418226,-0.7884815335,0.3731731176,-0.7758998275,0.7502189875,1.0179754496,-0.2132595032,-0.6256816387,0.6563635468,-2.0351250172,-1.6866027117,0.7681083083,-1.0538374186,0.0967316404,-1.3432598114,-0.2516896725,1.4454326630,0.1537240297,0.7852683067,0.1986494809,-0.2295962125,0.3377442062,0.9981122017,0.7033475637,0.8179015517,2.8854703903,0.1449834108,1.5653721094,-0.8830209970,0.2447814792,-1.6657313108,-1.0418515205,-0.0914706290,-2.2588729858,0.2607210279,-0.6904564500,-0.2766918540,0.4198768735,0.6650484800,1.2362228632,0.2318393737,-1.7664381266,0.2203081250,-0.6439874768,1.3943929672,-0.2212222815,0.5396524668,-0.9326766729,-1.1483886242,-0.5559464097,-2.1605238914,-1.5237659216,-0.8512112498,1.4548479319,1.4710714817,-0.0255904552,-0.0392868333,0.8066657782,0.2605836093,-0.0717089623,-0.4921136498,-0.7088971138,1.3106839657,-0.7427183390,0.5950650573,0.4102731943,-0.7450366020,1.2448486090,0.8819051385,1.2929413319,0.7543784380,1.5012474060,0.5012357831,1.6025744677,-0.1244885102,-0.7437287569,0.7625656128,1.5684475899,-0.8715553284,1.5655452013,-0.4011086524,0.3054696023,1.0253591537,-0.6708995700,0.3336648345,-0.7808531523,0.2032589763,0.4629889429,0.8305130005,1.3792150021,1.0666061640,-0.5386751294,1.8384336233,1.6489225626,-0.5408121943,1.1491128206,0.3872258961,0.7378184795,0.5292190313,0.1566731632,-0.8639983535,-0.4543217719,-1.1172450781,-0.1373617202,0.0493386127,-0.6242133379,-0.0747201517,-0.0418696329,0.1286173165,-0.2732076347,-1.2780323029,0.0635503307,-0.4641813934,-0.2046342939,-1.7704610825,-0.6292266846,-1.5954760313,-0.6125565171,1.3553122282,-0.6214655042,0.3244607449,-0.1392270476,-1.7893319130,-1.6337937117,1.2505484819,-0.3817860782,1.0203552246,-1.7707964182,1.5794938803,0.9360316396,0.6239099503,-0.5742901564,0.3519190848,1.6146284342,0.4477892816,-0.3142979741,0.4781792164,0.6606804729,-0.0335218385,-0.5427355766,-2.5328576565,2.1415202618,-1.8951349258,-0.2973324358,1.1050219536,1.2794615030,-1.4703121185,-0.4997144043,-1.1340399981,0.5188848376,1.5461864471,0.6832302809,-1.0181527138,-1.8280473948,0.0570660420,0.2686289847,-1.2347159386,0.6066080928,0.8530008197,0.3568423390,-0.3545398414,0.3357949257,-1.1221921444,0.1614009887,-1.2751108408,0.1513240039,0.6052228808,-0.0645731688,0.3507217765,-0.3744005859,-2.7758972645,-1.1287082434,-0.0116145117,1.3980032206,-0.0176374651,-0.1791180372,-0.4948559999,-0.4348399043,0.9603962302,-0.9801307917,-0.6622002721,-0.0265429523,1.6936491728,-0.0890061557,-0.1063767895,-0.6456767321,-0.6210477948,-2.4629504681,0.5300250649,-1.1274645329,0.1202629134,0.7539504766,-1.6694158316,0.8432223797,-0.6346231103,0.5511178374,-1.6847029924,-0.3897745609,-0.1799215525,-0.3502997756,0.7974809408,0.7187066674,0.5191764832,-0.1159625053,0.9157214761,-2.1128296852,0.5010185242,-0.4072211087,-1.2765816450,1.9876989126,1.3443856239,0.2349775285,0.6620453000,1.3393974304,-1.2028733492,-1.1018798351,-0.2779258788,-0.5651109219,0.4557473958,0.4294156134,0.3529987633,0.7264522910,1.4002771378,-1.0009080172,0.0965322256,0.9219058752,0.3410715461,-0.7426944971,-1.0091520548,1.4181830883,1.5620485544,0.4852831960,0.4569746554,-1.5205644369,0.8606964350,-0.0159703139,-0.1952470392,-1.7966439724,1.2196379900,-0.2568109930,0.1493610740,0.1471642554,-0.1334927678,-0.0951507837,0.8027544022,1.8461946249,0.5527061224,1.3992179632,-0.4277961552,1.2142347097,0.0890079811,1.1724892855,0.8421200514,-2.0531296730,-0.3815230131,-1.2456768751,-0.2631421089,0.3498506546,3.3013672829,-0.3395608068,0.9844453931,0.7795133591,-0.3801021874,0.4742499292,-0.5515266657,0.3347168565,0.4604980946,0.8324033022,-0.0461973809,-0.1935420334,-1.0834821463,-0.5094074011,1.4313070774,1.1016554832,-0.2138853818,0.4686948061,1.3630285263,-0.5100106001,-0.1556339264,0.3429749906,-0.3238503933,-1.0426410437,0.1445600837,0.1049434692,-0.2222164124,0.4424103796,-0.1254242659,0.5358566642,1.5508053303,0.6763385534,0.6407976747,0.1865347624,-1.2624466419,-0.4919446707,1.0839577913,0.8675064445,0.2160370052,1.4639556408,1.1394736767,-0.7107564807,0.0310300067,0.4451051354,1.2646448612,0.6961842179,0.3952502310,0.8698752522,-0.8570802212,0.2444748431,-0.3380377889,-0.3063204885,-0.6506505609,1.0126060247,-1.2486658096,-0.4531163275,1.3865495920,0.8400343060,0.8887103796,0.1331875622,-0.4949502647,0.2909305990,1.3711076975,-4.4466323853,-0.3461068869,-0.4214496017,-0.3191107810,1.4321105480,0.5082851648,-0.4887852967,-0.2842614055,-0.4167383611,-0.5153347254,0.1215999797,-0.9909867048,0.2912752628,-0.0309490580,0.0686672628,0.3116374612,-0.9446466565,-1.4318141937,-2.3070585728,0.1934504807,0.0642832592,1.6173255444,-1.4001069069,0.9930692315,0.4986160100,-2.1691753864,0.3272755146,-0.5290307999,0.3029612601,0.7106252313,-0.5628217459,0.3532442451,-1.2171857357,1.0224491358,0.0653357655,1.4942281246,-0.9784055352,0.9602708220,-0.2665057480,0.4682205617,-0.6420611143,-0.7896304131,-0.2709776163,0.8798081875,-0.2442070842,0.1087937206,-0.3002286255,-0.5277259946,0.4140106440,-0.2964256108,1.4545035362,0.4128693938,-0.8971816301,1.0674988031,0.1346273124,-1.0002290010,-1.5374671221,-3.4322154522,-2.1081695557,1.6781947613,0.0430080853,-0.2318437546,0.4126449823,1.4264055490,-0.5483173728,1.1825624704,0.0128414826,0.3367869854,-1.4143692255,0.1019542515,-1.7843068838,0.2959744334,0.6726202965,-0.4266151190,0.1067341939,0.2738974392,-1.5534147024,-0.8846866488,0.4381192923,0.8158077002,-0.0652576610,-1.3206679821,0.6635075212,2.6380484104,-0.6187989116,-1.0136746168,1.8584141731,0.6533104777,-0.4259442091,-0.1774014086,1.4402084351,-0.1898958385,-1.1205271482,-0.5485401154,0.1698873043,0.0687155649,0.0311105829,0.3088907599,0.3787349463,0.3809392750,0.0914585218,-1.4571095705,0.9450003505,-0.7444524765,-0.7551084161,0.9248359203,-0.2947985828,0.9806703329,0.6765164137,-0.4960588217,0.8475109935,0.7173162103,0.7837095261,0.4317607582,1.0102860928,2.1032080650,0.1576048732,0.0173003376,0.7079991102,0.6061809063,-0.6047534943,-0.1859838217,-0.9648866057,0.3602762520,1.5325679779,0.0651429519,1.0650039911,2.5460152626,-0.6730990410,0.2153566033,0.9968594313,-0.4184798002,0.3913473785,0.2801388502,-0.1887837499,1.6170681715,0.3825345039,-1.9914906025,0.4941851795,-0.1115392447,0.0824190080,0.2398149073,0.7439398170,0.2233340293,-0.7043433785,2.8407576084,0.3171818852,-0.0780908912,1.0117206573,-1.3970212936,0.2704565227,1.1053961515,-0.8552007079,0.1994792670,-0.7967630029,-1.7464600801,-1.4587714672,-0.9694950581,0.4347965121,0.7123994231,2.5555636883,0.2164577097,0.4949950576,0.8548553586,0.5338478088,1.8773450851,1.8840982914,-0.6057417393,-0.2921206653,0.3764616251,-0.8626120687,0.6312596798,0.1972151399,0.8950186372,2.1432530880,-0.5009615421,-0.0870208442,0.2992241681,0.1273721606,-0.5634948611,0.8877972960,-2.2128298283,0.4280473888,-0.2503516078,-0.0595523603,-0.0990573093,-1.3535153866,-1.0699493885,0.9600315690,0.3506530225,-0.0972179323,0.6288717389,-1.3509629965,0.1111599132,0.2762899995,0.8108143210,-0.1749507338,0.6180928946,0.0537807047,0.4083303213,0.7938087583,1.3735338449,0.1129539311,0.7087584138,0.2543578446,-0.7406477928,1.1616770029,-0.4258893132,0.5054414868,-0.4079273939,-0.8973106742,1.5773397684,0.0967438072,2.5411305428,1.1561323404,-0.3894842565,-1.9563227892,-0.3720968068,-0.4485727549,1.4407653809,2.2971429825,-0.1074938774,-0.1706637144,0.2393594086,-1.2897298336,-0.2838257849,1.4366940260,0.5021362901,-1.3120448589,1.3362712860,-0.9349203110,-0.1795876771,0.2796979547,0.3275337815,-1.5682973862,-0.1581210196,-0.4314252436,0.5257216692,0.5361158252,0.9633139372,0.0385950543,-0.2250328809,0.0394976810,-0.6151430607,-0.4402093291,-1.7778775692,-1.0987372398,-1.1117931604,-1.4587020874,-0.5599415898,-0.8956044912,0.5017939210,-0.3279520869,0.1389401406,0.3314218521,0.9030095935,-1.1500355005,-1.9140057564,-0.4541152418,1.1774168015,0.3544850051,1.1513677835,-1.0737146139,-0.2920063734,-1.4028655291,1.5057044029,0.3650828898,-0.8197543621,-0.6998680234,0.3804240525,0.4712976813,0.5005731583,0.2035487741,0.9716621041,0.5432396531,1.3573894501,-1.0096626282,1.6208111048,-0.5277240276,0.8372216225,1.8990112543,0.0555527322,-0.7414680123,-1.0119155645,-0.1866538525,0.8219956756,0.2626342177,-0.0517387129,1.0967673063,0.4631964564,-2.2763576508,-0.9005764127,0.4502929151,1.2675552368,1.4029026031,0.0410192646,0.4613499939,0.8826645017,-1.8186287880,-0.7178622484,-0.1207559109,1.4767705202,-0.0755815879,0.7688866854,0.4810449481,0.6946743131,-1.5904605389,-0.7692117095,-1.4830653667,-2.5812559128,-0.9567979574,-1.4820371866,-0.6474533081,-0.4920964837,0.6667062640,-0.0434637107,-0.4990424216,1.0992600918,0.7525292039,-1.6032221317,0.5581198335,1.3076291084,-1.6271916628,-0.9884853959,-0.3797832131,-1.3973912001,-0.3615023196,-1.9054090977,-1.2950693369,-0.2564415634,-0.4667300582,-1.2958893776,-0.5529566407,0.0508099534,-0.5288753510,-0.7055816650,1.2113600969,0.3943111897,0.2387282550,-1.2374818325,0.2701815963,-0.3978709877,-1.1572402716,3.0878937244,0.8014529943,1.8457676172,-0.0689089596,0.9194198847,2.2617175579,0.6498615742,-0.7515003085,-1.0202875137,-0.3537638783,0.3832994401,3.3604583740,1.0071740150,-1.1935818195,0.2676483095,0.3094398081,1.2086896896,-1.2866652012,0.7168079019,0.2362437248,-0.5765281320,0.7539612055,1.2162506580,0.2970718741,-1.2590700388,-1.1305162907,0.6088635325,0.4285758138,0.8790427446,1.0297600031,-0.0150263263,0.5672517419,1.9943733215,-0.2904198468,2.2879085541,-0.6683076024,-0.9014266133,1.1198561192,-0.3908662796,-0.7119098902,-0.1672258079,-1.8771710396,1.4835146666,1.5566693544,-0.5456945300,-0.3992888927,-1.8576182127,-0.0591329224,1.1905106306,-0.7533163428,1.3647427559,1.4910933971,-0.8707145452,-1.2028700113,0.1947313249,1.4388641119,-0.7994881272,-0.1219984218,1.3156124353,0.4465557039,-2.8038535118,-1.6329493523,0.4930388033,1.1889687777,0.9552270770,-0.8060735464,-1.2271238565,1.5816148520,1.0718077421,0.0845048428,1.0317893028,0.3432446420,0.4551599324,0.2916109264,-1.2060781717,-1.1404657364,0.1325116307,-1.1530866623,1.4436823130,1.3028328419,0.4774630666,-2.2254891396,-0.4252972901,-0.3897869885,0.3375076354,0.8366788030,-1.5183181763,-0.3942394257,0.3418150246,-0.9899711609,1.7337936163,-0.6356321573,-1.4572966099,1.1070363522,-0.3804219961,1.2175976038,0.1318281144,0.3227569163,-0.3193053603,1.1206564903,-0.9782357216,2.5470190048,-0.0272714552,1.3424437046,1.3656324148,0.1930369586,0.4632759094,-1.6178817749,0.5364732146,-0.5179991126,0.8289573789,-2.2828421593,-0.7208089232,0.5070265532,0.0186515842,0.0308151282,-0.5973554254,-0.3513200283,-0.2779895365,3.2370834351,0.0105593828,-1.0757038593,0.9850459695,-0.0400293693,-0.2541744411,0.2447330952,-0.1110943928,1.3795638084,-0.2299806774,1.0006225109,0.5272231102,0.8905154467,2.0872952938,0.6532689929,-0.3763174713,0.6781877279,0.3656844199,0.9306739569,0.2416982949,-0.3654942513,1.8575373888,0.1327817738,1.4138320684,-0.7374867797,-0.6212695837,-1.1035248041,-1.7859196663,-0.3236762583,0.2797504067,-1.7126622200,0.3749800622,-0.3638271987,-0.2331794649,0.4900467694,-0.1618707776,-1.4507075548,0.4063182771,-0.1040311977,0.7966028452,-0.3308908939,2.0540111065,-0.8186672330,0.0951378867,0.3161187470,0.3237067461,-0.2970733643,0.0833072290,1.5167295933,0.5328765512,0.3028484285,-1.4206554890,-0.4329741299,1.3647885323,-0.0198237337,1.1204465628,-2.4348003864,0.6366173625,-0.3564464450,0.6139984727,0.0905427411,-0.0487639718,-0.7035763860,0.3491133153,-1.6848409176,0.2357283682,1.1717361212,-0.8481423855,-0.2195025980,0.3186892569,0.2741073966,0.3729113638,0.2715400457,-0.4458433986,-0.3774275780,0.6609749198,-1.0435019732,-1.1683075428,0.2231950015,-0.1027064696,0.5333796144,-0.4214748740,-0.8696775436,-0.5515634418,-0.0729684234,-0.3588608801,-0.7902694345,0.2904454768,1.5837885141,-1.0763326883,0.0376655497,-1.5118037462,0.0069348137,-0.3564294577,0.6037105322,0.0964799896,1.5362436771,0.2995141745,1.2214409113,0.7883645296,-0.0879966095,0.6117028594,-0.3020986915,-1.8245121241,-0.2724688649,-0.1164358258,-0.5263771415,0.2055741847,-1.6351301670,-0.1721231043,0.4942176640,-0.6478079557,-0.7820081115,1.2534043789,-0.9469304085,2.0706932545,0.6533148289,0.5774577856,-1.9339703321,0.7606521249,1.7944775820,-1.0832855701,0.7078484893,-1.5409542322,-1.5427272320,-0.6692368388,1.0229578018,1.4193599224,-0.9133544564,0.4840072691,-0.9753501415,0.2186499238,0.1535844058,-1.3288750648,0.3165779114,-0.8043466806,-0.7737863064,-0.0225233603,-2.1306989193,-0.0007973393,-0.1462996751,0.3758448362,-0.5482758284,-0.2904385328,-0.2203367203,-0.1360739022,0.9308471084,0.5719411969,-0.8307803869,1.6780029535,-1.1897013187,-1.1363524199,0.5443426371,0.6116832495,0.9746663570,-0.3817377985,1.8900529146,-0.7435458899,2.4997756481,0.2572008967,-0.1710775048,1.5151948929,0.4258111119,0.7934648991,0.6231244206,-0.4840977490,-0.9201597571,-0.4832959473,1.1362259388,-0.7039580345,0.8110657930,0.6199864149,-1.2173436880,0.7433096766,-1.2307972908,0.8163778782,1.2898740768,-0.9440120459,0.7128977180,0.3834163845,-0.2448080033,-0.4208971560,1.0776454210,-0.9177082777,-1.3809242249,-0.0549273714,0.4324325323,0.8900623322,-0.1035629958,0.6625125408,-1.1518876553,0.2836413383,1.2821938992,-0.2739796638,0.4010577202,-0.3207268715,1.7261518240,0.5400056243,0.1708711684,0.6841276288,0.5838326216,-1.1475074291,0.9617252946,-0.5272442102,-0.3061755896,-0.2802444696,-1.2695152760,-1.6422095299,0.3058715761,-0.0128703928,-2.6293754578,-0.3578370512,-0.4003086686,0.9074838758,0.9345986843,0.9679060578,0.3018855453,0.0361836366,0.0973763913,-1.6076494455,-1.4042066336,-0.7118547559,0.5561019182,-0.0364919156,-1.5172846317,2.4007532597,-0.1681730747,-0.9137525558,-1.4355233908,0.7524472475,2.1874260902,0.5050536990,-0.4081895053,-0.2869866192,-0.7814391255,-0.9182626009,2.3791458607,-1.1824381351,0.0357667170,-1.0054905415,0.2820036411,-0.2671211064,-0.1642470062,1.4117362499,-0.2460403889,-0.7910364866,0.9709326029,1.2122645378,0.3736355901,0.9546735287,-0.5189890862,0.8345152140,0.1865234822,0.9267693162,-0.7936452031,-0.1931727082,-1.2181763649,-1.1549400091,-0.3107994795,0.3828459978,-2.1461999416,0.6490299702,2.1667606831,0.5197604299,-1.0844227076,-0.5551661849,0.5941517949,0.8355113268,0.0238041356,-0.1456642449,-1.7534958124,1.0213720798,-2.0443327427,-0.8794829249,-0.8769536018,-0.2262274176,2.2516703606,1.2893469334,-1.1498097181,-1.9233324528,0.4795956910,-1.0476869345,-0.1603702307,-1.3869994879,-0.4466053545,-0.1670096517,-1.2587105036,-0.6671476960,-0.1938714534,1.3857107162,0.3265101612,0.3107939661,2.0093312263,0.8311404586,-0.3633439541,0.9202536345,1.6982054710,1.0785430670,-1.1998401880,1.0437088013,0.9129307866,-0.1036761850,0.9082722664,-0.1097550467,-1.1004810333,-1.0039086342,-0.5625741482,-0.7018459439,1.0801191330,0.2250289023,0.6520404220,-0.2414115965,-1.3095985651,-0.2076982260,0.1262160689,-0.5799643993,0.1192129403,-1.1732382774,0.9104181528,-1.1093168259,1.3726590872,0.5925967097,-0.5359659195,0.7879594564,-0.5177975297,-0.1359538883,0.8724327087,1.2267098427,-0.2726623714,-1.2737469673,0.3153249323,-0.3683904409,-0.3502188623,-0.2695860863,-0.3834236562,-0.7484129071,-1.8965317011,0.4718063474,0.8372075558,-1.8106716871,-2.5100286007,1.0228426456,-0.2571284175,0.4561365843,0.1014745757,-1.9939613342,1.5270358324,2.7336032391,0.5241632462,0.0706301928,1.5364835262,0.4563824534,-0.2476233393,0.9482578039,0.4184074104,0.4652556181,-0.4185591042,-1.7924579382,-0.0816290453,0.1231039241,-2.1013731956,0.3075747490,0.9703420401,-1.1419631243,-0.2391041815,0.1807586849,1.3525646925,-2.1389710903,-1.8200509548,1.4221153259,-0.8525925279,-0.1797548085,-0.8431107998,-0.9901415706,1.7518792152,-0.6028918028,1.2872824669,-0.2191602588,0.9963245392,-1.0853056908,0.5814145207,-0.2415531278,-0.2949104905,-0.1386898309,0.9096865058,-0.2297956049,-0.5122372508,0.6257262230,-0.5922887325,-0.7369153500,-0.0611394197,-0.4971470535,0.4321023226,0.9778766632,0.1208294109,0.2494894415,0.0673965141,-0.1767411530,0.9871430397,0.2811503112,1.9028134346,-0.2427451164,-0.9117431641,-1.3278282881,0.0232584253,-1.6634082794,0.5697232485,-0.7888104916,0.2057036310,0.3429163396,-0.7559013367,0.9190707803,1.5341836214,1.0631592274,-0.7089481354,1.8540906906,0.6824290156,-0.8776482344,-0.9802616835,2.3940370083,1.6527678967,2.0181610584,0.0669684559,2.7364752293,-1.0129966736,0.2716617286,-0.1089972779,-0.0572592542,-1.0589312315,-0.3265284300,0.3300458789,-0.0004799794,0.8181158900,0.4282137156,-2.5039472580,0.1204811335,0.8078928590,0.6021209955,-0.8651900291,-0.1533203572,-0.2404905558,-0.0607633479,0.5328661203,0.7644009590,-0.8560833335,-1.6823405027,0.6530694366,0.9302550554,0.4051826000,0.2040024847,-0.8227655888,-1.2768743038,-0.2264368683,-1.0160527229,-0.6572948098,0.2939909101,0.6200525165,0.7796336412,0.4549840093,-1.3034356833,-0.5644497275,-0.6971324086,1.0378397703,1.5601544380,-1.4602061510,-1.9396758080,0.5265857577,1.6603387594,-0.3638090491,-0.0310451910,-0.3636223972,1.2418016195,-1.6686720848,0.6132101417,0.0434691086,0.1165482178,-0.5786048174,-1.2646787167,-0.1174873859,-0.4851864874,1.0230669975,0.1483554542,-0.0294206236,0.8758327961,0.1348077953,0.0840644166,0.8931159973,-0.1384363919,-0.2515294552,0.5490271449,1.6555695534,-1.3272736073,-0.1325270534,-2.0754849911,0.6027877927,0.4861270487,2.0449700356,-0.6894755363,0.3789910376,0.3894831240,1.2121812105,0.1136562079,-1.0378799438,1.5067687035,-0.4767748713,1.2916351557,1.2961734533,1.1144324541,0.1773619503,-0.2875421047,1.4568520784,0.8501911163,-0.3830829263,-0.6213039756,2.2090291977,1.0792033672,1.1268278360,0.1464464664,-1.0442385674,0.3112875223,0.9527289867,-0.1369006485,0.1579798460,0.9468470812,1.1619044542,0.1117127314,-1.2547981739,0.0041935598,-1.8870812654,1.8109247684,1.2467620373,-1.1706187725,-0.8198552132,-1.0388509035,-0.3795161247,0.2471856773,0.0978375450,-0.3687669337,1.4281040430,-1.2668262720,-0.7314748168,-0.2361954153,-0.0640455484,1.5850062370,0.5684098601,-1.0112850666,-1.1607600451,1.6386686563,0.0010163832,0.6599608064,-0.5040879846,1.7607916594,-0.2987151444,-0.0699679181,-0.2390695810,0.0480869710,-0.0561540872,-1.4012265205,-0.4074691832,1.0456372499,-2.2115867138,0.1003632694,-1.1718195677,1.9943586588,-0.7404477596,-1.8472335339,-0.3663715124,1.6781787872,-0.3644346595,0.2316042483,-0.6349893808,-1.0591756105,-0.3665927351,-1.3370912075,1.3054594994,0.0549971089,-1.1565880775,-0.1878262907,-1.7153264284,-0.2808305323,0.3602373302,-0.7212537527,0.5203909278,0.6193087101,0.0597162433,1.3419901133,1.7610182762,-0.4293690622,0.7105035186,-0.2299219370,-1.1954588890,1.5433597565,0.2379141748,0.7672137022,-2.1098141670,0.6415581703,-1.4304503202,-0.5032683015,-0.1808628291,-0.9698618650,0.9286208153,1.2245706320,-0.8532410860,0.3880198300,-1.2975735664,-0.7356634736,0.1969772279,1.2833096981,-0.2106740475,-0.1530257016,-0.1989236623,0.6560999155,0.1675494611,0.4150153399,-0.2940008044,-0.4093782008,-0.8216152191,-0.4769310653,0.9040605426,1.2138260603,0.8652194738,-1.1292105913,1.0701618195,-0.1425126493,-0.8724672794,-1.6130620241,0.0751923323,0.4281897247,0.1331243962,-2.1410734653,-0.9063301682,-0.3643827438,-1.4411940575,-0.8983129859,0.4188375175,-0.6246270537,1.0137139559,-0.0459714942,-1.2153115273,-0.8810849786,0.9074236155,-2.5559902191,2.1576261520,-0.4590293169,-0.9930305481,1.8669599295,-0.4173523188,0.9735121727,-0.5194160342,1.8311252594,-0.2143068463,-0.3267007768,-0.7139260173,-2.0381011963,-0.5063050389,0.6719281077,1.2255204916,-1.0252617598,0.2913454175,-0.5917704105,0.7488190532,1.6724610329,0.8395947814,1.7179481983,-1.6458688974,-1.7235046625,1.6781872511,0.6279851794,-1.2300579548,0.2063685060,1.7433674335,0.2346530110,0.7607139349,-0.3385611773,-0.2102975249,0.0059588552,1.4260768890,0.0142158372,-0.4406615496,0.2704971731,-1.0747419596,-1.3426505327,-0.1716880351,-1.2444826365,-0.8974450827,-0.0273043569,1.3485187292,-0.2789664567,1.0251704454,0.1180881709,-0.3778805137,-0.2141260207,0.4078404903,0.3173700273,0.3696385920,-3.5518553257,-0.0249717198,1.0215418339,0.6116573811,-0.8735608459,1.9158036709,1.0758155584,1.0407550335,-0.1262805015,-0.1615180820,-1.1025336981,0.7169651389,1.9114420414,-0.7175180912,-0.2838610411,0.1815304458,0.0509980470,0.1601001769,1.3206021786,-2.0074746609,1.1405119896,1.0774667263,-0.3010169268,-0.0158685166,0.2949124277,-0.9155491590,0.0511295386,-0.9183694124,0.4059500396,-0.9847790599,-0.3063639998,0.2768558264,0.6799152493,0.1374379843,-1.7768172026,1.0458937883,-1.5003950596,0.2859581411,0.4456777871,2.7115471363,0.0316340886,0.0237582047,1.3859419823,-0.2100570202,0.5256478190,-0.0925751105,-1.4566472769,1.6074087620,-0.4122121632,-0.8000978231,-0.4829004407,0.7124879360,2.1299157143,-0.0259689819,-0.2674769461,-0.5260988474,-0.1544209272,0.8619582653,0.1432756037,1.1954751015,-0.4071525037,-1.1334422827,-0.1827943474,-0.1172728464,0.1429066360,-0.6256256700,-1.1532642841,-0.7034975290,0.5680677891,0.2888707519,0.1756383628,0.5803961158,-0.5129320025,0.0149797229,0.9116480350,-0.1075092405,2.3236284256,-1.1821206808,1.3360717297,0.5781747103,0.2877194285,0.4588770568,-0.1316705644,0.0050465642,0.5311812162,-0.7386845350,1.6503698826,0.8862819672,1.2689412832,1.4950553179,0.0704524592,0.9109133482,0.0946484506,-1.0497871637,0.7867195606,0.2191394717,0.8150247335,0.0630580559,0.1004397869,1.4962004423,0.3818966448,-0.3216921687,1.6232447624,0.4632739425,0.3479743302,0.2854761779,0.0905378759,0.0078849401,1.1418205500,-0.2064098269,0.1464061737,-0.1620241702,-1.1185684204,0.0551032908,0.0955945477,0.1914982051,-0.2445030063,1.0773905516,0.7771847248,-2.0026953220,-1.3879367113,1.8168145418,-1.3441421986,-0.1909300387,-0.2537579536,-0.4333573282,-0.5043718219,-1.1934229136,0.8883563876,1.3796744347,-0.8058362007,0.6302874088,-1.4562950134,-0.2413089424,-1.1239010096,-0.8434281945,-0.6111188531,-0.3214215040,1.7906646729,-0.2953863144,-1.0996087790,-0.0280012544,1.5195906162,0.4385769963,-0.0715610012,-1.2215670347,-1.1551032066,-0.5126031041,0.5079829693,-1.5987869501,0.6407077312,1.2264078856,-0.5521286726,0.5383154750,0.9565272927,-1.1502499580,0.4597047567,0.3260488808,-2.5554530621,0.0539155044,0.9961486459,-2.3894460201,-0.3041664660,-0.2683731318,-0.8905698657,-0.0944725424,0.5605733991,0.7430984974,-0.6170213819,1.4618774652,-0.4896700978,-1.6775000095,0.9276668429,-0.3350292444,-0.2878435254,0.2499760538,-0.8336799145,1.0695707798,-0.8759759665,0.8804914355,-0.4413791895,-1.4477114677,0.3207118511,-0.6660116315,-0.0039797751,0.2596048117,-1.3988531828,0.0217267051,-0.3165823221,1.4104597569,-0.8589660525,0.3823044598,0.5117325783,0.5799040198,-0.7965207100,-1.0794136524,-0.5460695624,-1.4399230480,0.9373409748,-0.6249065399,-0.7326609492,1.7352846861,-0.7039022446,-0.8619210720,0.2775456607,1.8297880888,-1.3504639864,0.1678970009,1.6588230133,-1.4726707935,0.2412999719,-0.0883939713,0.8553674817,-1.1602106094,-0.0671377331,0.2164906412,-1.9931809902,0.0053256475,-0.2441381961,1.7421977520,0.2616285682,0.6127197742,-0.6840193272,-0.3926095366,0.4958389103,-0.4157512188,-1.8020431995,0.5348650813,-0.4459702671,-1.0132100582,1.6183987856,1.8912308216,1.4364794493,0.4951191545,0.3030346632,0.6038584709,0.6475570798,-0.2035506368,0.4782030582,0.8421400785,1.6720960140,-0.8565639257,-0.4995645881,-0.0788188726,2.6190998554,0.0172765702,0.8030301332,1.9209679365,0.6042689681,-1.6229704618,-1.5398095846,1.2159051895,-0.0491375811,0.6701576114,-2.0786049366,0.2396868467,-0.1663447022,0.4873751402,1.6635489464,-0.7188113332,-2.3959128857,1.7327207327,-0.5349614620,-0.0728966668,-0.2948603034,-1.4774221182,0.4834442735,0.3681408465,0.9823635817,0.5640633106,-0.0505462214,0.3036163151,0.9760785103,-0.2052964270,0.0603897423,-0.0227735676,0.4560826123,-0.7479364872,0.4386453032,1.5767741203,1.2626835108,0.5652157664,1.5275896788,0.0146089382,-0.8305668831,-0.0492977872,-0.4252792895,1.2362649441,0.0874866694,0.4226440191,0.0723808184,-0.0925615653,-0.5521541238,-0.5364710689,-0.5070555806,0.1121965498,-1.1298216581,-0.7371627092,0.8932670355,-0.6637581587,0.4557986557,-0.6397003531,-0.3043342829,-1.1985019445,-0.5069193840,0.5818718076,0.9713091850,-0.5977748036,0.0146248564,-2.4917397499,-2.0943746567,1.2473956347,-1.9712914228,-1.3773270845,0.1807457060,1.2754870653,-0.6485044360,2.5466191769,-1.3412190676,0.1961534172,1.7364504337,0.1384211183,-0.2164301127,1.4340209961,-1.1674877405,2.2805016041,0.7271856070,-1.6405873299,-1.7613757849,1.2478111982,-0.7066447139,0.4562221169,1.0106225014,0.6289210916,-0.2545123994,0.8075569868,0.9933471084,-0.7091018558,2.4793047905,-0.1058447361,1.4626127481,-1.1512520313,2.2819995880,0.1980908364,-2.0391972065,0.4623443484,-0.4528153837,-0.3034771681,0.6253050566,-0.9960688353,0.1848763525,0.1992302835,1.3969924450,-2.1879806519,-3.5258898735,-0.3500127494,0.1608139724,0.5911024213,0.6979445219,-0.4094097912,0.1062802821,1.5368102789,-1.2191261053,-0.1408000141,-0.3725816011,-1.0421752930,-0.1061916351,-1.8223229647,0.6922587156,0.0466201380,2.0245492458,1.8404192924,-0.5316298604,1.8038771152,-0.9891858101,-0.7872034311,-0.9601790905,1.5571957827,-0.0051668053,1.6011846066,-0.1465292424,1.2160656452,0.4363673925,0.0321315080,0.7290571928,-0.5699969530,-0.1844813824,-0.0893535689,0.4522967935,1.4669539928,-0.2522238791,0.4661012590,1.4432981014,-2.7434496880,0.3867551684,-2.0132300854,1.6866211891,0.7507246137,1.0172561407,-0.2487859428,0.7585685849,0.5755932927,1.2352458239,0.8978250623,1.2966716290,-0.6571815610,1.4671807289,0.7853207588,0.3756480515,0.6194713712,0.3272837400,-0.3676315248,-0.0267670508,-0.2408681363,-0.7468521595,0.6240339279,2.1852478981,1.1214398146,2.0001266003,-1.5732886791,-0.0183822736,-0.8087029457,0.9497622252,-1.0744439363,0.9904448986,1.4737164974,0.1133142486,0.3727804124,-0.5018841624,0.6833029389,0.3201475739,0.2428314686,-0.8037180305,0.2282627523,-0.6574258208,1.8786723614,-0.7279502749,0.5236622691,0.3721244335,0.7680162191,0.7290078998,-1.6448494196,-1.3555030823,-0.9520250559,0.7258281708,-0.2495432496,-0.3343724608,-0.1035859659,-1.5604089499,-0.0533355586,1.2266353369,-1.9780186415,-1.2835073471,1.0977239609,-0.0809845626,-0.1254453063,1.2240229845,0.8162678480,1.1728838682,-0.4857140183,2.0652470589,-1.0620183945,0.4987939894,0.1875279099,-0.1605241150,0.2976987064,-1.7253868580,-1.2821964025,-0.5454786420,-0.6711188555,0.4872035384,1.3012408018,-0.0574941002,1.0852347612,0.2164134383,-0.8638213873,0.0029188166,-0.3997426331,0.8708361983,1.0494933128,1.2122185230,1.0808790922,0.0889089853,0.3659733832,0.6266746521,-0.7211550474,-0.0947615877,2.5941832066,-0.6472509503,-0.0892662406,-1.1688027382,-0.7755636573,-0.1888562292,0.4613487422,-0.1133504286,-1.0579370260,-0.3661361039,-0.9344208837,1.4105546474,0.3662054837,-0.1800113618,-0.8287143111,-0.4588594139,-0.5348659754,0.1927637607,-0.1688094139,-1.0985659361,1.7208666801,-0.9949175119,0.0071640117,0.2181097269,-0.5293247700,-1.2477115393,-0.4222748876,-0.8102868199,1.5723097324,0.7872313261,-1.7233170271,0.5807046890,0.1063605845,-0.5338957906,-2.1653342247,0.4575393498,-0.5575693846,-0.8172625303,-0.3406208754,0.0603416599,-1.5120033026,1.1769851446,-0.2431340963,-0.8860734105,0.2002744973,0.0624899231,-2.2787888050,-1.7242875099,-0.3660179377,-1.5788301229,-0.9279945493,-1.8265781403,-0.8975494504,0.2838334143,1.9209350348,-0.1576115489,-0.5317687988,-1.6259893179,0.0153308073,-0.9110952616,-0.1653829366,-0.4306715727,-0.6055718064,-0.8026126623,1.3090204000,-1.2156563997,-0.0519316867,-0.6713653803,-0.7353394628,1.4131215811,1.1170443296,-1.1881471872,0.2349975854,-0.2238769233,0.2461022288,0.1120637581,0.2336885929,-0.5243279338,-2.1437044144,-0.2431624234,-1.2464995384,0.4675020576,-0.7527608275,0.5624199510,1.3365873098,0.7289454341,1.7958503962,0.2928060591,0.7216563225,0.9394800067,-0.6092904806,0.5123190880,1.6707273722,1.7536890507,1.2125877142,0.8943855762,-0.8880759478,-1.3625150919,-0.2121257335,-0.6096383333,-0.1692983806,0.1635778695,-0.1416323781,0.3522885740,-1.0253274441,0.0980968177,-0.1966700852,0.7525386214,0.0875271410,-0.4656350613,-0.4846600294,1.0480329990,-2.1517102718,0.4131481051,0.2350990921,0.8666293025,-0.0862590522,-1.3615747690,0.3523576856,0.6853317618,-0.3136028051,0.1880191416,0.4099854231,0.5680887699,0.5689167380,1.6204892397,-0.1595118791,-0.1066793799,-1.1540112495,0.6110669971,-0.7147044539,-1.7258614302,0.7982810736,-0.7267000079,0.1675357521,-0.8346014619,1.2481591702,-0.9113322496,-1.5161044598,-0.1560480595,-0.3392308652,-0.1593530327,-0.1827998012,-0.5442073941,1.3976205587,1.0422940254,-0.2430956662,2.9464750290,-1.0710835457,-1.2913874388,0.4633493125,1.0320210457,-0.1943645924,0.4055425823,0.8175639510,-0.6497596502,1.2451591492,0.3004733324,1.1675512791,-0.6333433390,-0.9965176582,1.0963352919,1.3911732435,-0.2135262489,0.0029021860,0.0531421266,0.3033952117,0.5173051953,-0.0102700051,-0.0946862027,0.2938453853,1.3135150671,0.4863734245,-0.8989269137,-0.7194559574,-0.1590253711,0.4843160808,-1.1027262211,0.0849133283,0.5688287616,0.2679769695,0.4811837673,-0.7134509087,0.2008953393,-0.8335529566,-0.7201511860,0.5242791772,0.0110169752,0.4427189529,0.4736892581,-0.5382049680,1.6526933908,-0.2942489386,-0.4903966188,1.2739274502,1.1805559397,-0.1975703090,0.4837063253,-2.3744602203,0.2897094488,0.6084982157,-1.6204299927,1.3142671585,0.6344429851,-0.4190022051,-0.4888667166,0.6072349548,0.9508922696,-0.6400114894,1.4980759621,-2.1872255802,-0.9253449440,-1.6960446835,1.5540304184,1.1076310873,0.4102774858,0.3571720719,0.0244482420,1.1432708502,1.6378223896,0.1038910747,1.1907352209,-0.7008403540,-0.4064160585,1.1399818659,0.8482441902,-0.8278619051,1.2165918350,-0.1842192709,0.5383604765,0.0136463754,-1.6233984232,-0.3791120946,-0.8511069417,-1.2866246700,-1.8059158325,1.1002595425,-0.6931541562,-0.2090755552,0.0067911642,-1.0231842995,-1.4700142145,1.5429402590,0.5305857658,0.7299745679,0.4535187185,0.1681299061,1.6024149656,-0.9856672287,-1.6728117466,1.1804482937,1.7814029455,0.0313383043,0.1245605722,1.5340962410,0.1487563401,-1.3175044060,0.5722743273,-0.8558244705,1.0446487665,-0.9774014950,1.4014579058,-1.2876857519,1.9653085470,-0.2574622631,0.8741406202,0.1923532635,0.4771126211,0.5219726563,1.0568250418,0.1275015920,0.3534825146,-0.4791073799,0.0526588932,0.8323126435,0.7390776277,1.3197847605,0.3206358850,-0.8508493304,0.1079496369,0.0510789007,0.8233492374,-0.2772503793,-1.0964258909,-1.0618132353,0.0157843046,-0.9365561008,-0.7326688170,0.1077768654,-0.2073359340,-2.3172490597,1.3560752869,1.5103831291,-0.1958469301,1.0512095690,-0.0394407101,0.3858150244,-0.0032381886,0.9143221378,0.9421868324,1.6064001322,0.4654370844,-0.2540049553,1.4979096651,0.6909629703,0.4411643445,-1.0131149292,-0.1733857840,-1.7086960077,-0.3259657919,-2.0024752617,-0.6706923842,0.6668214202,-1.9155961275,-0.3144879341,-1.2456922531,-1.2796248198,-2.2090945244,0.7396605611,0.0296590049,0.9433910847,2.1231267452,-1.0864417553,-0.6030449271,0.3438302875,-0.6608654857,-1.0862615108,1.3887225389,-0.7988653183,1.3075400591,0.9552127123,0.3432019651,-0.2984606922,-0.1288973540,0.7399637103,0.0231899377,0.6450478435,-1.3013180494,-1.3024494648,-1.0995938778,-0.2466881722,-0.3775995970,0.4923250675,0.1694402844,0.9104561806,0.6665503383,-0.5168366432,-0.3762043715,-0.9129214287,-0.2788790166,-0.4600901902,-0.8824477792,0.5361903310,0.6113188267,1.3454030752,-0.8275414705,0.4882041514,0.8205421567,0.8798395395,-0.6477968693,2.4074959755,0.5788549781,-0.0437356532,-0.7579018474,0.9680426121,0.5040457845,1.1636078358,1.8771742582,0.6200423837,1.5920174122,-1.8497363329,-0.8436110020,0.3149974346,-0.4593172967,0.8473721743,0.0478686653,0.4404908121,0.3380852044,-1.1299993992,-0.1233110130,-0.9066924453,0.4301193058,-0.3466370702,-1.0565040112,0.2993363738,-2.2224280834,-1.1136168242,-0.5317560434,-1.9586926699,1.2876089811,0.5533798337,0.8821557760,1.1840175390,-0.1996572614,-1.7286516428,-1.8491935730,0.5178694725,1.7988730669,-0.2523056269,-0.4970327318,-1.4278050661,0.3399576545,0.7023395896,-0.7998167872,0.7301787734,0.5362419486,0.8577725291,-0.9817480445,-0.9755565524,0.3299261034,1.4980843067,0.7955431342,0.8185396194,0.0570088066,-0.1452435553,-0.4598515928,-0.4803588092,-0.6821164489,0.4632911086,-0.0423791558,1.8142098188,1.3901891708,-1.0697890520,-0.0289973561,-0.6405655146,0.0753127635,-0.5270310640,0.1859117001,-0.1663290560,0.5048159957,-1.7322213650,1.6413090229,-0.7120727897,-0.4916498661,0.8107194304,0.9926199913,-0.1052645668,-0.0880601779,0.6687352657,-1.4801020622,-0.7137554288,-0.3793790638,-0.1603921801,0.7068908215,1.2170107365,-0.4102213979,0.4785642028,0.3500928879,0.4325503111,-0.6816869974,0.2588504553,-2.3803224564,0.0774483383,-0.5226783156,-0.3486301601,0.1307638288,-0.4308033586,1.0323166847,0.7308865786,-1.0509271622,-0.3705799282,-1.4526411295,0.7582592368,-0.1112433150,0.2123344541,-0.1703404486,0.5684955716,1.2879304886,0.4955765605,0.9762223959,0.5969173312,1.0294094086,-0.4016108215,1.4354219437,-0.4525334239,0.9244177341,-1.8113485575,-1.8544753790,0.6716580987,-0.1637547463,-1.0912935734,1.0384893417,-2.0325262547,0.6750365496,0.1859313697,1.4355543852,0.9272583723,0.3481788635,-1.7764997482,0.6461026073,0.3343574703,-1.1932055950,-0.7114098072,-1.1107187271,0.2314597964,-0.3236814439,-0.2080765665,-1.4484943151,0.4726499617,1.2705886364,0.0462085642,-0.8196042776,-0.4398490787,-0.5813989043,0.0109049398,-0.3579022586,-0.3998372853,1.3548592329,-1.9293205738,-0.6319025159,-0.7778295875,-2.0569281578,-0.7499248981,0.9562718868,0.7526506782,0.3659623861,-2.2221159935,-0.5005191565,0.0293950923,0.0451079011,0.2878231704,1.1077967882,-2.5320174694,-2.6052191257,0.5428759456,-0.3326431513,-0.2977385223,-0.3886250556,0.3837181628,-3.0844507217,-0.0326572843,1.9840731621,-0.0990928710,-2.0813033581,0.9364513755,-1.5018221140,-0.7127351761,-0.4184252620,-1.6085178852,-0.5712712407,0.3170658648,1.3702354431,0.2474628687,1.6732935905,0.3019446135,-0.5106189251,-1.6296691895,0.0827088729,-0.2414676398,0.0117205493,-0.3977093697,-0.8551368713,0.5991954803,0.4162049294,1.5830416679,-0.1344192475,-0.8080347776,0.8270174265,-0.2177505791,0.7213084102,2.7542774677,-1.9037790298,-1.1765846014,0.9574951530,-2.2370584011,-0.1641188562,-1.5068861246,-0.5019809604,0.2476276606,-1.3522347212,1.5981073380,-0.0016236352,0.0727113858,-1.4785469770,-0.8532192111,1.3951283693,-1.0664182901,0.4442366064,-0.4066230357,0.2653382123,1.0576475859,-0.2093126327,0.0964964181,0.1187895015,-0.1235642135,0.1212674677,-0.6063463688,-1.7976351976,-0.2944546044,0.5414992571,0.5756024122,-0.4685805142,-0.7462616563,-0.3464683294,0.2230277807,0.9854597449,0.0767948404,-0.4874532223,-0.1219522431,0.8327487111,-0.1716076732,-0.3945173025,-1.1791951656,-0.4452678263,1.3629028797,-1.1066451073,0.3573346436,0.6323838830,-0.3071047366,1.6411852837,0.8643095493,-0.2245212346,1.4297059774,1.3671625853,0.2288126200,-2.0948269367,0.9121999145,0.1160216853,-0.0257257298,0.2509836555,-0.1600100994,-0.6034733057,-0.1384988427,-0.0839320645,-0.6945816278,1.9426094294,0.0452554338,0.3266722560,1.2575550079,1.1093206406,0.8573603034,-1.2389947176,-2.0883388519,2.1227445602,1.1516443491,0.2675343156,-0.3369225860,-0.4755612016,-1.1894302368,-0.2873914242,-0.1477799714,-0.1865244955,0.9614298344,0.1122136638,-0.1507401168,-0.7496002913,-0.8663163185,1.8104102612,0.1771599203,-0.7490789890,0.0366497710,2.0983855724,-1.0290652514,-0.5826900601,1.1658000946,1.2506613731,-0.1822900325,0.0264755636,-1.3294763565,0.1857622564,0.1860099584,0.6812687516,-0.0765349269,-0.5551304817,0.2183326185,1.0382562876,-0.7524948716,-1.2267206907,-0.5154917836,-0.9957588315,-0.8302957416,1.1273059845,-0.7931482196,0.0290784836,-1.8754261732,0.6611202955,0.7537636161,1.4504109621,0.4328519702,-0.1413241476,-0.3728679121,0.6295785308,-0.2826263309,0.1017487198,0.1004890427,-0.7599399686,1.1586389542,-0.4124349654,-0.9641899467,0.9970339537,0.6460083127,-0.4832358658,-0.6841650009,-0.0303084180,0.5566793084,1.2560545206,1.2719508410,-0.0263155978,0.0070461296,-0.8024127483,0.1088609323,-1.8889316320,1.7075667381,0.4763677418,0.8923625946,-0.1581884325,0.3295147121,-0.6005237103,-0.7768769860,-0.4446044564,2.0271074772,1.3566521406,0.0894624814,-2.5341632366,2.3792328835,-0.2505889535,-1.3664253950,-0.5644386411,-2.1931164265,1.1769444942,1.0361630917,1.8065854311,1.3853068352,0.8310387731,-0.6718800068,0.0839435682,0.5932793617,-0.3277965784,0.4227188528,-0.9974304438,0.1251470149,-0.4001867771,0.2866265476,-1.7253122330,0.4782764316,0.7806475163,-0.5707991719,0.4938725829,2.1363813877,-0.6386837363,-2.1948287487,1.2262840271,-0.0510553345,-1.0744620562,0.5451381803,-1.9778690338,0.9243052006,-0.2363083810,-0.8462770581,-0.4339647591,1.5218746662,-0.2496304214,-1.2015702724,0.4348722398,-0.7702450752,-0.3616005480,-0.9668240547,-0.7775117755,1.6584910154,1.2157908678,-0.0582093261,0.4874089956,-0.4351541996,-1.2981131077,0.4196226597,-1.1504046917,-1.3714263439,-1.1537238359,0.2113851160,0.9948299527,-0.0589868426,-0.2105388194,-0.1264684796,-1.0223534107,-0.1095140055,0.3037421107,-0.2303951383,-0.3564314842,-0.2918756604,0.3242609799,1.4333026409,1.8529117107,0.2137945294,1.9478644133,0.6609766483,0.2107582986,-0.0890568718,-1.0639896393,1.5600599051,-1.1038756371,-1.2550096512,0.1083938032,0.5406846404,-0.2521128654,0.4976765513,-1.5165120363,0.7626850009,0.2167731673,0.6663960218,0.4201067984,-0.5433947444,0.3073146641,0.7519953847,-0.5402916670,0.5032405257,-0.7342537045,-0.9444994330,-0.4982891083,1.3228744268,-0.1457812637,0.5063264370,0.5172562003,1.5089118481,1.8802934885,-1.1349375248,0.1486520320,-0.3159368038,-0.9561010003,-0.1483890116,-0.6002311110,0.8183563948,0.9246582985,-0.2708984911,-0.1344445795,-0.3975899816,0.2588158548,-0.8930866718,-1.6686511040,-0.5920096636,-0.0261793677,-1.0039272308,0.5324293375,-0.7660702467,-1.5267822742,-0.0449126177,-0.5578223467,0.4411966503,2.8361527920,-1.0847097635,0.5951077342,0.6513732076,0.5490559936,0.2389404327,-0.6742807031,0.2803015709,-0.5785861611,-0.4543779492,-0.6440399289,-0.9178314805,0.3433896899,-0.0781365111,-0.0110655092,1.0301516056,0.2924049199,0.9450477362,-0.7342799902,-0.4853533804,-0.0152373305,0.3297406137,-0.9591660500,0.6535556316,0.6672778726,0.5473683476,-0.0690325350,1.7266031504,-0.6833693385,-0.0771031976,1.3326834440,0.6728719473,0.8581472635,-0.7994928956,1.7931659222,-0.2488678694,-0.9435475469,-1.3550130129,-0.1657632738,1.8103445768,1.6421945095,-0.5307902694,0.3177648783,-0.8274542093,-1.5274112225,1.0199569464,-0.8939806819,-1.1168608665,1.3539602757,0.2608950734,-1.5025458336,-0.0350464173,1.6370078325,-0.2023550272,-0.9884869456,-0.7876907587,0.3030428588,-0.8543554544,-2.0759766102,0.8074741960,0.0092417505,-0.7486258149,0.9306184053,1.5228734016,1.0625956059,-1.0638818741,0.9000504017,0.9773253202,1.4914863110,-0.9541801214,-0.1188048348,0.0520063490,-0.7230827808,0.4520131350,-0.6191820502,-0.9545143247,0.1884564161,0.3061656952,0.4476604462,0.0418105461,-0.1309568137,0.4180471897,1.2613639832,-0.7609384656,0.3685899377,-0.2012770772,-0.4936135709,1.1598070860,0.3737017810,-0.1421750039,0.2495179474,-0.8559209704,-0.6964498758,-0.2374830842,-0.9256697297,-1.7266376019,0.2695619464,-1.4074134827,0.8068033457,0.6471933722,-0.5924095511,0.1117355973,0.2366000563,-1.4429482222,0.8711776733,1.5175033808,-0.2762643397,-1.2968262434,-1.2299476862,0.9790905714,-0.6197896004,0.2056121975,1.1886742115,0.6697474122,0.1087135598,1.2664176226,0.1910816878,-0.3005948663,0.6051598191,0.1337996721,2.2987043858,-0.2989132106,0.0533511490,1.4336971045,0.3602710962,-1.4897760153,1.9669363499,1.7474601269,0.7100765705,0.2949651182,-0.0514402352,-0.3578273058,0.3582149446,-1.3475846052,0.0255273320,-0.7661463022,0.6330846548,1.4332324266,0.9169499874,0.8839311600,0.7519271374,-0.1242360175,-0.3691127002,-0.8278617859,0.3434691429,1.4831691980,0.8366777301,1.0739248991,1.0072058439,-0.6175259948,-1.3308913708,1.1121007204,-0.8164995909,0.8835690618,-0.9938970208,0.9998544455,0.4616194069,-1.1370314360,0.9062680602,1.1257185936,-1.9194012880,0.2764996290,0.5737554431,1.4669361115,1.4267357588,1.0081113577,0.7518727183,0.9374237061,0.6022189856,0.9636828899,0.6104877591,1.2044204473,0.9677898288,-0.5647366643,1.0105677843,-0.3122237325,0.3334992528,-1.9033569098,-0.9630427361,0.2652240694,0.5199043751,-1.1540907621,0.7361152768,1.2738237381,0.1880766749,-2.2973453999,0.5291508436,0.0009351905,-0.6024293900,-0.2233156264,1.5331068039,-0.9884901643,1.5078092813,0.7398353219,2.3887550831,-0.3120129704,0.5433498025,0.0288962387,-0.2012146115,1.0563759804,0.0455531701,-0.1074009314,-0.9435821772,0.8474586010,2.1150949001,-0.5216084123,0.6223477125,-0.4835988879,0.0323945619,0.1332448572,-0.6117167473,1.2821873426,0.6829779744,1.7952840328,1.4735364914,-0.0281432271,0.3344296217,0.0498930812,-0.7253366709,-0.1882753372,0.7500153780,0.3084684014,-1.2596098185,0.4998308122,-0.2986431718,0.7846732736,-0.5215204358,0.4127131701,-1.4233584404,0.3591822088,0.8100859523,0.6673883200,-1.4757587910,-2.2996366024,-0.5354201198,-0.6260387301,0.0607966073,-0.9204249382,-0.3795864880,-0.0245653503,0.4642808735,-0.2157164365,0.8455864191,2.2098424435,-0.4032137394,1.2565199137,0.3011314571,-0.4515376091,-2.2521011829,0.2975798845,-0.6609811783,1.2324833870,-0.2599743605,0.6994997263,-0.9482492208,-0.0442115664,-0.1683008969,1.7778540850,1.5128661394,1.1165469885,-0.9578713179,0.5861684084,0.4876947403,-0.0258086044,0.8223834634,1.0231527090,1.5395146608,0.5583790541,-0.5228635669,0.8827819824,0.4835412502,0.4577231705,0.5126315951,-0.7414305806,-1.8140503168,-1.3544577360,0.8708856702,1.0170553923,1.0010755062,-0.6828664541,-0.0983215198,0.2329484820,-0.5799430013,-0.9481555223,1.3907268047,0.6413714886,0.3823638558,0.9870128632,-0.4725233614,-1.5783783197,-0.6470431089,-0.9037789106,0.0999176055,-0.6165252924,-0.5567381978,0.6479242444,0.5634599924,0.4559148848,-0.7018021941,0.5007602572,-0.7826791406,0.3516834974,-0.5544981360,0.9681010842,-0.6531418562,-0.0493310317,-0.3987984359,-0.0768239871,1.2028565407,0.9053220749,-1.5396063328,-1.5210251808,0.0095656775,0.4015446603,0.4952757657,-1.9695576429,-0.9904660583,0.0043475674,-0.3832959235,1.5924043655,0.1618719697,1.1238229275,-0.3456900418,0.7589526772,-0.2558067739,-0.1103068292,0.3348076940,-0.2165825069,-1.7158200741,-2.2370626926,0.7226798534,0.1446095556,-0.3551731110,0.7914757133,-1.0397866964,0.3701458871,1.5328626633,0.1711807400,0.0900413617,-0.1533249617,0.7270753384,0.1712650359,1.2431062460,0.2759212554,-1.4751939774,0.1763630956,3.6361017227,-1.5242985487,-0.0279763695,-0.9603900313,1.1799722910,0.2726994753,-0.2330887020,-0.6826753616,1.0471214056,1.1989165545,-0.4046612084,-0.7465475798,0.8356605172,-1.0643728971,-0.3423130512,1.3552594185,0.0537857786,-1.5534422398,-0.5955978036,1.1433280706,0.2265868187,-0.2054847330,1.4488072395,-0.9428060055,0.2496462762,-0.5333206058,0.9197281003,0.0167320166,-0.5308976173,-0.3981518447,0.1968156695,1.2565236092,-0.1500016153,1.7518627644,-0.5710981488,-0.7607555389,-0.5640133619,-2.1015295982,0.2339061052,0.3560619652,-0.2133811563,1.6464656591,0.8782684207,0.6951352954,-0.8930280805,-0.5173587203,-1.0700474977,-0.6147041917,-2.5534784794,0.4594208002,-2.9251899719,-0.6844087839,-0.1010654792,-0.9624158740,-1.0140864849,-0.0757387206,1.1583821774,-0.5384712815,-0.9480490088,0.9694117904,-1.3669112921,-1.2707827091,0.7595877051,0.9194093347,-0.9817193747,-0.7923594713,-0.9515684247,0.1903454214,-0.6589611173,0.2844074667,-0.0866462439,1.4720683098,-0.1156150550,-3.1793930531,1.5431214571,-0.6267422438,-0.5408167839,-1.4073745012,0.0020372916,-0.9605144858,0.0653555542,-0.0072504482,-0.2048006058,-0.8758507967,0.6794900894,-0.5280171633,-0.2964494228,-0.6805481315,0.7795145512,1.9110471010,-1.3809238672,-0.0489975736,1.4007698298,0.4083929360,0.2260774076,-0.6497412920,-1.0933283567,-0.2311290503,1.1378812790,-0.7990297079,-0.7805021405,2.1594064236,0.0872589722,-0.3067907393,-0.5868695974,0.4651990831,0.0277806502,0.3595694602,-1.7833522558,-0.9235187769,-0.1305120736,1.2421206236,0.7602189779,1.3953794241,0.3049729168,-0.5557566881,-1.0600878000,-1.5434368849,-0.4848669171,0.6762301326,0.3975794613,1.4395723343,0.6811670661,-1.5078858137,-0.2627333403,0.4361654222,-0.0008911950,1.0187122822,-1.0375159979,-1.6047658920,-0.0847408697,-1.3486804962,-1.8990767002,-0.7349280119,-0.1065333709,0.6665663719,0.5214542150,-0.0061568609,0.9659379721,0.7524757981,-0.0891807601,0.1273224354,0.8268703222,-0.1176565886,-0.7092362046,0.2952494621,-0.2299559861,-1.0425001383,1.2988185883,0.5426243544,0.4739787579,0.8060304523,1.5848567486,-0.0154908923,-1.9596747160,0.0608664788,-0.8224123120,0.2057334930,-0.3345183134,-0.7199540734,-1.0148650408,1.2570089102,1.7332231998,2.7068395615,0.5335254669,-2.0145659447,1.3850419521,-0.8592329025,0.6600543261,-0.4218591750,-0.0107094571,-0.6457693577,0.9560267329,0.5790085793,0.0617983118,0.3226754069,1.0685539246,-1.2620589733,-0.2347259670,-0.2421554327,-1.3379868269,0.9540162086,0.5375425816,-0.1855080128,-0.8155971169,1.2428810596,-1.7945463657,-0.0921459422,-1.4434609413,0.1425899863,0.0288435649,-0.7485082150,-1.0032165051,0.7188972831,-0.9643496871,1.1487607956,0.7042000294,1.0104765892,-1.3018821478,1.7104345560,-0.2635222673,-1.3582605124,-1.5040088892,-1.0269665718,-0.6213265061,0.1832721084,-0.3864678442,0.4071185589,0.4705953002,-0.4236857295,-0.1801551133,0.7529713511,0.8858818412,0.2697959542,1.4118680954,2.3722064495,-0.9191628695,-0.9307866096,0.3029454648,0.9904204607,1.2289518118,0.4089305103,-0.8350077271,0.5419706106,-0.5536469817,0.1028060094,0.3641077876,-2.9135649204,-1.1976279020,1.7268692255,1.0548107624,0.9957117438,-1.4481039047,-2.2000696659,0.4746692479,-0.3013611734,2.5931897163,0.1785014421,-0.9042234421,0.7220194340,0.5479753017,0.8089565635,0.2825019360,1.6301807165,-0.9289301038,0.7758326530,1.7873525620,-1.7252171040,-2.6020746231,0.5115439296,3.2497107983,-0.5192397833,-1.0423642397,0.0324750915,0.4287697673,0.8982563019,1.3349349499,0.3121462464,-0.3937326074,2.0630812645,-1.4304995537,-1.3159050941,-0.0241598841,-0.7293787599,-0.3655036390,1.4027618170,0.1256354004,-0.0866579339,1.6698479652,0.6147372127,2.1514334679,-0.0860073492,0.5820814371,-1.2603700161,0.0365599617,0.1094137803,-1.0534101725,0.3607339859,-0.9958238006,-1.4315663576,0.7793776989,0.1461087465,-0.1628145576,0.3107595444,1.3687645197,0.5772598982,-0.4336755574,1.1175009012,-0.2714384198,-0.1034518629,-0.2754325569,0.9069437385,-0.0283357389,-0.1800245643,-0.1651595682,-0.5861871243,-0.4601516128,-0.0606546029,1.5763812065,-1.0784891844,0.9564955831,0.9455194473,0.7763608098,0.4902954996,-0.2564931214,-1.0015263557,0.3603806794,-0.7381950021,0.2104441971,-0.2726085186,-1.4666761160,-2.0567760468,1.1105402708,0.3748869598,-0.8810894489,-0.0609646738,-1.1932916641,0.0129567189,0.5431383252,0.6572669744,-0.6381964087,0.6827172041,0.2055616975,-0.4754789472,2.6849081516,0.9908787012,0.4223089516,-0.9532756209,-1.4316188097,0.4283581078,-1.3681161404,-0.0958754867,0.5441727042,1.0810705423,-0.0415074416,2.5692317486,-0.3227604330,0.4241096675,1.4338536263,-0.4114264250,0.0011840090,0.3396936655,-0.7032704353,0.0369640626,1.9964704514,-1.0196714401,0.2410306334,-0.6645501256,-1.9832742214,2.1286649704,-0.2816694379,0.6200950742,-2.5297253132,0.2783054113,-2.2589633465,1.5027683973,-0.6791571379,0.7946748734,0.5594283938,-0.4154709876,0.0868373662,-1.1731896400,-1.0965510607,0.4667754173,0.3479546905,0.5917227268,-0.1208579317,-1.9895873070,0.0767334402,0.0827785879,-1.5488442183,0.4962759912,0.6963671446,-0.6112600565,-1.9577354193,0.9674578309,0.7537819743,2.4563322067,-0.0252350532,-1.5132838488,1.2217682600,-0.7690975666,-0.2130514085,-1.2223173380,-0.5371199846,-1.0274674892,1.1752959490,0.0587048046,-1.2375228405,0.4799143374,-0.8488432169,-0.6043387055,1.1303751469,-0.3233990967,-0.6648087502,0.9539896250,-0.3432818949,-0.5456913710,1.2928091288,0.6582537293,-0.3367332220,0.1220468283,-1.5532795191,-1.7195379734,-1.0341162682,0.2998998463,0.8046797514,0.4961921871,-0.6684690118,-1.5009387732,1.2318353653,0.3643293083,0.4558056891,-0.7469726801,-0.1064849347,-1.1267255545,0.2651161849,-0.3827407956,-0.8086588979,0.0461993329,1.4123934507,0.1515855044,1.5572073460,1.3240995407,-1.5372346640,-0.2648573220,-1.5860991478,0.0319794863,-0.9175467491,-0.8246659040,-0.2483655810,0.1255396158,-0.5857534409,-1.9942765236,0.0182692204,-1.7602024078,0.3323732615,-1.4235423803,-0.0769748762,-0.6448416114,1.1782761812,-0.8038555384,0.5822150707,-1.4353785515,0.1170133278,-0.8189358115,-1.2466543913,0.6469664574,0.9749919772,1.2244031429,-0.2720718384,-0.0915584937,-0.6139442921,2.7357959747,0.6321662068,-0.4468442202,0.0670683905,-0.0152648930,1.4001054764,0.8164184093,0.2930732667,-0.6081119776,-0.9192171693,-0.1245781928,2.3893449306,-2.4778037071,0.5976509452,-1.4283977747,0.4154342115,-0.4454664290,0.3893599212,0.2045798749,0.1197161973,-0.0726990327,-0.0892046988,0.2428955585,0.6287866831,-0.8733956814,0.1548168063,-0.8002090454,-1.3946036100,0.5990428925,-1.1735966206,2.5494780540,-0.7590735555,0.1940673888,-0.4431787431,-1.4156470299,-1.9468938112,0.3451087773,0.5958864689,1.1357485056,0.8258775473,-0.5660755038,1.9902119637,1.3801629543,-1.7834206820,0.8641321659,-2.3902966976,0.6164762378,-1.0545002222,0.6365401149,-0.6782473922,0.5563191175,0.7363837957,-1.8891561031,0.0214900393,-0.7824299335,-0.2060978413,0.3763463199,1.4707410336,0.4039954841,0.6742861867,-0.6028607488,1.2719975710,-0.7390785813,-2.4224550724,-1.2123428583,2.3222174644,-0.4605011046,3.1352612972,0.2794305980,-0.5493283272,1.0512810946,0.1013304591,0.3027843535,0.7218084931,0.2959215641,0.6120178699,-2.3468084335,-1.1663336754,-0.8147548437,-0.4591985345,1.3389530182,-0.0083134025,0.0621182621,1.2398926020,-1.1599477530,0.0201061536,1.5943176746,-1.4953566790,0.0830490291,0.2470071912,-1.9120575190,-0.1153577715,-0.4227010310,0.8099350333,0.0726526678,0.8789698482,0.6540535688,-0.6828325987,-0.4248169661,0.3941554427,-0.6652766466,0.0736672878,0.4986302853,1.2773303986,-0.2276820540,-1.7044115067,-0.9628150463,2.3503878117,-0.9085405469,-0.1369735599,0.4999858141,-2.4511468410,-0.1574627161,-1.2132976055,0.7054603696,-0.8242201209,0.9384362698,0.0222000740,0.5847182274,1.7617032528,-0.7561365366,-0.0969338343,2.0506048203,-0.6521903872,-0.5247980952,-0.8815501928,-0.2154593319,-1.5231957436,0.1173115671,0.8983911276,-1.5951839685,-1.7393609285,-0.4271378517,0.2468763441,-0.6876968741,-0.8700183034,-0.3693754673,-1.0298929214,0.4024917483,-0.4774999917,-0.8142039776,1.4894051552,0.6848152876,-0.6682641506,0.5156447887,-0.0836239308,-0.1595827490,-0.9284272194,1.6347107887,-0.5399640799,1.0173338652,0.2623037398,-0.4373755455,1.2972157001,0.9749194384,0.9706473351,0.6446200609,0.8166325092,1.1084922552,-0.1151099503,-0.0970648900,-1.6904464960,1.3225225210,-0.7746454477,-2.2212016582,1.1361017227,-1.3346679211,0.4757602215,-0.9677015543,-0.4630626142,0.0695191398,1.3389387131,-0.1383368075,-1.3319382668,0.6405091286,1.2340289354,-0.6869156957,-0.4758132398,-1.9471237659,-1.2886620760,1.2084196806,-0.5310587883,-1.3227537870,-0.7771701813,-0.0368499942,0.4158807993,0.3814026713,1.0844006538,3.4120693207,1.7345339060,-0.0976254642,-0.2757738233,-0.8358352780,0.1355589926,0.7318641543,-0.3644649684,0.3209478557,0.2786023319,0.7931556106,-0.5511992574,-0.4364145994,-1.2345582247,0.3531896770,-0.1258494258,1.9726265669,1.5069609880,1.0744990110,0.7512360215,0.5726920962,0.0459811017,0.6249359250,1.7143579721,0.9048161507,-0.1954852939,0.0158866066,-0.4643318653,-1.1683137417,-2.2276227474,0.8133713007,-0.5477312207,1.1287671328,0.4268198907,-0.4344830215,0.5964285731,-0.5707772374,0.1042475775,-0.2392384261,-0.3934238553,2.3036134243,-0.9504826069,-0.6469936371,-1.0541242361,0.0337269567,-0.7810605168,0.9689751267,1.9031298161,0.2525197864,0.1838586181,-0.2395608574,-0.5237963200,-1.1532931328,0.4638881385,0.4851041436,2.1061365604,-1.5883505344,0.6773467660,0.9099257588,0.4675730467,-0.5751948953,0.8763380051,0.7442619205,0.0406341441,-2.2689523697,0.7088384032,0.2085940242,-1.6460503340,-1.2184493542,-0.8154140115,-0.2806397378,0.2383890152,0.7780022025,0.7270069718,-1.3557515144,1.2708170414,-0.1392763555,-0.3877072334,-1.4174968004,0.3400408626,-0.8829170465,-1.9422985315,1.4105211496,0.4198240936,0.3245728314,0.0032399215,-0.4103808403,-0.1612507552,-0.3893881440,0.5924805999,0.0768460557,0.2591560483,-0.7614800334,-0.4818507731,0.3876158595,-1.8072429895,0.6448305845,-0.4991023242,0.2990922332,0.7611392140,0.2680123746,1.9994397163,0.3640748560,-0.2594336271,-1.1131106615,-0.8219708204,1.1891075373,-0.1939040869,-1.7173801661,0.2022092044,-0.5829202533,0.5355664492,-1.4946354628,0.9865855575,-0.8716754317,-0.9377834797,0.3892740905,0.6675186753,2.0363080502,0.9215611815,-2.0991868973,-1.0165593624,2.0159192085,0.4246093333,-1.3649692535,0.8177539110,0.1407611221,-0.7992921472,-0.2672897279,0.7641906142,-0.3375808597,0.2430761158,-0.2130232900,-0.4740942121,1.6659946442,1.5688807964,0.1841378659,0.4639534056,-0.5424900055,1.4749709368,-1.3607293367,-0.6117712259,-1.2864717245,0.7173013687,-0.8206724524,-0.8166086674,-1.1200137138,-0.1569412053,0.4703750908,-0.7065168619,0.4275971949,-0.3475115299,-0.7177425623,1.2331171036,0.1298312247,-0.9110089540,-0.1160564497,-0.1007026881,0.1473488063,-0.0265515819,-0.1134301201,-0.6335337758,1.0367230177,1.2019270658,0.2903762460,0.8871808648,-1.3211030960,-1.2637345791,-0.3478819430,2.6312584877,-0.0779268518,-0.0033409558,-0.6762089133,-0.2439787388,0.8177816868,1.4604249001,-1.5679810047,-0.1339834630,-0.1631641537,1.5747507811,0.1084988192,1.4038569927,-1.6337524652,0.0177575890,1.0167950392,-1.6949776411,0.0757225081,1.4419057369,0.2556048930,-0.6593601108,-0.2549015582,-0.9439916611,-1.8636031151,0.3080304861,0.4328792691,-0.7933393717,-0.2392593324,0.4455813468,-1.1091521978,0.6833079457,-0.1153917611,-1.4299768209,-2.4306547642,-0.4589000940,-0.9767031670,-1.1525596380,-1.1114211082,-0.6227270365,-0.3940295875,-1.1870974302,0.3540764153,0.8213087320,0.5123792291,-0.0097675789,0.7527971864,0.4728479683,1.2856576443,-1.5182529688,0.7346980572,-0.1847112030,-0.7216877937,1.3291749954,1.1263566017,-0.7484042645,-0.2636847794,0.0217362791,-0.9375768900,-0.7247433066,-0.0415024720,0.0492623039,-0.7459357977,1.1220898628,-0.5154392719,-0.4776915610,1.5804840326,0.8040207028,2.2452106476,1.7335001230,-2.4033691883,-0.2907517850,1.0620511770,0.9767885208,0.2632334530,0.5237601995,-0.5357385278,0.4868034720,-2.4270212650,1.2570142746,0.2010706663,0.6235077977,0.7071534991,-1.2176045179,-0.5152527690,0.3981330395,0.2556486428,-0.5797071457,-0.6267167330,-0.9684706330,0.2104416192,-0.8124510050,0.7867467999,0.5026560426,-0.0581949949,1.6213607788,-0.0828385055,1.9328351021,1.7954280376,0.2441668212,0.4763677716,-2.6320970058,-0.0609419681,0.4138411880,-2.8224081993,0.8544120193,0.3406496048,-1.3216235638,-0.1166282445,0.0615011118,-0.9227725863,-0.7776309252,0.6261429191,0.6446788907,-0.2852533460,0.4866887033,-1.7207942009,0.3032245636,-0.7486038804,0.2438063323,-0.2671179175,-0.3899340332,0.0800387189,1.1771892309,-2.8977830410,0.5417762399,0.5842677355,0.5015832186,-0.4940728843,-1.4268690348,1.7689621449,1.7392749786,-0.3849787414,-0.9646254182,-0.1681044698,0.1822709441,0.6294948459,-0.4607347548,-0.4217625558,0.4491379857,-1.9762825966,-0.8236123919,-0.6104609966,-0.3675303161,-0.7454993129,2.4073290825,1.1063375473,2.4108457565,0.2904265821,-0.0319271833,-0.1898043603,-1.1604915857,1.1043064594,-0.4222970903,0.1301062554,0.3959206343,-0.1617540270,1.0322108269,-1.7450871468,0.2481280863,0.5010092854,-1.0896248817,1.2918280363,0.1254145205,-0.9438206553,0.5197620988,0.8137003779,-0.5376303196,0.2467346787,-0.6972445846,0.9036880732,-1.7012495995,0.1490175277,1.6514542103,-0.3002925217,0.6282120943,-0.0789799169,-0.5649306178,1.1362684965,-0.1409714818,0.7433593869,-0.4661725760,1.0111490488,-0.1314715445,-0.2794724107,-0.5579557419,-3.0807359219,0.6628274322,-0.4908138514,0.2899478078,-0.0956695154,0.4372552633,-1.0438014269,-0.1414678246,0.0443393439,-0.0560218208,-0.4559345841,-1.9249411821,-2.0573368073,-0.0334194154,0.0930603072,1.3541816473,-0.0132205859,0.1044306085,0.2731702626,-1.0667283535,-1.3606183529,-0.3784544766,1.4905642271,1.3429602385,-0.7809277177,-0.3124582767,0.1603041440,0.7163369656,-0.5278331637,-0.8617659211,0.0707306340,0.5078257918,0.5343469381,2.7920517921,1.1080427170,0.6272335052,-0.2741323411,0.5719816685,0.7550273538,0.8943145871,0.1229175404,-0.6765108109,1.5254110098,2.3936822414,0.8236930370,-0.1658976078,-0.5570540428,0.1447302103,-0.0118487366,0.2371482849,0.2607527077,-0.3373178542,0.0334553272,0.4224862456,2.3579299450,-0.2408792973,-1.9752658606,-1.0364269018,3.8317902088,-0.9200903773,-0.6679349542,-1.6793940067,1.1850756407,0.0062380657,0.9284568429,-0.1546033323,-0.8065575957,-0.3873867691,0.6424305439,0.2068197876,0.1537742168,-2.0683746338,-1.7794313431,-0.9078343511,0.3276721835,0.0317510068,-0.9162718654,-0.9382501841,0.8591877818,0.0205972660,0.3160986602,0.4791103005,2.3585975170,1.2266488075,0.0675020814,-0.0706233829,0.1332499087,-1.2125068903,0.9365451932,0.1137873232,0.2121182531,0.9187198281,-0.9210603833,-1.3618185520,-0.8186307549,0.2531672716,1.0069762468,0.8433437347,1.1979171038,-0.5553349257,1.0772843361,0.3243967593,1.4009695053,-0.7212144732,0.2164977342,0.1635417789,-0.4878661633,0.2016631365,0.6704857945,0.1343654990,0.9387943149,0.0494832285,-0.1038764939,1.4206699133,0.1582160592,-1.6772825718,2.0133848190,0.1406247765,-0.4359038472,1.9959181547,0.0242856946,-0.9826890230,-0.8497070670,0.9738262892,-0.9124195576,1.5310759544,1.1907900572,0.8818747997,-0.2512267828,-0.4001435935,-1.6142051220,0.7161724567,0.1099669784,-0.7687640786,0.1460857093,-1.2593784332,-1.1577454805,-0.8739498258,-0.1982318014,-0.4073867500,-1.3021171093,-0.1136029884,-1.5907045603,-1.1428781748,0.1213455573,0.3092034757,0.0334026329,-2.4200618267,3.3238034248,1.1879281998,1.9430119991,0.2992740571,1.6709127426,-0.3273898959,1.4901436567,-0.6158698797,0.9194712043,-1.7540516853,0.4838142991,1.2830245495,0.5275840163,0.8925089836,-0.4407205284,-0.0098689431,1.5410522223,0.2787226439,0.6298201084,-1.2696967125,-0.1690566242,-1.3529920578,0.4250549376,1.9450334311,0.9914284945,-1.6382533312,-0.4501300156,-0.0474638417,-1.6697709560,1.3145624399,-0.8170112371,-0.8111792803,-1.0784217119,-0.3456541896,0.4999735057,-0.4648705721,-0.7333679199,0.0848675817,-1.6081210375,0.0173648894,-0.0103555061,0.8468238115,-1.1412696838,0.3661522269,-0.4450252354,0.8290936947,1.1968002319,0.5475606918,0.0861864313,0.5601829886,-1.5211524963,-0.5370119214,-0.5964001417,-0.5213727951,1.0056358576,0.3153733909,-0.8991996646,-0.5396741033,0.9581548572,-0.5757839084,-1.0513538122,1.1611233950,1.8634634018,0.4477458298,-0.2449746579,1.5770003796,-0.2315210402,-0.3703002334,0.0056428425,-0.4994624555,0.0295562055,-0.0041788672,0.8292986751,-0.0069422261,0.4954382181,-0.7247942090,1.1682143211,0.0745441839,0.0941772833,-0.7176083922,0.8280134201,-1.6582189798,0.6430417299,0.1367926598,0.7049418092,0.0571377203,1.1631231308,0.6296694875,-0.0647290796,-1.2796778679,-0.5895133018,0.8610818982,0.3743764460,-0.8071950078,1.3061199188,-0.8803336620,-0.0079116700,-0.5633738637,0.3912031353,-0.1816237271,-0.1595174670,-0.8321972489,0.2964517474,0.9229819775,1.4701541662,0.6736425757,0.5532526374,-0.1107472777,1.7293556929,-0.5153669119,-0.6763880253,0.2341462821,-0.5053901076,-0.1485505253,1.2039222717,0.4330215752,1.6672991514,0.3798584044,0.5994235277,-0.3695307672,0.6090422869,-1.8857115507,1.0357469320,-0.6409605742,0.5081863403,0.8336287737,0.2464233786,0.1892288029,-1.5773829222,0.7635652423,1.6710473299,-0.3723566532,-0.0935106426,0.4004655480,1.6516311169,-0.0239151251,1.3460192680,-0.0556113571,0.7014779449,-1.1409986019,-1.9849413633,0.7863185406,0.1040583923,-0.5113148689,-0.6147990823,-0.1334390640,-0.8577879071,-1.6896690130,0.0303357765,1.0349303484,-1.3887677193,1.4465106726,1.4462199211,0.9695534110,-0.9796079397,1.0599244833,-0.3817900717,0.5725802779,-1.0808739662,0.6993675828,0.0584711172,-0.5152519345,-0.3773689270,-0.9231536388,-0.0607250929,2.4555163383,-2.2077910900,1.5051277876,-1.2260414362,-0.2329563051,-1.2366898060,-0.3229627013,-1.4195483923,-0.1831594706,1.7906260490,0.2295542806,0.2179629952,0.3471575677,0.2313944250,-0.0609209612,-0.1078507155,0.4665036798,1.1243994236,0.9174999595,0.2093791664,1.6390047073,-1.3195793629,-0.1680346727,-0.5173400640,0.6296047568,1.0929300785,-1.5066785812,1.2682543993,-0.3669987917,-0.0628513321,-0.3588504791,-0.8302126527,0.2542398572,-0.3541894555,0.8507209420,-0.6196182966,-1.1007553339,0.5014449358,-0.8606661558,0.4498639703,0.2191863060,-1.4525839090,-0.1573316753,-0.3670399189,1.1949836016,1.2781003714,-0.3769445121,-0.8998956680,-0.1330458224,-2.1117086411,-0.3949528337,1.4143472910,0.0138987098,2.0456752777,-1.7744398117,-0.0091569005,-2.6830213070,-0.2830215991,0.5834649801,2.3459873199,-0.9336617589,-1.0544435978,0.9978377223,0.8136739731,0.8705741763,-0.4490517080,-0.4460271597,-0.8419141173,0.2584621310,0.2546221018,0.0829493180,0.1972437054,-2.2637302876,-0.3299877644,-1.9285436869,1.0270245075,-1.5507107973,-0.4767905176,0.3876853883,0.9809426665,-0.6491833925,0.2031453401,0.8613374829,0.9279358983,0.3166069984,0.3596234322,0.0556599312,2.6604681015,-0.3559695184,-0.8140570521,1.2609890699,0.7009537816,1.6023476124,-1.6866204739,-0.3539562225,0.2053398639,-0.1173354909,0.0861274227,-3.4895308018,-0.4967344999,-0.0145240240,0.3744366169,-0.9175367355,-1.4568159580,0.7877227068,0.6968756914,-1.1660602093,1.4751977921,-0.1938352287,-0.0264743380,-1.3262991905,0.0237702597,-2.4104363918,-0.6477180719,0.5059946775,0.3510814011,0.3875126243,1.2187185287,-0.2408093661,0.6088964343,-0.3309341669,1.8326859474,0.2369977683,-0.3282163143,-0.2274724394,-0.2073322684,-1.0838879347,-2.1840865612,-0.4663523138,2.0218403339,0.9449817538,-0.9978976846,1.3662493229,1.7149190903,-0.2701505125,-0.8451486230,-1.6304798126,-0.7960706353,1.2277041674,-1.7852749825,1.2480875254,-0.3981883824,-0.7367050648,-0.4135238230,0.5079085231,0.0900633857,-1.2990952730,-0.6961169243,0.3780362606,0.9619675279,2.1818091869,0.4237046242,0.6840161681,0.6984956861,-0.2514249980,-1.7293785810,0.3667742610,1.1325265169,0.7683765888,-1.1529784203,0.4323818088,2.3151834011,0.3081058562,-0.6248998046,0.5047844052,0.6498021483,1.7978770733,0.3899771869,-0.4997722208,-0.1578063518,-1.9672470093,-0.3175988495,-0.0856336206,-0.9187674522,0.9462944865,-0.1890290082,0.0526048094,0.7671905756,0.0052128769,0.6099808812,0.5507966280,-1.3356704712,1.1185127497,-1.0913438797,1.2091479301,0.7399811745,0.1125142574,-2.0963685513,-0.2536096871,-1.4916297197,0.6988286972,1.0503125191,-0.7035870552,-0.4649752080,0.3794374168,0.7661656141,-0.5972264409,-1.0623397827,-0.0284309927,1.3018770218,-0.9428182840,-0.2252209038,-0.3813332319,-0.9502642751,0.0767621696,0.7689592242,-0.0794237703,0.2420342267,1.4336521626,1.5250978470,-1.3550601006,0.5420228243,0.7595084310,0.1850525141,0.9257733226,0.2702014446,1.1696821451,0.8106309175,-1.0838518143,0.4734386802,-0.4565702081,1.3057682514,1.4480742216,-0.5279594064,0.6467399597,1.6548110247,-0.0588355176,-1.4721015692,-0.9004341364,0.0964303613,-0.6494836211,-1.2516726255,-1.5430279970,1.6699434519,-0.2119133621,-0.3817618191,0.3938360512,2.3915538788,-1.0785287619,1.3833017349,-0.5712346435,0.0911998898,1.0019682646,0.4382897615,1.1474125385,1.1693954468,0.1031880304,0.7955002785,1.3405262232,0.0209042039,1.6260020733,0.3945917785,-0.3832558692,0.7924461961,0.0312300827,0.7102786899,-1.7634069920,-1.3943989277,-0.7769746184,-2.2571027279,-1.1994607449,1.0450494289,0.3268254697,-0.6890351772,-2.0280230045,-0.4204472303,0.4531336129,0.1239523813,-1.0549724102,-0.4190306664,1.0953723192,0.2018714398,0.7987915874,-0.2929423451,-0.1676543951,0.5970343351,-1.2773684263,1.2236326933,0.9840433598,0.1225740537,1.1968276501,-0.3415886462,-0.6405214667,0.7638618350,1.5436466932,-1.0006358624,0.1138499379,-1.0741703510,-1.5411993265,-0.7750322819,-0.9824083447,1.0209515095,0.7557222247,1.0524106026,0.2535609007,-0.3112972081,1.7932996750,-1.2139261961,2.0946898460,-0.0090470267,0.6447563171,-0.7594442964,-0.1354953796,0.0660691410,-1.0660305023,0.8187485933,-0.3587822914,0.4471886158,0.8411183357,0.5693242550,-1.4816662073,-0.7689180970,-0.7788417339,-0.9212349057,0.7576090693,-1.2389307022,0.6051481366,-1.1756383181,-1.2799351215,-1.8131713867,-0.0544976145,-1.5947587490,0.1935119927,-0.3740875423,-1.1885846853,-0.0792386606,1.1125651598,0.3793795705,0.5841192603,0.0571746901,-0.1136863083,-0.5652914047,0.7779823542,0.4327304661,-1.0822675228,1.0263322592,-0.4865728915,0.0487550497,-0.2343792617,-0.2356239855,0.0258828122,-1.5499720573,0.2839837670,0.0145347295,-0.1443930119,1.1493870020,-0.6262537241,-1.7196328640,-1.7135055065,0.4295227230,-1.3662779331,-0.4895913601,0.2493050396,-3.3102571964,0.4204231799,-1.0910575390,-0.9758739471,-0.1436772048,-2.1989107132,0.3001672029,-1.7423200607,-0.5652357936,1.4203227758,0.3454657495,-0.8482355475,-1.0011060238,0.8571538925,-0.4992506206,0.7553210258,-0.8703880310,0.7454122305,1.4743127823,-0.3983528912,0.8992680907,-0.8724070191,-0.4594956636,-0.2891397178,1.6464035511,-0.5800548196,0.1192378998,0.3251797855,1.5719088316,0.2433685362,1.6238752604,0.9168971181,-1.7127541304,0.4310311675,-0.2766275108,1.5945236683,0.7060499787,-0.2566100061,1.0110602379,1.4094588757,0.9080002904,2.1751139164,1.6054965258,0.9616665244,2.2810950279,0.4121274054,-0.0153397154,-0.3080755472,1.4366900921,-0.4038511515,0.7201999426,-0.7327430844,2.0949237347,0.0393173620,2.2166905403,1.2483799458,0.4711368680,-0.4010816813,0.7753511071,-0.5172150135,0.3040603995,-0.2500374317,-1.0669492483,-0.0891368464,0.0055941949,-0.9773228765,1.1023194790,0.4938498437,-0.5543298721,0.0906332210,0.0505249016,0.5267651677,-0.5476112962,-1.3049540520,0.8578358293,-2.0298936367,-0.1674510688,-1.0671063662,-1.4121545553,-0.9709029794,-0.3150966167,1.9244461060,0.4939165413,-0.0465229526,0.4197863042,-0.4554887116,-0.8888947368,-0.4829266965,-1.9815404415,-0.1060535312,-1.4770417213,0.6611261964,-0.8000780344,-0.0008512373,0.0904324129,-2.3193302155,1.2738482952,0.8960350156,0.3338158429,-0.8541143537,0.3179859519,-0.2948468626,2.4262568951,-0.6027595401,-0.1137509346,0.3913904130,-1.4957355261,0.4632006288,-1.5061677694,-0.0406272337,1.3672878742,0.9088773727,0.0280201621,-0.3759260476,-0.5266292095,-1.6783390045,0.7885782123,0.3884814978,0.5505877137,-0.2127685249,1.5057326555,-0.3375179768,-0.4418465793,0.7669808865,0.4645462036,-0.4733898342,0.0666616634,0.6061386466,-0.4868551195,0.4049857855,-1.6582262516,1.4912316799,0.1251794696,-1.2685055733,0.3584597707,-0.0061725895,0.1182529852,-0.4459925294,0.0649669096,-0.5827793479,-0.9905433059,-0.9163452387,1.7737463713,-0.4419859648,1.9480772018,1.4152547121,0.9885281920,-0.7954316735,-0.6662418246,-1.1790033579,-0.2741505206,-2.0678997040,0.3266300261,1.3303706646,-0.2867909372,-0.9021807313,0.2714713812,-0.5843097568,1.2097675800,0.2966309488,-1.0622887611,0.6333710551,0.3833867610,0.2917357981,-0.5103815198,-0.3244171441,1.2576582432,0.9913121462,-0.1317096502,-0.5059637427,1.1085257530,0.1522968709,1.1645395756,-1.2047892809,2.2415204048,0.1009635627,-0.1189174354,-0.3255894184,-1.5088373423,-0.1761455089,-1.2958545685,0.4631999731,-1.4431842566,-0.0815225467,0.0264114328,-0.0134794405,-1.7359671593,-0.8405629992,-0.0171891171,-1.5212892294,-1.3272206783,0.3295044005,-0.3159745634,-0.4405059218,-1.2775102854,-2.0660405159,-1.3951530457,-0.3871063888,-1.9635423422,0.3878398240,0.2240091264,-0.6311438084,1.1141709089,0.2829698622,0.1319483519,-0.9153652787,1.4351322651,-0.6812025309,0.1347745210,0.8289664388,-0.1638492942,-0.8752292991,0.6741952300,-0.8481402397,-0.4189682901,-0.8234933615,0.2876498699,0.0553242527,-1.3581985235,0.1725343168,1.4257600307,0.3076897562,-0.6096960306,-0.6603984237,0.2657020390,-0.3375091851,1.0193190575,0.3068545163,0.3049698770,-0.8007757664,-1.4549874067,-0.7384971380,-1.3470081091,-1.8314106464,0.0719065815,-0.4571023285,1.0792492628,2.2859106064,0.2279076427,-0.9891816378,-0.6099649668,-0.6531402469,0.4977306128,0.8263016343,1.8157972097,-2.3561737537,0.7034680843,0.3216913640,-0.2272416651,-0.8027136326,-2.7809767723,-0.7257278562,-0.2273125350,0.2905314267,-0.3215314150,-1.8055938482,1.4343173504,-0.9048855305,0.1905162185,0.0468965657,0.8480873108,1.7085329294,0.4332759082,-0.3628672361,-0.6735289097,-1.1163346767,1.3994438648,-0.4484830201,-0.9012812376,-0.4600181282,-0.4331746101,0.1538828015,2.2690322399,-0.1937780529,0.1015669405,-0.5000990629,0.1091853082,0.6234668493,-0.4246721566,-0.0613945201,-0.8901450634,-1.1397343874,-0.8808919787,-1.0332076550,-1.1599528790,0.0582559519,1.4459686279,0.1238117516,-1.9827600718,-1.5158689022,-0.6710330844,-1.8118439913,-1.6237982512,0.0679273456,-1.3040943146,0.3018227518,1.1907341480,-0.0415180326,-3.0691003799,-1.3719874620,1.0663380623,0.4812533259,0.4310096502,1.4828522205,-0.5797268152,0.4582100511,-0.6201152205,0.1096500233,-0.6994256377,0.3923276663,1.5864090919,-0.9220345020,-2.6383047104,0.1972300112,-1.7775818110,1.6898244619,0.5709993839,-0.5445369482,-0.2049824893,-0.4456205368,0.4843392372,-1.4021123648,-1.1148446798,1.3989207745,-0.1107301638,1.9977177382,0.0048229685,0.6804937720,-0.4943865836,0.0055954242,-0.8179009557,0.6151177883,1.7471002340,0.5628360510,-0.6135786772,0.1982985437,0.3813651800,0.1579486132,-0.7328537107,-0.0750542954,-0.1824423671,1.0054148436,-0.0228289776,-0.3487198949,-1.0940510035,-0.7222530842,-0.6091982126,-0.6036486626,-0.2050597668,1.1312741041,2.0681664944,1.1864436865,-0.2236890197,-0.8625605106,-0.7263569832,0.3035775125,0.0642245412,0.4337040782,-0.2739275396,-0.3962904513,0.8403483033,1.0489102602,-0.4937454462,-0.5222024918,2.6116652489,0.1352985650,0.0618634447,-0.3024633825,-0.8286788464,0.1451219916,0.5880844593,-0.6094891429,0.3219236434,-1.3695703745,-0.0585177056,0.1700653136,0.4964697361,-0.9321046472,-0.1507416666,-0.3361282051,-1.9466036558,1.1729111671,-0.2739106417,1.6313178539,-0.1329207718,0.2038348913,-0.7290941477,0.8423547745,-0.1522175819,0.0712911412,0.9698452353,-0.7045807838,-0.3561033309,0.0883658156,-0.4302078485,-1.2478718758,0.4989421368,-1.7669965029,-0.4198913872,0.6975441575,0.4738608301,-0.0651089847,1.0222551823,-0.5519806147,-0.3389316499,1.5764091015,-0.7053538561,-1.2888039351,0.3234673142,-0.1417339593,0.9278524518,-0.2274197787,0.7508451343,1.4466332197,0.6488268971,-0.9954628348,-0.6652079225,0.2864868939,-0.3673034012,-1.4958170652,0.2327007651,-1.5480067730,-1.3630514145,-0.4443548620,1.6024609804,-1.0053298473,0.7348178625,0.8800488114,0.8419062495,0.0995379835,-0.2248645723,-0.5294179916,0.3160320520,0.0924004465,-0.4043036699,0.8951402903,-1.2198828459,-0.0668722764,0.4917221963,0.5889586806,-1.8725498915,-1.7988634109,0.3151299059,-1.3311706781,-0.4863022566,-0.3315199912,-0.1942166537,1.7517579794,0.2368437648,0.5656731129,-0.0282656793,1.7823673487,-0.1720479727,-1.3562507629,1.0161684752,-0.9181568027,-0.6771322489,-0.2678036094,-0.6415093541,-0.9906380773,1.3346472979,-0.7320179343,0.6933484674,-0.3105112314,0.0937701985,0.5368575454,0.0130084530,-0.9673388600,0.5386470556,0.1005189866,2.0324866772,1.2055453062,0.8220839500,-1.5560021400,0.1882465482,1.6134934425,-0.0579883754,-0.4294087291,2.3164374828,1.3468019962,0.7022433877,0.2779477239,-0.5003404617,0.8945329785,0.2074485123,0.0166519284,0.9358554482,-0.3249890804,1.4698566198,-0.4166862071,-0.5823774338,0.6684930921,0.0280649178,-0.3356093764,0.5318160653,-1.4786239862,-1.0148028135,1.1849619150,0.2391745150,-0.6188251972,1.0286505222,-0.7010456324,-0.5719571114,0.1553662270,1.0689032078,0.0141669363,-0.0817926750,1.2871496677,0.8973370790,1.0335407257,0.5311743021,0.2168038338,0.3711017966,-0.7261734009,-0.6836606860,-0.4303300679,-0.9623488784,-0.2232476622,-2.8081274033,-0.1310659349,-0.1354033500,1.3199428320,-0.4372418821,0.3999006748,-2.7013614178,0.2619364262,0.1507003158,0.0715506971,0.8289863467,1.2401783466,-1.0547454357,-0.0138927512,-1.1025797129,-1.3504421711,1.4697799683,-0.4074902534,-1.1207348108,0.0986788496,0.3246071041,-0.8392274976,1.0582296848,0.2235145271,-0.5397490263,1.1688777208,0.2009891868,0.1039046645,-1.0009261370,-0.8749092817,-0.2685181201,-1.0310175419,-0.4049829543,-3.1205077171,-0.3098204732,0.5935285687,0.1903157085,1.1804158688,-0.3473457992,0.8149939179,-0.7612107396,-0.8262937069,0.6924495101,-1.3365644217,-0.7892350554,0.1343418360,0.7926063538,-0.1322494149,-0.4287471771,-0.3642910719,0.1303860843,-0.1418085694,-1.5912516117,-0.0276062898,0.4361262321,1.0095407963,-0.0749416277,0.2285602689,-0.1831205785,-0.0460781157,0.2784950733,-1.8076405525,-0.3249053955,-0.7071861625,-1.1327867508,-0.0700493380,1.8727740049,-0.9032890201,-0.4349606037,0.4104333520,0.6316285133,1.0076644421,-0.8771318197,-0.9682021737,0.4976361096,0.8091021180,-0.0814546943,0.1587979943,0.5097995996,0.5882976651,0.5308931470,-0.0849480703,1.5427222252,-0.3993819952,-0.6722313762,0.6797321439,0.3277135193,-0.0085896691,-0.3661646247,-0.9072237015,-0.4623303115,-0.2023209929,0.6599558592,-0.7539873719,0.8019641042,-0.1096544489,0.0187816937,-0.2943032682,1.1049185991,0.8500798345,-0.8090435266,-0.9830206633,-0.2533683479,1.5624762774,-0.8042505980,0.0995938256,-1.0303261280,1.0731709003,0.5126503110,-0.3870714307,-1.0472843647,0.3077230453,-1.7716023922,-0.1703357995,-0.3809374273,0.2320100963,-1.0177683830,1.2246047258,-0.6436703205,-0.2181359231,1.5420596600,-1.2188315392,0.5913078785,-1.0695223808,-1.0774040222,0.4448950589,1.1289564371,-1.2322168350,-0.9961451292,0.1253382862,-1.2857888937,0.8030779958,0.5583163500,-0.6780901551,-0.0292556807,0.6156740189,0.6637461782,-0.2593209445,0.1577128321,-0.6255224347,-0.5165698528,1.3434090614,-0.1373769790,0.8557762504,0.7699329853,0.0583121888,-1.5436519384,1.2966266870,0.5823848844,-0.3058349490,-0.1300800890,-0.3919242322,-1.1922485828,-1.0443159342,-1.5529685020,-2.7964434624,1.2522928715,1.2292847633,-0.2496839911,-1.6875931025,-0.2166756839,-1.1366854906,1.1348092556,1.0292310715,0.2931405902,-0.0401573479,-0.9168517590,3.1208748817,-3.0247054100,0.1153336465,-0.2590649724,-0.5816124082,1.8359223604,0.8361560702,1.3724067211,1.9320363998,-0.8699535131,0.3323044777,0.9254535437,0.9190768003,2.0381422043,1.0914663076,0.7399589419,0.6411070824,0.1178541556,-0.8540045023,1.2046840191,-1.7498428822,0.1689570099,-0.7534065247,-1.4080204964,1.3100963831,2.1610531807,-0.6405741572,-1.1049610376,-0.5449877977,-0.2860692143,0.3250898123,-0.9200837612,0.9884458780,-0.5333630443,-0.6851798296,-1.0003677607,-1.5293353796,0.0621513054,-0.0578085035,0.6272996068,2.0618607998,-0.2794499397,-0.4480098784,0.1708033234,0.8488475680,-0.0460077003,1.1200356483,0.3858909607,-0.1463131756,-0.8500095010,1.1876649857,0.8287144899,-0.3788069487,0.2699967027,0.7841120958,0.9621093869,1.0886086226,-1.4207915068,0.8679859638,1.1370193958,1.1478097439,-0.0892617479,0.4420532882,0.4368574619,-0.1616665870,1.2207653522,0.3205839992,-1.3781871796,-0.5439456105,0.6632543206,-0.2686441541,-1.0038115978,-0.1014877558,0.5503932238,-1.3899176121,0.0010357754,1.5733733177,0.4335486889,0.0456469469,1.9128178358,2.6157686710,0.3550651968,2.7038369179,1.0162559748,0.6567167640,1.4713921547,-1.3117628098,1.0215899944,-0.9033085108,-0.1266045272,-1.4393845797,1.2639056444,0.7589184046,0.8724140525,0.3952097595,2.1992070675,-0.5563782454,1.0330309868,2.2867393494,-0.6047636867,1.7792675495,-0.8073445559,0.4877997935,-0.2104053199,-0.7016320229,1.4434002638,0.0233583841,0.4562973678,-0.4751683176,0.4907547235,-0.1294404715,0.5382491946,-1.3764859438,-1.3180493116,0.6598469019,-0.9768490791,-0.5608139038,0.7176390886,1.1750555038,-0.1087838933,0.8607848883,0.0236848835,-1.5650117397,-0.8263857365,0.2376575172,-0.3216416240,-0.0618195906,0.5945374966,0.3223091960,1.4338846207,-1.7596757412,0.0521411188,0.6781387925,-1.2394995689,-0.9775453806,1.7855298519,0.4754302204,1.0716226101,-0.0919560567,1.0172238350,-0.3709467351,0.1175377220,0.3524052501,-0.0831708163,-1.4916843176,-0.0503998026,-0.6599224210,-0.2826690972,1.7006320953,-0.6317148805,-0.3335561156,-1.8706378937,0.4418658316,-0.9441236258,-0.3783243299,-0.9927918315,-0.3547174335,-0.6230579019,0.2012146562,-0.4615501761,0.6221498847,-0.2511247694,-1.4008331299,0.3153209388,-0.1327913404,-1.9306480885,0.2888429463,-0.1532785892,-0.7431642413,0.3893904388,0.5003846884,0.5587242246,-0.7005661726,-0.5150581598,0.6435684562,0.3248820007,-0.8303997517,-0.6451705098,-1.5633621216,0.4436821043,-0.5834668279,1.4078401327,0.9660906792,-0.2825075686,-2.9486505985,0.4625095129,0.3063019514,-0.4668817818,-0.8732379675,-0.3178085983,1.3156703711,1.1733013391,0.0139046516,-0.7732798457,1.6154451370,-0.7379982471,0.2065338343,-0.9543405175,0.8040487766,-0.4187107980,1.3101384640,-0.0562577173,1.0397031307,0.8087363839,1.0376975536,0.6207315326,-0.0367724709,0.1032700464,-0.7664158344,0.7779768705,-1.7194195986,-0.9962170124,-0.4599902630,-1.0737614632,0.4924404621,0.5062992573,-2.3763055801,0.3256783783,1.0295050144,-1.0963584185,1.0508966446,2.2131047249,-0.3020640910,0.3280752301,-0.0142530557,0.0741175264,0.3232976496,1.8511095047,-0.0932176560,-0.1747188568,-1.9773966074,0.8212793469,1.3709951639,1.3017138243,0.5213615298,-1.8491699696,-2.2682118416,0.7733955383,0.2187506855,1.3515372276,-0.5978830457,-0.1860491633,0.7750968337,-1.1614238024,0.5150699019,-2.3115155697,-1.1966111660,0.1801932007,0.2726337612,-0.1692290753,-0.5952160954,0.0005237133,0.6088415980,-0.3638955355,-2.2119069099,-0.6087537408,0.8907001019,-0.7753039002,0.1969347894,0.4207064807,-0.8330823183,0.0483885109,1.9549907446,-1.6341890097,0.1474251449,0.3637137711,0.9511996508,-1.1052323580,-0.9953976274,-1.4866085052,-0.2924993634,-0.0756657571,0.8346943855,-0.0225741137,-2.0840604305,0.4949536622,-0.3814873397,1.1613310575,-0.3354426920,-1.0039441586,-1.1599848270,2.5265002251,-0.3191393018,0.3884355426,0.1033144817,1.4330396652,-0.0158385038,-0.5452295542,-0.1095836759,-0.7352720499,-0.9227036238,0.0774430260,0.0953032821,-0.3727390468,-1.0648605824,-0.2965101898,0.8064007163,0.8640318513,1.0614836216,-0.4732660949,-0.9734390974,-0.4409328401,-0.4907247722,-0.4260222316,-0.3214211166,-1.2692657709,-0.6843496561,-1.0450330973,0.9267991781,1.0043290854,-1.9433656931,-0.1234595403,-0.0358733200,-1.0778970718,0.8430383801,-1.6297807693,0.4672100842,0.1302661300,-1.3048177958,0.7166115046,-0.4405407906,-1.6556293964,-0.7538868785,-0.8053990006,1.7398165464,0.8470565677,-1.0320606232,0.6498590112,0.6128501892,-0.2097587138,1.7268390656,-0.4334447682,-0.9774934649,0.0173344910,-0.8519948125,-0.2736777067,1.1822780371,-0.7529136539,1.2937862873,-0.4342118800,-0.4783442914,-0.1367436051,1.1648869514,-1.3607287407,-1.2247972488,0.5062522888,-0.3501808345,-2.3892455101,-0.3553076386,0.0785791352,-0.4684511423,-0.9138480425,-0.7515913844,0.3910466731,1.8633239269,0.0983788744,-0.5529601574,-0.8192595840,0.0123285549,0.9051536322,-0.5296494961,0.6193763018,-0.7575354576,-0.6588627696,1.4482965469,0.1804517806,-0.0969546363,-0.8561577797,-0.1636443138,0.7998893261,0.4571678042,-0.0476388596,-1.4426069260,-0.1742287725,-0.5233820081,0.7883758545,0.3852189183,0.3091126084,0.5430634022,0.4737339020,-1.0917273760,-1.0901318789,0.4070112109,-0.9084571004,-0.7717982531,0.0192359034,0.9061601162,0.5126354098,-1.3967828751,0.7774495482,0.5376854539,0.1111765280,-0.8687179089,-0.6647869945,-0.0788185447,-0.2937527895,-1.9742597342,0.9528505206,-0.6390838027,1.2707260847,-0.6682310104,0.4715318680,-2.0942647457,1.7908589840,0.2074149996,-0.4311299622,0.4696592391,-0.6548035145,0.4858731925,-1.1523069143,0.5596313477,-1.4902211428,-1.7995990515,1.6622927189,-0.2245040238,-0.5269060731,-0.0428438373,-1.2792727947,-0.7476548553,0.0938511789,0.8331119418,1.3060201406,0.3938763738,0.9923769236,-1.6811056137,-1.1295176744,0.2734489143,-1.6697459221,-0.6384560466,0.9949476719,-0.5062407255,1.0034281015,0.0994017720,-0.0723804981,-0.0227089208,2.1757483482,0.1033674479,-1.2962023020,1.6298233271,0.0310833752,0.0043407893,-0.7852146626,-0.7798393369,-0.7882912159,-1.0835288763,0.3038004935,-0.0921095908,-1.4625827074,-1.5864539146,-1.0401488543,0.3578006923,-0.6439752579,0.6123004556,-0.8602662683,-0.0679839328,-1.9755679369,1.0582910776,0.0997800231,-1.1577682495,-1.5413347483,-0.3838081360,0.4210002422,0.4642764032,-0.0339855291,0.1298860610,-0.3884651065,-0.8865935206,-1.6143238544,3.6056587696,0.1462464035,1.5213328600,-1.0632134676,-0.5663945079,-0.1952020824,-1.3035510778,-0.0436232910,-0.4883011281,-1.0581581593,1.6403815746,-0.2546814978,0.3874523938,0.2777298093,1.1789630651,-0.2963931262,-2.3299434185,-1.0283929110,0.4161494374,0.7006410360,1.7180471420,1.0294718742,0.8499308228,-0.1957364976,-2.0873782635,-0.9732530713,0.3517284989,0.6282029748,0.7819412351,-0.6832048893,-1.0266739130,1.5057219267,-0.9331673384,-2.0270714760,-0.7710177898,-0.6412399411,-0.2176401466,1.9960709810,0.1312145889,0.7394256592,1.3804028034,-3.1236875057,0.8488565683,0.7830206752,-1.2917408943,0.4925467372,0.1587381214,-1.1164747477,1.5651832819,-1.0977840424,-0.6612092853,1.8947798014,-0.7653524280,-0.3012660742,0.4719370008,-0.8919570446,0.1150531024,0.2762588859,-0.4841531515,1.3143765926,0.2696977258,-0.2131957114,-0.6583449841,-1.3425199986,0.2763188183,1.1737834215,-0.8113678694,0.4808428288,-0.8791851997,0.2634968162,-0.6410830617,-0.0812414438,-0.6814115644,1.5104262829,0.5177908540,-0.6783463359,-0.1256770492,-0.2949545383,-0.7587720752,-0.8653795123,0.3860862255,1.2165676355,1.2671173811,0.2852470577,-0.5262190104,1.2160490751,-0.2968252599,0.6153306961,-0.6760441661,-0.0796759948,1.0532268286,1.3543426991,1.5206708908,-0.2734349668,1.6068272591,-1.2159032822,0.4170197248,-0.4496528506,0.5826635361,-0.1970722526,-0.2496076673,-1.2450256348,-0.1965055168,-0.5271847844,0.4371919930,-2.1151013374,-0.2608734667,0.0152701726,0.5723733902,0.0681537613,0.0613985993,0.3411239684,-1.2768346071,0.3332662880,0.5430427194,-0.0432091579,1.6785727739,-0.7715849876,-0.1714796424,-0.3674465716,0.6206015348,-1.6828806400,1.1599649191,0.4741328657,0.8494206071,1.0655183792,0.8664425611,0.8542308211,0.2530686855,1.4608001709,-1.4641044140,0.9866617918,1.7032502890,0.9210450649,0.8014882803,0.3322421610,-1.5023698807,-0.3505462706,0.0389856398,0.0831000507,-0.3857187629,-1.5359857082,1.2615644932,1.2758626938,0.1480398178,1.2954460382,-0.7860206962,-1.1860078573,-2.2061941624,-1.0470296144,0.3352247775,0.5302492976,-0.0405291393,1.4120001793,0.4016290307,-0.1539154351,0.9125192761,-0.5446004272,1.2182688713,-0.8864365220,1.1918206215,1.0045500994,-1.6376503706,0.9360725284,-1.2072974443,-0.7660700679,0.5314910412,-0.8932678103,1.1890400648,0.3187058568,1.6210167408,0.4157439768,-0.4446620047,-0.6844602227,-0.8145654798,0.6531211734,0.8158108592,1.4798234701,0.4006395042,-0.7666428089,0.9254111648,-0.3484019637,-1.1469308138,-0.7036637664,-0.0442226976,-0.2382203043,0.4113468826,-0.5789852142,0.7120308876,-0.6015210152,-1.1392376423,1.1177431345,0.4594758749,1.5914516449,-1.0618811846,-0.8215261102,-0.7494154572,0.7032563090,-0.1234351471,0.0701818541,-0.5553544760,0.0761191547,0.3339363635,-2.1919014454,-0.3116528094,0.8165085912,0.2899995446,0.2868409753,2.1124336720,-1.1487253904,-1.4357818365,-0.3476918936,-1.3994435072,0.8405013680,-0.9114860296,0.4391860366,-1.6877720356,-0.2196552604,1.3988096714,-0.6408332586,-0.1922979355,-0.2654271424,0.0860480741,0.2465860546,0.2520399392,2.9076354504,-1.4887257814,0.6890859604,0.4454374611,0.6194879413,-0.0967055187,1.1441223621,0.1449663192,-0.5741001368,0.0515831709,2.8111915588,0.2500806749,-1.0168375969,0.0459030941,0.5006407499,1.2243378162,-0.5594944358,1.5234234333,-0.5856988430,0.8465883732,-0.1062590182,0.7699720860,0.7508335114,-0.5606443286,-1.7602663040,0.4370567799,0.3021217883,0.1467457712,0.6101540327,1.5521664619,0.0121918637,0.0001930556,-0.7419973612,-1.3801542521,-0.0754940435,1.1674489975,-0.0283292662,-1.2254366875,1.6937772036,0.7008804679,0.1472029239,-0.2088548094,-0.9180703163,-0.9908519983,-0.8559581637,0.5744030476,0.2971726060,0.7592765689,0.5797044039,-0.3228662908,-0.3427666128,-0.1186992005,0.2182934582,0.9786879420,-1.4661244154,0.7656714916,-0.3914667666,-0.4707569182,-0.0234617610,-2.1558485031,-0.8340327144,-0.4761915803,-0.1583889872,-1.3076349497,0.6191383600,-0.3673848808,0.4211728573,0.0395293981,-0.2179098874,0.1381019950,-0.0317963026,-0.4639281929,-0.0641642138,-1.1540219784,-0.9627858996,-1.6770368814,-0.5858719945,-0.0825671777,-1.5955755711,-0.0500167795,-0.0760848224,-0.0237301663,-0.0268115401,0.2086068839,-1.6112877131,0.0350952968,-1.4237899780,-1.2756197453,-1.6744543314,-1.3942058086,-1.4011231661,0.5572247505,-1.6251987219,0.0624367483,-0.9734458923,1.9991265535,0.3975417614,1.9408439398,-0.4244121313,-0.7449286580,1.5648454428,-0.1315009445,-1.1770961285,-0.1874196529,-1.0828311443,-0.4274128377,-0.3763251603,-1.8707411289,-0.3534707427,-0.0243204199,1.9254937172,0.5000748634,-0.0090672439,-0.1229096130,-0.1555079669,1.1247876883,0.6508572698,1.3430335522,0.3828526735,-0.7241315842,-0.0204289500,-1.2060266733,1.8055220842,-0.0309408773,1.6533294916,0.9167777300,0.6583053470,2.4935271740,0.1820680201,-0.4153838158,-1.7359157801,-0.9003521204,1.3195201159,1.1472709179,-0.3788455427,0.3824750483,0.5139021873,1.7121081352,1.1626836061,0.1476384997,-0.5816458464,0.2407868803,-1.5572460890,-0.9878185987,-1.6791173220,-0.1426104307,-0.6590248942,-0.6210706234,0.9594504833,0.2867678702,-0.0755748749,-0.0945067704,1.8625407219,1.0528297424,-0.6334456205,-0.5078506470,-1.3274567127,-0.7107422948,-0.2926018834,-2.0036118031,0.1115319952,-0.0476051159,-1.3324609995,-0.7805432081,0.3220021725,0.9446145296,1.6483644247,-0.2507813573,-1.4725340605,-2.6068005562,-1.0014157295,-1.0183038712,1.2119328976,-0.8830393553,0.5760194063,0.4326705337,-0.6804663539,1.8935378790,1.0359658003,-2.4166157246,1.1839493513,-0.2268783003,-0.5061920881,0.9377138019,-1.2114729881,-0.7506918907,0.4980424941,0.8761253357,-0.4148249626,1.1402990818,0.1848191768,-1.8540214300,-0.8729506731,0.8739518523,1.9581677914,2.4186632633,-1.1326782703,0.5931650996,-1.1454510689,0.1306309998,-0.7470979095,-0.5057881474,-0.9316557646,0.0993926078,-0.7553661466,0.1219220161,-0.2455041856,0.3656617999,-0.8616326451,0.1999523640,0.1532318890,-0.7006615996,0.4613142610,1.3785855770,0.6721458435,0.3734226227,-1.3855634928,0.4933677316,-2.0586693287,-1.8312758207,-0.5378765464,0.1734742075,1.1764724255,-1.6062233448,0.9842114449,-0.1152400449,-0.0080436319,2.1545655727,0.9554353952,0.1760829836,-0.4261439741,-1.0313150883,-0.4449267685,-1.6515427828,0.8663641810,-0.3967720568,-0.3075744510,-0.8735423088,0.6620267034,-1.0369021893,0.5346903801,-1.5483399630,-0.3606949151,-1.5275582075,-0.1260908693,1.1827498674,-1.3001586199,-0.8946741223,-0.4685489535,-1.0407261848,0.2360029519,-0.1681945175,0.7322675586,-0.1572569311,1.2127138376,0.0375163071,-1.0115327835,-0.0792735964,-1.0087019205,-0.2862460911,0.9906303883,1.2327841520,1.3395975828,-0.1617410332,-3.1198022366,1.2752115726,-0.9587536454,0.0452648103,-1.0152710676,-0.5220885873,1.2208900452,-0.0604511015,0.6024882793,0.4948946238,0.0399792418,-0.2535513341,1.5232809782,-1.2082173824,0.1494268030,0.7835847139,-0.2103703767,-0.0482308120,0.1537257582,1.2463809252,0.6994246840,0.5315209627,2.1850254536,0.4130679369,-1.9432587624,1.1612490416,0.5338376760,-0.0464589708,1.1988745928,-0.9518498182,0.1815148890,-0.7856477499,-1.3307493925,1.2344479561,1.0216497183,0.6948999166,1.3199999332,-0.3467248082,-0.6526562572,-0.2523265183,-0.4008188844,0.8922727704,-0.4961834848,-0.2049113363,1.6276949644,-0.1190614551,0.1953179687,-0.0473487377,-0.3821465373,1.0792948008,-0.5341405869,-0.7568749189,-0.2242150456,-1.9106316566,0.4949327111,0.8403900266,0.4573747814,-0.8882073760,-0.5454280376,1.3229922056,-0.0953648686,0.1615354121,0.3111441433,-1.2016353607,-1.1228525639,1.5913999081,0.4555059075,-0.0846310630,0.0696771741,1.3984402418,0.8977686167,-0.0743149444,-0.8610787392,-0.0034345402,0.4643716812,0.6500335932,0.3972373605,0.6056055427,-1.1137615442,1.2621937990,-1.0029988289,0.7454153299,-0.9797261357,-1.0222493410,0.2281863987,-0.2279123515,1.2973057032,0.7009657621,-0.1237428635,0.6601970792,1.6168614626,-0.1405349374,0.4543885589,-0.9073397517,-1.3353450298,-1.4128642082,-0.8668837547,0.2140561193,0.6704117656,0.2983856201,0.1711228490,0.0040384457,0.2274931222,-0.5629349947,-0.2145272195,-0.6500881314,1.0181735754,-1.0987073183,-1.1695632935,1.4457358122,0.9086647630,0.5250781178,1.1210864782,-0.5814261436,-1.9068636894,1.2717565298,0.3779475689,1.1875561476,2.1112318039,1.3692845106,0.4907457232,-0.1053989232,1.7720201015,0.3179871738,0.6021529436,2.0522155762,-0.8119975924,-1.2906919718,1.9221531153,0.2619466484,1.4544030428,-0.0270028636,-1.0798466206,2.4531943798,0.4816752672,2.3576691151,0.8212106228,0.6885333061,-1.1239271164,-0.3848465085,-0.5353651047,1.2736561298,-0.4609678388,0.1968630999,0.5500658154,2.0417609215,0.5277529955,-0.4230228662,-1.5167474747,-0.4852030277,1.0694479942,0.3578872681,0.3670755923,0.3847409785,0.5441589952,-1.1518552303,-0.3627217412,-0.2236316949,-0.1309448630,0.3189993501,0.7243591547,0.6128135324,0.6833281517,0.1058774963,-1.0476717949,1.2348972559,0.1849824041,-1.0603389740,2.7461400032,1.0114446878,1.3566025496,-0.6985847950,0.9919859767,-0.1195081174,-0.5770586729,-1.6611901522,-1.4490962029,-0.1540308297,-0.0394946598,-1.5549813509,0.4014787078,-1.4460828304,0.3835073709,-0.2769566774,-0.1825580746,-1.3795892000,-1.0845396519,0.2838324010,-1.9333698750,-1.5066390038,-0.8090303540,-2.3525457382,0.3431841731,-1.8326971531,0.4958780706,-0.6096104383,-0.1282366365,0.0555926375,0.8264662027,-0.5319551826,-1.3494676352,0.0178227182,0.2657372057,1.5358214378,1.4378138781,-1.5428961515,-1.0020878315,-0.1664336324,0.3720614016,-0.9722996950,0.4478465617,-0.5604529977,-2.8267419338,-0.1732289642,-1.3194926977,0.7245579362,-0.4114677310,-1.0185942650,0.0171113219,-0.3274767399,0.8993369341,0.4165078700,-0.4409069121,2.3318879604,1.0301353931,0.0106273629,0.5165274739,0.3694303930,-0.7169600725,-2.0160875320,-1.5899252892,-0.7279121280,1.0887588263,0.2646250725,-0.2574935853,0.2369214147,-0.1405727863,1.1408565044,1.3749165535,-0.3872929215,0.3741849363,-1.1731528044,-0.8771096468,1.7028417587,0.7422641516,0.7952908874,-0.6359503269,0.0625767857,-1.4387636185,0.7526410222,0.5943829417,-0.6834931970,0.4352502227,0.0361339785,-0.3459370732,-1.3282161951,-0.3925054371,-0.3875874877,-0.4427610338,0.6347910166,0.7603368759,-0.4462294281,0.2494061291,-1.7198584080,-2.5241043568,1.0394392014,-0.8128814697,-1.3440935612,-0.9509823918,0.5185998082,0.6612313390,-0.3765857816,1.2585207224,-0.2729130089,-0.1594479978,-0.8824411631,0.3794788122,1.0085316896,0.3316577375,0.5210019946,-0.2534552217,-1.6504944563,0.1905167997,0.3426152468,-0.4149730504,0.4229606390,0.5006102324,-0.6884571910,-0.0085293930,0.2035993785,1.6628166437,-0.7422149181,0.4549663663,0.9701353312,-1.4671440125,1.0306642056,-0.1751043946,-0.3081717193,-0.1086230949,-0.3445905149,0.3018523157,0.5331122279,-1.4184136391,-1.3059164286,0.0133221578,-0.4561957717,2.0107197762,0.0168454461,-0.5268836021,-0.5163084865,-0.2862188518,1.9081737995,0.3808764815,1.1053049564,-0.1701475978,1.8028768301,1.3454405069,-0.9716171622,2.0151402950,0.4353454411,0.2021296322,0.3094969988,-1.2130287886,-0.6061766148,-0.8579288721,-0.5894806981,0.1631432176,0.1187847629,-0.4992081821,0.6937823892,-0.3709974885,0.3257789016,-0.3987151682,-0.7485961318,-0.2293497622,-1.0146118402,0.0110471090,1.7328293324,1.0677479506,1.2207168341,-1.9264101982,1.5223257542,0.3796040714,-0.3781650662,0.1991085708,-1.2878689766,1.4412564039,-0.3321222961,-0.0153004900,-1.0780576468,0.9807602763,-0.1083590388,0.3219371140,-1.0011390448,-1.0939098597,1.0125167370,0.2617959380,-1.9774245024,0.8176585436,-0.5400171876,0.8523032665,0.0277114268,2.1040093899,-1.4332144260,0.8153598309,0.4336749613,0.6829534769,0.6602942348,0.4276879430,-2.8726365566,-0.9237739444,-0.4451941550,-0.1291576624,0.0826604590,0.2901602387,0.1507606357,0.4976918399,1.9305351973,0.6905815005,1.1261466742,0.1136901900,0.4927196503,2.1992692947,-0.7340601087,-0.6472967267,1.2486354113,0.4821243584,-2.0340688229,-0.7239329815,-0.0443657637,0.1745765060,-0.6582645774,0.4640335143,-1.2629460096,-1.6618301868,0.1800085753,0.9277454019,-0.2590980828,-0.7413901687,-0.6935709715,-0.5875934958,1.2377283573,0.3266763985,0.0787180141,-0.5542194843,-0.9741730690,-0.4150099754,-1.5515369177,1.0647892952,0.6235165000,1.3300273418,-0.3489451408,1.3718315363,-0.6768189669,1.3851624727,0.8357720375,-0.6882252097,-1.0305742025,0.0712251291,0.3130685091,-0.6692923903,0.9052766562,1.9800167084,0.9550880194,-0.7589914203,-1.5862555504,1.5604054928,1.0711680651,-0.1050480083,1.1862883568,-2.3280029297,-1.6582649946,-0.3555588722,0.8859654069,2.1518859863,-0.7442384362,0.6685908437,-1.1250841618,-2.7138724327,0.0137464041,1.3366407156,-0.4603686929,-0.8399344683,-0.4507792294,-1.4983799458,-0.8027215600,1.6966629028,0.4295882285,1.5084462166,0.4342085719,0.1687584966,-0.2440459728,-0.1066379622,1.1238811016,-1.6822667122,-0.9517872930,0.4881279469,-0.0958632976,-0.4737888873,0.4130543172,-1.2868320942,0.0282274242,-0.0538525246,-0.6100097895,-0.4368116558,0.5414137840,-0.6348329186,-0.6271486878,1.1452444792,-0.3874225318,-1.0906164646,0.3533582091,-1.7489846945,0.8108950853,0.1281350255,0.9760327935,-1.0696296692,0.8331253529,-0.9128801823,-0.5867547989,-0.1854138970,-0.8016400337,-0.0122459978,-0.2811549902,1.5724511147,0.8933423758,1.5236115456,1.1318390369,-2.1643643379,-1.1678924561,-0.5303066969,0.1001020819,1.5827381611,-0.3443536460,0.4299806058,-0.6880388856,2.3481752872,0.8799027801,-0.1208624095,0.3161224425,0.1859720945,1.3103215694,0.5370991826,0.2128050774,-1.6082152128,-1.0610541105,-0.3076724708,-1.3912265301,2.0203952789,1.2839845419,-0.1427117586,0.7247159481,-1.4809105396,0.4151991010,0.7133069634,-0.9822463989,1.0256047249,0.8960664868,0.2456524372,2.2871968746,-1.1332281828,-0.9934768081,0.0801362023,-1.4279161692,-0.1673499644,1.9552475214,-0.7649120688,-0.1214441359,-0.8505011201,0.0120534971,-0.2664821148,0.1010014117,-0.0249482337,0.4609630108,-0.4709973037,0.7293856144,0.3688291311,-2.2109615803,1.2869336605,-0.3740674257,0.0017372227,0.1274275184,-0.0548788235,0.4981512427,2.0514848232,-0.3548823297,-0.5679026842,-2.2651638985,-0.9933956265,-0.4226258695,0.5724143982,0.6467649937,-0.5059992671,0.6243510842,-1.3668729067,-0.5580800772,-0.2308873683,-0.4146345556,-0.8414208293,-0.8874806166,0.8085399270,-0.7730150223,1.0769597292,-2.2644515038,-1.7992531061,-1.5193790197,0.6511667371,2.0010735989,-0.4351148307,0.5123409629,0.4797986448,-0.3782280385,0.3045934141,1.0081927776,2.1089031696,1.4194885492,-0.7833939791,-0.7446916699,0.1809913516,-1.4201674461,1.5365930796,1.5332006216,-0.0955717042,-0.0791906789,1.2793784142,0.2346884012,0.6085548997,-0.7300610542,-0.7544391751,-0.0971425176,1.7628134489,-0.5690230727,-0.2787840366,-0.2442644686,1.3795033693,0.6344102025,0.4248405397,-0.1316951513,-0.4010356665,0.9959358573,0.4057629108,1.0247602463,-1.6310348511,-0.1843463928,-0.0751169100,1.0483053923,0.8583419919,1.0581882000,0.5709701777,0.1121916398,-1.2642484903,-0.7674326301,-2.1037101746,-0.3202399611,-0.6719353795,-0.8261151910,0.7101277709,2.6124789715,-0.1418309510,-1.3277183771,1.0787343979,-1.2282276154,-0.1210674867,0.2911917567,0.6180588603,-1.4232866764,0.5941316485,1.0013989210,-0.0831873789,-1.4150587320,-0.3144525886,0.2749459743,1.5043956041,-0.8493507504,-0.3435238004,0.1091308668,-1.4348704815,-0.6094563603,-0.3990669847,0.1706257463,-1.0890892744,1.3205559254,0.2972381413,-0.7722620368,-0.3236086071,0.4466733932,-0.4585110843,0.8907366395,0.3113555014,-1.0298800468,0.6594182849,2.1507937908,-0.5677946210,0.3051919937,-0.3771156669,-0.5940546989,1.2152264118,-1.7259300947,-1.0823833942,1.3255735636,-0.8910102844,-0.0269354563,-0.1528990567,1.4183866978,-1.6457661390,0.8868795037,-0.8474878669,-1.3936561346,0.0618900172,-0.5172175765,3.1002268791,-1.4958193302,0.3102186024,-0.9779730439,1.1106261015,0.7437641025,1.4932644367,1.0055906773,-0.7624963522,-0.4558341801,1.2478998899,-0.0513665862,-1.0852686167,2.5063498020,1.4703984261,-0.3500232399,0.6674960256,0.2232310176,0.7430081964,1.4739216566,-0.2805545330,0.0959332883,-1.2647999525,-0.8458613753,0.6121600270,0.3654181659,-0.5369811654,-0.4391386211,-2.1446189880,0.8581434488,1.3331199884,0.0303843282,0.6091219187,1.1128925085,-0.6695650220,-0.2710272074,-1.6208012104,-0.6248922348,0.5111383200,0.4374771416,-0.0601305887,-0.3222166598,1.5219869614,-0.2043878138,0.7294411063,0.5184146762,1.4763427973,0.9772499800,-1.1257607937,0.1171994582,-0.5923586488,-0.3355710208,-1.0741111040,-0.5246708393,-2.2213320732,-0.1392166018,-0.4191494286,-1.0089921951,-0.3403863013,0.5482953191,-1.1640391350,-0.3767908812,0.5043502450,1.2352068424,-0.0104251159,-0.1011670530,-1.4769479036,1.0991642475,0.9631522298,-0.1085720211,-0.3289594054,-0.1785956621,-0.1722016186,-0.9106789827,-0.0757652223,1.6013062000,2.8825588226,0.0283018276,-1.4420264959,-1.0566796064,0.3184948862,-0.7164399028,-0.6493185163,-0.9150819778,0.1000853702,0.6208550334,-0.1778074652,1.1770408154,-1.3932850361,1.4212722778,0.5371090174,0.4546726048,0.4049543738,0.3981168866,0.0488865748,0.8620789647,-1.1955425739,1.2540414333,-2.0386204720,-0.0258903690,-1.3946413994,1.7492851019,-0.3227463663,-0.0915191621,-1.4765635729,-0.0714700073,-0.4856380224,-0.3160601854,-1.1019278765,-1.4820511341,0.4517401159,-1.3478686810,-1.5971720219,0.4214863181,-1.2817587852,-0.3930203617,-0.1581448764,0.6314710379,-1.2951623201,-0.1740406007,-1.0108921528,1.2809277773,0.6833066940,0.6616382599,1.7153782845,-0.6153312922,1.5842894316,0.7544012666,1.6303297281,0.1301917434,-2.7217433453,0.3398594558,-0.8163784742,0.1465732604,-1.2905712128,-0.4101938009,1.6654448509,-0.2119739801,-0.7760418653,-0.4227268100,0.6563307047,0.2659547925,-0.0037535611,-1.0131603479,-0.2349339277,0.9261472225,0.3318826854,0.3253736198,-2.6372146606,0.2674591243,-0.1940494925,1.3571807146,-1.6915826797,0.5772549510,0.8997503519,-1.3403272629,0.7346234322,1.5062402487,-0.1679347157,1.2141203880,-1.6488654613,0.6915194988,-0.2572011054,-0.1990943253,0.2498833686,1.2450773716,0.3484862745,-0.2589534819,0.7116019726,-0.0218918305,0.5702000260,-0.9457767010,0.6703088284,-0.1766744554,1.3134074211,-0.1710943580,-0.2920600772,0.9888873696,0.6314431429,-0.6614246964,0.9294165969,0.2508786917,0.5414218903,0.2954601943,0.8805912137,-0.0731926933,1.7276763916,0.3145478964,1.1606113911,1.0999108553,-1.5043370724,-1.5866116285,0.0370911658,1.3214834929,0.0746138021,0.9906339645,0.1499240994,0.9241827726,-1.4057812691,-1.2694085836,-1.2315986156,-1.0792061090,0.9238930941,0.3661459982,-1.6559048891,0.3552600443,0.1590854973,-2.0836281776,-0.3751182556,0.8667919040,0.2102769166,1.4756578207,-0.5184097886,-0.0366294533,0.8832123876,-1.0546194315,-0.1811883897,-0.1210824773,-2.1764533520,-1.5692141056,2.0706942081,-0.9752756357,0.1462701559,-0.1786944121,-0.9237043262,0.2103956491,-0.1442062855,1.2261948586,-1.5112875700,1.5062558651,0.0944361016,0.7306627631,0.6643269062,2.2133276463,0.8330996633,-1.4814969301,-0.3682819903,-0.4991627038,0.5526918173,0.3599629402,0.6244876385,-1.0617635250,-1.0455168486,-1.1398391724,-1.3221683502,0.0184009988,-0.5667765737,1.8121285439,-0.9326394200,-0.7341508865,-1.1592438221,1.2299790382,1.7348306179,-0.7335332632,0.8989298344,1.2027136087,1.1966621876,-0.1625650376,-0.1017761528,0.2831718922,0.4695369601,1.1291228533,0.6805573702,-0.0990784019,-0.7106087804,0.2395488918,0.1024907678,1.7224653959,-0.9518821239,-1.7251338959,0.9914779067,-0.9855437875,-0.3009017408,0.9082549810,0.0410030857,-0.0605210140,1.1658284664,-0.9308250546,0.8737416863,-1.2085171938,1.0346195698,-0.5344747901,-0.2332480103,0.6903033853,0.1028862447,0.8828144073,1.8908827305,-0.7360958457,-0.2265916616,-0.5171056390,0.6966750622,0.3447278440,-0.0323995762,-0.6886252165,-3.2709035873,-0.8757738471,-1.4021294117,0.1837808639,-0.9577113390,1.2251466513,-0.2875821292,-0.2114524692,-1.4256474972,0.8641709089,0.0528381169,-0.0744572952,1.5797815323,-1.1734684706,-0.0783758909,0.2729905248,0.5856707692,-1.0022348166,-1.2545819283,1.0302791595,-0.3580471575,-0.9342455268,-1.9813054800,-1.5998274088,1.3066407442,0.4830575883,1.6324607134,0.1079617515,-0.4973579049,-0.5194500685,-0.3114619255,0.1192606017,-2.0525612831,0.2186866999,-1.5327219963,-0.4967102706,-0.1050102040,-0.0578927137,-2.1460046768,1.3595274687,0.2326336652,-0.1665844172,-0.4899091423,0.7253504395,-0.2241188586,0.0341161974,-1.7404079437,0.5003447533,0.4687319100,1.5334626436,0.2852185965,-1.5014708042,-0.4241717756,-1.2355568409,0.0657551959,1.2892919779,1.2911703587,0.6110507250,-0.0205472484,-1.2269330025,0.0883116126,-1.0893718004,-0.6376819611,0.5561304092,0.0832567215,1.6728909016,-1.2436583042,0.1721850187,0.6242291331,0.3138146996,-2.2066717148,0.2796196043,1.0710690022,1.3156319857,-0.0950455889,-1.5921502113,-0.9913931489,0.1297880560,1.4663813114,-0.1556957811,-0.8660828471,-0.4202181101,-0.9978961945,0.5445381403,-1.5141788721,1.9711934328,0.5910512805,-0.9280182719,-0.6373056173,0.4286117256,0.7815433145,-0.0861902535,0.0154004376,1.5583499670,-0.5532020330,0.2428787202,-1.3022339344,-0.6369246840,-0.1703581214,-0.3426039219,0.8764404655,0.5651657581,-1.1531502008,1.3143377304,-0.6532971263,1.3424408436,-0.5932373405,-0.3148380220,0.3417423964,0.0807463825,0.7385244966,0.1785105616,-1.0377227068,2.5720541477,-1.6021740437,0.3730979860,-1.0089817047,0.2074581236,0.7690361142,0.1414442956,-0.0658927634,1.2981730700,0.5637852550,-0.7915480137,1.1714626551,-1.0327466726,1.2980322838,-1.8191382885,-1.5950011015,-0.0475060828,0.1701105088,-0.1173396930,-1.1642503738,-2.2592539787,-1.0229673386,0.0272143669,-0.0346517377,1.9163516760,-0.3508054614,-0.5195938945,0.7642535567,-2.5424456596,0.0920520052,-0.5108087659,-0.8645259738,0.8696979284,1.5335197449,0.1574706435,0.8634047508,-0.7973005772,-0.7276571989,-0.0082663214,0.6169670820,1.2819828987,1.0705560446,-0.3476598859,0.8035858870,-0.2554123700,1.5247392654,-0.3427659571,-0.2781977654,-0.0387262739,-0.2124831229,-1.0138919353,1.1995728016,-0.3768789768,-1.0625375509,1.2412786484,-0.0552544296,-0.7425494790,0.5503547192,-0.2265021652,-0.5776142478,-1.0426775217,0.0635304376,-1.0789164305,-0.0305424035,-0.4114821553,0.8515140414,-0.8038818240,0.1948237717,0.1175146028,-1.1841410398,1.4999989271,0.7257269025,1.1487137079,1.6531249285,-0.9639879465,0.9420316219,-0.6486244202,0.2358347327,0.2451820672,-0.9946019053,-0.4021207988,0.6609389782,-0.6528478861,-0.7113485336,0.2650088370,0.6931459308,-1.5257225037,-0.5300140977,0.4230892360,-0.1780603528,-0.7085021138,-2.0326261520,1.1543872356,-0.6382230520,0.1267194450,1.1673766375,-0.1194199398,0.5173939466,1.3585667610,1.1757655144,1.2875258923,1.7019704580,-0.3240980208,0.3856199980,-0.5278858542,-1.4395867586,-0.4803539813,-0.7832537293,2.5728754997,0.6120492220,0.1088558584,-1.4145896435,-0.0893893540,-1.1972055435,-0.8456657529,2.5421011448,0.8142038584,-0.4200177789,-1.3778551817,-0.1695551574,-1.4214105606,0.3386326432,0.4762045741,-0.8144193292,-2.0145246983,1.3744714260,-0.0912032276,-0.5277309418,0.3268625140,0.0133851767,-0.5244994164,-2.6017088890,1.9043643475,1.1018794775,-1.4449181557,0.0988714769,0.1080312133,0.2872729599,-1.0176873207,-1.5658758879,-1.4753624201,0.6132729650,-0.6109262109,0.7954557538,0.3561187685,-0.6416935325,-0.8037799597,-1.0986231565,0.6042654514,-0.0362247378,-0.4225933254,-0.0711886138,-0.5749738216,1.0292119980,-0.0141652646,0.3381133080,0.2150502056,-0.4366036057,1.1847845316,1.2134108543,0.0970221311,-0.3986929655,-0.3410035074,0.5849024057,0.8327379227,-0.3633055687,1.1413456202,-0.3347489834,-1.4785804749,-0.6094909906,0.8936745524,-0.2556134760,-0.1951664984,-0.6637004018,-0.9761881828,0.5172336698,1.0505046844,1.0351791382,0.9528251290,-0.6650516391,-0.5152972937,-0.5114353299,-0.5137189627,0.1342589110,-0.4055825472,0.9870741367,1.1039853096,0.7906116247,0.1031517833,-0.5891082883,0.4176992476,1.1658488512,0.9659720063,0.0746390373,-1.0539230108,0.8605904579,1.0937052965,1.4656609297,-0.0631425753,-0.2436380386,0.5220047235,-0.5257426500,-0.3511520624,0.1896903366,1.1232941151,0.9083298445,0.6321584582,-0.2297795564,0.4393576384,-1.1335648298,-0.1767812520,-0.9877588749,-0.6336392760,0.6270663142,0.5877546072,-0.2975437939,-0.6329882741,0.9075940847,0.1420644522,0.4181271493,-0.8419764638,1.3827379942,-0.2564235032,0.4914464951,-1.2188130617,-1.7116364241,-1.8048491478,-1.8463013172,0.3928754032,1.4446197748,1.7741932869,-0.2339616269,0.8514254093,-0.7865287066,-0.4787963033,0.8111802936,0.5455805063,-1.4866166115,0.5192504525,0.5673210621,-0.2531650364,0.4797608554,-1.7640885115,-1.7594573498,-1.0405248404,-0.6443892717,-0.0463766120,1.5923037529,-0.9849032760,0.9268825054,-0.3332609534,0.1753576994,-0.4664939940,1.1735558510,-0.4948464334,-0.5844563842,0.7905429602,0.9834874272,-0.5397875309,-0.3261406720,0.5392394662,-0.5751277208,-0.2247804999,-1.1403326988,-0.9152319431,-0.3199635148,-1.0563613176,0.4798598886,-1.5495011806,-0.2683282197,1.0509999990,-0.8671765327,-1.7904404402,-0.4655726850,-0.8255794644,1.2549281120,-0.5127987266,0.3980410993,0.5606667399,0.2152752578,-1.6999623775,-0.0291132275,1.8648895025,0.6139222980,0.0244569257,-0.9495642781,-0.0074470057,-0.9770514369,-1.3872021437,0.1106198654,-1.5846104622,-0.4539607763,-1.1245915890,-1.2696129084,1.3264654875,-0.6482177973,1.0197538137,-0.7960487008,0.0526552238,0.1811360568,-1.6001381874,-1.2790617943,-0.7372736931,0.8097754121,1.8652113676,0.6001631021,0.4037535191,-0.0492363907,1.1228337288,-0.6498822570,1.0116053820,-0.2541756630,-0.5277975202,-0.2402507961,-0.1130158454,1.1338608265,-0.7202472091,0.5499478579,-0.9729791284,-0.8757820725,-1.8153737783,-0.6840500236,0.0959931836,0.5253782272,1.0612294674,0.0080760587,1.4577175379,-1.3004442453,1.9005447626,-0.7658629417,-0.0105433399,0.8367369175,-0.6676630378,0.9297543764,0.9685356617,-0.0386456437,-0.4531649053,0.1079624817,-0.0924528167,0.6686045527,1.7595429420,0.8170405626,-0.6267473102,-2.5353696346,-0.6208639145,0.0412966460,0.5412843823,-0.6714181304,-0.1228801236,-0.3316660523,-0.1653130352,1.4541288614,0.6057051420,0.7982510924,0.1380858123,-1.4818567038,1.8989332914,-0.9859840870,-1.2145018578,0.7614639997,-0.7683216333,-0.4145599902,-0.4076405764,-0.2403526902,-0.5470996499,0.9964763522,-1.8223305941,0.4747248292,1.5665532351,0.9140262604,0.1729218364,0.5444464684,-0.1636365354,-0.8873438835,0.4439423680,0.6227127910,1.7554078102,-0.4988125265,-1.3193113804,-2.5715079308,0.1748979837,-1.1597133875,0.9316927791,0.1183342338,1.0189135075,1.0244257450,-0.5853592157,0.9235587716,1.2721583843,0.8519009948,-0.4364132583,-1.2144123316,0.2642391622,-0.3939892352,-0.0805365071,0.4169847965,-1.6299033165,-1.9063054323,-0.9444448352,0.9864621758,-3.2844877243,0.4394325912,0.5473648310,-0.2011999935,0.6504402757,0.3405825198,0.5267879963,1.7770034075,0.5222274661,0.9281985760,-0.2189456522,0.3734814525,-1.2006289959,0.2925578952,1.1988446712,0.7234704494,-0.4607257247,-0.8953572512,-0.0688983947,-0.1996186823,2.5704195499,0.2287005633,1.5053178072,0.0987073630,0.4207965136,-0.1668317318,-0.3914250135,0.0472337753,0.8962624073,-0.6044977903,-0.2340323478,0.3957251310,-1.4881333113,0.4008922279,-0.2279271781,2.0719885826,-0.5289013982,0.3241880536,-2.6822669506,1.7045650482,-0.1832091957,-1.3438804150,-0.1880180538,1.0730087757,0.3521874547,0.2114675641,0.5612317324,0.9730195999,-1.4720804691,-0.0725681335,-1.4717452526,1.6405420303,-1.4896878004,0.0528693758,-1.7767858505,0.9301193357,1.7837607861,0.2781662941,0.1405596286,-0.3057101071,-0.2079758793,0.5234370828,-0.5637179017,-1.4416309595,-1.0048124790,0.4227478504,1.0247695446,-2.4148521423,1.2287952900,2.0506439209,-0.3796081543,1.4330184460,-1.6261191368,-0.4310197830,-0.3651142120,-0.8131893873,0.1408641189,-0.0862338468,-1.0842740536,-0.4975840449,-0.8313937783,-0.3324953318,-2.9499680996,-1.3614028692,-0.0652090460,1.5336951017,0.6620618105,-1.4137949944,1.0900887251,0.1952648610,0.4613917172,-1.3025218248,1.1172809601,-1.0675442219,-1.5549499989,-0.2244365811,0.5666527748,-1.8053593636,0.2591793835,1.1105011702,-1.9888157845,-1.3004876375,0.9484360218,-0.1045219526,-0.1354653537,0.7844735980,-0.3132534623,-1.7118363380,-0.1989667118,-0.2725273967,1.5450774431,-1.2673224211,1.6919636726,0.2171541452,2.2025887966,1.4983998537,0.5503693223,1.3401776552,1.4544260502,-1.9329987764,0.1200451478,-0.9440642595,-0.3997438848,0.7572956085,-0.0289923865,0.4980324805,0.4981862605,0.6089060307,0.2215690613,2.8459966183,-0.3495443463,0.3898267448,-1.3111178875,-1.4949693680,1.5423781872,0.4355337620,-0.2667261362,-0.6964426637,-0.0315350629,-0.0684453547,1.2804672718,-0.3476506770,0.3679663539,-1.9576956034,-1.5535807610,0.3000622094,-1.0038506985,0.0751238614,0.0237246975,1.8045992851,-0.9453797340,-0.2001632899,2.1614372730,-0.9781127572,-1.0257860422,0.3228924870,-0.0656457618,-0.5376325250,-0.5086116195,2.1152424812,-0.4741887152,0.9335947037,-0.9201823473,-1.5525681973,-0.8249668479,-0.2767834663,0.3954752684,-2.5128004551,-0.5187504888,1.7483252287,-1.5200672150,2.7166440487,-0.3970314860,-0.8433889747,2.4272284508,0.2976959348,-1.3999366760,0.9331608415,-0.6598845720,0.7047004104,0.4617165029,1.2049220800,-0.4600013494,0.7962696552,1.4818439484,0.4008847177,-0.4036520720,1.8412313461,-0.1604305208,0.0991646573,0.4628383219,-0.9043536782,-0.8916121125,0.4315722287,1.3325688839,1.9264107943,-0.6885731220,0.3321375847,-0.2413543910,1.0912894011,1.1436660290,-1.4943883419,0.4226326942,-0.3977138102,0.6066868305,0.1816943884,-0.0278797448,-0.7122353911,0.7773500681,-0.3370968997,-0.0819773525,0.3859794736,0.0197459012,0.7838968635,1.1054192781,-0.0492523052,-1.1183481216,2.0457713604,1.4440535307,1.4088461399,-0.3506045938,0.9419050813,-0.4516931474,-0.0231885668,-0.2311489135,-0.5307110548,-0.6097031832,1.5688374043,-0.0618275702,-0.3840580285,-0.1462161839,-0.7490805984,-0.4684410393,-1.1734311581,0.2761482000,1.6468441486,-0.4369893670,0.6186989546,0.5075575709,0.2093936950,-0.0073280954,1.4158865213,1.3943082094,-1.1606276035,-0.1925585568,0.7860649824,-0.1255825013,0.7291187644,-0.0382035486,0.8796746731,3.2665982246,-0.1572821438,1.2827008963,-0.2016982436,0.0290385038,1.2065564394,0.5020515919,-0.0758089051,-0.5608183742,-2.4836220741,0.7568008900,1.7811390162,1.6835224628,-1.1110769510,0.3087627888,-0.5306309462,1.4413764477,0.0940743685,-1.1490490437,1.7519093752,1.1665536165,-0.5972436070,-0.9645920396,-1.8831322193,0.3731502593,0.7097339630,0.8633415103,0.0572413802,-0.3672955632,0.0742917284,-0.5524155498,-0.0990694165,1.2753888369,0.1014469489,-0.2720424533,0.7490035295,-0.0318105072,-2.5118894577,-0.7490311861,1.6888785362,-1.5632879734,0.3120557964,2.4351465702,0.9439433813,1.7685650587,-1.7593694925,-0.9471104741,-0.3451783657,0.7697889805,-0.6745629311,-0.1576409042,-0.7649592757,0.7051118612,0.4522475898,0.1596816778,-0.3910192847,1.8914453983,0.1121585667,-1.7256836891,2.5300681591,0.2082690150,-1.8599275351,0.7754518986,1.6154131889,1.3406716585,0.7618990541,-0.1711893827,-0.0310675185,-0.0496421643,0.4200766385,-1.5414303541,-0.3754616678,1.0248707533,0.7819921970,0.8943247795,-1.0348619223,-0.3936333656,2.4675981998,1.1788799763,-2.4421749115,-0.7062406540,-0.4198507965,0.0803024247,-0.6633006930,-0.1075372994,-0.4508400857,0.4074032307,-0.7849459052,-1.2711269855,1.3193122149,0.4826998115,0.5387716889,-0.2636992335,-2.0554578304,0.3182610571,-0.1439537555,-0.0299516935,0.4889170527,0.6923212409,0.6136444807,-1.1940793991,0.4658052623,-0.0280528236,-0.3650117815,-0.5338830352,0.7320910096,0.6896799803,-1.2262221575,0.6613311172,-0.8810014129,0.0679493994,0.3078416884,-0.5542497635,-1.0899014473,-0.1688338518,0.6363798380,0.9226398468,0.2054868639,0.2460445613,-0.9185663462,0.1189117134,-0.0556812920,1.2891730070,-2.4134826660,-1.5054019690,-1.1148625612,0.5536409616,-0.7582384944,1.5371382236,0.5538336635,0.2182800174,-1.1763197184,0.5749715567,0.7819045782,0.8062111139,-0.1452429444,-0.2014859468,0.5254017711,0.1605516672,-1.7581435442,0.5122259855,-0.6614473462,-0.5915403366,2.0017547607,-1.4677304029,-1.8257400990,1.0064178705,-0.5828084946,-0.4141933322,-1.9140504599,-0.0616672523,-0.0180219132,-0.4038219452,0.6312733293,1.2066689730,-0.4449644983,-2.8706459999,-1.2025235891,1.0925306082,0.7826869488,-0.7611364126,0.3302960694,0.5973567367,-0.0336623602,0.4979988039,-0.6890585423,-1.2695591450,0.9333893657,1.1220725775,-0.7051638365,-0.3467444777,0.9953252077,0.5555455089,-0.0913688913,0.9911448956,0.0564950071,1.1763910055,0.4268105328,-1.6847207546,0.4380587935,-0.8402453065,0.8270261288,-0.0309975259,-0.7158976197,0.2076825500,0.2148397267,-0.6354771852,-0.2590553463,1.9080600739,-2.6474463940,-1.6957372427,0.0676404461,-0.1840924770,0.0144398957,-0.7230440974,-1.4499595165,-0.3431442082,0.7012284994,1.6000750065,-1.1220747232,0.6476452947,1.2227518559,-0.6261531115,-2.0118496418,0.5587783456,0.5587535501,-0.7095311284,0.9690502882,-0.0612876080,-1.0169298649,-1.8414348364,1.4388775826,1.2759331465,-0.5176864862,-0.3065904975,-0.1054771617,-0.8933632970,1.7129597664,-1.0600179434,-1.7203254700,2.1747725010,0.5608677268,-1.0009634495,-1.6312663555,-0.1436923146,1.0822681189,-0.8980425596,-1.1708720922,0.8111722469,1.4318437576,0.7622471452,-0.1665702909,-0.7519943714,0.9354758859,0.4794349074,-0.9928976893,1.2101974487,-1.4867138863,0.6146788001,-0.2739740908,0.7458140254,-0.4276439250,-0.7129654884,1.0291323662,0.1629079729,0.5204790235,0.4500774145,0.6597102880,-2.1476511955,0.7354454994,2.0337862968,-0.4528868794,0.0470402688,-0.6466990113,-2.4321630001,0.9452065825,-0.8999962211,-0.2017476708,0.5209354758,0.1222702488,0.3367359638,-0.6224790812,2.3189260960,0.8680391312,-0.5176272988,0.5175158978,-1.4247558117,0.2031879127,-2.5270433426,-1.1400226355,1.2911773920,0.4571803808,1.5411505699,0.3775106966,1.0139513016,-0.9173130393,-2.1711902618,-0.0480994694,-1.5899727345,0.1245185956,-0.1466777176,1.1491481066,1.8068344593,-1.2763129473,0.2475799173,0.9650402069,-1.5658047199,1.2057271004,-2.1787817478,-1.9162775278,0.3622097671,-0.6148615479,2.2243676186,-1.0941650867,-0.1319183856,0.3140008748,0.1496839225,-1.5112067461,1.5638947487,-0.0783534944,1.1089277267,0.0493666902,-0.3356166184,0.2406343371,-0.2573273480,-1.6920350790,-0.3557884097,0.5366314650,0.9400575161,-0.9624430537,1.0769087076,-1.0523335934,-0.0877942294,-0.0052203424,1.4278577566,0.7861345410,-1.3564819098,0.1132832840,0.3424504399,0.5758148432,-0.7315395474,-0.2296319157,0.7997226119,-1.0046871901,-0.2958320081,1.2034623623,-1.9853528738,-0.0400415435,-0.7096756697,0.5029446483,0.3679005504,-0.6466954947,0.8429231048,-0.3528733253,-0.8913444281,2.4212992191,0.4225657880,1.5877314806,1.0010522604,0.8875393867,0.0978859067,0.9387049675,0.9202107191,-1.2897603512,2.0188601017,1.4211659431,-0.6326606870,0.3057494760,2.0222163200,0.9547148347,-0.1210186332,1.0936723948,0.4895169139,-0.4024842978,1.2918033600,-0.7272326350,0.5280922651,0.9792674184,-0.9152534604,-0.4218613207,0.7013449669,0.7105325460,0.4497777820,-0.1501760036,0.4193355441,0.0714192092,-0.0715517104,-0.3542770147,-0.3148297369,0.2007195204,0.4526666105,1.2837107182,0.6288003922,1.4994120598,0.1824219525,0.9061366916,1.5625766516,-0.3971055150,-0.2912955880,-0.0010462973,0.6671071053,-0.7881889939,-2.7450766563,0.4060696363,-0.1217147857,-0.0527308248,-0.5595987439,-1.0663646460,-1.6144676208,-0.8451096416,-0.7483228445,-0.4292066395,-0.7167803645,0.3249592483,1.0160164833,0.5160896182,0.5963602662,1.8268053532,-0.2776781321,-0.4084135890,1.1316784620,-0.0133100701,-2.4482481480,-0.0586686917,-0.8878390193,1.3675085306,-0.0189303663,-0.3145028353,-2.3099646568,-1.7913293839,-0.4868177772,-0.9915539622,-0.8610973954,0.5070689917,-0.6919354200,0.4805471301,2.0585455894,0.2822274566,-0.6514480710,-0.1684999913,-0.9540156722,-0.5895755887,-0.4050535560,-1.8935021162,-0.2592824101,-0.5564218163,-0.5321366787,-0.3610735536,0.7515267730,-1.0464690924,0.2622892857,1.9876885414,0.3568264544,-0.7345346212,-0.0195515398,-1.3769825697,0.3296893537,-0.2662521303,0.4305160344,0.8540118933,-0.0390822478,0.3072167933,0.2258054018,0.6492428780,-2.1197884083,-0.7837410569,1.2383978367,0.4710659683,1.1728113890,-0.9507129192,0.2316634953,1.5851820707,0.9761613011,-0.6257829070,0.7709450722,-1.2106201649,-0.1576354951,2.5922064781,0.5946409106,-0.8199970126,1.3616390228,0.8881381154,0.1613833308,-0.7847581506,-0.1245018691,-0.3079818189,-0.2307329029,1.0258018970,-0.3544710279,0.4603793323,0.1158363000,-1.5349887609,0.5325800776,-0.3238184154,-0.7847681642,-1.0883129835,-0.3599952757,0.3478820324,0.8348949552,-0.1920605004,-1.6158021688,-0.4275300503,-0.9156060219,-1.5471988916,-0.0337640494,0.3297310174,0.1512339711,-0.1176083460,0.0440559611,0.0721314177,-0.0469049104,-0.5487977862,-0.6798905730,0.1742166579,-0.9439554811,0.5917685628,-0.0007143845,-0.6769761443,0.9055025578,1.2873252630,0.8089355230,0.1100778431,0.9906618595,0.5761532187,0.3763134181,1.0817846060,-0.2395380288,0.8779850602,0.1564888656,-0.3758312166,-0.9272571802,1.9166927338,-1.0327939987,0.1510976553,-0.5881170034,0.7933108807,-0.5769035220,2.0220353603,-0.7505076528,0.9200173020,0.3916193843,0.2468304783,1.6190906763,-0.0692143887,2.9150190353,0.6242098808,0.6861552596,0.3290536106,-0.0465923660,-0.1690702885,0.2150677294,0.8022250533,-0.4570151865,-0.3585347533,-0.8290402889,0.9220418334,0.3166327477,1.3787505627,-0.4238806367,-0.6832771301,-2.3926756382,1.3433904648,-0.4304220378,0.0106177842,0.0189974494,0.1315878183,0.2400119901,0.3355641663,-0.4072660506,0.9903833270,0.1759019643,1.1644349098,0.1000541449,-0.4680081308,-1.3790748119,0.3504778445,0.0912212506,-0.7095877528,0.4825436175,-1.9707536697,-1.7738105059,1.2781053782,1.0709049702,-1.1580072641,-0.0813724622,-1.3623567820,0.3525542617,-0.7098584771,-1.3302956820,-1.0732815266,0.7031227946,1.6278609037,0.3216923773,-1.6622815132,-0.5861720443,0.7162619233,0.5596861243,0.3960135877,-0.1563261449,0.7563478947,0.8782933950,0.6613606215,-0.9163061976,1.9936851263,0.7046018243,0.5298975706,-0.3517471254,-0.2529703975,-0.6819351912,0.4511622190,-0.3695062697,0.2835831046,0.0965076685,0.9501286149,-2.5614476204,0.5790864229,0.4087923765,-1.2475892305,-1.3186043501,2.3067893982,-0.5290445685,-0.4532274306,-1.4219975471,0.4242465794,-1.1147121191,1.1617943048,1.3607591391,-0.1647880673,-0.6505087614,1.3001717329,-0.4226404727,0.0101207495,0.8180606365,-0.1478663832,-1.1388643980,-0.9242997169,1.6581678391,0.6156594157,-1.3556060791,1.0397180319,0.0057428153,-1.0736074448,-0.1493596137,0.0751666129,0.4852134883,-0.0637846664,1.2028560638,0.0310445186,-0.1631756276,0.5054315925,-0.6068215966,-0.7260636687,0.9337012172,0.4490439594,0.9612168074,-0.4713724256,0.0757001787,-1.2501882315,0.0985274091,-0.0683198124,1.4502435923,0.1849096119,-0.7560486197,-1.8285669088,0.6093274951,0.0586636290,0.2028598487,0.6563054323,-0.5652397871,2.2766592503,-0.9085285068,0.6356878877,0.5116490126,-1.5929365158,0.1327019781,0.1812831610,1.7507266998,0.9238305688,1.8036668301,0.2698839903,-0.1360591203,-1.8491562605,-1.5269157887,-1.4091269970,-0.4059423804,1.1683697701,0.3950791955,-0.3730430007,0.9432966709,-0.4507664144,2.1472918987,0.4739236236,1.6310644150,0.4206609130,-1.5757130384,-0.9026260376,1.4252194166,1.0862905979,-0.5142824650,0.9228453636,-0.9622536302,0.5519937873,-0.0327038616,1.2062320709,-0.1808272600,-1.4194060564,0.9631287456,-0.6597050428,-1.0749583244,1.4704674482,1.8247721195,-0.7203150988,-1.0254713297,1.4141848087,3.0542407036,-1.0799494982,-0.6734762192,-0.1547389776,0.8099894524,-0.0583977439,-1.0075556040,-1.7363808155,-0.2186141759,2.6054716110,-0.3520674407,-1.4125469923,-0.9866930842,-0.3136315644,0.2758622169,-0.0382532291,-0.2909025848,-1.2334349155,-0.6941742301,0.4460225999,-0.3344380558,0.2541289926,-0.7754428387,0.6982194781,-0.1970705390,-0.4232169390,-0.2842783928,-2.1254146099,-1.6987265348,0.8912936449,0.0369419828,-0.4753980041,0.9474012852,-1.1694549322,0.0957721621,-1.9647138119,0.8450680971,-1.0638986826,-1.7959105968,1.0335805416,-1.0350733995,1.3430973291,0.5613515377,-1.3858976364,0.2772824168,0.2037287652,-0.4732226133,-0.9405746460,0.7366333008,1.3613336086,0.0208984539,0.4093787372,0.0871815830,-2.0470230579,-0.6185591817,0.5369277000,-0.9558705091,0.4795728326,-1.9930492640,1.2474435568,0.0068958555,1.5790319443,1.0980535746,-0.0637846440,-0.5902965665,-0.0061245328,2.0637385845,-0.5407064557,-0.8410700560,-0.3185648620,-0.3438983560,-2.0251550674,0.1584590971,-0.4653836489,0.4902653098,1.1586868763,-0.6380576491,-0.3382273018,0.1718517691,1.8048999310,-0.6133977771,1.1827590466,-0.4546300471,0.5546512604,-1.0758531094,0.3262319863,-1.6125426292,1.1405082941,0.9962644577,-0.3908626735,0.2542061508,-0.5308600664,0.8220796585,1.4729973078,0.6980400681,1.9615049362,1.2876982689,0.2182829082,2.1297807693,-1.1058113575,-0.8929600120,-1.6870913506,-0.9594828486,1.6345727444,-0.2234487683,0.2769846916,-0.4827255011,0.6188679338,-0.7529045343,-1.8513833284,-0.5449662209,-0.2289349586,-0.2275588512,0.1584722102,-0.9139913321,-0.4197747111,0.9362422228,0.8670089245,-0.0218320917,-0.1137257963,0.8240271807,-1.0934950113,-0.1945286244,0.8003533483,-0.2396968752,1.1544240713,0.1843745708,1.8148233891,-1.2879664898,-0.2209738046,0.8045834899,-0.0956563428,-0.5216675401,0.0386822708,-0.0084566763,0.7532719970,-0.5548394322,-1.2596553564,0.6709458232,0.5227302909,0.3640642464,-0.4185277820,-0.2747395933,-1.3535087109,-0.7166903019,-0.4688091278,-0.7064665556,0.1297899634,0.4820433259,1.6228344440,-0.0645888969,1.1060124636,1.3474090099,-0.0167565756,0.1718845665,-0.7142949700,-1.5984379053,-1.3632293940,0.4917477965,0.2064529210,0.7901336551,0.8137999773,0.7803962827,-1.1908946037,0.7658921480,0.2878961563,-0.4552826583,-0.0192807633,0.2585481405,-0.1401580274,0.4660041928,-0.2457492054,-1.0530674458,-0.1534679681,-1.4978170395,0.5043719411,0.1542381793,-0.5338128805,-0.3461004198,0.1491215080,0.7485570908,-0.0845168531,-0.2989161909,-1.5050033331,-0.2240383327,0.1300648153,0.3475236297,-0.1500207782,0.6453188062,0.0438788645,0.6376432776,-0.5648962855,0.6896584034,2.0232799053,-1.0980631113,-0.1578527689,1.0964521170,0.6350690722,1.6230158806,-1.2539564371,-1.8732732534,0.2195006907,-1.4115343094,-0.3199668527,0.5239178538,-1.4737608433,-0.8933182955,-1.3867191076,0.1345203072,-1.0216890574,0.9537410736,-0.4129306376,-0.2612096369,-2.0409665108,-0.0334131494,-0.0334027857,0.9169976711,-0.7904871702,1.2259902954,1.1751644611,-0.4285097718,0.5169038773,-1.4336477518,-0.8526900411,0.4836533964,0.5627523661,1.2323125601,1.4806730747,0.8469880223,0.4425852597,-0.9853484035,0.0293111708,-1.5114089251,0.9939314127,-0.5136312246,1.8423138857,-0.3224902153,1.3486384153,0.1608252227,2.3281126022,0.3682502508,0.8500390053,-1.2086205482,1.6425739527,1.6567891836,2.5163788795,-0.5516718030,-0.7090018392,0.5536077619,0.1044385284,0.5848913193,-0.5738294125,-1.1334881783,0.4964465499,-0.4429698884,-0.5444251299,-0.0184476022,1.0488680601,-1.3786221743,-1.3408986330,-0.8560641408,-2.0122303963,2.1372659206,0.5076947212,-0.9105145335,1.0034862757,-0.5493667722,0.8107016683,0.5115770698,1.4349923134,-0.2621361017,-0.8416423202,-0.3985565901,1.4450401068,-0.5568643212,-1.9461606741,0.1166291758,-0.0909571052,0.7195361853,0.2246374786,-0.6057894230,-1.2935698032,-0.3281378448,0.0623177253,2.6832988262,-0.9763700366,-0.1302705854,-0.4990547597,0.0406178869,-0.7492877841,0.0462367646,0.1370660067,0.9836137891,-1.3005661964,-0.3430009186,-1.6979012489,-0.6472293139,-0.5646333098,0.3106422722,-0.9889423251,-1.7156691551,0.6313973069,-1.9979158640,0.3836011887,-0.3882793784,-1.7840440273,0.7430712581,0.7994744778,-1.2537626028,1.3493068218,-1.0350950956,-1.1018353701,-1.8689471483,-1.4032249451,0.1971910149,-0.4794034660,0.2162466347,1.1728647947,0.2414074838,-1.8751955032,-0.6058746576,0.3895087242,-0.3630200624,-0.7610980868,-1.3947130442,0.3746354878,-0.7805181742,-0.8008945584,-1.1045049429,-0.8625071049,0.2624949515,-0.8144610524,-1.1403104067,-1.4325137138,-1.2969572544,1.1078927517,1.2386733294,-1.0097072124,0.4666787088,-1.9054232836,-0.3379438221,-0.9478093982,-0.1815164536,-2.1254286766,0.3806206882,0.3613242805,-0.3807277381,0.6509169936,-1.1140364408,-1.6195075512,0.1372729540,0.8177353144,-1.6663779020,1.6164512634,0.5298832655,-0.6429971457,0.4450341761,-0.3613208830,0.4252066314,-0.3191341460,-0.6303688884,-0.6494750381,0.3941224813,0.7792255282,-0.7178655267,0.5349315405,-0.3798153996,-0.3439167440,0.6115089655,0.8245086074,0.1483690888,0.8659130931,-0.4422810674,0.2366063893,-0.8263459802,-0.2544108331,0.7105622292,1.2936662436,-0.0061172731,-1.3991149664,-0.2684777379,0.5478208065,-0.5861970782,1.2108368874,1.2831014395,2.4623322487,1.7803323269,0.0805140138,-0.1960275471,0.0362248681,-0.1431263834,0.4654183090,-0.7120475769,-1.4517489672,-0.3825183213,0.3767770827,-0.2440060675,0.2647753358,-0.5264542103,-0.1851858348,-0.5366991758,1.2142837048,0.0382215828,0.2983546853,-1.3661375046,0.6581992507,-0.3689630628,-1.1523690224,0.2207235843,-0.3588210046,-0.5084909201,0.4237173200,-0.2514657378,-1.4737418890,0.3986872733,1.4346228838,-0.6114665866,-0.0471816361,0.7091511488,-1.2037036419,-1.2475736141,-0.2429477423,0.0104824426,0.9887840152,-0.5232872367,-0.6540614367,2.9717705250,-0.8098665476,-1.2220925093,0.6366750002,0.3437053561,0.2384938598,-1.5848807096,0.1682298779,0.7390740514,-1.1523597240,0.5150222182,0.2875719666,-0.3649416268,0.5651715398,-1.4896733761,0.8772756457,-1.3336732388,-0.7780230045,1.8497377634,0.2610572875,0.7758993506,0.0206704233,-1.0282015800,3.1966378689,0.2818923295,-1.2109206915,-0.8321417570,-1.3174719810,1.2380001545,-0.2314254940,-0.8635729551,-0.1830273271,-0.8175476193,-0.4133780003,-1.5508835316,0.1624538600,-1.0400195122,-0.2823365629,-0.7531560659,-2.6896286011,-2.2430329323,-0.0545572713,0.1620842814,-0.1392417997,-1.0881642103,-0.2334382683,1.0073410273,0.9778640866,0.0852946490,-0.3693783879,-1.1538172960,0.9188566208,-1.2099559307,-0.6782140732,-0.1138747409,-0.4954129457,-0.7024160624,0.1558332443,-0.1858649552,1.5633962154,0.2435840368,0.2163445055,-1.9303464890,-0.4743229151,-0.9498266578,0.3237558603,-0.2460615784,-0.4553605020,-0.7298208475,-0.3582246900,2.1175317764,-0.8765597939,0.5634529591,0.0625522062,-0.9692933559,1.1842176914,0.4230535030,0.4874381721,-0.5687189102,1.8937847614,-0.1945808977,1.4794397354,-1.3262608051,-0.8606801033,0.2191320211,0.7188069820,0.0009182103,0.6576800942,0.8063944578,0.8810168505,-0.5035043359,-0.7760851979,0.1666544825,0.1153337806,-0.8356602192,-0.5901991129,-0.3215951622,-0.9975553751,-0.6187186241,0.2700315416,1.2824653387,-0.1581376642,-2.1533644199,-0.7170999646,-0.6648142934,0.2680378854,-0.4821653366,0.0698350668,0.6788092852,1.2517094612,0.0046356483,0.0086138453,-0.6417683959,-2.4156284332,-0.4155599475,-0.6338680983,0.7500723004,-0.5130292773,0.5746928453,-0.1184019148,-0.2648290098,-2.0818395615,-0.7137652040,-0.9739657044,0.7537212372,0.2535819113,0.6169744730,-1.4554769993,0.3506465554,0.7433042526,1.3686823845,1.4085261822,0.9369397163,-1.1510248184,-0.8294801116,-3.0858607292,1.1538147926,-1.0315407515,0.4071751833,-2.3339128494,-2.4373297691,-1.5677690506,0.5979134440,0.9495761991,-1.1302498579,1.5698679686,-0.0112411575,-0.4865964055,-0.6322322488,2.2198269367,-0.1834526360,-1.1265172958,1.3004908562,-0.8718284965,-1.0175803900,0.1230721474,1.2845140696,-0.3991899788,-1.1820335388,-1.5773611069,-1.8915426731,1.0482774973,0.4631630778,0.5453273654,-1.2216370106,-1.2610167265,0.3723307848,-0.7056763768,0.5499272943,-1.4075728655,-0.2471286952,-0.1996609718,-0.6414245367,-2.0822985172,1.0572780371,-0.2430976778,0.9677157402,0.2788408399,-0.0577941090,0.6746733189,-0.7687827945,0.1710018367,0.2308249325,-1.4008908272,-1.5655425787,-2.2899365425,1.1975847483,0.7657328844,-1.6059250832,0.6931754947,0.6015011668,-1.5637310743,-0.3585254550,1.7346768379,-0.4272238016,0.6572923064,0.7208228707,0.4170411229,1.6985064745,-0.6069838405,0.1985742748,1.3401014805,0.1548866481,1.1064743996,1.3651067019,-1.2938311100,0.1128372401,0.4152404964,1.8631957769,0.6998057961,-0.7854279280,0.7744868994,1.1030099392,-0.6815320849,-0.6766694188,0.7262734175,0.1705344319,1.5088578463,-1.4776148796,-0.0586480461,1.1006953716,0.7420361638,1.6587747335,0.1205245256,-0.0020093988,2.2212829590,1.0334048271,0.7167780995,0.7675334811,-0.4229756892,-1.8542928696,-0.1795200706,-0.3950515389,-0.1793856621,0.2677515745,-0.2145903558,0.9883928895,0.6095905304,0.8403566480,-2.7272720337,-2.5840220451,0.4287470877,-0.8445891142,0.5398139358,0.1210710034,0.9378256798,-0.3317985833,-1.0996099710,0.0415950157,-0.3239310086,0.3395366967,0.6336280704,0.7191601396,-0.7759758234,0.1708994955,3.4803307056,-0.9206820726,-0.4048551321,-1.0755497217,-0.8828337789,-0.5957428217,-2.1283802986,-0.5010408759,0.4380800128,0.1451422721,0.0548269637,0.7946581244,1.5738191605,0.4238313138,1.1378115416,-2.3402349949,0.2621157765,-0.5924669504,0.6416893601,-0.0999486968,0.0793482810,1.2093353271,0.6182104349,-0.1222885475,1.1483215094,-1.2530092001,0.8336417675,-0.5853553414,-0.8618545532,-1.0123625994,-0.2709977627,1.1808912754,1.0666790009,-0.5410199761,0.2418011427,-0.0650454462,-1.3687447309,0.6643924713,1.2235996723,-1.2306170464,-0.3710289299,-2.3630490303,-0.0823582411,-1.3592556715,-0.0260777790,0.4334647059,0.2359000891,-1.6590589285,-0.6708953977,1.0374119282,0.5894627571,0.1390295923,0.4612559378,-1.1581498384,-0.6379216313,-0.5233878493,0.2453523725,-0.6686667204,-0.2729541361,0.0582876019,-0.1641405523,2.6693544388,-0.7174984813,1.1088682413,0.5329573154,0.0444557518,-0.5908399820,1.7005236149,-0.1409078687,-1.1669863462,0.6829881668,-0.1745918244,0.2864745855,-1.8335051537,0.4798454344,0.3556045294,0.5267731547,0.4601722360,0.5871078372,-0.0579544082,-1.0574859381,0.9699077010,-0.1474561393,0.9218323827,-1.1894884109,-0.6066743135,-0.8240451217,0.6136225462,0.6406924725,-1.2699052095,-0.7971712947,0.7746338248,-0.9440367222,-0.0133051872,-0.3265692890,-1.1451457739,-2.6992063522,-1.1471670866,1.6526821852,-0.1636654586,-0.7557908297,1.0712401867,0.9058020711,0.6016139388,-1.8284126520,1.7088695765,-0.1438959986,0.9743440151,1.1755664349,-0.6853446364,-0.9805140495,-0.7326768041,0.6781848669,-0.9718044400,-1.4187847376,1.5915788412,1.6385931969,0.6819905043,0.9449669123,-2.1971836090,0.6113591194,-1.1820850372,-0.3689990342,1.5513277054,-0.5906776786,-0.4767121673,0.8203312755,1.0888025761,1.1581448317,-1.5558147430,-1.1395241022,0.8870739341,0.1858982444,0.2697058022,-0.9096365571,0.3069518507,1.2159620523,-0.2464475781,0.3862953186,-0.3224743903,0.2444050610,-0.6824684143,0.0999120772,-0.6802471280,-1.1838104725,0.5632140040,0.6371393204,1.0253103971,0.3471388221,-1.4211109877,-0.3159162104,-0.5746237636,-0.1463756412,0.5199471116,0.4381284118,-0.9439998269,-1.1170305014,-1.6122260094,1.5769633055,1.3907139301,1.1999559402,1.3022366762,-0.6340661645,-0.0995960012,-1.6399950981,-0.6119499803,0.1380764097,-0.6237627864,1.1016682386,-1.9356443882,0.5634610653,0.4649307132,0.5689449906,-0.6906414628,1.0428044796,-0.9816251993,-0.0944080576,0.9025543928,-0.9932280779,0.7247273922,-1.6060585976,0.6052199006,-0.0746025890,0.2692794502,0.0836235955,-0.6294842362,-0.2354930639,-0.3489116728,1.4909719229,2.2565157413,1.1001173258,0.1191658676,0.2973752916,-0.6802826524,0.4829027653,0.6770628691,-0.8792845607,-0.5022274852,0.4680658877,0.0524122715,1.2018536329,1.2017225027,0.2157837749,0.6835497022,-0.5031975508,-0.8575496674,-0.7981103063,-1.3048182726,-1.0906238556,-2.1067719460,0.2701582015,-0.1355769187,0.1928640008,0.7015531063,-0.2581508756,0.0451877564,0.8290317655,2.4921574593,0.6755216122,0.6239854097,1.9080717564,-0.2598963976,2.0262806416,0.6672372222,0.1927894354,-0.5935207009,1.2906221151,1.1303480864,1.8212866783,0.1627627015,-0.7681046128,-0.2628323734,-0.1882967800,-0.4641387463,1.1165431738,0.0123880208,1.1824625731,-0.5635791421,0.4094505906,0.5499470234,0.6730532646,1.1384918690,-0.0318734385,0.5249695778,0.9564266801,-0.1829735190,-0.8484261036,0.1849524081,-0.6116765738,0.4040069580,1.1256523132,1.3207218647,2.0485391617,0.2022244185,1.0597351789,1.2315956354,0.3742661178,1.4664480686,1.0261442661,0.9445564151,-0.7210229635,0.3330769539,1.1520477533,0.0342893526,-0.1105533689,-1.1973357201,-0.3417419195,0.8220157623,0.7772755027,-1.5686694384,1.6022686958,-1.6342042685,0.9400302172,-0.4801312387,0.1337077469,-0.0188103653,0.0742905065,-0.7465792298,-1.0140510798,1.7433282137,-0.2325217575,-0.2834181190,-0.8204702735,-1.2446351051,-0.2062532604,0.8481276631,0.8852192163,-0.8912778497,0.3083090186,-1.8603940010,0.3590204418,-0.1462968290,0.8163167238,1.3781898022,-0.5198218822,-0.6847628951,-0.8724231124,-0.2871099412,0.0967746899,-0.0191583131,0.5907481313,-1.5904307365,1.3970313072,-0.2175879031,0.7887555361,0.8525711894,0.9093270302,1.1224218607,-2.1383500099,0.8649312258,0.8823870420,-1.1048812866,-0.9562670588,-0.8385741711,-1.4619178772,-0.1579514742,-0.2121369094,1.2227568626,0.5742275119,0.0359639078,-4.6599531174,-0.0978555605,0.8772867918,0.9253914952,-1.5906937122,0.3186887503,0.7967299223,-1.0925660133,-0.1356026530,-2.7123830318,0.7223868966,-1.3690061569,-1.2025033236,0.7792565823,-1.1973105669,1.7177031040,0.0948203802,2.5072460175,-1.5663551092,-0.6132227182,0.1630306989,0.5378769636,0.5238105655,0.2860624492,-1.1264125109,0.1445035040,-0.5489215255,-0.3247438967,-1.3651691675,-0.6719406247,-0.3707260489,-0.8329691887,1.3739992380,1.4054895639,0.6142627597,0.3801291585,-1.9824923277,0.5518612266,-0.9396815300,-0.4278084040,0.0637271479,-0.8120394945,-0.5692890882,0.9053315520,-1.4505615234,0.7103596926,-1.2559800148,0.0491107069,2.4521374702,-0.9200552106,0.2403309941,0.0198677108,1.2498037815,1.2705478668,-0.3080240786,0.8807117343,-1.7154098749,-0.2565684021,0.1640652120,-1.4016714096,0.7097941637,1.9095629454,0.9995204806,-0.4326931834,-0.6567226648,0.1821094900,1.0034320354,-0.3981125355,2.0536632538,1.8618398905,1.3602993488,-0.4498952627,2.0644013882,0.9212067723,-0.2571714818,-0.3730241656,0.8073030710,1.3182489872,0.1169435158,1.3609436750,-0.1411994398,-0.1029899791,-1.9461628199,0.4719499946,-1.4018038511,1.0566523075,2.1330528259,-0.7859642506,0.0822543800,-1.3732144833,1.7473028898,-1.0639010668,-1.2659695148,0.2229897678,0.4247764647,0.4805686474,-0.8474889398,-0.3383961320,0.8022504449,-0.5559909344,-0.4041362405,-0.5135216713,-1.3163421154,-0.1205931008,1.5122067928,-0.0104675554,-0.2192304283,-0.1263844669,-1.1371041536,-0.5089555979,-0.1946117580,0.8600028753,0.0638399795,-3.5213615894,1.0045546293,0.5567478538,-0.6885315180,-1.4055252075,-0.3676231802,-2.9203844070,-1.1243324280,-0.3046654463,-0.7170249820,-0.6134189367,1.1806969643,-0.0221272781,1.1801662445,0.3245626092,-0.2887108624,-2.0269603729,-1.4936410189,0.1252851188,0.5235942602,0.7694662213,0.1733997315,1.3879876137,0.9336732030,-0.2111702561,-1.0503019094,-2.0826382637,1.4609395266,-0.0856881514,-1.7071745396,-1.1867042780,2.1376116276,0.8348627687,0.2069842666,1.7539217472,0.3535583615,-1.8743047714,-0.0553962588,0.8481658697,-0.9995617270,0.3901985884,0.1343593001,1.6648913622,1.2137875557,0.3217611909,1.4884146452,0.1555677801,1.0586683750,-0.0288448110,-1.7163136005,-0.4568204582,0.6596849561,0.3663463891,-1.0010029078,0.6994525790,-1.2128429413,-0.5362828374,1.0057533979,-1.0551908016,-0.5448315740,-0.3002343476,0.2546850741,-0.2694426477,-1.7030316591,-0.8511922359,0.4108665884,0.8940765262,0.4596008062,-2.0727031231,-1.5894145966,0.6068012118,-1.3510271311,0.8960603476,-0.6474032998,0.2486500740,-1.2714422941,-0.0038882706,-1.2690234184,-0.7396576405,-0.0264970679,-0.3070549965,0.3133223951,-0.0787381977,0.8041164279,0.2555361092,-1.9416064024,-0.9758633375,1.1594858170,0.6093669534,0.9097701311,-1.1062548161,0.8592962623,-0.2846635282,0.6063728333,-0.2664417028,0.3516781628,-0.0238830093,0.6255849004,-0.7902545333,-2.0264768600,-1.1567298174,0.1229565144,0.0750426725,0.3840484023,0.6105062366,1.4286056757,1.5390007496,0.0215927530,-0.6384230852,-0.0326580927,-0.4754877985,-0.0593326017,0.2306943089,-1.5714039803,0.2333770394,1.1175312996,-0.4276227057,-0.2300469875,-0.7984775901,0.5063858032,0.7095662355,0.0707808509,0.3261324763,-0.5166196227,0.7755348086,1.4209582806,0.4472828507,1.5131568909,-0.5091314912,-0.1463637352,-1.2307108641,0.8167770505,-0.8237021565,1.6269707680,-1.3415946960,0.0487488285,-0.8004634380,-0.6269339323,1.8451014757,0.4949062467,-1.3215615749,0.6344664693,0.2089666575,-0.4782479703,0.3076966107,-1.6594357491,1.3730232716,-0.2208669931,-0.5210494995,0.2851623893,0.8996701241,-2.5622427464,-0.0674514249,0.0234192368,1.0144755840,-0.9546979070,0.8461613655,-0.0649054199,-0.6372078061,1.3974251747,0.3746976852,0.7681015730,0.2594341636,1.7057238817,0.1613429636,0.0854009017,-0.8134281635,0.9436557889,-0.9423817396,0.5801091790,0.1318775266,-0.2848078012,0.1335559636,0.5876556635,-0.3178980350,-0.0128314896,0.0865386352,0.3319094777,-0.2248116732,0.0240327138,0.6187692881,0.3574542105,0.9088279009,0.0697148070,0.4406653047,-0.1967163235,-0.4700434208,-2.1740925312,-0.3500843346,0.1516977102,0.2233592272,0.2852753103,0.6240082383,0.1125972867,0.3403343856,-1.4563639164,0.3733136654,2.1346266270,-0.9266167879,0.3932163715,-2.0109872818,-0.0350480564,0.5640030503,-0.3578226268,0.1307384968,-0.2989596725,-0.7109010220,1.3044710159,0.4014618695,-0.5151721239,-0.0912843123,-0.8773889542,0.3478965759,-1.0700992346,-1.2515821457,0.6234746575,0.5236243606,-1.6252604723,-1.2834419012,-1.0935277939,1.0660840273,1.4242330790,0.1721225530,-0.4695689976,0.3664133847,1.7772021294,-0.9540381432,1.0367292166,-2.3827981949,-0.3921341002,-0.5850293636,-0.2167987227,1.3427859545,0.6053371429,-0.6285265088,0.3417230546,1.3946480751,-0.3851041198,-0.5210492015,-0.8341775537,1.8781659603,0.4993408620,0.9196839929,1.4708603621,-1.3287057877,-1.8750246763,-0.6538562179,-0.4436583817,0.3147097826,-0.2363654673,-1.1563998461,-0.7322943807,-0.8094955087,0.1966855228,1.8921687603,0.1011165977,1.0714277029,-1.1122522354,-0.8491483927,1.0026543140,-1.8699041605,0.4910463989,-1.3007510900,-0.7558706999,-1.2062203884,-1.3015846014,2.2981455326,-0.3842036724,-0.4086307585,-0.5081439614,1.0238132477,-0.0232919119,-0.7040374875,-0.6754306555,-0.5368385911,0.4415324926,-0.2231244147,1.5856546164,0.3726929724,-0.8339967728,-0.3401282132,0.4355895817,0.4122020900,0.5042055845,-1.2808250189,-0.3089379668,0.2095138282,-0.9887799621,0.5872370601,-0.4417540729,-1.7355332375,1.5637019873,1.1506174803,0.0401921943,0.8149108887,1.6987164021,-1.0433235168,-0.4187589586,0.3610968888,-1.5596761703,-0.3735758960,0.2021843344,0.6289901733,0.8797625899,0.5344867110,0.1503546983,-0.7813857198,0.2976354361,0.7332540154,-0.7058255076,0.0368137881,0.3777216375,-0.5616474748,0.0333609879,0.7632266283,-1.1654425859,-0.4225851893,-0.4182069302,-1.7396740913,1.2583700418,-1.4786802530,0.2079833299,-0.6789172888,2.0099575520,0.2491786927,-1.5300163031,-0.3059594631,-1.3193536997,1.9566799402,0.6859662533,0.2039905638,0.1241332442,-0.0059582829,0.4895803034,-2.1932377815,0.4535388052,-1.3756812811,-0.7140263915,0.5834588408,-0.4265936911,-0.7711508870,-0.0634818077,-2.0736818314,0.4877722561,0.7690168023,-2.2140629292,-0.1235852242,-0.7416536808,1.1636881828,0.7511378527,-0.1915588677,-0.6453274488,-0.4290712178,-0.7228347063,-1.0105632544,-0.5159531832,-0.4688208699,0.6070471406,0.2960442603,0.7811290622,1.2193843126,-0.7364284992,-0.5761831999,0.0020575896,-0.4753360450,-1.2325395346,2.1083066463,0.3523429036,-0.9894808531,0.4212930799,-0.3872063458,-0.7398980260,0.6265519857,1.1915148497,0.5910297632,0.9382076859,-1.6488192081,0.9358170629,-0.0788703635,-0.7320182323,0.4131195545,-0.6173188090,-0.5903555155,-0.2789388299,-0.1472140253,-1.2764873505,-0.1217904240,1.2791328430,-0.6618398428,0.6625029445,0.5320830345,-0.4551331699,-0.5017670989,1.8236455917,0.6914116740,0.3026286960,0.1815621406,0.2498879433,-1.2506207228,-0.0442353934,-0.1216291115,0.5298925638,-1.5443810225,-0.4020614624,-0.0662033781,-0.0818239599,-1.4185363054,-1.3683942556,-0.0888589248,1.7211959362,-0.3998090625,0.0440240912,0.6941738129,-0.0163219403,-0.2769297659,0.3046324849,-0.2503691316,-0.3313120604,0.2744653523,-1.2622573376,-0.2323275506,0.0178010147,-0.8282309175,1.0964192152,0.2451598942,1.5029834509,-1.4286749363,0.5833849907,0.5235205889,1.7843471766,0.3572329283,-1.2430522442,-0.5951647162,1.7783439159,-0.9175342321,1.5678970814,1.7504197359,1.7831438780,-0.7279756069,0.4373401701,-1.2401688099,0.0116553763,0.0059235734,-1.5822329521,0.4546556175,-1.1685270071,0.2259088755,-0.5036152601,-0.4659640491,0.0927771181,2.4530568123,0.6292487979,1.6537941694,0.3002971411,0.3096996248,-0.6645023823,-1.5523566008,-0.4031520486,-1.6061965227,2.7819669247,-1.0583498478,-0.1395788193,-0.1203634888,0.1022626758,0.8720859885,1.4830600023,-0.4962566197,1.0328984261,0.3373303413,2.3986284733,0.1229605749,0.6004591584,-0.7395074964,1.4079188108,-0.0688579455,-0.2888651490,0.0585243143,0.7603533268,-0.7401866913,-0.6543632150,1.1241512299,1.3855564594,0.2501965463,-0.0244971812,0.7574801445,1.2781273127,1.5284435749,0.6185496449,0.5040275455,-0.2804699838,0.1216544211,-0.6845163703,0.7941741347,-0.0366092920,-0.6983697414,-1.8522673845,0.2542896867,-3.2831485271,0.3953566849,-0.5015579462,0.6498671174,-1.1276022196,1.1505984068,0.1903680265,-1.2231880426,-0.6573792100,-0.4833384156,-0.4638567567,1.3860788345,-0.6521995068,0.1385852545,0.3805219531,0.1140052676,-2.4107685089,0.8874932528,1.6550575495,-0.3197214603,-1.3988662958,0.4590135515,-0.2101721168,0.4094855785,-0.9342734218,0.6102930903,-0.0219919235,0.8110104799,-0.1327028722,-0.5929984450,0.0896767303,-1.4792257547,-0.6357883811,-0.1910596639,-2.4750189781,-0.5322038531,0.5241442919,-0.6994981766,0.8529137373,-0.4903007746,-0.8817639351,-1.3482192755,-0.0317793489,1.2985696793,-0.3465938270,-0.5808402896,0.0075849593,-0.7275836468,0.8141966462,0.4521128833,0.2785006464,1.8277621269,-0.5190520287,-0.8914665580,0.2689761817,-0.9662404656,-0.6470789313,0.2914797664,-0.8155297637,-1.3739093542,-2.3848102093,-1.1209721565,-0.8182407618,-0.1182447374,-0.3398118019,0.4466997087,0.2464601994,1.0585348606,-0.2261178344,-1.3365659714,-2.1779890060,-2.3538610935,0.9866024256,0.8527196050,-1.0528454781,-0.8125745654,-0.3296542466,-1.1564801931,0.7735942602,0.9443894625,-1.1332502365,0.3197281063,0.2241103351,-1.9744640589,-0.9417819977,-0.2481104732,0.3611280024,0.8934960365,-1.1568579674,-0.5745681524,0.0709185824,-0.2200739235,-1.0778328180,-0.1161477938,-0.0324398316,-0.4999149740,-1.7372184992,-0.0684553757,-0.8528540730,-0.5410062075,1.1508429050,-0.1721008271,0.1344915330,-0.5637725592,-0.3995460272,-0.6501408219,0.9465684295,1.9391757250,-0.5684672594,1.5173685551,-0.6282674074,-0.9417642951,0.0144041413,0.0889731869,-0.2330531925,0.2974446118,1.2360913754,0.1447630525,-0.7290937901,-0.7561873198,1.1870754957,0.2414626628,0.2983992696,0.7458506227,2.1857104301,0.8399736285,0.7549082041,0.7326828837,-0.0318742953,-0.6576696038,0.0198269822,-0.6515598297,-0.4805519581,0.6991463900,2.2100965977,-1.7864370346,-0.6630361676,-1.1771378517,-0.6534810662,0.4054700434,-0.6601068974,-0.7464119792,0.2744610012,1.6158492565,-1.7060116529,0.2919547558,0.1256903559,-0.7018199563,0.2004989535,0.3009130657,0.8931428790,-1.2528479099,-0.9481801987,0.7718013525,-0.8815566301,-1.0193971395,0.0920027643,-0.7858209014,0.9181225896,-0.7570737600,-0.0542134568,1.0911778212,-1.1670839787,-0.3656161427,0.6322442293,2.5866792202,-0.9024486542,-0.1006447151,0.0434250124,-0.6026551723,-0.7511234283,-2.1465878487,-1.3147332668,-1.0441503525,1.6845152378,-0.9341364503,-0.3411107957,-1.7455786467,-0.5735567212,-0.3543936908,0.8459254503,-0.0149782002,1.0783048868,-1.4044744968,-0.5981349349,0.7644030452,-0.2567512095,-0.4749291241,0.3467444479,-0.0457928218,0.3171402514,-0.3241792321,-2.8057308197,0.9024006128,-0.5445762277,0.9712939262,0.4558846056,-0.1432908773,0.1366594285,0.5268583298,0.4409561157,0.3136016130,0.3074067235,-0.5648976564,-0.8228408098,-0.9566798806,-0.9248560071,-0.2933781147,1.1406354904,0.9162472486,-0.0694442838,-1.0854730606,0.4244476855,-1.0796084404,-1.1030313969,1.4148253202,-0.4556069970,1.4371075630,0.0990088806,-0.7168421745,-1.4504446983,-0.2324653566,0.7561825514,0.1022730097,0.6021108031,-1.4685246944,-1.6902762651,-0.9539712071,-2.0895330906,0.4726255536,-0.4029881656,0.0007847449,-0.1372971684,-0.0785327554,-0.7824497223,0.3144697845,0.9834409952,-1.3111101389,0.1794102639,-0.5454942584,-1.2275632620,-1.1055543423,0.1894212812,-1.2745862007,0.3700563610,-0.0895574987,0.1387081742,-0.1900572032,-0.8278012872,-0.2102169394,-1.1714949608,1.8205448389,0.1352094561,1.0171357393,-0.7764116526,-0.9255347848,0.3677875102,-0.1336479634,1.0903134346,-0.5522167683,-0.1727647781,2.1905345917,0.0677361563,0.0585403368,-0.5572353601,-2.4835076332,-1.2631917000,-0.9267233014,-0.3717812896,-0.2926731408,0.0466216952,-0.7515469790,-0.5927543640,1.4340451956,0.3440235853,-0.4755963087,0.3029372394,0.4228192568,0.8591195941,0.9187337160,-0.9696948528,-0.8918405771,-0.7458072305,-0.3890754282,-0.7237933278,0.2729220390,0.5538294315,1.1950474977,-0.1350257993,-0.0628644973,-1.0330879688,0.8075287938,0.4006544948,-1.5620900393,-0.2522285283,-0.7478344440,-0.7600804567,-2.5066511631,0.2466514409,0.6960947514,0.8043972850,-0.7229521275,1.8516392708,-0.5131801367,1.9044151306,0.7484899163,0.3236445189,-0.2882115245,0.7676124573,-0.3992791474,1.0807728767,-0.6194197536,0.1106903628,1.4164921045,-0.4014247060,-0.8979519010,1.2561978102,0.4640975296,1.9639859200,-1.8645833731,0.4402790070,0.2453724444,-0.8920995593,-0.2342789471,0.9694778919,-1.5542093515,0.4818401933,1.1038746834,0.0457208902,-0.3195508420,-0.1857536137,-0.5587615967,0.2741684318,1.5274512768,-3.0374977589,-0.5423014760,-0.0150344083,-0.6761445403,-1.0511331558,-0.4787085354,0.2322977632,0.5701154470,2.6077516079,1.5823068619,-0.4669645429,0.9781920910,-0.9199672341,-0.1703516096,0.4301041663,0.7154524922,0.4585685730,-0.8489269614,1.4372155666,0.8874803185,-0.1794517487,-0.0144406203,1.2646210194,-2.9158418179,0.4403441846,-1.3688344955,0.8333687186,0.5244902968,0.2989941537,0.9304910898,0.6709625721,0.9794834852,1.3098096848,-1.1596137285,-0.8816054463,-0.5656709075,0.9917655587,0.4784300923,-0.5290926695,-1.1244556904,0.3402399421,-0.8361654282,1.4321713448,0.8068723083,2.2013251781,-0.1939378530,-0.4361837804,0.3527769744,-0.8224888444,0.2225948572,-0.0207322240,0.1455113739,-1.2164512873,0.0929658487,-1.1042196751,1.4114979506,-0.6173691750,1.9363077879,1.2560794353,-2.7780065536,0.7533286214,1.3619881868,1.1684308052,-0.8395903707,1.9072697163,0.4078255296,-0.2256548852,-0.5843978524,0.0805882514,1.6368948221,1.3414212465,-0.6055875421,-1.0454299450,1.3621159792,-0.2686824799,-0.0739303008,0.5343942642,-1.3068132401,0.9384565353,-0.3994387090,0.4542995989,0.7322161198,0.7305169106,-0.5614368320,1.1140637398,0.6526744962,-0.0719099790,0.9098330736,1.7640006542,0.4237023890,-0.6691291928,0.5890297890,-1.9160044193,-1.0037022829,0.9969838262,0.8288206458,0.7137361765,0.4376760721,-0.3152429163,-0.1279374659,0.3058860302,2.4879970551,-1.6800762415,1.3998795748,0.1315685362,-1.5002568960,-0.2054777592,-0.5640303493,1.3824599981,-1.5066652298,-0.1466574669,0.0915420279,-1.5763106346,0.3803360164,0.3596437871,1.6621896029,-2.0491542816,0.5765722990,0.1055285856,-0.6198460460,0.1618170589,-0.2169940472,-1.3427215815,2.0164062977,-0.1058017090,0.1578689814,-0.2270162851,-1.2023625374,0.1935603917,-1.2298405170,0.8036319017,0.4344801307,0.8951734900,-1.2423279285,1.8490303755,-1.7592107058,-0.0522167459,-0.4019152522,-0.5006610751,-0.3094775975,-1.4385825396,-1.0389883518,0.1763581932,-2.0889842510,-1.5009762049,-1.7347135544,-0.5499082804,-0.4091817141,-0.5084925890,-1.7259931564,1.1904336214,1.4008835554,-0.7470872998,-1.3493409157,0.7245262265,-1.4676628113,0.5550032258,0.9892581105,0.4554331899,-0.9375141263,0.2234862894,1.4883899689,-1.2857881784,0.6532883048,0.4550784528,-0.4044540226,1.1459242105,-1.0726145506,1.7762796879,0.6335772276,2.1317172050,0.0332975127,0.5179934502,-0.0992914513,-0.7737841010,-1.8695286512,-0.7923610806,0.1761527956,-0.7032017708,0.5412458181,-0.9078052640,0.4937606454,1.1527210474,1.1989228725,-1.6906565428,-0.6281328201,0.2278220356,0.4933513403,-1.0064896345,-0.0000735259,-0.8934984803,0.1968393624,0.6673569083,-0.5315707326,0.3909243643,-2.2143652439,0.9027023315,1.4943727255,0.9048801661,0.2294406146,0.9573911428,-1.2223769426,0.1271428764,-0.4152106047,1.0905336142,1.6445459127,-1.5889605284,0.1431340277,1.3259994984,1.2536746264,0.8460054398,0.7108342648,-0.1171533167,-0.7995001078,0.7147882581,1.0996558666,-0.8065167665,1.5425846577,-1.9306179285,-0.5112408996,1.7824292183,-0.3771158457,-0.5927338004,1.0465234518,0.9517975450,0.8834025264,1.7332577705,0.4638868272,-1.2697304487,-0.1591738909,-1.7999488115,-0.9415250421,-0.1269199103,-0.0580913350,-1.2965680361,2.1223971844,0.0455871597,0.2907867432,-0.3369020820,-0.6078436971,-1.5405783653,-0.1512064636,-0.6500342488,1.2631211281,1.0848257542,-1.4378325939,1.8252682686,-0.3971527517,-0.4756045938,-0.8820447326,-0.0112926476,1.2548937798,-0.6723657846,-1.2332930565,-1.6561949253,-0.4634982944,-0.6589117050,-0.8096425533,-0.0774505436,-0.9581915140,-1.0015362501,0.3436736166,-0.7924914956,0.4270743132,1.6997318268,0.1629018933,2.6756398678,-1.3755729198,1.0998866558,1.8532304764,-0.2589176893,-1.5839751959,1.2968481779,0.1454011351,1.0266642570,-0.9606741071,0.2631573379,-0.6971349716,-0.7989433408,0.6325493455,0.5290307403,-0.8914008141,-1.4983018637,0.1810698956,-0.0936394185,0.7586063147,-1.2714086771,-0.1377002895,2.1368517876,0.0857330486,-0.9389966726,1.3523417711,1.9735085964,1.8241761923,-1.9587459564,0.3082878888,-1.1944063902,-0.4493401945,1.2215254307,0.1729801297,-0.0349820703,1.2029552460,0.5404530764,-0.0075979042,-1.0764358044,-0.7699571252,1.1834006310,0.5547564626,0.9156490564,-0.9856804609,-0.2785350978,-0.5186696053,1.3056958914,1.0631380081,0.1274959594,-0.2401805520,0.1479017437,-0.0582404770,-0.0790114775,1.0718803406,0.7031837702,-1.9135128260,0.3803895712,0.5894224644,-0.2192968726,-0.6255428195,-0.6426970959,-0.9397515059,0.5840689540,1.3284479380,1.3117339611,-1.5271680355,-0.3960041106,0.6294850707,2.4824326038,-0.9239836931,-0.5315219164,-1.0664471388,-1.2447993755,0.5901226997,0.2070456147,0.9431948662,-1.0233124495,0.6501449943,-0.0389963426,-0.1377603114,-0.1678514928,-1.2874910831,-1.5522481203,0.8630752563,-0.3618498445,-0.2759974897,-0.8493277431,1.7580159903,0.9600577354,-1.8509514332,-0.9705380201,1.6187961102,2.1266665459,0.0816572905,-0.4026440084,-1.1554012299,-0.2847146988,0.2674738467,-0.8082942367,-0.8134348392,1.1221520901,0.0270938650,-2.2677624226,-0.9180805683,0.2363503575,0.2875520289,0.8363741636,-0.0643644705,-1.5559432507,1.6432741880,0.5946225524,0.4202830791,0.0109968660,0.6184870005,-0.4283002019,-0.3038954735,0.2131291479,0.0461715311,1.5333558321,1.9102970362,0.0692449957,1.0393091440,0.1182040423,-0.7626225352,0.6060833931,-0.4008977413,-0.5854520202,-1.5112763643,0.9768438339,1.2555006742,0.3712321520,0.3047838807,0.5041245818,0.1352996081,0.6537587643,-0.1001813114,-0.8632913828,-0.7738704681,-0.8903281093,0.0303989761,-1.5796298981,-1.8807632923,0.4715923071,0.7007640600,-0.4200832248,-0.6220460534,-0.0537967421,0.6815012693,-1.2996648550,0.7641907334,0.1130914018,0.3476420939,0.8941524029,0.0757900104,1.6656370163,0.4651370049,0.7107572556,-2.1352045536,0.9271841049,1.3995282650,-1.4733744860,0.3333723545,1.2920279503,-0.0935617089,-1.4775958061,-2.2185895443,-1.0155769587,-0.0170312412,0.4430365562,-0.0669785142,2.0955364704,-1.2891235352,-0.3313333094,0.1508097947,-1.0214672089,0.6050590277,-0.3226830959,-0.6393830776,-0.7354826927,0.5948662162,0.0514817126,-0.3487473130,0.2998561263,-2.3917312622,1.9389803410,1.3662700653,-0.2757565379,-0.3776474595,0.0289556049,0.4271129966,-1.4703136683,-0.8241951466,-0.9340753555,-0.0965261236,-0.3129947484,-2.1099956036,-0.4961585999,-0.6232930422,-0.4650352299,0.9700036645,-0.1744728535,1.5180350542,0.6357852817,-0.2957075536,-0.7334786654,0.3546252549,0.1438398659,0.0114881210,2.3138237000,0.6166037321,0.5094236135,0.2026752681,-0.8440943360,-0.5575982928,0.3867180049,0.9236090779,0.2406300455,0.9912159443,0.5896103978,0.3247047365,-0.0631345809,-0.8472291231,0.4703036845,0.5695025325,0.1397066861,-0.2487258315,1.1258966923,-1.0027259588,-1.0338441133,1.1072216034,-0.7892639637,1.6951647997,0.1438161433,0.0723784938,1.4623792171,0.6937738061,0.0695512146,2.1728897095,-0.3971661031,1.0819935799,0.3043802977,1.4986712933,0.6935018301,0.5144372582,-0.7089034915,2.0252778530,2.0352370739,-0.5140570402,-0.4385772347,0.1052131802,0.7070764899,1.1298842430,0.9526279569,-0.3403368294,0.3679586947,-0.5590703487,0.5506619811,-1.2554082870,0.9212560058,0.3789348006,0.4162181020,0.8884142041,0.8954343796,1.3765288591,0.1669536531,2.1947975159,-1.0765970945,-0.4415110648,-0.8056438565,-0.5395519137,1.4391063452,-1.0550506115,-0.3433833122,-0.7339180708,-0.5391919017,-0.2920258939,2.4956951141,1.7541620731,0.3999114931,-0.5657392144,-1.4513942003,0.0673754513,1.3311697245,-0.9032511711,-1.1899926662,0.9078088403,-0.5799974799,-1.0377428532,-0.6368058324,0.3528950512,0.4219335318,-0.1826667786,-0.5943683386,2.2517185211,0.7124376297,-0.5504871011,-0.8670164347,-0.2532586455,-0.9611055851,0.5109337568,-0.9788072705,0.7710443735,0.0522208549,-0.1642433405,-0.2398169041,1.0718778372,-0.2769748271,0.8341576457,-0.9128410220,0.6022919416,-1.1872302294,0.5882807374,-0.7837983370,0.0029770739,0.9149373174,-0.0023518181,-0.3423418403,-0.2342749983,-0.2588711977,0.5861242414,0.2901591957,-1.9919506311,-0.5077320933,-1.0557484627,-1.3903524876,-0.8617141247,1.8194987774,1.4909827709,1.1573592424,-3.5810458660,-0.9443206787,-0.6563444734,-1.9958139658,-0.4275041521,-1.9974306822,1.0515087843,1.4036556482,-0.8239413500,-0.2179917097,0.8843204975,0.4367180169,-0.9152120352,0.5092750192,-0.4325858355,-0.2898980379,0.1608916968,0.0433968008,0.7225730419,-2.3706922531,-0.1152571887,-0.2443416417,-1.7064037323,-2.2502951622,0.9623617530,-0.9202928543,0.5554278493,1.4936690331,-0.8538382649,0.4118251801,0.4199622273,1.0834783316,0.7692968249,0.9061453938,-1.7944680452,-1.6934518814,1.0800925493,2.9148349762,-0.6273124814,-1.0704936981,-1.0964157581,1.2692940235,-0.0670206621,0.4683865309,-0.2278233916,-1.6969687939,-0.1294624507,1.3910541534,-0.8832511306,-0.5370650291,-2.7819578648,1.0052194595,0.0291601941,0.1069035754,0.1541337669,0.4313090146,-0.0532100685,-0.2221809328,-1.2927292585,2.0467059612,0.6717846990,-1.4643356800,-0.5161830783,0.8706104755,-0.7400351763,1.7521550655,0.7392818332,1.1075246334,-0.9495987296,-0.2971502244,-1.7795100212,-0.3664148152,0.3774253428,-0.3637647033,1.0382292271,0.9270262718,0.9909930229,0.4617742598,-1.7854360342,1.1072719097,-0.4553121328,-0.1896470487,0.7345716357,-0.1584715992,0.1256743520,-0.4396451116,1.7899280787,0.4290977120,-1.1429880857,0.1356596798,0.2704877853,-2.9028491974,0.2635847330,-0.2302935719,1.4411734343,0.7899709344,0.7097681165,-0.1670908928,-1.1633665562,0.8314404488,-0.5223177075,-0.6025066376,-1.0426368713,-1.0971044302,0.0751154199,-0.0060958047,0.5358031988,-0.3496257663,0.1946886927,-1.0601308346,-0.3055567741,0.7915786505,-0.6497223377,0.1561425328,0.0680144206,0.1885385960,-0.0341186747,-0.0913931131,3.2813217640,0.7469103336,-0.7709512115,-0.6652572155,0.6616647243,0.8398932219,0.1677317768,0.2261482328,0.5642980337,-0.9490278363,-0.4119906127,0.8089081645,2.3489282131,0.0059719253,0.1277764440,0.4831945300,-0.1986074001,1.3758893013,0.9559911489,-0.3276863098,-1.9237053394,-0.0273960028,1.2066987753,0.5038545132,2.0547614098,-1.0013649464,-1.2404457331,-1.6175206900,-1.8106907606,-2.2587397099,1.4911020994,0.5077068210,0.1578625590,-0.2871367633,0.2982170880,0.2387153804,-0.8506680131,0.7121008039,0.2630681098,-0.4266733825,-1.2599084377,0.1100775227,-0.7961258292,0.0884582102,-0.4036722779,0.2554541230,-0.7653817534,1.2740881443,-0.9017828703,1.0660438538,0.2381526232,1.3428379297,-0.9337721467,0.5818094611,0.6203938723,0.5277485847,-1.3358016014,-1.0161755085,-0.3920041919,-0.3217634261,0.0977156609,-0.7099808455,-2.1828842163,-0.2492626160,0.5232057571,0.6404082179,-2.8672451973,0.0099505708,0.0627208427,0.5408713222,-0.8533446193,-1.0616909266,2.1865887642,0.7885946631,1.6995860338,0.8987043500,-1.2937207222,-1.3201901913,-0.3269158304,-0.5847586989,1.1706972122,-0.3119771183,-0.8133928776,2.2317814827,-0.0656682402,-1.2794408798,0.7121872902,0.6827929616,-0.9849511385,0.2409691066,1.4361633062,0.8795505762,-0.1011779606,-0.3517198861,-1.3311268091,0.0398764387,-2.5397872925,0.5240123272,-1.1318515539,0.1736470163,2.3500032425,-1.0210710764,-0.9013856053,1.2843419313,0.1951693445,0.2922241092,-0.9190829396,1.3920661211,0.3929746747,-0.2270657122,-0.0221442040,0.5061912537,-0.7442373633,-0.3657039106,-0.6952665448,0.6621089578,-0.1160282418,1.0427018404,-0.4019634724,0.3994499743,1.1279504299,0.1322755814,0.0824102312,0.1473124176,0.7525485158,1.3919463158,0.9325844646,-0.2164360136,-2.0686099529,-0.3924939334,-0.2780714035,0.0101592699,0.6358350515,-1.4313091040,-1.1910624504,-2.2517459393,0.1745254099,1.0222985744,1.6670593023,0.5249434710,-0.1815162599,1.8214089870,-1.4406580925,-0.9919193387,-0.5310760140,0.2919684052,-1.6313235760,0.3511316478,-0.9309894443,1.1974879503,-1.6794967651,-0.8118848205,-0.8416833878,2.4623873234,0.3009655476,-1.4257361889,0.6312994361,2.2594048977,0.6614672542,0.9749627113,-0.8439388275,-0.6263849735,1.0214941502,1.8435775042,-0.7835627198,-0.5893369317,0.9996767044,-1.7351483107,0.5586682558,-0.9594988823,1.1005119085,0.2692739367,-1.0257135630,-0.7306185961,-0.3707855940,1.0002390146,1.7818371058,0.2506727278,-0.1208279952,0.7990749478,0.4406612515,-2.7838218212,0.3292020559,-1.1683198214,-0.7424931526,-1.6718312502,-2.2292375565,-1.5895670652,-2.1763262749,0.6465926170,-0.2387440056,-1.2814507484,1.5724308491,-0.0866635591,0.3556214273,-1.5556114912,2.2516131401,-0.0788190961,-0.9873566628,-0.5010582209,0.5617690086,-1.3074728251,-0.6975981593,-0.2382981330,-0.8825020194,-0.3499997556,0.8037531972,0.2698097825,1.4658676386,0.8141592145,0.6054009795,0.7439873219,-0.9993648529,0.3399610519,2.7317314148,-1.0810840130,0.1323891431,0.3207344413,-0.6511629224,0.3457941711,-0.7831311226,-0.9879703522,0.3776917756,0.8772977591,-1.7880016565,0.2965702415,-0.9034597278,1.7864934206,0.9782868624,-0.2956964970,0.6477823257,0.0506903753,0.5080415606,-1.3493453264,0.2018167675,-1.4426267147,-1.1808420420,1.0383150578,0.9860555530,1.8076187372,-2.0575242043,-0.6333572268,-0.2041875720,-0.9048840404,-1.3473826647,-0.2191231549,-0.5989145041,-0.9193871617,0.7825738788,-0.6629906893,-0.0044529312,0.4017296731,0.5302216411,-0.6302867532,0.1900966913,0.1169983447,0.6267263889,0.2086966336,-0.3434092402,-0.0818031728,0.2871176302,1.8508354425,-0.4121738076,-0.3695137501,-0.8422460556,1.0362706184,-1.5687952042,1.3191411495,-1.4238070250,-0.1425267160,0.1950446665,-0.0501813479,-0.9971384406,0.5666148663,-0.7734076381,2.1213474274,1.0192799568,-0.2502143681,-2.5300765038,-0.1859777421,-0.5562409759,-2.1014626026,-1.5545033216,-1.9805938005,-0.3614606857,1.0864875317,-0.6382172108,-0.1713171601,1.4588235617,-0.1968735009,0.3457186520,-1.2535402775,-0.4798072278,-0.5499140024,-0.6521920562,0.0745719150,-1.3990981579,1.5811384916,0.9943895936,0.8224885464,-0.9130792618,0.6656284928,0.4408087134,-1.0863834620,1.6354051828,-0.1830042750,2.0229175091,0.9130825400,-0.7718485594,0.5636826158,0.9207437038,0.6272261143,-0.0113689406,0.1329929233,-0.7101846933,0.7689437866,-1.1801084280,-0.2835783064,0.4113340974,0.5327725410,-0.7214313745,-1.5421614647,-1.9424954653,-1.6779434681,-0.0172744263,-0.5212426782,2.3069400787,0.4098668694,-0.3884662688,-1.4270358086,-0.4474042058,0.0626090840,-0.6908984780,1.6261773109,-1.3247954845,-0.9704781771,-0.8681657314,-1.9094009399,0.7300789952,0.0771100372,-1.2461156845,0.3015325367,0.3156217039,-0.0172931459,-0.4923977852,0.8767017722,-1.7975519896,-1.3432596922,-0.1768195033,0.2010150999,-0.0109114358,0.2074261457,-0.0014144401,1.3219326735,-0.1442534029,1.5599341393,0.5865324736,-1.0671136379,0.9432078600,-2.4022483826,-1.6965386868,-0.3520489037,-0.6729676127,-0.4498138726,-0.1366031319,2.2423534393,-0.6495697498,-0.6955966353,0.2690102160,0.0754883811,-0.2480758727,0.4548644722,-1.6006692648,2.9957056046,1.1254948378,0.1499847472,0.1920881867,-0.5768033862,0.2211746275,-0.2526126206,-1.2733937502,-2.1981089115,-0.1316194385,0.6110743880,-0.4321219325,-2.6817026138,-0.1910612583,0.9476387501,-0.9832076430,-1.1690601110,0.3118586838,0.1494942456,-0.0717568323,0.1027661785,1.6578212976,-0.4804956317,0.4835452437,0.1303046048,0.8426531553,-0.4875191748,1.4141306877,1.9516247511,-1.5209347010,0.1807358265,1.0086404085,0.1693771333,-0.6385271549,0.3150402606,0.2134657651,0.1275645643,-0.2692812979,-0.4176293314,-0.5310031176,-1.2867263556,0.4024953544,-0.6629074216,-0.8900157213,0.0173238255,-1.3357878923,-1.4739190340,1.2099581957,-0.8706635833,-1.1307188272,2.5382192135,-1.3760643005,-0.8997769356,0.0810065046,-0.9796665907,-1.9800330400,-1.3330463171,-0.0266266223,0.6131624579,0.7309258580,-0.4710527658,1.8186960220,1.0128185749,-0.2675081193,0.3097981215,-0.3390848637,1.3907425404,-0.1129092425,-0.1128220260,-0.7463982105,0.3480891287,0.1308476329,-0.8871914148,-1.1553707123,-0.8099475503,0.9398341179,0.6741917133,0.5551754832,2.3883841038,0.0637566000,-0.3006283641,1.7931590080,0.6349275708,0.0974078625,1.9796898365,0.9637216330,1.2067064047,2.6625752449,-2.9752113819,-0.2145902961,0.8895272017,-2.5124297142,-1.1934756041,0.6111067533,0.5439530611,0.9195749760,-0.0145593109,-0.1723228544,0.8032369018,-0.1235672086,0.8890910745,-0.5182160139,0.6868421435,1.3251487017,2.2621772289,-0.9907764196,1.2263659239,-0.7818847299,2.5534036160,0.0250207074,-0.6922243237,0.4500946105,0.8247621059,-1.5440511703,1.0582951307,0.9684923887,0.0219670925,-0.6095378995,0.2694644332,0.6649788022,-1.0967034101,-0.7213160992,1.1593426466,1.0333893299,-1.1508731842,0.6200610995,1.0737234354,-2.6945307255,1.0907959938,-0.4236430526,0.5467333794,0.3633519411,-1.4687079191,0.2660523951,0.4187117815,-0.2689535320,-0.7421191335,0.4190295637,-0.0754861236,-0.9021491408,1.7387038469,-1.0696322918,1.2910215855,-0.9210324287,-0.5588905215,1.5117577314,-0.7016773820,1.5223786831,1.0122696161,-0.4869149625,-2.6730711460,-0.4777221382,0.3872422874,0.1491771042,1.2386612892,0.1987817436,0.7457051277,1.2785915136,0.1476992965,0.2074522674,-0.4072807729,-0.5786799788,-3.3096375465,-0.6840371490,-0.8496714234,-1.0677458048,1.0516594648,0.3639971912,0.0243675150,-0.0318917781,-0.0292874929,0.4616909027,1.9434530735,1.6624674797,0.8748117685,2.0247778893,-1.5770218372,1.6974775791,0.7939242125,-0.1475799233,-0.4257296026,-0.9291113019,-0.1765965670,-0.9489408135,-1.0270024538,0.3457305431,-0.1267700195,-0.8588191271,0.0220551956,0.4580956995,-0.8898931146,0.6698141694,1.1612095833,1.5577360392,-0.0882073417,-0.1198285371,0.5890731215,-0.3089555502,-0.9081842303,-0.1492018104,-1.7106012106,-0.7759175897,-0.4991606772,2.0636332035,-1.2211964130,0.2082914710,-1.8170255423,0.1874208301,0.8306953311,0.1591050774,0.1346683651,0.5078101158,0.3186313212,0.0747938156,1.1232910156,1.1165424585,-1.5080624819,-1.8543579578,0.4946228862,-0.3128373027,-0.8260221481,-1.1768620014,2.7075240612,-0.8599362969,-0.1943347603,0.3728359938,1.5643889904,0.1224704236,-0.2554540038,-2.4267845154,-1.2763670683,0.1865660548,0.9339870214,2.1913509369,1.0479716063,0.5310890675,-0.4444085956,0.0102695441,-0.4931077957,-0.8591019511,0.3635742068,0.1819271296,1.4570590258,0.6254669428,-0.0766212940,0.7366033792,0.4073336720,0.3157582879,1.2674711943,1.5260124207,-0.1460522711,-0.6169248223,0.7802696228,-1.1895266771,-1.6959145069,1.0615260601,0.7290648818,-0.0039269542,-0.2192747742,-1.2065370083,-0.5926264524,0.4990629554,0.6350317001,0.2500172257,-0.7767462730,0.1204522327,-0.0855962262,-2.9598872662,-0.0594991967,0.0107230311,-0.6957206726,0.6268827319,0.8848359585,-1.0965247154,-0.3538480401,-0.2793050408,-0.6663282514,1.6578052044,0.9893534184,0.6942030787,-0.0255823508,-2.1172115803,0.8453764915,0.0800878629,-0.0446344092,-1.3436617851,-0.3629655540,0.7153369784,1.8806054592,0.5140509009,1.3209331036,-1.5869755745,0.0630695596,1.0406191349,-1.1759856939,0.7265060544,0.5853495598,-0.4912182987,-2.3420684338,0.2360036075,-0.0184030049,-0.2514174879,-0.5149710774,-0.9576873779,1.1475124359,-0.3164398074,-0.6195050478,0.9377791286,0.6614924073,-2.1293914318,-0.8671734333,1.8095625639,1.2773045301,0.7302829623,0.9080862403,0.4408243597,0.1983782947,-0.6720163822,-0.5482321978,0.1505797505,0.5328464508,-0.5543004274,-0.2349988371,0.3065464199,0.2317438871,-0.2143950164,-1.9504706860,0.3647886813,-0.9620810151,-0.5049009919,1.1725252867,-0.2122905999,-0.0769631341,-1.5674600601,0.1936446875,0.9210233688,-0.7128981352,-1.8007926941,0.3849214613,0.9164446592,-1.5944501162,0.4832324684,1.2739291191,0.3470695019,0.7192894220,-1.2342510223,-0.5707786679,0.3982577324,1.6125490665,0.8283737302,-0.4355474114,-0.5516900420,1.8830914497,1.4993001223,-0.4664620161,-0.6440277100,-0.1982753575,1.7335997820,0.7828823328,0.4520802200,-1.0521594286,0.6122381687,2.5034127235,-0.2546629012,-0.0021838548,-0.3127757013,-0.2439358383,2.8342952728,-1.1100224257,-1.8255298138,-0.2851569653,0.6020030379,-0.0797088295,2.1328616142,-1.2060884237,-1.0391825438,1.9026936293,1.5160888433,0.2516080439,-0.7265576124,0.6257002354,0.2562513053,0.3520869315,0.2826059759,0.7028957605,-1.1565545797,3.2492113113,0.6998537183,0.3435056210,0.0474957936,0.0238234904,1.0075225830,1.0553672314,-0.5581072569,1.4102920294,-0.8471719027,-0.3154569268,0.3686653078,0.3602911532,0.4066274166,-0.6914747953,-0.2434081584,0.1288081408,1.6579293013,1.3141508102,1.4821339846,-2.0403368473,0.6059473753,-1.0832898617,-1.4585893154,-0.3728159070,-1.8068834543,0.3847947121,0.5434930921,-0.3806275427,0.8868139982,1.4337956905,0.3013240099,0.3587332964,-1.2386696339,-0.8911620975,0.0859268382,1.1943483353,-0.6367681623,-0.6623798609,-0.2061398029,-0.5292823315,-1.5271534920,0.3254251480,-0.0908186063,-0.7286639810,1.3047002554,-0.0827621073,-0.1901878268,-1.0190961361,0.9524612427,1.5536764860,0.1080959290,0.7212635875,0.1993038505,-1.4570226669,-1.6779817343,0.3893408775,0.3303967416,1.0638159513,1.7132321596,0.8575462103,-1.6333636045,-0.4927726984,0.7085943222,-0.6649975181,-0.7540698051,0.3705411851,1.5952237844,-0.9408431649,0.8396894932,-0.0682655498,0.1102770716,-0.1911044121,-0.3837050498,0.1033612564,0.4805106521,1.1790075302,-0.3850603402,-1.5772523880,0.1418904960,0.2107743323,1.0745302439,-0.1163458973,-0.2989508212,-0.1717454642,-0.1741078496,-0.5722891092,-1.1931658983,-1.0240820646,1.3909329176,-0.5920624137,-1.3037887812,-0.4021603465,0.4387072921,-0.4330362976,1.8886967897,1.1421550512,-0.6339848638,-0.4418257177,0.3721695840,0.2701981068,1.3258050680,-0.5577306747,-0.0739254504,0.3768513799,0.4234072566,-0.5511019826,1.1147866249,2.3339898586,0.4122173786,-0.5530776381,0.3115015626,0.0289805699,1.5773285627,-1.2268995047,0.4624019861,1.0431036949,-0.2830632031,-0.6748375893,-0.0909511521,-0.0818173736,-0.7964636683,1.1432673931,-0.5838388205,-0.7343836427,0.8128823042,-1.9741328955,1.0655366182,-0.1382042468,-0.4833156466,-1.5031466484,0.0463636853,-1.9227097034,-0.6942155361,-0.0444220677,-2.9480149746,-1.3248479366,-0.7946349978,0.1203350052,-1.8178205490,-0.8409462571,0.0176582448,0.7654770017,-1.1241449118,1.0637383461,1.5732291937,-0.2002674639,-0.3629679680,-1.1078330278,0.3732503355,0.0650348887,1.0154954195,0.5308608413,0.8413332701,-0.8172613978,-1.2249294519,-0.1462770700,-0.8106113076,1.2757968903,0.8820825815,0.8402888775,1.7235717773,-0.2222751230,-0.4631427824,-2.0011272430,-1.3081351519,0.3727766871,0.2681252360,0.9854740500,-2.2283413410,-1.8407127857,-0.8173459172,-0.1097566634,-0.2490268350,0.0852077156,-1.7533066273,-0.0306593943,0.0494587459,-1.7486133575,1.0223621130,0.9939898849,0.8368474841,0.4449765682,-0.9100048542,0.1528287232,1.8625997305,0.2812252343,-0.4299602211,1.2618894577,0.4911216199,-0.2961321175,-0.3500322402,0.9766417146,-0.6072682738,-0.3793948293,-0.2228083014,0.7391654849,-1.3898029327,1.9329074621,-0.9888586998,-1.6468340158,1.3287822008,-0.4032287598,-0.6147022843,0.8088668585,0.2952104509,0.4654255807,0.4560590386,-1.1324355602,0.8947141171,0.4242992103,-0.7234010100,0.1395297050,-0.5978423953,-0.0356286205,0.9698703885,0.5998618007,1.1406219006,-0.3814889491,-0.9062640071,-0.4771881998,-0.2948560417,0.7076987028,-0.9771244526,-0.5480884910,-0.3703163564,-0.2734317183,1.2818864584,0.8690806031,-0.2168426067,-1.0013710260,0.3965295255,-1.3480749130,-1.3271099329,-0.3585632443,0.1892410517,0.3836632073,-0.3862533867,-0.1512429714,0.8624945879,-0.5295600295,0.9678261876,0.5995805264,0.8620498776,-1.7274713516,0.9354030490,0.8139658570,-0.8361479044,-0.1532518119,0.0936337113,-2.4775524139,-1.9780313969,0.2005530298,0.8046504259,1.7265368700,-1.1824663877,1.0006707907,0.2549159527,-0.5395684838,-1.3906004429,1.1599717140,-1.1941506863,-0.0242273454,1.0806976557,-0.6423122287,-1.7502503395,-0.0535725392,1.0014064312,0.3842054307,-0.9795367718,0.0303774159,-0.5324507952,-0.3401973248,-1.1212528944,0.0285949763,0.4956311285,-0.2267297208,-1.3515195847,0.4184161723,0.1721993089,0.7958292365,0.1263063103,0.2711284459,-0.2135034651,-0.7038419247,0.2187733203,-0.5362712145,0.1083598137,-0.2600317895,-1.2274924517,0.6941085458,-1.5299791098,0.4951930940,0.0788252577,1.3300241232,-0.9726471305,1.7447634935,0.7137358189,0.4610167146,-0.3599465191,-0.1522779316,1.7052100897,1.5464543104,-0.1919985265,-0.2842799425,0.6308130622,2.0006842613,0.4859058261,0.8829320073,-0.1657233387,-1.2302795649,-0.5572073460,-0.8428971171,-0.0465976670,-0.2116975784,-0.1333411336,-1.3210440874,-0.6006979942,-0.4126179218,0.0754443184,0.7098649144,-0.7600352168,-0.6254181862,-0.4199784398,-0.0825512707,-1.0666607618,1.6464910507,-1.1209568977,-0.7917913795,0.1129865870,0.0059932861,-0.4723086357,-0.2796922922,0.5758187175,0.9736551046,0.2789586484,-0.5730145574,-0.4830294251,-0.2489068210,-1.9525696039,-0.6475285292,-0.2628311813,-0.7734012008,0.8395585418,2.5376198292,-0.3365868330,0.5846264958,1.0598243475,-1.1626652479,0.0405477248,-0.9395235181,-0.2485307753,0.0545488633,-0.9857591391,2.4720458984,2.0487780571,-1.2066218853,-0.0878543928,0.9413759112,0.9323689938,-2.0413239002,0.2184711546,-1.9071009159,1.1700785160,0.5026462078,1.8074660301,-1.5341821909,-0.2498243898,-0.4873360395,-0.6551302075,0.8344846964,0.3601314127,-0.4684588313,1.2849541903,2.2285103798,-1.0161749125,-0.0508062355,0.7545269728,1.4866827726,-0.9345136285,0.7692088485,-2.3289158344,0.2548599243,0.2512003779,-0.9487016201,0.2089540064,-0.9035751224,1.4267714024,-1.0731743574,1.7076709270,1.2272638083,0.2197493315,-0.5237355232,-0.1973887086,-0.2108744830,-0.5565663576,-0.6995753050,-0.5322136283,0.3217452466,1.1632359028,-0.6271314025,0.3296809494,1.0473831892,0.4364182651,-1.3696779013,-0.2976042032,0.0399223492,0.7550673485,0.5357517600,0.4226417542,-0.0695470870,0.1780906320,-1.4290182590,-0.4919155836,-0.6635327339,-0.6278638244,1.0992287397,-1.2899185419,0.5348879695,-1.5645805597,-0.6093159318,1.9165036678,1.6862343550,1.2086102962,-0.5938796997,0.2510013580,1.5818654299,-0.0920653418,0.4793538153,0.4611625969,0.4175966382,-0.7902413011,1.3530526161,2.4345374107,-0.2522033453,-0.4852724969,-0.9632862210,-1.0252519846,-0.7647008300,2.6910192966,-0.3028256297,-0.1939556748,-0.6827206016,0.4865101576,-1.1748796701,0.9050163031,2.6230053902,0.1278017312,0.9562465549,1.0719659328,0.7716265917,-1.8127437830,-2.0730187893,0.2582882345,0.6441308260,1.4222255945,0.5335395932,0.4913542569,-1.1710500717,1.2177139521,0.6230660081,1.5083622932,2.5376482010,-1.0855648518,-1.1384391785,0.4204219878,-1.2163747549,1.5409317017,-1.7850402594,0.2881009877,-1.7824188471,-0.6656666398,0.2255385816,-0.2045584470,0.6886078715,0.4971415102,0.4256645739,-0.2858218849,-0.1442836076,0.8134331107,-1.1828783751,1.7522083521,2.3498823643,0.1647088081,1.1515992880,-0.7531849742,1.1517670155,-2.1913006306,0.9838366508,0.7988774180,1.2420282364,-0.3205684125,-0.0106539931,0.1312756538,-0.5737478733,0.6149320602,-1.3822107315,-0.3531156182,-0.5641967654,-1.1561065912,0.8050509691,-0.3803443015,-0.7108378410,-1.6383564472,-1.3067328930,0.8056710362,-0.9770047665,1.4766548872,-0.5168541670,0.3145562112,-1.1484050751,0.7664395571,0.0075045303,0.0210218653,0.5821520686,-0.0796812326,-1.5467196703,0.1330328286,0.9529478550,0.6269364357,-0.2962416112,0.4320018291,-0.5550686717,0.9274399877,1.1973664761,1.2910717726,-1.4917968512,0.0722649843,0.5383219123,-0.2111446708,-1.4312043190,0.1909869164,-0.2979548872,-0.1053253263,0.4545270801,-0.1573643684,-2.6192853451,0.3299501240,-0.7100323439,-0.5290266275,0.6963036060,1.0016850233,0.3713839650,-0.0537927784,0.5277480483,0.9580436945,-0.3080750406,0.5621162057,1.1065112352,-0.1435552835,-1.2238268852,-0.6453787088,-0.0446425751,2.3824806213,-0.3643109500,-0.8466729522,1.1849539280,-1.9625260830,-0.2382405549,-0.3108474314,0.7180377245,-0.2890521586,-1.0908354521,0.3532983065,-0.9382154346,0.5689409971,-0.3626126945,0.1292094141,-1.3126652241,-0.4163072109,-0.8589738607,-0.0338691622,-1.0064257383,0.1432997137,-1.2719420195,0.4668884873,-0.3053086400,-0.0977246687,0.2234309167,-0.0470772311,1.0469348431,-1.3022555113,-0.8693733811,-0.1281105727,0.8558647037,0.8242882490,1.8926994801,2.1205914021,-0.3344083428,0.7537657022,-0.1441276968,-0.7482367158,0.4418944120,0.0492459051,0.3857703805,0.6495937109,-0.9396342039,-2.2726123333,0.5253503323,-1.3726311922,0.7066520452,0.8941339850,1.0972421169,-1.2170317173,1.4726543427,1.2693320513,0.7312103510,-1.4249899387,-0.4283734262,-1.2901015282,1.9668451548,0.6691100001,-1.5574185848,0.4526828229,-0.8244184256,-0.4453442395,1.3221229315,-0.2892827392,0.2289659083,-1.0478963852,0.4761168361,-0.2551328838,-0.4333049655,-1.1237722635,0.8928756714,-1.5040786266,-0.9676579237,2.4354195595,0.2679666579,0.8277609944,0.3292419612,-0.1868321896,0.6399228573,0.0246101934,-0.5365167260,-2.2954347134,0.9310479164,-0.1232519746,-0.7564478517,-0.4085958004,1.0798666477,0.4010500014,-0.0367867351,1.1169235706,-0.9824579358,-0.0519333407,1.1601675749,-0.5204966664,-1.4007287025,0.3084657490,1.1606221199,-0.2109643072,0.4174713492,0.7629770041,0.9784686565,0.6438628435,1.3034147024,0.0565330721,-0.1181432754,0.2954445481,-0.0077796308,-2.3304641247,-0.6992905736,-0.1077904403,1.6501281261,-1.1473655701,-0.4608682096,0.0156514887,1.2672146559,0.4234745204,0.1822052300,0.4332121909,0.4516955316,0.7653177977,1.6070424318,1.0253183842,-0.2590387762,-1.0479173660,-1.6088930368,0.1823649406,-0.9678751826,-0.7864817977,-0.0212973952,0.5997629762,-1.3160744905,-0.9506019354,0.5000987053,-0.1930724084,-1.2007164955,-0.9722674489,-0.9011637568,0.9087528586,-1.0918318033,-0.0354075357,-1.4514678717,0.9590007663,0.6602175236,1.3757650852,-1.0226017237,-0.8164103627,-1.0483584404,0.3173210919,-0.4989819825,1.5050772429,-1.3538606167,-0.3477463424,-1.2884012461,0.5413200259,-0.0952065215,-2.5451941490,0.8496850729,-0.8102738857,0.3639152944,1.0038706064,0.8044942617,0.2769761086,-0.8043497801,-1.0582702160,0.9640245438,-0.9525019526,0.2505484223,1.7418069839,1.1239496469,-0.2312931418,0.5900598764,0.2988237441,-0.9258888364,-0.7468770742,0.6754369736,-1.1314466000,2.2557041645,0.3076329231,0.1141875535,-0.7910183668,0.9181339145,-0.2924492657,0.1954403967,-0.0891278759,0.9766722322,0.8747189045,-1.0259243250,0.6990704536,0.5039597154,-0.2485073507,-1.1559615135,-1.5401313305,-0.5223922729,0.7553474307,0.5209439993,2.2820031643,0.6241645813,0.1820227355,-0.8249456286,-1.0354923010,0.0518557951,0.6551367044,1.0242308378,1.2647337914,-0.3354948759,-0.8350704312,0.1489525437,0.8589512110,0.6270372272,-0.5417641401,-0.2549240887,-1.0517722368,-1.3470808268,1.7237402201,0.2793397903,1.0387977362,0.3658451438,1.7909607887,0.1156069040,-0.6626947522,-0.6802643538,-0.3461824656,-0.1924321353,1.7015250921,0.9053295851,0.1271467358,1.0843471289,-0.3697059751,-0.8226702809,0.3727995455,1.2557933331,1.3963470459,0.8964594007,-1.0065754652,1.3490592241,-0.2992320955,1.1706128120,1.8907653093,-1.7348724604,-0.1472353786,0.5626885891,0.1557893902,-1.5522532463,-0.7784453034,-1.1265046597,-0.5841084719,-0.3729529679,-1.0711065531,-0.4288546741,-1.5960400105,1.3952161074,1.3239439726,-2.5381610394,-1.0360237360,0.3437467515,-2.5755796432,0.0326888487,-0.2264865786,-0.7182295322,1.0793272257,-1.1627691984,1.3597364426,-0.2644090056,0.1385675967,-0.3974082470,1.2229468822,0.9545928240,-1.6005281210,0.4387021065,0.3070425093,-0.0559233315,1.7117067575,1.7901859283,1.9087609053,0.2534044385,-1.0119205713,-1.4722032547,0.5966674685,-1.1095695496,1.1928594112,0.0251557846,0.4326552749,-1.1571912766,-0.6874693632,-0.3447971344,0.3170865774,0.7671335340,-1.7947992086,-1.3456940651,-1.4110554457,0.1072896123,0.1770090908,1.9528205395,-0.5405386090,0.5682284236,0.6587491035,0.9563859701,1.0822306871,1.2021546364,0.7378921509,-0.5463986397,-1.7351492643,0.6233202815,-1.3622575998,-0.4995904863,1.4538668394,-0.5640485883,-0.4524624050,1.5386605263,-0.4490965605,-1.7440617085,1.1747021675,-0.8111938238,0.8217701912,-0.5931746364,1.0802215338,-0.2538038790,2.3748760223,0.1568471640,0.6048847437,0.1726618111,1.2744444609,-0.0180251598,1.1177147627,-0.4916356206,-0.3290631771,1.3595130444,1.1628024578,0.6827121973,-0.2205483317,-0.2955637276,0.6364265680,-1.0403375626,0.8137436509,-0.2903918028,0.2760030925,0.4262830317,2.0322773457,1.5663291216,0.3227753341,-0.0340636298,0.0319516100,-0.3528116345,-0.0407276042,-0.2693226039,1.4170272350,1.7600680590,0.7054511309,1.4845144749,-1.2117332220,0.8845197558,-0.4061044455,-2.0150425434,0.0858845934,-0.3021506965,0.2173276544,0.1497766674,1.0825449228,-0.5751865506,0.4710103273,-0.1027014628,-1.6194263697,-0.7232217193,-0.9368378520,-0.2567723989,0.2749138474,-0.6792963147,0.2497180104,-0.1856022477,-0.5589736700,0.4200106561,1.6372632980,-1.2062540054,0.7298827171,-2.3512728214,-0.7061026692,0.6459239721,0.9156780839,0.2385244370,0.7191008329,0.1381670535,0.2389231473,0.8946838975,0.8140711188,0.3687241673,-0.8611537218,-1.2541856766,0.6498557329,1.6523033381,-0.7426189780,-0.2608479857,1.2524713278,-0.7394489050,0.1951705813,-0.5104800463,-0.1717242897,-0.4723890722,0.0514790267,1.2266012430,0.6670045853,-0.2716105282,-1.6211389303,-0.7709470987,-0.4063224494,1.0450941324,0.6701294780,0.4660073519,-0.3111612499,0.4569470286,-0.3755842745,0.2935816944,-0.7299827933,-0.3773456812,-0.0588846505,0.5191531777,0.6253951788,0.5395801663,-1.1540787220,1.1528965235,-0.7550507188,-0.4361100197,-0.8517587185,-0.2650027573,-0.4558273852,-0.1218817607,-0.1632884443,-1.7337768078,-0.2454500645,-0.4841493666,-0.2076745182,0.9510493875,-0.1895506978,1.7178503275,-0.0648765713,-1.3134737015,0.0220830422,1.5550876856,1.1541197300,0.9463537931,0.8542752862,-0.3284910917,-1.6964749098,0.8325127959,0.5698849559,0.1683153063,0.4132466018,-0.4727652371,0.9073839188,0.3624867201,-0.5237817168,0.5296620727,-1.5915416479,0.7892110348,1.2042807341,-1.2157537937,-0.0659838766,-1.0977131128,1.8772678375,0.0199707374,-1.0153725147,0.9905872345,0.2679038346,-0.6155877709,1.6769979000,2.2211329937,1.2426955700,-1.1432538033,-1.3055896759,0.1563118249,1.5841238499,-2.2452995777,0.4084261954,2.3925390244,-1.5944696665,-0.2753798664,0.7038434148,-2.1634190083,1.5523954630,0.0431083739,-0.6386553645,0.1563305855,0.4483917058,-2.9002535343,-0.2124763727,1.2646445036,0.9671489596,0.1235830262,-0.6239078045,0.1781397164,-1.2477340698,-0.8786101341,0.0340745784,0.9605447650,0.3556161225,-3.0921344757,0.3453056216,-2.2019863129,1.5977934599,0.0587060228,-1.2354182005,-0.5321778059,-0.8846167326,1.3429207802,0.1889484078,-0.7125145197,-0.9847447276,-0.3402684927,-1.9771710634,1.4227645397,1.8663989305,-0.6787713170,0.0083999801,1.4120321274,-0.8796091676,-0.8530539870,-0.2235978842,0.7683705688,0.3531757891,-0.8423203230,0.8098526597,0.2967545092,0.1743304431,0.6617275476,1.5916795731,0.3336613774,-0.3279126287,-1.1561247110,0.8219054937,-0.0077004205,-0.0758062452,0.9670962691,-0.9370991588,0.1727723330,-1.0711120367,1.2559354305,0.6726061702,-0.1603709906,-1.5501614809,-0.0739242285,-0.6497949958,0.3207924664,-1.1628973484,0.4206815660,0.7446953654,-0.5787026882,-0.3373136222,1.4212529659,-1.6684862375,-0.1762335151,0.3530758023,0.4051634967,-1.2940163612,0.9606325030,0.4437426329,-0.2314557731,-0.0697056428,-0.2034419626,-0.7468641400,0.9059106112,1.1647446156,-0.9227508307,-0.7264728546,-0.7138158679,-0.7802699804,0.7355730534,-0.7290205956,0.5469813347,-0.7842488885,0.4940427542,-0.9318450689,0.3016936481,-1.1100772619,0.4054757953,-0.7490972877,0.5455661416,-2.0676968098,0.1622077972,1.2108730078,-0.5942135453,-2.1084134579,-0.3815261126,0.6267691255,1.2911912203,-1.4211307764,-0.0792804286,1.2469061613,-1.2400754690,-0.6282653809,0.6214656830,-1.9671771526,0.9299145937,-0.1225127801,-1.6832170486,0.3292508423,-0.6738933921,0.3709022999,1.6576431990,1.8432923555,0.1324210614,0.0297149438,-0.7616475224,-2.1235435009,0.1847538352,-0.5866488814,-1.1501641273,-0.1941118091,0.2461440712,-0.2032909393,1.0314236879,0.0010392868,-0.8659663796,-0.7367367148,-1.2445702553,0.5127481222,1.2003036737,-0.9545887113,0.3125925362,-1.1271697283,-0.0129429530,-0.7439265251,-0.2158260792,0.9935899973,0.6832865477,1.1826785803,-0.6790092587,-0.7337641716,-0.3919575214,1.2301563025,0.1421116590,-1.9185277224,-0.1422203928,0.0144021548,-1.2244794369,0.8910320997,0.8001833558,-0.6226376295,-1.9729691744,-0.3718367219,-0.6450943351,1.4727654457,0.4042130411,-0.2300358117,-0.1837593764,-0.3389971852,1.0521665812,-0.5878276825,0.8147978187,0.2012608349,0.5305464268,-0.0704385564,0.6780981421,-0.5457631946,-1.0154840946,0.3954752088,-0.8780980706,0.6862570643,-1.6729224920,0.8030760288,0.4177638292,0.5515066981,-0.8780927062,-0.3644495308,-0.7639865279,-0.2581588328,-0.0097340150,0.1328005195,-1.3428583145,-0.5613111258,0.0030085165,-0.2764977217,0.3225880861,1.0092039108,0.2349234968,-1.1569188833,0.3209208548,0.8061857224,0.9328452349,1.5121496916,1.4083685875,-0.7483514547,1.3963418007,-0.2169407457,-1.0577676296,0.2618527114,0.0820487142,0.2296931744,1.1636767387,-0.6497741342,-0.7683633566,0.3333502710,0.8443777561,1.1035634279,1.1778227091,0.9579150081,-0.8281220198,0.4982230663,-1.7778943777,-0.7316639423,-1.6550662518,0.1353182048,0.4598369896,-0.0059965760,0.6672404408,0.6366089582,0.3507957757,0.2280575633,0.5433624983,0.6431276202,1.0851905346,0.8459165096,1.2322151661,0.9934787750,0.1766625792,0.1074638367,-0.8066105247,1.8972502947,-0.6080517173,-0.4537470043,0.5049105287,-0.0842246264,0.8485350013,0.9383783340,-0.1987407804,2.5588440895,0.9118668437,-1.2429528236,0.4617349505,1.2518606186,0.6015286446,-0.4189657271,-0.3078119159,0.0632796735,1.3473374844,1.3317080736,0.8101310730,1.3187366724,-0.0723575279,-0.6994635463,0.8570897579,-1.5637105703,-0.2297752500,-1.2368377447,0.4984486699,-1.7071242332,-1.1083687544,0.0562235564,-0.4866240025,1.7403073311,0.0683723688,-1.6624240875,1.0369526148,0.4173009694,-0.9422541261,-0.3057643175,-0.0225711260,-2.3352799416,-1.2981127501,0.1158406734,-1.7067408562,-0.8495888710,-0.2003936023,-2.6660759449,-0.1373704821,1.8758572340,0.4224371314,-0.9995551705,0.7457840443,-0.6162922978,-0.6332775354,-0.3346899152,-1.7673785686,0.1534919441,0.5546674132,1.5832332373,0.0081346072,1.0892113447,0.9690399766,-0.3808458447,-1.3704863787,-1.2239551544,1.3384201527,-1.7577083111,-0.4571655095,-0.2167893350,0.2889954448,-1.5132929087,-0.0505164191,-1.0508286953,0.9178054333,-0.5142904520,0.6449629664,1.2783317566,0.0204112101,-0.9757503271,0.8718924522,1.2775079012,-0.8486067653,-0.7375156879,-0.8481579423,0.2910692394,-1.4055770636,-2.4370431900,-0.2421151698,-0.1659164876,0.0634354576,0.8462583423,-0.3317031562,-0.0410253853,0.8783381581,-2.0833046436,1.9415665865,-0.4809909165,0.9779080153,-0.1633502096,-1.0577044487,-1.0115772486,-0.9951361418,-0.8234838247,1.3299692869,-0.3004491925,-0.3629858494,-1.1682218313,0.0332856104,0.0584488660,0.5619188547,-1.4354987144,-0.6348283291,0.5653066039,-0.7393788099,0.4992229044,-0.8277471066,-0.8877035975,-0.4010598660,0.1966238767,1.2567228079,1.7160092592,0.6613878608,0.9422925115,0.6065798402,0.1258662939,0.1002879664,0.3995673954,0.5345766544,1.5022646189,-0.6795228720,1.2247700691,0.3355742097,-1.9241726398,-0.5274044275,0.3859989941,-0.1902812123,2.0812780857,-0.6521640420,-0.9521286488,-0.1160523742,1.2861061096,-0.9185868502,-0.0956847370,0.7666553259,0.0705903322,-0.9173219800,-0.6386165023,-0.2875458598,0.4759561718,-0.2991779745,1.0411814451,-0.2388623655,-1.9096094370,0.9282014966,0.1911507100,1.0705833435,-1.3557881117,1.5480512381,-0.0446682349,1.5442548990,-0.6466215253,0.8872923851,-1.2207497358,1.0928955078,1.7613279819,2.2592256069,0.0676627234,-1.4281723499,0.0194905587,-0.7902153730,-0.2634108365,1.2093659639,1.7138423920,0.4568839371,-2.7929172516,2.0279846191,1.9827568531,-0.3400610685,-2.5195252895,0.1077408493,1.2092367411,1.3849642277,0.4741785228,0.6720715165,-1.3682155609,1.3626445532,3.0927917957,0.2808203399,-0.0680369139,0.9278790355,-0.3832291663,-1.0694628954,-1.3236962557,0.2294029742,-0.1003467962,0.5837204456,1.4401695728,0.6600863934,-0.1587504148,-1.0510327816,2.8563518524,0.3107630312,0.0793141946,-0.7014832497,-2.2048156261,-0.1639941931,0.8510155678,0.8897792697,-0.2509429157,0.7656675577,-1.8384664059,-0.9290833473,0.8442848921,0.0714782104,0.7431453466,0.7526600957,-0.3000283539,-0.8917927146,0.3781193793,-0.8924313188,-0.7258448005,1.2255562544,0.4353717268,-1.0612089634,-1.0652147532,0.1068682298,1.5616360903,-0.5242556334,0.9643884897,0.7915732861,-0.3687317967,-1.5341099501,-0.6866817474,-0.0766677111,-0.5075598955,0.0492559411,-1.5805724859,0.4028103650,0.5294559002,-0.2617757022,-1.5436277390,-0.4214951396,0.7148287296,-0.7212103009,0.4432360232,-1.1655206680,-1.7276140451,1.6665664911,0.1276424825,-2.0064013004,2.2659885883,-1.1007127762,-1.7148460150,-0.9983851314,-0.1229355112,-1.5004343987,-1.0642398596,0.5147129297,-0.1959828287,1.0724027157,0.5129589438,0.2611027360,1.0203869343,1.8625689745,1.0872251987,0.1776206940,-0.6679985523,-2.3908557892,1.9265812635,-0.0750824064,-0.6875794530,-1.8375434875,-0.1266568005,0.4062012732,0.9031251669,-0.1045055613,-1.1981265545,-0.3047462404,0.7788920403,-0.5198747516,-3.0495319366,0.4344826937,0.5080818534,-0.0456377529,-0.6228168607,-0.3361916542,-0.4655468166,-0.8032031059,0.0986663103,-1.4225085974,-0.7214075327,-0.1927438825,-1.2750662565,0.3828608692,-0.2010356784,-0.3411757648,1.0567926168,0.8308400512,-0.3758359253,-1.7007135153,-1.0153723955,0.7814183831,1.3333725929,-0.0588039719,-0.1536338776,1.7262624502,0.5375443697,-1.4447143078,-1.0294841528,-1.0612380505,-0.1466866732,0.0248447470,1.2826215029,-0.6459833384,-1.5521104336,-0.7346411347,0.4375969768,-0.6678929329,0.2032340467,0.7792050838,-0.1258176714,-0.7511096597,-0.6474458575,0.2450655252,-0.9021635652,-0.5974918604,-1.1855431795,-0.8081023097,-0.3418832421,-0.0899530277,1.9315698147,0.0990892202,0.6180377007,-0.9881890416,0.7278859615,0.2622669935,1.4801809788,-0.4546771049,-1.0858519077,-1.0294415951,-1.2702590227,-0.2850361466,1.2038623095,0.4503741860,0.5454785228,-0.6018747687,0.4178525209,1.3235566616,-1.9712238312,-1.0972834826,1.2963863611,0.1940562278,-0.6993190646,0.1960473210,0.3936943710,-0.6680406928,0.2631404102,-0.0992291048,1.5811232328,0.5356354117,-0.0902978182,-0.2183861434,0.0835172236,0.2231216878,0.4585287869,-1.0632811785,0.2157344222,-0.7864517570,0.0688186809,-0.8122203946,0.9727475047,0.4813622832,0.9644367099,-0.0104756039,0.2411717325,0.3121369183,1.1740385294,-0.8667576909,0.3110567629,-0.4314704835,0.1743235737,0.5403572917,-0.6680797935,1.0002886057,1.6705429554,1.1789067984,0.5091510415,0.2972907722,-0.3430694044,-0.8662321568,1.3162040710,-1.8510755301,-0.4570961595,0.9468869567,0.5335932374,-3.9929611683,-1.1525392532,0.4048165977,-0.7148792148,-0.0899725407,1.1440914869,-0.5628069043,-1.5965940952,2.3284101486,-0.6404005289,-1.9125361443,-0.8831542730,0.5702723265,0.3274931014,-2.0143942833,0.5962705612,-0.2118565291,0.2940602303,1.0698854923,-0.7329437733,0.5447551608,-0.7397634983,0.8467305899,-0.5462845564,1.9932767153,-0.0706784353,2.3692502975,-0.4771787226,-1.3188631535,-2.1861901283,1.1592558622,-0.2879912555,1.3112417459,-0.1735279113,1.7638275623,-0.1482204646,-0.5775184035,1.6037025452,-0.2173911482,0.8606928587,-0.7163739204,0.5022127032,0.6795402765,0.7757351995,0.9296262860,2.1179580688,-0.1177830398,-0.6922940612,1.8955492973,-0.1037179306,0.8602941632,-1.3067930937,0.0278356988,-1.8676902056,0.8719504476,0.2133634984,-0.4246577621,0.2922644913,0.5142137408,0.7787869573,0.3955132365,-0.0308551546,-0.5254090428,-0.0208215415,0.5863494277,0.2410605252,0.2540073991,-0.0505717807,0.3257252574,0.0478928015,0.0124214934,1.1643067598,1.0866931677,0.1932839900,0.7468745708,-0.4936366081,-0.1967490166,-0.5898027420,-0.3114001453,1.2001738548,-1.1749259233,-3.6432943344,-0.7237185836,2.1023168564,0.3772802353,0.9598003626,0.6345593333,0.9760369062,0.5842297077,-0.4238112867,1.0510704517,1.4212644100,1.2052621841,1.1709578037,1.2481642962,0.1114866585,0.7139697671,-1.6507397890,-1.1089572906,1.0787169933,-2.2450892925,1.2657155991,1.0965223312,0.4065240622,0.4205618203,-0.1879614741,-0.6797156334,0.9142844677,0.0223195404,-1.9562933445,-2.0345225334,-0.3191227913,-0.6532308459,0.7075082064,0.8971603513,-0.2222088575,-0.7548856139,-0.8718494773,0.5969509482,0.4012758136,1.4944665432,-0.0430379659,-2.5413269997,0.2290947139,-1.7839071751,1.7898751497,0.9773983359,0.8138353229,0.3676052094,-0.4572495520,2.3534555435,1.7259155512,1.3094695807,-0.2298201919,-1.5486131907,-0.4831325114,-0.1515334994,1.1911811829,-0.1305567771,0.7306992412,-0.9365200996,-1.0807114840,-0.4267658591,-0.6438264847,0.4536756277,-0.4718679786,0.0732847527,0.9452646971,-1.5916801691,-0.0438594930,-1.6057710648,0.2780228853,0.1078691557,-0.4012733102,0.5433638096,-1.8002210855,0.0649706200,0.1245789826,0.8710531592,0.1115417033,-1.9357055426,-0.5548510551,1.2520089149,1.4839948416,-0.5209493041,-0.9624369144,0.8466321230,-0.5569323301,0.2157223821,0.0956537575,-1.0298379660,0.4497537911,0.1934795082,-1.4493902922,0.3130516708,-1.3260329962,-0.2592625022,-1.8027895689,0.5699852109,0.5679404140,-2.5769262314,0.9336313009,0.7585353851,-0.6365656853,-0.4001408815,0.9239498973,1.9906063080,1.4039293528,-0.5344263315,-1.6005463600,-1.1294572353,-0.6989622712,-1.0434752703,-1.8072863817,-0.2911771536,-0.3740274906,-0.2669128776,-0.6695302725,-1.0134661198,-1.7485753298,-0.2880801260,-0.0940565765,0.1530825347,1.2911791801,1.3317542076,1.1100609303,0.9411215782,0.6393887997,-1.3498729467,-0.1483654976,0.1755969822,-1.0591218472,-0.4806758165,0.0374209993,-0.2632440925,-0.2745012343,0.6968136430,-1.8665977716,-0.1406579614,0.7593407631,0.4745651782,-1.2644783258,0.6004345417,1.4316047430,-1.1685087681,0.2429454327,0.4121043384,-0.2837245464,0.0339051634,-0.4033333957,0.4898167849,-1.8071894646,-0.0860238522,0.3482603729,0.8476430774,1.7993699312,-0.4857821763,-0.9498022199,-0.0087727476,-0.9771353602,-0.8784105778,1.8610028028,0.4241184890,0.4889109433,-0.5960755348,-0.1157418191,0.2188333124,-0.9271811843,1.2049478292,-0.7487514615,-2.4948208332,2.3248777390,0.1948041320,-0.9396010637,-0.0695591941,1.1261837482,-1.4390196800,0.1074865907,0.2451537251,1.4741477966,-1.3714965582,1.4597207308,-0.2240107805,0.4680463374,-0.7798717618,-0.8509687781,-0.0445612594,1.0413498878,1.0824186802,-1.3900460005,0.8383417726,-0.5728988051,-0.7608184814,-1.4918603897,-1.1130791903,0.9705112576,-0.9052938819,0.0602722466,1.7449322939,1.3911231756,-0.2824020386,-0.0249941666,-1.8760643005,-1.9072006941,-0.2799922526,-0.4541512132,-0.3491178155,1.3265537024,0.3157596588,0.7349253297,-0.3306770921,-0.0793977678,-1.4547114372,-0.9750895500,2.5718612671,-0.4372460544,-0.3933745921,-0.2879850864,1.6932580471,-0.2667824626,-0.4276626110,-1.5534998178,0.5865116119,-1.1775484085,-0.3417048752,0.2226299047,0.8676363230,0.8768593073,0.4840772152,1.3084653616,1.7750610113,0.5020828843,0.8089952469,0.6637986302,0.2111792713,0.3420891464,-0.5921617746,0.2682724297,-0.4276701808,-1.0372554064,0.0703604743,-0.8647756577,0.5419068933,-1.7433658838,-0.3307072222,-0.5725274086,0.6627629995,-0.3101287186,0.5326774120,-0.7019532919,-0.8407902122,0.7224192023,-0.1563667655,-0.5524084568,-1.0491452217,-0.7639257908,-0.2581304610,-1.5388603210,-0.6796113849,0.8086640239,-0.1712522805,0.5022003651,1.1249178648,0.2038956285,0.1236568317,-1.4507499933,-0.4801124036,0.1786764115,-0.2940721810,0.9317100644,-0.3659346402,0.7731112838,-0.8082608581,-1.8103444576,-0.4421080351,-0.9311588407,-0.6190632582,-1.6836090088,0.6225354075,1.8004719019,-0.3675890863,-1.5402535200,0.5061526895,-0.7011044621,-0.2044154704,0.7838950157,0.6873581409,0.3003750443,0.2717193067,-0.7483507395,-0.2657977045,-1.1034845114,0.9093827009,-1.7455307245,0.2808555067,-0.6657431126,0.2908801436,-0.3246472478,0.1302491426,1.6909010410,-0.1852371842,-0.3363511562,-1.5134866238,2.3311779499,-0.0808570161,-1.1184997559,-0.1656611711,-0.2683204412,0.5825760961,-1.1025604010,-0.9419777393,-0.7417781949,-1.4885994196,0.1455330104,0.0818805471,1.8152869940,-0.3648020625,-1.0479524136,1.0624965429,-0.1902331710,-0.5713142157,0.6154579520,0.3105306625,1.3375319242,-1.4385323524,0.4703989625,-0.0446280465,0.2165392637,0.2389579415,-1.2069883347,-1.5069841146,2.8056120872,-0.4463079572,0.4630065858,0.3852918446,1.0595120192,-0.1924976408,-0.7959891558,0.5518957376,0.1073498875,2.0644276142,-1.3379882574,2.1439268589,0.0684103593,0.1015025824,-0.6148912311,0.0664112791,1.3932160139,0.1381065100,-0.4723600745,0.6620807052,-1.3079439402,-0.9490098953,1.5134844780,1.3218621016,-0.4307395518,-0.0436251275,-1.3971976042,-0.9197613597,-0.1284685731,0.9387473464,0.0908714011,-0.6960137486,0.8947666287,-0.4395277500,0.0078539103,0.0331664793,-0.4104016125,0.2590791285,2.3322181702,0.5433509350,0.3989716768,-2.2112383842,0.9127438068,1.0851579905,0.0210881140,1.1078456640,-0.0505299978,-0.5449906588,1.7212568521,-0.7205293179,0.1527352482,-0.5153023005,0.0899326950,-2.0822553635,0.7137017846,-0.6866122484,-0.3113394976,0.3766130805,-0.3086671531,-0.0307912417,0.9296104908,-0.0212098304,-0.7371267676,-0.3977877498,1.2362489700,1.0222923756,-0.5818612576,1.8817348480,1.1494332552,-0.0183267836,-1.1659201384,1.5057953596,2.7619345188,-0.7941793203,0.0287719052,-0.7107766271,-0.2424992919,1.6478064060,-0.6357446313,0.8620203137,0.1403571814,0.3091052175,0.2087818533,0.9582784176,1.2466231585,-0.0951789767,0.0370424651,0.0931980982,-0.0357219428,-0.9581607580,0.6691345572,1.4618363380,-0.9407261610,-0.1881764531,0.1779287457,0.2282896638,0.0024585791,0.9555747509,-0.0863538906,-1.6428929567,0.4155323207,-0.4702777863,1.0200219154,-1.0292131901,1.9110612869,-0.3506657481,0.3369286656,0.1099356636,-0.8530461192,-0.5134611726,1.2525533438,1.9823640585,0.8887806535,0.1952644587,-0.3287902176,0.6369973421,1.1657168865,-0.3110114336,1.9505547285,0.5987884402,-0.3918232918,0.1895684898,-0.8541156650,-0.1494368315,-0.9396588206,0.5325658917,1.4862364531,0.5386831760,1.0839402676,2.7512357235,1.0610109568,-0.3076118827,0.0839342251,-0.2132758647,-0.4443840086,1.1139613390,-0.5371167660,0.6878733635,0.6211798191,0.1295899898,-0.1400801837,0.3262644410,-1.6013503075,0.3448503315,-2.4370861053,0.0091410428,0.4318372011,2.4131960869,0.7610641718,-1.2417212725,-0.5548300147,0.2673580945,0.4718003273,1.0521353483,1.0287045240,-1.2894179821,-0.0358988978,1.2699348927,-0.1881172657,0.5786081553,0.3217543662,0.5109526515,0.6527564526,-0.1036807373,-0.8156668544,0.0486890860,-0.8705747724,0.0336206816,-0.1434892714,0.0206560418,-0.5102793574,0.0312600732,-0.0512645692,0.3963692784,-0.9462928772,1.7282290459,0.0291529056,1.6862194538,1.0479409695,-0.1493015438,-0.4607142508,0.7110564113,-0.7917346954,-0.3492127657,-0.1107221022,1.2990982533,0.0823019817,1.3518792391,1.6583864689,-0.5439693332,-2.4000995159,0.4834471345,0.2429045290,-0.3895867467,1.5748558044,-1.8866602182,0.5014733672,-1.0549618006,0.6886458993,-0.5591328740,1.7372102737,-1.0586389303,-0.7030788660,-1.7595483065,0.5768519640,1.0110862255,-1.0807354450,0.7039963007,0.2570515871,0.2202721834,0.3636488020,-0.0619608201,-0.4254122078,0.1702727824,0.2321278155,-0.2789296806,0.3148307204,-0.2219217718,-0.0343165696,-0.6693635583,-0.7482005358,0.3152418435,-0.6094266772,0.5564612746,1.0861303806,-0.3645062149,1.1158699989,0.7505072951,1.6706467867,0.9701129198,0.9791996479,-0.4747344851,0.8000352383,-0.8672477603,0.0212012902,0.1365957260,-1.9201898575,-0.6686220169,-0.2664861679,-0.7977192998,-0.1907032579,1.1660275459,-0.8042742610,0.9925575256,-1.2276042700,-0.7777420878,0.4423106909,-1.0314748287,-1.1646858454,-0.1148602143,-0.0822476819,1.2950305939,-0.1583028287,-0.3801110685,2.1181035042,1.1377567053,1.1714947224,-1.4710574150,0.4374298453,-0.3345782161,-0.2080748528,-0.4310014546,-0.3359941840,-0.6037350297,-0.4509580731,-0.2071041912,0.4953692853,-0.9209408760,-1.6250727177,1.3350207806,0.5784474015,-0.7418002486,-1.0781373978,-1.4611221552,0.8532691598,-0.2607238293,0.5639829636,-0.5600467324,-1.1986761093,1.9563639164,0.9690504670,0.2546267211,-0.3837289810,-1.2347412109,-0.1670784652,2.9372646809,0.8678464890,1.1291265488,1.5747507811,-1.6810820103,-0.2933495343,-0.6225114465,-0.3882344663,-1.3630297184,0.0092936410,-0.5639885068,0.2759515047,-0.2828184068,1.1528820992,1.1894996166,1.1782293320,1.7409573793,-0.3719946146,2.2909574509,3.0704162121,-0.9461196661,-0.2518333197,-0.6309245825,0.5706209540,-0.4163119495,-0.0939932466,-1.1150132418,-0.4613604546,0.0398271419,-0.2534232736,-1.9071460962,-1.8280466795,-0.4866101444,-1.3184527159,-1.4179421663,0.2209537029,-1.1249928474,-1.9038407803,-2.7663104534,0.6664661169,1.0175549984,0.1773152649,0.2420164049,1.5144679546,0.0260805730,0.3917195499,0.2187479883,-1.1952811480,0.0412240624,0.1335472763,-0.3340080678,0.0762820840,1.1268568039,-3.0501861572,-0.8245661259,1.7237170935,-2.8219740391,-1.8330252171,0.7809044719,-0.3621836007,1.7247868776,-0.1848417073,0.3827749491,0.8851286173,0.1156658381,2.0285098553,0.8909919262,-0.7913900018,-0.4023923874,1.4397592545,-0.2121118456,1.3215402365,-0.1021919549,-0.2679600120,-0.6018244028,0.0751775131,-0.2411542386,-0.8728830814,-0.7452493310,-0.9146154523,-0.3126709759,-0.0148961348,0.3722932041,1.4483546019,0.3125064075,-0.4321153164,-0.3628958166,1.5365076065,-0.4864256084,-0.4952484965,-0.4730603993,-1.5365190506,-0.7496447563,1.2180451155,-1.2079240084,0.6674391627,1.0864683390,-0.2232403457,-0.1725623906,-1.0300061703,0.8511503935,1.1540714502,0.2684497833,2.0633459091,1.5850899220,0.9936402440,-1.7767057419,0.2575030923,-0.2837025225,0.9801308513,0.0955806598,-1.3171532154,0.0740581304,0.7199848890,-0.3346158564,0.2480404526,2.2816629410,-0.7901241183,-1.2123996019,-0.7006688118,-3.1003596783,-0.4071684480,-0.2404175103,0.3279474974,-0.1991623193,0.8064158559,1.3032054901,-2.3590478897,-0.0860624835,-0.0414754823,-0.7682408690,-0.6589986682,-0.3123554587,1.5079144239,0.2001926452,-1.2423874140,-0.8025832772,-0.2944001555,0.7860500813,-0.5993912816,0.0452994257,-0.1173223034,-0.3171161115,-0.6040194631,0.4698894918,-0.2821411490,-1.8677010536,-1.0488799810,1.0262153149,-0.9576758146,1.3599735498,-1.7847856283,1.2750602961,1.3729448318,-0.0263605714,-0.9299097061,-0.1553459466,-0.5619153976,-0.2708025575,-0.5707209706,-0.3943482339,0.3243137002,-1.2652244568,1.3428239822,-0.4716863632,-0.1471398324,0.5845143795,0.7798466682,-0.2970978022,-0.2879599035,1.1741337776,-0.3029748797,-1.0286338329,-2.5272741318,1.8863145113,0.5938357711,-1.5568106174,0.1661666781,1.0948197842,-0.4422018528,0.4641939998,-0.8608870506,-1.7977205515,-0.6338832378,-1.5577857494,1.3675371408,-1.8018686771,-0.4680710137,-1.3529676199,-0.3295443952,-0.0289831124,0.8985692263,0.5144635439,-1.5340685844,0.7415658832,-0.4952560365,-1.2680888176,1.5494275093,0.9896262884,1.1337209940,0.1172252595,0.5003512502,0.3104941547,0.8642488122,-1.9873039722,0.2901904881,-0.8896881938,-0.3933593929,-0.3691793084,-2.2398619652,0.4009266198,1.4610875845,-0.2109690011,0.3212065697,1.1923828125,-0.9447377920,-0.7677613497,-0.0199948680,0.7007796764,-0.9966187477,0.1880163848,-1.5960267782,1.1941541433,1.3885799646,0.3051355183,-0.4914822578,-0.0551109239,0.8271973729,-0.0875257626,0.5913065076,-0.3327606320,-0.6633206010,1.1625896692,0.5635477304,1.5795736313,0.7323051691,0.5140512586,0.7973369956,-1.0491675138,-0.8615369797,-0.0855538324,-1.1763240099,0.6985024214,0.7214810848,0.3039073646,0.7869974971,0.7645076513,1.6823736429,-0.3224197328,-0.6913388968,-1.0375618935,2.2595710754,0.3254954815,-3.2841098309,-0.9829556942,0.6173440814,-1.9146822691,1.6384691000,0.3188497424,-0.9541326165,-1.3458615541,1.1278688908,0.3943688273,-0.2816155255,-0.6670376658,1.7449932098,1.6885739565,1.6031520367,0.1641594321,1.3355803490,-0.5794470310,-1.4504963160,0.0844430998,0.2493409365,0.1463551372,-2.4972960949,-0.4465410709,-1.2534028292,0.9957426190,-0.7179170251,-0.9940697551,-1.5139750242,-0.3549970388,-0.0613587759,1.6371300220,-0.3277179301,-0.7049137950,-0.0345475487,0.8238404989,-0.0779935420,0.1792568564,-1.1482546329,-0.6932830811,0.6941252351,0.0120476391,1.0842584372,-1.1157293320,-0.2156767249,0.1917534322,0.2484143525,1.1325517893,-0.8084028959,1.9061423540,0.2140457481,2.5162801743,0.1694203168,0.2875690758,-0.4746890962,0.2268090844,0.6107716560,0.8992943764,1.2538052797,1.0825774670,-2.5980246067,0.8615135550,-1.2262650728,-1.2255992889,-1.7337546349,-0.0070146662,0.8009208441,1.0482748747,0.1379574686,1.4142774343,-2.7599356174,-2.6668968201,0.5720087886,1.0927113295,0.5224719644,-1.5818355083,1.6267343760,0.8453273177,-1.3154888153,0.7564472556,0.8823671341,1.7488454580,-2.1088161469,-0.3071520329,-0.9865061641,-3.3408041000,0.8878111839,-0.5089591742,-1.7002439499,-1.6869919300,-0.7074144483,-1.5640826225,0.0950985998,-1.5500789881,0.6208086014,-0.3661846220,-0.8483721018,0.1937151700,-1.3323022127,-0.3852874339,-0.2245144695,0.5444493294,2.3293950558,0.1018384323,0.0900604799,-2.0430760384,0.1845244169,1.0585149527,-0.4266940057,-0.2745861709,-0.9895468950,-1.4220205545,0.1086603552,0.7137717605,-0.7071261406,-0.6727264524,-1.1171315908,1.1003943682,1.4516644478,0.2674415112,0.7746139765,-0.4443411827,-1.4839503765,-0.4744228423,0.6212148070,0.1285764873,0.4126030803,-0.8194864988,0.2797495127,0.7431498766,-0.6712838411,-0.5915322900,0.0478469022,-1.9627013206,-0.1429765671,-1.1604765654,0.7248870730,0.5285183191,0.3912655115,0.8200900555,-0.0187557004,0.3092218041,0.8215553164,-1.2147023678,0.8691491485,0.1782266051,-0.3846947849,0.2185835987,1.0123075247,0.5845950842,0.8014039397,-1.2928036451,0.2337188721,-1.0127472878,-0.1021579877,0.4277488589,-0.4217742980,0.8380681872,0.9014368653,-0.5033906698,0.3400486410,0.0378595553,1.4128333330,0.8601081967,1.4224760532,-0.5014793873,-0.1299059242,-1.0861430168,-2.1957287788,-0.4724318981,-1.2804791927,0.8848083019,-1.0232039690,-1.9286930561,1.9506202936,-1.2104187012,-0.8170687556,1.6399490833,-0.2306459248,-1.4863326550,-0.9082179666,-0.2592566311,-0.6489036679,-1.1253803968,0.2403939068,0.0076182713,-0.6155346036,-0.6273389459,1.2138336897,0.1259267330,-0.4360826612,-0.2855346501,-0.9321278930,0.2889509797,0.0191639476,0.3197908700,0.1481243372,-0.3380688131,-1.4064606428,-0.1481387913,2.0216214657,0.1358122379,0.3295311034,-1.3799560070,1.0495952368,-0.6023465395,0.7122180462,-0.2905054092,0.0740248412,1.8817989826,0.0416676588,0.6724176407,-1.2744238377,0.3802832663,-0.3467430770,-1.1206740141,1.2709239721,-0.0360667482,-0.4205509424,0.8479788303,-0.2158568501,-1.0330330133,0.4496297836,0.2781554163,-1.9734966755,-0.7712466717,-0.1627359092,0.2592321932,-0.5584867597,0.3639693856,-1.8700847626,0.0532161370,-1.0296891928,-0.7521325350,-0.2848433852,-0.1023412347,0.3919997215,-1.0115511417,-1.2037749290,-0.5682365894,1.3685394526,-0.0325128809,0.1605796665,-1.9592183828,-0.7536043525,0.5448845029,-0.4187681377,1.5351369381,0.7247617841,-0.1284294128,-0.7700523734,-1.3904502392,0.2299453765,-0.0612412915,-0.4955629408,0.4037678242,-2.3232903481,-0.5163176656,-1.1535639763,0.1474791318,-0.3062639832,-0.3380345702,0.4434403479,0.1649090350,-0.0253193621,-0.2594115436,0.3455506265,-1.1220024824,1.1439352036,1.9330021143,-0.2664181888,0.6555473804,0.4029106796,0.6844402552,0.5201416612,-1.7882884741,-0.0639681965,0.9145079851,1.1875967979,-0.2303394228,1.4555683136,0.0759437382,0.3192932904,0.1900645643,0.1694294959,0.2299467325,1.1252853870,1.3348319530,-1.4127507210,0.8178436756,0.3104344010,0.0983516201,0.3478089571,-0.8033730388,0.4526213109,-0.2079967260,-0.3332097232,-0.7742238641,1.0865453482,0.3817871213,-0.8886569738,0.9300866723,0.2929508984,-0.1157365143,0.7728258967,-0.6975427270,-0.9684841633,1.3194321394,-1.7829133272,-0.3412713706,-1.2375971079,-1.0775034428,-0.5838529468,-0.7925577760,-0.5509713888,1.3133839369,0.3206467927,1.3325715065,0.4925050139,1.9970691204,0.4951836169,0.1311973631,1.4893194437,0.5594164133,0.4966352582,1.2948005199,-0.8946422338,0.3424288332,-0.4328266084,-0.8383091688,0.3484825790,-0.5664611459,-1.5805536509,-1.2075260878,1.0009816885,-1.1555238962,-1.1081479788,0.2666878104,-0.0843278915,-1.4013813734,-0.0587022007,-0.5409751534,-0.9161397815,-0.0049323305,-0.5609408617,-0.9947663546,1.7990250587,2.1042752266,0.3246460259,0.8142860532,-0.4318092465,0.0749454051,0.5255390406,0.8453169465,0.5342290401,1.3789731264,-0.1871801764,0.1282057762,-0.8915588856,-0.0542284548,-0.1044168994,-1.5793139935,-1.0756293535,-0.9769575596,-0.3783388138,-0.1792947501,0.1676430255,0.9718354940,-0.3327423930,-0.9197884202,-0.6990206838,-0.7812698483,-0.7872581482,1.0362886190,1.0649689436,0.3260521293,2.1018323898,0.0040883296,-2.0931577682,0.6810662746,-0.8956177235,-0.6246948242,2.6490068436,1.4860161543,-1.1300300360,-0.0098225111,-0.3665522337,-0.1155728847,-0.2216357440,0.0329407454,-0.3452160060,-1.6651244164,1.1996959448,-1.0849312544,0.0575289764,-0.6823420525,0.4595836699,0.4365171492,-1.0625749826,0.6479692459,0.1152886003,0.6351547837,0.8655322194,-0.1900938898,0.6194599867,1.3249210119,-2.9902887344,-0.9829337001,2.3041112423,0.8291086555,-0.6690052748,-0.2973387539,0.2854040861,0.2512688935,-1.0038155317,0.0745838508,0.6835303307,-0.3019574583,0.0656837150,0.2763928175,1.0574886799,0.2528705597,-2.0649085045,-0.2525582910,0.5633801222,0.7122578025,0.6231449246,1.2130430937,-0.3417893350,-0.6274027824,-1.0826811790,1.3845734596,-1.6314278841,0.9325391650,-0.2828492224,-1.1294640303,0.3213407695,-0.1412851214,-0.5739104152,-1.8523945808,0.1375545859,0.8524460196,0.9795963764,-0.4191142619,-0.1105024815,-0.8044444323,1.7718458176,-2.1773252487,-1.9565769434,-0.0790803954,1.5214020014,-0.9446907043,0.2151204497,-0.7931734920,0.1091351062,0.0690722018,-0.2768059075,-0.1884625107,-0.0551569052,-0.8582618237,0.7444183230,-0.3289690912,-0.4206421971,0.6482777596,-1.8037947416,-0.6215838790,0.2966335118,-0.5860925913,0.2072690427,0.3849021196,-0.0163337681,0.7419171929,-0.7282328010,0.3230105639,-1.0278416872,0.2014814466,-0.1945166439,-0.0878563076,0.5807428360,0.4235515296,0.5991556644,-1.6961510181,-1.7235015631,-0.1653775871,-0.0229291823,0.3718184233,-0.5282102823,-2.0017440319,-0.5723828673,-1.0784522295,-0.1570475549,-0.4171837568,1.1093618870,0.8538563251,-0.6578562260,0.2458041012,1.4572660923,-0.4246588945,0.5097835064,0.6360350847,-0.2560229897,0.0219479911,-3.1653001308,0.7525913119,0.1623850465,-1.1981235743,-1.5419058800,-1.2821328640,-2.3250749111,-0.0390541479,1.9492053986,-1.6592499018,-0.2550086081,-0.8584333658,-0.6264243722,0.0905184820,2.3940489292,0.8812188506,-2.6074683666,0.5467622280,-0.2826860547,-1.7907680273,-1.6223297119,0.0945725664,-0.6790642738,-0.0352940187,-0.6122911572,-0.7683660984,-0.5392516851,-0.3982014656,0.8679015040,-2.1680600643,-0.5140717030,0.8265195489,1.5463507175,-0.5618708134,-0.9446499944,-0.9218199849,-0.5487257838,0.5468548536,-0.1935274601,0.2828486264,-0.7948492169,-0.0389313214,-0.7580267787,1.2519108057,2.5005273819,-0.4626162350,0.7376989126,0.7565030456,2.0083138943,0.8451092243,0.8647089005,0.0845709145,0.6045849919,-0.2940496504,-0.7108674049,-1.6182552576,-1.1536600590,-0.5232933760,0.8932416439,0.0766904950,0.2250192761,-3.3111915588,-1.2070434093,-0.5528053045,0.2814783454,-0.0727163851,0.4501400888,-0.5304975510,0.0220623203,0.5409076810,0.5520184040,1.1103562117,-0.7519988418,-2.4101579189,0.8522349000,0.3122522533,-1.3813184500,-0.9066482186,0.0503111966,-0.5682703853,0.8344324231,0.0455108099,-0.5007439256,-0.0220513381,0.6138712168,-1.5130780935,-0.8231852651,-1.2862572670,0.0757517591,-0.3834818006,0.9912862182,-0.2152566612,-1.8530063629,-0.8569292426,0.8364073038,0.1884991527,-0.8838205338,-1.4345126152,0.4621810317,1.8554944992,1.7764538527,0.2408635467,-0.3988132477,-1.3176436424,0.3313519657,-1.5404409170,0.8066987395,0.6141310930,1.0647925138,-0.5903156996,0.4407163262,1.0937725306,-0.6846204996,-0.8255679607,0.0301491339,1.1726086140,0.5547693968,-1.9036145210,-2.1507112980,0.9439404011,0.8304248452,0.8022865057,-0.0395314060,-1.7726892233,-0.7131135464,-1.3535375595,-0.2295022607,0.6360743046,0.3305475414,0.1700846702,-0.4246495068,-1.0522756577,-1.6014963388,0.8445893526,0.4519396126,-0.7346076369,-0.9541358948,0.0660870895,-0.2796024382,1.5112785101,-0.2288440019,0.7933291793,0.9457479715,0.0437120758,1.0272008181,2.6187674999,0.2938658595,0.0002436232,-1.8856309652,-0.2801553011,-0.8098967075,0.2391258031,-1.5088934898,0.1154030189,0.1677009463,-1.0893034935,0.1279728115,-1.1742339134,0.0815478116,-0.4688488841,1.9693156481,1.1393784285,0.7566793561,0.0332948640,-1.1088514328,0.6060234308,0.3168972135,0.9489172697,0.8915824294,-0.0744909570,-2.9674692154,0.2204231173,1.3969603777,2.8875684738,1.1382696629,0.0757457167,-0.3666677177,0.0659102425,0.0668415278,-0.5749508739,-0.2340170890,-0.5543112755,0.2262243181,0.3229537606,-0.3703001440,1.2843537331,-1.3588908911,-0.4063398838,0.3984783888,0.4746867716,-0.5155292749,2.0688710213,-0.7366701961,-1.2884358168,0.0306869484,-0.6278145313,1.6479524374,1.2733566761,-1.5114120245,0.5874340534,1.4164183140,2.1109287739,0.6936261654,-0.7801271081,-0.1424248666,1.4228651524,0.7660459280,0.0757838488,-0.3184366226,1.6464478970,-1.3185890913,-0.6462491751,0.5449139476,-1.3927319050,1.1904312372,0.5407568216,-0.0330950134,-0.3919748962,0.7456977367,-0.6043021679,1.7865223885,-0.3086243570,1.0165492296,0.2271374613,-0.7343394756,-0.6063373089,-1.8273447752,-0.8988688588,0.3666749895,0.2657340765,-0.2736480534,-0.7589226961,0.2684849799,-1.1223801374,-1.1474984884,-1.2845572233,-0.3152797520,0.3679023683,-0.2113581449,0.5975563526,-1.9758757353,0.2240671962,-0.5090435147,-1.2870079279,-0.0849780515,-1.1679377556,0.4966672361,-0.6675986052,-0.4594515264,-2.6474492550,-0.3685693741,-1.2190847397,1.2057003975,-1.1603654623,1.1231783628,-0.5407581925,-0.5821552873,-1.8120853901,2.3940880299,1.2630169392,-1.4847002029,0.0002179273,-0.2718341053,-0.6148485541,0.6212561131,-0.8127297163,-0.2228314281,0.6530621052,-0.2918465734,0.8982840776,-0.3148573935,0.0192828048,0.1528849155,-1.0955338478,0.1683052927,0.7518684864,0.0263153650,-0.5481123328,-1.0166777372,-0.0326641724,0.6306336522,-1.0569366217,-1.3100726604,0.8450725079,1.1383305788,0.2161744982,1.4873583317,0.1062991545,0.0131904045,-1.0483144522,0.8597632051,-1.7767972946,1.5863535404,2.7823541164,1.6619212627,0.3272190094,0.6373428702,-0.3165480196,1.0289241076,0.0949189141,-1.5440686941,0.3050356805,0.1199226975,-1.2530963421,1.2903825045,-0.0241483971,-1.6955019236,0.4644385278,0.2589190602,-1.3097108603,-0.5500065088,-1.0812994242,0.6089993715,1.7156662941,0.4168740809,-0.6155125499,-0.1195571795,0.1958514154,2.2196655273,0.7892631292,0.7401278615,-0.2391066402,0.9518038034,0.5104688406,0.7215762734,1.3206062317,0.2645880580,1.1824287176,0.9417513013,0.7604390979,0.1519564837,-1.5020102262,-0.4238476455,1.3813818693,-0.3240005970,-0.9087860584,-0.4296375513,-1.5056200027,1.0380312204,0.9179576635,-0.2080131173,0.4261639714,-1.2480202913,-0.1067449674,-0.1843754649,0.2243936658,1.2510346174,-0.4090640247,-0.3410273790,-0.8742214441,0.0221707560,0.0311127305,1.9829660654,0.4096661210,0.5662220716,-0.6245689988,-1.7555264235,-0.0548473075,1.2680255175,-1.4447710514,-0.7565324306,0.5842719078,-1.8277680874,0.1456336826,-1.0918613672,-0.9649658799,1.3064036369,1.1600183249,1.1379429102,2.1565191746,-0.8689957857,1.5636215210,0.4368431270,-0.6594150066,0.2378106266,-0.0386009179,-0.2020491958,-0.7171027660,0.7523133159,-3.0087399483,-1.2096756697,-1.4830690622,1.1132252216,-0.0736747012,0.2278408259,0.8607809544,0.0230039097,-0.0100709805,0.5663136840,-0.4573984742,-0.3147220016,-0.5916610360,0.3633759320,-1.7309250832,0.7415539622,0.9788953662,0.4454882145,0.9996737242,-0.7172723413,0.4500461519,0.2097088099,-0.1300976425,0.3683418930,1.6021925211,1.3492051363,0.5966399908,-0.2869676948,-2.2014067173,-0.6466356516,-0.4141579270,0.0322575942,0.2764803469,0.0523899347,0.9976919293,-0.4418748617,1.1962385178,0.8795982003,1.3394536972,-0.5127735734,-0.5311194062,0.8626922965,-0.7423558831,0.9309554100,-1.4290853739,0.0858087614,-2.6495206356,1.6978728771,-0.4349122941,-0.3831622601,-0.0684857070,0.7442887425,0.5322425961,2.0612838268,0.1241032407,-2.3649044037,0.3680788875,0.1251933873,1.7623183727,0.3210356832,-0.2840740085,0.7346179485,0.1568394750,-2.1416144371,0.0518188179,1.2533953190,0.8536785245,-0.2809889913,-0.4789661765,-0.7346751690,0.5946739316,-0.7996873260,-1.3966721296,-1.7271291018,-0.7277098298,-0.0455504879,1.6599112749,-0.2437718362,-1.4668591022,0.0005579666,-0.6929865479,0.9924173951,0.1146905273,-0.0723900497,-0.3171693087,0.4661208093,-1.2721763849,-0.9968279600,1.4310706854,-0.1644446850,0.2184965909,-2.4001052380,0.5335850120,0.8570533395,-1.2253437042,2.6228101254,-0.8978168368,-0.4737388790,1.2820608616,-0.2572124600,-2.3622217178,1.6324220896,0.2936998904,0.4136489630,0.4954855144,-0.6417990327,3.0474805832,-1.4472365379,-3.3824377060,-0.5294840932,2.2834894657,-0.2915201187,-0.5834859610,0.6736102700,-1.0685982704,-1.0622173548,-3.0860776901,-0.1529570520,-0.9341332316,0.6026499867,-1.6047893763,0.5600776672,0.2471535951,0.3888663054,-0.5745077729,1.1368119717,-0.1875921935,-0.2457357347,1.0788971186,1.3245619535,0.4084223807,-0.9082864523,1.3701889515,0.5639448762,0.6552087665,0.2393982857,0.5696803331,-1.8782240152,0.1603340507,-1.0327521563,-0.1901682466,0.5955625176,0.8033736348,-0.3817498088,0.4623665214,0.5622440577,-1.9576177597,-0.2124888599,0.0532335043,1.7872124910,1.0935274363,-0.6834817529,-0.0209047794,-0.2557629645,-0.0322177224,-0.4546183646,-0.6292889714,-1.8742160797,-0.8476565480,-0.0208909176,0.9334092140,1.3976117373,0.7560239434,-0.6076855063,-0.4940192103,-0.2218679041,-0.0247830916,0.4010295868,-0.2099526823,1.6346033812,1.0749132633,-0.7803043723,-0.6348884106,-0.6152335405,0.9498234391,0.2001388222,-0.5263258219,-0.8058626056,1.0469522476,0.3226033449,0.1166816801,0.9418267012,-1.3817039728,-0.2754204571,0.6587382555,-1.1658596992,-0.5008330345,0.6715875268,1.0270637274,0.6949701309,1.0310188532,0.3335841298,-1.1015419960,-1.6726310253,0.0740614757,0.3277696967,-0.3727508783,0.1862053722,0.2605803013,1.8626759052,0.0707811713,-2.1108138561,-0.6218534112,0.4231096804,0.2173334807,-0.7314818501,-0.7883370519,-0.1343939155,0.4867017269,-1.6478499174,0.8052513599,1.0267293453,0.0742363185,0.0273618270,1.4169248343,1.9043926001,-0.3838944435,0.5245365500,0.2650912702,-0.3235317171,-0.8705883622,-1.5474305153,0.6036111116,0.0714829117,-1.1413797140,0.1435114741,-0.6295248866,-0.0765427724,-0.1058588624,-1.4466910362,-0.6485618353,0.0132218618,1.4305149317,0.3642526269,1.3517880440,1.3447993994,0.7358057499,0.7414743900,-1.2427915335,-0.3946131766,0.1648515463,1.1895046234,-0.2594691217,0.8554831743,-1.0946022272,1.1648385525,-0.2886697054,-0.7935397625,0.0376145579,1.3619145155,-1.3953189850,-0.1312556565,-0.4305959046,-0.7347027659,1.2504189014,-1.1138132811,1.8914943933,0.6668202877,0.5314742923,-1.1446431875,0.8470588326,-0.3559998870,1.8328109980,-1.0825778246,1.5532661676,1.4346286058,1.6508401632,0.1166369244,-1.7578734159,-0.2210106105,-0.3382823765,-0.7606144547,0.7037070394,-1.4212046862,0.7512388825,0.1273766011,-0.0193244293,1.8327016830,0.1493382752,-0.0756782517,-0.0355336964,-1.6446069479,-0.8279816508,-0.0862731785,-0.6101303697,0.6401699185,-0.1602170914,-0.9755163193,0.3217153549,0.1617767066,1.2197539806,0.1922034472,-0.4725489616,-1.2373657227,-1.7496455908,0.5991289616,-0.5498912930,0.0673314482,0.8375106454,0.8581475019,0.9310656190,-1.3271347284,-0.1280384958,1.7297261953,-0.2735048532,1.1787731647,2.2917857170,0.8384599686,0.9903156161,-0.2916140258,0.3382817805,1.0331203938,0.3903645873,-0.6004440784,-0.5967748165,0.9446532130,1.4222265482,0.0261503533,-1.4113605022,-1.8482435942,-1.0479794741,0.6841892600,-2.3524160385,-1.1195981503,-1.0631546974,0.3228687644,1.1693851948,2.5934445858,-0.4578936994,0.1776099205,0.0838143975,0.8039101362,0.5364631414,0.1926894188,0.4836985767,1.1132575274,0.1154624745,0.1372138709,-0.2826304138,-1.1644810438,-0.0809413269,-0.4451850951,-1.1100091934,-0.5838759542,0.3142054081,-0.6515339017,-1.3535983562,0.3675374985,-2.6818180084,-0.4444566667,-1.1640266180,0.0140349520,-0.3826368749,-0.7109439969,0.6577385664,0.0257320683,-0.4784716666,-0.6491413116,-1.1920108795,0.7272107005,-0.4145368934,1.3471291065,0.3028367460,1.9280700684,0.8856548667,-2.2657513618,-0.1738021672,1.1121703386,0.8565863967,0.0598084405,-1.1367391348,-0.3166633844,-0.4727935791,0.1086008698,0.0661494732,-0.5598045588,-0.2818463743,0.7618486881,1.0420223475,-0.0124819009,-0.2460182905,-0.2402713597,0.2803384960,0.6347672939,-0.7395008802,0.3717006445,1.8899036646,0.7324008942,-0.2531517148,2.1485793591,1.1714525223,0.7662360072,-0.7396721244,-1.2587963343,1.2214463949,-1.1060516834,0.2466125786,-0.0663431361,0.5754920840,0.0819447786,1.2410321236,-0.0663276836,-0.8556157351,0.1471997797,-0.1371292323,1.4430338144,0.1633171737,-1.1141107082,-1.4421511889,0.2584901750,0.1109801009,0.5133917928,-1.6274529696,-0.3198641539,1.5091960430,-0.5411385894,0.4407715201,1.6539150476,-0.1996767372,2.6565704346,0.0422839411,-1.1861289740,0.6739498377,-0.0582477152,0.0878551304,-0.0720350966,-0.9809566140,-1.0485097170,0.1298928559,1.5011910200,0.3872312605,1.3922791481,-0.8527609706,-0.1992137879,-0.3257340789,-0.2213805318,-1.5234873295,-0.1974401027,-0.8294673562,1.2558363676,0.7330928445,0.6681995988,0.8794973493,0.6108455658,0.5544348955,-0.6794480681,-0.7796459198,-0.7026695013,-2.1434984207,0.0411658436,0.3642963171,-1.1052713394,0.2658634484,-0.4520622790,1.2095198631,1.5577833652,0.3189541698,-1.2588919401,0.8697476387,0.2926436365,1.0497710705,-1.7970030308,-1.8265334368,-0.0994349569,0.3744624853,0.2839959860,0.5508910418,0.5231243372,0.7695473433,0.2353003919,1.0889656544,-0.0385504179,-1.6064237356,0.2855109274,-0.4909099638,1.2451142073,0.3549577296,-0.1303832978,-2.4352939129,0.5502526760,1.4097541571,-0.8143534660,-0.4583834112,0.5625880361,-0.0530144200,-0.0092057148,0.0317580067,-1.3821700811,-1.1400830746,0.2341952622,2.0570058823,0.6172062755,-1.9741103649,0.9930515289,1.0489962101,1.2614012957,-2.0655992031,-0.6154462099,0.3555959165,-0.2700898647,-0.9979034662,-1.8507244587,0.9184408188,-0.3622143865,-0.1437021047,0.9383545518,0.0250540581,0.5107842088,-1.4865230322,0.6810082197,-1.9815660715,1.1557435989,0.1040510312,0.8280178308,0.8028651476,-1.1024335623,-0.7035324574,-0.0274420045,-0.6655241251,-2.0715312958,0.2726945877,-0.6792376041,-0.1231326684,1.4458146095,0.2314967811,-0.6573718786,0.6712464690,-0.7653050423,1.4972485304,-0.9735265374,1.5854916573,0.2542545795,-0.1565025300,-2.3489050865,0.0153308529,0.7762720585,-1.4138087034,-1.5466600657,-0.2691728473,1.6029889584,0.7616153359,0.9480590224,0.9128962755,-0.7814031243,0.6315351129,-1.1406873465,-0.0793438703,0.7408534884,0.3598624766,-1.6224952936,0.7605880499,-0.4141521752,1.9717255831,-2.0489830971,0.3203971088,-0.5467629433,-2.4523425102,-0.9296472073,-0.2040585130,-0.5218498707,1.4715273380,0.9998838305,-0.4258372784,-0.1646424234,-1.0052925348,1.8012080193,0.7845478654,0.8161594868,-1.8706011772,0.0538863353,-0.5203756690,0.3057786524,-0.3377862573,0.2710774839,0.1396749020,-0.0968563706,-1.6479283571,-1.2091325521,-2.3561117649,-0.0236232337,-0.4046415389,0.0204066318,-0.2489682585,1.7718049288,0.7430356741,0.3051402569,-0.3081843555,0.6530711651,0.6653307080,0.9015319347,1.2185962200,1.2392010689,1.0117390156,0.1708698869,-0.0968572199,-1.0288013220,-1.4395042658,0.4888134897,-0.1481398195,0.2349804938,1.0387753248,-0.8918272257,1.1819578409,1.1469008923,-0.8863270879,-0.0768607333,1.6103775501,0.2564200461,-0.6540455222,-1.4819751978,0.3392748833,2.3457913399,-1.9290598631,-0.5931926966,3.8038439751,0.0150417322,0.4764592648,-0.7765587568,-0.1422771513,-0.0276196878,-1.0998263359,1.0197985172,0.7770087719,1.2607687712,0.3303723335,1.3598996401,-0.1502128541,-0.9660602212,-0.2033868581,1.8268421888,0.7102911472,-1.2924709320,1.4800399542,1.2848676443,-0.6317282915,-2.0580847263,0.7169486284,0.8882303238,0.9122008085,-0.0191191155,-0.9266655445,-0.7308059335,1.1142582893,-0.4701244533,-1.5005794764,-0.4836395681,-0.5511965156,0.8093124032,-1.2713971138,0.4431983829,0.5598557591,0.1382537782,0.5284568667,0.0855464339,1.0339580774,-0.9627118111,-0.0867765024,-0.5620479584,-0.0449695885,-0.5436484218,-2.0981886387,-0.2393644899,-1.0797698498,-1.1307771206,0.2753635347,0.7339200974,-1.4783803225,0.0846191719,0.4496826828,0.4637614489,-0.5138217807,0.8895533085,0.4025216401,0.4540904760,-0.2553262711,0.0476168953,0.3607804775,-0.9458797574,0.5130068660,1.0887874365,0.0324329808,1.7249981165,-0.5506155491,-0.2265087664,0.1730436236,-0.8672905564,-0.9517143965,-0.6819998622,1.8925633430,-0.5262590647,0.2710691392,-0.0368213281,0.2499300092,0.1145922467,0.4249081314,0.5221466422,-0.6290580034,0.5858543515,-0.7500481606,0.4885399044,-1.0888670683,-0.1751397997,-1.0800218582,-0.5044698715,-0.6824820638,0.3367467821,-0.0662877113,0.0004860878,0.3974931836,0.9878262281,-0.2203817666,-2.3339583874,-1.3713185787,0.7010454535,-0.1792138517,1.6398990154,-1.3528527021,-0.0485312343,1.6457034349,-1.5228041410,-0.9622097611,-0.7212290764,0.1708365530,-0.1943217069,-0.1791012436,-1.5973223448,1.0700832605,-0.0263415724,-0.0783090517,0.5096049309,0.2359365672,-2.0904521942,1.3343380690,0.0267197248,1.0169812441,-1.6574496031,-0.7635102868,0.0978857651,0.8636631966,0.2661770284,-0.9758553505,0.6706265211,-1.1487759352,0.7276757360,0.0401194058,-0.8232668638,0.1121659577,1.8414586782,-0.5288928747,-0.5942555070,-0.0549913421,-0.3535532951,0.4613077641,-0.8000953794,-1.1293758154,0.7078111172,0.2381000668,-0.2260020673,-1.0287990570,0.6059779525,1.0500333309,0.4062401950,0.5371391773,0.0047277003,1.6705203056,0.4563495219,0.2244141847,-1.6428673267,-1.8438435793,0.3145678639,-0.4614353478,0.4700029194,-1.7696510553,0.0000749491,-0.0976910740,0.5977476239,0.2733864784,0.3712363243,0.7553363442,0.3672829568,1.1928751469,1.4054775238,-2.3258380890,-2.9297554493,0.2743716836,-0.7235479355,1.5969778299,-1.8682086468,1.4272466898,-2.3928434849,-0.7951687574,-0.3718027174,-0.2111870050,-0.4080311656,0.4804771543,1.6419860125,0.9514871240,0.6680909395,-0.5509938002,-0.0222789478,-0.1015945151,0.1699242294,-1.2516422272,-1.5921986103,0.0323502608,1.3214668036,-0.0185927413,-0.4885272980,1.0027142763,0.0604401119,-0.5876231194,-0.2673060298,1.1417536736,-0.5216576457,-0.9080795050,0.2505319715,1.5503072739,-0.5802096725,-0.5431979895,-0.8207826614,-1.8523241282,0.7910633087,-1.5131099224,-0.5346738100,0.8551876545,-0.8079803586,0.3514728546,-1.0119205713,0.1222014651,-2.3043191433,-0.5708674192,0.5543924570,-0.8940060139,0.2141406089,-0.4124077559,-0.0373211876,-0.4836105108,0.9895735383,1.3710926771,0.3094007373,1.0810010433,0.7413520813,0.0272918269,-2.6059725285,0.7118025422,-0.3565561175,-1.5837817192,-1.8069742918,0.0314307399,0.7519264817,-1.6187287569,-0.0656537339,-1.2725286484,-0.0628013238,-1.2660244703,-0.2694690824,-0.9322804213,-1.7178848982,0.3884723186,1.1313183308,-0.8840425014,-1.5170679092,0.8701610565,0.6604436040,-0.3095566034,1.1559892893,-0.0074164211,0.9563302994,0.5253620744,-1.1275501251,2.1611838341,0.2815635204,1.0019308329,0.3967360556,-1.3517037630,-1.6757366657,-0.4909931421,-0.2150374204,-0.4196070433,0.0863581672,-1.1695873737,-0.2097769529,2.7132956982,0.6640202999,-0.3107252419,0.1927692294,-1.1766229868,0.5481172204,-0.0203474443,1.5921030045,0.8253238797,0.2750462592,-0.3395743668,-0.1995105147,0.2876706421,-1.2705643177,-0.4173485339,-1.0307558775,-1.9259363413,0.3010179400,0.5864936709,1.1382341385,2.5246179104,-0.5178236961,0.8482388854,0.9648278952,0.5560377836,-0.2276707441,1.0964823961,-0.2981500030,-1.1091046333,0.2975334525,0.6693788767,1.2441065311,1.2527660131,0.1742370129,-0.2687437832,0.8906718493,1.1863725185,-1.3319261074,0.1384135783,0.9704707861,0.6115167141,0.1373640597,-0.4339033961,-1.5552423000,0.6139218211,2.3210573196,0.5673650503,-1.5066421032,-0.9496950507,-1.8230872154,0.2817157209,1.3412139416,-0.3125414848,-0.7926390171,-1.8839703798,-1.5029090643,-0.4812536836,-0.8076776266,0.1639763117,-0.7107151747,0.9037547708,1.1245650053,0.4608503878,1.4936001301,0.8328832984,-0.1224921197,0.8565199375,-0.8202630877,-0.1175216883,2.6427290440,0.7497962117,-0.1043440327,-0.5497339368,-0.1805608422,0.2127023935,-3.0390629768,-1.0456823111,0.2500087917,-1.0225489140,-0.7522569895,0.1320671141,0.0960535109,0.2754767239,0.7104935646,0.4646618962,0.8646464944,2.8653013706,-2.1563317776,-0.9281902909,0.3972793519,-0.9229031801,-0.2998534441,-0.3409955204,1.2158575058,-1.6193940639,-0.4401818812,0.1239653826,-0.1996781826,-0.8049672246,-0.3598818183,0.2379658520,0.7701300979,-1.6182599068,-0.8581345081,-0.2470516115,-1.7491062880,1.4807767868,-0.5614758134,1.2209767103,0.2904929221,-0.0265204366,0.5695201755,0.1617171317,0.7726086974,1.0486824512,-0.3704072833,1.1730215549,-0.5312774777,1.3397569656,-1.0443192720,-1.3226132393,-0.2041894644,-1.5650993586,-0.0995839760,0.2208478004,-0.4249693155,0.9977360368,0.5591554642,-0.0693533272,-0.9527857304,0.7313643694,-0.1154942065,0.6147226691,-0.5344278216,-0.4461407363,0.6166067719,1.1970794201,0.3441028297,0.9995790720,-0.1399023682,-0.2110286802,-2.0446467400,2.6426510811,1.7442144156,-1.2394208908,-1.1079133749,0.2935610712,0.0725700185,0.3695668578,0.5065841675,-1.0672954321,0.5645725131,0.7228435874,-0.8897636533,0.4221113324,-0.4366683066,-0.4785924852,2.0385699272,2.5463235378,-0.9433593154,-0.9427928329,-0.7519164681,-0.6663823724,-0.3502293527,-1.4659262896,0.2184054852,0.3883730173,-0.5445824265,-0.4340218902,3.7029385567,-2.9254779816,0.0942560732,0.7164333463,-0.4786452055,-0.1175122783,-0.6979387403,0.2932125032,-2.5538980961,-0.6223775148,0.2257152498,-0.3763697743,0.8137111068,-0.5992847085,1.3243182898,-1.2376658916,-0.0529220700,0.3752489388,-0.2927281559,-0.8624119759,-1.7237237692,1.1811594963,-0.3744150698,-1.1541925669,-1.5252789259,1.3609256744,0.3352670372,-0.7940573692,-0.5847789645,0.0678094849,-0.2327625602,-2.0279872417,0.0251677223,-1.4056166410,-1.6464124918,-0.2422740161,0.8370131850,1.5657683611,-0.4537927806,0.7318181992,-1.0169379711,0.7392541170,-0.3775894642,1.7589201927,-0.9612664580,-1.5072410107,-0.9849436879,0.2215117812,-1.2333002090,-0.1126676127,0.1513326466,1.5155856609,-0.8208940029,1.8061890602,0.1750951260,0.0165317189,-0.0252383649,1.7736938000,0.5884373784,-0.9119014144,-0.6989759803,-1.0164759159,0.0299540386,-0.0303175766,0.5049239397,-0.6621921062,-0.2147170007,0.2130482644,-1.0169265270,-1.0796117783,0.9682517052,-0.2484214753,-0.0983709693,0.4231301248,0.9714114070,-0.3323786557,1.5941475630,0.0305444896,0.4641273916,1.1204073429,-1.7273485661,-1.9588909149,-0.0995916799,0.4214471579,0.2391090691,-0.8550423980,0.5174822807,0.6435247660,0.7362871766,0.2990854383,1.6299250126,0.0470980965,-1.4124903679,2.0001816750,2.4043455124,0.4756488204,0.3924701512,0.3098393083,-0.0730008855,0.0644879714,-0.5879397988,3.1723389626,-1.1309983730,0.4812060297,-1.0504877567,1.6183617115,-0.6508139372,-0.3729372919,0.8800085783,-0.1217752844,-0.7541463971,-2.0912880898,0.0173039250,-0.3026672900,1.9386875629,-0.5450688601,-0.8840935230,-1.0172849894,0.2282519937,-0.7308015823,0.0178454760,1.1036424637,1.0490378141,0.0145709217,-0.6570018530,0.6453847289,0.8068607450,-0.9951968193,1.6353204250,0.2871158421,-0.1186865047,-0.7178679705,-0.2702004313,0.7870482802,1.2354224920,-0.5233058333,-0.9856014848,-2.3766124249,-0.3460740149,0.8292262554,-0.1120812893,-0.5926383138,1.5636755228,0.5033448339,0.0718692541,0.0410754010,0.3172487020,1.0507453680,0.0159926750,0.4478392601,-1.4229664803,0.7920886874,0.1866728514,-0.8899513483,1.5150766373,-0.7372040749,2.3344931602,1.7175177336,-0.2363054156,1.2435344458,0.1209539473,2.1040270329,-1.0785930157,1.0357654095,-1.2035720348,0.6071705222,-1.2331465483,0.0831739157,0.5158026218,1.2514107227,0.5857951045,0.5511865616,-1.0304999352,-0.7450944185,0.8752056956,-0.8220462799,-0.5751981139,-0.3852460086,0.4066129625,-1.4922865629,0.5390688777,1.0325790644,-1.0658810139,0.8860808015,-1.0557252169,-0.3435255885,-0.3831379414,-1.5366101265,0.7045727968,-0.4226921499,0.2454482317,-0.9025840163,0.5418877006,-0.0653132945,-0.6542792320,-0.2471905053,0.6364162564,1.2548311949,0.8018607497,-0.0924706161,1.7474905252,-0.0242728647,0.7594467402,0.2591527998,1.2631505728,-1.0255336761,0.5002287030,-1.4737606049,-1.7188454866,1.5862935781,-0.7704221606,0.2158858180,-0.6859569550,-1.4657487869,0.1420394927,-0.7383154035,-0.6743084788,-2.7707183361,-0.1151084825,-0.6279640198,-1.6584491730,-1.2487521172,-0.1758100241,-0.2976056635,0.6281543970,-3.0891396999,0.6630514264,-0.9883195758,1.5522327423,0.6034018993,0.2812715769,-0.2210479379,0.0146459658,-0.3543334901,-0.4833302498,0.9713264704,-0.2638811171,-0.6870847940,0.2799275219,0.2579723001,0.0368682183,0.7310587168,0.2262041271,-0.2016255260,1.0671253204,0.0625227988,0.6604328156,0.6529068351,-1.1744426489,1.3701006174,-1.0094944239,0.5174626112,-0.8501479626,-0.3785215020,0.2888900936,0.8252806067,1.7142086029,0.7759332657,-1.7127082348,0.5845321417,-0.3192206919,-0.1254154444,-0.1918734610,1.2321667671,2.6393880844,0.2824049890,-0.6123250127,-0.3582670987,0.9553580880,-0.5618331432,-0.2247440219,-0.8032472134,-0.4080768824,-0.9748763442,-0.2706478536,0.5201159716,0.0428278558,-0.6018859148,0.7460201979,0.0247440431,-0.0502817854,-0.7423041463,-0.8392975330,1.2616049051,-0.9946495891,1.9058818817,-0.1542883366,-0.1210363731,-1.2415443659,-1.2345449924,0.9470774531,0.3019158542,0.8561933041,-2.6018064022,-0.7974361181,0.2222371846,0.4300654829,2.8669002056,-0.5035877824,-1.6985487938,2.0215651989,0.1090312600,-1.6191835403,-0.0101143373,1.0134818554,0.4818102717,-1.9236172438,-0.6230416894,-0.1731863171,1.4452866316,0.1037637815,1.5183800459,-0.4374295473,-2.5311095715,0.2603306174,-0.4341614842,-0.0227584727,0.0439706743,0.5057605505,-1.7936534882,-0.5852804184,0.1672791690,0.8425058126,-0.6111262441,-0.9124225974,-0.2337473482,-0.0449558981,-1.8964269161,-2.0928378105,0.8949176669,0.9105094671,0.9112442136,-0.4834975004,3.5092229843,-0.5729820132,2.0387670994,1.0817768574,0.3173472285,0.1624213457,0.8563386798,0.4270950556,-0.3292297125,1.1796474457,-0.0568520613,-0.6135614514,1.0171507597,-1.0845253468,-0.0473044775,1.4754977226,-0.0622475371,0.7117826343,-1.0041016340,-0.9487560391,-0.0518494286,1.4331901073,0.2149605602,-1.1410475969,-0.6128460169,0.5419374704,0.3689844310,0.8537623286,-0.7307296395,0.4909996092,1.1410055161,-0.7519097328,0.8367847800,-0.4134968519,-0.3831160069,-0.1194213182,0.2132193446,0.8922790289,1.1994528770,1.8140201569,-0.5317217112,0.7226940393,0.4397925436,-0.4289795458,1.2970182896,0.5386045575,-0.3921145797,0.3799457252,-0.2168604136,-1.2815352678,-0.5558221936,-0.6706677079,1.1508843899,0.8142685294,0.0629897863,1.0782709122,-0.3097993731,1.1608967781,-0.0450324751,0.9269484878,0.1099951491,1.0994768143,0.0873215795,-0.6024252772,0.0804315135,1.1702136993,1.2390604019,0.0422957130,-0.2660755217,0.0252159797,0.3653047979,0.6382434368,-0.1962671429,0.5976749063,0.2093169689,1.3053292036,-0.1818927377,-0.8006437421,0.7526998520,-1.2449376583,1.6166766882,1.4126682281,-0.9880897999,0.1460569501,-0.3867262900,0.8620718122,-0.9725794196,-0.2764593959,1.1102123260,-0.8179458380,-0.4496610463,0.1712568700,-0.5782694221,0.7184853554,-0.7871074677,0.1874635667,-0.9851943851,0.9395116568,-1.3483319283,1.3027681112,0.5989563465,0.3927023411,-1.0175455809,0.7853148580,-0.4428822696,1.2068151236,1.2453286648,0.2258458585,1.1729338169,-0.3745219409,-0.1013393402,0.7370291352,0.2293027043,-0.5496422052,0.4026574790,1.7350859642,0.8466253877,1.6243348122,0.2167896926,0.0440245979,-0.1143867150,-2.1155114174,-1.3466324806,0.3417681754,1.0367302895,-0.0448520556,0.1536931545,-0.1178123504,0.0942037478,-0.2840364575,-0.8906734586,1.0415467024,-0.3474560380,1.7721912861,-0.6977778077,-0.6533368826,0.2706574500,0.4579048455,0.5070598722,0.2563111782,1.0382679701,-2.1179025173,0.1377092451,0.0209780280,0.9947603941,-0.0382568911,0.2360651493,-1.6812630892,0.4709948599,1.8487871885,1.1363065243,0.6794203520,1.6432129145,0.3331112862,0.4847803116,-0.2373197377,0.8562826514,-0.8727971315,-2.7746782303,-2.3559737206,-0.2040310651,-1.7742786407,1.9584763050,0.7933133841,0.6449356079,1.4588258266,-0.0484815538,-1.0195758343,0.2607858479,0.3664327860,-1.2107329369,-1.9957568645,-0.4150539041,1.5697511435,1.9711836576,1.5477201939,0.0248154551,-0.7006254792,0.6331615448,0.5916293263,0.0568252914,0.1661783904,0.2813738585,1.0866055489,-1.0118426085,-0.0859973654,-0.7634933591,2.1033339500,0.3371011317,-1.1005963087,-1.3655861616,-0.8443711996,1.1577920914,-0.6241202950,-1.8529772758,-0.6705492735,-0.3144679070,-0.1968949288,-0.2270013392,-0.1578439176,-2.0221607685,-0.1185465753,0.4237858653,-0.0993085131,1.3173325062,0.1934987605,-2.9459500313,-0.1461422294,0.2651478350,-0.8410601020,-1.7123898268,0.0538811646,0.0466864482,0.0800267011,-1.7519488335,0.2975313067,1.4007811546,-0.9453305006,0.5971914530,-1.0898880959,-0.7380421162,-0.4164339900,-1.2008498907,-0.6115810871,-0.1443822831,1.1616984606,1.1686754227,1.2920237780,1.4396482706,1.3408201933,0.4317942858,-1.3623890877,-0.7680445910,0.5570045114,0.4734558761,1.1375391483,0.5354587436,0.4446857274,0.5467852950,-0.1238997132,-0.6851717830,2.1651611328,-0.4368666112,0.0831865296,0.0198221132,0.4435079098,-1.6825557947,-0.1355063766,-1.6379758120,-0.2781943679,-0.2904914320,0.8691003323,0.2901981473,1.5223109722,-1.3436995745,0.4895364940,-0.6511492133,-0.3522801995,-0.8010972738,-0.3451113701,-0.1639397591,0.6182901859,-0.8302804232,-0.0971979052,0.1578138769,1.5443570614,1.3465884924,-1.1086828709,1.7096700668,-0.1851585954,-0.0696520433,0.8750807643,-2.0553681850,-0.8725947142,0.6036568880,1.8323498964,-1.1572742462,-0.2411930561,0.6965112090,0.6085639000,-0.6458541751,0.1013178676,-1.0230764151,-0.8841358423,0.6133187413,1.1686683893,-0.1828366816,0.1179393306,0.6337798834,0.4901778698,-0.9213451147,1.1282690763,-1.3957413435,-0.9345256090,1.4516988993,-0.3256015778,-1.7746162415,1.1917959452,-1.2848377228,-2.0234019756,0.6253730059,0.5754631162,1.0525467396,-1.4490629435,-0.5101265907,-0.5352268815,-0.1461670250,0.4182570577,-0.8196110725,-0.2917360961,0.1357769370,-1.4317878485,0.5729535818,1.0932507515,0.9999333620,0.9448190331,-1.1056905985,1.2392117977,0.0591306388,1.4897656441,1.6061283350,-0.6775377393,-0.4090647399,0.3424934745,-0.9212122560,-1.3457553387,-1.0322591066,0.2986054420,-0.8338737488,-0.0210380573,1.5235228539,0.1132932231,-1.1214870214,0.2483399361,0.6102077365,0.1721328497,-1.2462910414,-1.4098676443,-0.0068863430,0.6785459518,1.0933088064,0.0307702217,-0.8330343366,0.0852738246,-1.6568013430,0.0855158269,-1.0569945574,0.3314259350,-0.7124000192,-1.2863686085,-0.0895156786,-0.0622664876,0.4961340427,0.1014336422,-1.3754044771,1.3578120470,-0.0705222040,-2.0296418667,-1.0720357895,0.5115970969,1.0631728172,-1.0660487413,-1.4533889294,-0.2905147672,0.2778032422,1.8945484161,0.6868228912,0.5472155809,-1.9280380011,-0.4031965435,-0.5989333391,-0.2061021477,0.8257248998,0.9506226182,-1.1330982447,0.4963971674,0.5451398492,1.2906789780,-1.5282840729,-0.8242005706,-0.0166608077,0.0335856453,2.2408883572,0.4733282924,-0.7696737051,-0.8335739970,-1.4651881456,0.9389994740,1.8702383041,0.0202532560,-0.4591764808,0.2830611765,2.2367684841,-1.4029413462,-0.1545487493,0.2303007990,-0.1837261021,-0.8145059943,-0.0218058843,0.0932727531,1.0467610359,0.7866660357,0.4435950518,-0.0753492266,0.3163510263,2.2630624771,-1.5913091898,-1.3097940683,-0.8521066308,2.0647218227,0.2911355495,-0.9971901178,-2.6643984318,0.1316338181,-0.7985268235,0.1305931062,-0.2064609826,1.2719758749,0.5087019205,0.2554793358,0.6482380033,0.7646680474,-0.6734172106,0.2700004578,0.0559221543,-1.0332484245,-0.4205034673,-0.9777092338,1.4239164591,-1.2049342394,1.1088242531,1.6507546902,0.2748976350,-1.1399236917,-0.5846256018,-0.4150563776,0.1476821899,-0.7782986164,0.9938122034,0.3498940170,-1.1976610422,0.4588616490,-0.3367350996,-0.4915359616,-0.2937815785,0.7800746560,-1.1308561563,0.7726313472,0.3986551762,0.5029765964,1.6762688160,0.4709570110,2.0376982689,-0.7127743363,-0.1392951310,-0.9906319976,-0.2955588996,0.2931172252,1.2992885113,1.7970376015,0.4209524691,0.9865259528,-0.9265616536,0.5395507813,-0.2611883581,-0.0639136136,-0.0800991580,0.5079711080,0.2602309883,-0.4143621325,-0.9424008131,0.6740956306,-0.3937194943,-1.0629720688,0.5936015248,-0.6519501209,1.1757981777,-0.7144102454,-0.1102670729,-0.3803231716,-1.3536223173,-0.8384763002,-1.8306593895,-1.6056002378,0.2277152538,-0.5050942302,-0.4376785755,-1.3809183836,-0.9032619596,0.9237828851,0.5372219682,0.2870643735,-1.5153040886,-1.6259210110,-0.0451527424,0.2230039835,-0.7418859601,-0.4045087099,-0.1136229634,1.6879923344,-0.9585251808,0.0452248342,-1.4134316444,1.5886644125,-2.2719659805,-0.8550316095,-2.3864667416,-0.4699884653,-1.4324147701,0.2486818582,-1.2270326614,-0.6884349585,-1.8654394150,-1.2348514795,0.4219813049,-0.3581189215,-0.3238225877,0.7833189368,-0.1920600682,0.7204907537,-0.1709788293,2.3878262043,-0.2370357811,0.9252066016,0.4822584987,0.6451716423,-0.6012758017,1.0694143772,-0.1956869662,-0.8577533960,0.4864356816,-0.2107046247,0.6681656241,-0.8437408209,1.2435525656,0.6121364236,-0.5362357497,-2.3874721527,-0.7291497588,0.6766259670,0.3310092092,2.5184285641,-0.9417285919,0.3908450902,-0.9795922041,0.4405451715,1.6861338615,-0.8826841712,-0.3646148145,-2.1359474659,-0.8896039128,-0.8913089633,1.8602352142,-0.0924306363,-2.5201990604,-0.4996497631,-0.7356934547,3.0227034092,-0.2779353559,-0.9125910401,-0.5229797959,-0.3131267428,-1.1275002956,1.0743371248,-0.5666452646,0.3104890287,0.6701961160,-1.6568621397,-1.3614599705,-0.3111041188,0.1598366499,-0.3078313470,0.1877021044,1.6093233824,1.2444223166,-0.2770603597,0.2751346529,-0.3467116654,-0.6917365193,0.5257941484,0.7689983845,0.3357297182,0.1524437368,1.6918798685,0.3152635694,-1.0607805252,0.6609638333,0.3341110945,-1.0415834188,0.8687285781,0.8544582725,0.1155287027,0.3381574154,1.2941756248,-0.2241853923,0.5553392172,0.8699635267,1.2132816315,0.1029268280,-1.5269670486,0.1696930826,-0.3773308396,-0.1566898823,-0.8203327060,-0.5906712413,-0.5726389885,1.7057299614,1.0661014318,-0.8808380961,1.9740517139,-1.5351676941,0.0559960082,-0.1033231318,0.2611945570,1.6715939045,0.6242154241,-0.9938521385,-0.0939270034,-0.6858149171,0.3675427139,-0.1992009878,0.6083980203,-1.5106667280,0.5414758325,-1.5780515671,1.3849695921,-1.3922752142,0.1662127376,1.1939231157,0.1069043130,0.0348040052,-1.3020936251,-0.7385377288,-0.9714508057,-0.1246909872,-1.2599545717,-0.5691602230,0.0913027450,-0.3601581752,-1.2885582447,-0.6923422813,0.0218632966,1.1481493711,0.3199811280,0.6208224297,0.1437385976,-0.0351644456,-0.2080980837,-0.7999038696,-0.0143128783,1.8700890541,-0.8725613356,1.9158043861,-0.5309497118,0.5074033737,-0.2050864398,1.8342417479,1.3920772076,1.2333165407,-0.0904451087,-1.6107214689,-1.2150744200,1.6213306189,1.3490490913,-1.2004847527,0.4088242948,1.6381580830,-0.0337113850,-2.1315181255,-0.6664378047,-0.3451897502,-0.5859259963,-0.7312455773,-0.8802397847,1.0734250546,-0.2296246886,-1.1476899385,0.0753600448,-0.1252810806,0.5062884688,-0.0693661049,0.0646183267,1.8327145576,0.6647765040,-0.3912880421,2.0176594257,-0.6505314112,1.8023506403,-1.4049191475,-1.0420913696,1.1070687771,-0.5325237513,-0.3083402216,-1.1807949543,0.1285699606,0.1529561281,-0.1071198657,0.6465570331,0.2372447997,0.6004552245,-0.3670341671,0.1296212673,-0.7611243129,-0.0786540359,0.7158681154,-0.4898069501,-0.0783000439,-0.2104012817,-2.9151592255,0.0618991032,-0.8712686896,-0.9809957743,-1.3866854906,0.2422163934,0.7125367522,-0.1848194599,2.3176703453,-0.4459954202,0.5021077394,-0.2677321136,-0.6174522042,0.0102121448,-0.8748270869,-0.5692952275,-0.2101370692,-3.1677110195,-0.9791932106,-0.4656033218,-0.8843027353,0.0018855287,1.6177743673,0.7415726781,1.2843861580,-1.5041314363,0.3272034526,1.0130852461,1.0509754419,0.1386350840,0.1534719616,-0.8860257864,-0.2906185389,-0.4992392659,1.0161581039,-0.3753769994,-0.8682446480,-0.9607298374,-0.9157308340,-2.2028121948,-1.2302342653,-1.0565544367,0.6787397861,0.4913366139,1.1512709856,0.2273500413,-0.3140943348,0.9650218487,1.1202888489,1.4143911600,0.1416300088,-0.6327657104,1.1599075794,0.9035273790,0.3643698692,-0.1275601387,-1.2958214283,0.4469485879,0.1940546483,1.2936275005,0.2017951459,-0.8351511955,-0.0646853894,0.1063179448,-0.7791896462,1.3193002939,-0.0662499070,-0.1504552513,0.5341873169,-0.4398691654,-0.0537598990,-0.8293182850,-0.8617116809,0.7136631012,-0.3939204812,1.5737469196,-0.0540837012,1.4036841393,0.1378640980,0.9466567636,-0.7069780827,-0.4565291703,-0.1137186959,-0.1762137711,-1.0199981928,-0.2759044766,0.7262592316,0.2267369032,1.0947389603,0.2019783854,0.3519686162,1.2753775120,-0.0727279261,-1.5853526592,2.0832924843,0.9841842651,-0.9553976655,-0.1030969620,0.1650699079,-1.0748144388,-1.8021926880,-1.3359909058,0.3166110814,-0.2559000254,1.7907859087,-2.5822634697,-0.7786031961,-0.8376648426,0.3916146159,1.1735594273,0.1578970551,-0.0654573068,-1.0033574104,0.4908643365,-0.3393624723,0.2656250000,0.5900098085,0.1851583868,1.1900016069,-0.0636883900,-0.6513484716,-0.1623256058,-2.4267354012,-0.3015221357,0.8572072387,-0.3075442612,1.3093880415,0.1426732540,-0.0542080179,2.3609998226,-0.5969130993,-0.9994596243,-2.0351839066,1.2536141872,-0.0141155524,1.1488707066,0.3340318203,2.5600366592,0.3605966866,0.6146651506,-1.4186687469,0.2727081180,0.0324210338,0.1732143015,1.2016236782,1.1515592337,-0.8048486114,-0.4166365862,-0.8107392192,-0.2680552602,0.7969276309,-0.2536909580,-1.2414793968,0.0307318419,-0.7246635556,-0.0614210144,-0.0980322510,-0.1273739636,-0.8733004928,0.8253334761,0.3285685182,0.2195947468,-0.4676854312,-1.7725604773,-0.0706478730,-0.8255471587,-0.8020666242,0.7796689868,0.0053337635,0.5974035263,-0.5471351743,-0.5485429168,-0.0285736788,0.0145894540,-0.8462850451,-0.3286907971,0.5849106312,-0.0293410309,0.3513242304,-0.6039078236,0.6773921847,0.8920910358,-0.3698989749,0.8443539739,-0.9569555521,2.1414206028,-1.4383490086,1.8881260157,0.2543646097,0.1823499501,-1.8379988670,-2.3626091480,1.9306805134,1.1447869539,-0.7892955542,-1.3583947420,0.1193050891,-0.5391947627,-0.8748807907,-1.0574221611,0.1377330273,-0.1817522049,0.3828250766,-0.6502447128,-0.4013140500,1.5177444220,-1.1044421196,0.4088673890,-1.6362469196,-0.0767254755,-2.1334729195,1.6754659414,-1.0141512156,-0.2841005921,-0.7273792028,-0.1547815204,-0.3518456221,-1.6101245880,0.3806446791,1.5120161772,-0.3957258463,-0.3997440934,1.0012264252,-0.5169299841,0.2179621607,0.0726020262,0.8056242466,-0.3302493989,-0.5640383363,1.6068236828,-0.8795584440,-2.0162665844,-2.8408839703,0.0471107960,-2.4121069908,-0.4298157692,-0.2259212136,-0.2872554958,-2.6355597973,-0.0566891581,-0.3242926300,-2.4704289436,0.1055299938,-0.9959416389,0.3086238503,0.9671957493,-0.5396192074,0.6040809751,0.5914162993,-1.0520744324,0.2196249813,1.1837112904,0.7854421139,0.2140046954,0.0103036715,-0.4791815281,1.0802093744,2.2894952297,0.5970520377,-1.0285168886,-0.8583711982,0.5456027985,-0.4148845971,-0.3353210390,0.1510142237,-1.1208082438,0.4330037832,1.5839723349,-0.4517824650,0.7348692417,0.6062211394,1.1804046631,-0.2156865895,-1.9402424097,0.7674831152,-0.6204615831,-0.9424259663,-0.7667592168,-1.7198344469,0.1882339567,0.3915354908,-1.2951434851,-1.4637438059,0.4099708200,-0.3732828200,0.2660309076,2.2915365696,0.8822026849,1.2864061594,-1.0476447344,-0.5300865173,-0.8190235496,-0.7607998252,0.6160025001,1.4188951254,-1.2633959055,0.9278722405,1.2578333616,2.5271196365,0.2058767378,0.4043089151,0.9949845672,-3.1527338028,1.2946237326,0.9710022211,-0.1420307904,0.5478397608,-0.8206241131,0.3207755387,-1.1367980242,-0.3007896543,1.0672885180,1.1049232483,1.0061985254,-0.6842412949,0.4629309773,-0.6022585034,-1.8163396120,2.4398572445,-0.5302162170,-0.1656367332,-0.4852881432,0.3775443435,0.5550758839,0.1274569929,-0.5471289158,-0.3199679852,1.2949386835,-0.6124832630,-0.1371923089,-0.2731872797,0.6984583139,-0.9401183724,1.2994360924,0.8181514740,0.7731116414,1.0036376715,1.5827988386,-1.2974874973,-0.1434350908,0.6647178531,1.7826393843,-0.5892428756,0.2183041722,-0.9415503144,0.6296509504,1.4211704731,1.8153684139,0.4850921035,-0.8563700914,0.6953250170,0.7074752450,-0.9068002105,-0.7238519192,0.8457453251,0.6591275930,-1.3648034334,0.9885088205,0.9899643660,-1.4283225536,-0.2611402273,0.6861331463,0.6731824875,-0.9871585965,0.3236202002,-0.2243195921,-1.3043832779,-0.9144351482,-0.0288481209,0.3471129537,1.9157763720,1.3639667034,-0.0679871738,0.0099768415,-0.7806731462,-0.3309215307,-0.5239000916,-0.7487209439,-2.0122323036,-0.7074913979,1.0903810263,-0.1148329824,0.7587329149,-0.8750514984,0.1420132518,0.7049495578,0.9195414782,0.0968873128,-0.5733492970,1.3557649851,0.6867563128,0.5227616429,1.4819657803,-0.5568839312,-0.4434660375,-0.6686267257,-0.2037937194,-0.2320554256,-1.2747259140,-0.5040209889,0.1536800563,0.3864961267,0.1177268252,0.4147295058,-0.4290784895,-2.1149220467,0.1111558527,0.5690610409,-0.5074170828,-1.3116228580,-0.3538000584,0.9582650065,-0.4444060624,0.4389349818,0.6684995890,2.0895423889,-1.5145853758,-1.0995954275,-1.9046037197,1.4437774420,-0.3302248716,-0.9572323561,0.3254705071,1.1758222580,-0.3314490020,-1.9969503880,-0.2365534455,-0.0082780914,0.2744103074,0.0309559889,0.4002328515,-0.7249093652,-0.1263285577,-1.1013489962,1.3815333843,1.8019288778,0.0788859054,-0.8572096825,-0.7831746936,-0.6566607952,-0.5514259338,1.1561759710,0.0486259237,-1.4882011414,-1.7478359938,-0.4349352121,-0.5980690718,-0.0105753476,0.6441072226,0.8070641756,1.3366454840,-2.4222583771,-1.7629585266,0.4242415428,0.5227168798,1.2409411669,-0.9768437743,0.5091602802,0.4706636965,0.8562821746,0.5442659259,0.9753083587,-1.0318638086,1.0895196199,-0.3157981634,-0.2498181760,-0.0072620874,0.3074987233,0.7405095100,0.0923283026,1.5314687490,0.4712828100,0.7196969986,-1.2597471476,-0.8728388548,-0.7292687893,0.1062755734,-0.7407863736,-1.3908658028,0.0886164233,0.6232225895,-1.4311265945,0.9013275504,-0.3596685529,0.1025697961,0.0446388386,0.6425230503,-0.2347142994,1.9980522394,-1.0065909624,0.1190448180,-0.2422155142,0.0530792251,-1.4308447838,0.2798071504,0.6393198371,0.4337556064,1.0134214163,-0.7661970258,-0.3400665224,0.6894814372,-0.6211586595,-1.1139371395,-0.4133455455,-0.8308604360,0.1453806609,-0.7555692196,0.6801390052,0.8128879666,0.5958173275,1.0729752779,0.4843373299,-0.4979102314,1.3864185810,0.9193938971,-1.5006879568,-0.4991283119,-0.2648375630,0.4287530482,0.8467736244,0.9204974174,-1.7422208786,-1.4175399542,1.3389828205,-0.1382659376,0.5003929138,-0.8001933694,-1.1260420084,-0.7873304486,-0.4730960131,0.1702415347,-0.4686396122,-1.4204618931,1.7457896471,-1.9309419394,0.6022258401,1.0969513655,0.2393837273,0.2116515785,0.5585256219,1.0960396528,0.9194073081,0.2306050062,-1.1204822063,0.5107620358,0.7941451073,0.1340462267,-0.8106143475,0.3599536419,0.5154025555,0.0600135475,-0.7232104540,0.3722366095,0.2504935563,-0.0045491043,-0.6716938615,0.2279936522,0.1172791049,0.5441622734,0.7014442682,0.1636167318,1.9247628450,1.3642557859,-1.3011333942,1.4473772049,-0.2376226336,0.6195828319,0.2934015989,-0.5696805120,0.0819147378,-0.0124860499,1.4523462057,0.4789505899,-1.6496356726,-0.0578171164,0.6523512602,1.5945521593,-1.2960835695,-0.6454660892,0.3898889124,-0.2493240684,-0.7321791053,-1.3518134356,-0.8230043650,1.4176563025,-1.4937674999,0.6788947582,0.0714109913,-0.1779415756,-1.9323011637,0.6027720571,-0.2723703384,1.1922283173,0.9429624081,-0.1027375609,2.0723633766,-0.8419672847,-0.7306387424,-1.5093916655,0.6934100389,-0.0410907716,0.7249060273,-0.1354019344,0.7563098669,0.3674355447,0.7718367577,-2.6049280167,-1.3262532949,-1.2036824226,-0.4017079473,0.4643644989,0.3264178038,-2.6617326736,-0.7910155654,-0.3290653527,0.2054002136,0.9232746363,-0.3793618381,-0.9501160979,0.2249486148,-0.6229797602,-0.9222994447,-0.8020499349,-0.1218004450,-0.1192131341,0.1981703192,0.2027932554,-0.5831612349,-1.5477751493,-0.6242799163,-1.9537978172,-1.3120753765,-0.8792384267,-0.2546037138,1.8232898712,1.9963171482,0.4631770551,-0.2157828957,-0.0033036820,0.9925291538,-0.6906385422,0.6020773053,1.8886865377,-1.2071678638,0.0356135145,1.9553414583,0.7453075647,-0.5721513033,0.3352523446,-0.8478366137,-0.7228087187,0.8866829276,-0.9401163459,-1.9854770899,1.0203789473,-0.4592664838,-0.5595240593,0.4180965722,-0.1041441485,-1.3117289543,-1.1925373077,-1.3618315458,-0.2454625666,-1.3739359379,-0.1230784133,1.3046419621,-0.3713450730,-0.1312476695,0.7927514315,-0.8698234558,-0.1680863947,-0.6188244224,0.3212174177,1.1077984571,-0.8575962782,-1.2911204100,-0.1478271186,0.8769837022,-0.4112337232,1.2420055866,-0.2285336703,1.3366562128,-1.6899101734,0.2851883173,-0.9931355119,-0.2546955347,-0.7716149092,1.0934343338,0.0426416881,1.5614147186,-1.0928755999,-1.6933665276,-0.4665859342,1.6828256845,-2.1104826927,-0.0419604629,-2.0320513248,1.1672431231,-1.0663675070,0.4055701494,2.9667816162,0.3135769367,-0.1272612065,-0.0019367305,-1.7865858078,-0.7973675132,0.0983067825,-0.7250729799,-0.1266469806,0.0654597431,1.6557376385,0.1442626268,-1.7148323059,-0.7256135941,0.2546228766,0.9104588032,0.4652565122,1.3994613886,-0.7664901614,0.1988223642,-0.6781148314,-2.5610532761,-1.2301489115,0.5389909148,0.4202900231,-0.1574928910,0.7148252130,0.0710679144,-1.8049743176,0.0158903282,1.6363402605,0.1195532903,1.5923948288,-1.0496184826,0.0179251097,-0.7340781093,-0.0044836081,0.2723886967,-0.1416033208,0.1716030240,-0.4047521949,0.2403499484,1.2817729712,0.3288176060,-1.0603730679,2.0009100437,0.3797760308,2.0110740662,-0.2068622559,0.7860251069,-0.5047575235,0.7063904405,-1.1786493063,0.3923666775,-1.0244634151,1.8500113487,0.5193219185,-0.9555152655,1.3364324570,1.4916113615,-0.5875380635,-0.2249176949,0.5363004804,-0.4077191949,1.2315989733,-0.0209633969,-0.7538880110,-0.4608057439,0.1677348167,0.6560636759,-1.0530261993,-1.1236027479,0.5489697456,1.1629155874,1.0196343660,-0.0328121632,-0.7612766027,-0.3375090957,-0.0431881398,-1.3949629068,1.6447660923,0.6821311712,-0.2217063755,0.7762494683,-0.1715980470,1.7823339701,-0.4120734036,0.3940093219,0.4754644036,0.0328231864,1.2554707527,-0.5431787372,1.2304182053,-0.8765879869,0.9375509024,1.1339820623,-0.3679790795,0.9494005442,0.9975679517,1.0307329893,2.1102905273,0.7695582509,0.5826106071,0.3467871845,0.0634680912,0.7141479254,0.2264734805,2.0048527718,-1.0984022617,1.2317520380,-0.8595981598,-1.2654389143,-0.6585014462,-1.2234858274,0.8852560520,-0.4570990801,-0.5080608726,0.1632690579,1.0896167755,0.3817169368,-0.0259354860,-0.4530935287,0.2448261827,-0.0249542110,-0.5475708842,0.8203950524,-0.0454053171,-0.1523360014,0.1439412832,-0.6669614315,-0.2771725059,0.3978259265,-0.4932720065,-0.9815487266,0.0112280538,0.0622864105,0.1676025093,-0.3985056281,-0.7404897213,0.8559097052,-0.8888737559,-0.3696354628,0.7236633301,-0.8088818192,0.1112069711,0.8000018001,-0.2828109860,-1.3591109514,0.0597446077,1.1427609921,0.9351323247,-0.5741488338,0.8525617719,0.3621784449,1.7871932983,-0.1630001217,-0.4958277643,0.3296086788,0.1071355641,-1.2501461506,0.2655957639,0.9955238700,0.3480997086,0.5811783075,-2.4376964569,-1.1687315702,-0.0813406780,-0.5605207086,0.8873816133,-0.6016888618,0.6948810816,0.3314882815,-3.5329918861,-1.4900625944,0.9414265752,-0.0608544908,-0.2282129824,0.2961200774,0.2064784765,0.9235963821,0.8165992498,1.0421718359,0.6450840831,0.3433330655,0.4462094009,-1.2916414738,0.2994377315,-0.6783190370,-1.4601011276,1.0403785706,-0.2990740836,-1.3489027023,0.4652444422,-1.8370354176,-0.8784723282,0.9383602738,-0.9043878317,-1.5784652233,1.0723438263,0.2476393133,-0.8018630743,-0.4048002362,-0.0732393563,0.9851552844,-0.7021204829,0.6982021928,-0.6263809204,0.7441608906,-1.2284842730,-0.0449464247,-0.6855147481,-1.4545799494,2.1253712177,0.6591351628,1.0927282572,1.2526097298,-0.6281160712,0.4327580929,1.6550632715,-2.2945992947,-0.0502533279,1.5303075314,-0.5409997702,1.1727341413,-0.5400050879,-0.4364598989,-0.0967092067,-0.4712429643,-0.6747933030,0.5726812482,1.1124210358,-0.0922250971,-1.5018668175,-1.0531485081,0.0086183911,-0.0545431152,-1.5454921722,-1.6756819487,1.5852866173,0.0307595395,1.1762250662,2.2206773758,-1.2185657024,0.5149343610,0.9203640819,0.5588316321,-0.0089860512,-1.4906351566,-1.3091335297,-1.5451923609,0.4636520147,-0.8842917085,0.2086382061,-1.3636584282,-0.5502992868,-0.3902366161,-0.5923804045,-1.5842198133,-0.0137870312,0.0795252994,1.9029623270,-1.1827250719,0.2084009647,0.1835195422,0.4632900953,0.3212157488,1.2559412718,-0.1729954481,-1.1393396854,0.4833806455,2.6549761295,-0.0624392033,0.2982380688,-1.1094950438,-0.4198685288,0.0068994844,0.3850246668,-0.5606642962,0.3175287545,-0.3674174547,0.4738435745,-0.5514103174,-0.9766073227,0.5305664539,-1.0486661196,0.2787618637,-0.8301656246,-0.1464786083,0.4386092722,1.0080722570,0.1367931962,0.6738983989,0.3898560107,2.6003527641,0.8472453356,0.8475563526,0.4127884507,1.4216381311,0.4300921261,0.4178426266,-1.4710381031,0.2721470594,0.8424003720,-0.2040570527,-0.8711925745,0.6280260086,0.2913725376,0.5029097199,-0.7581620216,0.1996175051,-0.8232809901,1.2004920244,0.5533089042,-0.8662698269,1.6752365828,0.5223246217,-0.0690548792,-1.2152057886,-0.0013798352,-0.4171872437,1.5942960978,-1.9580565691,0.9489240646,-0.5740866065,0.2111291140,0.9112172127,-0.2032184899,-0.8871902823,-0.3309149742,-0.7680382133,-0.2359905690,-0.9237763286,-0.0109956544,-1.9898606539,2.5647330284,-0.6217227578,0.0064217350,-0.1358610094,-1.1649965048,0.6981079578,-0.5372963548,-0.1233563721,0.2467169762,1.5969997644,1.5088599920,0.8951876760,0.3103065491,-0.2586609125,-0.0645775348,1.1478109360,0.7551135421,-1.5989308357,-1.0639597178,0.8607670069,-0.9049039483,1.0084027052,-1.0110167265,1.8463071585,-0.7842986584,-1.8329027891,1.6607512236,-0.1428315938,0.1744260192,2.4861826897,-0.1852011085,-0.3658530414,-1.5189673901,-0.8197247386,-1.4171614647,-0.7043625116,-0.0423857495,1.9210053682,-0.2739804387,-1.6898438931,-0.2022707313,0.5238206387,-1.7040828466,-0.6559479237,-0.2088008374,-0.4546749890,0.6832018495,-0.1399490386,-0.0158994384,1.2031900883,-2.3218762875,-0.8002865911,0.1409174502,-0.8941115737,0.1592972279,-0.7806494236,-2.2411077023,-0.6832921505,-0.2099120617,0.2427671105,0.5994983912,1.7587484121,-0.4734762311,0.9576066732,1.0439326763,0.3215130866,1.1165105104,-1.1664500237,-0.2707373798,0.8627887964,-0.5434683561,0.4097805321,0.8309146166,-1.2992010117,0.8051446080,-0.0502262339,1.2870852947,-0.0100108348,2.0543682575,0.3049731255,1.5535672903,1.2411839962,0.9481426477,-0.8539407849,1.0286288261,0.0647694692,1.0538676977,0.1396375895,0.6957244277,0.2910648584,-0.9009956121,1.1273261309,-0.0948203057,-0.8096640706,-0.4723818004,-0.6017938852,-1.5425246954,-1.3817493916,0.0491434112,1.0174921751,0.2119679451,0.1593198776,0.2184775919,0.0306259133,-0.0538404770,-0.8706930876,-0.2231848836,2.4912929535,-0.5015062094,1.0344709158,0.2444898188,1.4917860031,-0.6608645916,-1.4219645262,-0.2831400335,-1.3320243359,1.7224861383,1.0793416500,-2.1341109276,1.2406805754,-0.7852844596,0.0782570988,0.6343486905,-1.2520850897,0.7410355806,-0.6997129321,0.1451499909,-0.1370168477,0.9041714072,-0.1804198623,0.0712918416,-1.4128985405,0.7510366440,-0.1180425957,-0.1724923551,-1.7639014721,-0.0395201556,0.7621546388,-0.5221664310,0.7228161693,-0.1106093898,0.4198686481,0.8827266097,0.1813685149,-0.6062692404,1.4166896343,-1.0538520813,-1.7832826376,0.1536631137,0.7696893811,1.4886592627,0.2027274966,-0.3299671710,-2.1470396519,0.1910541207,1.2473070621,-0.6160305738,0.9013956189,-1.1003696918,0.0428022183,-0.2240002900,1.3721675873,0.2639842331,0.9908525348,-0.6108818054,0.6185465455,0.8091144562,-0.0958564207,-2.4742417336,-1.4627320766,1.2571899891,2.1967086792,-0.6468477249,0.4778275192,0.4487043321,0.8870905638,-0.5353265405,0.8139606714,-0.9202001095,-0.9111188054,-0.4403496683,-1.0960507393,-0.7820392251,0.3184137642,-0.8955340981,1.3307368755,2.5789258480,1.6368669271,-0.1470758021,-0.5990946293,1.8969904184,0.0959065408,0.3653283119,-0.8044139743,-0.1963423491,0.6994704604,0.9716321230,-2.4430494308,-0.0891370699,1.6713135242,-0.0061685285,1.3528705835,-0.7780772448,-1.2525608540,0.5983073115,0.7732192874,-0.6087434292,0.9746813774,-1.3182982206,-0.8068457842,-0.0047311722,1.7748740911,-0.6146159172,0.4845753610,0.6594731808,-1.1879068613,-0.3992961049,0.6266974211,0.4242372215,0.9081152678,0.0307728127,-0.8630605340,1.9725608826,0.9605245590,0.5259451270,0.1010104865,0.9442236423,-0.9346194267,-0.3141328990,1.5740138292,0.8825586438,1.2932610512,-2.2646677494,-0.8570740223,2.5405399799,-0.9077283740,-0.0705576167,1.1092141867,1.1942255497,0.1073936000,-0.7081599832,-0.1220684573,-0.1524242908,2.7508671284,1.3673774004,0.2572293878,-0.7890204787,-1.9807367325,-0.0600517057,-0.3794493377,-0.2172252089,-0.1736208946,0.4301603138,1.1614133120,1.8514386415,1.1475257874,0.4402486980,1.6443941593,0.8660095930,-1.0846067667,-0.7280923724,-0.7247751355,1.1563705206,-0.6895301938,-0.2457161993,0.6665600538,-0.1587394476,-0.9480696321,0.6335174441,-0.8753589392,-0.3239900768,-0.4539276361,-1.1788517237,-0.0075284201,-0.3648636639,0.7042046785,-0.8619546294,-0.8080089092,-1.4834641218,-0.5682203174,0.0640545860,-1.3926751614,-0.4957585931,-0.9867656231,2.2077383995,0.8689068556,-0.1288353801,-0.2259429991,-0.3784595132,-0.1942718327,-0.4684728384,1.3292363882,-0.5330204368,0.9046695828,1.6821259260,0.0649134219,0.9101820588,-0.6161113381,0.5321943164,0.1378296018,-0.7966747284,-0.3984784782,-0.7223089933,0.1889540851,-0.3044525981,-0.5599074960,0.2821009755,-1.0995750427,-1.1855823994,0.1406255960,0.1761286408,-1.1918876171,1.7644279003,0.8393975496,-0.1007546857,-1.5601830482,-0.2472936213,-0.6002095938,-0.5832691193,0.5630375743,-0.2304146737,-0.5821666121,-0.8668646812,0.1507098377,-0.8167546988,-0.7604181767,-1.3662077188,-1.5394088030,-1.5751433372,-0.4525258243,-0.3810411990,-0.2660856843,-0.7493767738,-0.8499608636,-0.3706573248,0.0562004596,-0.0263963435,-0.0762054101,0.0347596668,-1.7043470144,-0.3087723255,0.0925105289,0.3055296242,-0.6038087010,-1.3270583153,0.9827371836,0.2591477334,-0.5748916268,0.2182596624,3.1320657730,-0.1381565481,-0.7192556262,-0.0967331678,-1.2724033594,0.1888975799,0.9075344205,0.4408209026,-0.5638342500,-2.3636741638,1.3404798508,-0.4956731200,-0.1394995302,-0.5335831642,-1.9022147655,0.7844576836,-1.7396374941,-1.0470457077,0.0059125903,1.1089094877,-0.9378197789,1.2084882259,0.6415619850,1.1708856821,0.9288407564,-0.4969819784,-1.6088763475,-0.2479011863,0.3180273175,-1.4168658257,1.8286755085,0.1195928678,0.7719916105,-0.7462855577,0.1041880324,-0.9672582150,-2.6459031105,-0.1165833101,-3.1117084026,1.9623993635,0.8309456706,0.1377648413,-2.3812682629,0.6896886230,-0.1855984628,0.3543067873,0.9753615856,-0.6475732327,-0.8925844431,-1.0086665154,0.0782525837,-0.6183305979,0.6852272153,0.1687427461,-0.8541080356,-0.2065338194,0.4088042080,1.0348843336,-1.8947924376,0.0465237722,-0.4570004940,-1.2192322016,0.8203142881,0.3576781452,-0.2713727951,-0.0683235750,0.2432604730,1.3800150156,1.1533381939,-0.9297128320,0.5261302590,0.9035075307,-1.2131354809,0.2522619963,-1.5607283115,0.7069227099,-1.2718977928,0.5051910281,-1.1626993418,-0.0957609937,1.2475578785,0.4460627437,1.6918580532,-0.3250173628,0.6188752055,0.3587437868,1.6347857714,-0.5673042536,-0.6678325534,-1.5126785040,-2.0843534470,0.9316207170,-0.7939562201,-0.1389047503,-1.0928068161,1.3225532770,-1.9624245167,-0.5996420979,-1.2197872400,-0.9119546413,0.4276641309,0.0259381942,-0.4532708824,-1.7074309587,-0.8331914544,0.7614836693,0.0791674033,-0.6992869973,-0.8943839669,-0.2679222226,0.2194266021,-0.8759810328,-0.5073649287,-1.5110708475,2.2356791496,-1.3427168131,1.5245552063,-0.3868552744,0.1256234497,-0.1761559248,1.0805300474,2.1072673798,0.9131340384,-0.5150635839,-0.5568994284,0.1934793591,0.2294926941,0.0569185466,-1.5624272823,-0.3017155826,-1.1742011309,1.6733289957,0.3321471512,-2.5649945736,-1.0484580994,1.5249539614,0.6937811971,-1.4968557358,-0.0413185954,0.0577384606,-1.4827886820,0.6641077399,-0.4808337986,-0.5935848355,1.5506532192,0.2863505781,0.3010305166,0.7863500118,1.0970948935,1.0758353472,-0.6738184094,0.3312270939,-0.4622066617,1.8852907419,0.0494275317,0.6119221449,-0.9082134962,-0.2488493621,1.5805485249,0.5710447431,-0.0100161182,1.0434415340,2.6215713024,0.6912501454,0.0497087650,0.8760806322,-0.3577581644,1.4436415434,0.0282163415,-0.4429470897,0.0530390367,0.0762220472,1.1364022493,-1.6470911503,0.6877381206,0.8901814222,0.7812303305,1.3263591528,0.0477996878,2.5010333061,-2.1394217014,-1.9078707695,1.3412349224,0.4777317047,-0.0139821116,-0.1222880036,-1.0256145000,-0.3868508935,0.4203441143,-1.0873005390,-1.2217711210,-0.5821444392,-0.8056239486,-1.0757553577,-0.1141380593,0.7272791266,0.2058192939,0.0688363239,-0.2044557482,-1.1473109722,0.4968492687,-1.4591329098,0.1536498815,0.5128298402,1.3853830099,0.3292523623,-1.7917298079,-1.6369482279,0.8037596941,-0.3507469296,-0.9165260196,0.6277545094,-1.8771381378,-1.1168591976,2.0002963543,0.9762254953,-0.2480376661,-0.5302870870,1.9402929544,0.0267861206,-1.3505047560,1.7754563093,0.7663806081,-1.2515767813,-0.4576311707,-1.6291935444,-0.0677957162,0.6024122238,-0.9290607572,-1.2449533939,0.6113210320,-0.1610737294,0.0371984690,-0.2587880194,0.6847470403,0.3342157006,1.4733811617,0.6087473631,1.1020613909,-2.3822624683,0.6188970208,-0.6561591625,0.2269476801,0.2247478813,0.1287886500,1.0781495571,-1.5613390207,0.2265433371,-0.3973863423,0.8339469433,-0.6040529013,1.7165282965,0.7048300505,1.7899045944,0.2359161973,1.1899683475,0.9303969741,-0.5528115630,0.8526928425,0.4013674855,0.0542528853,-0.9132806659,0.2976969779,-0.4440785944,0.8972502947,0.8655430675,1.1715748310,-0.1977638453,-0.2246027142,0.0634627566,-0.1137804464,-0.7993347645,-1.0984220505,-0.6201526523,1.0808788538,-1.2932568789,1.0611051321,0.5813468099,0.4603781402,0.5116732717,-0.1236280203,-0.3366009891,2.3701324463,-0.2713805735,-0.9819604158,2.4698693752,-2.2890300751,1.6352475882,2.1706984043,1.7595663071,1.3014839888,-0.3608497679,1.2908350229,0.0412799045,1.0770276785,-0.8863621354,1.3306670189,0.6597825289,0.4063103199,0.0115959998,1.3941509724,-0.8768700957,1.2024830580,-0.2052872479,-0.3123206198,-0.1067714840,0.6414546371,0.4451971352,0.8133208752,0.4083485901,0.7939832807,-0.4251754880,0.4888560474,-1.1338469982,0.3686774671,-1.5876305103,-1.1317766905,0.3729013801,-0.0210948307,0.1209617406,-2.4760849476,1.0929088593,-0.2816660404,1.1428662539,0.4579641521,2.0584762096,-0.6132389307,0.2567722499,0.0170761682,1.2307608128,1.3749313354,0.8315657973,-0.4026392400,2.3707995415,-1.1325217485,-0.7696317434,0.9405528307,-0.4137949049,-0.1175819635,0.7805142403,1.8320804834,0.3148280978,0.3389058113,0.4954504073,-0.0342098735,1.2256599665,0.6079592109,-0.3224415183,-1.5470880270,-1.8527430296,0.7457096577,0.0043871086,-0.3397135139,0.6516956687,0.8055987954,-0.2371622622,-0.1931099892,1.1936423779,0.1004671603,1.0995388031,-0.2976596951,-0.1392439753,0.5259703994,-1.7792139053,0.7952412963,-0.2315692008,-1.1396455765,-3.1083474159,0.2638598979,0.1089628115,-0.7766565681,-1.1014711857,-0.1453552842,-1.4054925442,-0.0237163752,0.2195326090,0.5424352884,0.8379007578,-0.2166462690,0.2039635777,0.6850985885,-0.2847076654,0.7809556127,-0.3086790740,-0.3514919281,0.9503691196,-1.7364805937,-1.2029470205,-0.1090737283,2.3331315517,-0.7135651708,0.2003588378,0.1698276401,-0.8578826785,-1.7039403915,-0.1923047006,-0.6373355985,1.4842764139,0.8991172314,2.2821702957,0.2180647701,-2.0747385025,-1.3818309307,1.2608627081,-0.5096740723,-1.3451678753,1.1649746895,1.5543422699,0.6470571160,1.7453366518,-1.4800138474,-0.8186712861,-0.6925798059,0.3354967237,0.0370089076,-0.0598824024,-1.0103763342,0.2989828289,-1.2845501900,0.1014768258,-0.5032425523,0.8546702862,0.4338257015,-0.5709214211,-1.6417970657,0.2938322723,0.7571172118,-1.2316056490,0.5295363069,-0.3947353959,-0.5521669388,0.8162702918,0.0821020678,0.5902984738,-0.0606680997,-0.9304512739,-0.4575162828,-0.5528289080,-1.0609980822,0.1770114452,-0.7643995881,-1.8346927166,-0.3263114691,-0.7260974646,-0.2625757158,0.2421620190,0.8234714866,-0.3505697548,-0.1155276671,2.2433609962,-0.6450213194,0.5869686007,0.1855111122,-1.3059544563,-0.0481009148,-0.5584850907,0.9967713356,-0.1201881021,-0.0914791599,-0.6160403490,-0.5912835598,0.5793107748,0.8839061856,-0.6082174778,-0.1807097793,0.0818651319,-0.3470787704,1.5814223289,0.3732798398,0.0022905916,-1.1152783632,-0.8789777756,0.3264580667,-0.0843966827,2.0768249035,0.3223586380,-1.4704591036,-0.3605157733,-0.0795432106,1.3762940168,-0.3133580089,-0.3769643009,1.0150228739,-1.6130084991,0.7662905455,0.1537739336,-0.5736240745,-2.0595908165,-1.2742669582,-0.4551030099,1.1831039190,1.2629544735,-0.8028033376,-0.6116998196,0.2680445313,2.1303925514,0.6933071613,0.8110494614,1.6245647669,0.0246582367,0.1792008579,-0.6756305099,-0.2165194303,-1.7439608574,-1.0947178602,-0.5515912175,1.1397629976,-0.1814203858,-1.0873012543,1.9065188169,0.4820602238,1.2316817045,-0.7144633532,0.7393344641,-1.4779632092,0.8479858041,-0.6084827185,-1.4399133921,-1.2956974506,0.2913162410,-0.9487263560,-2.4500293732,1.2459511757,-0.8626870513,1.2747393847,0.8515521288,-0.9107000828,-0.0041014827,-1.0741207600,0.1243414879,-1.6088092327,0.3258252740,-0.5649567246,0.2144881934,0.1281290799,1.3411060572,1.1804949045,0.6733310819,1.5220293999,1.1019228697,-0.6039502025,0.4356611669,-0.4059346914,-0.6738638878,-0.2382538617,-0.3904451728,-0.9828028679,1.2583773136,1.6638858318,0.0410357155,-1.3966635466,0.1359305084,0.0167859215,0.6521763206,-0.2972988784,0.1731460541,0.1411231160,1.0567188263,1.6228011847,-0.5794419050,0.4272536039,-1.5739947557,-0.8606178761,1.0731964111,0.1164292842,1.1253268719,1.0621339083,1.8113048077,-0.2671763003,0.6486790180,0.6535865068,2.1206243038,0.3569327295,-0.3855935633,2.1172261238,-1.2179837227,-0.3329633772,1.1804958582,0.4870519936,-0.0225906167,-0.1032814756,0.2909719646,1.6734399796,0.6995837688,1.6279866695,-0.9171071053,-0.4649128914,-0.7849975228,0.1026836857,1.7261559963,1.4697047472,-0.9684790373,0.0554991364,-1.7402436733,-0.2492827326,-0.0431437008,-1.3587737083,0.6815609932,-0.8693833351,1.2369399071,-1.8863832951,-0.2015711665,0.5212758183,-0.8070146441,0.6563775539,-0.6166521311,1.0231083632,1.2899951935,0.6691089869,0.5692141056,1.3590040207,-1.2761324644,0.2012262344,0.1072357595,0.0752140060,-0.5331254601,0.2735618353,1.3830242157,0.4706042409,-1.1795712709,-0.3537247181,-0.5190734863,-1.1926151514,0.1233324781,0.3509021699,-0.5091461539,-0.0536347479,0.5855531096,0.5949400067,0.2779593468,1.2884949446,-0.9481160641,-0.4234532714,-1.1077837944,1.2787302732,2.0269575119,1.4635083675,-0.9697679877,2.6235475540,1.2805155516,-0.1222272217,0.3515428901,1.0016529560,-0.0150964251,1.6880726814,-0.2948833406,-2.3703005314,1.8436559439,-1.2131029367,-0.2624935508,0.9433795810,1.8394038677,-0.8153470159,-0.9672814608,-0.2367526293,1.2682460546,-1.8260550499,-0.6101045012,-0.8524032831,2.4874143600,0.6338421106,0.7834047079,0.6262134910,0.8847147226,-1.1235461235,-0.9794437885,0.3526352048,0.4729247093,-0.2141827941,-0.7229529023,0.0829834938,1.3534119129,-0.4975259006,1.0918790102,0.5944721699,-1.4659571648,0.8361387849,-0.3421808183,-1.0087279081,-1.2426744699,0.3281867206,0.0251218807,-1.8685960770,0.9150018096,-1.9452970028,-0.8615595698,2.1733384132,-0.9754824638,1.6710414886,0.4690485597,0.8657920957,-0.4328330755,1.2893782854,-1.0481760502,1.3680763245,-1.3068273067,0.9040389657,0.9369824529,0.8598939776,-0.8227170110,-0.3654539287,-0.6739743948,0.3190602660,-0.9016777277,-0.4370117188,1.0818015337,-0.7992702127,-0.8296168447,0.5022249818,0.3412137330,-0.3512504399,-0.3503727615,-1.8021380901,2.2804696560,-1.1720472574,0.2263271660,0.2877822518,-1.1337782145,-0.3909066916,-1.2376701832,1.0095298290,0.5217128992,-2.2821540833,0.5881370306,-0.2536352277,-2.5339996815,0.0288899709,0.1474454105,-1.5530334711,-0.1875560880,-0.2964601815,-0.1737500578,1.6984698772,0.9925410748,-0.1834912300,0.0390073396,1.2886043787,1.1899611950,1.6747417450,-0.0493365452,0.6665617228,-0.3943178952,0.4373920858,1.0100117922,-0.2434471995,0.4705701172,-0.0913033038,-0.1496414989,-0.1203377172,-0.9248952270,3.0170164108,-0.2714706659,0.4221477807,2.1623134613,0.8745349050,1.3869328499,0.7160037160,0.8574240804,-2.4605793953,1.4067883492,0.7826843858,0.0132020181,0.9728497267,-1.4302023649,-1.5503321886,0.7042499185,-0.0613900833,0.6003428102,0.6352524161,0.4287099242,1.4980370998,0.3880011737,-0.4563947618,-2.7111141682,-0.4926683903,-0.6083946824,0.9790099859,1.3553739786,1.1713775396,0.4362692833,-0.8042359352,-0.7024526000,0.3011744618,-1.4273091555,0.9567792416,0.6883066297,0.4607406855,-0.5390653014,0.6746558547,-0.8313179016,-1.0302064419,-0.0380053222,-1.8747175932,1.3076663017,-0.2346269339,-1.3506914377,-0.4520126581,-0.4520035982,1.7138769627,0.1253602654,0.2660092711,-0.0731366202,0.2919928432,0.0841064826,1.7978950739,-0.3284988999,1.1751443148,0.5153539181,0.2937392592,0.7174130082,0.4991062880,-0.1639733016,-0.3563329577,-0.4395076931,-0.2766478062,-1.0674500465,1.8819682598,0.7912315726,-0.1282933652,1.8472059965,-1.5106694698,0.7845364809,0.4449427724,-1.2240473032,0.5322827697,-0.1730926335,0.9488574266,0.4537747204,0.0691529736,3.4170293808,-0.9167636633,-0.3978354037,-0.5361738801,-0.4047685564,0.7148522139,0.2225925773,0.6639422774,-0.1292048544,-1.1110087633,-1.0102939606,0.2644718587,0.9000436068,-0.7264199257,1.3637973070,-1.2778736353,-0.1999248862,0.5343344212,-0.4080455005,0.1374131441,-0.2867443264,2.0778164864,-0.9607052207,0.9882478118,-0.3585515916,-1.4047431946,0.9531259537,0.2088538110,0.1369061917,1.3903574944,0.4575279653,-1.3510797024,-0.4881621003,0.7812165618,-0.4035978317,-1.0870518684,-1.5355210304,1.0299673080,-0.0183984078,0.1233158112,0.2659848630,-0.9376357794,-0.2414065301,-0.3026311100,0.0925273895,-0.0816137046,-0.0960379541,-0.0317799374,-1.3813295364,0.1347098649,-0.0820175707,-1.2389616966,1.6740804911,-0.2374209315,0.9658219814,-0.7939558625,1.2590600252,-1.5339493752,0.3371162415,1.4419755936,-0.4797958732,0.0273850411,0.7507920861,-0.1079000458,0.9697693586,-0.6925873160,-1.4347451925,0.3423879147,-0.6725934148,-1.7418110371,-0.0797282755,-0.3020401299,-0.3803686202,1.0125890970,-0.9325743318,-0.1049213335,0.0712086931,-0.2040427327,-0.7109842300,-0.7788132429,-0.4137320518,0.5208038688,0.1299502850,-0.1351567805,-0.6129224300,0.0145029593,0.5655912757,-0.8317987919,0.5818741918,0.6020925641,0.1391010433,0.8798360825,-0.3785371780,0.8962466121,-0.1627954245,-0.1554978937,-0.0491830073,1.0199846029,-0.5086528063,0.1819584221,-0.1886064410,-0.5281379819,0.5540053844,1.2801107168,0.5145618320,-0.2815166414,-1.8504830599,-1.4968154430,0.5677479506,-0.8508284688,0.4678899050,-1.3412883282,-0.1465302259,0.2389729619,-0.6580345631,1.4656655788,-0.5119754076,0.3634024858,0.8378620148,0.6821438670,-0.1599557549,0.8418995738,-1.6232244968,1.2753105164,-1.5744374990,-0.3053387403,-0.7655331492,1.0510780811,0.8004363179,0.2560030520,-0.6166889668,0.0854177177,-1.9206666946,-0.5267802477,-0.7869284749,-0.4115960598,-1.1991744041,-0.5750448108,0.2946201861,-0.7443304062,1.4293489456,-0.4902796745,-0.0483880341,0.6640558243,0.8327726722,1.8407005072,0.7809294462,0.0030927989,-1.5531117916,0.9506762028,-1.3810019493,1.1338344812,1.1597759724,0.1388784498,1.6293661594,0.1739115119,0.2015552223,1.5030477047,-0.4344612062,1.8117796183,2.2257161140,1.4357246161,0.7157769799,-1.1085772514,0.3848017156,-0.8877408504,0.5003702044,-0.8792350292,0.4230170250,0.8809534311,2.0490174294,0.0204322394,-1.2171998024,0.7011641264,0.5943517089,-1.5732725859,-0.7199173570,0.7867372036,3.0451655388,0.1843346208,0.7179120183,-0.1636048704,1.5786978006,-0.7018404007,-0.4428640306,-0.0944580883,-0.4445796311,-0.9633267522,-1.4163391590,0.3170681596,-0.8742064238,0.0117640896,-0.9380337596,0.4167654812,1.0110545158,0.8198906779,1.4507848024,-0.4969290495,0.9055968523,-0.0989162475,0.2817564011,0.1054915190,-0.2824602127,-2.7734065056,-1.1041206121,-0.9647773504,1.5364704132,0.5445757508,0.7791507840,-0.0502580889,-0.9385029078,-0.9562464356,0.5013201833,-1.3731353283,0.6837669611,0.7879750133,0.4322114587,-1.0507004261,-0.4315394759,0.5607248545,-0.3958632052,0.4185329974,1.0252966881,-1.0072593689,0.8607437611,0.4936594069,0.7559320331,-1.0182080269,-0.1923506409,0.5055880547,-0.3494649231,0.4047941864,-0.3316917419,0.1759418398,0.0013057090,1.2570570707,-0.2191038728,0.9023769498,0.7408381104,0.5125377774,0.9699680209,-1.3627812862,-1.5679252148,-0.0293262303,-1.8678886890,2.1712396145,-0.1571822166,-0.3564154208,0.0553524904,1.1599270105,1.2627038956,-1.3459423780,0.6730185747,-0.0750857741,1.0460783243,-0.4429310262,-0.3001503050,0.0078839790,-0.2567608058,0.9423267841,-1.5697605610,0.6863792539,0.9789968133,-0.0081998017,1.7019345760,0.2806222439,-1.4620214701,0.5297275186,1.1651798487,0.8243795037,0.8680918813,-1.7472949028,2.0696997643,-0.2578157783,-0.0249881465,0.6565919518,0.0272306334,-0.8412454724,0.2397221625,-1.7836779356,1.2204616070,0.5548753738,-0.4932431579,0.3310505152,1.0874546766,-0.1795441955,0.9982895851,-0.2980313897,2.0983877182,-0.7227540016,-0.2248633504,-0.1296203732,-0.9494423270,1.4522721767,-0.9315572381,1.8279565573,0.1612818539,0.2126344889,0.6816353798,1.1261162758,0.9266378284,-0.3534713686,0.9973428845,0.4953095913,0.8687413335,0.6141946316,1.4996018410,0.1254296452,-0.7379559278,-1.2608875036,0.3750228584,-0.6231452227,3.0864508152,0.4766899645,-1.1117894650,0.2051137537,-1.7827329636,2.1619787216,0.6303663850,0.5379341841,2.3428905010,0.1024986655,-1.9776982069,-1.9109508991,2.0136795044,0.5614098310,-1.5266704559,0.1959593594,0.6133632660,1.1159074306,-0.5647493005,0.4011000693,1.7993389368,-0.0339073166,-0.2392009497,1.6570544243,0.7138476968,0.3991074860,-0.8774254918,-0.4240868092,1.0801563263,-0.1920657456,0.3216613829,0.2953280807,-0.4288747013,0.4682311714,-0.9422526956,-1.1518111229,0.7867501378,-2.3118257523,-0.9087553024,1.6632435322,1.0761674643,-0.2712795138,-0.8323598504,-2.2843811512,0.2200830430,0.6697045565,-0.9509277344,-0.8576626182,-1.9374886751,0.8887458444,0.5036352873,2.0676424503,1.0283118486,-0.2918054461,-0.8564800024,1.6496522427,-0.1889360398,-0.3224303722,-0.5871344805,-0.9989820719,-0.0417234078,0.4708833098,0.8459716439,0.3378955126,-1.3688849211,1.9070968628,0.6046031117,2.0323977470,-1.0468131304,0.7598228455,0.1940415055,1.2512792349,-0.3850702941,-0.1691117436,-0.8089761138,0.8820098639,0.2849083245,1.2971107960,-1.0834826231,-0.1189776212,-1.1106203794,-1.3206923008,0.7566649318,-1.9178347588,2.7865297794,-0.5657482147,0.2699114084,0.3090089858,0.6460570097,-2.5136375427,-0.1902826726,-1.3483183384,-0.7845107317,0.8349735141,0.8349094987,-0.9854658246,0.1150932983,-0.3015092909,0.4304955900,-2.6301472187,-2.3760235310,0.2100565583,-1.6220120192,-0.6598060131,0.0390680023,0.9663178325,-0.0312575251,0.3434973955,-0.5051045418,0.2603479624,-1.6800607443,-2.0438206196,-0.7828196287,0.8378771544,-1.0073713064,0.3594104946,-1.0887169838,-0.2854229510,-0.6326141953,-0.7492433786,0.1771231443,-2.0925412178,0.7221005559,1.0629680157,0.8875825405,0.9514683485,1.1898092031,-1.3159422874,0.3789256513,0.0052759089,0.6215171218,-0.1703885645,-0.8301671743,-1.4931890965,2.1389789581,0.0210836176,0.0997546017,0.3395195603,1.5730198622,-2.4545269012,1.4472402334,1.2666022778,0.2692795396,0.7309278250,-1.1675630808,0.1287209988,-0.2159086317,1.9478616714,0.6417044997,0.4954462051,0.2918036580,1.1044400930,-0.0565379076,1.2288534641,0.9528832436,0.0863463283,0.5586382151,2.1897523403,0.1289473176,-0.8775374293,0.5111732483,0.6179109216,-1.8111522198,0.0995398909,1.3215231895,-1.1074717045,-0.8939023018,0.2247423381,-1.0083754063,0.8858939409,-0.2505567372,-0.3213457167,0.8018403649,0.2690301239,-0.5970544815,-0.9925628901,-0.5494341850,0.1522569507,0.1563308090,0.6602344513,-0.0799589828,0.8824433684,1.1563723087,-0.3943536580,-0.8907910585,1.6997411251,-1.1539968252,0.2835911512,-0.9666313529,-0.9075029492,-0.3648546338,-1.1380269527,-1.6632107496,0.0931004658,1.5548486710,0.6206492782,0.0812515914,0.5045549870,-0.0324226506,0.9576783180,0.6753861904,0.0415677503,-0.8783605695,-0.5465931296,-0.5524756312,0.4131335020,-0.6216126680,0.9888315797,-0.3318295181,3.0655612946,1.0167248249,0.0809800029,1.0825935602,2.0115580559,0.3990780115,-0.1417630613,-0.7643346786,0.9107628465,-1.2469594479,0.2185842395,-0.5608953238,0.7581259012,-0.5780990720,-0.3210789263,-0.1193744466,-0.6779866219,-0.5087441802,-0.1424155980,1.1234807968,0.1186617762,-0.0176850781,2.0666704178,1.0098127127,1.3752470016,-1.2679327726,-1.1970074177,-1.0551103354,1.1164258718,0.3721234500,-0.9255678058,-0.9442209005,0.4268756509,0.3172981739,-0.3741634488,-1.4125268459,-2.3680481911,-0.1069736257,-0.4030350745,-0.4043666124,0.1732717007,0.4453865588,0.0835408270,-0.3626154065,0.2124658823,0.7893753648,0.8026905060,-1.3991522789,-0.3200124800,0.9662565589,-0.9130623341,0.4093767703,-2.2999207973,-0.2824724913,0.8781957626,0.0921964645,2.3364260197,-0.3582146466,-0.2903281450,-1.2173844576,-0.5441349149,-0.8577818274,0.6779240966,0.0227339007,0.9655373096,-0.2647223771,-1.9813855886,-0.5777205229,-1.6076692343,0.3734553158,-0.2309042215,-0.0047361567,-0.1747259945,1.4980055094,2.3268282413,0.0851788521,-0.3865151405,0.6857342720,-1.9992141724,-0.5850980878,-0.8566595912,0.5763618946,-0.4204704463,-1.0309052467,-0.3967194259,1.0643119812,-1.3884699345,-0.2525475919,0.0347681716,-0.4270209372,1.8029408455,-1.7515459061,0.0540627949,1.4515020847,2.2537171841,0.7252607942,-0.3768343031,-0.4213645160,0.3329466283,0.4443221986,-0.1684675515,-0.5755594373,0.6468083262,0.6131626964,1.2769823074,-0.3528927565,-0.2351228446,-1.2301682234,0.4037817121,-1.3678727150,-1.0195753574,-1.1714248657,0.4959396422,0.7116174698,0.3401472270,-0.5646832585,1.3907834291,0.2785235345,-0.8563492298,0.3405274451,1.1643620729,1.2994824648,-2.8496544361,0.0588610545,1.9530397654,0.5605524778,-2.7157382965,0.9060288072,-0.6560640931,0.4947168231,1.2521569729,0.7251318097,0.4450671673,0.1428324431,0.5182865262,-2.0029828548,0.4784449339,-0.3109569848,1.4094113111,-0.4395599067,0.0288746692,0.5327027440,0.9105619788,0.7118870020,0.0834584162,0.6378134489,0.4777068794,0.6714622378,-0.2473972887,0.9334355593,-0.0149712618,-1.2888498306,0.3178930879,0.3878506124,-0.4473615289,-0.0200192370,-1.1375455856,0.2947454154,-1.6181722879,-1.4102656841,0.6471197009,0.0660516992,2.5253288746,-1.4385683537,1.1881508827,-0.5137376189,-0.3100413084,1.8618991375,0.2196703702,0.8764735460,-1.6034924984,0.9608685970,0.7578120828,0.1340373456,-1.2120584249,-1.0811951160,-0.5332429409,-1.2666810751,1.1997977495,-0.0147280395,-0.3411561847,0.0395528637,-1.0613685846,0.8180955648,1.3017721176,0.8937417865,-0.7969278693,1.0919103622,-0.6793391705,0.5171425939,1.9261372089,-1.4655749798,-0.9694035649,-0.2225221097,-1.3643192053,-0.1500839889,0.5843650103,0.7056804895,-1.0301253796,-1.0684210062,-1.0028663874,-1.5143984556,0.0788298324,-1.7967107296,-0.3639734983,-0.7513176203,0.1762141883,1.1550230980,-0.4082490206,0.9812905192,0.4297397435,-1.0552676916,0.4100736082,0.1593143344,-1.5990869999,0.9750310779,-1.0146784782,-0.4160335660,1.6984248161,1.1609507799,0.7490220666,-0.8482598662,-0.6165418625,-0.0323930122,1.6698666811,0.1386055946,-1.1053417921,0.2234233469,-0.0349204689,0.5528994203,0.7125429511,0.0064929891,-1.0954294205,-0.4205610752,0.8501464128,1.0036913157,-1.4143588543,0.4902287722,-0.0818249434,0.1800193787,3.1680388451,-3.1549611092,-1.7138682604,-0.3571625054,1.7889220715,-1.3005938530,-1.1199634075,1.1873326302,-0.3849809766,-1.2680217028,1.4615029097,-0.6191694140,-0.2495485842,0.2082553059,0.1791836023,0.3728811145,2.1315107346,1.3774552345,-1.4320223331,-0.3597615361,-0.1586332172,1.0218647718,-1.1757861376,0.7682100534,-0.3420245349,0.7694000602,-0.1330372542,1.1873819828,-0.3006245792,0.7143628597,-0.2423644811,-1.5537725687,0.3462584019,0.4230340719,1.0040265322,1.0997759104,0.7828722596,0.4102944136,-1.1098705530,-1.0867903233,0.0346978270,1.1880047321,-0.5926411748,-0.5738988519,-0.4091166556,-0.8370656371,1.0624153614,-0.9222751856,-0.2183016688,0.8524411917,-0.2983358800,1.0201835632,0.5510687828,-0.6143435240,0.0868408009,0.6313892007,-0.6356560588,0.9379420280,-0.9612347484,0.0437515527,0.1527118981,0.0146253034,0.1002622694,1.3769297600,1.8511936665,-0.9757603407,-0.1710399836,-0.3755131066,0.6657829881,-1.4439826012,0.8646513224,-0.5456988215,-0.3876164854,1.1869660616,-1.0903005600,0.2324468642,0.4489884079,0.2146653384,-0.3496420681,0.2460367978,-0.3882636726,-3.5028512478,-0.8601097465,-0.3408805728,1.0436613560,-0.1229604706,-1.1517763138,0.6286780238,-0.5831050873,0.2989288568,-0.8618805408,-1.0957497358,-1.6585500240,0.4104961157,0.3074675798,1.7889269590,1.4891097546,-2.1270682812,-1.0630022287,-1.0487341881,0.6423425674,0.2223631740,-0.6816553473,1.4914273024,0.8645065427,0.4738709927,1.0744345188,-0.0626458526,-0.1355794221,-0.5250419378,-0.5246269703,2.2068521976,0.8553270698,-0.0701120049,0.0589456148,-1.3844010830,0.1336048990,1.4933985472,-0.7632629871,0.0417235643,0.0002870396,-0.5796526670,0.8333060741,1.2923172712,2.1858572960,-0.3396995068,0.5367954373,0.9259405136,-0.2317183018,0.5833922625,-1.8033591509,1.9753354788,-2.3160240650,-0.5039364696,1.1172219515,-0.5671532750,-0.4029072225,1.2319533825,-1.3085190058,0.4285664260,2.4368367195,-0.8638158441,1.3917367458,-0.4627754688,-0.0249045976,-0.6280714273,-0.3255177736,0.6238153577,2.4476258755,0.3078250289,0.2715431154,-1.6325097084,-1.1116009951,1.1871554852,1.6313469410,-0.1071722433,1.0070543289,-2.4956753254,0.1061718240,0.0120313754,-0.2095249593,0.3418090045,-1.2988194227,0.9380907416,-0.1236676201,-0.4573471248,-0.7191598415,0.8948004246,0.4774148464,-1.7359133959,0.6295673251,1.4042685032,0.4560325742,0.2498383373,-0.7552278042,-0.2820581496,-0.9741064906,-0.0094816862,0.4927726090,-1.5904263258,2.0433969498,-0.2484231889,-0.3923215866,-1.2565356493,0.4341219962,-0.2114793807,0.0118124252,0.1367721707,1.8070771694,-0.6738863587,-0.7573686242,-2.5797410011,-0.0804657713,-0.4304643869,0.3704101741,0.0622019991,-0.3475724757,-2.1042618752,0.5381350517,-0.7691090703,0.1761910468,0.1809306294,-0.3777577877,-0.9449252486,0.2289055586,0.2820708156,0.4839225709,-1.6858013868,-0.8856335282,0.9421400428,-0.0791686252,-1.6161797047,-1.0410964489,0.6739453673,0.0878255740,2.3287050724,0.7083165050,-1.3314689398,-0.5426526666,-0.1750532389,-2.0199997425,-1.9016313553,-2.2880182266,-0.6802806854,-0.5845252872,-0.3345496356,-1.3252086639,-1.4987232685,-0.5198655128,-0.8556139469,0.7470584512,0.7125549316,0.0654351264,-0.6348320246,0.7843273282,-0.4739659429,0.2645100951,0.7582881451,-1.4469571114,-0.8762317300,-0.1305171847,-1.8916240931,-0.2047363669,-1.4006288052,-1.4427716732,0.4075613022,-1.5529645681,0.4010265768,-1.2205121517,-0.5830441713,0.7983804941,1.3810188770,1.2851274014,1.6508965492,0.8096008301,-0.7591167688,0.7297912836,-0.7162643671,1.0841537714,-1.2955800295,-0.7949441671,-1.1049574614,-1.8323066235,0.4911190569,-0.0560565628,-0.7176681757,-1.8872069120,0.5780738592,-0.8776240349,1.1596308947,-1.4674416780,0.7553941607,0.1954972744,-0.5818178654,0.2693494856,-1.0041868687,0.6039539576,-0.6923959255,1.9953961372,0.1902663261,-0.0727277547,1.5628709793,-1.3869262934,-1.2224737406,-0.9052775502,1.8306998014,0.1413167864,1.7664381266,0.7349786758,-0.1183590814,0.8745171428,-0.1398411989,0.2598904371,0.0656923652,0.8621975183,0.8937485218,0.2206461132,-1.2316112518,-0.7846273184,0.7935965657,-0.7879238129,-0.7651246786,-0.1138043851,0.6265539527,-0.1829637885,-1.1814017296,0.0661041215,0.9544205070,0.3241200149,0.1085844710,-1.2307775021,0.3755576015,-0.3521512449,1.3882151842,0.5725190043,-0.0776720494,-1.3191725016,-0.4986121058,0.3813388348,1.4137277603,-1.5064461231,0.0442575030,-0.5795447826,-0.6121605039,0.7674696445,-0.3727608919,-0.1838898957,1.0338747501,1.9497634172,1.0179313421,-1.1559066772,-0.3884924650,-1.3412394524,-0.8717449903,0.7448266745,0.4458397627,1.6077286005,1.6052932739,-0.5146309733,-0.3278999627,0.7633868456,-0.8159669042,1.4002127647,0.1569492966,1.9102462530,-0.1955651641,-0.6491927505,0.2193007469,-0.4692718685,-2.2204196453,-0.3630209267,0.2141387612,1.0269374847,0.7454722524,0.3479391336,-0.2595340014,-0.0004230243,-0.5843359828,1.0068081617,0.5920389295,-1.4571993351,2.0111148357,1.6898576021,0.1999664903,-1.2243306637,-1.9395003319,0.7388504744,1.3946845531,-0.8135850430,-0.8188219666,-0.1027977988,1.2393451929,0.3642773926,-1.1666374207,-0.5038280487,0.1114103869,-1.5347028971,-0.5841313601,-0.8017553091,-0.1922202855,-0.3450426459,0.3865180016,-1.2264298201,0.5880392790,0.2358413041,0.9229251146,-2.5078446865,0.4116154313,0.6169677973,0.3932493329,0.7349784970,-0.1033508405,0.5472589135,-0.8508823514,0.4239557981,1.7755675316,0.0498641804,0.0039831121,-1.1012924910,-0.0702986047,0.0500299931,0.9911147356,-2.1317226887,0.0189382583,-1.2867163420,0.5649483800,0.5770050883,0.6580603123,1.4723309278,0.0125505729,0.7892917395,0.5260727406,0.7284713984,0.9198905230,0.4369905293,0.1269310713,-2.4369902611,0.2138117403,0.6558313370,0.1240368336,-0.6512229443,0.7850050926,0.8441942930,-2.6291081905,0.0859598890,-0.8896072507,-0.6072485447,0.5743405223,1.1331851482,-0.4991896152,-0.6477818489,-0.5778541565,0.0418310277,0.4881654680,-0.9791178107,0.1232551485,-0.8317633867,-0.4315126240,1.2505896091,-1.6251081228,0.3261093497,0.7886345387,0.2484288216,-0.5134832263,-1.5124263763,-1.6093171835,0.5770623088,0.5730774999,0.4694595337,-0.1032461897,-1.6306973696,1.0383374691,0.3179350495,1.6510140896,-1.4021530151,-1.6068631411,-0.9987185001,-2.0106415749,2.4225859642,-1.4711263180,1.0438575745,-0.6822944880,0.5343873501,-0.2162118554,0.4941727519,-0.0919690430,-0.0362560339,1.7026308775,-0.5808956623,0.2818481922,0.4702845514,-0.7051241398,0.4703357816,0.4183109701,-1.0918869972,-1.1447758675,0.1090682745,-1.0183391571,-0.0740790442,0.8214829564,0.2784597278,-1.2427382469,-0.8619667292,0.9212391376,-0.3883512020,0.0477222577,-0.8693955541,-0.1270150840,0.4906855226,0.0592403039,-0.2530156374,-1.9048664570,-0.0264112484,-0.5457171798,-0.0354791954,1.5265716314,-0.1019395888,0.7486965656,-1.5187047720,-1.0162277222,0.6233072877,0.4643627703,-0.8993694186,0.4188348353,-0.2046624869,0.0254781116,1.2895642519,0.6310182810,0.3446836472,-0.5590118766,-0.2556653917,-0.9896861911,-0.5274890065,0.2978168428,0.0847402886,1.4692370892,-1.3065133095,-0.6991641521,0.3440778255,-0.2718342543,-0.5695889592,0.0174058340,1.0984630585,0.1190534905,0.9798473120,1.8879725933,0.8673732877,-0.9161585569,0.4036022723,0.0035582194,-2.3451409340,-1.0702661276,-1.6849539280,0.5669997334,-0.0257244613,0.0361120626,-0.0581826456,1.0888381004,0.4999228418,0.5219503641,0.4908412993,-0.4648894370,1.2614723444,0.3910034001,2.0438618660,2.3622827530,-1.1208287477,-0.5126113296,-0.9887000322,-0.5191606879,-0.2261203378,-0.1252585500,0.0878077075,0.0369837433,-0.3490452766,1.1845042706,-0.2965066135,0.8207860589,0.1675992906,-0.9627301693,0.2979668677,-1.6763862371,-0.1788655072,-1.2550932169,0.7845742106,-0.0772865936,0.3855877817,-0.7745981216,-0.1232291982,0.7760265470,1.3818191290,-1.0101274252,-0.7251560092,-0.2056710720,0.0522477031,0.1851748675,-0.5892301798,-1.8814272881,-0.8631243706,-0.6360574365,-1.1729818583,-0.9179823995,0.9177124500,0.7739092112,1.4054862261,0.8030353189,0.4492469430,-0.8796300888,1.2875020504,-0.9119425416,-1.7323316336,-1.3451622725,-1.0565350056,0.0448045060,0.3449862301,-1.5712947845,0.5012857318,0.5056712031,0.2673935294,0.2346226573,0.8127566576,0.8522439599,1.3639987707,-1.5733017921,0.4449477792,1.0757219791,-2.1031193733,0.0343645252,1.1781619787,-1.4266718626,-0.0131833591,-0.2667540014,-0.0093084434,-0.5884740949,1.7538708448,1.1161477566,-0.1020128131,-0.2309615612,-1.2694759369,-0.5607418418,-0.4304545224,-0.3253737688,1.4808640480,0.7316930890,-0.2684265673,0.4855044782,0.3031046987,-0.8914096355,-1.4147173166,0.0380460210,-0.7299775481,-0.2678869963,-0.3101365864,0.0350842513,0.2402429581,0.7029187083,2.7874162197,-0.1721138507,-0.6986640096,1.1523491144,-1.3354657888,0.0191495139,1.1237381697,-0.3511058688,-0.4177630544,-0.9081257582,-0.2498989403,-0.1846230924,-1.6133767366,-0.8762238026,1.6221534014,0.2161289006,0.4476101398,0.2794209719,0.8718365431,-0.1944708526,-0.6252462268,-0.7593362927,-1.4583418369,-1.4333637953,-2.1012365818,0.4250461757,0.9667654634,0.2156297415,1.4574354887,-1.2711378336,0.6589086056,0.5638456345,1.1474407911,0.1375724077,-0.2267200947,-0.1479162425,-0.0163359381,1.4957658052,1.5470947027,-1.1362988949,-0.0993754491,0.0944555551,-0.0559778437,0.9665927291,-0.2777977884,0.9807844758,-1.7313894033,1.2457816601,-0.7532542348,1.5628550053,-1.8272314072,1.1460046768,0.5990837812,0.6483633518,-0.8140592575,-2.5026910305,1.5262742043,-0.5325720310,0.1642222852,0.3184698522,0.9115745425,0.9058817625,1.2242089510,-0.7914894819,-0.5712547898,-0.2330745012,0.7534739971,-1.3289783001,0.2245698124,1.4651367664,-0.6622340083,-1.4486229420,0.4370337129,-0.4643350840,0.5815520883,-2.0180966854,0.6800788641,1.9025919437,0.4159368277,0.3808253109,-0.3558321893,0.2614868283,1.4179209471,0.3718845248,0.9492228627,0.1516134590,0.3136004806,0.0753630325,-0.8924691677,-1.5429160595,0.2965213656,-0.5717129707,-0.0413963459,-0.9464138150,-1.2638531923,-1.4999424219,0.4140037298,-1.3621689081,-0.1094720140,0.1787716299,-0.3219559491,-1.4167441130,0.5873966813,1.1247311831,-1.4185732603,-0.6824306846,0.3787460029,-0.2558441162,1.1735316515,1.0506619215,0.3373606205,-1.7914761305,1.0255435705,-0.4845902026,1.3263299465,-1.1724784374,0.5220450163,0.8054077625,0.0096950140,0.8125115037,0.3299151063,-1.0037217140,0.3730991185,-0.9277126789,1.4822149277,1.5176270008,0.0745661706,-0.9604218006,-0.1578906775,0.2494293302,-0.9300476909,1.5165371895,-0.5894943476,-0.1630633473,0.0795842856,0.3101577163,-1.2102751732,2.5860579014,-0.9084997177,-0.9838130474,-0.4032730162,0.4376574755,-1.1266232729,1.2498075962,0.5042888522,0.2260986120,0.6913132668,-1.5524065495,1.0065914392,1.2285039425,-0.3059667349,0.6399753690,0.1240009218,-0.5298648477,0.7409871221,0.6777750254,1.4533698559,0.7625650167,0.1595736295,-0.1319786757,0.8643478751,1.0831538439,0.0846288800,2.1185903549,0.4222730100,-0.5730257630,0.8299391866,-0.3804766834,1.1045529842,-0.5073445439,0.1418423355,1.2586370707,0.8240965009,-0.0925577134,1.7273045778,-0.3900260031,-0.0798248723,0.8808295131,1.2586567402,0.9773184061,0.9998583198,-0.2488287389,0.2702918947,1.4333872795,0.5639662147,-1.0274194479,1.8915591240,-0.9012168646,-0.3748772740,1.9961894751,0.3488658071,0.2414206564,-1.1801184416,0.8474820256,0.2638389170,0.4284295440,-0.4961136580,0.5766240954,-0.8417623043,0.4841005206,-1.2339916229,-0.7195590138,0.6247155666,0.2961598039,0.1626374722,-0.1993692070,0.4295589626,0.1204819679,0.2459912151,2.3836979866,0.9892594814,1.5916163921,0.0971853957,-0.8566622734,-0.2674368918,0.5222064853,0.9773113728,-0.3150422573,0.8756898046,-0.4676228464,0.2016017884,-0.7167613506,-1.4885647297,1.2574212551,-0.6553381085,-0.6623219252,-1.7356320620,0.2538641989,1.0851593018,0.5627361536,1.1075919867,-0.7186845541,-1.4439043999,-0.8579331040,0.5339972377,-1.0072786808,0.6900771260,-0.8863855004,-2.2532014847,-2.5111033916,-0.4095038176,0.2482353151,-1.2830238342,-0.8127713799,-0.0843408108,0.1111695021,-1.0864380598,-1.5028867722,-0.8787872195,-1.5936022997,-0.1871830970,-1.0399664640,0.0147543494,0.7644811869,0.9782803655,0.0003450581,-0.2709909379,-0.1951631755,0.3221687376,0.3713282347,-0.4911470413,0.7329746485,0.0925365835,0.2304435521,-0.9668128490,0.4846392572,-1.1093183756,-1.3233888149,-0.0245773736,-0.0953248069,0.1685880274,-0.0482572317,0.5383268595,1.0802992582,0.2973013222,0.9245066047,-1.3101730347,-0.4364936352,-0.4648250341,-1.1351803541,-0.8205749989,-0.8568386436,2.3754029274,-0.9961820841,0.8363527060,0.2676135302,0.8208408356,-0.9117810726,-1.0280570984,-0.9798866510,-1.0432735682,-0.6724710464,-1.4416898489,0.7651339769,0.5950027108,-0.1433894634,0.6269071102,0.8044335842,1.0749381781,2.0385212898,-0.1334894150,-1.8284147978,2.0971255302,0.5444354415,-0.7383652925,-1.5236394405,-0.5464919806,-1.5434194803,0.3095881343,-1.1199891567,2.2750618458,-0.4669438601,-1.8398299217,-0.1546743661,0.0634817109,-0.4727517366,1.8044909239,1.3376697302,1.1377027035,-0.3198766410,1.7948639393,-0.2277033031,-0.3369950950,-0.5130826831,1.2988376617,-0.7731146216,-1.0604265928,-0.2253106982,0.1074710190,-1.8205831051,0.7368350029,0.7032628059,0.9893723726,0.6483827829,1.4742196798,0.0884756595,0.4978652000,1.0682324171,0.6970139146,0.8740690351,-0.9838154316,0.2248925716,-0.5559855700,0.4227550626,1.1992962360,2.3643376827,0.8882084489,-0.5913435221,-0.7380414009,-1.0349892378,0.9173351526,-0.5621873140,-0.0949840769,-0.1317703575,0.0631912276,0.9709743857,0.3090033233,0.9268954396,-0.4655930102,0.2861961126,-0.2644225359,-0.3251528144,-0.8222166300,-0.0960599184,1.4646030664,1.4194988012,-0.4227886796,-1.8527027369,0.2715824246,-0.5044975877,-1.8221150637,0.1931934655,-1.5894869566,0.2379000485,-1.0019147396,-0.2313501835,0.0035350423,0.0740525126,-2.6869721413,1.5776410103,-0.5823276043,1.4910770655,-0.9430855513,-0.0499442630,-0.2272549123,-0.0936595276,-0.1898984909,0.5837596059,-1.1511113644,0.3232372105,-2.0862889290,-0.0450896136,0.1430051774,-0.3782043159,1.2295246124,1.5990449190,0.4077310264,1.0603466034,0.1066178828,0.9763474464,0.5174518824,-1.0154049397,0.1633393317,0.9158678651,-0.4462140799,2.7762815952,-1.7528024912,-0.8473525047,1.3816362619,-1.4776809216,-0.0661653429,-0.5095384717,0.1321265846,0.3022744358,1.0764505863,-0.8410828114,-3.0817403793,-0.0300313104,-0.0764164105,-0.2109280974,0.1390453428,0.4264347255,0.0728728324,0.2737209201,-0.4620195031,-0.0491712280,-0.3356860578,0.4319370985,-0.2530729175,-0.4461062849,-2.0072276592,0.9238764048,0.1594048589,0.0638244227,-1.3263802528,0.1089418977,-0.5390468836,-0.5481974483,-0.1197349951,1.0218429565,-0.7934098244,-2.4163577557,0.7732511759,-0.4387922585,0.6461163759,-1.3936929703,-0.6618784070,2.1668913364,1.0993745327,-0.1202072054,-0.4973158836,-0.6462906003,0.0609707199,-0.9450492859,-1.3187497854,-1.0022757053,-0.1960598081,0.7324171662,-0.4829072952,0.4753527939,-1.4519374371,0.8318330646,1.3754912615,-1.1183576584,1.5637904406,0.3519226611,-0.4841500819,0.3794345558,0.5975720286,0.6764720678,0.5199920535,-0.0438902751,2.0463252068,-0.5165079236,0.0998032242,-0.9830651283,-0.6394013762,1.1262912750,-0.8103187680,1.0153911114,-0.6205669045,0.3662223816,1.1925779581,0.8172106147,-1.0794445276,1.8628367186,0.0463979691,-1.1959922314,-0.0023014785,-0.3665894270,0.6613500118,-0.1001069471,-0.9814707041,0.3034345806,-0.7231702805,0.7263912559,0.8849028945,-0.0591529347,-0.7766273022,-1.2518745661,-0.6941793561,0.5461867452,-1.4127789736,-1.1363685131,0.4137958586,-0.2157655805,-0.1393927634,2.9335629940,-1.3698664904,0.4863412976,1.7759577036,0.9367753863,-0.5121124983,0.5831712484,-1.5519332886,0.2913210690,-0.5899180174,0.0952703059,-1.8471230268,-0.0709084868,1.4827005863,1.4237951040,-0.5086781383,-1.6200858355,-0.1084599942,-0.3973819017,-0.7838751674,1.9469268322,0.4652900100,-0.6131108403,0.4059070349,0.2010302395,-0.1316693425,-0.0746570900,2.3412575722,-0.1811244637,-0.7504181862,-0.3903382123,-0.2243826389,0.9201111794,0.4877253771,-1.4580579996,0.8116889000,-0.5697486997,-0.4015645683,-0.4854067564,-0.6364825368,0.9034591317,0.6379844546,1.5771756172,0.5850499272,-0.6220704913,0.4983624816,0.4711814821,1.1179269552,-0.2089185417,0.5540845990,1.2248898745,-0.5977462530,-0.5361250043,-0.0362544581,0.8173483014,0.1797466129,0.6411272883,0.5963133574,-3.6270735264,0.3135236800,1.7770348787,-0.5708009601,1.2956660986,2.3631596565,0.6470772624,-0.1276730001,-0.4334301949,1.7504278421,-0.7313968539,1.3321459293,-1.1168040037,0.0644597635,0.6098915339,-0.8870542049,-1.1227594614,-0.1024430543,1.0980104208,-0.1197945774,-0.7725059986,-0.2856721580,-1.4923102856,0.2849843204,1.2012387514,-2.6904499531,0.1604321897,0.0795088485,-0.9636630416,0.4146036506,-0.2131204307,-0.5044959784,0.3896358311,0.4751556814,0.2694335878,-1.3584232330,-1.5450501442,0.2078277916,-1.4040329456,-0.9148842096,-0.5544590950,-1.9398692846,-0.7526990175,-0.2037417889,-1.1072591543,1.9583116770,0.4932885468,0.2148445249,0.7477450967,1.5735576153,-0.0146483416,-0.7617738247,0.5999017954,0.7779759765,0.5772922635,0.2835288644,-1.2251069546,0.0834239051,0.7457368970,0.5876018405,1.0709481239,0.5153665543,0.7868348956,0.9774563313,0.1690707654,0.4484441876,-1.3282804489,-1.5179308653,0.4773723185,-0.2764462531,1.5602777004,0.3877660036,-0.3111630082,0.9336119294,0.9268003702,1.2970597744,0.4492572844,-0.5420606732,2.1234147549,0.4513804018,-0.7160360217,-0.3417129517,-0.3907018900,-0.0474371351,1.1380760670,0.4578434527,-0.2161199600,1.1832199097,-0.5278459191,-0.7826381326,-0.9901517034,-0.2069672644,0.7864428163,0.3632103205,-0.3682445586,-0.4018748999,1.0661147833,1.0399434566,1.4891061783,-1.6929762363,-1.0862518549,-1.6203837395,0.1468081474,-0.3604899645,0.8857752681,0.4906992018,0.0710786209,-1.1928530931,-0.1335477829,0.3187680244,0.0093177333,-0.9354539514,0.2795247138,-0.3294781744,0.4063001871,-0.9572349191,-0.8981993794,0.3415729702,0.8799454570,0.6367980838,0.7841370106,1.1163245440,-1.9475696087,-0.4421205521,2.8911242485,-0.8780661821,-1.0232143402,1.6205269098,-0.7261584401,0.0078559443,0.6348084211,1.1820709705,-0.1163733304,0.8389843702,1.2746939659,-0.1599865109,-0.9582620859,1.6713591814,0.6692322493,-0.6660379171,1.0564323664,0.9545536041,1.2530609369,-0.2479295433,1.6680572033,-0.4401457906,0.7781750560,-0.3038768470,-0.4356323183,0.6398789883,-1.5581569672,-2.0755450726,0.6866158843,1.3195549250,-0.3794221878,0.5103654861,1.9730210304,-0.7375587821,0.6860241890,-0.9076411724,-0.6199430823,-0.9175467491,-1.3471761942,-0.9156367779,-1.3426939249,-2.0646798611,-0.6329957247,-0.0766262189,-0.5408920050,0.9520366192,-0.8571756482,-1.1599135399,-0.5584220886,1.6461673975,0.1045306548,0.2158393413,1.7292610407,1.2974575758,-1.3764995337,-0.4452150762,-0.1526507884,-0.9902333617,1.5345755816,-0.1589398384,0.9030612707,2.0708162785,-0.9861791730,0.2067744881,-1.9495503902,-0.5985112190,0.9967989922,-0.8435174227,-0.2820928097,0.3777058125,-0.3613773882,-0.5519063473,-0.6273316145,-0.4378284812,0.2569901943,0.9104852080,0.0983464718,-0.2658705711,0.3255655766,-0.5762305856,-0.9602346420,0.2911734283,-0.5379109383,-0.9457253218,0.7973366976,-0.7568753958,-1.7424373627,-0.7140328884,0.7866174579,-0.0874564052,1.0776548386,0.0858798251,-1.2913337946,0.8008134961,-0.3137482703,0.5386188030,0.4172564447,-0.2212724090,1.0290312767,-0.6964595914,1.6124269962,-0.5174486041,-0.6736907959,-0.3899573386,0.1325595826,-1.0444660187,-0.2226642817,0.7306677103,0.5076549053,0.9035003185,-0.4636362791,-0.5478364825,-0.5060825348,-2.3333342075,-0.9416838288,-0.0387029424,-0.1578006744,-0.6142289639,0.8859317303,-0.8811742663,-0.6772906780,-1.1823346615,-1.3328503370,-0.0093972646,0.5491439700,-0.6104214191,-1.2850006819,-0.6465294361,0.1817125827,-1.4026774168,-0.1775815934,-1.2878239155,-0.4031934738,-0.8606334329,-0.7982609272,-0.6417425871,-0.6398243308,-1.3228656054,1.2034947872,0.8919556141,-1.8049753904,0.4476211667,0.2820806801,1.8818633556,-0.9953379631,-0.3909469247,1.3604015112,2.3987371922,0.3861819506,1.0936772823,-1.1391612291,0.8738053441,2.6254327297,-0.1070521250,-0.4421439469,1.9917935133,-0.3215175569,0.6542347670,-1.0363366604,0.5616360903,-0.9750161171,0.5296633244,0.5032150149,-0.8450386524,0.2101103216,-0.8270325661,0.2830041051,-0.9392392635,0.8031272888,-0.8688564897,2.0318152905,1.5412871838,0.3922415972,0.3853695095,-0.1013855189,-1.2406502962,-0.8898990750,1.6640088558,1.4869363308,0.0144009460,-0.0533166006,0.1196023002,-0.0499731563,0.0728715211,1.6635298729,0.1403089315,0.2601655424,-1.2603138685,0.5634941459,0.5055314898,0.7348325253,-0.4419586062,-0.1415433139,0.7567729950,0.9354738593,-0.0609624647,-0.3537159264,0.8630941510,0.5925130248,0.1479303986,-0.5582378507,0.8495017290,-0.1681861877,-0.8794690967,1.5341011286,-0.9373859167,0.3684532642,0.2468343675,0.5768260956,0.1956495643,1.7508788109,-0.2407533079,0.0557939187,-0.3764891624,-1.4740674496,1.0650231838,-0.6109123230,-0.8943587542,-0.2481622696,0.5509840250,0.1316975355,-1.0856409073,-0.5210722685,-0.4651280046,0.0003967007,-0.9472005963,0.3264623880,0.0406349227,0.6955839992,0.6747277975,-0.8340126276,-0.6404592395,-0.4645507634,-0.5293129683,0.1810609400,0.5685809851,1.0409775972,1.8969447613,1.4060031176,-0.9676909447,-1.1406483650,-0.8645566106,-0.9631246328,-0.4495841265,-0.3670941293,0.1041967198,0.9390909672,-1.9684011936,0.2957823277,0.0055266228,1.9068297148,0.2354781479,0.0417030305,-1.7206138372,-1.1816716194,-1.6864529848,-0.2795744240,-0.4381642938,-1.3464711905,-0.2227810323,0.4033103883,0.2749841511,0.2874121964,-0.0273968987,-1.6804682016,-0.8865109682,-0.2472569197,-1.1258128881,0.9342336655,-0.5807120204,-0.1418465823,0.0790987611,-1.0749927759,2.2134726048,-1.2006694078,0.2691707015,-0.2489442676,-0.8762915134,1.6632809639,-1.0335812569,0.8721647859,-0.1475594044,-1.2235310078,0.5650429726,0.2195928097,0.0491285175,-1.0111253262,-0.8699862957,0.1976990700,0.3421122730,0.4036723971,-0.0111169284,0.1301707774,-1.9352202415,-0.3411969543,1.5464907885,-0.8455371261,-0.2012025714,0.5543738008,-0.3549480140,0.9601488113,0.5847229362,-0.9601101279,0.1428328454,0.7909606099,-0.2072594315,0.5749731660,-1.2849420309,1.2086113691,0.4027648866,-0.9209063649,1.3428764343,-0.0497116633,1.1252496243,-1.4034109116,0.0854413658,0.5364454985,-0.4646377563,-0.2525386512,1.5714304447,-0.3075014353,0.7793367505,1.7497104406,0.1035423651,0.4156560600,-0.7896444201,1.5372807980,-1.0925191641,-0.3885779679,0.7863638997,-3.7716197968,0.3558905423,0.2657609880,-0.0128362346,0.2688941061,-0.3216839731,-0.8197370768,-0.4061123729,0.0722145662,0.6458423734,-0.5728822947,1.5331975222,-2.2644534111,-0.7149686217,0.7342334986,0.0273310989,0.4219648838,-1.8402411938,-0.5089277029,0.5984560847,0.6699381471,0.4165192246,-0.5552244186,1.8353990316,-0.6733164191,0.3321333230,-1.0508931875,-2.3420100212,-1.1035705805,0.2500540316,1.2323869467,0.9139543176,0.7953773141,-0.2368800640,-0.8238989115,0.9296641350,0.1124773398,-0.4949807525,2.1422438622,0.3602790236,-1.2223575115,-0.5173635483,0.2391503006,-1.1317293644,-0.8869965672,-1.9696947336,-0.8611670136,-0.4780994356,0.1703852862,0.0392747857,-0.8513867259,0.5941985250,0.7758460641,-0.2394779474,0.5881170034,-0.3526118100,-0.9439957142,1.4639183283,0.8294926882,0.2655101418,0.2055927962,1.5004353523,0.5081455708,-0.7707537413,1.5194914341,0.9345728159,-1.1830033064,-0.7755748034,-2.1746835709,-0.1002500951,-0.9036408067,1.1387488842,-0.0545942672,0.7622455359,-0.3603307605,-1.1414390802,-2.1771762371,-0.3917343915,0.9779875278,0.0251153242,-2.3134996891,-1.2564883232,0.5975403786,-2.0236263275,0.4483772218,0.4159247279,-0.9448549747,1.5468273163,0.4482175410,-0.6612976193,-0.4731059968,-0.4449138641,-1.9738931656,0.7042369246,-0.0061952700,-0.4430695176,0.7511484027,-0.6052109003,-0.7535775304,0.2447089404,-1.4141345024,-0.6515182853,1.1660512686,-1.8217883110,-0.6141258478,1.2125263214,-0.0212147497,-0.6908379197,-0.2760960758,-0.3090609014,0.0992453471,0.3898756504,0.6739951372,-0.2484564334,1.1012392044,-0.4972129166,0.4972700775,0.1244544089,0.8972615004,-0.9175131917,0.8274303079,-0.4539879858,-0.2072115093,0.5159810781,0.9847689867,1.0576518774,0.4988316596,2.1206722260,-0.2258833945,-1.7573635578,-0.6614010930,-0.5449556112,-0.3869622052,-0.1445140392,-0.1908085942,-0.1185690537,1.7395980358,2.7544355392,0.3639674187,-0.6550902724,0.3023473620,-0.2460299134,0.0533388853,0.6053739190,-1.3006967306,-0.2727494538,-0.8468128443,0.9766883850,-0.6045349240,0.2835266888,0.2119962424,2.5724422932,-0.1248733848,-1.5877096653,0.4133778512,1.3906018734,0.3611457348,-1.4941810369,0.9097679257,-0.7895452976,-0.0131430048,0.4787768126,-1.4094642401,-0.7671945095,0.4627577662,-0.2127619982,-0.5586658716,-0.0810662135,-0.6329986453,-1.5000852346,0.1569671482,0.4610330462,0.5216055512,1.0951989889,-0.6010218263,0.5522876978,0.4321692884,0.6307811141,2.0530083179,-0.5217092633,-1.4897885323,0.6250126958,-1.5613023043,-0.0225469321,0.3653716445,-0.1923164874,0.4022558033,-0.3239069879,-1.1409021616,0.2954473197,-3.0193588734,-0.4682822824,-1.4773166180,-0.9042945504,1.0454072952,-1.1082838774,-1.0444512367,2.1708672047,-0.4832859039,-0.6777984500,1.5595563650,-0.2915486395,0.0221522450,1.6878607273,0.9222207069,0.5000102520,1.1645658016,-2.7195198536,-1.5850836039,-0.3821529746,1.1708577871,0.5796393752,0.0682036281,1.1589673758,1.6575613022,-0.7662689090,-1.2816127539,0.1619419008,-1.3800725937,1.1070289612,0.9855763316,-0.9594042301,-0.8101201653,1.4170614481,1.6217786074,2.5478603840,-0.9287158251,-0.8941593170,-0.7534239888,1.6682021618,0.3101405501,-1.0944006443,-0.0103884470,-0.6301780343,3.0968067646,1.1102194786,-0.8093426228,-2.0855097771,1.2799286842,-0.7997585535,0.6396434903,-0.7613869905,0.3158714771,0.2002303302,1.6275659800,0.6539255381,0.4313740432,0.8388326764,0.3235431612,-0.3483707905,-1.0462989807,-0.6488026977,-0.1168876439,-0.2802293897,-0.3582161069,0.7303908467,0.0247646552,-1.3823878765,-0.6700788140,-1.7218041420,-1.5610544682,-1.3730332851,0.0397199988,0.0339602269,-0.0213197358,1.0941541195,-0.2352717072,-1.6322890520,0.0799121186,-0.9556933045,0.9889248013,0.2835512459,-0.4392039478,-0.9414988756,0.4072564840,-0.9518223405,1.3833876848,-1.1340763569,-1.8409861326,0.5475594997,0.5772783160,0.0075433361,0.4877021611,0.7304438949,0.3374955654,-0.1783489287,0.5135381818,0.5862373710,0.4374061227,-1.2511309385,-1.0444641113,-1.2574287653,0.8642635942,0.8503614068,-2.4733905792,1.0161190033,-1.7650945187,-1.0526522398,0.9574536085,0.2752321362,0.3666337430,-0.3609675765,0.8975061178,-0.3459243774,-1.4031714201,0.3312491775,-0.6045495868,1.2702319622,1.0439270735,-0.9935119152,0.2147451937,1.1008656025,0.4299190640,-0.1372111440,0.6169565320,-1.5516846180,2.0646662712,0.9198255539,-0.3870903254,-0.2804978192,1.3506839275,1.4641412497,-0.8443898559,0.1116885245,0.3858242631,-1.1577074528,0.0645114258,-1.4962903261,0.5474752784,-0.3548987508,1.0024415255,0.5446375012,0.8305513859,2.6467790604,0.6494945884,0.0595578328,0.3597752154,0.2516870499,-0.1181238145,0.4422335625,-0.1153549701,0.0733081177,-0.2758054435,-0.1951264143,0.1095378771,0.3252094388,0.8930382729,1.0510355234,0.9716653228,0.1504226327,0.5727462769,0.2539176345,0.0424893796,-1.0405927896,-1.4690296650,-0.0724262744,-0.1799088567,0.0264645424,-0.1598746330,-1.4990167618,-0.2105566263,0.1332618743,0.7448723316,-0.9744883180,-2.1181311607,-0.7248430848,2.7197012901,-0.5189481974,0.6716082096,0.1522336751,1.0515916348,-0.3552295566,0.0526108779,0.9851053357,1.0241189003,-0.5028194785,-0.8301829100,-0.3506364822,2.1013507843,-0.2975785732,-1.1915485859,-1.9310274124,0.0281611960,0.7278511524,0.0044026095,-1.3758076429,-1.2809020281,0.7183985710,0.2994307876,0.9146254063,-1.8804464340,-0.5685744286,-0.1684366763,0.6454023719,-0.1555209905,0.0017470572,-0.0461361818,-0.4751440883,1.6674766541,-0.2610110044,-1.3076088428,-1.0537695885,-0.1325166225,-1.6590558290,0.1996072829,-0.4648935199,1.6472010612,-0.7532877326,-1.2189908028,-1.2708369493,1.7304326296,0.9739592075,-1.6090298891,0.9269093871,-0.5141512752,0.3343603611,1.0514758825,-0.7026612163,-2.2228353024,1.6996566057,-0.0153976502,-1.1894229650,0.1029311270,0.9860951900,-0.0424149409,0.2471846044,-0.6132379174,0.1702657193,-0.9761342406,0.1023765877,0.9823054075,-0.2936163843,0.5247262120,0.2902828455,1.3442021608,-1.2850005627,0.8672465086,-1.5464787483,1.5290105343,-1.3002258539,-0.4517161846,-0.3036861420,0.4617317021,0.4716469944,0.1666602939,0.2115351707,-0.5178134441,0.9480272532,-0.0098326812,-0.2219161838,1.0748243332,0.0413280837,-0.3751921058,1.0054109097,1.0878173113,0.2635469437,0.8403769135,0.2879878879,-0.1068011448,-0.9250847697,0.2024889141,0.1903910190,0.7410366535,0.8781462908,-0.2524499595,-0.1668965071,0.7493336797,0.8561979532,-0.0669981241,-0.2866696715,0.0031576664,-0.3875811696,0.4032322168,-0.0186206941,-1.0397504568,0.5258228183,-2.0523731709,1.4011635780,-0.3832056522,0.2031720877,0.6009286046,-1.0024389029,0.9176901579,0.1213238463,0.4889194071,0.5418915749,0.6136344075,0.1356879771,-1.2291907072,-0.7746384144,-0.1509719342,-2.0120000839,-0.1013733819,-0.3087831140,0.5470914245,-1.7141972780,-0.2830403149,1.5329728127,-1.1248511076,-1.0335241556,-0.5896264315,-0.0678327307,3.0144801140,-0.1954812109,-0.8513020277,-0.8838554025,0.8399129510,0.4587032497,0.6862203479,0.4576050341,-0.9797825813,-0.9266083837,1.2219574451,0.1443065107,0.6248232722,0.2345218509,0.0487408191,0.1535460949,0.3320425153,-0.1576162130,-0.6590068340,-0.0338018723,0.4617294669,0.1008614600,-1.2741967440,-0.3311012089,1.3876305819,0.9555911422,-0.8060911894,-0.4946635365,0.9969357848,-0.1563356966,0.2311514914,0.8098935485,0.1144014150,0.3466364443,1.6067898273,-0.4078532457,0.8250998259,1.1099538803,-0.0130652459,-0.8130413890,-1.2216724157,-1.2805823088,-0.7013052702,-1.1525663137,0.5510089397,1.4384489059,-0.0168083627,-0.2640907764,0.5070714951,-0.6443662643,1.8311312199,0.6864961386,-0.1773331016,0.2223710716,-0.0704963654,-0.9840225577,-0.3356443942,1.0691854954,0.1201403961,0.5101134777,-0.8782663941,-0.5339717269,-0.9799844623,0.7834316492,0.7693622708,0.2057720423,-0.3445561528,-1.4284933805,-0.0017824746,0.9755434990,0.7316427827,0.0141161242,-0.0398816057,-1.2709821463,-1.5649716854,-0.3071387112,-0.5473391414,0.9616869688,1.5145448446,-0.7195694447,-0.3944427967,0.4071395993,0.1094340906,1.9397739172,0.0562009476,0.5139475465,-0.0046406253,0.0536796823,-0.8677092195,-0.7403584719,0.0448231101,1.3504319191,-0.3382182717,-1.2779160738,0.2713087797,-0.4566406012,1.0716338158,0.2072720528,0.3301466703,-0.2964983284,0.5896486044,-0.4153626859,0.5670648217,1.1750820875,1.4873989820,-2.3126528263,-0.8691516519,0.4574732780,-0.8475249410,0.8546934128,-0.6666801572,0.1129124910,1.2397251129,-0.3301310539,-1.1247928143,0.1654882878,0.2989130020,-0.2470651269,-0.3026075363,0.1921841800,-0.1730351001,0.4377845526,-0.2193670720,0.6114021540,0.6966733932,0.3748733699,-1.4609225988,1.5907051563,0.9739543796,0.8248856068,-0.3926510513,1.5374946594,-1.1393166780,-0.2162578404,-0.7730450034,-0.4251903296,0.5946242213,-1.1560473442,-1.5628254414,1.1010065079,0.2154533267,0.7111494541,-0.0475142524,-0.0388706252,-1.2525222301,-0.5174888968,-0.5561483502,-1.1154675484,0.1784954369,0.8350765109,-0.4459244013,-2.4139649868,-0.8504996896,0.5401726961,1.9785127640,-0.6393229961,-1.3613717556,2.0546019077,0.0595806055,-0.4285869002,0.9154852033,-0.3232243061,1.5594203472,-1.1150901318,2.0952014923,0.5021405220,-0.7830901742,-0.7693719864,-0.1663081795,1.4347996712,0.2960758805,-0.0027330727,0.2682686448,0.0127709676,0.2424747497,0.4638241827,1.7889491320,1.1757079363,-1.0222588778,2.6014802456,1.5808367729,-0.2146649361,0.7575861812,-0.4495947361,-0.5908117294,0.5592653751,-1.3259441853,0.5948846340,0.4069502056,0.8398963213,-0.4906890988,0.6471970677,0.6398313046,1.6471980810,1.4133006334,0.8426824808,1.0106039047,1.0245624781,0.0944321230,1.4529879093,-0.6713413000,-1.5175800323,2.1336538792,0.7717633247,0.6927742362,-0.4853357077,1.3379818201,-1.6785788536,-1.0422717333,0.5675963759,1.6423405409,0.1245919019,0.9202539921,0.0586088188,0.4284663498,0.1830497682,-0.1064387262,2.5498642921,0.1319633871,-0.8298854828,0.2510634661,-0.8929324746,0.6934131384,0.8412130475,-0.3025356829,-1.3898062706,0.7125902176,-1.8900271654,-1.2866756916,0.3507175446,1.0069307089,0.3439614475,-0.4223397672,0.4167747498,-0.6913272738,1.3721678257,0.1986006349,-0.5031130910,1.3957043886,0.4102612138,0.7169515491,-0.6730329394,-1.6226317883,2.0858526230,0.0266461149,1.1714679003,-2.1153361797,0.0740644708,-0.6488339305,0.0858231783,-1.3241528273,-1.0434464216,-0.3803936243,-0.6672549844,-0.1567256898,-2.3133258820,0.1390058398,-0.4018515348,-0.4512442946,0.3724332154,-1.1800881624,-1.3332873583,0.7908762693,-1.3407357931,1.6218533516,0.1306812912,-0.6198000908,0.0341969095,0.6919595599,-0.1018244103,0.3843306005,1.2551382780,0.1839106530,1.3701967001,-1.9215074778,1.5717345476,-1.0818972588,-0.2024257630,0.0068036322,0.7846305370,-0.4962382913,3.0493257046,2.2000374794,1.3815038204,0.5984432697,-0.6466378570,0.1070459485,0.0651153326,-0.4481697977,0.4599678218,1.3020391464,-0.7581306696,-0.2754032910,-0.0371919386,-0.5418404341,0.7452659607,-1.1534259319,0.9381926060,0.6659347415,-1.1937292814,-1.5376166105,0.1310789287,0.2398359627,0.5549139977,0.2483216375,-0.6198633909,0.8630862236,-0.1393041015,1.0174250603,0.3143958449,0.0683760419,0.0315545090,1.3078721762,0.4492118359,-0.4071181715,0.5910757184,0.3741379380,0.2453961819,-0.8749790192,1.2522603273,-0.3844586313,0.0375177786,-0.6383576989,0.7360663414,-2.3159997463,-1.3596284389,0.4820798934,0.7575388551,0.8861390352,1.0024284124,0.5143792033,-0.6864389181,-0.7257505059,1.7803571224,0.5731166601,0.8511525989,0.8942019343,0.3404513001,-1.7471883297,0.8651315570,0.4115097225,0.9011681676,1.6878750324,-1.6129397154,0.5108485222,-0.2522997558,0.7438052893,0.5033487082,-0.4613233209,0.4820011854,-0.4439652562,-1.4911876917,-0.3602609336,-1.5907628536,0.6927799582,-0.1477584839,-1.0334455967,-1.5674887896,0.4550902545,1.5604319572,-1.4422808886,0.5788357258,-0.2870239317,-0.4004207551,-0.8785344362,-1.4270888567,0.9402923584,0.8992320299,0.4155126214,-0.8877316117,1.7329494953,-1.5584703684,0.2766417265,0.6156333685,-1.3220993280,0.7813851833,-0.6368366480,-0.6957759261,-0.5995090008,-0.3846778572,-0.0360092148,0.2149695456,-1.0402828455,-0.8459938765,-0.9112716317,1.0995310545,-0.9367135763,-1.9902956486,-0.0227747150,-0.4758028686,0.9322866201,0.9273737073,0.8070508242,-1.7838457823,-0.6699023843,-1.5915911198,-0.2805326581,-1.4233908653,-1.4749735594,0.1594439596,0.0329884961,-0.8356202841,1.3274855614,1.0824410915,1.0488785505,-0.4469273984,-0.9992522001,-0.9932340384,0.5085969567,-0.5421534181,1.9483562708,1.1397675276,-0.0622630306,0.1688272506,-0.7671681643,-1.1403740644,-0.7531850934,0.3955881298,0.6842200756,-0.5735817552,-0.5361065269,-0.7205488682,-0.0343498290,0.4714860320,-0.1568353325,0.5368303061,0.7607414722,-0.7243655324,-1.3951404095,-0.8374814987,0.4954386055,-0.0606812388,-0.6688954830,-1.6458029747,0.6280921698,0.2495674193,1.5667924881,1.3704221249,-0.1882616132,-0.3503639698,0.6975366473,0.4451564252,-0.6488027573,-2.6514444351,-0.9436893463,-1.0788868666,-1.0912772417,0.0611912012,-1.4206846952,-0.6495169997,-1.2007901669,-1.3360172510,-0.0519311912,-1.2045214176,-1.1121664047,0.6280339956,-0.5048688650,-0.4457834363,-0.4472849965,1.1495735645,-0.5288956165,1.2007362843,-0.4974692166,-0.3109487891,-0.9244396687,-0.2693705857,-1.0468840599,-0.6721541286,0.5465496778,0.0884050056,-0.4098713398,-1.0514574051,1.4148094654,-0.4750121534,0.6167279482,0.9246222377,-0.4253928065,-0.6544781923,0.7891964912,0.3140968978,0.7648479939,-0.1695642024,-0.1479424685,-0.1064250320,-2.2116746902,2.3312244415,-0.6676529050,-0.9457675815,0.9474021792,0.7973690629,0.1704794019,-0.7035692334,0.7092891932,-1.8698717356,-0.2639527023,0.2181621939,-0.4548698962,1.5478996038,-0.4820409119,0.6898891330,0.6085611582,0.0193841830,1.8152153492,-1.6339917183,-1.3337707520,-0.5393002033,0.1599944085,0.4317499101,-1.7887134552,0.7140734196,-0.8148634434,-0.4388350248,0.6136690378,-0.8982139826,2.4423866272,-0.9562060833,-1.4921243191,-1.7531054020,-1.9354444742,0.1809691191,-0.9431200027,0.1708678603,-1.9138517380,-1.3267153502,-0.8237664700,-0.1747481823,0.8606752753,0.8452942967,-0.3969329000,-0.7858321071,-1.0196638107,0.1269257069,1.0621590614,1.5306878090,-1.5189861059,0.9269375205,1.2335311174,-0.4745801091,-0.6515474916,0.7936541438,-1.3056498766,0.2814712524,1.4409999847,0.8073496222,-1.8721452951,0.1184589267,0.8932977319,-0.5317001343,1.8536045551,-2.7512083054,-1.3216940165,-1.3283517361,-1.1938714981,-1.2970254421,1.1642961502,0.3630233407,-1.1360250711,0.4634298086,0.2409296781,-0.9782558680,1.8368214369,-0.0928911120,1.2228311300,-0.4003975093,-0.3872050047,-0.2419685572,0.1414249092,-0.3762511015,0.1452577263,-0.2219312191,0.7660420537,-0.7883638740,-1.6409637928,1.1355031729,1.3309619427,-0.9560182691,0.4649753571,1.1633868217,-1.4728108644,0.2295930833,-0.1990584433,0.3435695469,0.8488633037,-0.3607235849,-1.8055906296,0.2481548339,0.7938757539,-1.8822200298,1.2305692434,0.9074109793,-0.3646234274,2.4204812050,-0.8100681305,-0.5929164290,0.8905769587,-0.7271680236,0.3828736246,1.0301723480,0.7428522706,1.0397125483,0.5743683577,0.9277793765,0.3855857253,-0.4105027914,0.5453033447,1.5967614651,-0.2897183895,-0.9443405867,0.9612666965,-0.2591313124,0.7493833899,0.9668287635,2.2179422379,1.4288818836,-0.3036374748,0.3314071596,0.1685507894,-1.0392718315,0.5757080317,1.8846974373,-1.0078357458,0.4577882290,1.0183068514,-0.7346784472,-0.4650122225,0.0640585124,-0.7890337110,0.7123513818,-2.1669125557,-0.7675073147,-0.9449701309,0.8574027419,0.7751913667,0.1898535192,1.6693571806,-0.3673186004,-0.0210592635,0.4653729498,-0.6247548461,0.1980665624,0.7378042340,-1.0381380320,0.8246774077,-0.1759186089,0.6200713515,0.3294046819,0.2967543006,-1.0276694298,0.0227232017,1.1291382313,-0.6281598210,0.8043770790,1.0822321177,-0.1657423079,-0.0776807144,-0.1167014837,0.3684995174,1.9841905832,0.4295887053,0.6405870318,0.6379342079,0.8725138903,0.3877270222,0.8504217863,-0.0968416929,-2.1198146343,1.4159415960,-0.3126500249,1.5506500006,1.0458365679,-0.3016704917,-0.2235870957,-1.2391153574,-0.5851184130,0.5509126782,0.4651997685,-0.4118579626,1.5482922792,-0.0040421048,-0.9912667274,0.0142603684,0.8469740152,0.1916214526,-0.0247817542,-0.0518606752,-0.7906127572,0.6237937212,-0.2116433233,1.8560798168,0.6758502126,0.4323855340,-0.5427485704,-0.2471507788,0.8266699910,-1.2941006422,0.0277775917,-0.0114485594,-0.1420166045,0.4924000800,0.4590295553,2.5640699863,0.3363261521,-1.5822482109,-1.6178342104,1.3771090508,1.1515468359,-0.9595029950,1.7391210794,0.6310431361,-0.8181252480,0.3020314276,-0.8029966950,0.6402264833,1.1647168398,-0.8939806223,0.1350935549,-1.0642356873,-0.5717391372,-0.6346552372,0.5374536514,1.3573206663,-0.3348610401,-1.6466457844,-1.3988031149,0.6637595892,-1.4271485806,0.4709821343,-1.4963316917,1.3809591532,0.3187876642,1.0921761990,-2.2258255482,-0.5045356750,-0.7421919107,-0.2157391161,0.7126739621,0.6691911817,-1.1976441145,-0.8853336573,0.8246211410,-0.9868354797,-0.0254206806,0.0362228155,-0.1663735956,-0.9848557711,0.7515419722,-0.7585852742,-1.0937254429,-0.1821856797,-0.6961805224,0.3334859610,0.4389159083,0.2469871491,-2.0076756477,0.4291914105,-1.2334452868,1.3440158367,0.0627860799,-0.9219018817,-1.2558528185,-1.9622758627,0.1995464712,0.4981423914,-0.5179405808,1.9443092346,-0.4232400060,0.0491162017,-1.3236367702,-0.6165354848,0.7170464396,0.1112871245,-0.8130300641,0.2534252405,0.5796111226,1.9850246906,0.4960811436,-0.2429900765,-0.4833355546,0.6328579187,-0.6804760098,-0.1585241705,0.3408620358,-0.4281844199,-0.8441763520,-0.8560928702,-0.5648352504,0.0108333835,0.3450529873,0.7727462053,0.5534866452,1.6443219185,0.5270298719,0.2769190669,-1.0014778376,0.5765803456,-0.8796996474,0.5687882900,-0.0461753644,-1.2852069139,0.7221946120,-2.7615418434,0.0332008004,0.2197542191,-0.2995602190,-0.0586884245,1.8317363262,-0.6810992956,1.5084025860,0.3555968106,-0.2981703579,0.9358145595,1.9291380644,1.2278101444,-0.2416273504,-1.0936526060,-0.2135961056,1.5356572866,0.9269886017,-0.4677660167,0.5069100261,-0.5780176520,-0.2702128291,-0.5411428213,-0.3239991665,1.5921620131,-0.3274900615,0.0973749086,-0.1159433350,-0.7867313027,-1.3489117622,-0.6642484665,0.1416206062,-0.3015295565,0.7219636440,-0.5237560272,0.3400763571,-0.1233913451,-0.2009309828,0.8506157398,-2.1546499729,0.3547619581,-1.6757706404,-0.1415503621,-0.8680157065,-0.0768875107,-0.1592646539,-0.5014755130,0.0249998868,-1.8573825359,-0.3155896068,0.5905711651,1.0066084862,-0.5826127529,-1.1200389862,0.1239113286,-0.4321572483,0.2175883204,-0.1679378450,0.6261950731,0.5056493878,-3.1710517406,-0.1413709968,0.6767768264,0.3793789148,0.3022807539,0.7109302282,0.2650648355,-1.0345375538,-1.6468921900,1.0483371019,1.0237673521,0.3251764774,1.2741376162,0.2375988215,-0.7581788301,-0.5037139058,0.0572597869,-0.8450796008,-1.1608557701,-1.0911349058,-0.5320959091,0.9157405496,0.4893115759,1.6712793112,-0.5092890263,-0.9690325260,1.4766815901,0.7314090729,-2.4690501690,-1.3202705383,-0.3301222920,0.8962110281,2.0390863419,1.0254950523,0.1695734710,-0.2835012674,-1.0160237551,-0.2788228989,-0.0651427954,-0.3828991652,0.2328362316,-0.7724130750,0.5774948001,-1.8650261164,0.2756900489,-1.3820643425,-1.4922863245,-0.3723741472,-2.0753431320,-1.7942260504,-0.3470088840,1.7341159582,0.8438899517,1.0441874266,1.4977054596,1.0677449703,0.1652990133,-0.1096124351,0.1542658657,-0.0562523417,-0.0727530718,-1.1196274757,1.4136055708,-0.4164610803,-2.0809350014,0.0478956066,0.9895527959,-0.8603312373,-0.6730191708,-0.5802956820,0.7802674770,-0.9864706397,-1.9121707678,0.6803776622,0.1682149619,-0.7673743367,0.7056384087,-1.0421631336,-0.3231330812,-0.9202150106,-1.7474627495,-1.6890426874,-0.0504816063,-0.7599089146,0.6442566514,-1.4180889130,0.8134864569,0.3692963719,0.3944670260,0.1946570277,1.3176888227,1.3182153702,-1.4753251076,0.2395100147,-2.1885092258,1.0353777409,0.4226379693,2.4927759171,-0.7165281773,-1.2685643435,0.7180500031,-1.0596232414,-0.1318729967,1.2955181599,1.4145418406,0.3703507483,-0.2906166613,-2.1202604771,1.5874541998,-0.4480857253,0.1233151332,1.2725905180,-0.4341225624,0.8674485683,2.0624625683,0.5839276314,1.4544333220,0.3140803874,-1.1686724424,1.4655153751,-0.1854373813,0.0675033107,-0.1820190549,1.3975430727,0.3684431016,-0.5828213096,1.6327118874,-0.5973852277,0.6849465966,-0.5043992400,3.1433739662,1.0341066122,0.1156917736,1.5954945087,2.6153404713,0.6946935058,1.7668703794,1.1358177662,-0.5453659892,0.3216398060,-0.3820880949,-0.7366890311,-0.5614402890,-0.6733281612,0.5156762600,-1.2313117981,0.5289177299,1.3301786184,-1.7023651600,-0.9341116548,-0.8916813135,-1.1652710438,-0.1437996477,0.9670381546,0.2372026592,2.4822874069,0.5470020175,0.4206858873,2.6281704903,-1.5163463354,-0.5004493594,1.2942957878,0.6173464060,0.2298103869,0.4356625080,0.3032996058,1.1061048508,-0.3733479083,-1.9930585623,1.1398425102,1.1698259115,-1.2241064310,0.7899841070,0.2383679450,-0.7305232286,-0.4423871934,0.7964922190,-0.4245458543,0.3769742846,-1.8120678663,0.5874359608,-0.0313255563,-0.7554463744,0.6911882162,-2.2524123192,0.5145077705,-0.4655631483,-0.5376864076,-1.6770755053,-0.6433816552,-0.0429741144,1.1280231476,1.1490014791,-0.0671586543,-1.2202082872,0.7045454979,-1.0823764801,0.1428896487,-2.9295396805,0.6375863552,-1.7725259066,0.6920745373,0.0506045334,-1.8579263687,1.0407875776,-0.1360074580,-0.8596337438,0.0067301448,-0.1954611391,-0.1238392219,-0.8143445253,-0.6136426926,-0.9348247051,0.4640007019,0.7521933913,0.6640645862,-0.1378400475,1.1553994417,1.0206215382,0.3986735940,-0.4069051743,-0.0785310194,0.4717287719,0.2707085907,0.1270379424,-0.4223307371,-0.3201220334,-0.3389673233,0.4850408137,0.4809367359,0.2361204922,-1.0482326746,1.0621023178,-0.1028745249,0.1858724207,0.3908754587,-0.6750885248,0.2174529731,-1.0515180826,0.2160267383,0.2982191145,0.8590397835,0.0086025409,0.5641648173,0.4481794834,-0.6979264021,0.3443371356,0.3175536394,1.2855532169,-0.7491867542,0.3338579834,0.7577729821,0.3670987785,0.2343304902,-1.9538394213,0.7163391709,0.3700796068,-1.7885614634,-0.9458172917,3.0109028816,1.4560543299,0.6147252321,0.6920373440,0.6372101307,-1.3865582943,-1.7684077024,0.5304525495,-0.0079795672,0.8801140785,0.9465383291,0.1581633389,-0.8426349163,0.9479221702,-0.1354119480,-1.5711832047,-0.3637903631,0.4112898111,0.1602426320,-0.1830785424,0.7868187428,0.4419188499,0.0504920371,-2.2241265774,-0.6185190678,-1.1892626286,0.6705932617,1.0291326046,3.0448400974,-0.8008592725,0.9581548572,1.3260705471,1.1762444973,-0.9842439294,2.0668766499,-0.3960740864,-0.1752684265,-0.7192801237,-1.4173226357,-0.5742908716,-1.1648813486,0.9344018698,-0.1113579199,1.6854794025,0.3993677199,-1.1008958817,-0.5278835297,-0.7492056489,0.7847382426,0.4598958194,1.8640118837,0.4370495081,-0.9409788847,-0.5925995708,1.2170940638,-0.4932170510,0.7076863647,1.2122285366,1.3748151064,-1.1437553167,0.1958882958,0.1235001981,0.0688811988,-2.3859999180,-0.5745288730,1.7441747189,-0.8688986301,0.6938255429,0.2857529819,0.0937574208,-0.6805610657,0.6712647080,-0.2787623405,-1.1043686867,-2.3983387947,-0.8090463281,-1.0024791956,-1.1571393013,0.3918244541,0.3093427420,1.1425877810,0.9271572828,0.7051991820,1.2124754190,-0.4664890766,0.0037588740,1.7412911654,-0.4158358276,-1.5634813309,-1.3250594139,-0.2688057721,0.2384223789,-0.5030126572,0.8553127050,0.4374273419,1.1957253218,0.0462666750,-1.8070065975,-0.4504835904,-1.3686780930,-0.3058474660,-0.0495945141,0.1645372808,0.1849104613,-1.7716939449,2.3738782406,-0.1378646493,2.4643244743,0.5075989962,-0.1704922765,-0.0185646489,-0.0093221944,2.1728961468,0.9254801273,-0.5384533405,0.9051353931,0.3683229089,-0.8445315957,-0.3709745407,-0.9525077939,0.6499077082,-0.0273034014,-0.4088584185,2.1410124302,0.8542435765,0.9650903940,-0.6568892002,1.6100125313,0.7433479428,-1.6218360662,1.1497720480,-2.6727676392,0.3415644169,-0.4711919725,-0.4807176888,2.3651483059,-1.6804189682,-0.7778606415,-0.5134579539,0.8294714689,0.3388239145,0.5550401807,0.3536906242,0.8353669047,-1.1603729725,-0.9736599326,1.4669877291,1.6135033369,-0.1117185876,-0.3129193783,1.0819211006,-0.7731477618,1.1307908297,-0.6786795259,0.2116177529,-0.0737237260,-0.4597691596,-1.1927083731,-1.3991508484,-0.2123755366,-1.2098524570,1.4069837332,-0.2333389074,0.0752018467,1.4358216524,-1.5128277540,0.4061498940,-0.7061683536,0.2710811794,1.2111703157,-0.4321515858,-0.3260831237,0.0225785729,0.2212020308,1.4104518890,0.2452560216,-1.5462257862,-1.2980943918,-0.1110542938,1.1513741016,-0.3489472270,-0.8876929283,-1.0408627987,0.4383756220,-1.5169585943,0.4438357651,-0.3842916191,2.2116289139,0.2712109387,-1.6035920382,1.0682024956,1.2236803770,0.5410172343,-0.5111415982,-1.3180493116,0.4625207186,-0.0136173591,-0.5168929696,2.2955324650,-1.3852297068,0.6380922794,0.0593690909,1.6699051857,-1.6007295847,-0.3379013240,1.0723598003,-0.9798635244,0.8318992853,-0.8471778035,0.3142752051,0.5284886360,1.1218874454,1.8486001492,2.7345709801,0.4374895692,-1.2230619192,-0.2786168754,1.1966751814,0.7694658041,-0.4521544278,-0.4873460531,0.0760180429,-2.1347806454,0.9052285552,-0.5944761634,-0.3380056322,-0.1664792448,0.5691460371,-0.5731565952,-2.2000503540,0.0652889013,0.9432873130,0.3104563355,0.5494231582,-0.9663535953,-0.5229769349,-0.2445623577,0.5183826685,-0.9060575366,-0.9137417674,-0.1996527612,0.1335192323,-0.4433824420,0.3377778530,-1.6413617134,-1.7930675745,-0.1941461861,-1.8694553375,-0.9999119043,-1.4513466358,0.6723552942,0.1838610321,0.7941121459,-1.1660890579,-0.8116760254,-0.9434131980,-1.1249563694,-1.1655663252,0.6973057985,-0.6014246345,1.2728025913,0.1407245845,0.8612917066,-0.2324358374,1.4373520613,0.8628004193,1.5325776339,-0.1889394820,-0.5824972987,-0.9653490782,1.3446065187,-0.7162488699,-0.1897031218,2.0714435577,-0.6121030450,2.0374407768,-1.4945025444,-0.2567083538,-0.8972054720,0.1291142851,-0.3037604690,-0.8362293243,0.7068982720,-0.4486835897,0.2427803576,1.0932581425,-0.1559365541,0.7241747379,-0.7676721215,1.5684889555,0.7923648953,0.9502861500,-0.3227502108,-1.2624378204,0.2234718055,0.4752887785,0.2963661849,0.2820369303,-1.3083859682,-1.8737363815,-0.3256417215,-0.1815035492,0.3622895777,-0.2257685065,0.1857555956,0.0977337956,-1.1289507151,-0.1029930860,0.0768001899,-1.2031559944,-0.1173039898,0.0196279101,-0.2452402562,1.1445440054,-0.7530807257,-0.6296615005,-1.0584937334,0.7693899274,0.8202177286,-0.3264771104,1.0771063566,-0.4935064316,-0.5727998614,0.1287579536,-0.9393902421,0.9558954239,0.7553883195,0.6227222681,-0.0084682750,0.2514541149,0.8778777122,1.0188686848,-0.2856886983,-1.8559024334,0.0303529315,0.1430030465,-0.3618414998,-0.0351615176,-0.6785556078,-0.9759765863,-0.4848660827,-0.2929255962,-0.1925849020,-0.7591896653,-0.3228958249,-0.0205045063,0.3483543694,0.2820397615,-1.6995092630,-0.7122277021,-1.3917955160,0.5476497412,-0.3970116079,-0.0744653568,-1.1424483061,1.3950189352,1.2138121128,0.7932989001,0.3546606302,-0.1634015590,1.4944585562,0.7755617499,0.7647002339,1.2824169397,0.3859403133,-0.1856594533,-0.9363436103,0.4315616786,-0.2700640857,0.3939462602,1.4889338017,1.0297901630,2.0167706013,-0.5965355635,-0.8565047979,-0.9398768544,0.2297771126,-0.5574417710,-0.1267592162,-2.3832242489,1.1377506256,-1.1425361633,-0.5246202350,-1.5346717834,0.1314383298,0.0684951022,1.1131851673,0.2731709778,0.6787238121,-0.5446536541,0.0450214595,0.8453890085,1.8095526695,-0.2790301442,1.1491837502,-0.4293262064,-1.3085041046,1.0832661390,1.3500005007,1.1210151911,0.5666023493,-0.4597205520,1.0817568302,0.7697666287,0.8304558992,-0.2385064662,0.8480877876,-0.7320706248,-0.5562512279,-1.0011099577,0.5937754512,-0.8616179228,0.8863510489,1.6711868048,1.0623165369,0.6543915868,-0.1773722172,-0.0344006717,0.5973542929,1.2686825991,-1.5581994057,-1.1329184771,-1.2591944933,-0.6952503920,2.6306145191,-2.2633259296,1.0291699171,0.9703497291,0.7907989621,-0.9672769904,-0.7324648499,0.5958577991,0.2923487723,0.0744326934,1.4750037193,-0.1998525858,-0.1739941984,-1.8254380226,0.3562199175,0.7012470961,-0.2482330352,0.4486927986,0.0901318491,0.7526713014,0.2792355716,0.5251368880,0.3370932341,0.6470039487,-1.2970519066,-1.4007022381,-0.9944904447,1.5340650082,0.7310197949,-1.6445587873,0.4814043939,-0.5434415936,-0.9484261274,-1.4867604971,-0.5797979832,-0.1667503268,-1.4086076021,0.9149457216,0.4772666395,-0.6579295397,-2.5258929729,-1.9978051186,-0.2341778129,1.2802121639,1.7618249655,-0.8002349138,0.3736089170,1.1083867550,0.1761967391,0.4046993256,0.9638820887,0.8057360649,0.8382278085,-0.0438889638,-0.2375431359,-2.0383751392,-1.0941091776,1.5616539717,-2.0328569412,-0.9788680673,-0.6005727053,-0.5285338163,2.7921683788,-0.7145404220,-0.8009266257,-0.2848567963,0.6346355081,-0.4794748127,1.5668632984,-2.4055385590,0.4379455149,0.5932794213,0.6854198575,0.9216139317,-0.3407145441,-1.3855520487,-0.7462887764,-0.3033876419,0.0186376907,-0.0690334588,-0.2632014751,1.6265926361,1.4949783087,-0.6602244377,-0.7783056498,-1.3226950169,1.5882486105,-0.0956622288,0.7664166093,-0.5125342011,-0.7737212777,0.6168346405,0.7540829182,1.1455770731,0.3315310776,-0.1345494241,-1.5078363419,1.8647091389,1.8537608385,-1.0891287327,-0.5876540542,-0.3828836977,0.5380443931,1.4859291315,0.1173877418,-0.0830619484,-0.2604106069,0.9005637169,0.1149029881,-0.8461684585,0.9646666050,-1.3376936913,2.1376085281,2.3744444847,-0.1123782471,-0.6790237427,-0.2712702751,-1.2458635569,-0.2799184620,-0.0585089289,1.2172613144,-1.3013261557,0.4938486814,0.0018817389,0.1639826447,-0.1096468046,0.1895873547,0.6653810740,1.3794633150,0.3325508237,-0.3157938123,-0.4053605795,-1.2119607925,1.6195567846,1.0380227566,0.0044104871,1.2443182468,-0.5239819884,-3.1816990376,-1.6022835970,-1.0422313213,1.6971408129,-0.1422895491,-0.3386924267,0.0337778777,1.3895584345,-0.6798459888,-0.8735042214,1.4608218670,0.9804942608,-0.0700358227,-2.2575590611,-0.5207765102,-0.5970131755,1.4351145029,0.5342422128,-0.5326063633,-1.2744994164,-1.6573332548,0.1688603461,0.8684266806,-0.4371896982,1.9104814529,-0.1397882998,0.7860920429,0.3916041851,0.1504721791,-1.0214750767,0.2536700964,0.0443325303,0.4851707220,0.0727755502,-0.1179084405,1.6902691126,0.2719678283,-1.1939750910,-0.0545632914,-1.5358672142,-0.0898130834,1.1942884922,0.9992315173,1.0113880634,-1.4582569599,0.6580271721,-0.8810248375,0.7868432999,0.6703838706,-0.4072601795,0.8141466379,0.7604040504,0.2462893724,0.0050235200,-0.7474465966,0.6245143414,-1.0206460953,-0.8153722286,1.1893461943,0.4940040112,0.4967643023,-0.2958534658,1.8670926094,1.3553891182,-1.0535255671,-0.1981259435,-0.3524850905,-0.6183097363,-0.0779046416,0.7972301245,-0.5016496778,0.4480767846,-0.2101167887,-0.0168276727,-0.2014111727,-0.5612958074,1.3728827238,-0.3534809053,1.5735669136,0.9426801205,-0.0221692715,-0.9934756756,1.4621682167,-1.4462176561,-1.5750948191,-0.2356135994,-0.3192728162,1.4097740650,0.3186092973,-0.0515878908,0.4262378216,-0.0413998328,-0.7294147015,0.5786992311,0.5278693438,-0.2732734382,-0.0219900087,-0.5813630223,1.7156662941,-0.3235935867,2.4618074894,-0.6561592817,0.0910400450,1.2659327984,0.8638816476,1.0664783716,-1.2248061895,0.6043577194,1.0140352249,0.4129702151,-0.5681805015,-0.0218119808,1.3225139380,-0.0147479223,0.0736440644,1.1261093616,1.4245935678,0.9596525431,0.5288068652,1.1710895300,-0.7957918644,-0.1596978903,-1.3176041842,-0.3115763068,-0.0672747642,-0.3569861352,0.2234518230,0.3094016016,0.9527436495,-1.2522807121,-1.2509135008,-1.6274449825,-1.2778787613,-1.0911378860,0.2284249663,-0.3604622483,1.1675195694,2.0061020851,0.7697836161,-0.9829636216,-2.2009537220,-0.1629348844,-0.7106205821,-0.4898200333,-1.4288221598,1.0543422699,0.1862355769,-1.5556902885,-0.2575588226,0.5807380080,-1.8932569027,-0.4353618026,1.5906252861,-0.9965630770,-2.0895090103,0.9025256634,0.3491262496,-1.4236516953,0.1656542122,0.2637915611,-2.3229284286,-0.7769226432,-0.4434509277,0.2784052789,-1.7719700336,1.9006904364,-0.3290591836,0.4922101796,-0.5404827595,-0.9461563230,0.6440004110,-0.3489286602,-0.9171313643,0.4032333195,0.5990763307,-1.7341868877,1.2567689419,-0.2003704309,1.5010881424,-0.1889965534,-0.6302958727,0.1775143445,0.2809249461,1.7796574831,0.4534760118,0.1546487063,-1.5418481827,-0.5078651905,-0.8182194233,1.2638050318,-0.1745502055,-0.4214827716,-1.0797538757,-0.1164133102,-0.7410816550,-1.3497550488,-0.1168411151,-1.3411626816,-2.0407903194,-1.2275632620,-1.3231233358,0.0243034586,0.4815312326,1.4609789848,-1.4686429501,0.1677938551,-1.0592018366,-0.2852744162,-0.0706676841,-0.1581604034,0.9220636487,-0.1272540987,-0.2593966126,-1.7004094124,-0.5371990204,-0.7370152473,-0.0971123576,-0.3767374456,2.3517546654,2.6098873615,0.4989961088,0.0687675998,-0.3759937584,-0.8398221731,0.9545980692,-1.4972980022,-0.9398316145,1.1029561758,0.2521598339,-0.0855884403,-0.9977290034,0.8008356690,1.5740467310,0.4187212586,1.9298514128,0.1145944372,-1.1502786875,0.0434628800,-0.1572289616,1.0625115633,-0.8050823808,0.2032386810,-0.0399338417,0.5518578291,0.8568918109,1.7390502691,0.6615341306,-0.5819038749,-1.2263169289,0.1351081878,-0.1532971412,0.2919063568,0.6675716043,-0.0507290736,-0.6389257908,-0.1211285144,-0.1745242774,-0.2457411587,0.2195800394,0.6483494043,-2.5658056736,0.9271953106,-0.3155171871,0.2342108935,-0.4574358165,1.2141743898,2.0983936787,1.2039935589,-0.1287723780,-0.0756367967,-0.2917146683,-1.5107499361,-0.0836014524,0.7631447315,1.9176464081,-0.5091345310,0.0782249793,0.1212063432,0.6442352533,-0.7711468339,0.5957395434,0.2253505737,-0.9019545317,0.5706453919,-0.5385786891,0.9147205949,-0.7850139737,-0.1509184986,1.2764766216,-0.5555887818,0.5547939539,1.4719022512,-0.2048540562,0.1632129550,-1.7694426775,0.3638873100,0.2493520528,-0.5556089282,0.6050454974,-1.1778032780,1.2873336077,-2.7311754227,-1.8287607431,-0.3213097453,0.2433038205,-1.2711951733,0.2429094762,1.5860184431,1.2297668457,0.9442595243,-0.8065596819,-1.2923262119,0.8501077890,0.3705936670,1.4010832310,-0.4744163156,-0.2130869031,-1.9867215157,1.2959045172,-1.9881888628,0.1270659864,1.1208313704,-0.1007476598,-1.1433990002,0.1744137406,0.2917715907,0.2511937320,1.7150257826,0.9280009270,1.1453393698,-0.3360704184,0.4720384777,-0.3854337335,-0.4944903851,1.6074732542,-0.7994801998,1.4878766537,-0.0383373089,-0.4597311318,0.4766893387,0.7497329712,0.7272310853,-0.5855666399,-0.1302246153,0.3075602651,-2.5834276676,1.1175756454,1.2175463438,-0.4559751749,-1.0002273321,-0.4586575031,-1.1881129742,-1.0883032084,0.4656453729,0.1931448430,-1.4194663763,-0.1684705317,-0.0929002762,1.4055173397,0.1011286005,-0.2336747944,-0.7242429256,-0.4713487029,-1.6743985415,-0.4759764373,0.6226197481,-1.0360772610,-0.7374758720,0.3776315451,0.7032527328,0.3570717871,1.6821124554,-0.7404009104,-0.6392166018,-1.8168293238,-0.2498717159,0.9376166463,0.3249538541,1.8151599169,-0.8932920694,0.8224828243,0.2315905243,-0.4471608400,0.3912411332,0.9867906570,-0.1927725524,-0.5247645974,-1.5280073881,-0.1495466530,0.0160353705,0.0425342433,0.7152678370,0.3655344248,-0.9652132392,-0.8394863605,-2.0853965282,1.5263340473,0.8999857306,-0.9665651917,1.3215459585,1.6256463528,-0.6425731182,-0.3002862930,1.3954046965,-2.0651483536,0.3873505294,1.7838572264,0.8483130932,0.7518290877,0.5456620455,1.5536112785,-1.3005512953,-0.0011652977,1.1804986000,-0.3673217297,0.0885236189,0.8989169002,-2.2710711956,0.1494538188,-0.0522320829,-0.7923706174,0.2892282903,-0.2980457246,-1.0174229145,0.9635899067,-0.8385112286,0.6136938930,0.2540693581,-0.9374857545,0.9380664825,0.1181033030,1.1129386425,0.9579056501,-0.9558597207,1.0601702929,0.7341737747,0.2400165498,1.3471019268,1.6240410805,0.8954927325,-0.2616872191,-1.5816322565,-0.2222897261,0.1012802795,-0.6242704988,0.4884990752,0.9954836369,1.2131110430,-0.7540560365,-1.0051815510,0.6316062212,-0.3438287973,0.2564253211,-0.3662753701,-0.4446938932,0.6212993264,0.5648611188,-0.1582486629,-0.5771440864,1.2945601940,1.4222235680,0.9416752458,0.6796181798,0.1929067373,-0.8631902337,-0.0065787770,-0.2801783681,0.1711493433,1.6927223206,1.9421662092,-0.6135012507,1.3712947369,-0.6469724178,0.0916923508,-2.0832099915,0.3947067261,-1.0328670740,1.3029398918,0.2731808722,0.1960372478,1.0402327776,-0.0111813899,-0.0176756624,1.6581752300,0.6408863068,0.2431170642,0.1895090193,0.5048427582,0.7047714591,0.9869223833,0.2082526386,-0.1569980681,1.8514502048,-0.1799520552,0.4686902165,-0.7296008468,0.9013362527,-0.1100251153,-1.0055503845,-0.9817690253,0.8043930531,0.5625268221,1.8719913960,-1.1463146210,-0.0346449055,0.1817469299,0.9270682931,-0.2574214339,-0.0812553093,-0.5912104845,-0.3345954716,-0.8301431537,1.0862048864,-0.7808485031,-0.0158352572,-0.3031056821,1.6571618319,-0.8905954361,0.0837379172,0.6826679111,0.5788830519,0.2168190330,0.5412689447,1.2712599039,0.7540125847,0.6827997565,-2.8907747269,-1.5387016535,-1.5241500139,-0.3924700022,0.0892303810,-0.5330017805,-1.7088195086,-0.1490052342,-0.3517466784,-2.0205872059,0.7012131810,0.9212424755,-1.2042565346,-0.8458803892,1.0954351425,0.1554866433,0.6053807735,-1.4512552023,-0.0093505876,0.7159829140,1.6241915226,-1.0060654879,0.5553455949,-1.4876133204,-0.9805587530,-0.6491589546,0.0377813093,-0.4374382496,-0.4266566336,-2.0373737812,-0.3526954651,-1.3506067991,0.7612988949,-1.1326609850,-0.2315673083,0.4062868357,-0.4989110529,-0.0301045813,-0.2450016141,1.1841666698,1.1055570841,-0.3115909100,1.5708198547,0.0280597452,0.0123594552,0.4701385498,-2.1805176735,-0.4992506504,-1.8012614250,0.6283216476,-0.8813948631,0.6601570845,1.7074941397,-0.0323648006,0.8825834394,1.3912378550,-1.6596704721,-1.6631295681,0.8406025767,0.0631161332,0.1085712463,2.0449030399,0.0345824733,1.1145036221,0.4704167247,-0.1383501887,-0.4539908171,-0.0641246885,-0.3558729589,-0.9145979285,2.0010707378,1.6858053207,0.3380937576,-1.3622864485,1.6141508818,-1.9733695984,0.9540565014,-2.1892340183,1.3951656818,-0.5408843756,0.6286481619,-0.7919251323,0.0105986586,0.8478817940,0.0002034874,-0.9074158669,1.5799069405,-0.2770311236,1.0688809156,0.9766724706,-0.7193752527,-0.4294345379,-0.1861296296,0.7368682027,-0.1072331071,-0.8955709338,-0.2778291702,-0.2356924266,0.0711850822,-0.6330330372,0.2691031694,-0.5513830781,-0.7187303901,0.0601756237,-1.5095027685,0.8429980874,0.4193808436,0.0188407283,1.1542465687,0.9463533759,-2.3277208805,3.1905584335,-0.8127261996,1.6442073584,1.6567442417,-0.8463044763,0.1784670353,-2.0980811119,0.8293775916,1.9536508322,-0.7747604847,1.1398042440,0.9690032005,-0.2423246056,1.3939158916,0.1454046220,1.7181164026,0.0453010388,-0.0042198766,-1.3608663082,-0.5003177524,-0.8680332303,-0.9361079931,-0.3540412188,1.5443038940,0.1527195871,1.9295225143,0.8829023242,1.0667285919,0.7185322046,-0.1005984619,-0.5712147951,-0.2969015241,-1.0879497528,0.1453319192,1.1827607155,-0.6063740849,-0.5514721870,1.3078466654,0.8379271030,-0.6013044119,-0.9620295167,1.0878808498,-1.4823607206,2.0232403278,0.6163513064,0.5846143365,0.1666686833,0.4976269603,-0.1785562485,0.7540314794,-2.4182591438,1.3574743271,-0.5127028823,2.2171654701,0.8127683997,1.0364259481,0.0117332144,-0.7456771731,-1.8012324572,0.5935599804,1.0617488623,0.1362540573,0.5942974091,-0.2413583249,0.8704653382,0.6090841293,0.8453356624,0.2453041673,-0.7767860293,0.4689100981,-0.2965798974,-0.2062119991,0.3263522387,0.2172193527,1.1833193302,0.2821285129,2.3209342957,-0.1554056257,0.1805481464,1.7754137516,1.7161456347,1.2346943617,-0.8394340277,0.3948509991,-1.2444956303,0.7143678665,0.1295471340,-1.6973470449,-0.9740580320,0.9478079677,0.0702200681,0.6023330688,0.3383901715,-0.5129318237,-0.9346300960,-0.2646407187,0.5493919849,0.3167619407,1.0960144997,-0.1926865131,1.1150927544,1.4298577309,0.5634369850,-0.8687397242,1.0241733789,-0.7390829921,-2.4886791706,0.1626223028,-0.0862197801,2.2243971825,-0.4995155036,0.1662081778,-0.3019536138,1.2557128668,0.2725491226,-0.4110666811,-2.0384042263,0.4620322287,-0.9412257075,-0.3955143094,-0.9924059510,0.1638202667,0.3578505516,-0.4322696328,-0.7486923337,1.4323714972,0.4394994676,1.2358547449,0.6357761621,-1.2816650867,0.3573113084,-1.6242008209,-1.2238067389,0.1763255596,0.7219309211,-1.1676596403,0.3330031931,1.0878335238,-1.0375856161,-0.5326374769,1.8756786585,1.5115497112,-1.2856667042,1.1450330019,-1.0966980457,1.1074422598,-0.6321702003,1.5199065208,-0.5065426230,-1.0368436575,-0.0203417726,-1.3390274048,-1.2279171944,-1.0808128119,0.3871849775,-0.3497922719,2.3117475510,0.6136760712,-1.0078067780,-0.8818475604,0.8308844566,-0.2642922997,-0.8865725398,-0.2153000832,-0.2417999208,-2.1490194798,-0.7199160457,0.0679587796,-0.2582596838,-0.8022152185,0.9388174415,-0.9667415619,2.2158970833,0.9668938518,-0.6219958067,-2.9191241264,0.7569295764,-0.3887217045,-0.9876939654,-1.3517054319,1.3579764366,-0.4132209122,-0.3938776553,1.0867658854,1.0614277124,-0.3257678151,0.5012996197,-0.9414650202,0.8639216423,-0.1593751311,-0.8448317051,0.5117835999,-0.0846990570,-0.3059445918,-0.5071154237,-0.5131493211,0.0728861243,-0.0135237006,-1.0407599211,0.1897208542,0.8545592427,-0.5512021184,2.0016546249,2.1962902546,0.6786051393,0.6614071727,0.3245737553,0.7180817723,0.5551066399,0.0685995594,0.1573880464,2.0783345699,0.5659430623,2.3344035149,0.3795775771,-1.1248421669,-0.6414177418,2.1331074238,-1.0174721479,0.3696995974,1.3464163542,0.4752027988,1.4939831495,0.4542889595,-1.4727809429,-0.4702996016,-0.3798926771,-0.0606959425,-2.7277064323,-1.2520660162,-0.1419366747,-1.7190331221,-0.6506875753,0.0628099963,-0.7629907727,0.6080714464,-1.9897142649,-0.3891165257,1.0277502537,1.1713209152,1.4797284603,-1.3836252689,-0.2505295575,-0.4447467029,0.1925516874,-0.6498235464,0.2901880443,1.6240186691,0.4743281007,2.1063592434,0.5284393430,-0.8047794104,0.2104256451,0.7566365600,0.9716638327,-0.2522500753,-1.2101258039,-0.9453462958,-0.8787621260,-0.0724296495,0.6382610202,-1.0404309034,-0.4261433184,1.5532246828,0.5275081992,-0.3574368060,-0.7761614323,-1.7335830927,1.0692806244,-0.5937536955,0.4269003272,-0.3536632359,0.9446827769,2.5059707165,0.0690293163,0.2944066226,-0.7414646745,-1.0082733631,1.1343686581,0.2710540593,0.7274960876,-0.2651674747,-1.4867268801,0.5070603490,-1.2814332247,-0.3046406507,0.5114221573,0.3708107173,0.1999140978,0.7607744932,0.0477416702,0.4222696722,0.2854658961,-0.9390783906,-0.7843756676,-0.8260797858,1.4266068935,0.8196808696,-1.1903074980,-0.4611110985,-0.4952437580,0.6804166436,-0.6994231939,-1.1552095413,-1.7887793779,1.3153162003,0.6558619738,0.4816769361,-0.0126672778,-1.3285335302,-1.2688424587,-0.1523873210,-0.4339653254,-0.1709483713,0.2231142521,1.4828188419,-1.4240397215,-1.4417916536,0.4451074302,-0.1589459926,1.2505066395,1.3375947475,1.1642736197,0.3594298959,0.7713550925,-0.6801846623,-0.4980467260,0.9504658580,1.6608889103,0.4158179760,-0.2972727418,1.2367286682,-1.0620138645,-1.8265507221,-0.5331158042,-2.1153428555,-0.6209367514,0.4675408602,0.6143893600,-1.7113894224,0.2891764641,-0.6705935597,0.4754212797,0.3198952973,0.7838545442,0.3976619542,-1.1661629677,0.4603621066,0.9248743653,2.1145966053,0.0825881287,0.6749655008,0.8121272326,-0.2189459950,-0.1639946699,0.3587153256,-0.7834233642,0.6059847474,0.5444562435,-1.4124641418,-0.0233196020,0.0880037472,0.1275142431,1.0809987783,0.6402114630,0.7634710670,0.9324608445,0.3846043348,-1.7244272232,0.3992971778,-0.3185180128,0.1687958091,-0.0704131722,0.6610387564,-0.6090794802,-0.4523200393,1.0825520754,1.0088615417,-0.5682323575,-1.3370556831,1.0058012009,1.6292598248,-1.2862094641,-0.6961910725,0.2314819843,0.7249957323,0.6836280823,-0.1757106632,-0.9063949585,-1.3477391005,-1.1346484423,0.3227340579,1.3607194424,-2.8635163307,0.2292383462,0.4060978889,-1.3265417814,0.2751484215,0.7121296525,-0.6921774745,0.6154708266,0.2200543880,-0.5754459500,0.3323008418,2.1421134472,0.7250728011,0.6870709658,0.5515963435,-0.5132011175,-0.1644386500,1.9557372332,0.5852532983,0.7971339822,-0.4506426752,1.4849123955,0.2836766541,-0.6032394171,0.4705572426,-1.0361155272,0.2024379373,2.0730745792,-0.1682272553,0.3044758141,-0.1541289538,-0.6910542250,1.4061708450,0.4611213803,-0.2320941687,-0.4938946962,-0.2043031901,-0.0456889868,0.9397354126,0.9698880315,0.0257637091,-0.2238553017,-0.2935015857,1.0003639460,0.8938386440,1.1174061298,-1.4390172958,-1.3158385754,-0.4139026999,0.4302385151,-2.2730138302,-0.6109037995,0.6164110303,0.3562093377,0.9595016241,-0.5901470184,1.8615894318,0.3402916193,-0.0181768406,0.8151611686,1.2026921511,-0.9299021959,0.6094628572,1.2707104683,0.4547021091,0.9683445096,-1.0731282234,0.7785558105,1.6914439201,-0.2198672742,-2.2547419071,1.2058824301,0.6307622194,-1.8844203949,-0.3400211334,-1.4175158739,-0.1408693939,-0.2282040119,0.6934574246,1.0840233564,-0.1311188787,-0.4547898471,0.0308669638,-2.9230649471,0.1924819946,-0.0251757074,-0.1361604929,1.3143212795,1.3681744337,2.5020995140,-1.7766501904,2.9016273022,0.4275854528,-0.0154027585,-1.1051633358,0.2060504258,0.1583422422,0.3727222979,0.9876830578,0.0626214370,-1.1221803427,3.4378697872,-2.8637402058,0.9245373607,-0.2257023752,-0.5427214503,-1.8706995249,0.5202276707,1.4523717165,-1.8733434677,-1.2647411823,-0.5458576083,-0.6326601505,1.9794954062,-0.0096601248,2.2758998871,0.3492978215,0.2012365162,0.2095893174,0.6796535254,0.0502694286,-0.0435023643,0.2123025507,-0.4695489109,-0.3350050747,0.2190171927,-1.0715231895,0.3171286583,-0.2802983224,-0.6058686972,-1.5530456305,0.9496842623,0.2735980153,-0.4321633577,-1.6320595741,0.8468621969,0.6839948893,0.2943500280,1.5179771185,-0.3009389341,1.1591215134,-0.4598817229,1.6021217108,-0.2987172902,0.1620407104,0.0022509200,-1.0108187199,-0.9158037305,0.6183546185,-0.0589140914,1.9188567400,-0.0930142999,0.4509327114,1.3160575628,0.1009306461,-1.2808429003,-0.3061289489,0.2605623901,1.1934047937,1.3779098988,-0.8680241704,-1.0800518990,-0.0498448424,0.4656108022,1.0705919266,0.5382865071,-1.0938647985,0.6651583910,0.1397799551,-0.7773083448,0.6970692277,-1.1914598942,0.4689689577,-1.5771685839,-1.7258087397,0.9759751558,0.9858368635,0.9479118586,0.8612651229,-0.4446322322,-0.3175063431,1.2068784237,-0.5929441452,0.1791196018,-0.9298995137,-0.4742261767,-0.4334574640,1.3930308819,1.5312166214,0.5114341974,-1.9366881847,-0.0120311510,0.2527293563,-0.3314227462,0.5194210410,0.1215722114,-0.5180037618,-1.5782446861,-0.3423944712,1.1970065832,-0.0611416213,-1.3710052967,0.8990535736,0.5925429463,1.5193586349,-0.4414147139,-1.0274288654,0.3192766309,-0.2304987013,-0.0761491209,0.0690865219,1.3222659826,0.0257438123,-0.2477024496,0.2511856556,-1.5257942677,1.4712384939,-0.0396799296,-0.0264192075,-1.6288158894,-0.7242621779,1.9021406174,-0.5092082620,-0.0244931318,-0.5751573443,0.9152583480,1.1320323944,0.3048408628,0.7192915082,0.0029749731,1.7288789749,-2.0123455524,-2.4080128670,-1.7593473196,-2.4347224236,1.6136039495,0.4126974642,-0.7342951298,-1.0291619301,-0.2701182067,-0.2743706107,1.5435656309,-0.4356430173,-0.3694144189,0.5576394796,-0.2556772828,0.4563857317,0.2570762634,0.3890536427,-0.8774389625,-0.2383845448,-0.5045922399,1.0469880104,1.6212552786,-0.2120764405,0.6647508144,-2.0476558208,-0.8174135685,-0.8982970119,0.7912128568,-0.7010203004,-1.3018070459,-1.6871378422,0.5631584525,-2.1441884041,-1.6575580835,0.9514712691,1.6940368414,0.0827083439,-1.3294876814,-1.1565612555,-0.1200775355,0.4073521793,0.0284242388,0.0219066888,0.5942062140,-0.4101213515,0.8342248797,0.3034593165,0.2702042758,-0.8202449083,0.8972294331,0.1362715960,0.6182371974,0.3332054317,0.3803861737,-0.0642565563,1.5682134628,0.0266444050,2.2625157833,-0.8821482658,0.9058094025,-0.9818913341,-0.6558931470,2.1423466206,0.8509710431,-0.3466790020,0.8928981423,1.8331450224,1.0823125839,-2.2121467590,-0.2042878270,-0.8251465559,-0.3494953811,0.5181334019,1.1187945604,0.8085275888,-0.9451194406,-0.1899499297,-1.5023754835,0.5746624470,0.3227597475,0.9226501584,-0.6544494629,-1.2606118917,1.4417942762,-1.2978820801,-0.0916388780,0.2793105245,1.1175570488,1.7324228287,-1.0782588720,-0.0125431186,0.6125292182,-0.2632619441,-1.0598345995,0.2111615837,-0.3366095126,0.9723577499,-0.0001053959,-0.9998166561,0.3668155372,-0.1650307626,-2.6319227219,-1.3921569586,0.5988414288,-1.7351586819,1.4667917490,-0.5279781222,-0.3885532022,0.3108111024,-0.1206910387,0.8990362287,0.1039673463,0.1421874166,0.4403844476,-0.5696710944,-0.2248260379,0.9770126939,1.2786602974,0.8683383465,2.3025348186,0.0278422982,-0.1820368022,0.8733520508,-0.3343454897,-0.5557032824,-0.5515244007,0.5276218653,-0.7114800811,1.7720230818,-0.3970922530,0.4389536083,0.0650350600,-1.1340105534,-0.7053775787,-1.8313711882,-1.6354445219,-0.4521007836,0.3524754345,0.4045782983,-0.1586718410,-1.0496007204,-0.8052915335,-1.4610325098,0.3669247329,-0.9069761038,-0.7325763106,-0.9586330652,-0.1848229915,0.1050765216,-0.1473184377,-0.1583449841,-0.3924146891,1.3609659672,0.5217448473,1.9404394627,1.0777040720,0.3909571171,0.6589066386,0.1673523486,1.0541881323,0.3378158808,-0.7065559030,0.1609089524,1.7601629496,0.2293126136,0.9480530024,-1.2335206270,-0.0344778039,0.7309923172,-1.5902619362,-0.4351943135,0.6615905762,-0.3688139915,2.3102419376,-0.9426203370,-0.5544672608,-0.6343543530,1.0669492483,-0.2379402369,-0.4261119664,1.8326580524,-0.7513182163,-1.4482220411,-0.7471646667,-0.8635528684,-1.2731425762,0.6533293128,0.6602415442,1.2218433619,0.6049968004,-0.5613385439,0.0613612570,0.9906570315,0.5033934712,-0.6237265468,-0.0041219913,0.8261147141,0.2427824140,-0.3063735664,-0.0811720788,0.1534022242,-1.1207720041,-0.6678703427,-0.2377390862,0.8940547705,0.2770272493,1.3696693182,-0.0493086502,-0.0745674670,0.4672318697,-0.3150355816,1.4334459305,-0.1679604053,-1.9706282616,-0.3613967896,-1.6547517776,1.1160451174,-1.6003566980,2.0415852070,2.0366399288,-1.0523581505,0.3376710713,1.0529056787,1.6930022240,0.9688546062,-1.4531956911,0.8070805073,-1.3145008087,-1.4333742857,0.0553366765,0.4915426075,0.3531095684,-0.7884507179,-0.1045462191,-0.5995621085,-1.3206208944,0.6596292257,-0.9884840250,1.9658976793,-0.4340378940,0.0516867973,-0.5761942267,-0.4747160673,2.0759608746,0.9117660522,-1.3595043421,-0.0750775263,1.0767716169,0.8811606765,1.1698845625,2.6263203621,1.5705279112,-1.4361846447,0.8416768312,-0.7291257381,-1.9000356197,0.1692651510,-0.5643911958,2.2524120808,0.3646518886,-0.2983020544,-0.4583005309,0.9823272824,0.0525144637,-0.7168455720,0.5617127419,-1.3276793957,0.0449519083,1.7765147686,0.3622149229,-0.7156533003,2.7877490520,1.1703428030,1.6707651615,0.9258809090,-1.0642477274,1.1153731346,0.5419448614,0.0624054596,-1.0790256262,-0.2572177947,-1.1862916946,0.9607563615,0.1119695157,0.5639559031,-1.7139394283,-1.2567867041,-0.2268253267,0.3858694136,-0.0999460742,0.4597186148,-1.6977158785,-1.0717468262,1.4142743349,0.2119618356,1.3924894333,-0.9887067676,-1.0531584024,-1.2928825617,1.2426022291,0.5878120065,-0.9949681759,0.8283343315,-0.2635304928,0.4014886022,-0.6090260744,0.5791243315,0.5834465027,1.5511604548,-1.2230901718,-0.6187438369,-0.3775131106,0.9911983013,-1.7839671373,0.1290750504,1.6611936092,-1.9548208714,0.5270512104,0.9121604562,0.4895628095,0.0196124874,-0.4402401149,-1.8178555965,-0.2203289568,1.2370438576,-1.3454525471,2.4535121918,-0.1176287308,-1.0192205906,0.5798735619,0.0242904909,-0.0841123089,0.5548579097,-0.7952302098,-0.8613741398,0.8380604386,1.0689024925,-2.4395861626,0.3448410630,-0.5043354034,0.0641216338,1.1720117331,1.2903999090,0.4812498987,1.1072002649,1.0949929953,-2.3961193562,-2.7901766300,-0.2823035121,1.2701352835,-2.0818095207,2.6965289116,-1.3935769796,-0.2706691027,1.0988687277,-2.1704502106,0.6163380742,1.3522902727,0.7691040635,-3.0363001823,2.5481321812,-1.5075689554,-2.3067941666,0.8177285790,-2.4801552296,0.9572334290,1.1474175453,-0.5582699776,-0.2533708811,0.1953659654,0.0904167295,0.6058718562,0.3594837487,0.5418453813,-1.2951164246,0.4690193236,1.7330023050,0.1667902321,1.1768552065,-0.0910997316,-0.2359167486,-0.0121873543,0.4238246381,-0.0331050605,-0.5837310553,0.5397078991,0.3845285177,0.1106715724,0.1258557290,-0.4165729582,1.0588035583,0.4541542530,-2.6346459389,-1.2074881792,-0.1499014944,-0.3375472128,-1.5428763628,1.2837784290,-0.6475168467,0.3657090068,0.4615589976,1.6139746904,1.0400425196,0.8091872334,0.0503223762,-1.4139139652,0.1132474169,1.5251283646,1.6179705858,1.2431045771,1.7049555779,0.1189959124,-0.2425130904,0.1800673753,-1.4013088942,0.6485371590,0.8376440406,1.1608923674,1.1170085669,-0.8883395791,-0.1524236053,-0.8715451360,-0.1062527671,1.8281518221,-0.6069445014,-0.6816360950,-0.3067930639,0.9655979276,-0.2940889299,0.9251574278,1.1493262053,-0.5966495275,0.5556038022,1.9187790155,-0.2040707618,-0.4193641543,0.2341037840,-0.2179090828,0.7499462962,-0.2418686002,0.5113593340,-1.8201842308,-1.1509025097,-0.7798062563,0.1130120382,-0.3003650606,-1.9360016584,-0.9553108215,0.9728742838,-0.1972751766,-1.7404620647,-0.4687793553,1.1957448721,-0.5498569012,-0.7883052230,-0.1498728544,0.2681272030,-0.2486549169,-0.4183347225,-0.3109455109,0.1175777838,0.7868638635,0.9115644693,0.1073277220,-1.0881794691,0.8313896656,0.4506823123,-0.9034633636,-1.0354187489,0.6935775280,1.1028820276,0.6876826882,2.0347700119,0.5668647289,-0.3477827907,1.6544166803,0.3295305669,-0.1434911638,-0.1425676346,-0.4272623062,-1.2900912762,-0.2381984293,0.6456766725,-1.0504271984,-0.9134973884,-1.0105756521,1.1871837378,0.2558339238,0.9838050008,-0.5840255618,1.6918026209,-0.7227749228,0.5577063560,-0.2009231299,0.9748980999,1.0686962605,0.1406216919,1.4599475861,-1.1134356260,0.4520905316,-0.3960721493,0.9606674314,0.4791612625,-0.5085137486,-1.1975919008,1.2257055044,-0.7944650054,1.0772857666,-0.8134288192,-0.1460259855,-0.7566825151,0.5483761430,0.4096541405,-1.1490131617,-1.2600245476,0.4720077217,-0.8848083019,-0.3584946394,-0.3885389566,-1.6692073345,1.8913199902,-0.9435986280,-1.6560325623,-0.4170581698,1.4248950481,0.7457003593,-0.2701747119,-1.4329892397,-0.9257540107,-0.5308506489,0.2141064256,-0.7413557172,-0.7860522866,-1.6483081579,-1.3483446836,-1.2292420864,-0.5480573773,-0.5060109496,-0.5933606029,-2.0655674934,1.2769864798,-0.0294818971,-0.5929264426,0.6686656475,0.5973464251,0.2934952974,-1.2685967684,1.0854260921,0.0394030698,0.6842738390,-0.7315492630,1.6883585453,1.6437082291,-0.8642318845,-0.1803095788,-0.1081145182,-1.4840042591,-1.0925523043,-0.0899927989,-0.3712283671,-0.8431726694,-0.9773939252,0.5591737628,0.4611403346,0.0734049380,0.5970427394,1.9101938009,-2.3871018887,-0.4583065808,-0.5112628341,-1.3271329403,0.7063751817,-0.6450681686,-2.1740829945,2.9771606922,-0.7224324942,-0.6503081918,1.5257606506,-0.2274675965,0.4022358656,0.4434968829,-1.0218620300,-0.1315025240,0.0179176256,-0.4155089855,0.4858019650,-0.8543961048,-0.5012856126,0.8567308187,0.2221969515,0.1999620646,0.6042551994,0.6662653685,1.0663129091,-0.4896272123,-0.2026205212,-1.1394944191,-1.2054032087,-1.1226356030,-0.4939437509,0.1943001896,0.6055281162,0.7169389725,-0.3576804101,0.6503378749,1.6525493860,0.5573248863,0.1776629537,-0.4948503077,-0.0657189265,0.1559060067,-0.1242087036,0.0716841519,-1.5930215120,0.0682995692,-1.2083141804,0.9281802773,-0.0046851207,0.9349762201,0.2173268646,1.3025127649,0.0904640332,-0.3832762539,-1.6360230446,0.4152020812,-1.4499077797,0.8201241493,0.8912186027,0.0771826804,-0.5154270530,0.9378012419,-0.4901067615,0.5525051951,1.2330327034,-0.3991430104,1.4831937551,0.7175683379,0.2221147567,0.3608321846,0.2894625068,-1.6595556736,-1.9314495325,1.8751310110,-0.4770455658,-0.5211828947,-0.6297601461,-1.1078292131,1.9312903881,0.2273961604,-0.3932147026,-1.0034306049,-2.2730729580,0.0832397044,-0.5162621140,-0.9493662715,0.7647309303,-1.4768458605,-0.7454246283,0.2828139067,-0.3133463562,0.0699866787,-0.8258736730,0.9094543457,2.2345933914,-0.2716061175,-2.0914297104,-0.8450802565,-0.1864923686,-0.2835510671,-0.1033757925,-1.5680092573,-1.2161769867,-1.6124955416,1.3700754642,0.7851352096,-0.3823657930,1.3108464479,-0.8988699317,0.5083639026,0.3493502140,-0.0577305481,1.0597113371,1.0081275702,-0.6358467937,-0.4504096806,-0.3147639036,1.0732730627,-0.8271607161,-0.6222040057,-0.7991218567,0.7039133906,0.3510959148,0.5554497242,1.4979805946,-2.1750752926,0.2891605496,1.9272480011,-0.9401828647,1.3731950521,-1.7251560688,1.3734343052,0.3356144130,0.9673383832,-1.1017390490,-1.1915374994,-1.7516787052,-1.0826570988,0.6179661155,1.1888171434,-1.0887053013,-0.2124068141,-1.1567455530,-1.0044180155,-0.9566497207,0.7797390819,-1.7934116125,-0.3947986662,-0.4438236058,0.4794886708,1.2552320957,-0.7013828158,1.3951803446,-0.0517238714,-1.4133031368,-1.8694245815,-0.5054339767,-1.2462067604,-1.2365274429,0.3690735698,1.2771483660,0.0578073971,0.3081986904,-0.2649683654,0.5571885705,-0.5460993648,0.5755186081,1.1222224236,0.0097143548,-0.1952548772,1.3565348387,0.9633554816,0.7406532764,0.4492635727,0.3314831555,0.1872891337,0.5805309415,0.3974446356,-0.5829093456,-0.0477444232,1.0294648409,1.5680623055,1.6048808098,-1.7844184637,1.3980298042,0.5945453644,-0.5468156338,1.2185471058,-1.0988667011,-0.5286205411,-0.5052637458,-0.1807851791,0.1174189076,-0.9720669985,-1.5364803076,1.3941923380,2.1483066082,0.4284505546,-0.1856944412,-0.7900459766,0.0108980974,0.9540181160,1.2205339670,0.4898815155,-0.9313154221,-0.9521727562,-0.5750778913,-0.2174461782,2.1930093765,1.5066055059,-1.0824288130,-0.2641721070,-1.2634152174,-0.1384104043,0.4317926168,-0.6106199026,-0.4305661917,-0.2218575478,-1.1112926006,0.1515053213,-0.3358800411,-0.1186274439,-0.7633775473,-0.2121664286,1.9252479076,-0.5415530801,-0.4101755917,-1.9593467712,-0.1169006303,0.1504407674,1.2334483862,1.0831296444,-0.4920203984,-1.1058235168,-1.3844621181,0.1942979842,-1.2118817568,0.9645847082,-2.0245478153,0.2150682956,-1.8037940264,2.1545493603,0.2532272041,0.3322596550,0.8775139451,0.0413930006,-0.5169070959,0.8127090335,3.4397461414,0.8755329847,0.6949456334,-1.6751369238,-0.7122853398,0.5115014315,-1.2610419989,-0.0193399414,1.1886892319,0.3200702965,-0.4151143730,-0.4470207989,-0.7033379078,2.1508812904,0.2372479588,-0.8369963765,-0.6052927971,-0.6665679216,-1.3898322582,-0.1554756016,-0.9192994833,-0.7518845797,-0.3134998679,-0.2572743595,-1.5091480017,-0.5846824646,0.3287142515,1.6392349005,-0.0196348205,0.5276853442,1.1864744425,0.7721220851,0.6423051953,-0.7868347764,-0.1904338896,-0.0519685000,0.2901331782,-0.0316568166,0.3051229119,1.2303379774,0.2227156460,-1.8869382143,-0.0082769394,0.2376345396,0.8816763163,-0.1637671590,-0.8250055313,0.9399932623,-0.2580229640,2.0155923367,-0.1516564339,0.1265739948,2.1453938484,0.8217768669,0.9791879654,-0.2263262570,-0.4864189625,0.0454811975,1.3710892200,-0.9420208931,0.9791120291,-0.4800106883,0.8337278366,-1.3876479864,0.8446266651,0.8098564148,0.5751532912,-0.9790716171,-0.0171645191,-0.5026745200,0.6194605827,-0.8599231243,-0.3917999566,-1.4034454823,0.8840796947,-1.6543312073,0.0696845874,-0.4744838774,0.8552336097,1.8941549063,-0.4313303828,-0.2739033401,0.3928846419,-1.5880547762,0.9341297150,0.3463015854,-1.3363854885,-0.0499476194,-2.9639329910,-0.5594952106,0.7434971333,0.1999131292,-2.0764930248,-0.5285277367,-0.2470802069,-2.0624265671,0.9572924376,0.3903219700,-0.6605809927,-0.6549845338,-1.0186446905,-0.0800478607,0.8186472058,0.6616176367,0.0518838763,-0.9223122597,-0.5421885848,-0.2825040221,-0.3912544847,-0.2029047906,0.6893842220,-0.8635937572,0.5363397598,0.6943371892,0.0873916373,-0.2490534633,1.2992305756,-0.7386673093,2.0405597687,0.8024853468,-1.4069356918,1.1822263002,-1.3656258583,-0.5556980968,0.1787927747,0.1019315794,-1.3714215755,0.1987746656,-0.3629374206,1.8519080877,0.6735958457,0.4217328429,-0.3506659269,-0.1316977292,1.2174890041,0.3776035905,-0.8396139741,-1.1620602608,0.3407081068,-0.3355799913,-0.7459722757,-1.8262302876,-0.8597204685,-1.4879345894,1.1369839907,1.1803423166,0.0483212918,-0.3535215557,1.7021528482,0.1325516403,-0.1556667686,-2.0734696388,0.3474398255,-1.1306002140,-0.5391064882,0.0367188156,-0.1031585932,0.5129575133,0.1265309304,0.0982659385,0.4955267012,1.3003282547,0.6503933668,0.3970629275,1.8765217066,-2.2937936783,-1.0489534140,-0.3891129792,2.0643260479,-0.1525699496,-0.3799881637,0.4029478729,0.8279522061,-0.6166064143,1.0913140774,0.1232835948,0.0043251989,-1.2592334747,1.1358189583,1.3957405090,-0.0802572221,0.3133191466,1.0224242210,0.5248175263,-0.6712270975,-0.6747437119,0.0586817972,-0.4509712160,-0.9520729184,-0.7986681461,0.9456746578,2.1470000744,1.4799757004,-1.8066306114,-0.0310747288,0.8656225801,0.5112625360,2.5125331879,0.2004410326,0.2644173801,-0.5642243028,-0.3665525317,-0.8501471877,2.1454489231,0.0146866925,-0.2753212452,-2.2508983612,0.4200601578,-0.5757294893,0.3302652538,0.6833993793,-0.1050571799,1.3361978531,-0.8743016124,-0.1878415346,0.5748300552,0.4990630448,-0.9741004705,0.2689557374,-0.8159407973,1.5243690014,1.1392233372,1.6356216669,-1.5474957228,-0.0423558354,0.0719309151,0.0674327686,-0.4663897157,-1.0062319040,1.1016836166,-0.3533191681,-0.9534746408,-0.5174071789,0.3306112587,1.3137228489,-0.4841048717,-1.5414144993,0.7894215584,0.7925677299,-0.2099342644,1.6130772829,-2.2307887077,0.6066238284,0.4182311296,-0.8662330508,-0.1302055269,0.6588820815,0.7003934383,-0.6792898178,2.0538380146,1.4943599701,-1.2634873390,0.2456917167,-1.6332542896,-1.1893531084,0.7613589168,-0.3110498488,0.1274812669,-1.4536637068,1.2830148935,0.3669683635,-0.6743721366,0.3679584563,-1.8977421522,0.8388814926,1.7857834101,0.3952881098,0.9302375913,0.1583839953,-0.4621100724,-1.2903282642,-1.6294634342,0.7264854312,-0.0749876797,-1.2859839201,-0.3973017633,0.2206417620,-0.6645338535,-0.2155216634,0.5685132742,0.1122510657,-1.3511683941,-0.8059957027,-1.0774103403,0.4130584002,-0.2617705166,-0.1687471569,-0.2825335562,-0.3444823325,-0.9686818719,-0.1723157912,0.2521053255,-2.1374604702,0.4649966657,0.5567176342,2.4056639671,0.2969538569,1.8013700247,0.0617722496,0.4764775336,-1.2795540094,0.6798602343,1.4741630554,0.7309804559,0.3686659932,0.0889440775,-1.4905848503,2.1611554623,0.4314791262,0.1953540742,1.5225317478,0.7390133142,-0.4725934565,1.1161459684,-1.9433223009,-0.1393656880,0.2824656963,3.1519126892,-0.5079812407,-0.8862577677,0.6268798709,-1.2120158672,0.7088871598,-1.6071879864,0.8341999054,0.6533966660,-0.1934999079,-0.1612865776,-0.1745747179,0.6138933301,-0.2608250678,0.0169208851,1.4444025755,0.0534766540,0.2234792262,-1.0242514610,-0.7009769678,0.4972992241,0.1313402355,0.2999706864,-0.9448517561,0.2542484105,1.3423204422,-0.7973331213,0.4570710957,-1.5696889162,0.8125736117,-1.5350893736,0.5826305151,0.2596044540,-0.8103986382,2.3475239277,0.2638120949,1.5259733200,0.5666651726,-0.9071298838,-0.8720138669,-0.9882591367,0.4064132273,1.3104044199,0.1794917881,-0.3529058397,0.8675439954,1.5312627554,-0.1812909395,0.4155770242,1.4033385515,0.1539124548,-0.1244183630,-1.5379589796,-0.8867199421,-0.6548126340,1.8252388239,0.6651643515,-0.6815838814,-0.0382827222,0.4838942289,0.7248817086,0.0481229275,-0.5961760879,1.7160128355,-0.5742226243,0.4242486656,1.3640313148,-0.0682704076,-0.1149882078,-0.7724986672,0.5856184959,-0.5331230164,0.2725982368,-2.2121868134,-0.5297753811,0.3282147050,-0.2310766876,0.9220627546,-0.4692978561,0.9146265388,1.2192900181,1.1941511631,-0.1149736866,0.9485147595,-0.4857148528,0.6253182888,0.1254618019,-1.3645582199,0.4393002987,-0.9393618107,-0.3738214076,0.3530284464,0.3340075612,-1.0520275831,0.3124981225,0.2227747589,-0.3774113357,0.3376967609,-0.1335430741,-1.4239124060,0.3777493238,-0.6754847169,1.7558667660,-0.3419993520,-0.5435870886,1.5623818636,-1.0864465237,2.7157764435,-1.1701687574,1.0629879236,0.1548271179,0.2290085405,-0.5235656500,-1.2878988981,-0.5667066574,-0.0501692370,1.7568033934,-0.1276576668,-0.8953829408,1.0946452618,-0.3542604744,-1.2604600191,-0.3953779340,0.2435953319,-0.7940179110,-0.5217481852,0.4265375137,-0.3192216158,-0.8071255088,0.5322649479,-0.3526906967,-0.0918452591,-0.6988605857,-0.2911368012,-0.6488785744,-0.6978461146,0.3133989573,-0.7867271304,0.3081840575,-0.1553696841,1.6520466805,-0.8007677197,-1.9127302170,-0.8846508265,0.7461178899,1.0180773735,0.9306701422,-0.1126613319,0.1929772198,-1.0579559803,-0.2422025204,1.8559801579,0.3720010519,1.1825789213,-0.1039613783,1.0414545536,-0.3254982829,0.9571298361,-0.4382165670,1.0003467798,1.5939487219,0.5429488420,-2.0420072079,0.5728467107,-1.8618476391,-0.2918467820,-0.0487218536,-0.9199935198,-1.0266177654,1.6822305918,1.4191178083,0.6947760582,1.0251603127,0.6672874093,1.2495917082,-0.8335829377,0.2156088799,1.1924821138,-0.4395660460,0.6522639990,-1.6726173162,-1.0532317162,2.1165602207,-1.9447240829,-0.0893126354,0.2683942318,-0.1623480618,-0.2299717814,-1.2482939959,-1.4748595953,-1.1440454721,-0.1509122998,-0.5654972196,0.9534760118,2.3310527802,1.1738048792,1.2242695093,-0.1066419408,-0.4332847297,-0.8702556491,2.0648863316,-0.9727774858,-0.3140878677,-0.5490342379,0.6551995277,0.4908427596,1.0332645178,1.1219984293,1.3135952950,-0.4913543463,0.6445788741,1.7172362804,-2.7000076771,-1.9069814682,0.5195291638,-1.2169370651,0.2950018048,0.5568491220,-0.6202567220,3.0056195259,1.6280162334,-1.7385234833,1.4424477816,0.8223228455,-0.0615691058,-0.8732482791,-0.0132957678,1.3641716242,0.8280566931,-0.6633744240,-0.0640525073,0.1176194623,-1.9407721758,-1.8422350883,-1.4371339083,0.1744921356,2.3886828423,0.1898625940,-0.5868138671,0.9374192953,1.4271277189,0.1327908039,-1.2658762932,-1.1797477007,-2.2054107189,-1.2667415142,-1.1865519285,0.3430148959,0.7459679246,-1.5639922619,0.6891250014,0.6442363858,-0.1363123357,-0.3265230358,0.8321313858,-0.0314064920,1.1229662895,1.1464596987,-0.6990435719,-1.4267598391,0.8259562850,1.7598297596,1.2947094440,-0.5276837945,-0.2367414087,0.5686634779,0.6113168597,-0.1315857321,-0.0734574869,0.0436162390,0.1786444336,0.6293717623,-1.1854665279,-1.8017184734,1.1474248171,-0.2221667469,-0.8318022490,-1.1769648790,-0.6398457885,1.1581661701,1.0694650412,-1.1927752495,-0.3782918751,-0.5945242047,1.5984972715,-0.4153506756,0.9948699474,1.1457722187,0.2799803019,0.0362116992,0.1169509590,1.1984179020,-2.1507964134,-0.2818993628,0.1193391681,1.1043921709,-0.1576315612,0.7816631794,-0.1992943287,-0.7222493291,-1.6471685171,0.5236202478,0.3679266572,-0.2783089876,0.1911206990,1.7007887363,-0.2828701138,-0.6807302237,-2.0343830585,0.0755103827,0.1925597936,1.1212855577,-0.6325791478,-1.4917219877,0.1507131606,-1.4023673534,-1.4923455715,0.2636044025,1.2325544357,0.8019176126,0.7070560455,-0.4439917505,0.3190809786,0.3905167878,1.6310776472,1.1720501184,-1.2261582613,1.4022692442,0.6078658700,0.8062526584,-2.9621202946,-0.3987344801,0.3414399922,1.7619208097,1.5134036541,0.6041021347,0.5934362411,-1.1736227274,1.3398493528,-0.5730978847,0.1356645226,0.2863060832,-0.0154768359,-1.0178600550,-2.3243145943,-0.1675287634,0.6049609184,0.2159761786,0.0666745231,-0.0865136832,1.2352000475,0.0394294672,1.0100305080,0.2578782439,0.6886412501,-2.9555711746,0.3245435357,-1.1066570282,0.0578106418,0.8995000124,-0.5578057170,0.8344925642,-0.3650110662,-1.9382914305,-0.9237997532,0.1845855862,1.0926511288,-1.4047546387,1.5311555862,-0.8047308326,-0.7788903713,0.4715638757,0.4318743646,-1.6874840260,-2.7890527248,-1.5477393866,-0.4640494883,0.4432340562,-1.0020309687,-0.5192461014,0.1724080592,1.3290741444,0.6016322374,-2.4097959995,0.5145076513,-1.1226621866,0.5319163203,-0.9135279655,-0.3886004984,0.2594231069,-0.8287024498,1.3806180954,0.2069475651,-0.8147791028,-1.8920502663,0.3105571568,-0.6040369272,-0.5843714476,-1.3048652411,-0.9555811882,1.6718477011,0.2061201781,0.2449650019,0.6344435215,1.8947550058,-1.1782568693,-1.3522021770,0.5857774019,-1.2353422642,0.5616509914,1.3375346661,1.3691686392,-1.7339766026,-0.5559787154,-0.4727867544,-0.9000478983,1.2659494877,0.4353246093,-0.0236592907,0.9436045289,-0.6716923118,1.0447865725,1.3527976274,-1.0631425381,2.4571130276,-0.1190586910,-1.3206595182,0.2101318240,-1.4100403786,0.7463139296,-1.5983033180,-0.1158415601,-0.3557868004,-0.1035592780,-2.1708722115,0.3732755780,0.8958846927,-1.5255739689,0.0184564441,0.5205706954,1.0403897762,-0.0308587700,-0.9651818871,-0.2936720550,0.0902625993,0.4703084528,-0.3178536892,0.3725000322,-0.5491930842,0.6766549349,-0.5850317478,1.9644398689,2.4331896305,1.3197941780,-0.5910408497,0.5551754832,0.7306241393,-1.0116714239,-0.7693768144,0.1477881372,0.5307281017,-0.5618506074,-0.3604781926,0.5028930902,-0.5547525883,2.3241920471,0.7301399112,-0.0238630101,-0.3112625182,-0.0513433814,0.0332490802,-0.3835499585,-0.3944619596,-1.0770056248,-0.8284639120,-2.2706835270,1.1904422045,-0.7383732200,-0.7856744528,0.2669454515,-0.4751650691,-0.3949821889,2.0143547058,0.1436878145,-1.2537568808,-1.7973768711,0.3158451319,-0.2288792729,-0.6633766294,0.3909885287,1.5668081045,-0.8202961683,-0.2624257505,0.0357421786,-2.8803546429,1.0226624012,-1.6296515465,-2.3747596741,-0.0938686728,-0.4877255559,0.4899860322,-0.5391430855,1.3695386648,0.6441672444,0.7667090893,-1.3685532808,0.6206942797,1.2448111773,-0.8042119741,-0.5956533551,0.0014253046,-0.8887516260,1.6678035259,2.0496942997,-0.1034380123,-1.0603953600,-0.4802497625,0.1270350516,2.1686303616,-1.5617771149,0.4015067816,0.1245800033,-0.3452774882,0.8196158409,-0.1079464853,0.8407748342,2.0225064754,0.1155442074,0.5847235322,0.4388331473,0.1234409586,-0.2910670638,-0.6586142182,2.0476639271,-1.8610835075,2.2706551552,-0.1068520844,-1.3966004848,0.8132696152,-0.4033440351,-0.1480889022,-1.0043388605,0.3936049640,0.1324205846,0.5566450357,-0.1675183326,0.5736991763,-0.6849721670,0.9904925227,-1.8894196749,1.5981130600,0.7703539729,-0.1610601544,0.9238270521,-0.0515182950,-0.8868377805,1.0417042971,0.6102308035,-1.8677076101,-0.3840411901,-0.1164660156,0.0456374995,-1.8475975990,0.5355637670,-0.6964988112,0.7957055569,-0.1288603097,-0.3235868216,-1.6325315237,-0.5247679353,0.7241875529,0.7006774545,0.6510369182,0.2127076685,0.3019182682,1.7634776831,1.0604306459,-0.0160322711,-2.0777280331,1.1360679865,0.4793742299,0.4298013747,-0.9959617257,-1.0719579458,0.3770346940,1.4366446733,0.7699731588,-0.9030251503,-0.8420140147,-0.2891960144,-1.3440425396,-1.4827768803,-0.8795897365,0.8493244648,0.1213431358,2.4658744335,-0.5044754148,0.8377598524,-1.3034893274,0.4661247730,0.5391213298,-1.0591400862,-0.0326998606,-2.0926170349,-0.3239274919,-0.9163483977,0.7162846327,-0.0685323477,0.4281194508,-1.1246926785,-0.1664071679,-0.6484211087,-2.1521315575,-1.0705305338,-0.8617205024,0.2989324927,1.2873754501,-0.2156222463,-1.4065039158,-0.6083480120,0.0496303663,-0.0799441859,-0.3430354595,-0.5707333684,0.2139833272,0.1441838294,-1.6315569878,-0.4222122729,0.7287571430,0.4752489328,1.4714828730,0.7369390726,-0.5534162521,0.4637760520,0.8952754736,-1.3604298830,-2.1174213886,2.2016246319,-0.2555569708,0.5857450366,0.1036471277,-0.6595315337,0.5226187706,-1.8577984571,0.8471649885,-0.5092989802,0.8184267879,1.6758291721,0.4162685573,2.5203919411,-1.0321208239,-1.4705890417,0.5317592025,0.8014125228,0.9071531296,-1.5176868439,0.4063048065,0.7387344241,1.2877237797,0.3409604430,1.8790210485,0.9491173029,0.2067094594,-0.9716271162,0.3574623168,1.0916240215,-0.2871577740,-1.7678191662,-1.4303933382,-0.2483468205,-0.1160075366,-0.1474684626,0.4271591902,0.7722973824,-0.8035597205,0.2369090319,0.5585380793,-1.6493217945,-0.9682631493,-0.2224204242,-0.3922516108,0.8767914772,0.9763500094,-0.3122895956,0.9651550651,0.6296004653,-0.1026753411,-2.0676610470,-0.7020508647,-0.1088828817,1.3923741579,0.1279061884,-1.0830278397,1.7001254559,-0.7274262905,1.5997858047,-1.7580193281,-0.1680758595,-0.7228416204,-2.0124907494,1.3119337559,0.2128693163,1.7944684029,1.8756083250,-0.3741932511,-0.2608598173,1.0983625650,2.3297736645,0.3219519854,0.4034484327,1.2642672062,0.8221021891,0.4798425138,0.0399289317,-0.2851095498,0.5849317908,0.7732047439,1.2581137419,1.8532098532,-0.6349226832,0.4174361527,0.4140231311,-0.6864744425,-0.1428144574,0.4959804416,0.7714887261,0.2804813683,-0.5753896832,-1.2983716726,-0.5563231707,-0.0272231661,-0.4999603927,-0.2157250941,-0.7681286335,-2.0508408546,-1.0966194868,1.6365146637,-0.5183550119,0.6196789742,-1.3453786373,0.5836728811,-0.4710648656,-0.5288444161,-0.2772250473,-2.3445336819,-0.6098615527,-0.3629501164,-0.1410931945,-0.4874231517,0.7105670571,-0.5983030796,0.5260640383,-1.0717720985,0.3782913387,0.7160261869,-0.8814377785,-0.2456881255,-0.6174123883,0.2108476460,-0.3944846392,-1.3366764784,0.0207539462,-0.5891013741,0.2604995966,1.6924297810,-1.1274348497,0.5514831543,0.6292963624,-0.7273381352,-0.1221026108,-1.3238046169,-1.8603323698,0.0118839173,-0.0494511090,-0.7719197273,1.1183060408,1.1271860600,-2.0702965260,1.1230894327,-0.5023233891,-0.5238962770,0.1952285916,-0.2513331473,-0.3816655576,0.6158700585,-0.7880089879,-1.8909306526,-0.7469483018,0.0433481671,0.1173256263,0.4212864637,-0.3761186600,-0.9839541912,2.0143651962,-0.3616572618,0.2649833560,-0.1013830006,-0.6988646388,0.6318305135,-1.3341007233,0.5088815093,0.2114373595,0.6875721812,0.2607598007,0.0316194594,0.3898535371,0.7478242517,-0.9930844903,-0.5001050234,0.8352737427,0.3108315766,-0.0316842087,-0.7823688984,0.1578320265,0.9126993418,-0.2352722585,0.9408181310,0.6109023094,-1.9303262234,0.5498456359,-0.6723092198,-1.4504003525,0.5355149508,0.3497037590,0.1889631450,0.1326940656,-0.6038624048,0.5095413923,-1.0285254717,0.2388528883,-0.2497551739,0.4331155121,-0.0697732419,0.6253356934,-0.1688880771,0.9176494479,-1.8235207796,-1.0847314596,-0.5756394863,0.3497035503,0.2342435122,-2.6334090233,0.5881343484,1.7326449156,0.4294790924,-1.3273426294,-2.0741112232,-1.2210987806,-0.1957486868,0.2234403342,0.4510703385,-1.2828766108,0.2367241681,-0.2933946550,-2.7297432423,-0.3880361617,1.3037126064,-0.3852106035,0.5652311444,-0.3321615160,-0.5173915625,1.3139929771,0.8717244864,-0.6854110956,-1.9135602713,0.6436522007,-0.8172343969,0.2767552435,-0.1575471610,-0.5616329312,0.4937283993,-0.3603928089,0.4888756573,0.4363217950,0.7434330583,1.0488585234,0.2988363504,0.8631799817,0.4911931753,0.5605632067,-1.2499432564,-1.8365777731,-1.5436005592,0.2294761688,-0.9752155542,-0.7505861521,0.8158047199,0.8112878799,-1.1278395653,0.1002079770,0.1714561433,-0.0902783796,0.1032009050,-0.4986415505,-0.1339252293,-1.1308209896,-1.2856656313,-0.6171336174,0.0464790165,0.8600177169,0.7068345547,-0.5624985099,0.4751739502,-0.3413746953,1.0102072954,0.0230765510,0.2426536977,-1.8445314169,0.7333210111,0.5530741811,0.2356170565,0.1776789725,-0.2307106107,-0.0811266378,0.7031916976,1.5869663954,-0.3827952743,2.0957953930,-0.0665417612,-0.5297813416,1.3718634844,-0.2815313339,0.2085584700,-0.3606263101,-0.4346255958,0.9304487705,0.6789392829,0.3673276603,0.1621620655,0.4276526272,-0.1493246108,0.8981700540,0.7842456102,-0.7916181684,0.1158784404,0.4618153572,0.3543474972,1.4618315697,-0.0058341846,-0.8900887370,-0.4046399891,0.9123374820,0.5789139867,-0.4968176186,0.1236161813,-0.4920249581,1.8629844189,3.1188952923,2.1145527363,0.4688876569,-0.9595867991,-1.0293675661,0.6830950379,1.3771774769,0.1248709261,-0.4470041692,-1.2351502180,-0.0911605358,-0.3967476189,-0.0899577588,-1.3996888399,-0.5305298567,0.7499350905,0.5719929934,-1.4103066921,-0.3479000628,-0.2184364051,0.1737931967,0.0222933087,0.5647415519,0.8052543998,-1.0294834375,0.8431189060,1.5975235701,1.1170238256,0.6672995090,-0.8730934262,-0.5672993660,-1.2327417135,-1.4132713079,0.9281820655,0.7359776497,1.0769482851,-0.1153248027,0.2036904693,-0.8216454983,-0.7670912147,1.1390515566,-1.3738186359,0.3531615138,0.4086511433,-1.4268133640,1.0887863636,-0.4670736790,1.5938810110,-0.6779985428,-1.6609425545,-1.1497362852,0.0858812928,0.3081794083,2.7873344421,0.0017950319,0.7034717202,0.0402048379,-0.0539211519,-0.8005341887,1.2653822899,1.1613918543,0.0606069304,-0.9181155562,-0.2290524691,-0.1122236475,0.0549350791,-0.8877182007,-0.3766615987,-0.5949606895,-1.6478073597,0.8510466218,0.2196233720,-0.3607971072,0.8401561379,0.0543761253,1.4959983826,-0.5632653236,-0.2425057590,0.0648398325,0.7764827609,0.7312174439,-1.1121135950,-0.6776387691,1.0912896395,0.9742969275,-1.9399904013,-2.1802775860,2.1129066944,0.8291311264,-1.1868286133,0.5817332864,-2.1304891109,1.0515449047,0.4106768072,-1.2035242319,-0.7135511637,-0.4709822536,-0.5258688331,0.7505949140,-0.8277429938,-2.7819249630,-1.1523625851,-0.8028509617,-0.5026053190,-0.1736410111,-0.3603467047,-0.2416286469,0.1397867203,-0.1340719461,2.9043488503,-1.2880799770,-0.0549019389,-0.6406171918,-1.3738036156,-0.4437952936,-0.6030911207,-1.5600773096,-0.3178840280,0.7513098717,-0.0685902163,-0.5909373164,0.0339408405,0.0979840606,-1.9291602373,-1.1436108351,-0.0531030297,1.4900053740,-0.8120594025,-0.4823431373,-0.6355569363,-0.2808527946,-0.0437979996,1.9277224541,0.9682134986,-0.3746079803,-0.2915026248,-0.4581932127,1.6945850849,0.6297083497,-1.9033675194,1.3773635626,1.8451112509,1.3157194853,-0.4916698933,-0.7966602445,-0.3494751751,0.7045466304,-0.4455379248,-0.3833731711,1.3972334862,-0.5082765222,-0.1657868773,0.0295438245,-0.1786982268,1.2381014824,0.0978887677,-0.6584629416,-0.2192865759,0.9467751980,-0.0771661103,-1.0597406626,-0.1748822480,0.7894371152,-0.4872848988,2.2833466530,-0.5168839693,-1.3883464336,1.3372455835,0.2018319666,-0.2333852649,-0.3624745011,-0.5905905366,-0.7401220202,1.0021631718,1.2818202972,0.2926157117,-1.0420081615,0.4264304936,-0.0421497524,-0.5193667412,-0.8652704954,0.8540445566,1.0223616362,-1.1298987865,1.0555826426,0.0991955176,0.4002920985,1.1874296665,-1.5832803249,0.9813435078,1.2280945778,0.5722233653,-0.9180369377,1.3107286692,-0.2247706950,-1.1927497387,-0.7917345762,-1.1626080275,0.9272098541,0.5459935069,-0.6274787188,-0.0236869771,0.4932527244,1.1298884153,0.0539514609,-0.5518273115,1.1233708858,-0.0687913820,-0.1571341753,0.1179229915,-0.3325984180,0.2601344585,-0.1911605597,-0.4110339582,1.2266099453,0.2822836637,1.2508134842,-0.3510955870,-0.1616224051,-1.6587704420,0.1728632450,-1.3107187748,0.9391930103,-0.0142953722,0.7546882629,-0.8996400237,0.9940255880,-0.2330982387,-0.4980289638,0.2528294027,2.6544928551,1.5781192780,0.4817900956,1.1860171556,0.3339211643,1.6164300442,-2.9351656437,0.2499151379,0.7760117054,0.7523182631,-0.1247479841,0.3462697268,-1.0257136822,-2.8691601753,-1.1061319113,0.7648423910,-0.9595790505,-0.0078468043,-0.2652287781,0.9949512482,0.5908301473,0.7397772074,0.2819495201,0.9627394080,0.1467755586,-0.7852812409,-0.3648975492,0.7329995036,0.9112494588,-0.6349129677,1.0441013575,1.1536734104,0.7727792263,0.1085980162,0.3048982322,0.2045264691,-0.0964837223,-1.1621612310,-0.1049908698,-1.8086529970,1.1371610165,0.3990722299,-0.2340318710,-0.8070739508,-0.5447965264,-0.9057466984,-0.7056326270,-1.3920232058,-2.2496838570,0.6314688921,-0.0317909122,0.5471078753,0.2917467952,1.1517522335,-0.2557494044,2.4834494591,0.1827259809,-1.1629668474,0.0617253222,-1.1677007675,-0.6916891932,0.1345950365,1.0560717583,0.7259826660,-0.9369471669,-1.2553867102,0.8967444301,0.0060753874,-0.1242959350,-1.3210841417,0.0899388492,0.8379094005,1.1313247681,0.3248853981,0.3055925071,-1.3190481663,-0.4589845836,-1.0276916027,-0.4143671095,-0.2306914777,-0.7529071569,-0.3986451030,-0.4679827392,1.0484802723,0.7876905203,0.3911187947,0.9792061448,-0.1854469031,-1.1137851477,-0.4035208821,-0.8948764205,-1.0624626875,0.4093474150,-2.7420592308,0.5685927272,0.1045850515,0.8899027109,-0.6605038643,-0.0338754356,0.4368726313,-0.5698662400,0.3048413694,-0.9810655117,-2.1477074623,-1.0738272667,-0.4583679438,-0.1335805207,-0.6811560988,0.6706511378,0.0815103278,-0.0946848914,-0.8044914007,-0.1711455286,-0.2423008829,0.8169430494,-0.7940458059,1.6181575060,0.2855857611,0.8950667381,-0.6162665486,0.1139321849,-0.6352536678,-0.0765659958,-0.7508867383,0.1942287982,-0.7451517582,-0.8653050661,-0.2339722216,1.0282814503,0.2243474871,0.0027308404,1.3209453821,0.2174192816,-0.2634245455,0.1675521731,1.2263836861,0.0566299632,-1.2975367308,0.3696041107,-0.9182784557,-1.3032855988,2.0671389103,-1.4618188143,0.4181285203,-0.1183236837,0.4636798799,0.7680442333,-1.1236658096,-1.3899666071,1.2378437519,-0.6141276956,0.0449728668,0.3780954778,0.5110079646,-1.5044722557,0.5645886660,-0.7422678471,0.9555368423,-0.8196920156,0.5401763320,-0.5338007212,-0.0242628828,0.1132424623,-0.6125180125,0.7859786153,-0.0349822044,0.0732879490,1.1536586285,0.1490181834,1.1301728487,0.7858697176,1.2088547945,-1.8960126638,-0.0871836841,-0.8826141357,2.8862614632,-0.8807513714,0.0494962074,-1.1702387333,-0.6589772105,-1.6818491220,0.9417175651,0.7542197108,-0.8279682398,-0.4384127259,-0.1200602949,-1.6220785379,0.1089254692,1.3359794617,2.4555397034,0.0173700582,-0.0874115005,-3.2741274834,0.1969607472,-0.2217420191,1.3908416033,-0.3902492821,-1.8578752279,-0.8916897774,-0.4912000895,0.9974804521,0.2037437856,-0.3271367252,-0.6474327445,-0.1907690018,-1.6302834749,0.6798949838,-1.6188380718,2.0891149044,0.4113075733,1.0672979355,-0.1462323815,-0.1751722842,0.3902901411,-1.0913881063,-1.5157181025,0.9157704711,0.7945489883,0.7722069025,0.4243962467,0.9691821337,1.4120765924,-1.0809820890,-0.6280459762,-0.6338055730,-0.4000754654,-0.7342044711,2.2752947807,-1.5868879557,-0.5589603782,-1.3043125868,0.3147029877,-0.2022144794,0.8512126803,-1.4063329697,-0.6932082772,1.4493491650,0.0560668260,0.9236955643,-0.5947605968,-0.2050286680,-1.2416573763,-0.6073765755,0.4851435125,0.4411651194,-0.1564729959,0.2195530385,0.3204922378,-1.1177259684,1.0289072990,1.1188204288,-0.0411395468,0.6005723476,1.5676715374,-0.1191437095,-0.5251495838,-1.5412362814,-1.2549991608,-1.7545846701,1.3483644724,-0.9670109749,0.8642841578,0.3205362856,-1.7713440657,1.1340459585,-1.0328261852,-0.1334087253,-0.3448979259,1.2247921228,0.7575573921,0.6027758718,-0.6131908894,0.7743551135,0.5759877563,-0.1214414164,-0.0009457574,0.8447682858,-1.7850353718,-0.1575969607,1.1574027538,0.1245122924,0.6179469824,-0.9759038091,0.1979667097,-0.5714919567,1.1229913235,0.3113834560,-0.4361872375,0.0621054992,-0.8684849739,1.5532866716,0.4511200488,-0.5184523463,0.4275344014,0.4822023511,-0.5793940425,-1.2044733763,-0.0556597859,0.3327965736,0.1595038027,1.5718646049,1.1590943336,-0.7317303419,-1.0252996683,0.3034447730,0.0385221504,-1.4219295979,1.6513744593,0.5207285881,-0.5225039721,-0.5949496031,-0.2466515452,-0.7081933618,1.7684363127,0.2115738690,0.1667692959,0.9263616204,0.5199217200,-0.8082281351,2.0617651939,-1.6870878935,-0.5724027157,-0.0029290456,-0.8472099304,-0.3068249524,-0.7209590673,-0.4516503513,1.2118517160,-0.5764548779,-0.6438353658,0.3038035929,-0.4023731649,0.5642825961,0.1920437813,-1.0712314844,1.2746276855,1.6927058697,0.4486570656,1.3200535774,0.0160080902,-2.3641381264,0.5951035619,-0.1099106371,-0.1813999414,0.6511411071,-1.0492880344,-0.9243508577,-0.5737870932,-0.9042535424,1.7057296038,-0.6014401317,-0.3643075228,-0.2186646163,0.1627379209,-0.8163861036,-1.1460425854,0.9978126884,1.1337602139,-3.2709360123,0.9469668865,-2.5101165771,0.6990010738,0.8786799312,-0.5839535594,-0.6743929386,-2.4371728897,-0.0503076240,0.8705804348,-0.2608596385,0.0898400098,-0.3027840257,-1.2079818249,0.0692925304,-2.0684671402,-0.0220023058,0.3078320622,-0.7879421711,-1.0444283485,1.2165591717,0.1952220052,1.4552105665,1.0593975782,-1.0149605274,1.2875981331,-0.4663090110,1.5024882555,0.9685600400,-0.2157099992,0.2602674961,-0.9132912755,0.0151141891,0.4012723863,1.0047228336,-0.9285416603,-2.0817165375,-0.2928998768,1.5027165413,-0.1005974039,-0.3758979440,2.0350098610,-0.4853464663,2.9407486916,-0.5036264062,0.2076288760,0.2921140492,-1.1655380726,-0.9878220558,1.4906018972,-0.8561943173,1.8389580250,-0.1549417078,-0.2442326397,-0.7554346919,-0.8123953938,0.4190253019,0.6878544092,-1.6918449402,-0.0898365825,1.0332804918,1.4314122200,-2.1892902851,0.0718886927,0.7476850748,1.8579891920,-0.8819519877,0.9258650541,-0.9806548357,-2.4932901859,0.6940491796,1.6708992720,0.1564088911,-0.5294389725,0.7051659226,-0.4034671485,0.8142341971,1.4990714788,-1.3586189747,-0.5893127322,0.2642396390,-1.9446407557,-0.2521522045,-1.6591632366,0.6953535676,-1.0761489868,0.5135737658,-0.8951653838,-1.4820936918,1.6783659458,-1.3350443840,1.3742983341,1.4251997471,-0.4624463916,0.2494481504,0.8023421764,-0.5172142386,1.5071295500,-0.1262708008,0.1829024106,-0.3753479421,-0.7461107969,-0.9378911257,0.8594884276,-1.3996262550,0.2003267109,1.0123081207,-0.7833893895,-0.3972645700,-0.6808474064,0.4937455356,-0.5152196884,-0.7318217754,0.2788423002,1.9877916574,1.0418436527,-0.6853435636,0.0596736781,1.0391395092,0.7398166060,-0.9924521446,1.1051650047,-1.2520617247,2.8686056137,-0.1694054306,1.9018117189,-1.0746030807,-1.2265579700,-0.8510357141,-2.1456563473,0.6359826922,0.5066269636,0.9674390554,-1.1224880219,-1.0891484022,-0.1846278459,-0.5367618203,1.8058052063,-1.1354886293,-1.9588290453,0.7469393015,0.1361483037,0.1992729604,-0.8409942389,0.1434929073,1.8949650526,-0.5321903825,-0.2382396460,0.0410348624,0.5797135830,1.5907917023,-0.2758657932,0.1504357457,-0.5587373972,-1.4018324614,1.4326224327,-0.6219562292,0.4503026307,0.4008595347,0.3934817910,1.2696865797,1.8898544312,-0.1165970489,0.6457780600,2.2075743675,-0.9847111702,-1.2228060961,-1.0882190466,1.0747212172,1.1284934282,-0.7757837176,-0.1252997965,-0.1738859862,-1.0792155266,1.7511061430,-0.1438600868,-0.9502803683,0.2619571090,-0.2889937162,0.0514364801,0.5962271690,-1.3032315969,-0.3775050342,1.3788658381,-0.5376601815,-0.3634388149,-0.5220135450,0.6863537431,-1.0816643238,0.8089571595,1.1289632320,-0.1704909503,0.0241376441,0.9559123516,-0.2972258627,1.2451685667,-0.7107396126,-0.4264647663,-0.2931824625,0.5185298920,-0.1059233323,0.6447357535,0.7338988185,0.5817427039,-0.6184529066,0.1341575831,-0.4200459421,0.8393083811,-0.3927664757,0.4707723856,-0.0673559830,0.3716157675,0.3322022855,0.0640629455,-0.7132993340,0.0691948086,-0.8344638944,-0.1031417176,-0.4747044742,-1.6690871716,0.6154571176,-0.6817176938,-2.0737211704,-0.3878850639,1.4523063898,-0.6992966533,-0.4581898749,0.1936287731,0.2572551072,1.4544843435,-1.6571730375,-1.7270624638,0.0417574421,-0.9110734463,-0.0972457156,1.5952712297,-0.8988962173,0.5708675981,2.3974201679,-1.5280815363,-0.1108923852,-0.3071365356,-0.9979051352,-0.1661987454,-1.0751403570,-2.5248780251,-0.2498296946,0.9437659383,0.9217237830,0.7171913981,-1.4578920603,1.2408026457,-2.4817552567,0.2420867234,-0.3377861381,0.0360229239,-0.5133728981,-0.3208512962,-1.3301918507,-0.6975618005,0.6498871446,0.8788000345,0.0332687683,1.0863420963,0.9952074885,1.0205569267,-1.5511695147,1.1222990751,-0.2344319969,-0.6389635801,0.2854325175,-0.7309339643,-1.9008569717,-1.2902566195,-1.4089726210,-0.0378140882,0.8407415748,-0.6611420512,-1.2427229881,-0.5391062498,-0.7145795226,-1.0734699965,1.3682132959,-1.0783115625,-2.2720541954,-0.7096360922,-0.2335556746,1.0443377495,-0.4696555734,-0.3875656724,-0.8236765265,0.2266024798,0.1619909555,-0.0944048539,1.6084132195,-0.3988568187,0.1957289577,1.5395137072,-0.1689223051,-1.5008987188,-1.3173402548,1.1269226074,0.3471261263,0.3052436709,0.3154096305,0.0921308771,0.1269512475,1.8258371353,0.1363988519,-0.9507242441,0.7849888802,0.3052140176,-0.2709810436,-0.8993048072,0.2169116437,0.1867516041,0.7598631382,-0.8012745976,-1.1976956129,0.0239624623,0.3074752390,1.2831456661,-1.3402698040,-0.4516152740,-0.0013061600,0.4203725457,0.3012847304,0.2762047648,-0.9804582596,1.1610437632,0.5745239854,0.6747921705,1.4261837006,-0.5042745471,0.5857908726,0.8970323205,0.1667999625,-0.4011804461,1.7648248672,-0.8087148070,-0.2742171586,0.4606503844,-0.0885505006,0.2718375921,-0.8004333973,0.6516600847,1.3673778772,-1.5335977077,-0.0962385684,-0.8232393861,1.6774146557,0.2271115631,-1.5541958809,0.3077866137,-1.7232172489,-2.4555950165,0.8917973042,1.7451490164,-1.7838643789,0.6180729270,1.0859361887,1.1453979015,0.9061566591,-0.3431972563,-0.0705898181,1.0991281271,-0.2261981666,0.3282406032,1.0704436302,-1.1716351509,0.9848763347,0.2437052131,1.9884727001,0.4174208343,-0.1021214947,-0.3435896039,1.3310985565,-0.5973044634,-1.0328304768,-1.0166631937,-0.2418605387,-1.0737953186,-1.5078314543,-1.9658055305,-2.4816696644,0.0847596675,0.9371824861,0.5712789297,0.1847821474,-1.6016809940,-0.5153174996,0.3281519115,-0.0960697681,-0.7360475659,-1.3864686489,1.0394927263,-0.0865700766,-1.2883691788,-2.0292968750,-2.0399634838,0.6458489895,0.4366787672,-0.2919606566,-0.8011184335,-1.1781026125,1.2439732552,0.7523661256,-0.4787828326,-0.1176917329,-0.3622176647,-0.9125710726,-0.3694320023,-1.2082426548,-0.5479109883,-0.8315254450,-0.7423962951,0.1000797302,-0.2114170194,-0.6813454032,0.8390816450,0.4109891355,-1.2436894178,0.5534462929,-1.4438923597,0.8049284816,-0.8555861712,2.1477587223,-1.3949433565,-0.2616662383,-0.9542909265,0.1196367517,1.5450251102,-2.3118369579,2.7454116344,-0.5705853701,0.0806028023,0.2696255445,1.1088483334,-0.6098455787,0.2533075511,-1.6156879663,0.4766279757,-0.9498989582,1.3911211491,0.0607453063,0.3484802246,0.2540907860,-0.9823598862,-0.6200393438,0.6513434649,0.6371821165,1.2473409176,0.4007479548,-0.6293382645,-0.3995212615,-0.3992503285,2.1516108513,0.8495406508,-1.1839305162,-1.5761988163,-0.3321847916,-0.6933479905,-0.5461527705,0.2077549547,-0.0470405109,0.9233145118,-0.3973110914,0.0615227558,-0.0844099149,-1.7535184622,2.8657610416,1.7541314363,-2.3690114021,-1.1117147207,-0.9374561906,-0.7801645994,1.7342389822,0.5957742929,1.4701598883,-0.4405146837,0.6708141565,-1.2153530121,-0.1325355917,1.0050604343,-1.2139691114,-1.3798935413,2.3798618317,-1.9887228012,0.3868185282,0.8959914446,1.6038486958,1.5363543034,-0.7630540729,-1.4995023012,-1.8495545387,-0.2919710279,-1.5776841640,1.7685606480,1.1297414303,2.3360943794,-0.1433131546,0.0687443092,0.5931475163,0.3375712037,1.2554653883,0.2474237680,-0.9403129816,-0.2061767131,-0.4198792279,0.3141739070,1.7077875137,-1.4152840376,0.1187793538,-0.7630447745,-0.6395958662,0.0102028055,0.1042164192,0.1145903766,-1.4752571583,0.2472184002,-2.1607117653,-0.4515348971,1.2877726555,0.8726791143,0.5221362114,0.0558537394,-0.7062091231,-1.0879805088,0.5266829729,0.1596421599,2.6657764912,0.8143402338,0.9257330298,2.1734650135,0.5997606516,-0.1436795443,0.3496937156,-0.9546177983,-0.1620016545,0.9732399583,-0.5467224121,-0.2262014300,0.6731067300,0.2159280777,-1.3774738312,1.1656154394,0.6550341249,1.9122684002,-0.9768811464,0.9356287122,-1.2053273916,2.4479525089,0.6917709708,-1.5790313482,-1.4568662643,1.2126783133,0.6390294433,-0.5516815782,0.8256443143,0.4482912719,-1.8841407299,-1.3875689507,-0.1513385475,0.4152318239,-0.6240538955,-0.2882059515,-0.1251111031,0.0627681017,0.2525975108,1.4493167400,-1.2855988741,-0.0614147782,1.2215783596,0.3575677872,0.3007901907,-2.1066825390,0.6250435114,-0.6612740755,-0.1341212541,0.2166793793,-0.9497941732,-1.2139436007,1.2116563320,-0.9395774007,0.3062827587,1.1016186476,0.0750297382,0.1435457021,-0.8186900616,-0.4630457759,0.5266259909,-0.0092119304,-0.5354993343,-2.7169761658,-1.1486746073,0.2088882625,-0.6807827950,-3.0617961884,-0.3313309550,-0.1758318841,1.4389998913,-1.4673558474,-0.7488585114,-0.0289274994,-0.3636911213,-1.2437512875,-1.5300729275,-1.1790323257,0.3857260942,-1.5467594862,-0.1613754779,1.4048904181,-0.5613690019,-0.7192589045,1.7300932407,-0.5238711834,1.0657387972,-0.9189323783,-0.5509738326,-0.5299234390,-1.8563530445,0.7000102401,1.3967370987,0.1085478887,0.9389107227,0.6333724856,1.0824018717,1.2884047031,-0.4879322350,1.5856468678,-1.3458198309,0.4698221385,0.9904260635,-0.7995867133,0.4108642042,0.8107822537,1.3460342884,0.7748122215,0.6732077003,-2.0124661922,-0.1145293713,-0.4353868663,1.0582432747,0.4740674198,-0.8044639230,-0.0220145155,-1.1738559008,0.1407169402,0.1516216695,0.4735494852,0.9077764750,0.9353476763,-1.6902123690,-0.0617531240,1.0522574186,1.1403518915,0.4502256215,0.3180954456,-0.8513272405,1.7308795452,-0.9569784999,-1.1495845318,0.0731476098,1.3367174864,-0.1736793220,1.0153282881,0.7569540739,-0.4068577588,-0.9060294628,-0.1295568198,1.8163871765,-1.3072237968,0.6215203404,0.6559920907,0.6238611341,0.8602724671,1.3712561131,1.7863894701,-0.1854007989,-2.0719249249,1.9330905676,-0.2852199376,-1.1075080633,-0.1679364741,1.5029848814,-0.3086349368,-1.5096340179,-1.3769066334,-1.7379231453,0.3038515449,0.5172749758,-0.6259486675,0.7043590546,0.6408320069,0.4185501933,-0.1646103710,0.3187517822,0.8196350932,-0.4609601498,0.3704506457,2.3777439594,0.5094441772,0.5521851182,-1.3909140825,1.1121610403,0.8421571851,1.1006048918,0.6569547057,-0.8560597301,-1.2483242750,-1.7567801476,-0.8713760972,0.2235589772,-0.2905384302,0.6802270412,-0.0276177991,-0.9667946696,-0.3455171287,-1.4121873379,0.2059963942,-0.6952722073,-0.7459636331,1.0301487446,-0.6903392076,-0.1190134883,0.2581081092,0.2567854524,0.7716189623,-0.2509430051,1.0092092752,-0.5644721389,-1.3445675373,1.3076673746,-0.9773423076,0.3826100528,-2.6880400181,0.4268960953,-1.1517989635,-0.8691557050,-0.6256707907,0.5513302684,-1.1145905256,0.8849994540,-0.8217748404,0.9004893899,-0.5353831649,-1.2508430481,0.7113912702,-2.6005218029,-0.7853864431,0.3203434646,2.5373580456,-2.3225741386,-0.2459121794,-1.1617994308,0.7776864767,-0.1386852562,0.8962039948,-0.3026582301,0.0292508341,-0.2019753456,-1.3439552784,1.8885324001,-0.2357038409,1.0730520487,1.1235663891,0.1953596920,-0.2643015087,-0.0000123232,0.8602338433,-1.4039980173,-0.5216125846,-0.0435859486,0.3864676356,-0.6059318781,1.2893551588,-0.7495974302,-0.7594406009,-0.2251145393,-0.8615306020,-0.3031273782,-0.7514218092,-0.0263201371,1.0012412071,-0.4263814092,0.3582890928,0.3132919073,-1.7429720163,-1.0658556223,-0.5562067628,0.6188708544,1.2195292711,0.2364767790,-0.7100563049,0.6203096509,-0.9709291458,-0.7118019462,-1.3894826174,0.1876191944,0.7731317282,1.7870222330,1.3483870029,-0.2876165211,1.2424424887,1.0495731831,0.2199662328,-0.6506385803,1.4809036255,0.1745363027,0.5330241919,0.2584872544,1.7948721647,1.2031013966,0.2966628075,1.0648564100,0.2883406579,1.7498236895,-0.3993926644,-0.5972360969,2.3710198402,-0.1631287187,0.6456073523,0.1387225240,0.9679862261,-0.4325176179,0.3984373510,-0.1760327667,0.6858507991,0.1566565484,0.7886711955,-2.6216802597,0.6207202673,0.0285687726,0.6761151552,-1.3356418610,0.7205585241,1.2382751703,-0.6817107797,-1.1695361137,1.7380303144,0.8015923500,0.2585445940,0.3077518046,-1.6452590227,0.4001936316,-0.7441572547,-1.4529861212,0.2506214380,-0.0533802733,1.1744852066,0.7447588444,-0.3415437043,-1.0891363621,0.6034783721,-0.1482316405,-0.4128837585,-0.0329800732,-0.7001284957,-1.2899012566,-0.7876139283,1.2155237198,0.0087155225,-0.0377709866,-1.3937059641,0.7941431403,0.1870978177,0.6264303327,0.8145871758,-0.7728582025,-0.2493467182,-0.5739196539,-0.5565655828,-1.1334906816,-2.2793505192,0.4410243928,0.4123649299,0.0763852969,1.4099802971,-0.7776322365,0.9002335072,-1.7927150726,0.3387904763,-1.5426032543,0.1109750047,-0.1004541144,-0.7143050432,-0.9074044228,0.1946927160,-0.6922547221,-0.5126389265,-0.2491152287,0.8359513879,-0.5823138952,0.1778424084,-0.1264958382,-1.2308934927,0.0432014875,-1.7107870579,-1.2794522047,-1.4112915993,0.2468446046,0.2457828671,-0.3186832964,0.7732830644,0.9469830394,0.5959275961,-0.2578312159,0.3627173305,-0.3071349859,-0.1745721549,1.1378543377,0.7938080430,-0.5381634235,0.4013376534,-0.9682885408,-1.1399817467,-0.9329072237,-0.5803301930,0.1786864400,0.6346725225,0.5647393465,0.0286316723,0.0992199630,-1.0894353390,1.3608300686,-0.4605360329,-0.8283517361,-1.8477090597,-0.7479529381,0.4846981764,-0.8102111220,-2.7513906956,-0.8704450727,0.0546552204,0.9808416963,-0.4524506330,-1.1581110954,-1.8916167021,1.5128071308,-0.2710370421,-0.0432773046,1.0887061357,0.8253607750,0.9289151430,-0.1334707141,-1.1068481207,1.0271012783,-0.4083566964,-0.9534019232,0.9252843857,1.2556301355,-0.3255678713,0.6176265478,-0.1261923760,0.7121532559,1.1629872322,-0.7318741083,-0.0021026048,-0.6439540982,0.7954640985,-0.5480089784,-0.9157254100,-1.1337063313,1.0404101610,-1.9267649651,1.2752271891,-0.6368082762,0.1870581359,0.9406405687,-0.3973135352,-0.0837642848,0.1083026305,-0.1242073551,-0.2883494198,0.0421624370,0.0474995077,0.6321162581,-1.5836554766,-1.1032531261,-0.5887776017,-0.1524914503,-1.6673083305,0.9382166862,-1.0333873034,0.4561629593,1.1972030401,-0.6820040345,1.9431983232,-0.2159686685,1.8049536943,0.5602540970,0.0748924091,0.5605863333,-1.7343138456,0.6010981798,0.4802421331,-0.8561789393,0.1013424918,-0.4451296926,-0.3943363428,-0.0749234781,1.0080494881,1.6752249002,0.3181442618,-0.2150738686,-0.0598962717,-0.6142386198,-0.4861352444,1.5881255865,-0.0372432843,0.1362068504,-0.6435383558,0.3061073124,-0.1080607101,0.9142783284,-0.6750063896,0.1442564428,-1.9035853148,-1.9769639969,-0.2643598616,-0.1542481184,0.6130289435,-0.9667575359,0.4809058309,-0.8523111939,-1.5576803684,-1.7187989950,0.3377987146,0.7529808879,-1.0509667397,-0.7730994225,-1.2046824694,0.4276761115,-0.8403949738,-0.4825850129,-1.4747754335,0.7216343880,0.4391319156,-0.2775903642,1.8374639750,0.8860115409,0.5017250776,0.1924185902,-0.3279211819,0.5628093481,0.9199988246,0.2608970404,-0.1163030937,0.9977791309,-0.1468842328,0.8259064555,0.8571233153,-1.1635246277,-1.2943441868,-0.6337320209,0.0078612473,0.2800707519,-0.4688892663,-1.5412379503,-1.2810702324,-0.9014613032,0.7189544439,0.6765769720,-1.1631652117,0.4434119165,0.9910751581,0.3494699001,-0.4065314829,-0.3706806600,-1.8773276806,0.2003043443,-1.7980109453,0.4200835824,-2.1893362999,-0.2583111823,-2.0468666553,-0.2437464893,1.0890002251,-0.0624531172,0.3706884086,0.4278266132,-0.1703085750,0.8178662658,1.0959708691,0.5633809566,0.4105978310,-0.4165204167,0.4329338372,-3.3593549728,-0.7902920246,-0.5976426601,0.2041165531,0.7518958449,0.9105246067,0.6583688259,0.8852194548,-1.0034178495,2.1018614769,-1.3160889149,-1.2050503492,1.3702383041,-0.9215651155,1.1412268877,-0.5294218063,-2.0968155861,0.9883624315,-0.4318448901,0.9150150418,0.6191473007,0.9672363997,-0.5683717728,-0.9324068427,2.0865449905,-0.2670659721,0.3249341547,0.2030726075,0.2451879531,-1.6215312481,-0.5928865671,1.1713583469,0.9839522839,-0.0872299895,-0.3621385992,-0.9829427600,0.8884603977,-0.1793822050,0.5179939866,1.3586529493,-0.9791272879,0.3234313130,0.5289196372,-1.9766300917,-0.0034390925,-0.7666292787,0.7933413386,0.8603540659,0.9405009151,0.6027413607,0.5473909974,0.6982603073,0.3897379637,0.3500108123,0.1734568626,-0.6509557366,-1.7006138563,1.1740543842,-0.2860489190,0.7598106861,-1.4153439999,1.2704614401,-0.1627092808,1.0294121504,0.4012169838,2.0456750393,-0.0367478020,0.6690829992,-0.3728141785,-0.2102022916,0.0779081285,-0.9818955064,0.1598586440,-0.7887569070,-1.6699723005,1.1914888620,1.7864699364,-0.5499423742,0.5733178854,-0.5447788239,-1.7513740063,-0.9034187198,0.5524613261,-0.1586202979,0.0848929808,1.8023984432,0.4640448987,0.3638080955,0.2646439970,0.1547241062,-1.4154069424,1.4598560333,0.8310509324,-0.4224171937,-0.0165275075,0.2615670860,-1.1916067600,0.2750308812,0.6544116735,-0.3800196648,-1.8660432100,0.2894992232,1.1039299965,0.1959735453,-0.0791411027,0.1106350198,0.1640786827,-0.1299720556,-1.6187663078,-1.1956890821,1.1165030003,0.6533244848,0.3864424229,0.2913912237,1.0975930691,1.4230506420,-0.0867393687,-1.6922757626,-0.2748315632,1.2141071558,0.5547963381,0.0646452904,-1.1866117716,-0.0320456326,-2.1211907864,-1.9493031502,-1.0958501101,-1.0897547007,-0.1803523153,0.3207212687,1.2608158588,-0.5926650167,1.2983776331,-1.7294532061,-0.4939606190,-0.8452877998,-0.4836902916,0.6845428348,0.1369161159,1.1284254789,1.4544321299,1.5625711679,-0.1469358951,0.1927613020,-0.7056970000,2.1935093403,-1.0594838858,-0.1013154238,0.1026509628,0.8066827059,-0.2695352435,-0.5729221702,-0.3849198520,-1.0156600475,-1.5466378927,-0.1314595789,0.3548667729,1.6491620541,-1.0673861504,-0.5086348653,0.5900128484,0.5537997484,-0.9028851390,0.3827905357,-0.4903090894,0.1471827030,0.5189530253,-0.3839559853,-0.0064701196,0.0774409026,1.1993261576,-1.8423675299,0.8041459918,0.0865443349,0.9438959360,0.4559169412,-1.9510413408,-0.0187463369,-0.5971686840,-2.1307387352,-1.0078853369,-1.1159837246,0.0679549426,0.3910646141,0.6450982094,0.2970682085,-1.4807668924,1.1750893593,0.6418598890,1.7684969902,-0.5421749949,0.0230772309,-0.5444252491,0.6334091425,-0.1794523001,0.8945975900,-0.3239262700,-1.0767819881,0.3691432476,0.6942480206,-0.0642852709,-0.8203831315,-1.1774146557,-0.2505559921,0.8347317576,-0.1928883344,-0.5916996598,-2.2447366714,1.4082713127,-0.2975973487,-1.0574928522,1.0062141418,1.1215678453,0.6743121743,1.5402876139,0.5045122504,0.4825377464,2.3591935635,-0.1581576616,1.3925447464,-0.4449972510,0.6436666846,0.6480388045,0.6492596865,-0.3070269525,0.5588863492,-0.8348108530,0.7839213610,0.6336535215,-1.4643620253,-0.8206500411,-0.7092571259,1.5029654503,0.9617568851,-1.5836352110,1.0906035900,-0.5501468778,-0.9884999990,-0.1372122318,1.2027401924,-1.1109777689,-0.5006306171,-1.2436493635,0.8456214666,0.9922400117,-0.5578774214,-1.5881406069,-0.0128620062,0.7343695164,-0.6115727425,-1.6536990404,-0.0360801816,-0.2093567550,0.7303119898,0.3931238949,0.9025912881,-0.2072690576,0.2031912059,1.1792848110,-0.8231495619,1.9168200493,0.2706981301,-0.7323203087,0.8667071462,1.5296094418,0.2382735461,1.0494682789,-0.3883500099,0.1169275641,0.9171454310,-0.1054672450,0.0179931466,-0.9391468763,-1.3003677130,-2.8754465580,-0.1241761670,-0.1267907768,-1.4475177526,-0.0179561060,-1.7879973650,0.7654473186,-1.1107738018,0.1945697963,-1.0288122892,1.6509739161,0.1266491860,0.4879723191,-0.2690182924,1.3367944956,0.5753632188,-0.0968106240,-0.9281479716,-1.2006169558,0.0849150419,0.9885011911,-0.5190308094,1.0386395454,0.1456762850,0.4775098860,-0.4643878937,0.6115694642,-1.2517410517,0.8366264105,0.4481097162,-1.3137805462,0.1005480215,-1.1128195524,-0.0262514874,1.1235595942,1.6695141792,-0.1654336303,0.7355045676,-0.8682185411,0.0562831461,-1.4327114820,0.0250446890,0.0975233465,-1.1841610670,0.7637282014,1.5198569298,-0.7049927711,0.8754818439,0.3610333502,-0.6621111035,0.2180406004,-2.0024406910,-0.8863433003,-0.1631226391,-0.3874653280,0.5548259616,1.1022121906,1.0524899960,-1.2551360130,0.9903590679,0.8982601762,0.8245859742,-0.3155473173,0.0082518505,1.3746151924,-1.0334572792,1.6923905611,0.3971545994,0.2894242704,-0.5514086485,-0.3389030099,-1.0362766981,-0.5482236147,-3.2779073715,2.1528837681,0.1756819487,0.3480467200,1.8974837065,-0.7496224046,-0.3268892765,1.3972829580,-0.3456662893,1.4522365332,-1.6095561981,-0.0210978836,1.5160992146,1.0965744257,-0.2358710319,0.6267479062,1.7261326313,-0.3205836713,-0.1390050799,-0.7758511901,2.0753962994,0.1757676750,-1.7555754185,-0.2505002618,0.2840710282,-0.5393370986,-0.4869838059,-0.1303175837,-1.1189780235,-1.0521354675,-0.0231210198,0.0181847401,0.2078745663,-0.0338686258,-0.4818850160,0.0961250514,-0.9138529897,0.9418380857,1.3300968409,1.5610092878,0.4450918734,-0.1296869665,-0.2519723773,-1.5859483480,-0.9557150602,-0.2045584917,0.0128896115,-0.2095763832,-0.4511358142,0.5498040318,1.8048099279,-0.0429422446,2.2919325829,0.0038200787,0.2721864283,0.4414996207,-1.3005160093,0.1768380255,-0.9363270402,0.4566507041,0.3796249628,0.4649937451,0.7009580731,1.0819793940,-0.5470877290,-1.1549626589,-0.2274688035,-0.4943396151,-1.7293069363,-0.1460026801,1.5145381689,0.1582663655,-1.7069764137,-1.0666083097,-2.0992667675,-0.3120955825,1.5823105574,-0.2526357174,0.6126517653,0.7511574626,1.9334533215,-0.1653770506,0.0007328019,-1.1496319771,1.0879269838,-0.4144269824,-0.1782887280,0.2705714405,-1.3183277845,-0.7594566345,2.8128893375,-1.7517324686,-0.1413636059,0.4365155399,0.8948895335,0.3178620934,-0.6415089965,-0.0946490541,-0.0807673633,-1.0004671812,-1.5345644951,-0.2357628345,-1.5820407867,1.0702680349,-1.8865656853,-0.0901094601,-0.0760608092,-0.1922454238,-0.5639578104,-0.5438117981,-0.2419601381,0.9866610169,0.3484502435,0.2144006640,-0.5236511827,0.2716521621,-1.1190679073,1.0188894272,-2.0297060013,1.5627001524,-1.2868920565,1.2256826162,0.2894935012,-0.7158158422,-1.3701560497,-1.0779329538,-0.0256836489,0.3960071802,0.4327994287,1.2228806019,-0.1757212430,-1.3786426783,-1.9703372717,-0.5863664150,-0.0080045890,0.4041854441,-1.3040728569,-2.0099992752,0.8277711868,0.7524700761,-2.8358297348,0.3762879968,-0.0772758722,-0.1378519088,0.0027876387,-1.0244839191,-0.3540144861,1.7863705158,-0.3465160429,-0.5774444342,-0.2480545044,-1.1455147266,-1.4086068869,-0.7194760442,-0.4547182322,1.7560970783,-0.0071993573,-0.6203646064,-0.1874046624,1.5937808752,0.5413727164,-1.4341344833,-1.6528888941,-0.2458195090,1.1216475964,1.8508564234,-0.0923150182,0.1672917157,-1.5417040586,1.4463324547,0.5009288788,2.8749001026,-0.7061102390,0.0816367939,-0.2914707661,-0.0285660401,0.0983645543,0.2963778079,-0.3110705614,0.8581354618,-0.7723867297,0.8028447032,0.2162812054,1.0721161366,0.0564372241,0.6005313396,-0.1831871420,-0.4489869177,-0.9456906915,-0.0371265896,0.4959995449,-1.7010400295,-0.6790872216,0.0206640214,-0.1886631548,0.1214666665,0.5371381640,-0.6261289120,-1.1847596169,-1.1002988815,1.4077138901,0.3684228063,-1.1791006327,-0.0171466414,0.1485635340,-0.1480452716,-1.2246426344,1.0717194080,0.5924861431,-1.5882186890,-1.8824286461,-0.7987720966,1.6857186556,-1.9873899221,-0.6040264964,0.9996188879,0.7584842443,-0.5855907798,1.0974962711,-1.0957789421,2.0606269836,-0.5865968466,-0.8793839812,-0.7873229384,-2.5463385582,-0.6912784576,1.2159292698,-1.9346731901,0.3178563118,-1.4861592054,-1.6317461729,-1.2586566210,0.9521486163,-0.2169671655,0.7148294449,0.7958927155,0.9093554616,-0.1415878832,1.3334403038,0.5828847289,0.8194612265,-0.1050379872,0.4659985602,0.6288198829,-1.1417542696,-1.3998000622,-0.3798598349,-0.4254036546,-0.3694149554,0.5209847093,0.8141931891,0.2401541024,2.4843487740,-0.5280447602,-0.9274998307,-0.1653894037,-0.1363191158,-0.8200877905,2.1133174896,0.8898195028,0.8735603094,-0.0686016232,-0.9245443344,-0.7718877792,0.4842652678,-0.2915898860,0.7432041168,-2.1153192520,0.9568510652,-0.2215748578,-1.8422077894,-1.2303696871,-0.1241944283,-0.7307086587,-0.6680089831,-2.3341002464,2.2076082230,-0.2407692969,0.5288803577,0.2479257435,-0.1337349117,-0.5434597731,-1.7410125732,2.0310096741,1.1825866699,-0.5783034563,0.2525941133,1.1653379202,1.0282540321,-1.0832226276,0.1212414354,-1.0867486000,0.2782225609,1.0789091587,1.1128096581,-0.7514941692,0.4164353907,-1.0873526335,0.5424474478,-0.2048412859,-0.2030930966,0.5863599181,-0.8489893079,-0.3559145629,-0.5795920491,1.5493372679,0.4460066557,0.0156894699,0.1472632438,-1.3260676861,0.7402061224,-0.6366640329,-0.3111352026,-0.1385994852,0.0820364133,1.1148211956,-0.0950735360,0.2773782015,0.9351531863,0.1982546598,1.3031610250,-1.2071324587,0.5444293618,-0.4473699927,-0.4108420610,-0.0568518825,0.4197574854,-0.6447360516,0.3293173313,2.5226984024,2.6850180626,1.9191200733,0.0876055658,-1.8289321661,-0.3188391030,0.1750170290,0.7548211813,0.6596356034,0.3386530280,1.7292153835,-0.1219225526,0.6411107183,0.7875508666,0.2660456002,-0.1457971931,0.7125737071,1.7682244778,-1.1409661770,0.6875343919,-0.9086990356,1.6409335136,0.8345350623,-0.9138651490,1.2705948353,-0.2345217317,0.4959183931,-0.6939529777,-1.3865205050,0.0969705433,-1.4421837330,-1.9025647640,-1.1793817282,-1.9167758226,-0.3548213243,-1.7836306095,0.4976726174,0.9922037125,-0.0509538837,-0.7649970651,0.8111050725,0.1019998342,0.2750899792,-0.0343734659,0.9133414030,-1.3589154482,0.5406615138,-1.3692927361,0.7702706456,-0.8848457336,-1.3492389917,1.5141055584,-0.8034302592,1.4701484442,0.7194578648,-0.3280103207,-0.1737902015,0.3155027628,0.8393989801,-0.7880792618,1.4342643023,-0.2792739272,0.7217347622,-1.1199485064,-1.6488090754,-1.1588809490,0.2449669391,0.9734916687,-0.8612310886,0.2776378691,-0.1442465335,0.2899083197,0.1926309317,0.2951425612,0.1448704749,1.0455939770,1.5262594223,-1.8003038168,0.2336754799,-0.9080817699,1.2704061270,-2.1403088570,-0.9260414243,-0.1840798110,-0.3402787745,-1.6307851076,-0.2041860521,-0.1278241426,0.5095170140,-0.6179625392,0.0498966575,-0.4110610485,-0.5157909989,-0.6018150449,-0.4285067618,1.0633392334,-0.7848201990,0.1631879508,-0.2149524540,-0.3020791411,0.6054601073,-0.0504952818,-1.0965297222,-0.7816454172,-0.2012111992,-0.6565100551,-0.1104105487,-0.2088105083,-1.9115939140,-0.2466346174,-0.2519866526,-0.4590988457,-0.0494616181,-0.6155298948,0.2704988718,-1.8088672161,0.7919092178,-0.1851701885,0.4661017060,-0.3695489466,-1.0320540667,-1.1022082567,-0.6764156222,0.4022864997,-0.2559004724,-1.2627768517,0.2470270246,-1.8833502531,-1.2920002937,-0.5564384460,-2.3891890049,-1.1999177933,0.7154252529,-0.1808043569,0.1423880011,-0.0719283819,1.1965063810,1.0246064663,0.2847369015,0.0961781964,-0.2521937788,0.7456894517,-0.0504549034,-2.1432087421,1.7391443253,-0.0206905380,0.9230058789,0.1440964341,0.3340483606,-0.5639219880,1.1893047094,0.8010678291,-0.0857279226,-1.6603605747,-1.8865714073,-1.5158432722,2.2416851521,1.3034378290,-1.2954757214,1.3497186899,0.6987150311,-0.5378327370,0.9773977399,-0.6292833686,-0.2258862704,-0.0231768172,0.2287255973,-0.0307552647,0.2602588534,-1.1946291924,-0.4701487720,-1.6524150372,1.5998086929,0.8542186022,-0.8980391622,-0.3424322009,-0.7620440722,0.5442741513,-2.6877915859,-0.6870270967,-0.1067433506,-0.5056813359,-1.1792836189,2.6766495705,-0.7369825244,-0.4661085606,-1.5385745764,-0.0672003403,0.3695683777,-0.7869833112,0.4003332257,0.3783661425,0.5367749333,-0.5993347168,-1.6679698229,1.3760275841,-0.1786604971,-0.0802356526,1.0228990316,-1.9961047173,-1.0266917944,-0.5655768514,0.8560996652,-1.4708665609,0.7181494236,-0.1992621869,-0.3848416209,-1.4284293652,0.0078248149,0.0301324613,1.0360671282,0.0559637584,0.7436648011,0.2172421217,-0.4548107982,-1.8581829071,-0.2697221041,-0.7858588696,0.2048793733,-0.1674392670,-0.5469172597,1.3462063074,1.0827282667,1.1228549480,1.0326079130,-0.9947468042,1.4552406073,-0.3257787228,-0.7388832569,-0.7861909270,0.2828303277,0.3056680560,0.2146909982,-0.2772153020,0.3958362639,-1.3230555058,-0.8603905439,-0.2827332020,-0.3374444246,1.5174309015,-1.3406960964,-0.7753478289,-0.6090564132,0.4148904383,0.1143402532,0.6358146071,-1.0189952850,-0.2470776290,1.8384991884,0.2994590998,-1.3782683611,-0.9034779072,1.0411815643,-0.8380994797,-0.0788478255,-1.2593122721,0.0735025629,-1.2232187986,0.0042018746,0.4956058562,1.0793445110,0.3841406405,-0.5286387205,-0.8840914369,0.1363095641,0.2901922762,0.5978170037,0.2368114442,-0.1575534791,-1.1024419069,1.1252269745,1.5449730158,0.3530938923,0.7228652835,0.1168344319,-0.0158468988,-0.1661573797,0.5381613970,0.3136244714,0.0325458795,-1.2324377298,1.0933052301,-0.1038841233,-0.2963826954,-0.9586788416,0.7200127840,1.4924416542,1.7752082348,-0.0550629981,-1.6644073725,-0.5077100992,0.2773285806,1.0041874647,0.4742742479,0.4997110963,0.2690739036,1.5814677477,1.5842721462,1.1153169870,-2.0206856728,-0.6906757355,0.8339030147,-2.4003989697,1.7535443306,1.4520895481,0.5084596872,-0.1650930792,0.1084622741,0.5147604346,-0.7298306823,-1.9664291143,0.6762105227,0.5794365406,0.7264261246,1.2572396994,-1.8034398556,-1.4639929533,-1.3501420021,0.3714019656,0.7283082008,0.5316600204,0.4573111832,-1.6541035175,1.7793091536,-1.6135524511,1.4555981159,0.8226402402,0.7780967951,0.1016966924,1.1728751659,-0.4354915619,-0.4268640280,0.8830320835,-0.7973753214,-0.8927229643,1.0299344063,-1.4835407734,1.2919406891,0.9132064581,0.3831681311,0.3834024370,0.9610646367,-2.4891815186,-0.8557786345,0.2069403827,-1.5988606215,-0.9463294744,1.0044388771,0.5957759619,0.3084153235,0.2008418739,-1.1726783514,0.2280961126,-2.1500291824,1.9621980190,0.0185094886,0.4452189505,0.9216417670,-1.0115605593,2.1943533421,-0.1640067250,-0.4602047801,-0.2296462357,0.9627048373,-1.0101568699,-1.4202458858,0.4832316637,0.0462592840,-1.5302428007,-0.3245599866,-1.0381706953,1.2537368536,-1.6339751482,-0.1652428210,-0.3389556408,-0.0146003719,-0.7025259137,2.6607224941,-0.6276010871,-1.0365874767,0.4586429000,-1.0496587753,-0.2999071777,1.3842225075,1.0823534727,-2.3419559002,0.8761150837,-1.8273769617,-0.2215786427,-0.3491138816,-1.9336280823,-0.0474423543,-2.4403247833,-1.2015104294,-0.2873283327,-0.8806145191,-0.8555080295,0.0481235869,-0.8469879031,-1.1857453585,-0.9132013321,-0.4592289925,0.0136311175,0.6643366218,-0.0491968133,0.2498437613,-0.8947763443,-0.0383777991,0.0546499304,-0.3900771439,-0.4424458146,1.0053803921,-1.6437406540,-0.2351907790,0.0837585628,-0.8065138459,0.3854508698,1.7295747995,1.0369310379,1.0545397997,-0.1897726953,-0.6609727740,-0.6300903559,1.0252816677,1.3816955090,0.0301201232,0.4552626610,-0.0021572479,-1.2396833897,1.6422270536,-0.9795646071,0.3572402298,-1.4496890306,1.4168978930,-0.8599024415,-0.1259931624,-0.8222708106,0.3623867333,0.1708000451,-0.3181733787,-1.9245707989,0.0009699502,-1.5193839073,0.6653414369,0.2419777066,1.6192805767,0.9414151907,-0.6941750050,0.4210597575,0.2198369801,-0.5225008726,0.5529451966,-0.1377501786,-0.0109302262,-2.6844522953,1.0686687231,-1.0907949209,-1.6353297234,0.2023297548,0.6188598275,-0.2628114522,1.0546277761,-0.1554549485,-0.4642913342,-0.0471217670,-0.0422636569,0.7548336983,0.4991921484,-2.0590631962,0.3868599534,1.4013535976,-0.9825395346,-1.3489254713,-2.1613402367,-1.1077320576,-0.0115719670,-0.1067917049,0.2030382305,1.0208203793,-0.9721820354,-0.8007465005,0.7475744486,-0.1014548764,0.1717854142,-0.8900861740,-1.1787598133,0.2836291790,0.6105752587,0.0714654922,0.2032693624,-0.0388820209,0.0560920835,0.2171260417,1.4609282017,0.3397671580,0.6166418791,1.0261284113,1.1398640871,0.0585809164,0.3839966655,0.1210960820,-1.4486052990,0.9515943527,1.1694599390,-0.4625164866,-0.5766818523,1.3717787266,0.4527533352,-1.0115367174,-0.2389606684,-2.1135818958,0.9200044870,1.2121772766,-0.0131268874,-1.0547879934,-0.4625411332,-1.1228022575,-1.9511053562,0.2523438334,0.0335213430,3.1744377613,-0.3097344339,-0.0796215609,2.3843185902,0.1680177748,1.1310538054,-0.2883731723,1.0993871689,-0.0557040833,-1.3803638220,-0.1418625414,-0.0994756371,-0.3607069254,0.1630599797,-1.8716735840,0.5809935331,-0.0887572840,-2.0139195919,-0.1107501611,-0.1171881333,0.0923445001,-1.1246478558,-0.0643767715,-0.6560503244,-0.0982639194,-1.1385906935,0.3597646356,0.7687802911,1.0907343626,0.9932415485,1.5794206858,-0.4556078315,-0.0845103040,0.1953143030,-0.4470531642,-0.3148096800,-0.5831922889,0.7251600623,-0.3664899170,1.1142308712,-0.2529630065,0.1108265817,-0.0751002133,1.6626136303,0.1881306767,1.1572419405,-1.5092159510,0.4438718259,1.0644911528,0.0690576583,-0.5484440327,-1.1120855808,0.2062901407,1.7126512527,-0.6370053887,0.4516954422,-0.6429297328,-0.4736404121,1.9491024017,-1.1057304144,-0.0583164655,0.0027293719,0.0433787964,-0.9135349393,-0.7275012732,0.1881026775,-0.6704826951,0.3486644924,0.7248296738,-0.3045236170,0.4539546967,0.5046046376,-0.4356022477,1.3943544626,0.8857178092,1.4404188395,2.6176686287,-0.5996223688,0.9162171483,-0.5749520063,0.0330234617,-1.6783542633,0.2071019560,0.2668921053,-0.2316341698,2.5724213123,0.0771679357,0.0226416700,-1.0104405880,2.0703089237,0.2559503615,0.3081150055,0.4898057878,-0.8981673717,0.1386307776,-2.3951253891,-1.0491285324,-1.4085648060,2.2214100361,-0.0909142420,-1.2632048130,-1.3839141130,-0.4299320579,1.6684657335,2.2021830082,0.5257831812,0.5739874840,1.2139933109,1.1535638571,0.1974461824,0.5228608251,-0.4663076997,-0.8205826879,1.2096979618,0.4772752225,-0.2883346677,1.1037921906,-0.4656058848,-0.0572867543,0.1929015964,-1.2480163574,-0.2613046765,0.3618875444,-1.8665893078,0.4445092082,0.3430060148,-0.3016341925,-0.6712490320,-1.9647588730,-1.4762607813,0.6007431149,-2.1796936989,1.7869907618,0.4041797519,0.7283347845,0.2149192095,0.0791092888,-0.0756125897,2.0927040577,0.6142238379,0.6972085834,-0.2808259726,-0.6297846437,-0.6537150741,-0.6563082933,0.0635813102,1.1474578381,-1.3920365572,0.8224881291,-1.2620323896,2.2960383892,-1.5349198580,-0.7157036066,1.8768742085,0.6480322480,-0.0833342448,1.9466234446,-0.9626903534,0.1901564449,0.2450418174,0.6438478827,0.5414466858,-1.6009700298,1.2528609037,-0.5713541508,-0.1698438674,-0.0962642208,0.7907935977,-0.3675736487,0.2545646727,-0.1731839627,-2.0102469921,-0.0823436901,0.4109261632,0.9124290943,-0.5108228922,-0.1702895910,0.5690754056,0.1842122078,1.1614910364,-0.7973006368,-1.7424471378,-0.1686261892,0.9480429292,1.2066537142,0.9066698551,0.6930658221,0.3705970645,0.5162458420,0.6608072519,0.4866171181,-0.4750882685,0.9606438875,-0.1774173826,-1.1164638996,0.6565501690,0.2430785298,1.3326601982,0.2276160568,-0.7638772130,-0.6724875569,-1.3945460320,0.7054424286,-0.3470198810,0.7814444304,-0.9647708535,-0.8465443850,-0.5008096695,-0.5663548112,1.0299090147,-1.2219821215,-0.9223409891,-0.0413170531,0.7327345610,-0.4150656462,-0.3697193563,1.3278313875,1.1300793886,0.8595128059,-2.1058371067,0.4117957950,1.4069085121,-0.8631376624,0.9940280318,0.0828463808,0.6927403212,-0.5555388927,-2.1278247833,-0.2419712394,0.2147070467,0.8770046234,-0.8252259493,-0.3071250319,-0.4251047075,0.4736202955,1.4847452641,0.7876216173,-2.3725543022,0.8668217063,-0.5885546207,-2.0502035618,0.1267351955,-1.3493905067,0.6182358861,0.1972312331,-0.8721260428,-1.7464439869,1.3869823217,0.1516992599,-0.0960684121,-0.5976011157,-1.6084567308,-0.1104261652,-0.3266306520,0.9532612562,2.8422458172,0.7323229313,2.3837733269,-1.4173332453,-0.2441341728,-1.0598491430,0.0659141317,0.1451799124,-1.3646274805,-1.3189326525,1.0868996382,1.1407871246,-0.7739912271,0.2757473886,1.0186146498,0.3553026319,0.0994194523,0.4954006076,1.3101518154,0.9655687809,-1.3013892174,1.6685962677,-1.6873700619,1.2311973572,-0.7829509974,-0.5541905165,0.2968224883,0.1373548359,-0.3030631542,2.0867037773,0.2923654318,1.0142391920,-0.3932260871,-0.0352618359,0.5864498615,-0.5295163393,0.6852313280,-0.1643852890,-0.3441419303,0.2067484409,0.1120802909,-1.8413914442,1.0845415592,0.7977465987,-1.6193389893,-0.3356162012,0.5115650296,0.1433262229,0.6185114980,1.3554399014,0.7320787907,0.7957426906,1.4062149525,-1.7205719948,-0.2503417730,0.5847280025,-1.2508269548,0.0660410076,1.6999821663,-1.6192164421,-0.5963765979,-2.1174936295,-0.8630749583,0.3964715302,-0.6267700791,-2.0068068504,-1.7333778143,0.3489642739,-0.3829937875,2.0327324867,1.9875861406,0.2677262127,-1.4474372864,0.3494439423,-0.8642144203,-0.5014429688,2.0740737915,-0.3882977068,-0.4317372143,-0.4059042037,1.0080896616,-0.6950193048,0.5184195042,-0.9137551188,-1.4409933090,-0.7854880691,1.8851081133,-1.7892971039,-0.8158497810,-0.3761253655,-0.2095122784,-0.7854520679,-1.0257658958,0.3675001562,-0.7535496354,1.1216030121,1.0277554989,0.1140085235,0.3061859906,-0.8787401319,1.1658949852,0.1283266991,-0.2367148250,0.6065468788,-0.2742420435,1.1453546286,-0.0845240206,-0.0997853056,-0.4292584658,-0.9366860986,0.7969179749,-0.0418951027,-1.9022171497,1.3403178453,-0.2650252581,-0.1395718455,-0.1130125746,-0.2644657791,0.8363052011,1.4173330069,-0.0139653347,0.0140969520,-1.3867497444,-0.2896922827,1.4394404888,0.0371060893,0.4729910493,-1.6448743343,1.9283530712,-0.0540869758,-1.5597012043,1.3833075762,1.4959639311,-1.2113410234,-0.8035944700,-0.0742011741,-0.0012471536,0.5972085595,-0.5049758554,-0.8977391124,-2.4309682846,-0.7694957852,-1.2447004318,1.8496736288,-0.1600045711,0.3851931393,1.6098812819,1.3233433962,-0.5853709579,-1.4895451069,-1.6313624382,-1.0789774656,0.1750666648,-0.8689029217,-1.2971252203,-0.1602051109,-0.4810235202,0.8413378000,0.4719519913,-1.4436874390,-0.4337729514,0.1231140718,-0.1029697135,-0.2789793313,-1.8605657816,0.9095398188,-0.3967422843,2.4552280903,0.7007195950,-1.0971454382,0.1571447253,-1.6993728876,1.1674585342,-0.6445943117,-0.3044758141,0.6822560430,-0.6443675160,0.2809943557,-0.8231162429,0.3418474495,-0.9646231532,-0.9446858764,-1.1312217712,0.2950759232,-2.0998363495,-0.9623675346,0.5983527899,-0.5706901550,-2.8149156570,-0.9644336700,-2.2830367088,-1.4362345934,-2.5027389526,-1.0116815567,-1.3881716728,-1.0808703899,1.1213512421,-2.9426026344,-0.8580161929,0.8869637847,1.3504574299,1.6489382982,-2.0368595123,0.4648270607,0.4125159681,1.5089983940,0.1617003679,0.2972085178,0.3435890079,1.2503364086,1.6973853111,0.5223636031,-0.6074130535,-1.4800554514,1.0115360022,1.2797082663,-0.9638424516,0.0238593630,0.7001688480,1.0566946268,-1.2123521566,-1.5452622175,-0.7135031223,-0.2995873392,1.3495112658,1.0317986012,-2.1518487930,-0.2608613670,0.4728642404,0.1432889700,-0.5136743188,0.8816134334,0.4160916507,0.9742739797,-0.5911037326,0.5096975565,0.7329760790,0.1781499535,0.4407790899,-0.7507807016,0.9301936626,-0.1136841103,0.2096375674,-0.3831914961,0.1437592804,1.9191459417,1.1668577194,-0.0390432589,0.7552515268,0.7185825706,-0.1992563307,0.2191366404,0.4416317344,-1.7806103230,-0.5829799175,-1.6506224871,-0.3800404370,0.5495235324,-2.4511246681,0.2122054845,-0.6588183641,0.2381319553,1.4138728380,0.1893429458,-0.2653420866,-1.4341834784,-0.0134915356,1.0526467562,-0.4494713843,0.3941705823,0.4576940835,-0.6274823546,-0.4867767394,-0.3145232499,0.7940014005,0.2057987899,-0.9098162651,0.3779762983,0.4768439829,0.5508027077,-0.2443206012,0.3771245480,0.9358108640,1.0886226892,0.9422910213,0.5694215894,0.1278016269,-1.6078619957,0.9920114875,2.0334231853,0.8720038533,1.2157073021,1.0835859776,0.0771418586,0.9433466792,1.1806234121,1.7133400440,0.8349636197,-0.3409295380,-1.4217534065,-0.9918186665,1.3714574575,-2.8138613701,1.5928198099,0.0514569990,-0.3350365162,0.1681042314,2.0830357075,0.1723357737,-0.7525523901,-0.6203945279,-0.4310478270,0.8727289438,-1.6561784744,-0.0651366413,-0.2049668729,-0.6367900372,-0.4473701417,-0.4513550401,1.0316622257,-0.6272398233,0.8326088786,0.6830444336,-1.3253782988,-0.5727469921,1.1235693693,0.3231909275,0.7557680011,-1.1440552473,1.2230265141,0.4768500626,0.2638700008,-0.3666841686,-0.1768282652,-1.6205668449,1.7069422007,0.8102005124,0.3011316061,1.5844978094,1.3711355925,-0.9427987337,1.6457824707,-1.0328581333,-0.2671949267,-1.4802416563,1.9849010706,-0.5626236200,0.0849812925,0.2822172940,0.7228338718,-0.7783156633,-1.2473411560,0.2193592489,1.0145031214,-0.0329789929,0.2228203714,1.1445417404,-0.7094033360,-0.7841330767,-1.0221625566,-0.5994387865,2.6038806438,-0.0352037288,-1.0069522858,0.7614061236,-0.3151522279,-0.4787478149,1.0351151228,0.9559835196,-1.6696609259,-1.5952768326,0.8844750524,-0.1393707395,-1.9339787960,0.5813475251,1.3983411789,0.7789682746,0.6822609901,1.1423463821,-2.8080708981,1.2361961603,0.1793654710,0.2740286887,1.7551431656,0.8033042550,1.5408403873,1.2425165176,-0.3679214418,-0.4071923494,1.0675301552,1.0157678127,-1.6916062832,-0.0623279475,-0.0539634116,-0.8613557220,1.2769105434,1.3883987665,-0.0332604498,-0.3398702443,-0.6552860737,1.4018083811,1.0553525686,0.1255802065,-2.8219633102,0.5146217942,1.4022740126,-0.0046099331,0.8136485219,-0.9195903540,-1.3112980127,-0.4670576155,1.4047838449,0.5764878988,0.3580507934,-1.5716396570,0.6349464655,0.7771478295,1.0435512066,-0.3213168979,-0.8127188683,-0.2205226868,-1.2179155350,-1.9275535345,1.7975726128,0.5448293686,0.7044969797,-0.3992608190,-0.5087509155,2.1094746590,-0.7843719125,-0.2291737050,-0.7270941734,-0.7784538865,0.4416177571,-0.2448096573,0.8384055495,1.4899570942,-1.1972079277,0.3306650817,-0.5491546988,0.3423768878,-0.7401416302,0.6068357825,0.3473240435,0.3175152540,-0.0742286593,0.3980647922,0.7580665946,-0.0345872045,-0.8518533111,-0.4360183477,0.6210014224,2.7143337727,0.7998730540,1.5790160894,-0.4784846306,-1.3615520000,-1.1311392784,-0.8737077713,0.4509058297,-0.9993168712,-1.9487090111,-1.0683714151,-0.6897867918,0.1995844096,0.6471304893,-0.7248669863,0.5458530784,-0.0195752960,-0.6879757643,0.0733593181,1.4149322510,0.6252916455,-1.2030237913,-0.8833094239,0.4984725118,-0.8347005248,1.1032197475,0.3863393962,0.4053649902,-0.3788195848,0.0324828625,0.3399371207,2.4221336842,0.5677464008,1.5449701548,1.0187703371,1.1051464081,-0.0787986144,0.7276761532,-1.7961450815,-0.7372569442,-0.4961169660,-1.8179187775,0.4991966486,0.4435710609,0.6528558731,0.0615191497,0.5835493803,1.1446419954,0.1317789853,0.4888918102,0.7580172420,1.5825773478,-0.4546769559,-0.4600296915,-0.2378547490,-0.0576866977,0.9007138610,-0.5783562660,-0.9360529780,0.8583307266,-1.1411458254,-0.2024374753,-1.1240649223,0.5279912353,-0.4751847982,0.6631527543,1.6318333149,0.0969477370,-0.4408459961,-0.4316680431,0.5758231282,-0.7765583992,-0.3135903776,0.1644244492,-0.9466973543,2.4841709137,-0.1300010383,0.9978062510,0.7827248573,2.0063924789,1.5243164301,-0.3948339224,0.0537491739,0.7989837527,0.2240976840,-2.4085738659,0.7977293134,0.8477253914,1.0057256222,0.8337087631,-0.4097576737,-0.4895608127,-0.6883573532,1.0892106295,-0.0431515090,-0.6405534744,0.6923466921,2.7715198994,-0.0121520748,0.4013367295,0.2561378479,-2.0776169300,1.7508301735,1.3922433853,-1.0740218163,0.5858798027,-0.8643900752,1.1791176796,0.5617208481,-0.2729750872,0.4421900213,1.9618458748,0.1082156897,-1.0202893019,0.6061573029,-0.9337441325,-0.6937928796,-0.6611673832,0.5429068208,-0.4369900823,0.4420260191,0.2651502788,0.1907901913,-0.1864834428,-0.6720966697,-0.1947799325,-0.4772402048,-0.3070857525,0.5616519451,0.4010860026,1.2816871405,-0.1345330328,-0.3634308279,0.2095918655,0.5743795633,0.5211598873,-0.3771933019,-0.5893455148,0.4899389446,-0.5980780721,-0.2535832822,0.0282106660,-0.7644257545,-0.4702759683,1.3134050369,-0.1494729519,-0.7538666725,0.0136112459,0.0777157620,-0.1643834263,-0.2342753261,0.8124720454,-0.6758717299,0.1944087893,1.5166828632,-1.3424445391,-1.7649502754,-0.8097494245,-0.0012850497,1.4531955719,-0.4727535844,-0.8327094913,1.0155029297,0.3293326497,-0.6450911760,0.3764901757,0.1045299768,-0.1445874125,-0.2936522067,0.9235664010,-0.2783232927,1.3137370348,0.0172006525,-1.3841036558,1.5561493635,-1.8639020920,1.0495033264,-0.5255575776,-0.1408940107,-1.9543750286,-0.1556380987,0.1417855322,-0.2631154954,-0.4426996112,0.5870085359,-0.5000515580,-0.5050081611,0.5463028550,-1.0903365612,1.5628612041,-2.7882788181,-1.3344719410,0.8784140348,-1.6840302944,-1.8166384697,0.0311815683,-0.4051390886,-0.0798487365,-1.5385483503,0.9227674007,-0.5343394876,0.0507932045,-1.4572614431,0.3584845960,0.3457713425,-0.5961431861,-0.6469150782,0.1584200561,0.4568893313,0.3769147992,0.4354852736,-0.5486419201,-0.2239340246,0.6698993444,-1.0490089655,0.5744723082,1.5347912312,1.5397765636,-0.1221618131,0.5470622778,-0.6007783413,-1.2336231470,0.9368577600,-1.1393072605,0.0572789684,0.5984082222,-0.1399062723,-0.9106681943,-0.8067533970,0.1479307711,0.9215002060,0.3112674356,1.3075610399,-1.7026318312,1.3720930815,1.2918262482,0.5612526536,-0.9967388511,1.2426233292,-2.2951490879,-0.0152674960,-0.9043204188,-0.5141695142,0.4446947277,1.1492751837,0.0521705337,0.6528357267,-1.2749031782,1.0507358313,-1.0188709497,1.7837384939,-0.9868627191,-0.2265499085,0.2017863989,-0.9687949419,-1.9731079340,0.1696194410,0.5233901739,1.4001473188,0.4637394249,0.7948895693,0.0983602554,-0.4224130213,-1.2093416452,1.1387294531,-0.9182177186,0.5414411426,-1.1186860800,-1.8909265995,-3.0632636547,0.4568120241,2.0387444496,0.4237249792,-1.9272114038,0.9853472114,1.3389278650,-0.1318121105,-0.8920201063,-0.2773597240,-0.4517774582,-0.7616629004,-1.1646945477,0.9879109263,-0.3608299196,0.4053466022,-0.4165501297,0.3574571311,-1.2699836493,-1.6300295591,0.5598648787,-1.4674304724,0.4131439328,-0.4219754934,2.0304031372,-1.4413354397,0.4799681306,-0.0420383178,1.6915184259,-0.5232487917,-0.8039526939,-1.0601407290,-1.5404548645,-1.0749971867,-0.2996744812,1.3575615883,1.0603859425,1.0530307293,0.1001334339,0.3675707281,1.1156344414,-0.7672547698,-2.4473090172,0.3544388413,0.7223312259,0.8279894590,-0.6757613420,-0.1550412029,-0.0579219274,0.1946964562,-0.6854659319,-1.0218989849,-1.1483523846,-1.4241236448,0.5684677362,-1.2633242607,-0.5404099822,-0.6181235313,0.8761564493,0.2720177472,0.6743654013,-1.3917897940,-1.3827804327,0.0717442855,0.1175106540,2.1652770042,-1.1354564428,-0.6457980275,0.0317389071,-0.7400742173,0.9619795680,-0.0593260564,-0.6544432044,-0.1337867081,-1.2988967896,-0.3555890620,-0.6045878530,0.2226153016,0.9822761416,1.1462154388,0.2895379364,-0.4104592204,-1.1960166693,-0.1224415079,1.1972869635,0.6265248656,0.3610025048,-1.7972739935,1.3773232698,-0.6522130370,-0.7375943065,-0.4990181625,-0.3867849708,2.1639332771,0.1491455138,-1.3630967140,1.8294426203,-0.8609524369,1.4427920580,-0.4151449502,0.1516723335,0.2960756719,0.3308898211,0.4983998239,0.1312209517,-1.0052082539,-0.8411090374,-0.6049742699,-0.0483746789,1.0027732849,1.0322577953,0.2257779986,2.2114481926,0.2201044112,-1.3947371244,-1.0045163631,0.5725672245,-0.4024380744,-0.1606439054,0.5383403301,-0.9939112067,0.4404547215,0.4778611660,-0.7972090840,1.2639709711,-0.0904689953,0.0119346408,-0.2128958404,0.1294909567,0.6935775876,-0.8069289327,0.0381242223,0.0640896633,-0.8519039750,-1.1961863041,-1.6041916609,0.3708937764,0.4002925456,0.6246642470,-0.3795958757,-0.2372878045,0.5787289739,-0.6773391366,0.1989562958,-0.0726481527,0.6693786979,0.5971757770,-0.1213830337,-1.7431809902,1.4139084816,-0.3425191939,0.2435627282,-0.0741600394,-0.9220610261,1.0343546867,-0.8678551316,-0.3198132217,-0.6899349689,0.4179919362,1.2124581337,0.0375941433,2.2486476898,-1.0220209360,0.6465313435,0.4278988540,0.9193848372,0.4222237170,-0.0933749005,-1.0670326948,0.7879496217,-0.9432157278,-0.9096699357,-0.7628371716,-1.6910816431,-0.1087954193,1.1553153992,-0.2835746109,0.9786539078,-0.1439840198,-0.5912532210,-0.7626441717,0.2139990479,0.8680096269,-2.1934850216,0.7954643965,1.2878558636,0.3072288930,0.9573891759,0.5701214671,1.2529802322,-0.0815569162,0.8128978610,-0.9811226130,0.2701521218,0.9489287138,-1.9259961843,0.2753039300,-1.3883477449,-0.5270357132,-0.2019829303,-1.1113721132,0.1056974530,0.4965963960,-0.1771866232,2.4821672440,0.8626716137,-0.1475741863,-1.8463534117,-0.1793068349,-0.8907314539,-0.4722703099,-1.5586285591,0.1077410355,-1.9330302477,0.7558904290,0.2947430611,-0.6818034053,0.8157358766,-1.2121231556,0.3502351940,-2.2251851559,-1.0909916162,-0.0607460439,-0.7485980392,0.5062255263,0.2378816903,1.2893656492,-0.6041642427,-0.6925551295,-1.1607208252,-0.2876462042,1.0311911106,-0.0499792546,-1.3574689627,0.8249968290,-0.8970457315,-0.1135150492,0.2143322527,1.3763307333,0.8509597182,1.7496386766,0.6001273394,1.4015005827,0.3860958517,0.5434395671,-0.4725933969,-0.2877027690,-0.6129447818,-1.4196848869,0.3062418699,-0.1553191394,-0.9508764744,-0.0760941654,-0.8062614202,-0.8954066038,0.0484242700,-1.0906312466,-0.1732535660,-0.3397390246,0.3176231682,-1.5844293833,1.2997056246,-0.6607711315,0.1271229833,0.0425397344,-0.4639439285,-0.9103606939,0.3158217371,-0.3238605857,1.6766819954,0.9372931123,0.2473313659,-0.8097632527,0.0890621245,-0.8043243289,-0.3928592503,-0.3789885342,-0.7877340317,-0.7610335946,-0.4013801515,-0.0189523175,2.3299083710,0.8038778305,-1.9815123081,-0.7011249065,-0.9096357226,0.9332553148,-0.2004610598,1.7981244326,-0.0330081321,-0.2495200932,0.8726334572,-0.6514548063,-0.5128629804,1.6354423761,0.3905225694,-0.8390223980,0.8316834569,-0.0595287457,2.0173168182,-0.8562936187,0.6865690351,1.3743298054,0.3907682300,-0.2398041636,-0.1251194626,-0.6344032288,2.2980499268,-0.4630606771,0.2461500913,1.3341190815,-0.3485464156,1.2087879181,0.1016988084,-2.1994295120,0.1064224765,-1.8571059704,1.5093195438,0.1532788873,-0.5053347945,0.3831263781,-0.1220782623,1.1170195341,1.0353970528,-0.7229524255,-0.3387831151,1.6032934189,1.7609171867,-1.2161747217,0.5180673003,-0.6836446524,-1.6527055502,-0.8767384887,1.0462769270,0.2828881741,0.4827982187,0.2307805121,0.7823326588,0.9507107735,1.4595805407,0.6798090935,-0.8676077724,0.3908489645,1.0838125944,0.6227587461,0.0919146538,0.6267312169,0.7369835973,-0.4665488899,1.5379717350,-1.0313144922,1.0398963690,0.8687855005,0.2055855989,-1.7716643810,0.2428264916,0.1570801437,-0.8153182268,-0.2022062540,0.5724145174,0.5329394341,1.6678758860,0.5379707813,-1.2548235655,1.5401520729,-0.2270848900,-1.1637035608,0.7588675022,0.6385750175,0.2570756972,1.0582165718,0.3091140985,1.6547634602,-0.2367554605,1.2576045990,0.0599439889,0.0446613617,-1.8018302917,-0.2758919001,0.6777992249,-0.1838328093,-0.9692851901,0.9890301824,-0.2224184275,0.5610032678,0.7233167887,0.0912953764,-1.4654313326,-0.5956678987,-1.0447202921,-2.0769333839,0.9551025629,1.1798607111,-0.5978704691,1.7572724819,-0.1310936958,-0.2408575267,-1.5555117130,1.5630480051,0.4313979149,0.6554265618,0.0821268037,-2.1948366165,1.2969125509,0.8677711487,0.3639212549,-0.5787127018,1.5105884075,1.0996694565,-0.5503646731,-0.4026169181,-0.0874640346,-0.4514757693,1.4189465046,-0.4797129035,0.3733192980,0.2657961547,-0.8370972872,0.3150520921,-0.9210009575,0.1015821472,-0.5309605002,0.0664992332,-2.0074801445,2.2297945023,0.0819370598,0.1479992270,0.1758866161,0.8668915033,-1.0901758671,-1.8159155846,0.5403104424,-0.1107598692,1.0183703899,1.9810978174,-0.4993706942,-1.5936735868,-2.0820102692,0.8839993477,1.2424896955,-0.3754470050,-0.4873703122,-1.3391138315,-2.8575394154,0.8945623040,-0.0517046452,1.1353893280,1.0172095299,0.1628982425,-0.3798680305,-0.8960040212,-0.2011121809,-0.0567418709,0.2119727731,0.6210333109,-0.1791775525,0.8862378597,0.8935353756,0.8979471326,-0.8102669120,0.0424867161,-0.6294496655,-1.0798614025,-0.2119414806,0.7185308933,0.8276394010,-1.5393027067,0.7995367050,0.6526834369,0.3812628984,1.6862120628,-0.5823438168,0.5357362032,-1.8718117476,1.8158414364,0.0115653146,1.0090109110,-0.0481402576,-0.0621399991,0.5543729663,-0.0510954261,-0.4064195454,-0.5600697398,-0.1420308799,1.2426292896,0.2519005239,-0.0725310817,-0.8719974160,-0.6856629848,0.0003807768,-0.1563270241,-0.4662569165,-0.0164176356,-0.3071641624,-0.4057198167,1.3780448437,-0.9845128059,1.2129591703,-0.2401970625,1.7031100988,1.1683377028,-0.9992445111,-0.8173805475,0.2220273167,-0.3547341526,0.4088989198,0.3500408828,-0.4819968045,0.3505795598,-0.8347722888,-0.6508687139,-1.4876539707,-0.2163732499,-0.2417284250,0.9192639589,-0.0174811445,-0.6125581861,-1.7423535585,-0.2791055739,0.3562209904,0.2949730754,1.1177265644,-0.5972783566,-1.7783836126,-1.1208477020,-0.2938118279,-0.4967626035,1.0432761908,-1.0701702833,1.0008829832,2.2375409603,-0.0449116081,-1.3642407656,1.4596179724,1.1632910967,-0.5697431564,-1.7598483562,0.0133777484,-0.4007295072,0.7930163145,0.9166504145,-0.4451917112,-0.3771822751,0.5663695931,0.6020166278,0.6256309748,0.3488479257,1.4128754139,-1.1541855335,1.3467293978,0.0763891712,-2.2180795670,-0.8790378571,0.7706360221,-1.0272171497,0.3823670149,-0.4660917819,-0.5811817646,-0.9728909731,-0.3998017013,1.3444324732,-0.2047507763,1.6922044754,0.7689399719,0.7740138173,-0.9281789660,-0.4968115091,-0.7952126861,-0.0446061157,0.2427589148,1.3154057264,-0.9638298750,-2.4491629601,1.8243825436,0.6550926566,1.3024812937,1.2062610388,1.5797829628,1.6227316856,-1.1122174263,-1.0028078556,-0.3198828399,0.6408913136,0.5411697030,-0.3132085502,0.0905704945,0.4082139432,1.0586953163,0.0793558359,0.2908940911,-0.4207540154,-1.0434504747,0.8331912756,-1.2780961990,-1.4766488075,-1.6978293657,-0.0705931783,0.2020439953,-0.0928261653,0.6194707155,0.0804834291,0.3376404047,3.4837553501,0.2669399977,-1.4626413584,0.8958411813,1.1550073624,1.0528649092,0.7435577512,-1.5690900087,-0.4255738258,0.9140344858,1.2361495495,-1.2471395731,0.7626679540,-0.1928639710,-1.2733954191,0.7811949253,-0.4019659162,-0.4094708264,0.0163625069,1.4163241386,0.2105273604,-0.4444972277,-0.5089505911,0.4650335014,-0.2184793502,-0.4025595784,1.0784583092,1.0624145269,0.0769374445,0.0645173937,0.8455424905,0.9994160533,0.9331492186,-0.7005475163,-0.2368602306,-1.2239063978,0.2130108923,-0.5972399712,1.8470237255,-0.6240378618,0.5833202600,-0.5017367601,-3.0102710724,-1.3837611675,0.1786506176,-0.3187453449,-0.5781022906,0.0315280780,-0.4391703606,-0.2296233028,2.3488371372,0.3843484819,-0.5347214937,0.1268615276,0.8902928829,3.8520202637,0.7244234681,1.1944116354,-0.6678529978,1.0415666103,-0.8658940792,0.9077596664,-0.3378550708,0.9775423408,-0.0754776895,0.6063098907,0.6713734269,0.0194545370,-0.3463670015,2.1391818523,-0.4366911352,1.7306786776,-0.1830381155,0.2859286666,-1.4076973200,-1.0983570814,0.2282403558,-1.1998163462,0.4056214094,0.9875051379,-2.2728385925,-1.3111302853,-1.8743584156,-1.2082616091,-1.5854942799,0.4378720522,1.4147380590,0.3267107308,-0.5729110837,1.2912527323,-0.6939992309,-0.0833639130,-1.6856313944,1.0955225229,0.5547582507,-0.9104179144,0.4392534792,1.9463402033,-1.1000357866,-0.7706585526,1.2468438148,-0.4902793765,0.5345413089,-0.9500870705,0.1477532536,1.2505365610,0.0899634138,0.3677219152,0.8650166392,-0.2937146723,-0.1290635020,0.3401563466,-0.3108875155,-0.7258995771,1.3177022934,-0.9953907728,-0.0467900336,1.0885127783,0.1454632878,-1.2228176594,-0.7175816894,-0.7583139539,1.9346177578,-0.7771400809,-1.0648733377,0.1046056002,-1.6488226652,-1.0661364794,2.0642158985,-1.8892747164,0.1650791317,1.0846154690,-0.1468636394,-1.1351752281,-1.2594205141,0.4703114927,-0.3027814627,0.2559323013,-1.8508899212,-0.9306232929,0.9595783949,0.1062435508,0.8443471789,0.2098277062,-0.8347812891,-0.7564993501,1.0179579258,1.0825403929,1.3440455198,0.1753898412,0.4277119637,0.2193833888,1.4308446646,0.9249140620,-1.7949538231,0.0283557717,1.7641273737,-0.7250720263,0.6685691476,1.1260482073,-0.3413906991,-0.4857299626,-0.0957151726,-0.4632709324,-0.7183370590,-0.0102504687,1.3925209045,-1.1265658140,0.8746911287,-0.9904094934,-0.4190586209,-0.2849096358,0.6538196802,0.7931527495,-0.3543632627,-0.8418226242,0.6238386035,-0.7723533511,1.4631421566,0.1103246212,-0.8867618442,1.6526117325,1.2548710108,0.2880513072,-0.4933074713,-0.5117329955,0.6032633185,-1.3497583866,-0.5111608505,0.6675429940,1.8336050510,0.3924017251,0.5415292382,1.6077739000,-1.6158584356,0.5651822686,-2.9483938217,-0.1493530571,1.1534879208,0.2299067229,0.2548667490,0.3125708103,-0.1421936601,0.0962879658,1.4915516376,-1.4980111122,0.2542267740,-0.3468973637,0.4250290394,1.9612369537,-1.1135908365,-1.4034284353,-1.3214765787,1.4184826612,2.2413375378,0.5875048041,0.0437724106,0.7939956188,-0.6215597987,-0.5815342665,-0.0857137591,1.4495682716,-3.0346090794,-0.5904287100,-1.1807073355,-0.8728227615,0.1840069443,0.5226079226,-0.7583761215,1.5459980965,1.1350790262,1.2372657061,0.2346145958,0.9069361687,-0.1464601457,0.8803369403,1.6036959887,-0.0359401405,-0.5794182420,-0.8478991985,0.4720226228,-0.0823028833,-1.2614284754,0.4648005366,1.1294105053,1.5758064985,-1.3074091673,0.4784797132,-0.0898916945,-0.4759197831,1.2124656439,-0.2539686859,0.0967589170,0.0534103699,0.2857500017,-1.3306634426,0.4249919951,-1.1950973272,1.0747199059,-0.2170769274,0.0450050756,0.1741701663,-0.2596285939,-0.7920688391,-0.4063050151,0.9191468358,1.7260661125,1.4962009192,-0.2412421852,0.3035558164,1.5768409967,2.0336244106,-1.6690231562,-1.3676552773,-1.2393416166,-0.5456511378,0.8899183273,-0.1883179098,1.1415015459,0.3300242722,0.6155939698,0.7084887028,1.5292983055,-0.3306114674,-0.0788572133,-0.4493339062,-0.2701256275,0.5901252031,1.5623044968,0.3643705249,-1.4534931183,0.5249486566,-1.2966890335,1.1808009148,-0.0224379860,0.3152523935,-0.2782708406,0.8091103435,-0.4187511802,-0.4770900905,-0.3365066946,0.5623541474,-2.0182147026,-2.1983170509,1.1045867205,1.2624795437,-0.0276180673,0.1718224883,0.1991921812,-0.2634349763,-0.0887101442,-0.8009012341,0.3470789790,-1.4324259758,1.4175089598,-1.6810934544,-1.0911394358,0.5939617157,-1.1652457714,0.7605130076,-0.6547212005,0.3845574260,0.7944753766,0.6379547119,-1.1523764133,0.1821886748,-0.5537084341,1.5448677540,0.8237330317,-0.5419313908,-0.7200653553,0.6935390830,1.1008996964,0.9097881913,-0.9642880559,-0.4383548498,0.8910411000,-0.3298941553,0.9730165005,1.2895667553,1.1915460825,-0.6843030453,-0.9302793145,-0.2390873879,0.1579615325,0.2212390304,-0.6818502545,-1.7127672434,1.1771396399,1.1114701033,-0.3492176831,-0.0472809970,0.7482308745,-0.0730901062,-0.5841656327,0.4504536092,-1.1025894880,0.0581932291,0.6327283978,0.1792763323,-0.8223001957,-0.2284287810,-1.2400608063,0.4701416492,-1.1249814034,-0.4419503808,0.4520464242,0.4384505749,0.4458945990,-0.4454752505,0.6874499321,-1.9018042088,-0.8928960562,1.0825363398,0.2178558558,-1.2581878901,-2.8035640717,1.6928415298,0.0167334545,-0.7488485575,-0.6693356633,-1.2117948532,0.1265929341,0.5291302800,0.3899676800,0.4554530382,0.4301682711,0.4348187447,1.0085790157,-1.7501940727,1.1373521090,1.1931743622,2.0794131756,-0.2773678005,0.8379659057,0.6542209983,0.2838761508,0.5350176692,1.3807713985,1.7053838968,0.8826751113,-0.3271561265,-0.3581827283,-1.2562394142,-0.8812279105,-1.0632889271,-0.1390643716,-0.7417252660,0.5785334706,-0.5842409730,-2.0249407291,0.0031048066,1.6786370277,-0.1028214321,1.4051040411,-1.2307188511,0.0745233521,-1.3036009073,-0.4741173089,0.7923251390,-1.6625601053,0.5009847879,-0.4260414243,0.4607705772,-1.4588941336,-0.8828140497,-0.2869668007,-2.0858445168,-0.6617110372,0.9500411749,-0.4903324246,-0.1242794171,-0.6876080036,0.9306303859,-0.2304113060,1.0719676018,-2.1756176949,0.5917387009,1.5272648335,-1.1067727804,0.3803062737,-2.1274337769,0.5029523373,-0.2445702404,-0.0006700782,0.9635633230,-0.2261878550,-1.6574515104,2.6968736649,-1.1250771284,1.0807653666,0.0584954619,-1.4129952192,0.8620643020,0.8713108301,1.6652963161,-1.6135631800,-0.1984029859,-0.2902413011,-0.6188423038,0.7531723976,0.1087239310,-1.6153539419,0.4767957926,-0.4382492602,-1.0736072063,1.2319749594,-1.2424856424,-1.4469009638,0.5112141371,-0.2780409157,-0.9318844080,0.4025871754,-0.7289595604,0.4709553123,0.1000782549,1.2074514627,-0.2669787109,-0.3595815599,-2.1342899799,-0.4210056067,0.4573920667,0.9248502851,-1.2482802868,0.6569746733,0.4175840020,0.0368951969,-0.0607408360,-1.8906854391,-0.0682709813,-0.5059621334,0.2151026875,1.8872957230,-1.1071970463,0.1205267534,-1.0122386217,-0.6658754945,1.1404993534,-0.5657894015,-0.8201801777,0.6875778437,2.0678489208,-0.6186278462,1.0876693726,1.6158015728,-0.1567347497,-1.2611894608,1.4985532761,0.4219383597,-0.1459040344,-0.6523817182,0.7554470301,0.2956840992,1.1193044186,1.6107659340,-1.5123630762,-0.4555642009,0.7889720201,0.8956725001,-1.3317306042,0.6401042938,0.2166453004,0.8215140700,0.0503329076,-0.0965074822,-0.1113443226,-0.2042803764,-0.6873565316,0.5317636728,1.1151205301,1.5243155956,-1.2777767181,1.7654581070,0.0725174472,1.0041288137,-1.6742922068,-0.1915116161,-0.6583703160,0.0271707252,-0.7335672975,0.1892032921,0.2953191400,0.0094617000,-0.1575515270,0.3323207200,-1.2621731758,0.1978865266,1.3326668739,-0.6343193650,0.9134386778,0.0729104951,-0.1353257895,-2.0858786106,1.0808997154,-0.3004504144,-0.2755873203,-0.7367097139,0.3021540642,0.2700982988,0.4530409575,-0.7007525563,-0.8959960938,-1.1999323368,0.4935321510,-0.5960142612,-0.9639679790,-1.2851704359,0.4559888542,-2.5519254208,1.4413543940,-1.0547283888,-0.4198956788,0.2472599745,1.0853878260,-0.5223800540,1.9698237181,0.5240100026,0.7831386328,0.4234170914,-0.1564492285,0.1359184831,-0.1162117422,-0.4195275009,-1.1759042740,0.3552658260,-1.9931274652,-1.4269702435,0.6328967810,0.4862891734,0.0348587781,-0.0004265035,0.1926831156,0.8282247782,2.8950171471,0.4765744507,-1.0976687670,-0.7158638239,0.7778658867,-0.2204324454,0.0522998534,2.3419752121,-0.2337766886,1.5526149273,-0.2743647099,-1.2966957092,-0.5145607591,-0.6441264153,-0.9436242580,-0.5575792789,-0.2886804938,-0.5300575495,-0.7995063663,0.4609216154,0.0503422990,-0.1202928945,1.2408776283,-0.5033631325,-0.0448194630,0.2108783871,0.0507609658,1.4534044266,-0.9200549722,0.0032031226,0.6261848807,0.2485037446,-0.7718658447,0.2863176465,0.0988020748,-0.7075133920,2.0979690552,0.0536587685,-0.4469783306,-0.6916967630,-1.4713886976,-0.6406098008,-0.9751100540,-0.7251353860,0.7354019284,-0.0255986620,2.1644103527,0.1879548430,0.9535272121,1.1498577595,-0.9122163057,-0.8776962757,-1.5234766006,-0.9056487083,0.4926247299,-0.3897213340,0.4013664424,-0.1390452832,0.0777551010,0.8162872195,-0.3259987235,0.1420471519,0.1295469105,-0.5685203075,-0.0366480462,-0.7493227720,-0.0521788187,1.3544013500,0.9088275433,0.9768580198,0.5170670748,1.2871779203,-0.1010567024,-0.0856445506,2.6273643970,-1.6656155586,0.5624790788,-0.5161991119,-2.1735665798,-0.3417043090,1.9319416285,-0.9397265315,-1.7080259323,-0.7614494562,-1.2761473656,0.4220181406,0.9958624244,1.0256894827,-0.1235863641,1.8414309025,0.0351293795,-1.0325827599,-0.4244602025,0.1708007455,0.5898537636,0.2644017041,0.1715549082,-2.2165124416,1.0189716816,-0.5055457950,-0.5834990144,-1.2355498075,0.8014555573,0.3301530182,-0.8047369719,0.2689402997,-0.8028509617,0.8982989192,1.5976356268,-0.2384607941,0.5498903394,-0.3153492212,0.0371826515,-0.2799673378,-0.2572603822,0.8187432289,0.8705870509,0.7939828634,1.4407110214,0.0046773427,-1.0408636332,-0.4254775345,-1.0005455017,0.1042390913,1.2375731468,-0.0690675676,-1.8301037550,-0.2057546228,-1.1653020382,-0.9878067374,-0.1361900568,1.1316952705,1.0342150927,-0.6592921615,0.2408573180,0.2436449975,-1.2514510155,-0.5721936226,-0.0520525165,-0.4139078557,1.8763142824,1.1753531694,0.5226545930,2.1683094501,0.6907484531,2.2160840034,1.1130344868,0.4593990743,0.7844545245,0.6997361779,-3.1261579990,1.5720311403,1.7266691923,0.3456651866,0.4389714897,-1.6385536194,0.4049912691,0.2712102234,0.1878780574,1.3390874863,-0.0299388077,-1.3081719875,0.0632864684,1.2408345938,-0.9132910371,0.5147520900,1.1721259356,0.0147358524,-0.3792796135,0.8482502699,0.9654959440,-1.4460035563,0.4597578347,0.1704647690,-1.1115249395,-0.7208780646,-0.3793327212,1.2741154432,-1.6364229918,1.5149157047,0.0631237701,-1.2959022522,0.4598662853,0.0281794146,-0.7976759076,0.3872869909,-0.8583239913,0.1689493805,1.5861971378,-0.8286434412,-0.9093782902,0.0804205164,0.0313321017,-1.8652266264,-0.3101404309,1.6558412313,0.4230325520,-1.1583219767,0.9033274055,-0.4117244184,-1.0604335070,-0.5190912485,-0.5632234216,0.1435869932,-1.5192936659,0.0426138528,1.4924136400,1.2707833052,1.9864619970,0.5108605623,1.2856057882,0.8407601118,-2.0035340786,0.8936482668,-0.3260267377,0.8181855083,1.0708587170,-1.8654093742,-0.4303693771,0.3521697521,0.1649127901,0.2585572302,-0.7880253196,0.2695698440,-1.3194481134,-0.6205232739,-0.0030871087,-1.2652636766,0.5406863093,0.4429259598,0.4298315346,-1.2147737741,-0.1896856129,-0.4850975573,-0.3081047237,2.3780131340,1.2015973330,0.2664550841,0.7288299203,0.7034993768,0.0048138006,-0.3591594398,-0.7174685001,1.7085003853,-1.3032776117,1.1584476233,1.0995483398,0.5414423347,0.9730444551,-1.0727057457,-0.5748537183,-1.3290205002,0.7744051814,1.4045319557,-0.2159052491,1.7948094606,1.6460920572,1.3411537409,-0.4496222734,-0.5609518290,-0.0992444083,-0.0853365064,1.2166137695,-0.0213507153,-1.4752011299,2.1615161896,1.2456383705,0.2582988143,0.2717613876,-0.1682876796,-1.4384615421,-1.0607285500,-0.1907466799,1.6710277796,1.2433642149,-0.7574949861,-0.0647511855,-2.9306302071,1.5923978090,0.0510240272,0.3966749310,1.0205726624,1.1665779352,1.6779688597,-2.3571422100,-0.5891851187,0.3185988665,1.8541604280,-0.0838108212,-0.4632383883,-0.1345472634,0.8540049195,0.7585686445,-1.0865671635,-0.8296186924,0.4694327712,0.3256563544,1.4290058613,0.7655954361,1.2069232464,-0.1459943205,0.8065757751,-0.3280249536,-0.0742716119,-0.4548668861,-0.0853952095,-1.1056786776,0.9523906708,1.7686954737,-3.2922542095,-1.5821778774,-1.3896070719,-1.2549228668,0.3908016682,0.6844573021,1.4914137125,-0.4642134607,1.1045403481,-0.4899351001,-0.9562233686,-0.2807927430,0.0053708674,1.1767382622,0.1583883911,0.2319228053,-0.8078649044,-0.1561281085,0.3615372777,0.4036455154,0.9082906246,-0.0023141834,-0.0452877991,-1.5662910938,-0.1033781320,0.5418262482,-0.9377847910,1.0195208788,-1.1293481588,0.0335480943,-0.4405394495,-2.2315773964,-0.4775855541,2.0507366657,-1.3063079119,1.6552379131,-1.1819411516,-0.0324509963,-1.4311203957,0.8767514229,-0.1345372945,0.8536100984,1.5587157011,-0.2368998080,0.1880593002,0.2717109025,0.6395956874,-1.2362473011,-0.0319846682,-0.8295824528,-0.2055542320,1.5347025394,0.7827878594,1.2703878880,2.7300498486,-0.2844167948,1.1753647327,0.4245087504,-0.5369454026,1.2073285580,0.0930977017,-0.5196133256,1.0421657562,0.1690351069,-0.4875896275,0.6770972610,0.0044279699,0.3105448484,-1.2954131365,1.3982955217,1.7429810762,3.6478598118,-0.7394582629,-1.1202218533,-0.4658226073,-0.9041526914,1.1250499487,-0.1801972389,0.1294232458,0.7745076418,0.5126174688,1.4980577230,-1.0465172529,-0.4988512099,0.5188845992,1.1863158941,-1.1096326113,0.5208597779,1.2098367214,1.0017185211,0.6673674583,0.5668189526,-0.0521996841,-0.8716872931,0.1681198180,-1.2476809025,1.9259685278,-0.5453615189,-0.8922271729,1.9886724949,-0.3135860860,0.7334384918,0.5198380351,-0.4526397884,-0.9506946802,-0.2661958933,-2.5570335388,-0.0557328612,1.1625821590,-0.4434820712,1.1122316122,-0.0545103103,0.2586460412,-0.6618434787,1.4436861277,-1.3688731194,0.7621035576,-0.2985791862,-1.0211650133,-0.1357472390,1.0373653173,0.3776987195,-0.4136635363,-1.6953018904,-0.1204522103,-1.1567699909,-0.7138453722,-0.3276610970,-0.6435422897,-0.7366944551,-0.1425680071,1.7642153502,2.8425951004,0.0610087626,-0.4151884615,-0.1082942411,0.0857538283,-0.8597403169,-0.9152332544,0.1713453978,0.9422041178,-1.0082613230,-0.7561030388,-0.3161784708,-0.1782092303,0.0957031474,-2.5437932014,-0.6769134402,-1.4552763700,-0.1227465048,0.4310432673,-0.9728448391,0.3342837393,1.1829782724,-0.0065461015,0.5665283799,0.1695615500,-0.0044607525,0.0285913981,-0.8989881277,1.1593964100,-1.4732522964,-1.4600700140,1.7094210386,0.0207724255,2.0963575840,-1.2747777700,-0.6057670712,-0.8993343115,0.2116632611,-0.1160674915,-1.2055330276,0.7836779952,0.5415595770,1.0465161800,-1.6241914034,-0.8055034280,0.5579012632,0.8232837319,1.6447900534,-1.2311408520,0.2137642205,-0.9106723666,-1.9084692001,-0.2605872154,0.2076506913,-0.9598652124,-0.9803130627,1.2351433039,-0.9859101772,-0.3903642595,-1.0345238447,-0.3124050200,0.7462546229,-0.5244422555,-2.4146971703,-0.1631130129,0.5022974014,0.9429028630,-0.8194223046,0.0069113285,-0.2531582713,0.2928455770,-0.6136545539,-0.3634734154,0.8031544089,0.0733277798,0.5689120293,0.9162364006,-1.4241131544,0.6944862008,0.1126557738,0.2768815458,0.0754733682,0.4862255752,0.3217608333,0.3620449007,-1.7405321598,1.1516690254,0.9695023298,1.0705699921,1.1136047840,0.7925577760,-1.7781143188,0.8929021358,2.0690708160,0.5849423409,-2.1492705345,0.5832387209,-1.0383287668,-0.4568869174,3.1900093555,-0.7241430283,1.1837641001,-0.1022715420,1.8591374159,-0.3411387801,0.3150487542,0.0275884047,-1.3723717928,0.0300342757,0.4547230303,1.8566195965,0.2995341718,0.6253018379,0.4939307272,-0.0265730321,-0.3234100342,0.3595822155,0.6894904375,-0.6438739300,-0.9093788266,1.2942886353,1.2176066637,-0.9077116847,0.1113884673,1.0686095953,0.1878102571,-0.5059827566,-1.6027270555,0.0214889795,-1.3829032183,-1.7231186628,-0.3605511785,0.5595287085,-0.4247933030,-0.3993293941,0.0908166617,0.1786594391,0.7535029650,0.6296449304,-1.5375419855,-0.2698430121,-0.7669034004,1.2986503839,-0.5635685921,0.1221668199,-0.3815145195,-0.4466152489,-1.1692444086,1.6965802908,0.3721182048,1.7709367275,-1.6176935434,0.2316016853,-0.8005692959,0.7475548983,-0.8234938383,0.7365947962,0.7701295614,-0.9460060596,-0.4202794731,0.3530687392,-1.8267436028,0.2953773141,-0.6090833545,-1.0919172764,-1.6189069748,-0.0322289020,0.4412971735,-0.4813476503,-0.6603649259,-0.8035909534,-0.8457508683,0.2187346816,-0.9387763739,0.0936134532,-0.0921785682,2.2268385887,-0.4825090468,1.5371801853,1.9999849796,-1.3969053030,-0.0445936732,-1.4784121513,-1.8323581219,0.3004155457,-0.3889199495,-1.3225893974,1.8505661488,0.0649111494,1.6666123867,1.4079970121,0.2198562622,0.4401271045,-1.1840212345,-1.4271931648,-0.7065832615,-1.2413952351,-1.3692640066,-0.0096538514,-0.6498388648,-0.2452564836,-0.9085732102,-0.1391163319,-0.8336672187,0.5473741293,0.8369570374,-1.1456743479,0.0624656156,1.8641681671,1.6749701500,-0.5735353827,-1.4077433348,-1.9448838234,0.5631722808,-0.6609920859,0.2506439686,-1.1130369902,-1.0673143864,-0.3806003332,1.4953833818,0.6200692058,-0.6979174018,-3.6335635185,-0.8773848414,1.7083442211,-0.7415100336,-1.0148513317,1.2024078369,0.7076079249,-1.2916729450,1.0737441778,1.0685819387,-0.5960540175,1.1803132296,-0.0333345570,0.0980365053,-0.4779715836,-0.8072968125,-0.0824001506,-1.9273227453,0.7178004980,-1.0592756271,-0.9261478186,0.1021981537,-0.2795476615,-0.9590332508,1.0488163233,-0.4690090716,1.6720734835,0.6879519224,-0.0157241132,0.5268683434,-0.5965974927,1.6848707199,-0.8259072304,0.7594338655,1.2602584362,-0.6720221639,-0.0584140681,1.0932010412,-0.5520174503,-0.6187421083,-0.8900236487,-0.8719530106,1.2347486019,-1.3540980816,-1.2299486399,0.6464612484,-0.0974468589,-0.3091480434,0.5283569694,1.0791188478,0.2561168075,1.4158717394,1.7008452415,-1.4289003611,1.3387390375,1.1170512438,0.5130531192,1.0400758982,-0.6153922081,-0.1668823063,0.7639955878,1.0470120907,-0.6455356479,0.7287098169,-0.5354412794,1.2531111240,-0.4258435369,0.3980273902,-1.6516693830,0.5757321715,1.1960839033,-0.4860200882,0.3503985405,-0.0763770789,0.0167850349,0.8753983378,0.5204891562,0.8198471665,-1.4274868965,-0.5994745493,1.2439334393,0.8900793195,-0.3447135091,1.6019076109,0.4453103244,0.3134413362,0.2098031342,0.8220742941,2.1609876156,0.4291853309,1.9126983881,-1.1369169950,0.1236273199,-0.0741692111,0.1741669476,0.1106243953,0.4574111104,-0.7266279459,-1.6765234470,0.8124452233,0.4615250528,0.2150113583,1.4487680197,0.6443644762,-1.3313271999,0.6483889818,0.0551732592,0.0946426168,-0.5147324800,1.3383497000,-0.6886813045,-1.3321741819,1.4576708078,0.3417120576,0.1916114688,-0.0513381623,1.6174348593,0.7993416786,0.1274137199,-0.8448427320,1.2690343857,-0.5826838613,0.0557822697,-0.7457270026,0.0534833819,-0.5319348574,0.5449818373,0.0617729798,0.1800281107,-2.3204801083,1.0729317665,0.3631948233,-0.4377925098,0.1569657326,0.5283293128,-0.5462140441,1.2347840071,0.5054156780,1.6532857418,-0.6099229455,-0.6667820215,-0.5278279781,-0.4208771884,0.4319642186,-0.1246592775,-1.0448354483,0.0785995051,2.6429173946,0.0422035158,0.2535940409,-0.9304233193,1.0765348673,0.3263046741,-0.6096877456,0.6794693470,1.5073816776,0.3643631041,-0.7833818197,-0.8042606115,-1.1636455059,2.1159131527,0.6903854609,0.1691145897,1.3395061493,-0.3655520380,1.3998910189,-0.4119296074,0.1565577090,-0.9600688219,0.1500866711,-0.4632772505,-2.9622406960,-1.1724597216,0.6507877707,-0.5097853541,0.3659832180,0.4810813665,-0.0095656291,0.4939456284,0.1545771658,2.0188348293,-0.3500584066,1.2580102682,-0.3938673437,1.1757705212,0.5819926858,-0.1100534201,-0.4838815629,-1.1713180542,1.0384311676,-0.4346498549,-0.6087762117,-0.5977138281,1.2044967413,0.5018853545,0.3364687562,-0.2894819081,1.2561717033,-0.1431188136,-0.0513663627,0.1945189983,-0.1383751035,-1.2002265453,-1.5160598755,-0.3494048119,-1.1222406626,-0.1564642340,0.1808167845,-0.3393794000,0.5907009840,-0.9833743572,0.9756684303,-1.3281390667,0.2585115135,-0.3627780676,0.8321187496,-1.8786463737,0.4968658686,0.0689388067,-0.0079110470,0.3008804023,-0.7525809407,-0.3469925225,-1.5925863981,-0.7068521976,-1.3115445375,-0.2572110593,0.1371918172,-0.6321007609,-0.4874186814,-0.0709755793,0.0640492663,0.3276489973,0.3932814300,-0.2793305516,0.4494642913,1.7821687460,-0.9390084147,1.5413779020,0.0079562068,0.1199712157,0.1818806082,-1.7790522575,0.0833725855,0.3141438663,0.2376887649,0.3440466821,0.7322938442,-0.6423465610,-0.9430661798,-1.0507161617,-1.1356643438,-0.9131414294,-0.1980059296,-1.0524215698,2.0543701649,-0.5051992536,-0.2961077988,-0.1411919743,0.2223303318,-0.5895858407,-0.5231840014,0.6206701398,0.8080673814,-1.3365075588,0.3356038332,-1.6119444370,0.8270612359,-2.3478622437,-0.1573795974,-0.8355489969,-0.1855920851,0.2819520831,0.1627157480,-0.4957902730,-0.2017339319,0.0587787591,-0.8486970067,-2.2888104916,-0.9550905228,0.0425533839,-0.8235985041,0.2843135595,1.3483312130,1.6403613091,-0.1185661405,0.2167840004,-0.4161785841,-1.7830762863,-0.5561192036,-0.0708618909,-1.0473921299,1.0332918167,0.1671882719,1.5324164629,-0.6358706355,-0.2964316905,-1.5015150309,-2.2901973724,-0.2640973926,-1.3396550417,0.7526706457,-1.1424431801,0.2186951339,-0.4216327071,-0.4880354106,0.5038363338,1.6515885592,-1.1511272192,-0.6911903024,-0.8230931759,-0.2474271357,-0.3428781927,2.3004641533,-1.2634423971,1.2604916096,-0.4096618295,-0.2799764574,0.7918033600,-0.6636201143,-0.0015233173,1.6005517244,1.3663774729,-1.7475005388,1.0692484379,0.2425226271,0.4911504090,0.6091113687,1.1200417280,0.6362381577,0.1359951049,0.1392289251,-1.5782338381,0.9691632986,-2.3665611744,1.0742968321,0.5516464114,-0.5444959402,0.8318801522,-0.7501646280,1.2486605644,0.3589930236,-0.3600519598,-0.7901878357,1.5135924816,-0.2313470095,-0.7407914996,0.8029611111,0.2708649933,-1.6062647104,0.5937306881,-0.3154849410,0.1361830235,-1.0001647472,-0.0763395801,0.0344249457,0.3669148684,0.5293010473,0.0763758123,-0.2572541237,0.5138447285,-0.1288889498,0.6439459920,0.5794592500,-0.7824993134,2.2121942043,-0.3496154547,0.4119117856,-0.8420560360,0.4544038773,0.0109467581,0.0010534312,-0.2950676680,0.1750898808,-1.2973902225,-0.0623139627,0.2126978934,0.6877377033,0.3352945447,1.7457261086,-1.0843807459,0.7854700685,0.0600954890,-0.0855508447,0.7329173684,0.2756085098,-1.0048882961,-0.7781894207,0.8054320216,0.0727083459,2.3196663857,0.3006044030,-0.2822029293,0.4725848138,-1.5897241831,0.0941874236,-0.9508988261,1.4989129305,-0.3068813980,0.2385282964,0.4217751622,0.7946755886,0.7492550611,0.5127679706,-2.2465128899,-0.1663811803,0.5605801344,-1.8675581217,0.4418747425,-1.0016011000,0.7059368491,-0.0510153249,-0.2325836271,1.5391352177,0.9156982899,-0.8702345490,-0.5608828664,0.8970757127,0.3895307481,0.6618192792,1.2001011372,-0.1240015626,0.4234113991,-0.7949218750,-1.7483150959,0.1998164356,-1.5106359720,-1.1773667336,-0.6218593717,0.3076383173,0.5031841993,1.5083596706,-0.7131744623,0.2623642981,-0.0309111103,-0.1339277327,-0.1106061265,-0.1045916006,1.0869770050,1.6638536453,0.6696953177,-0.2361247987,0.9860504866,0.4088005424,-1.0221886635,0.0886315182,-0.4157384634,0.1207668409,0.4294110239,0.1377238184,1.2307782173,-0.1232055947,-0.8324245811,-0.3747373223,2.4342443943,-1.1951713562,-1.1546982527,-0.9615500569,1.2484122515,-0.3975964487,0.8206714392,-0.8452029824,-0.2450099438,-1.6266416311,1.1472618580,1.0578019619,0.1282176673,1.1876020432,2.5764918327,-0.0823692530,1.1622513533,1.2577518225,0.7237423658,0.4700427651,-0.7886118889,-0.4397766888,-0.8123567104,3.0631451607,0.5537109971,-0.0900671929,-2.6399536133,-0.1701684147,-0.6035872102,-0.6521043777,1.1507827044,1.2750959396,0.2453898042,0.3872298300,-0.8278653026,0.9271902442,1.6431338787,-0.4256422222,0.5522973537,0.1817890704,0.4363834858,1.0876022577,-0.4799385071,0.9566588998,1.3544300795,-0.1174629778,-1.2165155411,0.8368718028,-0.8922112584,-1.5480458736,0.0400244184,0.3244729638,0.0817489848,-0.9257849455,-0.7675449848,-0.7365167141,1.6259465218,0.6298605800,-1.4840712547,-1.4950245619,0.1297564805,-1.0976947546,-1.1410716772,-0.9285092950,1.0353862047,2.7001140118,0.9804233909,-0.3006408811,0.1535374373,1.3037381172,-2.0147192478,-0.1158716157,-0.6375645399,-0.1695705652,0.6505923867,0.6162424684,-0.8195439577,1.2143636942,1.0763442516,-1.8476772308,0.3398576081,-0.2474824041,-0.9045435190,-1.1834901571,1.6120089293,0.4015118480,0.3753013313,-1.0195120573,0.3743047416,1.5763468742,0.2818703055,-0.0415413007,1.1435390711,1.0312833786,0.5930593014,0.4299762845,-0.7077791095,-2.0817489624,-0.8573213220,0.8970362544,-1.1242753267,2.1089203358,-0.1735206395,0.7554202676,-0.6492454410,-1.1986908913,0.3451207876,1.0742040873,0.2218725234,1.5225878954,0.1871998757,1.1086134911,0.1162764803,-0.2187245935,0.3414756060,0.1085516512,-0.7073196769,1.2486360073,-0.9194564819,-0.8338657618,-1.0484052896,-0.1623076200,-1.9373788834,0.5603187084,0.5427429080,1.5060900450,0.0874666423,-2.4002182484,1.3652335405,0.5865104795,-0.3230989277,-1.3929996490,1.1904447079,0.3914655149,-0.6465815902,2.4218268394,-0.6179955602,0.0971411094,0.0927094892,1.1953548193,0.6744587421,-0.6237062216,-1.4494575262,0.5976842046,-0.3370549381,0.0000538884,-0.9751046300,-1.4531168938,-1.2553899288,-0.5801687837,-0.0705595762,-0.6704121232,1.3072650433,1.5074343681,-0.1624190360,-1.0658824444,-0.6713882089,-1.2154396772,-1.0532267094,1.3715112209,-1.1906760931,0.8829891682,0.1461430639,0.3025677800,-1.0018360615,0.7597610950,0.4627263546,-0.9727967381,-1.8330810070,0.6842470765,-0.0457889512,0.0743883923,0.1160207540,0.4871888459,-1.3810641766,0.7513743639,-1.6535325050,0.2805307209,-0.6730520725,-0.6538075805,-1.0937461853,0.8920948505,-0.5652847886,-0.2217692137,-0.9390385151,-0.2413975745,-0.0277992953,0.4737479687,-0.0896343440,0.4736139476,1.7478946447,-1.3817198277,-0.5763424635,-0.7620200515,-1.2223913670,0.0114631774,-1.4424446821,0.1032015532,-0.4778788388,0.6391831040,-0.3346210420,0.7208385468,0.6453597546,-0.6174742579,1.3672366142,0.4193812609,0.2484990656,-1.2752428055,-0.4317915738,1.3278837204,0.4312328100,-1.5758079290,-0.8080574274,-0.0961645246,0.2024365366,-0.2257446200,-1.4323306084,-1.1698937416,-0.1322149932,-0.2605111599,0.1435681283,-0.3786023855,0.9958216548,-0.0179624446,0.3827536106,-0.9316131473,-0.9425467849,-0.8002999425,0.9446987510,-1.1967359781,0.5227084756,0.3323342502,0.1467415690,0.3252617717,-0.2421308011,-0.3801048696,1.5932736397,0.8452807665,-0.3431094885,1.2928600311,0.0758657232,-0.8354057074,0.6789767146,-0.0734707043,0.4803312421,1.3606332541,0.8671076894,0.9994120598,-1.1754306555,1.4058384895,-0.9871997833,1.0385127068,-0.4434279203,0.8501870036,-0.6956353188,-0.6379371881,0.8698224425,1.4933327436,-0.9885481000,-0.6133674383,-2.2802202702,0.9688157439,-0.2850471735,0.0442743227,-0.3362223208,1.1406686306,0.5380051732,0.6882110834,1.2516015768,-1.3449673653,1.0782428980,1.6350847483,2.2968215942,-0.7110384703,1.6386603117,-0.9126443267,-0.3877492547,-0.1043018326,-0.0090003163,0.6059634686,-1.0972509384,1.7331362963,1.3298485279,-0.6946768165,0.8652173877,-0.8342711329,0.3025682271,-0.8910675645,0.6248769760,-1.6545723677,-0.9224897623,1.7043474913,-2.1606175900,-0.7243913412,-2.4045393467,1.6853871346,0.8936536908,1.0344368219,0.1707872897,-2.0846495628,1.3154208660,0.2850298584,-0.3303071558,0.9252412319,-0.5945811272,0.2951497138,-0.4839909971,-0.2808298469,-1.2129616737,-0.2385444343,-0.9515303373,1.8470141888,0.4530581832,-1.3355108500,-0.1361455619,0.8572332859,1.6664037704,-1.7786149979,1.1624349356,0.4030810893,1.3191045523,1.9514727592,0.1954828501,-1.1131478548,1.8760913610,-0.4106545448,0.9871078134,-0.3514513075,-1.1491596699,-1.0029109716,-0.4375024438,-1.7376359701,-0.1112331674,0.3778693378,-1.2642121315,-0.9193267226,-0.4944682419,-0.7798122764,-0.4271022081,1.0683219433,0.1328333765,0.7467706800,1.3215091228,-1.1968958378,-1.1443666220,0.6172171831,-0.0051761493,-0.2794991434,0.3744995892,-0.3662587702,0.4500087798,1.5653235912,-0.2852126658,-2.0067307949,1.3534057140,1.2254853249,-0.3875033557,-0.4426376224,-0.9592947960,0.6190398335,-0.3124010861,-0.5994002223,1.5445845127,-0.0053672073,0.9292419553,-1.4328645468,-0.9411212206,-2.3532216549,0.0921249315,-0.3608577251,1.1292972565,0.7657831311,2.4220712185,0.1606874019,-1.4992787838,0.2326702625,1.0695062876,1.6562827826,-2.1346623898,0.8291113377,1.9936954975,-0.0670990944,0.4760950208,0.6264278293,0.3247528374,0.6127083302,1.3447989225,2.1764240265,-1.0073144436,-1.2598137856,-0.3319583833,-0.9408110976,2.1974444389,1.1426124573,-1.1883490086,-0.6941516399,-0.8429222703,-0.4689262211,0.1896196008,2.4364590645,1.4495763779,0.9550628066,-1.3749413490,1.0702964067,-0.7423433065,-1.6166442633,0.3353677094,0.8143854737,-2.1510691643,-1.4398878813,0.4295713007,-0.6825832129,1.4495866299,0.0767971873,0.8710640669,-0.9394101501,1.2120714188,-0.1885681599,-0.6676308513,0.5666903853,-0.5110077858,0.8325109482,-0.9449007511,0.3893716335,0.0370208956,0.3440933228,0.0902620628,0.1622183025,1.9678138494,1.0434346199,-1.4853209257,-2.2796955109,-1.0654275417,-0.7173523307,-0.8523059487,1.6222326756,-0.6020047069,-0.1935931742,-1.0439174175,-0.8322221637,-1.7539211512,0.6675662994,1.5207853317,-0.7924110889,0.3303536475,-1.4821587801,-0.2574607432,-0.7888179421,-0.2782670259,1.1471936703,-1.1040791273,-1.1629147530,1.2700695992,-0.4843160808,-0.5253778696,0.8253301978,1.6041414738,0.3806031942,0.7163059115,1.0897123814,-0.9337714911,-2.2876377106,-1.0739610195,-0.3832927644,-0.1494626701,2.3470876217,-0.1703584939,0.3322209418,-0.8650518060,0.5197970271,-0.8209413290,-0.6846882701,0.6192402244,2.3423302174,1.3338751793,0.1373818070,0.7219576836,0.9726226330,-0.1536917388,0.9913292527,0.2540746629,0.1626318097,-0.3465512991,0.4595924914,1.2181417942,-1.0088903904,1.2518771887,-0.1303908825,-0.9561480284,1.8820406199,1.2069588900,0.3529352248,-0.8306714892,-1.4193843603,0.1155640781,-0.5738064051,0.6434262991,0.4984490573,-0.1118573099,0.7238074541,-0.5256049037,0.6390516162,-1.1183315516,-0.0976157486,-0.1260827035,-0.5548433065,1.7662122250,-0.2686588168,1.0087834597,-1.4268404245,1.1659404039,-0.9612586498,-0.3340024650,1.5359613895,0.1235429570,2.9805519581,1.0028824806,-1.0232834816,-1.4397224188,1.3039492369,-0.7188103199,0.5913882256,-0.9829553962,0.2619152367,0.0651016235,0.1422494650,0.0322833695,0.7933985591,0.3038003445,0.6963039041,-0.4510253370,-0.0787391812,1.2138137817,2.1563596725,1.1974829435,-1.3827234507,-0.5387663841,0.3749031723,0.3817621768,0.5126075745,0.7817907333,2.8445768356,-0.7148271799,0.1042771265,0.0861898214,-0.2078901976,0.1141170561,-0.3227742314,0.0504558496,-0.5519875884,-0.2047938854,-1.8481737375,1.2803936005,1.1041901112,-0.1439001858,-0.2400241643,-1.0030885935,1.1916694641,1.3330214024,0.0078061824,0.0833170936,-1.3876982927,-1.3872941732,0.8939967155,0.2273259908,1.3578511477,-0.1441743076,-0.7695208192,-2.5133471489,0.1119075045,-0.4572762549,1.0314948559,0.9591494799,0.3220496476,0.1193715185,-0.0206195451,0.6939818263,0.0383000039,1.0197111368,-1.3477758169,-1.8404810429,0.8510962725,0.8117278218,0.0951100439,0.6611233950,-0.7656561732,-0.9922797680,-0.9179639220,-0.3361779451,-0.5715629458,0.5896957517,0.1407307684,0.7236926556,0.7947764397,0.4836243689,-1.3869879246,-0.1118176356,0.2992152870,-0.4100322425,-0.7881225944,-1.8818029165,0.9634225965,-0.0309839323,0.8337911963,-1.9074735641,0.7431362867,0.4745285511,-1.1356483698,1.0912343264,1.2545942068,-1.4796434641,-0.4746834636,0.3405517042,1.1815891266,-0.8854237795,0.0957699418,-0.2880924642,-0.0463199876,-1.3265682459,-0.1858589202,1.2988238335,0.6762433648,-0.5991950631,0.3327338696,-0.5831449628,1.4332697392,1.9494212866,-0.7886651754,0.5240651965,0.1793854237,0.6290607452,0.4811582565,-1.4723852873,-0.0745147914,0.5363513231,-0.8404342532,-0.4846772850,-0.9714007378,-0.2141099870,-0.2834431529,0.1940501779,-0.5316337943,0.9639087915,1.6239774227,-1.3215353489,0.9414067268,0.7094277143,0.8003622890,-0.8477427363,0.9165262580,1.6716412306,1.2298988104,1.4809641838,-0.4254212081,-0.4077859819,0.3305155039,1.0415029526,-1.1496744156,0.1712993681,1.4701676369,0.4293683171,0.1795604676,0.0516814254,0.2441919297,-0.3086892366,1.1564617157,-1.2884559631,-0.7572581172,0.6286239624,0.5937031507,-1.1899099350,0.3375867009,-0.4291598201,0.5017452836,-0.8552255034,-0.8198128343,1.4330694675,-0.2992851734,-0.4924618900,-0.1553115398,-1.0980613232,-0.1505965292,-1.7112737894,0.5384337306,0.9439564347,-0.4357626140,0.5460928082,-0.8451873064,-1.3298441172,-0.5760731101,0.2821652591,0.7656444311,-0.0708712041,-0.7376880646,0.7219296694,-0.7072268724,-0.2859232426,0.6533915401,-0.8342830539,1.1105629206,1.6008365154,-0.6448624730,2.8344218731,0.6748697162,-0.3423575163,-1.4236814976,-1.1950898170,-0.5678108931,0.7195250988,0.5357619524,0.4457416534,-0.4799274206,-0.1652086526,0.1340560615,0.6014035344,-1.3409739733,-0.5987482071,0.0769548640,-0.3581912220,1.1240202188,-0.2238033116,-1.4019105434,1.6488307714,-0.2175414711,1.9418623447,-2.5849790573,-2.4083001614,0.3356060684,-2.0707116127,0.9840598702,-1.2379816771,1.0672813654,0.2889554203,-0.0074083852,0.4752945006,0.1841205209,1.2986530066,-0.0591709130,0.1742814332,-0.0644250885,-1.1764115095,-1.7949217558,0.7206540704,0.4559027553,0.3954004347,-0.7530158162,-1.8091009855,-0.3017390668,0.2449345738,0.7457346320,-1.5417525768,0.8053346276,-0.5716369748,1.6070737839,-1.2270644903,1.9155560732,1.0043300390,1.8278682232,-0.6639636159,0.6661688089,0.4428050816,0.0892480984,0.2309782803,0.8315519094,0.1459945887,2.3326561451,0.5832629204,-0.2406825274,1.9596458673,-0.6441795826,-0.8311957121,-0.9647058249,-1.5046192408,0.5703581572,-0.5187826157,1.4320012331,0.2922801673,-1.2171894312,-0.6377372742,1.4113386869,0.5109692216,-1.4242004156,-2.1111421585,-1.6401022673,0.3583278954,-0.0144035704,0.8650972247,-0.0165269319,0.9271504879,1.5814197063,-1.2962620258,1.4669339657,-1.8920297623,-0.5688353777,0.1828519851,2.2016677856,-0.1028954163,-0.9203289151,-0.1486750543,0.3816725910,0.4249047637,-0.5387316942,-1.5233194828,-0.8753087521,-0.2341729850,-0.2465784848,0.0562043898,0.1882509887,-1.0140819550,-0.2454162836,0.8557434082,-1.3931586742,-0.4529600143,-1.4558101892,1.3878477812,2.2907056808,-0.0797444135,-0.4271253645,-0.2662831247,0.5487980843,-1.0244842768,-0.8371625543,0.8822185993,-0.9598054290,-0.0063711633,0.8817792535,-0.8519062996,0.0839718059,0.6059336662,-0.8637058735,0.5584779978,-0.0299070161,-1.4362994432,-2.0078036785,-0.2094628215,-2.6569430828,-1.1245808601,-1.3522570133,-1.3392878771,0.2719299793,-1.0510017872,-0.5297577977,0.0293570850,0.3279094696,0.9607840776,-0.0345142111,-0.0836286321,-0.4210097790,-0.3227880597,-0.4815520048,0.4784446359,0.8643121123,-0.4473959506,1.6125975847,-0.3212073445,0.2659475207,1.1676646471,0.5559692383,0.7779700160,0.6278859973,-0.2657962441,-1.6537842751,0.5440248251,-0.3830282688,0.7568864226,-1.9953464270,0.2166253179,-0.1360926181,0.3883821666,1.4031965733,0.1071888581,-1.0993431807,-1.4928320646,-0.0251265056,0.4121911228,-0.7856203318,-0.3717033565,-1.3687229156,1.2271392345,-1.2881999016,-0.6959694624,-0.8874993920,1.4558117390,0.3226454854,-1.3846375942,-1.0860627890,1.0846112967,0.4653168321,2.5614218712,2.7988910675,0.9378732443,0.0436836891,-0.2922166884,1.7467682362,-0.9949976802,-1.1876443624,1.5535912514,-1.5948337317,1.3830382824,-1.7654812336,1.8867820501,-0.0235525575,1.3374916315,2.3650345802,0.6751262546,-0.6060769558,0.0485105924,-0.1316827983,0.0151644247,0.4798516929,-0.7473517060,-0.9493153691,-0.5720299482,-0.1864403486,-0.9693927169,-0.0035792037,-1.6661548615,1.3482993841,2.0277435780,0.3658308387,-0.8208331466,0.4718213677,0.6236744523,0.4980045259,-1.3271654844,1.3967874050,-0.1287742406,-1.1586636305,-0.2044127733,0.2533079088,1.2015191317,0.1085055918,-1.5884567499,1.0797991753,-0.5118536949,1.7802431583,-0.3157459795,-0.2945337296,1.5226759911,0.0407008827,0.9528471231,0.7287182212,-0.7189680934,-0.0266107712,-2.0186710358,1.2203032970,1.1047537327,-0.8241505027,0.8184968233,-1.7929810286,0.9446066618,0.0339597128,-0.3622136414,0.4354104698,-0.4571644366,1.4052172899,-0.2578752041,-0.1565036923,1.5309950113,1.0972181559,-0.2565720379,-0.4348123670,0.0947441384,0.9954605699,-0.5722588301,0.3652120829,0.5728793740,0.1401024908,-0.1164690852,-2.0019223690,0.2620675564,0.8731961846,-0.0032438957,1.2527974844,-1.0324943066,0.9453257918,-0.8272736669,1.6740643978,-0.9105581641,-0.3780149817,-0.0894450843,2.1181685925,-0.4071816206,0.7425952554,-0.7459664345,2.4063830376,-0.4379978478,0.9473155141,1.5492707491,-0.0160185508,2.9175112247,-0.3762186766,-0.8467391729,-0.0670067072,0.0901584849,-0.4757851958,0.0956222340,-0.3810622394,-0.9159494042,-1.2364341021,-1.1209826469,0.8402428627,1.3614509106,-0.6751222014,-0.3164610267,0.5810042024,-1.0004385710,0.6155641079,0.8530336022,-0.6594149470,-0.4928688407,0.7073107362,-0.4533206820,-2.0503511429,0.7237859964,-2.3081104755,0.7931211591,-2.2254080772,-0.5442180037,1.7981696129,-0.4281713963,0.3618839681,-0.5407407284,-0.2953153551,-0.2099083960,1.0288715363,0.8415134549,0.2290135175,-0.4205887914,0.0023723538,1.2285922766,1.1784408092,-1.0734616518,2.3597648144,1.1720961332,-0.6565869451,0.7126896977,0.1096705943,-0.0268855970,-1.7138684988,0.7106988430,-1.0446763039,-1.2062015533,-0.3407447040,1.3466372490,0.6082682014,1.3727915287,-0.0571841560,1.0773525238,0.2110953927,-1.5239913464,0.6126305461,0.6644054651,-0.9984656572,1.3315540552,-0.3504710495,-0.1185619310,1.3879070282,-0.9998387098,0.5702096224,2.1872117519,0.7356611490,-0.3437471986,-0.6454073191,0.6962169409,-0.4820179045,-2.4766716957,0.9680387378,-1.1541639566,-2.0597898960,0.1503677368,-0.7456140518,1.4302666187,0.8453559279,-0.9875950813,1.8884847164,0.7621361613,0.6842812896,-2.5535175800,0.1136048585,-1.4359040260,-0.9684360027,-0.2280776203,-1.2567373514,0.4444446266,0.6932767034,0.5163866282,1.1237536669,-1.4660167694,1.9476058483,2.8177776337,-0.6734972596,0.5416264534,-1.4821751118,1.6413025856,-0.6007871032,-1.6072694063,0.3414277434,-1.1667805910,-0.3343241811,-1.9332513809,-0.1265669763,-0.1862681210,0.1386926919,-0.4867524207,0.4340206087,0.0739651024,0.9674845934,0.8658832312,1.0888012648,-1.3989909887,-0.0956165418,-1.4477106333,0.6629640460,-0.2317875922,-1.2718285322,-0.9693523049,0.5948191881,2.1844816208,0.5021012425,0.0804309994,1.8132755756,-1.8225727081,-0.8481187820,0.2896516323,0.6112565994,1.3894894123,0.8772185445,0.5663446784,0.7064805627,0.5084221363,0.0819462836,-0.4970123470,-0.6747379303,1.2025511265,1.6175380945,-0.8847118020,-0.4290374517,1.5003818274,0.4689340889,1.6352735758,-1.1227899790,0.8453468680,-0.2696839273,0.7648316622,1.3724489212,-0.1384429038,-1.1072838306,-2.4854152203,0.1164309531,-0.0418152809,-0.8732971549,-0.3142679930,0.7281127572,-2.0499973297,-1.5354900360,-1.2159559727,1.0636960268,0.0742390528,-0.4086834490,0.6344577670,-0.0591966920,-2.1613221169,-0.1440149993,0.3146380484,-1.0171301365,-1.6388372183,-0.9077087045,-0.2367976457,-1.8067845106,0.7331464887,-1.2680211067,-0.5259135365,-0.2642040253,0.4714785516,0.4978014529,-0.4443696141,0.4366762042,0.9659940600,1.0915999413,-1.3117097616,-0.4258576334,0.2191979438,0.5577743649,-0.3677088618,-0.2587479949,-0.2951894403,-0.1285194010,-1.7410380840,0.2037728727,-0.0169256441,-1.9258970022,1.1891771555,-0.1056173444,-0.2551109493,0.0803601369,0.3078361452,1.4552494287,-1.7418527603,-0.1786758006,1.3843970299,-1.8449815512,0.2047158927,0.7096581459,-0.2328862250,-0.3915565908,-0.6430918574,1.1635156870,0.7798740864,0.3655540943,0.2442674339,0.9248095155,1.3240067959,-0.3801167905,-1.3439861536,-0.6244315505,2.1410539150,1.2676112652,-1.6609078646,-0.8470503092,1.0326119661,1.1942317486,-1.9800231457,-0.7131582499,-0.3807858229,-0.8833439946,-1.1810083389,-1.3195772171,-0.0540605076,-0.0507104397,-0.0006503842,0.2843582630,-0.1849077493,-0.9837927222,-0.4980651736,0.5068479180,-0.0115457019,-0.1425283551,-0.1853843629,-1.3138334751,0.6789863110,-0.1799073815,0.1523042619,0.8186873794,-2.3586330414,-1.1386350393,-1.8707106113,-1.3997253180,-1.6075724363,-1.7040657997,0.5580219626,0.8402561545,-0.4480331242,-0.8665820956,1.6506772041,-0.8412654996,-0.8535141945,1.0686321259,-1.8647556305,1.6807284355,-1.4227255583,0.7940302491,1.1190499067,0.1854119748,1.0127215385,0.4834828973,-0.0771656111,-0.3799327314,-0.0321431160,0.4283321500,-0.2940807045,0.4353268147,1.0631655455,0.1714275032,0.8127216101,-0.4509384334,-0.1770134270,-0.6772844195,0.1549729407,-0.0158453472,-1.1719727516,1.0151515007,0.5892142057,0.7689551711,1.2890911102,-2.1213917732,0.7964041829,-0.7404226065,-1.7036547661,-0.2855556011,0.8033329248,-0.1386539191,0.5521915555,-1.6757645607,1.1778060198,1.4586355686,1.4529005289,-0.1698000878,-0.6933089495,-0.2682672143,-1.6710566282,-0.0512348413,0.6260530353,0.7085033655,0.7272201180,0.3297210336,0.3958292603,0.2138654739,-1.0701493025,0.9027658701,0.6664137840,-0.4717260897,-1.6510242224,-1.2329187393,0.3288979530,-0.5451109409,0.5936804414,1.3355246782,0.1301572770,-0.2022518814,-0.8950264454,1.2793928385,1.5864177942,0.4107882977,-0.0241710469,0.5844276547,0.5538517237,-1.6992001534,0.6862621903,2.2658751011,0.8761395216,0.3837254047,-0.2647534311,0.4720512033,0.1841666549,0.2001533508,0.0668039396,-0.1149130762,-0.4432745576,1.1688767672,0.3746031225,1.0524545908,-1.1692347527,-1.2809635401,1.3166548014,-0.6610518098,1.4376925230,-1.0611702204,-0.5353015661,0.1217178032,0.6271507144,0.7130964398,0.5698034167,-0.0544330068,-0.0827762783,0.4918554723,-0.5561770797,0.9431702495,-1.2986550331,-0.9600256085,-0.1253585219,0.6193585992,0.2552787066,1.2878757715,-0.5704673529,-0.3831481934,1.0959254503,2.0086066723,-2.1474649906,-0.1529575735,0.8048326969,-0.4581208527,-0.0162758399,-0.2110669166,0.1082363203,0.6949726939,-0.5438286662,-1.1747916937,1.6570202112,0.5229940414,-1.2811999321,-1.8111737967,0.4468028843,2.0589504242,0.7505765557,1.5820052624,-0.9668190479,-0.3587667346,0.3426084518,-0.4487540424,-0.5114123821,1.7574405670,-0.4817022383,0.6514472961,-0.7424803972,-0.5344078541,-0.1580218077,0.3720195889,0.5527791381,0.4424994588,-0.1315764487,-0.4980100691,-0.5082452297,-0.1763692796,-0.4118542671,-0.7443788052,1.9393750429,0.8029169440,1.1061604023,-0.0243216679,-1.8400745392,0.6343280077,0.2006740719,0.5488215685,0.2727405727,1.0560905933,-0.6984013319,0.3588303328,-0.1235076785,0.0187691264,0.5021178126,1.6440634727,-1.8855284452,0.6837254167,-0.3057632446,1.5436513424,-1.0427814722,-0.5129017830,0.6372142434,-1.2669779062,-0.0673971698,0.4885091484,-1.0358808041,-0.4340546429,-0.3351761401,-1.0594669580,0.4214607775,-0.2359634340,0.1719900966,-1.6630712748,-0.7779294848,0.7398859859,0.9763131142,0.9751464725,0.3020714223,0.7720235586,0.8978174329,-1.3763316870,-1.1374385357,0.4448396564,0.0724404156,-0.7544128299,1.1938458681,-1.3248474598,0.0271121897,0.3545929790,0.1016891822,0.8709347248,1.2646727562,-1.1754066944,0.7666998506,-1.0119038820,-0.3860526681,-0.8156091571,-1.6459562778,-0.5340557098,0.7559775114,0.2526681721,0.3399650455,-1.1079380512,-2.3619008064,0.1570393592,1.3197020292,1.2027004957,-0.4237133265,0.7454201579,0.6623315215,0.1792276502,-1.3496153355,0.3558274209,-0.6212102175,-0.8429967761,0.0761769116,-0.9115606546,-0.1469836384,-1.2940363884,-0.3781982064,-0.3462474942,-0.8051198125,0.9975365996,-0.4378167391,-0.3652188480,-0.4983713627,-0.3541530967,0.4649488926,0.4458468854,0.1212970540,-1.2046818733,1.1245608330,-1.0488841534,1.5659842491,0.3328139484,0.4238919020,-0.0850975588,-0.2209404260,0.2532872260,-0.3511019945,-0.0293736942,-1.6951823235,0.3349150717,-1.3477668762,-1.0378328562,-0.0748831630,-0.6586401463,-1.7394788265,0.2208534479,0.3594329655,0.4248667955,-1.0971237421,-1.8624976873,-0.8188779354,0.5210671425,0.1090878546,-0.7082766294,-1.1870042086,-1.0185188055,-0.0105035771,-1.0859087706,1.0135194063,-0.2151187509,0.8128567934,1.1123318672,-0.2369445115,-0.7196567655,1.3356708288,-2.0030705929,-1.7887951136,0.5355278254,-1.9258182049,-1.0679100752,0.4666056633,0.6799566746,-0.6068207026,0.0376300998,-0.8954614997,-0.1887252182,0.0670508146,0.2367895395,-0.7261124253,0.1988874674,1.1370029449,0.2628233731,-0.1744217128,1.0385823250,1.9289591312,-0.6241374612,-1.0708029270,0.7845878005,0.2213747650,1.2395253181,-1.6699419022,-0.5792590976,-0.7590466142,0.1721247435,0.6796442270,0.2983916998,-2.5116040707,0.4435839653,-1.0932787657,0.3189210296,-1.4347689152,-0.4141550660,1.2627629042,1.2916916609,-0.7968822122,-1.6745941639,0.6268520951,-0.2823364735,1.5425739288,-0.6658401489,-0.2700735033,1.0813314915,-1.7792905569,1.3893454075,-0.2835470736,1.1381509304,-0.5500882268,-0.3804549575,0.2835711241,0.6406458020,-1.9321515560,0.4521977603,0.0565207116,0.0297215879,0.1266185045,-1.1317875385,-0.0913078189,-1.4813172817,-1.6310836077,-0.1334815770,-0.5777752995,2.1017003059,1.8821809292,-1.0327913761,-0.4687115550,0.9024651051,-0.2668906152,-0.3431535661,0.9062344432,-1.4410095215,-1.8423423767,0.1403119117,0.3281984925,1.4122068882,-1.4440245628,-0.2864913046,-1.1767127514,-0.2729947269,-0.3813755512,1.2839496136,-0.3271493614,0.1473392993,0.5373675227,-0.5618190765,-1.8962076902,-0.4639317989,1.9236954451,-1.6677190065,0.1464398950,-0.3466111720,-0.0322197936,-0.4217617810,0.6667121649,-0.6521687508,-0.1843066812,-1.4433963299,-0.0677214116,0.1818892509,0.2523166239,0.0736405179,-0.3877593279,0.8917374611,-0.3416461349,-0.9169380665,0.5122210979,-0.4665381312,0.5767468810,-1.4800413847,1.7983590364,-0.6339222789,-0.2424547374,-0.4834831655,-0.8287428617,0.3135240376,0.8550209403,-0.0855247900,1.5032401085,-1.1833488941,-0.0465497859,1.0746041536,-0.9027399421,-0.5185764432,1.8878662586,-2.1824460030,-0.5935040116,1.2031533718,-1.2403950691,-1.1820745468,0.2421696186,-0.3005659878,-0.5867491961,-0.1843579561,-0.0163780041,0.4539252222,-0.9440818429,-0.3242641687,-0.9195576310,0.1757366210,0.5645468235,0.6839561462,1.7646182775,0.0367704555,1.0817803144,-0.3612675667,-0.8710808158,0.6322647333,-0.3519022763,0.7156081200,0.2653824687,0.0456245095,0.6150549054,-0.2387576997,-0.9838037491,1.1115764380,-0.7091395259,0.5565314293,-0.1952365786,0.7066562176,-0.1020995602,-0.7186366916,-2.5378692150,-0.2224598378,-2.9098627567,-0.6451359391,0.3340830505,0.3082834482,-1.3182439804,-0.3153700233,0.3725237250,0.6292732954,-1.1076341867,0.1932128668,-1.1732625961,-1.2407459021,0.0289576929,0.4187066257,-0.1023253500,-0.5126762390,0.3325288594,-0.9176725149,0.3762895465,0.4857420325,0.6293258667,0.4774833620,-0.6179270744,-0.7745063305,0.2900193036,0.6556027532,0.7161750197,0.0969872698,-0.2772769630,0.9734714627,0.9022426605,0.5066912174,-1.3773590326,-0.4419030547,-0.9061026573,-1.2645193338,-0.6771960258,-0.7416522503,-0.4033834934,-1.7905031443,-0.7197990417,-0.1203307286,0.1458987892,1.0860456228,-1.3431071043,0.5452275872,-0.8861137033,0.0133407973,1.8350932598,-0.7494224310,-0.9539094567,-0.1490415484,0.4838488698,0.1974841207,-0.1861835718,0.4435926378,-0.8599298000,0.8017390370,0.8421186805,0.1312466115,0.6086190343,2.2241444588,0.9180830121,-0.1491888463,0.3608322442,-1.1499377489,-0.3584724963,-0.3109835982,-0.0412371941,-0.2816070318,-0.3876631856,-0.2826207876,-0.3808020353,-0.8287383914,-1.2302982807,-1.8592271805,-1.9187139273,1.2635271549,0.0478380919,0.5384370089,1.9528542757,0.0862558335,0.0315737054,-1.4575328827,-0.6429215074,0.2418305725,-0.8390690684,0.2132374197,2.1373596191,-0.7756822109,0.7898190618,0.3226329386,-0.6459203362,-0.8996171951,-1.1986262798,0.5406119227,0.3710613251,0.0836729556,-1.3073230982,-1.7027620077,-0.7785076499,-1.2514255047,-0.7407965660,-0.6227626204,0.7248088717,-0.9243300557,-2.0425086021,-0.1531879455,-0.8591698408,0.2854239345,-0.8992351294,0.6543528438,0.2941486835,-1.4519603252,-0.4732797444,-1.6374208927,-0.0668385923,-1.9343371391,-0.7832041979,-0.9100412130,1.6664811373,-0.2630090714,0.0338229686,0.2412451953,0.6096515656,0.3015289009,-0.1897550225,-1.3486781120,1.5449596643,-1.4853315353,-1.6852138042,-0.1775777191,-0.1915055960,-0.2492433488,-0.5336878896,-2.4988777637,0.8858756423,-0.8840622902,3.1992139816,-0.1212008819,-0.2876134515,0.0497608893,0.4297440648,1.5458735228,-0.1417457461,0.2272661030,0.4704810679,-1.0789257288,-2.4185669422,-0.8468856812,0.4660403132,-0.5138173103,1.7465744019,-1.1475670338,-0.1167239025,-1.4896283150,0.5956840515,0.9185001254,-4.8521175385,1.9427913427,0.1110671237,-0.8844205141,-1.5047377348,-0.0306469593,0.4130496979,-1.3862971067,-0.1759836525,-0.0979491323,2.1978659630,-0.3581565320,0.0429174267,-0.4899995327,1.6953723431,1.6068502665,0.8885279894,-1.8128461838,0.8054482937,0.3749721348,-0.1091318503,-1.4783062935,0.4781311750,1.1914623976,0.8886550069,0.9224624634,1.4349462986,0.6760825515,-1.1191790104,0.9839367270,0.5592536926,-0.3300490081,0.9047982693,0.6609485149,-0.0711592138,-0.9454471469,0.9492801428,-0.0225257389,1.1091521978,-0.3238544762,-1.5080913305,0.8890247941,0.1120769978,-0.3998112082,-0.0686101541,-1.0087525845,1.1175528765,0.7182284594,1.0960410833,-1.1370993853,0.5957803726,-1.2771836519,1.3723937273,-1.0925372839,-0.0115856826,0.5942286253,-0.4304260015,1.0643801689,1.0266114473,0.5688973069,-1.3226926327,-0.0613019504,0.1347569972,0.3081897497,2.7131412029,0.4377599359,0.6334095001,0.3660160601,0.0500705987,-2.2779371738,-1.4221690893,-0.6358492970,0.1561469287,-0.9243812561,-0.2980656326,2.0219075680,1.4666409492,-2.5164093971,-0.3836316168,0.8046503663,-1.5332547426,1.2595324516,0.9782047272,-0.6557393074,1.0916570425,0.5810801387,1.0126934052,1.5139583349,-0.3119343519,-1.6407750845,0.7864783406,-0.8549495339,-0.7213819623,0.3934730887,-0.7415456176,0.3942766190,1.1725586653,-0.3623433709,0.6115031838,0.3008793890,1.5449849367,0.3181261420,-0.6514180303,0.2031024098,-0.2640877068,1.7698686123,0.6486811638,0.4432561994,-1.1322586536,-0.0290353186,-0.0781910121,-0.8639219999,-0.1526577324,0.1938848794,-0.5969279408,-0.4834834635,0.1573596299,-0.0592252091,-0.2702434063,-0.1515217274,-0.6052051783,1.9567449093,-0.4848371446,1.4323050976,0.0834007561,1.0406645536,0.0405718312,0.4692253768,-1.5332688093,0.2604510486,0.1545928121,0.5367847085,-0.3339368403,-0.4093825817,2.1708376408,-0.7797004580,2.4333009720,1.3753080368,0.2541124821,-1.9115686417,-2.1534113884,0.7856022120,-0.3899005949,-2.4047720432,0.1866433322,-0.6678485274,-1.3123197556,1.2337210178,1.6666272879,-0.1272123754,-0.9279864430,0.7762946486,0.9160736203,1.7719123363,0.7667344213,-0.1590543240,0.6486815214,-0.6689631939,0.5103842020,0.4520286322,0.1566184610,0.3792171776,1.0502470732,0.4308493733,-0.3508707881,0.7412344217,-0.3274298310,0.9234266877,0.9893772602,-0.8493971825,0.0270343702,0.4415463209,0.6724033356,0.1209470704,0.5693858862,0.0050581717,-2.1161911488,-0.6223433614,-0.5580531955,0.2278435379,-2.5865576267,-1.7090963125,-0.0353317894,0.5161625147,1.2569897175,-1.4674524069,0.3912377357,1.5026664734,-0.4857432544,0.0476039536,-1.3667999506,0.2982648015,0.2895137668,-1.2085553408,0.1725535691,-0.1539426297,0.6676985621,0.1313693672,0.3164666891,-1.0863517523,0.0785836726,0.7611423135,-2.1127955914,-1.4819056988,-1.0567213297,-0.8317061067,-0.4102806449,1.3269690275,-0.4393536747,0.0698533207,-0.6893197298,2.1084895134,0.2268670052,0.8511615396,0.3854487240,0.4431305826,1.0205435753,0.4819956422,0.5102502108,1.5450580120,0.8968815207,-1.0848166943,0.7952970862,2.0239479542,-0.7240387797,0.0220920593,-1.1563844681,-0.1014404744,0.3656550944,0.5663932562,1.0644277334,-0.5995697379,-1.2106146812,-0.8576260209,0.5674060583,0.6007801890,1.5416058302,-0.6908056140,-1.0867762566,0.2649148703,1.4798949957,0.7393624187,0.2967948020,-0.2771933377,-1.1488587856,1.6003367901,1.6553497314,0.6626985073,-0.6280882955,0.0936584100,0.4981217682,0.9492636919,-0.4618748128,0.2677331269,1.2989481688,0.0265531186,0.3216917515,-0.2674317956,-0.0111542614,0.2487320751,-0.3743169010,-0.9511997104,1.6651052237,-1.6196660995,-0.5902080536,0.3614725173,-0.4152885973,-0.7183656096,0.3520698249,1.4739658833,2.4271173477,-0.5691303015,0.9813193679,-0.5925389528,-0.5128179193,-1.1542140245,0.5358704329,1.3890676498,0.5996650457,-0.2719255090,-0.0948925391,-0.7808255553,-0.6444920897,0.9755622745,-0.2208294421,-0.3493718505,0.2699482143,-0.7280527353,1.3917051554,1.4498575926,-1.2113507986,0.3349868953,1.3251229525,-0.9171952009,0.4963794351,-1.7986804247,0.0789784789,1.2199368477,0.3269993365,-0.1948697865,1.3435184956,-1.0425250530,1.3683353662,0.2499956936,-1.4721306562,-0.2956948280,0.5207143426,0.4645217061,1.4431642294,1.2225159407,-1.3223319054,1.0886017084,0.9286890626,-0.1376378387,-0.5915322900,-1.0464158058,0.5867432356,-0.8797436953,-0.7235412002,-0.6804904342,-2.0942678452,1.0294381380,0.7672358155,1.0971862078,0.6071217656,0.6025097370,0.8277061582,1.1057502031,0.5251725912,-1.1081231833,-0.4811174273,-0.3702764511,-1.3508657217,0.2259329855,-0.0718035176,0.1823831201,-0.2373090535,1.1184384823,1.3183101416,-1.9148426056,-0.4826577306,-0.4699207842,1.2780392170,1.4454777241,-0.2684786618,-0.2248070687,-2.3880140781,0.4959293306,-0.3267105520,1.3605651855,-0.5306251645,-0.0932557359,-0.5050152540,-0.7892034054,1.0203313828,1.2451971769,-0.4140982628,-0.3513950109,-0.9037069678,-0.0241906717,-0.9075904489,-0.6557211876,-0.1932841986,2.3157627583,0.5288925171,-0.6291821003,0.9991913438,-0.4957025051,-1.1099767685,0.0842455551,0.0248599015,0.0334466957,-1.6484893560,-0.8135964274,-0.0473386273,-0.7118042111,0.2833947837,-0.0167807993,0.2662077546,0.6260454059,-1.7930265665,-1.1567467451,-0.5512157679,0.6015375853,-1.2865725756,-1.9408442974,-0.1325186938,0.4100147486,-0.8295570016,0.1938338429,0.0979138017,2.5477495193,-0.4140664637,-1.7858626842,0.6429503560,-0.3502498269,-0.2588729262,-1.0729311705,-0.3541617393,0.3570177555,-0.6643162966,-1.4513443708,-1.6973505020,-0.0602100231,0.2496821880,-0.9163889885,-1.5405261517,-0.4512024224,-0.6341095567,-0.0097503057,-1.2270138264,-1.3736895323,0.1918285489,-0.9191774130,-0.6565604210,0.6039719582,-0.1332715899,-0.8285505176,-1.0401451588,-2.4385795593,2.2394487858,-0.2572565675,-1.8150984049,0.4597521126,0.4808021188,0.5467767715,0.6092917323,1.1429659128,0.2309983224,1.5645856857,-1.2469551563,-0.2577306330,-1.1540452242,-1.3649905920,0.6702425480,0.2360917628,-0.1505737454,0.3084661663,0.9137232900,-0.8299762607,1.7046604156,0.4507624209,1.6921821833,0.0341390707,1.4222145081,-0.5597399473,-1.0490896702,0.6614012718,0.7688275576,-1.1840931177,0.3911654651,-0.4891320169,-0.7211934924,0.8481540084,-1.0097805262,-0.3961494267,-0.4591137469,0.1611833125,0.1956343353,-1.2476583719,0.4416362345,1.1361719370,0.0931860134,-0.9278345704,-0.7907865644,0.6913827062,-1.3883576393,-2.3996989727,-0.3636757135,1.1655604839,-1.4245017767,1.2208950520,-2.0990407467,-0.9538810849,-0.5822237134,0.1402315944,0.0464295745,-0.5008851290,-0.2975231707,0.8082782030,-0.3997581005,-1.6819230318,-1.0130381584,1.7739200592,-1.0784034729,-0.1895323843,-0.7823113799,0.8008701801,-1.5388237238,-1.5723116398,-0.4203703105,0.1166450381,1.0583444834,1.5439826250,-0.5834670067,-0.9337796569,1.9155551195,0.1372870356,0.7505593300,-0.8319081664,0.6255533695,-1.4047561884,0.1378288567,-0.8832240701,0.5066967607,-1.3870570660,-0.2949680090,-0.5365743637,0.7241915464,-0.0380382910,-0.4298193157,-0.3633871377,-0.1892514825,-0.9280431271,1.6019604206,0.9871795177,0.4851090908,1.4912133217,-0.0962753594,0.2499185055,-0.5457340479,-0.4101860225,0.2294923216,2.2696387768,-0.3302621543,-0.2712452114,1.5598413944,0.2520926595,3.1268947124,-3.2329590321,-0.2350266725,-0.1970554143,1.6455147266,-0.4833549261,1.8614071608,0.1210813671,2.4485468864,0.3696423173,-1.1890643835,1.1097162962,-0.9812495112,-1.5117832422,0.4652085900,1.0399012566,0.4068359435,1.6711966991,0.4793457091,0.3833797872,-1.2494162321,0.1649812311,-0.4304262102,-0.7297959924,0.8276520371,0.7847200036,0.5139238834,-1.9722926617,1.0811411142,0.1848393828,0.0775561258,-0.2357782871,0.1912350357,0.5073704123,0.0564742349,-0.8233909607,-0.8220529556,0.1913980395,0.8005524874,-0.1441638619,0.7258716822,0.2305646241,0.9593602419,-0.1887491792,-0.6131626964,-0.2583982646,-0.7700645328,-1.6128127575,-0.6146055460,1.2405661345,0.4227060676,-1.0741027594,0.3241637647,-1.4035487175,-0.0658114403,0.6804963946,0.5681362152,-1.3921498060,-1.0300476551,-0.2371842414,1.8360530138,-0.9216187596,0.9207280278,-0.5574217439,-0.4712163210,0.2855410874,0.3498257697,0.5446513295,-0.0277582034,0.9110357165,1.0241811275,-0.4904206991,0.0496969819,0.6285252571,-2.9861686230,-2.1029310226,-0.3938883245,-0.2817675471,0.2416146547,0.9426638484,0.3875665367,0.1224803925,1.0414155722,-0.3351289928,-0.4107232392,-1.5650410652,-0.8893459439,0.0849630237,-1.7995682955,0.9912497997,-1.8885445595,-1.1762053967,-1.2450914383,2.7380778790,-0.3616687357,-0.2209551036,-1.7513599396,-0.8957287669,-2.2897720337,-0.0876673013,0.6963365674,0.3551538885,0.9297693968,0.0609674230,2.4712345600,-0.4208989441,0.5249027014,-0.2286021709,0.2329783738,0.1197842136,-0.9520625472,-1.8651957512,0.2399929166,-1.2985645533,-0.6591146588,0.2112485319,-0.6970937252,-0.6887322068,-2.0674235821,-0.0465840735,-0.9805367589,0.4654271901,0.5672482848,0.7053048015,-0.6611399651,1.5472348928,-0.9092199206,-0.0546701252,-1.0351397991,1.3140008450,-1.5395072699,0.0404680595,0.9997606874,0.6848905087,0.4523021281,0.4604639709,-0.1260150522,0.1083656922,0.5990031958,0.7269591093,-1.7155878544,0.6685690880,-0.6821148396,-1.3120325804,-0.5852013230,-0.3806896210,2.0486714840,0.6823633313,1.0913326740,-1.6782044172,1.5952193737,0.6944016814,-1.1871331930,0.9472473264,0.5641186237,-1.0589094162,-0.8352508545,0.8253346086,0.5406584144,1.0564606190,0.6108237505,1.3554942608,-0.0652598366,0.3243359029,-0.4841716290,1.2476578951,0.2305612564,0.9184203744,0.7574568391,1.0057890415,-0.4710326791,0.0801935941,0.0023979940,0.6727606058,-1.4283015728,2.0315153599,2.1044881344,0.8079706430,0.2700591683,-0.1420193762,-0.4140471816,-0.8383685350,0.3478310406,-0.1102372110,1.3906400204,-0.4889595807,-0.1187727004,-0.8679751158,-0.0362039842,-0.0926602483,-1.0390424728,-0.5257984400,-0.0478054583,-0.9813799858,1.6373766661,-0.0322443843,-0.4711576700,-1.7374867201,-0.3807227612,-0.1615162790,-1.1044647694,0.1208630577,0.8739864826,0.4768305421,0.6930779815,0.3838321269,-1.5314662457,0.3809277415,0.1716790795,0.3956367671,0.9040478468,-1.4133884907,0.8503904343,1.1443232298,-0.0336308964,1.1579585075,-0.3186286688,-0.1953814030,1.1942832470,-0.5953484178,-0.9550271630,0.2698577642,0.1056953147,-0.0633471906,0.3749876022,0.1402860582,1.2944872379,-0.4121560156,0.4817930460,-0.0993803889,-1.5939522982,-0.4357390404,-0.4619060159,-2.3683354855,0.2805862129,-0.3046934605,-1.2935652733,-1.1554673910,0.1633427739,-0.5986722112,1.2634762526,0.9150058627,-1.0899602175,-0.5049229264,-0.0143814981,1.5127053261,-0.8898098469,0.3804249167,-1.1658823490,1.2145162821,0.1391834766,0.9084006548,-0.0797242448,1.7454173565,0.8128961921,-0.3380572498,-0.8773782849,-1.1081911325,0.7548649311,0.2150626332,1.1833186150,-0.3489762843,2.1793832779,0.3019517660,-2.0800480843,1.3498222828,-0.6469517350,-1.0101433992,-0.0867938995,-0.3999692202,0.5472961068,0.4918823838,0.9543326497,1.3563923836,-0.8218570352,0.0116919894,1.2118961811,-1.2016319036,0.4808796048,-0.4284862280,0.2089256644,0.8705192804,-0.3592517376,1.0025163889,-1.3868917227,0.2231241167,1.6292181015,-0.7550464869,0.4189785719,1.3076460361,-0.3605156541,-1.1180034876,-1.1126116514,-0.6930063963,0.3895854354,-1.1811661720,-0.7325514555,0.1279658824,-0.5388088226,-0.3408534229,-0.2591611445,-0.1481301636,1.1229610443,2.1432387829,-0.3806581497,0.8855195642,-0.5941774845,0.8604633212,1.0511958599,1.0734173059,-0.2655522227,-0.3933710754,0.3349715471,-0.8550754786,-2.2061393261,0.9727731943,0.7498283982,1.6936372519,0.5487921834,0.0691117644,2.7273132801,-1.8114776611,1.1478933096,1.0795128345,-1.0359307528,2.3957827091,-0.7863538265,0.5545166731,-0.2966851890,-0.2659127712,-1.2508859634,1.1771451235,0.4923931360,1.2278065681,-0.7286225557,-0.0930251777,-0.5998708010,-0.2299500108,-0.4579644799,0.5729542971,2.3201682568,-0.8726349473,0.3805692196,0.8630654216,1.6897252798,-0.8851308227,-0.3429644406,-0.7624091506,1.3988976479,-2.7959020138,0.4372125268,0.0636285543,1.8906742334,0.0905186236,-1.0840857029,2.0455691814,0.9350713491,0.1695361584,1.2804718018,-0.6724713445,-0.3662121296,2.0804431438,1.7761652470,2.8678522110,-0.0991531014,-0.3440111876,-0.9633069038,-1.3825284243,-1.4679977894,0.2173433304,0.0366753228,-0.7773872614,-0.0060850084,0.2425571680,-0.3767814338,0.8276780248,2.0392413139,-0.2837807238,1.2338672876,-0.3843937814,0.5756478906,1.6414058208,-0.3666916788,-0.9714407325,-0.2356366962,-1.2913995981,-0.8960181475,0.1272795498,-2.2407054901,1.1917226315,0.4333340824,-0.3930523992,1.1191014051,0.6791875958,0.4361049235,1.0977270603,1.0344529152,0.3062209487,-0.0446278788,0.0910232663,0.5822839737,-0.1521469802,-1.1190607548,-0.2476054430,-0.7367978096,-0.4856684804,0.6659203172,-1.2921715975,1.8827733994,0.5838482380,-0.2108717859,-0.0243280269,0.1365130842,1.4073339701,0.9856215715,0.3627391756,-1.3479270935,1.1825037003,-0.2711353302,-1.2824739218,-0.6591538787,-0.5253095627,-0.4016566873,0.4823636115,-0.6241627932,0.4012881219,2.4049458504,1.8389296532,-0.8160229921,-0.8917958736,0.2054117322,-0.5678172708,0.0877340585,-1.3987337351,0.3651104569,-1.0884479284,-0.0357880071,-0.7008450627,-1.4183855057,-1.0605516434,-0.5557442904,-1.4653967619,0.3975590765,0.9693913460,-0.5058177114,0.1420748681,-0.1394046992,-1.1864151955,0.5770588517,-0.4497047067,0.6133778095,-0.2091179043,-0.8822066188,0.9266041517,1.9369000196,-0.9379522204,-0.5523123741,1.6441167593,2.0208413601,-0.5548222065,0.0124798529,0.5058183074,1.1044448614,1.3189389706,0.1909236014,-0.3080491424,0.5630736947,-0.0837698281,-0.3891959786,-0.9374899864,0.6200323701,0.7414302826,-1.2315765619,1.9131008387,0.8843234777,-3.2155885696,1.7159427404,0.2663838565,-0.0736449733,1.1531600952,-1.0004495382,1.8306009769,0.4198108017,-0.5446417332,-0.3730129302,-0.5347300768,-1.3494056463,0.5697371960,0.3700086176,-0.8028948307,0.1239058226,-1.1565580368,-0.9970475435,-1.4502310753,-0.5761058331,-1.4261182547,-1.5865499973,0.8991324902,0.6901183128,0.3546708822,-0.3055213392,-0.1828400046,0.0213740449,-0.7595441341,-0.1451109946,0.2397838533,1.0029948950,0.7565121055,1.3437296152,0.9344487786,-0.0852555111,0.8469684124,0.5529686213,-0.2060049176,0.1530812085,0.6497737765,-0.7188387513,-0.6574992537,1.2068393230,1.4107749462,0.5801166892,-1.9565601349,2.3294208050,1.6649837494,-0.1143305302,1.1704581976,0.1861006618,-0.3432528973,0.7738602161,-0.7633075118,1.6620934010,-0.0148074497,-1.5225170851,0.4448566735,-1.0804424286,-0.2595146596,-1.2039898634,1.1865116358,0.1244517788,-1.7411261797,0.6327655911,-1.4254326820,0.6072432399,2.2639195919,-1.7797319889,0.1546354294,-1.6730787754,-0.6163903475,-0.3629196286,0.1454897076,0.6794376373,1.9794061184,-0.4524740875,1.8563537598,-0.1063185409,-0.9688279629,-0.1407084316,-0.5214707851,-0.2364092022,0.1224080771,-1.4739046097,0.2961368263,-1.8272217512,-2.0639176369,-1.3346837759,0.5843850970,-0.5584329963,0.0578550063,1.0357207060,1.7963436842,1.2943576574,-0.7003925443,0.8481504321,0.6891615391,2.0482206345,-1.2533652782,0.2402896881,0.6737480164,0.4490898848,-1.6458679438,-0.9338932633,-0.3591641188,-0.0254199263,-0.5341939330,-1.2297190428,1.7889677286,-1.4703223705,-0.1667094529,-0.8333431482,-0.8809360862,-0.0065073199,-1.0043187141,-1.0234842300,0.3805767596,-0.4275160134,0.5769917965,0.9083298445,0.7803912163,-0.8485795259,-0.3394566476,0.6788250804,-0.5510795116,1.0690231323,0.6100328565,-1.1385766268,-1.2801609039,1.3604898453,-0.1692980230,-0.9945854545,0.1831673235,-1.6491280794,-1.4920870066,0.5627005696,-0.2753271461,0.1657936871,-0.5342975855,0.2055897117,1.9000588655,1.7738777399,0.0581240840,1.7368767262,2.5812046528,0.3220744729,-0.3783294261,-0.3094934523,0.8187251091,0.9548506141,0.9769791961,2.0029132366,1.7150564194,0.0704670697,-0.3864088058,-0.6378495693,-0.0315747187,0.3025371432,0.4778320789,0.3217836022,0.6492074132,-0.9109751582,-0.7691422701,1.4026347399,-0.9658105969,-0.1002218947,1.5368416309,-1.2793962955,-0.1795984358,-0.3374651372,-0.8700996637,0.4942047596,0.1025737524,-0.9360316396,1.4573398829,-1.1856033802,0.3710526824,0.5413604379,-1.3624647856,-2.2412455082,-1.4766739607,0.7899505496,-2.7598965168,0.4047561288,-0.6828455925,1.9673783779,0.6626994610,-1.0715668201,0.2047873735,0.0702401102,0.2123592794,-1.3596889973,-0.6493543983,0.7024531960,-0.7617487907,0.2701660991,0.5384673476,0.4484993517,1.4303277731,-0.2872730196,0.2255844325,-2.0188221931,1.1860226393,-0.0449120253,1.4178494215,1.1506255865,1.9027528763,-1.0151681900,1.4701216221,-0.3491511941,1.9576206207,1.7094520330,0.8521990776,-0.6261596084,1.6764523983,0.7147725224,-0.4068088233,0.6308442950,-0.0767498091,0.6154634356,-0.5383847356,-0.3225371540,0.4823666215,-0.3547261953,-0.2532891035,0.6753273606,-0.5546728969,1.0751554966,-1.3161867857,-0.9454118013,-2.4545342922,-0.0518297330,1.0433616638,-0.5003373027,-0.3093115389,1.7492716312,0.2976246774,-0.8289340138,-1.5835789442,-0.3375042379,1.9913307428,1.0772083998,0.0367077291,-0.0472101569,0.4658238590,-2.6238150597,0.9969777465,0.0754188821,0.3507779837,0.4585555196,-0.0999287292,-0.3928496540,1.7388290167,-0.8560393453,0.0992961749,-2.1302506924,-1.3153241873,0.8314374089,0.0599960461,-0.1368577778,-0.3394154906,-0.5296584368,0.2793669999,0.7099635005,-0.0835562423,0.6021608710,-0.1196800545,-1.3378901482,-0.3641176224,1.2721914053,-1.4890229702,-0.6869053245,-0.4686065614,0.6426337957,-0.5083370805,0.2268973142,-0.1974736899,0.2527569532,1.7184084654,0.8922979236,-1.5970692635,-0.4582478404,-0.4076239169,-0.1977892369,-0.7555869222,-0.3449466527,-1.2325458527,0.1456603408,-1.2386804819,0.1323075742,-1.8673850298,-0.0677953959,-0.8390944600,-0.2440842092,-1.1514731646,0.3661558926,1.9396024942,0.5101702213,-1.1429055929,-1.1398406029,-0.5165202022,0.3982322812,0.5776135921,-0.2317762971,-1.4540951252,-1.3447998762,0.8522616029,-0.5578137040,-0.2578280866,-0.0890806839,0.0349463075,0.6758262515,1.1467132568,-1.6023062468,-1.1934000254,0.7290937901,1.1782319546,0.3880271018,0.0174299795,0.7336113453,1.0139441490,0.5473438501,1.4955612421,-1.4451948404,0.6801576614,-1.3201237917,0.6385329366,0.0782859474,-0.0863106698,0.6152905822,1.3551502228,-0.0890230834,-0.0486132428,0.8171393275,-0.1492211223,-1.7590962648,0.9003215432,0.1985468268,-0.2245959789,0.6709069610,-0.9071885347,-0.0217190348,1.0644416809,0.2005730122,2.5758602619,-0.1752953529,-0.4584687352,1.0486868620,-1.1132804155,1.2848652601,0.0694471598,1.1292618513,0.9819657207,0.8070746064,-1.1838014126,0.9127116799,-0.0829647705,-1.8536667824,-0.0619276203,0.0663916543,-0.9791166782,3.1375920773,-1.5782490969,-0.0379903316,0.9323066473,-1.2534710169,-0.5725334883,-1.3511468172,0.7215948105,-0.5781445503,3.3989739418,-0.2205531001,0.3763498962,-1.2892030478,0.6944087744,-0.0149582736,-1.7329707146,-0.1396349519,0.8098288178,0.1786913425,-2.2183401585,-0.0800998956,-0.0742241070,0.3845080733,-1.6463791132,0.7107392550,0.9891936779,0.7867619395,0.0749255121,0.2001665980,-0.1341113001,0.0893330351,-0.9379463792,-0.9581400156,-1.2719728947,-2.7973825932,0.5311394334,0.5251041651,-0.4277549386,-0.2632635534,-0.0099409046,0.7350210547,0.4192803800,0.0018239388,-0.0443116762,-0.0689535663,0.7293576598,-0.4967725575,-0.5072520971,-0.1359933764,-1.2276622057,0.6094608307,-1.6442064047,-1.6363502741,1.2297830582,0.0999848545,-0.0986485630,-0.0178937595,-0.2287111878,-1.5501198769,0.2100454867,0.8902381063,0.1387624741,-1.6011765003,-1.2235500813,0.3127393425,0.3142060637,0.8466959000,-0.4800876677,1.5377589464,0.2422349155,-0.9983308911,-0.0291883871,-0.1622420102,1.0121430159,0.6871752739,-0.4247593284,1.0550050735,0.3513199985,-1.4561393261,2.1552989483,1.3274356127,-0.5354955792,-0.6845734119,0.4479947090,0.3242218196,-0.5768624544,-0.3779707849,-1.0639026165,-0.2439878583,0.0086092334,1.6724859476,0.0878778622,1.1755329370,0.1444046646,0.6706321836,1.2580265999,-0.4368670881,-0.3676288128,-0.1864498854,-0.5201572180,1.1724785566,0.2010924965,1.6923856735,0.2290286273,1.6569188833,-1.7776489258,0.4573445320,1.3080205917,-0.3747129440,1.2378357649,-0.5824361444,1.1357333660,-0.9598888159,1.1630618572,-1.5749995708,0.7833538651,0.1442527771,-0.2554296255,-0.9792585373,0.4596745968,0.6203821301,0.5021705031,0.9194006324,-1.0334367752,1.6282829046,0.8093135357,-0.2234846950,1.2612539530,-0.9625234604,-0.6355591416,0.4715775549,0.0068701040,-1.0172108412,0.2494076043,-0.5978446007,-0.7592504621,0.8392009139,-1.3911912441,0.4128962755,-0.7735784650,0.0836772174,-1.5262907743,2.5723426342,-0.1008686349,-0.2837621868,1.0058437586,-0.7359182835,1.1496107578,-0.8255521655,0.7245010138,-0.8101114035,2.0787091255,0.8559275866,-0.5351945758,0.6291060448,0.0856874585,-0.0063943989,0.3543403745,-0.5699222088,0.2983883321,0.7868961096,-1.0871948004,-0.2908948958,0.0930618271,-0.8280441761,1.1082425117,0.2538062036,0.2027538866,0.1541826278,0.2480404079,-1.4028227329,1.1533126831,1.6422873735,1.0832636356,0.8322021365,0.8517474532,0.7841898203,-1.7440323830,0.4765495658,1.0487160683,-0.7914233804,-0.4405639768,-0.2160148919,0.1842859089,1.1629821062,-0.0767243430,-0.7312394381,-0.6774958372,0.3769921958,-0.5758907795,-1.5134738684,1.4181641340,-0.7427386642,-1.0262612104,-1.0112211704,-0.8954152465,1.0703066587,-0.3507716954,1.0855424404,-0.3428264856,1.1746728420,0.3893014789,0.9072918296,-1.5879071951,-1.7463401556,1.5358440876,-0.2369948775,0.2931667566,0.4586500227,0.2925986946,2.3936650753,-1.6313507557,-1.3064545393,-0.2756645977,-0.1694798321,-1.8411900997,0.1854819059,-1.0566730499,-0.1226647571,0.0523388982,1.1009833813,-0.8073753119,-0.0405311659,-0.1907524914,1.6200549603,-0.8034185767,0.9933840036,0.8365669847,-1.0088229179,1.3915550709,-0.6660532951,-0.4306976795,-0.2386864126,0.0843213871,0.5830325484,0.1325431019,-0.7190958261,0.4042440355,0.1904487908,-0.3511888981,-0.0677566752,0.7692873478,-0.9150775671,-0.2478805482,-0.1723368913,-1.7062830925,0.1571991444,-1.2567185163,-1.2486581802,-0.3304790258,-0.1429319084,-2.0155272484,0.1789071411,-0.6599000096,0.2713014483,-1.5153937340,0.5429274440,-0.5614190698,2.1147344112,0.1305354685,2.3193845749,1.0932368040,-1.4592151642,0.8998706341,-0.5619531870,0.1160965636,-0.1549596637,-1.3603447676,-0.1224236861,0.1485626996,0.2863123417,-0.7079705596,1.2752975225,-1.8051139116,-2.4880578518,0.5680893064,0.7016727328,0.1439006329,0.4267070591,0.1790274084,-1.6500613689,-0.8564890027,-0.9328461289,-0.1378492862,-0.9564430118,-0.2885970175,0.2648217380,0.2335142493,0.8945885301,-1.3390487432,0.6258945465,1.6428123713,1.6459735632,0.5991826653,0.1086787358,-0.7074826956,0.9272280931,0.4744967520,-0.4278449118,1.0480604172,-0.4526143372,1.3277521133,-0.0564636923,1.3267620802,0.2104748785,0.3823283613,2.0361435413,-0.5682298541,-0.9197977185,0.2950363457,-0.0598035455,-0.3787401319,0.7625000477,-2.9526107311,1.0240620375,-0.1243128777,0.9883049130,-0.2431208044,-0.5595453978,-2.2868940830,1.2129172087,1.8089084625,1.2684593201,0.5851132274,-0.2312829345,1.8950910568,1.1503691673,0.6162592769,1.1002618074,-1.1529587507,-1.5807942152,1.0720236301,-0.8970527649,0.7691181898,-0.3447100222,-1.0881081820,0.6037220359,0.1806760728,-1.5382072926,-0.6406788230,1.2235890627,0.6681796908,0.5669136643,-0.9254377484,0.4890148640,-0.3914958239,0.3539678752,0.9485787749,0.3038055897,-0.1886343509,0.5120302439,-0.1569281220,2.2453000546,-0.4241433740,0.7208776474,0.3618130088,0.5907598138,1.0482422113,-0.7412730455,-0.1428454220,0.0379181169,0.2372295856,-0.2962428927,0.6757543683,-0.6153737903,2.5128779411,0.1799121350,1.3834085464,0.5711925626,0.9366635680,-0.7422040701,-0.5731911659,-1.0898987055,-1.5423468351,-0.4778312743,1.5007041693,-0.7780981064,0.2048971504,-0.5669568777,0.3746558130,-0.4002239704,0.6586911678,-0.3613056540,-0.9264248013,-1.0720075369,1.2189369202,-0.3600791097,-0.7939486504,-1.1968816519,-0.6835036874,-0.2224785089,-0.8625183702,1.2658147812,2.2403526306,0.8670475483,-0.9484440684,0.6970045567,-2.1961770058,-1.6428921223,1.0440677404,2.1168622971,-0.0151213622,-2.2564005852,-0.6929907799,0.2016869783,2.4280624390,-0.0699802339,-0.5621324182,-0.7554766536,-0.6078110337,0.8083912134,-0.8453896642,2.1699969769,-2.6128845215,-0.0212052483,0.4015052915,-0.5356868505,0.9977837801,0.1122059673,0.0778343603,1.3476768732,0.2835381627,-0.0142331179,-2.0367105007,-0.7371923923,-1.2246629000,2.2353093624,-0.7961319685,-1.9554548264,-1.2512631416,-1.0218428373,1.2124526501,1.1355682611,0.6193997264,0.2487773597,-0.2672690749,-0.4545343220,0.7911229730,-0.3282171786,-0.1699972153,-0.6668633223,-0.4596285522,1.5497270823,-0.0206197053,-1.1669906378,0.6233358383,0.7453544140,-0.4479801953,1.0420253277,0.1992836148,0.5260112286,-0.7913386822,0.5561696887,0.9695681930,0.4419442713,-0.2964356244,0.1331102252,1.4653676748,-0.4023957253,-1.9205198288,-0.1914123297,0.5629822612,0.4740603566,-1.2222735882,0.2560369074,1.1243366003,0.3371331096,1.7473640442,-0.4876609147,1.2396174669,-1.2924531698,-0.8329555988,0.8106189370,-0.3956554234,-0.5539463758,-0.2932499051,1.0425081253,-0.3843310177,-0.2666507065,-1.8152126074,-0.6074080467,-0.0640053749,0.3151269555,0.6183727980,-1.3044564724,0.8262851834,0.3810087442,1.1846222878,0.3196219802,-1.6368120909,-1.0149875879,0.5286067128,0.2212347835,-1.3540037870,-0.2165237516,-0.0980249420,-0.1607593447,0.6369425654,-0.1619250774,-0.5857174993,2.6423957348,0.9990339279,-0.3168399930,0.3381016850,-0.3765596449,-0.3019950092,-1.2485268116,0.0268364325,-0.4783943295,0.1249814257,-0.4447103739,1.1281132698,-1.7312458754,-1.7791578770,-0.5942288041,-0.5394236445,-0.3606801033,0.0106915636,-0.0157427508,-0.8622555733,-0.0226995777,-0.0577265061,-0.1762067825,0.2407553047,-1.0976681709,-1.3848628998,-1.8822962046,-0.0017791095,-0.5731220245,1.9252378941,-0.4404511452,-0.4575495124,-1.0234162807,-1.6612168550,2.4114139080,0.2933978736,1.0817257166,1.0481520891,0.3456228673,0.0791619942,1.0115976334,3.3180394173,-1.0060584545,-1.0057104826,2.2909924984,-1.4247964621,0.7731633782,2.4017169476,-2.6709401608,0.1828530282,0.2281860262,0.2734143734,2.3842585087,0.7326384783,1.1197537184,-1.3578523397,0.9588159919,-1.0450409651,0.7155377865,0.1096529886,1.2337069511,-0.2804929018,-1.8858106136,0.3575464189,-0.0844301283,-0.8718315363,-0.9173175097,-0.6598443389,1.4191524982,-1.0103415251,1.1741003990,1.8414045572,-0.3743493259,1.0813381672,0.4680810869,-1.5805219412,1.5340808630,0.7638397813,2.2288279533,0.1072080508,-0.7255489826,1.1193445921,0.1728860289,-0.6225542426,1.1737477779,0.5976502299,-1.7421793938,0.2293184102,0.8057854772,-1.6511553526,0.4416771233,0.3466319740,-0.0454043299,-0.1209124625,1.6247614622,-0.7286786437,0.5841590762,-0.1831379086,0.5785822272,-0.4785403013,0.9208111167,0.3044312298,-1.4587692022,-0.1678542942,-0.6752638817,-0.2496262640,-1.6186631918,0.7310032845,-0.4667387307,0.0839912370,0.0778162628,-0.8575924635,-0.2125936151,-0.6107373238,-1.1801326275,0.6009773612,-1.1573953629,0.7150562406,-1.4650510550,1.7268512249,-1.0357637405,-0.4485883117,-1.4579374790,0.8677504659,-1.4565110207,1.5130494833,1.5456116199,0.0075432993,0.0928202122,-0.4449352622,-1.2877678871,0.8085286021,-1.3784750700,-0.0561535470,-0.4697008133,1.3949416876,-0.4398849010,-1.9523414373,-1.8618255854,-0.4945134521,-2.0245842934,-0.7269943357,-1.2706829309,-0.8815476298,-2.0346591473,-1.1727267504,-0.7687079906,-1.7004654408,-0.2370119691,0.4915896654,-0.7950913310,2.6508188248,0.6726636887,-0.4534219801,1.8084821701,1.0631934404,-0.7404429317,0.1299059689,0.2656057477,0.7115128636,-0.0633414313,-0.6535018086,0.7916250825,0.3691915274,0.0040150597,-0.6620145440,0.2596068382,0.4594883025,-0.5084525347,-2.4214904308,-0.9198400378,0.5192216039,0.4900861979,0.8938479424,1.7531205416,0.2292024791,0.2872477174,2.1692998409,-1.0889079571,0.8446975350,0.0144895865,-0.4923832715,0.2821266651,-0.1231191456,1.4335643053,-0.2643232346,0.8737241626,0.9721201062,-1.1100924015,-1.3487612009,-0.2477868050,-1.1834433079,-1.2005623579,1.0191519260,0.7395281792,1.1104048491,-0.0219590571,2.0232183933,0.5489047766,-0.0274477396,-0.7132084966,0.2385355234,-1.7889448404,0.7535198927,-1.0275415182,0.0347306617,1.3003791571,-0.1093231812,-1.3040199280,-0.2029657960,0.5065885186,2.0733292103,1.3696361780,0.9754089713,-2.0454306602,-0.0382960923,-0.5714712143,0.2167275846,0.6750763059,-0.3483577669,-0.7746589780,0.6165201664,1.3618383408,1.2122330666,1.3800063133,0.5365054607,-1.9177306890,-0.5251973271,-1.0988540649,0.0278137494,-0.7636909485,0.6048128009,-1.1625010967,-0.7021710277,-0.6840939522,-0.2839722633,-0.9208801985,-0.3885153234,-0.9178700447,1.5394451618,1.4378056526,-1.4322452545,1.8636082411,0.4008088708,-0.4350753725,-1.1601147652,-1.1638344526,-0.0322148390,0.4595857859,0.9118782878,-1.5388293266,0.6242665052,-1.0804662704,1.2000719309,-0.1710569859,-1.0350323915,0.4459679723,-0.1440854073,1.3036524057,-1.7022899389,-0.9515473843,-0.6042004228,-0.5069737434,-0.2445824593,-0.6166288257,-0.1103350669,0.0383932628,0.3011859059,-0.5186234117,-1.4050905704,-0.3328391314,1.2396959066,1.4162265062,-0.3398074210,-0.1771123707,-1.0423727036,0.9640633464,-0.4511846006,0.9080410600,0.5163629055,0.9133321047,0.2308627367,0.9364045858,0.4994279742,-0.9036644697,-1.0831034184,-0.4359258115,0.0862119645,-0.6307891011,-0.0972120389,1.4832203388,-0.3554448485,0.2293844819,0.7009916902,-1.2562806606,-1.1880155802,0.8979741931,1.0003473759,0.8966107965,-0.1492953151,-0.1308869272,0.2263855487,-0.0130055640,0.4222289026,0.4016860127,-0.4904920459,0.7437108755,1.9387946129,1.6307559013,-0.5204173326,0.3517319560,0.0115969433,-1.4235920906,-0.4553895593,-0.1439766139,0.7038559318,-0.2786969543,1.5749616623,-0.0669014901,-0.8004282713,-0.7990862727,-0.4329472184,0.2307552397,1.6242434978,0.5721014142,-0.7301663756,-1.3531529903,-0.8805804253,3.4693908691,-1.3049875498,-0.4333794713,-0.2324779332,-0.7562892437,-0.0847490132,0.1238018200,2.0294234753,1.1775977612,-0.7600325942,-2.2919991016,-1.6500588655,-0.9651675224,-0.0731742159,-1.8575273752,-1.3492054939,-0.1087381393,-2.6830763817,-1.9446489811,-1.1404054165,-0.3651441932,-0.5104267001,0.8189151287,0.6377196312,0.5000778437,1.4043917656,0.2186368108,0.5616023540,-0.7406401038,0.7284206152,-1.1032539606,-0.1957814097,0.6142774224,-0.1744652241,-0.8923316598,0.5519254804,0.0332063623,-0.6735925674,-1.1467906237,0.5041069388,-0.0882616341,0.5556857586,1.6077281237,-1.5892181396,3.5689439774,-0.5289149880,-1.3064787388,0.1786384881,-1.1435884237,0.4807915092,-0.4079792202,0.0394755080,-0.6162922978,-0.6694833636,0.8787062168,-0.8178895116,2.6429357529,1.2247593403,0.0740591511,0.5969020724,0.4470560551,-1.7656972408,-0.9531686306,0.6847508550,-0.7460402250,-0.0438507125,1.1078300476,1.3620145321,0.3313216567,1.3880150318,0.4393956661,0.8094944358,0.4581452608,0.4303210080,-0.1151056662,-0.8882232308,1.1301658154,1.4888341427,-0.5208579302,-0.5673535466,0.0692926571,0.2035409361,0.4037210345,-0.4218095243,1.1342378855,-0.4237312078,-0.3344818950,-0.0618350804,-1.1918430328,-1.4559003115,-1.0172894001,-0.8198907971,-1.1291286945,-1.2913620472,1.1161898375,0.9469137788,1.3321481943,0.6899978518,0.6809046268,0.2032615840,0.0857793987,0.1699928343,-0.1400194466,0.4252460599,0.1930265427,-0.6893171668,-0.0112007195,0.5478432178,-1.6128880978,0.5252740979,1.9394230843,0.2731349170,-1.6321368217,1.1112415791,-0.9279717803,0.1051486731,-2.1612613201,0.8048269153,-2.2167458534,0.2070944011,0.3835910261,1.3284368515,0.1795494854,0.3918175399,-1.3203768730,-1.4642324448,0.3817415237,0.5377549529,-0.2622683346,0.6836646795,0.3972084820,-0.4240120351,0.0491578691,0.1181937605,-0.7205049396,1.6013940573,0.1794056743,-0.3333885372,0.8673188090,0.7273941040,-1.3895088434,0.8160765767,1.0607300997,2.6599748135,-1.0260976553,-0.4237062633,0.6025332212,-0.3183956444,-1.0793176889,1.1519999504,-0.4337845445,-0.2645676732,-1.4520622492,0.3616208136,-0.7904537320,1.5489475727,0.0706833676,-0.7320204973,0.5462500453,0.9109166861,-0.2380175889,0.8746619821,-0.5622177124,-0.7081284523,0.1509067416,-0.9439134002,-1.5680643320,2.3613348007,-0.4723900259,0.2858115435,-1.2789443731,0.4329091311,-2.0931222439,-0.1401796043,1.3160349131,-0.5561891794,2.8609473705,-0.9401915073,-1.1080731153,0.3751921356,1.6322127581,0.6731638312,0.0600589253,0.4372738302,0.4696765244,0.9339655042,-1.3887944221,-0.2863088250,0.7338685989,-0.1506843418,2.5223164558,0.8215770125,-0.2824140787,-0.1048718765,0.8483038545,-0.8062709570,-0.2444159091,1.4299122095,-2.1488876343,0.4855590165,0.7521313429,-0.0362242311,0.9838863015,-0.9353536963,0.0884423181,2.2920429707,-0.1700564772,0.2196080536,-0.7678773999,0.1562586427,-1.7027182579,0.6213787794,-0.9202602506,0.6407473683,-0.1986954063,0.6446263194,-1.6563129425,-1.0442481041,1.4251111746,0.0319977812,-1.0316035748,1.1146814823,0.9316073656,0.4386779368,0.3499840796,-0.3451722562,0.1396140605,0.6647171974,0.8718655705,-1.3025929928,-2.4178709984,-0.2907205820,0.3312182128,-1.2822395563,-0.1600407064,-0.1754976213,0.9503936768,-0.2703380287,-0.1025897637,-0.9934663773,0.0249258950,1.2744728327,-0.8118573427,1.1149960756,0.1397129893,-0.7670947313,-0.6668843031,1.3282564878,0.5447962880,0.5307455659,1.3833870888,-0.0055647413,1.0632278919,-0.5771430731,-1.2756719589,0.1890316457,2.1345887184,-0.8619757295,-1.0646456480,-0.5164789557,0.5170358419,-0.2600931823,-0.4217748642,-0.4166208506,-1.8200933933,0.1230064183,-0.0741620585,-1.4303330183,-0.4159705937,0.3553825617,-1.4155803919,1.0580601692,-0.1156407297,0.5948669910,2.3360552788,0.2601666749,-0.0094588660,-0.9592040777,0.6389791965,-2.1392457485,-0.7021299601,-0.5663596988,-0.7259340286,2.0994577408,-2.1976509094,1.4211015701,1.4037487507,-0.5544083118,0.4942214787,-1.3881099224,0.5758545995,0.5089108348,0.7930374742,-0.9582809210,0.7822327614,1.4710839987,-1.6592271328,0.6535981297,0.3041735291,1.0828449726,0.4052551985,1.3086524010,-1.1172833443,-0.6074464321,0.3001531959,-1.0475873947,-1.2174046040,0.0880611092,-0.3901859820,-1.6000955105,1.0908169746,-1.0064556599,-0.0125739658,1.0592347383,0.4535114467,0.9690465331,-0.9640182257,-0.8309549093,-0.0977261811,0.3498162031,0.6293475628,-0.2722138464,-3.0948634148,0.9942316413,0.7735679746,-0.2930199504,0.3510787189,-0.7872864008,0.3636801541,-1.6712719202,-0.5944473147,-0.7780117393,-0.0843283460,-1.4538215399,1.6016918421,-0.7877728939,-0.3877354562,-0.1187206879,-0.0575074181,0.7608479857,-0.7298144102,-0.8270982504,1.1454995871,0.9177365899,2.6103880405,0.0275212266,0.3144996762,-0.1462692618,-0.9897634387,-0.5029512048,0.6674743891,2.3210890293,1.0447092056,-0.4356173873,0.7188963890,0.3660807908,-1.3855001926,0.8256156445,-2.0150454044,1.1064456701,-0.6010576487,1.2496664524,0.1507250816,0.6486197710,1.2184954882,-0.1510147303,2.0641293526,-1.4498168230,-2.0317718983,1.2131361961,0.8736751676,0.1112035960,0.0250869896,-0.3772203326,-1.6222440004,-0.5841495395,-0.4699107707,-1.3665386438,-0.2026459277,1.0634649992,-1.0488432646,0.2799955606,0.5228345394,0.5676972270,-0.7177141905,0.8343642950,-1.1448087692,0.4393841922,0.5103766918,1.5104135275,0.0295173712,-0.8243343830,-0.7828230262,-0.6596770883,0.6153479815,-0.2708790898,-1.9587074518,-0.3796555698,0.2415509522,0.5919256806,-1.1046775579,0.1845662445,0.2122246623,0.6119584441,-0.3259581625,-0.3889915943,-0.7639250755,0.6078098416,-0.0667440817,-0.3067077100,0.5324385166,-0.4453656077,-1.1343411207,-0.5743299723,-0.2151301205,-0.2456267476,1.0301148891,0.4816589355,0.2701259255,0.0924869999,-0.7086822987,0.3224029541,-0.8674822450,0.1477069706,-1.4585555792,-0.7812615037,0.7472718358,-0.2691109478,-0.2376997769,-1.3751879930,1.0826475620,-0.4113312662,0.2539284527,-0.1638429761,1.3389561176,-1.0764062405,0.5501658320,0.7915554047,1.5759218931,-0.6999486089,2.9310317039,0.1950336695,0.4499127269,-0.5996899605,1.4481815100,1.6616878510,1.1369335651,0.2755799592,-0.4852996469,1.3345595598,0.3228714168,-1.3306968212,-0.4727328718,-0.6471650004,-1.1132016182,-0.0713217631,0.3562543690,-0.3879558742,-0.8892503381,-1.2379481792,0.8939266205,0.3848524690,-0.0012620862,-1.1376874447,0.5002755523,-3.1173944473,-0.3279280066,-0.8613476753,-0.2599486709,-0.5934633017,-0.5903510451,0.8368667364,1.4305448532,-1.0941609144,-1.2185326815,1.2903679609,-0.1296792477,-0.4799862504,-0.5509805679,0.4149641097,-1.7689479589,-1.5645645857,0.7041118741,1.1712943316,-1.5331878662,1.7426551580,-0.9360130429,-0.0077561252,1.1543563604,-0.4171964824,0.8241519928,-0.5553875566,-0.1821218431,0.5545003414,-0.9405351281,-0.7519527078,-0.1459754258,-1.1258925200,-0.0645399243,-0.0919869691,0.4392310381,-0.3822971284,0.9538373351,2.5823388100,-0.0202496629,-1.1847659349,-1.6862163544,-0.3795819581,-0.3198311329,0.2588284314,1.2887588739,-0.1577174366,0.3362316787,-0.3093566597,2.0915386677,-0.1336469650,-0.7076271772,-0.2241379768,-0.9879319668,0.3666142523,0.5691226721,0.8202407360,-1.7439919710,-0.5116857886,-2.3288261890,0.0181529243,-0.2852157354,-0.6766232252,-0.6026852131,-0.2991698682,-1.4322966337,0.4033516049,0.4984943569,-0.6238273978,0.6512020230,-0.1294459999,-0.2563645840,-0.0850734860,-1.6635020971,0.1540960521,-1.0692788363,1.2856413126,1.3886764050,1.2394807339,-0.3786866367,0.0405688733,0.0261330679,0.7440382838,1.1676402092,0.9192047715,0.3690302074,0.6918146610,1.0192283392,-1.1002117395,1.5993460417,0.0842537582,-0.2882339954,-1.6641160250,-0.2254856080,0.2086762488,0.1024906188,1.9029095173,-0.1601699591,-0.1618199199,0.0761273950,0.7380160093,-1.0263552666,1.2613258362,0.7727131248,-1.4276200533,0.2427285612,0.9233678579,-0.6908003688,1.1374328136,-1.5583342314,0.3230153918,0.5732840896,0.5374802351,0.0478959084,0.6080489159,1.9260646105,-0.1249577850,1.1183328629,-0.2025958151,0.9080084562,-2.0576729774,-1.0507560968,-1.0327750444,-0.2893113196,-0.5023987293,0.6811234355,-1.2514544725,0.3200329244,-1.2652056217,0.3359721005,-0.0252995491,-0.7358947992,1.0601046085,1.8516906500,0.8605123758,-0.3745788634,0.5313572884,-0.7876136899,-0.6817808747,-1.7882242203,0.7149001956,-0.8047255874,-0.2163498551,-2.7289826870,0.0985979512,0.5790400505,0.2990364432,-0.3108656704,0.4906449318,-0.0220372509,0.3153430820,-0.6366631985,0.5582022667,-0.0725143254,1.6017705202,0.3281800449,0.0548433438,-0.6032658815,-0.0313083753,-0.6846083999,0.8272629976,0.3764564991,1.2219976187,0.3424511850,-1.9520853758,0.5699878931,-0.2838295102,-1.2962739468,-0.3520423770,-0.0343406647,-1.7270351648,-1.5421413183,0.1779328436,-0.9161617756,-0.4136451185,1.1171588898,-0.4643569887,-2.5890705585,-0.0978169665,0.7960562706,-0.8719828725,-0.5912626386,0.6984806061,-0.5227940679,0.4376514256,-1.0884710550,-0.2189821005,-0.1773026586,-0.2215059102,-0.3727942407,-1.6285271645,-0.9006853700,0.0758861899,0.5086434484,0.3348540664,-1.3667118549,1.2991203070,-0.4577853084,0.2003161907,-0.0515099727,-0.8061420918,1.6344506741,0.0430850051,0.3335125148,0.4028064907,-0.2435404509,1.1255035400,-0.3624939919,1.3392149210,-1.1797457933,0.3497534692,1.7610549927,1.1116669178,-0.1403288543,0.5325508118,-0.4736567140,-1.1872699261,-0.8908538818,0.5292066336,-0.6279459596,1.1363736391,0.0741886124,-0.0612685420,1.8719406128,-0.7305373549,-0.7488399744,1.4618368149,1.0680894852,-0.5133447647,0.3789470494,0.6920509338,-0.0438605398,0.6057320237,2.3371551037,1.6273084879,0.4970181286,0.1759300977,-0.4805933237,2.0895617008,0.2881127298,0.1409717500,-0.9227795601,0.2344621420,0.1607084423,-1.3211661577,0.2385593355,-0.5965131521,-1.2087808847,0.2794382572,0.1888812184,1.9271669388,-0.6863006949,-0.7454478145,1.3094059229,0.0873842910,-1.5320618153,0.5683317780,-1.1412267685,-0.0090721669,0.4966467023,-0.9476978183,0.3827875555,-0.1609680057,0.6752560735,-0.7131679058,1.4439325333,0.8276761770,0.4239243269,0.0850653648,0.4328988194,-0.4906337261,0.0462160818,-0.0169979334,0.7315130830,-2.4731819630,-0.3385759592,0.8918678761,-0.3003723025,1.4887953997,-0.5745051503,0.1477561146,0.9416487217,-3.4703557491,-0.5359448791,0.7355026603,1.0419493914,0.2170319855,-1.0533621311,-1.3572306633,0.2210417986,-0.2556262016,0.8509920835,1.1125905514,1.2063499689,1.5522272587,-1.2215622663,-1.2061839104,-1.2950669527,0.2025153190,0.8298991323,-1.6604008675,0.6038448215,-1.3068019152,-0.0830953941,-0.1207791269,0.1019082442,-0.4354915023,1.0499731302,2.1721775532,0.8277935386,-0.8255026937,-0.3824424446,-0.6085035801,0.4934102297,-0.3934786618,-0.3122988045,-0.6388264894,-0.4257539213,0.1983288080,0.1787884980,-0.6914410591,0.3757758439,0.3676111102,0.0018327866,-0.3925342262,0.0072206180,-0.7803044915,0.7397019863,-0.3460148573,0.6108574271,-0.1799765527,-0.5952509642,1.7402403355,1.2058306932,-1.7820718288,-0.4921284318,-0.1624327749,-0.4435231984,-0.9929452538,-0.2207475901,0.9404109120,0.5551370382,-0.2299775779,-1.3604174852,0.6192497611,-0.1024679542,1.5234620571,-1.3118313551,-0.4637701213,-0.3026833534,-0.6559758782,0.7063180208,-0.1408954412,-0.2510201633,0.9387018085,-1.2084950209,0.9204330444,1.0249712467,-1.1086518764,-0.6219455600,1.0969376564,-0.9379596114,-0.8758180141,0.6695581079,0.4155954719,0.1114221439,-1.5905003548,-0.6057395339,1.1781516075,0.5552685857,0.0532497801,-0.8565030098,-0.0965542048,0.4256413877,0.5131956935,0.7127240300,-0.9340515137,-0.2032660544,-0.7067037225,0.8651694655,0.4279882610,0.0549685322,-0.3155857027,0.9081064463,-0.7040295601,0.5488665700,-0.7164933681,0.6457732320,-1.0947531462,0.5694273710,0.2458718419,-0.9906666875,0.2122940868,-0.1173533797,-0.4974184334,-0.6052320004,-1.2996211052,1.6052107811,0.0167007670,-0.8896363974,-0.1235675514,1.2180057764,-1.2930305004,-0.0934745148,-0.8663709760,0.5964619517,0.0963961259,0.7674152851,0.8012778759,0.5961014032,1.0097689629,-0.7147139311,-0.8749305010,-0.6941998005,0.9761347175,-0.4838216305,0.8083631992,0.0955365077,-0.7880268097,-0.0426202081,1.8439741135,0.4282551110,-0.0741682723,1.0584558249,-0.6867261529,0.8829703331,0.5617801547,0.3434916139,0.8344439864,0.4797274470,-0.3557169139,-0.3400082290,-1.2465457916,-0.0580307133,0.3834264576,-0.2598493397,0.3235251904,1.4750258923,1.1747642756,0.3843635023,-0.6985956430,1.5027586222,1.4956634045,0.8067368865,0.1969479024,0.0862167776,2.6182115078,1.2178329229,0.4351801872,-0.2157924771,0.0267683528,-0.2018048316,-0.2664071023,2.3273704052,-0.2287864387,-1.2879660130,-0.2599785924,-0.9273023009,0.5641449690,0.7914847732,0.9565588236,-0.8911844492,-0.0868590698,0.8247932792,1.1331245899,-0.7190009356,-0.5144978166,-0.2154463977,0.4985496998,0.9098943472,-0.2854295969,1.0122947693,-1.0168125629,-1.7378758192,1.9295582771,0.2372324765,1.4199649096,-1.4571065903,0.9987430573,1.4982053041,-0.1646643132,-1.0409728289,0.2996204197,-0.3438556194,0.1763267219,-1.2381007671,-0.5269424915,1.0394705534,-0.5188234448,-2.2872128487,-0.8193461299,0.7512777448,0.5032290816,-0.2287727147,0.0983647630,-1.3239839077,-0.3555992246,0.3286261261,0.3280561864,-0.0815626234,-1.0128548145,-0.6927438974,0.8964392543,0.8159549236,-0.3390179276,-0.3015466630,-1.4631524086,0.4497293830,1.3367420435,0.3859525323,0.7919450402,-0.7560143471,-0.4574146271,-1.0860054493,-2.2208795547,-1.6294802427,-0.0413829871,-0.2428517640,-0.4857134819,-1.1662257910,-0.9579188824,0.7621256113,1.3296331167,0.3138369620,-0.4716928005,0.6125260592,0.3406782746,0.0522802398,1.0202609301,-0.0340798423,-0.9259276390,-1.2390106916,-1.5818425417,1.1560853720,1.0905010700,0.7594812512,-0.5976432562,-1.1142151356,1.5844764709,-0.3622460365,-0.1226565912,-1.9871875048,1.4768576622,0.2379653603,-0.9133228064,-0.7880818844,0.9237326980,1.8276497126,0.7280939817,-0.5917063951,1.3107105494,0.7642640471,0.8204598427,0.5962021351,-0.3783559799,-0.4161889851,-1.4495459795,0.0745454207,-1.3453316689,0.9977020025,-0.4342275560,1.0422127247,1.1708983183,0.4311306477,-0.6837021112,2.1621861458,-0.5827428102,0.4477067292,-0.0211558007,0.1824309528,0.4264740944,0.1203467995,0.9909948707,-0.1859768480,-1.0240132809,-0.3639334142,-0.0936418921,1.0512423515,0.3733913898,0.6839901805,-1.9282292128,0.5622627139,-1.2091028690,-0.1106549725,-1.2581288815,0.8361244202,-1.1004523039,-0.1258943379,-1.5989625454,1.8102275133,0.4441590011,-0.5214574933,0.9797497988,1.2888114452,-0.8276115656,-0.0220992491,2.4498775005,-1.8377934694,-0.8514962792,0.9489679933,-0.0830500126,-0.0359301940,-0.1420495808,1.0556294918,-0.5497905612,1.0126923323,-0.7473862171,0.4052971900,-1.0751425028,0.1719949245,0.3107260466,0.4252511263,1.0308989286,2.1891362667,-0.7951731682,-0.9288254380,-0.8406194448,-0.5870738029,1.4166525602,-0.0508782193,-0.5263801217,1.7727472782,0.1618817300,-1.6156774759,0.9979695082,-1.5955677032,-0.1549735814,1.2778108120,1.1898374557,1.2261581421,0.1232592538,-0.4701025486,0.8268409967,1.4406825304,2.0723600388,0.6214050651,0.1583388299,1.0687154531,1.2600852251,-1.7723824978,1.7461088896,1.7796293497,0.1533010453,-0.4502541423,2.8840515614,-0.0278098118,0.2774529457,1.2356098890,0.9059458971,1.3719466925,-0.1427477598,-1.5313657522,-0.1988708526,0.0918548554,-0.7983700037,-0.7351155877,0.0807933062,-1.1822363138,0.4204095602,1.6773831844,-0.6493386626,-1.3810855150,1.8829346895,2.2381758690,-0.3106609285,0.1599945575,0.5009009242,0.2571044564,-0.2493799925,1.4916465282,-0.0642954409,0.1002008095,0.0911449566,-0.2840108871,0.0648470521,-0.5927429795,0.6111506224,0.2633831203,0.6087102294,-0.1314200610,-1.9108045101,0.3572774529,-0.2191513479,0.4376700521,1.1833018064,-0.8609423637,-1.1047463417,-1.0791573524,0.6086138487,2.6700644493,-0.7331061959,-0.4262737930,-0.6036394238,-0.7591724992,2.0492615700,-0.4318020344,-0.4356160462,0.4063673317,-0.0951606557,0.1538648903,-0.7921331525,-0.5645645261,0.6250701547,0.2017248124,1.6619211435,-0.0490566455,0.8955783844,1.0819174051,-0.8749611974,-0.5747096539,-1.3129776716,-0.8326802254,-0.5609090924,1.6952314377,1.0350174904,1.0616799593,0.9478091002,1.2279448509,-0.0191568751,-0.1780776232,-0.5881857872,-1.0479393005,0.2833366990,1.5692890882,0.0149694970,-1.1679285765,0.6675914526,0.2725379169,0.5069898963,-0.8566572666,0.2730761468,0.7228215337,-0.7045961022,-0.8416188359,0.4508380890,0.1944348961,-0.4541225731,0.7563244104,-0.1131819710,0.7128592134,1.4402623177,0.1528645456,1.0313960314,0.6298319697,1.2467131615,-1.1085821390,-0.9003415704,-1.4343361855,1.0231429338,0.0072061568,-1.8835331202,-0.7989682555,1.0520348549,0.3447473049,-2.5748610497,1.6703809500,0.0138393026,1.1409097910,-1.1738827229,0.7495995164,0.5710754991,-1.0748022795,-0.6461317539,-0.2453123629,1.1448947191,0.8853188753,0.7727425098,-0.0282142591,-0.1457471848,2.4659855366,-0.7119729519,-0.1440470964,0.3802301586,0.0594930463,-0.7933204770,-1.5470353365,0.9903058410,-1.0986013412,1.3785964251,-0.6182013750,-0.2940633595,-1.6926203966,1.8205765486,-0.0862483159,1.7647430897,-0.7206363082,-1.1045497656,-1.6156738997,-1.0962505341,2.8444337845,0.5576008558,1.6882987022,-1.1970424652,0.4513413310,0.9049255848,0.2253855616,-0.6835092306,1.8480138779,-1.3671431541,-1.0080400705,-0.9925702810,1.2446583509,-0.5805303454,-0.1164868474,-0.5888524652,0.2782382667,-1.0922057629,0.9598587155,-1.0899872780,-0.7082154155,0.3065707684,-1.5383666754,2.1593325138,-0.5230810642,1.0688405037,0.5502248406,0.2891297638,0.3945007026,-0.7157661915,-1.4161725044,0.5869718194,0.1101675332,-0.9291577339,0.9818926454,-0.2781111300,-1.0967657566,0.1139538214,1.1031048298,1.0086518526,0.6278707981,-0.1493199915,-0.4495257139,0.2201409191,0.4300591052,1.2368929386,0.6283149719,2.0061483383,0.7451803088,-0.2425652146,-0.2525975406,1.1054331064,-0.5970991254,0.9908251166,0.4830693007,-2.2409613132,-0.8885762095,-0.0143143935,1.0882319212,0.2041956186,-0.9607824087,-1.1832842827,-0.3721539676,-0.3367851079,0.2151497006,0.0878699198,-0.6686208844,-0.3243316412,-0.5673260689,0.2042728662,-0.0433752351,-1.7372738123,-1.4927453995,0.2947275341,1.8073326349,-2.2004306316,-0.1771846712,0.5147547126,1.0263893604,-0.3667627871,-0.3732538819,-0.8672274947,-1.5185539722,0.1291330457,-2.3146927357,-0.0381119587,-0.6768706441,-1.1104094982,0.1284427047,0.5935358405,-1.7596523762,1.6137292385,1.4737104177,-0.3111882508,-1.1401060820,1.3278982639,-0.7087484002,-0.5006707311,0.9336168766,-1.2285281420,1.1852614880,-0.6464233398,0.3168686628,1.0129629374,-0.9842917323,-0.8322681189,0.3770053089,0.4055832326,-0.7535272837,-0.5763852000,1.2844207287,0.2033589929,1.0656037331,-2.3893010616,0.2218722403,0.5269311070,-0.5230823159,0.2871558368,-0.6817102432,1.0522680283,-2.2263123989,-1.4442704916,-1.7066681385,-2.1534831524,-1.1033091545,0.5186153054,0.9830374122,-1.4134610891,0.7257140875,-0.3652280867,-0.8273479342,-0.0123440940,-0.7055724263,-0.0065825772,-1.4281263351,1.0454120636,2.1973111629,2.1394906044,-0.2185653597,-0.7726922631,0.0578657836,-0.1241003796,1.3615926504,-0.4700821936,0.6276119947,0.7610633373,-0.3084032834,-1.5049169064,1.1694749594,-0.3002104461,-1.7592983246,-0.7689751983,-0.6482440233,-1.3943746090,-0.6685357690,-0.2740963697,-0.1009262577,1.3430944681,-0.9573187232,-0.4756442606,-0.1120443791,0.4514842033,-0.1808938533,0.0360276587,0.7046375275,0.5217391253,0.1769850850,-0.3516299427,-2.1484513283,1.0110119581,-2.1996293068,0.8975638151,-1.2163029909,-1.0508220196,0.6954064369,-1.2345478535,0.6365551353,-0.1546197087,0.5181404352,-1.8113756180,-0.5626225471,-1.3982005119,-0.4505920410,-0.2327025235,-0.0388276242,1.5718796253,-1.1048280001,-0.1993524432,0.4389081597,0.7646227479,-0.5730227828,-0.5616265535,-0.3296748400,-0.7627649307,1.8219025135,1.0186827183,-0.7380231023,-0.8434823751,-0.6264718771,0.7264119387,-0.5833688974,-1.6604254246,0.0730206072,-2.4509689808,-0.5503947735,0.6281988621,0.3269348443,0.0925165340,-0.4955527484,-0.2733169198,-0.5889083147,1.7769594193,-1.1998845339,-1.7700980902,-0.8073721528,0.0494673774,-0.8524341583,-3.2187163830,0.5676971078,-2.2943770885,-0.1579331160,-0.7956486940,2.0401656628,-0.1461989731,2.1896297932,1.5324863195,-0.5835031867,-1.5549209118,-0.4209410548,-0.0279977787,-0.0782606602,-0.7426626682,0.0121981045,-1.5553230047,0.5819070339,0.0326453373,0.6056950092,-0.4712967277,0.4049454927,-2.1062376499,-1.1619187593,-1.2910219431,-0.6611953378,-0.4365321100,1.7293006182,0.4786488712,-0.2935953736,-0.4926992655,0.7536605597,-0.3894644082,-0.7081032395,1.0595657825,-1.0791609287,-2.6619422436,-1.6152977943,-1.1396865845,-1.2950086594,-1.2873415947,-0.1941757053,0.5377328396,0.8336847425,1.3057926893,0.7935741544,-1.1920603514,-1.2580881119,-0.1752467602,1.4270538092,0.3531105220,-0.2798886299,0.2382898629,0.5952281952,-1.3373407125,-1.5224821568,0.6214637756,1.1671440601,0.1557538509,-1.3565181494,1.1534074545,0.0552476197,0.8227424026,-0.2473755926,1.7100614309,-0.6010099053,0.0952295437,0.7519122362,0.6125386953,-0.1340970695,-0.2649757266,1.2478978634,1.3848875761,0.2351858020,-0.7321636677,-0.7952386737,0.4714525342,-0.7676478624,1.6104269028,1.1910309792,1.6014332771,0.8937367201,-0.5093985200,0.7270994186,0.1354524046,1.1415119171,-2.6321196556,-1.8495267630,-0.5692487955,-1.5690562725,-0.2997058034,0.9866194129,-0.0548178814,0.1174306124,-0.1186611429,-1.4897632599,-0.0651347712,1.4272356033,0.8654854298,0.3896121979,0.0904301852,0.0244684536,0.9569140673,0.5948505998,-0.6984776258,-0.2093743682,-0.1100684255,-0.4356186390,0.9230844378,-0.0802567452,1.0543168783,0.8095011711,-0.9505899549,1.5887154341,0.9821254015,-0.4611521661,-1.1893174648,1.1560828686,2.1422307491,-0.3830331862,0.2881630659,-1.0069626570,0.9505732656,-0.6370865703,-0.5005722046,-0.5218068361,0.0570890643,2.1391377449,-0.3942484856,-0.0125554344,-1.0029050112,-1.6481519938,-1.3115295172,-0.6975313425,1.4723504782,-0.5125975609,-0.7702323794,-0.0430547260,-0.0723921731,0.3706169128,0.9811360240,0.0741774514,-1.2132822275,-3.3102068901,0.2480957657,0.1500856727,-1.3044787645,-0.7662258148,-0.5189638138,-0.7032186985,2.0692028999,-0.4092837572,-1.9459711313,-1.0947782993,-0.8841983676,-0.0839635059,-0.8565853834,0.7222669721,1.4330573082,2.0029449463,0.6141778827,0.4747509956,-0.5246588588,-1.0898851156,1.2181375027,-0.7382065654,-1.0789153576,-0.4607920051,-1.2100571394,-1.8802586794,0.2697679102,-0.0484813824,-1.1286646128,-0.0754335970,-0.4993629456,-0.9535911083,-1.2571040392,-0.3249886036,-1.7524542809,0.1891974956,0.5681154728,-0.1350892484,-0.1838773489,-1.8538595438,2.1625046730,1.0804477930,0.8050185442,0.0583708286,-0.8403818011,0.4379777312,0.2320236266,-0.5907236934,0.5305605531,-0.2355878800,0.8831157684,-0.3832046986,0.1206885651,-0.2441270649,1.4652829170,0.1251680106,1.6854983568,-0.5830694437,-0.8190350533,1.2951843739,1.1042377949,2.4435899258,0.6359903216,1.0345590115,0.0918972865,1.2627774477,0.6608592868,-2.0900311470,0.3947992027,1.1637389660,-0.5153884292,-0.8478496671,1.4432096481,-1.4082688093,-0.2457654625,0.3125251830,0.4924857020,-0.0458401740,1.0880835056,2.3190202713,-1.3728237152,0.9819077253,1.4168225527,-0.8269272447,-3.1057460308,-0.2784600556,0.0084761279,1.1402667761,-0.1192869022,-1.1153726578,0.4603817463,-0.4175572991,0.5515987873,-0.8892507553,-0.9335702062,0.1421700418,0.8622007966,-0.1144793853,0.7831965089,-0.8715204000,-0.0539018773,0.7396158576,-0.2736086249,0.1636993736,-0.3604790866,0.6992456913,-0.4008758366,-0.5472824574,-1.3291764259,-1.1045629978,1.3297357559,-0.8264792562,-0.6032384038,0.1439969242,-1.2441627979,0.7882626057,0.2286830693,0.4731123149,1.1700091362,0.3139848411,-0.3568086028,0.3434693217,-0.7872848511,0.1237977520,-0.9416929483,0.4094843268,-2.0613017082,0.8186947703,0.2799305320,1.6776723862,-0.9916943312,-0.6852881312,0.8760497570,0.3148263097,0.6045241356,-0.8686185479,-0.6712832451,0.0449492224,0.1750403196,-2.0695581436,0.2488401681,-0.4023043811,-1.9713195562,0.9366938472,0.3973978460,-0.8258979321,0.2593599260,-0.4171347618,-2.0138168335,-0.2195019126,1.3088977337,-1.0805025101,-1.2335897684,1.7145081758,-0.7687286735,-1.5577871799,-0.7377884388,-1.0902771950,1.3249225616,-0.0432096124,-1.5101686716,-1.4007518291,-0.0030049440,0.5537450314,1.1865566969,-0.5845212936,1.2676486969,0.6573771834,0.4485799372,-1.3348814249,-0.2957971096,0.7416982651,-1.2257262468,1.2528117895,-1.4885023832,0.5322642922,-0.6019110680,-1.2413516045,0.3678843975,0.5308324695,-0.1434124857,-0.0195947830,-0.3229777813,0.5714412928,1.2527539730,-0.1473772079,-0.0419942997,0.0068792035,0.9574351311,-0.2035091221,-0.0903420448,-0.3691366613,-0.5072920918,-0.5398548245,-1.3546386957,-0.6282287240,0.5655155778,-0.5688884854,-1.9287480116,1.2996890545,-1.3261818886,0.2849215567,0.6106883883,-0.1060630158,-0.4809936285,0.0340173580,-0.9125748277,0.7783385515,-0.1310227066,1.2201029062,-0.3814059794,1.3374848366,-1.2288342714,-0.1551678479,1.0072926283,-0.6144304872,0.0839847699,-0.6462374330,-0.0756285638,0.7238970995,0.2455556691,-1.4122244120,-1.8843190670,0.2838617563,1.0761822462,0.2097860724,-2.2004213333,1.2754834890,-0.4360707998,0.8155106902,-0.0288391188,-1.7672243118,0.2476938218,1.0521885157,0.7191450000,-1.6686151028,0.0634164885,-0.3962253332,-0.9131394625,-0.3257185817,0.9493992329,-0.1860646755,0.4772316515,0.7308128476,-0.3646406233,-0.1680960655,-0.6723977923,1.8579225540,0.3541227877,1.3605973721,0.8575440645,-1.5376170874,1.1852170229,-0.8388038278,0.6530769467,-0.5707948208,0.1520410031,-0.5276001096,-0.6008660197,-0.7531970143,-0.1710914224,-0.0899885967,0.5186805725,1.0073469877,1.0555337667,-0.9564317465,1.0060201883,-0.3865070343,-0.2376815975,-0.2118640542,0.9394926429,0.6976744533,-0.2015943229,-0.9899131656,0.5405406356,0.8071326613,-2.0545885563,0.4489324391,-0.7159293890,0.7658372521,0.8533259034,-0.2951918840,0.5808369517,0.2168655097,-0.5482198596,0.3273206055,-1.5042330027,-0.4117659926,0.0382566266,1.1967242956,-0.8289934397,-0.5600231290,1.0414994955,-0.1932150424,0.0411262065,-0.4130541384,-2.0425164700,0.2735721767,-1.5550554991,-0.7226807475,0.7977443933,0.1485011876,0.9446786046,-0.4927309155,0.6173900962,-0.3243460059,1.2881433964,2.2453174591,-1.1089458466,0.6956653595,-0.9906356335,-0.0505813882,0.3978154063,-0.9886980057,-0.2622124255,0.0275835395,-0.3144522607,0.9326926470,-0.3414547145,0.4837387204,-0.2374359816,0.3685643673,-0.8963376880,0.6249161959,-0.2738130987,-1.0066910982,0.5856098533,-0.2894586325,-0.0821105018,-0.3100988269,-0.4248235822,0.2665741146,-1.7740272284,-0.1976617873,2.3445346355,-0.7961371541,0.3188365102,0.3922545314,-2.0804495811,-0.6469821334,0.7504340410,1.1765389442,0.9240966439,-0.3588912785,1.2186727524,1.1245067120,-1.7694383860,-1.4732788801,-0.2784310579,1.3830229044,0.1213222444,-1.1693680286,-0.7890093923,0.2241205424,0.0043442440,1.6878660917,-0.1504489183,-0.2639863193,-0.0475605465,0.4061010182,0.6480402946,0.9678143263,0.8842444420,-0.2457452416,0.9848177433,0.4075931609,-0.6050483584,-2.1982643604,-0.9470968246,0.6483018994,-0.9678875804,-1.0634075403,0.1625384986,1.2762326002,-0.8872547746,0.1652131081,0.5170665979,-0.0231691115,0.6141547561,0.3632443547,1.0437520742,-0.4099225700,-1.5331041813,-0.1598736197,-0.8773027062,1.1364567280,-1.7034946680,0.9508250356,0.0975447968,-0.6070606709,1.7351464033,0.4743512869,1.2093871832,1.2255852222,-1.2209358215,-2.1459023952,-0.5637799501,-1.3911374807,0.4593183398,0.5979510546,0.4527249634,-0.0445172526,-1.0204105377,0.6146193743,0.1513276845,-0.5046305060,1.2186865807,1.6874295473,1.6179510355,1.0376192331,-0.0943819210,2.2098233700,-0.5462614894,-0.8779112697,1.2222505808,1.2055162191,-1.5389888287,1.5902979374,-0.4417829216,1.7803531885,-0.5176959634,1.8613972664,0.7545554042,0.6129772067,0.4468424320,0.9953684211,-1.3956910372,2.0089464188,-0.4462093711,1.5784149170,0.3510382175,-0.0703873858,0.2534176111,-0.1998426467,-0.8111057281,0.3384461999,0.6583834887,0.8084661365,-0.9903705120,0.4196079671,0.3588507473,-0.5640988350,-0.1225297973,0.2798833847,2.6040446758,-1.2985949516,1.3740561008,-0.1327347904,-0.3478104770,0.6357547045,-0.8267017603,-0.0101069696,1.1574569941,-0.5891892910,-1.2464402914,-0.3473787606,0.3087954521,0.2835386992,-0.4206701517,0.2591592669,-1.2195488214,-0.1933093965,-0.5647271276,-0.8968281746,0.1931795776,1.3121608496,0.0971596316,0.9895777106,-0.4723748267,-0.5463014245,0.0892185643,-0.0195480473,1.8247439861,1.5372071266,0.0110428948,1.2742878199,-0.2674755454,-0.3730522692,-1.5067985058,0.4618104398,-0.1699099392,0.7135494947,0.6154643297,0.4335562885,-0.2648655772,-0.0513244420,0.5973302722,2.1014957428,0.2783280611,-0.5136555433,-0.7486355305,-1.0634144545,-0.5323330760,-1.5201735497,0.5931404233,0.4664847553,-1.2523989677,0.6027503610,0.0915953219,-1.3840013742,-0.8534832597,-0.3615029752,-2.4294033051,0.1112238094,0.0172027890,-0.2286780924,-0.8285278082,2.2321007252,1.9687647820,0.2778130472,0.5375308394,-0.8006395698,0.2198387384,-0.3095584214,0.8869483471,-2.8386275768,-0.9168944955,1.2239718437,-1.0722330809,-0.5158202052,0.6645996571,0.8560354114,0.1393965185,0.9551382661,0.4548152685,-1.9653131962,0.8772224784,-0.2593773305,-1.1952117682,-0.3621657491,0.0389585756,1.1604454517,-1.0822688341,0.5837280154,0.5754579306,-0.5814859867,-0.2461313754,0.0065278327,0.4200200737,-1.5244244337,-0.2629826665,1.3117327690,2.0171401501,-0.8675763011,0.2327602357,0.1637782604,0.4368565083,0.9518216848,-0.7166954875,-0.9328627586,0.8369590044,0.3547633886,0.1785100549,-0.0237964932,0.8859897852,-0.6042553782,-0.3762065172,-1.6474996805,-0.3082104325,1.0396336317,-1.5162066221,-0.9067734480,-1.0850670338,1.2581267357,-0.2214823216,-0.8220285177,0.4123277068,0.7663524747,-0.8339322209,0.6646717787,-1.0077667236,-0.5644736290,-0.9657685161,-0.0941603929,0.4566901326,0.3407334983,-0.7013095617,1.0366376638,-0.1873145849,-0.3645239472,-0.5983661413,-0.0358053558,0.9808912277,-0.3805266619,2.4766175747,0.9397842288,0.6496300101,0.0903372765,0.1319412291,-0.3573524952,0.7131528258,0.7749145627,1.8421769142,-1.1503663063,1.0779078007,2.4074707031,-1.2194875479,2.3397269249,-1.4365357161,0.4038117230,0.2114246339,-0.7000735402,1.7133610249,-1.6811267138,-1.3434336185,0.3275044262,-0.9965205193,0.6525971889,0.1109063923,0.5218975544,-0.2513494194,-0.1506602168,-1.0675710440,0.7060869336,-0.2939028740,0.7074757814,-0.1937825084,1.8526563644,-0.6828480363,0.1911466569,0.1817938238,-0.8393192887,-1.2712761164,-0.2967023253,-1.5580698252,1.0618728399,-0.7327790260,-0.0453399830,0.7231896520,0.2260579467,0.0045189788,-0.0292946324,-1.5553299189,0.3317606151,0.7949090004,0.6328572035,0.4006032944,2.1425490379,-0.6258561015,-1.3994067907,-0.5250332952,-0.5599845052,1.0373660326,0.8478179574,0.0953366831,-0.6932147741,-1.3818480968,1.0562552214,-0.4130301178,-0.1007573754,-0.6099736094,0.2333106846,0.9275327921,-0.7962839007,-0.6180340648,-1.5996370316,1.8704158068,0.8759252429,1.3884956837,2.4303166866,0.4895366132,1.3197805882,-0.1183772013,-0.1369920820,1.3485703468,0.6114919782,-0.0323543325,-0.6448656321,1.2038643360,1.1820948124,-0.2048023045,0.6790464520,0.4966803193,1.5222219229,-2.9318621159,0.4659831226,-0.9096521735,-0.1747777015,-0.0647855178,-0.8331367373,-1.5714011192,-0.2310294956,0.4662609696,1.3658882380,-0.5742117167,0.4292911887,0.5996888876,-2.3400518894,-1.5466567278,0.7606943250,-0.7578786016,-0.2359795421,-1.0300453901,0.1930342764,0.0036071180,-0.0514582843,-0.4616616070,1.7474654913,-1.2599040270,0.9778512120,0.3718870580,2.0573425293,0.0001507712,-1.3301340342,1.2774391174,1.6158695221,0.9101704359,-0.3199186623,-0.4357638061,-1.6184130907,0.4685378373,0.7183168530,0.1964053959,-0.0726887211,-1.1159377098,0.5207815170,-0.9250515699,-0.8146038651,1.5330342054,-0.6654334664,1.2355058193,1.2149068117,-0.8081433177,-0.1008972526,-2.6701030731,0.1122501418,-0.1568444520,0.6637252569,0.8165430427,0.2798295319,-0.7888636589,-1.4502432346,0.2165211886,-1.3123550415,-0.0796058998,0.9572609067,-0.3779307306,0.8503680825,0.4904717207,1.5245455503,0.1286518425,-0.3477151990,0.2938793302,-0.6671968102,-0.0250478294,-1.3159838915,-1.5637085438,0.7293962836,-0.0600265227,1.3219997883,-0.7478125095,1.6180843115,0.7206456661,1.0755368471,-0.6887121797,1.2116334438,0.1095357239,1.8574286699,0.5284230113,-1.0005639791,-1.7658504248,0.8115992546,0.1519138515,-0.8634884953,0.0946448296,-0.6255034208,-0.5461331010,1.1926347017,1.6944109201,0.7403153777,-0.4044455886,0.7798045874,0.7493108511,0.6431380510,0.1134475395,0.2037412971,0.2755376995,1.1141532660,0.9121242166,1.5169768333,-0.9620696306,-1.9707722664,0.8506955504,0.3520783484,1.6420823336,1.1664842367,0.0395719223,0.5504347086,-0.5065367222,-0.7530210018,-0.1424470097,0.3533922434,-0.5853402615,0.2046187520,-1.9142156839,0.9022826552,-2.0429213047,-1.1913815737,0.2445087582,0.6097036600,0.3708125651,-0.1089679971,-0.4501316845,1.0040342808,-0.7449307442,0.3174760342,0.1585830599,1.1094741821,0.2051526755,0.2611257434,-0.9332591891,0.5158112049,-0.0843781233,-0.5690991879,0.9467744827,1.3892228603,-0.1915261894,-1.4694588184,-0.6829240918,1.8040553331,1.4982194901,-0.6782018542,-0.2488974929,2.0247976780,0.7601909637,0.2023352534,-0.0089879557,-0.3011207283,1.2983838320,-0.6964088082,1.2567225695,1.4973249435,-0.0151675921,1.1256455183,0.5787013173,-0.7115837336,0.4392588437,0.6161403656,-0.3426590860,0.4325609505,-0.0037368375,-0.2693090141,-1.4960060120,1.1586462259,0.7610878944,-0.5264061093,-0.7910407782,-0.3750860989,-1.5029484034,0.7323586345,-0.9829524159,-0.6052945852,1.6173005104,-0.3960254788,-0.3167100251,1.4021726847,0.1614335328,-1.7691595554,0.4891624153,1.7525867224,-0.6651031375,-0.2736934125,-1.5221942663,-1.3538130522,0.9329830408,1.7201684713,-2.1362659931,1.3983808756,1.0712672472,0.8699352741,1.9718719721,2.8391821384,1.1305669546,0.1621609330,-1.0223643780,0.1640578508,0.3482623994,0.0992343724,0.9226043224,-0.5990541577,-0.5642827153,-0.3903325796,1.5199590921,1.2961598635,0.4010730088,-1.3141818047,0.6916372776,0.0341012813,0.2534821630,-1.5459098816,0.7012271285,-0.9198668599,-0.3922315240,0.5712463260,1.0828225613,-1.4264631271,1.8115274906,-1.2499611378,0.8060184717,-0.5210914016,0.2651344240,-1.2977297306,-0.3151990473,-1.4129822254,-0.3059104383,-1.2792009115,-1.3503084183,0.3274895549,-0.8965561390,0.1319619566,0.2559824288,-0.8015326262,-0.8983778358,-0.8235607147,-0.4976842105,0.9133901596,-0.9979527593,-0.0663572326,-0.1228386909,-0.3515924215,-1.6459765434,-1.1646555662,-0.5235185623,-0.3147287667,0.8435072899,0.6037076712,0.1352328509,-0.9873789549,-1.3439757824,-0.5656504035,-0.7461355925,0.1942629516,0.4915701151,0.9518358111,0.3652679920,-0.8218551874,0.0957542583,-0.4124514759,-0.3918253779,1.0724167824,0.1508688480,-0.1930464804,-0.3708569407,-0.2351885140,0.2533005774,0.3928980827,0.1800833941,-0.1871147901,0.1421864182,0.8545504808,-0.2546977401,1.2093913555,-0.0946916267,0.4536883533,1.8203556538,-1.4522353411,1.0122228861,0.3969878256,0.8579048514,-2.4725697041,-1.1170048714,-0.3419044316,0.2210522890,-0.0589853376,2.0522193909,1.3139799833,0.0032415872,0.9737606645,-0.3109631836,0.6522809863,0.1454812586,0.3584970832,-0.6686333418,1.0057399273,-0.4018355012,0.4271542430,0.7752248645,0.7583116293,-0.0558623113,1.9829217196,-0.0791059658,-0.1452606767,0.6852729917,1.0473220348,-0.4100103974,0.8070753813,-0.5444563627,0.5194547772,-0.7474954724,0.0800675452,-0.4973312616,0.7176632881,0.3519951701,1.1283892393,1.4414153099,0.7251556516,-0.2250899971,0.7314395308,-1.5019141436,-0.7311096787,-1.1236633062,1.5846997499,0.3824317753,-0.8789307475,1.9165765047,-1.2047196627,1.9510960579,0.1713950783,0.2518723309,-1.0073115826,0.0976815745,-3.2116572857,1.0625407696,0.3055147827,-0.1818564683,2.4210405350,0.2135395557,1.0038594007,0.2944985330,-0.1435895413,-1.9485757351,-0.3004073203,0.4409326613,0.6442545056,0.5157012939,-0.5109453201,-0.3380121291,0.4624716043,2.5077555180,-1.0816066265,-1.3965083361,0.6884524226,0.2567251027,1.2027677298,0.2761328220,-1.8016265631,0.4354678392,-0.4259582162,-1.4475284815,-0.4208916426,0.9427179694,0.4259283841,0.0079847854,1.1683820486,0.6213946342,1.0260797739,-1.8386904001,0.5446011424,-2.1929266453,0.3169703484,0.1466955394,0.2231619656,-0.5830193758,-0.9312384129,-0.4481034577,-0.4660280049,0.0486355685,-0.0424672253,1.1460434198,1.0676603317,0.2260905653,0.7005288601,1.4022908211,0.0001941096,-0.3831669390,-0.0770072937,-2.1831009388,-1.5603170395,0.4208289385,-0.9125955701,-0.5532537699,1.8200123310,1.6134670973,2.5783603191,-2.3645694256,-1.2364205122,-2.1010518074,-0.3773110211,0.3891334534,-1.8309109211,0.1862813532,-0.5885137916,0.5469305515,-1.2611180544,0.2711682320,-0.2295575142,-0.8624431491,-0.2658065259,-0.5441913009,-0.6111053228,0.3815867305,2.4132184982,0.2860789001,-0.9591971636,-0.2013577223,-0.2921943665,-0.5352737308,0.2526368499,1.0676268339,-0.0170707032,-1.2185895443,-1.6883766651,-0.0279599130,-0.4728796780,0.4600687027,-2.1366546154,-0.6944203377,0.4398227036,0.8040372729,0.6955130100,-2.2377107143,-0.1955517530,-0.8615193367,0.0634703040,-0.3660758734,0.1347871870,0.2589198947,1.4126286507,0.6336156130,-0.7764823437,1.5431591272,-0.7278642654,0.6717827916,-0.5883294940,-0.9275021553,-0.5374195576,1.4585071802,0.4842028618,0.7848344445,0.1956220865,-1.4329868555,1.4823243618,0.9601696134,0.3370892107,2.0254490376,-0.1215440184,0.3890198767,0.9085683227,2.1455557346,2.4146547318,-0.2953370810,-0.1564641893,-1.0599550009,0.9626013637,0.0099062221,2.0847289562,-0.6303656697,1.3723542690,-0.7465828061,0.3475526869,-1.6720502377,0.4044115543,-0.0562933162,-1.5195279121,0.7755575776,-0.8021618128,-0.2751158774,-0.7458245754,0.1956940740,-1.0238747597,-0.9840406179,1.0258538723,2.0173861980,0.1315372139,-0.5138539672,-0.5669877529,0.5406587720,-0.3071814775,-1.9967687130,-0.4333548844,-1.9966330528,-0.4374782145,1.7048588991,0.3344865143,0.3502452672,-1.5361242294,-0.2268669605,-0.4311481118,1.0138232708,-0.5507349372,0.5594305992,1.0659108162,1.4947098494,-0.7976589203,1.1181552410,1.3706774712,1.2994995117,-0.1372869313,-0.0259376168,-0.3461629748,0.4131499827,1.1723839045,-0.2778978348,-0.5928153992,0.0675194412,-0.8313975334,-1.1776564121,-0.4460479021,-0.6112349629,0.4268786907,0.8870689869,-0.6189897060,-0.1257660389,-0.9239557385,-1.8860009909,1.1535906792,-0.8335864544,-0.6902356744,-0.1756162494,-0.7561747432,0.5024242997,0.5363253355,0.0824064240,0.2639508545,-0.6364569664,-0.3769787550,-0.4377987981,-0.5338432789,0.5736504793,0.2441345602,-0.9038761258,-0.6077290177,-1.3279690742,-0.4976146519,-0.4994116426,1.3304718733,1.0966929197,-1.5022242069,-0.1590254903,1.6550925970,0.7573397160,1.3145182133,1.0289083719,-1.0945633650,-0.8774670362,0.1911343187,-1.0744937658,-1.0281189680,-0.4112767577,1.8617081642,0.2614100873,-0.1120274514,-1.1018739939,-0.5599132776,-0.9639128447,1.4452749491,-0.2379340380,0.0965326279,1.2240991592,-1.1137310266,-1.5898432732,-1.2747541666,-1.2285566330,-0.2418234199,-0.5687929392,0.6784836650,2.7191262245,1.0439400673,-0.5211651921,-0.1766644418,0.2213129550,-1.2737783194,-1.0919522047,3.2457404137,-0.5371184349,1.0131412745,1.3599733114,-0.1014137343,0.9044458866,-1.5049918890,0.3647313118,-0.7347620726,-0.7936519980,-0.4339566827,-2.1577720642,0.3033457994,0.6737972498,0.2448626608,0.6937257648,2.6209950447,-1.6615227461,-0.8978943825,0.3889890909,-0.4596033096,-0.7707110047,-0.1208278388,-0.5201724768,1.3842766285,-0.4282974005,0.7007796168,-0.4204046428,0.1363129318,0.4809338152,-1.1034513712,-0.4319312572,0.4005286396,-0.6485356688,0.2712681592,-0.7505175471,-1.4745311737,-1.1564862728,0.5677739978,0.6589148045,-0.8751621246,0.1891540736,-0.5418350697,1.8105150461,1.7355394363,0.2601662576,1.4141949415,-0.4384791851,-0.7842199802,0.4371353090,0.6943714023,-0.5380707979,0.4983506203,-0.5410212874,-1.1434106827,0.9545881748,1.3708180189,0.5112654567,-0.2825934291,0.8243518472,-0.3324177563,-0.9993035197,-1.6045049429,-1.7449423075,-0.8640743494,1.4113116264,0.3710772991,-0.3376179934,0.5454092026,-0.9610939026,-0.6323919296,-0.3632386029,-0.7752295732,1.8468760252,-0.0391475186,0.0493343733,-0.5033078790,-0.4727648795,-0.5759646893,-0.1179095358,0.1768748015,-0.0848587006,0.9794515967,-1.0092216730,1.5041515827,-0.2412413508,-0.3741708994,-1.3928172588,-0.1496126205,0.8959793448,-2.1168699265,-0.1839516461,-1.0776592493,-0.8422918320,-0.2578078508,0.7120755315,0.5457919836,1.2602188587,-1.3638870716,0.3252347112,0.3103461266,-0.6843565702,-0.8641714454,-1.3515841961,-1.3709787130,0.8442222476,0.6913160682,1.1721013784,-3.0055868626,0.1678446978,0.1083558276,-0.1259460449,-1.4384572506,-0.4379824996,0.6088418961,0.3323244452,0.1043943688,0.0842534676,-0.7801011801,-1.0713446140,-0.5946297646,-0.0363405943,0.6251944304,0.8738729358,0.8417578340,-0.1302471012,-1.7174865007,0.8975894451,0.7157564163,0.7714152336,-1.2969895601,0.2700895965,0.6959099174,-0.7589926720,-0.1790614128,-1.4486862421,-0.0582850389,3.2882657051,-1.0190426111,-0.2596707344,1.2057558298,-0.9189699888,2.0075521469,-0.6953464746,0.5769160986,1.0798561573,0.3362890780,-0.9042438269,-0.6373935342,-1.2408188581,0.5856894851,-0.6166279912,-1.0748144388,-1.1937690973,0.2725262344,1.7097991705,1.2231884003,-0.1864460707,-0.3886844814,-1.1401408911,1.1001895666,0.0698222071,-0.8169481754,-0.2381762117,-1.0990309715,0.0363042206,-1.0470657349,0.5295069218,-0.8829963803,0.6988388300,0.0920695812,0.2125919312,0.2035269290,0.4504480660,0.5238382220,-0.4745627046,-2.6972100735,-1.2137219906,0.8994110823,-0.5333787799,-0.2330003232,1.0217889547,0.1832010299,-0.1263355166,0.6309781075,-0.9253399968,0.1927347630,-1.1983563900,2.1006891727,-0.6179254055,-0.7291156650,1.5111485720,-0.9217118025,-1.3076606989,1.3268530369,-0.0251848493,0.7743625641,0.3491370082,-0.2782400250,1.5292787552,-0.9830396771,0.0843514204,-0.6756237745,0.4932007790,1.2645338774,0.4777994752,0.4024190307,-0.4145161808,-1.9489889145,-1.1476491690,0.6487477422,-0.5789185166,0.5087463260,0.6426893473,1.1313562393,-0.1236293092,-1.0429756641,-0.1709813625,-0.0481598303,0.7611688972,0.6133790016,0.3980072141,-0.2242967188,-1.0123447180,-0.6344790459,0.9931277633,-0.5333514810,1.0943918228,0.0513154417,-0.0190032981,0.6046923399,0.6036578417,-0.7517727017,-0.5252866149,-1.1066845655,0.9470067024,0.0642272905,0.5968157053,-0.2527898848,-1.1888705492,0.5340593457,-0.0894497484,0.4148004949,0.1358723789,-0.1815864891,1.2741400003,-0.4312350452,-0.5020402670,0.1918521374,-0.3785336614,0.3328542411,-0.9043675065,-0.1148370057,0.2523318231,0.5270742178,-1.7881046534,0.9077923894,-0.6153175235,-0.8822738528,-0.8405439258,-0.0023670495,-0.4354154170,0.0477021970,0.8350443244,1.4262235165,0.6257942915,-1.5644793510,-1.2305992842,-1.1948616505,-0.3577411771,0.9498245716,1.3089897633,-0.1266740113,-1.2482118607,-0.7585697770,0.3164147139,-1.6025328636,1.4389153719,0.8901625276,-2.9274833202,-1.3023848534,-0.1057398170,0.1712914407,-0.9100197554,0.9962213039,-0.3809780180,-3.3738229275,0.8629325628,-1.3146237135,0.6146615744,-0.7009440660,0.7499541044,2.5462694168,0.2149894536,-1.3944144249,-0.2389547080,-1.4857633114,1.2554066181,-0.7945663929,0.1306199729,-0.4769009650,-0.2954279780,-0.4177624583,0.7645667791,0.0706775561,-0.0036673227,-0.1686885506,-1.2878538370,0.9614015222,0.9980438352,1.6333302259,0.3764960468,-1.7786319256,-0.1212472469,-0.5497505665,-1.6330521107,-1.0370134115,-1.8117271662,0.1047022566,-1.6284438372,0.1362413913,-0.6433253288,0.5122199059,0.8732233047,-1.8397277594,0.3793027401,-2.2091073990,0.1155540869,-0.2137276232,0.8290930986,0.4650845826,-0.8942251801,0.4178222120,-0.6271676421,0.0223560892,-0.9844577909,0.5359445810,-1.5864883661,-0.5337475538,-0.0250616819,-1.2855857611,0.8331471086,-1.4578803778,-1.2561945915,0.7204806209,0.5493844748,0.9813920856,0.6658095717,0.2176280916,0.2478718907,-0.6187527180,1.7733623981,-1.0680766106,0.3115855157,0.9599409699,-0.6318791509,-1.7253450155,-0.1581967920,-0.2847787440,0.7510251999,0.6722778082,-0.5759375691,0.3976946175,-0.2699123919,1.1467082500,1.2894232273,-0.7950692773,-1.2313041687,2.5918538570,1.4108102322,-2.5290796757,-2.7064659595,2.0493443012,-0.1575528234,2.5390417576,-1.0978960991,0.6092931628,-1.7137644291,1.3925527334,-0.0829210207,0.9157499075,0.2611907423,-0.5531715155,-0.2612552643,0.1815842986,-0.2074785680,-1.3900825977,0.0094462279,-0.5616672635,0.6902035475,0.3310068846,-0.4598512352,-0.3554174304,2.5179774761,1.7027835846,0.7137155533,-2.5243444443,-0.0778169781,-0.7383882999,-0.4915468097,-0.4458041489,-0.1211165935,1.6788327694,-0.5277331471,-0.6074772477,-0.1313184202,-2.0344195366,0.6652619839,1.1473989487,-1.1869680882,-1.2858363390,0.6587207317,1.9654532671,0.7096003890,-0.7670360804,0.3632927835,0.1158852875,0.6583322883,-0.1609952003,0.1934109926,0.3165058196,-0.5613026023,0.1166221797,-1.3770916462,1.3263069391,4.2417716980,0.0803468376,-0.2049070597,1.5271331072,1.3036043644,0.5373516679,-1.9896894693,0.5142652392,0.6343153715,0.0603445619,0.5120731592,0.4221506715,-0.4696768820,0.0600340888,-0.4477773011,-0.0307193249,1.6819882393,0.2639681995,0.2140350789,1.3125169277,-0.3825906217,0.0022184977,0.1268048286,1.5481674671,-0.5468621850,-2.6106348038,-0.1282699555,-0.4177289009,-0.2894179821,0.9866001606,-1.2609921694,-0.9886783957,0.7946244478,0.8661491871,-0.4253971875,0.5601807833,-0.7023891211,-0.5714130402,-1.4841006994,-1.3401839733,0.0336159281,-0.0244027600,-0.1347808540,1.3022232056,-0.4897793531,0.6417346597,-0.8937379718,0.1637545079,0.2157087028,0.5360102654,-0.1275391430,1.7299357653,0.8968551755,-0.8804937601,-0.3912613988,0.8144260049,-0.4776334465,0.0370308645,-0.5445691347,-1.5247189999,-1.0484591722,1.0209940672,-0.0507922173,1.0969961882,0.0081091505,-1.0735074282,-0.4637985229,0.5490329266,0.7707652450,-0.9320597649,-0.5035763979,-0.3571883440,0.2904200852,-0.1153651178,-2.4413213730,0.5403788090,-0.8432013988,-0.7396709323,0.1283033639,-1.4762566090,-2.9589779377,1.3033297062,-0.2565463483,-0.3692474365,-1.1774467230,0.5953117013,-1.0849800110,-0.5788462162,-0.9446442127,-0.9873202443,0.8887941837,0.5191269517,-0.0704374313,-0.5656064749,-0.2987744510,0.4930670857,-0.4615590572,-0.2847803533,0.4016345441,-1.1605231762,-0.1913904548,-0.1202806160,0.2625747919,1.4581007957,-0.5056554079,1.7628393173,-1.4981478453,-1.3307580948,0.0612610243,1.5295269489,-0.3462225795,0.8649011254,0.4291520715,0.4492061138,1.0830732584,0.1221628636,-1.0343058109,0.3313332498,-1.0550051928,-0.3262061775,-0.2889346778,1.5725835562,-1.2517917156,0.0634046644,1.1232205629,-0.2517988682,-1.6302595139,-0.2371418178,1.7263067961,-0.7344884276,1.6452118158,0.2126683742,-1.0070602894,-1.1667169333,0.1198763698,-0.1139037609,-3.2478482723,0.1158405244,1.2873246670,-0.2967154384,-1.9113676548,-0.3062439561,0.2123287916,0.7192662954,0.2661412656,0.7092028856,1.0256335735,0.4500994980,1.9605486393,0.0655291229,-0.6529865861,-0.1378134042,-1.7298293114,-0.1140466258,-0.0287944637,-0.3820255995,-1.4283573627,-0.2104176134,0.8270501494,1.6666053534,-0.2273907214,0.4807750881,-1.1465576887,-0.7090556622,-1.8215582371,-0.1210410222,-0.3808588386,0.0259706769,0.1462689787,0.2766871750,-1.3793306351,0.2024340034,0.4679293633,0.7783885598,0.2412308306,1.4358551502,-0.5162473917,-0.3459844589,0.3041249514,-1.2383747101,-0.7322098017,0.1910422891,1.8059240580,0.9277132154,-2.0171482563,0.1951866299,0.6639137268,1.2373590469,1.2164707184,0.1519757211,0.6530285478,0.9477738738,0.2688260674,-1.2582738400,-0.9600851536,1.0390130281,-1.0648518801,-0.8012365699,-0.2251798809,1.1142963171,0.9341740012,-0.4841320217,-0.0355923399,0.3871592879,0.5604581833,-0.4087530673,2.0429780483,-0.4825588167,-0.6649580002,0.8005616665,-0.3599886000,0.1193309203,2.4247162342,1.1964256763,-0.0806443915,1.5196145773,-0.4052409232,-1.2675876617,-0.6781725287,1.5818355083,-0.9401290417,-0.5591271520,-0.6824262142,0.4200727046,-0.0844191387,-0.2632116973,1.2377724648,-1.8268915415,-2.0282392502,-0.7599870563,0.4133173823,-0.3004525900,0.3071993589,-0.0633047372,0.4281289279,-1.2683299780,-0.4179551601,-0.3186133206,1.1701862812,0.9885575175,-0.1080873460,0.2283486128,0.3161881268,0.6529545784,0.7720674276,-0.1712777019,-0.0354263894,-0.2102745920,1.9657728672,1.0205694437,1.4390608072,-0.5366148949,-0.7892500162,1.9705640078,0.3855912387,0.0629414320,0.6265225410,1.1438483000,-0.9780292511,-0.6935688853,-0.9762239456,-1.4685491323,-1.4372947216,-1.0730566978,1.4005103111,0.5869930983,0.0406822041,-0.3796490729,-1.4310114384,-1.5541208982,-1.1360594034,0.1388325095,-2.1530423164,0.1147642508,0.0471051075,0.3919199407,0.7114022374,1.1730850935,-1.3012977839,0.3481751382,0.2530570626,1.7267895937,1.5392260551,-0.9095569253,-0.5668856502,-0.4846865833,-1.9252877235,0.0159935709,-0.2737687826,0.8173170686,-1.4598239660,0.4550220966,-0.4915318787,0.3947442770,-1.4720059633,1.1339253187,1.3018774986,0.6073305607,-0.0294520799,-0.0245533902,0.8299852610,-0.2093410045,-0.8937062025,-0.2104247361,0.4905937016,0.9270766973,-0.8489860892,3.0901689529,-0.9478366971,-0.7347039580,-0.0914564133,-0.1481568217,2.1250960827,-0.6915543675,-0.7773598433,0.7704299688,-0.8429703712,1.2658998966,0.1026027575,-0.9573163986,-1.0858606100,0.2484246790,1.5868668556,-0.5566447377,-1.2599195242,-1.3841241598,1.1235691309,1.7500667572,0.0562867485,-0.2367135286,-0.5502758026,0.8646404743,0.2884162962,0.2858077288,0.3000690043,-1.2110253572,1.4334803820,1.3211159706,0.1077606380,-0.5899074078,1.2182687521,0.9392931461,1.7326339483,0.6656506658,1.1504017115,2.5321750641,-1.3975093365,0.1026985720,0.0797936320,-1.2145488262,-1.6663728952,0.1640934795,-0.7657446265,-0.9649801254,-0.2156695276,-0.3802717328,-0.0361323729,2.2739071846,0.5935225487,-0.7992947698,0.5043234825,-0.0635420382,0.0635460094,-0.4986944795,-1.2183550596,0.8497512937,1.3682345152,0.0592218079,1.8176462650,0.0380014367,-0.1648121178,-1.1811887026,1.6452852488,-1.1771593094,0.9260467887,-0.2866005898,-0.3300427198,1.0535910130,-0.4557752013,0.9618560672,0.3766882122,-1.8635056019,1.7812006474,-0.6835395694,0.2296070904,0.0775303841,-1.5565257072,-0.9657327533,-0.1612064391,-0.9848763943,-0.7570252419,-0.5434094667,0.0870989487,-0.3932954669,-1.4176454544,-0.6030968428,-0.5313537717,-0.7281560302,0.2537410855,0.8596052527,0.5377355814,0.0889668092,0.6040338874,-0.8646016121,0.4936359227,-1.3471070528,0.1851646155,0.5584734082,2.0683081150,-0.6238692403,2.4669466019,-1.0006500483,0.4998898208,0.5908782482,0.1898878664,0.9036785364,-2.6795573235,-0.6285718679,-2.2651124001,-0.0100735221,1.6246125698,1.2570762634,0.9649873972,0.4480108619,0.3538306952,-0.6394305229,0.6310080886,0.2673046887,1.3926157951,-0.5519245267,-0.6487637758,0.6073168516,-0.4114406705,0.3761738241,-1.4606273174,-1.4759228230,1.7613903284,1.2103283405,0.6520544291,-0.0654612854,-0.8724196553,1.2886662483,-0.9957754016,-0.2996768653,-0.5182425380,1.1075606346,-1.5807965994,0.1618001610,0.0243788250,-1.6595828533,-1.7371256351,0.1204244867,-0.2156693637,-1.6937848330,-1.0714200735,-0.2341331691,-0.3915313184,0.2276837975,0.2442232966,0.6898937821,0.8300570250,1.6709381342,-1.4706568718,0.6646685600,-0.7181670070,-0.0028348088,1.4022594690,2.1807963848,0.6828091741,-2.4582383633,1.1281207800,-0.6115419865,-1.1212936640,-1.2312363386,-0.4915806353,0.5487788320,-0.4697555602,-0.2441457063,0.4054579735,-2.1404464245,1.5693150759,-0.5173771977,-0.4552463293,1.1641325951,-0.4407202303,2.2006056309,0.2322905511,0.1107065305,0.2862088978,-0.2815102637,-0.3408988416,0.2058108151,-0.1996606290,1.8439724445,0.8755335808,-0.2496846020,1.5357745886,0.2453305572,0.6203836203,0.8212997913,1.3025162220,0.1074199975,0.8545994759,2.0262827873,1.6857354641,-0.5158991218,-0.9814931750,-2.5545742512,0.5971880555,-1.2477747202,-0.8447640538,-0.2711225450,-0.1848308742,-0.6540018916,0.2878918946,0.3621478677,0.6957350373,-1.6501054764,-1.1784461737,-0.8048467636,1.2036799192,-0.7421025038,1.2379450798,1.7582762241,-1.5390353203,0.4638553858,-1.3758928776,0.1921562254,-0.2725992501,2.1471478939,-1.2595988512,-0.3549736738,0.2839905918,-0.1939975917,-0.0150380591,0.9684531689,-0.8801771998,-0.6602508426,1.1853135824,-2.7470576763,0.5793197155,-1.2005586624,0.9979766607,0.1249912754,-0.7145936489,0.0190785658,-0.0678644404,-1.1773444414,-1.3656818867,-0.9308581352,-1.5273888111,0.6262164116,-0.9275572896,0.6307232380,-0.3932364285,0.3676517010,0.1095421910,0.4901863337,-1.3060173988,1.4643207788,1.2106331587,0.3033938110,-0.7580705881,-0.7045764923,-0.2487854362,0.7929059267,0.2234160602,-1.1094235182,0.1523469090,0.6313382387,-0.3104008734,1.2057654858,1.2911474705,0.1881976724,-0.0363846235,-0.6520819664,0.7624713182,0.9030723572,1.4012763500,0.9809569120,-0.1520080268,-1.1902999878,2.4968516827,0.5791797638,-0.5331690311,1.8849302530,1.2531266212,-0.5741626620,0.6255322099,-1.2660032511,0.0748630986,1.6345337629,0.2266604304,0.6084037423,-0.7702188492,1.9156914949,0.4047849774,-1.2006857395,-0.1776676178,-0.1083059758,1.7594144344,-0.1029189825,-0.5665433407,0.6066942215,-0.5196262002,-0.2490082681,-0.9327793121,0.3236896098,-0.3677179217,-0.1818056256,-0.5839886069,-0.2038229257,-0.0597114004,1.1402399540,-0.0260799173,-0.6193695068,-0.3960160315,-0.9552299380,0.6448193789,1.4817017317,1.5544289351,0.9933441281,0.4653750658,0.3257007897,0.1263968647,0.1049721017,0.7257955074,-0.3700866103,-0.5341292024,2.2867617607,0.2005052119,-1.9354718924,0.8988186121,-0.0689575225,-0.6440743804,0.5772926807,-0.4547063410,1.4799640179,0.0647191256,-0.4898588955,-0.8096262217,-1.0249881744,1.6329885721,-1.0937043428,-0.6664443612,-0.2176919729,1.8012778759,-0.9251882434,-0.5116018653,-0.1121688411,-0.2361086607,1.7645183802,-0.9666455984,-0.8906248212,2.5078215599,-0.3365430832,1.4512392282,0.2457870543,-0.7407913804,-0.5314186215,-0.2175210267,1.6160784960,0.1030726433,-0.2955012023,0.3930938840,0.3691558838,-1.4468399286,1.4991459846,0.7861236930,1.4582768679,1.0606905222,1.4576917887,0.4594173431,0.9900460839,0.0367541350,-0.0919883996,-0.4150067866,1.1121563911,-1.8991169930,-0.0029766932,0.9736584425,0.5819031000,-0.3772553504,-0.3100667000,-0.2848064303,0.2640193999,-0.3516303599,-0.4092839956,-2.0935854912,-2.2584433556,0.3784409761,1.2266635895,-0.6566455960,-0.0365018025,0.3758405745,-1.1574118137,-1.6608725786,0.3360662758,-0.4174785316,1.7872010469,-0.5762202740,-0.9449684024,0.1880954653,-1.2142983675,-1.3987449408,-1.0537490845,0.0820185915,-0.5293899179,-0.5560578704,-0.5497375131,0.2450578064,0.4957640767,0.8905921578,-0.9192040563,0.5279426575,-0.0151319457,-0.3531607687,-1.6664785147,0.5860685110,-0.1222635657,-0.4696131647,-0.8306789398,-1.7213633060,0.4148206413,-0.9287552238,0.5041882396,0.6945232153,-0.7018371820,-1.7570469379,0.3231323659,1.0354024172,0.1899425387,1.2799785137,0.5467972755,1.1144099236,-0.1551059335,-0.8696814179,0.6797798276,-2.4373333454,0.6826940775,0.5466501713,0.8491961360,0.5381039381,-1.3631504774,0.6576964855,-1.6812366247,-0.1420921236,0.0644702837,0.3568619490,-0.4917500317,0.0291998181,0.5068673491,-1.1943705082,1.3364574909,0.0296131652,-1.1348272562,0.3270067573,-0.7610291839,0.1490225941,0.1008909866,-1.4996412992,-0.6174682379,-0.6078441739,0.2064402550,-0.8942359090,-2.6421942711,-1.3883210421,0.1245091781,0.6594743729,-1.2438187599,0.7344162464,-0.3856297135,1.3615497351,-0.6648976207,0.1783328503,-0.0513411611,-0.3603737056,0.3984665871,-0.4077322781,1.3554097414,0.2356388569,-0.2174219340,-0.1714425683,0.4619775414,1.7577792406,-0.9965714812,1.1256047487,-1.0318431854,0.0069990228,0.1054399237,-1.0228053331,-0.3113851845,0.8585723639,0.2263864875,-0.6888257265,1.6379286051,0.7351904511,-1.3622685671,-1.4697754383,0.6048600674,-1.0446178913,-1.6048693657,-0.0697253868,0.7481107712,-0.8034046292,0.2074136585,-1.5064373016,1.5586475134,0.0487470403,0.2746212780,1.3123952150,-0.0130932564,-0.5733627677,0.1082773730,-1.0324797630,1.4006639719,0.1419160068,-1.2351351976,1.4697282314,-0.4961551726,0.3234536946,2.5705366135,0.6191286445,0.2001783103,1.8302137852,1.4770355225,1.2808552980,-2.0362477303,-0.7708904147,-2.2161989212,-0.6043381095,0.1801552922,-1.8412429094,0.2060479224,-0.2533358932,-0.8370944858,-0.7637611628,0.3168261349,0.5018517971,-0.2618725598,2.0702135563,2.1030116081,-0.0092163961,-0.9284299612,0.5606794357,-0.2881985605,-1.1079137325,-0.0594206415,0.2303173840,0.0974219963,-1.1072945595,0.6925656199,-0.3535038233,-0.6043095589,1.5273171663,1.1504018307,-1.5695350170,-0.6234639883,2.2262411118,0.5078104138,0.5744566321,0.9775137901,-0.2812677026,-0.6070799828,-0.6489948034,-0.2179257274,0.9815560579,-1.8020489216,-1.3939456940,0.2427239269,-1.1940877438,0.7539755106,0.2131537497,-0.9054090977,-0.9812750816,0.2375390530,-0.7263105512,-0.4075903893,0.4848812819,0.7323713899,-0.2195205986,0.7746742368,-0.5940266252,0.5959823132,1.5027459860,0.7207845449,-0.9153077602,0.7144644260,-0.4492384791,-0.1792533398,0.4524716139,-1.4900296926,0.1651769876,-2.2085511684,1.5511286259,0.7659050822,-0.3244543970,-0.4670624137,0.2195701599,0.7060580254,-1.4186925888,-0.3362497389,-0.8520848751,0.8867446780,0.3390224874,1.0442818403,-0.9417509437,-0.7377603650,0.0769798011,-0.7142660618,-0.7156736851,-0.1892230809,-0.5361557007,-1.3213405609,0.2317953408,-0.6825730801,1.0135622025,0.5309364200,0.2421779037,0.4017920494,-0.4618558586,2.3104119301,1.6827931404,-0.8894057274,-0.3898538053,0.8753790259,-0.6747983098,0.3014372587,-0.6322235465,0.0239859428,0.9638617039,0.9551012516,0.7515984774,-0.0033408087,-0.9071614146,0.3515233696,0.5865153670,-0.2021835446,0.4500505626,0.9413334727,-0.5805366039,1.7458322048,0.0380769074,-0.0990866572,-1.0987000465,0.0226462241,0.5436627865,1.1500978470,-0.4444086850,1.5100064278,-1.8368489742,-1.3223434687,1.0303223133,0.6480669379,0.4582530856,0.7627970576,0.1246709898,1.7402290106,-1.6799961329,-0.5588530898,0.7539991736,-0.6544169188,0.0672161505,-0.3272388577,0.5595880747,1.2202001810,-0.3627043962,0.8311170936,0.3439565897,-0.1743943244,0.2378960103,-0.4759786129,0.0559345298,-0.4318015277,0.3085387945,0.7614166737,-0.6752606630,1.1796420813,0.3769035339,-0.0317898244,1.9001022577,0.9514611959,-0.0556233376,1.3591566086,-1.2247810364,0.1007181108,-0.7172840834,-2.5895702839,0.4835788608,-0.9515837431,0.4092848897,-0.5652714968,1.6664245129,0.1597400755,0.3711966276,-0.6338654160,2.0866260529,0.5391490459,0.1859727055,-0.5546110868,-0.5572327971,-0.6505861282,-2.2647030354,0.4426457882,0.1652098149,-0.2662654519,-1.3499914408,-2.2734627724,0.5519658923,-0.0034194007,0.3603643179,-0.2471415550,-0.1274028271,-0.0114346435,-0.9155646563,0.1687090397,1.8955256939,0.2796881795,-0.5321885943,-0.7036546469,-3.1717319489,-0.7830032110,0.9552480578,-1.7417746782,-1.4782881737,0.2072343230,-0.3422027230,-0.0000039180,-0.7132492065,0.4970744252,0.2872682214,-0.0240418799,-0.0924070626,0.2005609572,-0.2416967005,-0.4522222579,-0.7911132574,1.1676659584,1.0429853201,0.4757418931,0.6947637796,-0.4414412677,-0.3858654201,-0.0315578692,-0.0620186105,0.7743752599,1.6831254959,-1.5434107780,0.2417434901,-0.4039699435,1.0505112410,-0.0232733302,2.4460079670,1.8306061029,-0.2217491418,-0.8391377330,0.4859440923,-1.8701001406,1.6040929556,-0.7600015998,1.1947399378,0.8387134075,0.2391007692,-1.1038827896,1.5782461166,1.1515152454,0.8457059264,0.5228255391,-0.7674822807,-0.2895836532,-0.6218723059,-0.5329485536,1.9727894068,-0.8545120358,-0.0130121699,-0.2113794982,1.2866762877,0.4343684018,-0.2603058219,0.4808883667,-0.7769899964,-0.2809680998,0.6315764785,-0.2057825625,0.6242778301,0.3901982903,0.5251529217,-0.3042872846,1.0285104513,0.1606976837,0.1045264378,2.1321480274,-0.1765216440,-1.4004218578,-0.4953492284,-0.3176076710,1.2840528488,-0.0970956907,-1.2646052837,-2.8805596828,1.0095061064,-1.6003195047,1.3290346861,0.1850828230,-0.4360282421,0.7396296263,-0.9351475835,0.3767962754,1.6771639585,-0.7094474435,0.6432923675,-0.2963850200,-0.9941192269,-0.4628743827,0.8353748322,0.6730687618,-0.1000754759,-1.0190597773,1.6968350410,0.6228394508,-0.8952073455,-0.7015125155,1.4203540087,-0.0927628949,-0.2419510335,1.0769065619,-1.0362827778,0.0588853620,0.4759929478,0.1233649552,-0.8965017200,0.2282161117,-1.5211969614,0.6221343875,1.4138190746,-1.0571297407,0.7189363241,0.6118679047,1.3299641609,0.8587504625,0.0770226419,-1.5501102209,-0.6436623335,-0.1981956661,0.5344657898,0.0764187127,-0.2980852723,0.1402880549,0.4510383606,0.1825833172,-0.6221678257,-1.8053606749,0.3611282408,-0.8057336211,1.4318394661,0.5070827007,0.5489898324,0.9191237092,0.6925198436,-1.1693946123,-0.9724825025,1.0652650595,-1.3838489056,-0.4112027287,-1.3346097469,-0.5550889373,2.1472911835,1.1219021082,0.3011842966,1.1503249407,-1.3700573444,-0.2416723967,-0.8239528537,0.2148872912,-0.1503032893,-1.6401677132,-0.4880145788,0.1143725961,0.0351575762,-0.2061207592,-0.7204528451,-1.8366031647,-0.1839381754,-1.5259851217,-1.1155805588,0.1875498742,-0.9459524155,0.1837504357,0.2436221540,0.1203817278,-0.0044349479,-0.6723968387,1.5836912394,-0.0804802477,1.4106041193,-0.6819021106,-1.0202736855,0.9404947162,-1.2492835522,-2.0210082531,0.0438118316,-1.1920198202,0.2237372845,1.3341157436,-0.4678844810,0.5081447959,1.5526033640,-0.8240080476,-1.7554879189,0.2668016553,0.0097025707,-0.1617574394,-0.3676709831,0.5528894663,-2.0743434429,-0.5731478333,0.1601055115,0.3278245628,1.2261792421,0.5595084429,0.8565822840,-0.0552693568,-1.5954004526,-1.1731684208,0.2836863399,0.0900228396,0.3806756735,1.6710040569,0.4169368446,0.0130567746,-0.3834365010,-0.6937999725,0.7352904677,-0.4927332103,-0.1502003819,0.6302086115,1.2963200808,-0.4325444400,-0.5431685448,0.7643723488,-0.3315337896,1.4310835600,0.6894853115,1.2302139997,-2.7370042801,-2.0758631229,0.8194510341,-0.4422242343,0.4619798958,0.4433602989,-0.4337116778,-0.9711326361,-0.7581747770,0.1246169358,1.2777051926,1.1372745037,-1.4670459032,-0.4377576411,0.5218424201,-1.3545349836,0.4560755789,0.5561665297,-0.2870936692,-0.9668313265,-0.5786038041,-0.4808922112,0.6795433164,-0.9512211084,-0.0520349778,0.6492468119,-0.4023033082,-1.4939315319,0.1896193027,-1.4484800100,-1.0535236597,0.4588146806,0.8064754605,-0.6888238788,-0.2907008529,-0.2247964591,0.5738497972,-0.3463048637,0.7758319378,-0.8346418142,0.3204473555,0.0675710440,0.6141188741,0.0013366932,-0.7410218120,1.6322492361,-1.2700757980,-1.0345075130,-1.0681058168,1.1929841042,-1.1688381433,-0.5785624981,-1.2230278254,0.5554084182,-0.4128984511,-2.2871227264,-1.1279395819,0.8433239460,0.1518727094,2.0980987549,0.4355578423,0.8607432842,1.7625917196,0.0613590404,-0.1310444772,-1.1538994312,-0.2084873766,0.6174628735,-1.7004872561,-1.0596629381,0.8424559832,0.6678346395,-0.7544751763,0.0714253187,0.6278148293,0.4992212653,1.0457350016,-0.1810946763,2.0991773605,-0.8590780497,0.2861403227,-1.4618811607,1.0282397270,-0.5337978601,-0.1446364969,-0.9851919413,-0.0448441878,-1.3567535877,-0.4009573758,-0.5194885135,1.9878838062,0.6508784294,1.0800508261,0.7166387439,0.2542805076,-0.1705901474,-0.8281711936,-0.2093469799,-0.3811714649,-2.3445951939,-0.3831149042,-2.7244744301,-0.8163167834,1.1056801081,-0.7393755913,-0.0141836274,0.7436538935,-0.7740547657,0.3735834360,-0.2184483260,0.9375358224,-1.2539305687,0.5076622963,1.3608239889,-1.1145510674,0.3206633925,-2.1811640263,0.3985752165,-1.3613519669,1.0203813314,-0.0525459312,1.2631360292,2.2825152874,-0.8123476505,-1.4406666756,2.0423271656,0.1090389937,1.4997259378,1.4937498569,-2.8995282650,-0.6637921333,-1.2237437963,-2.7321140766,-0.8622496724,1.9248254299,-0.0118800914,1.1111546755,0.4902781546,-1.1836172342,-1.7035608292,-0.6081807017,1.3975087404,-0.7155966163,0.2222000808,0.1491065621,0.5913746357,-0.5024318099,-1.7523351908,-0.8049672246,0.0088898782,0.5498868823,1.2858682871,-0.8413038254,-1.2562233210,0.8540031314,2.7723174095,-0.0660058931,-0.0704578236,1.4507570267,-1.7885080576,0.0580867492,0.0526900925,-1.2424575090,-1.1932390928,0.0536607280,-0.5483915210,-1.1195905209,1.2937419415,0.4144541919,0.5000180006,0.2320733964,-1.2249164581,1.0522677898,1.1093354225,1.0206264257,1.8482019901,1.0249714851,-0.6673058867,-0.4649356008,1.1188815832,-2.9661209583,1.1700307131,-0.8108969927,1.0020540953,0.1462125331,0.7842738628,-0.7974629402,0.2370982617,-0.2903953195,-2.3647882938,-0.4633262753,0.3321042359,0.0682333335,-1.5955102444,0.4221783876,-1.0460327864,0.0833548754,-0.0800244212,0.0916623548,0.8428997993,-0.0078278603,-0.0038369715,-1.8239731789,-0.6578385234,0.5915154815,1.1527293921,-1.2100425959,1.4766799212,0.2016633749,-0.1270681322,0.2116021514,-0.7006193995,-0.3207107484,-0.5239910483,-0.2711711824,-0.0808895975,-0.2620672882,-0.5259278417,-0.2087262869,-0.0847980306,-0.6684075594,0.1318341643,-0.3069368303,-0.3217082024,1.2094240189,0.3053298891,0.0364941768,0.4884267449,-0.2790943980,-0.9987446070,0.0164896939,-1.4116181135,-0.0203813892,2.0271334648,-0.4562243521,-0.7777702212,-0.0108297598,0.1521138549,-1.5504790545,-0.4843142927,1.1425955296,0.9327201843,-0.2901050746,0.5929782987,-0.7860559225,0.2315905243,-0.1417619437,0.0613079369,-0.0808374882,-1.5937153101,1.0773460865,0.2746188343,-0.7450028062,-0.6539436579,0.8430441618,-0.8579425216,0.8792074919,-0.1914065927,0.8935930133,-2.3076658249,-1.2254799604,-0.9316254854,-1.3976552486,-0.3991250396,-0.6948458552,-1.5662037134,-0.0899952948,-1.2958993912,-0.2588024437,0.0242907070,-0.1605933458,0.1624411196,0.6484341621,0.0786128640,0.1670193970,-0.7773826718,-0.7471885085,0.2092164755,0.2134766579,0.5705438852,-0.4578116536,0.5587601662,-1.0892243385,1.0605726242,-0.3094975352,-1.4312770367,-0.1730458140,0.4337505400,1.0741657019,1.6160172224,0.1272350997,-0.1938657910,0.6725165844,0.5144274831,-0.5641947389,-1.0385379791,0.2151829004,-0.4242037535,-1.5490713120,-3.3838853836,0.3964085877,0.4213456511,-0.3092971146,0.5519814491,-1.0131312609,0.1652939320,-0.7183796763,-0.2181751877,0.4323822856,-0.4072811007,-1.3852882385,0.0991055146,-0.9232534170,-0.0023331596,0.5881130099,0.4912368953,0.5116588473,-0.4789597988,-1.3557976484,0.8674719930,0.8575125933,-0.1776522994,-0.1775404066,-0.1856035888,1.3404828310,-0.9878146648,1.6222991943,-0.2595064640,-0.5972997546,-0.5425067544,0.5912622809,0.3834866583,1.3222781420,-0.8192518950,-1.0907922983,-0.6246671081,0.6052445769,0.4081635475,0.2373645455,0.1690674126,0.5802407265,-0.5613754392,0.2456480712,-0.9186141491,-0.2769204080,-1.7706328630,0.4763954878,1.5354692936,-0.0598922297,-0.5450186133,-0.1883676797,-2.5338580608,0.4641127586,0.3048112392,-0.6876582503,-0.4315545857,0.3876003921,-0.8581926823,-0.6158384085,1.0436244011,-0.3341654837,-0.0467620641,0.7010356784,0.1533711851,0.9586766362,-0.0557326339,0.3174902499,-1.2664761543,0.1697869450,-0.8404021859,-0.4100980163,0.2164599746,-1.5345907211,-0.3343243003,0.1733925790,0.6227089167,-0.3400717676,0.2302381098,0.7133636475,1.0837763548,0.6489784122,-0.4140874445,-0.4357428849,1.0704756975,-0.1154135317,0.4830461740,-0.2553482950,0.6317064762,1.4388637543,-0.6082205772,0.6572952271,0.4606111348,-0.4769994318,-0.6360312104,-0.0991303176,1.0446186066,0.9986180067,1.2831765413,2.1639351845,1.1235325336,0.2174135298,0.1962851286,0.7651981115,-1.2645888329,2.4407944679,0.0277731884,0.3911207616,0.3047181964,1.5580196381,-0.7807807326,0.1302722842,0.9293032289,1.0180013180,-0.1589470506,0.9012888670,2.0110130310,0.4158630371,0.0888017491,-0.3296423256,0.2352096140,-1.3284860849,-1.0254509449,1.5939886570,0.1282520890,0.4186613858,0.3527747393,1.8500404358,-0.6223271489,-0.6476612091,-0.2049963474,-1.3311686516,-0.1923779994,0.9806227684,0.0004467586,-0.6268636584,0.0827400163,0.9971995354,-0.9771696329,-0.2499272972,-0.3006271124,-0.3148871660,1.7323715687,1.7476186752,1.2388221025,1.5113986731,-1.3835494518,-0.7499847412,0.6338880062,0.5752592087,0.4825147986,-1.0033938885,0.3850116134,-1.2665108442,-1.2748463154,-0.0880842432,1.2344012260,-1.1817024946,1.1284167767,-0.3691191077,0.0791317150,0.3606567383,-1.3921650648,-0.8959398866,1.5028594732,-0.6054318547,0.2944380939,-1.0308992863,-0.0682621300,-0.9367830157,-0.4790829122,0.3819047511,-0.0056958185,-0.0107525261,-0.1028386652,-0.0407153480,0.8296846747,-0.1679052711,0.7480251193,-0.2704329193,-1.6717312336,-0.9499000311,0.0938736945,0.0792115331,0.9397433400,0.4047400951,-1.5396602154,-0.6735089421,-0.1467912346,-1.1075301170,-1.2755281925,-0.2567361891,-1.1061099768,-0.7344524860,-0.3856717646,-2.1764931679,0.0527051352,-1.4594818354,0.1187220141,0.0322499759,-0.8149708509,-0.0294837058,0.8411209583,0.5211537480,-0.0760316700,0.5130376816,1.3642598391,0.0968394950,1.3154854774,-1.4872413874,0.9520645142,0.3005496562,0.6140743494,0.4355062246,-0.5848545432,-2.5305237770,1.3488068581,0.3234812021,0.0880915597,-1.1336556673,0.0930403545,-0.1541861147,-0.3016662002,-1.4424922466,1.5437906981,-0.6499189734,-2.3192703724,2.1626596451,-0.9241775870,-1.1621884108,0.9141823053,-1.0259217024,1.8104969263,-0.3519425690,-0.9066295028,0.5648496747,-0.8370807171,1.4850924015,-1.0320893526,-0.5918660760,0.1176175773,0.1124671847,-0.5896363258,-0.5832690597,1.6353310347,-0.7493469119,0.0465250574,-1.0367507935,-1.4493075609,0.7984340191,0.0820988566,0.5954594016,-0.3189447820,0.5058848262,-0.7114982605,0.5402135849,0.9257064462,-1.4224647284,-0.7928759456,0.0240264982,1.6763641834,-0.3487647474,-0.1829279959,-0.3225548267,-0.3663921356,0.1824751198,1.0975593328,0.1602485627,-0.6861212850,0.7449244857,-0.1191331446,-1.4907772541,-0.0717278123,0.5842505693,0.2929826379,0.0632381737,-0.1342022121,0.4378673136,0.4098827243,0.8411206603,-0.0789814442,-0.2399690449,0.5405627489,0.6278280020,-0.0108255902,0.0505150706,0.9220871925,0.4489594996,-1.0202002525,0.0912503898,0.9841045141,0.9010125399,-1.1630496979,0.0682095513,0.8780198693,0.0305589475,0.3894029856,-0.7775303125,-0.0655512884,-1.6206985712,-1.1411087513,0.6450503469,1.2038553953,1.4712681770,1.2446136475,0.2164686620,0.2948817015,0.0351893939,-1.1672149897,1.1487790346,0.4665854871,-1.8246629238,-0.4153800309,0.1016899049,0.9141763449,-1.3728073835,-0.1546313763,0.8691310287,-0.7926211357,-0.1904437244,-0.6742334366,1.5098134279,-0.7134387493,-1.3717981577,-2.2027521133,0.1625714153,-1.5810571909,-1.4009828568,-1.3369977474,-0.9206066728,0.5045040846,1.0087817907,0.7085490823,-1.8204631805,0.3505395055,0.1601599306,-1.2087808847,0.4851200879,0.6961211562,-0.8115411401,0.6887942553,-1.4158912897,-1.6351356506,-1.5797746181,0.6322211623,0.7213320732,0.4606862962,0.8185957074,0.4297682345,-0.0461610332,-0.4848355055,0.0079860473,-0.2723667622,-1.7874740362,-0.9821856022,-0.1429887712,-0.0252348650,1.9776024818,-0.0204313695,1.2319833040,1.4091806412,2.0734572411,0.7006293535,-1.7150832415,0.2069371343,-1.6790082455,-0.2211100459,-1.1749776602,0.0365302674,-0.3868663907,-0.0528737232,-0.9732688665,-0.3719446659,1.6559091806,0.3440146744,0.3946353495,-1.2677277327,-0.1625610441,-0.9379303455,0.5799641013,-0.0261510685,-0.7596936822,-0.7694777250,-1.0063365698,0.2434116006,0.4409281015,0.7339676619,0.8679358959,1.1445062160,-0.8765382767,1.2840873003,0.0781262815,0.6481414437,-0.9263640642,-1.4005607367,-0.5750855803,-1.0007141829,-1.0111794472,-2.0524334908,-0.6442151070,0.7671940923,-0.1145124212,-1.1316365004,-0.4282675087,-0.5749440789,0.1833458543,-0.1921777874,-1.4095654488,-0.8744406700,-1.5981025696,-0.5336658955,-0.9894477129,-0.4347616434,-0.5107789040,1.3670536280,1.3113130331,-1.3499810696,-0.3468316793,-0.0047309161,-0.7323764563,-1.0284543037,-0.0138079068,0.1132538766,-1.5646991730,0.0751108974,0.8303509951,-0.1938802451,-1.9379101992,0.0315455496,0.6615291834,-0.3474954963,0.0518144444,0.2939739525,0.0353117324,-0.0989409313,-0.3005047441,0.1867303848,-0.2230330557,0.1489258558,-0.3088251352,-0.8473169208,-2.1500792503,1.2460508347,-0.5631950498,-0.0580349751,1.0495109558,-1.5226836205,-0.3884546161,-1.3195962906,-0.4702957571,0.9313479662,-0.6823721528,0.2000008970,-0.5764540434,0.8537899852,0.9402247071,-1.2445976734,1.5359268188,2.0948321819,0.0036094575,-0.8047494888,0.6427945495,-0.2275648564,0.9242594838,0.5359516740,0.4261472821,0.1482180059,2.3247148991,-0.0195343848,0.1890586466,0.5467409492,0.1936537623,0.1615436673,0.7448188066,-0.1855718195,-0.0946201459,-0.7014371753,1.3129265308,0.2720538378,-0.8413616419,-0.4604212642,-0.4750130177,0.1501253098,0.5798549652,0.6560567021,1.0006505251,-0.0545246713,-0.8020230532,0.1682970226,-1.3182489872,-1.1121965647,0.4462005496,0.6017032266,-0.9011870623,0.0598643757,-0.4081072211,-1.7386128902,-1.3758144379,1.4552366734,-0.4543621540,-0.0994410738,2.2818775177,0.5025957227,0.1134583354,-0.7030552030,-0.4476456046,0.2547734380,1.2222807407,-0.9206188917,0.2277347744,0.0041218023,-0.5322578549,-0.6025855541,0.7921522856,0.7033787966,-0.5238165855,-0.3242940903,0.2282759100,-0.7225562334,0.2189976722,1.8640956879,-0.2014419436,-2.0383541584,0.7670707107,0.0946207866,-0.9718177915,0.5874319673,0.6024810076,-2.0453674793,0.3536788225,0.9645302296,-0.1440635771,-0.5780105591,0.4737685323,0.5964793563,-0.6031044126,1.7813662291,0.2994776368,0.0040594037,-0.4686329961,2.2406263351,-1.0148507357,-0.1007227823,0.5790359974,-1.3669410944,2.4542148113,-1.0502914190,-0.3570873737,-0.5959746838,0.1286456734,-0.2735119760,1.1831076145,-1.9064669609,-0.0173027087,-0.8793388605,0.9526354074,1.7210581303,-0.5359464884,-0.4232902229,-0.7482769489,0.3254696131,-1.7439950705,-1.3261831999,0.6918687820,1.3905178308,-0.2113317549,-0.6825257540,-0.3879581392,1.7752315998,-1.2752637863,-0.1166420951,-1.2915318012,0.1837764680,-0.1601903141,-1.2379313707,-0.0902454183,-0.2519405782,0.5891952515,-1.2630279064,0.6976277232,-1.1750415564,-0.5748518109,-0.6612970829,-0.2794839144,-0.5347990394,-1.3255223036,-1.1630715132,-0.1496529430,-0.2865560055,-1.6683949232,-0.9315761328,0.7481259704,1.2013155222,-1.5000940561,-0.6404548883,0.7500379086,-0.4412990510,0.5010219216,-0.5410768986,0.0552483760,0.4714125097,0.0664171502,-0.5142256021,1.9464106560,0.3117389381,0.1133240163,0.0764206946,-2.1993992329,0.5718014836,1.3705084324,-1.5698078871,-0.5611788034,0.9989655614,-1.3109512329,0.2550405562,0.2179651111,-0.2458942831,0.7524243593,-0.8888767958,-0.9764984250,1.2953237295,0.4097941518,0.1875261217,-0.6974471211,0.5086981058,1.6450030804,1.9019715786,1.1486008167,0.7689781785,0.5361904502,-0.6677723527,0.6889824867,0.9869290590,1.0165002346,0.5444405675,0.5614240766,1.5270713568,-0.8393536806,-0.9333688021,-0.0409526937,-0.0998738036,-1.0882169008,-0.3863084316,0.3301858604,-2.1117844582,0.4842156470,1.3418143988,-0.5743961930,0.0791617855,-1.6336181164,-1.3499776125,-0.0084255254,-1.4727298021,0.7257235050,1.0187690258,0.8479738235,0.0947717726,-0.4799260199,0.0153171076,1.7028288841,-2.4398531914,-0.7412115335,-0.7696051002,1.3584727049,0.5375123620,-0.4170902073,-0.3068646789,-0.3780648708,-0.6893613338,-0.3763635159,-0.5504732132,0.6834804416,0.1133769155,-0.8619261384,1.0548527241,-0.3079719841,1.3956831694,0.2459279150,-1.6134513617,0.0425924845,-0.2693678439,0.4709191024,1.9377353191,0.7869468331,-0.0102772806,0.7438308001,-0.9149633050,0.0896701813,-0.4285502732,-1.3545906544,0.3714318871,-0.9662501812,0.0663880482,0.0755720139,0.8606848121,-0.3789045811,-0.5214172602,-0.0249759257,0.3855774105,0.7961698174,-1.1770154238,-1.4023742676,-0.2600174546,0.4639261067,0.4731233418,-1.4157626629,-0.8307561874,-0.4470773637,-0.3219674826,-1.9117525816,1.8478777409,0.4157984257,0.2571049929,0.3644884229,2.1297881603,-0.2326315641,0.4425879419,1.5757837296,0.0731884092,-1.9210509062,-1.3611035347,0.1254009157,-0.7626289129,1.3449469805,1.7275245190,-0.5753748417,0.7083702683,-1.1395683289,0.9009451270,-1.1356049776,0.1987769753,-0.0978872925,1.1407341957,0.9220844507,0.4430917501,0.6003719568,-1.2657593489,-0.3270651400,-0.5956538320,0.1456205398,0.6889383793,0.1033993214,-1.3690428734,0.7404351234,-0.1215081289,-0.1990689635,0.8810068369,0.3059888184,0.4480573535,0.0953786969,-0.1013018936,0.4117246568,0.3502552509,0.0194713138,-0.2473152578,0.0101099778,0.9885329008,-0.8361511827,1.9361438751,-1.5811871290,-1.1002520323,0.9397823811,-0.0545123816,0.7610992193,0.5216606259,-1.0363000631,-0.7652194500,-0.0382754430,0.9650835395,1.8669173717,0.1112473533,-1.2015788555,0.6443081498,0.6186507344,0.0816031545,-0.4066605866,-0.4410473108,-0.5908294320,1.1830356121,0.2105588764,-0.1489932090,-1.3678106070,0.5889723301,0.3990076482,1.5867253542,-1.5419884920,-0.3135329485,1.2928620577,0.5041116476,-0.9222351909,-1.7613097429,-0.4756738544,-0.7624484897,0.4504918158,-0.4556908309,-0.0724610984,0.7097553611,1.1203337908,-0.3484529257,1.1659314632,0.1397081167,-1.5629338026,-0.7076761127,1.4508572817,0.5759756565,-0.9922260046,0.2997192740,-1.5346330404,-0.9537140131,2.3760414124,-0.0492447056,-0.2149013877,-0.7276610732,0.0869092569,-1.3743280172,0.0617098734,-1.3765540123,-0.3937661052,0.5421155691,-1.4106866121,0.4895611703,1.1866769791,1.5226407051,-0.4637456834,-1.9443510771,2.0126781464,1.2011687756,0.4509884119,0.4688838422,0.1416492164,2.0351710320,0.4427682161,0.4046050906,0.5470671654,0.1857168674,-0.1370263547,-0.7957639694,1.1775459051,-0.2308127433,-0.3254511952,0.6586336493,-0.6313273311,-2.5197975636,0.6868247986,0.9503057003,0.5775336623,-1.1326794624,-0.1656296253,1.3421090841,-0.0567202605,-0.6803632975,-0.4050382078,0.6355462670,-1.5059229136,-0.2022885233,-0.2591747940,0.3714067638,0.8712681532,-0.3979974091,-0.9245500565,-1.0143244267,-0.4404507279,0.5970969200,0.2319602817,0.5535842180,-0.4240028858,0.5902436972,-0.5997185707,0.1466287971,2.3729963303,3.0086288452,-0.5136756301,-0.4350767136,0.9363536835,-0.0597128756,-0.8972352147,-0.6416056156,1.2984263897,1.8004604578,-0.7545091510,-0.3338066936,-0.2864007652,0.4252581596,0.5166036487,-1.0704407692,0.3727474511,-0.4662492871,-0.8777085543,1.0085009336,0.4567803144,-1.4343152046,-0.0693903938,0.6386763453,-1.2341254950,-0.0431989394,-0.1082422808,1.1039363146,-0.9819817543,0.6192163229,-1.2208844423,0.5299162865,-0.1968284845,0.7186149955,-0.2716750801,-1.0598012209,-0.6523534060,-0.7307460904,-0.1305984706,0.4185395837,-0.1593158543,-1.0495679379,-0.3906728327,-0.2174431086,0.1957010031,-0.8210510612,-0.7583345175,-0.6436064839,0.6527817845,-2.2995562553,-1.4217740297,2.6572241783,-2.4107866287,0.2148666978,1.1167837381,0.0689454675,-1.3653887510,1.1535874605,-0.4121600389,0.2929527760,0.3599597514,-0.6850985289,-0.4406382740,-0.5719017982,-0.1960382611,-1.7868933678,-1.3133436441,-1.1885946989,1.0874711275,-0.5319527388,-0.6841382384,1.2883000374,0.0816733018,0.5675491691,-0.3255595267,0.3317215741,1.0300211906,0.5762638450,0.8731001019,0.8163179755,0.7308938503,-0.6628636718,0.3519839942,1.2436153889,-1.1196715832,-1.0711348057,-0.1543116719,-1.0863668919,0.4676058888,-0.6846093535,1.3797492981,0.3526509106,0.1648032069,0.0237876102,0.2023786604,-1.1174907684,2.2319457531,-1.5312778950,0.6684376597,-0.8544011116,0.6476187706,-0.7095187306,-0.5701030493,0.2349684983,0.7085313201,-0.2691114843,0.3251794875,-1.1168712378,-0.3028653264,-0.2788650990,-1.0868864059,0.4872075617,-0.5189303756,1.1145070791,0.4584412575,-0.5998378396,-1.4327603579,0.1275960505,0.2901370525,0.5808152556,-0.3115820587,0.8584854007,0.8452209234,0.3459075093,-1.5614558458,1.6772382259,0.3585601747,-0.8467258811,-0.4606466293,1.7624496222,-0.6848064661,1.2684752941,0.8637610078,0.4877776504,0.8418605924,0.1541614383,0.8735924363,0.3841915727,1.6905543804,-1.1739689112,-1.3215125799,0.1166850626,-0.5511772037,0.1038629040,1.0686504841,1.3229821920,-1.6473169327,-0.8972117901,-1.7887773514,-0.7082397938,0.0563377440,-0.7301474810,-0.6179089546,-0.7773608565,1.2667914629,-0.5679482222,0.7532033324,1.0075652599,-0.5667064786,0.8302335739,-1.4011286497,-0.0043775220,-0.7475999594,-0.7050182223,-0.8238686323,0.0595666282,-0.9293041825,0.3678091466,-0.5593569875,0.8309092522,1.4071900845,-0.5506002307,-0.8832412958,-0.4212633371,1.7079013586,-0.2129941732,-1.2215648890,0.9746375680,0.5255259275,0.1676276326,-0.7460688353,-0.3985492587,-0.2419589013,1.0022572279,0.3096496165,0.0151867429,-0.9989675879,-0.8324916363,-0.2698731124,0.7522588968,-0.7222785354,-1.3158954382,0.2006363124,-0.5149350762,0.0061105140,-1.7563093901,0.0626748428,-0.5142523050,0.9311300516,0.2424508929,1.6043307781,-0.3289819360,-0.0494096093,0.7316811085,-3.0088012218,-0.3715510070,0.6926851869,0.0006539202,-1.5461733341,0.0995478183,0.2765178084,1.4613583088,-1.3338665962,1.1406615973,0.3171734214,-0.4835242331,-0.2373184413,-0.0232107006,0.8536342382,1.6586548090,-0.5782043338,0.4537277818,-1.6588265896,-1.2349920273,0.0675332099,-0.2628900707,0.3805647194,0.8191167712,-0.1620512605,-0.6835185885,-0.8386046886,-0.4493160546,0.1507066637,-1.9121794701,0.5574362278,0.7430413961,-0.2474150509,1.0876133442,0.4239715040,-0.3730142415,-0.0829822570,-1.4674832821,0.2024282217,-0.8522486687,2.2314176559,-0.5353853703,-0.1779713780,-0.2383777201,0.5534749031,-0.7674822211,-0.3580855429,-0.8130614161,-0.4385259449,0.4330780208,-1.6723484993,0.4503363967,0.2866947651,-0.3895815313,-0.2773104012,-0.2627112865,0.8851501942,-0.4606986940,-0.6227043271,-0.2819042802,-0.1450483352,-0.1862329692,-0.9947724938,0.1286654323,0.8603655100,0.8581410646,0.0987485275,0.5210778713,1.4589275122,0.6336409450,-0.8249817491,1.1077028513,0.0143080968,2.6831395626,-0.4208842516,0.1807337701,0.8042305112,-1.6470074654,-0.5645323992,-1.4007233381,-0.1503272057,-1.0351790190,-1.1351163387,0.3737889528,-0.4462286234,1.0661048889,0.3744573891,0.9195076823,-0.4215391576,-0.5308960676,-0.2440245748,0.2437709421,1.8744490147,0.0601186305,-0.2889816463,0.6083256006,-0.5951191187,-1.1753454208,-0.4446639717,1.6190202236,0.2731115520,-1.2823290825,-0.6856404543,1.0023931265,-1.0596644878,0.0099540399,-0.9112805724,-1.9877477884,-0.3559651077,0.6992651820,-0.5291158557,-0.2777605951,-0.6945871115,0.4263310730,-0.4606139064,0.5313073993,0.3477262855,-0.6290251017,1.0485340357,-0.4984591007,-0.7014091611,-0.1268873066,1.7174379826,0.3756468594,0.6778792143,0.6780077219,-1.9288370609,2.1379055977,-0.3503865302,2.6057658195,1.4180355072,-0.8483371139,0.4836727679,0.2986367643,-0.4045870006,-0.3841612935,0.4206042886,-0.2121454924,-0.7215571404,-0.9440875053,-1.8669323921,-1.2715229988,-1.3166813850,-0.2099368423,-0.4971982241,-0.6165689826,-0.8177767992,0.7123737931,0.0018365026,0.2189357430,0.4399895966,-1.4153739214,-0.4745371640,0.8956039548,1.8533095121,-0.6692598462,0.8224695325,-0.4222893119,0.0309825372,-0.0985280126,0.0038888101,-0.6720025539,-1.0864828825,-0.5846391916,-0.8959212899,0.7892262340,-0.5727711320,-0.2901080549,2.3455419540,0.5100870132,0.6484789848,0.2203816473,-1.2419773340,-0.2932655215,0.0602538697,-1.2372095585,-1.3545566797,0.7277938724,-0.5110531449,1.8365730047,0.1518082768,-1.2500865459,-0.8315503597,-1.6715674400,-0.6968267560,0.1409083009,-0.4922994673,-0.7246807814,0.0654167756,-0.7244126201,-0.1597559899,-0.5303936601,0.0489419326,1.0108239651,0.6513858438,0.5965271592,-0.8281033635,-0.4502198994,1.3260207176,0.1846620142,0.3190106750,2.7237520218,-0.2407226712,-2.0167696476,0.0360962264,-0.6404058337,2.0376145840,0.4976940155,-0.1475096196,-1.6457666159,-0.3195464015,-0.4240814745,-0.7984828353,-1.7798746824,-0.5305024981,-0.9451339841,-0.3695907891,-0.6193536520,-0.8740698695,1.6382918358,0.8859256506,-0.6783981919,-0.6647996902,1.8402383327,-0.4664635360,-0.2869035602,0.8843571544,-0.6794208288,-0.0783729777,2.0344007015,-1.1569439173,0.5343900919,-1.2190382481,-2.7440197468,0.3725993037,-0.9437746406,-0.8705223799,-0.2391330153,-0.3168485463,-0.1414447427,1.3143306971,-0.0398241282,0.9941142797,0.5481469035,2.4456527233,1.1136090755,0.8380909562,0.8857203722,0.4825400114,-0.4374621511,-0.3491562307,-1.1849820614,0.9566195011,-0.6884231567,-0.6400103569,0.4962954223,-1.2663766146,-0.3680319488,-0.4868077934,-0.5154715776,-0.2976514101,-0.8406806588,-0.0521839485,-0.2806237936,0.2266739756,-0.2517160773,1.0988744497,1.2061139345,0.1976041198,-0.5565751195,-0.4206511378,-0.6106412411,0.6980303526,0.8038991690,-0.5697152615,1.1649491787,0.7628110647,1.1644734144,0.9731919169,-0.7703890800,2.5272583961,0.2993666232,0.9850234985,0.7090337873,1.2726600170,-0.9547067285,-2.2828862667,1.8040145636,-0.3618632853,-0.2424062788,-0.0360498950,0.6348895431,-1.1561373472,1.6774686575,-1.1213855743,-2.1498403549,0.4187663794,-0.8002408743,-0.7238284349,1.1115944386,1.5962899923,-0.8676059842,0.7034949064,-1.2499570847,0.1972162724,-1.4184181690,-0.1329640746,-2.0752580166,-1.3371758461,-1.7525701523,-1.4658756256,-1.5818002224,1.6401294470,-0.4202954471,0.6047040820,0.3399446011,-0.8635126352,2.1736896038,-0.6485803127,0.7760526538,-0.5920584798,-0.1532118171,0.0984346718,-1.1254554987,-0.4605285823,1.1066592932,-0.3280683458,-0.2730957568,0.0873861089,0.3761961758,0.3713440597,0.1002379730,-0.3835586011,0.5256533027,1.5230630636,1.6018843651,-1.2051194906,1.0897098780,0.7993661761,0.0984100774,0.5448901057,-1.2182017565,0.2122826129,-0.0533185825,-0.8356292844,-0.0336980745,1.2712229490,-1.2643465996,-1.6775107384,-0.9985657334,1.0351241827,-1.5880872011,0.7903474569,-0.0167097095,-1.2681533098,-1.6248126030,0.6737528443,1.4385950565,0.2779538631,1.9929624796,-0.1199937686,-0.4443750381,0.9745465517,0.4621928632,-1.5144137144,0.9511830211,0.8978304267,-1.1884974241,0.0929282978,-0.5976312757,-0.9062644839,-0.4685940742,0.0498959236,0.1588799804,1.4182624817,-0.0872410312,-0.4276543558,0.0140459212,-0.8659215569,1.4454176426,-0.3340324461,-0.0349760242,-0.5698040128,-0.9010173678,2.1993246078,-0.8341708779,0.8671241403,1.1048197746,1.0847196579,-0.2546294630,1.2404844761,0.4475292861,0.2714076340,-1.4715112448,-1.2379156351,-0.2507206798,-1.3513888121,0.2730809152,-0.0653217137,-0.1397357732,0.5785194635,-1.1722716093,-1.1036603451,-0.0131531553,1.6345367432,1.2507511377,-0.5973930359,-0.0155039188,-1.9891339540,0.3615313172,-1.4075814486,-1.5032497644,-0.1248913184,0.6577493548,0.0023436123,0.2874972820,-0.8602231741,-0.0809271559,0.1523856521,-1.0670419931,-1.0369086266,0.2998365760,-0.6676939130,0.6504074335,1.3342704773,0.5072284341,-1.4595576525,0.7439997196,-0.9475765228,0.2244775295,0.4849691689,-0.3844098151,0.1123687103,-0.6872268319,0.3756891489,0.6597490907,0.7952565551,0.4855103195,0.3044109941,0.1490117610,-0.5080056787,1.2712522745,1.2272012234,-0.3299134672,-0.0199540183,1.8290190697,0.5677607656,-0.5968216658,-0.2418765873,-1.9487468004,-0.2772829235,-0.5381264687,1.2586739063,1.5063394308,-1.3124256134,-0.2960510552,-0.7850624323,-0.6174619794,1.1621369123,0.5564032793,-0.7371488214,-0.3468227684,2.3980824947,-0.1111919731,-0.2277705222,-0.6066004038,1.5664755106,0.8420552611,-1.3558931351,-1.0245736837,0.8999151587,-0.5651986003,-0.8465386033,-0.4856346548,-0.9645081162,0.1725240499,-0.7497085929,0.9174042344,-1.7963420153,0.0882364661,0.5786577463,-0.0313097350,1.8228253126,-0.1195402592,-0.3144756854,-0.7695646286,0.6737496853,1.7059468031,0.1110388115,-0.1290749758,-0.7515364289,1.1298259497,-1.9274809361,0.2750416994,0.9833395481,0.0931785628,0.5955570340,-1.3676586151,0.5912148952,-0.6878173351,-0.2396046817,0.4571484029,0.3076282442,-1.1353645325,0.5450010300,1.2716612816,-0.7891782522,-1.1442798376,0.5127852559,-0.3669523299,-0.8581065536,1.3917527199,-1.8237631321,0.1568117738,0.6871304512,-0.8506605029,-1.0436689854,0.7592877746,-0.4107601345,-1.4867564440,0.6242988706,0.4792506993,-1.1623834372,1.2963851690,1.8081043959,2.4934203625,-0.2422652245,-1.7136925459,-1.8513816595,-0.8949121237,1.1286860704,0.3440145850,-0.4634765983,-0.0613686703,1.7311720848,-1.2469245195,1.2263395786,0.3082263768,0.2303123176,1.1889343262,1.2646365166,0.0945713371,-0.1564330161,-0.1214945167,0.6576443911,-0.8273627162,0.1350538135,0.2720624208,-0.1212793067,0.7692606449,-0.7661889195,0.6638042927,1.2159714699,-0.6703962088,0.4307232499,-0.5342184901,1.0875924826,-0.5991690159,0.3697001636,1.0889072418,-0.2163190544,-1.2570856810,0.6826377511,1.3048549891,0.8470559716,0.3935773671,0.7606564164,-0.9260808825,-0.3522996008,0.4411866665,1.0888419151,1.8529471159,-1.0159670115,0.1586700678,-0.2941544652,-0.7677201629,0.6702014208,3.0485541821,-0.7110427618,0.0087685026,0.2127590925,-0.6027239561,1.8547546864,-0.9267640710,-0.9728785157,-0.5564861894,0.1114080474,0.6857814193,0.5599179268,1.0410881042,0.2579667568,0.9110988975,-0.9568061233,0.1526732743,-1.4196509123,-0.7998716235,1.2206411362,1.0975108147,0.8231616616,-0.0641085878,-0.6946839094,1.6023092270,-0.6245922446,-1.9093415737,1.3474690914,1.4625424147,1.6814835072,-0.1330091953,-1.6498638391,0.0761528090,-0.4358590245,0.2756622732,-0.8825276494,-0.3384377956,-1.3949745893,1.0857973099,-0.4014986753,-2.3074398041,1.1703572273,2.3323669434,-1.2561129332,-1.0790011883,-0.7676408887,0.3213644028,1.0556669235,-1.2354131937,0.6065539718,-0.6644827127,-0.8000290394,0.0954485089,0.3187395930,-0.6467474699,-0.3926055431,-0.8689112067,-0.3884165287,-0.4145347476,0.0493419617,0.2418716103,-0.3547745347,0.6621610522,0.8859947324,-0.7657930255,-1.9621956348,-0.6089704037,-1.1985352039,0.7472391725,0.6400617957,-0.4264973700,0.2084112614,-0.4279962480,-0.1868031621,-0.1573167592,-0.1913782507,-1.0503474474,0.1423900723,-0.7872502208,1.3039880991,0.2708427310,2.0053474903,0.8214874268,1.5796195269,-0.7677533031,0.6795278192,-1.0888278484,0.7510353327,2.0150184631,-1.5912657976,0.8089207411,-0.1970883459,0.8027809858,-1.2548944950,0.5105749965,0.4831301868,-1.5909609795,0.5785495639,1.3184320927,0.0695535466,-0.2157524079,-1.7929224968,1.2852239609,0.4923533201,0.3263441026,-0.9354546666,1.4339323044,0.2739963531,-0.0995752290,0.2425071448,0.5357111096,0.4545810223,0.5341140628,0.0805591345,1.3591556549,0.1434901059,0.2359346896,-1.2574553490,0.3136060238,-0.4058042765,-0.8217685819,1.3852506876,-0.9113008380,0.7037917376,-0.7449426055,0.9320917130,0.8437697291,-1.9806908369,-0.0670251027,0.5133256316,-0.4757016003,-1.2597001791,-0.4355548322,1.3151249886,1.1659435034,1.6419327259,-0.6083964109,0.4444638789,-0.4170851111,-1.5645383596,-1.3208391666,-2.3012502193,-1.0070270300,-1.3298571110,0.1743980348,2.5718021393,-0.6891092062,-1.6248441935,-0.5891755819,1.6138558388,-0.0993815511,0.6511113048,-0.2385976166,0.6658123732,-0.7941064239,1.3413614035,-1.2250225544,1.1066839695,-0.7866426706,-0.7299267054,-1.1541323662,2.5609581470,0.5317540169,0.3519812822,-0.6689489484,-0.1380787790,-1.1013877392,1.0932749510,0.9128538966,-0.9880322218,0.7098346949,-0.3154917657,0.6754376888,-0.0766175464,-0.3399885595,-1.0069338083,-1.2817411423,0.1082873270,1.1880060434,-0.3071840405,-1.3175830841,-0.3208683729,-0.7482139468,1.1091876030,0.0395907052,-0.0068238205,-1.8176137209,-2.2272694111,-1.0444130898,1.7971816063,-1.3809732199,-0.8909279704,1.7548052073,-1.9525624514,-0.4300846159,1.0891311169,-0.3463200033,-0.1930101216,0.8065233231,0.1266611665,-0.4590313137,1.0066936016,0.9566790462,-1.7197459936,1.0318695307,-1.4141339064,-0.0097696707,-0.1190411523,2.0956239700,0.4579995573,-0.6332737207,-1.4304943085,0.9629821777,0.3824220598,-1.4023016691,-0.5606012344,1.1431181431,-1.8398458958,-0.0627954900,-0.6901521683,1.6339272261,0.2412263602,0.1537550688,-1.1139428616,0.8870545030,-0.1872967929,0.5684547424,-1.0961941481,-1.1251753569,1.1886631250,-0.4543816447,-0.7960464954,0.9073171020,0.6863700747,-0.4552413225,1.5016720295,0.0206240546,-0.5202254653,0.5245888233,0.3571237922,-0.9080306292,1.0753819942,1.7178027630,0.7182201147,-0.5630775094,-0.0887095183,0.1610158384,-0.9418390989,-0.3211406469,-0.5363221169,0.6615352035,0.7728872895,0.5593809485,1.5761929750,0.4294976890,0.4844272435,-0.8199804425,-0.6379592419,-0.8718496561,0.4785815477,-1.6744025946,0.7056298256,1.1006934643,-0.3888773322,0.6314990520,-0.3749686182,-0.5715098977,-0.9321445823,0.6626054645,-0.1253063679,-0.6241140962,-2.5891406536,0.4141782820,-0.6123164296,0.5643692017,-0.7155497074,0.5605821609,1.6867932081,0.1108570546,-0.4897870123,-0.6119366884,-0.0666864291,0.4495974481,0.0085499445,-2.1522080898,-0.7636897564,0.2133529484,0.4067107141,0.8969731927,0.7151698470,-0.4244272411,1.2850111723,0.7844523191,-0.1529647559,-0.1405523121,0.3252138495,0.2649473548,0.5022157431,0.0850721747,-1.4688378572,-1.3880082369,0.6504700184,0.6187646389,-1.3998051882,-1.2288914919,0.1766103208,-0.4094978273,-0.2433090359,2.1143550873,1.4301925898,-0.4404291213,-0.0626156554,-0.4196424484,1.0478527546,0.9831517339,-0.4679268897,0.3133228123,-0.9002415538,-0.7844398022,-0.3946162462,-1.5743603706,0.6414580941,-0.2618705630,0.6462222338,-0.6590774655,1.0195286274,1.0634303093,0.0653074756,0.7577853799,-0.0516320206,0.6106615663,-0.4302142560,0.8421626687,-0.2350383252,-0.8129963875,0.5303506255,0.7106423974,0.0993085951,0.2506384850,0.9918402433,0.8889755011,1.3261528015,-0.2485965937,1.1315611601,-2.1970417500,1.4103869200,-0.4955347478,-1.8461620808,-0.0154520124,0.2505555451,-1.5311112404,-2.5265429020,-1.0538671017,-1.6120213270,-1.6950901747,-0.5707432032,-0.3110536635,0.0624820627,-0.1097832322,-0.5843027830,1.3145704269,0.2922441363,-0.4884521663,0.1748099029,-0.8954635262,0.8497131467,1.3345705271,-1.5859323740,0.1828643680,0.0375167504,1.4893962145,-0.8841351271,0.1239212006,0.1301903278,-0.2170444280,-1.4712740183,0.2646017671,-0.1447753906,0.9968265891,0.0993815586,-0.6090484858,-1.3570221663,0.7227269411,-0.0219510533,0.7023817301,0.0429944210,1.1319042444,-1.0029493570,-0.9856308103,-1.9643776417,-0.6212342381,-0.5674418211,-0.2722060084,0.5762308240,-1.7308312654,-0.1668733805,-0.3293681741,-0.3582380116,-1.1411564350,1.1042435169,1.6444514990,-0.4203042686,-0.7046890855,1.9541190863,-1.5065824986,0.1620152444,-1.4102603197,0.4765975475,-0.2991090417,1.2118850946,-0.3334017396,0.3071345687,-0.6667149067,1.2665424347,-1.2411324978,-0.3781921864,-0.1119469181,0.0351102464,-0.1019369289,0.0713379160,1.8285521269,1.1005022526,0.3116882145,0.7197256088,1.1275570393,-0.1129998118,0.3050722182,0.1734147966,0.2428309172,1.0162949562,-0.5538579226,1.0453534126,-0.2064165026,0.2954626679,1.1894056797,1.6967473030,-2.0918354988,-0.5620151162,-0.6162993908,0.1899436861,-0.1020427197,-1.0234582424,0.4789095521,0.0332386084,-1.4767955542,-1.9037156105,1.2354108095,-0.0018077961,-0.9863997698,-1.2346477509,1.8885161877,0.2936889231,0.8233779669,0.0891269967,0.4238564074,0.4432381392,-0.8548453450,0.3422487080,1.9250447750,-0.8454698920,-0.6730789542,0.1415164173,0.1184886545,1.3533905745,-0.2967815101,1.1134816408,1.2478499413,0.1484726369,0.7938684225,-0.0986338928,-1.1890305281,0.2958755791,0.1388797909,-0.6163766384,-1.4716683626,0.8207072020,-1.1493715048,-0.2178318650,-0.9332431555,0.0315085016,1.5580168962,-0.3341762424,-1.3798252344,1.9283100367,-0.2898777425,-0.9559110403,0.7655615211,-0.4317200780,0.4280168116,0.7353171706,1.4805815220,-0.2730192840,1.7999408245,-0.6273670793,-2.6943187714,-0.6990944147,1.1060009003,0.8578431606,-0.0840007663,-0.5585980415,-1.2817488909,-2.4378654957,1.6060805321,0.8997866511,0.6551699042,-0.3740907013,1.3194372654,-0.4168642759,-0.8414853215,-0.7929033041,0.3561357856,-0.3539623916,0.2779755890,0.4590013325,0.5880220532,-0.2773589492,-1.8300926685,1.2118127346,-1.0504593849,-0.9004604220,-0.0812280998,0.2696877420,0.0787571594,0.1149807945,1.3142724037,-0.1294342428,-1.7291231155,-0.0914452523,0.1939240694,0.6503858566,0.3664641976,0.7926014066,-0.2039321363,-0.4512749016,-0.5041785836,0.1370467991,-0.3436326385,-1.7019400597,1.3645384312,-1.0790003538,-0.0885153338,0.7273120880,-0.0962846130,-0.3853226304,0.9186987877,1.6411539316,0.0192694329,0.9914398789,1.0116108656,-0.2402564734,-0.2873272002,-1.0821862221,-1.9422683716,-0.5636457205,-0.9914990067,0.7986121178,-1.1720125675,-0.8651517034,-1.0168634653,1.3929049969,-0.5326869488,0.2972522676,-0.7363356948,-1.0323220491,0.2945378721,1.2807190418,0.2211526334,-1.8246880770,0.2985337377,-0.1622590274,-0.5336527824,0.5530636907,0.9003993869,1.0602345467,0.5563013554,-0.4820825756,-0.3741382360,1.2548416853,0.5277336836,1.0442218781,-1.0164369345,0.9119832516,1.8069756031,-0.8453161120,-0.6892279387,-1.9548838139,0.5399494767,0.5839894414,0.6357702017,0.4068482518,-0.8281987309,0.7952207923,-0.5682151318,0.6527551413,0.4371876717,-0.8736358881,0.7888579369,-0.2305625677,0.3886904716,0.4261684418,-1.7041398287,0.1460140944,-1.3941833973,-2.3413891792,0.3794504404,-1.5065003633,-1.0899549723,0.5814636946,-1.8431659937,-1.9167656898,1.0604321957,-0.6192001104,0.1313293129,-1.9399279356,-2.5218393803,0.8841423988,1.4313941002,-0.0698332638,-1.7999757528,-0.5638673902,-0.0389924608,0.8049888015,-0.9703688622,0.3512552083,-0.2308388054,0.1044155210,-1.2669880390,0.4026793242,0.9971115589,-1.0468974113,-0.1251971573,0.1129145920,-0.6320928931,0.7838298678,0.4312362075,1.1978577375,-0.6947177052,-0.2477532178,0.4473966956,1.3458278179,-1.3238114119,1.2147200108,-0.3629972637,-0.1120925844,-1.6106210947,-0.6715474129,-0.3695737123,-2.1063737869,0.3464091718,-0.1429023743,0.0154739022,0.2679836154,-1.3591574430,-0.4414421618,-0.5401853919,1.2818124294,-0.8664167523,1.2607386112,-0.5515830517,0.0223816186,-0.9567921758,2.1468987465,0.4018232524,0.3902551234,0.2271844745,-0.7034388781,-1.1465339661,1.3632919788,0.7479792237,-1.4447779655,-1.3149640560,1.6014412642,0.8386735916,-0.9777460694,0.0764696151,0.8212373257,0.7903966904,0.2094957680,1.1794633865,0.3876317143,0.2945517600,-2.2883436680,-1.4445925951,-0.0050359364,-0.0154747693,-1.0497438908,-2.1858596802,0.3199483752,0.4688971639,1.3384841681,-0.1049553305,-3.5104098320,0.0139802890,-1.0582283735,0.0157511942,-0.1317526698,0.5070823431,0.2266791016,-1.0741680861,-3.3275530338,-0.1029340774,1.3333551884,0.1533930302,-1.3400937319,-2.1410186291,0.6519215107,0.0122133074,-0.0897119120,0.7088866830,1.3721456528,0.7374876738,-0.1000189185,1.3357746601,-1.4139446020,0.6488098502,0.5202904344,0.3015293181,-2.3389220238,0.8091678619,0.6978511810,0.9705064893,0.3247336447,0.0050228359,-0.8070387840,1.5278664827,-1.6689298153,0.7235268950,0.3391357362,-0.4543726444,0.7102225423,0.0603245422,-0.2386469692,-0.1376174837,2.2262902260,0.7978293300,-0.1623223573,1.3508191109,-1.1919469833,0.5105102658,-1.2463465929,-0.7253215909,-1.5177099705,-1.8005180359,-2.0953040123,-1.4494000673,2.0138463974,-0.9422380328,0.4424597621,-0.1397095770,-1.1371566057,-0.0423600972,0.1930373460,0.2709112763,-1.1953920126,0.5570302606,-1.5900931358,0.4856736660,-0.5310302377,0.1510527581,0.3505887687,0.6495220065,-0.3104924262,-0.2100895643,-0.6556578875,0.0484873876,-0.4949260950,-0.5762988329,-0.0790554658,-0.8858715892,-0.7482577562,0.4565393925,0.8495110869,0.5410699844,0.2003258765,1.1066104174,2.4233675003,1.1743931770,-0.3243298531,-1.0906335115,-1.0359903574,1.1506870985,0.8038827181,0.0065249666,1.2016972303,-0.4348216951,0.4592243135,0.9285517335,-0.9519800544,0.9002231956,-0.0417470746,-0.6550382972,0.3652853668,-0.4817460179,0.4155755043,0.2305550873,0.0383341387,-1.3802094460,-1.0148710012,-0.4687513411,0.2466093600,-0.0788045675,0.3197855353,0.0394861288,-0.9513927102,-0.0540379882,-0.9681669474,-0.6324351430,0.1304977834,-0.1444966942,0.4706237316,0.3779866993,0.2013960183,0.2234681100,0.4384725988,1.8610857725,0.1288777292,-0.5215864182,-1.0086157322,0.7050257921,0.7817319036,-2.3805580139,-0.2110639066,-0.3800990283,-1.5330798626,0.8230214119,0.2022407502,1.2536604404,-0.3143420517,-0.3846403956,0.8717328906,-0.2717157006,0.2214356810,-0.7705176473,0.7046155334,0.6591244936,0.0442096666,-0.8060303926,1.8267966509,-0.2754566073,-0.8256037831,-1.5357751846,-1.0315228701,-0.8241909742,-1.0270508528,0.3138917387,-1.6600333452,-0.3888295591,0.0759017095,-0.5470116138,0.9134837389,0.9181766510,0.6794993877,1.8896580935,1.2877893448,-0.5754200220,0.1308063716,0.6196119785,0.2646083534,1.3591319323,-0.1376973838,-0.4108622372,1.0915858746,-0.4022491574,-0.2787691951,-1.4625638723,1.5055365562,1.3839673996,0.3047131300,-0.1136100814,0.0511076674,0.9380768538,1.2948635817,1.8470802307,0.0492418595,-1.2036857605,1.1663081646,0.4418370724,-0.2655751109,-0.9233930707,0.8207384348,0.5034034252,0.5235258341,0.9936625957,1.0459955931,-0.2367948443,0.4002315700,1.7345780134,-1.6753051281,0.9616335630,-0.5974237919,1.1064232588,1.8339977264,-0.2873453200,-0.2717796862,0.6485736966,-0.7970598936,1.2907695770,-0.1626946926,1.3069441319,-0.6765155196,-0.8155764937,-0.4989302754,1.5502585173,0.6216536760,0.3171115816,-0.9816764593,0.2284350544,0.1353972405,-0.7532781363,0.5987361670,0.2846145630,2.6697471142,0.8273726106,0.3656917810,0.3345196545,1.3987786770,-0.6768500805,0.9154971838,0.9169610739,0.6782941818,-2.2053909302,-0.2868286967,1.4951024055,1.3020434380,-0.1167226881,0.5561181307,1.3928959370,0.8201711178,-1.3544884920,0.7482158542,-0.9934462309,-0.7618706226,1.5368840694,-1.0926820040,-0.7544658780,-0.7657099366,-0.2162702084,-0.6240744591,-0.6869540811,-1.3244251013,-0.0615085214,-0.2740594745,0.7680806518,0.5850219131,0.7697795033,-0.8452374339,-0.2424748093,0.8591217399,-0.1297827959,-0.3272397220,0.5281672478,2.8159592152,0.0707529411,-0.0019932245,0.7365709543,-0.1870024353,-1.0456169844,-0.0245733839,0.3742526472,0.0466749147,-0.9359126687,-0.5803662539,1.2145210505,0.2210874259,0.8019478917,-1.6911070347,-0.8182746172,-0.7799111605,1.5378501415,-0.0670324489,0.5352994800,-0.9907878637,0.0810974091,0.0742879882,-2.1321122646,-0.2070179731,1.0230563879,-1.4774166346,-0.0569191352,-1.1915849447,1.2854273319,0.5736584067,-0.3161622286,0.0788122043,-2.6321368217,0.7516192794,-0.6747380495,1.7880039215,0.0600294322,0.8084431291,0.8202488422,0.7850489616,1.7138910294,0.8183184862,1.3371344805,-1.0704429150,0.7927608490,-0.7731685638,-1.5480746031,0.9363201261,-0.8637107015,-0.5787624121,0.5742868185,1.2831314802,1.1431300640,-0.1921418905,-0.1575302482,0.7531200051,0.1107663810,-0.1392740458,0.1642324924,1.1048551798,-1.0657318830,1.2152526379,-0.0280989539,1.4245631695,0.3038326204,1.0398333073,0.5144931078,1.3959500790,-1.4316306114,-0.4561814964,-0.5418317914,-1.2976498604,1.6599001884,0.6544582844,0.4120349586,0.1889998317,-2.0116407871,0.0190515742,-1.0315045118,-0.2084806114,-0.9521855116,1.3717107773,0.8201537132,1.2848557234,1.0412549973,1.1097702980,-0.7424427867,-1.3213529587,1.4162770510,-0.2218238860,0.1572814584,0.0420207120,0.8158637285,0.2443248034,1.5342217684,1.2111642361,0.7858352661,-1.0876142979,-0.3700317442,-0.2657727301,0.4492015839,0.0319982916,-1.0240249634,-2.5414311886,0.1361544430,-0.2829069793,0.5869057775,-0.8466492295,1.4590594769,0.6824162602,1.3178961277,0.1956192702,1.9053285122,0.2270766795,0.8468378782,-1.1426655054,0.1628837287,-2.0766322613,0.3954115212,-0.7994513512,0.8160585165,0.2688303888,0.6566452384,1.4310846329,1.2181339264,-1.1336773634,0.7861024141,0.6040832400,1.0225002766,-0.0625130981,-0.9539570212,-0.5392764807,-0.9254257679,-0.8865107298,1.5495288372,0.3416455984,-1.4592988491,1.1174447536,-0.8456580639,-0.2513967156,1.6444369555,0.4698045254,-0.3425119817,0.4703255594,-1.1068733931,-0.6331372857,0.0833904520,2.0509891510,1.1461318731,-1.4606683254,-1.3410766125,0.0828015357,0.8186067343,0.3983367383,0.0698770657,0.4072398841,-0.0359241553,-0.1619289368,0.8406882882,1.8046275377,0.1601787359,0.6465020776,1.1391314268,0.0097278478,-1.3131502867,-0.8829632401,-0.5586873889,-0.8721792102,-1.7141357660,-1.6847779751,0.9566531777,0.0900609344,-2.1673758030,-1.5872809887,-0.4245087802,-0.6903084517,-0.3588181734,1.3054128885,0.7735430002,-1.5612035990,0.0641486570,1.7226607800,0.4291057289,-0.8341003656,0.6271658540,0.8506008387,-0.6141491532,1.2932060957,1.0017577410,0.9150823951,0.9628162980,0.2699362934,0.0677945018,0.6238765121,0.8336200118,-2.0658693314,-0.8160885572,0.6131067872,-0.6992746592,0.0867898762,-0.9291868210,0.3126922250,-1.0321285725,1.1907221079,-0.8579597473,0.3683812320,0.0951150134,1.4797778130,0.1138498932,-0.1657631844,2.1404304504,0.6909690499,1.0141973495,1.3627005816,0.9600053430,-0.2231254727,0.8661641479,0.6439171433,-0.3375835419,-1.4438884258,0.5471693873,0.2623979449,1.4910924435,0.1808727682,0.0957317352,1.1674259901,1.0773286819,-0.8375552893,-0.1509543806,-0.3889933527,1.2889469862,-1.6503235102,-0.6901810765,1.3719030619,0.2788748145,0.2398491651,-0.1003404036,0.2019098103,0.8351427317,-0.3547764421,0.0477411337,-0.2419873178,1.1113913059,-2.3828821182,-0.3928278089,0.2063228041,1.4378747940,0.6241122484,0.6654278040,-0.8381136656,-0.1943056434,0.8262708783,-0.8781173229,0.7365460396,-0.2867861390,1.0262185335,-1.0862541199,-2.2211563587,-0.0351699404,-0.1053142026,1.0903381109,0.0490656979,0.6290349960,-0.1448164582,-1.0651451349,-0.2358892411,-1.5510635376,-2.0036041737,-0.8184807301,-0.7312480807,1.6621870995,0.0102839842,0.0925677046,1.7449682951,1.3801565170,-0.6567270160,0.5415236354,-0.2259770483,-0.6260111332,1.5308971405,1.0322775841,0.9775959849,0.1011903435,-0.1734205186,-2.5078294277,1.1471949816,-1.0667153597,-0.1465885788,-1.1242318153,-0.6100597382,-1.3902848959,-0.9408340454,-0.5747480989,-0.7050228119,0.2044974118,0.1679736227,-1.5893906355,1.6384850740,0.0945908651,-0.5734204650,-1.4962567091,0.8425856233,-0.7955751419,-0.7523640990,-1.3928989172,-0.6434774399,-0.0267408527,-1.3192676306,-1.1446229219,0.8909816146,0.7566283941,0.4858905971,-0.4653729498,0.2230161875,-0.3106475770,-0.9960952401,-1.9371960163,-0.0624998100,0.2280373722,-1.4546812773,0.7684928179,-1.3647917509,-2.4256286621,-0.8073800802,1.0723882914,-0.9055548310,0.8978029490,0.3257782757,0.6538295746,-0.2891353965,-0.1892136186,2.2979393005,1.4039591551,-1.9162375927,-1.5704979897,-1.2596937418,-0.5759724975,-2.3971576691,-0.5725220442,-0.8249366283,-0.3085795045,0.5204046965,-1.2902706861,2.2250847816,-1.3025299311,-0.5453331470,0.4720706940,-0.6122683883,-0.6175191402,1.1907383204,-0.6027181149,-0.1497769952,0.3475134373,0.0696816221,0.4372898340,0.6333782673,-0.1903668344,-0.5238707662,-0.2407862246,-1.7575255632,0.6175248027,0.4117534757,0.5725713968,-0.1537111849,-0.2685767412,-0.1302557737,0.6916129589,-1.7661845684,-1.2384231091,-1.5353415012,-0.8544256687,0.8948006630,-0.8968293071,0.4587621093,-0.6570677757,-0.6455622911,-0.3647587895,0.6582919955,0.0151019888,0.6143096685,-0.4849007130,-0.0224776696,0.8556644917,2.1596455574,2.0912363529,0.6864846349,1.9000794888,0.3535133600,-0.4887687564,0.2296750844,1.7741783857,0.8200288415,-2.3570518494,-0.6121400595,1.1244128942,-1.9312944412,0.2823550999,0.2266518772,2.0878908634,-1.7262382507,0.3788723648,1.0462868214,-1.2126829624,-1.5116736889,1.8529467583,-0.1404440552,-0.1386186481,-0.7274141908,-0.9291960597,-0.7300670147,0.5603982806,0.3851436377,-0.1989250630,3.1476488113,-1.4545503855,0.2226756215,0.6318311691,-0.5034347773,-2.0605225563,-0.2405045331,0.7324491143,0.2608508170,1.1732854843,0.3615217805,1.1910451651,1.1258134842,0.8236389160,-0.1661823541,2.0450708866,0.1467454135,-2.3809611797,0.4373816252,-1.4531396627,0.8588591218,-0.1570577621,1.0039044619,0.2207947969,1.0857644081,2.3349044323,-0.4538405836,-1.0556931496,-0.1135712489,-1.3338731527,2.0147054195,0.5743921399,-0.0406258553,1.0636233091,-0.7739616632,-0.4744435549,0.6629287601,0.6593925357,0.2389109284,0.3244543970,-2.4939632416,0.2376910746,0.2401821762,0.1714852750,-1.6680035591,-0.2254704535,0.1158540174,-1.5890207291,-0.0886749774,0.8084253669,0.2941642106,-0.2246614844,-0.6902972460,-0.9486091733,0.1864258349,1.3744177818,1.2856972218,0.0242699496,0.7165759802,-0.7738999128,-1.5016100407,1.3694467545,-0.5406073928,-0.5955885649,0.8310559988,0.7758463025,0.0332392007,0.0597205423,0.7009345889,-0.1214630902,-1.2265552282,0.9551652670,-0.9825314283,-0.0588454418,1.3474606276,0.2749947906,0.7564658523,-0.9267882109,0.2939739227,-0.7862483263,0.3147085011,-1.0929533243,-0.4037205279,0.1726106852,-0.9854048491,0.8076828122,0.5334472060,-0.5711045861,0.2277940810,-0.3884009719,0.0958303660,0.4074799716,-0.1783480793,0.6015118957,-0.2043264210,0.6595416665,0.5929055214,0.2067304552,-0.4159007668,0.0456653237,-1.0317988396,-0.0439903848,0.2529656291,-0.5262223482,-0.0891434103,-0.5803508162,0.2372836471,0.1403294653,-1.1127064228,-0.7271862030,-0.3711755276,0.4906193912,-0.9802835584,-0.4931763113,-2.4230916500,-0.6911710501,0.2911610901,-0.3813099563,-0.9066234827,0.4782035351,0.0682695433,-1.2720994949,-2.0620915890,-2.0388426781,-0.8398178816,0.1875489354,-0.6239607930,0.1227937043,-0.8136839867,-0.4940828085,-0.2377815545,-1.1428968906,-1.3174897432,0.2686184347,0.2657438219,-0.0437186994,1.7247594595,-1.2954945564,-1.5489299297,-0.0903909281,-0.2665699422,0.8504773974,0.9000029564,0.1670958251,0.2365684360,-0.6508274674,0.6521868706,-1.2457232475,-0.4461270869,0.0367440879,0.8848665357,0.4277692735,0.4192968607,-1.8041940928,-0.8850283027,-1.4226913452,-0.1611105055,1.5754060745,-0.7368183732,0.8704988360,0.5925328135,0.3334204555,2.3063228130,0.5068302751,0.6421422362,0.2884857357,-0.6937939525,-0.4742089808,-0.5211635232,0.5846737623,-0.6871022582,-0.5160235167,0.4397167861,-0.1327747852,-0.3461024463,0.8904767632,-0.3413029611,-0.7286113501,-0.3106502593,-1.1513842344,-1.4070318937,1.4902381897,0.7819204926,-0.5711467862,0.9897950888,1.0421978235,0.0064553972,0.2257383913,-0.5662776232,-1.6784616709,0.1300082803,0.3907846808,-0.1842308342,-0.5939362049,0.4409166574,-0.4065026641,-0.2743496001,0.2813808620,0.3920689821,-1.1994462013,-0.4680491686,0.3003554046,0.8930982947,1.3606835604,-0.8178442717,-0.9329233766,0.8158513904,-0.2013928294,-0.7077201009,1.0480406284,1.7602568865,1.0767135620,-1.1549855471,-0.4318770170,0.2878724635,-0.1249971166,0.0026210824,-1.9303877354,0.2099825144,-1.8180750608,-0.5248698592,0.5573206544,-1.3221145868,2.1918184757,-0.1596627235,-0.7318202853,-0.3619192839,-0.2752758861,-1.1489162445,-1.0136946440,0.8739019036,-1.1305433512,-0.6433794498,2.3157281876,0.4867565036,0.2869711816,0.7111119628,-0.7375450134,-0.2039852291,-0.2768211663,1.3463346958,-0.3390847147,-0.6786736250,-0.7262747884,0.8902787566,0.9133289456,-0.2505047619,-0.0415848196,-0.3829526007,0.5145270228,0.5090532899,-0.8748589754,0.5908644795,-0.8097217083,-0.6209503412,-1.6769145727,-0.7063034773,-0.0019511768,-0.7479312420,-0.4937320054,1.2623711824,-0.0325878747,-2.1162991524,-1.3957357407,-0.4022807777,0.2463667393,-0.2883108854,-1.0714792013,1.3542736769,0.3475864828,1.1947330236,1.4123615026,0.4734445214,-0.0291386191,-0.7498828173,1.8264600039,0.8586798906,0.8935324550,-1.2798057795,-1.2434326410,1.4402679205,-0.3074516356,-0.3824082613,0.9012572169,1.3327422142,2.0704622269,-0.7559067011,-0.6273303628,-1.3138438463,-0.5460834503,-0.1313429028,0.3516915143,-1.2709006071,0.2318837494,1.3678478003,-0.5695576668,0.9467203021,-1.0783817768,1.8729202747,-0.0971904844,0.0755688325,0.0776100382,2.0316021442,0.1603736281,0.5459352136,-0.9726063609,-1.1684632301,-0.6058312654,-0.8898193240,0.2162799835,0.2188819796,0.6266080737,-0.9264500737,-0.3930732012,1.2791380882,-1.4856559038,0.6038267612,-1.5345782042,-0.8310987353,-1.1575284004,-1.6151446104,-0.3164165914,1.6876577139,0.3008544147,-0.0813643858,2.1535699368,0.6083881855,2.0528795719,1.0854481459,-1.8040492535,-0.8503279090,-0.9169733524,-0.7187844515,-0.0188348703,0.9217076302,-1.1328121424,-1.0641452074,0.6557211876,1.6046416759,-0.8734141588,-1.1367805004,0.7530630827,-1.2990561724,-0.0882783160,0.0793868899,-0.1091432571,-1.5902625322,0.3879348934,0.0378575362,-1.3857095242,0.0273315851,2.5557720661,0.2602879107,1.6669652462,0.0515464433,0.2788645923,-0.4719827473,0.6808572412,-0.5266553164,1.5635540485,0.6531999111,0.5617042780,0.3659709394,1.2030426264,-0.3417057991,-0.3226774931,0.9697617888,1.1391057968,0.6558498740,0.2402107716,0.1402628124,0.0865132883,-1.1623040438,1.4959161282,0.4355273247,-1.5472781658,-0.1442041993,0.4357748032,0.3796449900,-0.1988835186,1.2006313801,-0.3266404867,0.4909732342,-0.1155063435,0.7805097103,-1.5917422771,0.2558749318,0.0028779260,-0.9973745346,0.3408148885,0.6907517910,1.7726098299,1.2931444645,0.0731726885,0.0033546537,-0.5160992742,0.9919461012,-2.0193617344,0.0540464595,-1.0469379425,1.8422071934,0.2026942223,-0.2223332375,-0.8785908818,-0.4768011868,-0.6508824229,1.4654546976,1.9984804392,-0.3018554151,0.5743958950,-0.9103906155,2.3126950264,1.1369340420,-1.1978269815,-0.5591164827,-1.3324406147,1.4774297476,0.4085949659,1.0875927210,1.2534742355,-0.2782524824,-1.2699588537,0.2338881344,-0.1154674813,1.3444168568,0.5542261004,0.5446771979,-0.7692145109,-0.8970652223,-0.4507069588,1.7428719997,-0.4185885191,-2.0615775585,0.5384839177,-0.1812524796,0.5966222882,-0.0884481892,-1.3890218735,-0.5953192115,-0.8984060884,0.2904509902,1.3895179033,-1.2992860079,0.3779320717,-0.0900823697,0.1684620082,-0.2983181477,0.7044838071,-0.3086249530,-0.4766749740,-1.6568388939,0.3046866953,1.1033426523,0.9387074709,0.5648691654,1.1102232933,-0.5370892882,1.6050131321,0.3298608363,0.8434912562,1.5994970798,0.3545402586,-0.9816116691,0.5793850422,1.8203120232,0.6507356763,-0.6160635948,-0.4756502509,-0.1226160377,-0.4512326717,0.9120926261,-0.0639616176,0.6028991938,-2.1917812824,-0.7067122459,-0.1262857169,1.8095263243,-0.6735818386,-0.0236892402,-1.2794020176,-0.3109898567,-0.4389147758,0.1079273149,1.0574131012,-0.3642730713,-0.5820379853,-0.0673111752,0.6866626143,-0.9802171588,-0.4072963893,1.5017372370,-1.3176370859,0.0456849113,0.6719582677,-0.6977844238,-2.4139885902,0.9166274071,1.9176933765,0.0757182539,0.2686379850,1.2910649776,-0.5725409389,0.0763535500,-2.0364468098,0.0009822916,1.2169647217,0.5885798931,-0.9567729235,0.0846289247,1.2598075867,-1.2678459883,1.2660022974,0.5127959251,-0.3129904270,-0.7242843509,-0.2958310246,0.2941564023,0.3908843100,0.1993192434,0.8601083755,-0.0118097821,2.9144937992,0.5598602295,-0.7121825814,0.6126078963,-0.4042938352,0.2696480155,0.7432195544,-0.3382290304,-0.3175045848,-1.0074145794,-1.1684331894,0.0796425790,-0.4121067822,0.4740624726,1.3114098310,1.0700200796,0.1490948498,0.6387857795,-1.7708073854,-0.9917168021,-2.5573399067,0.6741188765,-1.3366583586,-0.5455180407,-0.2197612971,-1.4311057329,-0.6745821834,-1.5028071404,1.0440351963,0.7176719308,-2.6579515934,-1.0510629416,-1.2848021984,-1.3853023052,0.4791358113,2.5045385361,-0.4729622602,-1.2650476694,-0.7059856057,-1.0171307325,-0.7169947028,0.1002878100,-0.3277071118,-0.2671995163,0.5931706429,0.2614943087,-0.1734369695,0.0991713181,0.1256472766,-0.3000682294,0.7157314420,1.0789563656,0.2905321717,0.0915650576,-0.2459096760,0.9417273402,1.1695841551,-0.4629750252,0.6636813879,1.2860013247,0.1320593655,-0.4724427462,-2.4939298630,0.8686680198,0.7980304360,0.0212606862,0.0895598605,-0.6142240763,0.2135329247,1.5683747530,-1.3909196854,1.9122843742,-0.1695288122,1.0792137384,0.2949759364,2.9196517467,0.1250986755,-0.9956979752,0.8259578943,-0.4130439162,-1.5986818075,-1.3872983456,-0.3145367205,0.1179488599,-1.7167025805,-0.3398543596,-0.2405494601,0.1653799564,2.2529299259,0.1527817100,-0.0522611253,1.6368466616,1.5746954679,-0.6853815913,0.7834398150,-0.4030088484,-0.9495356679,1.5865054131,0.0136783160,-1.1354285479,1.2099617720,-0.7505401969,-0.3670379817,-0.9019443393,-0.0718230233,0.3455559909,-1.0303230286,1.2956593037,-1.3617696762,0.6880182028,-1.8390884399,1.1746094227,0.2042525560,1.8721073866,-0.2429490089,-0.9037572145,0.4598532319,1.4084200859,1.4145408869,1.2590812445,0.4491093755,-0.2917197943,-0.1804877669,0.3747444153,-1.2223923206,-0.0042179539,-0.0286030844,-2.1629972458,0.8808540702,-0.4634902477,-0.4097259641,0.1188818812,0.8841651082,-0.7411962748,1.3089855909,0.2433037907,0.2072167397,0.0030417852,-0.4322900772,0.0580277666,-0.8421820402,-1.1227341890,-0.4095312059,-0.6351722479,-0.9240295887,0.1515339166,-2.7080621719,-0.8268998861,0.6793233752,0.0793776214,1.5474833250,0.0869547799,0.4061647654,-0.1170388460,0.7532392740,0.2103636712,0.2250218242,-0.3768270612,0.3614977598,0.9480288625,-1.6463083029,0.4892472327,-1.7122375965,0.5919700861,-1.8297494650,-0.3791226149,-0.4474929571,-1.0941311121,-0.6403060555,0.1746183336,-1.7660150528,0.0863045081,-0.5001140833,0.6139918566,1.6994225979,0.1999011487,-1.9983192682,-0.7136126161,1.4435380697,-1.1255981922,1.4526222944,0.5327004194,0.0478152595,-0.1422421634,1.5422103405,-0.4843623638,0.5077458024,-0.4235121012,0.4101985395,0.2985644937,-0.4474204183,-1.4437913895,0.0946096405,-1.0242272615,0.3150271475,-2.1535305977,-0.0214283168,2.2918503284,1.6116689444,-2.0501370430,0.4185002446,-1.2304670811,0.5945562720,-0.4853458703,1.2488714457,0.2259249687,-0.1908799410,0.0583935194,0.4459559619,0.4773775935,1.6011041403,0.7079492211,0.4374597669,-0.5841044784,0.9688305259,0.8779850006,-0.0789694786,-0.1578722596,-1.8777650595,0.0557074770,0.2137283534,-0.0753122121,-0.5718395114,-0.6800060272,1.3663361073,-0.3309047520,0.4557212293,0.4449327290,0.9501424432,1.0727024078,-0.9129831791,0.7791337371,0.8639063239,-0.7943357229,0.9940410256,-0.1175013930,1.6619648933,1.3453713655,0.1633823812,-0.1596832424,1.5186958313,0.9925870895,0.7669295073,-0.2227122933,0.9052174687,0.1742046773,-1.8046705723,-0.3167853653,-0.4060903490,-0.3562828302,0.9901017547,0.5220876336,1.0828599930,-0.9335242510,-0.8265603781,-0.5601838231,-0.1037390828,-0.0347839370,0.8033310771,-0.7626441717,0.1769310981,-0.8562979102,0.6401655078,0.4897463024,1.2890980244,0.3583827019,1.1658328772,-0.0718992352,-0.8952594399,-1.3356628418,-0.9950582385,-0.6626952887,1.5818070173,-1.6137483120,1.6730548143,1.0554708242,-0.7988551855,0.1265448183,1.4124367237,-0.4724154770,-0.9337536097,0.8365861177,2.3900251389,0.8229386210,-1.1517981291,0.6948511600,-0.1482112110,-0.5633614659,-0.3132559359,-0.1994884610,-0.8831216693,-0.1983086616,-1.2630894184,0.5556268096,0.9699519873,-0.1344390661,0.5338910818,-0.8431673050,0.2585937381,-0.5014234185,-0.9196692109,0.6794525981,-0.4677133858,-0.3580030501,-1.0047782660,-0.4246050119,-0.8890936971,-0.1875797808,-1.3680918217,2.4937102795,-0.2065069526,-0.3412998319,0.9275464416,-0.6399300098,-1.0326942205,-1.2631584406,-0.7057926655,0.2132282406,0.1349920183,-0.0767279118,-0.0180238225,0.9167872071,1.2965246439,-0.4996848106,-0.1523783654,1.3595687151,0.5616595745,-1.2922233343,-0.2067446113,-0.0955479667,1.0408117771,0.2260160744,1.5209286213,0.7850476503,1.2328828573,0.4577864110,-1.0894739628,-0.5421277285,1.8188209534,-0.4353050292,1.0453416109,0.9334639907,-0.8626065254,1.1428796053,0.4184126854,0.8542534113,0.2786234617,2.2667417526,-1.3422918320,0.0365474224,-0.6399766803,0.2765336931,0.6240792274,0.9419114590,1.2190315723,0.9540512562,1.8149379492,-0.5880147219,0.5229048133,-1.8234910965,0.5798783898,-0.4019498825,-2.4706156254,2.2076125145,0.0733084604,-0.8490743041,-0.1897683442,-0.0908034369,1.3684400320,0.3928494453,-1.5093868971,-0.9352346063,-1.6818646193,-0.3056127131,-0.9864490628,-0.1267329901,-3.4295580387,-0.8379977345,-0.2364562154,-0.0146869794,0.2902716100,-0.3721041679,-0.5221943855,0.1014696434,-0.0193115585,0.1473674327,-1.5494464636,-0.5399037600,-0.0246628616,-2.0717842579,1.0729697943,-1.1848657131,0.4384807050,-1.3108595610,-0.8152757883,-0.1412737817,1.5141129494,-0.1638685614,0.8585687280,-1.1072340012,-0.8543540239,1.0696147680,0.1962230355,-0.1166522354,0.4228607118,0.3876480758,-0.2862882912,-0.9716600776,-1.0824446678,-0.5052465796,-0.0500417948,1.0491191149,0.8568240404,-0.6495133638,-0.3671525717,0.0186419897,-1.5158751011,-0.0458600409,-0.4317787886,-0.0550946295,-0.8744986057,-0.1637722999,-1.1921287775,-0.5725089312,1.6396950483,-0.1935610920,-1.8141798973,0.5524504185,0.0224844627,1.7025898695,-1.1939163208,0.0611830056,0.4557733834,-1.8053938150,-0.1088439003,1.3869347572,-1.3557333946,-2.6577615738,-0.5621011853,-1.5449957848,-1.4346992970,1.6745887995,-0.7087044120,-1.1405794621,0.8468211293,-0.6259702444,-1.0013346672,0.8264898062,-0.0107424371,-0.0377501473,-1.6358803511,0.1592251062,-1.2914931774,0.4267860949,-0.0591404252,-0.3762255311,0.7003886104,0.3074934483,2.0389971733,1.0119352341,-0.8226264715,0.1964271665,0.6776129007,-1.9366357327,0.2702591717,-0.7943894267,-0.5161536932,-0.9527539611,-0.1551645100,-0.3698361218,0.5130124688,1.6964564323,-0.4065807760,-1.2760372162,1.2567688227,0.0966834277,0.5076339245,0.3789902031,0.8715313077,1.5521655083,-2.2539381981,-1.0728610754,1.2374900579,0.6128914356,-1.1944071054,1.9067157507,1.6737689972,1.1818349361,0.3899155259,0.4014538825,-0.5103981495,0.1652175784,-1.9009075165,-0.2527178824,2.0375125408,1.6334018707,0.0990877450,-0.2214143127,-1.2417927980,1.4322711229,-0.8110809922,0.6237356067,-0.8600297570,0.9621957541,-0.1469984949,-0.7951014042,-1.2351981401,0.3188866675,-1.0440903902,-0.9646935463,-0.4229103625,0.4964722693,0.1531331837,2.7971539497,-0.3278644085,0.5300644636,-1.1382143497,1.2793962955,0.2531116009,0.8383103013,-2.0147705078,0.6147590876,-0.2501372099,-1.6798156500,-1.1679533720,1.9104994535,0.7335022688,-0.6242956519,-0.1997241825,0.6580860019,-3.5438032150,2.2302262783,0.2623988092,0.4263668358,-0.5162287951,0.9116119742,0.7537800670,0.8147564530,2.0275216103,-1.0469170809,0.0447648279,0.4066671729,1.4574295282,-0.5511431098,0.1064528897,2.2086167336,1.0268939734,-0.6577744484,-0.1552726179,-0.0653077587,0.8309588432,-0.2720114291,-0.4248123765,0.4521262944,1.8212699890,-0.2710549235,-2.6737802029,0.8627644777,0.4140576720,0.7305349112,-1.1009577513,-0.0405872762,-1.7268170118,-0.9778028727,-0.3233233988,-1.1608653069,0.0106323780,0.0213840399,0.5337206125,-0.5303680301,-1.8097007275,1.0664070845,-0.0200915802,-0.8092259169,-0.6417803168,-0.2247069329,0.2727496624,-0.0173603650,-1.0712687969,0.2251258940,0.0471394435,-0.0443964601,0.7301927209,0.3327662051,-0.1669893563,-0.0900482908,-0.1879023314,-1.1513732672,-0.3616277277,-1.6583201885,-0.1897500455,-2.0509023666,1.4391367435,-0.3599698842,-0.6990902424,-1.3491034508,-1.0897932053,-2.0706076622,0.7112004757,0.0375067219,-0.6403739452,0.4059659839,0.6470164061,1.8503149748,-1.6849238873,-1.3065844774,1.0666915178,0.9946438670,-0.6309731603,0.2481388897,-0.6018763781,-2.1274530888,-0.4725838006,1.3387097120,-0.3620197475,0.4139246047,0.5800728798,0.0942340717,-0.3209901452,0.0889385194,1.1412287951,-2.3286304474,-2.0180230141,-0.7359105945,0.4361290336,-0.3935990930,-0.9925333858,0.5121065974,-1.0553890467,0.0176953413,-2.1810755730,0.4622453153,-0.2540527582,-0.7596648932,-0.0581332184,-1.7947191000,1.0270496607,-1.2321225405,-0.3689308763,0.6238868833,0.1727206409,-2.8847465515,0.2620530725,0.9489654303,-0.3782636225,-0.2526799142,1.0940079689,1.0400370359,-0.4539102912,1.4904272556,0.3527225256,1.2626172304,-0.8670571446,-0.3333664834,-0.3730029464,0.2025904655,-0.3326246440,-1.2971646786,0.9655994773,-0.1379029453,0.7102864981,0.8918810487,-0.9970547557,-1.4230805635,0.8162118793,0.7776215672,0.1969143003,-1.3174074888,-0.5844110250,2.4673445225,-0.5167017579,0.6806137562,-1.1483550072,-1.0401893854,1.7456251383,-1.6846861839,-1.0622183084,-0.0755550563,0.6051344872,1.4599839449,1.8236228228,0.0921196342,0.3357533216,-0.5934019685,-0.3730606437,-0.0822857097,0.6652532220,0.9473050237,0.1076403409,-0.1182667017,-1.6469464302,1.0899176598,-0.7156873941,0.5861592293,-0.8050276041,-1.7994321585,-0.5858718157,1.1953302622,0.8592127562,0.5409115553,0.5861743689,0.9212389588,-0.5880656838,-1.4463483095,-0.1815917939,-0.4911633432,0.5372625589,0.7450032830,-0.7984898686,1.0677664280,0.8281040192,-1.9189672470,1.7005119324,0.1223435998,-0.8320993185,0.2740614414,0.7001248598,-0.1688963920,0.5390168428,0.7814664841,-0.6030362248,2.4221360683,1.2155414820,0.1503422856,1.1967055798,1.4468495846,-0.4375343025,-1.6593545675,-0.2992757857,-1.3680181503,-0.2705932260,-0.8648747206,-1.6523784399,0.6376203895,-0.4645305276,-1.8024930954,1.7780036926,0.6793705225,-0.3502464890,-0.3452021778,0.7236866355,-0.0813378990,0.4103395045,1.2789365053,-0.8342955112,0.2764317095,0.1251170337,-2.4885394573,2.0236468315,0.4303716719,-1.5654964447,-0.2343400568,-0.6242378950,-0.0403054543,-1.2115743160,-0.1085954681,-1.2910075188,-1.7384176254,-2.4113729000,-0.0978536010,0.6314791441,2.3066551685,-0.3984035254,1.6925071478,-1.2291654348,0.4835025668,0.5373200178,-0.6602330804,-0.3534172177,-0.8657686710,-0.0444904864,0.1402515024,-1.3653799295,-1.6854676008,-0.6546943188,0.7114022970,0.3269849718,0.7538878918,0.8704966307,-0.2834851146,-0.3685553670,-2.0719401836,2.0501718521,1.5302041769,0.1144342571,0.0451931544,-0.3070267141,-0.4794501960,-0.6803899407,1.5648218393,0.6181089282,-0.7039632797,1.2172878981,-1.4121437073,0.5843098164,-0.1053195447,0.5416721106,0.3049403727,-0.6772118211,-0.9164791107,1.6576575041,0.3724136651,0.6646793485,0.4738456309,-0.6636233330,-1.9127037525,0.4893687069,-1.0458182096,1.0213255882,1.1951941252,-0.0156067144,-0.6898881197,-0.3947982192,-0.3666029871,-1.5148080587,-0.8758003116,0.0948660448,-2.5608656406,0.7091881037,-1.9902096987,0.2046894580,0.7916052938,-1.7560980320,0.3696931303,-0.7017374039,-2.2834138870,0.0468963534,1.3962758780,-1.0620392561,1.0181268454,-1.5523796082,0.8203259706,-0.3706235588,0.2112499028,-0.8861809373,0.9715576172,0.0313248895,0.3653339744,0.0832739323,-0.4625202119,0.3381362259,-0.2845149934,0.0662649721,-0.9863808751,0.0047100959,-0.0938413143,1.2307792902,-1.4328401089,-0.2935240567,0.2290964574,0.8445306420,-0.2453528792,-0.2585487962,1.1594229937,1.3921138048,-0.6235087514,0.7814606428,-0.7613408566,0.0034697903,-0.2389897704,-0.3329078257,-0.2609840333,-0.2696022391,-0.9208405614,0.2603013515,0.9995867610,0.0641251057,1.4203132391,0.7948572636,-0.6019089222,2.1973364353,0.9349791408,0.3494509459,0.1695573479,1.1671073437,0.6311008334,-0.5451691747,0.0396844149,-0.1348823607,-0.7637632489,0.9957833290,0.3538493514,-0.9998304844,-0.3069563210,0.0764340535,1.2341115475,-0.4459015131,-0.8853935599,-0.1158692837,0.3361707628,0.5471341014,-0.7158341408,-0.7225044966,1.5734320879,1.5906124115,2.3091294765,0.5050844550,-1.6723904610,0.1712281853,-0.2585093677,1.0001472235,0.5437983274,-0.0820056647,-0.0909900889,0.0230511352,0.7223117948,-0.7696962953,-1.0347841978,-1.2189891338,-1.9741156101,0.9746890068,1.5432999134,-0.9736856222,0.4056926370,0.4569702744,0.8798183203,-1.0623204708,1.8637923002,0.3763478100,-0.1089622602,-2.6937398911,-0.3388677537,-0.3510338366,1.0932720900,-0.4909926355,-1.4203675985,-0.1821767986,-1.2154457569,-0.7117774487,0.4508901238,-0.7958429456,0.2701161504,-2.1759605408,-0.6888856292,0.1048809215,0.3557719886,1.4286407232,-0.9892821908,-0.9702765942,-0.3957818449,-1.2025412321,-1.6958194971,-0.4899291694,1.2200242281,0.2535707057,0.3699500263,0.1447062790,-1.5934619904,-1.1716135740,1.2759325504,-0.8569272757,-0.6799893379,0.8412258029,-0.3783779144,0.6456711292,0.7831376195,0.2905963957,-1.3606551886,-0.8964964747,-1.4888651371,0.7162798047,1.0289067030,-0.8015437126,-0.1136556342,-0.2551667094,-0.6595488787,-0.2111678421,1.4372746944,-1.0267357826,-0.5512586236,-0.8835692406,1.0588902235,-0.1691202819,0.4261890650,-0.9193620682,2.5551671982,-0.7390261292,0.8471983075,-0.4127860069,0.3208262622,-0.6716014147,0.8648295999,0.0461724885,-0.8361611366,0.4000117183,1.2253652811,-0.8352629542,-0.4399746954,0.2978938818,-0.6611793637,0.4268187284,-0.3053519130,0.8972523808,-0.3825258315,-0.2013663799,-0.3409064114,-1.4009368420,-0.0572384521,-0.8031398058,1.5172399282,0.6763442755,1.4432848692,-0.2264365107,-1.4626077414,-0.1477045119,-0.3010220528,-0.4390170574,1.0616732836,-1.6102832556,-0.2703692913,0.1356078684,0.2474282086,1.6711789370,-0.1386670470,-1.0705966949,-1.0397030115,-1.6174699068,-0.1875222772,0.3125074208,0.7058945894,1.6676181555,-0.8247151375,-2.6883125305,-0.0254399497,0.2976902723,0.7683712244,-0.2267342806,-0.0494219884,-0.6753277779,0.7129440308,0.3559135199,-0.3811956644,0.9569373131,2.0430958271,1.7159265280,-2.7088499069,0.4763430059,0.6436210275,-0.3214740455,-0.0530350506,0.8985423446,-0.5783354640,-0.6321326494,1.0727838278,-0.5652558804,1.9493138790,0.1443732232,0.7849040031,-0.9399734735,-0.0713980570,0.8070620894,1.4234772921,0.6374298930,-0.2836876512,1.9719129801,0.2325410694,0.8821958899,0.3814108372,-0.2397420704,0.1884869784,1.9887346029,0.9581700563,0.6938206553,0.8666102886,-1.2881469727,-2.5677328110,-1.0640289783,0.3348835409,-0.0858363882,0.4353652298,0.1455067396,-1.4057297707,0.2277472913,-1.1727318764,-0.6120919585,1.2771542072,-0.8003570437,0.6429291368,1.9732037783,-0.7130243778,-0.1332945228,-0.2530682981,-0.2103462666,1.7769855261,0.3102103472,0.1589248031,0.8054945469,1.4725772142,0.6171528697,-2.3603472710,0.2448849529,-0.0658212975,-0.4911062121,0.3746935725,-0.7771610618,0.5732238293,-0.2027808279,-1.3332324028,1.3494966030,-0.3272345364,1.5416948795,0.3958894610,-0.5925759077,2.2976679802,-1.9548562765,0.7169862390,2.1682713032,1.2674481869,0.0668742955,1.0733947754,0.7876006365,-0.4546663463,0.0326386094,0.0436380059,-1.1151885986,-0.2926286459,-0.2934510708,1.1921510696,1.5980594158,-0.8130311966,1.1409503222,1.3313578367,0.8444764614,-1.2648280859,0.9731772542,-1.1700046062,1.0548166037,-0.5340769291,-1.8655465841,0.1589542329,1.6472337246,-1.1182059050,1.2130138874,1.1797075272,0.5020463467,-0.7686650753,-0.1314456314,-0.7434322238,-1.5818883181,-0.6749847531,-0.0076208692,0.7187939286,-0.5591735244,-0.6265111566,-1.3190778494,1.0906132460,-1.0671056509,0.0342655107,-0.4741897285,-1.1158161163,-0.2803910077,0.5985125899,0.5886665583,-0.1324573904,-0.8394958973,0.0530796871,1.2963345051,0.0079052718,-0.9098715186,1.1129853725,-1.6644388437,-0.6847685575,1.1993128061,2.5089540482,-0.3476056159,-1.9554597139,0.5798164010,-1.9721982479,1.0853871107,-0.3682597578,2.2866818905,1.1455234289,-0.0026167410,1.1169599295,1.3755278587,0.5090430379,-0.6836943626,-0.4428147078,-0.0736249387,1.4757091999,-0.8413479924,-1.1724884510,-0.7022691369,-0.3636963964,-1.0440857410,-1.0499132872,-0.9251657128,0.4470546544,2.1343755722,-1.0937464237,-0.3145466745,0.0791752636,1.8015995026,-1.1708307266,-0.3710770905,0.0021474429,-1.2492738962,1.2540581226,-0.3887788653,-0.0979342535,0.6381052732,0.5091582537,-1.3069186211,-3.2205343246,-1.6814134121,-0.2490135878,0.6927216053,0.3460028768,0.4161698520,1.7263311148,1.3670994043,-1.2537178993,0.8223969340,0.1540791988,0.4974704087,-1.4824185371,-1.3710247278,1.9001389742,2.0547459126,0.4271369278,-0.3725138009,-1.3944122791,0.2006481439,-0.2336889803,-0.9436457157,-0.6381720901,0.3321398199,-0.2137336731,-0.6376451850,-2.6190822124,-1.4501197338,1.0656617880,0.6423869729,0.3586390316,0.0616030321,-1.3555532694,-0.6935083270,-1.4561247826,-0.6963708401,-1.9475837946,-0.1860286593,-0.9210773110,0.7253800035,0.7981371284,0.4483519793,1.6668821573,0.1371351928,1.3965914249,1.5389333963,-0.6738855243,0.7440813780,1.6378698349,2.2377979755,-1.6630915403,0.6449002028,0.0226498768,-1.0483651161,-2.1157052517,0.7034059167,1.0860549212,0.6332697272,0.5163491964,-0.7699266076,1.0532444715,-0.2817136347,-0.1954266131,0.6466432810,-1.1061758995,0.4786778092,0.6414473653,1.2876604795,0.5732532144,0.3575452566,-2.2497246265,1.2791950703,0.5004061460,-1.9408650398,-0.5976858735,0.3575026095,0.2238463461,1.0250608921,1.5798437595,-0.7968079448,-1.5439547300,1.2245321274,-1.3009462357,-1.3025891781,1.0694528818,-0.6745738983,0.0826234743,-0.1688699126,1.3309227228,1.3732751608,0.7255052924,0.2665914893,1.3750485182,0.0715328604,-1.1448044777,1.1675745249,0.2949744761,-1.1843786240,0.1423856020,-0.6588349342,1.2551316023,-0.1594646573,0.6699225903,0.6179960966,-1.7483422756,1.3339719772,0.3029723167,-1.1223556995,-0.4683272839,-1.6160479784,-0.3782319129,-0.7951239347,1.4735752344,1.6484818459,1.9880499840,-0.1242350116,0.1590626389,-1.8769822121,-1.0277003050,0.3765939772,2.0874798298,-0.9381197691,-0.2639953792,-1.9528026581,-0.3390138745,-1.9990794659,-0.6516773105,0.9337078929,0.6412097812,0.4076411426,0.0087392740,-2.6370751858,-1.2452684641,-0.3792372048,2.0947167873,1.2018176317,0.9371799231,0.2011674345,-1.8033559322,0.5050754547,-0.5637676120,0.0107321963,0.6286424398,0.0492702387,-1.6498469114,0.0104927039,-0.1102788448,1.2789262533,-0.2689329088,-0.9935606718,-0.8252071738,1.4261518717,-0.1880145818,-0.9265387058,0.4540956914,-1.2168729305,1.8058356047,-0.1168055758,0.5073953867,0.3392245173,0.7426418662,0.5837747455,-0.7182095647,0.3108665347,-0.0449238829,-0.6104008555,0.5157542229,-0.9972209930,1.6061866283,-0.2779401541,1.4404076338,2.3598353863,-0.0747601092,0.8856165409,-0.4305108786,2.0704896450,-1.2632654905,-0.1376118213,0.3399257362,0.4172295034,0.0091022998,-0.5716640353,1.1888803244,0.1341378689,0.7014256120,-0.5142672062,0.2883620858,-1.7981014252,-1.5133697987,0.6216871142,0.1071367636,0.4802518785,0.7183364630,-0.5698022246,0.8356449604,1.3484818935,-0.5819205046,0.2602949739,-0.1543977708,1.7979315519,0.4334428012,0.3003485203,-0.4186342061,-1.8175272942,0.1426157504,0.2628866732,0.3613359332,-0.2564287484,-1.0144606829,-0.8692834973,0.2546459138,0.5684943199,1.2995219231,-1.7172603607,-0.2453630418,-1.2629826069,0.7414638996,0.2217936367,-0.9192535281,-1.1625478268,-0.7427448630,0.6232370138,1.4456577301,-1.3260273933,-1.3074417114,0.3686677217,-1.7282638550,0.1614782363,-0.8077552915,-0.5116407275,0.9091966748,-0.8138747811,0.8174273968,-0.2035060823,0.1387581825,-1.0483995676,-1.1789760590,-0.1418992430,2.0072953701,0.2946895659,-0.1563377231,1.9827004671,-0.5443348885,-0.6208754182,-0.0153734796,-1.0330175161,1.5375193357,2.0169827938,-0.8606604338,0.7027775645,-1.1580990553,-0.8982186317,0.4647661448,0.1343112588,-0.4590297639,0.1715912819,1.5083426237,0.0586618483,0.7613887191,-0.6067987680,-1.7963507175,1.2548172474,1.1760858297,1.3762103319,-0.8332884312,1.9168746471,1.2767934799,1.7126957178,-0.8065787554,-1.2705796957,0.5567392111,0.6912044287,-0.1580438316,2.1341280937,-0.5214887261,0.4928900898,0.4675154984,-0.1240027398,-0.6425836682,-0.0069333049,-0.6486710906,-0.6996839643,1.3014633656,0.2614509761,-0.2373386174,-1.3424488306,-0.4017966986,2.2234640121,0.6983535886,-2.3241012096,-0.9949077964,-0.2743484080,0.5673701167,-0.8014136553,-1.0267834663,-0.3481470346,0.2476348877,0.0547130778,1.3874765635,0.7338072658,-0.3730239868,-0.4653834701,-0.6865920424,0.3276156187,-0.5956894159,-0.0898129418,-0.8099248409,-0.9437165260,-0.1692812443,-1.0413445234,-1.7066810131,-2.0119111538,1.3718327284,0.2448530644,-3.1781678200,1.8929358721,-0.2453606278,0.7510632873,-0.2731828988,-0.0230197310,-0.6737012267,0.8937125206,-0.3046015501,0.3742146790,-0.1818317771,-0.4224560559,0.4293473661,0.0446226597,0.2028374076,0.6543111205,2.0454571247,-1.4786034822,0.3524400592,-0.4629359841,-0.3411388695,1.7129424810,0.4731816351,1.0813529491,1.3048049212,-2.1584177017,0.0670639798,-0.5799887776,-0.0091375699,-0.3846576512,1.0352602005,1.5867995024,0.9555609226,0.3972346187,0.1691245884,0.7903192043,-0.7628286481,0.7735763192,3.3371245861,0.5317189693,-1.3681658506,2.1529917717,0.4164772034,-0.4630190432,0.3562625945,-1.3067346811,2.7096297741,1.1794174910,1.2390013933,-0.3905018866,-1.2902466059,-0.6624063849,1.3344436884,-0.6159383059,-1.1763250828,0.3439395428,-0.6466949582,1.2733309269,0.5567304492,0.1190240979,0.4002852142,-0.1299002916,-1.4366146326,0.5557325482,-0.3819403052,-2.2948584557,0.7538915277,0.4088020027,-0.5706181526,0.9400187731,-2.2233648300,0.2392009497,-1.4521886110,1.4968353510,-1.1174561977,2.2601320744,-1.8304297924,1.3039175272,-0.0048594456,0.7367036343,-0.3838936687,0.5286387205,0.1551837325,-0.4323429465,-0.6561080813,0.5545196533,0.5781207681,-0.3996987045,2.3530459404,-1.3647236824,-0.1340306848,0.1753463745,0.0249666255,-0.3483884931,-0.0333038643,-1.9605727196,-1.5999488831,-1.3416832685,0.2788104117,-0.7476895452,0.8272824883,0.9861788750,-0.6861533523,0.1893069595,-1.6422375441,0.5166320205,-0.3142879903,2.8894968033,-0.3574573696,-0.7443041205,1.9324642420,-0.6711962223,0.8798464537,-1.0091282129,-0.5488491654,1.5701944828,0.2705782056,0.8730167150,0.9876908660,-0.0415039994,-0.6048167348,0.2426076084,0.1948920041,-2.5501427650,-1.7648794651,-0.0415776409,1.1606342793,0.3051763773,1.4745252132,-0.3646067381,0.1290424615,-0.2389613539,-2.2449805737,1.3227287531,-0.3557299078,-0.2465161532,1.0724699497,-0.0132042440,-0.6840516329,-0.4048824012,1.0555580854,0.2012488693,1.4333781004,0.5459110141,1.4253919125,0.1036763117,-0.8666305542,-2.1211733818,-1.3604879379,1.2255884409,1.0984667540,-0.2646973431,-1.2453637123,1.2485244274,-0.4639970064,-0.1485658139,0.4927731454,-1.1315159798,0.6742309332,0.1616810262,-0.2924068868,-2.2380015850,1.5050231218,-1.1828123331,-1.0715100765,0.2920324206,0.4176152349,-0.2618497610,0.3900544941,1.2369613647,2.2400150299,-0.6591055989,-0.3432904482,-0.9165864587,0.3899152577,-0.8128656149,-0.6911546588,-1.8697581291,-1.9872611761,-0.8085523844,-0.0751557872,0.2399503887,-1.3846840858,-0.1106751859,1.8108611107,0.2479185611,-2.0952146053,-0.0888442099,-0.1570831537,0.0162983797,-0.7323496342,0.9778578877,-0.4015278518,1.5470517874,-1.1965001822,0.5501039028,-0.3973948061,-0.5402927995,0.1135616377,-1.1342197657,1.5787736177,0.7312040925,1.3263958693,-0.9830656648,-1.5166749954,1.2743954659,-1.6303781271,0.5302878618,0.4884847105,-0.0564946122,1.4196146727,0.0485945493,-1.6874896288,0.0264888797,-2.2721157074,0.5597230196,0.0342372134,0.3025023639,-1.1467289925,-0.1418615282,0.4835216701,-0.4516725242,0.2854830325,-1.2665178776,1.5576566458,1.0947488546,0.2143646628,-0.2931555212,-0.6761689186,-0.5095722675,0.1104367077,-0.9266905785,0.1388486475,-1.7587862015,1.1457693577,-1.7809176445,1.7472233772,0.2431917340,0.9257518053,-0.1105109155,0.7692781687,0.8367552757,0.7457382679,-1.5059551001,-0.8665480614,-0.8388282657,-1.1409242153,-0.6999360919,-0.3496262133,0.2825672925,-0.7251719236,0.3119471371,0.6827612519,0.8235883117,-1.2512964010,0.2607354224,-1.1948734522,1.6742203236,0.1868904084,0.8913527727,-0.0905617997,-0.4602533579,-1.3090718985,0.2370790094,-0.5549578071,-0.3860284686,-0.3769266605,-0.3289939761,1.2747739553,-1.1576405764,-0.7707039118,-1.1006671190,-0.0534144416,-1.0460067987,-0.0220385697,-0.0187210329,1.0596003532,0.4855110049,0.9563537836,0.6240862012,-0.2181169987,-0.1297433525,1.3240571022,-1.3595471382,-0.0788813084,-0.4473232031,-0.8702023029,1.2506643534,0.9834125638,-1.0927263498,-0.6073045135,0.3495458961,0.1213660464,-0.4297527075,-0.3331126571,0.7537350059,-1.9193907976,-0.8438121080,-1.9194872379,-0.2119607925,1.8239436150,-0.2754066885,-0.5554115176,-1.0301826000,0.7643379569,-0.0227805395,1.3933587074,-0.1937872171,0.9693816304,0.6298752427,0.2584379315,-2.3164453506,-1.8396610022,-0.3373851478,-0.4343889356,0.5835508108,0.5079726577,0.7551559806,0.8957632184,-0.5572155714,1.4874306917,-0.5413039923,1.7688095570,-0.1760699153,-0.4086333811,-0.0682857335,1.2715420723,1.3316938877,-0.6478120089,1.7098898888,-0.2466237396,-1.8732783794,0.1492802203,0.8813462257,-1.7876430750,-1.2078424692,-0.5233929157,-1.0958852768,0.1002101004,1.2844595909,1.1891831160,-1.2014337778,-2.2963385582,0.9300718904,0.7659554482,0.7081581950,-1.4520958662,1.1127053499,0.2289859056,-0.7110806108,0.4880263507,1.5001052618,1.5714887381,0.7933399081,-0.3028346896,-0.1017167792,0.6995674968,-0.0198632907,-0.7587066293,0.7734092474,-0.3478929996,0.0377644747,-0.6838935614,-0.7128896117,0.5029635429,1.9088362455,-1.1404583454,-1.6888059378,-1.8423115015,-0.0389658883,1.1948564053,2.4157738686,-0.9063307643,0.6310094595,0.9897720814,0.7520170212,-0.4465702176,-1.6844987869,-1.9101190567,-2.3421952724,-0.4606425762,-0.5885396004,-1.0535298586,0.6714470387,-2.0614287853,-1.5895788670,-0.9668141007,-1.8850803375,1.0163460970,-0.4743680656,0.9278936982,-0.6074044108,0.8148276806,-0.1381165832,1.0583986044,-1.5783662796,0.7843630314,0.3421233296,-0.8151394129,0.8304324150,-0.5892474651,0.0996279344,-0.1991706789,-2.5094156265,-1.5909996033,0.2353384942,0.6018269062,-0.8568947911,0.2557218075,0.6682499051,-0.1879249215,0.0074428706,0.4798038006,-1.7355819941,1.9003592730,1.5346397161,-0.6947375536,-0.6060379148,1.2424333096,-0.4308054745,0.6093084812,-1.5997244120,-1.5050390959,-0.3377222419,-1.2019016743,1.1436249018,0.9114562869,0.1259697229,0.4765327871,0.3271493912,1.5688660145,-0.0834053159,0.6043325067,0.0358087867,-2.0696275234,1.1063140631,0.7426227927,-1.2348821163,-0.2855467498,-0.1477694511,2.1614141464,-0.7326849699,0.5784502625,-0.1212657541,-0.6860406399,0.2312044650,0.7677243948,1.4630963802,-1.4831662178,0.3842955828,0.3330720067,-1.4914379120,-0.6227321029,-0.6727771759,0.4612464607,2.0365641117,-0.8002539277,-1.1648292542,0.1289562881,0.4260367751,-1.7791209221,0.3649482727,-0.7779896259,-2.4400405884,-0.0435852557,-0.3500059247,1.1347149611,0.3358536363,-1.8796350956,-0.6165884733,-0.3348190784,-0.5539978147,-0.6812824011,-0.5439455509,-1.9715577364,0.3464953303,0.8795771003,0.1512504965,0.0113260550,-0.7210302949,0.4954958558,2.0371608734,-1.3999308348,2.0279750824,1.0738673210,0.7125077844,-1.7527254820,1.9098694324,-0.4230732620,-1.3026645184,0.4003872573,0.2172527611,2.9619445801,-0.8010261655,1.4232937098,2.3403263092,1.3790491819,0.1906539947,1.5853165388,0.1980482191,0.5038337111,1.2534674406,1.1705026627,-0.9915919900,0.7790826559,0.5936439633,-0.7537182570,-0.6383305788,1.0891114473,-0.5446549654,-0.2027605176,-1.1356508732,0.8898881078,-1.1803863049,0.0760592073,0.3940411508,0.8132078648,-1.2225940228,-0.2539710402,0.9250649810,-0.4512603581,-0.0236611646,0.2419966459,0.5349957347,-0.2259923965,-0.7846670747,0.4239006341,-0.0066497908,0.8761689067,-1.0638122559,-2.5720088482,-0.5335486531,-1.0095447302,-1.7223300934,-0.6535322070,1.1655402184,1.1832163334,-0.2269054651,1.7193808556,-0.1380582601,1.5151145458,0.2277833372,0.0959253907,-0.5170901418,-1.0309077501,-0.4735969007,-0.0485035852,-1.1286866665,-0.7307674885,-0.5463230610,-0.0409587808,2.0975720882,0.3434947133,0.9940972328,0.3789162636,1.0542325974,-1.8494417667,-0.4977275729,0.7369968295,0.5268564224,0.1865140498,0.8466647863,-0.6316319108,0.1136949435,-0.6331836581,0.3402028978,0.5535160899,-0.2889496684,-0.7305825353,0.4190462232,-1.0515617132,-0.4801098704,0.0261303224,1.5960645676,0.1610219181,1.7804647684,-0.3047503829,-0.8188756108,-0.3621890247,0.3808596432,0.2823227644,1.5666717291,0.3734123111,-0.8837423921,-0.7322314382,0.1986591965,-0.0118880589,-0.7151897550,0.0778959244,0.8643652201,0.6962469816,-0.5422630906,-0.9411893487,-0.8344305754,1.1522097588,1.3389163017,0.0177985504,0.5214101672,0.6627396941,-0.0895537585,0.3205173910,1.1086225510,-2.7512409687,0.7842624187,0.2301861048,0.4868739247,0.1914014667,1.4830135107,0.0156363230,0.6475189328,1.8308417797,0.4691707790,0.3148375750,0.7041759491,-2.6743814945,-1.5270642042,0.2455077767,-0.5976601243,0.9597811699,-0.4113830030,0.7531632185,-0.4996159077,0.6813071370,0.7660171390,-1.4191707373,0.3065551817,-0.1291158944,-0.4976983070,-1.2929699421,-0.1371014863,0.7562644482,1.0583063364,-0.4212669730,-1.9234799147,-1.6065359116,-0.2558904588,-0.4901143014,-0.0949113965,1.1031668186,-0.5381546617,0.2360364795,0.0465177372,-0.3361516595,0.1274346560,1.9163759947,0.6101396084,-1.1195522547,-0.7814033031,1.3373019695,0.2333422899,1.0861701965,-0.0382700153,0.8989006877,-0.0218960550,0.1018365696,-1.5967543125,-0.0113325082,1.1269840002,0.0552202910,1.4069075584,-0.9980571866,0.0247818157,-0.7040320039,0.3176784813,1.6605193615,1.0455915928,-0.8923811316,0.9219143987,1.1073287725,0.7103539705,-1.4154820442,1.0690660477,0.1309919506,0.0383858383,0.9466379285,1.3524271250,0.8901629448,0.4715458155,-0.1681349725,1.7018618584,-0.4245993197,1.5963537693,0.4084403515,-2.2818739414,-0.2058727890,1.1010887623,-0.7389399409,-0.2773337960,-1.1447142363,0.5750554800,1.7250024080,-0.9898491502,-0.4104329646,-1.6079535484,0.2768232226,-1.6983526945,-0.5670870543,2.1507933140,-0.2975871563,2.1437575817,1.3332302570,-0.3730902672,-0.1122499704,-0.7847885489,0.9248625040,-1.3942272663,0.6543221474,1.0042756796,-0.9440436363,-2.4518766403,1.3270406723,-0.1127001345,2.2061531544,-0.3989170194,-0.4466468096,-0.5355738997,0.0526149832,0.6064239740,0.5198518038,-0.8466613293,-1.5090380907,-0.4535782039,0.4313685894,-0.1462003887,0.1641013771,2.1521577835,0.3630537689,0.2070374936,1.7983050346,-0.0564059503,0.5928288698,-0.1816093922,-1.5518671274,-0.3621249795,-1.0239580870,1.0249418020,-0.0258395690,-1.7892510891,0.6218369007,0.6613118649,2.2723629475,-0.4432788789,1.0698333979,-0.8403570652,-1.4873845577,1.5990829468,0.3635856509,-0.1802307367,-0.3384521902,-0.2343396097,-1.4471864700,-1.3438107967,-3.1347074509,1.3278874159,1.4307368994,-0.2085703611,1.5691628456,-0.0372373499,1.5322495699,-0.8938466907,-1.6205263138,0.9487670660,0.0607111529,-0.0718811527,0.4896041751,-1.2187587023,0.8618543148,-0.2260780036,-0.4962435067,-0.8952035308,0.1894100606,1.9990708828,0.6714808941,-0.3252743185,-0.3147354424,-1.2198890448,-1.1942043304,1.2294464111,0.9353618622,-1.7695857286,0.3260254264,0.8139547706,0.1962550431,0.1314067394,0.5124615431,0.7095163465,1.3730001450,0.7314730287,0.8850992322,0.5249949098,-0.0936656371,1.0094020367,-0.4246652126,-0.0342488736,0.5519418716,1.0054379702,0.2137652487,-1.7681372166,-0.9254562259,-0.4854847193,-0.6538339853,-0.2760174870,-0.2612164021,0.9103474021,1.3952193260,-0.3264450431,-0.0597991198,-0.0280044656,-0.7869258523,-2.5064163208,-1.2314569950,1.4557712078,1.2016288042,0.4458014369,-1.4862548113,0.9897671938,0.9338101745,0.7926711440,-0.1426515281,-0.9763342738,-1.1071892977,1.8700821400,2.0336098671,-1.5667554140,-0.5214136839,1.1199978590,0.7776375413,-0.1399716139,-0.0623685531,1.1362810135,1.0089765787,-1.3147529364,0.6011255383,2.0578691959,0.2968917489,1.1136337519,-0.6109186411,-0.6683439016,0.9962469935,-0.8060427904,0.3595867455,0.7470183372,1.0633322001,-0.9276279807,0.3000597060,0.7063956857,1.0950361490,1.4885321856,1.4787135124,-2.1218326092,0.9264213443,-0.1775084585,0.9011278152,0.2840862274,0.0977649391,-1.0456649065,0.1681640744,0.0973941088,-1.7393004894,0.2261245102,-0.0660531223,-0.3362882733,0.8595430851,-0.4416444898,0.0228420068,-0.7061185241,-0.1840548813,-1.2924098969,-1.0702615976,-0.1731543988,0.9668654799,0.7544121146,-0.5534548759,-0.1589929909,-2.7193152905,-0.5930914283,-0.4942319989,-1.1334577799,-0.1847745329,-0.8339127898,0.1843493879,-0.3052302599,0.5634783506,-0.0959699973,-0.9182578325,-1.9924126863,0.3829368651,0.2503584921,0.2333265692,-0.3078962266,0.5468981266,0.1616246402,-0.4544194043,0.2356493622,1.1045236588,-1.3996573687,0.5584018230,0.5636180043,-0.8096659184,-0.1284091473,0.4092279077,0.2285577953,-0.3103590608,-1.3424509764,-1.2082949877,-0.9283201694,2.0955545902,1.1210683584,-0.8812590837,1.2313210964,-0.3197748065,1.7898057699,0.0698545128,0.7923595309,-1.0690809488,0.6286915541,-0.1670196503,0.9845463634,1.0878648758,-0.1941708624,0.5016475320,-1.1764376163,-0.7215655446,0.3653467000,0.7173801064,0.3487474024,1.1008827686,0.6648312211,-0.7699224949,1.8959935904,-0.1441157013,-0.2147849053,-0.7026571035,-1.2497316599,-0.7573789358,-0.5733095407,-0.4854148626,-0.7615327239,-0.5698633194,2.8097834587,0.8722813725,1.2352868319,-0.9432064891,-0.0974869877,1.7055737972,-0.1014531478,1.0176905394,1.5702327490,-1.7046865225,-0.3277420104,-0.3331027627,-2.1215126514,-1.7561151981,-0.2295200676,1.6113495827,-0.2443063259,2.5411062241,0.3537022173,0.4745986760,0.6965101361,0.1384816021,1.1178592443,-1.1784735918,-1.1290528774,0.2061873525,1.0603878498,-1.1349711418,1.2598598003,1.7623924017,0.0733724684,-1.3333655596,-1.0912177563,-0.6205294728,0.7761052251,0.1271678060,1.2515132427,-0.5780774951,0.7281842828,-0.7465434670,1.1616883278,-0.6196599603,0.3022282720,0.8347775340,-0.0490818210,1.5939271450,-0.9503580332,-0.4347720146,-0.7656218410,0.7085364461,0.9605593681,-1.0164953470,-0.2222494930,-0.8314278126,0.4303712249,-0.7721483111,-0.3019029796,0.5900394320,0.0245243497,0.1932301819,-0.0898328945,0.4563172460,0.6518187523,0.0078258719,-1.2128522396,0.5727971196,-1.3422386646,-0.8164447546,-0.0112239150,0.4942510426,-1.7097381353,0.6157289147,1.2700591087,-1.0838717222,-0.4467307925,-0.2466057837,-1.0219964981,-0.3065997958,0.3694855869,-0.0713111088,0.4026225805,0.6370279789,0.8591992259,1.0705020428,1.8353241682,-0.4750539660,0.6103578806,-0.5137580633,0.7581811547,-0.1050673276,1.5978858471,0.6333515048,0.0460980870,-0.7376776934,0.2096036524,-0.4071459174,0.7349792719,-0.4330402315,0.7938969135,-0.0671691522,-0.3470112383,1.8795491457,-0.1271699071,0.9610880613,-1.4886234999,-0.8252080083,1.3477144241,1.5563865900,0.1703135967,-0.9434504509,0.0534256622,0.1484180987,-1.2368420362,-0.1398315430,0.1595588923,1.5863084793,1.3536993265,0.5934506059,1.1358667612,-0.1774367094,0.9255916476,-0.1539941430,-0.6215142012,-0.6159935594,-0.4488615990,-1.4912188053,-0.5317133665,-0.2063709795,-0.4096370935,0.9561219215,0.5284463167,-0.8182538152,-0.5056212544,-0.1462823451,0.0752253309,-1.2333616018,-0.5615788102,-1.0774196386,-1.4043681622,1.4619164467,-0.6012640595,-0.2459688783,0.3324500620,1.0232548714,1.4352263212,0.1944244057,-0.1463443935,-0.2790006101,-0.6674974561,-1.3180520535,0.3201041818,0.3282475471,-1.4190750122,0.3450450897,-0.1171793342,0.1504306048,-0.7891467810,-1.0476018190,-0.3834323287,-0.1902684718,-0.4965841472,-1.3784673214,-0.1844371557,-0.4675067067,-0.6985540986,0.4536924958,0.3140238225,0.0564287789,0.7583971620,0.6013430953,-1.8449608088,-0.1788474470,-0.0510619581,0.5304078460,-0.4194923639,-0.7391867638,0.1276831329,-0.6782696247,0.1311978102,2.7735209465,-0.2934664488,0.5471537709,0.0393295288,1.0524917841,2.4084842205,-0.1510079354,-0.0755359530,0.2978080213,-2.5932602882,-0.1261765659,-0.0178737193,-1.1064251661,1.6046415567,-1.8980734348,-0.2849923372,0.4307873547,-0.7775550485,-0.9093212485,-2.1181476116,0.5486614108,-0.8518691063,0.1899482012,-1.2635831833,0.0362131745,-0.0570133552,-0.2774310708,0.5166860223,-0.6961334944,-1.1381798983,0.0194949433,-0.2258192897,-0.0000388383,1.0765069723,1.1303399801,1.8657202721,-0.4969576895,0.5364794731,-2.0242605209,-0.8213713765,-1.4851415157,0.8490946889,-0.0753547922,0.3361081779,0.0728952736,0.0231189914,-1.2837551832,0.9499085546,0.1681417376,-1.4466546774,-0.2972466350,1.1298607588,-0.2603873909,-0.9126073122,-0.4502425492,-0.5704441667,-0.9064111710,-0.8553234339,-0.4430517554,0.2436235696,1.4905276299,-1.0585029125,0.4943399131,0.7875627279,-0.3641681075,1.1554255486,1.2991687059,0.1732139587,-0.7331561446,0.1793219149,-0.1800402552,0.5449168086,1.3240280151,-0.1309091151,0.4784817994,-0.4267643988,2.0781397820,-0.7498555183,1.6521127224,-0.1664374918,-0.7460601330,-0.9441272020,-0.4832925498,-1.5331821442,-0.4067618549,-0.7364491224,-0.9086607695,0.3413515687,-0.8198691010,-1.7870553732,2.4673192501,-0.2311452627,0.3308919966,-0.1159708798,-1.7726674080,-0.9126517773,0.1084937230,-0.2664954662,1.1111640930,0.1229815185,0.6907859445,-0.1474541426,0.9019960761,0.2317667753,0.8363870382,-0.3399315774,0.7041403055,-0.1264661849,1.1791597605,-0.9016402364,-0.1811943799,2.3676764965,1.1302993298,0.3110736012,1.5677846670,-0.7050484419,-0.1518790126,-1.7081288099,0.6985465884,0.7089632154,-1.0309268236,-0.1347338855,-0.0365764089,0.1824831814,0.5456715226,-0.0108612115,0.1843760610,-0.0527592488,1.1165183783,2.0685019493,0.0236146916,-0.1301397979,-0.1713315994,-0.7619674206,-1.6910823584,-0.5223678350,-1.7465475798,-0.2006603628,0.7275930643,-0.4736891985,-1.4242618084,0.0546379611,-0.3088788986,-0.1335759610,1.9706972837,-0.2325765043,0.2274934202,2.2387323380,1.4907130003,0.3462500870,1.3234370947,-1.9889664650,0.7430348992,0.6448816061,0.5218971968,-0.1231725663,1.5066103935,0.8738765717,2.7089717388,-0.8890984058,0.0795818791,-0.0192832518,-0.9809086919,-1.2750723362,0.2867516875,0.2137882411,-0.9008516073,1.5888748169,-0.4282222986,0.4386356473,-0.1085125059,0.6985945106,1.9744687080,0.4545195699,1.3060090542,-1.3972746134,-0.2608897984,0.6921256185,-0.2758881450,1.0756412745,-0.1134573221,-0.0426482968,-0.9878318906,1.5196024179,0.6308060288,-0.9928121567,-0.4773582518,-0.5678960085,1.1409707069,0.0252071396,-0.9686629176,-0.1847696155,-1.1870638132,-0.4968124926,0.7360694408,-1.6462267637,2.3052799702,-0.8024062514,-0.6898394823,1.2083338499,-1.2181578875,-0.8410550356,-1.2503207922,-1.3341989517,0.5452713370,0.0004595034,-0.1027127653,0.5961635113,-0.5245649219,-1.8084018230,1.0589570999,-0.7794679999,0.6349820495,0.3862176836,0.8346452713,-0.8713117242,0.8153094649,-0.5405928493,0.2869177163,-0.6896800995,0.0557697900,0.1182901114,-1.7857323885,-1.0742902756,-0.4063031971,1.7793726921,-1.7563652992,0.6893250942,0.8844146729,-1.0142682791,-1.7650473118,0.2160642594,-0.7887262702,-1.1181463003,-0.1376193762,0.1754952371,-0.2765376568,-1.7079218626,0.9067323804,-0.0235241614,-0.3631467521,0.8013179302,-0.1235235482,-0.1538935751,0.5224968791,0.8662751317,0.2375682592,-0.8459567428,0.3390309811,0.6798582077,-0.9715719819,-0.1630507708,-0.1906574965,-0.3275502622,0.2688953876,0.4053089321,0.1773621142,-0.9372261167,-0.1691677719,-0.3724011481,0.8112956882,0.1267861128,-0.5620681643,0.2927173972,-0.8813909888,0.0762910396,-0.0483648069,2.1920011044,1.7463549376,2.3207309246,0.2887925506,0.7549450397,-1.4306452274,0.3228493333,-0.0288458075,-0.2087575942,-0.8381208777,-0.9550005794,0.7841243148,0.2179069519,-1.0709420443,0.3135614693,0.0914136097,0.0320585743,0.3876436651,0.3842196763,0.8502239585,1.0612168312,1.8604735136,0.0568598658,0.2732332349,0.0278589707,-0.8741342425,0.3974182904,-1.3401019573,1.6500184536,0.5345094800,0.4902154505,1.3779866695,1.4287627935,0.5794705153,-0.4708151221,-1.2481455803,-0.9796716571,0.1646438241,-0.2908467948,0.1688180864,0.2806825936,0.3941893280,-0.5539347529,-0.0067497804,-0.2968336046,-0.4971628189,1.9962546825,0.2005653828,-0.6932837367,-1.6317993402,0.3809179664,-1.5123542547,0.1992826313,0.3300321996,-0.3034650087,-0.1181315854,0.0882374570,0.1668884158,0.3019710481,1.4882793427,-1.1674114466,1.4780186415,-0.3395954370,1.6217408180,1.3903936148,0.0755978227,-1.1194069386,1.7365732193,0.1781414896,-0.9232194424,1.8039987087,-0.8838068843,-0.4083239436,0.3007299900,0.1699735075,-0.8590050936,-1.7392672300,1.5597413778,-1.3260040283,0.2854619622,-1.9159833193,-2.3440728188,0.4461363852,-0.0687278062,1.9588936567,-1.1906564236,-0.7276904583,0.2522965074,0.9506995082,-0.0913084596,0.7821321487,-0.0195057746,1.2213931084,-0.1069381684,0.7629193068,0.1845369637,0.3870324492,-1.0695841312,1.0488708019,-0.5519348383,0.5487302542,-2.5772011280,-0.2137518078,1.2179993391,0.9156683683,0.3357705176,0.5025701523,0.3491545618,0.7370117903,0.3278817534,-0.7132780552,-0.5390459299,-0.7518448234,0.5354685783,0.0184270069,0.2321900129,-2.1776525974,-0.0709908977,-0.3209287524,-0.2798088789,2.0468642712,0.9956209064,-0.2023959607,1.3509565592,-0.1920386255,-1.5777788162,1.6549317837,0.4675681591,-1.9365965128,0.9573156834,-0.7165775895,0.9248271585,2.1137826443,0.0793551803,-1.1837171316,0.7460383773,0.6538752317,1.3912616968,-0.1166813821,-1.7531785965,0.2474077493,-1.1580266953,-0.7121775150,1.8413614035,1.9593071938,-0.2458700389,-0.5498188734,1.1876565218,-0.3367114961,0.8950569630,-0.8747928143,-0.6351636052,2.0111460686,-1.3398618698,-1.7623288631,-0.3162357509,-0.3991983831,-0.1123126596,0.4193961918,-0.8965550661,-0.3267290592,-0.8449197412,-0.9209045172,-0.2399897277,0.4476865530,-0.7418269515,0.5197879672,0.0386816151,1.1803443432,0.2628131509,-0.2394232601,-0.3722534180,0.6683313251,1.3366475105,-1.4936909676,-1.4146258831,-0.2376010120,-0.2817085683,1.8941197395,0.4649803042,0.8323036432,0.4888179898,1.1489104033,0.6556180716,-0.7000198960,-0.6820146441,0.4848237932,-0.5177137852,0.0824175030,-0.8797442317,1.1639926434,1.1476025581,-0.8527011275,2.0083818436,-0.2703168988,-1.2097411156,-0.2276968956,0.2739947438,-0.5334571600,-1.5935918093,1.2445474863,-0.3134967685,-0.2985264361,-0.7968905568,0.8554915190,1.6267149448,0.6216568947,1.5030903816,-0.1151232570,0.8909834027,1.8018869162,-0.0360328667,-0.8202154040,-0.2220973074,-0.3517731130,-0.5957280397,-0.1514147520,-0.4198016822,0.2551528811,-0.1152595282,0.2171547413,-1.4629511833,1.1438225508,1.2084295750,-0.8150461316,-0.7321365476,0.3776405454,-0.9554858208,-0.4959684014,-0.2907817662,-1.0054425001,-0.4517457485,0.1696795672,-0.6147547364,1.1529808044,0.0660743788,1.5753021240,-0.4344066083,-1.7833483219,0.0277798567,-0.5330213308,-0.9183149338,-0.6086820960,-0.4047652185,-0.6416500807,-1.0837899446,0.0532945246,1.1404436827,-0.0453740098,0.7457920313,-1.9460426569,1.7987947464,0.9324730635,-0.8482402563,0.6843633652,1.3739305735,0.3718565106,-0.1377663314,-0.9630939960,-0.3043234050,0.0718399286,-0.2703020275,-1.1004296541,-1.3805667162,-0.5695853829,0.4196306765,1.9971634150,0.8231883645,0.2833084464,-0.2101227045,-1.8163676262,-1.7911117077,0.1537543535,1.9449908733,0.1513811201,-1.1334222555,0.5895084143,-0.5986622572,0.3019756973,0.7390938997,0.9933456779,0.6807634830,0.9933760166,0.5551660061,-0.8488301039,-0.5885685682,0.4313100278,-1.3862833977,0.7359342575,0.9195241928,-0.0853480026,-0.1070248708,-1.2493082285,0.5755701661,-1.0534989834,0.0406493060,-0.5918547511,0.0460599251,0.7082794309,0.7456382513,-1.0815974474,-1.2848150730,0.7570005655,0.9823464751,-0.4332475960,1.9694807529,-0.5031172633,-0.8139947653,-1.9751011133,1.2804644108,0.5563730001,-0.4628264606,1.1694854498,-0.4353146255,-1.6423184872,-0.5444234014,1.8026432991,-1.5473425388,0.3108020425,1.2917841673,-0.3807676435,1.7654125690,-0.6993806958,1.1027238369,0.6636332273,-0.6843606830,-1.4899740219,0.2734349966,1.2600288391,-0.2286336422,0.2327901125,2.4362354279,0.1817132533,-0.7989073992,1.1250274181,-1.0452672243,-0.8149611950,-0.2601708174,-1.3295027018,2.2031581402,1.1800258160,0.2624831796,-0.0770635083,0.7740607858,-0.3567553759,-1.1034004688,0.1847368032,0.6796195507,-1.0074751377,1.1585245132,1.4195199013,-0.6195434332,0.7116128802,0.6401365995,0.5280639529,-0.9293158054,-0.0831103027,0.5697512031,1.0032013655,1.0931603909,-0.4489105642,-0.2979501188,1.0878436565,1.6233495474,1.4550083876,-1.1979384422,-0.9113218188,-1.2620170116,0.1533333361,0.3634153008,-0.3303910196,0.1722114384,0.1782008410,0.9415059686,-0.7712236643,-1.5482803583,-1.4313429594,-0.3579024374,2.3041453362,2.1099629402,1.6484801769,0.1672390848,-0.0169916637,1.7207933664,0.2674842775,-0.4923659265,-0.6619585752,0.8079488277,-1.6243458986,-1.7960036993,-0.7675559521,-0.0231633689,-1.0103166103,1.2741718292,-0.6419000030,-0.7730162740,-1.4375553131,1.1895669699,0.3485536277,-0.4232673645,1.2198886871,0.4842070043,0.0227463860,0.5305594206,-0.8054476976,-1.7734887600,0.3406913579,-2.7052669525,-0.0847135931,-0.6385948658,-0.5110730529,0.3484685719,-1.3105498552,-2.5472373962,-0.3775078654,-0.0988472104,0.4710415006,-1.2057213783,-1.7653845549,-0.0680527538,0.7711173892,-0.7321217656,1.0039491653,-0.7371895313,0.5678637624,0.3336027265,-0.5274707079,-0.9774408937,-0.3786778450,-1.4249675274,-0.7147436142,0.3129166365,-1.7783929110,-0.4209950566,-0.5415373445,-1.2222980261,1.3970868587,0.8098871112,-0.2767983675,-1.8499927521,0.1502419710,-1.5492517948,0.7092196941,1.4950456619,-1.1154440641,-0.5161579847,1.2957165241,-0.5796651840,0.6269744039,0.9531516433,0.2816024125,0.4732829630,-0.7617855668,1.6947957277,-0.0578788295,-0.4390718937,-1.1987463236,-0.4341277480,-0.0426968820,0.7203280926,0.3357464373,0.8612458110,1.0400627851,-0.0488214567,-1.2987916470,0.8273304105,1.0139622688,-0.0649127662,0.7446480393,-0.1540967673,1.9260265827,1.2363505363,-0.4862475693,0.4868167043,1.7191879749,-0.0682080835,-0.9640083909,0.3089770079,0.9302484989,0.9873762727,-0.5898210406,0.4689652324,1.5302232504,0.7320433855,-1.3513690233,0.7897057533,0.2824765146,0.5834311843,0.1131865606,-0.8406014442,0.4050630033,-0.4101101756,0.5337298512,-1.3036297560,-0.6484665871,-1.1359941959,2.0571515560,0.6670948267,-0.4131903946,-0.5690752864,1.4522426128,-0.9800069332,-0.1403042823,-1.0196304321,0.9959092736,-0.2827495635,1.9643141031,-0.6609107256,-0.7525837421,0.5954794288,-0.3523457646,0.3810907602,-1.0135425329,1.4329707623,0.8080863357,0.8896982670,0.2208904177,0.3672073483,-0.6885126233,0.4308250546,1.1822276115,-2.0149857998,1.9600487947,-0.5171279907,-0.1703243852,0.8568869233,1.2518591881,0.2865099013,0.8115671873,-1.4276633263,0.5710371733,1.0781027079,2.2357771397,0.7279140949,-0.2229265273,0.5872340798,1.4881185293,2.3195126057,0.5637220144,0.6914354563,0.2569299936,-0.2285066694,0.4804783762,-0.2613047361,-0.4131895602,-1.4262596369,0.4228245020,1.0623100996,0.2604335845,0.6574383378,-0.0409760214,-0.1292385161,-0.6623541117,-0.6476683617,-1.6716749668,-0.1830161214,-0.3365137577,0.6030265093,-2.0935566425,1.2513388395,0.3918113708,0.7372437716,-0.0178348534,-1.1537516117,1.0530462265,-0.8401392698,1.8309344053,-0.9686001539,-0.3691553771,-1.4921547174,0.0017514684,-0.4581293762,-0.6935526133,1.0855137110,-1.0821048021,0.7962128520,-0.1281221062,-0.8133049011,-1.2505276203,-2.2208952904,-0.2130862474,1.0099068880,-1.4203333855,-0.2492176443,-1.3636775017,0.1963888705,1.9370468855,0.5962476134,-1.6595464945,0.1022451743,-0.5378738046,-1.8219336271,0.0530054718,-0.3030683696,-0.0812117681,-1.8513782024,0.3097834587,-1.5337352753,-0.2538897991,1.3182882071,1.1397893429,0.4829955697,-0.9046905637,-0.8380981088,-0.2948737741,1.9916062355,0.0728184804,-0.1014356986,-0.1235939339,-0.5081471205,1.2604811192,-0.1343659312,0.2073383778,0.3723934889,-0.4487771392,-0.4661149383,-0.3359813094,-1.3195090294,0.3540134430,0.3601185679,0.0083168242,0.3976401091,-1.6742360592,0.2504509389,-0.6635281444,0.8641865849,-1.1257250309,-0.3801716566,-0.1833992749,0.3565971553,-1.3327323198,0.6035583019,-0.5465292335,-1.5566965342,0.6932677031,1.6228110790,0.6801456809,-1.5924171209,-1.5193947554,-1.0084333420,0.4458001256,-0.8410766125,1.5464582443,0.6618500948,1.3115892410,-0.8060818911,-2.0020639896,-0.7427703142,0.9982657433,0.0429815277,-2.2929155827,0.7949628234,-2.0755562782,-1.1538249254,2.2420399189,0.3406197131,0.0048286184,0.2839885652,-0.4365164936,1.3366078138,-1.8391609192,0.3603280187,-0.0859675929,0.5570289493,0.5718832016,0.6106733680,-0.3083177805,0.0144931190,-0.2672089338,-1.2353001833,3.0229272842,0.3395426869,0.5264291167,1.2634595633,0.1770529449,-1.4849345684,-0.6991217732,-0.7283034325,-0.6939549446,1.5446032286,-0.2754387259,-0.2167219073,-0.7424051166,-0.9166474342,1.5751912594,-1.6181910038,-0.8253030777,-1.0706801414,0.8698484898,-1.1994905472,-0.8146388531,1.2920223475,-0.4625878930,-0.3836516738,1.0654515028,1.6666485071,-0.1208937168,-1.4995495081,1.2321619987,-0.6949200034,-0.5739510059,-0.1775606424,-0.9272752404,0.5301542282,-1.1949777603,-0.4780461788,-0.5277665854,-0.9728552699,0.4626088738,0.4503042698,0.9948613644,0.2734299004,0.1685026735,-0.6112354994,-0.9500792027,1.8824837208,1.7905997038,-1.1740034819,0.0983359888,-1.1613261700,-0.3503814936,-0.8911704421,1.0788980722,0.5437412262,0.6564418674,-2.4974653721,0.4571970403,0.0749873742,0.0620500483,-0.2306726277,0.1126581952,0.6336370111,-0.4393058419,0.6253045797,-1.3444340229,0.3629311323,0.9891084433,1.3607655764,-1.6233907938,0.3538567126,1.2099943161,0.7256388068,-0.4102138281,0.4880381823,-0.6662564874,-0.3059380352,-0.1223294958,0.9289811254,-0.9578050375,0.7637707591,-2.6466319561,-0.8069033027,0.2090090364,-2.1910057068,0.8204702735,-1.6458770037,0.1837251335,-0.4417119026,-0.3663473129,0.7258780003,-1.0395754576,0.3824823201,-1.3599922657,-1.3667659760,0.2267869860,1.0660798550,0.7252836823,-0.0433388688,-0.8327400088,0.5989152789,-0.1539460868,0.8072755933,-0.1370912343,-0.3414518237,0.6859472990,-0.0732531026,0.4887581468,1.4984587431,-0.8649017811,0.1688008904,-0.1289001107,-0.9218314290,-0.3603636324,0.9271414876,0.0079463189,-0.3383709490,0.8675869703,0.1249827370,0.4651188850,1.1462744474,1.2493416071,-0.4183758795,-2.5614197254,0.5680629611,-0.6206008792,1.7465558052,0.3847604096,1.4685661793,-1.1315544844,1.1918085814,-0.6606284976,0.4041602910,-1.4739680290,1.1007773876,-0.4919222891,-0.1771818995,-1.2822349072,-1.0434724092,0.3237209916,-0.7618917823,0.3099120855,-0.5639561415,-0.0917711481,-0.5850586891,0.6370205283,1.0494756699,-1.9202592373,1.2494323254,0.5849095583,-0.8469260335,1.3565355539,-0.0963294879,1.2453507185,-0.1400534064,0.8450857997,0.4133973122,0.7155808806,1.4432688951,1.5716166496,0.6924489141,1.4065362215,-0.4133162200,1.0888381004,1.3608398438,-1.0978585482,-0.2764387131,0.5563209057,0.8842734098,-0.3509296477,-0.9768342376,-0.7402306199,0.2903321981,0.1414962411,-0.4799614251,-0.3082216084,0.0267795082,1.2097295523,0.2476162165,1.1630425453,-0.0845261142,-0.2282030135,0.2696264684,1.2454012632,-0.1312718689,1.4098299742,1.0410118103,-1.6086004972,-0.5174929500,0.8974530697,1.0401508808,2.2852160931,-1.0753257275,0.0802447274,-1.2287327051,-0.0713328272,-0.8569629192,1.1176137924,0.5114846230,0.6936994195,-0.8175045848,-0.6783365011,-0.7737123966,-0.3651148975,0.6318411231,-0.6266897321,-0.6617985964,-0.5669463277,0.2499994934,1.1892088652,-1.9240505695,-0.3544670045,-1.0515387058,-1.8288736343,-1.2691622972,-1.3089474440,-0.0297324564,1.2603071928,-0.4449788332,-1.7621899843,-0.8053673506,0.5204708576,0.2721701562,0.2346938401,-0.6873981953,0.2655944824,-0.0325214528,0.5738306642,-0.5787928104,-0.8237167597,-1.2874125242,1.1350760460,-2.1356105804,0.4515221119,-2.1500139236,-0.4114108384,-1.1628191471,0.1297886521,-0.2495429516,-0.0260325857,0.9392570257,-1.3046522141,0.6903501153,0.6977592707,1.0701305866,-0.2887674570,-0.4104785323,0.1533241421,1.3199142218,0.3096901178,0.4101806581,-0.7352973223,-0.9126303792,-0.7222605348,-0.4227232933,-0.2477057576,0.5480054617,-1.1432491541,0.3385492861,0.2351884991,0.0385535322,0.8181906939,1.5828475952,0.7214038968,0.0897340551,-0.3189024925,-0.3974009156,0.9097927213,1.9650508165,0.1053364798,-1.2227591276,-0.0153107131,-1.2919523716,-0.7455282807,0.9781656861,0.6193071604,0.4077815115,-0.7046490908,0.1537861079,-0.0643131956,1.2573903799,0.9574343562,-0.5834718347,0.1090049073,0.5478889346,0.3504471183,-0.2250039279,0.8269471526,-0.0169237554,0.6220702529,-0.2975426614,1.2149496078,1.1151980162,-0.4507243931,2.2206854820,-1.8293071985,2.6430711746,-0.1439989805,-0.0610520355,-0.2829388976,1.0629047155,-3.1820971966,0.4401958883,0.7499151826,2.5593225956,-0.9967869520,-0.2721943557,-0.0896866843,0.6282408834,-0.0261002425,-0.9709675312,0.0230096858,-0.0140103968,-1.6569482088,-0.1382927299,0.7253227234,-0.7418099642,0.9728586674,0.4095517993,0.0483989120,0.0979183540,0.3018720746,-0.3589890599,0.5353608727,0.5360045433,0.7536387444,0.7505097389,0.5256783366,1.3380362988,-0.2981445193,1.8530151844,-1.1281915903,-0.0498322956,-0.7330253720,-0.6458021402,-0.5024451017,-2.2123041153,-0.9805191755,0.8008458018,-1.0077247620,0.6239641905,-0.8552334309,-0.2744834423,-0.1157714501,0.0847591385,-0.3774202764,-0.3264375031,-0.0360224955,-1.0819702148,0.3266488910,0.5532034039,-0.3854060173,-0.1618631631,-1.9549201727,-1.7788834572,-0.1174470335,-0.2493743002,2.1404275894,0.5593461990,0.6229158044,-1.8816431761,1.4607295990,-0.3706546724,0.0042911167,0.3046770096,-0.0710433796,-0.1237470731,0.4302512109,0.4529004395,0.6425746083,-0.1122784540,0.9161322713,-1.1342129707,-0.5450671911,0.2877930403,-0.2188682407,1.2186625004,-1.1504718065,0.5568408370,1.3841053247,-0.1620552093,0.7049739957,-1.2413967848,-0.9855633974,1.3243196011,0.3625219762,0.2983141243,-1.2990237474,-0.2681641281,0.1363256872,-0.1956966519,0.2655187845,-0.1531553864,1.2532037497,1.8852713108,-0.0882719830,1.7805033922,-0.4716087878,-0.9298340678,-0.3180843890,1.2743237019,1.0903788805,1.0813274384,-0.6996761560,0.7500818372,2.1777994633,2.2021887302,0.2121428996,1.6765725613,-1.2105097771,-1.5527480841,-1.3053249121,1.9286055565,-1.3529680967,1.0474323034,0.2311239541,-1.3959530592,-0.6062406301,-1.8592184782,1.0289849043,-0.1385550201,2.3706924915,1.1001138687,-2.1009137630,0.6809428930,-1.6257436275,-0.6237348318,0.6981055737,-1.8643096685,0.4661882818,-0.2186380774,-1.3467729092,-0.9527578950,0.2725820839,1.3400031328,-0.5603945851,2.5774965286,-0.5632506013,-0.3768528998,0.0353212729,1.4043915272,0.0230951086,-0.0061584190,0.6321358085,-1.9023759365,1.5614373684,-0.1971298605,-0.7250073552,-1.0256675482,-0.4578739703,-0.6443290710,-1.0963523388,-0.0895931944,-1.4758558273,1.6121660471,1.1630821228,-1.7796010971,0.0145237353,-0.5974840522,1.0503715277,0.3695131540,-0.3743128181,0.0213968288,-1.0481902361,1.0413702726,0.3212760389,0.3309848011,-0.6946014166,-0.7083328366,0.9349833131,-0.1450703889,1.1152725220,-0.8652854562,-0.4565080702,0.3007369041,0.9256248474,2.0625565052,0.2747337222,-0.2963839471,-2.6546571255,1.2803245783,0.1107093021,-0.6835398674,0.4723945856,0.9344331622,-0.7295447588,-0.2803449929,0.1233135983,0.6120019555,0.5841313004,1.7533856630,-1.0543075800,-1.2622847557,0.4116769433,-0.6446053982,-0.2465761304,-0.7146756053,1.3107023239,0.6113011837,-0.1636191308,0.4882713854,-0.3482097387,0.1603152454,-0.4162207544,0.1293164194,1.7988963127,-0.8851790428,0.3992467523,-1.7737257481,-0.3428349793,1.8912366629,0.0722259954,-1.6537472010,-1.6307649612,-0.4667405784,1.1868702173,-0.7915568352,0.4578755200,0.2519705594,-0.9535153508,1.2609884739,0.4392801523,-1.3256343603,-1.0367951393,-0.2201278061,-0.6169109941,-1.0181512833,-0.4103388190,0.1084682569,-0.6541967392,0.7603313923,1.3501311541,-1.6931246519,-1.5221095085,-2.0480751991,0.4730706215,1.3266686201,-0.0894597024,0.3304823041,0.1989917606,-0.4702607393,0.2213799506,-1.5739086866,1.7835437059,0.3327397406,-0.4354090691,-0.1039255261,1.8387240171,0.3680784702,0.6319974065,-1.5963237286,0.0214680173,-1.0597387552,0.1692428887,-0.1024794206,0.3460634351,2.1404290199,-2.7088286877,-3.3357634544,2.4715435505,0.5048002601,-0.0024718831,-0.3783724308,-1.8512169123,0.0197386872,0.5260105133,0.0301570203,1.1527439356,-0.6599699259,-0.7668974996,0.9182029963,-2.0533874035,-0.5711094141,-0.8333142400,0.5297877789,0.1696676463,-1.1874402761,2.6695325375,-0.3015936315,0.0863558426,0.6479152441,0.4200901091,0.0836594850,1.3033480644,0.6622453928,-1.5946129560,1.1357042789,-1.2606321573,1.0469983816,1.1802233458,-0.1032438353,1.1054823399,-1.2712923288,0.0872885138,1.3110666275,-0.3147211671,0.7948974371,-0.6520865560,2.3930139542,-0.6381352544,-0.1903901398,0.7538375258,-0.6007530093,-0.4748378098,0.4931529164,-0.3945479691,-0.7058361173,-0.4707331657,-0.6427865028,1.1003127098,1.2145934105,0.6543659568,0.1378059983,0.2667719126,-0.4505184293,0.7668704987,0.3069391251,-1.0402356386,-1.0768088102,-0.3584763110,1.4544060230,-1.4216730595,0.3472038507,0.2086229771,0.5839641094,-1.4341008663,-0.6708384156,0.2508373260,0.8319552541,0.5872681737,-0.4998468161,-1.1823883057,-0.3054107130,-1.0352274179,-0.6697105169,-0.8784491420,-0.8758939505,1.3824001551,1.1037901640,0.5120603442,0.2342875302,0.7024837136,1.1357293129,-1.0685719252,0.1360779256,-1.2616283894,0.1958422810,-0.7124678493,0.4309418797,-0.8070568442,-3.6666617393,1.2247881889,-1.8534743786,-0.8791117072,-1.1550799608,1.3362749815,0.6916596889,0.1911562085,-2.1766350269,-0.2334984988,0.1585360169,1.7308087349,0.2101554424,-0.4219810665,0.6413149238,3.6585171223,-1.6798986197,2.1572251320,-0.9573594332,2.1295564175,1.6554572582,1.4173837900,-0.1184742749,-1.3791389465,-0.1836668104,-2.5507338047,-1.8902881145,-0.2113366872,1.7934159040,-0.4378238618,-1.6616495848,-0.5122920871,-1.7967692614,-1.2768464088,1.4960579872,-0.4098713994,0.2792552710,-0.6689916253,-0.2977707684,-0.5372231603,0.6325138211,-0.3380914032,0.1361745149,0.5060076714,-2.7306387424,0.5758006573,0.0367980748,0.4948950410,1.3093698025,-0.6927099228,0.5162115693,-2.8285930157,1.4057217836,-0.8556907177,-0.5703662634,0.1480660737,0.2890440822,-1.7777055502,0.6198061109,0.9095965624,0.2691595852,0.0894911662,-0.0680072829,0.8367866278,1.0884227753,-0.7422149181,-0.3737275600,-1.6788115501,0.1495314837,-0.9467903972,-0.1744271517,-0.7147907019,0.5539358854,-1.1186755896,0.6251395345,0.6120824218,0.1489314586,0.7221364379,-0.6673222780,0.5348725319,-0.0781799033,-0.4313751459,-1.4768824577,0.6255025864,0.5036774278,-2.0770540237,0.8228256106,-0.2019738853,-0.0633517280,0.7215458751,2.4272737503,-0.4849633276,0.7702387571,0.7469590902,-0.1873421669,-1.3352429867,0.8034677505,0.5133347511,0.3616528809,-0.0800107121,1.6482689381,-0.2358781248,-1.1339635849,-1.1484259367,-0.2858934999,-1.7178094387,0.0422221310,0.7282291651,-0.5086132288,0.2948485017,2.0248792171,0.9847933054,-2.2134039402,0.1210705861,0.9005804658,-1.7938214540,-1.1630740166,0.6061529517,-1.3917492628,0.0659918785,-1.5254364014,-0.8436492085,-1.4030380249,-1.1273025274,0.6605858207,0.5244283080,-0.5535778999,0.5154033899,-0.0494096726,1.9339607954,1.0602059364,-0.2275834680,0.1745944023,-0.3988296390,0.2007772624,0.4210469723,1.1622320414,-0.1475005299,1.6775492430,0.3825560212,-1.4785602093,-1.0011734962,0.9199843407,-0.3728865385,2.1775677204,1.0654608011,-0.3552238345,1.2858337164,-0.0408678167,0.7288712859,-0.6996934414,-0.9515546560,1.4982056618,-0.8414525390,1.5781154633,-0.8477112055,-0.2554596066,0.7263152599,-0.8979797959,1.9918254614,-0.0547553524,0.2416841537,-0.0709533319,-0.8204307556,-2.0357275009,-0.1745917797,1.0008513927,-1.1479756832,0.6434391737,0.3278440535,-0.8116710186,-1.0752303600,0.3474791348,0.0802315548,0.1050836816,1.6445997953,-0.6685065031,0.2889428735,0.1904595792,1.9781349897,0.0672670230,-0.0199888926,-0.3196633160,1.0699506998,0.5876069069,1.4938871861,-0.2294600457,-0.6761348248,-0.9675368667,0.3901038170,0.9939051867,0.1740347892,1.2410316467,0.2331166565,-0.4013488293,0.0780516416,0.1232619882,0.4011231065,-1.1274694204,1.7268871069,-0.3178609014,1.1595098972,0.5392588377,0.5934121609,0.0710647479,-1.4837100506,-1.5382093191,2.3655643463,0.4086492658,-1.4912976027,-0.2096750140,-1.2068072557,0.1913460344,0.9109123945,0.3377050161,-0.8817027807,-1.7224570513,-0.7705970407,-0.5596790910,-1.0413635969,-0.4826701283,2.7578041553,-0.7895061970,0.2393582165,-0.1677271277,-1.5210280418,-0.9905596375,-1.2625994682,1.8897997141,-1.3356403112,-0.2018123269,1.1257551908,-0.6290640831,0.6600694656,-0.0313108787,0.3371075690,0.8491163850,0.9079491496,0.7914938331,0.5391131043,-0.4028544128,-0.3595976532,0.9391801357,-0.9340050220,-1.5900048018,1.0865169764,1.5760774612,-0.9845061302,-0.4753736556,-0.4715046287,-1.0118333101,-0.3843485117,-0.0267880801,0.0341033973,1.6630090475,0.7196737528,-0.9001411796,-0.1763302237,-1.8384820223,-0.5711111426,-0.6256062984,-1.0332602262,-0.2247431427,-1.4039026499,-0.6790704131,-1.2205200195,0.5722601414,-0.8030456305,-0.4784704745,-0.2942892313,0.6278070807,0.1514698267,0.4336849153,-0.3661702573,1.2590053082,-0.3364170790,-0.2155324370,-0.0285432246,0.7176227570,0.2905178368,-0.4122419655,-0.0120573184,-1.0927163363,-0.4791768491,1.0728253126,-0.4578598142,-0.1820637584,-0.6342881322,-1.2003618479,-0.5084941983,-0.1252528578,-0.5457894206,0.3418527246,-0.2050891072,-0.3844342828,0.8712399602,-0.0385699309,0.0265888497,1.3547886610,-0.3125000596,1.2956840992,0.9276458025,0.3030017912,0.9541946054,-0.7833327651,-0.9277109504,-1.5816023350,1.3954637051,-0.0899096355,0.9990671277,0.7146677375,0.2361557186,-1.3013103008,-0.1263361424,-0.2064883858,-1.6868683100,-1.2527776957,-0.4654269218,-1.3014801741,-0.1094226167,-0.1444881260,-1.4770342112,-1.9824503660,-0.3436704278,-0.8657111526,-1.2764846087,0.4240189195,0.5265209079,-0.7517572045,-0.8044191599,0.8929079771,-0.3144601882,1.0459331274,0.3026503921,-0.8141273856,1.7526532412,0.5301589966,-2.1711890697,0.2059477270,0.8248731494,-1.6328703165,0.4597865939,0.8475491405,0.2477189749,0.0925393179,-0.4595969319,-0.1853267998,0.3266243339,0.6708236933,0.6769939065,-1.0828754902,0.2627280354,1.3661319017,0.1279993355,0.9695571065,0.1432794780,1.1143633127,1.1418329477,0.1405775994,-0.4752911925,-0.0177135766,1.0221664906,-0.3322848976,-0.5167743564,-0.7432743311,0.3890959322,0.1556181014,-1.8614654541,1.6840809584,-0.7621278167,0.1582335532,-0.2684752047,0.5648133755,-0.1776323318,-0.6139817834,0.1006056443,-1.0148520470,-0.0685680658,0.9740679264,-1.0096333027,-1.2929003239,-1.1497299671,-0.2576673329,0.2650620937,-0.5298980474,0.1767422408,0.3737693727,0.0116174156,-0.8848586679,-0.2841534019,0.2786668837,1.2182451487,-0.8785102963,-0.6624893546,-0.2506814599,-1.6583607197,-0.0440883674,0.7125759125,-1.9737573862,-0.4872403741,-0.1577950418,-0.8622025251,0.1490759254,-1.1009280682,-0.7130812407,2.9556460381,1.6436719894,0.6758390665,1.0099107027,0.0647838414,0.3598891795,-1.5434740782,0.2607182264,0.7817473412,-1.9403500557,1.4225147963,-2.1519820690,0.5616424084,-0.8769695759,-0.2707855403,2.4196352959,0.2859359682,0.0165289156,-1.7499842644,0.3692513406,0.5031059980,-0.1664648801,-2.0056574345,-0.7654278278,1.0434603691,-0.6375411749,0.2848365307,0.0735133290,0.8452553749,-1.4876236916,-0.2486355007,1.4121173620,0.7177804112,-0.7401977777,0.3545803130,-0.5262724757,-2.8600194454,-1.9175211191,0.4451819360,-0.0762447342,-0.1314585060,0.8150295615,0.1831329763,-0.0879756361,-2.0604195595,0.2432845235,-0.1897565573,2.0000879765,0.2861734331,0.0464978926,0.1709866971,1.3898837566,-0.3738046587,1.2233188152,1.0814232826,-2.1520938873,1.0503945351,0.7663048506,-0.7665901184,0.5697636604,0.7073093057,-0.7511551976,-0.9094853997,-0.4420854747,0.9772966504,-0.1575781852,-0.1842168272,-0.3205026686,-0.6077862382,-0.0882692859,2.2927906513,0.9862863421,-0.2564762235,1.4920821190,-0.2900837064,2.2671697140,-0.0333347134,-1.1995899677,-0.3519096971,0.0096649854,-1.1579176188,0.1301806569,-0.3239947259,0.2254819572,3.1275162697,-2.1915900707,1.6642601490,0.3813494444,1.1953544617,-0.1923963130,-1.3483207226,0.6332259178,-1.1693799496,-0.8710323572,2.1890964508,0.5400183797,1.4145956039,0.7931981683,0.0518532507,1.3498840332,-0.3464334905,1.8504086733,0.2446140349,0.6482831240,0.9984034300,1.3537937403,1.1133658886,-0.3245791793,1.3398704529,0.4796682596,-0.4233224094,-0.6885091066,0.1215857938,0.6505106688,-0.4377563298,0.6642935276,-0.7825295925,-1.0611126423,-1.0111138821,2.4128932953,0.8924791813,-0.4122083485,1.2046082020,0.5568127632,0.7432289720,1.3462983370,-0.4105149806,-0.0584207624,0.8289735913,0.0149429040,-0.9931199551,1.9934371710,-0.4420913756,-0.3624625206,-1.1244492531,1.4691061974,-0.0499073863,0.2002401203,-1.1248832941,-1.2726184130,0.9452376962,-0.4676527977,-2.2370703220,-2.2448759079,0.9237034917,0.4242494106,1.7204461098,-0.3976499140,-0.0906097963,1.4850599766,-0.1435298324,0.3990937471,-1.3640803099,0.1675154865,0.9451347589,0.1672854722,1.1541965008,-1.3738102913,-1.6310482025,0.4398053586,0.9419565201,0.4221067429,0.8890461326,0.9389849901,-0.5344372392,-0.2121012062,0.1934045106,-1.1489433050,-0.1732483953,1.6298263073,0.7644013166,0.0068043680,-1.4946343899,-0.1486235559,1.0825355053,1.0867308378,-1.5739576817,-1.1025074720,0.3009252548,0.1753404289,0.1530693769,1.4307221174,-0.9575708508,1.3203545809,-0.6723961234,0.4719530344,-0.2558166087,-0.4151659906,0.2092033029,-0.3377778232,-1.7142255306,-0.0780475810,0.1520982683,-0.6602406502,0.8542318344,0.0446649306,-0.1880837232,-0.8102146983,0.1999365538,-0.8471016884,0.6609727740,0.0869688913,-0.8234723210,-0.0038673137,-0.7962244153,0.4736574292,-2.1708366871,0.5728909373,0.0155894784,0.1019155160,-0.9545924664,-0.0417357050,0.0830023661,0.3825495839,-1.5725542307,-0.5406516194,1.8002802134,-1.1717652082,-0.1948368400,1.2039487362,0.5995358825,2.4622888565,-1.4696532488,-1.8450510502,-0.8768398762,0.0656154454,-0.6295272112,0.0151507873,0.9739693999,-1.3466656208,1.7466659546,-1.2967122793,-1.5379266739,0.0025664088,-0.5259938240,-0.7475365400,0.1608507335,0.2720134556,0.6598511338,-0.2686775327,0.2295012027,0.1086877584,0.2343160212,0.4769563675,-1.0597660542,-1.9808396101,-0.7161743641,0.8676317930,-0.5259642601,-1.6665190458,0.2771702707,-0.5351759791,0.5666056275,-0.0272630919,-1.2385288477,0.6036389470,0.5278122425,0.0797868595,0.0228599031,-1.9098942280,1.5135689974,-0.2744904459,0.3447202146,-0.2918914258,0.0123673119,-1.0660989285,-0.7806712985,0.4060901105,-0.3038170338,-0.5685398579,0.7254636288,-1.4262027740,0.3587500751,-0.0250621587,0.4670973122,1.7571234703,1.2794920206,-0.7825925350,1.7953877449,1.4440474510,0.2549488842,-0.5291935802,-1.8028976917,0.2191513032,0.2555356026,0.0594101250,-0.2747816145,-0.8839666843,0.5966591239,-0.2426848710,-0.2062047273,0.6629035473,-1.1385248899,0.0354150161,-1.4973627329,-0.4372212291,0.1723114401,-1.4453716278,-2.5439577103,1.0714870691,-2.3216881752,0.6471449137,-0.2535232008,-2.4768803120,1.8743288517,0.3274333775,-1.4912362099,-0.4837066829,2.1048803329,1.4479202032,-0.6346545815,0.2597027719,-0.5986030102,-0.9634928703,1.1574920416,0.4726140201,-2.7617619038,0.4451379776,1.5339012146,0.6199848056,-0.6614613533,0.4931938350,-0.7092412114,0.4458418787,-0.7853662372,-0.2501262426,0.1611269265,-0.5285350084,-1.6091034412,-0.1904814690,0.5117421150,0.3120868802,-0.4000595510,-0.7666798234,0.9289351702,-0.2531622946,1.1696226597,-0.4199027717,0.3557711840,-0.4890812635,-0.5624075532,1.2869091034,1.1910554171,-0.3527726829,1.6044161320,1.2182590961,-0.0506892353,0.2301639915,2.1127395630,-1.8038836718,-0.1752304137,0.3366157413,0.1188599542,-0.3038607836,-0.6614480019,0.6676669121,0.8247133493,1.1330426931,-0.3428809941,1.3835335970,0.7142785192,-0.2841734886,0.8137839437,-0.9763744473,-0.5805509686,0.8007320762,0.7538213730,0.6759210825,0.6667888165,0.1327999085,0.5388278365,-2.5514461994,0.2968763709,0.0856194794,-1.2785900831,1.3809236288,0.1545603722,-1.6245212555,-0.9858641624,0.0683231354,0.9755828381,-0.1573059112,-0.5441203117,1.4863932133,-0.3820349276,-1.8454742432,-0.9734540582,-1.0773816109,-1.5850419998,-0.7565042973,-0.8189355731,0.4546409547,0.1463429332,0.2750940919,0.3259109557,-1.6890685558,0.6469773650,-0.5459377170,-0.3998305500,0.8339851499,2.4585688114,0.1916992962,1.0748101473,0.9357467890,-0.0929414183,-0.6584252119,-0.3570420742,0.0665325448,0.7298585773,-0.8224898577,-0.6889728904,1.1683588028,0.0241510794,0.6844079494,1.1921299696,2.1824836731,0.4918388128,1.9142444134,0.4802091420,0.7324468493,1.3169702291,-0.0847907364,-0.4453571439,0.3699448407,-1.0258462429,-0.3116862476,-0.0516151153,0.7953120470,0.6979629397,2.1893255711,0.3988084495,-1.1665880680,0.6708530784,0.6878688931,-0.8248539567,-0.5847064257,0.5866395235,-0.3840931952,1.4220393896,-1.1018649340,-1.1234416962,0.4223946333,-1.5349240303,-0.0431141518,0.2294328213,-0.6951954961,-0.4299486279,0.9124315977,-1.1123651266,-0.0226851795,-0.6936195493,-0.0072121215,-1.1652355194,0.1803177744,0.5420455933,-0.1974164546,-0.1034566686,-1.1659656763,1.4620234966,0.0676573440,-0.1860376447,-0.0255707297,0.5868535042,-0.7124443650,1.8730525970,-1.4280098677,-1.2111260891,0.0161925871,-1.0231288671,1.1533496380,0.0843438879,1.8062423468,0.4847639501,-0.1865802705,-1.1985164881,-0.7404387593,0.4595836401,0.3563097715,1.2884920835,-0.1245478317,-0.0213925559,-0.2822938859,-0.7291942835,-0.8705769777,0.9221906662,1.9151195288,0.2899247408,0.1849166900,0.0617027730,0.9693223834,1.1434739828,1.3673071861,1.3153882027,0.0179758314,-0.6445850730,0.1999620199,-0.6685073376,2.1232419014,-0.5719731450,0.6747733951,-0.0902681053,0.5864809155,-1.6446373463,0.9344949126,0.1072397977,0.9640066624,0.2265440077,0.1202564687,1.8057010174,1.2321231365,0.1216363013,-0.8128648996,-1.1337174177,-0.4002026916,-0.3188920021,-1.5820558071,0.6039871573,-0.9864867330,0.6012089252,2.4563450813,-0.5732899904,0.9521592259,0.3260547221,1.8853037357,-1.3204982281,2.0496821404,-2.2340407372,-0.6887130737,-2.2608993053,2.0778744221,2.7424345016,1.0892106295,2.5908606052,0.7477040887,-1.4859695435,-1.3533649445,0.5172604918,-0.2675825357,-2.2346560955,-0.7207927704,0.6210254431,0.4351610541,-1.5440757275,0.7776510715,0.8183146715,-1.9388126135,0.6442348361,0.1557279527,1.6979936361,-0.4870493710,-0.2069469690,1.2790093422,0.0868159607,1.1734422445,-2.3761756420,-0.2298842072,1.1400439739,-0.6254145503,-0.4515355527,-0.3749254644,0.8611729741,0.4854235649,-0.1822100878,-2.0930531025,0.2222319990,-1.4868695736,-0.3692798316,-1.3354876041,-1.3781586885,-0.2719875872,0.9334027171,0.5190452933,-0.8337520361,0.4389167726,-1.2404805422,-1.3586823940,0.8238016367,0.0736838952,-1.8239998817,0.6703809500,0.2388516814,-0.8363975883,-0.5493038297,1.1531976461,-0.2203984410,0.8369795084,-0.3004584610,1.3316445351,0.2204501927,-1.3941072226,0.5796142817,-1.4743403196,0.2360322624,-0.0470898226,3.3544440269,-0.0383296460,0.5620162487,0.3400013149,1.6698427200,0.3058384955,1.0403901339,0.7896620631,2.2139503956,-0.8617098927,0.0116197933,0.2294577211,-1.6858422756,0.8578336239,0.0620743819,-0.1545120627,0.3085938692,0.7593377829,0.6065549850,-0.5367869735,-0.5062915087,0.9420825839,0.3617729843,1.5440033674,0.1615864933,0.0659199730,2.2409822941,1.7344744205,0.8405517936,1.2798552513,0.2383038104,-1.1642180681,1.2421092987,-0.6393301487,-0.7457547188,1.6431002617,-1.1643340588,3.0044844151,0.3767578304,0.5810221434,-1.0409605503,-1.0302780867,1.0567331314,-0.5488164425,-1.0528279543,-1.1218669415,1.9058232307,-0.3550024033,0.3868098855,0.3766503632,2.7125041485,0.2050943375,-0.1935515255,-0.2608304918,-0.7655370235,-1.3006209135,1.7410725355,0.3444109559,0.9625317454,-1.5197042227,-2.2566416264,0.1158713400,-0.3307718933,0.0338330679,-0.2279780209,-0.6273221374,0.5892687440,0.0315760486,-2.4211452007,-0.5741143823,-2.9741172791,1.8141866922,-1.2270373106,-1.7089072466,-1.2472568750,0.2550107539,-0.2996766865,0.6542093158,1.1454129219,0.3152971268,0.0964322165,0.3907919824,-2.0905296803,-0.6558496952,-0.3131229579,-0.4145734608,-1.6045930386,-1.1430335045,-1.1225223541,0.5742155910,0.2588180602,-0.8291150331,0.3271596730,1.0199117661,0.4195581079,-1.2312644720,1.2604261637,-0.1361154765,0.9647939205,-0.8266542554,0.4887631536,1.7701907158,0.7247890234,0.4453731775,-0.8973620534,0.3199851513,0.0539685972,-0.8106490970,0.0733280629,0.0133526186,-0.6579945087,-0.3815068007,1.3540554047,-1.3347084522,0.4231979549,-0.3235702217,0.0383079089,0.2308514863,-0.9960447550,0.0932694674,0.1048167944,-0.6200649142,1.2804870605,-0.0674211308,0.6397436261,-0.1728785187,0.1322377771,0.6113134623,-1.3866189718,0.2125978023,0.0523288436,-0.3402370811,-0.2536427975,1.3289234638,-0.4033775330,0.6017901897,-0.8228362799,-0.7473247647,-1.4831603765,0.3024454117,0.1503181756,-0.6277262568,0.4740160704,-0.1196713299,1.7544775009,-0.0974104479,-0.1266327649,0.9487879872,-0.4919475019,-1.5392595530,0.6162174344,0.5011700988,0.9101887941,0.8777204752,1.2595125437,0.4018152654,-1.7166287899,-0.8698635697,0.4974375665,-0.0144640859,-1.7648240328,0.9489676356,-0.4182487428,0.4941950142,-1.1213845015,0.2394562066,-1.8312802315,-1.4354618788,0.9216833115,-0.8544840813,1.0875998735,-0.9171810150,-1.1399039030,1.3363617659,1.1059136391,0.8108481765,0.2172601074,-0.6312165856,0.6373825073,0.4367862642,-0.8210284114,-0.7013685107,-0.4239511788,0.5677524209,-0.2321190834,0.2549104989,-0.9880585670,1.1797896624,-1.8412686586,1.3705574274,-0.4650182724,2.6413793564,-0.4931051433,0.0091245165,0.2830466032,0.3595472872,-0.4690435529,-0.6955348849,-1.0818399191,-1.2531290054,-1.5354416370,0.6554519534,1.2130562067,0.1278675348,1.0614162683,0.0805788711,0.1987828314,0.7905623913,-1.1146622896,-0.7665066123,-0.4313217998,0.2837044001,0.1385461688,-0.6566702724,-0.7525277734,-0.3352095187,-0.0488350540,0.6274835467,-1.3588238955,-0.6190199256,0.0382770114,0.0188390687,-0.3117430210,0.7832928896,-0.0662060976,0.0303651243,0.4428240955,1.1008049250,0.4989125729,0.3406849802,-1.3838136196,-2.5580713749,0.1072607487,-1.7010232210,0.5015914440,0.3309070468,-0.2240238488,1.1814460754,1.0675925016,0.2472229749,-1.1753770113,-1.4115841389,0.6599791050,-0.8903461695,-0.7513751388,0.4441344738,0.0984115377,-1.6328358650,-2.7814333439,0.0352627784,-0.1952062249,2.5094332695,0.2350155562,-0.7036231756,-0.6226969957,0.1006892025,0.2735290527,0.3248717487,-0.9859005213,0.5884060860,-1.6339645386,0.6399517655,0.0949723125,-0.8603503108,0.7330551744,-0.4018296599,0.0621890053,0.9158736467,1.1411347389,0.4787520468,1.3159184456,0.6555212736,-0.1050648540,0.5479673743,0.1422740966,-0.0826835856,-1.1075340509,0.2643381357,-0.1198114604,-1.2939515114,0.4103282094,0.9645326734,-0.5595097542,-0.3438761234,0.9068605900,0.7637982965,1.2814041376,-1.3839570284,-0.5809727311,-0.3262540698,-1.5268710852,1.2061607838,0.9503488541,0.0565067790,0.5170537233,0.8136867881,0.9898092151,-0.5544456840,-0.2870925963,-1.6100064516,0.2155759931,-2.0440261364,-2.6521677971,0.6410305500,1.6874045134,-0.6198192239,0.6183931231,-0.3552034199,0.3808440566,-1.5048646927,-0.7682568431,-0.3286943138,-1.2153249979,-0.8321967125,0.6857488155,-0.7768926024,0.4683583379,1.4393649101,-2.0580306053,0.2417555600,-0.1287895143,0.9849979281,-1.2673319578,1.4937902689,0.6139543056,-0.7011052370,1.6358752251,-0.5591640472,-1.8699896336,-1.2037640810,-0.4650449753,0.4130979478,-0.4781028628,-0.3773052096,0.4896984100,0.5291000605,0.2909781933,-0.1239582077,-0.2593092024,-0.7551556230,0.0570368096,0.7843011022,-1.3545408249,0.3017587662,0.3814600408,0.1865427494,0.3018524945,1.1108403206,1.4385936260,1.2737234831,-0.1687798649,-0.2700041831,0.0939677283,-0.5982590914,0.0442983992,-1.2631759644,2.1559460163,-1.0446652174,1.4373403788,-0.5136585832,0.5201707482,-0.1930320710,1.4882138968,0.1718825847,-0.6136702895,0.1616206765,-0.1911924034,-1.3606525660,-0.6224917173,-1.8901438713,2.1093156338,-0.5344481468,0.5858753324,-0.1767421663,0.5121246576,-0.4941667914,0.4248593450,0.3161675930,-0.8331077695,-1.4626350403,-1.7189588547,-0.2488492578,-2.3246755600,0.8617739081,0.4979015291,0.7135391235,1.3816496134,1.7785661221,0.1185933501,-0.0692301467,1.3845703602,0.9387071133,0.1926213652,0.1305808425,-2.9852871895,-0.5626637936,-0.8844199181,-1.3015922308,-1.2187414169,-1.1000576019,-0.3812155724,0.7491910458,-0.7949401736,-0.1017555743,0.5167959929,-1.2674736977,-1.3182394505,0.3694709241,1.0132818222,2.0066077709,0.0588135272,-1.0413175821,0.4451495111,-1.5961176157,-0.5127106905,-0.0736058503,1.2943279743,0.9867642522,-0.3749952614,0.0219509210,-0.4264596999,0.6405826211,-0.2793408334,0.3446552455,0.2953101695,0.4174514413,-1.3424669504,-1.2077305317,-0.5029827356,-0.9704607725,-0.5791391730,-0.3410248160,1.2203289270,0.3139457703,-0.6450718641,1.9737294912,0.0937890559,-0.7589262724,-0.0004526210,-0.1392761469,-0.5184856653,-0.6445096731,-2.0933535099,3.6174440384,-1.4014939070,-0.3285408914,-0.0851450935,-0.4968545437,0.8777781129,1.2304735184,0.9676017761,0.2992458940,-1.0884692669,0.7705311775,1.2788481712,-0.4678036571,0.8469130397,0.5697970390,0.3013136983,0.7260673642,0.2109190971,0.9467196465,-1.5477573872,-0.7547515035,1.0165404081,-1.2013443708,-1.0009258986,-1.0381124020,-0.9545734525,1.0061957836,-1.3585246801,0.2498244196,-0.6100196242,-1.9319077730,-0.3646067679,-1.4917006493,0.7829834819,0.7965960503,-0.8203605413,0.7800762057,-0.1055379063,0.3846244514,-0.9033451080,0.9355486035,1.3010201454,1.5083156824,1.0601898432,-2.1822016239,0.0641560182,-0.1708367616,2.2009952068,-1.4505349398,0.6033412814,-0.3475028276,-0.0245241802,0.9902088046,0.7871859670,-0.2820515037,0.6837606430,1.7600520849,1.7086303234,-1.3337498903,0.5148547888,-0.1411535144,-0.5787584782,-0.1753298044,0.7662317753,2.2890543938,-0.3373456299,-0.7940471768,0.0870957598,0.2046343088,-0.3655799031,0.1403742582,0.7487806678,-0.0493908785,-1.0613024235,1.6651679277,-0.0721103400,-0.9661730528,-0.0118546663,-1.2443343401,-1.8370332718,-1.1943985224,-1.3811161518,0.0265875105,0.7113240957,0.4174372852,0.7321901321,0.3165853620,-0.8200309277,0.9104493260,-2.0742957592,-0.8789162636,-0.6044740081,1.7389211655,0.3027465940,0.8017164469,-0.1329290718,1.1411834955,-1.2318832874,-0.2818616629,0.3668227494,-0.1943957955,0.1467296183,-0.9400892258,0.6216479540,-0.3850940168,-0.2756251991,-0.0756106824,0.6708564162,1.7877844572,0.2348715514,-1.1913688183,0.1658644378,0.3144343793,-1.8043081760,0.8749025464,1.1378152370,-2.5943167210,-1.2024546862,1.2210763693,1.1203122139,0.1245990917,-0.9790798426,-1.1268764734,-0.4267218709,-1.6712464094,-0.2931473255,0.9772987962,-1.3596971035,0.0209441744,0.3558107018,1.1550899744,-0.5986868143,0.3185078800,0.6811698675,-0.3164308965,-0.1549912542,0.0994456187,-0.1038790345,-1.7121478319,0.2452230304,-1.0489326715,-0.2093195915,-0.4916971028,0.8829078674,-0.1305598617,0.0435559079,-1.4980833530,-1.2615302801,0.0852286965,0.5818434954,-0.8840133548,-0.4041324556,-1.0049831867,-0.5677416921,-1.8189404011,0.6888154745,0.4762073457,-1.6676757336,-0.0117815798,0.9636470675,0.2832666636,-0.3563674390,0.9574931264,1.1856490374,0.1930582970,1.1372985840,1.4829488993,0.4178263247,-1.0189751387,1.3939164877,-1.5043624640,-0.2485114038,-0.4893157482,-1.0204097033,1.2906845808,1.1540821791,-0.4610202312,-0.4744220972,-0.0785018057,0.5601623058,0.2905760109,1.2008045912,-0.9055359364,-1.2546924353,-1.3627620935,-0.4191326201,-0.2417927384,-1.6857676506,-0.6772042513,-0.7309972644,1.0813498497,-2.3207206726,0.3441968262,-0.6235502958,1.6584020853,-1.7576291561,-0.8164684176,2.6233417988,-1.4983351231,0.0849152654,-0.2290281355,-0.6555573940,-0.1725483537,-0.3922250867,1.2119016647,-1.9553462267,-0.6105675101,1.1522092819,0.6248836517,0.0559881888,0.4049755335,0.0688843802,-1.0096157789,0.3500415385,-1.3688995838,-1.1148210764,-0.2586264610,0.0292662345,0.2617202699,-1.1088030338,-0.2185048759,0.1528363377,-0.1823088825,-0.7560430765,-0.8633227348,1.8211431503,1.2482187748,-1.0431731939,-0.1619359106,-0.2505675554,-1.1278392076,1.4434571266,0.1162277162,0.8356947899,0.2004559189,2.7481603622,-0.6122629046,-0.1336817294,0.9449667335,-0.2098537385,-1.0220044851,0.1911619157,-0.6354675889,-2.6473999023,-0.4538244307,-1.0034236908,-0.4797924757,0.3036291897,-0.7502538562,0.3391863406,-0.3267144859,-1.5663520098,1.5844787359,-0.1541496515,0.0080233496,-0.2457676530,0.5802427530,-0.2375820726,0.4829804897,-3.2749388218,0.6998037100,-0.8014594913,-0.9856346250,-1.3622802496,0.9920208454,-0.8667515516,-1.1467056274,0.8337497115,1.4432774782,-0.4017332196,-0.1752787232,-0.1312951446,0.5203475952,1.6061456203,-0.3765571713,1.2273452282,1.0681328773,0.5741702914,1.6537784338,-0.1392436624,1.5222073793,-0.4666440189,0.8264855742,0.2139969468,-0.7227970362,0.1318987459,0.6431787014,0.0269627497,2.9194891453,-1.3445217609,-1.3357516527,-0.3646216989,-0.3339246511,-0.9061585069,-1.7167688608,-0.2931183875,-1.2002370358,0.0027208761,-0.8410323262,-0.8513520360,-0.8169867396,1.7177858353,-1.0786051750,-0.9716501236,0.7862368226,0.4703477919,1.5872616768,-0.6943163872,0.5795159340,-0.4428988099,-0.0336347744,-0.0675015002,-1.1188058853,-0.0059059928,0.3079329729,-1.5865097046,1.1954914331,0.0107388850,0.2328452766,0.3771139979,0.1556452364,0.5254788399,0.7656033635,1.8018838167,1.3587571383,-0.1060156971,0.5899567604,1.1444541216,-0.3648647964,0.3766710162,0.0900015309,-1.0156743526,1.4167870283,-1.1703493595,-0.6448116302,-0.1051116288,0.0020963072,-0.0745361373,0.8696280718,2.8341960907,-0.3513678610,1.3280119896,0.1946055442,-0.5135858655,-0.5002872944,-0.3048385382,1.4506249428,0.0044972659,-0.0088738408,0.6910936832,0.6415634751,-0.6344572902,0.2697565854,-1.0585714579,-0.5347191095,0.4512789249,-0.7875731587,-0.1061345711,-0.3123532832,-0.6738702059,0.7054605484,1.8631844521,0.6854217649,-2.4223566055,-0.3866092861,0.4214096665,-0.6705033183,0.6293103099,-0.9606555700,0.4024822712,0.9286620617,-0.2251343727,0.0375308469,-0.6891617179,-0.4474659264,-0.4347704947,-0.2488876730,-0.6395900249,-0.6902248263,-0.8352594972,-1.1157217026,1.1579307318,-1.0021015406,-0.9917744398,-0.5251912475,0.3097694218,0.9646864533,0.4288187623,-1.4920967817,-0.5031630397,2.0002958775,-0.8010430932,-0.1773892045,0.7078548670,0.7890493274,-0.7094715238,0.0394469835,1.5130943060,1.0473628044,0.7980496287,-0.2446120083,-0.8357499242,0.3035597503,-0.0023617276,1.8378235102,1.0127995014,1.0019253492,-2.0041329861,0.5986630321,-0.8298110962,-0.4977650940,-0.7103406191,1.1140469313,-1.0463049412,-1.1186000109,-0.6619963646,0.4847993851,1.1088175774,0.1798587739,0.6712608337,1.7970820665,-0.7250568271,0.5614169836,-0.3647833765,0.2266235948,0.4138481319,-1.9311686754,-0.9302152395,1.2558653355,-0.9853758812,0.7505119443,0.8275774121,-1.0908306837,1.4267879725,2.1317381859,-0.0587358475,-0.6239714026,0.5322213769,1.2944272757,-0.5415900350,0.3425603509,-0.0551128164,1.2260411978,-0.3073526919,-0.0158004314,0.0446104370,-0.2874431610,-1.3118320704,0.3087975979,0.4541290104,-1.3672093153,1.0977481604,-1.3857321739,-0.3321656585,-0.7112305164,1.7794216871,0.7596542239,0.9350003004,-0.6077075601,0.3117588460,-1.4983228445,1.2511718273,0.2724351883,-0.1407505125,-0.5702785254,1.9123885632,-0.0837195367,2.3620803356,0.5817832947,-0.6662903428,-1.4938615561,2.1392271519,-0.7084274292,0.3544390500,-0.1004240811,-0.7890850902,-0.6086986065,0.4826420844,0.5797073841,-0.9093092084,0.5444802046,-2.0700707436,-0.4536957741,-1.0652302504,-0.5660454035,-0.6453261375,0.5172896981,-2.2897562981,-0.8132987022,0.9573528171,0.1642129719,-1.1041778326,-0.2960029244,0.8012885451,-0.6051740646,0.2041897923,-0.2072525769,1.1589853764,-0.4625106752,-0.4647492766,-0.1737691313,1.1656908989,2.6465435028,0.7356799245,-0.6035447121,0.7761955261,0.1258596480,1.3203146458,0.0428092740,-0.5732164979,0.5334172249,-0.4383377433,-2.6443896294,-0.4882341325,-0.4131014943,-0.6506836414,-0.0589487515,-1.1589503288,0.0197763573,-0.4185853302,0.7655056715,-0.3029468656,0.7333875895,0.5726686716,-0.2836067080,0.0208763424,-1.9726077318,1.9458686113,0.8031986356,-0.5565538406,0.3064076304,-1.3078083992,1.3880399466,-2.4986119270,0.2955805659,0.4166693389,0.3991940618,-0.3132807612,1.9816641808,1.2151714563,1.7478718758,0.2781778276,-1.2538698912,0.3590858877,-1.6911876202,-0.3242392540,0.0751941875,2.0730650425,0.8241178393,1.5471822023,0.4346613884,-0.2523943782,-1.6861196756,0.3959576786,-0.3940330148,2.2799172401,-2.1057817936,-0.6796046495,-0.2385020703,-1.6790004969,0.6090376377,-0.2106702179,-0.5197761059,0.8246834278,-0.6630619764,-0.6153048873,0.3878263831,-1.6378360987,0.2738104463,-0.6956075430,-0.6798497438,-0.0288074967,-1.8039088249,-1.1410199404,2.5300855637,-1.3932182789,1.1908702850,-1.0227982998,-0.9062312245,0.8252307773,1.0381580591,-0.2450716347,-1.2224311829,-0.5532920361,0.0643740818,0.4217404425,0.9086120129,1.4833407402,1.8077830076,0.1879525930,-0.2831076384,0.8077802658,-0.0759647638,0.7265745401,1.4762508869,0.3692570925,-0.8803898692,0.5382549167,-0.4830761254,1.4964990616,-0.4836547375,0.4294926524,1.5498590469,-1.8430325985,-2.7364418507,1.1671922207,-0.4623150527,-0.0125561962,1.8133157492,0.4415445030,1.3514368534,-0.6283529401,0.9533058405,-0.9504081607,-1.3233529329,0.0559342392,-0.3043320477,-0.6132194996,0.2827467918,0.0211385582,0.6981754899,-0.3219046593,-1.1821082830,-1.6019649506,-0.7358622551,-1.5021909475,1.3134816885,1.0149642229,-1.4239060879,-0.4501751363,1.4480149746,-1.8850461245,-1.0855251551,-0.0552835427,1.1126552820,-0.3457433283,0.3627731502,-1.2939021587,0.0297653861,-1.0057828426,1.3407930136,-0.0574732423,-0.0764587745,2.4194180965,-1.4760574102,-0.5405495167,1.3480896950,-0.9823193550,1.7727591991,-0.7762312889,-1.1459913254,-0.9690763950,0.3205409050,0.2968346179,-0.0867063925,1.4222966433,0.0621957928,1.0828131437,0.5762202144,1.8638826609,0.0221075136,-0.4786196649,-0.5847828388,-0.0353326574,1.8716874123,0.3440319300,1.1833447218,-0.8264019489,-0.4332354665,-1.6377058029,-0.2957936227,0.4296649694,0.0330034830,1.4408249855,-0.9070200324,-0.2233535200,-0.5568699241,-0.0201630127,2.8606996536,0.1218447164,-1.1993663311,-0.1101554483,-0.0428591706,0.5230171084,0.9578502774,0.3164121807,1.4629195929,0.7499135137,-0.6314778328,-0.8180010915,0.9594846964,-0.0734098107,0.3534791470,0.2100719959,-1.3744202852,0.9371819496,1.8197331429,0.0385162905,-1.4419538975,0.4320627749,-1.0061644316,0.3089143634,-0.1311210543,-0.8641072512,-0.7125442624,0.9392834306,-0.6008676887,2.2745432854,-0.0422098339,1.4438676834,0.7602827549,1.7542577982,0.3981570899,1.5356993675,0.2983169258,2.0158410072,-1.3415718079,1.8989692926,1.7546209097,1.2540712357,-1.6169677973,-0.8762540221,0.9787555337,-0.6943745017,-0.0487157442,-1.8384969234,-0.0759068280,0.4606977403,0.4347637594,-0.4993920028,0.2148143649,-2.0123169422,1.6227184534,-0.2299919575,1.4253363609,-0.3838140070,0.2162957191,1.7839958668,-0.6574246287,0.2178135365,0.4388503432,0.5152842999,2.0197911263,0.3589576781,-0.1519799829,-1.3294918537,0.3256805837,-0.3265584409,-1.4352842569,-1.0348974466,0.6977605224,-1.4681086540,-1.1425429583,0.6803500652,0.4048239589,-1.0909260511,1.1290786266,0.8217989802,-0.9025979042,1.1533937454,1.0704193115,-0.4884494543,1.4770652056,0.0373433903,0.0077836541,0.6826797724,-0.8579919338,0.2251290381,-0.9385836124,0.7698971629,-0.1225737706,0.1218759790,-0.3805133700,0.0967485979,-1.8844478130,2.3024020195,-0.6849756837,-0.3304445446,-1.2974334955,-0.6761263609,-1.4177010059,-1.3832147121,-1.3262499571,-0.3938881457,-0.6269910932,0.2355906516,0.5818787813,-0.0156290065,-0.4996424615,1.8249180317,-0.2702373266,-0.0378957987,-1.3491808176,0.8316279650,-1.3577632904,-0.7994315624,-0.3274593353,-0.8930548429,0.6743643284,0.5958985686,0.0216204133,1.6101511717,-0.9585517049,-0.3917265534,-1.8435053825,-2.2900974751,-0.6511493921,2.3449501991,0.1335494220,-0.1154850870,-0.0498552248,-0.5847663879,-0.7291586995,0.2750283182,0.7288957238,-0.2256766409,0.7525697351,0.9032928348,1.1697378159,0.3740186095,-0.6911426783,0.3261582851,-0.2271312475,0.4647946060,0.0876392424,-1.1337498426,0.8469501138,0.7095554471,1.2220104933,1.0301719904,-0.7379205823,0.9471271634,0.3801421523,1.1546025276,0.5475896597,0.0115259765,1.3954277039,-0.7114993334,0.9818466902,0.1740345955,-1.6722321510,-0.5188888907,-1.2580188513,-0.0774400756,0.3143561482,-0.5942593813,0.4429920316,0.6551231146,1.8638199568,-0.8231512308,0.9583299756,-2.8441357613,-0.4623622894,-1.1016976833,-0.3292089701,-0.3490474820,0.7918364406,0.1010522470,-0.5955529213,0.8099021912,-0.6571288109,-0.5177548528,0.7080375552,0.4156391323,0.6487434506,1.0146337748,-1.5045164824,-0.4959926903,0.1978851706,1.0364204645,0.0211838745,1.3547075987,1.0349222422,0.2016938329,-0.7771456838,0.3141413033,0.4111408889,-1.7946816683,-0.8617743254,0.4630215764,-1.4796572924,0.2156282216,0.0648754835,-1.1287294626,0.8153375983,0.8462402225,-0.9069088697,-0.2586428821,1.5503832102,1.2572857141,-0.8906383514,-0.1220265105,-0.3822940588,-0.1107923314,0.3378605247,-0.4759807289,0.8223170638,0.5999978185,-0.5032872558,0.7468966246,-0.5116183758,-0.6416741610,-2.3637897968,0.5536193252,1.0693031549,-0.1984776855,0.5212368965,-0.1010358110,0.1642877162,2.5420272350,-0.8539747000,0.0189713798,1.4053024054,-1.0632971525,-0.9598603249,1.3750352859,-0.4135048091,1.8846297264,1.1503682137,1.0024423599,-0.0212843530,-0.7975702882,-1.5567365885,0.1432193369,-1.2462441921,0.1648118943,-1.9669402838,-0.0362720527,1.8989335299,-0.7362707853,-0.0263065547,-1.3074949980,-1.6733379364,0.4589193165,-1.5560327768,-0.2851602435,-1.1524580717,-0.7894440293,0.2129414976,-0.0265334882,-0.9173115492,-0.1233007684,-2.1116597652,-0.2548934221,-0.1000629812,-0.2341962755,-0.5075214505,-1.0097604990,1.6759552956,-1.1805329323,0.3522910178,1.1721547842,-0.8795605898,-0.2225883007,0.3419721127,-0.5531402230,0.5414720178,1.1503173113,0.8090146184,-1.1797549725,-0.4781074524,-0.4606604576,-0.6850347519,-1.0958294868,-0.8130276799,-0.4801674187,-0.5496889949,0.1198312268,0.9770823121,1.0006096363,1.5605578423,-0.2776606977,1.5436390638,1.3431284428,-1.0694115162,0.0319580436,1.0235497952,-1.6327320337,0.2094062716,-0.2779122591,-0.2549938858,0.9235299230,-1.7200658321,1.3078080416,0.3141606450,-0.9713298678,0.6507166624,0.5240988731,-0.8743537068,0.2245029956,-1.6577179432,-0.8995621800,-0.5963401794,-0.3028064370,0.6373192072,1.0106426477,-1.1714172363,-1.1551836729,-0.1290144324,-0.4418173432,-0.5398723483,0.7920086384,-0.1006233692,-1.2925938368,0.4630675614,0.5318786502,1.0925804377,-1.8792281151,1.2360200882,-1.0882061720,0.2990363836,2.0535075665,-1.3437252045,1.7961989641,1.0472359657,-0.6580789089,0.3637872040,0.8887823224,-1.0567698479,-1.4380348921,0.3630021513,1.0801453590,0.0848029777,0.3457524478,-0.5923113227,-1.1642155647,-0.6858039498,0.2838497758,0.1613612771,0.3430170417,-0.0750150234,-2.2998411655,0.1167422906,-2.1216418743,-0.7399117947,1.0929222107,-0.8083111644,-0.4524880946,-0.5343817472,-0.2154788822,0.5326138139,-0.4642713368,0.3502049446,0.2950757146,-0.3348174989,0.6952251792,-0.7663141489,-0.1191459745,1.8016871214,1.1503630877,0.0879920721,1.6557919979,-0.9713310003,-0.0952440724,0.0566643141,-0.4121611416,0.3589834869,-1.2417886257,-0.3981787860,-0.0955326259,-1.1746367216,-0.0903539136,1.8228377104,0.1594277769,1.3675057888,-0.8630368114,1.4712395668,0.1054009870,-0.2368630320,2.3829298019,-1.6929466724,-0.7913834453,-1.4271126986,0.2466607392,0.1234057769,-0.3978918791,2.7214033604,-0.6303295493,0.0198053010,-1.1812092066,-0.1202231199,0.3901976645,-1.0169278383,-0.3118689060,-1.2093325853,1.5801656246,-0.1262614280,-0.2772842050,1.7430753708,0.7829131484,-0.9974278808,0.5059066415,0.2753480971,-0.8170706630,1.4233903885,1.3587424755,0.3708223104,0.2664794624,0.0544346385,1.0021533966,-1.4790313244,0.5714965463,0.5185027122,1.2404508591,-0.3423627019,1.0433201790,-0.5620381236,-0.7999502420,0.3974117339,1.3396379948,0.5925657749,0.5062606335,-0.9846734405,-1.2468835115,0.1999926269,-0.7213277817,0.5002495050,-0.7886040211,1.4698174000,0.5244092941,0.2752928734,0.4098138809,1.4521061182,-0.7069355249,1.2058763504,1.6311770678,0.2563337386,0.5263522267,0.1898272932,0.8347653151,1.3658587933,1.1031242609,-0.0868932381,-1.0478790998,-0.6240808964,-1.3151839972,-0.6831984520,0.8852385879,1.6934367418,-0.3677411377,-1.4583725929,-0.6255928874,0.8111643195,2.1374673843,0.7400379777,0.1656147391,1.7086645365,-0.0734900981,0.8953284621,-0.6813739538,-0.0614439286,-1.2261948586,2.0596497059,-1.5261852741,0.6271134019,-0.3758432567,-0.9482771754,0.0166640133,-1.3925417662,-0.6260951161,-0.0622643456,-0.3813502789,0.5994868875,1.6862668991,0.5603588223,-0.0449138060,-0.1375849396,-1.6965512037,0.3292586803,0.3680608571,1.5089581013,-1.2935491800,-1.4540292025,2.0181722641,0.1847225428,-1.5040644407,0.8418682218,0.3571032286,0.1277844757,0.6452940702,0.8302066922,0.3316073716,-0.4937435985,0.1727012694,0.3508908153,0.4942966700,-0.1890991032,0.1464315653,1.2672983408,-0.5420016050,0.3489682674,-0.1656922847,1.8272436857,-0.0872897953,0.6986168027,-1.1467864513,-3.0869462490,-0.6514915228,1.3085490465,-0.1464149803,0.5489206314,0.3809079528,0.1223399192,-0.2563851178,-0.3303251863,-0.8524194956,-1.0438624620,0.9942628741,-0.7164640427,0.2523762882,1.8409081697,-0.0395202041,-1.9294208288,-0.4429220259,-0.2262780219,-0.6784824133,-0.4743759632,0.1318203062,0.1481006593,-0.0424164087,-0.5459465981,-0.7982281446,-0.4270841181,0.8304693103,-0.3444064856,0.0296886452,-0.0255151410,0.2025533468,0.6004497409,-0.5635874867,-1.3864352703,-0.5710804462,1.3912957907,0.1319333613,1.6396538019,-0.8336297870,-0.6034071445,-1.9802199602,-0.0118512791,-0.1108769551,-0.0129075134,-0.2374236435,-1.5954982042,-1.3275305033,-0.4772657752,-0.2762099206,0.8561545610,-1.0112084150,-0.6464535594,1.1537920237,0.2840941846,0.1511519849,-0.1263342947,-0.3606207073,-0.9840847850,1.4167820215,0.6281455755,0.8761416674,0.0240065102,0.0428546667,0.7045249343,1.3199563026,-0.2455899715,-0.4333233237,0.0839606822,-0.5357459188,-0.5189141631,0.0773424804,-2.4033913612,0.5579027534,0.2220277339,-0.1305405945,1.1741777658,0.1842390150,-0.1543905437,0.2372447699,-0.0578634739,1.1268147230,-0.6168632507,-0.6207220554,-0.3247307837,-0.6050617099,2.4619061947,-0.5523837209,1.7028896809,0.0241982024,-0.3090949655,-0.1183786169,0.6874657273,0.5977433920,-0.3424105048,1.0477715731,0.0600404032,-0.4835692644,0.2377821803,-1.9360288382,-1.1095243692,-0.2601641417,0.7298178673,-0.9078957438,-0.7949860692,0.5281986594,-0.0193301439,-1.4828484058,0.4641183615,-0.6966081858,0.6504861116,-0.7225518227,-0.0420571826,-2.2333300114,-0.6292539835,0.3642581701,2.1744987965,-1.4005479813,0.6594906449,0.0190161932,0.7265573144,0.4081478715,-2.0283536911,-0.2277533710,0.2533299625,-0.2692781985,0.8519235253,-0.9961074591,-1.3291726112,1.1561888456,-0.1695564687,-0.6412171721,-0.5963202119,-1.2543619871,0.3706256449,0.2367728949,-0.8329231739,0.1212827340,-0.1572631747,0.4193502367,-0.5477141738,0.4441763759,-0.1068404242,0.6890825033,1.2757037878,-1.3237390518,-0.7205080986,-0.2300838381,1.9304093122,-0.8222891092,2.3237411976,-1.5258569717,-0.2129818201,1.1545015574,0.1849959046,-0.4873098731,0.5797542930,0.4350897372,-0.4880842566,1.4818840027,0.7041978240,-0.0506795347,0.4129129052,1.2196661234,-1.2100301981,-0.6907811761,0.2639520168,0.6720523834,-0.1672959328,-1.3558725119,1.5750267506,0.5315433145,-1.3783342838,-0.5600621104,0.1594666988,-0.1252618730,0.1798083037,-0.3277032673,-0.8285724521,-2.2868967056,-1.3793725967,-0.7088655233,-2.1242513657,1.8299680948,-0.0487202220,-1.1619849205,-0.7737154961,1.1845551729,0.0657233149,0.5641449094,1.8346886635,-1.1153488159,-0.8920660019,0.1958157718,0.3952474594,-0.2617920339,-1.6110399961,-1.3485546112,-1.3979731798,-0.6749272346,-0.2331542522,-1.0221537352,-1.5719534159,0.0787544250,1.4476664066,1.0816694498,0.5359908342,0.5086901784,1.3539590836,2.1905260086,-1.3281347752,-1.5861293077,1.0052930117,0.2073535621,-0.2195786089,-0.6525210738,0.1171994656,0.2404762059,1.7054648399,-0.0166308656,-0.9980779886,-0.3845568895,0.2131299078,0.8598623276,-0.2320811450,1.2193504572,-0.7898730636,0.5503804684,-0.6646599174,-0.4484573305,-1.3752053976,-0.0077703991,0.4516531229,0.5158145428,1.5019677877,2.3400790691,-0.1689572185,-0.7131705284,0.0862102732,-1.8778115511,-0.5737338662,0.3488899767,0.0695413202,1.4736529589,0.1018898711,-0.3780619502,-0.3608337045,-0.3679491580,-0.5431326032,-1.0214086771,-0.1403140426,0.3082767725,0.1509161294,0.6119741201,0.7313207984,0.8829240799,1.8567088842,0.5742434263,0.4984557033,-0.4186875820,-0.9313029051,-1.6411021948,-0.5562921762,-1.4994580746,-1.5915665627,-0.0610120445,1.5467461348,-0.7506592274,-0.4631983638,-0.1926139444,1.7024631500,1.6659804583,0.5192429423,-0.5472186208,0.0565663762,0.2284213901,1.5348349810,0.2286630720,0.0394604020,-0.8655991554,0.8045617938,1.2748690844,0.5713320971,-0.1608036757,0.7733766437,2.1223337650,-0.9744271040,0.7814424634,-0.5671689510,0.4748123884,0.9607690573,-1.0613287687,1.2581557035,-0.7631398439,-1.7736225128,0.0356541537,-0.6820560694,-0.7282853127,-0.1053154469,-0.9815471172,0.4679682255,0.1102410853,1.7661479712,0.9696770906,-0.6157441139,0.0832946599,0.0154042337,1.4200258255,0.1912794560,0.8820790052,-0.7564318180,-0.9813390970,2.7474064827,-0.4309709370,-0.5363450050,-0.1029144824,0.4400387704,-1.0086545944,0.8715492487,-0.4610286951,1.2774317265,-0.3406333029,1.0627976656,-0.0177198425,-1.4871954918,-0.3110130727,-0.1273606718,-0.5646942258,0.3632155955,1.1745493412,-0.5503141880,-1.6987376213,0.5262299180,-0.5710070729,-1.2713433504,0.8851079941,-0.6829869151,-1.9171721935,0.7940423489,0.5627143979,-0.9600135088,-0.2346548587,-2.2996087074,0.8724299669,0.0616741218,0.4606336057,-1.6986548901,-0.1236542985,-0.8901436925,1.6886969805,-0.6276292801,-0.7237911224,0.5590992570,-2.4663658142,-1.0565769672,-0.4022848010,1.6344102621,-0.4803332984,-0.4069189131,1.0568474531,-1.2874617577,1.5985314846,0.8697004318,1.5187076330,0.3975264132,-1.4097440243,-0.0381349325,-1.1354163885,-0.4750063717,-0.2226876616,0.7452670336,0.2666867077,0.1722257733,0.4386547804,-0.4073028862,-1.2752696276,-0.3434637189,-0.2251634151,-0.8087444901,-0.7511361837,0.2216085494,-0.5121274590,-1.8204050064,0.7472478747,0.5685710907,0.1281473041,-0.8394502401,-2.5131106377,-0.9077122808,-0.6943283677,-0.5469990373,0.7462623715,-0.3083970845,-0.8384279609,0.8198192716,0.4979269207,0.0270626321,-0.1213922799,0.7247827053,0.3348164260,-0.2508352697,0.7643464804,-0.4294463694,-0.1170479879,0.0250977706,0.7436251640,-1.5160830021,-1.5851063728,-1.5032289028,-0.4924083948,0.6285675168,-1.1842933893,1.1135993004,1.2736849785,-0.0435120836,-1.3845635653,1.7388744354,1.7109934092,0.6870909929,-2.3529503345,0.5297210217,0.0182195548,-0.8128156066,-0.1349581033,0.5240533352,-1.1022468805,-1.2241221666,-0.2381365448,-1.0415886641,-0.1002316251,-0.4005219340,-0.2848261595,0.0950556099,1.7183667421,1.2604315281,1.8246142864,-0.2740058899,1.5894554853,0.2125496417,-0.8694303632,0.3586742282,-0.6369240880,-0.3130733967,0.1877637058,-1.3034642935,-0.5413097143,-0.9775701761,0.3182064295,-1.2245349884,1.3321487904,-0.1348018348,-0.0079483762,0.5871071815,1.6216561794,-2.3066439629,-0.3211205304,0.0831940025,-1.0155971050,0.3312295079,1.2365626097,0.4100286365,0.4295566678,-0.4415833354,1.0282262564,0.7797985673,-2.6591732502,-1.3471249342,0.7747009993,0.7138849497,-0.1456113309,0.9523909688,1.2731977701,-0.9705725312,0.6225118637,-0.6567438841,0.1674103588,-0.1905986071,-0.5853870511,0.9797718525,-0.5967161059,0.4017387033,-1.3391740322,-0.7596985698,0.9018880129,1.2323490381,0.6116399169,-1.2004809380,0.7040430307,1.9253069162,-0.1669967473,-0.4774456620,-0.1453061104,2.7242598534,1.0761202574,-0.7772324085,-1.8398270607,1.1820985079,2.2291193008,0.1210172623,0.5169967413,-2.0369746685,1.3334836960,0.9594944715,1.3979049921,0.0152120637,0.3863286078,0.0464983992,-0.8423812985,-0.4377827644,0.6164746284,-0.6307107210,-0.4342782497,0.2298891991,-2.0079159737,-1.4043928385,0.1458393335,-0.6708733439,-1.6447790861,0.0703957826,-0.2523188591,0.3924876451,1.0161181688,2.0849382877,0.8516621590,0.9680776596,0.1318573952,-0.7458209395,0.1732912064,-0.0171494074,1.5169693232,0.3570988774,0.9281348586,-1.3707672358,-0.0427510217,0.5875717402,0.0559275597,1.6824957132,0.8721467257,-0.8102717400,-1.0185278654,-0.8793839812,1.4426631927,1.5465738773,-0.8688929677,-0.1653910875,0.3350679874,0.9537213445,-0.9668954015,1.6751704216,-0.6430878043,0.3188067973,-0.3906269073,-1.2710647583,0.3388320804,-1.1807581186,0.9608909488,-2.0899810791,0.7109305263,-0.9204555750,-0.9144626856,-0.6868638396,-0.1635092348,-1.7601587772,0.1764658093,0.1667043418,-1.5872178078,-0.0366247445,1.0080679655,0.4422006309,-2.4767754078,-0.9045382738,-0.7697851062,-0.1585956812,-0.2367852628,1.1754802465,-1.1316013336,1.7630548477,0.2800961733,-0.6288664937,-1.2302342653,0.3262609243,0.2660154700,-0.0530349985,-0.4598177373,1.6693603992,-0.1160294041,0.4715109169,0.9127645493,1.6281094551,0.9660769105,1.7898586988,1.6077495813,-0.9647401571,1.1253098249,-1.2583026886,0.8288027048,-0.2743187547,-0.4070868790,1.4383150339,-0.7290006876,0.1344997436,-0.1674019545,-0.3628393710,-0.4540843666,0.6296550632,-1.8585166931,-0.1117752790,-0.1778820157,2.4086344242,0.1753031015,-0.4950847924,-2.2426016331,-1.4452265501,-0.2448479533,-0.1808102429,-0.2288896441,2.1536924839,-1.3813554049,0.2147695422,-0.0196479950,0.0244122334,-0.8968064189,-0.6828643680,-0.1684126258,-1.0011633635,-0.7751793861,-1.1394294500,-0.8886438608,-1.8494819403,0.1862669736,0.3815818429,-1.2124689817,0.4131552875,1.2002992630,1.5946217775,-0.5457906127,0.4128240943,0.2786887288,0.2461876273,-1.3450722694,-1.1776552200,-1.2061234713,0.2029906958,-1.4223995209,0.5777701735,1.6634222269,-0.2870059907,0.2412759215,0.3775524497,-0.9314845204,0.6768042445,-0.4252702296,-0.7470455766,0.2802719474,-0.5464428067,0.6813836694,0.7286756039,-0.5409637690,-0.7058429718,-0.1084262133,2.0533525944,1.2147784233,0.1359319836,1.0503759384,1.0613586903,-0.2144398689,0.1920922250,-1.0345438719,-0.5036805868,1.6150988340,1.6786446571,-0.4663047791,1.0681966543,-1.3721605539,0.1843423843,-0.5531916618,-0.8321005702,-1.0742633343,0.3251988888,-0.7832528353,0.7555800676,-0.1313978136,-0.0314237624,0.5373218656,-0.7306606770,0.6202054024,1.9043105841,-0.4875988960,0.2367156595,-0.4076660872,1.0004101992,0.3512436152,1.2557044029,-0.5128421783,-0.4611277282,0.1007170677,0.0925083235,-2.1999547482,0.1508994251,0.6993888617,0.7741886973,-1.5526758432,0.7084724307,0.1943209916,-0.4375484288,0.7226394415,0.1368113905,0.0707129464,-0.0306051858,-0.0026378226,-0.1765782833,-0.5268459916,1.9544335604,0.2153434902,-0.5700322390,3.2406566143,-0.1734665334,0.2326574624,0.2949871421,-0.8500581980,0.4187697768,-1.0791419744,0.8719388843,-1.4023494720,0.4674481452,0.4940485954,-0.4561758637,-0.2247166485,0.7698090076,1.1066019535,0.9135959744,1.8430663347,0.3033389449,-1.0240417719,-0.5697768927,-0.5450455546,-0.7129164934,-2.1384212971,-0.4906723499,1.0716369152,1.0448619127,1.1970314980,0.0851596743,-0.7071413994,0.4134632349,0.5083128214,0.4324565530,0.4515452981,-0.4726723731,-0.4617720246,-0.0498823039,0.1511984169,-0.1242134199,1.7733763456,0.6548894644,-0.9969044924,-1.0999536514,-0.4729947448,-0.8252610564,-0.3246595860,-0.2494323254,0.8223640919,0.5732952356,1.1071861982,-0.9319651723,0.3545930386,1.3546044827,0.3564473987,0.8952826262,-0.0207289252,-1.9850325584,1.6648896933,1.0103242397,-0.8624767661,-0.5156413913,-0.5986755490,-0.5133580565,2.7740614414,-0.0843275264,0.5370041132,0.0354410969,-0.4008655846,1.6665250063,0.0965174660,-0.5183625817,-0.9195118546,0.3387037218,1.1137673855,-1.5738148689,1.6057540178,1.3714587688,-2.3321993351,0.3463236392,0.7981258631,1.7536504269,0.0942437500,-0.3396389484,-1.2540856600,0.7180249095,-1.1979964972,0.5125359297,-0.8158826828,0.1937242448,0.5850766301,-0.2552036047,-1.0627428293,-0.0171058923,-0.3047343791,-0.5120671988,0.6329017282,-1.2476128340,0.6401041746,-0.8136311769,-0.0626717582,-1.4570958614,0.2782136798,-0.8262432218,-0.5279885530,-0.2686576247,0.0438584201,0.6822136641,-1.4326016903,0.5378295779,-0.7443700433,2.0603389740,-1.1167420149,0.3034130335,-1.0690333843,-1.0751850605,0.0629330426,-1.8225570917,-1.5243411064,1.2396709919,1.9703440666,-0.4888984561,0.4765799642,-0.3094685376,-0.9791085124,-0.1147989929,-1.6355508566,0.4577118158,0.2286115885,-0.1039451063,0.7752788663,-0.3030622900,-0.0726639628,0.2677658200,-1.6213132143,-0.4331697822,0.1601847857,-0.7287859917,0.3674771488,-0.1830540895,-0.8931375146,0.4875233173,0.9322209358,-0.1905431449,3.1566889286,0.3486742377,1.0539091825,0.4353290200,0.6332775354,-0.7265618443,-0.7866077423,2.5195691586,-0.0017073880,-0.6077119708,1.2275959253,0.7180952430,-1.3357245922,-1.0510390997,-0.7974286675,-0.4727028608,1.5297054052,-0.4044028521,-0.7877702117,1.6482814550,0.8431814909,0.2029867172,-0.6682254076,1.6193115711,-0.5954051614,-0.3906408250,1.9035891294,0.6554541588,-2.8776378632,0.2603771389,0.7601162195,0.5754011869,0.7990735173,1.1752868891,0.4685513079,0.9743111730,-0.2307738513,-0.0264357254,0.4110282660,-0.3004532456,0.2818160057,-0.5710403919,1.0028342009,0.5024909973,0.4595133066,1.4817398787,0.2799629867,0.5637354851,-0.6241150498,0.8133111000,-0.0602380522,1.1828916073,-0.1272625327,-0.8460607529,0.3959697485,1.4310905933,-1.0955809355,-0.2613841593,-0.1580035388,0.3657860160,1.2321866751,-0.6503368020,0.0420608893,-0.8093909621,0.5546837449,0.2265381217,0.3556352556,0.7656990290,-0.3249478340,-0.1872305423,-0.8028757572,1.8795111179,1.1952743530,0.8303111196,-0.1781547517,0.5080417991,-0.1168814152,1.1812840700,1.0313570499,-1.7196556330,0.2446504086,0.1371421814,0.0973915532,-0.4585001469,-0.8280373812,-0.4593352675,-0.6757261753,-0.0793135092,-0.4180409610,1.2445529699,0.2011100203,0.9248659015,-0.4210970700,-0.8320764899,-0.1646859646,-2.5782234669,1.1942738295,1.5204107761,1.2211294174,0.7107045054,-0.1187882051,-0.8583485484,-1.0267019272,0.5830163360,-0.1584341824,0.6857743859,-1.6815145016,0.2011470497,0.1775249690,0.4979387820,0.8372054100,0.5836708546,-0.1584636122,0.2616901696,0.5922822356,1.0962525606,-0.2246936560,0.3583438396,0.5079059005,2.4989459515,0.7612602115,-0.6034088135,-0.6274229288,-0.0049325931,0.4828433096,-0.1417066455,0.5503855348,0.9566833377,-0.4469841719,-1.8436908722,0.0132681746,0.6910766363,-0.9844883680,0.6257191896,-0.0121382996,0.9449425936,0.4866577685,-0.1009661183,-0.1784197092,0.7964317203,0.1096719578,-1.0981303453,0.1085784137,-0.2215659022,0.6406838894,-0.7363584042,-0.1355459243,0.1792862862,-1.5051630735,-3.0252084732,2.3134453297,-0.1067946255,-0.2164448351,0.5656723976,0.1987833977,-0.4938872755,0.3542607427,0.7917511463,2.0004119873,0.1138286367,1.0661466122,-1.2925044298,0.0914441869,0.6103685498,-0.9954180121,-0.4100271165,-0.4298735261,1.2885445356,-1.7387659550,-0.5108031631,0.1936938167,-0.2972007990,-0.5979477763,1.5313448906,0.0219627060,-0.7502336502,3.1279857159,-2.1839592457,1.0440800190,-0.6610156298,-1.2552039623,0.4473415315,-0.9450294375,-0.2153885067,1.1292688847,1.4167747498,0.0083199078,-0.7387729883,-1.5310351849,-1.2331342697,-0.0405933820,-0.4422261715,-1.0382130146,1.3626192808,1.1903202534,-0.1882884353,-1.8005816936,1.5561032295,3.1526033878,0.4462724328,-0.5650293827,0.2617058754,-1.4923347235,0.1959274411,1.6606786251,2.1215653419,0.4635251164,-1.6947836876,0.5675776005,-0.0769856125,0.8061911464,-0.7121078372,0.3398130536,0.2747018933,-0.9738521576,-1.0838885307,1.6086019278,-0.1070212498,-2.4784710407,1.2567377090,-0.9551062584,0.8460628986,-1.0296751261,-0.3630988300,0.4910036623,1.3033028841,0.6093656421,-1.5684084892,0.2002652586,1.8276238441,0.1794807613,0.7145086527,0.4715159535,-1.3110510111,0.3708418012,0.5671648383,-0.1211298183,-1.9422543049,2.7631845474,-0.0019290138,-0.9331898093,0.2469065487,0.9991958737,0.1478086561,0.5288000107,-0.2993927896,0.6493500471,-0.5947993398,0.0689935088,0.3103188276,-0.5490578413,0.5102764964,1.0045766830,0.4634752870,0.3118042052,-0.1784106791,-1.2324748039,-0.2715279460,1.3155361414,0.6285444498,-0.7697691917,0.3814707100,-0.7372010946,1.6317893267,0.0496188216,1.8298569918,0.2486533225,0.2665860057,-0.5764042139,-0.1545846164,0.5823374987,-1.2349112034,0.9288624525,0.2240541875,-0.8932236433,0.6563537121,-1.9804890156,0.2280142903,-0.9330589771,0.8488634229,-0.0275313407,0.7628030181,-0.5166394114,-0.0639637858,0.5297335982,0.0976115614,-1.2929050922,-0.2473904490,0.0017580237,-0.0445541181,-1.2251801491,-0.9520522356,0.3250408471,-0.9763738513,-0.3191157579,0.0639646500,0.3773847818,-1.7942626476,-0.3388437927,-0.7155359983,-0.9516233802,-0.8122008443,-1.0962382555,0.8137555122,-1.6893570423,-0.7392467260,-1.0180219412,0.3281373978,0.8430277109,0.6054344177,0.9184139967,-0.4063994288,0.0855568647,-0.1104435921,-0.7943481803,0.2338262349,1.0993648767,-1.3479268551,0.3901562393,-0.3676171601,-0.5882406831,-1.7047501802,0.0156326983,0.3451995254,0.1704274416,-0.5342517495,0.1036691368,1.9168593884,-1.0093951225,-0.2074879557,-0.1844485551,-1.1339180470,-0.7229844928,0.3331287503,0.3014786243,1.4839015007,-0.2690161169,1.0232335329,0.7889760733,-0.4552712739,0.3501521647,-0.2285785526,0.9389357567,0.0447394811,0.1851441115,-1.2355756760,1.2031196356,0.0116550243,0.9264087677,0.3385564387,-0.5845701694,-0.6950528026,1.0220985413,-0.7311565280,-0.9815580845,0.8116582036,-2.7727127075,0.1836193055,-0.8430696726,-0.9484882355,0.3477781117,-1.2728915215,-0.9775258899,2.0550086498,-1.1804845333,-1.6777393818,-0.2583949864,1.9016064405,-0.2666935325,-1.0596487522,1.1103088856,-0.5217511654,-0.1671878248,-1.3836013079,0.5602372289,-0.7295765281,-0.0698853359,-0.5959703326,-0.6792480946,-1.0985150337,0.4957344830,1.3550078869,-0.3935103118,1.1229667664,0.8153097034,-0.6519557238,-0.4303318560,-2.8154788017,-0.3087665737,0.7753482461,0.6616540551,1.1300858259,0.6900553107,-1.8309692144,-1.0626448393,-0.7698283195,-0.8680559993,-0.7421313524,1.8048762083,-0.0947011113,0.4935582280,-0.1392302960,0.1740383208,0.1270922571,-1.5548484325,-0.0411530435,-0.6951826811,0.3269871473,-1.4882113934,-0.3722811639,-0.3547021151,0.1275018305,-0.4833881557,-1.8390951157,0.1966317892,0.5947086215,-0.0949502289,0.2317803800,-0.9899123907,-1.4969880581,1.9577594995,-1.1843186617,1.5552152395,0.5649688244,-1.7155886889,-0.6562070251,-0.8054563999,-1.6628246307,0.7222976089,1.0663632154,-0.1094901860,-1.5984297991,-0.5933257937,-0.0686090812,1.2584441900,-0.3986067474,-0.4922445416,0.2149075568,1.6925339699,0.4467121065,0.0721166655,-0.1689761132,-0.4769457579,0.1210901141,-0.1196763217,-0.3491147757,-0.6679611206,-1.1081523895,0.8642325997,-0.3652341068,-1.4192044735,0.5283550024,-0.4291144013,-3.9799249172,2.5193560123,-0.0001015828,-0.3741996288,1.1290762424,1.6821254492,1.0898627043,0.0934686586,0.3777738214,-0.5232481956,-0.5119860172,0.8392738700,-1.3982032537,-0.5136648417,0.2465056181,1.1420283318,-0.4828293025,1.1170063019,0.2153869420,-1.0433691740,0.7852531672,-0.3490794599,-0.5112475753,1.0232989788,-0.0248605367,0.6658914089,-0.0275805313,-0.3348940313,1.8200131655,-1.0081651211,-0.2610522807,1.3033430576,-0.4144646525,-0.0354455411,0.8998509049,0.5341755748,-0.4204404354,0.2261348367,0.2233097106,-1.1665488482,-0.5937159657,-1.4060828686,0.4686772823,0.0984703451,-0.7751576304,0.3141351938,0.8974028826,-0.1393257678,0.7376810908,-0.3796384633,0.7480918169,0.2854343355,0.4962151349,0.0067210966,1.3005772829,1.0714277029,0.6444802284,-0.5154283047,0.0870009586,1.0096105337,-1.8330725431,0.1132716388,-0.0708507001,0.1738734245,-1.0237518549,0.2748146057,-0.2124217898,-0.1312001646,-0.7777321935,-0.8523564339,-0.5532600880,-0.4056203365,2.1330664158,0.2694247961,0.0929921642,-1.1530809402,0.5591195822,0.1892250180,0.6476491690,0.0823355317,0.4193497598,-0.6377058029,0.2406051308,-0.6672044992,2.6748664379,-0.5676947236,-0.3393431604,-0.5449929833,0.2807078958,0.9032731056,-0.6467321515,0.8295060992,-1.8630459309,0.4991222322,0.4042034745,-0.0883236080,-0.0470565073,0.9142104983,1.0030266047,0.2447029352,0.6141192913,-0.8892118335,-0.7647240758,-1.1047742367,-0.8095286489,-2.0631930828,0.2100882679,0.2161284685,0.1404330134,-1.7657244205,0.2368792892,-0.1763023734,-0.4331485033,0.1648295075,1.7212885618,-1.1766096354,0.1771905273,0.0255289283,0.0521093681,0.2013487816,0.8420627713,0.9915324450,1.5613195896,0.6682843566,-1.4083592892,-1.2373524904,-1.3657908440,0.5665727258,0.1114991754,0.5536442399,1.0835049152,-0.0504580699,0.2503991425,1.9299334288,-1.5645395517,0.4178295732,0.1182594225,-0.2803184986,-0.0412648320,0.1382355541,0.7969234586,-0.1608946025,-1.3431527615,0.2850189209,0.2608601153,1.9069812298,-0.3040925264,-1.0234804153,0.8924683332,0.9798862338,0.7105198503,-0.5560311675,-1.9237110615,-1.5857894421,-0.0867523253,0.7510196567,-1.6821100712,1.7742727995,-1.1292693615,1.2592233419,-0.5400198102,0.4569769502,-0.1657794416,0.5541830659,1.0131599903,1.1774101257,0.3166932166,1.1890761852,0.4440013170,1.7804197073,-0.8230453730,0.0510413684,-0.8502710462,0.2226673365,-0.8931104541,0.7461739779,0.5200843215,2.4808294773,-0.4306486249,0.7000415325,-0.6627852321,-0.6666034460,0.6417964697,-1.3115973473,-0.4170653224,-0.0155315036,0.2604958713,-1.9038473368,0.8179932237,-0.8048866987,0.1132161394,0.6200553179,0.8735640645,-0.8754689097,-2.9979059696,1.8664747477,0.2899555564,-0.3376359046,1.4218786955,0.0991161391,1.5541207790,-0.0542410761,1.2513942719,-1.3293449879,-1.5720999241,0.2153496891,0.4149667025,-0.3295794129,-0.2767211795,-0.0946821421,1.7693696022,0.0545876808,-0.6418469548,1.1964954138,0.4129462242,0.3027030230,2.1559007168,-0.6829319596,-0.3651222289,-0.0442247801,2.2708928585,-0.7823866010,0.4403840601,0.1520252228,-1.2476013899,0.5838144422,-0.5700789690,0.0327484533,-0.8868691325,2.3026103973,-0.3992435634,0.4614451826,-1.6609683037,-2.1689975262,-0.7229250073,2.8979327679,0.7089292407,-2.3434951305,0.1656176299,0.5335359573,0.0808340311,0.3161955476,-1.3906550407,-0.6597616076,-0.3027254045,-0.3078902364,-0.3183090985,0.2484171093,-1.8363064528,0.1134862378,0.9222687483,1.4002178907,-0.6588960290,-0.5069347620,-0.1029141247,0.0792785361,0.8484690189,0.5411299467,-0.2156495005,-1.4614349604,-0.0294835921,-0.0679289103,1.7664188147,-0.3468401432,-0.9617422819,-1.0435235500,1.4455068111,0.4401999414,0.0200419500,0.0252560489,1.3682826757,-0.7683274150,-0.8309261799,-1.9147306681,0.1773295254,-0.1637866497,0.8641271591,-1.4150470495,1.3570704460,-1.2145545483,0.1236755922,-0.0837656856,-2.5834338665,0.3076185882,0.2000334412,-0.2788176537,-1.8437790871,-0.7380565405,0.6632315516,2.2895617485,0.6810886264,-0.4265203774,1.3332300186,0.9933365583,1.0180410147,-2.1297695637,2.2985951900,-1.2535015345,-0.7859506607,0.3115945160,-1.4633288383,-0.2197153121,0.1873781085,-1.5290776491,-2.2650036812,0.4986795783,-0.4243268967,-0.4248904884,1.2769355774,-0.3564965427,1.3732653856,-1.4011700153,-1.5260056257,0.6965202093,0.1845299453,-0.7892647982,-0.1872230172,0.4882991016,0.1650603563,-1.6113953590,0.2592717409,-0.1188143864,1.2228955030,-0.8016638756,0.6876689196,0.7840186357,-1.5337510109,-1.1500921249,1.2201095819,0.5806935430,-0.8960040808,0.8627079129,-1.1348323822,-0.9670757055,0.3248357773,-0.4929454625,0.1369240880,-0.5122059584,-1.0240994692,0.8177993298,-1.5714014769,-0.9127979279,0.3507647216,0.5462158918,0.0155025600,0.2486607134,0.4373335540,-0.0667797402,0.3301390707,0.5512520075,-0.0004508996,0.2623131573,0.8791959882,-1.3433330059,0.0341191590,-0.1302566528,-0.6102820635,-1.9780943394,1.0417385101,-0.1486586779,1.3084896803,-0.1083629355,0.2558193207,0.6630388498,-0.7649769783,0.0660102144,0.6541601419,0.1619965583,-0.2343661040,1.1309125423,0.9972749352,0.3769946396,0.9053672552,0.0170451328,-0.2916249335,-0.0637479946,-0.8857896924,1.0207086802,-1.3605722189,1.5603965521,0.4978734851,-0.0114495857,0.2822905183,-0.0966921449,0.4231345654,-1.5016077757,0.5884187222,-0.8756873012,0.5964536071,1.5745950937,1.0954363346,-0.8237411976,-0.2152891606,-0.2709789574,-0.2081480324,2.2277188301,0.3763382137,1.2043631077,1.1044359207,-1.3858469725,1.2034906149,0.0602937639,1.5043460131,-0.4531169236,-1.3994597197,0.9959958196,1.4748657942,-0.6896502376,0.5163658857,-2.1955311298,-0.7591708302,-2.2448000908,0.4303465486,-1.8543956280,1.4948334694,-0.3116846383,0.4466024935,-0.0118529536,0.7244918942,-1.6666995287,0.0236608721,-0.4630951583,-0.5484100580,-1.1173944473,0.4898535311,1.6996483803,-1.8060977459,-0.4497342110,0.4933337867,0.0872113928,1.6383810043,0.2239727825,-1.2708234787,0.3466352224,-0.4335897863,-2.5197424889,0.7378028631,-0.8447279334,-0.0559481047,0.6839315891,-1.1025488377,0.2024087608,2.9150803089,-0.3840768039,-0.0326391011,-0.0803115442,-0.8246007562,0.3065483272,0.0389659554,0.8100610971,-0.3687470257,1.0887268782,0.0036491603,-1.0394093990,-1.0970540047,-0.7277394533,0.2685888410,0.7355921268,0.9661358595,0.5190473795,0.0508830100,1.2438833714,-2.2499885559,0.8982744217,-1.2954920530,0.8556146026,-0.4744929671,-0.6942690611,-0.1644901037,-0.2620332837,-0.1451232731,0.0785102472,1.0016654730,-0.2739449739,0.8009263277,-0.1702002585,-0.8886307478,-0.1733903736,-1.1252379417,-0.4982013106,-0.5461481214,-0.7811477184,0.1073800698,-0.7631527781,-1.3092365265,-0.1617819816,-0.0008865069,0.5713884830,-0.1136347950,0.1617997438,0.1273338348,-0.7498638630,0.8821802735,-0.0337238349,1.3859173059,0.5330554247,0.1874614954,1.6891919374,2.0251679420,-0.4745604992,0.0918694958,0.1943952888,0.6713520288,-2.0351748466,2.6817276478,-0.1689636558,-1.2043520212,-0.8034988046,-0.6250877380,1.4457765818,-1.4667338133,-0.8495544195,-0.3539527953,-1.0773371458,-2.4111745358,0.5679433942,-0.2081842870,0.9879924655,1.2360608578,0.7949596047,0.4199788272,-0.6940913200,-0.8832488060,0.5228080153,-0.2757284045,0.2805615962,-0.4129777253,-1.1507169008,1.8317346573,0.1299459189,-1.3232452869,-0.2197397053,1.6015273333,-0.7579594851,0.5799200535,1.2151949406,-0.2547016442,0.1068254113,0.0516264960,1.1671109200,1.3634036779,0.0900574327,-1.0950243473,0.8401091695,0.6654623151,-0.3086810708,-0.7375400066,-1.0307489634,0.1048286334,-1.5460332632,1.8186627626,0.8098951578,0.9708928466,0.7102554440,0.9713087678,0.3875834644,-1.1385778189,0.5401791930,0.4986961782,0.2263549715,-0.2634185255,-1.5598323345,0.3776816428,-1.7435592413,-0.6064981818,-1.0359470844,0.7043692470,-0.5080588460,-1.9649239779,1.1656636000,-0.8278691173,-0.3729766309,-1.5564032793,-0.8267266154,-1.1934009790,0.6669597030,-1.0290228128,1.0644114017,2.3462307453,-0.2566364408,1.2686136961,0.2236939818,-1.1905844212,-0.8348674774,1.0824284554,-0.8072878718,-2.0340442657,-0.1297576725,0.1229395643,0.4321765304,-2.7568418980,-0.5900364518,-0.2194618881,0.9851743579,0.5149931312,0.7409499884,0.9859756827,-0.7990174294,-0.9565790892,-0.6254098415,-0.5258603692,-1.1526063681,0.5984534025,1.7542530298,0.5825209618,-0.0108615747,1.1506799459,1.6939212084,0.6322537065,-1.0341697931,-1.4992163181,-0.9192206264,0.2501222789,-1.6166472435,-0.3118333817,-1.5592268705,1.2363440990,-0.2899449468,0.2497586608,0.8226853609,0.0091154482,0.5934258699,-1.0807846785,0.6175705194,-0.2989517748,0.0668154061,-0.3421589136,-1.2376976013,0.2341058552,-0.2281744033,0.9363278747,0.7818625569,-0.5937199593,-0.2155658305,-0.2269501239,0.0548860207,1.2610039711,-1.1864619255,0.2939851582,-0.1575176418,0.3959463537,-0.5379269719,0.0852746218,-0.1205217764,1.1457941532,-0.6422573924,0.6109707355,-2.3347873688,0.8817616105,-0.4318682849,-0.2186090648,2.3368148804,-0.8696759343,-1.3311178684,-1.4940352440,-0.1126572788,-0.1654232144,0.6756837964,1.0262820721,-1.5286720991,-1.7455735207,-0.0086124055,-1.3048062325,0.7480476499,-0.1624615192,0.8573369384,-0.2427486479,1.5718251467,-0.4005960226,0.1661429852,-0.3388045132,-0.8788685203,1.1277475357,-1.8028851748,-0.9683129191,-0.2205161005,-0.3632950187,0.9993163347,-1.1250728369,0.2273952663,-1.6806476116,-0.5850839615,0.4633552432,0.5404006243,-1.1591656208,-0.4043771923,-0.5775872469,-0.4467805326,-1.3486293554,0.1647246778,0.5355979800,0.6689383984,1.6987106800,1.0737128258,1.5600349903,0.5412341952,-0.2705770433,-0.5515835881,0.4355035424,-0.1320427060,-1.2384092808,-0.3141611516,1.3099900484,0.6195878386,-0.0317559093,0.4572177231,-1.0924277306,1.0926088095,-0.3314957321,1.8907419443,-0.4943482280,-0.0626017973,-0.0550512932,-0.0231284834,0.7892349958,0.3658465743,0.4307425022,0.1753020287,0.4385994077,0.9858914018,-0.7419704795,1.7252422571,-1.0884103775,0.9333866835,-0.4368148446,-0.6445410848,-0.7094064951,0.5206435919,-1.9676936865,-2.0886249542,-0.0491473936,1.7515029907,-1.2138712406,-1.0226154327,-0.5423930287,0.7038816810,-0.8431472182,0.7065833211,0.2752345502,0.0155479768,0.4675925374,0.9834657311,1.3818086386,-0.0449825265,-0.8379833102,0.6575056911,-0.9417086840,-0.9865073562,-0.8108641505,0.4895179570,-0.2885791063,0.6517304778,-0.0437750444,0.9180089235,1.0069895983,0.5761268735,0.4679514468,0.0979376882,-0.6210292578,0.2446375191,-0.2866552174,-0.4697014689,-0.6670892835,-0.2212103456,0.1083477437,-1.3208975792,0.2513886690,-0.6949612498,1.3961971998,1.0441313982,-0.8038179278,-0.6545550227,1.0894525051,-0.8547613025,0.4289109409,-0.9605471492,-1.3116114140,-1.4649935961,2.2020881176,-0.7328217626,0.2469987720,-1.4316263199,1.0094193220,-0.5877754092,-1.2018294334,-0.4497393668,-2.0317924023,-1.3781358004,0.2250173539,-0.2393929213,1.0711579323,1.0380489826,-1.6511549950,-0.3789921403,0.9080212116,0.8696871400,-1.6957534552,0.3965432644,0.0837741494,0.0010892110,-2.4933798313,2.0837154388,-0.2696723044,0.7178445458,-1.4326989651,-1.0441292524,0.9024427533,-0.2075345218,-1.0056159496,0.8656446338,0.0663467273,-1.0112538338,0.4815161228,0.6747781038,1.7164748907,0.0540352389,0.0186312608,0.6076316833,0.5149070024,-0.6382617354,-0.2592832446,-0.1123041362,-2.3297955990,-1.2326625586,0.1074425578,-0.0259655807,-0.4965038002,0.4682292342,-0.7256876826,2.5770611763,-0.5546184778,-0.7165570259,-0.5988902450,1.3805335760,-0.9438036084,1.8827584982,2.2911372185,-0.3109315038,-0.4171719849,-0.9282898903,-1.2628384829,-0.8774039149,-0.1966391057,0.1648458242,-0.0454749390,-0.4523634613,-0.8597000837,-1.8105161190,-0.5551453233,-0.4640676081,0.0456892885,0.9407829046,-0.4700866640,-0.4446507394,-0.9410798550,0.1821057349,-0.8256917000,-0.5830290914,1.5628407001,-0.1577423513,0.3348858356,-1.0220993757,1.5164207220,-0.4169793427,0.0705198646,-0.9684671760,-0.7755367756,0.8577855229,0.7357011437,0.8049449325,-0.5722336173,2.4884157181,-1.0409582853,-0.5645226836,-0.8657156825,0.8756935000,-0.0816876218,1.6169995070,-0.4836786091,-0.5187353492,-0.1280231029,0.3786218464,-1.0286502838,0.9747040272,-0.4097430408,-0.0414662100,0.1704852134,1.2174123526,-0.4135402739,-0.9620710015,-0.6299701929,0.7686001062,1.6596417427,0.1165930480,1.5519549847,-0.0122310994,0.6999790072,-0.3696699142,-0.6388676167,-0.3132658899,-0.3769345582,0.4913886487,0.9003452063,-0.6527366638,-0.9828684926,0.0031222911,0.3023118973,1.1393951178,0.0686765835,0.8947140574,0.1511452794,1.2494877577,0.2830680609,1.0252991915,-2.0512757301,1.0091516972,0.8578301668,-0.4312323630,-0.0823090598,-0.6327573657,-0.6221244335,0.1637613624,-0.4898373783,-1.0175414085,-0.1421252489,0.7623457909,0.6941013932,0.8787897229,1.0183321238,-1.3048707247,0.6710067391,-0.5081533790,0.7300412655,-1.0180243254,-0.6606916189,1.6511225700,-0.3809156120,-0.8625769019,0.1733328998,-0.3080062270,-0.4351976812,0.6185950637,0.1875175387,0.2302682847,1.6791144609,0.6098973155,-1.7957258224,-1.9296709299,0.4632092416,0.9872512817,-0.2040626854,-1.6726781130,-0.7090438008,0.1458017230,-1.1318336725,-0.2968883812,-2.6211783886,0.1238219291,-0.3862033188,0.1050975546,0.4096537530,0.3024674058,-0.8510958552,0.7929092646,-0.2956811488,-0.1781456769,-0.4592222571,0.6618961692,0.7615174055,-0.3307532370,0.0029948372,1.0480338335,-0.9730817080,-0.7652286887,0.1419316083,0.9494506717,-0.6568839550,-1.5343198776,0.7911569476,-0.0277832802,-0.0588698722,-0.9085233808,0.0808649138,-0.0074584479,0.2145736217,-0.0665548891,-0.3323315680,0.0640165284,-0.9991938472,1.8833183050,-1.0895928144,0.8137967587,-0.4096502066,-0.2939639390,-1.3181260824,-0.7032576203,-0.8461838961,-0.0827098563,-1.9362289906,-0.3094807267,0.0122073861,-0.4892766178,0.8326879740,0.8380709887,-0.5376721621,-1.5581637621,0.4174664915,-1.3119213581,-1.4869244099,0.8268741965,-0.0097436709,-0.6998175979,-0.6954088807,-0.2588140666,1.1530423164,-0.8297799826,1.8891391754,-0.7696596980,0.0943683162,-0.0774358884,0.7215057015,-0.5595492125,1.3661303520,0.7425178885,-0.0379569791,-0.5930621624,0.3185641766,1.4783425331,-1.1458002329,-0.9837580323,1.0978168249,0.8367465734,0.6999016404,0.6078990102,0.6545804143,-0.9899599552,0.6728334427,-1.1816710234,-0.8178920746,1.1061612368,0.3675162494,-0.5634465814,-0.2326633036,-0.6539015174,0.4468860626,-0.9113517404,-0.3453916311,0.1714687198,0.2547176480,-0.2261466980,-1.6652747393,1.0987795591,0.7416546345,-0.5794039369,1.2014195919,-0.4735201597,0.7171515822,-0.3532316089,0.5127348900,2.0128924847,0.9054009914,0.0433341525,-0.2319250405,1.2205764055,0.7686790824,1.4405000210,-0.3859676123,0.6124944091,-0.7336784005,-1.2352366447,0.7807996273,-2.3257813454,-0.3928811252,-0.2172492445,0.6651454568,1.7893996239,-0.3957181275,1.1372895241,0.7369244099,-0.8327875733,0.6632367373,-0.0397752263,1.4086065292,0.4437205195,1.4935532808,0.0716269463,-1.0937371254,0.4778392613,-0.4515686929,-1.5649410486,-0.0638999194,-0.4206497371,-0.5077050924,1.3147307634,0.2272905707,0.0551176965,0.3449913859,-0.6504779458,-0.0079302043,-0.6291233301,1.4332242012,1.2907489538,0.3631163239,0.5036269426,0.5870404243,-1.5838334560,1.8516979218,-0.1510378718,0.0084957005,1.7752424479,0.3407488465,-1.7290748358,-0.1309578121,0.1811762899,0.9766051173,0.8586809039,-1.4115585089,-0.5120242238,-0.9084070921,-0.6975479126,0.2765782475,0.5603165030,0.8318665028,0.1136660054,-1.2513357401,0.3720861077,0.6408976912,1.5998200178,1.0436722040,-0.3570035696,-1.7902721167,0.0918675587,-0.1112808436,0.3380652964,0.3301384747,-0.6644927263,0.6445029974,-0.6061426997,1.9779821634,0.1567000747,0.1088435352,-0.8300416470,0.1776271611,-0.3211027384,-1.1594855785,-0.4041348696,1.4324586391,0.2450418323,1.3597365618,-0.2198139727,0.7452784181,0.5204197764,-0.1552402973,-0.0877770483,0.6449214816,-2.0652017593,-0.4502398968,1.5628504753,-0.2074006945,0.5728432536,0.5312701464,-0.5582386255,0.4903011024,0.4000514448,-0.3402361572,0.1078620851,0.1054711565,0.0762601420,-0.8976479173,-2.7556171417,0.6805824637,-0.8755759597,0.5861801505,1.0099159479,-2.0829658508,0.8546541333,0.4041488171,1.4322775602,1.9776724577,2.1114580631,0.2207719088,1.9176034927,0.9244675040,1.6649698019,0.2163754702,0.0035872904,2.6416580677,-1.4437009096,0.4020408988,-1.1299657822,2.0063018799,0.3601942062,0.0552108772,-1.6590025425,-0.6537028551,0.6874204278,1.6122521162,0.2168688625,0.9429037571,0.5354552865,-0.9631315470,0.9434006214,1.5907050371,0.2731074691,0.9513245225,-0.2791555226,1.1296684742,0.7820475101,0.1685398072,-1.9420115948,-0.9730284214,1.1653062105,-1.4316834211,-1.3316079378,-0.0116488738,-0.1106063351,-0.3327346146,-0.1284098923,-0.4964047372,-0.3758531809,0.4843265712,1.5204824209,1.1139789820,-0.3578812182,1.8609610796,0.9948360920,-1.3479914665,0.8106604218,-1.0499941111,-0.6323813796,-1.4502238035,-0.7411080599,-1.1738317013,1.0985153913,-1.7316554785,0.5024092197,0.6399983764,1.8322696686,0.2193556577,-0.2059195042,1.5266751051,0.8948894143,1.6918249130,0.5572015643,-1.3783254623,1.2419376373,-0.1381992251,-0.3036934733,-0.4471315444,1.3595137596,0.5195784569,1.0076969862,-1.0152332783,0.4372532666,-2.2233533859,0.3535255194,1.5505034924,-0.5713678002,0.0189786758,1.5610871315,0.6443794966,0.3136890829,2.5183229446,-0.1112032235,0.4580637813,0.4732072651,-0.6347094178,-0.1455913633,-0.3562349081,-0.0463523492,-0.2493555695,0.7978110313,1.3423910141,0.2120787650,-0.9567505717,1.3303672075,-0.3680039048,0.7403077483,-0.2130557746,-1.3168724775,0.9083569646,-0.4936971068,1.0476306677,0.5149489641,0.5401264429,-0.3668811321,0.5347924232,0.4814083576,-1.0775488615,0.9366270900,-0.3202053010,-0.3182254136,-1.4235715866,2.0460758209,-0.6138587594,1.4505295753,-0.0747881457,-0.8538289666,0.0534842983,-0.2949616313,0.3182134926,2.0032804012,0.2364036888,0.9947002530,-0.5805375576,1.5063704252,-0.9826948047,-1.6039320230,-0.7312178016,0.2631585598,0.0081778783,-0.2120543271,1.4288504124,0.0310508497,-0.4847147167,-0.3707052171,-0.1414912492,-0.1123282909,0.5229693055,-2.4375815392,-1.9124066830,0.1451980472,-2.0455174446,-0.4165692627,1.6499553919,0.0982848108,0.9086429477,1.1524801254,1.1450995207,-0.8715981841,0.2962348163,-0.0864251330,-0.7070257068,-0.0059363027,-0.0952185914,0.9882470965,-0.2431317419,1.0272905827,-2.2877068520,-0.0339677818,0.2500078678,-1.6668512821,0.3891637921,0.5523136258,-1.7448424101,0.6041775346,1.7510638237,-0.5160238147,0.7353807092,-1.2460041046,0.0510762073,-0.1354765445,-0.8791379929,-1.5496599674,0.1134271175,-0.2463372648,-0.0203294978,1.5303599834,-1.0988429785,0.3622785807,-0.7890076041,1.4901959896,-0.2522631288,0.6070600748,1.0430524349,-0.1125693843,-0.4349509776,0.7843998075,0.6623550057,0.0715067312,-0.2036272436,0.0255890638,1.2453645468,0.1566366106,-0.4086671472,0.8515979648,0.4264606535,0.0430518128,0.1734429896,-1.9741030931,0.6002647281,-1.0860610008,-0.4001491666,0.4027245641,-0.4328278005,-0.6476949453,-0.0458221361,0.4308312535,0.8188905120,2.1767871380,0.5373866558,-0.9187107086,1.3414472342,-0.8143109679,-0.4182454348,-0.9356334209,1.1228146553,1.3687461615,-1.2463581562,0.5486357808,0.3156320751,2.7218301296,0.4282638729,-1.6033006907,-0.2760243118,1.5372369289,0.3407447040,0.8939761519,0.2236253321,-1.2835608721,0.5933554173,-0.8735864162,-0.1540386975,1.7338123322,-0.2981918752,0.6927968860,-0.5642343163,-1.1485286951,0.7087337375,0.7157472372,0.1084082723,-1.2599521875,-0.1718678474,-0.1303246766,-1.6611258984,-0.1089953035,-0.8575206399,1.2285900116,-0.5913127661,-0.8356810808,-0.8497319818,1.6891064644,0.9818716645,-0.7118170857,-0.0595040582,1.1489208937,-0.1327075511,-0.7262676358,-0.6392194629,-2.7723453045,-1.0678972006,1.4211807251,-0.5049116611,1.0029976368,-1.7353630066,-0.0004422014,1.3126903772,2.6282687187,-0.8856875300,1.2361621857,1.1301437616,-0.7847929597,-1.4580696821,-1.9722865820,-0.3570451140,1.5762296915,0.6130509377,-0.8741570711,1.8246018887,-0.4657349586,-1.2615884542,-0.4083859324,0.3294874430,1.1362862587,1.5787801743,-1.5691125393,1.1296247244,-0.8173444867,0.0448391438,-0.2004632354,-0.1206745356,2.1760234833,1.4095352888,1.7142325640,0.1296830177,-0.0240912717,0.1981743574,-0.5931743383,-0.6481423378,0.2112238854,0.0259035602,-0.7714331150,0.4130635262,0.4231062829,-0.1897049546,-0.2473408580,-0.5636284947,-1.4844306707,-0.5463525057,1.6333186626,-0.4062886238,0.6718820930,-0.1990920752,-0.0755890235,-2.4272682667,-1.0069460869,0.2937736213,-1.8922125101,0.0387951620,3.0649490356,-0.2021356225,-1.7997900248,0.1907552779,0.2254720032,-1.4364736080,1.7227665186,-1.0507551432,-0.3714186549,0.2494156957,0.1630332470,0.5737173557,0.3798969388,0.6762976050,2.1938946247,-1.3434695005,-1.8401567936,-0.4973259270,0.2549467981,-0.4350290895,1.7625454664,0.2511341572,2.0254280567,1.4629654884,-0.2105290741,0.1842921525,-0.8437554836,-0.1074019298,1.3886370659,0.6858979464,-0.7213442922,0.7010446191,0.2083124965,-0.5340302587,-1.8905137777,-0.2197514623,1.8318955898,0.5987322330,0.5050485134,-0.0544060431,-0.5782997012,-0.2975089848,-0.1296807826,-3.1675622463,0.4436289370,-0.8021137118,0.6727771163,-1.4421380758,1.5984972715,0.7499288321,-2.0262806416,-0.2081878334,-0.5387793183,-0.0523785017,1.5313670635,0.7524619102,-1.2980279922,-0.4864748120,-1.9687265158,-1.1095793247,-1.3467646837,0.1210370436,-0.4014209509,-0.3103523254,-0.5346525311,0.2820588350,-0.1820099205,-0.1331241280,0.2891933918,-0.2156425118,-0.4738779366,-0.4227135181,-0.3396925926,1.0411024094,0.5079514980,2.2190010548,0.1058152467,1.4273592234,-1.4032130241,-1.1333082914,0.4115984738,-1.2759627104,-1.7923833132,-0.9866417050,0.0260736253,0.2983654141,-1.0883109570,0.1540415883,0.7682629824,0.1405778527,-1.7093214989,0.8520715237,0.3354863822,1.0088881254,0.9830012321,-0.1587079316,0.2750813067,-0.5337952971,0.5333610773,0.5658074617,0.1133866310,-0.5827506781,-0.1758695394,-2.3300492764,1.3145494461,1.5094611645,-1.1486440897,-0.9897459745,-1.2299499512,0.4605937004,-0.7130784392,0.9297976494,0.1480864882,-0.6089158058,-0.8862819076,-0.0294247605,-2.0403492451,-0.4883415103,-1.0245062113,0.2432617396,-1.2315342426,-0.3076558113,-1.0241663456,0.4212306142,0.1273297518,-0.8465504050,-0.7393798232,0.0760505572,0.3653028309,0.1351646036,-0.0163296815,2.1622841358,1.6225196123,-0.9306966066,0.9292284250,0.3719254434,0.1162487194,-0.0589749292,0.2543700635,-1.6679431200,0.4688638747,1.8470935822,-2.0336110592,0.2948815525,-0.5645554066,-1.2335046530,0.6282685399,-0.3543842137,-0.7103201747,-0.4193950295,-0.7470821142,-0.7791161537,0.9769921899,1.0773099661,0.6259647608,0.8145341873,0.2484787703,-1.5553941727,0.2921783328,-0.8426584005,-1.1621177197,-0.0484674945,0.8237134218,-0.8495957255,1.6625444889,-0.5229098201,1.4123066664,1.4815165997,-0.5415441394,0.0697141588,-1.3264377117,-0.2319623828,1.2776615620,1.8105273247,0.4019567072,-0.3616358936,-1.6378117800,0.3181915879,0.9920549393,0.4044793546,-0.6421396136,-0.7581509352,1.0275832415,1.5470706224,-0.7398016453,0.6584480405,1.1294622421,-2.4815869331,-0.8624873757,1.3350468874,-2.7070226669,-1.4999361038,0.1586216390,1.8153672218,2.8114330769,1.5783907175,-0.1268175691,0.7761794925,-0.0535948388,1.4350873232,-0.3202698529,-0.6328254342,0.6196979880,0.9736643434,-0.8059627414,-0.0634836704,-0.4779267907,0.8468277454,0.9047194123,-2.0163111687,0.8780838251,-0.4427151680,1.5682283640,-0.0647773743,1.9337058067,-0.0634923875,-0.8278262615,0.1841171682,-1.2062327862,-0.1774312556,-0.3325543106,0.5048562884,0.1616335213,-1.3787573576,0.2442163378,-0.4408593178,-0.1357885301,-0.5383255482,-0.9141966701,-0.1598681062,-0.3700854778,-2.1424248219,-0.7458830476,0.1234179586,0.9672073126,-0.1455941498,0.4572854638,0.9470093250,-0.1653638631,-1.2481099367,0.6318738461,-0.0626924559,0.5399544239,0.8403316736,0.9862011075,-0.3642502129,-0.6327438951,-1.3328721523,0.6068063378,0.8446694613,-0.6332240701,0.5425485373,0.7139165998,-0.0305935647,-1.4514397383,-1.3369790316,0.5513197184,-1.5224503279,0.5453975797,0.8725185394,1.4529868364,0.5624259710,2.0542755127,1.7089699507,0.9274854064,0.4328777492,0.7026924491,-1.3295015097,0.2746844888,0.2033832967,-0.4538957775,0.1762087941,1.7823884487,-1.4706496000,-1.2204672098,1.4729512930,0.1214189082,1.0871387720,-0.3612067699,1.7784131765,0.9309613705,0.2597780526,-1.4110622406,0.2922568917,-0.6586437821,-0.0512520969,-1.3286775351,1.6530493498,-0.7626387477,0.9156857729,1.9149209261,0.2932203114,-3.0808136463,-1.0101010799,0.6143974662,0.2382051498,-0.0467596762,-0.0474947765,0.9090418816,-0.2340825051,0.5424991846,0.4172537029,0.4624036252,0.4270164073,1.6592540741,-1.0672186613,-0.1578507125,0.0752028897,-0.9551435709,0.7953690290,-1.1591863632,0.7421058416,-0.2349259704,0.5437689424,2.1095736027,-0.0088392152,0.8944605589,-1.1591901779,1.0720796585,1.0443638563,-0.4178381264,-1.0055652857,0.2256257236,0.1818790883,0.8913904428,-0.2827850282,0.5382263660,0.5552778840,0.5970648527,-0.3059228361,-1.1920317411,1.1359806061,-0.6876258850,0.9734085798,-0.1243617684,0.7628061175,-0.8110380173,-0.7298203707,-0.0372581482,1.0960302353,0.8897184730,1.0013744831,1.2954847813,1.0943894386,1.0337970257,-0.6451089978,-1.1438543797,1.6907882690,0.6538919806,0.2325033396,0.7079269886,-0.4387639165,-0.8021144271,-1.0609641075,-0.5739922523,-0.0819813982,-1.1191276312,-1.4699013233,1.2190533876,-0.7642792463,3.6206753254,0.2141495645,0.5528623462,0.1748252213,-0.6519388556,-0.6073905826,0.3652521074,-0.9204075933,-0.7603232861,1.0630009174,-0.9325689077,-0.5900637507,-1.1881865263,1.2027990818,-0.8413612247,0.2781607509,-0.2080128193,0.1023407057,-1.2445551157,0.6239708662,1.8129197359,1.0736453533,-1.8964418173,0.0017032215,-2.1157252789,1.3135426044,0.5474115610,0.2074623406,-0.4299831986,0.8374266624,1.6306321621,-0.3326140046,-1.8029530048,0.1280977726,0.6147022247,-1.1669268608,-0.2353281975,1.2309724092,0.2109920084,0.5916821361,1.1949048042,-1.6691788435,2.2587573528,-0.8347861767,0.7055326104,-1.2176433802,-1.5963435173,-0.9394806027,1.1430879831,-1.0527108908,-0.2372030914,0.5021895170,-0.1742438227,-0.6610577106,0.9951126575,-0.5641317368,-0.9586183429,-0.4543020725,1.5888733864,-0.5602775812,-1.4585738182,0.2766699195,-0.2458266318,0.0311310496,0.3165929019,-0.4411346018,-0.7168897390,1.6787896156,-0.5344859362,0.1416471153,0.1917462647,0.5545337200,-0.9684610367,-0.2502814233,0.8965836763,-0.3063308001,1.5524247885,-0.2281495482,0.5966132879,-0.0518924855,1.4180803299,1.1030684710,-0.5906302333,-0.4166026711,-0.1812176853,1.2438272238,0.0661688223,-0.4422826469,-0.0799380690,0.1919439882,-1.7107120752,1.0774523020,1.3768286705,-0.4153911173,0.5705907941,-0.0298591200,-0.6760396361,2.0611596107,0.6797024012,-1.9420374632,0.1937771142,-1.4224283695,2.3359291553,1.5439224243,-0.1088899821,0.3045460284,-1.9224047661,-0.8653616309,-1.4767225981,-1.0221436024,1.1010134220,1.6597355604,-0.9422587752,0.2524269819,-0.5980673432,-0.8463162184,0.1441775709,-0.0865074918,-1.4574160576,-0.6760374308,-1.1465848684,0.6518920660,0.3316673040,-2.1897077560,-1.5613869429,1.1978230476,1.8515207767,-0.1663241088,1.5600320101,0.6311469674,0.5801112652,-0.6303533316,-2.2313139439,1.1076989174,1.4743758440,0.0909270272,-2.3126523495,0.0237566549,-0.5718167424,-0.2207095027,2.1772885323,-0.4963387847,-1.0081264973,-1.5023629665,0.7746482491,0.5341107845,-0.5666756630,-1.3972266912,-0.6807674766,0.9254412055,0.5504223704,0.6605623960,0.8508396149,1.3720737696,0.1541136503,0.8757134080,0.5460981131,-0.3596907854,0.1870216429,0.0117444582,0.6488144994,-0.5489287972,-0.3713762760,-0.7516688704,1.4095368385,-0.9506681561,1.2551702261,-0.2971719801,0.7826270461,-0.1850647628,0.0467204042,-0.5125409961,-0.4186106026,0.6029446721,-0.1644520611,-0.7338615656,1.0119118690,-0.9809918404,0.1098827720,0.0214030836,-0.0427952483,1.5712121725,-1.2539938688,-1.1002814770,1.1327694654,0.7072475553,0.3967822194,-1.5087244511,-0.7145330906,-0.3722834885,0.6798279881,-1.1214778423,1.6043719053,-0.5292537808,0.6880461574,1.8885463476,-0.0577552915,0.2836357951,-0.5647696853,0.2792871892,0.8215509653,-1.3532710075,1.7211893797,-0.0139528438,1.8308835030,0.7426056862,0.7111511827,-1.6903294325,0.1072090045,-1.0851238966,1.3005352020,0.0922427997,0.3189244568,-0.2317275256,-1.6285777092,0.2906110287,0.5595755577,-1.5583685637,-0.5369408727,-0.2023313344,-0.4653785825,0.2014144212,-0.7816708684,-0.3592549860,0.8583226800,0.8177946210,0.5941096544,1.9991146326,-0.1164116636,1.6596740484,-0.1440827549,0.4968259335,0.6306084991,0.6978434920,-0.7464147806,-0.2029277682,0.0740947649,1.0179958344,0.3487094343,-0.9844735861,0.5505439043,0.2724183202,1.6677926779,2.0806522369,0.4009736776,-0.5573444963,-1.5428788662,0.3109628558,-0.1744219512,1.1310318708,-1.1780905724,0.2007820308,-0.7422007322,-0.9340967536,0.5350461006,0.0442560837,1.1695052385,-1.3321918249,0.6491150260,-0.4747289419,0.5556890965,0.7429620028,-2.0583868027,1.9008646011,0.3469739258,0.0191483814,1.1078541279,-2.2555680275,-1.9164475203,0.2035084963,-1.1060945988,0.3864742815,1.8186519146,1.0955337286,-0.1587141752,1.2405792475,1.1290600300,0.1848345250,-1.3021864891,-0.5888038278,0.5011674762,-0.2290555686,0.1941754520,-0.0028979329,0.1620416641,-0.1024544761,1.3428152800,0.5823216438,0.5299244523,-0.4311875105,-3.9000253677,0.1455959678,0.1971248835,1.5607292652,1.1137356758,-0.4552126825,1.4894210100,-0.2594603002,1.3953379393,0.0575970933,1.1616679430,-0.5125772357,0.2737622857,0.6855733395,-2.2379720211,0.0204583369,-0.4642761946,0.5056542158,-1.1518577337,-0.0480799004,0.8714804649,-0.4403902292,0.9177758694,-0.2967298031,-0.1093246862,-0.3690237701,-0.8198360205,0.8055944443,-1.2107851505,0.3110791147,-0.1688169837,-0.3388747573,-1.0188363791,0.5383563638,0.2944939733,-0.4924473166,-1.0070977211,-1.6481902599,1.4362820387,0.6015846133,0.5694240332,1.6722046137,-1.7027004957,-1.3625906706,-0.1457322389,-0.5113507509,0.2680238783,-1.7027720213,0.7206459045,-0.5888085365,-0.6532110572,-1.0642852783,2.3046946526,-1.4179235697,0.2645181417,-0.8454362750,0.4878188074,-1.3037599325,0.7964784503,-0.1442486495,0.3195949793,1.4605239630,-0.6226558089,-1.4823346138,-0.4593512416,-0.9331763983,-2.1541390419,0.6264881492,0.0523369238,1.1512045860,-0.4332700968,-0.9674804211,-0.1992558837,1.5613337755,-0.3819993436,0.6795611978,1.0330165625,-0.6436550021,-0.0710420236,-0.8683775067,1.9464271069,1.7365958691,0.8267059922,-0.2149627805,0.3993192315,-1.1981478930,0.6476678252,1.6629068851,0.1144966111,-1.2598162889,1.8402992487,0.1836557686,-2.4232974052,1.7620264292,-1.8486828804,-0.9964275956,-1.1717942953,0.6456684470,0.2873594165,-1.3820856810,-0.7862964869,-0.2583193183,-0.8816519976,-0.5542247891,-0.6523939967,0.5725956559,0.4938937128,-0.7512942553,-0.0124218957,-0.9071369171,1.4349648952,1.1218518019,-0.1233512685,1.0522289276,-1.6539301872,-0.1291158497,-0.2237756848,-1.1045513153,0.4521828890,-0.9502961040,-0.1316948235,-0.7792828083,0.8250408173,-0.8836473823,1.2532879114,0.7888385057,-0.8419920206,2.7643673420,1.0004105568,-0.4344625175,0.2776719928,1.3631216288,-0.7419697642,-1.4716395140,-0.1492524296,0.0200016722,-0.5150440335,-0.4084215462,1.4968609810,0.4010550976,-0.7996406555,-0.3596092463,0.5699978471,-1.6187551022,-0.2355066538,0.4505786896,1.0382069349,0.1090804636,1.1643670797,-0.9958294630,0.8406545520,-0.6185593605,0.4861762524,-0.1435554177,-1.1838173866,0.6962852478,0.8449316621,-0.5324366689,0.0854075029,0.3886263371,-1.1088260412,0.0637926683,-1.5521410704,-0.8580669165,0.5527657270,-1.3862566948,-0.3908568025,0.9630132914,-0.7347410917,1.8605796099,1.0593957901,-0.3667660952,-0.6616054177,-0.5578662157,-1.0552052259,1.4580582380,1.1121358871,0.9594700933,0.2913878858,-0.1537316144,-0.5127632618,-0.9405737519,-0.6017516255,0.2945948243,-0.3719144464,-0.9353292584,-1.3446847200,0.9422808290,-0.6510933638,0.8299900293,-0.3449546695,0.6160442829,0.4052671790,-0.6935716867,1.0162554979,0.6377590299,-0.4352501035,-1.4257146120,-1.2524747849,0.7853822112,-1.5440671444,-0.1379649192,-1.7845451832,-0.3356660903,1.3356161118,-0.1294857413,1.7964646816,0.0304738451,0.7768535614,3.1488924026,-0.2558109760,-1.0679833889,-0.7244794369,-1.2258969545,0.6932333112,0.0211398620,0.1776879132,-0.5041844249,-0.2590360343,1.1173756123,-0.4724331498,1.3155813217,0.4622018635,0.6426978111,-0.5433134437,0.4678083062,-0.3611486554,0.8685443401,0.8873092532,0.9602596760,0.2302647084,1.2853378057,0.5569596887,0.0047805822,-0.6112685800,-0.6782135963,1.8684548140,-0.0579861216,-0.5789955854,-0.5955775976,-0.0142703950,-1.9806233644,-0.3151291013,0.1911353171,-0.7444159389,0.3003838956,0.3280220032,0.3322880864,-0.4767027795,0.2453860193,-1.5312238932,0.4211049378,1.9572474957,-0.2563537657,-0.7224268913,1.6377799511,-0.7879798412,0.3240051568,0.9042937756,0.7157511115,-2.7979767323,-1.2734445333,0.9677686691,0.9257705808,1.2029485703,-1.3839800358,0.7151804566,-0.2824457288,1.1473516226,0.2747390270,-0.7925121188,-0.7553021908,1.7981562614,0.6151124835,-0.2200139612,0.2743393481,0.9763574004,-0.3318104446,0.3161179721,-1.2327262163,0.7387780547,1.0659815073,0.5092077255,0.4646466076,-0.1616929471,-0.3656149805,-0.9359837770,-1.6265611649,-1.7118582726,1.0020611286,-1.0089641809,-0.5619198084,0.0407424457,0.4716152847,-0.7087352872,0.2111394554,-0.0356240310,0.1253914833,0.3591753542,0.6934660077,0.6154317856,0.5487660170,-0.6675722003,1.3222116232,-1.3435800076,-0.3621238470,0.6056843400,-1.4640836716,-0.1939837933,1.3377373219,1.3163279295,-0.2840470374,0.1725505888,-1.0558664799,-0.5492330790,-0.2993440926,-1.0710476637,0.0941991359,0.1093792766,-2.4019165039,-0.7428352237,0.9365871549,-0.1508529186,-1.0279309750,-0.2757891715,-0.3821061254,-0.1312558502,-0.9542873502,-0.9391035438,0.7704802155,2.5137343407,-1.8576669693,0.8858221173,-1.0607217550,0.8156251907,0.7083178759,-0.2483287305,-0.3928205669,1.5658286810,-0.4305017591,0.7362316251,1.7274297476,0.6333814859,0.7388486862,-0.0623305477,0.3513028622,1.0972409248,-0.4740725160,0.1975655705,-0.0587218367,-0.9982358217,-1.9500787258,0.6160622835,0.8414084315,0.1016046256,0.6070315838,0.1194629371,-1.4341905117,-0.1593689024,-0.6355468631,-2.6104624271,-2.0266444683,1.4117767811,-0.3176827431,0.9845973253,0.0557049438,0.4061246812,-0.8875346184,0.6713454127,1.0031460524,0.3599224389,0.9649901986,0.0233377106,2.1343255043,-3.0345256329,0.0627000332,1.7538636923,1.6268380880,0.3056345880,-0.3472956717,0.4976058006,1.6890598536,-2.3212182522,0.3656421304,0.1159397736,0.8868479133,1.6109799147,-0.6043145061,0.0901816487,-0.5041403770,0.1524684727,0.4275237024,0.8015805483,0.1325070113,1.7922909260,0.0355416387,-0.0134482626,-0.1337601840,-0.4896154702,-0.4701613188,-1.1700284481,1.0802490711,-0.3751786947,1.8959558010,0.7834692597,-0.0290208533,0.2484013289,0.5301579237,1.0153846741,-0.1129957139,0.0102426130,1.1725256443,1.3199801445,-2.3764221668,-0.0671974123,0.1287298054,-0.0941253453,0.4301971197,1.1682566404,-0.8586180806,-0.0630043671,-1.1315516233,0.8523266912,0.8010767102,-0.5508226752,-2.2161388397,-1.2388525009,1.3747489452,-1.3621162176,-1.3913899660,-0.8186293840,-0.4310851693,-0.3265868723,-0.6595625281,2.3377609253,-1.4617418051,-0.3850235641,-0.5001681447,-0.7882581949,-0.6133599877,-0.7521061897,-1.3350371122,0.8898956776,-0.1522801816,-0.1465325207,-0.3226323426,-0.4473139346,-0.5643959045,-0.9613133669,0.8519867659,0.3872238696,1.4215050936,0.3426579237,-0.9598645568,1.6452548504,1.7389665842,-0.6744043231,0.3472268283,0.2202254236,0.2865630090,-0.6780747771,2.7566978931,-0.8731807470,-0.7633216977,0.6871228814,-0.6211286187,-0.4921645522,0.0778925493,0.2215663344,-0.2430664897,-0.3674600422,-1.3664894104,-1.6891640425,-0.6190827489,0.6096336246,0.4023823142,-1.6844097376,-1.2404732704,1.2487276793,1.0760413408,0.7050176859,0.2361517102,0.0590851456,0.6469197273,-0.0474967249,0.4412597120,0.5177218914,0.2961484194,0.6438617706,-1.9988317490,1.8926148415,0.1096209288,-0.1981773376,-0.4132628739,0.1424571574,0.2664468884,-1.3339275122,-0.5177214742,-1.3208273649,0.3496943712,-1.0425800085,0.9637414813,1.1737784147,0.4498517811,-0.0644505918,0.5101744533,2.1366763115,1.4451804161,-0.4666092992,-0.4894590378,0.3287404478,0.3134740591,-1.2987185717,1.3868933916,-0.2306082249,-0.6893220544,1.3180077076,1.3273700476,0.4140501618,0.7191207409,-1.2703672647,-1.2914323807,0.7756549716,-0.5866320133,-1.0754280090,1.3346775770,-1.1625427008,-0.0874402970,0.3637840152,-0.7374979258,0.0501301140,2.0589954853,-0.1709011495,1.1750373840,-0.7916604280,0.6599710584,-0.1943487674,-0.7274425626,1.4040251970,2.2787554264,1.5396624804,-0.0670272559,0.2121014595,1.2338556051,0.1547452658,0.0879635513,-0.7265217304,-0.2062857002,-0.5102232099,-1.6904525757,0.6855853796,0.4538678527,0.6846259832,0.2891429365,-0.3029614091,-0.3062827587,0.7371539474,-0.2199067771,-0.1700534672,1.6199733019,1.2885725498,-0.7799361944,0.1090501919,0.4491660595,-0.0288286079,-0.0628983006,0.8857010007,0.2705981135,0.3398106098,1.2366462946,2.3887815475,0.2669627666,1.2540435791,-3.3561549187,1.2307398319,-0.9899719954,-0.8115420938,0.3570990562,-1.3176939487,-0.5587753654,1.2871930599,0.5928227305,-0.1087322533,-0.9933822751,1.3560775518,0.1624943316,0.0694571063,-0.0019136409,0.7378163934,1.8368467093,-0.5628502965,-2.1004903316,0.1066910550,0.9081601501,-0.0222555753,-0.3945684731,1.4343575239,-0.5552595258,1.7829042673,0.0356468856,-0.2347169667,1.4369341135,0.8930010200,0.4602114558,-1.9390178919,-0.4052565396,-1.1254340410,-0.2811224461,-0.5239998698,-1.0315814018,0.1420727074,0.3060365021,0.0850403309,0.0480993278,-1.2978804111,1.0131076574,1.3917434216,-1.8141626120,-1.2823776007,-0.1916575879,-0.3455839157,-1.2886086702,-0.8586668372,-0.6362670064,-1.4075217247,-0.9333543777,0.1762785763,-1.3649258614,1.2995932102,-1.1005318165,0.4033268690,-0.3083316386,0.0538614839,1.3773829937,-0.0019546524,-0.2184900641,0.2411379069,0.8984738588,-0.2639446259,0.2973072827,-0.1650132984,1.6599066257,-0.5840214491,0.2017857730,1.3713948727,-1.0020972490,-0.4293357432,1.4016997814,0.1269748211,0.9718328714,0.1917524785,1.1341800690,-0.8607709408,-0.6005527973,-1.3925638199,-0.3704949021,-1.1400412321,-0.1199970022,0.3022707105,-0.3858364522,0.2210528702,0.0352988578,-0.2549173236,0.2986409068,0.4361649752,-1.0413330793,0.3294892013,1.4552787542,1.5862495899,-0.0227510352,-1.0812748671,-2.4277453423,1.2509670258,0.2331276834,0.4919901788,1.9083909988,1.1447935104,0.7911493182,-1.0623035431,1.0173264742,-0.5506180525,1.3086786270,-1.1312993765,-0.2539741099,-0.7769720554,-0.8569401503,-1.0207500458,-0.4745619595,-0.0598216392,-0.8905045986,0.7787166238,1.3677231073,0.1858465374,0.4457555711,0.7118093371,0.2962641120,3.0088768005,-0.4178437889,1.5481282473,0.4459330738,-0.9167686105,0.8193830848,0.7471025586,1.5379596949,2.2011966705,0.3746042550,-0.7496331334,-0.9353886843,0.0856559277,-0.2704099715,-0.2366278768,1.7826231718,1.6654078960,-0.1156392843,-0.3040034175,-1.1702992916,0.3079847693,0.2505033910,-2.8715040684,-0.2713453174,-0.6889963746,0.9085056782,-0.4304555953,-0.8376456499,-0.5170556307,-0.3983263373,-0.1063844338,0.5968197584,-0.8843860030,-0.5697482824,0.9696322083,0.4466669858,2.6486330032,1.0537792444,1.1315171719,-1.6960200071,1.4721640348,0.9752472043,-0.7270838022,-0.0512396209,-1.2781599760,0.0176169593,1.8218171597,-0.7481163740,0.5921722651,-0.3314355314,0.5687924027,-0.0314355269,-0.1451000571,0.0710702613,-0.9201598763,-0.7968252897,1.6790449619,-1.2463930845,-1.1037224531,0.2885740697,1.1588948965,0.6854236126,0.2255977839,0.2921647429,-0.6920856237,-1.1240699291,-0.3644988835,-1.7979272604,-1.1228899956,1.2272027731,-0.5487995744,-1.3136093616,-1.0297425985,0.7001258731,1.7890787125,-0.7551582456,-0.8016943336,0.0867572725,-0.5807051063,-1.9119019508,0.5016669035,-0.7634596825,0.4129818976,-0.6169055104,0.2314937115,0.0343069099,-0.3614818454,-0.0572039559,-0.0302359294,-0.4526371956,-1.9301646948,1.3086107969,-0.2420634627,-0.4892685413,-1.1492084265,-1.3499071598,0.6945834160,-2.6993854046,0.1622554362,1.8245487213,-2.3775310516,1.2132954597,0.4981803596,-0.4224981964,0.6930828691,0.7331420183,-0.8765794039,-0.1939884126,-1.3364939690,0.9969375730,-0.7817802429,0.1041869819,0.5689641833,-0.1894062161,1.7746828794,3.4010379314,1.7501906157,1.1160522699,0.5270024538,-0.5151191354,0.7056614161,0.3733058274,-2.1757833958,0.7578504682,1.2810604572,-1.3550686836,-0.0728973374,-0.8941698670,2.7244987488,0.6562985778,-1.3424791098,-1.4879219532,-0.4622645676,-0.8685433865,-0.8274912834,1.8957636356,-0.2304519713,0.7528501749,-0.4163318872,1.2387114763,0.4693082869,0.5144113302,-0.7112178802,-0.5271394253,0.2068586797,0.3400960863,0.4101056755,-0.7695389390,-1.8163501024,1.2588369846,-0.7120572329,-2.1530566216,-0.3808211088,0.1169305518,-1.2409464121,-0.4366751611,0.2634794712,1.7055178881,1.6841148138,1.5426491499,-0.9426856041,-0.3110214472,-0.6535518765,-0.9700681567,-1.0188583136,1.0102300644,-1.3473342657,-0.9368382692,0.2325300127,-1.4934231043,-1.2163499594,-1.3792191744,-1.7362242937,-0.4512777925,-0.5170749426,0.4252825677,0.7567505836,-0.5467865467,-1.1445674896,-1.5563454628,-0.2236038148,0.1928770691,0.7539950013,-0.2075280994,0.5398771763,-0.9476968646,-0.9016711712,0.2438880652,-0.0737104565,1.0209364891,-0.9426563382,-0.4375885427,0.4001968503,0.2803052068,-0.2396769971,-0.5233165026,-0.0707564503,0.8131171465,-0.3948679268,1.0977296829,0.9422441721,0.0974572301,0.7161006331,-1.0236706734,0.3119589984,-1.7411181927,-0.1571304351,0.9331872463,-0.3369457722,0.4094284177,0.4208583236,0.4179211259,1.1235785484,0.7556237578,-0.3103762269,0.8064317703,0.0034907553,0.0354942977,-0.5652838349,-1.3458013535,0.3002234101,-2.1501505375,-0.0334357657,-2.6188161373,-1.2006733418,-0.0334124565,0.6445909739,-0.6677893400,1.4247175455,1.0710269213,0.4332047105,1.3313224316,-0.4722385705,0.6907301545,0.1094585806,-0.2851660252,0.3637922108,1.1852264404,0.1758918315,-0.7584307790,0.2633218169,1.0621172190,0.2851718664,-0.6434780955,-0.1335996836,0.1274035126,-0.5857658982,1.0504328012,2.0061223507,-0.4886282980,0.0543444939,-0.2162028104,-0.6167577505,-0.7822800875,0.9975462556,-0.0760741457,0.8697055578,-0.5896819234,1.4034289122,-0.6588875651,0.1298187226,0.3436029553,0.2405471802,0.8691177368,-0.2007995248,-2.4776923656,0.1163100004,-0.3875218034,-0.1351628304,0.4279449880,0.0200409684,-1.2814878225,-0.0035458973,0.5171042085,-0.7989640236,-0.5903617144,0.7532331944,-1.8532392979,-0.7018445730,1.1726995707,0.8857141137,-0.6251412630,-1.4943467379,0.8706994653,0.1993800104,0.6574698091,1.3126466274,-1.0984554291,-0.3523005247,1.7237235308,-0.4371421337,-0.2530871630,-0.3125239313,-0.1090791225,-0.2442880720,-2.3474428654,1.0265904665,-1.1621482372,0.5418043733,-0.1000503302,1.6922651529,0.4630069435,0.1329090595,0.6170014739,0.7838420868,-0.5633745193,-0.8491060734,-1.1731932163,1.7671117783,0.2489637136,0.3668170869,1.0373156071,0.4797249138,-0.3064503670,1.5058437586,-1.7131545544,0.5895314217,-0.1014877111,0.0677429512,1.6819930077,-0.5216151476,0.2966107726,-0.6731379032,-2.9088072777,-0.1597213149,-0.8009475470,-0.3718868494,-0.5039060712,-0.8859555721,-0.1667399555,0.8699729443,0.2995379269,-0.0808590502,0.1149650365,-1.2343654633,-0.8192324042,-0.2976688147,0.6526411176,0.8078739643,-2.2390789986,-1.3788408041,-0.0203030016,1.0580019951,-0.1675913930,-0.3040016294,0.4077051580,1.6256030798,-0.4806309640,1.5464959145,-0.2882610261,-0.6253515482,1.1862369776,0.2702769339,-0.0170092937,-1.1964570284,0.9761407971,-1.3807101250,-0.0267551281,-0.7193158865,0.1454325020,0.8919139504,1.2186563015,-0.5411350727,-0.0417981744,0.4048648477,-2.4425880909,1.4544825554,0.9795028567,-0.9254541397,-1.0124781132,-1.2881475687,0.0540674552,0.0661320314,0.2954331338,1.0461391211,-1.0540885925,-0.4005309641,-0.1517889798,0.4216340780,0.0530298762,0.1122975871,-0.3990632594,-0.7042989731,0.1255299598,0.3206685483,1.1385912895,-0.4752325118,0.6582928896,-0.1538144350,0.6831755042,1.7123292685,0.5671478510,0.6366145015,-0.3570763469,-0.0657979697,0.4211172163,-2.2837688923,1.0036052465,0.2398010492,1.0281908512,-0.4071367979,0.9219275713,0.0722149760,-2.6470177174,1.3578057289,0.1536241025,0.4696274400,0.8234762549,-0.4083556831,0.3090576828,-0.6590387225,0.2341024876,0.1462763995,0.2002189904,0.2424708307,2.4530985355,0.1110666841,-1.9045937061,0.6433965564,0.4160172939,-1.7808061838,-0.1339179873,0.8255435228,-0.2238264829,0.4268227518,1.0249240398,0.8471112847,1.3706696033,1.1877846718,-0.9383885860,0.3343340456,-0.4794832766,-0.4944494367,-0.1750551313,0.3527951539,-0.8698111773,0.1937713474,-0.1925773323,0.9743717313,0.6055154800,1.2223517895,0.3614206910,-0.2067714334,-0.9952375889,0.3734723628,0.6979523897,-0.4219244421,-0.5955637097,0.9482497573,-0.7519682050,-0.7860441804,1.3740886450,0.9647676945,1.7791903019,-0.7668116689,1.3360780478,-0.6458644271,-0.1355869919,2.8971319199,-1.1330628395,-0.6012628675,0.5005002022,-0.4042484164,0.4834759235,0.3865878284,-0.3293069601,0.8250538111,0.2771557271,-0.5596065521,0.9277037382,2.3185040951,-2.0182914734,-1.8434972763,1.8513425589,-0.2051957250,-0.3890289664,0.3600519001,0.9884135127,1.2457922697,-1.3364551067,1.7537808418,0.2910317779,-0.2233881950,1.5224063396,-0.4635525346,-1.0450754166,-0.4129071236,1.3809294701,-1.6089481115,0.3078214824,0.9460044503,-0.4184794128,-1.7909796238,-1.0131839514,-0.3165536225,-2.1457698345,-0.9870025516,-0.9171952009,-0.1917024702,-0.7953843474,0.6767178178,-0.3210875988,1.3021671772,-0.4075162709,1.5203324556,0.3550294042,-1.4809036255,-1.2452964783,0.1944308579,-0.9956462979,-0.3705863357,0.5113051534,-0.5084799528,0.7373731136,-1.0020056963,-1.2280149460,0.0769010037,-1.0816389322,0.6120415926,0.5528837442,0.9699832797,-1.6074030399,-0.3329996169,0.2555321753,0.7930832505,0.5816390514,-0.6598396897,-0.2890957296,-0.7990741134,-1.4835071564,1.6605551243,0.8653522134,-1.0595493317,0.9085577726,0.3510276079,0.5514123440,0.8528275490,0.0775258243,-0.0942507908,-0.5741663575,0.4272858500,0.4936881065,-0.4890993237,0.8531798124,-0.5760458112,-1.8211534023,-0.6887232065,-1.4060014486,0.7858404517,-0.7537473440,-1.0371315479,-1.1446654797,0.8815869093,1.2654161453,-0.6383075118,-0.8257868290,-0.9015462995,0.1437274814,1.3519058228,-0.1625126898,-1.9967465401,-1.8057687283,-1.2218840122,-0.4923840463,0.6176373363,-0.7052366138,-0.7661755681,-0.2294089645,-0.0140243210,1.3474508524,0.9664565325,-0.5530868173,0.5022634864,-0.4175859094,1.2790845633,0.3473213315,-0.5481665730,0.1712707430,0.5872876048,-0.2753806710,-0.7414954305,0.4202188551,1.1896193027,0.8167036176,0.0596480407,0.9580199718,-1.3611825705,1.7055370808,0.0063230065,1.8501033783,1.4732143879,-0.0210349392,-2.0528321266,-0.0954066589,1.0599880219,0.7781971097,-0.4838570356,0.4811122417,-1.8912461996,0.3263382018,-0.2272473574,-2.0044629574,1.1873849630,1.5935777426,-2.1323070526,0.3736905158,1.1431974173,2.2025403976,0.5080515146,0.7770988941,-1.9484568834,1.8847243786,-1.0159929991,-0.3248388767,-0.1660611182,0.4894922078,0.1777799129,1.0510669947,-2.4797639847,-1.1504589319,-0.8618552685,0.9332055449,-0.4171830714,0.1696135104,0.4340079725,-0.0387988202,-0.3269042671,0.1180056855,-1.0725272894,-2.8303813934,0.2598698735,-1.9996215105,0.7559278011,-0.9798888564,1.3117982149,0.0267896838,0.7077409029,-1.3086125851,0.4044201374,-2.3094742298,1.6848480701,0.1338439882,-0.6248208880,1.6932362318,0.0373727605,1.5558153391,-0.1714841425,-2.3042349815,-0.4278883338,-0.9955630898,-0.5958486795,-0.0447826646,-0.1579531431,1.5243920088,1.9227956533,0.0402987376,-0.5851413012,1.5017855167,2.1803050041,-3.0837733746,-1.4648975134,-0.3116869926,1.9565404654,-0.3280645013,0.4791809916,-0.5352160931,1.1737276316,0.4787496030,0.4083316028,0.3431856334,-0.6605724096,2.7108654976,0.1147972420,-0.4463745356,-0.5844126344,-1.1667927504,0.5431652665,-1.9812204838,2.9475674629,2.6613872051,-1.2210031748,-1.1133307219,1.1255795956,0.5629199743,2.0009100437,1.5682934523,0.3448376358,1.2724161148,1.6458244324,-0.6888008714,0.2147175968,0.7798329592,-0.3226068914,1.0111198425,-0.5555141568,0.0550549068,-0.4487963021,-0.0010088464,-0.2460303754,0.3926325738,-0.4658337235,-0.0550008826,0.9606356621,-1.3934432268,0.2840017378,0.4586493075,1.6391483545,0.2773736715,-0.4988467097,-1.2484349012,0.6145244241,-0.2343735695,-0.6073554158,0.1037323400,-0.4924787283,-0.8200624585,-0.8451112509,0.3545969725,-0.9189939499,1.3295829296,1.4435455799,-0.4522539079,-0.6177167892,0.4639691710,-0.1216813028,-0.2014279813,-0.3888003230,-0.7420611382,-1.0614147186,0.1071903482,-0.1916001439,-0.8809502721,1.1320753098,1.8845841885,-0.6628830433,-1.5071902275,-0.1309629083,0.3128623366,-0.8688427210,-0.6582813859,-0.2740010321,-0.7021917105,-0.0590858348,0.5003613234,0.4435341060,-0.2532876730,-0.8129278421,0.0408533216,0.9117563963,0.1363046020,0.2125895768,0.2870524526,0.4323830903,0.8272413611,-0.8387100101,-0.5534974933,-1.4483233690,0.5585784912,-1.7981764078,0.2371001542,2.4801561832,-0.3021345437,-1.9256451130,-1.3350820541,-0.2666696012,1.0199847221,0.4717119038,-1.3698065281,0.4468599856,-0.0044480967,0.1817408204,-0.4527272880,-0.1334051341,0.3836607635,-0.4943971932,-1.4046680927,0.9504975080,0.0615183525,-0.5815150142,1.3562990427,-0.6733461618,-0.1815000921,1.1351847649,-1.8547165394,0.0427258536,1.2927519083,-0.7696661353,-0.8274409771,-0.2532393634,-0.0308168735,-0.7520497441,1.3307759762,-1.3623781204,-0.4073944986,1.5803796053,2.0406692028,0.5565537810,0.2322279662,-1.0841896534,-1.7789659500,3.2291426659,1.6942933798,0.9701338410,-1.2909091711,-1.8891059160,1.4711436033,0.4616388381,3.1894185543,-1.5284318924,-0.4539346397,1.7737467289,-1.0063527822,-1.0183699131,-0.7966518998,-0.6973011494,-1.8228462934,-0.6940974593,-1.1141934395,-2.0748908520,-0.6731943488,-0.1411335617,-0.5918131471,0.3981718421,-0.4185449481,0.6575914025,1.2034171820,0.7911134362,0.4504041076,-0.1689087003,-0.6241304278,0.1604327261,1.1599665880,-0.5865268111,1.4177463055,0.7862163782,-0.9866256118,1.3610484600,0.1662872732,0.7623544335,0.4777636528,-0.4978094697,-0.9205987453,-0.6019160151,-0.5025660992,0.2650274038,1.7796533108,-0.6799931526,-1.1500374079,2.1551897526,1.2656960487,-1.8137335777,0.8788180947,-0.1766525656,1.0173312426,-0.3976323307,-0.4874837101,1.3260022402,2.5298173428,0.3581320345,0.6151618958,-0.9057765603,0.1278074235,0.4101307094,2.0343420506,3.1579160690,-0.2835023105,-1.6285960674,0.2310625762,-0.1825703532,0.7172837853,-0.9383327365,0.7119765282,-0.1827139258,-1.0331274271,-1.5335197449,-0.0797828063,0.9077846408,1.8982933760,1.4115979671,-0.4417716563,1.4773440361,-0.0987058356,0.1569772065,0.1336328238,1.4706661701,0.3962785900,0.3535576165,-1.0396783352,-0.8096060753,-0.9630953074,-0.7505313754,-0.1620675176,-0.0327635854,-0.5966364145,-0.0887803882,0.2664997876,0.6335312724,1.0054351091,0.0889114439,-0.5581123829,1.3313112259,-0.0271414258,1.7692632675,-0.3311189711,0.2609533072,0.4870017171,0.5392374992,1.2806769609,-1.3460060358,1.5021263361,-1.1109247208,-1.3770757914,-0.5652141571,0.5334227085,-0.3018633425,-0.9164126515,-0.4580081999,0.1177384034,0.8895198107,0.8998060822,1.0108145475,0.6404081583,1.3359845877,1.2474398613,3.1175408363,-1.2394305468,1.5618791580,-0.8826349378,0.3026507795,-1.4841973782,1.9171879292,0.6733652949,0.2914884686,-0.0425878204,0.7053133845,-0.2756962776,-1.1116207838,0.2003324777,0.4464299381,-0.4472725391,-0.5560350418,0.5862920284,-1.1646692753,-0.7891066074,0.0170574617,1.8001844883,-0.3394494653,0.5136883259,-0.5891038775,0.0483943895,0.4620130360,0.4717587233,2.6874232292,0.8009564877,0.0847277343,0.5359853506,-0.5240750313,-0.2925489545,-1.8751555681,-0.0490361750,0.9783039689,1.7588734627,0.6002600789,-1.5460512638,-0.3047045469,0.1539754272,0.0915840715,-0.5992405415,-0.8042455912,1.4659844637,0.1012221351,-0.1497529149,1.3030563593,0.1541244388,1.2717978954,0.8867399096,-0.4318663478,0.0770084262,1.6258184910,-0.6968182325,-0.3166991472,-0.7483909130,0.5786557198,0.0780947804,0.2426024377,0.0229945462,0.6200746894,0.2310543954,-1.1079101563,-0.4020124376,1.2420753241,-0.6679664850,0.2542519271,1.0629830360,-0.2348063737,-0.0438308194,1.3501619101,-0.7894948721,-0.5703001022,0.3089890480,1.5118911266,2.1752941608,-0.4885034859,0.8232432008,-1.0765361786,-0.0186190307,0.3972360492,-0.6259902120,-0.7424067259,-0.0163867436,0.1629671752,-0.0893045589,0.4563429058,-0.3665952981,-0.0754317641,0.5265722871,-3.5460734367,-0.6457802653,0.7653337717,-2.1300947666,-0.6183684468,-0.1406880170,0.5203972459,-1.0640109777,-1.0158450603,-0.4575025737,0.2972842455,-0.8521395326,-0.7556797862,0.9271347523,0.7557883263,0.9758871198,-1.1998525858,0.7437992096,1.5684306622,-0.5971830487,-0.5554358959,-0.2583679557,1.1155749559,-1.0676947832,1.0032776594,-1.8513797522,-0.3517214060,0.6328516006,1.7444175482,-0.8807442784,1.4790461063,-0.1968304813,0.4180056751,0.7282510996,-1.6500500441,0.3640683889,1.1129844189,0.3351568282,-0.0096940594,-0.8879166842,-0.2117554396,-0.6859401464,0.3963009417,0.4607585669,-0.2736138701,1.7940083742,-0.1557259709,0.4512560666,0.7477252483,-0.5220136642,-0.0076781982,0.2178294808,-0.6283373833,1.9523649216,-2.1755685806,0.3284509480,0.0459350087,1.3447287083,-2.9746835232,-0.4574049115,-0.4559212029,-0.7927967906,0.9932083488,0.5941705704,-0.0860538781,0.4814716876,-0.5481458902,-1.3757659197,-0.6130162477,-0.9668075442,-0.2767145038,1.1864753962,-0.2110439092,0.0695132017,-0.1974823922,0.2356964946,1.3622299433,1.2369188070,-1.0267732143,-1.3356039524,0.4908373058,-0.4819887877,-0.4039094150,-0.6929343939,1.2614177465,0.1905747056,1.1455303431,-2.1158614159,0.2583775818,0.4038105011,1.1752716303,0.4600075483,1.1974021196,-0.8707522750,-0.2817451358,0.0584771670,0.0356177837,-1.0699961185,-0.8630678654,-1.3466277122,-0.6549223661,1.1585097313,-0.1777383983,-0.2447415143,-0.0686794594,-0.4224056900,0.1100068390,-0.2732768059,-0.0694849864,-1.6778137684,-1.1774704456,0.2881167829,-0.3823485672,-0.2653631568,1.6647901535,-0.6484985948,-0.3476527035,0.0990425199,1.2877132893,0.2625562549,-1.7195298672,0.1339644045,0.9347825050,0.6773042679,1.3379974365,-1.1952675581,-1.4742416143,0.4088601172,0.5837417245,-0.8978670835,0.9447718263,1.2271732092,-0.1702542156,-0.7172225118,0.8332493305,-0.9608859420,0.6667991877,0.1675264537,-2.4551825523,-1.3160276413,-1.3327628374,-0.3683435619,0.2090760469,0.2522863746,-0.3697250783,-0.6468358636,-1.3560963869,-0.2139449418,-0.0944914892,1.3924498558,0.8243910074,1.6508191824,0.0590403564,-0.2889220715,-1.5590000153,-0.1294312924,-0.6941680312,1.7140065432,0.3213033080,-1.2664537430,-1.2225905657,-0.4669961035,1.2360336781,-0.0267958753,0.7786743045,0.3648271859,-0.2769484818,-1.7265735865,-2.1605618000,2.6050536633,0.5951356888,0.1564329863,-0.4526445568,0.3408089876,0.7182588577,1.1662245989,1.1812388897,-1.6080279350,-0.6149919629,0.0630393922,1.1043940783,-0.3757201433,2.8040859699,-1.2027796507,0.4753766060,-1.0247412920,0.0444119908,-0.0440445766,-0.9484578967,-0.9130100608,2.2063055038,1.8155006170,-0.4957681298,-0.0989568830,-1.0796426535,0.7822895050,-1.5829148293,-2.0142185688,-0.2487754971,-0.5554159880,-0.4700220823,1.3454676867,1.0648335218,1.0868573189,-1.7082974911,1.4550259113,-2.0609056950,0.1190925390,-0.3908568621,0.7174708843,-1.6193270683,-0.8048923016,0.3411201835,-0.4839953780,0.2841969430,1.0325852633,0.4843482375,-0.3298141658,0.8892413974,-0.3105459511,-0.9782136679,0.9867196679,0.3042748868,-1.2289379835,1.2453569174,-0.9088758230,3.6785209179,-0.8134478331,0.1131959110,0.1259584725,0.1765042692,-0.4288792610,-0.1435288638,-1.2279988527,-1.8669244051,1.1203285456,-0.7590832114,-2.0584406853,-0.3421135247,-0.6633723378,0.3519513607,-0.0436158255,0.2055463493,-0.3620091081,-0.6658552885,0.8952859640,0.4214867353,-1.3065363169,0.5173885226,-0.2587612569,-1.5498518944,-0.7420065403,-1.0491241217,-1.3573287725,0.8090244532,1.1611310244,1.3288847208,-0.1811762154,1.1714485884,-2.1874475479,-0.5001651645,2.5885710716,0.0558268018,-0.2819325328,0.3446589708,-0.4038097858,-0.1715606302,-0.1005059630,0.0135818729,1.7682633400,-1.9547574520,-0.6286581755,0.5792235732,-0.7384209037,-0.5796393156,-0.0029503813,1.5651570559,2.1308877468,0.3770836890,-0.2992276251,-0.4751704931,0.9646815658,0.8811886907,1.2541283369,-1.8058665991,-1.2195588350,-0.2300940603,-0.2072250694,0.3269861937,-1.7808606625,0.9240894914,-0.2287798822,-0.7127582431,2.2856419086,-0.9465098381,-0.1695698649,-0.2585377395,-1.0501010418,-0.7296738625,0.5356189013,0.0110701267,-0.4649605453,-0.1267327815,0.3069141507,-0.2413745672,-1.9641823769,-0.4948186278,-0.3253749609,-1.1279431581,-0.2000069767,-0.0331251286,0.9191393852,0.2092423439,-1.7219876051,0.2334833145,0.5516022444,0.1393381953,0.8058815002,-0.6283417940,0.5322570205,-0.1071301252,1.4491105080,-0.4998187125,-0.8268104792,0.0094867535,-1.2482749224,0.4494889379,-0.0147008393,2.0177221298,-1.5565807819,-0.9726316929,-0.7886752486,-0.9195621014,-0.3232328296,-1.6523182392,-0.6833917499,1.1239200830,0.1679050326,0.3240798414,-0.7736946940,-0.5426825285,0.5655519366,-0.5882941484,-1.1837854385,1.1089788675,-0.5024980307,0.5236488581,1.0887473822,0.1232571155,-2.0052480698,0.4221430421,0.4283335209,-0.4680225849,0.8110977411,-1.0689373016,-0.5722622871,-0.9641005993,0.1786365956,0.4109344780,-0.2174949795,-1.2787374258,-0.2087196559,0.5712300539,0.4369576275,-1.6268904209,-2.0347113609,1.1750626564,0.3646789193,0.1261532754,-1.7006433010,2.5722634792,-0.4614850283,0.4970600307,0.4907185733,-0.0615386628,-0.0598403178,-1.1332823038,0.3685927987,-0.9918488264,0.2320727259,-0.3870346844,-0.2509341836,0.0421222299,-0.3261132240,0.1328040659,-1.4239165783,0.4410168231,0.8100617528,-0.0148307206,-0.5331758857,1.3579202890,-0.4871828556,-0.5692438483,-0.0303262174,-1.2603951693,0.3815560937,-0.2728674710,2.5167510509,-0.0868564248,-1.0303136110,0.7523828149,-0.0511697941,-0.8479565382,-1.6042995453,-0.7471022010,0.1003591493,0.9704436064,0.2647618651,1.9099409580,0.7866731882,0.1858402044,0.1325393170,0.9469413161,-0.4874721766,-0.0009565527,0.8496548533,-0.6209245324,0.2415722907,-1.9862576723,-1.4180949926,2.0506248474,-2.1965746880,-0.0406296737,-0.3715413809,1.2954125404,0.6550036073,1.6960650682,-0.6649290323,0.6570203900,-0.0266126283,1.8540788889,-1.2913211584,0.3372913897,-0.4722357988,-1.3040305376,0.0621721260,-0.0789120272,0.0933005512,1.3070337772,0.4582025707,0.7568929195,-0.0107256742,-0.1645700037,-1.1813340187,-0.2204653174,0.2581693232,0.8963260651,0.0670128316,0.8854981661,0.1641241163,-1.2728308439,-0.9655811191,-0.4384520650,1.6505980492,-0.5964840651,-0.2924530804,0.1418313682,-1.1281623840,-0.1900935769,-1.4205986261,-1.0110018253,-0.8043029904,1.2034075260,0.2360412180,0.7618456483,2.4332990646,-0.2489451468,-2.5425071716,-0.7711074948,-0.4524628222,-0.8661909103,-0.7690161467,1.0050204992,1.8060809374,2.0945205688,0.6686277986,0.6050437689,-1.2227077484,0.4604870081,-0.7087969184,1.8917765617,-0.0848279819,-2.1807665825,1.7026932240,0.1401837468,-0.4388398528,0.0585128926,1.5256692171,-0.2458079308,-1.3954952955,-0.8067660332,0.4578137696,-0.0693819672,-0.5427391529,0.5748937130,1.9503580332,-0.9398818016,1.0572952032,0.7284172177,-0.4724606872,0.7204971313,0.7258913517,-0.2430327237,-0.3732158244,0.8272249699,0.4962197840,-1.8620917797,-0.1028145254,1.1597520113,-0.4121288359,-1.2027361393,0.6976327300,-2.4462964535,-1.7038713694,1.3121316433,-0.5465721488,1.1759943962,-0.0005320666,0.1727978289,0.4999870956,1.2192925215,0.0659877881,1.3122242689,-1.5925445557,-1.8933696747,-1.5688316822,0.7063481808,-0.0540814176,-0.4093583226,0.5415523648,-0.2810840607,1.2379930019,1.8455535173,-1.9942268133,1.9342218637,0.2190882415,0.2802676260,-0.6883954406,-1.4517098665,0.7597011328,1.3933690786,-0.4069502056,1.2743493319,0.7263096571,-1.1906430721,-1.7904323339,-0.7842006683,0.0496981777,1.1656367779,1.2140377760,0.5458866358,0.1088893190,-0.7287024260,-0.3762235045,-0.0407645404,0.0176126137,-0.3848236799,-0.3484652638,0.4573885798,-0.7914643884,-0.5282921195,-1.6176098585,-1.3753209114,-0.7362214327,0.2440520674,-0.5911464691,0.0714291632,1.3157017231,0.8958864212,0.7456697226,0.5918785334,-0.8514651656,1.1709183455,-0.0985445157,-0.7902092934,-0.8238563538,0.6776641011,0.6242868304,-1.7112609148,1.1113905907,0.3983590603,-0.3072124124,0.9468228817,1.0867260695,0.0427968390,-0.2378879040,1.1288268566,0.1591834277,-0.8023855686,-0.0328822881,0.9165640473,1.8892006874,-0.5545433760,0.2005936652,-0.1401738226,0.7532416582,-0.7191939354,0.1173081622,-0.9961249232,-0.0623728819,0.8635931611,-1.3111095428,1.0600906610,0.3490823209,1.0388455391,-0.1214415208,-1.2302621603,-0.3991114795,0.6279140115,-0.7386919856,-1.3221846819,-0.8256247640,-1.4266526699,-0.1054395214,0.1213134825,-1.1871228218,1.2489768267,-0.6177254319,-1.7859925032,-1.0651925802,1.6506885290,-0.0826005265,-1.7071485519,2.9751720428,0.7023817301,-0.5732915401,-1.4239773750,-0.4566698670,-1.0727081299,-1.4537141323,0.1222363412,-1.3030611277,-1.7162252665,0.1611646712,-0.0376786999,-0.5798072219,-0.8318155408,0.3107450306,0.3105241358,0.1700328141,-0.7377840281,0.1470898688,-0.0813722014,1.3564113379,0.1340189725,-0.6625532508,-0.0410240777,-1.3023015261,-1.0368205309,0.5293307304,-0.5021158457,-1.0542820692,-1.1481188536,0.1947138011,0.3171689510,-1.0173329115,0.5187175870,0.1057950556,-0.7455425262,0.4904182851,-1.0010027885,0.3528049588,-0.0746711195,1.0803209543,2.0294268131,0.4842899740,1.8676234484,-0.5828618407,0.7272090316,0.0941341445,0.9208273888,-0.4615549743,0.3433523774,1.0225626230,-1.3546812534,1.1875417233,-0.1132918969,-1.1203707457,1.2187744379,-0.4989327192,-0.9112264514,1.1047421694,1.0056560040,1.5598826408,0.6722717285,-1.3777923584,0.6470066905,0.2687519193,-0.2030589879,0.5464590192,-0.0320212431,-0.2359107584,-1.0255286694,-0.3290923834,-1.6468341351,0.0409779586,0.3232469857,0.1093000770,-1.0682225227,-1.3022935390,-0.1504627466,-1.0588222742,-0.3715017438,-1.1889908314,0.2288609296,0.2993321717,0.4552179277,-0.5519235134,0.0778525472,-0.1051733196,1.2543287277,-2.6627442837,-0.5184801221,-1.8136134148,0.1367356926,0.0721394643,-0.7105522156,0.7686612606,0.3240852356,0.8016172051,-0.2594587207,-1.3651039600,0.7902607918,-0.0750836357,-0.0406575575,-1.5975726843,-0.9080748558,-0.8948983550,0.7329773903,2.6953494549,-0.8728044629,-0.4765469730,1.2926892042,-0.8532977700,0.2273871750,0.8500044942,0.8162901998,0.3053658307,0.1576725543,-1.2945351601,-0.2502624691,1.2744140625,-0.7250322700,-0.2637364864,-1.2683051825,0.9549968839,-1.9983717203,-0.9407818913,0.2056222409,0.9628034234,2.5071811676,0.4945580959,-0.2393418849,-0.4995599389,-1.2183736563,0.6175827384,0.3530254960,1.8969041109,-0.7900554538,1.6417257786,0.5082850456,0.7210969925,0.1719370484,-0.8770158291,1.2253770828,0.0307714008,-0.5999941826,-2.0702910423,0.1392152160,1.5867739916,-0.2774418890,-0.3968944550,-0.6462703943,-1.8079203367,-0.1435433030,0.2059432119,1.6489461660,-0.2428348064,0.8678718805,-2.1709468365,-0.0419791229,0.5046077967,-0.6470251679,-2.1490387917,1.5061701536,1.2396297455,-0.4780521691,0.0269159973,-0.7107182145,0.2932947576,-0.0467100739,-0.6241620183,1.5232892036,2.2675340176,-0.1043779999,2.0489764214,2.2696111202,1.2227553129,1.6606631279,-0.5712388754,0.0546040423,0.2590203583,1.2644896507,0.2683848739,2.7493901253,-0.9891241193,0.4144333899,0.3645968735,-1.1913316250,0.0431974605,1.7358802557,-2.4658632278,0.0826712474,0.4959769845,0.5519586802,-0.2668684125,-0.9466699958,1.6705639362,0.7358431220,0.7760394216,-1.1162991524,-1.0943129063,0.5646335483,0.5407114029,-0.5756079555,1.8289971352,0.8284856081,-1.6793274879,-0.0482726954,-0.3428310454,0.4674871862,0.4687924385,-0.7644754052,2.9350652695,1.5090997219,-1.2739346027,-0.8650171757,1.0715694427,0.7076815367,1.1324560642,-0.7596591711,0.4681403041,1.6337355375,0.3445463777,-0.3208348751,1.2135955095,1.3381587267,-0.1650899053,1.0665588379,-1.1150864363,1.0701800585,-1.3052628040,0.0422085188,1.9998065233,-1.7469418049,-0.2975669801,0.5028178692,0.8254718781,-0.4733499885,0.4095201790,-0.4338210821,-0.4989029765,-0.9439502954,0.1678249538,1.9921586514,-1.6073846817,-0.8297287822,0.0909254551,-0.6161510348,-0.5609905124,-0.2859306931,0.6985344291,-0.6712636352,-1.4290097952,0.5024514794,-0.6953155994,-0.8284509182,1.5240137577,0.3114162683,-0.5688574910,-0.5349234939,-0.4808453023,0.1530985087,0.2676455081,-0.2223212123,0.1744278967,0.2862839401,-0.6046664119,0.4904140234,0.0750555247,0.7289562225,0.6942309737,-1.0967652798,-0.7154685855,0.4513160884,2.0987625122,0.9161058068,-0.9617047906,-0.0101944050,-0.3066106141,0.0998871475,1.0319311619,0.2301389426,-1.0832765102,1.8243718147,-0.9366260171,0.1783067882,-0.1649248004,1.3017970324,0.6445472836,1.7660093307,1.3376543522,-1.1191633940,-0.1635971516,-1.6489555836,0.0993696302,0.6865174174,0.9365585446,0.2498519421,0.1184616387,0.6225427985,1.2603803873,-1.4978742599,2.1375963688,-0.1365803182,-0.1895365268,-0.2252049595,-0.1031861082,0.4588972330,-0.1754950583,-0.7891124487,-1.4106558561,-0.2436112761,1.3145904541,-0.2643491924,0.2929087579,-0.2023253739,-0.3809172213,-0.2256442457,-0.7095449567,1.6255832911,2.3382439613,0.4938969910,-1.9099097252,0.4098784924,0.9579098225,1.1237193346,-0.0052647912,0.0314161777,-0.2493994832,-0.8705860972,-0.8726430535,0.7882552743,0.7331334949,1.7048001289,-0.8281053901,-1.4328604937,-0.6085548997,1.3891786337,-0.5192667246,0.4646701813,0.1095870212,0.7222380638,-1.0051553249,0.9021429420,-0.3742950559,-1.1925488710,0.6312025785,1.0276609659,-1.8227084875,0.1302038729,0.5725678802,0.7566816211,-0.6131682992,1.6283639669,0.5575514436,-1.5517416000,-0.3973201811,0.3933172822,-0.6209436059,2.2299447060,0.9194506407,0.1127791330,-1.3650295734,-0.3201951385,0.3234144151,0.8839156032,-1.6540412903,-0.6980065107,-0.6564571857,-0.7529318929,-1.6853379011,-0.8302558064,0.9642930627,-0.3338047266,1.1360625029,-0.1617259681,0.8039368987,-0.7213765979,0.9166084528,-0.2778778970,-0.1063275859,0.2079641819,-0.0063563455,0.2102287859,-1.0888133049,0.4468370378,1.1374158859,-0.5253376365,-0.4778427184,0.2243154347,-0.6749815345,1.0322270393,-0.9930639863,-0.4859096110,-0.3069780767,0.4539842308,0.7087320685,1.3813514709,0.0334968083,-1.5020490885,0.2795063853,0.9115028381,0.0795381293,-0.9493045807,0.0057000839,1.8318384886,0.2391988933,-0.2994287610,-0.1245497540,0.3006445765,-0.4049408138,0.0507116504,0.1041309908,-0.4472372830,0.2908937633,-1.3848526478,0.9086578488,0.3378473818,1.4619905949,-1.5845800638,-1.1525335312,-0.6863923073,-0.1426220536,-0.0538095944,-0.9843934178,0.7708935142,0.3634274900,0.7222071290,-1.4486782551,2.1479396820,-0.9167398810,-1.0138820410,-1.2438874245,1.6870024204,0.0624750219,-1.7277748585,1.0282175541,-1.0794452429,-0.9668543339,0.6164269447,1.0389000177,0.6272831559,-0.0910195485,0.3704117835,0.0858492926,-0.6236388683,0.6556786895,-1.1343281269,-0.6852283478,0.4187905490,-0.3736714423,0.4399876595,0.4863699675,-1.2893429995,1.2970787287,-0.9376946092,-0.0708927140,0.4519757032,-1.2560162544,-0.7564775348,-1.2853606939,-1.4764347076,0.0187401716,0.5181655288,0.1931071728,2.0165812969,-0.6870343089,-0.5474315882,-0.9243340492,-0.0350501649,0.4463641942,1.0694886446,-0.3940467834,0.8290531635,2.7378354073,0.6988120079,1.1682595015,1.2565833330,2.2958664894,1.0740492344,-1.1948891878,0.7294963002,-0.8258320689,-2.4308962822,-0.2404142767,0.3294350803,0.5455643535,1.1034344435,0.1110701412,0.3185352981,0.4520530403,-1.4553079605,-0.5798675418,0.3087005615,1.6675961018,-0.4612086117,-0.8659790158,-0.8224008083,-1.1954746246,2.3250622749,-0.0474405810,1.1397987604,0.4894039333,0.6380180717,0.8720409870,1.3701871634,-0.6702001691,0.1365573555,0.8938791752,-2.2082872391,-1.5051922798,0.4718648493,0.4459237456,1.0747903585,-0.3032374978,-1.9131064415,-0.9425461292,-2.1948966980,-0.5122132897,-1.1340646744,1.0650100708,-0.0310556535,-0.3919205070,1.9453985691,-0.9041585326,-1.1375190020,0.5593029857,0.3512958884,-0.2719665766,-1.2004096508,-0.9829906225,-0.5594509840,0.7834479809,-1.0296547413,-2.9886469841,-1.3362042904,1.3961710930,0.0321802497,1.6879734993,-1.9495279789,-1.3146616220,-0.6059178710,-0.1589753181,-1.5342533588,-0.0959366262,-1.0127555132,1.6585209370,-1.0970559120,-0.0442612171,1.0565162897,-0.4931052327,-2.3154871464,0.8893052340,-0.5490179062,-1.0743147135,-0.7600001097,1.4808275700,-0.6100429893,-0.0965769142,-0.1723432541,-0.3031660020,-0.9866677523,-1.1144934893,-0.0944731832,1.2081950903,-0.5706077218,1.4837689400,1.4544682503,0.3421855569,0.5417101383,0.1148955226,-0.1729538888,-0.6006920934,-0.8390375972,-0.8688585758,1.9264659882,-0.5148521662,0.0482680723,1.4802362919,0.0934116393,0.1687042266,-0.5380268097,-0.1822315454,-0.6247577071,1.0951794386,-0.5520597100,1.1341189146,-0.9410278201,-0.6713935137,-0.7394921184,0.4502103925,-0.6198716164,-0.6839472651,0.1225380972,-0.2928015292,0.5678059459,1.3917983770,1.9239299297,-0.2305802852,-0.5392155647,1.9057199955,0.1113132760,0.2179827541,-0.3769581318,0.5038686395,0.5441030264,2.1462361813,-0.1754538417,-0.2272842228,-0.7777884603,0.3594806194,1.0193614960,-1.1204891205,0.9485693574,-1.2363845110,0.6520394087,-0.2308014482,1.6299146414,-1.1982326508,-1.4894257784,0.1250338554,1.6823540926,-0.0901871324,-1.1973161697,-1.0665248632,-1.6871834993,-0.8226858974,-0.2290683836,-0.2399158925,-1.1904006004,-1.1496270895,0.4385099411,-1.4581204653,1.4406924248,-0.3567754328,-1.2256165743,0.6519488692,-1.6003174782,1.6349955797,-0.4684672058,-0.8184659481,-1.4700213671,0.9492305517,0.9033931494,0.0192416534,-1.0961804390,-2.7277271748,-0.6291338801,-0.4750710428,-0.9310365915,-0.4051821530,0.6260236502,-1.2584766150,0.1520262361,-0.5098328590,-0.5226279497,0.5744693875,1.2434821129,0.0292647406,0.1323002875,2.9719250202,-0.2966171503,0.2232382149,-0.8948405385,1.9650298357,-0.4943556488,0.2295539081,1.1664227247,1.3640789986,1.3521430492,1.5934813023,-0.1320769340,1.0461800098,-0.6914286613,0.5779567361,-0.5560915470,-1.5874744654,0.2247067690,-0.3761298060,-0.6025452018,-1.5737394094,-0.8176524043,0.1051435396,-0.5349892974,-0.1311412752,-0.2104492337,1.1861252785,-1.3101953268,0.0564993545,-0.6865065694,-1.7655328512,0.8406751156,0.9682949781,-0.3303029239,1.2768537998,0.5624393821,-0.2575190067,0.1811937392,-1.0224636793,0.0395928435,-0.6465151906,1.3817548752,-0.8498784900,0.9605399370,-0.5322082043,-0.5752568245,-0.2549653947,1.0302226543,0.1062326059,-1.2118384838,0.1191878691,0.0014828539,-1.1837663651,1.0874757767,-2.8219051361,0.3327438831,0.3325736225,-0.9217550159,0.7638429999,1.3450644016,-1.1933127642,0.5198947787,-0.5931326151,-1.2922502756,0.1143693775,-0.0845904127,1.0581725836,0.9305245876,0.4070013165,-0.7341075540,-0.1060848758,2.1465601921,0.1787221581,1.7992449999,-1.2903478146,0.1223225221,1.4852894545,0.2455696911,-0.8079850078,-0.9959421754,1.3645406961,0.8025732636,0.2571508884,0.4182025492,0.7682970166,-0.2245483398,-0.9194589257,-0.4008037746,-1.7039490938,0.7321809530,1.0105509758,0.8314722776,-0.9105592966,-1.0720477104,-0.4215989411,0.7376125455,-2.4036571980,-0.3848825991,0.8627403975,-1.0709260702,0.9025353193,-0.2341202199,1.4916242361,1.0881841183,-0.4007686973,-0.3403339386,0.5308698416,0.7718102336,1.6546257734,2.7061583996,0.3537329733,-0.0448146500,0.1036679819,-0.7673404217,1.4605641365,-1.6149725914,-1.0541573763,0.0763381571,-0.8486981392,0.0386477970,-0.4559693038,-0.8339561224,-0.4026286006,-0.4288522899,-0.3586120307,0.1533448994,-0.1136549860,-0.8437499404,0.6916508675,-0.4252757728,-1.9518626928,0.4714142382,0.5827259421,-1.2929222584,-0.3891405165,0.4851530194,0.5295843482,1.3490113020,-0.5542256832,0.0399686582,-0.6475527883,0.7677624822,0.1303908378,1.0854752064,1.7191438675,-1.0001112223,-0.6612618566,-2.0385735035,0.9662070274,-0.9222030640,0.2547031045,-0.1173657700,1.5544829369,-1.2023463249,0.2614167929,-1.9884563684,-0.0514406934,0.4254758358,0.2848817408,-1.1909495592,0.4748627841,-1.1672532558,-1.2991082668,0.2625207603,-0.2106069028,0.1302159131,0.6869119406,-1.2869962454,-0.4398226440,0.1023867726,1.9681735039,-0.3628941178,-0.3845193088,-1.8106294870,-0.3800882399,-0.3710056543,0.0102245891,0.5141667724,-0.9211145639,-0.1126588136,-1.1501650810,1.9226061106,1.2949194908,-0.2108839899,0.7516497374,-0.6861072183,0.4273181260,1.4809700251,-0.2807698846,-0.6138682961,0.1348924786,-0.1911712438,-1.2088664770,-1.3775349855,-1.5261063576,-0.3294872344,0.9192034602,0.6944690347,-0.2111102492,1.3722932339,1.0175527334,0.1142073944,-1.1281518936,0.5902181268,0.8330125809,0.6166064143,1.2236114740,0.4062391222,1.2697188854,-0.8363413811,0.1143634394,-0.4184566140,-0.3388504982,-0.0837198272,0.2457090765,-0.2588721216,-2.6595571041,-0.2221146077,0.2140495479,-0.8823900223,-0.4630803168,0.2623826265,0.4191049337,0.8740573525,0.9312805533,1.6630910635,-1.1229330301,-0.3988712132,0.3089698553,0.6604155898,1.0093617439,-1.6651716232,-0.7364777327,0.3452317119,-0.4719576538,0.0853512287,-0.6963783503,-0.2385855615,0.4833333492,-0.0953106210,1.8122999668,0.3582427204,-0.7948063612,0.4761179686,0.2154228389,0.6026530862,0.3933068812,0.6928840280,0.2977566421,0.6478030682,1.0729994774,0.4346579313,-0.9511593580,0.9497818351,0.8753393292,-0.3284352720,2.1367778778,1.6212879419,-0.6599621177,0.4766357243,-1.4166018963,0.7105426192,0.1458755434,-0.1393823624,0.1677254587,0.3930626810,0.0387067795,-1.0487891436,-2.1851563454,0.4409761131,-1.3168141842,-1.2756685019,0.4949780107,-0.0053673140,-0.3223702908,-0.6519203186,0.5039027929,0.2957015634,1.2806518078,-0.7631545663,-0.7418268323,1.3974416256,0.4859984517,-0.2325882018,-1.1511465311,-0.0982916951,-0.2832758725,0.0918571278,-0.1249718368,-1.4539741278,-0.2667857409,-0.5932501554,1.5480179787,0.1944077015,-1.2783476114,-0.1039233878,0.2209801972,0.5416983366,1.8491382599,0.7789201140,1.4660717249,-0.7854235172,0.7227502465,-0.0031879030,-0.3045358062,-1.3084830046,0.7555395365,-0.3509569466,0.8722602725,0.2640450895,-0.0512377284,-0.3850245178,0.2748367488,-0.8619273305,-0.5983606577,-0.2911280096,-1.1638661623,-0.1225519106,-1.1247522831,-0.7245661020,0.3172141910,1.0484007597,-0.6781160235,1.6836032867,1.7057974339,-0.7776958346,-0.7127845287,-1.7799401283,-0.9424460530,-0.2567984760,-1.7354787588,0.5987724662,0.6738944054,-0.7204313874,1.4037210941,0.9783397317,0.1899294406,0.8302225471,-0.8875858188,-0.1858076006,-0.8468185663,-1.0604618788,0.0126434006,-1.1486490965,-0.5749979019,-0.4174935520,1.3039525747,-1.1012734175,1.0699433088,-1.4980803728,1.2565586567,0.4683552682,-0.4248012006,0.5665093660,-0.8894879222,-0.9242884517,0.5567165017,-0.2315455079,0.6107094288,0.0718754381,-0.4053229690,-0.1032371223,0.1640097946,0.0202594232,1.6416261196,-1.9592071772,0.7429304123,-0.7617667913,-0.9404531121,-1.0880265236,-0.4952817559,-0.1792133898,-1.0586580038,-0.2037551254,-2.7976267338,-0.2782055438,-0.3884856105,1.4003995657,-0.7439337969,0.1906057298,-1.2973126173,-0.5760190487,0.0010075861,-0.3164952993,0.4198083282,0.5122329593,0.6419844627,1.5902930498,-0.9253531694,0.4934574664,0.1158690378,-1.2287720442,0.8400771618,0.8152031302,-0.9727423191,-0.5200578570,-1.6350430250,0.7669951320,-0.7027513385,-0.2783911526,1.2756760120,-1.0061872005,0.5207966566,-0.1774211377,0.1268888563,1.1396467686,0.2380308509,-0.2564617991,1.5399690866,0.1576723307,0.7258236408,0.9801822901,-1.7694141865,-0.4557214975,-0.4337657094,1.1572785378,0.5312779546,-0.2003088146,0.6846209168,1.2052086592,-0.2296351045,1.1039553881,1.3138203621,2.8796958923,1.0311387777,-1.8142951727,-0.3141567707,0.2261027247,0.5151367188,3.0695443153,0.2548579574,-0.9201954603,-0.3639743030,1.4982109070,0.2461914569,-0.2713237107,-0.9528974295,0.7874175906,0.3267644346,-0.8727814555,0.1782025397,-1.1037790775,0.1650889963,-0.1240965798,-1.1618554592,0.1651325077,-0.6387265921,0.2335938811,1.3918951750,-0.9376947284,1.0478419065,-0.3835449815,1.6917550564,1.0707421303,1.5578179359,-0.4176296294,0.8883716464,-0.0825842023,1.0968365669,1.4495837688,0.3236922026,-0.0004275652,-0.0215025973,0.0394743606,0.8524720073,0.8768084645,0.8922595978,0.2185391933,0.4017852545,0.8576724529,0.8088468909,-0.3175498545,-0.4993957877,0.4370413125,0.0653270409,-0.5538098812,-0.8825448751,-0.1844616681,0.0126108462,-0.5641058683,0.2735268176,0.3900638819,-1.4210958481,1.3800935745,1.7626299858,0.2206579298,0.2094408274,0.1169288829,-0.0439985879,1.6005190611,1.9413633347,-0.9205535054,1.0154896975,0.5654467344,1.1234375238,-0.0849402025,-0.5356362462,-1.8453865051,-0.5912247300,2.3808486462,0.6380431652,-0.0779390782,-0.5372304916,-1.0714815855,-0.9567815661,-1.9812661409,-0.8885300756,0.3465723991,-1.5381587744,0.5294940472,-0.8159481883,0.1816445738,0.5993745923,-0.0688724965,0.4917052090,-2.1673610210,-1.2983940840,0.6069096327,-0.1220805272,-0.3988957107,1.2535202503,1.5654284954,0.2309513092,1.1095582247,-0.2400104105,-0.3079902530,0.2744587660,1.0943692923,0.2639151514,2.7983736992,1.5682145357,0.2655566633,1.0198340416,-0.1856144965,0.0719759017,0.6974091530,-0.3650955856,-1.0268156528,-0.0775278434,0.3819551766,-0.2707291245,0.4601927996,0.1960742921,-2.8733341694,-0.7153529525,-1.5700154305,-1.1252595186,0.8889979124,-0.1681040972,0.4190223217,-0.1275238544,-2.1446073055,0.4539523423,-1.7821577787,-0.7988014817,0.9233134389,0.0920516923,1.9260506630,1.1535536051,0.1917728931,-0.8712940812,-1.3023717403,0.2304571271,-0.2696764469,1.7969834805,-0.2386470139,0.3282249868,-0.6356702447,0.5387446880,0.8461692333,-0.2104572505,-0.8630337119,0.7488220334,0.9744762778,-1.9335272312,0.2642577291,-0.7576102018,0.1086469367,1.0653381348,0.5454222560,-0.3583743274,-0.2401515096,0.8858023286,-1.5596271753,1.0870817900,0.4798313379,0.9968619943,1.0761747360,0.0166343134,0.7263668776,3.0349943638,0.2674559653,1.0315163136,-0.6091318130,1.3296933174,1.1060048342,0.1791629940,0.7824376822,0.3643795848,-0.0688682124,0.3397498429,0.0978621468,-0.6770811677,0.6139251590,-0.5844218731,-1.0284618139,0.8847949505,1.6860802174,-0.1588840932,-1.4511556625,0.9644990563,0.1010972485,0.7338010669,-0.1568467021,-0.9706460238,-0.6732884645,-1.0313397646,-0.8497923613,-1.4788682461,0.7079484463,0.3125767708,0.0050403099,0.4007194936,-1.1395459175,2.0679659843,-0.0851880386,-0.5869293809,-0.4736531079,0.7341102362,-0.3778316677,-0.5041046143,0.6410043836,0.0255725123,-0.6730322838,-0.4380423427,-0.6478739381,-0.0050521214,-0.3049477041,-0.8393627405,0.7373325229,0.3903099298,1.0192760229,0.7384288907,-0.3072429597,-1.5440155268,-1.2261928320,-0.6180872321,1.3727256060,-0.3824479878,-0.0834695697,0.7977703214,-0.7664447427,0.3092956245,-0.8667956591,-0.0599133223,-1.5001881123,-0.5292657018,-2.3725910187,-0.4090963602,-0.3331638277,-1.2272868156,0.8172550797,1.5381202698,-1.1170098782,-0.8876941800,0.1524083763,-1.9791057110,0.3771382570,-0.5076460838,1.2998002768,-0.8550341129,-1.0795487165,-0.1310768127,0.5569698811,-1.9104845524,0.6803012490,0.1322748959,0.3465833664,-1.1199702024,-0.3691485822,-1.7317962646,-0.8497638106,3.6870191097,2.2949135303,0.5006017685,1.6048829556,0.9236067533,0.5055042505,-0.6939823627,1.1900153160,-0.1262883246,2.3308765888,0.1819272786,-0.5119418502,1.1648005247,2.2314093113,0.6448895335,-0.6988681555,-0.0384671949,1.5574637651,-0.6268103123,-0.4058221579,0.4050198793,1.0012731552,0.7926679254,0.1292645335,-0.0604107268,0.3225554526,-0.4775817096,0.8939678073,1.1663762331,-0.5386640429,0.9164229035,-0.1918735504,1.4974851608,-0.6885712743,0.0340448506,-1.2865372896,0.7451160550,-1.6031799316,-0.4937097132,1.3747198582,-0.5014317036,0.8943790793,-1.3215848207,0.5586235523,1.5413256884,-1.4550051689,-0.9163423181,-0.5487048626,0.1736886799,-1.1643437147,-1.8016388416,0.9181058407,0.4756911993,0.0509872176,0.1600379348,0.1163054481,0.5942176580,0.2267961651,0.4649511874,-0.2198812366,1.7069232464,0.0407197364,-0.0010570940,2.6112511158,-0.8208794594,-0.8140652776,0.9350974560,-1.2511539459,1.4331966639,-0.6402844191,0.6937068105,0.5366545320,-1.0673049688,-1.0099349022,-0.7698056102,-0.1967914104,0.4551593065,0.6804695129,-0.2212719023,0.1560983211,0.2077799588,-0.2559347749,-0.6590756178,1.8647357225,1.4707669020,-1.7711633444,-0.0389776789,1.2798991203,-0.2931283712,0.4195695221,1.2389466763,1.4354935884,0.8050691485,-0.7181984186,-0.5427057147,-0.0143227829,-2.0996563435,-0.2624518871,-0.0271753389,-0.4848319292,0.1522143483,-0.3941994607,-1.3695958853,0.8463138938,0.7625041604,-2.6974196434,0.1153355688,0.9856745005,-0.1841914952,-1.1387770176,0.5851966143,0.9297739267,0.7000173926,-0.7721249461,-1.0423361063,0.6085122228,-0.1843611747,0.2995264232,1.6914433241,0.1621672064,-0.6695007086,-1.5838277340,0.1919981539,-0.2652933002,1.2727167606,0.7557719350,1.3111314774,1.0354379416,0.0457438529,1.8368517160,0.5285716057,-0.0358069725,-0.3260233402,-0.0109968940,1.7571246624,0.8397163749,0.0457721874,-0.2342656553,-1.1719472408,0.4112628996,0.4550276399,-0.2209479064,-0.3792432845,-0.5196670890,0.6338948011,-0.4687461257,0.3789885342,-0.6974380612,0.6244715452,0.6647689939,0.1989351660,0.9490326047,0.9538723230,-0.3232532144,-1.2485311031,-1.1898362637,-1.3543343544,-0.1478466094,-1.7027926445,-0.2219823599,-1.3504548073,-1.4105155468,1.4693017006,-0.9841487408,-0.1953340322,0.8112298846,1.3687382936,0.2290214747,-0.8213371038,-0.5722841024,1.8054988384,-0.2536306977,0.0729738325,0.4649703205,0.0422217771,-0.3143117428,1.3984079361,-0.0015608553,-0.5787816644,0.5725606084,-0.3906839788,0.0330548063,-0.5729920268,-1.3764246702,1.0837403536,0.8048295379,1.1178059578,0.9453338385,0.0617002957,-0.6828507781,0.8997985721,1.0651228428,-0.1373525262,-1.5338754654,0.1621236652,0.2117942125,-0.9399450421,0.9874948263,-0.6034541726,0.1361092329,-0.3756698966,-0.0457318723,-0.6480113268,-1.4728063345,-0.3526277840,-2.5419843197,0.2226303667,-0.0023718607,-0.2957418263,0.4968234003,0.7623850107,0.4839349389,0.0289388001,-1.1439795494,1.4620765448,1.2326036692,-0.9133926034,0.4964179397,-1.0620882511,0.7359864712,-2.2167191505,-0.7982082963,2.1331815720,-0.9304955602,0.1575941294,-0.7669993639,-0.3956198692,-1.8070354462,0.3882973194,2.8525314331,0.9374451041,0.9887226820,-0.6674115062,0.2041293830,-0.6884194613,1.2304478884,-0.2918583751,0.3572739363,-0.4392817020,0.7722851038,-0.2283833772,0.2234459370,0.6006508470,-0.5135402679,1.1010036469,0.0592561252,0.9372741580,1.2490446568,0.0454107709,-1.2143180370,1.2831765413,-0.2877854705,1.1066776514,1.7132198811,-1.5615347624,1.2326842546,-0.6733837128,0.5636820793,0.2575648725,1.9115114212,-0.6896926165,-0.9419258237,-0.0117741860,0.1123029664,-0.2908022702,-0.3897866011,1.2393567562,-0.5410919189,-0.0594159551,0.5686154366,1.2410963774,-0.5654718280,-1.1199505329,-1.6332823038,-2.3909821510,0.7570685148,-0.1796463877,-1.0146815777,-0.6059055924,0.8664308786,-1.8528240919,0.6743731499,-0.6671823859,-0.8835974336,-1.0965219736,1.5275717974,0.7300167680,-0.2790175378,0.7463711500,0.1410504282,-0.8136600256,0.7124322653,0.6585643291,0.4684002995,1.6137416363,1.1167794466,-0.6949005127,-0.1380605549,-1.5743788481,0.1458098441,0.1653126776,1.1618109941,1.2810046673,-1.1934560537,0.2221141905,-1.3247392178,-0.9758756757,1.7848703861,-0.4239293635,-1.5496392250,-1.0143722296,-0.9373916388,-0.0033001278,0.4032337964,-0.0522733368,0.5052266717,-0.3572324216,-2.1708812714,-0.8520315289,1.2847210169,-0.5304069519,-0.4453616142,-1.2954775095,-0.3580422103,-1.8790763617,0.9117733240,-0.7384397388,0.3458448648,-1.1715149879,-0.5691010952,-0.3036805391,-1.4098423719,2.2985846996,-1.0172985792,0.4456582069,0.1196669713,-0.1597136408,1.3163573742,0.6440555453,-0.4741426706,-2.1343107224,0.7861979604,1.0434623957,0.1084718406,-0.0941078067,-0.1117874235,-1.9170396328,0.3132521510,-0.3455376625,-0.5181628466,-1.0792073011,1.1498949528,-0.3038112223,0.3882457614,0.5555512309,0.8595563769,0.9541366696,1.4233583212,-2.9718353748,-0.7919180989,1.3287876844,0.6337758303,-2.0233647823,0.1994745880,-0.0833952278,-0.8845870495,-0.2299005687,0.3188984990,0.4911392033,1.5346169472,-0.2562862933,0.3037653565,0.6775609255,-0.2594868243,0.9171200991,-1.1272230148,-0.0771622583,1.9170622826,0.0905564949,-0.1810506284,0.0498206317,0.1376063973,0.8997771144,1.0737489462,0.0820906535,1.3511236906,-2.0293605328,-1.1584099531,0.2168816030,-0.0768081844,-0.5279827118,0.7440552115,2.0216920376,-0.1949700266,1.0104807615,-0.7675292492,0.1056777388,0.4347531796,0.7299080491,-0.7642510533,-0.0106105693,-0.2643010318,-1.8072508574,1.3940663338,0.3064333797,0.4452610612,0.6079790592,0.3127636611,0.5288425088,0.0853652284,0.1245446801,-1.2992873192,-1.6149802208,-1.0670560598,-0.6736964583,0.6929746270,-0.7262415886,0.9602357745,-1.0777587891,-0.2623558342,0.2148114890,0.8735753298,0.0214401037,-1.0976064205,-0.4945487976,0.7895449996,0.2681889236,0.7866907716,1.1217195988,-0.0987510309,0.4238417447,0.6273287535,0.4225327671,-0.8348941207,1.6016408205,1.5246837139,1.4992862940,1.3512203693,0.9674935341,0.0298249535,1.2098042965,0.8318428993,-0.2006926239,-1.1404662132,-1.2379252911,-0.3444960713,-0.5028432012,1.1103632450,0.7753596306,-0.6887470484,-0.8987953067,-0.0610145554,1.9189139605,-0.1576679349,0.0352119133,-1.6327770948,-0.4427270293,0.7562611103,-0.2466283292,-0.0400478803,0.9635592699,0.5934650302,-0.8815698624,-1.0712459087,-0.6394456029,2.0791168213,-1.5084906816,0.1330436021,0.5975986123,0.3697303534,-0.6510151029,-1.2109297514,-1.4117516279,0.4338284135,-0.0864954367,0.0024174221,0.9538350105,-0.4261922538,0.4513969421,1.9549031258,-1.6480233669,-1.2982463837,1.6858726740,-0.8666954041,-0.3963478506,-0.8370561600,-0.6677888036,-0.0802014470,-0.9439086914,-0.4302936494,-0.6549695730,0.2192734480,1.8352367878,1.7390035391,-0.4004605711,0.3200043440,-0.2482670993,0.8343432546,0.9010576010,-0.6557250619,-0.3174437582,-1.4815505743,0.3341366053,1.3810726404,0.3408678174,0.2780138254,0.4463123679,-1.0640423298,0.5948966742,0.9701595902,-0.3354811668,2.1228146553,-0.3853601515,0.8973402977,-1.6078014374,0.4986139536,1.5752862692,1.0740270615,0.5252494216,-0.9065878987,-0.3239499032,-0.8208144307,1.4252241850,0.7748389244,1.6811554432,-0.4814466238,-0.4224803448,0.3014148474,-0.4887431860,0.5419479012,-0.2225292623,0.3341558278,1.3281743526,-0.7061454058,1.1406314373,1.7456609011,-0.3581234515,1.8958735466,-0.9984493256,0.9563930035,-0.5737659335,0.8312965035,-1.0460712910,0.2084058076,-1.1228160858,-0.3064347208,0.0921172574,-0.1723273247,0.2616755962,1.8572127819,1.2639824152,0.0297166966,0.7248386741,-1.0261186361,0.6415510178,0.5504319668,0.0855867118,-0.2484924197,1.0947587490,0.6734647751,0.0738114491,-0.6452680826,1.9789581299,0.3102551699,-1.3629002571,0.0274566971,-0.0190395452,0.2973560095,0.1557310671,-0.1468652487,1.4216049910,-1.3144340515,0.8182174563,1.2978197336,0.6167443395,0.2798875868,-1.1098065376,-0.4280781448,0.2754967213,-0.0831788480,-0.6103398204,0.4578257203,0.8553571105,-0.5358012319,-0.1420752406,0.3383913934,-1.3604153395,1.0594539642,0.6419425011,0.3380404115,1.0207705498,0.6028524637,-1.0487345457,0.3747584224,-0.9873114228,0.5715779662,0.8900516033,-0.3863794208,-0.3268699944,1.1698690653,0.8926932216,0.2617246211,0.1278757006,-0.8974625468,-0.4251092672,0.7840434313,0.2114642859,-0.4872782528,1.1878559589,-0.0447122194,-1.6312956810,0.9626309872,1.5028502941,-1.1069815159,0.5493133068,-0.0670908988,-0.9915824533,-0.5925250053,-0.9678844213,0.6036627889,-0.1400649548,-0.9178651571,-0.0356261842,1.5151066780,-0.1383053213,-0.3510780334,-0.4292304814,-0.5429307818,-1.5706568956,0.1042975038,0.7102490067,1.8552374840,0.3347614706,-0.7081097364,1.1634874344,2.1036181450,-0.7794679403,-0.5313645601,-2.0222191811,-0.6882897019,1.2757804394,0.9143882394,-0.7780158520,1.6167298555,1.0925157070,0.7997589111,-1.6580874920,-0.3671254814,-0.1214561462,0.5333232880,1.8171951771,-0.5902642608,-0.7296072245,1.4643578529,0.6638869047,-0.5257128477,-0.1212170571,-0.9509884119,-0.6017122865,-0.3032298088,0.3008897901,1.7487587929,-1.4716196060,-0.4065019786,0.1656065583,-1.1072632074,0.7372105122,-1.1134939194,0.6655398607,0.5232836604,-1.3998881578,-0.2136789113,-0.3169328570,-1.0540878773,0.0523890071,-0.3415353894,0.2425192446,0.2672145963,-1.0849430561,0.1197969317,1.6511855125,0.8567194939,-0.4198167622,-0.0061530750,-0.2666466236,-2.3022949696,-0.1626988351,-1.1963500977,0.0330941156,-0.2138646841,-1.1792644262,-0.8235653639,-0.5738009810,-2.5206964016,0.9328417182,1.1077494621,-0.1811641604,0.2459245920,-1.6585836411,-0.5189835429,-0.2116440684,-1.9794597626,-0.3549507856,-1.1766176224,-0.1413746923,-0.9840304852,0.2118366063,0.1956791133,0.0256031454,-1.7828342915,-0.9711146951,0.9384088516,-0.9248518944,-0.1011454016,0.3087741137,-0.8797972202,0.3986951411,-1.6176860332,1.1128709316,-2.2385592461,0.6260812283,0.1871027201,-0.0254999250,0.3770545125,0.3706595004,-1.7061337233,0.3555938900,0.3026677072,2.3950519562,-0.8477203250,-0.2803919017,-0.5236788392,1.4797307253,-0.2061602622,-1.2524269819,-0.4490454495,0.3581798375,0.4895872772,1.5629991293,0.8327241540,-0.3907397389,-0.6531038880,-1.0658258200,0.8748501539,-0.7687430978,-0.7552185655,-1.2149530649,1.1354509592,1.5423836708,-0.5928421021,-0.6696397662,-0.8266085982,0.5995821953,1.6138184071,-0.3615201712,-0.8327620029,0.4664305151,0.9396260381,-0.6726012826,-0.3961285055,1.1466346979,-1.1610549688,-0.3767644167,1.1379449368,0.1347682774,-0.0495987386,1.2985827923,-0.7667092681,-0.2375340462,-0.7819229364,0.4346813858,0.9445708394,-0.5190451145,0.9228600860,-2.0988132954,-0.2211748511,0.0915240720,0.5281891823,0.5730536580,0.3545318246,0.9084903002,0.7303026915,-0.6365323067,-0.2045491636,1.2701267004,0.0289865974,-0.0711520687,1.9361691475,0.1886532605,1.2679781914,0.7062788010,0.2168968320,-0.2863503993,0.2347160429,-0.6281237602,0.0405537225,-0.2235246599,-0.2665000856,-0.8118832111,1.4879057407,0.3624395132,-0.2154130787,-0.6729236245,-0.9089426398,-0.1334685832,-0.1044594646,-0.6322259903,-1.7956866026,0.1443674415,1.1078892946,0.1278653294,-1.4188404083,-0.8868185282,-0.3755210340,0.6156448722,0.2973950207,-0.3261060119,0.3075840473,-1.0595344305,0.6999576688,-0.1738804132,1.1124271154,0.0801854208,0.5716896653,-1.0374674797,-0.0721909776,1.9828381538,-1.3460509777,-0.5868654251,2.1197776794,-0.8811689019,-0.5918867588,1.3096985817,0.5816102028,0.6569513679,2.4478139877,0.0861110836,0.5811345577,0.4229134023,-0.3605940342,1.5369105339,0.4504128993,0.3325541914,-2.6560053825,0.0780802891,-0.5812519193,-0.1294345409,0.2331547439,0.5030118823,0.5096856356,1.6935214996,-0.5959262252,0.2305141240,1.0273890495,0.2305488288,0.8759493828,-1.8008491993,-0.7317401171,1.7506126165,0.4269411564,-0.0429548435,-0.1476143003,-0.2250723988,1.7548139095,1.6987363100,0.4552177787,1.5571171045,0.6796240807,0.2440751046,1.0473498106,0.5143606067,1.4031444788,-1.2559754848,2.0805716515,-0.0157355964,0.3213089406,-0.2585878968,-0.9314686656,-0.2365136594,-0.5920739770,-1.4044491053,0.3690233231,-0.7666178346,-0.3709909916,0.2319030166,-0.9386507273,-1.5684202909,-0.9699392319,-0.1636213660,0.1689850539,0.2926900685,-0.6215610504,1.4952127934,0.7245684266,0.4298216999,-0.6791428924,-1.4297268391,0.2240037620,0.8946802616,-0.6121846437,-1.0005315542,-0.9501293302,-0.2909827232,-0.5344090462,2.3198983669,-2.2879838943,-0.9288844466,-0.0034081170,1.0812544823,-0.8310899734,0.8552720547,-1.0219707489,0.2177965343,-0.9733440280,-0.0174913909,0.4193081558,-0.3332124054,0.4880933762,-1.5816885233,-1.4639986753,-0.6394988298,0.2832532227,0.1952934414,-0.8858428001,-2.3023381233,0.0895171762,1.8412590027,-1.1203542948,-0.8483638763,0.2196273506,0.3113439679,0.1000621319,1.1735875607,-0.8860414624,-0.8599038124,-0.6715561748,0.1867471635,-0.2337619066,-1.1266306639,0.9036043286,-0.9000715017,-2.0205488205,-0.9581099749,0.7905055285,-1.2348706722,0.4671658576,0.4668186605,0.3785419464,-0.0996996388,-0.1534485519,0.4217807949,-0.4923402369,-1.4948923588,-0.1059649363,-1.4504761696,-1.2151101828,-1.5624502897,-1.6301554441,-1.0333613157,-0.6717498302,0.1625663489,-0.9796378016,0.2504408658,-0.4498012662,-1.3315489292,0.5227864385,-0.4967396855,-0.7746353149,-3.2565047741,-0.7625097036,-0.2435188144,-1.6264389753,0.2406946421,0.3750441670,-0.5929222703,-1.7938333750,-1.2085139751,0.0064371475,-1.7667037249,1.7038869858,0.4753684402,0.5051966906,-0.2259977311,1.6209121943,-0.4586403966,0.4619432092,0.7081202269,-0.1198732406,-1.9040656090,2.5461783409,-0.5098463893,-0.5149093866,-0.6470791101,0.0598744750,-0.0804928392,-1.1862183809,0.7540088892,0.5231956244,-0.7941627502,-0.5351686478,0.1464129686,-3.2503798008,-0.9900084138,0.0208800603,-0.0939341038,-0.7024986148,-1.4116461277,3.3354561329,-1.6807198524,0.7628878951,-1.1663935184,-0.9231708646,0.5788217187,-1.5420737267,0.3719091415,0.4810803533,1.2950202227,1.1624336243,1.7827768326,1.2083466053,2.1456758976,0.0785913095,-0.7186422348,-2.0778264999,-0.7815722823,0.2554871440,-0.2430197746,0.3738383651,-0.1691911221,-1.5751345158,-0.6850867271,0.9226065278,-0.4163829684,0.2016043663,0.2430605590,-2.0118079185,0.6240944266,0.4783047438,-0.2266190797,-0.0495828427,1.2547620535,-0.7426257133,0.0852039978,-0.3938572705,0.3231543005,-1.2266924381,-0.7905484438,0.7264937758,-0.1436624080,0.6927309632,-0.1799502820,0.7293747663,0.2032651603,0.9094336629,-0.4490212798,-0.5067827702,0.2291303724,1.0174266100,-0.5093548894,-1.4442439079,2.3562941551,1.0144230127,0.8205124140,-0.3604024351,0.5040035844,-0.0327425338,-0.9325399995,0.7155613899,0.1095617339,-1.8171060085,0.1261477470,0.8790358305,0.9427734017,0.8065360188,0.9868785143,-0.6248038411,1.1574034691,-0.4969314933,-0.9548960328,0.2056397945,0.6338357329,0.7086056471,0.3203323781,-2.4203219414,0.5915226340,0.7968711853,-0.7548759580,-0.7817936540,1.4170876741,-0.5229552388,-0.2530987263,0.1287870258,0.1348793209,0.3662788272,0.9481594563,1.5518367290,-0.1748871803,1.5927872658,-0.5910189748,-0.2056038827,1.4960036278,1.5196142197,0.6698520780,-1.1990022659,0.4433546960,-0.9905802011,-0.8024225235,-0.3416491747,-0.1046441644,-1.0017228127,0.4857330620,0.3659887016,0.1782243699,2.0004279613,1.5760009289,1.3417978287,1.2599104643,-0.5527366996,2.0692360401,0.4941767156,2.0470237732,-1.0875812769,0.7576946616,1.7907387018,-2.9291129112,0.8575381637,-1.3554950953,-0.4839210510,-0.0655705929,-1.1057314873,-1.3319424391,1.8408344984,-1.6634352207,-0.4494746327,-0.1036276221,-0.6675081253,-0.5608288050,0.0666391999,-0.5574812889,0.2405882627,1.4979455471,-0.3060584068,0.0120285843,1.6143784523,1.1359167099,-0.9106744528,1.2418780327,-0.9291626811,-1.9791833162,-0.9713079333,0.3243151903,-1.4647428989,-1.2395029068,0.0382350758,0.8031321168,-0.8530051112,0.4882732034,0.8558873534,0.6460304260,-0.5682061315,-0.9189545512,0.8990505934,1.2603000402,-1.0781060457,-0.7336502671,0.8740951419,0.7658302784,-0.2238070220,0.6157169938,0.6769030094,1.2593274117,-1.8752324581,-0.0772253424,-0.2439778447,1.8605688810,0.3804485798,-1.8733338118,-0.5691103339,0.5537204742,-0.6699575186,0.4479410946,1.0299412012,0.7603972554,-0.4966503382,0.3634217978,0.8501811028,1.6847851276,-1.2144894600,-1.4988577366,-1.1940227747,-0.5858005285,0.6833459735,0.4837764502,0.8482929468,0.9312326312,0.5123922825,-0.9934224486,0.7389886379,1.5904425383,0.1515328288,1.8001233339,-0.5165967941,0.6810074449,1.1736761332,0.4009504914,-0.1953288466,0.5581561327,0.1997068077,2.1620819569,-0.0908827558,1.0417481661,1.6549855471,-0.7760302424,-0.3316659927,-0.2115495950,0.5966792107,-1.0887472630,0.2982098758,1.5184670687,0.4310917556,-1.4303095341,-1.6879490614,-0.5256771445,2.3723435402,-1.1201488972,-1.6246181726,-0.7182115316,2.2989356518,-0.7916751504,-0.1085834578,-0.0711057559,0.3724485934,0.3015347719,0.2816698551,-0.5369709134,-0.7400909066,-0.4385055602,0.4664757252,0.7917868495,-0.0000355124,-1.0004467964,2.1101815701,0.9932739139,0.8110388517,1.0303093195,2.1443128586,0.2792387009,0.8437840939,1.1218912601,-1.3918541670,0.4506911635,-2.0793647766,-0.0121497940,-1.0440405607,-0.9657757878,-0.5087488890,-0.0789047405,1.4459255934,-1.5358483791,-0.4629052877,-0.3632760942,-1.0295374393,0.1215865463,-1.5990295410,0.9378693700,-1.1836384535,-1.0631419420,0.6355529428,-2.4377219677,-0.0904419720,-0.4806424975,0.2118658572,0.4217100441,0.1558341831,-0.9841300845,-2.7493028641,0.9413385987,0.3539286554,0.6233276129,-0.9138478041,-0.5024273396,-1.6548289061,1.0006732941,1.9455966949,0.0933097750,-0.1363495439,0.0907459259,0.0056755515,0.3079532683,0.9652287364,-1.1859726906,2.0238280296,0.2781577110,0.5562726259,0.7591621280,-0.1311170906,0.9709328413,-0.8000256419,-0.3964389563,0.3583988249,-1.2603985071,-0.6288074255,0.1997476220,1.5333764553,-0.9561508894,-1.1526873112,-2.0702159405,0.2626678348,2.6558797359,0.3057968020,-0.0556512699,0.4347166121,-0.2524664700,0.5330020189,2.1679821014,-0.0680899248,0.0938287526,0.3151662648,1.3177949190,0.2194497287,1.4449121952,-0.2030343860,0.3360009193,-0.9564311504,-0.8714737892,1.4866508245,0.6670100093,1.0294823647,-0.8069849610,0.7517868876,0.6363819838,-0.2490818948,-0.2208531499,-0.7862807512,-0.0412395597,1.8023437262,0.8893542290,0.8283433318,1.1427662373,1.0990648270,-0.1380199790,0.0603353344,-0.6218895912,0.6183639169,1.6191837788,-0.2276409566,-1.7644103765,-1.5434100628,0.5247124434,0.5242751837,0.7079523802,0.1106121019,-0.4096989632,-0.9592539668,1.7692834139,-0.4390759170,0.9115946293,3.0482261181,-0.0887733400,0.4471243024,0.1182788983,-0.0481228195,0.2647619545,0.1651706994,-1.0986613035,-0.2626098692,0.8710223436,0.2023158371,0.0185922198,-1.6146917343,-0.7584802508,-1.8991247416,0.1000484303,0.0444046557,-1.0100754499,2.0759148598,0.6520631909,2.0937871933,-0.1748518348,-0.0945110694,1.4562783241,-0.3171853125,-1.3235573769,-1.0152374506,-1.1026420593,0.2675947845,0.6974791884,-1.4816414118,-0.5089939237,0.8205317855,-0.6032758355,1.1610811949,0.2848510146,-0.2113544494,-0.0693584830,0.4601627290,0.2715222836,0.3543163836,1.1241178513,-1.0009111166,0.4233255386,0.8821615577,-1.2673573494,1.0599933863,-1.9858329296,1.7473354340,-0.8925181627,-1.5392049551,0.3679618537,-0.9061989188,1.6234297752,0.3026809692,-1.2521638870,-0.9746393561,-1.6885068417,0.1270830184,-1.1797159910,-0.1793961972,-1.6843693256,1.1783792973,1.2475259304,-0.2204871029,0.7822663784,-0.7288885713,0.5897322297,1.5894587040,-2.0798897743,-0.9088625312,1.0042586327,-0.4040690362,1.0435874462,1.0213680267,-0.5034691691,-2.8381204605,0.5957017541,-1.7376792431,-0.3987622857,-0.5514874458,-0.3678982854,-0.1919072121,0.9552351236,-0.2671971619,-0.7120574117,0.7922269106,0.7821462750,-0.8510670066,0.4528163671,-2.8724989891,-1.7404062748,-0.0358726680,-1.0349525213,0.9958155155,0.7042294741,1.8772702217,1.2644282579,0.5117878914,-0.7683165669,-0.3760642409,0.3992835879,-0.6319594383,-0.1234124750,1.3657724857,-0.4243614376,0.3409079909,0.8824703693,0.3096629381,1.1415899992,-0.3601651490,-0.4110813737,1.4603716135,0.2897032797,-0.6120595336,-0.6877930760,-0.0798668489,-0.9543554783,1.1657077074,-0.7224388719,0.5840330124,-0.4707277417,0.9872319698,-2.4506506920,0.0268113595,-0.4014832675,-0.9910459518,1.8364913464,-0.1808601767,-0.6913096905,-0.4763865769,-0.8570129275,0.6800124645,0.2375830114,0.2993802130,0.6163609624,1.0929050446,-1.2402175665,-0.9390913844,-1.3111484051,1.5088058710,1.3480857611,0.5016481280,-0.2476610988,0.7036614418,-0.0966909081,1.3176031113,1.0656447411,0.2396778166,-1.9526786804,0.8595772386,-0.2595057487,0.9080550671,0.0765460432,2.1173491478,-1.0088042021,-1.7454794645,1.2033076286,0.4952604175,0.1535671651,1.0042064190,-0.2208959013,0.5841389298,-0.3922788501,-0.3614006042,-1.8522236347,0.2663365901,-0.4901424944,-0.7449171543,-0.3399548233,-0.3400003314,1.3681870699,1.0906018019,1.0649048090,1.2599071264,-0.1997389942,-1.5190547705,0.9784672260,-0.8858841658,-0.7331888676,1.7371307611,-0.9528511167,1.2391638756,-0.6803607941,-0.8854863644,0.5288819075,0.0407255515,-1.7051877975,-1.1911907196,-0.6170998812,1.8401297331,1.2869774103,0.7416225672,0.1012784541,0.9506714940,-0.6890847683,1.1691758633,0.2125397325,-0.5651474595,1.1363813877,0.3282095492,0.2325947732,0.8333733678,-0.3224644661,-0.0435054190,0.8779395223,-0.1092095077,-1.3758436441,-0.8854057789,-2.1870152950,1.4359880686,-0.5213032365,0.3130353987,-0.3004281521,1.5077716112,0.7161954641,0.4850605428,-1.3312293291,0.1999393255,0.7143920064,-0.2711220086,1.0470339060,-0.5351563096,2.1122450829,2.2901554108,0.1676862389,-0.3756659031,0.2262535393,-0.4149861634,0.7650973797,-0.7531386018,1.2070817947,1.2787936926,0.1595245451,0.1642178148,0.2609710991,-0.7997441292,-0.1890465617,0.4980888069,-0.8788653612,-1.4926164150,0.2842349410,0.1910644174,1.9113937616,1.1137232780,1.0943866968,0.9748689532,0.8634682298,-0.2590862811,-0.0192987844,-0.8789740801,-0.7913516760,0.6180747747,-0.7121517062,0.3878835738,-1.3793500662,-0.1918176562,0.0958151296,3.1094701290,0.3986200392,0.2136057466,1.1821939945,-1.1471401453,0.8588299155,-2.0046691895,-0.1928652674,-0.6466591358,0.0150989927,-1.0306770802,0.9040096998,-2.1417479515,-2.7447814941,-1.1748067141,0.5511487126,0.0278319884,0.3978701234,-0.4533764422,0.6338236332,0.2078187764,0.6372888684,-0.6748731136,-0.1286127865,-0.5645707846,0.4383159578,-0.7623828053,0.7904329300,-0.1006841809,-0.4627493024,1.0368299484,0.4300449491,-1.7973104715,0.7144021392,-0.4045287371,-0.8542004824,-1.1299022436,0.7849571109,1.1772171259,-0.8059206009,-1.1383796930,0.4343900383,-0.2633340955,-0.4062776566,0.1033182815,-0.5581795573,-0.0883774608,1.0320638418,1.4132361412,1.6514214277,0.1695428044,0.2159408629,0.8343988657,-1.1636316776,1.0585942268,-0.1515603811,0.8289833069,-0.0556437746,-1.2486417294,-0.3393330276,-0.3956955671,-0.1733885854,-0.6103331447,-1.6589229107,-1.3826439381,0.8436100483,1.1876813173,-0.5175749063,-1.0741704702,-0.2104587704,0.8762942553,-1.0773400068,-0.2500136793,1.3766224384,-0.4211629629,1.6774389744,0.4335694313,0.1595920026,0.7415378690,0.6724870205,0.3878264725,-2.0489420891,0.8812448382,0.1120989919,-2.1312644482,-0.3068031967,1.4072669744,-1.8038721085,-1.9736406803,0.0415054634,-0.0308436342,0.9076535702,0.3400208652,-2.2132844925,2.3224930763,1.3219075203,2.3032946587,0.6108966470,-0.1145442501,-1.5732045174,1.1812853813,0.2263955772,0.4435280859,-0.4413294494,-0.2191576660,-0.4763602614,-1.1287884712,0.9238072634,-0.2126406729,-1.4508607388,-1.0319195986,0.1644870937,-1.5002006292,-1.2616881132,-1.5085011721,0.1622222662,0.4869650006,0.5460504889,0.1898836493,2.0961461067,-0.3474938273,1.8628062010,-1.1646004915,-0.9452017546,-0.5434473753,0.2812504768,-0.5410401821,1.7726508379,0.5803670883,1.0367780924,-1.6005064249,-3.0092163086,0.1392125040,2.4194037914,0.3260611594,-0.9767702222,0.5747098327,0.1420334429,0.2335471809,-0.0718801618,1.0421361923,0.5592299104,0.5113453269,0.2498618364,-0.9558623433,-0.3218068182,-0.1402815431,-1.6505886316,0.0835994780,0.9163863063,-2.8156573772,-0.7224086523,-0.2607764006,-0.7745448351,0.7839495540,-0.7016636133,-1.2114204168,-1.3935538530,-0.1395538896,-0.5087388754,0.8473874331,1.3882595301,2.1699202061,-0.2208291292,-0.3559795022,-0.7718069553,1.0199204683,-1.1986038685,1.2818330526,-0.8575738668,0.7588049769,-0.3571656942,-0.8376092315,-0.1244146153,1.0222516060,-0.2545220852,1.8373160362,-1.4680243731,1.3336762190,0.2705392838,-0.7611726522,0.6549308896,-0.0792744756,0.9494455457,1.1246320009,0.0557211973,0.8274643421,-0.0141875586,-0.4157760143,-0.2442740798,-0.1689703465,-1.4288641214,0.2172202319,0.7753660679,0.6355167031,-0.6720003486,-3.3398942947,-0.3721321821,0.7748588324,0.2912347913,-0.0677062869,0.2498321682,-2.0455522537,0.3599575460,0.8134485483,-0.7892555594,-0.9455010891,-2.1506998539,-1.1472947598,1.6073971987,0.3767109215,-1.2686046362,-0.3529419899,2.0551450253,0.9534871578,-0.3973580897,-1.4923707247,-0.5456050038,0.0431090258,-0.2758043110,-0.2455203533,2.1469547749,-0.9647199512,-2.1054956913,-1.6152031422,0.6804012656,0.7725505233,0.6639801860,-0.5187103152,-0.6598019600,-1.0491077900,-1.5657329559,0.5533331037,1.2845594883,1.1052020788,0.9238629341,-0.4194052517,0.5052201748,0.6276740432,0.4903647304,0.5449354053,0.8436488509,0.5930407643,-1.2337615490,-0.7152583599,-0.7161428332,-0.5219246745,1.1452192068,0.6020815969,-0.6623034477,-0.3540771306,0.2188376784,0.2990494668,-0.3308923244,0.3350869715,-0.0748877674,-0.0690385029,1.8809734583,-0.6586229801,0.3756047189,0.4063786864,0.9886311293,-0.9031563401,-1.2128840685,-0.5440398455,0.8093140125,0.1141676530,-0.3551281095,-1.1269905567,-1.5992106199,-1.0362365246,-0.3802249730,-0.0893609747,-1.0580019951,1.2933925390,-1.9946708679,-0.7844277620,1.2969027758,0.4970777929,0.8003904223,0.2300457060,1.2736281157,-1.0021532774,0.4828888178,-0.1670626998,-1.8273473978,0.2340641320,-0.6276967525,-1.6696863174,0.0048749070,0.9814209938,0.6604838967,-0.5587424040,-0.5823022723,0.1978456527,0.8078650832,0.8510124087,-0.6664382815,0.8562269807,-0.6985203028,-0.3025896847,-0.7559245229,-1.0003705025,1.5326434374,-0.0137318987,-0.6858326793,-0.3156582415,0.4162408710,-0.6101112366,0.4867403209,-0.3826802969,-1.2199368477,-0.4200175107,1.0042294264,0.3964896202,-2.3662467003,0.9675166011,-0.3118633628,0.0873739272,-0.4918978512,0.6635258794,0.3169205189,-0.3862748146,-0.7754532695,0.7976115346,-0.9872649908,-0.9692402482,-0.2291807681,-0.7056533694,1.3953976631,0.3147648871,0.4875667989,0.6540688276,-0.9398791194,0.7224289179,1.1777349710,-0.9915122390,0.9375629425,-0.5861776471,0.4290914237,-0.8124514222,-0.2063853294,-0.9410168529,-1.1546858549,-0.1660162508,-0.2981323004,1.5257365704,-0.6887041330,0.4322051406,0.0187902357,0.3851979673,-1.5070592165,-0.0877329856,1.6083472967,-0.7919498086,1.7719179392,-0.5008546710,-0.7702132463,1.5552997589,0.0259561371,1.3426429033,0.0170335490,0.5972861052,-0.3192002177,0.6835110784,0.4572851360,1.8811956644,-2.5470488071,-0.4798873067,-0.4972526431,-0.4892331660,-0.7172479630,-0.0641170889,-0.0721785799,-2.2250163555,-0.7003098726,-0.9463029504,0.5387721658,0.1171965152,0.7794079781,0.9873548150,-1.2788540125,2.0102021694,0.1099134684,-1.4208669662,0.1849313974,-0.2944383323,1.1591405869,-0.2540302277,0.5338650346,2.5842995644,0.4451530874,-0.3505676389,-0.1859664619,-0.1787521392,-0.0542083494,1.6706476212,0.9630910754,0.6391386390,1.6442874670,0.0071885237,-0.5470194221,-0.0029828497,-0.0276721809,-1.6777534485,-0.8231400847,-1.2297281027,-0.7362014651,1.1312052011,-0.3959090114,0.2928639650,0.0256736502,-0.9436841011,-0.8668084145,0.1719511896,1.7600250244,-0.3097595572,-0.7261739969,-0.0894311666,2.0879607201,-1.0827295780,1.1696344614,-1.8928852081,-1.4066766500,-1.6461080313,0.0934822261,-0.0529018976,0.1754294932,-0.4250826538,-1.6005401611,0.2298563123,-0.5026178360,1.5759580135,1.0479354858,-1.3923493624,1.5411509275,0.5450043082,-1.5957812071,0.0078355968,-1.0235074759,1.4455271959,0.2516079247,-0.0059909956,0.5103890896,0.6152398586,-0.1133571044,0.0452356748,0.8750831485,-1.5508222580,-0.8830829859,0.2080126405,0.0176873859,0.0009350795,0.3643147647,-0.3425868452,-1.1389331818,0.2679989040,-0.2351417392,-0.3743028641,-0.2967391312,-0.3949703872,-1.2074548006,-1.5331141949,1.0537494421,-0.6973699331,-0.3979943097,0.9710779786,0.1486331820,0.7276759148,-0.3589974344,0.1361308545,0.5942563415,-1.1173524857,0.1162814796,0.1708787680,-0.9081650972,-1.2323310375,-0.2043872625,-0.9505392313,-1.7209446430,0.0769074261,0.3739518523,-0.9559456110,0.6215204597,0.5835911036,2.1823852062,-1.1971487999,0.4832358956,0.6317840815,-0.8399761319,-0.8457883000,-0.2453269064,-1.3662616014,0.2259954810,-0.8711085320,-1.0088886023,-0.0795122460,-0.2749667168,-1.4504717588,-1.1735156775,-0.1123355925,-1.2269114256,-0.8250812888,0.0331604481,1.8441269398,0.6902368665,0.6502194405,0.4802848697,-0.4361600578,-1.9481081963,-0.9514036179,-1.0143113136,0.4540541172,-1.0325177908,-0.1135502532,0.8384748101,-0.1321249306,-1.8348624706,-0.9096595049,-0.0661195368,-1.1773709059,-0.2655218244,-1.0226361752,1.7931406498,-0.5638654232,-0.8700715899,0.1031277925,-0.3818658292,0.9453787804,0.2722228169,-0.4883063138,-0.7425808311,0.3954738379,3.5413982868,1.1422576904,-0.1177065670,-1.3207576275,-0.4200673103,-0.9338312745,0.4874849916,-0.7146152854,0.5772513151,-0.2517969310,-0.5349732637,0.9662621617,-0.6398757100,-0.2928552926,0.3574216366,-1.0193123817,-0.5647442937,1.3439898491,0.9467440844,-1.8994320631,-2.3763782978,-0.0155165065,0.9333648086,1.2560585737,-0.5713263154,-1.1139186621,-0.6125965118,-1.5679283142,2.0549027920,-0.7713843584,-0.5557987094,-0.5585767031,0.1265952587,0.9497575760,-1.6862744093,0.4159049392,1.6351566315,-1.0996099710,0.1305427402,0.2132267654,0.2193509191,0.1171146780,-2.9186856747,-1.6857429743,1.2380404472,0.1488410085,-0.5628337860,1.2209196091,-1.0582157373,-0.4046570361,0.1282916665,-0.8336083293,0.6628674865,-0.6343099475,0.4895289838,-1.5728354454,0.1174273640,-1.0989309549,0.7623879910,0.6364852190,-1.3394111395,-0.9577367902,1.2531023026,-0.0068191397,-1.0997195244,0.5822053552,-0.8811379671,-0.9198532104,-0.0741320997,0.0454016849,0.2210511118,-0.3389450312,0.2945863605,1.6904438734,0.2295662761,0.3174210787,0.8400560617,-0.5025610328,0.4230135083,2.0097754002,-0.6062899828,-1.3862564564,-1.6698477268,0.5712623000,0.1846959591,1.3817620277,-0.4764849842,0.0659929290,0.3075664937,2.1360414028,-0.3807438016,-0.2041121721,0.4065637887,-1.4117066860,-0.2051517218,0.6111496091,-0.4619669914,-0.3576725721,0.0207850803,0.5707749128,-0.5527526736,-0.1327189803,1.0202493668,0.6725012064,-0.1995927095,0.4116949141,1.3201146126,-0.8511425257,-0.4216827452,1.0985009670,0.5239596367,1.6738646030,1.0952597857,-0.4176313579,0.6746681929,2.0459949970,0.9361134768,0.5849192739,-0.8187872171,-0.8112853765,0.6149257421,-0.0066334433,-0.8003438115,0.0657561496,0.3939533532,0.1361585706,-1.2089350224,-0.2615604103,0.9463102221,-1.8061428070,1.6406424046,1.3682647943,0.6324747801,2.7865254879,-1.1303302050,0.3894205093,-0.0782135278,-1.0114086866,-0.6274721026,0.5245721936,-1.5063163042,-1.9922429323,0.3584777415,0.5166468620,-0.1857368648,-0.8542599678,-0.9650046229,0.4234408140,-0.3074883819,-1.7931255102,-1.5989216566,-0.3567943275,1.4546153545,0.6844121814,0.5107967257,-0.0391141847,-1.4022755623,0.3946054280,0.6230074763,0.3575500250,0.6456065774,-0.8244645596,1.6284826994,1.3106117249,0.5425267220,-0.0468281060,-0.1053166837,1.5829575062,2.1437420845,-2.6331455708,-0.8834359646,-0.0580697283,-0.2573893964,-1.0412811041,-0.9003218412,-2.2390277386,-1.4651108980,-0.1499534696,0.3560865223,-0.8711300492,0.4428383112,-0.7426754832,1.9199404716,-0.1389176399,0.8840380907,-0.0846645460,1.1519436836,0.6512896419,0.4417738318,0.5237726569,-0.0788306445,-1.0378000736,-0.0144220442,3.2748272419,-0.4563313723,0.1812780350,1.0921074152,-1.0814076662,-0.7821266651,-0.3949780762,-0.3073712885,-0.4651679397,-0.1078325585,0.8263167739,1.2388310432,-0.0984496921,-0.9567881227,-0.2131212503,0.4681727588,-0.8755455017,-0.3477372825,-0.3609948754,0.2883796096,-0.1543822289,1.0686825514,-1.2054982185,-0.2616977692,-0.2440364957,0.3487615287,0.3591597080,0.8647454381,0.0454029441,1.3971421719,0.4091089666,-1.1374706030,0.3737558722,0.0758722574,-1.3365100622,0.3250429630,-2.3053030968,-0.0668937638,-1.0083193779,-0.7527424097,-0.0073583261,0.4523725808,1.3834358454,1.5274974108,0.5206997395,-0.1829435676,1.9268072844,1.7041747570,1.2395449877,0.8001048565,-0.6456826329,0.1719383746,-1.1980223656,0.1657909304,-0.3878783286,0.1869106740,-0.5592908263,-0.5458331704,-0.7450099587,-0.0316931196,-0.0618060678,0.3835448027,0.4217584133,1.1206994057,-0.4465995431,1.7511516809,1.3176025152,-1.5822561979,1.2087854147,-0.0655139759,-0.2714920640,-1.0172853470,0.8885841370,0.6089287400,0.7097648382,-1.0400695801,0.7560692430,-0.1527360380,-0.0720087662,2.0048029423,0.9776907563,1.8429362774,0.5951318145,0.9638172984,-1.4097329378,0.9143978953,-0.6318609118,0.3108898103,-1.0307670832,1.5938689709,0.1314638257,0.1371712685,2.2998940945,-1.1544933319,0.9436885715,-0.1268677711,2.5043098927,1.9020754099,0.0107692750,-0.6744157076,0.4011289477,0.3623802662,1.7662875652,-0.9019196033,0.2089881748,0.7885096669,0.1734537929,1.3288722038,-1.6579455137,1.5910657644,0.4592954218,1.3853743076,-0.4122804701,-0.6964764595,0.1028952003,-0.2327424735,1.3980441093,-0.2943899035,-0.1668646485,0.7435558438,0.1972083002,0.6509979367,0.2048090845,0.6409730315,0.0838581249,0.9075406194,-1.0100653172,-0.8159732819,1.1770539284,-1.1766952276,-0.4897406101,1.5740053654,-0.5039058328,-0.0056537632,1.2350809574,1.9353353977,0.7992894650,1.1764726639,0.5102623701,0.1331552863,1.6801360846,-1.4638708830,-1.4318088293,0.7316586375,-0.0776355043,0.1326100230,1.3219194412,-1.2926105261,0.5352171659,0.2413900346,-0.5880570412,-1.6252239943,-0.2039538324,-0.2277193218,-0.7866405249,0.4781764746,-0.2251786292,0.4531523883,-1.5962477922,1.4734230042,0.5247167945,1.3522722721,0.8866689205,1.1717010736,0.4088672400,2.3660075665,0.4089567363,-0.2065753043,1.2208466530,1.6604276896,-0.8562346697,0.3405393362,0.0647998601,0.8287518620,-0.6682997942,0.9128044844,0.8960058093,-0.5783953667,-1.8637040854,0.9895142913,0.1827133447,0.3518616557,0.5791466236,-0.6660627127,-0.6760500669,0.2832719982,-0.3868727982,-0.6564489603,-0.5221094489,1.2264560461,-1.3206096888,-2.1526074409,0.3476690948,0.3220793307,-0.7065263391,1.2328867912,-0.0474791229,0.6002050042,-0.6559346914,-1.1499810219,-0.2271601856,0.0775771588,1.4095139503,0.3245908320,-0.6881970167,-1.1337358952,-0.4698321223,0.0208422132,-0.2039146572,0.6458313465,-0.1945850253,-0.2234966606,-0.4036347568,-0.1006233916,-0.5893812776,-0.3851362467,0.6804109216,-0.2284515202,1.5971822739,-0.5365006924,0.3082237542,0.5073539615,0.1667853743,0.5216529369,-0.5112001896,-2.3981661797,-0.5508834124,-0.4447124004,-0.1626759470,0.1065026373,0.2490579486,-0.6605647802,0.1807012260,0.9926020503,-1.1432589293,-0.6874733567,-0.0878316462,1.0072650909,1.5095521212,-1.6570911407,-3.3662109375,0.3644823432,0.9877869487,1.3811259270,0.1469745040,0.6534839272,-1.9952636957,-0.6510771513,-0.7774798274,1.4520498514,0.2092368752,0.4919971526,0.1677229851,0.6899916530,-0.3618898690,0.2964192331,-2.1922900677,-2.8469946384,1.2499256134,-0.3056958020,0.2330211699,1.8649996519,0.6184995770,0.0053699506,0.3032593131,1.4434729815,0.7936376929,0.1969661117,-1.3081755638,-1.2562611103,-2.0427565575,0.8932399750,-0.4132222235,1.3045953512,-0.9867917299,0.1995005459,-1.7860189676,0.7441645861,-0.3486237228,0.0734504163,-1.0310095549,2.6190226078,-0.2775891423,0.9633615017,1.5110583305,-0.8518043160,-0.3761514425,-0.1686878651,0.2582244277,-0.1115956157,-0.7016026974,-0.4886007607,0.2954337895,-0.7916867733,-1.0443811417,-1.2603008747,0.9914335608,-1.0003927946,1.2466765642,-2.2859148979,0.9926853180,-0.6228358150,0.2328247130,0.1546843797,-1.4545462132,-0.3578131497,-0.7590592504,-2.1569862366,-0.8818256259,0.6978793740,-2.1174297333,0.7130247355,-0.3263854086,1.4276014566,0.9877415895,0.5409177542,1.0951485634,0.1220243201,-1.7321188450,0.4447348714,0.6616247296,-1.3816518784,0.8129363656,-0.5154392123,1.1574823856,2.6286344528,-0.5050146580,3.4021975994,1.4216302633,-1.0183618069,-0.3884378374,0.8395509124,-0.2105975747,0.4740676880,-0.0842759758,-1.9411085844,0.4352273345,-0.1354239732,-0.9024779797,0.7749136686,-0.4862678647,-1.8972977400,-0.4917300045,-0.0748297572,0.9854032397,0.2509278655,0.8058610559,0.1157606617,0.7863579988,1.4600559473,1.1236486435,2.3348710537,-0.5767028332,-0.6702319980,-1.2023346424,0.5142666698,0.2149520069,0.6355566382,1.5429649353,-0.2103935927,0.3804515302,0.6273841858,0.3169680238,0.3265507519,-0.3104707897,1.5206472874,1.2834477425,-1.0403629541,-0.7318644524,-0.5680179596,-1.3175101280,0.0111222519,0.0148605723,-0.0837772042,-0.1081169844,-1.1673394442,0.5008950830,-0.8864564896,0.4724477530,-0.0436774604,0.1715297550,-0.3525592387,-0.9352099299,0.3690447807,1.9065877199,-1.3537904024,1.1824322939,-0.9419884086,0.1806846112,-0.2388978302,-0.4788640440,0.9938432574,-0.4293144345,-0.9021407962,-1.0721393824,-0.3390442729,-1.4578844309,1.4132852554,0.5697637796,-2.3599929810,-0.2966747582,0.9824299216,-0.3056213856,-1.2084267139,-0.4508726001,-0.6144681573,-0.2360159010,1.3597880602,-0.6465095282,-0.3063315749,-0.3036143482,-1.1422830820,-1.6548137665,0.3659083247,-0.6401305199,-1.0536401272,0.8842850327,1.0639809370,-0.7625054121,0.7067868114,-1.8095438480,1.6055014133,1.9578210115,-0.0146530466,0.1607527882,0.0634327382,0.9684318304,-0.6058360338,1.0671213865,-0.1546684355,-0.4690584838,1.0974758863,-0.3586915731,-0.5239579678,2.1667027473,-0.6392484307,-0.5902347565,-0.5282523036,1.4030483961,0.5651695132,-0.2470132709,-1.3528504372,0.7387406826,-1.3053969145,0.4459773898,0.6248256564,-0.4102109075,-1.4706453085,-0.1719833761,0.6154183149,-0.1918688715,0.7560840845,0.2232549936,-0.4626301527,1.8654347658,0.4972397983,-1.4983967543,2.1595275402,0.4665803611,0.0884945244,-1.1619651318,-0.2765117288,-0.1715537906,-0.3518653810,-0.9461241961,-1.1457321644,1.2026308775,2.4595475197,0.4014116824,0.6902657747,-0.2663109899,-1.3605632782,-0.5054963231,-0.4462118149,-0.6951832175,0.6664215326,-0.1848514378,-1.6823832989,-0.3947536945,-1.2504912615,0.6512746811,0.1747264266,-0.0348788761,-1.1168770790,-2.1164686680,-0.6573825479,-0.4557669163,0.4483180940,-0.3280870020,1.1538000107,0.6581790447,-0.1787044406,-0.6257719398,-0.2563052475,1.0647335052,-0.6776366830,-0.0441894680,0.8303117156,-0.6585288048,-1.7951769829,-0.4860822260,-1.2639374733,0.8270537853,-1.5556081533,0.4140720665,-1.3718259335,-0.4767510295,-0.7637899518,0.2245294452,-0.2684869766,0.9843692183,-0.5093818903,-0.8165298700,-0.0653958842,1.1830229759,-0.5425726175,2.0562729836,-0.5610432625,-0.5977123380,0.9381351471,-0.2507341206,-0.3926568329,0.6979966760,-1.9392474890,-0.5521243811,-0.9458277822,-1.1004375219,-1.6574097872,-2.4388780594,0.7281301022,1.3262432814,-0.3952213824,-1.2761065960,-0.4463176131,-0.1996756494,0.0460203737,-1.8395447731,0.8358345628,0.0776033774,0.3844222426,0.2353907377,-0.5447943211,0.9198400974,-1.0590447187,-0.7494023442,0.7968676686,-0.1726324707,1.8498902321,-0.1682839394,0.1879395097,-1.7048875093,-0.4969268739,-0.1124747172,2.0928378105,0.1882959604,-0.1514537334,2.7660396099,0.4743964076,-0.1937914789,2.7596483231,-0.7834467888,1.0347872972,0.0152278300,-0.7610386014,-1.9078309536,0.3805552125,0.3727011681,-0.0694252625,-1.4736522436,0.2938594818,1.3245332241,1.7787688971,-0.0070120962,1.6617984772,0.8333523273,-1.7519874573,-0.2134312093,-0.0100032743,-1.4998146296,-1.8115137815,0.9965004921,-0.3041839004,0.4738995433,-1.0041937828,0.5569674969,0.8938269019,-0.8305382729,0.0593917184,0.3627528250,-2.4793670177,-0.0537039153,1.3435860872,-0.1680946201,-0.2323862910,0.3036299050,-0.5398108363,-1.0809445381,0.3632449210,0.6647271514,0.7428128719,-0.1369682550,-0.0496443063,-0.1413195878,0.9341860414,1.8201687336,1.4392632246,-0.4426941872,0.5988597870,-1.0540181398,1.5845466852,-1.8445963860,-0.6951264143,-0.7396306992,0.6659613252,0.5334790945,-0.1635098904,0.0039233668,-0.6267506480,-0.6743814945,-1.3609571457,2.2019507885,1.0629549026,-3.3453154564,-0.4029050469,0.1154041514,0.7916713953,-1.0441731215,-1.8813159466,-0.8272339106,-0.0320983604,-0.6287982464,0.2015765011,0.4855963588,1.6028063297,0.8580584526,1.3570153713,0.7573254108,-1.0525548458,-0.8210426569,-0.3900167942,-1.5697445869,-0.6533695459,-0.0810939893,0.5408882499,0.7513781190,-0.4506444633,0.9149255753,1.4994388819,-0.0303670596,1.0417119265,-0.2023945749,0.8270350099,-0.1792833060,-0.0137997605,-0.6589713097,-0.3070053756,0.0456016734,-0.0929416865,-0.8315680623,-0.9879750609,-1.9678112268,0.4647029638,0.3763283193,1.1709362268,0.8068950772,0.3331092000,-0.2832021415,0.1535404325,0.0047497978,-0.6976765394,0.0749599189,-0.1627242714,-0.6791628599,0.5772633553,1.5324664116,-1.1410440207,1.7173656225,-0.3408393562,0.9652553201,0.2716450393,-0.7487616539,-0.1968285292,0.1606321335,0.6696608663,-2.2959189415,-0.8271072507,-0.0054756412,-0.2375295013,0.0163776018,-0.8759958148,0.5110145211,1.9992854595,-1.2928618193,0.5799829364,-0.7743336558,0.9561066628,0.0935266614,0.3667050898,-1.1060663462,1.1112999916,0.8064696789,-0.7583508492,1.5314108133,1.2391928434,0.0666859671,1.9098252058,1.2984734774,0.4810087383,0.2941254973,-0.0169484559,0.4986978769,-0.3291710019,1.6480085850,-0.9981449246,0.5191267133,-1.3664671183,0.2130313367,-1.1082155704,-1.0726953745,0.0305134151,-1.2059307098,0.3432687521,0.2289526612,0.8410323858,0.9339575768,0.9122983813,0.1333952397,-1.7370053530,-0.3468855321,0.2191209644,0.5838090181,-1.1512639523,-2.1934931278,-0.4012824297,-0.5996697545,-2.5864920616,-2.8078482151,-1.9428218603,0.5865498185,1.0440528393,0.2802296579,0.2726215720,-0.7898737192,-0.5721588135,0.9211881757,0.9148751497,0.1910182387,1.4056829214,0.4825052023,0.3429075181,-0.5708855987,0.3786260784,-0.9315177202,1.0208618641,-0.9725951552,1.0935645103,-1.2232342958,1.0409260988,0.6748644114,-0.8847046494,1.7760386467,-0.0125171226,0.8016899228,1.8771826029,0.2736357450,-0.6259844303,-0.9930151105,0.3236394823,-0.2595492899,-0.1605339348,-0.1315153837,0.6235751510,0.6957799792,1.6935269833,0.4405800402,0.0049002608,-0.5700479746,0.2159934789,-1.4336683750,-0.3797477186,1.4713785648,1.8703402281,0.0075660832,-1.4935919046,-0.8821055293,-0.6234281659,0.9677629471,-0.7328437567,-0.2575615942,1.0310820341,1.8457337618,0.0857489705,-1.4493061304,-1.2911778688,-0.0060188952,-1.2698920965,-0.5432638526,0.1579181850,-0.7544699907,-1.0726186037,1.2530040741,0.0434547551,0.6073220968,-0.6502922773,-0.3982699513,-0.2588134706,0.0140502499,0.7154316902,-2.1796958447,1.3421326876,0.9615692496,-0.5703505874,2.5212097168,-0.0208987631,1.0348778963,1.9658333063,0.3773489296,1.4068762064,-2.7714827061,-0.5579730272,1.2298541069,0.6545353532,0.8766176701,1.4339731932,1.1497399807,-0.5089753866,-0.5128499269,0.5389691591,1.3455309868,-0.8251724839,-0.8975332975,0.8422950506,0.8494792581,-0.1416618824,-0.6297848225,2.3947386742,0.1711565703,1.2305666208,-1.0552343130,2.2050673962,-1.1041059494,0.0757807940,0.5562387109,-0.3192164898,-0.7332569361,0.2332962155,0.8301983476,-1.3935382366,-0.1565247476,0.2479268014,0.0560801663,1.7070498466,0.7718081474,-0.7962634563,0.7645039558,-2.1454570293,0.6315026879,0.4187367857,1.1163557768,1.2457189560,1.1284046173,-0.0940276459,-2.3251667023,0.5586260557,-0.3234356046,-0.3314171135,-0.7101279497,-0.1197030023,-1.7641125917,0.6344687939,-0.3916080594,2.1762027740,-0.9665816426,0.0275986735,-1.0265176296,-0.7908039093,-0.2755824327,-0.1384730488,1.0248076916,0.8314927816,-2.0504336357,1.2907943726,-0.2341943830,-0.6094402671,0.5007750988,-0.3549800217,0.1185565591,-1.1103465557,-0.2405512780,0.4953965843,-0.0646155775,-0.4671186805,1.1927411556,-0.6523253322,-0.5857589245,-0.2545292974,-0.1239542216,-0.0203897934,-0.0034907917,-0.6640003920,-1.3702145815,-0.8654106855,0.0326672718,1.3138712645,0.4208591878,-0.9769559503,-0.8214844465,0.1297749430,-0.1297391802,1.0146135092,1.7940646410,0.2197928280,-0.1319720149,1.0318607092,-1.8993104696,-1.7712563276,0.2810631990,0.4633574188,1.6809766293,-0.3751383126,0.7755542994,1.0474252701,0.2971350551,0.5951340795,1.6116594076,0.1424589455,1.2979151011,-0.4820315242,-0.1617800742,0.0396738835,-0.8928088546,1.1956772804,0.3390346169,-0.4060118496,2.4652819633,0.8918821812,-0.0780620202,0.7143768072,0.3408457935,-1.7165350914,-1.1632332802,0.3031347394,-0.0014043999,0.3238669932,0.6181593537,0.0723976716,1.0229631662,1.1097664833,-2.3270466328,1.3248306513,-0.2984437943,-1.4610385895,-0.0516262911,0.5079306960,-1.0296018124,0.0228735339,1.1103858948,0.0523694046,-0.0578812994,0.1035495922,-1.4611114264,0.3591971695,-0.9242418408,0.3373346329,0.5315905213,-1.1278209686,-0.1850767732,0.0478607044,1.8553361893,-0.1041360721,-1.0382961035,0.5020739436,0.0162114426,0.4946565330,-0.3373891413,-0.8022236824,1.7341907024,-0.0187101774,0.7622405291,-1.3417707682,2.0679044724,-1.0047054291,-1.5931515694,0.6079227328,0.6830322742,0.1589563638,-1.3811666965,-1.2644420862,-1.9886835814,1.9554864168,1.1086750031,1.0685912371,0.0946351141,-0.1953218877,0.3039997220,0.4832267761,1.2116614580,-0.5229575038,-1.0833784342,-1.9380421638,-0.1046403423,-1.2439750433,-0.1244251058,1.0000693798,0.9575945139,-1.6811643839,0.2811778784,0.8408188224,-0.7864719629,-2.2276020050,1.8322992325,-0.4967197478,-0.7136280537,0.0266603082,-1.4942921400,0.8555268049,-0.7208786607,-0.8286910653,0.0459153466,-2.0120952129,0.3852713704,0.0434668995,-0.9490215778,-1.5576071739,1.1132159233,1.4050958157,-0.4533327222,0.4062691331,-0.7710663080,0.4899501204,-0.3605414927,-0.7879081964,-1.4783047438,-0.6426596045,0.0291680340,-1.8412855864,0.3601514101,-0.1602088660,1.1215077639,-0.6920269132,0.4370068312,-0.6374166012,0.9822850823,0.0243866947,0.1872158647,-0.0480282828,-0.2081749886,0.2828293145,-2.1054990292,-0.4270705283,-0.7249308825,-0.9879758954,0.0718391016,-0.5815575719,-1.1283096075,0.1646392792,2.2088565826,-0.8298310637,0.1257507503,-2.0224769115,0.6178207994,-1.2828671932,0.4831278920,-2.5446667671,0.0235447213,0.6328905225,-0.2720804214,0.2828456461,-0.2629654408,0.2357223034,-0.2633309066,0.3823617697,-1.0612810850,0.8905143738,0.2787717283,-2.9553375244,0.4997931123,0.3578976393,0.5189617276,0.3165110052,0.1713823676,2.0032389164,0.5444811583,-1.5100010633,1.6583312750,0.4102133214,2.2827858925,-1.4170377254,1.0672702789,-1.0848878622,-0.9437910318,-0.7768186331,-0.7263257504,1.1376026869,0.1669677347,0.1908601671,1.6095134020,1.1411566734,-0.1959963888,1.8457901478,2.7180738449,0.0899037942,-0.4714163244,1.5490199327,-0.0940073505,-0.6156017184,-0.8397650123,-1.5853828192,0.6788233519,-2.0469789505,-1.0404422283,0.6478714943,-0.5592913032,0.7406380773,-0.6209233403,-1.7690067291,-0.3744283617,0.5275703669,0.1906655729,0.1695944369,-0.1484553218,-0.5499172807,0.6520490646,0.1473938972,-0.8528057337,-0.6439852715,-0.2095579505,-0.1239432767,0.3361501396,0.2245066762,1.9661922455,-0.0664852038,0.4860768616,-0.1386903822,0.9536022544,1.0937627554,0.1194592714,-0.6387403607,-0.5548762083,-0.5451083779,1.4894568920,-0.7443156242,0.7375551462,0.3067426980,-2.0427732468,-0.4271575809,-1.3816052675,-0.5549044013,-1.5412914753,0.9646945596,1.0175510645,0.8287231922,-0.6588662267,-0.8034091592,-1.0398589373,-0.1990352720,-0.2321966738,-0.8626244664,0.7902417779,0.5957292914,0.0277387053,-0.0978775173,-1.7130082846,0.7651479840,0.6190039515,-1.8823497295,-2.8895819187,-0.3021363914,0.6384620667,1.1293169260,0.8372123837,1.8616006374,-1.3465864658,-0.9666275382,-0.8175053000,-2.2610628605,1.1906888485,-0.8104630709,0.0317354426,-0.2019810528,2.2502446175,-0.2259142995,-0.2013495713,-0.4183434844,-1.7510526180,2.2945125103,-0.7594260573,0.3623003066,0.2451833487,-0.5534833670,0.8765788078,-1.2913513184,-1.5042854548,0.7121409178,-1.0445988178,-0.9468733072,1.0692250729,0.2658461034,-0.5082159042,2.3868613243,0.3205399811,-1.0530476570,1.8602855206,1.8128275871,0.6259533167,-0.7656450272,0.3985169232,0.3867060840,-0.1872877032,0.4220613837,0.8917585015,-1.4155749083,-1.2021927834,2.2409737110,1.1562517881,0.3536393642,-1.7080003023,1.5424200296,0.9600786567,-0.0872785896,0.7514562011,0.9496883750,-0.6002808809,1.6835938692,-0.2155499607,0.9516291618,0.4370562732,-0.4840465486,0.1115614027,0.2884726524,1.3234615326,1.0874466896,-0.5007370710,-1.0555545092,-1.3426496983,-0.3183835149,-0.0679995045,0.3516796231,-0.7929608226,-1.4250048399,0.3407011926,-0.5564637184,-0.5598407388,-2.0848259926,-0.3684155047,-1.5428141356,0.0320821367,-0.7246804833,-0.5784972310,-0.0024182077,-1.0722943544,0.6343519688,-0.2621089816,0.2908956707,0.8434097767,0.7944604754,-0.0688873604,0.2049677670,-1.0564239025,-2.9353809357,-1.1070784330,0.8343291283,-0.2105655819,0.8942486644,0.1070115343,2.8148813248,-0.1915903836,-1.2917917967,0.6141395569,0.2729116678,-0.0089775594,-0.9163486362,-0.3805558085,0.4296191335,-0.5568725467,0.0454204902,0.3127158284,-1.2098184824,0.5218726397,-1.8089548349,-1.7078270912,-1.0075867176,0.2304183394,-0.6987965107,0.6294561028,1.4788361788,0.2974897623,0.9382640719,0.6637336016,1.1047103405,-0.1571140289,-0.9894824028,-0.5497223735,-2.0647106171,-2.5246694088,-0.3880341649,-0.2562047243,2.0650627613,0.2814728320,1.5140551329,-1.5470811129,-0.5152064562,0.2855536342,-0.7161605358,0.1456434429,-0.7985317707,-0.1925467849,0.7353378534,0.8663336039,0.0977301821,-1.6826072931,0.3238239288,1.8810269833,0.0977288559,-0.6490523815,-0.7416719794,-0.4745566249,-0.4449836314,-1.5103685856,-0.0510294065,0.3497232795,-1.3869361877,0.1665868908,1.4021207094,0.9121657014,-0.4573785961,-0.7126724124,1.1894726753,-0.7016700506,-0.1637506485,-0.1672487110,-0.2228942066,0.7889564633,-1.7819786072,-1.0300257206,1.5504140854,-1.2054677010,-0.5473297238,-0.6004752517,-1.4439833164,0.7139390111,0.3109297752,-0.3902191520,0.9313625693,-0.0723820999,0.5176621675,0.1685560048,0.6693775058,0.4388497770,0.4009196460,-0.7448923588,0.1883382797,-0.0165072586,0.1768764108,1.0786801577,-0.4834615886,1.3717924356,-3.5873508453,1.6853481531,-1.1144967079,-0.6112350821,0.4245436490,-1.7847050428,-0.1747217029,0.1853655428,0.1908560395,-0.6552680135,1.0942722559,-1.4203670025,0.0901684761,-0.8357254863,-1.3958472013,-0.6363635659,-0.3363048434,1.3161414862,2.3062155247,0.2548306286,-0.5943790674,0.1230811551,1.3223766088,1.0881372690,-1.4070535898,1.0152657032,-0.4547869563,-2.4484944344,-0.7348918319,-0.1146792397,1.8282408714,0.4467991889,0.5553500056,1.0960659981,1.1745150089,-0.6352566481,0.9568100572,-0.1503251493,-0.6595150828,0.4656138420,-0.2699167728,0.3962543607,0.0893835947,0.9601736665,-0.2942351103,-0.0805045590,-0.1939863265,0.7092486620,0.7895736694,0.5779416561,0.3850767314,-0.4842936695,0.6331396103,1.1849069595,-1.2239178419,0.6399813890,-0.1655349433,-0.2754193842,-0.4561723173,-0.0982396007,-0.7950536609,-1.3405947685,1.4434165955,1.4510871172,-0.5008798242,2.3326554298,1.7171764374,-1.1214941740,-2.1384959221,-1.4371384382,-1.2622073889,0.3689718246,0.3668732345,-0.1287642419,0.4816688895,-0.7438533306,0.7954478860,-2.9465436935,0.0280521810,0.5243663788,0.8543690443,-0.5550677776,-0.9916635752,1.0783920288,-0.2361106575,-1.0624667406,-1.0621988773,-0.3515598178,0.0059884796,-0.2377974391,-0.2549857199,-0.5997722745,1.4417372942,-1.2261022329,-1.3927828074,0.3786606491,-0.8822529912,1.9552049637,1.3698495626,-0.7608377934,0.4118162394,0.3870486319,-0.1944354028,-0.6407830119,-0.4655601978,0.3296374083,0.3511639833,0.6457598209,-1.6749877930,0.3648128510,-0.3509193361,1.3478113413,-0.6998479962,0.1091958135,-1.2648110390,0.6919533610,0.8096422553,0.4792396128,2.1586918831,-1.0145262480,-0.4494864345,2.1004250050,-0.8175516129,-0.1288737357,0.6267175078,-0.9657980204,-0.3166680932,1.2221369743,0.6191287637,0.8959646225,0.2814862728,-0.3159213364,1.3342118263,-0.9356304407,-0.7985250354,2.5087397099,0.2187114060,-0.3500434756,-0.5621758699,-1.1118510962,2.3423166275,-0.8084353805,-0.6880099177,0.9092693329,-0.4087174237,1.1080206633,0.9253252149,-0.9031172395,-0.6476074457,-1.5008963346,0.4107389748,0.5725745559,0.0407793745,-0.8929830790,0.7959543467,0.6446728706,1.5393860340,0.2424186319,-0.7756873369,-0.3757202029,0.9156033993,1.5491391420,-0.2052761167,-0.7376536131,-1.8269327879,-0.6759383678,1.0747044086,0.3764349818,-0.0615763552,0.0539816134,1.3830044270,-0.2138948143,0.6070758104,2.2050757408,-0.5970668197,1.5818897486,-1.7589093447,0.2374013215,0.6174883246,1.5783377886,0.2767152190,-2.0720968246,-2.1631407738,1.1022502184,0.9568095207,-0.7925844789,-0.0129932240,-0.4571443796,1.1118091345,-0.0802769810,0.5072802305,1.4994150400,0.9595949650,-0.5461329818,1.2634196281,-1.2565197945,0.0333052836,0.4604368210,-0.5963924527,-0.4048521519,-0.0185353886,-0.4433542490,1.0058584213,-0.6991336942,1.2530970573,-1.8591336012,0.1965983361,-1.3790326118,0.6991924644,-1.1815651655,0.5590909123,-0.5781280994,-0.2810287178,0.9894128442,0.5948468447,-0.2116240114,1.6549823284,2.1434628963,0.1538797021,-0.2101962715,-0.2762024403,-1.0265514851,1.2561662197,-0.0961916596,1.8024312258,-1.0695019960,2.2832481861,1.1988962889,-1.3095893860,-0.6166658401,-1.0923980474,-0.4167923927,-1.1538887024,0.6146585941,-1.0539424419,0.2147403657,-0.9397309422,1.2403391600,0.6924793720,-0.1568285823,-0.2127067894,-0.4619454741,0.4466876090,-0.8593928218,0.3885909915,0.5803668499,0.3129754663,0.5921312571,0.2810893059,-1.0458991528,-0.3443108499,-1.3744816780,-0.3332820535,-0.8077567816,0.4288160503,-1.7361116409,-0.1163452491,-1.3128036261,0.0584229752,-0.1550195813,0.5011024475,0.9355930686,0.5465435386,0.4411371946,0.1784846634,0.4730665684,0.3743475676,0.3358268142,0.3381077945,-0.0342798606,-0.8083887696,-0.3979845345,-1.1604353189,-0.0066471668,0.1081213802,-0.0444181934,0.1806796342,-0.7541006804,-0.7393528223,-0.9072701335,0.2659946382,0.8296968937,-0.2166975737,-0.0818051770,-0.1148054823,-0.7135875821,1.2623482943,0.9717949629,0.6293833852,1.6772850752,1.0530080795,-2.5207023621,0.0990564898,-1.2991740704,1.4384398460,-0.5041558743,-2.4514865875,-0.7514006495,1.0182894468,-0.4337368309,1.8021686077,-0.4107547402,0.0077835210,0.2561873496,1.2580149174,-0.2291361839,0.1945354342,-0.7990037203,-0.4128118157,0.3472887278,0.6855760217,-0.0667856112,0.5450399518,-1.0061272383,-1.0191876888,0.8211130500,-1.1527760029,-0.5438255668,-1.2694709301,0.2857372463,1.1246901751,-0.3271239996,-1.5309205055,0.9586626291,0.7188817263,1.3707944155,2.0927855968,0.9110329747,-0.4163654447,-0.2413679957,0.1141957939,-0.3054531515,-0.1258421391,0.4647783935,-1.0801485777,-0.4261832237,-0.9162673950,0.7924376130,1.0909430981,-0.6960784197,-1.6909022331,0.2807614803,-0.9859634042,1.3558187485,0.4552947879,-0.6819797754,-0.5628001094,-1.1365072727,0.0257628281,1.3203532696,-1.7315850258,-0.2278526872,1.1781377792,2.3463416100,0.1275173873,-2.5863084793,0.6135267019,-0.8700727224,-0.8105805516,1.5111283064,-0.3862929642,-0.4356092811,0.0636376143,-0.5927600861,-0.5895982385,0.1878833175,-1.9611967802,-0.3901644945,1.0398082733,1.2147284746,-1.1976518631,2.3415234089,-0.7130673528,0.2361291051,-0.3015916646,0.5939913988,-1.4054470062,-1.0503392220,0.6779701114,0.5623335242,0.0663100109,0.4308245182,1.0027855635,0.8165775537,0.4989019632,-0.0002661952,1.5691658258,-0.7713332176,0.1407069266,-1.0722569227,1.5917398930,0.6614595652,0.2007022649,-1.0523856878,0.0822489485,-0.6039589047,0.4681268930,-0.5547893047,-1.6950765848,-0.6791362166,0.1981026828,1.9102047682,-0.5541394949,-0.9890259504,0.7984296083,0.0003176213,0.0550370589,0.4107954204,-0.0231982525,-0.7725265622,0.6694859266,1.2758612633,-0.1744779348,-0.0360984839,-1.6794584990,0.4439693987,1.3904777765,0.5694403648,1.7294931412,1.5751372576,-1.9432759285,-0.3927997947,0.9067459106,0.5820047259,1.2948682308,0.1216424406,1.1153415442,1.5315512419,1.1464210749,1.7029515505,-1.0568026304,-0.0944661796,0.3944582939,-0.1618760973,0.0606435351,0.6873081326,1.0236778259,-1.4742099047,-0.4439935684,0.6182740927,-0.0559816100,0.4584692419,0.9900916815,0.5068622828,0.1548262686,1.0944187641,0.4731070399,0.9248341918,-1.4233351946,-0.8062060475,0.1411530674,-0.7675983310,-0.8649474978,-0.0317371860,0.7700589895,0.7849109173,-1.3150564432,-0.1650596410,0.1696455181,-0.0934922174,-0.6370592713,0.5575283170,-1.4024553299,-0.2018749118,0.2528863251,0.1751198769,-1.1257034540,-0.1473133713,1.0206111670,1.2502821684,-1.1858514547,-0.4971847236,-1.9140037298,0.1850125492,0.6661189198,1.7885531187,0.4540091157,-0.5431872010,0.5952700973,0.3110172749,0.7823548913,-0.3349719644,-0.3264983892,-0.7418109775,-1.7509810925,0.1852183491,1.0977188349,1.5520267487,0.3697099686,1.7792718410,-0.1528856754,0.2824684978,-2.4584684372,-0.2338568270,-0.1353407651,-0.7570917606,2.0325019360,0.3802107573,0.0842941403,0.1059182584,-0.0346744955,-1.6290546656,0.5493621230,-0.3867263496,-1.4424030781,-0.6036384106,0.0387400873,1.5152940750,0.1151001677,-1.0722410679,-0.2107968777,-0.4670877755,-0.1375235170,-0.1439756453,-1.0298039913,1.0332676172,0.8170245290,-0.1887505949,-0.0494192839,-1.0711476803,-0.8699306846,0.4188597202,-0.3706445992,-1.1961505413,-0.7853118181,-0.4474318326,0.4565109611,-0.3028509021,0.0739333481,0.5674366951,0.1040408462,-0.0226907004,-0.2704212666,1.5229213238,1.6927081347,-0.4871771336,0.7022641897,1.0417212248,0.6593301296,0.6112542152,-0.9994509816,0.6857087016,-0.1322730035,-1.0452054739,-1.3029451370,1.2493374348,0.0080011049,-1.2995612621,-0.0949502289,-0.3533111811,-0.8815700412,-1.4849035740,0.6015857458,0.3696425855,0.1216674820,0.1807393730,0.3852241039,-0.8649283648,-0.2445823848,1.3928322792,0.8241620660,-0.1049988940,1.2019417286,-0.8042196631,-0.1875663549,2.1202955246,0.5893884301,0.6650680900,-1.4238115549,-0.4695525169,-1.4288089275,-0.3693912327,0.8288694620,-0.1480082422,0.8329437375,-1.5620113611,1.4933506250,-1.9748326540,0.3324063122,-0.8589459658,0.5188101530,1.1035842896,-0.2568058074,0.8886639476,-0.7919666171,0.4869928360,1.8516781330,-1.1125978231,-1.1663391590,-0.2702799141,-0.9070065618,-1.8252818584,-0.3983536363,0.9135220051,0.6276210546,-1.2996852398,-0.8030201793,-0.8869251013,-0.1006307080,-0.1849675477,0.4097519517,1.1918514967,-1.1746904850,-1.5114037991,-0.0913629159,-0.5989208817,0.9410465360,-0.8433012366,-1.2563877106,1.0473858118,0.9126477838,-0.5827721953,-0.5856482387,-1.7571837902,1.3324482441,0.4234672189,-0.6457720399,-1.0114756823,-0.0575404130,0.4846711755,0.5327658653,0.0827659070,0.2714155316,0.4643567502,1.9540315866,1.3832021952,-1.0131411552,-1.0373722315,0.8032507300,0.2130549699,-0.8439952135,0.9219255447,1.1542927027,-0.0212097038,1.6666793823,-0.5585919619,0.2945807576,-0.0132242423,0.5881583691,-0.6531445384,-0.2318715155,0.0456866808,0.0064122831,0.4922307730,-0.6649486423,1.2209202051,-2.3153216839,-0.8188648820,-0.7945204377,-1.2346620560,-1.2860282660,-0.8244218826,0.7727444172,-1.7617459297,0.0262414347,-0.3023742139,-0.0454284027,0.5600838661,0.3081323504,-0.6677283049,-0.0851749256,0.4230430126,1.1981501579,-0.5143482089,0.1208445281,-0.3302524090,1.4326996803,-0.4619111121,0.8303595781,-0.2305427641,0.4566539824,0.0284742471,1.1725553274,-0.6778904200,0.7474908233,-1.4357063770,2.0686724186,-0.6995326281,0.1032049581,-0.9478116035,-0.1820008606,-0.8253668547,1.1953212023,0.3244872391,0.6627004743,1.0053045750,0.2691727877,0.2567492425,0.6107055545,-0.7879512310,0.9819718599,0.6871561408,-0.8443669677,0.0294165127,0.6981332898,-0.4156535268,-0.4417705238,-1.1484087706,0.4935772717,0.9644652009,-2.2177762985,1.2895581722,1.9430149794,-0.1687173247,0.2524688244,-0.0231861938,0.2763607204,-0.8558312058,-1.3785704374,0.9749888182,-0.0315952413,1.2336918116,0.8569123745,-0.1242811829,1.0706355572,0.0651801452,-1.0987329483,-0.0845275149,0.3220182061,1.3133853674,-0.3922113478,-0.8745101690,-1.6545143127,1.3099434376,-0.3884691894,-1.0207983255,0.9145443439,0.6784790158,-0.4679728150,-1.8396611214,-0.6501001120,1.0174416304,-1.2393320799,-0.0569090955,-1.5452183485,0.4984608293,-1.0995006561,0.4160440862,-0.2431684881,-0.0810485184,0.1673014760,-1.2867910862,1.1799737215,-0.2366669923,0.2107269764,0.1286269724,0.7097382545,-0.7196391225,1.0831000805,0.2915651202,-0.8028673530,-0.4497925341,-0.2961663902,-0.3938611150,1.3102715015,0.1274573952,-0.3415600657,-1.3402360678,0.3736258149,-0.1554016620,-2.0350890160,-1.6971189976,0.2403908372,0.2295648903,-1.4248719215,2.1251647472,-1.4979672432,-1.2219846249,0.3304457068,0.0374567807,2.1840059757,0.5777245164,0.1611160338,0.8961535096,0.3680781722,-1.9025293589,-2.9646284580,-0.6679293513,0.0742716938,1.4247859716,-1.4310384989,0.6191782951,-0.2454420179,1.8304854631,0.5033181906,1.5404642820,2.0885241032,-1.3709269762,1.6574317217,-0.5738112330,0.4851473868,-0.5364739895,1.9374666214,0.5323956609,-0.7937283516,0.7213377953,-1.9963128567,0.5997330546,-2.5905666351,0.4053169489,1.0426921844,-0.2191019654,-0.5558608174,1.5116729736,-0.8256971240,-0.2864851356,-0.5010135770,1.4569622278,-0.4448128939,1.1936591864,0.6703691483,2.1985344887,-0.6182096004,-0.7770881653,-0.7601132393,0.8608002663,1.1269603968,0.0908432677,0.1105712205,0.9951350093,1.0663802624,-0.6953923702,0.0459341668,-1.2705870867,-0.4319158792,-0.7496430278,0.5289142132,-1.6569365263,-1.0187835693,0.9269422889,-1.4888494015,-0.4321640730,-0.1888191402,-0.4988208711,-0.7500018477,0.5415527821,1.2704626322,-0.5392972231,-0.5853786469,2.0392589569,0.8061009049,0.4328102469,0.1999326795,-0.1828068048,2.0369491577,0.5376186967,-0.9456459880,0.2697933614,1.6897407770,-1.3979105949,0.2796856165,-1.2426117659,0.6467071176,1.0034134388,-0.5081450939,-0.1762165129,-0.9470931292,-0.9216216803,0.0103546353,-0.9105349183,-1.5967898369,1.6333882809,-1.1184823513,0.7191648483,-0.1556680799,-1.1775581837,0.6844239235,-0.0761843994,-0.8918274045,-0.9387372136,-1.4445216656,-0.8445951939,-0.1898192763,-1.2781102657,-1.6075053215,0.6881842613,1.5046265125,-0.6197365522,0.2504410148,-0.2626022100,-0.5783621669,0.9059876800,-1.2948360443,-0.2569444478,-0.8420674801,-1.3039224148,0.5142272115,0.4427238107,0.1815748215,0.4946224391,-1.3786232471,-0.2891066074,0.4617694318,-0.8750137687,-0.6624167562,0.2299284190,-0.3934533298,0.1057336032,-0.5486158133,-0.7816815972,1.4666053057,1.4891735315,1.4241904020,-1.1920310259,-0.6360286474,-0.4250755310,0.0566578321,0.7702762485,0.1289665252,-1.5876783133,-0.0016417794,0.4250714779,1.0069613457,0.9110912085,0.6452820897,1.2802551985,0.8736882210,-0.1176333576,1.3896194696,-0.8711903095,-0.8319627643,-0.2103565633,-1.5452733040,-0.2017096281,0.0036522455,0.3344618678,-0.4068647623,-0.7161149979,-1.2258971930,0.5839748979,0.6048594713,-1.1431585550,-1.7302323580,-0.0968581066,0.1390904784,-0.3141165972,2.1717050076,1.9471942186,0.5632810593,-0.2581654489,-0.8188413978,-0.7301347852,-1.9451324940,0.1461771280,-1.3031450510,-1.2256352901,0.2075386643,-0.3776623309,-0.6919597387,0.7050512433,1.5114662647,0.1402460635,0.9202152491,0.4513795972,0.7388632298,1.0826296806,-0.3678231835,0.3671057522,1.1094573736,0.3479338884,-0.6016224623,0.0073265564,0.4310854077,1.7144032717,-0.3383898139,1.0131033659,0.2747268379,0.7387757301,-0.4018067122,0.6781775355,-2.1581020355,0.2278467268,1.7021756172,1.3773645163,-2.0554974079,-0.6872193217,0.1226048097,-1.9852946997,-0.3543234169,0.1991903782,-2.1077291965,0.9524010420,-0.8265848756,0.0515594371,0.7495928407,-0.5910230279,-1.9738554955,-0.4401849806,1.2871997356,0.3963395059,-1.3662760258,-1.0966602564,-0.1497679204,0.2017935365,1.5538893938,-1.4132012129,0.8584647775,0.0906719267,-1.0717674494,0.1683136374,-1.6558039188,0.5440172553,1.2324019670,0.5137600899,0.2472419590,-0.0660363659,-0.3757608831,0.5444558263,-1.7358322144,-0.0051293653,-0.2503592670,-0.4951822162,1.2275048494,0.2725945115,0.3664792776,-0.6326197982,0.0382645912,0.7879148126,-0.1890475899,0.6260702610,0.6560769677,-0.8796280622,-1.0355696678,-1.1185706854,1.8544151783,0.7461084127,1.7544984818,-0.6223727465,-0.4497933388,0.8481234908,-0.3922756314,-0.4858475626,0.0968091264,0.0066539571,1.0293912888,0.2278260440,2.0721802711,0.4783202708,0.7750809193,0.3829811513,-1.0834962130,-0.6774073839,-1.5615712404,-1.6606448889,0.3167343438,-0.4906793833,0.0483574681,2.2943816185,-0.0707739368,-0.4499971867,-0.1112928838,-0.2830072939,-2.6263105869,-2.1136035919,-1.1006478071,0.7729149461,1.4741439819,-1.2733880281,2.3177292347,-0.5778938532,0.0909742787,0.4740823805,0.5157712102,0.5300472379,-0.8119449019,1.2384713888,0.5614928603,0.2497849166,1.2373347282,0.1882596016,-0.1199569330,0.5125343800,-0.4821256101,-0.5073617697,-0.3014651537,0.6116203666,0.1299709827,0.6942937970,1.1415054798,-0.2746116817,0.1055720225,-0.5667106509,0.4699902534,0.3701259792,-0.4664997160,-0.0554599166,-0.9459332824,-0.7991710901,-0.0254140403,-0.1795408279,0.5957148671,-0.9031828642,-1.5857150555,1.0605216026,-1.5644696951,2.2349119186,0.2240771055,0.9779759645,-0.3761295676,-0.6323259473,-1.1920045614,1.5147486925,1.5310157537,-1.3137631416,0.0094543528,-0.2456318289,0.5364572406,-0.9972238541,1.2738656998,-1.3176814318,0.3259899318,1.0292425156,-1.3389029503,1.4183219671,-0.4529511333,-1.0125648975,2.5792348385,0.6706108451,-0.4555190206,-0.8167887926,-0.2441108376,1.4933758974,2.3693647385,-0.0329419933,0.2555276155,0.1001068726,0.4355405271,0.7977789640,-0.3352335989,0.1421558112,-0.2073267847,0.0726978779,0.4240096211,-2.3663616180,-0.8102269769,1.0085755587,0.2688770592,-1.0159114599,-0.1881680489,1.8253681660,0.8918188810,0.0901473612,-0.1998090148,0.6020976305,0.9907689691,-3.2210643291,1.6036646366,-1.0785632133,-0.4379940927,-0.7611535192,-0.0714974627,-0.6375125051,-0.3485542536,0.3473993838,-1.2568857670,-1.3050128222,0.0136722717,0.7082781196,0.8472917676,0.8057292700,-0.1659359187,-0.5133125186,0.3766638637,-0.2679806054,-1.4026973248,-1.0416235924,0.7020118833,-0.1503003240,-0.5658562183,0.1204976216,-2.6717855930,-1.9358696938,-0.8094495535,-0.6051175594,-2.0002884865,0.7022117376,2.1806385517,-1.7201800346,-0.0582118407,-0.1393259019,-0.1016402170,-0.2271406353,-0.0488020889,0.1912101656,1.2248835564,-2.2081222534,0.0591728874,-1.0548201799,0.2093756348,0.7086314559,0.4830908477,2.0755898952,0.0622914173,0.9292717576,-0.4380646348,-1.6233458519,0.1461371183,-0.5482233763,0.7338901758,0.0389567427,0.6998253465,1.0116010904,-0.3618020415,1.8255698681,-0.9448072910,0.1480549872,0.9181790352,1.1242004633,-0.7497963309,0.5569706559,-0.3830719590,-2.8234889507,-1.1781505346,1.4321072102,1.2316467762,0.2388788015,0.0512132496,-0.4228218794,1.1188286543,0.3400440812,-0.4093388915,-0.3253835738,-0.5566400290,1.2506176233,-0.5119938850,-0.7112380862,1.1241469383,0.2668454647,-1.7113490105,0.2358381599,1.1011041403,0.8496887684,-1.2886971235,-1.3477289677,-2.8305227757,-1.0628187656,-0.2909052968,-0.1643280834,0.0555402003,0.5318995118,0.5488132834,-0.3408282399,2.4728338718,-0.0778830498,0.2826209366,0.3594366014,1.1223710775,-0.2526025772,-1.8722442389,1.2654098272,-2.6454839706,-0.4887316823,-0.4427509308,1.2608346939,2.1664521694,1.1900120974,-2.3902049065,-0.6655550003,-0.1544005424,0.5118381381,0.0688272491,0.3676896989,0.1625170857,1.4110800028,0.0116869053,0.6106952429,0.0455630608,-0.1926245689,-0.2303574234,0.8177344799,0.1466995478,0.0532553457,-0.6141367555,0.5387769341,0.0295939930,-0.0525368638,0.5687243342,0.6703144908,-0.6449947357,0.3593075573,0.7457771301,-2.0517790318,0.0016169018,-0.0653042272,-0.1865885556,-1.4693999290,1.1893911362,1.0076799393,-1.4579092264,1.3490563631,-1.6361253262,-0.5041018128,-2.0277647972,-1.4027677774,0.4853744805,1.1966117620,-1.9860762358,-1.1433326006,-0.4991798997,0.8099403977,0.9741308689,-1.1231752634,1.2916612625,1.2223510742,1.1004766226,0.1277393401,0.9839468002,0.0020423641,-1.3422156572,1.1989815235,1.0622923374,-1.0130317211,0.0652642846,-0.5992264152,0.4082034826,0.0806819052,-0.3798908591,1.2465872765,-1.0993893147,-0.5118710399,-0.2986849844,0.5246425867,0.6732012033,0.0628702417,-0.9138420820,-0.9044297338,0.0181843303,-1.6680605412,-1.1724907160,-0.8832670450,-0.2367167175,-0.0361848995,1.4360933304,-0.2679459751,-0.8920229673,1.0423166752,-0.0651038066,1.7097898722,-0.9543641210,-0.7677184939,0.1742484719,-0.2672248483,-0.4275380373,-0.1414251775,0.9008878469,0.8739157319,-0.3322092593,-0.5973111987,0.2851661444,-0.1468812525,-0.2907929420,-1.0881502628,-0.6024230123,-0.5802869201,-1.2372754812,-0.4289747477,-0.5685067177,0.9802915454,0.0765238106,0.9593495131,0.6458209157,-0.6384899020,0.6581201553,0.4170886278,1.3364971876,0.8242484927,1.4422096014,-0.4826723039,0.2676834166,-0.1370688677,-0.3821313083,-0.9061530232,1.1765571833,0.4614237249,1.9140841961,0.0065699657,0.4581893384,2.2392342091,-2.1551437378,-0.6505623460,0.1773225814,0.1001090482,1.1466196775,-0.5088146329,0.9910753965,-0.6102650166,-1.6703640223,-0.5117351413,-0.6359770894,-1.0455538034,0.3068882227,-2.8139216900,-0.7243748307,2.3602602482,1.1162489653,-0.5636335611,-1.3498125076,2.0970036983,-1.6311956644,-0.3248442113,-0.7526709437,-0.6360383630,2.2367043495,0.8790027499,-0.4985416234,-0.4463484585,-0.7190703750,-0.3197208345,-0.1645631343,1.6601192951,-0.0426488407,2.3123860359,-1.5778800249,-0.0058000362,0.1096969396,-0.0175224114,0.9351284504,0.9580059052,-1.3353056908,0.1352744251,0.7962580323,-0.7297627926,0.9289662838,0.7584497333,-1.0704288483,-0.1412631720,-0.2476228029,-0.6682301760,0.0307615045,-1.4234244823,-0.7623709440,-0.9366347790,2.0120165348,-0.5410431027,-0.4628232121,-0.1133372635,-2.6215143204,-0.1878034025,-0.1376096606,0.2618097961,1.3662329912,-2.2204368114,0.8991046548,0.7960936427,0.4082904160,0.3135900199,1.0021790266,2.2778322697,-0.6833299398,0.2828281820,0.4902434647,-1.6065645218,-1.2876976728,0.4138703048,1.4634865522,-0.8037552238,-1.8263963461,-0.1062341779,-0.4714684784,-0.2142926008,0.8328797221,-0.2681073248,0.4731663764,-0.6831670403,1.0777174234,0.3799136877,-1.1204904318,-0.1482727826,-2.2189519405,1.4719551802,1.0429495573,0.2535926402,-0.9038581252,-0.2051886171,0.2231454849,-0.9873346686,-0.1028130278,-0.9490976930,0.5669447184,1.3465336561,0.5354964137,-1.4442919493,-1.3446625471,0.1368197799,0.3121242821,0.6082185507,-1.9605544806,0.7699592113,-0.9161998630,1.6719350815,0.0406786539,-0.2060671747,-0.3644065261,-0.4067469239,0.6496877670,-0.4569232166,-0.4409435093,0.1681868136,-0.8629373312,-1.1391000748,-0.5719874501,-0.6937422752,-0.3806343377,1.2496166229,0.1289080679,0.9666724801,-0.5838910937,0.1186358780,-0.7255809307,1.3304361105,0.2326592952,0.8757634163,-0.7049357295,-1.0692155361,-1.2293150425,0.2959873080,0.0319055319,0.1620924175,1.4239611626,0.7566784620,-0.3976113498,-0.4200448394,1.8963367939,-0.5100295544,-0.1136146113,-0.7116947174,-1.1979464293,0.0628819540,1.6701619625,1.3206782341,-0.3954262137,1.6946469545,-0.1842424870,2.0869755745,0.4656747282,-0.9359200001,1.0937289000,-0.2609280646,0.8597438931,-0.4747339189,-1.7674329281,-0.7370138168,1.6124833822,0.8634741306,1.2746123075,0.4331390262,-0.2857427001,-1.2503889799,-0.4103792012,1.2073097229,-0.2294325531,0.1557102054,0.1661618203,0.1306845248,-0.3510292768,-0.7382842898,-0.1517895609,-1.5608966351,0.0113451760,-2.5729622841,-0.2821547389,0.2182861120,-0.0131761897,0.4549012780,0.2538626492,0.8881043196,-0.2298544347,-0.0876468346,-0.3201176524,0.2374811918,0.8972510099,0.4730105698,-0.6594987512,-0.0209075324,1.3408588171,1.4259743690,0.6906683445,1.4695892334,-1.7932443619,-0.3990622759,0.3883207440,-0.1653114706,0.7263434529,1.0113916397,0.7325154543,1.0358587503,0.2038902938,1.6042402983,0.0524286889,1.0023922920,1.1868354082,1.6180857420,0.8422029018,-0.3649192750,0.6122750640,0.4988044798,-0.5457030535,-0.4046074748,-0.2460051328,-2.1963894367,0.2778351903,-1.2490707636,-0.5998269320,0.4359167516,0.9332191348,-0.2432841212,0.1132514253,2.0727136135,0.7468464971,-1.4363973141,1.6554725170,-0.5935822129,-0.0301943701,-0.0096276281,0.9447058439,-1.1380391121,-0.3193050027,0.3661886156,0.7435558438,-0.1640613824,1.1098930836,-0.3936080635,-0.4477424622,-0.3403979838,-2.5856881142,0.9082188010,-0.8674103618,1.4339728355,-0.8392519355,-0.5988446474,0.1905030608,-1.3781613111,1.0868411064,1.0486859083,1.1246263981,-0.7191772461,-1.0842479467,-1.6448795795,0.8328526020,-0.9384015203,-0.4217948020,-1.3769412041,1.9037914276,-0.5599355698,0.1158174872,-0.1574285477,0.4571927786,-1.7404035330,-1.8275996447,0.7204089761,-0.2950896919,1.4025130272,0.2427419722,-0.0037648869,1.3575364351,-1.1893963814,-1.1178938150,0.3041092753,-0.8188020587,-1.1610109806,0.2950367033,0.0649628937,-0.4260863960,1.3116868734,0.5123817325,0.3020256758,0.1874590069,-1.5938930511,-1.7766227722,-0.2056816667,-0.1434836537,-0.6319875121,-1.3853851557,1.7522269487,0.1705312729,1.9834896326,0.0428273194,-0.2813680470,-0.0961206928,-0.6106506586,-1.2427818775,1.4810787439,-0.6395637393,1.4544156790,-1.0006572008,1.0430054665,0.2761348486,0.3180278540,-0.5181749463,-0.0602431931,0.0929836407,0.4769335091,0.3015520573,0.5975839496,0.6896985769,-0.1892197728,-1.0921987295,-0.4295704961,0.4336581826,0.3824291527,0.1809328645,-1.0461263657,-1.4477847815,0.6859626174,-0.7645117640,1.0940294266,1.4802038670,-0.9201808572,-1.0781209469,0.9212292433,-0.3049114645,-0.0715369731,1.0498589277,1.0016895533,1.4182119370,-0.5187898278,-0.1311899126,0.9670145512,0.5622414351,0.4447497129,1.1318860054,0.7751047015,-0.3009999692,-0.4801048636,0.0647643581,0.9612099528,0.8127611876,0.6242893338,-0.0070319353,1.0763334036,0.3677817285,-1.3627214432,-1.0657974482,0.8311042190,-1.3935128450,-0.2092558742,0.4993962944,-0.9601699710,1.0647552013,2.2043251991,0.3423570991,0.1696930826,-0.2994166017,1.0733228922,-0.3528176844,0.4736300111,-0.5256693363,-1.5099061728,-0.2726048827,1.8399487734,1.0151726007,-0.4483799636,1.0994441509,-1.8038136959,0.4645211697,0.3011919260,-0.7694646716,0.9885981083,-0.3152141571,-0.8028303981,-0.1730686873,-0.6892525554,-0.9899894595,0.6263012290,1.6653257608,0.3095535338,-0.5246341228,0.0186689477,1.6799933910,-0.5161258578,1.8456840515,1.9402329922,-1.6643905640,0.7645756602,-1.0416288376,1.8423246145,0.5390047431,-1.9061768055,0.8301377892,1.0769793987,0.6682855487,0.9632487297,0.6451629400,0.0955077112,0.6230443716,-1.1125954390,-1.1393494606,-0.2665373385,2.2958316803,-1.8586397171,0.1168465689,-0.0136828171,1.4055063725,-1.3613090515,1.2799606323,-0.8697892427,2.4187178612,-1.5788184404,0.5349386334,0.4891916215,0.6985910535,-2.4071002007,0.6912989616,-0.1731216162,-0.3386763334,-0.6762531996,1.8666601181,-0.0154876197,1.4744048119,0.8798419833,-1.8359698057,-1.4010410309,0.1690005064,0.4600860775,-0.2688275576,-0.1073251069,-0.6607923508,0.0372763202,0.1201879010,-0.1509473771,-1.0607008934,-1.1784601212,0.0837295130,-1.1999645233,-0.7227930427,-1.1312910318,1.4536602497,-0.3281475008,-0.2820889950,-1.9610961676,-2.2980158329,1.6167727709,-0.9151739478,0.7914054990,1.4067481756,0.5194048285,0.8777590990,0.5513826609,0.2247539461,-0.0472301021,0.9914721847,2.1558043957,1.8301255703,0.1900593936,0.2965781391,-0.0984601229,1.0304844379,0.4766424894,-0.7833252549,-0.5008711219,-0.5573242903,0.4439268708,-3.2847006321,0.4752749503,0.5018771291,0.2221382260,0.7174639702,-0.7699761987,0.3723175824,0.5160827041,0.4284012020,-0.8318826556,-0.3510650694,0.6850978136,0.6224149466,0.1465418190,-0.3880501390,0.1311548799,-0.3739495575,-0.0982051417,0.0241817795,-0.2103700042,2.3744344711,-0.5839608908,-0.1087427288,-0.2498640120,-0.0379346982,0.3635368645,-1.4021166563,-0.3856891692,-0.5266512036,0.5923498869,0.5811980963,-0.1913233995,0.2475237846,-0.6341478229,-0.4015057981,-0.2930896282,-1.6198561192,-1.5492149591,-0.4098072052,-1.1009782553,0.0696988776,2.2207129002,0.3850325644,0.1232785955,-0.1360888630,0.5543779135,-0.0335183479,0.1661666334,-0.9750319123,-0.3781283796,-0.6851177812,-1.3397881985,1.8235151768,0.7576472163,0.4756061435,-0.1756661981,-0.7518137693,0.8833954930,-0.1723460406,1.4779287577,1.1817060709,0.6576637030,1.7607759237,0.3329871595,0.3841156960,-1.6105310917,-3.4629151821,1.5630116463,0.1894923598,1.1110873222,-0.4295303226,0.0688258111,-2.6791574955,-2.3411090374,-0.6443280578,-2.5961453915,1.8770301342,1.6789271832,1.1087728739,0.4900375903,1.0108305216,-0.7254547477,-0.8507792354,1.0462187529,-0.5669525266,1.7076981068,-0.2117697448,-1.2549630404,0.7878744006,-0.6559647918,2.6261720657,0.0378729068,-0.9183604121,1.5393013954,-0.1139022857,1.5634179115,-0.0301232282,0.0856970623,0.2333744764,-0.3873595893,1.9680051804,1.4474378824,1.2159805298,-0.0786215439,-0.8479925394,0.3741477430,-1.3048787117,-0.6006184816,-0.1725184321,0.3311712146,-0.2673325241,-0.3190022707,0.5827477574,-0.7233198881,-1.2103803158,-0.0765999481,-1.9542196989,0.3852671683,1.4858161211,-0.0310763177,-1.7405352592,0.8110358119,0.1677609235,-0.3663225472,0.4820788801,2.0430974960,-0.2657999992,-0.4802150428,1.6891940832,0.6045791507,-0.2234309465,0.8571979403,-0.2686817646,-1.5307800770,-1.0786039829,-0.9064611197,-1.1571456194,-0.0541361533,-0.5406714082,-0.2749684751,0.1239802092,-0.5381905437,0.6174876094,-0.9688651562,0.9094956517,0.2015793473,2.0235207081,0.2642515600,-0.7107654810,0.6661833525,0.7415869832,1.9120591879,0.9989323020,0.4370322526,0.5388150215,0.2214304805,-0.4388776720,0.0455226041,-0.9726260304,1.4213956594,0.7784917951,-0.8738764524,-0.6479167342,0.9478707910,1.3753795624,0.0296977572,0.8786270618,-0.5038436651,0.1264273673,-1.8705068827,2.3100185394,-0.8938060999,0.3092682958,-0.2958122790,2.1298017502,0.2210101187,0.8279167414,-1.3819217682,1.0468441248,0.7928908467,0.6151984930,-2.1460978985,0.0850671232,-0.2827851772,-1.4269472361,-0.7818253636,2.2002530098,-0.9858335257,0.5671643615,1.5863406658,-0.0924895555,-1.0210804939,0.6836526394,-2.2170433998,1.1493161917,0.3413541317,-0.2154352516,0.5662803054,-0.7847980857,-0.4791492820,-0.8131125569,0.8970845938,-0.4572354853,-0.7225107551,-0.5756103992,-2.2434556484,1.0185506344,-0.5351034999,-1.3657653332,2.0675470829,-1.0386697054,1.4762983322,-0.7982075810,2.0018270016,0.2635194659,1.2353080511,0.4287237525,0.0174695142,0.9563567638,1.6330941916,1.6011214256,-1.2320027351,0.1984476298,-0.9122123718,0.7111468911,0.7488287091,-0.3852639496,-0.1148628294,-0.2698810697,-0.3712545931,0.2244575918,-0.0854918435,-0.0593928993,0.1030734554,-0.4511945546,0.5479831100,-0.6317163706,0.6489620805,-1.0175821781,-0.1811434031,1.5832920074,-0.6779805422,1.3851190805,-0.3345347941,-0.1046513170,-1.6282833815,-0.9392483830,0.2728080750,-0.0925905555,0.2160407156,0.6644548178,-0.2666618228,2.6946973801,0.0434410423,-0.6470096111,1.7980229855,-1.2989336252,0.3984160423,0.6778487563,-0.0981895402,0.9798938036,-1.2538865805,-1.4360401630,-0.5902845860,-0.8581837416,-0.2199495137,-0.3045339286,-0.5929993987,-1.2001744509,0.4193471968,0.4130449891,-0.0643541962,-0.3918884695,-1.9008547068,-0.6400154829,-0.0310537405,0.3388310373,0.7863161564,-0.7796239853,-0.6914700270,-0.8911319971,-0.1382533163,1.1118685007,-0.6569674015,-0.1794133633,-0.5717086792,-0.4314243793,0.7357690930,0.2798558176,0.8829190731,-0.3237231374,-0.6520662904,0.2529103756,-0.3372556865,0.5908755064,0.5626513362,-2.2970151901,-0.2403149754,-0.3434230983,0.6380447745,-0.5477387309,-1.4343986511,0.8501843214,0.6045268774,-0.5088319778,0.1553441733,0.7751315236,-0.5564307570,0.0922820196,1.0430363417,-0.0166171789,0.0004913778,-0.3558220565,-1.0550065041,0.5611869097,0.5342825055,-0.0304869320,0.2164323777,-0.1864604950,0.0301791150,-1.0917770863,-0.1840087622,-0.0184875894,-0.6151685119,0.3353316188,-0.1206564009,0.0764194801,-0.2989043295,-1.5547710657,-0.6537920833,1.8045568466,-0.1564288735,-1.1329820156,0.5988346338,-1.8747942448,1.9920927286,-0.2383167297,-0.0050372910,1.7662442923,0.4502291381,-1.6901876926,0.2092062235,-0.3719630539,-1.4031659365,0.8186979890,0.3760634363,-2.2954051495,0.5926311016,0.0171566214,0.2273662835,-0.4911201298,0.2143833786,0.5893830061,0.1842756271,0.9189839959,1.7500014305,-0.0224729050,-0.0380397290,0.3788199723,-2.2946538925,1.7362905741,0.5558519959,1.1632210016,-0.3035589755,0.7126848698,0.2978425324,1.0315711498,0.4382598400,1.0446311235,0.1455101073,-0.7554751635,0.1581776291,-1.1658589840,-1.2868412733,0.7790217996,1.1975550652,0.5179507136,0.4167861640,-0.1070448756,0.8847790956,-2.1269643307,-2.1746633053,0.9809335470,-1.8558607101,-0.0589242019,-0.3949842155,0.1342334598,-1.9917581081,2.0874900818,0.2646040916,-0.3620138764,-0.4476041794,-0.0092560723,2.7727761269,-0.9875227213,-1.1261665821,0.8644894958,0.0200013202,-0.5129029155,0.4734310210,-0.0488065369,-2.4048309326,-0.1564999670,1.1135571003,1.1397062540,-1.4627355337,0.7660913467,1.1386791468,-1.7050300837,-0.8706223369,1.3747351170,-2.1854331493,-0.7849680781,0.5419611335,-1.3487257957,-1.3122342825,0.1711963266,0.6263733506,0.1525226533,1.4732654095,-0.0650783703,-2.6287243366,1.1032720804,-0.2081544995,0.2773850560,-0.8050147891,1.7604209185,-0.4776040614,0.3857266903,1.1773180962,0.5346040130,0.7014524937,-0.2645107806,-0.1771366298,-0.8814995885,0.1855238378,0.5930702686,1.3211059570,0.3621626794,0.4415043592,0.9820915461,-1.1620858908,-1.5575093031,2.3486135006,-1.4105807543,0.5415712595,-0.3308941722,-1.2917026281,-0.1719277054,0.1799248606,-0.0432348475,0.2673465908,0.1946123540,0.8462187648,-0.8374105692,0.1203589514,1.9621579647,1.5041606426,0.6325783730,0.4140176177,-1.5472197533,-0.8060904741,1.3864337206,-0.7399890423,0.3658272028,1.8032287359,-1.0524270535,0.2010727376,-0.5947147608,-0.4959990084,0.5370004177,0.4044150114,-0.5982482433,-1.7088147402,-1.0533634424,1.2031201124,-0.1458389908,0.5778471231,0.0965054780,-0.5388431549,0.8363574147,0.4032280743,-0.2996425927,0.0294992831,1.9186033010,0.9316451550,1.4993157387,-1.7577295303,1.2611371279,1.0125068426,-0.2110064179,0.6125735044,0.7863415480,0.5930656195,-0.4154962897,-0.7229909897,-0.7670542598,-0.4934742451,-1.7241714001,0.9628956914,1.3955906630,-0.4624428153,-0.7550997138,0.2275715172,0.8299591541,0.9396640062,0.9205953479,-1.9562321901,0.5347333550,-0.3697306812,-1.0418801308,0.7764693499,-0.5618635416,-1.3113641739,-1.2335938215,0.7353008389,0.1957557499,-0.7724125981,1.1139376163,1.3518786430,0.0805120543,1.5585693121,0.5469241738,-0.5058984160,0.8069629669,-0.7987787724,0.1504934281,-1.6120203733,0.0503893793,0.7792242765,-0.3512535393,0.0884182081,1.1663037539,0.6744574904,-0.3506546021,1.3014886379,-1.0340659618,-0.3779429495,-0.9123903513,-0.3398987949,1.0012029409,-0.2418974638,0.8322359920,1.2388926744,1.4504948854,-0.0846828520,-1.9022624493,2.3461015224,1.5761616230,-0.4713822901,-0.2990472019,1.4670183659,-1.4660875797,0.1758549064,0.5109443665,-1.3963633776,0.3641264141,0.4785705507,-0.7390723825,-0.1571729332,-0.0894001424,-0.8202293515,-0.0035593198,-0.3045049012,-0.6465057135,-0.5934047699,0.8569859862,-0.4925061762,-1.3001301289,0.1930694282,0.0667027608,1.0578979254,-1.4051775932,0.5545969009,-1.9266557693,-0.3564795852,1.1653716564,-0.6970770955,1.0272433758,0.1583375931,-0.3123612106,-0.9408250451,-0.0537493266,0.4240416884,-0.1350065917,0.4084877074,0.0649588257,1.2394356728,0.0960153639,1.5031138659,0.2776180506,0.7171580195,0.8699058890,-1.8727498055,0.3917263150,1.8253725767,0.2035031319,-0.3448802531,0.8481007814,-0.4494965672,0.8984521031,-0.3145972490,0.1103251651,-0.2218849212,-2.0152313709,1.2233344316,0.6462559104,-0.1851824820,0.5452057719,-0.1294742972,-1.7381348610,1.4482873678,-0.0049621151,-1.7968306541,-0.4029459059,-0.3125780225,0.9872809052,0.7336838245,0.1305475235,-2.8211119175,1.8661111593,-1.2324781418,0.2694059908,0.9574196935,-0.4235167801,1.3931517601,-0.5280845165,-0.7973154187,-0.1673012674,-1.2300739288,-0.1831893921,-0.9138897657,0.5805856586,-0.0222635027,-0.4146025181,0.9250200391,1.1654540300,0.1428458989,2.0506296158,0.8355020285,0.6833344102,-0.6771549582,-0.1392180920,1.3074415922,0.6128761172,0.9603426456,-0.9988200068,1.3938060999,1.4483420849,2.3093905449,0.8961781263,-0.4832390547,-2.5290327072,0.6685495377,-0.9248668551,0.5174524784,1.5624305010,-1.0747776031,0.0684774816,1.2940604687,-0.2854608595,0.8098345399,1.0701078176,0.0960196704,-0.7887099981,0.3971018493,0.3612840474,0.0241373852,-0.2990406454,2.1660528183,1.1026490927,-0.9874019027,-0.0388727337,0.2446159571,-0.5563523769,0.2279099971,-1.0013686419,1.0143290758,-1.5527062416,0.8506965041,1.2558175325,-0.2148320824,0.8770825267,1.1198774576,0.3611235023,-0.2671338916,0.0430668853,-0.1653925180,-0.9529352188,0.0276208688,0.1230975538,0.8873025179,-0.1752104014,0.2513716519,-0.2348491400,2.1551887989,0.7347248793,-0.4261212051,-1.4302924871,0.9446163177,2.5085418224,0.4724510610,-0.1860275865,-0.5170155168,0.8182741404,0.5141733289,0.0327660330,-1.5501236916,-1.9620072842,-2.0062484741,0.9044618607,-0.1077708378,0.6405754089,-0.5198460817,-0.1346986145,1.0445538759,-0.0471237898,0.6623798609,-2.9060950279,-2.2693784237,-0.9272943139,-0.7652207613,0.6250887513,1.0728448629,-0.3229994476,0.6231277585,-0.8498978019,-0.7956701517,0.2162239701,0.3675494194,-1.1451079845,-0.9653976560,0.2594099939,1.9920861721,-1.0531497002,1.0164002180,-2.6073150635,0.1700922847,-0.6301968694,0.2218909413,-1.0393652916,0.1635822654,-0.8220946193,1.2132215500,-0.2270285189,-0.0932268277,-1.9150704145,0.5888198614,0.8222286105,-0.9247884750,0.5923997760,1.2341030836,0.2066896558,0.0557046607,-0.4123021960,-0.5475937128,0.0371494219,-0.4496034384,-0.3558986485,-0.0194285549,-0.2425739467,1.0339695215,-0.9851918221,-0.5976397395,-0.8841294646,1.6174160242,-1.9489552975,0.7389916182,-2.6600670815,0.4461476505,-0.8088853359,0.8462277651,-0.6602464914,1.6914891005,-0.2079225481,0.1770420671,-0.1914528757,1.8777939081,-1.0028346777,-0.3571747243,-0.5823912621,-0.3817023933,-0.7646320462,0.3977974951,2.1370313168,0.0228019860,1.0142006874,-0.5090188980,2.4213712215,0.2384048551,0.4153284132,-0.5815684795,-0.3279374242,2.0014894009,-0.2259496450,-0.7761495113,-0.7924335599,-1.6703323126,0.2091366947,1.5131661892,-0.2143556774,0.4151538014,1.4834935665,1.0899714231,0.3293718398,2.0831754208,0.1978849769,0.2735405862,-0.6502671838,1.2972633839,0.1335616857,-0.3772461116,-0.2008029372,0.0285819676,-0.5361480117,-0.2193754762,0.2928190529,0.1224274337,-0.9885019660,0.0658708662,-1.2322801352,1.8402957916,0.6772176027,-0.7635117769,-0.2598209679,-0.9752302170,-0.9368657470,0.5052095056,-0.5493775010,-0.7561277747,1.1606968641,-0.8948866129,0.7956269383,-1.0711044073,0.4195824265,0.4358394146,-0.5332286954,-0.7573457956,-0.6774635911,-1.6076130867,1.3072478771,-0.5927714705,0.1389958411,0.7185947895,3.7669422626,-0.0290491264,1.9280542135,-0.7334471941,-0.6078340411,0.8206052184,-0.7893049717,1.1871837378,0.5642030239,-0.4392837882,-0.5427054763,1.4480323792,0.9012516737,-1.4478220940,-0.2742679417,0.3881469667,-0.7936916351,0.9068234563,-0.2690926790,0.6635046005,-0.8194814920,0.8768583536,-0.2403390408,-0.4118672311,-0.1585797518,0.7974650264,-1.6701654196,0.2306298316,1.2565150261,0.7238920927,0.2698653042,-0.1637378335,-1.1882640123,0.1818947494,-0.7447010875,-1.3373509645,2.0189678669,-0.2577935159,-1.8308736086,0.5547665954,0.5500036478,-1.5290178061,0.2087140232,-2.4184942245,0.1614990234,-0.5703580976,-0.3850896358,0.3657353520,-0.6663386226,-0.5914227366,-0.1594028920,0.5978386998,0.6462613344,-0.5100587010,0.9332790375,0.1504412591,2.2288496494,-0.0264447983,-0.3791185021,-1.0874207020,1.3430011272,0.1849463731,0.1412463486,0.4610200822,-0.4325022697,-0.1002900004,0.4237989783,-0.0037172488,-0.7439040542,1.3982913494,0.6422342658,0.2297436744,-0.3174774945,-1.8848919868,0.4019989967,-1.0464760065,-1.4771206379,0.9808022380,-1.1731636524,-0.5929113626,1.4529060125,1.8952001333,0.8750221729,-0.8161361217,-0.8773684502,1.5960000753,-0.0505642667,2.1601340771,-0.5453072190,0.0826762095,-0.7931586504,-0.4187310934,0.8851934075,-0.0452485234,0.7194694877,-1.1667468548,-0.8115680814,1.0736287832,-0.0052045393,0.2035568357,-0.2131816298,-1.4077930450,0.4754085839,-1.6127541065,0.9811051488,0.3119699657,3.0805301666,1.3608472347,-0.4485848546,-0.5215060115,2.0166110992,-0.3327984214,1.2407314777,0.6968078017,0.0539997965,0.0699510276,-0.1169878095,0.8041012883,0.1101086438,0.0337015390,0.6410145760,1.6915745735,0.0526624918,-0.2966575623,-2.1406083107,-0.8456923366,0.7050642371,-0.0481108874,0.1677255780,-0.3968006372,-0.2574980557,1.8308932781,0.7751365304,1.7864623070,0.4759546816,0.3503513336,1.3485484123,-1.1443794966,0.4006808996,-0.9962391853,-1.1875445843,-0.9584485888,0.6679587364,0.8440365791,-1.6700847149,-1.6379746199,1.4682731628,-0.1765896976,0.0353947654,0.1196492165,2.1720237732,1.5219050646,0.2371326536,-0.2789554000,-0.6909232736,-0.1486644447,-0.7018318176,-0.6372700930,0.4759524167,-0.6893990040,1.1211477518,-1.2002559900,0.2479523867,-0.1926452816,1.7607023716,-0.5664526820,-1.9813816547,1.9055066109,-1.4104237556,-0.5574155450,-1.0331728458,-1.3837974072,0.2761999965,-1.9508929253,-0.0858562961,-0.4836938679,1.6077718735,0.7905129194,0.2117312104,-0.4057725370,-0.2354757786,-0.2259673476,-0.3836088479,0.3403173387,-0.2910141647,0.2482576072,-1.5559599400,0.3220538497,0.7779824138,-0.2298941314,0.7137753367,0.0410445072,0.8990941048,-0.0591654740,-1.2160205841,0.7276846170,1.3633673191,0.2227507532,0.0442474857,-0.0720062032,-0.4402479529,-0.2421229333,-0.1403012723,-0.8662195802,0.7516864538,-0.5260761380,0.3029883206,-0.1204497144,-0.8628455997,0.6711946130,-1.5811458826,-1.0912187099,1.5749882460,0.8000087738,1.4918595552,-0.0239492729,-0.6851808429,1.6194691658,-0.6268472075,0.7402077913,0.3828008473,0.2770670056,-1.6399253607,-0.7085242867,-0.4483987689,1.1894177198,0.1778671741,0.7329412103,0.2275713235,0.9885006547,0.3365898430,1.0390247107,-0.3508904874,-0.7135981321,-0.5375814438,-1.8914824724,-0.8740919828,-1.0973818302,-1.7287472486,1.2013589144,-2.6296367645,0.7503966689,0.1960070133,1.0780261755,0.5065403581,-0.5458502769,0.3345984817,0.1483134329,0.9152549505,0.1478965133,1.5200810432,-0.7546271682,-2.1418476105,-0.2708940506,-0.2287595272,0.6522660851,-0.2509295642,2.2269825935,0.5684635043,1.0577745438,0.7382932305,-0.0012409586,1.4664787054,-0.1449816078,-1.0437244177,0.6076418161,-0.4137753546,1.8593870401,-1.4749391079,1.8089412451,0.0769915134,0.5412765741,0.3424822688,1.3275287151,0.1800303906,0.0366178341,0.3738724887,-0.7425840497,-0.0967953280,0.6599724293,1.0047409534,0.9127472043,0.5290979147,-1.2235962152,1.8528863192,-0.3413074315,-0.3027526140,0.4114413261,0.9746417403,0.1835276186,1.0362179279,-0.6989639401,-1.2286016941,-1.2848297358,-0.9485433102,1.5757834911,0.2003630102,0.3445673585,1.0008212328,-0.0349921770,3.7082657814,0.8298263550,-0.6615275145,1.3744132519,-1.6828603745,0.5283031464,0.6071580648,2.1209676266,0.9397947192,0.5499040484,1.2169115543,-1.5446734428,0.0012747148,1.7734676600,-1.0784699917,-0.9334080815,-0.3895108104,-0.4134129286,2.5833759308,-1.1176213026,-0.5504791737,0.8675289750,-0.5212416053,0.4319742918,1.1117717028,-1.8729016781,-1.6570641994,-0.9629516006,1.2397440672,0.0037459065,1.0992046595,0.0913702697,1.1402840614,-1.0717334747,-0.9748516679,-0.2703653872,-1.2980529070,0.6257337332,0.6659516692,0.3891419768,0.8163871169,1.4753880501,-0.2891272604,-0.5772545338,-0.3888491094,-0.7375437617,0.1387289315,-0.0836863145,0.1055305451,-1.0039715767,-0.2395810485,-1.6525434256,1.6949305534,0.3663100302,-0.7106671929,0.3623050153,0.1398703009,0.0709123462,0.4497546256,-0.4463917315,-1.8335397243,0.1431326866,-0.5487794876,0.2520763278,-0.4617098868,-0.6493166685,0.8026529551,-1.4981682301,1.4404788017,0.2838287055,0.7307789326,-0.5151305199,0.7872204185,0.8811286688,-0.1221335679,-0.0872639865,-1.3045835495,-0.4357743859,2.2551152706,0.2483468205,-1.9551292658,-0.4188409150,0.0355005972,0.7761195302,0.5764486194,-0.9114215970,0.4186478853,0.0519385114,-1.3720073700,0.9566460252,1.0162568092,-1.2849221230,-0.1405265629,1.1921300888,2.2774107456,0.6626639366,1.2861585617,-0.4691481292,-0.5023907423,-2.0549042225,-0.5954032540,0.6965740919,-0.0113108791,0.9470972419,-0.4827988446,-0.7364525795,1.5049593449,-0.5338101387,-0.5999995470,0.2748598456,1.2512134314,1.3383157253,0.8594609499,0.2186160684,0.7017844915,-0.4627053738,0.0034496156,-0.1348692179,0.3913027644,-0.7634017467,1.2350702286,-0.2394351661,-0.3701135516,0.5651393533,-0.0991172194,-0.0025406210,1.0179543495,-1.3121225834,-0.4948684275,1.2599962950,0.1616281420,0.6271054745,0.3267571032,1.7896078825,-0.1520906836,0.7437182069,0.1602447033,-1.1462504864,0.7538537979,0.1994169801,-1.5422637463,-0.1115837023,-1.1347322464,-1.5603486300,-1.3231898546,-0.5864630938,0.2438378185,1.0190917253,-1.4585080147,0.2916617692,0.1212151349,1.8103116751,0.0997496024,0.8982300758,-0.6879515052,1.4924706221,-1.4564908743,-0.7765069604,-0.9859484434,0.2000730485,1.2155988216,0.0159493014,1.4958109856,0.1811317950,0.5959467888,-1.3172075748,0.2131920159,-1.2470915318,-1.2693005800,-0.5841072202,-0.0466538183,1.4094572067,0.7706953287,1.0238623619,0.5501586795,-1.9324756861,0.8537841439,0.0228950474,-0.9649195671,-0.1006398126,3.7234966755,-1.4024811983,1.4509285688,-0.0061165541,-2.3573803902,-1.7164319754,1.4367122650,0.4027778208,2.0568888187,-1.4577573538,2.1596512794,0.0112678483,0.4823514819,-1.0151923895,-0.2748779655,-0.1498049647,-0.9562303424,-0.4943629801,0.9176456332,-1.1512298584,-0.6620446444,-0.7779641151,0.3872365654,-0.9894063473,-0.7422857881,-0.3691743314,-0.7506567836,-0.1978930682,-0.8630726337,1.1947299242,-0.6482266784,0.6255560517,1.0509376526,-0.1812707335,0.3463947773,1.2976157665,-0.3504452705,-0.4335976541,1.2804650068,-1.0233523846,-1.5230047703,-1.8323204517,1.0930193663,-0.9281481504,-0.5940221548,-0.7265738249,-1.2965354919,-1.0185232162,0.7093110681,1.1391676664,-0.7207520604,0.0884170756,0.2882946134,0.5193282962,-1.4298005104,-1.6081708670,-1.2717075348,0.4682482779,-0.0170615129,1.7580053806,-0.9173281789,-0.4693002105,-1.9680835009,-0.3299243450,1.0726827383,0.8806637526,-0.7417538762,-0.6689109802,-1.7082813978,0.4313643873,0.0347285047,-0.9227795005,-1.4209941626,0.7686933875,1.9805835485,-0.8032012582,1.6413334608,1.3727482557,-1.0299570560,-1.0851159096,1.5018138885,-1.3383134604,0.9689275622,-0.9780363441,-0.4031761587,-0.3334401846,0.6129492521,0.1054987162,1.3304780722,-0.1858203262,-0.4620821774,-1.9098011255,-1.3124620914,-0.7047039866,-0.7252709270,-0.1312124729,-0.9187059402,0.6097781658,0.2633499205,0.6997118592,0.8780248761,-0.1637497842,0.2091602236,0.5623223186,2.0462377071,-0.8705199957,-1.1179158688,-0.5697802305,-1.0332211256,-0.3013561070,-1.1498878002,-1.2747392654,-0.5573811531,-0.4904537797,-0.7212755084,0.3405832052,0.2075432539,2.3557858467,-0.3203197718,-1.0107301474,-0.4470166564,-0.8744552135,0.9583758712,-0.3872155547,-0.3068799078,0.2179597914,0.5574518442,1.4925589561,-1.0170717239,-0.7130813599,0.1082530543,0.7955113649,0.4275724590,-0.7770849466,0.3904846013,-2.1188902855,-0.8035373688,-1.8661222458,-1.3831884861,1.5261973143,0.9782083035,2.0999190807,-0.9385385513,-0.7025492191,-0.5098134279,-0.0868382528,0.6528349519,-1.4956269264,1.7219619751,0.6622504592,0.0382152312,0.4614329040,0.5472880006,0.5798900127,0.5045868754,-0.6498355269,-1.9459872246,1.3929944038,-0.6809290648,-0.2962422967,0.0108508496,-0.9638430476,-0.9484646916,0.5165789723,-0.1640670300,-1.7002995014,0.8765365481,0.1269982159,-1.2878123522,0.6062132716,-1.5158621073,1.2426468134,0.0607079677,0.4924314320,-0.1854637265,-0.1353620142,0.2781190872,0.2474597394,-0.9971805215,-1.0900882483,-1.0746543407,-1.8340034485,0.3812614679,-0.8598755598,-0.1040497944,1.3925131559,0.3986272812,-0.0415031575,-2.3675251007,-0.0305877812,1.6660884619,-0.1070648730,-0.5445333719,-0.7710431218,0.3810178041,0.2547812760,0.0593349338,-1.8837507963,0.5730901957,-1.0793691874,-0.4145066440,0.8921239376,1.0510808229,1.2406498194,0.1838686913,0.2870498300,-1.5952960253,0.3279765248,-0.4117076099,-1.3453356028,-1.2739416361,1.5920748711,0.5261922479,-0.0942941159,-1.0936295986,-0.6000131369,1.0554364920,1.1460963488,-0.8146736026,0.8606137037,1.5689191818,-0.5961349010,0.0758933052,-0.3385274708,1.3630273342,-0.5600120425,0.9728752375,-2.6392047405,0.3673083484,0.9900626540,0.3304453790,-0.1471444517,-0.2834138274,-1.0353995562,-0.5525274277,-0.5576259494,0.1510661095,-0.2260467261,0.2252246886,-0.6449528933,0.5770357251,0.6935384870,-0.1395560056,0.2972361147,0.1321164519,0.1647407860,0.3600349426,0.2307815105,-2.8135678768,0.0207150485,1.1604722738,-0.6801362038,0.8473317623,-1.2867816687,0.9362281561,-1.0985594988,0.3639356196,0.0338978171,1.3219554424,0.1933799237,-0.4506433904,0.8257185221,-0.2247683406,-1.3679728508,1.0385216475,0.9364742041,-0.6909128428,1.5373262167,0.6860220432,0.4178827405,0.6212495565,0.4344584346,-0.8601510525,-0.3218546510,-0.8268820047,-1.5539178848,-0.0130258258,2.2126760483,1.7009296417,1.0740090609,-0.3324290514,-0.8985465169,1.4576840401,0.4782959223,-0.3509194255,1.1262203455,-1.2219204903,-0.2200453132,1.3531450033,-0.1954530925,2.3975813389,1.8100578785,-0.5661913753,0.1861822009,1.3492763042,1.3133230209,-0.6185108423,1.3017319441,0.9068949223,-1.0815957785,-0.4340805113,-0.3503829241,1.4641578197,-2.0569789410,1.0820784569,1.7439060211,1.8248600960,-0.7774598002,-0.4939185083,1.0127602816,0.7717211246,-0.3367897570,-1.2080198526,-0.6399074793,1.1590770483,-0.1210201681,1.1723109484,0.8146342635,0.1039312407,0.8836551905,-0.5924564600,0.1072652787,-0.3974935710,-0.2205309421,-1.1659206152,-0.8362118006,-0.8025512695,-0.2125316709,0.7141345739,0.6295037270,1.1987661123,0.1260221899,-0.1531082541,-1.0310268402,0.0731412917,-0.1965200156,-0.4568440616,0.8053567410,0.2883935869,-0.6044726968,-0.1260431856,-0.0165450405,0.6680634618,-0.2518533468,-1.0752733946,0.3414058983,-0.7781500220,1.3908762932,-0.4280652702,0.3502120078,1.5740196705,1.5462254286,1.3005847931,0.2207820117,1.2206280231,1.2158526182,-0.4125004411,0.3144003749,-1.4685095549,-0.0741400197,0.5391044617,1.2650680542,1.1636080742,-0.6286639571,0.3842039406,0.4505725801,1.3273755312,-0.7348456383,0.7658395767,-0.4287714362,0.3170690536,-1.6846287251,1.2574837208,2.2304196358,0.1366726011,1.1004315615,-0.1765469760,-1.1436213255,-0.4769022167,-0.0776945502,-0.5553138256,0.6878874302,0.7855275273,1.6607589722,1.0358875990,0.4534233212,-1.6446279287,-0.1976266950,2.1636257172,-0.7871826887,-0.2852320671,0.4802152514,-1.8419892788,-0.2016286850,-0.0867040604,-1.0645453930,-0.8415598869,1.5475199223,-0.3730809987,-1.4787642956,0.2056966722,-0.3578105569,-0.1109743640,-1.2149100304,1.2062696218,1.3023071289,0.9274048209,-0.7516996264,-1.3269295692,0.3645735383,0.2758433521,1.9448007345,-1.4305678606,-0.0758651718,0.0477598943,0.7821953893,-0.5015829206,-1.6125231981,0.1059435233,0.6842874885,0.9025937915,-0.6946648359,-0.2183943540,-0.3142189384,-0.0116561214,1.1320439577,0.6315576434,-1.1208635569,-0.3343107104,0.5499612093,0.8175386786,1.5596295595,0.5662127733,1.5119391680,-0.1291352212,-0.1208290309,0.5914816260,-0.8418577313,2.0425741673,-0.2564697862,1.2515211105,0.6368747950,-1.1409413815,-1.0605794191,-0.1664215922,-0.9259193540,2.5111291409,-0.0861898288,-2.0625565052,0.6647928357,0.0328417681,0.5346663594,1.9692085981,0.4651908278,0.0526132919,-0.4012923241,1.6575239897,1.1805459261,0.5314475894,0.7792928219,-0.5494493246,0.3818164170,-0.0567653663,0.4041859508,1.4742921591,-1.0135000944,0.4748797119,0.7541258335,-1.0927159786,0.0926267952,0.9003172517,-0.5001785755,0.5012148023,-0.6418183446,-0.9861421585,0.9376791716,-0.5699564815,-0.6094684601,-1.0713261366,1.9327700138,-0.9455596209,-0.9719607830,0.6471062303,-0.0367334001,-0.5560221672,-0.3756830692,2.0556206703,-2.3344113827,0.3166075051,-0.0935946330,0.9930018783,0.5013293028,-0.1114913821,1.7273072004,-1.0956972837,0.1108219996,0.0784082487,-0.1691263020,0.2886268198,1.7784488201,0.1265564561,-0.5149015784,-0.2519254982,-1.0531100035,0.7891155481,0.4315459132,-1.5275148153,1.4729213715,-0.3302557170,0.0881882012,-0.8817841411,-0.7540366650,0.8779074550,-0.8743508458,0.2878976464,-0.5434914231,1.0279676914,0.9953140020,-0.8819229007,-1.3638242483,0.3675503135,-0.3905891180,-0.7033363581,1.2411277294,-0.3832196891,-0.5711125731,-1.4024157524,-0.3557167053,0.3662314713,-0.6938498020,0.0533289164,0.3695681691,0.1856286973,0.0036913755,0.1313543767,0.8270304203,1.3178888559,-0.3671407402,-0.2499872595,0.3193106651,0.3666144907,-0.4536692798,0.0637796372,0.6246864200,0.0064440314,0.4970657527,-1.6432136297,1.0414912701,0.5748828053,0.1528365761,1.0264930725,0.0289772060,-0.7684674859,1.8304229975,1.9216315746,-1.1279611588,-0.2746619284,-0.1850537807,0.7062392831,0.3555676937,1.0713543892,0.4431940615,0.1439880580,0.9895448685,-0.0911555588,-1.7978384495,0.5766109228,-0.0966744050,0.0376248136,-0.9085863233,1.7782652378,1.0522457361,0.6517040730,-0.8900560141,0.6581432223,0.6606887579,-0.4885232449,-1.1564961672,1.9684470892,2.1824321747,-0.3049057424,-0.8701323867,2.3631441593,0.3133211434,-1.1149035692,-1.3495191336,1.9155670404,-1.0757849216,-0.6060916781,0.3758997321,-0.9581190348,0.6761481762,-1.5759015083,0.0877688527,0.9830061197,0.5539374948,1.0762681961,0.2258782238,1.5641163588,-1.3022426367,0.4803126752,0.6107187271,-1.0131540298,-1.5784831047,-0.8989061117,0.4761588275,-0.9230661988,0.5590661168,-1.0126085281,-0.3330108821,0.4091787934,0.8562009931,1.3837891817,0.9529459476,0.0378294997,1.7116134167,0.1376933604,0.4267888963,1.4159948826,1.1380883455,-0.8711742163,1.3790419102,-1.1110154390,0.0842593387,-0.2383049726,0.3928242922,-0.0319515020,0.6350234747,-0.5745252967,-1.0377408266,-0.5247514844,-0.3461388052,0.2433131039,1.9716480970,0.8219295740,0.6601530910,-0.9692701697,0.3216661215,1.2229069471,0.9288674593,0.3407813609,-0.0449075103,-0.6433902383,-0.3510982990,0.4039245546,1.4285668135,2.1478550434,0.1891006231,0.5928854346,-0.0630526319,1.3296774626,-0.2089577764,1.1789846420,-0.8879231811,-1.1200343370,0.5014985800,-0.6400913596,1.3707021475,0.8418042064,-0.0632963851,-1.1129459143,1.2401936054,-0.2269525230,1.8008857965,1.1790270805,0.5483096242,-1.9282461405,-0.0091208350,-0.0526960641,-0.5831608176,0.7987315059,-1.6418938637,-0.9462875128,0.3626517355,0.7144135833,0.0920099840,-0.1160614640,-2.1590559483,0.8512916565,-0.9435035586,-3.0365452766,0.3538107574,-0.9204629064,-1.2248587608,-0.4802761674,-0.0648367479,0.3905614316,0.5931641459,0.4110111594,1.9805357456,-0.5985766649,1.4174280167,0.2611472011,0.4249542952,0.8081253767,-0.4066265523,1.3087968826,0.3670448959,-0.4409090877,0.1955190897,0.8306531906,1.0105479956,-1.2028720379,1.6242797375,-1.0599883795,1.1703038216,0.3944687247,-0.0508274548,-1.7612975836,0.9173631072,0.1352318525,-0.9668301344,0.9786379337,0.9339951277,-1.3411684036,-0.8798589706,1.2675123215,-0.3759378195,1.0647661686,1.0037868023,-0.5811907649,-2.7897138596,-0.1828412116,-1.3186894655,-0.6859114170,0.3702635467,0.1879754215,-0.2166812122,-0.4224203527,-1.1869359016,1.4768501520,-0.1624441296,1.3615174294,0.0276617203,1.2067369223,1.8776559830,0.4511460364,-1.2373962402,0.7331387997,1.7680873871,0.9055304527,0.3431780040,-0.7190120220,-0.8236030340,0.3431842923,-0.2256057709,0.1887262464,0.7279495001,0.1026036218,0.0037209450,0.2864089906,0.1306706518,0.3032578826,-1.9690222740,-0.3773420453,-0.3418140411,-1.1602931023,0.6077716947,0.9177352190,-0.7473893762,-0.3076132238,-1.1850211620,0.1065358967,1.5186152458,0.7725510597,-1.0014253855,-2.1937179565,0.3250127137,-0.6440759301,-0.1811335981,-1.1045614481,-2.1818692684,-0.2243866771,-0.0173453316,0.3536208272,-0.0725474954,1.8809698820,-0.2315787226,0.8793317080,1.1665952206,0.0993929505,-1.4947397709,1.0953342915,-2.2650103569,1.1013573408,-0.3124994040,-1.2784965038,-1.7349416018,-0.7721288204,-0.9405128360,-0.0988894254,0.9771395326,0.6489016414,1.6465309858,-0.1293012649,0.0067455000,1.6675785780,-1.0477951765,0.4693665802,-1.3260034323,1.6122599840,0.8219315410,-0.2401393354,-0.4720887244,1.1021941900,0.4860531688,-2.6774544716,0.7096341848,2.5483486652,-0.2957075238,-0.6031370759,0.1926307380,-0.4034855664,0.1463181674,0.5350070596,2.0819504261,1.8139798641,-1.0643401146,-0.3128781021,-0.1442638040,-2.1851909161,-1.5748522282,-1.0711203814,-0.4753435254,0.0661187768,1.1281665564,0.1130188406,0.8959493637,-0.0683412403,-1.3801412582,-0.9871893525,-0.7403144836,-0.8445615172,1.6470441818,1.0460041761,0.6926950812,-0.7393996716,-0.9453443885,-0.2465624362,-1.2683348656,1.9672598839,0.9712939262,-0.7164001465,1.2384980917,1.3134400845,-1.2783517838,-0.9249799252,-0.9393361211,-0.6579603553,-0.2182013690,0.9198998809,1.2773807049,1.1855596304,-0.6381624937,-1.0942879915,0.4838123024,-0.4306229949,0.1810165793,-0.1996294707,1.2885905504,-0.1678638160,-0.1881410182,1.3225277662,0.0953734741,1.8875477314,0.0770172328,1.6916360855,-1.7926950455,0.4905884266,1.0937842131,-0.0595675372,0.9946762919,2.0324313641,-1.0170233250,2.0547215939,1.6750184298,-1.0087105036,-1.6904520988,0.3167631328,0.6377083659,-0.7585461140,-0.6136844158,-1.8868082762,-0.1847042292,0.8395951390,-0.1964798272,0.0806577355,1.1836705208,0.6784030795,0.8249893785,-1.2950379848,-1.1152267456,0.6911618710,-0.4725620151,-0.6914433241,-0.2887046039,0.8318896294,0.5734977722,0.7145007849,1.7885981798,0.0377317369,0.7398540378,-0.6245130897,0.7582843900,0.8068283796,1.8076828718,0.6233335733,0.6361873746,-1.2487183809,0.2187319547,-0.6943225861,0.3531611562,0.8272674084,-1.9904072285,-0.9367148280,-1.0429241657,0.6981034875,-1.5150380135,1.4994618893,-1.4663890600,2.2427587509,-0.3023525774,-0.6387372613,-0.8940060735,-0.1322064400,-1.0280362368,-0.4068548679,0.2255519480,0.9413877130,0.0257321727,-0.1329892278,-1.6131180525,0.8192076683,0.1125036925,1.3352439404,0.6392394900,-3.1156716347,2.0869877338,1.0112729073,2.4250719547,-0.1496810317,0.7387430668,1.2361007929,0.0684093386,-0.9277183414,-0.1533320844,-0.7304266691,0.6191169024,-0.7954546213,-2.1412179470,1.2499122620,-1.3871273994,2.1028695107,-1.0435626507,-0.5314572453,0.2357278168,-0.7836205363,1.6709499359,1.4669779539,3.1746845245,1.3023787737,2.3591947556,-0.1380295604,0.9297934175,-0.5155693889,-0.1036393195,-1.1186670065,-0.1851234734,-0.2512214482,1.1714904308,-0.2232470512,-1.4790050983,1.2210992575,1.7563029528,0.4102286100,0.0601698495,0.2168567479,-0.8762237430,0.9252765179,-1.7906960249,-1.3530749083,0.0037942464,-0.6046807766,-0.4491837025,0.1465787441,-0.2187786400,2.6423318386,1.8395512104,-1.2164244652,-0.0062938496,0.7514982820,-1.7471815348,1.3979443312,0.4519581199,1.2722970247,0.0478293486,0.0334270969,0.5252046585,0.8231018782,0.4410232306,-0.2736770213,-0.6498092413,0.6456122398,-1.5126706362,-0.9126222134,-1.0825484991,0.8857665658,-0.4664177299,1.2132717371,-1.1514225006,-1.0739794970,0.1377086192,1.9164336920,-1.2203828096,-0.7694478035,1.3315281868,-0.7050071955,0.8304207921,0.6928241253,-0.4450389445,1.1498022079,-0.6999378204,-0.6708523631,2.8639185429,0.7906737924,0.6672154069,0.7954690456,0.1095909402,0.1944302619,0.0010998135,-0.4005476534,0.2124238312,0.4286309779,0.2146281302,0.6275988817,-0.0620207116,-0.4323121309,-1.7828309536,1.5191432238,-0.3685704768,0.3279248774,0.2474352568,0.7215018868,0.7299074531,0.0056346082,0.6240631938,-0.7521722317,0.7414829135,1.3525691032,0.2047773600,0.8658626080,-0.2844838798,0.5375939608,0.0502211004,-1.9202650785,0.6328778863,-1.0243452787,-0.3291671872,1.2854202986,-0.3071571589,1.1487460136,-0.6724426150,0.9937167764,0.0755469427,0.0181107987,0.3345252872,0.0915125236,-0.1587377340,0.9943240285,1.0686699152,-0.0836843699,0.8532247543,-0.1283108890,0.5830957890,-0.5074785352,-0.8843220472,0.9858810306,0.4600271285,-0.9244024158,0.2015917897,-2.2051551342,-1.3684561253,-0.0070179529,0.9507652521,-0.8961302042,1.3040012121,-0.4097203612,0.5474057198,1.3817955256,-1.2054364681,0.5918625593,0.2912769020,0.3815670609,-1.7695758343,0.2565854192,0.6678588390,-1.9968492985,-0.4847605526,-0.4586411417,-0.2693426907,-0.1771221757,1.7575697899,0.0226126239,1.3108720779,-0.1741402000,0.5192768574,1.5016207695,-0.3459168375,0.8827842474,-1.0666747093,-0.6622051001,0.2035106122,-0.0336035080,0.4757933319,2.3770163059,0.7890660763,-0.4296334386,-0.6260621548,0.8593677878,0.9754520059,-0.5508008003,-1.9562290907,-0.4794707298,2.1985228062,0.7364495993,0.2542623580,0.2583675385,-0.0006999811,-0.0937647223,0.0307967123,2.1079499722,-0.9306992292,2.4908797741,-0.0683824047,0.8416444063,-1.4192576408,-0.2434727401,0.7902024388,-1.5382992029,0.9410758018,-0.7255437374,-2.1972353458,1.4353498220,0.6533204317,-2.7115106583,0.6271278262,0.3922728002,0.1899161339,-0.2647828162,2.3061597347,-0.3845082223,-0.2433109134,0.4348921478,-1.5491979122,0.1541192085,-0.4593312144,-0.9138321877,-0.1297478825,-0.2293144763,1.6444797516,0.9206303954,0.2121412903,-1.3027334213,0.8136668801,-0.7190756798,-0.3822887242,0.2437139153,-1.1598749161,-0.2366128266,0.9961916208,0.9275527000,1.0301316977,0.8716277480,1.1247831583,0.7137174606,-0.0485413894,0.5693393946,-1.9486206770,-0.4884814322,1.6192941666,0.8910787106,0.0180339478,-1.7390911579,0.2681433856,-0.1390723884,1.0840507746,-0.3824338019,-0.5290316939,-0.6295898557,-1.5379174948,1.1584496498,0.6609149575,-0.6455150247,-1.4774763584,1.3007858992,-0.8344992399,0.2422126979,-1.0668669939,0.7216842175,-0.2747242153,0.6934828758,-0.3771536648,0.2721296549,1.6877368689,-0.3436425626,-1.3526052237,0.6161730289,-0.3104036152,0.4038379490,-0.8696197867,-0.0881191045,0.8002542853,0.2152355313,-2.1688718796,-0.1544931531,0.5612537265,-0.7872266173,-0.6685209274,1.3880770206,-0.0438574255,0.6691686511,-1.1393299103,1.5715401173,1.7690942287,-0.1770737022,-1.2838332653,-0.1482763737,-1.1807324886,-0.1246396676,0.5556858778,-0.5587546825,1.9595792294,-1.0273351669,-0.2892897129,2.1519374847,1.4404784441,-1.6324875355,0.9220415354,-0.8804201484,0.9086288810,1.3144823313,0.1263292283,1.1237426996,0.1560661346,0.9178130031,1.0348485708,-0.0764593482,-0.1803882867,0.4778284132,-2.6791322231,-1.4770958424,0.0729591846,-1.4535052776,0.1024222225,-1.0942270756,0.3704869747,0.4322766662,0.2548621595,0.6323297024,-1.3469249010,0.9590857625,-0.7356510162,-1.4300709963,-0.8788210154,1.3715491295,1.1217643023,-0.5817310214,-0.6780789495,0.1847612560,-2.2621667385,-1.3844285011,-0.4063298106,-0.4010620713,1.0016220808,0.0181291588,-0.3874219656,-0.6327757835,-0.6283560991,-1.4798924923,0.0586887263,-0.3952905834,-1.0938864946,0.9593856335,-1.2852833271,0.5518447161,-1.1919951439,0.4875165224,0.4057821333,0.9937305450,-0.9238799810,2.6145756245,0.4748609662,-0.3027443588,0.2600146830,-0.2662793696,0.5243310928,-0.7458996773,-1.3094813824,0.2878949642,1.0456981659,-0.3525495529,-0.8172661662,0.2186447978,-0.5194003582,-0.2409159392,1.5012190342,-0.3814423680,-0.2719659209,-1.6522637606,0.8976294994,1.6063685417,-0.3337241113,-0.7124217749,0.8000403643,0.0348635353,-1.2435899973,0.2742917240,1.2672042847,1.3071616888,-0.3089774847,-0.5630499721,-1.6949775219,-0.3910141885,-0.4686586857,-0.4318181872,-0.4553795457,-1.5290528536,0.7596347928,-1.2247896194,0.7929475904,3.2648231983,0.0765919611,-1.7044337988,0.5527252555,-1.2542990446,1.0776225328,0.7700014114,0.3957244158,1.0734199286,-0.3395042419,-2.0320532322,-0.7339397073,1.7088943720,-1.7991150618,-0.3706928492,0.2754571736,0.2273407429,-1.0307626724,1.1256923676,-0.8246914744,0.3956819177,-0.9917507172,0.7536754012,0.6936249733,1.8786382675,0.5164870024,-0.5184623599,0.1207001433,0.2281433642,-0.9246230721,-0.0446610264,-0.3871702552,-1.5042041540,-0.0066607548,-1.5743414164,-0.2049447745,-2.2182295322,0.2431137711,0.5944489241,0.5098665953,1.4379987717,-0.4044253528,1.0512136221,-0.6692307591,-0.5159274340,-0.5512489080,0.5259061456,0.2661730647,-1.5106946230,1.9273676872,0.5774011612,-0.4199075699,1.3673183918,-0.5175925493,0.0277764630,-1.0282031298,-1.2392059565,-0.3175444007,0.0651226565,0.1687745154,-0.7958122492,-1.1371675730,1.8399970531,1.0105547905,-0.5101677179,-2.0513987541,-0.2365717590,1.0404173136,0.8387218714,-1.5863597393,-0.2953415215,-0.3548167348,-0.8969500661,-0.5921047926,-0.4963432848,-0.7090011239,-1.4159350395,0.0659552068,0.6083223820,1.4280581474,-2.7973577976,0.2793337703,0.4457551241,-1.1316871643,0.7324762344,0.0465258770,1.2708383799,-0.8990916610,0.9488687515,0.9713152647,-1.1941430569,-0.3017987013,-0.9432987571,0.7103397846,0.1358730197,0.1415656805,0.5150106549,-1.7309122086,-1.9883096218,0.7167133689,0.0778244287,-2.1529717445,-0.9673052430,0.3667652607,0.1836275011,0.5833052397,-0.4578369260,-0.4256786406,-0.9554052353,1.3549624681,-0.4652006924,-0.2363625318,0.0994006470,-0.6568480134,0.0348669849,0.3077637255,0.3547363579,0.8136194944,-0.6794636250,-1.0101652145,0.7936237454,0.7654732466,-1.3967742920,2.0011563301,-0.8323894739,-0.1461954713,1.0044622421,-0.6343291402,0.2242664993,1.7496575117,-0.4828544855,2.1647851467,0.7960585952,0.0863240808,-1.8356450796,-0.1754117906,0.9070207477,-1.2061300278,0.6664801240,0.2954353392,1.9272356033,1.0407719612,0.4945245683,0.5699928999,-0.1160124764,-0.4865684211,-0.0170620270,-1.6850682497,0.6151177287,-0.6133508086,-1.4380831718,1.6350381374,-0.2955036759,-0.4080443978,0.6777896285,-0.7060639858,-0.4976985455,-0.9679428339,0.0706002116,0.0416285954,0.2848752439,-0.8778271079,-0.1663546264,-1.4794622660,-1.9278879166,1.6978425980,1.7794172764,-2.9531173706,-1.2205433846,1.5037174225,0.5455800891,0.6231148243,-0.1637870520,-0.1267165393,-0.6366458535,0.4950649738,0.3843171895,0.3920426071,-0.8354402184,-0.2788834572,1.0194483995,0.0986561626,-0.5203149319,-0.0823765323,0.0222817399,-1.2570695877,0.0349741466,0.2028528899,0.2815420926,-0.1766107976,0.2764383554,-1.3478579521,1.4862694740,-0.4602116346,0.1060000360,0.6406856775,0.6851381660,0.9093105793,0.5848791003,0.1880259067,-0.9595815539,-0.2873590291,0.5662950873,-3.1337368488,1.4183876514,-0.3170253038,-1.9341831207,-0.7753921151,-0.5650481582,0.9571687579,-0.0570281744,-0.2114823312,-0.1237578094,-0.5994918346,1.2810485363,2.4784626961,-1.4082845449,0.6607084870,1.2495912313,-0.8925880194,-0.8004648685,-0.1284520179,-0.9761826396,-0.3523084521,1.5950284004,1.3361389637,-0.4479740262,1.9581365585,-0.1791668683,-0.7813001275,0.9748125076,1.9654608965,2.1079697609,-1.1303747892,-0.3680176139,-0.1541169137,-0.4737612605,0.2893137038,0.0942446738,-1.2750767469,-1.6875716448,0.0291447006,0.9104262590,-0.7338591218,0.1654359996,0.4833254218,0.1837635785,-0.0783622116,2.0477280617,0.4575521946,1.4642084837,1.8992501497,1.3101515770,-0.8264897466,1.1015996933,-1.8358174562,-0.5262581706,-1.3427133560,-1.8201973438,-1.3885704279,-0.7330588102,0.9829092622,-1.1346485615,-1.8879934549,-0.4256469011,-0.5990062952,2.0774192810,-0.2175528258,-1.3139890432,0.8544276953,-0.8505318165,-1.5247815847,1.0540881157,-0.7676452398,-0.0154721728,0.0645280629,1.1965137720,-0.7829078436,-0.7461743355,-0.9474745989,-0.4311519861,-0.1322558373,-1.4352858067,0.3022035360,0.8314113021,1.5980254412,-1.2497850657,-0.4789477289,-0.4042346478,0.9194238782,-1.9574488401,-1.5083035231,-1.0556405783,0.3304715455,0.4454304576,0.7204989195,-1.4876512289,2.3934466839,-0.3657112420,-0.6892605424,0.7944124937,1.1503497362,-1.1436711550,0.4530783594,0.1073921546,0.2563025057,-0.2650616765,-0.5858703256,0.3914135396,-0.0370595977,0.6986816525,-0.6059454679,0.7438039780,1.5383099318,1.5709109306,-0.0677266866,1.0556417704,-1.0941773653,-1.9463193417,-1.5928672552,0.7118583918,-0.1078235880,-0.1363062114,-1.1848173141,1.0763760805,-2.1852428913,-1.0170569420,1.0829125643,0.2023819089,0.3322030008,-0.8313293457,-1.2125116587,-0.7498506904,-0.6480713487,-1.0642518997,-0.0535658970,-1.5605756044,-0.3149810433,-0.6010142565,-0.4871916175,0.8242281079,1.8240424395,-0.0996669456,1.5988140106,-0.5990390778,0.0666736066,0.0582151599,-0.4938335717,0.1771529615,-1.6437077522,-0.5018564463,-0.3862938881,0.2370947152,0.4438247681,1.8506821394,-0.8399331570,1.2295398712,-0.0405258946,0.5014107227,0.3826455772,0.0491048954,-1.0085386038,-1.4686864614,0.6855700016,-1.0127818584,0.3318201005,1.3520195484,-1.1127836704,1.1357103586,-0.9928646684,0.8556365967,-1.0570096970,-1.6995784044,-0.9159128666,0.6399106979,-1.0972138643,0.7753602862,0.4758385718,2.3228681087,-0.0455329157,0.8702580333,2.2876014709,2.2667026520,1.0052275658,-0.5927371383,1.3670648336,-1.1437461376,0.3765378594,0.7944192290,-0.1012149379,1.0979666710,-0.3328878284,-0.5348561406,-0.0316795930,0.9100095034,0.7350540757,-0.7042039037,-1.0100349188,-2.6791682243,1.0962806940,0.8025962710,-0.0379705727,1.4441269636,-1.5085335970,0.0003205369,-0.0880573839,1.1053018570,0.1118759215,0.9201207161,3.1936144829,-0.5558418632,0.4877890944,0.0970641673,0.4611878693,0.2145508379,0.0961457565,-0.0012075664,0.4158501625,-0.0128498999,2.2061691284,0.3245992959,0.5149602294,-0.8647653461,-0.4778534770,0.1767767519,1.1144613028,0.7067543268,0.2953458130,0.4151735902,1.3802677393,0.4514097869,1.4310191870,0.1890203953,-0.0607744493,-1.0145285130,0.4822328091,0.0662695393,0.5966459513,-0.3585332334,-0.4946506321,-0.5472767353,-0.0253793262,1.2802063227,-0.5363033414,0.4587896466,0.2496608347,-0.7562409639,0.6417131424,-0.3292468190,0.4829611182,0.0107420720,1.8334723711,-0.8969556689,-0.5865179896,1.4124860764,0.9335811734,0.6803567410,-0.7399356961,-0.9453975558,0.0589627735,0.9332634807,0.2295327932,1.2144051790,-0.9396538734,0.7404459715,-1.4058126211,0.3758881092,-0.5415832400,0.3609177470,0.4216291308,0.0672683716,0.4954783320,-0.3137744963,0.0770393088,-0.7609525323,0.6436778903,0.6758462191,-0.2501106262,-0.1796221882,-0.4029569924,0.2886023521,0.1287038326,1.7206531763,-0.2571421862,1.5516285896,0.1779292226,1.8721263409,0.4874676168,-0.3857848346,0.7131745219,-0.1883796006,-1.1051175594,1.0015405416,-0.0806301087,0.5015828013,-0.7649217844,1.2179169655,-0.6834611297,-0.3220885992,0.1348572373,0.3637213707,-0.0528043061,1.0957769156,0.2416266203,0.3221211135,-0.1729038656,0.4899542034,-1.3926836252,-0.8075534701,-0.4263211191,-0.3185393810,1.8184756041,-1.4812299013,0.4924119711,0.1793278903,-0.3062870204,0.7527695894,0.6813973188,-0.4136724770,0.1930301487,2.4636559486,1.0544172525,0.5969682932,0.3538553417,-0.7953445315,0.4444134831,-0.9988148808,0.2708710730,-0.2231728882,-1.5424858332,0.0671981946,0.7165861130,-1.7390002012,0.1175277680,0.5987126827,1.2449854612,-0.4765720367,0.9063929915,0.5871992111,-0.2316968739,-0.4770857990,-2.0407674313,-0.8889138103,-0.4778654575,1.0535147190,-0.8856458068,-0.0943486169,-1.9650886059,1.5634150505,0.9272034764,0.8704501390,-1.2399034500,-0.0045439149,0.0171208791,1.5940405130,0.5065575838,-1.0628005266,0.6307820082,-0.0456372090,-1.1207317114,0.0359663069,-0.6097961068,0.2768594623,-0.9132888913,-0.8086346388,-0.5995755196,1.0584326982,-1.3386423588,-0.0910859630,1.2630821466,-1.1991431713,-1.0497963428,0.6557671428,-2.8756728172,0.0049800058,1.1699956656,1.7030316591,0.5046100020,-2.2967424393,-0.4492062628,-0.4919267297,-0.8143878579,-0.7950159311,-0.5516642928,-0.1837606877,2.1352300644,1.1462190151,2.0455040932,-0.5048813820,0.8189655542,0.1658494473,0.3154302835,1.2556283474,0.7457754612,0.3385994136,-1.6795654297,-0.6067926884,1.2469490767,0.5089952946,-0.0530367568,0.5155069828,-0.6019174457,-0.1175310239,0.3800863326,1.4116129875,0.4822998345,0.6734839082,-0.7265940905,0.9609754682,-1.0695693493,1.2773134708,-0.0383228734,-1.1684441566,0.6060315967,1.6832801104,0.7533211708,1.5771530867,0.4684437513,-0.2532663345,1.5824003220,-2.6677989960,0.7695742846,0.4340322316,0.6323025227,-1.0616002083,0.6552160978,-2.0156300068,-0.2300008535,0.6324152350,-0.8441838026,-0.7557621598,-0.1748217940,-0.6759279966,-0.8832311034,2.3019340038,-2.3870930672,0.0982676297,0.1205674782,1.3445794582,-0.2255969346,0.6980847716,-0.4308630526,0.8111328483,0.9373266101,-1.6052649021,1.4621964693,-0.2540515065,0.8156651855,1.0076911449,-1.7301025391,-1.6204510927,0.7440069318,0.0341309048,1.5476413965,-0.8900391459,-0.3766621947,-0.6074256301,0.3939062655,-0.5218016505,1.2918245792,-1.3143782616,1.5072596073,1.0231168270,-0.2359389961,-1.1725305319,-0.9327100515,0.6893956065,-0.2224030793,0.1603256017,-0.4459508359,-0.1136763841,-0.1959608495,0.7789053321,1.0510292053,-0.0700007603,0.5266662836,-0.9966610074,-0.9432050586,0.7437862754,1.3008739948,0.3434124291,0.0258266907,0.0869140998,0.6960690022,0.7120946646,0.0515276678,-0.0726527721,-0.3411781490,-1.3804582357,-0.2881645858,0.5035392642,-1.3463668823,-0.6638413668,-0.5775796175,-0.5389131308,0.4343502820,-0.2203941643,1.6989192963,0.5641354322,1.6838576794,1.2410887480,0.1104821563,1.7673959732,-0.8824916482,1.3487502337,0.5774065256,-2.2027637959,0.3938376009,0.2434094995,-0.4469590783,-0.1877329051,-1.0865863562,-0.6238707304,0.1701171249,1.0134552717,-2.2195823193,-0.5561084747,0.0621400401,0.2244819254,1.0336713791,-1.3963009119,-0.2985310555,0.3228592873,1.3612934351,-1.4880374670,-1.6463325024,0.4461197257,-0.3382137716,-0.4326903224,1.2684216499,1.2643234730,1.0895330906,1.2925497293,0.1350784600,-0.4523508847,-0.8258852959,-1.7149457932,0.6874905229,-0.7296146750,1.2389507294,0.9146369100,1.3814866543,-0.0028754754,2.3910377026,0.1634847671,1.5939153433,0.1600411683,0.3318611383,0.4221729338,-0.9187315702,0.3347060084,-0.4368286729,-1.2759553194,1.1613256931,0.4264028370,-0.2972605228,-0.0180641264,-0.6553592682,-0.5903983712,-0.5169649124,-0.4399635792,0.0741655752,-1.2233260870,0.2017238438,0.9079591632,1.0736171007,-0.4128850102,-1.1717312336,0.6035646200,1.5451973677,0.6227061152,1.2984673977,1.6092420816,-0.9485616088,1.8946329355,1.2957694530,1.0307075977,1.4255412817,1.7190335989,-1.3016798496,-0.9480474591,1.1068694592,-0.8514854312,0.3590765297,0.4884167910,-0.2413618565,-0.2864337265,1.9658122063,-1.2297976017,-1.3506499529,-1.0592341423,-1.2962996960,0.6311379671,2.3245151043,-0.8188385367,0.6870383620,0.0071533509,0.4189999998,0.5118589997,0.9282453060,0.1976849586,-0.2832446694,0.4292204082,-0.1534999758,1.5900549889,-0.2832624912,0.9434610009,0.7822171450,0.7615031600,-0.3012326658,-0.1083905846,-0.3890056610,-0.5637946725,0.0940228626,-0.1532761008,0.4407454431,1.1213968992,-0.7484930754,0.4968990684,-0.8124283552,0.8374453187,-0.5514011383,0.7271595001,1.1901440620,0.4425831437,0.7223262191,0.0920367613,0.1827518195,-0.9553514719,2.2778782845,-0.0951565281,0.6599346399,-0.4985764623,-1.2338274717,-1.0685179234,0.5681238174,0.4908271134,0.2003903836,-0.1043929160,-0.6512681842,-0.0636266619,0.0732113644,0.4932597578,-0.9207543135,-0.1076298058,-1.6838189363,-0.2428099662,0.7228756547,-0.4640580118,0.6245583892,-0.7864403129,0.9854980707,0.1483794004,-0.1238286272,-1.9773298502,-0.6761142612,-2.0313007832,-2.1170983315,-1.5734508038,-0.8779585361,-0.0909841582,1.4897482395,0.6401346922,-0.4880248904,-0.4623247981,-0.2730410695,0.2345179766,-0.2584047318,-1.0733059645,-0.6118106246,1.8113634586,2.0679802895,-0.9476329684,0.7383434176,0.0674313679,-1.6945581436,0.3529974222,-1.2724621296,1.0977891684,-0.8179125190,-2.8983523846,-1.2201880217,-0.1745642573,0.0033349809,0.2662228346,0.7162650824,-0.4651221633,0.5385454893,1.1434221268,-0.4105019867,-1.6019604206,0.6570641398,0.3827970028,-0.8969772458,-0.6783589125,0.4421870112,0.3902520239,1.2652155161,0.8713499904,-0.1916929632,-0.1945413202,-0.4036102295,-0.0592381246,-0.7947420478,2.4768147469,-0.5596383810,0.0513080209,2.2183132172,0.7428569198,-1.1224207878,1.2905070782,1.6988288164,-0.0087889144,-0.3099016845,-1.0261619091,1.2815786600,-0.3887642324,-1.8203357458,0.6565842628,0.8482696414,-0.3657097220,2.5571284294,0.9646287560,0.5014576912,-0.7785434723,-1.0838786364,-1.0007174015,-0.6832125783,0.6869196296,-0.8909994364,0.7105440497,-1.5718376637,-1.0136063099,-0.4651289284,-0.9581088424,-0.4869917929,0.8937326074,2.2701437473,-0.5487756133,-1.2599574327,0.2497866601,-1.0012441874,-1.0906326771,-0.0996188372,-1.5389875174,-0.3022162914,2.1879057884,-0.7253212333,1.0624971390,-1.2916557789,-0.3524868786,-0.9313794374,-0.7848801613,1.5815815926,0.1106806770,0.4807272553,0.6900759339,1.2145121098,1.1435748339,-0.7682368159,-0.1096613705,0.6715409160,0.0713482127,0.2610453367,-0.2741608322,-0.2731364667,-0.6862300038,-0.4789772928,-1.3881918192,-0.6710447669,-0.2162043303,1.2445957661,1.1760710478,-0.5608954430,0.2300017178,-0.5237638950,-1.4979652166,-0.4840055704,-1.0160231590,0.0633943900,0.2442258596,-0.1619214714,-0.1240627095,0.2674188316,2.1347377300,0.7680336833,0.7131571770,-2.2288031578,0.3683202863,1.3970509768,0.2402867228,-0.3467687964,1.0369762182,0.9858167768,1.7241109610,0.3450718224,-0.3579460382,-1.4150452614,0.3929713666,0.4741328359,0.2615441382,1.3558253050,-0.1826655865,0.7189281583,1.1006554365,-1.2778162956,-0.6737187505,0.2032980323,-2.3750617504,0.5275279284,0.0699259490,0.0522095188,-0.0179084744,0.7750706077,0.3565326333,0.2300423533,-1.4687960148,-0.0426535085,-3.7455356121,-0.7975733876,-0.2791737318,1.7593774796,0.0835426897,0.8876459002,1.1769098043,-0.8923800588,0.6272987127,-0.8653988838,0.5507037640,-0.1309112310,-0.7270892262,-0.5536189675,0.1476335227,0.9601663947,0.4076004028,-0.8485045433,-0.1765632182,0.2317116857,0.0372135900,1.3644959927,1.3756741285,-0.2507399023,-1.8323187828,1.4180147648,0.3964681327,0.2041271180,-0.3245566487,-0.4420765638,-1.3968116045,-1.3434318304,-0.9108263850,0.6881069541,0.6643660665,0.2395091802,-1.3126059771,0.9548830390,-0.2024228126,-1.4638279676,-0.4380912483,0.1316522658,-1.5384185314,0.2050340176,0.6454075575,-0.9426968098,-0.5764552951,0.6355412602,-1.1904445887,-0.0340364538,-0.8278380632,0.5902572274,0.3412825763,-0.1369599551,-0.0623027273,1.5578794479,0.7105544806,1.0725549459,-1.9698865414,0.8213605285,-1.2326803207,-0.4292006195,-2.2102420330,0.7281572819,0.3447653949,-1.3590006828,0.3094686866,0.2325506210,0.1171084866,-0.0100068245,-2.9082498550,-0.0394074060,-0.7112797499,1.0732913017,1.0485405922,0.8922514915,0.0037649970,0.3218860924,-0.2153628469,0.1521495283,-0.9304068685,-3.3970711231,-0.5037402511,1.1651905775,0.7021167278,-0.7433487773,0.3981168568,0.9380275011,-1.5853767395,0.0831920207,0.0841076896,-1.0592501163,-0.9714565873,-0.7586913109,-0.6948418021,-0.4219135642,-0.8064761758,0.7126872540,0.4738564491,0.3092348576,1.3096922636,2.0170652866,-0.8423181176,-0.0324107222,0.6601939201,-0.5238676667,1.1682136059,1.5572181940,-0.7529825568,1.6637852192,-0.4154839218,-1.3779836893,-0.1081061214,-1.5806005001,1.8208845854,-0.3819041550,0.5165681243,1.8766587973,0.8654612899,-0.9601491094,-0.3456733525,-0.6894811392,-0.7221453786,-0.6066665053,1.0309771299,0.8200556040,-0.7337735891,-0.1614723206,0.9861069918,1.4574701786,-2.1444618702,0.3525089025,1.7056667805,-0.9310776591,0.6707212329,-1.3782510757,1.1024730206,0.8600340486,-0.2841083705,-0.4831273854,-0.1850067079,0.1130082682,0.2305518389,0.3413489461,-1.0034881830,-1.0885648727,-0.9350720048,0.1794212759,0.4361413419,-1.8060265779,-0.1309453547,1.4649746418,-1.3094321489,-0.3479111791,-0.8606664538,0.3332029581,3.0923016071,1.3583788872,0.0134683866,-0.8860229850,0.2574064434,1.1946133375,-1.1781209707,1.3553206921,-0.6204507351,-0.6351287365,-0.0614457428,-0.5441697240,-1.1895301342,-0.1810240746,-1.1449270248,-0.1968882829,0.5040771961,-0.4403439760,-0.4055637121,-0.4553186297,-0.9085854888,0.0759990811,-0.1860614270,-0.2720640302,-0.1599345505,0.3134514391,0.4481948316,1.9346771240,-2.1949660778,0.8848531246,0.6827428937,-0.9667618275,0.1164045185,0.3335077763,-0.9087823629,1.8471758366,-0.6295967698,-0.8704705238,-1.4105505943,-0.7595064640,-1.2473758459,-0.3623605371,1.0579477549,0.0246553812,0.5469079018,1.0893458128,0.4062927067,-0.3033017218,-1.2926683426,1.0524569750,0.2503056228,-0.3500367701,0.6117320657,-0.6270340681,-0.2911286056,-1.0969469547,1.0318131447,-2.5585491657,1.3501057625,-0.2241195887,-0.4697246253,-0.5922012925,0.3770401776,-0.1585283130,0.8999029994,0.2463238984,0.3050529659,0.0677323788,-0.6213287711,0.5435842276,-0.3985887468,-0.9317046404,-1.2294517756,0.0828140751,1.2535772324,0.0256637987,2.8696305752,1.4507285357,-0.4330395758,0.8850038052,0.4619824290,0.5875666738,-0.3392009139,-2.4040269852,-1.2309052944,0.8450149894,1.1948267221,-0.4159831703,-1.7273284197,-0.4782824218,-0.0359106883,-0.4035047591,-0.1818247736,-0.6230558157,-1.1475069523,0.4307565391,-0.7822400331,-0.4539892375,-0.5645713806,0.7916404605,-1.2734173536,1.1932449341,-0.3262642026,0.1361260116,0.4524342418,1.8424292803,0.2679949403,-0.7157343030,0.9898098707,0.4705828428,-0.5157236457,-0.0149328671,-0.3967804015,0.2779393494,-0.6822986007,0.1624890715,-2.0525116920,0.0262571834,0.2762793601,0.4157950878,-1.2589560747,-1.0236248970,-0.8549474478,0.4833740294,1.2150045633,0.3890248537,-0.0069801174,0.9563995004,0.1099641994,-0.3607292473,-1.0780054331,-0.1775603443,-1.5771030188,2.8553757668,-0.6350323558,1.4035706520,-1.5484172106,0.4918170571,-1.0095106363,2.1850802898,0.9022112489,0.4329253137,-2.1208972931,0.9020392895,0.5670707226,0.2932744026,-1.7365777493,0.3774078190,0.7109208107,-0.1204144135,-1.3939466476,-1.0072985888,-0.1054091528,0.6280057430,-2.4682083130,0.2006152719,-0.9499309659,-0.8038668036,0.5076775551,-0.9942888618,1.0489151478,0.1733068526,0.0147161372,-1.7972850800,-0.1931378543,-0.4037202895,-0.7168515921,-0.3700949550,0.2424467951,1.3536716700,0.5044452548,-1.1023502350,0.1263127476,0.1913612634,0.4485045075,-0.0773018971,2.0170025826,-1.0194779634,0.3922486901,2.9099795818,-0.1763591021,-0.5611923933,0.2001597732,0.4984797239,-0.4362840652,-1.5781536102,-0.0572126582,-1.6782734394,0.1083617732,-0.4752859175,1.9072747231,2.0408916473,-0.8214539289,-1.2110806704,-0.0955808163,-0.7157170177,-1.5102883577,1.8471789360,-0.6968463063,0.5167600513,1.8500298262,-0.6309816837,-0.0008967539,0.6174471974,0.2788871229,-0.8685209155,-0.1644606888,-0.6464869976,-2.1174771786,-1.7138003111,-0.1598047316,-0.3160598576,0.6028695107,-2.0008893013,0.5322968960,1.4469785690,0.6468976140,1.1313585043,-1.0836691856,-1.6371321678,0.1979190111,-0.4971550107,0.3789435327,1.2085425854,2.3498613834,0.2326178402,0.6639389992,-0.2816003561,-1.1688593626,-0.7957587242,2.1797263622,-1.2281219959,-1.0931417942,2.4704101086,0.3591396511,0.3633414209,1.7679173946,-1.5819662809,0.5613010526,0.8031804562,-0.9179223776,0.3878885508,-0.1153258309,0.2231075317,-0.1290087104,0.7834047079,-0.2219590694,-0.0516575351,0.7322729826,-0.6734268069,1.3610804081,0.7266793847,0.7462473512,-0.9291234016,2.1887683868,-0.9468863010,-0.3495929539,-0.0428985730,1.3444181681,-0.0642006993,-0.4990572035,0.9972393513,-0.1914417893,1.2694454193,-0.6293994188,-0.1585151702,-0.2537268102,-0.0725091919,0.7362402081,1.1210161448,-0.4297934473,-2.9094355106,-0.1323205382,-0.2460999191,-0.7158421278,2.1082756519,1.1742449999,0.9783309102,-0.2963083088,-1.1627272367,-0.0309837069,0.8325194120,0.3749943376,1.0111228228,0.1109903753,0.0558381490,0.2111046016,0.0354266241,0.9828637242,0.5850839615,0.0928330123,-0.9776461124,-0.8418869376,0.5141755939,-0.1413520724,1.1167169809,0.8080258369,0.8365648985,-0.6641654968,-1.2707079649,0.1409545690,0.9196810126,-1.2050665617,-0.6511962414,0.4858438671,0.5146605372,1.5368059874,-1.4482113123,0.7256953716,-0.4815798998,-0.4271739125,-0.7080703378,-0.7192265391,0.7303133011,-1.1464543343,-0.0006264384,1.9445780516,0.0367070660,-1.9715096951,-0.9793316126,0.9981327653,0.4227823615,-0.3801508546,0.8276200891,-0.3732515275,-0.5242275596,0.7299136519,0.9283463955,-0.9516673088,0.0363494493,-0.4172412455,0.6668561697,0.7712953687,1.2420126200,-1.0641741753,1.0731617212,-0.3424093425,0.0912520811,0.8670433164,-0.2390884310,-1.2840259075,-1.0081032515,-0.4506661594,0.0318231210,0.9985192418,-0.4479965866,1.9789948463,1.1024099588,-0.8284841776,0.9265839458,0.8247851133,1.1524419785,0.6611723304,0.8174999952,-0.0465653911,0.7161703110,-1.5024360418,-0.6508199573,0.2619676888,0.8435713053,-0.8028890491,0.7184874415,-0.9584380388,-0.5889627934,1.1051890850,1.0269550085,1.1142108440,0.8566098809,-0.1889745146,2.1708762646,0.3211729527,-0.7073199153,0.2713794112,2.1762907505,-1.6629705429,-1.5230276585,0.2944081128,-1.8447911739,-0.4856126010,0.1250060797,-2.6290686131,-0.7232851386,0.4715391695,1.0080659389,0.0524155572,0.4955901802,0.0261317994,-0.4716481268,-0.0053549618,0.9015104771,-1.0712935925,-0.8792697787,0.2951650620,-0.7993769050,-0.7291873693,0.1309042275,0.8772374988,-0.8512756228,0.6310116649,0.2843870819,-0.6464396119,0.4193823040,-2.7665982246,-0.6511185765,-0.6155664325,-1.3428583145,-0.3334512115,-0.3145128787,-0.3880962133,-0.0138087487,-0.0732112080,0.8911177516,1.0543974638,-1.6987104416,-0.9329395294,0.6918064356,0.4133537114,0.9851148129,0.5021405220,-0.4187388122,-0.3045681715,1.2685724497,1.5336577892,0.4741467834,-0.4501512349,0.4564183354,0.3882172406,0.5919806957,-0.4965659082,0.3365334868,1.6907614470,-0.7521701455,1.6877909899,0.6436438560,1.6518549919,1.0253766775,0.9109950662,0.7273064256,0.5286173820,1.1155961752,1.8448877335,-1.5188112259,-1.7974079847,-0.9361957312,-0.5099250078,-0.1010021567,0.8071030974,0.1876153201,-0.0064344634,-0.0497765839,-0.5475576520,-1.0387189388,-0.3532833457,-0.5067877173,-0.9035395980,0.7844749689,0.9171721339,0.8255385160,1.1045073271,0.9061017632,0.8320184350,-0.3664151728,-0.6954748034,-0.3559719622,0.1738903522,0.9105868340,0.2641392946,0.5053906441,0.4349961579,0.8912056684,-0.1841396093,-0.7150786519,-1.3447219133,-0.4978642464,-0.0933635756,-1.1518702507,-0.6728532314,-1.6219307184,0.3163990974,-0.7288520932,-0.5077275038,0.3367995322,-0.7175356150,0.4415037036,0.7889863849,0.6716121435,0.9814752936,1.2690737247,-0.6693392992,-1.1873300076,1.4108334780,0.3188565969,-0.2024255991,0.7412149310,-0.4959668815,0.0802198648,-0.7489406466,-0.1091844365,0.9267287254,0.0638568923,1.1230969429,-0.2486508340,-0.2947012782,0.2912669778,-0.3035437167,1.0478081703,0.9640623331,0.7009201646,-0.8394269943,-0.4298658669,-0.0208310578,-0.9664135575,-0.4727172256,0.3689211309,0.8614180684,0.8856139779,-1.0648728609,-0.4798837602,1.6359280348,-1.5494107008,-0.2393066734,1.6723638773,1.0869294405,-0.1503750980,-1.3417633772,0.3851701319,0.8203778267,0.2636116445,1.2380123138,-0.2437708676,-1.6408116817,0.9459151030,-2.6160981655,0.1274162382,-0.8868399262,1.2920694351,1.2345162630,-0.1554797590,-1.2826472521,0.3236345053,-1.3748104572,0.1620595008,-0.5028721690,0.7731192112,0.0074709491,1.0263241529,0.3440847397,0.4407630861,0.2580718100,0.4818874002,-0.9904689193,0.3456379175,-0.7643799186,-0.5512456894,0.6247019768,-0.0195069723,-2.3036928177,0.4286721349,0.3994229734,-0.3317076266,0.9082452059,1.3464412689,0.8724412322,-0.2232536077,-0.9121289849,-1.0593949556,-0.9844374061,0.4946773946,-1.2179546356,0.8431268334,-1.0629291534,0.9424785376,0.6598713994,-0.5156948566,1.2651425600,0.6092521548,-0.9670048356,0.5924138427,0.8206498027,-0.1055323258,-1.3936834335,-0.2509214580,0.4976290762,0.7790489793,-0.6068552732,0.7373483777,-1.0231674910,0.7975035310,-1.8134320974,-1.6039186716,0.0184440892,-1.5174918175,0.1511792094,2.4891557693,-0.7333879471,0.5969586968,1.1847419739,1.4520896673,-0.1143778041,-0.4433355927,1.7384566069,-0.3925912380,-0.0808646306,-0.4252757728,0.8303156495,-0.0310105458,-0.4736564159,0.0218356308,-0.5272080898,-0.3808960319,1.7675691843,1.5582160950,-1.0983140469,0.5440816879,1.2187278271,-0.4388285279,-0.2428838164,-0.4820106030,1.0899262428,-1.1954586506,0.8806062937,-0.0880520642,0.1150913313,-1.0539691448,0.6986237168,1.8885309696,0.9215537906,1.8435418606,-2.1448302269,0.3851986229,-0.7131193280,-0.3901919425,-1.3624395132,1.5063632727,-0.4614166915,-0.3000406027,-0.1013559550,0.0810948461,1.5957373381,-0.5460469723,-1.3816664219,0.5379842520,-0.6066759229,2.2901933193,-0.7612150311,0.5551570654,-0.9203477502,0.7038357258,-0.6596065164,-1.1327278614,-0.7435246110,1.0183490515,0.6444005966,-0.6632887721,0.1449518502,-0.9932124615,-0.7061646581,0.6948489547,1.6899902821,-0.3036556840,-0.7680572867,0.4792656898,0.4494149387,1.9874323606,0.1310714483,0.5772669911,0.4271465540,-0.3796473444,-0.5137271881,1.3119901419,-0.6844062209,-0.5254566669,0.0645294040,-0.2315711081,-0.9539589286,-1.5046663284,-0.3089866936,1.3342427015,-0.7204396725,0.3384650350,0.0651963726,1.0387514830,-2.1739177704,-0.7222473621,-1.8249527216,0.5022072792,0.0201506056,-2.2221145630,-1.7429068089,1.2421858311,-0.2116023302,-0.7000771761,-1.1120636463,0.2420840859,0.5119414926,-0.9397857189,-1.3358485699,2.8444836140,-0.9619747400,-0.8597752452,-0.3271184266,-0.5138223767,0.0424317084,-0.0836657956,1.0398344994,0.1050056592,0.7023622990,0.0821461901,0.9920848012,0.6409959793,0.3868029118,0.1679462940,0.4380161464,-0.8118830323,-1.0857101679,-0.8440061808,0.8092541099,0.1587680727,-0.5558717847,-0.2662746608,-0.7828058600,-1.8595489264,0.6069732308,-1.0864323378,0.0739274174,-3.2514317036,1.3766409159,-0.4158675373,-0.6441162229,0.5918098688,-0.3352716565,-0.6861219406,0.6173312068,0.8340231776,2.1576929092,0.7559766769,-1.9395177364,-1.5068037510,-1.6640449762,-1.0494740009,0.3865607977,-0.8776586056,-0.3444928527,2.2688899040,0.1278932095,1.4168598652,0.5408000350,-0.4373477995,0.7047700286,1.6746137142,0.0112737603,-0.4115543067,0.4049486816,0.3209570348,-0.0363627002,0.0535618663,0.9652701616,-1.0335603952,-0.8917180896,-1.0212895870,-1.2253913879,1.3610954285,0.5986154079,1.2577533722,-1.1704236269,-2.7986218929,-0.2227247208,0.6540288329,-0.5734651685,-1.3834633827,-1.4270046949,-0.7254546285,-0.6367143393,1.8409622908,0.0058467253,1.4262659550,0.1178915799,0.5660122037,0.9328692555,-0.3919641376,-1.2900167704,0.5978199840,1.0307321548,-0.6817595959,1.5728329420,-0.9726041555,-0.3166731596,1.4570447206,-2.8043234348,-0.1258659363,0.1362825036,-0.2868614495,-0.8499239087,0.7297567129,2.0664722919,-1.0674616098,-0.0646936595,-0.4705346525,0.8866371512,0.0606195629,-0.2033787519,-1.0553119183,0.2734993100,-0.1094169468,0.2509588599,-1.0711268187,0.2432459742,0.7302077413,2.0591175556,0.9453964829,0.7122648954,0.1843675375,-0.8156602979,-0.9698758125,-0.3812840283,0.5082962513,-0.6116515398,-1.4949227571,-0.8798989654,0.1354723424,-0.3616631031,0.4147650898,-0.3228835464,-0.5915602446,1.3671255112,-0.5830543637,1.1036515236,0.0076271435,-0.8378448486,-0.9426112771,1.0647289753,1.1454114914,0.6047657728,-0.5769218802,-0.3423543870,-0.0147391697,-1.2193109989,0.8734396100,-0.5175681114,-0.8919221759,0.6767447591,-0.3358008564,-0.5971326232,1.1393744946,0.1059352309,-1.0928663015,-0.0023749452,-0.8992219567,0.5955408216,-0.1915006489,0.9519176483,-1.6528651714,0.4768061042,0.2691729665,1.0863753557,1.7779698372,1.6851940155,-0.5937855244,-1.2471388578,-1.4843024015,-1.6690483093,0.8079186678,0.6009854674,-0.1532800347,-0.4540135264,0.8403998017,0.0214106571,-0.6578392386,1.5833458900,0.3572075069,0.0490770936,0.3193014264,-0.0974152535,-0.2502352893,0.7973176241,-0.7291021347,0.0530070215,1.3097430468,0.3382050693,-0.4680342078,0.5104855895,0.3980289996,2.7617027760,2.8023548126,-0.9081757069,0.0257167872,-0.6720604300,-1.0278261900,0.5908465981,0.1360614896,0.0536954999,-0.6864715219,0.2259481102,-1.7827547789,-0.4555638433,0.4290686250,1.1622430086,-0.4761041105,-0.1950169206,0.2584655583,0.9476106167,-1.2855743170,-0.1756140739,-0.1077017039,0.9727046490,2.2783825397,-0.7615939975,-0.0914252028,-0.4492025077,-0.1590934247,0.3942250311,-1.8457733393,2.9138922691,-0.6026506424,-0.6460301280,-1.1496130228,0.2545246184,-0.1576082557,0.4011459947,-1.0190671682,-1.5612306595,-0.8178557158,0.1179975867,-0.1237922013,-0.1505875736,-1.5492738485,0.5640113950,0.4910785556,-1.4756758213,-0.0605845712,-0.7968961596,-0.3090079427,-1.4476984739,-0.0446362980,-0.7001911998,0.9888365865,0.0728237554,0.5284053087,0.1921956390,-0.0171768777,0.6343825459,1.2951797247,0.6299999356,0.5879244208,0.2705804408,-1.6909981966,2.4678122997,-2.3150990009,0.7861059308,1.1524168253,0.0536516793,-0.7031561136,2.6576049328,-1.3356398344,0.4453574717,-0.0873836875,0.8940993547,1.7681417465,-0.9471057057,0.7181583047,-0.9346099496,-0.8268125057,0.8860337734,-1.6342958212,-0.9823036790,0.2693607807,1.3396952152,0.0485697836,-0.3400638998,0.7500931025,0.3225327730,2.6488277912,0.3102334738,0.8130268455,-1.1668528318,0.9298003316,0.3419047296,0.3981050849,-0.7024795413,-0.0838392451,2.1503913403,0.3166868687,-0.4655977488,-1.0422612429,0.5906660557,-0.3481139243,-0.0162188802,-0.1142532825,-1.6149265766,0.0337558053,-0.8138551116,-1.9581266642,1.8291319609,-1.5578610897,2.1736629009,-0.7472221255,-1.7286211252,0.7932048440,-0.5200570226,0.1771980226,0.7093726993,1.9725366831,1.6122074127,1.6713001728,-0.2878654003,0.9476270676,-1.9848715067,0.6367865801,-0.8831424713,-1.0610102415,0.6461561322,-0.9139950275,0.2092022151,1.7103219032,-0.3820849359,-1.5692948103,-1.8255572319,0.3962948620,-0.1347055435,-1.3692386150,-1.3420454264,-0.0727353171,0.6803857684,0.2496832758,-0.7072216868,1.5534228086,0.5460235476,-0.1979304999,0.4633287787,-0.3761905730,-1.1127810478,-0.2559715807,0.0235608853,-0.6353579164,-0.6384484768,0.6815594435,-0.4563060701,1.2554326057,-0.4534022510,-1.7506196499,-0.5014964938,-0.2295739204,-0.1924448907,-0.4733704925,-0.2241870314,-0.8210021853,0.5572533607,0.2077593505,1.3226039410,0.8503068686,0.3388375938,-0.5830029249,2.0334277153,1.0397149324,1.2391461134,1.0362479687,-0.5698149204,-0.6259616017,-0.2362915277,-0.3661133647,-0.8876191974,-1.6699805260,1.5485368967,0.0311318263,-0.7217914462,-1.2424839735,-0.0392079912,0.3139655590,-1.0111051798,0.7933912873,0.3894520998,0.2327877879,0.6048811674,0.8615930080,1.2502133846,0.3906288147,-0.5203686357,-0.1070114747,0.8577687740,-0.7629805207,-1.5210009813,1.3381309509,-1.6148548126,-0.2387400120,-0.1157045662,0.1873877794,-0.9930270314,-1.7484232187,-0.9100748301,-0.2736967206,-0.8384456635,0.0644456372,-0.6747201681,1.2409303188,-1.3965411186,0.5551806688,-0.2347596139,-1.5017775297,-0.4084243178,-0.6948349476,0.6206647754,1.0374354124,0.8068956733,-0.9258612990,-0.3243401945,0.3644148707,-1.1015172005,0.7313768268,0.8892873526,0.1480387300,-1.0648075342,-1.4160317183,-0.9014066458,-0.4222130179,0.2445816100,-0.5626324415,-0.4851743877,-0.3403742909,2.9591856003,-0.0881588683,0.5897176266,-0.2818697095,-0.4818490148,-0.0522636548,-0.7201578021,0.8085952997,0.7062283158,1.3574514389,3.1008806229,2.4156870842,1.3525607586,-2.0091259480,-0.0851096436,0.9077156186,-1.2800422907,-0.8717706203,-0.0972527489,-0.5018403530,-0.3444746137,0.7191011310,0.1668957919,0.5495115519,0.8817923069,-0.9869719744,-0.4999747574,0.4192822874,2.0949213505,1.0182723999,-0.9415771961,2.1363947392,-0.1266851574,-0.1686273217,0.1555329263,0.2692514956,0.0107193282,0.6864767671,-0.3113112748,-0.6079178452,1.0384211540,0.3583306968,-0.0989136025,-0.1000434235,0.1119473800,0.9623701572,-1.6869838238,-1.7702426910,-0.5314478874,-0.1993282437,-0.2009946853,1.0972038507,0.1889088154,0.7660380602,0.6959185600,-0.0903240070,0.4758541286,0.4996165335,0.3103198409,-0.2523146272,0.0269732401,0.7140724659,-1.4831380844,1.7946801186,-0.2277995795,1.5964488983,1.7150933743,-0.1319871843,-0.3674093485,0.7914146185,-0.3072839379,-0.8771335483,1.3631716967,0.6096215248,0.0368815847,1.0796775818,-1.5741424561,1.8392524719,-0.1673394144,-0.0709104463,1.3131312132,0.1592441201,0.7896984220,-1.4784001112,-0.2822154462,1.2148447037,-0.0967611820,-2.2488405704,-0.1258734167,0.1380659342,-0.7507057786,-1.7866828442,-0.1211231351,0.4181524813,0.3321387172,-0.1422798783,0.5991910100,1.8145097494,-0.2987695634,0.1185233369,1.7562841177,-0.0889143497,-0.8222903013,-1.4978560209,1.5606752634,-0.7209838033,0.9876718521,0.7995440364,0.3725219369,-0.1506541669,-1.4730818272,2.0495085716,-0.4954752922,1.1434779167,-0.5692482591,-1.4061460495,0.6421436071,-1.8218369484,-1.2275563478,-1.0374466181,1.6718900204,0.3865244985,-0.7263987660,0.5036387444,-0.1251687109,0.0561733358,-0.0534702614,1.3122061491,0.3336322904,0.4826311469,1.7704149485,0.1591441482,1.5266855955,1.2783801556,-0.6986181140,1.0752340555,0.4369335771,-0.4910381734,-1.2765337229,-1.5475559235,0.1101098582,0.4548444748,0.4179526865,3.5148334503,1.3793034554,1.2272132635,-0.7775411010,0.1388985366,-0.9853470922,-2.1588702202,1.4759497643,1.0479900837,-0.2329456359,0.4264881909,1.6505819559,-0.6207741499,-1.3017786741,0.8918532729,-1.8384761810,1.6479315758,1.4943436384,-0.2758189738,-0.4083052278,-1.7543193102,-0.8631698489,-0.3464847505,-1.0863679647,-1.0439672470,0.7048197985,-0.6013585925,-0.5195314288,-0.4424979389,-1.3421670198,-0.1133228242,-0.1815241724,-0.4386858344,1.2019025087,-0.5518383980,1.4825443029,-0.1924960464,-1.3046330214,0.8492895961,0.3339430988,-0.4778641462,-0.7398019433,-0.1873675436,0.9931180477,0.1758742630,1.1829441786,0.5680868030,-1.5838301182,0.1504982114,0.6607076526,-0.0231101718,-0.1185555682,-0.1340669245,-1.0390249491,1.7121312618,-0.0431025848,-0.3924097121,0.5211667418,-0.8721234202,1.0714064837,-0.2642340660,-0.4705439508,1.5070914030,0.0275213439,-0.8787099719,0.2398306876,-0.9827113152,1.2846596241,1.2042113543,-0.2682869136,-0.0602881312,-0.1187253222,0.1935069561,0.6068314314,-0.9962551594,0.1362517178,-0.5295902491,-1.4795718193,-0.3208876252,-0.0433504656,1.3398160934,-0.5696412325,-0.1615510434,2.2393598557,-0.4070459902,1.1034712791,0.8850687742,0.4269449711,-0.0309651364,-0.3605507016,0.7600423694,-0.7894233465,-0.1974647790,1.5508267879,-0.8302157521,-0.3430190384,0.0971933901,0.7561179996,0.1921995878,0.6613284945,-1.3063372374,-1.8925228119,-0.5819588304,0.0686352998,0.7780308723,-0.1821022481,-0.2784351110,0.9828819633,-0.3580800891,-1.4925870895,1.1827394962,-1.2048211098,0.0015660966,-0.7056044340,0.3516597152,-1.3311002254,0.1076234132,-0.9575064182,-0.5319263339,2.2485411167,-0.8890992403,-1.5095508099,-1.4435843229,1.2062375546,-1.0373508930,-0.9600437880,-0.2674483955,-0.8744071722,-0.8395624161,-0.2602224052,-0.0716149807,0.1754660159,-0.0509066172,-1.3418159485,0.9362290502,2.0501604080,-0.8092800975,-0.2566420734,-0.9628132582,0.4812192321,-1.7650332451,1.6551828384,0.2969235182,1.9384123087,-0.7422243357,-0.8657963872,1.9764961004,0.2587822676,-1.2811017036,0.8559010625,-0.2178717405,0.5513018370,0.6288032532,0.3456377685,0.0518872105,-0.2260817885,1.3474808931,0.4960836172,1.1231657267,-0.2785956562,0.1864937544,-0.9686026573,-0.4685764611,0.0343641862,0.8239734769,-0.0382086560,0.8648043871,-1.5192743540,-0.3801605999,-0.7757578492,0.6177380085,1.1645232439,-0.3902976811,-0.4834443033,-0.5099754930,1.1100440025,1.9989259243,0.0120947240,0.7738932967,-0.1626637578,-0.2748828530,0.1500775963,-0.1423937976,0.7558955550,-0.2406939566,-0.8073249459,-0.8291538358,0.5597535968,0.6038845181,-0.4026309848,0.6417809129,-1.0559430122,1.4719893932,0.5502031446,0.4619366527,-0.3297341466,0.9770031571,1.1077107191,0.6487148404,1.0592761040,2.2452018261,-1.4517990351,0.3241731226,0.5708991289,-0.2178623378,-1.4555898905,0.8619402647,-0.7125315666,-0.4648037255,-1.1987832785,-0.3875809610,-0.8089615107,-1.6652204990,-0.6737309098,0.4696156383,-0.9500765204,0.5246605277,-0.3600152433,1.0752583742,0.3630267680,-2.2392160892,-0.4884197116,0.0897057503,0.5078607798,0.2434695959,0.6669661999,0.1939474046,1.1956789494,1.2731165886,-0.2553974092,0.5463133454,0.7415204644,0.8253844976,-2.2207424641,-0.5939807892,-0.5405517220,0.5992439389,0.5527491570,0.2647654712,0.3965257108,0.7488173246,-0.6501255035,0.7335247397,2.3412547112,-0.2428223044,1.3753275871,-1.7682363987,-0.0811214820,-0.1482257694,0.0008704733,-1.1559543610,0.4070131183,1.3749901056,-0.3521507978,-0.5838592052,0.7910311222,-0.8108868599,-1.7694545984,0.6860965490,0.6280745268,-0.0189835038,0.7401046753,-0.0957614034,1.5742759705,0.6285890341,0.6735109091,-2.2882628441,0.9412603974,0.8516026139,-0.2982982099,0.7832838893,1.8826241493,-0.6292356253,0.5742823482,1.9699435234,-0.9881187081,-0.6871194839,-0.7571073174,1.7136073112,0.0445418991,-1.3317672014,-0.0278986376,0.1168358251,-1.9115582705,-0.3436582088,-1.2878416777,-0.4543692172,0.4965259731,-0.3469325006,-0.2261100411,0.7186712027,0.4477775395,-1.1620095968,0.6727824807,-0.0883801803,-1.8939939737,-1.2754259109,1.0608910322,-0.8201976418,0.2681608796,-1.5161629915,2.1384537220,-0.0212910455,0.6318595409,0.0462469086,0.3144905567,0.3767325878,-1.1331812143,-0.2977827787,1.0825668573,0.5229936242,-0.8243591189,0.2687449157,0.4557905197,-1.6796916723,0.0562063754,0.5043262839,1.0077110529,0.6924237013,0.9910323620,-1.1296902895,-0.8210905194,-1.4609053135,0.9427023530,-0.6383852959,0.1021938547,0.5141855478,0.0296744183,1.2136639357,0.6528182030,-0.4292894602,1.3012942076,0.8445175290,-1.8041859865,-0.0520955026,0.6637779474,0.8166362047,0.4969393611,0.1612919420,-1.2245982885,0.8383113146,0.1584201306,-0.6001465321,-0.6403214931,-0.2489199936,-0.8059918284,-1.7376863956,0.2539567053,0.9096975327,0.9964336753,1.1921913624,1.0994590521,0.0866026059,0.1853996962,0.3626529872,-0.6009641290,-0.8141295910,-0.1610737592,0.0605895333,-0.6976833940,-0.6364158392,-1.6901087761,-1.4714292288,-0.8151713610,-1.0487115383,0.6838766336,-0.5414502025,-0.5800019503,0.4200898111,0.8287611604,0.2556479871,1.0243107080,0.6832750440,0.9061375260,-1.0559997559,-0.5638802648,-0.0439743996,0.1173364073,1.6787053347,0.3498084545,1.0181390047,-0.5923074484,0.3546623290,-2.6732180119,0.7222507596,-0.9528815150,0.6282278299,0.6948962212,0.7244352698,-0.4419042766,0.6062676311,0.4268949032,1.2982889414,-0.0492773838,0.1728408486,-1.8239735365,0.0842023790,-0.1465672702,-0.5029066205,-2.5519418716,-0.8701648712,-0.3346950412,0.8195809126,0.9252887964,-0.4902196527,0.7730194330,-1.9046716690,-1.5051252842,-2.4048972130,-0.2875409722,0.8639270067,0.7805999517,1.4741975069,-1.3624743223,-0.8319619894,1.3560540676,0.3230776787,-0.8606194854,-1.7348588705,1.6464912891,0.9878881574,0.6745097041,-0.7136139870,1.6001394987,0.1300480217,-1.5410406590,-0.5384830236,-1.4236744642,0.5284870267,0.1341856122,0.2507516742,1.0759317875,1.0543617010,-1.2375645638,0.1014309525,-1.2856109142,1.5152353048,1.0129420757,-0.5068862438,-0.0818387121,0.8557261825,0.6897322536,-0.6936151981,0.8198645711,0.5045341253,1.4971163273,0.7517387867,-1.0433621407,-2.2742910385,-0.5024763942,-1.5331497192,-0.6632850170,0.1812437326,2.9718608856,1.1071363688,0.1692442596,2.0369729996,0.4972907901,1.4878046513,-0.1821295917,1.4015305042,-0.8876495957,1.7378798723,-0.8951967955,1.0968136787,0.7477356195,0.5420276523,0.8818691969,0.7651853561,-2.1793744564,0.1379532367,-1.5338999033,-1.6719213724,0.8710910678,1.4140412807,-0.8285297155,-0.4181405008,1.0015592575,1.0259017944,-1.0662993193,-1.5625612736,1.5425119400,-1.5811508894,0.0358812883,-0.4583835900,-0.2951638699,0.6391587853,1.2410137653,-1.0080453157,0.0030940096,0.8546661735,0.5233162642,0.1683357954,-1.0702836514,0.6986927986,-2.6348586082,-0.2744528651,1.0474078655,0.6944044828,0.4282088280,0.5804508924,-0.2621594965,-0.1507897526,-0.6044706702,-0.5499491096,-0.8979150057,0.6255866289,1.9500479698,-0.3619381189,-2.0538542271,-2.2297744751,1.2849069834,-1.6552209854,2.3148140907,0.7873542905,-1.1823868752,-1.3611557484,1.6840388775,0.8037516475,0.1811046898,0.1025839970,-0.0465708077,0.9594902396,-0.5949816108,-0.4117023051,-1.0228437185,-0.0251171757,0.8824501038,0.7591711283,0.6231270432,0.5917374492,0.6219696403,-0.0495552123,0.4270074368,-1.1682341099,-0.8261880279,-0.5186452866,0.9526984692,0.2365787178,0.7776110768,0.7848405242,-1.3479496241,-0.6416763067,-0.3390326500,-0.5502781868,-0.9254025221,-1.2017199993,0.1044468060,0.5422565341,1.1859241724,0.0673230439,0.3402942121,1.9644356966,-1.2449916601,2.0009057522,-1.7514717579,-0.1355766803,-0.0298841372,0.0156432688,-1.6379914284,0.0300169382,-0.1188428104,0.4865311384,-0.5542267561,0.2956261337,0.8642213941,-0.3620271087,0.5115072727,2.4552910328,0.1400547177,1.0980756283,-0.9341176748,-0.0969975144,1.0263452530,-1.5575366020,-0.6205061078,1.1078485250,0.9087997079,0.0788982362,-0.2932177484,-2.6274516582,-0.5674450994,0.8807153702,1.8894174099,0.5257295370,1.7268207073,-0.0833458751,1.6114909649,0.5052893758,0.8463229537,0.4828009903,-0.0895236433,-0.2982712388,0.4179650843,-0.0710343793,-0.5111294389,0.3934566081,1.1269727945,0.5989762545,-0.1793426871,-0.5627002120,-0.3595992625,0.5753319860,0.3222674429,-1.3311716318,-0.5409787297,0.1170743182,0.1916641593,2.1233403683,-0.3985538185,1.1539492607,2.1156904697,-0.2566215396,-1.5207226276,2.0685455799,-1.1869761944,-0.8740059137,-0.4242081940,1.5217876434,-1.5788558722,0.5758740306,0.3150611818,-0.7949121594,0.5349891186,0.4776623845,0.4408864379,-0.5021479726,-0.2214682847,-0.4992967248,-0.0067575639,-1.8457427025,0.9280284047,-0.6053181887,0.7470316887,-0.0616565011,-1.2198575735,0.0267692748,-0.6104433537,0.0101288538,-0.3280124068,1.1101564169,0.3608153462,0.4453727007,0.9636499882,-0.8304093480,-0.4685767293,0.9103437662,-0.6982381940,1.1686404943,1.1610959768,-0.1441449672,1.0166361332,1.8670653105,-0.1394449472,-0.4043854177,0.5049604177,-0.6021443605,0.2187743187,0.3758377731,-2.1905653477,-0.4398531020,0.1216888949,1.1135267019,-1.3173891306,0.5598527193,-0.0590468831,0.6931667328,2.4740109444,-2.0966489315,0.1619170755,-1.5034503937,-0.6038945317,0.5554865599,-1.4479967356,-0.8917023540,-0.6455559731,-0.4626631737,0.4900054634,-0.3706803024,0.5256991386,0.1678807884,-0.5502416492,-0.3375319541,-0.3431487679,2.1183767319,-0.7996915579,-0.3146005273,0.3703980744,-1.0030088425,-1.9712535143,-0.2197760195,-0.2830720842,-0.1667875350,0.5648902655,-1.6655410528,0.7426096201,-0.1408229321,-0.3646937609,-0.3127844632,-3.0347666740,0.1353932172,0.6488391161,0.5635000467,0.6422799826,-0.5255937576,1.3670353889,-0.1994901747,0.2347858846,-0.5399846435,-0.2052275538,0.7761011720,0.3517878354,-2.4709758759,-0.5613272190,-0.0516717657,-1.9915071726,-0.8145096898,-0.1598192304,-0.4733167291,0.3067771792,-0.4550936222,0.4928416610,-1.5474539995,-0.5095470548,1.3454902172,0.6438094378,2.3404154778,1.0623267889,0.2608698010,1.3165721893,0.3916930854,1.2871226072,-1.1001724005,0.4859510958,-1.0528469086,0.0048558200,0.5584079623,0.8512579799,-0.9370487928,-1.2440121174,1.4365291595,0.0317177959,0.2058206797,0.0645339563,0.2769898772,0.0672572851,1.3564913273,-0.8004226089,-1.0108019114,0.2683846056,-0.3449343443,0.5715727806,1.8105565310,-0.4251840413,0.0933929682,-0.0318874568,-0.0917476565,0.2792342305,-1.3499195576,-0.3130746782,0.1089106649,0.7911434770,0.1674464196,-0.5621147156,0.0358672328,0.3739733100,0.1566600949,1.6247915030,-1.3720308542,0.0518179424,0.2691105306,0.1931755841,0.0992060304,-0.0557342619,0.6415981650,0.2318139821,0.1195221543,-0.7894995809,0.7086682320,-0.2938629985,0.4510083795,-0.2968471646,0.9600773454,0.8050220609,0.9683947563,0.5477582812,2.1819415092,0.2233613133,1.3260169029,-0.3495138288,0.0223538298,0.1567016244,-0.7688352466,-1.0201549530,-0.0924670175,0.0193462633,0.3662928641,0.5027229786,0.4168736339,-0.6279435754,-0.4090660214,-0.2738506794,-0.7319854498,-0.7716166973,-0.4655268788,0.0913858637,0.6756829619,1.0749363899,-2.9845871925,-2.3411133289,0.7401157618,-0.5512769222,1.1327184439,-0.3372319043,-1.0306859016,-2.1232624054,0.1218878105,0.2254609168,-1.8603311777,0.1255722195,0.1211966723,-1.5937081575,1.2448704243,-0.4653194249,-1.1432752609,-0.8448824286,0.4323055148,-1.5212147236,0.4646244943,1.2543433905,0.6006751657,-0.5522754788,0.6215143204,-1.3684450388,-1.2913494110,-0.7055885792,-0.7935898900,-0.2950033844,0.8652331233,-0.3805498779,-1.6659548283,-1.2524651289,0.0942175016,0.4701784253,0.4993986189,0.3036863804,0.3379638195,-1.0666376352,0.9350460768,0.0076516639,0.8255095482,2.0182163715,-0.2377916873,0.4250042140,-1.2792454958,1.1763788462,-2.4107418060,0.0559295639,-0.8411914706,0.9756729007,-0.2996968329,1.1991971731,-0.0036011224,1.5130709410,-0.7111702561,-1.3614077568,2.2163901329,1.9284011126,0.6578730345,-0.5633271933,-0.5350072980,-0.6862948537,-1.6068059206,-1.5318435431,0.6679149866,1.0064121485,1.1902654171,0.2330749482,1.5748063326,1.1538707018,-0.9454938173,0.4218579233,-0.6603856087,0.5557044148,-0.3310923576,1.2670267820,0.6889605522,0.5879198909,0.8793924451,0.5530157685,-1.3612712622,0.6004394293,1.5862592459,1.7088806629,-0.3228707016,-1.5339814425,1.3532996178,0.1337690353,0.4033794701,0.9362673759,2.5070328712,-1.4719178677,1.1299579144,-1.2589129210,0.8528534174,0.8711306453,1.6040962934,1.7402243614,-0.6684724689,-0.8084316254,-1.1939450502,-0.2090555429,-1.5653285980,-1.6939487457,-0.7268587351,-1.8237613440,0.1104834676,-0.5062472224,1.1678825617,-1.4700238705,-0.8294458985,-0.4625340104,-0.2558137476,-0.5204338431,0.5611996055,-1.4619174004,-0.6257733107,-0.7569713593,0.7612380385,0.6510775685,0.4265863895,0.8792460561,0.0824565366,-0.6086297035,-1.2662295103,-0.5894017816,1.4452910423,0.6569434404,-0.3121954501,-1.8380763531,2.0977277756,1.1606415510,-0.8928475976,-0.2812048793,-0.7891488075,-0.5135432482,0.1404644102,1.7727484703,-0.7247069478,-0.4047034383,1.1784008741,-0.0882060081,0.4330866337,-0.2398931980,0.6297299266,-0.7113015652,-0.2888081670,-0.6917343736,-1.0160704851,-0.0501448251,-1.7557926178,0.8874514103,0.6896318197,-0.9837778211,1.9327976704,-1.7024279833,1.1284931898,-1.7392871380,-0.1856941730,1.3723155260,1.3488906622,-0.2660662234,0.9858436584,0.3364506662,0.4291782975,1.2164518833,1.5936523676,0.5462658405,-1.1891343594,-0.3331855237,0.0216330234,-0.3720126450,0.6676066518,-0.1610603034,-0.6453488469,-1.2660588026,0.1885916442,-0.1913194507,-0.2533226907,-0.4697803855,0.0147942333,1.9812374115,-0.0728941634,0.4952958822,0.0687560663,-0.6622215509,0.0422153100,0.0999927744,1.8953807354,-1.4996274710,-0.5814818740,0.7663285136,-0.6812976599,-0.1066205800,0.2546959221,1.2007323503,1.3327698708,0.2031353116,0.7176383138,1.2447898388,0.4891205430,-0.9856312275,0.8673879504,-0.6054337621,0.4199489355,0.1581125259,-1.4761838913,1.1224590540,2.9868655205,2.0953581333,-0.6189078093,-0.7180119157,1.2323864698,-0.4477436841,-0.4142808020,-0.1765896827,-0.9405736923,-0.3397848606,0.6380889416,1.3421542645,-2.2330129147,0.2280873209,0.7671604753,1.4022625685,-1.3546260595,-1.7892752886,-0.9778614044,0.2651600242,-0.7413028479,0.2085521221,0.6731303930,-1.5684994459,-1.0101099014,-0.5023919940,-0.6700144410,0.7095361352,0.8025005460,-0.2038030177,0.4760249555,0.4454511702,-0.5939602852,-0.7164628506,-1.5171319246,1.4800959826,-0.0717306584,0.9497123361,1.4563376904,1.5433458090,2.4010305405,3.3334319592,0.4822435677,-0.5614119172,-0.9017120600,0.9639977217,-0.2467245311,0.6018739343,0.6744873524,-0.7295719981,0.2263079584,-0.0595782287,0.4756217003,-0.1380271614,1.4944998026,-1.1411798000,0.4533945322,-0.5606918335,0.6212491989,-1.1574071646,-0.2401100546,-0.5401071310,-0.8303443193,0.3478609622,-0.8683995605,-1.3129228354,-0.1908754110,-1.8695154190,-0.3507457078,-1.6960946321,-1.4109058380,-0.0006375873,-1.9163777828,2.3475019932,-0.9438844919,0.9024425149,1.2787234783,0.2669394016,1.0342036486,-1.1763765812,0.2994127572,-1.5218186378,-0.6456666589,-0.0896530226,-0.3566700816,-0.5822973251,0.2027257532,1.2007070780,-0.9537147284,-1.7942665815,-1.6502112150,0.3794765770,-2.1909353733,0.3905528784,1.6661679745,-1.2986001968,-1.2059516907,-0.9303827286,-1.6575475931,0.2639370561,0.2804372013,-0.1337700784,0.4575373232,1.4409017563,-1.3529820442,1.1944533587,0.1142227128,0.1391180605,1.3320208788,-0.5805708766,-0.4466572404,-0.8611194491,-0.1826741546,0.3247959912,-0.4794469774,-1.5512284040,-0.6987625360,0.7923681736,0.3309248388,-0.5274670720,1.7341567278,-0.5651237965,-1.1047180891,-0.8757085800,1.9002363682,-0.5654552579,-0.1503885388,2.3177163601,-1.0674678087,0.4179449975,-0.8482495546,0.1508035660,-0.2906613052,1.7630039454,-0.4032920003,-0.8586524725,-0.8267387152,-1.0485448837,0.4945226312,0.8998538852,-1.2160298824,-0.4785618782,-0.3782664239,-0.1571599543,-0.7503957748,-1.5480009317,0.2291377932,0.6442772746,1.8228875399,-0.0811340883,-0.9858629107,0.1007367000,-1.0231248140,0.8747323155,0.7531514168,-1.6565316916,0.9526207447,-0.0294028688,0.2464197874,0.1333850771,0.5864880085,1.0717082024,1.4090615511,0.8718538284,-0.0508552119,-0.0712610632,-0.1940155625,-0.7806551456,0.5808362961,-0.0453044698,0.9831092954,-0.0407605805,1.6183751822,-0.4711570144,0.9464051723,-0.1902614683,-0.5595943928,0.7917163372,0.8945364356,2.0407261848,-0.0378948264,-0.5753856301,0.7319956422,0.7065110803,-0.1146564707,-0.3133381903,-0.6908829212,1.3543372154,-1.2197914124,1.0682621002,-0.4357069135,0.4142681360,-0.8415632844,0.0666707754,-0.1261732876,0.4309399724,1.7831349373,0.2475240082,0.5416277051,-2.3900408745,-0.0873001814,0.4318037629,-0.0842064768,0.0386220776,0.0086299293,0.4828562737,-0.3126920760,0.6790862679,-0.0472784191,1.0052809715,-0.7735071182,0.4777276814,-0.1993416548,-0.7341573834,2.2931449413,-0.8017128110,-1.2624527216,0.4948807955,1.9594209194,-0.2333582640,-1.1403502226,0.7428901792,0.4308326542,-0.0369284041,-0.8011110425,0.2558170557,-0.8303340673,0.4260979295,-0.7176937461,0.3255190253,0.2934720814,0.0140975080,-1.6804726124,-0.3438348174,-1.4502503872,-0.9531344771,-0.1847796291,0.1688913107,0.6571382880,1.5159125328,-0.1185081005,-0.9134144187,2.3134839535,0.9210193753,-0.1931522787,1.1115853786,-1.5775060654,-0.4333670139,0.9147577286,-0.8540613651,0.4533645511,-1.5374147892,0.3218281269,-2.0726091862,-0.2654472589,0.4145475924,-2.7371721268,0.0493369773,-0.8245742321,-0.7906406522,-0.4056213796,-1.2431070805,0.1490028054,-0.5710224509,-1.1668577194,0.3953489661,0.7068749070,-0.3533940911,-1.9965847731,0.8758977056,0.4603376687,1.2675856352,-0.7088031769,-0.6654269099,-0.9213801622,0.4947441518,-0.0715525448,-1.0028457642,0.3830953240,0.4520997703,-1.2615735531,0.9056553841,0.3861218393,0.1425308436,-0.1260088682,0.9447017312,0.6559101939,-1.8171663284,1.4004011154,-2.0061945915,-1.8255103827,0.1024764478,0.1558491588,1.2420189381,-0.4764030576,0.3463437855,-1.7062416077,-1.5446808338,-0.3215472400,-0.4196771085,1.8047077656,-1.8244951963,-1.2479240894,0.8842428923,-0.7375934720,-0.4316256344,-1.1759667397,0.3775776029,0.3401539326,-0.7903994322,0.4455604553,0.5148267150,1.0482620001,-2.2607221603,0.0069156969,-0.9996435642,0.4997765124,-0.8113646507,-0.2739197314,0.7623291612,1.9041544199,0.0038511909,-2.2380661964,1.2144907713,-1.3699985743,0.5216916203,-0.9953954220,-0.0678855330,-0.9681578875,-1.0197651386,0.4510965943,-0.9384776354,0.4080997109,0.2205782682,1.4572985172,-0.0716064721,-1.3010287285,1.0668503046,0.5560036302,0.0169553459,1.3414565325,0.3216943741,0.4991309047,1.4584230185,0.2209969759,-0.6442297697,1.2691410780,-0.0391359441,1.1090129614,0.3669699728,-1.2093535662,-0.2478190958,1.0072946548,1.3478624821,1.4052371979,0.7991831899,-0.5470215678,0.1076327264,-1.2209036350,-0.2053703666,0.6416805983,0.8527611494,0.8009208441,-1.1441555023,0.5289140344,-1.3059980869,0.8233359456,-0.9994716048,0.4629640877,-0.9534198642,1.9949338436,1.0057520866,0.4678486586,-0.4734914899,0.0677830651,0.3521122932,-0.1107401550,1.0441912413,-0.4773075581,1.3873674870,0.5615459681,-0.7976940870,-1.3771500587,0.8169613481,1.3486270905,0.5091228485,-0.3491946459,-0.4665772915,0.2233534604,0.6446563601,0.9125355482,0.9257678390,0.8465470672,0.0578327812,1.3858836889,-0.2434680015,1.6562070847,0.9416037202,0.5632153749,-0.5659677982,0.5274534225,1.1877981424,1.4489836693,-0.7451183200,-1.5661666393,-1.1835601330,-0.9559128284,0.1651993841,1.1368753910,-1.0665529966,-0.4836068749,-0.8145627975,0.3149281442,-0.1883910000,0.4216847420,-1.1827241182,-0.0994306877,-0.3438635170,-1.9663894176,0.2089749277,-1.4949587584,0.3206232488,-0.6770358682,1.1477482319,-0.2624453902,1.4652047157,-0.0285696778,-0.0104226936,-1.3233613968,-0.5543357134,-0.1505497992,0.2329614758,-0.5039017200,0.2137409151,-1.2017041445,-0.6092761159,0.5041880012,-2.6073977947,-0.5180581212,-1.2378791571,-0.7136105895,-0.7491711378,0.8616729975,-0.6471394300,-2.4227328300,-0.1132138893,-0.6853970885,0.3431085646,0.8768229485,0.2715342343,-0.3802629411,-0.8611323833,0.3513724804,0.5549112558,-1.2833085060,0.7726469636,-0.4660710394,2.5595307350,-1.7120479345,-0.4161309004,-0.2351716012,0.3630282879,0.9382425547,0.6695708036,-1.7179670334,-0.5959632993,3.7025876045,-0.2213580161,-0.1287264526,0.6192150712,1.0531377792,-0.2467512041,1.4417458773,-0.3152952492,-0.7391575575,0.1590342820,0.8058029413,-0.1784851551,2.3034143448,-0.4181099534,1.3932461739,-1.1737822294,0.7538549900,0.6269468069,-0.7819752693,-0.7092577219,-0.5887012482,-1.0844168663,0.9721927047,1.2547427416,1.7547675371,-0.7578601837,-0.3038023710,0.6221553683,0.2105609030,0.6844446659,-0.0726488233,-0.8142358065,1.5024870634,-0.9599415660,0.8041617870,1.2129323483,0.2786012888,-0.4806325436,-1.5507179499,-0.6431815624,-0.9598134756,-0.0414928049,0.9750754833,0.2134624720,-0.7340024114,-0.9867333174,-0.9676715136,-0.3153736889,1.7369050980,0.1728345603,-1.6357651949,0.5001330972,0.0361833759,-0.3400045931,0.6917695403,-0.6486070156,0.5865759850,0.6650483012,2.3782908916,-0.7281708121,-0.1784517318,-0.6568906307,-0.0668870881,0.4001824856,0.5983645320,1.4374731779,0.8282849193,-0.2202301174,1.4063117504,-0.2658022344,-1.0646981001,0.2660436034,0.2665685117,0.8515069485,0.0041442462,0.3150144517,-2.1227982044,0.7639856339,-1.4190670252,0.7797390819,0.9185681343,2.0322315693,-1.4458156824,0.1613995284,-0.4561886489,-0.8995773196,-0.2119886428,0.1786645055,0.1776530445,-0.3201810718,0.1161821634,-0.5768741369,0.6252367496,-0.1033955812,-1.0653221607,-2.6090035439,-1.9755235910,-0.0643296540,0.3567645550,0.1918041110,-0.2986488640,1.0968306065,-0.4158258736,1.2320274115,0.6485459208,1.6077394485,-3.1362752914,0.3075769842,0.4591005147,0.3467891812,-0.3982659280,1.1793015003,-1.7780370712,-1.3126175404,0.4909677207,1.6737562418,0.0124732330,-0.3899201453,-0.1232452691,-0.6100804210,-0.9292196035,0.8099145889,0.6836316586,1.4735952616,-2.2071619034,1.9934275150,0.6117762327,-1.5051028728,-2.4555799961,-1.0627012253,0.9527903199,1.5368833542,0.0395082273,-1.3321162462,0.5243310332,-0.1798415333,0.5129242539,-0.4493110180,0.0150246527,-0.9672916532,0.9956399202,0.2072731555,0.5924943686,-0.5087363720,-0.1341209561,2.0133500099,1.2745864391,-1.7311307192,0.8783261776,0.2382151335,-0.5218320489,-0.7136888504,0.9078969955,0.1662100703,0.6880350113,0.6426402926,-0.1699856371,0.8449928761,-0.2059611827,1.2312691212,-0.1832074076,0.7024871111,0.0767141655,-1.0377204418,-1.2589073181,1.2890216112,-1.6496952772,1.3731424809,-2.5840425491,0.8842554688,0.7858142257,1.2424460649,-1.1142414808,-1.6087180376,0.5588724613,-0.3181532919,0.1282300502,0.3226558864,1.7192137241,1.8144487143,0.0832170099,1.0794529915,1.0780323744,0.1856908500,-0.6103316545,-2.1893501282,1.1166290045,0.7507947087,2.0451416969,-0.0583368354,-0.7521981597,0.1606955081,0.9020569921,0.2915190160,2.0094237328,-0.5653720498,-2.0505139828,0.3951239884,-0.1658412069,0.1319901049,-0.8073076010,1.1072100401,-1.6461715698,-1.6490888596,-0.7021602392,0.1291684657,1.0130834579,0.4326122403,0.0710866079,0.6522153020,0.9110949039,1.2549139261,0.3565925658,0.4046155214,0.4020137191,0.3690601587,-0.4672718048,1.3912384510,-0.4798047543,1.5850034952,0.2715241313,-0.0765904635,-0.1810461581,-1.1558505297,-0.3667913377,-0.3131943941,1.6469752789,0.1343065500,-0.6560097933,0.5086302757,0.4044632912,0.6018323302,1.7113457918,-0.1906548142,0.0425776057,0.0373008773,0.1381624639,-0.4156305790,-0.7981631160,0.0582099520,2.6061866283,-0.7722873688,-0.0470007211,1.5131361485,-0.0309810881,-1.0579044819,0.8854081631,0.7483155727,-0.2261427641,-0.7398789525,-1.0611298084,-1.4868919849,-0.4077556431,-0.5551923513,-0.3160439432,0.7666338086,1.4771444798,-0.1199424937,1.2570329905,-0.6283643842,-0.6694485545,1.3534792662,0.1671885401,-0.9664984941,0.1351937652,-2.2209308147,-1.7459772825,0.8721058369,0.4668622911,-0.9920146465,-0.3378461897,-1.5689595938,0.0369126610,-1.8374615908,-0.9583182931,-0.0569251254,0.0614638180,0.3806518018,-0.9281975031,-0.3982549608,0.6343744397,0.5360945463,0.4420194328,-0.1513541192,-0.1408912539,-1.2138690948,0.9535938501,-0.1115452573,-1.2844252586,0.2494014949,1.4498769045,0.8719550371,0.0237522461,-1.6092516184,0.1648471653,0.5427899361,-0.4420486987,-1.4820035696,-0.0689525232,-0.7968429923,-1.6705019474,0.7698445320,-0.1265096515,0.7726453543,0.1753320694,-0.5076130033,-0.1544819772,0.2653084695,-0.0847224519,0.6755714417,1.0591664314,-0.0757832155,0.0805232376,0.0671821758,1.6652826071,0.2529174089,-1.0575348139,0.0438446961,0.6698242426,0.5310724378,-0.4435330033,-0.3427950442,1.0558329821,-0.9846804738,0.5860679746,1.3339457512,-0.8269437551,0.9077727199,0.1672893316,-0.8939241171,0.3120681345,-0.6364495158,-0.7267069221,2.6667218208,1.1729916334,1.2637227774,-0.3764693141,0.1535074413,-0.2704104781,0.0951040611,-0.7366018891,-1.2720896006,-0.6093081832,-0.2956297398,0.1220130399,0.9173392057,-0.2534488142,0.4520286620,-1.8082159758,0.7244623899,0.7396792769,0.6426346898,0.0797319785,-0.5158020258,0.5891546011,-1.4976643324,-1.2477073669,-1.7936444283,0.8376747966,-0.7089396119,-0.1811517924,-0.7688514590,-1.4071519375,0.2784728110,-2.5875277519,0.9116972685,-0.5199452043,0.1479708701,-0.8809148073,1.8356801271,-0.8060521483,0.4518039227,-1.6225919724,-2.0098841190,0.1720021516,-0.4275765419,0.1004268378,0.1585029215,0.8063095808,-0.1378083378,-0.0826101378,0.6346687078,-0.3701512814,0.4816154242,0.3261772096,0.7613685131,0.6079658866,-0.6945112944,-0.2238053679,0.0034116469,0.0198742934,-0.6288275123,0.3040928245,1.0772180557,1.1524056196,1.1629301310,-0.3494142294,0.5766470432,0.3408490717,0.4503265023,-1.0144721270,-0.0498800389,-0.5482375026,0.3489536345,0.7263273001,-0.9238932133,-0.3699231446,-0.8713849783,-0.7335543633,0.8255431652,-1.5280839205,0.5197145939,1.0876455307,-0.2757599950,1.5692808628,0.7538465858,0.9047079682,1.1547479630,1.0163842440,-1.1070152521,-0.2055583447,-0.9297230840,-1.8402305841,-0.0856739655,-1.4860048294,-0.5312367082,-0.2028853595,-2.2556784153,0.3083379269,-0.6643678546,-1.4581902027,0.1362811774,-0.2612127960,-0.3958458602,0.2158193737,2.3531103134,0.5730254650,1.5000845194,-1.6561217308,-0.9346296787,-0.0294601489,-2.1529641151,0.3335566819,1.1823263168,-0.5181627870,0.6104934812,-0.7329621315,-1.1848534346,0.4069354832,0.0345559642,1.9944534302,2.3979656696,-1.1336600780,1.2679555416,-0.4079175293,0.0792932883,-0.4174874723,-0.2649638653,0.9532611966,-0.3875336945,0.6469477415,-1.6494807005,-1.5241768360,-0.9117911458,0.9734886289,0.2089319974,0.5428323150,-1.9180088043,1.2095471621,-0.2803136408,-0.8650236130,0.3140363991,0.2163758725,-1.3617240191,-0.9943023324,0.6911141872,0.7621330023,-1.2232488394,1.6510376930,0.2612263560,0.1864361614,-0.0706841946,-1.0403263569,-2.0321514606,-0.7808988094,-0.8977251649,1.6592231989,-1.3123985529,-0.5749298930,1.1344422102,1.6615151167,0.1504340172,-0.0827697366,1.0395177603,-0.7313262820,1.0351142883,0.2846813202,0.3578853905,-0.8776550889,-0.0276330616,-0.2406794727,0.2422078401,0.2753272355,-0.9000979066,-2.1857159138,0.2421487421,1.9852120876,0.6831824780,-1.3812738657,0.2342664003,0.7960075736,-1.0990927219,-0.6038036942,-1.5455021858,-0.2055137306,-1.2040677071,0.1401914656,-1.1692546606,-0.7095637321,-0.2126831561,-1.3855490685,-0.2365769148,-0.3908159137,-0.0181708690,-0.4164932966,1.7714226246,0.8974324465,0.5611874461,0.8519725204,0.9009156227,-0.1347933710,-0.3339865208,-1.3960329294,1.1774704456,0.2161447108,-0.6004638672,-1.0433120728,1.2550470829,-0.3633813262,-0.5906378031,-0.0185135938,-0.1028014421,-1.7445312738,1.6993048191,-0.6432486773,-0.9254992604,0.5182227492,-1.2138725519,0.8419089317,-0.6030687094,-0.1839088202,0.4044023156,0.1647076309,2.3706243038,-0.8371855021,-0.3153517246,-1.0361464024,-0.1055759564,-0.8192484975,-1.3087396622,0.8839029074,0.8903806806,-0.1596081257,-0.3812036216,-0.8509666324,-2.1042964458,-0.1953709871,0.7087575197,-2.1301450729,-0.0047883722,1.4961576462,-0.6381576061,2.3768637180,-0.9427425861,-0.1516778916,-2.2839558125,0.5090414286,-0.2221545130,0.4502406120,1.1437622309,-0.1963302344,0.3094167709,1.3509380817,-0.5044822097,-1.6174205542,1.5378000736,1.3241184950,-0.2176084369,1.0739580393,-1.3880198002,2.6526143551,1.3435379267,0.9719251990,0.1656426191,-0.4877803326,-0.9836961031,-0.7674241066,-2.3378081322,0.3354743123,-1.1810867786,1.2881627083,-0.2078816146,-1.2664439678,0.5565501451,4.0197734833,0.8854044676,-0.5009924173,1.0933628082,-0.4822470546,1.1983449459,-0.7168338299,1.0617597103,1.4151138067,0.2771531641,0.7030990720,-1.2996754646,0.5242429376,-0.5445105433,0.7130293250,-0.3225224316,-0.6599298716,1.4526163340,-1.0813671350,-1.3591839075,0.8215834498,-1.0169330835,0.1585911661,1.6827707291,-0.9877544641,-0.8410540223,-1.2568205595,0.6768353581,0.3739871085,0.2208058387,-0.3934979141,-0.4662604630,0.5557742119,-1.4550930262,0.6333280802,0.2107170522,-0.0745086297,0.4422843456,1.3056447506,0.2425055355,0.0369345658,-0.1842762232,0.6566666365,-0.2707042992,1.6456437111,0.3681226671,0.6295041442,0.9925812483,-0.3826599419,0.1413362175,0.4062003493,2.3438417912,-0.3850591481,1.5470700264,-0.8475514054,-0.6330932975,0.4426223338,1.1135199070,0.0156516992,0.9530420303,-0.2288440615,-0.5985863209,0.8398433328,0.3938765526,1.7500195503,-0.6720721722,0.2872419059,0.6539419293,0.1856593937,0.1378008425,-1.3960168362,-0.1134697646,-0.2837387621,-0.8654352427,0.3288089037,0.0301165637,1.1624650955,0.0011483978,-0.6361009479,0.5182092190,-0.0406220965,1.7414946556,-1.6548664570,-0.6029675603,-0.5882458687,1.4716166258,1.1737931967,-1.1955555677,-0.1590917110,0.2381560504,0.9164401889,-0.1090425402,0.5899898410,-1.2650150061,0.5999732614,-1.0951660872,-0.0711921379,-0.7832251191,-0.6987342834,-0.0219315849,1.1395345926,0.2375022620,-1.7151470184,-1.5024656057,1.7313393354,-0.5030255914,-1.2392387390,-0.1868620217,0.9655178785,-0.5649629831,-0.6893165112,-0.7033599615,-2.2348511219,-0.0525545701,0.3070724905,0.6070462465,1.1996613741,-0.5176995397,1.0299232006,0.8695846200,-2.1147446632,0.4078527093,-0.8786563873,0.4362991750,1.1177811623,0.5423116088,0.9149170518,2.4281659126,0.2401718497,-0.5961187482,0.0141318729,0.3701690435,0.1808289289,1.2599830627,0.2183745056,-0.3465143144,0.8355005383,0.2451741993,-0.1894374192,0.6959276199,1.5179269314,0.2976191342,0.5701390505,1.4372801781,2.0795273781,-0.3756849170,-3.5909032822,0.0716620237,0.6304141879,0.0261821225,0.8042483330,0.9069849849,0.3464861512,-0.5794659853,-0.5438749790,0.0289033912,0.9105071425,-1.4992305040,-0.4793045819,0.8542497158,-1.0811475515,0.2171867788,-0.5041297674,1.7892602682,-0.0283070989,-0.0441253670,1.2115254402,-0.7234268785,-1.1590812206,-0.1522644460,-0.9474188685,0.1717792600,-0.2749402225,-1.0617312193,0.6321954131,-1.3946050406,-0.5197392106,0.8903101683,1.0188506842,0.0586597063,0.3688014150,0.7033883929,0.5548697114,-0.9274749160,-0.6818982363,0.4796386361,0.2311522514,1.9238237143,-0.6357836723,-0.1479309797,2.6409428120,0.5992001891,0.0839401186,-0.3585545421,1.6161761284,-1.1302142143,1.3481178284,0.5973325372,0.5636794567,-0.0097401869,-0.3516861498,0.8041421175,2.3142130375,1.7594890594,1.5309214592,1.8990132809,-1.8272774220,0.8267484307,-2.2523925304,-0.1968108118,-0.2863500416,0.4057592750,-0.7191252112,0.2487123907,-0.6566113830,-1.3493041992,0.1164432839,0.1086965054,-1.4072995186,-1.7230648994,-1.9000509977,-2.4684510231,1.2062046528,0.4911671579,-0.0894651636,-0.3995863199,0.0991533101,0.0014761668,-0.7353255153,1.0571197271,0.3556884527,1.1477404833,1.5356293917,2.0558340549,0.2317831367,-1.1191799641,1.3284108639,-1.4650167227,1.5791805983,0.2670737803,2.0296282768,0.7951829433,0.4688805938,0.0782255381,-0.3811810315,-2.0412206650,0.9424459338,1.4058378935,2.0227613449,-0.4164577723,0.1712241471,-1.2878608704,0.2662688792,0.4602661729,-1.9420094490,-1.0917539597,1.0351030827,-1.3396145105,0.4247620106,0.4522379935,-0.1753645241,0.3741957843,0.6832326651,0.2857375145,-0.7751410007,0.2919989228,0.3030637205,-0.7733544111,0.2354594618,-1.6997842789,0.8201661706,-0.2567533255,-0.4506866932,-0.3111549914,-1.0207248926,-0.5771256089,-0.9786616564,0.1340002865,-0.8608180285,0.5694761872,-0.4418152273,-0.1610226035,0.2886717916,1.9575083256,0.7234182358,-1.0948028564,-0.2901492417,-1.3798342943,-0.6869062781,-0.5215283036,0.2655810118,-0.2533085644,0.2296121866,-0.6031663418,-0.8315091133,-0.5224909186,-0.4015553594,0.2074885517,1.6709539890,0.8634210825,1.5834872723,-1.7893948555,-1.3206269741,-0.6768729091,2.1363854408,1.2582120895,1.0345571041,-0.1696926504,-0.7326226830,1.0371384621,-0.9781098366,-0.2509648204,1.0754765272,-0.5080704689,-1.7204457521,1.3550037146,-0.7376111746,0.2516528964,0.0143696088,1.4959465265,0.9013447165,0.0666519925,1.2546199560,-0.6876458526,0.1289302558,-1.2125207186,-1.3062785864,0.1477067918,-0.9687612653,-0.6614953876,0.4936519265,-1.0251137018,1.5563279390,-0.0668517277,-0.6016780138,1.2578229904,-1.6711659431,-1.7495858669,-0.6962295771,1.7163276672,-0.6159476042,0.8581643105,-0.0230642557,-0.1786852777,-0.5286377668,0.2368431985,-1.6006636620,1.2182400227,-0.9850192070,-0.7063335776,-1.0004578829,0.2919587493,-0.1049265787,-0.7563028336,0.4225782156,0.0824065655,0.2042005062,1.2740459442,0.1095527783,1.1274046898,-0.6521725059,0.0609520078,-1.1165735722,0.9280680418,0.1987430453,0.4761828184,0.1669905335,1.0124512911,-1.2776417732,-0.3814474642,0.7289512157,-0.3052847087,0.7282732129,-0.5393836498,1.2419661283,0.5911603570,0.3793136477,0.1260632575,-0.1371300519,1.8880878687,2.8134269714,-0.2924009860,0.3732911646,-2.3748250008,0.3623911738,-1.5661566257,1.3808929920,0.9725285769,0.2446972132,0.7711442113,0.3922756314,-2.1892728806,-0.0823605731,-0.2208417803,0.4101850986,0.2744546831,-2.2105195522,-1.3529791832,-2.0533165932,0.7840827703,-1.2388772964,-0.0091828620,0.2710341811,0.7293034196,-1.9300572872,0.2674436867,-0.6061401963,1.2984786034,1.4081494808,-0.7296541929,0.4568593502,-1.4688404799,0.3038083017,-2.5448539257,-0.9092229009,-0.3816877902,0.7162517309,0.7011740804,-1.4708878994,1.0043964386,-0.0533178635,0.1780886203,-0.0656738058,-1.8832274675,-0.7870368361,0.2258797288,0.8136019707,-1.6132806540,-1.6500467062,-0.7262764573,-1.8060714006,0.1261256337,0.0837224349,0.0827596188,0.7586573362,0.6176240444,-0.3255368769,1.4318530560,0.0577022061,-0.2958157361,-0.6132124662,-0.8152903914,0.8220098615,0.2450569719,1.2573981285,1.5494660139,-1.2309507132,-0.9299182892,-0.6454734206,1.0468801260,1.1484909058,0.5869446993,-2.1177897453,0.4626471102,1.0198746920,-0.1138288900,0.4247196913,1.1570379734,-1.4135748148,0.0725923181,-0.2679024637,2.7661833763,0.2679988146,-0.5027480125,-0.0181943942,0.6711435914,-0.0941974670,0.1855315417,0.2543438077,-1.4764968157,-0.9377606511,0.3014186025,0.2370459586,0.7084241509,0.1626368910,0.3276515603,0.1585559845,0.2503229976,-1.1399179697,-1.0920814276,-0.6667899489,-0.8548904657,0.7033684850,-0.7761536837,2.1346483231,-0.2393279821,1.3535968065,-0.9506493211,-0.4076920450,-0.5581548810,0.1968198419,-2.0824365616,-0.6504297853,-0.7817162871,1.5999169350,-0.4707145393,0.2664442956,-0.0279191937,-2.3622436523,-1.2645890713,-0.0324613638,-0.4157408774,-1.9002436399,0.8337079883,-0.5889626145,-0.5031498671,-0.0618600398,-2.4662024975,0.0627399012,0.8152358532,2.1090805531,-0.0630077720,-0.1326286197,0.1434296221,0.8538603187,-0.1592878252,1.6691845655,-0.4810115099,0.4189854264,0.2810520232,1.4511069059,0.1108039841,-1.6083573103,-0.2608066201,0.6873603463,1.0323524475,0.3345609605,1.4037721157,-1.1845630407,-0.2300915718,-0.1948073506,0.5498065948,-0.2714291513,-0.7518230081,-1.1877788305,0.3030099869,1.2471328974,-2.2817478180,0.5460087061,0.8085818887,-1.4102207422,-0.7649542093,1.1998691559,-0.3109331429,-0.5489453673,-1.1739296913,-0.7573813200,0.3622814119,-0.1803682745,-0.5011548400,-1.0009831190,0.1868225932,-0.6029005051,-0.8547886014,-0.1348072588,-1.1864544153,0.7664079070,-1.4393889904,-0.9475734234,-0.5573213100,0.8925701380,0.5009971261,0.7198488712,-0.5231234431,-0.1421491206,-0.6183432341,0.0882850811,-1.6847449541,-0.5839746594,0.2101413608,-0.6959885955,-0.4180793464,1.7377842665,0.5398337245,2.4762804508,1.5915863514,-0.7944422960,-0.3500894308,0.1223903745,1.8400007486,-0.0912151709,-1.1437829733,-0.3499307334,0.8078536987,-1.0026249886,0.2237447202,-1.0386419296,0.2516576052,1.2548787594,0.0778929368,-0.4539818168,-0.5510498285,-0.0578782186,0.4725125134,1.8870012760,2.4323177338,0.2010755539,1.1056728363,-1.8366775513,0.9536247849,0.7939686775,1.1003919840,2.3458998203,1.4692678452,0.6490464211,1.9670273066,0.4042147398,0.6566967964,-0.7697871923,1.5224796534,-1.0281040668,-1.0950347185,0.8894008994,-0.7297667861,0.6717054844,-0.2670283914,-0.5510465503,0.0973181725,1.1938539743,-0.0754729062,-0.4562895000,-0.8172528744,-0.0423791744,-0.5283162594,-0.3101071119,0.1037842855,0.3862933218,-2.5298702717,0.0148019399,2.0022518635,0.4043906629,-1.8893733025,2.0781323910,-0.2799007893,1.5677926540,1.0496910810,0.2109147310,0.7038741112,-1.3184523582,0.7989603281,0.2703145444,-2.6894779205,0.5198162794,-2.2797818184,1.5013480186,0.9218204618,0.8572191596,0.8756232262,-1.7740607262,-0.4072049558,-0.0811734796,1.3906067610,0.8266698122,-1.7439453602,-0.0620697737,0.1208140701,0.1889812201,1.7714536190,2.0588123798,-2.7417387962,1.1500811577,-0.4305594563,-0.8185398579,2.0702614784,0.5266123414,1.0601838827,-0.5946053863,0.8639861941,-0.1706417352,0.6222539544,1.3736292124,-0.7181694508,0.0831693858,-1.1598395109,-0.4952351451,1.2962372303,0.0690178201,0.1662487537,0.3988175988,0.1684028208,1.8821505308,-0.5882483125,-1.0507441759,1.7254124880,0.1957102418,-0.3709122241,1.4042637348,-0.2510891557,-0.4316080213,0.0685362518,0.6092994213,0.7451376319,-0.4354406893,1.3262227774,1.4801108837,1.3739769459,0.1878964752,0.4108370543,0.9605338573,-1.5134578943,-0.1964982003,0.6435061097,0.0736133829,0.8728601336,-1.3197245598,-0.1270552576,0.0426341854,0.8820625544,1.1046253443,-0.2755198777,0.2538744807,-0.9900706410,1.3647599220,-0.8029752970,-0.9458059072,1.7950054407,-0.3628331125,-1.4039831161,-1.1162095070,0.4925628901,-2.0292842388,1.5619550943,-1.8280488253,-0.0055643721,-0.5366774201,-0.7328761816,-0.8478962183,0.0121869650,-1.6183778048,-0.4681866765,0.2380838990,0.3942469358,-0.0017471110,0.6457191110,0.1618220210,0.3286625147,0.1949937940,-1.8389343023,0.0252901614,-1.1302721500,0.5937021971,-0.1768487543,1.4522219896,-0.4664727151,-1.4856642485,-0.9684375525,-0.6833172441,-0.4522916675,-1.3983139992,0.2946139574,0.7114067674,-0.4360235631,1.3628817797,0.3709173501,-0.1819907874,-0.1708724201,0.6615654826,0.5053963065,-1.2913050652,-1.1293932199,-0.3762286007,1.4005522728,-0.3681354821,0.2439703345,-1.9376685619,0.0061770533,-0.3084800243,0.0341180898,0.6517161727,-1.0235981941,0.3485942483,-0.8717853427,0.1752543598,-0.8681605458,0.5755802989,-0.4126141667,-0.7222152352,0.9932783842,-0.8108548522,-0.8651838303,-0.4406715333,1.2634201050,0.3228797913,1.7299368382,-0.2031331807,0.7388085127,-0.3652395010,-1.0800300837,-0.4905096591,-0.3866543770,2.2770588398,-0.6903892756,0.9328139424,0.8298351765,0.0020154689,-0.4209246635,-0.6973096728,0.0860553086,-0.5382195115,-0.3424751163,-1.3047096729,3.0107023716,-0.2132201046,-1.7896158695,-0.2584707439,0.7357210517,-1.6454079151,-0.1919890344,0.8854669333,0.5473588109,2.1477603912,-0.3015838265,-0.3280054033,-0.5345777273,-0.0564358309,-1.0776684284,-0.0625013635,-0.8091907501,-0.9522696733,-0.0291139688,0.8151841760,0.4640530646,-0.4346605241,0.7263224721,-0.9717104435,0.0229827929,1.1674512625,-1.3929512501,1.2918885946,-0.2988780737,0.2283933908,0.3405737579,0.3639356792,-2.1020929813,0.8405295014,1.0143632889,-0.1635631919,-0.2963094711,0.1203462780,-0.5817037225,1.0243686438,-1.1446744204,-0.1163422912,1.0779199600,0.7442581654,-0.5289862752,0.3235702515,0.8104526401,-0.6944915652,0.7105034590,-0.4998841286,1.3602881432,0.9865704179,0.9607505798,-0.5986943245,0.3859920204,0.8108100891,1.3603370190,0.1453486830,0.4959866405,1.0660791397,-0.3927115500,1.5472337008,-0.9704090357,0.6275779605,-0.1618680060,0.5084855556,-1.0714122057,-0.8444173336,2.5354545116,-0.4143082500,1.4401415586,-1.8746173382,0.0717201754,0.9315521717,-0.1924583465,0.2826135755,-0.4956521988,-0.5171129704,2.2835865021,1.2014240026,0.4965412319,0.6352142096,0.2207820266,-1.5204813480,-0.2159054577,1.4612492323,0.4836098850,0.7791002393,-0.7924147248,-1.9963259697,-0.9082238078,-0.0739156827,-0.1735779345,-0.6885651946,-1.6898833513,0.1898370534,1.3742725849,0.4149084389,0.9179326892,0.1505246013,-2.1365816593,0.6585453749,0.0833003744,0.1664917320,0.2179910988,0.1975180507,-1.2237678766,-1.4798632860,-1.5096775293,-1.6420594454,-1.0052191019,-1.4127585888,0.2579631805,-0.4421169162,-0.0934734941,0.4567604363,2.2722504139,-0.3473166525,0.1571355462,-1.1206731796,0.4965228736,0.5498935580,0.1304169148,-0.7870458961,0.8281716704,0.4544727802,-0.0937828198,-0.8460122347,-0.0507329628,-1.3765958548,2.1486096382,-1.7733092308,-1.1574308872,-1.3433600664,-0.3764662147,0.2813237309,0.2202699929,0.6045076847,-0.1821339726,1.2025723457,-1.3828216791,-0.9747838378,0.2388301194,-0.8707327247,-0.1252780706,-0.6416910291,1.3086551428,-0.5332537889,0.0063522253,-0.6723710895,-1.6051152945,0.3130868971,-0.1302162409,1.4862173796,-1.0393095016,-1.2276927233,1.7093112469,-1.7208932638,-0.3173751235,-1.1881891489,-2.3398308754,0.2897851169,-0.5540105700,0.3708947003,-0.6902725697,0.4827075303,0.5152086020,-0.8001226783,0.5289755464,0.6751053929,0.1977580190,-1.8228195906,-0.5684699416,1.7509375811,-0.7015925646,0.6359348297,1.3688038588,1.0106269121,-0.6654335260,1.0200300217,0.0526707098,0.4489641190,2.0376715660,-1.5846176147,1.3363882303,0.4211618304,-2.3855931759,0.4183519781,0.7159678340,0.1074562818,-0.2730627060,0.3309553862,1.5496168137,1.1344338655,0.9619284868,-0.8347564340,1.0374566317,1.4408031702,0.1390461475,1.7395902872,2.9890756607,-0.3393157423,-1.5076727867,1.4666700363,0.2921347022,0.3553029597,0.9788808227,1.2384502888,0.3073142171,-0.6225633025,1.0165023804,-0.7128052115,-0.0668653473,-0.5550617576,0.4804181457,2.0454192162,0.0330334306,-0.2663131058,-0.7029079199,-0.2169049233,-1.0697338581,-0.8404394388,-1.1840552092,-2.3508896828,0.1685397476,-0.1027170047,0.5997434855,-1.9493203163,-0.8024225235,-0.4092237949,-0.4173745215,0.2873328328,0.4117684960,0.2399783283,0.2981419265,-1.6334201097,-0.9804607034,-0.3757415116,0.6015896201,-0.7534538507,-1.1112320423,1.6509275436,-0.1514259428,-0.4161066115,-0.3126336038,1.3812828064,0.8161883950,-0.0387242921,0.7398338914,0.0209227726,-0.4717726409,0.1601802260,0.7710543275,0.1447940767,-0.0283841789,-1.6753015518,-0.8868216276,-1.0859651566,-0.6444486380,-2.2279274464,1.3281667233,0.0351902060,0.0617455207,-1.5774900913,-0.5398665667,0.7255911231,-0.4908719063,2.2670347691,-1.9021373987,1.2350738049,-0.9386199713,0.7089691162,0.7957819104,-0.9514808655,1.2497242689,-0.3672064841,-1.3906115294,-0.5919629335,1.7621365786,-1.4293707609,0.3684018254,-0.7765325308,-0.1114501879,-0.9075161219,1.2576494217,-0.8669949770,0.4935116470,0.1877672523,-1.3370648623,-0.7650950551,1.1577278376,-0.6422299743,-0.6276326776,0.1233862042,0.2219813317,0.0170367789,-0.7312810421,0.6946656704,-0.7900857925,0.5711570978,-0.6337569356,-1.2564939260,-1.9684580564,0.7597616911,-0.6197546721,1.0595633984,-0.1620984077,-1.4307351112,-1.2425879240,0.3334033489,-0.8551697135,0.7142262459,0.2552497387,-1.4737071991,-1.2400416136,1.2253839970,-0.4654192924,-2.1136255264,0.6339798570,1.6607668400,0.7691323161,-0.0107232919,-0.3207734525,-0.8382658362,0.3205773532,0.0976580307,0.2763164639,-0.4415012300,-0.7790068388,-0.6566889286,1.4151773453,0.4216744602,-0.8975771666,-0.4491711557,1.3207405806,0.9556534886,-0.2062499523,-0.4255151749,-0.5410502553,0.7635242343,1.0545524359,-0.4757571518,-0.3823243380,0.3522265255,0.6711670756,-1.7673711777,1.4733440876,-0.5324310660,-1.6187958717,0.6993540525,-0.9426357150,-1.1725157499,-0.3552233279,0.5078729391,1.4298133850,0.2571879029,1.4719634056,0.5778535008,-0.2065822333,2.3589992523,0.2131077051,-0.3065221906,0.4680456221,0.1980422735,-0.8443328142,-0.2465468198,2.7550952435,-0.0163592007,0.0708196610,-0.3586863875,-0.1086756513,1.2919684649,0.9084424376,0.7995363474,0.3683059812,1.1267640591,-0.0028436235,0.1808570176,-0.1837261468,-1.2601875067,-0.2753442824,-0.0100960284,-0.1514759511,1.3774771690,0.2780973613,0.1607485414,-0.3234707117,-0.6531004310,-0.4414724708,1.2662265301,1.3459706306,-1.0425080061,-0.2603740394,0.0437238626,0.2833698094,-0.0748640820,-0.3282703161,0.6336637735,0.0157164261,-1.1069000959,0.0525508635,0.2700309157,-0.3761922717,-0.4791140258,0.4749079943,-0.2400727868,-1.6324510574,0.1481562406,-0.2036515921,0.5730488300,0.3368732631,0.6147609949,0.8890558481,-0.7400008440,2.0510735512,0.0945650861,-0.3494800329,-0.6844366193,0.1977184117,-1.5378758907,1.7580767870,0.4568970799,0.7572392821,1.4373345375,0.2000212222,0.0556829832,-0.2715509832,1.1920673847,0.8942832351,-1.2035263777,0.4194567502,0.4005192220,0.5703665614,0.5575336814,-1.3979532719,1.0963864326,0.0250807907,-0.0674761832,-1.3193664551,-0.3257948756,-0.1157574356,0.1749069393,1.5000028610,1.1391853094,-0.9547190070,1.0541182756,-0.2260276377,0.7414301634,0.9308434725,0.1472192556,0.2028086632,1.0589454174,-0.3633924425,-0.3617959023,-1.1625291109,2.2101442814,0.2819685638,0.1859583557,-0.2687607408,0.0440233089,-1.0015631914,0.6896772385,-1.3712488413,-1.0608513355,-1.1808810234,-0.4728468060,1.0679525137,0.9100573063,1.6535276175,-0.5239212513,0.5605090261,0.9432093501,-1.9324355125,0.8190538883,-2.1978337765,-0.2977302969,0.6257901192,-0.1263576597,0.9088796973,1.5055203438,0.1521550417,-2.2133748531,-0.1194746345,-0.5715026259,1.5380450487,-1.0065170527,-0.5844327807,2.0164713860,0.0378994644,-0.1642175913,0.5951735377,-0.7040801644,-0.2119091898,-1.3055820465,-0.0513718873,-0.3308599591,0.0339758396,0.8075446486,0.1187833175,0.6131482124,-0.4814960957,0.0764794052,0.9820422530,-1.7076627016,1.3723251820,-0.7145006061,-0.5938451886,-0.0183429793,0.7288543582,0.8106418252,-1.5039621592,0.3948372304,1.0601956844,1.0729640722,-0.2177887261,-0.3614816070,0.6474339366,0.4636586905,0.1736662537,0.7257980108,-1.3463358879,-0.1328872144,-0.4435177147,0.2674212754,0.8134050369,-0.8270956278,-0.7177349329,0.6141757965,0.6915240884,-0.4994766414,0.5097733736,-0.1994809657,-0.9650039077,-1.3885537386,1.5378166437,0.5882808566,-1.0985815525,-0.8555923700,-1.3664350510,-0.5528749228,0.2774377763,0.6846002936,-0.6543120742,-0.9933399558,-2.6504812241,0.3394016325,-0.2626033425,0.4674544036,-0.2633951604,-0.2068358809,-1.0403506756,0.4053127766,1.1273319721,0.1939062625,1.3327549696,0.7872596979,-1.1306591034,-0.3493178189,0.1557210684,1.1165831089,1.3770676851,-0.7949782610,-0.6838003397,0.6526792049,0.6445679665,-1.1254947186,-0.2173337489,-0.8494017124,1.1666642427,1.2532933950,0.9628742337,1.0837029219,-0.6331955194,0.8385151029,0.3361526430,0.3915138543,-0.0933211073,1.1968898773,-0.5742031932,-0.0500956103,0.9402880669,0.7142255902,0.5690819621,0.7714705467,-1.5002479553,0.3130998313,1.1639127731,0.6727718711,0.0101976758,0.9451437593,0.5655166507,1.6275627613,0.8402985334,-0.3411326110,-0.3251051605,-0.7312197685,-0.2371633053,-0.1245433688,-1.7427054644,-0.6266471148,1.6334964037,-0.0915187076,-0.3417382836,-0.0914409012,0.6394451261,-0.9623674154,-0.2364961803,-1.0329637527,-0.1231606677,-0.2556661069,1.1051532030,-0.3228335083,-0.9258052707,0.6563531756,-0.4999623001,-1.6209917068,-0.1153591797,-0.8811206222,1.0089468956,1.2612160444,0.5947718620,-0.2692162991,0.2056351900,0.5102504492,1.7642725706,-0.5403218269,1.0996212959,-1.2504529953,1.0675100088,0.5051488876,-0.8187961578,-0.8085387945,0.0946609080,-0.1569521129,0.7736035585,-2.0229930878,-0.5482857823,1.0867170095,-0.1797525287,-1.0244921446,-0.3236004710,1.0927515030,-0.2026444674,0.4056845307,-1.0475788116,1.4953615665,2.0108199120,-0.3379966319,-0.3342337012,-0.4520601332,0.9962898493,-1.3105881214,1.2578663826,0.2881660163,0.5212141275,2.0398442745,0.8010252714,-0.7030718923,-1.5192036629,-1.2763825655,0.7861399651,-0.5948548317,1.0182152987,-2.0379059315,-1.1396664381,-0.4048861265,0.0318119638,0.8137828708,-0.8330386877,-2.0578346252,1.3120894432,-0.2637521923,-0.4078529477,0.2702302933,0.7227398157,-0.8606963754,-0.5009006858,0.4711194634,1.6186574697,1.4121378660,-0.0002848467,0.6598795652,1.2394162416,-0.5023958683,0.4566825926,-0.8102485538,-0.0185096450,1.5662649870,-1.0101697445,0.5655524731,-0.2134593427,0.0219880417,1.3343462944,-0.9169719815,-0.1619948745,1.0586124659,-0.3841233253,0.1626750678,2.1752021313,1.5525988340,-0.2626132071,-0.6253407598,-0.3021035790,0.5044687390,-0.1912412196,-0.0795418695,-0.6908488274,-0.4781500995,1.0784960985,-0.4422915280,-0.4586786628,-0.1436938047,-1.0484225750,0.3351688981,0.9214617610,-0.1563158184,0.3626534641,0.6382313967,1.2679969072,-0.0452971682,0.7486544847,0.5606036186,0.9569472671,-0.0700276718,-0.3959464133,0.1904693246,-0.7078367472,-0.0979526788,1.9592298269,-1.1198773384,0.4000999331,-0.3875292540,1.4898318052,0.6270580292,0.5690717697,-0.3728976846,-0.5502703786,-1.1284275055,-0.0041970341,-1.6097604036,1.1527045965,1.6746832132,1.5408614874,2.0273838043,-0.5349593759,0.7125822902,0.7540348172,-2.8705582619,-1.8638910055,0.5038121939,0.6373669505,-0.5574759841,-0.5050622821,-0.8507771492,-0.5713256001,0.8568009734,0.5190439820,0.0653787851,-0.9294126034,-0.6523821950,0.4704572558,-0.8607774973,-0.1529620588,0.0826679990,-0.1757801771,-0.5495941639,0.7834180593,0.0671116933,0.7145394087,-1.3842253685,-0.7460412979,-0.6277463436,1.0182669163,0.0907923281,0.9149090052,1.0882586241,1.7943143845,0.4608672261,-0.0809834972,-0.8602779508,1.1938617229,0.6517693996,0.0092181843,-0.7635804415,1.2017304897,-0.8502430916,-0.1846573204,-1.6849205494,-0.2419226319,0.4188693166,1.2817186117,-0.4473271072,-0.1569877714,0.7320977449,-0.0141397016,0.4355955422,0.4715900123,0.6773759723,-0.4215749204,0.3264049292,2.4344141483,-0.0604711324,-1.0446228981,1.5301111937,1.3959794044,-1.4553323984,1.7583258152,1.5257213116,-3.0210578442,-0.9142537117,1.7957469225,1.1200355291,0.5840203762,0.5999845266,0.0407632738,0.6290143728,0.2058549970,-1.1277829409,-0.8097259998,1.6846119165,-1.2507945299,0.1569381058,0.7785435915,0.7929396629,-1.8754302263,-1.1775150299,-0.9298060536,1.7393478155,0.4945442080,0.4163727760,1.5628179312,0.2502279580,1.3238953352,0.4312912524,0.0220150761,-0.2147385180,-1.8523584604,-2.0134761333,1.4432740211,-0.5076486468,1.3906644583,0.5807424188,1.2673971653,0.2372799963,-1.5070856810,1.0928071737,-1.5873508453,-0.1693418473,-0.4200076759,0.2688405514,-0.3601242900,-1.2954751253,-0.7431051731,-1.2575507164,-0.2012025267,2.2574408054,0.1104647666,-0.1512969583,0.0174025111,0.4458542466,-0.7248215079,0.9082215428,-1.3589265347,-0.9368333817,-0.7312052250,1.0721185207,-0.7326382995,-0.5639464259,0.6095701456,-2.0346000195,1.0954475403,-0.2311936021,1.4384429455,0.5641620755,-0.2077282071,2.3088765144,0.9453276396,-0.1790513992,-0.6986765265,0.0849507675,1.8025000095,0.4350953996,0.7734685540,-0.3476094306,-0.3814012110,0.4308768213,-0.9413963556,0.5490882397,-1.2022879124,-1.0516980886,-0.9482901096,-1.6367952824,1.8386996984,-0.7118865252,0.1055972502,-0.7026752830,-1.0756582022,-0.1422663033,0.3937110305,-1.8437414169,-0.2732995152,-0.2043423504,0.5992166400,0.6439359784,1.7993170023,-0.7580192089,-1.3359285593,1.4962481260,0.1730103940,-0.6356427073,0.0779678747,-0.3810184300,0.4025068283,-1.0337539911,-2.1191465855,0.2678066492,-0.5662587285,-0.5005620718,-1.0199508667,0.2415617257,-1.9484695196,-0.5845148563,2.9574551582,-0.1329732090,-0.2781083882,2.0026571751,-0.6654509902,-0.9315814972,-0.5124284029,-1.0220663548,1.5914081335,0.7247942090,-0.8515052199,0.6342797875,-0.4960220754,0.5928196907,-0.9952784181,0.8246176839,1.0320022106,-1.9398835897,2.0664064884,-0.9641517997,-1.8633273840,-0.0337739438,-1.3035702705,0.1331416517,0.1698399037,-0.1870108247,0.3671292365,-0.4189546108,-0.4695348442,-2.6624681950,0.5423961878,1.5010020733,0.3459192812,0.0675365776,-0.8721294999,-0.4595796466,-0.5068891644,0.5873795748,0.3420045674,-0.0998604968,0.4836119413,-1.3472015858,1.6239326000,0.6348768473,0.0179399494,-0.4565315545,-0.2640585005,0.8355404139,1.1033011675,1.5110306740,1.1274770498,-0.7093459368,-0.0744580925,0.2659905851,-0.1485776901,-1.6719353199,0.7489042878,0.0443355255,-0.9490557909,-0.8815689087,-0.6441028118,1.2353124619,-1.6454527378,0.3230223954,1.0776292086,-0.8387464285,-0.5173830986,1.4620894194,-0.0286578313,-0.7814294100,1.4929542542,-0.7920092344,0.3892004192,-0.4025924206,-0.9289677143,0.8831150532,-2.4916441441,-0.7269167304,-0.3389181793,0.0518149436,2.3087661266,-1.0090583563,0.9877404571,0.1650268286,0.9553805590,-0.7569466829,0.7209989429,-1.1299874783,-1.3067044020,1.1002798080,1.8736176491,-0.1802768111,0.9645875096,0.7066676021,-0.1683974713,-0.9512957931,-0.8372158408,-0.3797715008,-0.2867600620,1.0953788757,-0.4406148195,-1.3737680912,-0.8403751254,0.7122806311,0.6732238531,-1.2772501707,1.4470598698,-1.6477565765,0.8578764796,0.9182669520,1.3492974043,0.6436387897,-0.1199597120,-1.4940854311,0.1026622728,0.7803411484,-0.5787874460,0.9917155504,0.4909535050,-0.5574346185,-0.6866763234,0.2321932614,-2.1183209419,0.4316413403,-0.4042158127,0.8837202191,-0.1353183091,-0.7172310352,2.7005834579,1.1152646542,0.8556065559,0.3109346032,-1.0019065142,-0.1889768243,0.6665068865,1.8737750053,0.5609683990,-0.4682036340,-0.3340584040,1.0639505386,0.1632687896,-0.2742658556,1.0798113346,-0.6057754159,-0.2749799490,-1.1890770197,-0.2930025756,1.8735110760,2.2746007442,0.8219443560,1.9643771648,1.3195849657,0.1458032131,0.5102447271,-1.6404271126,0.6829751134,-0.6760859489,-0.7591422200,1.1757338047,-1.2378255129,0.8542348742,-1.6906770468,-0.5590405464,-2.0516254902,-0.7075557709,-0.6136775017,0.7814898491,0.3277451098,0.7363686562,-0.7694044113,2.5541281700,-0.9461388588,-1.0866278410,-0.6960321069,0.3335900009,1.2417874336,1.3287516832,0.9328956604,-1.0503815413,0.2631334960,0.5054531693,-1.5257029533,-0.2071426213,1.1814788580,0.2966313064,-0.9725993872,0.3309081495,-0.3167668879,0.6853064895,-0.2060380578,2.7066907883,1.5249216557,1.2280702591,0.5085874200,-0.3147315979,-0.1998735368,-0.7020621896,-0.7529008389,-0.6573159099,-0.4857104123,0.2419129610,0.4221928120,-0.8887619972,0.4519138634,-0.5847700834,1.5164148808,-0.3560203314,-0.9716092944,-1.1448581219,0.1373418719,-1.6014651060,1.3189338446,0.2547961473,-1.4622094631,-0.1789774597,0.8794451356,-0.3040826917,1.5860936642,-0.7125411630,-1.5092651844,-0.4747304022,0.4026572704,-1.7841160297,1.4312634468,0.6950429678,0.4651306272,0.8870432973,0.0887216479,0.4096937478,-0.5062332749,-0.2962773740,1.1971416473,1.3719564676,1.9563847780,0.8283421993,1.7993576527,-1.2152526379,-0.0858739465,0.2326095849,-0.2911576033,1.0595628023,-0.5787106156,-0.4047865868,-0.5017714500,0.0693776011,-0.4276338816,-1.3622661829,0.4445276856,-0.7927712202,0.9814260602,0.5316746831,1.5762796402,0.8111576438,1.9288363457,-2.2223255634,-1.3883488178,-0.3999559581,0.1310270727,-0.3544170260,0.9905593395,0.2306950390,1.9439210892,-0.5027143359,-0.0143833691,0.3165681660,-0.1115248650,-0.0917987972,0.2415666580,-0.0787839368,0.4116333425,0.5505738258,1.1692513227,0.7651976943,1.2653208971,-1.2472923994,1.1245467663,0.4015773833,-0.2108438611,1.5653553009,-0.0090202373,0.3653865457,-1.0638052225,0.3883264959,1.2481312752,-0.1546858996,1.3234074116,-0.8675174117,2.0376651287,-0.7730429769,0.4148543179,0.2054794282,-0.8716959357,0.5587248802,-1.0899597406,0.5063377619,0.2100979537,-1.6693204641,-0.4869732261,0.8901972771,0.7649075389,1.4790863991,0.1984126270,0.2106683105,1.2196710110,0.4870115221,-0.8584403992,-0.6259924769,-0.4319318235,-0.2345139086,1.1433793306,1.2349792719,1.1137609482,0.3417917192,2.7702353001,0.5551794171,-0.7779662013,-1.3389432430,0.3691887856,2.0352487564,0.1049689651,-1.3625838757,-1.2054003477,-0.1510334313,1.4791287184,1.5493704081,-1.2234296799,1.1098680496,-0.3641369641,0.2689851820,1.0093431473,-1.0931015015,0.8034202456,-0.1910215169,-1.2416673899,-1.4777083397,1.0865781307,-0.2192025781,-1.4991483688,-0.3896990120,0.7066301703,0.6640823483,-0.2975024283,-0.1652295887,0.2889887094,-2.8535153866,0.6054579616,-0.0322866999,-0.8152453303,-1.0316278934,-0.4888164401,-1.3081847429,-0.1466890872,2.9084668159,2.2889723778,-0.4269299209,1.8235203028,0.6112687588,0.1520540267,0.2729745209,0.4491570592,2.5501518250,1.4125373363,-0.3937563598,0.6757388115,0.1855499148,0.8891111016,0.4965530932,0.6705762148,-1.0051658154,0.4118530452,-0.3306933641,0.7756954432,-0.1614267975,0.3098185360,1.0678449869,0.8791055083,1.5784460306,0.1212876365,-2.1881835461,0.2398423702,-0.6166628599,-1.0495116711,-0.2046049982,-1.5786684752,-0.4201811254,1.0646731853,0.6574370265,-0.4980138242,-0.9568085670,-0.3948968053,0.5613503456,-0.2417133749,0.0204319879,0.4374487698,0.9105584025,-0.1001281738,-0.0798568353,0.0035209819,1.7699304819,-0.8864417672,1.1483435631,0.9128133655,2.3566586971,0.0609659180,-1.8903415203,-0.9600875974,-0.0770855024,-0.2616542280,-1.2499434948,0.5119954944,-1.7796143293,-1.5820428133,0.8977500200,-0.7375071049,-0.7488090396,-2.2484743595,-0.8623650074,-0.7743161917,1.3640680313,0.4618594646,-0.4605868459,0.1531334072,0.2061138004,-0.7647488117,-0.0337435305,-0.7385146022,-0.5625520945,-1.2569856644,0.2129893452,-0.9553509355,0.0948104262,2.5250504017,-1.6878075600,0.6934902072,0.6625792384,-0.5822758675,-0.7410813570,0.0621082224,-0.0299436729,1.1133687496,0.4249279499,0.5673895478,0.1886189878,0.0354875848,0.1282968819,-0.6992625594,1.1561349630,1.9655958414,0.4005120397,-2.1143636703,-0.5863888860,0.7493094206,0.5219535232,0.8459887505,0.5666259527,0.1399505585,-1.2476874590,-0.4998947680,0.3239963055,2.3878009319,0.4304938018,-1.2388671637,-1.0990287066,-0.3986670673,-2.1690292358,0.5610336661,-0.2620897889,-0.7111989856,0.2920810878,-1.6883717775,-0.1379259974,-0.9189206958,0.4376925528,1.5696545839,0.6147102118,0.5508036017,-2.5583667755,0.3781401813,-0.5038151741,-1.7127869129,-1.4350970984,-0.1412201822,-0.0816503242,0.4081589580,0.7809235454,0.6255474687,-0.2427212447,-0.2043065876,-0.6814991832,-1.8603205681,-0.5025548339,-1.9000107050,-0.1304477006,-0.6851273179,1.0265516043,-0.6661650538,-2.3975861073,-1.7486999035,0.0605677813,0.6212993264,0.4197052121,-0.3831737936,1.3025627136,1.1073590517,-0.8643981814,1.3570622206,-0.4238911569,-1.2117905617,0.1408114433,-0.1960694492,0.6899011731,-1.3563886881,1.4247977734,-2.2074992657,-0.5906651020,0.6465181708,-2.1144294739,0.8956786990,-0.9129745960,2.0979588032,-1.1935856342,-1.2795675993,-0.8881188035,1.0661122799,1.6177762747,1.1079305410,-2.0232996941,-1.2102463245,1.5625468493,1.1707061529,0.2248326093,-2.2631869316,0.3136663437,2.0882434845,-1.1118528843,0.8269920945,2.2001664639,-1.0525869131,0.1732597351,-0.6301019788,-0.2861230671,-0.7035486102,-0.6158868670,0.6836638451,1.2540742159,1.1350761652,1.1168063879,-0.0671314672,-0.5278354883,-1.6708488464,-1.8426793814,-1.4898799658,1.5074266195,0.8699860573,0.4585454762,-1.2405214310,-0.3520327508,0.2623713315,1.2189782858,1.9564009905,-1.8678971529,0.2386119515,-0.3934918940,0.0209807158,0.0772104561,-1.7392042875,-3.5995438099,0.9020640850,-0.1195738018,-0.5754822493,-1.1097879410,-0.1072186753,-0.9343097210,1.1105796099,-1.1826517582,-0.1520720869,-1.3386286497,-0.6448604465,-0.0941165313,-1.3919219971,-0.0296481308,0.1762068868,-0.2783095539,-1.6376761198,-1.0517594814,-0.6948207021,0.0998614058,-0.6569946408,-1.8207826614,-1.1987988949,0.8665890098,-1.1092697382,-1.3847301006,-0.3812083602,-0.3967207372,0.7238845229,0.1558206677,-0.3647925258,-0.5851247311,0.4368338585,-0.7570932508,0.0958884582,0.7646985650,0.6894189119,-1.3329033852,0.0163381044,-0.3504721224,-0.7617780566,-0.8003528714,0.9703143835,0.2425616533,1.4180577993,0.8548147082,-0.4770228565,-2.0487129688,-0.4198290110,-0.5687003136,-1.3870117664,-0.5220409632,1.4553519487,0.5901443362,-2.1908631325,0.0048135603,-0.9869437814,-1.1687397957,-0.6182921529,0.3242558539,0.1612989306,-0.5659643412,-0.6204778552,-0.6357564330,-2.4414963722,1.7249587774,-0.4532583356,0.7349098921,0.6877690554,1.6072475910,1.3938087225,-0.1504776627,0.1785371900,1.7748429775,-0.2517042160,1.1803649664,-0.4024221003,0.2015507370,0.2357416600,-0.1340533942,-0.1057958901,1.6359223127,0.3880910873,-0.3377050757,-0.4242796600,0.1702330261,1.4504141808,-0.2115017474,1.4328291416,-0.5159255266,0.0500065312,-1.7297106981,1.3677421808,-1.0256661177,0.7512863278,-0.5840461850,-0.9218277931,-1.3074322939,-0.7596263885,-0.1303110570,0.6998056173,1.6276044846,0.9300687313,-0.6382806897,0.6924938560,-1.4637494087,-1.0807045698,-0.7944297791,-0.2523753047,-0.9769495130,0.0696765333,0.0790520534,0.4146587253,-0.3838759363,-0.8621741533,0.5710561872,0.5936986208,0.4419238269,-0.2544811368,-0.0549358837,0.2354987264,-0.5314922929,-0.5649043918,-2.2214460373,0.5590788722,1.1864672899,-0.7585781217,-0.6145302057,-1.5558300018,-1.4099539518,0.8280416727,0.9231147766,0.7842741013,0.9364667535,0.1571408212,-0.0711527541,-0.3171508014,0.5082898140,-0.4674690962,0.2489854246,-0.6435582042,0.1705356985,0.0941540748,2.0618970394,-1.3521838188,-0.6742211580,1.9083428383,0.3393023908,-1.2060261965,-0.3309186101,-0.1274856180,1.2129625082,0.0350924097,0.8869325519,0.4675163925,0.3396925926,-0.6079598665,0.8370874524,-0.9059494138,1.4852802753,-0.2368526459,0.5075811744,1.3175470829,0.9353399873,-0.5524255037,0.1175686345,-2.5573158264,-1.6868667603,0.2753569782,1.0403324366,-0.6371220946,-0.2227719426,-0.2769407034,-0.5384197831,-1.2360104322,1.6299774647,0.3417989910,-0.1112552434,0.3643215597,1.7209881544,0.5956207514,0.1271493584,-0.3662891388,0.8358281851,-0.4693106115,-1.0826193094,1.5552965403,-0.3990328312,0.3532243371,1.3296083212,-0.1214048937,1.4217294455,0.2872732282,0.0609251931,-1.2650548220,-0.2146121860,-0.5631961823,0.9530636668,-0.5803635716,1.0396372080,0.0411144495,0.4864621758,-0.6175361276,-0.0901167020,-0.4780751169,1.1069477797,-0.1862807423,-0.8247175217,-1.6179413795,0.7025146484,0.3208766282,-0.1970423460,0.7278860211,1.6373358965,0.6480888724,-0.8358708024,0.6518102288,-0.1171416640,-1.0953273773,0.3416704834,0.2952704728,0.0544999093,0.1129286736,-0.2682801485,-0.7968363166,-1.3915562630,-1.0005905628,0.0861226767,-0.2342195213,-0.2970535755,0.3015836179,0.6606718898,-0.3637237549,0.2571111917,0.4363758266,-0.2371700704,1.7235711813,-0.2948478460,0.4730113745,-0.1083832458,0.9850977063,-0.3806095421,-1.6842314005,-0.3037002683,-1.1704878807,1.0020384789,0.3830957711,-0.6013025641,1.1467078924,0.0981238931,1.7418649197,0.6734358072,0.3837615550,0.2948663235,1.7496265173,0.6189327836,-1.7904872894,-0.4210635424,0.9242000580,0.6071117520,0.6344060898,-0.7756280303,0.8779548407,-1.7009711266,1.8138630390,0.3526122868,0.1569912732,-0.2284603566,0.4965924919,0.1646198183,0.5903906226,0.6860850453,0.9792392254,0.8350661397,0.2694632113,0.5770038366,0.6414442062,-0.0007064881,0.1891670227,3.3849787712,0.3436114490,1.0508141518,0.8994019032,-1.4829807281,0.5896140933,-0.7613607645,-0.2228245735,-2.2727417946,-0.7928166986,0.8713169694,0.7702066302,-0.2003716528,-1.1520656347,1.3296504021,0.1453818381,0.1850291640,2.1702175140,-0.0070129517,-0.9936382174,0.7370295525,0.6775777340,-0.3520190716,0.2269107550,0.3641117215,0.2620734572,-0.3037872612,0.7699797153,-0.5900830030,-0.0836289078,1.4655891657,-0.4953507483,0.9964833856,0.6668241024,1.6373746395,-1.0739023685,1.5138012171,-0.9158896208,0.3178542852,0.1864966750,0.7493636012,-1.6645890474,-2.7454783916,-1.2306253910,-1.6678169966,0.2192802429,-1.4617450237,-0.8441195488,-0.5457106829,-0.5780082941,1.8181878328,0.0347079597,-0.3133533299,-1.1121459007,0.7268883586,0.3151122928,-0.5868066549,-1.7393980026,1.4476518631,0.4207965732,0.6836621165,1.8285927773,2.0717456341,1.6458361149,-0.2653712630,1.2877157927,0.4153696597,-0.8352056146,-2.2649061680,0.0756139308,-1.1362289190,2.3471145630,0.6214581132,2.1959691048,-1.1375454664,-2.3548367023,0.2680402696,0.2878903747,-2.3156638145,0.7746370435,0.5787066221,-0.5267652869,0.7834333181,-0.6082605720,-0.2690319419,0.3098383546,-2.3032941818,-0.5287114978,-0.4524430037,0.5710779428,0.2465500385,-0.0645666569,0.3519504070,-0.5015529990,0.3956600130,1.3372106552,0.8897716999,-0.4648024738,-0.2677031755,0.2189188153,0.4962541163,-0.4791700840,2.3462817669,-0.5984350443,1.2644433975,0.1036138311,-0.6658110619,0.0362412110,-0.2366671264,0.1581058204,1.3862762451,0.6495568156,-0.2329453528,0.0977031738,-0.5559794307,-0.8441994190,-0.0818201452,-0.1046767831,0.1273758411,0.4763332605,-0.1459098011,-0.1045340598,0.7774121165,-1.0574012995,-0.3140885234,-0.1191266701,0.8644908071,-0.0673007965,-0.6035963893,-0.5750159621,0.1821621656,0.6175658703,-0.7133141160,-1.4616454840,-1.5156626701,-0.5073814392,-2.4346702099,-0.7047346234,0.9782006741,0.8120400906,-0.4308604598,-0.4996556640,-0.5441598892,-0.2324918956,-0.7524700165,0.4344911575,0.1049314365,-1.2540309429,0.8012621999,1.1741023064,0.1364507526,0.0647116527,1.0092266798,-0.9059830308,-2.1721153259,1.1897959709,-0.1393132359,-0.8553556204,1.7093845606,-1.1029998064,-0.1866924912,1.3107669353,1.1628562212,1.0969941616,-1.2107185125,0.5536623001,1.1172728539,-0.2946329415,1.9040652514,0.0030044951,0.0876778588,-1.6686580181,0.0381268524,-0.3123620749,-0.5600023866,-1.0734754801,-1.3627321720,-1.2353109121,-0.0829710588,-0.1355157346,-0.9162235856,0.3678059578,-0.2945487499,-0.4046669006,0.8659502268,-0.5342887640,0.8775099516,0.2651894093,-0.0377184190,0.7347764373,1.7639116049,0.0837946832,1.2767306566,0.5433607101,-1.1277854443,-0.4092319906,0.3871065974,-1.3732262850,0.0484902039,0.3826854825,-0.8100257516,0.5566810369,-0.0652687475,-0.5655643344,-0.7411604524,-0.2269089818,-0.8638867736,0.9950011969,0.2840652168,0.5898693800,0.1182757393,-0.6138235927,-0.4195107520,-0.6143563986,0.2658936679,-2.7899060249,2.2320573330,1.3054738045,0.5085213184,-2.8490052223,0.5092891455,-2.4805524349,-0.7394009829,0.6821433306,1.6671719551,0.4611730278,-1.3810774088,0.7877162099,1.0247899294,-0.4438346326,1.6174777746,-0.5054686666,0.1760485619,-1.3114635944,0.4309389293,0.4800304770,-0.1087075472,-0.5780231953,-0.7047863603,-2.1476862431,-0.2139531970,0.8352521062,0.8809152246,0.2713364661,0.3603095114,0.3651247323,-0.8552098274,-1.1180651188,-0.6216140389,1.9746416807,-1.6354407072,0.6205993295,-0.3181858361,-0.5416350961,-0.8335084915,-1.0118873119,0.4987774491,-0.3509887457,-1.1358166933,-1.7522422075,0.6429727077,-0.1995020509,-1.5381036997,0.1544527858,-1.2883707285,0.5439504981,-0.0020331419,-0.2399383932,2.7470574379,0.5867281556,-1.3848453760,-1.5909763575,-1.3414326906,1.2320175171,0.9906088114,1.5391710997,1.7031075954,0.1598866582,0.5140388608,0.7190224528,0.2349463552,0.8574712276,-1.1896023750,-1.2586706877,0.2605868578,-1.1289823055,0.5695583820,0.5411376357,0.3698288500,0.3675069809,-2.2430713177,-0.6659237146,0.8024030924,-1.3820905685,1.0470803976,-1.4281877279,-0.3887173235,0.3055648804,-1.5657507181,-2.1697707176,1.4391497374,-1.5002782345,0.8511645794,0.5123485923,-0.0351729281,-0.1442015767,-0.3420092463,1.5379468203,0.9169666171,0.0578503907,0.2137975246,0.1961234212,-0.5389728546,-1.6089800596,0.4754639268,0.2233437747,0.1733196378,1.2684612274,-0.2865017951,-0.1468806267,2.4246311188,-0.0136099840,-0.1019738093,-0.6110169291,-0.8038156033,-0.0695337504,0.4967861176,1.9961833954,1.2340877056,-0.0171101298,0.0730238631,1.2438621521,-0.5428292155,0.5201815963,-2.0732119083,1.0970755816,1.7306132317,-1.7191520929,-1.0230888128,-1.6075240374,0.6967043877,1.0618695021,-0.3732878268,0.6697552204,-0.9198107123,0.7653980255,0.6345857382,0.3547610641,0.7504929900,-0.3338160217,-0.5197306275,0.9472274780,0.2227191478,-0.1130388081,-0.0185331739,0.5474200845,-2.2555432320,0.4503259957,0.9500397444,-1.8120361567,-0.9349394441,-0.0216028914,0.5007613301,-1.4258812666,0.9653455615,-0.2123300284,-0.9972632527,0.4599822760,1.4621566534,-0.9623032212,0.0821985975,0.7254318595,-0.8844993114,-1.1279693842,-0.0905174986,2.1163721085,0.5569891334,0.4357909858,0.1275379509,-0.3727503419,-1.5048179626,-0.9216700792,2.6693191528,1.8621063232,0.0340112634,-0.2996329963,0.1685769856,-0.0407568179,0.2233879268,-1.7338620424,0.4193114340,-1.7407432795,-0.3416656554,1.9146230221,0.7406899929,-1.3047709465,0.4453069568,-1.8995198011,0.1776600182,-0.1196291074,0.6559990048,0.4963692725,-0.4981673658,-0.2931072414,-1.5256278515,-0.3368673921,-0.0629800633,-0.3711330593,-0.4460727274,-0.1216611713,-0.7857735753,1.7829257250,0.5151084661,-1.0354783535,0.3958749175,-0.7858343124,0.3499429822,-0.4504361749,1.8571742773,-0.5264532566,0.8362266421,-0.6549919248,-2.2250118256,-0.3075691462,-0.7183296084,1.3063586950,0.2724380791,-0.7761501074,-0.3567362130,0.0337915644,-0.6230852008,1.2878644466,0.8142136335,0.7467980981,0.0545031875,-0.7823157907,-2.0375680923,-1.5598759651,0.7258884311,0.2529396415,-0.1873801351,-0.2569098175,0.9535322785,0.3202666640,0.9372274280,-0.7806515098,0.0057575130,2.1948187351,2.1471142769,-0.3790979385,1.2801339626,0.6664164662,0.8390047550,0.2793636620,0.3506715596,-0.8946903348,-0.1892145276,-0.2091954798,0.8307814598,0.7596340775,-0.6366750598,-0.2397034466,0.0246799253,-0.7540863156,0.6899034381,0.7105519772,1.9139291048,-0.9092925787,1.0814040899,-1.6866900921,1.2264014482,-0.0857531503,1.1177709103,0.0718116313,0.6214321852,0.8597166538,2.5825061798,-0.0952331051,0.2181185037,-0.2722103000,2.0228359699,-0.4731457233,-0.4897209406,-0.8466237187,-0.7927527428,0.2535848320,-1.7146792412,1.4753947258,0.1289210320,1.0652494431,0.8515291214,0.4173741341,-2.0765564442,1.2504419088,-0.0443437658,1.5116868019,1.8558517694,0.3491135240,1.6937165260,-1.0338196754,-0.4067380130,0.8262225389,1.4143344164,0.8692837954,-0.2377124280,-0.3093731403,2.4539537430,1.8264842033,-1.1981890202,-0.0252850149,0.4000261128,1.0661538839,0.8577992916,1.7236268520,-0.3746747077,-0.6475515962,1.0553491116,1.0886489153,1.0331463814,1.4672757387,-0.2489519864,-1.0970305204,0.9412765503,1.0543107986,-0.0536026321,-1.0659681559,-1.0156000853,-1.5400930643,0.4246522188,-0.0187172014,0.8591113091,0.5056961775,1.0604348183,0.4011115432,0.6088192463,-0.4373769760,-0.4630948007,-0.1633478701,-0.0268928893,-0.9721285701,-0.0090062944,-1.8252615929,-0.8835651875,0.8288798928,0.9291929603,-0.6319452524,-0.7508799434,-1.2358655930,-0.2250781059,0.8632010818,-1.3284317255,-0.1848070771,0.9850524068,2.7465870380,0.3367196023,-0.1066792235,0.6596503854,0.5575050712,1.2563635111,1.6511420012,-2.0832810402,-1.7445597649,1.0956785679,-0.3525366783,0.7681734562,-0.8345808983,-0.4927855432,-0.7883468866,-0.7326194048,-1.2440841198,-0.0345288664,-2.7205607891,0.6942610145,0.7805992961,1.9402210712,-0.3773797154,0.6861529350,1.4874285460,-1.1206152439,0.4860053062,-2.2346808910,1.6082966328,-1.4920960665,-0.0897716880,-0.9688981175,0.2630314231,-0.2303248346,0.7283701301,-0.2108328491,0.8876338601,-0.0404112227,0.3710825443,-1.7251782417,1.6026358604,-0.5407242775,-1.5847551823,-0.2540806532,1.0504814386,-0.6451629400,-0.2521845698,-0.7335251570,1.4679886103,0.9870139360,-0.2953719795,-0.6325708032,-0.2677554488,-0.6401776671,-0.9570604563,0.7377889156,-1.1807512045,0.2154497951,2.0238044262,-0.0856862068,-0.9026969671,-0.7318025231,-1.8274935484,-1.2555172443,2.3201255798,-0.0519613996,0.1016197801,-1.6232725382,-0.1265503317,0.3801241219,1.2250181437,-0.8491208553,-0.0472059064,0.8237924576,0.0123016173,2.5513939857,0.4294205010,0.9571111202,-1.0746427774,0.7808172703,-0.0097871711,-1.0527443886,1.9884264469,1.4375798702,0.1371785998,1.1927306652,0.5296163559,0.7076142430,0.7082402110,-0.0101034651,-0.9877721667,-0.7654364109,0.8536295891,2.0100181103,1.7068982124,-1.0156911612,-0.3960444927,1.1031227112,-0.5324784517,-1.4763936996,-1.0825276375,1.8315578699,0.2433653921,-0.8337994218,0.4364992380,-0.0291025154,-1.1196365356,-0.6079728007,0.3150257468,0.9560776353,-0.4641246200,0.0915727168,1.4087785482,0.5882574320,-1.0789182186,1.1352727413,0.3621936738,0.7451221347,0.9481421113,1.1590278149,0.3194058836,0.2874425352,2.1013104916,0.5960393548,-0.9192075133,2.1953134537,-0.2614995241,-1.1423128843,-0.6494238973,1.2167494297,-0.4384835362,-0.4017018974,0.9502454400,1.7171781063,-0.3878672123,0.1367998719,-0.2946698964,-0.3433934152,-2.0157806873,0.3329694569,0.1684727818,-0.6111791730,-1.2262228727,-0.3766339123,-0.0963002965,2.6844952106,-1.4412274361,-0.3843735456,-0.6183712482,0.2814792395,0.4891471267,-1.6365194321,-0.5198187828,-0.4364172220,-0.1316254586,0.7158564329,0.9850757122,2.1309149265,1.7007933855,0.4094660878,-0.4367023706,0.1017921567,0.9821092486,-1.8584427834,-1.8049651384,0.3871385157,-0.7662376165,0.8493132591,0.8043100834,-0.7121513486,-1.0511052608,1.5637362003,-1.4827083349,-0.5826970339,-0.1382329762,-1.4593697786,0.8752971292,1.5086021423,0.0051624221,-0.6862916946,-0.0043434026,-0.1981390715,1.6246167421,-0.7251117826,1.4283695221,0.3859604895,1.3972984552,1.5540999174,2.5077965260,0.6106916070,-0.2925674021,-0.6402983069,1.1182700396,1.3853303194,-1.2084366083,-0.0332357697,1.1627514362,0.3403298259,-1.4742140770,0.1268104017,0.0190874953,-0.2759317756,1.9947268963,0.3381502628,-1.2353051901,0.1884480715,-0.0715656877,-0.4184769392,1.6307207346,0.8701319098,1.6656786203,-0.2166256756,-0.8495945930,-0.9305421114,-0.2624989152,-1.0245912075,-0.3905347288,-0.8387540579,-0.7649152875,0.7450212240,-0.1490360945,-1.2048982382,0.0052565383,0.2848755121,0.2007502466,1.8125782013,0.6278348565,0.3501205146,-0.7780155540,0.2294713855,0.2744221985,-0.7625269294,1.2621465921,1.7222411633,2.0579175949,-2.1386463642,0.1349654347,1.3889241219,1.0150574446,-0.1360161752,1.1493418217,0.9397243857,-0.2867267430,0.1947177649,-0.4196768999,-1.1011104584,-0.4494042397,-2.1123704910,0.8957493901,-1.3408659697,-1.5817927122,0.5287882090,-0.4619643688,1.8015409708,-0.3952269852,-1.9611263275,0.7645410895,0.0038085454,-0.5192066431,0.6467928290,-1.2985756397,-1.0088950396,0.0489339791,0.7028077841,-1.9100688696,-0.2068070322,1.0011336803,1.4111698866,-1.7828242779,1.2758779526,1.0975503922,0.1588366926,1.1677552462,-0.1960469037,-2.4964635372,-0.5020163655,0.4433894455,1.3550033569,-1.8140020370,1.3322262764,-0.0272594821,0.5605358481,0.6819627285,-0.3883218765,-0.4051531553,1.9179229736,-0.1898309290,-0.4401783049,0.3061546683,0.5527454019,-0.0615562722,1.1755992174,-0.3579424620,0.6841399074,0.8924797177,1.0648961067,0.3632277846,0.5677139759,1.2489463091,-0.1964088529,0.6993002892,-0.3229619265,0.2260445952,0.9134680629,-1.1335862875,0.8838149905,-0.2615242898,-0.5182797909,-0.7718955278,0.6097289920,-1.0060567856,-2.0341730118,2.3055205345,-0.0929920897,0.8716686368,-0.9269929528,-0.2685537636,1.5324709415,-1.0759367943,0.1769119054,0.6477789879,0.6450597644,-0.0311753843,-0.3823924959,0.9851641655,-0.0099959550,0.3076856434,0.8313928843,-0.9556804299,0.9590794444,-1.6914818287,0.1404424012,0.1872563809,0.6698793769,-0.6741681695,-0.6608606577,-0.5262241960,1.7734227180,0.5527629256,1.2757896185,0.1524516791,-1.0622953176,-1.8591362238,0.6258513927,-1.0650826693,0.1954589635,0.0974331871,-0.5126291513,0.7299199700,0.3523078263,-0.3958586156,0.3189874291,-1.6703007221,0.1114622653,2.7657816410,0.3965610564,-0.3496138453,-0.9666339159,-2.0601592064,-0.5482038856,0.7389851809,0.7662830353,0.6029362679,-0.3516857326,-0.2998183370,-1.4955811501,-0.3838070035,1.3036487103,0.5547218919,0.3298881352,1.1064683199,0.9430986643,0.3839015961,1.4636781216,0.5495438576,-1.0143105984,-0.1891726404,-2.5100672245,-1.1935496330,0.2183128446,0.9599092007,1.5681704283,0.8648939133,-0.5642094612,-0.3421497941,1.4679930210,0.1009292603,-0.1126660332,-0.0972139761,-0.9727141261,1.3819562197,-0.2575739920,0.2227812111,1.6426393986,0.5266095400,0.3665766418,1.4545422792,0.8404076695,-0.8013294339,0.9210820794,-0.6172357798,-0.4117927849,-0.7112870812,-0.2017239034,-0.0910126418,-0.8601288199,0.0719281286,0.7666918039,-0.0444614887,0.2221361250,-1.0537574291,0.6026690006,0.1948057115,-0.5820829868,0.9025380611,-0.1448483169,-0.1274862140,0.0873810202,2.6046392918,1.4802066088,2.0170738697,-2.2271463871,2.0235662460,0.1746399105,1.1856992245,0.3476963341,-0.1823394597,-0.9577738643,-0.6233409643,-1.0143755674,0.8863685727,1.2911611795,-0.7955857515,1.9125989676,-0.7551600337,-2.2882008553,0.6161273718,0.1451403648,-0.7093462944,1.2617323399,-0.6054198146,0.2747418582,0.4786858857,0.6184700727,0.0912145898,-1.2048335075,0.3290942907,-0.2360955030,0.5835716724,-0.9597758055,1.7403790951,1.5781999826,-0.7483271956,0.5618293881,1.2583650351,1.1227834225,-0.4328562021,0.1996002942,-2.6929018497,-0.8850705624,0.3370223641,1.0766296387,0.2751036286,-0.0249971207,0.3484513462,-1.4661811590,-0.5508713126,0.7615688443,0.2132720649,-0.5305895209,0.5651596785,-2.1194589138,1.5398962498,-0.1179601401,-0.0704612285,0.8395457268,3.8448247910,-1.6787865162,1.2805011272,0.5926063657,1.0369732380,-0.9114980102,0.7235304117,-1.1771003008,-0.8924003839,1.5978136063,-0.9991945624,1.4228422642,-0.2267849296,-0.8862344027,0.7951184511,-1.0446032286,1.5943152905,1.0219110250,-0.5544071198,0.0632716194,1.3749527931,-0.3679391444,0.8503480554,-0.5020872355,0.6588804126,-1.8511382341,1.3213031292,1.8603336811,0.5004802942,0.3071632683,-0.2847483456,0.2404857427,-1.5341200829,-0.3211204112,2.2744309902,-0.1365518570,0.8923602700,-0.3667230308,-0.5734806657,-0.3486274481,-0.1186143011,0.8307850957,0.6011481285,-0.7103462219,-0.6508090496,-0.8464833498,0.6043699980,0.2763639688,-0.1737786531,-0.0291063003,1.4368228912,-1.5170634985,-0.9887233973,1.1650506258,-0.8643849492,1.2665343285,-1.3787747622,0.3148807883,-0.8181608319,1.1779116392,-0.7715457678,1.0275965929,-0.1303185225,0.1004789919,-1.2106908560,-0.0878942758,0.1088947505,0.6320188642,-0.9480621219,-1.3948607445,0.0503652915,-0.3959770799,-0.1595087647,-1.2462719679,-0.8731278181,-0.3450042605,1.7942147255,0.4963313341,1.0791658163,-0.0937815085,-1.0531029701,-1.2803995609,-0.3876163363,0.3790248632,1.1142001152,-0.4398929477,-0.8452531099,-0.3301915526,-0.3507989347,-0.9891392589,-1.3544497490,0.9459623694,0.2598392963,0.5682955980,-0.9399594665,-0.2605684400,-0.8619480729,-0.5104118586,0.5194774270,-0.9169836044,-2.6900908947,2.7366669178,-1.4323606491,1.6291747093,-1.4959498644,-1.1548160315,2.5480496883,0.2900446653,1.4242911339,-1.2634080648,0.1963342428,1.4480313063,0.3778089583,-0.6415191293,-0.2120681107,-1.3008939028,0.3545155227,-0.2053026557,-1.9529192448,-0.0525757596,-1.0794268847,0.6703519821,-0.4758709371,1.1867605448,-0.3449138403,0.3547198176,1.6804623604,-0.9776315093,-1.9091552496,0.6955775023,0.9033918381,-0.1566496491,1.4611063004,-0.8640043139,-0.9245055914,-1.2249439955,0.7369412780,1.0058851242,0.5710602403,0.1333852112,-1.2250558138,-1.7569497824,-0.5837014914,1.0665876865,-0.8548253179,1.4985412359,-1.5736359358,1.4790285826,-0.5080267191,-0.4287172854,-1.9432892799,-0.6099470258,-0.2015367150,-0.8354988098,0.1913418621,1.0483424664,-0.2596043646,-1.7170075178,1.5210067034,-0.6716116071,-0.0163926631,-0.4215934277,-0.0219555702,-0.7757620215,-1.5904581547,-0.2381323576,-0.9930461645,-0.7130764127,-0.0591275357,1.0727508068,-0.3543343246,3.0782167912,1.2767871618,0.7470397949,-0.9672718644,1.4354689121,-1.2770084143,-1.4952831268,0.6237402558,-1.3215762377,-1.4172451496,-1.2935512066,0.5550708175,1.3703895807,-0.5524062514,0.4399808049,-0.4097305834,-0.3165017962,0.3495762050,0.7616158724,-1.1521909237,-1.0199534893,0.7851632833,-0.7123095393,-1.3383508921,-0.6731940508,1.0400739908,-1.7057328224,-1.6736978292,1.1462876797,0.6484333873,-0.7210823298,-1.1814935207,-0.0193868037,1.2531992197,0.1176470742,0.1281784475,1.0190414190,0.3068197668,0.2843888700,0.6067525744,-0.4399292171,-1.8810433149,-1.7169803381,0.1544450819,0.3690387607,0.1635134518,1.8912612200,-1.0243716240,0.8578745127,-1.1951819658,1.0820078850,-0.0740952268,0.4703108072,-0.4310616255,-1.6714330912,-0.6286044717,1.5786759853,-0.2143421322,1.0809478760,0.4545911551,-0.6744666100,0.0244885739,0.5634146333,0.1647529304,-1.3875241280,0.2178342938,-0.0701511055,1.8721164465,0.2166976780,0.5953648686,-0.3440511525,-0.3522693515,1.8573738337,-1.2786791325,-0.6153733134,0.7561426759,-0.5053442717,-0.0918319449,0.5894739628,0.1524143517,-1.6383651495,-0.4843915999,-0.2537766397,1.3841521740,-0.7449327111,0.0421048775,1.2323815823,-0.7230997086,-2.1666941643,0.0070414278,-0.3546690643,-0.6129224896,0.5168722272,0.0161491167,-1.3249355555,0.2833559513,0.2064211667,0.6386342645,-0.2798440158,1.6235107183,-1.9121247530,-1.0733910799,0.7745764256,-0.2634502351,0.1581316441,-0.2726663649,0.2395518273,0.0382109508,-0.9823060632,0.2630215287,1.1353650093,-0.9041807652,0.3829956353,-0.0649039596,-1.3555053473,0.7701690197,-0.8610923290,0.8052645326,-0.8781912923,-0.7311577201,-2.9039270878,0.0947883651,0.4915755689,0.6707758307,-0.3843032420,-0.0357921906,-0.5924118757,0.9842528701,-1.4029403925,1.2588713169,2.0025391579,-0.3116514683,-1.9610450268,0.6682580709,-1.6717112064,-0.5060207844,-0.3277585804,1.4305614233,-1.0951304436,0.2470769286,-0.0456573442,-0.3003408611,0.5671326518,0.0664090812,3.3978607655,0.1929901093,-0.3330067396,0.0479260944,0.6180526018,1.0526547432,-2.1311256886,0.1027629226,0.8785018921,0.0608107410,0.4887917042,0.6694629788,0.3460426033,-0.4522186220,-1.4803252220,0.0475699566,-1.0768768787,0.2929372489,0.2556186914,-0.4252198935,-1.8915692568,-0.2100862265,-0.0845040902,-0.7917732000,-0.4677768350,-0.4222314358,1.2808054686,-0.3017964065,-0.1799859554,-2.1371099949,-1.6400431395,0.5384729505,-1.4935162067,1.4454184771,0.4328987002,-0.4091602862,1.2936794758,-0.7945672274,1.1871507168,1.5372850895,-0.8579943776,-0.7523997426,-1.3768255711,-0.5170516372,0.5266361237,0.5500448346,0.2686732411,1.1339052916,0.1505801380,1.0301640034,-0.5608243942,0.5116033554,-0.1938695461,-0.2318379730,-0.6758121252,0.6146999598,0.7851496339,-1.3886620998,-0.3124918342,-0.1945108175,1.3500403166,0.5355877876,-0.6446334124,-0.3353732824,0.1246494949,1.4483478069,-3.0476114750,1.8138883114,-1.7988743782,1.6526031494,-0.1701273024,1.5951917171,-0.4962559342,0.5138649940,-0.1693724394,0.2989767194,0.9507718682,0.1399330646,-0.2367779166,-0.5848656893,0.0408673994,1.1533704996,-0.1025816724,-1.8772822618,0.7537982464,-1.0198754072,0.0566727556,-0.8193967938,0.6501716375,-0.6657895446,-0.7310741544,-0.4085451663,-0.9486625791,-0.0811254904,-0.2931586504,-0.2771906257,1.2176634073,-0.7611948252,0.5342000127,0.2206405699,-0.3270626366,1.6594908237,-0.9000232220,-1.8313491344,1.1096508503,-0.1459466666,-0.6582320333,0.3887246549,-1.8797705173,-1.1226110458,1.8616946936,-2.1927931309,0.0301647671,0.0473821871,0.6955246329,-0.5873502493,1.2350827456,-0.7400141358,1.6582258940,0.8974621296,-0.8383839130,-0.1603887081,0.4101619422,2.2152121067,-0.6797272563,-0.2635640800,-0.3556258082,-0.7574476004,-0.1034703329,0.2876872122,-1.0428086519,-0.5722566247,1.1083568335,0.5434480309,1.1623055935,-0.1919558942,-1.3977537155,0.3964772224,-0.3976658583,1.0213907957,-0.6081345081,-0.1984753758,0.7719884515,1.6116856337,-0.5647926331,-2.0718548298,1.2286254168,-1.5091139078,-1.1186282635,-0.2798033059,0.0749905184,0.3844977021,-0.0438706018,-0.2827286422,1.2734726667,1.2332676649,0.5621038079,-0.1019901857,-0.4522658288,-1.5339000225,-0.7295792103,-1.2359548807,-0.5382317901,1.6926423311,0.0574849769,0.5758835077,1.9828463793,0.5544055104,0.1886905134,2.5439355373,-0.3392686546,-0.6245530248,-0.4217739999,-0.1226378530,-1.1134990454,0.3403982222,-0.2209866643,-0.0216140505,0.8030695319,-0.5919985175,-0.0856432617,2.3269383907,0.2625982463,1.1156468391,0.2020006925,1.2754621506,-0.8897251487,0.9669903517,-0.5493559241,1.4233219624,1.3478831053,0.4568857253,-0.0930040702,-1.2832940817,0.2640421391,0.6426716447,1.6632509232,-1.4980686903,-0.5740880966,1.1556472778,1.3272485733,-2.1616599560,-1.6268901825,-0.5095205903,-0.1517010182,0.0697079748,0.6218604445,-1.7932162285,-1.5523602962,-0.2364832610,-0.2116670161,-0.9998782873,-2.7679753304,1.1789580584,1.2540689707,0.2540247738,-0.4325055182,-0.3744247854,0.5653214455,-0.2487467080,0.9951139092,-0.3737806082,1.4783589840,-0.4989001155,0.1346275359,0.4608412683,1.2888094187,-0.4664494693,0.9327733517,0.6842293739,0.4536570907,0.7156196237,-0.8881968260,2.7164895535,0.3652488589,0.6087380052,-2.6499264240,0.4615913928,0.5398000479,0.6077411175,0.1409384161,-0.6123158336,-1.3663132191,-0.8288936615,1.7153819799,-0.5907678604,0.9421477914,1.1129484177,-1.4384629726,0.5338668227,-0.7236166000,-0.3594409227,0.3317614794,-0.0182189792,-0.9622032046,1.2848628759,0.0738611221,1.8387027979,0.9678576589,-0.5062652230,-1.4060206413,0.7187169194,-0.0001753581,-1.2740622759,0.3961002231,-0.4440979064,0.2215769291,1.1455968618,-1.5288711786,-0.1165431365,0.1862287372,0.4621602297,-1.2539870739,-1.9266433716,-0.3532809019,-1.2628905773,0.6617218256,-0.4527367353,-0.2476387024,-0.3344658315,-2.1655943394,-0.0272593759,1.5402753353,-0.8876109123,-0.5740729570,1.4609684944,0.8156918883,-0.6739629507,-2.1460916996,0.1425817907,1.2147607803,-1.1786000729,-0.6290073991,-1.2190272808,1.9812610149,-1.8409180641,-0.5344301462,0.0046728416,1.4701166153,0.0316930152,0.6217797399,0.3374963999,-0.0923807099,-1.0196141005,0.2970777452,0.5648963451,0.0846193135,-0.5526602864,-1.0114645958,0.0666290522,0.7835562229,0.2549487650,-0.5999336243,-0.9358597994,-1.2035146952,0.0867796391,0.2015919834,-0.6562302709,0.5852459669,1.0319597721,1.6525110006,1.0681165457,-0.3666232228,0.4162625074,-1.4362779856,0.9617007971,0.2182102948,0.4531165659,0.0359582119,0.2627207041,-0.6436700225,-2.5046739578,-0.1782875061,0.6615344882,-0.8519901037,0.2686338723,-0.6474667192,-0.1683191508,0.6466437578,1.4409619570,-0.2617304027,1.9130183458,-1.5077996254,-0.9462426305,-0.2838377357,0.0526938327,-0.6236193180,-0.4251126945,-0.0550731048,-0.8132697940,-1.2440909147,-1.0892269611,0.3136571050,-0.0490135439,-0.6237413883,0.6349942684,-1.0433175564,-2.0065948963,-1.9424735308,-0.6845101714,-0.6202213764,-0.3914147615,2.2720336914,0.0739588216,2.2880032063,0.5641351938,0.4740304947,-1.8853971958,0.4114308357,-1.1214060783,0.4880087078,0.4406731129,-1.2576910257,-0.6754882336,2.2553937435,-1.3919758797,-0.6938131452,-0.0537123717,-1.1831597090,-1.1901445389,0.6069281697,0.8246663213,0.3340826333,-0.2523243427,0.0757556856,-0.2096677721,0.7798483372,-0.8629242182,1.6895529032,0.1870408505,0.3471640348,1.1528530121,-0.5211679339,-0.3400958478,-1.8149099350,0.1189164966,0.4202474952,0.2755539119,0.3063024580,-0.1489593983,-1.3223544359,-0.1619068384,0.9510185719,-0.0225095376,-0.8107722998,-0.3870677650,1.5546485186,0.0615551658,1.6332503557,-0.7618871331,0.9830802679,1.2946121693,-1.3857856989,-1.5067552328,0.2777404487,-0.4606186450,-0.4907822013,1.3923071623,0.6343035698,0.9364335537,-1.7004997730,-0.4155659676,-0.1267781258,0.3403526843,-0.5315839648,-0.7173085213,-0.0580628328,-0.4464083612,1.3359794617,0.0476373993,-0.2086803317,-0.1372452974,-0.0591464713,1.3616489172,0.0903304443,-0.3211252391,-0.9177269936,-0.9550664425,0.3909903765,-0.2268156558,-0.0082257940,1.2424693108,-1.3258881569,1.4352700710,0.7880265713,0.1414163709,-0.2054441571,-1.1014525890,0.6595254540,-2.3181002140,-0.0876651481,-0.6974890828,-1.4716603756,0.7876362205,0.1344156265,-1.3554036617,0.6036042571,0.1190322861,0.9254586697,1.2508783340,0.2331293225,0.4055940509,0.7998869419,-0.5757550597,-0.9135111570,0.7675039172,-0.7781230807,2.4180750847,2.7852742672,0.1045434698,0.6787592173,0.4007455409,-0.3564361036,1.5347712040,-1.4705452919,-0.7479464412,-0.9566254020,1.2649875879,-0.1646696180,-0.5155603290,-0.7206394076,2.1404452324,-0.7790234089,0.7116395235,0.9158282876,-1.4436525106,-0.4211129844,0.7956809998,-0.9565706253,-1.3517844677,-0.3119147122,0.2453809679,1.4581965208,0.7543629408,1.6049604416,-0.4158651829,-1.2043303251,-1.0034831762,-1.1723743677,1.0647040606,0.2321242392,1.0505148172,0.8940162659,-0.1205676943,0.3933456540,-0.4981866777,0.8221628666,-1.1024289131,0.9230841994,0.1395951062,-0.2751727700,-0.4984712899,-1.3625754118,-0.4306615889,-0.5384787917,-0.9555833936,2.1937851906,-1.1307214499,0.4357461333,-0.8771927953,0.8578191400,0.3055385947,0.2204068154,0.6302809715,-0.0163004622,-0.8319802284,-1.3126729727,-1.3170480728,0.5569218993,-0.3531013131,0.3641794920,0.3810200691,-1.4238847494,0.1009590551,-0.3800279498,0.7649206519,-0.6368266344,1.7794678211,-1.1880887747,-1.4316164255,-1.6969466209,0.5561639667,1.1471374035,0.9899902344,-0.1633966267,0.6074290276,0.5961022377,-2.8764624596,-1.0727797747,-0.8768104911,-1.0192153454,2.8190350533,-0.2256239206,-0.3943177760,0.8255993724,-1.1556965113,-2.1723108292,0.7178436518,0.6824865341,0.5922962427,-0.3120145798,1.0898365974,-0.3011100590,-0.1291559339,0.4131253660,-0.3478083014,0.3667017221,0.3330966830,0.3752444685,-1.4574064016,-0.2556218207,-0.3968566358,0.5036401153,-0.9107782841,1.3879652023,1.2289830446,0.7992539406,0.6849098802,0.0707288608,-0.0696446821,-0.1699579954,0.4269837737,-0.5689053535,1.0672354698,-0.7523844838,-0.6921916008,0.7129670978,0.0622992143,-2.1855492592,-1.0172541142,0.6609465480,-0.2331690043,0.2233446985,1.7745434046,0.0969029590,1.6294189692,-0.6170974374,-1.2387092113,-2.4741020203,-0.0289155487,0.2518738508,-0.1491267532,-0.3006697595,-0.9428971410,0.3010059893,2.3177731037,0.1611628830,0.6096910834,-0.5344636440,-1.1325211525,0.5708059072,-0.2217664272,-0.1881082803,-0.2953444421,-2.7062401772,-0.0275921281,0.9700416327,-0.5384776592,1.4731795788,-0.6910365820,-0.8083460927,-0.2849730253,-0.9540877938,-1.0074419975,-0.3939363658,0.8493119478,1.3113639355,0.1255604029,-0.5570324659,-1.1712133884,-1.6394242048,1.0471559763,-0.6554031372,0.3733699918,0.8540666103,0.1184398606,-0.1343704611,1.3181189299,-0.0528781712,1.9076501131,-0.1207094342,1.0920281410,0.5713807344,1.3109537363,0.7840664983,-0.7930327654,0.7855635285,1.5472874641,0.6432893276,-0.0242837500,-0.3870694935,-0.5971293449,-0.2899690568,-0.7334938049,-0.0300292429,-0.9743447304,1.1392588615,-0.9915491343,-0.8986487985,-0.8678231239,-0.6919215918,0.4460268319,0.7036303878,-0.3525555134,0.2887427211,-0.7344346642,-1.1392246485,-1.1486465931,-1.1256231070,0.2172904909,2.2096951008,-0.2768126130,-0.4194982052,0.0895349309,-0.4994725883,-0.4294939935,1.5925871134,0.9207655787,0.1646861136,-0.3742833734,1.3894538879,-0.4878883362,-1.2071138620,-0.1191699728,-1.4390913248,0.2861081958,-0.1579031646,-0.3974367380,0.1752463430,0.3748835325,-0.3617827296,0.8169750571,1.3362919092,-0.1484031230,0.8671530485,-2.8536005020,-0.0906554833,0.0088043632,1.6732629538,2.1423466206,-0.7370496988,-1.2664498091,0.6641715765,1.2869904041,0.6079743505,1.3022139072,1.3500844240,-1.5029324293,0.6907622218,-0.4061397612,-0.8483211398,-0.3681233823,-0.8578148484,-0.1548754722,-0.5499112606,0.2328155786,-0.6580201983,-0.0703464821,0.5699104667,0.1111837327,0.7781289220,-1.5467842817,0.5690723658,0.4452523887,0.0673167929,-0.0463277884,-1.8743733168,-2.8230288029,0.5497969389,1.9723832607,0.5564820766,-0.3615648150,0.0729349479,-0.0699678808,-0.7118794918,1.3303546906,0.0751053691,0.5226886272,0.9767999053,-1.7849285603,1.5602053404,1.0742962360,-2.6806015968,-0.4691926837,-0.5361781120,-0.2826193571,-2.2090110779,0.9901263714,-0.0261297319,0.8651404977,-0.2917624712,0.4948405921,-0.7538119555,1.5201109648,-0.7561060786,1.1786170006,-1.1826119423,0.7336524725,0.9188173413,-1.9997373819,0.4963880479,-0.8404771686,0.4128607512,0.4337054193,0.2035663426,-0.7117573619,-1.7409338951,-0.5598160028,-0.9008379579,-0.4741972387,0.0416170508,-0.7776945233,-0.2547941804,1.1234530210,-0.3588818014,-1.5244874954,1.1329869032,1.7894061804,0.7349005342,0.1345884353,-0.5785191655,-0.1267298460,-1.1764208078,1.3696135283,0.4106918871,-0.0976169482,-1.2190376520,-0.9109613299,-0.0955943689,-1.0170726776,1.0108891726,0.1099565029,-0.7064110637,0.2942879200,-0.5495336652,-0.4723607302,0.5777610540,-0.7016943693,0.7423120141,0.0810565427,0.8770937324,-0.1352943182,0.6857259870,-0.5274185538,-0.3148475289,0.4312712550,0.8180384040,-0.1410973966,0.5621446967,-0.8120179772,-0.0752384365,-0.0236309376,0.9926939011,-0.5143352747,0.1516641676,0.7576454878,0.1885048598,0.8092653155,-1.4317138195,0.7512933612,-1.7853584290,-0.3403401673,0.5114456415,-1.0479772091,-1.7917723656,-0.7522316575,0.9491505623,-1.5872008801,-0.1898578852,0.7266498208,-0.9619154930,-0.1413860023,0.9052723646,-0.3882459998,0.1237693802,-0.2326326221,0.3206429183,-1.3629474640,1.1452333927,0.7874519825,0.4181374013,-1.5147526264,0.0730068237,1.3311444521,0.7093572021,-0.9712299705,2.1352322102,1.0231037140,-1.1636049747,1.0286316872,-0.5036383271,-1.6746673584,0.4073672295,-0.0182898492,0.1493997425,-0.7960625291,-0.4407243431,2.3877747059,0.4815349579,0.5813381672,2.2279050350,0.9356135130,-0.4409787059,-0.8286496401,0.7311822176,0.2700185478,0.5507662892,-2.5871624947,0.6772342324,0.2074013352,0.4615665972,-0.4190964699,0.4770605862,2.4217619896,-1.9182502031,-0.8544636965,0.8381118178,-0.4485734701,-1.0919756889,-0.2648122609,1.0098994970,-0.5472998023,1.2348033190,-1.4701932669,-1.9155840874,-0.1090629399,-0.1855992675,0.1095966473,-0.6782081723,0.1180862114,-1.2295197248,1.5274536610,2.3235061169,0.2913398147,-0.3180084825,-0.9371327162,-0.5686488748,1.8743900061,0.0845806673,1.3588453531,0.1544833183,-0.4382197857,-0.6617422104,-0.2704090774,-0.0473123975,-0.1375723928,0.5586237907,-1.4751049280,-0.3098645806,-0.8870976567,1.3249599934,-0.2478749007,-0.4527670145,1.0433957577,-0.4988560379,2.0353519917,0.1222634986,0.8268195987,-0.2070628256,0.4064068496,0.7379081845,-0.1530139744,1.1486705542,0.7987783551,-0.0146313990,-0.8424440026,0.2351379693,0.5839104056,1.9307159185,-0.1338217556,-1.2729601860,-0.9533520937,1.4415456057,-0.0951500610,0.3972956836,0.2098439634,0.5354406834,0.8776354790,0.5473576784,-0.2294035405,-0.8871148229,1.8933590651,0.1261401772,-0.5996055007,-0.0468349196,-0.4060138166,0.0416313224,0.0498172343,0.5637643337,-2.2129881382,-1.1236852407,-0.1304418892,-0.9155464172,-2.0547239780,0.6958734989,0.0104737310,-0.0415819399,0.4621022642,0.0875720531,-0.5839158893,-0.1784689277,-0.4025821686,0.9536439776,-0.1893357337,0.4697566330,-0.8019378185,0.4339478314,-0.4863450527,-0.7643893361,-0.4413174093,0.7450090647,0.4705619812,-0.5967475176,0.2144325823,-0.0487319790,0.4239455760,-1.8733527660,-0.6309217811,-1.3656258583,0.5353654027,0.3123120070,1.3560433388,0.0231874250,-0.7732568383,-1.4160184860,1.1718209982,-0.6379296184,0.9241999984,1.1896660328,1.4317412376,-0.1303557307,0.5576506853,0.7538163662,0.4692847729,-1.0503007174,2.2192955017,0.7662305236,1.4199377298,-1.1396961212,0.6984863877,0.8586908579,-1.4875825644,0.1292233914,3.3051817417,0.7467623949,0.8142894506,0.5744169950,1.0687381029,-0.8679308295,0.2648360729,-1.8214925528,-1.5498822927,1.0336124897,-0.3167379498,1.6213614941,0.0680482686,-0.0182913449,0.0870022327,-0.7723815441,1.0164847374,-1.1489291191,0.3398660421,0.4741336107,-0.1662758589,0.0326907784,-0.3206206262,-2.1174454689,0.3675934374,0.3425858915,-0.5936652422,-0.7317870259,-0.8706053495,0.3625514805,-0.7185558677,-0.3813236952,1.6017394066,-0.4086554348,1.1893210411,-0.3677315414,-0.8534657359,0.2419654280,-0.2601073980,-1.7017725706,-2.0002150536,-1.2726695538,-2.8272268772,-1.3180217743,0.2695805430,0.8193210363,-0.0601939671,0.2057047337,2.1258807182,-1.0387762785,-1.0656303167,0.8474498391,-2.0752680302,-0.7518011332,-1.0824229717,-0.0520494208,0.8673002720,0.7077292800,-0.6896764636,0.5508205891,-0.5087099671,-0.7953282595,-0.7552286386,0.3783166111,0.1480294019,-0.4080043733,1.3215683699,-0.2240578383,-0.9652453065,1.6936491728,-0.5004338622,-0.4313458204,1.8143146038,-0.8686926961,1.2914714813,-0.2357162833,1.4363687038,-1.2961885929,0.1975327134,-0.8971417546,-1.4519535303,-0.4755281806,1.1832439899,0.5823754072,-0.7990812063,-0.1475500166,-1.5841269493,-1.0030679703,1.5403479338,0.8109509945,-2.1969048977,-1.9337809086,0.9102554917,-0.2021962404,-0.8042155504,-0.3982497156,2.4267811775,0.6462002993,0.5270777345,0.2776626945,-0.3879787624,-1.2539374828,-1.0608892441,0.8798408508,-1.0080276728,-1.2297723293,-1.1807438135,0.7539607286,-0.3988789618,-1.2075831890,1.9517722130,-0.0741142184,1.6240398884,0.2602418065,1.8968186378,0.9252575040,-0.6450889707,1.4229569435,-0.1587112993,0.8568664789,-1.0669229031,0.6148740053,0.7432900667,-2.3107280731,-0.7096374631,0.1439763308,-1.7630770206,0.8053269386,1.0544917583,-0.2164501399,-1.1995971203,-1.1014965773,-0.6774827838,-2.0162796974,-1.3040640354,1.7306530476,0.4679165184,1.5393271446,-1.1890480518,0.1019532531,-0.9641910195,-0.6676917076,0.3440614343,-0.2543410659,0.5562074184,1.3031641245,0.3274115324,-2.5846605301,1.2806965113,1.9282523394,-0.1295706928,0.4334105253,0.8793066144,-0.5240471959,-0.1192059442,0.2685222328,0.6581997275,0.3720701039,1.0289461613,0.6471891999,-1.3104859591,-0.7705357075,-0.6850705743,0.2172274739,1.4807068110,-0.2180891037,-0.6771414280,1.5424208641,1.0833897591,-2.8045880795,0.4607556164,0.7872321010,1.3725421429,-1.5756440163,-0.3378772438,1.1134512424,-0.0857403502,-0.7604584098,2.4517266750,1.1246706247,-1.8834089041,-0.3396808505,0.4468193650,-1.3754568100,0.2401239425,0.2437317073,-1.6011885405,-0.6616942286,0.3145923913,-0.5798115730,1.6361236572,-0.8283223510,-0.0387554541,-1.4568865299,-0.9266756773,-0.6654282808,-1.0409642458,0.1891269684,-1.0281019211,-0.6576402783,-0.2294373065,0.3463232517,-1.1547359228,-1.8444094658,0.9560483694,-0.6993877292,0.3474283516,0.2573563457,-0.5045565963,0.6014789939,0.0792550221,2.0729916096,0.5574637055,2.2566828728,-0.7126176953,-1.8690760136,1.1867282391,-1.2382060289,0.5142056346,0.9849852324,-0.9336848855,0.1257813275,0.0927541032,1.3971587420,-0.3119037747,-1.1926451921,-1.2881635427,-1.3171620369,0.4146163762,-0.4774722159,-0.3868423402,-1.0103545189,-1.1745402813,-0.2091901600,1.3277802467,1.1256504059,0.2741110325,-1.3244829178,1.5284399986,-1.0842255354,-0.8799241185,0.4729141891,-1.9505088329,-0.4351518452,-0.8081485629,0.3269541264,-0.7062594295,1.6481834650,0.4895448983,-0.9180828333,-1.4240669012,-0.1890579164,-0.9585830569,-1.0736232996,-1.2009921074,0.0086217457,2.2900185585,0.9107310772,0.3459389806,-0.2933109701,1.7081165314,0.7132967114,0.1095507592,1.3954622746,-0.0916409269,-0.4428087771,0.3978556991,-0.9287421107,0.6775330901,-2.0309498310,-0.2861202955,-1.3187100887,0.6868452430,-0.1280173510,0.3954797983,-1.4868066311,2.6867311001,-0.2837397456,-0.4692958593,0.8649511933,-0.4000707567,-1.3636385202,-0.4336688221,0.4807041883,-1.1696223021,0.4139298797,-0.3658573031,-0.8346003294,-0.6913728714,0.6472249031,-0.9495275617,1.0565907955,-0.1551950276,0.0402307771,0.5411900282,1.9618538618,0.3323952258,-0.1880543530,0.3495495617,-0.2323200107,-0.0774672851,1.1608976126,-0.6110397577,-0.0833180025,0.5343641639,-0.1402324885,0.7121111155,1.1572567225,0.6025365591,-0.0661304966,0.9814050198,-2.0910024643,0.6004716754,-0.8897766471,0.5802534223,1.2903648615,1.0397731066,-0.8031101823,-0.8996082544,-0.2524068058,-1.2267825603,-0.9092355967,-1.0889654160,0.8441944718,0.8110027909,-0.0405239128,-1.0715160370,-0.1124812588,-1.5997368097,0.1420539320,0.6181820631,-1.4807455540,0.2736857831,-0.0874448717,1.4611581564,-1.0566525459,0.4870162010,-0.0450987816,-1.0364639759,0.7334445715,1.5605502129,0.7317325473,-0.8760612011,-0.3242733181,0.5894088149,0.5113537312,-0.2457536161,-1.0911314487,1.1978468895,1.4237911701,0.2477284819,-0.2938754857,0.5031723976,0.0124401199,-0.4126176238,-0.7320761085,-0.4052883387,-0.2108996511,-0.7781730294,2.1468038559,2.6817145348,0.2516969740,-1.0822778940,-0.0529402457,0.8459635377,-1.2501021624,-1.1299482584,-0.7857146263,0.1984169632,-1.6308257580,0.9140481949,-0.2152125388,-0.2536766827,1.7120695114,-1.6373603344,-1.5643184185,-0.4590578377,0.4787595272,0.0577515550,-0.8291638494,-1.4593600035,-1.9532253742,-0.7408310175,2.6602454185,1.3658504486,-0.4614217579,2.1605172157,-1.6152997017,0.0586317293,-1.2505980730,1.0217580795,0.0332866982,-0.1231489927,0.8719854951,0.3502269387,-0.3011886775,-0.3683407009,-1.3110753298,-0.5376300216,0.3520507216,-1.2554615736,-0.3561529517,-1.4860554934,2.0891554356,0.4023406506,-1.2871041298,0.4452855885,-0.3306802511,-1.0909045935,1.2342441082,-1.3968569040,1.2671681643,0.3808578551,0.1622464359,-0.8135055304,-0.2238749415,0.1271271706,0.3600368202,0.1486675888,-0.3422999382,-0.9236380458,-0.1554073095,0.7903410792,0.1860257089,0.1308351606,-0.2578380704,1.5718585253,-0.7012122273,1.0408076048,-1.0936492682,0.8577693105,0.4340395927,-0.2430948913,0.2685880661,-1.8785663843,0.9641314149,0.3043458462,-0.6693259478,0.6128401756,-0.5462137461,2.3161671162,0.0049466984,0.0762785673,-0.8627022505,-0.1909276098,-1.7148029804,0.8741716743,-1.0369155407,-0.9876949787,0.0601231158,-0.9681298733,-0.8266518116,-0.0769524872,-0.5266578794,0.6762766838,1.3591698408,0.6121618748,-0.3233613670,0.0347821042,0.8331773877,1.1339416504,-1.0403983593,0.1039372236,0.3434944749,0.7209177017,-0.6197436452,-0.6891433597,-0.7516368628,0.9467796683,-0.2635918260,0.6381617785,-0.5782182217,-0.3497321010,0.9256712794,-0.6284171343,-1.8411649466,0.2277844101,-0.4046567082,-0.2888169885,0.7736723423,0.7876480222,0.9130166173,2.5497612953,1.3560099602,0.5737367272,0.2998895347,-0.7253481150,1.6977071762,0.1428591907,1.6922923326,-0.7899493575,-1.6153711081,0.8779649734,1.6200410128,-0.7291763425,-1.0820019245,0.7858555317,0.2406725436,-0.2910236716,-0.0595621802,-0.4121816158,0.3560032547,0.9713022709,-0.3304999173,-1.7688531876,1.1638083458,-0.9774751067,0.4061269462,1.4668464661,0.2371457219,-0.1761687845,-0.2912491560,-1.8847373724,-0.6073658466,-0.5818338990,-0.3286408484,-0.6674704552,0.3853674531,-1.2600563765,-0.0117033292,-1.2790175676,-0.0959654301,2.4882016182,0.3786404729,-0.7029803395,0.7567839026,0.1165871844,-0.1981320381,-0.4176677465,0.7999218106,-0.3878305852,2.3828504086,0.4363039136,-0.3107819259,-0.3244489431,1.2963690758,-0.5949802399,-0.3192541301,0.1184017360,-1.0748354197,-0.2322329283,0.0255772974,-0.1782385856,-0.4525050223,-0.9569429159,1.7335696220,-0.5961167216,-0.9838139415,-1.5097740889,-0.5643052459,-1.0459479094,2.0024902821,1.1414196491,-0.7664759755,-1.2552784681,-0.1251813024,-0.2468750924,-0.2969430983,0.2811274230,1.1297291517,-0.4285236895,1.6837493181,0.1570269614,-1.3796472549,-0.0221588574,-0.9108480811,-1.4940923452,0.3765714467,0.1872464269,1.0197986364,-0.4883226156,-0.3771733940,0.0635235235,-0.3010345995,0.2305924147,0.3498499691,0.6820290089,0.7376207113,0.2440648973,0.2061410099,1.6231516600,-0.4384661913,-1.0267047882,-1.4744080305,-1.1771376133,0.1827095300,-1.0081615448,1.2591556311,-0.1388425082,0.4758206606,-0.2766729593,0.5053372383,-0.0261183511,-0.1096292585,0.3588334322,-0.1530779451,-0.1198340133,-0.2816464007,0.1439685822,-0.2829401791,1.0409681797,-0.0788520947,-1.1657164097,2.2557945251,2.0186963081,0.2609864473,0.6588216424,-0.0292505622,-3.0369510651,1.2542692423,0.5731019974,-0.0044440515,-0.4187056422,0.6035118103,1.5395250320,0.9933514595,-0.5339363813,0.7204960585,-0.2520633638,0.1129418686,0.3106788397,-0.1949516982,-0.7873948216,-0.9607906938,0.3240345418,1.3103933334,-1.2638764381,1.3863197565,1.8211445808,-0.3672892451,0.4053455591,1.7521601915,1.6447889805,0.7403008342,-0.8374760747,1.8835134506,1.4278148413,3.0550069809,-1.2181924582,-0.8227337599,-0.1327370256,0.3542967737,0.6749712229,-0.3170649409,0.9784115553,0.3086686730,-0.1767462045,0.0843835175,-0.6492677331,0.3701886237,-2.1043498516,-0.0279286541,-0.8700038195,0.6007041335,-1.9832814932,0.2308917642,-1.3054196835,-0.3247613013,0.2073209584,-1.3216863871,-0.1985991448,0.9323601723,1.6048812866,-0.0951557308,-0.2890453935,0.6215823293,-0.0441857241,0.9499992728,1.8083887100,0.1037293598,0.8567683101,-1.0534691811,1.9651103020,-1.9569315910,-0.4348264337,0.6502805948,-0.9168347120,1.1094492674,-0.9395704865,0.8174906373,0.9895029664,-0.1846548319,0.4872570932,0.3263651729,-0.6341340542,-0.1032819226,-0.7346142530,0.1689246595,-0.1534329206,-1.5958054066,0.2307239473,-2.1755774021,0.4595609605,1.0350043774,1.1936333179,1.2886185646,0.5671181679,0.0456784628,0.4965856373,-0.8134568334,0.9582699537,-0.0257120635,1.0541176796,0.1182258353,1.0523356199,-1.8147698641,0.7733538747,-1.3099697828,-0.9093947411,0.5400250554,-0.3680446744,-3.2436428070,0.1594742090,-0.6183111072,-0.5293322206,2.0307416916,-0.1469859183,1.3975157738,1.4203033447,0.5249443054,0.7566241026,-1.0997810364,1.1431112289,0.8553681970,1.1881549358,-0.3714130521,0.1984697133,-0.5287451744,-0.3881629407,0.8084456325,-1.3102331161,0.2904533148,-0.6494663358,0.3399093449,2.3053667545,-1.9359093904,1.7290390730,1.5100733042,-0.2926071882,0.3544541597,1.9625288248,-0.6443831325,-0.4173543453,1.1030114889,0.3282997310,-0.0072064842,0.4895175695,-0.5674248338,1.6213970184,-0.4362982810,0.3757034838,-0.8909569979,0.5226764083,-0.6865759492,0.8143765926,1.2320840359,-0.7808359861,0.0008738514,-0.8514294028,0.4705692232,-0.3333962560,-0.3492262959,0.2567463517,-1.1781015396,-0.4792070985,-0.3375956416,0.8531564474,0.8517883420,-0.1833593547,-0.3668282926,0.4279274046,-1.1330124140,0.6293390393,-0.1875369698,0.1160475165,2.1682090759,0.8720598817,1.4349334240,1.2770864964,-0.1004557535,-0.5276843905,-0.1601087302,1.3145697117,-0.0181776304,0.5276513696,1.3746075630,-0.8591616750,0.0153728090,-0.1448028535,0.6654556394,-0.8472108841,1.1001250744,0.4171614349,-0.0177354254,-1.1216690540,0.7256075144,0.1507796347,1.0267204046,0.6718088388,0.2002222389,-0.8297312260,-0.8101356030,2.3435692787,-0.4786757231,1.0909048319,-1.7758495808,0.2627611756,0.2653958797,-0.5927811265,1.5539902449,-0.9272117019,-0.2532606721,0.0267162919,0.5292546749,0.3089748025,-0.3464745879,1.7746504545,2.9259448051,-0.6218938828,-0.3926011324,-0.3428994119,-1.1926394701,1.5049992800,-0.8424344659,0.7986744046,-0.7885806561,-1.1607004404,-0.0135042230,0.9922061563,1.9919799566,-1.2437075377,-0.4395283461,-0.5311597586,-0.0297754165,-0.5898804665,-0.7635480762,-1.5769889355,1.0587168932,-0.0034756528,0.1553152949,-1.9455130100,0.2943831086,1.3622395992,0.4102196097,-0.4908825755,0.4014503062,0.0278171897,-0.0536309853,-1.2789026499,-1.2796289921,0.4953480065,-0.4660226703,-0.9548496604,-0.9615236521,0.9491387606,0.3494040668,-0.9034793377,-0.8746790290,0.3864723444,-0.7408620119,0.8857078552,-0.9054695368,0.3242028058,-0.9857577682,-1.7794227600,0.7796273828,-0.2548395693,-0.9350469112,-0.0115598422,-0.0557284057,0.4348230958,1.1245038509,2.6359810829,-0.2186294347,-0.0949227884,-0.2960619032,-0.7614319921,0.6499288082,0.0611613914,0.4410744905,0.7678567767,0.0930860490,-1.0300735235,0.3483096361,0.7597416639,0.0011209270,-1.1556539536,1.1331659555,0.9468092322,0.2521147132,0.1224794090,-0.5496848226,1.5198215246,-2.1303267479,-2.2218475342,-2.5806076527,0.0837756246,0.4271501005,0.8224028349,1.1306557655,0.3919700682,-0.0115966676,0.0475504175,-0.6004253030,-1.2305142879,0.5945131183,1.0072363615,0.3247313201,-1.2197523117,-1.1868721247,-0.9118242264,0.1778739989,0.3262349665,-0.8597450256,0.0205650963,1.7530291080,0.7721672654,-0.1331358552,1.0669914484,0.8614687920,0.9448447227,0.4930521548,-1.0212017298,0.7986354828,-0.7440475821,-0.1944002360,0.3420980573,0.5632216334,-2.4997861385,-0.4994763136,0.6333222389,-2.0620503426,0.8145817518,1.4459090233,0.9552916884,-0.7975873947,-2.1032149792,0.0418324843,0.5111634135,1.7133549452,-0.3090857565,-0.6058284640,-0.8708721995,1.2175831795,-0.2389851511,0.4239602387,-1.5448274612,-0.3783124983,-0.0029062431,-0.6120293736,0.2799707651,-0.0570160225,2.0717158318,-0.3598082066,1.4251867533,-0.0134970779,-0.9720110893,-0.2252669930,0.5460293293,1.5419213772,-1.5147491693,-0.3293933272,-0.0275527146,-0.9521688223,-0.3834776282,1.4057289362,-0.7203474641,-0.9101272821,-0.1940222532,1.3746294975,0.4223842025,1.1517481804,-0.3333800137,0.0154191507,2.1487598419,-0.9099595547,1.2981448174,-0.4607750475,0.7508655787,-1.1511445045,0.6852880120,0.3033760786,1.1724207401,0.0635844842,1.9570583105,0.8574123979,0.5666555762,0.7369867563,-0.3596095443,0.0712693930,-0.2050676346,0.7476635575,-1.5979381800,-1.6696869135,-0.0033412154,0.2548270524,-0.4833313227,1.0923733711,-0.2952604592,-0.8811125159,-0.4041282833,1.2807453871,0.1407522559,-0.2607857287,0.8139761686,0.2080699205,-1.0974228382,-1.0547447205,-0.5768285394,1.7892030478,0.4703820050,-0.7589623332,0.4739449620,0.3060959876,1.4044001102,-0.4405074418,1.5767858028,0.2276372015,-0.0085633667,0.1122219488,-0.1186968386,-0.7556450367,-0.2551757693,0.2367250472,-1.3682280779,-0.0868984833,-0.9292290211,0.4767979980,1.2660095692,0.7017489076,-0.0994677246,0.4604631066,0.5536651611,-0.6214803457,-0.1921214759,-0.9230517745,0.2861795425,1.9730838537,1.5194038153,-0.2218993008,0.0676458031,0.8111193776,0.5127606988,-0.0850184634,-0.3213681579,-0.2438399494,-0.1359906793,2.0709638596,0.3468191326,-2.5300788879,-0.7631182075,0.2191569060,0.0090567889,-0.7353634834,-1.5984612703,-2.1198539734,-0.1774644852,0.7098138332,0.8213640451,-0.0107929576,1.2051004171,0.0632010624,-0.3080267012,0.9183343053,0.0939481556,0.8973917365,1.3931572437,-0.2151860446,-1.0463820696,1.2186774015,0.4525365233,1.2896789312,0.3542840779,-0.4334890842,0.0643699095,0.1865993589,0.5796870589,-0.7730751634,0.4719973505,1.7717124224,-1.5757242441,0.2662694454,-0.4041916132,0.4621180892,0.6618397832,0.1943725944,-0.9175354242,-0.0798297524,-0.7954104543,0.4863788784,-1.4996377230,0.8618410826,-2.9106974602,0.3565086722,1.5209159851,0.5370289087,-0.1094295308,2.1429982185,-2.2595870495,-0.4742313921,0.4032390714,-1.3632237911,2.1153512001,-0.8269336224,0.4764483869,-0.3866333365,0.4835948348,-1.0510087013,0.9150114655,-1.4388750792,-0.3364607096,0.0429121219,-0.1839305013,0.3848934770,1.5128203630,-1.1400394440,-1.4442991018,-0.4257532358,0.8354291320,-0.2160586119,0.9489045739,0.3786438107,-0.6682091355,1.0235065222,-0.8382804990,-0.1399486065,-0.9926248789,-1.2264190912,-1.3117069006,-0.1271556914,0.0079912404,-0.3760568500,0.5664597154,-0.8595212698,-0.1183861569,0.8529757261,-1.9854843616,0.2800190151,-1.7601602077,0.6664977670,0.6719502211,-0.7664304376,1.0983656645,0.2911262214,-1.1661839485,-0.8158940673,-0.2933756411,1.4010317326,1.6039435863,-0.5165402889,-0.1408138573,1.1347715855,-0.4194507301,-0.5617449284,0.5707189441,-0.0715572983,1.7359468937,-0.6072747111,0.2172731906,-1.6416498423,1.1322650909,-1.7049622536,0.2442215234,0.7345991135,0.9624508023,-0.7012826800,-0.4934635758,0.2794271708,1.1199611425,0.0138948634,1.3469048738,-0.5083768368,-0.3632907867,-0.4739925861,-0.8815130591,2.1984884739,2.9767618179,1.0400345325,0.5973387957,0.6966767311,0.3020858765,0.7583796382,-0.7667793036,-0.0830394998,-0.6338041425,0.4115710855,-0.0886307508,1.4750047922,0.6065263748,-0.6084166765,0.4203138649,-1.1035499573,-0.1466142833,0.0930199549,-0.4346646070,-1.3677084446,1.7228507996,0.7114614844,-0.7142797112,0.3464543819,-0.6122346520,0.7374718189,-1.2237185240,-0.4646267891,-1.4108309746,-0.4445342124,-0.4988172054,1.8301521540,-0.7865855694,-1.0325416327,0.3002009392,0.1759860516,-0.3930571973,-0.0841103196,0.6128829122,1.1748423576,2.0594334602,-0.1751677841,1.9157706499,-2.0087039471,0.0548449084,0.9300742149,0.7866141200,1.1222592592,0.1036242396,0.6618089676,0.0268117934,-1.9981175661,0.9294196367,2.2584624290,1.0756754875,1.1363080740,-0.2930243909,-0.0277448576,0.8949297667,-1.3616064787,0.3977112472,-0.7987060547,1.2334747314,0.2763086557,-2.1072409153,-0.2869181931,-1.5621356964,0.7045946717,0.8275618553,-0.4897731841,-1.0612022877,-0.2257146686,-0.4813244045,0.8550677896,0.4653412998,-1.9319355488,0.0123473499,0.6307618022,0.1360304952,0.3419711292,0.2482180744,1.0112982988,-2.8517372608,1.0242309570,1.3946468830,-1.4900366068,1.3303142786,1.1665626764,-0.0065014083,-1.8222254515,1.1139158010,-0.4737008810,1.4344037771,-1.1761858463,-1.6211301088,1.0432368517,1.0384088755,1.0714992285,1.5375100374,-0.7071874142,0.0438755527,-1.1680675745,-0.1133877560,-0.8412772417,-0.7477636337,0.6549735665,-1.6748837233,0.1416903734,1.8518723249,0.5723341703,-0.2291723639,0.4399379194,0.8588612676,1.9773676395,-0.4936513007,0.2287907153,-1.0384471416,-0.1597029120,0.1248741448,0.7425230145,0.5512924790,0.7303834558,-0.8165476322,-0.7640091777,-0.1144194901,0.8935913444,1.6052113771,-1.2538806200,0.2855737209,-0.4613464773,1.2086780071,0.4985507429,-0.3405464590,-0.8937238455,1.2616927624,-0.9317969084,-1.0411241055,0.8100412488,0.7059498429,1.3697428703,0.9094738960,-1.9717726707,0.2420305610,-0.9077606201,1.6671775579,2.3022015095,-0.1790511310,0.8325935602,1.3162128925,-0.2899599671,-0.4036357999,-1.3132460117,0.1316954643,0.9602703452,-0.1307659447,-1.0357890129,0.5832430720,-1.4192433357,1.2996268272,-0.1998086125,-0.6707410812,1.8675396442,-0.2962323725,0.9742482901,0.2611752450,-0.1437780410,-0.6985815167,0.6297942400,-0.9077713490,-0.3890576065,0.4322726727,0.1401295662,-0.0165128782,-1.4022303820,0.3342009485,-0.0561159886,-1.2076241970,0.0269585140,0.0797272325,0.1862457544,-2.2476606369,0.9444752932,-0.2633162439,0.5973744392,-1.3259795904,-0.4369872510,-0.6111346483,0.4619466960,0.1574052423,0.4900255203,0.1863169968,0.2730141282,0.0945252627,0.6730496883,1.2070502043,-0.7237103581,-1.5864273310,-0.5616668463,0.8356405497,-0.0633497909,0.1185418442,-2.5133163929,-0.2127508223,0.9225611091,-0.4511755705,-1.3210129738,-1.5038857460,0.3074418604,-1.4114911556,-0.9896835685,0.4621183872,-0.1546157897,-1.0632112026,-0.6646524668,-0.2710254192,-0.0559235252,0.2106004804,0.3330169618,0.2115703970,-0.1708970219,-0.2765752971,-0.3595123887,-2.1213698387,-0.0695509166,0.9423075318,-0.6175131798,-0.5573751330,0.0207770932,0.8922007084,0.4503358305,0.0453439653,-0.9838991761,-0.1429029554,-0.0101154400,-0.3242063522,0.8762276173,-0.1310543418,-1.3132834435,0.1048069224,0.9953035712,0.0019832081,-0.5763996243,-1.5993032455,0.2357865274,-0.5236660242,1.2498191595,-0.3972760141,0.5428637266,-0.3759145141,-1.0959819555,0.4462662935,-0.4387346506,-1.1529084444,-0.0285182241,-0.1020001173,0.5932555795,-0.5795496702,-1.0888371468,-1.7439676523,-0.2361356318,-0.0777337477,0.7394383550,0.0782520548,1.6987942457,1.7381364107,1.1641181707,1.4951943159,0.1576152593,-0.6602454782,-1.6606831551,-1.8109960556,-1.5184327364,-0.6278802752,1.0903507471,1.0761795044,1.2518355846,-1.6058274508,-0.3573199511,-0.9369678497,1.4489934444,-0.0281910524,1.0515197515,1.3035051823,-0.7908535600,1.5493855476,0.1785422266,-0.2503399253,0.5442001820,1.4513047934,0.2108101994,-0.7557499409,-0.8626450300,-1.3776224852,1.0434657335,1.1152778864,-0.5381469727,1.1608798504,-1.1071029902,0.7692725062,1.7361100912,0.6548727751,-0.2329286039,-0.2109164447,0.8669708967,-0.5419610739,0.3878645599,1.0662782192,-1.9696036577,0.8957763910,0.0708186775,0.8453901410,0.0108403713,1.4044237137,0.6272301674,-0.7871339321,0.7302926779,0.5642443895,-2.1129529476,-1.1371386051,-0.0070197177,0.9867774844,0.0979930758,0.2202437371,-0.3924337029,0.5245616436,0.9684751630,-0.3208032548,-0.6954401731,0.2925103903,0.6001781821,-0.2031298876,2.5664210320,-0.7845811844,-0.0679450184,0.0334720835,1.3929741383,1.5113071203,0.2075864077,0.6620129347,-0.6452699900,0.7408705354,-1.7304400206,-0.1776096076,1.5553163290,-0.1056940630,-0.6364824176,1.5327748060,-0.9357856512,-0.2761799097,0.4746173322,-0.8172100186,-0.6547473669,0.5243036151,-0.0618794486,-0.2851223946,-1.0006905794,0.7876641750,-0.8730727434,-0.6232350469,1.6723668575,0.5514597893,-1.0533039570,-0.3889478743,0.4371635914,0.9450132847,-2.1121516228,0.7922255397,-0.3742645383,-0.1040292904,-0.1706566215,0.8582338691,-1.1603547335,0.6076740623,0.9498484135,-0.8680899143,-0.8084941506,-0.5008729100,-1.4534268379,1.1655235291,-0.9484149814,-0.0762682483,0.0358931646,-0.2384106368,0.9499883652,-0.9772548676,-1.0445420742,0.1405598968,0.5456544757,-0.5860677958,2.0359721184,-0.7959108949,1.8235174417,1.8872886896,1.1418535709,0.3126354218,0.3064375222,-0.2798117399,-0.4689850807,-1.6476761103,-1.5992029905,-1.2629358768,-1.7541141510,1.1695880890,-0.0457241274,0.4733829498,0.0854842886,2.0468397141,0.2154959887,0.0350889787,0.2971332371,0.9285229445,0.9239901304,0.4604280591,-0.5467797518,0.4883889854,-0.9885988235,-0.5728197694,0.9264045358,0.7810805440,1.0949702263,0.1750663072,1.4096968174,0.2180642933,0.7436999083,-0.1266501397,1.3566181660,0.3130574524,1.2390726805,-0.1934143156,-0.7612330914,1.0759313107,-0.3289625347,0.1660896689,0.0740403831,-1.1717393398,1.1129521132,-1.1576689482,-1.7789555788,0.9600282907,-0.7468833923,0.5374038219,0.9328088164,1.5861493349,0.8423115611,-0.4052751660,1.0446491241,0.0374817997,-1.1891011000,-2.3277878761,0.3875864446,0.2966091335,-2.2180492878,1.0663291216,0.2598075867,1.9161059856,-0.7282618880,-0.6266215444,-0.6739975810,-0.6415785551,-0.6179529428,0.6047268510,-0.2844314575,-0.4305409491,1.9450337887,-0.1466508955,0.4638362825,2.0536992550,-1.2035881281,0.2433279604,0.3226449490,0.2997124195,-2.0240993500,1.5049318075,2.5287919044,-1.6473007202,-1.8275324106,0.7434623837,0.3066866100,-1.1217963696,1.3457329273,0.6340570450,1.1217298508,-0.0488672554,-1.2668669224,-0.4204682112,1.2064194679,-0.1509321928,2.8461978436,-0.0451924764,0.4221574366,1.7345610857,-0.5981693268,0.7031428814,-0.0062330775,0.8340855241,1.6620643139,-2.1220414639,0.2365728617,-0.1516558230,0.5030402541,-1.7541236877,1.3960247040,-1.2516578436,0.9715057611,-0.1300617158,0.2552434802,1.9452192783,-1.0372388363,0.5538521409,-0.3709153831,-1.3116137981,0.6361788511,0.9690408707,-0.9008204341,-1.6484543085,-0.0956472978,0.3216061890,-0.4470887482,-0.7181816697,-0.4564741850,0.0436974354,-0.8783827424,-0.2153731734,-0.7284212708,0.0316979624,0.5592319369,0.3584336936,0.3528334498,0.7266294956,1.2041256428,0.6806427836,0.3226889074,-1.6938356161,1.0152925253,-1.2883669138,1.5473442078,-1.6940101385,0.7440575957,0.5449872017,-1.5002492666,-1.1375263929,0.4404759109,-0.9481218457,1.0618398190,0.3651114106,-0.1956363469,-0.0600685142,0.2220172286,-0.2049867213,0.7872170806,0.5148497224,-0.4739772379,1.0607751608,-2.2600011826,-0.2448202819,-0.5458866358,-1.6628972292,0.6307308674,0.6686230302,-0.8363482356,-0.5782997608,-0.6807925105,-0.1028094068,-0.3188337684,-0.2476856112,-0.8180071115,0.1356047243,1.5968712568,-0.8921045065,0.7458104491,-1.2947020531,-0.0416521616,-1.5273494720,-0.4211159647,0.4188219309,0.0392890759,0.6555977464,0.9114678502,0.3619571626,-0.5588787198,0.2664752603,-0.3256011307,2.4297068119,-0.5743183494,0.2944850326,0.9484425783,0.9825353622,0.3974099755,-1.0577732325,0.6464989185,-0.2026707530,0.3146737516,-1.5660982132,-1.0093059540,0.9294809699,0.9666360021,0.3079728484,-0.0658802390,0.5567436218,-0.4141434431,-0.9001114368,-0.2555243075,0.4303688407,0.6368939877,-0.3189966381,-0.1767177880,2.1670389175,-1.1297926903,0.0641836300,0.1511009932,-0.8907510042,1.9690883160,0.8412009478,-0.9752152562,-1.5275386572,1.0577732325,1.3252483606,0.8089088202,1.4796154499,-0.2566390634,-1.3153479099,-0.8288609982,-0.2103146762,0.1020352095,0.9253606200,1.2352576256,0.5293609500,0.4743773043,-0.8591988087,-0.1014773473,0.5960752368,-1.3404738903,1.1582435369,1.2524724007,-0.6086274385,-0.7040278912,0.8515852094,2.5486783981,-0.6445094943,0.4089204371,0.3661203384,0.1784386188,-1.1837905645,-1.6509048939,1.1145668030,0.2557139695,-0.0395323709,0.0242085606,-0.4647791684,-0.2464168668,-0.5249590874,-0.0612839907,-0.1260320395,-1.0659192801,0.7829201221,1.1975088120,-1.8215229511,1.2382860184,-0.5807151198,-0.2608066201,-0.0539864413,-1.5416053534,0.7714299560,0.5916702747,0.5156317949,1.1404858828,-1.3494912386,2.1378667355,0.3047274649,1.2195792198,-0.3578601480,0.0984548479,0.7212519050,2.6335790157,-0.4315360487,0.5843237042,-0.0755212381,-0.2289883345,0.9112005234,-1.0294852257,2.1142601967,1.0679942369,0.5550442338,-0.1199776754,0.5793484449,1.8686089516,-0.6061916947,-0.0292256158,-0.1874776036,0.4629638493,0.4734807909,-1.0361982584,-2.4138829708,-1.1330380440,-0.5306935310,-0.6419487596,-0.5470802188,0.1643695980,-1.6450990438,-0.2671853602,-0.1303537935,0.0227936525,0.9756251574,-0.0457911752,-0.4323091805,-1.2599148750,-0.1694476306,0.4077905118,1.0774275064,-1.1228400469,0.2199149877,0.4889201522,-1.2091072798,0.4924613833,-1.7255488634,0.9194186926,1.4995775223,-1.0543442965,0.4016973972,0.9137138724,1.4287455082,-0.7213507891,0.5033758283,-1.1633116007,-0.7225621343,-1.4303677082,-0.2655269504,-0.8245450258,-0.6388269663,1.1980402470,-1.7719768286,-0.5820679665,1.0126674175,1.2914206982,-1.1844006777,0.3093956411,-1.2403331995,-0.4625792503,1.7663393021,0.6885182858,-0.1327944398,-0.8755931854,-1.5265610218,0.2222946286,-0.3382628858,0.6167198420,-1.0755565166,0.0484146737,-0.9836882949,-0.3923490345,0.5466002822,-0.3768848777,-0.7443243265,0.3661516309,-0.1037210673,-0.6928908229,0.7701465487,-0.2680769861,-0.1214702353,-0.6213663220,0.2482643723,1.5134902000,-0.0739834234,-1.4493509531,1.1660684347,0.1881067455,-1.2092013359,1.2742975950,0.3987053037,0.3768714368,1.4138619900,-0.8284464478,-0.0801821947,-1.1233460903,-0.6918120980,0.5208147764,-0.0682908595,-0.9105952978,0.1875498742,-0.5142341852,-0.5274975300,0.7494561672,-0.7152031660,0.4310196340,-0.4823740721,-0.2510137260,0.1944553405,-1.3107248545,-0.1923373193,-0.1888710707,0.2006835639,0.8063291907,0.7279618979,0.2301612198,0.5022042990,-1.6600764990,1.0828719139,1.8728606701,0.6034314036,-0.4063622355,0.0974950045,-0.8997538090,-1.5935285091,-1.0190300941,1.0629904270,0.0831695795,-0.4738741815,-0.4485514760,0.3416296840,-0.1248249412,1.1692199707,2.2329859734,-0.3595784605,2.1218981743,-0.0728280321,0.4060373604,0.5449692011,0.8206561208,-0.4518414736,0.2907862067,-2.1724636555,1.1614646912,2.5593364239,0.7427705526,0.9906321168,2.0261092186,-0.0148052406,-0.2360571027,0.0363243632,1.2760270834,2.2971293926,-1.1610804796,-1.7893850803,-0.3227211535,-1.8779487610,-1.3441138268,-0.8956089616,-0.0985141471,0.4440960586,-0.9870734215,-1.1733098030,-0.4680004716,0.0355096310,-0.9436638355,-0.1876551807,-0.2832317352,1.1657112837,1.5924739838,1.0328596830,-0.4097533226,-0.4622452855,-0.5567474961,1.1893956661,-0.3589572310,-0.8171840310,-0.3599012196,0.5284134746,0.6601926684,-0.2853067815,-1.5502932072,0.6783145070,-1.3337225914,0.9995742440,-0.2768847942,0.7775377631,0.6332675219,-0.1205610335,-0.9084852934,-0.1494361758,0.3467653990,-0.8398606181,0.4216800332,-2.1474878788,1.0741838217,0.5535035133,1.4500633478,0.5962111950,-0.3862569332,1.0310724974,-1.6946784258,-0.4748837650,0.9095218778,1.2876939774,-1.8530343771,-0.6701546907,1.8218663931,0.6484426260,-2.1453423500,0.1260983646,0.6405251026,-0.1364991963,-0.5790331960,-1.1921503544,-0.0568375923,0.2709504068,0.9835256934,0.8560069799,-1.0371228456,0.1756413430,0.4604872167,0.1207154393,0.0869964808,0.1099092290,0.7736787200,2.4697232246,-0.8884851933,-1.8836847544,0.4033220410,-0.9149255157,-1.0660659075,-0.1941040903,-0.9507152438,-0.6525584459,-0.2845203578,0.5010703206,-1.1385391951,-2.5650165081,-1.0482982397,0.7601513863,1.0343254805,0.1622663587,0.4804539382,0.4948939681,-1.1310155392,-0.4456132054,-0.0148028927,0.6583849192,0.8705469370,-1.4775637388,1.5122822523,-2.5054395199,0.6433568597,1.1670595407,-2.4150571823,-0.7000072002,0.4520107210,0.2669504285,0.0745046884,-0.0961903110,0.8950932026,-0.0153444046,2.3216211796,-0.0087271752,-0.7285081148,0.8591826558,-0.0213805623,-0.9274692535,0.8245937228,-0.0500126071,0.9498620033,0.0939764380,0.2396673709,0.3366479874,-0.0664266646,1.4263436794,0.2282274365,-0.6703722477,1.6196011305,1.5359443426,0.8145934343,0.0678382739,0.0837390274,-0.2199727595,-0.4387906492,0.3200174570,1.2475085258,-0.4494763911,1.4635165930,0.7197579145,-0.1485113055,0.0235467963,-0.0737998858,-0.1217009351,1.1287385225,0.3565534651,0.0661123544,-1.4903062582,-0.1748026311,-0.3600355685,0.4882857800,0.7067445517,1.7316313982,-1.5993480682,1.1871122122,0.0806279257,0.1233804226,1.4097801447,0.0073844674,0.4032472372,0.1401428878,1.4815948009,-0.3940936625,0.9161916375,-0.1888489723,-0.2546358109,0.1415531337,0.2554948926,0.5829980373,0.5339160562,0.1090676412,1.0032021999,-0.1615457684,-0.6464024782,-0.5283038616,0.3620505929,2.9733176231,-1.0681328773,0.7487841249,0.8224366307,1.5359381437,2.7004611492,0.6946715117,0.9688691497,-0.2185768485,-1.7118986845,0.6170027852,-1.4078933001,0.2380145192,0.9218633771,0.8282817602,-0.2167852372,1.2319794893,1.1953899860,-0.7662591338,-1.2329901457,-0.6564483643,-0.7983369231,0.4234818816,0.4227693379,0.3662743270,0.3555461764,0.3225057721,0.0377100483,0.7185549140,0.1276012510,-0.8430910110,-1.1099169254,-0.7077657580,0.9883331060,-1.2329790592,-1.6483401060,0.0518403128,0.4276541770,-0.2361366451,1.1640164852,1.8784108162,1.5808711052,-0.7807156444,-0.8628751636,-1.4693769217,1.1178039312,-0.8612729311,0.3775274754,0.0553550571,-0.2481898218,1.1510961056,1.4155236483,0.4141672552,-0.1486062407,0.1500177085,0.7754682302,1.1698340178,1.0434730053,-1.3811140060,0.4370983243,0.5352761745,-1.8544534445,1.2646948099,0.2929232419,0.0995730236,1.7987678051,1.3470214605,1.2089182138,0.1961900741,0.1137968972,-1.6796602011,-0.0636957809,-1.4094570875,0.2016211897,-0.8527985215,-0.3630916178,0.8872061968,-1.0532958508,0.3649423420,0.8411453366,-0.3478016555,-0.1131411865,0.4069535732,2.3565943241,-0.6662643552,-0.9734390974,-0.6908809543,0.9773233533,-0.1573923081,-0.7164798379,-0.4443368018,-0.1431108266,1.3523162603,1.8951483965,0.3178819716,-0.5887733102,0.8732778430,-0.6213280559,-1.3105956316,-1.8258597851,0.3260253668,-0.9911643267,-0.7561984658,-0.2424144000,-1.4406697750,-1.8866000175,-0.4525777102,0.4981562197,2.9362752438,-0.4877498746,-1.0544553995,-0.3383483291,1.2915300131,-1.2027258873,0.3907198012,-0.0700768232,0.8171388507,2.8624243736,1.7433649302,0.0142839653,-0.7587402463,-1.0983080864,-0.1429131776,0.9946195483,0.2118909806,0.2142890394,0.7555453181,-0.7680301666,-0.7556154132,0.1945812553,0.9759526253,1.1216096878,-0.0747907311,0.7729748487,1.2828271389,0.2414376140,1.2615263462,0.6379812360,-0.4018948674,-1.7069851160,-0.4766686261,1.3859781027,0.9483999014,-2.4435849190,0.9283960462,0.1634889543,-0.3825234175,1.8444286585,0.2194792330,-0.9868534803,0.5217725635,1.0495344400,0.8497440219,0.6917409897,1.0312966108,1.2406227589,-0.3547858298,1.9061973095,-0.7241984010,0.4865470529,0.6772283316,-0.7669066787,0.3942653239,-0.8978323936,0.8897718787,0.2239701748,2.4911932945,0.3996796012,-0.5503692627,-0.8688344955,-0.4812298417,0.0351235606,1.9813669920,1.5126305819,-2.0804917812,1.2661659718,0.0236697476,-0.6080989838,-0.9334201813,-1.1945544481,2.2148840427,-0.0787384063,-0.4709452689,0.3463014662,0.2351722717,-0.6441224217,0.7173498273,-1.0471272469,-0.9710624814,0.3333386481,-0.0502374433,0.0522217862,0.7412327528,-0.9452767968,0.4947839677,1.9146962166,0.4911620319,0.6288027763,-0.2933082283,0.0901089683,0.7404099107,-0.1309597939,-1.9170587063,1.6293636560,-1.7506906986,0.4758150280,-0.6292086244,-0.1218387485,0.2569647133,-1.7762563229,1.1726000309,-1.1609822512,-0.4973379970,1.3849647045,0.2108934671,1.7501076460,0.1977767199,-1.5061140060,0.2052410543,0.8849083185,1.0420837402,-1.5378690958,-0.9945856929,0.3950080276,-1.1667097807,0.7336266637,1.0541245937,-0.7604739070,1.0298671722,0.4831345081,-0.9305076599,2.3098583221,0.8978148699,-0.7780020237,-0.0763000399,0.1405724138,-0.9309204221,-1.2948073149,-0.9992104173,-0.7626069784,-1.1946477890,-0.0887558684,-1.1694561243,1.4181926250,-0.5647112131,0.1377933472,-0.8132561445,1.9780479670,-0.2693868876,2.5489280224,-0.4812024236,2.1438763142,-0.6436809897,-0.2257929593,-0.1043324471,-0.0241426136,0.3608437479,-1.3132336140,-0.2473047823,1.9679007530,-0.0772148073,-2.0944638252,-1.2689850330,-0.3390084207,0.0193167645,1.2736999989,1.4182841778,0.7875558734,-0.5130640268,0.0768273100,-0.9786463380,0.2218512148,-0.9420463443,-0.2778419554,0.2273272276,-0.4655575454,-1.0925114155,-0.1088153049,-0.8575080037,-0.7718771696,-2.1138706207,0.1061449572,-1.2214846611,-0.4387984276,0.6525202990,0.7284477353,-1.1624752283,2.0951714516,1.4666159153,0.5122377276,1.6254560947,0.5767518282,-1.4740482569,-0.3197341561,0.0622204207,2.2914700508,0.5785361528,0.5546657443,0.7368097901,-0.2011972219,-0.3459620476,1.4479689598,0.7183705568,-0.7114289403,-0.2445436120,0.9475785494,0.1670360416,-0.1054515019,1.5192409754,-0.2389630973,-0.3069087863,0.3849918544,-1.9849205017,-0.8939456344,0.1685190648,0.6565925479,-1.5131690502,0.3487373590,-0.4754433334,-0.5820451379,0.9503807425,-0.6067024469,0.4588730037,1.6100572348,0.5035930276,0.4674057364,-0.3812543452,0.4779359996,0.5542572141,0.8604867458,-0.0800580233,-0.5947277546,0.3877373040,0.9289138317,-2.0369527340,0.8429705501,-0.8200830221,-0.3597954512,0.1188161224,-0.8078942895,-0.6227641106,-2.1208841801,-1.0918895006,-1.2143417597,-0.9062018991,0.2425887883,1.0418492556,-0.8915598392,1.4448651075,0.5658872128,-0.6691966057,0.0779437646,0.3703321815,1.0202715397,0.5159808397,-0.3667911887,0.1917651892,-0.0155972950,0.6114939451,-0.5516857505,2.0143985748,-1.4417407513,0.1094853356,1.6910899878,-0.5058087707,-0.2841334641,-0.4427628219,-0.7798770070,0.3184933960,1.5184088945,-0.3982077539,-0.3256989717,-1.9115608931,-0.4265502393,1.9067032337,-0.5795803070,-0.9464166760,0.1618944108,0.2046693861,2.7043745518,-1.1141778231,-0.2270487696,0.0677588880,-0.8169810176,-0.0516205356,0.2156272531,-0.0458132848,1.1395378113,-1.9288947582,1.0327042341,-0.6658371091,-1.0002037287,0.7938078046,-0.5091620684,1.1180939674,-0.8911152482,-0.6446077824,0.1085245833,0.1545051485,0.7162056565,0.0998768061,1.5463054180,0.3392734230,-0.1677765995,0.0178067535,2.2100381851,0.1243686378,-0.4336081743,-1.1434708834,-0.2915322185,0.2938709855,0.1741888076,-0.9570773244,0.2976694703,-0.8821976185,-0.0567142293,1.8015016317,-0.0966258571,-0.8744275570,-0.3556698859,-0.2422062755,-0.0088157170,1.0579258204,0.6251289845,2.1922950745,0.8293181062,1.1037898064,0.1161758080,1.3735295534,1.8517149687,1.2776745558,1.1805377007,-1.1309832335,-1.4316225052,-0.7249827385,0.4579662681,-1.0276892185,-0.9429395199,0.7407530546,-1.1371870041,0.8070212007,0.8429144025,1.3206818104,0.6324065924,1.9122589827,1.9089622498,0.9503044486,1.8724390268,-0.3448031545,-0.0643757060,0.5141147375,-1.0741199255,-0.6546777487,-0.2585322559,-0.4660071731,0.2123210430,-0.6828444600,-0.3794018924,1.5062401295,0.1076194942,1.1968497038,1.3637975454,-1.5723030567,-0.2526699901,-0.8103145957,-0.7729591131,-0.3791863918,-0.5915085673,-0.0657836497,0.5478895903,1.4897552729,1.2893457413,0.3316682577,-1.2735449076,0.3352213204,-0.1605404168,-0.6274160743,0.0444982313,0.4427059889,-0.1887391508,0.0424868092,0.6873580813,-0.5684332252,-1.8209024668,-1.5618481636,1.1418203115,-0.1679338664,-0.1575482935,0.8625968695,1.7374920845,-0.6851282716,-0.7020391822,-0.5403820276,0.0701741204,0.6840214729,-1.0883448124,-1.0662660599,0.3783966303,-1.2807009220,-0.6299644113,1.1646709442,0.6178892255,0.2659975588,0.5481295586,0.8629608750,0.3323490322,-1.7330682278,0.7170284390,1.3835469484,-0.1560150534,0.6267575026,0.0135885328,0.5174806714,-1.3381071091,0.2403987944,-0.6325420737,-0.3140203655,-0.5688653588,0.0899808258,0.2951270342,-0.3967520297,0.8154203892,0.6676385403,-1.0550323725,-1.7451119423,1.2019145489,0.8572792411,0.5403226018,-0.3976074755,-0.5785681009,-1.1575276852,-0.7872358561,-0.7130684257,-0.6214036942,-1.0228501558,0.0767670125,-0.4886718988,1.1801239252,-0.2055412382,-0.6231933236,1.3826036453,-0.8254976273,-0.2961417437,1.4713494778,0.2379731238,0.8579406738,0.3441528976,-0.5790320039,-1.0394935608,-0.3038409948,-0.4149534404,-1.0315365791,-1.7151025534,-0.5805560946,1.2495222092,-1.4802988768,0.2671444416,-0.6707246304,-1.2410545349,0.1354297549,0.9997917414,0.4972026944,-1.0840744972,0.6837875843,-0.3927797079,0.3305899799,0.6962628365,-1.0900052786,-0.6791628003,0.3703728318,-0.3813745379,-1.2939769030,-0.4187581241,0.2346390933,-0.2559554577,-1.0008970499,-1.3414121866,-0.4729372263,1.4051200151,-1.5527420044,-1.2766270638,-1.0660550594,-0.5740276575,1.2553514242,1.3542720079,-1.4046258926,0.3287573159,-3.0902717113,-0.8251926899,1.3747756481,-0.5134324431,-0.0683978125,-0.5844672918,2.3122715950,-0.1144952849,-0.1771259159,0.6621459126,-0.9766175747,0.9550002217,-0.2011980265,1.0007474422,0.2201173604,0.5645438433,0.1237144545,-0.7314903736,-0.0032809498,-0.6201736331,-0.3656804562,0.4783496261,-0.1402065754,-0.8107504249,0.4245607853,-1.9665911198,0.0242772475,-0.2220647484,-1.0378764868,0.8202825189,1.1987079382,-0.3498147130,-0.1208228320,-0.7644951940,0.0111101391,-0.5653514862,0.5157155395,1.1558949947,0.1688937247,1.6910996437,-0.8339630961,-0.7835124731,-0.0265033338,0.7289951444,-0.0396559015,-0.6672050953,-0.9940689206,-1.0564441681,0.9359007478,-0.7483726740,0.7249618769,0.7593082190,0.7683255076,-1.2546075583,-0.1201548800,-0.1855690032,-1.3772150278,-1.6465450525,-0.4068576992,1.6283794641,0.1573139578,-0.4508792460,0.4044491053,-0.5097197294,1.2035160065,0.4231516421,1.4437040091,-0.1109154448,0.2013794035,-1.0002640486,-0.3121077120,-0.6141272187,0.1143021211,-0.3780872822,1.0046535730,1.8508744240,0.5487187505,-0.7260112166,2.1805567741,0.3423650563,-0.8168572783,-0.4555746317,-0.3628090918,-2.2633161545,-0.6448135972,-0.7452431321,0.2334146351,0.8234783411,0.5006471276,0.4734275937,0.6055223942,0.5627831221,-0.4720727503,-0.1004450172,-0.2453504503,-0.3004291356,0.2103607357,0.8166112304,-0.9881518483,0.6973307133,1.4465472698,0.7168634534,0.5701670647,0.9973092675,0.7807003856,0.0557702519,0.8964763880,-2.2280788422,-1.1141041517,0.7094801664,1.4749150276,-0.1043331474,1.5968731642,0.6388558745,-1.8664846420,-0.9645528793,-1.4716819525,0.1554246396,-0.7584255934,-0.6129170060,-0.1678290069,-0.2931369245,0.8345580697,0.4046899974,-0.2836818397,-0.1639537364,-1.3903989792,-0.4709609151,-0.1503601223,-0.4822956324,1.0982751846,0.7710070610,-0.7754664421,-0.2240831107,-0.0304530412,1.0826807022,-0.5305797458,0.6023666263,-2.1382906437,-0.0566323511,1.1664443016,-0.7720962763,-0.9089879990,-0.4142166376,2.5208303928,-0.1248839349,0.0180679932,-0.9986228347,-1.2627335787,-0.5651069880,-0.4552381933,0.5557269454,0.9943681955,-0.2865622938,-0.5457049608,1.6967656612,-0.5081860423,0.0036205626,-1.0185145140,0.2515618503,-0.3381818235,1.0141428709,-0.5825280547,0.6387898326,-0.3677871227,-0.5683578253,-0.7212477922,0.1982797086,-0.2174220383,0.9147565365,0.4437566400,-0.3062036335,-0.9490559101,-0.4480834901,0.4285705388,-0.1649990529,0.8649626374,-0.6476624608,0.7200577259,-0.3377147615,-2.0285484791,0.7261819839,-1.1678304672,-1.2852076292,-0.4837974906,1.2880570889,-0.1298787147,-0.1980783939,-0.3344875872,-0.3914431930,-0.6124061942,-0.6765239835,1.3272296190,-0.4486954510,-0.3164072931,0.0308305565,-0.3133567274,-0.1732591838,-0.3273687065,0.9443682432,1.1220173836,0.1123387292,1.3723402023,2.0625617504,-2.4485590458,-0.5619884133,0.3550988138,0.6343781948,-0.3924500942,-0.8131564260,-0.2328732610,0.2468012124,-0.5624132156,-0.8416020274,-0.9421200156,0.9453729987,0.1409107000,1.7535657883,-0.3472236991,-1.4894933701,-0.5080354214,1.9926500320,0.5554619431,-1.6960769892,1.7523661852,-0.5975508094,-0.4664914012,-1.0947922468,-0.6454249024,-0.2021548301,0.2050734758,-0.2703858316,-0.3102994859,0.3622126877,-1.8181655407,-0.1004303396,-1.0705139637,-2.0765106678,1.7234400511,-0.1522772014,-0.3638286889,0.3420642316,1.4070423841,-1.3161656857,-2.1506977081,-1.5808782578,-0.3616223037,1.1524333954,-0.4334156513,0.7738724351,-0.8342115879,-0.7282395959,0.6749752760,-0.4777715802,1.4923013449,-0.6583909392,0.5604837537,-0.5135775208,-0.4712557197,1.6082854271,-1.3844133615,2.2784225941,1.3843681812,-0.9408109784,0.0214956999,0.1947668046,-1.2912441492,-0.3801298738,-0.8062320352,-0.7280040383,-1.0826486349,1.0985850096,0.1326422393,1.8456447124,2.1873707771,-0.7083841562,0.6465144753,-0.5518972278,0.2373841107,-0.0164395105,-0.0291097742,1.6453253031,-0.5479516983,0.1853130013,0.6488700509,-0.3811258376,0.0817243606,1.0087109804,-1.1935225725,0.2637767792,-0.8994972110,0.3363832235,0.2713788450,0.5522467494,-0.6908838749,3.2648844719,1.3637685776,-0.5434085727,-0.8160778284,2.5939521790,0.5945166349,0.0170803964,-0.8449776769,-0.8151623607,-0.6342274547,0.9066578150,-0.6744567156,0.2777738869,0.2134030014,-0.6038596034,0.5620812774,0.4132402539,-0.9826997519,1.0715109110,0.4687927365,-0.1042525694,-0.4841112792,-0.2296179980,0.9663137794,-0.5415360332,-0.3242196739,-0.0827071369,1.3674101830,-1.2061275244,-1.1793091297,2.2461023331,-1.5597070456,-0.7396000624,-0.1240326911,-0.0979401693,-0.8028639555,-0.9611197710,-1.2690706253,-1.4909585714,1.5873177052,0.1216608360,-1.4530825615,1.1822804213,0.6036565900,0.6341340542,0.6647869349,1.0432860851,0.1756239235,-0.1246411651,-0.0421862118,0.7873358130,0.0727108419,-1.8087786436,1.8381971121,1.0782800913,-0.3556542397,-0.9404379129,1.1988965273,-0.3806185126,-1.1939523220,0.2033593506,1.0147236586,-2.7281723022,0.7938317657,0.1125748605,0.5684316754,-0.6089876294,0.2789086998,0.9851705432,1.7537573576,0.2681056559,0.8519150019,2.4660148621,-0.2989487350,0.0854466408,-0.4715458453,-0.5302187204,-2.3346014023,-0.4460463226,-0.5775428414,-0.6922178268,-0.3119456172,0.3294471204,-1.3128342628,0.3397966027,-0.2910468876,0.9310884476,0.5599357486,-0.0645182207,-0.0022406222,-0.5151447654,0.5345206857,0.3004088998,0.2320223451,2.1810531616,-0.1001604870,-0.6051329970,-0.5047010779,0.0176231600,-0.5135729313,1.3429766893,0.4130504131,1.0463596582,0.8617561460,0.0478619747,0.0463153683,0.3848271072,1.6161820889,0.8716033101,-0.7510064244,1.6390513182,1.7839026451,0.5109132528,-0.4672897458,1.1222280264,0.9888499975,-0.9561136365,0.5663571358,1.4470038414,-0.7865455747,-0.4490454197,0.1197444052,-0.0093231238,0.5896588564,-0.2719801962,0.1982195675,-0.2045348287,0.4862102866,-0.9825719595,0.2153809816,-1.1695139408,1.4600381851,-0.4786804616,-0.2161083519,1.3162412643,-1.0952185392,-0.2379431874,0.0441102535,-0.4496622980,-0.5129234195,-1.9090203047,0.5068237185,0.2302060127,-0.7661902905,0.0725760013,0.9885923266,1.0863655806,-2.9028239250,-0.5360904932,-1.9112136364,1.8043782711,-1.2130129337,1.3801456690,-0.3277495205,0.2450582385,-0.7642333508,-0.3404273093,0.1624981314,1.7061364651,0.8927001953,0.8685998917,-0.5195849538,-0.0039161691,-1.3448412418,-0.3250283897,-0.7400012612,0.1771302372,0.6164767146,1.7528487444,-0.3680059314,-1.0127396584,0.7688501477,-0.2467727959,0.7563650608,0.9357182980,1.0622066259,2.3305165768,-0.5720127225,0.5467406511,0.5635195374,-0.9249114990,2.7588467598,0.8314345479,0.1939035803,0.7628485560,-0.4104726315,-1.9406030178,-0.3032291830,0.4363195598,1.2151136398,2.1058390141,1.1828629971,0.3339031935,-0.8795049191,1.2889955044,-0.8493562937,0.2111147940,-1.2545552254,-0.6699841619,0.1545667648,0.9607257843,0.9349159002,0.8397400975,0.6369614005,1.0919691324,1.8135930300,0.9556264877,-0.1990593225,-0.8042902946,0.6528923512,-0.0553436130,-0.9927421808,-0.5951382518,-0.0551041886,0.6262081265,2.3066689968,-0.2077073157,0.7109154463,-1.1168620586,0.5868679881,-1.0205169916,-0.4096455276,0.5808160305,1.0296586752,0.6482652426,-0.2194568217,-1.4834964275,-0.1184953302,0.4194943607,2.1360015869,-0.4918103814,-0.7194541097,-1.3561576605,0.2670113444,0.6546127200,-0.2104466856,-0.1670428365,0.5703315735,-0.4559410810,1.0440343618,1.2773948908,-0.5565972328,1.6024007797,0.2661893368,-0.4304800034,0.2327338457,-0.6957453489,0.8529608250,-0.1704961210,1.0020779371,-0.4330396354,-0.1417545974,-0.1366312355,1.1569111347,1.1959494352,-0.6120578051,0.3761216402,1.3039016724,-0.6344389319,0.5409040451,-0.2106793523,1.7126660347,-0.1599847823,1.6979123354,-1.2285583019,-1.1358175278,2.6169531345,0.8238010406,-1.1758143902,1.1397869587,-2.3761627674,-0.2448349744,0.1050523967,1.4465601444,0.3278667629,-0.9939356446,-0.9700256586,-1.2412242889,1.1203885078,1.4587260485,-1.9321591854,-0.2354511768,-0.0673358142,0.4001037776,0.2343670577,0.7390849590,-0.2944712937,-0.3466485143,-0.1584270895,0.3662830889,-0.6116271615,-0.2264357954,1.5210326910,-0.6150326133,-1.5202091932,-0.5913832784,-0.4052457213,-1.4865701199,-1.9483112097,-0.5207968354,0.4274829328,0.3046709895,-2.0096416473,-1.5396296978,-0.4011812806,1.5112646818,-0.7303193808,-0.5129240751,-0.8286438584,0.0695798472,1.7603245974,-0.3305148482,-0.8455023170,-1.4774661064,1.2175356150,0.3046442270,1.5573654175,0.2028430849,0.1601100266,0.9338047504,-0.1322722286,0.5623129010,-1.1053166389,0.3339771032,0.7388482690,-0.5675597191,1.4587401152,0.9002025127,0.7754671574,1.2447451353,-0.9453841448,-0.0203836951,-0.7514674067,0.2120767683,0.2850379646,0.1254609972,0.2035339177,-0.3764954805,-0.9387801886,-0.1428789049,0.5332627892,-2.6065831184,-0.8216148615,-0.7328824997,-1.4360533953,0.2980169356,1.7235522270,-0.1267851740,1.2048579454,-1.2153682709,-0.4437190592,0.7440560460,0.9141807556,1.5864833593,0.6928018332,-0.9534311891,0.6793599129,0.5651528239,0.2193024904,-1.1105041504,-1.0860613585,1.1356219053,-1.1252977848,-0.3664375544,-0.0169660207,-0.5677758455,0.5198579431,-0.4156208634,-1.2413494587,-0.4517956972,1.2629374266,-1.9606316090,-2.0649142265,1.2586480379,-1.0318564177,0.6451462507,-0.0639000982,0.3058444858,0.3714894652,3.2189693451,0.8671776056,-0.6356307268,-1.2256245613,-0.6236977577,2.0042676926,0.3193460405,-0.2986065447,-0.0811628103,1.1276055574,0.4359809458,-0.8637416363,-0.8411214352,0.0813471526,-2.5876824856,-0.4164364338,-1.0778590441,-0.4280856252,-0.1837351769,-0.4342537224,-2.1249547005,-0.7090559006,0.4856309593,-0.2251652330,-0.4225297570,0.7283768058,-0.4008677304,1.7381820679,-2.5891318321,-0.0358014069,0.7630400062,1.2215707302,0.5623279810,-0.2767444849,-0.7788773179,0.6425501108,-0.2790244818,-0.0601394959,0.9226582050,-1.2856285572,0.5124117136,0.6543196440,0.6985861063,-1.1863965988,-0.7743391395,-0.8036898375,0.1511544138,-0.2061739713,0.2215616107,1.4245580435,0.6433502436,0.2171405405,1.0231777430,0.8845224380,1.2237645388,0.7285240889,-0.2870639265,-1.1345304251,0.4285645187,-0.9715670943,0.5583679676,-1.2529093027,-0.0554292351,-1.1577489376,-0.8337481618,-0.9095815420,0.5952699184,0.4276467860,0.4741272628,-0.4778809249,-0.5791444778,2.0132668018,0.0643128380,-1.7063057423,0.2727234066,0.1687286496,0.6589840651,0.2412974089,0.3876089454,0.1535113156,-0.7328495979,0.6013470292,-0.8155531287,-1.5449550152,0.8408113718,0.0877092257,-0.5942927003,1.5020433664,0.5605551004,1.1409633160,1.9613232613,1.1202725172,-0.3546351194,2.1160829067,0.5874300599,-0.6321915388,-1.2108942270,0.1716439277,-0.2549261749,-1.2034045458,1.0263698101,0.9422594905,0.2088890970,-0.1047871783,-1.2705695629,-1.1836208105,-0.7867333889,1.7524260283,-0.7368371487,0.3624839783,-0.5364046097,-1.8370509148,0.1137978658,0.6024752259,-0.2508539855,-0.2528652251,1.6051051617,0.0342720747,1.5153194666,-1.0420209169,-0.4630776942,0.1474878788,-0.9713253379,0.0588521026,0.3362514973,0.2530673146,0.3107353151,0.1848080754,0.2764378190,-2.1524662971,2.7178449631,1.1053645611,0.8582649827,-0.1122928783,1.1051639318,-0.7339845896,0.0696830601,-0.2674444020,-0.2647155225,1.1227550507,0.2607275844,1.8020198345,-0.6892679930,-0.0933775827,-0.2251587808,-1.3664307594,0.3179258406,0.0487223379,0.4735718071,0.0241525117,0.8647046685,0.6103027463,-0.2139733285,-0.4484854937,1.4012920856,0.3160155714,-0.3197103739,1.7200762033,3.0469586849,-0.2641649544,-1.4224961996,-0.7580975294,-0.9873674512,0.1957168132,-0.4102197289,0.2144638300,-0.7272182703,-1.2818526030,-0.3538502753,0.5934340358,0.0904515535,-0.5685857534,-0.7609325647,0.4194073081,0.8674047589,-1.3904449940,0.0177442655,0.8740746379,-0.5924335122,-1.7502161264,-0.0792060792,-1.3580681086,1.1974959373,1.0274500847,-0.8471487761,1.3548214436,-1.0140715837,0.9863840938,-0.9353408813,-0.8694415092,0.3170388937,1.4484037161,0.6906737685,0.8037082553,-1.4583121538,-0.3531333804,-0.3408255875,1.5303416252,0.5340528488,0.6250340343,1.3767137527,-0.5115512609,2.1108081341,1.5340073109,-0.0016632290,0.0813266411,-1.1583846807,-0.7179369330,-0.7177065015,1.1551008224,1.6540576220,-0.4208811224,0.4496422112,-0.9338514805,-0.5616552830,0.6697068214,0.3913882077,-0.3269231319,0.2208180726,0.5489981771,-0.8624801040,0.0121480618,1.1665678024,0.1535249054,-0.1479054093,-1.0810278654,0.5306854844,-0.4219224155,-0.4571480155,-1.6084355116,0.9218780398,-0.2359026372,0.2739748061,0.2933753133,2.9100708961,-0.9172291756,1.7333257198,1.4234604836,-0.3695767522,1.8046455383,0.5196769238,-0.0223775655,-0.0609745122,0.4093607068,-1.4313142300,0.4745879769,-0.2658665776,0.1218895316,0.0092011830,0.6915896535,-1.2806612253,0.4025485814,1.1575285196,0.4067355394,0.9415536523,0.4428307414,-0.3000774086,-0.9426550865,-1.0320085287,0.7782731056,0.6642094254,0.8447062373,-0.7672371268,-1.0206696987,-0.1935468763,0.6972218752,-0.8549840450,0.0458985455,-0.0316515081,-0.9947295785,0.0599444099,-1.6356289387,1.4886174202,-1.1804332733,-0.5649894476,-0.3141291738,-0.5540065765,-0.0268782862,0.1907479763,0.3300601244,-0.0094888257,1.2847651243,0.7848905921,-1.8625837564,-1.5045292377,0.7757042050,-0.5151198506,3.4884924889,0.6410551071,-0.8507729769,0.2530885935,0.4635319412,1.5692179203,1.8518171310,-1.3878117800,0.6403602958,-1.1527994871,0.5967409611,0.1180173531,0.5744929910,0.2153960019,-0.4859421551,0.2957971692,0.4451091886,1.2154741287,0.3185328245,0.1403361112,0.0406874493,0.5657766461,-2.6195344925,-0.7967351079,-0.9214567542,-0.7220990062,1.1061993837,-1.4456450939,-0.2186345011,-2.0822770596,-1.3654150963,1.8305156231,-0.0043937741,-1.7268742323,-0.4598450661,2.7442691326,-0.7711686492,0.2119555622,0.6657399535,1.8725705147,0.8713087440,-0.0707813352,-0.2834530771,-0.1813057214,0.8837855458,1.0758835077,-0.0943579450,-0.2998608947,-1.2143330574,0.1564082950,-0.6589041352,-1.5153027773,-0.4579784274,1.2980852127,0.2589216232,-0.6551944017,0.5270182490,0.7990094423,0.5013885498,-0.5969684124,0.9251852036,0.1497516632,0.3835472763,0.2245106548,0.3399053216,0.9988560081,-0.2961629331,-1.2441223860,-1.0278291702,0.6651023030,-1.1447552443,-0.9833480716,-1.8347622156,0.7757753730,0.4770247340,-1.5743138790,-1.1904482841,-1.2004079819,0.4256134331,1.4869117737,-0.0860315859,-0.2575958669,-0.0120158978,0.4862571061,0.0525990017,0.4884842336,0.2983732820,-1.5491154194,-0.9905139804,0.6269329786,0.1086431965,-0.2456014603,-0.1656596661,-0.9914613366,-0.2911224961,0.3206650615,-2.0059871674,-1.4480019808,0.7958505154,-0.9722334743,0.0591765344,-0.6312087774,0.2814213037,-0.4718524516,-0.4777416587,-0.8816665411,0.5701669455,-0.8234921098,-1.6473771334,-0.2114145905,0.7337220311,1.7068860531,0.1092660576,0.5084820390,-1.0156943798,-0.6823235750,0.4121778905,-0.0907771587,0.0038814421,2.6090002060,1.1189103127,-1.9125928879,-0.3776756823,0.4361971617,0.0557256676,-0.0821820721,-0.7631011009,0.4519874156,-2.4382345676,0.1086765230,0.7393144965,-0.0481885150,-0.3635574579,-0.3686617911,-1.4666473866,1.1164562702,-0.9669422507,0.7040798068,1.2670004368,-1.7580957413,0.0831064582,1.8570041656,-0.5323807597,0.7726399899,-0.5263054371,-1.6371046305,1.4653873444,1.3102437258,-1.8714300394,0.7401259542,1.4640793800,-0.3641062081,0.5393807888,-0.4796035886,-1.0403650999,-0.4575759172,1.8171423674,1.2859230042,0.8897191882,1.0549505949,1.3600300550,-0.3504465818,-0.6137373447,1.4029437304,0.7413427234,1.4288338423,1.3940635920,1.4501439333,0.7185511589,0.4196183681,1.1800745726,-1.0972715616,1.0779728889,-0.3046537638,0.1432365626,-0.7692264318,0.4684534371,-0.4527581930,-0.0037421312,0.9633156061,-1.6476392746,-0.6606883407,0.7935672402,1.4174605608,1.2771332264,0.1160060540,0.8817456961,1.2700384855,0.5530409813,-1.2621611357,-0.3488104641,-0.0174375270,0.5478835106,-1.4185255766,0.0217602048,-1.1966099739,-0.6348711252,1.1889677048,0.0976005048,2.5740497112,-0.3773222566,-0.4613899291,-0.0986436456,0.0541701391,0.2876920104,-1.7548836470,0.9253419638,0.2831991613,1.9411002398,1.4710776806,-1.4093031883,-0.5841726661,0.6404128671,-0.8920534253,-1.5517531633,0.4828912020,-0.2645669878,1.1087429523,-0.2828297615,-0.0158070270,1.5413781404,-0.8813383579,-0.4438351989,1.0622408390,0.9529253244,0.6253203750,0.9075292945,0.9945212007,-1.6742419004,-1.6183062792,-0.2126778513,0.6402559280,-1.2418143749,1.5323899984,1.8869425058,-2.1036224365,-0.2886890471,-0.2596866786,-0.2835617661,-1.5854977369,0.6081105471,-0.1809121221,1.2577123642,0.2052631229,-0.8163881898,-1.1063590050,-0.0912579298,0.3450472057,-1.5712219477,0.8036522269,1.0187789202,0.4720780253,-1.2311170101,0.5175920725,-0.4290986657,-0.3666216731,0.6965180635,-0.1685263962,-1.5898982286,0.0220934488,-0.1997891963,-0.0530815497,0.8660960197,1.2025402784,-0.2280056924,-0.4191038013,0.9244895577,0.3037866652,-1.0225591660,-0.3245607018,-2.1816282272,-1.6213059425,-0.0621134415,0.5913257599,-0.1323050410,1.2850565910,-0.9554300308,0.2916534841,-0.1600199640,-0.0251585990,-0.8426494002,-0.2910325229,-0.0537761226,0.9424139857,0.6624855995,-0.5286464691,0.7076581120,-0.6090992689,1.5335679054,0.0755734891,-0.1748557091,-0.2534921765,-1.8603761196,1.1692599058,0.6042902470,0.9103702903,-0.1232990026,-0.4136359692,0.4350080490,-1.5793688297,0.6769706011,-0.4317162931,-1.4103405476,2.2864291668,0.0951946005,-1.4713804722,1.1892334223,1.1890237331,0.4429376125,-0.8387430310,0.0935311168,-0.7773849964,-1.8710905313,1.7024439573,-0.3445017934,-0.4553095698,0.7642885447,0.9821681976,-0.4583004117,0.0066860346,-2.2333476543,-0.1283345819,-0.5246235728,0.9105899334,-0.8629112840,-1.2106477022,-0.4193559587,0.0832006633,0.8583486080,-0.7869291306,1.7270901203,0.6822558641,-0.7230071425,-0.9777082205,-0.3344391882,-0.3701584637,-1.7645907402,-0.4649545252,1.0170435905,-0.0217694566,-0.9039642215,-1.6144140959,-0.7381874919,-0.6702867746,-1.3525016308,-0.4430875778,0.7287974358,-0.2385735363,-1.9752480984,2.0346944332,0.7689108253,-1.3528065681,0.6410573125,1.3192390203,0.3270509541,1.3804658651,0.2953875363,0.2034599483,-0.0645830110,-1.0361405611,0.5138510466,0.4093931317,-0.1102928594,0.0347731411,1.5495173931,0.4664959610,-0.3283931017,0.8254403472,-0.5107836723,-1.5615645647,-1.3665698767,0.3007652760,0.2336972654,-2.3706405163,-1.4505566359,0.3662475348,-2.1614456177,0.1082526296,0.0599631332,-0.4569309950,-0.0464944579,-0.8626391292,-0.5210534930,-1.3991318941,-1.0450747013,1.2357361317,0.7472088337,0.0294626709,-0.0323381051,0.8234859109,-0.6799733639,0.4621934593,-2.5489547253,-0.9245632291,-0.7865313292,0.6090202332,-0.3597594500,-1.5277130604,-0.7501274347,0.0724710599,0.3506417572,-0.0656960309,-0.4374740124,-0.4982353151,-0.1413731575,-0.6359506249,0.5705936551,-1.5379847288,2.0364022255,-0.4719463289,1.2827460766,-0.0661825612,0.2151302248,2.1430366039,-1.1678416729,-0.7821418643,-1.0774587393,0.0208406113,2.9643104076,-0.7014997602,-0.6581448317,0.8276968598,-1.2026946545,0.2845969498,-0.2574639916,-2.1206636429,0.2223912179,1.0973002911,0.5591518283,0.4466454387,0.2330162525,-0.7495750189,-0.0029619916,-0.4267501831,-1.6162149906,-2.1914863586,-0.6577326059,0.4989123344,-0.6556199193,-0.0895094723,-0.0112790493,0.0701447576,0.2679291070,1.5603930950,-0.9185328484,1.2158505917,0.6496582031,0.9756454825,1.3745002747,-0.8222441673,0.2244423032,0.1343432516,-0.3055539429,-0.9232123494,-0.1694074422,-1.1765798330,-1.1712293625,0.3721295893,-0.6939271688,-1.7612162828,-1.1052387953,-0.8033535480,-0.2181822509,-0.8658139706,0.2206589878,0.6181307435,0.5405413508,0.5935147405,-0.4217613637,0.4479676485,1.5241919756,-1.2515456676,0.3748424947,2.0765490532,0.3203200698,0.8813945651,0.8924462795,-0.1924320161,-1.5929996967,-2.3032474518,0.1078558564,0.6173242927,-0.8837097287,-1.4029815197,-0.5150201917,0.1820349246,0.8237689137,-1.0956190825,-0.6264654398,2.0228900909,0.5752149820,0.0658197179,1.3183259964,-0.6357634664,0.8268523812,-0.3430708945,-0.0185604282,-0.7815250754,-1.1980940104,-2.0872871876,0.4336906970,-0.4385131896,-0.5323140025,-0.3113310635,-0.3358350396,-0.8802808523,-0.1359132677,-1.0820661783,0.6475699544,-0.2714052200,0.3617736399,-0.2199012190,-0.2596733272,-0.9010024071,0.7449892759,0.4877879322,-0.9734915495,-1.0764521360,0.6607186198,1.9671131372,-1.5323868990,-1.6164841652,-1.3796384335,0.9423570633,-0.2951205373,1.3519340754,-0.2381277531,-1.0184181929,-0.8733766675,0.4789345264,-0.8836178780,1.3279944658,-0.9801152349,-0.1271719635,0.2661816180,-0.9542296529,1.6332507133,-2.5235753059,1.0538122654,-0.7360922098,-0.3780718446,1.5566005707,0.2872518003,0.8437467813,0.3021098971,-0.5063041449,-0.5947359204,-1.4161554575,0.5075585842,1.0832319260,-1.0159112215,-0.7424957156,0.4478953183,0.6075967550,1.0550105572,-0.1584615558,-0.7829976082,-0.7657365203,-0.1861712188,0.2837609649,-0.3579142988,-0.1085585579,-0.2172659487,-0.5554970503,1.2288670540,1.9843388796,-0.7815829515,1.4802480936,-0.8235428929,0.8025032878,2.2790677547,0.9906148911,-0.6867852211,-0.7537479401,0.1955792606,0.0749062449,1.9827543497,0.9090567827,0.9319398403,-0.7689310312,0.2998859584,0.0846697241,-0.3599868119,-1.5779273510,-0.6001316905,0.7877557874,0.0443977341,-0.5797268748,0.2533348501,-0.2036195248,-1.3632600307,0.8793420196,-0.4388233125,-0.7233103514,0.5692442060,0.4922772646,-0.1630162150,0.3571025729,0.1961718649,0.2645778954,-0.7818415165,0.7580390573,-0.0369912013,-0.7612245083,-1.0428425074,-1.6256395578,1.5037935972,-0.1167479455,-2.5956823826,-0.7661041617,0.3693991005,0.4504629374,0.3117121756,-0.5613887310,-1.1832345724,1.2855526209,-0.6030053496,-0.6560151577,0.1852611452,-0.5990884304,2.4433631897,0.0511516444,0.4812693000,-0.0832996145,0.2482223809,-1.9432893991,-1.6592720747,-0.4858410358,0.5000698566,0.1994387358,-0.1384883970,-0.9286952019,1.1757085323,1.1086024046,-0.8868203759,-1.0367414951,-0.1277745217,-0.8232452273,0.4371286631,-0.1243734136,-0.3757143617,0.1735518128,1.7695791721,0.0277947448,-1.3792670965,0.3176753223,1.3203235865,-0.3832557797,-1.4734238386,-0.2980696857,-1.0584447384,-0.5828962922,0.5312491655,0.3283676207,0.9943018556,-0.7106354237,-0.9073405862,-0.5333749056,-1.0341758728,0.1330567151,-1.0525498390,-0.2770160139,-0.2599232197,1.0627063513,-0.0400909074,0.4328006506,1.7536995411,1.3945586681,1.4096744061,0.2681570947,-1.3833025694,0.3761285543,1.2858004570,0.6580190659,-0.1391668916,-2.1075122356,-0.6969650984,-0.4540668726,0.2670806050,-0.2743560374,-0.0209443346,-0.7997515202,-1.1989635229,0.0803686678,0.7327975631,-1.4023789167,0.1931434423,0.9743856788,0.8532840014,1.1824666262,-0.7256034613,1.2055327892,0.5179441571,0.4593677819,-1.0894452333,0.9806094766,-0.2745089829,-1.4509284496,-0.4190232158,0.7034731507,0.5885317326,-0.8590492606,-0.1408797503,-0.1429534405,-0.1686502695,1.5083961487,0.0664177239,1.6594139338,1.6427066326,-0.3360191584,1.2271697521,-0.6477968693,-1.8092172146,-0.9437155128,0.2422796041,0.9709712267,1.1938385963,-0.2580324411,0.2235572189,-0.0080338093,-1.0137414932,-1.0294257402,-1.2949119806,0.4745123088,2.0134837627,-0.3586051464,-0.7135395408,-1.3953684568,0.3262714148,-0.9641054869,1.4204113483,-1.4024853706,2.1189253330,-0.5846406817,-1.1655416489,-0.8957322836,-1.1574605703,-0.1748732775,-0.4009687603,1.1054528952,1.9881278276,1.3893102407,-0.7504013181,0.7380410433,0.2013456821,-0.4352020621,-0.1771009415,1.5475465059,-1.0222883224,0.6397832632,0.8793185949,-1.1897361279,2.3307409286,-0.0984229222,-1.2100880146,-0.3881158829,-0.5199695230,0.4241195917,-0.0116548957,-1.4528745413,0.6298332810,-0.6663973927,-0.4127940536,1.3213293552,2.1988401413,-0.1545394957,0.6720430255,-1.5908136368,1.1947685480,0.6126347780,0.2747550309,-0.6444818377,-0.3922859728,-0.2779766321,-0.5158533454,1.0888648033,-0.4051799178,0.0381805673,1.0520000458,0.4421851337,0.7295815349,0.2826419771,0.3008019626,1.0624518394,0.0210728142,1.0455101728,0.0507967658,1.4170062542,0.6779723763,0.1280576140,1.0865745544,1.4637603760,0.8787689209,-0.3339741528,-0.9834817648,1.2178926468,0.2774706781,-0.3207702339,2.3072702885,-2.0267996788,-1.0228863955,0.2627939582,-0.6198943853,0.2880648971,0.1017346680,0.0353729799,-0.5069180727,-1.6419990063,-0.7368588448,-1.0442868471,1.7887995243,-0.0079993038,0.1718894988,-0.6887407899,-0.3678089082,-1.5573518276,-0.4891292155,-1.2914336920,-0.5052575469,-0.6315882206,-0.9011530280,0.1310378164,1.2318689823,-0.7219327688,0.8740233779,2.0904352665,0.2487895340,-1.0377489328,-0.4964048266,0.8279573917,-0.3556987345,-0.4572505951,1.0447623730,-0.7082029581,-0.1460758001,-1.6420407295,-0.5102956891,-0.6610686183,0.6488505006,-1.1323249340,-0.3774205446,0.6173532009,-0.2405151129,-0.0985287949,-1.2055841684,-0.2576752603,-0.3729512990,-0.9217440486,-1.7550470829,0.4352207780,-0.4867249429,0.5257884264,0.6555952430,-0.1585087776,-0.3430123627,-1.8562735319,-0.3113770783,0.5841275454,0.5621509552,-0.3464486003,-0.5415142775,0.0917498544,0.2995837927,0.3927473724,-2.8245084286,-0.3212784827,-0.3785587549,-0.7113556266,-0.6022580266,-2.6119797230,-0.0254186876,1.0269163847,-0.5338106155,-1.4207351208,0.8609966040,0.9684557319,-1.1536953449,-0.1923975646,0.7043721676,0.8859874606,0.4263644814,0.8193140626,-0.1051984951,0.1981133819,0.6787722111,0.4743790627,0.4614576697,0.4642948210,-0.9053800106,0.2947457731,-1.3450095654,0.4394025803,0.4799166918,0.4150917530,-2.1966297626,-0.0429796278,1.6986823082,-0.5377891064,-0.6587689519,-0.8812151551,-0.5194984078,0.0733721107,0.5582324266,0.3964279592,0.2120293975,0.3054826260,-0.2871125340,0.7834923267,0.3903766870,-0.0846089721,-0.1705707610,1.2015510798,-0.6100164652,0.5426404476,0.0102491574,-1.3187043667,-0.3852408826,0.4882010818,-0.6264355183,0.6432433724,2.6491410732,-0.7734444737,-2.0508220196,0.3473735750,0.4667849839,-1.8796936274,-2.5656268597,0.2532318532,1.7867356539,1.5840818882,-0.9908537865,-0.1217880398,0.1486516148,0.5512774587,-0.2852463126,-0.7899572849,-0.3199961782,0.0614964701,0.0901733115,-0.3096054196,-0.1612850279,1.2000919580,1.2057310343,0.1887879372,0.4619420469,2.2673599720,-0.0099240970,-1.8448913097,-0.8179546595,-0.8862370849,0.2955748141,-0.1304718554,0.9787134528,0.8472347856,-0.1288524419,0.5706324577,1.2143545151,-0.5389542580,0.1138983741,0.7284115553,2.3312344551,1.2056900263,-0.9562098980,2.7902858257,0.1274458468,-0.5790623426,0.5577117205,0.6300501823,-0.1559722424,0.5293494463,1.9820027351,-1.3815310001,1.7998952866,0.7246081233,-0.1543004215,0.6131431460,-0.6942011118,-0.3525010645,-0.5144149065,-1.2278832197,1.4018414021,1.7004867792,0.6758140326,-1.8631590605,-0.0994367823,-1.4539935589,-0.8443304300,0.0253531449,0.1577637196,-0.8598079681,-0.1473255455,0.8919650316,-0.7243660092,-0.1229981408,-1.6209475994,-1.6732126474,-0.8255846500,1.2784086466,-0.3470903039,-0.1857288927,0.4499431551,0.5625912547,1.1732017994,0.1230131313,-1.8694161177,1.3007078171,-0.3756277859,-0.2890734673,0.0999187604,0.0808265805,1.2099618912,1.0885607004,2.2550585270,0.8889443874,0.7035228610,0.8246964216,-0.6405169368,-0.3325651288,0.0771268159,-0.6547657251,-0.8956646323,1.3768603802,-1.4912687540,-0.2551057935,-0.9616905451,0.4821599722,-0.1796675920,0.2831281424,-0.1340553463,1.0645695925,-0.6067219973,0.8581216931,-0.8533557057,0.1947769821,-1.3405125141,-0.0545026809,-0.0804695264,1.3081027269,-0.3672732115,-0.9950604439,-0.1673544943,-0.6271149516,1.0561723709,-0.8029696941,0.1047154367,-0.6536308527,0.4128457010,-0.3468890786,0.2208393216,-0.3895644844,-1.8310519457,-0.2431140691,0.1881937236,-0.7013317347,0.0772262961,0.3569529653,-0.5789977908,0.8872517347,-0.5732261539,0.4532896876,1.1999888420,1.3070069551,0.5669031739,0.6928222179,0.1783494949,-0.8095983267,-1.6969149113,-0.2449482530,0.8840457797,-0.4317087829,0.2946268618,-0.7384603024,0.8370640278,0.2964679301,0.6661210060,-0.0482210517,0.2334891409,0.2837832868,0.5236741304,-0.4918816090,-1.4834574461,1.5049879551,0.3132415712,-0.0655054599,0.2337341458,0.5793153048,0.4204308987,0.1527949274,-0.5522327423,-0.3710898757,-1.4416307211,0.3492567837,1.9169337749,-1.1547886133,0.1601953954,1.6751732826,-0.0111167338,0.3223155439,0.7473372221,-0.8906780481,-0.5188031793,-0.2556838393,0.7918527722,-0.1100981310,0.1180559546,0.8671013117,0.9141765833,-0.2264145017,0.9463275671,1.2277970314,-0.2910000980,0.3737040758,0.0451757126,0.0928840712,0.1828407347,-0.7114292979,-0.7026841640,-1.1814341545,-0.4881572127,0.0155485887,-2.7573442459,-0.6148686409,0.0310324896,-0.7967752814,1.1301997900,0.8300131559,0.2524907291,-1.0185047388,0.6041662097,-0.6465168595,-1.6469916105,-1.1552380323,-0.2510072887,1.3071713448,0.2094026506,-0.8110154867,1.0590174198,2.1924555302,-1.1202188730,-0.8820242882,-0.2305018008,0.4774096608,0.4056183100,0.3316685855,0.7246740460,-0.2441137731,-1.1167860031,-1.3302159309,2.1725409031,0.8256790638,0.8306998014,0.0433921330,-2.6837403774,0.1183398664,-1.5742039680,1.3130691051,0.5735969543,1.3894512653,-0.2349755168,-1.4868464470,-1.5704554319,1.2836638689,-1.4032113552,0.0997329354,-0.3284315169,-0.7569980025,0.4101175666,0.2967536747,0.0999957025,-1.7917844057,0.1166789830,0.9223045111,-0.5208253860,0.3779269159,0.3759181201,-0.9334786534,-0.4578769207,0.3737753034,-1.1865646839,1.4694766998,2.1069328785,1.4723044634,0.8738681078,0.8008302450,-0.6091771126,0.6025853157,-1.7750355005,2.5449066162,1.9469372034,-0.0892248526,-0.7289734483,1.7631760836,0.3075451553,-1.0003085136,-0.4178240597,0.8397405148,-1.3949640989,1.2439329624,-1.2816982269,0.5767304897,1.1978013515,-0.0095124440,1.4640440941,0.9479848742,0.4466987848,-0.4483757317,-0.1509431601,1.0327948332,-0.4387851655,-0.7053198814,-1.7758510113,2.3635933399,-1.2871538401,1.2330980301,-0.0103951599,-2.0432476997,1.1372212172,-0.2039745152,1.1895712614,2.1988720894,0.4431562126,-0.6325745583,0.7957141995,1.5974450111,0.2394031286,-0.7119681835,-0.5758239031,0.2845700085,1.1215269566,0.3454354703,-1.1157178879,0.7630261183,-1.0396157503,-1.2194751501,0.4127437174,0.8683571219,-1.4072741270,-1.0504204035,1.4434605837,1.7263585329,1.0688557625,-0.6204966307,0.2786242962,0.0499957725,1.7350540161,1.0227462053,0.0887895748,-0.1811278611,0.0582000278,-0.4657486677,-1.7719552517,0.8368805051,-1.1324976683,0.3575865328,0.5382347107,-0.8788229227,0.5577881932,-1.4245994091,-1.3215843439,1.1583495140,0.6064372659,1.8785479069,1.2669287920,-1.6431622505,1.4687012434,0.1747233868,-0.7408152819,-1.7918393612,0.0706328824,2.3624007702,1.3255273104,-0.8967608809,-1.8747004271,0.0701705366,-1.8117138147,-1.1072317362,0.4218684733,0.9634417892,0.2764050663,-1.0511800051,1.2283619642,0.5277022719,0.9080645442,0.8044661283,0.7120621204,1.1845030785,0.6737482548,0.2570166290,1.1729450226,0.9283907413,-0.2583913505,0.2896552980,0.4090211391,-1.5187941790,-0.1357347518,-0.4136520922,-0.9496188164,-0.7845684290,-0.6877620220,1.4111977816,0.7903782129,0.2329047620,2.4450430870,-1.2297238111,-0.3623290360,-0.1056897566,1.4517501593,0.0444726944,-1.6526907682,0.1572376639,0.8969747424,-0.4539208114,0.3395579457,-0.7769137025,-1.1884061098,1.7207614183,-0.2107622027,-0.3655122817,0.7336954474,3.9021322727,-0.1486244053,0.0116885044,-1.4245262146,-0.8629705906,-1.4355378151,1.3567553759,-1.2594320774,1.1831315756,-1.1354767084,2.2162899971,1.4533467293,-0.6889243126,0.6834006310,0.1057725549,-0.8852538466,0.1678477079,-1.3591594696,0.5192753077,0.3029523492,0.7172673941,0.9541074038,-1.1572390795,-0.2347368300,-1.7002626657,0.2449831665,-1.1469874382,0.8641168475,1.4774310589,-0.0520692803,-1.3869181871,-0.2344624996,0.1029674485,0.8140225410,-1.2963079214,1.6603183746,0.0933022127,-1.0267788172,0.7393246293,1.4649448395,0.3346224725,-0.4709796906,0.3763844967,-0.2554529607,1.2848366499,-0.1008833647,-1.4221745729,1.3263037205,-1.5512310266,-0.0674574524,0.1974201351,1.9573367834,-0.5765719414,2.5311250687,0.0921669155,0.5961879492,-0.5765373111,1.1144328117,1.0982080698,-2.1409747601,1.4250926971,0.9062033296,-0.4229671955,-1.7703527212,-1.4376366138,-1.2039889097,0.4187853932,-0.9995331168,0.0991715044,0.5590418577,-0.3176335394,-0.7645334005,0.1076866239,-0.2528138459,-0.5841336250,-0.4563258290,0.6959413290,-0.3995080888,-0.2161872089,-2.4993913174,0.1716826558,1.9722093344,-0.1077965498,-0.2359120846,-0.6924694180,0.3745718896,-0.6471085548,1.1404736042,1.0013725758,0.0168315694,1.0300970078,1.0599291325,0.0489125997,-0.7580710649,-1.4751648903,0.6038507819,0.0657226518,-0.1146567091,-1.2612990141,-0.1839995682,1.0401122570,-0.4304883778,0.1605222672,0.3470155001,-0.2415146828,0.6425074339,-1.8182214499,0.5159596205,0.1558146328,0.0451287888,-0.0311791990,1.4505674839,-0.9712655544,0.7230480909,-0.5097474456,0.1868300736,-0.7318282127,-0.4006540775,0.0385716334,-1.0778014660,0.9501018524,0.2879245579,1.0167944431,-0.4306978285,0.3810772598,2.1066005230,-1.9030117989,1.2764573097,1.3993682861,-1.0606230497,-1.3270933628,0.8174833655,-0.8962209225,2.0776956081,-0.2050100565,0.9393951297,1.3354527950,0.9743983150,-0.3406037092,-0.5477521420,2.6748812199,0.4349660575,2.3099956512,0.7869509459,-1.4177607298,0.9141976237,0.6136193871,0.6456041932,-0.6823461056,-0.4874903858,-0.1170524731,1.9651896954,0.0810671002,-2.3023612499,1.1835066080,0.8766115904,-0.9631479383,-2.1853756905,-1.2428277731,0.0720189661,-0.4796108902,-0.1266144216,-0.9395406246,0.8748876452,0.4869423807,1.9948581457,-0.6947699189,0.2270700186,-0.3317213953,0.6422330141,-0.4053525925,0.6357408166,0.1552224904,0.1389403045,0.9798236489,1.6588976383,0.6248997450,1.3167870045,0.1932007372,-0.8761605620,-0.5672311187,-0.2326073647,0.3890257478,0.2928788364,-1.3203250170,-0.9401980042,0.3664203882,-0.5633349419,1.0236297846,-0.0916399956,-1.0432430506,-0.7348905802,-1.4612178802,0.0253731403,-0.0812676325,-2.3844251633,2.1396183968,-0.3534555733,-0.5941804051,-1.4541046619,0.3458630145,-2.0107643604,-0.4030187726,-0.5923594832,0.2931079268,-1.4421180487,-0.9520923495,-0.9846225381,-1.5098954439,-0.7086515427,-0.0347315706,0.2972258031,1.1616653204,0.1510649323,-0.5060365200,0.0093106842,-0.0073053623,1.0132656097,-0.3046438992,-1.3726711273,0.0134564815,0.8839237094,0.9101039767,-1.4731736183,0.2599923015,-2.1118168831,0.9287536740,-0.9762788415,0.2646948993,-0.3983414769,0.8249574900,1.6295404434,1.0062322617,0.1468868256,1.0601128340,-0.1219236851,1.4774035215,-0.1063908115,0.3392222524,0.2582385242,-0.8551683426,1.0945085287,-1.0423394442,-0.4286342561,-0.9640535116,2.5036330223,-0.0431590155,0.9850620627,-1.0826802254,-0.0051798890,-0.8156575561,-1.6702399254,0.6556189060,-0.6202479601,0.8388648629,1.3374948502,1.1133385897,-0.6639132500,0.8211407065,0.7570949197,0.6676589847,-0.1204034463,0.2454028726,0.6149377823,1.1963888407,-0.5744004846,-0.7452492714,0.1945770830,-0.9737981558,-1.4163233042,-0.4329152703,0.0736613274,1.3573538065,-0.1728477329,0.2341295928,-0.1851958036,0.8775706291,0.1613099128,1.1886209249,0.9928414226,0.5726636648,-1.0495097637,-0.7697876692,-0.0529748313,-1.2455561161,0.8108440042,-0.8752728701,0.4357014596,-1.5372251272,-0.7729937434,0.2567974627,0.4485482275,1.8845136166,0.2564440370,0.1844030470,1.7274739742,-2.3057599068,0.7775979042,0.5623003840,0.2061211616,-0.5265920162,-0.3165593147,-0.7587300539,0.5017391443,-0.0206113029,-0.5766850710,0.9890679717,-0.6054541469,-0.4035939872,-0.5519093871,0.3898775876,-0.8180458546,0.8589459658,-0.4786759317,1.0392462015,0.2402326465,-0.3096106946,0.2151809037,-0.6961288452,-0.4223067760,1.2795596123,-0.2458327711,0.1790923178,-0.7446967363,1.5123780966,1.8332709074,-0.1309396625,-0.5887723565,-0.1028404683,-0.8091694713,1.5737030506,0.0129924612,1.7106083632,0.3016880155,1.5860959291,-0.7288613915,-1.2153372765,-0.2323260754,-1.5699255466,0.4336345196,-1.5333116055,0.0587876514,0.6924380064,0.9327794909,-0.1513533443,1.1799548864,-2.2671871185,0.1525774598,0.8967125416,0.6222859025,-0.2084840834,-0.1403931379,0.1346957684,-2.0565283298,0.4950318336,-0.4319967330,0.9162702560,2.7992014885,1.5372692347,0.8877406716,1.0195660591,-0.4253476262,0.5052951574,-0.8647077680,0.2749290466,0.1537522674,0.5428519249,-0.6285081506,-0.4747620225,1.7780978680,0.5352087021,-1.5661109686,-0.5283264518,0.0906709209,2.0831224918,0.7579495907,0.5779919028,-0.2779310644,0.1220835596,0.6336193681,-1.0817463398,-1.1549593210,-1.4704773426,-1.1104469299,0.3906410336,2.1418421268,-0.4694980979,1.9122390747,1.2186927795,0.2590028644,-0.0949972644,0.5684119463,-0.9523119330,-0.1190907806,-0.6136029363,-0.0960134193,0.6986835003,-0.9704755545,-0.6268044114,-0.5610452294,0.6267525554,-0.4279605448,-0.3012984395,0.0593986809,0.9925241470,1.3790812492,1.0318965912,1.0415772200,0.2689839602,0.3476128876,1.5841513872,-1.3008955717,-0.6530005336,0.2141337395,0.9915444255,-0.1424658149,1.3862416744,-0.9926421642,1.7042853832,-0.8251213431,-1.5188190937,0.4262528419,-0.4792524576,-0.9867950678,1.0061618090,0.5120648146,0.5273358226,-1.1984391212,0.7163698673,0.6981152892,0.1147046685,-1.1462678909,-0.7785617113,0.9478487372,1.5295920372,1.4200506210,0.3724110425,-0.5420010090,-0.4563983381,0.6563023329,-0.4331812859,0.0931108072,-0.1951667070,-0.3696748018,-0.5538032055,-0.6306383014,0.8567004204,-0.2205395103,-0.8111694455,-0.8887060285,1.2530621290,-0.3134068251,2.2097487450,-0.7303216457,-0.8344842196,-0.4096687436,-2.4196662903,-0.0106813936,0.4485253394,1.8782069683,-1.8911976814,-0.1464397758,-1.3518520594,0.7725373507,0.0136093041,-0.6495004296,-0.5794745684,-1.0514913797,-0.2449943721,0.5634900331,2.0310289860,-0.7452318072,-1.1391593218,0.1187069863,0.6543679833,-0.0734154284,-1.2560356855,0.7408869863,-0.4925400317,-1.0945181847,0.0686069354,0.3952773809,-0.1935277283,0.4949653149,2.5847566128,-0.6973088980,-0.1285281926,1.4140560627,-1.1363401413,-1.0524957180,-0.5918847322,-1.4523485899,-1.9308159351,0.0701744705,-1.3957195282,1.1885744333,1.2093832493,0.2166377157,-0.3030340970,0.0597176440,-0.5784593821,-0.1520032585,0.0584271438,-0.8972605467,0.6736978889,0.6967254877,0.4667727053,0.0286635868,0.2837365568,0.4581332207,0.3056941926,-0.0116381422,0.9084653854,-1.3365603685,2.8502945900,1.0096521378,-0.8975444436,-0.3106841445,-0.1088178307,-0.8972753286,0.9920865297,-0.0723804459,0.5263554454,-1.0233750343,1.2341985703,-0.3395036757,-0.0130303865,-1.0015542507,-0.3587833345,-0.5115778446,-0.9865487814,-0.1158994958,0.8093836904,1.4579401016,0.3082989156,0.2266820669,0.9964211583,0.0073694857,-2.0784134865,-1.7294149399,-0.4265480638,0.4939056933,0.7890198231,-0.4054355621,-0.5412698984,2.1344156265,0.7287756205,-1.2158207893,-1.0318105221,0.6429752111,2.7805309296,1.1857364178,-1.5435954332,-0.1381753832,-0.2538266480,1.1751824617,0.0941778049,-0.4272075593,-0.4489406049,-1.2893304825,0.3536476791,-2.1066591740,-2.2367551327,-0.5366755128,-0.5199564695,-1.3183445930,0.8450385332,1.8122462034,-0.1849884093,-0.5415422916,2.2770223618,1.5768443346,-1.4913719893,0.6609851718,0.9181861281,-1.9391117096,-1.4061818123,0.2801476419,-0.3844480813,-1.1504819393,0.3682684898,-0.6189881563,1.1590030193,2.6743111610,0.4546943903,0.2690356374,-0.1853425950,-0.2681950033,1.4984539747,0.0044779256,-0.3983008564,0.1030340418,-0.0268113017,0.1630320698,-0.4327528477,-0.7730445266,-1.0588603020,1.5333759785,1.5113227367,-0.3076021969,0.1370654255,0.0941180363,0.8745601773,1.1456735134,0.4186946154,0.3277677894,1.2020785809,-1.2507486343,-0.4188847244,0.6161471605,0.3914790452,-0.9654144645,0.2758603990,-0.0457552262,0.6747549772,0.9733185768,-0.6183296442,0.0650520474,0.7692757845,0.5387182832,-0.8589666486,-1.7312017679,0.0673047602,-0.0327091403,-0.1677000821,0.6749193072,-0.8480613828,-0.4110155404,0.1744018346,1.9193584919,0.2909437716,0.2042945921,1.2015007734,-0.1746187657,2.0067448616,2.2541844845,-0.9878281951,-1.7081015110,1.0036889315,0.8530163169,-0.0468556173,0.9961929917,-0.9784662127,0.4863100350,-1.1680382490,-2.0089857578,1.6244140863,0.0916079283,-0.3821515739,2.1537449360,0.3477901518,0.4862693548,-1.6556663513,-0.9747734666,-0.6179747581,-1.8434002399,0.2441639751,1.2477802038,1.0027505159,0.7601565719,0.4941864014,-0.8031545877,-0.1345568299,1.3695721626,-0.6639223099,0.3247958720,0.0043942472,0.1913578659,0.0745675713,-0.6932394505,0.0181727502,-2.3302776814,-0.7034760118,-0.3380787969,-0.1769035012,0.7856540680,0.1328079104,-0.3098344803,-0.9356276393,-0.0556659177,0.2006022036,3.4013428688,-0.1138542965,-0.7904957533,-2.3656320572,-1.6644995213,-0.0752599388,1.2415909767,0.4848107994,-0.2712499797,1.0699157715,0.6268231869,0.6100659966,1.6827350855,0.2057249993,0.4664883018,-0.8904610872,-0.6790813208,0.4590415955,-0.0912852958,1.3914935589,-0.7131012678,0.2295179665,-1.3685091734,0.4473334253,-1.7683360577,-0.5036785007,1.3914653063,0.5441012383,-0.5553440452,-1.2935613394,0.8311233521,-0.6089043617,-0.1083713174,-1.0062488317,1.0542385578,-1.4220438004,1.4223126173,-0.5420668721,0.7962802052,-0.4968725145,0.7224124670,-0.9014311433,-0.0173226800,-1.8692378998,0.7442633510,1.1637054682,-0.9639398456,-0.1304800659,-1.3041782379,0.1481969059,0.1446544379,-0.3365060687,-0.5480625033,-0.5852605700,-0.5312329531,0.2836891413,0.4132503867,0.4652761221,-0.3472861648,0.1682231873,2.2558338642,-1.2319662571,0.5227214694,-0.4734502733,1.7072815895,-0.3913713694,-1.9416004419,0.1609739214,1.0534284115,0.6118378043,-0.8480007648,-0.6930434704,2.4445428848,0.3759610951,0.0456087664,0.3976513147,0.1482326239,0.0915998146,-0.1041516364,-1.3221958876,-0.8823789954,-0.9341890812,1.6293078661,-0.2838116288,0.0902046338,-1.2891747952,0.9338698983,0.0727711618,-1.2760754824,0.3651596606,-0.1811099648,1.4663398266,-1.3555800915,0.5154141188,-0.6398217082,-0.9735441804,0.9723172188,-1.4711934328,1.0343658924,1.1213243008,-0.2257323861,-1.5045515299,1.3349263668,-0.2323711216,-0.1518178135,-1.8108577728,1.8254790306,1.2762485743,-1.0044380426,-0.8060824275,-1.1536781788,-0.0594115667,-1.5260562897,0.6320920587,0.5781828165,1.8738344908,-1.7082090378,-1.2055032253,-1.6750184298,0.9773060679,1.7373665571,2.0059866905,2.3705921173,-0.9223784804,-0.6740148664,-1.4445827007,0.5108569860,0.4014914334,1.7079445124,-0.9667310119,-0.0251678526,1.2655253410,0.5475633144,-1.3689777851,0.9426730871,-1.2328010798,0.9257682562,-0.2959577143,-0.6005290151,0.5494224429,2.0729205608,-0.6353592277,0.3192138970,0.6131855845,0.1523712426,0.0587622598,0.2394811511,1.7130912542,1.2879834175,1.1557379961,-0.3637089729,-0.2145810127,0.9560777545,-0.0508564450,-0.1313996017,0.7307595611,0.5367805362,1.8643679619,-0.9024128914,-0.2627148032,2.0112290382,-0.5909074545,1.4932234287,-1.0802291632,0.6225048304,1.3895535469,-1.4506711960,-1.3074595928,0.2020994872,0.3432753086,0.2278840840,0.6360409260,-1.0779962540,-1.0535291433,1.5352840424,-0.2123942673,1.2253196239,-0.8935346603,-0.9941996932,0.3262534142,-1.1904532909,-1.7328804731,-0.2980934978,0.1107948944,0.5599442720,-0.4482952654,1.2198443413,1.1387603283,-0.1491803825,0.1041010097,0.4254328609,0.3654618561,0.9308492541,-0.3119447827,-1.3580926657,1.0101203918,-1.5451142788,0.2026536763,0.3477017283,2.3403952122,-0.0724377260,-0.1430427432,0.3848078549,-0.1609339267,-1.2239019871,0.0277106408,1.5609391928,-1.3043521643,-1.1645221710,-0.2278364003,0.7276721001,-0.1473096013,0.2433789521,-0.9658976197,-0.2630626559,-1.3427623510,-0.3987060785,0.6780408621,0.3158074319,-1.4230879545,-0.2691633701,-1.5128043890,-1.4413479567,0.0664281994,0.2924026251,-0.0307732169,-0.0908246115,-0.6818583608,-0.3328570724,-0.8593428731,-0.4004930854,1.3459855318,1.1941367388,-0.5967947245,-0.0030466982,0.7044922113,0.5484733582,0.1524624825,0.1162964776,-1.1390522718,1.6581176519,0.0612685196,-1.6157741547,-1.9226813316,0.7732533216,-1.3893855810,-0.9835121036,-0.4904064536,-0.7418014407,2.0079159737,-0.5394204259,-0.4050091803,-0.8270653486,-0.3081693947,0.2111128122,-0.2667162418,0.2949900031,0.1134409904,-1.0153115988,0.0493623950,0.2900373936,0.7097696662,0.7082123160,0.3717222214,0.2401635796,0.0780070871,-0.9557723403,-0.1404657364,0.0148379868,-1.7255346775,-0.7337841392,-0.8126275539,-0.2047343999,-0.6537588239,-0.1437726617,-0.3824236989,-1.8198882341,-0.3698104620,0.7416635752,0.7381506562,0.3432342708,-0.6773697734,-0.5082986951,0.0642926022,-0.0629437044,1.2554669380,-0.1163146794,0.5489455462,0.6377999783,0.4149386287,-0.7792364359,2.1353731155,-0.5781716108,-0.8798395991,-0.9598072171,0.9588785768,-2.1271765232,0.6209558249,0.1527183652,0.3872463405,-0.5138054490,-0.0146184405,-0.2630323172,-0.9618073702,-0.3712114990,-0.8843356967,1.9723078012,-0.4195107520,-1.6190768480,-2.0020143986,1.8401244879,0.2102288306,0.0879932866,0.0495191440,-1.1159087420,-1.1406750679,0.5224584341,-0.2365093976,0.3528335094,0.5825575590,-0.0848055333,-0.1709183455,0.3926368952,0.7267042994,0.9824547172,2.0305740833,-0.3654267192,-1.7048155069,1.1908239126,0.5972874165,1.1509351730,2.3433780670,0.5069172382,-0.3373184502,-1.2413910627,-2.4824178219,-0.7841681838,-0.2749174833,1.4181344509,-1.1041259766,-1.2695769072,0.4413174987,1.4447129965,3.0843203068,1.1354111433,0.9596952200,0.0692582726,-1.8266723156,-0.1291946471,1.1994426250,0.1244117692,0.5631824732,2.2121365070,0.4624514878,-0.7957055569,-0.0160569772,0.1778953522,-1.3429569006,-0.0165645760,-2.1498680115,0.4199761152,-0.3032145500,-1.1267306805,1.4630862474,-0.0667405128,-0.1823576540,0.8276292682,0.2431415319,-0.0560194775,1.2737932205,-0.1540903896,0.5906959772,0.8791603446,-0.3834092021,0.0394203626,-0.5252980590,-0.2408296615,0.7998421788,-0.6245598793,0.8748078346,0.6978314519,1.8217324018,1.1725424528,-0.5058450103,-1.1825522184,-0.1523513198,-0.9517591596,0.3418970406,0.8446737528,-1.1665372849,0.3165706992,0.9696199298,-1.2162469625,-0.5531826019,-0.3029631674,-0.1280330271,-0.2350587249,-0.9241914153,-0.0322184227,0.0353361554,-0.5270760655,-0.2926283181,-1.0359057188,-0.5217298865,-0.0545432195,0.9752314091,0.4386629462,-0.1634233445,0.3504447937,-1.6003768444,1.5135135651,0.6002835631,0.8065099120,-2.4900567532,0.8633902073,-0.6167137623,-0.3883438408,-1.3907675743,1.3066443205,-0.7658559680,-0.5670421124,1.6960184574,1.9653801918,0.6198975444,-0.7111523747,1.6282720566,0.4226017296,0.2790413797,-0.9668534398,1.1160160303,0.6634340882,-0.2094600797,-0.4581094086,-1.0761604309,1.4729379416,-0.6079205275,0.6071959138,0.3631769419,0.0164318662,-1.3065373898,0.6455099583,0.1708582193,0.0014818548,-1.8358229399,0.8673004508,1.3817694187,0.7489470243,0.1228798330,0.7249348164,-0.2352134287,0.4495169818,-0.9030604362,1.0610578060,0.8425629735,0.6626394391,0.7027125955,-0.8264446855,0.4003860652,0.1967862993,-0.5250782371,-0.0714196265,-0.6816290617,-2.0005903244,-0.1332174838,-0.9352809191,-0.0467789285,-0.3418357372,-0.5217453837,1.4358524084,-2.8482091427,-0.1477034539,-1.8174880743,-1.4565387964,0.5249419212,-1.3412015438,1.0536248684,0.6991011500,0.9847779870,0.0895238072,-0.2042881399,-0.1511867195,-0.1911108941,-0.8483758569,-1.1394416094,-0.6263279319,0.3262504339,-0.4187115729,-0.9000268579,-0.5546446443,-0.8508963585,-0.4535124004,0.0920558199,0.0759566426,0.2565580606,-1.8011915684,2.1070511341,-0.3016174436,0.5993249416,-0.6456158757,0.2734361589,0.2095994651,-0.9430122972,0.0983353779,-0.7922813892,0.6698214412,1.5299458504,1.0799561739,-0.4676948488,0.8438532948,1.4016919136,0.5662866235,0.6506659389,1.3225227594,-1.1737947464,0.0492078066,1.6108115911,1.2239793539,1.2101303339,-0.0170063470,0.1157550141,-0.5027875900,-0.5176725388,0.8887032866,0.5435528159,1.5120570660,-0.1064564437,0.6360615492,0.6020301580,0.8799878359,-0.0621630587,2.2621920109,2.6340875626,-0.5016446114,-1.1367765665,1.3416843414,0.4375230372,0.7510082126,1.6931953430,0.9512465596,-0.8695816398,0.9354771376,0.5091691613,-0.4463708401,-0.0330573730,-1.3820322752,1.2793287039,1.1265002489,0.3270427585,1.1429853439,-0.3402656913,0.3560847044,-1.0059175491,0.2028916031,-1.1150841713,-1.3619811535,1.0493425131,1.5576870441,-0.5290608406,1.1438901424,-1.5659375191,0.2392479181,-0.3553093076,0.0694101900,0.8125998974,1.6412402391,0.0621431805,-0.2580104470,-1.6815711260,1.6350235939,1.7907772064,-0.3013070822,-1.3498184681,0.9766227007,0.8020770550,0.1571407765,-0.3929232657,-0.3565121293,0.8001793027,0.7584725022,-0.9664206505,-2.0399837494,-0.7562393546,-0.0191347543,-0.1659532487,0.2461894006,0.0534501150,-1.4511636496,0.8290471435,1.4202630520,-0.6461420059,-1.1758359671,-0.9557312131,1.4096255302,-1.0442581177,1.8160980940,-0.3281961679,0.1080035195,-0.4689996839,-0.4098793268,-1.8007936478,-1.4797694683,1.2166144848,1.3121565580,-0.6322200298,-0.3365573585,0.7352458835,-0.2050330043,-0.4896292984,-2.1675162315,-0.0871381313,-0.6976063848,1.2434237003,-0.2033266723,-0.0167122856,0.1015309244,2.7080247402,0.2532948852,-0.8676658869,0.0866448730,0.9485441446,0.1438010484,0.1264382154,-1.1578149796,0.5896145105,1.3902870417,1.6312388182,0.3860552907,-1.3228954077,0.6822083592,-0.8747211099,-0.1168340445,-0.0816032961,0.0949813724,-0.2675711513,-0.2850045860,0.6082111001,-0.3288976252,-0.7892969251,0.8910753727,-0.4391539991,0.4801815152,1.5932966471,-0.7188422680,-1.0578689575,0.4190469682,-0.3070425391,0.4496214390,0.3089589775,-0.6861286163,1.1116139889,0.5191278458,0.7216537595,1.0761941671,-0.1724572033,-0.2763061225,0.1145950407,-0.0036275154,0.1950309277,-0.4134352207,0.2700786889,-0.4687091112,0.3374997079,-1.2691653967,-0.9487433434,-2.3327836990,0.4507500529,0.9267107248,-0.3292925954,1.1686035395,0.2126315683,0.1942957640,0.5142114162,0.8292499781,-0.2244424075,0.4714294672,1.2915810347,-1.1542066336,-1.3901450634,-1.0315078497,-0.5843418241,-0.3625900745,-0.6811479330,0.0109514073,0.4034639895,-0.7629212141,-0.6994753480,-0.5534796715,2.0600101948,0.9628931880,0.0250039492,0.1217478886,0.6854715347,-0.3456495404,-0.6771116853,3.5718197823,-1.3524976969,-0.7330499291,-1.1353269815,-0.6868650913,-0.1242099255,-1.8488539457,-0.1784221828,-0.5338147879,-1.4749981165,-0.9773634672,0.1918828785,-1.6867041588,-0.9012171626,0.9544080496,0.3894421458,0.8154364228,-0.5928393602,0.7729503512,-1.2539441586,0.9535008669,-0.4108581543,1.1859742403,-0.7260681987,0.0907370001,1.5868970156,0.1683713347,-0.4438912570,-0.3875832558,-1.8504856825,-0.8048030138,1.2810553312,-1.0632429123,-1.1179351807,-0.6259436011,0.2457038760,0.7051655650,0.5252198577,-0.7441893220,0.3223232329,-0.8422292471,-1.6582146883,0.2706842124,0.5295950770,-0.6153351665,0.4503405988,-0.6227647662,0.5138043165,-0.2224375010,-0.1313886046,-0.9083277583,1.6377744675,-1.3036310673,0.9719820619,0.6772412062,0.5541941524,2.0696039200,2.1902463436,-0.9359971881,1.5101017952,-0.8271532059,1.1484556198,-0.7858132720,-0.8876923919,0.9454967976,0.4654867053,0.8108379841,0.9280185103,-2.0502116680,-0.2926620543,0.4862718284,0.8723092675,0.6239894629,1.6616897583,0.4626489580,-0.6597118378,0.7611908317,0.4519271851,0.1392660737,0.3012660742,-0.1104904786,0.5151509047,-0.4535919130,-0.5744910240,0.1589653343,0.6228471994,0.6753728986,1.4053241014,-0.3785912097,-1.3496842384,0.0238295868,1.2929308414,-0.7779426575,-0.0595474653,-0.0276483335,0.2683479786,0.3438584805,0.5323349833,0.0969401300,0.7111643553,0.6105911136,1.3095695972,0.3804032207,-1.2960375547,0.0383879021,0.4270890057,-0.9619238973,-0.7499616742,0.1058324948,0.6600143909,-0.1229051799,0.8982565999,0.6313751936,-1.2400015593,-1.3406934738,-0.7260510325,0.1453833431,-0.2229319066,-0.7966413498,0.0715794265,0.8668941259,-0.2490485162,0.9793452621,-0.4966464639,-1.3573478460,0.2178915888,0.0893864110,0.7565530539,-0.3809821308,0.3454945385,1.0413463116,-1.5530769825,0.6615539193,-0.6907436252,-1.0928965807,-0.3175019026,2.4032316208,0.1700476259,-0.2063445449,0.4634450078,0.9587469697,0.1602792293,0.4382282197,-0.6603542566,-0.1854121238,-0.7110162377,-1.0502065420,0.3033640385,-0.0090368362,0.9971413612,0.0437622704,-1.6310248375,-0.8269742727,1.7787942886,-0.7838104367,-0.0933950394,0.7300506234,0.8639712930,-0.7480256557,1.2835432291,-0.9399489164,0.7385509610,-1.0714541674,0.4192541242,1.2823365927,0.4535315037,1.6193950176,-0.8308219314,0.6912407279,-0.2242636681,1.3361150026,0.6657164097,1.0476800203,-0.3936673701,0.3589158058,-1.9339230061,0.4487364888,2.0723960400,-1.0328774452,0.7694115043,0.2298396081,-1.9235595465,0.8481762409,-1.0481160879,-1.7839934826,1.8505026102,-0.1471647471,1.4117530584,-0.4248147607,1.0637511015,-1.6170943975,-0.1204279289,-0.8135151863,-0.9916515350,-1.3610657454,0.2157028317,-0.4446689188,0.7377965450,-1.4382053614,0.8609056473,0.4337145686,0.4578846097,-1.0002191067,-0.2169005722,-0.3418893814,1.4400826693,-0.6663337350,-0.9091744423,0.3776062727,1.3034206629,-0.6550186872,0.0032101073,-0.8028377891,-1.3056483269,-0.1703900844,0.6938927770,-2.5968184471,0.6109979749,-0.1903804541,-1.7227438688,0.0623724312,-1.3457913399,0.3999651670,0.4954300821,1.3090932369,-0.4598393142,-0.6244497299,1.5473086834,-0.1307564676,1.5282249451,0.0975896195,1.3858814240,-0.4262283444,-0.0787541643,0.0616688319,0.5138702989,-0.3498030901,-1.3233053684,0.4028116465,0.3263849616,0.5358191133,-1.7932841778,0.9994078875,-1.3617011309,1.1623231173,-1.7890124321,0.6985490918,-1.1428382397,0.2147274613,0.1396360397,-1.1729005575,-0.6266290545,1.2859871387,-1.0260407925,-0.5826871395,-0.1028865278,-1.7940053940,2.0454301834,1.0318255424,-1.1083452702,-0.4782355428,3.4777047634,2.4325971603,1.7189693451,-1.4776905775,0.5881302357,0.5027113557,2.8661079407,-0.1098669693,-0.1802531779,1.1672160625,-0.0681959763,-0.5658228397,0.3528211415,1.2640615702,-0.4119260609,0.4474448264,-0.6144564152,-0.3673212230,-0.0331863575,-0.2325524390,-0.5525498986,0.4451538920,0.3916987777,0.0216711983,0.8088118434,-0.2224570215,0.5602177382,-0.8138303757,0.0004522767,1.0792688131,-2.1361529827,0.9336476922,1.6088411808,1.8209517002,-0.8839716911,-0.2459857762,-1.2426134348,-0.1604559571,0.8543289900,-0.8487345576,0.7471719384,0.0556920283,0.4832492471,0.7741348147,1.4826248884,-0.9840801358,0.7220378518,1.0715200901,-0.4242345691,0.0419250503,0.8400822878,0.0718306378,-0.2302375734,-1.6227520704,1.2532012463,-0.6595457196,1.4351598024,0.4085188508,-1.9150269032,1.5044716597,-0.0597980022,1.1048128605,-0.4878143370,0.3595606387,-0.8408216834,-0.6972226501,-1.1642152071,0.9077614546,3.1851241589,-1.2781811953,-0.9502065778,1.4101806879,1.1578328609,0.5755327940,-0.3855011463,0.1394493580,1.5561326742,0.3201376498,-0.3746150136,-3.3304371834,1.5891109705,-0.4015725553,1.0671237707,0.4332732856,0.5515481830,0.8586447835,0.1360096633,-0.0430612415,0.8356793523,-1.8970340490,0.5594943166,0.8892461061,1.5231126547,-1.9689277411,-0.4791465700,-0.1135723814,-1.3317320347,1.2973388433,-0.7804918885,1.8386099339,-0.4639483690,-0.1304014027,0.4642805159,0.4224203527,1.5378631353,-0.6809688807,-0.7566910386,-0.8838561773,-1.6089427471,-1.5269782543,-0.5458895564,-0.0781098157,2.1578493118,-0.1167186201,-0.7636818290,-0.5750817060,-1.4051170349,0.8595709205,0.2047751695,0.5402824283,0.0225952975,0.5965875983,0.0429086573,-0.8807626963,0.2503642142,-0.2607371807,0.7006023526,0.1024034098,0.2675665021,0.8997215629,-1.3800114393,0.6278210282,-0.6009278893,0.0229070876,-0.8209497929,0.6459999681,-1.3651671410,-0.9422188997,0.8445447087,-0.5556010604,-0.2866741419,-0.6988923550,-0.2834370732,-1.5584450960,-0.3284163177,-0.2235734910,-1.2259905338,0.5285528898,-1.0578813553,0.3370731175,-0.1701500416,0.2106822878,0.1954178661,-1.2928462029,-1.0101048946,-1.0162965059,0.7101376653,1.1929751635,0.2930506766,0.3283641040,1.8373104334,0.1537463218,1.6340095997,1.5657008886,-0.1655842960,1.2367951870,2.0852239132,-0.3394646943,-1.6677970886,-0.1699476838,0.1307020038,1.3757307529,-0.1364614964,0.5837905407,-0.6506878138,1.0382732153,-1.1101716757,2.2023341656,-0.5978506207,1.2223081589,0.0622529648,1.0693994761,-0.1176077351,-0.5627841353,1.4076569080,1.7500611544,0.6664909124,0.2402775288,0.5856772661,0.1869566590,1.1902452707,-0.3557678163,-0.2289677262,-0.5311463475,-0.7184414268,0.8175365925,0.2107467204,-0.5429624319,-0.1168661341,2.7603781223,0.7776145935,0.1007762924,0.1165065393,1.5572880507,0.3648286164,2.0247426033,-0.3560695946,-0.0204400718,-0.7988411188,-0.9985968471,-0.5758203864,0.2325834781,-1.2333204746,1.3030353785,-0.7864224315,-0.5838130116,-1.3188313246,0.2502593100,1.2273973227,-0.2414512187,-0.8900685310,0.4520162046,0.5013954639,-1.2339198589,0.5234656334,1.8722342253,0.2422109544,-1.3943357468,1.5739291906,0.3023069799,-0.1267141402,-0.4534452260,0.7923907638,-2.1231665611,-0.2892504334,-1.2547494173,1.1192709208,0.1841019541,-0.5269345045,-0.3538885415,-0.3898421228,-1.2952687740,-0.7927324176,1.1888612509,1.3829047680,1.0012235641,0.1509179920,-0.5995969176,1.0717393160,-0.6755110621,1.8635855913,1.7817964554,-1.5924193859,0.7871559858,0.1822643280,0.6299715042,-0.4798375964,-0.2566851377,-0.8125913739,0.0916184112,0.3510672748,0.7465915084,-1.2982705832,0.4566431642,-1.4501985312,-1.0551677942,1.1857924461,0.2242699265,-0.2082041055,0.1747808009,1.4196221828,-0.8689292073,-1.5527167320,0.0466211066,0.3829758465,1.4496682882,-0.6000432968,-0.2342979163,0.9764523506,-0.1101170778,-0.2743099630,0.5450106263,-0.6299778223,-1.0088422298,0.5787731409,0.6363965869,-0.9875950813,0.4465334415,1.6913824081,0.8224819303,0.6353470683,0.6847267747,-0.8218975067,-1.7893120050,-0.3205640018,1.1568148136,-0.6012837887,-0.0253048092,-0.8224580884,0.4368734360,0.5922030210,0.2948924601,0.4711373150,0.2339244038,-0.8675713539,-0.1623468995,0.2907239795,0.0648862347,-0.7679846883,0.4781250954,-0.9584442973,1.2950092554,0.4279106259,0.1744094789,-0.2890577018,0.4377071559,-1.0612857342,0.6737443805,1.4462653399,-0.0192514602,0.4609615207,-1.7821609974,-0.3013353348,-0.3335744143,-1.1731162071,1.3955233097,-1.2123579979,0.2251206934,1.1979632378,0.0889767930,0.5139861107,0.9769540429,0.3754872680,0.7002015114,-0.4718477726,-0.9561746120,1.3625870943,0.5210314989,-1.7651660442,-0.5209172368,1.1049113274,0.0181649495,0.4430385828,0.0258633532,-1.1045073271,-1.0388607979,-2.2845268250,0.8429036736,-1.1021239758,-0.2099017054,-0.6958201528,1.9615095854,-0.3146707714,0.7117929459,-0.9054128528,0.3786839545,1.2535066605,-0.5864236355,-0.6019744277,0.3552685678,-0.7152664661,-1.2186499834,-0.8128777146,-0.1254124641,0.5544507504,0.8033244610,-0.0788029656,-0.3765355647,-0.1530294567,-0.0445062034,-1.0340093374,2.1138308048,-1.4381253719,-0.3641769290,-0.7461310029,0.5013814569,-0.4317185283,-1.5411124229,-0.0315037817,0.1206132025,0.3322246075,-0.3178224564,-2.4873731136,0.9532303214,-0.2243309021,0.8475925922,-0.1884335577,2.1482484341,0.1499400139,0.5643538237,0.4252497256,-1.0068868399,-0.1776017845,-0.8614460230,-0.3621585071,0.3836019039,0.9026619196,0.9432954192,-0.3222702444,-0.6358183622,-0.6205145121,-1.2305152416,-0.1459206790,0.9727852941,-0.6101299524,-1.1514422894,-0.5444167256,0.2890828252,-0.1478310674,-1.2646784782,-0.7198884487,0.7411797047,0.3236621618,0.6102467179,1.9273406267,-0.7630124092,-0.8950296044,0.1038967371,1.3054035902,1.1023359299,2.0166347027,1.2310870886,0.3453706503,0.4032297432,-0.3820646107,1.4327986240,1.2221440077,-1.3450983763,-0.6113471985,-0.0736481622,-0.4696511924,0.0348328836,0.2735553682,-1.7579873800,-0.2284794301,-0.2847909033,-1.1847519875,0.9780002832,-0.0279450770,1.1050629616,0.5406913161,-0.4539557099,0.3432274759,-0.5386041999,-2.3486204147,1.0494381189,1.0514642000,0.1160023734,0.4832822382,-0.0234396216,0.0183158182,1.3490015268,-0.5867910385,-0.5934441090,1.6418461800,0.8020620346,0.3180578947,-0.0109635685,-0.8504745364,-0.3389580846,-0.4799004793,0.2578036189,0.4269354939,-1.3231627941,-0.5754043460,0.1770341992,1.9017140865,0.4532558918,-0.7606176138,0.7406585813,-1.0882092714,1.8031427860,-1.3217358589,0.4403271973,0.3200185895,-0.0844190046,-1.0422834158,1.3751612902,-1.3435511589,-2.2676715851,0.1229116991,0.4220400751,0.8152249455,-0.5771619678,-1.5192883015,-0.1184898242,0.0107239718,-1.6067227125,1.5956927538,0.0263506193,0.9669717550,-0.8889227509,-0.4053593278,1.3851294518,-0.4103517532,-1.2005337477,0.8040002584,0.0697512850,0.6278099418,1.3422721624,-0.1635767967,-0.1250185519,-0.3778596222,-1.0309101343,0.5122585893,0.3585168719,-0.3668381572,0.7736611962,-0.5901617408,1.0048699379,1.6593602896,0.0736119524,-0.5228585601,-1.1776105165,-1.2693563700,0.7466336489,-0.4147734344,-0.6222800016,-0.4369660020,1.1900970936,-0.0045385598,-0.3916423321,-0.4234701991,0.4515590668,1.6646592617,-0.7858273387,-1.0369464159,-0.8603183627,1.8155955076,-0.9686090350,0.2055028230,-0.0671775788,-0.1541100144,0.1235477552,0.6986100078,1.5323183537,0.3527896404,0.5008907914,2.1498534679,0.3520805240,0.8896867037,2.5267851353,1.0206768513,-0.8351369500,0.4967375398,0.8105723262,-0.7931277752,0.2910664976,-0.7967676520,0.2498087585,0.3448672295,-0.1164075732,0.0368722863,1.3828399181,0.4213814735,-0.9003941417,0.5536766052,-0.4180638790,-0.4147278368,-0.9282360077,-0.7860546708,1.1377804279,0.4159342051,-0.7434610724,-0.7378995419,-0.0775714889,-1.1062474251,-0.1626705676,-0.0320903845,-0.6710093617,-1.9599610567,-1.0496373177,0.4051431119,-2.0050468445,0.3016331196,1.1520593166,1.2890785933,0.6122150421,0.4631689787,0.2665107846,-2.0319108963,1.7829045057,-0.5972828865,-0.2010582238,1.9431426525,-0.1263195872,-2.0065937042,0.9118897915,-0.4932822585,-1.6785792112,0.7633743882,-1.4086085558,-0.7630506754,2.4220027924,-1.4050699472,0.3170969188,0.3332512081,0.5363234282,1.2329015732,-1.1386669874,0.7243200541,-0.5739594102,1.1940883398,-1.3103320599,0.0189716071,-1.0934224129,-0.6630554199,0.6524068117,0.4000760615,-0.4352589548,1.8864926100,0.1805183440,-0.5843188763,2.0612359047,0.2389136702,-1.0740573406,-0.3438945413,0.5787284374,0.6672785282,-0.3425982594,-0.2763700783,-0.0430908315,0.3072268665,0.4272223711,0.7463321090,2.3031678200,1.1491247416,0.7463536263,1.6505769491,-0.7130047083,0.4484150410,2.5032739639,1.5361375809,-0.0852901042,1.7603957653,-0.7834419012,-1.5477027893,-1.2571730614,1.3132101297,1.6227086782,-0.1173110008,0.7305071354,0.3547957242,1.1275627613,-1.3428343534,0.1347589195,-0.2234453708,-1.6528010368,1.1485866308,1.3285199404,-2.2826619148,0.2097360492,0.7691443563,-0.3663109541,-0.9105324745,-2.1862375736,0.4142344594,-1.2459869385,-0.5919961333,-1.1263803244,-0.7219035625,-1.2844762802,-0.6319314837,0.4255679846,-0.9710791111,-0.1546536833,-0.9671045542,0.8408493400,0.4944689572,-0.9499318004,-0.9606438875,-1.6236588955,-0.0765073076,0.1454095095,-0.6725363731,1.5028852224,0.3382230401,0.9947757721,-1.5230675936,0.3305849135,1.0095059872,-1.2323187590,-0.9129067063,-0.6490970850,0.7627770901,-1.5042232275,1.9205620289,0.6990779638,0.3981493115,1.7094851732,-0.8547058105,0.6071660519,0.3208642602,1.3405076265,-0.8251224756,0.7542603016,1.5279054642,-0.0644014403,0.0308947098,-0.4144746959,-1.2328224182,1.3450195789,0.5506920218,0.7623227835,0.4588803649,2.4532387257,0.4284676611,-0.6673672199,-0.7856223583,0.6798230410,1.3754965067,1.2486560345,0.8557427526,-0.6578801870,2.8154249191,-2.0665171146,-0.8970668316,0.8705096245,-0.5161067843,-0.8774737120,-1.3747942448,-0.0044820942,-0.0629592091,0.8383932114,0.1018836051,0.2315552235,0.8842407465,1.9258217812,-0.3826536238,-0.7059099674,-0.9088483453,-0.0775755346,-0.8568040133,0.6119330525,-1.1394847631,-1.0729565620,2.5123028755,-1.1320472956,-0.0720144957,-1.3061287403,0.0605295226,0.5201559067,-0.7216553092,-0.0817440078,0.4655059576,-1.0059340000,1.6584295034,1.3138953447,-0.1685477644,-1.7573693991,-0.5177462697,0.2565937340,-0.7753594518,-0.3755358458,0.9658132195,-1.6226822138,2.0549082756,1.1139340401,-0.4460828304,0.3770333529,-1.0984185934,-0.7914294600,-0.7182283401,0.8725944757,1.4336870909,0.1247830093,-2.4568533897,0.8807242513,1.4794603586,0.5188699961,0.1264361292,-0.9099682570,-0.3541872203,1.0382727385,-1.1467587948,0.0937129781,-3.0879652500,-0.7070456743,-0.8758177161,0.7819408178,-0.7893208265,0.3356752098,-0.3563073277,0.4893903732,-1.0363898277,-0.9055857062,-0.7337564230,0.1480658501,0.9461278319,0.3862171173,-1.0495040417,0.9934561253,-0.2928678691,2.2781779766,0.4375535846,1.4886761904,-0.2329892665,1.1606227160,-1.1704735756,-0.8371050358,0.4440965652,0.0336679667,1.2123416662,-0.3476849496,0.5047299862,1.0939006805,-0.1639223248,-1.1171123981,-0.8182387948,0.5606721640,-0.4868011773,-0.1622991860,-1.1784236431,-0.0316150524,-0.6546902657,1.9915369749,-0.1884418726,-0.1821149737,-0.5000926256,1.5627294779,0.5795538425,1.7219066620,0.3575980067,0.7396416664,-0.7974137664,0.1111887917,-1.3111822605,0.1688636690,-1.2101415396,2.0626072884,-0.1517615914,-0.1261129677,0.5988250971,0.3151803315,0.2292727828,1.5950623751,0.7607192397,-0.6130860448,1.2753077745,-0.0473849252,1.0907490253,-0.5991789103,1.1112835407,-0.7966700792,-0.9286405444,1.1475811005,0.7448164821,-1.0517472029,1.8815093040,0.4007554352,0.5530241728,-0.3934260905,-0.0581542328,-1.2024121284,-1.1866624355,0.4203956425,0.9341752529,1.2243565321,0.8899989724,0.3466911018,-0.7389758825,-0.9940132499,-1.0827097893,-0.6211391687,0.0189784765,0.6920895576,-1.3577948809,-0.1852061152,-0.3256109953,-0.3312273026,2.7818863392,-0.6032305956,-0.5881502032,-0.2108903974,0.9609686136,-1.7761542797,0.1638919264,-1.8034422398,0.3438547850,-2.0366148949,1.2626676559,-1.0085458755,0.8398509622,1.1671663523,-1.6237409115,1.2003210783,-0.6494108438,-0.3809467852,-0.8366717696,1.0897408724,0.7005752921,1.8595799208,0.7068119645,0.2377082705,-0.4191710055,-0.0960142314,-0.4157134593,-1.4508297443,0.6521006823,2.3216221333,0.6430325508,1.4736698866,-0.4491530657,1.0629155636,-0.9583804607,-0.6451090574,-0.6868199706,-0.0433918200,0.9207156301,1.4857054949,0.3920950890,-0.4053091705,0.8437995315,-1.5179128647,0.1888910085,0.0703740716,-0.7147838473,0.2936773896,-1.1163834333,0.4440954924,-1.5620125532,-1.4867972136,0.9728970528,0.0287208781,0.2518751621,-0.8563625813,-0.0962809995,0.9173402786,0.1593800485,0.3545618653,-0.5275490284,-0.1848464012,1.1037555933,-1.7516676188,1.1288124323,0.4776148796,-0.0878350437,0.8084073067,-0.5648819804,1.1433855295,-2.9104449749,0.8359450698,0.0287205018,-0.3140828609,0.2962246537,2.6138598919,1.9440122843,0.2640841007,-0.9142881632,-0.5235984325,-1.0183387995,0.2797614336,-0.6935437322,-0.2669579685,0.8215245605,-0.2807157934,-0.4905641377,0.4833571315,0.2829817235,0.5185962915,0.6601308584,-0.3351995051,1.0649538040,0.1437657326,-0.1996699721,0.1168802828,1.0141957998,0.1364440620,0.6416521668,-0.0714805797,-0.1246618554,0.6482216120,0.7308468819,0.2386373132,1.0028398037,0.5547579527,-0.5872223973,-0.7867373228,-1.1379771233,0.0934178531,-1.1745666265,-0.7475016117,-0.5521036983,0.1610332578,-1.0222641230,-1.0741324425,-0.0681060180,-0.5505965948,-0.0340255834,-2.0789461136,1.2974512577,-0.2434522808,-0.6320980787,1.6777137518,0.2020441890,0.7013676763,-0.9742774963,-0.4643732905,-1.7642954588,0.2217412889,-0.8830285072,-1.1129447222,-0.6823812127,1.3527050018,-1.2479234934,-1.7996045351,-0.8925056458,-0.0426734425,0.5319902301,0.2391276062,1.0110605955,-1.4177103043,0.4677368701,-0.4861982763,1.6502017975,-0.2858231962,0.4730424285,0.4991550446,1.8836057186,-0.4640003443,-0.0351408608,-0.4028859138,-0.2978712618,0.0881469771,1.7128058672,0.0741602257,-2.0762367249,0.6053909063,-1.3824832439,0.5659181476,-2.0131797791,-0.3630668521,0.6377583742,1.1255798340,0.1482716650,0.0555110313,-1.0066103935,-0.0993747562,-0.5288520455,1.3735204935,0.4501582086,0.9103261232,0.5915299058,0.8719922304,-0.1844073534,-0.4059509635,-0.7417193651,-1.1776884794,-0.2048167139,-0.7765574455,-0.3557467163,-0.4653972089,0.1155521870,-0.0342244320,-1.6729363203,1.5951782465,0.3936387300,2.1581971645,0.0029275578,-0.2868529856,-0.9359773397,1.2794549465,1.4388250113,-0.2805157900,0.1168797389,1.3458018303,1.0483114719,-0.6029849052,0.7616730928,0.5633711815,-1.0731381178,1.0358542204,-0.7741640210,1.0627392530,-0.4310510159,0.1969968379,-1.5273967981,0.9693744779,0.4679141045,-2.0622494221,-1.4941822290,-0.2936666906,-1.3504440784,-0.4829608202,-0.4429127276,0.8962433338,0.4110181332,-0.7450675964,0.3003093004,-0.1053996682,0.5656231642,0.0190361906,-0.5192342401,0.3490352929,-0.2058995962,1.3725743294,-0.8968298435,0.5423145294,-0.8962261677,-0.1491219550,-2.0275385380,-0.6608038545,-0.9174212813,-0.3269410431,-0.6984471083,1.6944645643,0.4648699462,-2.1589312553,0.0426462181,-0.4002126157,-0.9844839573,-0.9373098612,0.3330574632,0.8121154308,0.1654017717,0.0265124217,0.8958481550,1.0384033918,1.3312896490,0.2691825032,-0.5273260474,1.1580491066,0.9136486650,-1.8261531591,-1.6294533014,-0.4599237144,1.3166241646,1.2717188597,0.3420768678,0.1444726288,-0.9680743217,0.4697493017,0.8182046413,-1.4236667156,0.7308368087,1.0863107443,-1.4559316635,-0.0180493183,0.0013391395,-1.5703587532,-2.0040662289,-0.1724464595,-0.7469660044,-1.5486024618,0.9595509768,-0.9743630290,-0.0639142990,-0.3483835161,-0.5184774995,-0.1823514253,0.2897956967,-0.2570497990,-0.0183025580,0.1666794717,-0.4107077122,0.3243245482,-0.6374425292,-1.3727964163,-0.7992866039,1.1616351604,-0.0549143553,0.0692056417,0.4817972779,0.3330696821,-0.3786138296,-1.9377900362,-0.8723055124,-1.9915663004,-0.7240679860,-0.5480913520,-0.0218152720,-0.1139964089,-1.6564424038,-0.9848123193,-0.5869332552,1.3057488203,1.0492138863,-0.3129112720,-0.9047678113,-0.7177250981,-1.2049781084,1.3314702511,-0.6231637597,0.7844091058,-0.0176781621,0.4116369486,-1.3127673864,-0.2670100331,-0.0723978579,1.0006428957,-1.9221795797,-1.2662967443,0.5329766870,0.0479580536,1.1082743406,-0.0548312664,-0.8269295096,1.1963032484,-0.2248819619,-1.2792636156,0.4042378664,0.0060892166,0.2407629043,-0.2863627970,-1.7510541677,-0.8826270103,-0.1805585325,-0.8399214149,-0.3694585264,0.6691579819,-0.6126208305,0.5864830017,0.3455734253,1.0982719660,-1.2218780518,-0.7412814498,0.6595743299,0.6852849722,-0.4938407838,-0.8290623426,1.8494502306,0.7113271952,-1.3318347931,-1.2668334246,0.6168457866,0.0138242068,2.3361804485,0.0133694801,-0.9318174124,1.0154223442,-1.8149859905,0.1063761935,-0.4912840724,0.0053320178,0.1622054279,-0.3720568120,-1.7061535120,-0.3411099017,1.8075840473,-1.4172304869,-1.3801350594,-0.1177887693,-0.4706535637,-0.5100216866,0.0099745048,1.0853533745,0.3263893127,0.0064063426,1.8728448153,-0.5153175592,-0.0248616636,1.0729645491,-0.9651572704,1.2770721912,-1.1947435141,-0.4683704376,-1.5828979015,-0.2075870931,0.7596347928,1.1891981363,-0.2871383727,0.7696259022,1.1756484509,-0.2555998862,-1.1806615591,-1.5777649879,0.7371015549,-0.8200165629,-0.3479668200,1.5302962065,-0.8369179964,1.9417058229,0.3632695973,-0.5283840299,-1.4799474478,-1.0299297571,-0.3006336093,0.7646048069,-0.7382662892,-0.0858026668,-2.0297603607,0.7612405419,0.4500703812,1.1386395693,1.0415931940,-0.6529315710,-0.1752320975,-0.0934556127,-0.3674602807,1.1684161425,1.7406518459,0.2140564770,0.1849590987,-0.4445253611,0.9117878675,0.6770923138,0.8259384036,0.0250431057,-0.6785590649,1.5031665564,0.4678463638,-0.2961201370,-0.8332222700,-1.7620338202,-0.5066124797,-1.4213819504,0.0325794555,0.4598464966,0.8975044489,0.7793223262,0.2708227634,0.3689299226,-0.2866435945,-0.4612148404,0.2356104404,0.4840772152,0.0035614318,0.5616604090,-1.1055561304,2.8946905136,1.2669999599,0.4352328479,-0.6449033618,1.0168118477,0.1424993426,-0.6114996076,0.1845914721,-1.2095587254,0.1187560558,0.1327622831,-0.9325071573,-0.0071629351,0.8303387761,-0.0023879316,-0.4078947604,0.5116908550,0.5126677752,-1.8852918148,-0.6545630097,-0.8021213412,1.7759143114,0.0790987164,-0.0372745730,-0.5091186762,0.3631534874,0.1563995630,-1.1762232780,-0.2444291711,-0.9540668130,0.8484722972,-0.2094481140,0.2584297061,0.4090232253,2.4077796936,-0.6442091465,-0.3512670100,-1.6794028282,0.6157962680,0.9134595394,-3.0511646271,-0.1610290557,0.0838241577,-0.2765303552,0.5775899887,0.5077181458,0.6141081452,-0.2548968792,-2.2971007824,-0.4871230423,-0.7298045158,-0.2915547490,-0.8250328302,-2.1933531761,0.5092428923,-0.9196913838,-0.2856418192,0.4852777123,-0.5238398314,-0.8249314427,-0.2213008106,0.4922359288,0.0046398826,0.0410495177,2.0978188515,-0.6671367288,-0.6185826659,0.9899863005,-1.0268276930,0.9838751554,0.1415936202,0.9602013230,-0.4019086659,0.0917325616,-1.7731301785,-0.6001939178,1.4872521162,-2.1950342655,1.4718630314,-0.4139128923,-0.9561069608,-0.8113186955,0.3326387703,0.8214855194,-0.2038237303,0.1721137315,-1.4140814543,0.8006810546,-1.1539144516,-0.4913604856,0.0820094123,-1.4642955065,-0.1441533267,0.3502728939,-0.5427587628,-0.1549838632,0.9814139605,1.6057529449,-1.7895412445,-0.5796220899,0.1910269558,0.1117242649,-0.8288728595,1.0306375027,-1.0849578381,-0.6961807609,-0.8261684179,-0.1974864304,-0.8071389794,0.9624972939,1.9254288673,0.3915759921,-1.8992302418,-0.6777492166,-0.3872167468,0.3622063696,-0.8133463264,0.4327911437,0.5757126212,1.9948111773,-0.8023193479,1.4258333445,-0.3936565518,-0.7623519897,-0.1646928489,-2.3818755150,-0.3824919164,1.1486035585,0.4143595994,0.5045929551,0.2677341700,1.3893061876,-1.6509420872,-0.1595229954,0.5341352224,0.5419927239,0.5675623417,0.0678644925,-0.4693374336,-0.2899969816,-0.2941041589,-0.3687418997,1.0642687082,0.3990949392,0.2112073898,2.1691763401,2.5314116478,1.1707247496,0.7853136063,0.8281221390,-2.0882747173,0.2841241062,0.3198890388,0.1984391659,-2.4289112091,1.0632315874,1.9254181385,-0.2166331410,-0.5206612349,0.3861836493,2.1343843937,-0.9316899180,-0.4525576830,0.0293869525,1.5127466917,-0.5325924158,0.2071255594,0.6559854150,-0.4750492275,0.6517692208,-2.0260581970,0.5454990268,0.9007616639,-2.1234264374,-0.6924746037,-0.2750160992,-0.7721719146,1.6402645111,0.1960601807,1.0715852976,-0.8867476583,-1.2654846907,0.8506244421,-1.0026184320,0.4239800870,0.0143493805,-1.0331511497,-0.2458608299,-0.2627170682,2.2830805779,-0.4507263899,0.4234290123,1.9715867043,1.0045151711,-0.8947780132,1.0483188629,-0.2448585927,0.9080960751,0.6717668176,0.7670707107,2.6760594845,0.2887377441,-0.5765333176,-1.3535066843,-0.1563234329,-1.6242492199,0.8874552846,0.4395448565,0.2620094121,0.8149400353,-0.7656787634,-0.1232830957,-0.6337431669,0.0293763019,1.4243355989,1.0572086573,-1.8027933836,-0.5571980476,-0.3124030530,1.2649337053,2.0032932758,0.9319395423,0.1501328796,0.1547182649,0.0764016360,2.4216063023,0.7080580592,0.2585445046,-0.2951288521,1.1590728760,-1.4281768799,-0.6427973509,1.0778914690,1.3738418818,-1.0305179358,1.2834491730,-0.1111884490,0.0416006520,1.2782590389,-1.3953489065,-0.2880483568,0.2030022740,-1.4335784912,-0.8353443146,-0.7202455997,0.5462498069,1.4243865013,-0.1032523811,-0.0441531800,0.1812570095,0.6535425186,0.7359706759,-0.3278496861,1.6425333023,2.3137261868,-0.1360592395,0.5812934637,-0.6448676586,0.0685226098,0.8798252344,-0.7275282145,-0.6837694049,1.2179878950,0.5052300096,-0.1817120165,2.7077167034,0.5897852778,0.0560361706,-0.2262458354,-0.1569620222,-0.8156437278,-2.8309299946,-0.0347006284,2.3700158596,-1.4517055750,-0.7827415466,0.2200433016,0.6763939261,0.5266736746,-0.3205535114,0.4175000787,-1.4401388168,-1.2638221979,-0.0063566575,-0.4596130848,2.0484826565,2.6739189625,0.1921385825,0.8656622171,-0.7989099026,1.2951737642,0.5948476791,-1.1622223854,-1.0827726126,-0.6607543826,1.0801876783,1.7353651524,0.2039402127,0.4578662515,1.4513297081,0.6782011390,-1.0781478882,0.9227527380,0.8389589190,-0.3721253276,1.6220294237,-1.5711258650,0.5092188120,1.6772679090,0.2103672624,0.3513631523,-0.6458117366,-0.1160704643,2.5399868488,0.2986964285,0.7530531883,2.7717247009,1.3016248941,-0.5547922254,0.8124800920,-0.5440471768,2.9482123852,-1.9910891056,-1.2753846645,-0.8022624850,-1.4422289133,-0.5684272051,-0.1325278580,0.6433197260,-0.0040892162,-2.0867819786,0.3624523878,1.7563529015,0.1436444223,-0.7461550236,-1.4902784824,0.2751983702,0.2716933787,-0.5269842744,1.3409408331,-0.5586332083,0.5571196079,-0.4478425086,1.0341912508,0.5109900236,-0.9873884916,0.0708701387,0.3049991429,0.5304082632,0.1405647397,-1.0756629705,1.1812801361,1.6754041910,1.5391957760,0.1541727930,-0.3437381983,0.8482227325,-0.1725202948,0.8681633472,-1.2652460337,0.9696620107,1.3187575340,0.1618376225,-1.4064910412,-0.4977366924,-2.9630827904,0.2724413574,0.5373820066,-1.1703877449,0.2719387710,-1.0549979210,1.4473180771,1.9692100286,-0.1396738887,1.2972766161,1.3983153105,0.7203134298,-0.4064352512,-0.5069192052,-0.7329676747,0.4564698935,1.4903695583,-1.5688288212,-0.2548439503,1.0869340897,-2.3693585396,-0.0668379068,-0.2766051590,-0.5685678720,0.1007213444,0.4818153977,0.3051174581,-0.6083016396,-0.4800639451,0.2737148702,1.9641357660,0.9281412363,0.3207195699,0.2103534937,-1.6923233271,1.1626750231,-2.2308335304,1.4662967920,-0.0578541830,1.0219566822,0.8956917524,-0.4066852629,0.6047781706,-0.2009098828,-0.0700096786,1.5064666271,-0.0695334747,-0.8002229333,2.0655736923,-1.8748968840,1.4135584831,-0.1391232759,1.5362677574,0.2097577006,0.2475161254,0.9883912206,-1.5831539631,0.4373769760,0.3146182895,0.6461459994,-1.4481978416,0.4126372039,0.2698713243,0.2971876562,0.6936231256,-1.7687585354,-0.1024047658,1.8644307852,0.1501193047,1.4666852951,-0.0993625149,0.8320145011,0.2680338025,0.9386171699,-0.4379406571,0.0308498964,-0.5973451138,0.1201213524,1.8185228109,1.2896347046,-0.7865766883,-1.1671062708,1.0264364481,-0.4385924637,1.1909672022,-0.2365868241,-1.2961139679,0.7524974346,0.2822886109,-0.8649634123,0.0341063626,-2.8012323380,1.8497134447,-1.4406055212,-0.8967682123,0.4737245440,1.4397727251,-1.7417879105,1.3006533384,-0.5665988922,-0.8679270744,1.1672435999,0.8426421881,0.5777239799,-0.0019734991,0.2628566623,-0.6765850186,-0.9454251528,0.6963109970,-2.0113916397,1.2220158577,-0.3644271493,0.3940259516,-0.4764729738,0.6744356155,0.4133459032,0.7129043341,-0.1390728951,2.4798042774,0.4449064732,1.0364000797,0.3874957561,-0.2127955854,-2.7277810574,0.8964817524,-1.1030762196,-0.9547590613,-2.6085407734,0.8240185976,-1.0024412870,0.5572627783,1.2201204300,0.6980441809,-0.3182870150,-1.0811100006,-0.8984940052,-0.9392712712,2.1252901554,-1.0693789721,0.6708747745,-1.2933703661,-0.4726088941,1.1888222694,0.2114872038,-0.4543708563,-1.3946108818,-1.3129746914,1.8129559755,-0.6399911642,-0.3761229515,1.0799931288,-0.8454584479,-1.1660637856,1.2091180086,-0.0841020271,-0.6888543367,-0.2568129599,0.1405620426,0.3394407630,-1.4461472034,-1.1847535372,1.1745417118,-0.5321114063,-0.0360228755,-1.2600207329,0.2216902971,0.3386104107,-0.4858584404,-0.2366298586,-1.5974326134,1.6561534405,-0.0659240410,-0.1518712789,-0.2975880206,-1.6202889681,-0.5111511350,0.4328710437,2.2999274731,0.1036824062,1.0497152805,-0.6470173001,1.2935286760,-0.8573095202,0.2456389517,-1.6096886396,-1.5166975260,2.2229051590,1.7827144861,0.0722996220,1.2876883745,3.4461617470,0.7335449457,1.2204228640,0.0536431260,0.0680795535,0.1912591606,1.3810964823,1.6709645987,-0.5143932104,-1.0899485350,-0.7233867645,-0.6821279526,1.3069764376,-0.2939797640,-0.5712470412,-1.4585288763,0.6952814460,-1.2076721191,1.0499768257,-0.0916740969,-0.0482324064,-0.5674934983,0.5605602264,0.7756689787,-1.1728376150,-1.5867017508,-1.2057219744,-0.2544875145,0.2107366025,0.5100553036,-0.3370763659,-0.9028173089,0.3074392378,0.0235144868,0.4365579486,0.2447894067,3.3895692825,0.7273297906,-1.8519378901,-0.7392191887,0.6342939734,-1.1659489870,0.2778316140,3.2687973976,0.8361719251,1.5480146408,-0.3752118051,-1.6580158472,-0.1478787810,-1.5146595240,0.6179021001,0.7550742626,-0.0943882689,0.7755956650,-1.5603001118,1.3169560432,-2.0728368759,-1.0825216770,0.6124401689,-0.2606959045,-1.1539610624,-0.7913170457,1.8059349060,0.4528495371,0.1427119225,-1.5344995260,0.1410109401,1.0175800323,-0.6247666478,0.9975888729,0.1294607967,0.1843679994,-1.1771456003,0.9625459909,0.9107032418,-0.7806379199,0.3773173392,-0.6000570655,0.5929875374,0.6998752356,-1.2417523861,-1.2792830467,-0.0448341966,-0.0431805402,-0.4964704514,1.9926270247,0.7569426894,-0.7253473401,0.1321403235,-0.0756466463,1.7732292414,-0.3561931551,-0.3286891282,0.7018263936,-0.8119922280,-1.1326178312,1.7631685734,0.4812170267,-0.1956695765,0.4439469278,-0.2367948741,1.3929479122,-1.0372287035,-0.0327260606,-1.0332548618,-0.6647860408,0.3720833957,0.1972508132,0.4465264380,1.3022334576,-0.3980585933,-1.0992186069,-1.1671767235,1.2631903887,0.3971188068,-1.5323983431,-0.4032920003,-0.6760450006,-0.2094847560,0.3652860224,-0.3081654310,-1.8190023899,-0.1701465398,2.2619700432,0.2899451852,-0.7703804374,-1.1064257622,1.2357764244,-0.2967175245,-0.2518014610,-1.5689984560,-0.0665395111,-0.0862559229,-0.9216248393,1.2766802311,1.5393574238,1.0558137894,0.0327471532,-1.6642035246,0.8495980501,-1.7295979261,1.3477027416,0.1795098633,-0.2721120119,0.7435341477,-0.4873876870,0.5400074124,0.4466554821,-0.1522121280,-1.0432454348,-0.0845364034,1.7754360437,0.3426231146,0.4469730258,2.3664221764,0.6919433475,-1.1116325855,0.8461518288,-0.2383031100,0.8409350514,-0.7595874071,0.3608250618,0.8970346451,0.2595388591,1.0047931671,0.2540408075,-0.3400612473,-0.0989332497,-0.0843240842,-0.3543157279,-1.7633622885,-2.1017308235,1.2253223658,-1.1555352211,-1.7978022099,-0.3463512659,-0.0117409742,0.5840808153,-1.0323102474,-0.4460191131,0.0180029366,0.5165215135,1.0082906485,0.4918971956,-1.4555004835,0.4997964203,-1.1232254505,0.9987378120,-0.8648818731,0.1568584144,-0.7785245776,-0.3282842934,1.8889665604,0.1762571484,0.1230012551,-0.1905523986,-1.9035918713,0.6908513308,-0.4261215627,0.1221275926,1.0988082886,0.0977977887,-1.7845711708,0.7103321552,-1.1468501091,-1.2720302343,1.1274603605,-0.8638828993,-0.8295898438,-1.3732126951,0.1212136671,-0.7930681109,1.4917933941,-0.4714035690,0.2895286381,1.6895601749,-0.8141436577,-0.8679010272,0.1823181361,1.4328541756,-0.4204801917,0.2739147842,1.2020156384,-1.8207857609,0.0096109519,-0.8583530188,-0.9887015224,-0.1826705188,-0.6696085334,-1.5090953112,-0.1405836046,1.4303534031,0.3717813790,-0.6468277574,0.6109654307,-1.4839514494,-1.3144893646,-0.7689852715,0.6979426742,-1.9050546885,0.5673009753,1.0644997358,1.4237437248,0.8367416859,1.4612578154,0.9356698990,-0.5868975520,0.8214159012,-0.3272928298,0.4603173733,0.0749733821,0.1287813038,-0.2579364479,-0.1763682663,0.3552583456,-0.6590710282,0.8675601482,0.1804513335,0.0760865286,-0.2730111480,-0.7868251801,-0.1163439304,0.0811429247,0.1231359839,0.5234337449,0.1796350628,0.9489487410,1.6153148413,0.9410284758,1.0284470320,-0.9127117395,0.2013400793,-0.4045197666,0.7818467021,-0.3640500903,-1.8174712658,0.4952382147,-0.3121580482,-0.2593118548,0.1520194411,-0.0602648407,1.1699638367,-0.4944905341,2.1621308327,-1.3320986032,-1.6290991306,-0.7247669697,1.2197005749,-0.4413643777,-0.3647455573,-1.7348531485,-0.3638899028,0.0509795621,-0.5163988471,1.0410149097,1.0232046843,-2.2675664425,1.1889684200,0.4370892942,0.6450393200,0.7288362384,0.1710212827,1.3312356472,1.3694489002,-2.7367355824,-0.8831370473,0.4819488823,-2.1779723167,0.5980419517,-0.5120624900,-0.3950772583,-0.9564168453,0.3127147853,-0.3291445673,-0.9316582084,-0.6530855894,-0.5801360607,-0.8719137311,0.6725584865,0.3189466000,-0.9949298501,2.0379827023,-0.3290540576,-1.4721562862,-0.5032038689,-0.9637928605,-1.2094340324,0.7158033252,-0.0927066430,-1.2442517281,-1.0542521477,-1.1061631441,-1.2389072180,0.5120587349,0.2246490270,-2.1872861385,-2.1402411461,1.5952260494,-0.0812475979,0.6093641520,-0.5080390573,-0.2121757418,0.2089391798,-1.5400040150,0.3724039495,-1.1847088337,1.5130584240,0.7076172829,-1.5021262169,-0.6401950717,0.4719422758,0.0465151928,0.5896236300,0.1516773552,-0.7396040559,1.5477974415,0.4146561623,-0.0829181895,0.0063156439,1.1727257967,1.2963408232,-0.4674797058,-0.1541069448,-1.4523546696,-2.4150819778,0.3667570949,2.6291785240,-0.4988396764,2.0458302498,-0.0747351050,-1.2224282026,0.2986982167,-2.0429217815,-0.9583296180,0.8893783092,0.2481311560,-0.5463197231,-0.1864299476,0.8800899386,-2.0384750366,-0.5730707049,2.2102062702,-1.3429448605,0.9100778103,2.2369208336,2.9532630444,0.2449691147,-0.0423857160,-1.2589607239,1.9544759989,-2.0986361504,1.1010017395,-0.6761249304,-0.5158253312,2.1491205692,0.6918260455,0.4865469933,-0.0197637565,0.3024237752,1.2770613432,1.5790829659,-1.3644719124,0.1178247705,-0.2447064966,2.2056901455,0.5842333436,-0.8112859130,-0.8845480680,0.5018767715,-0.9628272653,-0.6917787194,0.5183368325,0.2223260701,-2.4080696106,-0.6258693337,-0.2220265567,-1.1970661879,-0.4511078000,0.1818592101,1.0391007662,0.1656878889,-0.1195623577,-0.4278938174,-0.3380023241,0.7096031904,-1.2523366213,-1.0001627207,2.1837749481,1.1153163910,-0.3457722962,0.2794967890,-0.3424712420,-0.4181531668,0.5340260863,-0.9294694066,-2.6755039692,-0.5858883858,1.1506539583,1.0913171768,-1.0706495047,0.0423627459,-2.0051174164,-1.3628343344,-1.1141849756,-0.0660549477,-0.9681855440,-0.6248205304,0.6539865136,-0.7431252003,1.1930276155,0.0813564435,0.4269303679,-2.9126818180,0.6502090693,-0.5792543888,-0.0636761934,-0.2226995528,0.2611485124,-0.1963765770,-0.7510466576,-0.4036752284,-0.7355467677,0.8295586705,0.2841912508,-0.5753408670,-0.4433884919,-1.4987837076,0.7639639974,1.1248340607,-0.3037438393,3.0878508091,-0.6452888250,0.1875440478,0.0079111867,0.2569694221,-1.0926113129,0.2290089428,0.3807959557,-0.0390078202,-0.0512206107,-0.0093297828,1.1520316601,0.3930533230,-0.6344077587,0.0940024257,0.8543282151,0.3782372475,0.9214416742,-0.3992048502,0.2794377804,-0.0629065409,-1.1470851898,1.0025026798,-1.7029709816,-0.3982113898,-0.1038763076,1.7992355824,-0.7881760001,-1.4537860155,-0.4431024492,-0.0188008342,0.8453229666,0.3609706759,-0.1380304694,1.3005646467,-0.7697758675,2.0646855831,1.5479987860,-0.6123995185,-0.7303442955,1.0699342489,1.2121047974,-0.2541789114,0.4415258467,-0.2636577189,-0.3476258814,2.0897309780,-0.0466064326,-0.9225341678,1.2898052931,1.8792136908,1.5108665228,-0.1160245165,-1.3695697784,-0.2568242252,-0.8984883428,-1.3459892273,0.3001153171,0.2522737384,0.4287333488,-1.4466867447,0.4010054767,1.7777253389,-0.0489532314,-0.3533559740,0.1734737754,-1.0124557018,0.0805245712,-0.1957098097,0.1044771150,-1.0432385206,-0.3111307025,-0.6315842271,0.2103316486,0.9604236484,-1.4323203564,0.0213550087,0.2500723600,1.5048394203,0.8332036138,0.5828694701,-1.1305952072,-0.5224618316,2.7289142609,0.5754151940,-0.1905027777,-0.7241643667,0.1696766764,0.3804264367,1.3739337921,-2.0588717461,-1.2422560453,-0.2515717745,0.0229164604,0.0536120906,-1.9283407927,1.7888227701,-0.1094532013,1.1283302307,0.0836060122,-0.1131427437,-0.1455607265,-1.7971167564,0.4484315515,-2.7939643860,-1.3108272552,-0.3902270198,2.8373355865,-0.2132748961,0.9357783794,-1.0359768867,-0.1403545290,0.7936987877,0.7273046374,-1.9549911022,0.0507963784,-0.6482225657,-0.0779463053,1.0098884106,-0.4915691316,-1.7953245640,1.0999864340,0.3593125641,-0.2098834813,-0.6835131645,-0.0330367573,0.1991713047,-0.6592006683,-1.2774186134,-0.9763864279,-0.4536683857,-1.0885910988,1.1693351269,-1.0799335241,-0.7590987682,-0.8095877171,0.2647846639,-0.3310623765,1.2105258703,1.8539288044,-2.3340659142,0.1285315156,-0.3244792521,0.8191900849,0.9074296355,1.1251484156,-0.6740199924,-1.7290600538,-0.2522689700,-1.2518934011,-0.3544958234,0.3565763831,0.5419793725,0.2216321081,0.0744594485,0.4009789228,-0.9030396938,1.1985112429,1.3050527573,0.2644869983,1.2111719847,1.4938938618,-0.3135474324,1.6932300329,-2.1511843204,0.8760904670,0.3790178001,0.1553075314,-0.7556515932,0.4605605006,0.1281558573,-0.5230821967,1.4032703638,-0.2235340029,0.7719467282,-0.8938195705,1.8719172478,1.7318835258,-1.2508921623,1.4505107403,-0.7890445590,-0.1284002364,0.5220596790,0.3965850472,0.3776007891,-0.8109610081,2.5998513699,-1.2116770744,0.6401030421,0.0995526016,0.2845474482,-0.3137201369,0.5138025880,0.5688924789,0.0490821227,-0.5854231119,-0.1241295859,-1.2401731014,1.7278945446,1.3531194925,0.8374717832,0.7225297093,0.7827263474,0.6421630383,1.3519514799,1.1704369783,0.1243656427,-0.4696682394,-0.5816171169,-0.0667436421,-1.6302013397,0.2320342809,1.2981059551,-0.3229315579,2.4780550003,1.4481487274,-0.8240926862,0.6625467539,0.4279925823,1.1662126780,-1.0683534145,0.6251668334,1.0923655033,-0.3942586184,0.9659493566,-0.9605253339,0.9597508907,0.2220281959,0.0806372091,2.1207196712,-0.9710009098,0.1539418548,1.8333917856,0.5665449500,0.3243786395,1.5739785433,-1.0496633053,-0.3769021332,0.4410339892,-0.3513799310,-0.2858914435,-1.0758993626,-0.2779846191,-0.9377691150,-1.5190898180,0.1464475989,0.5293513536,-1.0593185425,-0.7463225126,0.6748778224,-0.9203764200,-0.8092591763,-0.6285470128,0.6317136884,0.5938884020,-0.2016290873,-1.0690140724,0.8877389431,1.0266020298,1.7298130989,2.1594829559,-0.0914283618,1.1662026644,1.1089171171,-0.5123221874,-0.3319963813,-0.3509967923,-0.8236360550,1.2866132259,-1.0179052353,-2.3028659821,0.2056182623,-0.5770489573,0.6231693029,-1.2684029341,-1.0089328289,-0.6858816147,0.2580859959,0.5197789073,-1.2355266809,0.8098257780,-1.1747789383,1.2804471254,0.4993601441,1.1285796165,-0.1324673593,-0.3163600266,-0.1993279010,1.1616035700,-0.4632444382,-0.3264450729,0.3072538078,0.1358029395,1.4254649878,0.1142488122,-0.0371584930,0.4293601513,-0.9944052696,0.6163930893,-0.1263526529,0.6469143629,1.0459427834,0.6449648738,0.3584982455,-0.3914584517,-0.8582537770,1.0382779837,0.4811164737,-0.7321038842,0.8452780843,-0.8298352361,-1.4297674894,0.8056114912,-1.3645051718,0.2932583988,-0.4535759389,0.8559157848,-1.0738148689,0.2676266730,0.0838424116,0.1785915345,-0.0274679642,-1.0839809179,0.1531840116,-1.6444801092,-0.5802404881,0.6161803603,0.4401788712,-0.0861002505,-0.1942696422,-1.3705750704,-0.3469303250,0.4158354700,-1.9293687344,-1.3931224346,2.0027859211,0.7087925673,0.5379871130,1.9546526670,0.7514656186,-1.3095040321,-0.0490565225,0.5774003863,0.0596319139,0.1235771477,-0.8998639584,1.1102211475,0.3734438121,-0.1030125245,-0.0789468586,-1.3038878441,0.0609854460,0.3799828291,-1.2476456165,0.6118445396,-0.3204786479,-0.4230053425,0.5840607882,-0.6879864931,-1.7932746410,0.9541391134,-2.3621644974,0.4547835588,-0.2293474674,0.9833710194,0.1935296506,0.1290696412,-1.5336457491,-0.7804637551,0.8936599493,-1.0555058718,-0.8772373796,1.6407520771,-0.3166005313,1.5166699886,1.1298456192,-0.3969652653,0.7104807496,-0.9392107129,-0.1705227792,-1.2460235357,1.4000566006,0.2025852352,0.2420491725,0.6935530305,-0.4681382179,-0.7721756697,0.9676588178,0.1198359430,0.1922744066,1.8341497183,-2.7488372326,-1.0611772537,0.1251877993,-0.3508950472,0.8396126032,1.1544494629,-2.1873486042,0.1149946302,-0.6635305285,-0.2694257200,0.6697966456,0.4052609503,-0.4259499311,-0.0662061721,0.0750824437,-2.0473349094,0.5177432895,0.4888772666,0.9255126715,-1.5766785145,1.2748899460,-0.7883622646,0.2249861956,2.6988117695,0.3158188462,1.5834808350,0.1978325099,-0.2180462778,0.5772840381,-1.1148155928,-1.2709002495,1.0019147396,0.1085478067,0.0644170269,-1.2529100180,-0.0105301021,1.6947497129,-0.2921498418,0.6520886421,0.7268299460,-0.5517195463,1.1416976452,-0.8316757083,-0.1236225069,0.7180331945,-1.7250076532,-0.5391926169,0.7702272534,-1.8290551901,-1.0975006819,0.1231060103,0.1836741120,-0.2079072148,-0.3733049035,-0.2890796661,0.1109581962,0.0841258988,0.4721401334,-0.5287404060,-1.0826221704,-0.0720474869,-0.5139278173,0.6535246372,-0.1900931895,0.5698981881,-0.2145587355,-0.1457729191,1.0641998053,1.2511655092,0.8574934602,0.8291519880,0.4578750432,-0.7188019753,0.0051001688,0.1767217517,-0.0890806839,-1.6345053911,0.6368270516,1.6084293127,-1.2352643013,-0.0038276801,-0.9700303078,1.0549601316,-1.4505219460,-0.4465314746,0.8876798153,1.0627869368,0.4874746203,-0.5734726787,-0.5883601308,0.5869722366,0.2755430341,0.0495398827,0.6863536239,-0.8936468363,0.9656808972,-0.0415965989,-0.8703505993,-1.5649480820,0.7539380193,-0.8508267999,-0.7657111287,0.9372233152,-0.5270434022,0.3940381706,0.9115097523,-0.6412190795,-0.7600647807,0.4493492544,1.0575815439,1.2218286991,0.2423966229,0.5654261112,1.1719374657,-1.3715431690,-0.1721050143,0.2998908460,-0.6642464995,-3.1117630005,0.3729720712,-0.3114005923,0.2432861477,-0.3534573615,-0.1880740076,0.5819046497,-0.3220902979,-0.3700904846,1.7209761143,-1.0574181080,-1.2687592506,-0.5830300450,-0.6538046002,0.6858478785,1.8021428585,-0.0014441964,-1.8535352945,1.3842341900,0.5036410093,0.8910794258,-0.2037441581,-0.8835229874,0.2358111292,0.8903995156,-0.6490919590,0.1825971007,-0.4593852758,-1.3794941902,-0.5826588869,-0.2057380974,-0.1274713874,-0.0318536498,0.5356215835,1.3765367270,0.6221526265,-0.5182808042,-0.0778893232,-0.1184563860,-1.5069004297,1.8594160080,-0.6981487274,0.9367927909,0.4855525494,-0.1547571570,-0.5993320346,1.1967276335,-0.2093621343,-0.0519363619,-0.8732603192,0.1621766239,-0.7586136460,1.8687325716,-1.0110545158,1.7136559486,0.2294831127,-2.1291050911,-0.0054081036,1.2772713900,0.4153493345,1.1322646141,1.2953122854,-0.4021786153,-0.8659353256,1.3614841700,0.4887880385,-2.2888154984,0.7517309785,0.7804059386,1.4343571663,1.1280318499,0.4125819206,1.6644282341,1.0138138533,1.1136579514,0.0347738303,-0.0656888932,1.3539829254,-0.8064793944,1.7992246151,-2.0517346859,1.1155378819,0.3399031460,0.1162784547,0.0452033058,-1.8890718222,1.8050925732,0.7577112317,1.9084178209,-0.2905920446,-0.8593422771,0.5828835964,-0.0455377772,0.5747262239,-0.8365653753,-1.5725414753,0.6745752692,0.4211437404,-0.1733942330,-1.3247904778,-0.3337387145,-1.0581274033,-0.1005994231,1.0474176407,-2.9184198380,0.3160714209,0.6893534660,-0.7181006074,-1.0671374798,-1.9399932623,-0.8578689098,-1.2643039227,-1.0543541908,-1.3231947422,2.0581784248,-1.4635936022,-1.8555091619,0.5931416750,-0.0641021878,-2.0411744118,1.4487619400,-0.9831895232,1.1797959805,-0.9788149595,0.5968145132,1.6935912371,-0.7220646143,-0.5078238249,0.8034408092,1.7207052708,0.6739747524,-0.0758223757,0.5789842606,0.9166283011,-0.2725763619,-0.3547967076,0.9579622746,-0.4331351519,-1.4609791040,-1.0095167160,0.1861312240,0.0965674669,-0.5023012161,0.7978777289,1.1768301725,-0.2873516083,-0.3553848565,0.7831780910,-0.3031035066,1.0905922651,-0.3384682238,-1.5104107857,-1.4142198563,0.5335105062,-0.9249476790,0.3325738907,-0.6441063881,0.3561105132,0.1303441375,1.3840107918,-0.7485288382,-0.9498573542,0.4881732464,-0.0074557588,-1.2329013348,0.8200548291,0.0354016982,-1.2749636173,-0.7796729207,-0.9187532067,-0.7172759771,0.4123795033,-1.2273064852,1.5586960316,1.1174397469,-0.2219770998,1.9217811823,0.6616954803,-1.4222782850,-2.0599975586,0.0867804214,-2.2925868034,1.3697549105,0.8076735735,-1.4938260317,0.0309710633,-0.4543955624,0.9160174131,-1.3730944395,-0.7710475326,-1.1737235785,-1.4549480677,0.3577015102,-1.7589148283,0.0929171890,-0.4369859695,-0.3473596573,-1.5033946037,-0.0985980779,0.0101886811,-1.2029874325,1.4330537319,1.2072029114,-0.0131212957,0.7697699666,0.1444311142,-0.0711760968,1.4660404921,1.2070227861,0.2769919932,0.7466009855,0.4890920818,-0.8605375886,-2.1168172359,1.1051851511,-3.1067254543,0.4607944191,0.5312582850,0.7263253331,-0.1775484681,-0.4622008502,0.3566424549,0.8464894891,-0.6093367934,0.3593332469,0.2175244391,0.7817227244,-1.7723919153,-1.4126907587,-0.3926410079,-0.5199172497,-0.5307080746,1.0303177834,0.2988476455,-2.0974349976,0.5404635072,-0.0937601328,-0.1606501788,-0.1147610173,-0.8684297800,-1.1027407646,0.5567104220,0.6773251295,-1.6910611391,-1.4039698839,0.0599403195,1.2236547470,-0.1871442646,0.0593416244,0.8148764968,0.3711216450,0.6319756508,-0.0623319261,1.5143686533,0.9789410830,-0.7867607474,-1.0358027220,-1.3657990694,-1.8243933916,0.4192204773,-0.2765286565,0.3474358320,0.4425532222,-0.2964217961,1.0173045397,-0.0976274237,0.6084778309,-0.5599411130,0.2848835588,-0.2352688760,-0.1809513718,0.1363043934,0.1136598513,0.4099833667,0.8103279471,-0.4263535440,0.4786857963,-0.4269832969,-1.9123014212,-0.8065711260,0.5510292053,-0.0150344782,-0.3349220753,0.0880308002,-0.8002303243,0.3176805675,0.8337778449,-1.5033525229,0.5691682696,0.0770459697,1.5434830189,-0.0361299738,-2.0033481121,-0.7982869744,-1.1101838350,-2.1667561531,-0.8929808140,0.2909214199,-0.0600078702,1.8678102493,0.6645435691,-0.5375238657,0.3015767038,0.8310984373,0.8583566546,-1.2841429710,0.2107521594,0.9149329662,-1.4058991671,-0.7324476242,-1.6634695530,-1.3212348223,-0.8275483251,-0.1830658913,-0.9442102909,0.6262663603,1.0551890135,0.8133642077,-0.4543934464,0.9712342620,-0.3185590208,-0.1727422923,1.0257860422,-0.2464818507,0.5092759728,-0.3984328508,-0.7305040359,-0.5991800427,-0.7956777811,-0.1845896840,-0.0305629540,2.0064487457,0.9583771229,0.0363172144,-0.0191859677,-0.3577366471,-1.2744368315,-0.0630775541,-0.0684572831,1.8726197481,-0.1023565009,1.0510714054,0.4325604439,-0.8658845425,-2.0781784058,-0.0383642949,-1.1078237295,0.5350592732,1.4228900671,-1.1049482822,-0.0801641643,-1.0005115271,-0.4297798574,-0.0559677742,0.2867806852,0.3633767962,-0.2082037479,1.1467409134,0.7982702851,0.0084525729,0.1348223388,-0.0987749547,0.4950430095,0.2327910811,-1.5314847231,-0.8182778955,0.2929429114,0.5952238441,1.5427302122,0.8737509251,0.7998639345,-1.2590091228,0.4758330584,0.5333705544,-0.8768574595,0.3324282169,0.0279628281,0.3362767398,-1.4143075943,-0.2139455825,-0.8838997483,-0.4397753775,-1.3462122679,-0.0181162562,0.5175273418,0.3846479952,1.2185842991,0.6779496670,0.0439935140,0.0856824592,-2.0083913803,0.2829786539,-1.2908842564,0.9698345065,-0.1842066050,-1.7637593746,0.8919836879,0.4382879734,1.2267940044,-0.1170026511,-0.2494598031,-1.7412210703,0.6522830129,0.0244456157,-2.2340483665,-0.4830648899,0.1403207183,-1.3167569637,0.1011837199,-0.6489614844,1.0936598778,0.1544923484,-0.9260298014,-1.3525762558,0.7894437909,0.1807664037,-0.6345968843,1.0378496647,-1.1073594093,0.5320475698,0.1034940556,0.7239211798,-1.7146366835,-0.9290454984,0.5460405350,0.6197391748,-0.6808706522,0.5027135015,-1.1057575941,-0.2300989777,-1.2203605175,-1.9491988420,1.2034761906,-0.4060276747,0.4978751242,0.1822032332,-0.6505709291,-0.3541910648,0.2075365186,-0.0094287647,0.2557637393,2.1727738380,-0.8296252489,-0.3163543642,-1.2971352339,-2.0529043674,0.3074778914,-0.2195957899,1.0099247694,-0.0117843701,-0.1268891692,-0.9868423343,0.3460584581,-2.3466484547,1.3982958794,-1.0281090736,0.6707727313,1.4497638941,-1.6454523802,0.3650892377,0.3026635051,-0.4742977619,-0.4233018160,-0.6639545560,2.2567322254,1.9358763695,-0.4846771657,0.6917907596,-0.0628971905,-1.6291610003,1.3567776680,-1.1375604868,-1.7353007793,0.1414480656,2.2786235809,-0.5899149776,0.1783048213,0.7491911650,1.6066801548,1.2810688019,1.7628934383,-0.9193839431,-0.1078255475,-1.4992743731,0.1968777180,-1.1903437376,1.4254845381,1.0927671194,-3.0272002220,1.9271652699,0.5826958418,0.9965778589,-0.4075433016,0.4611845911,1.0407460928,-0.8860122561,0.8657599688,-0.1595807970,0.4464957416,-0.4966609478,2.9157238007,-0.6837469935,-0.2011281997,0.0069960882,-1.0792711973,-2.0461034775,-0.2763215601,-0.1097814068,-0.2376969159,0.8770941496,-0.9377326369,0.6465483904,1.5600159168,0.4526254237,-0.8150980473,0.0279371645,-0.6981883049,-0.8752954602,-3.2129752636,-0.6134070158,-1.5156295300,0.4352482259,0.1551049948,-1.2635306120,1.9354977608,-0.6287520528,0.5079177618,-2.1001939774,0.3900247812,0.5513725877,-0.5999241471,-0.7899345160,-0.7181108594,0.1940894574,0.6138250828,-0.4738227427,0.8976388574,-0.8623569608,0.7657828927,-0.0611073673,1.1355913877,1.4761710167,-1.0551246405,-0.7247058153,-1.9813483953,-3.0640888214,0.1663405299,0.0124569135,-0.2628451884,0.8943400979,-0.2469936311,-1.9407814741,-2.2188706398,0.4381474257,0.1332459599,-1.7151442766,-1.0381941795,1.9939316511,0.8085494637,-1.1738445759,1.0872621536,-0.1853503287,-1.1145530939,0.4168367386,1.0869874954,-1.6734377146,-1.0069420338,1.4226447344,1.3044387102,-1.2753057480,0.2289368361,-0.3836416304,0.0978016034,0.2819712460,-0.1764324158,0.8378456831,0.2236027420,-0.2701498568,0.6950197816,-0.0077380328,-1.1970260143,-0.3734492660,2.0470554829,-0.4651390612,0.9548599124,-0.2230303735,-0.8019583821,0.3957392275,-1.2221180201,0.4072573483,0.3880814612,-0.6441312432,0.6174584627,1.0846157074,0.6076990962,1.3721759319,-0.0749501362,1.0494583845,0.1591409296,1.2146483660,1.2344856262,0.1549460143,0.9441838861,0.8796211481,-0.5252056122,1.1343315840,-1.0764510632,0.2324069738,-0.1777675897,-1.1545977592,0.7995833755,1.0012146235,0.0061407532,-0.3563856184,-0.2577395439,0.7515842319,1.1220419407,1.0445507765,-0.9168112874,0.6538673639,1.4195749760,1.0493332148,-1.3196792603,-1.7301003933,-0.7242970467,0.6112730503,-1.0061122179,0.7732378244,0.5763732195,0.1579078883,-1.6517345905,0.7781819701,-1.1136115789,0.0968965143,1.1728216410,-1.3469579220,-0.0480953678,0.8859339356,0.1404125839,0.4784304798,1.3342672586,-1.2530455589,-0.5268494487,0.7873428464,0.4130172133,0.1780058444,-0.3267858326,-0.0826260373,-0.3123799562,-0.9598277211,-0.0987945795,0.7427921295,-0.7078848481,0.4165566862,1.3543208838,0.4051081240,-0.8848313689,-0.2286397219,0.2070284635,-1.6439064741,1.2955049276,-0.2987741232,0.9125178456,2.1810588837,0.2293576598,0.8749178648,-1.3403472900,-0.5969886184,-0.4366630316,0.0945704505,1.6732033491,0.4051296711,-0.4160036445,0.9374626279,-1.2810299397,1.7304445505,0.0030098860,0.4869622588,0.8563162684,1.0231707096,0.3627135456,0.2392707467,-1.9643951654,-0.7161080241,-0.2974090278,0.2324644774,-0.3435841501,-0.6919144392,-2.9642279148,0.4640024602,0.0311744493,-0.1404165179,-0.4386716485,0.4086935222,0.1824422330,0.7120854259,-0.6734026074,-0.8858430386,0.3498681784,1.5669513941,0.9241248369,-0.8324046135,1.1146484613,0.9041340947,0.2956512868,-1.0480246544,2.8630208969,1.4399596453,0.5258901715,0.5015463829,-0.3171377778,-0.4555572867,-1.0919431448,0.5997264385,-1.7279002666,-1.0438963175,-0.0601046048,-1.2033896446,-0.1048328951,1.7255532742,-1.2785211802,0.8037407398,-1.1056637764,-0.8321886659,-0.6981978416,0.6783164740,-0.6690093279,-0.4299170375,-1.9805632830,0.3072091937,-1.4346629381,0.2722908854,0.3559779823,0.5817649961,0.9715235829,0.9819499850,-0.3409855068,-1.3291027546,-0.8595953584,-0.2314220369,0.5113080740,0.1259804070,-0.0081106750,1.8190455437,0.8666212559,-0.1718907505,1.0014348030,-1.0544644594,0.0663620755,0.8409745693,0.1343867183,-0.4915670455,-1.1927989721,0.4487790167,-0.3024437428,-0.9536862969,0.0255348217,-0.2934833765,1.4988203049,0.1637242138,0.1977759004,1.1715903282,1.3605438471,-0.7619611025,-0.5757738948,-0.2096434981,-0.7292847037,-1.3548737764,-1.3679894209,-0.4481071532,-0.6871653199,-0.1607779413,0.3172212541,0.0824580118,-0.0072252350,-0.8245114088,0.8536661267,-0.6266992092,-0.1128967926,1.2639377117,-1.9712094069,0.5339668989,-0.2932064533,1.5378162861,1.1618890762,-0.8614155650,-1.0626561642,1.5011287928,0.0631416887,-0.6804838181,-0.1782898456,2.5135641098,0.4825144708,-0.4274825752,-1.5566039085,-0.1402496248,2.8049387932,-0.9801715016,0.5661875606,0.7939589024,-1.0236939192,1.9633581638,-0.1391828954,-0.2312912196,-1.1576309204,0.5281303525,0.9900379181,0.2896926105,0.0827321708,2.2535164356,0.1212359220,0.5381548405,1.5913234949,2.0978007317,-0.7286148071,-0.5753691792,0.0828324556,0.0549454726,-3.2569141388,-1.8817790747,2.0503520966,-0.2591432333,0.7470239401,0.3248349428,-0.4882176816,-1.3225115538,0.4865359664,-1.0414841175,-0.7895792127,0.8525590897,0.7897837162,-0.6213835478,0.0934152529,-1.9919574261,-1.2485752106,-0.9487129450,-0.5130205154,1.1634507179,0.3678902984,-0.7489489317,0.8876307607,-0.1656009853,-0.4229520857,0.7181720138,-1.0354518890,-0.3245650828,-0.0019222775,1.8520420790,-1.1361961365,-0.7627169490,-1.5301635265,-1.6102468967,0.3663013875,-0.2587484717,-0.3138886690,1.6451128721,-0.4497563839,-0.1718848050,-0.4313556850,0.2476296723,-0.4489573836,2.0903165340,0.7821831107,-0.0666693375,0.7762039304,-1.5657635927,-0.3966723382,0.6482068300,1.2220047712,0.2189141363,-0.3889785111,0.1967448145,0.0520267896,0.4590506554,0.5041958094,-0.1697325110,-1.2416745424,0.1428915411,1.6692961454,-0.0450778902,-1.6467303038,-0.8072274923,-1.3155603409,-0.9456545711,-1.0992310047,0.6658183336,-0.5641582012,-0.3236243725,-0.9900243282,1.3859374523,1.8923567533,0.1954327673,-0.5008239746,-0.8863476515,0.0526065789,2.1536448002,-0.2155486196,-0.8135938644,1.8556420803,1.4562864304,-0.0517918803,0.6744711995,-1.7987359762,0.9923582673,0.3135000169,-1.9504567385,-0.1242371649,1.5248242617,-0.1120917201,0.2942447364,0.4463695288,1.0370858908,-0.2582800686,-0.5030901432,1.0489833355,-1.9220529795,-1.3229802847,-1.1880118847,-0.6967065334,-0.1832891852,0.6462819576,-0.9041520357,0.8098919988,0.8147661090,-1.4799150229,-0.3029147983,0.3950447738,-0.3467047513,0.9894205332,0.9808540940,-1.3005290031,-0.9212888479,0.8779946566,-0.5321686268,0.4928537011,-0.1064901054,2.0072026253,0.2842397392,0.0219647326,0.2706302404,0.4453656971,-1.0214610100,-1.1261841059,0.5503368974,1.0498505831,-1.1867488623,-0.3131522238,0.2150351256,-0.7758720517,-1.2624981403,1.5144072771,0.5820170045,0.1279897690,-0.4706283510,-1.0356974602,-0.2843975723,-2.1004853249,-0.1418736279,0.3538064361,1.2380549908,-0.0495617092,-0.2308800519,-0.6746603251,-0.5816107988,0.1941962689,-0.7019876242,1.4929260015,-0.8704730272,-0.3817136288,-1.3759821653,1.1188722849,-0.6615345478,1.7322149277,-0.6132860184,0.0772217736,0.7857915759,0.5138965845,0.8683391213,1.0741430521,1.1444586515,0.2174246758,-1.2567451000,1.2492321730,-1.2271503210,0.2029304504,-0.4345974922,-0.5613096952,0.9899421334,-0.7794497013,0.9226804972,-1.4347459078,1.8226745129,0.2517725229,1.3048853874,0.2598344386,0.8284549117,-0.1853842437,0.9909932017,0.8433710337,0.2945882678,0.1580699831,1.1083993912,-1.2196359634,1.0195169449,-0.7478786707,-0.7492168546,-0.7852820158,0.8240640759,-0.1690352857,0.3865447342,3.0318000317,-1.3104873896,-0.2106412500,-0.0911137834,0.1675297022,-0.4070737362,-0.5210168362,-0.6016403437,1.5758588314,-0.4493618309,0.5540955663,1.4807208776,-0.4585899711,1.5710061789,0.2264640331,0.7540287375,0.2100552619,0.1138534173,1.2335205078,-0.1995334029,1.2598119974,1.9921194315,-0.1144331172,0.1608610004,-1.0974568129,1.5505696535,-0.4277614951,-0.7436270714,-0.5684842467,1.5652070045,-1.9541970491,0.1121145114,-2.2796773911,-0.4204390347,0.3072674870,-1.1443328857,-2.1288378239,-1.4380398989,-1.1068999767,0.7632105350,0.8052682877,0.0307863411,0.5012815595,-0.7604537010,-0.1332142353,1.9456522465,0.9724579453,-1.0146543980,0.4536070824,1.9216108322,-0.9443646073,-0.4025148451,0.5432344079,0.2296927720,0.8836902976,-0.4197762311,0.2263710350,-0.4735622704,0.2265483439,-1.0051529408,1.0260937214,0.0039349413,-0.6438735723,-1.5596687794,2.2677609921,-0.0115529187,-1.9361091852,-1.2214096785,2.3677110672,-0.2835217118,-0.4986249208,0.0987454504,-0.2859016657,0.5878900886,-0.2068942785,-0.4712097347,-0.0293408167,0.1004185751,0.5754767060,1.2288657427,0.7598702908,-0.3827791214,0.2701179087,1.9307528734,0.3766086996,-1.2595345974,-0.1427586228,0.2123726457,-1.0897004604,0.9504085183,0.0233728476,0.0613599457,0.1773449779,-2.6466653347,0.4382828176,1.0714106560,-1.0919705629,0.2308921069,-0.5418452024,-0.6811359525,-0.0733657703,-0.1108241528,-0.6205454469,1.3386415243,0.3169844449,-0.0132978726,-1.6194648743,-0.1214035675,-1.2176237106,2.3920612335,0.2677967548,1.9048371315,-0.1090479195,-0.2812086046,-0.8757746816,-0.1215230674,-0.8371799588,1.3561232090,-0.5343367457,-1.3576158285,-0.0527018160,-0.8965148926,-0.1940020174,-0.1157381758,1.3223857880,-0.0518980287,-0.5180981755,0.7235001922,-0.5034645200,-0.9930452704,0.5033494830,0.5044299364,-0.1784189790,2.0653004646,-2.3807713985,0.2423002571,-1.1575675011,-0.8651419282,-1.2484507561,-1.4254765511,2.6023020744,0.5604815483,1.2961738110,0.7792427540,-1.0478221178,-0.4755157530,-0.2933375537,-1.2906724215,-0.5171805024,1.1661533117,-3.0772411823,0.4945068955,0.8361061811,-0.4539458454,0.6520614028,-0.0636517256,0.1846643686,0.4559874535,-0.7601983547,0.7996939421,-1.3556103706,1.4006017447,-1.2842981815,0.0201086011,-2.4067430496,1.0017011166,-1.2208684683,1.1259891987,-0.1002016664,0.4338685572,0.5633941889,-2.0205998421,0.7079035640,-1.3134320974,-0.7481291294,-2.0741927624,-1.3709870577,0.2138299495,-1.3161886930,-0.5571706891,0.5849643946,0.8160891533,-1.3734140396,0.1693484336,0.4666670263,-0.1848581731,0.6021742225,0.7658632994,-0.2800158262,-0.8746697903,0.6097396612,-0.6713853478,-1.1039898396,1.4990520477,0.1935194135,0.6815602779,0.9476210475,0.0892999396,-0.3394016922,1.2948087454,0.2439201474,2.0538434982,-0.0148545131,-2.3645238876,-1.2313162088,1.4056997299,0.3840621412,1.3106213808,-0.3852375150,-1.1932288408,-0.1657445431,0.0863959864,-0.2528146207,-0.2925288379,-1.4965672493,1.0718343258,1.5679070950,2.0106396675,-0.0910225138,-0.4950281084,0.9399472475,1.1115689278,0.4600949883,1.2392388582,-0.0673111305,-0.8725827932,-1.6198756695,0.1760318428,-0.0825519711,0.2308563888,-1.0177457333,-0.1170732826,-0.8819388747,0.2377493382,1.0289160013,-0.8309114575,-0.8098101616,1.5898245573,1.0980596542,0.3096333444,-0.4698989689,0.5669177771,-0.0059816218,0.4326222241,2.6160898209,-0.5428299308,-0.5957408547,1.2545629740,-0.7029317617,-0.0110392943,-0.3283358514,0.4800703526,-0.4944664538,-0.3524605036,-1.0188369751,0.1142610535,0.4262864292,-0.7915928364,0.4737672210,0.6954224110,1.0050495863,-1.1403791904,0.0269745216,0.8302710652,-0.7582543492,0.0169747900,1.6924520731,1.5741794109,0.1987948418,1.1307752132,0.6800326705,0.3710531890,-0.7827582359,-0.8127122521,1.0480321646,0.3776837587,-0.8211373091,-0.1559403688,1.6256326437,1.0607466698,-0.3728995621,-0.5707845092,-0.3217938840,0.4106550217,-0.9551732540,0.0835519657,0.2593034208,0.7858951092,-0.0355189852,0.4143232405,0.3124325573,-0.6817540526,-1.0727124214,-0.8389334679,1.4706026316,-0.7480475903,0.1054771543,-1.3369356394,-0.0947246999,-2.0778944492,-1.3957155943,0.2285256088,-1.2759611607,-0.3343304098,0.0893022716,0.7450934052,-1.3093935251,2.0228989124,1.3606815338,-1.8446570635,-0.5683281422,0.2735865414,-0.4449757934,-1.9793847799,-0.0671787336,-0.4893623888,-0.6754632592,-0.7179415822,0.2092989981,-1.4558817148,-0.0806349814,1.6811379194,-1.4438048601,-0.7252404094,-2.2249646187,-0.8503048420,-0.1294687390,-0.4447180629,-1.4720023870,0.9454625249,0.5489059687,-0.0052853036,0.4739248753,-0.6366956234,-1.6935415268,-0.7258015275,0.1571865827,-0.6548541784,1.8914365768,1.0652371645,0.4324242473,0.8018820286,-0.5653391480,2.6766371727,0.1969307512,-1.0498875380,2.2293496132,-0.6575648189,-1.5168567896,-0.3831220865,0.0663847551,-0.0127926245,-0.0289653186,0.8270576000,-1.2334251404,-0.1683523655,1.0262917280,2.0759630203,2.6905012131,-0.3199998736,-1.9919358492,1.3505409956,0.4858950078,0.4985644221,-0.0941948369,-0.1956441253,-1.8708121777,0.5297023654,-0.2530247569,-0.7849372029,1.8887374401,-0.1904240698,-1.0549265146,-0.9172002077,2.4479074478,0.0858606398,-1.1978263855,-0.4034654200,-0.3708377481,1.3119311333,-1.9337878227,-0.2400770187,0.7398082018,-0.7001578808,0.2794561386,0.1471390873,1.7028954029,0.4503670931,0.6144703627,1.8867530823,0.1782859117,0.5037370920,-0.8585119843,-0.9124016762,0.9520156980,-0.4813594818,1.0137593746,0.5279722214,-0.4412348866,1.2565177679,-1.2011139393,-1.2171599865,0.3179094493,2.3057527542,0.0162226334,-1.0044425726,0.8488297462,0.8104820848,-0.3958480060,2.2574179173,-0.8400303125,-0.0290416647,-0.8049724102,0.1110918969,0.1712533683,-0.3029280901,0.9060761929,0.4949313998,1.5811786652,1.1496472359,1.7891368866,1.6989605427,-1.2844060659,-1.4256250858,1.9526252747,1.4928870201,-1.0814081430,0.9162069559,2.1888005733,0.4808399081,-1.2371330261,-2.3750650883,-0.5375353694,-1.4709631205,-0.9133584499,0.0837792382,-1.8881543875,0.6336411834,-1.2488851547,1.1549003124,0.9698441625,-0.1542241722,0.0810905918,0.1434110105,-1.2068035603,-0.2149506211,2.2364194393,-0.7714393735,0.1282031387,-1.6601262093,0.2144560665,0.2410408109,1.5626209974,-0.1163768768,0.9992430210,-0.8798793554,-0.5838215947,0.3413982987,0.1006489098,-0.0714010820,0.0203747340,0.4074044526,1.3556555510,-0.2700893581,-0.9345957637,-1.3730533123,1.3425372839,0.5145732760,-0.7645043731,-0.7455899715,-3.1266086102,-0.0076880553,-0.8621249795,-0.9780056477,-0.4648793340,0.1431073397,0.8786411285,0.0829805061,-0.6876224875,0.9151754379,-0.4527014196,-0.3110263348,0.1074373797,-1.1986666918,-0.6184980273,-0.9270381927,-0.2079146504,-0.4372631609,1.1997834444,0.1383371651,0.2398205400,0.4831244349,0.6147862077,-0.6656706929,0.8235280514,-0.5021594763,0.9050056338,1.0267746449,-0.0839773044,0.2934941649,1.4526919127,-0.5227711797,-0.6307641864,0.7450272441,-0.6373867989,-0.2456774414,1.1337466240,-0.9645944834,-0.5025370717,0.2286235988,-0.4299673736,-1.4565142393,-1.0908288956,-0.6438586116,0.9676718712,-0.7037091255,0.0187808182,-0.8907798529,0.9865032434,-0.2691493332,0.2577497959,-1.9395964146,-0.6774106026,-0.9088381529,-0.0304178633,0.2201902270,0.8568982482,0.7380009890,-0.5199701786,-0.7361801267,0.6977995634,1.9890062809,-0.2889457047,-1.9138393402,-0.9784683585,0.7392961979,0.3418764472,-0.1733308434,0.4325277507,0.1451773793,-1.2198106050,-1.4039171934,1.1004782915,0.1187280118,0.6469854116,1.0802356005,-0.1612346619,0.4949934781,-0.0387254246,-1.1470397711,0.9689227343,-0.6782378554,1.5090565681,-0.1389405578,-0.2824213803,-0.1344258338,-0.1288654208,0.1623164266,-0.1821363419,1.1691294909,0.8031123281,-0.5740057826,2.0071382523,-0.1318964064,-0.4972498715,-0.4756318033,0.9943248630,-0.6209115982,-0.6978612542,-1.5944736004,0.3212108910,-2.1554422379,1.2142683268,0.9055288434,-0.3738659322,-1.6954593658,0.8965313435,0.9389824271,0.9087389112,-0.5691789389,-0.5289321542,1.2088074684,-0.8341738582,0.5690646172,-0.8160740733,-0.2697964609,-0.8304342031,-0.7724876404,-1.3361012936,-2.0136146545,-0.7321896553,-0.5210469365,0.4472853243,1.3969060183,-0.0323589183,-1.2332663536,-1.2633476257,-0.5402527452,-0.8164409399,0.8692822456,1.5394263268,-0.6449768543,2.7324981689,2.2829384804,-0.0243462957,-0.4708231091,0.7802814245,-0.8517262340,-0.5438752174,1.3492876291,-2.1100623608,-1.0599167347,-1.5305445194,0.9629749656,0.3840721250,1.6027978659,0.6158267260,1.7967692614,0.6978132725,-0.3588051498,0.5557240844,2.0012843609,0.4117252231,-1.2055360079,-0.8306830525,0.7206227779,0.1442007422,-1.0898617506,-0.5330889225,1.3166472912,0.7317251563,0.7280780673,1.6997103691,0.1930397451,-0.1861350387,-1.4679410458,-0.6894759536,0.5577561855,-2.7302639484,1.7028381824,0.4612136781,-0.4558180273,-0.3445228040,0.0529292449,-0.3675781786,0.8226752877,0.4586767554,1.3503264189,0.8677229285,-1.7889962196,-0.9069355130,-0.1365360618,-0.8261981606,-0.0284881555,-0.7588346601,-1.0901699066,-0.9001386762,0.9422703385,0.5553904176,-0.2856693268,0.4512157142,0.1980567575,-0.6102285981,1.1556385756,0.1393267065,-0.5263919830,-1.1312519312,-0.3653927445,0.8627732992,1.0686572790,0.3649345636,0.0013756203,0.1762937754,0.1261652112,0.0962752104,-0.7591469288,0.0422343500,0.1832052916,-0.1315644085,-2.0348117352,-0.5923904181,-0.5324992537,1.1435881853,-0.9107784629,-1.7445204258,-0.4858583212,1.5137287378,0.4766238034,-0.1806454360,-0.9680721760,-0.3028369248,-0.3065006733,-1.1280874014,-0.7446612716,0.8452233076,0.3190322518,0.8402855992,-1.6233057976,-1.4034744501,0.4287578166,1.1428534985,-1.5632708073,-3.8884437084,-1.2155498266,1.5331667662,0.2305153459,0.6118981242,-0.5459505320,-2.5060958862,0.9057552218,-0.0377277546,-0.2225462347,0.5662169456,0.7287843227,0.8154967427,-0.8809786439,0.6194652319,0.2452322841,-0.1912601143,-1.1317753792,0.6059587002,1.3791689873,1.5434559584,-0.3077296615,-0.0549331531,0.6082119346,-0.4465995431,-1.6164356470,0.7707487345,0.3566562831,-1.0651414394,1.2344359159,0.2838335931,-1.4992698431,0.9605651498,1.3660390377,0.4354725480,0.1872466207,0.6108676195,1.2492525578,0.1859040558,1.0766217709,0.2355428487,1.1754379272,0.0057427166,-1.5887515545,0.3769720495,-0.2890666425,0.1181629524,-1.0365852118,-0.9767994285,-1.2941398621,0.4882920086,-0.9798254371,1.8120832443,-1.2130056620,0.2267473191,-0.1387804300,-0.3132337034,0.4717891514,0.2309700698,0.0566052124,0.1241219193,2.1627066135,-0.6082924604,1.2542783022,-0.3301045597,-1.0780427456,2.4032220840,-0.2280689329,-0.2645161450,0.1353555322,2.1393721104,1.4293290377,2.6570754051,-0.7824953794,0.6957845688,-0.2106664479,1.4867365360,-0.6972081661,-0.0462230630,-0.6337217689,-2.0922307968,-1.1119211912,-0.0705752820,0.3467822969,2.1771509647,1.1771267653,-0.3236551881,-1.8883998394,0.4537965953,0.2125834823,-0.3116625547,-0.0193837136,-0.7874299884,0.0644968003,0.4301182330,2.2707767487,1.0474052429,-0.5718730092,-0.6267511845,1.4229493141,-0.5729410052,0.8310288191,0.5821508765,-1.0076065063,-0.1922570169,0.0469058715,-0.1675707102,1.0838055611,-1.3790389299,1.3507223129,0.6134766936,0.0176201425,0.8428995609,-1.4992263317,0.0356088988,2.2975597382,-1.0299751759,0.2906056643,-0.5603120923,-0.5430343151,-0.5503050685,-2.0349340439,0.3507160246,0.0798382014,1.8635390997,1.4128968716,-0.3009924293,-0.6323676705,1.2433440685,-2.6133000851,1.0574719906,-2.4669671059,-1.0075842142,0.7337694168,0.4244298339,-0.5422949791,-0.5591009259,0.1210958511,1.4105414152,-0.2632221580,0.7265729308,-1.6804473400,-0.7905883789,0.5711280704,0.6042720675,-1.0270519257,-0.5709877014,0.4242979884,1.0850281715,0.5821233392,0.2940220535,1.1921521425,-0.3279542625,-1.0906670094,0.3363183141,-0.4115214050,0.2423718274,0.9718721509,1.3256907463,1.3731383085,-0.3152098656,0.2616109848,0.7625992298,-1.1046898365,0.7405341864,0.3569501936,-0.0304454751,0.4198069572,-1.1654562950,0.3820678294,1.9267227650,-0.4919791222,0.2134685665,-0.5913387537,0.3960608840,-0.3911811709,1.5581468344,-1.7947453260,-2.1093726158,1.1553223133,-0.4462725818,0.3671998382,-0.2049529552,-0.3518499136,1.1037057638,-0.8849042058,0.6334500313,0.8141261935,-0.3845141530,-0.9080251455,2.6200330257,-1.3253928423,0.2427710891,-2.1761622429,0.3425274491,0.4839399457,-0.1631598324,0.8371133208,-1.6910206079,-0.5188969374,-0.5083132982,-1.0096994638,-0.0340005644,1.6234545708,-2.2919981480,-0.8237686753,-1.6870236397,0.2045819759,2.6661920547,-0.3744850755,-1.3754044771,-0.5262570381,-0.1487215459,0.3899958730,-0.3349808455,-0.2147201151,0.8382616639,0.0128131611,0.2007857412,0.4351505935,1.2793378830,0.4645488858,-1.1116894484,-0.2591662705,-0.4701961279,1.0315747261,-0.1856772453,0.9001066685,-1.3104590178,1.3114802837,-1.0081175566,0.3077223003,-0.6241681576,1.4459326267,-2.0826654434,-1.4616817236,0.5706226230,-0.0821249560,-0.4760001004,0.5327296853,1.5234986544,0.1988669932,0.6964995861,0.0093918424,0.7568479180,0.5697199702,-1.8994301558,-0.6445646286,-1.0114517212,-0.3073485792,-1.0358322859,1.1701234579,-0.7295694947,0.1950688511,-0.0414369553,0.7513110638,-0.3562017083,-0.3402531445,1.0202345848,-0.1407631487,-0.7549223304,1.6024886370,-1.5254733562,2.2856884003,1.0988514423,-0.2321708053,0.5067417622,-0.8190221190,-0.9867876768,0.9519258738,-0.6780868769,0.1301680803,0.8194435835,-0.4938240647,1.2405018806,0.6402520537,0.1182226539,0.7945907116,0.0175350085,1.5766327381,1.1100355387,0.5462289453,-0.2211159617,0.5913339257,0.5664343834,0.5663946867,-0.3709756434,0.3571896255,0.7610222697,0.1248397306,0.0199591443,-0.4644696116,0.4498883486,-0.7748786807,-0.2893411219,-1.7340050936,1.2877976894,2.4911108017,0.5305491090,0.7266719341,0.1545901895,0.9030400515,0.3245202005,-0.1829281300,-0.3200109899,0.3289081156,-2.9458432198,0.8093186021,0.3413748443,0.5557262897,-0.1546023935,1.4225945473,1.1587522030,0.2325889766,0.5621083975,-0.9386121631,0.0797256827,0.5854457617,-0.8971057534,0.2960605621,0.4373312593,0.2856488526,-0.2587785721,0.8635243773,0.1729522645,0.4400544167,0.6298682094,-1.7541642189,0.0078843795,-0.4985109866,0.1519829929,-0.4746786654,0.6637639403,1.1471449137,-0.2405385375,0.5008134246,-0.4119012356,-2.0247213840,0.6055507064,-1.0243568420,0.3559515476,-0.8437631726,3.1102230549,0.7065474987,1.5697489977,0.2100787759,0.3337875605,0.3581123650,0.4796786904,-0.1394378543,1.7159233093,0.9836455584,-0.4811730683,1.2921022177,-1.4980825186,0.3234030604,-0.9263525009,-1.9753719568,-1.2800205946,-0.6501467228,-0.4534287751,0.6986515522,-0.6066743135,-0.3495893776,-0.4151754379,-0.1613209397,-0.3423712254,-0.4407419860,0.3743268549,0.0228571836,-0.2950489223,0.4956834912,-1.0063159466,0.8071094751,-1.4763947725,1.2184668779,-1.2583113909,0.4009124339,-0.9315493703,0.3108949065,-1.0812360048,1.2314478159,-0.0053389100,-0.2175952047,-0.3266625106,-0.6629793048,-0.6949992776,0.1832964271,-1.3664089441,-0.7330182791,0.0111999176,0.3048385084,0.3065909445,-0.3205359280,0.3547713757,0.2387059480,0.0288662184,0.3407653272,0.0688019916,-0.6346371770,-2.9236137867,-0.0657542571,0.2381646484,-1.4751336575,-1.0005645752,0.3903593123,-1.5890965462,-0.5685404539,0.7253620028,-0.4060972035,-0.7793660164,-0.9706671238,-2.1348261833,1.4878499508,1.6540946960,0.0158814453,-1.3564432859,-1.2082302570,0.5394089818,0.4960101247,1.3246908188,-1.0439869165,-1.4069757462,-1.2993481159,2.4255983829,0.9048818350,-2.4917924404,1.1100304127,-1.5330778360,-1.1706732512,0.1931117922,0.2511897683,-1.3754106760,0.3725407124,2.4211819172,-0.4166229665,1.7748960257,-0.3293336928,-0.3670873642,0.2008082420,-0.7868642211,-0.7763853073,-1.8592094183,-0.5754011869,-0.4025988281,-1.4596866369,0.6588805914,-1.7689900398,0.5031039715,1.2791875601,0.1997129023,0.0951175317,0.7077681422,-0.3682105243,-0.6120201945,0.2989490330,0.4668666124,-0.0516404063,-0.0072434973,-1.4731035233,-0.6742974520,-0.1071094051,-0.0481653474,0.3348087370,0.7697380781,1.0444390774,0.6389073133,0.7965302467,-0.5480006933,2.1861627102,-1.7186702490,-1.0547710657,-0.7335004807,-0.4895069599,-2.5456478596,0.4805270433,-0.2115930915,0.6833215356,-1.2567358017,0.5541188121,1.4430524111,-1.2658931017,1.3923492432,-0.5163353086,-0.8217576742,0.5181081295,-0.0065804077,-0.1548570544,-1.4562957287,-0.6649558544,-0.2081828266,0.7567382455,-1.9596194029,1.1570088863,2.8178348541,-0.9480741024,0.3081744909,1.0048877001,-1.0370769501,-0.9271890521,-0.5718141198,0.5977467895,-1.5901451111,-0.5971243978,0.7271687388,-0.3104576766,-0.7801139951,-1.4054712057,0.5915648341,0.6452729702,-0.5297361016,0.0908126980,-0.5574408174,-0.8353986740,-1.0422720909,-0.3353568017,0.7226265073,2.0564503670,-0.5431280732,0.6647246480,0.1695094258,0.0573868677,-0.9498914480,-0.3513489366,-3.0019948483,-0.0066395034,-0.4072309434,-0.9640353918,-1.3792288303,1.2849546671,0.4020608366,0.5306547284,-0.1897467226,-0.9025427103,0.2592071891,-0.2822673023,-1.5999060869,0.8814782500,2.0872652531,-1.8682709932,1.2595149279,-0.7809629440,-0.6400290132,-1.4980249405,0.2437685728,1.3451523781,-0.0861069784,0.0169560835,0.8107209802,0.0504279770,1.0673788786,-0.3041729927,0.7378834486,-0.2011504918,0.2117267698,-1.3680343628,-0.7541540265,-0.8309316635,0.0250439066,1.0769543648,0.1214284599,-0.0662044212,0.4549642503,-1.0856857300,-1.6837859154,-0.1463906467,-0.4956187010,0.0208592359,1.2435624599,0.5489192605,0.2411355078,0.3825907111,-1.6864269972,0.6340034008,1.2933397293,-1.2414149046,1.3236659765,-0.4560811222,0.0856558979,-1.0383340120,-0.0595628954,1.1350011826,0.8011539578,0.3942179084,1.4639997482,-0.4066986144,0.4662700593,0.9133059978,0.9119114280,0.2083911151,-0.2895689011,-0.6915959716,0.5094326138,1.2007409334,-2.1352896690,0.2560206056,0.2516901791,-1.3380346298,-1.4319194555,-1.0343267918,0.6933841705,0.0523918718,-1.6278096437,-1.7473222017,-0.5706251264,0.3746893108,-1.4037268162,0.6328114271,1.1285928488,1.0005843639,-0.0091215968,0.2692708373,0.5430057049,0.6359573007,0.6018438339,-0.9794576764,0.4686716497,0.1191736385,0.6245647073,-1.6013067961,-0.3516278565,-2.0193760395,0.8631431460,0.6426948309,-1.2152938843,-0.7574124932,-0.1954472661,-1.4739801884,-1.7282948494,0.7948954105,-0.3243267536,0.4970909953,-0.9655341506,1.0447359085,-1.6254166365,-2.4415161610,-0.0110456059,0.6514555812,-1.2094271183,0.8311422467,0.7294400334,-0.7013913989,-0.9180595279,-1.5018708706,-0.2198044360,0.3838777542,-1.1265043020,1.1347600222,0.8210456967,-1.1263074875,1.6014512777,0.1510402262,2.6066834927,-0.8219428062,-1.2476803064,0.6389467120,-0.4005217850,-0.7135859728,-0.6143370867,0.6910892725,0.2512392700,1.4253145456,1.7152156830,0.3454139829,-0.9362812042,1.2939212322,0.5791168213,-1.5516303778,1.2336236238,1.2780562639,-0.2307296097,0.5151617527,2.3914289474,-0.8676834702,0.1678168923,-1.8745352030,0.0887532830,-0.0148388622,-0.5805263519,1.8545913696,-1.0860618353,0.3407716751,-0.0286480375,0.8063637614,0.1843805462,-0.2964666188,0.2472796142,-0.4235060513,0.4835164249,1.4205632210,0.7961882353,0.1411911696,-1.9163612127,-0.6891729236,-0.6566789150,-1.4901683331,-0.6937078238,1.4161351919,-2.0617113113,-1.0494184494,-0.8323073983,0.8514946699,-0.3380451202,-0.8639111519,-0.8786121607,-1.7560200691,-0.7598963380,-2.0147390366,2.4679574966,-0.2002087235,0.3709254861,-0.1325344741,-0.7265365720,-0.1155025512,0.0221462883,-0.5978046656,1.7831364870,0.3680877686,1.3986713886,0.2212256342,0.8435522914,1.4509996176,0.2756426930,-0.0882249475,1.1780829430,-1.2781015635,0.9661692381,0.0849523470,1.4569551945,0.1979640424,0.0714182109,1.2154024839,0.6585696340,-0.3421055973,-1.0114430189,1.7284212112,0.1652764082,0.0440218449,1.9963196516,-0.2177901864,-0.3685661256,0.3754687011,0.7273710370,-0.0082708513,-0.8066374063,1.3471446037,0.9464960098,1.4551038742,1.7335010767,-0.7727061510,1.2335720062,-1.0976076126,-1.2013162374,0.8994884491,0.8080055714,0.0058319694,-0.7987020612,-0.6682382822,0.3353258371,0.2434836775,1.0560492277,-0.6121442318,0.4928761423,-0.3694842756,-1.8778828382,-0.0021931289,0.4397992492,0.0179698374,0.6603020430,-1.2249333858,0.3797037899,0.0017936496,-1.1764934063,0.1773265749,0.2379674315,1.8248631954,2.0317924023,0.5488117337,0.6360759735,-0.0691221654,1.2608212233,-0.0978059471,-0.4273525476,1.1747417450,1.1928589344,-0.7382788062,-0.1795980632,0.3162508309,1.9766232967,-1.1666280031,-0.3134149909,0.0035257055,0.4764416814,-0.4459216595,-0.0344706252,0.9892446995,-0.7527502179,0.1697129011,1.0399791002,0.8508217335,-0.1022319868,-1.0322203636,-0.8765253425,1.6454482079,0.2713077366,0.0806060657,0.6563324928,-0.3451429307,0.1096281931,-0.4809369147,1.7522681952,0.2002703995,0.1564730555,-0.9563501477,-2.6347720623,1.6463611126,0.2392531037,-0.2259557843,0.3380222619,1.8624340296,-0.1859715879,0.0106931049,0.3789506555,0.1891666949,0.2392414361,1.6173669100,-1.2887517214,0.4338289499,-0.0806743056,-0.4152863920,-0.4792827368,-0.3852518499,1.1886054277,0.2293532044,-0.0757466853,-0.1865629554,-0.6457681656,-0.1063916758,0.2182568908,1.9584716558,-1.3472338915,0.7995253205,0.1375773102,-1.4171931744,-0.0779861510,1.7121382952,0.3812084496,0.1072792262,-0.4451794624,-0.4806461930,-1.0805552006,-0.7667006850,-0.2458909303,-0.5287251472,-0.1539849043,0.4048659801,0.4522774518,0.9267548919,0.0533838384,-0.5965754986,-0.7000019550,0.6710319519,0.8343346715,-0.7737452388,-0.6778567433,0.8769618273,1.4523413181,0.3435254991,-0.9673869610,0.1777562052,-1.7617540359,1.0451806784,-1.2181231976,1.2019933462,1.7208796740,2.4286599159,-1.6599638462,0.6040220857,0.6516717672,-0.2622128725,-0.7239272594,-0.8162904978,1.4671630859,0.2137639672,0.3574137986,-1.0039931536,-1.0461215973,1.1023905277,1.2569910288,1.0668817759,-0.0154753542,-0.9374274015,0.4624779820,-0.1082559749,0.6684598923,-0.5393890142,-2.1180541515,-0.9959486723,0.2782751918,0.2944386601,-1.7939523458,0.4444533885,-0.1882642359,0.5147325397,0.2929969430,-1.8092688322,0.1214284822,-1.0645792484,-1.6098444462,-0.5044631362,-2.3047981262,1.7936631441,0.5146069527,0.9426302314,-0.6366305947,-0.2010298967,0.6305668950,-1.2798579931,0.1300441027,0.1669493467,0.7836005092,0.3279234469,1.2725434303,-0.0735878423,0.5170953274,-0.0156838894,0.2086202949,-0.3578739464,0.5611712337,-0.1845562160,-1.3503365517,-0.2838805020,-1.0690042973,-0.1829974055,0.7866693735,-0.2664945722,0.8257446289,0.4535391033,-2.3860180378,2.7660934925,-1.6022106409,-1.6800652742,0.1000329405,0.2255189270,0.4775266945,0.9800982475,0.0695611909,-0.1636302322,0.7325497270,0.9747005105,0.7435159087,1.4804545641,1.2320071459,-0.8016436100,0.4638025165,-1.3180469275,0.9796977043,-1.6520098448,2.0815844536,1.7063485384,-1.1672502756,-0.2736607194,1.4327979088,-0.1547749192,0.7636130452,0.3382462263,-1.3285471201,0.9728714824,1.3283112049,0.5871783495,-0.3835515380,1.2146409750,1.5588822365,-0.4628805518,0.1570315212,0.7060463428,1.1901321411,-0.6649191380,-0.7949004173,-0.2459549904,-1.0208480358,0.6603729129,-1.2617355585,0.2647471428,-0.2705723345,-0.1136778742,-0.2293915749,-0.2497108281,1.0774041414,0.9895689487,0.7714352608,-2.4308023453,1.0879162550,-0.0287893172,-1.7348122597,0.8923826814,0.2280374914,0.5680179000,0.0501384847,1.2335151434,1.3422961235,-0.3221537471,0.1614855081,-0.6970582008,0.8141419291,-1.5891063213,-0.2522450089,-0.0983667821,-0.1677764803,0.3889777958,-2.3217234612,2.2559692860,0.9853873253,0.1528448313,0.1335994452,0.0960316658,-1.1012336016,2.1527287960,-0.7543258667,1.4281525612,-0.5952357054,-0.6522353888,0.0763411149,-2.4124116898,0.1143976673,3.1385512352,-0.6567717791,0.5438843966,0.2478468269,-0.8372309208,-1.0154943466,-0.0634565204,-1.0248450041,-1.1556870937,-0.7422597408,-1.4936764240,-1.8463222980,-0.9808491468,-0.7588642836,-0.1710610092,0.0920800194,-0.7544130683,0.6935185194,-0.3152893484,-1.2180192471,1.5641496181,0.2795628011,0.5534697771,-0.3952704966,0.7293699384,-0.4047926664,-0.0643341914,-1.7703485489,0.1241352558,-0.9134722948,0.3001177013,0.7077474594,0.8252443075,-1.1510851383,-0.5846912265,0.2272734344,-0.1831062436,1.2051370144,-0.1876637787,-0.5765454769,-1.0280808210,0.3914548457,0.9839670062,1.0020608902,-1.4458919764,1.3140779734,0.0528018363,0.2362228930,-0.4548761249,1.6524966955,1.7901469469,-0.2248424739,0.1754400581,0.9779208302,0.5776523948,0.9024821520,1.1635148525,-0.3024394512,0.3784768581,-1.7918648720,0.3735060096,1.0666931868,-0.4633731842,-0.5668267608,0.9597026706,-0.7974790335,2.2758290768,0.9152048826,0.9018004537,1.3983670473,-0.9318888187,0.3431453705,-0.2198560387,-0.6310589910,-0.5225726962,1.9764684439,0.3742882907,-0.4727636278,0.2065766305,-0.2785574496,0.2065834999,0.3348022997,-1.0158301592,0.0557430349,1.2103167772,-0.8823601604,0.5185846686,0.2634567320,2.1054568291,0.3655582368,1.0914030075,1.0806419849,-0.7831611037,-1.0495216846,0.4184381962,-0.0781125873,1.3796223402,-2.1329607964,-0.6260906458,0.1810334921,0.5751695037,0.2468598932,-0.1141770110,1.3287128210,-1.1890742779,-0.4207553864,0.7122940421,-0.9073532224,-0.3651553094,-0.4226305783,-0.0830838680,-1.0728796721,-0.1376402676,-0.7822508216,1.2550245523,1.8266563416,0.7291188836,0.8544880748,-0.2885992229,-0.6249886155,-0.1918189228,1.0057471991,1.3464815617,-0.0350044779,-0.7850279212,1.2537226677,-0.7549847364,-0.7763412595,-0.5457606316,0.8749659657,-0.1705278009,-0.1407030970,0.1812559962,-0.2123323083,1.0182181597,-1.2406775951,-1.7901406288,-1.7229549885,-1.9905031919,-0.5597758889,-0.6072100401,-0.2092664540,-1.9350706339,1.2083387375,-0.7741381526,0.7506406307,0.9133481979,-0.7715125680,0.6030091047,0.5493309498,0.4792211056,-0.2988275588,0.9531223774,-0.0966653600,-1.4549390078,-0.5645372868,-0.3757342100,1.3526890278,0.7144587040,0.2461370528,0.0577381253,1.6676069498,-0.5236766338,-1.4429916143,-0.7393116355,-1.2088468075,0.0605625138,-1.5278388262,-0.9210611582,-0.2517165542,-1.9440078735,0.6988514066,0.1982673407,0.3086035848,0.5408528447,-0.9238742590,1.0745069981,1.2209699154,-0.5641684532,-1.5028772354,1.5196889639,0.2270999849,0.5806286335,-0.1388664693,0.2372200936,0.6519583464,-0.1114310697,-1.2452012300,0.8265328407,-1.1701641083,-0.9429509640,-0.0014479960,-0.0517590232,0.7875321507,0.2763226330,-0.3950987458,1.4887293577,-0.0903558433,-0.6510680914,-1.0548905134,-0.1655217260,1.2616093159,-0.0127523160,-0.1354828477,-0.2113614231,-0.6180521846,-0.0597930215,-0.2407428026,-1.5077199936,-0.1971070170,-0.6861489415,-0.0931828097,-0.8914435506,0.1905655414,-0.8744983077,0.0098695075,-0.3797313571,0.7740601301,0.0845667273,0.2132222652,2.2988576889,-0.1039733142,0.7457541823,-0.8987375498,-1.3461180925,-0.8154997826,-0.5025764108,-0.3514509797,-1.0883080959,0.8634200692,1.5210120678,-0.8854886889,-0.7128968239,1.0747821331,0.7041067481,0.8238183260,0.4915956557,-2.5970296860,-0.5477147698,-0.9649059772,2.5200729370,-0.3640636206,0.8815293908,-0.9766589403,0.4918274581,1.3674652576,1.0179756880,-1.2977014780,-0.8691310287,0.3466084301,-0.6623682976,-0.3450996876,0.6613887548,1.5178869963,0.4877279997,0.9343072176,-1.0097370148,0.6456452012,0.3174564540,0.7257652283,-1.3117456436,2.4636328220,-0.6551507115,-0.2571562529,-0.4730632901,1.5332181454,-0.7421475649,-1.1132484674,-0.5764532685,1.0589469671,-1.1869277954,-0.5670490861,0.6283428073,-1.1403493881,-0.9345607162,-0.4807460606,0.3763595819,0.4279716611,1.1986782551,-0.2374680340,-1.2819801569,0.1377163678,0.4830263853,-0.5013511777,-0.6719954610,1.5218192339,-0.1730282307,3.6219646931,-0.1248321682,-0.1220605448,0.2830874920,1.6604256630,0.5359668732,1.3583760262,1.6301083565,0.6225463152,-0.9911639094,-0.8537741303,-0.6471802592,1.8175919056,-0.1935535520,0.0851218626,-1.0140290260,-0.1194371432,-0.7439462543,0.3609744310,0.1996553689,0.4417337179,0.0744811743,0.6526217461,0.5125229955,-0.2765215933,1.2034013271,-0.4930281639,0.6316803694,-0.8473200202,1.1323636770,-0.9325317740,-0.1085536703,0.2190643996,0.4257893264,-0.1137780547,-0.8615435958,-0.6558609605,1.7273952961,-1.1156474352,0.4715724885,-1.2323323488,-0.9245020151,0.2340586185,0.4171338379,0.5103055835,-0.8030940890,1.3934131861,-1.7207546234,0.8516317606,-0.7090355754,1.3007886410,-0.2409402430,1.5606890917,1.2331166267,1.1565121412,1.1419471502,0.4737171829,-0.0646478087,0.7538887858,1.1985429525,-0.8085051179,-1.7302092314,-0.7214023471,1.0235490799,1.9192208052,-0.0632185340,0.5950103402,-0.0955924690,0.0445052236,-0.2363787144,-0.6596962214,0.9489222169,-1.8176273108,0.3249565661,0.5321244597,-0.2519031167,-1.0410438776,0.3578720987,-0.2318406850,-0.4318566322,-1.0400800705,0.0432879440,0.2405186594,0.6484411359,-1.4198623896,0.5731082559,1.6903151274,-1.2536605597,0.8934561014,-1.7532277107,0.3545506299,0.3714213669,-0.4971423745,1.3633073568,-0.8850327134,0.5577733517,-0.0002178800,-0.7989585400,1.0268219709,-2.0480480194,1.0952467918,0.4634559453,-0.0991200507,-0.2166755944,-0.1800895333,0.2274161875,-0.1490253955,-0.1709231734,-1.1723672152,-0.7563461661,-0.4348413944,0.8389985561,0.5278283358,-0.0855753422,0.6674067378,0.1275337189,0.1393093020,0.0813582242,0.1333002299,-0.5479602218,-0.8135802746,-0.7446947694,1.0566511154,0.8022787571,-0.8659976721,0.3931536376,1.5148967505,1.2328475714,-0.4744767845,-0.0396147296,-0.3586524427,0.0859779865,0.8946546912,-0.2486164570,-0.3365946710,-0.6286838055,2.3325791359,-0.0751589090,-0.1462642252,-0.6692479849,0.1297315210,-1.5226391554,-0.3211878538,-0.5852881074,-1.2526824474,-1.5365287066,0.4731831849,0.8354712129,0.1848156005,1.1968663931,-1.0546797514,-2.1675684452,-0.7382207513,2.6727535725,0.5967551470,2.2287185192,1.3105413914,1.5683557987,0.3387235701,-0.5780242085,-0.9694200754,-0.0542619228,-0.7023670673,-0.3473659456,0.1283979267,0.9860328436,1.8086926937,-0.2518500388,-0.7601784468,-0.6687451005,0.5814293027,1.2638016939,-0.0553046763,-1.8108512163,0.1957877129,1.5420058966,-0.6303429008,-0.0445778482,-2.4625091553,-0.2039029151,-1.0149819851,-0.3121074140,0.7373507619,0.0069484706,1.5634709597,-0.4883809388,1.6265809536,0.4967319071,-0.6871525049,0.5922659039,0.8526945114,0.6075148582,0.2839967012,-1.9847686291,1.2767001390,1.7508671284,0.2804496586,-0.0903932750,0.7302295566,-1.0770375729,-2.1788797379,0.0533087961,0.5184302330,-0.9022838473,0.7812830806,0.7872949243,-0.8752070665,-0.7053655386,1.6697065830,1.4777274132,0.0331411175,0.4019483328,0.0795291141,-1.7472738028,-1.6027665138,-0.8463315964,-1.3971626759,2.2727987766,-0.7152912021,1.2079150677,-2.5324273109,-0.2201086730,-0.8586494327,-0.6715086699,1.0920449495,-1.4367811680,-1.1334613562,0.8020817041,-1.4378912449,1.9518941641,1.0430494547,-1.9164535999,-0.7914465070,0.4349558949,-0.6983420849,0.8788402677,-0.6938580871,-1.6382540464,-1.3454945087,0.3314038217,0.7301472425,-1.6229919195,2.4571003914,0.9816461205,-0.1934306026,-0.6380050182,-0.6916678548,-0.0730158985,-0.6435752511,0.2499887049,0.9054161906,-1.9165015221,-1.7656427622,-0.9856516719,1.3381596804,-0.0236687176,-1.7433477640,-0.4669364989,-0.3746806979,-0.6021181941,-0.3435127437,0.5429405570,1.6806927919,0.3754731417,-1.7427126169,1.1184897423,-0.0914018527,-0.2547079027,0.0444798470,1.2944244146,0.9571075439,-0.9411146641,0.0178249963,-0.2201198488,0.2704386711,0.1415091902,0.7426109314,-0.1449626833,-1.3681911230,-0.9975286722,-0.7867771983,-0.1971043646,1.1083836555,-0.2619640827,-2.1241817474,0.5822571516,-0.5158762932,1.4686164856,0.4476768076,0.1179724336,0.8681359887,-1.6180802584,1.3157556057,1.3680702448,1.2255792618,-1.2426224947,-0.5846403837,1.3134173155,0.8510391116,0.0566169582,0.5327958465,0.5105850697,-0.0755836368,-0.1719992310,0.5381946564,0.0138440710,1.1242705584,0.3068951666,1.7257516384,0.9957590103,0.8762136102,0.1220595390,-0.5659295917,0.2277036905,-0.5829985142,0.2336221337,0.5245922804,0.6979594827,1.2982851267,0.6850818396,-0.5728030205,0.5248136520,-0.3277309239,0.4528121650,0.4383815825,-0.9423355460,1.1154732704,0.1451929361,-0.7689108849,0.2972296774,-0.5694436431,-0.1806611866,-0.9186413288,0.7959067225,0.4119114578,0.5434252620,-0.0524524115,0.5843896866,-1.5658318996,0.2693421543,-0.2651713192,-0.6462969780,0.9390318394,-2.3189029694,-1.9477659464,0.9899591804,-0.3546177149,0.1199787855,-0.4854714870,-1.6318863630,-0.1745455414,-0.4783552885,0.1253313422,-1.0133267641,-0.1568865627,-0.9031783342,0.0745390579,-0.1635649502,1.6315912008,0.3370809257,-0.5317426324,0.1358670890,-0.7163832188,-1.0768035650,-0.9230828881,0.2219968587,-0.5246748924,0.6829332709,-0.2877226770,0.2317267507,0.4880829155,0.6605032682,0.7699363232,1.2062032223,-1.3281532526,-2.0703158379,-0.3716563880,-0.3761352897,-1.0077327490,0.0220914204,-1.0736358166,-0.5218760371,-0.6671406627,-0.3167509735,0.2668158710,0.7138624191,1.6762847900,0.5364630222,0.7131706476,-0.4521187544,2.2354354858,1.0070247650,-1.4814945459,-0.9544055462,0.5616211295,-0.4388044178,-0.5384815931,2.5188238621,0.3578646779,1.0072035789,-2.3006868362,-3.0283837318,0.1582179517,0.0786268860,0.2975986898,0.3020519316,0.2252492458,-0.1169260144,1.1698973179,-0.2377756834,-0.9876517653,0.9444678426,0.7366877794,-0.2140249312,0.6662899256,-0.1698795259,0.1597381830,-1.1117084026,1.5774035454,0.7038061619,-0.8269827366,-1.2444053888,0.6046368480,-1.2741203308,-0.0075483327,0.1214978695,0.1185389608,0.1672204137,1.4469048977,0.9831426144,-1.2359778881,-0.0607702211,1.0580685139,2.1470263004,-0.6063710451,0.3545796573,-2.0619568825,-0.6264045238,-0.6515289545,-1.4760322571,0.6560636163,0.1312911958,-0.6359328628,1.0950239897,0.8734268546,-0.0087732999,0.2270132303,0.2920324504,-0.5871611834,-0.6498407722,-0.4679347277,0.7037794590,-0.3263746202,-0.6026700735,1.5626196861,-0.3909978867,1.2148580551,-0.1074242890,0.2417563349,0.8551151156,-1.1614420414,0.4012592733,-2.6826231480,0.2988246977,1.0284411907,0.9653552771,0.0241382923,-0.6744859815,0.0252455268,-0.5691433549,0.9945526719,-0.7929928899,-0.0188295841,1.7620083094,1.1326615810,-2.1382300854,-0.4516732097,-1.7331445217,0.9578317404,-1.9982173443,2.0854375362,-1.4002338648,-1.2631605864,-0.2547115088,-1.1759921312,-0.1266184151,-0.1415224522,-0.2777317166,1.8104367256,-0.8818674088,-0.1876362264,-0.6606785655,-0.8318985701,-1.3102446795,-0.1048089117,0.2003894299,-0.4948415160,-0.6170853972,0.3395398855,1.1125634909,0.8719718456,-1.1671817303,0.1546787918,0.1532687992,-0.7465642095,-0.3725242317,-0.5178562403,-1.1987986565,0.6836966276,-1.4780657291,1.3997263908,-0.7279686332,-1.4971139431,-0.7506303191,-0.8950587511,0.3868414760,0.0534542501,-0.2117811590,-1.5080431700,-0.7876279354,1.1501566172,-0.3116948903,-0.3763196170,-0.9797936082,0.5246469975,-1.2769556046,-0.6016128659,0.0543154590,-1.8809392452,-0.8625527620,-0.4563853145,0.5321665406,-0.2617306411,-0.6068289876,1.8533170223,-1.9562035799,-0.5140955448,0.4745437205,1.1698094606,-0.5805649757,-0.3693213165,-0.9228043556,-0.7345765829,0.5629547834,0.3122575879,-0.3497559130,0.9135907888,-0.7911636233,0.1847207397,0.3809929788,-0.8879823089,-0.1338323057,-0.3490095735,2.1165955067,-3.1589138508,-0.5436285734,-1.7455108166,-2.1049289703,-0.1302325428,0.4640696049,-0.7451955676,0.5188206434,-0.4138991535,-1.8001177311,1.1008683443,0.4474474490,-0.1786603630,-1.0551677942,0.5523467660,1.5565564632,-1.0508276224,-1.2913016081,0.4513285160,-0.7465084791,-0.2419379652,2.0543141365,-1.3258612156,0.8564865589,-0.7004728317,0.9789661169,0.2529447079,0.3756442666,-1.1552598476,0.2251007259,-0.6217958927,-1.2075531483,-2.1160759926,-0.5377485156,-0.4078000784,1.2833286524,1.2621468306,1.9884413481,-1.9587829113,-0.3365916312,-0.3414989412,-0.1485837251,-0.5208674073,0.9343284965,-1.1504461765,-0.7001681328,0.5539194942,-1.4810436964,-0.6036912203,0.9199162126,-0.3080572486,0.4597660601,0.0606138296,-1.4523596764,0.0182523839,0.3977748454,0.2504182160,-0.0457268581,0.1204058975,0.8092479110,0.7734143734,0.7709316611,0.4113011956,-1.3937188387,0.4055718184,-0.4176865220,-0.3609451056,0.2942406535,1.7711349726,-1.3721432686,1.8080185652,-0.6679579020,-0.6259421110,-0.4016775787,1.0835027695,0.9990584254,-0.1049466804,0.0027226934,-0.8598833680,0.5965404510,0.4464733899,-0.9998130798,0.3802746236,0.1903662384,1.0069195032,1.7607945204,-0.8770285845,0.0015625909,0.1690426022,0.4705689251,0.2795690894,-0.3947535753,0.2917557359,0.4942769408,1.7180832624,1.8849114180,1.0528432131,0.0112085836,1.9515383244,-0.8529167175,2.5300376415,0.9883424044,1.5475788116,2.0330502987,-0.4147629738,-1.7989500761,1.3826758862,-1.0269834995,0.5999916196,0.9867404103,-0.2702056170,0.3600501716,-0.7583336234,-0.5758518577,-1.0197910070,0.6279180646,0.5060213208,-0.1114388481,-0.7055656314,-0.1577177644,1.3694399595,-0.1905371100,-0.6570346951,0.3182444572,0.6559875011,0.1073881984,-0.8325852752,0.7134782672,-0.0001436342,1.1665621996,-0.9761604667,0.4922949076,0.1762838662,0.8394795656,-0.9334070086,-0.6946863532,1.1474127769,0.0837756693,1.0693693161,1.5215953588,-1.8261275291,-0.5862078667,0.8109973669,-0.0215907376,-0.3971729875,0.1443639547,0.7105217576,-1.5630483627,0.8906173706,-0.0771133453,-0.7070862055,-0.6657230258,-0.2032502890,0.4337565005,0.6398509741,-0.0961007103,-2.0606822968,-0.3801790178,-0.7287710309,-1.1679856777,0.8636924028,2.0345959663,0.8056660891,0.0790649727,0.1292844862,-0.2441989928,0.6843965054,-0.0466990806,0.2574798167,1.7390024662,-1.0807328224,0.3902039528,-0.0904696211,-0.6639072299,-0.9807626605,-0.5844775438,0.7836155295,0.0463408977,-0.5736125708,-0.2846724689,-0.8746067882,0.1992656440,-1.1177204847,1.5649669170,0.1965961903,0.8586657643,-1.4847395420,1.4379744530,-0.3827043474,1.0768358707,0.5697392225,-2.5409808159,-1.1086584330,-1.4590468407,1.9061291218,-0.4039606154,-0.3141342402,-0.6788002849,0.4221759439,-0.6185811758,1.2265267372,1.3419264555,0.9365577102,-0.8626218438,0.0714093968,0.3579553068,-0.7517531514,-0.1326746047,0.4824095666,-0.1637495905,-0.2193266600,-0.7112823725,1.6637583971,0.6090463996,-0.3620583117,0.7486864328,1.4172860384,-1.3887069225,-0.4702116251,-1.8121628761,-0.4067336619,-0.4508442581,1.6809742451,-0.6856459379,-1.0960397720,0.6169106960,-0.5126711130,0.7367286682,-0.1227271408,-0.9381112456,0.3682388067,0.5237234831,-0.1901168376,-0.7895736098,0.0390522219,0.1888903528,-1.9014731646,1.7833452225,0.3512957990,0.0422377065,1.1961449385,-0.4127797782,-1.7096159458,0.4396434426,1.6618039608,-0.2889024615,-0.4047232866,-0.3430258334,0.4502983093,-0.8993715644,-0.2819147706,-0.6409164667,0.3729336262,-0.7371287346,0.4244229794,-0.9481826425,1.7409205437,-1.9509413242,-1.0926223993,-0.7474913001,-0.3169195354,0.2738073468,1.0230799913,0.5049025416,-0.1530090719,-2.4460172653,0.3451049626,-0.7874396443,0.4234744608,0.8010879755,-0.7266035676,-0.0287357550,0.5261215568,0.4974059165,-2.2859344482,-0.5524745584,-1.6442023516,0.2132236212,0.4708622992,1.5447111130,-0.4303492308,2.1815609932,0.3391433060,-1.6993885040,0.5555101037,0.1248709261,-0.5245776772,-0.8237133026,0.0852307156,-0.6021905541,-1.9891923666,-0.2042742521,0.0665240660,-0.5630695820,1.3211286068,2.6150777340,-0.8884028792,-2.7250652313,-0.7953874469,0.4453403652,-0.0466313288,-0.8660322428,0.9148148894,1.3114209175,0.0853873789,-0.0865378082,-0.8240836263,1.5242363214,-0.1447027177,1.0685709715,0.6887947917,0.3693505526,1.2384396791,-0.1528254151,0.4717794359,0.2557708025,-0.2342842966,0.2985180914,1.4603908062,1.1556718349,-1.0860780478,0.8485520482,0.8186067343,-0.4889854193,-1.1824482679,-0.0552532971,-2.0472691059,0.3136096597,0.0956232697,-1.2475279570,-1.0659813881,-1.4372975826,1.3939661980,-1.5543537140,-0.2287389338,0.8398764133,-1.0875582695,0.3782944977,0.5431341529,0.8844070435,0.0712101758,-0.7438293099,1.4641083479,-0.2514543831,-0.7803747654,-0.7884621620,-0.5040911436,0.1236531809,1.3709342480,-1.2878456116,-0.0993014053,-0.5816023946,-0.1617263407,1.4658393860,-1.1843436956,0.1996217370,0.7093799114,0.6478058100,2.4174399376,-0.9946103692,0.9256981015,0.2354338616,-1.5637323856,-0.4097500741,0.9532274008,-1.7446402311,0.3983721733,-0.9129959345,-1.8641510010,-0.0650398284,1.8328038454,-0.3282188177,-1.4489845037,-1.2304841280,0.3586666584,-0.2042628974,-0.3145161271,0.9496209621,-0.3764860332,0.7279493213,-0.8917263150,0.3433779478,1.1824033260,0.0408701040,0.4175057113,-0.6440492272,0.9012810588,-1.0648696423,0.9149550796,-0.5418872237,-0.3558420837,0.8348129988,0.1753689051,0.0140529331,1.4487305880,-0.0789629817,-0.0814047679,-1.5064017773,-1.0320729017,0.5171748996,-2.2602293491,-1.7476472855,-1.5101404190,0.3992056251,-1.5515506268,0.7638925314,0.6154313684,-0.2482495755,0.0194012262,0.0098772850,0.4108774662,-0.0947879553,0.4412504435,0.1092329770,-0.7233854532,-0.5602306724,0.9036995769,1.2431905270,0.0285293981,-1.6290500164,1.2356460094,-1.9054615498,-1.5224015713,0.4625911415,0.1904840916,1.5625308752,0.4856654108,-0.0246778559,-0.1548504829,1.2992460728,0.1943925023,1.2544627190,0.6112693548,1.4020404816,0.8133472800,-0.7494078279,1.3856695890,-1.6867324114,0.1892388910,1.2696735859,-1.3791120052,2.2082250118,-0.9735414386,-0.2286798209,1.3652757406,-0.8393858075,-0.6100654006,-1.1962810755,-1.3717755079,-0.7170159221,-0.8828419447,-0.3372710645,-3.3247058392,-0.9084119201,1.6302831173,0.8176118731,-0.0111802975,-0.2251095921,0.5649040937,1.4012663364,0.7089836597,1.2665133476,-1.1005299091,2.4844765663,0.1761873364,-0.0088386908,-1.3534541130,0.5137736797,-0.5706036687,0.8757398129,0.0449838303,2.4435112476,0.2079927921,-1.9996918440,-0.6087223887,-0.6385773420,1.6442676783,-1.4658410549,-0.2207080126,1.0008113384,-0.7584369779,1.4786957502,-0.4342084229,-0.0399412848,0.0586465672,-0.5101655722,0.0631559715,1.0645006895,0.9889351726,0.7960072160,0.9740015864,1.7200036049,1.4311993122,0.3660484254,-0.0995860323,0.2606077790,1.2410806417,-0.9831237793,-1.6199501753,-0.1432815939,1.0276182890,1.9477783442,-0.1715546250,0.9028071165,0.9455989003,1.7721807957,-2.3770511150,0.0422005840,-0.2649149299,0.1626689434,-1.7165741920,2.0142836571,1.2888416052,1.3182411194,-0.2988808751,-0.9702196121,-1.3273938894,-0.1208585128,0.1018750072,-0.3974203765,-0.9312421679,1.5495072603,-0.2257322222,-1.5345994234,-1.2101567984,0.5442845821,2.3244996071,0.6885232925,-0.3893218637,0.5857572556,0.8583837152,1.1273128986,1.5923551321,-0.6475256681,-0.4328983426,0.3193134367,0.3736357391,-0.0583607033,0.9926229119,1.1097198725,0.0237506758,-0.3030325472,-0.4242801964,0.0150921475,0.8205795884,-0.1523793340,-0.1743751317,0.1002234742,-0.5741091371,0.4680297673,1.3265185356,0.7591851354,0.7968487740,2.4510006905,1.0455299616,0.1616481096,0.4591381252,-0.5118848085,1.3974906206,0.0444282293,-0.2367054075,-0.5850853920,-1.7926813364,1.0850917101,-0.0153463064,0.8085225224,-0.0650879070,-0.8191810250,-0.3907743394,-0.8836235404,0.8422560096,-0.9372207522,0.1334853172,-1.4340825081,-1.0172991753,-2.9318859577,1.7403756380,0.6695041060,-0.5234505534,-0.4980879426,-2.2248792648,-0.3270122707,1.4429141283,0.0257454775,0.9544253945,-0.1030614227,-0.0222805012,0.8595652580,0.7901018858,0.0139517374,-1.5680670738,-0.7101589441,-0.9396982193,0.5569794774,1.6559907198,-1.0252135992,-0.5993455648,0.7724023461,-0.0052897935,-0.7790496349,-0.5721173286,-0.1611474603,0.1147837266,-0.4912993908,0.2682353854,-0.1408393532,1.1909285784,0.1201085225,-1.1754007339,1.0866947174,-1.3127019405,0.5852900147,0.4494962990,-0.0917720422,1.5772259235,-0.0028221165,-0.9338590503,0.4315549433,-0.7911572456,-0.7792272568,0.4389078021,0.2131284922,-0.4663459361,0.0148027567,0.6259170771,-0.8518497944,0.0935833678,0.2924852371,0.3590088189,-0.5718174577,-1.1496263742,1.2068468332,-0.1130583733,-0.2927685678,-0.6665418744,1.2084698677,-0.5074796677,0.6037199497,0.5330540538,0.0671800524,-3.1931815147,1.3412168026,-0.0472922698,1.2909542322,-0.0951048583,-0.3293198049,-0.3368616104,-0.6205972433,0.1633470356,1.0400021076,-2.4417200089,-0.1430457532,-0.3949324489,1.5079751015,-0.0933669582,0.7111688852,0.4588423967,1.0893750191,0.6711891890,-0.1723787934,0.3056735396,-1.0339529514,-0.5147407651,-0.0625401884,-0.4944783449,-0.2281164825,1.8994734287,-1.1122488976,0.8064043522,-0.9070198536,-0.7515420914,0.4880173504,0.5601146817,-1.6990242004,-0.5601556897,0.0330446623,-1.1386178732,-0.0413848385,-0.4364368320,-0.0484491810,-0.8381305933,-1.9084656239,0.3641952574,0.4897067845,0.2050378919,-0.5196628571,1.1518422365,0.2143942863,0.6736453772,1.3390365839,-0.9382547736,-0.5802168250,-0.2404362857,0.0388144962,1.2864723206,-0.7813917398,-1.4558441639,-0.5873885751,0.9965207577,0.0476341769,-1.6072156429,-0.6474640965,0.7038937807,-1.2242337465,-0.3836533427,-0.3961207867,-1.0149700642,1.0830006599,-0.2466066629,1.1158556938,0.6452320218,-0.1450219601,-1.9907687902,0.2957869768,0.7098045945,-0.0348816589,0.7518092990,-0.5935727358,-1.2528318167,-0.5177393556,1.5163943768,1.2004730701,-0.9606300592,0.4015153646,0.4090261459,-0.0634377599,1.2732558250,-0.3282780945,0.9231778979,0.2382800877,0.8408981562,-0.7702533007,0.4584795237,0.1061263978,0.0769923702,0.4656309485,1.1552935839,1.3841668367,-1.3653978109,1.5498673916,-0.3918735981,-0.0810078084,0.6211736798,0.7627735138,-0.0829695016,-0.9319149256,-0.5280153751,0.2751726806,0.3330031931,-0.7518762946,-0.1446366012,0.1988864541,1.2466605902,0.4027922451,-1.2030483484,0.4533600509,0.7313265204,1.0936702490,0.0037894470,0.0050270087,0.0251088440,-0.0352713205,-0.5701832175,-1.9719990492,0.4366341829,-0.1345392913,-0.1814393252,-1.8553251028,0.0617607608,0.6062008142,-0.4244881868,-1.0817292929,-0.6807661653,-0.6261473894,-0.0540766194,0.2786253989,0.8372100592,0.0017704318,0.5310544372,0.6352730989,0.9221379161,0.4457738400,1.5647474527,-1.6837626696,1.2410209179,-1.0796965361,2.2747447491,0.5723548532,-0.5651129484,-0.1718373448,-1.6550757885,-0.3474877179,0.6547319889,-0.7872471213,-1.5143712759,-0.3837069571,1.4854574203,1.3285131454,-0.2988612354,1.3719160557,-0.3424156010,0.4441322386,0.3561630547,0.3292013407,-0.4663069844,-0.3964741230,1.4079635143,-0.0168015026,0.2487754226,-0.6136851311,-1.5734347105,-0.8163513541,-0.2254180610,-0.0962739587,0.2816110551,-0.9428220987,0.1577043533,-0.2643011510,-1.3468902111,-1.6785992384,0.6566977501,-0.1757939309,-0.4243683219,-0.8836905956,0.1485837400,-0.7256431580,0.0940819830,-0.7429986596,1.3145816326,1.5680030584,-1.3079791069,1.0795658827,1.6322503090,-1.3270734549,0.2825237513,-1.8363772631,1.4280408621,0.8779270649,0.1488070041,-1.1796215773,-0.7179731131,0.7257335186,-0.0448335893,-0.4180825651,-0.9488744736,1.3562891483,0.6680294275,-0.4531681240,-1.1939545870,-3.9058244228,1.6860084534,0.0763802007,0.8831697106,-0.0188103337,-1.6418547630,-1.3217287064,-1.7891827822,0.3362942636,0.3228811324,-0.1052464694,0.3700760007,-0.2983788848,-1.7491821051,0.0411379486,-1.1203415394,0.6413006186,0.0217642933,-0.6283631921,0.5370006561,0.0651604682,-0.6565572619,-0.4752445519,-1.2263764143,-0.6557531357,-0.1826541275,2.3952448368,0.1607136875,1.0272328854,-0.8275399208,1.0438835621,0.7619448900,-1.1307396889,-1.2205406427,1.3907771111,0.6221396923,-1.0409410000,-0.7856572270,-1.1721094847,-1.8064625263,-0.3921511769,-0.2310555279,1.5131512880,0.4917284548,-0.0432878397,1.6977798939,-1.3908723593,1.4940390587,1.8423306942,-0.1109176725,0.2542709708,0.2416193187,0.1212384477,0.2414720356,-0.4855381846,-0.6720389128,-1.0101215839,1.1480742693,-0.0514740795,0.2556264997,1.1470924616,0.9148079753,-1.1060256958,0.4811087251,1.2506557703,1.3353089094,1.7559952736,-0.1265173256,-0.8010993600,0.4566311240,0.3428300023,-1.7524900436,-0.9317060113,-0.8634976745,0.3061068654,-0.1965166926,1.0003229380,-0.1569621265,0.1014276296,0.8939095736,0.9408544898,0.2834113538,-1.3292179108,0.9167075753,0.2990117371,-0.6239182353,0.9428245425,0.2198539376,-0.4146504402,0.7951261997,0.2012115568,0.6641840935,1.9132390022,0.0612025335,0.3415098488,-1.0602945089,0.8366987109,-1.6226406097,1.1113557816,-1.3292145729,-0.3143319786,0.3570109010,-0.1764928848,-0.1717350632,1.6343352795,2.5383000374,-1.0527589321,-0.7758113742,-0.3192665279,-1.0465342999,1.9890724421,0.3994129896,-0.5866478086,-0.8957120180,-1.6844896078,-1.3510472775,0.3692949712,-0.2429165691,-2.3788287640,0.5294952989,-0.9295908213,-2.0615482330,-0.6898310184,0.0278328750,1.6711131334,-1.6555784941,1.4271929264,0.0273575801,0.2971141934,-1.1789822578,0.9930096865,1.0365034342,-0.1519527435,0.4682734311,-2.3577785492,1.3565287590,0.9537298679,-0.2706686854,0.2951039374,0.3883643150,-0.0566962734,-0.3984859884,0.2041887492,-0.9976084828,0.7897940278,1.4099681377,-0.3404171765,0.3241531551,-0.4855938256,-1.2421112061,1.5360037088,-0.9463829994,-0.3573916852,-0.0232634433,-1.2513146400,-2.2355549335,-0.7908390164,-0.4839990735,-1.6056691408,0.0734652206,-0.2260978222,-0.5341376662,1.0534939766,1.5730623007,1.0264832973,-0.9042997956,0.7410283089,1.2227886915,-0.9809672832,0.8328786492,2.7288522720,-1.6969711781,1.2512172461,-0.3696545064,-0.2950987518,0.0518392660,0.8288123608,1.2777222395,-1.2569802999,-0.3112655282,-0.5696928501,-0.2377070040,1.1983821392,-0.2934773564,0.8378570080,1.7270666361,-0.8205666542,0.3335210681,-0.8726528287,0.6561540365,1.0646369457,-1.4809577465,-0.3941823542,-1.0625725985,-1.1441496611,1.1643037796,-1.7063095570,0.1826176941,-0.3895122707,-0.5045616031,0.5522103906,0.0773333758,-0.0574592091,-1.5021427870,-1.7225257158,1.7434196472,-1.8855978251,-0.1019827873,0.4856334627,-1.9518294334,-0.1191142574,1.0445772409,-1.1645052433,1.6964392662,0.5589596629,0.6847245097,0.6614169478,0.4820757210,0.3499038517,0.6179351211,-1.9481719732,0.2576283216,-2.2164435387,0.2630864084,0.0669203550,-1.1707545519,0.6772699356,0.1684508771,-1.2875515223,1.0062065125,-1.1552302837,-0.8029338717,-2.2737193108,-0.7485864162,0.6612769365,-1.1619497538,2.1173989773,-0.3294250369,0.3562559187,0.2107373476,0.8565757871,0.6712851524,0.5338254571,-0.8010561466,-1.6697434187,0.3606756032,1.2867676020,-0.2094346732,0.5576734543,1.0525827408,0.9210794568,-0.2470230609,-0.0034603099,1.6976779699,0.6332430840,0.0199560001,0.0755996332,-1.0569541454,-0.6732931733,-0.4159931839,-1.5330858231,0.5702850819,-0.1691996306,-1.8038196564,-0.9590678215,-1.5392922163,0.3994826972,-1.0821446180,0.3027870357,1.0220326185,-0.3363763094,0.0301486459,1.5134326220,0.5621951222,-1.2312422991,0.6054644585,1.1600813866,1.3731253147,0.5823098421,0.1793181896,-0.9241508842,-1.3068791628,1.0078873634,-0.0847553387,0.6938104630,0.1029771790,0.1699392349,-0.5331149697,-0.5968712568,0.8790861964,-0.2934698761,1.2495779991,0.1272739172,-0.7125212550,-0.4451971948,0.4075957537,-1.0298527479,-0.2791715860,0.3461883962,1.6816877127,-1.6031706333,0.0056235124,1.0078634024,1.3490788937,-1.5436534882,0.1696927845,-0.5270277858,1.6223733425,-0.5162442327,0.3828381300,0.4506391287,-0.9998950362,-0.6521401405,-0.3246061206,0.2585060298,0.9276508689,-2.0880565643,0.8682402372,0.0620451719,0.2503739893,-1.0289133787,0.1270450950,-0.8162886500,1.4642271996,-0.3115217388,3.0074081421,-1.2791824341,-0.2708213627,1.7376896143,-0.5052874088,0.6811109781,-0.7712689042,-1.5408807993,1.1143568754,-0.4985656142,0.7032669187,-1.3779296875,0.0579764359,-0.3669286370,0.5524052382,-1.1774955988,-0.9593952298,-2.5553278923,0.3986499012,-1.8606998920,0.5338377357,0.6182241440,-0.3920603395,-0.9350994825,-0.6044998169,-0.3034831882,-0.4526685476,-0.5963338017,-0.7564249039,-0.2662839592,-1.2210955620,-0.6124317050,-0.5627401471,-0.4255528152,2.0560801029,-0.8246173859,-0.9876614213,-0.6199842691,-0.4691637754,-0.1785079837,0.5794753432,-0.6497477293,-0.3748328388,1.7727497816,-0.4439648986,-0.2879000008,1.4938969612,-1.4431997538,-0.1966993660,-1.5506589413,-0.0824496299,-0.3735535145,1.8474872112,0.4143075943,-1.3707956076,0.4110006988,0.1122452915,-0.8783571124,0.1543612927,0.0001337494,1.3457558155,0.1956868619,0.0120426994,0.4659405947,1.0559220314,0.4118642807,-0.2827820480,-1.0537084341,-1.7089247704,-1.2605371475,-0.6627028584,0.0284964610,-1.5919424295,-0.8879739046,1.3372726440,-0.3084809184,0.2604015470,1.5567058325,-0.9774645567,0.9206609130,-0.3910360932,-2.0741565228,0.6043616533,0.8186147213,-0.2919317484,-1.8189321756,-1.3367571831,0.0049841022,1.1277798414,-0.1117683128,-0.7106814384,-0.0921612084,0.4363644421,0.5508530736,0.2112184912,-0.4217892885,-0.3625360429,-0.5210886002,-0.7911268473,0.6036680937,-0.9205818176,0.9471231103,1.3281573057,0.5098133087,-0.2765147686,-0.0400175266,0.9152051806,-0.0791764036,-0.4207233191,-1.4149441719,0.1290478557,-0.0053360481,-1.1818076372,-1.2097790241,-0.6358364820,1.0997394323,-0.3663605452,-1.3995124102,0.5268882513,-0.0040545431,0.8065931797,0.5818359852,-0.7355961204,0.2951637805,-1.8553963900,0.7826838493,0.9054294229,1.3948525190,0.4250205755,0.3838944435,-0.6590161324,-0.5383474231,1.9159451723,-0.3733713031,2.2129595280,1.8961585760,1.6835546494,-0.5816136003,-2.1392905712,-0.9826152921,-1.5338691473,-0.4559504688,-0.1861871928,-0.4478240609,-0.9198418856,0.6889845133,-0.7898256183,-1.5680773258,0.6147295237,-0.5621627569,-0.3072946072,1.9393631220,0.9291343093,-0.6737373471,1.3822253942,0.2642171383,0.2372154593,0.3773427904,-0.4426511824,-1.9745779037,0.8025727272,-1.0189781189,-0.6997631192,0.2891789675,-1.1383354664,-2.0471360683,-0.1752144843,-0.0870466754,0.2797400653,0.2387488484,-0.1481952071,-0.2302711010,0.8003568649,-0.6089862585,0.0534715429,-0.5716961026,-0.9841057658,1.2828774452,-0.1688161492,1.2798538208,-1.0940895081,-0.2482675761,-0.7160670161,-0.1450303942,0.3953606784,0.6148098707,-1.0022808313,0.3334307969,-0.9138579369,-0.8279646039,-0.2285257876,1.1132116318,0.6443887353,-0.1507997662,0.8884394169,-1.0409892797,-1.2017220259,0.4876228273,0.6594662666,1.0187479258,-0.8132072091,0.4418626726,0.6325352788,1.2463976145,-0.1135608032,-0.9164980054,0.7859613299,0.4463684261,0.6968076229,0.6227259040,-0.6469994187,0.9220806956,0.7630829811,1.0957705975,-0.4319012761,-0.4152270555,-0.2044944763,0.9506226182,0.5847282410,0.2539539337,-1.7795450687,-0.6887845397,0.6866399646,-0.0558012277,1.2429003716,-0.5696885586,-0.1877678037,-1.1906847954,-0.4526516199,1.0057507753,0.7095575929,-1.6089472771,0.6746912599,-0.0422934592,-0.1314605325,1.1723577976,1.3062764406,0.0529669598,-0.3620713353,-1.5355778933,1.1157461405,0.1266220212,-0.3168752789,-0.2654770017,-1.4859975576,-1.1428658962,-1.8808702230,0.7916238904,-1.0978664160,-0.3868590593,-0.0748722702,-0.5582896471,-0.3408991992,0.0357785411,-2.8540141582,0.1198951602,-0.3569850326,0.6131075025,-1.6270140409,-0.2847393453,0.0791950300,0.7125725150,0.9216774702,-0.5362963676,1.0582467318,1.0025253296,-0.4564027488,-0.9334833026,1.2776427269,1.3159724474,0.9056265354,-0.0394703001,0.2864100337,-1.8664575815,0.1179925725,0.2843076587,0.6929876804,-0.8222893476,-0.7008691430,-1.1756200790,0.0781022459,-0.9581169486,1.2042080164,1.2288545370,-1.2023644447,-2.1400723457,0.8589876294,0.9031086564,-0.6311286092,0.2257191837,-0.2904500663,2.5082805157,-0.7749772072,0.4404409826,1.5937997103,-0.6869628429,-0.8768021464,1.1542279720,0.3378003240,0.7085487843,-0.0843881667,1.3874114752,-0.8350510597,-1.8387274742,0.0471214205,-0.6551354527,-0.8090748191,0.6171238422,-0.1551373601,-1.3722908497,-0.7655444741,1.6287691593,1.5615321398,0.3192647994,-0.9870176911,-1.4553993940,-0.6677874923,-0.0301759038,1.0221860409,0.2797620595,1.9955043793,0.2484874576,0.0276262611,0.2522889674,-0.8351356983,-1.0892126560,-0.1633870602,-0.4688637555,0.2814452946,0.6965830326,-0.8071414232,0.4933938980,1.1570245028,0.5350809693,-1.7146855593,0.3662984073,0.6917946935,0.4543409348,1.3346126080,0.8517884612,-0.8048650026,1.4301743507,0.5187414289,2.5650734901,0.5571698546,-1.4397175312,-0.0305997543,-0.5573413372,-0.3947639763,-1.7622674704,-0.5569675565,-0.9407226443,-0.4493946731,-1.6613689661,-0.8826978207,0.3443049788,-0.1960539669,1.6036450863,0.2909748852,-0.1233137473,-0.2173997611,0.3150077462,1.0498563051,-0.6585019231,0.0957669914,-0.2687816024,-0.6586936712,-0.3349936903,0.9559844136,0.2193197906,1.3311969042,1.7547625303,-0.4384146035,-0.5910891891,-0.0369080007,-1.7037577629,1.1412252188,-0.1880388260,-0.6701797843,-0.2139253467,-0.4461108446,0.4609785080,-0.6667152643,-1.0494136810,-0.9170075059,0.4246536493,0.4500367045,-0.4323231876,-0.7817713022,-0.8252133131,0.9703499675,0.5069776773,-0.5588415265,-0.5356715918,-0.2954487205,-0.6099143028,0.0746136606,1.6815915108,-0.3075112998,-0.8263124824,-0.7620713711,-0.8745070696,-1.0211056471,-1.0041357279,-0.7308058143,-0.2631337643,0.5446914434,0.6488231421,-0.5848956704,-0.2323754430,0.6658927202,-2.3170225620,1.2412644625,0.7278534770,-0.1591682732,-0.0863246992,0.0435153991,1.1766989231,-1.3432213068,0.7669236064,-0.8524904251,-3.0434315205,-1.0095849037,-0.0935433209,0.4370863438,-0.2978182733,-0.8723636866,-1.6289815903,-0.4529634416,-0.2159748822,2.2257893085,0.5159680843,-0.0077975448,0.6277788877,1.8291573524,0.7833284140,-0.6949352622,-2.3123188019,0.8569595814,-0.3096266389,-1.2400895357,-0.3410450518,0.5242138505,1.9794309139,-0.1311748475,-0.6779469252,-1.0015225410,-0.7074307203,-0.6888180971,1.0624884367,0.6066510081,0.8800684214,-1.3701462746,1.2867304087,0.5365315676,1.2999631166,0.6271314621,0.3918847144,1.9875098467,-1.5191190243,0.4580776691,-0.0840576738,-1.1077204943,-0.3676539361,-0.5172212720,0.4895897508,0.6502180099,1.4189645052,0.4343042374,-0.3245664239,-0.3949351311,0.3454012871,-0.0033489121,1.3653379679,0.7686623335,2.2122874260,-0.2360703945,0.5532864928,-0.1661921591,1.6751831770,0.0132257845,1.4176884890,1.7192947865,1.6324951649,0.3114824593,0.7976205945,0.4467043281,1.4926853180,-0.2878831625,-1.6661862135,-0.0044908966,-0.2455088496,-3.2745137215,-0.2838715017,-0.1518843770,-0.8731604815,0.1849374026,1.0501680374,0.2308520377,-0.1487602592,1.1539299488,1.0388782024,-0.7927692533,1.0399427414,-0.3865675628,-0.3344063163,-0.7397027016,1.5190846920,0.0405279025,0.9089628458,0.3263829648,-2.2702953815,0.2929112017,1.2355471849,0.7129567266,0.5659303069,1.5859659910,0.3280636072,-1.5915364027,1.1417033672,-0.4248448312,0.7930880785,0.0883681923,1.8440197706,0.1610373408,0.5732743144,0.0075075594,0.4905359447,0.6674293280,-0.0319283381,1.1117783785,-0.8937884569,-0.5062664151,-1.0149229765,-2.0016167164,-1.0205111504,2.2229752541,0.0113997580,0.8003988266,0.2961736619,-1.6971895695,0.8078061342,0.2169072777,0.0451913550,0.5088980198,0.2208980471,0.6954385042,0.8863599300,-0.3556869626,0.5780002475,1.1718003750,1.1406605244,1.0717451572,0.4423497319,-0.5674478412,0.2898722291,-0.9614549875,2.5144340992,2.3160614967,0.8769077659,-1.0370091200,-2.4022161961,0.6049721241,-0.4953610301,-2.3281629086,-1.4473972321,-0.9300103784,-0.9152269363,0.0122897141,-1.7381287813,-0.9521546960,1.2463902235,1.2603173256,1.0538812876,-0.4877656996,1.4871590137,0.7009145617,0.6607995033,-0.5052556396,-0.3830589950,0.2948637903,0.6955531240,1.4680861235,-0.8497928381,0.3967521787,0.3792177737,-1.8099541664,0.8800607324,-0.2358582616,-0.0895350128,0.4097339213,0.1439082474,-0.8039250970,-0.5788547993,0.6057286263,-0.0667697638,0.5830227733,0.9660890102,-0.2354748845,0.4906316698,-0.2285811156,0.6608774662,1.3144094944,-2.1506252289,1.1890547276,-0.0107625481,0.5143793821,0.6493283510,-1.3720718622,1.7808263302,-0.5661188364,-0.1417411417,0.3248441517,0.5483885407,-0.3008512259,-1.2304807901,-0.3662090898,0.1400451660,-0.0959511250,-2.2191183567,1.1093850136,-0.0595243648,0.9957280159,-1.1562790871,0.7081853747,1.2150986195,-0.1032100692,0.6972517371,0.7193431854,-1.0294797421,-0.1768095046,0.9343592525,0.2372649163,0.7474091649,-1.5894510746,0.7022696137,0.8446638584,0.7430752516,-0.6214725375,-0.4367303252,-0.4456193745,0.8655875325,-0.5149858594,0.3280645013,-0.1024664417,0.7322508693,-0.6337894201,-0.4929722548,2.4898169041,-0.8463423848,-0.5593562722,-0.5450578332,0.8441916108,1.4418475628,-1.0300234556,-0.6466807723,0.2288228869,0.0954682603,-0.5915262103,-3.0876836777,-2.0283315182,0.5751449466,-0.6132372022,-1.1095269918,-0.0689608827,-0.0798729211,-1.4768925905,2.1811816692,-0.2500698566,-0.5732578039,1.0652742386,-0.8546937108,-1.1292870045,1.2695087194,-1.2510520220,-0.8316658735,-1.6696878672,0.4545242190,0.1797860861,0.0970116705,1.2030805349,-0.7623143792,0.8427641392,0.2079904526,0.7502828240,0.2300081998,2.2469732761,0.9968439341,0.6118012071,0.4577815235,1.2006202936,0.4174729586,-0.2497812212,-0.2987058163,1.5730762482,-0.7681244016,-0.4798147976,-1.6172803640,-1.7546819448,0.2139769793,0.3619492650,0.0847462118,-1.7089012861,-0.1561836153,0.3462845981,0.6182725430,-1.8326427937,1.2170871496,-1.0436891317,-1.3648991585,-2.2823894024,-0.5620194077,-0.5828886628,-1.7087174654,0.6809772849,-1.0947186947,-0.2100659460,-1.0447046757,0.5272279978,-1.5686168671,-0.1761078984,1.0267621279,-0.9264883399,-0.5448895097,-1.1664751768,0.9067573547,-0.1943168789,-0.9029732347,0.3409390152,-0.3423842192,-0.4933809340,-0.1203116477,0.6469014883,1.4632275105,-2.2619640827,-0.4403368235,-0.2874864936,0.3995994627,0.0293659437,0.4649489224,0.5351887345,0.5258300900,0.2087713480,1.2079454660,-0.0458886884,0.5520437956,1.7916995287,0.3296727836,-0.2645019591,0.1053925529,-0.3000160456,0.5894111991,-1.7004368305,-1.1702919006,0.7144211531,-0.3652415574,-0.4975321591,-1.2789793015,-1.5159935951,0.9037019014,0.9386519790,-0.2034149766,0.0920588151,-1.9900647402,-1.4680039883,-0.8426797390,0.0067214174,0.9794570804,0.5074473619,-0.4286257327,-0.6218476295,1.3840569258,2.5538566113,0.6628007293,-0.2189400643,0.4221946299,-0.7699494958,-1.4606316090,1.2698231936,-1.3451348543,-0.1210730821,-0.9649879336,-1.0809884071,0.5695738792,1.4865843058,-1.7563409805,-1.7095904350,-0.8119915128,-0.5803133249,0.2327409685,-0.6860216260,1.4256445169,0.5897830725,-1.0782427788,-1.7356255054,0.8439821005,-1.0922048092,0.3640676439,0.1694461256,-0.2845337391,-0.0015914980,-0.6929503083,-0.3809933960,0.7967649698,0.3464201391,-0.8488762379,0.0735314563,0.3796829581,-0.3305215538,0.1394914091,0.2664026618,0.5161311626,-1.1287683249,-0.2626350820,0.5476616025,0.3476051390,-0.6108629704,-1.8545712233,-0.7726867795,-0.1765599549,-0.6290928125,-0.2056999356,0.6018232107,-1.4811753035,0.9063700438,0.5083891749,-1.2830897570,-0.4046699703,0.7701845765,0.0314547308,0.4233820736,0.9221630096,1.7657654285,2.3693754673,-0.1023481190,0.2427469939,0.3453752100,1.0699369907,0.3138153553,2.0743460655,-1.7169541121,-0.4115565419,-0.1496352702,1.1596267223,-0.7840048075,-0.7558175325,0.8825569153,0.6057924628,-0.0026302291,0.6777153611,0.7162336111,0.8861199617,0.9713836312,1.0570205450,0.1008922532,0.2519199550,-1.7796982527,1.0196323395,0.1301587075,-0.3126945794,-0.5350653529,0.2415903062,-1.2447651625,0.8951871991,0.1416310817,-0.5771242976,0.3480791152,-0.5791205168,0.5143607259,0.6251235008,0.4787263274,-0.5682345629,0.5818405747,0.5476638079,-0.2344136238,0.4926259518,0.0020974108,0.4648458064,-1.2469049692,0.9685260057,0.2488428503,0.8673420548,1.3650695086,-2.1453146935,0.0148590002,2.2118170261,-0.4790977240,1.8335345984,-0.4013042450,1.8113731146,0.8131791949,-0.4838180840,-0.5870887637,-0.3348998725,-1.5233494043,-1.4847657681,0.4049981236,-0.3059670329,0.1298778802,0.7187888026,-2.7429368496,0.4560085237,0.3684889376,0.2669047713,0.5020672083,-0.0811798126,-0.0078832060,-0.2715966403,0.2410754412,0.0067627095,-0.8049398661,-0.3467500806,-1.1980543137,0.3195302486,-1.2405413389,-1.0926430225,1.2750275135,-0.2405105084,-0.1525734663,0.5744650960,-0.3584517539,1.9834860563,-0.0039220667,-0.2727905512,0.8813328147,-0.8601807952,-0.0736739039,0.3197454810,-1.5756418705,0.5200622082,-0.4795474708,2.6535255909,-0.9987680316,1.2702453136,0.3841578662,-0.4805614948,1.2172632217,0.7606619596,-1.5414643288,0.1976353973,0.7160565257,0.4035159051,0.6984516382,0.1601044387,1.0915095806,0.3534328341,-0.1184051558,-0.4150804579,-1.8912463188,0.4045003653,-1.8975316286,-2.2630052567,-1.4463518858,0.3579699993,2.1300139427,1.2352734804,-0.2789600790,1.3526080847,0.3938015997,-1.3408533335,1.7260075808,-0.0077996096,1.5074975491,1.8468036652,0.6475793123,-0.3252647221,-0.8967847228,0.9662185311,0.1558922529,-0.1998231411,0.6230989695,-1.4783391953,0.6823682189,0.8574786782,-0.8982612491,-0.0487452298,2.1404359341,-0.7900241613,0.2257759124,-0.4074427187,-1.0557363033,-0.9133280516,0.3864759505,-0.2905539274,-0.7860685587,0.7287256122,-1.2111824751,1.0915997028,-0.5741703510,-0.8632349372,1.8330698013,-0.2431361377,-1.3883429766,0.5145610571,0.4060795903,-0.3183524907,-0.0028131553,0.1949463636,0.1193532422,-0.5316559672,0.8666998148,-1.0010826588,-0.5808494687,0.8329043984,2.0336697102,-1.1984018087,0.7143980265,0.1848467290,0.6511341333,0.5259750485,-0.3475879431,-0.9058694839,-0.5467703342,-1.4293168783,-1.7306935787,0.6718448997,0.5225819349,1.1162972450,-1.5372996330,-0.7658146024,-0.6932194233,-0.5045186281,0.7642450333,-0.5672447085,-0.3762857020,1.3930920362,-1.0889377594,-0.9572563767,-0.0917122737,0.6868191957,-0.4004735351,-1.3633692265,0.6427147388,-0.7196304798,-0.8512632251,0.5361620188,-1.1725454330,0.1028381735,0.5060002208,-1.3521600962,-0.8992948532,-0.2606385052,1.1963212490,0.4467527270,0.6490583420,0.6809411645,1.4820773602,-0.7598612905,0.7339666486,1.4499570131,-0.1634774804,-1.6448104382,0.0809721798,-1.1142492294,-0.2901205420,-0.1146303713,0.2195672244,0.4080210030,-1.0791637897,-1.8717880249,1.6003428698,-0.1694111526,-0.3783018291,-1.6030508280,0.2283682078,1.0475113392,0.7307556272,-0.4210613668,-0.3517955542,-0.4050840735,-0.5490471125,-0.3479705453,1.9079108238,0.3872929811,-1.1613664627,-0.1516494900,0.3707110584,1.4472540617,-0.2746278346,0.4029833674,-1.2051960230,0.2465004772,-0.7065382600,0.0371126421,0.8646813035,-0.6913815737,-0.3071915507,-0.1538460851,-1.7917917967,-1.2598940134,-1.8016839027,0.9368255734,-1.3379613161,0.5263180733,-1.5782839060,-0.4033615589,1.0468375683,0.8125714064,-0.4790661335,1.0822108984,0.5306308270,3.2135152817,0.6620602608,-1.6667072773,0.0143323876,2.9585022926,1.2215119600,0.4183119833,-1.1557128429,-1.1458501816,1.0365495682,-0.2553441823,-0.4749603271,-0.4489164948,-0.1246030629,0.9618656039,0.0579839200,-0.3051787019,0.1202649400,0.0543751307,-0.6086128950,0.0081361765,0.4306674302,-0.0972862765,0.3353385031,-0.2733195722,-0.1604502201,0.9772319198,-0.1361977905,-0.5129996538,0.6338104606,0.1387738585,0.1811870933,-0.4650717676,-0.2434235364,1.3702030182,-1.0426175594,-1.5735248327,-0.5793191195,-0.3952281177,0.6459346414,-1.9756667614,0.3489671350,2.3008513451,0.0771680027,0.6087843776,-1.4710805416,0.3890483677,-0.5295361280,0.9832375646,0.1260338128,0.8573789001,0.2447784096,0.3204292953,-2.5175051689,-0.7122991681,-0.8745144606,0.0141174290,0.9317763448,-0.9803977013,-1.5740404129,-0.3517892361,-0.8231508136,0.0262164883,0.6211560369,-2.0268793106,1.0612952709,-0.3552500010,0.9536997080,-1.2097529173,0.4185555279,0.2573874295,0.6497887969,0.8740681410,0.4048483372,-0.4238315225,-1.9540976286,0.4655889571,-0.0313888192,-0.2161873132,-0.2317292094,-0.0759339109,0.0675848275,0.0878292397,-0.9489600062,-0.1432806849,1.1445298195,-2.7369377613,-0.5840117931,-0.5899749398,1.2879940271,1.3466374874,1.0962083340,0.2304671705,-1.7148902416,1.3411163092,0.1041158214,-0.0788779110,-2.2844712734,-1.0280727148,-1.2645610571,1.1588771343,-0.4571908414,1.2539838552,-0.2162689269,-1.7553088665,0.2741356492,0.7430927157,-1.1741378307,0.3358246982,0.0238060430,0.0031688462,-1.3877177238,0.5490756631,1.1530783176,1.6128815413,-0.3410646319,-1.2937667370,-1.6469665766,-0.7334685326,0.1037245989,0.8387489319,0.0148075577,0.5645905137,-1.3039965630,-0.5846779943,-1.5839500427,-0.2638729811,-0.0072477343,0.8843932748,-0.3676111102,-1.5938299894,-0.8872205019,-0.4249498248,-0.1557797194,-1.3146603107,-0.1697295159,-0.2765368521,0.4457674026,0.9021023512,0.1397904456,1.7429642677,-0.4599343836,-0.6597484946,0.4328436255,1.4983532429,1.2432944775,-0.4208336174,0.4489599764,0.1689072102,-0.4926060140,-0.0422246605,-2.3662722111,-1.8588395119,0.3812257349,-0.7578253746,1.2569688559,-0.3351842761,-0.7692585588,0.4607789814,0.8273998499,-1.1147665977,0.8162701130,-0.2671040297,1.4073350430,-0.7888681293,0.1561743319,-1.2401427031,-1.2775328159,-0.7646373510,-0.6475517750,2.0057315826,1.0876049995,-1.1954290867,-0.1807238609,-0.8135599494,-1.2610627413,-0.9346448779,0.3905242085,-1.4709957838,0.6816416979,-0.4965876043,-0.1572820246,-0.4188430607,1.1873232126,0.9308753610,-1.9551130533,1.0496579409,-1.0345253944,0.8236737847,0.5495346189,0.5497707725,2.3413565159,1.6484090090,-0.7264957428,0.3208186626,0.2824824750,-0.6003243327,0.4457696080,1.7169154882,0.0159275644,-1.6579325199,-1.0831270218,-0.5027672648,-0.6477096677,1.4063690901,0.3528015018,1.1226716042,-1.5352687836,0.3197790682,-0.2060278803,1.3496638536,0.6235291958,0.0421331450,-0.3542109728,-0.6579025388,-0.6250056624,0.6840335131,1.3491804600,-0.6798034310,1.0311497450,0.3708248138,2.3034310341,-0.8823706508,0.2779397368,0.2376018465,-1.0999842882,-2.3625836372,2.5004153252,-0.0031369352,-0.5761529207,-0.9552867413,-1.1486686468,0.2252877206,1.3544378281,1.1923971176,-1.0452986956,0.4250714779,-0.6534120440,-0.9170339704,-1.8241276741,0.6940741539,1.0891760588,1.1354733706,0.8429929614,-0.5788779855,-0.3875228167,-0.5509646535,-1.9952298403,0.8218613863,0.6798110604,1.1460310221,-1.0449521542,-0.5703985691,0.5750790834,-0.7848528624,-0.5177422166,0.2719036937,0.5763064623,1.7560209036,0.7867377400,-0.8005876541,-1.3305873871,-1.3257182837,0.7724911571,-1.8970799446,0.9184693694,-0.5014103055,0.5121781826,-0.2338661253,-1.9732248783,-1.2685248852,0.5421708822,0.3566212654,-2.7719295025,0.0120019102,0.2266089767,1.5233207941,-0.5277122855,0.8992790580,0.9162186384,1.3245271444,-0.3380609453,-0.2191164792,0.1802497059,0.7791525126,0.3603124619,0.6356837749,-0.0949871168,-0.1510977745,1.0524718761,-0.8924908042,0.1134970784,0.7762354612,-0.1041747034,-1.2717193365,0.1911706775,0.2469402403,-0.4907810986,-0.0449020043,-1.1582369804,-1.8383409977,-1.4759110212,1.8879642487,1.2204946280,0.7254795432,-2.1488111019,-1.9087783098,0.8363744020,0.1254971474,1.1508957148,0.1561222225,-0.1453067958,-1.0493863821,-0.3168115318,0.5137270093,-0.6062394381,-1.0988081694,1.2591933012,-0.1684797853,-1.2144109011,1.3161044121,-0.2794598639,0.6305717230,-1.1718168259,-0.5043300986,1.3296680450,0.6659186482,0.0582517385,0.0609587096,-1.5843622684,0.9506537914,1.3065859079,-2.2422685623,0.5747953057,-0.1019831151,0.1581490189,-1.2338908911,-0.7650310993,-0.4184915423,-0.9221194386,0.6965978742,-0.8460552692,0.1583629102,0.8735681772,-0.3400534987,-0.1723876595,2.3087937832,0.6242477298,-0.3329307139,0.1324429065,-0.5053774714,-0.9988173246,-0.9100036621,0.0229380503,-1.2823932171,-0.3242506385,-0.6225237250,0.7587878704,-1.6966271400,-0.3292137086,-0.9888989329,1.8447217941,0.6552241445,0.5138090253,-0.7122284174,-0.6896860600,0.2713268697,0.2952925265,0.1329986453,-0.2784538269,-1.2005258799,-0.4423667192,-1.3582398891,2.2271566391,1.7319980860,0.1650353372,0.6235536337,0.9041349292,-0.7492755055,-0.6408665776,0.5311431289,1.1350789070,-0.0610747412,1.5564525127,-1.1107958555,-0.9086764455,0.4045865536,-1.2979991436,-0.3478908539,-0.6960718632,-1.7867015600,-0.3869774938,0.3975443840,0.3818458319,-0.9753320217,-0.2342271954,-1.3683166504,-0.2547301948,-2.3559172153,0.3542802930,0.6389033198,-0.2198933065,-1.5690653324,-0.4407686889,0.8176122904,-0.0587791465,1.2063684464,1.1797443628,-0.3437459171,-0.4739488363,-1.5506465435,-0.3452513516,0.8360907435,-0.8022053242,1.5924566984,-1.5707868338,-1.0464003086,-1.2346476316,-1.5263248682,0.8003885746,1.1033037901,-0.1054809988,1.4715224504,-1.7682429552,-1.1850502491,-0.8126041293,0.8842704296,0.9425088763,0.0330735892,-0.2409315258,1.5489830971,0.6468773484,-0.1781851649,-2.7890059948,-0.0014940457,0.4603638053,0.1230962947,1.5464887619,0.3794255853,-0.7880982161,0.7934423089,-1.5169560909,0.0380557850,-1.4559270144,0.5339881182,0.3679506779,-1.1586297750,0.0873472542,-0.5471687913,0.0661044717,2.1989641190,0.2341248393,1.7468538284,3.7643828392,-0.9423438311,-0.0853690207,1.9483058453,-0.2876728475,-0.1539317667,1.6529641151,1.3316450119,0.9574147463,-1.1216984987,-1.0181498528,-0.7338421345,-1.3882849216,1.0699387789,-0.6837269664,-1.2928775549,-0.1253340095,0.4996267855,0.9240604639,0.5986737013,1.7402137518,0.3486900628,-0.5245723724,-1.1849862337,0.2726819515,-1.6281638145,0.2654599845,-0.4116245806,0.4574624300,-0.1537874192,-1.9013284445,1.4959928989,-0.0532272644,-1.2966313362,-1.3777812719,-0.1085461006,-1.1366568804,2.4738366604,-0.6625595093,-0.3700547814,-0.6848813891,-0.9847663045,-0.3399543166,-0.7798151970,1.1458569765,1.2416856289,-1.1501663923,-0.6315066814,1.1676069498,-1.4100657701,-0.5687700510,-0.5040619969,1.4950553179,-0.7586460710,0.3278019726,1.1096271276,-0.3833582699,0.2235788554,-0.5815556645,0.0966813415,-0.6273540854,0.6732571125,0.0662461072,-0.1287237704,-0.8700714111,0.8890676498,-0.3600372672,1.6472837925,-1.6016446352,0.8628495336,0.4772661924,0.0748748258,-0.3812872469,-0.7134984136,0.6940374374,-1.6486783028,1.4736716747,-0.0254137758,0.0967500806,-0.1661897451,1.1823667288,-0.6112408042,-1.5404152870,1.2952648401,0.7924426794,-0.4812881052,0.8054927588,-0.2136539519,-1.7206912041,-0.3016053438,0.2895011902,2.0912322998,-1.9579486847,-0.8064804673,-0.3919655383,1.6497608423,1.0967392921,-0.0155962491,-0.0089084962,0.5606082082,-0.7090340853,0.7310581207,0.0730704814,0.6230039597,0.4864089191,0.4549812078,-0.2649352551,-1.1511001587,-0.9840397239,-0.2999227345,2.2628390789,1.1271271706,0.3714485168,0.2622233927,1.4365916252,2.0530672073,-0.0107169645,0.6136042476,0.0226049926,-0.0324297585,-0.7721080780,-0.5181171894,-0.3055936694,1.3205901384,-1.5773636103,-0.3167185187,-0.1485596001,-1.1861242056,0.1441131532,0.7637791038,-1.9861276150,-0.2936843038,0.8477237821,0.0517439954,0.0406466722,-0.9705188870,-0.7261933684,-0.0312301386,0.3390150666,-1.0390940905,0.2602939308,2.0953760147,0.0473578013,1.2825541496,-0.3004450202,0.5410876870,-0.1447229385,0.4664852023,0.3632920980,0.5882064700,-1.5549762249,0.0268624183,-1.0717278719,-0.1177723333,-0.4627850652,0.3465367556,2.2943594456,1.7421190739,0.0722834393,0.5992326736,-0.7836269140,0.5283228755,0.0322488360,0.5551918149,0.2175752223,-0.4546332657,1.4639328718,-0.6801419854,-0.0971610919,0.6066857576,1.3741084337,0.2518433928,0.6852304339,0.2889463305,-0.1472174823,0.2218355238,-0.0487602502,-1.0502138138,-2.2987830639,1.5475156307,0.3123504221,1.0007822514,-1.7533344030,0.3010531962,-0.1631305069,0.4981911182,-1.0523788929,1.5803315639,-0.5132887363,0.2444366068,-0.7612324953,-1.0226480961,-1.5267606974,1.2850830555,1.5239545107,-1.4156295061,-0.8883552551,1.0721236467,-0.7571452856,-1.2760622501,-0.0873958692,1.1551344395,-0.2928124964,0.1826197952,-0.1817886829,0.0830894485,-1.1084549427,2.3446435928,-0.1304149628,0.8465356231,-0.0870315060,-0.2174553275,0.1470153332,0.6346374154,-0.2693883181,1.3204683065,-0.3679193556,1.1488084793,-1.1435592175,-0.4943830669,-0.2291122079,0.2982085347,-0.9264073372,0.9086833000,0.8751946092,0.3901867867,1.0084059238,0.2700186968,0.4779162705,0.2833504975,0.0971349180,-1.3063620329,-0.7672454119,0.1625791639,0.1736915410,-0.8138611317,-0.3182066679,-0.5231506228,-1.3166358471,-0.2597752213,-2.8546957970,0.2950502336,-2.2095010281,-1.1995346546,0.1285841912,-0.0192146059,-2.2865560055,0.8165867925,-1.3509417772,0.7002499104,0.3727229536,-0.4820721447,0.8639489412,0.8133208156,0.0887968391,-0.3125910759,3.0393307209,1.4080055952,0.2269381732,-0.0300363377,0.7396939397,0.0493804477,-0.4246927202,0.1304106563,0.9637285471,-2.9354915619,-0.3544369638,1.2836763859,-0.8559589386,1.8721460104,0.9731093049,0.5492524505,-1.0334913731,1.3251916170,1.3108726740,0.5195982456,-0.4179671109,0.6543501616,0.4693245590,0.8555210829,0.0848020539,-0.1515882611,-1.7304179668,-1.0883326530,1.0102947950,-0.2386721522,0.8745925426,1.3899519444,0.7876927257,0.6158488393,0.5215525627,1.4409991503,-0.0144396611,2.2355680466,0.4180262387,1.0790933371,-1.4335969687,0.7017084956,-0.0270159505,-0.0620286353,1.0418047905,1.2607593536,-0.8740250468,0.3189888597,0.2929864824,-0.8016648293,1.1566418409,-0.3863493800,-0.6131212711,0.4015072286,-0.3994033933,0.5563696027,-0.3870293200,-0.7484621406,1.9729208946,0.3187820911,-1.0970444679,-0.8086558580,-2.5966191292,0.6420378089,0.6515240073,-1.5672519207,-1.1887092590,0.1352421641,-0.1588215977,-1.1035181284,-0.3870321214,-0.1285940260,-0.0611574203,0.5199727416,-0.6207996607,-0.8858322501,0.2921783328,1.7415742874,1.1214604378,0.4722931385,-0.0375859216,0.9042145610,1.5266809464,0.9645444751,1.1944296360,0.3133407533,0.0609702654,-0.7147462368,-0.9949486852,0.0263745487,-0.9406294823,0.6160652637,2.3014707565,-1.1834588051,-0.8900075555,-0.2471520454,0.4672086537,1.9268618822,-0.6749277711,0.6205279827,-0.2686580122,-0.7099538445,-0.9639384151,0.7790831327,-0.5402551293,-0.0003102511,-0.8768327236,-1.0687489510,-0.4675288796,-0.2242846638,0.8382201195,-0.3525581658,-0.7518466711,0.4557478726,0.2760375738,0.6195541620,0.3318205774,0.8327250481,0.0537931845,-0.3553763926,-2.0381026268,1.6230796576,-1.5148580074,-0.1860478520,-2.0974383354,-0.2627943754,-2.4067049026,-0.4767214060,1.3863887787,-0.7196408510,-0.1204650104,0.7024926543,-0.8471753597,-0.4811016917,-0.2101222873,-1.5753133297,0.0518422872,-0.6725054979,-0.0771305710,0.2476974279,1.1442660093,0.8213924170,-2.0979964733,0.0083712144,-2.8003196716,0.5200743675,1.1690288782,1.6796238422,1.7359300852,-0.3625329137,0.8729770780,0.0395113789,0.4805897474,0.8971570730,1.0508792400,-1.1386889219,0.2386064231,-2.1639914513,0.1895284206,0.7108013630,-0.1431214809,1.1821506023,0.4952346385,0.0679816455,1.9600552320,-2.0621733665,-2.3717496395,-0.0206102040,-1.3767124414,1.6856360435,-0.5215978622,-0.1548906118,1.1633713245,0.1333243102,-0.9365465641,-1.1232398748,-0.1756432503,-1.5008443594,2.0137960911,0.5293657184,0.4739171267,-0.0677911416,2.7306401730,-0.8007552624,0.8647549748,0.1554780453,0.2040397525,-0.1762325615,0.3810936511,-0.2150106728,0.1929219216,1.3094671965,-1.0703794956,-0.6601840854,0.1119203046,-1.0493140221,0.6418649554,1.0578992367,0.3493487239,0.0387381762,-0.7578765154,1.7252588272,-1.1950592995,-1.0095664263,0.8863735199,-0.9332340360,1.0328786373,-0.3667743504,-0.6750990748,-1.0239139795,0.6232453585,-0.4233544767,-0.6697765589,0.3974470198,0.1741041839,-0.2741079032,-0.0697648525,-0.2788359821,0.0967028365,0.4162475765,0.0730348527,1.6830052137,-1.7050038576,-0.9182111025,-0.0687336549,-0.4993008077,-2.6333050728,1.2867982388,-0.8157199621,1.8138675690,1.3882590532,-0.6029289961,0.0287784822,1.1772009134,-0.2755854428,-1.2099580765,-0.2019699514,1.2501586676,-1.0892593861,2.4252128601,0.8154894710,-1.0352143049,-0.2517317533,-1.3882302046,0.9432877302,0.7587483525,1.0898754597,1.0566821098,-0.8384352922,-0.3188551664,0.1994140446,-0.7795777917,2.1310243607,-1.7256475687,-0.3948467374,-0.7480053306,0.7033433914,0.5914207101,0.0639219061,-0.3472526371,-0.2467501760,0.1587737948,1.3566329479,-0.1416103244,1.3385957479,0.9539729953,0.0049228636,0.9412178993,0.6962132454,0.8853695393,0.0664721727,-2.7985961437,-0.9155045152,-0.0428128801,-0.6666034460,0.9059969783,-0.3675763011,-0.5666050315,-0.6845122576,1.0391764641,-1.1581093073,-0.0269874949,-1.3750796318,0.9732193351,1.2611368895,0.0356923081,0.2246537358,-3.0932531357,2.3984165192,2.2979116440,-1.7785514593,1.3218277693,0.1280211210,2.0275268555,-1.0245759487,0.8668836355,-0.8607371449,-0.7002310753,0.0155158956,-1.4728592634,1.7080414295,-0.7406947017,0.8791487813,-0.4585764706,0.3052116632,0.0468687899,0.5164999366,2.0355801582,0.6521666646,1.8466851711,1.7116943598,0.6319134235,1.3719582558,-1.6670839787,0.4300492704,-0.6846798062,0.9375258684,0.3836639822,-0.0728900358,0.0684805885,0.3087892830,0.6202475429,-0.7178317904,-0.2522747517,1.1459041834,2.0370550156,-0.2767766118,-1.3960233927,-0.9338543415,1.1877619028,-2.6348557472,1.9516296387,-0.1824237257,-2.0092451572,-0.9741954803,0.4679149389,0.9008089304,-0.5722278953,0.6044968963,0.6506953239,-1.6755926609,1.5076848269,-0.5969001055,-1.0222656727,1.9562164545,-1.2689777613,-1.7846150398,0.1661764532,-1.5170683861,-0.7610163093,-0.8992091417,-1.6415470839,1.3204326630,-0.2228368372,0.7749367356,0.4024796188,-1.3226431608,0.2422006428,-0.4162628353,-0.5555692911,0.0719668418,-0.1871663779,0.5951982737,-0.5845536590,-2.1090695858,-0.1772703975,-0.0548733100,0.4509508312,-0.9313350320,-1.7773886919,-0.3563153446,0.2669277191,0.2997245789,-0.4658081532,0.5417457819,-0.2356391251,0.4109375477,1.5283123255,-0.3351726830,-0.3406950831,1.2914118767,1.3758453131,0.8519734144,0.4109028578,-0.3435279429,0.8422434330,-0.0266405381,-1.5175741911,-0.1276775450,-1.5115371943,0.3101183772,-0.6066270471,1.0376282930,-0.0093769059,-0.0544994585,-0.5122949481,-1.2871826887,-1.0043041706,-0.8428524733,0.1637625247,0.1111728325,0.0281228572,1.3473829031,0.0723849237,-0.1692962050,-0.8452322483,0.5937932730,-1.5416975021,0.5983489752,-0.2016807795,-0.4967584610,0.1199091077,0.4734321535,-0.0088558868,1.2080721855,-0.3648279011,-0.6955690980,-0.4260819256,-0.7084145546,0.0491476320,-1.5102821589,1.0569622517,0.5366889834,-0.0563135706,1.5393899679,1.7595765591,-0.3918105364,0.9197299480,0.3016016781,-0.1586421728,0.0058817188,0.4183733761,1.5566524267,-0.6086767316,-0.5249670744,-0.8945267797,1.9990261793,1.0346226692,0.9244108796,1.8088890314,0.4348047376,-0.7111964226,-1.3284702301,-1.1754543781,0.3776286244,0.4044982493,1.7677334547,-1.0616512299,2.2402262688,-0.1550719440,0.1358435005,-0.1329102516,-0.7924153805,-1.3541342020,-0.0541118197,0.7407044172,0.1474341452,1.3359956741,0.7409295440,-1.4758354425,0.0812779739,1.5620260239,0.1671449095,0.3341617882,1.3199590445,-1.4782437086,-0.5552400947,-0.2017293274,-0.4659951627,0.2432397157,-0.6974768043,-1.2883409262,-0.7465677857,-1.1168094873,0.4712827206,1.6376899481,0.6912307143,-1.3686044216,0.1189413965,-1.4354121685,-0.1401813477,-1.1164814234,0.3037294745,-0.3992435634,0.2656225264,0.3130260110,-0.8659200072,-0.4726854563,-0.0152176367,-0.0930923000,0.3841016293,0.9208854437,-1.3471815586,-0.2411450744,1.6320923567,-0.6548956037,-0.4167873561,-1.5803978443,-0.1135653034,-1.2573654652,-2.0530848503,0.9897403121,-0.4235695899,1.5027476549,-0.6127468348,0.2498405725,-0.1621945947,0.5481315255,-1.0397114754,1.0767316818,0.6571477652,0.8535944223,0.3218203485,1.0353807211,0.2963234782,-1.5258238316,1.6403651237,0.4474198818,0.5159975290,0.0112749394,-0.4295137823,-0.0053783916,0.8010345101,0.0232382063,-0.5535251498,-0.7191053629,-1.7811300755,-0.3628551364,0.5310444832,2.4867811203,1.9475063086,0.4156304598,0.6378083229,-1.8176249266,-0.4333888888,1.0649061203,-0.7765557766,-1.1090966463,0.0572323352,0.2367252856,-0.1627569199,-0.0342329107,1.1516398191,0.0576944612,2.5441424847,0.4243032932,0.6389544606,-0.7369576693,-0.4054327011,-0.1950183809,1.2195286751,-0.7707237601,0.3494344354,-0.8499855399,-0.4434051812,-0.8354090452,0.6398029327,0.0468047112,-0.0552285872,0.5982164145,1.0310800076,1.2464448214,1.5467491150,1.9671247005,-0.7465594411,-1.2460572720,-2.2472889423,0.7259353995,0.6860581040,-0.9589980245,0.7132995129,-0.4153469801,-0.3921484649,1.2021461725,-0.0087545915,0.3043210506,0.5953631401,0.1601187736,-0.7451269031,0.2441005409,0.3973066509,0.2535099089,-1.4309951067,-1.6279504299,-1.1323072910,-1.2013375759,1.3001255989,1.8920334578,-1.2963359356,-0.4052232206,-1.9754989147,0.7988344431,0.4170355797,-0.4807196558,-2.0655698776,-0.7232215405,-0.8220478296,-0.4829567671,0.0755685493,0.6312243342,0.5088500381,-2.4266726971,-0.6307898164,0.1054759845,-0.3693656921,1.7723187208,0.6556220055,-1.3453546762,-0.6720908880,1.1442575455,-1.4109114408,1.2649291754,-0.8008374572,0.0384092443,-0.2519807816,-0.2426828742,1.2038187981,0.4667410553,-1.0764840841,1.2552109957,1.3426625729,1.5059294701,-0.9154779315,-0.0498299412,2.0281126499,0.6835604310,-1.8105126619,0.4737175107,-0.8432004452,2.0750002861,0.2878215015,-1.1522181034,2.0514914989,-0.7687619328,-0.6637822986,0.6724092364,0.6839038134,0.0562897585,-0.3016141951,0.4957450032,1.0637838840,-0.6770959496,0.2365283668,-0.2895208299,-0.8617882729,-0.9594106674,-0.0157391503,0.8399378061,0.8110836148,0.4611687660,-0.7466703057,-0.0806623921,-0.9150440097,-0.9413416386,0.3335480094,-0.3684301674,0.4436233044,1.0678399801,0.5630221963,1.3437930346,-1.7708089352,0.3103902936,0.6368618011,-0.4932948351,-0.2312989533,-0.3020412326,0.0923235640,1.3628299236,0.7628677487,0.7790932655,1.5329159498,0.2183266133,-1.2446256876,1.0062347651,-0.0709650144,-0.7959281206,1.2688463926,-0.8175793290,-1.0273636580,-0.6656317711,1.1612483263,-0.5840453506,1.4325695038,-0.8769946098,-0.5628446341,-0.2621915340,0.6548326015,0.0389738902,1.7369393110,2.3276939392,0.2912586033,-0.1409829259,0.8625109196,-1.4595911503,0.2316573858,0.9324889183,-0.6206426024,0.5359648466,-0.3008208573,0.0612839088,-1.7155638933,0.9352427721,0.1170468032,1.0926513672,-1.5903171301,1.6055085659,-0.1270006150,2.5916931629,0.3588993847,-0.4123798013,-1.4389734268,-0.4076504111,-0.3596978486,1.8169152737,0.3336016238,2.4945390224,-0.6098358631,-0.3644248843,0.8882802129,0.4999442995,0.5015850663,0.6149253845,1.1175642014,1.8079290390,0.2978225946,0.6117570400,1.7117923498,0.4619747698,-0.2899212837,0.7065873146,0.1721730530,1.0118405819,0.7275610566,-0.6780998707,-0.1265953183,0.9778655767,-1.3090860844,-0.4225935042,-0.1998132616,0.0992397964,0.9909891486,-0.8389635086,-0.2723429799,1.9301704168,0.9522368312,-0.8642147779,0.6867908239,1.2381422520,0.8961113095,1.7952609062,-0.2819908857,0.7153847218,0.0273373686,-1.3802032471,-2.0942184925,1.0688688755,0.2658931017,0.9404011965,-0.0069303596,0.5577315092,0.2194401324,0.5258272290,0.5876083970,-1.1635379791,-0.5140573978,-1.4443894625,-2.1708698273,-0.1201778799,-0.6402384043,0.2971675098,0.1304511130,0.1133562103,0.6318150163,0.1640680581,1.5028864145,-1.7749533653,-0.7292850018,0.1292218417,0.1633696705,0.5901848078,0.9318404198,0.0090533029,0.5410732627,0.6497133374,0.0382000655,0.2489194572,-2.0864832401,-0.4515062571,-1.2362923622,-0.2087910324,-1.2355883121,0.5569347739,1.3323907852,0.5438510180,-0.1150219962,0.0459278598,0.4252981246,-1.4181237221,-1.7148958445,0.6399292350,1.3488681316,-0.5249696970,-0.7036726475,0.3729901612,1.3503198624,-0.6562246680,-1.8335790634,-0.7283580303,0.4336759746,-0.0378222503,-0.2591528594,0.6934357285,0.2126318961,-0.2649644017,-0.5409034491,-0.1988546699,-0.0906299800,0.1306391060,-0.6612063646,0.3144090772,-2.1315474510,0.5624923706,0.6593207717,-0.6201909781,-0.5569365025,0.3504077792,-1.3898166418,-0.3267312050,-1.5478287935,-1.0569232702,0.4089502990,1.0574078560,0.3555086255,1.3506741524,0.7100051045,-2.4160699844,0.2878858447,0.1611437201,-0.5060824156,-0.5658532381,0.0795270875,-0.5061843991,0.2112802863,0.1915567666,-0.1671071202,-0.4966573715,-0.3014395535,1.4349435568,-0.0081969770,0.8687512875,1.7044713497,0.7172669172,0.1723873615,0.7683315873,0.8068082333,0.7374470830,-2.3381924629,1.4708920717,-0.6122639179,1.1907120943,1.3497942686,-1.3654749393,-0.3542251587,0.6783241034,0.7457907200,-0.1441514641,1.7073394060,0.1043201610,0.4953304827,0.4898969233,-0.7908129692,0.3112324178,1.2854849100,-1.1699900627,0.0307697803,-0.0978933945,0.2470248342,1.5309244394,0.0981095359,1.4879208803,0.6778614521,0.1257022619,-0.6889806986,-1.7376300097,1.6067085266,0.2240911871,0.3167164326,-1.0415329933,0.6432635784,-0.1780188829,0.2714662552,0.5061727762,-0.0400048196,0.6168119907,1.1573162079,-0.6214919686,-0.0559455715,0.2033772618,-0.0524638593,0.4651843607,0.7974411249,0.9521196485,-0.8156989813,-0.7175847292,0.0430429354,-1.1026031971,0.7501711249,-0.0570429079,0.2406162471,-0.1664299071,-0.4878765345,-0.8518081903,1.0820053816,0.2024823874,-0.6305008531,0.5867401361,-0.1111482680,0.9543295503,-1.5515456200,-1.3526494503,-1.2814865112,-1.2083516121,0.6300700307,1.2377527952,0.1157994419,-0.1324049979,0.8532496691,-0.2272783518,-1.9050981998,-1.4512780905,0.5527977347,1.9561060667,-0.5117322803,0.2994587719,-0.8818569779,0.7253333926,-0.2888867855,-0.0488190539,0.6111413240,0.8727059960,1.0785720348,0.6621670127,1.1721650362,-0.5383167863,0.7041527033,0.8776189685,-0.1341997683,0.5267609954,-2.2195818424,-0.0641778633,-1.4765670300,-1.6097735167,-0.2215120941,1.0128235817,0.3994425237,-0.6306587458,0.8556500673,0.5664199591,-2.7598052025,-0.5542398691,0.9546697140,0.2972911000,-0.5923198462,0.8346678019,-0.5135295391,-0.2254577875,0.3647433221,-1.1742988825,-0.0221651979,0.2011860758,-1.1618353128,0.3587828279,-0.3569490016,-0.6757637858,0.1543741524,0.5523005724,1.1413083076,0.9759478569,1.3029022217,1.5852334499,0.5111664534,0.9931082726,0.9090556502,-0.8942973018,-0.8136970401,-0.3231808841,-2.9619100094,-1.7260572910,0.6305112243,0.9046978951,-0.6565795541,1.1913491488,-0.6926817298,0.8507476449,-1.4126199484,1.5484261513,-0.3532052040,-0.1554211229,-0.5210480094,0.5052769184,-0.5785877705,-1.8058321476,0.4119521677,1.2402284145,0.5937663317,0.9732915163,-0.3283392489,0.1560894847,0.2356980294,0.0013753889,0.4547128677,0.2108037323,2.2417321205,-1.5689145327,1.9793784618,0.6024902463,0.1141058430,-1.3041629791,0.5927038789,-1.4569309950,2.2926297188,-0.7402815223,-0.0437542982,2.4251124859,1.0239573717,-0.9977756739,-0.7223476768,-0.6301113963,1.4681988955,1.1038920879,0.2033595741,-0.6396667361,-0.1190782934,-0.0005420816,-0.1301973015,1.5639034510,0.0902540758,-0.1481139511,0.6896650195,-0.5098571777,-0.3564096689,1.5234655142,0.8508958220,0.8980773091,0.5878921747,0.0211714022,0.1310488582,-1.7261478901,0.4319587052,3.3127100468,1.2555725574,-2.4129700661,0.1548143625,-1.3937963247,-0.0669993684,-0.4945868850,0.6425649524,0.4099414349,-1.2230517864,1.1344254017,0.2476155311,-0.0826025009,-1.7094839811,-1.3960864544,0.0779310912,1.0671143532,-0.7367090583,-0.8694255948,-2.1651918888,0.2056596577,-0.6978781819,-1.3931280375,1.1689006090,-1.0735945702,-0.1320720315,0.3157189786,-1.1467095613,-1.8069293499,0.3965733051,0.6804736853,1.1677420139,0.1507781297,1.5749038458,-1.6790566444,-0.4240026474,-0.0486205667,-0.4190273285,0.0764597952,0.2051582783,-0.1262133867,-0.0686233491,0.9195166826,0.2387665063,-0.1942841411,-0.9263069034,2.2984178066,1.1526581049,0.8616171479,0.3174169362,-1.7027870417,-1.7472238541,1.0208576918,-0.3556275070,-0.1951083988,0.7903609872,1.3327525854,0.8751086593,0.2799882591,0.1954333037,-0.3937276900,-1.7281918526,0.0852415413,0.9325007200,-0.1659661531,0.7091153860,-0.4390468597,0.0979182422,-1.1979483366,0.4096597433,0.1257333606,-0.6742489338,-1.5028485060,-0.7201532125,1.8562434912,0.0316390693,-0.5786090493,0.8689778447,-1.4990413189,1.0552029610,-1.6764425039,-1.5236849785,-1.5653573275,0.4090256691,0.1788931787,-0.1072124392,-0.7379006743,-0.0220090747,0.2177771926,0.6614961028,0.3497148156,0.2820779681,-2.2396645546,2.3719971180,-0.4914728701,0.3381384015,-0.9512355924,-0.4113211334,-0.1319223195,-0.7636014223,-0.0705542788,0.0945843682,0.5141342282,-0.2185685933,-0.5152382851,0.0872560367,1.3440091610,0.6572620273,0.4007388651,-0.5317484140,0.7063996792,0.9795297980,0.9454191923,0.4927286804,0.2224742323,0.0633541867,0.1593330353,-0.7465167642,1.2386281490,0.2575991154,-0.4987689257,0.2045920640,0.6867196560,1.4968909025,-0.3125460148,-0.9242553115,-1.4892401695,2.4101431370,-0.0921221748,-0.9982684851,-0.1168525666,2.1869966984,-1.4745687246,0.5221762657,0.1889460534,-0.8488870859,-0.9581833482,0.9912944436,-0.4461146593,-1.0186274052,0.8116633892,-0.7028707862,-0.2395506054,-1.3628484011,0.6342271566,0.4812361300,-0.8224328756,0.1313161552,1.5504002571,-0.9111961126,0.2188706696,1.0305371284,-0.0790315494,-0.9508096576,1.2417500019,0.4015571475,0.2897460163,0.1677240729,-1.4348064661,-0.5332908034,1.5793312788,-0.1691692472,0.1776634902,-0.2642582059,-0.5794829726,0.8309162855,-1.6052863598,-0.9368858337,0.9558969140,-0.0408717506,0.3745765686,0.6062545776,0.6897696257,0.6617829800,0.6259799600,-2.4486322403,0.3745160699,1.1456580162,1.0062994957,0.3313815892,1.0699118376,-0.6684012413,0.5727875233,0.6733343601,-0.0626238659,-0.4325711727,-1.7898069620,-0.7044024467,0.2529786825,-0.1920649707,0.3323691189,-1.1825512648,0.5753129721,-1.4658842087,-2.1032445431,1.1631325483,-0.5351141095,1.3923389912,0.8280168176,-0.7771325707,-1.1401008368,-1.7066495419,-0.6760823131,0.4116258919,-0.6975342631,0.6350879073,1.9184994698,-1.0803020000,0.3992839456,1.0008097887,0.1050618738,0.6947386265,0.9541548491,-0.4823937416,0.0798426941,2.0793166161,-1.0948320627,-0.7919138074,-0.3036155403,0.2675095499,-0.3363015354,1.2337770462,-0.0565242618,1.1298168898,0.2538796067,-1.4344059229,0.7543268800,-0.4848037958,0.1588084549,-1.9065899849,0.7605556846,-0.9614201188,-1.6162747145,-1.3088313341,0.7706814408,-1.2203983068,1.0250405073,0.1936548799,0.6911200881,-0.9923204184,-0.7455840111,0.4099641144,0.4822587371,1.1336737871,-0.3551127613,0.3467658460,-0.2646628320,2.0391478539,0.3230980039,0.8732517958,0.3943471909,-0.7295206785,0.6893681884,0.6827322841,2.2047653198,0.2522270083,1.0462615490,0.3333738148,0.9523355961,-0.5945228338,0.4556433558,0.6373681426,0.7313504815,1.3079185486,2.0483045578,0.9635858536,-0.7311703563,0.8531662822,0.1186441779,0.2476326227,0.7424806952,-0.1205264479,2.3297095299,0.2212003767,0.0787303224,0.4282938540,-0.7846913934,0.7370166183,0.1164571047,0.4009823501,-1.5018119812,-0.7576122284,0.2048009932,0.4468692541,-0.7943142056,0.9658300877,-0.0924994797,-0.5092731118,0.1271789968,-0.5681103468,1.2777352333,1.3446389437,-0.4176205099,1.1254996061,-0.1987000555,0.3697093427,0.6449429393,2.1140766144,0.0287610460,-0.2087999135,-2.2224323750,-0.1076841950,-0.5155770779,0.3130055368,-1.2204751968,-1.6488747597,-0.7013992667,0.9725614786,1.8311501741,-0.0420313030,-0.4865702391,-1.2558275461,0.0240110978,0.0409290753,0.5420319438,-1.2074099779,-1.4793547392,0.0677488744,2.0287189484,0.1211663187,-1.0394985676,-0.2092629373,-0.5419185162,-0.2526287735,0.6307049990,0.7881709933,-1.3417301178,0.5147671700,-0.1236193851,0.3639915884,0.0800566152,-1.4012484550,-1.3367093801,-0.9948487282,-0.2640236318,0.0116868606,-0.1084337905,-0.8910443783,-0.2605855167,0.7310494781,0.2275884598,-0.4247497022,-0.3506610692,0.5176494718,0.8392418623,-0.1413768381,0.4017984271,-0.8027892709,0.0070667868,-0.1382342279,1.1400476694,-1.2793195248,0.9133566022,-0.4161378741,-1.3781870604,0.1653951555,0.4276550412,0.1956777126,2.8762161732,-1.1102243662,0.1171223372,-1.6822745800,-0.9032545090,1.2693028450,-2.2613315582,-0.8250658512,-0.2805194855,-1.4849926233,-1.2322430611,2.0261244774,0.0272019934,-1.8280910254,-1.6233180761,-0.1065211222,-0.2862212360,-0.4451537132,-0.2557170689,0.4339169562,-0.9887716174,1.2868506908,1.1453354359,0.8280850053,0.1992067993,0.2173833102,-1.7708069086,-0.2707109451,0.7886084914,0.0197867677,1.5219205618,0.4495322108,-1.8151134253,0.1503618360,-0.8707200885,0.1044267043,-0.1727676690,-0.3222731054,2.0104050636,-0.2804686129,-0.0797644407,2.4352912903,-0.3499047756,-1.8723024130,-1.0576988459,1.5366865396,0.2987216115,-0.5741385818,0.7206164002,-0.5140460730,1.1396903992,0.4905533195,-0.7538064122,-0.0299488585,0.6763259768,1.1116752625,0.0127552878,1.0710752010,-0.6004653573,0.2281350344,-0.9140645266,-0.3691907525,-0.3375107050,-0.8282238841,0.7861650586,0.3188356161,-1.5241420269,-0.7093237042,0.6100569367,-0.1316596866,0.3417309523,-0.4438876510,-0.8978509307,-1.0393338203,-0.8868865967,1.9541177750,1.0689802170,0.0547712296,0.5502784848,0.0277117081,0.6421114206,-0.6505494118,0.6176762581,-0.9987822175,-0.1520087272,0.1977556646,1.4567295313,0.9476689100,0.3120063245,0.1578296274,1.3490449190,0.9076947570,-1.5802649260,0.0284059606,0.3208372891,0.6578550339,1.2572970390,-1.0926563740,1.2521040440,-0.6177709699,-1.0928300619,1.1918451786,-1.0383467674,0.2914623618,0.5544426441,-1.9991108179,-0.6491318941,-0.1269466877,-1.3599926233,0.2060403973,1.1349284649,0.5194821358,0.8900290132,-0.7164104581,0.5118864179,0.2188488990,-0.6501572728,-1.0021990538,0.9629164338,-0.6489469409,0.1203286722,-0.3681460321,0.0381681658,-1.0675135851,0.2147252262,-1.4677051306,0.9678803086,0.5567008257,-0.4400278926,0.5860223770,0.7764663100,0.7028333545,-0.2341640592,-0.5149731636,0.7935917974,-0.5220533013,0.6459440589,-0.2909165323,0.6664276123,0.5232625008,0.9840770960,0.6887192130,-1.1589708328,-0.1337791681,2.1475710869,-1.1999230385,-0.0397767313,0.2972322702,-1.1360603571,-1.0197287798,0.0860073194,-1.0629270077,0.7163521051,1.6431040764,0.8835981488,-0.8887983561,-0.4056135714,0.5577527881,-0.5359670520,-0.6085321307,-1.0848847628,2.3708302975,-0.3000078201,0.9129256010,-0.8528723717,0.7104384899,-1.4673618078,-0.0468426906,1.5498622656,-0.6497247219,0.1055054367,-0.6367157102,-0.7790260911,0.1303004473,-0.8807298541,1.2931112051,-0.0242201276,-1.3028495312,1.0931696892,0.8489127755,0.5620557070,0.3824717402,-0.8211005926,-0.2894999683,-0.3295023143,1.9161242247,-0.3875193894,-1.5950083733,-1.2387349606,0.9860461354,1.1215429306,-1.4169552326,0.7774617076,1.3781566620,0.4257713854,0.1041262969,0.6187925935,-0.1452303976,-0.1544398069,-0.3350002766,-0.7903438210,2.2526700497,0.5864151716,-0.0685864314,-0.6246374249,-1.3993204832,-0.4303893149,-1.2822613716,0.1559318602,1.5798255205,-1.0765495300,0.4107350409,1.3614157438,-0.7937434912,-0.1587989628,-0.0826069266,0.1638277918,0.3035634458,-1.0530942678,0.3941660225,-0.3778450787,0.5913537741,1.7228548527,-0.2308357060,-1.0750149488,1.7766871452,-0.2589304149,-0.6578678489,-1.3033595085,1.0156477690,-2.2127144337,-0.7063292265,-1.1299027205,-0.8751794100,0.0943318456,-0.8357192278,-0.6747906208,-0.1819349229,1.2726923227,1.1324168444,-0.0653668642,1.7812215090,1.4365423918,1.2911921740,0.6556486487,-1.8097792864,-0.4941692948,1.0009518862,0.9566744566,0.1753100008,0.7363275886,1.0797368288,1.5626415014,1.5590084791,1.1770696640,1.8266727924,-0.8828266859,-0.5780462623,1.1614030600,0.0819185227,1.1126433611,0.2359033823,1.5360554457,-0.7368761301,1.1381391287,-1.1523531675,0.4186245203,0.4560465217,-1.5258060694,-1.1486253738,0.0944953263,1.1487392187,0.4432187080,0.4212090075,0.1783284396,-1.0721273422,-0.6282792091,0.1184149534,0.1077746376,1.6965463161,-0.0277585164,-0.1918672770,0.5346242189,1.8567492962,0.9038385153,-1.7754197121,0.0008006179,1.3203227520,-0.9212475419,-0.1841087192,-0.1914251149,-0.2672573626,-0.7262297869,0.5493069887,-0.0501594692,0.4068301320,-0.4298945665,-2.2442214489,-0.7497539520,2.2230682373,0.1048255190,-0.7576667070,-0.2962541580,-1.4607772827,0.6312759519,0.2765136063,-1.7077609301,-0.3536328375,2.0978047848,-1.0209709406,-1.9278744459,-1.0835400820,-0.6693260074,-1.7807040215,-0.0103057222,-1.2683321238,-1.4392585754,0.5706706643,0.2299688011,-0.8338006735,0.0692932904,-0.0159100499,-1.2371246815,1.5750194788,-0.4039532244,0.0204617586,-0.3619193733,0.6404605508,0.3293938637,1.2330603600,1.0708794594,-0.2778260112,-1.0820939541,-1.1345940828,-0.9574249983,0.1622495651,1.4215382338,0.4582139850,0.4866745770,-1.1338460445,2.6203932762,0.3832954764,1.0140392780,-0.9759644270,-0.1634153575,-0.7954094410,-0.3030864894,-0.3183051348,0.4918797612,0.8558522463,0.3166932762,0.5860859156,-0.6056419611,0.1423945576,1.3445808887,3.1942925453,0.3613812327,0.7262311578,-0.0039374535,-2.8172578812,1.2778655291,-0.5762477517,0.8407689333,-0.7480339408,-0.7672458291,-0.1195229515,0.2324158102,-1.8714499474,0.5519493222,-0.5039342046,-1.7590987682,1.6869199276,-1.9298254251,-1.3470934629,-0.6425828338,2.0217587948,0.6767479181,0.3098316789,-1.4022588730,0.6783840060,0.8065295219,-1.1054807901,0.5464166999,-0.3851571679,0.3955411017,0.3208754361,1.5504038334,-0.2144103050,-1.5548576117,-0.2614115775,-1.4425181150,-0.2540749609,0.3945147991,-0.7667369843,1.4624339342,-0.0706093833,0.2780528069,0.8718714118,-1.7170612812,2.0644669533,1.3981959820,-0.0241681747,0.0153257139,0.1551327109,0.8673528433,0.4098148942,-0.4804344475,0.4392388463,-0.6017239690,0.0909047872,-0.6866038442,-0.8969714642,0.9651571512,-0.6932944655,0.6336821318,0.8397692442,2.6203660965,-0.6895518303,-1.7960164547,-1.6501295567,1.8551411629,0.1128157750,-1.7513470650,0.8404824138,1.3223236799,-0.5824505091,-0.0671811923,-1.2150722742,0.9815346003,-0.3406918347,-2.1729745865,1.5029435158,1.4895166159,-1.0849428177,0.0340151675,0.3322142959,-0.5848049521,0.1907823086,-0.8129360080,-0.0226928703,-0.0279446561,-0.2016942650,-1.1095571518,0.8078178167,-1.1353489161,0.2967233658,0.5234735012,-0.7270941138,1.1792708635,0.6389978528,0.3985453844,-1.2015575171,0.7863968611,1.1112177372,-0.5595420599,-0.5727396607,-0.8466938138,-1.9493989944,-1.0869103670,-1.0681582689,0.3008961976,-0.5245221853,-1.5388499498,0.6930798888,0.5540941954,0.9507279992,0.8663878441,-0.4860620499,-0.1471722573,-0.1502821445,-0.4803615212,0.6171793938,0.5383598208,1.2860487700,-0.1998111606,2.9812784195,2.1534991264,0.6020771861,-0.2183421254,0.5264843106,0.2851968110,0.4971400797,-0.9605002403,0.9666528702,-0.0700143129,-1.3566243649,0.3706783354,0.4595982730,-2.5560221672,0.3511317670,-0.6403661966,-1.2884974480,-0.6789479256,-0.6717274189,-1.2106477022,-0.0163370986,0.3457172811,1.6352626085,-0.4889360368,0.5581252575,0.3349420130,-0.1122701392,-0.9621224999,0.8743726611,0.5053303838,-1.8802504539,1.1275217533,-1.1256831884,1.3232104778,0.3116884828,0.9008846283,1.4898868799,0.0042057778,0.1580962092,-0.9577461481,0.0220026318,-0.4892366827,0.1239973605,1.1565297842,-0.4127237499,-0.1431506574,0.0075374050,-0.2322238684,-0.3758442998,0.4405148923,-0.2959225178,-1.9549883604,0.0191233903,-1.1686453819,0.3244661689,-0.7563298345,-0.9059374928,0.2940572798,1.7263318300,-1.4125913382,0.8717287779,0.8929125071,1.0991194248,0.7424063683,-1.1658024788,0.1678114682,-1.3147382736,1.0513582230,0.8278679848,0.9144086838,-0.2248248011,-0.6977533102,0.7616482973,0.1096616462,1.9541888237,0.2071506679,-0.0072634853,1.6672128439,-0.2180464268,0.2142009735,0.6916992664,0.8198504448,0.2656022012,0.4191500843,-0.1563543826,-0.0766619965,-2.0684545040,-0.5974961519,-0.3178389370,0.9397915006,-0.2236629725,-0.6539345980,-0.1499699354,1.3334772587,-0.2018540204,-0.8706596494,1.8530994654,-1.2432664633,0.0694535226,-0.6399093866,0.5563447475,1.1774454117,0.3720839918,0.0705601349,-1.5265114307,-1.3808004856,-0.7226364613,-0.0671254769,-0.7904212475,0.1652627289,1.6826713085,0.9410175085,-0.1707097888,-1.1935794353,0.5031608939,0.7144062519,0.3102995157,0.0893526301,0.4119528830,-0.6044661403,0.7267200351,-0.5432944894,-0.4802464545,-1.2587251663,-1.6022361517,-1.0864841938,-1.4701102972,-1.3144232035,0.9932833910,-0.4609676600,0.4559967816,0.9519225955,1.9400188923,-0.9149392843,-0.5548046827,-0.0177294016,-0.7559466958,0.4510883987,-0.0255159680,-1.1708710194,-0.7565687299,1.3700623512,-0.8828909993,1.1024614573,-0.4919537604,-0.8594636917,-0.1812487990,-0.5608417988,0.7042586207,1.0489093065,-0.0738557726,-0.3878282309,0.0897080898,0.6622738838,0.3745981753,-0.2529806495,-0.2844143212,-0.0747609586,0.3734287322,-0.3683740795,-0.9679385424,-1.5396726131,0.1518522203,1.1448954344,-1.1830432415,2.3214013577,-0.2190132141,-1.0381678343,0.4893311262,1.2217268944,0.4482461214,-0.7320929766,-0.0737974867,-0.4775159955,-0.2962387800,0.9918540716,-0.2520774901,0.7377212644,-1.1158239841,-0.3469292819,0.7313711047,0.6559993625,-0.9429005980,-0.9391338825,0.8579667807,0.0583344996,-0.0099074114,1.0966665745,0.1336360723,-0.1326661706,-0.9921869636,0.5340189338,-1.0867534876,-0.4550673962,1.3559694290,-0.1116294712,1.0091249943,0.1412471086,0.5255767107,-0.3881579638,1.3969186544,-0.1676418036,-0.1452837437,0.9945383072,-0.2506922185,1.1986724138,-1.7370616198,-1.3467944860,0.8549793363,0.2784049809,-0.6807608008,-0.6913851500,-2.2432849407,-2.3831932545,0.7839045525,0.0188699197,1.0645942688,0.1286784858,0.4382385910,-0.6687325239,0.5978592634,1.1087765694,-0.1641141921,-0.3620709479,-1.7388533354,1.3200438023,-0.2533108592,-0.4184384346,-1.5299417973,0.5822222233,-0.5063092709,-0.1981868595,-1.3021932840,1.2743741274,0.0432033651,0.4569822550,-0.5047770739,0.1699194163,-1.3279764652,0.3524358571,0.1321837306,0.5692359209,0.6053616405,0.2480343133,1.6470834017,0.3169894814,-0.5630028248,-2.4546029568,-0.3362979591,-1.3944190741,0.7804767489,-1.0859674215,0.4189290106,0.8998404145,-0.6749925017,-0.7698157430,-2.2536473274,-2.3058500290,1.2095606327,0.1959027052,0.3622468412,0.0256938580,-0.9933300614,0.4945476353,0.9161879420,1.4648804665,-1.8006176949,0.7049255967,0.8880855441,0.4263364673,0.2365619391,-0.3710543811,-0.7134770155,-1.3234868050,-0.0384293981,-0.1907331049,0.2600144148,-0.8479497433,0.5255256295,-0.5529755354,0.1325170100,0.2094378769,0.3922344744,-0.2805377841,1.1552339792,0.0220841095,0.7056201100,-0.8617077470,0.5466896892,0.8280608654,1.7718749046,0.5791893601,0.3954809308,0.6250145435,1.8468208313,-0.5212256312,-0.7269707918,-0.0188041087,0.2731238902,-1.7006938457,1.2754198313,0.4935974479,-1.1783540249,0.6881445646,-1.0047477484,0.8587782979,-0.4211801887,-1.1423093081,1.8459129333,0.4986789227,0.3107667565,2.1952350140,-0.2329679281,2.2344813347,-2.3799045086,-0.6172450185,0.9939242005,1.6428675652,-3.8169021606,0.8213685155,-0.2383841127,0.8085193038,0.8943603039,-0.7287612557,-0.8341719508,-1.6358424425,-0.0163045768,-0.3030619025,0.0600189455,1.0085133314,-0.7476360202,-0.5483891964,-0.9263272285,2.6085176468,-1.2780238390,-0.9766176939,-0.5389821529,1.3002591133,0.9012833238,1.6520648003,1.8740491867,2.7003669739,1.3751206398,0.7383854389,0.4513852000,-0.0785458460,0.9784024954,-0.9420097470,1.0711314678,0.1228365153,-0.4089529514,-0.0938136727,-0.4688596725,-0.0395304710,-1.4214097261,1.9610992670,-0.8136855960,1.5312091112,0.7010276914,-1.3808984756,-0.2077739984,-1.0954723358,-1.5649642944,1.6708961725,0.0262108147,0.4416314065,-1.0797450542,-0.4252988994,-1.1980069876,-1.4782294035,-0.9501484632,0.0933405459,0.8175611496,0.4934800565,-0.0887110531,-0.2513252497,0.2430290729,0.0722308606,1.1764454842,-0.5189903378,-0.4726536572,2.1911048889,-0.4614456296,-0.1552190930,0.6430007815,2.3364167213,0.8803315759,1.2821724415,-0.1783988476,0.6398929954,-0.6916404963,0.0685556680,0.4741430879,1.7757326365,1.3293614388,-1.6313576698,-1.1642336845,0.3845895231,1.0874531269,0.8030692339,0.9298844934,1.1026318073,-0.4465782642,-0.9066677690,1.6973699331,0.3255869448,0.4437576234,0.6298837066,-0.1388432831,0.4877704084,-0.5768527985,-0.6939834356,-0.6422843933,3.4686851501,-0.8099491000,1.0799697638,-1.1004024744,0.4231131375,0.1130894870,-1.2025954723,-0.4120817780,-0.9697688222,-0.8534077406,-0.5020948052,1.3400472403,1.7938925028,0.6689025164,0.9888962507,0.2849170566,-0.0868029594,-0.2804565132,0.2670521736,1.1490031481,0.2609162629,1.0914986134,-0.1469503343,-0.1726162434,-1.0124996901,1.6172940731,-1.4287543297,0.0207366310,0.4133826494,-2.1272759438,-1.0434956551,0.3534581065,1.8912388086,-2.0706202984,0.7521951199,0.1733450145,0.3660833538,0.4582214057,-0.0752727687,1.0993863344,0.7004218102,-0.2836722732,-0.3275241554,-0.9340184927,1.6282463074,0.6356199384,0.0225061178,-0.3679436743,-0.3817060590,0.6974017620,0.0895482525,0.4078374803,-1.0503004789,-1.8791811466,-1.1724802256,1.0532171726,-0.0058436240,0.2517630458,-0.7201429009,1.2702769041,-0.0458424352,0.4193159938,1.5528337955,-1.1905040741,-1.3259557486,-0.5397362113,0.7404883504,-0.9480809569,0.7349120975,0.2989366651,1.1667926311,-0.0275125522,-1.9530737400,-1.0072118044,0.5982735753,-0.7819896340,0.2409633547,1.0072343349,0.5993404388,0.1452574730,0.4981725514,0.4348387420,1.0504794121,0.9790147543,0.6895599365,0.1251991391,-0.8385702968,0.8198758364,0.3724953830,0.5099990368,-0.4112640321,0.1107642874,0.3995991051,-0.3792087734,-0.1735995412,0.0200130008,-1.1897200346,-0.0422304757,-1.0703550577,-0.0569381416,-0.0801360905,-0.8206369281,0.7945466042,1.3026648760,1.1943631172,0.4166095257,-2.3133356571,-2.0431711674,-0.0859138668,-0.7850488424,0.4934567809,-0.0740535557,0.5806821585,1.1419591904,-0.5928174853,0.3389694393,0.9335060120,1.5325789452,0.2682217956,0.6445912719,-1.1811283827,-1.3357715607,-0.2605241239,-0.1114650816,-1.0182495117,-0.1397437006,0.4789614975,-1.3894425631,-0.8259648085,-0.9689841270,0.7458997965,0.2991378307,0.8106826544,-0.3790820837,0.7313722372,0.6382530332,2.0013265610,0.2483182549,-2.0251369476,0.1511827558,-1.8691866398,0.3484821618,-1.3629926443,0.0344463214,0.2344449162,0.4313440025,0.2729780376,-1.5452675819,-0.0550522581,-0.6612935066,0.5417645574,2.0425043106,0.2200262994,-0.1124477014,-0.3067903817,2.6385672092,0.0758075565,0.9185811877,-1.1661971807,0.0555665419,-2.0132887363,-0.0612099841,-0.0498628020,1.1586894989,-0.4992930293,-1.0344942808,-2.0566396713,-1.7438385487,0.4182908833,1.9617835283,0.3961114585,1.9309381247,-0.4613923132,0.1689138561,-0.1322667748,-1.2334487438,0.9377317429,0.7998334765,-0.6520880461,-0.1707964838,-0.5642157793,1.2804228067,0.0208851863,-0.5527569056,-0.4434795380,0.0876937509,1.7762702703,0.8643834591,0.7251709104,-0.2246964127,-1.1765624285,-0.8831675053,-1.3195488453,-1.7548000813,-0.6290677786,0.4152307808,0.5666602850,-0.2163264304,-1.6369053125,1.3941433430,-1.7514255047,-1.9723445177,-0.7031470537,-0.9993395805,-0.8704144359,-1.2276570797,2.4672963619,1.1786454916,0.2572571933,0.2190767229,0.6950595975,0.7149975300,-0.0045571011,0.5289281011,-0.6817349195,0.7423099875,0.0222218968,-0.3022816181,-2.5626525879,-0.8660374880,0.5463693738,0.1478862166,0.4148804545,-0.2576435804,-1.3388051987,-0.9884957075,-0.1858710945,1.3034764528,1.2491785288,-0.2166267633,0.3619436622,-0.5870447755,0.4298285246,0.4556368589,1.4775171280,-1.2154983282,0.4434569776,1.2889420986,-0.1644225568,1.5875742435,-1.2383381128,0.1369165182,0.8227247000,-0.2720991671,1.3772487640,-1.0866830349,0.5779238343,-1.3674609661,0.3796960711,-1.2340633869,1.5236074924,0.8480984569,0.8815364242,-0.2750021517,1.0931401253,0.3164792061,-0.6241439581,1.0555865765,-0.3296152651,-0.9498324394,-0.6139930487,0.0078044580,1.9462395906,0.1260036528,-0.0267669503,1.5000147820,-2.2058892250,0.2527365386,1.4516202211,0.0328859240,1.4210357666,-1.8086668253,-1.2372293472,1.3431107998,-0.3939828873,0.3295665383,0.0458708517,-0.8294584155,2.3301115036,-0.1783146113,-0.3502511084,-0.8924494982,1.0734086037,-1.8520869017,-0.9093677998,-1.1956225634,-0.4636309147,-0.2347074598,-1.0941042900,0.7002073526,-0.0075926357,-1.6863496304,1.6743515730,-1.3652117252,-2.9964680672,-0.0707102716,0.1781398654,0.4942721725,-1.4362123013,-0.7788179517,1.6206996441,0.2547658384,-1.1822535992,0.9864816666,0.3597769141,-1.1920862198,-0.5226871967,-0.6126774549,-0.7237797976,-0.1754818857,0.2489106804,0.8328000903,-1.1851280928,-0.5307146311,-0.6191227436,0.7989680171,0.1682512611,-1.1042748690,1.3994650841,1.0414515734,0.0627358332,0.6830793619,-0.0892262608,1.5641775131,-0.1822139621,1.6051907539,0.8997560143,-0.0619025528,-1.2406721115,1.5553014278,0.6757091284,0.2351159900,-3.2029783726,-0.2392832935,0.0999327451,-1.0192216635,-0.5507404804,-0.4247370958,-0.1092737615,-0.4355481267,2.0317144394,-0.2517910004,1.1875435114,1.0763266087,-0.6341527700,1.2765887976,-0.6087099910,1.2905139923,0.2440712750,-0.2550278902,0.6374529004,1.1602060795,-0.5558677912,-0.7458577752,-0.1815477461,0.1130491644,-0.1535087526,0.8310692906,0.2297729254,1.5552196503,0.3676000535,0.1164899766,-0.2793305516,0.0842381567,1.1744824648,-0.5380910039,1.1350588799,1.6307651997,0.5054000616,0.3415246606,0.1714084893,1.2019101381,0.0502630584,0.5542773604,0.9386487603,-1.0577836037,-0.2838217020,-0.6229845881,0.0756353810,-2.2039809227,1.0031237602,0.8466241360,-0.4926395118,-0.3171692491,-2.5975430012,-0.9221938848,-0.4696512222,-0.1379987448,1.6596388817,-0.7340003252,-1.3171730042,0.3707151115,-1.3485159874,-1.1177152395,0.8394469023,1.7678155899,-0.5140664577,0.3884877563,1.1650243998,-0.7375556231,0.0720298588,-1.3064266443,0.8903331757,-0.4982529581,-0.2980082631,-1.1973793507,0.4307799637,1.4663467407,-0.4940899312,-0.1184043512,0.6036401391,-0.6061331630,0.1731641889,-0.4107045531,-0.2922571301,-1.0013037920,0.1425794065,-0.4769991040,-0.8599395156,-1.5917048454,-1.4707101583,-0.5162295699,0.0312709026,0.9078719616,1.0566560030,-0.0541705601,0.4534251690,-0.3871499896,-0.1667667329,-1.3632845879,0.8195942044,-0.7354663014,-0.6091674566,0.8308277726,1.1752266884,0.7835314274,1.3266550303,-0.0654770806,-0.3728080094,-0.8336992264,1.1622248888,-0.3846301138,1.0055280924,-1.2250599861,1.1725132465,-0.1270800084,1.9019786119,1.5142729282,-0.1225099191,-0.1151846126,-0.1686504632,-0.0648666248,0.1656596959,-1.8448135853,-0.4019766450,-1.2433512211,-1.1153597832,0.9793652296,1.3056718111,-1.3503453732,0.5518975854,-0.2453743219,0.0945341364,0.9384822249,-0.4939763248,0.1662771553,-0.0385320112,0.4536897242,1.6621969938,-0.8693246245,0.5161611438,0.3339156210,1.2932506800,0.8945618272,-1.8559041023,-1.0705528259,-0.6615146399,0.0996204913,0.4900225997,-0.2379509211,-0.0018551836,-0.0410420187,-0.6998842955,-0.6224127412,0.7980476022,1.6843181849,-1.3955712318,-0.0199635271,0.6951984763,0.5448355675,-1.4337213039,-0.6472737789,0.5337479115,-3.0123813152,0.1207514852,0.3387083411,1.0219434500,0.3195720017,0.4922348559,0.4318786860,-1.5374253988,0.2995702624,0.6266925335,-0.1475751251,-0.9628657699,1.3692935705,1.7332062721,1.0504539013,1.6112185717,0.3021770716,-1.5211652517,-0.0542259924,0.7082381248,0.2385789454,-0.5415235758,0.2251457572,-0.7766765952,-1.1232200861,1.4787577391,0.0738270581,0.9700493217,1.4055027962,0.2390944362,2.5265150070,1.1471470594,-1.9478795528,0.3010020554,-1.1164835691,0.5054375529,-1.1840339899,0.8414674997,-0.2105533332,1.0772610903,0.1378324628,-0.2625436783,-1.2023355961,-1.2959524393,-1.9612358809,0.4218974710,-1.6659665108,-0.5268239975,0.9753533006,1.0594240427,-0.2273750156,-0.7501193285,1.5347290039,0.6678853631,-0.0581064932,-0.1379352659,-0.2763449848,-0.2625544667,0.9622181654,-0.5553058982,1.4604641199,-1.2602964640,0.0350733362,1.3494240046,0.0647262409,-0.2970011532,-0.1286823303,-0.4147179127,0.3933965564,1.0783635378,-1.1027158499,0.9179580808,-1.1704337597,-0.1262967438,-0.6603304148,0.2892201245,0.3097912669,-0.4064918160,0.6283999085,-1.0411736965,-0.0379688144,0.0183309894,0.4731063843,0.9111999869,-1.3404321671,-1.8525221348,0.4234216213,-0.0911732167,-0.1249522865,0.3678356707,0.5566195846,-0.0299841147,-0.0175340120,1.2085926533,0.6181845069,0.7668458223,0.2914898992,-0.3310023546,0.5573409200,1.2957259417,-1.1349855661,-1.5247069597,-0.1056646109,0.8937266469,-2.4366216660,0.4809564352,-1.0557091236,-2.0977416039,2.2568325996,0.8655489683,1.5234045982,0.7148271203,0.9997466803,-0.3668726683,1.5002795458,0.5295903683,-0.0688808635,-0.3074559867,-0.5956582427,-0.7585545778,-1.7481904030,-0.7318330407,-1.0182477236,0.2035604119,1.8202784061,-1.6629431248,1.1729696989,-0.8748952746,0.4623175859,1.7992956638,-0.2273533642,0.8438876867,-0.5174407363,-0.3450641334,-0.2517184317,-0.4905411601,0.6074772477,0.8887094259,-1.1760468483,0.2600905597,-1.2200479507,0.8933705688,2.1258146763,-0.5572912097,-1.8600933552,0.7779752016,2.5773346424,0.1733140200,0.1253862232,0.5314847827,0.2223214656,-2.9037373066,-0.9753293991,-0.8351879120,0.0942138582,-0.6895788908,0.7909314632,-0.9552357197,1.1238473654,0.5297656655,0.7592256665,0.2255097628,-0.8313544989,0.9092111588,-0.3085229695,1.8506548405,-0.2688187361,-0.0903450549,1.1477758884,-0.8157768250,0.5765594840,-0.6213289499,-1.0924533606,0.3988735378,-2.0458335876,-0.5939063430,0.9805639982,-1.0290400982,0.0781027302,0.2894194126,-0.0519753769,0.8758471012,-0.3554590642,-1.8353921175,0.0100867106,-0.4113383293,-0.2478044927,1.4757231474,-0.1460000873,-0.1348475516,-1.9121975899,1.1605008841,0.4398345947,-0.8364595175,-1.1910685301,-1.2645142078,0.6124418378,1.1392834187,-1.2183645964,0.0038925342,-1.0627678633,-0.7069594264,0.4486484826,1.2478134632,-1.8462580442,-0.6957844496,-1.5319015980,0.6585696936,0.7199642658,-0.2957348526,0.6642016768,1.3873531818,0.9918613434,0.2797018588,-0.4639515877,-1.5886434317,-0.4204191566,0.8649352789,0.9510036111,-0.9391480088,2.0292148590,-0.1282894462,-0.7238674164,-0.1788964719,0.0195331033,1.0771375895,-0.4234253764,1.4801914692,-1.7666741610,-0.5446242094,0.6746259928,0.1982609779,-1.1595536470,0.9801321030,1.8839025497,0.2379632145,0.5130231977,-0.6771757603,-0.3835451603,0.6720554829,-0.5601616502,-0.2693561912,-0.7150922418,0.9604054689,-0.1766158491,-2.1141669750,-0.1035743877,-0.1573709249,-0.6674705744,-1.6187994480,-0.3529086113,0.0866112337,2.2035353184,1.0520107746,-0.4452825189,-0.3899340332,0.1289973855,-1.2968221903,0.3952779174,-0.2544807494,-0.4893265963,-2.1965639591,0.2055465132,0.7529613376,-0.3973491192,1.2315872908,1.6232351065,-0.0800956413,0.0522243381,-0.6569432616,-0.7473552227,0.1069898829,-0.9588980675,0.2506351173,-0.0965848640,-0.0504180305,0.5609652400,2.0323703289,0.0770998970,-2.0426630974,-1.7376391888,0.7450774312,1.9501069784,0.6154040098,0.9178984165,1.4370058775,-1.7092440128,0.5272009969,0.5203163028,-1.1656514406,-0.5942999721,0.1818185747,1.5111366510,-0.0468265265,-0.5543540120,-0.1215622202,-0.8664098978,-0.2492751628,0.0694557428,0.1134820506,0.3137679100,-1.2232038975,0.8229790330,-0.7367380857,-1.8020118475,0.0884521306,-0.8212783933,0.2604509294,2.0971336365,-1.0609384775,0.7672310472,0.5581717491,0.0284287650,-0.7300484776,1.6223838329,1.8920705318,0.7585506439,1.2013385296,-0.6682579517,0.5687101483,-0.0458690971,0.7914537191,0.6461397409,0.5958306789,0.3313758969,0.5736564398,0.1297451556,0.6420159936,-0.3512704968,-1.6068793535,1.0904586315,-0.1694664806,0.8543040752,0.4681234062,0.6300991774,-0.5073465705,0.0981798470,0.5250322223,0.2505944371,-0.7383431792,1.5344400406,0.8768033981,0.9915237427,-0.1485308558,2.7769432068,-0.7796960473,-1.1073904037,0.6106311679,-0.1776532382,-0.7403364182,-0.0547751002,0.1981050968,0.4532022774,0.9392779469,-0.8190399408,-0.7111040950,-2.2401287556,0.0680859536,-0.5838615298,0.2028556317,-0.4420544803,-0.5240891576,0.1586313397,-1.1596050262,2.0908944607,-0.6640832424,-0.0376775339,-1.3674635887,-0.0834356248,-1.1543424129,-0.2867710888,-0.2558217049,-1.2492008209,1.9734691381,1.3248716593,1.6726819277,0.1237697229,-0.5251456499,-0.0927522108,0.9765563011,0.4406595230,-2.0358545780,-0.0322042890,0.2834545076,-0.2984555364,2.5113687515,0.6123604178,-1.7609668970,0.1541956365,-0.1179339066,-1.6794335842,-0.0388058573,-0.3712675571,-1.3224407434,0.8247251511,0.1571902931,-0.4441169202,-0.0230798498,-0.0669803545,0.8565628529,0.4665855765,-0.7799400687,-0.8101128936,-0.5259451866,-1.4127696753,-0.9107655883,-0.0380207002,-1.1302808523,0.2475105673,-1.0421621799,-0.2518622875,-0.6521123648,0.9967294931,0.3215339780,0.1610585898,1.0579377413,1.0964981318,1.0885875225,1.5951294899,-1.4319165945,0.5318467021,0.3024968803,-2.2370159626,0.3017950356,-0.3017114103,-0.6175892949,0.8086286783,-1.0254920721,-0.7773222923,0.3564308882,0.8522893190,-1.5144516230,-1.2158509493,-0.0528383479,-0.2945184410,-1.1897754669,0.1364751011,-0.3321232796,-2.0284500122,-0.6192065477,-0.9456180334,-0.1601357013,0.4249179065,0.1432779431,-1.2779705524,-0.1355749816,-0.5009277463,0.6132161021,-0.2418944091,-0.2416060418,-0.2200713307,1.8523660898,-0.1587850600,-1.9892187119,0.9731972814,1.1787183285,-2.0948641300,-0.8218100667,0.9060323238,-1.3545004129,0.5676369667,0.1284798980,-1.0084096193,1.4587696791,-0.5944750905,-0.5187753439,-0.6267364621,0.0450868420,0.2594417930,0.8670076728,0.4846119881,-1.4180843830,1.0617189407,-0.2597389221,0.9757429957,-0.9346953630,-0.4718877971,-0.1700360179,-0.2180638164,1.1518630981,-0.5961496234,0.1541005969,1.2585749626,0.1049211174,0.1370392442,-1.1218445301,-1.2547951937,-1.3814834356,0.9695735574,-0.1086363643,-0.8288313150,0.5897889733,0.1763927042,-1.6123449802,-0.3767241836,1.0482236147,-0.6818988323,-0.8554486036,-1.0561922789,-0.9120386839,-1.0435223579,0.7464059591,1.5055519342,0.5351999402,0.1048421785,-1.5796937943,-0.1231038421,-0.1131892130,0.0296576433,-0.1823898405,-1.0289748907,-0.8570144176,0.3856546283,1.2521356344,0.4814043343,-0.6368389130,-0.4543634653,0.7679942846,1.6410802603,1.9045054913,0.1016824543,-0.9051506519,-1.0915925503,0.5618121028,-0.0764838457,-0.1261715442,-0.2757646739,-1.6904895306,0.1201585308,0.4685803950,-0.7667537332,0.5887155533,1.0020669699,-0.4119359553,0.5783369541,2.0256936550,1.3819185495,0.9228142500,-0.8997434378,-2.1333208084,0.5421010852,0.5343675017,-0.1246316880,-1.4611852169,-0.3485037684,-0.1807983965,-2.3376026154,-1.5892693996,0.0738651678,1.8555306196,-0.3728599250,-0.7936410904,-0.7694765329,0.1537291110,-1.2192952633,1.0588021278,1.7063795328,-1.4852479696,0.7988227606,-1.5708323717,-0.0804250613,-2.3823585510,-0.7975266576,-0.6703687906,-0.1327716857,2.0303711891,0.4827000797,-1.0179685354,-0.1614174098,0.3180173337,0.4515491724,1.3316066265,0.6386704445,-0.2509791851,-1.0985279083,-0.5632628798,0.0922431201,-0.0308225118,-0.3874062300,1.0752867460,2.0628256798,-0.0924772248,0.5879930258,0.2235952467,1.9383288622,0.2087660283,1.0126709938,-0.9500865936,0.8185034990,-0.6236126423,0.2088777721,0.1101473123,0.3424575925,-0.1206818819,-1.3793892860,-0.4113827944,0.9614917040,-0.9937870502,1.7580798864,0.0080232378,1.3879599571,-1.9699418545,-0.0177614167,0.3617301583,-0.0824940875,0.4315568209,0.5943727493,0.3909710050,-0.2284035534,-0.0388397276,0.7088179588,-0.8342286348,1.0389921665,-0.4749735594,-1.2656178474,1.6008704901,0.0157479066,-0.8812649250,-0.2172022909,0.5726627707,1.1687834263,0.7123550177,-0.2866460979,0.9056574106,-0.1671238095,0.7700747252,-1.4749193192,-1.9875162840,-1.9177916050,-1.0036017895,2.3900575638,0.1375515759,-0.6110166311,1.5173581839,-0.5640364289,1.3913329840,-1.1090196371,-0.4102989435,-0.4230274558,-0.8586001992,-0.0699972957,0.5191432238,-1.7878763676,-2.2792520523,0.4116008580,-0.5971567035,0.6625709534,-0.1563580632,0.0519339070,1.3340390921,0.3207374215,0.7841516137,-0.1863603294,0.8826067448,0.8950135708,2.3930306435,-0.1827965528,-1.4979075193,0.6857637763,0.4625678360,0.2142915875,-0.6569813490,-0.3911370039,-0.0136631001,-0.4137517214,1.3745381832,0.9061549902,-0.6315728426,0.3884846270,0.7096084952,0.2195208967,-0.9828910828,-0.6491459012,-2.3690044880,-0.1559623629,-1.0859808922,-1.3553333282,0.2614978254,0.3400335610,0.7255932689,0.0967543870,0.3278695047,-1.0589563847,-1.6091902256,0.5406217575,2.1439728737,0.6192141771,0.9494862556,-1.4554423094,-0.0448695049,-1.4860472679,0.5595998764,-0.9465503693,-2.0627651215,0.4471147358,-0.6683236361,-1.2262574434,-0.2228455693,-1.3789155483,-0.5255289674,0.1673466712,0.5638135076,-1.4176610708,0.5824736357,-1.4399206638,-0.2605627477,-0.5131645203,1.5817571878,0.9342992306,2.0273759365,-0.9074780941,-1.4963614941,0.2098528743,-1.3330277205,-1.0364831686,-1.1096246243,1.2138468027,-0.6777035594,-0.9634899497,-0.2676663101,1.7159404755,-0.5196566582,0.5119627118,-0.3616420925,-0.3848065436,-0.2256528139,0.3118752837,-0.3490059674,0.1993868798,-0.9058728218,0.4433694780,-0.3112775981,-0.0912733003,-0.6117324829,-0.5883981586,1.7798914909,0.0368696302,0.5935785770,-1.6113942862,-1.8226302862,0.7137543559,0.3825588524,-0.0519888066,-0.5621618032,1.2645081282,-1.4425507784,-1.0361926556,0.5223254561,-0.3062395751,-0.6406183243,-1.5627833605,0.7695292830,-0.3185529113,0.1646706760,-0.3141778708,0.6940912008,-1.3859407902,0.2595100701,0.9433202147,-0.9889213443,-0.7876140475,1.5091377497,-0.0022732059,-0.9895153642,-0.7657221556,-0.3768515289,-0.7495852113,0.9069278836,0.8732688427,-0.6578397751,-1.8318632841,-0.5395345688,0.3903403282,1.3636548519,-0.5079500675,-0.4028911889,-0.9917718172,0.4559382498,-0.0439116731,0.6223576069,-1.9363251925,0.2596221566,-0.4668768048,-0.1926385313,-1.1734788418,-1.9986387491,1.9325946569,-1.3068764210,1.1438997984,2.0557627678,1.9167425632,-1.3739305735,1.8942967653,-1.3069814444,2.5766277313,-1.2845826149,2.6390814781,0.0117756752,-0.8140695095,-0.0189126283,-1.7700136900,0.1316619217,0.6881023049,-0.0800242648,-0.3123969436,-0.1349624991,1.1459685564,-0.3061838448,0.8619158864,-1.3219367266,1.3408268690,-0.2174276561,0.7989725471,0.1819919050,0.3068866432,1.5338616371,2.0315186977,0.7892776132,-0.7427718639,0.5892996192,-0.0023908424,0.2674568594,0.0645150989,-0.4013667107,0.8512451053,0.6213958859,0.8364474177,1.9893764257,-0.1589120328,0.4406788349,-1.8999271393,-0.0583184175,2.8087897301,-0.6425076127,0.5418109298,0.3948427141,1.2454727888,0.4545042217,-2.7257065773,-0.8574002385,2.5853521824,-0.3502472937,-0.5604780912,-0.6599280238,-1.1559455395,1.3983881474,-0.8947708011,-0.3445873260,0.0215723384,-0.5061492920,-0.1462244987,2.1528968811,-0.8219048381,-0.6240154505,0.9768301845,0.6534996629,1.4312934875,0.5451650620,-0.1355044693,-0.4385142028,1.1829334497,0.8356802464,-0.5545064807,-1.4946864843,-0.9651259780,0.8002617955,1.6885603666,0.4508632421,-0.5405079722,-0.7677236199,2.1276350021,-1.5085190535,1.0470719337,-0.3742038906,0.4816255867,1.2239198685,2.2002627850,-1.1459487677,-1.9393211603,0.8348519802,-0.8973862529,-0.0270348825,-0.4584574997,0.2868529260,-0.0345946364,-0.9449191689,1.6783432961,-2.5124733448,0.2714243531,-0.7285017371,-1.1114827394,0.4374779165,1.2229865789,0.1188821420,0.6417844892,-0.0339858830,0.1788398623,-1.2683531046,-0.8834310770,0.0883188769,-0.7413329482,0.4079362750,-1.5605533123,0.6710539460,-0.3997884691,-0.8656931520,0.5296225548,-0.1787042618,-0.6306082010,0.1262859553,-0.0460716784,0.9800592065,0.6499250531,0.2291618437,1.3460974693,-0.4842807353,-1.3417708874,-0.3950604796,-1.0232306719,2.1392402649,-0.4437207878,0.3694180548,-0.8835060000,-0.7907400131,-0.6032630801,-0.4702125788,0.0179922599,-0.4642401636,-1.3101488352,0.8742898703,-0.7117217183,0.1661468446,-0.5677089095,-0.8415204287,0.5891016126,1.4322475195,-1.4599040747,0.4364635944,0.7957346439,0.4348514676,0.2555656135,0.7927491665,0.1485411376,0.5828484297,0.8439933658,-0.5871391296,0.0046702735,0.2771545649,-1.2712996006,0.2197576612,0.0016449381,0.9348805547,-0.1721846610,-0.2281569988,0.4430972934,-0.7958605289,0.9351830482,0.1677804291,-1.0998831987,-1.4856913090,-0.7987915874,-0.0081814257,0.3317958713,0.0209362600,0.9280778766,1.3373113871,-1.8254497051,-0.4517202079,-0.4237102866,0.4339829683,-0.0882978663,-0.8270207047,-0.5583283305,1.0447891951,0.3826203048,0.6272954345,-0.4586470723,0.5723845959,0.7396498322,1.7548961639,1.2826986313,-0.7351671457,-0.8461158276,0.0586707927,0.4825576544,1.0927946568,-0.8203950524,-1.0296913385,-0.1650319546,1.3045974970,-0.0735537857,-0.5020622015,-0.2131796926,-1.9353233576,-0.0282856803,-0.0519692637,1.2257838249,-0.3289196491,0.0804954693,0.6277905703,-0.4614386857,0.8901169896,0.6736842394,0.2361200452,-1.7104322910,1.4444857836,0.6761213541,1.8072758913,0.5737406015,0.1480455250,-0.5947783589,-0.0989431441,1.4684959650,1.1539797783,0.2363432348,-0.1957866400,-1.4308358431,-1.0022342205,0.6599704027,1.3189892769,-0.0529710427,0.7598709464,1.4087154865,-0.1161145121,1.4070295095,0.5922804475,-2.0745668411,1.0892683268,0.6900909543,0.2436967641,0.5517532825,1.2490776777,0.1645147800,0.5463775396,-1.2008447647,-0.6278283596,0.5528708696,1.0359449387,0.0826989859,-0.2087807506,-1.0988688469,0.8048434258,-0.8141828775,0.3546221852,-0.2129131258,0.2873154879,1.7163056135,0.3986051679,-2.2500936985,1.6220793724,0.1039571762,-0.6963388920,1.6507164240,-1.1810199022,1.0891958475,0.4307694137,1.2198220491,-0.9328013062,-0.7104882002,0.2273416668,1.2003076077,2.2550117970,-0.9103827477,-0.5597643256,-0.4322056770,-0.4192131460,0.7286592126,0.0349851511,0.8051463962,-1.2571941614,0.2547564805,0.2583035529,-0.4347037077,-0.0791249797,-1.6814187765,0.5205547214,2.3092405796,0.7493299246,0.9001592994,-0.1037041694,0.7711718082,0.3438462913,0.4822458625,-2.0766065121,0.0221872889,-0.0421145484,-0.7678053975,0.3982978165,1.2170741558,-0.4540759325,-0.7831273675,-1.0605846643,-1.6356533766,0.2026299387,-0.1641400456,1.0439503193,-1.0182771683,0.1616994590,-0.2499357611,0.7871867418,0.1861835867,0.5747888088,-1.7889155149,-1.9064621925,-1.0385804176,0.7762565613,0.3348379731,0.2335910946,-1.0033197403,0.7750243545,0.6567839384,1.4885655642,-1.0188703537,0.4090184867,-0.0310165752,0.5363311768,1.5438086987,0.6926738024,0.9071796536,-0.1791453212,-0.2743999660,0.0375481956,-0.0360734574,-0.0225227624,0.7798106074,-0.3104155660,-0.5394257307,-0.3660118282,-1.2562537193,0.1709382087,-1.0761003494,-0.0932355300,-0.1811507940,0.5199954510,-0.5508889556,-1.0994771719,-0.4694336057,0.7088356018,-0.0675911307,1.3022845984,-1.4211859703,1.2567162514,-2.3688504696,0.7742468715,-0.4273701310,0.1674273014,-1.3203834295,-1.8911298513,0.5281402469,1.3740572929,0.3885111809,1.0885382891,-1.7151808739,-0.3717588782,0.0876440331,-0.5725683570,0.0155486111,-1.0659922361,0.4667593837,-0.0940362737,-0.4041534066,-0.1656819880,2.3223657608,-0.7614206076,0.9490546584,-1.4844082594,0.7458498478,-0.0060643018,0.7887188792,-1.1180588007,-1.0001761913,0.7314289808,0.2357216030,0.3824612498,-1.7703744173,-0.2727081478,-0.1264617443,0.6515104175,0.5096127987,0.6367074847,-1.0184148550,1.2223472595,1.3987852335,0.7798677087,0.6547874808,-0.3030628264,0.0454207473,-0.3884822726,0.3867644668,-0.9542946815,-1.8427627087,0.3048293889,1.9156039953,1.2040926218,-0.2316040397,-0.5864921212,-0.2658803463,-0.4716253281,-1.5087419748,-0.0129999518,-1.6092796326,0.7645639181,0.7615116835,1.2913290262,-0.4876889288,-0.4697682858,0.3820580542,0.4084323943,-0.6136229038,0.6022604704,-0.3676231503,-0.7209435105,0.5586885810,-0.5583328605,0.4996970892,-2.0316460133,0.0585249402,-1.0543115139,-1.0559836626,0.3332637548,0.0095748026,1.8420743942,1.0140199661,0.0083231404,-1.5318380594,0.6986145973,0.6373190880,-1.8509548903,0.2487269789,-1.2360033989,-0.3390091062,0.4469988048,-0.1896353811,-0.3229845464,0.4780968726,-1.3126137257,-0.2899254262,-0.1851799935,-0.3376224339,0.4259453416,-0.4082024992,-0.8978323936,-0.6690765023,0.2631308734,0.5530337095,0.1995165348,0.2926838398,0.8894163966,-0.0055672377,0.7018143535,-0.8826447129,0.0749236047,1.2906317711,1.0046035051,1.0409386158,3.0276360512,-0.0133288782,-0.0506551601,-1.8908251524,-0.2714906931,-1.3030624390,-0.2462271601,-1.8104127645,0.1279558837,0.1793313920,-0.7023834586,-1.0055930614,-1.4191739559,-0.4562571943,0.4048222899,1.3166447878,1.1341559887,0.7166735530,0.5539758801,0.4354004264,0.3141281605,0.6505777836,0.2128535211,1.6090195179,0.1628310382,-0.6526899934,1.2286890745,-1.2203204632,0.4666250944,0.7341588736,0.1583673805,0.1684402227,0.1241835728,0.7640827894,1.2957168818,0.7631736398,-0.6601703763,-0.0008463254,0.0685535297,1.1067372561,-0.4385348558,1.7345260382,1.9808120728,-0.6242682338,-0.0815576091,-0.1650884449,0.4348444045,0.5211656094,-1.6433618069,-1.7573856115,-1.4892438650,-0.4256701171,0.2377105355,1.5365910530,0.3241511881,-0.5333830714,0.5189927220,-0.3648990393,-1.9341444969,-0.4795877635,-0.9685363770,0.3621700704,-0.4226962328,1.9258793592,0.5076354742,0.2610789239,-1.2897127867,1.4333382845,-1.6838537455,-0.7709188461,0.8705440760,0.1586957872,0.2956838310,-2.0230813026,1.1002036333,-1.1002752781,-0.5147218108,0.1019927114,-1.0212808847,-0.5737935305,-0.7874208689,0.4350974560,0.1936040074,-1.3571660519,-0.4171037376,-1.6063512564,-0.2483906001,-0.2693999410,-1.5144617558,-0.1226147190,1.5742284060,-0.2891094089,1.2006629705,-0.3703657985,-1.6033035517,-0.4120010436,0.2618357539,0.0800257102,-0.0225607231,1.0052714348,0.2401950359,-0.9681993723,1.6243599653,1.7711733580,-0.4288421571,0.8745658994,-0.7261585593,-0.7740636468,-0.3783999681,1.0468926430,-0.1909528077,2.1233911514,1.6014511585,-1.4648680687,-0.2578746378,0.5449219942,-0.8318146467,0.2432440072,-0.5521076918,0.4936685264,-0.0429933108,-0.7929572463,3.4898121357,0.6794958115,-0.6419728398,-1.2206847668,1.3815455437,-1.5034804344,-1.4729547501,-0.7631402612,1.4460397959,1.1735513210,1.1392821074,-0.3697892427,0.1053928807,0.1785945147,0.1319828779,-1.2402095795,-0.7929094434,0.0239162408,1.2175018787,1.2581635714,-1.1096943617,-0.7467578650,-0.1821890175,1.7982856035,-0.9656202793,0.0464049689,-0.4019823372,0.8537561893,-0.9632617831,-1.3833892345,-0.3336651325,-0.6310629249,-0.6288160682,-0.6705541015,1.1295614243,1.2133406401,-0.1866526157,1.8917940855,-0.2755779922,-0.6542409658,-0.3929320574,-1.2494572401,0.3466140926,-0.5797623396,0.8853974938,-0.2189182490,0.6220045686,-0.3418531418,-0.9100940228,0.8505608439,-0.5887028575,-0.7855650783,-0.3946730494,-0.2303701043,1.3030629158,1.7425899506,0.1629963517,-0.1453389823,-1.2816724777,-0.6563048363,0.0003808588,-0.6638936400,0.8562603593,-0.1051234752,3.0289349556,-1.4466205835,0.1836807728,-0.5522636771,0.5423675179,2.7219474316,0.8910558820,0.6465635896,-0.0759895593,0.1817708462,0.3457686603,0.7239876390,0.7132585645,-0.4586695135,1.0333595276,-0.2189355940,-1.1411225796,-0.8677021861,-0.9688470960,-0.6339297295,-0.0074916431,0.0354148932,2.4297785759,-0.8822140694,-0.9148740768,0.8378556967,-0.1476698518,0.6026245952,-0.0974400416,-0.6325020790,-0.8441191316,0.5103759170,-0.7266747355,-0.7533026934,1.4277828932,-0.7310283780,-0.0555546284,-0.9097919464,0.9007401466,1.1238573790,0.0252667442,-0.7156252265,-0.2277295440,-2.1477272511,1.5932493210,-1.8628616333,-0.3776150644,-0.1090053990,-1.5743252039,0.9123138785,-1.3972257376,-0.0600600950,0.3769355714,-0.4396723211,2.1093904972,0.3233568668,1.2451854944,0.7502902150,0.8297964334,-0.0762333572,-0.0797017440,-1.1705890894,-1.7427301407,-0.5095266700,0.3880380094,-1.5055037737,1.0071586370,0.5120072365,-1.0015641451,0.6942522526,-1.1639013290,-1.5982449055,1.4353106022,1.3250426054,-0.7664409280,-0.2600101531,-0.8542203307,-0.8446595669,-1.4417269230,-1.6894496679,-0.7739345431,-0.4729284644,0.6903986931,0.5380149484,-0.6231607795,0.1010175794,0.6848499775,-0.6755223274,0.3829651773,1.0227255821,0.0714008585,-0.0293932445,1.8250042200,0.2873611152,1.8083481789,0.5629999042,-0.8379108906,0.4814782143,0.9358680248,0.3034250140,0.4835818708,0.6362583637,-1.9723367691,0.1129239202,-0.9730765224,-1.2520319223,-0.6632204652,-0.5693321228,0.0858491659,-1.6128265858,2.4252493382,-1.2824521065,-1.2813147306,2.0825462341,0.9443973303,0.3961180151,-0.6054111719,-2.1568701267,0.8435489535,1.5585157871,0.8996023536,-0.1726988107,-0.2633880973,-0.3633803427,1.7543785572,-0.5090419054,-0.1032537743,0.2715066075,-0.4920640588,-1.5715212822,-0.9911488891,-0.4591449201,0.1021347195,-0.1885639131,-0.1514699608,1.2429906130,-1.2038488388,0.1201531067,0.6239452362,0.8239920735,-0.8424552679,-2.4820933342,0.0825293586,0.7349550724,1.4615254402,-1.8211261034,0.7355304956,0.0824137405,-0.0821021348,2.4546854496,-0.6104809046,-1.4369820356,0.3347872794,0.0953120217,-0.1711449176,-0.2775689960,0.2559177577,-0.6192325950,-0.0518681258,0.7144017816,0.1674056649,-1.9963171482,-1.2033586502,0.1521248519,2.5265574455,-0.6133159995,-0.3060063124,2.1903588772,-0.0703226253,-0.3838198483,-0.9298690557,2.1403698921,-1.1335151196,1.8761792183,-1.1630308628,0.7195526361,-0.9941395521,0.2390076518,-0.5244604349,0.2172025740,-0.3227881193,0.4246652126,-0.7177217007,-0.1237884983,1.0893511772,0.3389956653,0.6737839580,-0.4500505924,1.9005181789,0.3046309054,1.0528272390,0.6181700826,1.2530003786,0.1073710024,0.6634507179,0.6261904240,0.9524511695,-0.3014968634,1.7174031734,-0.7578988671,-0.4663391113,-1.4782775640,-0.2628045380,0.5235355496,2.8543355465,-0.7934467793,0.2137494832,1.1492207050,0.7139776349,0.2760613859,0.4369187057,-1.4526598454,1.1321744919,0.4283018112,0.6453626752,-0.3679089546,0.8216310740,0.2988089919,-0.6367230415,1.3324908018,-0.2185408473,0.4428556859,-0.9793181419,-2.3876283169,0.7414361238,-0.5878328085,-0.1686553657,-1.0306122303,-0.5140874386,-0.6933035254,0.8230751157,-1.2295557261,2.2675883770,-0.0020896329,-1.5306205750,-0.2049885243,-0.6176739335,-1.0552675724,-1.0267729759,0.7805772424,1.4680932760,-0.6374821067,-0.0440820456,0.6838778257,0.1650949717,-0.6097522378,-0.9951433539,-1.1233109236,0.2587343454,-0.6517683268,0.6634348631,-0.1877324134,0.0308681466,0.0288206376,0.5415495634,-0.5201122165,0.4827626944,-0.1858599484,-1.3083807230,0.2003160715,1.1300369501,2.4712626934,-0.2974512577,0.7705679536,0.0965008363,-0.8537307978,1.1313229799,-0.4410588145,-0.3641335070,-0.4061614573,0.2904089391,-0.2795744836,-0.6002675891,0.2109877020,-0.0930366442,-0.0394295789,0.2261722982,0.8024736047,-1.8428796530,-0.6576650143,-0.3111714125,0.8684728742,-0.5444998145,-1.9280499220,-0.1636284292,2.2250468731,-0.1079393625,0.6490951180,-0.6822468638,-0.1159646735,0.9660808444,-1.0916345119,1.2806700468,-0.6005136371,0.4279638827,1.6419439316,-0.7441155314,-0.5071685314,0.2477568686,-0.6498341560,0.8419561386,-0.7465654016,0.8345745802,0.7719214559,0.0275003444,-0.8203216791,0.7621380091,1.8413269520,1.9317811728,0.7190065980,1.2122613192,-0.5506513715,1.2079052925,-0.5110875964,-0.9887308478,-1.4687793255,0.7604703307,0.8583361506,-1.1693745852,0.9667693973,-1.0014497042,0.9113854766,-0.8501291275,0.1033337414,-0.2851611078,0.4838745594,0.0306431390,-0.9261587858,0.5031406879,-0.7204946280,0.0854555964,0.5342746973,-0.2392912656,-0.3483181894,-0.7283043265,-0.1952078938,-0.2268493474,-0.5073602796,0.4071733952,1.7896782160,-0.7856964469,0.1932238191,-0.8698413372,-0.2894476950,-0.4371841550,0.6789008379,-0.5095900297,-1.1314054728,-0.9796065688,-0.9307839274,-0.2411198616,-1.8260837793,-2.1603901386,0.7138137221,0.4682048559,1.8073990345,0.3030933738,-1.5624271631,-0.1223475486,-1.4457436800,-0.1992979646,-0.4670667946,0.5985659361,0.0050599673,1.0435233116,-0.3494057655,-0.1419804990,1.0799071789,-1.1984112263,-1.6463519335,0.9736518264,0.2760215700,0.4218560159,0.2312800139,0.0733595192,1.0696476698,-1.1329557896,-0.2230795324,1.1043237448,0.3311566710,-0.1949632615,0.4872407019,-0.5673235059,0.3815425336,-0.5976793766,0.3133822381,1.1188403368,0.1023709923,-0.7640777826,0.5128422379,-0.9548774958,-0.7417376637,0.8232577443,0.6041470766,-1.5107276440,-0.6352846622,-1.6938943863,-1.4230499268,0.8208574057,-0.1627612412,-0.3808040321,2.1364395618,-0.9052449465,-1.3772284985,-1.6807270050,-0.5424402356,0.9703767300,2.0392134190,0.0691738948,-0.1845367402,1.0785111189,2.0295569897,-1.2068397999,-0.4048538506,0.3063526452,0.0183172151,-0.7925714850,-2.4151265621,-0.5461390615,0.5046216846,-1.1571860313,-1.0568937063,0.0951267779,-0.2945894301,0.6409581900,-0.5636038184,-1.2628661394,-0.5963248610,1.0266063213,-0.1695082039,-0.8970633745,-1.5442864895,-0.6414470077,-0.6634951234,0.0513509884,0.4815643728,1.3058356047,0.4562318921,-1.1240118742,0.8064363599,-0.2292824686,-0.9644187689,-0.8825575113,0.4957913756,0.4160384238,0.7359398603,-1.0344359875,0.6110323668,0.0616292097,-0.8699955344,0.9175645113,0.5920697451,0.2377380133,0.1208677292,0.1229188591,-1.1193079948,-0.5608552098,-1.0286526680,1.4120683670,0.2869732082,-0.7669487000,-0.4248317182,-1.6202235222,1.1397325993,-1.1340955496,1.7128037214,-0.0321023352,2.4242587090,-0.3608433008,-0.3228870332,1.5381108522,-0.1577602327,1.7750029564,-0.7555779815,-0.2008749545,-0.7190867066,-2.0994808674,0.6139115691,-1.2123483419,0.8159266114,-1.8295583725,-3.5421888828,-0.3941495419,-1.0236091614,0.2525290549,0.5810935497,-0.1076203361,0.4633731544,-0.4760022163,-0.0666669309,0.9731261134,-1.4544069767,0.0888629779,1.7643368244,-0.1727118343,0.5579123497,-1.1497603655,-0.3366352916,0.8751723170,-1.4169456959,-0.8309580684,0.3659218550,-0.3941937983,-0.3234885931,-2.1415123940,-0.2322276533,1.7834504843,-0.4405650198,-0.1744079888,-0.4390559494,-0.8015988469,-1.1638343334,-0.5664111972,0.2518135309,-0.6597012281,0.2770966589,-1.0669745207,0.2963372171,-0.0308781285,-0.3477644324,-0.8671655655,-1.2455052137,1.2770495415,0.1706280708,0.1064133495,-0.7048476338,0.6347349286,-0.7335917354,-0.8754142523,1.1479344368,1.5040304661,1.3156964779,-0.5855301023,-0.1134957299,-1.0665155649,0.2300466001,0.9959614873,-1.3386521339,0.4310475886,0.4835477769,-0.5265149474,1.6178389788,-0.0525867380,-0.9931297302,-0.2980194092,-0.8178262711,-0.7970831394,-0.5230959058,-0.2952790558,0.1519235820,-0.5994967222,0.8724045157,1.0875824690,-1.2039092779,1.0752569437,-1.4313342571,-0.0718548223,0.5625308156,-1.0406832695,-0.5584868789,0.6927548647,1.2421534061,0.2440869510,-0.3585351706,0.6971446276,-0.0839696378,0.1699494272,1.3358668089,1.2711428404,-0.5545876026,-1.3880506754,2.2152044773,-0.8038774133,0.5055804849,1.7750318050,-0.0108200340,-0.4221525490,-0.0152974008,-0.7703688145,0.0354482979,0.3172935545,0.6298582554,-0.8587480187,-1.3135603666,-0.5014687181,1.8155835867,-0.6328458190,-0.3373099566,-1.5931397676,-0.2987871766,2.0653538704,-0.3638643920,-0.9729212523,0.7749390006,-0.7497231364,-1.8904943466,0.8607858419,0.1471386701,-1.5295069218,0.5777686834,0.8261218667,-1.0119875669,0.0897994936,-0.4430561960,0.0323836058,0.2219475061,-1.2818908691,-0.2708592713,1.4573109150,0.8804024458,-1.5916829109,1.0492521524,-1.1633678675,0.8123183846,0.4321608245,-0.8351872563,-1.6270632744,0.5444349051,1.7567660809,-1.4698419571,-1.3057603836,0.6106351018,-0.6856634617,-0.0027157622,0.7870089412,-0.1850146800,2.8850343227,1.5643398762,-1.0507323742,0.6868153811,1.1048454046,0.1835930198,0.5201048851,0.7623929977,-1.4696066380,0.0583677441,0.4692377448,-0.2277192771,0.9734441638,-0.0795424357,-0.2654288709,-2.2028191090,-0.2876582742,-0.0065556336,-0.0743332133,0.5298947096,-1.4907051325,-1.0873161554,-2.1639416218,-0.4339273572,0.3658332825,-0.2206286639,-2.2076971531,-0.4790238142,-1.8818588257,0.4069420695,0.2041137069,-0.2685712576,2.1940827370,0.3173443079,-0.5103394389,-0.3893362880,-0.4261973202,1.2880473137,1.3300783634,1.0021003485,-1.7409325838,-0.1299262196,1.4271765947,0.1755771786,-0.1361971200,2.6091077328,-2.1213953495,-1.4876091480,0.4027919471,-0.7992261648,0.8391885757,0.6907860637,0.0751595125,1.9657648802,0.5034283400,-0.5381843448,2.5232529640,-2.2388384342,0.5314210057,2.4042863846,-0.1817212552,0.4993635118,0.2077349424,0.8697637320,0.4360201657,2.3369359970,0.2676490843,1.1903718710,0.8799911141,-1.1188682318,-0.9714317918,-0.9767854810,-1.3006596565,-0.2873510718,1.4437073469,0.9303485155,-0.3495375216,1.2017552853,-0.9662505388,-0.7631691694,1.6332331896,0.8243235946,-0.4884332120,-0.0201347098,-0.7768230438,-0.7631254792,-1.2737504244,0.4627576768,0.1729757488,-0.3228688538,-2.4766850471,-1.1090526581,-0.6864037514,-0.8046090007,-0.7138791084,1.6377116442,0.6567335725,-0.0047580036,-2.2416980267,0.1491056532,-0.0847144574,0.2720263004,-1.6646059752,-1.1872817278,-1.5886445045,-0.2330412865,0.2284714878,-0.9844371080,-0.1336304843,-0.5829446912,-0.2540107667,2.2281854153,-0.5904042721,-0.5926827192,-1.3128408194,0.1390305161,-0.1672947854,-0.7939913869,-0.6221416593,-1.5166251659,-0.1779445559,0.0959212556,-1.6828132868,-0.7401673198,0.5231422782,-0.3322941959,-0.1783479750,0.4485481381,-0.3100477755,0.0970409885,1.1743543148,-1.8261427879,0.4978103042,-0.0108789131,0.5395866036,3.3376805782,0.5630101562,-0.4743687510,-1.9228357077,-0.0009492107,1.3383150101,1.5428452492,-0.2962970436,-0.5699378848,-0.4364693761,0.2970700264,-0.5584040284,-1.9995604753,-0.7018766999,0.7856997252,1.6371961832,-1.1782302856,0.5775887966,1.2874151468,0.6118171215,-0.5430070162,1.0252311230,1.9605115652,1.1515276432,-1.1050601006,-0.3522197604,0.3429833055,1.9247678518,0.1838604361,-0.4415161908,-0.7715782523,0.1724594831,0.7692704201,-0.5029193759,-0.2041465640,0.6117989421,0.2968843579,-0.9996942282,1.7067486048,0.6819940209,-0.6585046053,-0.1444742084,-1.0080267191,1.4498666525,0.3252133429,-0.8631876707,-0.0172087178,-0.9234526753,-0.1951841712,0.8916925788,-0.4279014468,-0.4757214785,1.1231888533,0.5568086505,0.5508191586,-0.1973502934,-1.0614956617,-0.9130429029,-1.2311202288,-0.1490184516,0.6185660958,-1.0488156080,0.4432644546,0.8579077125,0.6526910067,1.9192267656,0.6657885313,-2.7699515820,-0.8622987866,-1.5329411030,0.5477091670,-0.3008966446,0.4089683890,-0.2756463885,0.2297792137,0.7346068621,-1.2895530462,-0.6784411073,-1.2107373476,-0.4332395196,-0.0472933054,-2.2021653652,-0.2635502517,-0.7713882327,0.9504997134,0.5086578131,0.8237007260,0.6284089088,2.4425268173,0.6307875514,2.4813482761,0.1044523641,0.6090664268,1.5078846216,0.6996105909,0.5948370099,0.2660599947,-0.2112916857,1.5669039488,0.9084113836,-0.6771945953,-0.1638096422,-0.4631693959,1.1034935713,-0.1055989787,0.0793656483,0.6271271110,0.7019786835,0.3838609755,-1.0738798380,-0.6967238188,-1.4907166958,1.2653003931,2.0242471695,-0.3331431746,1.3018358946,0.2629842162,0.0544529743,0.5886738896,0.7199140191,-0.2402157187,-0.3608579338,0.7160065770,1.2522007227,-0.8780410290,1.2056716681,-1.2108603716,-0.2572793365,-1.8514751196,-0.1546487361,1.5449539423,-0.2368666679,0.0098899864,-1.0413780212,0.2774117887,-0.2326158434,1.7425477505,0.9690331817,1.6429095268,-0.5832452178,-0.1323042661,-1.0757516623,0.5345213413,-0.3577066958,-1.2440371513,-1.1071386337,1.0463796854,1.0088303089,-0.0133500062,-0.3407829702,-1.4332808256,1.2677539587,-0.6842421889,-1.5895107985,0.1031334102,0.3260625005,-0.8146274686,-0.5703064799,1.5360972881,1.1497735977,-1.0545229912,1.1621849537,-0.0205927342,0.0773499012,1.5707740784,2.3440666199,-0.0833226591,1.2771021128,0.6326636076,0.3524564505,1.0547939539,1.2561269999,0.9254574180,-0.4101853073,0.7814167142,0.5550388098,-1.8132902384,0.5165917873,-1.6028478146,0.1231929883,-0.8797899485,-2.0823435783,0.3851499259,-1.3730741739,0.3431421518,-1.2870882750,-1.0696678162,-1.9551162720,2.1060843468,0.5244371295,-1.8513286114,-1.8891903162,1.6993538141,0.4485278726,0.8354133368,-0.3720458746,-0.5648186207,0.2110529244,-0.4747396111,-0.7716717124,-1.2227087021,-0.3932309449,-1.0957214832,-0.3843332529,-0.4385857284,-0.2289460748,0.1591261774,1.8326412439,0.3320563436,-0.3171687424,1.8090025187,1.0536510944,1.5990201235,0.6480306983,0.9056814909,1.0043029785,-0.2869877517,0.1809553057,0.9514772296,-0.0422179550,0.7730164528,0.5366948843,-1.3359624147,-1.2184035778,0.5566676259,-1.3658822775,-0.4281991422,-1.7386028767,0.4616151452,-1.1900107861,-2.4713108540,-0.4954342842,0.2345984131,-1.8488981724,-2.1743729115,-0.6402022839,0.0303491205,-0.7284300923,1.9178283215,1.6713473797,0.4037494957,0.2346402109,2.0459208488,0.3015230596,0.7130191326,-0.6341357231,1.4106793404,0.2356214225,0.1327618361,-0.2230495960,-0.4091452658,0.2005991936,-0.0833660811,-0.8700286746,2.7954144478,1.7317944765,-0.6571676135,0.6018900871,-0.0520828702,0.3507285714,-0.5154905915,-0.1296486408,-0.5092809200,1.2773561478,1.0116991997,-0.6150847673,-1.4773579836,0.7563268542,0.8471134305,-0.4720822871,0.4313528836,0.0375151336,0.8350439072,0.4294562638,-0.3305866718,0.4861770868,0.6976563931,0.6272200346,-1.6637167931,-0.2475887835,1.0828968287,1.9375406504,0.0171681941,-0.2749762535,-0.7067273855,-1.8384919167,-0.6727235913,0.4818950891,0.8734824061,1.1389626265,-1.3718824387,1.0223542452,0.4262120128,0.2025973946,0.1423050314,1.4298902750,-1.3199853897,0.4568197131,1.5345735550,0.5935459733,-0.4387113154,-0.1879886091,-0.3233093619,0.4590752423,-1.5666143894,-2.3096513748,-0.8251853585,-1.0219471455,-0.0014929610,0.4029170573,1.0825065374,1.4356482029,0.6444023252,-0.1995886266,-0.2893678248,-0.0991581753,-0.1651691198,1.0189162493,-0.1947890669,-1.2835777998,-1.7958240509,1.9413176775,1.4828227758,-0.8889564276,-0.5395320058,-0.5694774985,0.0775188878,-0.7718951106,0.8657597899,-1.5139957666,-1.2930766344,-1.7993720770,-0.2752868831,0.9181541800,-0.7155758739,1.0465465784,1.2638782263,2.2021529675,-0.9961844683,0.0974123031,0.0123674851,-0.2089405060,0.9067828655,1.2267822027,0.3396924734,0.1184439957,2.0369150639,0.3253271878,1.8651583195,1.4540983438,0.5370510817,-0.7455057502,0.2601398528,1.7201685905,-1.7035471201,-0.2939456701,-0.3423474729,0.9926267862,-0.7185393572,1.6899878979,0.0963688120,1.5225541592,1.2421973944,1.1041691303,1.5041767359,0.4050821960,0.5243073106,-0.1115907133,-0.1680535376,-0.0969657302,0.0803446621,1.2012168169,-0.4391567707,1.2089624405,-0.7686284184,0.2084608078,0.5243440270,-1.6587768793,0.4990506470,-0.6774152517,-0.4325406551,0.6804471016,-1.4003276825,-0.1406010389,-0.6582599282,1.6774594784,-0.6680455804,0.2592495978,0.8286221027,-0.5804581642,0.2537096143,0.9645189643,-0.3157314360,0.5982891917,0.8521072268,0.5036994219,0.0840232447,-0.1938900799,0.0138512980,-0.2024308294,-1.0314016342,0.0266645644,-0.6234315038,2.1404976845,-0.3796528280,0.8915473223,-0.7924473882,-0.2630101442,1.2968854904,1.0652110577,0.4945122898,0.4680919051,0.4252710938,0.0305738803,-0.7643531561,1.3036431074,0.1892702878,1.0127239227,-0.4154120982,0.1690457165,0.2398145199,-0.2753032148,-0.0394092537,-0.1768219471,-0.6261203885,-0.4798114896,2.0902595520,2.4536385536,0.2569797635,-1.3700937033,0.2429075092,-0.0302436706,0.0957037061,-0.5650098920,0.4821854830,1.5858329535,-0.3087330759,0.0644669831,-0.0620031543,-0.0495426171,0.6991023421,-0.1768588275,0.2576231658,1.0498266220,1.1218752861,2.0640258789,0.2962799668,-0.5372537971,0.0778273121,-0.6351861358,1.9494534731,-0.7365251184,0.2154163718,-0.8799818158,1.1496148109,0.3462239504,-0.7713207006,2.7176063061,0.6472253799,1.5203940868,0.0201782063,1.1566685438,-0.6539087892,0.2394919395,-1.7418583632,-1.1859192848,1.3754141331,0.5204149485,-0.1954313666,0.4072748423,1.2499068975,-0.2092721015,1.2599943876,0.4698984027,-0.1057309136,0.6285521388,-0.1283890307,0.2182361186,0.5527539253,-0.5691096783,1.1039172411,-0.0255232845,1.2810142040,-0.3833185732,0.1088434681,-0.0079321684,-0.6392134428,-0.3211532533,-0.6840104461,2.2359540462,-0.7377978563,-2.1295697689,-0.8262901306,-0.2741989493,-0.7584269047,0.2667566240,-0.1170935258,1.2125899792,1.3901118040,-0.1025477350,-0.5680760145,0.5732792020,-0.6226810813,1.0726773739,-0.7555589080,1.3011289835,-0.7514100075,-0.3121113777,0.1953123808,-0.7970280051,-0.0469507203,-1.1711391211,-0.5039377809,-0.1742249131,1.7650339603,1.0166648626,-2.3796470165,2.1885800362,0.6374771595,-1.4910366535,0.5055052042,0.2328806818,0.8630269766,-2.2999992371,-1.5238486528,0.5972530246,0.1055067182,-0.5324211717,-0.5370553136,-1.2598272562,1.6097830534,-0.7878819704,-1.7461416721,-2.0719652176,-1.1854764223,0.3427107036,0.5295251608,1.7611126900,0.9704126120,0.5100552440,-0.6306912303,-0.4613394737,0.9809895158,-1.7130533457,-0.7521519661,0.1366459578,0.5631435513,-0.1118881255,-2.4540958405,-0.0765665099,0.7642238140,0.6514412165,-0.2037922889,0.9903054237,0.3785459697,-1.6247358322,1.2173683643,0.2166759223,-0.8612121940,0.4859002531,-1.0364907980,-0.4721792936,-1.6349135637,-1.4085305929,-0.8389165998,1.2321178913,1.3330185413,0.3066735268,0.9116269946,0.6791136265,2.8482429981,-0.4379735291,-2.2370553017,-1.5435577631,-0.1815133095,1.2109670639,0.5453848839,0.4780768752,1.5647675991,2.2001993656,2.1024439335,0.8078509569,-0.3416246474,-0.6584426761,-0.1349043101,0.3547728360,-2.2675919533,-0.2931696475,1.0089668036,-0.6153686643,0.1034570783,0.6448723078,-0.8765313029,0.4534460008,-0.3699859381,1.2004622221,-0.0722925514,-0.0325831361,0.9020727873,-0.7152183652,-0.8456809521,1.1576007605,0.6171180010,-0.0472845919,-0.9105609059,0.1960259825,-0.2576677501,-1.9657860994,0.9828581214,-0.9305165410,0.8664217591,1.2800661325,-1.1278365850,1.8148369789,0.2521477938,0.8906397820,1.5773588419,0.4439918995,0.0060209022,0.8361096978,0.4923763573,-1.1642525196,0.7681359649,0.2648225427,-1.1226508617,-0.2650801241,-1.6352653503,-1.3773202896,0.6504764557,-0.9845471978,0.5976469517,-0.0603680871,0.3551152945,0.9604079723,1.4429877996,-0.9509329796,0.4106124043,-0.8905282617,1.4084507227,-1.2862893343,1.1871342659,-0.2408435643,0.7524929643,0.9669978023,-0.0317020342,0.1478836387,0.4667394161,-1.1262389421,0.4174720943,-0.4278752208,0.0893254876,0.3123355210,-0.6510843039,3.6935560703,0.3481149971,0.9524300694,1.2629102468,0.9691338539,0.8425455093,0.4645085037,0.8258065581,-0.2780044377,1.0713196993,-0.7075175047,-0.1032134444,0.5142312646,0.5319851041,-0.0098116705,-0.1779374182,-0.2449193746,0.8509523869,-0.6144673228,-0.4817785025,-1.2756514549,-0.6126600504,-1.1293950081,-0.1908688098,1.0651584864,0.3274653852,-0.8781397343,-1.2023971081,0.5885425806,0.7167418599,0.0696014911,1.5573089123,-0.5623143911,0.3726352453,-1.0666670799,0.7341268659,-0.7441030145,-0.5995749831,0.4551900327,-0.1493398994,-0.0821552277,0.1749963611,-0.5736764073,0.6820808053,0.1590649784,1.7094728947,-1.2093794346,0.1417449266,0.0874756873,0.0445520170,0.1454997957,0.6226649880,-0.7579197288,-0.8653601408,-0.8565465808,0.0884546340,-1.1490837336,1.2844370604,1.7234747410,1.4080694914,-0.3957767785,-2.0336396694,4.2858557701,0.1105877906,-1.0418227911,1.2223359346,-1.1886203289,0.1480172127,-2.7951111794,-0.5097351670,-1.1575583220,0.9877367616,0.2623551488,1.2971171141,-0.9021095634,-0.7333549261,0.3958832324,0.0376789942,-1.4897017479,0.7928319573,0.3467888832,-0.2384968996,0.5339655876,1.0606970787,0.6961131096,0.5275928378,-1.0800560713,-0.6828938127,0.7291389704,0.4540881515,-0.9229554534,-0.2239529192,-0.8285161257,-0.7912678123,-0.0725147203,-0.1320558935,1.2266693115,-0.1467476189,-0.5098367929,0.1437175274,0.0615985021,1.1454741955,-1.6718358994,0.2883616388,-1.0447431803,1.8523039818,0.0715519041,1.2537438869,-2.2294402122,-0.9726954103,-0.8541699648,-1.2510904074,-0.2680608928,-0.0982486233,-2.7065048218,0.4315496087,0.4952709377,2.3173794746,1.7902907133,1.0368921757,-0.4934299886,-0.6587244868,0.2156995833,-0.7816968560,0.1607544422,-1.4151940346,-0.4447843432,1.6773577929,0.3867525756,1.1128669977,1.8861371279,0.9591953158,2.4224495888,0.8388727307,-0.8159924150,1.5163911581,0.6435745358,0.4092240930,1.7183226347,-0.0800361559,-1.0487719774,-0.2141771913,1.0178449154,0.7592806816,0.5728220344,0.6055765152,-0.8523482084,-0.8808542490,-0.4607036412,0.7181840539,0.5790495276,-0.3860639036,-0.6235859394,-0.3401636779,-1.3322459459,-0.3735280037,-0.9619418383,0.9170179963,-0.0155261103,-0.7936813235,0.2904969156,-0.2934159935,1.5998722315,0.2245161682,-0.6810392141,-0.7174949050,-0.0229964331,-0.6433348060,0.8996737599,-0.1399249732,-0.9068041444,1.2186594009,-0.4671718776,-0.0194043443,-0.5684084296,-0.8678084612,0.5519516468,-0.9348483086,0.4797087014,-1.7733447552,0.5873536468,-2.0052974224,-2.0336976051,-0.2158455700,-0.2398948669,-1.9766912460,-1.7725622654,0.7912243605,0.6274369359,0.0156383421,-0.4388458133,-0.2509407997,-0.7350332141,0.0592636503,-0.2649568617,-1.1821020842,0.1051000580,-0.4178300500,-3.0862278938,2.1433157921,1.8003720045,-1.3339478970,-0.4993157387,-0.0595764108,-0.0815746859,-1.8172090054,0.9544544816,0.0266386792,-0.7247435451,0.4710936844,-0.0355378725,0.5382333994,-0.2017002255,-0.2736326456,-1.0850501060,0.4361391664,0.7275456190,-1.5133862495,-1.0869604349,-0.4892189503,-0.2241794765,-0.7801714540,-1.8050248623,0.4219087958,0.0985516831,0.7518414855,0.0099756178,-1.3204857111,-0.7362210155,-1.3625191450,1.4659570456,1.5852022171,0.9222944379,-0.6225005388,-0.4121412635,-0.1012708023,1.0839953423,-0.1868243515,1.3171703815,0.7383409142,0.7114495635,-1.3378200531,0.4559955299,-1.0297137499,-1.0663639307,1.8599836826,0.2518027425,0.3776589930,1.6198328733,-0.1385766864,0.0779930502,-0.9513822794,1.6096773148,-1.1503460407,0.2158631533,0.9789539576,-1.6471439600,0.3016359508,1.4386115074,0.7306500077,-1.8357973099,0.6295026541,-0.4132591188,-1.5983790159,-0.0675861537,-1.8248832226,0.5449636579,0.6511113644,1.1925294399,1.4464730024,-0.6434930563,2.7133228779,0.9117081761,-0.4531750381,-1.2206915617,-0.3705402911,1.2997782230,-0.8172878623,1.0327092409,-1.2872046232,0.3879989088,-0.3668969572,1.4443743229,0.0700865909,0.1676746309,1.4242259264,-0.8452426195,-0.4409632683,-1.3721363544,0.9033271670,1.2147731781,-0.7221063972,0.3519815505,-1.0255091190,0.2319916338,1.2535445690,0.1925023496,-1.2753477097,-1.1186707020,0.8844894767,0.0683436990,-1.2587802410,0.2794378698,0.8379051685,0.2669829130,0.3449877799,2.3400497437,1.0804201365,1.4391826391,0.7339784503,-0.8790752292,0.0026909518,-0.8914278746,0.4804829061,1.4641373158,0.6813607216,0.8553986549,1.7090407610,-0.5028632283,1.4325996637,0.2645716369,1.0826915503,-0.0516118817,-0.3066533506,1.0699689388,0.1768194139,-1.2282488346,0.2069570571,1.3318647146,-0.9424896240,-1.0964196920,-0.4572708905,0.4500499368,0.1980328262,-1.9181954861,-0.0174330324,0.0999595150,0.0267650168,-0.5508563519,1.4106292725,-0.2244167775,0.6556907296,-0.0054974109,-0.5443715453,-0.1919281334,0.3812180161,-0.4736113846,0.6195918322,0.7323521972,0.9373790622,-2.6295375824,0.3766013682,0.5224608183,-0.8840683699,-0.7412922978,-0.5194513202,-1.3004968166,-0.0051153982,-0.7945897579,-0.1301139295,-0.0011560072,-1.0379506350,-0.6288818121,-0.0096841361,-0.2014763355,0.6976454854,0.1354101002,1.5714323521,1.0308767557,-1.3190690279,0.8940302134,-0.5858420730,2.8178141117,-2.2886848450,-0.1681453437,0.5785136223,-0.8217912912,0.3408507407,-0.6147227287,-1.1310694218,0.9431957006,-0.6122029424,-0.6093533635,-0.2190532982,0.2843426764,0.6691458821,-0.8678124547,1.5971509218,-0.1540083289,-2.2375392914,-0.5721747875,-0.3298413455,-1.0728195906,0.5367963910,2.1423006058,1.4925087690,-0.1332240850,0.7596751451,-0.9900237322,1.6975897551,-1.1039967537,-0.2365738451,-0.8477472663,0.5158218741,0.9538124800,-0.1393971145,0.2098560929,1.4214780331,-0.6133620739,-0.3443203270,0.7987253070,0.2965416312,-0.6252503395,0.0912849978,0.3837498128,-1.9019155502,-0.9714212418,0.8765338659,0.2010715902,-0.3521747291,1.3726044893,-0.2925174534,-0.6309738755,-0.1950662732,-0.5796111822,0.2951392829,0.3845759332,-0.1556660980,-0.2773683071,0.2328125387,0.7338165045,-0.1784263700,0.1823998541,0.7299521565,0.1716358215,-0.0308698844,0.2138171941,0.3089756966,0.7322928309,-1.0055240393,-0.4655968249,1.4510535002,0.8053041101,0.8307817578,0.5806190372,1.4012625217,0.4137353301,2.2663216591,0.9053751230,0.2676714361,-0.2638470531,-1.1524258852,-0.2055503577,2.0920567513,-0.0389869474,-0.5045543909,-0.1704713106,1.7036591768,2.3972051144,-0.3624917269,-0.0865611285,1.2785141468,0.6021286249,0.2753924131,-1.7304373980,-0.9938117862,0.2796024084,-0.3657841682,-0.0245826654,1.2244658470,0.2047881931,-0.3773700595,0.8032777905,-1.9749366045,-0.1891875565,-0.0975503027,-0.0583613701,0.5487793684,0.3212392628,0.7469420433,0.4802857339,-0.0953975916,-0.0016161953,0.4400027096,-0.3889231980,-0.2829461396,-1.2563219070,0.6948705316,-0.8324922323,-0.4046234488,-1.0711333752,1.3630745411,-0.4418192506,-1.3101440668,0.5938716531,1.8128287792,-1.2612177134,1.0351736546,-1.6114523411,1.9638142586,-1.2056689262,0.3683494329,-0.4289750457,0.5871503949,-0.4308027625,-0.4693752527,0.4237685800,1.0735077858,-0.4528256953,-0.4611294568,-0.4493314326,0.2348384559,1.4725769758,0.8286721110,-0.8574910164,1.1002789736,0.2178244442,-0.0682177767,-1.1096816063,-0.8833054900,1.1900689602,0.8638876677,-0.7919912934,-1.1155849695,-0.0368701331,-0.8000605702,0.0575532131,-0.6001101732,1.7475066185,-0.1024022102,0.7054311037,0.8884329200,1.4535988569,0.8446703553,0.6319045424,2.1480684280,-0.3688235581,0.6120865345,0.6029073000,-0.9015443325,1.8531484604,2.4086322784,0.5047215819,-0.4523896277,0.0560955927,0.0015819527,0.7949462533,-0.4127202928,-1.2027662992,-0.4916600585,0.9999223351,-0.6061544418,-1.1319777966,1.1700640917,0.6804245114,1.5015945435,2.0653812885,0.0969319269,0.2641748488,-0.0362505354,0.6237525344,-0.8102051616,-1.5553128719,0.2032443285,0.2953858972,0.5768323541,0.1966675222,0.9187663794,-0.9852730632,-1.7754678726,0.5656357408,1.5518661737,0.1246112362,0.7218389511,1.1248434782,0.7300990820,-1.7761151791,0.4202294946,-0.6030195355,0.4817877710,-0.3983127773,-1.2921808958,-0.7133482099,-0.0695136040,0.0268135220,-1.8523842096,0.3018036783,0.5316495299,-0.1636061519,0.3650557697,-0.2680281103,0.0313414261,-0.6150335670,-2.5063366890,0.8658521771,-0.8896884918,-1.4359755516,0.7071300149,-0.8117466569,-0.8193208575,-1.6796098948,0.2288485318,1.1684442759,1.3867622614,0.3720430732,-2.2209444046,1.0519523621,-0.3739921451,1.1328148842,0.4190898538,0.5840306878,0.3622587621,1.3552360535,-0.6779456139,-0.4645721912,0.7942563891,2.9545433521,0.1648689657,0.2273791283,0.8398232460,0.1645840257,1.2705302238,1.9689812660,0.5604508519,0.2973692119,-0.3421580791,-0.7549017072,-0.9641358852,-0.0671323538,-0.2883839011,0.9323253036,-0.4751592577,0.2069311291,-0.9538527727,-1.8852221966,-0.1730320305,0.0738568977,0.7191287875,-0.1032047048,-0.5027757883,-0.6713217497,1.1065231562,-0.4910871089,0.3194410801,-0.3272990882,-0.5864269733,-1.6019154787,-1.2150155306,-0.4830319285,-2.2106018066,0.5272894502,1.1339933872,-1.6582157612,0.1045286432,0.9769923687,0.6356340647,-0.0837953761,0.8529375196,-1.1835395098,-0.0311263781,0.1229125187,0.1845661104,1.4570873976,-1.0240747929,0.2515321076,-1.5033500195,0.1378750950,-1.1685484648,-0.4524605870,1.0256450176,-1.7534796000,-0.7314636707,-0.9282721281,-0.0200786255,0.3444993198,1.2372258902,0.2347012162,0.0017177498,0.7588968277,-0.8208673596,-2.9165871143,-0.5337390900,1.1897857189,-0.4590893388,1.1943334341,0.6033994555,-0.9690102935,-0.4756906927,-0.5146775246,-0.6181944609,-0.4739496410,-0.8306716084,0.7850691080,1.0141893625,-0.1255545616,3.0548119545,-0.5503615737,0.7137859464,-1.8925294876,-1.6286408901,0.1578745246,0.2897020578,1.1416177750,1.6445769072,0.0266005080,-0.6002950668,1.8851222992,0.5006518960,0.8041281700,-0.4171819687,0.9126561284,-0.9665496349,-3.0324594975,0.1772412509,-0.7743625641,-0.7814670205,0.5761278868,0.1479105800,-0.3336394429,0.4467318654,-1.1148625612,-0.7398648262,-0.1982903183,0.2771024704,0.0037587737,-0.7214294672,-0.7772885561,0.3695692420,-0.8413255215,0.4420565069,-0.3661336303,0.2388688028,0.7574204803,1.8069114685,-0.3563021123,-0.6996699572,0.4083276093,0.9007179141,0.9037804604,-0.1237754449,1.1282645464,-0.3496119678,0.7314071059,1.5345368385,-0.2547729909,-0.8683311343,1.1891893148,1.1465867758,1.3951969147,-0.3881577253,0.5991099477,1.2029726505,1.2379013300,0.1110376492,-0.5402413607,-0.4763735831,-0.6523308754,-0.4530446529,-1.2403632402,-0.4820930958,1.9094609022,-0.8305430412,-0.5602543354,-0.3380995393,1.2139499187,-0.6730381250,1.8736811876,0.5619761348,1.2849764824,-0.7612153888,0.6084617972,0.5260947943,-0.3612978756,-0.0199031364,-0.0179262515,2.7262132168,0.1001558080,0.0873316899,0.4253403842,-0.2572331727,0.3998314738,0.5780014396,0.5289971232,1.1858935356,1.5703359842,0.6258378029,-1.3216575384,-0.3723444939,-0.7417381406,1.0053710938,0.2518371046,-2.2449259758,0.7364364266,-0.7436603308,0.2557405531,-2.1114578247,1.4893753529,-0.1315749884,0.0937679037,0.3575634956,1.3543114662,-0.5280987620,0.0921488330,1.1167320013,-0.1133646667,1.3830109835,-0.3453722000,-0.0628339872,-0.6401051283,-0.6774563193,0.0201832801,-1.3557044268,-1.7727380991,-1.3186904192,-0.8905112147,0.6380245686,-1.9156514406,-0.6751238108,-2.3304250240,-0.0731968582,2.6341967583,-0.1446866840,0.9468255043,0.1266835779,0.5929878354,0.2527090013,-0.7906475663,-0.1088170782,-0.0180691257,1.7883660793,-0.7638135552,-0.3626271486,0.7353001237,-1.9343894720,0.9877597690,-1.2362815142,0.3096195161,-1.3171862364,-1.2322047949,1.4253273010,0.0599365123,0.4724906981,2.3247697353,0.3512053192,0.4358356893,-0.2270360738,-2.0736320019,2.1042101383,0.6262249351,2.0178065300,-0.4194451571,0.1140522435,1.6493346691,0.5421503186,0.4119198918,1.8837475777,-0.1114307493,-0.4739866257,-0.1118430570,0.3266671002,1.0846471786,-0.7667149305,-0.3911579847,0.7709604502,0.9599793553,-0.6258073449,0.4235780239,0.2291588485,-0.5419658422,-1.3261935711,1.4792988300,-0.5172199011,-1.8417431116,-0.9530127645,-0.5386762023,0.5477579832,-1.3143244982,1.2823202610,-0.8449356556,1.7781059742,0.2892118096,-0.6741756797,-0.2984076440,0.3891500831,0.0456696413,-0.7156158090,0.1342495084,-1.8112068176,0.9137851596,0.0664710850,-1.2650182247,0.2943314910,0.2052179128,-0.0621892735,1.0672193766,0.6473845840,0.4740798473,-2.3851220608,0.1769553572,-0.8922551274,0.3362334967,0.9756082892,1.1115776300,-1.6051492691,0.3320700526,-0.5360628963,-0.4085548818,-0.1155323014,-0.9104030132,-1.3911604881,-0.6406959891,-0.7174149752,0.2314108014,0.9844489694,-0.7310201526,-0.7337293625,0.1070518643,0.1595049948,-0.2646666467,-0.6786507368,-0.1914107949,1.4713796377,-0.9440070391,1.6280828714,-0.9151198268,-0.3460160792,0.0264972281,1.2194769382,0.9777076244,-0.9459745288,0.2136550546,-1.1340179443,0.6967772245,-1.0132279396,-1.6084231138,-1.2107805014,-0.7951170802,-0.9152131081,-1.5939664841,0.2302491367,-1.0035600662,0.5383255482,0.3087547123,0.0042029740,0.5027353168,0.4750975668,0.0975661203,1.3311247826,-0.4950006306,-2.6560649872,-0.9025616050,0.8317630887,-2.5742125511,-1.1284319162,-0.0401342697,-1.3941005468,-1.0090293884,-1.0960578918,1.2098025084,1.3029168844,0.0013557881,-0.2298772782,-0.7874842286,1.1899797916,-1.7895762920,0.6294350624,0.2206836939,0.1826732308,-1.4839683771,-0.6505553722,0.6233601570,-0.8338543177,0.2824832499,0.3885993659,1.0900565386,1.8766107559,0.8075032830,0.1507251561,0.8691424131,0.3986098170,0.5120561123,-0.0635230392,1.1407741308,0.9157882333,0.4682558179,-0.5680037141,-1.6270081997,-0.6732350588,0.9897184372,-0.1337077469,-0.4015781581,-0.5095635653,0.4383413196,0.1368908882,2.3518426418,0.2311750799,0.4614313841,-0.6706026793,-0.9506882429,0.6988849044,1.1486055851,-1.3775639534,-0.1598063409,0.2637604177,-0.1926568598,0.8263894916,-1.2977201939,-0.8600575328,-0.6402958632,1.6776019335,-1.9129065275,1.3457714319,-1.0432997942,0.3238283992,-0.1716978103,1.4572438002,-1.0432966948,-1.5072041750,0.0903891772,-1.2257448435,-0.6195468903,-0.8568475842,0.2043592334,0.2641375661,-0.8464022279,0.2488178313,1.0052314997,0.4492959678,-0.0295740031,0.2290060669,-0.1275434643,0.3373597860,0.1626713276,-0.6524628401,0.7707580924,0.3476366401,-0.0531140119,-0.0087814219,1.6692032814,1.6984108686,-0.1209266335,-0.8074813485,-0.1444534808,0.6372165084,-1.3039739132,-1.8125053644,-0.1793181598,0.4690181315,-2.4916374683,-1.8491213322,-0.5576793551,1.3404135704,1.0666805506,-1.5593063831,-0.9231505394,0.9490910769,0.4438292682,0.2828915715,-0.1954534054,0.0018107980,-0.1907095164,-0.1145968288,1.9409518242,1.0856090784,-0.9538422227,-0.8621790409,-0.4659977257,-1.7791017294,-0.5010645986,-0.6775425076,0.7356759906,-1.7972897291,1.5602645874,1.2374145985,-0.0871757418,-0.6793118119,0.3375435770,0.8931931853,-0.2421072423,0.8488683701,-1.2290204763,-0.2693973780,-0.1366267353,0.0585083216,-1.7161861658,-0.5805538893,-0.9939773679,-0.2650007010,0.4637797177,0.7559719682,-0.7087855339,0.1012896299,1.1064854860,0.6333464980,0.2938173711,0.2699801624,1.7075775862,0.9169011712,1.4294006824,0.3349779844,-0.6877442598,1.5435626507,0.8220308423,-0.4070742130,0.7013475299,0.1943705380,0.0186969098,-2.3783740997,-0.3056056201,0.2207050323,0.9657750726,1.0608078241,-1.1249374151,-1.8694682121,0.7967307568,-0.1668088734,0.8929074407,0.5497352481,-2.2809424400,-0.0579407215,-1.5476003885,0.8956011534,2.7000272274,-0.2422973365,-0.0058167744,-2.7817559242,-0.8345428705,0.5110921264,0.2318991423,-0.2348987013,-1.1566245556,-0.9918349981,-1.8085412979,-0.5614330173,-0.5285215378,1.1941301823,1.4853051901,0.3416150510,1.3896061182,0.8218294978,1.3636242151,0.2253000736,-0.5104549527,0.3647124767,-1.9561990499,-0.8729413152,0.0701007172,-0.2375694811,-1.7378988266,-1.0403276682,-0.8218318820,0.3926897645,0.1339692175,0.1656624079,-0.2436903417,-0.5954623818,0.1061979011,-0.4252826273,-2.0241460800,0.2748028040,-0.0702078119,0.3288494349,1.0060845613,0.4409485757,-0.6922742724,0.2370910496,-0.5651920438,1.8939553499,1.2779444456,0.7899533510,-1.6924171448,0.9689711332,1.3714234829,-0.1442247182,0.5031644702,-0.2282197922,0.1537615359,1.8720436096,2.1535537243,0.0067972033,0.1998646408,0.2613457739,-0.1279868037,-0.2985032201,-0.3642401695,-1.3701349497,0.7696627378,-0.5171828866,0.0796941370,1.0161266327,-0.1516731530,-1.4251996279,1.0709221363,0.9388007522,1.3731763363,-0.5839059949,-0.2922695279,-1.2067660093,-1.0474648476,0.0075881016,-0.0970899835,0.7804442644,0.2210815251,0.0727487653,-1.4848616123,0.4621598125,1.5490251780,2.5317053795,-0.0357220359,0.1732001901,1.8565897942,-1.5049402714,0.9150194526,-1.2461922169,-0.6568403840,0.8576791883,-0.1446761936,-1.4876954556,0.0227297749,0.6311181784,1.8708921671,0.5190147161,0.9861489534,1.2462815046,0.1173469424,0.9257962704,-0.9750080109,-1.2085790634,-0.4388735890,-0.3076315522,-0.0882748291,-0.7719042897,1.8123188019,1.5279533863,-0.8639286757,0.7459006906,0.2987340391,-1.1948617697,-0.3614636660,0.7074557543,1.8297299147,0.5339940786,0.8260959983,1.7657806873,1.2677180767,0.1828723848,0.0288342815,0.8607107401,-1.5287158489,-0.1524372548,-0.6711853147,-0.3347103596,0.0846325532,2.3551928997,1.0067535639,0.3421706259,-0.5376572013,-0.1644151658,-1.3603549004,0.2899155319,0.6658204794,0.7675340176,0.6614913344,-0.0999178067,-0.6015158296,-0.2123781145,-1.5590256453,-0.3314684033,-0.3496010900,0.0747257844,-0.3252461553,-0.8702195883,1.9684408903,0.8418162465,-0.3862409592,-0.8120633960,0.7752045393,-0.3333698511,0.5466673374,-0.1422412992,0.7192386985,0.4905242622,-0.1880952865,0.2143013477,1.3246078491,-1.2478592396,2.0077860355,0.5948082209,-0.2080378234,-1.5965000391,-0.2735635638,1.3294361830,-0.7973580956,1.4204609394,-1.1398384571,-0.0142109981,-1.5199676752,1.1904004812,0.3158183992,-3.0604200363,0.1238618642,0.9671947360,-0.2805726528,-2.0813367367,-0.3729003072,-0.1396138072,-0.5271163583,0.1263424456,-0.4353207052,-0.2924160659,-1.1753132343,-0.1308605820,1.1438410282,0.1119249091,0.3604819775,-1.0717647076,-0.2294389606,0.1563594043,-0.6368703842,-1.2792086601,0.0777032673,0.0775017738,1.3998067379,-0.6097219586,0.4177627861,0.4011989236,-0.5329536796,2.3956975937,0.1811924279,-0.8800264001,-0.4670289159,-0.3687879145,-2.8602409363,-0.6590387821,-0.2655385137,-0.3368494809,-1.9276156425,-1.5855481625,1.0563932657,-1.3409841061,0.3984279335,-0.2940606773,-0.5712441206,-0.0067037856,-0.6415054798,-0.4785518944,-0.1218238324,0.2206111699,-0.4235476553,-1.3250722885,1.7152470350,-1.3964438438,0.2865219414,-0.4178703427,-0.6859941483,1.0773335695,-0.4156297147,-2.6461470127,0.4012067020,1.0373991728,-1.4278997183,-0.2466971874,0.0849356949,-0.8817490339,0.5450678468,0.1807463765,-1.0566569567,0.1781830043,-0.0064033647,0.3077405691,0.6102537513,0.0652264729,0.2542940974,-0.2305352241,-1.6249768734,1.2014248371,-0.2054571807,1.1181812286,1.1214034557,1.1425615549,-1.2870421410,-0.1241030917,0.5297012925,-0.0382554494,0.3882488012,-0.6190707684,-1.5623250008,0.7568140626,-1.6866751909,0.0804848298,-1.4858338833,0.2297888249,1.4524667263,-0.5968704820,-0.0833020732,-0.2826476097,1.5136855841,1.4851976633,-1.1327924728,-0.8760012984,-0.6094191670,-1.4564394951,-0.7331520319,-0.9318554997,-0.8895848989,0.8252238035,0.1218120083,0.0662026778,0.6619882584,2.0303890705,1.0554903746,0.7169943452,0.1783896387,-1.1470445395,-0.3398191333,1.3697793484,-0.0253568981,1.1636499166,-1.2545666695,-0.1280414611,0.6935864687,0.1563157439,-0.1740721315,1.1867508888,-0.0169510152,-0.0078435130,0.7718135118,0.1622573286,0.2028463036,1.2996282578,1.9638586044,-0.8999834657,1.1722446680,0.4890742600,1.1593204737,1.3701916933,-0.2957761586,0.7029923201,-0.2342174649,0.3841736317,1.0627040863,1.0547840595,-0.3150112927,1.1945139170,0.4034687877,-0.5125347376,1.0919033289,0.4950831234,-0.5558901429,0.3558287621,-1.0803325176,1.0500856638,-0.6788198948,0.5517796278,0.7566818595,0.5830651522,0.6025416851,1.1403605938,1.9247280359,0.5235610604,0.4997765124,0.7582163215,-1.1293796301,-0.3010092080,-0.9889057875,0.6745214462,-0.8895672560,1.0809191465,0.8366023302,0.4471575320,0.6851827502,2.1633660793,1.8103870153,-0.3494542837,1.1950857639,-0.3678962290,1.7989248037,-0.7417379022,0.5473921895,1.0161283016,-0.3572591841,-1.0351872444,2.6292521954,-0.4950847328,1.0285687447,0.0339635722,-1.6448830366,-0.5516107082,0.0174649954,0.4552769065,-0.1754626930,0.1529568881,-1.2097570896,-0.8168189526,2.3861827850,0.6213911772,-0.8158392310,0.5483052135,0.0878597200,-1.0948483944,0.2889161110,0.3388940394,-1.2642379999,-1.5323306322,-1.0071874857,1.0103991032,-2.4863183498,-1.1070255041,-1.3683352470,-0.4224180877,0.7639471889,-0.5177192688,-1.0074887276,0.1551092863,1.3369476795,0.5466856360,0.3232005239,-1.6532018185,-0.7173513174,-1.0652648211,-1.3265746832,-0.5660467744,-1.3132909536,-0.8130620122,-0.1815343946,1.2690964937,1.1019312143,0.9516880512,1.7226719856,0.4446351230,0.5170425773,1.0413635969,0.4556803405,0.1972223371,1.8935484886,-0.2192615122,-1.4354544878,1.5602838993,-0.6460107565,0.8395658135,0.8136681914,-1.7072492838,-0.7649660110,-0.2882774472,0.8429179788,-0.2447516322,0.9172566533,-0.2275722325,0.2997744977,-1.0302278996,-0.1052929237,0.3555447757,-0.0440536961,0.2784536779,-0.5446269512,-0.7629913092,0.0162314177,0.5546040535,0.9613997936,0.0616658404,-0.2609883249,1.0197192430,-0.6264053583,-0.5688632131,1.5122493505,-0.3373487294,-1.6997095346,0.5993637443,-0.9272513390,0.0842745379,0.8615155816,0.4361516237,0.0753251612,0.2608761787,-0.9517005086,0.9069390893,-1.0981204510,-0.8780823946,0.7374699712,-2.0681431293,1.6813424826,-1.0838361979,-1.1617941856,-0.2509556115,-0.5042505264,-1.1139525175,-0.2048496157,0.1186023057,-0.3202336729,-1.1404109001,0.2558881640,-1.7212871313,-1.0247824192,-1.7450982332,0.6630205512,-3.1837379932,0.4456369877,-1.1326383352,-2.2103080750,0.1183590889,0.6692360640,1.2288067341,-1.9078927040,-1.5564306974,-2.0014181137,1.4565919638,-0.3936092556,0.1973627359,-0.0117214527,0.2743053138,2.0025804043,0.1375686824,0.4163160026,-1.0364779234,1.3307567835,-1.9111024141,-1.5484838486,-0.1650904715,0.8083508611,1.1169708967,-0.3402090073,0.9838241339,-0.1346430779,1.8263845444,-1.7422721386,1.0641328096,-0.4452352822,-0.0513705388,0.4752159119,1.6146486998,0.5102171898,-0.8978606462,-0.8856185079,-1.4149117470,-1.1215506792,-0.7647787929,0.2960679531,-1.1323281527,0.6728130579,0.2450481653,-1.2277650833,0.2975145876,-2.0824947357,1.9949676991,0.1659021229,1.0105559826,0.2631520331,-1.9276918173,-2.7682528496,0.4685620964,0.2694377601,0.2202383578,-0.0813253671,-0.9782060385,-0.6891325712,0.8377320766,0.0159451328,1.3094940186,0.4035644233,1.0255818367,0.5153917670,-0.1808453053,0.1277346462,-0.0179174189,-0.9238844514,-0.5562965870,-0.3335781991,-0.1112420335,1.0880632401,-0.9739040136,-0.6805738807,-1.2655941248,-1.1422700882,0.3249793351,-0.0527833514,-1.7724030018,-2.8175151348,0.8032355309,2.1276588440,2.1617305279,-0.0527869426,-1.0185065269,-0.4677870572,0.2683751881,0.0304780379,-0.1207695752,0.0642614439,-1.6406875849,1.1186835766,1.4654172659,0.7769879103,-0.5351511240,0.3237947226,0.2958904505,-0.1936709285,1.3598756790,1.1916985512,2.2793455124,-0.0956685990,-1.3434432745,-0.1309389323,0.2118412554,-0.6874347329,-0.8510482907,0.0485115610,2.1660628319,1.8733015060,-0.4796108902,0.7988507748,-2.6731781960,-0.4153742194,-0.1474187672,0.9681109190,-0.4934926331,-2.7047929764,-0.3549762070,-1.0457595587,-0.5838010311,0.0829716697,0.0265663285,-0.9133974910,-0.0864409208,0.2548206151,-1.3221129179,-0.9357287288,1.3260126114,-1.9737194777,1.4048113823,0.4354310632,2.7296981812,0.4620052874,0.1094514206,-0.8226955533,-0.8031890988,0.0278037265,-0.7649024725,-1.1145186424,-0.0622494183,-0.4565858245,1.1405748129,-1.0133868456,-0.5143136382,0.6725979447,-0.0492859147,1.0113819838,1.1048659086,0.6603216529,-0.3727340400,0.7112011313,0.7985103130,-0.2034807801,-0.3387661576,-2.1463022232,-1.1241475344,0.7797137499,-0.2611505687,0.9198236465,0.8049122691,0.3930318952,1.0530589819,-0.3481652737,1.6241984367,-0.2310409844,0.8785673976,-0.5285487175,-1.6051872969,-2.2492547035,-0.2764416635,-0.5564856529,-0.1424106061,-1.6674304008,-1.1508232355,-1.1337341070,0.2225996703,0.9500737190,-0.8307194710,0.2994698584,0.6526410580,0.3251613379,0.0689228550,1.1470413208,-1.4659957886,-0.0308823474,-1.1581293344,1.3566701412,0.0564573184,-1.8906033039,-0.9888930917,0.8690288067,-0.5142025948,-0.6776256561,1.2080899477,0.0295389090,0.5598149300,-0.4604727030,-1.0156501532,2.0301139355,-0.8149390817,0.4358777702,-2.2680025101,0.7438141108,1.9459930658,-0.1377315372,-0.0557070971,0.6126846671,0.4535076916,1.3437209129,-0.4962809682,0.7099696994,0.7285888195,0.5127623081,0.1487104893,-0.4102285206,0.1795057654,1.2648516893,0.8477721214,-1.3445240259,1.1553347111,1.1411762238,-0.1662096381,0.9143199921,-0.0289703812,1.4069156647,0.3577559888,-2.8750307560,0.5885147452,2.0400743484,0.7269452214,-2.0255157948,-0.7129239440,-1.8075281382,-0.0634173900,-1.1268689632,-2.0150179863,0.8664655685,-0.5846761465,-0.7784549594,1.7345633507,-2.3513545990,-1.0365632772,0.8950498104,-0.2481182218,-1.4468442202,0.0471748933,0.3714194298,-1.3437989950,0.1846590042,0.1699056774,0.0043113870,-0.2608861625,-0.6190173030,-0.6328819990,1.0290852785,-0.0337157957,0.4794288874,2.3265194893,0.6430379152,-2.3729488850,0.9642911553,0.1792990863,-0.7555418611,-1.6815297604,-0.7509630919,0.5920519233,0.5271238089,-0.3613370359,-0.8814773560,-0.4798953831,0.4807034135,1.0450673103,0.4689154923,-0.8064729571,-0.1262860000,0.5163205266,-0.0193388909,1.3125473261,-0.0543386117,-1.2151954174,0.2638210654,-0.0364308245,-0.5281606317,1.2426241636,-0.3205830455,-0.1426075846,-0.4687280953,0.1643962413,-0.3802402318,0.3136390150,-1.4041841030,0.5760033131,0.1114661992,1.5098890066,0.6955231428,0.1370026469,-0.7484128475,0.8863014579,0.6602393389,-1.9834080935,-0.5476236939,-0.1973284334,2.7404897213,0.3918314576,-1.0367541313,3.3678669930,1.2490388155,0.4868883491,-0.1266106814,-0.3812051713,-0.0928058252,-0.6301029325,-0.2929019630,0.8924237490,-1.1051132679,-0.5074141622,0.8979958296,0.6536089182,-1.9230524302,-0.1654659212,1.8929178715,1.2809594870,-0.0103674419,0.3907116354,0.7662822604,1.8371510506,-0.3340227604,2.5882060528,0.2204035223,0.5281216502,-1.7063302994,0.9104158282,-1.6062641144,-0.7288155556,0.2892820239,-0.9528056979,-1.0483649969,-1.4120820761,-0.4685563743,-0.9451056123,1.8808521032,-0.7579481006,-0.1606787741,0.5887008309,0.4289551675,0.3829198778,-0.3382299244,-1.3812276125,0.4090642035,1.3374681473,1.2288401127,1.5761895180,-0.8516318798,-0.2723531723,-1.2398227453,0.2986592054,-0.1322129071,0.0139572183,-1.0466662645,-0.2781076133,-2.0794694424,-0.0169874635,-0.2712719142,0.0039244746,0.4328824282,-1.1713631153,-0.7448069453,-2.3252754211,0.8434809446,1.0628112555,1.0627806187,1.3218361139,-0.1161545292,1.3281513453,0.2959490418,-1.1790206432,1.4481866360,1.1699938774,-1.1192673445,0.6433444619,0.2693232000,-0.1480689347,-0.1910275519,-0.8702706695,-1.4614882469,1.8815187216,-1.4435530901,1.4433736801,0.3612532616,-1.4280672073,2.8515341282,0.6932016015,-0.9333375096,-0.3010189831,-0.5288223028,-2.0452833176,0.0003303100,0.0397834890,-0.2597131431,0.8163148165,1.0304787159,1.0927882195,-0.3876484334,0.6974347234,-0.2137241662,0.0889874473,2.0182070732,-0.6308559179,-0.4557030797,1.8793838024,1.0392211676,0.3013942242,1.0411463976,-0.7474292517,0.4135686755,-1.2054290771,-0.4202263951,0.7777327895,-0.4293861985,-1.3665663004,-0.6443052292,0.9349673390,-1.2924108505,1.2160620689,0.3794503212,-0.5429808497,1.1152054071,-0.0982226357,-0.2433270663,-0.5958116055,0.1453744769,1.3489847183,-1.0879634619,-0.7124319077,-1.0658148527,0.6417328715,-0.9150858521,1.7110761404,-0.1847843677,-0.5252919793,-0.1499496102,-0.6333470345,0.5339637995,-0.0101217143,1.5284255743,1.4889923334,2.0363731384,0.2519434094,1.1972477436,0.1169527769,1.0913250446,-0.7577394247,-2.2312619686,2.0685327053,0.9227512479,-0.4438139200,-0.7689087391,0.5014011860,-0.0705506951,0.8355823159,1.4453328848,-1.8012226820,1.9324140549,-0.3285877109,0.3485644460,-1.0819559097,-1.6279023886,0.3250808120,-2.0706045628,0.3532761335,0.1403892487,-0.1772062927,-1.8101980686,0.4101774693,-0.0899073407,1.7163796425,-1.1482729912,-0.9280102253,-0.9309043288,0.7067950368,-1.5563870668,0.7764381766,0.4183218181,-0.5949311256,-0.5479576588,-0.3660928607,0.1221372858,-0.8077557683,-0.7920037508,2.3722608089,-1.5027210712,0.0144450190,0.1528333724,0.7655932903,0.4014534056,-2.3351640701,0.4352296889,0.4105211794,0.6907932162,-0.9530596733,-0.6473321915,-1.4276818037,-0.2839665115,-0.6459219456,1.0340801477,1.1909698248,0.4201194346,2.0286815166,1.7382160425,1.2285472155,0.3203367889,-0.1061791256,-0.0371501744,0.1596977413,2.9247212410,0.4545726478,0.1455145329,1.1376500130,-0.6597639322,-0.7237402797,1.7943882942,-1.0624425411,1.0409113169,0.7168018818,-0.7416293025,1.6516425610,-1.2652876377,1.5150113106,-0.4677824974,0.3317876756,-0.1702616215,1.0125669241,0.6174751520,0.0796523988,-0.3447691798,-0.8938841224,-0.2084598839,-1.6965242624,-0.3470969200,-0.5429576635,-1.2105997801,-0.8608617783,-0.9803560376,-1.0367319584,-0.2582563162,-0.0054417914,-0.9185775518,0.0305522084,-1.5969980955,1.0509661436,0.4743795395,0.3633412123,2.1253325939,0.2701029480,0.7550885081,-1.0644488335,-0.6703055501,0.5664753318,0.2437788546,0.9583575726,-0.7638131380,-0.0029742755,-1.6142610312,-2.2065219879,-0.6328999400,-1.1739649773,-0.1321678013,0.4885062575,1.3792656660,0.9682490230,0.0666629449,-1.4227808714,0.9389460683,0.6142101288,0.4952200651,-0.3560309410,-0.4492895603,0.8873738050,0.4932395518,-1.5655148029,-1.1107832193,1.0344661474,-0.6064270735,2.0916547775,0.8920361996,-0.9328433275,-0.5210302472,-1.3629417419,0.6946575642,1.2764936686,-1.5056940317,0.1522615552,0.5383676291,-1.5878702402,-0.4938810766,0.8755227327,0.9683454633,-1.1522424221,-0.0225333683,0.9137845039,-0.5549679995,-0.7432829738,0.5882457495,1.3948264122,-0.5563979149,-1.2109256983,0.6127566695,0.7170585394,-0.9698428512,-0.0640512407,0.9629530907,-0.6542029381,-0.4348601699,1.3914189339,0.0691725537,-0.7639746070,-1.0185455084,-0.6848862767,-0.8079086542,1.0332250595,2.0122599602,0.2306910008,-0.1354916990,0.6538707018,-0.5724883676,-1.4610589743,-1.1935203075,0.2267056406,-0.8769122958,-1.8110815287,-0.0701249689,-2.1590735912,-1.7739510536,0.7410432100,1.1597032547,1.0969405174,1.9822311401,1.7125688791,0.4174836278,0.7853913903,0.5818963051,-0.2479056716,-0.7231642604,-1.0702124834,-0.3364195526,-0.1131938845,1.1898450851,0.3929497898,-0.9904890060,1.3256819248,-1.4747922421,0.8332212567,-0.3751766980,-0.5573330522,1.6865506172,0.4411950111,-0.1255817413,2.5350151062,-0.0580064729,-1.1477249861,-0.9363329411,1.0586061478,1.6392625570,-0.5135805011,0.5801268816,-0.0548072122,-0.9464817643,0.0946878791,-0.7109422088,-0.3775828481,0.6923879981,-0.1164232716,-0.0274552815,0.9514126182,-0.4382908940,-1.1965507269,1.2529064417,0.2980563641,1.3691887856,-0.0335965566,-0.5210404396,-0.0635088459,-0.6337655187,0.4338080585,0.0755116045,1.0962269306,-2.0093507767,-2.4804511070,-0.4190257192,-1.1947860718,0.7652868032,0.1273288131,0.8648121953,0.1008700207,-2.7048275471,-0.9510456920,-1.4726403952,0.0437071584,0.0826288909,2.0108227730,-0.6876509190,1.0703777075,0.3906943798,0.5436729193,0.9461514354,0.4150171578,-1.2524062395,0.3780267239,0.4788390398,0.1191774979,-0.2176552713,0.6323692799,1.2053620815,-2.3339111805,-0.6712306142,-0.2902439833,0.9778840542,-1.2306065559,0.6382020712,1.4408342838,-1.4152365923,0.7717177272,1.0857385397,-0.0721675083,1.7905182838,0.2215190679,0.3466854990,0.4562369287,0.5969560742,2.9985487461,-1.3164579868,-0.3309495449,-0.1202616245,-1.3430130482,-0.3943373263,-0.2237624377,-1.0122376680,1.0934064388,2.1965367794,-0.9623855948,0.4112857878,-0.7151125669,-0.2869275510,0.2724553049,-0.4762646854,-0.4325575829,0.6262726784,-0.8784438968,-1.5952491760,-1.9096953869,0.3377545774,-0.7852398157,-1.2339268923,-0.6910353899,-0.6821838617,-0.4460454285,2.0578155518,-0.8237828016,-1.1603840590,0.4606530964,0.7554635406,-0.4197842777,-1.7064237595,-0.4686983824,-0.8817868829,0.2867316008,1.2538535595,-0.1737776101,-0.2247789651,-1.5630481243,0.4511615634,0.6216961145,0.0750527158,0.3924145699,-0.3754163980,2.8608353138,1.5530757904,0.0425318517,-0.1855948865,1.3114998341,-1.9979593754,-0.1392807513,-0.5736815333,-1.1196737289,-1.2200103998,-1.2405149937,1.6866083145,-0.1392551512,1.4387949705,-1.4744572639,-0.1115004197,-0.1053058803,1.5830054283,0.5361398458,-1.1185491085,0.1301326603,-0.1323783994,-0.6407990456,-0.4196328819,-1.3846974373,1.3309514523,-2.7046353817,0.0045477180,0.8607456088,-1.1245253086,1.2274123430,1.0389893055,-1.9995344877,0.8867872953,-0.7012874484,0.4385780990,-2.4129841328,-1.8402497768,-1.1964808702,-1.0597640276,-0.4711083174,0.9958802462,-0.7689711452,0.4363094270,-0.3747068644,-0.8480607271,1.2542796135,0.2656555772,2.2228662968,-1.8119665384,-0.9371265769,-1.4262866974,0.1876880974,-1.0126883984,-2.0700709820,-0.0803233460,-0.7962924242,-0.0414651409,1.7242867947,1.1771477461,-0.8121748567,-0.1645865291,0.9184431434,-1.0123202801,-0.3763069212,-0.1460562795,0.2211588472,1.1201910973,-0.0191150960,0.7085775733,1.4897265434,-0.0689364448,2.1542754173,0.4996797740,-0.4819819331,-1.2270764112,0.9048069715,1.1497319937,0.1581166685,0.9835773110,0.8247444630,0.0351414941,-1.9824454784,0.2739833295,1.2348875999,0.7725579739,0.2573614717,0.5969483852,0.2761405706,-1.0226633549,1.7934087515,0.1439145803,0.9556096196,1.9798411131,1.5616306067,0.4073262513,0.8567109704,-0.5908481479,-0.4551822841,-0.6076927781,3.1823654175,-0.2167487592,0.2382182330,-0.1999024898,1.5419658422,0.5953208208,-0.5438700318,-1.2184040546,1.0318024158,-0.3316418827,-0.8802697659,-0.8947135210,-0.0105047869,-3.3704369068,0.4810324013,-1.9140502214,0.3950212300,1.6429020166,0.8465449214,0.4476325512,0.4394526482,0.6456232071,-0.1141211912,0.3965323269,0.4823193252,1.1300865412,-0.1235338151,-0.5488389730,0.5645562410,0.2612779737,0.3265740275,0.6936011910,-0.2548986077,1.5862183571,-0.9947738051,0.7125069499,-0.2931319177,1.1054304838,2.4689922333,0.8357470036,0.0130731547,1.4690824747,1.7760980129,1.7123028040,0.7116003633,0.0806625262,-1.2783840895,-1.2734508514,-0.5681645870,-0.6348869205,0.4688507617,0.6399840117,-0.1546345800,0.0401923917,-0.4833675027,0.7989139557,-0.5271605849,2.2883720398,0.9557285309,-2.1976850033,-0.9270659089,-0.7950120568,-0.0018317529,0.1464039981,-1.2294088602,1.3516594172,0.9153459668,-1.5380679369,-0.8945394158,0.4787234664,-2.2154150009,0.4985513687,-0.3055807352,0.3027708232,0.7394517064,-1.1887978315,-0.8729275465,0.0136809060,0.2144620121,0.1222232655,2.0651092529,-1.3659356833,-0.6718088388,-0.3926681578,1.7661414146,1.9525667429,0.5477364659,0.4586538374,-1.6999478340,-0.9211118221,-0.7009931207,-1.2132214308,0.1789101660,0.1699265093,-0.5791007280,-1.1458439827,1.6576943398,-0.0798066929,-0.5319992304,1.1932622194,1.2408850193,-0.9731871486,-1.6201738119,-0.4493438900,-0.4226911962,-0.0897471532,0.7771114111,1.4575105906,-1.3590695858,-0.2422187775,-0.0717459098,-1.5813609362,0.3929780126,-0.6107853055,1.0224369764,0.9272652268,0.2391461581,-0.7454996109,2.5418419838,-0.0836168155,0.0664021298,-2.0217483044,0.0662804097,0.8211984634,-0.5589304566,0.2068057358,0.0640166700,0.9859380722,-0.9006294012,0.8219537735,0.1385826170,0.9545242786,-0.0526152104,0.2759426534,1.2005162239,-1.2941392660,-1.3588281870,0.0705319345,0.7191971540,0.9778149724,-0.8361923099,-0.0056291926,2.0522983074,1.5833069086,-2.3987114429,1.3274357319,0.0064704483,-0.6484159827,0.9853000641,-1.3528258801,0.9159484506,0.2959030271,1.7370500565,1.2756021023,-0.0047396058,-0.2977020144,-1.0068558455,0.3262749016,-0.2303540409,0.2995219529,-0.3161655068,0.0587377883,2.1757032871,0.7780051231,-0.6155528426,-0.6651592255,-1.9044895172,1.0170710087,-0.2350578159,0.8182260394,-0.8092999458,1.7549093962,1.1859247684,1.2325001955,-0.4970070422,-1.8003635406,0.0549518168,-0.8563482165,1.9319586754,1.1410189867,1.4234589338,1.0574718714,-0.3678317964,-0.6011454463,0.9331198335,0.4304300845,0.9622161388,0.7820424438,0.5289376378,-0.1422957182,-0.0972463861,-1.1529253721,-0.3259295225,-0.7833554745,1.3779989481,-0.8609403372,-0.1602535546,-0.0599776134,-1.4946795702,0.2707850337,-0.5179989338,0.8004550338,-1.2054712772,0.5004020333,-1.8651032448,0.5174418092,-0.9989871979,0.3034828305,0.3723188043,0.3597621620,1.8270949125,0.4796812832,-1.3419852257,-1.7499210835,-0.1308304220,-0.8859434128,-0.4169880450,0.1174671724,-2.3178379536,-1.3677680492,0.3057938218,0.4547121227,-0.3513031304,-0.2731293142,0.0115191638,-1.1899770498,-0.7389093637,1.1789582968,-0.8494232297,1.5048207045,-1.4718470573,0.0784921274,-0.8367189169,-0.7885698676,-1.6579880714,-0.3294337988,-2.6300072670,-0.4856718183,-0.2715861797,0.2706677616,0.3428797126,-1.0286426544,-0.4359491169,-0.8634329438,1.7400062084,-0.6620771289,-0.8842269182,-2.4243388176,-1.9477770329,-0.2599925101,1.3951880932,1.7454518080,-0.8353650570,0.9496917725,-1.1362177134,2.7656846046,-0.3285786211,0.1080850959,-0.3550520241,0.5351243019,0.0626995116,-0.9387552142,-0.3435013890,0.7270622849,0.6199610233,-1.6607036591,-0.6297575235,0.7958660126,0.2775168121,0.1991933733,1.5361841917,0.0672869310,0.3522060812,-0.6162402034,-1.7315293550,-0.0968044847,1.3629524708,0.0375886112,-1.2578284740,0.4546712935,-2.2027161121,-0.7068659067,0.1386501193,-0.5204744935,0.8022690415,0.1464944929,-1.0731513500,-0.0275365952,0.3999854028,0.6108346581,0.7355435491,1.8661667109,0.4773959816,-1.0730679035,0.8396475315,1.1034216881,-0.5024297237,0.7762069702,-0.0361183025,0.6873787045,-1.6265043020,0.0699692369,0.3768470585,-0.9322768450,0.0477588251,0.9751135707,-1.9907674789,0.1195630580,0.3530760705,0.3995818198,1.1568886042,-1.2285298109,-0.2479773462,-0.0089573311,0.7797752023,0.3299199641,0.9332191348,-0.4034706950,-0.3111452460,-0.4305924177,1.3256598711,1.1262835264,1.1973778009,0.1951432228,0.2563470602,-0.2257311791,-1.0581756830,0.5406070352,1.2327010632,0.3645146191,-0.9438908100,-0.5273874998,-0.0965472907,-0.7064593434,1.3101346493,-0.6243762970,0.5321087837,0.8991381526,-0.0843996927,-0.9281385541,-0.0536656491,1.8132817745,-0.6429740191,0.2113274634,-0.2402074486,1.0136674643,0.3831409812,-1.0056535006,0.6262342334,-0.0874363706,1.3416323662,-0.4109298885,-0.0141236670,-0.7411656380,2.0815262794,-0.7702627182,-0.3985530734,-0.6752582788,-0.9599013925,-0.3416412175,-1.3532416821,1.8661503792,0.1309303790,0.1339515895,-0.5823944807,1.7389822006,1.0031000376,-1.0844048262,-0.4892614186,0.5706951022,0.7267456055,-1.5972158909,-1.3844085932,0.1251437813,-0.1611333787,1.2971414328,-0.4890547395,-0.2959007025,-0.2359022498,-1.5221960545,1.6418451071,1.8629655838,-0.6008669734,-0.6448215842,-0.6749278307,-0.2803279161,2.2114477158,-0.2965689003,-0.3168765903,1.3606915474,-0.1464030147,-1.2688233852,-0.8596234918,-0.2300802022,-1.5350259542,-1.1681234837,0.0532827750,-0.6676311493,1.1589723825,-0.2325885743,-0.1550059468,1.2478905916,0.2482963949,1.3774282932,-0.8201007247,0.7307916880,0.3846693635,-1.3935933113,-0.5091059208,0.1876038760,1.2699453831,0.0560138673,0.8535129428,0.5293108225,-1.3195542097,-0.3675530255,-0.5306439996,-1.3628910780,0.4709477127,-0.4559128284,-0.2349215001,-0.9671003222,-1.4965330362,0.3901738822,1.0340222120,-0.1132831424,-0.8353191614,-0.2977720499,0.4513333738,0.8387823701,1.0269012451,0.7130354643,-0.3210241795,0.6128639579,1.6848592758,1.6609615088,-0.0710362568,-0.4100494087,-1.2127778530,0.8047491312,-1.7605817318,2.9120903015,0.9917885065,-0.5696196556,1.1640443802,-0.3759628832,0.5348631740,0.8605149984,-0.4322288930,-0.8272349834,0.8973447680,-0.9950327277,-0.0557409078,1.0292906761,1.1893057823,-0.2426627278,-0.4762936532,-0.3401097953,1.9560794830,-0.9409772754,-0.1492427140,-1.4113221169,-1.7686339617,1.7728070021,1.4844536781,-0.6800952554,0.8788170815,0.8911567926,1.2230223417,-0.8783909678,-2.2849061489,-0.5757948756,0.9280388951,-0.7595967650,0.0587394610,-0.1624921113,-0.2155980915,0.2433040589,0.0557866134,-1.1757665873,-0.1818657964,-0.2644596994,-0.9477189779,-0.9844954610,-1.3387968540,-0.0450486951,-0.6944232583,-1.0707694292,-0.7842970490,0.6350764632,-0.7319315672,-1.6097750664,-0.4874561727,-1.2056317329,-0.3934192061,-0.9384541512,-1.2435036898,0.7331660986,-0.1061901152,-0.2536563277,-0.4899016917,0.2329620421,-0.8986451030,0.2935437560,-0.6980230212,-1.5478031635,-0.6342258453,1.7035830021,0.1028883606,-0.7894119024,-0.1351793706,0.5689413548,-1.0633289814,-0.0086180344,1.7042182684,-0.6117020249,1.2448474169,-0.6777845025,-0.2346623689,-1.9456766844,-0.0306932554,2.1096534729,-2.2844188213,0.0728366897,1.2431104183,-0.5718863606,-1.0966272354,-0.9830226898,0.4332626760,-0.6825378537,0.8575298190,1.3153325319,1.9670081139,-1.3972771168,-0.1857836246,0.1219161525,-0.5779262781,0.6101424098,0.2377535701,0.2397469133,0.2591325343,-2.0442194939,-0.6908274889,0.2541438639,1.8209025860,-0.7531303763,0.8614359498,1.5990792513,0.8102792501,-0.6263534427,0.0995728076,0.2731429636,0.7282792330,0.0114688184,-0.4514726102,0.4547981322,-1.7314876318,0.9617160559,0.2156383395,2.5990610123,-0.8828431368,-0.1147982627,0.1282157302,0.4696044922,-0.5134382844,-1.5148773193,1.6586340666,-1.0218036175,-0.0250433777,-0.2382687032,0.2340601683,-0.7567276955,-0.3305819333,-0.3038704395,0.8338783383,0.1608898491,0.4396271110,-1.8737742901,1.3429384232,-1.3435566425,1.1009212732,2.0582981110,-0.9400506020,0.7694303989,1.4895060062,1.1229710579,-0.4763310552,-1.1265016794,0.4342498481,-1.0764023066,0.1756174266,0.2279533893,0.4279670715,0.2260316908,-0.9843562841,0.6740505695,-0.8490674496,-0.3237790465,-0.4662958682,0.1734868139,-1.4428119659,0.6804466844,-1.0618598461,-0.7360239625,-1.2143082619,0.4160400033,-1.0800274611,0.3315010965,-2.1402599812,1.2378108501,-0.7899955511,-0.1041101590,2.0045559406,-0.4333100617,-0.4725388587,0.1273653358,1.4571205378,1.3495620489,0.5959379077,0.2545638978,0.3057740331,-1.0019536018,0.5784690976,0.2518575788,0.6918970942,1.5384705067,-0.2609039545,-0.2850797176,1.3235375881,1.1674975157,-1.4240127802,0.6997848153,-0.8154026270,-0.3378392756,-1.8234149218,0.6829866767,-1.2062163353,1.6120146513,-0.7018817663,-2.2123842239,0.8546330333,-0.4547747076,-0.3642478585,-0.3706068397,-0.2988089323,0.6899989843,-0.6115986109,1.2595679760,0.2240811884,2.6741890907,-0.5876898766,1.5658192635,0.6845703125,1.0701469183,-0.3652437329,-0.2096356004,0.3791528642,1.5315600634,-0.1469570398,-1.5674178600,0.7937241197,-1.5094797611,-0.4463437796,-0.4219004214,-0.3260750473,0.3198117614,-0.9380064011,-1.2634960413,1.2424186468,1.4660786390,-0.4180395603,0.1620767266,-0.2839062512,1.7759104967,-0.8857923746,-0.5912535787,-0.5251594782,0.3382563591,-1.5086387396,-0.3405946791,-1.8012282848,-0.0873163119,-0.5842204690,1.2199001312,-1.4205188751,-0.2968263030,-1.3448718786,0.6785737872,0.7722478509,-0.2272520810,0.0527814403,0.9790414572,-1.3844666481,-0.7844890356,-0.7075823545,-0.3223336637,1.5800389051,-1.0154743195,0.3925264180,0.5471366644,0.2460810691,0.1381963342,-1.3894932270,1.9471534491,-1.5014412403,-1.0413231850,0.3324744999,-1.6873404980,-0.2129056156,1.4749987125,-1.4523178339,-3.1190896034,-1.2718390226,2.4424221516,0.9950337410,-0.0496420674,0.9837993979,1.9826014042,0.7137126327,0.3330027759,0.0999203622,-1.2657548189,-0.4869438410,0.9282532334,1.1198828220,-0.3685782850,-0.3691154420,0.2586824596,0.4915171266,-1.1458977461,0.8304197788,-0.2539549768,-0.1996763498,-0.5544936657,-0.0025407872,0.1407305300,0.4582334757,-0.4711025953,-0.2920936346,0.6538417339,1.5560307503,1.7619452477,1.2360332012,-0.1315362304,0.0920973346,-1.4905031919,1.2301188707,-0.4421279728,-0.6929170489,-0.7973194718,0.0634542629,-1.2857584953,0.0631699786,-0.0861530378,0.2839331925,1.2970875502,0.2933334410,-2.3788189888,-0.6523681879,-0.0305581670,-1.1570004225,-0.7451606989,-1.3816602230,-1.4926953316,1.2165389061,0.4167850018,-1.4080522060,-1.4262783527,1.2082084417,0.6638391018,-0.7060305476,1.1353538036,1.3180701733,0.8578649163,-0.8731014729,-0.9829578400,-0.5651094913,0.6818859577,-0.6653128862,-1.0673677921,0.8933325410,1.2560358047,-1.1704576015,1.4296464920,0.6040555239,-1.8464752436,1.3270595074,0.1488941312,1.6056982279,0.5017446280,-0.8903104663,0.1706050634,0.8819519281,-0.0030436872,1.6358895302,-1.2797946930,1.2676116228,0.1627141535,0.7670778036,1.4692165852,0.0669638589,-0.3648871481,0.4743653536,1.0513372421,-1.1020389795,0.7753785253,1.0108804703,1.0408326387,-0.5209835172,0.6818500757,0.0904824138,1.0239518881,0.6365932822,0.4699539542,-0.7060739398,-1.0360990763,-0.4540962279,-1.3326988220,-0.5124089122,1.0929511786,0.5940018296,-0.4353291094,1.6788744926,0.7090277076,0.6970493793,0.6935103536,-1.5174489021,-0.6674986482,0.3959916234,0.0314268805,1.1867270470,0.1292989403,0.2488492429,-0.2043378651,-1.3287620544,-0.7390286326,0.8793639541,0.5443399549,0.4859343767,1.2453608513,-0.3818763494,-1.6809335947,-0.3598356843,-1.3391313553,0.6595156789,0.0735542253,-0.0190615188,0.3803745508,1.8210678101,-0.0958271772,1.8411321640,-1.3670797348,0.5427723527,-0.7703274488,-0.6727721691,2.0768125057,-0.8670269847,-1.2214968204,1.0898650885,-0.0725031719,-0.0864036158,-0.4280133247,0.4899945259,-1.1253395081,2.0763638020,0.1353816539,1.4642211199,-1.5274518728,0.9599250555,-0.7167305946,-0.1460455060,-1.6847262383,0.4852546155,-0.2923988700,-0.4610815942,1.1864080429,-0.3434349298,-1.2183084488,-0.4544598758,1.3759692907,-1.1702294350,-0.8205097318,0.0596311018,0.2823673487,-2.4523892403,0.1126904637,0.4746390879,-1.6707005501,-0.9480802417,-0.1634900272,-0.4575511217,0.6539748311,1.3743329048,-0.2066034228,1.9918875694,0.0467024818,-0.5654628277,0.5026557446,0.7354540229,-0.2884488404,-1.1007701159,0.3083924353,1.0963255167,0.1424771547,-0.1030726954,0.8625275493,-0.7215863466,-0.9913249612,0.6632069349,0.4783222377,0.3580340743,-0.1725240052,-0.6392794847,0.2011111081,-1.6484777927,-1.0174485445,-0.0872349590,1.1921215057,0.5025959015,0.2836691439,0.8681715727,0.3389258087,0.5296366215,0.6545069814,-1.9461959600,0.5430054665,0.5104394555,-0.7187666893,0.4541369677,0.9566402435,-0.0594963208,1.6902428865,0.8972370028,0.2773114443,-0.4134947062,-1.2408342361,0.4204489291,-0.4516286850,-0.2110308409,1.0829126835,-0.9779353142,1.0323063135,-1.2429711819,0.6037898064,-0.3205806017,-1.2381771803,-0.3923279941,-0.0805774033,0.4635975063,-0.2898182571,-0.2014379799,-1.4034485817,1.1136484146,0.0691273436,0.2618164718,-1.8693686724,-1.2310501337,-2.6746325493,-0.6870961785,0.4724680781,-1.7013285160,0.7355017066,-0.2741308510,2.2835941315,0.7250497937,0.7654329538,-0.5647279024,0.1644261926,0.5307115316,0.5746467710,1.9586399794,-0.5265694857,-0.4879961312,-1.4865173101,-1.1455962658,-0.4128835797,0.6693022847,-1.5804158449,1.2603547573,0.7857226729,1.2067354918,0.4648757875,0.9003841877,0.5806150436,-1.7880207300,0.5372216702,0.7575263977,-0.5589818954,-1.0746775866,-0.0021043734,-1.6893839836,1.7304996252,-1.1568057537,-0.0617405735,1.0687190294,0.5711197853,-0.4428283572,0.1552816480,0.2527465224,-1.1368750334,-0.5381591916,1.5881439447,0.2860608101,0.3805446029,-1.6672601700,0.7602344155,0.4308459461,-0.5576328635,1.4369031191,0.5004381537,0.6119653583,0.7021585107,0.3857577443,-0.7897416353,-0.6196731329,1.0033321381,0.5967955589,0.6828916669,-1.1994363070,-0.9904943109,-0.3934526742,-0.4732136130,0.2426480353,-2.0425484180,0.8007996678,0.5071797967,1.5479482412,-1.9100352526,-0.9601728916,0.9510821104,-0.0823726431,1.3400896788,0.0834527016,0.6438699961,-0.9652031064,-0.4854627550,0.1482844353,-0.9956216216,-0.3950155675,-1.4705321789,-0.6609185338,-1.8514585495,0.1311995983,1.6940715313,-0.1337316930,0.5798290968,-0.2847125828,0.3875262141,-0.0368419625,-0.2958053052,-0.2373793572,0.3187682629,-1.4628130198,1.7015430927,0.3156693578,-0.0703716800,-1.4071842432,-0.5739857554,-0.6005715132,0.0037154576,0.3062636256,1.8498947620,1.4188458920,1.4881933928,-0.9052850604,-0.1264310330,0.3862965405,-0.8140952587,-0.3810549974,0.6935589314,0.2257216722,1.0393418074,-0.1589675099,-0.1574358940,-0.8825321794,-0.1856806725,-1.1158484221,0.0572987758,-1.7708715200,-0.1011177674,0.7603165507,-0.8440169096,-0.2493463904,1.7614215612,-1.5872883797,-0.1093700677,-1.3668683767,0.0597839355,-0.4041580260,2.0201151371,-0.8874104619,1.0089551210,1.1857368946,0.8527296185,-1.5749006271,0.4625138044,0.0153149329,1.2475622892,-0.1801164150,-0.1654497087,0.2987264693,-0.0666087642,-0.5388320088,0.5844370723,-1.0518535376,1.1758712530,2.0751616955,0.0651127324,1.0435625315,1.2183630466,-1.1029225588,-0.3894551992,0.4537330270,2.0570921898,-0.6587897539,0.7516878843,-0.3802327514,0.6569559574,0.3319684267,-0.7577400804,-0.6714701653,0.6479204297,-0.0799216107,0.8066828251,0.1515915394,0.4205271602,-1.3345781565,1.2583372593,-1.6809546947,2.8598580360,0.6408307552,1.4548523426,-2.0656576157,0.9247038364,0.1503020823,1.2612864971,0.1509641409,0.4554774463,-0.3452061713,0.7462652922,-0.1073673740,0.9654961824,-0.1182610542,0.4436274767,-0.9892361760,-0.7423120737,0.0164196324,1.1263713837,-0.9633116126,2.3793332577,0.0003982415,1.7510664463,1.4233546257,-1.7395235300,0.7623349428,0.3986560702,-0.3507902622,-0.9979709983,-0.2359415144,0.1348109394,0.1125656813,-0.6708725691,0.3356072605,-1.2268385887,-0.1155574620,1.5565766096,0.4939498603,-1.1511844397,-0.2640740573,1.2304129601,-0.6129906774,1.4380507469,0.5469411612,-0.2832261324,-1.2993297577,0.9013664722,0.2450891584,-1.5840128660,-0.9167362452,-0.8300950527,0.1757986993,-1.6784344912,0.0636152625,-0.4752668142,1.0027318001,-0.4386060238,0.4709543586,0.2046563327,0.7120774984,-1.0557335615,-0.1954088658,-0.3462091386,-1.4930646420,-0.1731721908,-0.0131932432,0.1934194416,0.6658257246,0.6255763173,0.7684777379,-0.2945936620,-0.6855698228,1.6016274691,0.4373116791,0.2726550102,0.8263636231,0.8291152120,-0.3335766494,-0.8821152449,-0.2419444174,0.3788249791,0.7710736990,0.1886449307,-0.7076955438,1.0469366312,-0.1463537216,2.6089265347,-0.6633446217,-0.2353220284,-0.2212995142,-0.7482500672,-0.2117432356,-0.6482862830,1.7328232527,0.2244552821,-0.6652676463,0.3964279890,0.5592606664,-1.9637831450,-1.8922384977,-2.4780626297,-0.1493539512,-1.4736962318,-0.5816019773,0.9401268959,-1.4714045525,-1.1942760944,0.3668976128,0.0830259994,-0.8098945618,-0.2031483948,0.7353839874,0.0058557466,0.1347817332,-1.1094521284,0.2028308660,0.2542048991,-1.1559451818,0.2734256089,0.2041602880,0.7460332513,-0.0899389461,-0.2154787630,-0.2122800201,0.9198871851,1.8418318033,-1.5593268871,0.2610054612,-0.7024561763,1.7462798357,1.4986221790,-0.8376168609,1.0504339933,1.7258865833,-1.9487813711,1.1911542416,0.2755780518,-0.2877275944,-0.9894776344,-0.3523977399,0.3716616035,0.7340951562,0.0465161428,2.0946755409,-0.4287497699,1.2823368311,-0.1708106399,-0.3339754343,-0.3745219409,0.0234510638,-0.5941810608,-0.6525736451,1.0548883677,0.2085448205,2.1524362564,-0.2876541615,-0.8876055479,1.3150926828,0.5178136826,1.6735327244,0.2665548027,-1.4265080690,-0.4362727702,-0.3537387848,-0.4326723218,-0.2196337879,0.1769788712,-0.5016754270,-1.9468058348,-0.8031057119,0.8652901649,-0.1611579061,0.2561255395,1.7606273890,-2.1001949310,-1.3642786741,-0.2298175246,0.2183056921,-1.8855527639,-0.4925869107,-0.2614548802,-0.8557839394,-0.1850143373,1.1688899994,-0.6215562820,-0.7275066376,-0.3990510404,-0.0416359417,-1.7970087528,2.5328645706,0.2876232266,-0.9678805470,-1.0853585005,2.2810258865,0.5573899746,0.7743658423,0.6814321280,0.8439531326,0.8247879148,-1.6703401804,-0.6495918632,-0.5389128923,-1.3334633112,0.5207111835,0.6436123848,-0.6462132931,0.3580046296,1.6225868464,-0.4871959984,0.6803805232,-0.2100579590,0.1405427754,-0.5697072148,2.1073331833,-0.9879789948,-0.5540517569,1.3131885529,-0.5549680591,2.8242397308,-0.5965105891,1.5914705992,1.4811695814,0.3065227866,-1.2098796368,0.0168109611,-0.1309269071,-1.2207504511,0.6678852439,-2.1338050365,-0.6641706824,-0.3057371974,-0.0899235457,0.1791422814,0.8580896258,-0.8787598014,0.4738532007,0.6654763222,-0.8824122548,-1.6115596294,0.5279802680,0.0964465886,0.9635578394,-0.3902786672,-0.3802396059,-2.2409791946,-1.0808991194,-0.7525261045,0.2250808775,-0.3743494749,-0.1169842705,0.0614006370,-0.3293505013,0.3097124100,-0.7995985150,1.8154002428,-1.5777002573,-0.5507161617,0.6225386262,-0.3113619685,-0.9763633013,1.4898904562,0.9300459027,-0.5811542869,1.2458498478,-0.2211971879,-1.5934373140,0.0132478783,0.9656499028,-0.1373882741,-0.0728489086,-0.5899522305,0.1944191307,0.4169383943,0.2829756737,0.1644549668,-2.1832423210,0.6266455054,-0.5795871019,-0.9039760232,-1.7385983467,0.2067382336,-0.2576915324,-0.4712277055,-0.5019993186,0.1468517184,-0.9671674371,0.0666483492,0.9021647573,-0.8958581090,0.8980016708,-0.1871165037,-1.4828082323,-0.5323514938,0.0343699008,-0.0326057225,-0.0458269492,-2.2640006542,-0.2263824195,-0.0426686592,-1.0875192881,-0.0749526247,-0.1680147648,-1.7522611618,-1.0544925928,0.5329548120,-0.4137636125,1.4957363605,-1.1262655258,-0.9431248903,1.1091076136,0.3187142015,-0.4425956309,1.9129506350,0.1657711565,-0.1740225405,1.1547033787,-0.4135216177,0.0847586095,0.6157559752,-0.2677897513,1.0562356710,-0.4857402742,-1.3100956678,1.5738106966,0.3299025297,-1.1636645794,-0.5389083624,0.3641978502,1.1415319443,0.3955402672,0.1479743123,-1.5591546297,-0.2825756967,0.9462650418,-0.6458616853,-1.2211798429,-0.6016332507,0.7985215187,1.0275365114,-0.0160687435,0.4915259778,0.1202829033,1.1910266876,1.3510931730,0.9124286175,-1.5193203688,-2.6604340076,1.6008164883,0.1068808660,-1.2210118771,0.8822169900,1.0649386644,-1.4589542150,-0.7992488742,-0.1713563204,0.4389387369,-0.2636434436,-1.6290132999,1.1303752661,0.1080426127,0.8657753468,-0.9457086325,-0.5738193393,1.2187113762,-0.5768360496,-0.8167025447,1.2510757446,0.3992554247,0.2217383087,-0.6826551557,1.1338157654,-1.2801879644,0.9553549290,0.2114500254,-1.3725106716,2.0755689144,0.3925169110,-0.4047083855,0.5372302532,-1.0917904377,0.1228743196,0.1735812575,1.3295997381,-0.9710007906,-0.0175675768,0.6346111894,0.5424829125,0.4861537218,-0.5748277903,-0.4538476467,-0.6988639235,0.3595512807,-0.3014974296,0.4904040098,-0.4762947261,-0.2976291776,0.2722819448,1.8400909901,1.1112102270,0.3468321562,-0.7620072961,0.4823642671,-0.0431677178,-1.1301577091,0.7625041604,1.0072216988,-0.7397775650,1.2135487795,0.4348278940,0.2891020775,-0.2582736611,-0.4398835003,-1.1159187555,-0.4120377302,-0.3862161338,-1.0398606062,0.5330690145,0.0991028398,-0.3123979270,1.4060606956,-0.2284294963,-0.2856896520,-0.3457508683,-1.8428200483,0.7488943934,0.1384963244,-0.2578194737,-0.1127146631,1.1032286882,0.5590403080,-0.1274744719,1.1027128696,-0.3745149970,1.4169546366,1.0180193186,0.3566385806,-0.2235454619,-0.9186764956,-1.8063689470,0.6170316935,0.8247284293,0.1426244229,0.1843836755,-1.2132909298,-0.3551035225,-1.0385468006,-1.0946146250,-0.6682890058,0.0346868075,0.7390833497,0.6645213962,-0.6030436158,-0.5423620343,0.4705986083,-1.2859250307,-0.0684260353,-0.3965751231,0.0891710445,1.4725625515,-0.5956141353,0.2861987054,0.1781372875,-0.1194024906,-0.2217310071,0.9313843846,-0.6242418885,-0.0836989135,-1.6565767527,0.7462492585,-0.2159588784,0.2116937339,-0.2267422825,-2.0483932495,-0.0378425568,0.7382618189,-0.8901466131,-0.1636219770,0.1239845902,0.3381330073,-1.2129957676,1.0842293501,0.9588112831,-0.4454301894,-0.7255096436,0.5139003992,1.0043842793,0.4047205746,2.6048500538,-0.7641742229,-0.1398930699,-1.2959104776,-1.8625189066,0.8397760987,0.0908519179,1.7395669222,-0.4368506372,-0.4642670155,0.8948456049,0.0972507000,-0.5477635264,1.8051584959,-0.6752122045,1.8902174234,-0.2260762304,0.0208178144,1.9998450279,-0.6578727365,0.1301973611,-1.1438729763,-1.0635344982,0.3119478226,-0.4038535357,1.0320700407,0.0470034257,-0.3322484791,0.8958112597,-1.0423126221,-0.2093100846,-1.0931046009,-0.1595915258,-1.0094487667,-0.2817739248,1.2365338802,0.1999276727,-1.5332267284,-0.7521827817,-0.0498312488,-0.1254887134,0.2784412205,-0.4777686596,0.1808462292,1.7320671082,0.6485695839,-1.1794214249,-0.0287689120,2.1534762383,2.1387667656,-0.1862127781,1.3411992788,1.2107347250,0.9686575532,-1.3244681358,-0.3789440989,-0.5815922618,0.3594802916,0.5171622634,-0.6009837389,0.3175195158,-2.2224929333,-0.6074861288,0.2733509541,0.0802273899,-1.0692006350,-0.9597536922,0.0113089839,-1.3741334677,0.2265929431,-0.6278473735,1.2340617180,0.0882001072,-0.3142201900,0.2227886170,0.8545964360,-0.0908002779,-0.2843574286,2.4294245243,-1.6052583456,-0.2354816645,-0.7199215293,-0.6534951329,-0.1538714468,-2.6277620792,0.9282026291,0.4786596000,0.7063364983,-0.9769585729,0.5844084620,-1.4787604809,1.5954923630,-1.5470777750,-0.0792327374,0.7591784596,-1.0835412741,-2.8589627743,-0.0519933216,1.1929847002,0.1627516150,0.9921510220,-0.1297453046,-0.5478489995,-1.8640022278,0.2769920826,1.2735897303,0.7470535040,-0.0304872170,-0.0428298526,1.0499415398,0.4667961597,1.2053909302,-0.0714367554,-0.5911626816,3.0160570145,-1.3844703436,-0.1397884190,1.4430978298,-0.6048903465,-0.7319226265,0.0735818520,0.1856525242,-0.3724898100,2.3749258518,0.4259150028,-1.3816146851,-1.0676062107,0.0282882024,-1.3178880215,-1.5067243576,1.7033506632,-0.3256493509,-0.3136684895,1.1504480839,0.3979339004,-0.8979489803,0.6665918827,-0.2177965790,1.7094330788,-0.0203922130,0.5821586847,1.4792309999,-0.0451435968,1.9510873556,-1.4385012388,0.6818209887,-0.6088625789,1.1092604399,0.2422867864,-0.4770748615,1.6948552132,1.1704604626,0.4564086497,-1.0953822136,-0.7527635098,-1.5625915527,0.1791021079,1.8587647676,0.0916229114,0.4258229136,-0.9329550266,-0.0671339333,0.1869338453,-0.1333879828,0.6261107326,-1.5891088247,-0.2642643452,1.1548100710,-1.3183220625,0.6512417793,0.9680756330,0.9950332046,-1.0700780153,-0.2943134904,1.7982032299,0.4225844443,-1.5542390347,0.2829584479,-1.2698465586,-0.8019006252,2.0648713112,-1.2976447344,-0.2495082319,-2.9228045940,0.5553191900,-0.6955707669,-0.0912849903,0.0168256983,-0.3094053566,1.1338710785,1.4277110100,0.6253098845,1.1908096075,0.2107233107,-0.7185921669,-0.2519544363,1.7649414539,0.6261631846,-0.2532690167,-0.4259355664,-0.3002924323,0.7058870196,-1.5119395256,0.6891105771,-2.2670624256,-0.3775601983,-0.7435219288,0.6637009382,-0.6702621579,0.2118441910,2.0264430046,0.2950162590,-1.9733177423,-0.6014866829,0.7231934071,-0.5663225651,0.2073399425,-2.2557966709,0.0920352787,-0.1102471575,-1.1182092428,0.8314582109,-0.6517904997,0.5727631450,0.6002388597,1.0145868063,1.2000041008,-0.3893697262,-0.2220023125,0.0439428948,-0.0033232714,2.1105318069,-0.7621703148,-0.1955248266,-1.0612522364,0.5935337543,-0.7442343831,-0.4376539886,-1.2502030134,-1.1209059954,0.6724943519,-0.6831957102,-1.3959691525,-0.3748416901,-1.3967071772,-0.6097630262,1.0784497261,-0.0811343193,-1.4515217543,1.7069116831,-1.4116988182,0.0189672094,0.0360026099,1.5870809555,-0.8664822578,-1.3608570099,0.5752806664,0.0327789560,-0.4369576275,-0.1481619924,0.5401315689,-0.5292395949,-3.2350654602,1.1074713469,0.9541392326,-0.6092355847,-0.6445279121,-0.1951347739,0.6513268352,-0.7532553673,0.3051186800,0.9178270102,-2.5410294533,-1.6669428349,0.4259666800,0.6748510599,-0.4968488812,1.1697164774,-0.1687025577,-0.6268527508,-1.2338035107,-1.3931992054,-0.3564191163,1.4220254421,1.0918205976,1.2700427771,1.5146982670,-0.3999033272,0.0118509382,-0.3351794183,-0.4617187977,-0.2531777620,1.2234048843,0.2188955843,-1.2126897573,1.0774984360,1.5508300066,1.3986558914,0.4946941733,2.1584038734,2.4771494865,0.5729361773,-1.1950562000,0.5807843208,2.3439888954,2.1803681850,-1.5197203159,-1.3456399441,0.0533661768,-0.7593796849,-0.4989078045,0.0440334193,-1.8984165192,-0.4864933789,0.6840640903,0.2822242975,0.7824342847,-1.0771510601,-0.5577027798,1.4288663864,1.0138487816,0.4544593394,1.0341511965,-1.6534334421,-0.5851719975,-2.5957257748,0.6972800493,-0.2410648167,-1.1962827444,0.6448838711,-0.4857121408,-0.3649063706,1.0979299545,-1.5546585321,0.1901791841,-0.4854544401,0.0275086965,0.9509277344,-0.7999033928,-0.1402400732,0.0964038074,-0.1028219312,0.5689355135,0.3108150065,-0.3040729761,-0.4496122599,0.4359531999,-0.1692104042,0.0689164475,-0.7930421829,0.8997336626,0.7421265841,0.2194436193,1.0569325686,0.0017485305,1.0466918945,0.3023291528,0.3153903782,0.8032365441,-1.1121325493,2.6082203388,-1.3207836151,-0.3867725432,-0.3457061648,1.4187725782,-0.6497259736,0.7847685814,0.2821341455,-0.1602710783,0.0889612883,-1.4676092863,0.6674157977,-1.0673069954,0.2699068785,0.1724976599,-0.3715167940,1.0822068453,-0.7078635693,0.4691339135,0.3721350431,1.1494282484,-0.0420525447,-0.4953653812,-0.4252645075,-1.8390085697,1.0680310726,-0.0759820119,1.0406930447,-0.6761109233,-0.2665938139,0.3006088734,1.1225448847,-0.9760149717,-0.0417896174,0.0025571589,0.4015204310,0.7486844063,-1.3603100777,-0.8001003861,-0.4906891882,-1.0416312218,-1.0722851753,2.4610190392,0.2289647162,0.3938124776,-0.3345311284,0.5383934975,-0.2748134732,-0.6480213404,2.1349983215,0.1050079092,0.8258822560,-0.4955825508,1.7874985933,-0.3892707229,-0.7922250032,-0.3951547444,-0.0935009569,0.1839891970,-0.8543516397,-1.0464440584,-0.7042970657,-1.1806395054,-1.2209229469,-0.2441308498,0.6465824842,-1.5547673702,-1.7660431862,-0.4821627736,0.1407624334,-0.1678617150,0.9397349954,0.2312805504,-0.0280464403,1.6767039299,-0.9470214248,-0.9351007342,-0.9674376249,0.5599937439,-0.7846594453,-0.4185580611,0.1562634110,-0.5272597671,-1.4458227158,1.7874987125,-0.8945755363,-1.2059798241,0.2898784280,-1.5602114201,1.3168905973,0.4170904458,-0.5218951106,0.0991009474,1.1913528442,-1.0922662020,-0.8239323497,-1.3484790325,0.5477755070,0.6710631847,-0.4247452617,-1.6761363745,0.4697081149,0.0555586666,1.6238911152,-0.6668378711,-0.7418172359,-0.7404046655,-0.2535289526,0.7424023151,-1.4185131788,0.1802333444,0.1009450033,0.3009157479,0.1991927475,-2.3257699013,0.6526278257,-1.6105198860,0.7812666297,-1.1860648394,0.3073795140,-1.5439826250,1.0786151886,1.2680554390,1.1521686316,1.1935445070,-0.1329169720,-0.3085395694,0.0761978850,1.8443210125,-0.2638729513,-1.5977312326,0.8382647038,0.0859807804,0.1356368512,1.1917499304,-1.0192261934,-0.3402422965,-1.1250737906,0.2373281419,-0.5993966460,0.4661963880,-0.5152217746,-0.5071100593,0.5282868743,-0.1788586527,-0.1281480938,-1.3527747393,1.0704989433,0.5577857494,0.0059412615,-0.3464069664,-1.0306385756,-0.1926615536,1.6605831385,1.3970597982,1.7178465128,0.5896280408,-2.2436287403,1.4201089144,-0.6560614705,-2.3737287521,0.0326512717,0.2078212202,-0.0501976386,-0.3021792769,1.1992337704,-0.4503636658,-0.2515912652,0.1691752970,-0.0690513998,-1.7739503384,-0.0254569277,2.1342687607,-2.2958354950,0.4292617738,1.1680651903,-0.0823156610,0.6136156321,-0.1594337076,0.3683827817,-0.0694643259,-0.4721207917,0.3415882885,-0.6719304919,0.0745203495,0.0926815197,0.7809058428,0.8021600842,1.2536708117,1.2047463655,0.8457165956,-0.2689283490,-0.0406811796,0.7122931480,-0.0020184009,-0.7400744557,1.5476503372,0.7627727985,0.6692178249,-0.5025582910,-0.3137260675,-0.2285013795,0.3727241158,0.3642551601,0.6032511592,0.8335736990,0.1891970634,-0.3147652745,1.5904812813,1.0627577305,-0.6074346304,-1.1208091974,0.5797903538,-0.5553388000,-0.7626169920,-1.4770214558,2.1922209263,-2.2505557537,1.1951607466,-0.6032582521,1.1439125538,0.7489135265,0.8095982671,-0.3108332455,-0.3310345113,-0.8971514106,-1.5992891788,-1.4045076370,-1.4514647722,-0.5385984778,-0.9099396467,0.7821102142,0.3216437697,-0.7002050877,-1.6994129419,-1.0463931561,1.0386457443,0.1906262785,0.0693022907,0.3480342925,0.6630804539,-0.9648827910,0.1472559869,-0.0458867997,-0.9605195522,0.2654193640,-0.4124167562,1.2029577494,0.1682241857,0.1582312435,0.6462152004,0.7105493546,-0.5076053143,1.2874636650,0.7914259434,-0.3501081765,-1.3159191608,0.9087712765,0.3375329971,-0.0894550458,-3.3134696484,-1.0573728085,-0.4799038172,0.1022162735,0.0140804453,-0.4237525165,-0.0029144140,-0.4657649696,-1.2013605833,-1.8574804068,-0.7658002973,0.2583065629,-0.7350707054,0.5241965652,0.5456067324,0.5849019289,-1.0737682581,-0.3010232449,-0.4734374583,-0.3524091244,0.4543142021,-0.4802360535,1.5676404238,-0.0989632905,-1.2484837770,-0.8684524894,-2.6856575012,-1.2519989014,-0.3295105100,1.1998020411,1.5729202032,0.9265779257,1.4141265154,-0.2236066461,0.9494342804,0.8590515852,0.1530281156,1.1916043758,-0.1836208552,-1.3414688110,0.8105289936,0.2061579078,-0.5158743858,-1.1998797655,0.8480063677,-0.9648107290,1.0120599270,0.1300519258,0.1588593423,-0.1458848864,0.4267154038,1.5206574202,-0.2062469721,-1.0819133520,-0.9290098548,-1.7997145653,0.7159577608,-0.5012516975,-0.9157263041,0.1787528396,0.0459793061,0.5049911737,-0.8993741870,-3.0976221561,0.7384113669,1.5854134560,1.1512668133,-1.4262179136,-1.2774196863,1.7157492638,0.8839167953,-0.6359609365,0.8234870434,0.8796422482,-2.3434367180,0.5187589526,1.3172487020,0.2944667935,0.2227121741,0.5968134999,1.2236213684,-0.4995519519,-0.5660246611,-0.6994220614,-0.3106907010,-1.2275322676,0.7521572113,0.3444543183,1.5920861959,0.2251924723,2.2333335876,-0.0396176800,-0.1746587604,-0.1322690248,-0.4289151430,-0.7689406872,1.2304511070,0.2261408120,0.6992877126,0.8450301290,-0.6699578166,-1.3206387758,-1.4513704777,-1.8766469955,1.6361585855,-0.3785747290,0.8501096368,-0.0773385093,-0.1470464617,1.6808183193,0.3025913537,0.2117206156,0.0503673851,0.2844220996,0.3684289753,0.9366687536,0.6129627228,-0.6902558804,-0.3202367425,-1.7368016243,0.1083192900,0.2266173512,-0.2204572260,-0.8055815101,-0.5609047413,-0.5874257684,-1.4272302389,-0.4451175928,0.4001646340,-0.5392788649,0.0617882907,1.2349941730,-1.5404955149,0.6322777867,0.8958539367,-1.2067916393,-1.0665080547,-0.6116001606,-0.6186541319,-0.4733894765,-1.3370724916,-0.4977751374,0.6712226272,0.0883457363,2.0432891846,0.0867749825,0.2891819477,1.6255686283,0.5093495846,0.8634660244,0.7550491095,-1.4651743174,1.2748829126,1.3423838615,0.0865078941,-0.7244066596,0.8706378937,-1.7124751806,0.5211428404,-0.5917902589,0.5395089984,0.0224716794,0.4386703372,-0.8138235211,-0.2059317082,-0.9192074537,-0.0604479648,-0.4525226951,-1.9594230652,-1.5452584028,-0.2895898819,-0.0253855549,0.6934217811,0.3090851307,-0.2218995094,-0.0529302284,1.2924019098,0.9603215456,0.3587602675,-0.9552350640,1.1490943432,-0.0335796215,1.6779471636,-0.3259856403,-0.1739709228,1.5214538574,-0.6064954996,0.1615271866,0.6834179759,0.3536682725,1.0816570520,0.3024944663,-0.6590800285,-0.8109408617,-0.1566258967,0.4882825315,-1.2851366997,0.6194458604,-1.6078065634,0.0334874280,0.9258344769,0.3397276998,-0.0351016968,-0.8456002474,-0.4561108053,-0.8913973570,-0.1025945768,-0.2888323367,-0.2083857954,-0.1048913971,1.9896476269,-0.4569800794,0.0361020789,1.0713363886,-0.7877628803,-1.0399837494,1.3942734003,-0.4270233214,0.3786351383,0.9357964993,0.9731655717,-0.7636753917,-1.6540989876,0.8779069185,-1.4263557196,-0.0950654224,-1.5323438644,0.0343191847,-1.1123816967,-0.2708704770,0.1493589282,0.5749483705,1.4909499884,0.0755190328,-0.9530516267,0.6965177059,-0.6865991950,-0.9001799822,-1.1961323023,0.1245036572,-0.3526382148,-0.4453476369,-1.8010739088,0.5374770164,0.2574934065,-0.3085855544,-0.0640777200,-0.8079072833,-0.5141606927,-0.5505889654,-0.1982488185,-0.3675305247,0.4208337367,0.0965360552,-2.0656948090,-0.1829688996,0.2506989241,0.2846823037,0.3001767695,0.2364291400,-0.7418822646,0.5268235207,-1.3270870447,-0.8376921415,-2.0307159424,-0.4796929359,0.7163648605,-0.4497404099,0.0741514638,1.1273583174,-1.0137497187,1.3068083525,0.0346848592,-0.8894021511,-0.9632061720,-1.5303732157,-1.1514923573,0.8990085125,0.9828225970,1.2495281696,0.5501637459,-0.7472378612,0.8517258167,0.4913127124,1.1090178490,-1.0322618484,-1.5959858894,-0.3413833380,-0.1173982024,-1.6070528030,-0.2624657154,-0.6415647864,-2.6126191616,-0.5836005211,-1.0906150341,-0.8369953036,0.2202195823,1.8754501343,1.1174076796,1.0884023905,-0.2120194435,-3.0440869331,1.4379463196,0.1025658697,-1.5558474064,0.6945379972,-0.3602610528,0.0620819256,-2.5303983688,-1.4525141716,-0.0484901033,1.0190861225,-1.1029773951,-0.1772495806,-0.0186824985,-0.4372339845,-0.7663955092,-0.2264468819,-1.8660597801,-0.0174309351,1.2895250320,2.8766248226,0.5093661547,0.6372798085,0.3782185614,-1.2775412798,-0.9037016034,0.7714995146,-0.7808824182,-1.0733382702,1.5326451063,1.6875671148,1.1831212044,-0.3538039029,0.4219298065,1.1515035629,0.1067457125,-0.6593474746,-2.3907163143,-1.6215455532,0.0232353490,-0.4400199056,-0.0634604543,0.2586629093,-2.2663216591,0.6431171298,-0.6066202521,1.8293699026,-0.6815040708,0.5783654451,-0.8462299705,-1.7036626339,0.2688787878,-0.1152593791,0.0679218322,-0.4225247502,-1.4610382318,0.5065841079,-1.9560542107,0.4685810506,-0.6444819570,-1.4162796736,0.9209262133,-0.9962162375,-0.8262240887,0.9954686165,-0.6650307178,0.9970404506,-0.1991078705,-0.6442340612,2.0496962070,0.0618126243,-1.0454064608,-0.6637465358,1.9695299864,0.1250195652,-0.7327752709,-0.1359323561,-0.4412856400,-0.3675518930,-0.2591361403,-2.5769243240,-0.5419714451,0.2259461731,-0.1193021312,0.7141500711,-0.6071059704,0.3218783438,1.9557578564,-0.2104028761,-0.6749036908,-0.4633462429,-0.5990371704,0.9030663967,0.6569451094,-1.5796002150,1.3999508619,-1.0496129990,0.3546217382,-0.0530159920,-1.1967575550,-1.5856877565,0.0531225428,0.8695508242,-0.3861188293,-0.7244033217,-0.1855974942,1.0887128115,2.3390982151,-1.7254819870,1.5232543945,0.3753961921,0.9166776538,0.2828798890,-0.3334253728,-1.2294572592,0.3655229807,2.0233829021,0.2879462540,-1.4131339788,-0.7401593328,0.6440915465,-2.2614407539,-1.4203243256,2.6897394657,1.0188958645,0.8922799230,1.5838291645,-0.3026787937,-0.4696189463,0.7466695905,-0.6594412327,1.2971545458,1.1126279831,0.0633644760,-0.5827593803,-1.2563552856,0.1899198294,0.8947163820,0.4806729853,0.0808907971,0.8153989911,-0.5255755782,1.4518349171,-1.5716581345,-0.5564303398,-0.1252691299,0.8958023190,0.7547018528,0.6371154785,-0.1164987236,-1.7575292587,-0.8542814851,-0.7686762214,-1.0782096386,0.6460056305,-0.7257015109,-0.3034015298,0.6748173237,-3.3844981194,0.1262123883,-0.1035634950,1.4074908495,0.5247564912,-0.3472731113,0.8271560073,1.0331898928,-0.6009578109,1.1177165508,0.5174444914,-0.2727499604,1.3153707981,0.4109996557,-0.1952133924,0.3007640541,-0.5758360624,-0.5602527857,0.3082463443,-1.3120938540,1.7105407715,-1.5808700323,-0.8947734833,1.3084439039,0.5117423534,-1.4647477865,0.0225376338,-1.7247672081,0.4059568346,-0.5297921300,-0.4586297572,0.5186428428,1.1221458912,1.1941851377,0.7090333700,-0.1947846115,1.9539064169,0.2526306808,-0.7416341305,-0.3133064806,-0.3473016918,-0.0026028380,-1.0973331928,-1.1440614462,0.5836762190,-0.4917782247,2.3554165363,1.5738666058,0.5428704023,0.0142914858,-1.2510061264,-2.2476670742,2.6870701313,0.8242061138,1.8147623539,-0.3681277633,0.8724951744,0.4893138111,0.4355538487,1.4844454527,-1.4029507637,0.2526011765,0.1869145930,-2.3647630215,-0.4800653756,0.9991058707,-0.5212966800,0.1787936091,0.2968055010,-0.9514818192,0.7149151564,0.4679512978,-0.2365171462,-0.0139078815,-0.1421744227,1.4185181856,-0.8405714035,0.1105919480,-0.5550268292,1.3210300207,0.3122994602,2.4679713249,-0.6052124500,1.2478696108,0.0954830274,0.9173564315,-1.9533030987,-0.9786008000,-0.3256475627,1.0131014585,0.1920856088,0.8135458231,0.5758315325,2.8805861473,-0.5539932847,-0.1677597016,-1.1043391228,1.4870136976,-0.3989987969,-0.7816363573,0.9050074220,-0.6455032229,-0.4766314626,1.0585227013,0.3848082721,2.5556023121,-0.7868890166,-1.9005753994,-0.7796630263,1.6994067430,-0.8025813699,0.5371515751,0.4411693215,-0.1469948888,0.5937262177,-1.2914032936,-0.0362044945,0.7089365125,2.9356086254,0.0261324681,-0.0169340111,-0.0850357786,-1.1811912060,0.5618770123,0.1779046506,1.4448437691,0.1256714612,-0.9184864759,-1.1742694378,1.0258781910,-1.4049621820,-1.8019059896,1.6122846603,-0.9469008446,-0.9792156816,-1.0730874538,-1.9244215488,0.1242880449,-1.3025438786,0.9926157594,0.0525438972,0.1790150851,-0.8310004473,-0.1794541776,-1.1104866266,-0.2170728147,-0.4860383868,-0.0960857049,-0.4243250787,-0.3056462705,-0.0738886967,-0.2791997492,-0.1564156264,-0.8399229050,1.1458208561,0.6837478876,1.6160286665,-0.1099802181,0.1030385345,-0.4512418509,0.8318041563,0.9506053329,-1.7757173777,-1.9854574203,0.3565828502,-0.3700554073,-0.6152406931,-0.9687829018,1.3810563087,0.2320157290,-0.0397417285,-0.4070185125,1.0224226713,0.6736516356,-0.1206513643,0.3238360882,-0.7017626762,-0.0897023901,1.4467226267,-0.7196639776,-2.5757844448,0.3970977664,-0.2733588219,-0.3398293257,-0.2725647688,-0.4187522829,0.3255429864,1.5826820135,-0.5754086375,0.0943736285,-0.4439761937,-0.1710792184,-0.4510376751,-0.0273558944,0.2152557671,1.4247077703,0.0805678144,-0.6716182232,-0.9144644737,1.0538321733,1.6822096109,0.2016815394,1.2589432001,0.4971260726,-0.4490357339,1.7315534353,-0.4510636628,0.1474699676,0.9106471539,0.1625524759,-1.4341237545,-0.7749769688,-0.3517271876,0.8197718859,-1.1186920404,0.6920174956,-0.4592382312,-1.0409634113,1.7210446596,0.1002967730,0.0334235467,0.9438540936,0.5847578645,0.4156909585,-0.7136794329,0.5987677574,-1.1312581301,0.4730856419,-0.9133135080,-0.4913589358,0.1282602251,0.2038312554,1.4765167236,0.5084848404,-0.2917088866,0.3517220020,0.6517812610,0.6369057298,-1.2051205635,-0.6937068105,0.0933035389,-1.1256998777,-0.8713313937,0.6497979164,1.6654264927,-0.2665706575,0.9316011667,1.0475007296,-0.4163180590,-0.2547314763,2.2949197292,-0.7823335528,0.4881402254,-0.5845407248,-0.2045453191,0.1332875192,-1.0624183416,-0.7866970897,-1.6789759398,-1.4453302622,1.1875790358,-0.9976070523,0.7905008197,2.6770126820,-1.5829631090,-1.4054129124,0.2432076484,0.5539929271,0.9461371303,-1.2753396034,-0.4961832166,-0.1548965722,-0.4539283216,0.2310051918,0.1122577861,-0.3159879148,-0.1546914428,0.9573659897,-0.9810982943,-0.0313256383,2.7361254692,1.1906349659,-0.1153252274,1.1036010981,0.1202579215,-1.8402842283,-0.9810041785,1.6234278679,1.7131366730,0.9054279327,-0.0411528088,-1.1291643381,0.9142575860,-0.1347265393,0.7485822439,-1.1155381203,0.8338834047,0.0044410489,-0.1199790686,-0.2514708042,0.2934603393,0.0102223698,-0.9591860771,-0.4407611191,2.4567036629,-1.4015727043,0.3956102133,-1.2079521418,-0.3189548254,-1.0416499376,0.3006887138,-0.2559400499,-1.5648876429,-0.5479289889,0.9294615984,-0.7143161297,-1.3360306025,1.2542421818,1.6548587084,-0.7020130157,-0.0768703371,0.0540100858,0.7866579890,1.0969753265,1.6252093315,-0.5440499187,-0.7300460935,0.5121057630,-0.1335268468,2.5226573944,-2.0427842140,0.1997319609,-1.1326947212,-2.2240474224,1.7012556791,1.6482611895,-0.0981576741,0.6183930039,0.7943008542,-1.0404632092,-1.2540209293,1.0974723101,0.3400676847,-1.7999849319,-0.5149138570,-0.1294233352,0.2476343811,0.8727270365,0.0723300055,0.2251117826,1.4213521481,0.1532366574,2.6486074924,0.1167246997,-0.4805921614,0.3937732577,-0.9335401058,-1.4705386162,1.1323963404,0.0321465358,0.9102234840,1.3990534544,0.4905488491,1.0244057178,-1.6630067825,-0.3994784951,-0.3401413262,-0.3454761505,-0.0475850701,0.4195607305,0.1365256459,0.0498067103,0.4276661575,-0.5091152787,1.7417982817,-1.5653539896,-0.1948224455,1.4137815237,-0.3796446621,-0.6055162549,-0.4563442171,0.9318701029,2.0537283421,0.7551569939,0.1563235372,0.4450795949,0.2379143834,-0.8415094614,0.1656335741,2.3153066635,0.6370079517,0.6397714615,1.8445942402,-1.9889305830,-0.8778341413,-0.2747113407,1.4435391426,0.3957173228,-0.1096090600,-0.8891395926,-1.2789076567,0.0116699347,1.0117725134,0.3835023642,-0.5092669725,-0.0680650771,0.9934516549,-1.1740164757,0.1203645915,-0.2318346053,1.2257432938,0.1388643533,-1.1649215221,0.5175055265,0.2016887665,-0.3390520215,0.6372504830,-0.8617182970,0.3922643661,-1.1405359507,0.2569530010,-0.4474111497,0.0448078550,-0.2087467760,1.6296164989,-0.0296883136,-1.2102688551,0.5677373409,0.0009645627,1.3742536306,1.1661435366,-1.1338286400,0.7868994474,0.4527561665,0.2778838873,0.6215717793,-0.9352455139,-0.3557741642,-0.2322310805,-0.9921100140,-1.4324650764,0.6023430228,-1.1864603758,-1.0976997614,0.8242604136,0.1729867607,-1.1119036674,0.2921111584,0.0507399924,0.6631184220,1.2487870455,1.4756360054,-0.7475041747,0.5366319418,0.1717128307,0.4651950300,-0.0540710352,-0.2115193903,-0.2900735438,0.7111625075,-0.1079788059,-1.6012848616,0.3743604422,-0.0169442687,-0.9762680531,0.3801927269,0.1165735647,0.4455650449,0.1271342188,-0.5844639540,-0.3766897917,0.5482994914,0.2216329426,-0.5788456202,1.3263802528,0.6550196409,-0.7106993198,-1.1114065647,-1.2377024889,-0.9838712811,-1.2531896830,0.4703316987,0.0795856193,0.1470217109,-2.2242867947,-0.6280842423,0.3862711787,-0.2358767688,-1.0647182465,-0.2574432194,-1.4735280275,1.1477354765,0.8785506487,0.6193646193,0.0978459045,-1.0593994856,-1.1262053251,1.2516567707,-1.4200671911,-0.3345801234,0.2187118828,-0.1080835685,-1.2882615328,0.7958784103,-0.6218714714,-0.2906329036,-1.4599126577,-1.1279275417,-0.9053555131,-1.0980588198,0.1504440308,1.1394290924,0.3642742634,-0.1579071581,-0.9825789332,-2.1468319893,0.0083792591,0.7393897176,1.4622263908,0.1394752264,-1.5417640209,-0.2361054122,0.7392612696,0.8448073268,0.5637169480,0.0669474825,-0.0490082353,-0.1221956983,-0.0868485868,0.0036756690,0.0283785351,0.9145377278,1.3506923914,0.2616867423,2.4223361015,0.3500064015,0.5549456477,-1.2616983652,0.2947146297,0.8523635864,1.2621779442,1.0800333023,1.5876103640,-1.9408265352,0.2570088506,1.7748100758,-1.6168836355,-0.9866812229,-0.0237126984,1.4818791151,-0.2154493928,0.0660840422,-0.6549353004,0.0116032315,0.4643039107,1.3120938540,1.0078448057,0.4175274968,1.7760876417,-0.2337876260,-1.1625869274,-0.5908479095,1.1094672680,-0.5619422197,0.2336943001,0.5299299359,0.7005144358,0.9736207724,-0.4927281737,1.4668943882,-1.0239930153,-0.0770049617,0.7348200083,0.2523647845,-0.2476083785,0.9233145118,-0.0127188815,0.7690323591,1.3147650957,-0.0070816535,-1.9878875017,-1.5712317228,0.7105522752,0.5278979540,0.2327578664,-1.2572900057,-0.1001996845,-0.1817302555,-0.3798861802,2.3356816769,-1.6914775372,-1.1774146557,1.2655371428,-1.5351748466,0.7914337516,-0.6201122403,-0.3057745695,0.1126926094,0.6709082723,1.1037712097,0.1790883690,0.6736957431,-0.4431216717,0.8462934494,-1.1090414524,1.5360138416,-0.6972581744,-0.4059306085,-1.8871546984,2.0013945103,0.0334238783,-0.2949000001,-1.3512518406,0.6522342563,-0.7653886080,2.2844948769,0.8337475061,0.3221344352,-0.5305902362,-2.4431941509,0.8988071084,-1.0610204935,0.8465533853,-0.1923000813,-1.3131548166,-1.5066918135,0.6025505066,-0.8746331334,-0.3928633332,1.1593921185,0.1034096554,-0.3026155829,0.4849913418,0.1135137603,1.6720339060,-0.3694227338,-1.4470843077,0.7193400264,1.0495063066,0.0959530175,-0.6709577441,-0.3056570888,-0.6415513754,-0.5251059532,-0.6818318367,0.3147960603,-0.4887236953,-0.9638143778,-1.1264886856,-0.4230669439,-1.3753056526,1.4559468031,1.4765875340,1.2504413128,-0.4936591685,0.3515748084,0.2022776455,0.9292532802,0.8853971958,-0.6428562403,0.2419474721,0.6410183311,-1.7333700657,0.9614998698,-1.3203852177,-1.3492267132,0.1798286587,-0.5843139887,-0.3930367231,0.0276744086,1.1229655743,1.2574152946,0.5836015344,-1.8359272480,0.0817378908,1.3239192963,-0.4715490639,-1.7266557217,0.3238314688,-0.2207290232,1.0489692688,0.9688036442,0.4010276198,-0.3819698393,0.1248324960,-0.0166277848,-0.9547690153,-0.4959850311,-0.5902844071,1.8655183315,0.0865403786,-0.6640671492,0.5868545175,-0.2740457356,0.6969856024,1.4407171011,-0.1463461518,0.8920519948,0.3390126824,-0.0442162864,0.4553397000,-0.6127408147,0.3977233469,-1.7088475227,-0.1218002737,0.1388552785,0.4274210334,-2.0180900097,-0.1601694822,1.6350325346,-0.4815888107,1.4442528486,0.1157166064,0.2844043970,0.1153378934,1.5692323446,-0.2419142425,-0.5717042685,-0.1694380194,0.8772971630,-0.6982527971,-1.3658602238,-0.7143605351,-1.2969588041,0.3269412220,0.8335607648,0.4132811427,-0.0035941750,0.5502625108,-1.2089297771,-0.4677336812,0.4932954907,-0.2773734927,0.3793223500,-0.2142858654,1.4164570570,-0.0279256701,-1.4179240465,0.9715839028,0.3082867861,0.3752784431,0.9423430562,1.3675347567,-0.6815214157,0.5373745561,-0.4753558040,-2.2577373981,-0.1867559999,-0.4563869536,1.1202806234,1.1302267313,-0.9389406443,-0.7574245334,0.5267103910,-0.8715178967,-0.1430505812,-1.9246406555,1.8750369549,-2.5997474194,-0.8381543756,1.5143324137,-0.5030655861,-0.5764772892,1.0302103758,-0.3347219825,-0.0474841893,0.0351716802,-0.8788820505,-0.7732199430,0.1133688316,-2.5959587097,0.0701987743,-0.9390360713,-2.1080806255,1.2983478308,-1.7246512175,-0.6754827499,0.1538365036,-1.6606847048,-0.6705852151,0.4778603315,-0.4059040546,-0.4880833328,0.2577357292,-0.1147083938,-1.2455481291,-0.5508422256,0.3719415665,-0.5658921003,0.5245736241,-1.1117680073,0.0928273723,0.0218124297,-0.3010913432,0.8775908351,-0.2169012874,-0.8590472341,-0.3291174471,-0.5996320248,0.1607422233,0.4372586012,1.5891768932,-0.0624184571,0.7525455356,2.5343019962,0.7479329705,0.8544104695,0.4639654458,-2.2253143787,-1.0417768955,-0.0010615842,0.2537246644,-1.0748190880,-1.3404649496,-0.2640745640,0.3361747563,0.2933667600,0.7682360411,0.1233829632,-0.7152925134,0.7858465314,0.2019590288,0.5854577422,0.9132457376,-0.3124257922,-0.6049257517,-1.7231265306,0.7158805132,0.7621665597,0.4707882106,-2.9688909054,1.0587520599,-0.1631650478,0.0793522522,0.1336528510,1.0867087841,-0.5280027986,0.2855147421,-0.0667707622,-0.0035638765,0.4216847718,0.5443183780,0.2461861372,-0.1809778661,-0.8805108070,-0.1438997090,0.3478353322,0.8228884339,-0.5667278171,-0.4600711167,0.6176699400,2.3540959358,-0.8628973961,0.9088322520,0.6932885051,1.0956834555,1.0052500963,-0.4408296347,2.0047576427,-0.9447867274,0.9418581724,-2.8230834007,-0.3410270214,1.3397841454,2.1751554012,-0.0430340357,0.4309962392,-0.0155594079,-0.6336702704,-1.5577777624,0.1310043186,-0.4537871182,2.4866731167,1.1449908018,-1.5187022686,2.0298993587,-1.5842804909,0.2514736354,0.9716297984,1.7878285646,-1.2653026581,-0.1265586317,-0.1470164657,-0.7129474878,0.4800057709,2.8610293865,-0.1240404844,1.0638287067,-1.5669780970,0.8731978536,0.3589456379,0.2653459311,-0.5578699112,-0.6540279984,-0.2132600099,0.0867705345,1.2787603140,1.3769998550,1.2984076738,-0.0174389817,-0.0729143023,2.0917215347,1.5554282665,-0.5141366720,-1.5810707808,1.3129007816,-0.3244799376,0.7690106034,-1.3313903809,-0.1335199028,-0.1562579721,-1.2194261551,-0.0974660292,-1.2154504061,-1.0153028965,-0.9581129551,1.4123982191,-0.1402374953,-1.2557382584,0.6547852159,-0.9383400083,1.0114247799,-0.7177949548,0.8543280959,-1.2188569307,-0.4752506912,-0.6735640764,0.0805893838,2.9027316570,0.0258577615,-0.2556987703,0.0209448729,0.2968816459,1.4511637688,-1.0195590258,0.3860342205,-0.2076390535,-0.7492733598,-0.2612061799,0.2322777659,-0.0773505419,-0.8092628717,-0.3922980130,-3.0591294765,-0.7700003386,-1.5647056103,-1.1685365438,-1.1834771633,-0.7745651007,0.6517621279,-0.6666411161,-1.2065341473,0.8831382990,-1.3153542280,-0.0880349576,0.5406996608,-0.2709668577,1.2457705736,-0.4655426145,0.5110310316,1.6702328920,0.0507460684,-0.6514158845,0.4647938311,0.5530887246,0.1307623982,0.0550314337,0.3614056408,1.2339098454,-0.5118358135,-0.1313847899,-2.1826581955,-0.1817007065,0.0118881213,1.1555757523,-0.5332305431,-0.7610717416,-1.1782858372,-0.1647985727,0.6561669707,-0.7847946286,0.1190716103,1.7935775518,-2.1962480545,-1.1013448238,-0.8153190017,2.0948555470,-1.3238399029,1.0909674168,0.7659215927,-1.5969687700,-0.5738921762,-1.4300869703,0.7761298418,0.1169549376,-0.2567743063,-1.3555506468,-0.0286894329,0.3896198571,0.1592593044,-0.1276924163,0.7255066633,0.8067373037,0.9591949582,-1.6959720850,-2.4361855984,0.6476137042,-0.7000209093,-1.7535645962,0.0522507057,-0.9426590204,-0.1567277461,-0.2495714128,0.3145912290,0.7321646214,-0.2300930619,-1.1882681847,0.7567175031,-0.7333874702,1.4053243399,-0.3211281300,-1.7157675028,-0.7250712514,-1.2069982290,1.3195250034,0.2129811645,-1.8306376934,0.0801075250,-1.1997556686,-0.3797031641,-0.1439069211,-1.3755490780,-1.9295804501,1.0497505665,2.1053328514,1.3196328878,-0.0395816118,1.2614026070,-0.0005954857,-1.2713522911,-0.1604739726,0.4342354238,-1.0333087444,2.0633223057,1.0521577597,0.3827154636,0.7366225719,0.4496108294,0.0940372646,-0.7754995227,0.1078162566,-0.7633399963,0.4329693019,-0.7188794613,0.6669287682,1.4806238413,-1.2925173044,0.3922462165,-0.1607157439,1.3540416956,-0.2693899870,-1.8579820395,0.0982898772,0.9795159101,-0.0613298379,-1.5851001740,2.1930634975,0.8165221810,-1.4409997463,-0.8420747519,0.8619980812,0.3620576262,0.0261950083,0.1866548657,1.8038645983,-0.2240944952,0.7091770172,0.7871082425,-0.6826594472,0.8542404771,-1.8168696165,-0.7128713131,-0.0538153574,0.1904992610,1.2892400026,-0.9406535625,-1.7142122984,-0.4913613498,0.6450148821,-1.1126114130,-0.2288775891,-0.4744396210,-1.3762102127,0.5254834294,-0.5287557244,-0.5262985229,-0.1062486768,-0.6348058581,-0.9365763664,-0.1497449428,-0.1949767023,0.2172982693,-0.3022725284,0.8047858477,1.3903118372,1.3883538246,-0.7042567134,-0.1121719480,-1.3455646038,0.3870194852,-0.0965950713,0.9518412352,-0.1091744900,-1.1043176651,0.6279343963,1.4129952192,0.5325927734,-1.6628987789,1.5105077028,-1.2438029051,0.8583120704,0.2078500837,0.5437254906,1.4735174179,0.2169694006,-0.1485404968,-0.7130903602,1.4223324060,-1.0756270885,-0.9242228270,-0.7942515016,-0.6728418469,-0.6729523540,2.3121747971,-0.0744164959,-0.2179881036,-0.4866858423,-0.8224667907,1.1551148891,0.7958337069,-0.3938231468,0.2431697249,-1.9529821873,-0.2154482901,-0.2813555598,0.0592441037,0.2069272697,1.7651711702,-0.3149431348,1.1901835203,0.9350205064,2.1286346912,-0.1006811112,0.0827367827,-0.6280285716,-1.2208617926,-0.6480045915,-0.6513798237,1.3888345957,-0.0509894826,-1.5703502893,0.5715800524,0.9913051724,-0.1888523996,-0.3661287725,-1.8164740801,1.6539181471,0.2706396580,-2.3285901546,-0.6339191198,1.0078198910,-0.2167435288,2.8713746071,-1.0747338533,-1.0448617935,0.4725149870,-0.4177502692,1.1482754946,0.7925708890,1.6601495743,0.0192887355,0.2908635139,0.2582688928,0.7782739997,1.9146323204,0.7430780530,0.0700267404,0.0750506967,-0.8305863142,0.3035894930,0.2465319186,-0.2787216604,0.5338457227,-0.6506549716,0.9350888729,-0.1797624230,0.7599012256,-0.3284780979,-0.8421573043,0.1916376352,1.1291347742,1.5996108055,0.8662851453,-0.1602092385,1.8883359432,0.3574674428,0.2051007152,1.5985630751,0.8055735826,0.7127355933,-0.3533496857,-1.4823664427,-2.0089395046,-0.9939237833,-0.6550972462,-0.0262048952,1.2165206671,0.1078934073,-1.3689708710,0.1513076723,-0.4456702173,-0.0554245599,0.7030171156,-1.2767373323,-0.7908762097,0.2892021835,-1.2196539640,2.0823202133,1.0406847000,-0.2916181982,-0.3322509229,-1.2407140732,-0.1473717541,0.5597736239,-0.3266303241,0.8758299947,-1.4328693151,1.1302080154,0.9464007616,1.0138847828,1.8907960653,-0.7582595944,0.1726988256,0.1735392958,-0.5599799156,1.8208374977,-0.7746500969,-0.6911838651,0.0445401333,1.2483352423,-0.7943223119,0.0519079305,-1.5848653316,0.8621872663,1.2930183411,2.7784893513,0.3236986399,1.4388288260,0.7258377075,-0.8048277497,0.2800495028,-0.0499605834,1.3089578152,-2.4130134583,-0.2753242254,-0.7478988767,-0.6888538003,-0.8414610624,-0.8301863074,-1.1255892515,-1.0282196999,0.5207557082,0.2261744589,0.3474826515,-1.0355030298,2.4439811707,-0.8515596390,-0.1384771913,-1.0451205969,0.6859315038,-0.9893190861,1.7343578339,0.1348031312,1.1066228151,-1.0953452587,-0.1847550869,0.2814736664,-0.6099718213,1.6427118778,-0.1525585204,-1.4401333332,0.5616949797,0.7036054730,-0.3839696050,0.0347902104,1.3739222288,-1.3430659771,-1.5973757505,0.3135956228,-2.0644445419,-0.5595622063,1.2138389349,-0.0590524115,-0.2654310167,-0.0230365172,2.3398439884,-0.4614900947,1.2380152941,-0.2797059715,1.4746888876,0.2444090098,1.7653659582,-0.4687747955,-0.3881003559,-0.3427613378,-1.1154838800,-0.9173331857,-1.2664217949,0.8875035048,0.6352165937,-1.1627904177,-0.6139476895,0.5397555828,-1.8344066143,-0.2994301021,0.2945496738,-0.2418930382,-1.9963649511,0.3640803993,-0.1844701171,-0.6950638294,-1.4857170582,1.1242765188,0.7085320354,0.2723022401,-1.5546014309,0.1953181177,-1.5684660673,-0.6086485386,-1.3542300463,-0.4276607335,1.4777511358,0.0993386284,-1.8139836788,-0.7365110517,0.6629828811,0.2414772660,0.5044490695,1.0643922091,-0.1175867841,0.0788819045,1.0972431898,0.2484007776,-0.0112973209,0.7241719365,-1.8626170158,0.0347400159,0.1793256998,-0.8870456219,-0.0319259167,0.8181232810,0.6993884444,1.2714951038,1.4938253164,1.2755190134,-0.7280711532,-0.0053603342,-0.6611225605,1.2958151102,1.1125426292,0.0500253364,1.4127457142,1.2092069387,-0.6113958955,0.5983562469,-0.7948383093,-0.0255965069,0.5676263571,-0.4503745735,0.8968400955,-0.5737510324,-0.8267991543,1.5909577608,-1.5717008114,1.0053443909,-0.1096132845,0.4106061757,-1.1032598019,-0.0910399705,-1.2157471180,0.9933787584,0.3237740099,0.1134621352,-0.1503658146,1.2782334089,-0.7552730441,-1.2234134674,-2.0203626156,1.0978006124,0.7394206524,1.2319457531,0.5734107494,0.4472402632,-1.9491572380,1.7882524729,0.7341278791,-0.3616535962,0.6778038144,-0.5595866442,-1.1381254196,1.4615677595,1.6242483854,-0.5140312314,-0.2640652955,-0.0112548228,-0.3889789283,0.6068689227,-2.8274755478,-0.0085445140,0.4904544950,0.1616977453,1.0789258480,-0.0618563630,1.7721537352,0.3887664080,0.9643759727,1.4623794556,0.1064803451,-0.8805568218,0.2923339605,0.9559921622,0.3187932968,1.0508491993,-0.2954924107,-1.0405685902,-0.0598033965,0.9603899717,2.1053576469,1.3079080582,1.2512524128,-0.6764339805,0.4047291279,-0.8339336514,1.8518990278,0.9332556129,0.7688630223,1.9514070749,-0.3171782494,-0.4678969979,-1.0559155941,2.0887012482,-1.8049836159,0.0430028215,0.3988151848,0.4500122964,-0.2574366927,-0.3913790882,-0.6121475101,1.0972211361,-0.0593496226,0.3291324973,-1.7988839149,-1.0083388090,-1.6112517118,0.1174412668,-0.3404005766,-0.4726842642,-0.4491213262,-1.0615438223,-0.2107420564,-0.3817735910,0.2995887995,-0.9482329488,-0.2399285883,-1.4830079079,1.4051352739,0.8220074773,1.0181708336,0.7705841660,-1.4086661339,0.1062365994,-0.3218088448,-0.0925237611,-1.0620304346,1.6652784348,0.0058519463,1.4551757574,-1.4438506365,0.2192535847,0.3335919678,-1.2820657492,1.2886893749,0.3952491581,1.1653424501,-1.0537530184,-0.0074237022,-1.2312995195,0.4738241136,0.2731259465,0.7465436459,-0.6233760118,-0.2805426717,1.5110511780,1.1256532669,-1.1806602478,-1.3495339155,0.3354279399,-0.1391374320,-0.8745224476,-1.7112647295,-1.4185328484,0.1687638760,1.9717078209,1.1529743671,0.6822891235,-0.4956736565,0.0578047819,-0.7183652520,0.5551437140,0.3473408520,0.4653676450,-1.8341126442,2.2764511108,0.4477431774,-0.6344168186,0.5948296189,1.5689496994,-0.1255524755,0.9398848414,-0.4700069427,-0.0290891398,0.9742378592,-0.8186925054,0.4190974534,-1.6216185093,-0.3389663696,0.5089208484,1.5303941965,0.3098924458,-0.7619076371,0.3587762415,-1.3091235161,0.8170292974,-0.6985152364,-0.1834008396,-0.1097707674,1.0684025288,1.3673287630,0.0024511134,-1.0490896702,-3.0076134205,1.4514784813,1.2511434555,-0.0860626996,0.5120401382,0.6248494387,-1.5006062984,1.8949669600,-0.7988373041,0.0659881309,-0.2443456352,-0.5105406046,-0.2946806252,0.8995938897,-0.6719914079,-0.9645525217,0.4793780148,-0.3133210838,-1.4314814806,-0.9944772720,-1.4454166889,0.0671993122,-0.5245435238,-0.3248140812,-0.0862735212,-1.2868779898,-0.2069968730,-0.8418411613,-0.8098770380,-0.0245797615,0.2288850546,0.4888761342,-0.9548777342,1.2134466171,1.6297017336,1.0540798903,-3.5775067806,-0.5092924237,1.5152270794,1.3439284563,-1.3064225912,0.5239573121,0.6371377110,-0.5815712214,1.4705703259,0.2761515379,-2.2635154724,0.8119996786,0.2082707137,-0.3286717832,-0.2771964967,2.2118780613,-2.1735358238,0.1249354333,1.4037474394,-1.4499368668,0.3003337979,-0.5304105282,-1.7573840618,-0.6856645346,-0.5914506912,0.7638018727,-0.2675991952,-1.0980226994,-0.4089368284,1.1221373081,-1.0884951353,-0.6319181919,-1.2549594641,0.7170437574,0.0045071896,-0.6356463432,2.3410551548,0.8706154227,0.5790865421,-0.8792712092,-1.1271067858,-1.8982055187,-0.6447094083,-1.5107764006,-1.7840856314,-0.5934742689,0.6970037818,0.8130237460,1.6075373888,-0.1049850583,-0.2260528356,-0.8203536868,-0.2570720613,-3.0439462662,-0.8317464590,-0.0221328903,-0.7338784933,-1.1955124140,2.2275626659,-0.6152293086,1.0770606995,-0.8655061722,1.4497618675,-0.2080348730,0.0465875715,-0.6258221865,1.1146214008,-0.4552742243,-0.5624456406,0.8417857885,-0.5142645240,-0.2130188048,0.2848901749,-0.4078902900,1.4543926716,0.9406331182,-0.4867027402,0.0767036080,-0.2662543356,1.5841546059,-0.0371828750,-0.3927924335,0.5836333632,0.7966336608,-1.4907039404,-0.7028891444,-0.7504969239,-0.7478713393,-0.9128293395,1.1214281321,-0.9350854754,-0.4669199884,2.3918759823,-0.2142266184,1.8552978039,-0.9463956356,0.4829190373,1.2582088709,0.4328311682,1.1292302608,0.3805397451,1.2985144854,0.6846257448,1.6851937771,1.7153955698,0.8266667128,0.3266970515,-0.9034817815,-1.9895290136,-0.1561795175,0.7916913629,1.2313185930,-0.0866586864,0.8667936325,-0.9921289086,0.2599111497,-0.5031987429,0.2345968187,1.1069636345,-0.6858910918,0.6509312987,0.8513160944,-2.5334670544,-0.0781184584,0.6531443000,0.2202208340,1.1924302578,-0.0056578512,0.9925175905,0.4677110612,0.4470631778,-0.7054750323,-0.3973045945,-0.4325635731,-0.6860013008,1.0001733303,-0.9480412006,-0.8789937496,0.6653664112,-0.6843322515,0.8633398414,-0.5817058086,-0.6112054586,0.8448106050,0.6149102449,-1.7258707285,-0.2807382941,-0.1708089411,1.5577105284,-1.2645984888,0.9760804176,0.5516930819,-0.5967000127,-0.3854245543,-0.1739615947,-0.0207591373,-1.2616332769,-0.4005171359,0.3221673667,-0.2869417071,1.0295534134,0.1294983327,0.6947427392,1.2161408663,0.9053342938,1.4678857327,0.9029391408,0.5970921516,0.7944867611,0.4798160493,0.5198258758,1.2812861204,-1.1480890512,-0.0881863534,-0.2476950139,0.4717128873,-0.6225486398,0.2505447567,-0.6700253487,1.4420573711,-1.6963062286,-0.7611740232,0.6617693901,-0.0086765150,0.5258134604,-0.1621825248,-0.6918660998,0.7783997059,0.0281068888,-0.1641781330,-2.5166752338,-1.4063049555,-0.4924475551,-0.6959780455,0.9172568917,-0.5700587034,-1.9835411310,1.5791540146,-0.4925122857,-0.0458450317,-2.0372576714,-0.9087883830,-0.6633548141,-0.7705920935,-0.3299379647,-1.0611827374,-0.1742917597,1.0259675980,1.1829209328,-0.9411280751,-1.0046323538,-0.7954505086,-0.4666687250,-0.1476753652,2.2875802517,-0.2079681754,-0.2876192033,1.2012648582,0.6918829083,0.0862621292,-0.7218672037,-0.0940898657,1.8701169491,-0.0919047073,0.4451364577,0.5785190463,1.0394281149,0.4340084791,0.6246455312,-1.7443118095,0.0707430169,-0.2417886257,0.6761582494,0.2193481177,0.0652367175,0.2281389534,-0.1589985937,-0.0161593799,-1.1481174231,-0.8527640104,-1.9987218380,-2.2161722183,-1.1947005987,1.8645793200,-0.5195894241,-0.7349023223,0.1043193266,-0.7930381894,-0.5610723495,0.9559897780,-0.1279041469,-0.0052697291,-0.2292125374,-0.8965917826,0.1681797057,-0.5898171663,-0.3136174977,0.3532792330,-0.8734504580,-1.3299645185,-0.7033492327,-2.1503171921,-1.2717120647,-1.0888218880,-1.3648161888,-0.1491083056,0.5447972417,-1.7824438810,0.6282010078,0.1593699604,-2.5262157917,-0.7317644358,0.6677094698,-0.2354516834,-0.7564174533,-0.0117295058,1.3500658274,0.6012318134,0.6721284389,0.4980325699,-0.7003022432,0.5756027699,-0.5126936436,-0.0571699105,-0.7423155308,-0.8981233835,0.4272961020,-0.0257868152,0.8800768852,-0.8634132743,0.4586406350,-1.4525709152,1.0027289391,-0.2363725603,0.7175219059,-0.8529829979,-0.4932558239,0.1452093124,0.3464656770,-0.5518008471,1.5215642452,-0.3498942256,-0.8275839686,-1.7511603832,-0.5457261801,0.8822903633,0.0703879967,-0.9963659644,1.2804361582,2.6976993084,0.4033238292,0.8038191795,1.2802057266,-0.2588358521,-1.1650398970,1.1707892418,-0.5047108531,-1.0936511755,0.5469737649,0.0263632089,1.0759764910,-1.0194599628,-0.3734528720,-1.9364116192,0.0224650707,1.0462511778,0.4847756624,0.1901340932,1.2200636864,-0.5608323812,0.0520195700,0.0540600084,-1.3133441210,0.3604013920,2.1903557777,1.2696301937,-1.7450065613,1.4612462521,1.1277128458,-0.9614953995,0.1591152400,-1.0061297417,-0.3439558744,0.5855348110,-1.4501737356,1.5458877087,-0.6284275055,1.8623217344,-0.2068486512,0.0354135484,0.3395684361,0.2642773390,-0.7321042418,-0.5713635683,1.0891259909,0.3595553041,-1.1960923672,-0.3504222929,0.4999573231,-0.5098363161,-0.8443207741,-0.3192293346,-0.4329998493,-1.4102517366,-0.2385727018,1.1790127754,0.2475124747,-1.0066397190,0.9068338275,-0.5423150063,-0.3165667355,1.6968829632,-1.1119974852,0.4216455221,-0.8087496161,0.1220505908,0.1811276525,0.2846711278,-0.9815238118,0.0810643435,1.3072894812,-1.5053919554,0.8824597597,-0.9424833059,0.5472854972,0.1866397262,-0.3782856166,-0.6489279866,-0.1960052550,-0.7824270725,1.1514835358,0.9470567107,0.6862918735,0.4898491502,-0.2240593582,-0.5082946420,1.5246375799,-0.7205083966,-0.7252399325,-1.2068340778,0.6562124491,0.8725742698,-1.3504531384,0.2655869424,-1.1543271542,-0.3576900065,-0.3631928563,0.0644443333,1.0960409641,-1.2485544682,-1.3851460218,0.4644928277,1.5118932724,-1.6827667952,-0.1037741601,-2.8227734566,-0.4538195133,1.8951827288,0.2947148085,-0.4407174885,-0.6552804112,0.8836204410,-0.7145662904,0.2673783898,-1.0053929090,0.0218670834,-1.3796296120,0.3507533967,-0.2442570925,-1.0691617727,-0.7232266665,1.7802512646,1.4755240679,0.2832114100,-0.1803559959,-2.4272570610,0.9166278839,-2.0436441898,-1.2705802917,0.5730054975,1.5823352337,1.0499491692,-0.0399254858,1.3576145172,0.5052609444,-0.0344939381,0.7515062690,0.9314097762,-1.3302785158,-0.2806506157,1.6494643688,-0.6945965886,1.4947701693,0.5611131191,0.1360976994,0.1329657882,0.6428858638,-0.8688668013,0.5326808691,0.1221128181,-2.0173878670,0.2001792789,-0.4099375308,-0.6947799921,-0.2808746397,-0.1188127324,-0.5621849895,0.1748513132,-0.6217819452,-2.3000860214,1.0840605497,-0.7496613264,-1.5219525099,-1.7810281515,-0.8950442672,-0.0703199431,0.3249710202,0.4448671937,0.0597899482,-0.3028272986,-0.8436756730,-0.9046571255,-0.3266875148,0.4347041845,0.3949435353,1.1973904371,-1.1560224295,-1.0398107767,-0.0699188486,-1.4301743507,-0.0146584222,1.3570151329,-1.6681015491,1.2011176348,-1.0629158020,-0.2667770386,1.9444168806,0.8705314398,0.1332209855,-2.6169438362,1.2772220373,0.4033893347,-0.6000118852,-0.9993430972,-1.0177826881,1.3402198553,-0.4007156491,-0.1191185564,0.4988934398,0.0814124867,1.3495470285,0.2988345027,0.5763264298,-0.2183794379,0.4989469051,0.3067570627,-0.2668756247,0.0877958536,0.5085925460,1.4055000544,0.6140383482,0.0896825865,1.3617206812,-0.3267118037,0.6306826472,0.6890478134,1.1796201468,1.0196118355,-0.5822272897,-1.0949366093,0.0220815465,1.0912129879,0.8769557476,0.9900035262,0.9397202134,-0.0994466692,1.6669824123,1.4517176151,1.3211481571,0.2491372228,0.0155243585,-0.6893531084,-0.1140175387,-1.8416621685,-0.2381248474,0.7401183844,0.3654841483,0.2882166505,-1.0167877674,0.7473244667,-0.1891875267,0.9808660150,0.9236414433,0.6881241798,0.0554025508,-0.0573162176,0.5692203045,0.7792938352,0.6142871976,-0.6288341880,0.2108489275,-0.3727882206,-0.4873711467,-0.3820485771,-0.3673192561,1.5540332794,0.2947099507,-1.5285689831,0.3804260194,-2.0671718121,0.0550171919,0.8531175256,-0.6018936634,-0.8865386844,-0.5568744540,-1.4733337164,-0.8281208873,0.3987645507,-1.1531097889,-0.1092760414,-0.9467664361,-0.7997373939,0.3220396340,-0.3594762981,-1.1803499460,-1.3892723322,1.6811511517,-0.2709219158,-1.3034292459,-1.0962494612,0.1192781776,0.3181969225,0.6427437663,-0.4708162844,-1.8047537804,-0.1646451503,-0.2703527808,0.6318225265,-0.4536555111,0.1989347637,0.8032560945,-1.3178848028,0.6166307330,0.2845878303,-0.9893379807,1.2858288288,0.7459064722,0.9172755480,-0.4152849317,0.6127344370,-0.1464545727,0.3386917412,-1.1799244881,0.5358649492,1.8083715439,-0.9430469275,0.4336068034,0.8175193667,0.6452999711,0.8691123128,0.2442887574,1.8094760180,-1.6751033068,0.0677766576,-0.9925397635,-1.0871496201,-0.2437263578,-0.4215831161,-0.1992474645,-1.3104773760,-1.4547755718,-1.1687017679,0.3781206310,0.5475878716,0.9851617813,0.4662987888,0.3638120294,0.2394635975,0.9616629481,-0.0387977324,0.9407829642,0.0011507085,1.8726496696,0.1954480559,0.4769034386,-1.0875762701,-0.7599243522,-0.8566319942,-1.9922207594,-2.2812983990,-0.2973401546,-0.5694825053,0.0664883927,0.4117467999,1.1683961153,-3.0562281609,1.7612978220,1.7013229132,0.2869657576,0.0255660973,0.3154593110,-0.2584732175,-0.1614930183,2.3610413074,0.4873589873,-0.5125331879,-0.3015183806,0.3679594100,-0.3626063764,1.0938476324,-2.5488677025,-1.3180434704,1.4499435425,0.7009496689,-0.1576300114,0.4049410820,0.1778909564,1.3396008015,-0.2206843495,-0.2286064029,2.0505385399,-0.4772749841,-0.0627959520,0.0254990458,-1.3595477343,-1.3190525770,-1.0695114136,-0.6161350608,1.0919641256,-0.3321318030,0.7260578275,1.1332423687,-0.2503430545,1.1677489281,0.7886906266,0.2164149135,0.7647698522,-1.3076148033,1.1607283354,1.8137441874,2.8209869862,-1.1829620600,1.2793636322,-0.4161130786,1.4560747147,-0.8382224441,-0.2064589411,-0.3601056635,-1.9282368422,0.2948355377,0.6405059099,-0.9806084633,0.0274974220,-0.4893453717,2.7329032421,1.4204442501,0.6902386546,-0.4438398480,0.8475421071,-0.8242413998,-0.2056256086,1.2381081581,1.8283888102,-1.7836816311,0.7437072396,-0.2981782556,0.4307036698,1.2446408272,-1.5674799681,1.7146155834,-1.9383628368,0.3435726762,-1.5765607357,0.0504746065,0.8115888238,-0.3472369909,-1.1612019539,0.3186337650,-0.6062232852,-0.7585208416,-0.5607734323,0.5222164392,0.7790774703,2.6089880466,0.6626429558,-0.2798112035,1.1184885502,-0.1381485909,0.0895912275,0.7735747695,-1.2175766230,-0.2237391025,-0.1026925892,2.0417473316,0.7975260019,1.5041879416,1.0822825432,0.7253676057,-0.8952884674,-1.8488601446,0.1530598551,-1.9314616919,-1.6300439835,-0.8163452148,-0.5146376491,0.5783777237,0.0899859294,-0.2165891677,-1.5324651003,-1.3432455063,-0.5275440812,-0.6659939885,0.0604406931,-1.3241438866,-0.9218361974,-1.9925515652,0.2451740056,-0.3967302442,0.1276450008,1.2230695486,0.0030670676,-0.2247872502,-0.0633816347,1.4691959620,0.5458295345,-0.5807732344,0.9379773140,0.3422805071,1.5076049566,0.6746079326,-0.1290075630,0.5062861443,0.1298588663,1.8845261335,0.9324017167,-1.0008316040,0.1478935778,0.5123214722,-1.5427743196,-2.1174151897,0.0422072709,-0.3248087168,-0.4121863544,-1.5678561926,-0.7964280248,0.7105121613,0.2873294055,0.6519631743,0.5355852842,-0.6085993052,1.1440550089,0.9712348580,1.3347989321,0.2167384177,-1.2789026499,1.2023334503,-0.4959734082,-1.8249573708,0.3743883073,0.0709712729,0.2931367457,1.6866817474,0.1300894916,-0.1589677930,0.9902415276,0.1049473360,0.6208986640,-1.7520277500,-1.6000163555,-0.9802316427,0.0425251871,2.1325788498,-0.9563222528,-0.4039032757,-0.6859712005,-1.1440685987,2.8847551346,-1.4577374458,-1.6533602476,1.5437217951,-1.6310477257,-0.3676165342,-0.5928305984,1.3807523251,-0.5501603484,-0.5219319463,-0.0825198963,-0.3111062944,-0.7352650762,1.1713025570,-0.0221288241,0.6046815515,0.2135297805,0.1448385417,0.9258138537,0.6199473143,0.8385660052,2.1954982281,1.4447660446,-0.2872459292,0.2114256471,-1.0960211754,-0.8197528720,-0.2152145207,-0.1540306658,-1.6386111975,-2.5233354568,1.2656054497,0.9129872918,-0.6085659862,-0.6617404222,0.6074315906,-1.9679963589,0.7266260386,0.2714606822,0.1947142482,0.5195682049,0.8111485839,0.3197706044,-2.0950548649,0.5762258172,-0.8431512713,-1.2846280336,0.9035053849,-0.3686189353,0.8176126480,0.6898447871,1.2300739288,3.2548313141,0.9898021817,-0.7532128096,-0.9045040011,0.5490559936,0.8705734015,0.7328756452,-0.8265963197,-1.5101081133,0.3340276182,0.5381116867,0.6491934061,-0.1450466812,1.7645809650,-0.7833189964,-0.5206372142,-0.3905070424,1.1084893942,0.5302432775,-0.7692154050,1.2692584991,0.9881228805,-0.5279560685,-1.0720012188,-1.6803950071,-1.5877646208,1.9102419615,0.3213319182,-1.6464880705,-0.1613440216,0.3271096349,0.5641773343,-0.2901338339,-0.6286158562,1.0368025303,1.4191545248,0.3205574453,0.8432882428,-0.4522081912,1.1206735373,0.9856461883,-0.1103538498,0.3788451552,0.8254184127,-0.9615396261,-1.7476845980,0.3499236703,-0.8517538309,0.7227854729,0.9791315794,0.7726531029,0.6913672686,-2.0398874283,-1.3073374033,1.6918557882,-0.8667309284,-1.0342205763,-0.3692653477,0.5241845846,-0.4410466254,2.1805980206,0.5975066423,-0.6366894841,-1.4811692238,-0.3947469294,0.1086023152,0.1037365198,-0.5710659623,1.2462812662,1.2071619034,-0.6543464661,0.3778489232,1.4369262457,0.8684048057,0.9227760434,1.9248412848,-1.0600451231,0.5242900252,2.4939887524,-1.4329419136,0.5927869678,-0.0053195218,1.4319832325,-0.6679624915,0.1154298410,1.2070343494,0.1147793829,-0.6715605855,0.0334689096,1.6597380638,-0.9170382023,-0.5053157806,0.1027670279,1.1581686735,-0.5237666965,-0.4403850436,-1.6496279240,0.7673044205,1.1748074293,-1.4838258028,-1.6586328745,-0.6399556398,-0.5451463461,0.2890629768,-0.3449325264,0.5661980510,-0.2247092426,-0.3704339266,0.4762049317,-0.5505967736,-0.3622225821,0.8294441104,-1.0188047886,-1.3211250305,-0.5238136649,0.0719858110,0.5811215043,1.3551915884,0.9022732973,0.8348205090,1.7601321936,-1.2035567760,-0.1610284895,-0.6985741258,-0.8050824404,1.6160351038,-0.2635310590,-1.2230753899,0.0442702919,1.4457842112,-0.2831886113,-0.5522205830,1.8225749731,0.5256469846,-0.0092465924,-1.1489993334,0.7133934498,0.7125946283,0.4428358972,-0.2494825572,-0.8214784861,-0.3348659575,1.7764191628,0.3546428382,1.4700632095,1.0542569160,2.1549079418,-1.7109314203,-0.4482811987,-2.1268780231,2.0661754608,0.1601428241,-1.0449494123,-1.0156296492,0.6733638048,0.9290160537,-1.0412443876,0.3149002790,0.7868452668,0.8227619529,0.1526217610,-0.1421793401,0.6412929296,1.3321976662,1.2902623415,0.0031562971,-1.4625291824,0.2808877230,0.5652723312,1.1053085327,-1.2109456062,-0.3344887495,0.9515791535,-0.9712296724,-0.4897898436,0.5153864026,-0.5969720483,-0.2086329162,1.0944644213,0.1678696126,1.6910209656,-1.6885894537,0.8107523918,-0.1487727761,0.8241059780,2.5300707817,-1.1119675636,-0.0557166263,-0.9830359817,-0.0218584090,1.2924665213,-1.5760532618,0.2903743386,-0.0360350795,0.1165624261,0.5244975090,-0.1452632844,-0.7145482302,0.9750678539,0.4187014699,-0.1647199988,0.0827688649,2.8011438847,1.1906450987,0.5398116112,-0.6014398932,0.4039287567,0.2727628350,1.3142924309,-0.5986911058,0.3755066097,0.3850517273,0.5240681767,0.1509334147,-0.2982423306,-0.9690389037,0.1482082903,-0.5794170499,1.1058530807,-0.6659970880,0.5248563886,0.6544551253,-0.1016000733,1.7019340992,0.1335662603,-0.3516343236,0.7148193121,1.2314994335,-0.9258267283,0.0363452137,-1.1703430414,1.7012137175,0.2636000216,2.5404133797,-0.0304493718,0.4889936447,0.7376376390,-0.3831209540,1.7555421591,0.2273544669,-0.8490986824,-0.1827587038,-0.7989795804,-0.8379164338,-2.0694205761,-0.5316456556,-0.2463656515,-1.3631684780,-0.7051585317,-1.6138539314,1.3198417425,0.3702345788,0.0753858536,-0.0132740363,-0.9950203896,0.6775140762,-1.5192737579,-1.1931970119,1.0480457544,1.0526509285,-0.2511567771,-0.2708320022,-0.9000599384,-1.0730860233,-0.8332417607,0.6814241409,-1.1012221575,-0.5161744356,-1.9944025278,0.5473926663,0.2162017673,0.6118625402,1.6970700026,0.9290080667,-0.6630474329,1.9621838331,0.6916124225,-0.5143244863,1.3465787172,-0.1014270186,1.6098065376,-0.4065241218,0.2456360906,-1.0644011497,-0.6824391484,0.9376380444,-0.4972450137,-1.3954156637,-0.7931784987,0.3863891661,-0.5077642798,0.1169658527,-2.2643694878,1.2981832027,-0.0722546279,1.3718563318,-0.9511761069,1.1634547710,-2.4079461098,-0.2811202109,-1.4747558832,-0.7960328460,1.6813354492,0.1580020636,0.4906089008,-0.6557968259,0.1914050281,0.8196141720,-0.5575736165,-0.1627945155,0.2597014308,-0.4878998101,-1.5364331007,0.8920765519,0.1526391953,0.2662674487,-1.8847845793,0.3603782356,-1.0658118725,3.2456190586,0.2545815408,-0.0740487799,1.0587692261,0.4594543278,-1.2144246101,0.8521980643,0.1920867115,-0.6966613531,0.9356654286,1.4123430252,1.9032716751,-1.1575750113,1.2239912748,-1.3523010015,1.3675932884,0.0028783996,-0.1164716333,0.0636274517,-0.1263964623,0.6503781676,0.4069949985,1.0436509848,-1.4743063450,0.1385995448,0.1789027303,0.0112371799,0.2460647076,-1.1011744738,-0.5300943255,-1.6115192175,-1.9061876535,-2.5654923916,0.0496643037,1.0157072544,-0.2320692241,-0.2537081838,-1.9836074114,-1.2122704983,-0.8500339389,0.1666402519,-0.5580587983,-0.7058231831,-0.6347995400,0.2047363073,0.2284586877,-1.1299531460,0.7173625231,1.1171007156,1.0772426128,0.0177433770,-1.2954846621,-0.5299506783,-0.5749281049,0.5966389179,2.7219719887,0.6849224567,0.8479590416,2.0062556267,-0.0862625539,0.9452161789,0.8045234680,-0.3388015628,-0.2429846227,0.6233448982,1.2148296833,0.1562897563,-0.3656148314,0.1104548946,0.9932194352,0.5684428215,-0.9437820315,1.0924483538,-1.5989911556,-2.0403063297,0.8947772384,0.3354680538,-0.8832319379,-0.9793969989,1.6826566458,-1.0103543997,-1.2948708534,0.0603040457,-0.3768114746,0.6062066555,1.3397293091,0.4506835639,0.4326622188,-0.4533344805,-0.3971926570,-0.6595103741,-2.4956014156,1.7504210472,1.3513900042,-0.6080017090,-1.0249046087,-0.1988066733,2.1393291950,-1.8256448507,1.2898792028,-0.9707172513,-0.6307196617,-0.3292931020,-1.3354488611,0.3118260503,1.2624188662,-0.3525214195,0.0506781153,1.5740100145,0.9165746570,-0.3342539668,-0.2621529996,-1.2329554558,-1.5453443527,2.1995866299,0.6019462943,-0.3987810612,0.5707879066,-0.4209889472,-0.0048142010,-0.0332821496,-1.5761977434,-2.1236410141,0.4128189087,-1.1925446987,0.4046672285,-0.3922690153,0.9129861593,-1.2042829990,-2.5270962715,1.1464778185,-1.0409102440,-0.2294565439,-0.1564095914,0.2098131180,0.4423882961,0.6708213687,0.0011970691,1.3835297823,-2.1146876812,0.4195026755,-0.5974859595,-0.7789434195,-1.1835699081,-0.4481227994,-0.5926176906,-0.5601764917,-0.2906090021,-0.0740258768,-0.4800468087,-1.0527486801,-0.7800763845,0.3000288010,-0.3290872574,0.9112530947,0.1389426142,1.1165764332,1.5068144798,0.5325995684,0.4274400175,1.1449474096,0.7173746228,1.2336890697,0.6168799400,-0.5105078816,-0.4883999825,0.2610085905,-1.3890395164,-0.2097653002,0.1856197417,-0.8605422974,-0.3273102641,0.2982771695,-0.0288848169,-0.9086425304,0.3567273021,-0.5856960416,0.7619949579,-1.1993529797,-0.4374361038,-0.0871637315,-0.8370314240,0.2818605304,1.3145585060,-1.1522951126,-0.1624574959,2.4466850758,-0.2131539136,-0.3643190265,1.1231597662,-1.4967659712,-1.3696490526,2.5906090736,-0.8502928019,-0.0154352458,0.0708632097,-0.0892392695,0.9884635806,-1.4502840042,1.9888542891,0.0451550037,0.2025863230,-0.3004295826,-0.0864960775,0.2483033687,-0.1879534423,-0.3177562356,-0.5728502870,-1.3048775196,-0.5676960945,0.9221876264,1.3602030277,0.2550102472,0.5108075738,0.6118447185,-1.2540539503,0.7811601758,0.1337841600,-0.5227097869,0.6001027226,-0.5171794891,-0.4444061518,-0.9055517316,0.3879831135,-0.3776228130,-1.8549275398,-0.4994918406,-0.5876417756,-1.6503987312,-0.2694072723,0.9541515112,-1.4059816599,0.6579794884,0.8008347750,0.8226274252,-1.1246813536,-0.0056366222,0.5829159617,-1.5171155930,-0.2439792901,0.2839211524,-0.7109612823,-0.7272608280,1.2907973528,-2.4604752064,0.2687241733,-1.1931895018,0.1179150194,-0.2157852799,-0.2656730711,-0.8884975314,0.7275415659,0.2283545136,1.6116662025,0.7428886294,-0.0892703235,-0.0904256403,-0.1552596092,0.4787852466,1.3613634109,0.1748903543,-1.6370717287,1.0790226460,-0.1739098728,-1.0114746094,1.4560087919,-1.9859833717,1.3460286856,0.1526861787,-0.4367708862,-0.4582619667,0.9152957201,2.7462913990,0.1391252726,0.7504043579,0.7596225739,0.5596187115,-0.0583412908,1.6963244677,-0.3965150118,0.1869936138,1.8145555258,-1.3269416094,-2.2988479137,-0.5298420191,-0.8341919184,-0.8106333017,-2.5397062302,-0.0860494003,0.4506426752,-1.2943652868,1.0642453432,0.9367136955,-0.1269537657,0.5206781626,-1.1788055897,-0.0925211310,1.0476361513,-1.2335727215,-0.2922436893,0.0496872887,-0.2639459372,0.3845275939,-0.1538703591,-0.1169964671,0.1776241362,0.6594055295,-0.5636582971,-0.9561285377,0.4923869669,0.2409788370,1.6332099438,1.9169098139,1.1394318342,-2.5501418114,-0.3268522024,0.9455291033,-2.0710549355,-0.1209253818,-0.9449245334,1.5542948246,-0.2254855931,0.5607367754,-0.4980247319,1.2718555927,-0.9843304157,-1.6917517185,0.3631607592,0.2028281391,0.0599766299,-0.0586545616,1.1578779221,-0.1312680691,-1.6256289482,-1.0176999569,-0.1003823131,-1.0121793747,-0.4727144837,-0.5200366974,-0.2728419602,-0.4269649386,0.7875617146,0.9885934591,-0.4017859101,-0.0173298735,0.6428719163,0.4834312797,-0.2587702572,-1.1848987341,1.4192327261,0.1049401015,-0.3738996387,0.7806690931,-0.6665983796,0.0297318734,1.0643459558,-0.3537979722,-1.3078233004,0.7726968527,2.1866788864,-1.1002861261,0.1728644818,-0.3756933510,-0.9906257391,-0.8670617938,0.2038979679,-0.4590037465,-0.9317319393,0.1539378166,1.7603360415,-0.7288731337,-1.2079353333,-1.7485420704,-0.2674083114,-0.7923513055,0.8678576946,-0.8161421418,-0.5595346093,0.5180754662,-0.5601761937,1.9338699579,-0.2529518902,-1.1536580324,0.8240326643,-0.2938970327,-1.0393499136,0.0384243019,-0.1298382133,0.6317511797,0.9699698091,-1.2614362240,-0.3775847554,-0.3486490548,0.2697852552,0.7138586640,0.1024048105,-2.2221372128,0.0392785184,0.5322803855,-0.3420674801,-0.3462099135,1.7591598034,1.8691898584,-0.1903523058,-0.5461303592,-1.8728995323,-0.3152549863,-0.1878576875,-0.8418833017,0.4303056002,-0.0654961094,0.3263684511,0.5223084092,-1.4092383385,-2.7141454220,-0.6595085263,-0.6816119552,-0.3690533638,-0.3258565962,-0.6590272784,-1.3374688625,0.2712288499,-0.5335494280,0.3359538317,-0.5624163747,-1.7754486799,-1.3497921228,1.7255154848,2.0891745090,-0.1147161946,-0.4825686216,0.1295297593,0.3011428714,0.9685909748,-2.6775097847,2.0935235023,0.5985561609,-0.5186195374,1.1494662762,0.0178137068,-1.7103466988,0.0695706159,-0.4838339686,-0.6910316944,-0.3891272545,0.4077689052,0.1103762239,0.3082531989,1.6875544786,-0.8012143373,-1.2962436676,-1.1299370527,0.8236520886,-0.2105285227,-0.0350589901,-0.1153961793,-1.2768372297,-0.4285729825,1.0847262144,0.7416942716,-0.3530087173,-3.1282429695,-0.9469532371,-0.6899254918,0.8435842395,-0.2861720920,-0.3562988639,0.2356502563,-0.5722347498,0.5325630903,0.2162115574,-0.2787752151,1.9393185377,0.2387497127,-1.0231500864,-0.1833423823,-1.3151319027,-1.1783853769,-0.8859948516,1.2054790258,-0.5636700988,0.4386736155,-0.6196897626,0.8047269583,0.1394855082,1.4760224819,-0.7151355743,-0.3518398702,-0.6956925392,0.4250043929,0.1587561816,-0.8085920811,0.9429353476,-0.4326693714,0.8953675032,0.9709054232,-0.9297704697,-0.1016962975,-1.1935923100,-0.9966936111,0.2610221803,0.0391289629,0.8596969247,-1.1022953987,-1.3328871727,-0.3936585784,0.3379068673,0.3390775621,1.8913849592,0.1280214936,-0.1877435148,0.7314977646,0.8108587861,0.2118465602,0.5429373384,0.2095481604,0.0367294289,1.3247373104,1.1130683422,-1.1776549816,-0.1899321526,0.9921732545,1.9340195656,-0.7474932075,0.5622502565,0.2565377355,-0.5058898926,-1.1801614761,1.1046266556,-0.2420715690,1.0296734571,-0.4392384887,-1.2390613556,-0.6452093124,-0.3723985553,-0.0273250490,-0.8667244315,1.2947559357,0.6697645187,0.8879160285,0.1957534999,-0.1988423914,1.2720395327,0.2759205401,1.7492319345,-0.2943438888,1.1912611723,-0.0809823349,0.0359159783,-0.4873678982,2.9271998405,-1.1786690950,1.0902714729,-1.0070717335,-0.0559710450,0.5503617525,-0.2708517611,-1.4462407827,-0.0244226474,-0.9263724089,0.3695653975,-1.0758725405,-1.0543339252,1.0808296204,-1.3966062069,2.2895793915,1.8400338888,-0.5700233579,-1.0836747885,0.7417201400,-0.2145137787,0.5379716158,0.3843903542,0.0347256139,0.3680998087,0.3415450454,1.0920809507,1.0413075686,0.0939790681,0.7268617153,-1.1950058937,0.4225138724,0.7281823754,-2.2234709263,1.2858834267,-0.9244327545,1.6425834894,-0.8119661808,3.3916356564,-0.2394975424,-1.2916408777,-1.2434978485,0.1182641983,-1.0540636778,1.0878865719,1.0936306715,2.7451908588,-2.4534094334,0.0842225254,-0.7882358432,-0.2610311210,-0.1405747086,-1.2278044224,0.4670206010,-1.5480242968,-1.0367826223,0.1100453958,-1.6257070303,-0.6632278562,1.6480108500,-0.3857504129,1.3263442516,-0.7813788652,-0.2630614638,2.2347497940,0.0668686181,1.6011503935,-0.2215524614,2.5348920822,0.6628156900,0.6786739826,1.7699764967,-1.7675346136,2.8429641724,1.7460889816,0.1622756273,-1.2240581512,0.9790400863,-0.4723766446,-1.2521955967,0.1068915650,0.2467359900,0.4016210437,-0.4117667079,-0.4852364361,-0.0951911286,0.6827812195,-0.2690612674,0.6709222794,-0.4353961647,0.8948027492,-1.9490350485,-1.0914882421,-0.3209503293,-0.2963206768,0.4339114130,-2.2697405815,1.2201591730,-1.8413844109,-0.3661860824,0.7219944000,-0.9503106475,0.6586489081,0.0980350003,1.0423717499,-0.4973531961,-0.5744463801,-1.3544663191,2.0338106155,0.0617796816,0.5912122130,-0.7075412273,0.0460111462,1.2361793518,1.7257440090,0.7506306171,0.5277210474,0.6417139173,0.3805473745,-0.9311766624,0.9438769221,-0.8593149185,-1.7188237906,-1.4166681767,0.7779759169,1.1453680992,0.2659092546,-0.7271529436,0.1307234317,0.7076218128,-0.6337662339,0.8103998899,-0.7279103398,0.2717936635,0.5227202773,-0.8961473107,-0.1444521397,-0.7144158483,-1.4684110880,-1.8797703981,1.4193205833,0.2078864872,0.7992144823,0.0320600830,0.8656871319,1.2021867037,-1.2167718410,0.8329434395,0.1805313081,0.3732955158,-0.6465490460,-0.9415496588,1.2734313011,-0.8172774911,-0.9249973297,0.1996483356,0.4317770898,-1.0799595118,1.4785776138,-0.0096156178,-0.8270172477,-1.0379046202,0.2136165649,1.1392287016,1.2750461102,-0.8241134882,-0.2134141624,1.7874548435,1.2697911263,-0.7215440869,-1.2200564146,0.7094538212,0.2863227427,-0.0210470576,0.3863923252,-0.3042067885,1.0375249386,0.6831886172,-0.8644843698,-0.3198086619,0.4823707640,-0.2265983522,-0.4702896476,-0.5963839889,0.9628387094,-0.3546466827,-1.3467926979,1.0188089609,-0.8363088369,-0.0953657553,-1.3766548634,0.5656586289,-0.4472826719,-0.6763988733,0.9349191189,-0.8283550143,0.5968904495,-0.5544840693,-0.1959493458,0.0332162529,0.4148295224,0.0375486575,-1.0577303171,-0.9384614229,-2.0667753220,0.4751504958,1.0487740040,1.3003197908,0.3228363395,0.2529530525,-1.1515924931,-1.2190105915,-0.9456254244,-1.1880462170,2.6874439716,-0.3045670986,-0.7014102340,1.5996931791,0.3379813731,0.9407749772,1.1743144989,0.9814895988,-0.3301385045,0.7717459202,-0.2328396291,0.9203398228,-1.0166190863,0.0462331660,0.0152617535,-0.0070052808,-0.6647570729,0.5429480076,-0.5906264186,-0.0308912378,1.0884922743,-0.0040217643,-1.1533929110,-0.1063377857,-1.0902687311,-0.0371520258,-1.8188394308,-0.7905772328,0.1596994698,1.1226239204,-0.6813367605,-0.1751530617,-0.0979226381,-0.8810763955,1.1648347378,1.3413946629,1.1284626722,0.5128263235,0.0187418163,-2.0666255951,1.0853357315,1.0145881176,0.6455498338,0.3209685683,0.5687319636,1.0641225576,1.4271905422,-1.3905673027,-0.9891104698,0.0020802424,2.3130781651,0.6045076251,-0.8978734016,-0.3523695469,-0.9741426110,0.3125937879,-0.1361470819,0.7558745146,-0.6038464308,2.2138009071,0.2676672935,0.4894275367,-0.1646461040,0.2514430285,-1.4151527882,-0.1414795518,0.3838063478,-0.8808335662,1.9905422926,-0.3512460887,-1.5725287199,0.7633091211,0.0000131410,1.6761398315,-2.1059546471,-0.3404865861,-0.5632696152,-1.5203379393,-0.5280867219,-0.7296812534,0.6876379251,1.4581366777,-1.1583836079,0.6405873895,-1.0695174932,-0.1391310841,0.7101902962,-1.3572121859,0.1433014721,0.6498459578,-0.2396032214,0.4949466884,-0.0583442226,1.3597508669,-1.1603624821,0.9705311656,2.1088654995,-1.7841472626,-1.5925489664,0.4765196443,0.7140438557,-0.2969127893,-1.0004702806,-1.4487510920,2.0203588009,-0.4833310246,-2.3372316360,-0.5886305571,1.6995788813,0.0083491514,-1.0568113327,-0.1681756973,0.7782428265,0.6581347585,0.0151447775,-1.6557891369,0.8034425974,-1.0629384518,0.7985153794,2.1845128536,0.5347851515,1.6842222214,-0.6536903381,0.9090065956,-0.6756687164,1.9171681404,-0.0657464713,1.3801714182,-0.5541518927,0.2358659059,-0.1883283705,1.0601769686,-0.2588506639,0.4196306467,-1.2001607418,0.5803898573,-1.4160250425,1.7342479229,-1.1105753183,0.0719698370,-0.0096054645,-0.6200602651,0.1690012068,1.2434685230,1.4427556992,-0.1093287393,0.1923421919,1.8308950663,-0.6960420012,0.1550203562,1.0692973137,0.2098853588,-0.3324133456,-1.2730194330,0.6015979052,0.6712191701,0.2805779576,-0.5934511423,0.9138393998,0.0384552255,-0.0258487891,-0.8879203200,1.0867121220,-0.2558456957,1.3400003910,0.8616962433,0.9091723561,0.3765018284,-0.0544774011,-1.1591389179,-0.1942774951,0.9726710916,-0.9714103937,1.3434149027,-1.1338416338,-0.7891272902,-1.9806178808,1.4280047417,-0.3443213403,1.2054544687,0.9668977261,-0.4083234668,-1.2918647528,-0.6399744153,-1.3426039219,-0.5441907644,-0.0543023236,0.1115766466,-0.4973062575,0.0533691123,-1.0189346075,0.0490081087,2.0632190704,0.9324282408,1.4523895979,0.5729588866,-0.4189784825,-0.3286801577,-1.1514205933,-0.8807796240,0.2938400507,0.7655924559,2.1366088390,0.0733786449,-1.6295683384,0.1775692850,0.8521859646,0.4896481931,0.5674389005,0.2375758439,0.0813688114,-0.6042775512,-0.5440589786,-1.2309296131,-1.4950492382,1.4114691019,0.4880595207,-1.9063181877,0.3281845450,-0.3974549770,0.2618822157,0.7912273407,-1.7842062712,1.4989305735,-0.2391272038,3.0528898239,0.3499550223,-1.4347679615,1.0079482794,0.4206511974,0.6000564694,0.1201554537,-0.5846073031,0.3514090776,-0.8588541150,-1.0708264112,1.9690668583,-0.0061912374,-0.7901587486,0.9585415125,1.9639558792,-0.4290848672,0.5445072651,1.2167263031,1.4984652996,-0.3440700471,0.3850102127,1.1216851473,0.6268048882,-2.3510096073,-1.3539459705,-0.0425043851,1.0418293476,-0.2806175649,0.4425379932,-1.3477407694,-0.9427426457,-0.0101525290,0.9552149773,0.2844652534,-0.0253380742,0.4472802281,-1.0420781374,1.8255304098,-0.1858208627,-0.9919012189,0.4774014056,-0.1065087095,0.5237557292,0.1012536585,0.4370443225,0.4235878587,0.6120776534,0.6691703200,1.0026834011,-0.3116049469,-0.0213360675,1.8255027533,-0.4455459118,-0.0459221825,-0.7012569904,-0.1852261573,0.5536851883,2.1449239254,-0.1896124780,-0.3305495679,-1.0523796082,0.5392750502,0.7831043005,0.3730578721,-0.1366892159,-1.0765298605,-0.4404587150,0.9915053844,-0.0562079400,-2.5473208427,1.1598278284,-0.7649890184,1.2011524439,-0.0606509931,-0.0063281334,-0.7450198531,0.6501030326,0.2470915914,0.3507081568,-0.8862549663,-0.6400193572,0.8826782107,1.1692306995,1.7553559542,-1.0607961416,0.6163920164,0.2505285740,1.2890933752,-0.5036508441,-0.5445509553,1.3842186928,0.3668037355,0.2400822192,0.4661004543,0.4137141705,-1.2596691847,-0.8630129099,-0.2596816719,-1.3117531538,2.5076625347,0.8216830492,-0.8308066130,-0.2402574420,-0.3923582733,0.2755875885,-0.8734244704,0.0743628964,0.1546310931,-0.0208904427,1.4379118681,1.2219953537,0.2602660060,1.0976809263,-0.0790601820,1.4060403109,-1.7074382305,0.1989279836,0.7320793867,1.0455595255,0.8985303640,0.5794932842,0.7482882142,1.0181425810,-2.1934535503,-0.1195093766,-0.5527552962,0.9271039963,0.0382056795,1.3007956743,0.2055685967,1.7423490286,-0.0785754547,-0.0049815332,-0.0163416192,-0.4962151647,0.1003125310,-0.8750685453,1.3657735586,-0.3143217564,0.1486933380,-0.6111947298,1.1490167379,-0.5325989127,0.0778353959,-0.8201375008,0.9185136557,0.3281737566,-2.0297646523,1.1189615726,1.0363020897,-0.2897744775,0.3120375574,0.7430668473,-0.1351819932,0.2756820321,0.2833786309,0.1408464015,-0.7921109796,1.6592693329,0.8912046552,-0.2330278158,-0.7310743332,-0.6375401616,0.7888815999,-0.5637577176,1.5878105164,0.5654777884,-0.7989003062,0.6526470780,-0.5024884939,-1.4605481625,0.6715288162,1.0051063299,-2.2796263695,-0.0421458483,0.5515695214,-1.6218701601,1.2987296581,0.1798663735,-0.5212946534,0.5497487783,-0.9817274809,-0.7634006143,-0.4252837300,-1.6081527472,-0.5749193430,-0.0845824331,0.3179959953,-0.8117060661,-1.2607413530,-1.7419383526,-0.8477881551,-0.7736322880,0.0881378502,2.0652372837,-0.6772291064,-0.2555656135,-0.1456658989,1.2135969400,0.6333103180,0.6250420213,-0.5774396062,0.2879560590,0.8352848291,0.4350744784,-0.3484890163,0.0795898214,0.8474707603,-0.1157193184,0.4633275568,-0.3415514231,-0.6989926100,0.6122351885,-0.8388199210,-0.7292807698,-1.0647550821,0.4956947267,0.1355170608,1.2068425417,0.2432746291,-0.2817509770,0.2291960120,-2.0235092640,1.2210216522,1.1453696489,-1.3078383207,0.5784826875,-0.1166832522,0.4518258870,1.1240378618,-1.8123457432,0.6662940979,-0.9611188173,0.7314282060,-0.2969223261,-0.3550669253,1.4163671732,-0.9020425677,0.0199772660,-1.1304079294,0.1079952568,0.4287727475,-1.6183984280,0.6845467091,2.8033049107,-0.2084693313,0.1491068602,0.2246538848,-1.1328402758,1.1970536709,-1.1747390032,0.6738021374,2.5621573925,-0.6892337203,-1.5325818062,-0.8725388050,-1.8731801510,-0.8512567282,1.2584059238,0.6210688353,1.8926613331,0.5126205683,0.7967803478,-0.4531759024,0.6966472268,-0.9069048762,0.0096370932,-0.6075945497,-0.7283154726,0.5826425552,0.2152446657,-1.2975306511,-0.5846914649,-0.4268600941,-1.0764298439,-0.7263673544,0.9428517222,-2.0351703167,1.5888681412,1.1721462011,-0.7234143615,-0.6291493773,2.0337893963,0.2800778449,0.0618867502,-1.0652469397,-0.1269562542,0.0394340493,-0.2710518539,1.1494917870,0.7313186526,1.4539731741,0.4317398369,0.1555168629,-0.6679779291,-0.6185320616,-0.4576709569,0.8619299531,-0.3402082324,-0.0162530318,-0.9234033823,1.1426278353,-0.4658351541,0.4760331213,0.1220721081,-0.0449118540,-0.7347796559,0.4099939167,-0.4844644368,0.8656507134,-0.0493310839,-1.6068956852,0.6101850271,0.3961558640,-0.5334519148,-1.2353732586,-2.1528379917,-0.6461086869,-0.7687655091,1.0920033455,-0.0443054624,0.9873304367,0.1205482185,-0.0901331529,0.2483174056,-0.0232608952,-0.9315232038,-0.4337712228,-0.7576855421,-1.4757883549,0.4191368818,1.0992763042,-0.5225518942,-0.3033358455,1.4686160088,0.2693915963,-0.5548349023,-0.0744934976,-0.9019102454,-0.4306880832,-0.4611977935,-0.8646348715,-0.9281977415,-0.2186366916,-0.7222694755,-0.5996643305,-0.7126638293,0.9143796563,-0.1718460768,-0.7571513057,-0.8897672892,-0.2077621669,0.3679377139,-0.6376763582,0.6803770065,0.1529729366,1.6237425804,-0.7013158798,-0.7598114014,2.4127118587,-0.0613814630,0.5617071986,-0.4261292517,1.3765552044,-0.1034885272,-1.5822913647,0.2727092505,-0.4394279420,0.0855139270,0.5925198197,0.9543700218,-1.3967151642,1.0356595516,1.2689288855,-0.0545611903,0.2998319864,0.2138415426,-1.5542737246,-0.5578077435,-0.0780339167,-0.7181679010,0.4998109639,-1.1115146875,-1.6112943888,1.5544286966,0.7367937565,-1.1129119396,0.7780324817,0.4822565317,-0.8536413908,0.4397369325,-1.3432642221,-0.9365406632,-1.2382225990,-1.2970274687,-0.6214320660,-0.4893566370,0.1583636999,-0.2710636258,-0.1458918750,0.6112800837,0.6005087495,-0.7187950611,0.8169072270,1.6199951172,-0.7268152833,0.2404350340,0.2810488343,-0.4852738678,0.9925027490,0.0956963748,-2.8951740265,-0.3318829834,1.3719614744,0.5818605423,-2.0010683537,-0.4226765037,1.0245097876,0.7852441072,-0.4349224865,1.4291239977,-0.4860503674,0.3763881922,-0.4843531251,-0.3523619175,0.7469093204,0.6595010161,-0.3882180452,0.9919152856,-0.2797157764,2.4180109501,0.0411199592,-1.8055504560,0.5286077261,0.1346055269,0.3227880299,-0.3051802516,-0.3027456105,-0.0010736089,0.4762355387,2.2697131634,-0.3243034482,0.1008412465,-1.4537488222,-2.0363309383,2.1591031551,1.5303931236,-0.7778717875,0.2341108471,1.3119387627,1.3180574179,-0.8847883344,0.5251903534,0.2385541797,-0.3019807041,1.0521885157,0.0388435014,-0.1639668941,1.7076059580,-0.6597477198,1.3579747677,-0.7429273129,-0.0546745248,-0.1375604272,-0.9347351789,-1.1826816797,2.0394957066,-0.4085650742,0.4151297510,-2.3462462425,-0.3660867512,0.2620778680,0.4003766775,-0.0485555828,0.8496025205,-0.8509175181,-1.4193309546,0.8738920689,-1.3105102777,-0.1310589164,-0.0740571916,0.1930714250,-0.9857059717,-1.6849098206,0.4512572885,0.1277438253,0.3671044409,-0.1350663900,-1.0645258427,-0.0029378785,-0.0521377474,-0.0649472773,-0.6643292904,0.5142106414,-1.7635880709,1.6859691143,-1.0984498262,-0.7941613793,1.1221563816,1.3669830561,-0.0905384943,0.2765818536,0.6256956458,-0.3617914617,-0.2852146924,0.7979028225,0.2126920968,0.8998239636,2.2797007561,0.2099189162,-0.3656977713,1.4928067923,-0.4475935102,-0.4616768956,0.2791537642,0.2556216717,-0.6943846345,0.4273623228,0.1741427183,0.1316052079,1.1936930418,1.5984715223,1.0562391281,1.0298056602,-1.2818797827,-0.8192679286,-1.9437376261,0.6600036025,0.0188401472,0.4665989578,1.4290597439,0.7851303220,0.2261232734,0.7731981277,0.5813441277,0.5581420064,1.3034487963,1.0300573111,2.0724573135,-0.7095886469,-0.8896782398,0.1834590137,0.6919991374,-1.0479919910,-0.9896458387,-0.2847566903,0.7601591349,0.5769826174,1.3861632347,-1.7981691360,0.5600209832,0.1504398137,0.6467001438,-0.3333204985,0.2885289490,-1.5847134590,-0.6807080507,-0.4037251472,-2.4674272537,0.1292898357,-0.1086133048,-0.3344806433,-0.4761407077,-0.4093746841,0.8121746182,0.9868445396,-0.4382044971,-0.7254872918,-2.4136452675,-0.3176845610,1.9473218918,0.2170838863,0.2626359165,0.1446496695,2.9867980480,-1.6840299368,1.3493431807,-0.6842327714,0.2324342579,0.8585680127,-0.6588760614,-0.3588640988,-0.3767255545,-0.5748527646,0.2612748146,0.1919667572,0.9821797609,0.4179340303,-2.2200431824,0.2395582497,-1.1190239191,0.7308257818,-1.2480312586,0.7303984165,-0.6898256540,0.3308303952,-0.6568310857,-1.0560706854,0.3887234926,0.5087570548,0.7185772061,-0.2959088087,-0.2250892967,0.4436039627,0.7100724578,-0.3117805421,-0.7210696340,1.4668381214,-0.6216652989,0.4426654875,0.4567816257,-0.8505325913,0.8974496722,0.8174543977,0.4282577932,0.8738188148,-0.3808510900,-0.5091495514,2.3714761734,0.1522615403,-1.2650282383,1.3257935047,-1.4895132780,2.3313984871,-1.2792991400,0.7764997482,-0.7210823894,-0.1681635827,0.1529988945,0.4695449471,0.1967510283,0.2921490669,1.3127886057,-1.2193900347,0.2852847874,-1.2616995573,-0.7584261894,-0.1306209564,0.9959502816,-0.8483362198,-0.6962991357,0.3551653624,-0.2280855030,-0.7159309983,-0.3786600828,-0.4753340483,-0.1977416724,-0.9485037327,0.3293333650,1.2257366180,-0.1455384195,-1.4984012842,-0.1919256151,2.1786687374,-1.0019141436,1.0610024929,0.6823122501,0.0800496340,0.9403626323,0.5023782253,0.3214206100,1.6189458370,-0.1983540952,1.7617611885,1.1387735605,-0.8849478364,-0.8603631854,0.5942631960,1.4637345076,-1.2320071459,1.5357743502,-2.1328830719,1.7089049816,1.1534118652,-0.0069381776,1.1776837111,-1.5097141266,0.2115106434,-0.1186552644,0.1261516213,-0.3330809772,-0.1185161993,1.1600736380,0.3577325046,0.7345383763,0.7769987583,0.7655192018,1.6940709352,0.6339361072,1.0973848104,0.4087703526,-1.7375053167,-1.0483746529,-0.4302817583,1.5430914164,0.0006288328,-1.2928329706,0.3590690494,-0.3027823269,-0.9697774649,-1.5566012859,0.5141104460,1.1575758457,-1.1170324087,0.0305965990,-0.1459143758,-0.7981154919,0.4145491421,1.4571155310,-1.3967839479,-0.0655855462,-1.0104351044,-1.1136292219,-0.1907861084,-1.8058137894,-0.2570574582,-0.6587927938,-1.3274798393,-0.1549696177,0.2305874527,-2.0742232800,-0.0295557063,1.3538379669,0.3438618183,-0.2380728573,-0.2246685326,1.5747584105,0.6863652468,1.3693779707,-1.2951009274,1.3435353041,2.0449006557,-1.6192568541,1.7248616219,-0.1750580519,0.3598082364,-0.8229542971,-0.9378738403,0.1098855510,-1.0314471722,0.0641856417,0.6701291800,1.5685896873,-1.6793966293,0.4545374811,-0.0591463894,-0.0386027545,0.1191953644,-1.2499835491,0.9295192957,-0.5419933200,0.1619770080,0.1354142129,1.5632513762,-0.3869238198,1.2132548094,0.0554801188,-0.6512631774,-2.6216135025,-0.2254151106,0.4330559969,-0.5367842317,-0.8901445866,-0.8257043958,0.5760731697,-1.5437245369,-0.7159849405,-0.9570081830,-1.3737111092,1.6673197746,1.3580203056,0.2791488171,1.0237982273,0.9078584313,-0.8839287162,0.0231411308,-0.3945089281,-0.2564010918,-0.5195775628,2.2790925503,-0.9839748740,-0.1140683740,0.7237284184,0.1794247627,0.9464429617,-0.4277381003,2.1282601357,0.0217097141,-1.7380595207,1.3669571877,-0.2642624676,1.5720680952,-1.8166810274,0.5242646933,-0.8335030079,-2.0098788738,-0.6536083221,0.2945873141,-1.4782997370,-0.1516771913,1.1408663988,-1.4657688141,-0.3113844097,0.7662166953,-0.4563453794,-2.4438807964,-1.4533135891,-0.4236075282,0.5318500400,-1.8602722883,-0.6261865497,2.0996797085,-0.8635161519,-1.2204080820,0.4388450384,-2.0069413185,0.2024406493,-0.8838145733,0.0309155099,0.7476049662,0.8999215364,-0.8639245033,0.0988463908,-0.6415423751,-0.6678134799,-0.0940411165,-1.7194350958,-0.4066540897,-0.4778663814,-2.6078004837,-0.9008126259,-0.2668288946,0.7076120973,1.3418669701,0.4082632065,-0.4423490763,2.5291156769,-0.0829270333,-0.9171121716,-0.7369276285,-1.6547844410,0.3231929243,-1.0614206791,0.3161898851,-0.3398891389,-0.0626130924,-0.9866225123,1.2956130505,-1.7446339130,1.8742061853,-0.0142730968,-0.3598657548,-0.6989034414,1.3945087194,-0.0364240184,-0.6663540006,-1.7180625200,-1.2895328999,-1.8650425673,-0.2848217785,-0.6872664690,0.6471204162,1.3397916555,0.3441358507,-0.6507552266,-0.0044669984,-0.5204245448,0.3537707329,0.6218783259,0.8653511405,-1.9395599365,-0.3520051837,-0.3968527317,-0.1872099787,2.5866026878,1.3923414946,0.4628205299,0.0473618843,1.5894398689,1.1269013882,0.3289514780,0.0482734181,-0.6642089486,1.3771688938,-0.0996530503,0.3009798527,1.1523993015,-1.0771466494,0.8700125813,-1.5626024008,-0.1853292584,-0.4131501615,0.3208904266,0.7904941440,0.1825299263,0.0197186228,-1.1914066076,-0.9240799546,0.8452393413,-0.1513461173,-1.2526690960,0.1262753606,-1.6897244453,-0.4013103247,1.9904233217,-1.3785617352,-0.0342551842,1.2655111551,0.2004050314,-0.4384508431,-0.9500871301,-1.6665233374,-0.7320570350,1.6763832569,1.4295755625,-0.2407578230,0.8036060333,-1.8491408825,2.9870183468,-0.6388540268,-1.8830124140,-1.6932355165,2.1526920795,0.1216804460,-1.4847382307,0.1124377400,-0.0760384947,1.3658516407,1.2392852306,0.0693709552,0.2876286805,0.0789157599,-0.8022515178,-0.2305098027,1.9006695747,0.9412038922,0.3962628841,0.6482299566,-0.8974066377,-0.4834775031,1.2487920523,1.1562736034,0.6536567807,-0.3170304596,0.2463564575,2.4179408550,-0.4878221750,0.8989579082,0.4149280190,-0.3923274279,1.2863267660,0.7034213543,-0.7199124694,-0.4644466341,1.4654096365,0.3432749510,-0.9306016564,-0.7491942048,-0.1750261039,-0.7223092318,0.1536332071,-0.3865046799,0.5169742107,-0.4115245044,1.6728409529,1.1052545309,0.2504644990,0.6183803678,0.1082001925,-0.6866397858,-0.1700413972,0.4843541086,1.3254795074,0.1514006704,-0.2798740566,0.4530131221,-0.1875061393,-1.5138655901,0.2696782053,0.3310975432,-1.5183287859,-0.4288371205,-1.0433771610,0.3195703924,0.2241828144,-1.7004652023,0.8005896211,-1.3455075026,-0.7087361217,-1.0131795406,0.4448340237,0.8383929729,0.7657484412,-1.0465499163,1.9463306665,1.6850688457,1.6361572742,-0.4113813639,0.8208792210,-1.3112231493,-0.4735149145,-0.9699966908,0.8628758788,0.9517716169,-0.9734086990,-0.6572603583,0.5387002826,-0.2033254206,0.6137370467,1.5639606714,0.3512731194,0.2677857578,0.1491088122,-0.6859575510,-0.1748508811,0.0057693808,1.2078301907,-0.2483086884,-1.5793319941,-0.1355962008,0.5014082789,-1.3090702295,-0.9902474880,0.1836945713,0.3580158055,0.1922743022,0.0095682470,-0.2284177840,-0.5888280869,-0.9356576204,0.5763784647,-1.0042114258,-0.3705872595,-0.2505876124,-0.7080980539,0.1050026119,1.1257755756,-0.4953170419,0.9546896219,-0.6923274398,0.3183096647,-0.5688853264,-0.6310497522,0.2750060260,0.0254878420,0.2571436465,0.5700058937,-1.7250375748,-1.4157315493,-1.4600043297,-0.8703076243,0.0653536320,1.1396144629,1.4283490181,-0.6810770035,0.5877169967,0.1974487454,0.0439355373,-0.5478091240,-0.8501861095,-0.1452676207,-2.0167658329,-0.1970911473,0.0701859370,0.7894083858,-1.7675129175,1.2736612558,1.4884271622,0.5635340214,0.6796386242,1.2423328161,0.0540213957,1.3500727415,-0.2239092141,1.4953960180,0.2478047758,0.5561262965,0.2338157147,-0.1017286703,-0.3675415218,-1.7073664665,1.6565083265,1.6814539433,-0.0360563397,0.4497372806,0.0980281234,1.4531240463,-0.6414846778,0.1412290037,-1.0449951887,-0.4438725412,0.9779627919,0.7688708305,-0.5568965077,-0.9761307836,0.7911739945,1.4035484791,-0.5847625732,-1.4764374495,-1.2948927879,0.7119658589,-0.8156015277,-0.2008070648,0.8081845641,1.5236290693,-0.3609860241,-1.0343962908,1.7678860426,-1.1862468719,-1.7334928513,-0.8210963607,0.3756120205,0.2281047553,-0.8125753999,1.4891103506,-1.8475048542,-0.1294121295,-0.6484277248,-1.0389952660,-0.2641805112,-1.4201703072,0.9795006514,-1.3405352831,1.4375221729,2.0169596672,1.1405482292,0.7233772874,0.5449270606,-0.7012047172,-0.2516741455,0.1970013082,-0.7681846023,0.5858729482,-0.3477722704,0.2033023685,-2.0873692036,0.9893494844,-0.5800985098,0.6182278395,-1.9546772242,-0.6086624265,-0.7773972154,-1.2600343227,1.8167859316,-0.0987552106,-0.1810840815,1.2722183466,-0.3335888088,1.5315827131,-1.3085680008,-1.2660052776,0.9042910337,0.3279466331,0.3045103848,-0.3153513670,-1.5934838057,0.4933577776,-0.3654850125,-0.5737106800,0.2879352868,-0.4627600908,-1.0108826160,-0.6777721047,-0.8984144926,0.2504751086,0.8091649413,2.6401121616,1.7911562920,-0.8305351138,0.8344239593,-1.4438226223,0.3508011997,0.2592615485,-1.5862669945,-1.4240231514,1.5163314342,-0.8924900293,-0.0843262747,-0.7113832831,-0.2796256840,-1.0860145092,-0.3189810216,1.4416177273,0.5681290627,-0.3779550195,0.4941016138,0.2960478067,-1.2442852259,0.0931274667,-0.0518829748,0.1845656782,-0.7338954210,-0.5237256289,0.8684477210,0.6828365326,0.5501427054,0.8220844269,0.7082092762,1.0605940819,-0.2782573998,1.0126662254,1.1477307081,-0.0826153383,-1.4017388821,-0.7767349482,1.1191364527,-0.4544364214,2.3977463245,0.5580090880,0.8164888024,-0.7969041467,-1.2697274685,1.5049589872,0.1810080558,-0.2684362829,-0.3502424061,-0.4023967385,1.2367614508,2.0550661087,-1.4493792057,0.1685050875,0.4869134128,0.8313385844,0.6722729802,-0.5500596166,0.2919599712,-0.0776337832,0.3386179805,-0.5368257761,1.8082138300,-1.5536627769,-0.2598360777,0.4972334504,-0.5991903543,0.1945166141,0.2947003841,1.3485603333,-1.8906611204,-2.3424110413,-1.2688889503,0.0344363041,0.2485752255,0.9743855000,0.5960764289,0.3309855461,-0.5189491510,-0.8919455409,1.1610465050,-0.5045477152,1.3423473835,1.5131756067,-0.6779407263,-1.7057740688,1.3286938667,-0.2861714661,0.3773959279,-0.0487306230,0.9769710898,0.0155381076,0.2035691142,0.2230139375,-1.5775175095,0.3229602873,-1.2306278944,0.0244359765,-1.4809737206,1.2955615520,-0.0120471921,-1.2050281763,-1.8280923367,-0.1050783247,0.9775385261,0.7549197078,0.0924711451,-0.1297639459,0.2104711384,0.2063230872,0.0318034813,0.6998687387,-0.0475344919,0.0653456599,-0.4324573576,-0.2389912307,-0.0385269783,-0.3596199453,0.9366604090,0.2594126165,0.8580753803,2.4031043053,0.6737225652,0.6189863682,0.3409185708,-1.7746075392,-2.3424885273,-1.2195376158,0.0443152338,-0.3048034012,0.4648899436,1.8452289104,0.3149746358,0.0522343889,0.3195095360,-0.7438256145,0.2410807163,0.5562276244,0.2206500024,0.3171322346,-2.2169415951,0.5470215678,0.9518302679,1.1646939516,-0.4791328311,1.3888785839,-0.3748681843,0.7778351903,0.8615957499,-0.8165302873,0.5390430093,-0.6619489193,-0.1029545069,0.0851025358,0.9509700537,-0.5260720849,0.8613053560,-0.9844242930,1.3661401272,0.5948407054,0.1009211168,0.0307289679,0.1981360763,0.8672862649,1.1369253397,-0.1251385957,0.1661457717,-0.9388157725,-0.2449741960,-2.4094924927,0.0623265356,-1.2366584539,1.8895184994,1.3102403879,0.9462187886,0.3420774639,0.3925039768,1.2095966339,-1.4361178875,0.5183697343,0.3537858129,1.2890650034,-0.2607053518,0.2743812501,-0.6387026906,0.6534357667,0.1286210418,0.5044686198,0.1814749390,-0.4254333973,1.5863105059,1.7321563959,1.5264887810,0.1210952625,-0.5436092615,-0.9529995918,-1.6551265717,-0.1553141028,0.2441254854,-0.7731710076,-0.2470936179,0.2712610662,-0.6617076993,1.0395247936,0.6841502190,-0.9874541759,1.3303834200,-0.6565662622,1.1300296783,-0.1293801665,2.3106272221,1.4594422579,-1.0526741743,-1.0220749378,0.0577553660,-0.5097522736,0.3840633333,-1.2838438749,0.7513307929,-1.6153922081,-2.3277418613,-0.6914343238,-0.4368054569,0.3361124098,0.8448717594,0.4833911061,-0.4330910444,0.6864856482,-0.7480033040,0.5588150024,-1.5406918526,0.8605827093,0.0865264311,0.6239672303,-1.1139910221,-1.5116748810,-0.7817136049,1.5633437634,1.6206901073,-0.1340485662,0.5526981354,-0.0745343417,-0.5309984684,1.1839113235,0.3718740642,-2.9650082588,0.6733871102,0.3198423088,0.6197563410,-0.0403066762,-2.3952093124,1.2700175047,-0.8881990314,-0.7429559231,-0.8290517330,-1.1331794262,-1.8599679470,0.7857927084,-0.2451763600,0.3910550177,0.1410217583,0.7675020099,0.7578459978,-0.3758762479,1.2606920004,-2.8472449780,1.4555310011,-0.2381768674,-2.2845680714,0.1599343717,0.7724515796,-0.1817385405,0.8262177706,-0.7928229570,-0.8502887487,0.1392326504,0.4767868519,0.7469817400,0.4203766584,1.9672571421,1.5491867065,0.0936574414,0.1747819185,0.1045727581,2.1363508701,-1.2314023972,-0.6329893470,-0.4213211536,0.8636973500,-0.3888166547,-0.4820105731,0.4317566156,-1.1235409975,1.3373652697,0.7710515857,-2.7142024040,-0.2182231843,1.6929919720,-0.0195358247,1.3989555836,-0.3875274360,-1.0358554125,-1.1316094398,-1.5382269621,0.9663111567,1.0785235167,0.3704659343,0.2607283294,-0.2777065337,1.8606232405,-0.6065781116,0.3053328991,0.6207325459,0.0930356830,1.2091175318,0.1401986331,0.8139212132,0.0959253460,-0.8038667440,-0.9163048267,-1.9060095549,0.1097709686,-0.9959290624,-0.3285111785,1.2623658180,0.2582879066,1.3890106678,0.1220844612,-0.4873121381,0.5140516758,0.3178030849,0.5869648457,-0.3526543379,-0.3959585726,2.3274693489,0.1709618419,-0.9874722362,0.3988903761,0.3557094634,0.9122059941,-1.7059065104,1.5565053225,1.3327462673,-0.3147378266,0.1606792957,-0.5181043744,-0.0744991302,-0.1525735259,0.8446281552,-1.9320089817,1.4879050255,0.1854588836,-0.1515202969,0.2979521453,0.5038195252,0.8791267872,-2.6462893486,0.1011591628,0.5374528766,-0.0020966744,-0.0970841497,1.9185301065,0.5449617505,-0.4810386002,-1.5802356005,0.3312494159,-0.8791120052,0.3050711453,1.0962580442,0.5063979626,-0.0172869842,0.9996516109,-1.5001869202,-1.8311299086,-1.1142653227,1.2140845060,-2.3504610062,0.3383857608,-0.2453690469,1.0279306173,0.0342444330,1.4575858116,0.7556669116,-0.2027938962,-0.3228623867,-0.1250157803,-0.2761982381,-0.0912716240,0.6139395237,0.1320572197,-1.7598555088,3.8252158165,2.3801681995,-0.5304226279,0.4853073955,0.4158081114,1.9410279989,1.3093279600,0.4837481976,1.0330768824,0.1908234954,0.8460777402,-0.4605898261,0.4409380257,-0.0441601798,1.8047442436,0.9391747117,-0.9743002653,-0.6022531986,-0.9103568196,0.7067342997,1.0348250866,-0.1873424798,-0.4120945930,-1.6666873693,0.1700548679,0.8848538995,-0.5189235806,0.6518719196,-1.4336264133,2.1102340221,0.6158944368,2.0755994320,0.9486870170,1.4196146727,-0.6370040178,1.4725530148,-0.2676182985,-0.1825240552,2.1773166656,1.9086070061,-0.1137179285,1.5164897442,-0.2023674399,0.2179028988,1.7951279879,0.3171834350,0.4730903208,-0.9259622097,-0.5089650750,0.7982944250,1.1375516653,0.3526133299,1.3780834675,-0.0489090681,-0.1768110543,0.0780580640,0.0144599462,-0.0084795738,-1.2281516790,0.9156061411,0.2464201152,-0.0167766493,-0.1420723051,-1.5855610371,1.6599810123,-0.0597732589,-0.0273799822,0.8296191692,0.8847360611,-0.5626728535,-1.7483476400,1.1403344870,-0.0690325201,1.3960663080,0.6275839210,0.5832805037,0.0118617360,1.2410900593,-0.6006539464,0.2910424471,-0.5646578074,0.4662118554,-0.5337926745,0.3868106008,-0.4784782529,0.5543790460,-0.4056519866,0.7447139025,-0.0469487794,2.4892342091,1.3938800097,-0.1264778972,0.4362581074,-0.8975135088,-2.5608577728,-0.7694765329,0.6344984770,-0.1369070113,0.4036124349,-0.2340947241,-0.9804391861,0.4205627739,1.2156971693,0.1035736427,-1.7539309263,1.0600017309,1.2703372240,-1.2950500250,-1.5065121651,-1.3031721115,-0.1997547597,-0.5540348291,1.3706039190,0.3994727433,-0.2424000353,-0.5245046020,-0.0897789225,-1.1353756189,-2.1022062302,1.2222563028,-0.2435424030,-0.0676702186,-0.8102147579,0.3558183014,2.0535726547,1.0213717222,-0.2912064791,-0.7373991609,0.3800884783,-1.0866839886,-0.2113780975,-1.0243973732,-1.0861248970,-0.1851570606,0.4320114851,0.5590879917,-0.3961796761,0.9062599540,1.5587188005,0.7504378557,-0.4613761306,-1.9730011225,-2.1190068722,0.4325800836,0.0537056699,0.8598451614,0.6354776621,-1.6893638372,-0.2476013154,0.9518808722,1.5663367510,1.6191905737,-1.6549032927,-0.3134933412,1.4668923616,-1.8313214779,-0.3367227614,-0.5707110763,1.6618161201,-0.3145177364,0.0156628042,0.1667782664,0.8142173886,-0.3663666248,0.2926310003,1.5102934837,-0.8687940836,-0.5283280611,-0.5114175677,0.6322653294,-0.1110791191,0.0009631776,2.9895756245,1.4097995758,-0.5420150161,0.9210902452,0.5834612250,0.7994394302,-1.3424725533,-1.0264796019,-1.3861973286,0.1247647181,0.1029771194,-0.4731315672,-0.5921694040,0.7910331488,0.6274262667,-0.1472722888,2.5348424911,1.7897282839,0.6568221450,1.7179471254,0.5924511552,0.5724430680,1.4984492064,-0.5010377765,0.0174681451,-0.5767454505,-0.4235750437,-0.3686167598,0.1869814843,0.8584616184,0.0341167487,-1.2190752029,-1.8360806704,-1.7777047157,0.3351447582,0.2758966386,0.2172588408,-0.1049501747,0.4783955216,-0.3389906883,-1.5148092508,-0.2531677485,1.5903692245,-0.2204401195,0.6823341250,0.6670246124,0.3315284848,1.3474885225,-0.6062452793,0.0387766436,0.3242726922,1.6093249321,1.7843703032,0.5993479490,0.9222139716,-0.7880330086,2.2105967999,-0.7617409229,1.2312707901,0.6148130298,-1.4690411091,-0.4746180475,-0.6721571684,1.0992940664,-0.0940861106,0.6958556771,-1.2895159721,0.2084652185,-0.7831521630,2.0253167152,-2.4375717640,-0.0784258023,-0.2919144630,0.9683870673,-0.2354955524,0.5750846267,-0.3641513586,0.8403220177,0.5809874535,0.6007576585,0.0460261889,-0.3048984408,-0.7436544895,-0.1375458986,-0.0768285319,0.6623673439,0.4524120688,0.3483710289,0.6208192706,1.7647602558,0.4740043879,-0.2359790057,-1.0643504858,0.4502330124,0.4655013680,-0.9948694706,-0.2585768700,1.3167483807,0.1989564151,0.2323360294,0.7958525419,0.3262020648,-1.3898649216,0.1671944559,-0.9119162560,0.2252446115,-0.9267496467,1.1519112587,-0.5130313039,0.1882673055,0.6804435849,-0.4746681154,-0.4878197908,0.1800938845,0.1051743627,-1.0580087900,1.4008100033,0.5489974618,0.5481874347,-0.5832469463,-1.2305303812,-0.3625142276,0.0120345866,0.2264911383,1.2822241783,-1.2907737494,-0.8618292212,-0.9438347220,0.4134423137,-1.0703722239,1.4725133181,1.4156024456,-0.4514758289,-0.5120148659,-0.6924622655,0.3693538606,0.8347567320,0.6099922657,0.8409538865,-0.2589316368,0.1839996278,0.3036150634,-0.0842262655,-0.2866791785,1.1813234091,-2.3766260147,-0.9739966393,-0.9959408641,-0.7160070539,0.3816682100,-1.7369004488,-0.7823039889,-1.6728433371,0.5592993498,0.6593230367,-0.6877341270,1.5265905857,-0.0742725432,0.8444102407,-0.7459825873,-0.0516187772,0.2302361876,2.4707098007,-1.7039589882,0.1352397501,0.4142930210,0.1444460303,-1.1740654707,-1.2802608013,0.1036694646,-0.3136852682,0.0832345337,1.2571145296,1.8054370880,0.7833987474,0.2159276009,1.3131119013,1.0496573448,-0.2494902462,-0.9532986283,0.8174754977,1.8209816217,-0.4751147926,1.5540887117,-1.6372287273,-0.5182297230,-1.2041864395,-0.7944150567,-0.2081774175,-1.7688667774,0.9372014403,2.3383221626,1.2419533730,-0.1160321012,0.8310201764,0.3418564796,0.0724793375,1.4042508602,-0.0997533277,-1.5711517334,-0.1969444603,1.4441918135,-0.7084956765,-0.4584809840,-0.4085344374,-1.7429348230,-1.4977319241,-0.2693070471,0.9721183181,-0.4137994051,-0.6265276074,0.5437030792,-1.2866847515,-0.7732895613,-0.8717803359,-0.0661167651,0.0868368670,-1.4115611315,-1.1569627523,-1.9649760723,-0.1715185195,-0.9807068706,0.1386085302,0.4682126045,-0.7425556779,-0.6112797260,-0.9979614019,-0.3386137486,-0.1766004115,-1.7047775984,0.1936862469,0.1481569558,-1.5413073301,0.3674076796,0.0811279714,-0.9216552377,2.4965655804,0.8719742894,-2.0750610828,-0.8497855663,0.5540226102,0.2907184958,0.6172452569,-0.4571862221,0.4977155328,-0.9748178720,0.5232276917,-0.0748741329,-1.2881364822,1.3667689562,0.1484711468,0.9896100163,0.3713888526,-0.4138089418,-1.0227590799,0.3866163194,-0.9294429421,-1.0626591444,-0.0199987087,0.0961680189,0.2672078311,1.2036789656,0.7388323545,1.2408499718,0.6849725246,-0.2830341756,1.7859346867,-0.6817632914,0.6170616746,0.7021603584,-0.0052990373,0.0670303106,-0.3759177029,-0.5266339183,0.5763165951,-1.1446790695,1.0514925718,-1.2716163397,-0.3700241148,-1.7133955956,0.4637143910,-0.0871691108,0.4271546900,0.7751936316,-0.4274554849,-0.4503265619,-0.5333029032,0.5149218440,-0.2053171545,-0.6556538939,1.2024029493,-1.4963507652,-1.0015004873,0.2347760946,0.5991263986,-0.5835256577,0.0645779371,0.4332801104,-0.8684640527,0.6871785522,0.2869982421,0.0550472997,-0.6587293148,-0.5711126924,1.2947942019,-0.7356818914,-0.3393787742,-0.3914661109,-1.1938683987,-0.0813956112,-1.5593749285,-0.3439086378,1.2804453373,-0.9656952024,1.6998059750,0.3437785804,1.2053562403,-1.3430669308,-0.2202706486,-0.2032942921,-0.4607440829,0.6888646483,0.9494631290,-0.5992566347,0.6588060856,-0.8213128448,0.3451172411,-0.1872069687,0.5875008702,0.6419531703,0.8461623788,1.4980093241,1.5428068638,-1.0534813404,0.1087473035,-1.9668846130,-0.4938659072,1.0318287611,1.4068181515,-0.1060440391,0.1013416573,-0.3797146380,-0.0020411925,-0.4893866777,1.2483414412,-0.9816740751,1.0710183382,0.3810484111,-0.2293544710,-0.9001345038,2.1937174797,-1.2616010904,-1.2372906208,-1.6419368982,0.2051976770,-0.3173463643,1.1138305664,0.0690412819,-1.4165972471,-0.9509050846,-0.4597766995,0.2946996391,-0.7381731272,0.9412861466,-0.6347444654,-0.2386984080,-0.5287588239,-0.2509096265,1.6997805834,1.9507800341,-1.3863464594,0.0064332704,-0.7473371029,-0.5901803970,0.7893643975,-0.0761919171,0.6964703202,-0.6725970507,0.2126092315,0.7568253279,-0.9808959961,0.1224446669,1.5959967375,-0.4214015007,0.7471168041,0.4177250266,2.1514711380,-0.2517547309,-0.5861119628,-0.7115761042,-0.2423496544,0.4907200933,1.3639013767,-0.0233906917,-1.2201986313,0.5158403516,0.2809210420,0.1244746000,0.2069127262,1.4315224886,0.3899920881,-0.2881478667,-0.4212123156,1.2691807747,0.1441033632,-1.9708248377,-0.3076345325,0.6847977638,-0.2083214968,-0.9662112594,0.5662410259,-0.4710945487,0.6587586999,0.4371346533,1.2881650925,1.8142797947,-0.2653055191,-0.8061235547,-0.2660584152,1.1144868135,0.4511666894,-1.0467418432,-1.2955060005,0.4813936055,0.0717912763,-0.2718241215,-1.4206292629,0.5015422106,-1.5696884394,-0.7510741353,0.5357149839,-0.4761382341,0.3027769625,1.0439693928,-0.2968443632,0.4115947187,0.1417464614,-1.7686996460,0.5488359928,-0.4652283788,-0.2023715526,2.0392110348,0.9476948977,-0.5790069103,1.3782595396,0.0463112034,-1.4538191557,1.0799579620,-0.4495364726,0.6995849013,0.9958032370,0.1410770565,-0.7974423170,0.7335600853,-0.8051303029,-0.5576012731,0.6688166261,-0.6395130157,2.0262405872,1.8946053982,0.4527872503,0.3898622692,-0.6865835190,-0.8698310256,-0.1018036604,-1.2498087883,-0.9337173700,-0.6132207513,0.1670824289,0.5964810252,-1.0693768263,1.1424970627,-0.4055011570,-0.0484616831,1.4438123703,-0.3742063642,1.9146231413,-0.8712691665,-1.6244757175,-0.9451323748,-1.8532702923,-0.4922710955,-0.7652184367,-1.5269926786,1.0519231558,-0.7186142802,-1.1369289160,0.1738671213,-0.8412277102,-1.2510764599,-1.5560952425,-1.2814587355,0.2802022398,-0.1892165393,-0.3990669250,-0.4418022037,-0.1641026884,-0.0208841823,1.4467082024,-0.1773938984,-0.2656075656,0.9284580946,0.8337346911,1.3918434381,-1.5541487932,-2.3029310703,1.2056473494,-0.7153151631,-0.6681523919,-1.8057876825,3.0629129410,1.0158607960,-2.2026958466,1.0273900032,0.9297968745,0.7835995555,1.2467330694,1.9681586027,1.1947727203,-0.2920994461,-0.2260138839,-0.4726005197,0.7220215201,1.1053067446,0.6730644703,0.2965455055,0.5883324146,0.9228509068,0.1861357391,-1.1552476883,-0.1277422905,1.7361689806,0.5216132402,-2.2289402485,-0.5762023330,-0.3333890736,1.0773743391,1.5460308790,-0.4793303311,-1.2360799313,0.8915560842,0.5807973146,-0.9052379727,1.8003457785,1.5324009657,-1.0009678602,-1.3704814911,-2.0461034775,-1.6933704615,-0.3919988871,1.0435934067,-0.1997463107,-0.2654405534,-0.3796259463,1.1171686649,-1.1622449160,0.2430635393,1.2648487091,0.2460895479,0.7015656233,-0.2465724051,1.4588391781,-0.3708950579,0.1133627743,-1.8181365728,-1.2764829397,0.1797037721,-0.9096319079,0.1833432168,0.6413455606,0.2378626913,1.0471014977,2.1745960712,-0.2824437916,0.6198886037,1.4454858303,-0.6241021156,-0.0874009505,-1.2409427166,0.6960406303,-0.4450871348,0.4783905447,-0.7847806215,0.3396017849,0.8402874470,-0.3396469653,-0.5243570805,-0.4028583765,-0.4860184491,1.6486966610,0.9750620127,-0.4632399082,-0.0831132308,0.4595403671,-0.3360282183,1.2276799679,2.9337465763,-2.7567064762,-1.8911068439,-0.5368624926,-1.2443982363,-1.9356986284,-0.4737740457,1.1805994511,0.4548642337,-0.3293735385,2.1251163483,-0.1460131258,0.5125373006,-0.6775860786,-0.3787424862,-0.4837478399,0.1269359440,-0.5968005657,0.0434482470,0.0882226899,-0.4975458682,-0.8245134950,0.5286591649,0.0518661812,-0.1529803872,0.2797895372,-0.2412377894,-0.3942654729,-1.4258618355,-0.1979169846,-0.4607566595,1.9837756157,1.3194955587,0.4016983807,-0.1167668849,0.0360824801,0.7133179903,-0.0223064348,1.4471542835,-0.4008077383,0.9587165117,1.2700641155,0.2602819502,-0.1262758076,-0.7956354618,0.9213441014,-0.8105702996,1.2343528271,0.1792832315,1.0454692841,1.8160818815,-0.2565951049,0.6567875147,-0.9121094942,0.0882756636,-2.3321690559,-0.2221315503,0.4362458885,-0.4040724635,-0.9728463888,1.8061887026,2.8223960400,1.9238047600,0.4281252325,-1.0113406181,-1.0569467545,0.7463124394,0.7058548331,-0.2373242229,-1.2442312241,1.4772787094,-0.1161244661,-1.1747477055,0.0377737507,0.3676355183,1.0512756109,1.0939421654,0.3265855610,0.5304086208,-0.4535779953,-0.1297783256,0.9609361291,-0.6423221827,0.1481865197,-0.1527392268,0.2322229594,0.6704090834,-1.1654951572,-0.3747846484,0.7840104699,1.1033495665,0.5778945088,0.5689970851,-0.0741880238,0.8559090495,-0.6340079904,-0.2442087978,-1.2459036112,-1.0313720703,-1.2667640448,1.8217892647,0.8577761650,2.7689638138,-1.1735712290,-0.5874087214,-0.7750111222,-0.9776890874,-0.9262546897,-1.0075428486,1.1539785862,-0.2632883787,1.9082475901,0.7450637221,-0.4940591156,0.6841157079,-0.5536890030,0.6943057775,0.6760548353,0.9306396246,1.3879038095,-2.4359529018,1.0196198225,-2.3955872059,1.2872189283,0.4549034834,-0.0617699176,-0.7158759832,-0.4316509962,-0.6489620209,0.5559383035,1.0439940691,-1.3500230312,0.6517568827,2.4761118889,-1.4052060843,1.4435579777,-0.4848107994,0.0389968641,0.7329373956,0.0906467363,1.3932663202,1.6153687239,-1.0152901411,0.3226601481,0.3640216887,-1.2530380487,-0.3811959624,2.3525457382,-0.3899695873,-0.3235520124,-0.5818331838,1.0788103342,1.2848529816,-0.5897274613,1.8995616436,-0.0095527787,0.4356729984,-1.2555909157,-0.7084031105,-0.5457687378,0.3907106519,0.4804974198,1.0105402470,-1.1896303892,-0.9705888629,0.7118433118,-0.6612381339,-0.3134835660,-0.6854033470,-0.1347203255,1.0188876390,1.8438681364,-0.5356816053,0.8939056396,-0.2387982011,0.3773968518,-0.5067309737,0.3475973010,0.1116873249,-0.3291538656,-0.4861176014,-0.1610072404,-2.0568583012,-1.5355416536,-0.7158253193,-0.9671429992,0.3337282538,-0.5167418122,1.8286303282,-2.3692855835,1.1425521374,-0.4168982506,1.1942421198,-0.5849003196,-0.4810088575,-0.2370169908,-3.2313024998,0.1890334487,0.2700953782,1.3857370615,1.1544367075,-1.5452423096,-0.7408530712,0.3481022120,0.4148260951,-0.3747694790,-0.6615316868,1.5172027349,-2.1836273670,0.0456692502,-0.0833318532,-0.9288641214,1.1208633184,-1.5847899914,0.8110761046,0.2517983913,0.3271596134,-1.8162002563,0.4868193269,0.9116107225,-1.9339040518,-1.3720557690,-0.6756509542,-0.1909210086,-1.2321888208,-0.0097519904,-0.6435344219,1.5714240074,1.3172254562,0.7528502941,0.3804392219,0.7566663027,0.3085334003,0.4007671475,0.3258664608,-0.9499855042,1.4211901426,1.2636379004,-2.1053454876,1.0966620445,-0.2560794652,-1.1866722107,-0.1082164645,-0.9384649992,-0.4065252841,-0.3620557785,-0.6806376576,0.6351390481,-1.2025653124,-1.6817848682,0.4998220205,1.2873026133,0.6916964054,-0.1651842296,1.1613186598,-0.5508473516,-1.3952718973,-0.7212381959,-0.2760586739,-0.9742767215,0.9609985948,1.8242496252,2.2517738342,-0.8537518978,-1.2370250225,1.6758298874,-1.2859879732,0.8290636539,-0.0007398854,-0.6669198871,0.7239009738,0.4930982590,2.3166418076,0.2593319416,-0.4904332459,0.9100781083,-1.5406177044,1.0337108374,-0.0417323932,0.1815911382,0.8316265345,1.1683583260,0.2908100188,-0.8651617765,0.1349878907,0.5809453130,0.6313925385,0.9107890129,-2.0079622269,2.2667987347,0.1362239718,-0.4542431533,0.8893927336,-1.3563278913,-1.4928052425,-2.5350847244,-2.5609161854,-0.5255851150,0.0438330211,-1.6740049124,-0.3690219522,2.2857151031,0.9468349218,-0.3893817365,-0.0589064620,0.4195207953,-1.5684384108,-0.9302867651,-0.9671948552,0.6613282561,-0.8047224283,-1.7897052765,-0.2297337502,0.0934528559,0.2821525931,-2.0221195221,0.5018086433,-0.1606549770,-0.0830269158,1.6817605495,-1.3330610991,0.2334875464,0.9362577200,-0.8867135048,0.6424555779,0.6285135150,0.8862875104,-0.7600226998,-0.1048611850,-0.1568768024,-0.1049152017,-1.1293969154,0.4765573442,-0.4045842588,1.0629390478,-1.0136929750,0.1548542231,-0.0260496736,0.7368959785,0.6437106729,0.8629876375,0.9513613582,0.5345712900,-0.3428974450,-0.8951515555,-0.7072141767,-0.8290418386,-1.9441916943,0.3352486789,-1.6981418133,-0.6064324975,0.9298272133,-0.0455442220,0.4545024931,-0.6905018687,1.6557446718,-1.8656061888,-0.0764164850,0.1352482140,-0.9649400115,-1.1107592583,0.8871802688,0.3857004642,-1.3479410410,0.2313199341,1.1432842016,0.9774471521,-0.8249517083,0.9975424409,-0.4786781669,0.9934655428,-1.5249751806,1.4200520515,-1.3656040430,0.1201347858,-1.4304561615,-0.5459815264,0.3317955434,2.7635042667,0.5319283605,-0.4035831988,0.1656674147,-0.0348275118,0.9128665924,-1.0659881830,1.5218554735,0.4108059406,-0.8818579912,-1.8898864985,-0.8056340218,-0.2248883545,-0.3115158677,-1.9761034250,0.2347872108,0.0435139611,0.8959118724,-1.4635934830,-1.4139857292,0.5881743431,0.4636629820,0.4652281404,0.1577140689,-0.4330151975,-0.6331516504,2.2929763794,0.1627715528,0.4049665332,-1.0525262356,1.3194918633,-0.2121516019,-0.8326429129,-0.1556195468,-0.2294962704,1.7370721102,0.0576815419,-0.3365804553,-1.9751281738,0.3499570787,0.8850831985,0.6897427440,0.3805027306,0.8950417042,0.5748343468,0.9603128433,-1.5605746508,-0.9406257868,0.1844527274,0.4658717513,0.5011162758,-0.2088306248,1.1758521795,1.1635521650,0.4772557020,-0.7171283960,-1.7251302004,-0.7932379842,-0.7980470061,0.2869731784,-0.9468921423,-0.0588519983,-0.9246168733,-0.4363086224,-0.7276189923,-0.0040393011,0.1989732385,0.8241624832,0.4181136787,1.7991360426,1.6254104376,-1.0304411650,-0.8917178512,1.1133543253,-0.8911256790,0.3151792586,0.9218831658,0.9283659458,-0.7275673151,-1.8838251829,0.8151659966,-0.3029778004,0.3363099098,0.7451679111,0.6459904313,1.5648649931,0.4582104683,0.6197059751,-1.5433871746,-1.1824321747,1.0177524090,-0.7003726959,0.1140275300,0.5453913212,1.4336909056,0.2446464747,0.3940807581,1.9681952000,0.6926275492,0.2997940183,-0.5876314640,1.6486163139,1.3615334034,0.3137921095,0.7396493554,1.2286649942,0.6699882746,0.6917827129,1.3034600019,0.4483648837,-0.1363343149,0.9878246188,-1.0063430071,-0.3920277953,-0.2899178565,0.5260047913,0.6267307997,1.3453166485,0.2274762243,-0.0629633963,-1.1903443336,-0.6259784102,-1.4462623596,-1.6484795809,-0.9891631007,-0.6025660634,0.4475584924,0.2266521007,-0.0169600137,0.3846054673,0.3575282097,0.6688492298,-1.5007214546,1.0728921890,-0.9921048880,-0.8433125615,-0.2272939533,-0.5822410583,-1.4138011932,1.1975219250,0.6921180487,-0.2646894753,-0.7491828203,-0.4853253067,-2.2885367870,0.1974256933,1.4541417360,-2.2559049129,-0.7094967365,0.4081711471,0.0805931389,-2.1951055527,-1.2974768877,-1.3876715899,2.2653400898,-0.9290544391,-0.0399216227,-0.6982507110,-0.5406550765,0.2805226445,0.2198031545,-0.5062025785,0.1667801738,-0.1336404383,-0.2559153736,-1.5829130411,1.7256107330,0.3249048591,0.7238846421,-0.0049705473,0.1070211902,-0.0440496467,-0.5861712694,-1.2517702579,0.9920070171,0.0184310395,-0.2521992922,1.0478001833,-0.8511126041,-1.0877283812,0.8057253957,0.5307689905,-0.2180033922,0.8828327656,-0.4397656024,-1.9520184994,0.7932648063,0.5082966685,0.3833715320,-0.9113702178,-0.3640641570,0.7479833961,0.6907197833,-1.7358108759,-1.0114843845,1.0597826242,1.4337526560,-1.9482045174,0.1001625508,-0.9070497751,0.6013016701,-0.3366676569,1.5244055986,-0.4733226001,-0.4377292693,-0.6595449448,0.9301330447,-0.4823285341,-0.4746858478,1.0638920069,1.8176459074,-0.0334640481,1.5302972794,-1.4440655708,0.3651750982,-1.0116682053,-0.1984334737,-0.1631214619,1.5133635998,-0.7044069171,2.1420927048,-0.1501505226,0.0840540752,0.5596846938,-1.3633971214,0.6780669689,-0.2560397387,-0.3821427524,-0.0927638486,-0.6855667830,2.3247995377,0.0162809864,-0.8881989717,0.5334579349,0.1402356327,-0.9644435048,0.2259918451,0.4266486466,0.7260495424,0.3118670881,-0.6226944923,2.6717684269,-0.5756723881,-0.4234935641,0.3955070078,0.6205416918,-1.3463940620,0.3289612532,1.3118835688,-1.3313224316,1.2080878019,-0.4787815809,0.1577800959,0.0663677827,-1.1360330582,-2.5606052876,-0.6011534929,-0.3796326518,-1.1565338373,0.1681053191,-1.2738326788,0.8146806955,1.1786562204,0.3972067237,1.4141077995,-0.8077833652,0.2641517222,-0.6645264626,-1.1914525032,-1.9402074814,-0.1699234396,-0.1685755104,1.9913597107,-0.5442168713,0.7998579741,-0.2674789727,0.2076923251,0.8118554950,3.0703585148,0.6901968718,-0.7633002996,-1.9414342642,-1.8525712490,-0.3263784945,-0.7097280622,-0.3387582898,0.5192115903,-0.0137907621,1.2764714956,-1.2416212559,-1.1341321468,-0.2834493518,0.2832931876,-0.8440576792,-0.3899221122,-1.2861567736,-0.0039009314,-0.3991547823,-0.1507866830,-1.0784094334,0.6873516440,0.2398162633,-0.8915411830,0.0160620846,0.1190035343,1.3595669270,2.2851662636,1.2656277418,0.5647453666,0.4386366606,-0.2786923051,-0.0450435877,-0.9073960781,0.8157382011,-0.2528479397,0.1099881604,-0.5259025693,0.9864002466,-0.3098907769,0.1118538901,-0.1846686453,-0.4830997586,1.3937410116,0.6692713499,-0.2855373621,-0.3015303910,-1.2393440008,1.0436235666,-1.3757392168,0.3743044734,-1.0209194422,-0.9742291570,0.4092015922,0.2553415895,-0.6028506756,-1.3848016262,-0.2793629766,-1.3943332434,-0.2918968201,0.9001582265,-0.4785775244,-0.6464923620,-0.0132998796,-1.1716102362,0.2067309022,1.0480587482,-1.4701331854,-0.2972986698,0.7241115570,-0.4221785963,0.3793757260,0.5570320487,0.8278382421,-0.5132340789,0.4097019732,0.1758598834,2.0416235924,2.2838354111,-0.4602448940,0.4201773107,-1.0172317028,-0.3338675797,-1.9052309990,0.0349817537,-0.3715404868,1.1575589180,0.4315404296,-0.6823685765,-0.2479079217,-1.3237612247,2.5582401752,0.6202364564,-1.0272048712,-0.7202998400,1.8100709915,-0.2270940989,0.4384859204,-0.4506998360,0.4351607263,-0.1438863873,1.5774437189,-0.4889984727,-0.7328954935,-0.9708195329,0.1281945407,-0.1182762161,-2.0853116512,-0.9564751387,-1.6145592928,0.5195460916,1.4585510492,-1.0158007145,0.0924392417,1.1844977140,1.8504533768,-0.3173408806,1.0457521677,-0.8087899089,1.1489765644,-1.3961595297,0.2893914282,-0.2376532108,-1.2573392391,-0.8585844040,-0.4192205966,0.6898103356,-0.1702734679,0.7137411833,-0.1038140580,-0.5801587105,0.3293689787,-0.1780804843,2.1423149109,0.5859926939,0.8150727153,0.0960851610,-0.0801161528,-1.5072997808,0.3067455888,0.9733224511,-0.6691715717,-0.0896074921,0.7155662775,-0.8350681067,-0.8200449944,-0.2977332771,0.4310656786,-1.8563512564,1.2392419577,-1.5641089678,-0.0520131513,-0.3065806627,-0.1996008605,-0.1993302405,1.4793595076,-0.6917536855,1.1229088306,0.0617509261,0.2330419570,0.9543156028,0.3231183290,-0.3006335795,-0.5459107161,-0.3147141337,-0.0181828812,-0.2925636470,-0.1001829058,-1.5876607895,0.1932607740,-0.6446776390,-1.1246975660,0.7368519902,2.3475573063,-0.1616914719,0.3552694023,0.0810829923,-0.2951989174,0.3914378285,0.3118802309,0.6587822437,1.0558242798,1.5984497070,-0.2858626544,-0.9805120826,-0.7844312191,0.2835466862,-0.6526885033,-0.2016610503,0.8101894259,-1.3438426256,0.1658969969,-0.5662457943,1.3452924490,-0.2444649488,1.6518733501,-0.9791072011,-0.7222418189,-1.0671290159,0.4526766241,0.4453455806,1.2471383810,1.1432536840,-1.8908467293,-0.4724683166,0.4400090277,0.4122885764,0.7332125306,-1.7321538925,1.9177784920,-0.2359334975,0.7171579599,-1.1484898329,0.2975558341,0.1324217170,0.8498703241,2.0220580101,0.0642231554,2.0187501907,0.6166564226,-0.3392534256,0.8539775610,0.3858638108,2.0248098373,-0.1607054621,0.4017896354,-1.4190493822,0.3904750347,0.2559507191,-1.5319329500,-0.1452561766,-0.4501852691,0.3744405806,0.7547407150,-0.3966326714,-0.1949160248,-0.9319941401,0.5192106366,0.1668777913,0.7877882123,-0.5676600933,-0.5376181602,1.7631980181,-0.4717208445,-0.2970747948,-1.6887958050,0.8346431851,-0.2908143401,0.4495654404,1.1724085808,0.3258660734,-0.3408461511,0.9547800422,0.7426418662,0.7121489048,0.0964861736,0.3108291626,1.7955456972,0.6886371970,0.6476287842,-0.9715218544,1.6482530832,-1.3654054403,-1.4465010166,1.8486927748,-1.2850440741,0.1249407083,-1.0885308981,-0.2485388815,0.2764838040,0.5420431495,-0.4004425406,1.9209617376,-0.6851661801,1.1391372681,-0.1613515317,0.4473843873,0.4043840468,-0.2895264924,0.5565383434,0.7464129925,0.6821542978,-0.6891804934,1.7582477331,-0.0945984796,1.8338278532,-1.2337061167,1.6532959938,0.5494328737,-1.1798790693,1.4739180803,-1.6404334307,-0.5586791635,-1.6484837532,2.4162697792,-0.3091666996,0.0423371978,2.1097922325,1.0761109591,-1.7526555061,0.1723993570,-0.3163443506,0.3997488320,1.1593134403,0.2288526297,0.9422805905,0.4081701636,-0.6158750653,0.4793061912,-0.7150249481,1.4441509247,-0.4498966634,-2.6479845047,1.2745366096,1.1473503113,1.8102370501,0.1164595559,-0.6753442883,-0.6330440640,-0.3043009639,0.6173820496,0.4520477951,-0.9501532912,-0.4605540037,0.0309729315,0.2326854914,0.4442227781,0.2579292059,-0.1524424553,-0.2695141137,0.6597102284,0.3571333289,-0.9604148865,-0.1528694034,0.4026290774,0.8940368891,-2.1126663685,0.6282519698,-0.9926656485,1.4733834267,0.6488913298,-0.9213027358,-0.5731467009,-0.6374110579,0.6401329041,1.3533540964,-0.3756834865,2.6135437489,0.1940688789,0.0630342886,-0.1559038311,-0.8732242584,1.2136697769,-0.4508092403,1.0960631371,0.3103138506,1.1365141869,-0.8697562218,1.2769855261,-1.9234557152,-1.1386402845,1.4014794827,-0.9552711248,-0.0660765618,1.6641439199,-0.8903948665,0.0384727232,-0.9314847589,0.7644599080,1.3544265032,-0.8408039808,1.2758435011,1.6310828924,0.8584744334,0.7314692736,0.2873908281,0.0925639942,-0.1756385863,0.7188848853,0.1778239012,0.0075021056,-0.3179973066,-0.8962370157,0.5907183886,1.3393832445,0.1291782856,0.2163106054,-0.1918319762,-0.4468945563,0.1792847812,-0.2239666730,1.4377971888,1.4812185764,0.4640325606,1.1958353519,-1.6090112925,0.7192595005,-1.8846025467,-0.4219196141,0.8524013162,-0.3068114221,0.7166014910,1.0810377598,0.0509062372,-0.8165169954,2.6991014481,-0.4963667691,1.1587369442,0.6737996340,-1.4490827322,0.6106519103,0.3198771179,0.0267605837,1.4674906731,0.4409443736,1.1011567116,-0.4959523380,1.0790488720,1.3844223022,0.1370456964,0.4587925076,1.1820701361,1.2755533457,1.1850805283,0.5455582142,0.2740237713,0.3107175529,-1.3007590771,1.2341132164,0.5541449189,-1.4907549620,-0.3145397305,-0.8253541589,1.0124372244,0.4967445433,-0.1998725533,2.3858799934,-0.2239804566,0.6783373952,0.6622564197,0.5010342598,-0.8637469411,-1.2166178226,-0.7888168693,-0.4862669706,-2.1496996880,0.2434635609,2.2176091671,0.6138218641,-0.1121539772,-0.0708785951,0.2982955277,-0.8135273457,-0.1176461875,-0.3864695132,-0.3397121727,1.9965733290,-0.4525742233,-0.7801883817,0.1617140174,2.0445573330,-0.6421329379,1.0683028698,1.4681972265,0.4830242693,-0.7713213563,0.9028714299,-1.1294329166,1.1345814466,-0.5910274386,0.6970822215,1.0826804638,-0.8912727237,2.1045033932,-0.1427501440,-0.0198568925,0.4012412727,0.5061278939,0.6106132865,0.8168576956,0.8838734031,1.8924901485,0.1710574180,-0.7019839287,0.3490320146,1.5296567678,-1.1244053841,-1.1642284393,-0.4193575084,0.5746083260,-1.1689153910,0.2877218127,-0.1881029308,-0.3931901157,0.4175453186,0.7864643931,-1.7730191946,1.7171610594,-0.5239853263,-1.6591190100,0.2596905231,2.7576310635,0.3869003057,-0.9029765129,-1.6944363117,-0.6992952824,-0.1057624966,-0.2710611224,-1.0353348255,-0.3324691951,-1.1543858051,-0.8658341169,0.1334683746,-0.1229031235,0.5339189768,0.6564360261,-0.4034191966,0.4229221046,-1.0462310314,0.4336838722,-0.2808940113,-0.6553801298,-0.0031763159,0.1415689141,-1.3357542753,0.0714949444,-0.4073644578,0.4600543976,0.3203541636,-0.1955058873,-1.4824770689,-0.4383046925,0.8585121036,0.0071368990,1.4751278162,0.6233286858,0.6207359433,-0.5246831179,-0.0414664410,1.7709965706,-0.0709905550,-0.2821904719,0.1701576114,0.8789879084,0.8838764429,-0.3726766109,0.7503628135,1.8942296505,-0.5893586278,-0.9376010895,-0.4995022118,2.0414099693,-1.1939601898,2.3895537853,-0.5800492167,-1.4941869974,0.3914678097,0.7654280066,-0.3711814880,-0.1482408494,-0.8229711652,1.0125423670,1.9014531374,2.1342532635,0.8377076387,-0.5943709016,1.0816322565,-1.4450104237,-0.9806501865,-0.0139226625,-0.0261511095,-0.1476468891,-0.1782859713,0.0654901490,-0.9970036745,1.8520280123,0.2998270392,0.4222496748,0.3607931137,-1.9088587761,-1.3702299595,0.1112247109,-0.3712612391,-0.8905547857,1.5990093946,1.0519772768,-1.6142657995,0.9828546643,1.1408561468,1.0751584768,-2.1395509243,0.8739467859,0.8484569192,0.4239789844,0.7949110866,-2.2604801655,0.2834377289,0.1236173958,0.6627572775,-0.1966073513,-0.8987166882,0.1549092829,-1.7537448406,1.3848297596,-0.0972593948,0.2573923469,-0.3925730288,-1.3261764050,0.6730273962,-0.0823751241,-0.2015870810,1.3150098324,-0.4746868014,-0.9555039406,0.0567918830,-0.2349265516,-1.2320506573,1.6329518557,-0.3194123209,-1.8545962572,-1.5797518492,-0.7913144827,-0.5306677818,-0.7435374856,0.0374403261,-1.5283485651,1.6451562643,-1.7834663391,-0.1449975967,0.9374970794,-1.1378582716,-0.4348377883,-0.3451203704,1.6907564402,-0.0922324732,-0.2340613306,0.3029639721,0.6703021526,-1.2160876989,-0.1070491970,-0.8925184608,-0.9153434634,1.5998293161,-0.2169963121,-0.0921376273,0.7837740779,0.3923157454,-0.4793142974,-0.6740366817,1.2255915403,2.2740068436,-0.3493728042,0.7215506434,0.4427873790,-1.2372415066,0.3400833905,0.3696044385,-1.1532834768,-1.3326276541,-1.3978134394,-0.7902693152,-0.0793885812,-0.0871508643,-0.8185797930,0.3032013774,-0.9155107737,-0.4498315752,0.0133975549,1.2002675533,-0.0543997772,-0.5718390942,-1.1672619581,0.2706866860,-0.6121038198,1.5340633392,1.3675135374,-0.3314547539,-0.6407935023,0.1904756725,-0.0176693890,-0.1542854309,-1.0666533709,-0.8065037131,-0.5172939897,0.1125126705,-0.8618041277,-1.0027049780,0.1088037044,0.8530612588,2.4807577133,-0.4043349624,-0.6118181944,0.4480062425,0.1232022196,0.2338018715,0.9920058250,-0.8674075007,0.3546648920,-0.7531710863,-1.1711133718,0.5628138781,-0.4150498211,0.3105407059,-2.4759883881,1.6793575287,1.7537196875,0.1912416220,0.2514575124,-0.5988570452,0.0741735473,-0.2699765563,-1.2148730755,-1.7194465399,0.2601687908,0.6379894614,-0.1272419095,-0.5413345098,-1.0075840950,0.4337921739,0.4659135342,-0.3689009249,0.0981860682,-0.5749191642,-0.5014486313,0.3198375106,-0.7704556584,0.9145529866,-0.4085680246,1.4911134243,1.4047791958,1.1867433786,-1.6885709763,-0.3014551997,-0.1118771732,0.7182075381,1.0829957724,-0.8519905210,0.1300453693,-0.4334434271,0.4877637625,0.8054375648,-1.4181320667,-0.4921872914,0.4618836343,-0.6419098377,0.4662364423,-0.5979802012,0.3456205726,-0.3643333912,-0.2508301735,-0.2602106929,-0.9041038156,-0.7807335854,1.4818336964,-0.0963200405,0.9439044595,-0.0088408943,-1.5938279629,-1.6104105711,0.1701638550,0.1085248068,-1.1758224964,0.3988420963,-0.4401808977,1.3763401508,-0.4395669699,0.4183611572,-0.8105944991,-0.6222549677,0.2567108572,-1.8000807762,-0.3589302897,-1.5436463356,-0.1948490441,-1.3861801624,-1.2604641914,-0.4003143311,2.4831156731,0.9226174355,-0.3849322796,0.2759652436,1.2357858419,0.5366231799,0.2259910405,-0.2262105793,0.9908719063,0.6953120828,-1.4158452749,-0.0114128450,1.1648558378,0.0026331618,-0.6417639852,1.7007479668,-1.0409736633,1.2814551592,-0.6953024864,-0.6436872482,0.5956673622,-0.8900166154,0.8791947365,0.4307781756,-0.5199248195,1.3481355906,-0.3190667331,0.5465198159,-0.1034876481,0.2821509540,-0.2298322320,-1.2568703890,-0.5725135803,1.8433989286,-0.1977019906,1.4076530933,-0.4182282388,-0.0286837257,0.4214601517,0.2952394187,-0.1422851980,-2.3230524063,0.5700261593,0.8659446836,0.4792743027,-0.0860511214,-2.4152247906,-1.1893260479,0.6089113355,-0.3519750535,-1.0636354685,-0.9764991999,1.4291633368,0.8169809580,0.7607301474,-0.8915486336,0.2099952251,0.7656538486,-0.9530802369,0.9028717279,-0.6837580204,-1.1406611204,-0.0980555266,-0.8678302169,0.0618282855,-0.9474887848,-0.4634743035,-0.8415288329,-0.2886526287,0.3071372211,0.2244463861,0.3965576887,1.1935093403,0.7316077948,-0.6506578326,0.2081241310,0.6839416623,-0.9692512155,2.0871205330,0.5729706883,3.4624316692,0.5383459926,0.3396901488,-0.5575518608,-0.5723373890,-1.7078907490,-1.6338896751,2.9699966908,2.5188298225,0.0883686095,2.0530881882,-0.6892683506,1.7217940092,0.8135957122,1.0825539827,-1.3073396683,0.2213107646,-0.8297741413,0.8229870200,-0.2925997078,0.2938055098,-0.2028401792,-1.0501542091,0.3662391901,0.0436582863,2.8220024109,1.6359175444,-0.2000506669,-0.6892738938,0.6414157748,0.1814173460,-1.2759850025,0.7353927493,0.9251579046,1.1306307316,-0.8013715744,-0.3105247319,-0.2614181936,1.4937690496,-1.1773779392,-0.9231160283,-1.9470348358,-1.2480545044,0.1362063885,0.6162065864,-0.4116608500,0.4412190020,-1.4277477264,0.7063032985,0.8237750530,0.4653929472,0.2365056872,0.0285083521,0.9960690141,-0.8011170626,-0.5131413341,-0.4017004371,-0.2410633862,-0.6117011905,0.5667151213,-0.4457055628,-0.7197325230,-2.7344152927,-0.2064120770,1.0151226521,-1.3595682383,1.3549883366,-0.1983778775,1.3015027046,-0.1049090922,0.7218281031,-0.1797719151,0.7467459440,-1.6058382988,0.8894509077,0.2281947583,1.1969484091,-0.6350207329,0.7831915617,0.5507146716,-1.3282835484,-1.1195918322,1.0832135677,0.4004996419,2.0190610886,-2.1272804737,0.5968118906,-0.6430553794,-0.9771640897,0.4279308915,-0.8297137618,-1.1755281687,1.0167371035,-1.0099674463,-0.3996248245,0.8061579466,0.5100678205,0.6430982351,-0.0116527425,-0.0569755547,-0.8373223543,-0.1155486926,0.8459715247,0.3501706421,-0.7146452665,-1.3728239536,-0.6906177402,-0.8787280321,0.3087691367,-2.0644254684,-0.8531473875,-0.7981085181,0.9267256856,-0.2735356688,1.6844605207,-0.3576886952,0.4597080350,0.5911514163,0.9546337128,0.7858938575,-1.0806646347,0.0153782917,0.8166173100,1.3586717844,0.6759258509,-1.1599477530,-0.9371449351,1.9049314260,0.4763910472,-0.0252852160,0.5366802216,0.1893805712,0.0235877261,-1.2631338835,0.1262231022,-0.4659309089,-2.0677807331,-0.2172206342,0.2418677211,0.2863640487,-0.5541240573,-0.4875922203,0.9178158641,0.8355688453,-0.3356583416,-0.4909035861,1.3364617825,-0.5274421573,0.0552913696,1.2746754885,-0.4226909876,0.6258471608,0.8982531428,0.7511479259,-0.2033134550,-1.7190890312,1.2277430296,0.3163192570,0.2681086063,-0.3645800948,0.3647791445,0.5008106828,-1.0483267307,0.0229089204,-1.1120997667,0.4731096923,1.0203477144,0.0132737607,0.3177182376,0.1482971162,-0.9006447196,0.7418464422,0.8549311161,-0.4601553679,0.4142823219,-0.5291186571,-0.2832478881,-0.9400891066,2.0045392513,0.9907512665,1.2803305387,-0.8706706762,-0.0438755862,-0.1437354237,0.1352631003,-0.2147992402,-0.4306062162,0.7384632826,0.1026570722,-0.9193673730,-2.8592047691,0.5031278133,-1.6948381662,0.0623850375,0.4504397213,-0.2354303449,2.3214147091,-1.8391581774,-0.0035846911,-2.3443999290,-0.3101183176,1.7663384676,0.3807913065,1.7143090963,0.2600724101,-2.4273955822,1.1260516644,-0.1763039678,1.6863145828,1.0932096243,-0.2558988035,-1.1969647408,-0.1792815775,-1.8289457560,1.5591448545,0.8391063809,1.2969179153,1.6576949358,-0.4130849540,-0.7088075280,-1.2217174768,0.1126335263,0.0402188487,-1.5738127232,-2.1769027710,-0.2445770651,-0.3699555695,0.3325831890,-1.2605797052,-0.0567351133,-0.0740334541,-1.6811589003,1.3763895035,-0.4706969857,-0.9843922257,-1.1051831245,-0.4698985219,0.8479211926,-1.0044732094,0.2730768919,0.8285003901,-1.1652021408,0.7067195177,0.5655376911,0.4849031866,-1.0408544540,0.2165114880,-1.6860473156,2.1083023548,0.6807785630,-0.3152302206,0.8114103079,0.0277315732,0.8226593137,-0.7260422707,0.0740356222,1.3696192503,0.4227825999,1.0678523779,-0.6593800187,2.4530041218,-0.5130468011,1.3998401165,-1.1113494635,2.8427562714,-1.2515159845,1.7911391258,1.4213436842,0.1319545954,0.9271252751,-0.5539256930,-2.1196947098,0.5384703279,1.7564214468,0.2037496120,-0.4946107566,-1.3231574297,0.6391705871,-0.2147297114,-0.9286428690,0.3146469295,0.3201300204,1.6130293608,0.9120296240,0.2281010896,-0.9520408511,-1.7568795681,-0.0860790312,-0.3216405213,1.5971487761,0.2164636552,-0.8063322306,1.4201835394,-0.9114590883,2.0482690334,0.4544996917,-0.9965992570,1.7234151363,0.4029419422,-0.0605051927,1.1774067879,-0.1526352167,-1.3627843857,1.0119982958,0.5999497771,0.1030077115,0.0237347633,-0.9818653464,1.2113623619,-1.0080310106,0.6341429949,0.3184710443,-0.6536894441,-0.3419989645,0.8524641991,-0.0375635810,-0.4750849605,-1.1283820868,0.0493629947,0.1907393783,1.8657075167,1.6624958515,0.4755136073,0.3853852451,-1.7855322361,1.5675200224,-0.3439013660,1.4749809504,0.4404431283,-2.3438589573,-0.6509875059,1.7350389957,0.5399621725,-0.7919213772,-0.7674368024,1.3210825920,1.8883692026,0.7461881042,-0.1613261849,0.9186052084,0.9145761132,0.4075089395,1.4331464767,0.7037459612,0.5462380648,-0.7761021852,1.0948152542,0.9146957994,-0.7808047533,-0.9392088056,-1.2161570787,-0.4258204401,-0.0622376651,0.6151955724,-0.1300780773,-1.2082298994,0.1191710830,-0.4793582261,0.3698245883,0.5303626657,-1.4388060570,0.3178140521,0.2438377589,0.5394156575,0.0692542270,0.7180391550,0.0523633435,0.5539424419,0.2073472142,-0.2396894544,0.8435296416,-1.1016947031,1.1617139578,-0.2411237210,-0.2124344260,0.0503696166,1.1276808977,-1.8850216866,0.9905751944,-0.1987105459,-0.0699739307,-1.5369192362,-0.4018937349,1.0958739519,-0.5575975776,1.7045712471,0.7433077097,-0.5954273343,0.6866076589,0.9778364897,0.2530172765,-0.1848416775,-0.4636569917,0.2392144501,-0.3474380970,0.8023971319,-1.1096651554,0.8329088688,-1.2316823006,-1.0217108727,-0.3689428568,-0.6006485224,-0.6255954504,-0.6185607910,0.2374453992,0.7998460531,-0.4682604969,0.4123714864,1.7706925869,1.1507540941,0.9583311677,-0.4108321667,-0.1481068283,0.0342794694,-1.1916863918,0.8081879616,-0.9666482210,1.0906995535,-0.1639183015,-1.1320599318,-1.5155814886,0.3599909842,-0.9653348923,-0.7701853514,0.7542246580,0.0639560819,0.2171070725,0.0094398977,0.4814985693,0.6337531805,1.2952977419,0.0742636099,0.6645027399,0.1214422286,0.6358388066,0.5883584023,-0.6672433019,-0.5090835094,-1.8338547945,-1.2418490648,-1.8587424755,-1.2738869190,-0.4197821021,-0.1913201660,0.8862715364,0.2564136982,0.2612314522,2.2699978352,0.9013975859,-0.6366124749,0.4804432690,-1.0621896982,-2.1655814648,-0.9202276468,-0.6696566343,-0.5409637690,0.7462758422,-0.3009483218,1.7442085743,0.2338610142,0.0837169215,0.3850113153,1.1419742107,0.5510025620,0.8352980614,0.4338721633,0.4724246562,0.2723473907,1.7705891132,-0.2735621929,-0.6433638334,0.6840257645,-0.2410134673,1.8150671721,-1.8267018795,2.3056502342,0.3518390059,-0.3171675801,1.3055222034,0.8078785539,1.3020491600,-0.9885943532,0.8765869141,-1.5162200928,0.2587037385,-0.6520469189,1.3673703671,-1.5630866289,0.9796712399,0.2590078712,0.4991450906,-1.1541076899,-1.1035073996,-0.3751842976,-0.9048180580,0.3524917662,-0.8524733782,-0.6322894692,-0.4022717774,0.6911383867,-1.1806863546,0.0684107095,0.5824618340,0.4333196282,-1.2544018030,-2.2081205845,-0.9804613590,0.1319895834,0.9541259408,0.3229891062,0.0549656115,1.7258254290,1.1441347599,0.7627381086,-0.3379273117,-0.0155780120,0.1145182028,0.0303633697,0.4696642160,-0.2231311798,-0.1135704070,-1.4808541536,-1.3070743084,-0.8091095090,0.2676424682,1.4319150448,-0.1194170862,0.3829805553,-0.4280880392,-1.2592542171,0.5967583060,0.0245815534,-0.5553333163,-0.0784272552,-0.9085083008,-0.2988561690,0.0019547611,1.6142442226,0.0618199073,0.1645226181,0.6071572304,-0.9973375797,1.0976777077,1.4667928219,-2.1746215820,0.3314406872,0.0927470177,-0.2048122436,1.4143673182,-1.1663620472,-0.2159975767,1.9280686378,0.7685463428,-0.1528172344,0.0260222536,-0.7631306052,-0.7862910032,-0.2226518989,0.5308263302,0.8197928071,-1.6154203415,0.3681326807,-0.7986581922,-1.6969778538,-0.8310033083,-1.1390073299,0.4657533169,-0.0444163941,-0.0632248893,-1.8191641569,1.0638192892,-1.3606250286,0.6245934367,-1.3430202007,-1.1037573814,0.2160263807,0.8564948440,0.1884693950,0.1738087684,0.0949733108,-0.9783391953,2.1088376045,0.8860807419,-0.1600560844,-0.9818916917,-1.6848745346,-0.4343046248,0.6651635766,1.9885319471,-0.2870945036,0.9635787606,0.0447185487,-0.4152676761,-1.3084661961,0.5204074383,0.5992215872,1.9145693779,-0.8939692974,1.0495287180,0.2583296001,-1.0402622223,0.6333838105,-2.7544460297,-1.5477565527,-2.1013078690,0.0633282438,-1.1671156883,0.2825079858,0.6212230921,0.2638114393,0.5210747719,0.2484542876,-0.3608361185,1.8238667250,-0.1757961065,0.4721578658,-0.6213430166,0.2073867470,0.0125586027,-0.5172837973,1.1994928122,0.4062629342,-1.2676839828,-0.5387573242,1.6995825768,0.4816310704,0.8849418759,0.2497922778,-2.0610547066,-0.8003373742,-0.2149155587,-0.2607664168,0.0678154752,-0.1214217842,-1.7614785433,0.4538424313,1.5986852646,-0.5152428746,-0.9982887506,0.2431342751,1.0021549463,0.7107254863,1.2005827427,-1.3013552427,-1.7587054968,-0.8021962047,0.9416404366,-1.0701202154,1.7020624876,0.8600663543,-0.0366093032,1.1781638861,1.1968842745,-0.5840277076,-0.0184764396,-1.8357027769,0.4158545732,0.3273654580,-0.3873716891,1.6004836559,-0.2800341547,0.7892519236,-0.1054666266,0.5070289969,0.3303568065,-0.4675278366,-1.6173273325,1.1189441681,0.3584862351,-1.4084955454,1.0983003378,-0.1029772460,-0.9113822579,-0.6339533329,0.0714032203,0.6224611402,-0.5115113854,1.3892023563,0.5634469986,-0.6348069906,0.2799148262,0.2578309178,-0.7327276468,-0.6066296697,0.5482274890,-0.9846584797,-1.4991323948,-2.6056971550,0.5932595730,-1.4395385981,-0.7592237592,-0.9646526575,0.6389320493,-1.6647413969,0.7618963122,0.5511775613,0.5638883710,0.0919290781,1.2376972437,-0.4143681824,1.6608420610,1.1134301424,-0.3549555540,1.1900693178,-0.2941959202,2.0036094189,0.1889229864,0.2768132389,0.3631108105,-0.4527046084,-0.0876503065,0.4518642426,1.2216837406,-0.5853601098,-1.2460826635,1.4365702868,0.3918838799,0.4344147444,-0.3103542626,-1.4794760942,-1.1437619925,1.4064294100,0.8123748302,-0.8287097812,0.0644502342,0.5039708614,0.0464049242,0.6796227098,0.2334593832,-0.0366540141,-1.4885165691,-0.5560668707,0.0822257921,-0.2212876827,1.6971707344,0.1416028738,-0.3375744522,-0.2809337080,-1.0013574362,-1.1856667995,-1.1524541378,-0.0177265145,-0.1572738290,-0.4203666151,2.2288005352,1.6894711256,2.2608036995,0.0578856580,-1.6283227205,0.5768634677,-0.1903793067,-2.0627646446,-0.4917488992,0.8252843618,-0.9127709270,-0.4938484430,0.9456370473,-0.2809567451,-0.3177897632,1.0033947229,0.2217080295,0.8518112302,1.9643433094,1.8874276876,-1.5707550049,-0.8626135588,-0.2519744337,-0.1130561605,1.0470582247,-0.1848319024,-0.7244028449,1.4268809557,1.9367127419,-0.5947025418,1.2139691114,-1.1336416006,0.4106018245,-1.2320458889,-0.0817621946,-0.6174464822,0.8128951788,1.5221180916,-0.2531063259,-1.6988849640,-0.2455919683,-1.8654962778,-0.8597924113,-1.6687711477,0.0930599421,0.9343118668,-0.5308892727,0.9207680821,1.6391845942,-0.0630735978,-0.5165376663,-2.3341619968,0.9599221349,1.2102273703,0.7616304159,0.0274917819,-0.0581777953,-2.3147866726,2.0967600346,1.4149196148,-1.0977212191,-1.6241617203,0.0720105991,-1.2375843525,0.3066580296,1.5010496378,0.2146603018,-0.1769921929,-0.2609245181,0.0112806298,1.3085396290,0.1515700370,-0.1343057156,0.5356020331,-0.3263483346,-0.8350747228,0.9119567275,-0.5826714635,0.1920842826,-0.7925053239,-0.3949542046,1.8459690809,0.3976787925,1.0924711227,-0.2221397012,-1.7229070663,0.4710488021,-0.1177469268,0.7858834863,-0.5207809806,-1.7956728935,0.2063074410,0.1493661255,-1.9783360958,-0.6310718060,-0.5640435219,-0.7965235710,-1.4358403683,-0.9247434735,0.4182759821,-0.7810117006,-0.1456603557,-1.8540166616,0.9421648383,-0.9929693937,-2.0774114132,-0.7155947685,2.6200604439,0.1311487406,0.1741613895,0.1489846259,1.5386333466,0.7290978432,0.3322045505,-0.8202380538,0.5158880353,-0.6750556827,1.3344002962,-0.4489007294,-0.1453179717,-1.0834563971,1.0381031036,0.2068814933,-1.0295704603,-0.3696275651,-0.6469484568,0.3838300407,-0.4384109974,-1.5211050510,0.6330561638,0.1468900144,-0.2644926608,-0.0833066702,-0.1666891873,0.1699847132,1.7822586298,1.4239218235,-0.4095877409,-1.2577289343,-0.2261657417,0.1536862552,-2.4841010571,-0.1690602601,1.1236718893,1.3120075464,0.4703026712,0.7917539477,-0.0024559440,-1.0582803488,-0.8924607635,1.9422979355,0.1470964402,1.5199949741,-1.4546091557,-0.2491374910,0.1628889889,-0.0223796498,0.0273962896,-0.8624451160,-0.3553950787,-1.1562964916,-0.5350723267,-1.1832722425,0.0762151852,0.8057109118,-2.6641361713,0.9860156775,-0.3996573389,1.4996862411,1.6512048244,0.9693275690,0.9770048261,0.5826814175,0.7136456370,0.0839540139,0.2687855661,0.7190995812,0.3238495588,-0.0822469965,0.5498287082,0.8601994514,0.4141937792,0.1921910942,-0.5373055935,-0.0399440303,-2.9793040752,1.1761871576,-0.5453553796,-0.2182899714,-0.3996349275,1.3795903921,0.6229868531,-0.1509124041,-0.4743267298,0.3084315658,0.6045871377,0.2694589198,0.8859691024,1.3523759842,-0.3754374087,-0.0136016058,-0.5773574710,-0.1826155484,1.0299216509,0.9875227809,0.3665340245,-1.8713101149,0.4778993130,1.3742740154,0.8267615438,-0.4324137568,2.3989701271,1.5465426445,-0.7949463129,0.8532446027,0.9856741428,1.3061232567,0.8775233626,-1.6787419319,-0.3526584208,1.4827687740,0.3022454977,-0.1343125403,0.8234794140,0.0794778913,1.1625801325,1.5019149780,-1.1354607344,-0.6904141903,2.9148166180,-0.5319117308,0.8360420465,-0.8598858714,-0.3846859634,-0.8635641336,0.7971241474,-1.5385718346,-0.9597117305,1.4342877865,0.0260773115,-0.6131992936,-0.0396655016,0.0818362907,1.3144561052,1.8665846586,-1.1760950089,1.0667315722,-0.2050069720,-0.5495911837,-0.5504364967,0.3499258161,1.7730232477,1.0658493042,0.0046089194,0.5828529596,2.8937945366,0.7601087093,0.4959368408,-0.3398263752,-1.1179248095,-0.0759203956,-0.7791621685,0.5058390498,0.3832107782,0.6314857602,-1.2179418802,-1.2486593723,0.2801901996,1.0210988522,0.3753940463,-1.4467526674,-0.6495608687,0.0395036824,0.2830541134,-1.3890956640,2.1286034584,1.4011929035,-0.0469790399,-0.0941228271,-0.0834299549,-1.4725753069,0.7305154800,-0.2272632569,0.2950935662,-0.7175719738,-1.7210181952,-0.2352459580,1.8049403429,0.2901862264,0.2384487092,-0.4335539639,2.1697747707,0.5837168097,-2.0065824986,-1.5619883537,0.5572479367,0.6204081774,-0.6503604054,0.3235428333,-0.6237254143,0.0254766438,-0.9556758404,0.9256320000,0.1110662892,-1.3950949907,1.6628248692,-0.5550198555,0.2506259084,-1.2280722857,-0.8849002719,0.2853524089,0.7186892629,0.3485122323,0.4830940366,-0.9126710296,0.0648288727,0.5861564875,-1.1012845039,0.8903179765,-0.5021155477,0.2146847993,1.5970772505,-1.6596252918,1.7038996220,0.5897356868,-1.9231088161,0.1841837913,-0.8422321081,-0.2690632641,0.3078442216,-0.6378785968,-0.2733365893,-0.4018662572,1.1151080132,0.1203839406,0.5301672816,1.9052218199,0.5232292414,-0.5509648323,0.1532472223,-0.6852358580,-0.0168571491,0.2829575539,0.9693676829,-1.3901803493,-0.8579546213,1.6857061386,-1.8683937788,1.1424872875,-0.1706787050,-0.9109064341,-1.0370491743,-0.5145337582,-1.4502618313,-0.8660738468,1.1110023260,0.4196021557,0.2588478923,0.2073096335,-0.7804108262,-0.7706721425,0.2005842775,-1.2953560352,-2.0662872791,-0.1776489168,-1.5487222672,-0.4867807925,0.9630966783,0.0749432296,-0.4267623425,-0.8447555900,0.5929803252,-2.1236004829,-0.0424731523,2.4609448910,-0.9759138227,-1.7832497358,-1.6214101315,0.5515912771,-0.7159795761,0.4605422914,-1.0591150522,-1.1180940866,-0.1050870642,-0.4247130156,0.8251236677,-0.6458255053,0.0270585772,-0.7671965957,-0.6085761786,1.5552158356,-0.6036732793,-0.9812249541,-0.8282076120,-0.2138131559,-1.4566339254,0.5174087286,2.0507590771,-0.1476765126,1.0797405243,1.3560801744,1.0424228907,0.3342956603,1.2495017052,0.7392379045,1.1074708700,0.1809802502,1.7764987946,0.2816728055,-1.9343605042,-0.0202827193,0.3671101928,0.0815860778,0.0512436032,-0.5376491547,0.4952427447,1.7752697468,-1.6656461954,0.1051459163,-0.6446504593,0.8385035396,0.6940054297,-0.5207248926,-0.1721844971,1.7069374323,-0.5153077841,-0.5635568500,1.5965918303,0.1318876296,0.3199602365,0.8840111494,-0.2084402442,-2.4241857529,0.9587558508,0.4362331629,-0.9273656011,-1.2563002110,0.1305574328,1.1341838837,-0.4569153786,0.0596981235,-1.3988307714,-1.5971320868,-0.4953704476,0.7124653459,0.3637164533,1.4194965363,0.6654574871,0.6962931752,-0.0628936514,0.4574303627,-0.8212164044,-1.2626589537,0.7945659757,-0.1253741384,0.2529629171,-0.5118837357,-0.5959960222,-1.4390065670,-0.1195924282,-0.1827707291,0.3372287452,2.5050127506,0.5503866673,-1.8325817585,0.2706216276,-0.2371074110,-0.1965096891,-0.6216363907,0.4986001253,-0.0241942480,1.1589165926,-0.5790826678,1.8832604885,0.2265321314,-0.4650239050,0.8145852685,1.2787189484,1.2368496656,0.2810806036,0.5590633154,0.0165573135,-0.1671055108,0.2981031537,-1.7313406467,0.0702708587,0.9237394333,0.7955741882,-1.0611020327,0.1046951190,-0.6292627454,-1.1767753363,1.6472417116,0.9162951112,2.4193027020,-0.4519712627,0.1546483189,1.0768247843,-0.2482834458,-1.0319919586,0.9817290902,-1.2656478882,0.3102760911,-0.6407822371,0.2745261490,1.4232051373,0.0962205753,-0.5079040527,-0.2026175261,0.4734267294,0.3398221433,0.1162773520,-0.3965824842,-0.0524844863,-1.3785188198,-0.5009530783,1.3419600725,0.4458302557,1.6235131025,0.5704522729,-0.5884652734,0.1655925512,-0.5934273005,0.8961495757,0.1395948231,1.8811582327,-0.4704824090,0.6056877375,-1.8371515274,-0.3883416951,-0.2261543870,0.1075822636,0.8845273256,-0.2323669195,1.0182594061,-1.2435951233,0.1850990653,0.6556530595,0.7260800004,-0.0777541026,0.6657271981,-1.5444598198,-0.4093579352,-0.1104109064,-1.2403335571,-0.7037749887,-0.0475286730,-0.0110759111,-0.3843451142,0.9995355010,0.2956174314,-0.1288992912,0.8820962906,-0.7885088921,-1.3096528053,0.1360455155,0.6605646610,0.4773285687,0.1000278816,-0.2009449899,0.9680691957,0.9661629796,0.3475872874,-1.0521339178,-0.2399311066,-0.6726133823,0.6403880715,-0.2364929765,-1.4091043472,-0.5644134879,0.7580716014,-0.1551982909,0.0443324931,-0.6542751789,0.1354361475,0.1713111103,0.3366525471,-1.1363209486,-0.8197965026,0.9096105099,-0.3897396922,-1.1618636847,0.2323047370,-0.1626732200,-0.3283954561,2.0063948631,-1.6640892029,-0.2251854539,-0.5884788632,-0.7459271550,-0.3304202259,0.5145342350,0.0916930512,1.8832346201,1.8666164875,1.2778718472,-0.6346173882,-0.6968966126,-1.2571614981,-0.0928414315,-0.8907172680,0.4955960512,2.0003273487,0.3299041986,0.5431902409,0.9838431478,-0.6571618915,1.1528811455,-1.0470914841,1.3171378374,0.2243078053,0.3119038641,-0.3337868452,2.0032920837,-1.0856931210,-1.9538714886,-0.1341106296,1.0241699219,1.2208647728,-1.6466290951,0.2385760546,-0.1349076927,-0.9472653270,0.3611437976,1.8478543758,-2.3713274002,-0.9970322847,-0.0145900678,0.6273401976,-0.2074701786,0.3642231822,0.8874557018,0.6856731772,1.0776827335,0.4891940057,-0.6078050733,-0.3043553829,1.4372410774,-0.9145619869,-0.1745103747,0.8110514283,0.5476842523,0.6497424841,0.5543809533,-1.0524549484,-0.6980483532,0.3797794580,-0.8720604777,-0.0382295512,0.1213534698,1.2860654593,0.6915104985,0.9888854623,-0.4740723670,0.3520619273,0.6744676232,-0.4462754428,-1.4237420559,0.2925428450,-0.4372058511,0.7580588460,-0.1709490865,0.2753054500,1.5881859064,-0.8896048069,-0.9051228166,-0.0149402972,-0.0148151759,-1.5531495810,0.0139444396,0.5084567070,-0.8614171743,0.5642536879,-0.5657557845,-0.1187821403,-0.4563186765,0.3088122904,2.5398862362,-0.0289198011,1.4139448404,-0.8513980508,-0.1655536145,1.7412998676,-0.0283007547,-0.6911320090,0.6281622052,0.6107546091,0.6955740452,0.9466020465,-0.4255324900,1.3051526546,-0.6912388802,0.7697520256,-1.6392782927,-0.4025473893,-0.1954599470,-0.0032584365,-1.1283636093,0.8464527726,0.1064395979,-0.3436134756,-0.9426211715,0.5683631301,0.4941053391,-1.6244103909,0.4565205276,0.7516614795,0.6100686193,0.2671549320,-0.4684554636,0.4916934669,2.2799537182,-1.0597896576,-2.0844984055,-0.0247393716,-0.1110131443,-0.0192019120,-0.8450926542,0.2091219872,1.3058104515,1.6750828028,0.6700471044,-0.2928491533,1.7783085108,1.0262509584,-3.0318641663,1.6394308805,0.4991608560,1.4980392456,-0.1323428154,0.6211748719,2.0379743576,-0.5224591494,0.3273642361,0.1952998042,-0.4680666924,0.4209490120,0.5322787166,-0.7942463160,-0.5132656097,2.5295221806,-0.4084399343,-0.2231356502,0.1975568682,1.2763007879,-0.6899693608,1.0642337799,-0.5653979182,-1.2869952917,1.2466315031,-0.1241233274,1.0194280148,0.2496183366,-0.1709581017,1.7310829163,-0.1135782599,-0.1945802718,-0.4631730318,-0.1747877598,0.2316061854,-0.2133623809,-0.7444867492,1.7741721869,-0.5213237405,-0.0052383416,0.6835482717,-0.2477262169,-1.1038888693,0.3005446196,-0.9216147065,0.0160131194,-1.3955249786,1.8256142139,-0.2967949808,-0.6049112678,1.0554323196,-0.0910923630,-1.7532095909,0.6685379148,-0.2274804860,-0.7936704755,-0.6907336116,-1.1049113274,-0.4015493691,1.2235264778,0.0144734150,0.1218120903,-0.3425313532,-0.0198845416,0.4693568945,-0.1412683278,-0.1441329271,-1.2095980644,0.3068394065,1.4111222029,0.1158419624,-0.9842948318,0.3015630543,1.1471153498,0.7848933339,-2.0293517113,0.5302294493,0.2043271512,-1.1321178675,0.6940064430,0.8048830032,-0.0286177434,0.1219166294,0.6416437030,-0.4542204440,-0.4865248501,-0.0323937610,0.2326822728,0.7127761841,-0.7575730085,0.7263642550,0.0730553716,-0.2330107689,0.6749507189,-0.0529052541,0.2778891921,0.6335431337,-0.9314393997,1.5075997114,0.0337050445,-0.5642749071,-0.7681024075,-1.2881439924,1.7528229952,1.3125530481,0.1685075015,-0.4345751405,0.6745186448,0.4473234117,3.4154362679,0.0939195305,1.4169496298,-1.7073221207,0.1352761835,0.6206020117,0.1212979928,-1.6183773279,0.2478966564,-2.0915911198,1.3072786331,0.0073723211,0.1456651837,-0.5119955540,0.6050021648,1.0283262730,-0.7437700629,0.6922110915,1.8326694965,0.3287743926,0.9887950420,-1.2720338106,-0.8566733599,-0.4071277976,0.6455544233,-1.4670102596,0.5637975335,0.0863739476,1.1576341391,-0.5866075754,1.1902070045,0.4292430878,-0.6513916254,-0.2522836328,-2.7996482849,-0.0108595164,-0.3560985923,-0.0908001214,0.9481230378,-0.9476252198,-1.5085779428,1.0062683821,-0.8160352707,-1.3991876841,1.4791408777,-0.1391293257,-0.2057078928,-0.8553714752,0.5186762214,0.5040826797,-0.8638767600,-0.9191851616,-1.3979185820,-0.6784217358,1.2306538820,-0.9332259297,0.7083811760,-0.4577125907,-0.0620121956,-0.0351362042,1.0652267933,-1.1760458946,0.0446300060,-1.5669469833,0.4134811461,1.5374922752,0.0544624180,1.0646126270,1.5449422598,-0.4001969397,0.2695350945,0.8955142498,-0.1994645745,-0.8738275170,1.7183253765,1.0541538000,-0.6865471601,0.8660798669,-0.9972230196,-0.0987603590,-1.1042673588,-0.1311311722,1.1802910566,-0.4166555107,0.1959019303,0.1618142575,1.2000273466,1.7318041325,-0.7448762655,-0.6215144396,0.8590826988,-0.9501357675,0.2647697330,-1.0188965797,0.1645448953,-0.5019816756,-0.1122976840,-0.7125408649,-1.6597757339,0.0543932766,0.6145295501,-0.9701308012,-1.8752157688,0.5507056713,-0.3657512069,-1.3984634876,-2.3039720058,0.5814130902,0.9320523739,-0.6677701473,0.4140245020,-0.2230456620,1.1848533154,-0.2327275574,-2.3117311001,1.0083969831,2.0880084038,0.7807578444,-0.2806711793,0.3659831285,0.3532699645,-0.1186335459,-0.2383485287,-0.2226555645,-0.1092954203,-0.7526459098,0.0635053217,-0.4191754162,-0.3093976378,-0.3990128934,-0.5901996493,-0.6269081831,0.5943827629,0.9215744734,0.6849617362,-1.1751044989,-0.1513048857,-0.4341301620,0.8947159648,0.0362598374,-0.6948597431,0.9275332093,0.5545841455,-0.4738935828,-0.1504694670,2.4883825779,1.1122415066,0.1489479244,-2.0799446106,-0.3141900599,0.5396690369,-1.3634753227,-0.9709356427,-0.3622013927,-0.3671687841,-0.1727541834,-0.7378624082,0.5973001122,-1.1517913342,1.4300465584,-0.7156851292,0.8373429775,0.2585847974,0.1721901596,-0.0018438506,-0.8097422719,2.1313259602,0.7968180180,-0.2775542736,0.8631947637,-0.8420573473,2.7444453239,-0.6136727929,0.3800564408,-0.2119310200,-0.4017619491,-0.4494703114,0.4593496323,0.5182594061,1.0070230961,0.3051910102,-1.7294261456,-0.3718368113,0.8044009209,-0.5573958755,1.2480124235,1.8836368322,-0.1714086086,0.0244216826,0.2147856355,0.6537339091,-0.6575426459,-1.7292504311,0.3809339404,-0.5554701686,0.8253012896,1.0695204735,-0.8808111548,-0.4070812464,-0.5109980106,-1.3897756338,-0.0042871847,0.4558518827,0.4185920954,-0.2674489021,-0.3960486948,0.8053077459,-0.1883954406,2.6233503819,-0.1203388870,-1.6325961351,-0.5712729096,0.0376099385,-1.0410552025,-1.2952389717,1.7780630589,0.2537894547,1.2101197243,-0.5471873879,-2.1763610840,1.1458199024,0.3720822334,1.6003818512,-0.4095530510,-1.9625519514,-1.5254100561,1.0795557499,0.6412642002,-0.2453266233,-2.3478925228,0.6769649386,0.3459262252,1.0892885923,0.0059136492,-0.4414263368,0.0774223357,0.4073279500,0.9646092057,1.3409656286,-0.5068500638,-1.1570055485,0.4112512171,-0.8605152369,-1.1234155893,-0.9586995840,-0.6890590787,-1.5872890949,-0.4864371419,0.0497915000,2.1994481087,-1.7377170324,0.6416237950,-0.7923098803,0.1304780692,0.3397642672,1.4351961613,0.2319086790,-1.0006706715,-0.3280332685,-1.0791562796,0.9721171260,0.4853863418,-0.9484644532,0.3009895980,0.3293378353,-1.5128226280,0.9338934422,1.1475496292,0.0169203840,0.3695321083,0.0343017913,0.5545833707,-0.5545576215,-0.3831988275,0.8395510316,1.2106777430,-0.3786276579,-1.2317663431,-0.2997151911,0.9177377224,0.9696442485,0.3414999843,0.8652888536,2.6955928802,-0.3250256777,-0.9790326357,-1.0462377071,1.8175184727,-2.4941484928,-1.0403255224,-0.5982604027,0.2539756596,-0.7462789416,-0.9838350415,1.3585087061,0.1825647354,-2.0929007530,0.4379278719,-1.1159633398,0.8405852318,0.5710203648,0.6748986840,-0.3078625500,0.2797708809,0.1595890224,0.1293483973,0.2212487906,-1.0180786848,-0.6851283312,0.5324478745,1.7520087957,0.7664175630,0.6118838191,1.4230185747,-0.0700611845,-0.3144167364,2.0584418774,-1.1153713465,-2.3753750324,0.0852801129,1.0693234205,0.3637231290,0.5887388587,-0.4191713929,0.1261838675,-2.0334804058,-0.4840212762,0.2973466516,-0.5006974339,0.9281368852,-0.1265035123,0.4268484414,-0.1641852856,-1.4899976254,0.7738882303,-0.1064092964,0.9350059032,0.7224861979,0.6837131977,-0.2813137174,-0.2018849254,-1.4496183395,0.2822894156,0.6741409302,0.5833388567,-0.3834654987,0.9216980338,-0.5402904153,0.0449905135,1.6210678816,0.4038809836,0.8260396719,0.9907310605,-0.1848691553,-1.2419217825,0.9926421046,0.6334283352,0.8985478878,-0.5619766712,-0.8210536242,0.1006678417,-0.0309645627,-0.0446182489,0.7577447295,-0.6273584366,2.8296339512,1.2464458942,-1.1661547422,-1.5976299047,-1.6750463247,-0.6959130764,0.4801782668,-0.3721280694,0.2400489748,0.3327723145,0.3250359595,0.5707746148,-1.3501437902,0.2438921332,0.8684121370,0.0373390540,-0.4162268639,-1.5516031981,0.4893818200,-0.9510130882,0.4297042787,0.3235373199,0.1469300836,0.7171718478,-0.2045047581,-0.2003860474,-0.9752749801,-0.8899661303,-1.1855645180,0.3116814792,-1.2083834410,0.3561777174,0.3181398809,-1.3351159096,0.2889765501,-0.3798525333,-1.2264633179,0.1558524966,-1.3657807112,0.0333562158,1.3740893602,0.2170120925,1.4955347776,0.0376551785,1.0529077053,0.9597856402,0.1183744967,-0.0969234258,0.6593038440,2.1102674007,0.8496427536,-0.9985044003,0.6058217883,-1.0085011721,-1.0398656130,-1.0336683989,-0.0988367200,-0.6505918503,0.9194741249,-0.7106096745,-0.8037624955,-0.6252217293,-0.7874242067,0.9015535116,0.0489723794,-0.3165658712,0.4750823081,-0.8362310529,0.5985621810,0.0831746012,-1.9769351482,0.4109248817,0.9616567492,-0.1925200224,-0.6872479916,-0.0291667711,0.4817531705,-1.2618397474,0.8041153550,-1.0452064276,0.9234446287,2.3404836655,-0.5770075917,0.1780190021,-0.6452456117,0.1780572832,-1.1206645966,-0.7152308822,-0.9273412824,1.5543338060,-0.9651429653,-1.2783868313,0.3413947523,-0.3924708366,-0.6756599545,-0.1602455676,-0.1887249947,-1.0889669657,-0.3058025539,-0.9298772216,0.9752748013,-0.1857045293,0.3902679384,2.4783458710,0.6216580868,0.8140361309,0.5323762894,-0.1220407784,-0.1911884248,0.9695015550,1.7107357979,-0.8332494497,1.0158033371,-1.3568849564,0.3202181160,-0.4249622524,1.0535852909,-0.0648548529,-1.1206247807,-1.3313488960,0.2760379314,-0.8660236001,-0.2355240434,1.1059592962,-1.0518497229,-0.8911786079,0.4755552411,-0.4749928117,0.8618794680,0.8533287644,0.0164538156,-0.1435441524,-0.2964879870,-1.2023267746,-0.0720503479,-0.9484385848,-0.2501189113,0.6416484714,0.7757827044,0.7773790359,-0.2722290456,-1.0522669554,0.5333345532,-1.8526387215,0.3252865672,-1.0955603123,1.5631155968,0.6736435890,0.1962209195,-0.0650429949,-1.5892469883,2.2871513367,0.5928719640,0.5669403672,0.2304450274,-0.4885673523,2.0260953903,-0.5616394281,1.2725027800,-1.2598658800,-0.7209414840,-0.8498359323,-1.6869456768,-1.4535824060,0.6325818300,0.8368428349,-0.0728568211,-0.8834574223,1.3237099648,1.5845621824,-1.4369770288,0.1884049624,-0.3132542372,-1.3461782932,-0.1914197803,-1.0135910511,0.4060253203,0.8252695799,0.5558263063,1.1091421843,-1.1206122637,2.4767508507,0.5643259287,0.9157356024,0.5002053976,0.7908154130,0.8274473548,-1.7692761421,0.7141329646,0.4376039803,1.3221139908,0.1192799956,0.1986379474,-0.6428962946,-0.8024330139,-0.6532709002,-0.6049788594,-1.2296186686,0.6375156045,0.9582261443,1.9821717739,0.9358143210,0.8946135044,0.0913714394,-0.6747932434,1.0523104668,0.0653479770,-0.7234938145,0.1506555378,0.2563973963,0.6422882080,-2.1984939575,0.1423068494,1.3988722563,0.9099609852,0.4305366874,-0.0558515005,-1.2119708061,-0.4905354083,0.4168024957,-1.1127213240,0.2744130790,-0.9005704522,-0.2425050139,0.9652739763,-0.1550932974,-2.7414751053,2.7117772102,-1.4189043045,-1.0313910246,1.4430273771,0.3495107293,-0.1600436270,-0.4971172214,-0.6566462517,1.7511360645,2.6167964935,-1.6863998175,-0.8562343717,-0.9014871120,-0.5291117430,0.0483883694,-1.5449298620,2.5941178799,1.1498541832,-0.8130968809,-0.9091265798,1.7938588858,-1.9932663441,0.1483443230,0.5673434734,0.3636609614,-1.4151256084,0.9914378524,0.3327944577,-0.7365987301,-1.1241701841,-0.3251023293,-0.1126096621,-1.0407176018,0.2644003928,-1.2129006386,-0.6472233534,2.0263800621,-0.2055637240,1.1558588743,-0.5569451451,1.0327348709,2.9583289623,-0.0690718144,-0.1696743220,-0.2801229656,-0.1217102259,1.6591004133,1.0041955709,0.7745190263,0.4571551681,0.2016106397,0.6540086269,0.6006768942,-0.6057759523,-2.4989545345,-0.4389500022,-1.1566992998,0.2245195806,-0.1928787529,1.0130279064,2.8678760529,3.4200766087,-1.1019076109,0.7968271971,0.3168827593,0.9232071638,1.5975202322,-0.4766547978,0.1227640808,1.5033007860,-0.1045565084,-0.5908822417,-1.4120235443,0.3343747258,-0.6939716339,1.3138922453,1.7582516670,-2.0948252678,-0.3867600262,1.4881784916,-0.2614794075,-1.0096803904,-0.8288538456,1.1242891550,0.8932532072,-0.7381454706,-1.5702298880,-0.6367726326,1.0390914679,-0.6599599719,0.1851871461,0.2441084385,0.1874911785,-0.2299124449,-0.0557615831,1.2884424925,-0.4906115234,1.0648677349,-0.7498172522,1.3501983881,1.2616695166,0.9143901467,0.1215201989,-0.1740020961,-0.8299691081,-1.3438180685,0.6896972060,0.2989670038,-0.9304523468,2.1257295609,-0.3191212714,-0.9800383449,0.9961398840,-0.3433336616,-0.9051725268,-0.5238730311,-0.1880698651,2.2426862717,0.3711197674,0.4215188324,1.9264063835,-0.8985811472,0.9724038243,0.9724006653,0.5963121653,-0.1313816905,-0.9208067656,0.0731222332,-1.0595364571,1.7986855507,-1.4451892376,-1.6628885269,0.1031904817,1.8886716366,2.1079497337,-0.0436575674,1.6163161993,0.7489252687,1.0819302797,-0.6431999803,2.6041235924,2.1054654121,0.1228456721,-1.3445225954,0.2740955949,0.8061972260,-0.7437826395,-1.1212561131,1.0593879223,-0.7465335727,0.6351316571,-0.1259510219,0.7468909025,0.9277933836,-0.6623082161,0.9495425820,-0.3312621713,0.3156095445,-0.0621979199,0.2871080637,0.5507833958,0.7471680045,-0.1918139458,-1.0566934347,-0.3854509890,-0.9094166160,0.3269947469,1.6029323339,-1.3439395428,-1.0700266361,0.8704138994,1.7585107088,0.8698053956,0.1614292413,-2.1836338043,0.4575574696,-0.3837276399,-0.7936035395,-0.7575538754,0.7196499109,0.3993514776,-1.1120111942,-2.4084584713,1.1744660139,0.6642578840,-0.1801867336,-1.1095536947,1.8082687855,-0.5784759521,0.7034670711,0.0047463123,1.9643903971,-0.6102766991,-2.0074377060,-0.0763465017,0.2575736046,1.8768074512,-1.2388337851,-0.7563742399,0.5345876813,-0.8474777937,0.0104724141,-0.0560626648,-0.2254574150,0.7342847586,-0.1823126227,0.9410361052,0.1615654975,1.0111799240,-0.9020431638,-1.2960655689,0.5210303068,-0.0611365028,0.1001681834,0.7305082083,0.5266997218,-0.6311574578,-0.1671253741,-1.4037280083,-0.2443351150,-1.2517610788,-0.6421838999,1.4461832047,0.2268501073,0.0399844833,0.7946876884,-1.2721235752,1.2676312923,0.3134599328,-0.3629707396,0.5874877572,1.3795229197,-2.0228421688,-1.0742843151,0.7796605825,1.8933137655,-1.9481340647,-0.7232157588,0.6457300782,1.0992538929,1.2602574825,1.2173357010,0.3225525320,-0.8072761297,1.9048274755,0.2093349546,0.0960786119,-1.5297433138,-2.1362874508,1.6078487635,-0.0083657373,-0.4866380692,0.3900962174,-1.9635704756,0.3925728798,-0.9276992679,0.9480867982,-0.4484598935,-0.2534022331,1.1133691072,-0.4018307030,1.1105887890,0.0697086081,-0.0130785871,-1.2711316347,-0.4720092714,-0.6093285680,-0.3815086186,-0.2593854666,0.6868306398,0.2982982695,-1.0888745785,-0.0356637649,-0.7768434882,-0.8902729750,-0.7600454092,-0.4218118489,0.3945529759,-1.7036703825,-0.6038737297,-0.6489652395,0.7995288372,-0.2697657645,-0.2542925477,0.1636188477,1.6742730141,1.2430789471,-1.2469968796,-0.3124547601,-0.1815218925,1.0640125275,1.8174276352,0.1209504902,-0.2399097234,-2.0230894089,-1.1016820669,-1.4689011574,0.1792734712,-0.1051847711,-0.5941409469,0.1108767465,0.5730710626,-1.2479622364,-1.0237392187,1.3488510847,1.1845982075,0.3580740094,0.9250638485,-0.2230274081,0.1302635074,0.6828508377,0.7219886780,0.4433879852,-0.5854877234,0.7401592731,0.8713111281,0.2033105642,-0.5434444547,0.3103612363,-0.2429424971,0.3660286367,-0.9809601307,-1.3397420645,0.1668384820,-0.2828427851,0.4434334338,0.5371432900,1.9583348036,1.2049523592,0.2372088730,-0.3331832886,1.1592470407,0.2292878628,-0.7659143209,-0.3226299882,1.0478326082,-0.0462466627,-0.0130897462,-1.5684120655,-0.3709748387,0.9952441454,0.5843552351,-0.5555575490,-0.9959812164,-1.1858104467,0.3064933121,-0.3683856726,0.9699641466,0.9785125852,0.0002325818,-0.4245741367,0.3247098625,-0.1118231490,-1.9157896042,0.2442909628,-0.5570378900,0.1214372441,1.2457281351,2.3516080379,-0.0346703567,0.2227616310,1.0316162109,-0.3360175192,-0.1249095425,-1.2381279469,0.5380402207,0.2509429753,1.4545207024,0.3763480484,1.1317685843,0.1574275047,-0.4038485885,1.0350737572,1.5813468695,-1.2058871984,1.8397190571,-0.5369747281,-0.1675504595,-1.6808416843,-0.3973738253,0.8955420256,-0.9474033117,0.8863657713,-1.3639428616,-1.1407256126,0.0768821016,0.1626100093,1.1859166622,0.8617249727,0.0092263343,0.5938783288,-1.6519448757,0.4657230377,2.0321743488,-0.6253198981,0.4228032529,0.1740853935,-1.1310549974,-1.1406570673,-0.3442859054,1.0565874577,-0.2801092267,1.8965030909,-2.4183242321,-0.1742828339,-0.7835971117,0.2747937143,-0.6171855330,-1.6374839544,-0.0998052806,-1.5593715906,-1.2759281397,-1.4176751375,0.7536286712,0.8720196486,-1.2819939852,0.7087141275,1.9042751789,2.7620675564,1.1157127619,-1.0292673111,-1.2326740026,0.4892507195,2.1081411839,0.4370924532,-0.5593727827,-1.4354031086,1.0570830107,0.4167571962,-1.1469852924,0.4386380911,0.4627600610,0.0152175874,-0.5675275326,-1.2706890106,0.3094842136,0.3353318870,-0.5180909038,1.4484337568,-1.8907704353,-0.0004836629,-0.3969363868,1.0633287430,0.0843856484,-0.1612736881,-0.0583505481,-0.0020569484,0.0918041766,-0.5388286114,0.4628135860,-1.0131388903,-0.4627156258,1.8314408064,-0.5217072964,-0.1163138002,-1.9294489622,-1.0067454576,0.5082025528,-0.3337702453,-0.2269964814,-2.1366028786,0.1338530332,-0.3698782027,-1.0692406893,0.3903188705,-0.0497018024,1.1616665125,0.9621710777,1.4915152788,0.1182670668,1.5708578825,0.7640832067,-2.0470445156,0.2740463912,-1.6569459438,-0.2085611820,-0.9933959246,0.7703897953,0.1919436753,-0.1551560611,0.5901817679,-0.7839456797,0.5055692792,-0.6600452065,-2.1255404949,2.5530233383,-1.4889702797,0.6624996066,-0.8144878149,1.2584605217,-0.6314144731,-0.9057261944,0.0311285201,-0.8325083852,0.3457152247,1.0724612474,-0.1779902279,0.6224679351,1.1843028069,0.3990680873,-0.3444859684,2.2503702641,0.5720024705,-0.6524844170,0.8113818169,0.6207444072,-0.2953625619,-0.2325160801,0.5621783733,-1.1866376400,-0.2479910105,1.3240972757,0.4694396853,-0.8371084332,-1.1386457682,-1.5861579180,-0.1940881610,0.5150237679,-0.7020881772,-0.1579501629,-0.3900207281,-0.9069029689,0.2974373698,1.0060987473,0.3582396507,1.3689446449,0.8325985670,-0.6259139180,-1.0219625235,0.8717699647,1.5553936958,1.9892309904,1.7129807472,-1.7524341345,-2.4156734943,0.3734627664,-0.9791836739,-1.1838378906,-1.6001518965,-0.2521800399,-0.9588496089,-0.0467710644,1.4703460932,-0.1281604916,1.9166052341,-0.7853434682,-0.8153104782,-1.2059153318,-0.0041961134,0.8652752042,-0.1252185553,-0.3175365925,0.0003913178,-0.8116727471,-0.1722526997,0.2703862786,1.1430435181,-0.0179268271,0.5940791368,-0.0597756766,-0.7731306553,1.7648396492,0.6532765627,-0.0256540347,-0.2082199454,-1.4125479460,-0.2929659188,-0.0797623321,0.4935064018,0.6900241375,-0.8711327910,0.2377964407,-1.3421390057,-1.0594630241,0.8106474876,-0.9261490703,0.0168073885,-0.1170370802,0.4168663323,1.3247480392,1.9524668455,-0.7113932371,0.8084810376,-1.1566987038,-0.2625491023,-0.1377955228,1.8415939808,0.2191815525,-0.3335691094,1.3335675001,0.6392911077,0.2304753959,0.1254295856,0.4711110294,0.5567567945,-0.1583541334,-0.1846426278,-0.3851806819,1.0271519423,-0.0131389173,1.4698441029,-0.5619645119,-0.0572414175,0.5521336198,-0.3570716977,0.4461381435,1.5787917376,-0.2964460850,-0.6109013557,0.5612183213,2.4743282795,-2.0427081585,0.7436702251,0.5880488157,0.1136561483,0.4198854864,-1.5047591925,0.5283017159,0.4352711737,-0.8595504761,-0.1644246876,-0.3773303032,-0.6257966161,-0.6975237131,0.4315404594,0.1575031728,0.5167097449,-1.4270300865,0.4468098283,-1.6486895084,0.4399907589,-0.2159845680,1.4771642685,-0.0137156723,-0.0051958985,-0.0996746719,1.8157832623,1.2126486301,-0.8141968250,0.0797947198,-0.3740171492,-0.0235440154,-0.4075264931,-1.5856205225,-0.8143793941,1.2097389698,-0.6563789248,0.0917219445,-0.2388767302,-0.5819990039,-1.9098675251,2.0859701633,0.4343566298,-0.4059936106,0.4935959578,1.1469419003,-0.8147927523,-0.0642666221,1.0216310024,0.2484840751,-0.2188244909,-0.4161131978,0.9300234914,0.8221677542,1.3278201818,0.7848719358,0.7350556254,0.3275857270,-0.9404194951,0.8318222165,1.3112833500,-1.7765289545,-1.7815247774,-0.3423713744,0.4871589839,-1.4034453630,-0.3804571629,0.4861087799,-1.2812838554,-0.0835635960,1.6544206142,-1.2440884113,0.8436793685,0.7396528721,1.1865768433,0.0844733939,0.1610046029,-1.5059672594,-2.0161046982,0.4744549394,-0.1027829498,-0.8932421803,2.6681511402,0.8733780980,-0.6771495938,-2.1171841621,0.4179076850,-1.5294778347,0.6122385859,-0.5188607574,0.0253527220,-0.5863035917,-0.6137494445,-1.3239506483,-0.1866202801,1.4357578754,-2.6238973141,0.9697104692,1.3150304556,-0.1740820110,-1.2808016539,-0.7015659213,-0.3883333206,-0.0155479601,-0.5180083513,-2.6574621201,1.2562646866,1.7780845165,-0.8762903214,0.4460975826,-0.5522505045,-0.1025809869,1.6547645330,0.4384832084,0.8500418663,-1.0074121952,0.8443838954,0.3932457268,-0.2968220711,-0.8347958326,1.3171423674,0.9378548265,-1.2623959780,0.7586356401,0.2216345519,-1.1635854244,-0.2694393396,0.7349928617,1.1965305805,-0.4751051366,0.2625339031,-0.5044584274,0.3648485243,0.6711106896,0.8469839096,-0.0794413686,1.4676808119,-0.5880222321,1.2756909132,2.1141371727,1.2257579565,-3.1443977356,-0.8633837104,-0.4782708287,0.7528486848,0.0728427917,-0.1478959173,-1.8716983795,-1.2341648340,1.9306218624,0.4773486257,-0.7664555907,1.0502686501,-0.6320495605,0.7806579471,0.5659831166,-0.7911544442,-1.2014272213,-0.4031826258,0.3939342797,2.0412855148,-0.5606901050,-0.3510407507,0.4227169454,-1.3822602034,-0.2495191246,-0.4121963382,-0.4797803164,-1.6132888794,-0.1541571766,0.5172279477,1.8714196682,-0.8915430307,-1.0249711275,-0.4603399038,-0.8396726847,-0.2851386666,0.4890405834,2.7800784111,0.2114791274,0.5173261762,-0.4926160276,-0.5128554702,0.3635650575,-1.2499142885,0.1577661932,-1.1878240108,-0.1372671872,0.2076225579,-0.9449370503,-0.6277039647,0.0855376199,0.9168802500,-1.4615525007,-0.8221495152,-0.0306883696,-0.3794527352,0.6988317966,-0.3404355347,2.0155558586,-0.9869990945,2.3109531403,0.8517220616,-2.0357089043,-1.3717461824,0.4539968669,-0.3938590884,-1.1531527042,-0.6132876873,1.6227045059,1.5988278389,-0.4305523634,-1.5203722715,-0.2126695216,-0.7949711084,1.0062519312,0.1088095903,-0.1143707111,-1.5254942179,-0.5971631408,0.0266929027,0.1798896790,0.6165832877,0.1774144769,-1.1522259712,0.3164618611,1.3300391436,1.5971671343,1.4609972239,-0.1620344818,-0.0415391847,1.7246509790,-0.3874904513,2.1607668400,0.3433647454,0.3206478953,-0.6261118650,0.5304078460,0.0695448145,-0.0012609762,-0.5348551273,-0.4886779487,-0.1492735595,-1.1154803038,0.2743631601,-0.8677986264,-0.8241101503,1.0104525089,0.6254281998,-0.9113668203,-1.6015820503,1.7713805437,-1.2572556734,0.1901635826,2.1025061607,-0.0653650835,1.8718448877,-1.3963491917,2.3231360912,1.5577259064,-1.4847933054,0.1091064811,0.1189436316,-1.8201619387,0.9907189012,0.7037143707,-0.1040920019,-0.3882758319,0.6091170907,-0.3306565285,0.2832741141,-0.2206534594,0.8937234282,-0.1409606785,0.9197987914,0.9479706883,0.4320091307,0.8930882215,-0.2672516704,-0.2465402484,0.1139625460,0.5704907179,0.3211796284,-0.7757544518,0.2262502760,-0.6387628913,-0.5648298860,-0.1335153878,-1.9806940556,0.8351049423,-0.6341540217,0.2234416455,0.7767619491,1.0302518606,1.2044047117,-0.6560946107,-1.1046437025,-2.5660791397,0.7642706633,1.7174856663,-0.2373072505,-1.4493148327,-0.0723819956,1.2432292700,1.9301974773,-0.0527655259,1.5347336531,0.7458348274,-0.3054525852,0.2830949426,0.7241360545,0.4799636900,-0.4515165687,-0.9522143006,-0.2386518270,-1.5671073198,1.1002331972,0.9565708041,-0.0753502250,0.3522382975,1.5541101694,1.0659878254,0.2211657315,0.7039881349,1.3312822580,1.1425888538,-0.8043620586,0.1118339002,0.7051146626,0.2405101657,-1.2077591419,-0.7707319856,-0.4111624956,0.8228642344,1.3478077650,1.3317564726,1.2580941916,-2.1362700462,-0.6044573784,1.3983079195,-0.2267834991,1.1038742065,1.8309376240,2.5118257999,-0.7461085320,0.4706372619,0.3283693790,0.5749509931,0.0096055260,1.5103399754,0.4314630032,0.8736536503,1.0169622898,-1.6128311157,-1.1360261440,0.5721042752,-0.6031692624,0.1187613904,1.1165670156,0.1368981600,-0.9850955009,0.6313478351,0.7843387127,1.2135647535,0.3128623366,0.5757420659,-0.1311307251,-1.4725977182,0.2902924418,-1.6542005539,1.3504993916,-0.3761866093,-0.0340541266,1.3819690943,-1.8941106796,-0.2743933499,-0.2576075792,-0.4365912676,0.4990610778,0.9072874784,1.0279914141,-0.2289631665,0.5705673099,-1.8134893179,-1.4707256556,-0.1991883665,0.1905540079,-0.1706116498,-0.4919151664,0.8360471129,-0.4966766536,1.3094147444,-1.3342524767,-0.8660213947,0.4778424203,-0.3906137049,-0.2144182622,0.3572425842,0.2118220329,1.1288861036,-0.0217239484,1.0320818424,-0.3704183996,0.1348206401,0.0780876055,-1.1623704433,0.0471805632,1.8262777328,-0.1326367855,1.2541949749,0.4579695463,0.6132331491,-0.6418583393,0.8945944309,1.3853417635,0.6127995253,1.7553474903,-0.8952273130,0.5639309883,1.1167125702,1.1573514938,0.6090118885,0.4605760276,1.3694016933,0.3081550598,0.4055664539,-0.4725796282,1.7730118036,-0.0457734875,0.0639425218,-0.6374250054,0.5051111579,0.5209814906,-1.3633556366,0.6776292324,0.5936003327,-0.9643524885,1.3238570690,-0.9794591069,-1.8232733011,-0.9560294151,-0.9466639757,0.4216081202,0.0111554582,-1.2830356359,0.0037587516,0.2466487288,-0.7067456245,-0.1197778061,1.3785123825,-2.2226142883,-0.1396190971,1.3109309673,0.0336780511,-0.5899109840,1.8874821663,0.4395863414,-1.2137041092,0.9638198614,0.5589596629,0.1619139463,-2.0408895016,0.0560152270,0.7049338222,-1.8372228146,0.0895555690,-0.8652178645,-0.5274806023,-1.4498169422,1.8824826479,-0.7552757263,0.8409298658,-1.4074972868,0.2751502097,-0.0361059606,1.3069361448,-0.4460712075,0.7948856354,0.2241593003,-0.0092800902,0.1511366814,-0.5700770020,0.9738789201,1.4050635099,0.7358398438,0.3554930687,-0.5356953740,0.6154323220,0.9979453087,-1.3390628099,-0.8583290577,-1.7452572584,0.1104434729,0.3890730739,0.0756772608,-1.6073110104,-0.3842329979,-0.5743327737,-0.5342398882,-0.5943794250,-0.6329166293,0.1348872036,0.0209345836,-0.6921874881,1.2580894232,-0.1487711817,1.4409718513,-1.9829041958,-0.3945930004,-2.0652801991,1.9432833195,0.8998360634,-0.2134810537,1.7895114422,1.2492611408,-1.2575070858,0.2093546093,-1.7946289778,-2.2766561508,1.5815219879,-0.6217867732,-1.5840293169,1.0552384853,-1.4108628035,0.0078826984,0.0647610202,-1.2973845005,-1.4553879499,-0.6940916181,-0.0104205608,0.2180850804,-1.1110692024,-1.4055019617,0.6910184026,0.1690434515,-0.5238924026,-0.9038918614,0.1617193222,-1.5668437481,0.5746982098,0.7966463566,0.3421330154,-0.1778702289,0.0627256557,1.2577672005,0.7419780493,-0.4220174253,-0.5558896661,0.5636611581,-0.5715605617,1.2305231094,-0.6542611718,0.5123797059,-0.5756513476,-1.2421853542,0.9539251924,-0.7216297388,0.2888312638,0.0398992859,1.9420181513,-0.9858289957,0.1439062804,-0.1981014162,-1.3955296278,0.1860184371,0.5092500448,-2.2733435631,0.4448447824,0.7383634448,0.9620494843,0.9712896943,-0.5859873295,-0.4633949995,-1.1635951996,-1.0255144835,0.9860011339,0.3003800213,-0.6828405857,-1.2880755663,-0.0181694888,1.3963208199,0.6787196398,-1.3546409607,1.0398122072,-0.0002420847,0.4149239361,-1.3920470476,0.4387226701,1.7786114216,0.0279869679,-0.5754590034,-2.8383243084,0.3669659793,0.3989785910,-0.3432056606,-1.4067237377,-0.5664580464,-0.7988797426,1.9535807371,0.9568747282,-0.2729994059,2.0905108452,-0.9002789259,1.7589235306,-0.2031082958,0.2045028061,-0.3391548991,-0.0187342484,0.6179451942,-0.1164130643,-1.0554273129,1.1348347664,-0.5240642428,-0.0533059984,1.1834615469,1.4722721577,-0.3002305627,-1.1545814276,-0.0434754863,0.3521986306,1.1709691286,0.2513211071,-0.4330072105,0.3237198889,0.2494965345,0.2712747157,0.1401934177,0.0521037690,-1.1359419823,-0.8886265755,-0.4292696416,-0.6217500567,-0.2999503016,0.2239636630,-1.4546821117,-0.4629549384,0.2481509894,1.1152031422,1.2186678648,-0.8037263155,-1.8307890892,-0.9193554521,-1.9347736835,-1.7906540632,1.4603732824,0.6034803391,-0.7582035661,-1.4562839270,-0.4283702075,0.2467783093,0.8750617504,-0.5399234891,0.0219904687,0.1347843856,-0.6984317899,1.2807254791,0.6972069740,-1.1246480942,1.2445069551,0.0746976510,-0.3634368479,0.9292349815,-2.1193280220,1.9793330431,0.9654034376,-0.8357360363,2.3896911144,0.5750907063,-0.6683084369,0.4982488751,-0.2650178075,0.3913143575,-1.9028433561,1.2230871916,-1.6067589521,-2.1641135216,-0.6277225614,0.8032400608,0.6450325251,-1.3358204365,-1.5891611576,-0.3048976958,-1.1766319275,0.9003731608,-0.2710793614,0.7207944989,0.2262839079,-0.2502329051,-0.2332939208,-0.3703612685,0.4698289037,-0.7305675745,-0.2357319444,1.5106195211,1.0950709581,-0.6133319139,0.5051881671,1.0278711319,-1.7371171713,-0.2370272130,-1.0186152458,-0.5381708741,0.6036685109,0.0080919098,1.3370512724,0.3532626629,-0.7991682291,-0.2605423033,0.9962968826,0.3493235409,0.4128884375,-0.7413421273,1.0753172636,-0.1606328785,-2.4201703072,-0.7577661276,0.9301439524,0.3775624931,0.3262410164,0.8824862838,0.4710078835,-0.8032360673,-0.5725351572,-0.0582918525,0.7470893264,-0.4320694208,-0.4195062816,0.7359803915,0.9830491543,0.1097064689,0.5909559727,-1.5239113569,-0.5554866791,0.1916795075,-0.2884576321,0.4674206376,2.1317734718,0.8106547594,-1.1282305717,1.1774668694,0.5297613740,-1.5435117483,1.0490826368,-1.4259819984,-1.2291139364,-0.0065258709,-0.2216066718,0.3152341843,0.3517228663,1.0046916008,1.1837831736,1.6787571907,0.5730426908,1.1133731604,-0.7634158134,-0.4686076939,0.7512238622,2.1902413368,-1.1080244780,-0.0866195410,0.7111128569,-0.0059136329,1.6001064777,0.2407293469,0.7014157176,2.2532317638,-1.1692081690,1.0892179012,-0.1247122213,0.3142854273,-0.0842473879,-0.1432422101,1.1002390385,0.5898386240,-2.9799461365,-0.5483270288,-0.3715531826,-0.3583878279,-0.0210139882,-1.1149870157,2.4004268646,0.1063649058,0.7702438831,-0.4968264401,0.0172923505,0.2284315526,-1.0430088043,-0.9970272183,-1.6039516926,0.2978511751,0.3246447444,-1.1764000654,-1.0792928934,-0.7115822434,0.9049133658,-0.1356133074,0.7902173400,-1.8608924150,-0.0342043675,-0.2184225768,0.2755118310,-0.5773473382,1.9079804420,-0.9805600047,-1.7185441256,-0.2441821545,-1.5625159740,-0.0510449111,-0.6830695271,1.4691959620,0.3331987858,-0.1861740500,-1.2373799086,-0.2372961491,-0.1537933350,-0.1583372951,0.9213557839,0.1104177907,0.7021344304,-2.2697911263,-0.9931976199,1.3266222477,-2.0886709690,0.9214906096,-0.4929367900,0.7904263139,1.5942453146,-0.5685650706,1.1563068628,-1.7574599981,0.3507694304,0.9195406437,2.1849930286,0.4669177234,0.0332165174,-0.9302831292,-1.1052159071,0.5699044466,2.7418849468,-0.8644914031,-1.1204868555,1.0906944275,-1.8325343132,1.2423360348,1.0562793016,-1.8252551556,-0.1053487584,0.6263771057,1.5337488651,0.3819944263,-0.3788675964,0.4347829521,1.0719298124,-1.9757854939,0.4538616240,0.9466922283,2.0393373966,0.8154541850,-2.2556941509,0.2045707256,1.3789530993,0.4618313015,0.6645997763,-0.1469683647,0.9429551363,0.3144655824,0.5231790543,-0.3446117938,-0.9457993507,0.7486024499,1.3672702312,-0.7518332005,-1.3094704151,1.2875912189,-0.6445900202,-0.4857350588,2.7472012043,-1.5506581068,-1.7447063923,-1.6849077940,-1.1065803766,-0.0241784956,-0.0330930389,0.8838341832,0.7734587193,0.5042662621,-0.6122062802,0.7282840014,0.9780203700,0.7290042639,1.1951694489,-0.0285034478,-1.7318187952,2.8072602749,-0.8139628768,-0.6801139712,0.3368071020,0.6303592920,0.0890115127,-1.2492383718,0.6210021377,-1.3981107473,-0.0684296265,-0.8358044028,0.7615279555,1.1252840757,-0.2928672731,-0.1489151269,-0.2545097768,1.7402290106,1.0581798553,0.1409235895,1.3134722710,-1.2648737431,0.3441012800,-0.9336190820,-1.2345448732,-0.1902813017,0.8853290677,-0.5469426513,-1.2303242683,-0.2285664976,-0.2023745328,-0.4210486412,-0.1622483581,-0.6331458688,0.6673703790,-0.8797009587,0.1470505744,-1.6115312576,-1.7434673309,-1.1627935171,0.2992941439,-0.7151190042,-1.2173782587,0.2558501363,-0.5031922460,-0.1038606390,-0.1561047882,-0.8796012998,1.0886113644,0.3119497001,-0.4022977650,-0.1012258232,1.7479351759,1.3647730350,-0.0543092415,0.2226750851,1.6659430265,-0.5892763734,-0.3167293370,0.7162985206,2.7947816849,-0.2856855094,0.3759886622,0.6820854545,-1.9602570534,2.3843588829,-0.8123612404,0.6058959961,0.7391664982,-0.4000688791,-0.9828444123,0.7060558200,-0.7857539058,1.1159673929,0.2286228538,-0.4661549330,1.4146889448,-1.5722010136,0.8475800157,-2.1850621700,0.4052006304,0.9268170595,-0.5286844373,0.3858979344,-0.9194214344,-0.8946732283,0.0659045056,-1.2474843264,0.4395863116,-1.1277976036,0.7343308330,2.2652714252,0.2736219764,0.8193798661,0.4121380746,0.9677261710,-1.4630614519,-1.0397695303,0.3285118639,1.4500451088,-0.1098707393,0.8462182283,-0.6662430167,0.5424329638,1.0663647652,0.3155307770,-0.6716760993,-0.8097543716,1.6464439631,0.5302342176,-0.3151896596,0.2689172924,-1.2359784842,-0.1069266498,-1.5323109627,1.3193717003,0.6514467597,1.5726830959,-0.5646753907,0.8270943761,0.0647617579,-0.5997740030,-1.9733934402,1.2835294008,-0.7041236758,0.2832516134,-1.2470406294,0.0342308544,0.5632337928,1.7738374472,1.0023999214,0.5243485570,0.4966398180,-1.9411910772,-0.5846640468,-0.1156490222,-1.8383711576,-0.6315868497,0.2895682454,-2.7668647766,0.1243848652,0.5403708220,2.5971651077,0.9537038207,-0.5311449766,-1.9729572535,0.1686208397,-2.2282452583,0.0519388616,-0.8657557368,2.1935203075,0.9435275793,0.3583879769,-0.7221446037,0.8322559595,-0.1130532399,-1.4182372093,1.7974859476,-0.6891320348,-0.2459898293,0.3112476468,0.2605895996,0.4272195399,0.5657240152,0.1126472205,0.5242422223,-0.5227910876,0.8922997117,-0.4843709171,0.3712804914,-1.6282891035,0.1348460317,0.3993672132,1.3468558788,0.7090018392,0.4272810817,0.3625778258,-1.5106115341,1.8112719059,-1.1968251467,-0.1324630231,-0.7746610045,-0.1489947736,-0.2863193154,-0.7271369696,0.4484030902,0.4039295614,-0.6630720496,0.2465493828,-0.1913393289,-0.5363966227,0.0706059188,-1.9758604765,1.2545558214,-1.2935758829,0.1870326698,0.5147288442,0.2047286779,-0.9113526344,-0.3674494028,-1.3195163012,-0.5636649728,0.4023266137,0.3050526977,-1.3710098267,0.7285389900,-0.2600562572,0.9642859101,0.7061238289,0.0804846361,0.3684956729,-1.3706005812,1.7705264091,-0.0568827242,-1.1363366842,-0.5154197812,0.4832886755,0.1776915193,-2.1355118752,-0.2538057566,1.1987390518,-0.9549040198,1.4837807417,-0.3976415396,0.2713989019,-1.3256140947,0.0872604623,-1.8873546124,0.4834865928,0.7455752492,0.0950498506,0.2772811353,1.2658462524,1.5551054478,1.7185579538,-0.2580177486,-0.5866049528,0.3638573885,0.4724708498,-1.0699458122,0.3302752972,-0.5717364550,-1.9355258942,-0.4169055820,-0.3732923865,-0.4488600194,0.1205200925,-0.6611413360,0.3152336776,0.5914426446,0.5891466737,-0.4318289161,0.5248982906,-3.0162057877,-0.7288278341,0.5338007808,-0.5691620111,0.0026917364,1.3950619698,0.9638216496,1.2086063623,0.5523138046,-0.1347372085,0.4186432958,-0.0125459330,-2.3909592628,1.2674869299,0.8219062686,-0.9020726085,0.8937808871,0.5497428775,-1.8376889229,-0.3232720494,0.9673829675,-0.1577348262,-0.8051065803,-1.4380515814,0.5605085492,-1.6228570938,0.8229484558,0.6320642829,0.8324034214,-0.7958431840,-1.2507016659,0.3585999310,-0.2646588385,1.5732150078,0.3994229436,-0.6318780780,0.2118939310,0.4288383722,0.1017487049,0.3347709477,1.3281470537,0.5289729238,2.2454297543,-1.1805934906,-0.1550690830,-0.1861247271,-0.6157492399,-0.2086265832,1.8791502714,-0.5473974943,1.2587167025,0.0400549732,-1.2131153345,0.4959487915,-0.6701539159,0.0377192609,2.0914919376,-1.2017105818,-0.5418961048,0.0715248883,1.1804654598,0.0372791365,0.5071865916,-1.1190364361,0.1947530657,-2.2451906204,1.8115687370,-0.3882434666,0.4428933263,-1.3330305815,0.0781882405,-0.1043641046,1.0043901205,-1.0324101448,-0.4917244315,-0.5101444721,0.7722641230,-0.5372172594,0.3941535652,-1.0564483404,-0.1142743900,0.2367779464,-0.4811623394,0.8114396334,0.7052668333,1.3426921368,0.4971502721,-0.4514482915,0.1606788486,-1.0752604008,-1.5647202730,0.3447371721,0.2896904051,0.6959680319,-0.0190260354,-0.1225974485,0.6586026549,-0.3244411349,0.7685539126,-0.1682316661,-0.9780043960,1.9468239546,-0.1223541796,1.4135782719,-0.3331348896,1.5832772255,-1.2763670683,0.3524271250,-1.0963369608,-1.3600704670,1.3364082575,0.8700780272,-0.3765659034,-2.6367402077,-1.0929170847,-0.0520115234,-0.9117823839,0.5583176613,-0.8233562708,-0.1356477439,-0.5791643262,0.2063644528,0.0742090866,-0.9129800200,-0.5781509876,-1.3166632652,0.5495023131,0.6567738056,0.5245886445,-0.5641840100,0.1216162369,-2.2587895393,-1.1103811264,-0.2331566811,0.4222166240,1.4316504002,0.8986779451,0.2228398025,1.3977748156,1.0694563389,-0.8107503653,0.7228331566,0.2350391448,-0.1462830901,1.1465845108,3.0110960007,0.1884022951,-0.2710390687,-2.4918198586,-1.3116731644,0.6081784368,-1.8274118900,0.3237744570,-1.0996891260,1.6525988579,1.7144389153,-0.7473198771,0.1106017306,0.0607738420,-0.4209593534,0.5615531802,1.1473829746,1.3023934364,-1.0771951675,-0.0043456485,1.1957966089,-0.6975986362,0.6175321341,0.0798140764,0.3990066051,-0.1930454522,-0.2801606953,-0.6360430717,1.5740067959,-0.6150626540,-0.6657387018,0.6328179836,1.5874658823,-0.8234479427,-0.9082185626,-0.9049493670,-0.1048155203,1.4692788124,-1.4920828342,-0.2135273218,0.1324931532,0.3250708878,-0.5595640540,-1.6266405582,0.6432067156,1.0292233229,0.4580583870,0.1775811911,-0.0012351129,-0.4039856195,-0.8623089790,-0.4011097252,1.3185437918,2.4721014500,1.5110800266,1.1565639973,0.1544111222,-1.4040644169,1.1386544704,0.4006298184,0.1019146889,1.1850543022,0.5945206881,-0.3560276926,0.8948068619,-0.3113974035,-0.5629203916,0.8216427565,-0.8694606423,2.0849277973,0.4553703964,0.2011788487,1.6399581432,1.1543406248,-0.6563993692,-0.1601136774,0.3659283817,-1.5479089022,-1.6454467773,-0.5885052681,0.4701368809,0.8731890917,-1.0473310947,-1.6058140993,0.5154587626,0.0192641634,-1.1761554480,0.3215034902,-1.0969194174,-1.1431628466,0.9230197072,-0.8684829473,1.2271327972,1.0552119017,-0.4195388556,0.7144517303,-1.5553835630,-0.5773956776,0.9839149117,1.9320902824,0.4686033130,-0.5418919921,-0.2432720214,-2.3585970402,0.6843538284,-0.5589225292,1.4080122709,0.5970636606,-0.6819794774,-0.7745859027,-0.5762728453,3.3780813217,0.9202184677,-0.5481423736,1.3764128685,-0.3434719145,0.3977651894,0.3125531971,-0.3766749501,-0.9650712609,-0.6414336562,0.2432779819,-0.0810078681,-1.4610075951,-0.5868371129,0.6019322276,-1.1608246565,0.4770873189,-1.1839425564,-0.9647042155,-1.2911399603,-0.7851390839,0.0474583209,0.5524968505,-0.4648094177,0.6342483759,0.2583498955,-1.6864966154,0.0093507320,0.6306871176,0.3638943732,-0.5551549792,1.9378409386,0.4792116284,-1.3169698715,0.3789154291,0.5505794883,0.3445309401,-0.2305428237,-0.5491927266,1.4039272070,-0.1311127692,1.2018909454,1.4131186008,0.6897209883,2.8037290573,-0.9207084179,0.3258124292,0.5043047667,0.0766622126,0.6969939470,-0.2453171611,-0.0269711744,0.1035700291,0.1819505543,-0.5836421847,-0.6208786964,-0.8684943914,-1.0072883368,2.5586364269,1.1484230757,1.4538383484,1.0172985792,-1.1306617260,-1.1712599993,1.4082340002,0.1663869172,0.8057622313,0.0210015643,1.0863547325,-0.4501363635,1.1340610981,0.3947748840,-0.9205060005,-0.1627232879,-1.3064237833,0.7684119940,-0.2114374936,-0.4287933707,-0.4915237129,-1.6247475147,-1.9873917103,-0.0473227836,0.3810624182,2.1965646744,-0.4863922298,-0.2136739194,0.2542577088,0.6342818141,-0.6232274175,1.3386460543,-2.8707752228,-0.8340262175,1.6175956726,-1.5389409065,1.0650939941,1.5738481283,-0.2559369802,1.8801785707,-0.6821094751,0.5025829077,2.0232660770,0.7300717235,-0.7082805634,-1.3114689589,0.5112272501,1.6427576542,1.4437679052,-0.4480295777,1.2616261244,-1.0043283701,0.0544764996,-1.6036715508,-0.1986960471,0.7933214307,0.6842283607,-0.9457077384,0.3122385442,-0.3216295838,-1.5933513641,-0.9579170942,0.3627172709,-0.8289911747,0.6612448692,-0.1123323664,-0.1781046540,1.4285470247,-0.7790344954,2.9845044613,1.1620213985,0.8558660150,-0.2367271185,0.3755499125,1.6477419138,0.1121707782,-0.9373643398,-1.3632234335,-1.5604901314,-1.6682239771,-0.2411317378,0.1953369826,-2.2244782448,0.4661431313,-0.6613999605,1.1189903021,0.4893060029,0.8133631945,0.1535202712,1.6659163237,-0.6708444357,1.8384982347,-2.3238289356,-0.0551512279,-0.9679136872,0.0428756699,-0.7018769383,-0.1918913126,0.7778669596,0.8716066480,0.6106519103,-1.2859187126,-0.4537215829,-1.1330381632,1.0173296928,0.6480510235,1.4370362759,0.1523553282,-1.6252946854,0.6880706549,-0.4669993222,-0.1189476922,-0.0044371127,2.1690118313,0.2642358840,0.2700255215,1.5732755661,-0.3509848118,-1.8715351820,-0.0526743382,0.3962967694,-1.5842945576,1.2396576405,-0.8333008885,0.1840726137,0.7715519667,-0.3682126701,0.3607615530,2.0035834312,0.1541242748,-1.3954974413,0.0325314477,-1.6350804567,-0.9458541870,1.2335181236,0.3805272579,1.0706945658,1.7222070694,-0.6014351249,-0.0275845937,2.3488023281,-0.9489246607,1.0424493551,0.5509977937,0.5912781954,-0.3194181025,-1.8344695568,-1.5199538469,-0.2534407377,-0.6822112203,-1.5001311302,-0.5672664046,-0.0814578012,-0.7873686552,-1.0422301292,-0.3025351763,0.4241429865,-1.5904347897,0.1101631746,1.0006101131,-0.6859989166,0.9753202200,1.0051900148,0.5923214555,-0.4300889373,0.7324078083,1.2622574568,0.0162067059,1.2897980213,-1.6987493038,-0.7873823047,-1.1084727049,2.4867002964,-1.0069047213,-1.1833405495,-2.6878020763,-0.4799250960,1.2554645538,-0.5688960552,0.0881453305,-0.4376583397,-0.6516036987,-1.0665112734,0.1584681869,3.1608436108,0.5720539689,-1.5262326002,0.4792236686,0.2597243190,-0.0070801945,0.4739401639,0.1779567897,0.4280982018,0.3195990920,-0.8183332682,1.4376466274,-0.3180052340,1.3227945566,0.3346593678,1.6663300991,2.1549162865,0.5529408455,2.3215246201,1.6306368113,-0.2287237942,0.3626566231,0.6241252422,0.2874783874,-0.5562575459,-1.0645240545,0.3074939847,0.9751630425,0.4938282371,0.4887374043,0.0105593298,0.6010999084,0.1875414848,-1.4502644539,-0.5887443423,-1.1079670191,-0.7399981022,-0.5830377936,1.9610450268,1.9490827322,0.1687097102,0.6483928561,-0.3631643653,1.2609117031,0.5470111370,0.3083211482,0.9779278040,-0.2285307497,0.6608920097,0.4434262514,2.3462135792,1.2344197035,-2.0416243076,-0.5078871250,0.6721323133,1.3655580282,0.6412608624,-0.1009380966,0.8257616758,-0.8150367737,-1.0085000992,-0.2928051651,-0.6150723100,-0.4936757684,-0.2183852941,0.9689996243,1.4067459106,0.2134040892,-0.4075092673,-0.4920285940,-1.7855901718,-1.0941070318,-0.2059654444,0.6229280829,-0.7334624529,1.2113645077,-0.4594071805,-1.4258073568,0.5498878956,-1.5167644024,-1.0164055824,-0.9841329455,0.4166430235,-2.2984161377,-0.7978627086,-1.9428042173,-0.4716677964,-2.6861188412,0.2464052886,-0.7541234493,0.0767890364,2.4924387932,1.0294005871,0.4078120291,0.0231720693,-0.2605399787,1.0949954987,-0.4825623930,-0.8047713041,-0.9314247966,0.1557550281,-0.2464975119,-1.7501392365,-2.1452300549,2.0917215347,-0.5078848600,-1.1502003670,0.8368268609,-2.2316017151,-0.6839256287,0.8083926439,1.5101549625,1.7092049122,0.3911790252,2.3782274723,-1.8589886427,-0.3594858348,1.6014767885,-1.1541914940,-1.0710375309,-1.0111941099,-0.3062404394,-0.2918458283,0.4250952005,-1.4448601007,-0.6035043001,1.5781127214,-1.5689852238,-0.8176691532,1.5150188208,0.6178444624,1.6630421877,0.4960637987,0.2892667055,-0.4297368526,0.3063223064,-0.3640555441,-1.3150182962,-1.5254424810,-0.1548462957,0.1717245430,-2.3199658394,-0.6687420011,-0.8737539053,-2.1310255527,0.1657736599,1.0154526234,-0.8788712025,0.4433715641,-0.6407283545,-0.1064218804,0.9291561246,-0.4667377174,1.0356763601,-0.2875490189,1.7318445444,-0.1297231019,0.2333392501,0.1582544744,2.0523178577,-0.7429432273,-2.1222071648,-1.4895672798,0.3120341897,-1.4317234755,-0.6542963386,1.3853491545,-0.8467838168,-0.7864772677,-0.7140951753,0.7617847919,2.6022748947,0.4526357949,-0.1344853640,-0.7801381946,-0.3832502067,-0.0866161734,0.4906598032,-1.0615791082,0.8940999508,-0.3497473001,-1.2624950409,0.1075066999,-0.0659220442,-0.6305398345,0.2686221302,-0.1823195964,-1.4534528255,1.9937129021,0.1483629793,-0.2734782398,-1.5328689814,1.9309226274,0.0419135392,-1.9509328604,0.3718533218,-1.2233750820,-1.3658379316,-0.2958777845,-0.4734799266,0.7543007135,0.2856521606,-0.4374417663,0.8792541623,1.3735964298,-1.4071791172,0.1599424481,0.2732090056,-0.1884759814,1.5184983015,-0.3780666292,0.1182340458,-0.3417127430,-0.6154448986,0.9049147964,-1.8434865475,-0.6616224647,-0.2895358503,-0.4325897992,-0.6810391545,-0.1942910403,1.0399843454,0.7656468153,0.8919506073,0.8561698794,0.5976582170,0.8780407310,0.2451337427,-1.2113918066,-1.2457233667,0.5290142298,0.8976787925,-1.4235173464,-1.2115622759,-0.9235364795,-0.5710926652,-0.6926459074,-0.8372098804,0.1629962623,0.7053339481,-0.0904416740,-3.0984549522,0.6686881185,-0.7333278656,-0.6111493707,0.7304154634,-0.8588292599,0.8808065653,-0.6583173275,0.7451996803,-0.2612974644,-0.7302530408,0.4351638556,0.9296533465,0.6713768244,0.3829293251,1.4064166546,-1.2013900280,0.1457719803,-0.9313827753,2.6163449287,0.5473232865,1.4893498421,1.4373891354,-0.7347108722,-0.8683974743,1.4311701059,0.2228661329,0.4464642406,1.1559196711,0.0410200059,-0.1286565661,0.2647444606,0.6956012249,1.3178719282,1.0041838884,2.1021845341,1.0517970324,1.4445554018,-1.1228381395,1.5592223406,1.2020138502,-0.0028192063,0.5974342823,-0.8048190475,-0.9230668545,0.3318743408,-0.8511945605,0.0609234236,2.2532401085,0.2028496712,1.1774448156,-0.5526928902,-1.9647001028,-1.8609727621,1.0291814804,1.0270837545,-0.1857776791,-0.8119634390,1.0355705023,0.2473882139,1.0378277302,0.5087451935,-0.9540367126,0.8271316886,-0.2665016651,-1.7770938873,-0.6815657616,2.0232789516,-1.2229034901,0.2241365314,-0.0978290513,1.2142428160,-0.3724579513,-0.3604663312,-0.4075214565,-0.1006050706,0.7029295564,0.9857544303,-1.3855587244,-0.7235353589,0.1705339402,0.2272443473,1.5756491423,-1.0199034214,-1.4712222815,-0.1937682778,-1.4571503401,-0.4014287293,1.7913830280,1.4787840843,-0.8528799415,0.8736353517,-0.1563538909,0.1690182835,0.4658602774,0.1371072829,0.2078346610,-0.4466711581,-0.9114081264,-1.0166107416,-2.6908288002,-1.5399973392,1.4427289963,2.1239728928,-1.7548342943,-0.4824391305,-0.5262094140,-0.5427834392,-0.6966464520,0.4204410613,0.4263037443,-0.4591600001,0.2637559772,-1.9718030691,1.6417837143,-1.1051946878,-0.3639093637,-0.9486865997,0.4432385862,0.3481712639,0.4060375094,-0.5423926711,-0.3527583480,-0.4264259338,-0.9308899641,1.5440005064,1.5066274405,-0.1226757243,-0.3284087479,0.1419685334,-1.1529750824,0.2755541205,0.7012867928,0.0936654210,0.8950644732,-2.6700437069,0.2992852926,0.6254771352,0.1787260175,0.9335781932,-0.5372442603,-0.9831199050,0.8023634553,0.9252654910,0.0591549464,0.6226165891,0.2587251365,0.8355274200,-0.7327592969,0.6793955564,-1.4561997652,0.7465295792,-0.7011393905,1.5439178944,1.1826778650,0.2308337688,0.3512136638,0.1431451440,1.1339086294,-0.2589430809,-0.2183725685,-0.1566379517,-1.6944813728,0.3345756829,1.6899503469,-0.0316444114,-1.1810456514,-0.3684019446,0.3207881749,0.7920659781,1.6422004700,0.2716714144,-0.5603635907,-0.3599757254,0.1677870452,0.0078198100,-0.4939026535,-1.7546492815,1.0226032734,-0.0200631488,0.5507588387,0.4915273488,-1.8573807478,0.8740385771,0.0427967496,-1.6065392494,0.7721800208,-1.1217762232,0.6055000424,-0.9973308444,0.6799186468,0.1740625948,0.0296238065,0.5217496157,0.1923450679,-0.5879488587,0.5928028226,-0.5710805058,-0.7600550652,1.1986136436,0.8760007024,-1.8550120592,0.7245780230,0.0701237619,-1.0581716299,-0.1062726602,-1.1632649899,2.3888280392,0.0001293403,-2.5444760323,1.6522936821,-0.4627757967,1.1748318672,-0.1822272688,-0.7353000641,-0.9973748922,-1.2355535030,-0.4939834774,-0.9968354106,-1.7728964090,-0.0487909168,-1.1636132002,0.7202252746,1.9825910330,-1.6155759096,0.5454311371,-0.7507312894,0.6600294113,0.0698041469,-0.8771593571,0.4602817297,-0.5655164719,0.0821633413,-1.6148333549,-0.2856899202,-0.9010733962,-1.5962631702,0.0608109497,1.7148712873,-0.1972455084,0.7661412358,1.7797145844,-0.7024210095,1.1253442764,1.9075862169,1.8911184072,0.2929170728,-0.4096447527,-0.0711998194,-0.7124832869,0.2756503224,0.8862338066,1.5982501507,-0.8595206738,-0.8688374758,-0.6461665630,0.7948951125,0.2192122340,-0.0730743557,0.1788961291,0.0994319618,2.5646259785,2.1651239395,0.6786749363,0.8574656248,0.1200354621,2.7303805351,-0.4879829586,0.8700460196,-1.2592363358,0.5971306562,1.3760768175,1.4629197121,1.4793893099,-2.2686212063,-0.3273313642,0.4973333180,-2.2781610489,1.1125961542,-0.3504355848,2.1755020618,1.2387313843,-2.1263351440,-1.7304564714,0.6072626114,0.8712618351,0.1535709053,-0.8973566294,1.4609305859,0.0118550872,1.2186610699,-0.3652283251,-0.0985303745,-0.4372721910,-1.1246514320,-1.9076437950,0.0822057426,2.1654286385,-0.5866769552,-2.5962011814,0.7465396523,1.0702034235,0.3408767581,0.8843899369,0.9880162477,0.3733038008,0.7469571829,-0.3654667139,-1.1835292578,0.0639124513,0.9607874751,-0.6897494197,-0.1239338443,-2.1009445190,-0.1710033417,-0.0617053173,-0.0188370664,-0.2777236104,-1.4326847792,0.8153862357,-0.0844529122,-0.1488251239,-2.0507738590,0.6880062222,-0.5953730345,0.8839527965,-1.1588287354,-0.8564046025,1.0334230661,-0.8303106427,1.0943323374,-0.1897011697,-0.7996029854,-0.3756458759,-1.0631002188,0.6210219860,-0.8794413209,-1.2669420242,-1.6641253233,-0.9473111033,-0.1794932634,-0.7986416817,0.4215012491,-0.3709406555,0.1757474840,0.9827396274,0.0277207959,-0.1375899166,0.9105586410,-0.6598195434,0.6502033472,-0.9171069860,-0.0821832120,-1.2704133987,-1.4377149343,0.8652183414,-1.9529612064,1.0661842823,0.9509752989,0.7923091650,-1.2883765697,-0.1132074520,0.0863654539,2.7263689041,-0.2265016735,0.2427878529,-0.7156814337,2.1491582394,1.4603886604,-1.8682442904,-1.1941982508,-1.4207702875,0.2143935561,0.6873126030,-0.8676314354,0.8319645524,1.4122692347,0.3956587911,-0.3590189219,1.4693763256,0.0357302763,-1.7043617964,-0.5215309858,1.2631664276,-0.5264201760,-0.1750185192,1.4218360186,0.2109541893,-0.8578353524,0.0341349170,-0.8854100108,0.6071174741,0.2590273321,0.6369572878,0.2007258683,-1.5683698654,0.0528304949,0.2185943723,-2.0792095661,0.3473087549,1.5566731691,-0.9429470301,0.3542098105,0.1842521578,0.0781935975,0.9226818085,-0.1423786730,-0.4596142173,0.4551231563,1.8416955471,1.6079021692,-0.8521170616,0.5756788850,-0.5148565769,-1.2641240358,0.1978517026,-1.4766743183,1.1515684128,0.1763038188,0.2640692890,-0.8323398232,0.0230683852,0.6586131454,1.5933395624,-1.4179666042,-0.7774670720,-0.4964284897,1.4293264151,0.2270773351,-0.0167941060,-2.0283677578,0.0885260925,0.3764227331,-0.7332847118,0.9534940124,-2.1248283386,1.4294171333,0.7428011894,0.3662443757,-0.0806344151,-0.0672872812,-0.1971713156,0.2399710268,-0.5236250758,1.1410593987,-0.0949220136,-0.1947147548,1.1396582127,-0.1080093160,0.3194012046,0.2399757802,1.7890506983,-0.1936757118,0.8872783184,-0.1072830781,1.3524184227,-0.4339081645,-2.6261727810,-0.5521342754,-0.3567785025,-1.3351668119,-0.5639197826,-1.2869068384,0.4983268678,-0.3498931229,0.0223497171,-0.6007211804,-0.0052249120,-0.0424862429,-0.4661367536,0.1067087874,-0.0690322369,-0.8722267747,-1.4753071070,1.1081073284,-0.3371511996,0.5770972967,0.4407486618,-1.3237779140,-0.4519773126,-1.7085222006,-0.8972691298,0.9348768592,-1.0095119476,0.8008344769,0.5961164832,-0.3867681026,0.0516395830,-0.5375924706,0.7138876319,-0.9433989525,1.0816320181,2.1809961796,-1.1811590195,0.3935625851,0.3030322790,-0.6758750677,-0.9937831759,-1.3757630587,-1.3634648323,-0.8317195773,1.4114764929,-0.3476401865,0.2501884401,1.3920596838,-1.5477883816,1.7170302868,-0.8295890689,0.6617835760,-0.5374920368,0.1471432447,0.3597033620,-0.1635111123,0.8404725790,0.1525148302,0.7160716057,-0.8264759183,-0.5981168151,1.0916924477,0.9427590370,2.3003776073,0.5416697264,0.4278137088,-0.3079363406,0.1193876937,-0.2164104432,-0.0375090204,2.0504729748,0.2739741802,1.0871514082,1.1895177364,0.0692935809,-0.2275115550,1.4736508131,0.6942522526,0.1104047671,-0.8769634366,0.7775915861,-0.3444183767,0.0806557834,0.7060059905,0.7481377125,-0.9507731795,-1.2001460791,-0.2362423986,-1.4188394547,1.1630134583,-1.5362975597,-0.5948074460,1.5993782282,-1.2341548204,-1.5226598978,-1.5064285994,-0.7967886329,-1.6548575163,-0.7267010212,-0.2619487047,0.8821213245,0.9663928747,1.4349234104,2.9031307697,0.6623058319,1.7527112961,1.4296424389,-0.1722200811,-0.0848347172,0.3168185651,1.6467040777,0.2583158612,0.6035906076,0.8671565652,-0.5262527466,0.3319886625,-0.5497463942,0.4200908840,1.6204705238,2.8567569256,0.6891232729,0.3979914188,0.5920624137,-0.7559434772,-1.0975944996,1.1700562239,-0.4009858072,-0.7570546269,-0.8614937663,-0.8159902692,-1.5159968138,-2.3159945011,0.0993413925,-2.6141450405,-1.0592906475,-0.3929703832,0.5702621341,0.2737638056,3.2217895985,-0.4519669116,1.0404402018,-2.1363830566,-0.0241962317,-0.0399352834,0.8125180006,0.9310963154,-0.2669395208,2.5663955212,-0.6801775694,-1.4735100269,-0.8673360348,-1.0219819546,1.7570893764,-0.4413214624,1.6531904936,0.0096711023,-1.3588843346,-1.0291464329,-0.2288335562,-0.2092395574,-1.4058778286,-1.1912089586,0.3284628987,-1.0475353003,0.3501040041,-0.0520703569,-0.4176031649,-0.1001003236,0.3600634038,0.1698016822,-0.5551374555,-0.0693989471,1.8276351690,-0.4938232303,0.9474299550,-0.3534296453,0.8308686018,1.2829548120,-0.9371561408,0.2828264236,0.8204187751,0.6815150380,-0.6391969919,-0.9756089449,-0.5878043175,1.2785863876,-0.4788477421,-0.9972364902,0.5297797322,-0.4876992702,-0.9401187301,0.1255615801,0.2447793335,-0.2591195703,0.2090267986,0.7089790702,-1.8272619247,-0.1440818161,0.8749162555,-0.2225515842,0.4995204806,0.0576416738,1.8956968784,-1.2364346981,-0.7038460970,1.0908890963,-0.4718849063,1.5693057775,0.4428057373,-1.1780397892,-0.7212728858,-1.7846194506,-0.1182599962,-0.7501379848,0.2489561588,1.8320907354,-0.6475961804,0.3235092163,0.1731548309,0.0735771284,-0.5053666234,0.7075278163,0.6965507269,0.5890418887,1.1716029644,-0.0515752882,0.3394494951,0.7700596452,2.5715339184,0.6072596908,-1.3007305861,0.0350546315,1.1603693962,-0.4538965821,-0.9783593416,0.0265502688,-1.2858632803,0.8167668581,0.1688446403,1.0662164688,-0.1026733741,-0.2595639229,1.0778741837,-0.4531909525,0.7623999119,1.2975021601,-0.0175253283,0.5181298256,0.2790040970,0.2507131994,0.0025475521,-1.6279962063,-0.1111964807,-1.8634821177,0.6435146928,1.0264328718,-2.0913350582,-0.5856692791,-0.1057725400,0.9844291210,-0.5320448875,-0.3761405051,-1.4245996475,0.6602067947,0.6311514378,-1.3559193611,0.3137751818,0.0596246235,1.0330663919,0.2284503877,-2.2971618176,-0.2615343928,1.0323364735,0.8715969324,1.4434144497,0.5397428274,0.6451210976,0.1844959557,-0.5831304789,-2.3598949909,-1.2856405973,-0.8049598336,0.3824418187,0.3135951459,0.5857704282,-1.8370773792,0.0837134793,-0.7865746617,-0.0764674395,-0.9077297449,-0.0669379085,-1.1441036463,0.5880070925,0.8309264779,0.4098588824,0.6063267589,0.1993841529,0.5601068735,0.0649905801,-1.5127788782,-0.6029203534,-2.0260241032,-0.0003807083,-0.1481437981,-0.8094789982,0.0633503646,1.7339324951,1.2790162563,-0.9811885953,0.9675010443,0.9853165150,0.5567837358,-0.3229420185,-2.2369308472,0.8412714005,2.2719078064,0.6248325109,0.0663437992,-0.4816880822,-1.0125662088,0.3245003521,0.8556165695,0.9044156671,-0.4809673429,1.5824408531,-0.6986125112,0.1831489205,-0.3048543334,-1.6329776049,-1.0484548807,-0.6673472524,-0.8022212386,-1.0551776886,0.3699105084,-0.9840784669,0.1571353376,1.7181296349,-0.1393129677,-2.6459677219,1.3768317699,-1.6159496307,-0.0081165750,0.4292753935,-0.2024205625,-0.9072603583,-0.2654633522,0.9579659104,0.1673599780,-0.8797431588,-0.5267537236,1.4190117121,0.6785064340,-1.1449259520,1.6081007719,-0.0469748788,-0.1846182495,0.2468699813,-0.2540178895,-0.7599125504,-1.4848744869,0.3800463378,-0.3932013512,0.1033055782,-0.8647897243,1.3579629660,-0.6633557081,-0.2434872836,0.5606272817,0.6669448614,-0.8341302872,0.3966738284,-0.3269149959,1.6633266211,-0.1126521826,1.4816939831,1.4156904221,-1.1166630983,-0.0606553070,0.0546188205,0.5445508361,-1.1936712265,-1.6309795380,0.8516145349,0.5265679359,0.1179899126,-0.5334897637,0.5507861972,0.7433545589,-0.7290908694,0.0266585760,0.2498948872,-0.4962490797,0.9441946745,-0.5713911653,-0.0213359054,-0.7809194326,-0.3588345647,1.6766144037,-0.6612223983,-1.1081395149,0.7486165762,-1.3002353907,-0.0150593566,0.5272737145,0.7198087573,-1.7407058477,-0.8895874619,-0.9602290392,-1.2390866280,-1.4357074499,1.9074325562,-0.7550415397,-0.6781569719,0.4313832223,-0.8729441166,-0.1306226403,-1.0444041491,-0.3175023794,-0.0994322449,-1.2217093706,-3.0405607224,-2.0784544945,-0.3157816529,-0.2450707406,0.1222063676,0.6923543811,0.4367699325,2.0453593731,-0.1379508525,-0.2453946471,1.9804742336,0.8290540576,1.7626791000,1.0024492741,0.0583503172,0.4870532155,-0.5370153189,-0.3089361191,1.2510309219,0.3513412178,-0.9523450732,1.0798521042,-1.5914729834,-1.3701014519,-1.4990744591,0.9432504773,-0.8200966716,-0.7967817187,-0.1315291226,0.1992424875,-1.4237283468,-1.0715271235,-0.3152555823,0.6245658398,-0.5692147017,0.6681869626,1.0679280758,-0.0746023059,-1.1953831911,0.1121772081,0.9854134321,0.1716614068,0.7160137892,0.8524336815,1.9281487465,-1.0551660061,-0.0363917984,0.8865175247,-1.9527336359,-1.4990662336,1.0684392452,-0.6240852475,-0.3335091770,0.0973984450,-0.1852093339,0.5368331671,-1.4069367647,2.1364684105,-0.7955299020,0.8053387403,-0.2109974325,-0.2769947350,0.9727430940,-0.8858503103,0.2244490236,1.5067592859,0.9171571136,0.0369015187,0.2488748580,-0.4096579254,0.1632209867,-0.1903329939,-0.0624251887,-1.4613902569,0.3192446530,1.0520952940,0.1580966562,0.8568762541,0.0363764167,0.0138445962,1.7657972574,0.0549255759,0.9261724949,-0.2794926465,0.2829901874,3.4744529724,0.6240840554,0.0514252074,0.3288902938,-0.9306465983,-1.0744475126,-0.7351902723,-2.2935986519,0.7545247674,-1.1019783020,-1.3874216080,0.7956593633,-0.2586257756,0.8067504764,0.6845870614,1.1044504642,-1.3624535799,-0.0332132876,2.5060169697,1.7505385876,0.6042174101,2.1284039021,-1.6996500492,1.5683763027,-0.3298414052,0.6837784052,-1.2028763294,-1.4863746166,-0.4961459935,1.9162024260,-0.7335478663,-1.2341134548,-1.7722808123,0.8240976930,-0.0894157216,-1.5428103209,0.0126349842,-1.2780302763,1.0979908705,0.0222587101,0.4325967729,0.9945772886,-0.5362792611,0.1228516474,0.2050954252,1.4675050974,-0.5703064203,2.1974587440,-0.3568199277,0.2641554475,-1.1423335075,1.1377191544,0.0303159729,-0.2573347986,1.0057265759,-1.4090272188,2.4242238998,-0.6121561527,-0.0515848696,-0.1749645323,0.3523877859,-0.1276333034,-0.1103901342,-0.2866850197,-0.0464149900,-0.3077701330,1.4960175753,-1.3631552458,-1.7209351063,0.6491242051,1.4050065279,0.2676798403,0.2793314755,2.0455369949,-0.2602713704,0.6774649620,0.2130657732,-2.2492074966,-1.3942852020,-0.8942496181,-0.4105454981,0.8247628212,-1.2053675652,-1.0555409193,-0.4163510501,0.9191569686,0.0591878742,0.8970375657,0.0131746996,0.3099085987,-1.1245883703,-1.4458359480,-1.0214380026,-0.4532108903,-1.0915752649,-0.2660917342,1.9693787098,0.0519596413,0.3412489295,1.4262259007,0.1354945898,1.2808616161,-2.3592946529,0.2309911996,0.6223339438,0.2537646294,0.3454696834,-2.0824322701,-0.1931213439,-0.3224272430,1.1653181314,-0.2260784060,-0.4215541780,0.4131685793,-0.3051755428,-1.3343261480,0.1708700806,-1.3212068081,-0.4973501563,2.0076658726,0.4784404337,0.0108408937,0.6487086415,-2.2793097496,-1.5167176723,-1.1210008860,2.0984489918,-0.9964933395,-0.2537392676,-0.6362712383,-0.6566887498,-0.4824739695,0.9052526355,-0.9712961316,-0.1638876498,-0.0615659095,-1.1938039064,-0.2663016915,1.2792323828,0.7501752377,0.3072949052,-0.3662904799,-0.8046880364,-0.0044827433,0.4288261235,-1.3418343067,-0.8763881922,2.3424198627,0.4666526914,0.4213204086,-0.4127517939,-0.7668270469,-0.8369839191,1.0337042809,1.5320605040,0.9207615256,-0.4779024720,1.1084336042,-0.6088128090,2.3399221897,-0.8646865487,0.2438831180,-0.5149421692,-0.5303933620,-0.5218394399,-1.6868261099,-0.0578323007,0.0224060658,-2.2675683498,-0.0580441840,0.7456520796,-1.2059559822,-1.2292213440,-0.2225447744,-1.3295269012,0.0634491891,-1.0590066910,-0.3777595162,1.3155578375,1.4310772419,-0.5424057841,0.1443112940,-2.4531741142,-0.8215950131,-0.1773539037,0.8877364993,0.1353154629,-0.6411932111,-0.5869292021,-1.4347361326,0.0225070901,1.1605197191,0.6720536351,-1.4405599833,-0.5473454595,0.7145345211,-1.1814160347,1.8402242661,0.3987374604,1.1327170134,-0.0116247721,0.3855871856,2.2576406002,0.3361343741,-0.6971358061,0.0903513953,1.9358855486,-0.0837212652,0.7940992713,0.6294739246,-0.0230218563,-0.4086762071,-0.7781276107,-1.5784299374,1.9371912479,-2.1188192368,0.3531058133,1.1220483780,-0.5264663100,-0.1083615795,-0.0701917931,0.1257195175,-0.3426410854,1.4279152155,0.8725541234,0.2656742334,-1.4155806303,-0.5311722755,0.5770264864,-1.9181660414,0.2317260057,0.6019353867,0.9077202678,-0.4718322754,-0.5740461946,-0.1232953146,0.9156028628,0.4621352255,0.4633850753,-0.7176672220,-0.9824862480,-0.1898862273,-0.2449781001,-1.5985085964,0.9512001276,0.8413665891,0.0192009527,-1.0423125029,-0.9620074034,-1.1568783522,0.0290435944,1.1404398680,-2.0211308002,1.6410949230,1.1472212076,-1.1088819504,0.8519145250,-0.5757724047,0.0184833016,0.5957829952,0.5147176981,-0.7896971703,-0.9568346143,0.3608250320,-2.3002521992,0.9077754617,-0.6996142268,-1.3030370474,-0.4180361331,-0.2474314123,-0.0635405704,-0.4888866842,1.1069529057,0.4685696661,0.1609025151,-2.3913598061,1.0130462646,-0.2157368809,-1.0683450699,-1.5078005791,-0.5091286302,-0.1590702087,0.3359768391,0.5903284550,-0.0485109314,-1.3737658262,0.5323999524,0.1814595312,-0.9770289063,-0.0009856647,-0.5759761333,-0.8987975717,0.5400237441,0.9631063938,0.7029232979,0.1237453818,0.6921179295,-0.9819133878,-1.1649929285,1.9168785810,0.0260932688,0.5961437225,-1.0539348125,-0.1854109466,-0.4541092813,-0.8012022376,-0.8627537489,-0.3639629781,-1.5960626602,1.1273057461,2.2912368774,-1.5819373131,0.0768916383,-0.7541574240,0.9644643068,0.4963940382,-0.3556044698,-0.1880870759,0.2791007459,0.9201265574,-1.6708345413,0.0320946388,-1.5955154896,1.6061308384,0.0217349976,0.3895410895,1.7398505211,-0.1265877634,0.4094446003,-0.6966269612,-0.6312574744,0.4016741514,0.8904861808,0.6256996393,-0.4016552866,0.4941623807,0.4165548086,-0.1249488592,0.7846920490,-0.4188575745,-0.1406167001,0.5847015977,-0.3898477852,-0.9432166815,0.0343675576,1.8963041306,1.1666419506,1.9057749510,1.6193721294,-0.5440173149,-0.2137131691,0.7101011276,0.6619938612,-0.5311143398,0.6764826179,-0.9523943663,1.3086831570,-0.3232148290,0.3837288022,1.1706738472,-0.1583350450,1.3312753439,0.2241350561,-1.6838308573,0.5691562891,-0.4549115300,0.3088451326,-0.1045141220,-0.0612401441,-0.7073890567,-1.0161758661,0.5968431234,0.8028610945,-0.2996942997,0.2950571775,0.4948324561,0.4771435261,0.2741064727,-0.2335633188,0.2663442791,-0.0397798195,0.5287874341,0.3386964500,0.0797383338,-0.0556877255,-0.8294295669,2.1340575218,-1.6558796167,0.3286934495,1.6617243290,1.0909644365,-1.7356817722,-0.3916744590,0.6007047892,0.0267706569,-0.6286586523,-0.8454390168,-1.2340822220,-0.5262479782,0.2183321267,-0.7545596361,-0.9005653262,-0.5328521729,-0.8601483703,-0.7806350589,-1.0522665977,1.8136574030,0.9027171135,-0.7261156440,-0.0490528308,0.5775359869,0.5649013519,-0.7593803406,0.3464302421,0.6238087416,0.6746863723,1.7811609507,0.0354143009,-0.7106010914,-1.6929748058,1.2977504730,-1.0984780788,1.1117619276,0.1678503603,-0.5709893703,-1.7195818424,-0.9556397796,-0.9034484625,-0.0908293873,-1.0700818300,1.3671873808,-1.8064297438,0.7554394603,-0.5026817918,1.7806242704,1.0917088985,0.8868745565,-0.0075888634,-0.4598862231,-0.7556013465,0.0549330562,0.2221430540,1.3729677200,-0.9540419579,-0.3789446354,-0.1505113691,0.7726684809,1.7614964247,1.0252877474,-0.3415622711,-1.3802000284,0.0690797642,-1.1985107660,-0.5829547644,-0.0029087467,0.6864536405,-0.7441490889,0.9273821115,1.1335115433,-0.0438062884,-1.3134324551,0.2154727727,0.3803556263,-0.3672275543,-1.3546211720,-1.5402970314,0.0953702331,-0.4527512193,0.2291198820,-0.7780883312,0.3277203739,-0.0930765718,-1.0328152180,-0.8990030289,0.9657142162,-1.7825680971,1.2948658466,0.8651069999,0.5233416557,0.6785563827,0.1730827838,0.6709386110,-0.2403714061,-0.3969297111,-0.0562244244,0.9086267948,-0.0806159154,-1.3319112062,0.4982792437,0.0500809923,0.6967548132,1.0448199511,-1.1299753189,-2.7560486794,0.1868395656,1.3268688917,0.5976457596,-1.8544654846,-0.6114086509,2.1996905804,-0.0069061555,0.9068157077,0.0332768932,0.5828394294,-0.3923009932,-1.1152610779,-1.0476948023,-0.0980769023,-1.9471046925,0.3602553010,0.6499018669,-0.3639253378,-0.6350816488,0.1268273890,0.4119163752,-1.2266123295,1.4781122208,0.3314739168,-1.3378620148,0.2472490221,-0.8766486049,0.0906429887,-0.6079481244,-0.6427965760,-0.8671147227,0.8152963519,-0.0899893939,-0.0517604873,0.2418456525,0.3122246563,-0.7654765248,1.3197525740,-0.1157104000,1.7435361147,-0.6417414546,0.6864396334,-0.8152928948,-1.3649516106,-1.5759655237,-0.1911571473,0.9851586223,-0.1836736351,-0.1282128096,1.4109607935,-0.3864745796,-1.0339030027,-1.3751579523,-0.5158736110,-1.0271582603,1.2922033072,-0.2954572439,0.4869286120,-0.2285408676,-0.0162027627,-1.9017342329,1.6025589705,-0.4845978022,-1.2267167568,-1.0501669645,-0.6654804945,-0.9559248090,-0.6065716743,0.0243174918,0.7494941950,-1.8077092171,-0.1077916324,0.8796631098,0.0062837857,0.5151043534,-0.6206137538,0.1735114008,-0.9676117897,-1.3759051561,0.0525254011,-0.5183722973,-0.1062775850,-0.8050181866,1.2755728960,0.0143800322,1.2767688036,0.9166401029,-0.3082312644,1.8080588579,-0.6768823862,0.3165327907,0.8092871904,-0.4501982927,1.8188048601,-0.9475402236,-0.0415148437,-0.8145132661,0.2790819407,-1.1835186481,0.7343748808,-0.5032110214,1.4122532606,0.2738788724,0.8091881275,-0.0099356575,-0.6308447719,1.1316365004,-0.3096952140,0.2567524314,-0.3351007700,0.8001866937,1.6676236391,-0.8846474290,-0.2603313923,0.1370266527,0.0493109673,0.9733078480,-0.3513320982,-0.8878127337,-0.7262001634,0.2246757895,3.0239856243,0.2840051949,-0.7080864906,0.4759110510,-0.0502727516,-1.0398198366,0.4720818400,0.3196711242,1.2657147646,-1.1127299070,1.2408133745,-0.3051033914,-0.1297694147,0.6046590209,-0.4969549775,-0.7131097913,-0.9040707946,0.6418151259,-1.3217216730,0.0984766409,-0.9235069156,1.1407945156,0.2827794254,0.2023810148,-1.7084463835,-0.1919159442,-1.6301255226,-0.4870570004,-0.0667773858,0.4956967235,1.3667733669,1.2660340071,-0.0160720777,-1.4300978184,1.5479718447,-0.5026729703,1.6225996017,-0.4625676870,-0.9789949059,-0.6550973058,0.4892952740,-0.0918960720,0.4369480312,-2.7726590633,-0.3816050291,1.4429813623,0.7978885770,1.0307193995,-0.2216360867,-0.0587479360,-0.1162854955,-0.3884234428,0.0990402028,0.2731604576,0.1190148816,0.0518279746,-0.1054238603,0.4520575404,-2.0491440296,-0.3809584081,0.3005086780,0.3459797204,0.3234552145,-0.1599316448,-1.6980955601,1.7123942375,1.4055458307,-0.8293477893,0.1827742159,1.4559041262,0.0637789965,0.0475166366,0.6155928373,-0.9956529737,-1.4131263494,-0.1182635501,0.8190299273,0.5125033259,0.0770660043,-0.7871782780,0.4206069112,-0.0446137898,-1.1966786385,-0.2150852829,-0.2339724153,-0.7401009202,0.5566579700,0.6771113873,1.4938442707,1.3028098345,-1.3230277300,1.6066470146,-1.3189405203,-1.7869796753,-0.8453440666,0.1779462099,-1.0992565155,0.8223231435,-0.3773572743,-1.4823824167,1.8274016380,-0.9582762718,0.8690104485,-0.1457026154,0.4907839894,-0.4807015657,-0.1869495213,-0.9083141088,-1.5402960777,0.0317795537,0.0290756747,0.2935406268,-0.0085515557,0.8803539872,0.3078594208,1.2030415535,-0.8128335476,1.6358748674,1.1200956106,0.4681635797,-0.2939386666,0.9326472878,-0.6292216778,-0.7046082616,0.2003094703,-0.8784189820,0.2474409193,0.5440397263,0.1008563042,0.5313048363,-1.4959849119,0.2413581014,-1.0873416662,-0.7164362073,1.2811007500,-0.7253606319,-0.3197246790,-0.9055584073,1.0824757814,-1.0967745781,1.4039075375,-0.8226977587,-1.5650757551,-0.1779900938,0.3357891142,1.6376110315,0.2842205167,0.0611847453,1.0054154396,1.5567678213,-0.4624824226,1.7156288624,-1.6495491266,-0.9886603355,-0.5040734410,2.1461417675,0.4368059337,0.2772457898,-1.4140040874,0.0257757753,0.3154803514,-0.2752482891,1.2735975981,0.9660745859,0.3129498661,-0.9183510542,-0.0528000295,-1.4535831213,-0.4218615294,0.2285152674,0.4834912121,-1.0394859314,1.5353862047,-0.6263337731,-0.3788434863,-1.7689143419,-0.9368940592,-0.4472614527,0.7502661347,1.1232037544,-0.2082219273,-0.3345964253,1.1510394812,-1.1813848019,0.5503615737,0.5231403112,-0.8894044757,-1.1481416225,0.3089981377,-0.0089807743,-0.3435496390,-1.4222484827,-0.6001983285,-0.2960148454,-0.6301397681,-0.2517532110,0.5226249695,1.6253954172,0.6440001726,0.6713175774,-0.9343277812,-0.4876067936,0.2829792798,1.1756912470,-0.6696252823,-0.0702424943,-1.6962444782,0.5822570324,-0.3008073270,-0.7424628735,0.4427735806,-1.6259888411,-0.2963338494,-0.9052641392,2.0158989429,-0.0409712046,0.0850246251,1.2611733675,-0.5877819061,1.5001118183,0.3374356329,-0.8833405972,-0.8129408956,1.0231391191,0.2039081007,0.5219868422,2.1710143089,-1.5364967585,-0.9825080633,-0.4576882720,0.1181099117,-1.3131301403,-1.3747745752,0.6685074568,-1.1598657370,0.1115264669,1.2732436657,0.9837774634,1.0079425573,1.2042628527,1.4757161140,1.9824581146,-0.0836161450,0.6380442381,0.6169739962,-0.6086562872,-0.5009913445,-0.5547283292,0.9836614132,-0.1071657091,1.2167388201,-0.7316679955,-0.1268628389,-0.5843551159,-0.3292862475,1.3337472677,1.3200297356,0.7653281689,0.2057382762,0.2780999839,1.9284055233,-0.4090837836,0.1546208113,-0.2178405672,1.8453789949,-0.0609560572,-0.8356684446,-2.0992302895,-1.6502887011,1.8192211390,0.5958074331,0.6264472008,-0.6886128783,0.0464336015,2.2116112709,-1.5227183104,0.2625297606,1.5642783642,-0.5167988539,-0.1535461694,1.0193160772,-0.4149324000,-1.3377883434,0.2785515785,-1.4212867022,0.5633701086,-0.5416283011,-0.5272933245,0.0087975692,-0.5657374859,-0.5035797358,0.5643779635,1.5762873888,-1.0485948324,-2.0079891682,-1.6455342770,0.7365643382,-0.0382613279,1.7036528587,1.3061082363,-0.6127634645,-0.4571321309,0.9667922258,-0.2397709042,0.7455832362,-1.3719718456,0.1176320612,-0.9625248313,-0.3331040144,-2.3206830025,-1.1050237417,0.0505683310,-1.6521037817,-1.1555784941,-1.8600842953,-0.1436365545,-1.3095002174,0.5672355294,2.2935447693,0.2653402388,-0.4710046947,0.0420597941,0.6235096455,-0.3959354758,0.6133328676,0.8685811758,0.3623816073,0.8595988750,-1.2475121021,-0.8317956924,1.3300708532,-0.6564030051,-0.3196218610,-0.9565773010,-0.9911345840,-0.7629100680,-0.9317533970,0.4946089685,-0.0070229843,0.5263068676,0.1096296310,-0.7030386925,1.3341176510,0.0588235408,-1.3557839394,1.3701558113,1.3979157209,-0.0241335556,-1.5421690941,1.3926768303,-0.0572788082,0.0924422741,0.1306796372,-0.4506987333,1.0594346523,0.2627052665,-0.7358296514,-1.7386627197,-0.8884651661,-1.5768609047,-1.2932181358,-0.3603904545,-0.5076446533,-1.8667639494,1.0743008852,0.7913588881,1.0181564093,0.6479498148,-0.0823470876,-0.0806593820,-0.4157681167,2.2641456127,0.4007044137,-0.3426760733,0.3771518767,0.5061627030,1.5559914112,-0.4237650633,-1.1088336706,0.7923083305,0.6938353777,-1.3250257969,1.5535944700,0.0049045268,1.1246401072,0.0097699733,1.5038679838,0.5279566050,0.6128170490,0.3623874485,-0.0392698757,0.3612433374,0.6001952887,-0.7416902184,-0.3430719972,0.1613178700,-0.6219967604,0.2432402670,1.3867510557,1.4010163546,-0.6260728836,-0.2785092890,-0.8145068884,-2.1860978603,0.4015526474,-0.5687218904,0.0735837519,2.3719646931,-1.2226122618,-1.7341774702,0.5211261511,-0.7689599395,-0.4643093646,-0.1880650520,1.8296451569,0.1179625243,-1.2873387337,0.2452962250,0.7529872656,-0.4656670690,-0.7779188156,-0.9317938089,0.2511917353,-0.8010789752,0.3875940442,-0.2854766250,0.2135651559,0.9496786594,0.4434437156,-0.2921417952,-0.2893070579,1.8729990721,-1.3912776709,0.8823206425,-0.7693408728,0.8297691941,0.6176412106,-1.6273237467,1.3451734781,0.7532227635,-0.9126815200,1.1919921637,-0.1777725518,-1.3362666368,-1.0282952785,0.7495453358,0.7746673226,0.5302920341,-1.1779735088,0.4359086156,0.9370511770,0.6625077128,-0.2525390983,-0.1961964667,0.6796283722,0.1560912132,2.0079288483,-1.3467699289,-0.9276216626,-0.0741150156,-1.6958822012,-0.2605181336,-1.2530063391,0.2627429664,0.7165470719,-1.8141559362,-0.9000178576,0.7370605469,1.4289104939,-0.6930576563,1.7424666882,1.6449006796,0.5382955670,-0.7510215640,-0.2363715321,1.0369923115,0.9657538533,-0.7431786060,-0.8046639562,1.4332410097,0.1665688902,-0.6746644378,-0.3744138181,-0.2142071873,0.3782551587,-0.0284325425,-0.5066626072,2.2650198936,1.4231873751,-0.0743084699,0.4235864282,1.5384422541,1.3585460186,-0.0352351889,-0.2189443856,-0.8031013012,2.0303540230,0.5452772379,0.2255565971,0.0925863236,-0.4921898842,0.2845351994,0.2062941492,0.3464781344,-0.0111541692,-1.7251620293,-0.7196274996,1.0001733303,0.1533291489,-0.7373467088,-0.4225189388,0.1528119892,-1.0180543661,-0.2779996693,-1.5780826807,-0.4613038599,0.5342951417,-0.1558797210,0.0374767967,-0.3804990351,-0.4957786202,-0.2577657402,0.5751443505,-1.0979690552,0.0594886243,-1.0828264952,-0.1919242889,-0.3676927984,0.5205117464,0.1584236622,0.1191426143,-0.8184567690,2.6164002419,1.8043608665,-1.4470647573,-0.7504413128,-0.0128210383,1.7690523863,-1.0356879234,-0.8855569959,-0.8161084652,0.3014318943,0.0012616556,-0.5786834955,-0.5376681089,1.7274968624,0.7023185492,0.0531656817,0.0197559502,0.0192194246,-0.4238943756,1.0916885138,0.3940524459,0.6978895664,-0.5300963521,-0.1750378609,-0.7282319665,0.3309630752,-0.7242958546,0.8023917079,1.2333136797,0.0600263327,1.8488427401,-0.7148504257,0.4385460615,0.9688469768,0.0299088582,-0.9750109315,-1.0483665466,0.0277658887,0.2368310541,-1.2071895599,1.2570800781,2.0445125103,1.6918454170,-0.6865190268,0.2112120986,1.5974457264,-1.1287384033,-1.5620183945,-0.9195592403,-1.1469166279,-0.2893614471,0.6627973914,1.0217088461,-0.3918666542,2.0864372253,-1.0320661068,0.3124392033,1.3697936535,-0.3738217652,-0.1886551231,-1.0122405291,0.8189871907,-0.3247868717,0.3251466453,-0.2431050241,-0.1908031404,0.0159445219,-1.1716156006,0.4313590527,-0.4181154966,-0.5454003215,0.3107697368,-0.4312063754,1.6988054514,0.3427794576,0.5752515793,0.3136224449,0.0746937171,-0.2343776822,1.3644443750,1.7880711555,-0.8330552578,-0.6701244116,0.0977286845,0.6908764243,-1.6960651875,2.1555716991,-1.0845538378,-1.0772690773,0.9238383770,0.1551842541,-1.7129218578,1.0820883512,-0.6496840119,-2.1078553200,-0.8854192495,-0.0315521695,0.1816882342,-1.6160395145,-2.0274572372,-2.2314357758,0.3817986846,1.3415185213,-0.7032774687,-0.6273907423,-0.5772133470,0.8161108494,-0.3537312150,0.8900743127,0.7412501574,-0.1986007243,-0.0569934621,-2.0071425438,0.8271296024,-0.2330507785,0.3007969260,-0.4647093117,0.4949223399,-0.4368942380,-0.0580027997,-0.2060611546,0.5465889573,-0.7176531553,0.2781758308,-0.0540548712,-0.8538475633,0.7752673030,-1.1576044559,-1.6881654263,0.2807030082,-0.8262535930,-0.0240261238,-0.9551573396,-0.2277644128,-0.2805421650,-0.2276842594,0.8241704702,1.1559234858,-0.7621541619,0.1560282558,-1.3470283747,2.0022385120,0.4317237735,1.2540224791,-0.1634758413,0.8219774365,1.1389209032,1.5196316242,-0.1628244519,-1.0992746353,-0.9544483423,-1.6510956287,-0.6569509506,1.0500578880,0.6824148297,1.5513504744,0.4548636675,2.7451868057,1.0425418615,0.1934823841,1.9569149017,-2.2074351311,0.9075617790,2.0576922894,0.8540446162,-0.9392482042,0.0225526020,-1.3599926233,0.0982640311,-0.4961391985,-2.2542142868,0.7189049721,0.5635581613,0.7037670016,0.3800044656,1.0090733767,0.7960253954,1.5524606705,-1.0578310490,0.0954674557,0.6344092488,0.2032889277,-0.2713959813,0.8102875352,-1.6120643616,-1.3914624453,1.3278867006,0.7482947111,0.8191539645,-0.2149544358,0.5363849998,-0.9918892384,0.8326933384,-0.4563343227,0.9957206845,-0.3911642730,-0.5761083364,-1.6257008314,0.3507175446,-0.6471960545,-0.6633731127,-1.1012862921,-0.1357158273,-0.4140460193,1.1256126165,-0.2547148466,1.1853294373,-0.6736295223,-1.2852391005,-0.6020596027,1.0396854877,-1.1734688282,1.0483592749,-0.1930020899,1.4001460075,0.6863822937,0.1874726713,0.1960242987,0.3801824749,1.2780096531,0.0715012625,-0.5726922750,-1.1324484348,0.3092543483,-0.1041374058,-0.7648612261,-0.6558532715,-1.1425851583,0.3871780038,0.9160779119,-0.2528611720,0.3229587674,-1.3621455431,1.0407729149,-1.5615122318,-1.7674455643,-0.1657711864,0.3561912477,-1.0535864830,-1.3808097839,0.0066822111,1.7632035017,-0.5058322549,0.4460215271,1.8662033081,-1.4253808260,-0.0295527857,1.3246070147,-0.4824059010,-1.3144742250,1.6353757381,-0.7058399916,0.6552345157,-2.3853127956,2.0654399395,-0.8080892563,-0.7019706368,0.4695746005,-0.5398542285,1.9267045259,-1.6482932568,-0.7667036057,-0.0920951143,-0.3394153118,0.4104304612,0.0820508972,-1.0529474020,-0.1035258546,-1.2655054331,-0.8173121810,-1.5338441133,0.7748808265,-1.3071223497,0.7862274051,1.2642416954,-1.6465983391,0.7156240940,0.0004608648,1.3903490305,0.7563246489,0.7296988368,3.1193788052,-1.5182796717,-0.4620943666,0.6188848615,-0.6592494845,0.1667702049,0.1148974299,-0.4236586988,-0.6178045869,0.5739185214,-0.7387426496,-1.9529211521,1.4813373089,0.9259881973,-0.3275189400,-0.5661215186,1.0159183741,0.3718490899,1.7064806223,1.0632951260,0.2158806324,-0.0558133088,0.9810810089,1.0780202150,1.5175112486,-1.0642248392,0.8798881769,1.0489073992,0.7985528708,-0.2425360382,-0.5692839622,-0.4421700239,1.1829074621,0.1835972518,0.4506121576,0.9762408137,1.1348419189,0.5359632969,-1.2192471027,-2.3011717796,-0.2138852626,-0.4985000491,-0.1059588790,-0.0988596678,1.0034368038,-0.5149103403,-1.8779270649,-0.6865703464,0.1736295819,0.8265163302,-0.5225960612,-1.3647763729,-1.0260533094,0.2010704130,0.6330992579,-0.8404617310,0.3592998385,0.3706113994,0.5354285836,1.0670536757,-0.1831074059,-1.4682694674,0.0098087247,1.5302503109,0.1058414206,-0.1238831207,0.4766884148,-0.4761192799,1.2386989594,0.8832945824,-0.0387233086,1.3760423660,1.6366331577,-1.9266943932,0.2121179402,-1.6006190777,0.1265319735,-0.9488639832,0.3272991180,1.2126785517,0.6757702231,-0.9969081283,-0.8930254579,-0.6828251481,2.1810488701,0.1021359116,-1.7115709782,0.7546977401,1.5872236490,0.2561224401,-0.6409754753,-1.3000752926,-1.5575027466,-0.3797564209,-0.2285472006,1.1859147549,0.0516077168,0.9234830737,-0.8794897795,-0.2575468421,-1.9377614260,-1.5830955505,-1.5876456499,1.1509450674,-0.4737126529,-1.1898517609,1.3928337097,1.6262747049,-0.4686792493,1.0509574413,1.5402649641,-0.7110273242,0.7389134169,-0.4548214078,-0.8832143545,-0.7396560311,-0.8138209581,0.4599758983,0.0499489568,1.7926896811,1.0037494898,-0.0817498639,-0.9807576537,0.1917232126,-0.7828310132,-1.9145452976,0.4286828935,0.9644827247,0.0961133540,-0.3806517720,-0.5880751610,0.0334974229,1.4758988619,0.0888777971,-0.6958780289,0.1805043221,-1.7607322931,0.2534747124,0.0275088325,2.2588088512,0.7110636234,-0.1102534533,-0.0299374927,-0.5157200098,-0.4786728323,-0.7900257111,0.4293768108,0.3290570080,0.0805050284,0.6053853631,-1.1858336926,0.1329994649,-0.8362782598,-0.4463221431,0.2802517414,1.5189036131,-0.9790352583,-1.0094639063,0.5211237669,-1.6937114000,-0.1594283283,0.6029412746,-0.0587336123,0.0071533583,0.0523125641,-0.2256063074,0.1295899749,0.1687475741,0.6759440899,-1.6508245468,-0.6614670157,1.0911030769,-0.4605453908,0.4364682734,1.3217781782,1.1893281937,0.1233901903,-0.9958592653,-0.3711001277,0.5379791260,-0.0070412341,-0.3989662826,-1.0785380602,0.1701700389,-0.3741233051,-1.2407640219,0.4376882315,-1.1232664585,0.4728543460,1.7027870417,0.3569022715,1.6514447927,0.0602583177,0.3123974800,0.1193226576,-0.5213288069,-1.4381340742,1.4283020496,0.5926224589,0.1629691124,0.5686670542,-1.0246697664,-1.1791366339,-0.9171492457,-1.4742364883,0.7465749383,0.4492428005,0.9631430507,1.0591726303,0.1239316314,-0.3596034646,-1.0907340050,-0.6030093431,-1.1057633162,-0.8140255809,-2.1808836460,0.8547969460,-1.1567357779,1.3341215849,1.3263473511,-0.6043748856,-0.6644125581,0.8303882480,-0.7894672751,-0.5509001613,-1.1912413836,-0.4110831618,0.0052479375,-0.5508015752,1.2821806669,0.8930993080,2.6927654743,-0.0384279191,-3.2195563316,-1.0180802345,-0.8228209019,1.4848512411,0.1804568619,-0.0416801386,-0.4823452234,-0.3673158586,-1.7843573093,-0.6924807429,0.5369516015,-0.6816094518,-0.7692908645,-0.4790070057,-0.4438000023,0.0430159196,-0.1231807619,-2.3414075375,0.4058639705,-1.1069461107,0.9379891157,0.5567139387,1.6205422878,-0.0333523005,0.4900620282,-1.5986202955,0.5159187317,-0.8220391870,0.5268859863,-0.1108082831,0.9905723333,0.6257894039,1.1551108360,0.2970907986,-0.0550662689,-0.3417685330,0.4716485739,-1.9665927887,0.6737215519,-0.3018049300,0.1630557626,0.4377413690,1.6650433540,-1.2340313196,1.0803861618,-0.9714391828,1.0315043926,2.7991528511,-0.9023184180,0.3342669308,0.8662059903,0.4187904596,1.6631202698,0.9461517334,0.0383105762,0.3874709606,-0.9331662059,-1.5427381992,-1.2080690861,-0.0268997028,-0.3367968798,0.8820804358,0.8696154952,-0.9525085092,-0.1397367120,-1.0950832367,0.9954438806,0.1454400718,-0.1136238873,2.0428493023,1.1829013824,1.1000951529,-1.1066437960,0.1360276341,0.7086342573,-1.2057681084,0.1230445802,-0.0300690066,-1.3471719027,-1.1712793112,0.4815954268,-0.0332318284,0.0187704470,0.8783824444,-0.2106922418,2.4618752003,1.7784832716,0.2102992982,-0.2804616690,1.8727797270,-1.0322837830,-0.6775320172,0.5041838288,-1.9068819284,-0.4035941362,-0.4970909655,0.4764173329,0.7262157202,-1.3696603775,-0.2180223465,0.9146516323,-0.6380504966,-0.6836457253,-0.9392985106,2.5385532379,0.7848135829,-0.4739396274,-0.1609451324,-0.3473201990,0.4547399580,0.0022027995,0.3719330728,-0.2290373445,-0.8378288150,-0.5939671993,-0.4501929879,-0.9564500451,-0.7512276769,0.3331740499,1.7069742680,-1.8661465645,1.6704733372,-0.7440801859,-0.5513499975,-1.3664151430,0.4946258068,0.6614918113,1.0545921326,0.7613997459,-0.1494040340,0.1473492235,1.0284640789,0.1794055253,1.3030784130,-1.0664352179,0.8017191291,1.0707521439,0.4280396998,0.7229521275,0.6674688458,-1.4753994942,-0.1161597595,-1.5815646648,-1.1041642427,0.2921075225,-0.6162883043,-1.0617330074,0.0474488698,-0.2354591340,-0.3827132881,0.0709788352,0.9242456555,-0.7282121181,0.5422099233,-0.7606021762,-0.6083860993,-0.0204535741,2.1217327118,-1.1327162981,0.5107544661,0.0726600289,-0.0524952970,-0.1610554010,0.5236122012,0.4384548962,-0.2347787917,-1.5538160801,-0.2386575490,-0.0072724433,0.5456941724,-0.1086401194,0.7346530557,-0.5908902287,-0.1918531358,-1.8580100536,-0.5037835240,2.0335335732,-0.9577164650,0.0651107430,0.9060782790,-0.5345256925,0.1751286089,0.4575206637,0.3239696324,0.0477281995,0.8175007701,0.9586806893,0.2785039842,0.5604625344,1.0212132931,0.4966633320,-0.0258158334,0.9687435031,-1.3536084890,0.8649412394,-0.8730837107,-0.8804031014,-1.6783584356,-0.5945875645,1.2743442059,-0.6184026599,0.1897069663,0.0141431382,0.2350640744,-0.7193506956,0.1511185616,-1.5639774799,-1.2819161415,0.0610125959,-1.1097881794,-0.8521714807,0.5019956231,0.0409483574,0.1502437443,-0.7988834977,-1.8650946617,0.5831124187,-0.7960220575,0.2591686845,-0.0523419008,0.6130117774,-0.4703146815,0.8446735144,0.9293216467,-0.7193233967,-0.3462554812,0.0266267434,-0.2921901047,-2.0190968513,0.8755489588,-0.1333952248,2.0068006516,1.4492278099,0.1540557742,1.7440308332,-1.0899720192,-0.3867556453,0.1545641422,-0.7254714370,0.7313339710,2.5498569012,-2.4311244488,2.2926156521,1.3991469145,1.1989866495,1.3550738096,-0.9609283209,0.3282889426,0.8142353892,1.5970354080,-0.2387523353,0.0792709738,-0.5485795140,0.4264426529,0.2009727061,0.3822948635,-0.3160178065,0.9924373031,-1.0522011518,0.6819784641,0.1449483186,0.7345592380,-0.4123094082,-0.8291899562,-0.1473677456,-1.9918057919,1.2308152914,-0.4426414371,-0.3787471354,-3.0473160744,-1.6859333515,-1.3871006966,-0.0958412439,2.0981168747,0.5395963788,0.5177062154,-0.6460278630,2.3688600063,-0.7596668005,0.8309730291,-1.3052463531,-1.1465224028,-0.2534221113,-0.0777573884,1.5662372112,-0.8439161181,0.5423812270,-0.4233368933,-0.0301173329,-0.1885342002,-0.7636304498,0.6386103034,-0.3293936551,-0.5986554623,1.6507289410,0.6110025048,-1.1714577675,0.2430572808,1.4613201618,1.2600826025,-0.5669208765,-2.4710955620,0.7282733917,0.0715143606,2.3573234081,0.2791848481,0.3507069945,-1.4286094904,-1.3957622051,-0.6828049421,-2.1207742691,-0.5035426021,-0.0339629166,0.7257949114,0.6201557517,1.2286385298,0.9077768326,-0.3393974602,-0.8418522477,1.1805078983,0.0826563761,1.4109766483,-0.1218153611,-1.1622179747,0.6720657349,0.8871431947,-0.6016659737,-0.2201759368,0.5747567415,-1.4447933435,0.4896268249,0.7228952050,-2.4493446350,-0.7032957673,-1.5452859402,-1.4874507189,1.7770699263,-0.5654845834,0.9598588943,-0.2666018903,-0.1979894638,-1.8093239069,0.5844339132,0.0779933855,-0.7883568406,2.2556648254,0.2092601806,-0.0397630557,1.2062901258,1.1393060684,-0.5246899128,-0.6015848517,-0.1014802530,1.8655210733,-1.2383139133,0.0829883963,0.3803620636,-0.4085579813,3.0920526981,-0.8149982691,0.2523723245,-0.3126744330,0.2925846577,1.2427134514,-0.3900679052,-2.2280981541,-2.0701429844,-0.5498985648,-0.3402158022,-2.2202494144,1.0159556866,0.8057820797,1.4112379551,0.4200439751,-1.3517037630,-0.4663037062,0.8230061531,1.4041137695,0.0515968874,-0.3207317591,-0.9438809156,1.0704278946,0.8321710229,-0.0838056281,0.1407217234,-0.4895201027,-0.1014306247,1.3761303425,1.7014065981,-0.2475039661,1.0797243118,0.2581546605,-0.0555630252,-0.7183734179,-0.4093923867,-0.4314723313,1.6992679834,-0.5810607672,-0.4299448729,-0.1757195890,0.4817943871,0.8706088662,1.1988463402,-2.6215486526,-2.0343215466,0.4191960394,1.6816884279,0.2876927257,0.9413163066,0.7395244837,0.4954246581,-1.6228507757,-0.6659519076,0.6042791605,-0.3217880428,0.1207242757,-0.2647857964,0.2765117884,-0.1759828329,1.1069335938,0.4527967274,1.9177540541,-1.4181673527,-0.5517150760,1.4401162863,1.2062914371,0.1064064354,1.1001257896,0.5693667531,-0.0823822916,-0.8558875322,-0.3975574374,0.8107486963,-0.7338398695,-1.6810228825,0.2814816236,2.0815069675,-0.8396160007,0.7340915203,-0.1046710759,2.3806743622,1.1243662834,-0.7335973978,1.3209965229,-0.0835166797,-0.4221691787,-0.2683244646,-0.2047377080,-0.8506658077,0.3369838893,-1.3512299061,0.5600090027,0.4778011739,-0.9195017815,1.3022620678,0.0175112654,0.5426177382,0.1755894125,1.0299211740,0.7771252394,-1.3532475233,-0.3722300828,-0.1029285714,0.7554801106,0.5151497126,0.3328151405,0.2304541320,0.1953039616,-0.5153769851,0.4043092728,0.1988413036,-1.2689567804,0.4159680605,0.3145648837,1.0199477673,-1.7042839527,0.8625801802,-2.2885460854,0.4905623198,-0.5468719602,-1.4397684336,-0.2191286832,-0.3316198587,-0.0544967875,2.1939680576,-1.3659399748,-0.3305815756,-0.7713046670,0.9388977885,-0.7135739326,0.1881475300,0.7682553530,-1.1076250076,2.2674283981,-1.1733065844,-0.0992131382,-0.0065833130,-0.7474772334,-2.5292699337,1.3511906862,-1.0686225891,2.1275341511,-0.7644865513,0.7966610789,-0.0352354646,1.6254175901,-0.4221188426,1.3619796038,0.6780332923,0.3214618266,1.1740883589,0.0146083022,-0.9775192738,-0.8737570047,-0.3637194037,-2.3226566315,1.0262193680,0.3523386419,-0.8140775561,-1.0497467518,0.1893426478,-1.9934339523,-0.4920479059,0.0709401369,-0.2049642354,1.6265887022,1.4623658657,-0.3380526900,0.6974494457,-0.6214071512,0.6323260069,-0.1815361679,-0.2832997441,0.4412190616,1.0376160145,-0.0181217846,0.2928813994,-1.3679971695,0.6803232431,1.3326506615,0.5246801376,-0.4922191799,-1.0667096376,0.5750662684,-1.2777228355,0.4103414118,0.0826276764,-0.0194279980,1.1380794048,-0.7974613309,-0.1227394193,-0.4622454047,-0.9462473392,-1.0382105112,3.0540573597,0.3594521284,0.5559291244,0.7019115686,-0.1078845412,-0.8671279550,0.3546288610,0.7513562441,0.1686596423,-0.2308986932,-0.6836241484,-0.9934930205,0.0928095505,-0.4998281896,1.3151831627,0.7407268286,0.5519161224,-1.9649449587,1.5386253595,1.6443663836,1.4250090122,-0.4822165370,-1.0676637888,0.3187181652,0.4153170884,-0.8883006573,-0.2742860317,0.2505654395,0.3850674331,1.8112043142,-0.6003881693,-1.2677028179,-0.0657587349,0.5034014583,-0.1584416926,1.0296255350,0.7896546721,-0.1844998002,-0.8324058652,0.7251090407,0.3456537127,-0.1612031162,0.5519640446,-1.2285329103,0.4051709771,1.7382738590,-0.7669152617,1.3024536371,-0.2334417999,-0.8495087028,0.0963180736,-1.4320399761,-0.4009811580,-0.0825446695,-1.6872545481,0.3303807080,1.4178494215,-0.7337759733,0.9069579244,-0.9080467820,-1.1837409735,-1.2833039761,-0.7491318583,2.5821473598,-0.5403444767,-0.4830243587,-0.2678615451,0.8788146377,-0.0934342444,-0.6283229589,-0.1921992749,-1.9643006325,0.2488131225,-1.1531807184,0.3248987794,-0.2471186668,-0.7058179975,0.5422291160,1.1079134941,1.4611216784,0.8116730452,-0.0140767116,0.4220570624,-2.0194842815,-1.1250903606,-0.9013854265,-0.1820059419,0.3428933024,-1.2460854053,1.4754422903,0.9102709889,-0.7721157074,-0.0860439911,1.6187556982,0.5236514211,0.6717063189,0.8059553504,-2.1456305981,1.8775573969,-0.8045200706,-0.7242151499,-1.2274599075,-0.3879765868,0.0832767859,-0.9325447679,-0.5355188251,0.7970010042,-1.0122157335,-0.2169611752,-0.4314942956,-0.7536115646,0.9737334847,0.5086837411,-1.4131776094,0.0424655750,-0.5832741857,0.7751629353,0.6793202758,0.4981907010,0.6098150611,-1.0555416346,-0.4501825869,1.2009423971,-1.1430513859,1.2606869936,-0.2908736765,-0.3532292247,0.2760093510,0.0486681461,-0.9852678180,-0.5179210901,2.9281203747,1.8839042187,-1.2333828211,-0.5978958011,1.6062750816,-0.3856277764,0.3353347480,0.9008058310,-0.4921723604,0.4860668480,0.1493294090,-0.3788942695,0.3776074946,-0.1087439433,0.8221364617,-0.0039486336,0.0350735076,-0.7033908367,-0.3409045637,1.2027546167,0.0638573021,-0.4985602200,-0.3220447898,0.8035058379,0.0312587582,-1.0049045086,0.0859072581,0.4213287532,1.3841396570,-1.9018831253,0.2462813258,0.3927054703,0.8714232445,-0.5415591598,0.9047995806,1.5702162981,0.5778482556,-0.3848070502,-1.4516043663,-0.1781129241,1.0578336716,0.1071197763,0.4987775087,0.4444977641,0.1904703826,-0.0500574149,0.8652390838,-1.3767344952,0.6599958539,-0.1546868533,-0.4128006697,0.4206206501,0.7529597878,1.6279267073,1.6883649826,0.3809396625,1.4642118216,0.0701802224,0.9007957578,-1.0695656538,0.0756013691,-0.2558471262,0.6178277135,-0.1640721709,0.5888280869,-0.0450142436,-1.9780269861,1.5108190775,0.0201296490,0.3490985334,-0.8458254933,-2.2395009995,-0.1078830585,-1.2979288101,2.2681913376,1.1489452124,0.5595183969,0.6483691335,-0.8494003415,-1.2000247240,-1.7947679758,-0.3354310393,-0.8372511864,0.4137484133,0.4951325357,-1.3353157043,-0.4037382603,0.1360496730,1.7940540314,0.5145080090,-1.1026799679,0.3898757398,-1.3311768770,0.6445837617,3.1182668209,0.7394161224,0.5409551263,1.4241337776,-0.4103944302,-0.9392827153,-1.0108066797,-0.9068341255,0.0709434673,0.9242113829,-0.2061729133,-0.5818979144,1.0988814831,-1.0460087061,-1.2680871487,0.4011656642,0.7063562274,0.5195142031,0.1841870248,0.4354915619,-1.1544827223,0.7519261837,-0.8682871461,1.2139902115,1.8845286369,-0.3824562132,-2.9315984249,1.0975605249,-0.6656762958,-0.3710460961,-0.4581338763,-0.1719742119,0.6240089536,1.4918496609,-1.3402218819,0.5351183414,0.3458021283,0.4096876383,0.6907798052,1.3452779055,-1.4073811769,-0.7307488918,0.4452004731,0.9288562536,-1.3342907429,-0.9971263409,-0.2311260700,-1.9997789860,-1.1380411386,0.5919696689,-1.6074502468,-0.5450325012,0.1557483375,0.4483186901,0.7535129189,0.3043299913,0.7550746799,-0.7720427513,-1.0777661800,1.1778817177,-1.8641024828,0.5344553590,-0.0597600453,-0.5732216239,0.9112659693,0.1287456751,0.8489707112,0.4421401024,0.6027107835,-0.1285692751,-2.4745180607,0.1951732039,0.7277007699,-1.4732520580,-0.4286610782,-0.1154345125,-0.0769550353,-1.2591086626,-0.1017499194,-0.0210780762,-1.1737729311,-1.1453151703,0.3725708425,0.8576273322,-0.4034656584,0.1232902855,0.4509639442,0.3320712149,0.2331693470,-0.6623501778,1.1165158749,0.3908354342,-0.2755193710,0.7766165137,2.2021074295,0.7839115262,0.1298831701,-0.8191106915,-1.3449116945,-0.2769561410,0.0589544252,1.4789159298,0.6346148849,-1.5675116777,-1.2349410057,0.0871513784,0.4487423897,-0.2801265121,0.8739984035,-0.6375115514,0.2110447139,-0.3336372674,0.9330590367,-0.5646930933,0.5073488355,-0.0384628698,-0.3513286114,-0.8750590682,-0.9063674808,-0.3104023635,0.4549559355,0.0239758920,-0.5857896805,0.0329510607,0.6853071451,-0.9402374029,-1.0898227692,1.1488786936,0.3411648273,0.7200110555,0.1597515345,-0.3885217905,1.3693848848,-0.3649668992,1.1565055847,0.0767926425,-0.2566693127,0.4097830355,-0.1426362097,0.5309285522,-1.0245457888,-0.0216459669,0.5516811013,0.1327580810,-0.2019371092,2.0907456875,-0.6933072209,-2.1148211956,-2.0299284458,0.3427873254,-0.0116709834,0.4638992548,0.6261547208,0.5721890330,2.9009780884,-1.1405460835,0.1877879500,-0.1944549531,-0.1844120920,-0.5303893089,-0.4590159655,-0.1941795200,-0.1404060721,-0.7878784537,-1.3694969416,-0.0244819149,-2.6898519993,-1.0086953640,1.1471830606,0.5464369059,0.9971829057,-0.0929342508,0.7358595729,-0.2085779309,-0.9564427137,0.2623963654,-0.7120863795,-1.0331848860,0.2814248204,0.2566384077,2.1200895309,-0.7847632170,-0.9394590259,2.1373596191,0.4847322106,-1.0768883228,0.0257185530,-0.3627569079,1.1377524137,-2.3272347450,-0.7009713054,-0.3798924983,0.5566964746,0.2665447593,0.2588733137,-0.4382838905,-1.5288709402,0.7454527020,-2.0549416542,-0.7336265445,0.7902216911,1.0842144489,0.8565483689,-0.5160650611,-0.2388527393,0.1325882673,1.2349766493,-0.5192912817,0.6799807549,0.3111981750,-0.1828193814,-0.6931616664,1.0630458593,-0.3297859728,0.3573651314,0.1918357015,1.0749788284,0.8603224158,-0.5975485444,-1.3843562603,0.9666813612,0.2949757576,-1.0964585543,0.9764108658,0.0149889840,1.0665789843,-0.8470121622,0.8645345569,1.3421913385,0.7372649908,-1.0292098522,-0.7991414666,2.0994555950,-0.0386573002,-0.1209427640,-0.1018707603,-1.8904802799,0.2138135731,0.5829991698,0.1209255829,0.2682153881,0.1597340852,2.0694198608,-0.8160514235,0.9405336976,-0.2612581849,-0.7488277555,0.2938060462,-0.4454466403,2.0709934235,1.0594415665,-2.0218315125,0.1861803085,-0.3184541464,1.0500028133,-0.7971460223,-0.4653572142,-0.1952562183,-0.3340694904,-1.5124847889,0.8677157164,0.1723863482,1.2384344339,-0.1841048002,-1.2000898123,0.4072071910,1.3923242092,-0.7195712328,-0.9771297574,0.7300099134,0.0627533272,1.9138554335,-0.0584848188,0.8246739507,-0.4379732609,1.9184089899,-1.5187605619,-0.8122234941,0.8544716239,-0.3368932903,0.4989197552,-0.6576798558,-0.5772010684,1.0729271173,0.8953892589,0.4057393372,1.2137151957,-0.8393722177,0.0525206178,1.3459855318,2.1250915527,0.1242673770,-2.0543036461,-0.7189696431,-1.6973289251,-1.5774748325,-0.0314979739,-0.2412691116,0.2239166349,-0.5194889903,1.0742644072,0.1609522700,1.0746810436,0.1200929657,-0.2726342082,1.4211553335,0.0857824907,-0.2053765953,0.3187888861,0.5143779516,-0.5992152095,-0.6816874743,2.9358263016,2.0151743889,0.5622567534,-0.0935387388,0.1492368132,0.5007673502,0.5098925233,1.1149957180,2.1785109043,0.6689604521,-0.9561447501,-0.7765575051,-1.2729759216,-2.5599219799,1.2151373625,0.5340461135,-0.6273633838,-1.3690152168,-0.7996125221,-0.2076777518,0.5959313512,0.0312181860,-2.0051684380,1.3749988079,0.5573381186,-1.8676750660,-1.1792148352,-0.4203329086,0.0985771790,0.6573711634,1.1733105183,0.3345836997,-1.2246304750,-0.5836922526,0.4716092944,0.4792221189,-1.2958402634,1.8630772829,0.2784361243,1.0937455893,-0.2099616975,0.4214741886,-0.5144574046,-0.2383110076,1.2241157293,1.1667163372,-3.0629582405,0.2755071521,0.9796141982,1.1982212067,-0.7435212135,0.0888084620,-1.1646779776,-0.8349477053,0.1836696565,1.0464693308,1.4091336727,0.3512982130,-1.1093584299,-0.0148777813,-0.7249640226,0.5148887038,-1.1883825064,0.7954053283,0.0648263469,-0.3492616117,0.6866639853,0.1444717646,1.5906834602,1.1906172037,1.1974231005,-0.2618243992,-0.7974213362,-0.7960732579,-0.3851014674,-0.9355871081,-0.6335410476,0.1873655766,1.1265091896,-0.0838515311,0.1801059991,1.3423806429,0.8518787622,-0.6987745166,-1.1183056831,0.0339035653,1.2098129988,1.0811673403,-0.1526868492,0.5863786340,-0.6288794875,-0.2684370577,-0.1966408342,-1.8438454866,-0.7123699784,-1.7283849716,-0.9004950523,0.4246796668,-0.3308639824,-0.0020428838,1.0246882439,-0.8577266932,0.6733812094,-0.9730071425,0.5584130287,0.3536276817,0.5739370584,0.5155097246,-0.0672519654,0.1801947504,0.1836582124,0.5291321278,0.5086742640,0.0655369684,-0.8849287629,0.6907548904,-0.0488187782,3.3209657669,-0.0501876213,0.8470934629,0.1091856286,0.5762174726,0.1049321070,0.4455679953,-0.8758905530,1.8857425451,0.7774903774,-0.0076641762,0.8670355678,-0.3381590247,-0.8557353020,-2.0405881405,-0.2047748268,0.5438323617,-0.9618906379,0.7381688356,0.3258624077,1.4617965221,-0.0028879009,-0.2676487267,-0.8923782706,-1.8217835426,-0.0186384395,1.7530089617,-1.1791179180,-0.4352858365,0.9670229554,-0.3449574411,-0.3940675259,0.4946045578,0.2536029518,-1.0679191351,-1.2482924461,-0.1159172207,0.8719373941,-0.3312026560,-0.3494094908,0.6839279532,-0.5084854960,0.7218002677,-0.2618828714,0.3507729471,0.2381303906,0.7938268185,0.7570793033,1.0622991323,0.6175446510,-0.9916316271,1.6769894361,-0.3215295076,-1.0892727375,-1.4173982143,-0.5432204604,-0.2167730033,1.6159602404,-2.2631447315,0.9030470252,0.6519251466,-2.4697923660,-0.8317915797,0.0972767100,-1.2725318670,0.6019590497,0.0795885250,-1.1497843266,-2.4003005028,-0.9797340035,-1.4273698330,0.6937153935,-1.8866250515,-1.2132887840,0.2422034889,0.9020537734,-0.6387479305,-1.2040439844,-2.5717265606,-0.9823888540,-0.8603173494,-0.1113521829,-1.5185772181,0.3711701632,0.7167190313,-0.2066891938,-0.6412582994,-0.9086228609,1.2789639235,-0.5552526116,-0.2739999890,0.6681884527,0.2850576937,1.1664259434,-1.3593558073,0.3325866759,-0.2983123660,-0.1339031905,1.3430116177,-0.1880369335,1.9697154760,-0.1896455884,1.6410228014,-1.5998033285,0.4156921506,0.5480934978,-2.6319608688,0.3182291687,-0.4545027018,-0.0404811949,0.5020309687,0.4129009247,-0.9264763594,-0.8234125376,0.6390948296,-0.0019334590,-0.5494630337,-1.3261779547,-0.7078437209,-1.0352882147,0.8757877350,0.3657563031,1.5296053886,0.6850796938,1.3457660675,-1.2615861893,0.0619928725,1.7164348364,1.1516953707,1.2520174980,-0.0763857737,-0.9964673519,-0.6538204551,-0.7642871737,-2.7673952579,0.0269780625,-3.5376372337,0.2615314126,-1.8532675505,-0.3508562446,0.3244189620,0.4992468953,0.2832391262,-0.8766116500,0.3057894111,1.6057144403,2.1141822338,-1.0781127214,-0.9287056923,-0.8534093499,-0.2685569525,1.3060340881,0.1535290927,-1.2112205029,-0.4509466588,1.3873354197,-2.5044455528,0.5372287631,-0.6981587410,-0.4939994812,-0.2896173000,-0.2453738302,0.3176817298,1.4238258600,0.7012366652,0.2226518840,0.8875376582,-0.2895725965,-0.5405652523,-0.5801152587,-0.6099621058,-0.1794458330,0.3522992730,-0.3782028258,0.5201066732,0.7829122543,0.1191232353,0.1265148669,-1.2816922665,0.5576660633,-1.7459415197,0.2186397910,-0.5908021331,0.9046570659,-0.6815707088,0.2523507774,-0.1003115773,-0.6361647248,-0.2780383527,0.8642255068,0.9515980482,0.9820371270,-1.4303667545,-0.0983356610,1.4673168659,1.1516301632,1.9530824423,1.2597833872,-1.4902018309,0.3255969882,0.7496146560,-0.0849756375,-1.0007236004,-0.5960429311,-1.0154364109,1.2511830330,1.2626070976,-0.5875334144,1.4028255939,0.4695758522,-0.0255566500,1.8417292833,-0.0399172194,1.1069836617,-1.2826505899,-0.1472184211,0.9856489897,-0.1729861200,-0.3876519799,0.6959972382,0.2856332362,-1.0207430124,-0.9289630055,0.0632748380,0.4820849895,1.5037152767,0.4867504835,0.0797959343,-0.1955450326,0.7896358371,-1.1532626152,-1.1208647490,-1.6553353071,1.8035339117,-0.0838049203,1.3239436150,-0.4971853793,0.8107408881,-1.1551069021,-0.1953871846,-0.7771847248,-0.7813466191,0.5065687299,-0.1820823550,0.2684529126,0.9292242527,0.7593740225,-0.9009737968,0.4765752554,0.1643548906,-0.3488487899,-0.3658882976,-0.2314924598,0.4069265723,-0.9488435984,0.7248171568,1.4139008522,1.5861266851,-0.1279027164,-0.0553276762,0.7255465984,0.1429184526,0.1820705831,0.2178043425,-0.0077814292,1.4773465395,-1.1627372503,-0.6053957343,0.4770019352,-1.0118191242,-1.3295882940,0.7362958193,0.7915869355,0.3331216276,0.5359749794,-3.0860996246,0.3936527073,-0.7873288989,0.1485450566,-1.2330771685,-1.2370146513,-0.5632748008,-0.4914303720,1.0046528578,-0.7574470639,1.2790346146,-1.9569309950,-0.6932571530,0.3972877562,-0.1010534316,1.6112462282,-1.3199983835,-0.5487880111,-0.5936339498,-2.0641529560,0.5989998579,0.8124501705,0.3341778815,-0.7117627859,-1.7005486488,-0.7905029655,-0.7358307242,-0.0822679624,-0.2129524499,-0.0102335811,0.2852599919,-0.2062803209,-0.5369126797,0.9724613428,-0.3041396439,-1.0042915344,1.0672525167,-0.2289439440,1.3452187777,0.5357630253,-0.4374930859,0.6523374319,0.0650269166,1.2034343481,2.5041522980,-2.2119021416,-0.0325773247,-0.2486386299,-1.2621959448,0.9550855756,-1.0251768827,1.3576012850,-1.0082174540,0.4790438414,0.7539923787,-0.2292823493,-2.0603711605,1.2167100906,-0.0632605180,0.6282228827,-1.2875719070,1.2758817673,-0.0361953229,-1.1444544792,0.0995380729,2.0643885136,0.0476284251,0.3599074483,1.3913724422,-0.8276139498,0.4267857373,-0.9940422773,-1.6722874641,-0.4820932746,0.9585770369,-0.3583551347,2.2475891113,0.6795741320,0.0427838154,-0.0337097496,0.2812221050,2.2352130413,1.5787955523,-0.0525405966,0.7612043023,-0.2395873815,-1.1629893780,0.9450313449,-1.5587869883,-1.0885256529,1.2096309662,-0.6176126003,0.2794592083,0.4000840187,-0.2106546909,2.1949429512,-1.7044574022,-0.2265886366,0.5426079631,1.1125903130,-0.5519072413,-1.1224460602,0.8363450170,-1.5743186474,-0.5271378160,0.6508792639,0.5543196201,-1.1395976543,0.1506068110,-1.3732875586,-0.5603883266,-0.3320862949,0.0500928350,1.4821004868,1.3670789003,1.0397155285,0.9093261957,0.2789103091,-0.4556762576,0.9363845587,0.5859700441,-0.8330316544,0.9558687806,-0.2014526874,-0.0478864685,-0.8698826432,0.2509627938,0.1928938031,-0.5245307088,-0.7604442835,-0.9027975798,-0.8322229981,-0.2535308897,0.2865951061,-0.8358671069,-0.0175675061,-0.4595412612,0.2229304463,0.2540488839,0.1446684897,-0.5048643947,1.2162379026,1.4006818533,-1.8685104847,-2.1495907307,0.3018081784,-0.9322087169,-0.6951150894,-0.3476719856,-0.8317773938,0.5383685827,-1.4129815102,-0.1823303849,1.0443432331,1.1775488853,0.0203446262,0.6534597278,0.1316889226,0.9037830830,-0.8564657569,-0.2451224774,0.5288985372,-0.3417075574,-0.4940801263,1.2461600304,0.1253131926,-0.1442823708,-0.2593114078,-0.7173941135,1.5848474503,1.3283705711,-0.4759116769,0.5617510080,-0.2803081572,-0.1529893428,0.7441819906,1.0778692961,-1.6746370792,-0.0191578642,-1.6233841181,1.3962148428,2.4005887508,-0.7849439979,1.6532175541,0.8943389058,-0.7218570709,0.0025848437,0.1503669173,-1.1533824205,-0.6082597375,0.5895243287,0.6123408675,1.0880017281,-0.8497795463,0.2664059699,0.1507609338,-1.1018321514,-0.7293382287,-1.2999854088,-0.5079394579,1.9566550255,-0.6045329571,-1.1847981215,1.3479480743,-0.4842537940,0.4533431828,0.2714575231,-0.0489397943,-0.0387133919,-1.2142137289,-0.5738778710,0.4517196119,-0.0616835095,0.7554846406,-1.2030466795,0.2224065214,0.8758687377,-1.5098052025,-2.5789873600,-1.3044232130,-0.9159380198,0.3439801037,1.0308520794,-0.5655797124,0.6416946054,-1.5301198959,-0.2333142459,1.3705869913,0.5391677022,2.1740953922,0.6560552716,0.4826991856,-1.5273411274,0.6695680618,0.4246776700,-0.1707382351,-1.0786836147,0.3128767908,0.5183787942,0.5231448412,-0.7981930971,0.0068109701,-0.9226770401,-0.7949106693,-0.1485601366,0.5388772488,1.1333990097,0.2188962549,-1.0067234039,-0.3539472222,0.7378255129,-0.2585050464,-1.1470578909,1.2719910145,0.6277831793,-0.6327692270,-1.3171602488,-0.6405596733,-0.4403110743,0.5331921577,-0.0618506931,0.1133509055,-0.2367716134,0.0172743201,-0.9363154769,0.0419243276,1.2715209723,-0.6324470639,0.4981867671,-1.4744064808,0.9432847500,-1.3852499723,-0.0248926673,-0.1987091005,0.9218626022,0.3695135117,0.6386186481,0.9051753283,-0.6882691979,0.1940152645,1.0115746260,-0.1039159670,0.0934223235,0.6569828391,1.5856434107,1.3781589270,1.1807434559,-1.2077684402,-0.0713830218,-0.6892064810,0.7983953357,-0.1320799440,0.9095534086,1.0258624554,-1.0350824594,-0.1084372476,-0.7068145275,1.0966942310,0.2121248394,1.6011934280,-0.1354372799,-1.6426924467,1.9219787121,1.9771164656,-1.2754851580,0.4517096877,1.3728480339,-0.5387133956,-0.5070499182,1.0105915070,0.7020894289,-1.4419972897,0.0110328682,-0.1098614261,-1.4754793644,0.3179679811,0.3669794202,-0.9281835556,1.2898329496,-0.9199350476,-0.9801771045,-0.9031108022,-0.3989333808,-0.3263574541,0.1047135815,-2.0553271770,-0.9773147702,-1.4125535488,-2.2337026596,-0.9101406932,-0.2648207545,0.5565056205,-0.6932720542,-0.8804928660,-1.4365410805,0.0302592870,-0.1010962129,-0.3346745968,0.3059233427,-1.3067972660,-0.0088376841,-0.3915492594,-0.6771771908,-0.5156219602,0.1084053442,-0.7851771712,2.0248520374,0.0768793225,1.6671743393,1.1379973888,-0.0037817969,-0.1691045761,0.1110712513,0.0237912405,-0.2556541264,-1.9002453089,-0.7983082533,-1.8317855597,-1.2898895741,0.0141506037,0.2845778465,1.1239186525,0.4390246570,-1.0800429583,0.9424997568,0.0881775469,-1.6444958448,-0.8998572230,-0.9650136828,0.2967081070,-1.0165929794,-0.5798018575,1.3800915480,0.6454607844,-0.0140456948,-0.5817818642,-0.1011662409,1.0112067461,-1.8833494186,1.3017792702,-0.7716539502,0.5666996241,0.2956871092,-0.2049203664,1.9108538628,-1.3607987165,-0.0717590377,0.0956634954,-0.5079314113,0.3618172109,-0.3595963717,-1.4459455013,0.2162457108,-0.7750922441,-0.2253048420,-0.6305879951,-0.6282056570,0.1342151314,0.9079183340,-0.3357201517,-0.9684320092,-2.0011854172,1.0298330784,-1.1672452688,1.2127306461,-0.5632342100,-1.1428827047,2.3399078846,-0.8843747973,0.5320113897,-1.1435959339,-0.8313342929,1.1637715101,0.8253864646,-0.9990708232,0.3957966864,0.4645176828,-0.6763690710,-0.2837693691,-0.4347972870,-0.7891721129,0.8290168047,-0.3206014335,-0.3041936457,0.7272228599,1.2169837952,0.7897850275,1.2175595760,0.9864512682,0.3498557806,0.9575622678,0.1763862520,1.5062904358,-1.4601914883,0.8869418502,0.4095101357,-0.0545322858,-1.0357341766,0.0918669775,0.7407202721,0.4786416292,0.6654282212,0.2292959541,0.2076932490,0.2183427811,-0.7750036716,-0.8375609517,-0.8351103663,-0.9253761768,0.0818053335,0.2907602191,1.0790300369,3.0961189270,-0.4322378933,-0.5297884345,-0.7185241580,-0.0790990219,-0.5318148136,0.3011080623,-2.3876340389,-0.6010844707,-0.6294558644,0.9789693952,-2.1652061939,-0.9091853499,-1.5246109962,1.6593085527,-1.1628981829,1.6147589684,2.2718012333,-1.5532001257,-2.0527155399,-0.4091469049,-1.0820819139,1.5153158903,-0.4930484593,0.8512840271,-1.1784952879,1.0569536686,0.0160085466,-0.0003073825,-1.4744670391,-1.2892800570,-1.2932577133,0.6164194345,-1.7043364048,0.2677577436,0.6191200018,-0.2715763450,-1.5342735052,-1.0618538857,-1.2137271166,-1.9104957581,-0.5562978387,2.0095219612,0.4219472408,0.2807143331,0.2929550111,0.0925148204,-0.7408627868,-1.2786219120,0.5953165293,1.1873878241,0.7985800505,1.1434313059,0.1420213878,0.3704443574,2.0830335617,0.8558987975,-1.0863219500,-0.6328001618,-1.0930259228,-0.7155646086,0.2989422679,-0.1714941859,-0.2596023083,1.0251544714,0.4840430021,0.5426319242,-0.0317259394,-0.5928928256,2.3365657330,0.8119526505,-0.3559478223,1.2486777306,0.3161210120,0.3295256793,-0.2986513674,-0.8083889484,-0.1058205962,-0.2012898922,0.1898895204,1.2744652033,-0.5763427615,-1.7786310911,-0.4619722664,-0.0343275331,-0.0804154128,0.0896555558,-0.2375993878,-0.6510353088,0.5634438992,-0.2756451070,-1.1919237375,0.0106554357,1.0845719576,-1.4242180586,-0.7915678620,-0.4528565705,-0.5867254734,-0.3834092915,1.3105416298,-1.1719135046,-1.8663834333,-0.4044742584,-1.0571340322,2.1624724865,-0.3283438981,-1.6711210012,-0.2128783464,-1.1012598276,1.2401621342,0.1001905724,-1.6413034201,-0.4412343502,-1.6417485476,0.5818608403,1.0299129486,2.2170233727,-0.7258693576,0.3411789238,-0.0758841783,-0.1068310887,-1.5048621893,-0.7476377487,-1.0252985954,1.2971277237,0.9907476306,-1.0029420853,-0.8703005910,1.2154511213,0.1695734859,-0.6100532413,-0.2701125443,-1.8159172535,0.0744715631,1.4320803881,0.8319642544,-0.3548873365,-0.4736134112,1.2513190508,0.7541353106,-0.7968253493,-1.1330760717,-0.4850624204,1.3151828051,-1.8339599371,1.2641755342,0.6874196529,-0.1858444214,0.2456031442,1.2378497124,0.3065797091,0.1393100023,0.8186387420,0.5621598959,-0.2971632183,-0.9280245304,0.5608353615,-0.5151640177,1.3092679977,-0.1564584374,0.0101362988,-0.1147716045,-0.3308030069,0.5426612496,1.0478041172,-0.7588689923,0.9058098793,-0.6638476849,0.0271008201,-0.5996529460,0.9415428638,0.3311151862,-0.6850024462,-1.6973967552,0.8252288699,0.5447505116,-0.5340859294,-1.0320228338,-1.9213482141,-0.3236763477,-1.1210227013,-2.0754590034,0.9175598621,-0.1582947224,0.0355038270,-1.8584797382,0.8211516738,0.5859157443,0.9854813814,1.0377193689,0.8087520003,0.0553114042,-1.1089491844,0.2617270350,0.7748783827,-1.3112766743,-0.2853017449,-0.8751548529,0.4537158906,-0.4724691808,1.9114776850,1.1201875210,-0.6998970509,-2.2755661011,0.6124466658,-0.4858125746,0.1044009998,0.6781061888,1.0112067461,-1.0053843260,0.5832854509,1.3902379274,-0.3954279721,1.4138845205,-1.1117755175,0.0675625056,-0.7510002851,0.1992310286,0.1564755589,1.4238003492,1.1698158979,-2.0644772053,-0.7029905319,0.2314308137,0.2684699595,0.7005752325,-0.1916425675,0.1933514178,-0.3600777090,-0.5549749136,-0.6029216051,-0.7787041664,-2.5662279129,-0.7273243666,0.6202687621,-0.7350562215,0.2137556970,1.7911796570,0.5588005781,0.0419100970,-0.6966994405,1.0583099127,-2.8149473667,-0.2643944621,-2.2827417850,-0.7935805917,-1.1352584362,-0.2278170884,-0.8056265712,0.7685412169,0.3496689200,-0.3449663222,0.3916354775,0.0579748861,-1.4494156837,-0.1893656999,-1.6724202633,1.0861943960,0.5076280832,-0.0133326286,-1.2809752226,1.3494324684,-1.2507998943,0.7153228521,0.2078970075,-0.6573593020,0.7824165821,-0.5148826241,1.3713448048,-0.0101848487,-1.4278615713,0.6900991797,-0.7380038500,1.6913758516,1.6196644306,0.9960871935,-0.6944152117,1.6037415266,1.3314589262,0.2126102298,0.8190729618,-0.3324639797,-0.4693499804,-1.2738293409,-1.9276175499,1.8065828085,0.6967000365,0.1457846165,-0.8485788107,-0.0902344882,-0.4437417090,-0.8114491701,0.6733375788,-1.0148701668,1.2667295933,-0.2555393577,1.0527654886,0.0487716459,-1.0939552784,1.0991251469,-0.9288706183,0.6616157889,-0.1064211130,0.5533397794,0.4668231606,-1.0746521950,0.5423960686,1.0720642805,0.8632643223,0.1105926335,-0.4526108205,-1.0977783203,-0.8176969886,-0.2230648398,-1.1865390539,-1.0723834038,-1.0440925360,0.9188759327,-0.1689279526,0.3107523918,-0.1185576096,0.3864873350,0.5850405693,-1.3451581001,1.1591099501,-1.7213473320,-1.1616033316,-0.3630917370,0.9260309935,1.9034808874,0.7039475441,0.8226540685,-0.2596986592,1.2070049047,-0.9120343924,-0.1701831520,-2.9533367157,1.2373387814,0.7368846536,-1.1026964188,0.7084195614,-0.5575756431,0.6083027720,-1.9660063982,0.0480993725,1.7596119642,-0.2430192381,0.5924292803,-2.4542522430,-0.1702857912,-0.8102533817,0.3578571081,-0.3168414533,-0.7957355976,0.8105921149,1.2186963558,0.2567883730,0.9143864512,-0.0124621931,2.1438231468,-0.7441107631,-1.0311625004,-1.0583885908,-0.3230136037,-1.2296295166,-0.5679237843,-2.8217861652,1.2539693117,-0.6278217435,0.2693663836,0.5483108163,-0.1207809523,-1.0742874146,-0.6069313288,1.5203852654,-2.7174751759,0.3162423968,-0.9960474372,1.1332710981,1.0375409126,-0.0346815698,-0.2378142923,-1.8274402618,-0.7565240860,0.3035017252,0.6736583114,-0.3378650248,1.4695996046,0.8090537786,-1.8708773851,0.9925187230,0.3028483391,1.4664566517,-0.6074188352,1.0674394369,0.1149998233,-0.0621099845,-0.1732854992,1.2566143274,0.4596324861,0.1921480447,0.6472542882,-0.0070908745,-1.1495875120,-1.5454713106,-0.8810761571,-0.9932910800,0.4973982275,-0.0830497742,1.3150237799,-0.8044264317,0.3923761845,-0.8494360447,-0.5066404343,0.4646987021,0.1593044102,-0.0949085504,0.2508442402,0.8306478858,1.5014774799,0.6009095907,-0.2514753044,0.5792323351,3.3733355999,-1.7200666666,1.0272295475,-0.0590384156,-0.4829144776,-0.7770543694,1.1213577986,0.2282679379,0.3859090507,-1.0854517221,1.3076217175,-0.0168237090,-0.7895203233,-1.0785923004,0.0915632099,0.9873991013,0.6320911050,-0.6186110973,0.6905904412,0.6880133152,1.5512328148,0.9121033549,0.5840374827,-0.4260689318,1.5989313126,1.5102443695,2.8731038570,0.1307470798,-0.0351151600,0.4154373407,1.0803951025,-0.7689779401,0.2349200249,0.2127694488,0.1637901515,0.2540091574,-0.5789597631,-0.2085085064,-1.4617660046,-1.2019745111,1.3285419941,-0.5355551839,-1.0052437782,0.8944669366,0.6750456095,-0.3523706496,0.5630317926,-0.2512718141,1.2605104446,-0.1540245712,-0.7847375274,-0.5049604177,0.5393610001,-0.1454569995,-1.9208295345,0.1988556087,-0.5276432037,-1.9898313284,1.3303182125,1.1966954470,0.8466907740,-1.3549520969,0.1534716338,-1.6951408386,-1.0888959169,-0.7846040130,0.0208831783,-0.5135362148,0.1377027631,-1.1420041323,-1.0348410606,1.0945382118,-1.6735677719,0.8930306435,1.2586365938,-0.4186193049,-0.5548886657,0.7520841360,-1.2721277475,3.2311539650,0.4641966224,-2.0481486320,1.9270210266,0.4723309278,0.3861116469,-0.5980855823,2.4221987724,1.1139601469,0.7150088549,-0.5016779900,-0.2652854025,-0.5569392443,0.5937147141,0.7529249787,0.9008342028,0.4063133895,0.1512439102,1.2978001833,0.2491936237,0.2895989120,0.8108627796,-0.2134086490,1.6224154234,-1.1592159271,0.2234223038,0.1212291792,-0.9138811827,-0.4205074310,1.5794224739,0.1617780775,-1.6059589386,-0.4434491992,0.6146141291,-1.1083737612,-0.3466961682,-0.4387931228,-0.2230413556,-0.1678518355,-2.6264977455,-0.1727611125,1.0355259180,0.3443305790,0.5022798181,-0.5143413544,-0.4986781478,-0.8272845745,-0.0147204055,-0.5727688074,0.0031921251,0.3674898148,2.0267584324,0.5630730391,1.0627936125,0.2569692135,0.3916804790,-1.0073970556,1.2933391333,0.0424646772,0.5398423076,-0.5044786334,-0.5983367562,0.7175628543,0.4539347291,-0.8410576582,0.2607088089,-0.2576574683,0.1949142963,-0.2623168230,0.6356629133,-0.1043076217,0.1324877888,-1.0602743626,-0.2008478791,1.2160608768,-0.0292315781,-0.1890411377,-0.8686054349,-0.9382474422,-1.0121945143,-1.4328993559,1.1785588264,1.5638674498,0.1427608132,2.0439651012,0.9626225233,0.2164034098,-0.3151763380,-0.4807561934,1.9710719585,-0.4390293062,1.7081115246,-0.3730249107,-0.8752344847,1.0402947664,1.0650632381,2.2234606743,-0.2990089655,0.1338202506,-0.0058257026,0.8717163801,0.4131239653,1.7113682032,-0.3095157444,0.4589198530,-0.6647123694,-1.9829771519,0.2398172468,0.7303733230,0.0065799267,-0.2386463732,0.7785472274,0.1026007161,-0.9697332978,0.9232811332,-0.3040901721,-0.3353936076,0.4633235931,-0.3067607284,-0.1129981503,0.0151031548,1.4305889606,0.2822506726,-0.3901175261,0.2373402417,-0.3301363885,-0.4907036722,0.3101215363,1.6566424370,-0.1352761388,2.0479047298,-0.8596891165,1.3939336538,0.5532745719,-0.1697778255,1.0746655464,-0.6602277756,0.4712713957,0.8705766201,0.2959489226,-0.1473409534,-1.7874796391,0.4816951752,0.0301115476,-1.0984210968,0.3432916701,-0.6739798784,-0.8314334154,-0.0407379083,0.4170181155,-1.1367658377,0.7947146297,1.3205595016,0.4236109555,1.4152296782,-1.2873961926,0.5734673738,-0.1166800484,-0.4258343875,0.7109622359,0.9978282452,-0.7153664827,-0.1323070973,-0.1627074182,1.2122015953,0.7887623906,-3.2201621532,-0.1679748148,1.3945446014,0.7399389148,-0.2768034637,0.4165839553,0.8265034556,0.9802414775,0.4776431918,2.0166103840,-0.0249875244,0.4829532504,-0.7448346615,-2.0533394814,0.9954663515,0.5559939742,0.1557032168,1.2560248375,-0.0910743177,0.7448199987,1.5151149035,1.0682363510,-0.3936732411,-0.4404679239,-1.2789002657,-0.7345156074,-0.8073781729,-0.2055337727,0.8966993690,-0.0118007520,-0.7772536278,-1.2498084307,-2.0847239494,0.4443413317,-0.9075754285,-0.0707240850,-0.3365614414,1.1858187914,-0.7117362022,0.9870203733,-0.6684255600,1.4725475311,0.1366336048,0.7424795628,1.4361493587,-0.2917276919,-0.3563250899,0.6698901057,0.8398872614,-0.8428919911,0.7355796695,-0.0806103125,-0.4388633668,0.4438080788,-0.6025252342,0.1011375487,0.4766345918,-2.1126976013,-1.3606692553,-1.0401051044,-0.0643365011,1.7286696434,0.7811232209,1.2519133091,0.1582637727,-0.1840040833,-1.0580223799,2.1860694885,0.7420462370,-0.6358695626,0.3461574614,0.0260392353,0.2544353902,2.4137811661,0.5811787248,1.4372696877,-1.1470407248,0.0356767289,-1.9682257175,-1.6825907230,0.7045783997,0.9582905173,0.4860132933,-0.4299276471,0.4619325399,-0.3726094365,-0.4181045592,-0.6713925600,-0.4985078275,-0.6091927290,-0.6080089808,0.3473231494,-0.0035682917,1.2791190147,-0.2127529532,1.0742793083,0.7116464376,-0.6488238573,0.2859148681,-2.0417239666,0.4539825618,2.0291399956,-0.5095365644,-0.9993411303,-1.1150147915,-0.6259767413,0.1875912845,-0.2886156142,1.0134998560,-1.1804151535,0.1758203655,-1.2308334112,2.5587472916,-0.9636149406,-0.0713531971,1.5979670286,-1.5108559132,0.1449113637,1.1441174746,0.2312457860,0.2274304181,0.1459915936,-0.6081528664,0.0709826797,-0.0125633776,-1.3180460930,-0.3260259330,0.4805007279,-3.2030875683,0.4306159019,-0.5212286115,0.8575561643,-0.8960441351,-0.1932385713,-0.7063098550,-0.9964183569,0.7934882045,-0.4802501500,0.3568688333,-1.0943177938,-1.6923885345,0.7779947519,2.6947827339,-1.0811645985,-1.4731924534,0.0109302318,0.3299140036,-0.1448013633,2.4050495625,0.1636990309,-0.1965565681,1.5348142385,0.2748448253,-0.9842527509,-0.4361257255,-0.5287380815,0.7196028233,0.2204200625,-0.5418440700,1.3916079998,0.7451648712,0.2643483579,0.6969248652,0.2191476822,-0.3153337836,-1.1294671297,0.2236620039,0.8282073736,-1.0530409813,-0.4204666913,-0.2162797153,-0.7607799172,1.0307723284,0.7421389818,0.4817281663,0.3772906065,-0.2255851179,0.2419869155,-0.2462873459,1.2878042459,1.2064702511,1.9481141567,-0.3638069034,-0.2458624840,-0.8163990974,-1.3361914158,0.1759304553,0.8073284626,0.2768845856,-0.1631110460,0.7782697082,0.2213267684,0.6580312848,-0.8218443394,-0.5532718897,-0.5647550225,-1.2183798552,0.5782849789,0.5329989791,-0.6715250611,0.8244873285,1.0194652081,-1.1014153957,1.6967984438,-0.0429516323,-1.0793919563,-1.1583365202,1.1959785223,0.8431320190,-0.4192778170,-0.3327940702,1.9657697678,0.3050765395,0.8305168152,0.9101333618,0.5969888568,-0.2304041535,1.8251065016,-1.1460005045,-0.2217972875,-0.5881155133,-0.4704960585,0.4888032973,1.3412656784,-1.0570495129,0.4420121312,1.2955129147,0.8408915997,0.7732490897,-0.6764742732,-0.0356562771,-0.6429589391,1.8658261299,0.5035269260,1.2822653055,0.9182057381,0.4520080388,-0.5673279762,-0.4225480556,-1.2345860004,0.9104699492,-0.6104401350,0.5325096846,0.2594264150,2.1227545738,0.6246936321,0.3436859250,0.4797151685,0.5576152802,0.4796886742,0.6413477659,0.1015166044,-0.5291261673,0.0093640964,1.1927584410,1.5470068455,0.9478160739,-0.8584091067,1.4589502811,1.0034278631,-2.0495164394,1.0458933115,-0.6270156503,-1.6971756220,-0.4960333407,1.4561544657,1.0882210732,-0.0976122990,-0.7173095345,0.1641712338,-0.6962606907,-1.3123685122,0.7208009362,1.4251564741,-0.9525543451,-1.6627132893,-1.3450037241,0.9273759127,0.3668547571,0.0847202390,-0.8547070026,-0.1450030655,-1.0790885687,0.6394917965,-0.7484422326,-0.0812485516,-2.3238573074,-0.8937191367,-0.2410787642,0.7658015490,-0.1973870993,0.1931478530,-0.5485792756,-0.3950333297,0.3372679055,0.7965800166,-0.1148310974,1.0055104494,-1.7035870552,-1.2542206049,-0.0020835998,-1.0969371796,-0.6635608077,-0.6708840728,-0.1306800544,2.0890042782,0.2768505216,2.3234868050,-0.1149376929,1.7064332962,-0.0357143879,0.0917023197,0.2306758016,-0.8789747953,0.6359471083,1.0145800114,-1.2079186440,0.7884379625,0.5274050832,0.1402386427,0.3174589276,-0.5563088655,-1.8163865805,1.6633933783,-0.1732443124,0.1822638363,-0.8089761734,0.6185746193,1.4769704342,-0.8918659687,1.0805387497,-2.2777967453,0.0982830897,-0.9784666896,0.1409724802,-0.6910139918,-0.2581627965,-0.3227139115,1.2393940687,1.4970542192,0.3486480415,0.6801899076,-1.2906173468,-0.8694254160,0.6916615367,-0.3949315548,0.4967114031,-0.9639406204,1.0947629213,-0.5677868724,0.1172745824,0.1036742851,0.8766137958,-0.5469971895,0.0912009105,-0.8483621478,-0.1651878506,-0.8982597589,1.8080214262,-0.1094860435,-0.6009634733,-0.3665615022,-1.1674404144,-0.3560737967,0.4168348908,1.2016643286,-0.5615233183,0.6447062492,-0.2535068691,-1.1192104816,1.1256830692,-1.6240452528,0.9639360905,0.4438114166,1.8228126764,1.9016685486,1.3340772390,-0.9280285835,1.7382543087,0.5836077929,2.3370118141,0.5108041763,1.4469654560,0.4597733915,1.0623366833,0.0035629983,0.0866807178,-1.3463780880,1.1956572533,0.3716119528,0.0912752375,0.5642582178,0.7687278390,-0.0072249584,-0.4405217469,1.2104653120,0.0289006699,-0.6262733936,0.2481508404,1.7004103661,-1.0955580473,-0.9726043940,-0.9737624526,0.2870694399,0.5214788914,1.4835518599,-0.2087257504,0.0239505731,0.2233554721,0.2403004915,-0.8426833749,-1.2004982233,0.7131180763,-0.6364238858,2.0007157326,-0.3677787781,0.5677682161,-0.5169160366,0.7849178910,-0.1691215634,0.3505437374,1.2626199722,-0.3145025969,0.0967818573,-1.1018123627,2.0346674919,-0.5044198632,2.0918335915,0.5418912172,0.1253499985,-0.4790270329,0.9885153770,-0.2244774550,-0.7532069683,-0.2590924203,-0.3724360764,-0.5268012881,0.0099415304,0.9852399230,-0.9677956104,0.9610522985,-0.4307636321,0.9771789312,0.4913146794,-0.1979523748,-1.2591580153,0.1725802869,0.3992780149,0.2902160883,0.6774837375,0.1915705055,-0.5545125008,-1.6164081097,-0.4995488822,0.1495799124,0.7770783901,-0.6658815742,-1.3216475248,0.7363036275,0.4968822896,0.5971414447,-0.6678465605,0.1934313029,0.4205310643,0.5923535228,0.0337040164,0.4831328690,-0.3680884242,0.3568235636,-0.3181792498,-0.8712489605,-0.8680101037,-0.5461862683,0.6563332677,-0.3947722018,-0.2092790902,0.0315701514,-0.4167560935,0.0570355020,1.4990587234,-0.8132793903,-0.4818907976,0.4890195429,0.6042798758,1.5244840384,0.4387151301,0.3640931845,1.5731611252,0.5005360842,1.0017102957,-0.4325468838,-0.7100720406,-1.3056461811,0.3504725397,0.2902453542,0.3730077446,-1.8038679361,0.3144704103,1.1459712982,-0.9655853510,0.4122045934,1.5242187977,-0.2994287908,0.0495324992,-0.8841370940,-0.9477353096,-0.5417408943,-0.0676480904,-0.4663005173,0.9185313582,0.0686773732,-0.6691791415,0.3122829497,-1.1253046989,-0.1556600630,0.5729102492,-1.0837713480,0.0669136345,0.4971903265,0.0897533596,-0.1047038808,-0.6622824669,-0.7894172668,0.8324003816,0.7106827497,0.3483260870,-0.7259815335,0.6386246681,-0.5196985602,0.5204224586,0.0865338221,-0.7810475230,-1.2443351746,0.3589504063,0.4397775829,-1.1927919388,0.9172086120,-1.2508444786,1.7453820705,-0.3246877491,-0.4532547295,-0.0731760189,-1.3975434303,-0.7634076476,1.5434905291,-0.4080433547,0.4650013745,-1.4238005877,0.2563230693,1.7736479044,-0.7137615681,2.2522010803,-1.3089007139,1.1525106430,-0.1405597478,0.5320132971,-0.6810653210,-0.4485176206,-0.3747822344,0.4281465709,0.8007715940,0.0123932073,0.1402721852,1.9548217058,0.3309944570,0.3134448826,-0.8624955416,0.1731562018,-1.1307023764,-1.2180870771,0.3798313737,0.1041512787,-1.0410223007,-0.2304405719,0.0916122720,-1.1846817732,-1.1531682014,-0.4354380965,0.4104143679,-0.4816984534,0.4900153279,0.7041178942,-0.7546210289,0.5832744837,1.2078104019,0.4386845529,-1.5632371902,-0.8126469851,0.1477559507,-0.0461850464,-0.3673082590,-0.4501196742,-0.1551027894,-0.7583582997,-0.0730031282,-1.9887934923,-0.8846876621,0.6732758880,-0.0811193660,1.0592772961,-0.5077518821,-0.3238532543,1.3735461235,-1.4465440512,0.1821355820,0.0676640049,-0.4560262859,-0.3496088684,-0.6075907946,0.6537126303,-1.7022186518,0.0755707473,-0.1904866546,-2.1203536987,1.7095605135,0.7199447155,1.7510561943,0.8169274330,0.8673193455,-1.2237163782,2.6919562817,0.3033113480,0.2355719060,0.4901683927,-0.7814581394,0.8745526671,0.2152803242,1.0555243492,0.3528210223,0.3482930064,-0.0836526528,-0.8183871508,-1.3136165142,0.5067337751,0.9809406996,-0.3727931380,0.1372788996,1.2173398733,1.0570574999,-0.1092743352,0.4346898496,-0.7528158426,0.8488703370,-0.8521622419,-0.8124353290,-2.1803562641,-0.7766513228,1.1283991337,0.3751853406,-1.3530814648,1.3838658333,0.4173292816,0.7445374727,-0.0002430229,-0.9045234919,-2.6463234425,-0.3570845723,0.2908712029,0.3473463953,0.5702397823,0.7549381852,1.4791334867,0.9874882102,-0.6921150684,2.3449747562,0.6544520259,0.3682841957,1.9040485620,0.4765006304,1.1654456854,0.7307538390,-0.4611986578,0.6390597820,0.3741174340,-0.5228999257,1.6194049120,-1.0346127748,-0.5952832699,-0.8493008614,0.8470287919,-0.5518957973,0.2897983789,-0.0187721644,-0.3662812412,-0.3504948616,-0.3711920381,1.7615973949,-0.4802156985,-1.8253751993,-0.1795722097,-0.3333802223,0.4528505504,0.7250844240,-0.1168686971,-0.2354764342,-1.0015610456,0.5932791233,-0.7151992321,1.1872414351,-0.6099489331,-0.8342801929,1.0395519733,0.4641788900,-0.1812096685,-0.2494318336,0.1936044991,-0.3829216361,-1.2802710533,-0.0509898625,-1.1535187960,2.3395931721,0.9372795224,-1.0627675056,-2.2381188869,-0.0003268473,0.1890586317,1.9689356089,0.4381758869,0.6209080815,-0.0069314591,0.6565827131,0.9101958871,-0.8087453246,-1.0782167912,-0.4138877690,-1.1793274879,0.3645130098,2.4339489937,1.2218075991,-0.5169935226,0.3686336875,0.3838019669,1.0012456179,0.0827877894,0.6399840117,-1.1393259764,1.1500494480,0.1755813956,-0.4248540998,-0.9612060785,1.2496811152,0.6430417895,-0.8739003539,-0.6526424289,1.1801552773,-1.3901848793,0.6684985757,0.7047442794,-0.0454604439,0.9043201208,-0.0832923055,-0.0246616453,-0.7082564831,-0.6657384038,1.1625177860,0.7331817746,-0.8065531850,3.0549848080,-0.6254408956,-0.9780409336,0.3719343543,-0.7863800526,0.2642794549,2.1103971004,-0.2257129401,-1.3434938192,-0.6517789364,0.9215201735,-0.5927384496,0.9416487217,0.0437185653,-0.3107615113,-1.8002775908,-1.5352293253,-1.2877420187,0.2497640550,0.0889306590,-0.3507105410,-0.5227136612,-0.5778329372,-0.7980781794,0.2110481560,-1.3815633059,-0.6894747019,-0.2972003222,0.8221981525,-0.2503884733,0.7942054272,0.9488335848,-0.1884921640,1.0855621099,-0.6987811923,-0.2730012834,1.4528568983,-0.6969278455,0.5462369323,0.4251119494,1.1552058458,0.3428002000,0.8982730508,-1.4678502083,-0.5434156060,-0.0516024604,1.3498048782,1.7462068796,1.0836268663,0.8198674917,-0.4759975374,-1.0495749712,-0.9996607900,0.3143595755,-0.8451169133,0.9353263378,0.9249797463,0.2017759383,-1.9286822081,-1.1570881605,0.5033632517,1.1476683617,0.2429254949,-0.6879550219,0.9943078160,-0.2067762166,0.6849880219,1.4044768810,-1.4275686741,-0.8624293804,0.7384086847,-0.5561550856,-0.8264702559,0.7136894464,-0.3004029989,0.8249571323,1.3415811062,-0.1680783927,1.0953153372,-0.8835517168,-1.0230761766,-0.2327672988,1.2700972557,-1.1392649412,-0.4342262745,-0.7223634720,0.5530021787,0.5501202941,0.3454295397,-1.0601592064,0.3098625839,0.3677841425,0.9607761502,0.6529376507,1.4435209036,1.0172544718,1.3574310541,-0.0099963387,0.0024282169,-0.4879335463,-0.4324880540,1.4777532816,0.2670559883,-0.4485886097,0.6798025966,0.6807366610,-1.4864747524,0.2098133266,0.4501485527,1.2317266464,-0.2362726778,-0.4584268034,2.8149886131,0.1683895439,0.2099463046,1.2645759583,1.2813298702,-1.3021427393,-0.0147156315,-0.4178023934,1.9107762575,-0.6563686728,-1.0691428185,-0.4230622947,-0.0132462140,1.8421353102,1.7196012735,0.5972613692,0.3515547812,-0.5387497544,-0.0692220926,-0.3597345054,-1.0044300556,0.5427931547,-0.8332656026,-0.5242043734,0.8488559127,0.1747637987,-0.3172430992,-1.2048152685,0.6520953178,0.4357360303,-0.5587982535,-0.4179782867,0.4264180362,-0.0548314825,-1.1908137798,0.4734176993,-0.6122033000,0.4030275941,-0.2191144228,-0.3238929510,0.6194945574,-1.2550044060,1.5398229361,-0.4604188502,0.7527544498,-0.3760625124,-0.6907941699,0.6619018316,0.3901435733,-0.9779542089,0.2812705040,1.3486820459,0.8936386704,-1.0297094584,-0.7766075730,0.5017185807,-0.9354196787,-0.4815663397,-0.0947765708,-1.3963850737,0.2590472400,2.3648326397,-1.9255220890,1.3736010790,-0.2367615402,1.2566763163,1.9916495085,-0.5050504208,-0.6587370634,0.1339435875,-1.5667083263,0.4359713495,0.0420700498,0.0357943885,-0.0433804691,2.2872498035,1.2421827316,-1.6219403744,0.2979706526,0.5869822502,-0.6416541934,0.3410756886,-2.2526934147,-0.8089647293,0.2043059468,-0.1011173427,-0.4876793921,-1.3751064539,-0.2896009982,-0.3614101410,-0.4906738997,2.8373856544,0.2476367205,0.0999422297,-0.9083200097,1.2840486765,-0.9753172398,0.0642992556,-0.8871639371,0.3426522911,-2.1190073490,-0.7735089660,-1.3035955429,-1.9201433659,1.1583014727,-1.3426201344,1.3124009371,0.4313886762,0.0344963595,-1.2075973749,1.2700092793,0.6499128342,3.3665959835,-1.6459656954,-1.3581641912,-1.8216447830,1.4461368322,-0.1574293673,0.1464605033,-0.7976961136,0.1109806001,0.1583217680,1.0877591372,-0.0723408088,-1.0505943298,0.2393178642,-1.4363778830,0.3752524555,1.2342381477,-0.8808445334,-0.2301429659,0.3931305408,-0.4250062704,-0.5529979467,0.6862195730,2.4019544125,-1.3151100874,-0.2301423550,0.4676499367,0.5954039693,0.4348103404,-0.0355928615,1.3828746080,-0.2989363372,-0.8919566870,-1.3971213102,1.7783776522,-0.2302737534,-1.7624164820,-0.6463377476,1.1267231703,0.4442473948,0.4791038632,-1.4811384678,-2.1068751812,0.5931427479,-0.1246527433,2.1817100048,1.6543698311,-0.1731125265,-0.1042543724,-0.0780078098,-0.7192997336,-0.4809856117,-0.1577761769,0.4041523635,-0.0076569053,1.1993273497,-0.3402960598,0.7366626859,1.3511939049,0.4218282104,0.1720520854,1.8980066776,0.2961442173,1.1082334518,-0.7020488977,1.1318085194,-0.6802171469,-0.6433147788,-1.0897530317,-0.1884802282,-0.8276434541,-0.7988906503,0.3866085112,-0.0302876048,1.0736109018,0.0648761988,0.8674221635,0.4764135778,-1.1911543608,0.7603228092,1.4816516638,-0.8416389227,0.1508948207,-0.4492126107,-0.5611734986,1.6207737923,0.8324872255,-0.5176488757,0.5176472068,3.0010211468,-0.5873510242,-0.7627546191,0.7660671473,0.6905959249,-0.2636062503,-0.4258366227,-1.2875888348,1.4470908642,0.0458003469,-0.5081302524,1.5856559277,-0.5258768201,0.1839931756,-0.4267107844,-0.7687863708,-1.9748845100,-0.7904258966,-0.3710695207,0.2210629135,0.1301920861,-0.8979573250,0.2273373753,0.7875413895,0.7730968595,1.2694029808,0.2548620105,-0.8165200353,2.0619447231,0.0528843738,-1.4856121540,0.5538668633,0.4425628781,-0.2612531483,0.2037329376,1.2159631252,-0.1642043442,0.4371479452,-0.2363016307,-1.6688332558,-0.8167054057,0.2186635584,-0.2214595377,-0.2448555678,-0.3115261793,0.9378111362,0.1662903726,-0.6850562692,-0.8621481061,-0.8770141602,0.2879326642,-0.7475222945,-0.7961471677,1.0106245279,-0.2903393209,0.1513967961,-1.1147676706,-1.2387049198,2.6652097702,-0.1084619164,1.3810008764,0.6159277558,-0.5572487116,-0.4658169150,-0.2820259333,-1.1114195585,-0.3663528562,-0.4245306551,-0.1668689102,1.3447589874,0.0826546401,0.5931445360,-2.0726764202,-0.6349374056,0.1409984976,-0.8965637088,-0.2465610951,-0.7543249726,1.3068647385,0.5193663836,1.2673950195,0.0530828945,-1.3074204922,-0.9408559203,-0.3132842779,-0.3520522416,0.2639456987,-1.6094528437,0.2965346277,1.1979731321,-0.6135300398,-1.2268162966,0.1642137766,0.9970766306,-1.3188539743,1.0603978634,-1.1148290634,-0.0663175508,-0.7761843204,-0.8369712830,1.0939637423,-0.1550624073,-1.6109610796,-0.0460047275,0.6645396352,-0.2567320764,0.0598233193,0.7579881549,1.9713249207,0.3284783065,-0.5257778764,0.9011698961,1.1173251867,-1.0251053572,-0.0538991652,0.2657756507,0.6858976483,-0.0486010723,0.1332474202,-0.5991258025,-1.6124672890,0.0241628140,0.0723342896,0.6667144895,0.3458332419,-1.0246504545,0.0992837548,-0.8964792490,0.0723521560,0.2398944497,-0.7628162503,0.4543907344,2.3749954700,-0.1462941468,0.0003235369,1.0902603865,0.5219897628,0.3533296883,-0.7274948955,0.3543509543,0.3556120694,0.8606618643,-0.6099217534,0.6097067595,-1.0419270992,0.1097846627,-0.1417976171,-1.1922610998,0.0365081467,1.3653956652,-0.5518307686,0.3183691800,0.1170945540,-0.1883369386,0.9821451306,-0.0275580082,0.6468264461,-1.5413923264,1.6071134806,-0.9581078291,0.7696560621,-0.1862657368,0.4136942625,-2.6068975925,0.8061500788,-0.7720109224,0.1059482396,-3.1292214394,0.0776122808,-1.3263397217,0.3734543025,0.9427181482,0.1115776300,1.9515994787,0.7113924623,-0.2507297397,1.5339950323,-1.1204895973,0.3802853823,0.5562388301,0.4393317401,0.3805435896,-0.1796236187,-0.0068756798,0.3063318431,-0.8758431673,0.0523967259,-0.9203234911,0.4118686318,-1.1167979240,-0.8827121854,1.2052417994,-2.1289260387,0.5620676279,0.9299391508,1.7372515202,0.9391069412,0.1322578937,1.6648646593,0.6191270351,-0.4869742095,0.0202155150,-0.0032952912,-0.7536495328,-0.0577502102,1.4988473654,1.1853531599,-1.1569428444,0.4523760378,-0.4761290252,0.4584850967,-0.0814426169,1.1522524357,0.5754417777,0.9752656817,-0.6391966939,0.8959468603,-0.5191081166,0.4095037282,1.2617907524,1.3778895140,0.9799590111,1.6725335121,-3.0943217278,0.9498860240,0.8754180074,-0.3936840296,-0.4376997054,-0.2135491520,-1.3722800016,0.3389026225,0.1849378496,0.1413071156,0.1889852732,-0.9622039795,-0.6044231057,0.8672102094,0.0209429972,0.6589286327,-0.1708002537,0.1002857089,-0.8388501406,-0.1158685908,-1.9335631132,-0.2489332408,-1.6315416098,0.5039172173,1.1015135050,0.5260147452,0.3572916090,-1.0680633783,-0.7171474695,-1.0039732456,-0.6688591242,-1.7563149929,0.3410589695,-0.0830375180,-1.8177490234,-0.1606295109,1.2918634415,-0.8302479982,-0.1817802340,-0.2532959580,1.9223433733,-2.0590584278,-0.7776770592,1.4901905060,1.2545901537,0.8289508224,0.1364070326,0.0048171692,0.4144740701,0.1384837925,-1.2213534117,0.4205737710,-0.1566273570,-1.3302257061,-1.0808893442,-0.3223316371,2.3164737225,-0.6410893798,0.7436528206,-1.2338428497,-1.8407684565,-0.9513223767,-0.5103200674,-0.5803955793,-0.3061780930,0.4369329214,-0.9844542146,-0.3322239220,-0.5980868936,2.0401651859,0.7489195466,1.0855104923,-1.0209662914,0.9438039660,1.3219096661,-0.7857168913,-0.7631080747,0.3792274594,1.9473079443,-0.4503182769,0.3687690496,0.5508050919,-0.0530326739,0.3569258451,-0.2823581696,0.1155722141,0.0433711931,0.0135188764,-1.3273210526,0.2165891230,-0.6997963190,-0.0507710278,-1.7662363052,1.1606320143,-0.0638204664,-0.1239236444,-1.5254353285,0.8884639740,-0.0218050219,-0.4060950279,1.0596505404,1.6093878746,0.6677417755,-0.8113313913,0.2368712276,-0.7918953896,1.3205071688,-1.1475688219,-1.0701115131,1.3642249107,-1.0599621534,0.0186037924,0.5424012542,-0.7976353168,0.5737085938,-1.7811143398,-0.8941566944,0.6157245636,-1.4740045071,-0.0339163728,-0.2008125037,0.4697420597,0.7060800195,0.3085568547,1.4709632397,-1.4332449436,-1.3343772888,-1.9902968407,-0.3875651062,1.7211320400,1.4731040001,-1.1057852507,0.8125382066,1.5489228964,0.2021583468,2.3115398884,-0.4626514018,-0.0988822505,-0.3713912368,-0.1346644759,-1.1158742905,-0.1639193296,0.0890217721,-0.4499882460,-1.1167421341,0.4916646779,0.2613768578,0.2538814545,0.2545026839,1.0541639328,3.0064599514,-0.7094870806,0.7198755145,0.1062187478,-0.7458360791,1.3711556196,0.9849750996,1.1028059721,0.2148303241,0.2942796648,0.3881600797,-2.2538924217,-0.0313082747,0.0384150855,1.4320955276,-0.9805296063,-0.8168244958,-1.0708725452,-1.3232696056,-0.0492793471,1.1589303017,0.9985959530,0.1406734884,-0.2315083295,-1.3020762205,1.6821084023,0.0845298097,-0.0012636767,1.3425643444,-1.1528156996,-0.4846612811,-1.1822725534,-0.6761192083,-0.0896490365,0.0943385810,0.3186304867,0.7720057964,-0.2023819238,0.2094048411,-1.2419801950,-0.3391025066,3.1322660446,0.1629785895,1.3776082993,-0.4834138453,-1.4403148890,-0.9649205208,0.6832093000,0.3958668113,0.5880941153,0.0307263527,-0.8174967766,-0.0751677454,0.4808998108,0.1181297526,0.2792820930,-2.1766908169,0.3593552709,1.2126170397,-0.7078419924,-0.1993245333,1.2566301823,0.3003346920,-0.4112148881,0.4869786203,-0.0476831608,0.6511651874,-1.5540522337,-0.4369316995,1.0390468836,0.9457051158,0.2111051232,-0.3961375952,0.9423094988,-1.1002054214,-0.7350199819,0.0146141937,0.5745733380,-2.6855244637,0.5434151292,-0.1790276021,0.7951074839,-1.7326436043,0.0923662931,-0.5095089674,0.5917858481,0.8422880769,-0.1820607781,-1.6822385788,0.9818657041,0.5777400136,-0.7624858618,-1.0306129456,-0.2130795270,0.9831990600,0.8381908536,0.4186193347,0.2878623307,3.3586564064,0.6768281460,0.7891095877,-1.5845159292,0.6934824586,0.1463712752,0.1077918932,-0.0776537731,-0.9601588845,1.5597449541,0.2852105498,1.1821978092,1.4600056410,-1.0947434902,-0.5802459717,-0.3190021217,0.2932513952,-1.2169111967,-0.1552423239,0.2548938096,-0.6420126557,0.9541916847,-0.4548354447,0.2853848338,1.0490132570,-0.1054982617,-0.8711935282,0.0640761554,2.0955986977,2.2802312374,-0.7062234282,-0.9325771928,-2.7064745426,0.5550458431,-0.8726333976,0.8819828033,0.4131059051,-0.4404965639,0.5863825679,0.9154740572,0.2949877381,-2.6654002666,1.2274175882,0.1260483563,1.0107161999,0.4425277412,1.2145001888,2.3537797928,0.3502727151,0.4897087514,-1.4731489420,-0.6829451919,0.7784183621,0.0769444928,0.8899565339,0.6568589211,-1.4877281189,0.8486710787,0.2527044415,-1.2365397215,1.8013707399,2.1016540527,-0.0500311032,-1.3022519350,-1.9501366615,-0.5360963345,0.3994601369,0.5160616636,-0.8235284090,-1.7060825825,-0.7978700995,1.7503622770,-0.1441345215,-0.9500775933,0.5486234426,0.1444375366,-0.7123869658,-0.1756013632,0.1871870011,1.1465924978,-0.3897903562,1.8086135387,1.1280059814,-0.0083743073,-0.3285886049,0.2197051197,0.7689400911,1.0436525345,0.2513706982,2.6073219776,-0.3112938404,0.2724854648,-2.2912137508,0.2034903765,1.1328512430,-0.0851072371,-0.1136390269,-0.2366341352,1.2237306833,-0.2443148643,-0.1149372980,0.8067960143,0.7126696706,-0.3885196447,0.8958705068,0.6093592644,0.7420414686,-1.1293281317,0.0535399579,0.1800847501,0.9242040515,1.0947157145,-0.4837334454,-0.8320499063,-0.0283501279,-0.7321954966,-0.4648154080,0.5936284661,-0.1790808439,0.6123202443,-0.3115934134,-0.6220819950,0.3708849251,1.4454218149,-0.1824720055,-1.4103887081,0.2352046967,1.5774737597,0.8297368884,1.1899679899,1.4147301912,-0.1582700610,-1.1319595575,-0.5135700703,0.7510833144,-1.5830452442,-0.6762850881,-0.6799480915,0.4081239104,0.8614497185,-1.4354953766,-1.4303246737,-0.3100005388,0.6109189987,0.3791231215,-0.7022027969,1.0591596365,-1.4798945189,-1.0763273239,-0.6885050535,-0.5565457940,-1.9920260906,-0.5430017114,-0.2988832593,-0.4576859176,0.6534484625,0.0158297122,0.0252145696,-0.5811895132,1.6511220932,0.0293052960,0.8481232524,1.3957945108,0.9147311449,1.9018837214,0.0225104298,-1.0985888243,-1.5755480528,-1.9768010378,-0.4817121029,-1.4537837505,0.7854406238,-0.3301056623,1.2437915802,-0.0110594444,1.3535820246,-1.1919013262,0.6878582835,0.4309915602,0.0344051160,-0.4072600603,0.1183931530,-1.1715111732,1.1703085899,1.4365798235,-1.1344217062,-0.5182979107,0.8712841272,0.8400304317,1.4912987947,0.3017890751,0.2879858613,1.5178281069,-0.3468378782,-0.1891960204,0.3158127964,0.2165258229,-0.2097465992,0.6558660865,-1.6493350267,0.0418719389,0.2596367896,-1.1072080135,0.1650775224,-0.6635113955,-0.7450125813,2.1797268391,0.7675815821,1.6386095285,-0.7342829704,-0.8826609850,0.8525941968,0.0779680610,-0.2251982987,0.5225286484,1.7051614523,-1.0837510824,-1.2669957876,0.1919908673,0.8322687149,-0.7541927695,0.6820940971,-0.0351917483,-1.4053186178,0.2227966338,1.3239190578,1.3002049923,1.4524662495,0.3714876473,0.2805170417,-0.0919749141,-0.5110696554,1.1964526176,-0.0531565435,-1.1680847406,-0.6295111775,1.6872906685,-2.5313727856,0.2121602297,-0.8588676453,0.5005645156,-1.4779620171,-0.4762757719,-0.2537456751,0.5073809624,0.6816993356,0.5533781648,0.9636012316,1.4837093353,1.5566785336,1.2752995491,-1.1811940670,1.4324865341,0.2819110155,-0.4524187148,0.7230597734,-2.5340185165,0.0218055099,-1.2718653679,-2.7177481651,0.5364590287,-0.0088465754,-1.0927875042,-0.2092958838,0.3976587653,0.1919134855,-0.5732107162,-0.0421538688,-1.5942142010,-0.3043152690,-1.3545215130,-1.0652045012,2.5165457726,0.8235344291,-0.8325254917,0.7410484552,-0.8188034892,-0.3710550368,-0.1469221711,1.4208518267,-0.6055439115,-2.3149800301,0.0533712320,0.9889836907,0.5201842785,1.0583690405,0.0227681696,1.2871819735,0.8295145035,0.1761369258,-1.2930803299,0.5198744535,0.3537299931,0.9064239860,0.3577017486,-1.2018020153,1.5393267870,1.1606206894,0.3462671638,1.0494418144,2.0337548256,-0.6492514014,-0.2536161840,1.1055673361,0.7026463747,0.8310782909,1.0652977228,-0.2652146518,0.6976580620,-0.1085451543,-1.5246456861,0.3379697502,0.6745842099,0.6699867249,0.7807105184,0.3559247553,-1.4706202745,0.2427008599,0.1194189042,-0.9471550584,0.5363782048,0.7715194225,-0.7956759334,1.3846803904,-0.0059837541,1.6803729534,0.4307575822,1.3302416801,-1.9971408844,0.9966135025,0.6510790586,0.3689449728,0.3054286242,-0.0868136510,-0.4496328235,-0.4203562438,0.0446175151,0.0464101844,-0.6030803919,0.9469773769,0.8830232620,-0.6825973988,0.0063548535,0.9545045495,1.7176597118,-0.4867136478,0.5350939631,0.2192623615,1.4326761961,-1.8599370718,-1.3125212193,0.1645046771,-1.1676248312,1.4429554939,-0.5579243302,0.4837940633,0.9947431087,-1.2013341188,-0.4283203483,-1.7186342478,0.0546005592,1.0362206697,-0.9954963326,0.0477595143,-0.0268921070,0.6498132348,0.1365755051,0.1145898923,1.2277548313,-0.7165322304,-0.3180812597,-0.9940687418,-1.9625616074,0.7006590962,-0.0359061249,-0.3734052181,-0.2956706583,1.2970714569,-2.0354444981,1.5242056847,1.4134936333,0.6256355047,0.6216192245,0.5148414969,1.6640155315,0.0376209542,-0.2404932976,-1.3875989914,1.0557792187,0.9804635644,0.2911759019,1.6869058609,2.4566636086,1.6708139181,-0.6846850514,-0.0785990059,-1.9915647507,-2.2253570557,1.7390940189,-0.0221805908,-0.5199558735,-0.4286879599,-0.8465876579,0.1239822507,-0.3726306856,-0.8203553557,-0.0182525702,0.5630733371,-1.8752394915,0.4155042470,0.5997116566,-1.9111266136,-0.1225134805,-0.9004780054,0.5674170256,0.9721233249,-0.5763071179,1.2280766964,0.0869190246,1.5497611761,0.0690125600,-0.3725866973,1.1458171606,0.7421871424,-0.2898759842,0.4488764405,-1.1340010166,-0.6257569790,0.8099257350,-0.5755894184,-0.3711819947,-1.2420692444,0.5750556588,1.2347095013,-1.3155068159,0.5820550323,-0.1800024062,-0.7291352749,0.9901236296,1.6943480968,0.3219739199,0.4525323808,-0.8705807328,1.2545053959,0.0177927706,-0.9325863123,0.5151397586,-0.0098660281,0.4695507288,-1.9551370144,0.1708181202,-1.2006139755,-0.6353746653,-0.3414449990,0.6378657818,1.6013050079,1.3553612232,0.3463516533,0.4996110201,0.5760862827,-0.3864963055,0.6062389612,-0.9762124419,3.0961830616,-0.3332355917,-0.6250987053,-0.3858212531,-0.0016092911,0.1147701219,0.1219455898,3.0642769337,0.9969142675,-0.3090046346,-0.6291542649,1.7868961096,0.3111509979,2.1643211842,0.2989636660,-1.6422638893,0.0548259765,0.0236156844,0.6794649363,0.6361483335,-0.2971331179,0.1430229992,0.3408798873,0.1371335685,-1.1627069712,-1.6395305395,-0.7312899828,0.8405165672,-1.4277316332,-0.6171786189,0.9497544765,0.1589775980,1.0119231939,1.3794178963,-0.4360499978,-0.0422094576,1.5773836374,2.0762181282,0.7507163882,-0.3115755916,0.7139906287,-1.1984947920,1.6259472370,-1.8023258448,-0.2536619902,-0.3082579374,0.0895618051,-0.2826513350,-0.7755914330,0.1211613193,-0.5160586238,0.3996881247,2.6127579212,0.7454584837,-0.5768119097,-1.1571289301,0.2560498416,-0.8254200220,-2.6075785160,0.8396331072,1.7745233774,-1.1578730345,-0.2286801040,0.1026872993,-0.4894656837,-1.0386230946,0.6681470871,1.1531586647,-0.2183658928,0.3109624088,-0.6623362303,-1.8053112030,0.3087073267,1.0570780039,1.0746499300,0.5073927045,-0.8723320365,0.6104628444,0.4474971294,-0.7325591445,0.2552275360,0.4838557839,-1.0039037466,-0.1963803470,-0.6780635118,-0.4196233749,1.5498566628,-1.6033440828,0.3494834006,1.0629042387,1.0952367783,-0.9827461243,1.2384337187,-0.7188549638,0.0698258132,-0.5090520978,-1.3466193676,0.2113907784,-1.9054464102,0.7425320148,0.0713237897,-0.3361792564,-0.1544833332,1.2751290798,0.9343932867,-1.1927865744,0.1609488577,-0.0817530602,-1.6265294552,0.0792161152,1.0164269209,0.0274453927,0.5830265284,0.4806797206,1.7057460546,0.3446226120,0.1727063209,-0.5576907992,0.5787950158,0.2685793638,-1.1247400045,-1.1956520081,0.7687556148,-0.8483432531,-0.1325481385,0.6503481269,1.2317855358,2.5165569782,0.9462372661,0.7442957163,-0.1037486866,0.8058280349,1.2004961967,-0.2012088895,1.2878060341,-1.6287704706,1.1572757959,0.2970125377,-0.8433011770,0.6941140890,-0.3813734949,-0.7616585493,0.2744237781,-0.0081879422,-2.0205621719,-0.4257437587,0.0422513634,-0.0920020416,-1.5582008362,-0.0928666592,-1.2283902168,-0.1833214313,-0.3190955520,-0.0863488317,0.9307079315,-1.9677612782,-1.5400369167,1.0738964081,-1.0055810213,1.1223951578,0.5734156966,0.4714262486,-0.0594240949,-0.8080806136,0.2278677970,1.0362339020,-0.2495359480,-0.7958166599,-1.1433826685,-1.1669473648,0.2910191119,-0.2219422013,0.1698516011,-0.5612007976,1.1821777821,-0.9412812591,0.3577224612,-1.4375506639,0.6173115969,-0.0753971860,0.4404014051,0.3479704261,1.7728350163,-2.4903116226,1.9318493605,-0.1871684641,-0.0486194454,0.5669991970,-0.1999413967,0.3919151723,-1.0137641430,0.4496327043,1.2215998173,-1.3674079180,-0.3145882785,-0.6682460308,1.7609888315,0.4312697351,0.4117654860,-0.8673826456,-2.2342579365,0.8778496981,1.7627274990,0.1801376790,-0.9213985801,-0.7761957645,1.5885344744,0.3222749829,-0.7482187152,-0.0693738833,-2.5485017300,-0.0396765657,0.9220715165,-1.1876281500,-0.2048502117,-0.8791155815,-0.2799369693,-0.7904237509,0.7771903872,0.0180385746,0.2614985704,0.1531894207,0.4526953697,-0.7578824162,-1.0335227251,1.0775671005,0.2108330131,0.2002221793,0.4302573204,-0.9542171359,-0.1206719950,-2.2216730118,-1.1611789465,-0.8942284584,0.3513225317,-0.4492657483,1.7326287031,0.8167504072,-1.3099080324,1.0597997904,-0.0260978416,-0.0922782496,-0.2445535958,-0.8588480353,0.0233809687,0.8380134702,-0.8886740804,0.0055783619,0.8041345477,0.5155995488,1.3099330664,0.0607562996,-0.4853078723,-1.2040776014,-1.8143754005,-0.9156990051,1.1903975010,0.3376074731,0.4168293178,0.2208614945,0.0823195726,0.3248101473,1.0169280767,0.3660759330,0.7446341515,-0.6754641533,-0.9308695197,-0.9214447737,-0.9902174473,0.0467686094,-0.4429434836,-0.2878521383,0.4659559727,-1.5754804611,0.7648607492,0.6077049971,-0.2009276748,0.1410205662,-0.7378753424,1.5970349312,2.4544296265,-1.7936341763,-0.6051549911,1.5142178535,-1.1078259945,0.3795293868,1.7709084749,0.4984016716,-0.2436304092,-2.2577059269,-1.2458858490,-0.7088252306,1.5962058306,-1.9355672598,0.6987320781,0.3166677952,-0.8615584970,-0.1896579862,-0.6173701882,-1.0844488144,0.5718342662,-0.5237622857,-0.4043986797,1.4371533394,-0.5186876655,-0.8964678645,0.9899360538,-1.3119916916,-0.7182676196,1.0389785767,-1.1774294376,0.6187053919,-0.4993627965,-1.1766394377,0.0940822363,-1.0231488943,-0.4538815022,-0.6294190288,0.5030683875,-0.2208803594,0.9774012566,-1.0498013496,1.1215320826,-0.2495442778,0.3619700968,-1.0616446733,1.0567066669,1.3423643112,0.7119333148,2.0674512386,-1.6267881393,0.6471201181,0.2160703689,1.3485805988,-0.1709989458,-1.2881512642,-0.3260785937,-1.8688436747,-0.1713963598,-0.2822999358,-0.7701655626,0.1642793864,-0.4175589979,-0.6222335696,0.2136606127,0.4244953096,1.0451035500,-1.6823191643,0.0403030105,-0.4710847735,-0.2437952608,1.3693777323,-1.1758570671,-0.0542855076,-0.9699545503,-0.5364821553,-1.7010054588,0.2163471431,-0.2669135332,-0.3398927152,-0.0248095077,-0.4684832692,-2.0178093910,0.4001567960,-0.6108651161,0.5783423781,0.1649526060,0.8978267312,0.7421654463,0.4261821806,-1.0519768000,-1.4087666273,-0.8967926502,-0.6909884214,-1.0733422041,1.3887276649,-1.5292494297,0.6003373861,-0.3892106116,-0.0517769493,0.0179459751,0.1571146250,-0.5726046562,0.0190555137,0.5697455406,-0.8141471148,-0.3097047508,0.4373070598,-0.3019420505,0.1362971067,-1.0670320988,-0.0000817540,0.8114110827,0.4083184600,1.8282098770,0.1381276697,-1.9155849218,0.0719738081,0.2208820730,1.2493988276,0.3405856788,2.0780653954,-1.2551661730,1.0017586946,-0.5354287028,0.8841439486,-0.5767771602,1.1559445858,0.3145794272,0.1051806211,0.6909182072,0.7290110588,0.1197143495,-0.6287478209,-0.6085677147,-0.8197476268,-1.5091049671,1.0208386183,-0.0439724736,1.7148467302,-0.0321364142,1.3864095211,-1.0215556622,-3.0513429642,-1.1673578024,2.1856009960,0.2588728666,0.3434796929,-0.8460996151,-1.9793503284,-1.1928198338,0.9098986983,0.4554537833,-1.0023721457,-1.8009947538,-0.6367038488,0.9891266227,0.0203659870,0.3414032459,-0.4097161591,0.2278744727,1.2209628820,1.1159952879,-0.9623272419,-0.4903887212,0.4621538222,0.2723306119,-0.9540486336,-0.2404303402,0.3517660499,-1.4416646957,0.4990543127,-0.7126743197,0.3536555171,-0.9577149749,-0.3402226269,-0.8734661937,1.0238445997,-1.2684786320,0.2645486295,0.2472764254,1.1231633425,0.8844839931,-0.5912511945,-0.3987582028,-0.6692000628,-1.7035512924,1.1779968739,1.1480795145,-1.9619866610,-0.6322578192,0.4063148499,0.8685815930,0.1516608745,-1.1480426788,0.0343636200,-0.2617740929,0.8340689540,0.8000271916,-0.4284797311,-0.0311497673,-1.1331477165,0.1529792249,0.7315949202,-0.4204881787,-1.7638682127,0.6233843565,0.1415092200,0.2131320089,1.0914654732,-1.6148589849,0.4392548501,0.3568493426,-1.3790297508,-0.1812242717,-0.4438568354,-0.5541661978,-0.4909126163,-0.9593079686,1.0866227150,0.0711556524,-0.6503744125,0.3807986677,-0.0300570186,-1.6283313036,0.6702497005,0.2368342578,0.6066207290,-0.6736672521,-1.0897010565,-1.1997205019,0.2919110060,0.5207223892,0.6099629998,0.6813975573,0.4636356533,0.0687451810,-0.4502599537,0.1851959527,-1.4338147640,-0.4437556267,1.4200047255,-0.6315543652,-0.7744462490,0.6045300961,-1.2394708395,-0.2095934153,-0.3702944219,-0.6200354695,-1.3909845352,-0.3433581889,-0.9693596363,-0.3587476015,0.3847161233,-0.2518064678,0.4357206225,-0.9091473222,0.6839234829,-0.0295625720,1.4972803593,-0.1460575759,-0.0939826742,-0.2217037976,0.0946994647,-0.2410782129,0.9098507762,-1.3256295919,-0.0817464665,1.3583462238,0.7781915665,0.0069436296,0.5164428353,-0.0651496351,0.7075184584,-1.4202232361,0.2231310159,-0.3650387228,0.1650255471,-1.3219217062,1.0231046677,0.7444481254,0.5359328985,0.5666531920,0.3261220157,-1.3667412996,0.1605643630,0.2437143475,0.4470121264,0.3345755637,1.5117784739,-1.4013890028,-0.3585534990,-0.2405987382,-1.2795827389,0.3206909299,-0.4760054648,1.4264730215,0.2798275650,-0.0359120257,0.4687083960,-0.4645172954,-0.1489082575,1.6419786215,0.8950193524,-0.2498975992,0.0254452918,0.7679093480,0.3977237940,-1.2860594988,-0.3435108960,1.3776507378,-0.2499962747,0.5837259293,-0.3566249013,-1.5012432337,-0.0366155952,0.6415373683,1.7652125359,-1.3682287931,-0.0861081928,0.0383691862,1.2417683601,-0.1283382177,-0.1103384346,-0.7885918617,0.0254839975,-0.7123177052,-1.1390565634,-0.0729266852,0.2223683745,-2.5684566498,0.4270484746,-0.0046181614,0.0415315256,0.6546118855,-0.9823287725,-1.3519179821,1.2908511162,-0.5305488706,1.7785286903,0.8555805683,1.3566535711,-0.4564712942,-1.4938685894,-0.9814547896,-1.3854124546,-1.5733133554,-0.8129420280,0.3343071938,-0.2484793961,0.7299104333,0.6596966982,-0.7074251175,1.6392796040,-0.7114089131,0.3561543822,0.1788314283,-0.0102422200,-1.5114012957,-0.0173943099,-1.0720241070,-2.3937253952,-1.3889380693,0.0471616276,-0.4784292877,-0.8774627447,-0.7773531675,0.5064339042,1.4271920919,0.6994634271,0.3179759979,2.0188155174,-0.6257854700,0.4875732064,0.9742701650,-0.6120517254,-1.6027874947,-0.5442904234,-0.2421242595,0.5398359299,1.3619903326,0.7030728459,-0.4203302264,-0.0356382467,0.4759574831,-0.3176399469,0.9230871201,-0.7705651522,-0.8988927603,1.8517060280,0.6137269139,-0.1375556439,0.7560847998,-0.7871061563,-0.8101333976,0.9718251228,-0.2960273027,-0.8531348705,-0.7449046373,-2.3861715794,0.5155227184,-1.4067013264,0.3101865947,-2.1656732559,-0.4105100334,0.4387335181,0.6727346778,0.2653877437,0.9309439659,-1.1482447386,1.7589145899,0.4293440580,0.6618949175,0.6083560586,-0.7772499323,-0.2988936305,1.9642839432,-1.3446459770,0.3042408824,-1.8033968210,1.1037830114,-1.7535353899,-0.5489560366,0.9455407262,-0.8433424830,-0.1801532805,-0.4749929905,0.2693964243,0.4919607341,1.2626482248,-1.0708043575,0.1030553579,0.1843638122,-0.7110225558,-0.0900483355,2.1595232487,0.1592033505,-0.9272395968,0.9635785222,-3.7438845634,-0.7730277777,-0.9164265394,-0.2171987295,0.0299481545,0.4585601985,-2.6037380695,0.2609812319,1.3040894270,0.9559362531,-0.0413816720,-0.6852220297,0.4935119152,0.7921469212,0.1276420653,-0.1001019925,-0.0484789126,-0.5497506261,-1.6832387447,-1.5431174040,-1.1059116125,-0.1819771081,0.1616688073,-0.5764904022,-0.9880220890,0.0783481523,1.4437611103,1.9365442991,-0.3549702466,-2.2470059395,-0.4686661363,-0.9983262420,1.7535051107,0.6303505898,-0.7734314799,2.6364636421,0.0392718092,1.5254333019,-0.6479625106,1.6099628210,0.3199017942,0.3757773638,-0.4623837471,-0.1848932803,0.3996022344,-0.0442292541,1.3251973391,-0.4424172640,0.0063154404,-1.4659434557,0.5882980824,0.6704141498,0.9195390344,0.5987154841,-0.6095600128,2.0387501717,1.5419700146,-1.3648542166,-0.9416725636,-0.5326945186,-0.6290355921,0.2064234316,-1.1643296480,1.3079528809,0.4787613750,-1.1614365578,-1.2261186838,0.6149030924,1.1901096106,-1.7869648933,-1.7015125751,-0.0369055569,-0.1572385281,-1.8780126572,-0.1200147271,-0.4242606461,-0.3192552626,0.0104762856,-0.6464591026,0.8706829548,0.5600137115,2.6534612179,1.3147951365,-2.0153663158,-1.6875379086,-0.6459116340,-0.4426926076,0.1987432837,0.4108413756,-0.4009189308,0.9362496138,-0.7191836238,0.6938658953,-1.7758921385,-0.1403557509,-0.0228065960,1.0006980896,0.8325053453,0.6643543839,1.0108941793,-2.3972070217,-1.1385048628,0.4741702378,-0.6687298417,0.4963333309,-0.7473987341,-0.3865411580,0.2450307906,-0.8685840368,-1.5923013687,0.0233582482,0.8655768037,0.9436566830,-0.7575323582,1.0158644915,0.6127064824,-1.7185145617,-0.4814927578,0.0290120076,-1.8096933365,-0.8135496378,0.5268061161,-1.3745579720,0.8449429870,0.7756015658,0.2198592126,0.1512816399,0.7091155648,1.1741852760,-0.5143500566,-1.6707895994,1.2580791712,1.5318725109,-0.5002031326,-0.2448760867,-0.2390441149,-1.4903237820,0.6865671277,-0.3201767504,-0.0794070512,1.9951273203,-1.4163293839,0.9918632507,1.7666332722,0.1555749178,-0.3725374937,-2.1025719643,-1.2156616449,-0.8836985230,-0.3397898972,0.4215038717,0.4887259007,-0.4905745983,-1.3774695396,-0.6583486795,0.0738252997,0.7343323231,0.4211414754,0.1247600242,1.7488490343,0.2251959741,-1.0532218218,0.4716623127,0.5744453073,-0.0024379981,1.1637272835,-1.9481000900,1.4603103399,1.5550012589,-1.2255028486,0.6156579256,0.6069850922,0.8603722453,-0.5207680464,0.8478476405,-0.3461050093,-0.6320928931,-0.7256397605,-0.9042200446,0.7228765488,-0.0928905234,-0.7883547544,1.6062039137,0.0710300654,0.5437248349,-0.4915961325,-0.1041649207,-0.3031794131,-0.4425407946,1.1392168999,-2.0505964756,0.4079806805,-0.0800484493,-1.3515720367,-0.9124820828,-0.8583441377,1.2894556522,0.5908492804,-0.5798185468,0.0520669743,-0.1212026998,0.4420488775,0.6347669959,2.2531759739,0.4614149332,2.1107082367,-0.6364678741,0.6796067357,-1.2275124788,-2.1137130260,-1.4560955763,-0.1521469504,-1.1474013329,-0.0936479792,-0.4342494607,-0.3847503066,0.9745326042,-0.8003863692,-0.1759050786,0.4681669176,-0.2825888991,0.5702939630,-2.0764098167,0.0134140672,-0.7991058230,1.5231801271,0.3928492367,0.8087913990,0.1406501085,0.2782938778,-1.2058972120,0.7704486251,-0.6398083568,1.8859362602,0.8982129097,1.1188243628,0.0342440680,0.1872243583,1.8391888142,1.3006812334,0.3444184959,0.1678676009,-0.2385491282,0.1145463064,-1.5685496330,-0.4964090586,-0.3101575971,0.3440920413,0.1293883473,0.5067656636,0.3827549219,-1.0888370275,-1.4858487844,-0.9661257863,-0.7745360136,-1.4245500565,0.1393938810,-1.4260451794,-0.5082685947,0.8763096929,-0.6662014127,-1.2093539238,0.7315164804,-1.1380810738,0.0281808823,-0.9322289228,1.2290621996,0.7308822870,0.1425308883,1.4224876165,0.7261432409,1.1260491610,-0.8474053741,-1.1105213165,-0.8556407094,-0.7260117531,1.1177033186,1.1724927425,-0.1795573980,1.0290118456,-1.1191790104,0.0396585315,-0.0047235782,0.2664375901,-0.5832667947,-0.8921521902,-0.8755141497,-0.9598096013,0.4069607854,2.1447017193,0.3723194003,0.3736964762,-0.6830319166,1.3127006292,-0.6640972495,0.7430377603,1.0540186167,2.0303764343,0.8735508919,-0.6355731487,0.5069352984,-0.9557527900,0.9533885121,-0.4849050343,-0.1885131001,-0.6945106983,-0.6633606553,0.2577122450,0.6968512535,0.0700863674,-0.8694693446,-0.9572583437,-0.1153896451,0.2002226561,-0.3849981725,0.2202363312,2.0618686676,0.3926514387,-1.5631883144,-1.2940770388,-0.5507266521,0.7313650250,-1.7164524794,-0.7593462467,0.3257178962,1.1041924953,-0.6681020856,-1.2724117041,-2.1357870102,0.3565237820,-0.0748446658,2.0107169151,-0.8546269536,-1.1847459078,1.8804349899,-0.1341653168,-0.5399327278,0.6568149924,-0.6100254059,-0.0584002621,-0.3279354274,0.0255116895,-0.4765267670,-1.3591419458,-0.1435545087,0.5789028406,-1.7496489286,1.4535236359,-0.6286903024,0.2937216759,0.1816752106,0.3662569225,-0.8155812621,-0.7177008390,-0.6351452470,-0.5987464190,-0.7643153667,-0.0924506560,0.0002173648,0.4418594539,0.2845681310,0.1451430768,-0.9784609079,-1.6784154177,-1.2964258194,1.5535236597,-0.7936209440,-0.5138964057,-0.9194343686,-1.3460687399,2.6226949692,0.8296312690,0.6559735537,0.5372175574,-1.2835997343,-1.2348910570,-0.9327340722,1.3215962648,0.4506095648,-0.1519411802,-0.1253918707,0.1870906502,1.6497941017,0.0869149938,-1.0887746811,0.7199364305,0.4501723051,0.2700583041,-0.4041815102,1.0006670952,1.3125792742,0.6810870171,-0.1800761074,2.4339106083,0.1763603538,0.8710671067,-0.3742243946,0.4617210627,0.3632403314,-1.1402145624,0.8772246838,-0.2340421081,-0.8595511913,0.0905576646,-1.4307808876,0.5439644456,-0.0927907899,-0.6408239603,0.6136070490,0.5124572515,-0.6934475303,-0.6896564960,0.5295175314,-0.1667579859,0.2426082194,0.0189859830,2.2494912148,-0.2460813224,-0.2038732916,-0.6019621491,-0.0026605215,0.1960952580,-1.1902012825,0.4211482704,-0.4473219514,0.4534853399,-0.3401862979,0.1513924450,0.3664656281,0.2547777295,-1.0560954809,-1.9132366180,1.4109679461,0.6244448423,0.4116883576,0.4919942617,-0.6390546560,-0.0430185869,1.6317751408,0.2780894935,1.6450288296,-0.3439806104,-1.5669082403,-0.0530644134,1.5441375971,-0.4733426571,0.6746113300,1.0411593914,0.9855762720,-1.7978531122,-0.9804763794,0.6059101820,1.1089842319,-0.8183146119,-0.9320350289,-1.1980115175,0.1660242826,-0.7525303960,1.5922327042,-0.8294901252,0.9423011541,-1.8002551794,0.0447457209,1.4288845062,0.5406267047,-0.1151995510,0.8838722706,-1.7344129086,0.5595968366,0.4175852537,0.6582928896,0.7738341093,0.7438519001,1.0156049728,-1.3063168526,-0.9007453322,-0.5195229053,-0.0660142750,1.7721335888,-0.5381574631,0.0451898575,-0.8444939852,-0.0029482909,0.9423898458,-0.8007932305,2.1239731312,-0.2745014429,-1.9707047939,-1.2178057432,0.7433405519,0.2328127027,1.4669008255,0.1985478550,0.8833305240,0.4210582674,-0.6766483188,0.7286726236,-1.7391421795,0.4351043105,0.6838805676,0.1998222470,1.5584337711,-0.7463527322,1.0878604650,-0.5838196278,0.3922228813,-1.2806158066,0.0529088899,0.3663826287,-0.1530306935,0.0078097042,0.3014991581,-1.7583640814,0.5166698098,-1.0459570885,0.3360862434,-0.3021540940,1.6351559162,0.2339851409,1.3475879431,-0.2810580730,1.2364726067,0.8393220305,-1.1669842005,-0.9311234355,0.3072465360,-0.7316344976,0.6209425330,-0.4304316342,1.0347040892,0.3869737089,-0.8412460685,0.9965993166,0.2931939960,-1.5351545811,-0.2541728318,-0.5098071098,-1.9362185001,-1.0679433346,1.2295447588,-0.6092607379,-0.2998788953,-0.2101449221,1.5696338415,-0.9006688595,1.9490916729,-1.1761932373,1.4566138983,0.7829972506,-0.9729502797,-0.6038942933,-0.3258980215,0.3648591340,0.6088670492,0.5756407976,0.1295090169,-2.0584166050,0.7405277491,-0.0565741882,1.6712781191,-0.0073989523,-0.7615351081,-1.7625714540,-1.6687066555,0.2233912647,1.7904453278,-0.2203775346,0.3719655573,-1.2596836090,-0.1352416873,1.6784518957,0.9244667888,0.6470136046,0.1950820833,0.2686503530,-0.3164552450,-1.4811400175,-0.4500595033,0.9400957823,-0.8417010903,1.2031250000,0.1384577602,0.7147232890,0.8561578989,0.8689596653,-0.7192590237,-0.4665651917,-0.1493928432,-1.8951672316,0.9723851681,-1.4815393686,-0.3151030242,-2.1755998135,0.3345840275,0.4477573931,-0.8480839133,1.4286578894,-0.5938410759,-0.3036641181,-0.1643898785,1.4175655842,-1.2077329159,0.5321143866,-0.3946001530,1.0930041075,0.8004240394,0.0015130466,-1.2983140945,-0.2006176710,-1.0674712658,0.6152316332,1.3683578968,0.5303028822,-0.3842371404,-1.3599123955,1.2266104221,0.7833281159,1.6608939171,-1.1905647516,-0.5298700333,0.9390087724,-0.7273864150,-3.0896890163,-0.9112982154,-0.2719693184,0.4283858538,2.2000403404,1.2904229164,-2.8206224442,1.5973047018,-0.3084849417,-1.2416521311,0.3893934488,0.9960338473,-1.6180120707,-0.7857273817,-1.6723463535,-0.1164723262,-1.4589574337,-0.2019911110,0.2670248449,0.9341351390,-0.5450060368,-0.9017308354,-1.1602119207,-0.9146684408,-0.4528957009,-0.7189208269,-0.8239266276,-1.4149652719,1.0071654320,-0.7333939075,-1.2482929230,0.3368687928,1.5294657946,2.1932830811,-0.0322217532,1.3643707037,-0.7223550677,-1.0060669184,0.4713765979,0.0374758020,-0.2954056263,-0.5196225643,-0.3418472409,0.8694543839,-0.0366826206,-0.3693021238,-0.0720364004,-0.3977731168,-0.2981844246,0.3481273651,-2.2333576679,0.1124164909,-0.5860416293,1.2649736404,0.4698347449,-1.6995165348,-0.6768918633,0.5547665358,0.1519433111,0.4794569612,-2.0995452404,0.1126223803,-0.5789268613,0.7632908821,0.6681728959,-0.1237390935,-0.2411789000,-0.8700891137,-0.0535563789,0.1604736447,-0.2040840238,-0.3879729211,0.3112916052,0.7895922065,-0.0806431398,-1.9122922421,-1.2963095903,0.9608740211,-0.5996281505,-0.2180650234,-0.1556250751,0.5601133108,0.5118433237,-0.6297109723,-0.2477449030,0.4377675653,0.1655773968,-2.1302938461,-1.1546865702,1.3413959742,-0.7347362041,0.8989260197,0.4398216605,-0.8333153129,-0.5954267979,-0.4634758532,-0.0472172499,-0.1780685633,-0.6798447371,-1.1439967155,-0.0540322363,-0.7338622808,-0.3657207787,-1.3311915398,-0.0009648965,0.8482714295,-0.3821905851,0.5203379989,-0.4978805780,-0.6867644191,-0.3023690581,-1.7219276428,-0.0706413612,-0.9097322226,-0.6544209719,-0.6343010068,0.1573838145,0.8664366603,0.7233697176,-2.0078625679,0.2135981321,0.4005902708,0.3631705046,-1.0551964045,0.1154454425,-0.6361332536,-0.7936405540,-0.8201953769,1.5267411470,-0.3820387125,0.8344710469,-0.4640203118,-0.1984673291,1.1495521069,-0.2665902674,-0.3317551613,-2.1129162312,-0.9538705945,0.7641342282,-1.5903077126,0.8508225679,1.7642945051,-1.1222983599,0.5385093093,0.4542241693,-1.7904034853,-1.0321934223,3.2340333462,0.3957667649,1.8712517023,0.1348981857,0.3125168383,0.2443830669,0.4996775389,0.2636229098,1.9391344786,-0.4150807559,-0.5804721117,-1.0143501759,0.1284436435,1.1321600676,0.3555642068,-0.1672841161,0.6568336487,1.0217926502,1.1322041750,-0.7075734138,-1.3878320456,0.4098901749,0.2341521829,-0.1374025643,-0.0444334671,0.4156866968,0.9274237156,-0.5546074510,0.6505785584,-0.1995093673,-0.0293728597,-0.3378144503,0.5294931531,-0.8031910062,2.0809404850,-1.1738935709,0.7713395357,-0.7774733901,-0.5353500247,0.3451361656,-1.3199455738,-0.3418870568,-1.0163743496,-1.1710753441,-0.2852978408,1.0949852467,1.3117394447,-0.8261899948,-0.6163251400,0.0279291794,-0.4021877348,0.5516725779,0.5848386884,1.0316517353,0.3473063111,0.6851702929,0.8027648926,0.5897445679,-1.0397065878,0.8500480652,-1.5022568703,0.5201315880,1.5309634209,-0.0968860835,1.6017364264,0.3336514235,-0.0345757678,1.5534172058,1.7362976074,0.6443283558,0.8172535896,-2.2950198650,-1.5091173649,-0.1997069120,1.0716969967,-0.1073218584,-0.7956750989,-0.6962655783,0.4508700073,-0.3004487455,-1.1373023987,1.7564595938,-0.1807855815,-0.3760594130,-1.2967089415,-0.6098486781,0.4165080786,-0.8964832425,1.7748460770,-0.7647678256,-1.5128406286,-0.3202617466,-0.2043563724,1.0446738005,-0.7297920585,-0.0262035001,-0.1444185227,0.3840039670,0.2060625702,-0.2181037962,-1.1294969320,-1.0868163109,0.3352339864,1.9930715561,0.5076326132,1.3730456829,-0.0023539420,-1.5736697912,-0.3311335146,0.9903514385,0.0521080866,-2.4414179325,-2.5822451115,0.1565915942,1.4188001156,0.7368789911,0.2345260978,1.0152734518,2.2886154652,-1.0148390532,-0.3122152388,-0.2702304125,-0.5222117305,1.4889755249,0.5128302574,-1.7104084492,0.1142061651,-0.2926707566,-0.8836719394,1.8603035212,0.1356332749,0.8755128384,-0.9803749323,-0.2293416560,0.2006159127,1.7615724802,0.3264065087,0.6724275351,-0.0469790995,3.1880333424,0.4425591826,-2.3789470196,-2.4320871830,-1.5881433487,-0.4209427834,0.4819173217,-0.5247082114,-1.5172423124,0.8938916922,-1.6846462488,0.2446191460,-1.0680624247,-0.3203495741,0.0754074827,0.9786596894,-1.0031156540,-1.4559154510,0.3935267925,-0.3842234910,0.4690336883,-1.0834065676,1.4030132294,-1.4369273186,1.1485811472,1.4488285780,-0.9468003511,-0.5519796014,-0.4509304166,-0.4519639015,0.0976786837,-1.9000874758,0.7958002090,0.1177812293,-0.3470512629,0.0172776580,0.8916116953,0.1383883506,0.1076137498,-0.1316533536,-1.9620102644,-2.0274169445,1.5324951410,0.7383908629,-1.1564779282,1.5768051147,-1.4502425194,0.9668387771,0.3540835083,3.4085419178,1.9100345373,-0.8650856614,1.4155201912,0.5690464377,0.5973732471,-0.8678830266,0.8286939859,-0.2351627350,0.9233389497,-0.5177605748,0.4496781528,0.0800872520,0.2445594221,-0.2652956247,2.1359424591,0.1638048589,-0.7652742267,-0.8763234019,0.3231536448,-0.6016790271,0.2801153660,0.8367733955,0.5688657761,0.6027054191,1.1826387644,0.0957681388,0.1674305946,-0.1956560016,0.5108280778,1.0816714764,0.6208047867,-0.1561427861,0.8358264565,0.9209582806,-0.8191552162,-0.1509196013,0.8101909161,1.2557537556,0.2925243676,-0.0419176333,1.1210883856,-1.0228914022,-0.1098661944,-0.8591143489,0.2410670966,0.9973797798,-1.4664530754,-0.0980027616,1.8604106903,-0.6354730725,0.2107730508,0.5374374986,-1.1003706455,0.8711256385,-0.6260376573,0.2263965756,-0.0102861263,-0.1871914864,0.8020673394,0.5475625992,0.2951956689,1.2020192146,-0.4511943161,0.6142093539,0.0216287971,1.3507753611,-0.3723137379,-0.1512116939,-1.7927660942,-0.4930469692,0.6896463633,-1.8515053988,-1.6282465458,-1.2689808607,0.3326217532,2.1312882900,1.7744779587,-0.8050757051,-1.5977858305,-0.3082677424,0.1215020418,1.4367951155,1.2268460989,-0.0081329355,-0.5573827624,0.1035985723,-1.2760721445,-1.1780765057,-1.2280064821,1.1160129309,1.7673761845,1.7334949970,-1.7602155209,0.5039381385,-0.3720277846,0.3963406086,1.0447177887,-0.8420517445,-0.0861799866,-0.1530893594,0.2599826753,1.1811122894,0.5532831550,-1.3378735781,-0.8013755083,-0.8412433267,1.0781079531,-0.0028998200,-0.6660804749,-0.7412942052,2.3283331394,-0.4305628836,2.7005894184,-0.6134419441,-1.0312664509,1.0619452000,-1.1738936901,1.2846373320,1.7262413502,1.3725773096,-0.7013794184,-1.3772867918,0.4172764719,0.4020915329,-1.1206417084,-1.2978309393,-0.0802910849,0.9490975738,0.0574220717,0.1611342430,0.6615610719,-1.6403830051,0.2258825600,-0.2138030678,-1.7920988798,-1.5084474087,1.6496242285,-1.0713797808,-1.8907377720,0.0772534534,-0.2337310910,0.0140136406,0.5051288605,0.4664832950,0.8642095923,-1.8167469501,1.0395417213,-1.1637365818,1.1356519461,-1.7042986155,-0.0973814875,1.1059724092,0.6865385175,-0.0097261248,-0.0064713955,0.2397290915,0.4610339105,2.3903193474,0.5248602629,-0.8353090286,1.6538916826,-0.5744239688,0.4300434589,-1.4513535500,-1.2397629023,-0.9852696657,0.1993034035,0.0661344454,-0.5709816217,-0.0929837227,0.2432375997,-0.0583449788,0.0009275326,0.8209046721,0.0518882200,0.8052539229,-1.6794208288,0.2178734690,0.7934340835,-0.8915417790,-0.9696401358,0.0556026287,0.7279754281,0.4486949742,1.3063867092,0.0655736998,-0.5748510361,0.0804484934,-1.2538518906,1.0344552994,0.0385405272,0.1673927009,-0.4514338970,-1.3391981125,-0.3614654243,0.9321334958,0.4562244713,0.2335039377,0.1003533304,-1.6953806877,0.1109338477,0.4388502240,-0.1420196295,-0.5670718551,-0.4239734113,0.6679923534,0.1954314113,-0.7743871212,0.7897585630,0.2001348287,-1.4090903997,-0.6529703736,-0.5033426285,0.8819975853,-0.8331340551,0.4697431326,0.1163358986,0.7791193128,-0.4779369533,0.3048064709,-0.5940655470,-0.4552982152,-0.4650419652,0.0361061431,1.5899168253,0.0063533471,1.6877865791,0.0515951440,-0.9018155932,1.2319109440,-0.6424393058,-0.2568293810,0.6929336190,-0.3502320945,1.4825685024,1.3803684711,1.1104739904,0.6726384163,1.6660864353,-1.1913731098,0.4051263034,-0.3095752001,-1.2381680012,-1.6911195517,1.1668710709,-0.6490058303,0.4584015310,-0.9608908892,0.0266461428,-1.2123868465,-1.4942896366,0.1524978429,-0.6395063400,-0.3380450904,-0.9216715693,-0.0510670282,1.1863936186,-0.6247690320,0.3869996667,-0.5245535374,0.3170322776,-1.0178136826,-0.1742559820,-0.1370685846,0.8142974377,0.7342265844,-1.9699764252,2.2751204967,-0.3226063848,-0.5424374342,0.6009609699,-1.7587728500,-1.5937917233,0.9980217814,0.4808895290,0.5623027086,0.3096584976,-1.2413680553,0.0726389959,-0.2213159949,2.1800575256,-1.4602934122,0.0018683164,-0.1173354015,-1.0309307575,-1.3381360769,-0.7076413631,-2.1738369465,0.6837378740,-0.7091113329,-2.7662103176,0.7608048320,1.0504329205,-1.4428687096,-0.7895605564,0.7236565351,-1.1905863285,-0.6919526458,0.8573622108,1.5371603966,-0.9198681116,0.7844922543,0.6338860393,-0.4500072896,-2.0559315681,-2.0172803402,-1.2834616899,-0.3556898534,0.6204849482,2.3478055000,-1.3467277288,0.1222354546,-0.2214947045,-0.2462989539,-0.0867773294,0.6118643284,0.6414287686,0.4616425931,-0.1879353225,-0.3813198209,1.3266900778,0.4950915277,-0.8527886271,-1.9915175438,-0.0268161800,0.2655802965,0.3149074912,1.0536828041,0.8504412174,-0.7472555041,-1.5911126137,1.3834769726,-1.4433643818,0.6882103086,-1.4758917093,0.8962612748,-0.6082796454,-0.8149115443,1.3695408106,-1.9525241852,-0.5935515165,2.1671218872,-0.9892462492,-0.2221836448,-0.2219780684,0.9403944612,0.1978086531,-0.7817671895,-0.4124997258,0.3687230051,1.0968439579,-1.8594348431,0.0029549592,0.1101333052,1.5394915342,-0.0038964562,1.0981504917,-0.0400299132,0.2016086131,-1.3140232563,0.2941615582,-0.7528982162,-0.0452784672,0.7580948472,-1.3945977688,1.3409752846,-0.3101814091,-1.2464029789,-1.1343907118,1.7912290096,0.7197954059,-0.5015527010,-0.1126659065,1.1124942303,1.3593585491,-1.0211582184,-0.7661721110,-0.6488007903,-0.9884676933,0.7920768261,0.5087880492,1.3648190498,0.6742984653,-1.6158971786,-0.8027673960,0.2757093608,0.2329666018,-0.6251592040,0.0634803176,-0.1018172055,1.5068968534,0.6900904775,-1.7025721073,0.3553458452,0.3871901035,0.9579328299,0.7569516301,0.7862011194,1.3912926912,-0.1798933148,-0.3273005486,-0.3807692528,-0.6068280339,-1.0164443254,0.7183098793,-0.3550116718,-0.0208350029,-1.5521923304,-1.1644581556,1.0302523375,1.1733825207,0.2134277225,0.0292529687,-0.5484084487,-0.3583379388,-0.8931321502,-0.1975669116,0.2763205469,1.1366759539,-2.0308594704,0.3366666138,0.3184001446,0.4373573661,-0.8740926385,1.0525960922,-1.2406895161,-0.5679717660,-0.5852907300,1.1207735538,0.4359603524,-0.8621008396,0.2411166579,-0.1937544495,0.6315796971,-0.4637977481,-0.8728907704,-0.3243234754,0.3536755145,-0.2431924790,-1.2344973087,-1.1073101759,1.7516149282,-0.4201321900,-0.6599223614,-0.6240724325,0.0641648844,0.8778529763,-0.7815441489,0.8508049250,-0.8690682650,0.9813565016,-2.0868430138,-1.1037631035,-0.1131165251,0.0414229818,-0.8837306499,-1.4935542345,1.1044009924,-3.1893181801,0.5092691183,0.4799568355,1.3159337044,-0.0970403627,-0.2791163325,1.7901148796,1.5886393785,-0.3469516039,-0.9854775667,1.3777000904,-0.4683577418,1.6312767267,-0.5955067277,0.6797708273,0.6795912981,0.5310679078,-0.8304234743,0.7193893194,-0.0236661416,2.5271956921,-0.7473905683,-1.0720716715,-0.1273948997,-1.3011174202,-1.6902400255,-0.4170007110,1.1451983452,0.8875586390,-1.9904561043,-0.6132237911,0.0021884013,-1.0157800913,-1.2629107237,-1.6704556942,-0.9015039206,-0.7487605810,-0.0734295398,-1.4195762873,0.9139781594,1.6136165857,-0.3155820668,-0.5592501163,1.7205772400,0.1843333095,-0.2459741086,0.7138553858,0.9178287387,-0.3423841894,0.6098057628,1.5959429741,0.6128612757,-0.6838819981,0.6335126162,-1.2277721167,0.0185308941,-0.8606790900,0.1154111698,1.4965243340,-1.1527279615,-0.6795991063,-0.9856798053,-1.2678070068,-0.4434808195,0.0805942714,0.2353551388,0.0121626621,0.5561687350,-0.0758090466,0.1448151320,0.2649245858,0.7526773214,-0.2883499265,3.2922325134,1.2451647520,-0.6571530104,0.7045717239,1.0751260519,0.2896658480,-0.0684312060,-0.7031256557,-0.7291713953,-0.4636211991,0.5477852225,0.4574085772,-2.8637101650,-0.3515471518,-0.6543455124,1.0587671995,-1.0377566814,-0.1081912965,-0.7057687044,-1.2898498774,-1.6401636600,-0.0102215903,-1.6310093403,-0.6036027074,-0.3954981267,-1.0030182600,-0.6082266569,2.5081093311,1.6789019108,0.2176964432,1.2520422935,-0.4151733816,-1.2843372822,-1.0400305986,0.3440242708,-0.4483019412,0.6690663099,-0.7175396681,-0.1458407640,2.2244884968,0.1947859079,0.1055293828,-0.6040461063,0.8576923013,-1.5997809172,1.8376449347,2.8909277916,-0.5177230239,0.2298939377,1.8100821972,-0.5709523559,-0.5115388036,1.2967069149,-0.5621591806,-1.1462398767,-0.9591106772,-1.6882694960,-0.7014160156,0.6921666265,-1.1444196701,-0.1640264839,0.4573389292,0.5338413119,0.8252105117,0.1567942351,1.4680320024,-0.2286765873,-2.0002055168,-0.6564577818,1.9003719091,0.4424801469,0.4283055365,0.6784015894,-0.9360645413,0.5108249784,-0.0562780872,0.0913101286,-0.8051065207,-1.8382200003,1.4490640163,0.5964669585,1.4912917614,-0.3538664877,1.1519131660,-1.2095607519,0.6885273457,-0.0599056147,0.8238558769,-0.0441347621,-0.9308155775,-0.7122085690,-2.2147786617,1.1632386446,0.6279171109,-1.3401852846,-0.9253047109,1.6279819012,0.5150529146,-0.6503204703,0.1271840185,-0.1690019965,-0.5984864831,0.5934988856,1.3468483686,-2.3228442669,0.3811374903,0.0807556435,0.4608016312,1.1064083576,-0.9534149766,-0.5410642624,1.6721212864,0.3387215137,-0.5848330259,0.1684350818,1.1708821058,-0.0112401946,-0.0421408676,-0.0110325404,-0.0399069786,1.8626705408,-0.3295717239,0.2178692967,0.3128709197,-0.6914327145,-0.0489474349,-0.4623219073,0.6858608127,0.4037072062,-0.4837623537,-1.6117572784,0.0941191539,-0.6782262921,1.2615525723,-0.2805505693,2.6711010933,1.3798089027,-1.1973799467,-0.4020443559,-0.5639002919,1.5455411673,0.6903855801,0.9709954858,0.0853693932,1.2079653740,-0.1136911586,1.1985101700,-0.8023996949,0.8236210346,-0.7027028799,-0.5922062993,-2.2783963680,-0.3009352088,-0.7893054485,-0.2613692284,1.8687489033,0.1451711506,1.1809588671,1.4143635035,0.2772610784,-0.3749769330,0.6385892034,0.7431727648,-1.3622537851,1.3739572763,-0.9690158963,1.0907326937,-1.2023899555,1.2161438465,1.5248703957,-0.1389713138,-0.3804358244,-0.1093302220,0.5503053069,-1.3575862646,0.4582281709,-1.1639021635,-0.3647545874,-0.7115260959,1.4336994886,0.2221960723,2.0658452511,-0.2943881452,-0.7061772346,0.6280207634,0.5662272573,0.3857337832,-0.4284617901,-1.3776395321,-0.6398698092,0.4830209613,0.9864068627,-0.7793473601,-0.4055784643,-0.5901540518,-1.5036782026,2.4848642349,-0.3595902622,0.4562184513,-1.2775880098,-0.4926495552,-1.4293605089,-1.3942863941,0.7871758938,-1.9546544552,-0.9582464099,-0.8009232283,-0.3317953348,0.5323982239,0.4935196638,0.8553711176,0.1533751488,0.9288468957,0.1826938540,0.8980613947,0.4672872722,-0.0300932415,0.3488621712,2.1993985176,-0.3082002103,0.6237960458,-0.5904917717,-0.5733503699,-1.4770421982,-0.3424594402,1.8895410299,-1.0194392204,-0.7236206532,-1.3778822422,1.0129799843,1.1487203836,-1.0671883821,0.8054333925,-1.6088992357,-0.9679784179,0.4632321298,1.2936443090,0.6811715961,0.0065504359,-1.3251696825,-0.5823521614,0.3334719539,-1.1553093195,0.6754829288,-0.6283892393,0.0070697991,-0.1301544905,0.0000159070,1.6803572178,1.0456736088,-1.2322541475,-1.7359474897,0.8063043952,-0.3912761509,1.4771649837,-0.3736453354,1.5715459585,1.1237367392,-1.5193575621,0.5520567894,0.5154913664,-0.0857104436,-0.9226989746,-0.1511355489,-0.1532225013,-0.4101878107,2.1041259766,-1.2773672342,-0.4122236669,-1.2621785402,-0.6445494890,0.2983115911,-0.4472069144,0.0983226672,0.2284848690,0.4287489355,-0.2973191440,-0.8167265654,1.2091214657,-0.4534170032,0.9312779903,-0.3093512654,-0.3528625667,-0.0741263479,1.0887343884,-1.2669620514,0.3354581296,0.0044241310,0.3022244275,1.1900383234,0.2975670993,1.4324852228,0.6217397451,-0.5294061899,0.4970742464,-0.5087625384,0.1304465979,-0.1666449457,0.5193110704,0.8491689563,0.5580003262,-0.5960376263,2.3947246075,-0.5828321576,-1.2493512630,0.7954925895,-0.5065029263,-0.5937213898,0.9579040408,-0.0251192842,-0.5465407968,1.1391458511,-0.4674501121,-0.1967873126,0.2859996259,0.9837669730,-0.9668199420,-0.1133453920,-0.2571675479,2.5318741798,-0.5155376792,0.8728454709,0.0778044462,-3.1305611134,-0.4914603829,1.1896528006,-1.4559942484,0.3755713403,-0.5113667846,-0.4030328989,-0.8139418364,1.3834196329,-0.1454866529,0.2846169770,1.1209895611,0.8712860346,-0.0718860626,-0.6956607103,-0.4459330440,-0.4794711769,1.5473222733,0.0038444141,-0.9808133841,0.2412267625,0.9256925583,-0.5301594734,-0.4780997336,-0.6812683940,0.5242022872,0.1786995083,0.8638377786,-0.3517528772,0.5365935564,0.5407190323,1.1510950327,-1.0237739086,0.6385636926,2.2565796375,0.7124504447,-1.9051090479,0.5709059238,1.9324462414,-0.8584792018,0.8580051064,0.2227552831,-2.1613814831,-0.2940069735,-0.1814101785,0.7617862225,0.6633594036,0.1448772103,0.4526188672,1.6508759260,-1.7932395935,-1.7927554846,-1.2987227440,-3.7009484768,1.4530611038,0.2657386363,-1.1115087271,0.3476705849,0.9187952876,-1.2118660212,0.9229725599,1.2597514391,-1.9153442383,0.4390523732,-1.1919585466,0.2263162732,0.8045522571,-0.8975812793,0.1102162153,-1.7435343266,-1.5475306511,0.1274931878,2.3257565498,0.2937721014,-1.1089141369,0.5591292381,-0.3039319515,0.7630262375,0.2723177671,-1.6435691118,-1.1236854792,0.1609627306,0.6847237945,-2.4690279961,0.0209366865,-0.5310238600,0.4430907667,-0.3956150711,2.5748353004,0.9656668305,0.5004914999,0.4974248707,0.1869066209,-0.3793111145,-0.5843949914,1.0160140991,1.0422772169,0.0353021547,-0.2838065624,2.4264302254,0.1781947762,-1.4493917227,-1.2831250429,-1.2559127808,0.8513959646,-0.4708440900,-0.9816243052,-1.4453076124,1.0640504360,-2.4597752094,2.4951465130,-1.3210877180,-0.3973611891,0.6279271245,1.2438503504,-0.8696066141,-1.6361762285,-0.0915040895,0.5303424001,0.1272949874,0.6879992485,0.6507039070,1.6750425100,-1.7682852745,0.4391796291,0.0041834023,-0.2630576193,-1.8533036709,-0.8588609695,0.1978735924,-0.7241343856,-0.4095613658,-0.6204192638,0.2809041440,0.0266254898,0.5631239414,-0.0666484684,-1.3585243225,0.1720818728,-0.9857338667,0.6432245374,0.4694710672,0.3492645621,-0.5567824244,-0.4697691798,-0.4117129147,2.1153721809,0.5442541838,-1.6541137695,2.1774716377,-0.1963181496,-0.8331007361,0.7331581712,-0.0479035601,-0.4869109094,0.6976183653,-0.1689549834,0.6171053648,1.2108881474,0.5635103583,-0.8354082704,1.2755782604,0.9359452128,1.2179498672,0.2265103161,1.6606619358,0.5011734366,0.1251170188,0.2605842352,-1.5394775867,0.4511664212,-0.2313937992,1.1197661161,-0.1140006483,0.3820356131,1.3873690367,0.6571901441,0.5457989573,-0.6308066845,-1.1354978085,-2.4026119709,-0.3027979434,-0.5020709634,-0.2321306318,-0.0201238710,0.9409797788,0.7256790996,1.3103921413,-1.0225174427,0.8154883385,-1.1430218220,0.5008414984,0.3574302495,0.0495680012,1.5883718729,-0.1069783717,0.1745323092,-0.0496963039,1.0220882893,0.4006874859,-1.0913971663,-2.3291058540,-0.6900204420,-0.9169560671,-1.1179387569,-1.0036914349,0.2173535079,1.0790767670,0.0816364065,0.2541635036,-0.8011046052,0.4594263136,-0.6509816051,1.1677899361,-0.3477513790,0.5618755221,1.1921788454,1.5922267437,-0.2455349416,-1.0317528248,0.2817627192,-0.8351853490,2.2162134647,0.3737241030,-0.9866889119,-1.3697648048,-0.1978318542,-1.4279685020,0.1537464261,1.1027641296,-0.4549758434,1.3040695190,0.9517257810,1.3341605663,-0.5766361356,0.4542465210,0.6612707376,-1.2149206400,0.7250176668,1.0353204012,-0.3413012028,-1.3613491058,0.4005934596,-0.1110523567,-0.0788928047,1.1674675941,-0.3902478814,0.8044789433,0.7681032419,0.0321332254,-0.2218496799,-0.8551516533,-0.4030755162,-0.0721132234,-1.2544465065,1.4844565392,-0.5042630434,1.1852766275,-1.2150322199,2.2204818726,-1.1828657389,0.7846149802,-1.9904559851,0.1393995136,0.6561467052,0.6043061018,-1.0907354355,-0.7484697104,-0.7126812339,0.8230614066,-1.3216540813,0.1326915920,1.2171856165,-0.4447000027,0.8073532581,0.6256611347,-0.0607976690,0.7808696032,0.3649677634,0.5778753161,0.4065142274,-0.5495318174,0.4771209359,2.5231893063,0.6165393591,-0.5275948644,0.5816348195,0.5120906830,-0.7348868251,-0.4592056274,0.4749583006,1.1358423233,0.6339197755,1.2536251545,0.0191743113,1.3371372223,0.6908062100,-1.5238791704,0.7582221627,-2.0854206085,1.0246943235,0.3916818202,-0.3441234529,-0.3393303752,0.5980219245,1.7809047699,-0.0322760791,-0.5638660192,0.7236633301,0.1639522463,1.5012469292,-0.3719091415,1.1622062922,2.8788545132,0.0829108357,-0.0003996070,1.1071796417,-0.9313130379,0.1179228798,-0.6248297095,-0.6864803433,0.3658074439,-0.1976805627,-0.7697430253,1.1433596611,0.4378886223,1.0920422077,-0.1473139822,-0.4550720155,0.8509523273,-0.4368683994,0.1370265186,0.9994106889,0.0470677242,-1.2024868727,0.7732259631,0.7193604708,-0.4950317442,-0.6972939372,-1.1340928078,1.4360136986,-1.0777835846,0.6327699423,-0.7165985703,-1.7260651588,0.7511957884,-0.8365247846,1.4378730059,-0.2593916655,-0.7531266212,-0.0018816765,0.2780501246,0.3728078902,0.5840899348,1.1903779507,-0.7974692583,0.6395269036,-0.1412059069,0.5012361407,-0.1481624842,-0.0530277118,0.2532734871,0.7361589074,-0.5505169630,1.3500739336,-0.7229986191,0.5972332358,1.5588985682,-0.9929527044,0.6563365459,2.0401813984,0.2912432551,-1.0593951941,-0.7136363983,-0.4101233482,-0.8217135072,-0.9647257328,1.5899295807,1.4830676317,-2.0082218647,0.6201471686,0.0921110585,1.0209305286,-2.2872138023,0.2827239335,-2.0732119083,1.1393668652,-0.8216959834,0.2826004326,0.0577638298,1.0376316309,-1.2894252539,-0.5568271875,0.3712979555,1.0854558945,1.6734513044,-0.2837608159,0.7808902860,1.2088090181,-0.3496015966,-1.8581924438,-0.3988831639,-0.4860283136,0.5964819193,-0.1913231909,-1.8144276142,-0.9861682057,-0.9875866175,-0.3508193493,-1.0703758001,0.9739978313,1.7451748848,1.1622909307,1.2399636507,0.1838206500,-2.1057317257,-0.3868809640,-1.4580152035,-1.9583094120,-0.5214228630,-0.8149047494,-0.2598052323,-0.0679654256,1.5236089230,-1.8181490898,0.7602464557,0.2036284059,-0.6710840464,-0.4183948934,1.6409194469,0.0934851244,-0.9035621285,-0.1599463671,-0.2006375492,-0.1909182221,-0.9695960283,0.5366060734,0.0499979891,-0.5023054481,1.6040503979,-1.2374203205,-0.2361531258,-1.3638973236,1.9122620821,-0.8687421679,0.5375559926,0.4242394269,-0.5340645313,0.7021860480,0.2912759781,-0.4078489244,-0.0786173418,-1.5945433378,-0.3502337337,2.0544710159,-0.1928384900,0.9104574323,-0.0862179101,0.6111246347,-0.3534440100,0.5634724498,0.4857985377,0.2631002367,1.4814050198,1.1656149626,1.1763496399,-1.2619029284,1.0174994469,0.8297733068,-0.5920416117,1.5649130344,-0.7932690978,-1.9636081457,0.0073007345,1.7777563334,0.4939030111,-0.8862183094,0.5388250947,2.3175821304,-0.6583781838,0.0406383574,-0.6774467230,-0.0744541883,-0.6628022194,-0.7723457813,0.8113358021,-0.0109207612,-1.4630174637,0.8977974653,0.0017468558,0.8730773926,1.8256112337,0.9446329474,1.9473477602,0.5063759089,-0.2418232411,1.6875723600,0.5409396887,-1.7663731575,0.7723557353,0.7904483080,-1.1151059866,0.6893996000,0.0964727402,0.3555314541,2.8903863430,-0.2023495734,1.1651166677,-0.1074468717,-0.4425264895,0.3537662923,-0.5301949382,-0.1266164333,0.1925617903,1.4034749269,-0.4170812666,0.2439171225,0.6235732436,0.0569755919,0.4600847065,1.2430694103,-0.2150766850,0.5950499773,0.1923431158,-0.1020159572,-0.9160646200,0.8229887486,1.0482641459,0.5558660626,-0.7286831141,1.7109791040,-1.3896939754,0.7022241354,0.7677382231,0.8328258991,-0.7697517872,0.6147429943,2.0839247704,0.7161874175,-0.3919250667,0.9053443670,0.0932821408,-0.7115653157,-0.2126543075,-0.8772642612,-0.1721208841,1.3694014549,0.2511317730,0.1415636986,0.0112932771,-0.6726903915,-1.6037570238,-0.5378059745,0.0845245272,0.7646923065,-0.2101514488,0.9166517854,0.4953337014,-1.5049014091,1.1143501997,1.6012240648,0.6021217704,-0.9676260948,0.5672973990,-0.0398906879,-0.2725612223,0.6513987184,0.5207162499,-1.9729640484,0.8367348313,1.0528236628,-0.4983050823,0.5411375165,-0.6223208308,-0.5388869643,0.9614911675,-2.0136291981,2.0114109516,0.2237331420,0.7709437013,0.1642037779,0.9776116610,-0.2966648638,-1.1799397469,0.7032052279,0.0894018561,0.7504652143,0.3706242144,0.5047916770,0.6028758287,0.4940436482,0.8593719602,0.5868232846,0.1310377866,-0.3590817153,-0.8620396852,0.6448566914,0.6952871084,0.9641913176,0.1289675683,0.9945142865,-0.3077834547,-2.1486518383,1.8851884604,2.6745195389,-0.3878851533,0.3051368296,-1.3988252878,-0.6323857307,-0.8161635399,-1.3922702074,-0.6827468276,-0.2562257946,0.5322270989,-0.7437602878,-0.2868638039,0.7098515034,-1.4383655787,-0.6667670012,-1.3716266155,-0.1098348424,0.7378181219,-0.0879292637,1.1370954514,1.7925657034,-0.2012682259,-0.2694388330,-0.4670928419,-0.5821979642,-0.7644075751,0.6695444584,0.0306869764,-1.6800422668,-1.6340225935,-0.4223179817,0.7865099311,0.1305941641,-0.7552067041,-0.0254859049,1.9027297497,-1.3717647791,0.7811303735,-0.2215402573,2.1291007996,1.1312514544,-0.2409127802,0.5062365532,-0.5534172058,-0.3004655242,-0.5346511602,-0.8108330965,0.3282672167,-1.0185667276,-0.3533863127,-0.8215651512,0.2005594671,1.8420407772,0.3635246158,0.7861365080,-1.0597175360,-0.1873623729,0.7724383473,1.2314850092,-0.7266256213,-0.2569041550,2.0182263851,0.4881033897,0.3779078424,-1.1142752171,-0.5767669082,0.1944286525,2.3854238987,0.7869626880,0.8664147854,-1.8784008026,-0.5955214500,0.6883810163,-0.6199914813,-1.1991696358,1.2152301073,-2.4070537090,-1.0307068825,-0.6643091440,-0.5183378458,-0.4899657965,-1.8663284779,1.7655661106,-0.7547045350,-1.4823474884,0.0760180503,-0.1749891788,-0.3796023130,0.0475712158,1.7384783030,-0.2914048135,-0.1437018216,0.1325060278,-2.3676879406,-0.2258290648,1.6418195963,-0.7734972239,0.7461740971,0.6074157953,0.4117653370,-0.6067041159,-1.6472831964,1.7200328112,0.0232646484,0.4374954998,1.2455363274,0.5894487500,-1.7584183216,1.0120782852,1.0967348814,0.0198814012,0.3985802829,0.6743020415,-0.8145176768,-0.7799610496,0.3777892590,1.0087720156,2.0344851017,0.0204913002,-0.0241909269,-1.8100771904,0.7795275450,0.2824576795,-0.6737608910,1.0618784428,-0.3735115230,-0.1141227409,0.0508635230,0.1573044062,-0.7637298703,0.1603048593,0.1740360856,-0.0722323060,1.0070261955,1.3884991407,0.5985660553,-0.5918496847,-2.4490859509,0.3502865136,-0.7734159231,-0.7966606617,1.0198645592,-3.6166062355,1.3282010555,-0.9895777106,-0.0881013423,-0.5323204994,-1.1653339863,-0.9234332442,0.1528675258,0.6556922197,0.2687607110,0.2779617310,-0.4949930906,-1.0904607773,0.9958393574,0.6449023485,-0.0139402952,-0.6758316755,0.0389272645,0.2130638659,-1.5142279863,0.5219237804,0.6738876104,0.0340359621,1.2885986567,0.3472016752,-1.3768179417,-1.1709387302,-0.1141757742,0.3047106266,0.3039871454,-0.5379764438,-0.0836184621,-0.8551713824,-1.5300897360,-0.6361967325,-1.9284130335,1.1020956039,-0.2246899605,0.5269551873,-0.9494376183,-0.9701120257,0.7764113545,-0.2850833535,0.5099344254,-0.1375637800,1.1417900324,-0.2920076251,-2.0219731331,-0.7772913575,0.0708815753,-0.3063801825,-0.4740124345,-0.2298611403,0.7288610935,0.2877394259,0.1773329675,0.4523156583,0.6529164314,-0.7750585675,1.6021527052,0.8939141631,-0.0089290179,0.2659767866,0.1753713489,-0.5379931331,0.2873095870,2.2902197838,0.9296517968,0.3582972586,-1.6173806190,1.1959173679,0.3798225224,0.3370334506,-0.6950842142,-0.1877526492,-1.0495693684,-1.9517418146,0.9486764669,1.3959928751,-0.1565124840,-0.8272699118,-0.6829131842,-2.2610342503,0.2792412639,-0.8317098618,-0.0329254083,-0.0633183643,0.0907527655,1.6180012226,0.1789626926,-0.5308724046,-0.1154055297,2.2669715881,1.0755400658,-1.2605806589,-1.3714374304,0.6071957946,0.6227938533,-0.2147837281,-0.3323607743,1.2683321238,0.0792714432,-0.7269679904,-1.4837813377,0.1482709199,-0.8914306164,-0.3136545420,0.8342787623,0.5124506950,0.3868113160,0.6767075062,-1.5070546865,-1.1736109257,-0.4428335726,-1.2228515148,1.6584920883,0.8860940933,-0.3657595515,0.2537226081,-1.5250725746,0.7131353021,1.0954420567,-0.4071093798,0.6125251055,0.2761376500,-0.2350142002,1.3670639992,-0.3232049346,-0.7421479821,1.3723272085,0.1204612628,-1.4851864576,0.3227433860,-0.8716908097,1.0561125278,1.1365944147,0.4882908463,-2.3186235428,1.2475165129,-1.0494215488,-1.1936898232,-0.8012831211,-0.1370985806,0.7666711211,0.1403384358,0.3451739848,0.7921397090,-0.0043549207,0.4684241712,1.0302612782,-0.1617009193,0.5881261826,-2.0054824352,0.3759513497,1.6423543692,0.8723756671,1.5837312937,1.2748030424,-1.9394344091,-1.3062525988,0.8021035790,1.2067923546,-0.6591643095,1.4958468676,1.4278705120,0.2870118320,0.2882831693,-0.9594781399,0.1612415165,1.7277601957,0.8202464581,1.2654410601,1.6296563148,-0.4528054595,1.2124234438,-0.9555593729,0.7217754126,1.3135437965,-0.9282189608,1.1860563755,1.3845413923,-0.0372342989,-1.0035890341,0.7181358337,2.2787775993,-1.8576666117,0.1417283565,1.1989032030,-1.0669670105,-0.5698820949,-1.3290554285,0.0011848081,-0.6872947216,-0.0984507203,0.0053924564,1.8844401836,0.6896256804,-1.1454101801,0.2944171727,0.5787634254,-1.6376229525,1.6078158617,-0.6052874327,1.0842406750,-0.6343843341,1.1234267950,0.6614363194,-0.5274475217,-1.6983145475,0.1424814761,1.5018779039,1.6019635201,0.2406056076,-1.3378336430,0.3889307678,0.7279734015,-1.4437752962,0.2451101989,1.3260084391,0.4043070674,-0.6334703565,-0.0905047655,2.2889361382,-1.6737362146,0.4014829993,0.9645870328,-0.3940742314,2.2201044559,-1.1043834686,1.0660539865,0.6407681108,-2.9392998219,-0.1941942126,0.0725432858,-1.6567014456,-0.9918910265,0.0521232933,0.2113792449,1.2878824472,1.0472283363,-0.0297677517,0.6040073633,0.8790017366,0.5193853974,1.0043952465,0.1468016207,0.2064592689,-0.1191236898,-0.7948093414,-2.2682187557,0.3695141971,0.0789367929,-0.2442376614,2.2216601372,2.7800517082,-0.0808964223,-0.9864557981,0.1934024394,-0.1443898380,-0.5223660469,2.2616927624,-0.0752847716,0.6587827206,0.4554153383,0.4489373267,-0.7989477515,-1.1259423494,-0.9596457481,1.1747367382,0.0612658411,-0.9934889078,-1.4369478226,0.4548711479,1.2188794613,-0.8638844490,-1.6974016428,0.3228982687,0.4121471941,-1.0056366920,-0.4581864774,-1.6678930521,-1.3405390978,0.4931705296,-0.0594159402,-0.9209959507,-0.5359746814,-1.2050573826,-0.2416513860,0.0205140915,0.8051583171,-0.3039194643,0.4501983523,1.6569852829,0.8124082088,-0.2882144153,-0.0287091434,-0.8580284119,-0.5605448484,1.5844684839,1.6319321394,0.2433615923,1.8722686768,1.3541325331,0.2546465099,0.7951636314,0.4162734747,0.7153671980,-0.5670320988,-0.4803200364,-0.4373582602,-0.8799190521,0.5002053976,-0.4195810854,1.4329137802,0.7451282740,-0.2605960965,-0.1553190053,-0.1571091563,0.5476624370,-0.5343143940,0.3311653733,0.8613076806,0.4169470966,0.1481061727,-0.9566766620,0.3370350003,-1.6706675291,0.6576215029,1.1566696167,-0.2248429358,-1.4964891672,-1.4325475693,-0.4104234874,-0.0051225480,0.2184714079,0.8567622304,0.0752849728,-0.5590589046,0.0686668381,1.1503990889,1.2555845976,0.8356750011,-1.2136638165,-0.6048707366,-0.0624855757,0.0132966116,-0.0085763428,-0.8367882371,-1.0246938467,2.9996769428,-0.2250829041,-1.3752338886,0.4163417816,1.5430538654,0.8278558254,1.0882321596,0.6639254093,0.0291860960,-0.6185283661,-1.1871991158,0.5030259490,0.8486614823,-0.4215537012,0.5474107265,-0.1873566657,-0.5774893165,0.9267744422,-0.6131139994,0.6064761877,2.2037541866,1.8484804630,0.2465688884,0.4237998426,2.8766086102,-0.6650875807,-0.2597856522,0.4639374614,1.1446344852,-0.6116654873,-0.0218625776,-0.4358089566,-0.5646321774,0.5649581552,0.7810892463,0.7661207318,-0.0211674664,1.7043101788,2.2350108624,-0.1355992109,-0.4077370465,1.7714235783,-0.8152344227,-0.3246816397,0.2365811616,-0.8649201989,-0.8507444263,-1.2081509829,0.7433677316,-1.2326159477,0.6326366663,-0.6106397510,0.0574978702,-0.7415626049,0.9871259332,2.2205648422,0.6921710372,-0.8000081778,0.9471917748,-2.2180683613,-1.0951820612,-0.4547932744,0.7424654365,1.8997622728,-0.5095831156,1.2237663269,1.2456455231,-1.2396967411,-0.3688427806,1.2640622854,-1.0342392921,-1.4049681425,-1.5210585594,-1.0076230764,1.3294607401,0.6158753037,0.7308965325,0.0848912075,-0.1969574690,-0.0819591358,-0.3404512405,-0.6221250296,-0.7510188818,-0.4768586755,1.2083463669,0.4217658043,1.4242808819,0.0852572173,-0.3053416908,0.9350500703,-0.4598187804,1.8786497116,1.3874312639,0.5443605185,-1.4051083326,0.1745427251,1.4360253811,-0.9045711160,0.0467361361,0.5182443857,1.4112025499,1.2951264381,-0.7757521868,-0.2411681116,-0.4241921604,-0.5597399473,-0.6066641808,-1.1611486673,0.2278152853,-0.0413084850,1.1212860346,0.6273789406,-1.0726985931,0.7191551328,1.1449415684,-0.5668084621,-0.8096838593,0.2828166783,-0.6697654724,0.0814880952,0.4383083880,-0.3998520970,0.6673691273,-2.2718055248,0.4157564938,-1.9803010225,-0.4021820128,-0.9504793286,0.5314682722,1.3823496103,-0.1732390821,-0.3971373439,1.3028131723,-0.8584709167,0.7786294222,1.4142960310,-1.2077190876,0.3213968873,1.8558900356,0.2112760097,-0.3709301651,1.1207209826,1.1596553326,-0.5884460211,-1.1001182795,0.3257922828,-1.1892958879,-0.7330425382,-1.5030636787,0.2551620305,0.2792249322,-0.3615036905,-0.6149381399,-0.5369812846,-1.1995630264,0.5322521925,-1.3133509159,-0.6877193451,-0.0793563500,0.7657913566,1.0005102158,-0.1015864313,-0.6221787930,-0.6660726666,-1.0681372881,1.1551531553,-0.1612300426,0.4519759119,-0.8223438859,0.7364921570,2.1589651108,-0.6829474568,-1.0340731144,-1.4623531103,-0.8314996362,0.9340252876,-0.1944855750,0.0987237468,0.0290169753,-1.8448588848,-0.7846073508,-0.0732088313,-1.7333260775,-4.0291380882,-0.5306329727,0.7409014106,0.2832567990,-0.9075359702,0.1050713211,-1.2936125994,0.9663115740,-0.5140835047,-0.5231055021,0.4298277795,0.8415327668,0.3716501296,-0.0323132835,-0.6347941160,1.3319286108,-0.8133419156,-0.9136698842,1.3833984137,0.8047218323,-0.8619208336,-0.9462947249,0.1797300130,2.6600546837,-1.1597884893,0.4171127379,-1.4330574274,-0.2685092986,-0.5563176870,-0.1373858452,0.2979919016,-1.6659470797,0.9449476004,-1.2770717144,-0.1901160926,-1.1533769369,-1.0791780949,0.9957335591,1.4861640930,1.0744752884,1.2719250917,-0.4285410643,-0.7043931484,1.0934284925,0.3522428274,0.3764531016,-0.3339338601,-1.4555534124,-0.4577522576,0.2179024220,1.1649961472,0.9591401219,0.6655773520,0.3939776421,0.5124578476,0.2843569219,1.3237973452,-2.1637573242,1.0497915745,-0.0111749861,0.5166006684,-1.2268714905,-0.1555034965,-0.0298048109,-0.8875045776,0.1314747632,-0.3267731369,-0.5512117743,0.6083897948,0.6339176297,-0.8001993895,-1.3872141838,0.4129168987,0.6903015971,-0.8204827309,-1.4886994362,-0.3166840076,-0.0989368260,-0.5029759407,-0.2094892561,-0.2207775265,0.6260372400,2.3226847649,-0.8254155517,-1.2173273563,0.4000590742,-0.1477404535,-0.2987808287,0.7859148383,0.5849666595,-0.2389931232,-0.3345387280,-0.4545707107,0.0136067895,2.3920662403,-1.5474188328,-0.0663272217,-1.2421488762,0.7367187738,-1.2968086004,0.4109822512,1.8854326010,-0.3313354552,-0.7640479803,-0.1868978590,-0.2272865027,0.1732350737,0.0523185283,0.1169780940,-0.2806419432,2.2475368977,0.2511340380,-0.5130397081,-0.5074169040,1.0990157127,1.2466640472,0.3869113028,0.3809750080,1.1946322918,-0.3047500253,-0.5252722502,0.0020444905,-2.1285502911,0.2623390555,0.5451027155,1.8167289495,-1.1404950619,0.5926309824,0.5969594121,-0.0148727661,0.0002652447,0.4641184211,-0.4436666667,-0.6841523051,0.5644008517,0.1762598157,-0.3095212281,0.9205504656,-0.0046450230,-0.4804340601,0.5649686456,-0.3629473150,0.1853141338,0.6242626309,-0.6242429614,0.3195052743,-0.2832978666,-0.7747485638,0.6012946367,-0.1605652124,-0.4696919918,0.7488157749,1.0230870247,0.5574153662,-0.6297346950,-1.2690787315,-0.6727031469,-1.1326258183,-0.9907282591,-0.4507670999,0.4559905231,0.9178841710,-0.6517288089,-0.4528707564,2.0510644913,-0.4466638565,0.3832630217,-2.3713276386,-0.7958715558,1.5951139927,-0.6162417531,-0.7024154663,-0.7358942628,-0.0514691435,-0.2618040740,0.3440458477,-0.2452831417,-1.1451121569,-0.2014667243,0.4369078875,0.3151161969,0.4121712446,0.2650465369,0.9768393636,0.9651262760,-0.1851613075,0.7949992418,1.2735664845,0.9264928102,-0.3236273825,0.4478474557,-0.3741316497,-0.1214300245,0.0958605856,-0.4238029718,-0.4743156135,-0.8259438872,0.7757176757,0.3365464211,-1.4995009899,0.7254462242,0.8834500313,-0.6244534850,-1.6591092348,-1.0582569838,-0.4764253795,-1.7733248472,0.9393494129,0.1969945282,0.1639864594,0.1929222494,1.4174526930,-1.1465125084,0.8462514281,0.5178537369,-1.0700050592,1.4103268385,0.2136932462,1.4934782982,1.8879579306,-0.7683445811,-0.8442191482,1.9063091278,-0.6955130696,1.6429194212,-1.1053818464,0.1641834229,0.1306985021,-0.1009309143,-0.1554664522,0.6429009438,-0.3547316790,-0.3141651452,-0.7517613769,-1.2651112080,0.4944086671,-1.7528989315,-0.0695738867,0.3000741899,-1.3996940851,-1.2547707558,-1.1402056217,-0.5491457582,-0.1278792620,0.6167907715,0.4023316503,-0.2770686746,0.8350918889,-1.2336196899,-0.8996614218,0.8900222778,-0.1889329702,1.2801160812,0.6478344202,-0.6443380117,0.3230400383,0.5593442917,1.1015638113,-2.2827229500,-0.5276812911,-0.3871492147,0.8352118134,-0.2477561980,-1.7110137939,2.6469244957,0.3301985562,-1.3280184269,-0.8027424216,-0.7288699746,-0.8320157528,0.1406433880,0.0071848044,0.6772457361,0.7906083465,1.5656526089,1.8632999659,1.4107118845,-0.1728944927,1.5014334917,0.5151723027,-0.5827595592,-0.6851282716,-1.1576546431,-0.7370390296,1.1400220394,0.1113723516,0.8906426430,-0.1768481135,1.7654592991,-0.0840447322,0.6247481108,-0.9882045984,1.0037338734,0.0724427253,0.1596299112,-0.5648909807,-1.0839179754,-0.5491756201,0.8615249991,-2.6529829502,-0.5975295305,-0.2969869673,0.8291987777,0.9888102412,-0.0241858158,0.0042725853,-0.6767337322,0.4008062184,-0.1150729880,0.6527836919,-1.3201049566,0.5537902713,-1.0040954351,-0.8293229342,0.4181952775,0.2711547315,0.7081342340,-2.2100968361,0.4100460112,-1.2368681431,0.0858222991,-0.6589938402,-0.0142544145,1.3100295067,0.4607637525,-0.3612421453,2.7282576561,-0.4968651235,-0.4072162211,0.4305685759,-0.9169256687,1.4734205008,-0.6685152650,-0.8737441897,-0.5534303188,0.5200399160,-1.1848164797,0.3177312613,0.0415630788,0.5504212379,1.3617442846,0.5164669752,-0.0615786836,-0.6427606344,0.1296616346,0.3920331001,0.2797629535,-0.7505016327,0.0564294457,-0.1437963694,0.2603136599,-0.9009698629,-0.2277601510,-0.7939273715,0.3479827642,1.3618816137,-0.5092176795,0.3851687908,-1.3853656054,0.7346545458,0.5953921676,0.6145576239,0.5108073354,-0.7996370196,0.2773365974,0.2169533074,1.1366590261,-1.0889068842,-1.0152673721,0.7809972167,0.7224917412,-1.3904248476,0.2733822465,0.6747696400,-0.0467090495,-1.1458916664,0.7344310880,1.2709969282,1.0786265135,1.3192250729,-1.7286123037,1.0670614243,-0.0010136778,-0.5207394958,-0.3519857526,-0.0657513589,1.2044017315,-0.4093344510,-1.0834403038,0.0430439971,-0.1649459302,-1.7983412743,0.6118800044,-0.7838023305,1.0087105036,-1.5372934341,-1.0053912401,0.7615340948,1.9778778553,0.9270530343,1.1736884117,0.0775798485,-0.4577569664,-1.3965622187,1.8189158440,-1.9773858786,-0.7674823403,1.9165551662,1.1599441767,1.7834349871,-0.1174152419,0.9704736471,-1.1975587606,-1.5968848467,-1.7459049225,0.5906978250,1.1235213280,2.0732831955,-1.0014953613,1.6119662523,-0.4356044829,-0.1917356253,0.7411944270,0.5390760899,0.4717051387,-0.6492152214,0.8157361150,-1.8203171492,0.2394956350,-1.0516985655,-0.1302240044,0.4464549720,-0.8567866087,-1.8950551748,0.0301094223,-2.3413836956,-0.9489056468,-0.9709588885,0.1027731523,0.6144888401,1.4732381105,1.7237547636,-1.2133656740,0.1944560856,-0.0028214678,0.4646196365,-0.4514550865,-1.0959115028,1.0776283741,2.0255107880,1.2845118046,-0.0877527371,-0.5224267244,1.7399580479,0.7644951344,-0.8440381885,0.5369064808,-0.7958087921,-0.0592793599,-0.6017829776,1.6896573305,-0.6590547562,-1.0762586594,0.4362809658,0.0668928027,2.0457201004,0.5018579364,0.5019522309,-1.1521987915,-0.2816174030,-1.7676477432,0.0686004385,0.5971288681,1.5740783215,-1.5005308390,0.2959667742,0.0992885381,-0.4789198041,-0.4450925291,1.6048885584,1.9666018486,-1.5215646029,0.6102808118,-1.0968976021,1.1952879429,1.0654774904,0.0481246337,1.0292104483,0.6108282804,-1.9799226522,-0.1822997779,-1.0944604874,0.3795200884,0.6275728941,-1.0811973810,0.5579342842,1.4074038267,0.2341215163,-1.9398125410,0.1486764103,-1.7583855391,-0.8627243042,0.8016073704,0.2244357616,-2.3210380077,-0.1822131872,0.2372455597,-0.0160580892,-0.6138968468,0.2037782669,-1.0922092199,1.6620970964,-0.1207506806,1.4912840128,1.9458825588,-1.0110816956,-0.3563345075,-0.7647183537,0.3050349653,-0.0155192744,0.8703370094,-0.2007468790,-0.0845041946,-0.2028828859,-0.7978484631,0.1054977104,0.3118167818,-1.6269580126,1.1409548521,0.9135065079,0.1632136852,-1.0845395327,-0.8973467946,-0.1036828682,-0.3324064910,1.1789542437,-0.3770294487,1.5620265007,-1.3538585901,0.1679062247,0.1029169038,-0.4538665116,0.0385230370,0.7132785320,1.3319801092,0.2151621729,-0.6791537404,0.0503540374,-1.7433155775,-0.2129102945,2.3486294746,0.6435081959,0.0417948477,0.4045048654,0.5760819316,0.2136069536,1.5347999334,-1.6873236895,0.6115571260,-0.0327798501,-0.5411595106,-0.4453768730,-2.0417563915,1.9538553953,1.5702822208,0.9667896032,0.0068834368,-1.4329059124,1.7121027708,-1.2107728720,0.8673722148,-0.0087148799,-0.2151390463,0.1782071441,-1.7905542850,1.1115261316,1.0436437130,-0.8217792511,-0.8795315027,-1.5809032917,0.3619697690,1.7345861197,0.5589722395,1.2194062471,1.2847113609,0.7623335123,-0.4450575113,-0.5541297793,2.3819768429,1.0045148134,-0.2210227102,0.0310857967,-0.3054305315,-0.2346151024,-0.2350860834,-1.0135045052,-0.4001455605,-0.4735128582,-2.3997213840,-1.6969120502,0.6540305614,0.7910987139,2.6275141239,-0.5053266883,-0.6437256932,0.4331637621,-0.1179857254,1.3676888943,-0.3311014175,0.0152680846,-0.0236807577,0.9302479625,0.6600639820,-2.4037752151,-0.9464588761,0.0438113771,-0.0725328401,1.0720617771,1.0761135817,-0.2737096846,-0.5588893890,0.2598156333,0.9769091606,-0.6441979408,0.7905815244,0.8603966832,0.2026889175,1.3673669100,-1.3858262300,0.2233661562,-0.1094158739,1.4453797340,0.0151959099,-1.6613028049,0.7575907707,-0.1962304562,-0.1996283978,-0.7416828871,-0.7916600108,1.4287346601,-0.4484005272,0.6876532435,-0.6248690486,0.3298631310,0.9127324820,-0.9684745073,1.3250454664,2.2452054024,-0.9814113975,0.0123218549,-0.0707478821,-0.0363855138,1.0943500996,-2.1510896683,0.5944954753,-1.0275869370,-0.7499034405,-0.9592984319,0.5362375975,-2.1820952892,0.6188629866,0.7973918915,-1.7052952051,-0.7358623147,1.4108181000,0.3214335740,1.3040961027,0.6007806063,0.6384257674,0.5477932692,-0.0138832955,-0.8589347005,0.8096865416,0.3102856278,-0.2026515752,0.9718768001,0.6564921737,0.1603172570,1.0024086237,-0.9002149105,-0.8006245494,-0.9411728382,-0.1576966792,1.1415449381,-0.0577506274,1.1866910458,0.3541076481,0.6679896116,1.3162442446,-0.2557232678,-0.3763893545,0.2416353524,0.7076978683,-1.8903992176,1.1509604454,-0.5034546256,0.2765678763,-1.8116631508,0.0736504048,-0.5345338583,-0.2187395692,0.8730805516,0.2851711512,0.4014697671,0.5744179487,-0.9496762156,-0.9646509886,-0.2687695622,1.8421496153,0.8335016370,-0.6742351651,-0.3898480535,-1.3010454178,1.2313911915,2.5872275829,1.0136504173,-0.1823874265,-1.9427940845,0.0121092172,1.0977327824,-0.9339600801,0.0772805214,-0.7465289831,-3.4953188896,-1.5749645233,0.0567488112,0.4932927489,0.4036336541,1.5102025270,-0.3151389062,0.4847653508,2.2489926815,1.2595604658,0.4640718997,-0.2695495784,-0.7470452785,0.7966135144,-1.2423455715,1.0008935928,0.1510142535,-1.3154373169,-0.5294527411,-1.4460440874,0.0734137148,-0.9246321321,0.0041351891,0.3118188381,-0.4110965133,-0.4202423096,0.1939986348,-1.1355917454,1.0640664101,0.1575757712,0.2295729369,-0.5353895426,0.2008222491,-0.0894518197,-1.2742060423,-1.2324142456,-0.0447078608,-0.1281779855,-1.2925449610,-2.0690896511,1.6433898211,-0.6176621914,-1.8369152546,0.8185908198,0.3368025124,0.2383316606,-0.3955019116,1.0942413807,1.0905435085,-0.6878349185,-0.8977550864,0.5481200814,-0.8589039445,0.2464670092,2.2294669151,0.3704622686,-1.6462700367,-1.0096625090,-0.7288820148,0.0720273480,-1.4444570541,-1.4314428568,-1.0962486267,-0.6008301377,0.6626305580,0.3884952664,0.1886538416,-0.0186148025,0.9334484339,0.5448017716,0.1605713814,-0.5728644133,2.3174045086,-1.1572582722,0.3675760925,1.2822412252,0.6096727848,1.0833481550,-1.4809343815,0.6521091461,0.4051893651,-0.0447794273,-0.4249199927,0.9600380063,-0.1428283155,0.1274694651,1.0010346174,0.9665576220,0.7157662511,0.1009588018,0.9976038933,-0.3180441856,-0.7530906796,0.5247619748,-0.1527070850,1.2734057903,0.4071713686,0.9690848589,-0.7642352581,1.0456936359,0.6039264202,-0.6427201629,0.2151586413,-0.3214791715,-0.4597530067,0.5271275640,-0.6031562090,-0.3741852939,1.9624742270,1.3004586697,-0.9262704253,-0.5459587574,1.9289519787,-0.1279011965,-0.8018730879,-0.3704701662,0.1392263919,2.2456700802,-0.2131865770,0.2803228796,-0.2014343739,0.4005430639,-0.7303941250,-0.6890636683,-0.1513775736,0.8517774343,-1.3185310364,-0.8762566447,-0.1303947270,0.9660004377,-0.4019751847,0.4808919728,-1.3781931400,1.8092302084,1.2631082535,1.0598397255,1.1649284363,-0.5299757719,-0.2302153260,0.4181659818,1.0113337040,-0.0762433708,-0.1666911095,-0.0848165229,-2.1126856804,-1.9476577044,-0.3496899605,-0.4967019260,0.5956168175,-1.2740421295,1.6090040207,1.1050789356,-0.3681654334,-0.4480681121,-0.2363000661,-0.2702892125,0.8397852182,0.4432892799,-0.6930931807,0.8435317278,1.0990096331,-1.4728732109,0.3252948225,0.1570708901,-0.2961833179,-0.0988946781,-0.6090566516,1.7864310741,0.3255374432,-0.7772111297,0.8540177941,-0.3736964464,-0.1458571851,-0.4800638556,0.6023507118,1.3466943502,-1.3057725430,-0.6299296618,-0.1963314563,-0.6180570722,-0.6634348035,-0.9157820344,-2.1389577389,-0.5336833596,1.3248667717,-0.6429237723,-1.1559734344,0.6903609633,1.2517040968,0.9739649892,1.2991584539,0.2655103207,0.3484174013,-1.2541536093,0.1894829720,0.8233504891,-0.0764275566,-1.2177714109,-0.8417980671,0.8581524491,0.0035927813,0.6365355849,-0.8042198420,-0.1388953626,-1.6326507330,-0.6042947769,-0.9669717550,0.2938333750,0.9714415073,-0.1223727614,-0.8723503947,-1.1460812092,-0.2133648992,-1.1128445864,0.9363123178,0.1991896331,-0.8822627068,0.1223424897,1.3291049004,0.0668822005,0.1119093895,1.6684954166,-0.9703634977,0.8244425654,-0.3810819983,0.6499918699,-0.4449295998,0.5241637826,1.8430259228,-0.1138890088,-0.7317150235,1.5404244661,-0.6431032419,1.0746787786,0.9530599117,0.2035676390,1.7534618378,0.4639586806,0.0214881431,0.3588767946,-0.4447282851,1.6261456013,1.7030267715,-1.4624485970,0.6691627502,-0.4120528400,-1.2016181946,-1.0315819979,-1.8414787054,0.7353565097,0.0985109657,-0.5989940166,0.6289370060,-0.7668067217,-1.0768667459,1.1415388584,0.2427966297,-1.5039368868,0.2121663541,1.8831692934,1.7689586878,-0.0031755727,0.1881536543,0.0798226669,0.4581492841,0.2642267048,0.9306536317,-0.4983684719,-0.1663818955,-0.9144891500,0.9846673012,0.2117036432,-0.6294923425,2.2421128750,-0.1303592473,0.4997661114,0.9499601126,0.7253001332,0.2831318378,-0.4090300798,1.1107546091,2.2380344868,1.3806735277,-0.3407057524,0.4970670044,1.3422850370,0.1040709913,-0.1962797344,-0.6731407642,0.3965022266,1.6650975943,-0.6868150234,-0.9100295305,1.5729589462,-0.1079028100,-0.8686639071,0.2137991190,-0.8141530752,-1.2586628199,-1.0130791664,-0.1064461023,1.3744591475,-0.5557163358,-1.4183386564,0.4970445335,-0.1264280081,-0.6952810287,0.7875682116,0.9634685516,-0.0873802453,0.4830078781,-2.0697469711,-0.2951569259,1.9275074005,-0.2655444741,-0.5246491432,0.6961337328,-1.1402201653,-0.8014924526,0.4705885053,1.3276981115,0.9487622380,-0.1226340607,2.2388117313,0.9282962084,0.8358730078,0.5729625225,1.3172289133,-0.7303490639,0.1824570298,-0.6966341138,-0.8805764914,0.7411084175,0.2305240929,0.0980034173,0.8006091118,0.2612165213,1.0207033157,-0.0486149713,-0.1296018958,-0.2046490759,0.3058603108,0.1007243693,-1.8249213696,0.5788246989,0.5505513549,0.8283489943,2.3347523212,-0.3820807934,-0.6665652990,-0.6986245513,0.5523877144,0.5897316337,-1.7852385044,1.5092515945,0.5711547732,0.3464311659,0.2958600223,2.0925042629,-0.2321517169,-0.1434054524,0.5728091598,-0.2187698931,-0.4759446084,0.1177005395,0.2013361752,0.5981849432,-1.9799973965,0.2529041767,-0.5476834178,-0.1730593890,-1.7854814529,-1.1705741882,-0.3581634760,0.3817416131,0.7512064576,-0.1027551740,0.6353870034,1.3960314989,-1.2177100182,-1.2762954235,0.2829504609,-0.3222350478,-1.9788143635,1.1852393150,-0.8120482564,0.2017181963,-0.7778249979,0.1324888170,-1.7530630827,-0.3840102851,0.5514950156,-0.9082639813,0.2709457278,-0.2724392414,1.7407710552,1.0251507759,0.5038827658,0.0599922501,0.2778967619,1.1140643358,0.5126416087,0.9094967842,-0.2608771026,1.0770685673,0.3795000911,-0.1550950557,0.4098328948,0.0182807632,1.7432143688,0.0442269817,-0.0733183324,-1.7420239449,-1.0372033119,-1.4505765438,-1.0695979595,0.3520697057,-0.1199650243,0.1623314768,-0.4059309363,0.2590332925,0.3168719411,-0.2985204160,-1.1141160727,0.4796123803,0.5619376302,-0.0879992098,-0.2896755636,0.0345673114,-0.6017387509,2.2942187786,-0.4575514793,0.4433886707,-0.6393599510,-0.7018532753,-2.0840408802,0.2744977772,-1.7085973024,2.0885903835,-1.0704900026,0.6227512956,-2.3643672466,0.4737828970,1.8228685856,1.2083232403,0.5655582547,1.1943204403,-1.6110794544,-0.8104713559,0.6233947873,1.4821898937,-0.3512924016,-0.9832256436,-0.3109658360,0.2102089971,0.0661011934,-0.7598971128,0.2737687528,-0.3565664291,0.0649320632,-0.8309890628,0.8115738034,0.5818820596,-1.2470250130,1.5066984892,0.0355780944,0.5166119933,2.2526850700,-0.8431701064,-0.0671550483,-1.1754525900,0.5172681212,-1.4026856422,1.2922587395,1.1752586365,0.4308859110,-0.1489560753,1.2196234465,0.2266667634,0.6856338382,-0.0718977973,-0.7315303683,-0.7587987781,-0.6444988251,1.0108252764,1.7422361374,-1.0566121340,-0.1381981969,-2.4956552982,-0.6139257550,-1.2556135654,3.1750850677,0.2591003776,0.2450738251,0.3005379438,-0.9752496481,1.7764663696,-0.1214622557,0.5261299014,0.2342363894,-0.0667102411,-0.9946687222,-0.7998950481,-0.1393250823,0.5439608097,-0.3280489445,-1.6486464739,0.0773164555,-0.6094115973,0.7776465416,-0.7698317170,-0.2485616952,0.7960718274,0.2313920408,0.0460020714,-1.7142246962,0.6232043505,0.2541713715,-0.4534405470,1.7899509668,0.1362471282,-1.9164524078,1.3635959625,-0.8852525353,-0.3090792894,0.3931639791,-0.9311147928,-0.3980593979,1.9160156250,-2.4146127701,0.9591246843,0.0804828331,-1.1393139362,0.5533338785,-0.0600930825,0.2490953207,0.3519489169,0.7660022974,-1.6150187254,0.6105470061,-1.2359455824,-0.8698206544,0.3892658055,-0.7539950013,0.6950904131,-0.9604725242,0.4308103025,-2.3256311417,-0.7111156583,-0.4337917566,0.8061956763,-1.3608552217,0.4315817952,-1.3107632399,0.5574386120,-2.2791669369,-0.9615024328,-0.0104346648,1.8257387877,1.4231183529,0.2945812345,-0.1324300915,0.2946366966,1.6782826185,0.6541477442,0.4029373229,0.4747828245,1.1353145838,0.3953845799,0.1936890781,0.4062623680,0.4179663360,-0.1990364641,0.2323853821,-0.1627434790,1.2631576061,1.0686953068,-0.2658118308,0.6809504032,1.5407712460,-0.6695981622,1.8600367308,0.4357393682,-2.5560443401,-0.5719974041,-0.8085638285,-0.2786338627,-0.7596287727,-0.7966396809,-0.6347700357,0.6346846819,-0.1229087114,-0.4061551392,0.4961775839,-0.9298028350,1.7950794697,-0.4195333719,-0.6384252906,0.4334599376,1.2472872734,-0.2829909325,0.1914219707,-2.3444113731,0.1594360918,1.2696460485,0.4959804118,0.2380602211,-0.1448186785,-2.1736934185,0.0322666392,-1.1135591269,0.1910399944,0.5964226723,0.6934137344,-0.3309519887,0.5232272744,0.6514256001,0.5427439809,-1.2049249411,1.2035021782,-2.1379439831,-0.0123552503,1.6907293797,1.3622356653,0.0854423568,-0.1239003465,-1.1248239279,0.3118157685,1.4227129221,1.3931421041,-0.5201041102,-0.6520749331,-0.1951945126,-0.0238409471,-1.0981628895,0.1196731627,-1.0028203726,-0.0433323942,0.1475336701,-0.2034588307,0.0879188478,-0.1838414073,0.8159422278,-0.6409673691,0.0307073314,-0.8225424290,0.1864877790,-1.2164173126,-1.0154621601,-1.4576314688,-0.7777158022,-1.0057930946,1.5576810837,1.0352222919,1.8638725281,-0.0097064106,0.8054191470,0.1223727986,-0.0801445544,-1.4936922789,-0.4619750381,0.0596807078,0.3278731108,-1.0393821001,-0.4951561689,-0.3413927257,0.1904700100,-0.1210603565,-0.1594241560,-0.5338973403,-2.1179163456,0.9923138022,1.6756576300,-0.5539448261,-0.4309539795,1.2551391125,-0.9311563969,0.6251273155,-0.0564246289,0.8008189201,-1.9777007103,-0.3098180890,0.7816771269,0.6166989803,-0.6998443007,0.4654302001,0.0343916118,2.4334328175,0.5027511716,-0.5978142023,-1.1934173107,1.1687659025,-1.3383669853,1.0300269127,-0.0677551478,0.3900418580,-0.4028481245,1.5647825003,0.4914836287,-1.0139048100,0.7788290381,-0.9364992976,-0.4769464433,-2.2719848156,-1.2316024303,1.4936300516,1.1475230455,-1.6251858473,-0.1341409087,-0.6324136257,0.9583027363,-1.8046439886,-0.6657356620,-0.2849379182,1.1019287109,0.3203172982,0.8305735588,0.8801663518,0.2541929483,-0.7876218557,-0.4848353863,-0.6038257480,-0.3463531435,-0.4620301723,0.3399290442,0.4784194231,-1.4630919695,0.5666418672,0.6698990464,-0.1886400282,-0.0589710884,-0.8409474492,-0.5538551211,1.1771206856,0.0073921932,-0.0275823288,0.4827136993,2.1394298077,1.0037149191,1.3728575706,0.5932582617,0.6228179932,2.2393188477,0.6417520642,-0.6442270875,0.3314913809,0.4365530312,0.9575701952,0.1253282130,-2.6363835335,-1.1195566654,0.1741666943,-1.3815630674,-1.3405553102,-0.9259150624,0.7431330681,-0.5993356109,-0.9352449775,-0.2250264287,-0.3261758387,-0.9840246439,0.8795168996,-0.0585330613,0.4813308418,0.6932357550,-0.6614339352,-0.6948084831,-0.5029956698,1.0634011030,1.9179027081,-0.1568887830,1.2873591185,0.7845811844,-0.9608737826,-1.5719852448,-0.3008854091,-1.5339412689,-0.2134107649,0.4248637855,-0.3359931409,-0.1320641041,0.8435388803,-2.7100458145,-1.7172553539,0.8296487927,-0.9835475087,1.5917860270,0.1721152812,0.4304965138,0.7664323449,-1.2311582565,-2.3880450726,-0.4940323532,-1.0391459465,-0.7237001657,1.2727987766,1.6193475723,-1.0287649632,0.7299798131,-0.6349011660,-0.0274767578,-1.5900055170,-0.4706409872,0.7383552194,-1.4446251392,2.9851384163,-0.5311147571,0.0925131291,1.0023488998,0.9239675403,-0.3110629916,-0.3885660768,-0.5063413978,0.2894129455,0.8276406527,-0.4842105806,-1.5078349113,1.2256025076,0.8286691904,-0.3395346701,-0.0520976894,-0.6069356203,1.4886635542,0.8925319314,0.5489603281,0.4804161787,1.3660881519,-0.4378204644,-0.7837976217,0.3279939890,-0.4669124186,0.5884266496,-0.1041898355,-0.7743563056,1.9065687656,-0.1401365250,0.0404757708,-0.4654856622,0.1470849812,-1.2212413549,-0.2502074838,-0.5511439443,0.1273302287,-0.8361667991,0.5060011148,0.4187401831,-1.0274453163,0.1833582371,0.1491656005,0.8520369530,-1.0309195518,-0.2227566093,0.0463354513,-1.7734726667,0.2360962629,1.2328624725,1.3344942331,-0.6834138036,-0.9213144183,-0.2375682145,-1.0676547289,-0.7755971551,-0.1519525945,-1.1810057163,0.6070850492,-1.2324193716,0.7946123481,0.4432314336,-1.2385253906,0.7860576510,-1.2088580132,-0.6392730474,-0.8253847957,2.0636448860,-0.3773825765,0.2946148515,1.2927073240,0.3535074592,-0.4379634857,-0.0179980081,-0.0072805942,2.2701530457,-2.1468765736,-0.3751948774,-1.4295772314,2.2897188663,0.7464865446,0.2147173584,-1.1608482599,1.5358866453,0.5187512636,1.8804030418,1.5796387196,1.0487182140,-0.8676830530,-0.0556595251,1.3028850555,-0.5795240998,-0.5162953138,-0.0655466840,0.9422415495,0.7499783039,-0.9180640578,0.4498133957,1.1590911150,0.4048582017,-1.7504346371,2.2532100677,0.0281716362,-0.6220969558,-1.5183184147,0.9161355495,-0.8907647133,-1.3098375797,-0.3318792582,0.2209775299,-1.2912184000,-1.5370779037,0.2036247104,2.0972721577,-1.0611443520,0.9589093328,1.1591913700,1.0168168545,1.2855957747,-0.0241216458,-0.8847688437,-0.2365839183,0.0415988378,-0.1515546739,-1.0070446730,-1.1214296818,-0.3417044580,-1.3171265125,-1.5975716114,0.8810922503,0.4943160117,0.0729970559,-0.0358922035,1.4424666166,-1.5872232914,-1.3994543552,-0.4739158154,-0.4085120559,1.6491034031,0.3564356565,-0.5753759146,2.0592122078,-1.0333622694,2.1544709206,1.3682296276,-0.7064908743,1.7868995667,-0.9723177552,-0.7266247869,0.9715178609,0.4088996947,-1.7122020721,-0.4308840632,0.3252696097,0.2743642926,-0.8869826794,-1.0270365477,-0.5657429695,0.0832255706,0.0655450523,0.4747250974,-1.3726384640,0.4130788743,0.6846900582,-0.5520215034,-2.0530512333,-2.1558058262,0.1264140904,0.3746607900,1.8946000338,0.1379344761,-1.2841641903,-0.3011165857,-1.3064757586,0.6817041039,0.9905909896,-0.3322680295,-1.0966534615,-0.5721865296,1.1613034010,0.4173618853,0.2521701753,0.0170840435,-1.1218461990,1.3891819715,2.0246393681,-0.3689926863,1.2998167276,-0.0202535987,0.4367121756,1.0193365812,0.9042968750,0.6680484414,-0.6065965295,-0.5022114515,0.5810588598,-0.3901543915,-1.1834454536,0.8150207996,-1.1420608759,-0.3598107100,-1.6044889688,-2.4384107590,0.0117071439,1.9975863695,-1.3817124367,-0.3072476387,0.0048268959,-1.7112979889,0.9031231999,-0.2966916263,-1.0396625996,-0.1289494932,-0.7083650827,-1.4692304134,-0.5094682574,1.9392372370,-1.6139283180,-1.1871839762,-1.1809390783,-1.9714508057,-0.9087123275,-0.2333478034,-0.7533107996,-0.9897646308,1.4758378267,0.1605499536,-0.0507054329,-0.2238054425,0.8934520483,-0.0074833194,-0.3475907147,0.4808534384,-1.3428298235,0.0425792374,-1.4493671656,-1.1105960608,-0.3286893964,-1.1615190506,0.7743390799,0.5156641006,1.4899449348,0.7932764888,-0.3827163875,0.9504209161,-0.1228832677,-0.5156506896,-0.2268660665,-0.6296691298,1.0760799646,-0.4033052623,-0.7914856672,-0.2877828479,1.5812536478,-1.1596530676,0.0779661462,0.6545679569,-0.2202242166,-0.7564415932,-0.0417143740,-0.3171341121,-0.4582436979,-0.9056224823,-0.9524829984,1.6070226431,-1.2132416964,2.2914252281,-1.1252080202,-0.6691984534,-0.2136556059,1.5424201488,0.3239894807,-0.1936365366,-0.3805269301,0.3153375685,-0.0132743232,-0.7174763680,-0.6745864749,0.5147384405,0.2804582715,0.8614385724,1.0986897945,1.7333666086,-0.7799022198,-0.9911209941,0.9604320526,-0.8721246123,-1.6883252859,-0.8845354915,0.7923492789,-0.5049350262,2.0076103210,-0.0851265863,0.7332333326,-0.1772662252,1.5707787275,-1.1044410467,-0.1525815576,-0.9408708811,0.4330949187,-1.2818670273,-0.3055057526,-0.1675800681,0.0284603387,-0.8147291541,-0.4210108519,0.7458789945,-1.1510759592,-0.5196728706,1.2945172787,0.3134264946,-0.5981710553,-1.7199571133,-0.9573861957,0.3585983515,0.1577864438,0.0976585224,0.9235061407,-0.4882372022,-1.2233790159,-0.3873362243,0.1936537027,0.8459808230,-2.3967981339,-1.7979650497,-1.3401989937,-0.6894354224,0.0410711132,-0.7186352611,0.0600788631,1.3476153612,0.3278820813,-1.3045172691,-1.3771083355,-1.7876477242,0.2890119255,1.3028764725,-0.3252322376,-1.6646826267,1.0996216536,0.8495755792,1.1889733076,-0.6801342368,-0.9674876332,-0.5559958220,-0.8111504912,1.2361888885,0.2234009504,1.1607664824,-0.7407107949,-0.2627224922,-0.6727229357,0.6591702700,-0.1328006536,1.9366884232,-0.0906984061,0.7591729164,0.1739566326,0.7143741846,0.5020965338,1.7826042175,0.6204472184,-0.5581421852,0.2132278383,0.3122832775,-0.9909564257,1.2599604130,-0.1934482753,-0.9713167548,1.1571723223,1.5756896734,-0.5407086611,-0.6157051921,-1.6384927034,0.9595841765,1.1959745884,-0.2396019995,0.5296090841,0.0760802999,-1.4119911194,0.2633403540,0.8130000234,-0.0615768097,-2.6958682537,-0.0774267390,0.2242079079,-1.1902222633,-2.2081933022,1.3072851896,-0.6697205305,0.3599147201,-0.5324732065,1.8647314310,-0.6539912224,-0.0811203197,-1.6695041656,-0.1677595228,0.1529489309,0.0326982960,0.3603679836,0.2729178965,2.6728754044,0.0517382957,-1.1903650761,1.9886676073,0.3085786998,1.2711433172,0.3996826708,-0.9335381389,-0.3373581767,0.5985429883,-0.7188912630,-0.5423603654,0.8109322190,2.1182680130,-0.2123235017,-0.2050291598,-0.3468085825,-0.0957891718,-0.2557451129,0.1651563942,-0.9804444909,1.7935678959,-0.5420064330,-1.2521762848,-0.4070931375,-2.2685718536,0.2797066867,-0.1671731770,0.7808704972,-0.2584797740,-1.3019461632,-0.8495772481,1.1621996164,0.7994099259,1.4648393393,0.0249336269,-0.5417373776,-0.1430224478,0.3782896399,0.4983956516,-0.3447601497,-0.0361413844,-1.3818486929,-0.1909462810,-0.6342868805,-1.5501580238,0.4438783824,1.4791367054,-0.2694898248,-0.5962350965,-0.4852928221,-0.9123769999,1.4600878954,0.0140110198,-0.0810736865,0.4739871919,-1.6347879171,0.6561161280,0.7903645635,-0.0381236821,0.7106814384,-0.4605905414,0.0920624137,-0.7547672391,0.0979229510,0.3171488345,1.1117020845,1.4691916704,2.1095216274,0.0467688963,-0.2855694592,-0.9627265930,-1.6467630863,0.4463484585,0.1725912839,-0.4279518425,-0.1798031181,0.3101399839,0.0048362794,1.4784452915,1.5026966333,1.0328475237,-0.4919162393,-0.1434764564,0.4667615294,0.9142318368,-0.9285969734,-0.2069311589,1.4059398174,-0.5289928913,-0.4967575073,-1.3956668377,1.4277200699,0.8334128261,-0.0185762569,-0.1923116297,0.0418641306,-0.4321692884,0.8290914893,0.8341650367,-0.2333217710,0.7934345007,0.3587965965,0.5614849925,-2.0616495609,-0.1924656183,-0.0459085889,0.2538861036,-0.4057802260,-0.0318090059,1.3345776796,1.9516458511,-0.4307067394,0.8678566217,-0.1097779796,-1.6316813231,0.1627230048,0.6683475971,-1.0535581112,0.3491037786,0.4147782922,-1.2055585384,0.4886077940,-0.1130808294,0.7219112515,0.0661294386,-0.1400840580,-0.0657013953,-0.6607044935,-0.6015189886,0.7106990814,1.7140800953,0.9367416501,-1.2773195505,-0.6420869827,-0.6175547242,-1.8307830095,-0.4264650047,0.5967303514,1.3804618120,0.8144572973,1.5835609436,-0.3536988199,0.7703401446,1.4535437822,0.7620157599,-0.2588397861,1.8452669382,0.2829564810,-0.8681214452,-1.8005297184,0.4997319281,-0.4752902091,0.8748758435,-1.3430117369,0.5314849615,-0.5759868622,1.2641209364,0.8554402590,1.5168594122,0.2480181605,-0.2194981575,0.5211862922,-0.6440048814,0.7792780399,1.4497418404,0.7278845906,-0.5463015437,-0.0357734151,2.2245075703,1.7500543594,-0.1910633743,0.6573238969,-1.3362874985,-0.7534814477,1.2886375189,0.8610209227,-1.0121858120,0.9795084000,-0.1356090903,0.5075626969,-0.8574798107,0.5879177451,-1.7946065664,-0.0130303819,2.6269860268,-0.2716670632,-0.0657275766,0.1854525954,0.6998822093,0.2578449249,-1.4977544546,-0.6380822659,0.3094310462,0.9322613478,1.0821434259,0.0982655212,1.2655304670,0.8077735901,0.7658033371,0.0170805342,-0.6523284912,0.4967969060,0.2543117404,-0.1472297460,-1.0754979849,-0.3788460195,-0.6500695348,-1.2020435333,-0.7062480450,-0.1719639748,0.1413584501,1.7674720287,1.4245822430,-0.6928767562,0.4070508480,-0.8351898193,0.6124445200,-1.4726996422,1.2751882076,-0.0078987619,0.7250511050,0.4638235867,0.2765693367,1.0345190763,0.6211076975,-0.2134134769,1.0013273954,-0.3205123544,-1.9580650330,-0.1975866854,0.5886839032,0.2872526348,1.8216292858,-0.8485202789,-1.1175162792,0.0909620300,-0.1545620412,0.6551841497,0.7736989856,-1.3568792343,0.7647265792,-0.2998824716,-1.3783611059,-2.0769608021,-2.3308551311,-0.1665841937,1.6644699574,-1.1846499443,1.8231101036,0.4575906098,-0.5072680116,-0.3290798664,-1.7656143904,-1.0600577593,-0.2223261595,0.4002893269,0.7339606881,-1.7777433395,0.1461729258,0.7029541135,0.7349690199,-0.4175417423,-0.6678780913,-1.4948253632,-1.2591323853,0.7002172470,0.4057020247,-1.8846118450,-0.4096996486,0.3572451174,-0.5729187727,0.3632394969,0.8388002515,0.7888129950,2.0745422840,0.1977431327,0.1684732288,-0.5357504487,-0.7693734169,0.4129380882,-0.3638237119,0.6388210654,0.0842956081,-0.1233994961,0.0458561741,0.0440238081,-0.8346993327,1.1818025112,0.3015581667,0.2385077327,-1.2280052900,-0.0870673805,0.3921283185,0.4252742529,-0.0002660285,0.4988144040,-0.3004822135,-0.2015036196,-0.5291435719,1.3097598553,1.4225721359,0.6904790998,-0.7867959142,1.5844599009,-0.2980011702,1.2988511324,0.2470097095,-0.4910517037,-0.4043954611,1.0191758871,0.1660731584,1.6221412420,0.0662123859,0.1093840599,0.3859095871,-0.1514603198,0.7722839713,-1.8401905298,-0.4582791924,-1.5480029583,0.8383934498,1.5307412148,-1.0848832130,-1.4832700491,1.3966538906,0.7267266512,0.5375882387,-0.7886016369,1.0743261576,-1.1768319607,0.1318906993,-0.3701928556,0.5601051450,0.3761105239,-0.0058422196,0.8287389874,-2.5389571190,2.1728942394,0.3999422789,-0.0519637764,-0.0581969433,0.1575311124,-0.7968834043,1.0298998356,0.3352723718,1.8463332653,-1.3961603642,-0.1399134099,0.8294527531,0.8428064585,0.1062459201,-1.6589927673,-0.5416683555,-0.3484183848,-1.3727669716,-2.1644611359,-1.1050168276,-0.6006038189,-0.6543050408,0.4155762792,-0.4915748537,-2.1399559975,1.0393067598,-0.1879214644,0.8151748776,-0.5987551212,-1.0111064911,-0.1526869535,-1.9934095144,0.0915879831,0.0305229817,0.0214052256,1.4779964685,0.4579023123,-0.1609235853,0.8058716059,-0.1193252355,-1.4209824800,-1.4432802200,0.3448107541,0.8484117389,0.3917312622,-1.3221226931,0.2110161185,-0.1322266310,1.2812737226,0.2105053812,0.5784762502,1.2395321131,-0.1125992611,0.6148221493,0.1073464751,3.1926834583,-1.7169188261,-0.4264818430,0.5589302778,0.0098558068,0.0445020609,-1.0925434828,0.5685714483,1.8520839214,0.2249426991,-0.1640461534,0.4741087854,-1.8028807640,2.5509712696,-0.3230691254,0.1120029092,1.4169816971,-1.1021708250,-1.3753912449,-0.6458590627,0.1685565859,-0.2544992864,1.2977367640,-0.6434763670,-0.4687041342,-1.5133686066,0.5543805361,-1.6351692677,-0.5480977893,-1.8672090769,1.8669744730,0.1007032543,-0.7519266605,0.9288895130,1.0849411488,0.8286650181,0.2248411477,-1.4469972849,-0.8432237506,0.4922606349,1.0674357414,1.0139129162,1.8805615902,-1.0198467970,-1.4214346409,0.0867412463,0.7238012552,1.2070678473,-0.2821899652,-2.5294377804,-0.1533146352,1.5075769424,0.1515903473,-0.7290561795,-0.3938293755,-0.3148902059,-0.0655002147,1.0328027010,0.9855728745,0.0142235737,0.1424133629,2.3653128147,-0.0937726349,0.6720957160,0.3193032146,-0.0347761326,0.8808904290,0.6379359365,0.5533177257,1.1247152090,-0.0711953193,0.0823010355,1.5953356028,-1.1492849588,-0.2697221935,2.5629601479,-0.4678767622,0.3748208582,-0.3017410338,-1.1595700979,0.9848414660,-1.5886949301,2.1473009586,-0.4320541620,0.3351209760,1.1572041512,-1.6510055065,1.4763158560,-0.8780969977,0.7521370649,0.7664933801,0.6427647471,0.6748605967,-2.1987223625,-0.7755331993,-0.6144747734,0.1226312146,-0.0433201976,-0.9534757137,-0.7053830028,-0.2736400366,-1.2137296200,0.6272516251,-0.1973339170,0.1871281117,-2.7975583076,-0.1932645291,-2.1384193897,0.0670402572,-1.4602125883,-0.1883114576,-1.9900075197,-0.1766163856,1.3107856512,0.8267203569,1.0474450588,-0.4156937301,1.4552435875,-0.9403783679,0.6154562235,0.9041082263,-1.4211113453,0.1542359740,0.2054781765,1.2778793573,-0.1201702952,-1.3128867149,0.3029603362,-0.7522927523,-0.9131040573,0.9282863140,0.5733796358,-0.9316766858,0.2135121375,-0.7382605076,-0.5023554564,-0.9460375905,-0.3469051719,0.3816500604,-1.3926203251,-0.7923706174,-0.8669332266,-0.5555337071,0.2142671943,0.5651071072,-0.6646097302,-1.0670479536,0.0496083200,-2.2859947681,-0.5420932174,-0.8602784276,1.1403759718,0.5368918180,0.4115375876,1.4746530056,-0.2967051268,-0.4382048249,-0.7692515254,-2.1632175446,0.2171597481,-0.4031183124,0.8962494135,0.9963235855,-0.8190985322,-0.3271569610,-1.8990769386,0.3499003649,-2.3797082901,0.6820656061,-1.0557612181,-0.1580118388,1.3777353764,-0.9384363294,0.2778090537,-0.7599855661,0.0350417122,0.3391051590,1.0693094730,-0.4610579610,-0.7098724842,0.2182071954,0.8414065838,0.8761809468,-1.2011101246,-0.0909584537,1.6314455271,-0.3418768048,-0.6599820852,0.0627719760,1.9397410154,-2.6317727566,-0.9709402919,0.2281691581,-0.1328415275,0.3824462593,0.9747131467,2.1028826237,-1.8011776209,-0.7046427727,0.1276893169,1.2597452402,-0.2805773318,1.7098058462,-0.5087597370,1.8857795000,-1.8405008316,0.1865903288,-0.4646588862,-0.8164331317,-0.6990193129,-1.1148481369,-1.4104843140,-0.5799752474,-0.4449983835,-2.0007512569,-1.5721967220,-1.9587359428,-0.6990004778,0.0577918403,-1.6206052303,-0.1327113062,-2.6066644192,0.3853771985,0.7883592248,-0.4743609726,0.3637579083,1.8269271851,-0.3550509512,-0.3871345222,1.4265280962,1.3550875187,-0.0144073600,0.0320234708,0.2594887316,-1.8753159046,1.2990872860,1.1652233601,-0.4094679356,0.6926257014,0.4886541367,-0.3665470183,0.9978932142,-0.4778836966,-2.4469411373,0.8460370302,0.2013505697,-1.1429011822,2.0269160271,-0.3998430967,0.2654949725,-1.0957469940,-0.7791578174,0.7616731524,1.3665670156,-0.8782943487,-0.8286035061,-1.1778832674,-0.8636802435,-0.0061646109,2.2168614864,1.0119706392,-0.2279826999,-0.6041381359,-0.6085149050,-1.2976219654,-0.2709690034,-0.0114500197,-0.4823000729,1.2648714781,-1.3784844875,0.6856546402,0.9222300053,0.6966942549,-1.8633707762,-0.1454697251,-1.3210371733,-0.1145494431,1.1239894629,1.9604538679,-0.4812983572,-0.5667022467,-1.0941706896,-0.7513188124,-0.4788049757,-0.9990747571,-0.7967398167,-0.9379817247,-0.9230493903,1.3206555843,-2.1616094112,0.9471166134,1.4199587107,0.6445659995,0.4961482286,0.4532108903,-1.3316901922,0.6221421361,1.1318142414,0.5100553036,-0.1593082994,-0.7789161801,-2.7416522503,1.1332864761,-1.0270265341,-0.2043064237,-0.8484025598,-0.1263597310,-0.1946774721,0.6200547814,-0.6168873906,-1.3963674307,-0.6660103798,0.0967090577,-1.6318593025,0.2810838521,0.6856861115,-1.1412400007,0.3920578957,0.3876029253,-2.0110924244,-0.6093295813,0.8308763504,-0.6013477445,1.4756437540,0.3031979799,-0.5353441238,-0.5915081501,0.9075561166,1.1504007578,0.6115757227,-2.3925230503,-1.2824686766,-1.3351628780,1.1867614985,0.2219233513,-0.8080751300,0.5201536417,-0.1467103064,1.5671451092,1.9779373407,-0.2780325115,0.3241499662,1.5429707766,0.3520541489,-0.0514822975,-0.1410155594,-1.3119984865,-0.3331850767,-1.3207861185,-0.0688070208,-0.1959996521,-1.2634282112,0.4501601756,-0.6468436122,0.6385756135,0.4816366732,0.8377054334,-1.1855635643,0.5892620087,-0.6773741245,-1.5393686295,1.6592665911,1.1991732121,-0.8384900093,-0.0617964156,-0.3647063375,0.0483825915,0.6977452040,0.8587312102,-0.5782601237,0.6752809882,1.8073829412,-0.4694879651,2.6854341030,-0.7661315799,-0.1617361754,-1.6490541697,-0.3861537874,1.1943726540,0.4325670004,0.9196245074,1.1767194271,-1.1586842537,2.2081480026,-0.8941178322,-0.1457774490,-1.3551640511,-2.0796351433,-1.5357860327,1.3167635202,-0.4685901403,-1.3264200687,-1.1433360577,0.5723722577,-1.3153508902,-0.0003914612,0.4272823632,-0.6007682085,-0.9464733005,0.9466275573,-0.3957338631,0.3242906034,0.3518322706,-0.9805750847,-1.4119974375,0.9316169024,-0.0752965063,-0.3946371078,1.0344431400,0.5991471410,0.7365334034,-0.8374543190,-0.0171916950,0.5245986581,-0.2836663425,-0.7435886264,-0.5999352336,0.5393315554,-0.9004894495,0.9330707788,-1.0388084650,0.5326125026,-0.2157468051,0.3797125518,-1.6414234638,-1.5240204334,-0.1943216473,2.4012343884,-0.1102185398,1.0404075384,-0.5839586258,-0.6843239665,-1.0446710587,1.3564828634,-1.1882144213,0.4350872934,0.2158848494,-0.3997232020,1.3127151728,0.7766410112,0.0745480806,0.8701055050,0.5700027943,-1.9929957390,1.7805351019,0.0368345529,-0.2137983143,0.9791098237,0.3465301096,-0.1790597886,0.7861873507,0.2161410749,1.9109491110,0.0643576086,1.4099440575,0.5143269300,-1.2256814241,0.3933446407,0.9667174220,-0.0542557761,-0.6940347552,-0.1299740523,-0.6604279876,0.0753633454,-0.4645026326,-0.9675666094,0.6419441700,1.0465860367,0.4986249506,-0.3357897699,-1.8439725637,-1.3316335678,-0.4952035844,1.5557930470,0.6939328909,-0.9675522447,0.1987546235,0.0348333046,-1.2145023346,-1.0559561253,-1.6981366873,-0.6445525289,-0.4339305460,1.0280379057,1.7661401033,-1.4261125326,-1.3287851810,-0.8939813375,1.1151138544,0.4468123913,0.5887181163,-0.0540989488,0.8927987218,2.1387660503,1.7823724747,1.7096697092,1.8147362471,-0.1693580598,-1.0753818750,1.2679872513,-2.0095827579,0.6978594661,-1.2827425003,0.3344699740,-0.0405597240,0.1785971820,-1.7131185532,0.8015590310,-0.7889513373,0.4382426143,-0.2685180604,-0.4353355765,0.8980778456,1.4425247908,-0.6797144413,-0.5390772223,-1.2332694530,-0.8271765709,1.2962095737,-0.6857874990,0.4101184309,-1.0391228199,0.4739780426,0.2037101090,1.2740825415,-1.7347189188,1.1883305311,-0.2816534936,-0.0767895505,-0.1394811720,-0.5756545663,-0.4448460937,-0.9648231268,2.6027748585,-1.0214937925,-0.8026785254,0.1019904837,0.0143244155,-0.4809729457,-1.2737265825,-0.5467684269,1.2570265532,0.7116396427,1.6483726501,0.4744225144,-1.3267292976,-0.0733655021,-1.5249861479,-0.0464469939,2.2251887321,0.2355747223,1.2292549610,-0.8253579140,-0.1976063699,-2.2327098846,-0.2294290513,-0.8787239790,-0.4248799682,-0.9848347306,1.1690719128,-1.8133636713,-1.8084857464,0.0479786545,2.0665719509,-2.6742475033,0.5344931483,0.0683459938,-0.4919559062,-0.9514514208,-1.2987574339,-2.8886623383,-0.0731047243,-1.9328001738,0.9243254066,0.4220359325,-0.7849935889,-1.3458760977,0.3226920068,-0.6062769294,-1.6259837151,0.6885620952,1.7813590765,0.0121325897,1.6976926327,-0.3455361128,1.0504717827,0.1753101647,-0.0284505151,-0.2338887602,0.7708004713,0.4418765306,1.2308294773,-0.5319422483,-0.4612456560,0.3082421124,-0.5902484655,-0.2054267824,1.5642417669,0.1995749623,-1.3234007359,-0.6998391747,-0.6464892626,-0.3926881850,0.1428338438,0.2082134038,-0.3770585358,0.2527660429,2.2772750854,0.6177937388,-1.6407494545,0.0468776226,-0.9865619540,-0.4993889332,0.8691691160,-0.2714325190,0.9959207177,-0.4606694579,-1.1768029928,1.0289868116,0.7226113081,-0.7540940642,-0.7165128589,-0.5451242924,-0.4123264253,-0.8378821611,1.1969192028,0.2376316488,0.6620379090,-1.2662197351,-0.2605038881,-0.4416389763,1.6299383640,0.0120546557,0.1751725078,2.0253489017,-2.0747103691,0.7142991424,-0.8726304173,0.1750395596,0.4198315442,0.8568505049,-0.7676183581,1.2397425175,0.6619054079,-0.8535833955,0.9861800671,-1.0405623913,-0.2410328388,1.1349664927,0.2311729193,0.1398157328,0.7055028081,-1.5441834927,-0.2105818391,0.8658529520,-1.5761580467,-1.0042510033,-0.6100757122,-0.1319507957,1.9316471815,-0.3888913393,1.4629999399,0.3790009618,-0.7812678814,0.2428106815,1.7966394424,0.2591165304,-1.0846961737,0.4639006257,-0.3702415228,-1.3542098999,-2.5225086212,2.1170349121,0.2919540107,1.5617704391,-0.5720227361,0.1448655128,0.8777965903,-0.7311284542,0.6961936951,-0.2438761741,0.2898792624,-1.0157407522,0.1055957079,1.5368494987,-0.2627255023,0.5305185318,-0.9444933534,0.9583199024,-0.4513328671,-1.7957193851,-1.9104524851,1.5604406595,1.0587686300,-0.2916118801,-0.8341334462,0.6081914306,0.5385888815,0.2649672329,1.9931534529,1.7101278305,-0.3339462578,-1.6201473475,0.4781301022,1.6592991352,1.8929585218,-0.5796220303,0.1620042324,-0.9191796780,0.2226093709,-0.3510306776,2.5146825314,1.3014285564,-0.5516109467,-1.7102047205,-0.8960490823,-0.9496671557,-0.4185546935,-0.6126506329,2.3513891697,-0.5045138597,0.2073156387,-0.0403192304,0.2158572525,1.6789017916,-0.0491207652,-0.0926134512,-0.9717449546,0.3141212761,-0.1822118014,1.5598946810,0.1269149184,-1.7584841251,-0.2879258394,-0.5144426823,0.8904726505,0.0560838953,1.0901510715,-0.3769854307,-0.6356492043,-0.2561465204,-0.2323470414,0.8959264159,1.5302934647,0.9458421469,-0.7589567900,1.3199381828,0.2553999126,0.0001370502,-0.9755280614,0.1034968719,-0.5387631655,1.1641650200,1.5335197449,-0.0891886353,1.0386070013,0.3652443886,0.4225503206,-0.9608186483,0.2354464382,0.8191389441,-0.0019620592,-2.2598648071,0.2033568025,0.9071549177,1.6220998764,0.0620047227,1.1191365719,-0.6640503407,-0.2967987657,-0.1196853444,0.4721096754,-1.5424871445,2.5747241974,-0.9410291314,0.2411335409,-0.5882598758,0.5838999152,1.2239956856,0.0473095626,0.0269213933,-1.7474669218,-0.1254788041,0.6390517950,-0.1682768017,0.1148226485,-0.8987408876,-1.1397955418,1.4998438358,1.4500621557,0.1748585701,-0.1256774962,0.6514495611,-1.3195337057,-1.3019288778,0.1573456079,1.1976250410,-0.6434811950,-0.0719533190,-0.0295303278,-0.9087253809,0.6040388942,-0.3942040503,0.8656547666,1.3265830278,0.1610490084,-0.5010558963,-1.4810063839,-0.2897340357,-0.6645922661,0.2873976231,0.0032383415,-2.2635951042,0.7036095262,0.2958571017,1.3461945057,0.4321117997,-1.0315165520,0.9034367800,-1.0506396294,0.3633961380,1.2920157909,-0.1767129153,0.9583020210,1.9570393562,-0.0153314872,0.2814647257,-0.3974483609,-0.2976866663,-1.3961068392,-1.6619836092,-1.1750111580,-0.3427028060,0.8588997126,-1.0289971828,-0.1670207977,-0.2226491570,0.5565141439,0.3041157424,0.1601631343,-0.6869891882,0.0558025204,-0.1517806500,0.2210749239,-1.2610491514,0.4965585470,-0.8622374535,-0.2092900723,1.9283560514,2.0117387772,1.2364124060,-1.2820222378,-0.5927175283,-1.2122610807,-0.2559721172,0.3717762232,-0.4502603412,1.7123154402,0.3875474632,0.6138361096,0.4190999269,0.7165051699,-0.9974407554,0.6195259690,-1.8539083004,-0.8086301088,-1.7899594307,0.5038084984,-0.9629930854,1.0737767220,-0.0268682484,-1.5845243931,1.5086864233,0.6216324568,1.9804166555,-1.0086367130,2.2385258675,-0.5203742385,-0.8196234703,1.1165432930,-1.2808620930,1.2763589621,-0.9164367914,0.1268753260,2.0863809586,-0.7245088816,-1.2106389999,1.2202898264,-0.8158519864,0.8383903503,1.5530946255,-0.1538568288,0.2419621795,-1.1090013981,2.5024588108,0.1697666496,1.0527145863,0.6301341653,-1.3145409822,-0.5830605030,-0.2038480788,-0.1603022367,-0.6039440632,0.6921498179,0.5524765253,0.8396931291,0.4275787771,0.5381883383,-0.0318626240,2.2095665932,1.4112273455,0.0706845075,0.3475209475,0.3752060533,-0.5024744272,0.4471912980,0.3937501609,-0.4151968062,1.5611482859,1.7722326517,-0.4225720763] +[ + 1.7640523911, 0.4001572132, 0.9787380099, 2.2408931255, 1.8675580025, -0.9772778749, 0.9500884414, -0.1513572037, + -0.1032188535, 0.4105985165, 0.1440435648, 1.4542734623, 0.7610377073, 0.1216750145, 0.4438632429, 0.3336743414, + 1.494079113, -0.2051582634, 0.3130677044, -0.854095757, -2.5529897213, 0.6536185741, 0.8644362092, -0.742165029, + 2.2697546482, -1.4543657303, 0.0457585156, -0.187183857, 1.5327792168, 1.4693588018, 0.1549474299, 0.378162533, + -0.8877857327, -1.9807964563, -0.3479121625, 0.1563489735, 1.2302906513, 1.2023798227, -0.3873268068, -0.302302748, + -1.04855299, -1.4200179577, -1.7062702179, 1.9507753849, -0.5096521974, -0.4380742908, -1.2527953386, 0.7774903774, + -1.6138978004, -0.2127402872, -0.8954665661, 0.3869025111, -0.51080513, -1.1806322336, -0.028182229, 0.4283318818, + 0.0665172189, 0.3024719059, -0.6343221068, -0.3627411723, -0.6724604368, -0.3595531583, -0.8131462932, -1.7262825966, + 0.1774261445, -0.4017809331, -1.6301983595, 0.4627822638, -0.9072983861, 0.0519453958, 0.7290905714, 0.1289829165, + 1.1394007206, -1.2348258495, 0.402341634, -0.684810102, -0.8707971573, -0.5788496733, -0.3115525246, 0.0561653413, + -1.1651498079, 0.9008265138, 0.4656624496, -1.5362436771, 1.4882521629, 1.895889163, 1.1787796021, -0.1799248308, + -1.0707526207, 1.054451704, -0.4031769335, 1.2224450111, 0.2082749754, 0.9766390324, 0.356366396, 0.7065731883, + 0.0105000203, 1.7858705521, 0.1269120872, 0.4019893706, 1.8831506968, -1.3477590084, -1.2704850435, 0.9693967104, + -1.1731233597, 1.9436211586, -0.4136189818, -0.7474548221, 1.9229420424, 1.4805147648, 1.8675589561, 0.906044662, + -0.8612256646, 1.9100649357, -0.2680033743, 0.8024563789, 0.9472519755, -0.1550100893, 0.6140793562, 0.9222066998, + 0.3764255345, -1.0994007587, 0.298238188, 1.3263858557, -0.6945678592, -0.1496345401, -0.4351535439, 1.8492637873, + 0.6722947359, 0.407461822, -0.7699160576, 0.5392491817, -0.6743326783, 0.0318305567, -0.6358460784, 0.6764332652, + 0.576590836, -0.2082987577, 0.3960067034, -1.0930615664, -1.4912575483, 0.4393917024, 0.1666734964, 0.6350314617, + 2.3831448555, 0.9444794655, -0.9128222466, 1.1170163155, -1.3159073591, -0.4615845978, -0.0682416037, 1.7133426666, + -0.7447548509, -0.8264385462, -0.0984525234, -0.6634783149, 1.1266359091, -1.0799314976, -1.1474686861, -0.4378200471, + -0.4980324507, 1.9295320511, 0.9494208097, 0.0875512436, -1.2254354954, 0.8443629742, -1.000215292, -1.5447710752, + 1.1880297661, 0.3169426024, 0.9208588004, 0.3187276423, 0.8568305969, -0.6510255933, -1.0342428684, 0.681594491, + -0.803409636, -0.6895498037, -0.4555324912, 0.0174791589, -0.3539939225, -1.3749512434, -0.6436184049, -2.2234032154, + 0.6252314448, -1.6020576954, -1.1043833494, 0.0521650799, -0.7395629883, 1.5430146456, -1.2928569317, 0.2670508623, + -0.0392828174, -1.1680934429, 0.5232766867, -0.1715463251, 0.7717905641, 0.8235041499, 2.1632359028, 1.3365279436, + -0.3691818416, -0.2393791825, 1.0996595621, 0.6552637219, 0.6401315331, -1.6169559956, -0.0243261252, -0.7380309105, + 0.2799246013, -0.0981503874, 0.9101788998, 0.3172182143, 0.7863279581, -0.4664191008, -0.9444462657, -0.4100497067, + -0.0170204137, 0.3791517317, 2.2593090534, -0.0422571525, -0.955945015, -0.3459817767, -0.4635959864, 0.4814814627, + -1.5407969952, 0.0632619932, 0.1565065384, 0.2321810424, -0.5973160863, -0.2379217297, -1.4240609407, -0.493319869, + -0.5428614616, 0.4160500467, -1.1561824083, 0.7811980844, 1.4944845438, -2.0699849129, 0.4262587428, 0.6769080162, + -0.6374370456, -0.397271812, -0.1328805834, -0.297790885, -0.3090129793, -1.6760038137, 1.1523315907, 1.0796185732, + -0.8133642673, -1.466424346, 0.5210648775, -0.5757879615, 0.1419531703, -0.3193284273, 0.6915387511, 0.6947491169, + -0.7255973816, -1.3833639622, -1.5829384327, 0.6103793979, -1.1888592243, -0.5068163276, -0.596314013, -0.0525672957, + -1.9362797737, 0.1887785941, 0.5238910317, 0.0884220898, -0.3108861744, 0.0974001661, 0.3990463316, -2.772592783, + 1.9559123516, 0.3900933266, -0.6524085999, -0.390953362, 0.4937417805, -0.1161039397, -2.0306844711, 2.0644929409, + -0.1105406582, 1.0201727152, -0.692049861, 1.5363770723, 0.2863436937, 0.608843863, -1.045253396, 1.2111452818, + 0.6898181438, 1.3018462658, -0.6280875802, -0.4810271263, 2.3039166927, -1.0600157976, -0.1359497011, 1.1368913651, + 0.0977249667, 0.5829536915, -0.3994490206, 0.3700558841, -1.3065268993, 1.6581306458, -0.1181640476, -0.680178225, + 0.6663830876, -0.460719794, -1.3342584372, -1.3467174768, 0.6937731504, -0.1595734358, -0.1337015629, 1.0777437687, + -1.1268258095, -0.7306777239, -0.3848797977, 0.0943515897, -0.0421714522, -0.2868871987, -0.0616264008, -0.1073052734, + -0.719604373, -0.81299299, 0.2745163441, -0.8909150958, -1.1573553085, -0.312292248, -0.157667011, 2.2567234039, + -0.7047002912, 0.9432607293, 0.7471883297, -1.1889449358, 0.773252964, -1.1838806868, -2.6591722965, 0.6063195467, + -1.7558906078, 0.4509344697, -0.6840109229, 1.659550786, 1.0685093403, -0.4533858001, -0.6878376007, -1.2140773535, + -0.4409226179, -0.2803554833, -0.3646935523, 0.1567038596, 0.5785214901, 0.3496544659, -0.7641439438, -1.4377914667, + 1.3645318747, -0.6894491911, -0.6522936225, -0.521189332, -1.8430695534, -0.4779739976, -0.4796558022, 0.6203582883, + 0.6984571218, 0.003770889, 0.9318483472, 0.3399649858, -0.0156821124, 0.1609281749, -0.190653488, -0.394849509, + -0.2677335441, -1.1280113459, 0.2804417014, -0.9931235909, 0.8416312933, -0.2494585812, 0.0494949818, 0.4938367903, + 0.6433144808, -1.5706233978, -0.2069036812, 0.8801789284, -1.6981058121, 0.3872804642, -2.2555642128, -1.0225068331, + 0.0386305526, -1.6567151546, -0.9855107665, -1.4718350172, 1.6481349468, 0.1642277539, 0.5672903061, -0.2226751, + -0.3534317613, -1.6164741516, -0.2918373644, -0.7614921927, 0.8579239249, 1.1411018372, 1.466578722, 0.8525519371, + -0.5986539125, -1.1158969402, 0.7666631937, 0.356292814, -1.768538475, 0.3554818034, 0.8145198226, 0.0589255877, + -0.1850536764, -0.8076484799, -1.4465347528, 0.8002979755, -0.3091144562, -0.233466655, 1.7327212095, 0.6845011115, + 0.3708249927, 0.1420617998, 1.5199948549, 1.7195893526, 0.9295051098, 0.5822246075, -2.0946030617, 0.1237219125, + -0.1301069558, 0.0939532295, 0.943046093, -2.7396771908, -0.569312036, 0.2699043453, -0.4668455422, -1.4169061184, + 0.86896348, 0.2768719196, -0.9711045623, 0.3148171902, 0.8215857148, 0.0052926461, 0.8005648255, 0.0782601759, + -0.395228982, -1.1594204903, -0.0859307647, 0.1942929327, 0.8758327365, -0.1151074693, 0.4574156106, -0.9646120071, + -0.7826291323, -0.1103892997, -1.0546284914, 0.820247829, 0.4631303251, 0.2790957689, 0.3389041126, 2.021043539, + -0.4688642025, -2.201441288, 0.1993001997, -0.0506035425, -0.5175190568, -0.9788298607, -0.4391895235, 0.1813384295, + -0.5028166771, 2.4124536514, -0.960504353, -0.7931173444, -2.2886199951, 0.2514844239, -2.0164065361, -0.539454639, + -0.2756705284, -0.7097279429, 1.7388726473, 0.994394362, 1.319136858, -0.8824188113, 1.1285940409, 0.4960009456, + 0.7714059353, 1.0294388533, -0.9087632298, -0.4243176281, 0.862596035, -2.6556191444, 1.5133280754, 0.5531320572, + -0.0457039624, 0.2205076516, -1.0299352407, -0.3499433696, 1.100284338, 1.2980220318, 2.6962239742, -0.0739246681, + -0.6585529447, -0.5142339468, -1.0180418491, -0.0778547525, 0.3827324212, -0.0342422798, 1.0963468552, -0.234215796, + -0.3474506438, -0.5812684894, -1.6326345205, -1.5677677393, -1.1791579723, 1.3014280796, 0.8952602744, 1.374964118, + -1.3322116137, -1.968624711, -0.660056293, 0.1758189499, 0.4986902773, 1.0479722023, 0.2842796743, 1.7426687479, + -0.2226056755, -0.9130792022, -1.6812182665, -0.8889713287, 0.2421179563, -0.888720274, 0.9367424846, 1.4123276472, + -2.3695869446, 0.8640522957, -2.2396039963, 0.4014990628, 1.2248705626, 0.0648561046, -1.2796891928, -0.5854312181, + -0.2616454363, -0.1822447777, -0.2028968334, -0.1098827794, 0.2134800553, -1.208573699, -0.2420198321, 1.5182611942, + -0.3846454322, -0.4438360929, 1.07819736, -2.5591845512, 1.181378603, -0.6319037676, 0.1639285684, 0.0963213593, + 0.9424681067, -0.2675947547, -0.6780257821, 1.2978458405, -2.3641738892, 0.0203341823, -1.3479254246, -0.7615733743, + 2.0112566948, -0.0445954278, 0.1950697005, -1.7815628052, -0.7290446758, 0.1965574026, 0.3547576964, 0.6168865561, + 0.008627899, 0.5270041823, 0.4537819028, -1.8297404051, 0.0370057225, 0.7679024339, 0.5898798108, -0.363858819, + -0.8056265116, -1.118311882, -0.131054014, 1.1330798864, -1.9518041611, -0.6598917246, -1.1398024559, 0.7849575281, + -0.5543096066, -0.4706376493, -0.2169495672, 0.4453932643, -0.3923889995, -3.046143055, 0.5433118939, 0.4390429556, + -0.2195410281, -1.0840365887, 0.3517801166, 0.3792355359, -0.4700328708, -0.2167314738, -0.9301565289, -0.1785890907, + -1.5504293442, 0.417318821, -0.9443684816, 0.2381031513, -1.405962944, -0.5900576711, -0.1104894057, -1.6606998444, + 0.1151478738, -0.3791475594, -1.7423561811, -1.3032428026, 0.6051200628, 0.8955559731, -0.1319086403, 0.404761821, + 0.2238435596, 0.3296229839, 1.2859840393, -1.5069984198, 0.676460743, -0.3820089698, -0.2242589295, -0.3022497296, + -0.3751471043, -1.2261961699, 0.1833391935, 1.6709430218, -0.0561330207, -0.0013850428, -0.6872990131, -0.1174745485, + 0.4661664367, -0.3702424467, -0.4538040459, 0.4032645524, -0.9180047512, 0.25249663, 0.8203217983, 1.3599485159, + -0.0903820097, 1.3675972223, 1.0344098806, -0.9962126613, -1.2179385424, -0.3049636483, 1.0289355516, -0.0722870082, + -0.6006575823, 1.5522432327, 0.286904484, -2.3205943108, 0.3171606362, 0.5200406313, 0.2256086618, 0.4497120976, + -0.0672756061, -1.318395853, -0.3707039952, -0.9456157684, -0.9327409267, -1.2630683184, 0.452489078, 0.0978961438, + -0.4481653571, -0.6493379474, -0.0234231055, 1.0791947842, -2.0042157173, 0.376876533, -0.5457119942, -1.8845858574, + -1.9457030296, -0.9127835035, 0.2195095569, 0.3930629194, -0.9389815927, 1.0170209408, 1.4229835272, 0.3960865736, + -0.5914026499, 1.1244192123, 0.7553957105, 0.8674074411, -0.6564636827, -2.8345544338, 2.1167910099, -1.6108783484, + -0.0357680731, 2.3807454109, 0.3305767477, 0.9492464662, -1.5023965836, -1.7776669264, -0.5327028036, 1.0907497406, + -0.3462494612, -0.7946363091, 0.1979672909, 1.0819351673, -1.4449402094, -1.2105430365, -0.7886692286, 1.0946383476, + 0.2348215282, 2.132153511, 0.936445713, -0.0350951776, 1.2650778294, 0.2114970088, -0.7049213648, 0.679974854, + -0.696326673, -0.2903971076, 1.3277827501, -0.1012814865, -0.8031414151, -0.4643376768, 1.0217906237, -0.5525406599, + -0.3868708611, -0.5102927685, 0.1839254946, -0.3854897618, -1.6018360853, -0.8871809244, -0.9327890277, 1.2433193922, + 0.8126740456, 0.5872593522, -0.5053583384, -0.8157915473, -0.5075175762, -1.0518801212, 2.497200489, -2.2453217506, + 0.564008534, -1.2845523357, -0.1043434888, -0.9880019426, -1.177628994, -1.1401963234, 1.754986167, -0.1329884231, + -0.765702188, 0.5557869673, 0.0103493147, 0.7200337648, -1.8242566586, 0.3036039174, 0.7726948261, -1.6615983248, + 0.4481952786, 1.6961815357, -0.0148577038, 0.8214059472, 0.6705704331, -0.707505703, 0.0397667363, -1.5669946671, + -0.451303035, 0.2656879723, 0.7231004834, 0.024612125, 0.7199837565, -1.1029062271, -0.1016972736, 0.019279385, + 1.8495912552, -0.2141666561, -0.4990166426, 0.0213512238, -0.9191134572, 0.1927538514, -0.3650552034, -1.7913275957, + -0.0585865527, -0.3175430894, -1.6324232817, -0.0671341568, 1.4893559217, 0.5213037729, 0.6119272113, -1.341496706, + 0.4768983722, 0.1484495848, 0.5290452242, 0.4226286113, -1.3597806692, -0.0414008126, -0.7578708529, -0.0500840954, + -0.8974009156, 1.3124703169, -0.8589723706, -0.8989421725, 0.0745864064, -1.0770990849, -0.4246633053, -0.8299645782, + 1.4111720324, 0.7858038545, -0.057469517, -0.3912170529, 0.9409176111, 0.4052040875, 0.4980524182, -0.0261922367, + -1.6882300377, -0.1124659851, -0.5324898958, 0.645055294, 1.0118424892, -0.657951057, 0.4683852196, 1.7358789444, + -0.6677127481, 1.6819217205, -0.8525858521, 0.0229597557, -0.0111456122, 0.0114989001, -0.8376780152, -0.591183126, + -0.6677202582, 0.3269625902, 0.3300351202, 2.2259442806, 1.370988965, -0.5098432302, 0.3248696029, 0.9971179962, + 0.0306018237, -0.0696415752, 0.0515749417, 0.8672766089, -0.8483205438, -0.3256694674, 0.4704331458, 0.311447084, + 0.2395827621, -0.3698011637, 0.972535789, 2.1338682175, 0.4064154923, -0.1931767017, 0.7557402849, -0.5391326547, + -0.7496903539, 0.0328087471, -2.5827965736, -1.1539503336, -0.347961843, -1.3533889055, -1.0326430798, -0.4367483258, + -1.6429653168, -0.4060717821, -0.5352701545, 0.0254052076, 1.1541839838, 0.1725044101, 0.0210620221, 0.0994544551, + 0.2273927778, -1.0167386532, -0.1147753224, 0.3087512553, -1.370759964, 0.8656529188, 1.0813760757, -0.6313759685, + -0.2413377911, -0.8781903386, 0.6993804574, -1.0612223148, -0.2224770039, -0.8589199185, 0.0509542786, -1.794229269, + 1.3264616728, -0.9646064043, 0.0598946847, -0.2125230432, -0.7621145248, -0.8877801299, 0.9363985658, -0.5256406069, + 0.2711701989, -0.8014968634, -0.6471814513, 0.4722471535, 0.9304084778, -0.1753164083, -1.4219198227, 1.9979560375, + -0.8565493226, -1.5415873528, 2.5944244862, -0.40403229, -1.4617327452, -0.6834397912, 0.3675448895, 0.1903115511, + -0.8517292142, 1.8227236271, -0.5215796828, -1.1846865416, 0.960693419, 1.3290628195, -0.8174930811, -1.4013472795, + 1.0304383039, -2.0473237038, -1.2266216278, 0.9674461484, -0.0553525463, -0.2639373541, 0.3528166115, -0.1527744234, + -1.2986867428, 1.2760753632, 1.3250139952, 0.2053325623, 0.0451340154, 2.3396248817, -0.276432842, -0.2595769763, + 0.3644812405, 1.4713219404, 1.5927706957, -0.258572638, 0.3083312511, -1.3780834675, -0.311976105, -0.8402903676, + -1.0068317652, 1.6815767288, -0.7922866344, -0.5316058993, 0.3658487797, 1.2978252172, 0.4811151326, 2.7593550682, + -0.0746679753, 0.2587164342, 0.2756006718, 1.4350494146, 0.5072389245, -0.1162296981, -0.947488606, 0.2444434613, + 1.4013447762, -0.410381794, 0.5289435983, 0.2461477816, 0.8635196686, -0.8047537208, 2.3466470242, -1.2791610956, + -0.3655510843, 0.9380925298, 0.2967331707, 0.829986155, -0.4961023331, -0.074804984, 0.0122319832, 1.5692596436, + 0.6904290318, 0.7966721058, -0.6579260826, 0.9688826203, 0.2255816609, 1.3891453743, 2.0140602589, -0.306765765, + -0.4063031375, -0.8640449643, -0.1435795128, -0.3820254505, 0.3595044017, -0.1445668191, -0.3615992665, 1.0645850897, + -0.937880218, 0.4331079423, -0.4059417248, 0.7243685126, 1.3852615356, -0.3030982614, 0.4410329163, 0.1787928641, + -0.7994223833, 0.2407875061, 0.2891204953, 0.4128708243, -0.198398903, 0.0941923037, -1.1476109028, -0.3581140637, + 0.5559626818, 0.8924738765, -0.4223148227, 0.1047140285, 0.2280533314, 0.2014799416, 0.5407735705, -1.8180776834, + -0.0493240692, 0.2390335947, -1.0003303289, 1.6739857197, 0.1615592688, 1.5634047985, -0.7905229926, -0.9073001146, + 0.224252224, -1.6786884069, 0.2149655968, 0.0972192287, 1.0156652927, 0.7010413408, -0.4174773395, -1.0974966288, + 1.7123051882, -0.7921150327, -1.0455245972, -1.0848560333, 1.1173052788, -0.5189002156, -0.7537044883, 0.1376898289, + -0.2069447041, -0.6780954599, 0.7539914846, 1.065315485, 0.9853175282, 0.7669196725, 0.402625531, -1.7758879662, + 1.6692508459, 0.3019891977, 0.6081564426, 1.1149623394, 1.4333524704, 0.4183980227, 0.4355461597, -0.5992242694, + 0.0330897495, -0.8541612625, -0.7199405432, -0.8935744166, -0.1560238898, 1.0490932465, 3.1709747314, 0.1894996315, + -1.3484131098, 1.2649832964, -0.3007838726, -0.6606085896, 0.2098494768, -1.240624547, 0.2224631608, -0.0883755237, + 0.0983779058, 0.3814162612, 0.0674922541, 0.0163380839, 0.2843145132, 0.4154006243, -1.0314824581, -1.4299912453, + -0.0616380535, -1.4327354431, 0.0875314698, 0.9387468696, 0.6071116924, -1.0481704473, -0.8602624536, 0.3283012807, + -0.4012978077, -0.316655308, 0.5969064832, -0.9872866869, -0.4012347162, -0.8000825047, -1.0431294441, -0.8570781946, + 0.6774621606, 0.0518203899, -0.8791606426, -0.2311016023, -1.6388072968, -0.7333127856, 2.1495745182, -0.0902438462, + 0.7316589355, -0.0654883757, 0.3481692374, 0.6632580757, -1.104616642, -0.0309362579, 1.5788651705, -0.7955005765, + -0.566439867, -0.3076912761, 0.2690240741, 0.524917841, 1.2674117088, 0.4994982481, -0.0620531254, 1.2591670752, + 0.7041110396, -1.4956794977, 2.5263681412, 1.769921422, -0.1682142168, 0.3779101074, 1.3243587017, -0.172200799, + 0.7303518057, 1.104578495, -1.0148259401, -0.6023318768, 0.9214084148, 0.460814476, 0.9237965345, -0.1325680166, + -0.2890052199, -1.9986394644, -1.1460003853, 0.0470660962, 0.8245572448, 0.5311783552, -0.1282419711, -0.27177158, + 0.2171796262, 0.0782111809, 1.4045455456, 0.1464407742, -1.4812459946, -1.2725580931, 1.5187593699, -1.1711604595, + 0.7644974589, -0.2683727443, -0.1697582901, -0.1341327876, 1.2213850021, -0.1928418279, -0.0333192833, -1.530803442, + 0.2066905051, 0.5310425162, 0.239145577, 1.3978962898, 0.0551713556, 0.2989774644, 1.6485040188, -1.5500141382, + -0.4558253586, 1.4261587858, 0.9361291528, 0.6783800721, 0.8326507211, 0.3270662129, 1.6315973997, 0.3777591586, + 0.2398671061, 0.1589586735, 0.1928639561, -1.157017231, 0.7706730366, -0.1304397285, 1.8219151497, -0.0756504685, + 0.4209182858, 0.2466021925, -0.6255570054, 0.9921368361, 1.9050636292, -0.0147772199, -0.3004787862, -0.3550287187, + -1.8923618793, -0.1778131425, 0.2509981096, 1.0547579527, 0.9600477219, -0.4164990783, -0.2768229842, 1.1239053011, + -0.1734638959, -0.5100295544, 1.3925184011, 1.0375856161, 0.0187917911, -0.5937774181, -2.0118803978, 0.5897036195, + -0.8963696957, -1.9627319574, 1.584820509, 0.6479678154, -1.1390081644, -1.2144013643, 0.8709617853, -0.8779706359, + 1.2961498499, 0.6164593101, 0.5365965366, 0.4046954513, 0.191450879, 0.8805112243, -0.454080373, 0.0859519765, + 0.7519465685, 0.5629897118, -1.1949868202, -0.5004096627, 0.2528035045, -0.4080147147, 1.7746585608, -0.3931531906, + -0.1622184515, 0.7694301605, 0.3305327296, -0.1452744603, -0.7564935088, 0.3015140593, 1.0390964746, 0.4790952206, + -0.7781835198, 1.7367749214, -1.4465779066, -1.5826855898, 0.9605572224, 0.2258404791, -0.549498558, -1.0985707045, + 2.3207998276, 0.1170908734, 0.5342011452, 0.3178851008, 0.4348079562, 0.5400944352, 0.7324240208, -0.3752224147, + -0.2916419804, -1.7410228252, -0.7803044319, 0.2711127996, 1.0450233221, 0.5990395546, -0.3406923413, -1.2631728649, + -2.7773592472, 1.1517339945, -0.5892289877, -0.4484650195, 0.1315739751, -1.4055600166, -0.3497821689, 2.0234718323, + 0.5053869486, 0.3592491448, -1.5824944973, 2.243601799, -1.4227949381, 1.9223247766, -2.1150560379, 1.4053654671, + 1.6180542707, -0.8244091272, 0.4225803614, 0.5474805832, -0.8137944937, -1.4491176605, -1.3177173138, 0.541008234, + -0.0851156041, -0.5643010139, 0.9667680264, 0.5080679059, -0.7554627061, -1.2012015581, 0.5232617259, -0.5375833511, + 0.0992048606, 1.5762989521, 0.502328217, -0.8622670174, 0.1606611907, -0.9526449442, 1.6085221767, -0.5615787506, + 0.2072707415, 0.3077325821, 0.159250468, -1.9585489035, -1.4464210272, -0.4523502886, 0.3194318414, -0.1377792209, + -0.9571474791, -1.3484243155, -0.4015575349, -0.4684760571, 0.5128364563, -0.3263184726, 0.602707684, -0.5946497917, + -0.2559576631, -0.3480463922, -0.782366991, 0.6251186728, -0.8135960102, -0.5216414928, -0.0731196478, -1.2973796129, + -0.3249349594, -0.7113063335, -0.3881541789, -0.0599280037, -0.7999136448, -0.2200757861, 1.3086687326, -0.0257985573, + 1.1452621222, 0.3464944363, 0.7741606236, -0.7744589448, 0.1049071625, 0.133912921, -0.6126257181, -0.8228283525, + -1.4902653694, 1.4961396456, -0.9724028707, 1.3462210894, -0.4674931765, -0.8624932766, 0.6225191355, -0.6311919689, + 0.5684589148, -0.3328117728, 0.4804244936, -0.9681860805, 0.8313510418, 0.4879726768, -0.9196506739, 2.6429357529, + 0.5401230454, 2.2904670238, 1.6002677679, -0.1888347864, -0.4122717679, -0.4034591913, -1.8300285339, -0.6958351135, + 0.2467660308, 1.5259575844, -0.7727718949, 0.8820565939, -1.2525933981, -0.5863200426, -0.4576405883, 0.3718110919, + 0.4573096335, 0.9623417258, 0.7708369493, 0.2431682199, 0.3903649449, 1.5885306597, -0.510926187, 0.7747282982, + -1.8081439734, 0.4113342464, -0.4832495451, 0.0025711823, 1.0400862694, 0.1646438092, 0.8851875663, 1.4737647772, + 0.3890939653, 1.1710410118, -0.3265609741, -0.0082098823, -0.5226194263, 1.0429775715, 0.4140913486, -0.5072344542, + 0.1546688378, 1.0415683985, -0.0392679907, -0.9489328265, 0.1319117546, -1.9805655479, 0.7687706351, -0.4213275909, + -0.4693107307, 0.8756957054, -1.3651628494, 1.9470986128, -0.4802420437, -0.5232509375, 1.0212247372, 0.7086952925, + 2.4512298107, -0.2112059891, -0.1204066351, -1.4793159962, -0.3321022689, -0.7214313149, -0.4487670064, -1.7441877127, + 1.6606075764, -1.416603446, -2.8022027016, -1.188424468, -0.6038395762, -1.1495540142, 1.0983035564, -0.1378391832, + 0.0253856052, 0.610391736, 0.2860125303, 0.9785673022, -1.10947752, -0.5475180745, 0.6659671664, -2.5345544815, + -1.375184536, 0.5009922385, -0.4802490473, 0.9361075759, 0.8091803193, -1.1980929375, 0.4066570997, 1.2016978264, + 0.1474343985, -0.9774648547, 0.8793899417, 0.6354245543, 0.5426107645, 0.7159388661, -2.9946129322, 0.8809375763, + 1.808131814, 0.4366384745, 0.1927289963, 0.6964386702, 0.3382254839, 0.651781261, 0.0014710003, -0.7667048573, + -1.0043227673, -0.9981917143, -1.3730425835, -1.0677419901, 1.7612661123, 0.7540956736, -0.6250274181, -0.3903926909, + 0.1125575304, -0.6555450559, 0.0675168559, 0.7776041627, -0.0357427336, 0.3360157311, 0.8864915371, -0.2721317708, + 0.2847906053, -0.3093775809, -0.0285288692, -0.3247302771, -0.5288698673, 0.1737118512, 0.5665453076, 0.1463044435, + 0.498726964, -0.737931788, -1.2037352324, 0.4170435071, 0.6878814101, 0.0498572662, 1.3480358124, 0.9076988101, + 2.6805708408, -0.2008085102, -0.9988487959, -0.7401368022, -0.5654978156, 0.4760313928, -2.1580686569, 1.3185510635, + -0.2392965853, -0.2467935532, -1.0793431997, -0.1142255515, 0.0132397674, -0.1219449267, 0.3390592635, -0.5896320343, + -0.8958157897, 0.5483281016, 0.0986674502, 0.1971810609, 1.059027195, -1.0225644112, -0.8552404642, 1.2572196722, + -1.4828833342, -1.3094121218, 0.817861855, 0.2382001877, 0.1052321345, -0.0916594118, 0.0312675461, -0.0921121165, + 1.3554426432, -0.3981481194, -0.1613735408, 1.7944488525, 0.0275097024, 2.232016325, -0.1049797013, 1.3674149513, + -1.6553440094, 0.1536444575, -1.5844736099, 0.8444542885, -1.212867856, 0.2837695479, -0.2821958661, -1.1582032442, + -1.6193599701, -0.5110404491, 1.7406294346, -0.2934850454, 0.9172215462, -0.0570428669, 0.8767267466, -1.8269113302, + -0.403188318, 0.949405551, -0.1632549465, -0.0864552855, -0.4304619133, 1.1493793726, 0.2975143492, 0.044022277, + 0.6430545449, 0.5882249475, 0.2125870436, 1.5470315218, -0.0602875352, 0.2780810595, -0.6429525614, 0.1501152217, + 1.5877615213, -0.643257618, -1.133592844, 0.9967596531, -0.1487661451, 0.096004203, -0.0451133028, 0.0791217238, + 0.850530684, -0.8391242027, -1.0117740631, 0.0849681348, -1.6064397097, -1.3730535507, 1.8666831255, 0.7574683428, + -0.0100564715, 1.2380069494, -1.040599227, -0.315603137, 0.6234536171, 0.8906716704, 0.512916863, -2.5412387848, + -0.96808213, 0.4770680964, -0.355951488, 2.5402317047, 0.9265583158, 0.5580818653, -1.1169495583, -0.0352967381, + 0.2412039638, 1.1277836561, 0.8811311126, 1.0329891443, -0.9239119887, 1.4121516943, -1.3804306984, -0.5359145403, + 0.4307711422, -0.1498915851, -1.0060368776, -0.8215498328, -1.5482543707, 0.5319746137, 1.2605688572, -0.1003935039, + -0.4003488123, -1.4723229408, 0.9132019281, 2.2113044262, -1.7974557877, -1.0634329319, -0.6795930266, -0.5643178821, + 0.2273459435, 1.6142495871, 1.0085972548, 0.5275973678, -0.72392869, -1.119628191, -0.7967752814, 1.5480668545, + -0.0617433004, -0.4468362629, -0.1837557256, 0.8246182203, -1.3128496408, 1.4148740768, 0.1564762592, -0.216343984, + 0.4428461194, 0.218397066, -0.3441964686, -0.2527106702, -0.8688625693, 0.6563907266, -0.5319938064, -0.9562584162, + 0.1658635288, 1.3291412592, -0.0483446233, -0.6081012487, 0.4038960338, 1.9367125034, -1.451905489, 0.3822027743, + 0.2050866187, 1.1615338326, 0.9909091592, -0.186709106, -1.6845172644, 0.8065637946, -0.8351926804, -0.9467403889, + 1.1483505964, -0.9108504057, 1.4028447866, 0.3358447254, 0.3191184103, 0.307264775, -1.6384236813, -1.7763886452, + 0.2155530602, 0.56800735, 0.0826110318, -0.8215345144, 0.0189221036, -0.0820341557, -0.9571580887, 1.0139721632, + -1.7302761078, 0.588742435, 0.3843234181, 1.0097118616, -1.0053118467, 0.1014071479, 2.1711649895, 0.6620742679, + 0.1005812064, 0.5391612649, 0.0861768425, 2.1908979416, 0.9836362004, -0.0856149569, 0.2523314357, -0.3907980025, + 1.2098500729, -1.4061048031, -1.6047384739, 1.4587147236, 2.1531198025, 0.4683049023, 0.1127379388, 0.6572676897, + -0.6470535398, 0.1712435484, 0.0389087051, 0.6265642643, -1.557998538, -0.5070347786, 0.8449956179, -0.675593853, + -0.9933613539, 2.0420720577, 0.0381180011, -0.578918159, -1.6923704147, 0.7293463349, 0.699136138, -0.2987596095, + -1.1022301912, -0.0245494228, -0.8358560801, -0.9420936108, -0.1032127514, -1.0513904095, 0.2466489524, 0.6079925299, + -0.8396324515, -1.3682451248, 1.5612796545, -0.9402702451, -0.6599426866, 0.2130171657, 0.5993693471, -0.2563169003, + 0.4607943296, -0.4009861648, -0.9711706638, 1.4263168573, 2.4884417057, 1.6959695816, 0.1418066323, 1.8334354162, + 0.3557035029, -0.4772862792, 0.4663795829, -0.0943925083, -0.9831181765, -0.8983219862, 0.802051723, -1.8465319872, + 0.604136765, -1.6295835972, -2.1211764812, -1.8388465643, 1.9667639732, -0.196233958, 0.0865831822, 1.4192550182, + 0.9341797233, -1.3915052414, 0.8690063357, 0.1841812581, -0.3416780829, 0.0242909137, 1.2798119783, -0.8859664798, + 0.4008856714, -0.0096572367, -1.7971645594, -0.8022531867, 0.1932135522, 1.297342062, 1.0013309717, 0.5972124934, + -0.8152756691, 1.8012139797, 0.2152404636, -1.0063655376, -0.1829049736, 0.8962484002, 0.0076174983, 0.8868646622, + 1.1036939621, 0.4005306959, -0.8577026129, 0.1354546696, 0.0451658554, 1.8593463898, -1.6263219118, -0.134822458, + -0.5840935707, 0.3351056278, -2.437564373, 1.1149245501, 0.0137484875, -1.8447011709, -0.361113131, 0.608962357, + -1.5914478302, 0.0032222164, -1.0574736595, -0.5559850335, 0.0267383829, 0.1834502518, -0.4707424939, 0.2727963924, + 0.8179776073, -0.2789142728, 1.4315677881, 1.4622141123, -0.4287020564, -0.637840569, -1.664173007, -0.1265693307, + -0.3634377718, 0.7790512443, -1.5096615553, -0.2773914039, 0.9687443972, -0.7303571105, -0.7623615265, -1.4469403028, + 2.6205737591, -0.7474731803, -1.3003468513, -0.8038504124, -0.7742950916, -0.2693897784, 0.8253722191, -0.2983231544, + -0.9228233099, -1.4513385296, 0.0218573585, 0.042539075, 1.5309323072, 0.0924477354, -0.0990083143, -1.0506538153, + -0.3059525788, -0.4384744465, -0.370164156, -0.9592553973, 0.5383296013, -0.1424454153, -0.2003534734, -1.7140461206, + 0.4936440885, 0.4870153368, -0.8391293883, 0.9901213646, -1.3647582531, -0.021869909, -0.2712073326, -1.3171747923, + 0.1897026151, 1.7025702, 0.0676342323, -0.4630217552, 0.4470241666, 0.1057199985, 0.0277621318, -0.4255422056, + 1.4219756126, 0.4563633502, -0.5286706686, -0.1080038399, -0.7408667207, -0.6082911491, -0.6407257318, -1.1343115568, + 0.7772769928, -0.2910414636, 0.554127574, -0.6701259017, -0.0603624955, -0.711040616, 0.7196681499, -0.2484192997, + -0.7308735847, -1.641703248, 0.2756665349, -0.7083850503, -0.0157792177, -0.491730094, 0.9541895986, 0.5441447496, + 0.4472121, -0.6161211133, 0.4662900567, 1.7148315907, -0.8321860433, 0.1723391414, -1.6492170095, 1.3985620737, + -0.3979120851, 0.7825788856, -1.7232282162, 1.7975393534, -0.3568715155, 0.5456573367, 0.1508181989, -0.2554707825, + 1.6857923269, -1.6480462551, 0.2987136543, 0.9106456637, -0.0298561212, -0.1181707829, -0.1426877081, -1.2276364565, + 0.0381273851, 0.512717545, 0.0685992241, -0.2722761035, -0.4897250235, -0.2792966664, 1.2577441931, -2.0866348743, + 0.0400714576, -0.3277549148, 1.4558079243, 0.055492226, 1.4849256277, -2.1238899231, 0.4595848918, 0.2800578475, + 1.3905339241, -1.6413486004, -0.1550358087, 0.0660602599, -0.4957954884, 1.2165777683, -0.3386821747, 2.0347626209, + 1.0541778803, 0.9508336782, 0.5592989922, -1.06369555, -0.4310963452, 0.5727513433, 0.6775570512, 1.3071838617, + -0.4674410224, -0.8601533771, 0.8591042161, -0.8096265793, 0.8733118176, 1.1997361183, 0.4561530352, -0.3575790226, + 0.0410822257, 0.5934659243, 0.0101855183, 2.1982963085, -0.9906709194, -1.0026686192, -0.9768953919, -0.5895799398, + -2.1789314747, -0.629650414, -0.6532847285, 0.0785140246, 0.4178005755, -1.2402163744, 0.9000542164, 1.8022422791, + -0.2082851082, 1.5743712187, 0.1989894956, 1.9887318611, 1.1172834635, -1.5639046431, 0.0186273698, 1.0543249846, + 0.0305465814, -0.0368835293, 1.269764781, -0.7098541856, 0.0175156128, 0.3236257732, -0.3337909579, -0.0201291032, + 0.7750232816, 0.4328376353, -0.8087175488, -1.10412395, -0.7891021967, 0.0012484558, -0.1599397808, -0.8319575191, + -0.5981504321, -1.52003932, 0.417853713, -0.0400187261, -1.2597873211, 0.0286205038, 1.3426220417, -0.7399358749, + 1.3151376247, -0.3234574795, 0.1978281736, 0.0977508053, 1.4015234709, 0.1584338397, -1.1419013739, -1.3109704256, + -1.5329210758, -1.7119702101, 0.0461350605, -0.9583745003, -0.0808116123, -0.7038590312, -0.7707843184, -0.4808453321, + 0.7035855651, 0.9291451573, 0.3711725473, -0.9898225665, 0.6436312795, 0.688896656, 0.2746472061, -0.60362041, + 0.7088595629, 0.4228185713, -3.116856575, 0.6444520354, -1.9137426615, 0.6635615826, -0.1540724039, 1.1936116219, + -0.0981612131, -0.8866142631, -0.147353664, 1.0598063469, 0.0262466185, -0.114335157, 0.7435535192, 0.2103593647, + -0.0059274058, 1.3660600185, 1.5551140308, 0.6133262515, -0.2859591544, 1.4969110489, 1.1831195354, 0.7188971639, + -1.2160766125, 0.1406719089, -0.7436721921, -0.1590122581, 0.240056932, 0.1001594067, -0.4751751125, 1.2729537487, + -1.6961312294, 0.7301835418, -1.8574832678, 0.3825981319, -0.8869042993, 0.8783037663, 0.0864525214, 0.2477063835, + -1.018279314, -0.6545701623, 0.2072173953, 0.5835699439, 2.9290962219, 0.2228583246, 0.9760375023, -1.5569338799, + -1.3298919201, -0.3554947674, -1.1974277496, 1.4863992929, -0.4102186859, 1.3821818829, 1.4867824316, 0.0427797213, + 0.5017997622, -0.0560994744, 0.5384370089, 0.4833418429, -0.123649627, 0.5049699545, 1.7236962318, 0.713016212, + 0.3257996142, 0.1247695237, -1.0126731396, -1.0272969007, 0.323356539, -1.3693910837, -0.7663276196, 1.2815113068, + 1.9142297506, -1.6659560204, 1.6266496181, -0.2114382982, -0.0150050875, -0.1134116277, 1.0805441141, -1.6076766253, + 0.456163615, -0.9448701739, 0.5707885027, 1.5427963734, -0.0004173264, 0.3741550744, 0.4095517695, -0.7995935082, + 1.5116393566, 1.7064682245, 0.7017833591, 0.0732854307, -0.4618938267, -0.6264902353, 1.7108365297, 1.4144150019, + -0.0636614859, -1.5799305439, -2.8320119381, -1.0834267139, -0.1306203902, 1.4006890059, -0.6516562104, 0.5048154593, + 1.303180933, 0.1285363138, -0.142447874, -1.308763504, -1.2024753094, 0.4160996377, -0.2009075284, 0.1225313172, + -0.0472777151, 0.6641440392, -0.7846873999, -0.335580647, 1.8961821795, -0.7997861505, -0.2815754414, -0.5893867016, + 0.444781363, 1.0223922729, -0.4982116222, -0.431414336, -0.2789815962, 0.5298337936, -0.7393953204, -0.3759599626, + -2.3721938133, -1.3817449808, -0.1124437526, 0.8978641629, 0.2950757742, -1.0987684727, -1.4002561569, 0.1746800989, + -1.6528036594, 1.0659267902, 0.0638961941, -1.6073201895, -0.9659538865, -0.7243112922, -0.7731925249, -1.4899330139, + -0.8746625185, -0.6844015718, -0.7112857699, 1.1279566288, 0.1048278064, -0.9932572246, -0.3346216083, -0.8795570731, + -0.3000066578, 0.8755091429, 0.252270788, 2.2856011391, 0.3759274185, -0.9135944843, 0.8097407222, 1.0799312592, + 1.0941669941, -1.0942409039, -0.147637412, 1.1318119764, -1.6847289801, -0.4994167686, -1.4269376993, -0.932570219, + -1.0124571323, 1.2505698204, -0.2345380336, -0.863355577, -1.0356057882, 0.1416671723, -0.0111356275, 1.3440743685, + 0.5000166893, -1.4317977428, -0.6289806962, 1.0700725317, -0.6210827231, 1.7345721722, -1.0982894897, 0.5726133585, + -0.8612155318, -0.5095951557, 1.0985816717, -0.1270671636, 0.8134522438, 0.4732905924, 0.7538656592, -0.8881881833, + -0.2215743959, 0.4242526293, -0.8490728736, 1.6295000315, -0.7772280574, -0.3000035882, -1.0065590143, -2.1433081627, + 1.7969185114, -0.204338938, -0.4479148388, -0.1987150609, 1.4198639393, -0.9651066065, 0.6795678735, -0.4237882495, + -0.596670866, 0.5670582056, 0.9882405996, -0.5139029622, -0.7688491344, -1.1690957546, 1.1035038233, -0.57525599, + -1.8491307497, 1.4099521637, -1.369859457, 0.7794605494, 0.1834286451, 0.2879154384, -0.5843752623, 0.3655914664, + -1.6677799225, 0.5880377293, 1.5570100546, 0.8840271831, -2.0195400715, -0.9842090011, -0.1877949238, 0.4869373143, + -0.1066526771, -0.4932143986, 0.5953003168, 1.1641517878, -0.2322940081, 0.7289298773, -2.5790507793, -0.9375093579, + -0.3212589324, -0.4885662198, 0.3327982128, 1.0137505531, 0.5066690445, -0.6222254634, -1.5227681398, 0.5569640994, + -1.8381767273, 0.6530373096, -0.1884490848, -1.1758350134, 0.2872573137, -0.0028761027, -0.0365972929, -0.0842233002, + 0.4195241034, 0.9244340062, 0.4966152012, 1.0121332407, -0.0441397205, 1.6184593439, 0.5711098313, -0.5436940193, + -1.0938950777, 0.205796808, -1.3065215349, -0.9733759761, 0.239087075, -0.6078874469, -0.9333162308, -0.0344750471, + 0.0726778954, -0.2058340311, -0.3775469065, 0.8546427488, 0.3424273431, -0.2234261185, 2.4643218517, 0.1938317418, + 1.1320050955, -0.5609809756, -1.3629409075, -0.7917565107, -0.2680097818, -0.4966081977, 1.3363862038, -0.1200411245, + 0.4614688754, -0.0464811549, -0.4335543215, 0.0379960127, 1.7140514851, -0.7679485679, 0.7669904232, -1.0260072947, + -0.4596264362, 0.0035832059, 0.326375097, 1.4831286669, -0.0500826426, -0.8436155915, 0.6500419974, -0.3641698062, + 0.2386815697, -0.1162224412, -1.9434568882, 0.5082991719, 0.5833680034, 0.9266047478, 1.8004627228, -1.1951037645, + 0.5165074468, 0.4092949927, -0.419081986, 0.3971062303, 0.4996469617, -1.2186838388, 0.2462227643, -0.9179843068, + -0.651856482, -1.7747448683, -0.4733609259, -0.2035706788, 0.5498568416, 0.0008999266, -1.5422881842, 0.8621480465, + -0.1185866222, 0.4883705974, 0.9659361243, 1.4226047993, 1.9612269402, -0.0722387582, 0.311124444, -1.0783610344, + 1.0616002083, -1.1848874092, -1.8052517176, 0.830385983, -0.5216965079, 0.7776072621, 0.4080746472, -1.6300026178, + -2.7196793556, -1.0966017246, 0.0164914876, -1.2217763662, -0.6527614594, -1.4589407444, 0.1698779613, 0.0908259302, + -0.481392622, 1.3970652819, 1.4977149963, 0.5652672052, -1.7997711897, -1.1046901941, 0.4071303308, -0.6285575628, + -0.4870914221, 0.8989673853, 0.5108748078, 1.3141543865, -0.4292092919, 1.3752254248, -0.5541312695, 1.4994914532, + 0.1058346406, -0.8605097532, -1.6312195063, -0.3014723063, -0.2562327087, 0.8576619029, -0.1105905026, -0.4324319661, + 1.0770374537, -0.2248265594, -0.5762417912, 0.574608922, -0.489828229, 0.6588021517, -0.5969170928, -0.2229591757, + 0.1521769762, -0.3741263151, -0.0134514691, 0.8154719472, 0.4106017947, 0.4809698462, -0.6354304552, 0.8528297544, + 0.6695623398, 1.0044192076, -0.7263658047, -0.172458604, 0.633533895, -0.6088151336, -0.2261224687, 1.9258056879, + 1.9517610073, 1.2399405241, 0.9385851622, -1.0192511082, 0.5125622153, -0.3591165841, -1.0585719347, -0.5090058446, + 0.1156650707, -0.5473555923, -0.5507994294, 0.7920414805, 0.1441064924, 0.2334580868, 0.1118723974, -0.6757031679, + -1.3705719709, 0.3105646968, -0.5070366263, -2.0107822418, -0.3925672472, -1.0922179222, 0.6986502409, 0.5216252208, + 0.4968931377, -0.6650416255, 0.7315515876, 0.3196497858, -0.4098545313, -0.453337431, 0.8927081823, -0.4736040533, + 0.3036564589, 1.0339570045, 1.9093426466, 1.6638730764, 0.9008227587, -1.5059113503, -0.6890484095, -0.5480871797, + 1.6531498432, -0.6993179321, 0.386166364, 0.1008670628, -0.9351271987, 0.3818240166, 0.398296088, -1.2557748556, + 1.2228775024, -2.086509943, -0.5907571316, 0.9719703197, -1.1932578087, 0.3502659202, -1.2963603735, -0.0930241421, + -2.3137731552, -0.8425716758, -1.5429214239, -0.4017637372, -0.4152314067, -0.6736641526, 0.7979131937, -0.8868796229, + 0.6343866587, 1.6292757988, 0.1390641481, -0.857670188, -1.2493385077, -0.7097851038, 0.7046427131, 0.1555907279, + 0.9367952347, 0.7703309059, 0.1408106536, 0.4734882712, 1.8552461863, 1.415656209, -0.3027460277, 0.9896794558, + 0.5858508348, 1.1363880634, 0.6716165543, -0.9741674066, -1.619684577, 0.572627008, 1.9026181698, -0.7756640911, + -0.1880897433, -1.0357477665, 1.177829504, -2.3051669598, -2.2636601925, 0.375019908, -0.0823436454, -0.4796230197, + -0.3010948002, 0.5369879007, -0.4138039947, -1.0969250202, -0.9273629189, 0.8883388638, -0.5247419477, -1.3852776289, + 0.1021783277, 0.50499475, 1.3289607763, 0.2179033905, -0.6597112417, 0.4740078747, 0.7271748781, -0.0389053077, + -0.0445993915, 0.2601329088, -0.0698564947, 0.2501139045, -1.02191329, -1.1504377127, -0.8361113667, 0.6422109604, + 0.2587975562, 1.0402389765, -0.1866909266, -1.1436413527, 1.1445535421, -0.0187670551, 1.2834550142, 0.597946465, + 2.18861866, -0.2197729796, 0.9007239342, 0.8913640976, -0.555126369, -0.1724823117, -1.461738348, -1.5487961769, + 0.1265687943, 0.7930070758, 0.6380240321, 0.3400245905, 0.8630171418, -0.5896977782, -0.2725327611, 0.7375215292, + 0.4331187308, -0.210188821, 1.3207943439, -1.2920012474, -0.5186786652, -0.283397764, 0.8165348768, 0.0023851979, + -1.2614917755, 0.5140041709, 1.0875463486, 0.7393045425, 0.6191549301, -1.8743134737, -0.8998864889, 0.4820806086, + -0.0548881851, 0.5225576162, -1.2663426399, -0.0614947639, -1.3897809982, -1.9536786079, 0.2957790792, 0.8425887823, + 0.2456164211, -0.0329964794, -1.5620143414, 1.0061070919, -0.044044897, 1.9595620632, 0.9423143268, -2.0051255226, + 0.7550497055, -1.3965352774, -0.7594954967, -0.250756681, -0.0940624475, 0.3975652158, -1.0228550434, -1.1506919861, + 0.6006051898, -0.0132502681, 0.1743730456, -2.1936833858, -0.1771373898, -0.8907291889, -0.9206264019, 0.9219347835, + -1.0956711769, -1.0928965807, -0.3310106099, 0.4502888322, -0.8840147257, 1.2341440916, 1.449847579, -0.8814470768, + -0.2450817525, -0.7786754966, -1.6853821278, 0.3030110598, 0.7335948944, 2.0118641853, -0.8974094987, 1.3362350464, + 1.3423537016, 0.1978533119, 0.6021634936, 0.8732730746, 1.9740999937, 0.4778085649, -0.0601378866, -0.866168797, + 0.3053207695, 1.0241649151, 0.2446103543, -0.7799232602, 0.0890762061, -0.1291534752, 0.2647387683, -1.6618484259, + 0.550788641, 0.595423162, 0.444853425, -0.0037628172, -1.8059362173, -0.0193227921, 1.0607149601, -0.8601288795, + -1.989269495, -1.5405579805, 0.3140257001, 0.3728760183, 0.8862931728, -0.0552589968, -1.5003284216, -0.8185041547, + 0.8188393712, 0.1404959112, 0.6498296261, 0.4347887933, -0.2049605548, -0.1740068346, 1.8571022749, 0.4146742523, + -0.128587544, 0.4554199874, 0.2229058146, -2.1573562622, 0.6500844955, 1.8209393024, -0.7802798748, 1.454035759, + -0.2568697035, 0.293471396, 1.0703600645, -0.7200014591, 1.2424938679, -1.2142173052, -0.8751547337, -0.5935203433, + 0.6620053649, -0.3408744037, -1.5199744701, -0.2165328711, -0.7842214108, 0.7312936187, -0.3432350457, 0.0707740784, + -0.4054724574, 0.4339389801, -0.1835907698, 0.32519871, -2.5933885574, 0.0972508788, 0.4139136672, -0.1992800534, + 0.6693924665, 0.738607049, 1.3042138815, 0.1048116088, -1.9138007164, -2.2854993343, -1.6018409729, -0.0379070602, + -0.1573052853, 0.2762398422, -0.6252459288, -0.7364911437, 0.5550479293, 0.6559244394, -0.2566501498, -0.0384766571, + 0.4043143392, 0.5043435693, -1.1439807415, -0.7195738554, -1.2305459976, -0.5069066286, 0.8123335838, 0.5462718606, + -1.0980979204, 0.5122667551, 0.0858431086, -0.4939267039, -1.4064596891, -0.1748233736, 0.6799439788, -2.16309762, + -0.3961232007, 2.2542836666, 0.6726367474, 0.2598325014, -0.7371851802, -0.6783298254, -0.0832883939, 1.6028636694, + 0.4655891955, -0.8721584082, 1.1767870188, -0.2925941944, 1.6973464489, -0.5666030049, -1.0032657385, 0.174629584, + 0.9823269844, 1.0374448299, 0.1591917723, -0.988096714, -0.5053406954, -2.0182819366, -0.9131215215, -0.1784568131, + 0.3890021443, -0.3394543231, -0.0569790564, -0.3961854577, 0.7510253191, -0.8991129398, 0.8375478983, 1.9608807564, + 0.4727896452, -0.5270916224, -0.5362701416, 1.2098371983, -1.1265894175, -0.9538044333, -1.1644484997, -1.2785137892, + -1.0448163748, 0.789904952, 1.1022825241, -0.697073102, 0.2073340416, 0.7591567039, 0.1005642042, -0.9549427629, + -1.4704017639, 1.0104275942, 0.4961794019, 0.5769559145, -1.1076469421, 0.2349771857, 0.6289995909, 0.3140338361, + -0.745023191, 1.0122605562, -1.5276319981, 0.9287419319, 1.0810559988, 1.5723303556, -0.342492193, -0.9994300008, + 0.7938803434, -0.6992152929, 0.0439955108, -0.3174622059, -0.9020719528, 0.3209994733, -1.392015934, 0.5922057033, + -0.9669311047, -1.7317312956, -0.0501074605, 0.4316338599, 0.576934576, 0.8183537126, -2.3536403179, -1.0051444769, + 0.1066522971, 1.5190032721, 0.783744514, 1.9013400078, -0.5249394178, 0.2744169831, -1.0999708176, -0.4043522179, + -0.7352957129, -0.6339886785, -0.3934491277, 0.0027175399, 0.0222126637, 0.543453455, 0.1399884671, -0.344045639, + -0.5225785375, -0.3071317077, -0.4490371346, 0.4909710586, 0.8655251861, 1.2740445137, -0.7977027893, 0.4693722129, + -1.3946796656, 0.373174727, 1.0826722383, -0.1495895088, 1.0726360083, -1.1385679245, -0.8886452913, -0.1358098388, + 1.0222103596, -0.4174294472, -0.4535531104, -0.9916283488, 0.2028810382, 1.2466951609, 0.7006801367, 0.6966506839, + -0.2069744766, -0.5633093715, 0.6772459149, -0.0319110751, -0.1736082286, 0.8982406259, -0.1977874488, -0.8377762437, + 0.909188509, 0.0807198882, -1.0370293856, -1.1129058599, 0.0954118744, 2.3374097347, -0.3928205967, -0.336273849, + 1.5237711668, -0.0572811998, -1.448466897, -1.572796464, 1.2266639471, 0.666354537, 0.8261256814, -0.0577565581, + -0.7267120481, -0.2171631157, 0.1360312104, -0.8383111358, 0.5614498854, -1.2595961094, -0.3327587545, -0.2040078789, + -0.6910198331, -2.2055053711, 0.4478696585, -0.7557507753, 1.3257079124, -0.3419822752, -0.5413596034, 0.0915219486, + 1.0534397364, -0.5634076595, 1.0147377253, 1.4403036833, 0.9903228283, 1.6264314651, 1.2926460505, 1.5148823261, + 1.6043263674, 0.2080695331, -0.4292238951, -2.2622437477, -1.3227331638, -0.4482828081, -0.3817350864, -0.1527944654, + -1.0007604361, -1.5957776308, -0.1302231699, -0.1894179285, -0.8075540662, -0.7421521544, -0.940156579, -0.3965237439, + -0.8563027978, 1.2598752975, 0.2409967333, -0.972317934, -0.2804477811, -1.180285573, 1.0121682882, 1.3841867447, + 1.2520020008, -1.1446926594, -0.0912670195, -0.4015706778, 0.5620130897, -1.0079097748, -0.6758916974, -0.4132170379, + 0.1532884687, 0.6941286922, -0.3287276924, 0.6639650464, 0.8220763803, -0.2132152319, -1.2456581593, -1.1711903811, + 0.5917269588, -0.4762244225, -1.7126293182, 0.6129523516, 0.129554525, -1.4059671164, 1.1794199944, 0.8366360068, + 0.1387452483, -1.2743194103, -1.4023305178, -0.3070684969, -1.7139153481, 0.4050802588, -1.4108233452, 0.1649127305, + -0.2881314456, 0.7117852569, -0.9379475713, 0.2737294436, -1.3948402405, 0.7955495715, -0.1149617657, 0.4958506823, + -1.3205252886, 0.499084264, 0.3062033951, 0.3636978865, 0.3126339614, -0.1934638768, 1.2412992716, -0.1558979899, + -0.7391691804, -0.0587261915, -0.9505179524, -0.4639964104, -0.1772466153, -0.3795541227, 0.1993970722, 1.9457614422, + 0.5709498525, 1.0723006725, -0.5037094355, -0.5870162845, -0.3781780601, 0.8528891206, -2.1481184959, -1.0331647396, + 0.1023358479, -0.2240923643, 1.9677296877, 0.4476832151, -0.6621914506, -1.5776070356, -0.3405600488, -1.3032200336, + 0.4667506516, 0.1611063182, 0.3200319409, 2.0791766644, -0.9074659944, -0.1924042106, -1.2125157118, -0.0805985183, + 1.5932736397, 0.5687224269, -0.1144870445, 0.2516302466, -1.2108556032, -0.3937337101, 0.0852525756, 0.0994219854, + -1.5306162834, 0.3276231885, 0.2791965008, -0.3770512044, 0.004174999, -1.48349154, -1.4797955751, 0.1346872598, + -0.6677231789, -0.0115555199, 0.8394906521, -0.1739299297, -2.8106679916, -0.1506536454, -0.4810440242, -0.2346943617, + 0.8997308016, -1.5785301924, 0.2439566255, 1.5703039169, -0.6259431243, 0.472327888, 0.9663057923, 0.2102314383, + -0.6850969791, -0.7095209956, 0.7438001633, 0.5921490788, -0.7864683867, -1.1764731407, -1.2808066607, 1.6616518497, + -0.0679451227, 2.3602285385, 0.5555456281, 0.439522326, 0.3062724769, 0.999149859, -0.9660632014, 2.1600131989, + -0.1003017053, -0.7034000754, 0.3025610149, 1.0923389196, -1.0075548887, 0.5668693781, -0.7164441347, -0.5062735081, + -0.4894824326, 0.76354146, -1.1090726852, 0.1926161051, -0.3434178531, -0.8472101688, -1.2135236263, -1.2028883696, + -1.6337959766, 0.8961672187, -0.2416531593, 0.1586519331, 1.1781893969, -1.2201172113, -0.9415456653, 0.2547155321, + -1.8240795135, -0.5787085295, -0.9248930812, 0.3295224309, -0.4258158803, 2.0081493855, 0.9378913641, -0.8532384634, + -0.3873134255, -0.3475845158, 3.3065743446, -1.510199666, 0.2035396993, -2.0844321251, -0.0069374414, 1.9098905325, + -0.4084554315, 1.1045544147, -0.0661152229, -0.422498703, -0.2516563535, -0.5869026184, -0.6260582805, -1.3301943541, + 1.5068007708, -0.39307639, 0.2937743068, -0.8765318394, 1.1169905663, -0.2735557854, -0.0910326689, -1.8289766312, + 0.3959762156, 1.8115056753, -0.8690775633, -0.4582291543, -1.1383239031, 0.1291621774, 0.0640241951, 0.7050811052, + 0.5514735579, -0.8125160336, 0.2249480486, -0.3283011019, -1.0910329819, -0.12685588, 3.8016602993, 2.3151705265, + 0.1398265958, 1.7388571501, -0.045383364, -0.053138338, -1.9495717287, -0.9601055384, -0.7834992409, 0.1075190306, + 0.0139845349, -0.5789423585, -0.5888131857, -0.1661531329, -1.3814116716, -0.6126385331, -0.3812898695, -1.2489489317, + -0.3302378953, -0.8348071575, 1.2353824377, -0.2438037992, -0.1895456612, 0.4280281067, 0.5569683313, -1.7362418175, + -0.376784116, -0.9090323448, -0.1451702416, -0.5363325477, 0.1570694596, -0.9804592729, -0.5677672625, -0.5911596417, + 1.0825914145, 0.3680036664, 0.368888706, -0.2863182724, -0.3847178519, 0.5610029101, 0.7774339318, 0.0151467854, + 1.1416479349, 1.2741550207, -1.6646980047, 0.4303788841, -0.0426019281, 0.3882888258, 1.115976572, -0.920538187, + -1.6202740669, 1.1061915159, -0.9984846711, -0.6862195134, 0.2046208978, -0.6861017942, -1.5922106504, 0.0341897681, + -0.7814846635, 0.5978598595, -0.5060765743, -0.6884461641, -0.2100005448, 1.0521534681, 0.9079040885, -1.0932261944, + 2.7997076511, -0.3257763386, -1.1524157524, 0.8882319927, -0.361672461, 2.1537194252, 0.8474083543, -0.1987198442, + 1.5753068924, 0.8491151929, -1.2288951874, 0.8883941174, -0.5164874196, -0.0833262876, 0.1310544461, -0.8790960312, + -1.3333423138, 0.3677840233, -1.3882335424, -2.5752027035, -0.8361055851, 0.3310924172, -0.2698811293, 1.267130971, + 0.1837534904, -0.7663096786, -0.43958354, -1.4365413189, 1.0857971907, -1.3811000586, -0.9204076529, -0.1602862179, + 0.0023532645, -1.5026503801, -0.9055358171, 0.2650406063, 1.1297233105, 0.3490035534, -0.0258097611, -1.5624086857, + -0.6173423529, 0.5214942694, 1.0809466839, 0.8893759251, 0.1380716413, 1.2046004534, 2.8814606667, -0.5938619375, + -0.7631158233, 1.5184829235, 0.2354645282, 0.1123076901, 0.3923743367, -0.6544864774, -1.0347952843, -0.7771475315, + 1.2459462881, -1.4366406202, 0.4986546338, -0.5576874614, -0.3533668816, 0.7429509759, 0.8439888954, 0.3429765403, + -1.8731197119, 1.570964694, 1.3101965189, 0.0914368331, 0.0102578169, 1.8014491796, 0.9472242594, -0.0292944033, + -0.2923386693, -0.1935371161, 1.1772320271, 1.0399917364, -1.6134229898, 0.4646424055, 0.8641213179, -1.5064631701, + -0.0029647513, -1.777043581, 0.1294928342, -2.0832345486, -0.6817455292, -0.6110659242, -0.7088498473, 1.4515280724, + 0.53551054, -0.3995688558, -0.9330778122, -0.2387763113, -1.0291129351, 0.9730799794, 1.9967659712, 1.0531998873, + 0.3316903412, -0.165628776, -0.4051062763, 1.7452845573, -0.5759356022, 1.5610985756, -1.1315392256, -0.2962316573, + -1.7140566111, 0.1592341959, -1.2637276649, 1.6650494337, 0.4122722745, 0.537396729, 0.2826784551, -1.0925408602, + 0.1241182908, 1.8370807171, 0.0085549261, -1.0170161724, -1.8523426056, -0.7133269906, -1.7622288465, 0.8305173516, + 0.7811672688, -0.8756818175, 0.6139813066, -0.5764546394, -0.0456142835, 0.3719555438, -0.443960011, 0.4182033539, + -1.6857280731, 0.1174749881, -0.0349520221, -2.0463931561, -1.809690237, -1.859523654, 0.4143068194, 0.1239596233, + 0.2739575803, -1.3263784647, 1.1389738321, 0.9828411937, -0.7669630647, 1.1760603189, -0.2509224117, -1.7762050629, + -1.6326947212, 0.7337234616, -0.1040488109, 0.8812249303, -0.0883731246, 0.2676708996, 2.1235263348, 1.3968490362, + -0.4328272641, 0.3749687374, 0.4944454432, 0.7613911629, 0.0710088089, -0.493531853, -0.0036228173, -0.4802871048, + 1.6833672523, 1.2407262325, -0.2036150247, 0.4282922745, -0.1654592603, 1.1932411194, 1.0488804579, 0.568610847, + 0.8712642789, 0.6605708003, 1.1740618944, 0.5311313868, 0.1519005299, -0.5772256255, -1.5717507601, -0.0278483797, + -0.7410555482, 0.060009066, 1.1404883862, 0.1728246808, -0.4150016606, -0.853128612, -1.4301352501, 1.3328052759, + -1.7766909599, -0.9347830415, -2.3132019043, -0.3161415756, -0.3422845602, -0.4042944312, -0.0631299019, + -0.8212651014, -0.9136556387, 1.8178263903, -0.3340629339, 0.9076586366, -0.836771071, 1.6127285957, 1.5141820908, + 0.2310186774, -1.0995316505, 0.0870013833, 0.0473044999, 0.2396239191, -0.9782206416, -1.5230001211, 0.1623630375, + -0.0102913165, 0.0020750219, 1.0268006325, -1.4751604795, 1.0106936693, -0.7432275414, -0.3952220678, -0.8257793784, + 0.0896198601, -1.9058178663, -0.5680857301, -0.5157565475, 1.2639302015, 0.1506981403, 0.6955183148, 0.0059388145, + -1.0489003658, 0.9072048664, -0.8454413414, -0.526243329, 0.1820997745, 0.9455388188, -0.2013845444, 1.5105247498, + -0.5714784265, 0.665589273, 0.0036163009, 1.5466718674, 0.2144060135, -1.8773127794, 1.0883351564, -0.081548512, + -0.5530619025, 1.2229647636, -0.3313086331, 0.599986732, -0.7683833241, -0.8361301422, 1.8105818033, -0.7870327234, + -0.5847709179, -1.7083207369, 1.629982233, 0.397998333, 0.2377796322, 0.9751384258, -1.329336524, -0.5410467982, + -0.0914377347, -1.5484710932, 1.3114271164, -0.0184290502, -0.3232886493, 0.2362254858, -0.7525823116, 0.0451130047, + 3.4275386333, 0.6046820283, 1.6683111191, -0.3550831079, -0.7515689731, 0.3097035885, -1.3417049646, -2.3069577217, + 0.7315924764, 0.6413381696, 0.8338512182, 0.0281698741, 1.9783726931, -0.0873281881, -0.5539647341, -3.0064988136, + -0.0471658669, 0.831877768, 0.0068611987, 1.1242216825, 2.2948811054, -0.173350215, 1.2312535048, -1.585852623, + 1.0313191414, 0.0634904802, -0.2213905007, -0.1633989215, -0.1563034654, -0.3088029027, 0.1986729652, -0.1742921323, + -1.1557924747, 0.4170538783, -0.6078679562, 1.0479866266, -0.0338269658, 0.1270239502, -2.0492320061, -1.256680131, + 0.9396144152, -0.7338167429, -0.5324376822, -0.2779399753, 1.36374259, 0.3741379976, 1.3102645874, -0.2677477896, + 0.2131762654, -1.203243494, 1.1780312061, 0.1086482033, 0.0441290997, 0.3383155465, 1.4467921257, -0.2144951075, + 1.663038969, -0.8515225649, 0.4221846163, 2.0092184544, -0.4898147285, 0.2452558577, 0.877505064, -0.1378996968, + -1.5003532171, -1.0559593439, 0.5809326172, 0.8915153146, 0.784555316, 1.1464320421, 0.0719851926, 0.2082331777, + -1.5188686848, 0.3173289597, 0.6126807928, -0.5832113028, 0.6440017223, -1.8158888817, 0.7510995865, 0.3002843261, + 2.1106085777, 1.4130855799, 1.5069802999, 0.8173971176, 0.6466156244, -1.1816313267, -0.3350912929, 1.8267284632, + -1.4561644793, -0.4502818286, -1.4192340374, 1.4509518147, -0.5657813549, 1.5445343256, -0.41376248, -0.504132092, + 1.2785291672, 0.9388317466, -2.7162802219, 0.4511407912, 0.6001668572, 0.209806934, -0.6576579809, 0.0284084454, + -0.3980614841, 0.2113230228, -0.202394262, -0.6219281554, 0.1637704521, 0.8024389148, 0.2890059054, -0.5536423922, + 0.3362540305, 1.0697923899, 1.5954041481, 1.2075525522, 0.5373802185, -1.0091240406, -1.365552783, -0.2023812085, + -1.4091848135, -0.7847847342, -0.1701223105, -0.4842104316, -0.3279180527, -1.3280045986, 0.2314667553, 0.9965080619, + -0.548137486, 0.7257553339, 2.6627266407, -0.0918110311, 0.6512100101, 0.1967700869, 0.9696237445, -1.7186498642, + -1.056956768, 0.1434639245, 0.8869625926, 0.1305240244, -1.6645731926, -0.823613286, -0.7947061062, 0.3889919519, + -0.7620389462, -0.6808071136, 1.0847475529, 1.3353163004, -0.4132747948, 0.4249026775, -1.8814837933, 0.1983270645, + 1.1899780035, 0.5267816782, 0.101060845, -0.3886429667, -0.6467919946, -0.1790824085, -1.5514411926, 1.6104589701, + 0.5642106533, -0.1024370342, -0.6198047996, -0.0703396201, 0.7977949381, 1.0114479065, -0.9036909342, -0.9735287428, + 2.0782299042, 1.136592865, 0.7085199356, -0.138646245, 0.92402035, -1.2732331753, 1.5317684412, -0.035772223, + 0.7908614874, 0.6462177634, -0.1315709054, -0.175366357, 1.221583128, 1.026497364, -1.772231102, -1.6924057007, + -0.9462206364, -0.8935453892, -1.1185258627, 0.272110641, -0.463704437, 1.2061246634, 1.4528777599, -0.0286832377, + 1.6834579706, 0.0242143106, -0.4347906411, 0.0647857413, 0.9448599815, -1.6144609451, -0.208599329, 0.2974056602, + 0.3630846739, -0.3684363365, 0.4887857437, 0.292121619, -0.5919080973, 2.1815986633, 0.4395501912, -0.3311833441, + -0.5717190504, 1.0294089317, 0.102059789, 2.5481126308, -0.4359241128, -1.2426069975, -0.0276984591, 0.1750674546, + -2.1184506416, -0.3091685176, -0.3684154451, -0.3687635362, -0.630225718, -1.3431925774, 0.758038044, -0.583840847, + -1.0237014294, -0.7599342465, -0.4723232388, 0.108647123, 0.6683390141, -0.9531794786, -0.4792973995, -1.345507741, + -3.3922998905, 0.1557939351, 1.5200035572, 0.5220832825, -0.5070599318, 0.0964791402, -1.1748200655, -0.1222923547, + -0.4277092516, -0.8527142406, 0.405652225, 2.5998671055, 1.6654495001, -0.07207302, 0.8841146827, 0.8627074361, + -0.6475380063, 0.6439040899, -1.4409921169, -0.805298388, 0.2387528718, -0.4147876501, 1.7564786673, 0.6480404139, + -0.3820381165, -0.4705797136, 0.1869706064, -1.0555312634, 0.5956119299, -1.3753019571, 0.6230102181, -0.1645947248, + 0.4146135151, -1.0125858784, 0.2449852079, 2.4123477936, -0.4572167397, 0.3173998594, 1.5055669546, 0.7617041469, + 0.4318854809, -1.0136892796, -1.2775883675, 0.0534324422, -0.4632358551, -0.0190582145, 0.2056566775, -0.6764278412, + 0.4941030145, 1.8585561514, -1.0093410015, -0.4695463479, -0.0496106595, 1.1404596567, -1.1863820553, -1.0651481152, + -2.1636610031, -0.440362215, 0.6801457405, 1.0652247667, 0.3571536541, -0.6009569764, 0.706471622, 0.2043185979, + -1.9207055569, -1.2280948162, 1.5118652582, 0.3222050965, -1.374794364, 0.819953084, 1.0614349842, -0.4350340366, + 0.6576821208, -3.7401006222, 0.9735767841, 1.1751554012, -1.124702692, 0.2820853889, -0.3381205499, -0.1025294811, + -0.424880445, -1.3322954178, 1.8904037476, -0.3103108406, 0.104755044, -1.0094006062, -1.0368671417, 0.4125984013, + 0.5263921022, 0.8779241443, 1.1037739515, -0.2102075368, -0.4442030787, 0.7468138337, -0.6374391913, 0.8717585206, + 0.3745002747, 1.1550264359, 0.6703916788, -1.0544458628, -0.8656336665, 0.7324852943, 1.9070558548, -1.3228117228, + 0.023211604, 0.2816745639, -1.5257774591, 0.478125006, -0.0931227952, -2.0965573788, 1.6217279434, -0.8632082343, + -1.2825033665, 0.4201416075, 0.5574867725, 0.7364113927, -0.3860033751, -0.0109143378, -0.7308067679, -1.3101973534, + 1.0791306496, -0.1027626842, -0.1823142618, -1.9992675781, -0.1783711016, -0.8424944878, -0.1746136546, -0.2192441523, + -0.446464777, 0.9388386607, 0.4470541477, 1.1271544695, -1.3248273134, -0.6489559412, -0.0402808189, -0.4066389799, + -0.0792577267, -1.1821033955, -0.7161780596, -1.641553998, -0.8900255561, 0.6941767335, -0.2142068893, 1.5057532787, + -0.5955338478, 0.1190710813, -1.213252306, 2.6006717682, -0.1786205918, 0.8296298385, 0.4133850336, -0.5838788152, + -1.3309012651, 0.1561431289, -0.5567897558, -0.1555043012, 0.6513020396, 0.0782411546, 0.3771162927, 0.1500465721, + -1.4672492743, 1.3960622549, 1.1758522987, -1.1361649036, 0.5053006411, -0.6620242596, -0.7469163537, -0.0048416615, + 1.7476682663, 1.05795753, 0.6052213311, -1.1506056786, 2.5544493198, 0.8737310171, -2.3488373756, 0.3994743228, + -0.4886947274, 0.4099823534, 0.4006403685, -0.9185190797, 1.8258857727, 0.1997846216, 0.9413478971, 1.3514236212, + -0.7381575704, -0.911768496, 1.1219073534, 1.3928374052, -1.3770185709, 2.0112431049, -0.2355033159, 0.6917845011, + 0.5643882155, -0.9713423252, -0.8640481234, -2.0835924149, -1.1511501074, -1.482475996, 0.0401905142, 1.3694021702, + -0.0271449313, 0.3388541639, 0.7780035138, 0.6797094345, -0.3858315051, -1.4633450508, -0.4298055172, 0.0629593581, + -0.8716452122, 0.3619607091, -0.2927120924, 0.6218215227, -0.8032394648, -0.9219676852, 1.7740563154, 0.0287562385, + 0.5529638529, -1.0984222889, -0.3772644699, 0.682169497, 1.5656158924, -0.7244850993, -0.8029174209, -0.0226689409, + -1.5243951082, -0.030133307, -0.0647283867, 0.7247491479, 1.4146097898, 0.5698443055, 0.7415510416, 0.0522789508, + -0.3597445786, -1.9959769249, -0.8862208128, 0.2172666788, -1.6455937624, 0.2428898215, -0.4008347094, -1.0215598345, + -0.4700243175, 0.7287815213, 0.8855010867, -1.9370213747, -0.1494840086, 0.9138846397, -0.2578948736, 0.1088152677, + -1.4954109192, -0.4800336659, 1.8287754059, -0.7880680561, -1.4406323433, 0.1494717598, 0.788629353, 1.193810463, + -0.5177226663, 0.2224755734, 0.544354856, 0.6492105126, -0.5472027659, 1.7127249241, -0.6872970462, 0.7078721523, + -0.0219112355, -0.5872185826, -0.6428512931, -0.5863469243, -0.4468710721, -1.0188856125, 0.6974096894, -0.7035152912, + -0.6150208712, 0.4886905849, -0.1079619452, -1.4219036102, -0.9360095263, -0.1965572387, -0.5749878287, 0.7504825592, + -0.7644020319, -0.9671270847, -1.0105462074, 0.4066572487, 0.4834717214, -1.672444582, 0.6220752001, 0.8609732985, + -1.6909977198, -0.690431416, 1.428892374, 1.0061017275, 0.02479266, 0.501249373, 2.1120195389, 0.502796948, + -1.2208088636, 1.3649389744, -0.8709388971, 0.9939022064, 0.6562706828, 0.8895135522, 1.540933013, -1.4659143686, + -0.0695885569, 1.9460494518, 0.9763817191, 0.1771583408, -1.0231730938, 0.1067204922, -0.9118813276, -1.4683669806, + 0.5764787197, 0.0653056055, -0.7735127807, 0.3949481845, -0.5038898587, 1.7795591354, -0.0305724442, 1.5770882368, + -0.8128020763, 0.6133491397, 1.8436999321, 0.2710909843, 1.1364476681, -1.7383319139, 0.7071347237, 0.0303861313, + 0.7650019526, 0.8676652312, -2.2562501431, -0.4436027408, -0.6700232625, 0.152164191, -1.9405333996, -1.0905086994, + 1.0019207001, 0.1768924445, -1.0880144835, -0.2532173693, 1.0982730389, -1.8395668268, -0.2114286125, -0.2296632379, + 0.186979413, 0.5037794709, 1.9103424549, 0.5537812114, -0.5874814391, 1.2579499483, -0.8586683869, 0.4361870885, + 1.5714631081, 1.0773148537, 0.8110896945, -2.2315375805, -0.1010025144, -0.5873750448, 1.3248683214, 0.8406484723, + 0.2611061931, 0.7944416404, -0.6496164799, 0.6342844963, 0.0950026661, -1.6832067966, 0.3440461457, 0.7071580291, + 1.1934145689, 0.5273885131, 1.0067039728, -1.732327342, -0.3734121621, -0.1425103992, -0.329742372, -0.0890421197, + -0.5773962736, 0.7361654639, -0.9912055731, 0.1251746118, 0.0731527135, 0.1439372301, -0.9477243423, 1.3992298841, + -0.2261237204, -1.4388542175, 0.8013010025, -0.0033314459, -0.0969415605, -0.0958714485, 0.3954369724, -0.053243041, + -0.773499608, -1.4191855192, 0.3034519255, -1.5182067156, 1.1197077036, -0.9538609385, -0.8496140242, -0.9818996787, + -1.3630776405, -0.7725985646, -0.2836254537, -2.3276040554, -2.4452273846, -0.7158649564, 0.8833968639, -1.3004398346, + -0.0763390809, 1.4305567741, -1.3234086037, -0.4383561611, -0.7431524992, 0.8919675946, 0.4638727605, 0.6176608205, + 2.4964170456, 1.6294752359, -0.0990447029, -0.2019919604, -1.4488258362, -1.7141647339, -0.0496415719, -1.299395442, + 0.6253554225, -0.7917193174, -0.5829433799, -1.5526804924, 2.1101534367, 0.7588295341, -0.7099302411, 0.1511470377, + 1.3230912685, -0.9278250933, 1.9065986872, -1.0321749449, -0.1773614883, -1.6503783464, -2.5385110378, 1.0100908279, + 0.0857020915, -1.7338609695, -1.6406011581, 1.1453614235, -0.1505951136, 1.4314432144, 0.6365867853, -0.0665628463, + 0.0323299803, -0.5550736189, 0.0977861062, -0.0609849803, 0.8375166655, -0.163418442, 0.8235554695, 0.9206323028, + 0.1807626039, -1.3129683733, -0.1604766995, -1.9060746431, -1.2066216469, 0.7304183245, 0.494892776, -0.0032088785, + -0.3024331629, -0.7394009233, -0.512812078, 0.9652515054, 0.4766792655, -1.3712165356, 0.1988528371, 0.1399628371, + 1.6486734152, -1.7575517893, -0.7831295133, 0.9736258388, -1.1109322309, 2.3856215477, -1.1789442301, 0.0291221458, + 0.5595475435, 0.8810371161, 0.7152084708, -0.4620775282, 0.9132069945, -0.7546525002, -0.534977138, 0.4566424489, + 1.5095769167, -0.2281712443, -0.8903415203, 1.2097718716, -1.2648000717, 1.8381814957, -0.9840826988, 0.6409484744, + 0.9266912341, 0.7850340605, 0.2270026356, 0.0495295525, -1.65318048, -0.7808196545, 0.7246446609, 0.6633691788, + -1.0378812551, 0.346979022, 0.2520309985, 1.7509188652, -0.4184011519, -0.5198572874, -0.9234429598, -0.9992784858, + 0.3749483526, -0.7043411136, 1.0747038126, -0.6272990704, 1.5339956284, 0.4177254438, 0.2583836317, -1.1504285336, + 0.3291141987, 0.0455219783, 0.6320825815, -0.5108472705, -1.4536298513, 0.2752215862, 0.1397872418, 0.2438923568, + 1.0056501627, -0.9396406412, -2.3817501068, 0.4750269949, 0.4059125185, -0.4770562947, 0.1705982089, -1.0477807522, + -2.1061971188, -1.6929115057, 0.0423611403, 1.3827104568, -0.3895183802, 0.8139379025, -0.5943319798, -0.0554390214, + 0.7965607047, 0.1331798881, -0.541678369, -0.8653023839, -0.0925281271, 1.1821020842, -1.5706546307, 0.8593307734, + 0.2836470008, -0.969112277, -0.0183737297, -0.204035446, -0.947740376, -0.5394350886, -1.2562873363, -2.0715236664, + 0.1512364447, 1.0444895029, 1.633349061, -1.1113785505, 2.1473650932, 1.5263067484, 1.4234750271, -0.7856664062, + -0.5622516274, -1.9383574724, 0.1911592335, -0.3936029375, 0.1617906839, -0.8345180154, 0.6728704572, 0.343188107, + -1.1441230774, -0.0458879471, 0.284684509, 2.0084414482, 0.0957808495, -0.9404090047, -0.3162630498, -0.0312234666, + -0.1335952878, -1.8414719105, -0.3315768838, -0.6933088899, -0.260512948, 2.1209623814, -0.8322905898, 1.4379409552, + 1.160618186, 0.6834978461, 0.0031104183, 0.6543934345, -0.44991979, -0.5464591384, -0.7478616834, 0.2739015818, + -0.2097705752, -0.2395850718, 1.4202288389, -0.7047485113, 0.7353649139, -0.5219275951, -1.592195034, -1.425950408, + -0.4915523827, 0.6296114922, 0.6417863965, -0.2406871468, 0.6184217334, 0.0762631074, -0.2614903152, 0.8547312617, + 1.1878938675, 1.0160274506, -0.3068729639, 0.5677075982, -2.1292457581, 0.1950669289, 0.3610023558, 0.1519751996, + -0.2222727239, 1.3047732115, -0.0932376981, -0.1395379305, -0.2409367412, 1.0341054201, -0.2924596369, -0.8343493938, + -0.108758539, 1.7077137232, -0.300686121, 0.6157716513, -0.2781107426, -0.2767468095, -0.5608413815, -1.2163040638, + -0.1097816303, 0.7184557319, 1.576192975, 0.4418694973, -0.816861093, 0.7455046177, 0.4540291727, 1.3983632326, + 2.0896103382, 1.2146077156, -0.3927581906, -0.1592295468, 1.1579405069, -0.5076931119, -0.1404834688, 0.6343402267, + 1.0706061125, 0.2229107618, -2.8925197124, 0.3393659592, -0.3120492101, -0.9759209752, 0.0241301656, 1.1204642057, + -1.1298772097, 1.5899230242, 0.9787300825, 0.93416363, -0.8147085905, -0.2512424588, -0.3828348815, 0.0003409579, + -0.0622048005, -0.3173488677, -0.177927345, -0.2116203159, 0.2674838603, -1.6518170834, 0.4865783453, 1.6972717047, + 1.0725008249, -0.9458972216, 1.0446079969, 2.2896277905, -0.242556259, 0.7210319042, 2.2993803024, 1.0302956104, + 1.5507205725, -1.0952255726, 0.2356208563, 0.3919691145, 0.5642871261, 0.7895075679, 0.1561750621, -1.3123941422, + 1.066272378, 0.3788603246, -1.178616643, 0.758995831, 0.5529800057, 0.5370345712, -0.2868351936, 1.6344056129, + 0.5712266564, -0.7899540663, -1.542757988, -0.7673321962, -2.3696231842, -0.2605598569, 0.1289570481, -1.2076663971, + -0.5454435945, 1.5532826185, 0.1072913334, 1.5353435278, -0.1849514097, -0.1767827123, -2.1992540359, 0.7292887568, + 1.1005582809, -0.3423680365, -0.3103042245, 0.8130363822, -0.736297071, -0.7823243141, 0.3170981705, -0.606251359, + 0.6110578775, -0.9203095436, 1.5095089674, 0.6564636827, 0.0658511817, -0.8736306429, -1.0577539206, -0.8972370028, + -1.4322032928, 1.3404302597, 0.3420748413, 1.0706282854, 1.7390650511, 1.3066060543, 0.4496167898, -0.4110504389, + 0.7492995262, 0.2111377716, -0.2606511414, -0.51519835, 1.0792167187, 1.4774627686, -0.2751087248, -0.4370077252, + 0.6981697679, -0.6351764202, 0.6036766768, 1.7369296551, -0.4178344309, 0.0245132316, 1.9896930456, -0.3731683195, + 0.141036734, -0.9418154955, -0.7028346062, -1.3788369894, 2.9252495766, 0.5717520118, -0.0458755493, -1.0570642948, + -1.8246930838, 0.2417382896, -0.1451518238, 0.5019926429, 0.6923288703, 1.0122750998, -0.0421771109, 0.6220104694, + -0.4075361192, -0.8514463902, -0.338183254, 0.7689677477, 0.6064976454, -0.0126131419, 0.3224277198, 1.6075083017, + -1.8024101257, -1.2550679445, -0.0130337598, 0.7003573179, -0.2152732313, 0.9030884504, -3.0074372292, -2.3304672241, + -0.5678032637, 2.6673221588, -0.0000683526, -2.2414488792, -0.3600297272, 0.6174938679, 0.9622223973, 0.470548898, + -0.2358042002, 0.6787893176, 1.1536179781, -0.5547327995, -0.1236007586, -0.1360976994, -1.7055424452, -1.2570964098, + -2.3186249733, 0.0843379274, -0.2976732552, -0.3390328884, -0.0344037488, 0.5192691684, -0.6725831032, 1.1736112833, + -1.5922294855, -0.013649201, -0.0983454883, 0.8498770595, -0.4949856997, 1.0687308311, -0.2338664085, -0.1018051058, + -0.1490771621, 0.6980962157, 0.8531481624, -0.6047407985, -1.4088909626, -0.9811016321, 0.1651830673, -0.0166458562, + 0.1409326643, -0.7251721025, 0.7957408428, -0.1764385402, -1.6334345341, 0.1553497761, 0.5474259853, 0.1437603086, + 0.1302209795, 0.2271719575, -1.0537291765, 1.5317530632, -0.3264935911, 1.4668451548, -0.5541288853, 0.9666754007, + 0.240179643, 0.1003144309, -0.9387914538, 1.2058185339, 0.4189720154, -0.0902500674, 1.2073749304, 0.0885801986, + 2.2098054886, 1.0166771412, -0.33070907, 1.3583818674, 0.0608563833, 2.0058913231, 0.0816583633, -0.079209365, + 0.093968302, 0.3995066881, 1.5493112803, 0.2928569317, -0.1067149267, -0.4934600294, 0.7856813073, -0.5543451309, + -1.1688302755, -0.9422464371, -0.4649276137, -0.1244343743, 1.0531721115, -0.5772435665, 1.1971284151, -1.6377062798, + 2.6346027851, -1.5864238739, 0.1980870366, -0.2175800204, -0.7853147388, 0.6764087081, 1.0572141409, -0.1721861064, + 1.2093849182, 0.0640576929, -1.0637799501, -0.0791875049, -0.5274960399, 0.4602147639, -0.399166882, -0.0741831958, + -1.0853574276, 1.0693564415, -0.3556284308, -1.0694770813, 2.6314742565, -1.4129743576, 0.507430315, -2.1636655331, + 0.3085227609, 0.1881135255, -0.2523779571, -1.3635439873, -0.8585309386, -0.8065607548, -1.1741236448, -0.9480458498, + 1.435125947, 0.3912090063, 1.3308275938, -0.9888421297, -0.4313032329, -1.7370495796, -1.1904556751, -0.2911131382, + -0.4206063449, 1.7773537636, 0.1080465764, -0.2650998831, 0.4594625831, 0.0268785525, -1.0857034922, -0.6268877387, + 1.3989568949, 1.3037877083, 0.2572353184, 1.0194852352, 1.6428092718, -0.4417257011, 0.184314847, 0.2210908979, + -0.826813519, 0.4464316368, -1.1436780691, 0.1022599861, -0.2689138949, 0.4295471311, -1.3548612595, -0.5210994482, + 1.8831641674, -0.1348460466, 0.0681441575, -0.6695713997, 0.0453709252, 0.3797713816, -0.4755639732, -0.249496296, + -0.1664597243, 0.2957374454, 1.1305173635, -0.6693257093, 0.8059806824, 0.8046057224, 0.2548323572, 1.0816518068, + 0.099068366, 0.1078162864, -0.1735524535, -0.2703637779, -0.2104981542, -1.8608211279, 0.6002736688, -0.3222564161, + -1.4688658714, 0.9703220129, -0.9755422473, 0.8594921231, -0.7415559888, 0.9588875771, 1.8989210129, -1.5950626135, + -0.2549622059, 0.956808567, 0.2796890736, 0.2816965282, 0.9156034589, -0.7888602614, -1.2830469608, -0.7138097882, + 1.3335521221, -0.7639064789, -1.5349581242, 1.1567809582, -0.5121814013, -0.4490087628, -1.3938723803, 0.5303887129, + 0.5679660439, -0.5504558682, -1.1937325001, -1.8920999765, 0.5680583119, 2.5964953899, 0.4043229222, 0.6083219051, + 0.1465612203, 0.3495765924, -0.2330164611, 0.2941886485, -0.8010068536, -1.2406933308, 0.1112386584, 0.0981622413, + -1.1744223833, -0.5514314175, -0.3500730395, 0.7157834768, 0.1586675495, -0.1676100791, -1.5922158957, 0.2704105675, + 0.5291992426, 2.1981124878, 0.4463334382, 0.9241107106, 0.9336605668, -1.812702179, -0.1246180162, -0.1696453393, + -0.4599695206, 0.8565337658, 1.6267207861, -0.9244696498, -0.1559941918, 0.4249975085, -0.7795513868, -2.1165361404, + -0.2150630206, -1.1040906906, -1.9384589195, 0.9018970132, 1.6354812384, 0.5289262533, 0.415963918, 0.4340830147, + -0.077607967, 0.4491689801, -0.1313019097, -0.7509349585, 1.2776517868, 0.7487615347, 2.6572730541, -0.8186072707, + -1.4451512098, 1.3417631388, -0.1051895544, 1.3567872047, 2.0140140057, -1.3726296425, -0.8574283719, -1.6812884808, + -0.1505986601, -0.7210639715, -1.9408824444, 0.0999050587, 1.2818363905, -0.970079422, 1.2453765869, 0.6968713999, + -0.0645520166, -1.0578403473, -0.4692222774, 2.1283955574, -0.3892408013, 0.5696129203, -0.2742994726, -1.0984168053, + 0.6897208691, 1.6492482424, 1.065132618, 1.6090450287, 0.1430166811, -0.0025570951, 0.5276804566, -0.2226212621, + -0.4914850295, -1.5938395262, 1.0183731318, 0.0496852174, -1.6018487215, -1.8184107542, 1.7716566324, 1.0756032467, + 0.3834027946, -1.4669975042, -0.2647817731, -1.0320789814, -0.3644350767, -0.216874212, -0.725282073, -1.3937695026, + 0.738705337, 0.2493469417, 0.5485517979, 1.1348981857, 1.1029473543, 1.6632301807, 0.9258661866, 0.4591159523, + -0.4123454392, -1.2897313833, 0.5902590156, -0.2920606136, 1.9976263046, -0.5045529604, 0.2800785005, 0.2846641541, + -1.4732339382, -0.7650971413, -1.9866602421, 0.2745036185, 0.186680764, 0.74376297, -0.7251886725, -1.059525609, + -0.3219626844, 0.4132559597, -1.0829941034, 0.3818486631, 0.4902530909, 0.8203164935, -0.3574656546, 0.0871377513, + 1.2285019159, -0.6999685168, -0.0382436216, 2.0060265064, 0.3040466607, 0.9432737231, 0.300478369, 1.0069338083, + 0.484680295, -0.2194198221, -0.2402843833, -0.2284196168, 0.6577883959, 0.0243720971, -0.0167382881, 0.0804451779, + 0.2744990885, 1.5632476807, -0.9265797138, 1.0785713196, -0.4262202978, -0.3350518346, -0.1482925713, -1.3545845747, + -0.6348443031, -0.135872066, -0.596770823, 1.2970815897, -0.824147284, -0.1672525704, -0.6040331125, 1.2512923479, + -1.3428666592, 0.4152507782, 1.1968697309, 1.4077038765, 0.1768872589, 1.7283319235, -0.9516835809, -0.551576674, + -0.5391194224, 0.2572713494, -2.1139318943, 0.948532939, 1.2312760353, -0.2881865203, 1.25819695, 0.573756218, + -0.9768746495, -0.6910295486, -0.5072914362, 0.3287530839, 0.9405872822, 0.6720070243, -0.620275557, 0.1128496304, + -0.6132038236, 1.5822707415, -0.3844380975, -0.0673749968, -0.2834100127, -1.1995179653, -0.0790346786, 0.8218730092, + -0.1707502753, -1.6510307789, -0.2086256593, -0.7109470963, 0.0523468554, 0.9653596878, -0.7002084851, -0.1555075496, + 0.0463614166, -1.4276753664, 0.3529338241, -0.2941586375, -0.9563120008, -1.3457732201, -0.042498108, 0.8205020428, + 0.4909951687, -1.1780422926, -0.3410792053, 0.4586801231, 1.1928086281, 1.5076155663, 0.2159299105, 1.076200366, + -1.3993560076, 0.5086227655, 1.592425704, -0.0414426811, 1.3759416342, 1.3556041718, 0.6253252029, 1.6755017042, + -0.2901961207, -0.2289954126, 1.5246464014, 0.3891948462, -1.2429443598, 0.0270989761, 2.9799761772, -2.3688035011, + 1.3221940994, -0.5086752772, 0.5284387469, 0.8252167106, -1.3484315872, -1.5581241846, -0.8698654771, -0.0978383347, + -1.6825011969, 0.6562595367, 0.5922316909, 0.2983350754, 0.2247846574, -1.3188779354, -0.3159044385, 0.041677516, + 0.7735174298, 0.1309816986, 1.6671591997, 0.6244473457, 0.054561384, 0.4523994327, 1.6147964001, -1.1268408298, + -0.3600841165, -0.3496910334, -0.6707585454, -0.9565799832, 0.5979391932, -0.4567743838, 0.6110959649, -0.4604537189, + -1.2620191574, 1.1980472803, 1.7984120846, 0.2246788591, 0.5230852962, 1.7367670536, 0.5086534619, 1.1650388241, + 0.7131203413, 1.3199769258, 0.3111094236, 0.2989323735, 0.6086726785, -1.3495463133, -0.8733163476, 1.3610419035, + 1.4206547737, 0.4303741753, -0.9519916773, 1.202767849, 0.0799262673, -1.1702611446, 0.6195428371, 0.8924890161, + 0.8761147857, -0.3095809221, -0.5196042657, -1.3068716526, 1.5195988417, 0.2128613889, 1.5664979219, -0.2589054108, + 1.7114889622, -1.8208161592, 0.1634945124, -0.8131170273, -0.6053546071, -1.3275238276, -0.6441715956, 1.9088834524, + -0.5635452867, 1.0824725628, -1.9519108534, 2.4412162304, -0.0172850862, 0.9122820497, 1.2396584749, -0.5733674169, + 0.4248894751, -0.2712600231, -0.683567524, -1.5374375582, -0.101374425, 0.7466657162, 0.9291818142, 0.2294180095, + 0.4144058824, 0.3097238243, -0.7374562025, -1.5369198322, -0.5622548461, -1.5995111465, 0.8243899345, 2.491486311, + 1.0118551254, -0.2812379301, 0.0167065077, 1.1539196968, -0.6009150147, 0.1329372674, -2.1699743271, -1.1165589094, + -0.5693680048, 0.6362667084, -0.7676492333, 0.6184794903, 0.183161214, 1.8593512774, -1.0755146742, -2.0192196369, + -2.4374644756, -0.1485635042, 1.1511514187, 0.1853233874, 0.6584609151, -0.0495361015, 0.2373988479, -1.511580348, + 1.9323703051, 0.482422024, -1.3157830238, -1.9636150599, 0.5330681801, -0.1093232185, -0.2831834257, 1.4337438345, + -0.5686172247, -0.8498464823, 0.7244464755, 0.6058983207, -1.2902585268, 0.7894331217, 1.9609137774, -0.3355398178, + -0.6076121926, -0.7272418737, 0.8514086604, 0.8884165883, -1.1113233566, 1.1378443241, 1.2755492926, 0.2945994139, + -2.1856794357, 0.7923774719, -1.6250413656, 0.7398307323, 1.0142691135, 0.9582080841, -2.6153709888, -0.7281308174, + 0.7424984574, -0.0821439624, -1.5249018669, -0.4381790459, -0.0053916587, -1.7120848894, 1.7055863142, 0.8111898899, + 0.1493609101, -0.7354556918, -0.3129665256, -0.6534162164, -0.9912257195, 0.1489663869, 1.1033235788, -0.1900487989, + -0.4122638702, 0.1786202043, 0.78168118, -0.5246403813, -1.3810967207, 0.9454761744, -1.3616911173, 0.5349876285, + -0.0959592983, -0.896406889, 1.3871814013, 0.9973930717, 0.5764676332, 0.4400008321, 0.4754700959, -0.983577311, + -0.5619937181, -1.6410032511, 0.2922827303, 1.4331048727, -0.3837113082, 0.2374925911, -0.5327551961, -0.4711798429, + -0.340084523, -1.4632056952, 1.1385982037, -0.0050248299, 0.9715877175, 0.3023412228, -0.8062357306, -0.3169119358, + -1.5868651867, 0.7886871099, 0.1372247785, -0.7851805091, -1.50657022, -0.5764098167, -1.1072884798, 0.1352825314, + -1.052777648, 2.052293539, 0.9853089452, -0.3728401065, -1.486235857, -0.1116613746, -1.9596153498, 1.060701251, + 0.7912979722, 1.4486447573, -0.5566545129, 0.8055643439, 1.3840409517, -0.4356646836, -0.7338418365, 1.3481131792, + 0.1454764307, 0.4252978861, -0.0880398229, -1.248473525, 1.1045972109, -2.0293858051, 0.9979759455, -0.2792384624, + -0.1876324564, -0.5325407982, 0.526850462, 0.4087450206, 1.6114984751, -0.1840722412, -0.182061106, -0.3537951708, + 0.1039311066, -0.44898054, 1.1552664042, 1.3704001904, -1.9223861694, -1.2888606787, -1.0187835693, 0.6616163254, + -0.8920385242, 0.5518894196, 1.3713300228, 0.7708854675, -1.0448182821, -1.1999044418, -2.6680612564, 0.4900120795, + -1.2550389767, 0.0423943661, 0.2307881862, -1.3097743988, 0.9433927536, -1.0359666348, -0.5941559672, -1.1822756529, + 0.049039647, -0.6646436453, 2.2700588703, -0.6435940862, 0.1863738149, -0.2803147733, 0.8866586089, 0.0039090207, + -1.461771369, 0.1988759339, 0.4399749041, -1.2791353464, -1.0427937508, -0.6556071043, 0.2571541965, -0.3568092585, + -2.2522468567, -0.7602754831, 1.1351559162, 0.6326811314, 0.6538631916, -0.0560684986, 2.1729958057, -0.068730779, + -0.2313192934, -0.4723461866, -0.3986878395, 0.7822806239, -2.0840001106, -1.1852180958, 1.4007776976, -0.7757635117, + -1.1275815964, -0.167248413, -0.7482985854, 0.2928707302, -1.1963318586, 1.499101162, -1.3109302521, -0.0839465857, + 0.0558208153, 0.2463919818, -0.0606065616, -0.0057793492, -0.0700023621, 1.3056834936, -0.1253987551, 0.9635531902, + -0.7322648168, -0.0024187912, -0.13017039, 1.0004709959, -0.586601913, -0.6917225122, -0.1560804099, -0.0212033875, + -2.1023504734, -0.8584808111, 1.1101720333, -0.2545737624, -0.2416257262, 0.5702453852, 0.5405352712, 1.7392754555, + 0.631243825, -0.4402846098, 0.0550365932, 0.7741043568, 0.9616689086, -0.9026238322, 0.6697832346, 1.767131567, + -0.1734208614, 0.0113102626, -0.9254624844, -1.061874032, 0.0115344757, 0.7880923748, -0.2987428606, 1.1056511402, + 0.9078025818, -0.3661470115, 0.7300938368, -0.1293408722, 0.0929499343, 1.0738584995, 2.4386839867, -1.3962153196, + -0.3303312063, 1.1602600813, -0.2442411035, -0.4293623567, 1.6676892042, -0.0608364716, 0.7872980833, -0.3093358874, + -1.558637619, -0.5111013651, 0.6837660074, 0.1929822713, -0.7978610992, 2.0638716221, 0.1178953871, -0.9953600168, + 1.2995123863, 0.91660285, -0.5599343181, 0.6541744471, 0.7905471325, 0.4623413086, 0.129854396, -1.7680779696, + -0.3233806193, -0.0529145338, -0.5833628178, -0.3562459648, 0.7015071511, -0.4987028837, -1.696171999, -0.6258285046, + -0.5355837345, -0.1618913412, -1.2267602682, -0.3106380999, -0.8768603802, 0.7795471549, -0.1935388297, 0.5475685596, + 0.2768119276, -1.284570694, -0.0423595309, 1.6698843241, -1.6108504534, 0.9478467703, 0.0986463651, -1.5106642246, + 0.5734161735, 1.0034544468, -0.0609908327, 0.3071651459, 1.8223924637, -0.6054177284, 1.8280153275, 1.6417883635, + -1.3252933025, 0.1235409901, 0.066932328, 1.2934104204, 1.1690789461, 1.5101593733, -1.6193233728, 1.3771556616, + 0.5679165125, -1.8386728764, 1.3130825758, -1.1070921421, 0.7729588747, -0.5860818624, -0.2058396339, 0.4436039925, + -0.2096983939, -1.4521727562, 0.3058028519, -1.1525199413, 0.5443555713, -1.2522698641, 0.1393335462, 0.3642078936, + 2.0137174129, -1.937597394, 0.316160202, -1.2603361607, 0.4786128998, -0.1122477651, 0.7691808939, 1.4161857367, + -0.3374640048, -0.0133701405, 0.9041422606, -0.5291411281, 0.4031642973, 0.8388589621, -1.076187849, -1.524972558, + 0.1757129133, 0.8767262697, -1.504966855, 0.4910938144, -0.3653927147, -0.1716035455, 1.0316590071, 0.140504539, + -0.8550847769, -0.0122549757, -0.233622238, -0.2811496854, 1.1793352365, -0.6546878815, -0.7931123972, 0.2504535615, + 0.6389125586, -0.1338374466, -1.2315516472, 0.1087464318, 2.4242548943, 0.5663132668, -1.6622200012, -0.9516454935, + 0.0935006887, 0.541827023, -0.6956735849, 2.1641728878, 0.5378525257, 0.3326438665, 1.2569468021, 0.2456189245, + -1.9654610157, -0.3942227066, -0.6392866969, -0.3373064399, 0.1140286326, 0.6925070286, -0.7737633586, -0.7652257681, + -0.0776397437, 0.5756703019, 0.5510339737, 0.6002933979, 1.1095582247, -0.3609852493, 1.1201286316, 0.3345442414, + 0.1578962952, 1.8014444113, -0.318744868, -0.7662656307, 1.4651508331, -0.0448592342, 1.1052986383, 0.3984775245, + -1.7524188757, 0.2810229659, 0.6246092319, -0.0725462735, 0.6233510375, 1.1921753883, 1.4715322256, 0.7919710279, + -0.8447570801, 0.1241444349, -0.7139037251, -0.4604227841, -0.4756816626, -0.0533989593, 0.2218795717, 2.0838932991, + 0.2475150228, 1.7827460766, -0.0134890378, 0.7679715157, -0.3554916978, 0.0362120308, -0.716643393, 0.6927425265, + -0.7791339755, -0.2974212468, 0.2203360796, 0.4349841774, 0.5249035358, -0.4737904668, -1.3593201637, -2.2599756718, + -0.8934810758, -0.6567152739, -0.6929903626, -0.8416537046, 0.4606203735, -0.2749021649, -0.137153089, -0.7862843871, + 1.6317793131, -0.2760257423, -2.3511528969, -0.777233541, -1.3283784389, -1.4011971951, 0.4626928866, 2.3816864491, + -1.2089858055, -0.418867439, -0.7853214145, -2.1645514965, 1.1445811987, -0.9505017996, 0.7641232014, 1.3194897175, + -0.1203246713, -1.0543094873, -2.7589275837, 0.6597554088, 2.1434054375, -0.4508769512, 0.4651074708, -0.3877440095, + -0.6067355871, 1.5365588665, 0.1711568981, 0.0135632185, 0.1285218298, 0.1237851009, -1.6126866341, -0.1699062586, + 1.7187911272, 0.7952760458, -0.5621861815, 0.1939502656, 1.2603075504, 0.3326231539, 2.4959945679, 0.334872514, + 0.2440851331, -1.0814745426, -1.6712106466, 1.0294514894, -0.3955523074, -0.7647819519, 0.5640015006, -0.6139293313, + 0.7056366205, 0.2410723269, -0.6252645254, 0.2575959563, -1.4764999151, 0.4396305084, -0.513410449, -0.0369065218, + 1.234064579, 0.0310939327, -0.6546210647, 0.9864290953, -0.0455574021, 1.2032821178, -0.7458623052, -0.297845602, + -0.9822353125, -1.3218252659, 0.1633568257, -0.6249672174, -0.7417123914, 0.1362227798, -1.0594494343, -0.0809739381, + -0.524548173, 1.8382658958, -0.8360715508, -1.3591579199, -0.5534932017, 0.1547365636, -0.8778612614, -0.5545231104, + -1.2758891582, -0.8472756147, 0.3394901454, 0.8867839575, 0.3970008194, 0.9629596472, -0.0797268972, 0.6448428035, + 0.4046718478, -0.0212829933, -2.4381325245, -0.1657105386, 0.9223551154, -0.8054891229, 1.8176586628, 0.8265794516, + 1.5185177326, 1.7634532452, -2.100679636, 0.9573124051, 0.2478752732, 1.182571888, 0.9785193205, -0.5731644034, + -0.9844460487, -0.9941863418, 0.1693080962, -0.9317142963, -0.9543631673, -0.6126065254, 0.3264756799, -0.8015695214, + 1.0485463142, -0.7815785408, 1.3674834967, -1.0214259624, -0.2009140849, 0.1025521085, -0.9636093974, -0.7346326113, + 0.2468834966, -0.4661616087, -0.5672651529, -0.4167720973, 0.1828022152, -0.8394173384, 1.663421154, -1.8836456537, + 0.0390705056, -0.1487848461, -0.3561755717, -1.4013719559, 0.6198907495, -1.6715638638, 0.5220121145, -0.1027402878, + -0.5389942527, -1.2783858776, -0.7213203311, -2.3513112068, 0.6171727777, 0.1380944103, 0.5125414729, -1.2011198997, + -0.5964149833, 0.5951352715, 0.2339069694, 1.1006313562, 0.4247358143, 0.3372429609, 0.1389364749, 1.4059437513, + -0.478353411, -0.6449186206, 0.0131500335, -0.0374759957, -0.2436141372, 0.8794044256, 0.3872634768, -0.5042549968, + 2.1577014923, -0.5692856908, 0.5889863968, -0.8519099355, -0.5406209826, -0.3512584567, 1.859205842, 0.1071278453, + 0.1881214976, -1.4387773275, 0.227847904, -1.0301718712, -0.6761962175, 0.4439955652, -0.4711591303, 1.5134398937, + 1.292071104, 0.1850506514, 0.0724349618, -0.1809644252, 0.3238140941, 0.4700443745, -0.2543262243, -1.1642212868, + 0.2567294538, 0.1768714786, -0.6741221547, -0.0544025823, -0.8167592883, 0.6026630402, 0.1571673602, 0.1848359108, + 0.7246237993, 2.1916341782, 0.0395292416, 0.588530004, 1.0862364769, -0.0933451578, 0.8974225521, 1.2546049356, + 0.0124170966, 2.8417673111, -1.7472499609, -0.7727107406, -1.1648753881, 1.1488866806, 0.2784065306, -0.7488279343, + 0.7987616062, -0.2916001379, 2.6300568581, -0.5040947199, 1.0890872478, -1.0070320368, 0.5389986038, -0.4499021173, + -1.3006299734, -2.0500237942, -0.2852370441, 0.9818706512, 0.0392058752, -1.4161587954, 1.4106215239, 0.424754858, + 0.7822275162, 0.4471131861, 2.5369141102, 0.1805239916, -0.8006153703, 1.0798196793, -2.1828672886, 0.2883101404, + -0.3787364364, 1.2829811573, 0.046352271, -0.7552426457, 0.1391619742, -1.3081711531, 1.8474140167, -0.2298999429, + 0.6889461875, -0.6292168498, 0.4396181107, -0.0836468861, 1.9265546799, -1.4717415571, -0.4133013189, -0.5089668632, + -1.2310500145, -0.1285655946, 0.8536369801, -0.7277516723, -0.0126291113, 0.4544115961, 0.5498104095, -0.5179764032, + -2.4123616219, -0.4469912946, 2.0694754124, -0.939424336, -1.0521241426, 0.2036963105, 0.0071311919, -0.6870504022, + -0.0155820046, -0.164744854, 0.372484386, 0.4417797029, -1.082960248, 0.6957066059, -0.2200885266, -0.6384267211, + 1.0450456142, -0.0275342409, -0.3599655032, -0.2629359663, 0.5287644267, 0.182917729, 0.6768316031, -1.8263455629, + 1.1303802729, -0.0842294767, 0.5546888709, 1.3973606825, 1.3698474169, -1.3730745316, 1.015119791, 0.2647194564, + 1.0315226316, -1.5784586668, -0.990763247, 0.2567261159, -0.8996278048, -0.3867754042, 1.4097727537, 2.2299740314, + -0.1896184236, 0.9524666071, 0.1702094078, 0.9398848414, 0.5321618915, -1.238774538, 1.2894320488, -0.8582060337, + -1.3007978201, 1.1981871128, -0.3366500735, 0.8419474363, 0.5433722734, -0.9629876018, -1.6009552479, 1.7573373318, + 0.6935952902, 1.4654803276, -0.1797384024, 1.2437579632, 1.7125695944, -0.2490044981, -0.2686403692, 0.0930381417, + -0.0375618339, -2.6600220203, -0.9509128332, 0.2806393504, 0.2936806977, 0.2567313313, -0.3014256954, -2.0332870483, + 0.1230432019, 0.2137270868, -0.9075357318, 0.3526922762, 0.2563580275, -0.5407764316, -0.1236735359, 0.8370244503, + 0.2930872738, -0.9313671589, 1.5671607256, 1.1615507603, -0.8167613149, -0.7182096839, -0.6333760023, 0.5856393576, + 0.6780885458, 0.5890313983, 0.7123593092, -1.2848955393, -0.5609303117, -1.9114166498, 0.8378915191, 1.0157173872, + 1.0953134298, -0.4000841677, 0.3343574703, 0.3863209784, 1.5166685581, -1.912468791, 0.7424203753, -0.3382374644, + -0.3509818017, 0.6303770542, 0.4310825765, -0.8497053981, 0.5221378803, 0.4046062231, 1.6502557993, 0.2492208332, + 0.7841585279, -1.4824200869, -0.4545456767, -0.9722738266, -0.0509347804, 1.7074534893, -1.7254183292, -0.309001714, + -0.0453792103, -0.5058189034, 1.3871597052, 1.1207715273, 1.0124270916, -0.3037402928, -0.1054088175, 0.5237683654, + 0.142974332, -0.8187479973, 0.7458306551, -2.1103670597, 1.0728235245, 1.7312847376, 0.3593048155, 0.8765829206, + -0.0282392837, -1.0374023914, 1.3495305777, -0.8798107505, 2.2148194313, -0.3535363674, 0.0634836853, 0.0064468719, + 0.4102476537, -0.5776757598, -0.3282352984, 1.2123632431, -1.4314142466, -0.6823901534, -0.8864627481, -0.1065689325, + 0.0673301294, -0.2074949145, 0.291215837, 0.953479588, 0.7978639603, -0.1701406687, 0.2286783755, -0.8701025844, + 1.3222193718, 0.1815055162, -2.439409256, -0.347412318, -0.9069854021, 0.9881507158, -0.5943987966, -0.6776933074, + -0.5054681301, -1.7560210228, -1.4633255005, 0.5323156714, -0.8000277877, 1.1683307886, -1.0447676182, 0.0635707676, + -0.3356823921, -1.1476477385, 0.1429802775, -0.6482725739, 0.0072258324, 0.4359221756, -0.8878523707, 2.4653964043, + -0.5865577459, 0.7874836326, -0.0772186443, 0.0906665623, 0.1741325259, -0.7149444222, -0.0434522107, 0.0239767432, + 0.1674236953, -0.3820293546, -0.0326141678, -1.2816491127, -0.2897256017, -0.594694972, 0.0430568755, 0.3749506772, + 0.0121182492, 1.7634828091, -1.3510473967, 1.1881501675, 0.4915170074, 0.0009339975, -1.8913590908, 0.4536544681, + -0.3723362088, 0.231260702, -1.413693428, -0.5840505362, -0.1064425334, 1.3762027025, -0.4251186252, -1.9075818062, + 0.2827370465, 1.4952538013, -0.2975981832, -0.7461140156, 0.3224439025, -1.4082685709, 0.1460434049, -0.15487881, + -0.2577507496, -0.207764253, -0.6747339964, -0.5161724687, -0.7427644134, 0.2661053836, 0.0695588514, -0.4860402048, + 0.5244890451, 0.4730707407, 1.7623431683, 0.8991122842, -0.0184322987, -1.0504052639, 0.2551665604, -1.1870924234, + 0.6593571305, -0.3136428595, 1.2176970243, -1.0874655247, -0.0515389442, 0.2061298043, -0.626527071, 1.392166853, + 2.8257706165, 1.0335572958, -0.8086478114, -1.0901274681, -0.3106675744, -0.1632628441, -0.4603413045, -1.3341411352, + 0.5154522061, -0.4899453223, 0.303283751, 2.4529964924, -1.8736343384, -0.0681086928, 0.0572270155, 0.0044212798, + -0.0653590336, 0.2338360548, -1.1391998529, -0.0103998687, -0.5209394097, -1.0892212391, -0.3462033272, -1.8454072475, + -2.5989222527, 0.1982216686, -0.4841802418, 0.2070287764, 0.754987061, 1.3594202995, 0.696072042, 0.6822013855, + -0.0112141585, 1.3447604179, -0.831492424, -0.4079718292, -1.3308038712, 0.3525986075, -0.5378847718, 0.3934444189, + 0.2865182757, 2.0425362587, -0.9194611907, 0.1146700308, -0.137423709, 1.3655269146, -0.2616383433, -1.2862409353, + -1.6546574831, 0.0372327417, 1.270301342, -0.1432766169, 0.7952552438, -0.0720724761, -0.7424240112, 1.2256538868, + -2.2053880692, -0.5306376219, 0.1682143807, -0.9688461423, 0.3096540272, 0.940107882, -0.1633903384, -0.3208823204, + -0.4034307897, -0.6640667319, -0.116287455, -0.4164044857, -0.2106245607, 2.6117999554, -0.8170961142, 0.2296934575, + 0.1352863908, 2.0153095722, -0.9835947752, -0.0398398787, -0.7099856138, 0.2519035935, 1.010051012, -0.7469947338, + -0.2271399647, 0.8424672484, -0.0028453339, 0.0573192686, -0.7911548018, 1.5115075111, -0.4292039275, -0.2814901173, + -0.2986505032, 0.9713628888, 1.1659340858, -0.184505716, 0.0065851845, 0.5065482855, 0.1957827955, 0.7852159739, + 1.0992507935, -0.6381587982, -0.2258110791, -0.0518908724, -0.4910358787, -2.2459900379, -0.7985108495, -0.8093937039, + 0.2404313385, 0.4376957715, 0.3021634221, 0.276812017, -0.9123110771, -1.4636436701, 0.8011099696, -1.477596879, + 1.9602862597, 0.2919983566, 0.1149028838, 0.3892951906, -0.4618502259, 0.7220209837, -0.1333760023, -0.8379451632, + 0.4440839589, 2.7235734463, -1.1158251762, -0.2277544439, 1.3317129612, -0.4921458066, 1.3590461016, 1.084772706, + 0.0156160211, -0.1734282523, 0.9402840137, -0.7774642706, 0.7608965039, 1.4017525911, 1.2316533327, 1.0011581182, + -0.9780515432, 0.6779560447, -0.0694640726, -1.0573610067, -0.1401209533, -1.4334952831, -0.1790812165, -0.1230426356, + 0.5381953716, 1.0654780865, -1.401320219, -1.3276036978, -2.0463159084, 0.8385336399, -0.6869310737, -0.5620132089, + -0.0442883112, -0.0047367625, 0.6841859221, -2.1602709293, -0.1973593086, -1.2325326204, 1.691839695, 0.5312877893, + 0.3519688249, 2.1720921993, -0.1462069154, 0.8961949944, -1.4612011909, 0.2014119923, 2.2746560574, 0.498010844, + -0.7518550158, -0.9755960107, -1.5738663673, 0.4436374903, 0.8610516787, 0.1271061748, -0.8113466501, 0.2418205291, + -0.6867427826, 1.2207347155, -0.4108690321, -0.8827690482, -0.5456284881, 0.3868001401, -1.2304912806, 0.6670293212, + -0.2712611258, 0.0818201751, -0.1299658567, 2.2640588284, -0.1695053726, 0.8452254534, 2.4532289505, 0.4257523119, + 1.8475958109, 0.0974547565, 0.7967066169, -0.5887081027, -1.1121789217, -0.9687710404, -0.024155112, 0.2857384086, + -1.1169031858, -1.3783563375, -1.8767281771, 2.1267092228, 0.107593216, -2.1452682018, -0.0090910634, -0.1592708379, + -1.3771734238, 1.159311533, -0.4573624432, 0.0412932597, -0.2843123376, 0.0463854149, 1.0175329447, 0.6056706309, + -0.4518868327, 1.5754882097, 1.5401930809, -1.4632025957, -1.1145495176, -0.6111642122, 1.5250842571, -0.1827131957, + -0.5719213486, -0.0339936987, -0.2241427749, -0.1559786499, -1.0696374178, -0.7931587696, -0.2671611905, 1.3815757036, + 1.2891613245, 0.9156867266, 0.3633261919, -2.6118755341, 1.7803673744, 1.1180121899, -0.3693193495, -0.648383379, + 0.1860720217, 0.0447100475, -0.6926733851, 1.4939805269, -0.6550534368, 0.2498712093, -1.2042515278, -0.2552892864, + 1.0822662115, 0.0425696447, -0.5869133472, -1.9481761456, -0.340991348, -0.3546536267, 0.7333459258, 1.322218895, + -1.2185709476, 0.8016905785, -0.9687362313, 1.1493378878, -0.4367955327, 0.55727911, 1.5488294363, -1.7036701441, + 0.146858573, 1.5773946047, 0.7791216373, 2.1659414768, -0.4962480664, 1.0852104425, 0.7184401751, 0.0505882911, + -1.0123195648, 0.2237323672, 1.933760047, 1.2498807907, 0.4884160757, -0.4939172566, -1.4075125456, -0.199029848, + -0.9089871049, -0.3559097946, 1.1026279926, 1.225241065, 1.087177515, 0.5441542268, -0.5297963619, 0.4389980137, + -1.7267080545, 1.1040461063, -1.0993429422, 1.3341366053, -0.6335446239, 2.2331142426, -0.2638579607, -0.1156971976, + 0.7624002099, -1.3418661356, 0.2185997516, -1.0052831173, 0.6768507361, 0.499756366, 0.2243302017, 1.236182332, + 0.1434970349, -2.1947665215, -0.7532163262, -0.9595815539, 0.6633858681, -0.2023599595, -0.6430290341, -0.8134525418, + -0.3416174352, 0.4218400717, 0.8895066977, 0.037506301, -0.4428788722, 0.0392513834, -1.2110996246, -0.4579227865, + 1.4286129475, 1.0722044706, 2.2364633083, -0.7332018614, 2.6002426147, -0.5068512559, -0.6531524062, 0.2969976068, + 0.4913036525, 0.1942404211, -0.077574715, 2.0618264675, -1.197943449, -1.0965492725, 0.2128379345, -0.0973059759, + 0.0509134494, 2.3178815842, 1.6716791391, 0.6432677507, -0.7658655047, 0.2551034093, -1.7418290377, -0.8488428593, + 0.7497497201, -0.9394742846, -0.6140592098, 0.2242153883, -2.9374637604, 0.2126290649, 0.313521266, 0.567825973, + 1.6826602221, -0.516286552, -0.2058548182, -0.7859453559, -0.6208847761, -0.7223044038, -0.719337225, -1.960868597, + -1.1417084932, 0.7958766818, -0.3401833475, -0.4921501875, -0.4349618852, 0.3137913048, -1.3271640539, 0.9106199145, + -2.0794861317, 1.0177873373, 0.4266745448, -2.0590798855, 0.0865664855, 0.3999687433, -1.1941734552, -0.0655964836, + -1.5167351961, 0.8678767085, 0.7040355206, -0.0141630126, -2.5513372421, -0.0591046214, -0.1782632917, -0.6721311212, + -1.4577360153, -0.8415274024, -0.4924280941, -0.1054591313, 0.6587065458, 0.627759397, 0.2027057856, -1.0286164284, + 0.1998594999, 0.6571788192, 0.6904782057, 0.9589516521, -2.3220672607, -1.4431536198, -0.3931055367, 0.7838268876, + 0.8431079388, -0.6274953485, 2.0802054405, -1.8623497486, -0.3251871765, 0.691859901, -0.4644671977, -0.9389165044, + 1.2123388052, -0.1305605322, 0.2123090029, 1.2012878656, -0.799431324, 0.2028683871, -0.415315181, -1.1983784437, + 1.0681349039, 0.5389846563, 0.284617424, 0.0825485736, 1.4062007666, -2.5803592205, -0.2879975736, -1.4541510344, + 0.2424149364, 1.2237983942, -0.8512282968, 1.5265872478, 0.3694509864, 0.7817362547, 0.8075862527, 0.3952428102, + -0.936288476, -0.7247197032, -0.0328013301, -0.4716132581, 0.5637686849, -2.2679274082, 0.3426539898, -0.0979672372, + -0.2402446121, -0.0963036716, -2.1943864822, 0.694276154, 0.0291213989, 2.4530353546, 0.7187931538, 0.2133912891, + -1.0874562263, -0.887341857, -0.9403048158, 1.922118783, -0.8266971707, -1.5223639011, 0.9220241308, 0.8729629517, + -0.1005499288, 0.9404553771, 0.2749381661, -1.2735220194, 2.1069967747, -2.2149572372, -0.3422880471, 1.466830492, + 1.9702908993, -0.9250925183, -0.0060714148, -0.9882918596, 1.4887702465, 0.2804108858, -0.3489108682, 0.5542525649, + -1.5422412157, -1.25753057, 0.2715023756, 1.2902284861, -0.2465406358, 0.3424791992, -1.0304328203, 1.7649421692, + 0.8475595117, 1.3346787691, 1.6747332811, -0.2368809879, -0.3557014465, -2.0324966908, -0.4428349435, 0.6714438796, + 1.0843613148, 0.2764685154, -0.115548104, 0.9883731008, 0.4112939835, -0.6270067096, -0.1460562497, 0.2729308009, + -1.0989434719, -2.7572638988, 0.7561358213, -0.9827682972, 0.9108489156, 0.6604135036, -0.1289324462, 1.8280123472, + 0.675960958, -0.351955533, 1.6215261221, -1.0882657766, -2.5271363258, -0.3571330607, 0.9479765892, 0.436882019, + -0.2717285156, 0.6993663907, -0.7780221701, -1.1863687038, -0.558370471, -0.7359765768, -1.025190115, -0.1638904214, + 1.2510455847, -0.3172542751, -0.9209412932, -0.5378237963, -0.2243570387, 0.557343483, 0.7788372636, 1.7665655613, + -0.5648117661, 0.5073568821, -0.1877584457, -1.0030902624, 0.0020168158, -2.2090637684, -0.3919711113, -0.0892934874, + -0.2768075466, -0.7382922173, 0.4781686962, -0.5271230936, -0.8565163016, -0.0114886239, -0.3409681022, 0.9220369458, + 0.4548239112, 1.1105103493, -0.8540458679, -0.5342381001, -0.1587235928, 0.378657639, 1.622563839, -2.4055118561, + -0.9667271376, 0.7057707906, 0.2168771327, -1.8539066315, -1.3120892048, -1.1653203964, -0.5374454856, -0.4951444268, + 0.610609293, 1.46506989, 0.2833453417, 0.0034100253, -0.4601604939, -0.7077453732, -0.1619891524, -0.3710734546, + 1.2191070318, 1.4806418419, -1.0868707895, -2.0648705959, -0.9124275446, -1.9892864227, 0.8951463103, 0.8109661341, + 0.7963710427, 0.7626373172, 0.6699028611, 1.3099942207, 0.1779273599, 0.3980103135, -0.2223629951, 0.7420293093, + -2.4057607651, 0.7425398827, 0.773981154, 1.8070101738, -1.3846660852, 0.1880014688, -0.1909513474, -1.517403841, + 1.2443370819, 0.4424822032, 0.7484818697, -1.835957408, -1.0961536169, -0.5201159716, -0.4773720503, -2.121389389, + -0.7915535569, -0.1687713414, -0.3899119198, 0.2895978987, -0.351121515, -1.3487813473, -0.0930239484, 0.3696572185, + -0.3927856386, 0.1512555778, 2.9449841976, 1.6288179159, -0.3464185596, -1.0187661648, 0.1346620172, -0.1407055557, + -0.2609769702, 0.8170487881, 0.0737538487, 0.598213017, 0.1496603042, 2.720085144, -1.6137839556, 1.5230054855, + -2.3850162029, 0.9167109132, -1.0846986771, 0.1835428476, 1.8487994671, 0.3989471197, 0.8919633031, 1.2315006256, + -0.0234141331, -0.7482023239, 0.148795262, 0.4381481707, 0.383654207, 1.5491355658, -0.7265835404, 0.9751958847, + -1.2847875357, 2.1041853428, 0.227257058, -1.1291662455, -0.2813319564, -0.7394167185, -2.584321022, -1.1766476631, + 0.9712014198, -1.2400223017, 0.6785711646, 0.7806016803, 0.9310101867, 0.2308028489, -0.9521868229, -1.056937933, + 0.0101044821, 1.2908110619, 0.8434351683, -1.0314128399, -1.3817199469, -0.0570717938, 0.4098027349, 0.7228524089, + -0.1619416177, -0.112795487, -1.3605376482, 1.695984602, -0.1019152254, 1.0857456923, -0.1930623353, 0.5130358338, + 0.2026667893, 0.7818601727, -0.5955975056, 0.1939072609, -0.2461180836, -0.295291096, 1.102492094, 0.4419107437, + -1.1785167456, -0.1340370774, -0.3758517504, 0.1165554896, -1.1369833946, 0.9722950459, 0.1699508727, -1.1497621536, + -0.557764709, 2.4325559139, 2.0300633907, 0.3172180355, 1.0420550108, 1.397002697, -1.3860317469, 0.6756493449, + -0.208802253, 0.0416123271, -0.3647925854, -1.3826622963, 0.032714203, -1.730044961, -0.6120365262, 1.1658670902, + 0.7848781943, -0.5333843231, 1.370192647, -0.6063991785, -0.9086737037, 2.2848854065, 0.6883058548, 0.662396729, + 0.8888964653, 0.5443738699, -0.7265207171, -0.6869468093, 0.3359093666, 0.4884953499, 0.9215206504, -0.1096334979, + 1.8479670286, -1.32515347, 1.9301359653, 1.4032901525, 0.3269095421, 0.3069120944, -0.2451367527, -0.816981256, + -0.4496933222, 0.406504184, 2.2406930923, 0.8854416013, -1.4401488304, -0.9977304935, 0.9404314756, 0.027680127, + -1.0297243595, -0.9591946602, -1.1910470724, 1.755515337, -0.0457942411, -0.0153770149, -0.3424043953, -0.6024621725, + -1.5076104403, 0.3168259561, 1.2989704609, -0.3437852859, 0.3600607812, 1.1474263668, 0.8276595473, -0.794862628, + -0.3214859068, 0.149946779, 1.691505909, 1.2442883253, -0.111723043, -1.8866000175, -0.0652765781, -0.8484117389, + 0.9157932997, -0.8810158968, -0.6766892672, 0.0717540085, -0.0943662152, -0.8810151219, 1.5139248371, -1.065279007, + -3.0692067146, -1.7233544588, 0.2145391554, -0.0761685669, -1.6524933577, -1.8591082096, 0.0064446605, 1.4435199499, + 0.4387893379, -0.8295137882, 0.4456272721, -0.829764545, -2.2846164703, 0.3067142367, 0.2384975702, 0.9313440919, + 0.7382943034, -0.0273835473, 0.7648501396, -0.8317270875, -1.4108572006, -1.7982788086, -0.6981588006, 0.6069019437, + 0.8501870036, -0.8509014845, 0.4383669794, 0.6248463988, 0.8739450574, 0.3806868494, -0.9634509683, -0.1053313464, + -1.0504844189, -1.2173187733, 1.4710108042, 0.6670583487, 0.0257385876, -0.9211400151, -0.537424624, -0.0370455347, + 0.9016004801, 0.6242956519, -0.005014874, 0.8383492231, -0.6565697193, 1.8286083937, 0.5789019465, -2.3177831173, + -0.5858536363, -0.3403774202, 1.7211940289, -0.0403645262, -0.0005720349, 0.983725071, 1.1704604626, -2.0550563335, + 0.5990749598, -1.3058104515, -0.1033330113, -0.3316901922, 0.9040453434, 2.9563987255, -1.584758997, 0.4970963597, + 1.2656636238, -0.1820234358, -0.6379039288, 1.7642017603, -0.3535215557, -0.3904646635, 0.0819236487, -0.4960451722, + 0.6401004791, -1.1532803774, -0.7206152678, -0.4024859965, 0.7426589727, 0.6694399714, 1.4347842932, -0.3065627217, + 0.3679106236, 1.2681542635, 0.0654527098, 0.8345687985, -1.1156513691, 0.8476576805, 0.2385712713, -0.4635876119, + -1.1457544565, -0.0187508408, 0.5387160778, 0.2548680007, -0.0915771574, 1.0684789419, 1.0852134228, -0.8394083977, + -0.18096973, -0.3924306929, 0.1450937837, -0.0587084554, 0.6864700913, -1.0417679548, 0.2963407636, 2.9507956505, + -1.92506814, -0.1433570832, -1.1863735914, 0.1866655797, 0.9594634175, 0.3174482286, 1.453343153, 0.5670638084, + 1.309548974, 0.1332997233, -0.9662900567, 0.3597651422, 0.160278216, 0.207173571, 0.8496370912, -0.7209706306, + 0.1189359799, -0.7544926405, 0.8743216991, -0.668168366, 0.3383395374, -1.1891311407, -0.020724088, 0.3600969017, + 1.082388401, 0.4390854836, 0.6673156023, -0.1929547191, -0.0451419055, -0.4575970769, 0.2687020898, 0.5414130688, + 0.5603662729, 0.4634231329, 1.2978063822, -0.2309095711, 1.7121770382, 0.2484276593, -0.7386830449, 0.33043167, + -0.0578057617, -0.0305827893, 0.941293478, -0.5984822512, -0.9803550243, 0.2070207894, -0.6550219059, 0.1320174783, + 0.7900218964, -1.3689039946, 0.9380484223, 0.4847313464, 0.2433396876, -1.4307051897, -1.0672821999, -0.7570881248, + -0.4750105143, 0.0807691738, 1.295681119, 0.5300829411, -0.4246348143, -0.600746572, 1.3769870996, 0.4140109718, + 1.0277614594, -0.8248614073, 0.2571107447, -0.7096899748, -0.1520026624, -0.6228904128, -0.1400981396, -0.1943059713, + -1.3681163788, -1.1639925241, 0.4308236837, 0.1339069456, -0.8116710186, -0.5282785296, 0.462800622, 1.3132369518, + 0.8331753016, -0.2018923014, 0.0933108181, -1.0099724531, 0.417052716, 0.4332081079, -0.2000631541, -0.4819248021, + 0.0526755936, 0.5904321671, 0.419487685, 1.4380538464, -0.2091670036, 0.1405492425, 0.8455461264, -0.1576862335, + 0.7914052606, 0.5603117347, 0.6225966215, -0.6495121121, 1.6057735682, -1.4565155506, -0.1592467129, 0.9452735782, + -1.1509324312, 1.1862341166, -0.9232009053, -1.486823082, 1.2887068987, -0.5039800406, -0.9293571115, 1.4114164114, + -1.3048022985, -0.5259607434, 0.1474925727, -0.6388627291, -0.4544603229, 1.6006817818, 1.8981077671, 1.2952227592, + -0.6770508885, -0.0343132466, 0.0424407683, 0.0593665354, 0.1125282869, 0.1721530408, 0.2323742956, 1.0071390867, + 1.1618844271, 2.0738105774, -1.5517368317, 0.5792925358, -1.5301368237, -0.9412553906, 1.5477662086, -0.1588866711, + -0.5141246915, -0.160757795, 0.588575542, 0.7499521375, -1.081977725, 0.2867581248, -0.842626214, -0.4466435015, + -0.716601789, 1.5151894093, -0.3630546331, -1.2952378988, 0.2233130634, 0.7022958398, 1.2997992039, -0.2185886055, + -0.3559314013, 0.9324097633, -1.1729716063, 0.8698990941, 0.3515312672, 0.5347394347, 0.5843375325, -0.9044497013, + 0.2044183016, -1.1293611526, 1.0726300478, -0.582288444, 1.2378178835, 0.2893677652, -1.0045837164, -1.0325323343, + -0.9010717869, -0.5148781538, 0.4178542495, -2.048832655, -0.9897443652, -0.3382941782, 1.503826499, -0.2582089603, + -0.1545956433, -1.6558270454, -0.0935545862, -1.0900809765, 0.778008163, 2.1689538956, 0.5874821544, -1.1014442444, + 0.6476220489, -0.8646059036, -0.3191539943, 0.1379110068, 1.247325778, 0.1051613837, 0.5986577272, 0.0665234625, + 0.618591547, -0.1027515382, 1.2281802893, -1.4339200258, -0.7613863945, -1.1129082441, -0.6932907701, -0.9792848229, + 0.4943833947, -0.6510017514, -0.0364130028, -0.535065949, -0.7569305301, 0.1001948863, -1.3082510233, -1.0891143084, + -1.6640188694, -0.7002798915, -0.0759273991, 1.1599098444, -0.8365039229, 1.5821044445, -0.1271798313, 0.4336561263, + 0.1694084853, 0.5724648237, 1.8298932314, 1.418651104, -0.9776277542, -0.4195668101, 0.4297143519, -1.0633279085, + 0.391182363, -0.0747859403, -0.9993607402, 0.3444029987, 0.9736811519, -0.9430867434, 1.6025952101, 0.237615779, + -0.1281956732, 0.3923225701, -2.5928940773, 0.7752914429, 0.2649167776, -0.4567572176, 0.3371549845, 0.4049337804, + -1.0609476566, 0.0936940014, -1.5922925472, 1.8138062954, -0.1034576967, -0.3052410781, -1.4047080278, -0.3657502234, + -0.0972745717, 0.2751365006, -1.5588892698, -0.3687875867, 0.7465646267, 0.3279536366, 0.1500969678, 0.6712778807, + -0.3980213404, -0.8001051545, -0.5537888408, 0.7133117318, 0.8906948566, 0.0045022634, -0.9853961468, -0.178278923, + 0.9238131642, 0.7145440578, -1.0212540627, 0.2322989702, -0.1549165547, -0.3999933898, -2.6583871841, -1.003428936, + 1.3892837763, -0.0713517517, 0.1388881058, -0.0967622548, 0.4031153023, 0.6281492114, 0.5679972768, 1.1819807291, + 0.4587058425, 1.7037755251, 1.5106276274, 0.0188147873, -1.2132136822, -1.159539938, -0.9960440993, 0.1820143163, + -1.2581967115, -0.0109062744, 1.2203755379, 0.6200798154, -0.2033996284, -0.0597796105, -1.1121650934, 0.3698798716, + 0.2429883182, -1.4556866884, 0.2045957595, 0.2362975627, -0.2086562663, -0.8186010122, -0.2720654607, -0.5458545089, + -1.2913902998, 1.241292119, 1.4953358173, -0.2214281559, 0.5088971257, -1.5477359295, -0.7341091037, -0.0617847852, + -0.9167001843, 1.7482943535, 0.6113579273, 0.1244715825, -1.7654695511, -0.8131557107, -0.2266721576, -0.2433164567, + -0.9586618543, -0.3598257303, -0.1786702126, -1.8549596071, 0.4828202128, -0.237414822, -0.2234849483, -0.792811811, + -0.0088003566, -0.1138385981, -1.161303401, 0.5579746366, -1.1964149475, 1.2761023045, -0.5428506732, -0.7676082253, + -2.0380215645, -0.8374180794, 1.8076927662, 0.6725515127, -0.4143821895, 0.0190587919, 0.6254171133, -0.2820325494, + 0.8748767376, -0.5163024068, -1.0898655653, 0.127573818, -0.1395269185, -1.5575122833, 0.4249118268, -0.1607739925, + 1.3152391911, -0.7662281394, -0.1419369578, -1.1442737579, 0.5419403315, -0.0603652373, 0.0115801683, -0.4260250032, + -0.8693335056, 0.3321054876, -0.2232301235, 0.1859180033, 0.0755599067, 0.4812561274, 0.0805540904, -0.1881784499, + -1.3111925125, -0.088724412, 1.5127700567, 0.5737081766, -0.5410040021, 0.1011774912, 0.9945519567, 0.018713031, + 0.2556715012, -0.7111772299, 1.1038419008, 0.7498760223, -0.6901777387, -0.6161143184, -0.8754807711, 1.3833988905, + -1.4642595053, -1.2905743122, -1.1369878054, -1.8163366318, -2.0593073368, -1.5773495436, -0.1809103638, 2.6330025196, + -0.8738535047, 0.4626492262, 0.5717197657, -0.5768548846, -0.3781278729, -0.1874432266, 0.1967199296, 0.3621532023, + -1.7878540754, 1.1232843399, 2.2314839363, -0.259203434, 0.4197042882, 0.3647200167, -0.4982883036, 0.8533704281, + 0.6698650122, 1.4574915171, 0.1867191195, 3.0060515404, 0.0711427107, -0.2154966444, 0.0293234326, -0.0889864117, + 0.1243936792, 0.0645327345, -0.2294944078, -1.0487772226, 0.1695384383, -0.4823871255, -0.2830505073, -1.2472976446, + 0.1283144057, 0.4478857815, -0.6975439787, 0.1654880643, -0.3362832665, -0.1657265425, -0.6748378277, -0.6607167721, + -1.285744071, 0.2204591036, -1.4501774311, -0.0336493291, 0.8193687797, -0.7773550153, 1.2970961332, -0.5298593044, + -0.2872518003, -0.0863314644, 0.3339187801, 0.3005096018, 0.9379919171, -0.4672140777, 1.9484413862, -0.3087449372, + -2.0272562504, 0.2302280813, 0.1488207579, 3.2926943302, -0.5023747087, 0.9368308187, 0.4223787189, -1.214615345, + -0.3633534908, -1.0163754225, 0.8161545992, -2.6420648098, -0.9995900393, -0.6842966676, -1.3786201477, -0.1166622937, + -0.5009272099, 1.3049273491, -1.1700606346, 0.4273369908, -0.4868766069, -0.9399681091, 0.1936713308, -0.1304665208, + 1.6364108324, -1.2473168373, 0.4555480182, 0.7874873281, 1.0548788309, 1.4028953314, -0.3403153718, -0.7662428617, + 0.7910608053, -0.5680841804, -1.686437726, 1.7951066494, -0.5170757771, 1.3853578568, -0.4875607193, 0.9538254142, + -0.4127383828, 1.2545660734, 0.9811357856, 2.5652039051, 0.4855013788, -1.6319627762, -1.9827576876, 0.7196250558, + 0.3306773603, -0.3879871368, 1.6143678427, -1.7628905773, -0.2992368042, -0.2816053331, -0.4913335741, 0.1062109917, + 0.6110439897, 0.4482290745, 0.8110507131, -0.0504925326, -1.0317854881, 0.5823349357, 0.8444985747, -0.3849413693, + -1.3550829887, 0.6306875348, 0.3171112239, 0.0095400224, 0.8568302989, 1.8019857407, -0.9952394366, 3.2118475437, + -0.1661012471, 1.7766364813, -0.334089309, -0.2285335511, -0.081091851, -1.7271569967, 0.4434600174, -0.7047592402, + 0.5324918628, 0.4588414729, 0.6069088578, -1.1168786287, -0.4205290377, -0.4082236588, 0.915915072, 0.0197826736, + -0.9659548998, -0.0031386658, -1.1092762947, 1.1993969679, -0.9169333577, -0.3250979185, -0.655459702, 1.0403012037, + -0.8468415141, -0.0201100614, 1.0483227968, 1.3847842216, 0.2876734436, 0.3542454243, 0.4986132979, -0.2432114482, + -0.1372609735, 0.5234652758, -1.2656041384, 0.4806742072, 3.0031232834, -0.151272133, -0.7243952751, 0.0387897491, + -0.1198186129, 0.8208485842, -1.0074971914, -0.6677929163, 0.0483032688, 0.1750379354, 0.2083159089, -1.9190596342, + 0.9766510725, 1.8913180828, 0.4273438454, -1.3285946846, -0.1469343305, -1.3562725782, -0.3669628799, 0.1919582635, + 1.382992506, -1.0648114681, -0.2708503604, 2.7610263824, 0.6004490256, 1.3111655712, 0.9766030908, -0.1186602041, + -0.4448900223, -1.097869873, -0.4263503253, -0.2740243077, -0.1068669632, 1.0883152485, -2.981372118, -1.1545959711, + -0.0348202735, 0.2651986182, -0.4033118188, -0.8410776854, 1.0309700966, 0.403604269, 0.1645698398, -0.4990791678, + 0.8270534277, -3.1262013912, 0.2744820118, 0.8101330996, 0.7581610084, -0.7181271911, -1.3808708191, -0.5076599717, + 0.0838778764, -0.8853391409, 0.6123282313, -0.1626137942, 0.2677460611, -1.4126522541, -0.4442411065, -1.2625015974, + 1.50329566, 0.6110239029, -0.4633914828, -0.2613438368, 1.8707574606, 0.6762051582, -0.3888108432, -1.0406956673, + -2.4245371819, 0.4552400112, -0.4199117124, 2.008749485, 0.638930738, -0.3146655858, -0.0531506911, -0.1081308648, + -0.8942368627, -0.2720023394, 1.1744161844, -0.5152111053, -1.5052090883, -1.397262454, -0.0511602834, -0.0412393324, + -0.2354413718, -1.2756769657, 0.177450195, -0.1988486648, 0.8698195815, 0.4150623381, -1.1867893934, -1.266620636, + 1.5865522623, 0.0610986762, -0.1770948023, -0.585431993, -0.4385347962, 0.0175962076, 1.3314625025, 1.5840754509, + -0.3236637712, 2.3411216736, -0.6135569811, 0.924923718, -0.2237814665, 0.891120851, 0.1451560408, 0.2448153049, + 0.3776126504, 2.0296990871, 0.6324076653, 0.358943224, 0.4496875703, -0.3058456481, 1.1094084978, 0.4872805178, + -0.3038507998, -1.4573172331, -0.9205236435, 0.6826651692, -0.3554729223, 0.3927389085, -0.3810762763, -1.7063821554, + -0.1602554619, -1.6169706583, 0.6162632704, 2.406586647, 0.315202415, 1.2607896328, 0.3310032785, -1.3002210855, + 0.5527735353, -0.764560163, -1.6030761003, 0.2826044559, 0.1884256005, -1.1052546501, -0.0256252103, -1.4617702961, + 2.3069312572, 0.1014108062, -0.5887804627, -0.0482289307, 0.7604926825, 0.712606132, -1.1288833618, 0.3887622952, + -0.2175828516, 1.4924032688, -0.1203889251, -0.4008507431, -0.4998865426, -0.9092680812, -1.4348453283, -1.2464061975, + 0.490583241, -0.4584877491, -1.7624422312, -1.2848756313, 0.1869234592, 1.6680623293, 1.4857335091, -1.3092820644, + -0.4001376033, -0.6902616024, -0.2851842344, 0.5611698031, -0.2224484831, 0.1025903299, -1.3632470369, -0.5505031347, + 0.9418570399, 0.4167126417, 1.5588051081, -0.4624279737, -0.3520548344, 0.6923726201, -1.3459591866, -1.3967781067, + -1.2523069382, 1.1929949522, -0.8578463793, 0.2459804118, 1.1848936081, -1.6676170826, 0.3219023943, 0.1425884366, + 0.8878026605, 1.3843916655, -2.0635306835, 0.4181311429, -1.6780023575, 2.8656015396, -0.6755149364, -1.2139745951, + -1.7235435247, -0.0115590412, -1.2834458351, 0.6609151959, -0.1157040447, 0.3007107079, -0.9618673921, 0.6788420677, + 0.4106647968, 0.7691630721, -1.8603491783, -0.2602683008, -0.6554810405, 0.8151291013, -1.1044774055, -0.025844479, + -0.684694767, 0.7430288196, 0.0927735269, -1.8108327389, 1.464235425, 2.1097369194, 0.5113024712, 0.9214703441, + -0.7961116433, 0.155784294, 1.6264904737, 1.6839746237, -0.1017777249, -0.0270002671, -0.5560973883, -0.3349419832, + 0.4305644631, -0.3148517013, 0.5323333144, 0.4808635712, 0.636670053, 1.1908731461, 1.2183773518, -0.0871770829, + 0.1331706196, 0.0532641746, -1.2944794893, -0.6270956993, 1.0332086086, 0.8411585093, -1.1188211441, 0.9106353521, + 2.4634940624, 1.3054764271, -0.5078490973, 0.6401654482, -2.0949027538, -1.5359004736, -2.1329395771, -1.2214189768, + -0.0510937348, -0.6269537807, 0.9085376859, -1.7701388597, 0.1271123588, 0.2025357783, 0.2193867266, -0.1419527531, + 0.4712587297, -1.1216319799, 0.2348901033, 0.2660713494, 0.1221213117, -0.0339588486, -0.4119123518, 0.2396080047, + 0.4450393617, 0.1456137896, 0.1783765703, -0.8795627356, 0.0829178467, 0.2220709324, -0.2598603666, 1.2970924377, + -1.6507456303, 0.6115096807, -0.3253150582, 0.1117031053, 0.7479269505, 0.4571745992, 0.1007617787, 1.4383536577, + -1.4001889229, -1.9547203779, -0.758856535, 0.1194262281, 0.736410141, -0.665871501, -0.052111119, 0.1420148462, + -1.2008237839, -0.0141287912, 0.1722817719, 1.0185024738, 0.3625552952, -0.2192810923, 0.6853411794, 1.0109658241, + 0.0720389709, -0.5317717195, -0.260489136, -0.2174306065, 0.986092329, 0.3199743629, -0.0393218994, 1.514220953, + -1.8734128475, -0.8563058972, 0.7394201159, 0.9219983816, -0.8890936971, -0.546631515, 0.5607649684, 0.8172806501, + -0.2346559316, 1.4355891943, -0.5468201041, 0.1247638464, -0.6282752156, -0.2512498796, 0.0405594669, 0.4966886342, + 0.7192645073, -0.5121807456, 0.2786832452, 2.3277153969, 1.7324640751, -0.1355056465, 0.9407029152, 1.778506279, + 2.0651509762, 1.174988389, 0.0644653961, 0.3345230818, -0.275934726, -0.9038693905, 0.0737935454, 1.7145204544, + -0.0049464516, -0.4580802917, 0.8939317465, -1.5609588623, 1.1997606754, -1.3571116924, 0.2147751749, 0.6041502953, + -0.4827028811, 0.4263130724, 0.3580539525, 2.095600605, -0.2793421745, -1.6219590902, -0.270298928, 1.0025880337, + 0.7011756897, 0.1722511351, -0.177385062, 0.779099524, 0.8636000752, -1.0049010515, 0.6323234439, -0.7638198137, + 0.3079225421, -0.3288014233, 0.3946300745, 0.8784893751, -0.1306656599, 3.0949795246, -1.414657712, 0.3331373334, + 1.1519114971, -0.1283607334, -0.6941428185, 0.1147115529, -0.0274392385, -1.7293875217, 2.331277132, 1.6542543173, + -1.7632293701, -1.9415524006, -1.1907383204, -0.0048493538, 0.4222418964, 0.0341976583, 1.521315217, -0.1766054034, + 0.2243996412, 0.7282629609, 0.1159321964, -1.4154875278, 0.316568315, 0.8783222437, -1.1561028957, 0.5572648644, + 1.5004160404, -0.8511629105, -0.5939493179, -1.1936300993, 0.6819807291, -0.0313347243, -0.0286470875, 0.8888990283, + 1.0018740892, -0.1425251812, 0.2556823492, 0.7652249932, 0.1631320864, -0.2498634607, -1.5008529425, -2.9273338318, + 0.6607398987, 0.1327477843, 0.5937239528, 0.1125463098, -1.6437536478, 1.5341486931, 2.1285750866, -1.0796158314, + -0.287997961, -2.2914717197, -0.8244517446, 0.4066144824, 0.6147168875, -0.5193148851, -0.732567966, 0.461165309, + -0.426803112, -1.184346199, -0.1097135618, -1.1662861109, 1.3328620195, -1.4928250313, -0.238229841, -1.2711412907, + -1.069635272, 0.6976164579, 0.3925410211, 1.2439258099, -0.3567233384, 1.2630944252, 0.0982297659, -0.5787029862, + -1.2956535816, 0.8188961744, 0.4646765888, 1.2062302828, -0.0755145028, 0.2233940512, 0.0219676215, -0.2262375951, + 0.8005526662, 0.2583341599, 0.0134167904, -0.9566358328, 0.6107801199, -0.3282876909, -0.5326413512, 0.3580334187, + 1.6714169979, 1.4230730534, -0.5663484335, -0.725820303, 0.5634755492, -0.4356320798, -0.1045525447, -2.32127285, + -0.2140943706, 0.5434054136, -0.5374541283, -0.3802753389, 0.2654729187, -0.1454317421, 0.3900747597, -0.14292638, + -0.0141180474, -0.5412923098, 0.9153400064, 0.7681113482, 0.1016348004, 0.8094421029, 0.0004556435, -0.2267173529, + 1.2817173004, -0.0734994039, 1.0696345568, 0.7920151949, 0.3397075832, 0.6335131526, -0.3126899004, 0.3656824529, + 0.3227659762, -0.1339740306, 0.3025370538, -1.660661459, 0.1812739521, -0.3153503239, -1.0073664188, -0.7484238744, + -1.7166824341, -0.1572054476, 0.8618949652, -0.995608747, -1.1582169533, 1.3176295757, -1.6233000755, 0.179895252, + 0.6858589053, 0.0602968559, -0.6038802266, 1.0489137173, -2.2571678162, -0.0584337749, -0.1138860956, 0.0855550766, + -0.7688744068, -1.2541327477, -1.4902909994, 0.1294953823, 0.0926831588, -0.5188183784, -0.7847260237, -1.0042928457, + -0.070749566, -1.5369973183, -0.8811527491, -0.9041975737, 0.7040268183, 1.1990603209, 1.8376708031, 1.3268336058, + -0.1728139222, -0.1250518411, -1.5261913538, -1.8103522062, 0.3975400925, 1.7494088411, 1.7238782644, -1.3281983137, + 0.1908317953, -0.8550479412, 0.1436198354, -0.33082968, 0.1347103268, -0.5981942415, -0.9036156535, 0.8448509574, + -0.5984261632, -0.3971627057, -0.1978619695, -1.2565414906, -0.4385175109, -0.6725533009, -0.5639172792, 0.0460369922, + -1.9070044756, 0.4588394463, -0.4961534441, 0.5328682065, 0.2758805752, 1.0665974617, -0.1897082031, -1.0725839138, + 0.9363661408, 1.1084721088, -0.3609683514, -0.6044198275, 0.7308124304, -0.2895660102, 0.9214672446, 1.1936705112, + 0.1420208365, 0.9903038144, 1.02485466, 0.7819829583, -1.5155851841, -0.120473206, -0.264603436, -0.4781559408, + -1.2578017712, -0.8879620433, 0.8834035993, 0.3680997789, -0.3455525041, -0.1083529815, 0.836263597, -0.8118629456, + -0.8376584053, 1.31528759, -0.3645234704, 1.9935706854, 1.5848784447, -2.1046626568, -2.5531182289, -1.2426662445, + 0.2019866556, -0.3053317666, -1.1955868006, -1.5779031515, 0.8499122262, 0.3275901377, -0.0016695884, -0.035563428, + -0.489251554, 1.9304982424, -0.2626447082, 0.8259323239, -0.6432670355, -0.8289811015, -0.2027345747, -0.257866472, + 0.0708145201, 0.9978447556, 0.260080725, 0.9250656366, 1.4760758877, -1.8792523146, -0.7825285196, -1.4022051096, + -1.4552857876, -1.1523354053, 0.0965485498, 0.2922802567, 0.8867214322, 0.1132206246, -0.0294816475, 0.2782558203, + 0.9704330564, -1.4312628508, -1.4022347927, -0.1946246922, -0.535497129, 0.6042767167, -1.4157117605, -0.9723172784, + 1.031283021, 1.4538744688, 0.2337075174, 1.3080239296, 0.7617688179, 0.5921661854, -1.2361630201, -0.908408165, + -0.7632186413, -0.8020383716, -1.3764209747, -1.5502327681, -0.166393429, 0.7598895431, -0.2875463068, -0.3408353031, + -0.4380674958, 0.1424137503, -0.2995167673, -2.1005253792, 2.4057154655, 0.3382180035, 0.3632414639, 0.3133047223, + 0.4243564308, 0.1828026623, 0.404355675, 2.5423345566, -0.3791434169, -0.1495744288, -0.8346999884, -0.7742741108, + 1.2149647474, 0.7606167197, 0.3171077371, -0.1672189832, 0.1230465323, -0.5340057015, -0.0623281896, 0.4993795156, + -0.6112615466, 0.2279778421, -1.2632958889, -1.0773020983, 0.3607445359, -0.2576623857, 0.7818472981, -0.476354599, + 1.3054454327, 0.6843120456, 0.4527694881, -2.4472017288, 0.6361515522, -0.5922811031, -0.140744105, -1.1186494827, + -0.2712420821, 0.3353216648, 0.9042813778, -2.189012289, -0.3902392983, -1.2158573866, -1.4680877924, -0.2748048902, + 0.875046432, -1.0083405972, -0.4647849798, -0.1865984648, -2.0889463425, -0.5600870848, -1.3486815691, -0.3641701937, + 1.1793979406, 0.1997187734, 1.6865342855, -1.07523036, 0.5811572075, 0.3023730814, -0.5949453712, 1.3834298849, + 0.326089263, -1.5045257807, -0.6118640304, 0.1986764967, 1.094609499, 0.9827951193, -0.0680601895, -1.0457265377, + -1.746984601, -0.5958772302, -0.3935099542, 0.7819852829, 0.1315787882, 1.3365695477, 1.2137441635, 0.4329839945, + 0.7754896283, 1.2031998634, -0.4921071529, 3.0196695328, 0.602455914, 0.2277309895, 0.5269126296, -0.1516455263, + -0.2588847578, -0.5245341063, 0.2717128098, -0.8874869943, -0.8964639902, -0.1968666464, 0.0911976174, -0.8873035908, + -1.8681821823, -0.0760981515, -0.7805968523, 0.4802442491, 0.0320365019, -0.7067071795, -0.4631549716, -1.1735436916, + 0.5445239544, -1.3017100096, 0.3699762821, -0.0850021094, -0.7237022519, -0.7464592457, 0.2509557009, -2.1246905327, + 1.6723703146, -0.7169879079, -0.5348271132, 0.3575956225, -0.2395388484, 1.992325902, 0.1982047707, -1.4630272388, + -0.5053290725, 0.8650518656, -1.3065795898, -0.6528154612, 1.70140028, 0.2201984078, -1.6176035404, -0.5858163238, + 0.3461747766, 1.7925175428, -0.8658657074, 0.0194235109, -0.2472789586, -0.9830157757, -1.2460169792, -1.4011884928, + -2.3403863907, -0.7892500758, -0.1878778636, -0.0241079796, -1.2374361753, 0.4444930553, 1.4464956522, -0.6280738115, + 0.0667637363, 0.6859157681, 1.8527070284, 1.5816912651, 0.0943878442, -0.6667955518, 0.6660448313, 0.5320387483, + -1.0508078337, -0.5289185643, -1.9789937735, -0.0936506018, -0.5537081361, 0.1577619612, 0.3714364469, 0.4536406696, + 1.1362136602, 0.4127557874, 0.0746068135, 1.4729266167, -0.0521894582, -0.3334014714, -0.2249729484, -0.5179290175, + -1.0466347933, 0.9848658442, -0.0994437635, 1.7418688536, 1.1313471794, 1.5630669594, -1.0602076054, 1.6669305563, + -1.4789799452, -1.9057705402, 0.3552731574, -0.7447243929, 0.1306759268, 0.9287368655, -0.1092540473, 0.3579307199, + 0.0620544627, 0.9341294169, -1.3217412233, -0.1887846887, 0.5450025797, 1.1946133375, 0.1155479774, -0.0156681519, + 0.0818186924, 0.3128174245, -0.5175796747, -0.9493309259, -0.500919342, 0.3581947982, -0.6916647553, 0.7086075544, + 1.2116622925, -0.5839709044, -0.10232687, -0.4031613171, -0.0775697455, -0.1116259247, 0.557122767, 0.6536220312, + 0.1175153852, -1.226595521, 0.2845886052, -0.3341941833, -0.9034729004, 0.3816067576, -0.0520795807, 1.3590296507, + 0.2401977628, -0.5103403926, 1.4039888382, 1.0099010468, -0.4682047069, -0.190314889, 0.2275711149, 0.3296707869, + 1.313934803, 0.3545247018, 1.6756818295, -0.4598955214, 0.0968695879, 0.9012082815, -0.6129329205, 0.5607587099, + 1.7570564747, 0.6849796176, -0.1868782192, -0.410297364, -1.4443739653, -0.052258499, 2.2450199127, 0.179861635, + 0.7548625469, 1.1856045723, 0.2843368649, -0.4107406437, 0.4364345074, 1.2590898275, -0.306425333, 0.7047862411, + 0.4805850387, -0.1725681275, -1.0563880205, 1.0208398104, 0.9267752767, 0.1891755462, -0.382202059, -1.4817459583, + 1.2379530668, -1.5762476921, -0.882106185, 1.7232716084, -0.5654813051, -0.0660265014, -1.1681851149, -0.66284585, + 0.7722485662, 0.2607228458, 2.2022979259, -0.7688165307, 0.0033735237, -0.1173261702, -0.9136849642, 0.3267530501, + -0.1441042274, -1.2224164009, 0.8834843636, -0.6588438749, -0.2248045206, -0.8135863543, -1.1237211227, -1.0655337572, + 0.4619101584, -0.7503932118, 0.3477369547, 0.2655709982, 0.8278338909, -1.286981225, 0.3188256621, -0.8562581539, + 0.7813947797, 0.615455687, 0.6575708389, 0.1797037572, -2.2783794403, -1.3994863033, 0.7637216449, -0.602238059, + 1.0573459864, -1.2417126894, 0.8444338441, 0.4190975428, 0.54084903, 0.1426850855, -0.993177712, -0.379470706, + 0.595397234, -0.8911392093, 1.2549008131, 1.0709406137, 1.3681180477, 0.7540420294, -1.3617898226, 0.2148898542, + 0.766669631, -0.5721467137, -0.9326041937, -1.346318841, -1.0583540201, 0.3082196116, 0.1263058931, 1.4746549129, + 0.0198656376, -0.1533403397, 0.5427250266, -0.8982430696, 1.0728341341, 0.9212007523, -1.0459827185, 0.2398848087, + -0.2399872392, 0.2015265524, 1.0953737497, -0.7641457319, -1.0590814352, 0.9709772468, -2.7245488167, 0.0263428781, + 0.0311356522, -0.1787093282, 0.4194993079, -0.8683885336, 0.4747060835, -0.4976926148, -0.6131805778, -0.899308145, + -0.6951372623, 0.2548579872, 2.4627816677, 1.2880226374, 1.3663511276, -2.0841400623, 1.0545402765, -0.6584460735, + 0.7016707063, -1.4842098951, 0.7018342018, -0.736702621, -1.1353683472, 0.8034266233, 1.9471383095, 0.281815201, + 0.6163467169, 1.6901090145, -1.7596832514, -0.0940287039, -1.5356237888, -0.4820639789, -0.2813972235, 1.9129413366, + 0.1789698899, 0.2698389292, -0.4756282866, -0.0582442805, 0.6104027033, -0.1537651569, -0.3071576655, 0.0031420253, + -1.1825238466, -1.8446222544, -1.3169915676, 0.1479340047, -0.6539691091, -0.3660846055, -0.5772585273, -0.5850701928, + -0.292416811, -1.8485302925, -0.148933813, -0.7512722015, -0.7153009772, 1.0778415203, 0.6231737137, -1.6968379021, + -0.8516989946, -0.9225254059, 0.9233241081, -0.3950044215, 0.7099353671, -0.042934183, -0.6496396065, -0.3185375035, + -1.8720908165, 0.0721271336, 0.291205734, -0.2783482969, 0.604954958, 0.6706092954, 0.7283976674, 1.3359290361, + -0.8727504015, -0.1820479333, -0.2766488492, 0.538548708, -1.2421909571, -0.6489337087, -0.8941696286, 0.1014679298, + -0.0520993546, -0.610604167, -2.9797456264, -0.6892374754, -2.2069187164, -0.4327895939, -0.6774798036, 0.1662548184, + -0.1374444216, -0.7766288519, 0.4023796916, -1.8384613991, -0.733776927, -2.0104799271, -0.868922472, -0.0495265275, + -1.3442329168, 0.0602338761, -1.7688345909, -0.8403044939, -1.0115302801, 1.9035303593, -1.2843977213, -0.4898892343, + 0.7581721544, 1.147215724, -1.3688549995, 0.608080864, -0.5300948024, -0.6094548702, 1.0624125004, -0.0401498191, + -0.2764210701, 1.5775593519, 0.2636820376, 1.2670412064, 1.1847480536, 0.6004807949, 0.6627605557, -0.9631214142, + -0.0651835725, 0.3965368867, 1.2247297764, -1.5966616869, -0.91615206, 2.0568938255, 0.1804197133, -0.0667092502, + -0.0283539798, 0.4848047495, 0.8173012137, 0.8953057528, -0.7625162601, 1.4375944138, 1.1974359751, -0.6648783088, + 0.4911331534, 0.436178714, 2.483625412, 1.2508749962, -0.865224719, -1.1523828506, -2.5317647457, 0.6768011451, + -0.8235494494, -0.0016548608, -0.292658031, -1.7133356333, 0.2775128782, -0.4684120715, -1.0212373734, 0.3111077845, + -0.5543714166, -0.5277050734, 0.0934340209, 0.0553637892, 0.1839600801, 1.0744355917, -0.8088902831, 0.0177089591, + -1.0553754568, 0.0537255295, 0.8920047283, -0.1436830014, 0.5428864956, 2.6151807308, 0.9089220762, -0.6701074243, + 0.1462989897, -0.4177500904, -0.3071745634, 0.2703181803, 0.0061454624, -0.0414125137, 1.2520478964, -0.5853372216, + 0.0183674395, -0.3882516623, 1.10161376, 1.8874223232, -0.6500365734, 1.4510560036, 0.2006217688, 0.1075251549, + 0.4110045135, 0.2201270163, -0.955843389, -0.0729107559, -0.2200553864, -0.1955879778, -0.3888328075, -0.1492266357, + 0.2064908445, -0.4907214046, 1.338052392, 1.0333486795, -0.3924434781, 0.2761882544, -0.0500014015, 0.2783436775, + -0.2208845317, 0.4076091349, -1.6868382692, -1.1322995424, -0.4491987824, -1.6285598278, -0.0747513771, -0.9900171757, + -0.5021103621, -0.0169003569, 0.6617447734, 0.5219373107, 0.0710919797, -0.1033318341, -0.1241831928, 0.5050722957, + 1.7465324402, -0.9384755492, -0.2050182074, -1.4408466816, 2.0659956932, -1.2176458836, 1.0436911583, -1.6367999315, + -0.8311728239, 0.0383930989, -1.4327731133, 1.6502213478, -0.0957067087, 2.222868681, 0.307682544, -1.7243221998, + -1.6951988935, 0.2783026695, 0.9383012056, -0.8741029501, -1.1462081671, -0.6457691789, -0.8208730817, 1.1436293125, + 1.4125794172, 0.2804195881, -1.6822501421, -0.4242359996, 0.6605323553, -0.0331386216, -0.0384374969, -0.8116567135, + 0.1741831154, 1.4778373241, -0.2192885429, -0.5614511967, -0.8825250864, -1.2342511415, 1.1353919506, 0.8536889553, + 0.6619521379, 0.194042787, 1.2519853115, 1.4540354013, -1.487691164, -0.5286277533, -0.5613620281, 0.4594193399, + 0.4614850581, -0.8415557742, -2.404756546, -1.4944550991, -2.2047286034, -0.7104699612, -0.6865041256, 0.4871855676, + 0.9703326821, 0.01916508, 0.030557435, 2.1260392666, 0.382540375, 0.1017763391, 1.2437696457, 0.0841875896, + 0.0260246377, -0.3963061869, 0.2071161419, -0.4882599413, -0.1168544292, -0.9286617041, 1.10612607, -0.2454181761, + -0.0635446012, -1.3290656805, -0.2628045976, 1.4840424061, 0.5852842927, -0.6792443991, -0.4082862735, -0.342530638, + -0.5310598016, -0.2525795102, 1.2393785715, -0.6161656976, -0.8743874431, -1.1418819427, -0.5788629055, 2.3537743092, + 1.3391598463, 0.708635807, 1.0133312941, -0.6402965188, -0.475222379, 1.2483383417, -0.0412226953, -0.3494254649, + 1.2869471312, -1.3261907101, 1.0926253796, 0.3833552301, -0.6908642054, -0.0721437111, 0.4729478657, -0.4645186067, + 0.8151687384, -0.7450098395, 0.3585434854, -1.3225007057, -0.5362467766, 0.055673942, -0.5106480718, -1.4202176332, + 1.1659399271, 0.7442878485, -0.6453229189, 0.473351568, -1.0344504118, 1.7793974876, -0.7470325828, 1.7667423487, + 1.0275626183, 0.0522043034, -1.9739670753, -1.1114044189, -0.3246097863, -0.3506036103, -0.3710768819, -1.9017586708, + 2.0592153072, 0.1685639471, 0.0427768752, -1.3544977903, 0.527438581, -0.8166235089, -0.6331622601, -0.0177748725, + 1.5376009941, 1.5840349197, -1.5073336363, 0.0665762797, 0.3779613674, 0.9021579623, 0.0178753231, -0.1060614064, + 0.9497752786, 1.145573616, 1.1762216091, -0.8378641009, -0.5064931512, -0.5005347729, 0.0742226392, 0.5423977971, + 0.6719839573, 0.3955279887, 0.1929187477, -0.0416823812, 0.5823065639, 0.4075008333, 0.9344403744, 1.6156861782, + -0.403066963, -0.5414798856, 0.3706814051, -0.41433689, 1.2245029211, -1.761234045, 0.0220842361, 0.0963661671, + -0.9343460202, -2.0305268764, -0.6361606717, -0.4195115566, 0.7116051316, 0.6106399894, -0.2644272745, 0.4211940169, + -1.1107473373, -0.6500771642, -0.1556589901, 1.8477299213, -1.4575940371, 0.4544501007, 0.5361469388, -1.832457304, + 0.0428999849, 0.5673006773, -0.3812290132, 0.1586058289, -0.7432076335, -2.3003587723, -3.017878294, -0.4192528725, + 0.3673498631, -0.3779532313, 0.3696709871, 0.7667483687, 1.1323468685, 0.1713690609, 1.9920309782, 1.0371128321, + 0.7972601652, -1.5348200798, -0.2240379602, -0.721164763, 1.2391200066, -0.5251198411, 0.3672321141, -0.2873863578, + 0.1083054766, -0.3605248034, 0.0712789819, 0.979960382, 0.6624241471, -1.781785965, -1.0848448277, 0.5504264832, + -0.4166675508, 1.6126602888, -0.2049243599, -1.0211094618, 0.3455152214, -0.531737566, -0.7377064824, -0.4188673496, + 0.8521258235, 0.2819546163, 0.845064044, -1.0280054808, 0.9755204916, -0.0629693344, -0.6170272827, -1.3914250135, + 1.1874107122, 0.1367413551, 0.4460196495, -1.2611466646, 0.0386255011, -0.9642368555, 0.4145136178, -0.1752219051, + -2.575417757, -1.6540249586, -0.0349275842, 0.0448959023, -0.4018982351, -0.7180095911, -0.0794271529, -1.0193690062, + 0.046608869, 1.0369007587, -0.4155933261, -0.6224948168, 0.2363770604, 2.0348365307, -1.3155070543, 1.4027558565, + 0.7323297858, 1.2334948778, 1.3659120798, -0.0808410868, 0.5328992605, -0.0881688148, -1.8309184313, -0.5434551239, + 0.6239242554, 0.8248231411, -0.5365520716, -1.2415540218, 0.7438274026, 1.1258167028, 0.1619975269, 0.2171468437, + -0.0945205837, -0.7705362439, -0.2652542293, 0.3964420557, -1.0244829655, 1.4870411158, -0.1595176905, -2.5220484734, + 0.8388492465, -1.231723547, -0.9562405944, -0.6581323147, -0.2054009885, 0.0864707008, -1.546765089, -0.0167100113, + 0.0975208133, -1.6225047112, -0.6531865597, 1.1103789806, 0.1780981272, 1.4125519991, 0.6659147143, 0.7821815014, + -2.0617392063, 0.8627902269, -0.3878584504, -0.1652761549, 0.0142101552, 0.0475623906, 0.8808799386, 0.0930731744, + 1.9853578806, 0.2075347602, 0.0492352843, 1.8051396608, -0.5307197571, -1.1836994886, 2.3241052628, -0.3693919778, + -0.0356154442, 1.7207887173, -0.0219147708, -1.0829179287, -1.5767006874, -0.1409223974, 1.347786665, -0.1534931064, + -1.1728582382, -0.7144800425, -0.2241252959, 0.354003787, -0.11531353, -0.9265352488, 0.1685252041, -0.6477338076, + -0.5638371706, 0.1049879938, -0.0841720998, -0.5061149597, -1.2376722097, -1.2302114964, -0.2418429554, -0.047562059, + 0.347055465, -0.7907449603, 0.0829786956, -0.9652466774, -0.8953530192, 0.7561290264, 0.4937201738, -0.3596648276, + 0.9256682992, 1.1828033924, -1.1108970642, 0.6139956713, 1.3882287741, -0.2518001795, -0.756391108, -0.9352231622, + 0.9392328858, 0.5460475087, 0.9603745937, -0.9488556385, -0.4981226325, -0.4026987553, 0.5920459032, 0.0090565272, + -0.8863218427, 0.0490998067, -0.1781470776, 0.2800677419, -0.9707691669, 1.3887768984, -0.6077256203, -0.2242699414, + 1.9329805374, -0.8913836479, 0.0187778343, 1.3015447855, 1.3718682528, 0.5478003025, -1.0495789051, -2.1708903313, + 1.3192451, -0.9026982784, -1.4011514187, 2.0441510677, -2.023317337, -0.0080679497, -1.6217567921, 0.4429032803, + 0.0473358221, 0.9135802388, -0.0456274971, 0.0288143251, -0.5566142201, -0.1602125764, 0.7894438505, -2.3435871601, + -0.8936960697, -0.6324608922, 1.4873902798, -0.735527277, 0.0185255464, 0.2910588682, 1.8088326454, -1.2172501087, + -1.475050211, -0.5276563764, 2.0352544785, 0.4579901695, 0.0531067401, 0.1881678998, -0.8126240969, -1.0810470581, + 0.6841163635, 1.4170793295, 0.4437287152, -0.0769727081, -1.0915343761, -0.4374568164, 1.6740102768, -2.9241530895, + 1.6825302839, -0.1471130699, -0.3678592145, 0.1373748779, -0.2201071382, -2.5014238358, -0.603821218, 0.7263562083, + 1.2062644958, -1.0378527641, -0.2458584905, -1.3896532059, -0.0786310136, 0.9795127511, -0.2071323991, -0.4947267771, + -1.6725231409, 0.2150016129, -0.6723101735, -0.2168543935, -0.9003168344, -1.2477769852, -0.1771844625, -0.6590757966, + 1.1977955103, -1.5937381983, -0.7925133109, -0.622146666, -1.6597610712, 0.4350447357, -2.5738360882, -0.6248568296, + 0.336224705, 1.0735864639, -1.4852718115, -0.2946455479, -0.311185658, 1.2795861959, 1.4509670734, -0.9087712765, + -0.875056088, -0.645388186, -2.5647492409, 0.2437494695, 0.5734773278, 1.1027342081, -0.7475714684, 2.0953369141, + -1.3439731598, -1.2973996401, 1.159611702, -0.950376749, 0.0014978965, 0.1826970875, 0.1884649992, 0.3975955248, + -0.66458112, -0.1333314031, -2.8415510654, 0.4180964828, -2.7764372826, 0.2658073008, 0.2275587916, 1.4011553526, + 1.555511117, 0.8428824544, 0.9028973579, 0.3212300241, -0.5996940136, -1.0242420435, -0.6158038378, 1.6927067041, + 0.2687541246, -0.3995000422, -0.300573349, 0.2216373682, -0.2204890847, 0.6902763247, -1.4169993401, -0.8151863813, + -1.9904801846, 0.4423972666, 0.6706801057, 0.7185264826, -0.297277391, 1.110876441, -0.8177000284, -0.57548666, + 1.1977572441, -2.6281495094, 1.5867403746, 1.4161043167, 0.7671688199, 0.1658380479, 0.8150725961, -1.6277327538, + 0.3003188074, 1.3336789608, 0.8292962313, -0.4848930836, 0.1618258804, -0.5849781632, -0.6967284083, -1.147051692, + 0.7196304798, -0.9395693541, -1.2485228777, 0.977257967, -0.9749694467, -0.9194549322, 0.155264914, -1.340796113, + 1.0570300817, -0.0778691396, 1.7038300037, -0.2739207745, -0.3102475405, -1.7548904419, 0.4191471636, 1.2825931311, + -0.5296666622, 1.0294588804, 0.1527706832, -0.8580433726, 0.4660653174, 0.2710532248, -0.7573392987, 1.7085819244, + 0.2593532801, 0.2727315128, 0.0305096321, 0.6543181539, 0.717641592, -0.2725006044, 1.1646317244, -0.1886187494, + 0.6548362374, 0.7484856248, 1.5596144199, -1.2608844042, -0.6304160357, 0.6321176887, 0.2912154496, -0.8312640786, + -0.2090908885, -0.7051216364, -1.5571593046, 1.7400833368, -1.1747038364, -0.3725011945, -0.3637978733, 0.4852464497, + -1.6679120064, -0.4092452228, 0.4874619842, -0.0685126632, -0.2348806113, 0.1828349084, 1.0253461599, -0.3952368796, + -1.0767440796, -0.4530940652, -0.5046754479, -0.4909371436, -0.3833635449, -1.825499177, -1.1022430658, 0.3569259942, + -0.224372223, -1.7885184288, 0.9822217226, -1.4025393724, 0.8213406801, 0.3869772255, -1.1860983372, -1.2052828074, + -0.1533375829, 1.8314754963, 0.8154265881, -1.0724186897, 0.8384286761, -2.0999834538, 0.2436810583, -0.034912508, + 0.7932613492, 1.1110419035, 2.4974799156, -2.8381979465, -1.0605124235, 1.058907032, 0.9585606456, 0.8247618079, + -2.523029089, 1.5672498941, -0.202685073, 2.0308806896, -0.0637612268, 0.5324293375, 0.9650161266, -0.3561647236, + -2.2441608906, 0.5721330643, -0.0420632027, 0.8333802819, -0.1294799, 0.2182023227, 0.3625458479, -0.3400902748, + -1.353757143, -1.2952094078, 0.7723783255, -0.0648406297, -1.2400768995, 1.6827946901, 1.1401575804, -1.5258969069, + 0.8159262538, -1.1959249973, -1.5505919456, -0.6034004092, -0.6083353758, -1.0715056658, -0.1194637045, 0.0140260626, + -0.9964612126, -0.117271252, -0.5439452529, -1.6995549202, -0.000862509, -0.9978842139, 0.3596127033, -0.7026296854, + -0.5324466825, -0.7600529194, -1.3232053518, -0.5340525508, -2.1644289494, 0.4067259431, -1.6405332088, -0.3487933874, + 1.1609245539, 0.2904104888, -0.1469300389, -1.5347036123, 0.2856205404, 0.0134263178, -2.1771950722, 1.0045795441, + 0.8746539354, 1.1157619953, -0.090741694, 1.4753232002, 0.5067855716, -0.7191897631, -0.35758847, -0.1088900194, + -0.4578658938, 1.6910647154, -0.351221174, -0.3477337062, -0.0016170363, 1.601130724, 0.8124353886, 0.1603957415, + -0.3600437343, -0.2487288564, -0.5773665905, 0.8298076391, -0.4896481931, -0.7197877765, -0.0610746816, -0.3374556005, + -1.5635737181, -0.6105449796, 0.517272532, -1.2310928106, 0.6385520101, 0.2386399955, 1.5264911652, 0.5826241374, + -0.6799334288, -0.5346289873, -0.2036975175, -0.7439308763, 0.4147465229, 0.0078077312, -1.0435984135, -1.2097308636, + -0.326585561, -0.8725820184, 1.7610948086, -0.9714349508, 1.5349853039, 0.2814086676, 1.2379722595, 0.4718837142, + 1.1676279306, -1.280400157, -1.5776510239, 0.4372701347, -1.1033475399, 0.6475730538, 0.4473706782, -0.1467706263, + 0.7794570923, -0.6803262234, 0.9622517824, -0.858722508, 1.2174996138, 0.2897004187, -2.5981965065, -1.5418102741, + 0.0819696561, 1.5873248577, -0.7349403501, 0.7290760875, 0.9269818664, 0.7080751061, -1.2577210665, 1.1770211458, + -1.9203807116, 0.7047927976, -1.0936950445, -0.2829663157, 0.6887729168, 1.2502661943, 0.1848202497, 0.4263668954, + 0.0182026662, -1.5792089701, -0.3927980363, 0.8779292107, -0.4019509554, 0.4690700173, -1.5016077757, 0.3696859777, + -0.9097312689, 0.730226934, -0.7808380723, 0.5710436702, -0.6982168555, 1.8683104515, 0.0536289178, 2.7342181206, + 0.9965337515, -1.3732835054, 0.5279285312, -1.594653964, 0.5114824772, -0.0093094138, -1.9116069078, 0.5795866251, + -1.323743701, -0.9147019386, -0.5839483142, -0.1468760073, 0.9125059247, -0.1213563755, 0.6303017139, -0.4348902702, + 1.0431065559, -0.3461530209, 1.0725315809, 0.9376847744, -0.6338280439, -1.7862892151, -0.8356691003, 0.463198334, + -1.3741754293, -0.151253894, 0.4590940177, -0.753461957, -0.8041709065, -0.17985636, -0.2793759406, 1.349650979, + 0.9117848277, 0.6284425855, -0.1181348413, 0.5227888823, -0.8071405888, -1.4427751303, -0.5251013637, -0.471208334, + -0.4328814149, -0.0625080392, 0.2701307237, -1.2395265102, 1.9819504023, 0.5889578462, 0.7082515955, 0.13543199, + -0.4342207611, 0.8350552917, -1.5380432606, 2.2015075684, -1.2920140028, 1.6503757238, 0.4370865226, -0.6922412515, + -1.8327370882, -0.1175616831, 0.0189046878, -0.1070931181, -1.7652977705, 0.5713495612, -0.8332467079, 0.3077534735, + -0.5451762676, 0.5432214737, 0.9431089759, 0.2331315875, 0.4595543742, 0.6053746343, -0.5241636634, 0.6633955836, + -0.5136868358, 0.3695436716, 2.5949618816, -1.8505828381, 1.3736778498, -0.2972381115, -1.7225773335, 0.3269241452, + -0.9890488386, 1.9549521208, 0.5292824507, 0.6432071328, 0.2097698003, -0.3138158023, 0.0110373385, -0.836854279, + 0.633898139, 2.1725356579, -1.3096066713, 0.5576665401, -0.8026767373, -0.0024915286, 0.7201132178, 1.1928230524, + 0.2271231711, -0.0062309671, -2.3676698208, -0.2402453274, -0.5720393062, 0.8346250057, 0.1938629746, 0.6820136905, + -0.1138827205, 0.0992246643, 0.6323102713, -1.8433687687, -0.2471316308, 0.8616644144, 0.6367298365, 0.6539236307, + 0.5544044971, -0.3177534342, -0.7643328905, 0.5900797844, 0.7913125157, 0.7577337623, 0.7785899639, -1.044039607, + -0.6633660197, 1.5012997389, -0.0091627706, 0.7560212016, 0.8975538015, -0.9736179709, -0.2276934981, 0.9973939657, + -0.333458513, -0.8088312745, -0.3517300487, 2.3488607407, 0.6854371428, 0.3064183891, -0.4391704798, 2.6296787262, + 0.2384973019, -0.9323630333, -0.1401946098, -0.8720086813, 0.7077708244, -0.3136989176, -0.0932615995, 0.6460273266, + -0.4569582045, 1.7222473621, 0.2486722022, -0.5947818756, -0.572445631, -1.2928011417, 0.3518567085, -0.2768443227, + 0.1744876951, 0.7715813518, -0.3155222535, -0.6012001038, -0.0778921768, 0.6547526121, -1.5268802643, -0.8698882461, + -0.2165810913, 1.1484020948, 0.6043649912, -0.7420395613, -0.0446573719, -1.3837007284, 0.5973103046, -1.201723218, + -0.4692558944, 1.0996962786, 0.4843816459, 0.39249295, 0.5177378058, 2.1317279339, 1.7797539234, 1.8023210764, + 0.5402734876, 1.6492481232, -1.1998282671, -1.1383824348, -1.3544220924, 1.0511277914, -0.3663887382, -0.0666134506, + -1.7126017809, -0.1563147753, -1.6851294041, -1.6602188349, -1.3355588913, -0.2164773196, 1.3588712215, -0.7749710679, + -0.5971747041, -1.5134319067, 0.6159718633, -1.0240488052, 0.4399787486, -0.2938184738, 1.3824003935, 0.9063398838, + 1.7439777851, -0.8023254871, 0.7868092656, 0.0004580946, 0.4446972311, 1.3736970425, -0.3319808543, 1.690384984, + -0.811449945, 1.7070233822, 0.3595496714, -0.1166067645, 0.646396935, 2.5515398979, -0.9076561928, -0.1777824014, + -2.195761919, -1.9981634617, 0.4334587753, -0.7519865036, -1.0104613304, -0.7528412342, -0.2588641346, -1.237197876, + -0.0698891729, 0.2212488353, 0.4128143191, 0.5448367596, -0.3559421003, 0.1989956051, -0.7013852, -0.6775157452, + -0.4674378335, 1.0175814629, -0.9423191547, -1.4644925594, 1.0119210482, -0.5379062891, 2.3790464401, -0.7766230702, + -0.2486738861, -1.7352688313, -0.0490255542, 0.3822934031, 0.7362163663, 0.7763320208, -0.1527945995, 1.2485646009, + 0.2239975333, 0.6150395274, 0.1295638382, 0.0960831046, -0.1421104372, 0.6133358479, 0.8356537819, 0.7742197514, + 0.1762249768, 0.1703704149, -0.3257652521, 0.547119081, -1.5459822416, -1.510463357, -0.3404698074, 1.1019839048, + 0.8252863288, -0.2277154028, -0.4301207066, -0.0688877627, 0.8002319932, 1.4292235374, 0.4345422983, -1.4420714378, + 0.160687536, 0.3235762119, 0.1411382407, 0.1357653439, -0.4222933948, -1.0847389698, 1.8023097515, -1.3667072058, + 1.5778913498, -0.0131876403, 0.3190685511, 0.8450273871, 1.1641961336, -0.716237247, 0.3938809037, -0.3219540715, + -1.7239831686, -1.1850391626, -0.2674075663, 1.1804103851, -0.9732410312, 0.1530347764, -0.5131613612, 0.5818021894, + -0.1796519756, -0.3842805624, 0.4687068462, -0.3080357015, 0.646046102, -1.9881218672, -1.7341786623, 0.0405684933, + -1.2557553053, 1.1959751844, -0.2807148993, -1.1054583788, -0.9994213581, 1.3731906414, 0.524882853, 1.1866965294, + -0.8613355756, -0.2546068728, -0.4799605608, -1.8969695568, 0.2036823183, 0.0273817368, -1.9169287682, -0.9908143878, + 0.1783454567, 0.4995328784, -0.3635697961, -0.0450246893, 1.6701726913, -0.1013248339, 1.0435426235, -0.8696965575, + -1.1632086039, 0.1831671149, 0.6457328796, 0.200663954, 1.5764163733, 1.4348359108, 0.4867582619, 0.0998035371, + 0.2122234851, -0.0686026067, -0.2263608724, 0.3516403437, 0.7742586732, -0.3687585294, -1.5238984823, -1.5085883141, + 0.2777234614, -0.3668000698, 0.1228307188, -0.8946448565, -0.5748972893, -0.0552437901, 0.130643025, 0.4406910539, + 2.4174592495, -0.9714004993, -0.5191168785, -0.5188544393, 1.3178100586, 0.1041980833, 1.246374011, -0.0790428743, + 0.6186703444, 1.2864513397, -0.8152043819, 0.4917009175, -1.106779933, 0.0927638784, -0.1811284125, -0.4697842598, + 0.3500574529, 0.3294185996, 0.1947860867, 0.8966708183, 1.9381089211, -0.9195051193, 0.7260957956, 0.8662853837, + -0.5145770311, 0.1757200509, -0.8238931298, 0.1056567132, -0.1374659091, -1.2861822844, 0.5849096775, 1.8646203279, + -1.6820768118, -0.9834036827, 1.380774498, -1.2435959578, -1.6130899191, -0.7388973832, 2.2242629528, -0.4154294133, + -1.748073101, -0.2249363214, -0.7993203402, 0.646039784, 0.1766046137, -1.6437238455, -0.011055097, -1.4476402998, + -0.2804417014, 1.2617326975, -0.2355776876, -1.687300086, 0.8121863008, -1.6272295713, 0.7626906633, 0.1414132714, + -0.9910776615, 0.8963002563, 1.4895867109, -0.7519250512, -0.1140206978, -0.2397381216, 1.8317588568, 0.971061945, + -2.1389555931, -1.1381371021, -0.7534425259, -1.2349971533, -0.9838739634, 0.7869290113, 0.7393561602, -0.9010815024, + -0.1183883175, -1.5193796158, 1.0234062672, 0.492972672, -0.5983226299, -0.8546621799, -0.9928486943, 0.8580879569, + 0.8566496372, 0.319827348, -0.2430842817, 0.252921313, -0.4792161882, -1.486495018, 1.4555321932, 1.3306303024, + 1.2000240088, -1.2556482553, 0.4722168446, 0.7385764122, -0.3788935244, -0.4737539589, 0.972207129, -0.9189504981, + 0.6632404923, -0.1334913969, -1.566370368, -1.7486513853, -1.1225919724, 0.7985507846, -0.0880931318, -0.2178262472, + 0.3675931692, -2.1636779308, 1.576837182, 0.0332911499, -0.6151152849, 0.7404027581, 0.7260823846, -0.8314467072, + 0.6558555365, -0.3027761579, -1.3855255842, 0.0839681327, -0.891427815, -1.5680286884, -0.6328111887, -0.1193251312, + 0.2832503319, 0.2091138959, 0.0765040293, 1.0707458258, 1.1313108206, 0.6235074401, 1.1784594059, -1.4363331795, + -0.4905205369, 0.124826856, 0.3911684453, 0.2099477947, -1.4990891218, 0.5412989259, -1.1710778475, 1.2187296152, + 0.6991159916, 1.268679142, 0.0984257534, 0.1025270298, 1.6023763418, 0.3297880888, -0.9317253828, -1.277725935, + 1.5729357004, 0.7261555195, -2.7456653118, 2.269012928, -0.4050147533, 1.7808687687, 1.9016879797, -0.3218570054, + -0.2043680102, 0.1489765644, -1.4593832493, -1.5017405748, -0.867035687, 0.2126237601, 1.335105896, 1.6312758923, + 1.6304445267, -0.4380942583, -1.3650913239, -1.4511771202, 1.0316030979, 0.8142898679, -1.6095172167, 0.733058095, + -0.3812020123, 0.5772187114, -1.0423914194, -1.7273218632, -0.0568555333, 1.2256610394, 1.6008268595, 0.4206520319, + -0.5724737048, -0.2653441727, 0.5704436898, -0.2628526688, -0.771846354, -0.1277451515, 1.1820430756, 0.4724800885, + 1.4606692791, 0.0491502918, 0.4095941186, -0.5304942131, 1.300716877, -1.6952812672, -0.3756690323, 0.3484024704, + -1.6185001135, -0.1921009719, 0.0708475932, 2.43572855, 0.9716811776, -0.9329621792, 2.865203619, -1.7920479774, + 0.544934392, 2.4494490623, 0.0170834791, -1.3960881233, 0.591299355, 0.7908234, -0.2101195306, 1.0908360481, + 0.9109295607, 0.105351828, 0.9273505211, 0.8930205107, 0.5378038287, -0.6903609633, -1.1878529787, -0.4941872358, + 1.1770657301, 1.0582617521, 0.5110420585, 0.5188018084, 1.3615533113, -0.2138238251, 0.4488541186, 1.4647057056, + -0.383551538, 0.7276459932, 1.1939560175, 0.212264657, -1.0129065514, -0.5653158426, 0.1305658966, 0.2739067674, + 0.741299808, 0.0615668334, -0.4668753147, 2.5491123199, 1.0991567373, 0.6903136969, 0.6747993231, -0.4939589202, + -1.8001532555, -0.2043026686, 0.0035368698, -0.00573332, 1.0612637997, -1.4626442194, 0.4315978885, -0.6228010058, + 1.2404770851, 0.1704462916, 1.986898303, 0.1113011688, 1.2096550465, -0.4573297799, 0.9231835008, 1.3255188465, + -0.9531663656, -0.6781297922, 0.3340995908, -0.7549282312, -0.3883825243, -0.6265756488, -1.3064211607, -0.0384958498, + 0.1435673833, -0.7890736461, -0.0985037014, -1.4528664351, -0.947865963, -0.8695787191, -0.3055172861, -0.6051473618, + 0.2248205394, -1.038472414, 0.7718191743, -0.4800092876, 1.8347450495, -0.1087654233, 0.4544749856, 0.0987093523, + -0.4583054483, -0.8570440412, -0.774402976, 0.708787322, 0.0184736028, -0.1040805802, -0.234857738, -0.2509063482, + -0.9627502561, 0.4934051633, 2.1330499649, 0.9838882685, -1.8092817068, 0.0423588157, 0.5168721676, -0.0329206921, + 1.2981114388, -0.2021170259, -0.8332309723, 1.7336002588, 0.1906490028, -0.1778104007, -1.0850250721, 0.9722623229, + 1.4314717054, -0.2450730503, -0.6232538223, -0.3959988654, -1.3585224152, 1.3226025105, 0.0034439384, -0.0001967701, + 1.5337039232, -0.7730822563, -0.401254952, -0.1153567657, 1.0115554333, 1.513235569, 0.9170686007, 0.7288931012, + 0.5520321727, -2.8032341003, -0.3960531652, -0.7131436467, 1.3008337021, -0.5528658032, 2.0708973408, -0.3659083247, + -0.8976300359, 1.4449365139, 0.1729418486, 0.2826884985, 1.0908695459, -0.2013481557, -0.6806857586, 0.8032750487, + -0.342163831, -0.4724888504, -0.6922569275, -0.0466712639, -0.61958009, 0.8695260286, -0.146882847, 0.3280917704, + -1.3630435467, 0.8078343272, 0.660664022, 0.778850019, 1.5073202848, 0.3795762062, 0.6519295573, 0.3520001471, + -0.4837388992, -0.135742873, -0.1349714249, 1.0053361654, -0.8543254733, -1.7947654724, 0.9829106331, 0.8027749658, + -0.4673963487, -1.4142329693, -1.1199934483, 0.88719666, 0.0762820542, 1.2231287956, -0.665636301, -0.3412737548, + -0.5046559572, 0.327573359, 1.1423867941, 0.7465314269, 1.7910561562, -0.0725371093, 1.2476819754, 0.071142979, + -1.8477734327, 1.9659148455, -0.2410738766, -0.1578042954, 0.5254576206, -1.9116709232, 0.9348053932, 0.8459461927, + 0.1184646636, 0.5029144883, -0.198277086, 0.7655358315, 0.9073389769, 0.1973911673, 1.3738481998, -0.9893300533, + -0.9891023636, -2.4769854546, 0.7702542543, -0.0861265808, -0.8576679826, 0.6391736269, -0.24720034, 0.2333795726, + 0.8708141446, 0.6738551855, 1.6272670031, 0.751696527, -0.7883411646, -0.8082208037, -1.3736037016, -0.4045992196, + 1.0280630589, -1.5187823772, -0.4838001728, 0.615073204, 0.8216204643, 0.1266588718, 0.5752500296, 2.1062376499, + 0.8944895864, -0.7871508598, -1.3972195387, 0.327319622, 0.794654429, -0.4160199165, 0.7112743855, -0.0405380018, + -1.7044556141, 0.5837534666, -1.0075877905, 0.7251850963, 0.9467189312, 0.5067328811, 1.6449491978, 0.5131101012, + 0.3260095119, 0.5165187716, 0.1619718522, 1.9142762423, 0.6852089763, 2.6714634895, -1.261583209, 0.0633755252, + -0.6122508645, 0.7064356208, -0.1490675062, 0.3214509189, -0.3426703811, 0.3457258642, -0.4682802856, 0.2918916047, + 0.4650507569, 0.1249749437, 0.5599335432, 0.6786236167, -0.4045546353, 0.6692442298, 0.4938224852, 1.2209396362, + 0.1036879346, 0.6975646615, -0.6695911288, -1.29091084, 0.1948612928, 0.194225207, -0.67482692, -1.9970334768, + 2.4057705402, 0.6200784445, 0.3772981763, 1.5525032282, -1.4655271769, 0.3644940555, -0.0155226057, 1.1985623837, + -0.4178135395, -1.6951625347, 0.8210743666, -1.7736728191, -1.059450388, 0.7284531593, 1.1591846943, 0.2815538645, + -0.3945144117, -1.985350132, -0.4423422217, -0.9395880699, -0.3203176856, -0.9223166108, -0.52976197, 1.6634757519, + -2.5264670849, -2.2690434456, 0.5216883421, -0.3797107339, -1.0727113485, -1.2990864515, 0.1797483265, 0.2679230273, + 0.7701867223, 1.3195123672, -0.4258531332, 0.0932302922, -0.1008663177, -0.0527959503, -0.2420887053, -1.235877037, + 0.2188131213, 0.2474349886, 0.091124095, 0.9356385469, 0.6642363667, -1.7988439798, -0.9775348902, 1.0068738461, + -0.4412638247, 0.2630724311, -0.2938269973, 1.2398545742, 0.1530414075, 0.091940254, -1.4946030378, -1.6424170732, + -0.3924821019, 0.9380593896, -0.7755195498, 1.4306209087, -0.597309351, 0.4153765142, -0.4966987967, 0.455167383, + 1.3969449997, 0.9603327513, 1.669487834, -0.7250531912, -1.1356847286, -1.2331088781, -0.2271185815, -1.2854925394, + -0.9318059087, -0.76067698, 3.2205018997, 0.2209428847, -0.062912263, -0.6298869848, -1.0732094049, 0.001055815, + -1.0177214146, -1.5743277073, -1.6354320049, 1.7043139935, -0.6617698073, -1.659916997, -0.3333908916, 0.6777613759, + -0.0104675246, -1.1323215961, -0.0904404595, -0.5879105926, 1.0276099443, 1.4621688128, 0.2452373505, -1.8568937778, + -0.2075275332, 0.0924542099, -0.5434443355, -0.5015999079, 0.3858227134, 0.5888552666, 1.1586396694, -0.7475170493, + -0.2434626371, -0.1310633272, 0.266756773, 0.5259755254, 0.112122409, -0.5332795978, 0.8407949805, 1.0488711596, + 1.6149709225, 0.9318397045, -2.2712433338, -0.7382249832, 0.0473290794, 0.1856919378, -1.3058172464, -0.7064233422, + -0.1791879386, 0.503854692, -0.6263046265, -0.0282821339, -0.7154991627, 0.4878412187, -0.0843407884, 1.773789525, + -0.4433949292, -1.0820724964, -0.5127086639, -0.4460237324, 1.8900141716, 1.337377429, 0.3039647639, -0.1128789261, + -2.2114961147, -0.7659804821, 0.0121604325, -0.5553606749, 1.8555424213, 0.9179546237, 0.235240981, 0.858458221, + -1.1751790047, 1.6242084503, 2.2770774364, -0.1804874986, 0.5590753555, -0.199274227, -0.5453976393, 0.5759513974, + 1.165238142, 1.6872155666, 1.8794616461, -1.1923128366, -0.3455305696, -0.09260986, 0.0298121963, -2.2340764999, + -0.0128461355, 1.7809996605, -1.769805789, -0.1657604724, -0.2962538302, 0.3984484971, -0.2784538865, -0.7657407522, + 0.5881029963, -0.0268511921, 1.2491877079, 0.5969085693, 0.8053591251, 1.2250876427, -1.6654818058, 0.7458550334, + 0.176718384, -1.0294940472, -0.3047012985, -0.8348066211, -0.5481224656, -0.2275418341, -0.3919983208, 1.7537639141, + -0.454885304, -0.2024148703, -0.7957806587, 0.7550222874, 0.5483199358, -0.6040002108, -1.0742310286, -0.2339738905, + -0.7312679887, 0.6031473279, -1.9090847969, -0.4644692838, 1.8127008677, 0.5727068782, -1.1307305098, -0.2126340717, + 0.9141866565, 1.0289263725, -0.9336540699, 0.968583703, -0.4468255639, -1.3155292273, 0.9664657712, -0.130592674, + -0.1409974098, -0.2777955234, 0.1934855133, 0.2790493965, -1.0827175379, -0.6172372103, -0.9062939882, 1.6249476671, + -0.8238903284, 0.6574448943, 1.3339018822, -0.73962152, 0.0353739858, -0.9580649734, -0.1081325933, -0.5253806114, + 0.8399999738, -0.6203387976, -0.1352863312, 1.8578811884, -0.9981376529, 1.3206781149, -0.0126401605, 0.5569839478, + -0.1270247847, 0.4880434573, 0.5574302673, -0.4547669888, -0.6072672606, -1.0674308538, -0.5023055673, -0.4857284427, + -0.0919217393, -0.9623599648, -0.0035295901, -0.0758933797, 0.0933261737, 1.2281299829, -0.0178553499, -0.4720449448, + 0.22141397, 1.4468604326, 0.4306001961, 1.0677331686, -1.6240931749, -1.1872859001, -1.1063474417, 1.1893283129, + -1.3409972191, 0.7507525086, 0.214459762, 0.3168707788, 1.2522690296, 0.9644386172, 2.1303524971, -0.7632300258, + 1.7955607176, -0.3486187458, -0.385946691, 0.2825184762, -1.0904860497, 0.2479778975, -0.3009818196, 0.4486035109, + 0.9551592469, 1.4568217993, -0.647967577, -0.371350646, 1.0168209076, 1.2009193897, 1.0800970793, -0.3941484392, + -0.1019895002, -2.3731226921, -0.3524095416, -1.0711951256, 0.5553830862, -1.7090671062, -0.6871978641, 0.0623640977, + 0.0408379324, 0.4368767738, -0.9474046826, 1.3001302481, 1.1587718725, 0.4988572299, 0.2281088084, -0.6101936698, + -1.8242050409, -0.0441021472, 2.4481766224, 0.9330115318, -0.1531505287, 0.043076545, 1.4130680561, 1.1317970753, + -0.8838879466, -0.4641161561, 0.8401603103, -0.1360720992, 0.7551409602, 0.9949775338, -1.5624421835, -0.3360073268, + 0.2582748532, 0.6022772789, 0.17842336, 0.7269070745, 1.0488575697, -0.3621068895, 0.6744479537, -0.4786558449, + -0.2334593087, 0.4071067572, 0.283918947, 0.7738007903, 0.4134279788, -0.1320126951, 1.0825728178, -0.8175003529, + 1.4486014843, 1.0853774548, -0.2358137816, -1.6589474678, 1.1178635359, 1.0709910393, -0.3829950988, -0.1981175393, + -1.398810029, -0.0638643652, -0.1147952601, -0.38312006, -0.885700345, -0.8296794295, 1.4530539513, -1.6511634588, + -2.5654265881, -1.1252266169, 0.3472560346, 0.9780961275, -0.7914997339, 1.9477938414, 0.3580872715, 0.1118140593, + -0.2804694772, 0.4610228837, 0.6023619175, -0.5335633159, 0.0542477593, -1.7664861679, -0.050807666, 1.9950895309, + 1.5672857761, 1.4353256226, -0.5908765197, -1.2080715895, -0.6752406359, -0.7683525085, 0.2406216562, -0.8646903634, + -1.6352556944, 1.7879844904, 0.3776165843, 1.570445776, -1.4466234446, 0.8425059319, -1.20139575, -0.3469410837, + -0.7660391331, -0.6346268058, 1.6559984684, -0.6233503819, 0.4907566309, 0.8447885513, -0.9813486338, -1.4458115101, + 0.6337310076, -0.556142807, -0.5065686107, 0.1102068424, -0.5101391673, -1.1948239803, 0.7441099882, 0.0857115984, + 0.051598262, 1.1483319998, 0.7804873586, 0.5419780016, 1.2188420296, 2.0769410133, -2.4862742424, -0.4223719239, + 1.00997293, -0.7526311874, 0.0810160041, 0.5616210103, -0.4127331972, 0.1325272769, -0.5238465071, -0.3826581836, + 0.0631827638, 0.2585388422, -1.0420076847, -0.4863687158, 0.0387250669, -0.4188231528, 0.0140505927, -0.9987033606, + -0.8189831972, 0.2218448222, -0.5424128175, -1.5457696915, -0.4346087873, 0.425547868, -0.2396979183, -1.6252154112, + 0.3310910463, -2.3621444702, 0.2520245612, -0.2275166214, 0.329708457, 0.9491755962, -0.0028857999, 0.3958771825, + -0.3808728158, -0.7215411067, 0.9620351195, -0.9630186558, -0.4433543384, 1.2981798649, 0.0506372303, 1.3202215433, + -0.0137817934, -2.1586008072, -0.285115093, 1.0693598986, -0.4877946377, 1.0574339628, -0.5105757713, -0.5830003619, + 1.8261824846, -1.2577497959, 2.4384016991, -1.2908158302, -1.2552080154, -1.0708709955, 0.3558755517, 2.2702765465, + 1.6279611588, 0.9271426201, 0.4194103479, 0.699685514, 0.2764927447, 0.0600915737, -0.2719833255, -0.0216664709, + -1.0817744732, 0.2898022234, -0.7958546281, -0.5543126464, 0.0587645993, 0.2073607743, 1.6387189627, 0.9563472271, + -0.114477843, 0.4083743691, 0.3125553429, -0.0443716496, -1.4478203058, -1.4528867006, -1.0498052835, -1.0768823624, + -0.981790781, 1.0057474375, 2.1739764214, -0.1706229895, -0.3973425627, -0.8106067777, -0.3117626309, 1.7385970354, + 0.4636293352, -0.3924411833, -0.5573529005, -1.3127901554, -0.0500530154, -0.3318820298, 0.6395338178, 0.1124192551, + 1.618853569, 1.5975137949, 0.7731382847, 0.1306872517, -1.3235602379, -0.4722246826, -0.2985983193, -0.439748317, + 0.9028589129, 0.7685422301, 0.9230428934, 1.6842801571, 1.4418077469, -2.5131144524, 0.4086238444, 0.0655701682, + -0.3320867121, 1.7466781139, 0.3734170496, -0.272829175, -1.6017853022, 0.7018960714, 0.4604117274, 2.3683567047, + 0.4982431233, -0.3625016212, -1.7402305603, -1.1604846716, -0.0124342721, -0.0771125332, 1.2629164457, 0.2355280519, + -1.0599642992, -1.4503680468, 0.19688043, -0.3745819032, -0.6852248907, 1.8013814688, 0.493092984, 0.7483561039, + 2.1840589046, 0.0830427632, -0.6732596159, 1.021571517, -0.5686770678, 0.8424426913, -1.9740310907, 0.6989012957, + 0.0312862769, 1.7320979834, 1.0707975626, -1.0670249462, -0.2167563587, 1.7714269161, -0.2345068604, 2.4865136147, + 0.2414270341, 1.7394777536, 0.4267886877, -0.6875585318, 1.1192632914, 2.2618951797, -0.1167902946, 0.4676852822, + 1.3006483316, 2.9003543854, 1.5146406889, -1.1470533609, -1.2451536655, -0.5879987478, 0.5812782645, 2.1253869534, + -0.0506866947, 0.4011137187, 0.7882096171, -0.6160338521, -1.2647396326, -0.2363180667, -1.5727478266, -0.053175617, + -0.5144679546, 0.2395006865, -0.8833888769, 0.2919378281, 0.2528843284, 1.3525061607, 0.1802900583, -0.9587054849, + -0.1820952743, 3.0571014881, 1.5167911053, -1.0126098394, -0.17193681, 0.407913059, 0.1754129082, 0.3528579772, + -0.2692727149, -0.8049977422, 0.0460437089, -0.0798596963, 1.072180748, -1.1028991938, -0.6041131616, 3.4571788311, + -0.4846538603, -0.6901526451, 1.0774567127, 0.1411880702, -0.4632414579, 0.1769790202, 0.8287273049, -0.7865691185, + -0.8834164739, 0.8981291056, -0.3418011665, 0.4376186132, -0.8193335533, 0.7731699347, 0.351690203, 2.3642060757, + -1.3887287378, -0.3825967014, 0.6642029285, -0.8499180079, 0.8090372682, -0.0887294859, -0.7657515407, 0.4094007313, + -0.2589460313, -0.0710417926, -0.2994653583, 0.1474562585, -0.026548788, 1.6107178926, -0.8812941909, 0.0249902233, + -0.3142261505, -1.5077643394, -0.5018021464, 1.0165740252, -0.0183646958, 0.3615891039, 0.7975444198, 1.2121458054, + -0.6506839395, 0.3548581898, 0.2484272867, -0.2789663076, 0.5858780742, 2.3015351295, 1.2746146917, 1.0363812447, + 0.7774479985, 1.1028864384, -0.1068114564, 0.1970036775, 0.1932538748, -0.3952465057, 1.1583861113, 1.4059976339, + 2.121932745, -1.8358495235, -1.2085362673, -1.3249143362, 0.4205504954, 1.1037262678, 0.9093187451, 1.4752906561, + -0.8287338018, 1.0169249773, -0.6972437501, -1.4810217619, -0.7408619523, -0.6186295152, 0.5369817615, -0.2822094262, + -0.1443003863, -0.7923364043, -0.6148132086, -0.0632172227, 0.1186423898, 0.3373407423, -1.3994134665, 0.5843821168, + 0.1835361719, -1.369317174, 0.658125937, -2.2536697388, -0.7097249627, -0.2993446589, -0.7744182944, -0.7150697708, + 2.7478237152, -0.4464194179, -0.5393986702, 0.504845202, 0.0309016295, 0.7893177271, 0.8253213167, -0.1216339916, + 0.8358047605, -0.5530250072, -0.6232783794, 0.1180848405, -0.5877562761, 0.3572616875, 0.6083747149, -1.6882966757, + 0.3013758063, -0.9361636639, 0.6878786087, -0.5113450289, 1.38537395, 0.2846948504, 0.4329951406, 0.1250179708, + -0.8994542956, 0.2352239043, -1.2032506466, -1.7193822861, 0.5931987762, -0.9778930545, 0.2653068602, 0.5067004561, + 0.5289206505, -0.8424483538, 0.3913740814, -1.1664303541, 1.4980700016, -2.3028693199, 1.2116063833, -0.2439048588, + -1.2052580118, -0.2917331755, 0.0616047978, -0.6883229017, 0.6314316392, 0.2147449553, -0.4651604891, 0.0913353115, + -0.6877609491, 2.5887622833, 2.2688219547, 1.6409702301, 0.7080410123, -1.6533527374, -1.6032719612, 1.0296443701, + -0.1468841136, 0.70792979, 0.7750738263, -0.5503200889, -0.1952609122, 2.206902504, -0.3737757802, 1.3544288874, + -0.1811147928, 0.1393500119, -0.1114728898, 1.0114481449, -0.6935762763, 0.2787633538, -2.0546996593, -0.5709084868, + -0.3062367737, -0.3156863749, -0.8897069693, -2.323143959, 0.4797623754, 0.0417126454, 0.0786912814, 0.831097424, + -1.6643717289, -2.1256644726, 1.2952638865, -0.9766326547, 0.1436393559, -0.7110436559, -1.1480141878, -1.1452629566, + -0.8019243479, 1.5351486206, 2.1707282066, 0.7657800317, 1.5620862246, 0.1756275594, -1.350317359, 1.7917487621, + 0.7160843611, -0.1938566267, -0.4526286423, 0.2835141718, -1.2592515945, 0.3630310297, 0.3490190506, 0.493124485, + -0.8836598992, -1.2861914635, 0.6278840899, 0.5298740864, -1.4413779974, -0.2835259736, -0.5337915421, -0.5376721621, + 0.2081073076, 0.9799979329, 2.2777760029, 1.2127616405, 0.5642753243, 0.0354485251, -1.0789268017, 0.11252103, + -0.2152985483, 1.7759253979, 0.9840850234, -0.0767186433, 0.6679525375, -1.011530757, -1.5240343809, 0.1609255522, + 0.8578897119, -1.6950411797, 1.2214843035, -0.1197355837, 0.9035636783, -0.2301980704, 1.8057299852, 0.013448217, + -0.8037886024, 0.445260644, 0.1248501688, -0.5301916599, -0.8451347947, 1.15023911, -0.1114130989, 1.0182909966, + 0.1798265725, 0.072553888, -0.0725682154, 0.6086733341, 0.6504692435, -0.0388825051, 0.6453584433, 1.5192260742, + -1.3471193314, 0.3118595779, -0.6958822012, -0.8889675736, -1.8208668232, 0.3896815777, -0.2915764749, -0.0712015107, + 0.4959938824, 0.5245856643, 0.1248565987, 2.2854576111, -0.3773034513, -0.4099958241, 0.2611141205, -1.1319282055, + -0.8118616939, -0.0755043477, 0.8247570395, -0.2658351064, -0.5308529735, -0.5981125236, 0.5713994503, 0.1442613006, + -0.0215171184, -1.5180338621, -1.9154884815, 0.9877078533, -0.2374628782, 1.3302844763, 0.1467256844, -0.2150432318, + 0.6785774827, -0.7292082906, -0.2542716265, 0.4539424479, -0.0867115185, -1.2298870087, -1.1490353346, 0.9752449989, + -0.1623965055, -2.7027933598, 1.0214067698, -1.6213696003, 0.4340440631, 1.3481116295, -1.2926946878, 0.3220206499, + -0.6569662094, 1.6419132948, 0.1643116474, -0.0132283932, -1.8333109617, -0.9346026182, -0.9406163096, -0.9235872626, + 0.6504324079, 0.1044687778, 1.22681427, -0.2209423184, -0.238408342, -1.2015172243, -0.5316178203, 0.1752220094, + 0.6893568635, 0.2345945686, 0.4606382847, -0.6025770903, -0.8063659668, -0.5693377852, -1.8322895765, -0.458871901, + -0.4438908696, 1.3813488483, -0.7166424394, -1.3205441236, 1.6986227036, -0.9610489607, 0.740299046, 0.5968779325, + -2.0013959408, 1.5075762272, -0.038940303, 0.493681848, -0.3687821925, -0.3875725567, 1.2237678766, 0.3262037039, + 0.8998846412, 2.1900782585, 1.2703543901, 2.1951560974, 0.2156772017, -1.5663990974, -2.2078025341, 0.0685291588, + -1.5581027269, -1.0036827326, -1.3702378273, 0.1694180816, -0.9137530327, 1.0961093903, -0.1972991228, -0.8759288788, + -0.524163723, 0.4103074372, 0.1449525803, -0.7451390624, 0.2333553135, 1.1782257557, 0.1412797421, -1.436144948, + -0.3597810268, -0.8911457658, -2.2995569706, 0.0269727893, -0.5035428405, -1.4560674429, 1.7810405493, -1.3310171366, + -1.886980772, -0.2242967784, 0.7271280885, 0.7559499741, 1.4708317518, -0.0475333333, -0.550506115, -1.2091144323, + 1.0972720385, 0.1798228621, 0.0975974947, 0.6015082598, -1.5747113228, -2.380423069, 0.2242878824, 0.4144230783, + -2.0694725513, 0.0689833388, -0.8785431981, -0.2263758332, 0.2870897055, -0.1257645935, -0.5280503631, -0.6401610374, + -0.9018902183, 0.6883198023, -0.2870998979, 2.0648100376, 2.5321288109, -0.1234981641, 0.370254755, 1.3969179392, + -0.287263602, -0.517541945, 0.1475308388, 0.0770351812, 1.0055582523, 1.4378954172, -0.5518070459, -0.0454276241, + -0.9547314644, -1.7417740822, 0.5516366959, 1.4494178295, 1.2299993038, 0.0344757847, 0.8050377369, 0.158656314, + -1.4417908192, 0.8038492203, -0.4616938531, -1.5563237667, -0.2434473038, 0.8458123803, -0.3156723976, -0.9523938298, + -0.3382590115, 0.1520356685, 0.3631040454, 1.6726390123, -0.6849400997, 1.6337143183, 0.3757461905, -1.1149408817, + -0.1292464733, 0.5845023394, 2.7107896805, 0.1954807341, 2.0079009533, -0.3136621714, -1.4966130257, -0.482779026, + -0.5490916967, 0.8668015599, -0.4425382912, -0.347021848, -0.0106614679, 0.1458479911, 0.9882314205, 1.5065393448, + 1.0266677141, -1.6985048056, -1.2251684666, -0.0537470914, 0.6280582547, -2.1100039482, 0.092158258, 2.0108947754, + 0.1368566453, 0.2666280866, 0.5259639025, -0.5141676664, -0.1254386157, -1.9846127033, -0.6376038194, 0.1830519587, + -1.3448629379, 1.7952604294, -0.6953235269, -0.444584012, -0.285097599, -0.6821460128, -0.611626029, -0.0420884788, + -1.1017171144, 0.6697148681, -0.3835142255, -0.1298492849, -0.4696798623, 1.4395703077, 0.0283602029, 0.4346496761, + 0.9028067589, -1.2745651007, -0.8085855246, 0.2151665688, 1.1069250107, 1.0683196783, -1.1012074947, -0.2108737677, + 1.031654954, 0.0220382344, 0.1956191957, -0.0308300909, 0.981885016, -0.9788653851, -0.4604631364, 0.717371285, + -2.1900360584, -0.0521114245, 0.0403597429, 1.245362401, 0.5835828185, 1.4235873222, 0.9640865326, 0.2892068624, + 0.2281533778, 0.1888966411, -0.6644412875, -0.3662932515, -0.4654232264, -0.126557976, -0.527933538, -0.2821264863, + 0.5741770267, -0.9894772768, -1.6030364037, 0.5362505317, -0.0642012283, -0.5990480185, -0.398134172, -0.4884864092, + 0.8829444051, -0.9191870689, -3.5971634388, -1.1088981628, -0.2825691402, 0.0801857784, 2.0061070919, 0.5381712317, + -0.6989403963, -0.6342703104, 0.6783562303, -1.7275750637, 0.1030801684, -1.1218008995, -0.8425818682, -0.2069326192, + -1.2354469299, -0.6567828059, 0.1083241701, 0.8044376969, 0.2656084299, -1.1283918619, -0.7726039886, -0.267803371, + -0.8238725662, -0.7397587299, 0.3420245945, 0.6743623018, 1.0771563053, -1.1560052633, -0.3988094032, -0.2347034961, + -2.5536952019, -0.4352763295, -0.7365463376, 0.6908099055, 1.7416143417, -0.8961228728, 1.100348711, 1.5549330711, + 0.7204515338, 0.2944574058, -0.5237665772, -1.2406834364, 0.1910576522, -0.5132317543, -0.1078897566, 0.2912856638, + -0.1775024086, -0.4434978366, -1.6129906178, -0.883127749, 2.1223089695, 0.5924318433, -0.1580628008, -1.5093832016, + -0.105222173, 0.4946533144, 1.304449439, -0.5286353827, 0.5293801427, -0.0658370033, -2.1142232418, -1.6638370752, + 0.1901883334, 0.072226882, 1.624886632, -0.1596909165, 0.9091033936, 0.0457334258, -0.1473118365, -1.2650078535, + 1.229351759, -2.2262835503, 0.8036817908, -1.5079095364, -0.3022215068, -0.5339203477, -0.0028147821, 0.9604151249, + 1.0207607746, -1.7765924931, 0.3125726283, -0.5199762583, -0.7035210133, -1.5594059229, -0.9711892009, -0.8094975352, + -0.2992601693, 0.1038063467, 0.4899407625, -0.4866145849, -0.4270956218, -0.1204021871, 0.0000380513, -0.7106295824, + -1.1571166515, 1.2584540844, -0.9098292589, 0.4606101811, -0.8967497349, -0.7487707734, 1.1330285072, -0.2487686425, + 0.048568964, 0.9908419251, 1.7194275856, 1.1388652325, 0.4050374627, 0.7197656035, -0.0095453719, -1.7850903273, + 0.280736208, 0.3113456666, -0.4148780704, -0.5144474506, 2.3370497227, -0.9018598795, -0.0432650372, 0.6294213533, + -1.2214990854, -0.3480480611, 0.4941302836, -0.8427708745, -1.0920269489, 1.1331650019, 0.5445849895, -1.9988650084, + -0.5136639476, 1.5669808388, -1.4852890968, 1.1697503328, 0.1714032292, -0.1498004496, -1.7167567015, 0.2077475339, + -0.2835475206, 0.6810171008, 0.1799054295, -0.3234174848, 1.2285729647, -0.2494829297, 0.4951613247, 1.2835344076, + -0.2153073847, -1.5655417442, 1.0642517805, -0.4465774298, 0.625802815, -0.4518454075, -0.6958141923, -0.4009466767, + -0.7438731194, -1.0151065588, 0.2284471691, -0.520006597, 1.7738699913, -0.9808174372, 1.6659055948, -1.2655656338, + 0.1619434059, 0.5714436173, 0.8214023709, -0.7151944041, -0.7368196845, -0.5527368784, -0.4281289577, -1.3470569849, + 0.2309796363, -1.1804646254, -0.1970812082, -0.6844750047, 0.1222466752, -0.5097717047, 1.03883183, -0.003298261, + -0.9455435276, 0.0521331877, 0.9406508803, 1.4224059582, 0.7051896453, -0.0485493839, 0.0030716613, -0.0828417838, + 0.3621097505, 1.1506960392, -1.2411286831, 0.6016132236, -1.8681024313, -0.2948068678, -0.5459722877, -1.3271028996, + 0.0146063436, 0.0820118934, 1.1872184277, 0.022624217, 0.5577337146, -0.6835659146, -0.3828615844, -0.0172030423, + -0.305927068, -1.1533372402, 0.2937498689, -1.1304335594, -1.5362212658, 1.1067888737, -1.7159109116, 0.1627099216, + 3.4915504456, 0.8252794743, -0.6337646246, -0.6024153829, 0.2472287565, 0.0888550505, 0.3549385667, 0.6885216832, + 0.0299285725, -0.0664129481, -0.6327346563, -0.1739193201, -0.8258158565, 0.1949875653, -0.2163696438, 1.0570889711, + -0.7573488951, -1.5297939777, 0.3537744582, 0.3407221437, 1.3309781551, 0.750100553, -1.1971751451, 0.3842400312, + 0.1106487289, 0.9332572222, 1.2433928251, 1.0489282608, -0.7144296765, 0.3993691802, -1.192486763, -1.6388714314, + 0.6282942295, -0.3221462667, 2.2317204475, -1.0032519102, 2.5989425182, 0.7262270451, 1.8382234573, 1.0665451288, + 0.6297884583, -1.7966475487, 0.2026394159, -0.6314821839, -2.0691819191, -0.3227912486, -0.6972043514, -0.0853688121, + -0.7535147667, 0.3925627172, -1.5193345547, -0.2938063443, 0.3562227488, -0.9631296992, -0.3119919896, -3.0219933987, + -1.2542766333, 0.3058491051, -0.0131095555, -0.0122315139, -0.0387849845, -1.0967736244, 0.5564718246, -0.6666582227, + 0.3884274662, 1.9603561163, -0.5804669857, 0.8530720472, -0.3293070197, -0.7811429501, 0.5486994982, -0.2156431228, + 0.4974171817, 1.8149178028, -0.083125338, -0.2076419592, 0.4824213386, 0.2035827041, 0.2575459778, -1.2080625296, + -0.9822015166, -0.8012655377, 1.1425778866, 0.7922763228, 1.2311615944, -1.5688765049, 0.704767406, 0.2851555347, + 2.2098674774, 1.0570685863, -0.0321040228, -0.128372103, 0.3590631783, -1.3702954054, -1.4281027317, -0.2610388696, + 0.653054595, 0.4184088409, 0.2936683297, -0.1556836814, 0.9377830029, -0.1359964013, -0.817079246, -1.2400767803, + -0.473241657, -1.1670972109, -0.84130162, -1.4027423859, 1.0371077061, -0.8688614964, -0.5326256752, 0.5555218458, + -1.4648450613, -1.0836731195, 1.8800867796, -0.8621342778, 0.5107352138, 1.9502209425, 0.6216194034, 0.4190502167, + 2.2297959328, -0.8208199739, -1.7991086245, -0.6422991753, -0.7526358366, -0.0102676786, -0.6219030619, 0.9146863818, + 0.6332815886, -1.3110525608, 0.8213313818, -0.1096853018, -2.4599967003, 0.6964056492, -1.6533551216, 1.4545164108, + -0.0317682959, -0.2366403639, 0.8078718185, 0.1043894738, 1.0441939831, 0.5735760927, -0.3592137694, 1.643856883, + -2.3127036095, -0.6342550516, -1.009115696, -0.323871702, 0.1599443555, 0.0075996816, 1.2957876921, 0.1138323396, + 0.8152285218, -0.6953651309, -0.739720583, 0.2354884744, -0.0152770123, 1.1379036903, -0.4955999851, 0.6735898852, + 0.1157289371, 1.3253082037, -0.0473974869, 0.0749195814, 1.1126670837, -1.3454822302, 0.5657912493, -0.317373246, + -0.6623814106, 0.9390728474, -0.3503127098, 0.5224634409, 1.7018532753, 1.1917303801, 2.5286018848, -0.9827714562, + -1.7515311241, 0.3258644044, 1.1894116402, 0.2793818414, -2.5151178837, 0.2461755723, -0.0248270202, 0.8610759377, + -1.4125248194, 0.9993839264, -1.4585593939, -1.2222012281, -2.5958955288, 1.763641715, -2.3849341869, 0.8637584448, + -0.1760935038, -0.3307088912, 1.314555645, 0.5149357915, 0.5830872655, 2.394797802, 1.3304606676, 2.7539777756, + -1.133907795, -1.7897496223, 0.080531396, 0.2522512376, 0.2491337359, 0.6630885005, 0.2543898225, -0.1769705266, + 0.5460646749, -0.1675920635, 0.6434882879, 1.2286797762, -2.2995398045, -0.2927011251, 0.6443910599, -1.0067539215, + 1.6835182905, 0.9931317568, 0.4729190767, -1.1432638168, -0.7436600327, -0.2560135126, 0.9444711208, 0.7911326289, + 1.6346222162, -0.1302263737, -1.0289372206, 0.0085418718, -1.333129406, 1.1780107021, -0.9500072598, 0.6754372716, + 1.0067199469, -0.8243820071, -1.0483652353, -1.9091670513, 0.0497869141, 0.2428957224, 0.0930123553, 0.1747187376, + -0.2940579355, -1.8441371918, -0.6564555764, -1.37479496, -0.2950574458, -0.5911638141, -0.9996911287, -1.0452963114, + -0.8234270215, -1.3071545362, 0.451952666, 1.1589044333, -0.5272555947, 0.4144105017, 0.9806813598, 1.7847551107, + -1.014529705, 0.5712207556, -0.5980527401, 0.5029620528, -0.0612854436, 0.7624505162, -1.3226306438, -0.4346112013, + 0.6056466103, -0.0498499461, -0.3783754706, -1.5018903017, 0.0628009811, 0.6265262365, 0.8333978653, 0.314048022, + 0.0424722657, -1.9600057602, 1.5053578615, -1.9780138731, -0.5857676268, 0.6841420531, 0.6114683747, -1.3019052744, + 0.2540067136, 0.9127832651, 0.4417865276, 1.2836414576, 0.1039965823, 1.2140318155, -0.5549297333, -0.4985508621, + 0.6292501092, 0.3685869873, 1.1157144308, 1.5523375273, -2.3205018044, 0.5883346796, -1.674358964, -1.380802989, + -1.1486417055, -0.4540960789, -0.2932817936, -1.0938034058, 1.2470657825, 0.1483083218, -1.3925426006, -0.8331165314, + -0.2666631341, 1.5057089329, -0.8068805933, -1.0885897875, 2.3916010857, -0.4042384028, -0.4770764112, -0.15645428, + -0.6575467587, 0.2871340513, -0.0035539989, -0.1058869883, 0.1488221437, 0.360537976, -2.4916563034, -1.5001876354, + 0.4150368869, 0.8202406168, -1.4984824657, 1.2506990433, -0.9239646792, -0.9689198732, -0.6747028232, -0.9625166059, + 0.0919773877, 1.788821578, -0.3183748126, -1.561627388, 0.7808475494, -0.072523497, 0.7236689329, -0.8480882049, + 0.4332070053, -0.7184300423, -0.5073258877, -0.7155088782, 0.1922626346, -1.8225835562, -1.5416775942, -0.4609018862, + -0.4596909881, 0.2107827514, -2.0516586304, 1.519523263, 0.8270009756, -0.3949391544, 1.247461319, 1.3624265194, + -2.0977537632, 0.336730808, 1.3497856855, -0.1149254441, -0.110692881, -0.6452971697, 0.4695451558, 0.0963989571, + -0.2132138759, 1.3956539631, -0.4724814594, -0.85940516, 1.8760187626, -0.1349168271, -0.3604379296, 0.4938758314, + 0.2165178359, -1.3356113434, 1.1783431768, 0.1670271158, -0.0458714627, 0.2959707677, -0.8548012972, -0.2733450532, + 0.4309072495, 0.5981340408, -0.6337695718, 0.1154701039, -0.1036763787, 0.8955789804, 0.3470619619, 0.3223627806, + 0.6703640819, 0.3695249259, -1.2931357622, 2.0881593227, -0.31637007, -0.0996335223, -0.041353453, -1.41750741, + -0.5930390954, 0.4457131326, -0.149612844, -0.1687347889, 0.3874080181, -0.8589089513, -0.5768976808, 1.7151972055, + -0.6996167898, -0.2785257995, -1.026072979, 1.3125190735, 0.2768625617, 0.7143705487, -0.2726789117, -0.05714963, + -0.062878482, -0.7734673023, -1.7554893494, 1.3222324848, 0.8918345571, 1.3041300774, -1.3633157015, 0.0353974849, + 0.3286035955, 0.6159794331, 1.3449649811, -0.0227691717, 1.6639068127, -1.9228399992, 0.5120229125, -1.0251792669, + 0.6372367144, 1.5930398703, -0.6409438252, 1.4217171669, 0.0658135042, 1.8625446558, 0.6787316203, -0.4409461915, + 0.1394979209, -0.703058362, 0.7338191271, -0.7291454673, -0.3782072663, -2.8154554367, -0.8627194762, -0.8333143592, + 1.2222462893, 0.8411992788, 0.3509971201, 0.2359188348, 0.9166232944, 0.0066510001, 1.5729032755, 0.4003543556, + -0.4913519323, 0.8445338607, 0.0200802702, 1.0654255152, 1.3981710672, -1.605594635, 0.0228539519, 0.8410942554, + -1.5818178654, -0.3087835014, -0.7839787602, 0.8243343234, -0.9782735705, -0.129107669, -1.1661448479, 1.257915616, + 0.3912162185, -0.1826521456, -1.5388045311, 0.0681304187, 0.7006773353, 0.0295840409, 0.1992514282, 0.2526450753, + -1.8144961596, -1.1816760302, -0.9918892384, 0.6096387506, 0.2016691118, -0.6762703657, -1.3589177132, 0.7350046039, + -0.1993409395, -2.6887750626, -1.2836247683, 1.9510684013, 0.1622150093, -1.4023469687, 1.4098094702, 0.0630933121, + 1.0961402655, -0.8833422065, 1.870262146, -0.1089891195, -0.3058429062, -0.7081920505, -0.3911435902, -0.7089096308, + 1.9077292681, -0.5598803759, 0.999101758, 0.7150085568, -0.3869202733, -0.9710565805, -0.0675847158, 1.1329613924, + 0.6529337764, 1.2304496765, 1.1190041304, -0.9004789591, -0.0169585124, 1.5388683081, -1.9974298477, -0.0319209136, + 0.223965764, 0.9455083609, 0.4229235351, -1.1756800413, -0.2048513144, 0.9564954638, 1.5861339569, 0.7912840247, + -0.5508337021, -0.6716780066, -0.696827352, -1.3961554766, -0.5600498915, 0.3246770799, 1.4076087475, -0.0798354521, + 0.2515286505, 0.4909705818, 0.3263372183, 1.4774889946, 1.0507353544, -0.5025584698, -2.5827465057, -1.3963918686, + 0.3938339055, 0.1324110627, 0.6092009544, -0.6405442357, 1.071023345, 0.9779106975, 0.9465399981, -0.9084601998, + -1.0478686094, -0.1336563677, -0.9601236582, -0.2246695161, -1.3933295012, 1.6808741093, -0.8732835054, -0.4315283, + -1.2740129232, 0.432411015, 1.1807173491, 2.502799511, -1.1592706442, 2.4850172997, 1.2996827364, -0.1811547577, + -0.4567832351, 0.0583423376, 0.4886063039, 1.9107813835, -0.4104271531, 0.7122089863, 0.1199572161, 0.7052668929, + 0.1382817328, 1.1929559708, -0.1740968972, 0.9283349514, -0.7982419729, -0.6423220634, 1.1604852676, -1.0541092157, + 0.7567608356, -0.1418243349, -1.370280385, 2.9446048737, -1.4440181255, -0.0868617892, -0.4741066694, -0.8283151984, + 0.9016938806, -0.1963388175, -0.6778028607, 1.1174887419, 0.2317363173, -1.0282225609, -0.200512737, -2.2192344666, + 0.2017867267, 0.0493783355, 1.337551713, 0.4729900658, -0.7144607306, -0.9983495474, 0.6037179828, -1.8254740238, + 0.240002647, 0.2330179662, 2.5256221294, -1.417547226, -0.3735436201, 1.6245576143, 0.2052359134, 0.6497414112, + 0.4077384174, -0.2230141908, -0.7564809322, -0.0916129127, 1.0873105526, -0.2665374875, -0.5684608221, -0.7968423367, + -1.6703445911, -0.8607365489, 0.318392545, -0.9658346176, 0.0435120389, -0.515096128, -1.1097168922, 0.1698560864, + 2.9419577122, -2.3477473259, -1.3247072697, -0.4962736666, -0.1773999929, -0.0164038111, 2.5538542271, 1.7659779787, + -0.0989361107, 0.3340937793, 2.1344652176, -0.4907274842, 0.1163907647, -0.2446371317, -1.2983027697, -1.7936493158, + -0.6849700809, 0.814424634, 0.3181484938, 1.9092911482, 0.8085999489, 0.7802957892, -0.0886350796, -0.2588721514, + 0.0695181787, 0.3667381108, -0.376224637, 0.207495302, -0.3414714932, 0.1384399831, -0.7856284976, 0.5178771019, + 1.3630260229, -0.6483896375, 0.8072376847, -0.330907464, 0.2732403576, 0.5953650475, 0.4950374961, 0.4725801349, + -0.813368082, 0.4031637311, -0.8463309407, -1.2494440079, -0.7790490985, -0.300124675, 0.7606703043, -2.6036124229, + 0.2312413156, 0.0621792115, 1.317422986, -0.5900319219, 1.1107158661, 1.0482529402, -0.2892859876, 0.2211965621, + -0.8559523225, 0.0115584433, -0.9336676002, 1.9462053776, -2.1260342598, 0.2948924899, 1.2464601994, -1.7223078012, + 0.8161273599, -1.0551950932, -1.0623240471, 0.6164644957, 0.6140427589, 0.7598878741, 1.3047753572, 1.5473181009, + -1.1017062664, 0.3287614584, 0.5281797051, 2.5536885262, 0.2077630758, -2.2922198772, -1.4933623075, -0.2370071262, + -0.7327952385, 2.1606707573, -1.1783447266, -1.3211505413, -0.7479308844, -0.5706911087, -2.535140276, 1.187964797, + -0.693716526, 0.0836460069, -0.5761220455, 0.9647812843, 0.3790502846, -0.5369278193, -0.9889282584, -0.0713329986, + -1.9731627703, 0.0177028272, -0.0183720831, 0.3783574998, 0.0163121391, -1.3108023405, 1.7357823849, 0.8464573026, + -0.3903010786, -0.3368534148, 0.4967666566, -2.7908391953, -0.3965183496, -0.362408489, 0.4881130457, -0.1702686101, + -1.1690906286, -1.826186657, -0.4230371714, 0.4788505435, 0.4658548534, 0.2310337573, 0.098535575, 0.4738362134, + -0.734444797, 1.2384089231, -2.6306266785, -1.5320723057, -1.2753394842, 1.5467416048, 1.6379555464, 1.0030064583, + 0.9898139834, 0.0424625278, -0.4771284163, 1.1298083067, 0.6710648537, -0.3274264336, 0.7314128876, -0.8347561955, + -0.2209829986, 0.8305916786, -0.1107638553, -1.0064861774, -0.7868315578, 0.2856790125, -1.1872032881, -2.685447216, + 1.1837202311, -0.5017939806, -0.7630453706, -0.759931922, -1.7406020164, -0.3569377363, -0.3295323551, 0.1544053108, + -1.6152344942, -0.781668067, 0.9302698374, -0.4331679344, -1.4746901989, -1.2758826017, -0.8955430388, 1.1119370461, + -0.4404303133, -0.2563897967, -1.3007929325, -1.0545949936, 1.7923588753, 0.5344469547, -0.1055984795, 1.254036665, + -0.12751095, 0.1339087486, -0.2487187982, -0.4006001949, -0.2114236802, 1.1732668877, 0.5091586113, -0.1582694799, + 0.691676259, -0.1102267802, 0.2098225951, -0.2684221864, -0.2210887969, 1.4088248014, -0.4681519568, -1.2454816103, + -0.7584915161, -0.5442646742, 1.2987605333, -0.0903712809, -0.7038058043, -1.8618180752, 1.3913886547, -2.0506701469, + 1.0668116808, 1.0024168491, -0.9046353698, -0.3053961098, -0.2314878851, -0.1263826787, -0.8304456472, -0.8061316013, + -0.2422748208, -1.9520103931, -0.723651886, 0.4473903477, 0.1257790476, 0.6045052409, -1.0181647539, -0.2301247269, + 1.051879406, 0.2211459726, -2.1039614677, 0.4767338634, -0.5758100748, -0.7040908337, -1.3656538725, -0.9187939167, + 0.1141875982, -0.0630888268, 0.9285331964, -2.311634779, -2.1702721119, 0.6343227625, -1.6013319492, -0.2154222429, + 1.527594924, -0.6772807837, 1.9274326563, 0.7861020565, -0.2652913034, -0.8883908987, 0.2253436595, -0.5352017879, + -0.5620777011, 0.5740081668, 0.3111010194, 1.5274264812, -0.3963585198, -0.2029903829, 1.3392060995, 0.4060575068, + -1.0550361872, -1.0509568453, -1.0039232969, -1.6214109659, -1.1161359549, -0.5431999564, -1.6879911423, 2.1472158432, + -0.5342582464, -1.1732395887, 0.2828506827, 0.6968113184, -0.3553364873, -1.320964694, 1.4841766357, 1.4951782227, + -0.0843770579, -1.151063323, 0.2676264048, -1.9190896749, 1.3373588324, 1.0322799683, 0.4293705821, -1.0973135233, + 1.1228461266, -0.1259989738, -0.3956427276, 0.5731127858, -0.7413690686, 0.0254712421, -0.1747244149, -0.609097898, + -2.3484940529, -0.8988916278, 1.0013848543, -0.61787498, 3.2145085335, 1.7016453743, -0.1834490895, 0.3850836754, + 2.8780665398, -0.3341577053, -0.3734532297, -0.1130664498, 0.181355834, -0.5761479735, -0.5341535807, 1.4379769564, + 0.0405320339, -0.6183389425, 0.4018271565, 0.35254547, -0.6058232188, -0.5648207068, 0.0922305062, 0.1551928073, + 1.5452309847, -0.9681372643, -0.5784638524, 0.355255574, 0.4516860843, -1.909873724, 0.2499908358, -0.8666939139, + 0.8051800728, -0.8144145608, -0.2480166554, 0.1575364619, 0.2941561341, -0.1956454664, -0.3580013514, -0.9503346086, + -0.6282243133, -1.3779340982, 1.5391281843, 0.0974658281, -1.564941287, 0.6169933677, -1.5744905472, -0.8908445835, + -0.0382696539, -1.0136801004, -0.268507719, 0.4745731056, -1.853156209, 1.5317523479, 0.6800500154, -0.6525881886, + 2.0080859661, -1.0958909988, 1.0522122383, -0.3234107196, 1.9245126247, 0.3289987743, -0.1973149925, -0.1600109935, + -0.1019958928, -0.1369468868, -0.3338777125, -0.4217321277, -0.6276172996, -0.0088310521, 0.2495359033, 0.6251870394, + 0.2042882591, -0.0481986813, -0.4357247949, 0.1891266406, 0.1527542472, -0.38669011, 1.0209299326, 0.6823812127, + -0.6945874095, -0.7691562772, -0.5777331591, 0.0130191892, -0.8398479819, -0.2155789435, 0.4451689422, -0.2670453787, + 0.1741062254, -0.5216994882, -0.8992028236, 0.3179417849, -1.7559511662, 2.4414460659, -1.0115315914, -0.7715908289, + -0.3075437844, -0.6755710244, -0.6566454768, 0.3051428497, -0.1559470147, -0.4731896818, -1.5133440495, -0.9692866802, + 0.1147779524, 0.1330191642, -1.4187124968, -0.2106103599, -2.4852890968, 0.3849193454, -0.445950985, 1.0283155441, + 0.4236266315, 1.1467685699, -0.4037198126, -0.0717719048, -0.8492287993, 0.8758452535, 0.1124814972, -0.1776066273, + 1.2060687542, -1.8546257019, 1.0201659203, -0.8215023279, 0.0630850345, -1.8618688583, 0.1551971585, -0.7597349882, + -1.1710904837, 1.4031120539, -1.3759285212, -0.4247080982, 0.4434662163, 0.4800909758, -1.3437353373, -0.3794100285, + 1.7216287851, -0.4607748687, 1.8423278332, 0.3057335317, 0.5179230571, -2.2636806965, -0.4333676398, 1.2896549702, + -0.4285718203, -0.8006920815, -0.4375852048, 0.5202440023, -0.9587842822, -0.5118048191, -0.9421377182, -1.1184242964, + 1.6118689775, -1.2746709585, 0.7071536779, 0.1218064204, 1.1981039047, 0.6363534331, -0.0728155077, 0.9757786393, + -0.417360127, -0.0015435452, -0.7620249391, -0.5343719125, 0.440512985, -1.324041605, 1.4426378012, 0.4065026343, + 1.5632677078, 0.0156175345, -0.452475071, 1.0752927065, 1.2035952806, -0.8711138964, 0.2041112036, 0.2468991578, + -0.1774842441, -1.1503459215, -1.238202095, 2.4137120247, 1.1750917435, 1.596783638, -1.6567083597, -2.3314807415, + 1.3394186497, -1.0232579708, 0.9828591347, 0.6385476589, 0.6664152741, -0.1034429669, 1.0297343731, 0.2680951357, + -0.5350618362, -0.4283976257, -1.2094867229, -0.1973341703, 0.5106055737, 1.0990395546, -0.3337288201, -0.4588372409, + -0.8280749917, -0.263494581, -0.7192752361, -0.0046136426, -0.2803740203, 1.8313490152, -0.2697892189, 1.5935767889, + -0.603856802, -0.186221242, -0.2486424148, -0.16839993, -1.2148817778, -0.4478370547, 0.3814966083, 0.3098362982, + 0.3672737181, -0.510830164, -1.126082778, 0.4522577822, -2.3199803829, 1.2764129639, 0.0071071084, 0.8953126073, + -0.1732992828, -0.8343470693, 1.2000719309, 0.60279423, 0.0065583684, -0.5235270262, 1.4073104858, 1.5511393547, + -0.6028784513, -0.6788135171, -0.4255207181, -1.2978883982, -0.2149679661, 0.1982887536, -1.813231349, -0.7148556709, + 0.9376966953, 0.0934126228, -2.2183358669, 0.2135851234, 0.9191421866, 1.0439063311, 0.9127506614, -0.5701822042, + -0.5769571066, -0.3889191747, 0.8824122548, -1.0307428837, -0.6692697406, 0.4454301298, -0.381829679, -1.5339218378, + 0.3329823315, 1.0650533438, -0.7414758205, -0.1798739582, -0.3133811057, 0.0330814943, 0.8718146086, 0.3320226669, + -0.5496357679, -0.6352506876, 0.4852578044, -1.3856655359, -1.0167318583, 0.3205580413, 0.4294673502, -0.7857626677, + -0.1906618029, 1.4213653803, -1.3946044445, 0.0078004524, -1.0760178566, 1.2182247639, -1.1788051128, -0.3671139181, + -0.122348845, -0.6729784608, -0.3291174173, -0.0389075093, 0.5921736956, -1.6977338791, -0.2491133809, -0.4006183147, + -0.3961207867, 1.5913404226, -0.5850166082, 0.9393358827, 0.497438252, -0.4705432653, 0.4906757176, 0.0837168992, + 0.392570883, -0.5851889253, 1.0661809444, -0.4824724197, -0.2261067629, 1.2158709764, -0.1601240784, -0.098304376, + 0.5352964401, 1.6688851118, -0.5516088605, 0.1419655532, 0.3875458241, -0.3246272802, -0.5487880707, 1.0352808237, + -0.3842982948, 1.4187676907, -1.3117232323, 0.2935632169, 0.6130684614, 0.454906404, -0.8751249909, -1.3332929611, + -0.8147768974, 1.0529824495, 1.2756927013, -0.5867362618, 2.0169563293, -0.2070715725, 0.8094360828, -0.0061388025, + -0.2174635977, 0.9481768608, 1.2745907307, 1.1427247524, 0.0107475081, 0.3241678476, 0.3622403741, 2.076551199, + -0.8151247501, -0.0743439496, -0.9019891024, -0.0548304245, -0.4506755173, 0.7100703716, -1.0151324272, 1.8718290329, + 0.6454366446, -1.4716508389, -0.761464715, -0.6045665145, -1.5807316303, 1.3683742285, -0.708784759, -0.5360591412, + -1.1137635708, 0.0546837524, -0.2155482918, 0.0912592858, 0.5711795092, -0.5264383554, -0.2848584652, -0.9425686598, + -2.4303109646, -0.1181594357, -1.4667463303, 0.9932658076, 0.1965706199, 0.368606627, -0.3189594448, -1.3668688536, + 1.0229911804, 0.3237343132, -1.1159375906, 1.0948339701, -0.7159814239, 0.9033344984, 0.6435657144, -0.1155977696, + 1.0557695627, 0.6256161332, -1.828281045, 0.8863859773, 2.2530357838, 0.9894797206, 0.0942059904, 0.0559607707, + -0.6437538266, -0.5194265246, -0.1113528311, -0.5954051018, 0.0305511039, 2.0396575928, -0.9323299527, 1.1999788284, + -0.1505632401, -0.0716161281, -0.1202129871, 1.6836475134, -0.381901592, 1.0422122478, 1.2395704985, -1.1008722782, + 0.3359590769, 0.3583621979, 0.3088277578, -0.7779789567, 0.2468801737, -0.0547442622, -1.1857970953, -0.7717460394, + -0.6387051344, 0.5602406263, 1.7625153065, -0.0663885921, -1.3087264299, -0.6310637593, -0.0381813124, -0.6173859835, + 0.3789446056, -0.2139604241, -1.170761466, 1.3018363714, 0.7095224261, -0.003579542, 0.1458305418, 0.0410517007, + 0.2223228961, -1.1324160099, 1.3681198359, 1.0462281704, -1.5376925468, -1.6998412609, 1.1517218351, -0.282892406, + -0.1268702596, 0.0175452475, 0.6152723432, 2.9246551991, 0.0550507084, -0.4084461927, -0.4082174003, -0.0883197784, + -0.6834801435, 0.1403120756, -0.0701343417, -0.548897326, -0.7441422343, 0.0780278295, -0.5865127444, -1.9822689295, + -0.5372510552, -0.1041933, -1.2280911207, 0.8918114901, 0.805057168, 0.7902606726, 0.1689276099, 0.8103792071, + -0.3139070272, -1.0741906166, 0.8703773618, 1.0449312925, -1.3065792322, -0.3290812373, 0.0967386067, 1.6248611212, + 1.0085247755, 0.7625691891, -0.6881162524, -0.0375259668, -0.1837271601, -0.5998256207, -0.6495984197, 1.860408783, + -0.3011618555, 0.7878006101, 0.332967639, 0.0409335904, -0.9390720725, 1.2049945593, -0.1606714725, 0.6641917229, + 1.1545108557, -0.469101727, 0.9510985017, 0.3453378379, 0.6326152682, 0.8411407471, 3.379540205, -0.5579387546, + -2.2784161568, 1.2684965134, -0.1679872721, 0.5747269988, -1.2267564535, 2.6995685101, 1.2447136641, 2.0237715244, + -1.2390452623, -1.2545794249, 1.7316627502, -2.1253314018, 0.3927900195, 0.708550632, -0.8432416916, -0.0852408782, + 1.6294378042, -0.6161226034, 0.9238883257, 2.052462101, 0.8227902055, 0.49471578, 0.8637558222, -0.273091346, + 0.8136610985, -0.3739970922, 0.4879109561, 1.6569792032, 0.3815992177, -1.2899910212, 1.9640835524, -0.0580297746, + -0.1557988226, -0.6913321614, -1.4017077684, 0.3727024496, -0.6369473934, -0.6303749084, -2.6259300709, -0.0493691675, + -0.9832947254, 1.0024470091, -0.3762393594, 1.3069745302, -1.2268050909, -0.7823822498, -0.0879970342, -0.1371357441, + -2.0683543682, 1.3137185574, -0.542049408, -1.869058609, -0.422952503, 1.2428137064, -2.0199379921, 1.1582741737, + 0.3339900672, -0.1540900767, -0.3291948736, 0.5431203246, 0.554884553, 0.8049129844, -0.9914619923, -0.2426926792, + 0.439661175, 1.1291645765, 1.5539902449, 0.0206491835, 3.109318018, -0.6115761995, 0.6421800256, 0.354914844, + -0.5587056279, 1.3602957726, 0.8574593067, 2.1869783401, -2.0839545727, -0.1410952508, -0.2207788825, 0.3456647098, + 1.7722004652, 0.2104642242, -0.0937629715, -0.6939895749, -1.4438390732, -1.4316949844, 1.3473109007, 1.1719737053, + 0.1000234857, -2.5027976036, 0.5600686669, -1.7411983013, 0.6763187647, 1.1642938852, 0.1111669838, 1.0283162594, + -0.9822398424, -1.5453110933, -0.8225803375, -0.6440979242, -0.0711455941, 1.9552521706, -0.3010765314, -2.1804435253, + -0.415966928, -0.2086515576, 0.0323335044, 0.7367733121, -0.1938336194, 0.0218441971, -0.6198917031, -1.2360179424, + 0.0325217918, -0.1815406382, -0.8679505587, -1.239860177, 2.716145277, 0.8557375073, 0.0299651753, -0.4124097824, + 1.7006686926, -1.1124067307, 0.0908856541, -0.1516654342, -0.2011841089, -0.878025353, 0.1487515718, -0.1081603616, + -2.6986460686, -0.6502318382, -1.3820240498, 1.3549199104, 0.2082520574, 1.0158964396, -0.3602983356, 1.0314747095, + 0.7706522346, -1.4677193165, 0.4941012859, 0.4933527708, -0.736969471, 0.593883276, -0.9388635159, 0.3698066771, + 0.1977473944, 2.0577509403, 1.8244630098, -0.662194252, 0.9831089973, 1.8373091221, -1.702688694, -0.0270229913, + -0.7254310846, -0.5342456102, -0.249546662, 0.9207409024, 1.1019066572, 1.4010708332, -0.4718470275, 0.7765082717, + -0.2912778556, 0.3498292863, -2.712975502, 0.3319345415, -0.4187539518, 1.3095924854, 1.1868669987, 0.8806769252, + 0.3419238627, 0.3971645832, -0.5310337543, 1.2703276873, 1.2536746264, -0.238458693, 0.7138925791, -0.6958540082, + 1.073053956, 1.0104210377, -0.2720271051, 2.4342498779, -0.1827040464, -1.1780284643, 1.5289424658, 0.2870815396, + 1.0993279219, 1.0624066591, 0.9699524045, -1.5428931713, -0.3731743395, -0.9524514675, 1.6522585154, -0.6506668925, + 1.8939784765, 0.7598444223, -1.4891389608, 0.2364653498, -0.4037335515, -0.3316952884, 0.4112060368, -0.4684414566, + -1.5352321863, 0.7067044377, -0.2318485826, -1.124042511, 1.5368109941, -0.1835157275, -0.4744376838, 0.3413875699, + -0.6717487574, 0.7119252682, -0.2505222857, -1.0557770729, -1.3723297119, -0.3597370386, -0.4294839501, 0.7981411219, + 0.1716908067, 0.7857249975, -0.2756601572, 1.3481935263, 0.1696635783, 0.4440221786, -0.8391209245, 0.4513442814, + -1.5586638451, -0.3483391404, -0.8522367477, 1.5907986164, -0.3074297011, 0.2480690479, 0.7581233382, -0.5760253668, + -1.8630077839, 1.0422192812, -1.7398986816, 1.222251296, 0.5329426527, -0.5442413092, -0.4942600429, -0.855114162, + 0.0436583534, -0.5721877813, 0.6107054353, 0.3239576817, -0.7967873216, -0.6653596759, -0.929915607, 0.5174583197, + 2.7006502151, 0.0948338807, 0.5206369758, -0.34059605, -1.6355158091, -1.1801077127, -1.0089060068, 0.8826825023, + 0.8409978151, 0.5379786491, -0.8869519234, -0.6959516406, 0.897069335, 1.1439201832, 0.2837764323, 0.6520831585, + 1.5538183451, 0.9409436584, 1.6984336376, -0.248923406, -0.4934352338, 1.1103788614, -0.0425555967, -0.2637329102, + 2.3317098618, 0.1342730075, -1.1002831459, -0.3531531394, -0.9949698448, -1.243776679, -0.3254702687, -0.2078438252, + 0.6164678335, 1.4852756262, -0.6047641039, -1.6532808542, 0.4184491634, -1.6963517666, -0.2338368893, -0.7228124738, + -0.1625349373, -0.4308318496, 0.0099216374, 0.4700077772, -1.2281514406, -2.7309982777, 0.3110759258, 0.4845410585, + -0.2558689415, -0.7635210752, -0.3534634411, 0.9853637815, 2.0035877228, 0.1427997351, 0.3458914757, 1.1226363182, + -0.4557880163, -0.7759872675, 1.3420548439, 0.0752204135, -1.5103042126, -0.0915874243, -1.2788894176, -0.2196186185, + 0.2062564492, 0.233169049, 0.21551691, -0.5119232535, 0.2016098946, -0.2278685421, -0.693728447, -1.173279047, + -0.2774077356, -1.6016391516, 1.0906006098, -1.1602990627, 1.1262484789, -1.0025730133, 0.0271053445, -0.257902056, + 0.4614878893, -0.1589870751, 0.1840162426, -0.6898531318, 0.0125418641, -0.4625565112, -0.8035131097, -0.2153994441, + -1.3669756651, -0.3434249461, 0.2921564877, -1.1370795965, 1.9588086605, 0.8582231998, 1.3342782259, -0.1519452184, + -0.1291483045, -0.6357197165, -1.139644146, 0.8062340021, -1.2459180355, -0.9046903849, -1.2425501347, -2.1115393639, + -0.4970543683, -0.8733558655, 1.1578514576, 1.0069839954, 0.4968858361, 0.366614908, 0.6556609273, -0.3875073791, + -0.5488761067, -0.0836496875, 2.0249290466, -1.0677149296, 0.3628509939, 0.3246399462, -1.1875450611, 0.2687779069, + -1.085265398, 0.7550567389, -0.4066241086, 1.2095012665, -0.1736595035, -0.3596734703, -0.6551199555, 0.3217178881, + 0.3877495825, -0.5331507921, -0.5281913877, 1.2084648609, -1.3032892942, 0.7628052235, -0.1079162583, 0.4455998242, + 1.1350136995, -0.1589067131, -0.6414845586, -0.6046472192, 0.9702689648, 0.7563495636, 1.1022398472, 0.9599217772, + 0.3824656308, -0.2513045669, 1.9816982746, -0.1709746271, 2.5292274952, -0.0726553649, 0.8528701663, -0.2167818695, + -1.1923350096, 0.7861623168, -0.1764873415, 0.5312441587, -0.6337814927, 0.5093117952, -0.6839939952, 0.5782969594, + 1.6045950651, 0.813192904, -0.717381537, -0.37809214, 1.3238222599, -0.5112685561, 0.0101344641, -0.2775341272, + -0.5660531521, 1.0679335594, 0.1818200201, 0.021048611, 0.2730336189, 0.9373193383, -0.5658476949, -2.9819197655, + -0.7312950492, -0.6392739415, 0.3130269647, 1.3852910995, -1.7225570679, -0.1778837144, -0.2917789519, 2.5960144997, + -2.071762085, -0.5658675432, -0.1349422485, -0.6983388066, 0.0349466354, 1.1256330013, -1.4770747423, -0.5363630056, + -0.240348056, -1.1767562628, 0.1195749193, -0.2448243648, 0.5246302485, 1.8328498602, -1.3843655586, -0.0110265408, + -0.0536559224, -0.0643325523, 0.1795994788, -0.9816644192, 0.3176301122, -0.1802364588, 0.9853456616, -1.163315773, + 0.0661375895, 0.1401054561, 1.1376334429, -0.4585750997, 1.6170740128, -0.862200141, 0.0746508464, -2.0770630836, + 0.9686267972, 0.239510417, 0.7997642159, -0.7137439251, -0.4591530561, 1.0764036179, 0.7686495185, 1.0426416397, + -1.1665842533, -0.0190958213, 0.2914540172, -0.7461980581, -1.0264773369, 1.1318042278, -0.6412966847, 0.4828600883, + 0.4435411096, -0.2497335821, 0.721185267, -0.9790833592, -0.1474432647, 0.5849481821, 0.3871085644, -1.6994421482, + -0.929405272, -0.4046594501, 0.0394828208, -2.2656846046, 0.8610637188, -0.5293418169, -0.9234024286, -0.7983475924, + 0.3869788647, -0.0125233578, -0.6018054485, -1.5917366743, -0.6404822469, -0.8488659859, 0.3502156138, -1.9618258476, + 0.4609496295, 0.7993075252, -1.2686504126, -2.0727105141, 0.4813488722, 2.2085037231, -0.1328210086, -0.1219409853, + 0.7389209867, -1.2908295393, -0.6629701853, 0.0689686611, -1.8911678791, -0.0095606102, 2.2362875938, -0.2920475602, + -0.4304375947, 0.6180891395, 0.3166204989, -0.267704159, 0.74963516, -1.5953862667, 1.612003684, -1.2561944723, + -0.265833199, -1.653205514, 0.3250307441, 0.2280231416, -1.7944575548, 0.986310482, 0.965508461, -1.2732337713, + 0.8295410872, 1.7446888685, 0.4547727108, 0.9031069279, -0.0009527904, 0.10828913, 0.0627697557, -0.7638112903, + 0.118442826, -0.6439966559, -0.6934063435, -0.6369379759, 0.0757776573, -0.332980603, -0.8138238192, 0.6588058472, + 0.0405100137, -0.7962877154, 0.1916862875, 1.6392009258, 1.5568352938, -0.2725393474, 0.4475654662, -1.8609107733, + 0.2686832845, 0.5630605221, -0.8181628585, 0.7510074973, 0.5397127867, 0.1188118681, -1.5726583004, 1.1463209391, + -0.1599459797, -1.5908477306, 1.1402555704, 0.0534986258, 0.6712822318, -0.2257112414, 0.2104907334, 1.2600893974, + -0.84239012, 0.4301144779, 0.0580476858, -0.1085274071, 0.2783560753, -0.1843588799, 1.1259652376, -0.9875113368, + -1.3340691328, -0.2070790976, 1.1330128908, -0.5045336485, -0.0493099913, -0.9911766052, -1.016169548, 0.6145914793, + 0.2172343433, 0.8915202618, 0.7863522172, -1.5050923824, -0.4608986676, -0.9159309268, -1.0463711023, -0.4841423333, + 1.4623806477, 0.9499843121, 0.1457133293, -0.0732988268, 0.4994755089, 0.0105162933, -0.9202109575, -1.79857409, + -1.8778783083, 0.1385161132, -0.1998910755, -0.6571277976, 1.3705222607, -0.0393945649, -0.6115819812, 0.1122607738, + 1.7633579969, 1.1450352669, 0.0145209311, 0.413438648, 1.0941917896, -0.7587047219, 0.1511386931, 0.8067439795, + 0.3308694363, 0.8130151629, -0.4325229824, -0.3996813297, 0.7124310136, 0.559602797, 1.2407661676, -1.5103613138, + -0.7653915286, 0.4409960806, -1.3893051147, 0.2526411414, -1.5413987637, 2.1944396496, 0.6292828321, -0.8632075787, + 0.2486867309, -0.4590431452, -0.9867677093, 0.3626977801, -1.0730080605, -1.6345175505, 0.2953622937, 0.2162745744, + -0.2574618161, -1.3549469709, -0.6115554571, 0.7602116466, 1.9480760098, 0.9903740883, -0.2730256915, -0.9925105572, + 1.0541404486, 0.2880633175, -1.1912264824, 0.8099787831, -0.1467864662, -1.1243214607, 0.236890614, -1.0483739376, + 1.5535750389, 1.7349170446, 1.7200393677, 0.4215571284, -0.5391463637, 0.7642809749, -1.4886449575, 0.7880499363, + -0.13839674, 0.2078452259, 1.2732071877, -1.3002576828, 0.4559438527, -1.1586076021, -2.5392279625, -0.1181192771, + -0.1082064211, 0.5446758866, -0.036097452, 0.7261715531, 2.2089526653, 0.2038448453, 1.1848708391, 0.0747086108, + -0.3506720662, -1.0089811087, 0.4365611374, 0.2272382379, -1.2056691647, 0.1030338556, 0.8712006807, -1.437759757, + 1.392770052, -1.1165030003, 0.129857555, -1.0141154528, 0.0596608967, -1.4940531254, -0.2160215676, -0.0512839481, + 0.9271569848, -0.4844455123, -0.2318405509, 0.6599657536, -1.7151789665, 0.7706661224, 0.0119470004, 0.9035109282, + -0.1867048591, 0.0665158778, 0.8442751765, -0.0485997386, 0.5673190951, -0.2960724831, -0.1498709619, -0.402474463, + -1.2394433022, 1.5663323402, -1.0304254293, -1.6466841698, -0.8810069561, -1.1049762964, -0.4639779627, -1.5220855474, + 0.233527422, 2.7803463936, 0.0539885126, 0.9135933518, -0.9690374732, -0.1095990017, 0.195894286, 1.7529040575, + 1.5590376854, 1.5509411097, 0.8768229485, -1.7840468884, -0.1732115, -0.6301497221, 0.3956625164, 2.387765646, + -0.0268936399, 0.5478615761, -0.5379067659, 2.1843235493, -0.5380644202, -0.5254244804, 0.5818068981, -0.7079021335, + 1.3369965553, 0.8060417771, -1.6658140421, -0.5134732127, 0.7067216635, 0.8297515512, -0.4131700397, -0.2021587193, + -0.5879874229, -0.7992437482, -1.0584437847, -0.8227606416, 0.3689611852, -1.1542803049, -0.056655053, 1.3873462677, + 0.6274378896, 1.1806343794, -0.0127347568, 0.7829507589, -1.7611320019, -1.8452315331, -0.4864417017, -1.2627916336, + -0.9706924558, 0.1326923072, -0.0447083339, -1.2672939301, 0.5071989894, 0.1937571317, -0.4156983495, -0.7045055032, + 1.5209288597, 1.0463624001, 0.2856897712, -0.2598487735, 0.3661739826, 0.5295231938, -1.4221961498, -0.8767566085, + 0.6296004653, -0.0801178962, 0.6200874448, -0.568918705, 0.1718118489, -0.342238456, -0.9554112554, -0.2749791145, + 1.5549792051, 0.0348670818, -0.6264494061, 0.4486315846, 0.1790567935, -2.0919644833, 1.0272736549, -0.3224200904, + 1.3721137047, 0.0656904429, 0.1180860549, 0.1220767125, -0.1829499155, 0.5675747991, 0.8053595424, 1.9218912125, + -0.7440114021, 0.0348815545, -1.8749556541, -1.4344085455, -1.3828809261, -0.0116490088, -0.9548451304, 0.2953458726, + -1.4136312008, -0.9416632056, -0.5594043136, 0.6049207449, 1.0211660862, 0.2590726018, 0.910618484, -0.2311110795, + -1.251819253, -0.7415366769, 0.4421019256, 1.123483777, 1.3203134537, 0.6332851052, 0.5463161469, 0.2642716169, + -0.5631567836, 0.2989800274, 0.332850337, -0.4342570901, -0.8483982682, -1.7796927691, 0.0795050189, 0.7186124921, + -0.6157069802, 0.1147888228, 0.083878614, -0.2524175644, 2.883759737, 0.8444882035, -1.946241498, 0.7658838034, + -0.4896616936, -1.7648249865, -0.3483499885, 0.8363187313, 1.167593956, 0.7815184593, -0.5237451196, 0.0220253151, + 0.6432757378, 0.2756863832, -1.3450036049, 0.0794675127, -0.4446147978, 0.4111537635, -2.1214573383, -0.791364491, + 0.6275324225, -0.1632787734, 0.3176547289, 1.3256460428, 1.9135844707, -0.3551263511, -0.1786167324, 0.6787138581, + 0.2391502708, 1.0172373056, -1.8531953096, 0.3468162119, -1.4673253298, -0.2697222829, -0.7077001333, -0.669786334, + -1.4380449057, -2.5307970047, 0.8736237884, 1.1434020996, 0.6140899062, -0.1727177799, 0.5524320006, -1.1338095665, + 0.3060199618, -0.3793222308, 1.4749680758, 0.8436607718, 1.7927627563, -0.3670867682, 0.2940903902, 0.6996473074, + 0.1865092516, 0.2714602351, -1.1878365278, 0.0535032712, -0.365434438, -2.1078500748, -0.845035553, 0.7202682495, + 0.6847658157, -1.5380316973, 0.1071202233, -1.4377793074, 0.5285930634, 1.1309717894, -0.2409960181, 1.1711474657, + 0.0241652615, 0.147479564, 1.078743577, -0.2041695267, 1.1821421385, 0.7134022713, -0.1815098971, 0.6097062826, + -0.7310802937, 1.321323514, -0.4690505266, -0.1206440702, -1.9621025324, 0.0792470798, -0.903724432, -0.6727975011, + -0.5813845992, 0.7638904452, -0.7982986569, -1.1170951128, -0.0278148465, 0.7436719537, -0.034929879, -1.5607745647, + -3.6942853928, 0.239262864, 1.6242785454, 0.1078562513, 0.8389151692, -1.0812578201, -1.3334944248, -0.3950431943, + 0.1764431298, -1.5741150379, -0.2641482949, -0.5769725442, 0.057904385, 1.6284952164, 1.3821072578, -0.1604852676, + 0.5396218896, 0.3823760748, -0.5413639545, 0.3832670748, 0.3760714531, 0.6530348063, 0.708278954, 1.6361300945, + -0.8255808353, 0.4770345092, 0.7754092813, 0.5997623801, -1.0650105476, -0.1005972773, -0.656381309, -0.4330505729, + 0.2436604351, -0.1934807748, 0.4373670518, -0.1382869184, -0.0957607403, -0.9223588109, 0.2641588449, 0.448690176, + 0.717965126, -0.2507312, -0.3429058492, 2.7186050415, -0.003143413, -1.7863855362, -0.1491491944, -2.4144194126, + 1.8584879637, 1.0816385746, -0.0691355243, 0.041213721, -0.1214653924, 0.8756392598, 0.6263403296, -0.2714163363, + 2.5999414921, 0.0031115902, -0.6093174219, 0.8194519281, 0.2598125339, -1.5010932684, -0.3467047811, -0.5145673156, + 0.8833550811, 1.5528534651, 1.1378787756, 0.4535325766, -0.2141902596, -1.0113316774, -0.0475542098, -1.9863569736, + -0.0898115486, 0.872148037, 0.6683921218, 1.509411931, -0.5674828291, -0.2722056508, 1.1545054913, 0.9233204722, + 1.7845782042, -1.106572628, 0.8899226189, 1.1991003752, 0.3537445962, 2.0520317554, 0.4479960799, -2.4655239582, + 1.1212525368, -1.6055749655, -0.5201081634, 0.529912889, 2.2476568222, -0.7108030319, -0.0680756792, 1.3571964502, + -1.8943730593, 0.6292427778, -1.071167469, -1.9200879335, -0.0095262108, -0.061230056, 0.3710441887, 0.9317353368, + 0.2323822975, 1.5968242884, 1.2942872047, -0.7865222692, -0.0996802449, -0.2432516068, -1.8798357248, 1.6190136671, + -0.4560818374, 1.0802834034, -0.3977110982, 0.9913378954, -0.4810326695, 1.1207609177, 0.3215666711, 0.6868842244, + 0.7012643814, 0.3027723134, -0.5669187307, -0.8218886256, 2.14483881, 1.5178095102, 0.3204951584, 1.2383538485, + -0.6073427796, 0.1993925571, -1.6000400782, -0.7605104446, -0.1507879049, -0.1515130103, 0.1344979405, -1.3684259653, + 0.0471347682, 0.077459313, 0.2506715953, 0.747543931, -0.5684504509, -1.4915621281, 0.4500528872, 0.3627835214, + 0.2907096446, 1.4360669851, 0.2089084089, 0.7776738405, 0.0575551018, 0.1220124662, -0.583812356, -0.0324958488, + 0.2039363533, 0.3325089812, 1.327127099, 1.4291518927, 1.6142344475, -0.2566379309, 0.0891720057, 1.0746363401, + 0.0611726567, 1.3872996569, -2.3101968765, 1.593637228, -0.6907869577, -0.0694889277, -0.2972775698, 0.8311193585, + -0.1777330637, 2.0184845924, 0.5656145811, -0.2051413357, 0.9329389334, 0.6280627251, -0.1737667471, 1.2492796183, + 0.8439475298, 1.2072235346, -1.0259077549, -0.2974030375, -0.4043617547, 0.8485488892, 1.0105415583, 1.0167632103, + -0.3439735472, -0.7064131498, -0.3029172421, 1.4635292292, 1.8002523184, 0.4651216567, -0.3715837598, -0.2971130908, + 0.3571931124, -2.6784129143, 0.3649374545, -0.3777738512, -0.7590556741, -0.0151699381, -0.8821194172, 0.5951886773, + -0.0852708519, 0.9750209451, -2.0264630318, 0.3239995539, -1.546826601, -0.6036015749, 1.2733149529, -0.5170837641, + 1.3886284828, 2.0128860474, 0.6841310859, 0.5642735362, -1.7078286409, -0.1220685244, 0.8022543192, 2.9402222633, + -0.5440009236, 0.5440354347, -0.3028250933, -0.123647131, 1.071105957, 0.1711559743, -1.1677023172, -1.594858408, + 1.1498628855, 1.7074403763, -1.7957524061, -0.3149690032, 0.1568339318, -0.3114894927, 0.0211651828, 0.1890159994, + 0.9555293322, -0.2745038271, 2.7662432194, 0.4147194326, -0.403447032, 0.3713617623, 0.3691652417, -0.8164408803, + -0.0419991501, 0.8501044512, 0.4174660742, -0.466160655, 0.7105901837, -0.1279045492, 0.3523364067, -0.2073855847, + -1.1988571882, -0.0351843536, 0.1673676521, 2.1629037857, 2.3720927238, 0.5707538724, -1.2859030962, -1.7754752636, + -2.2168619633, 2.3724796772, 0.0648849458, 0.421698004, -0.4210457206, -1.1706908941, 1.2849756479, 0.0288783815, + 0.0029941904, -0.2512137294, 1.0792390108, 0.0430316254, -0.1150320619, 1.3237221241, 1.2466740608, -0.7737157941, + 0.356837213, -0.7242242694, 2.0552656651, 0.5782729983, -2.119440794, -0.4371688962, 0.5964887738, -0.1009557024, + -0.2599818408, -0.5893468261, 1.4360679388, -1.2596794367, 1.6888058186, 0.1015370265, 1.0656791925, 0.5520688295, + -0.1842226237, 0.363054812, 0.3245004416, -1.7664282322, -0.6189075708, 0.8789561391, -0.0498849228, 0.1388183832, + -0.6309426427, -1.2514204979, -0.9320270419, -1.3813583851, 1.6924980879, 0.4783075154, -0.2157701105, -0.4409082532, + 1.7098357677, -0.0066842828, -0.6266974807, 0.3062791824, 0.8604946733, 0.3906947374, 0.6621009707, -0.3415372968, + -0.1327738911, 0.109002769, 0.5395166278, 1.3441191912, 0.3890197575, -1.500349164, -1.6765406132, 1.0947563648, + -0.419475168, 2.2247760296, 1.4415625334, -0.7291014791, -1.1591322422, 0.0448737144, 0.1642017961, -0.4120277464, + -1.080082655, 0.0302338228, -0.1979196072, 0.2417976409, -0.421729207, 2.8807368279, -0.2916334867, -0.111949861, + 1.4483487606, 1.3079737425, 3.1414964199, 1.9990832806, 1.3666808605, -0.408988297, -1.9430245161, 0.1383289248, + -0.2756088376, -0.3302395046, 0.3767584264, -0.1456294358, -0.0736739188, -0.2632665634, -1.0246253014, -0.0997517109, + 1.414686203, 0.3474251032, -0.3105725646, -0.6983625293, 0.1704372913, 0.5889595151, 0.3045978248, -0.9002690315, + -1.0737453699, 0.9776275754, -0.821629405, -1.4059617519, -0.8584246039, -0.9430308342, 0.0863835663, 0.4300649464, + 1.0046936274, -0.1960627437, -0.9061456323, -1.2908878326, -0.8379617333, -1.2833580971, -0.4425460398, 0.8820519447, + 1.7542774677, -0.9453480244, 0.4118882418, -1.1179608107, 0.1755656004, -0.6019179821, -0.2438964695, 1.4608323574, + 0.6031800508, 0.405844301, 1.3704522848, -0.8749694824, -0.2395764142, 0.3866791129, 1.1813465357, 1.0303496122, + 0.4329538345, 0.6799361706, 0.1898843944, 0.5167849064, 1.348892808, -0.9842775464, -0.9970665574, 0.4313078225, + 1.4899312258, 0.2684113979, -0.8607005477, 1.5387905836, -0.237350747, 0.1182171926, -1.9649727345, 0.1285471916, + 0.7161492705, 0.0362120271, 0.9534409046, -0.9433271289, -0.9471279979, 0.4125443995, 1.580752492, -0.6251024604, + 0.0839564353, -1.3108118773, 0.8444495201, -0.9436219931, 0.2464914024, 0.150142923, -0.9166177511, 0.8560885191, + -1.7652616501, 1.0727841854, -1.1108458042, 2.2795565128, 0.9886731505, 0.7996646166, -0.758295536, 0.5232353806, + -0.5892561674, -0.495947957, 0.5991611481, -0.9851461053, 0.5707060695, -1.1462754011, 0.0037861473, 0.393121928, + 0.6216490269, 0.65967834, 0.8396199942, 0.1782273948, -0.4145593047, -0.1143532768, 1.4198349714, 0.4542442262, + 1.0489712954, 0.1573176235, 1.6916421652, 0.2117508501, 0.6056104302, -0.841984272, 0.8234154582, 0.998083353, + 1.0220810175, 0.661272943, -1.0162453651, -0.6721482277, -1.023997426, 0.7389633656, 0.606441915, 0.4327298105, + 0.4807211161, 0.1548499912, -0.1756894737, -0.4154034555, -0.5601374507, -0.62864995, 1.0796920061, 0.5231323838, + 1.2025828362, 2.7605485916, 0.9448372126, 0.4897510409, 0.3005301058, -0.3569986224, 1.4894896746, 1.0769951344, + 0.9457442164, 1.3836812973, -1.2388128042, -0.9194841981, 0.659217298, 1.1811634302, 0.1504609138, 1.1520256996, + 0.7040884495, -0.7302854657, -0.7238515019, 0.6783299446, 0.5535770059, -1.1894803047, 0.1862907112, -0.7157256007, + -1.6877734661, 0.2565253377, 0.9417484403, -1.1264679432, 0.3717091382, -0.6848784089, 0.8496810794, 0.5500252247, + 1.2373111248, 0.5267019868, -0.3370111287, 1.7402325869, 0.6208246946, 0.1496523172, -0.0145279448, -1.0990328789, + 1.0914890766, 0.3146514297, -0.2327844501, -0.9927524328, 0.2801242769, -0.8725679517, -0.3057530224, -1.4110640287, + 0.0511594787, 0.0009446123, 0.4381587207, 1.037823081, -0.8866230845, 0.1709326804, -0.2147371024, -0.5751985908, + -0.4123259783, 0.323120147, -1.2464450598, -0.1151144356, 1.0316728354, -1.7826942205, -0.2277909219, 0.2456097901, + -0.1247552261, 1.1718108654, -0.9280160069, -0.8763661385, -0.9531322718, 0.3050051033, 0.9160202742, 1.1899218559, + -0.3139192462, -0.5719921589, 0.2692719996, 0.6695338488, -1.4176100492, -0.1810361296, 0.8919016123, 0.3253822625, + 0.2102392316, 1.1510844231, -0.273162514, 0.9161008596, -0.3529846966, 0.7246912122, 0.3719465435, -0.6608036757, + -0.7025949955, -0.2617565691, -1.5062785149, -0.2983382642, 0.7757444978, 0.5407574773, -0.894816041, -0.3278140426, + -0.2843683064, 0.3198806047, 0.7847097516, 1.0833867788, -1.1843409538, 0.9079430699, 0.7242349982, -0.1339356005, + 0.420999229, 0.3426757455, 1.302302599, -0.1115856692, 1.1961381435, -0.6273810863, 0.5569947362, -2.0751523972, + 0.4874547124, 0.0112005575, -1.9131480455, -1.6525598764, -0.9860039949, -0.4189216495, -0.2969622314, -0.4724214971, + -0.292068094, -0.6366106868, 1.4640799761, 0.0001000688, 0.6696881056, 0.3056806624, 0.2199319601, 0.5476730466, + 0.2989024222, -0.3060296178, 1.5866267681, -0.19234249, -0.7535434961, 2.4642388821, 1.4206904173, -1.3298442364, + -1.6729069948, -0.2089457661, 0.128696084, 0.2165742069, -1.2509105206, -1.2517259121, 0.0144478939, -0.5250476003, + -1.4943634272, 1.7899401188, 0.7980135083, -0.2467044145, 0.1137525737, -0.8360635042, -1.079026103, -1.4593545198, + 0.6329082251, -0.1951130778, 0.2109565586, -0.6452851892, 1.3813667297, 0.3914685845, 2.4400918484, 0.8632235527, + 0.4989744127, 0.4575488269, 0.6004958153, 1.402320981, -0.9147142768, 0.3939240277, -0.2197887301, -0.9745028019, + -0.8095402122, -0.1595830917, 0.3253418505, -0.9514853954, -1.2631294727, -1.9905785322, -0.1589462757, -0.2686427534, + -1.0362379551, -0.5929874182, 2.1278758049, 0.6741823554, -0.3402375579, -0.8575452566, 0.1285680085, -0.1974782944, + 1.3091429472, -0.0491636656, -0.8006293774, -1.9171167612, -1.6133759022, 0.672434628, 0.2764676511, -1.0947827101, + 0.7140973806, -0.4589699209, -0.5040537119, -2.6571507454, 0.4938603342, -0.1112184599, -1.1413344145, 0.3065828979, + -0.0351181589, -0.2077741474, -1.2007638216, 1.3442721367, -0.2882195115, 0.7794566751, -0.0357597359, -0.4914976358, + -0.6510698795, 0.4476221204, -0.2434361875, 0.3303336501, -0.1247829944, 0.945684433, 0.3387642205, -0.0858657435, + 0.0836824849, 0.3197313249, -0.522459805, 0.0667929351, 0.9599102736, -1.2944271564, -1.6121833324, -0.46102193, + -0.0686687902, -0.6209889054, -0.5094255805, -1.3296127319, -0.651994884, 0.3874265552, 0.2548698485, 0.6057342887, + -1.1156878471, 1.7558230162, 1.3769574165, -0.5067620277, -0.2540018559, 0.1169501916, 1.4090871811, -0.2061688751, + -0.3826217651, 0.0744053125, -1.0701073408, 0.2666794658, 0.0159707237, -1.0801004171, 0.302000612, -1.1221276522, + -0.0603687689, 0.4302231073, 0.8030367494, 0.3813634813, -0.5177665949, -0.5745231509, -1.2133439779, 1.0359526873, + -1.077368021, -1.0581761599, -0.7194543481, 0.791187346, 0.3575147688, 0.4734067023, 1.3755928278, -0.3413253725, + -0.7216416001, 1.4161067009, -1.065731883, -0.5758734345, -0.0554632656, -0.5676805973, 1.0491763353, -0.5460031033, + 0.0000377406, -0.1134769619, -0.1902130544, 1.112224102, 0.0361957811, -0.5202575326, -0.9287207723, 0.467323184, + 0.2076914012, -0.5268574357, -1.4158695936, 0.9209938049, -1.2451177835, 0.3177010119, 1.3631247282, -0.6694192886, + -0.5273765922, 0.1168278307, -0.1416368484, 1.090290308, -1.5505670309, 0.8457047343, 1.2713711262, 0.8615369797, + -0.6803045273, -0.943688333, -0.8042429686, 1.2764884233, -1.4393085241, 0.6460635662, 0.1760231256, 0.6022271514, + -0.6289021969, 0.2052420974, -0.905431211, -2.2867314816, -0.5080083013, -0.3702924848, -0.3562673926, 1.6888591051, + 1.0248645544, 1.2868249416, -1.4498550892, 0.4269231856, 0.7690059543, 1.2068730593, 2.2509765625, -1.3853080273, + -0.0437916964, 0.5083934665, -0.1405894905, -1.9240996838, -0.0695686266, 1.029079318, -0.6863524318, 1.5921109915, + -0.5149906874, 0.4313142598, 1.2325224876, 0.7381823063, 0.0506481752, 0.2718752027, -0.0458972342, -0.2813476324, + 0.1470736563, 1.1240963936, -0.4729631841, 0.3032023907, -0.0378687717, 0.7551904321, 0.2726889551, 0.8062175512, + -0.9914822578, -1.3461425304, 1.3953132629, -0.3963041306, -0.1348937005, 0.1861299574, -0.1282923222, 1.31917274, + -1.3927209377, 1.6524684429, -1.4570862055, 0.1970746368, 0.7873681784, -1.5872268677, 0.7789785862, 0.725715816, + 0.9104884863, -1.045809269, 0.1311151236, 0.0523036309, -0.5617845058, 0.6315040588, -0.8047713637, -0.7324396968, + 0.5472825766, -1.1248081923, 0.7605649233, 1.9306453466, -0.8998404741, -0.9145870209, 0.7737373114, -0.7555955052, + -0.0085799778, 0.6102102995, 1.0703949928, 0.0122935213, 1.7418897152, -0.8565835357, -0.1485811919, 2.5863671303, + 0.2296967655, 0.4921732545, -0.2157451808, 1.7708336115, 1.4435811043, 0.3088599741, 0.3821006119, 0.7828531265, + 0.8288940787, 1.2654770613, 0.5320999622, 1.6035956144, 0.0555833168, -0.7808041573, -0.4768952131, 0.0609117076, + -0.4685634375, 0.0401823297, -0.7980151772, -0.1980319172, 0.362218529, -0.012424225, 0.001921227, -1.8690266609, + -0.6661810875, 1.260376215, 0.392599076, -0.947157979, 0.9259031415, -0.6989381909, -0.5957267284, 0.8059161305, + -0.0204536505, -0.7605403066, -0.8714606762, -0.0785574615, 0.217692405, -0.0952641219, -0.6237257719, 0.8928356767, + 0.020747656, -0.8050456643, -1.1606603861, -2.1986162663, 0.5743509531, -0.3747348487, -0.9865067601, 0.6025411487, + -1.6260415316, 0.4241379201, -1.5761916637, -0.5231423378, -1.2368144989, 1.3236354589, -0.262889415, 0.9006096721, + -0.5883111954, 0.9315660596, 0.3901229501, 0.3613577783, -0.9036842585, 0.6531979442, -0.5237332582, -0.4377007186, + 1.2412061691, -1.8077656031, 1.0896279812, -0.5850965977, 0.9993878603, 0.979395628, 1.7526859045, -0.1627811193, + 0.0789898112, -0.600851655, 0.6423956156, -1.3718004227, 0.8177475333, 0.1333660483, -0.7116602659, -0.7372015715, + 0.0193281416, 0.5816512108, 0.632212162, -0.9512215257, -2.3198320866, -0.1225626543, -0.7548299432, 1.7849982977, + -0.4172134101, 1.1810698509, -0.6830892563, 0.9388549328, -1.2363265753, -0.6732035279, -1.1739046574, -0.3762327731, + -2.270149231, -1.8741184473, -0.9467853308, 0.1845830977, 0.0290970095, -1.1332253218, 1.5481897593, 0.6677289009, + 1.6565377712, -0.1813921779, -1.4472157955, -0.9493680596, -2.3203413486, -0.1047000363, -0.5362039208, 0.1503630877, + -0.2119492143, 0.1951975077, 0.3594886661, 1.10711658, 0.5541626215, -2.2391679287, -0.0982199907, 0.1499948204, + -0.2038379759, -0.364125222, 1.2327725887, -1.0428520441, -1.1857684851, -0.375867486, -0.7437927723, -0.5258880258, + 1.6090214252, -0.5477022529, -0.5831058025, -0.7693243027, 0.9592191577, 0.7612723112, 0.6288821697, 0.4854650795, + -1.0746076107, 1.00548172, 0.026111247, -1.3465268612, 0.8569097519, -0.8402596116, -1.0034821033, 0.034005329, + 0.6326579452, 0.0624723062, -0.8272801638, 0.9872714877, -0.649325788, -0.0124687888, -0.0510785058, -1.0020663738, + 1.7653633356, 0.6531934738, 1.7806649208, -1.2149158716, 0.1973568499, 1.2248632908, -0.6891977787, -0.5806148648, + -1.4091354609, -1.4452899694, -0.162105456, 0.2553484142, 0.5607942939, -0.3715134859, -1.2819964886, 0.1613192409, + 0.7283805609, 0.9018242955, -0.469933033, 0.7522509694, 0.0473475978, -1.4565970898, 0.2873678505, 0.6105089188, + 2.308709383, -0.4378469586, 1.5861054659, -0.0902395621, 0.2450557947, 1.6665794849, -0.2875549495, -0.6267389655, + -1.1200077534, -0.1176927686, -0.9884122014, 0.0998817012, -0.3104116321, 1.6640614271, 1.8047343493, 1.7079073191, + -0.2945924997, 1.4536072016, -0.9042026997, -1.5250431299, -1.2416226864, 0.9511591196, 1.6640285254, 0.9149685502, + 0.534848392, 0.0271247104, -0.4100965559, -0.4923259616, -0.528452456, 0.73269701, -0.6320443749, -0.1361745298, + 1.7820904255, -0.4102703035, 0.1149579212, 0.4176089168, 0.5615858436, -0.1241502464, -0.2711972296, 0.8339188695, + -0.3911842406, 0.8035120964, 0.4347385466, 0.3256336153, -1.0912731886, -1.106426239, -1.0023913383, -0.0014343157, + 0.6572046876, 1.1768506765, -0.161215812, 0.2430538386, -0.4206996262, -0.6818819046, -1.5458599329, -0.4415317476, + 0.8601318598, 0.5682681799, 0.5093677044, 0.6739342213, 0.2802112103, 1.0092612505, 0.5739693046, 0.4783741236, + -0.7188705802, -0.755521059, -1.2773789167, 0.9673935771, 0.7169851065, 0.6318838596, -0.3510349393, -0.2784935236, + 0.9245770574, 0.145611763, 0.8596948385, 0.5870320201, 0.3222205639, -1.1058843136, 0.1310071945, 0.1351862252, + 1.4976658821, 0.064257659, 0.980596602, -0.2625622451, -2.0229084492, -0.2577911317, 0.8459518552, -0.9816684127, + 0.0494478457, 0.1633282155, 0.8872380853, 0.2346172631, -1.4553668499, -1.2075823545, 0.9899796247, -0.7265192866, + -0.1070689112, 0.4315021932, 1.5511058569, 1.0648895502, 1.2513504028, -1.6179898977, -0.1960540712, -1.1174563169, + -0.0627279058, 0.3648060262, 0.4943988621, 0.469973892, 1.5897046328, 0.4787073135, -0.2594979405, 0.983923912, + -1.1296446323, -0.2151689082, 1.8668168783, 1.2359091043, -0.7876203656, 2.2410216331, -0.6001842618, 0.6790406108, + 1.9386615753, -0.2716152966, -2.4987998009, 0.7988651395, -1.735239625, -0.8488154411, -0.2405159175, 0.0022603455, + -0.8565176725, -1.7655363083, 0.0227796603, 1.1678682566, 1.5977461338, 0.6137763858, -0.1560899615, -1.2249263525, + 1.0691320896, 0.8002671003, 0.9079485536, -0.5812396407, -0.6096565127, 0.8414008021, 0.8574656844, 0.8194988966, + 1.9166227579, -1.2481331825, 0.1276202202, 1.202721715, 0.6284421086, 1.8388808966, 0.7530941367, -0.5810328126, + -0.1983797401, 2.4699819088, 0.5870167613, -0.3973526657, 0.4335496426, 0.5002970695, 1.2368345261, -1.0192248821, + -0.4722243547, 0.1429932714, -0.6643745303, 0.9991702437, -0.7230226994, -0.9242684245, -0.6563588977, 1.8147925138, + 1.0481163263, 0.5963919759, 0.3161043823, -1.5705043077, -3.0482473373, -1.4911568165, -0.5620017052, -1.5762267113, + -0.2792216539, -0.0183045566, -0.3427428901, 0.4325659573, 0.084194079, -1.5596717596, -2.3954472542, 0.6650484204, + 0.9164831638, -0.6995766759, 0.7592606544, 1.9653995037, 2.1778728962, 1.3679281473, 0.3184723258, -1.375374198, + -0.5408719778, -1.3242262602, -0.0486250222, -1.4743169546, -1.9059720039, 0.4585015178, -1.3563024998, -2.1027057171, + -1.6160247326, -0.8111845851, 0.6833175421, 0.3431516886, 1.0679210424, 0.3967325985, 1.3747622967, -1.9252409935, + -1.562143445, 0.3567034006, 0.1609219313, -0.4597774446, -1.5141679049, 0.2331478596, -1.2618752718, -0.7512057424, + -1.0166230202, -0.5066205263, 1.9142640829, 1.3055176735, -0.3582405448, 0.3410398662, 0.7159633636, -0.9026330709, + 0.9061701894, -1.3593796492, 0.2564473748, 0.637150526, 0.4507238567, 2.0558533669, 0.4674500823, 0.4008921087, + 1.1421283484, -0.7805560827, 0.8754662871, 1.1091470718, -0.4740432799, -1.047109127, 0.5696887374, 1.4610911608, + 0.2937921584, -1.3595267534, 0.5948380232, -0.5259676576, 0.6979746819, 2.6188032627, 1.7860373259, 1.3816629648, + 0.3645930588, 0.6413857937, -0.3179526329, -0.669434011, 0.8531759977, -0.5612838268, 0.6540765762, -0.7173810005, + 0.7171044946, -0.3337262869, -1.2696685791, -0.3191621602, -0.0951602459, 1.643728137, 0.410402298, -0.6791217327, + -0.5343052149, 0.1236637682, -0.686752677, 0.4327032268, -0.9899078012, 0.3520361781, -0.037229035, 0.0954944342, + 0.8924535513, -1.3897480965, 0.290815413, 0.1433742046, -1.2002483606, -1.1578544378, 0.2018009126, -1.7330788374, + -0.3900980949, 0.3442434072, 0.5612210035, -2.3735797405, 0.4677275121, -0.8755277395, 0.3840200901, 0.7140026093, + -0.0161184259, -0.2327160239, -1.3661100864, 1.8017098904, 0.1095980778, -0.914031446, -2.1166992188, 1.5349193811, + 1.5171842575, -0.783121407, 0.8759396672, -0.3350074291, -0.6258761287, 1.1088163853, 0.165931046, 0.385913372, + 2.1467437744, -1.4819864035, -0.1044765934, 0.0227515679, -1.3247855902, -0.0460397489, -0.2199831605, 0.3223781884, + -1.8705461025, -0.2860034704, 1.3835725784, 0.0756484866, 0.7798700333, 1.1855169535, 1.0793471336, 1.5322893858, + 0.4833815396, 0.7111821175, 1.2975721359, 0.5630246401, 1.6598074436, -0.3058865666, 1.0004166365, 0.239913553, + 2.0036790371, -1.0272872448, -0.2898159623, 0.3397452831, -0.5536059141, 0.1857142448, -0.8085384965, -1.5434528589, + -0.0007162808, 1.0881972313, 0.6845315695, -1.8424415588, 0.6105918884, 1.3732216358, -1.060147047, 1.1996201277, + -1.2230579853, 1.1186140776, -0.6385557652, 1.1005522013, -1.8498262167, 1.9758620262, 0.3748421669, 0.9024031758, + 0.6665591598, -0.5407711267, -1.1386766434, 0.8666719794, -0.7272105813, -0.5572866797, 0.3335200846, 0.2419228256, + 0.1356631666, 0.0634459481, 0.507109344, -0.1976352483, -0.1633360833, 3.0307579041, -0.6317493916, -0.2643266618, + -1.2277452946, -1.0420066118, -0.2836993039, 0.8368556499, -1.4368258715, -0.4121444225, -0.1726893187, -2.3277754784, + -0.5735732317, 0.4645721018, -0.1024918482, 0.9124009013, -0.9102084637, 1.3875967264, 0.7080764174, -1.5910292864, + 0.193564862, 0.8600574136, 0.3366048932, 0.4506984651, 0.65147686, -0.0764857233, -0.5673771501, -0.2962603569, + -1.1983201504, 1.093072176, -0.4548245668, 0.9074430466, 0.0770448744, 0.8746569753, -0.2766015828, 1.23797822, + -0.0664854795, -1.2437325716, -0.4574719965, 0.7507360578, 0.6556258202, -0.270444721, -1.5917396545, 0.9173870087, + -1.8183697462, -0.6614665389, 1.0413696766, 1.2564733028, -0.5287645459, -0.7868911624, 0.4760374725, 1.4004799128, + -0.3912179172, -0.3319635987, -0.1274384409, -0.3486401141, -0.5874551535, -0.4041832685, -1.2626019716, + -0.2735873163, -1.8302440643, 1.1272053719, -0.9103027582, 0.9363489151, 1.7044332027, -1.4405498505, 0.1213527992, + -0.7432028651, -0.3949774206, -0.6219618917, -1.0270428658, 0.3988615274, -1.2037241459, 0.0879646614, -1.0123245716, + 2.2703430653, -0.1986519694, 1.0142803192, -0.5765676498, -0.1850306988, 0.9218153358, -1.4215303659, -0.3045988679, + 0.8781455755, 0.4839467108, 0.3406828046, 0.1385729313, 0.5530541539, -0.2178639174, 0.6572006345, -0.7660921216, + -0.1504787654, -0.6955124736, -0.8039906025, 0.1935697198, -0.6107688546, 1.4775750637, 2.1482009888, 1.2706098557, + 0.8919548392, 0.551794529, 0.4745905995, -1.3749998808, -1.9628106356, -0.2441599369, -0.2756695151, 2.3750700951, + -1.012503624, 2.3627867699, -1.0484228134, 0.0202945489, -1.6291437149, 1.5460455418, -0.2626701891, -1.3716934919, + 1.7448372841, -1.9003964663, 0.7340160608, -0.9719927907, 0.4878770411, 0.8426557183, -0.0036995597, 1.1608890295, + -0.1446119249, -0.3867310584, -1.2060709, -1.8427013159, -2.1762900352, 0.5401457548, -0.5232191682, 0.6863697767, + 1.7252759933, 0.9453377724, -1.2271872759, -0.5287625194, -0.5573931336, 1.1400207281, 0.8531771302, -0.7874594331, + 1.4860290289, -0.3966833353, -0.8653481603, 0.668287158, -1.3460118771, 1.11013937, 2.5374398232, 1.5781009197, + -0.2074164003, 1.1810634136, 1.3876578808, 0.4343869984, 1.0187358856, -0.3469872475, -0.0697899982, 0.684971571, + -0.7938639522, 1.0810682774, -0.7873340249, 0.4875499606, -0.5890196562, 0.6428114176, -0.5371803641, -0.0320537537, + -0.6355226636, 0.2840048969, -0.7231734991, 1.6757985353, -1.3749076128, -0.1871342212, -0.5509265661, 0.2247584015, + 0.0963228941, 0.5343322754, 0.4177618623, -1.0538265705, 1.7033421993, -0.1041369513, -0.5689711571, 0.144902125, + 1.510117054, -0.8077566624, 0.1635077, 0.3681793809, -1.3697288036, -0.9026447535, 0.1419233531, -0.4355032146, + 1.4709450006, -1.2994558811, -0.1398774087, 0.4056711495, -0.9279340506, -0.4008336663, -0.1832318157, -0.4932772815, + 1.1810588837, -0.4294885397, 0.258695513, -0.6026366353, -1.6949310303, -2.4281458855, 0.3360414505, 0.0007651557, + 0.6452424526, 0.0013740991, 1.2619608641, -0.6294914484, 1.0755714178, -1.694604516, 0.4138219059, -0.9013427496, + -0.9153943658, 0.2750778496, -1.7745633125, 1.2423049212, 1.4853067398, 0.6582362056, -0.494494617, 0.8580268025, + -2.5256597996, -0.4416845739, 0.0358854383, 0.2637412548, 0.139609471, -0.2113924474, -1.0850139856, 0.8667337894, + 0.6863631606, -0.7880696058, 0.2563993931, 0.6276249886, 0.5765470862, 1.0376647711, -0.8950424194, -0.737447083, + -0.5733580589, 1.5468299389, 1.0180302858, -1.3552303314, 1.5083237886, -1.5015984774, -0.4331097603, -0.723611474, + -1.265230298, 1.8355219364, -0.9491904974, 0.7845528722, -0.1004951149, -0.9171906114, -0.6248505712, -0.5434099436, + 0.2936888933, 0.7476300597, -0.1759679466, 0.7415206432, 0.1636239588, 0.3913640082, -1.0406374931, 1.596668601, + 1.7157511711, -0.9193367362, -0.515561223, 0.3866383433, 0.3502348959, 0.6012752652, -0.2728933096, 1.0108480453, + -0.3607590199, -0.9352738857, 0.011394416, -1.0877426863, -1.2035589218, -0.5796896815, 0.0864668638, -0.7101565599, + 0.0531113632, -0.7170058489, -0.0952148288, 0.3925267458, -1.0388872623, 1.1641366482, 0.4681651592, 1.2697256804, + 0.5855969787, 0.8054180145, 0.5459367037, -0.0193008948, -0.0799392536, -0.7031532526, -0.3332782388, 0.8763495684, + -0.3275536895, -0.0899465531, -0.7804068923, 1.5976791382, -0.0845693126, -0.8380930424, 1.2919481993, 0.3801421523, + 1.0650464296, -0.4915513992, 0.3796888292, 0.3082422614, -1.2515425682, 0.8574884534, 0.0453626625, -0.8994646668, + 0.1817809045, -0.3982611299, -0.4245830178, 0.4759723842, -0.5196942091, 0.9084286094, -0.2574448586, 0.6669890881, + 1.4542843103, 0.6965520978, -0.4026068151, 0.4368975759, -0.1450076252, -0.7213081121, -1.9050275087, 0.1893024594, + 2.1357374191, 1.5123866796, 1.454182148, -1.6385452747, -1.5910087824, -0.6939245462, -0.8785220981, -0.807592988, + -0.3812121153, 0.8093725443, 0.2798313498, 0.527017951, -2.3664381504, 0.5130461454, 0.0916117877, 0.6262785792, + -0.7436412573, 0.3277203441, -0.7760006785, -2.5068039894, 0.4759555757, -0.901019454, 0.0145629812, 0.8987622857, + 0.335319221, 0.960667789, -0.2874678075, -2.9939599037, 1.2504578829, -1.1720881462, -1.035664916, 0.6958131194, + 0.4948087037, -0.4572609365, -1.6435623169, 1.5744616985, -0.0300552286, -1.0009658337, -0.9311393499, 1.0732966661, + -0.2361930311, 0.2371501774, -0.5839691758, 0.8537157774, -0.2181455344, 1.7659276724, 0.2091579586, 1.5832922459, + -0.1612836719, -0.6309607625, -1.7614916563, -0.5587900877, -1.0242021084, 0.0377286524, 0.4732848704, -0.1918084174, + -0.0163135994, 0.2189601362, -0.9728784561, -2.5277113914, -2.9586434364, 0.6248936653, 0.9954282641, 0.9903995395, + 2.019397974, 0.4239855707, 0.8024560809, -0.2874479592, 0.2707243562, -0.7016677856, 0.360619396, -0.3674240112, + 1.8943160772, 2.4282639027, 1.5565392971, 0.8108466268, -0.4795611799, -1.8067957163, 1.3225959539, -1.4695440531, + -0.4730064571, -0.1111553162, -0.1633212417, 0.7373108864, 0.0697204918, 0.1390757263, -0.5723037124, 0.1945779175, + 0.4934951663, 0.8671396375, 0.0400937945, -0.8754099011, 0.375447005, -0.1142536923, -0.4761653841, 1.7966411114, + -0.2497129291, -1.3456119299, -0.2531846464, -0.0173894931, -0.8581447005, -0.8182291985, -1.2103476524, + -1.8957642317, -0.5462412238, -0.3278253973, 0.4181403518, -0.8027678132, -0.1248840615, 0.3669672012, -0.4320286512, + -0.6431820393, -0.3669171929, -0.4180790484, -1.1114394665, 1.5662413836, 0.4966558814, -1.5271258354, 1.6809345484, + 0.9452425838, 0.7926274538, -0.1260183305, -0.3414977193, 1.1150146723, 0.7628927231, 0.718639493, 2.0608656406, + -1.1427087784, -0.6720955968, 0.4238626957, -0.2674430609, -0.1200173497, 1.1119060516, 0.2046580315, -0.1742334217, + -0.689933598, 0.4895804822, 0.5928009152, -0.6894159913, -0.7927412987, -1.3092082739, 0.6599462032, 1.1592344046, + -0.6471576691, -0.8530796766, 0.2530079484, -1.2349803448, -0.4698171914, 0.6378022432, 0.0646075532, 1.26651299, + -0.0035302599, -0.4264021516, 1.9557579756, 0.3368331194, 0.1942038685, 0.2976615727, -0.2447934896, -1.1720229387, + 0.0022187224, -0.5681318045, -0.00831577, -0.2423404306, 0.407969445, -0.4025951028, -1.6668678522, 1.1076716185, + 1.1742789745, 0.8371176124, -1.2049195766, 0.8989720941, 0.5069872141, 1.2650052309, 0.5479833484, -0.6105635166, + -0.7324912548, -0.7606137395, 2.3526127338, 0.3232249618, -0.0974526554, 0.4910657406, -0.3990236223, 1.5860863924, + 0.8555051684, -0.1618283838, 1.5360722542, -0.0187115595, 0.4534055293, 0.5044534802, -0.269919306, 0.7831186056, + -0.0310493931, -1.5355266333, 0.1740212291, -0.5708485842, -1.2032914162, 1.0133572817, -0.992564857, 0.619382143, + -0.5009004474, -0.094874613, 0.5210202932, 1.4905010462, -0.0342098996, -0.743103385, -0.1009846702, 1.3803369999, + 2.7175147533, -1.6663825512, -0.6393872499, 0.2210241407, -1.6114358902, -2.2916140556, -0.1636691839, -0.5086622238, + 1.3264782429, -0.7173157334, -0.6772971153, -0.3950392008, 1.3992792368, 0.4134455919, 0.9333790541, 0.8993307948, + 0.2048672885, -0.289876312, -1.4870306253, -0.0224908516, -0.6100093722, -0.0982251316, 1.4243254662, -1.5467219353, + -0.3993415534, 1.2259448767, 0.1247667298, -1.8018198013, 0.4228524268, -0.2830335796, 0.2086140662, -1.8642035723, + 0.2794917822, 0.891253233, 0.4764015675, 1.1169859171, -0.8097556233, 0.6917906404, -0.5510755181, -0.171116516, + 0.724278152, -0.1862911284, -0.8004393578, 0.1734851003, -2.3327710629, 1.0729398727, -0.0054144766, -0.6906583905, + 0.1949700415, 1.1526728868, 0.627772212, -0.4168083966, -0.4985950589, -0.4415447414, 0.4759062827, -0.9995189905, + -0.0556426719, -0.8905441165, 1.5150352716, -0.4012076855, -0.5104394555, -0.3579500318, -0.8876761198, -0.1260623485, + 1.210074544, 0.3163279593, 0.1174208298, -1.0488599539, 0.8006420732, 0.8193587065, -1.4236061573, 0.0530269407, + 0.84193331, -2.3811285496, 0.3123259842, 2.0316591263, -0.1334241331, 0.956674993, 0.3105371296, -0.0280005373, + 0.1698162705, -0.6434794068, 1.4687440395, 0.8223428726, 0.5253647566, -0.941432178, 0.2501220703, -1.4306063652, + 0.441755861, -1.3391911983, -2.1790165901, -0.6563906074, 1.6905251741, -1.0324158669, 0.0105966255, -0.4265025556, + 0.1774287373, 1.1015805006, -1.2504085302, 1.9962170124, -0.7548727989, -0.4495831132, -0.1260795742, -0.9168621898, + -0.538651526, 0.4052873552, -1.6897302866, -1.1016709805, 0.3024735451, 1.594365716, -1.4092345238, 2.6607553959, + 1.1071485281, 0.2390423715, 0.457316339, -0.1807434261, -1.9098607302, -0.3015142679, -0.5953611135, 0.1685141623, + 0.3814010024, -0.0196545552, 0.1171996817, 0.5379750729, 0.0300317835, -0.7584958076, 2.2050728798, 0.7647278309, + 1.4125244617, -0.650066793, 0.7842895389, 0.647223413, 0.1368263811, 2.1448404789, -0.4679664671, -0.3690626025, + -0.8305638433, 0.4829550087, -0.4260619879, 2.0036153793, 0.8908524513, -0.4578307271, -0.4667037129, 0.5653272867, + -0.2103756368, 0.0654499233, -1.0563793182, 0.8389202952, -0.9145900011, -3.0074131489, 0.8634305596, -0.3165632188, + 1.3181333542, 0.7771042585, -0.3728661537, -0.9975465536, 1.3015630245, 0.5809165835, -0.199198544, 0.4615896344, + 1.6888397932, -0.947691977, -1.0568165779, 0.6325836182, -0.2203704268, 1.1994246244, 0.2282462716, 0.7648639679, + -0.6254203916, 0.0122858062, -0.1240646094, -0.3559269309, 0.5451278687, 1.2897644043, -0.1418277174, -0.0237832293, + 2.4164583683, 0.3128513694, 1.2583760023, -0.0183320828, -0.2904647887, 1.126375556, -0.1271803826, -0.6991423368, + 0.4350317717, -0.9930130839, -0.0732888058, -0.0096755922, 0.6082351208, -1.4622994661, 0.3734008372, -0.2516731918, + -0.5549135208, 0.2704532146, 0.8839444518, 0.9480336905, -1.7732236385, -0.3400033414, 1.0801545382, 0.407674253, + 1.109223485, -0.5090354085, 0.0154662654, 0.8081864119, 0.1444585472, 0.4838244617, 0.4002939761, -1.8577429056, + 0.0833002552, 0.1059778705, 0.7952242494, 0.0375305712, -0.0192010757, 0.570804894, -0.6749990582, 0.6472918987, + -0.5778470635, 0.5768222213, 2.3813226223, -0.8882810473, -0.037080247, -1.5818849802, -0.5403636694, 0.9223807454, + 0.8768610954, 1.6823604107, 0.464168787, 0.5547270775, -0.747630775, -0.1079692096, -0.5736877918, -1.193366766, + 0.2192575037, -0.1325137913, 0.0294413287, -0.7202627063, 0.0728821531, -1.4440402985, 1.1075712442, -1.7380994558, + -0.3122649789, 0.5126811862, 0.052060321, -1.6752490997, -0.4572330117, -1.4403076172, 0.3279295862, -2.2079944611, + -0.2930724025, 1.5250643492, -0.7436814904, 0.1235063225, -0.9559509754, -0.783151269, -1.1331845522, 2.1102159023, + 1.419387579, 0.7471066713, -0.1063024849, -1.962652564, -0.8340319991, 1.9938367605, -0.6666597724, 0.9762901664, + -0.8030210733, 1.0035098791, 0.438418448, 1.1932302713, -0.2671444714, 1.6537593603, -0.030093275, 1.7405285835, + 1.1974927187, -0.2730903327, -0.414829433, -0.9199048877, 0.9715379477, 0.2495393604, 1.9860477448, 0.3632284403, + 1.0493472815, -1.7863451242, 0.4960638881, -0.5253154039, 1.2082391977, 0.7166950703, -0.1228279471, 0.5477110147, + -1.1976144314, -0.4063251615, 0.1708601564, -0.5023768544, 1.981621027, 1.4944957495, 1.3486838341, 0.1301545054, + 2.2598488331, 1.0608019829, 0.682843864, -0.1969961673, -0.0942310393, -0.1965968609, -0.0145343514, -0.4977135956, + 1.4621585608, -0.536514163, -0.18092677, 0.0045570266, 0.5690778494, 0.7586371899, 0.2046857178, -0.272793144, + 1.0885236263, -1.1514253616, 0.0665233359, -1.5880743265, 0.8120266795, -0.052665446, 0.072860837, -0.0096358024, + -0.1773585379, 0.801366806, 1.6797046661, -0.276527971, -0.5227367282, 0.4652282894, 1.0062574148, -1.0238008499, + -0.3171005249, 2.1590240002, 0.1793651879, 0.2974379659, -1.7805523872, 0.236588642, 0.5838900805, 0.86895895, + -0.1619296968, -1.8251862526, 1.0525997877, -0.7366934419, 0.2232283652, -0.2124611437, 1.1224877834, -0.525370717, + 0.8429335952, -0.4547739327, 0.2139290422, -0.3529743552, -0.4005251527, -0.358828634, 0.5342850089, 1.0697213411, + 0.362737596, -0.6180936098, 0.720623076, 2.3563475609, 0.7881179452, -0.1104493737, -0.102034241, 0.9928730726, + 0.8416631222, -0.2109418511, 0.0594552308, 0.1714573205, 0.9736061096, -0.2536408901, -0.5090725422, 0.2091951966, + -0.3952316642, 0.6734473705, 1.8492509127, 0.5406158566, 2.1666073799, -0.4017258286, -1.0504158735, -0.5410004258, + -0.1275609881, -0.8653998375, -0.7439379096, 1.7201974392, -0.3531041741, 1.3364866972, -0.6355758905, 1.0752155781, + 0.155441314, 0.849984169, 0.2878955901, 1.3831596375, 1.0869204998, -1.9145219326, -0.6446622014, -0.6476334333, + 0.5867015719, -0.1330263019, 0.3355934322, -1.06359303, 1.1624379158, -0.2087804228, 0.9965528846, 0.4709334671, + -0.7888488173, -0.9004927874, -1.5506350994, -1.1885224581, 0.0462546945, -0.24470222, 0.3237609267, 0.581530571, + -0.0116930585, 1.9005151987, 1.5096068382, 1.0625275373, -2.6801900864, -1.4928581715, 2.7504143715, 1.5735440254, + 0.1196702197, 0.2730636895, -0.6364715099, -1.6727474928, -0.6743252873, 1.058236599, -1.6658549309, 1.0274500847, + 0.8210723996, -0.3279028535, -0.5612089634, -0.8480519056, -1.2279438972, -0.6800284386, 0.9341332912, -0.0853653327, + -0.6074674726, -0.570014298, 1.1554375887, -1.6881010532, 0.8331784606, 1.5076262951, 1.9043989182, 1.4181431532, + 0.6705791354, -0.2154797763, -0.1985649318, 0.8634696603, -0.2186039984, -0.7260090709, 0.8744863868, 1.0869740248, + -1.0211362839, -0.4984046817, 0.0550192371, 0.183088392, 0.8126010299, 0.8161264658, -0.856926918, -0.1854367256, + 0.97965765, -1.7851219177, -0.4285949469, 1.2304253578, 1.0196049213, 0.1956699491, -0.9608377814, 0.058565069, + 0.5979899764, -1.1106897593, -1.0379048586, -1.7021956444, 0.2371710539, 1.361877203, 0.1308800131, 1.5423973799, + 0.0521697253, 0.3295921087, -0.3451442122, 0.0585741326, 0.2526168227, 0.1740647852, 0.0335522965, 0.6994304657, + 1.510512948, -0.4503269196, -0.4363505542, 1.3006982803, 0.8859831691, 0.6783366203, 0.7363558412, -1.7234025002, + 1.45703125, 0.8774670362, -0.6389059424, -1.0063931942, -0.4606885016, -0.7491079569, -0.4581098258, 0.0056097927, + 0.3033953905, -0.5941976905, 1.0164443254, -0.1951033771, -2.0242991447, 0.9950196743, -1.6479471922, -0.2919598818, + -0.4742799997, 0.8809318542, 2.0386807919, -0.1976701617, -0.3874321282, 0.1774139851, -1.5380210876, 0.7691081166, + 0.2360260338, 0.1340331733, -2.06858325, -0.4424262941, -0.2943103015, 0.7442401648, 0.5301663876, 0.0796818957, + 0.8675574064, 0.1207659021, 0.4363836944, 0.395712465, 0.4611773193, 0.6354420781, -0.6371799707, -0.3056533039, + 0.4651468992, -0.124662891, 1.1826097965, -0.0713501945, 0.481151849, 0.0363793969, -0.4016169012, -0.2674632967, + 0.3393284678, 0.5643074512, -0.9851466417, 0.5367643237, 0.8051172495, -0.7623518109, 0.3541601598, 1.1396274567, + 0.7583637238, 0.4819799662, 0.5493212342, -0.2779793739, -0.5416448116, -1.0729044676, 2.4494299889, -0.4952209592, + -0.9134637713, 1.0599906445, 0.6519761086, -1.1102234125, 0.3736817837, 1.182418108, 1.043219924, -0.1811021417, + 0.3057804704, 1.5537210703, -0.3224816918, 0.3417883515, -0.7627717257, 0.3877569437, -0.5905166268, 3.1262331009, + -0.0636707246, 0.2948612869, 0.8857660294, -1.3919001818, -2.0759520531, 2.0139601231, 0.5181505084, 0.2192502469, + -0.4590292275, -0.7326875925, -0.0743509084, 0.2777031064, -0.0589995608, 0.7715876698, -0.1587277502, -0.5620646477, + 0.3577314913, 0.3553095162, 1.7608978748, 0.3887453675, 0.2869249582, -1.5057801008, 0.1353569478, -1.1386996508, + -1.7352130413, -1.0972082615, -0.8925606608, 1.0090011358, 0.4416737258, -0.1895652562, 0.5086488128, 1.2149100304, + -0.5647054315, 1.0612516403, -0.0578660406, 0.3708175421, -0.0541841723, 1.822522521, 0.3027867377, 1.0238395929, + -2.0085389614, 0.048191715, 0.3897301257, 0.2223383039, 1.1534072161, 0.8207922578, 0.0908544362, -1.384170413, + -1.4576156139, -1.2129918337, -0.9277918935, 0.1623429805, -1.0262908936, 3.5983099937, 0.6017745733, 0.5672770739, + 0.6544624567, -0.9301851392, 0.1682607383, 1.410936594, -2.0551912785, 0.9204959273, 0.0109659592, -0.0355977714, + 0.1439855695, -0.229629755, 0.9706581235, 1.0231167078, -1.0316967964, 1.8201168776, -0.2633411586, 0.4973664284, + -0.8761262298, -0.7698000073, 0.9660003185, 0.2249306291, 0.2809285223, -0.9330500364, 0.4547836483, 0.5424904823, + 0.0041835858, 0.8023304343, -0.3718265891, 1.3409324884, -1.7307722569, -0.092967324, -0.1464788914, 0.605427146, + -0.3584529757, 1.156211257, 0.3190774918, 0.903116703, 1.1098406315, 0.3319199085, -0.7225655913, 0.029232651, + -0.6798599958, -1.0965301991, 0.8027890325, -0.2196585387, -0.6784861684, -0.6861836314, -0.9749602675, 0.6559276581, + -0.203637138, -0.5718295574, 0.2653274238, 0.3244380057, -0.036457058, 1.8394060135, -0.8206712008, 0.560500443, + 0.3706909716, -0.8948367238, -0.1099870428, 0.9826195836, -1.8920612335, 0.835563004, 1.1913090944, -1.7892980576, + 0.8185464144, 1.1664609909, -0.6384063363, 1.4365177155, 1.8991087675, 1.448099494, 0.5353578925, -0.101493381, + 0.2317328602, -0.0489891469, 0.2788106799, -0.3530018032, 0.7007697225, 0.8251960874, 0.5446463823, -0.2403146476, + -0.2228565663, 0.6680720448, -0.9187930822, -0.0626189634, 0.3346115947, -0.0144286985, -0.9312236905, -0.1410451829, + -0.1779760569, -1.4948040247, -0.8491395712, -0.6012837887, -1.1472615004, -1.0493052006, 0.9051018953, -0.8528327942, + -0.8717535138, -0.8167239428, 2.2011229992, 0.5912480354, 0.7781169415, -0.888476789, -1.3819385767, -1.1633492708, + 1.293779254, 0.3712132275, 0.1289652586, 1.7088830471, -0.1212667525, 2.0375425816, 0.2414857298, 0.5944365263, + 0.6591821313, 1.2509437799, 0.8774040341, 0.0764976963, 1.6224048138, 0.2065740824, -0.8375450373, 0.3608026505, + -0.7311544418, 1.8801552057, -1.2250365019, 0.7259657383, 1.4483156204, -1.571040988, 0.8928659558, -0.1776217222, + 0.5828669071, -1.1092414856, 1.0693781376, 1.7471616268, -0.0638344735, -0.2843283713, 0.1209072024, 1.7735556364, + -1.4085712433, 1.3586884737, -1.7795503139, -0.5770805478, 1.8389601707, 1.5333522558, 2.2969801426, 0.6170276403, + 0.5831583142, 0.0016300381, -1.4345458746, -0.3312624991, 0.7281045914, -0.0612430722, 0.1704209596, -0.7399250865, + -0.9588273764, 1.4042122364, 2.0758225918, -0.75479424, 0.0572688095, -0.9924984574, 1.1447558403, 2.0738089085, + 0.4144458771, -0.4910028577, 0.8720424771, 2.1747357845, -0.3411389589, 1.1494208574, 0.3893336654, -0.2615806162, + -0.1336776763, 0.356644839, -0.1948368698, -1.1085442305, 0.045254115, -1.6467444897, -1.0986956358, -0.4581389427, + 0.9293973446, -0.944440484, 2.2482736111, -1.8937467337, -1.0940096378, -1.5336623192, 0.9742526412, -3.2672441006, + 0.5969296098, -0.422968328, 1.9410246611, 0.3461483121, -0.1929189414, 0.8508393764, -0.8942077756, -0.0658058375, + -0.9040490985, -1.6763790846, 1.9827840328, 0.4141021073, 0.7216985822, 0.3340985775, 0.4529460371, 0.3948349059, + -0.3916791081, -0.6501089931, -0.1761995107, -0.491057992, -0.951806128, 0.5322595835, -1.1581377983, -0.7828429937, + -0.8784741163, -0.7512039542, 0.2515104711, -0.7926872373, 0.9031017423, -0.6620030403, 0.2099865377, 0.1103555858, + -0.3409232199, 0.3346741498, -0.5610801578, -0.6902984977, 0.6454124451, 2.1148784161, -0.1916747689, -0.5036607981, + 1.3881807327, -1.2380584478, 1.7191636562, 0.3221949041, 1.5209794044, 0.3738695681, -0.7806591988, -0.4377743006, + -0.3996760845, 0.9527902007, -0.1983201355, 0.2340738177, -0.3172970414, 1.4159215689, 0.7529594898, 0.7795801163, + -0.2162986398, -0.1358234584, -0.961343646, -1.3732218742, 1.2092061043, 0.6537166238, 0.0339915529, 1.4929498434, + 1.3207374811, -0.7652394176, -1.0177652836, -0.6362911463, 1.2755696774, 0.0088382503, 1.0899994373, 1.2225722075, + 0.7833430767, 0.4043075442, 1.7909801006, -0.3479894698, 0.7831335664, -1.4179023504, -0.1100483984, 1.2900805473, + 0.2464116067, 0.9515271783, -0.3098686337, -0.3669249713, 0.0978010669, 0.8864583969, -0.1877962053, 0.5702041388, + -0.1159990877, -0.3501803577, 1.9029144049, 0.309999615, -0.5302504897, -0.6566003561, -0.468757093, 0.9224168062, + 2.4704847336, 0.0035063766, 1.6607170105, -1.1333860159, 0.1573023349, 0.1733097583, 0.3055340052, -0.1416791677, + 0.3056150079, -0.5185316205, -0.2780053914, 1.101534605, -0.9035406113, -0.4951810241, 0.8598588109, 1.0429813862, + 0.2664982677, -0.0298852306, 0.8533706069, 0.0039714552, 0.9565080404, -1.5921889544, -0.8913908601, 2.336435318, + -1.1469471455, 0.0677223578, -0.9267605543, -0.2041192949, 0.3063176572, 0.2214103341, 1.0146539211, -0.2558603883, + -1.3943849802, 0.1468503773, 1.3297446966, -0.8142588139, -0.2132356614, 2.4995143414, 0.0899943933, 0.0429980233, + -0.1537914723, -0.4266037941, 0.8056005836, 1.1891802549, 0.2974522412, -0.1454759538, 0.1457174271, -0.0381532684, + -1.4634613991, -1.3462141752, 0.0664003119, -0.7865975499, -0.9306924939, 0.3232910931, 1.3516124487, -1.3557263613, + -0.5764961243, 0.2937407792, 0.7960445285, 0.2003103644, 0.3335437179, 0.1145793125, -1.4473557472, -0.3551094532, + -1.2691313028, -0.1487769932, 0.1636830419, 0.9360257983, -0.7665287256, 0.584207952, 1.2309166193, -0.8302861452, + 1.6384637356, -1.6886717081, 0.7259944081, -0.9984105229, 1.080573082, -0.4680268466, -0.3358856142, -1.3471429348, + -2.3989200592, -0.8478084207, 0.1898977607, 0.7270219326, 1.8451247215, -1.4518831968, -0.1755070686, -1.7972141504, + -0.3209051192, -0.2535520792, -1.1991846561, -1.0366666317, -0.3719597459, -1.233545661, -1.3254798651, 1.1153312922, + -0.5936127305, -1.2354867458, 0.4393461049, 1.6991671324, 1.6203832626, -0.0244100485, -0.3054488301, 0.9963783026, + 0.5320534706, 1.1051325798, -0.360689044, 0.4809477031, -0.6204119921, 0.6224191785, -0.9839615822, -1.0425922871, + 0.8285560012, 0.6690504551, -0.5170633793, 0.1227343306, -0.5366504192, -0.4230706096, 0.4494740963, 0.0801548958, + 0.3285671473, -1.4552829266, -0.0545614995, 0.3951006234, 0.8749583364, 0.7818165421, -0.7438398004, -0.3983262479, + 0.0770372972, 0.1963945776, 0.9916386604, -1.0397281647, -2.11353302, 0.2499190867, 0.804877162, -0.0107534034, + 0.6105771065, -1.0989814997, -1.4957785606, 0.5590358973, -0.4976819456, 0.003873378, -3.1699786186, -0.5023010969, + -1.2277863026, 0.9048526287, -0.330719918, 0.3236357868, -0.3506893814, -1.8465671539, 0.2423798144, -0.8711999059, + 0.5552427173, -1.0252454281, -0.985183537, -1.0336141586, -0.3072377741, -0.3015651107, 0.93007195, -1.1634535789, + 1.5237438679, 0.4603967071, 0.9846302271, 0.7602651715, 1.2697321177, -0.3905704618, -1.4983217716, -1.4723336697, + -0.7304906845, -0.2598758936, 0.8250431418, 0.7544211149, 0.6444281936, -0.8383622766, 0.2967797518, 0.752312541, + -0.7764243484, 0.795860827, 1.2056927681, -0.9662641287, -0.9335420132, -0.1679661572, 0.2740947604, -1.5847927332, + -0.7598161101, 0.0663753822, 0.4885937572, 1.4334609509, 0.1223380715, 1.2751848698, -0.5594834089, 0.4535132945, + 1.4081346989, -0.4110103846, -0.4689775407, 0.1422861069, -0.0778675601, 0.6395888329, -0.5474281907, -0.1878197789, + -0.5766133666, -1.8732328415, -0.1212131009, -0.0612858348, -0.1527992487, 1.8027352095, 1.4275883436, 0.4526786506, + -0.0216174275, 0.7622801661, -0.1540553421, 0.4228228629, -1.2467342615, -0.5674841404, 1.2695670128, -0.830847621, + -1.9346109629, -0.5754521489, 0.2582443655, 1.0578256845, -0.426925987, -0.418731302, -0.5974100828, 0.7509816289, + 1.0372412205, 1.2170906067, -0.0723076239, -0.9454078078, -0.2535687983, -0.0566087402, -0.1577985138, 0.7568653226, + 1.4414137602, 0.4087726176, -1.5048319101, 0.4968555868, 1.2993911505, -0.9232976437, -0.4792942405, 0.6598887444, + 1.9238653183, 0.0458117649, 1.7594987154, -0.2377487421, 1.2578010559, 0.0903284103, -1.4757454395, -0.7747513652, + 0.1500543505, 0.5281760097, -1.5053366423, 1.370264411, -1.5342292786, -1.8576005697, -1.5551402569, -0.8589060307, + 2.2405879498, 1.4200407267, -0.2279152572, 1.5842866898, -0.5206685662, 0.5317901969, 0.8036642671, -1.558144927, + 0.5541169643, 0.3074723184, 1.3566111326, -0.699637413, -0.208823517, -0.2496134192, -1.282943368, 1.9111602306, + -0.0551519729, 2.0919880867, -0.678155005, 0.1923809499, -1.11281991, 0.3574016094, -0.1978608668, 0.6969423294, + 0.9032924175, 0.1589456499, -0.4350588024, -0.3512411118, -0.0519459359, 0.9904433489, 1.2984777689, 0.6284416914, + -1.1503527164, -1.1220369339, 0.3831738234, 1.0778528452, 0.3843923211, 0.4374722242, 0.7809922099, -0.02308679, + 0.9145608544, -0.5255103707, -0.8014039993, -0.5153968334, -0.8046190143, 0.9278858304, 0.6122110486, -1.8956546783, + -0.931854248, -0.4475701451, -1.408905983, 0.5044367313, 1.0466452837, -0.4882206023, 1.6315196753, -0.6935045719, + 3.4683833122, 0.6756458282, 0.4363811016, -0.0252611358, 0.7786549926, -1.3182072639, 0.5751082301, 2.3058328629, + 1.3533002138, -1.3967939615, -0.3641127944, -1.0209269524, 0.2126713246, 0.4525144398, 0.2537213862, 0.1484848112, + -0.837780714, -0.3130927086, -2.0773918629, 0.8348540664, 0.4066103995, -1.7121460438, 0.4686309993, 0.9460710883, + 1.7069529295, -0.623393774, -0.8569788337, 0.0303167701, -0.575697124, 0.150044024, -0.2254502177, 0.5234786868, + 0.7500634193, -1.2132166624, 0.2510019243, 0.2570083737, 1.0357878208, -0.6433942318, 1.4982335567, -0.9077165723, + 1.4716104269, -1.7842148542, 1.1447430849, -0.6266376376, -2.2693505287, 0.3182332516, -1.0613924265, 0.6442693472, + -0.5000963807, -2.045258522, 1.4310381413, 1.8100054264, -0.6701334715, 1.5482307673, -0.5137092471, 0.5081887245, + -1.3406304121, 1.3682693243, 1.2737818956, -0.3865059316, -0.478069067, 0.7779576182, -1.7476885319, -1.100882411, + 0.0263148081, 1.8815983534, 0.3323176205, 0.2674674392, -1.3087997437, 2.1118044853, 0.2675665617, -0.4922035635, + 1.7720580101, -0.7110042572, 0.1589149386, -0.4881309569, -1.5783791542, -0.0925537944, 0.5986972451, -2.1295366287, + 1.7461127043, -0.9785813689, 0.3955598176, 0.676484406, -0.9934566617, 0.7253823876, 2.691798687, -0.5455944538, + 0.4043146968, 0.3411338329, -0.3855164051, 1.6743670702, 0.5616671443, 1.5067958832, 0.2787322402, 0.8779776096, + -1.8535884619, -1.311909914, -1.4514750242, -0.3689820766, -0.6068240404, -2.3265423775, -0.2324558496, 1.0002081394, + -0.6160846949, 0.0170312542, -0.2363373041, 1.965331912, -0.2599737346, -1.2773052454, 0.4339766502, -0.6928628683, + -1.0053579807, -0.1896031797, 0.6886450052, -1.9172238111, 0.4927026331, 0.529641211, 0.2830281556, 2.3585255146, + 0.1015405208, 0.1898712814, -0.3793027103, 0.2264746577, -0.1147489175, -1.2718250751, 0.5322838426, -0.1509367973, + -1.0796653032, 0.2211570591, -1.6349580288, 0.7289609909, -0.0924888924, 1.2654665709, -0.7704129219, 0.3740957081, + -0.6158271432, -0.6735936403, -0.7281390429, -0.1193343252, 0.7776176333, 0.4423677027, 1.3741822243, -0.4074907601, + -0.1957744956, 0.4908902943, -0.7967771888, -1.5564359426, 0.6080636978, 1.1600704193, -0.3984555602, -0.1730147898, + 2.0433011055, 0.9244021177, 1.0907392502, -0.1569561809, -0.9651011229, -1.516418457, -0.0046005156, 1.851148963, + 2.0630350113, -1.8583544493, 1.292291522, -1.0781641006, 0.3176600039, -1.4096624851, -0.6563232541, -0.111763373, + 0.6297587752, 1.2154203653, 0.2888377905, 0.7956738472, 0.3510543406, -1.1075544357, 2.0214886665, 0.991620481, + 0.56470263, 0.5993618965, 0.523104012, -0.8116585612, 0.6569921374, -1.8315339088, -0.6885490417, 0.3351188302, + -0.0013942909, 0.8267314434, -1.9799656868, -0.6828018427, 0.7968899012, -0.2808510363, 0.051260896, 0.1743437499, + -0.7116479874, -1.9787137508, 0.5628860593, -0.6114267111, -0.4011185169, -0.2396005392, 1.0169463158, -0.809130013, + -1.1353332996, 0.0133572351, 1.0202590227, 0.2226665467, 1.1409810781, -1.5810728073, -0.3684642911, -0.1554839909, + -2.3100559711, 1.0542657375, 1.6269677877, -1.7038469315, -1.2879344225, 1.0403683186, 2.2401287556, 0.1703069061, + -0.5179620385, 1.0845952034, 0.4455762208, 0.2167074829, -0.4839757085, 0.9151929021, -0.511167109, -1.0387377739, + 0.8055750728, -0.507674396, 0.0328205563, -1.5801910162, -0.4398359656, -1.1315128803, 0.2544636726, -0.6623916626, + -1.1471446753, 0.2642677724, -0.1311631501, 0.1489771158, 0.8975483775, -0.2278074473, 0.1106519401, -0.4545907676, + 0.0902820975, -0.392390579, -0.797611773, -0.0126832854, -0.3523421884, -0.1040960327, -0.2254287302, -0.4944473207, + 0.5934621096, 1.1226073503, -2.1177215576, 0.6347402334, 0.1774308234, 0.1942605078, -0.0195572022, -0.1038614362, + -1.2880922556, -1.8354381323, -1.01529634, -1.4097815752, 1.7686097622, 0.6368556619, -0.1358798593, 0.7228752971, + -0.9184829593, 0.202624023, -1.6902302504, -0.7515771389, -1.4603588581, 0.1438691318, -2.3376917839, 0.8028458357, + -1.7040096521, 0.8609021902, 1.7478538752, -1.3853265047, -1.2477948666, -0.5389990807, 0.7780463696, 1.2358132601, + -0.9333853126, -0.4348754883, -1.2053111792, 0.2426356375, 1.0397968292, -1.2316269875, 0.6959838867, -1.754422307, + -0.646422267, -0.4856535196, -0.3731232882, -2.0051338673, 0.2533751428, -1.3090395927, 0.8500843644, 0.5513440371, + 1.5281857252, 0.9997274876, 0.7820481658, -0.4565566182, -1.1126084328, 0.5382915139, -1.1646991968, 0.3164305091, + -2.3938493729, -1.0044484138, 0.4640351832, -1.2155511379, 0.1764370948, -0.817288518, -1.2739762068, -1.3600958586, + 0.8626067638, -0.9916674495, -1.2624299526, 0.9874475598, -0.214572832, -0.508277297, -1.6458400488, -0.3702574968, + -0.9768534303, 0.2904407978, 1.325553298, 1.210021019, 0.1227659956, 0.2595930994, -0.4679057598, 0.4274121821, + -1.3154900074, 0.1236572117, -0.985479176, 0.5440257788, -0.5402190685, -1.1039479971, -0.9907112122, -1.3060643673, + -0.5652656555, 0.9776216745, 0.2473392487, 0.8499594331, 0.7057187557, -1.3080376387, 1.0187844038, -0.0227408782, + 0.608821094, -0.6433678865, 0.6544898748, 0.9204548597, -2.713709116, 0.7325530052, 0.0752336457, 0.8366841078, + 0.927908659, -1.1596821547, 0.3568362594, -0.219685033, -0.2727072835, 0.5928372145, -0.177185297, -0.2883036137, + 1.1079210043, -1.0769922733, 0.4753883481, 0.3450099528, -0.3523810506, 1.4889559746, -0.2710278332, 0.2396248132, + 0.6586426497, 1.048238039, 0.3379995525, -0.4739660025, 1.6513723135, -0.8296175599, -1.3067449331, -0.6117827892, + -1.7295495272, -0.9451754689, -0.6887831688, 0.4632112086, 0.0821003988, -1.1309273243, -0.1603619158, -0.595031023, + 0.3923758268, -1.5252598524, 0.4210940599, -1.5164136887, -1.2393224239, -1.7814563513, -0.2897252738, -2.1949856281, + 2.8120102882, -0.8257092834, 0.1937599629, 1.0681219101, -0.8102371693, 1.1713981628, 0.3316555321, -1.2564464808, + -1.2102553844, -1.8110905886, -0.3118630052, -0.6994720697, -1.5547536612, 2.2070877552, -0.5162882209, 1.3778606653, + -0.789868474, 0.2299599946, 0.1487733722, -0.8022645116, 0.5625656247, -0.8308770061, -1.2218902111, 0.7719486356, + 1.6793210506, 0.6410716176, 0.5552347302, -0.6866862774, -2.3685967922, -0.5928680897, -1.276099205, -2.5390007496, + 1.2587535381, 0.4895009398, 0.1038385183, 0.5110086799, 0.338168323, 0.7548806071, 0.1276102215, 0.6869242191, + 1.2325774431, -0.6868656874, -0.8387863636, -0.8901911378, -0.8299873471, 0.6570521593, -0.8497098088, -1.9196294546, + 0.1074195951, 0.9909681082, 1.0813125372, 1.2957479954, 0.7512951493, 0.6021413803, -1.1488620043, 0.6352616549, + 0.0198759958, 0.9322074652, -1.4032728672, -0.5972887278, -1.1572170258, -0.1391252577, -0.0026114394, -1.2078139782, + -0.6075099111, -0.1559657305, 1.2921199799, -0.6285111904, -0.5723410845, -0.0440929458, 2.2640471458, 1.1017858982, + 0.1785074621, -0.4585222602, -1.4878432751, -0.4616599381, 2.7842957973, -0.8562133312, -0.8348052502, 0.5125629306, + -1.6848424673, 1.6984417439, 0.4297846258, 0.6659538746, -1.0364086628, -0.8324087262, 0.2216985375, 0.5052349567, + -0.4887041748, -0.1160030439, 0.7263070941, 1.2204111814, 0.1790825576, 1.0658636093, 0.2977754474, -0.5876668096, + -0.7762431502, -0.5158827305, 0.2565769553, 0.880949378, 0.8431380987, -0.4027089179, -0.1782636046, -0.1587935835, + 1.3338432312, -1.4606239796, -2.0378668308, -0.1473344862, 1.1285791397, -0.4220150411, 1.2866398096, -0.2262062728, + -0.6299557686, -0.7837253809, 0.7857016325, -0.2874922752, -0.7144582868, -1.5693187714, 0.4702760875, 1.3465423584, + 1.0922623873, 0.329234302, -0.3397429287, -1.1707133055, -0.8345708847, 0.1053590998, -0.9551098943, -0.0158422422, + -0.6733519435, 0.5780305862, 0.7031232715, -0.0393282436, -0.9383910894, 0.3805969954, 0.7196177244, 0.2210744172, + 0.5715443492, 0.2615196705, 1.4784181118, -0.0361505449, -0.9886692762, -2.5481803417, 1.3661826849, -0.3472016156, + -1.6215758324, -2.004281044, 0.220134452, -0.1717495918, 0.6369396448, 1.3920063972, 1.8210952282, -0.6172340512, + 0.1448362023, -0.4834059179, 1.1414402723, 1.8423522711, 1.4584639072, 2.5065975189, -0.4695457816, -0.2602095008, + -0.5626283288, 1.950440526, 0.4526340365, 0.4930631518, 0.6368220448, -0.7115779519, 0.914337337, 1.0674004555, + -1.4705325365, -0.1610876769, 0.0818736106, 0.149876833, 1.6491193771, 0.0072635375, 0.7203763723, 1.1762765646, + 0.2638449371, 1.9991233349, 1.0177111626, 0.3286144733, -1.2706656456, -0.1446818113, 1.7641743422, 0.8927143812, + 0.4896416962, -0.9942132235, 0.9834810495, 0.1882795244, 0.7997056246, -0.6269438267, -0.7839465141, -0.7389545441, + 0.7751408219, 0.7793362141, 0.5096878409, 0.231401369, -1.4001361132, -1.2783879042, 0.3915791214, -1.6315677166, + 1.2537792921, -0.7252321839, 0.9186237454, -0.5066030622, 0.5364947319, 0.3846390545, -0.7608844638, -0.9879293442, + 1.053699851, 0.1239340007, -0.6024615765, 0.7722412348, 0.6044166684, -0.100312978, 0.7670496702, -0.5458506942, + -1.4519466162, 0.2771151066, 0.3518697321, 0.024952, 2.6057703495, -0.913711369, 0.5218591094, 0.0153903477, + 2.6444854736, 1.3167178631, 0.3327669799, 0.6593927741, 0.2390110046, -1.4895582199, 0.6340134144, -1.6390534639, + -1.2675498724, 1.0433050394, 1.2519178391, 0.3263645172, -0.1726632714, 0.5519032478, -0.1143158376, 0.2162200809, + 0.9341704249, 0.3033621013, -0.5463930368, 0.875366807, 1.3833848238, 0.8291720152, -1.2218199968, 0.5906565189, + -0.7905145288, -1.7524110079, 0.3663987815, 2.1609265804, 0.8671112657, -0.5826405287, 0.1804178357, 0.6935610771, + -0.6312169433, -0.2545692325, 0.1374749988, -1.4491913319, -0.0883082896, -0.0105298012, -1.2318902016, -0.828985393, + -0.3602082729, -0.8703395128, -0.7262350917, -0.6620940566, 0.6471897364, 0.0936652049, -1.3356847763, -1.9162960052, + -0.1310082227, 0.8927040696, -1.8789820671, -0.6941149831, -0.8801056743, -2.4179081917, -0.351030916, 1.0250413418, + -2.0253155231, -0.2171654552, -0.6943956614, 0.4614755809, -0.2940581143, 1.0993890762, -0.4676396549, -1.0508223772, + 1.7287107706, -0.6683145165, -0.1298807859, 2.1324386597, 0.9666262865, 0.8443111181, -0.601377964, 0.7276886106, + 1.0302677155, -1.2724297047, 0.9751001, -0.117099002, -0.2573932111, 0.0356474034, -0.5298755169, -0.9047068954, + -0.1097842306, 0.8076342344, -0.3035034239, 0.7364196777, -0.1532740593, -1.5517117977, 1.3448683023, 0.9069454074, + -1.1535201073, -1.1836688519, 0.0531910323, -0.9787717462, -0.847715497, 1.5395288467, 0.1366031617, 1.1396311522, + 2.3474342823, -0.0828050002, 0.5587758422, -0.1701462269, 0.2563884556, 0.457657218, -0.5936612487, -0.0666432232, + -1.2495532036, -1.7759221792, -1.0503594875, 1.4247668982, 0.3914461732, 0.0761216953, 0.2842491865, 0.6038943529, + 1.293158412, -0.2688145936, 0.6839090586, -0.0863594636, 0.1521898508, -2.1591539383, 0.3447727859, -0.4143142998, + 0.3156183362, 0.1544964314, 1.3025699854, -0.0636318251, 0.6497617364, 0.5397651196, -0.2517716885, -0.9968451858, + 0.2427535653, -1.6707130671, 0.4256668091, 0.420152545, 1.6644111872, -0.1637274027, -1.0096265078, -0.7501395345, + 0.3889355659, -0.3280121088, 0.068355523, -0.2293541282, 0.0059699183, -1.2834771872, -1.471981287, 1.0352134705, + -0.149098292, 0.2533560693, -1.1749132872, 0.502871573, -0.2666368186, 0.7678294182, 0.5390011072, 0.1143793166, + 0.0369447507, -2.1100959778, -0.1035841182, 0.1734765768, -0.5206263065, -1.5388579369, 0.2944219708, -0.5542598367, + 0.3960934281, -0.5660918951, -0.5781425238, -0.4664564431, 0.0804147124, 0.4390437007, -0.0616029091, 0.700306654, + 0.6478360295, -0.2125269622, 0.9341881275, -0.9784104824, 0.4180209339, -0.6914352179, 0.7919614911, -1.1545484066, + -0.0029162788, 0.8164563775, -2.1450593472, -0.7141282558, -0.1273373812, 0.9063172936, 0.7292864323, -1.4445300102, + -0.5211780071, 0.7087510228, 1.8131198883, -1.2041488886, 1.4940724373, -1.3090559244, 1.7167582512, -1.7583614588, + 0.3108649254, -1.5711164474, -0.6901423931, -1.0158981085, 0.4401728809, 1.6992042065, 1.7186495066, 0.5683168769, + 0.7231294513, 0.0740922242, -0.3422453701, -0.4967070222, 0.7054743171, 1.3211479187, 0.2724389136, 0.6408790946, + -0.9621573091, -0.3153292537, -1.3749207258, 0.6791490316, -0.79407686, -1.0095255375, -1.3924701214, -0.2026451379, + 0.0677531809, -0.1508983523, 0.541418314, 0.7144338489, -0.6705932021, -1.3298588991, -1.3412828445, -0.5634455681, + -0.2916662991, 0.7729437947, 1.5142472982, -0.0278050378, -0.5018460751, 0.6177078485, 0.0424504094, 0.2765903771, + 0.6403551698, -0.5025407672, 0.5923534632, 0.6478619576, -1.5444386005, -1.2579747438, 1.2809257507, 0.6353840828, + 0.4131743014, 0.3158742487, 1.1801162958, -0.4564170837, 0.4091522694, -1.4798978567, 1.2729399204, -0.8004751205, + -0.4432139397, 0.3686844409, 0.7507426739, 0.9426909089, 1.64927423, -1.5455055237, -1.2340234518, -0.9009966254, + -1.2735397816, -0.061548464, 1.8640985489, -0.3493136168, 0.2173888832, -2.4374730587, -0.038372878, -0.2510394156, + -0.7139562964, 0.8909270167, 1.336673975, -0.0830413997, 2.5130395889, 0.0980813131, -0.8486409783, 0.4998627305, + -0.4094617665, 0.5458596945, -0.4862162173, -2.0455002785, 1.0393195152, 0.1168493107, -1.716588378, -1.1070877314, + 0.2518376708, -1.2448687553, 0.5589826107, 1.7770667076, -1.5959331989, 1.5407427549, -0.5897306204, -1.8142468929, + 0.169819653, -0.1295103729, 0.5277545452, 0.2446128577, -0.3235076964, 1.2561858892, 0.7550396919, 0.1513881832, + -0.4214838743, 0.8148363829, 1.4301729202, 0.1300896555, 0.4603887796, -0.8699390888, -0.0237311311, -1.1238359213, + 0.137733534, 0.244179368, -1.7290854454, -0.4972402155, 1.3003982306, -0.5680015087, 0.5945675373, 0.7442512512, + -0.2569022775, -0.9850519896, 0.2363358736, 0.3354244232, -2.0168704987, 0.6541719437, 0.1009543091, 0.0797480121, + 1.6220499277, 1.1278858185, 1.5643399954, 1.7326484919, 0.0972388163, -0.0682537928, 0.5457283258, -1.9053533077, + 1.7635300159, -1.5515018702, -1.2203807831, -0.1801347584, -2.6934776306, 0.1715345532, 0.6029487848, 0.057303831, + 2.35734272, -0.2083336562, -0.4516532719, -0.2417075187, 0.4663243592, -0.6326389909, 0.1208775267, 0.2149387449, + 1.3439264297, 1.2751500607, -0.4505316317, -0.5756392479, 1.4063438177, -1.4878020287, -0.5038126111, 0.984023571, + -1.084431529, -0.2784172595, 0.4415511191, -0.1162850186, 0.175782159, 0.741142571, -0.366881907, -0.7205744386, + -0.5024018884, 0.2062256783, 0.724178195, 1.5902775526, 0.0932773799, -0.6890472174, -1.9990137815, -0.4262224734, + -1.1738171577, 1.1300529242, 0.4181618392, -2.3131039143, 0.5922805667, -0.3001381159, 1.7097831964, -1.1595673561, + -2.1293334961, -0.3307192922, 1.2602394819, -0.710981667, 1.7607816458, -0.6528120637, 1.6467469931, -0.9482585788, + -0.8347230554, -0.6540571451, -0.3115817606, -1.6141192913, -1.0731090307, 0.0426733084, -1.099894762, 1.048972249, + 1.4080376625, -0.3871131837, 0.2852624655, 1.3540599346, 0.5000309348, -0.0193734169, 1.1629503965, 1.7707066536, + -0.7773700953, 0.8161155581, -0.6074299812, 1.9348500967, -0.7318091393, 0.9646677375, 0.4912351668, 0.5005277395, + -0.1886811703, 0.6468701959, -0.6115835905, -1.4020545483, -0.2524648607, 0.0008449311, -0.3852461576, 0.2591911256, + -0.2682701349, -1.5723091364, 0.3320451081, 3.2006881237, 0.6155536175, 0.8023455739, 0.1190806627, 0.1179326773, + -0.0133221503, -0.1462981254, 0.0558719449, 0.0060142102, 0.7527711987, 0.232440576, 0.5915004611, -1.0211442709, + 0.1468193084, 0.9947727323, -0.1153474972, -2.2038846016, -0.3664562106, 0.83005476, 0.7540668845, -1.2107092142, + 0.2661699057, 1.3505961895, 1.9395216703, -0.1923337281, -0.5798934102, 1.1088138819, -0.5727385283, 0.6018813848, + 1.7457513809, -0.7539621592, 0.339260757, -1.8162858486, 0.4703977704, -1.6360388994, 0.518032074, 0.3072411418, + -0.3721626103, 1.7841976881, 1.7781287432, 0.7256065607, -0.5469256043, -1.1149164438, -1.201035738, -0.0934013724, + -0.4959301949, -0.2157954574, -2.6348752975, -0.7417191863, -0.50418365, -1.9211819172, -0.4793742895, -1.3138118982, + -0.6303048134, -0.8648637533, -1.5271095037, 1.2077393532, 1.3537611961, -1.0298615694, 0.2516765296, -1.185784936, + -1.275901556, -0.1323886216, 0.0077520325, -1.1594430208, 0.1734642833, -0.8420557976, -0.1126872674, -0.4606709182, + -1.1694540977, 2.2664411068, 0.4393515587, 0.8670080304, -0.6363406777, 1.0128105879, 0.5352993011, 1.2980554104, + -0.3366172612, 0.7446729541, 0.0706164017, 0.5329166055, 1.5777875185, -0.7912862301, -2.4273786545, -0.0999521613, + 0.440131247, -0.2123771459, -0.8119220734, -1.1485599279, -0.4177002013, -0.1898192316, -1.5691518784, 0.7123882771, + -0.4033349156, 0.1992595643, -1.0107963085, -0.7487183809, -0.3474726081, 0.5490239859, -1.311727047, 0.4529985487, + 1.2649879456, -1.3282953501, 2.2694823742, -1.9726030827, -0.1417467296, 2.0489106178, 0.6848044991, -1.1864144802, + 0.0095336009, 0.5513510108, 0.4967232049, -0.5022209287, 0.7636085153, 0.7493492961, 0.9887427092, 1.0534604788, + -0.5208474398, 1.5930726528, 1.1946299076, -1.1940947771, -0.6941130757, -0.2753409147, 0.3418467939, -0.3992665112, + 0.014435743, -0.1594496369, -0.4563882053, 1.4027935266, 0.241143927, 0.0072475886, -0.8765354753, 0.4561424851, + -0.0980236828, -1.0085912943, -1.3533272743, -0.8581139445, 0.8061968088, -1.0639472008, -0.1058177575, 0.4276168644, + -0.8239603639, 1.8089847565, -1.5798636675, -0.0302213319, -0.3193961382, 0.5277996659, -1.4658607244, 0.5939242244, + -0.8696262836, 0.3683566749, 0.4510522187, 0.5968563557, -1.1456565857, -0.0630941987, -0.072509028, -0.6521866322, + 1.9407103062, -1.9997001886, -0.4733425677, -0.6821983457, -2.0067911148, -0.1969090551, 0.0117811309, 0.8634021282, + 0.5490431786, 0.503625989, 0.8777194619, -0.5009964108, -0.2476846427, 0.7691996694, -0.4389582276, 0.7626179457, + -0.9946994185, -0.9002199769, -0.2358198315, 0.5558941364, -0.5835582614, 0.0424835086, 0.5476747155, 0.4497909844, + 2.0062038898, 0.5630492568, -0.4302353561, -0.3927549124, 0.6127817035, -0.3549419045, -0.0465914086, 0.7972400188, + -0.0291995928, -0.1873065531, -0.2666181028, -0.5908914208, 0.4490607083, 0.4655361474, 1.3770449162, 0.3744198084, + 2.0639455318, -0.5035088062, 2.2640516758, 0.8200385571, 0.376224637, 0.1349862367, -0.7485954762, -0.691967845, + -1.5081450939, -0.8550764918, -0.334677875, -0.2704392374, 0.7448489666, 0.6368254423, 1.1909401417, -0.3652415872, + 0.0266696922, 0.185702309, -2.1289024353, -0.0612011552, -0.1647111028, 1.5982892513, 0.3783888221, -0.8879693747, + 0.1596832424, 0.9702088833, -0.4322770238, 0.7622994184, -0.9912603498, -0.0206081625, -1.8675857782, 1.329731822, + -0.2855650485, 0.4054629803, -0.6809203625, -0.5133872032, -1.8930710554, -0.0781741962, -0.4591271281, 1.4383069277, + 0.9537320733, -0.909866035, -0.5606174469, -1.12906003, 1.025395751, -1.3523454666, 0.3395365477, 0.7096471786, + -0.4674813449, -1.6451238394, 0.8107517362, 1.7173854113, -0.055368796, 0.3889346719, -1.2086811066, -0.0176033434, + 1.2727808952, -2.3618505001, -0.0911023468, -0.6099271774, 1.4351190329, -0.2916943431, 0.2546273768, 1.4699568748, + -0.0347926132, 1.3543151617, 0.0582686812, 0.7119902968, 1.3041653633, -0.2682042718, -0.38716501, 1.233336091, + -1.1758619547, -1.5743108988, 0.2008384019, 1.655849576, 1.3954097033, 0.2431987077, 0.6873512268, -1.5398448706, + -2.1012260914, -0.8874242306, 1.0868637562, -0.8933115005, -2.3817610741, -0.2322047204, 0.5744912624, 1.186404705, + 2.0981147289, -1.0142970085, -0.2725763023, 1.1405632496, -0.3188109994, -1.6895825863, -0.9098422527, -0.9992399812, + 0.2970742285, 0.4739212394, -0.3946261406, 0.9657480121, 0.171432212, -0.472579509, 0.0793206245, -1.2109538317, + -0.9714989066, -1.4903097153, 0.5481170416, -1.327421546, 0.1033664346, 0.3240928352, -0.0927641466, -0.7859684229, + -0.4100660086, 0.1349842697, -0.6123028398, -0.4821889997, -0.0113635045, -0.6305410862, -0.6447528601, 0.9588113427, + 2.0857424736, 1.6361919641, -0.0809310004, 0.4175556898, 0.5576475263, 1.154795289, -0.9088178873, -1.3321971893, + -0.6993666887, 0.8384341002, -0.0056715696, 0.0963145494, -2.0406420231, -0.5699337721, 0.210922718, 0.1758637279, + -0.1132779494, -0.1388639659, -0.567463398, -1.092774272, 0.4664836824, 1.3453660011, 0.9642984271, 0.1735391319, + -0.6066111326, -1.8372893333, 0.0989775285, -1.0595743656, -1.7484507561, 1.3843749762, 0.0083545428, 0.331114471, + -0.2330202758, -0.4341944754, -0.396922797, -0.7791808248, 1.1586873531, -0.7870743871, -1.3215303421, 0.5297895074, + -0.5042585731, -1.601397872, 0.6434103251, -1.1106889248, 1.0323313475, 0.0253233518, -0.5326119661, -0.7091501355, + 1.1146080494, 0.3246107399, 0.4328122735, 0.1061507687, 0.9968009591, -1.5700018406, 0.9111320972, -0.1880164742, + 0.0720187649, -0.1722674072, -1.2956403494, 0.1623233408, 0.9533376098, 0.8453432918, 1.0247024298, 0.8314163089, + 0.2169153392, -1.160556674, 0.6202650666, 0.7922874093, -1.1443600655, -0.1555470228, 0.2054934651, -0.0696882978, + 1.5672497749, -0.6392518878, 0.6004613042, 0.2808816433, 0.9697634578, 1.3994048834, -0.9369864464, -1.0598493814, + 0.6915630698, 0.0257297009, 0.5673299432, -1.9622377157, -0.7675710917, 0.3625481427, 0.7994940281, -0.0520695336, + 0.0688188747, 0.7390265465, 0.2610666752, -1.5965384245, 0.3458299041, -0.752130568, -1.320895195, 0.5133634806, + 0.6769243479, 0.8414777517, 1.7870870829, 0.5016800761, 0.6279888749, -0.0259170141, 0.0858539417, -0.114945516, + -0.991874814, 1.3966687918, 0.5319203734, 0.0872511491, 1.2238022089, -0.6457444429, 0.6148810387, -0.2943848968, + -0.7676346898, -1.9957956076, 0.0006206976, -0.4282977879, -0.3669142425, -0.2334992588, -0.181305334, 2.3843736649, + 0.0274813995, -0.2801706195, 0.0149513474, -0.2649163604, 0.2022246122, -0.38473171, -1.157615304, 1.6478676796, + 0.5820747018, -0.2079120427, -0.1404580623, 0.975066781, -0.6656797528, -1.051550746, -0.518140316, -0.072351411, + 0.924693644, 1.0558516979, -0.2617908716, 0.0100078853, 1.4384540319, -1.5206338167, 0.7696095109, -0.7830299139, + -0.6658165455, 0.8587329984, 0.0302361734, 0.7325266004, 0.6763762832, -0.9670042396, 0.543666482, -0.0928966329, + 0.272854805, 0.7476511598, 0.8182846308, 0.0401502326, 0.0703607574, 0.7100747228, -1.1809411049, 0.1525679231, + -1.4360591173, -0.9362903833, 0.6512863636, 2.5559821129, -0.4898336828, -0.5570479035, 0.3082244098, -0.1268011928, + -0.1690266579, 1.1079031229, 0.5577710867, 1.2079291344, 0.3057589829, 1.4704600573, -1.5299013853, -0.4372470081, + -0.1838792264, 0.4103325903, -0.0079925116, -1.4350907803, 3.0050628185, 1.9440249205, -0.5308479667, 0.767006278, + -0.1695310771, -0.493740052, -1.0065364838, -0.3335910738, 0.2164574564, 2.0567500591, 1.0385917425, -0.9172860384, + 0.1360678822, -1.4758296013, 0.2109170258, -0.6283934116, 0.4619432986, 1.2396088839, -1.2901101112, -0.4787948728, + -0.0482119285, -1.3737345934, 0.358761847, -0.1970571727, -1.1884554625, -0.3847505152, -0.4059247375, -0.8413720131, + -0.2346312255, -0.5250424743, -0.8797713518, -2.2436685562, -0.1204453632, -0.9047447443, 0.1623364985, -0.1249333546, + -0.4604585767, -0.1806154251, -1.5818452835, 0.7564077377, -0.3526729941, -0.5011270642, -0.4888699055, 0.2328237146, + -0.8190051317, -0.8744320869, -1.6677303314, 1.3656442165, 1.3829454184, -0.1329779178, 0.6396308541, -1.6524884701, + 0.8636744618, -0.6694845557, 0.8651663661, -0.9834919572, 0.988319993, -1.2616648674, 0.2136829346, -1.494803071, + -0.5576620698, -2.1199064255, -2.6051251888, 0.8021505475, 0.2092306316, 0.8647927046, -1.0634721518, -1.7716604471, + 0.1749333441, -1.3047918081, 0.8585357666, -0.0653507933, 0.811453104, -0.8026093245, -0.2348457277, -0.1972251832, + -0.173129186, -0.9763115644, -0.4425777495, 0.1876048744, 0.239018172, 0.5495560765, -0.4430482984, 0.5191142559, + 0.3313212991, -0.2732692659, -0.1305333972, -0.3552298546, -1.2423542738, -0.415468961, -0.5192009211, -1.0146884918, + 0.0872632042, 1.0132828951, 0.735514462, -0.8626582026, -0.903583765, -0.1659100503, -0.4304459989, 0.871001482, + 0.2093449235, 1.7577981949, -1.4495869875, 0.3389512897, 0.3277698159, -1.3833289146, -1.0309791565, 0.5938034654, + 0.338113308, -0.7506350279, 0.5864959955, 0.6818603873, 0.9190769792, -0.9943068027, 0.7560220361, -0.282307595, + 0.4619690776, -1.0569438934, -1.6896722317, 2.2968416214, 0.1863039136, -0.4671124518, -1.7164677382, -0.0640422776, + -0.9713795185, 0.9030221105, -1.0318793058, 0.702277422, -2.5937387943, 0.9347560406, -0.0407111496, -0.0842949972, + 2.1857056618, 0.812292099, -0.1597754359, -1.2797119617, -2.5321006775, -0.9836844802, -0.3681376874, 1.4671288729, + -2.6063854694, 0.1413185447, 1.1272912025, -0.3143338859, 0.2970275581, -0.9995012879, 0.3840419352, -0.8541126847, + 0.1262938529, 0.8874447942, 3.3216011524, -0.0434766375, -0.2402396351, -1.7334960699, -1.1922539473, 0.0395632051, + 0.3123318255, 1.5156829357, 0.1709397286, 0.408336699, -0.2023052424, 1.5522542, -0.4802343547, 1.696850419, + 1.4456083775, 0.2222046554, -1.3635166883, 0.4523965716, -0.1486860216, -1.3813056946, 0.2926163673, -1.4815069437, + 0.0460004359, 0.0685515702, 0.8657517433, -0.4926210642, 0.3616339266, 0.2384285331, -0.5062540174, 0.9793159366, + -0.3106910288, 1.4108459949, 1.4620524645, 0.2490852475, 1.367877841, -0.6981250644, 1.0042148829, 0.9979116917, + 0.4013634026, -0.5294713378, -0.9604782462, 0.7616765499, 1.0867910385, 2.4451165199, 0.5009768009, 0.5941057801, + 2.1568233967, -0.2864334583, -0.7203481793, 0.2201959938, 0.0211936776, 0.2499561757, -0.5913699269, 0.4207766056, + 0.5149331689, -2.2674925327, -1.3170949221, 0.0806484967, 1.6441719532, -1.6811925173, -0.7950924039, -0.5914666057, + -0.4738128781, 1.3944123983, -1.1955771446, -1.4249742031, 0.6435713768, -1.5451512337, -0.010147362, 2.2087171078, + -0.980080843, -1.4776380062, 0.7782774568, -0.7789295912, -0.0102034928, -0.0880911723, -0.484072715, 0.751457274, + 0.05499449, -2.4430112839, 2.1914079189, -1.0618168116, 1.4040321112, -0.2890518904, -1.8754194975, -0.4907815754, + -0.0630276427, -0.7582322359, -1.1303482056, -0.7832784057, -0.5160414577, 0.0700457245, 0.6622155905, 1.1924040318, + 1.4414311647, 0.6065171361, -0.4135439694, -0.1386700422, -1.0272814035, 0.4866032004, 0.1530758739, -0.3026266694, + 0.2846779227, 0.0424417257, 0.5401003361, -0.7115367651, 1.5831142664, -0.2675635815, -0.0213743374, -0.0043467307, + -1.564257741, 0.9680214524, -1.340877533, 0.148885712, 0.2985931039, -0.5775466561, -0.7951164246, -0.4007186294, + -0.5162972808, 0.4733025432, 0.2995747328, 0.8256702423, 1.2272002697, -0.0659088045, 0.4785670638, -1.1270323992, + -0.5993215442, -1.5867478848, 0.1878347248, -1.2973229885, 2.1392738819, -0.5237012506, 0.4061898589, 0.1321331561, + 0.1819093823, 0.3166199625, 0.1830487847, 1.1566855907, -0.9360304475, -0.1669008881, -0.519764185, 0.7517486811, + 0.0689731315, -0.3164053559, 0.2283985317, -0.4720411599, 0.3385706842, 0.4731729925, 0.4821418226, -0.7884815335, + 0.3731731176, -0.7758998275, 0.7502189875, 1.0179754496, -0.2132595032, -0.6256816387, 0.6563635468, -2.0351250172, + -1.6866027117, 0.7681083083, -1.0538374186, 0.0967316404, -1.3432598114, -0.2516896725, 1.445432663, 0.1537240297, + 0.7852683067, 0.1986494809, -0.2295962125, 0.3377442062, 0.9981122017, 0.7033475637, 0.8179015517, 2.8854703903, + 0.1449834108, 1.5653721094, -0.883020997, 0.2447814792, -1.6657313108, -1.0418515205, -0.091470629, -2.2588729858, + 0.2607210279, -0.69045645, -0.276691854, 0.4198768735, 0.66504848, 1.2362228632, 0.2318393737, -1.7664381266, + 0.220308125, -0.6439874768, 1.3943929672, -0.2212222815, 0.5396524668, -0.9326766729, -1.1483886242, -0.5559464097, + -2.1605238914, -1.5237659216, -0.8512112498, 1.4548479319, 1.4710714817, -0.0255904552, -0.0392868333, 0.8066657782, + 0.2605836093, -0.0717089623, -0.4921136498, -0.7088971138, 1.3106839657, -0.742718339, 0.5950650573, 0.4102731943, + -0.745036602, 1.244848609, 0.8819051385, 1.2929413319, 0.754378438, 1.501247406, 0.5012357831, 1.6025744677, + -0.1244885102, -0.7437287569, 0.7625656128, 1.5684475899, -0.8715553284, 1.5655452013, -0.4011086524, 0.3054696023, + 1.0253591537, -0.67089957, 0.3336648345, -0.7808531523, 0.2032589763, 0.4629889429, 0.8305130005, 1.3792150021, + 1.066606164, -0.5386751294, 1.8384336233, 1.6489225626, -0.5408121943, 1.1491128206, 0.3872258961, 0.7378184795, + 0.5292190313, 0.1566731632, -0.8639983535, -0.4543217719, -1.1172450781, -0.1373617202, 0.0493386127, -0.6242133379, + -0.0747201517, -0.0418696329, 0.1286173165, -0.2732076347, -1.2780323029, 0.0635503307, -0.4641813934, -0.2046342939, + -1.7704610825, -0.6292266846, -1.5954760313, -0.6125565171, 1.3553122282, -0.6214655042, 0.3244607449, -0.1392270476, + -1.789331913, -1.6337937117, 1.2505484819, -0.3817860782, 1.0203552246, -1.7707964182, 1.5794938803, 0.9360316396, + 0.6239099503, -0.5742901564, 0.3519190848, 1.6146284342, 0.4477892816, -0.3142979741, 0.4781792164, 0.6606804729, + -0.0335218385, -0.5427355766, -2.5328576565, 2.1415202618, -1.8951349258, -0.2973324358, 1.1050219536, 1.279461503, + -1.4703121185, -0.4997144043, -1.1340399981, 0.5188848376, 1.5461864471, 0.6832302809, -1.0181527138, -1.8280473948, + 0.057066042, 0.2686289847, -1.2347159386, 0.6066080928, 0.8530008197, 0.356842339, -0.3545398414, 0.3357949257, + -1.1221921444, 0.1614009887, -1.2751108408, 0.1513240039, 0.6052228808, -0.0645731688, 0.3507217765, -0.3744005859, + -2.7758972645, -1.1287082434, -0.0116145117, 1.3980032206, -0.0176374651, -0.1791180372, -0.4948559999, -0.4348399043, + 0.9603962302, -0.9801307917, -0.6622002721, -0.0265429523, 1.6936491728, -0.0890061557, -0.1063767895, -0.6456767321, + -0.6210477948, -2.4629504681, 0.5300250649, -1.1274645329, 0.1202629134, 0.7539504766, -1.6694158316, 0.8432223797, + -0.6346231103, 0.5511178374, -1.6847029924, -0.3897745609, -0.1799215525, -0.3502997756, 0.7974809408, 0.7187066674, + 0.5191764832, -0.1159625053, 0.9157214761, -2.1128296852, 0.5010185242, -0.4072211087, -1.276581645, 1.9876989126, + 1.3443856239, 0.2349775285, 0.6620453, 1.3393974304, -1.2028733492, -1.1018798351, -0.2779258788, -0.5651109219, + 0.4557473958, 0.4294156134, 0.3529987633, 0.726452291, 1.4002771378, -1.0009080172, 0.0965322256, 0.9219058752, + 0.3410715461, -0.7426944971, -1.0091520548, 1.4181830883, 1.5620485544, 0.485283196, 0.4569746554, -1.5205644369, + 0.860696435, -0.0159703139, -0.1952470392, -1.7966439724, 1.21963799, -0.256810993, 0.149361074, 0.1471642554, + -0.1334927678, -0.0951507837, 0.8027544022, 1.8461946249, 0.5527061224, 1.3992179632, -0.4277961552, 1.2142347097, + 0.0890079811, 1.1724892855, 0.8421200514, -2.053129673, -0.3815230131, -1.2456768751, -0.2631421089, 0.3498506546, + 3.3013672829, -0.3395608068, 0.9844453931, 0.7795133591, -0.3801021874, 0.4742499292, -0.5515266657, 0.3347168565, + 0.4604980946, 0.8324033022, -0.0461973809, -0.1935420334, -1.0834821463, -0.5094074011, 1.4313070774, 1.1016554832, + -0.2138853818, 0.4686948061, 1.3630285263, -0.5100106001, -0.1556339264, 0.3429749906, -0.3238503933, -1.0426410437, + 0.1445600837, 0.1049434692, -0.2222164124, 0.4424103796, -0.1254242659, 0.5358566642, 1.5508053303, 0.6763385534, + 0.6407976747, 0.1865347624, -1.2624466419, -0.4919446707, 1.0839577913, 0.8675064445, 0.2160370052, 1.4639556408, + 1.1394736767, -0.7107564807, 0.0310300067, 0.4451051354, 1.2646448612, 0.6961842179, 0.395250231, 0.8698752522, + -0.8570802212, 0.2444748431, -0.3380377889, -0.3063204885, -0.6506505609, 1.0126060247, -1.2486658096, -0.4531163275, + 1.386549592, 0.840034306, 0.8887103796, 0.1331875622, -0.4949502647, 0.290930599, 1.3711076975, -4.4466323853, + -0.3461068869, -0.4214496017, -0.319110781, 1.432110548, 0.5082851648, -0.4887852967, -0.2842614055, -0.4167383611, + -0.5153347254, 0.1215999797, -0.9909867048, 0.2912752628, -0.030949058, 0.0686672628, 0.3116374612, -0.9446466565, + -1.4318141937, -2.3070585728, 0.1934504807, 0.0642832592, 1.6173255444, -1.4001069069, 0.9930692315, 0.49861601, + -2.1691753864, 0.3272755146, -0.5290307999, 0.3029612601, 0.7106252313, -0.5628217459, 0.3532442451, -1.2171857357, + 1.0224491358, 0.0653357655, 1.4942281246, -0.9784055352, 0.960270822, -0.266505748, 0.4682205617, -0.6420611143, + -0.7896304131, -0.2709776163, 0.8798081875, -0.2442070842, 0.1087937206, -0.3002286255, -0.5277259946, 0.414010644, + -0.2964256108, 1.4545035362, 0.4128693938, -0.8971816301, 1.0674988031, 0.1346273124, -1.000229001, -1.5374671221, + -3.4322154522, -2.1081695557, 1.6781947613, 0.0430080853, -0.2318437546, 0.4126449823, 1.426405549, -0.5483173728, + 1.1825624704, 0.0128414826, 0.3367869854, -1.4143692255, 0.1019542515, -1.7843068838, 0.2959744334, 0.6726202965, + -0.426615119, 0.1067341939, 0.2738974392, -1.5534147024, -0.8846866488, 0.4381192923, 0.8158077002, -0.065257661, + -1.3206679821, 0.6635075212, 2.6380484104, -0.6187989116, -1.0136746168, 1.8584141731, 0.6533104777, -0.4259442091, + -0.1774014086, 1.4402084351, -0.1898958385, -1.1205271482, -0.5485401154, 0.1698873043, 0.0687155649, 0.0311105829, + 0.3088907599, 0.3787349463, 0.380939275, 0.0914585218, -1.4571095705, 0.9450003505, -0.7444524765, -0.7551084161, + 0.9248359203, -0.2947985828, 0.9806703329, 0.6765164137, -0.4960588217, 0.8475109935, 0.7173162103, 0.7837095261, + 0.4317607582, 1.0102860928, 2.103208065, 0.1576048732, 0.0173003376, 0.7079991102, 0.6061809063, -0.6047534943, + -0.1859838217, -0.9648866057, 0.360276252, 1.5325679779, 0.0651429519, 1.0650039911, 2.5460152626, -0.673099041, + 0.2153566033, 0.9968594313, -0.4184798002, 0.3913473785, 0.2801388502, -0.1887837499, 1.6170681715, 0.3825345039, + -1.9914906025, 0.4941851795, -0.1115392447, 0.082419008, 0.2398149073, 0.743939817, 0.2233340293, -0.7043433785, + 2.8407576084, 0.3171818852, -0.0780908912, 1.0117206573, -1.3970212936, 0.2704565227, 1.1053961515, -0.8552007079, + 0.199479267, -0.7967630029, -1.7464600801, -1.4587714672, -0.9694950581, 0.4347965121, 0.7123994231, 2.5555636883, + 0.2164577097, 0.4949950576, 0.8548553586, 0.5338478088, 1.8773450851, 1.8840982914, -0.6057417393, -0.2921206653, + 0.3764616251, -0.8626120687, 0.6312596798, 0.1972151399, 0.8950186372, 2.143253088, -0.5009615421, -0.0870208442, + 0.2992241681, 0.1273721606, -0.5634948611, 0.887797296, -2.2128298283, 0.4280473888, -0.2503516078, -0.0595523603, + -0.0990573093, -1.3535153866, -1.0699493885, 0.960031569, 0.3506530225, -0.0972179323, 0.6288717389, -1.3509629965, + 0.1111599132, 0.2762899995, 0.810814321, -0.1749507338, 0.6180928946, 0.0537807047, 0.4083303213, 0.7938087583, + 1.3735338449, 0.1129539311, 0.7087584138, 0.2543578446, -0.7406477928, 1.1616770029, -0.4258893132, 0.5054414868, + -0.4079273939, -0.8973106742, 1.5773397684, 0.0967438072, 2.5411305428, 1.1561323404, -0.3894842565, -1.9563227892, + -0.3720968068, -0.4485727549, 1.4407653809, 2.2971429825, -0.1074938774, -0.1706637144, 0.2393594086, -1.2897298336, + -0.2838257849, 1.436694026, 0.5021362901, -1.3120448589, 1.336271286, -0.934920311, -0.1795876771, 0.2796979547, + 0.3275337815, -1.5682973862, -0.1581210196, -0.4314252436, 0.5257216692, 0.5361158252, 0.9633139372, 0.0385950543, + -0.2250328809, 0.039497681, -0.6151430607, -0.4402093291, -1.7778775692, -1.0987372398, -1.1117931604, -1.4587020874, + -0.5599415898, -0.8956044912, 0.501793921, -0.3279520869, 0.1389401406, 0.3314218521, 0.9030095935, -1.1500355005, + -1.9140057564, -0.4541152418, 1.1774168015, 0.3544850051, 1.1513677835, -1.0737146139, -0.2920063734, -1.4028655291, + 1.5057044029, 0.3650828898, -0.8197543621, -0.6998680234, 0.3804240525, 0.4712976813, 0.5005731583, 0.2035487741, + 0.9716621041, 0.5432396531, 1.3573894501, -1.0096626282, 1.6208111048, -0.5277240276, 0.8372216225, 1.8990112543, + 0.0555527322, -0.7414680123, -1.0119155645, -0.1866538525, 0.8219956756, 0.2626342177, -0.0517387129, 1.0967673063, + 0.4631964564, -2.2763576508, -0.9005764127, 0.4502929151, 1.2675552368, 1.4029026031, 0.0410192646, 0.4613499939, + 0.8826645017, -1.818628788, -0.7178622484, -0.1207559109, 1.4767705202, -0.0755815879, 0.7688866854, 0.4810449481, + 0.6946743131, -1.5904605389, -0.7692117095, -1.4830653667, -2.5812559128, -0.9567979574, -1.4820371866, -0.6474533081, + -0.4920964837, 0.666706264, -0.0434637107, -0.4990424216, 1.0992600918, 0.7525292039, -1.6032221317, 0.5581198335, + 1.3076291084, -1.6271916628, -0.9884853959, -0.3797832131, -1.3973912001, -0.3615023196, -1.9054090977, -1.2950693369, + -0.2564415634, -0.4667300582, -1.2958893776, -0.5529566407, 0.0508099534, -0.528875351, -0.705581665, 1.2113600969, + 0.3943111897, 0.238728255, -1.2374818325, 0.2701815963, -0.3978709877, -1.1572402716, 3.0878937244, 0.8014529943, + 1.8457676172, -0.0689089596, 0.9194198847, 2.2617175579, 0.6498615742, -0.7515003085, -1.0202875137, -0.3537638783, + 0.3832994401, 3.360458374, 1.007174015, -1.1935818195, 0.2676483095, 0.3094398081, 1.2086896896, -1.2866652012, + 0.7168079019, 0.2362437248, -0.576528132, 0.7539612055, 1.216250658, 0.2970718741, -1.2590700388, -1.1305162907, + 0.6088635325, 0.4285758138, 0.8790427446, 1.0297600031, -0.0150263263, 0.5672517419, 1.9943733215, -0.2904198468, + 2.2879085541, -0.6683076024, -0.9014266133, 1.1198561192, -0.3908662796, -0.7119098902, -0.1672258079, -1.8771710396, + 1.4835146666, 1.5566693544, -0.54569453, -0.3992888927, -1.8576182127, -0.0591329224, 1.1905106306, -0.7533163428, + 1.3647427559, 1.4910933971, -0.8707145452, -1.2028700113, 0.1947313249, 1.4388641119, -0.7994881272, -0.1219984218, + 1.3156124353, 0.4465557039, -2.8038535118, -1.6329493523, 0.4930388033, 1.1889687777, 0.955227077, -0.8060735464, + -1.2271238565, 1.581614852, 1.0718077421, 0.0845048428, 1.0317893028, 0.343244642, 0.4551599324, 0.2916109264, + -1.2060781717, -1.1404657364, 0.1325116307, -1.1530866623, 1.443682313, 1.3028328419, 0.4774630666, -2.2254891396, + -0.4252972901, -0.3897869885, 0.3375076354, 0.836678803, -1.5183181763, -0.3942394257, 0.3418150246, -0.9899711609, + 1.7337936163, -0.6356321573, -1.4572966099, 1.1070363522, -0.3804219961, 1.2175976038, 0.1318281144, 0.3227569163, + -0.3193053603, 1.1206564903, -0.9782357216, 2.5470190048, -0.0272714552, 1.3424437046, 1.3656324148, 0.1930369586, + 0.4632759094, -1.6178817749, 0.5364732146, -0.5179991126, 0.8289573789, -2.2828421593, -0.7208089232, 0.5070265532, + 0.0186515842, 0.0308151282, -0.5973554254, -0.3513200283, -0.2779895365, 3.2370834351, 0.0105593828, -1.0757038593, + 0.9850459695, -0.0400293693, -0.2541744411, 0.2447330952, -0.1110943928, 1.3795638084, -0.2299806774, 1.0006225109, + 0.5272231102, 0.8905154467, 2.0872952938, 0.6532689929, -0.3763174713, 0.6781877279, 0.3656844199, 0.9306739569, + 0.2416982949, -0.3654942513, 1.8575373888, 0.1327817738, 1.4138320684, -0.7374867797, -0.6212695837, -1.1035248041, + -1.7859196663, -0.3236762583, 0.2797504067, -1.71266222, 0.3749800622, -0.3638271987, -0.2331794649, 0.4900467694, + -0.1618707776, -1.4507075548, 0.4063182771, -0.1040311977, 0.7966028452, -0.3308908939, 2.0540111065, -0.818667233, + 0.0951378867, 0.316118747, 0.3237067461, -0.2970733643, 0.083307229, 1.5167295933, 0.5328765512, 0.3028484285, + -1.420655489, -0.4329741299, 1.3647885323, -0.0198237337, 1.1204465628, -2.4348003864, 0.6366173625, -0.356446445, + 0.6139984727, 0.0905427411, -0.0487639718, -0.703576386, 0.3491133153, -1.6848409176, 0.2357283682, 1.1717361212, + -0.8481423855, -0.219502598, 0.3186892569, 0.2741073966, 0.3729113638, 0.2715400457, -0.4458433986, -0.377427578, + 0.6609749198, -1.0435019732, -1.1683075428, 0.2231950015, -0.1027064696, 0.5333796144, -0.421474874, -0.8696775436, + -0.5515634418, -0.0729684234, -0.3588608801, -0.7902694345, 0.2904454768, 1.5837885141, -1.0763326883, 0.0376655497, + -1.5118037462, 0.0069348137, -0.3564294577, 0.6037105322, 0.0964799896, 1.5362436771, 0.2995141745, 1.2214409113, + 0.7883645296, -0.0879966095, 0.6117028594, -0.3020986915, -1.8245121241, -0.2724688649, -0.1164358258, -0.5263771415, + 0.2055741847, -1.635130167, -0.1721231043, 0.494217664, -0.6478079557, -0.7820081115, 1.2534043789, -0.9469304085, + 2.0706932545, 0.6533148289, 0.5774577856, -1.9339703321, 0.7606521249, 1.794477582, -1.0832855701, 0.7078484893, + -1.5409542322, -1.542727232, -0.6692368388, 1.0229578018, 1.4193599224, -0.9133544564, 0.4840072691, -0.9753501415, + 0.2186499238, 0.1535844058, -1.3288750648, 0.3165779114, -0.8043466806, -0.7737863064, -0.0225233603, -2.1306989193, + -0.0007973393, -0.1462996751, 0.3758448362, -0.5482758284, -0.2904385328, -0.2203367203, -0.1360739022, 0.9308471084, + 0.5719411969, -0.8307803869, 1.6780029535, -1.1897013187, -1.1363524199, 0.5443426371, 0.6116832495, 0.974666357, + -0.3817377985, 1.8900529146, -0.7435458899, 2.4997756481, 0.2572008967, -0.1710775048, 1.5151948929, 0.4258111119, + 0.7934648991, 0.6231244206, -0.484097749, -0.9201597571, -0.4832959473, 1.1362259388, -0.7039580345, 0.811065793, + 0.6199864149, -1.217343688, 0.7433096766, -1.2307972908, 0.8163778782, 1.2898740768, -0.9440120459, 0.712897718, + 0.3834163845, -0.2448080033, -0.420897156, 1.077645421, -0.9177082777, -1.3809242249, -0.0549273714, 0.4324325323, + 0.8900623322, -0.1035629958, 0.6625125408, -1.1518876553, 0.2836413383, 1.2821938992, -0.2739796638, 0.4010577202, + -0.3207268715, 1.726151824, 0.5400056243, 0.1708711684, 0.6841276288, 0.5838326216, -1.1475074291, 0.9617252946, + -0.5272442102, -0.3061755896, -0.2802444696, -1.269515276, -1.6422095299, 0.3058715761, -0.0128703928, -2.6293754578, + -0.3578370512, -0.4003086686, 0.9074838758, 0.9345986843, 0.9679060578, 0.3018855453, 0.0361836366, 0.0973763913, + -1.6076494455, -1.4042066336, -0.7118547559, 0.5561019182, -0.0364919156, -1.5172846317, 2.4007532597, -0.1681730747, + -0.9137525558, -1.4355233908, 0.7524472475, 2.1874260902, 0.505053699, -0.4081895053, -0.2869866192, -0.7814391255, + -0.9182626009, 2.3791458607, -1.1824381351, 0.035766717, -1.0054905415, 0.2820036411, -0.2671211064, -0.1642470062, + 1.4117362499, -0.2460403889, -0.7910364866, 0.9709326029, 1.2122645378, 0.3736355901, 0.9546735287, -0.5189890862, + 0.834515214, 0.1865234822, 0.9267693162, -0.7936452031, -0.1931727082, -1.2181763649, -1.1549400091, -0.3107994795, + 0.3828459978, -2.1461999416, 0.6490299702, 2.1667606831, 0.5197604299, -1.0844227076, -0.5551661849, 0.5941517949, + 0.8355113268, 0.0238041356, -0.1456642449, -1.7534958124, 1.0213720798, -2.0443327427, -0.8794829249, -0.8769536018, + -0.2262274176, 2.2516703606, 1.2893469334, -1.1498097181, -1.9233324528, 0.479595691, -1.0476869345, -0.1603702307, + -1.3869994879, -0.4466053545, -0.1670096517, -1.2587105036, -0.667147696, -0.1938714534, 1.3857107162, 0.3265101612, + 0.3107939661, 2.0093312263, 0.8311404586, -0.3633439541, 0.9202536345, 1.698205471, 1.078543067, -1.199840188, + 1.0437088013, 0.9129307866, -0.103676185, 0.9082722664, -0.1097550467, -1.1004810333, -1.0039086342, -0.5625741482, + -0.7018459439, 1.080119133, 0.2250289023, 0.652040422, -0.2414115965, -1.3095985651, -0.207698226, 0.1262160689, + -0.5799643993, 0.1192129403, -1.1732382774, 0.9104181528, -1.1093168259, 1.3726590872, 0.5925967097, -0.5359659195, + 0.7879594564, -0.5177975297, -0.1359538883, 0.8724327087, 1.2267098427, -0.2726623714, -1.2737469673, 0.3153249323, + -0.3683904409, -0.3502188623, -0.2695860863, -0.3834236562, -0.7484129071, -1.8965317011, 0.4718063474, 0.8372075558, + -1.8106716871, -2.5100286007, 1.0228426456, -0.2571284175, 0.4561365843, 0.1014745757, -1.9939613342, 1.5270358324, + 2.7336032391, 0.5241632462, 0.0706301928, 1.5364835262, 0.4563824534, -0.2476233393, 0.9482578039, 0.4184074104, + 0.4652556181, -0.4185591042, -1.7924579382, -0.0816290453, 0.1231039241, -2.1013731956, 0.307574749, 0.9703420401, + -1.1419631243, -0.2391041815, 0.1807586849, 1.3525646925, -2.1389710903, -1.8200509548, 1.4221153259, -0.8525925279, + -0.1797548085, -0.8431107998, -0.9901415706, 1.7518792152, -0.6028918028, 1.2872824669, -0.2191602588, 0.9963245392, + -1.0853056908, 0.5814145207, -0.2415531278, -0.2949104905, -0.1386898309, 0.9096865058, -0.2297956049, -0.5122372508, + 0.625726223, -0.5922887325, -0.73691535, -0.0611394197, -0.4971470535, 0.4321023226, 0.9778766632, 0.1208294109, + 0.2494894415, 0.0673965141, -0.176741153, 0.9871430397, 0.2811503112, 1.9028134346, -0.2427451164, -0.9117431641, + -1.3278282881, 0.0232584253, -1.6634082794, 0.5697232485, -0.7888104916, 0.205703631, 0.3429163396, -0.7559013367, + 0.9190707803, 1.5341836214, 1.0631592274, -0.7089481354, 1.8540906906, 0.6824290156, -0.8776482344, -0.9802616835, + 2.3940370083, 1.6527678967, 2.0181610584, 0.0669684559, 2.7364752293, -1.0129966736, 0.2716617286, -0.1089972779, + -0.0572592542, -1.0589312315, -0.32652843, 0.3300458789, -0.0004799794, 0.81811589, 0.4282137156, -2.503947258, + 0.1204811335, 0.807892859, 0.6021209955, -0.8651900291, -0.1533203572, -0.2404905558, -0.0607633479, 0.5328661203, + 0.764400959, -0.8560833335, -1.6823405027, 0.6530694366, 0.9302550554, 0.4051826, 0.2040024847, -0.8227655888, + -1.2768743038, -0.2264368683, -1.0160527229, -0.6572948098, 0.2939909101, 0.6200525165, 0.7796336412, 0.4549840093, + -1.3034356833, -0.5644497275, -0.6971324086, 1.0378397703, 1.560154438, -1.460206151, -1.939675808, 0.5265857577, + 1.6603387594, -0.3638090491, -0.031045191, -0.3636223972, 1.2418016195, -1.6686720848, 0.6132101417, 0.0434691086, + 0.1165482178, -0.5786048174, -1.2646787167, -0.1174873859, -0.4851864874, 1.0230669975, 0.1483554542, -0.0294206236, + 0.8758327961, 0.1348077953, 0.0840644166, 0.8931159973, -0.1384363919, -0.2515294552, 0.5490271449, 1.6555695534, + -1.3272736073, -0.1325270534, -2.0754849911, 0.6027877927, 0.4861270487, 2.0449700356, -0.6894755363, 0.3789910376, + 0.389483124, 1.2121812105, 0.1136562079, -1.0378799438, 1.5067687035, -0.4767748713, 1.2916351557, 1.2961734533, + 1.1144324541, 0.1773619503, -0.2875421047, 1.4568520784, 0.8501911163, -0.3830829263, -0.6213039756, 2.2090291977, + 1.0792033672, 1.126827836, 0.1464464664, -1.0442385674, 0.3112875223, 0.9527289867, -0.1369006485, 0.157979846, + 0.9468470812, 1.1619044542, 0.1117127314, -1.2547981739, 0.0041935598, -1.8870812654, 1.8109247684, 1.2467620373, + -1.1706187725, -0.8198552132, -1.0388509035, -0.3795161247, 0.2471856773, 0.097837545, -0.3687669337, 1.428104043, + -1.266826272, -0.7314748168, -0.2361954153, -0.0640455484, 1.585006237, 0.5684098601, -1.0112850666, -1.1607600451, + 1.6386686563, 0.0010163832, 0.6599608064, -0.5040879846, 1.7607916594, -0.2987151444, -0.0699679181, -0.239069581, + 0.048086971, -0.0561540872, -1.4012265205, -0.4074691832, 1.0456372499, -2.2115867138, 0.1003632694, -1.1718195677, + 1.9943586588, -0.7404477596, -1.8472335339, -0.3663715124, 1.6781787872, -0.3644346595, 0.2316042483, -0.6349893808, + -1.0591756105, -0.3665927351, -1.3370912075, 1.3054594994, 0.0549971089, -1.1565880775, -0.1878262907, -1.7153264284, + -0.2808305323, 0.3602373302, -0.7212537527, 0.5203909278, 0.6193087101, 0.0597162433, 1.3419901133, 1.7610182762, + -0.4293690622, 0.7105035186, -0.229921937, -1.195458889, 1.5433597565, 0.2379141748, 0.7672137022, -2.109814167, + 0.6415581703, -1.4304503202, -0.5032683015, -0.1808628291, -0.969861865, 0.9286208153, 1.224570632, -0.853241086, + 0.38801983, -1.2975735664, -0.7356634736, 0.1969772279, 1.2833096981, -0.2106740475, -0.1530257016, -0.1989236623, + 0.6560999155, 0.1675494611, 0.4150153399, -0.2940008044, -0.4093782008, -0.8216152191, -0.4769310653, 0.9040605426, + 1.2138260603, 0.8652194738, -1.1292105913, 1.0701618195, -0.1425126493, -0.8724672794, -1.6130620241, 0.0751923323, + 0.4281897247, 0.1331243962, -2.1410734653, -0.9063301682, -0.3643827438, -1.4411940575, -0.8983129859, 0.4188375175, + -0.6246270537, 1.0137139559, -0.0459714942, -1.2153115273, -0.8810849786, 0.9074236155, -2.5559902191, 2.157626152, + -0.4590293169, -0.9930305481, 1.8669599295, -0.4173523188, 0.9735121727, -0.5194160342, 1.8311252594, -0.2143068463, + -0.3267007768, -0.7139260173, -2.0381011963, -0.5063050389, 0.6719281077, 1.2255204916, -1.0252617598, 0.2913454175, + -0.5917704105, 0.7488190532, 1.6724610329, 0.8395947814, 1.7179481983, -1.6458688974, -1.7235046625, 1.6781872511, + 0.6279851794, -1.2300579548, 0.206368506, 1.7433674335, 0.234653011, 0.7607139349, -0.3385611773, -0.2102975249, + 0.0059588552, 1.426076889, 0.0142158372, -0.4406615496, 0.2704971731, -1.0747419596, -1.3426505327, -0.1716880351, + -1.2444826365, -0.8974450827, -0.0273043569, 1.3485187292, -0.2789664567, 1.0251704454, 0.1180881709, -0.3778805137, + -0.2141260207, 0.4078404903, 0.3173700273, 0.369638592, -3.5518553257, -0.0249717198, 1.0215418339, 0.6116573811, + -0.8735608459, 1.9158036709, 1.0758155584, 1.0407550335, -0.1262805015, -0.161518082, -1.1025336981, 0.7169651389, + 1.9114420414, -0.7175180912, -0.2838610411, 0.1815304458, 0.050998047, 0.1601001769, 1.3206021786, -2.0074746609, + 1.1405119896, 1.0774667263, -0.3010169268, -0.0158685166, 0.2949124277, -0.915549159, 0.0511295386, -0.9183694124, + 0.4059500396, -0.9847790599, -0.3063639998, 0.2768558264, 0.6799152493, 0.1374379843, -1.7768172026, 1.0458937883, + -1.5003950596, 0.2859581411, 0.4456777871, 2.7115471363, 0.0316340886, 0.0237582047, 1.3859419823, -0.2100570202, + 0.525647819, -0.0925751105, -1.4566472769, 1.607408762, -0.4122121632, -0.8000978231, -0.4829004407, 0.712487936, + 2.1299157143, -0.0259689819, -0.2674769461, -0.5260988474, -0.1544209272, 0.8619582653, 0.1432756037, 1.1954751015, + -0.4071525037, -1.1334422827, -0.1827943474, -0.1172728464, 0.142906636, -0.62562567, -1.1532642841, -0.703497529, + 0.5680677891, 0.2888707519, 0.1756383628, 0.5803961158, -0.5129320025, 0.0149797229, 0.911648035, -0.1075092405, + 2.3236284256, -1.1821206808, 1.3360717297, 0.5781747103, 0.2877194285, 0.4588770568, -0.1316705644, 0.0050465642, + 0.5311812162, -0.738684535, 1.6503698826, 0.8862819672, 1.2689412832, 1.4950553179, 0.0704524592, 0.9109133482, + 0.0946484506, -1.0497871637, 0.7867195606, 0.2191394717, 0.8150247335, 0.0630580559, 0.1004397869, 1.4962004423, + 0.3818966448, -0.3216921687, 1.6232447624, 0.4632739425, 0.3479743302, 0.2854761779, 0.0905378759, 0.0078849401, + 1.14182055, -0.2064098269, 0.1464061737, -0.1620241702, -1.1185684204, 0.0551032908, 0.0955945477, 0.1914982051, + -0.2445030063, 1.0773905516, 0.7771847248, -2.002695322, -1.3879367113, 1.8168145418, -1.3441421986, -0.1909300387, + -0.2537579536, -0.4333573282, -0.5043718219, -1.1934229136, 0.8883563876, 1.3796744347, -0.8058362007, 0.6302874088, + -1.4562950134, -0.2413089424, -1.1239010096, -0.8434281945, -0.6111188531, -0.321421504, 1.7906646729, -0.2953863144, + -1.099608779, -0.0280012544, 1.5195906162, 0.4385769963, -0.0715610012, -1.2215670347, -1.1551032066, -0.5126031041, + 0.5079829693, -1.5987869501, 0.6407077312, 1.2264078856, -0.5521286726, 0.538315475, 0.9565272927, -1.150249958, + 0.4597047567, 0.3260488808, -2.5554530621, 0.0539155044, 0.9961486459, -2.3894460201, -0.304166466, -0.2683731318, + -0.8905698657, -0.0944725424, 0.5605733991, 0.7430984974, -0.6170213819, 1.4618774652, -0.4896700978, -1.6775000095, + 0.9276668429, -0.3350292444, -0.2878435254, 0.2499760538, -0.8336799145, 1.0695707798, -0.8759759665, 0.8804914355, + -0.4413791895, -1.4477114677, 0.3207118511, -0.6660116315, -0.0039797751, 0.2596048117, -1.3988531828, 0.0217267051, + -0.3165823221, 1.4104597569, -0.8589660525, 0.3823044598, 0.5117325783, 0.5799040198, -0.79652071, -1.0794136524, + -0.5460695624, -1.439923048, 0.9373409748, -0.6249065399, -0.7326609492, 1.7352846861, -0.7039022446, -0.861921072, + 0.2775456607, 1.8297880888, -1.3504639864, 0.1678970009, 1.6588230133, -1.4726707935, 0.2412999719, -0.0883939713, + 0.8553674817, -1.1602106094, -0.0671377331, 0.2164906412, -1.9931809902, 0.0053256475, -0.2441381961, 1.742197752, + 0.2616285682, 0.6127197742, -0.6840193272, -0.3926095366, 0.4958389103, -0.4157512188, -1.8020431995, 0.5348650813, + -0.4459702671, -1.0132100582, 1.6183987856, 1.8912308216, 1.4364794493, 0.4951191545, 0.3030346632, 0.6038584709, + 0.6475570798, -0.2035506368, 0.4782030582, 0.8421400785, 1.672096014, -0.8565639257, -0.4995645881, -0.0788188726, + 2.6190998554, 0.0172765702, 0.8030301332, 1.9209679365, 0.6042689681, -1.6229704618, -1.5398095846, 1.2159051895, + -0.0491375811, 0.6701576114, -2.0786049366, 0.2396868467, -0.1663447022, 0.4873751402, 1.6635489464, -0.7188113332, + -2.3959128857, 1.7327207327, -0.534961462, -0.0728966668, -0.2948603034, -1.4774221182, 0.4834442735, 0.3681408465, + 0.9823635817, 0.5640633106, -0.0505462214, 0.3036163151, 0.9760785103, -0.205296427, 0.0603897423, -0.0227735676, + 0.4560826123, -0.7479364872, 0.4386453032, 1.5767741203, 1.2626835108, 0.5652157664, 1.5275896788, 0.0146089382, + -0.8305668831, -0.0492977872, -0.4252792895, 1.2362649441, 0.0874866694, 0.4226440191, 0.0723808184, -0.0925615653, + -0.5521541238, -0.5364710689, -0.5070555806, 0.1121965498, -1.1298216581, -0.7371627092, 0.8932670355, -0.6637581587, + 0.4557986557, -0.6397003531, -0.3043342829, -1.1985019445, -0.506919384, 0.5818718076, 0.971309185, -0.5977748036, + 0.0146248564, -2.4917397499, -2.0943746567, 1.2473956347, -1.9712914228, -1.3773270845, 0.180745706, 1.2754870653, + -0.648504436, 2.5466191769, -1.3412190676, 0.1961534172, 1.7364504337, 0.1384211183, -0.2164301127, 1.4340209961, + -1.1674877405, 2.2805016041, 0.727185607, -1.6405873299, -1.7613757849, 1.2478111982, -0.7066447139, 0.4562221169, + 1.0106225014, 0.6289210916, -0.2545123994, 0.8075569868, 0.9933471084, -0.7091018558, 2.4793047905, -0.1058447361, + 1.4626127481, -1.1512520313, 2.281999588, 0.1980908364, -2.0391972065, 0.4623443484, -0.4528153837, -0.3034771681, + 0.6253050566, -0.9960688353, 0.1848763525, 0.1992302835, 1.396992445, -2.1879806519, -3.5258898735, -0.3500127494, + 0.1608139724, 0.5911024213, 0.6979445219, -0.4094097912, 0.1062802821, 1.5368102789, -1.2191261053, -0.1408000141, + -0.3725816011, -1.042175293, -0.1061916351, -1.8223229647, 0.6922587156, 0.046620138, 2.0245492458, 1.8404192924, + -0.5316298604, 1.8038771152, -0.9891858101, -0.7872034311, -0.9601790905, 1.5571957827, -0.0051668053, 1.6011846066, + -0.1465292424, 1.2160656452, 0.4363673925, 0.032131508, 0.7290571928, -0.569996953, -0.1844813824, -0.0893535689, + 0.4522967935, 1.4669539928, -0.2522238791, 0.466101259, 1.4432981014, -2.743449688, 0.3867551684, -2.0132300854, + 1.6866211891, 0.7507246137, 1.0172561407, -0.2487859428, 0.7585685849, 0.5755932927, 1.2352458239, 0.8978250623, + 1.296671629, -0.657181561, 1.4671807289, 0.7853207588, 0.3756480515, 0.6194713712, 0.32728374, -0.3676315248, + -0.0267670508, -0.2408681363, -0.7468521595, 0.6240339279, 2.1852478981, 1.1214398146, 2.0001266003, -1.5732886791, + -0.0183822736, -0.8087029457, 0.9497622252, -1.0744439363, 0.9904448986, 1.4737164974, 0.1133142486, 0.3727804124, + -0.5018841624, 0.6833029389, 0.3201475739, 0.2428314686, -0.8037180305, 0.2282627523, -0.6574258208, 1.8786723614, + -0.7279502749, 0.5236622691, 0.3721244335, 0.7680162191, 0.7290078998, -1.6448494196, -1.3555030823, -0.9520250559, + 0.7258281708, -0.2495432496, -0.3343724608, -0.1035859659, -1.5604089499, -0.0533355586, 1.2266353369, -1.9780186415, + -1.2835073471, 1.0977239609, -0.0809845626, -0.1254453063, 1.2240229845, 0.816267848, 1.1728838682, -0.4857140183, + 2.0652470589, -1.0620183945, 0.4987939894, 0.1875279099, -0.160524115, 0.2976987064, -1.725386858, -1.2821964025, + -0.545478642, -0.6711188555, 0.4872035384, 1.3012408018, -0.0574941002, 1.0852347612, 0.2164134383, -0.8638213873, + 0.0029188166, -0.3997426331, 0.8708361983, 1.0494933128, 1.212218523, 1.0808790922, 0.0889089853, 0.3659733832, + 0.6266746521, -0.7211550474, -0.0947615877, 2.5941832066, -0.6472509503, -0.0892662406, -1.1688027382, -0.7755636573, + -0.1888562292, 0.4613487422, -0.1133504286, -1.057937026, -0.3661361039, -0.9344208837, 1.4105546474, 0.3662054837, + -0.1800113618, -0.8287143111, -0.4588594139, -0.5348659754, 0.1927637607, -0.1688094139, -1.0985659361, 1.7208666801, + -0.9949175119, 0.0071640117, 0.2181097269, -0.52932477, -1.2477115393, -0.4222748876, -0.8102868199, 1.5723097324, + 0.7872313261, -1.7233170271, 0.580704689, 0.1063605845, -0.5338957906, -2.1653342247, 0.4575393498, -0.5575693846, + -0.8172625303, -0.3406208754, 0.0603416599, -1.5120033026, 1.1769851446, -0.2431340963, -0.8860734105, 0.2002744973, + 0.0624899231, -2.278788805, -1.7242875099, -0.3660179377, -1.5788301229, -0.9279945493, -1.8265781403, -0.8975494504, + 0.2838334143, 1.9209350348, -0.1576115489, -0.5317687988, -1.6259893179, 0.0153308073, -0.9110952616, -0.1653829366, + -0.4306715727, -0.6055718064, -0.8026126623, 1.3090204, -1.2156563997, -0.0519316867, -0.6713653803, -0.7353394628, + 1.4131215811, 1.1170443296, -1.1881471872, 0.2349975854, -0.2238769233, 0.2461022288, 0.1120637581, 0.2336885929, + -0.5243279338, -2.1437044144, -0.2431624234, -1.2464995384, 0.4675020576, -0.7527608275, 0.562419951, 1.3365873098, + 0.7289454341, 1.7958503962, 0.2928060591, 0.7216563225, 0.9394800067, -0.6092904806, 0.512319088, 1.6707273722, + 1.7536890507, 1.2125877142, 0.8943855762, -0.8880759478, -1.3625150919, -0.2121257335, -0.6096383333, -0.1692983806, + 0.1635778695, -0.1416323781, 0.352288574, -1.0253274441, 0.0980968177, -0.1966700852, 0.7525386214, 0.087527141, + -0.4656350613, -0.4846600294, 1.048032999, -2.1517102718, 0.4131481051, 0.2350990921, 0.8666293025, -0.0862590522, + -1.361574769, 0.3523576856, 0.6853317618, -0.3136028051, 0.1880191416, 0.4099854231, 0.5680887699, 0.568916738, + 1.6204892397, -0.1595118791, -0.1066793799, -1.1540112495, 0.6110669971, -0.7147044539, -1.7258614302, 0.7982810736, + -0.7267000079, 0.1675357521, -0.8346014619, 1.2481591702, -0.9113322496, -1.5161044598, -0.1560480595, -0.3392308652, + -0.1593530327, -0.1827998012, -0.5442073941, 1.3976205587, 1.0422940254, -0.2430956662, 2.946475029, -1.0710835457, + -1.2913874388, 0.4633493125, 1.0320210457, -0.1943645924, 0.4055425823, 0.817563951, -0.6497596502, 1.2451591492, + 0.3004733324, 1.1675512791, -0.633343339, -0.9965176582, 1.0963352919, 1.3911732435, -0.2135262489, 0.002902186, + 0.0531421266, 0.3033952117, 0.5173051953, -0.0102700051, -0.0946862027, 0.2938453853, 1.3135150671, 0.4863734245, + -0.8989269137, -0.7194559574, -0.1590253711, 0.4843160808, -1.1027262211, 0.0849133283, 0.5688287616, 0.2679769695, + 0.4811837673, -0.7134509087, 0.2008953393, -0.8335529566, -0.720151186, 0.5242791772, 0.0110169752, 0.4427189529, + 0.4736892581, -0.538204968, 1.6526933908, -0.2942489386, -0.4903966188, 1.2739274502, 1.1805559397, -0.197570309, + 0.4837063253, -2.3744602203, 0.2897094488, 0.6084982157, -1.6204299927, 1.3142671585, 0.6344429851, -0.4190022051, + -0.4888667166, 0.6072349548, 0.9508922696, -0.6400114894, 1.4980759621, -2.1872255802, -0.925344944, -1.6960446835, + 1.5540304184, 1.1076310873, 0.4102774858, 0.3571720719, 0.024448242, 1.1432708502, 1.6378223896, 0.1038910747, + 1.1907352209, -0.700840354, -0.4064160585, 1.1399818659, 0.8482441902, -0.8278619051, 1.216591835, -0.1842192709, + 0.5383604765, 0.0136463754, -1.6233984232, -0.3791120946, -0.8511069417, -1.28662467, -1.8059158325, 1.1002595425, + -0.6931541562, -0.2090755552, 0.0067911642, -1.0231842995, -1.4700142145, 1.542940259, 0.5305857658, 0.7299745679, + 0.4535187185, 0.1681299061, 1.6024149656, -0.9856672287, -1.6728117466, 1.1804482937, 1.7814029455, 0.0313383043, + 0.1245605722, 1.534096241, 0.1487563401, -1.317504406, 0.5722743273, -0.8558244705, 1.0446487665, -0.977401495, + 1.4014579058, -1.2876857519, 1.965308547, -0.2574622631, 0.8741406202, 0.1923532635, 0.4771126211, 0.5219726563, + 1.0568250418, 0.127501592, 0.3534825146, -0.4791073799, 0.0526588932, 0.8323126435, 0.7390776277, 1.3197847605, + 0.320635885, -0.8508493304, 0.1079496369, 0.0510789007, 0.8233492374, -0.2772503793, -1.0964258909, -1.0618132353, + 0.0157843046, -0.9365561008, -0.732668817, 0.1077768654, -0.207335934, -2.3172490597, 1.3560752869, 1.5103831291, + -0.1958469301, 1.051209569, -0.0394407101, 0.3858150244, -0.0032381886, 0.9143221378, 0.9421868324, 1.6064001322, + 0.4654370844, -0.2540049553, 1.4979096651, 0.6909629703, 0.4411643445, -1.0131149292, -0.173385784, -1.7086960077, + -0.3259657919, -2.0024752617, -0.6706923842, 0.6668214202, -1.9155961275, -0.3144879341, -1.2456922531, -1.2796248198, + -2.2090945244, 0.7396605611, 0.0296590049, 0.9433910847, 2.1231267452, -1.0864417553, -0.6030449271, 0.3438302875, + -0.6608654857, -1.0862615108, 1.3887225389, -0.7988653183, 1.3075400591, 0.9552127123, 0.3432019651, -0.2984606922, + -0.128897354, 0.7399637103, 0.0231899377, 0.6450478435, -1.3013180494, -1.3024494648, -1.0995938778, -0.2466881722, + -0.377599597, 0.4923250675, 0.1694402844, 0.9104561806, 0.6665503383, -0.5168366432, -0.3762043715, -0.9129214287, + -0.2788790166, -0.4600901902, -0.8824477792, 0.536190331, 0.6113188267, 1.3454030752, -0.8275414705, 0.4882041514, + 0.8205421567, 0.8798395395, -0.6477968693, 2.4074959755, 0.5788549781, -0.0437356532, -0.7579018474, 0.9680426121, + 0.5040457845, 1.1636078358, 1.8771742582, 0.6200423837, 1.5920174122, -1.8497363329, -0.843611002, 0.3149974346, + -0.4593172967, 0.8473721743, 0.0478686653, 0.4404908121, 0.3380852044, -1.1299993992, -0.123311013, -0.9066924453, + 0.4301193058, -0.3466370702, -1.0565040112, 0.2993363738, -2.2224280834, -1.1136168242, -0.5317560434, -1.9586926699, + 1.2876089811, 0.5533798337, 0.882155776, 1.184017539, -0.1996572614, -1.7286516428, -1.849193573, 0.5178694725, + 1.7988730669, -0.2523056269, -0.4970327318, -1.4278050661, 0.3399576545, 0.7023395896, -0.7998167872, 0.7301787734, + 0.5362419486, 0.8577725291, -0.9817480445, -0.9755565524, 0.3299261034, 1.4980843067, 0.7955431342, 0.8185396194, + 0.0570088066, -0.1452435553, -0.4598515928, -0.4803588092, -0.6821164489, 0.4632911086, -0.0423791558, 1.8142098188, + 1.3901891708, -1.069789052, -0.0289973561, -0.6405655146, 0.0753127635, -0.527031064, 0.1859117001, -0.166329056, + 0.5048159957, -1.732221365, 1.6413090229, -0.7120727897, -0.4916498661, 0.8107194304, 0.9926199913, -0.1052645668, + -0.0880601779, 0.6687352657, -1.4801020622, -0.7137554288, -0.3793790638, -0.1603921801, 0.7068908215, 1.2170107365, + -0.4102213979, 0.4785642028, 0.3500928879, 0.4325503111, -0.6816869974, 0.2588504553, -2.3803224564, 0.0774483383, + -0.5226783156, -0.3486301601, 0.1307638288, -0.4308033586, 1.0323166847, 0.7308865786, -1.0509271622, -0.3705799282, + -1.4526411295, 0.7582592368, -0.111243315, 0.2123344541, -0.1703404486, 0.5684955716, 1.2879304886, 0.4955765605, + 0.9762223959, 0.5969173312, 1.0294094086, -0.4016108215, 1.4354219437, -0.4525334239, 0.9244177341, -1.8113485575, + -1.854475379, 0.6716580987, -0.1637547463, -1.0912935734, 1.0384893417, -2.0325262547, 0.6750365496, 0.1859313697, + 1.4355543852, 0.9272583723, 0.3481788635, -1.7764997482, 0.6461026073, 0.3343574703, -1.193205595, -0.7114098072, + -1.1107187271, 0.2314597964, -0.3236814439, -0.2080765665, -1.4484943151, 0.4726499617, 1.2705886364, 0.0462085642, + -0.8196042776, -0.4398490787, -0.5813989043, 0.0109049398, -0.3579022586, -0.3998372853, 1.3548592329, -1.9293205738, + -0.6319025159, -0.7778295875, -2.0569281578, -0.7499248981, 0.9562718868, 0.7526506782, 0.3659623861, -2.2221159935, + -0.5005191565, 0.0293950923, 0.0451079011, 0.2878231704, 1.1077967882, -2.5320174694, -2.6052191257, 0.5428759456, + -0.3326431513, -0.2977385223, -0.3886250556, 0.3837181628, -3.0844507217, -0.0326572843, 1.9840731621, -0.099092871, + -2.0813033581, 0.9364513755, -1.501822114, -0.7127351761, -0.418425262, -1.6085178852, -0.5712712407, 0.3170658648, + 1.3702354431, 0.2474628687, 1.6732935905, 0.3019446135, -0.5106189251, -1.6296691895, 0.0827088729, -0.2414676398, + 0.0117205493, -0.3977093697, -0.8551368713, 0.5991954803, 0.4162049294, 1.5830416679, -0.1344192475, -0.8080347776, + 0.8270174265, -0.2177505791, 0.7213084102, 2.7542774677, -1.9037790298, -1.1765846014, 0.957495153, -2.2370584011, + -0.1641188562, -1.5068861246, -0.5019809604, 0.2476276606, -1.3522347212, 1.598107338, -0.0016236352, 0.0727113858, + -1.478546977, -0.8532192111, 1.3951283693, -1.0664182901, 0.4442366064, -0.4066230357, 0.2653382123, 1.0576475859, + -0.2093126327, 0.0964964181, 0.1187895015, -0.1235642135, 0.1212674677, -0.6063463688, -1.7976351976, -0.2944546044, + 0.5414992571, 0.5756024122, -0.4685805142, -0.7462616563, -0.3464683294, 0.2230277807, 0.9854597449, 0.0767948404, + -0.4874532223, -0.1219522431, 0.8327487111, -0.1716076732, -0.3945173025, -1.1791951656, -0.4452678263, 1.3629028797, + -1.1066451073, 0.3573346436, 0.632383883, -0.3071047366, 1.6411852837, 0.8643095493, -0.2245212346, 1.4297059774, + 1.3671625853, 0.22881262, -2.0948269367, 0.9121999145, 0.1160216853, -0.0257257298, 0.2509836555, -0.1600100994, + -0.6034733057, -0.1384988427, -0.0839320645, -0.6945816278, 1.9426094294, 0.0452554338, 0.326672256, 1.2575550079, + 1.1093206406, 0.8573603034, -1.2389947176, -2.0883388519, 2.1227445602, 1.1516443491, 0.2675343156, -0.336922586, + -0.4755612016, -1.1894302368, -0.2873914242, -0.1477799714, -0.1865244955, 0.9614298344, 0.1122136638, -0.1507401168, + -0.7496002913, -0.8663163185, 1.8104102612, 0.1771599203, -0.749078989, 0.036649771, 2.0983855724, -1.0290652514, + -0.5826900601, 1.1658000946, 1.2506613731, -0.1822900325, 0.0264755636, -1.3294763565, 0.1857622564, 0.1860099584, + 0.6812687516, -0.0765349269, -0.5551304817, 0.2183326185, 1.0382562876, -0.7524948716, -1.2267206907, -0.5154917836, + -0.9957588315, -0.8302957416, 1.1273059845, -0.7931482196, 0.0290784836, -1.8754261732, 0.6611202955, 0.7537636161, + 1.4504109621, 0.4328519702, -0.1413241476, -0.3728679121, 0.6295785308, -0.2826263309, 0.1017487198, 0.1004890427, + -0.7599399686, 1.1586389542, -0.4124349654, -0.9641899467, 0.9970339537, 0.6460083127, -0.4832358658, -0.6841650009, + -0.030308418, 0.5566793084, 1.2560545206, 1.271950841, -0.0263155978, 0.0070461296, -0.8024127483, 0.1088609323, + -1.888931632, 1.7075667381, 0.4763677418, 0.8923625946, -0.1581884325, 0.3295147121, -0.6005237103, -0.776876986, + -0.4446044564, 2.0271074772, 1.3566521406, 0.0894624814, -2.5341632366, 2.3792328835, -0.2505889535, -1.366425395, + -0.5644386411, -2.1931164265, 1.1769444942, 1.0361630917, 1.8065854311, 1.3853068352, 0.8310387731, -0.6718800068, + 0.0839435682, 0.5932793617, -0.3277965784, 0.4227188528, -0.9974304438, 0.1251470149, -0.4001867771, 0.2866265476, + -1.725312233, 0.4782764316, 0.7806475163, -0.5707991719, 0.4938725829, 2.1363813877, -0.6386837363, -2.1948287487, + 1.2262840271, -0.0510553345, -1.0744620562, 0.5451381803, -1.9778690338, 0.9243052006, -0.236308381, -0.8462770581, + -0.4339647591, 1.5218746662, -0.2496304214, -1.2015702724, 0.4348722398, -0.7702450752, -0.361600548, -0.9668240547, + -0.7775117755, 1.6584910154, 1.2157908678, -0.0582093261, 0.4874089956, -0.4351541996, -1.2981131077, 0.4196226597, + -1.1504046917, -1.3714263439, -1.1537238359, 0.211385116, 0.9948299527, -0.0589868426, -0.2105388194, -0.1264684796, + -1.0223534107, -0.1095140055, 0.3037421107, -0.2303951383, -0.3564314842, -0.2918756604, 0.3242609799, 1.4333026409, + 1.8529117107, 0.2137945294, 1.9478644133, 0.6609766483, 0.2107582986, -0.0890568718, -1.0639896393, 1.5600599051, + -1.1038756371, -1.2550096512, 0.1083938032, 0.5406846404, -0.2521128654, 0.4976765513, -1.5165120363, 0.7626850009, + 0.2167731673, 0.6663960218, 0.4201067984, -0.5433947444, 0.3073146641, 0.7519953847, -0.540291667, 0.5032405257, + -0.7342537045, -0.944499433, -0.4982891083, 1.3228744268, -0.1457812637, 0.506326437, 0.5172562003, 1.5089118481, + 1.8802934885, -1.1349375248, 0.148652032, -0.3159368038, -0.9561010003, -0.1483890116, -0.600231111, 0.8183563948, + 0.9246582985, -0.2708984911, -0.1344445795, -0.3975899816, 0.2588158548, -0.8930866718, -1.668651104, -0.5920096636, + -0.0261793677, -1.0039272308, 0.5324293375, -0.7660702467, -1.5267822742, -0.0449126177, -0.5578223467, 0.4411966503, + 2.836152792, -1.0847097635, 0.5951077342, 0.6513732076, 0.5490559936, 0.2389404327, -0.6742807031, 0.2803015709, + -0.5785861611, -0.4543779492, -0.6440399289, -0.9178314805, 0.3433896899, -0.0781365111, -0.0110655092, 1.0301516056, + 0.2924049199, 0.9450477362, -0.7342799902, -0.4853533804, -0.0152373305, 0.3297406137, -0.95916605, 0.6535556316, + 0.6672778726, 0.5473683476, -0.069032535, 1.7266031504, -0.6833693385, -0.0771031976, 1.332683444, 0.6728719473, + 0.8581472635, -0.7994928956, 1.7931659222, -0.2488678694, -0.9435475469, -1.3550130129, -0.1657632738, 1.8103445768, + 1.6421945095, -0.5307902694, 0.3177648783, -0.8274542093, -1.5274112225, 1.0199569464, -0.8939806819, -1.1168608665, + 1.3539602757, 0.2608950734, -1.5025458336, -0.0350464173, 1.6370078325, -0.2023550272, -0.9884869456, -0.7876907587, + 0.3030428588, -0.8543554544, -2.0759766102, 0.807474196, 0.0092417505, -0.7486258149, 0.9306184053, 1.5228734016, + 1.0625956059, -1.0638818741, 0.9000504017, 0.9773253202, 1.491486311, -0.9541801214, -0.1188048348, 0.052006349, + -0.7230827808, 0.452013135, -0.6191820502, -0.9545143247, 0.1884564161, 0.3061656952, 0.4476604462, 0.0418105461, + -0.1309568137, 0.4180471897, 1.2613639832, -0.7609384656, 0.3685899377, -0.2012770772, -0.4936135709, 1.159807086, + 0.373701781, -0.1421750039, 0.2495179474, -0.8559209704, -0.6964498758, -0.2374830842, -0.9256697297, -1.7266376019, + 0.2695619464, -1.4074134827, 0.8068033457, 0.6471933722, -0.5924095511, 0.1117355973, 0.2366000563, -1.4429482222, + 0.8711776733, 1.5175033808, -0.2762643397, -1.2968262434, -1.2299476862, 0.9790905714, -0.6197896004, 0.2056121975, + 1.1886742115, 0.6697474122, 0.1087135598, 1.2664176226, 0.1910816878, -0.3005948663, 0.6051598191, 0.1337996721, + 2.2987043858, -0.2989132106, 0.053351149, 1.4336971045, 0.3602710962, -1.4897760153, 1.9669363499, 1.7474601269, + 0.7100765705, 0.2949651182, -0.0514402352, -0.3578273058, 0.3582149446, -1.3475846052, 0.025527332, -0.7661463022, + 0.6330846548, 1.4332324266, 0.9169499874, 0.88393116, 0.7519271374, -0.1242360175, -0.3691127002, -0.8278617859, + 0.3434691429, 1.483169198, 0.8366777301, 1.0739248991, 1.0072058439, -0.6175259948, -1.3308913708, 1.1121007204, + -0.8164995909, 0.8835690618, -0.9938970208, 0.9998544455, 0.4616194069, -1.137031436, 0.9062680602, 1.1257185936, + -1.919401288, 0.276499629, 0.5737554431, 1.4669361115, 1.4267357588, 1.0081113577, 0.7518727183, 0.9374237061, + 0.6022189856, 0.9636828899, 0.6104877591, 1.2044204473, 0.9677898288, -0.5647366643, 1.0105677843, -0.3122237325, + 0.3334992528, -1.9033569098, -0.9630427361, 0.2652240694, 0.5199043751, -1.1540907621, 0.7361152768, 1.2738237381, + 0.1880766749, -2.2973453999, 0.5291508436, 0.0009351905, -0.60242939, -0.2233156264, 1.5331068039, -0.9884901643, + 1.5078092813, 0.7398353219, 2.3887550831, -0.3120129704, 0.5433498025, 0.0288962387, -0.2012146115, 1.0563759804, + 0.0455531701, -0.1074009314, -0.9435821772, 0.847458601, 2.1150949001, -0.5216084123, 0.6223477125, -0.4835988879, + 0.0323945619, 0.1332448572, -0.6117167473, 1.2821873426, 0.6829779744, 1.7952840328, 1.4735364914, -0.0281432271, + 0.3344296217, 0.0498930812, -0.7253366709, -0.1882753372, 0.750015378, 0.3084684014, -1.2596098185, 0.4998308122, + -0.2986431718, 0.7846732736, -0.5215204358, 0.4127131701, -1.4233584404, 0.3591822088, 0.8100859523, 0.66738832, + -1.475758791, -2.2996366024, -0.5354201198, -0.6260387301, 0.0607966073, -0.9204249382, -0.379586488, -0.0245653503, + 0.4642808735, -0.2157164365, 0.8455864191, 2.2098424435, -0.4032137394, 1.2565199137, 0.3011314571, -0.4515376091, + -2.2521011829, 0.2975798845, -0.6609811783, 1.232483387, -0.2599743605, 0.6994997263, -0.9482492208, -0.0442115664, + -0.1683008969, 1.777854085, 1.5128661394, 1.1165469885, -0.9578713179, 0.5861684084, 0.4876947403, -0.0258086044, + 0.8223834634, 1.023152709, 1.5395146608, 0.5583790541, -0.5228635669, 0.8827819824, 0.4835412502, 0.4577231705, + 0.5126315951, -0.7414305806, -1.8140503168, -1.354457736, 0.8708856702, 1.0170553923, 1.0010755062, -0.6828664541, + -0.0983215198, 0.232948482, -0.5799430013, -0.9481555223, 1.3907268047, 0.6413714886, 0.3823638558, 0.9870128632, + -0.4725233614, -1.5783783197, -0.6470431089, -0.9037789106, 0.0999176055, -0.6165252924, -0.5567381978, 0.6479242444, + 0.5634599924, 0.4559148848, -0.7018021941, 0.5007602572, -0.7826791406, 0.3516834974, -0.554498136, 0.9681010842, + -0.6531418562, -0.0493310317, -0.3987984359, -0.0768239871, 1.2028565407, 0.9053220749, -1.5396063328, -1.5210251808, + 0.0095656775, 0.4015446603, 0.4952757657, -1.9695576429, -0.9904660583, 0.0043475674, -0.3832959235, 1.5924043655, + 0.1618719697, 1.1238229275, -0.3456900418, 0.7589526772, -0.2558067739, -0.1103068292, 0.334807694, -0.2165825069, + -1.7158200741, -2.2370626926, 0.7226798534, 0.1446095556, -0.355173111, 0.7914757133, -1.0397866964, 0.3701458871, + 1.5328626633, 0.17118074, 0.0900413617, -0.1533249617, 0.7270753384, 0.1712650359, 1.243106246, 0.2759212554, + -1.4751939774, 0.1763630956, 3.6361017227, -1.5242985487, -0.0279763695, -0.9603900313, 1.179972291, 0.2726994753, + -0.233088702, -0.6826753616, 1.0471214056, 1.1989165545, -0.4046612084, -0.7465475798, 0.8356605172, -1.0643728971, + -0.3423130512, 1.3552594185, 0.0537857786, -1.5534422398, -0.5955978036, 1.1433280706, 0.2265868187, -0.205484733, + 1.4488072395, -0.9428060055, 0.2496462762, -0.5333206058, 0.9197281003, 0.0167320166, -0.5308976173, -0.3981518447, + 0.1968156695, 1.2565236092, -0.1500016153, 1.7518627644, -0.5710981488, -0.7607555389, -0.5640133619, -2.1015295982, + 0.2339061052, 0.3560619652, -0.2133811563, 1.6464656591, 0.8782684207, 0.6951352954, -0.8930280805, -0.5173587203, + -1.0700474977, -0.6147041917, -2.5534784794, 0.4594208002, -2.9251899719, -0.6844087839, -0.1010654792, -0.962415874, + -1.0140864849, -0.0757387206, 1.1583821774, -0.5384712815, -0.9480490088, 0.9694117904, -1.3669112921, -1.2707827091, + 0.7595877051, 0.9194093347, -0.9817193747, -0.7923594713, -0.9515684247, 0.1903454214, -0.6589611173, 0.2844074667, + -0.0866462439, 1.4720683098, -0.115615055, -3.1793930531, 1.5431214571, -0.6267422438, -0.5408167839, -1.4073745012, + 0.0020372916, -0.9605144858, 0.0653555542, -0.0072504482, -0.2048006058, -0.8758507967, 0.6794900894, -0.5280171633, + -0.2964494228, -0.6805481315, 0.7795145512, 1.911047101, -1.3809238672, -0.0489975736, 1.4007698298, 0.408392936, + 0.2260774076, -0.649741292, -1.0933283567, -0.2311290503, 1.137881279, -0.7990297079, -0.7805021405, 2.1594064236, + 0.0872589722, -0.3067907393, -0.5868695974, 0.4651990831, 0.0277806502, 0.3595694602, -1.7833522558, -0.9235187769, + -0.1305120736, 1.2421206236, 0.7602189779, 1.3953794241, 0.3049729168, -0.5557566881, -1.0600878, -1.5434368849, + -0.4848669171, 0.6762301326, 0.3975794613, 1.4395723343, 0.6811670661, -1.5078858137, -0.2627333403, 0.4361654222, + -0.000891195, 1.0187122822, -1.0375159979, -1.604765892, -0.0847408697, -1.3486804962, -1.8990767002, -0.7349280119, + -0.1065333709, 0.6665663719, 0.521454215, -0.0061568609, 0.9659379721, 0.7524757981, -0.0891807601, 0.1273224354, + 0.8268703222, -0.1176565886, -0.7092362046, 0.2952494621, -0.2299559861, -1.0425001383, 1.2988185883, 0.5426243544, + 0.4739787579, 0.8060304523, 1.5848567486, -0.0154908923, -1.959674716, 0.0608664788, -0.822412312, 0.205733493, + -0.3345183134, -0.7199540734, -1.0148650408, 1.2570089102, 1.7332231998, 2.7068395615, 0.5335254669, -2.0145659447, + 1.3850419521, -0.8592329025, 0.6600543261, -0.421859175, -0.0107094571, -0.6457693577, 0.9560267329, 0.5790085793, + 0.0617983118, 0.3226754069, 1.0685539246, -1.2620589733, -0.234725967, -0.2421554327, -1.3379868269, 0.9540162086, + 0.5375425816, -0.1855080128, -0.8155971169, 1.2428810596, -1.7945463657, -0.0921459422, -1.4434609413, 0.1425899863, + 0.0288435649, -0.748508215, -1.0032165051, 0.7188972831, -0.9643496871, 1.1487607956, 0.7042000294, 1.0104765892, + -1.3018821478, 1.710434556, -0.2635222673, -1.3582605124, -1.5040088892, -1.0269665718, -0.6213265061, 0.1832721084, + -0.3864678442, 0.4071185589, 0.4705953002, -0.4236857295, -0.1801551133, 0.7529713511, 0.8858818412, 0.2697959542, + 1.4118680954, 2.3722064495, -0.9191628695, -0.9307866096, 0.3029454648, 0.9904204607, 1.2289518118, 0.4089305103, + -0.8350077271, 0.5419706106, -0.5536469817, 0.1028060094, 0.3641077876, -2.9135649204, -1.197627902, 1.7268692255, + 1.0548107624, 0.9957117438, -1.4481039047, -2.2000696659, 0.4746692479, -0.3013611734, 2.5931897163, 0.1785014421, + -0.9042234421, 0.722019434, 0.5479753017, 0.8089565635, 0.282501936, 1.6301807165, -0.9289301038, 0.775832653, + 1.787352562, -1.725217104, -2.6020746231, 0.5115439296, 3.2497107983, -0.5192397833, -1.0423642397, 0.0324750915, + 0.4287697673, 0.8982563019, 1.3349349499, 0.3121462464, -0.3937326074, 2.0630812645, -1.4304995537, -1.3159050941, + -0.0241598841, -0.7293787599, -0.365503639, 1.402761817, 0.1256354004, -0.0866579339, 1.6698479652, 0.6147372127, + 2.1514334679, -0.0860073492, 0.5820814371, -1.2603700161, 0.0365599617, 0.1094137803, -1.0534101725, 0.3607339859, + -0.9958238006, -1.4315663576, 0.7793776989, 0.1461087465, -0.1628145576, 0.3107595444, 1.3687645197, 0.5772598982, + -0.4336755574, 1.1175009012, -0.2714384198, -0.1034518629, -0.2754325569, 0.9069437385, -0.0283357389, -0.1800245643, + -0.1651595682, -0.5861871243, -0.4601516128, -0.0606546029, 1.5763812065, -1.0784891844, 0.9564955831, 0.9455194473, + 0.7763608098, 0.4902954996, -0.2564931214, -1.0015263557, 0.3603806794, -0.7381950021, 0.2104441971, -0.2726085186, + -1.466676116, -2.0567760468, 1.1105402708, 0.3748869598, -0.8810894489, -0.0609646738, -1.1932916641, 0.0129567189, + 0.5431383252, 0.6572669744, -0.6381964087, 0.6827172041, 0.2055616975, -0.4754789472, 2.6849081516, 0.9908787012, + 0.4223089516, -0.9532756209, -1.4316188097, 0.4283581078, -1.3681161404, -0.0958754867, 0.5441727042, 1.0810705423, + -0.0415074416, 2.5692317486, -0.322760433, 0.4241096675, 1.4338536263, -0.411426425, 0.001184009, 0.3396936655, + -0.7032704353, 0.0369640626, 1.9964704514, -1.0196714401, 0.2410306334, -0.6645501256, -1.9832742214, 2.1286649704, + -0.2816694379, 0.6200950742, -2.5297253132, 0.2783054113, -2.2589633465, 1.5027683973, -0.6791571379, 0.7946748734, + 0.5594283938, -0.4154709876, 0.0868373662, -1.17318964, -1.0965510607, 0.4667754173, 0.3479546905, 0.5917227268, + -0.1208579317, -1.989587307, 0.0767334402, 0.0827785879, -1.5488442183, 0.4962759912, 0.6963671446, -0.6112600565, + -1.9577354193, 0.9674578309, 0.7537819743, 2.4563322067, -0.0252350532, -1.5132838488, 1.22176826, -0.7690975666, + -0.2130514085, -1.222317338, -0.5371199846, -1.0274674892, 1.175295949, 0.0587048046, -1.2375228405, 0.4799143374, + -0.8488432169, -0.6043387055, 1.1303751469, -0.3233990967, -0.6648087502, 0.953989625, -0.3432818949, -0.545691371, + 1.2928091288, 0.6582537293, -0.336733222, 0.1220468283, -1.5532795191, -1.7195379734, -1.0341162682, 0.2998998463, + 0.8046797514, 0.4961921871, -0.6684690118, -1.5009387732, 1.2318353653, 0.3643293083, 0.4558056891, -0.7469726801, + -0.1064849347, -1.1267255545, 0.2651161849, -0.3827407956, -0.8086588979, 0.0461993329, 1.4123934507, 0.1515855044, + 1.557207346, 1.3240995407, -1.537234664, -0.264857322, -1.5860991478, 0.0319794863, -0.9175467491, -0.824665904, + -0.248365581, 0.1255396158, -0.5857534409, -1.9942765236, 0.0182692204, -1.7602024078, 0.3323732615, -1.4235423803, + -0.0769748762, -0.6448416114, 1.1782761812, -0.8038555384, 0.5822150707, -1.4353785515, 0.1170133278, -0.8189358115, + -1.2466543913, 0.6469664574, 0.9749919772, 1.2244031429, -0.2720718384, -0.0915584937, -0.6139442921, 2.7357959747, + 0.6321662068, -0.4468442202, 0.0670683905, -0.015264893, 1.4001054764, 0.8164184093, 0.2930732667, -0.6081119776, + -0.9192171693, -0.1245781928, 2.3893449306, -2.4778037071, 0.5976509452, -1.4283977747, 0.4154342115, -0.445466429, + 0.3893599212, 0.2045798749, 0.1197161973, -0.0726990327, -0.0892046988, 0.2428955585, 0.6287866831, -0.8733956814, + 0.1548168063, -0.8002090454, -1.39460361, 0.5990428925, -1.1735966206, 2.549478054, -0.7590735555, 0.1940673888, + -0.4431787431, -1.4156470299, -1.9468938112, 0.3451087773, 0.5958864689, 1.1357485056, 0.8258775473, -0.5660755038, + 1.9902119637, 1.3801629543, -1.783420682, 0.8641321659, -2.3902966976, 0.6164762378, -1.0545002222, 0.6365401149, + -0.6782473922, 0.5563191175, 0.7363837957, -1.8891561031, 0.0214900393, -0.7824299335, -0.2060978413, 0.3763463199, + 1.4707410336, 0.4039954841, 0.6742861867, -0.6028607488, 1.271997571, -0.7390785813, -2.4224550724, -1.2123428583, + 2.3222174644, -0.4605011046, 3.1352612972, 0.279430598, -0.5493283272, 1.0512810946, 0.1013304591, 0.3027843535, + 0.7218084931, 0.2959215641, 0.6120178699, -2.3468084335, -1.1663336754, -0.8147548437, -0.4591985345, 1.3389530182, + -0.0083134025, 0.0621182621, 1.239892602, -1.159947753, 0.0201061536, 1.5943176746, -1.495356679, 0.0830490291, + 0.2470071912, -1.912057519, -0.1153577715, -0.422701031, 0.8099350333, 0.0726526678, 0.8789698482, 0.6540535688, + -0.6828325987, -0.4248169661, 0.3941554427, -0.6652766466, 0.0736672878, 0.4986302853, 1.2773303986, -0.227682054, + -1.7044115067, -0.9628150463, 2.3503878117, -0.9085405469, -0.1369735599, 0.4999858141, -2.451146841, -0.1574627161, + -1.2132976055, 0.7054603696, -0.8242201209, 0.9384362698, 0.022200074, 0.5847182274, 1.7617032528, -0.7561365366, + -0.0969338343, 2.0506048203, -0.6521903872, -0.5247980952, -0.8815501928, -0.2154593319, -1.5231957436, 0.1173115671, + 0.8983911276, -1.5951839685, -1.7393609285, -0.4271378517, 0.2468763441, -0.6876968741, -0.8700183034, -0.3693754673, + -1.0298929214, 0.4024917483, -0.4774999917, -0.8142039776, 1.4894051552, 0.6848152876, -0.6682641506, 0.5156447887, + -0.0836239308, -0.159582749, -0.9284272194, 1.6347107887, -0.5399640799, 1.0173338652, 0.2623037398, -0.4373755455, + 1.2972157001, 0.9749194384, 0.9706473351, 0.6446200609, 0.8166325092, 1.1084922552, -0.1151099503, -0.09706489, + -1.690446496, 1.322522521, -0.7746454477, -2.2212016582, 1.1361017227, -1.3346679211, 0.4757602215, -0.9677015543, + -0.4630626142, 0.0695191398, 1.3389387131, -0.1383368075, -1.3319382668, 0.6405091286, 1.2340289354, -0.6869156957, + -0.4758132398, -1.9471237659, -1.288662076, 1.2084196806, -0.5310587883, -1.322753787, -0.7771701813, -0.0368499942, + 0.4158807993, 0.3814026713, 1.0844006538, 3.4120693207, 1.734533906, -0.0976254642, -0.2757738233, -0.835835278, + 0.1355589926, 0.7318641543, -0.3644649684, 0.3209478557, 0.2786023319, 0.7931556106, -0.5511992574, -0.4364145994, + -1.2345582247, 0.353189677, -0.1258494258, 1.9726265669, 1.506960988, 1.074499011, 0.7512360215, 0.5726920962, + 0.0459811017, 0.624935925, 1.7143579721, 0.9048161507, -0.1954852939, 0.0158866066, -0.4643318653, -1.1683137417, + -2.2276227474, 0.8133713007, -0.5477312207, 1.1287671328, 0.4268198907, -0.4344830215, 0.5964285731, -0.5707772374, + 0.1042475775, -0.2392384261, -0.3934238553, 2.3036134243, -0.9504826069, -0.6469936371, -1.0541242361, 0.0337269567, + -0.7810605168, 0.9689751267, 1.9031298161, 0.2525197864, 0.1838586181, -0.2395608574, -0.52379632, -1.1532931328, + 0.4638881385, 0.4851041436, 2.1061365604, -1.5883505344, 0.677346766, 0.9099257588, 0.4675730467, -0.5751948953, + 0.8763380051, 0.7442619205, 0.0406341441, -2.2689523697, 0.7088384032, 0.2085940242, -1.646050334, -1.2184493542, + -0.8154140115, -0.2806397378, 0.2383890152, 0.7780022025, 0.7270069718, -1.3557515144, 1.2708170414, -0.1392763555, + -0.3877072334, -1.4174968004, 0.3400408626, -0.8829170465, -1.9422985315, 1.4105211496, 0.4198240936, 0.3245728314, + 0.0032399215, -0.4103808403, -0.1612507552, -0.389388144, 0.5924805999, 0.0768460557, 0.2591560483, -0.7614800334, + -0.4818507731, 0.3876158595, -1.8072429895, 0.6448305845, -0.4991023242, 0.2990922332, 0.761139214, 0.2680123746, + 1.9994397163, 0.364074856, -0.2594336271, -1.1131106615, -0.8219708204, 1.1891075373, -0.1939040869, -1.7173801661, + 0.2022092044, -0.5829202533, 0.5355664492, -1.4946354628, 0.9865855575, -0.8716754317, -0.9377834797, 0.3892740905, + 0.6675186753, 2.0363080502, 0.9215611815, -2.0991868973, -1.0165593624, 2.0159192085, 0.4246093333, -1.3649692535, + 0.817753911, 0.1407611221, -0.7992921472, -0.2672897279, 0.7641906142, -0.3375808597, 0.2430761158, -0.21302329, + -0.4740942121, 1.6659946442, 1.5688807964, 0.1841378659, 0.4639534056, -0.5424900055, 1.4749709368, -1.3607293367, + -0.6117712259, -1.2864717245, 0.7173013687, -0.8206724524, -0.8166086674, -1.1200137138, -0.1569412053, 0.4703750908, + -0.7065168619, 0.4275971949, -0.3475115299, -0.7177425623, 1.2331171036, 0.1298312247, -0.911008954, -0.1160564497, + -0.1007026881, 0.1473488063, -0.0265515819, -0.1134301201, -0.6335337758, 1.0367230177, 1.2019270658, 0.290376246, + 0.8871808648, -1.321103096, -1.2637345791, -0.347881943, 2.6312584877, -0.0779268518, -0.0033409558, -0.6762089133, + -0.2439787388, 0.8177816868, 1.4604249001, -1.5679810047, -0.133983463, -0.1631641537, 1.5747507811, 0.1084988192, + 1.4038569927, -1.6337524652, 0.017757589, 1.0167950392, -1.6949776411, 0.0757225081, 1.4419057369, 0.255604893, + -0.6593601108, -0.2549015582, -0.9439916611, -1.8636031151, 0.3080304861, 0.4328792691, -0.7933393717, -0.2392593324, + 0.4455813468, -1.1091521978, 0.6833079457, -0.1153917611, -1.4299768209, -2.4306547642, -0.458900094, -0.976703167, + -1.152559638, -1.1114211082, -0.6227270365, -0.3940295875, -1.1870974302, 0.3540764153, 0.821308732, 0.5123792291, + -0.0097675789, 0.7527971864, 0.4728479683, 1.2856576443, -1.5182529688, 0.7346980572, -0.184711203, -0.7216877937, + 1.3291749954, 1.1263566017, -0.7484042645, -0.2636847794, 0.0217362791, -0.93757689, -0.7247433066, -0.041502472, + 0.0492623039, -0.7459357977, 1.1220898628, -0.5154392719, -0.477691561, 1.5804840326, 0.8040207028, 2.2452106476, + 1.733500123, -2.4033691883, -0.290751785, 1.062051177, 0.9767885208, 0.263233453, 0.5237601995, -0.5357385278, + 0.486803472, -2.427021265, 1.2570142746, 0.2010706663, 0.6235077977, 0.7071534991, -1.2176045179, -0.515252769, + 0.3981330395, 0.2556486428, -0.5797071457, -0.626716733, -0.968470633, 0.2104416192, -0.812451005, 0.7867467999, + 0.5026560426, -0.0581949949, 1.6213607788, -0.0828385055, 1.9328351021, 1.7954280376, 0.2441668212, 0.4763677716, + -2.6320970058, -0.0609419681, 0.413841188, -2.8224081993, 0.8544120193, 0.3406496048, -1.3216235638, -0.1166282445, + 0.0615011118, -0.9227725863, -0.7776309252, 0.6261429191, 0.6446788907, -0.285253346, 0.4866887033, -1.7207942009, + 0.3032245636, -0.7486038804, 0.2438063323, -0.2671179175, -0.3899340332, 0.0800387189, 1.1771892309, -2.897783041, + 0.5417762399, 0.5842677355, 0.5015832186, -0.4940728843, -1.4268690348, 1.7689621449, 1.7392749786, -0.3849787414, + -0.9646254182, -0.1681044698, 0.1822709441, 0.6294948459, -0.4607347548, -0.4217625558, 0.4491379857, -1.9762825966, + -0.8236123919, -0.6104609966, -0.3675303161, -0.7454993129, 2.4073290825, 1.1063375473, 2.4108457565, 0.2904265821, + -0.0319271833, -0.1898043603, -1.1604915857, 1.1043064594, -0.4222970903, 0.1301062554, 0.3959206343, -0.161754027, + 1.0322108269, -1.7450871468, 0.2481280863, 0.5010092854, -1.0896248817, 1.2918280363, 0.1254145205, -0.9438206553, + 0.5197620988, 0.8137003779, -0.5376303196, 0.2467346787, -0.6972445846, 0.9036880732, -1.7012495995, 0.1490175277, + 1.6514542103, -0.3002925217, 0.6282120943, -0.0789799169, -0.5649306178, 1.1362684965, -0.1409714818, 0.7433593869, + -0.466172576, 1.0111490488, -0.1314715445, -0.2794724107, -0.5579557419, -3.0807359219, 0.6628274322, -0.4908138514, + 0.2899478078, -0.0956695154, 0.4372552633, -1.0438014269, -0.1414678246, 0.0443393439, -0.0560218208, -0.4559345841, + -1.9249411821, -2.0573368073, -0.0334194154, 0.0930603072, 1.3541816473, -0.0132205859, 0.1044306085, 0.2731702626, + -1.0667283535, -1.3606183529, -0.3784544766, 1.4905642271, 1.3429602385, -0.7809277177, -0.3124582767, 0.160304144, + 0.7163369656, -0.5278331637, -0.8617659211, 0.070730634, 0.5078257918, 0.5343469381, 2.7920517921, 1.108042717, + 0.6272335052, -0.2741323411, 0.5719816685, 0.7550273538, 0.8943145871, 0.1229175404, -0.6765108109, 1.5254110098, + 2.3936822414, 0.823693037, -0.1658976078, -0.5570540428, 0.1447302103, -0.0118487366, 0.2371482849, 0.2607527077, + -0.3373178542, 0.0334553272, 0.4224862456, 2.357929945, -0.2408792973, -1.9752658606, -1.0364269018, 3.8317902088, + -0.9200903773, -0.6679349542, -1.6793940067, 1.1850756407, 0.0062380657, 0.9284568429, -0.1546033323, -0.8065575957, + -0.3873867691, 0.6424305439, 0.2068197876, 0.1537742168, -2.0683746338, -1.7794313431, -0.9078343511, 0.3276721835, + 0.0317510068, -0.9162718654, -0.9382501841, 0.8591877818, 0.020597266, 0.3160986602, 0.4791103005, 2.358597517, + 1.2266488075, 0.0675020814, -0.0706233829, 0.1332499087, -1.2125068903, 0.9365451932, 0.1137873232, 0.2121182531, + 0.9187198281, -0.9210603833, -1.361818552, -0.8186307549, 0.2531672716, 1.0069762468, 0.8433437347, 1.1979171038, + -0.5553349257, 1.0772843361, 0.3243967593, 1.4009695053, -0.7212144732, 0.2164977342, 0.1635417789, -0.4878661633, + 0.2016631365, 0.6704857945, 0.134365499, 0.9387943149, 0.0494832285, -0.1038764939, 1.4206699133, 0.1582160592, + -1.6772825718, 2.013384819, 0.1406247765, -0.4359038472, 1.9959181547, 0.0242856946, -0.982689023, -0.849707067, + 0.9738262892, -0.9124195576, 1.5310759544, 1.1907900572, 0.8818747997, -0.2512267828, -0.4001435935, -1.614205122, + 0.7161724567, 0.1099669784, -0.7687640786, 0.1460857093, -1.2593784332, -1.1577454805, -0.8739498258, -0.1982318014, + -0.40738675, -1.3021171093, -0.1136029884, -1.5907045603, -1.1428781748, 0.1213455573, 0.3092034757, 0.0334026329, + -2.4200618267, 3.3238034248, 1.1879281998, 1.9430119991, 0.2992740571, 1.6709127426, -0.3273898959, 1.4901436567, + -0.6158698797, 0.9194712043, -1.7540516853, 0.4838142991, 1.2830245495, 0.5275840163, 0.8925089836, -0.4407205284, + -0.0098689431, 1.5410522223, 0.2787226439, 0.6298201084, -1.2696967125, -0.1690566242, -1.3529920578, 0.4250549376, + 1.9450334311, 0.9914284945, -1.6382533312, -0.4501300156, -0.0474638417, -1.669770956, 1.3145624399, -0.8170112371, + -0.8111792803, -1.0784217119, -0.3456541896, 0.4999735057, -0.4648705721, -0.7333679199, 0.0848675817, -1.6081210375, + 0.0173648894, -0.0103555061, 0.8468238115, -1.1412696838, 0.3661522269, -0.4450252354, 0.8290936947, 1.1968002319, + 0.5475606918, 0.0861864313, 0.5601829886, -1.5211524963, -0.5370119214, -0.5964001417, -0.5213727951, 1.0056358576, + 0.3153733909, -0.8991996646, -0.5396741033, 0.9581548572, -0.5757839084, -1.0513538122, 1.161123395, 1.8634634018, + 0.4477458298, -0.2449746579, 1.5770003796, -0.2315210402, -0.3703002334, 0.0056428425, -0.4994624555, 0.0295562055, + -0.0041788672, 0.8292986751, -0.0069422261, 0.4954382181, -0.724794209, 1.1682143211, 0.0745441839, 0.0941772833, + -0.7176083922, 0.8280134201, -1.6582189798, 0.6430417299, 0.1367926598, 0.7049418092, 0.0571377203, 1.1631231308, + 0.6296694875, -0.0647290796, -1.2796778679, -0.5895133018, 0.8610818982, 0.374376446, -0.8071950078, 1.3061199188, + -0.880333662, -0.00791167, -0.5633738637, 0.3912031353, -0.1816237271, -0.159517467, -0.8321972489, 0.2964517474, + 0.9229819775, 1.4701541662, 0.6736425757, 0.5532526374, -0.1107472777, 1.7293556929, -0.5153669119, -0.6763880253, + 0.2341462821, -0.5053901076, -0.1485505253, 1.2039222717, 0.4330215752, 1.6672991514, 0.3798584044, 0.5994235277, + -0.3695307672, 0.6090422869, -1.8857115507, 1.035746932, -0.6409605742, 0.5081863403, 0.8336287737, 0.2464233786, + 0.1892288029, -1.5773829222, 0.7635652423, 1.6710473299, -0.3723566532, -0.0935106426, 0.400465548, 1.6516311169, + -0.0239151251, 1.346019268, -0.0556113571, 0.7014779449, -1.1409986019, -1.9849413633, 0.7863185406, 0.1040583923, + -0.5113148689, -0.6147990823, -0.133439064, -0.8577879071, -1.689669013, 0.0303357765, 1.0349303484, -1.3887677193, + 1.4465106726, 1.4462199211, 0.969553411, -0.9796079397, 1.0599244833, -0.3817900717, 0.5725802779, -1.0808739662, + 0.6993675828, 0.0584711172, -0.5152519345, -0.377368927, -0.9231536388, -0.0607250929, 2.4555163383, -2.20779109, + 1.5051277876, -1.2260414362, -0.2329563051, -1.236689806, -0.3229627013, -1.4195483923, -0.1831594706, 1.790626049, + 0.2295542806, 0.2179629952, 0.3471575677, 0.231394425, -0.0609209612, -0.1078507155, 0.4665036798, 1.1243994236, + 0.9174999595, 0.2093791664, 1.6390047073, -1.3195793629, -0.1680346727, -0.517340064, 0.6296047568, 1.0929300785, + -1.5066785812, 1.2682543993, -0.3669987917, -0.0628513321, -0.3588504791, -0.8302126527, 0.2542398572, -0.3541894555, + 0.850720942, -0.6196182966, -1.1007553339, 0.5014449358, -0.8606661558, 0.4498639703, 0.219186306, -1.452583909, + -0.1573316753, -0.3670399189, 1.1949836016, 1.2781003714, -0.3769445121, -0.899895668, -0.1330458224, -2.1117086411, + -0.3949528337, 1.414347291, 0.0138987098, 2.0456752777, -1.7744398117, -0.0091569005, -2.683021307, -0.2830215991, + 0.5834649801, 2.3459873199, -0.9336617589, -1.0544435978, 0.9978377223, 0.8136739731, 0.8705741763, -0.449051708, + -0.4460271597, -0.8419141173, 0.258462131, 0.2546221018, 0.082949318, 0.1972437054, -2.2637302876, -0.3299877644, + -1.9285436869, 1.0270245075, -1.5507107973, -0.4767905176, 0.3876853883, 0.9809426665, -0.6491833925, 0.2031453401, + 0.8613374829, 0.9279358983, 0.3166069984, 0.3596234322, 0.0556599312, 2.6604681015, -0.3559695184, -0.8140570521, + 1.2609890699, 0.7009537816, 1.6023476124, -1.6866204739, -0.3539562225, 0.2053398639, -0.1173354909, 0.0861274227, + -3.4895308018, -0.4967344999, -0.014524024, 0.3744366169, -0.9175367355, -1.456815958, 0.7877227068, 0.6968756914, + -1.1660602093, 1.4751977921, -0.1938352287, -0.026474338, -1.3262991905, 0.0237702597, -2.4104363918, -0.6477180719, + 0.5059946775, 0.3510814011, 0.3875126243, 1.2187185287, -0.2408093661, 0.6088964343, -0.3309341669, 1.8326859474, + 0.2369977683, -0.3282163143, -0.2274724394, -0.2073322684, -1.0838879347, -2.1840865612, -0.4663523138, 2.0218403339, + 0.9449817538, -0.9978976846, 1.3662493229, 1.7149190903, -0.2701505125, -0.845148623, -1.6304798126, -0.7960706353, + 1.2277041674, -1.7852749825, 1.2480875254, -0.3981883824, -0.7367050648, -0.413523823, 0.5079085231, 0.0900633857, + -1.299095273, -0.6961169243, 0.3780362606, 0.9619675279, 2.1818091869, 0.4237046242, 0.6840161681, 0.6984956861, + -0.251424998, -1.729378581, 0.366774261, 1.1325265169, 0.7683765888, -1.1529784203, 0.4323818088, 2.3151834011, + 0.3081058562, -0.6248998046, 0.5047844052, 0.6498021483, 1.7978770733, 0.3899771869, -0.4997722208, -0.1578063518, + -1.9672470093, -0.3175988495, -0.0856336206, -0.9187674522, 0.9462944865, -0.1890290082, 0.0526048094, 0.7671905756, + 0.0052128769, 0.6099808812, 0.550796628, -1.3356704712, 1.1185127497, -1.0913438797, 1.2091479301, 0.7399811745, + 0.1125142574, -2.0963685513, -0.2536096871, -1.4916297197, 0.6988286972, 1.0503125191, -0.7035870552, -0.464975208, + 0.3794374168, 0.7661656141, -0.5972264409, -1.0623397827, -0.0284309927, 1.3018770218, -0.942818284, -0.2252209038, + -0.3813332319, -0.9502642751, 0.0767621696, 0.7689592242, -0.0794237703, 0.2420342267, 1.4336521626, 1.525097847, + -1.3550601006, 0.5420228243, 0.759508431, 0.1850525141, 0.9257733226, 0.2702014446, 1.1696821451, 0.8106309175, + -1.0838518143, 0.4734386802, -0.4565702081, 1.3057682514, 1.4480742216, -0.5279594064, 0.6467399597, 1.6548110247, + -0.0588355176, -1.4721015692, -0.9004341364, 0.0964303613, -0.6494836211, -1.2516726255, -1.543027997, 1.6699434519, + -0.2119133621, -0.3817618191, 0.3938360512, 2.3915538788, -1.0785287619, 1.3833017349, -0.5712346435, 0.0911998898, + 1.0019682646, 0.4382897615, 1.1474125385, 1.1693954468, 0.1031880304, 0.7955002785, 1.3405262232, 0.0209042039, + 1.6260020733, 0.3945917785, -0.3832558692, 0.7924461961, 0.0312300827, 0.7102786899, -1.763406992, -1.3943989277, + -0.7769746184, -2.2571027279, -1.1994607449, 1.0450494289, 0.3268254697, -0.6890351772, -2.0280230045, -0.4204472303, + 0.4531336129, 0.1239523813, -1.0549724102, -0.4190306664, 1.0953723192, 0.2018714398, 0.7987915874, -0.2929423451, + -0.1676543951, 0.5970343351, -1.2773684263, 1.2236326933, 0.9840433598, 0.1225740537, 1.1968276501, -0.3415886462, + -0.6405214667, 0.763861835, 1.5436466932, -1.0006358624, 0.1138499379, -1.074170351, -1.5411993265, -0.7750322819, + -0.9824083447, 1.0209515095, 0.7557222247, 1.0524106026, 0.2535609007, -0.3112972081, 1.793299675, -1.2139261961, + 2.094689846, -0.0090470267, 0.6447563171, -0.7594442964, -0.1354953796, 0.066069141, -1.0660305023, 0.8187485933, + -0.3587822914, 0.4471886158, 0.8411183357, 0.569324255, -1.4816662073, -0.768918097, -0.7788417339, -0.9212349057, + 0.7576090693, -1.2389307022, 0.6051481366, -1.1756383181, -1.2799351215, -1.8131713867, -0.0544976145, -1.594758749, + 0.1935119927, -0.3740875423, -1.1885846853, -0.0792386606, 1.1125651598, 0.3793795705, 0.5841192603, 0.0571746901, + -0.1136863083, -0.5652914047, 0.7779823542, 0.4327304661, -1.0822675228, 1.0263322592, -0.4865728915, 0.0487550497, + -0.2343792617, -0.2356239855, 0.0258828122, -1.5499720573, 0.283983767, 0.0145347295, -0.1443930119, 1.149387002, + -0.6262537241, -1.719632864, -1.7135055065, 0.429522723, -1.3662779331, -0.4895913601, 0.2493050396, -3.3102571964, + 0.4204231799, -1.091057539, -0.9758739471, -0.1436772048, -2.1989107132, 0.3001672029, -1.7423200607, -0.5652357936, + 1.4203227758, 0.3454657495, -0.8482355475, -1.0011060238, 0.8571538925, -0.4992506206, 0.7553210258, -0.870388031, + 0.7454122305, 1.4743127823, -0.3983528912, 0.8992680907, -0.8724070191, -0.4594956636, -0.2891397178, 1.6464035511, + -0.5800548196, 0.1192378998, 0.3251797855, 1.5719088316, 0.2433685362, 1.6238752604, 0.9168971181, -1.7127541304, + 0.4310311675, -0.2766275108, 1.5945236683, 0.7060499787, -0.2566100061, 1.0110602379, 1.4094588757, 0.9080002904, + 2.1751139164, 1.6054965258, 0.9616665244, 2.2810950279, 0.4121274054, -0.0153397154, -0.3080755472, 1.4366900921, + -0.4038511515, 0.7201999426, -0.7327430844, 2.0949237347, 0.039317362, 2.2166905403, 1.2483799458, 0.471136868, + -0.4010816813, 0.7753511071, -0.5172150135, 0.3040603995, -0.2500374317, -1.0669492483, -0.0891368464, 0.0055941949, + -0.9773228765, 1.102319479, 0.4938498437, -0.5543298721, 0.090633221, 0.0505249016, 0.5267651677, -0.5476112962, + -1.304954052, 0.8578358293, -2.0298936367, -0.1674510688, -1.0671063662, -1.4121545553, -0.9709029794, -0.3150966167, + 1.924446106, 0.4939165413, -0.0465229526, 0.4197863042, -0.4554887116, -0.8888947368, -0.4829266965, -1.9815404415, + -0.1060535312, -1.4770417213, 0.6611261964, -0.8000780344, -0.0008512373, 0.0904324129, -2.3193302155, 1.2738482952, + 0.8960350156, 0.3338158429, -0.8541143537, 0.3179859519, -0.2948468626, 2.4262568951, -0.6027595401, -0.1137509346, + 0.391390413, -1.4957355261, 0.4632006288, -1.5061677694, -0.0406272337, 1.3672878742, 0.9088773727, 0.0280201621, + -0.3759260476, -0.5266292095, -1.6783390045, 0.7885782123, 0.3884814978, 0.5505877137, -0.2127685249, 1.5057326555, + -0.3375179768, -0.4418465793, 0.7669808865, 0.4645462036, -0.4733898342, 0.0666616634, 0.6061386466, -0.4868551195, + 0.4049857855, -1.6582262516, 1.4912316799, 0.1251794696, -1.2685055733, 0.3584597707, -0.0061725895, 0.1182529852, + -0.4459925294, 0.0649669096, -0.5827793479, -0.9905433059, -0.9163452387, 1.7737463713, -0.4419859648, 1.9480772018, + 1.4152547121, 0.988528192, -0.7954316735, -0.6662418246, -1.1790033579, -0.2741505206, -2.067899704, 0.3266300261, + 1.3303706646, -0.2867909372, -0.9021807313, 0.2714713812, -0.5843097568, 1.20976758, 0.2966309488, -1.0622887611, + 0.6333710551, 0.383386761, 0.2917357981, -0.5103815198, -0.3244171441, 1.2576582432, 0.9913121462, -0.1317096502, + -0.5059637427, 1.108525753, 0.1522968709, 1.1645395756, -1.2047892809, 2.2415204048, 0.1009635627, -0.1189174354, + -0.3255894184, -1.5088373423, -0.1761455089, -1.2958545685, 0.4631999731, -1.4431842566, -0.0815225467, 0.0264114328, + -0.0134794405, -1.7359671593, -0.8405629992, -0.0171891171, -1.5212892294, -1.3272206783, 0.3295044005, -0.3159745634, + -0.4405059218, -1.2775102854, -2.0660405159, -1.3951530457, -0.3871063888, -1.9635423422, 0.387839824, 0.2240091264, + -0.6311438084, 1.1141709089, 0.2829698622, 0.1319483519, -0.9153652787, 1.4351322651, -0.6812025309, 0.134774521, + 0.8289664388, -0.1638492942, -0.8752292991, 0.67419523, -0.8481402397, -0.4189682901, -0.8234933615, 0.2876498699, + 0.0553242527, -1.3581985235, 0.1725343168, 1.4257600307, 0.3076897562, -0.6096960306, -0.6603984237, 0.265702039, + -0.3375091851, 1.0193190575, 0.3068545163, 0.304969877, -0.8007757664, -1.4549874067, -0.738497138, -1.3470081091, + -1.8314106464, 0.0719065815, -0.4571023285, 1.0792492628, 2.2859106064, 0.2279076427, -0.9891816378, -0.6099649668, + -0.6531402469, 0.4977306128, 0.8263016343, 1.8157972097, -2.3561737537, 0.7034680843, 0.321691364, -0.2272416651, + -0.8027136326, -2.7809767723, -0.7257278562, -0.227312535, 0.2905314267, -0.321531415, -1.8055938482, 1.4343173504, + -0.9048855305, 0.1905162185, 0.0468965657, 0.8480873108, 1.7085329294, 0.4332759082, -0.3628672361, -0.6735289097, + -1.1163346767, 1.3994438648, -0.4484830201, -0.9012812376, -0.4600181282, -0.4331746101, 0.1538828015, 2.2690322399, + -0.1937780529, 0.1015669405, -0.5000990629, 0.1091853082, 0.6234668493, -0.4246721566, -0.0613945201, -0.8901450634, + -1.1397343874, -0.8808919787, -1.033207655, -1.159952879, 0.0582559519, 1.4459686279, 0.1238117516, -1.9827600718, + -1.5158689022, -0.6710330844, -1.8118439913, -1.6237982512, 0.0679273456, -1.3040943146, 0.3018227518, 1.190734148, + -0.0415180326, -3.0691003799, -1.371987462, 1.0663380623, 0.4812533259, 0.4310096502, 1.4828522205, -0.5797268152, + 0.4582100511, -0.6201152205, 0.1096500233, -0.6994256377, 0.3923276663, 1.5864090919, -0.922034502, -2.6383047104, + 0.1972300112, -1.777581811, 1.6898244619, 0.5709993839, -0.5445369482, -0.2049824893, -0.4456205368, 0.4843392372, + -1.4021123648, -1.1148446798, 1.3989207745, -0.1107301638, 1.9977177382, 0.0048229685, 0.680493772, -0.4943865836, + 0.0055954242, -0.8179009557, 0.6151177883, 1.747100234, 0.562836051, -0.6135786772, 0.1982985437, 0.38136518, + 0.1579486132, -0.7328537107, -0.0750542954, -0.1824423671, 1.0054148436, -0.0228289776, -0.3487198949, -1.0940510035, + -0.7222530842, -0.6091982126, -0.6036486626, -0.2050597668, 1.1312741041, 2.0681664944, 1.1864436865, -0.2236890197, + -0.8625605106, -0.7263569832, 0.3035775125, 0.0642245412, 0.4337040782, -0.2739275396, -0.3962904513, 0.8403483033, + 1.0489102602, -0.4937454462, -0.5222024918, 2.6116652489, 0.135298565, 0.0618634447, -0.3024633825, -0.8286788464, + 0.1451219916, 0.5880844593, -0.6094891429, 0.3219236434, -1.3695703745, -0.0585177056, 0.1700653136, 0.4964697361, + -0.9321046472, -0.1507416666, -0.3361282051, -1.9466036558, 1.1729111671, -0.2739106417, 1.6313178539, -0.1329207718, + 0.2038348913, -0.7290941477, 0.8423547745, -0.1522175819, 0.0712911412, 0.9698452353, -0.7045807838, -0.3561033309, + 0.0883658156, -0.4302078485, -1.2478718758, 0.4989421368, -1.7669965029, -0.4198913872, 0.6975441575, 0.4738608301, + -0.0651089847, 1.0222551823, -0.5519806147, -0.3389316499, 1.5764091015, -0.7053538561, -1.2888039351, 0.3234673142, + -0.1417339593, 0.9278524518, -0.2274197787, 0.7508451343, 1.4466332197, 0.6488268971, -0.9954628348, -0.6652079225, + 0.2864868939, -0.3673034012, -1.4958170652, 0.2327007651, -1.548006773, -1.3630514145, -0.444354862, 1.6024609804, + -1.0053298473, 0.7348178625, 0.8800488114, 0.8419062495, 0.0995379835, -0.2248645723, -0.5294179916, 0.316032052, + 0.0924004465, -0.4043036699, 0.8951402903, -1.2198828459, -0.0668722764, 0.4917221963, 0.5889586806, -1.8725498915, + -1.7988634109, 0.3151299059, -1.3311706781, -0.4863022566, -0.3315199912, -0.1942166537, 1.7517579794, 0.2368437648, + 0.5656731129, -0.0282656793, 1.7823673487, -0.1720479727, -1.3562507629, 1.0161684752, -0.9181568027, -0.6771322489, + -0.2678036094, -0.6415093541, -0.9906380773, 1.3346472979, -0.7320179343, 0.6933484674, -0.3105112314, 0.0937701985, + 0.5368575454, 0.013008453, -0.96733886, 0.5386470556, 0.1005189866, 2.0324866772, 1.2055453062, 0.82208395, + -1.55600214, 0.1882465482, 1.6134934425, -0.0579883754, -0.4294087291, 2.3164374828, 1.3468019962, 0.7022433877, + 0.2779477239, -0.5003404617, 0.8945329785, 0.2074485123, 0.0166519284, 0.9358554482, -0.3249890804, 1.4698566198, + -0.4166862071, -0.5823774338, 0.6684930921, 0.0280649178, -0.3356093764, 0.5318160653, -1.4786239862, -1.0148028135, + 1.184961915, 0.239174515, -0.6188251972, 1.0286505222, -0.7010456324, -0.5719571114, 0.155366227, 1.0689032078, + 0.0141669363, -0.081792675, 1.2871496677, 0.897337079, 1.0335407257, 0.5311743021, 0.2168038338, 0.3711017966, + -0.7261734009, -0.683660686, -0.4303300679, -0.9623488784, -0.2232476622, -2.8081274033, -0.1310659349, -0.13540335, + 1.319942832, -0.4372418821, 0.3999006748, -2.7013614178, 0.2619364262, 0.1507003158, 0.0715506971, 0.8289863467, + 1.2401783466, -1.0547454357, -0.0138927512, -1.1025797129, -1.3504421711, 1.4697799683, -0.4074902534, -1.1207348108, + 0.0986788496, 0.3246071041, -0.8392274976, 1.0582296848, 0.2235145271, -0.5397490263, 1.1688777208, 0.2009891868, + 0.1039046645, -1.000926137, -0.8749092817, -0.2685181201, -1.0310175419, -0.4049829543, -3.1205077171, -0.3098204732, + 0.5935285687, 0.1903157085, 1.1804158688, -0.3473457992, 0.8149939179, -0.7612107396, -0.8262937069, 0.6924495101, + -1.3365644217, -0.7892350554, 0.134341836, 0.7926063538, -0.1322494149, -0.4287471771, -0.3642910719, 0.1303860843, + -0.1418085694, -1.5912516117, -0.0276062898, 0.4361262321, 1.0095407963, -0.0749416277, 0.2285602689, -0.1831205785, + -0.0460781157, 0.2784950733, -1.8076405525, -0.3249053955, -0.7071861625, -1.1327867508, -0.070049338, 1.8727740049, + -0.9032890201, -0.4349606037, 0.410433352, 0.6316285133, 1.0076644421, -0.8771318197, -0.9682021737, 0.4976361096, + 0.809102118, -0.0814546943, 0.1587979943, 0.5097995996, 0.5882976651, 0.530893147, -0.0849480703, 1.5427222252, + -0.3993819952, -0.6722313762, 0.6797321439, 0.3277135193, -0.0085896691, -0.3661646247, -0.9072237015, -0.4623303115, + -0.2023209929, 0.6599558592, -0.7539873719, 0.8019641042, -0.1096544489, 0.0187816937, -0.2943032682, 1.1049185991, + 0.8500798345, -0.8090435266, -0.9830206633, -0.2533683479, 1.5624762774, -0.804250598, 0.0995938256, -1.030326128, + 1.0731709003, 0.512650311, -0.3870714307, -1.0472843647, 0.3077230453, -1.7716023922, -0.1703357995, -0.3809374273, + 0.2320100963, -1.017768383, 1.2246047258, -0.6436703205, -0.2181359231, 1.54205966, -1.2188315392, 0.5913078785, + -1.0695223808, -1.0774040222, 0.4448950589, 1.1289564371, -1.232216835, -0.9961451292, 0.1253382862, -1.2857888937, + 0.8030779958, 0.55831635, -0.6780901551, -0.0292556807, 0.6156740189, 0.6637461782, -0.2593209445, 0.1577128321, + -0.6255224347, -0.5165698528, 1.3434090614, -0.137376979, 0.8557762504, 0.7699329853, 0.0583121888, -1.5436519384, + 1.296626687, 0.5823848844, -0.305834949, -0.130080089, -0.3919242322, -1.1922485828, -1.0443159342, -1.552968502, + -2.7964434624, 1.2522928715, 1.2292847633, -0.2496839911, -1.6875931025, -0.2166756839, -1.1366854906, 1.1348092556, + 1.0292310715, 0.2931405902, -0.0401573479, -0.916851759, 3.1208748817, -3.02470541, 0.1153336465, -0.2590649724, + -0.5816124082, 1.8359223604, 0.8361560702, 1.3724067211, 1.9320363998, -0.8699535131, 0.3323044777, 0.9254535437, + 0.9190768003, 2.0381422043, 1.0914663076, 0.7399589419, 0.6411070824, 0.1178541556, -0.8540045023, 1.2046840191, + -1.7498428822, 0.1689570099, -0.7534065247, -1.4080204964, 1.3100963831, 2.1610531807, -0.6405741572, -1.1049610376, + -0.5449877977, -0.2860692143, 0.3250898123, -0.9200837612, 0.988445878, -0.5333630443, -0.6851798296, -1.0003677607, + -1.5293353796, 0.0621513054, -0.0578085035, 0.6272996068, 2.0618607998, -0.2794499397, -0.4480098784, 0.1708033234, + 0.848847568, -0.0460077003, 1.1200356483, 0.3858909607, -0.1463131756, -0.850009501, 1.1876649857, 0.8287144899, + -0.3788069487, 0.2699967027, 0.7841120958, 0.9621093869, 1.0886086226, -1.4207915068, 0.8679859638, 1.1370193958, + 1.1478097439, -0.0892617479, 0.4420532882, 0.4368574619, -0.161666587, 1.2207653522, 0.3205839992, -1.3781871796, + -0.5439456105, 0.6632543206, -0.2686441541, -1.0038115978, -0.1014877558, 0.5503932238, -1.3899176121, 0.0010357754, + 1.5733733177, 0.4335486889, 0.0456469469, 1.9128178358, 2.615768671, 0.3550651968, 2.7038369179, 1.0162559748, + 0.656716764, 1.4713921547, -1.3117628098, 1.0215899944, -0.9033085108, -0.1266045272, -1.4393845797, 1.2639056444, + 0.7589184046, 0.8724140525, 0.3952097595, 2.1992070675, -0.5563782454, 1.0330309868, 2.2867393494, -0.6047636867, + 1.7792675495, -0.8073445559, 0.4877997935, -0.2104053199, -0.7016320229, 1.4434002638, 0.0233583841, 0.4562973678, + -0.4751683176, 0.4907547235, -0.1294404715, 0.5382491946, -1.3764859438, -1.3180493116, 0.6598469019, -0.9768490791, + -0.5608139038, 0.7176390886, 1.1750555038, -0.1087838933, 0.8607848883, 0.0236848835, -1.5650117397, -0.8263857365, + 0.2376575172, -0.321641624, -0.0618195906, 0.5945374966, 0.322309196, 1.4338846207, -1.7596757412, 0.0521411188, + 0.6781387925, -1.2394995689, -0.9775453806, 1.7855298519, 0.4754302204, 1.0716226101, -0.0919560567, 1.017223835, + -0.3709467351, 0.117537722, 0.3524052501, -0.0831708163, -1.4916843176, -0.0503998026, -0.659922421, -0.2826690972, + 1.7006320953, -0.6317148805, -0.3335561156, -1.8706378937, 0.4418658316, -0.9441236258, -0.3783243299, -0.9927918315, + -0.3547174335, -0.6230579019, 0.2012146562, -0.4615501761, 0.6221498847, -0.2511247694, -1.4008331299, 0.3153209388, + -0.1327913404, -1.9306480885, 0.2888429463, -0.1532785892, -0.7431642413, 0.3893904388, 0.5003846884, 0.5587242246, + -0.7005661726, -0.5150581598, 0.6435684562, 0.3248820007, -0.8303997517, -0.6451705098, -1.5633621216, 0.4436821043, + -0.5834668279, 1.4078401327, 0.9660906792, -0.2825075686, -2.9486505985, 0.4625095129, 0.3063019514, -0.4668817818, + -0.8732379675, -0.3178085983, 1.3156703711, 1.1733013391, 0.0139046516, -0.7732798457, 1.615445137, -0.7379982471, + 0.2065338343, -0.9543405175, 0.8040487766, -0.418710798, 1.310138464, -0.0562577173, 1.0397031307, 0.8087363839, + 1.0376975536, 0.6207315326, -0.0367724709, 0.1032700464, -0.7664158344, 0.7779768705, -1.7194195986, -0.9962170124, + -0.459990263, -1.0737614632, 0.4924404621, 0.5062992573, -2.3763055801, 0.3256783783, 1.0295050144, -1.0963584185, + 1.0508966446, 2.2131047249, -0.302064091, 0.3280752301, -0.0142530557, 0.0741175264, 0.3232976496, 1.8511095047, + -0.093217656, -0.1747188568, -1.9773966074, 0.8212793469, 1.3709951639, 1.3017138243, 0.5213615298, -1.8491699696, + -2.2682118416, 0.7733955383, 0.2187506855, 1.3515372276, -0.5978830457, -0.1860491633, 0.7750968337, -1.1614238024, + 0.5150699019, -2.3115155697, -1.196611166, 0.1801932007, 0.2726337612, -0.1692290753, -0.5952160954, 0.0005237133, + 0.608841598, -0.3638955355, -2.2119069099, -0.6087537408, 0.8907001019, -0.7753039002, 0.1969347894, 0.4207064807, + -0.8330823183, 0.0483885109, 1.9549907446, -1.6341890097, 0.1474251449, 0.3637137711, 0.9511996508, -1.105232358, + -0.9953976274, -1.4866085052, -0.2924993634, -0.0756657571, 0.8346943855, -0.0225741137, -2.0840604305, 0.4949536622, + -0.3814873397, 1.1613310575, -0.335442692, -1.0039441586, -1.159984827, 2.5265002251, -0.3191393018, 0.3884355426, + 0.1033144817, 1.4330396652, -0.0158385038, -0.5452295542, -0.1095836759, -0.7352720499, -0.9227036238, 0.077443026, + 0.0953032821, -0.3727390468, -1.0648605824, -0.2965101898, 0.8064007163, 0.8640318513, 1.0614836216, -0.4732660949, + -0.9734390974, -0.4409328401, -0.4907247722, -0.4260222316, -0.3214211166, -1.2692657709, -0.6843496561, + -1.0450330973, 0.9267991781, 1.0043290854, -1.9433656931, -0.1234595403, -0.03587332, -1.0778970718, 0.8430383801, + -1.6297807693, 0.4672100842, 0.13026613, -1.3048177958, 0.7166115046, -0.4405407906, -1.6556293964, -0.7538868785, + -0.8053990006, 1.7398165464, 0.8470565677, -1.0320606232, 0.6498590112, 0.6128501892, -0.2097587138, 1.7268390656, + -0.4334447682, -0.9774934649, 0.017334491, -0.8519948125, -0.2736777067, 1.1822780371, -0.7529136539, 1.2937862873, + -0.43421188, -0.4783442914, -0.1367436051, 1.1648869514, -1.3607287407, -1.2247972488, 0.5062522888, -0.3501808345, + -2.3892455101, -0.3553076386, 0.0785791352, -0.4684511423, -0.9138480425, -0.7515913844, 0.3910466731, 1.8633239269, + 0.0983788744, -0.5529601574, -0.819259584, 0.0123285549, 0.9051536322, -0.5296494961, 0.6193763018, -0.7575354576, + -0.6588627696, 1.4482965469, 0.1804517806, -0.0969546363, -0.8561577797, -0.1636443138, 0.7998893261, 0.4571678042, + -0.0476388596, -1.442606926, -0.1742287725, -0.5233820081, 0.7883758545, 0.3852189183, 0.3091126084, 0.5430634022, + 0.473733902, -1.091727376, -1.0901318789, 0.4070112109, -0.9084571004, -0.7717982531, 0.0192359034, 0.9061601162, + 0.5126354098, -1.3967828751, 0.7774495482, 0.5376854539, 0.111176528, -0.8687179089, -0.6647869945, -0.0788185447, + -0.2937527895, -1.9742597342, 0.9528505206, -0.6390838027, 1.2707260847, -0.6682310104, 0.471531868, -2.0942647457, + 1.790858984, 0.2074149996, -0.4311299622, 0.4696592391, -0.6548035145, 0.4858731925, -1.1523069143, 0.5596313477, + -1.4902211428, -1.7995990515, 1.6622927189, -0.2245040238, -0.5269060731, -0.0428438373, -1.2792727947, -0.7476548553, + 0.0938511789, 0.8331119418, 1.3060201406, 0.3938763738, 0.9923769236, -1.6811056137, -1.1295176744, 0.2734489143, + -1.6697459221, -0.6384560466, 0.9949476719, -0.5062407255, 1.0034281015, 0.099401772, -0.0723804981, -0.0227089208, + 2.1757483482, 0.1033674479, -1.296202302, 1.6298233271, 0.0310833752, 0.0043407893, -0.7852146626, -0.7798393369, + -0.7882912159, -1.0835288763, 0.3038004935, -0.0921095908, -1.4625827074, -1.5864539146, -1.0401488543, 0.3578006923, + -0.6439752579, 0.6123004556, -0.8602662683, -0.0679839328, -1.9755679369, 1.0582910776, 0.0997800231, -1.1577682495, + -1.5413347483, -0.383808136, 0.4210002422, 0.4642764032, -0.0339855291, 0.129886061, -0.3884651065, -0.8865935206, + -1.6143238544, 3.6056587696, 0.1462464035, 1.52133286, -1.0632134676, -0.5663945079, -0.1952020824, -1.3035510778, + -0.043623291, -0.4883011281, -1.0581581593, 1.6403815746, -0.2546814978, 0.3874523938, 0.2777298093, 1.1789630651, + -0.2963931262, -2.3299434185, -1.028392911, 0.4161494374, 0.700641036, 1.718047142, 1.0294718742, 0.8499308228, + -0.1957364976, -2.0873782635, -0.9732530713, 0.3517284989, 0.6282029748, 0.7819412351, -0.6832048893, -1.026673913, + 1.5057219267, -0.9331673384, -2.027071476, -0.7710177898, -0.6412399411, -0.2176401466, 1.996070981, 0.1312145889, + 0.7394256592, 1.3804028034, -3.1236875057, 0.8488565683, 0.7830206752, -1.2917408943, 0.4925467372, 0.1587381214, + -1.1164747477, 1.5651832819, -1.0977840424, -0.6612092853, 1.8947798014, -0.765352428, -0.3012660742, 0.4719370008, + -0.8919570446, 0.1150531024, 0.2762588859, -0.4841531515, 1.3143765926, 0.2696977258, -0.2131957114, -0.6583449841, + -1.3425199986, 0.2763188183, 1.1737834215, -0.8113678694, 0.4808428288, -0.8791851997, 0.2634968162, -0.6410830617, + -0.0812414438, -0.6814115644, 1.5104262829, 0.517790854, -0.6783463359, -0.1256770492, -0.2949545383, -0.7587720752, + -0.8653795123, 0.3860862255, 1.2165676355, 1.2671173811, 0.2852470577, -0.5262190104, 1.2160490751, -0.2968252599, + 0.6153306961, -0.6760441661, -0.0796759948, 1.0532268286, 1.3543426991, 1.5206708908, -0.2734349668, 1.6068272591, + -1.2159032822, 0.4170197248, -0.4496528506, 0.5826635361, -0.1970722526, -0.2496076673, -1.2450256348, -0.1965055168, + -0.5271847844, 0.437191993, -2.1151013374, -0.2608734667, 0.0152701726, 0.5723733902, 0.0681537613, 0.0613985993, + 0.3411239684, -1.2768346071, 0.333266288, 0.5430427194, -0.0432091579, 1.6785727739, -0.7715849876, -0.1714796424, + -0.3674465716, 0.6206015348, -1.68288064, 1.1599649191, 0.4741328657, 0.8494206071, 1.0655183792, 0.8664425611, + 0.8542308211, 0.2530686855, 1.4608001709, -1.464104414, 0.9866617918, 1.703250289, 0.9210450649, 0.8014882803, + 0.332242161, -1.5023698807, -0.3505462706, 0.0389856398, 0.0831000507, -0.3857187629, -1.5359857082, 1.2615644932, + 1.2758626938, 0.1480398178, 1.2954460382, -0.7860206962, -1.1860078573, -2.2061941624, -1.0470296144, 0.3352247775, + 0.5302492976, -0.0405291393, 1.4120001793, 0.4016290307, -0.1539154351, 0.9125192761, -0.5446004272, 1.2182688713, + -0.886436522, 1.1918206215, 1.0045500994, -1.6376503706, 0.9360725284, -1.2072974443, -0.7660700679, 0.5314910412, + -0.8932678103, 1.1890400648, 0.3187058568, 1.6210167408, 0.4157439768, -0.4446620047, -0.6844602227, -0.8145654798, + 0.6531211734, 0.8158108592, 1.4798234701, 0.4006395042, -0.7666428089, 0.9254111648, -0.3484019637, -1.1469308138, + -0.7036637664, -0.0442226976, -0.2382203043, 0.4113468826, -0.5789852142, 0.7120308876, -0.6015210152, -1.1392376423, + 1.1177431345, 0.4594758749, 1.5914516449, -1.0618811846, -0.8215261102, -0.7494154572, 0.703256309, -0.1234351471, + 0.0701818541, -0.555354476, 0.0761191547, 0.3339363635, -2.1919014454, -0.3116528094, 0.8165085912, 0.2899995446, + 0.2868409753, 2.112433672, -1.1487253904, -1.4357818365, -0.3476918936, -1.3994435072, 0.840501368, -0.9114860296, + 0.4391860366, -1.6877720356, -0.2196552604, 1.3988096714, -0.6408332586, -0.1922979355, -0.2654271424, 0.0860480741, + 0.2465860546, 0.2520399392, 2.9076354504, -1.4887257814, 0.6890859604, 0.4454374611, 0.6194879413, -0.0967055187, + 1.1441223621, 0.1449663192, -0.5741001368, 0.0515831709, 2.8111915588, 0.2500806749, -1.0168375969, 0.0459030941, + 0.5006407499, 1.2243378162, -0.5594944358, 1.5234234333, -0.585698843, 0.8465883732, -0.1062590182, 0.769972086, + 0.7508335114, -0.5606443286, -1.760266304, 0.4370567799, 0.3021217883, 0.1467457712, 0.6101540327, 1.5521664619, + 0.0121918637, 0.0001930556, -0.7419973612, -1.3801542521, -0.0754940435, 1.1674489975, -0.0283292662, -1.2254366875, + 1.6937772036, 0.7008804679, 0.1472029239, -0.2088548094, -0.9180703163, -0.9908519983, -0.8559581637, 0.5744030476, + 0.297172606, 0.7592765689, 0.5797044039, -0.3228662908, -0.3427666128, -0.1186992005, 0.2182934582, 0.978687942, + -1.4661244154, 0.7656714916, -0.3914667666, -0.4707569182, -0.023461761, -2.1558485031, -0.8340327144, -0.4761915803, + -0.1583889872, -1.3076349497, 0.61913836, -0.3673848808, 0.4211728573, 0.0395293981, -0.2179098874, 0.138101995, + -0.0317963026, -0.4639281929, -0.0641642138, -1.1540219784, -0.9627858996, -1.6770368814, -0.5858719945, + -0.0825671777, -1.5955755711, -0.0500167795, -0.0760848224, -0.0237301663, -0.0268115401, 0.2086068839, -1.6112877131, + 0.0350952968, -1.423789978, -1.2756197453, -1.6744543314, -1.3942058086, -1.4011231661, 0.5572247505, -1.6251987219, + 0.0624367483, -0.9734458923, 1.9991265535, 0.3975417614, 1.9408439398, -0.4244121313, -0.744928658, 1.5648454428, + -0.1315009445, -1.1770961285, -0.1874196529, -1.0828311443, -0.4274128377, -0.3763251603, -1.8707411289, + -0.3534707427, -0.0243204199, 1.9254937172, 0.5000748634, -0.0090672439, -0.122909613, -0.1555079669, 1.1247876883, + 0.6508572698, 1.3430335522, 0.3828526735, -0.7241315842, -0.02042895, -1.2060266733, 1.8055220842, -0.0309408773, + 1.6533294916, 0.91677773, 0.658305347, 2.493527174, 0.1820680201, -0.4153838158, -1.7359157801, -0.9003521204, + 1.3195201159, 1.1472709179, -0.3788455427, 0.3824750483, 0.5139021873, 1.7121081352, 1.1626836061, 0.1476384997, + -0.5816458464, 0.2407868803, -1.557246089, -0.9878185987, -1.679117322, -0.1426104307, -0.6590248942, -0.6210706234, + 0.9594504833, 0.2867678702, -0.0755748749, -0.0945067704, 1.8625407219, 1.0528297424, -0.6334456205, -0.507850647, + -1.3274567127, -0.7107422948, -0.2926018834, -2.0036118031, 0.1115319952, -0.0476051159, -1.3324609995, -0.7805432081, + 0.3220021725, 0.9446145296, 1.6483644247, -0.2507813573, -1.4725340605, -2.6068005562, -1.0014157295, -1.0183038712, + 1.2119328976, -0.8830393553, 0.5760194063, 0.4326705337, -0.6804663539, 1.893537879, 1.0359658003, -2.4166157246, + 1.1839493513, -0.2268783003, -0.5061920881, 0.9377138019, -1.2114729881, -0.7506918907, 0.4980424941, 0.8761253357, + -0.4148249626, 1.1402990818, 0.1848191768, -1.85402143, -0.8729506731, 0.8739518523, 1.9581677914, 2.4186632633, + -1.1326782703, 0.5931650996, -1.1454510689, 0.1306309998, -0.7470979095, -0.5057881474, -0.9316557646, 0.0993926078, + -0.7553661466, 0.1219220161, -0.2455041856, 0.3656617999, -0.8616326451, 0.199952364, 0.153231889, -0.7006615996, + 0.461314261, 1.378585577, 0.6721458435, 0.3734226227, -1.3855634928, 0.4933677316, -2.0586693287, -1.8312758207, + -0.5378765464, 0.1734742075, 1.1764724255, -1.6062233448, 0.9842114449, -0.1152400449, -0.0080436319, 2.1545655727, + 0.9554353952, 0.1760829836, -0.4261439741, -1.0313150883, -0.4449267685, -1.6515427828, 0.866364181, -0.3967720568, + -0.307574451, -0.8735423088, 0.6620267034, -1.0369021893, 0.5346903801, -1.548339963, -0.3606949151, -1.5275582075, + -0.1260908693, 1.1827498674, -1.3001586199, -0.8946741223, -0.4685489535, -1.0407261848, 0.2360029519, -0.1681945175, + 0.7322675586, -0.1572569311, 1.2127138376, 0.0375163071, -1.0115327835, -0.0792735964, -1.0087019205, -0.2862460911, + 0.9906303883, 1.232784152, 1.3395975828, -0.1617410332, -3.1198022366, 1.2752115726, -0.9587536454, 0.0452648103, + -1.0152710676, -0.5220885873, 1.2208900452, -0.0604511015, 0.6024882793, 0.4948946238, 0.0399792418, -0.2535513341, + 1.5232809782, -1.2082173824, 0.149426803, 0.7835847139, -0.2103703767, -0.048230812, 0.1537257582, 1.2463809252, + 0.699424684, 0.5315209627, 2.1850254536, 0.4130679369, -1.9432587624, 1.1612490416, 0.533837676, -0.0464589708, + 1.1988745928, -0.9518498182, 0.181514889, -0.7856477499, -1.3307493925, 1.2344479561, 1.0216497183, 0.6948999166, + 1.3199999332, -0.3467248082, -0.6526562572, -0.2523265183, -0.4008188844, 0.8922727704, -0.4961834848, -0.2049113363, + 1.6276949644, -0.1190614551, 0.1953179687, -0.0473487377, -0.3821465373, 1.0792948008, -0.5341405869, -0.7568749189, + -0.2242150456, -1.9106316566, 0.4949327111, 0.8403900266, 0.4573747814, -0.888207376, -0.5454280376, 1.3229922056, + -0.0953648686, 0.1615354121, 0.3111441433, -1.2016353607, -1.1228525639, 1.5913999081, 0.4555059075, -0.084631063, + 0.0696771741, 1.3984402418, 0.8977686167, -0.0743149444, -0.8610787392, -0.0034345402, 0.4643716812, 0.6500335932, + 0.3972373605, 0.6056055427, -1.1137615442, 1.262193799, -1.0029988289, 0.7454153299, -0.9797261357, -1.022249341, + 0.2281863987, -0.2279123515, 1.2973057032, 0.7009657621, -0.1237428635, 0.6601970792, 1.6168614626, -0.1405349374, + 0.4543885589, -0.9073397517, -1.3353450298, -1.4128642082, -0.8668837547, 0.2140561193, 0.6704117656, 0.2983856201, + 0.171122849, 0.0040384457, 0.2274931222, -0.5629349947, -0.2145272195, -0.6500881314, 1.0181735754, -1.0987073183, + -1.1695632935, 1.4457358122, 0.908664763, 0.5250781178, 1.1210864782, -0.5814261436, -1.9068636894, 1.2717565298, + 0.3779475689, 1.1875561476, 2.1112318039, 1.3692845106, 0.4907457232, -0.1053989232, 1.7720201015, 0.3179871738, + 0.6021529436, 2.0522155762, -0.8119975924, -1.2906919718, 1.9221531153, 0.2619466484, 1.4544030428, -0.0270028636, + -1.0798466206, 2.4531943798, 0.4816752672, 2.3576691151, 0.8212106228, 0.6885333061, -1.1239271164, -0.3848465085, + -0.5353651047, 1.2736561298, -0.4609678388, 0.1968630999, 0.5500658154, 2.0417609215, 0.5277529955, -0.4230228662, + -1.5167474747, -0.4852030277, 1.0694479942, 0.3578872681, 0.3670755923, 0.3847409785, 0.5441589952, -1.1518552303, + -0.3627217412, -0.2236316949, -0.130944863, 0.3189993501, 0.7243591547, 0.6128135324, 0.6833281517, 0.1058774963, + -1.0476717949, 1.2348972559, 0.1849824041, -1.060338974, 2.7461400032, 1.0114446878, 1.3566025496, -0.698584795, + 0.9919859767, -0.1195081174, -0.5770586729, -1.6611901522, -1.4490962029, -0.1540308297, -0.0394946598, -1.5549813509, + 0.4014787078, -1.4460828304, 0.3835073709, -0.2769566774, -0.1825580746, -1.3795892, -1.0845396519, 0.283832401, + -1.933369875, -1.5066390038, -0.809030354, -2.3525457382, 0.3431841731, -1.8326971531, 0.4958780706, -0.6096104383, + -0.1282366365, 0.0555926375, 0.8264662027, -0.5319551826, -1.3494676352, 0.0178227182, 0.2657372057, 1.5358214378, + 1.4378138781, -1.5428961515, -1.0020878315, -0.1664336324, 0.3720614016, -0.972299695, 0.4478465617, -0.5604529977, + -2.8267419338, -0.1732289642, -1.3194926977, 0.7245579362, -0.411467731, -1.018594265, 0.0171113219, -0.3274767399, + 0.8993369341, 0.41650787, -0.4409069121, 2.3318879604, 1.0301353931, 0.0106273629, 0.5165274739, 0.369430393, + -0.7169600725, -2.016087532, -1.5899252892, -0.727912128, 1.0887588263, 0.2646250725, -0.2574935853, 0.2369214147, + -0.1405727863, 1.1408565044, 1.3749165535, -0.3872929215, 0.3741849363, -1.1731528044, -0.8771096468, 1.7028417587, + 0.7422641516, 0.7952908874, -0.6359503269, 0.0625767857, -1.4387636185, 0.7526410222, 0.5943829417, -0.683493197, + 0.4352502227, 0.0361339785, -0.3459370732, -1.3282161951, -0.3925054371, -0.3875874877, -0.4427610338, 0.6347910166, + 0.7603368759, -0.4462294281, 0.2494061291, -1.719858408, -2.5241043568, 1.0394392014, -0.8128814697, -1.3440935612, + -0.9509823918, 0.5185998082, 0.661231339, -0.3765857816, 1.2585207224, -0.2729130089, -0.1594479978, -0.8824411631, + 0.3794788122, 1.0085316896, 0.3316577375, 0.5210019946, -0.2534552217, -1.6504944563, 0.1905167997, 0.3426152468, + -0.4149730504, 0.422960639, 0.5006102324, -0.688457191, -0.008529393, 0.2035993785, 1.6628166437, -0.7422149181, + 0.4549663663, 0.9701353312, -1.4671440125, 1.0306642056, -0.1751043946, -0.3081717193, -0.1086230949, -0.3445905149, + 0.3018523157, 0.5331122279, -1.4184136391, -1.3059164286, 0.0133221578, -0.4561957717, 2.0107197762, 0.0168454461, + -0.5268836021, -0.5163084865, -0.2862188518, 1.9081737995, 0.3808764815, 1.1053049564, -0.1701475978, 1.8028768301, + 1.3454405069, -0.9716171622, 2.015140295, 0.4353454411, 0.2021296322, 0.3094969988, -1.2130287886, -0.6061766148, + -0.8579288721, -0.5894806981, 0.1631432176, 0.1187847629, -0.4992081821, 0.6937823892, -0.3709974885, 0.3257789016, + -0.3987151682, -0.7485961318, -0.2293497622, -1.0146118402, 0.011047109, 1.7328293324, 1.0677479506, 1.2207168341, + -1.9264101982, 1.5223257542, 0.3796040714, -0.3781650662, 0.1991085708, -1.2878689766, 1.4412564039, -0.3321222961, + -0.01530049, -1.0780576468, 0.9807602763, -0.1083590388, 0.321937114, -1.0011390448, -1.0939098597, 1.012516737, + 0.261795938, -1.9774245024, 0.8176585436, -0.5400171876, 0.8523032665, 0.0277114268, 2.1040093899, -1.433214426, + 0.8153598309, 0.4336749613, 0.6829534769, 0.6602942348, 0.427687943, -2.8726365566, -0.9237739444, -0.445194155, + -0.1291576624, 0.082660459, 0.2901602387, 0.1507606357, 0.4976918399, 1.9305351973, 0.6905815005, 1.1261466742, + 0.11369019, 0.4927196503, 2.1992692947, -0.7340601087, -0.6472967267, 1.2486354113, 0.4821243584, -2.0340688229, + -0.7239329815, -0.0443657637, 0.174576506, -0.6582645774, 0.4640335143, -1.2629460096, -1.6618301868, 0.1800085753, + 0.9277454019, -0.2590980828, -0.7413901687, -0.6935709715, -0.5875934958, 1.2377283573, 0.3266763985, 0.0787180141, + -0.5542194843, -0.974173069, -0.4150099754, -1.5515369177, 1.0647892952, 0.6235165, 1.3300273418, -0.3489451408, + 1.3718315363, -0.6768189669, 1.3851624727, 0.8357720375, -0.6882252097, -1.0305742025, 0.0712251291, 0.3130685091, + -0.6692923903, 0.9052766562, 1.9800167084, 0.9550880194, -0.7589914203, -1.5862555504, 1.5604054928, 1.0711680651, + -0.1050480083, 1.1862883568, -2.3280029297, -1.6582649946, -0.3555588722, 0.8859654069, 2.1518859863, -0.7442384362, + 0.6685908437, -1.1250841618, -2.7138724327, 0.0137464041, 1.3366407156, -0.4603686929, -0.8399344683, -0.4507792294, + -1.4983799458, -0.80272156, 1.6966629028, 0.4295882285, 1.5084462166, 0.4342085719, 0.1687584966, -0.2440459728, + -0.1066379622, 1.1238811016, -1.6822667122, -0.951787293, 0.4881279469, -0.0958632976, -0.4737888873, 0.4130543172, + -1.2868320942, 0.0282274242, -0.0538525246, -0.6100097895, -0.4368116558, 0.541413784, -0.6348329186, -0.6271486878, + 1.1452444792, -0.3874225318, -1.0906164646, 0.3533582091, -1.7489846945, 0.8108950853, 0.1281350255, 0.9760327935, + -1.0696296692, 0.8331253529, -0.9128801823, -0.5867547989, -0.185413897, -0.8016400337, -0.0122459978, -0.2811549902, + 1.5724511147, 0.8933423758, 1.5236115456, 1.1318390369, -2.1643643379, -1.1678924561, -0.5303066969, 0.1001020819, + 1.5827381611, -0.344353646, 0.4299806058, -0.6880388856, 2.3481752872, 0.8799027801, -0.1208624095, 0.3161224425, + 0.1859720945, 1.3103215694, 0.5370991826, 0.2128050774, -1.6082152128, -1.0610541105, -0.3076724708, -1.3912265301, + 2.0203952789, 1.2839845419, -0.1427117586, 0.7247159481, -1.4809105396, 0.415199101, 0.7133069634, -0.9822463989, + 1.0256047249, 0.8960664868, 0.2456524372, 2.2871968746, -1.1332281828, -0.9934768081, 0.0801362023, -1.4279161692, + -0.1673499644, 1.9552475214, -0.7649120688, -0.1214441359, -0.8505011201, 0.0120534971, -0.2664821148, 0.1010014117, + -0.0249482337, 0.4609630108, -0.4709973037, 0.7293856144, 0.3688291311, -2.2109615803, 1.2869336605, -0.3740674257, + 0.0017372227, 0.1274275184, -0.0548788235, 0.4981512427, 2.0514848232, -0.3548823297, -0.5679026842, -2.2651638985, + -0.9933956265, -0.4226258695, 0.5724143982, 0.6467649937, -0.5059992671, 0.6243510842, -1.3668729067, -0.5580800772, + -0.2308873683, -0.4146345556, -0.8414208293, -0.8874806166, 0.808539927, -0.7730150223, 1.0769597292, -2.2644515038, + -1.7992531061, -1.5193790197, 0.6511667371, 2.0010735989, -0.4351148307, 0.5123409629, 0.4797986448, -0.3782280385, + 0.3045934141, 1.0081927776, 2.1089031696, 1.4194885492, -0.7833939791, -0.7446916699, 0.1809913516, -1.4201674461, + 1.5365930796, 1.5332006216, -0.0955717042, -0.0791906789, 1.2793784142, 0.2346884012, 0.6085548997, -0.7300610542, + -0.7544391751, -0.0971425176, 1.7628134489, -0.5690230727, -0.2787840366, -0.2442644686, 1.3795033693, 0.6344102025, + 0.4248405397, -0.1316951513, -0.4010356665, 0.9959358573, 0.4057629108, 1.0247602463, -1.6310348511, -0.1843463928, + -0.07511691, 1.0483053923, 0.8583419919, 1.0581882, 0.5709701777, 0.1121916398, -1.2642484903, -0.7674326301, + -2.1037101746, -0.3202399611, -0.6719353795, -0.826115191, 0.7101277709, 2.6124789715, -0.141830951, -1.3277183771, + 1.0787343979, -1.2282276154, -0.1210674867, 0.2911917567, 0.6180588603, -1.4232866764, 0.5941316485, 1.001398921, + -0.0831873789, -1.415058732, -0.3144525886, 0.2749459743, 1.5043956041, -0.8493507504, -0.3435238004, 0.1091308668, + -1.4348704815, -0.6094563603, -0.3990669847, 0.1706257463, -1.0890892744, 1.3205559254, 0.2972381413, -0.7722620368, + -0.3236086071, 0.4466733932, -0.4585110843, 0.8907366395, 0.3113555014, -1.0298800468, 0.6594182849, 2.1507937908, + -0.567794621, 0.3051919937, -0.3771156669, -0.5940546989, 1.2152264118, -1.7259300947, -1.0823833942, 1.3255735636, + -0.8910102844, -0.0269354563, -0.1528990567, 1.4183866978, -1.645766139, 0.8868795037, -0.8474878669, -1.3936561346, + 0.0618900172, -0.5172175765, 3.1002268791, -1.4958193302, 0.3102186024, -0.9779730439, 1.1106261015, 0.7437641025, + 1.4932644367, 1.0055906773, -0.7624963522, -0.4558341801, 1.2478998899, -0.0513665862, -1.0852686167, 2.506349802, + 1.4703984261, -0.3500232399, 0.6674960256, 0.2232310176, 0.7430081964, 1.4739216566, -0.280554533, 0.0959332883, + -1.2647999525, -0.8458613753, 0.612160027, 0.3654181659, -0.5369811654, -0.4391386211, -2.144618988, 0.8581434488, + 1.3331199884, 0.0303843282, 0.6091219187, 1.1128925085, -0.669565022, -0.2710272074, -1.6208012104, -0.6248922348, + 0.51113832, 0.4374771416, -0.0601305887, -0.3222166598, 1.5219869614, -0.2043878138, 0.7294411063, 0.5184146762, + 1.4763427973, 0.97724998, -1.1257607937, 0.1171994582, -0.5923586488, -0.3355710208, -1.074111104, -0.5246708393, + -2.2213320732, -0.1392166018, -0.4191494286, -1.0089921951, -0.3403863013, 0.5482953191, -1.164039135, -0.3767908812, + 0.504350245, 1.2352068424, -0.0104251159, -0.101167053, -1.4769479036, 1.0991642475, 0.9631522298, -0.1085720211, + -0.3289594054, -0.1785956621, -0.1722016186, -0.9106789827, -0.0757652223, 1.6013062, 2.8825588226, 0.0283018276, + -1.4420264959, -1.0566796064, 0.3184948862, -0.7164399028, -0.6493185163, -0.9150819778, 0.1000853702, 0.6208550334, + -0.1778074652, 1.1770408154, -1.3932850361, 1.4212722778, 0.5371090174, 0.4546726048, 0.4049543738, 0.3981168866, + 0.0488865748, 0.8620789647, -1.1955425739, 1.2540414333, -2.038620472, -0.025890369, -1.3946413994, 1.7492851019, + -0.3227463663, -0.0915191621, -1.4765635729, -0.0714700073, -0.4856380224, -0.3160601854, -1.1019278765, + -1.4820511341, 0.4517401159, -1.347868681, -1.5971720219, 0.4214863181, -1.2817587852, -0.3930203617, -0.1581448764, + 0.6314710379, -1.2951623201, -0.1740406007, -1.0108921528, 1.2809277773, 0.683306694, 0.6616382599, 1.7153782845, + -0.6153312922, 1.5842894316, 0.7544012666, 1.6303297281, 0.1301917434, -2.7217433453, 0.3398594558, -0.8163784742, + 0.1465732604, -1.2905712128, -0.4101938009, 1.6654448509, -0.2119739801, -0.7760418653, -0.42272681, 0.6563307047, + 0.2659547925, -0.0037535611, -1.0131603479, -0.2349339277, 0.9261472225, 0.3318826854, 0.3253736198, -2.6372146606, + 0.2674591243, -0.1940494925, 1.3571807146, -1.6915826797, 0.577254951, 0.8997503519, -1.3403272629, 0.7346234322, + 1.5062402487, -0.1679347157, 1.214120388, -1.6488654613, 0.6915194988, -0.2572011054, -0.1990943253, 0.2498833686, + 1.2450773716, 0.3484862745, -0.2589534819, 0.7116019726, -0.0218918305, 0.570200026, -0.945776701, 0.6703088284, + -0.1766744554, 1.3134074211, -0.171094358, -0.2920600772, 0.9888873696, 0.6314431429, -0.6614246964, 0.9294165969, + 0.2508786917, 0.5414218903, 0.2954601943, 0.8805912137, -0.0731926933, 1.7276763916, 0.3145478964, 1.1606113911, + 1.0999108553, -1.5043370724, -1.5866116285, 0.0370911658, 1.3214834929, 0.0746138021, 0.9906339645, 0.1499240994, + 0.9241827726, -1.4057812691, -1.2694085836, -1.2315986156, -1.079206109, 0.9238930941, 0.3661459982, -1.6559048891, + 0.3552600443, 0.1590854973, -2.0836281776, -0.3751182556, 0.866791904, 0.2102769166, 1.4756578207, -0.5184097886, + -0.0366294533, 0.8832123876, -1.0546194315, -0.1811883897, -0.1210824773, -2.176453352, -1.5692141056, 2.0706942081, + -0.9752756357, 0.1462701559, -0.1786944121, -0.9237043262, 0.2103956491, -0.1442062855, 1.2261948586, -1.51128757, + 1.5062558651, 0.0944361016, 0.7306627631, 0.6643269062, 2.2133276463, 0.8330996633, -1.4814969301, -0.3682819903, + -0.4991627038, 0.5526918173, 0.3599629402, 0.6244876385, -1.061763525, -1.0455168486, -1.1398391724, -1.3221683502, + 0.0184009988, -0.5667765737, 1.8121285439, -0.93263942, -0.7341508865, -1.1592438221, 1.2299790382, 1.7348306179, + -0.7335332632, 0.8989298344, 1.2027136087, 1.1966621876, -0.1625650376, -0.1017761528, 0.2831718922, 0.4695369601, + 1.1291228533, 0.6805573702, -0.0990784019, -0.7106087804, 0.2395488918, 0.1024907678, 1.7224653959, -0.9518821239, + -1.7251338959, 0.9914779067, -0.9855437875, -0.3009017408, 0.908254981, 0.0410030857, -0.060521014, 1.1658284664, + -0.9308250546, 0.8737416863, -1.2085171938, 1.0346195698, -0.5344747901, -0.2332480103, 0.6903033853, 0.1028862447, + 0.8828144073, 1.8908827305, -0.7360958457, -0.2265916616, -0.517105639, 0.6966750622, 0.344727844, -0.0323995762, + -0.6886252165, -3.2709035873, -0.8757738471, -1.4021294117, 0.1837808639, -0.957711339, 1.2251466513, -0.2875821292, + -0.2114524692, -1.4256474972, 0.8641709089, 0.0528381169, -0.0744572952, 1.5797815323, -1.1734684706, -0.0783758909, + 0.2729905248, 0.5856707692, -1.0022348166, -1.2545819283, 1.0302791595, -0.3580471575, -0.9342455268, -1.98130548, + -1.5998274088, 1.3066407442, 0.4830575883, 1.6324607134, 0.1079617515, -0.4973579049, -0.5194500685, -0.3114619255, + 0.1192606017, -2.0525612831, 0.2186866999, -1.5327219963, -0.4967102706, -0.105010204, -0.0578927137, -2.1460046768, + 1.3595274687, 0.2326336652, -0.1665844172, -0.4899091423, 0.7253504395, -0.2241188586, 0.0341161974, -1.7404079437, + 0.5003447533, 0.46873191, 1.5334626436, 0.2852185965, -1.5014708042, -0.4241717756, -1.2355568409, 0.0657551959, + 1.2892919779, 1.2911703587, 0.611050725, -0.0205472484, -1.2269330025, 0.0883116126, -1.0893718004, -0.6376819611, + 0.5561304092, 0.0832567215, 1.6728909016, -1.2436583042, 0.1721850187, 0.6242291331, 0.3138146996, -2.2066717148, + 0.2796196043, 1.0710690022, 1.3156319857, -0.0950455889, -1.5921502113, -0.9913931489, 0.129788056, 1.4663813114, + -0.1556957811, -0.8660828471, -0.4202181101, -0.9978961945, 0.5445381403, -1.5141788721, 1.9711934328, 0.5910512805, + -0.9280182719, -0.6373056173, 0.4286117256, 0.7815433145, -0.0861902535, 0.0154004376, 1.558349967, -0.553202033, + 0.2428787202, -1.3022339344, -0.636924684, -0.1703581214, -0.3426039219, 0.8764404655, 0.5651657581, -1.1531502008, + 1.3143377304, -0.6532971263, 1.3424408436, -0.5932373405, -0.314838022, 0.3417423964, 0.0807463825, 0.7385244966, + 0.1785105616, -1.0377227068, 2.5720541477, -1.6021740437, 0.373097986, -1.0089817047, 0.2074581236, 0.7690361142, + 0.1414442956, -0.0658927634, 1.29817307, 0.563785255, -0.7915480137, 1.1714626551, -1.0327466726, 1.2980322838, + -1.8191382885, -1.5950011015, -0.0475060828, 0.1701105088, -0.117339693, -1.1642503738, -2.2592539787, -1.0229673386, + 0.0272143669, -0.0346517377, 1.916351676, -0.3508054614, -0.5195938945, 0.7642535567, -2.5424456596, 0.0920520052, + -0.5108087659, -0.8645259738, 0.8696979284, 1.5335197449, 0.1574706435, 0.8634047508, -0.7973005772, -0.7276571989, + -0.0082663214, 0.616967082, 1.2819828987, 1.0705560446, -0.3476598859, 0.803585887, -0.25541237, 1.5247392654, + -0.3427659571, -0.2781977654, -0.0387262739, -0.2124831229, -1.0138919353, 1.1995728016, -0.3768789768, -1.0625375509, + 1.2412786484, -0.0552544296, -0.742549479, 0.5503547192, -0.2265021652, -0.5776142478, -1.0426775217, 0.0635304376, + -1.0789164305, -0.0305424035, -0.4114821553, 0.8515140414, -0.803881824, 0.1948237717, 0.1175146028, -1.1841410398, + 1.4999989271, 0.7257269025, 1.1487137079, 1.6531249285, -0.9639879465, 0.9420316219, -0.6486244202, 0.2358347327, + 0.2451820672, -0.9946019053, -0.4021207988, 0.6609389782, -0.6528478861, -0.7113485336, 0.265008837, 0.6931459308, + -1.5257225037, -0.5300140977, 0.423089236, -0.1780603528, -0.7085021138, -2.032626152, 1.1543872356, -0.638223052, + 0.126719445, 1.1673766375, -0.1194199398, 0.5173939466, 1.358566761, 1.1757655144, 1.2875258923, 1.701970458, + -0.3240980208, 0.385619998, -0.5278858542, -1.4395867586, -0.4803539813, -0.7832537293, 2.5728754997, 0.612049222, + 0.1088558584, -1.4145896435, -0.089389354, -1.1972055435, -0.8456657529, 2.5421011448, 0.8142038584, -0.4200177789, + -1.3778551817, -0.1695551574, -1.4214105606, 0.3386326432, 0.4762045741, -0.8144193292, -2.0145246983, 1.374471426, + -0.0912032276, -0.5277309418, 0.326862514, 0.0133851767, -0.5244994164, -2.601708889, 1.9043643475, 1.1018794775, + -1.4449181557, 0.0988714769, 0.1080312133, 0.2872729599, -1.0176873207, -1.5658758879, -1.4753624201, 0.613272965, + -0.6109262109, 0.7954557538, 0.3561187685, -0.6416935325, -0.8037799597, -1.0986231565, 0.6042654514, -0.0362247378, + -0.4225933254, -0.0711886138, -0.5749738216, 1.029211998, -0.0141652646, 0.338113308, 0.2150502056, -0.4366036057, + 1.1847845316, 1.2134108543, 0.0970221311, -0.3986929655, -0.3410035074, 0.5849024057, 0.8327379227, -0.3633055687, + 1.1413456202, -0.3347489834, -1.4785804749, -0.6094909906, 0.8936745524, -0.255613476, -0.1951664984, -0.6637004018, + -0.9761881828, 0.5172336698, 1.0505046844, 1.0351791382, 0.952825129, -0.6650516391, -0.5152972937, -0.5114353299, + -0.5137189627, 0.134258911, -0.4055825472, 0.9870741367, 1.1039853096, 0.7906116247, 0.1031517833, -0.5891082883, + 0.4176992476, 1.1658488512, 0.9659720063, 0.0746390373, -1.0539230108, 0.8605904579, 1.0937052965, 1.4656609297, + -0.0631425753, -0.2436380386, 0.5220047235, -0.52574265, -0.3511520624, 0.1896903366, 1.1232941151, 0.9083298445, + 0.6321584582, -0.2297795564, 0.4393576384, -1.1335648298, -0.176781252, -0.9877588749, -0.633639276, 0.6270663142, + 0.5877546072, -0.2975437939, -0.6329882741, 0.9075940847, 0.1420644522, 0.4181271493, -0.8419764638, 1.3827379942, + -0.2564235032, 0.4914464951, -1.2188130617, -1.7116364241, -1.8048491478, -1.8463013172, 0.3928754032, 1.4446197748, + 1.7741932869, -0.2339616269, 0.8514254093, -0.7865287066, -0.4787963033, 0.8111802936, 0.5455805063, -1.4866166115, + 0.5192504525, 0.5673210621, -0.2531650364, 0.4797608554, -1.7640885115, -1.7594573498, -1.0405248404, -0.6443892717, + -0.046376612, 1.5923037529, -0.984903276, 0.9268825054, -0.3332609534, 0.1753576994, -0.466493994, 1.173555851, + -0.4948464334, -0.5844563842, 0.7905429602, 0.9834874272, -0.5397875309, -0.326140672, 0.5392394662, -0.5751277208, + -0.2247804999, -1.1403326988, -0.9152319431, -0.3199635148, -1.0563613176, 0.4798598886, -1.5495011806, -0.2683282197, + 1.050999999, -0.8671765327, -1.7904404402, -0.465572685, -0.8255794644, 1.254928112, -0.5127987266, 0.3980410993, + 0.5606667399, 0.2152752578, -1.6999623775, -0.0291132275, 1.8648895025, 0.613922298, 0.0244569257, -0.9495642781, + -0.0074470057, -0.9770514369, -1.3872021437, 0.1106198654, -1.5846104622, -0.4539607763, -1.124591589, -1.2696129084, + 1.3264654875, -0.6482177973, 1.0197538137, -0.7960487008, 0.0526552238, 0.1811360568, -1.6001381874, -1.2790617943, + -0.7372736931, 0.8097754121, 1.8652113676, 0.6001631021, 0.4037535191, -0.0492363907, 1.1228337288, -0.649882257, + 1.011605382, -0.254175663, -0.5277975202, -0.2402507961, -0.1130158454, 1.1338608265, -0.7202472091, 0.5499478579, + -0.9729791284, -0.8757820725, -1.8153737783, -0.6840500236, 0.0959931836, 0.5253782272, 1.0612294674, 0.0080760587, + 1.4577175379, -1.3004442453, 1.9005447626, -0.7658629417, -0.0105433399, 0.8367369175, -0.6676630378, 0.9297543764, + 0.9685356617, -0.0386456437, -0.4531649053, 0.1079624817, -0.0924528167, 0.6686045527, 1.759542942, 0.8170405626, + -0.6267473102, -2.5353696346, -0.6208639145, 0.041296646, 0.5412843823, -0.6714181304, -0.1228801236, -0.3316660523, + -0.1653130352, 1.4541288614, 0.605705142, 0.7982510924, 0.1380858123, -1.4818567038, 1.8989332914, -0.985984087, + -1.2145018578, 0.7614639997, -0.7683216333, -0.4145599902, -0.4076405764, -0.2403526902, -0.5470996499, 0.9964763522, + -1.8223305941, 0.4747248292, 1.5665532351, 0.9140262604, 0.1729218364, 0.5444464684, -0.1636365354, -0.8873438835, + 0.443942368, 0.622712791, 1.7554078102, -0.4988125265, -1.3193113804, -2.5715079308, 0.1748979837, -1.1597133875, + 0.9316927791, 0.1183342338, 1.0189135075, 1.024425745, -0.5853592157, 0.9235587716, 1.2721583843, 0.8519009948, + -0.4364132583, -1.2144123316, 0.2642391622, -0.3939892352, -0.0805365071, 0.4169847965, -1.6299033165, -1.9063054323, + -0.9444448352, 0.9864621758, -3.2844877243, 0.4394325912, 0.547364831, -0.2011999935, 0.6504402757, 0.3405825198, + 0.5267879963, 1.7770034075, 0.5222274661, 0.928198576, -0.2189456522, 0.3734814525, -1.2006289959, 0.2925578952, + 1.1988446712, 0.7234704494, -0.4607257247, -0.8953572512, -0.0688983947, -0.1996186823, 2.5704195499, 0.2287005633, + 1.5053178072, 0.098707363, 0.4207965136, -0.1668317318, -0.3914250135, 0.0472337753, 0.8962624073, -0.6044977903, + -0.2340323478, 0.395725131, -1.4881333113, 0.4008922279, -0.2279271781, 2.0719885826, -0.5289013982, 0.3241880536, + -2.6822669506, 1.7045650482, -0.1832091957, -1.343880415, -0.1880180538, 1.0730087757, 0.3521874547, 0.2114675641, + 0.5612317324, 0.9730195999, -1.4720804691, -0.0725681335, -1.4717452526, 1.6405420303, -1.4896878004, 0.0528693758, + -1.7767858505, 0.9301193357, 1.7837607861, 0.2781662941, 0.1405596286, -0.3057101071, -0.2079758793, 0.5234370828, + -0.5637179017, -1.4416309595, -1.004812479, 0.4227478504, 1.0247695446, -2.4148521423, 1.22879529, 2.0506439209, + -0.3796081543, 1.433018446, -1.6261191368, -0.431019783, -0.365114212, -0.8131893873, 0.1408641189, -0.0862338468, + -1.0842740536, -0.4975840449, -0.8313937783, -0.3324953318, -2.9499680996, -1.3614028692, -0.065209046, 1.5336951017, + 0.6620618105, -1.4137949944, 1.0900887251, 0.195264861, 0.4613917172, -1.3025218248, 1.1172809601, -1.0675442219, + -1.5549499989, -0.2244365811, 0.5666527748, -1.8053593636, 0.2591793835, 1.1105011702, -1.9888157845, -1.3004876375, + 0.9484360218, -0.1045219526, -0.1354653537, 0.784473598, -0.3132534623, -1.711836338, -0.1989667118, -0.2725273967, + 1.5450774431, -1.2673224211, 1.6919636726, 0.2171541452, 2.2025887966, 1.4983998537, 0.5503693223, 1.3401776552, + 1.4544260502, -1.9329987764, 0.1200451478, -0.9440642595, -0.3997438848, 0.7572956085, -0.0289923865, 0.4980324805, + 0.4981862605, 0.6089060307, 0.2215690613, 2.8459966183, -0.3495443463, 0.3898267448, -1.3111178875, -1.494969368, + 1.5423781872, 0.435533762, -0.2667261362, -0.6964426637, -0.0315350629, -0.0684453547, 1.2804672718, -0.347650677, + 0.3679663539, -1.9576956034, -1.553580761, 0.3000622094, -1.0038506985, 0.0751238614, 0.0237246975, 1.8045992851, + -0.945379734, -0.2001632899, 2.161437273, -0.9781127572, -1.0257860422, 0.322892487, -0.0656457618, -0.537632525, + -0.5086116195, 2.1152424812, -0.4741887152, 0.9335947037, -0.9201823473, -1.5525681973, -0.8249668479, -0.2767834663, + 0.3954752684, -2.5128004551, -0.5187504888, 1.7483252287, -1.520067215, 2.7166440487, -0.397031486, -0.8433889747, + 2.4272284508, 0.2976959348, -1.399936676, 0.9331608415, -0.659884572, 0.7047004104, 0.4617165029, 1.20492208, + -0.4600013494, 0.7962696552, 1.4818439484, 0.4008847177, -0.403652072, 1.8412313461, -0.1604305208, 0.0991646573, + 0.4628383219, -0.9043536782, -0.8916121125, 0.4315722287, 1.3325688839, 1.9264107943, -0.688573122, 0.3321375847, + -0.241354391, 1.0912894011, 1.143666029, -1.4943883419, 0.4226326942, -0.3977138102, 0.6066868305, 0.1816943884, + -0.0278797448, -0.7122353911, 0.7773500681, -0.3370968997, -0.0819773525, 0.3859794736, 0.0197459012, 0.7838968635, + 1.1054192781, -0.0492523052, -1.1183481216, 2.0457713604, 1.4440535307, 1.4088461399, -0.3506045938, 0.9419050813, + -0.4516931474, -0.0231885668, -0.2311489135, -0.5307110548, -0.6097031832, 1.5688374043, -0.0618275702, -0.3840580285, + -0.1462161839, -0.7490805984, -0.4684410393, -1.1734311581, 0.2761482, 1.6468441486, -0.436989367, 0.6186989546, + 0.5075575709, 0.209393695, -0.0073280954, 1.4158865213, 1.3943082094, -1.1606276035, -0.1925585568, 0.7860649824, + -0.1255825013, 0.7291187644, -0.0382035486, 0.8796746731, 3.2665982246, -0.1572821438, 1.2827008963, -0.2016982436, + 0.0290385038, 1.2065564394, 0.5020515919, -0.0758089051, -0.5608183742, -2.4836220741, 0.75680089, 1.7811390162, + 1.6835224628, -1.111076951, 0.3087627888, -0.5306309462, 1.4413764477, 0.0940743685, -1.1490490437, 1.7519093752, + 1.1665536165, -0.597243607, -0.9645920396, -1.8831322193, 0.3731502593, 0.709733963, 0.8633415103, 0.0572413802, + -0.3672955632, 0.0742917284, -0.5524155498, -0.0990694165, 1.2753888369, 0.1014469489, -0.2720424533, 0.7490035295, + -0.0318105072, -2.5118894577, -0.7490311861, 1.6888785362, -1.5632879734, 0.3120557964, 2.4351465702, 0.9439433813, + 1.7685650587, -1.7593694925, -0.9471104741, -0.3451783657, 0.7697889805, -0.6745629311, -0.1576409042, -0.7649592757, + 0.7051118612, 0.4522475898, 0.1596816778, -0.3910192847, 1.8914453983, 0.1121585667, -1.7256836891, 2.5300681591, + 0.208269015, -1.8599275351, 0.7754518986, 1.6154131889, 1.3406716585, 0.7618990541, -0.1711893827, -0.0310675185, + -0.0496421643, 0.4200766385, -1.5414303541, -0.3754616678, 1.0248707533, 0.781992197, 0.8943247795, -1.0348619223, + -0.3936333656, 2.4675981998, 1.1788799763, -2.4421749115, -0.706240654, -0.4198507965, 0.0803024247, -0.663300693, + -0.1075372994, -0.4508400857, 0.4074032307, -0.7849459052, -1.2711269855, 1.3193122149, 0.4826998115, 0.5387716889, + -0.2636992335, -2.0554578304, 0.3182610571, -0.1439537555, -0.0299516935, 0.4889170527, 0.6923212409, 0.6136444807, + -1.1940793991, 0.4658052623, -0.0280528236, -0.3650117815, -0.5338830352, 0.7320910096, 0.6896799803, -1.2262221575, + 0.6613311172, -0.8810014129, 0.0679493994, 0.3078416884, -0.5542497635, -1.0899014473, -0.1688338518, 0.636379838, + 0.9226398468, 0.2054868639, 0.2460445613, -0.9185663462, 0.1189117134, -0.055681292, 1.289173007, -2.413482666, + -1.505401969, -1.1148625612, 0.5536409616, -0.7582384944, 1.5371382236, 0.5538336635, 0.2182800174, -1.1763197184, + 0.5749715567, 0.7819045782, 0.8062111139, -0.1452429444, -0.2014859468, 0.5254017711, 0.1605516672, -1.7581435442, + 0.5122259855, -0.6614473462, -0.5915403366, 2.0017547607, -1.4677304029, -1.825740099, 1.0064178705, -0.5828084946, + -0.4141933322, -1.9140504599, -0.0616672523, -0.0180219132, -0.4038219452, 0.6312733293, 1.206668973, -0.4449644983, + -2.8706459999, -1.2025235891, 1.0925306082, 0.7826869488, -0.7611364126, 0.3302960694, 0.5973567367, -0.0336623602, + 0.4979988039, -0.6890585423, -1.269559145, 0.9333893657, 1.1220725775, -0.7051638365, -0.3467444777, 0.9953252077, + 0.5555455089, -0.0913688913, 0.9911448956, 0.0564950071, 1.1763910055, 0.4268105328, -1.6847207546, 0.4380587935, + -0.8402453065, 0.8270261288, -0.0309975259, -0.7158976197, 0.20768255, 0.2148397267, -0.6354771852, -0.2590553463, + 1.9080600739, -2.647446394, -1.6957372427, 0.0676404461, -0.184092477, 0.0144398957, -0.7230440974, -1.4499595165, + -0.3431442082, 0.7012284994, 1.6000750065, -1.1220747232, 0.6476452947, 1.2227518559, -0.6261531115, -2.0118496418, + 0.5587783456, 0.5587535501, -0.7095311284, 0.9690502882, -0.061287608, -1.0169298649, -1.8414348364, 1.4388775826, + 1.2759331465, -0.5176864862, -0.3065904975, -0.1054771617, -0.893363297, 1.7129597664, -1.0600179434, -1.72032547, + 2.174772501, 0.5608677268, -1.0009634495, -1.6312663555, -0.1436923146, 1.0822681189, -0.8980425596, -1.1708720922, + 0.8111722469, 1.4318437576, 0.7622471452, -0.1665702909, -0.7519943714, 0.9354758859, 0.4794349074, -0.9928976893, + 1.2101974487, -1.4867138863, 0.6146788001, -0.2739740908, 0.7458140254, -0.427643925, -0.7129654884, 1.0291323662, + 0.1629079729, 0.5204790235, 0.4500774145, 0.659710288, -2.1476511955, 0.7354454994, 2.0337862968, -0.4528868794, + 0.0470402688, -0.6466990113, -2.4321630001, 0.9452065825, -0.8999962211, -0.2017476708, 0.5209354758, 0.1222702488, + 0.3367359638, -0.6224790812, 2.318926096, 0.8680391312, -0.5176272988, 0.5175158978, -1.4247558117, 0.2031879127, + -2.5270433426, -1.1400226355, 1.291177392, 0.4571803808, 1.5411505699, 0.3775106966, 1.0139513016, -0.9173130393, + -2.1711902618, -0.0480994694, -1.5899727345, 0.1245185956, -0.1466777176, 1.1491481066, 1.8068344593, -1.2763129473, + 0.2475799173, 0.9650402069, -1.5658047199, 1.2057271004, -2.1787817478, -1.9162775278, 0.3622097671, -0.6148615479, + 2.2243676186, -1.0941650867, -0.1319183856, 0.3140008748, 0.1496839225, -1.5112067461, 1.5638947487, -0.0783534944, + 1.1089277267, 0.0493666902, -0.3356166184, 0.2406343371, -0.257327348, -1.692035079, -0.3557884097, 0.536631465, + 0.9400575161, -0.9624430537, 1.0769087076, -1.0523335934, -0.0877942294, -0.0052203424, 1.4278577566, 0.786134541, + -1.3564819098, 0.113283284, 0.3424504399, 0.5758148432, -0.7315395474, -0.2296319157, 0.7997226119, -1.0046871901, + -0.2958320081, 1.2034623623, -1.9853528738, -0.0400415435, -0.7096756697, 0.5029446483, 0.3679005504, -0.6466954947, + 0.8429231048, -0.3528733253, -0.8913444281, 2.4212992191, 0.422565788, 1.5877314806, 1.0010522604, 0.8875393867, + 0.0978859067, 0.9387049675, 0.9202107191, -1.2897603512, 2.0188601017, 1.4211659431, -0.632660687, 0.305749476, + 2.02221632, 0.9547148347, -0.1210186332, 1.0936723948, 0.4895169139, -0.4024842978, 1.29180336, -0.727232635, + 0.5280922651, 0.9792674184, -0.9152534604, -0.4218613207, 0.7013449669, 0.710532546, 0.449777782, -0.1501760036, + 0.4193355441, 0.0714192092, -0.0715517104, -0.3542770147, -0.3148297369, 0.2007195204, 0.4526666105, 1.2837107182, + 0.6288003922, 1.4994120598, 0.1824219525, 0.9061366916, 1.5625766516, -0.397105515, -0.291295588, -0.0010462973, + 0.6671071053, -0.7881889939, -2.7450766563, 0.4060696363, -0.1217147857, -0.0527308248, -0.5595987439, -1.066364646, + -1.6144676208, -0.8451096416, -0.7483228445, -0.4292066395, -0.7167803645, 0.3249592483, 1.0160164833, 0.5160896182, + 0.5963602662, 1.8268053532, -0.2776781321, -0.408413589, 1.131678462, -0.0133100701, -2.448248148, -0.0586686917, + -0.8878390193, 1.3675085306, -0.0189303663, -0.3145028353, -2.3099646568, -1.7913293839, -0.4868177772, -0.9915539622, + -0.8610973954, 0.5070689917, -0.69193542, 0.4805471301, 2.0585455894, 0.2822274566, -0.651448071, -0.1684999913, + -0.9540156722, -0.5895755887, -0.405053556, -1.8935021162, -0.2592824101, -0.5564218163, -0.5321366787, -0.3610735536, + 0.751526773, -1.0464690924, 0.2622892857, 1.9876885414, 0.3568264544, -0.7345346212, -0.0195515398, -1.3769825697, + 0.3296893537, -0.2662521303, 0.4305160344, 0.8540118933, -0.0390822478, 0.3072167933, 0.2258054018, 0.649242878, + -2.1197884083, -0.7837410569, 1.2383978367, 0.4710659683, 1.172811389, -0.9507129192, 0.2316634953, 1.5851820707, + 0.9761613011, -0.625782907, 0.7709450722, -1.2106201649, -0.1576354951, 2.5922064781, 0.5946409106, -0.8199970126, + 1.3616390228, 0.8881381154, 0.1613833308, -0.7847581506, -0.1245018691, -0.3079818189, -0.2307329029, 1.025801897, + -0.3544710279, 0.4603793323, 0.1158363, -1.5349887609, 0.5325800776, -0.3238184154, -0.7847681642, -1.0883129835, + -0.3599952757, 0.3478820324, 0.8348949552, -0.1920605004, -1.6158021688, -0.4275300503, -0.9156060219, -1.5471988916, + -0.0337640494, 0.3297310174, 0.1512339711, -0.117608346, 0.0440559611, 0.0721314177, -0.0469049104, -0.5487977862, + -0.679890573, 0.1742166579, -0.9439554811, 0.5917685628, -0.0007143845, -0.6769761443, 0.9055025578, 1.287325263, + 0.808935523, 0.1100778431, 0.9906618595, 0.5761532187, 0.3763134181, 1.081784606, -0.2395380288, 0.8779850602, + 0.1564888656, -0.3758312166, -0.9272571802, 1.9166927338, -1.0327939987, 0.1510976553, -0.5881170034, 0.7933108807, + -0.576903522, 2.0220353603, -0.7505076528, 0.920017302, 0.3916193843, 0.2468304783, 1.6190906763, -0.0692143887, + 2.9150190353, 0.6242098808, 0.6861552596, 0.3290536106, -0.046592366, -0.1690702885, 0.2150677294, 0.8022250533, + -0.4570151865, -0.3585347533, -0.8290402889, 0.9220418334, 0.3166327477, 1.3787505627, -0.4238806367, -0.6832771301, + -2.3926756382, 1.3433904648, -0.4304220378, 0.0106177842, 0.0189974494, 0.1315878183, 0.2400119901, 0.3355641663, + -0.4072660506, 0.990383327, 0.1759019643, 1.1644349098, 0.1000541449, -0.4680081308, -1.3790748119, 0.3504778445, + 0.0912212506, -0.7095877528, 0.4825436175, -1.9707536697, -1.7738105059, 1.2781053782, 1.0709049702, -1.1580072641, + -0.0813724622, -1.362356782, 0.3525542617, -0.7098584771, -1.330295682, -1.0732815266, 0.7031227946, 1.6278609037, + 0.3216923773, -1.6622815132, -0.5861720443, 0.7162619233, 0.5596861243, 0.3960135877, -0.1563261449, 0.7563478947, + 0.878293395, 0.6613606215, -0.9163061976, 1.9936851263, 0.7046018243, 0.5298975706, -0.3517471254, -0.2529703975, + -0.6819351912, 0.451162219, -0.3695062697, 0.2835831046, 0.0965076685, 0.9501286149, -2.5614476204, 0.5790864229, + 0.4087923765, -1.2475892305, -1.3186043501, 2.3067893982, -0.5290445685, -0.4532274306, -1.4219975471, 0.4242465794, + -1.1147121191, 1.1617943048, 1.3607591391, -0.1647880673, -0.6505087614, 1.3001717329, -0.4226404727, 0.0101207495, + 0.8180606365, -0.1478663832, -1.138864398, -0.9242997169, 1.6581678391, 0.6156594157, -1.3556060791, 1.0397180319, + 0.0057428153, -1.0736074448, -0.1493596137, 0.0751666129, 0.4852134883, -0.0637846664, 1.2028560638, 0.0310445186, + -0.1631756276, 0.5054315925, -0.6068215966, -0.7260636687, 0.9337012172, 0.4490439594, 0.9612168074, -0.4713724256, + 0.0757001787, -1.2501882315, 0.0985274091, -0.0683198124, 1.4502435923, 0.1849096119, -0.7560486197, -1.8285669088, + 0.6093274951, 0.058663629, 0.2028598487, 0.6563054323, -0.5652397871, 2.2766592503, -0.9085285068, 0.6356878877, + 0.5116490126, -1.5929365158, 0.1327019781, 0.181283161, 1.7507266998, 0.9238305688, 1.8036668301, 0.2698839903, + -0.1360591203, -1.8491562605, -1.5269157887, -1.409126997, -0.4059423804, 1.1683697701, 0.3950791955, -0.3730430007, + 0.9432966709, -0.4507664144, 2.1472918987, 0.4739236236, 1.631064415, 0.420660913, -1.5757130384, -0.9026260376, + 1.4252194166, 1.0862905979, -0.514282465, 0.9228453636, -0.9622536302, 0.5519937873, -0.0327038616, 1.2062320709, + -0.18082726, -1.4194060564, 0.9631287456, -0.6597050428, -1.0749583244, 1.4704674482, 1.8247721195, -0.7203150988, + -1.0254713297, 1.4141848087, 3.0542407036, -1.0799494982, -0.6734762192, -0.1547389776, 0.8099894524, -0.0583977439, + -1.007555604, -1.7363808155, -0.2186141759, 2.605471611, -0.3520674407, -1.4125469923, -0.9866930842, -0.3136315644, + 0.2758622169, -0.0382532291, -0.2909025848, -1.2334349155, -0.6941742301, 0.4460225999, -0.3344380558, 0.2541289926, + -0.7754428387, 0.6982194781, -0.197070539, -0.423216939, -0.2842783928, -2.1254146099, -1.6987265348, 0.8912936449, + 0.0369419828, -0.4753980041, 0.9474012852, -1.1694549322, 0.0957721621, -1.9647138119, 0.8450680971, -1.0638986826, + -1.7959105968, 1.0335805416, -1.0350733995, 1.3430973291, 0.5613515377, -1.3858976364, 0.2772824168, 0.2037287652, + -0.4732226133, -0.940574646, 0.7366333008, 1.3613336086, 0.0208984539, 0.4093787372, 0.087181583, -2.0470230579, + -0.6185591817, 0.5369277, -0.9558705091, 0.4795728326, -1.993049264, 1.2474435568, 0.0068958555, 1.5790319443, + 1.0980535746, -0.063784644, -0.5902965665, -0.0061245328, 2.0637385845, -0.5407064557, -0.841070056, -0.318564862, + -0.343898356, -2.0251550674, 0.1584590971, -0.4653836489, 0.4902653098, 1.1586868763, -0.6380576491, -0.3382273018, + 0.1718517691, 1.804899931, -0.6133977771, 1.1827590466, -0.4546300471, 0.5546512604, -1.0758531094, 0.3262319863, + -1.6125426292, 1.1405082941, 0.9962644577, -0.3908626735, 0.2542061508, -0.5308600664, 0.8220796585, 1.4729973078, + 0.6980400681, 1.9615049362, 1.2876982689, 0.2182829082, 2.1297807693, -1.1058113575, -0.892960012, -1.6870913506, + -0.9594828486, 1.6345727444, -0.2234487683, 0.2769846916, -0.4827255011, 0.6188679338, -0.7529045343, -1.8513833284, + -0.5449662209, -0.2289349586, -0.2275588512, 0.1584722102, -0.9139913321, -0.4197747111, 0.9362422228, 0.8670089245, + -0.0218320917, -0.1137257963, 0.8240271807, -1.0934950113, -0.1945286244, 0.8003533483, -0.2396968752, 1.1544240713, + 0.1843745708, 1.8148233891, -1.2879664898, -0.2209738046, 0.8045834899, -0.0956563428, -0.5216675401, 0.0386822708, + -0.0084566763, 0.753271997, -0.5548394322, -1.2596553564, 0.6709458232, 0.5227302909, 0.3640642464, -0.418527782, + -0.2747395933, -1.3535087109, -0.7166903019, -0.4688091278, -0.7064665556, 0.1297899634, 0.4820433259, 1.622834444, + -0.0645888969, 1.1060124636, 1.3474090099, -0.0167565756, 0.1718845665, -0.71429497, -1.5984379053, -1.363229394, + 0.4917477965, 0.206452921, 0.7901336551, 0.8137999773, 0.7803962827, -1.1908946037, 0.765892148, 0.2878961563, + -0.4552826583, -0.0192807633, 0.2585481405, -0.1401580274, 0.4660041928, -0.2457492054, -1.0530674458, -0.1534679681, + -1.4978170395, 0.5043719411, 0.1542381793, -0.5338128805, -0.3461004198, 0.149121508, 0.7485570908, -0.0845168531, + -0.2989161909, -1.5050033331, -0.2240383327, 0.1300648153, 0.3475236297, -0.1500207782, 0.6453188062, 0.0438788645, + 0.6376432776, -0.5648962855, 0.6896584034, 2.0232799053, -1.0980631113, -0.1578527689, 1.096452117, 0.6350690722, + 1.6230158806, -1.2539564371, -1.8732732534, 0.2195006907, -1.4115343094, -0.3199668527, 0.5239178538, -1.4737608433, + -0.8933182955, -1.3867191076, 0.1345203072, -1.0216890574, 0.9537410736, -0.4129306376, -0.2612096369, -2.0409665108, + -0.0334131494, -0.0334027857, 0.9169976711, -0.7904871702, 1.2259902954, 1.1751644611, -0.4285097718, 0.5169038773, + -1.4336477518, -0.8526900411, 0.4836533964, 0.5627523661, 1.2323125601, 1.4806730747, 0.8469880223, 0.4425852597, + -0.9853484035, 0.0293111708, -1.5114089251, 0.9939314127, -0.5136312246, 1.8423138857, -0.3224902153, 1.3486384153, + 0.1608252227, 2.3281126022, 0.3682502508, 0.8500390053, -1.2086205482, 1.6425739527, 1.6567891836, 2.5163788795, + -0.551671803, -0.7090018392, 0.5536077619, 0.1044385284, 0.5848913193, -0.5738294125, -1.1334881783, 0.4964465499, + -0.4429698884, -0.5444251299, -0.0184476022, 1.0488680601, -1.3786221743, -1.340898633, -0.8560641408, -2.0122303963, + 2.1372659206, 0.5076947212, -0.9105145335, 1.0034862757, -0.5493667722, 0.8107016683, 0.5115770698, 1.4349923134, + -0.2621361017, -0.8416423202, -0.3985565901, 1.4450401068, -0.5568643212, -1.9461606741, 0.1166291758, -0.0909571052, + 0.7195361853, 0.2246374786, -0.605789423, -1.2935698032, -0.3281378448, 0.0623177253, 2.6832988262, -0.9763700366, + -0.1302705854, -0.4990547597, 0.0406178869, -0.7492877841, 0.0462367646, 0.1370660067, 0.9836137891, -1.3005661964, + -0.3430009186, -1.6979012489, -0.6472293139, -0.5646333098, 0.3106422722, -0.9889423251, -1.7156691551, 0.6313973069, + -1.997915864, 0.3836011887, -0.3882793784, -1.7840440273, 0.7430712581, 0.7994744778, -1.2537626028, 1.3493068218, + -1.0350950956, -1.1018353701, -1.8689471483, -1.4032249451, 0.1971910149, -0.479403466, 0.2162466347, 1.1728647947, + 0.2414074838, -1.8751955032, -0.6058746576, 0.3895087242, -0.3630200624, -0.7610980868, -1.3947130442, 0.3746354878, + -0.7805181742, -0.8008945584, -1.1045049429, -0.8625071049, 0.2624949515, -0.8144610524, -1.1403104067, -1.4325137138, + -1.2969572544, 1.1078927517, 1.2386733294, -1.0097072124, 0.4666787088, -1.9054232836, -0.3379438221, -0.9478093982, + -0.1815164536, -2.1254286766, 0.3806206882, 0.3613242805, -0.3807277381, 0.6509169936, -1.1140364408, -1.6195075512, + 0.137272954, 0.8177353144, -1.666377902, 1.6164512634, 0.5298832655, -0.6429971457, 0.4450341761, -0.361320883, + 0.4252066314, -0.319134146, -0.6303688884, -0.6494750381, 0.3941224813, 0.7792255282, -0.7178655267, 0.5349315405, + -0.3798153996, -0.343916744, 0.6115089655, 0.8245086074, 0.1483690888, 0.8659130931, -0.4422810674, 0.2366063893, + -0.8263459802, -0.2544108331, 0.7105622292, 1.2936662436, -0.0061172731, -1.3991149664, -0.2684777379, 0.5478208065, + -0.5861970782, 1.2108368874, 1.2831014395, 2.4623322487, 1.7803323269, 0.0805140138, -0.1960275471, 0.0362248681, + -0.1431263834, 0.465418309, -0.7120475769, -1.4517489672, -0.3825183213, 0.3767770827, -0.2440060675, 0.2647753358, + -0.5264542103, -0.1851858348, -0.5366991758, 1.2142837048, 0.0382215828, 0.2983546853, -1.3661375046, 0.6581992507, + -0.3689630628, -1.1523690224, 0.2207235843, -0.3588210046, -0.5084909201, 0.42371732, -0.2514657378, -1.473741889, + 0.3986872733, 1.4346228838, -0.6114665866, -0.0471816361, 0.7091511488, -1.2037036419, -1.2475736141, -0.2429477423, + 0.0104824426, 0.9887840152, -0.5232872367, -0.6540614367, 2.971770525, -0.8098665476, -1.2220925093, 0.6366750002, + 0.3437053561, 0.2384938598, -1.5848807096, 0.1682298779, 0.7390740514, -1.152359724, 0.5150222182, 0.2875719666, + -0.3649416268, 0.5651715398, -1.4896733761, 0.8772756457, -1.3336732388, -0.7780230045, 1.8497377634, 0.2610572875, + 0.7758993506, 0.0206704233, -1.02820158, 3.1966378689, 0.2818923295, -1.2109206915, -0.832141757, -1.317471981, + 1.2380001545, -0.231425494, -0.8635729551, -0.1830273271, -0.8175476193, -0.4133780003, -1.5508835316, 0.16245386, + -1.0400195122, -0.2823365629, -0.7531560659, -2.6896286011, -2.2430329323, -0.0545572713, 0.1620842814, -0.1392417997, + -1.0881642103, -0.2334382683, 1.0073410273, 0.9778640866, 0.085294649, -0.3693783879, -1.153817296, 0.9188566208, + -1.2099559307, -0.6782140732, -0.1138747409, -0.4954129457, -0.7024160624, 0.1558332443, -0.1858649552, 1.5633962154, + 0.2435840368, 0.2163445055, -1.930346489, -0.4743229151, -0.9498266578, 0.3237558603, -0.2460615784, -0.455360502, + -0.7298208475, -0.35822469, 2.1175317764, -0.8765597939, 0.5634529591, 0.0625522062, -0.9692933559, 1.1842176914, + 0.423053503, 0.4874381721, -0.5687189102, 1.8937847614, -0.1945808977, 1.4794397354, -1.3262608051, -0.8606801033, + 0.2191320211, 0.718806982, 0.0009182103, 0.6576800942, 0.8063944578, 0.8810168505, -0.5035043359, -0.7760851979, + 0.1666544825, 0.1153337806, -0.8356602192, -0.5901991129, -0.3215951622, -0.9975553751, -0.6187186241, 0.2700315416, + 1.2824653387, -0.1581376642, -2.1533644199, -0.7170999646, -0.6648142934, 0.2680378854, -0.4821653366, 0.0698350668, + 0.6788092852, 1.2517094612, 0.0046356483, 0.0086138453, -0.6417683959, -2.4156284332, -0.4155599475, -0.6338680983, + 0.7500723004, -0.5130292773, 0.5746928453, -0.1184019148, -0.2648290098, -2.0818395615, -0.713765204, -0.9739657044, + 0.7537212372, 0.2535819113, 0.616974473, -1.4554769993, 0.3506465554, 0.7433042526, 1.3686823845, 1.4085261822, + 0.9369397163, -1.1510248184, -0.8294801116, -3.0858607292, 1.1538147926, -1.0315407515, 0.4071751833, -2.3339128494, + -2.4373297691, -1.5677690506, 0.597913444, 0.9495761991, -1.1302498579, 1.5698679686, -0.0112411575, -0.4865964055, + -0.6322322488, 2.2198269367, -0.183452636, -1.1265172958, 1.3004908562, -0.8718284965, -1.01758039, 0.1230721474, + 1.2845140696, -0.3991899788, -1.1820335388, -1.5773611069, -1.8915426731, 1.0482774973, 0.4631630778, 0.5453273654, + -1.2216370106, -1.2610167265, 0.3723307848, -0.7056763768, 0.5499272943, -1.4075728655, -0.2471286952, -0.1996609718, + -0.6414245367, -2.0822985172, 1.0572780371, -0.2430976778, 0.9677157402, 0.2788408399, -0.057794109, 0.6746733189, + -0.7687827945, 0.1710018367, 0.2308249325, -1.4008908272, -1.5655425787, -2.2899365425, 1.1975847483, 0.7657328844, + -1.6059250832, 0.6931754947, 0.6015011668, -1.5637310743, -0.358525455, 1.7346768379, -0.4272238016, 0.6572923064, + 0.7208228707, 0.4170411229, 1.6985064745, -0.6069838405, 0.1985742748, 1.3401014805, 0.1548866481, 1.1064743996, + 1.3651067019, -1.29383111, 0.1128372401, 0.4152404964, 1.8631957769, 0.6998057961, -0.785427928, 0.7744868994, + 1.1030099392, -0.6815320849, -0.6766694188, 0.7262734175, 0.1705344319, 1.5088578463, -1.4776148796, -0.0586480461, + 1.1006953716, 0.7420361638, 1.6587747335, 0.1205245256, -0.0020093988, 2.221282959, 1.0334048271, 0.7167780995, + 0.7675334811, -0.4229756892, -1.8542928696, -0.1795200706, -0.3950515389, -0.1793856621, 0.2677515745, -0.2145903558, + 0.9883928895, 0.6095905304, 0.840356648, -2.7272720337, -2.5840220451, 0.4287470877, -0.8445891142, 0.5398139358, + 0.1210710034, 0.9378256798, -0.3317985833, -1.099609971, 0.0415950157, -0.3239310086, 0.3395366967, 0.6336280704, + 0.7191601396, -0.7759758234, 0.1708994955, 3.4803307056, -0.9206820726, -0.4048551321, -1.0755497217, -0.8828337789, + -0.5957428217, -2.1283802986, -0.5010408759, 0.4380800128, 0.1451422721, 0.0548269637, 0.7946581244, 1.5738191605, + 0.4238313138, 1.1378115416, -2.3402349949, 0.2621157765, -0.5924669504, 0.6416893601, -0.0999486968, 0.079348281, + 1.2093353271, 0.6182104349, -0.1222885475, 1.1483215094, -1.2530092001, 0.8336417675, -0.5853553414, -0.8618545532, + -1.0123625994, -0.2709977627, 1.1808912754, 1.0666790009, -0.5410199761, 0.2418011427, -0.0650454462, -1.3687447309, + 0.6643924713, 1.2235996723, -1.2306170464, -0.3710289299, -2.3630490303, -0.0823582411, -1.3592556715, -0.026077779, + 0.4334647059, 0.2359000891, -1.6590589285, -0.6708953977, 1.0374119282, 0.5894627571, 0.1390295923, 0.4612559378, + -1.1581498384, -0.6379216313, -0.5233878493, 0.2453523725, -0.6686667204, -0.2729541361, 0.0582876019, -0.1641405523, + 2.6693544388, -0.7174984813, 1.1088682413, 0.5329573154, 0.0444557518, -0.590839982, 1.7005236149, -0.1409078687, + -1.1669863462, 0.6829881668, -0.1745918244, 0.2864745855, -1.8335051537, 0.4798454344, 0.3556045294, 0.5267731547, + 0.460172236, 0.5871078372, -0.0579544082, -1.0574859381, 0.969907701, -0.1474561393, 0.9218323827, -1.1894884109, + -0.6066743135, -0.8240451217, 0.6136225462, 0.6406924725, -1.2699052095, -0.7971712947, 0.7746338248, -0.9440367222, + -0.0133051872, -0.326569289, -1.1451457739, -2.6992063522, -1.1471670866, 1.6526821852, -0.1636654586, -0.7557908297, + 1.0712401867, 0.9058020711, 0.6016139388, -1.828412652, 1.7088695765, -0.1438959986, 0.9743440151, 1.1755664349, + -0.6853446364, -0.9805140495, -0.7326768041, 0.6781848669, -0.97180444, -1.4187847376, 1.5915788412, 1.6385931969, + 0.6819905043, 0.9449669123, -2.197183609, 0.6113591194, -1.1820850372, -0.3689990342, 1.5513277054, -0.5906776786, + -0.4767121673, 0.8203312755, 1.0888025761, 1.1581448317, -1.555814743, -1.1395241022, 0.8870739341, 0.1858982444, + 0.2697058022, -0.9096365571, 0.3069518507, 1.2159620523, -0.2464475781, 0.3862953186, -0.3224743903, 0.244405061, + -0.6824684143, 0.0999120772, -0.680247128, -1.1838104725, 0.563214004, 0.6371393204, 1.0253103971, 0.3471388221, + -1.4211109877, -0.3159162104, -0.5746237636, -0.1463756412, 0.5199471116, 0.4381284118, -0.9439998269, -1.1170305014, + -1.6122260094, 1.5769633055, 1.3907139301, 1.1999559402, 1.3022366762, -0.6340661645, -0.0995960012, -1.6399950981, + -0.6119499803, 0.1380764097, -0.6237627864, 1.1016682386, -1.9356443882, 0.5634610653, 0.4649307132, 0.5689449906, + -0.6906414628, 1.0428044796, -0.9816251993, -0.0944080576, 0.9025543928, -0.9932280779, 0.7247273922, -1.6060585976, + 0.6052199006, -0.074602589, 0.2692794502, 0.0836235955, -0.6294842362, -0.2354930639, -0.3489116728, 1.4909719229, + 2.2565157413, 1.1001173258, 0.1191658676, 0.2973752916, -0.6802826524, 0.4829027653, 0.6770628691, -0.8792845607, + -0.5022274852, 0.4680658877, 0.0524122715, 1.2018536329, 1.2017225027, 0.2157837749, 0.6835497022, -0.5031975508, + -0.8575496674, -0.7981103063, -1.3048182726, -1.0906238556, -2.106771946, 0.2701582015, -0.1355769187, 0.1928640008, + 0.7015531063, -0.2581508756, 0.0451877564, 0.8290317655, 2.4921574593, 0.6755216122, 0.6239854097, 1.9080717564, + -0.2598963976, 2.0262806416, 0.6672372222, 0.1927894354, -0.5935207009, 1.2906221151, 1.1303480864, 1.8212866783, + 0.1627627015, -0.7681046128, -0.2628323734, -0.18829678, -0.4641387463, 1.1165431738, 0.0123880208, 1.1824625731, + -0.5635791421, 0.4094505906, 0.5499470234, 0.6730532646, 1.138491869, -0.0318734385, 0.5249695778, 0.9564266801, + -0.182973519, -0.8484261036, 0.1849524081, -0.6116765738, 0.404006958, 1.1256523132, 1.3207218647, 2.0485391617, + 0.2022244185, 1.0597351789, 1.2315956354, 0.3742661178, 1.4664480686, 1.0261442661, 0.9445564151, -0.7210229635, + 0.3330769539, 1.1520477533, 0.0342893526, -0.1105533689, -1.1973357201, -0.3417419195, 0.8220157623, 0.7772755027, + -1.5686694384, 1.6022686958, -1.6342042685, 0.9400302172, -0.4801312387, 0.1337077469, -0.0188103653, 0.0742905065, + -0.7465792298, -1.0140510798, 1.7433282137, -0.2325217575, -0.283418119, -0.8204702735, -1.2446351051, -0.2062532604, + 0.8481276631, 0.8852192163, -0.8912778497, 0.3083090186, -1.860394001, 0.3590204418, -0.146296829, 0.8163167238, + 1.3781898022, -0.5198218822, -0.6847628951, -0.8724231124, -0.2871099412, 0.0967746899, -0.0191583131, 0.5907481313, + -1.5904307365, 1.3970313072, -0.2175879031, 0.7887555361, 0.8525711894, 0.9093270302, 1.1224218607, -2.1383500099, + 0.8649312258, 0.882387042, -1.1048812866, -0.9562670588, -0.8385741711, -1.4619178772, -0.1579514742, -0.2121369094, + 1.2227568626, 0.5742275119, 0.0359639078, -4.6599531174, -0.0978555605, 0.8772867918, 0.9253914952, -1.5906937122, + 0.3186887503, 0.7967299223, -1.0925660133, -0.135602653, -2.7123830318, 0.7223868966, -1.3690061569, -1.2025033236, + 0.7792565823, -1.1973105669, 1.717703104, 0.0948203802, 2.5072460175, -1.5663551092, -0.6132227182, 0.1630306989, + 0.5378769636, 0.5238105655, 0.2860624492, -1.1264125109, 0.144503504, -0.5489215255, -0.3247438967, -1.3651691675, + -0.6719406247, -0.3707260489, -0.8329691887, 1.373999238, 1.4054895639, 0.6142627597, 0.3801291585, -1.9824923277, + 0.5518612266, -0.93968153, -0.427808404, 0.0637271479, -0.8120394945, -0.5692890882, 0.905331552, -1.4505615234, + 0.7103596926, -1.2559800148, 0.0491107069, 2.4521374702, -0.9200552106, 0.2403309941, 0.0198677108, 1.2498037815, + 1.2705478668, -0.3080240786, 0.8807117343, -1.7154098749, -0.2565684021, 0.164065212, -1.4016714096, 0.7097941637, + 1.9095629454, 0.9995204806, -0.4326931834, -0.6567226648, 0.18210949, 1.0034320354, -0.3981125355, 2.0536632538, + 1.8618398905, 1.3602993488, -0.4498952627, 2.0644013882, 0.9212067723, -0.2571714818, -0.3730241656, 0.807303071, + 1.3182489872, 0.1169435158, 1.360943675, -0.1411994398, -0.1029899791, -1.9461628199, 0.4719499946, -1.4018038511, + 1.0566523075, 2.1330528259, -0.7859642506, 0.08225438, -1.3732144833, 1.7473028898, -1.0639010668, -1.2659695148, + 0.2229897678, 0.4247764647, 0.4805686474, -0.8474889398, -0.338396132, 0.8022504449, -0.5559909344, -0.4041362405, + -0.5135216713, -1.3163421154, -0.1205931008, 1.5122067928, -0.0104675554, -0.2192304283, -0.1263844669, -1.1371041536, + -0.5089555979, -0.194611758, 0.8600028753, 0.0638399795, -3.5213615894, 1.0045546293, 0.5567478538, -0.688531518, + -1.4055252075, -0.3676231802, -2.920384407, -1.124332428, -0.3046654463, -0.717024982, -0.6134189367, 1.1806969643, + -0.0221272781, 1.1801662445, 0.3245626092, -0.2887108624, -2.0269603729, -1.4936410189, 0.1252851188, 0.5235942602, + 0.7694662213, 0.1733997315, 1.3879876137, 0.933673203, -0.2111702561, -1.0503019094, -2.0826382637, 1.4609395266, + -0.0856881514, -1.7071745396, -1.186704278, 2.1376116276, 0.8348627687, 0.2069842666, 1.7539217472, 0.3535583615, + -1.8743047714, -0.0553962588, 0.8481658697, -0.999561727, 0.3901985884, 0.1343593001, 1.6648913622, 1.2137875557, + 0.3217611909, 1.4884146452, 0.1555677801, 1.058668375, -0.028844811, -1.7163136005, -0.4568204582, 0.6596849561, + 0.3663463891, -1.0010029078, 0.699452579, -1.2128429413, -0.5362828374, 1.0057533979, -1.0551908016, -0.544831574, + -0.3002343476, 0.2546850741, -0.2694426477, -1.7030316591, -0.8511922359, 0.4108665884, 0.8940765262, 0.4596008062, + -2.0727031231, -1.5894145966, 0.6068012118, -1.3510271311, 0.8960603476, -0.6474032998, 0.248650074, -1.2714422941, + -0.0038882706, -1.2690234184, -0.7396576405, -0.0264970679, -0.3070549965, 0.3133223951, -0.0787381977, 0.8041164279, + 0.2555361092, -1.9416064024, -0.9758633375, 1.159485817, 0.6093669534, 0.9097701311, -1.1062548161, 0.8592962623, + -0.2846635282, 0.6063728333, -0.2664417028, 0.3516781628, -0.0238830093, 0.6255849004, -0.7902545333, -2.02647686, + -1.1567298174, 0.1229565144, 0.0750426725, 0.3840484023, 0.6105062366, 1.4286056757, 1.5390007496, 0.021592753, + -0.6384230852, -0.0326580927, -0.4754877985, -0.0593326017, 0.2306943089, -1.5714039803, 0.2333770394, 1.1175312996, + -0.4276227057, -0.2300469875, -0.7984775901, 0.5063858032, 0.7095662355, 0.0707808509, 0.3261324763, -0.5166196227, + 0.7755348086, 1.4209582806, 0.4472828507, 1.5131568909, -0.5091314912, -0.1463637352, -1.2307108641, 0.8167770505, + -0.8237021565, 1.626970768, -1.341594696, 0.0487488285, -0.800463438, -0.6269339323, 1.8451014757, 0.4949062467, + -1.3215615749, 0.6344664693, 0.2089666575, -0.4782479703, 0.3076966107, -1.6594357491, 1.3730232716, -0.2208669931, + -0.5210494995, 0.2851623893, 0.8996701241, -2.5622427464, -0.0674514249, 0.0234192368, 1.014475584, -0.954697907, + 0.8461613655, -0.0649054199, -0.6372078061, 1.3974251747, 0.3746976852, 0.768101573, 0.2594341636, 1.7057238817, + 0.1613429636, 0.0854009017, -0.8134281635, 0.9436557889, -0.9423817396, 0.580109179, 0.1318775266, -0.2848078012, + 0.1335559636, 0.5876556635, -0.317898035, -0.0128314896, 0.0865386352, 0.3319094777, -0.2248116732, 0.0240327138, + 0.6187692881, 0.3574542105, 0.9088279009, 0.069714807, 0.4406653047, -0.1967163235, -0.4700434208, -2.1740925312, + -0.3500843346, 0.1516977102, 0.2233592272, 0.2852753103, 0.6240082383, 0.1125972867, 0.3403343856, -1.4563639164, + 0.3733136654, 2.134626627, -0.9266167879, 0.3932163715, -2.0109872818, -0.0350480564, 0.5640030503, -0.3578226268, + 0.1307384968, -0.2989596725, -0.710901022, 1.3044710159, 0.4014618695, -0.5151721239, -0.0912843123, -0.8773889542, + 0.3478965759, -1.0700992346, -1.2515821457, 0.6234746575, 0.5236243606, -1.6252604723, -1.2834419012, -1.0935277939, + 1.0660840273, 1.424233079, 0.172122553, -0.4695689976, 0.3664133847, 1.7772021294, -0.9540381432, 1.0367292166, + -2.3827981949, -0.3921341002, -0.5850293636, -0.2167987227, 1.3427859545, 0.6053371429, -0.6285265088, 0.3417230546, + 1.3946480751, -0.3851041198, -0.5210492015, -0.8341775537, 1.8781659603, 0.499340862, 0.9196839929, 1.4708603621, + -1.3287057877, -1.8750246763, -0.6538562179, -0.4436583817, 0.3147097826, -0.2363654673, -1.1563998461, -0.7322943807, + -0.8094955087, 0.1966855228, 1.8921687603, 0.1011165977, 1.0714277029, -1.1122522354, -0.8491483927, 1.002654314, + -1.8699041605, 0.4910463989, -1.30075109, -0.7558706999, -1.2062203884, -1.3015846014, 2.2981455326, -0.3842036724, + -0.4086307585, -0.5081439614, 1.0238132477, -0.0232919119, -0.7040374875, -0.6754306555, -0.5368385911, 0.4415324926, + -0.2231244147, 1.5856546164, 0.3726929724, -0.8339967728, -0.3401282132, 0.4355895817, 0.41220209, 0.5042055845, + -1.2808250189, -0.3089379668, 0.2095138282, -0.9887799621, 0.5872370601, -0.4417540729, -1.7355332375, 1.5637019873, + 1.1506174803, 0.0401921943, 0.8149108887, 1.6987164021, -1.0433235168, -0.4187589586, 0.3610968888, -1.5596761703, + -0.373575896, 0.2021843344, 0.6289901733, 0.8797625899, 0.534486711, 0.1503546983, -0.7813857198, 0.2976354361, + 0.7332540154, -0.7058255076, 0.0368137881, 0.3777216375, -0.5616474748, 0.0333609879, 0.7632266283, -1.1654425859, + -0.4225851893, -0.4182069302, -1.7396740913, 1.2583700418, -1.478680253, 0.2079833299, -0.6789172888, 2.009957552, + 0.2491786927, -1.5300163031, -0.3059594631, -1.3193536997, 1.9566799402, 0.6859662533, 0.2039905638, 0.1241332442, + -0.0059582829, 0.4895803034, -2.1932377815, 0.4535388052, -1.3756812811, -0.7140263915, 0.5834588408, -0.4265936911, + -0.771150887, -0.0634818077, -2.0736818314, 0.4877722561, 0.7690168023, -2.2140629292, -0.1235852242, -0.7416536808, + 1.1636881828, 0.7511378527, -0.1915588677, -0.6453274488, -0.4290712178, -0.7228347063, -1.0105632544, -0.5159531832, + -0.4688208699, 0.6070471406, 0.2960442603, 0.7811290622, 1.2193843126, -0.7364284992, -0.5761831999, 0.0020575896, + -0.475336045, -1.2325395346, 2.1083066463, 0.3523429036, -0.9894808531, 0.4212930799, -0.3872063458, -0.739898026, + 0.6265519857, 1.1915148497, 0.5910297632, 0.9382076859, -1.6488192081, 0.9358170629, -0.0788703635, -0.7320182323, + 0.4131195545, -0.617318809, -0.5903555155, -0.2789388299, -0.1472140253, -1.2764873505, -0.121790424, 1.279132843, + -0.6618398428, 0.6625029445, 0.5320830345, -0.4551331699, -0.5017670989, 1.8236455917, 0.691411674, 0.302628696, + 0.1815621406, 0.2498879433, -1.2506207228, -0.0442353934, -0.1216291115, 0.5298925638, -1.5443810225, -0.4020614624, + -0.0662033781, -0.0818239599, -1.4185363054, -1.3683942556, -0.0888589248, 1.7211959362, -0.3998090625, 0.0440240912, + 0.6941738129, -0.0163219403, -0.2769297659, 0.3046324849, -0.2503691316, -0.3313120604, 0.2744653523, -1.2622573376, + -0.2323275506, 0.0178010147, -0.8282309175, 1.0964192152, 0.2451598942, 1.5029834509, -1.4286749363, 0.5833849907, + 0.5235205889, 1.7843471766, 0.3572329283, -1.2430522442, -0.5951647162, 1.7783439159, -0.9175342321, 1.5678970814, + 1.7504197359, 1.783143878, -0.7279756069, 0.4373401701, -1.2401688099, 0.0116553763, 0.0059235734, -1.5822329521, + 0.4546556175, -1.1685270071, 0.2259088755, -0.5036152601, -0.4659640491, 0.0927771181, 2.4530568123, 0.6292487979, + 1.6537941694, 0.3002971411, 0.3096996248, -0.6645023823, -1.5523566008, -0.4031520486, -1.6061965227, 2.7819669247, + -1.0583498478, -0.1395788193, -0.1203634888, 0.1022626758, 0.8720859885, 1.4830600023, -0.4962566197, 1.0328984261, + 0.3373303413, 2.3986284733, 0.1229605749, 0.6004591584, -0.7395074964, 1.4079188108, -0.0688579455, -0.288865149, + 0.0585243143, 0.7603533268, -0.7401866913, -0.654363215, 1.1241512299, 1.3855564594, 0.2501965463, -0.0244971812, + 0.7574801445, 1.2781273127, 1.5284435749, 0.6185496449, 0.5040275455, -0.2804699838, 0.1216544211, -0.6845163703, + 0.7941741347, -0.036609292, -0.6983697414, -1.8522673845, 0.2542896867, -3.2831485271, 0.3953566849, -0.5015579462, + 0.6498671174, -1.1276022196, 1.1505984068, 0.1903680265, -1.2231880426, -0.65737921, -0.4833384156, -0.4638567567, + 1.3860788345, -0.6521995068, 0.1385852545, 0.3805219531, 0.1140052676, -2.4107685089, 0.8874932528, 1.6550575495, + -0.3197214603, -1.3988662958, 0.4590135515, -0.2101721168, 0.4094855785, -0.9342734218, 0.6102930903, -0.0219919235, + 0.8110104799, -0.1327028722, -0.592998445, 0.0896767303, -1.4792257547, -0.6357883811, -0.1910596639, -2.4750189781, + -0.5322038531, 0.5241442919, -0.6994981766, 0.8529137373, -0.4903007746, -0.8817639351, -1.3482192755, -0.0317793489, + 1.2985696793, -0.346593827, -0.5808402896, 0.0075849593, -0.7275836468, 0.8141966462, 0.4521128833, 0.2785006464, + 1.8277621269, -0.5190520287, -0.891466558, 0.2689761817, -0.9662404656, -0.6470789313, 0.2914797664, -0.8155297637, + -1.3739093542, -2.3848102093, -1.1209721565, -0.8182407618, -0.1182447374, -0.3398118019, 0.4466997087, 0.2464601994, + 1.0585348606, -0.2261178344, -1.3365659714, -2.177989006, -2.3538610935, 0.9866024256, 0.852719605, -1.0528454781, + -0.8125745654, -0.3296542466, -1.1564801931, 0.7735942602, 0.9443894625, -1.1332502365, 0.3197281063, 0.2241103351, + -1.9744640589, -0.9417819977, -0.2481104732, 0.3611280024, 0.8934960365, -1.1568579674, -0.5745681524, 0.0709185824, + -0.2200739235, -1.077832818, -0.1161477938, -0.0324398316, -0.499914974, -1.7372184992, -0.0684553757, -0.852854073, + -0.5410062075, 1.150842905, -0.1721008271, 0.134491533, -0.5637725592, -0.3995460272, -0.6501408219, 0.9465684295, + 1.939175725, -0.5684672594, 1.5173685551, -0.6282674074, -0.9417642951, 0.0144041413, 0.0889731869, -0.2330531925, + 0.2974446118, 1.2360913754, 0.1447630525, -0.7290937901, -0.7561873198, 1.1870754957, 0.2414626628, 0.2983992696, + 0.7458506227, 2.1857104301, 0.8399736285, 0.7549082041, 0.7326828837, -0.0318742953, -0.6576696038, 0.0198269822, + -0.6515598297, -0.4805519581, 0.69914639, 2.2100965977, -1.7864370346, -0.6630361676, -1.1771378517, -0.6534810662, + 0.4054700434, -0.6601068974, -0.7464119792, 0.2744610012, 1.6158492565, -1.7060116529, 0.2919547558, 0.1256903559, + -0.7018199563, 0.2004989535, 0.3009130657, 0.893142879, -1.2528479099, -0.9481801987, 0.7718013525, -0.8815566301, + -1.0193971395, 0.0920027643, -0.7858209014, 0.9181225896, -0.75707376, -0.0542134568, 1.0911778212, -1.1670839787, + -0.3656161427, 0.6322442293, 2.5866792202, -0.9024486542, -0.1006447151, 0.0434250124, -0.6026551723, -0.7511234283, + -2.1465878487, -1.3147332668, -1.0441503525, 1.6845152378, -0.9341364503, -0.3411107957, -1.7455786467, -0.5735567212, + -0.3543936908, 0.8459254503, -0.0149782002, 1.0783048868, -1.4044744968, -0.5981349349, 0.7644030452, -0.2567512095, + -0.4749291241, 0.3467444479, -0.0457928218, 0.3171402514, -0.3241792321, -2.8057308197, 0.9024006128, -0.5445762277, + 0.9712939262, 0.4558846056, -0.1432908773, 0.1366594285, 0.5268583298, 0.4409561157, 0.313601613, 0.3074067235, + -0.5648976564, -0.8228408098, -0.9566798806, -0.9248560071, -0.2933781147, 1.1406354904, 0.9162472486, -0.0694442838, + -1.0854730606, 0.4244476855, -1.0796084404, -1.1030313969, 1.4148253202, -0.455606997, 1.437107563, 0.0990088806, + -0.7168421745, -1.4504446983, -0.2324653566, 0.7561825514, 0.1022730097, 0.6021108031, -1.4685246944, -1.6902762651, + -0.9539712071, -2.0895330906, 0.4726255536, -0.4029881656, 0.0007847449, -0.1372971684, -0.0785327554, -0.7824497223, + 0.3144697845, 0.9834409952, -1.3111101389, 0.1794102639, -0.5454942584, -1.227563262, -1.1055543423, 0.1894212812, + -1.2745862007, 0.370056361, -0.0895574987, 0.1387081742, -0.1900572032, -0.8278012872, -0.2102169394, -1.1714949608, + 1.8205448389, 0.1352094561, 1.0171357393, -0.7764116526, -0.9255347848, 0.3677875102, -0.1336479634, 1.0903134346, + -0.5522167683, -0.1727647781, 2.1905345917, 0.0677361563, 0.0585403368, -0.5572353601, -2.4835076332, -1.2631917, + -0.9267233014, -0.3717812896, -0.2926731408, 0.0466216952, -0.751546979, -0.592754364, 1.4340451956, 0.3440235853, + -0.4755963087, 0.3029372394, 0.4228192568, 0.8591195941, 0.918733716, -0.9696948528, -0.8918405771, -0.7458072305, + -0.3890754282, -0.7237933278, 0.272922039, 0.5538294315, 1.1950474977, -0.1350257993, -0.0628644973, -1.0330879688, + 0.8075287938, 0.4006544948, -1.5620900393, -0.2522285283, -0.747834444, -0.7600804567, -2.5066511631, 0.2466514409, + 0.6960947514, 0.804397285, -0.7229521275, 1.8516392708, -0.5131801367, 1.9044151306, 0.7484899163, 0.3236445189, + -0.2882115245, 0.7676124573, -0.3992791474, 1.0807728767, -0.6194197536, 0.1106903628, 1.4164921045, -0.401424706, + -0.897951901, 1.2561978102, 0.4640975296, 1.96398592, -1.8645833731, 0.440279007, 0.2453724444, -0.8920995593, + -0.2342789471, 0.9694778919, -1.5542093515, 0.4818401933, 1.1038746834, 0.0457208902, -0.319550842, -0.1857536137, + -0.5587615967, 0.2741684318, 1.5274512768, -3.0374977589, -0.542301476, -0.0150344083, -0.6761445403, -1.0511331558, + -0.4787085354, 0.2322977632, 0.570115447, 2.6077516079, 1.5823068619, -0.4669645429, 0.978192091, -0.9199672341, + -0.1703516096, 0.4301041663, 0.7154524922, 0.458568573, -0.8489269614, 1.4372155666, 0.8874803185, -0.1794517487, + -0.0144406203, 1.2646210194, -2.9158418179, 0.4403441846, -1.3688344955, 0.8333687186, 0.5244902968, 0.2989941537, + 0.9304910898, 0.6709625721, 0.9794834852, 1.3098096848, -1.1596137285, -0.8816054463, -0.5656709075, 0.9917655587, + 0.4784300923, -0.5290926695, -1.1244556904, 0.3402399421, -0.8361654282, 1.4321713448, 0.8068723083, 2.2013251781, + -0.193937853, -0.4361837804, 0.3527769744, -0.8224888444, 0.2225948572, -0.020732224, 0.1455113739, -1.2164512873, + 0.0929658487, -1.1042196751, 1.4114979506, -0.617369175, 1.9363077879, 1.2560794353, -2.7780065536, 0.7533286214, + 1.3619881868, 1.1684308052, -0.8395903707, 1.9072697163, 0.4078255296, -0.2256548852, -0.5843978524, 0.0805882514, + 1.6368948221, 1.3414212465, -0.6055875421, -1.045429945, 1.3621159792, -0.2686824799, -0.0739303008, 0.5343942642, + -1.3068132401, 0.9384565353, -0.399438709, 0.4542995989, 0.7322161198, 0.7305169106, -0.561436832, 1.1140637398, + 0.6526744962, -0.071909979, 0.9098330736, 1.7640006542, 0.423702389, -0.6691291928, 0.589029789, -1.9160044193, + -1.0037022829, 0.9969838262, 0.8288206458, 0.7137361765, 0.4376760721, -0.3152429163, -0.1279374659, 0.3058860302, + 2.4879970551, -1.6800762415, 1.3998795748, 0.1315685362, -1.500256896, -0.2054777592, -0.5640303493, 1.3824599981, + -1.5066652298, -0.1466574669, 0.0915420279, -1.5763106346, 0.3803360164, 0.3596437871, 1.6621896029, -2.0491542816, + 0.576572299, 0.1055285856, -0.619846046, 0.1618170589, -0.2169940472, -1.3427215815, 2.0164062977, -0.105801709, + 0.1578689814, -0.2270162851, -1.2023625374, 0.1935603917, -1.229840517, 0.8036319017, 0.4344801307, 0.89517349, + -1.2423279285, 1.8490303755, -1.7592107058, -0.0522167459, -0.4019152522, -0.5006610751, -0.3094775975, -1.4385825396, + -1.0389883518, 0.1763581932, -2.088984251, -1.5009762049, -1.7347135544, -0.5499082804, -0.4091817141, -0.508492589, + -1.7259931564, 1.1904336214, 1.4008835554, -0.7470872998, -1.3493409157, 0.7245262265, -1.4676628113, 0.5550032258, + 0.9892581105, 0.4554331899, -0.9375141263, 0.2234862894, 1.4883899689, -1.2857881784, 0.6532883048, 0.4550784528, + -0.4044540226, 1.1459242105, -1.0726145506, 1.7762796879, 0.6335772276, 2.131717205, 0.0332975127, 0.5179934502, + -0.0992914513, -0.773784101, -1.8695286512, -0.7923610806, 0.1761527956, -0.7032017708, 0.5412458181, -0.907805264, + 0.4937606454, 1.1527210474, 1.1989228725, -1.6906565428, -0.6281328201, 0.2278220356, 0.4933513403, -1.0064896345, + -0.0000735259, -0.8934984803, 0.1968393624, 0.6673569083, -0.5315707326, 0.3909243643, -2.2143652439, 0.9027023315, + 1.4943727255, 0.9048801661, 0.2294406146, 0.9573911428, -1.2223769426, 0.1271428764, -0.4152106047, 1.0905336142, + 1.6445459127, -1.5889605284, 0.1431340277, 1.3259994984, 1.2536746264, 0.8460054398, 0.7108342648, -0.1171533167, + -0.7995001078, 0.7147882581, 1.0996558666, -0.8065167665, 1.5425846577, -1.9306179285, -0.5112408996, 1.7824292183, + -0.3771158457, -0.5927338004, 1.0465234518, 0.951797545, 0.8834025264, 1.7332577705, 0.4638868272, -1.2697304487, + -0.1591738909, -1.7999488115, -0.9415250421, -0.1269199103, -0.058091335, -1.2965680361, 2.1223971844, 0.0455871597, + 0.2907867432, -0.336902082, -0.6078436971, -1.5405783653, -0.1512064636, -0.6500342488, 1.2631211281, 1.0848257542, + -1.4378325939, 1.8252682686, -0.3971527517, -0.4756045938, -0.8820447326, -0.0112926476, 1.2548937798, -0.6723657846, + -1.2332930565, -1.6561949253, -0.4634982944, -0.658911705, -0.8096425533, -0.0774505436, -0.958191514, -1.0015362501, + 0.3436736166, -0.7924914956, 0.4270743132, 1.6997318268, 0.1629018933, 2.6756398678, -1.3755729198, 1.0998866558, + 1.8532304764, -0.2589176893, -1.5839751959, 1.2968481779, 0.1454011351, 1.026664257, -0.9606741071, 0.2631573379, + -0.6971349716, -0.7989433408, 0.6325493455, 0.5290307403, -0.8914008141, -1.4983018637, 0.1810698956, -0.0936394185, + 0.7586063147, -1.2714086771, -0.1377002895, 2.1368517876, 0.0857330486, -0.9389966726, 1.3523417711, 1.9735085964, + 1.8241761923, -1.9587459564, 0.3082878888, -1.1944063902, -0.4493401945, 1.2215254307, 0.1729801297, -0.0349820703, + 1.202955246, 0.5404530764, -0.0075979042, -1.0764358044, -0.7699571252, 1.183400631, 0.5547564626, 0.9156490564, + -0.9856804609, -0.2785350978, -0.5186696053, 1.3056958914, 1.0631380081, 0.1274959594, -0.240180552, 0.1479017437, + -0.058240477, -0.0790114775, 1.0718803406, 0.7031837702, -1.913512826, 0.3803895712, 0.5894224644, -0.2192968726, + -0.6255428195, -0.6426970959, -0.9397515059, 0.584068954, 1.328447938, 1.3117339611, -1.5271680355, -0.3960041106, + 0.6294850707, 2.4824326038, -0.9239836931, -0.5315219164, -1.0664471388, -1.2447993755, 0.5901226997, 0.2070456147, + 0.9431948662, -1.0233124495, 0.6501449943, -0.0389963426, -0.1377603114, -0.1678514928, -1.2874910831, -1.5522481203, + 0.8630752563, -0.3618498445, -0.2759974897, -0.8493277431, 1.7580159903, 0.9600577354, -1.8509514332, -0.9705380201, + 1.6187961102, 2.1266665459, 0.0816572905, -0.4026440084, -1.1554012299, -0.2847146988, 0.2674738467, -0.8082942367, + -0.8134348392, 1.1221520901, 0.027093865, -2.2677624226, -0.9180805683, 0.2363503575, 0.2875520289, 0.8363741636, + -0.0643644705, -1.5559432507, 1.643274188, 0.5946225524, 0.4202830791, 0.010996866, 0.6184870005, -0.4283002019, + -0.3038954735, 0.2131291479, 0.0461715311, 1.5333558321, 1.9102970362, 0.0692449957, 1.039309144, 0.1182040423, + -0.7626225352, 0.6060833931, -0.4008977413, -0.5854520202, -1.5112763643, 0.9768438339, 1.2555006742, 0.371232152, + 0.3047838807, 0.5041245818, 0.1352996081, 0.6537587643, -0.1001813114, -0.8632913828, -0.7738704681, -0.8903281093, + 0.0303989761, -1.5796298981, -1.8807632923, 0.4715923071, 0.70076406, -0.4200832248, -0.6220460534, -0.0537967421, + 0.6815012693, -1.299664855, 0.7641907334, 0.1130914018, 0.3476420939, 0.8941524029, 0.0757900104, 1.6656370163, + 0.4651370049, 0.7107572556, -2.1352045536, 0.9271841049, 1.399528265, -1.473374486, 0.3333723545, 1.2920279503, + -0.0935617089, -1.4775958061, -2.2185895443, -1.0155769587, -0.0170312412, 0.4430365562, -0.0669785142, 2.0955364704, + -1.2891235352, -0.3313333094, 0.1508097947, -1.0214672089, 0.6050590277, -0.3226830959, -0.6393830776, -0.7354826927, + 0.5948662162, 0.0514817126, -0.348747313, 0.2998561263, -2.3917312622, 1.938980341, 1.3662700653, -0.2757565379, + -0.3776474595, 0.0289556049, 0.4271129966, -1.4703136683, -0.8241951466, -0.9340753555, -0.0965261236, -0.3129947484, + -2.1099956036, -0.4961585999, -0.6232930422, -0.4650352299, 0.9700036645, -0.1744728535, 1.5180350542, 0.6357852817, + -0.2957075536, -0.7334786654, 0.3546252549, 0.1438398659, 0.011488121, 2.3138237, 0.6166037321, 0.5094236135, + 0.2026752681, -0.844094336, -0.5575982928, 0.3867180049, 0.9236090779, 0.2406300455, 0.9912159443, 0.5896103978, + 0.3247047365, -0.0631345809, -0.8472291231, 0.4703036845, 0.5695025325, 0.1397066861, -0.2487258315, 1.1258966923, + -1.0027259588, -1.0338441133, 1.1072216034, -0.7892639637, 1.6951647997, 0.1438161433, 0.0723784938, 1.4623792171, + 0.6937738061, 0.0695512146, 2.1728897095, -0.3971661031, 1.0819935799, 0.3043802977, 1.4986712933, 0.6935018301, + 0.5144372582, -0.7089034915, 2.025277853, 2.0352370739, -0.5140570402, -0.4385772347, 0.1052131802, 0.7070764899, + 1.129884243, 0.9526279569, -0.3403368294, 0.3679586947, -0.5590703487, 0.5506619811, -1.255408287, 0.9212560058, + 0.3789348006, 0.416218102, 0.8884142041, 0.8954343796, 1.3765288591, 0.1669536531, 2.1947975159, -1.0765970945, + -0.4415110648, -0.8056438565, -0.5395519137, 1.4391063452, -1.0550506115, -0.3433833122, -0.7339180708, -0.5391919017, + -0.2920258939, 2.4956951141, 1.7541620731, 0.3999114931, -0.5657392144, -1.4513942003, 0.0673754513, 1.3311697245, + -0.9032511711, -1.1899926662, 0.9078088403, -0.5799974799, -1.0377428532, -0.6368058324, 0.3528950512, 0.4219335318, + -0.1826667786, -0.5943683386, 2.2517185211, 0.7124376297, -0.5504871011, -0.8670164347, -0.2532586455, -0.9611055851, + 0.5109337568, -0.9788072705, 0.7710443735, 0.0522208549, -0.1642433405, -0.2398169041, 1.0718778372, -0.2769748271, + 0.8341576457, -0.912841022, 0.6022919416, -1.1872302294, 0.5882807374, -0.783798337, 0.0029770739, 0.9149373174, + -0.0023518181, -0.3423418403, -0.2342749983, -0.2588711977, 0.5861242414, 0.2901591957, -1.9919506311, -0.5077320933, + -1.0557484627, -1.3903524876, -0.8617141247, 1.8194987774, 1.4909827709, 1.1573592424, -3.581045866, -0.9443206787, + -0.6563444734, -1.9958139658, -0.4275041521, -1.9974306822, 1.0515087843, 1.4036556482, -0.82394135, -0.2179917097, + 0.8843204975, 0.4367180169, -0.9152120352, 0.5092750192, -0.4325858355, -0.2898980379, 0.1608916968, 0.0433968008, + 0.7225730419, -2.3706922531, -0.1152571887, -0.2443416417, -1.7064037323, -2.2502951622, 0.962361753, -0.9202928543, + 0.5554278493, 1.4936690331, -0.8538382649, 0.4118251801, 0.4199622273, 1.0834783316, 0.7692968249, 0.9061453938, + -1.7944680452, -1.6934518814, 1.0800925493, 2.9148349762, -0.6273124814, -1.0704936981, -1.0964157581, 1.2692940235, + -0.0670206621, 0.4683865309, -0.2278233916, -1.6969687939, -0.1294624507, 1.3910541534, -0.8832511306, -0.5370650291, + -2.7819578648, 1.0052194595, 0.0291601941, 0.1069035754, 0.1541337669, 0.4313090146, -0.0532100685, -0.2221809328, + -1.2927292585, 2.0467059612, 0.671784699, -1.46433568, -0.5161830783, 0.8706104755, -0.7400351763, 1.7521550655, + 0.7392818332, 1.1075246334, -0.9495987296, -0.2971502244, -1.7795100212, -0.3664148152, 0.3774253428, -0.3637647033, + 1.0382292271, 0.9270262718, 0.9909930229, 0.4617742598, -1.7854360342, 1.1072719097, -0.4553121328, -0.1896470487, + 0.7345716357, -0.1584715992, 0.125674352, -0.4396451116, 1.7899280787, 0.429097712, -1.1429880857, 0.1356596798, + 0.2704877853, -2.9028491974, 0.263584733, -0.2302935719, 1.4411734343, 0.7899709344, 0.7097681165, -0.1670908928, + -1.1633665562, 0.8314404488, -0.5223177075, -0.6025066376, -1.0426368713, -1.0971044302, 0.0751154199, -0.0060958047, + 0.5358031988, -0.3496257663, 0.1946886927, -1.0601308346, -0.3055567741, 0.7915786505, -0.6497223377, 0.1561425328, + 0.0680144206, 0.188538596, -0.0341186747, -0.0913931131, 3.281321764, 0.7469103336, -0.7709512115, -0.6652572155, + 0.6616647243, 0.8398932219, 0.1677317768, 0.2261482328, 0.5642980337, -0.9490278363, -0.4119906127, 0.8089081645, + 2.3489282131, 0.0059719253, 0.127776444, 0.48319453, -0.1986074001, 1.3758893013, 0.9559911489, -0.3276863098, + -1.9237053394, -0.0273960028, 1.2066987753, 0.5038545132, 2.0547614098, -1.0013649464, -1.2404457331, -1.61752069, + -1.8106907606, -2.2587397099, 1.4911020994, 0.507706821, 0.157862559, -0.2871367633, 0.298217088, 0.2387153804, + -0.8506680131, 0.7121008039, 0.2630681098, -0.4266733825, -1.2599084377, 0.1100775227, -0.7961258292, 0.0884582102, + -0.4036722779, 0.255454123, -0.7653817534, 1.2740881443, -0.9017828703, 1.0660438538, 0.2381526232, 1.3428379297, + -0.9337721467, 0.5818094611, 0.6203938723, 0.5277485847, -1.3358016014, -1.0161755085, -0.3920041919, -0.3217634261, + 0.0977156609, -0.7099808455, -2.1828842163, -0.249262616, 0.5232057571, 0.6404082179, -2.8672451973, 0.0099505708, + 0.0627208427, 0.5408713222, -0.8533446193, -1.0616909266, 2.1865887642, 0.7885946631, 1.6995860338, 0.89870435, + -1.2937207222, -1.3201901913, -0.3269158304, -0.5847586989, 1.1706972122, -0.3119771183, -0.8133928776, 2.2317814827, + -0.0656682402, -1.2794408798, 0.7121872902, 0.6827929616, -0.9849511385, 0.2409691066, 1.4361633062, 0.8795505762, + -0.1011779606, -0.3517198861, -1.3311268091, 0.0398764387, -2.5397872925, 0.5240123272, -1.1318515539, 0.1736470163, + 2.3500032425, -1.0210710764, -0.9013856053, 1.2843419313, 0.1951693445, 0.2922241092, -0.9190829396, 1.3920661211, + 0.3929746747, -0.2270657122, -0.022144204, 0.5061912537, -0.7442373633, -0.3657039106, -0.6952665448, 0.6621089578, + -0.1160282418, 1.0427018404, -0.4019634724, 0.3994499743, 1.1279504299, 0.1322755814, 0.0824102312, 0.1473124176, + 0.7525485158, 1.3919463158, 0.9325844646, -0.2164360136, -2.0686099529, -0.3924939334, -0.2780714035, 0.0101592699, + 0.6358350515, -1.431309104, -1.1910624504, -2.2517459393, 0.1745254099, 1.0222985744, 1.6670593023, 0.524943471, + -0.1815162599, 1.821408987, -1.4406580925, -0.9919193387, -0.531076014, 0.2919684052, -1.631323576, 0.3511316478, + -0.9309894443, 1.1974879503, -1.6794967651, -0.8118848205, -0.8416833878, 2.4623873234, 0.3009655476, -1.4257361889, + 0.6312994361, 2.2594048977, 0.6614672542, 0.9749627113, -0.8439388275, -0.6263849735, 1.0214941502, 1.8435775042, + -0.7835627198, -0.5893369317, 0.9996767044, -1.7351483107, 0.5586682558, -0.9594988823, 1.1005119085, 0.2692739367, + -1.025713563, -0.7306185961, -0.370785594, 1.0002390146, 1.7818371058, 0.2506727278, -0.1208279952, 0.7990749478, + 0.4406612515, -2.7838218212, 0.3292020559, -1.1683198214, -0.7424931526, -1.6718312502, -2.2292375565, -1.5895670652, + -2.1763262749, 0.646592617, -0.2387440056, -1.2814507484, 1.5724308491, -0.0866635591, 0.3556214273, -1.5556114912, + 2.2516131401, -0.0788190961, -0.9873566628, -0.5010582209, 0.5617690086, -1.3074728251, -0.6975981593, -0.238298133, + -0.8825020194, -0.3499997556, 0.8037531972, 0.2698097825, 1.4658676386, 0.8141592145, 0.6054009795, 0.7439873219, + -0.9993648529, 0.3399610519, 2.7317314148, -1.081084013, 0.1323891431, 0.3207344413, -0.6511629224, 0.3457941711, + -0.7831311226, -0.9879703522, 0.3776917756, 0.8772977591, -1.7880016565, 0.2965702415, -0.9034597278, 1.7864934206, + 0.9782868624, -0.295696497, 0.6477823257, 0.0506903753, 0.5080415606, -1.3493453264, 0.2018167675, -1.4426267147, + -1.180842042, 1.0383150578, 0.986055553, 1.8076187372, -2.0575242043, -0.6333572268, -0.204187572, -0.9048840404, + -1.3473826647, -0.2191231549, -0.5989145041, -0.9193871617, 0.7825738788, -0.6629906893, -0.0044529312, 0.4017296731, + 0.5302216411, -0.6302867532, 0.1900966913, 0.1169983447, 0.6267263889, 0.2086966336, -0.3434092402, -0.0818031728, + 0.2871176302, 1.8508354425, -0.4121738076, -0.3695137501, -0.8422460556, 1.0362706184, -1.5687952042, 1.3191411495, + -1.423807025, -0.142526716, 0.1950446665, -0.0501813479, -0.9971384406, 0.5666148663, -0.7734076381, 2.1213474274, + 1.0192799568, -0.2502143681, -2.5300765038, -0.1859777421, -0.5562409759, -2.1014626026, -1.5545033216, -1.9805938005, + -0.3614606857, 1.0864875317, -0.6382172108, -0.1713171601, 1.4588235617, -0.1968735009, 0.345718652, -1.2535402775, + -0.4798072278, -0.5499140024, -0.6521920562, 0.074571915, -1.3990981579, 1.5811384916, 0.9943895936, 0.8224885464, + -0.9130792618, 0.6656284928, 0.4408087134, -1.086383462, 1.6354051828, -0.183004275, 2.0229175091, 0.91308254, + -0.7718485594, 0.5636826158, 0.9207437038, 0.6272261143, -0.0113689406, 0.1329929233, -0.7101846933, 0.7689437866, + -1.180108428, -0.2835783064, 0.4113340974, 0.532772541, -0.7214313745, -1.5421614647, -1.9424954653, -1.6779434681, + -0.0172744263, -0.5212426782, 2.3069400787, 0.4098668694, -0.3884662688, -1.4270358086, -0.4474042058, 0.062609084, + -0.690898478, 1.6261773109, -1.3247954845, -0.9704781771, -0.8681657314, -1.9094009399, 0.7300789952, 0.0771100372, + -1.2461156845, 0.3015325367, 0.3156217039, -0.0172931459, -0.4923977852, 0.8767017722, -1.7975519896, -1.3432596922, + -0.1768195033, 0.2010150999, -0.0109114358, 0.2074261457, -0.0014144401, 1.3219326735, -0.1442534029, 1.5599341393, + 0.5865324736, -1.0671136379, 0.94320786, -2.4022483826, -1.6965386868, -0.3520489037, -0.6729676127, -0.4498138726, + -0.1366031319, 2.2423534393, -0.6495697498, -0.6955966353, 0.269010216, 0.0754883811, -0.2480758727, 0.4548644722, + -1.6006692648, 2.9957056046, 1.1254948378, 0.1499847472, 0.1920881867, -0.5768033862, 0.2211746275, -0.2526126206, + -1.2733937502, -2.1981089115, -0.1316194385, 0.611074388, -0.4321219325, -2.6817026138, -0.1910612583, 0.9476387501, + -0.983207643, -1.169060111, 0.3118586838, 0.1494942456, -0.0717568323, 0.1027661785, 1.6578212976, -0.4804956317, + 0.4835452437, 0.1303046048, 0.8426531553, -0.4875191748, 1.4141306877, 1.9516247511, -1.520934701, 0.1807358265, + 1.0086404085, 0.1693771333, -0.6385271549, 0.3150402606, 0.2134657651, 0.1275645643, -0.2692812979, -0.4176293314, + -0.5310031176, -1.2867263556, 0.4024953544, -0.6629074216, -0.8900157213, 0.0173238255, -1.3357878923, -1.473919034, + 1.2099581957, -0.8706635833, -1.1307188272, 2.5382192135, -1.3760643005, -0.8997769356, 0.0810065046, -0.9796665907, + -1.98003304, -1.3330463171, -0.0266266223, 0.6131624579, 0.730925858, -0.4710527658, 1.818696022, 1.0128185749, + -0.2675081193, 0.3097981215, -0.3390848637, 1.3907425404, -0.1129092425, -0.112822026, -0.7463982105, 0.3480891287, + 0.1308476329, -0.8871914148, -1.1553707123, -0.8099475503, 0.9398341179, 0.6741917133, 0.5551754832, 2.3883841038, + 0.0637566, -0.3006283641, 1.793159008, 0.6349275708, 0.0974078625, 1.9796898365, 0.963721633, 1.2067064047, + 2.6625752449, -2.9752113819, -0.2145902961, 0.8895272017, -2.5124297142, -1.1934756041, 0.6111067533, 0.5439530611, + 0.919574976, -0.0145593109, -0.1723228544, 0.8032369018, -0.1235672086, 0.8890910745, -0.5182160139, 0.6868421435, + 1.3251487017, 2.2621772289, -0.9907764196, 1.2263659239, -0.7818847299, 2.553403616, 0.0250207074, -0.6922243237, + 0.4500946105, 0.8247621059, -1.5440511703, 1.0582951307, 0.9684923887, 0.0219670925, -0.6095378995, 0.2694644332, + 0.6649788022, -1.0967034101, -0.7213160992, 1.1593426466, 1.0333893299, -1.1508731842, 0.6200610995, 1.0737234354, + -2.6945307255, 1.0907959938, -0.4236430526, 0.5467333794, 0.3633519411, -1.4687079191, 0.2660523951, 0.4187117815, + -0.268953532, -0.7421191335, 0.4190295637, -0.0754861236, -0.9021491408, 1.7387038469, -1.0696322918, 1.2910215855, + -0.9210324287, -0.5588905215, 1.5117577314, -0.701677382, 1.5223786831, 1.0122696161, -0.4869149625, -2.673071146, + -0.4777221382, 0.3872422874, 0.1491771042, 1.2386612892, 0.1987817436, 0.7457051277, 1.2785915136, 0.1476992965, + 0.2074522674, -0.4072807729, -0.5786799788, -3.3096375465, -0.684037149, -0.8496714234, -1.0677458048, 1.0516594648, + 0.3639971912, 0.024367515, -0.0318917781, -0.0292874929, 0.4616909027, 1.9434530735, 1.6624674797, 0.8748117685, + 2.0247778893, -1.5770218372, 1.6974775791, 0.7939242125, -0.1475799233, -0.4257296026, -0.9291113019, -0.176596567, + -0.9489408135, -1.0270024538, 0.3457305431, -0.1267700195, -0.8588191271, 0.0220551956, 0.4580956995, -0.8898931146, + 0.6698141694, 1.1612095833, 1.5577360392, -0.0882073417, -0.1198285371, 0.5890731215, -0.3089555502, -0.9081842303, + -0.1492018104, -1.7106012106, -0.7759175897, -0.4991606772, 2.0636332035, -1.221196413, 0.208291471, -1.8170255423, + 0.1874208301, 0.8306953311, 0.1591050774, 0.1346683651, 0.5078101158, 0.3186313212, 0.0747938156, 1.1232910156, + 1.1165424585, -1.5080624819, -1.8543579578, 0.4946228862, -0.3128373027, -0.8260221481, -1.1768620014, 2.7075240612, + -0.8599362969, -0.1943347603, 0.3728359938, 1.5643889904, 0.1224704236, -0.2554540038, -2.4267845154, -1.2763670683, + 0.1865660548, 0.9339870214, 2.1913509369, 1.0479716063, 0.5310890675, -0.4444085956, 0.0102695441, -0.4931077957, + -0.8591019511, 0.3635742068, 0.1819271296, 1.4570590258, 0.6254669428, -0.076621294, 0.7366033792, 0.407333672, + 0.3157582879, 1.2674711943, 1.5260124207, -0.1460522711, -0.6169248223, 0.7802696228, -1.1895266771, -1.6959145069, + 1.0615260601, 0.7290648818, -0.0039269542, -0.2192747742, -1.2065370083, -0.5926264524, 0.4990629554, 0.6350317001, + 0.2500172257, -0.776746273, 0.1204522327, -0.0855962262, -2.9598872662, -0.0594991967, 0.0107230311, -0.6957206726, + 0.6268827319, 0.8848359585, -1.0965247154, -0.3538480401, -0.2793050408, -0.6663282514, 1.6578052044, 0.9893534184, + 0.6942030787, -0.0255823508, -2.1172115803, 0.8453764915, 0.0800878629, -0.0446344092, -1.3436617851, -0.362965554, + 0.7153369784, 1.8806054592, 0.5140509009, 1.3209331036, -1.5869755745, 0.0630695596, 1.0406191349, -1.1759856939, + 0.7265060544, 0.5853495598, -0.4912182987, -2.3420684338, 0.2360036075, -0.0184030049, -0.2514174879, -0.5149710774, + -0.9576873779, 1.1475124359, -0.3164398074, -0.6195050478, 0.9377791286, 0.6614924073, -2.1293914318, -0.8671734333, + 1.8095625639, 1.2773045301, 0.7302829623, 0.9080862403, 0.4408243597, 0.1983782947, -0.6720163822, -0.5482321978, + 0.1505797505, 0.5328464508, -0.5543004274, -0.2349988371, 0.3065464199, 0.2317438871, -0.2143950164, -1.950470686, + 0.3647886813, -0.9620810151, -0.5049009919, 1.1725252867, -0.2122905999, -0.0769631341, -1.5674600601, 0.1936446875, + 0.9210233688, -0.7128981352, -1.8007926941, 0.3849214613, 0.9164446592, -1.5944501162, 0.4832324684, 1.2739291191, + 0.3470695019, 0.719289422, -1.2342510223, -0.5707786679, 0.3982577324, 1.6125490665, 0.8283737302, -0.4355474114, + -0.551690042, 1.8830914497, 1.4993001223, -0.4664620161, -0.64402771, -0.1982753575, 1.733599782, 0.7828823328, + 0.45208022, -1.0521594286, 0.6122381687, 2.5034127235, -0.2546629012, -0.0021838548, -0.3127757013, -0.2439358383, + 2.8342952728, -1.1100224257, -1.8255298138, -0.2851569653, 0.6020030379, -0.0797088295, 2.1328616142, -1.2060884237, + -1.0391825438, 1.9026936293, 1.5160888433, 0.2516080439, -0.7265576124, 0.6257002354, 0.2562513053, 0.3520869315, + 0.2826059759, 0.7028957605, -1.1565545797, 3.2492113113, 0.6998537183, 0.343505621, 0.0474957936, 0.0238234904, + 1.007522583, 1.0553672314, -0.5581072569, 1.4102920294, -0.8471719027, -0.3154569268, 0.3686653078, 0.3602911532, + 0.4066274166, -0.6914747953, -0.2434081584, 0.1288081408, 1.6579293013, 1.3141508102, 1.4821339846, -2.0403368473, + 0.6059473753, -1.0832898617, -1.4585893154, -0.372815907, -1.8068834543, 0.3847947121, 0.5434930921, -0.3806275427, + 0.8868139982, 1.4337956905, 0.3013240099, 0.3587332964, -1.2386696339, -0.8911620975, 0.0859268382, 1.1943483353, + -0.6367681623, -0.6623798609, -0.2061398029, -0.5292823315, -1.527153492, 0.325425148, -0.0908186063, -0.728663981, + 1.3047002554, -0.0827621073, -0.1901878268, -1.0190961361, 0.9524612427, 1.553676486, 0.108095929, 0.7212635875, + 0.1993038505, -1.4570226669, -1.6779817343, 0.3893408775, 0.3303967416, 1.0638159513, 1.7132321596, 0.8575462103, + -1.6333636045, -0.4927726984, 0.7085943222, -0.6649975181, -0.7540698051, 0.3705411851, 1.5952237844, -0.9408431649, + 0.8396894932, -0.0682655498, 0.1102770716, -0.1911044121, -0.3837050498, 0.1033612564, 0.4805106521, 1.1790075302, + -0.3850603402, -1.577252388, 0.141890496, 0.2107743323, 1.0745302439, -0.1163458973, -0.2989508212, -0.1717454642, + -0.1741078496, -0.5722891092, -1.1931658983, -1.0240820646, 1.3909329176, -0.5920624137, -1.3037887812, -0.4021603465, + 0.4387072921, -0.4330362976, 1.8886967897, 1.1421550512, -0.6339848638, -0.4418257177, 0.372169584, 0.2701981068, + 1.325805068, -0.5577306747, -0.0739254504, 0.3768513799, 0.4234072566, -0.5511019826, 1.1147866249, 2.3339898586, + 0.4122173786, -0.5530776381, 0.3115015626, 0.0289805699, 1.5773285627, -1.2268995047, 0.4624019861, 1.0431036949, + -0.2830632031, -0.6748375893, -0.0909511521, -0.0818173736, -0.7964636683, 1.1432673931, -0.5838388205, -0.7343836427, + 0.8128823042, -1.9741328955, 1.0655366182, -0.1382042468, -0.4833156466, -1.5031466484, 0.0463636853, -1.9227097034, + -0.6942155361, -0.0444220677, -2.9480149746, -1.3248479366, -0.7946349978, 0.1203350052, -1.817820549, -0.8409462571, + 0.0176582448, 0.7654770017, -1.1241449118, 1.0637383461, 1.5732291937, -0.2002674639, -0.362967968, -1.1078330278, + 0.3732503355, 0.0650348887, 1.0154954195, 0.5308608413, 0.8413332701, -0.8172613978, -1.2249294519, -0.14627707, + -0.8106113076, 1.2757968903, 0.8820825815, 0.8402888775, 1.7235717773, -0.222275123, -0.4631427824, -2.001127243, + -1.3081351519, 0.3727766871, 0.268125236, 0.98547405, -2.228341341, -1.8407127857, -0.8173459172, -0.1097566634, + -0.249026835, 0.0852077156, -1.7533066273, -0.0306593943, 0.0494587459, -1.7486133575, 1.022362113, 0.9939898849, + 0.8368474841, 0.4449765682, -0.9100048542, 0.1528287232, 1.8625997305, 0.2812252343, -0.4299602211, 1.2618894577, + 0.4911216199, -0.2961321175, -0.3500322402, 0.9766417146, -0.6072682738, -0.3793948293, -0.2228083014, 0.7391654849, + -1.3898029327, 1.9329074621, -0.9888586998, -1.6468340158, 1.3287822008, -0.4032287598, -0.6147022843, 0.8088668585, + 0.2952104509, 0.4654255807, 0.4560590386, -1.1324355602, 0.8947141171, 0.4242992103, -0.72340101, 0.139529705, + -0.5978423953, -0.0356286205, 0.9698703885, 0.5998618007, 1.1406219006, -0.3814889491, -0.9062640071, -0.4771881998, + -0.2948560417, 0.7076987028, -0.9771244526, -0.548088491, -0.3703163564, -0.2734317183, 1.2818864584, 0.8690806031, + -0.2168426067, -1.001371026, 0.3965295255, -1.348074913, -1.3271099329, -0.3585632443, 0.1892410517, 0.3836632073, + -0.3862533867, -0.1512429714, 0.8624945879, -0.5295600295, 0.9678261876, 0.5995805264, 0.8620498776, -1.7274713516, + 0.935403049, 0.813965857, -0.8361479044, -0.1532518119, 0.0936337113, -2.4775524139, -1.9780313969, 0.2005530298, + 0.8046504259, 1.72653687, -1.1824663877, 1.0006707907, 0.2549159527, -0.5395684838, -1.3906004429, 1.159971714, + -1.1941506863, -0.0242273454, 1.0806976557, -0.6423122287, -1.7502503395, -0.0535725392, 1.0014064312, 0.3842054307, + -0.9795367718, 0.0303774159, -0.5324507952, -0.3401973248, -1.1212528944, 0.0285949763, 0.4956311285, -0.2267297208, + -1.3515195847, 0.4184161723, 0.1721993089, 0.7958292365, 0.1263063103, 0.2711284459, -0.2135034651, -0.7038419247, + 0.2187733203, -0.5362712145, 0.1083598137, -0.2600317895, -1.2274924517, 0.6941085458, -1.5299791098, 0.495193094, + 0.0788252577, 1.3300241232, -0.9726471305, 1.7447634935, 0.7137358189, 0.4610167146, -0.3599465191, -0.1522779316, + 1.7052100897, 1.5464543104, -0.1919985265, -0.2842799425, 0.6308130622, 2.0006842613, 0.4859058261, 0.8829320073, + -0.1657233387, -1.2302795649, -0.557207346, -0.8428971171, -0.046597667, -0.2116975784, -0.1333411336, -1.3210440874, + -0.6006979942, -0.4126179218, 0.0754443184, 0.7098649144, -0.7600352168, -0.6254181862, -0.4199784398, -0.0825512707, + -1.0666607618, 1.6464910507, -1.1209568977, -0.7917913795, 0.112986587, 0.0059932861, -0.4723086357, -0.2796922922, + 0.5758187175, 0.9736551046, 0.2789586484, -0.5730145574, -0.4830294251, -0.248906821, -1.9525696039, -0.6475285292, + -0.2628311813, -0.7734012008, 0.8395585418, 2.5376198292, -0.336586833, 0.5846264958, 1.0598243475, -1.1626652479, + 0.0405477248, -0.9395235181, -0.2485307753, 0.0545488633, -0.9857591391, 2.4720458984, 2.0487780571, -1.2066218853, + -0.0878543928, 0.9413759112, 0.9323689938, -2.0413239002, 0.2184711546, -1.9071009159, 1.170078516, 0.5026462078, + 1.8074660301, -1.5341821909, -0.2498243898, -0.4873360395, -0.6551302075, 0.8344846964, 0.3601314127, -0.4684588313, + 1.2849541903, 2.2285103798, -1.0161749125, -0.0508062355, 0.7545269728, 1.4866827726, -0.9345136285, 0.7692088485, + -2.3289158344, 0.2548599243, 0.2512003779, -0.9487016201, 0.2089540064, -0.9035751224, 1.4267714024, -1.0731743574, + 1.707670927, 1.2272638083, 0.2197493315, -0.5237355232, -0.1973887086, -0.210874483, -0.5565663576, -0.699575305, + -0.5322136283, 0.3217452466, 1.1632359028, -0.6271314025, 0.3296809494, 1.0473831892, 0.4364182651, -1.3696779013, + -0.2976042032, 0.0399223492, 0.7550673485, 0.53575176, 0.4226417542, -0.069547087, 0.178090632, -1.429018259, + -0.4919155836, -0.6635327339, -0.6278638244, 1.0992287397, -1.2899185419, 0.5348879695, -1.5645805597, -0.6093159318, + 1.9165036678, 1.686234355, 1.2086102962, -0.5938796997, 0.251001358, 1.5818654299, -0.0920653418, 0.4793538153, + 0.4611625969, 0.4175966382, -0.7902413011, 1.3530526161, 2.4345374107, -0.2522033453, -0.4852724969, -0.963286221, + -1.0252519846, -0.76470083, 2.6910192966, -0.3028256297, -0.1939556748, -0.6827206016, 0.4865101576, -1.1748796701, + 0.9050163031, 2.6230053902, 0.1278017312, 0.9562465549, 1.0719659328, 0.7716265917, -1.812743783, -2.0730187893, + 0.2582882345, 0.644130826, 1.4222255945, 0.5335395932, 0.4913542569, -1.1710500717, 1.2177139521, 0.6230660081, + 1.5083622932, 2.537648201, -1.0855648518, -1.1384391785, 0.4204219878, -1.2163747549, 1.5409317017, -1.7850402594, + 0.2881009877, -1.7824188471, -0.6656666398, 0.2255385816, -0.204558447, 0.6886078715, 0.4971415102, 0.4256645739, + -0.2858218849, -0.1442836076, 0.8134331107, -1.1828783751, 1.7522083521, 2.3498823643, 0.1647088081, 1.151599288, + -0.7531849742, 1.1517670155, -2.1913006306, 0.9838366508, 0.798877418, 1.2420282364, -0.3205684125, -0.0106539931, + 0.1312756538, -0.5737478733, 0.6149320602, -1.3822107315, -0.3531156182, -0.5641967654, -1.1561065912, 0.8050509691, + -0.3803443015, -0.710837841, -1.6383564472, -1.306732893, 0.8056710362, -0.9770047665, 1.4766548872, -0.516854167, + 0.3145562112, -1.1484050751, 0.7664395571, 0.0075045303, 0.0210218653, 0.5821520686, -0.0796812326, -1.5467196703, + 0.1330328286, 0.952947855, 0.6269364357, -0.2962416112, 0.4320018291, -0.5550686717, 0.9274399877, 1.1973664761, + 1.2910717726, -1.4917968512, 0.0722649843, 0.5383219123, -0.2111446708, -1.431204319, 0.1909869164, -0.2979548872, + -0.1053253263, 0.4545270801, -0.1573643684, -2.6192853451, 0.329950124, -0.7100323439, -0.5290266275, 0.696303606, + 1.0016850233, 0.371383965, -0.0537927784, 0.5277480483, 0.9580436945, -0.3080750406, 0.5621162057, 1.1065112352, + -0.1435552835, -1.2238268852, -0.6453787088, -0.0446425751, 2.3824806213, -0.36431095, -0.8466729522, 1.184953928, + -1.962526083, -0.2382405549, -0.3108474314, 0.7180377245, -0.2890521586, -1.0908354521, 0.3532983065, -0.9382154346, + 0.5689409971, -0.3626126945, 0.1292094141, -1.3126652241, -0.4163072109, -0.8589738607, -0.0338691622, -1.0064257383, + 0.1432997137, -1.2719420195, 0.4668884873, -0.30530864, -0.0977246687, 0.2234309167, -0.0470772311, 1.0469348431, + -1.3022555113, -0.8693733811, -0.1281105727, 0.8558647037, 0.824288249, 1.8926994801, 2.1205914021, -0.3344083428, + 0.7537657022, -0.1441276968, -0.7482367158, 0.441894412, 0.0492459051, 0.3857703805, 0.6495937109, -0.9396342039, + -2.2726123333, 0.5253503323, -1.3726311922, 0.7066520452, 0.894133985, 1.0972421169, -1.2170317173, 1.4726543427, + 1.2693320513, 0.731210351, -1.4249899387, -0.4283734262, -1.2901015282, 1.9668451548, 0.6691100001, -1.5574185848, + 0.4526828229, -0.8244184256, -0.4453442395, 1.3221229315, -0.2892827392, 0.2289659083, -1.0478963852, 0.4761168361, + -0.2551328838, -0.4333049655, -1.1237722635, 0.8928756714, -1.5040786266, -0.9676579237, 2.4354195595, 0.2679666579, + 0.8277609944, 0.3292419612, -0.1868321896, 0.6399228573, 0.0246101934, -0.536516726, -2.2954347134, 0.9310479164, + -0.1232519746, -0.7564478517, -0.4085958004, 1.0798666477, 0.4010500014, -0.0367867351, 1.1169235706, -0.9824579358, + -0.0519333407, 1.1601675749, -0.5204966664, -1.4007287025, 0.308465749, 1.1606221199, -0.2109643072, 0.4174713492, + 0.7629770041, 0.9784686565, 0.6438628435, 1.3034147024, 0.0565330721, -0.1181432754, 0.2954445481, -0.0077796308, + -2.3304641247, -0.6992905736, -0.1077904403, 1.6501281261, -1.1473655701, -0.4608682096, 0.0156514887, 1.2672146559, + 0.4234745204, 0.18220523, 0.4332121909, 0.4516955316, 0.7653177977, 1.6070424318, 1.0253183842, -0.2590387762, + -1.047917366, -1.6088930368, 0.1823649406, -0.9678751826, -0.7864817977, -0.0212973952, 0.5997629762, -1.3160744905, + -0.9506019354, 0.5000987053, -0.1930724084, -1.2007164955, -0.9722674489, -0.9011637568, 0.9087528586, -1.0918318033, + -0.0354075357, -1.4514678717, 0.9590007663, 0.6602175236, 1.3757650852, -1.0226017237, -0.8164103627, -1.0483584404, + 0.3173210919, -0.4989819825, 1.5050772429, -1.3538606167, -0.3477463424, -1.2884012461, 0.5413200259, -0.0952065215, + -2.545194149, 0.8496850729, -0.8102738857, 0.3639152944, 1.0038706064, 0.8044942617, 0.2769761086, -0.8043497801, + -1.058270216, 0.9640245438, -0.9525019526, 0.2505484223, 1.7418069839, 1.1239496469, -0.2312931418, 0.5900598764, + 0.2988237441, -0.9258888364, -0.7468770742, 0.6754369736, -1.1314466, 2.2557041645, 0.3076329231, 0.1141875535, + -0.7910183668, 0.9181339145, -0.2924492657, 0.1954403967, -0.0891278759, 0.9766722322, 0.8747189045, -1.025924325, + 0.6990704536, 0.5039597154, -0.2485073507, -1.1559615135, -1.5401313305, -0.5223922729, 0.7553474307, 0.5209439993, + 2.2820031643, 0.6241645813, 0.1820227355, -0.8249456286, -1.035492301, 0.0518557951, 0.6551367044, 1.0242308378, + 1.2647337914, -0.3354948759, -0.8350704312, 0.1489525437, 0.858951211, 0.6270372272, -0.5417641401, -0.2549240887, + -1.0517722368, -1.3470808268, 1.7237402201, 0.2793397903, 1.0387977362, 0.3658451438, 1.7909607887, 0.115606904, + -0.6626947522, -0.6802643538, -0.3461824656, -0.1924321353, 1.7015250921, 0.9053295851, 0.1271467358, 1.0843471289, + -0.3697059751, -0.8226702809, 0.3727995455, 1.2557933331, 1.3963470459, 0.8964594007, -1.0065754652, 1.3490592241, + -0.2992320955, 1.170612812, 1.8907653093, -1.7348724604, -0.1472353786, 0.5626885891, 0.1557893902, -1.5522532463, + -0.7784453034, -1.1265046597, -0.5841084719, -0.3729529679, -1.0711065531, -0.4288546741, -1.5960400105, 1.3952161074, + 1.3239439726, -2.5381610394, -1.036023736, 0.3437467515, -2.5755796432, 0.0326888487, -0.2264865786, -0.7182295322, + 1.0793272257, -1.1627691984, 1.3597364426, -0.2644090056, 0.1385675967, -0.397408247, 1.2229468822, 0.954592824, + -1.600528121, 0.4387021065, 0.3070425093, -0.0559233315, 1.7117067575, 1.7901859283, 1.9087609053, 0.2534044385, + -1.0119205713, -1.4722032547, 0.5966674685, -1.1095695496, 1.1928594112, 0.0251557846, 0.4326552749, -1.1571912766, + -0.6874693632, -0.3447971344, 0.3170865774, 0.767133534, -1.7947992086, -1.3456940651, -1.4110554457, 0.1072896123, + 0.1770090908, 1.9528205395, -0.540538609, 0.5682284236, 0.6587491035, 0.9563859701, 1.0822306871, 1.2021546364, + 0.7378921509, -0.5463986397, -1.7351492643, 0.6233202815, -1.3622575998, -0.4995904863, 1.4538668394, -0.5640485883, + -0.452462405, 1.5386605263, -0.4490965605, -1.7440617085, 1.1747021675, -0.8111938238, 0.8217701912, -0.5931746364, + 1.0802215338, -0.253803879, 2.3748760223, 0.156847164, 0.6048847437, 0.1726618111, 1.2744444609, -0.0180251598, + 1.1177147627, -0.4916356206, -0.3290631771, 1.3595130444, 1.1628024578, 0.6827121973, -0.2205483317, -0.2955637276, + 0.636426568, -1.0403375626, 0.8137436509, -0.2903918028, 0.2760030925, 0.4262830317, 2.0322773457, 1.5663291216, + 0.3227753341, -0.0340636298, 0.03195161, -0.3528116345, -0.0407276042, -0.2693226039, 1.417027235, 1.760068059, + 0.7054511309, 1.4845144749, -1.211733222, 0.8845197558, -0.4061044455, -2.0150425434, 0.0858845934, -0.3021506965, + 0.2173276544, 0.1497766674, 1.0825449228, -0.5751865506, 0.4710103273, -0.1027014628, -1.6194263697, -0.7232217193, + -0.936837852, -0.2567723989, 0.2749138474, -0.6792963147, 0.2497180104, -0.1856022477, -0.55897367, 0.4200106561, + 1.637263298, -1.2062540054, 0.7298827171, -2.3512728214, -0.7061026692, 0.6459239721, 0.9156780839, 0.238524437, + 0.7191008329, 0.1381670535, 0.2389231473, 0.8946838975, 0.8140711188, 0.3687241673, -0.8611537218, -1.2541856766, + 0.6498557329, 1.6523033381, -0.742618978, -0.2608479857, 1.2524713278, -0.739448905, 0.1951705813, -0.5104800463, + -0.1717242897, -0.4723890722, 0.0514790267, 1.226601243, 0.6670045853, -0.2716105282, -1.6211389303, -0.7709470987, + -0.4063224494, 1.0450941324, 0.670129478, 0.4660073519, -0.3111612499, 0.4569470286, -0.3755842745, 0.2935816944, + -0.7299827933, -0.3773456812, -0.0588846505, 0.5191531777, 0.6253951788, 0.5395801663, -1.154078722, 1.1528965235, + -0.7550507188, -0.4361100197, -0.8517587185, -0.2650027573, -0.4558273852, -0.1218817607, -0.1632884443, + -1.7337768078, -0.2454500645, -0.4841493666, -0.2076745182, 0.9510493875, -0.1895506978, 1.7178503275, -0.0648765713, + -1.3134737015, 0.0220830422, 1.5550876856, 1.15411973, 0.9463537931, 0.8542752862, -0.3284910917, -1.6964749098, + 0.8325127959, 0.5698849559, 0.1683153063, 0.4132466018, -0.4727652371, 0.9073839188, 0.3624867201, -0.5237817168, + 0.5296620727, -1.5915416479, 0.7892110348, 1.2042807341, -1.2157537937, -0.0659838766, -1.0977131128, 1.8772678375, + 0.0199707374, -1.0153725147, 0.9905872345, 0.2679038346, -0.6155877709, 1.6769979, 2.2211329937, 1.24269557, + -1.1432538033, -1.3055896759, 0.1563118249, 1.5841238499, -2.2452995777, 0.4084261954, 2.3925390244, -1.5944696665, + -0.2753798664, 0.7038434148, -2.1634190083, 1.552395463, 0.0431083739, -0.6386553645, 0.1563305855, 0.4483917058, + -2.9002535343, -0.2124763727, 1.2646445036, 0.9671489596, 0.1235830262, -0.6239078045, 0.1781397164, -1.2477340698, + -0.8786101341, 0.0340745784, 0.960544765, 0.3556161225, -3.0921344757, 0.3453056216, -2.2019863129, 1.5977934599, + 0.0587060228, -1.2354182005, -0.5321778059, -0.8846167326, 1.3429207802, 0.1889484078, -0.7125145197, -0.9847447276, + -0.3402684927, -1.9771710634, 1.4227645397, 1.8663989305, -0.678771317, 0.0083999801, 1.4120321274, -0.8796091676, + -0.853053987, -0.2235978842, 0.7683705688, 0.3531757891, -0.842320323, 0.8098526597, 0.2967545092, 0.1743304431, + 0.6617275476, 1.5916795731, 0.3336613774, -0.3279126287, -1.156124711, 0.8219054937, -0.0077004205, -0.0758062452, + 0.9670962691, -0.9370991588, 0.172772333, -1.0711120367, 1.2559354305, 0.6726061702, -0.1603709906, -1.5501614809, + -0.0739242285, -0.6497949958, 0.3207924664, -1.1628973484, 0.420681566, 0.7446953654, -0.5787026882, -0.3373136222, + 1.4212529659, -1.6684862375, -0.1762335151, 0.3530758023, 0.4051634967, -1.2940163612, 0.960632503, 0.4437426329, + -0.2314557731, -0.0697056428, -0.2034419626, -0.74686414, 0.9059106112, 1.1647446156, -0.9227508307, -0.7264728546, + -0.7138158679, -0.7802699804, 0.7355730534, -0.7290205956, 0.5469813347, -0.7842488885, 0.4940427542, -0.9318450689, + 0.3016936481, -1.1100772619, 0.4054757953, -0.7490972877, 0.5455661416, -2.0676968098, 0.1622077972, 1.2108730078, + -0.5942135453, -2.1084134579, -0.3815261126, 0.6267691255, 1.2911912203, -1.4211307764, -0.0792804286, 1.2469061613, + -1.240075469, -0.6282653809, 0.621465683, -1.9671771526, 0.9299145937, -0.1225127801, -1.6832170486, 0.3292508423, + -0.6738933921, 0.3709022999, 1.657643199, 1.8432923555, 0.1324210614, 0.0297149438, -0.7616475224, -2.1235435009, + 0.1847538352, -0.5866488814, -1.1501641273, -0.1941118091, 0.2461440712, -0.2032909393, 1.0314236879, 0.0010392868, + -0.8659663796, -0.7367367148, -1.2445702553, 0.5127481222, 1.2003036737, -0.9545887113, 0.3125925362, -1.1271697283, + -0.012942953, -0.7439265251, -0.2158260792, 0.9935899973, 0.6832865477, 1.1826785803, -0.6790092587, -0.7337641716, + -0.3919575214, 1.2301563025, 0.142111659, -1.9185277224, -0.1422203928, 0.0144021548, -1.2244794369, 0.8910320997, + 0.8001833558, -0.6226376295, -1.9729691744, -0.3718367219, -0.6450943351, 1.4727654457, 0.4042130411, -0.2300358117, + -0.1837593764, -0.3389971852, 1.0521665812, -0.5878276825, 0.8147978187, 0.2012608349, 0.5305464268, -0.0704385564, + 0.6780981421, -0.5457631946, -1.0154840946, 0.3954752088, -0.8780980706, 0.6862570643, -1.672922492, 0.8030760288, + 0.4177638292, 0.5515066981, -0.8780927062, -0.3644495308, -0.7639865279, -0.2581588328, -0.009734015, 0.1328005195, + -1.3428583145, -0.5613111258, 0.0030085165, -0.2764977217, 0.3225880861, 1.0092039108, 0.2349234968, -1.1569188833, + 0.3209208548, 0.8061857224, 0.9328452349, 1.5121496916, 1.4083685875, -0.7483514547, 1.3963418007, -0.2169407457, + -1.0577676296, 0.2618527114, 0.0820487142, 0.2296931744, 1.1636767387, -0.6497741342, -0.7683633566, 0.333350271, + 0.8443777561, 1.1035634279, 1.1778227091, 0.9579150081, -0.8281220198, 0.4982230663, -1.7778943777, -0.7316639423, + -1.6550662518, 0.1353182048, 0.4598369896, -0.005996576, 0.6672404408, 0.6366089582, 0.3507957757, 0.2280575633, + 0.5433624983, 0.6431276202, 1.0851905346, 0.8459165096, 1.2322151661, 0.993478775, 0.1766625792, 0.1074638367, + -0.8066105247, 1.8972502947, -0.6080517173, -0.4537470043, 0.5049105287, -0.0842246264, 0.8485350013, 0.938378334, + -0.1987407804, 2.5588440895, 0.9118668437, -1.2429528236, 0.4617349505, 1.2518606186, 0.6015286446, -0.4189657271, + -0.3078119159, 0.0632796735, 1.3473374844, 1.3317080736, 0.810131073, 1.3187366724, -0.0723575279, -0.6994635463, + 0.8570897579, -1.5637105703, -0.22977525, -1.2368377447, 0.4984486699, -1.7071242332, -1.1083687544, 0.0562235564, + -0.4866240025, 1.7403073311, 0.0683723688, -1.6624240875, 1.0369526148, 0.4173009694, -0.9422541261, -0.3057643175, + -0.022571126, -2.3352799416, -1.2981127501, 0.1158406734, -1.7067408562, -0.849588871, -0.2003936023, -2.6660759449, + -0.1373704821, 1.875857234, 0.4224371314, -0.9995551705, 0.7457840443, -0.6162922978, -0.6332775354, -0.3346899152, + -1.7673785686, 0.1534919441, 0.5546674132, 1.5832332373, 0.0081346072, 1.0892113447, 0.9690399766, -0.3808458447, + -1.3704863787, -1.2239551544, 1.3384201527, -1.7577083111, -0.4571655095, -0.216789335, 0.2889954448, -1.5132929087, + -0.0505164191, -1.0508286953, 0.9178054333, -0.514290452, 0.6449629664, 1.2783317566, 0.0204112101, -0.9757503271, + 0.8718924522, 1.2775079012, -0.8486067653, -0.7375156879, -0.8481579423, 0.2910692394, -1.4055770636, -2.43704319, + -0.2421151698, -0.1659164876, 0.0634354576, 0.8462583423, -0.3317031562, -0.0410253853, 0.8783381581, -2.0833046436, + 1.9415665865, -0.4809909165, 0.9779080153, -0.1633502096, -1.0577044487, -1.0115772486, -0.9951361418, -0.8234838247, + 1.3299692869, -0.3004491925, -0.3629858494, -1.1682218313, 0.0332856104, 0.058448866, 0.5619188547, -1.4354987144, + -0.6348283291, 0.5653066039, -0.7393788099, 0.4992229044, -0.8277471066, -0.8877035975, -0.401059866, 0.1966238767, + 1.2567228079, 1.7160092592, 0.6613878608, 0.9422925115, 0.6065798402, 0.1258662939, 0.1002879664, 0.3995673954, + 0.5345766544, 1.5022646189, -0.679522872, 1.2247700691, 0.3355742097, -1.9241726398, -0.5274044275, 0.3859989941, + -0.1902812123, 2.0812780857, -0.652164042, -0.9521286488, -0.1160523742, 1.2861061096, -0.9185868502, -0.095684737, + 0.7666553259, 0.0705903322, -0.91732198, -0.6386165023, -0.2875458598, 0.4759561718, -0.2991779745, 1.0411814451, + -0.2388623655, -1.909609437, 0.9282014966, 0.19115071, 1.0705833435, -1.3557881117, 1.5480512381, -0.0446682349, + 1.544254899, -0.6466215253, 0.8872923851, -1.2207497358, 1.0928955078, 1.7613279819, 2.2592256069, 0.0676627234, + -1.4281723499, 0.0194905587, -0.790215373, -0.2634108365, 1.2093659639, 1.713842392, 0.4568839371, -2.7929172516, + 2.0279846191, 1.9827568531, -0.3400610685, -2.5195252895, 0.1077408493, 1.2092367411, 1.3849642277, 0.4741785228, + 0.6720715165, -1.3682155609, 1.3626445532, 3.0927917957, 0.2808203399, -0.0680369139, 0.9278790355, -0.3832291663, + -1.0694628954, -1.3236962557, 0.2294029742, -0.1003467962, 0.5837204456, 1.4401695728, 0.6600863934, -0.1587504148, + -1.0510327816, 2.8563518524, 0.3107630312, 0.0793141946, -0.7014832497, -2.2048156261, -0.1639941931, 0.8510155678, + 0.8897792697, -0.2509429157, 0.7656675577, -1.8384664059, -0.9290833473, 0.8442848921, 0.0714782104, 0.7431453466, + 0.7526600957, -0.3000283539, -0.8917927146, 0.3781193793, -0.8924313188, -0.7258448005, 1.2255562544, 0.4353717268, + -1.0612089634, -1.0652147532, 0.1068682298, 1.5616360903, -0.5242556334, 0.9643884897, 0.7915732861, -0.3687317967, + -1.5341099501, -0.6866817474, -0.0766677111, -0.5075598955, 0.0492559411, -1.5805724859, 0.402810365, 0.5294559002, + -0.2617757022, -1.543627739, -0.4214951396, 0.7148287296, -0.7212103009, 0.4432360232, -1.165520668, -1.7276140451, + 1.6665664911, 0.1276424825, -2.0064013004, 2.2659885883, -1.1007127762, -1.714846015, -0.9983851314, -0.1229355112, + -1.5004343987, -1.0642398596, 0.5147129297, -0.1959828287, 1.0724027157, 0.5129589438, 0.261102736, 1.0203869343, + 1.8625689745, 1.0872251987, 0.177620694, -0.6679985523, -2.3908557892, 1.9265812635, -0.0750824064, -0.687579453, + -1.8375434875, -0.1266568005, 0.4062012732, 0.9031251669, -0.1045055613, -1.1981265545, -0.3047462404, 0.7788920403, + -0.5198747516, -3.0495319366, 0.4344826937, 0.5080818534, -0.0456377529, -0.6228168607, -0.3361916542, -0.4655468166, + -0.8032031059, 0.0986663103, -1.4225085974, -0.7214075327, -0.1927438825, -1.2750662565, 0.3828608692, -0.2010356784, + -0.3411757648, 1.0567926168, 0.8308400512, -0.3758359253, -1.7007135153, -1.0153723955, 0.7814183831, 1.3333725929, + -0.0588039719, -0.1536338776, 1.7262624502, 0.5375443697, -1.4447143078, -1.0294841528, -1.0612380505, -0.1466866732, + 0.024844747, 1.2826215029, -0.6459833384, -1.5521104336, -0.7346411347, 0.4375969768, -0.6678929329, 0.2032340467, + 0.7792050838, -0.1258176714, -0.7511096597, -0.6474458575, 0.2450655252, -0.9021635652, -0.5974918604, -1.1855431795, + -0.8081023097, -0.3418832421, -0.0899530277, 1.9315698147, 0.0990892202, 0.6180377007, -0.9881890416, 0.7278859615, + 0.2622669935, 1.4801809788, -0.4546771049, -1.0858519077, -1.0294415951, -1.2702590227, -0.2850361466, 1.2038623095, + 0.450374186, 0.5454785228, -0.6018747687, 0.4178525209, 1.3235566616, -1.9712238312, -1.0972834826, 1.2963863611, + 0.1940562278, -0.6993190646, 0.196047321, 0.393694371, -0.6680406928, 0.2631404102, -0.0992291048, 1.5811232328, + 0.5356354117, -0.0902978182, -0.2183861434, 0.0835172236, 0.2231216878, 0.4585287869, -1.0632811785, 0.2157344222, + -0.786451757, 0.0688186809, -0.8122203946, 0.9727475047, 0.4813622832, 0.9644367099, -0.0104756039, 0.2411717325, + 0.3121369183, 1.1740385294, -0.8667576909, 0.3110567629, -0.4314704835, 0.1743235737, 0.5403572917, -0.6680797935, + 1.0002886057, 1.6705429554, 1.1789067984, 0.5091510415, 0.2972907722, -0.3430694044, -0.8662321568, 1.316204071, + -1.8510755301, -0.4570961595, 0.9468869567, 0.5335932374, -3.9929611683, -1.1525392532, 0.4048165977, -0.7148792148, + -0.0899725407, 1.1440914869, -0.5628069043, -1.5965940952, 2.3284101486, -0.6404005289, -1.9125361443, -0.883154273, + 0.5702723265, 0.3274931014, -2.0143942833, 0.5962705612, -0.2118565291, 0.2940602303, 1.0698854923, -0.7329437733, + 0.5447551608, -0.7397634983, 0.8467305899, -0.5462845564, 1.9932767153, -0.0706784353, 2.3692502975, -0.4771787226, + -1.3188631535, -2.1861901283, 1.1592558622, -0.2879912555, 1.3112417459, -0.1735279113, 1.7638275623, -0.1482204646, + -0.5775184035, 1.6037025452, -0.2173911482, 0.8606928587, -0.7163739204, 0.5022127032, 0.6795402765, 0.7757351995, + 0.929626286, 2.1179580688, -0.1177830398, -0.6922940612, 1.8955492973, -0.1037179306, 0.8602941632, -1.3067930937, + 0.0278356988, -1.8676902056, 0.8719504476, 0.2133634984, -0.4246577621, 0.2922644913, 0.5142137408, 0.7787869573, + 0.3955132365, -0.0308551546, -0.5254090428, -0.0208215415, 0.5863494277, 0.2410605252, 0.2540073991, -0.0505717807, + 0.3257252574, 0.0478928015, 0.0124214934, 1.1643067598, 1.0866931677, 0.19328399, 0.7468745708, -0.4936366081, + -0.1967490166, -0.589802742, -0.3114001453, 1.2001738548, -1.1749259233, -3.6432943344, -0.7237185836, 2.1023168564, + 0.3772802353, 0.9598003626, 0.6345593333, 0.9760369062, 0.5842297077, -0.4238112867, 1.0510704517, 1.42126441, + 1.2052621841, 1.1709578037, 1.2481642962, 0.1114866585, 0.7139697671, -1.650739789, -1.1089572906, 1.0787169933, + -2.2450892925, 1.2657155991, 1.0965223312, 0.4065240622, 0.4205618203, -0.1879614741, -0.6797156334, 0.9142844677, + 0.0223195404, -1.9562933445, -2.0345225334, -0.3191227913, -0.6532308459, 0.7075082064, 0.8971603513, -0.2222088575, + -0.7548856139, -0.8718494773, 0.5969509482, 0.4012758136, 1.4944665432, -0.0430379659, -2.5413269997, 0.2290947139, + -1.7839071751, 1.7898751497, 0.9773983359, 0.8138353229, 0.3676052094, -0.457249552, 2.3534555435, 1.7259155512, + 1.3094695807, -0.2298201919, -1.5486131907, -0.4831325114, -0.1515334994, 1.1911811829, -0.1305567771, 0.7306992412, + -0.9365200996, -1.080711484, -0.4267658591, -0.6438264847, 0.4536756277, -0.4718679786, 0.0732847527, 0.9452646971, + -1.5916801691, -0.043859493, -1.6057710648, 0.2780228853, 0.1078691557, -0.4012733102, 0.5433638096, -1.8002210855, + 0.06497062, 0.1245789826, 0.8710531592, 0.1115417033, -1.9357055426, -0.5548510551, 1.2520089149, 1.4839948416, + -0.5209493041, -0.9624369144, 0.846632123, -0.5569323301, 0.2157223821, 0.0956537575, -1.029837966, 0.4497537911, + 0.1934795082, -1.4493902922, 0.3130516708, -1.3260329962, -0.2592625022, -1.8027895689, 0.5699852109, 0.567940414, + -2.5769262314, 0.9336313009, 0.7585353851, -0.6365656853, -0.4001408815, 0.9239498973, 1.990606308, 1.4039293528, + -0.5344263315, -1.60054636, -1.1294572353, -0.6989622712, -1.0434752703, -1.8072863817, -0.2911771536, -0.3740274906, + -0.2669128776, -0.6695302725, -1.0134661198, -1.7485753298, -0.288080126, -0.0940565765, 0.1530825347, 1.2911791801, + 1.3317542076, 1.1100609303, 0.9411215782, 0.6393887997, -1.3498729467, -0.1483654976, 0.1755969822, -1.0591218472, + -0.4806758165, 0.0374209993, -0.2632440925, -0.2745012343, 0.696813643, -1.8665977716, -0.1406579614, 0.7593407631, + 0.4745651782, -1.2644783258, 0.6004345417, 1.431604743, -1.1685087681, 0.2429454327, 0.4121043384, -0.2837245464, + 0.0339051634, -0.4033333957, 0.4898167849, -1.8071894646, -0.0860238522, 0.3482603729, 0.8476430774, 1.7993699312, + -0.4857821763, -0.9498022199, -0.0087727476, -0.9771353602, -0.8784105778, 1.8610028028, 0.424118489, 0.4889109433, + -0.5960755348, -0.1157418191, 0.2188333124, -0.9271811843, 1.2049478292, -0.7487514615, -2.4948208332, 2.324877739, + 0.194804132, -0.9396010637, -0.0695591941, 1.1261837482, -1.43901968, 0.1074865907, 0.2451537251, 1.4741477966, + -1.3714965582, 1.4597207308, -0.2240107805, 0.4680463374, -0.7798717618, -0.8509687781, -0.0445612594, 1.0413498878, + 1.0824186802, -1.3900460005, 0.8383417726, -0.5728988051, -0.7608184814, -1.4918603897, -1.1130791903, 0.9705112576, + -0.9052938819, 0.0602722466, 1.7449322939, 1.3911231756, -0.2824020386, -0.0249941666, -1.8760643005, -1.9072006941, + -0.2799922526, -0.4541512132, -0.3491178155, 1.3265537024, 0.3157596588, 0.7349253297, -0.3306770921, -0.0793977678, + -1.4547114372, -0.97508955, 2.5718612671, -0.4372460544, -0.3933745921, -0.2879850864, 1.6932580471, -0.2667824626, + -0.427662611, -1.5534998178, 0.5865116119, -1.1775484085, -0.3417048752, 0.2226299047, 0.867636323, 0.8768593073, + 0.4840772152, 1.3084653616, 1.7750610113, 0.5020828843, 0.8089952469, 0.6637986302, 0.2111792713, 0.3420891464, + -0.5921617746, 0.2682724297, -0.4276701808, -1.0372554064, 0.0703604743, -0.8647756577, 0.5419068933, -1.7433658838, + -0.3307072222, -0.5725274086, 0.6627629995, -0.3101287186, 0.532677412, -0.7019532919, -0.8407902122, 0.7224192023, + -0.1563667655, -0.5524084568, -1.0491452217, -0.7639257908, -0.258130461, -1.538860321, -0.6796113849, 0.8086640239, + -0.1712522805, 0.5022003651, 1.1249178648, 0.2038956285, 0.1236568317, -1.4507499933, -0.4801124036, 0.1786764115, + -0.294072181, 0.9317100644, -0.3659346402, 0.7731112838, -0.8082608581, -1.8103444576, -0.4421080351, -0.9311588407, + -0.6190632582, -1.6836090088, 0.6225354075, 1.8004719019, -0.3675890863, -1.54025352, 0.5061526895, -0.7011044621, + -0.2044154704, 0.7838950157, 0.6873581409, 0.3003750443, 0.2717193067, -0.7483507395, -0.2657977045, -1.1034845114, + 0.9093827009, -1.7455307245, 0.2808555067, -0.6657431126, 0.2908801436, -0.3246472478, 0.1302491426, 1.690901041, + -0.1852371842, -0.3363511562, -1.5134866238, 2.3311779499, -0.0808570161, -1.1184997559, -0.1656611711, -0.2683204412, + 0.5825760961, -1.102560401, -0.9419777393, -0.7417781949, -1.4885994196, 0.1455330104, 0.0818805471, 1.815286994, + -0.3648020625, -1.0479524136, 1.0624965429, -0.190233171, -0.5713142157, 0.615457952, 0.3105306625, 1.3375319242, + -1.4385323524, 0.4703989625, -0.0446280465, 0.2165392637, 0.2389579415, -1.2069883347, -1.5069841146, 2.8056120872, + -0.4463079572, 0.4630065858, 0.3852918446, 1.0595120192, -0.1924976408, -0.7959891558, 0.5518957376, 0.1073498875, + 2.0644276142, -1.3379882574, 2.1439268589, 0.0684103593, 0.1015025824, -0.6148912311, 0.0664112791, 1.3932160139, + 0.13810651, -0.4723600745, 0.6620807052, -1.3079439402, -0.9490098953, 1.513484478, 1.3218621016, -0.4307395518, + -0.0436251275, -1.3971976042, -0.9197613597, -0.1284685731, 0.9387473464, 0.0908714011, -0.6960137486, 0.8947666287, + -0.43952775, 0.0078539103, 0.0331664793, -0.4104016125, 0.2590791285, 2.3322181702, 0.543350935, 0.3989716768, + -2.2112383842, 0.9127438068, 1.0851579905, 0.021088114, 1.107845664, -0.0505299978, -0.5449906588, 1.7212568521, + -0.7205293179, 0.1527352482, -0.5153023005, 0.089932695, -2.0822553635, 0.7137017846, -0.6866122484, -0.3113394976, + 0.3766130805, -0.3086671531, -0.0307912417, 0.9296104908, -0.0212098304, -0.7371267676, -0.3977877498, 1.23624897, + 1.0222923756, -0.5818612576, 1.881734848, 1.1494332552, -0.0183267836, -1.1659201384, 1.5057953596, 2.7619345188, + -0.7941793203, 0.0287719052, -0.7107766271, -0.2424992919, 1.647806406, -0.6357446313, 0.8620203137, 0.1403571814, + 0.3091052175, 0.2087818533, 0.9582784176, 1.2466231585, -0.0951789767, 0.0370424651, 0.0931980982, -0.0357219428, + -0.958160758, 0.6691345572, 1.461836338, -0.940726161, -0.1881764531, 0.1779287457, 0.2282896638, 0.0024585791, + 0.9555747509, -0.0863538906, -1.6428929567, 0.4155323207, -0.4702777863, 1.0200219154, -1.0292131901, 1.9110612869, + -0.3506657481, 0.3369286656, 0.1099356636, -0.8530461192, -0.5134611726, 1.2525533438, 1.9823640585, 0.8887806535, + 0.1952644587, -0.3287902176, 0.6369973421, 1.1657168865, -0.3110114336, 1.9505547285, 0.5987884402, -0.3918232918, + 0.1895684898, -0.854115665, -0.1494368315, -0.9396588206, 0.5325658917, 1.4862364531, 0.538683176, 1.0839402676, + 2.7512357235, 1.0610109568, -0.3076118827, 0.0839342251, -0.2132758647, -0.4443840086, 1.113961339, -0.537116766, + 0.6878733635, 0.6211798191, 0.1295899898, -0.1400801837, 0.326264441, -1.6013503075, 0.3448503315, -2.4370861053, + 0.0091410428, 0.4318372011, 2.4131960869, 0.7610641718, -1.2417212725, -0.5548300147, 0.2673580945, 0.4718003273, + 1.0521353483, 1.028704524, -1.2894179821, -0.0358988978, 1.2699348927, -0.1881172657, 0.5786081553, 0.3217543662, + 0.5109526515, 0.6527564526, -0.1036807373, -0.8156668544, 0.048689086, -0.8705747724, 0.0336206816, -0.1434892714, + 0.0206560418, -0.5102793574, 0.0312600732, -0.0512645692, 0.3963692784, -0.9462928772, 1.7282290459, 0.0291529056, + 1.6862194538, 1.0479409695, -0.1493015438, -0.4607142508, 0.7110564113, -0.7917346954, -0.3492127657, -0.1107221022, + 1.2990982533, 0.0823019817, 1.3518792391, 1.6583864689, -0.5439693332, -2.4000995159, 0.4834471345, 0.242904529, + -0.3895867467, 1.5748558044, -1.8866602182, 0.5014733672, -1.0549618006, 0.6886458993, -0.559132874, 1.7372102737, + -1.0586389303, -0.703078866, -1.7595483065, 0.576851964, 1.0110862255, -1.080735445, 0.7039963007, 0.2570515871, + 0.2202721834, 0.363648802, -0.0619608201, -0.4254122078, 0.1702727824, 0.2321278155, -0.2789296806, 0.3148307204, + -0.2219217718, -0.0343165696, -0.6693635583, -0.7482005358, 0.3152418435, -0.6094266772, 0.5564612746, 1.0861303806, + -0.3645062149, 1.1158699989, 0.7505072951, 1.6706467867, 0.9701129198, 0.9791996479, -0.4747344851, 0.8000352383, + -0.8672477603, 0.0212012902, 0.136595726, -1.9201898575, -0.6686220169, -0.2664861679, -0.7977192998, -0.1907032579, + 1.1660275459, -0.804274261, 0.9925575256, -1.22760427, -0.7777420878, 0.4423106909, -1.0314748287, -1.1646858454, + -0.1148602143, -0.0822476819, 1.2950305939, -0.1583028287, -0.3801110685, 2.1181035042, 1.1377567053, 1.1714947224, + -1.471057415, 0.4374298453, -0.3345782161, -0.2080748528, -0.4310014546, -0.335994184, -0.6037350297, -0.4509580731, + -0.2071041912, 0.4953692853, -0.920940876, -1.6250727177, 1.3350207806, 0.5784474015, -0.7418002486, -1.0781373978, + -1.4611221552, 0.8532691598, -0.2607238293, 0.5639829636, -0.5600467324, -1.1986761093, 1.9563639164, 0.969050467, + 0.2546267211, -0.383728981, -1.2347412109, -0.1670784652, 2.9372646809, 0.867846489, 1.1291265488, 1.5747507811, + -1.6810820103, -0.2933495343, -0.6225114465, -0.3882344663, -1.3630297184, 0.009293641, -0.5639885068, 0.2759515047, + -0.2828184068, 1.1528820992, 1.1894996166, 1.178229332, 1.7409573793, -0.3719946146, 2.2909574509, 3.0704162121, + -0.9461196661, -0.2518333197, -0.6309245825, 0.570620954, -0.4163119495, -0.0939932466, -1.1150132418, -0.4613604546, + 0.0398271419, -0.2534232736, -1.9071460962, -1.8280466795, -0.4866101444, -1.3184527159, -1.4179421663, 0.2209537029, + -1.1249928474, -1.9038407803, -2.7663104534, 0.6664661169, 1.0175549984, 0.1773152649, 0.2420164049, 1.5144679546, + 0.026080573, 0.3917195499, 0.2187479883, -1.195281148, 0.0412240624, 0.1335472763, -0.3340080678, 0.076282084, + 1.1268568039, -3.0501861572, -0.8245661259, 1.7237170935, -2.8219740391, -1.8330252171, 0.7809044719, -0.3621836007, + 1.7247868776, -0.1848417073, 0.3827749491, 0.8851286173, 0.1156658381, 2.0285098553, 0.8909919262, -0.7913900018, + -0.4023923874, 1.4397592545, -0.2121118456, 1.3215402365, -0.1021919549, -0.267960012, -0.6018244028, 0.0751775131, + -0.2411542386, -0.8728830814, -0.745249331, -0.9146154523, -0.3126709759, -0.0148961348, 0.3722932041, 1.4483546019, + 0.3125064075, -0.4321153164, -0.3628958166, 1.5365076065, -0.4864256084, -0.4952484965, -0.4730603993, -1.5365190506, + -0.7496447563, 1.2180451155, -1.2079240084, 0.6674391627, 1.086468339, -0.2232403457, -0.1725623906, -1.0300061703, + 0.8511503935, 1.1540714502, 0.2684497833, 2.0633459091, 1.585089922, 0.993640244, -1.7767057419, 0.2575030923, + -0.2837025225, 0.9801308513, 0.0955806598, -1.3171532154, 0.0740581304, 0.719984889, -0.3346158564, 0.2480404526, + 2.281662941, -0.7901241183, -1.2123996019, -0.7006688118, -3.1003596783, -0.407168448, -0.2404175103, 0.3279474974, + -0.1991623193, 0.8064158559, 1.3032054901, -2.3590478897, -0.0860624835, -0.0414754823, -0.768240869, -0.6589986682, + -0.3123554587, 1.5079144239, 0.2001926452, -1.242387414, -0.8025832772, -0.2944001555, 0.7860500813, -0.5993912816, + 0.0452994257, -0.1173223034, -0.3171161115, -0.6040194631, 0.4698894918, -0.282141149, -1.8677010536, -1.048879981, + 1.0262153149, -0.9576758146, 1.3599735498, -1.7847856283, 1.2750602961, 1.3729448318, -0.0263605714, -0.9299097061, + -0.1553459466, -0.5619153976, -0.2708025575, -0.5707209706, -0.3943482339, 0.3243137002, -1.2652244568, 1.3428239822, + -0.4716863632, -0.1471398324, 0.5845143795, 0.7798466682, -0.2970978022, -0.2879599035, 1.1741337776, -0.3029748797, + -1.0286338329, -2.5272741318, 1.8863145113, 0.5938357711, -1.5568106174, 0.1661666781, 1.0948197842, -0.4422018528, + 0.4641939998, -0.8608870506, -1.7977205515, -0.6338832378, -1.5577857494, 1.3675371408, -1.8018686771, -0.4680710137, + -1.3529676199, -0.3295443952, -0.0289831124, 0.8985692263, 0.5144635439, -1.5340685844, 0.7415658832, -0.4952560365, + -1.2680888176, 1.5494275093, 0.9896262884, 1.133720994, 0.1172252595, 0.5003512502, 0.3104941547, 0.8642488122, + -1.9873039722, 0.2901904881, -0.8896881938, -0.3933593929, -0.3691793084, -2.2398619652, 0.4009266198, 1.4610875845, + -0.2109690011, 0.3212065697, 1.1923828125, -0.944737792, -0.7677613497, -0.019994868, 0.7007796764, -0.9966187477, + 0.1880163848, -1.5960267782, 1.1941541433, 1.3885799646, 0.3051355183, -0.4914822578, -0.0551109239, 0.8271973729, + -0.0875257626, 0.5913065076, -0.332760632, -0.663320601, 1.1625896692, 0.5635477304, 1.5795736313, 0.7323051691, + 0.5140512586, 0.7973369956, -1.0491675138, -0.8615369797, -0.0855538324, -1.1763240099, 0.6985024214, 0.7214810848, + 0.3039073646, 0.7869974971, 0.7645076513, 1.6823736429, -0.3224197328, -0.6913388968, -1.0375618935, 2.2595710754, + 0.3254954815, -3.2841098309, -0.9829556942, 0.6173440814, -1.9146822691, 1.6384691, 0.3188497424, -0.9541326165, + -1.3458615541, 1.1278688908, 0.3943688273, -0.2816155255, -0.6670376658, 1.7449932098, 1.6885739565, 1.6031520367, + 0.1641594321, 1.335580349, -0.579447031, -1.450496316, 0.0844430998, 0.2493409365, 0.1463551372, -2.4972960949, + -0.4465410709, -1.2534028292, 0.995742619, -0.7179170251, -0.9940697551, -1.5139750242, -0.3549970388, -0.0613587759, + 1.637130022, -0.3277179301, -0.704913795, -0.0345475487, 0.8238404989, -0.077993542, 0.1792568564, -1.1482546329, + -0.6932830811, 0.6941252351, 0.0120476391, 1.0842584372, -1.115729332, -0.2156767249, 0.1917534322, 0.2484143525, + 1.1325517893, -0.8084028959, 1.906142354, 0.2140457481, 2.5162801743, 0.1694203168, 0.2875690758, -0.4746890962, + 0.2268090844, 0.610771656, 0.8992943764, 1.2538052797, 1.082577467, -2.5980246067, 0.861513555, -1.2262650728, + -1.2255992889, -1.7337546349, -0.0070146662, 0.8009208441, 1.0482748747, 0.1379574686, 1.4142774343, -2.7599356174, + -2.6668968201, 0.5720087886, 1.0927113295, 0.5224719644, -1.5818355083, 1.626734376, 0.8453273177, -1.3154888153, + 0.7564472556, 0.8823671341, 1.748845458, -2.1088161469, -0.3071520329, -0.9865061641, -3.3408041, 0.8878111839, + -0.5089591742, -1.7002439499, -1.68699193, -0.7074144483, -1.5640826225, 0.0950985998, -1.5500789881, 0.6208086014, + -0.366184622, -0.8483721018, 0.19371517, -1.3323022127, -0.3852874339, -0.2245144695, 0.5444493294, 2.3293950558, + 0.1018384323, 0.0900604799, -2.0430760384, 0.1845244169, 1.0585149527, -0.4266940057, -0.2745861709, -0.989546895, + -1.4220205545, 0.1086603552, 0.7137717605, -0.7071261406, -0.6727264524, -1.1171315908, 1.1003943682, 1.4516644478, + 0.2674415112, 0.7746139765, -0.4443411827, -1.4839503765, -0.4744228423, 0.621214807, 0.1285764873, 0.4126030803, + -0.8194864988, 0.2797495127, 0.7431498766, -0.6712838411, -0.59153229, 0.0478469022, -1.9627013206, -0.1429765671, + -1.1604765654, 0.724887073, 0.5285183191, 0.3912655115, 0.8200900555, -0.0187557004, 0.3092218041, 0.8215553164, + -1.2147023678, 0.8691491485, 0.1782266051, -0.3846947849, 0.2185835987, 1.0123075247, 0.5845950842, 0.8014039397, + -1.2928036451, 0.2337188721, -1.0127472878, -0.1021579877, 0.4277488589, -0.421774298, 0.8380681872, 0.9014368653, + -0.5033906698, 0.340048641, 0.0378595553, 1.412833333, 0.8601081967, 1.4224760532, -0.5014793873, -0.1299059242, + -1.0861430168, -2.1957287788, -0.4724318981, -1.2804791927, 0.8848083019, -1.023203969, -1.9286930561, 1.9506202936, + -1.2104187012, -0.8170687556, 1.6399490833, -0.2306459248, -1.486332655, -0.9082179666, -0.2592566311, -0.6489036679, + -1.1253803968, 0.2403939068, 0.0076182713, -0.6155346036, -0.6273389459, 1.2138336897, 0.125926733, -0.4360826612, + -0.2855346501, -0.932127893, 0.2889509797, 0.0191639476, 0.31979087, 0.1481243372, -0.3380688131, -1.4064606428, + -0.1481387913, 2.0216214657, 0.1358122379, 0.3295311034, -1.379956007, 1.0495952368, -0.6023465395, 0.7122180462, + -0.2905054092, 0.0740248412, 1.8817989826, 0.0416676588, 0.6724176407, -1.2744238377, 0.3802832663, -0.346743077, + -1.1206740141, 1.2709239721, -0.0360667482, -0.4205509424, 0.8479788303, -0.2158568501, -1.0330330133, 0.4496297836, + 0.2781554163, -1.9734966755, -0.7712466717, -0.1627359092, 0.2592321932, -0.5584867597, 0.3639693856, -1.8700847626, + 0.053216137, -1.0296891928, -0.752132535, -0.2848433852, -0.1023412347, 0.3919997215, -1.0115511417, -1.203774929, + -0.5682365894, 1.3685394526, -0.0325128809, 0.1605796665, -1.9592183828, -0.7536043525, 0.5448845029, -0.4187681377, + 1.5351369381, 0.7247617841, -0.1284294128, -0.7700523734, -1.3904502392, 0.2299453765, -0.0612412915, -0.4955629408, + 0.4037678242, -2.3232903481, -0.5163176656, -1.1535639763, 0.1474791318, -0.3062639832, -0.3380345702, 0.4434403479, + 0.164909035, -0.0253193621, -0.2594115436, 0.3455506265, -1.1220024824, 1.1439352036, 1.9330021143, -0.2664181888, + 0.6555473804, 0.4029106796, 0.6844402552, 0.5201416612, -1.7882884741, -0.0639681965, 0.9145079851, 1.1875967979, + -0.2303394228, 1.4555683136, 0.0759437382, 0.3192932904, 0.1900645643, 0.1694294959, 0.2299467325, 1.125285387, + 1.334831953, -1.412750721, 0.8178436756, 0.310434401, 0.0983516201, 0.3478089571, -0.8033730388, 0.4526213109, + -0.207996726, -0.3332097232, -0.7742238641, 1.0865453482, 0.3817871213, -0.8886569738, 0.9300866723, 0.2929508984, + -0.1157365143, 0.7728258967, -0.697542727, -0.9684841633, 1.3194321394, -1.7829133272, -0.3412713706, -1.2375971079, + -1.0775034428, -0.5838529468, -0.792557776, -0.5509713888, 1.3133839369, 0.3206467927, 1.3325715065, 0.4925050139, + 1.9970691204, 0.4951836169, 0.1311973631, 1.4893194437, 0.5594164133, 0.4966352582, 1.2948005199, -0.8946422338, + 0.3424288332, -0.4328266084, -0.8383091688, 0.348482579, -0.5664611459, -1.5805536509, -1.2075260878, 1.0009816885, + -1.1555238962, -1.1081479788, 0.2666878104, -0.0843278915, -1.4013813734, -0.0587022007, -0.5409751534, -0.9161397815, + -0.0049323305, -0.5609408617, -0.9947663546, 1.7990250587, 2.1042752266, 0.3246460259, 0.8142860532, -0.4318092465, + 0.0749454051, 0.5255390406, 0.8453169465, 0.5342290401, 1.3789731264, -0.1871801764, 0.1282057762, -0.8915588856, + -0.0542284548, -0.1044168994, -1.5793139935, -1.0756293535, -0.9769575596, -0.3783388138, -0.1792947501, 0.1676430255, + 0.971835494, -0.332742393, -0.9197884202, -0.6990206838, -0.7812698483, -0.7872581482, 1.036288619, 1.0649689436, + 0.3260521293, 2.1018323898, 0.0040883296, -2.0931577682, 0.6810662746, -0.8956177235, -0.6246948242, 2.6490068436, + 1.4860161543, -1.130030036, -0.0098225111, -0.3665522337, -0.1155728847, -0.221635744, 0.0329407454, -0.345216006, + -1.6651244164, 1.1996959448, -1.0849312544, 0.0575289764, -0.6823420525, 0.4595836699, 0.4365171492, -1.0625749826, + 0.6479692459, 0.1152886003, 0.6351547837, 0.8655322194, -0.1900938898, 0.6194599867, 1.3249210119, -2.9902887344, + -0.9829337001, 2.3041112423, 0.8291086555, -0.6690052748, -0.2973387539, 0.2854040861, 0.2512688935, -1.0038155317, + 0.0745838508, 0.6835303307, -0.3019574583, 0.065683715, 0.2763928175, 1.0574886799, 0.2528705597, -2.0649085045, + -0.252558291, 0.5633801222, 0.7122578025, 0.6231449246, 1.2130430937, -0.341789335, -0.6274027824, -1.082681179, + 1.3845734596, -1.6314278841, 0.932539165, -0.2828492224, -1.1294640303, 0.3213407695, -0.1412851214, -0.5739104152, + -1.8523945808, 0.1375545859, 0.8524460196, 0.9795963764, -0.4191142619, -0.1105024815, -0.8044444323, 1.7718458176, + -2.1773252487, -1.9565769434, -0.0790803954, 1.5214020014, -0.9446907043, 0.2151204497, -0.793173492, 0.1091351062, + 0.0690722018, -0.2768059075, -0.1884625107, -0.0551569052, -0.8582618237, 0.744418323, -0.3289690912, -0.4206421971, + 0.6482777596, -1.8037947416, -0.621583879, 0.2966335118, -0.5860925913, 0.2072690427, 0.3849021196, -0.0163337681, + 0.7419171929, -0.728232801, 0.3230105639, -1.0278416872, 0.2014814466, -0.1945166439, -0.0878563076, 0.580742836, + 0.4235515296, 0.5991556644, -1.6961510181, -1.7235015631, -0.1653775871, -0.0229291823, 0.3718184233, -0.5282102823, + -2.0017440319, -0.5723828673, -1.0784522295, -0.1570475549, -0.4171837568, 1.109361887, 0.8538563251, -0.657856226, + 0.2458041012, 1.4572660923, -0.4246588945, 0.5097835064, 0.6360350847, -0.2560229897, 0.0219479911, -3.1653001308, + 0.7525913119, 0.1623850465, -1.1981235743, -1.54190588, -1.282132864, -2.3250749111, -0.0390541479, 1.9492053986, + -1.6592499018, -0.2550086081, -0.8584333658, -0.6264243722, 0.090518482, 2.3940489292, 0.8812188506, -2.6074683666, + 0.546762228, -0.2826860547, -1.7907680273, -1.6223297119, 0.0945725664, -0.6790642738, -0.0352940187, -0.6122911572, + -0.7683660984, -0.5392516851, -0.3982014656, 0.867901504, -2.1680600643, -0.514071703, 0.8265195489, 1.5463507175, + -0.5618708134, -0.9446499944, -0.9218199849, -0.5487257838, 0.5468548536, -0.1935274601, 0.2828486264, -0.7948492169, + -0.0389313214, -0.7580267787, 1.2519108057, 2.5005273819, -0.462616235, 0.7376989126, 0.7565030456, 2.0083138943, + 0.8451092243, 0.8647089005, 0.0845709145, 0.6045849919, -0.2940496504, -0.7108674049, -1.6182552576, -1.153660059, + -0.523293376, 0.8932416439, 0.076690495, 0.2250192761, -3.3111915588, -1.2070434093, -0.5528053045, 0.2814783454, + -0.0727163851, 0.4501400888, -0.530497551, 0.0220623203, 0.540907681, 0.552018404, 1.1103562117, -0.7519988418, + -2.4101579189, 0.8522349, 0.3122522533, -1.38131845, -0.9066482186, 0.0503111966, -0.5682703853, 0.8344324231, + 0.0455108099, -0.5007439256, -0.0220513381, 0.6138712168, -1.5130780935, -0.8231852651, -1.286257267, 0.0757517591, + -0.3834818006, 0.9912862182, -0.2152566612, -1.8530063629, -0.8569292426, 0.8364073038, 0.1884991527, -0.8838205338, + -1.4345126152, 0.4621810317, 1.8554944992, 1.7764538527, 0.2408635467, -0.3988132477, -1.3176436424, 0.3313519657, + -1.540440917, 0.8066987395, 0.614131093, 1.0647925138, -0.5903156996, 0.4407163262, 1.0937725306, -0.6846204996, + -0.8255679607, 0.0301491339, 1.172608614, 0.5547693968, -1.903614521, -2.150711298, 0.9439404011, 0.8304248452, + 0.8022865057, -0.039531406, -1.7726892233, -0.7131135464, -1.3535375595, -0.2295022607, 0.6360743046, 0.3305475414, + 0.1700846702, -0.4246495068, -1.0522756577, -1.6014963388, 0.8445893526, 0.4519396126, -0.7346076369, -0.9541358948, + 0.0660870895, -0.2796024382, 1.5112785101, -0.2288440019, 0.7933291793, 0.9457479715, 0.0437120758, 1.0272008181, + 2.6187674999, 0.2938658595, 0.0002436232, -1.8856309652, -0.2801553011, -0.8098967075, 0.2391258031, -1.5088934898, + 0.1154030189, 0.1677009463, -1.0893034935, 0.1279728115, -1.1742339134, 0.0815478116, -0.4688488841, 1.9693156481, + 1.1393784285, 0.7566793561, 0.033294864, -1.1088514328, 0.6060234308, 0.3168972135, 0.9489172697, 0.8915824294, + -0.074490957, -2.9674692154, 0.2204231173, 1.3969603777, 2.8875684738, 1.1382696629, 0.0757457167, -0.3666677177, + 0.0659102425, 0.0668415278, -0.5749508739, -0.234017089, -0.5543112755, 0.2262243181, 0.3229537606, -0.370300144, + 1.2843537331, -1.3588908911, -0.4063398838, 0.3984783888, 0.4746867716, -0.5155292749, 2.0688710213, -0.7366701961, + -1.2884358168, 0.0306869484, -0.6278145313, 1.6479524374, 1.2733566761, -1.5114120245, 0.5874340534, 1.416418314, + 2.1109287739, 0.6936261654, -0.7801271081, -0.1424248666, 1.4228651524, 0.766045928, 0.0757838488, -0.3184366226, + 1.646447897, -1.3185890913, -0.6462491751, 0.5449139476, -1.392731905, 1.1904312372, 0.5407568216, -0.0330950134, + -0.3919748962, 0.7456977367, -0.6043021679, 1.7865223885, -0.308624357, 1.0165492296, 0.2271374613, -0.7343394756, + -0.6063373089, -1.8273447752, -0.8988688588, 0.3666749895, 0.2657340765, -0.2736480534, -0.7589226961, 0.2684849799, + -1.1223801374, -1.1474984884, -1.2845572233, -0.315279752, 0.3679023683, -0.2113581449, 0.5975563526, -1.9758757353, + 0.2240671962, -0.5090435147, -1.2870079279, -0.0849780515, -1.1679377556, 0.4966672361, -0.6675986052, -0.4594515264, + -2.647449255, -0.3685693741, -1.2190847397, 1.2057003975, -1.1603654623, 1.1231783628, -0.5407581925, -0.5821552873, + -1.8120853901, 2.3940880299, 1.2630169392, -1.4847002029, 0.0002179273, -0.2718341053, -0.6148485541, 0.6212561131, + -0.8127297163, -0.2228314281, 0.6530621052, -0.2918465734, 0.8982840776, -0.3148573935, 0.0192828048, 0.1528849155, + -1.0955338478, 0.1683052927, 0.7518684864, 0.026315365, -0.5481123328, -1.0166777372, -0.0326641724, 0.6306336522, + -1.0569366217, -1.3100726604, 0.8450725079, 1.1383305788, 0.2161744982, 1.4873583317, 0.1062991545, 0.0131904045, + -1.0483144522, 0.8597632051, -1.7767972946, 1.5863535404, 2.7823541164, 1.6619212627, 0.3272190094, 0.6373428702, + -0.3165480196, 1.0289241076, 0.0949189141, -1.5440686941, 0.3050356805, 0.1199226975, -1.2530963421, 1.2903825045, + -0.0241483971, -1.6955019236, 0.4644385278, 0.2589190602, -1.3097108603, -0.5500065088, -1.0812994242, 0.6089993715, + 1.7156662941, 0.4168740809, -0.6155125499, -0.1195571795, 0.1958514154, 2.2196655273, 0.7892631292, 0.7401278615, + -0.2391066402, 0.9518038034, 0.5104688406, 0.7215762734, 1.3206062317, 0.264588058, 1.1824287176, 0.9417513013, + 0.7604390979, 0.1519564837, -1.5020102262, -0.4238476455, 1.3813818693, -0.324000597, -0.9087860584, -0.4296375513, + -1.5056200027, 1.0380312204, 0.9179576635, -0.2080131173, 0.4261639714, -1.2480202913, -0.1067449674, -0.1843754649, + 0.2243936658, 1.2510346174, -0.4090640247, -0.341027379, -0.8742214441, 0.022170756, 0.0311127305, 1.9829660654, + 0.409666121, 0.5662220716, -0.6245689988, -1.7555264235, -0.0548473075, 1.2680255175, -1.4447710514, -0.7565324306, + 0.5842719078, -1.8277680874, 0.1456336826, -1.0918613672, -0.9649658799, 1.3064036369, 1.1600183249, 1.1379429102, + 2.1565191746, -0.8689957857, 1.563621521, 0.436843127, -0.6594150066, 0.2378106266, -0.0386009179, -0.2020491958, + -0.717102766, 0.7523133159, -3.0087399483, -1.2096756697, -1.4830690622, 1.1132252216, -0.0736747012, 0.2278408259, + 0.8607809544, 0.0230039097, -0.0100709805, 0.566313684, -0.4573984742, -0.3147220016, -0.591661036, 0.363375932, + -1.7309250832, 0.7415539622, 0.9788953662, 0.4454882145, 0.9996737242, -0.7172723413, 0.4500461519, 0.2097088099, + -0.1300976425, 0.368341893, 1.6021925211, 1.3492051363, 0.5966399908, -0.2869676948, -2.2014067173, -0.6466356516, + -0.414157927, 0.0322575942, 0.2764803469, 0.0523899347, 0.9976919293, -0.4418748617, 1.1962385178, 0.8795982003, + 1.3394536972, -0.5127735734, -0.5311194062, 0.8626922965, -0.7423558831, 0.93095541, -1.4290853739, 0.0858087614, + -2.6495206356, 1.6978728771, -0.4349122941, -0.3831622601, -0.068485707, 0.7442887425, 0.5322425961, 2.0612838268, + 0.1241032407, -2.3649044037, 0.3680788875, 0.1251933873, 1.7623183727, 0.3210356832, -0.2840740085, 0.7346179485, + 0.156839475, -2.1416144371, 0.0518188179, 1.253395319, 0.8536785245, -0.2809889913, -0.4789661765, -0.734675169, + 0.5946739316, -0.799687326, -1.3966721296, -1.7271291018, -0.7277098298, -0.0455504879, 1.6599112749, -0.2437718362, + -1.4668591022, 0.0005579666, -0.6929865479, 0.9924173951, 0.1146905273, -0.0723900497, -0.3171693087, 0.4661208093, + -1.2721763849, -0.99682796, 1.4310706854, -0.164444685, 0.2184965909, -2.400105238, 0.533585012, 0.8570533395, + -1.2253437042, 2.6228101254, -0.8978168368, -0.473738879, 1.2820608616, -0.25721246, -2.3622217178, 1.6324220896, + 0.2936998904, 0.413648963, 0.4954855144, -0.6417990327, 3.0474805832, -1.4472365379, -3.382437706, -0.5294840932, + 2.2834894657, -0.2915201187, -0.583485961, 0.67361027, -1.0685982704, -1.0622173548, -3.0860776901, -0.152957052, + -0.9341332316, 0.6026499867, -1.6047893763, 0.5600776672, 0.2471535951, 0.3888663054, -0.5745077729, 1.1368119717, + -0.1875921935, -0.2457357347, 1.0788971186, 1.3245619535, 0.4084223807, -0.9082864523, 1.3701889515, 0.5639448762, + 0.6552087665, 0.2393982857, 0.5696803331, -1.8782240152, 0.1603340507, -1.0327521563, -0.1901682466, 0.5955625176, + 0.8033736348, -0.3817498088, 0.4623665214, 0.5622440577, -1.9576177597, -0.2124888599, 0.0532335043, 1.787212491, + 1.0935274363, -0.6834817529, -0.0209047794, -0.2557629645, -0.0322177224, -0.4546183646, -0.6292889714, -1.8742160797, + -0.847656548, -0.0208909176, 0.933409214, 1.3976117373, 0.7560239434, -0.6076855063, -0.4940192103, -0.2218679041, + -0.0247830916, 0.4010295868, -0.2099526823, 1.6346033812, 1.0749132633, -0.7803043723, -0.6348884106, -0.6152335405, + 0.9498234391, 0.2001388222, -0.5263258219, -0.8058626056, 1.0469522476, 0.3226033449, 0.1166816801, 0.9418267012, + -1.3817039728, -0.2754204571, 0.6587382555, -1.1658596992, -0.5008330345, 0.6715875268, 1.0270637274, 0.6949701309, + 1.0310188532, 0.3335841298, -1.101541996, -1.6726310253, 0.0740614757, 0.3277696967, -0.3727508783, 0.1862053722, + 0.2605803013, 1.8626759052, 0.0707811713, -2.1108138561, -0.6218534112, 0.4231096804, 0.2173334807, -0.7314818501, + -0.7883370519, -0.1343939155, 0.4867017269, -1.6478499174, 0.8052513599, 1.0267293453, 0.0742363185, 0.027361827, + 1.4169248343, 1.9043926001, -0.3838944435, 0.52453655, 0.2650912702, -0.3235317171, -0.8705883622, -1.5474305153, + 0.6036111116, 0.0714829117, -1.141379714, 0.1435114741, -0.6295248866, -0.0765427724, -0.1058588624, -1.4466910362, + -0.6485618353, 0.0132218618, 1.4305149317, 0.3642526269, 1.351788044, 1.3447993994, 0.7358057499, 0.74147439, + -1.2427915335, -0.3946131766, 0.1648515463, 1.1895046234, -0.2594691217, 0.8554831743, -1.0946022272, 1.1648385525, + -0.2886697054, -0.7935397625, 0.0376145579, 1.3619145155, -1.395318985, -0.1312556565, -0.4305959046, -0.7347027659, + 1.2504189014, -1.1138132811, 1.8914943933, 0.6668202877, 0.5314742923, -1.1446431875, 0.8470588326, -0.355999887, + 1.832810998, -1.0825778246, 1.5532661676, 1.4346286058, 1.6508401632, 0.1166369244, -1.7578734159, -0.2210106105, + -0.3382823765, -0.7606144547, 0.7037070394, -1.4212046862, 0.7512388825, 0.1273766011, -0.0193244293, 1.832701683, + 0.1493382752, -0.0756782517, -0.0355336964, -1.6446069479, -0.8279816508, -0.0862731785, -0.6101303697, 0.6401699185, + -0.1602170914, -0.9755163193, 0.3217153549, 0.1617767066, 1.2197539806, 0.1922034472, -0.4725489616, -1.2373657227, + -1.7496455908, 0.5991289616, -0.549891293, 0.0673314482, 0.8375106454, 0.8581475019, 0.931065619, -1.3271347284, + -0.1280384958, 1.7297261953, -0.2735048532, 1.1787731647, 2.291785717, 0.8384599686, 0.9903156161, -0.2916140258, + 0.3382817805, 1.0331203938, 0.3903645873, -0.6004440784, -0.5967748165, 0.944653213, 1.4222265482, 0.0261503533, + -1.4113605022, -1.8482435942, -1.0479794741, 0.68418926, -2.3524160385, -1.1195981503, -1.0631546974, 0.3228687644, + 1.1693851948, 2.5934445858, -0.4578936994, 0.1776099205, 0.0838143975, 0.8039101362, 0.5364631414, 0.1926894188, + 0.4836985767, 1.1132575274, 0.1154624745, 0.1372138709, -0.2826304138, -1.1644810438, -0.0809413269, -0.4451850951, + -1.1100091934, -0.5838759542, 0.3142054081, -0.6515339017, -1.3535983562, 0.3675374985, -2.6818180084, -0.4444566667, + -1.164026618, 0.014034952, -0.3826368749, -0.7109439969, 0.6577385664, 0.0257320683, -0.4784716666, -0.6491413116, + -1.1920108795, 0.7272107005, -0.4145368934, 1.3471291065, 0.302836746, 1.9280700684, 0.8856548667, -2.2657513618, + -0.1738021672, 1.1121703386, 0.8565863967, 0.0598084405, -1.1367391348, -0.3166633844, -0.4727935791, 0.1086008698, + 0.0661494732, -0.5598045588, -0.2818463743, 0.7618486881, 1.0420223475, -0.0124819009, -0.2460182905, -0.2402713597, + 0.280338496, 0.6347672939, -0.7395008802, 0.3717006445, 1.8899036646, 0.7324008942, -0.2531517148, 2.1485793591, + 1.1714525223, 0.7662360072, -0.7396721244, -1.2587963343, 1.2214463949, -1.1060516834, 0.2466125786, -0.0663431361, + 0.575492084, 0.0819447786, 1.2410321236, -0.0663276836, -0.8556157351, 0.1471997797, -0.1371292323, 1.4430338144, + 0.1633171737, -1.1141107082, -1.4421511889, 0.258490175, 0.1109801009, 0.5133917928, -1.6274529696, -0.3198641539, + 1.509196043, -0.5411385894, 0.4407715201, 1.6539150476, -0.1996767372, 2.6565704346, 0.0422839411, -1.186128974, + 0.6739498377, -0.0582477152, 0.0878551304, -0.0720350966, -0.980956614, -1.048509717, 0.1298928559, 1.50119102, + 0.3872312605, 1.3922791481, -0.8527609706, -0.1992137879, -0.3257340789, -0.2213805318, -1.5234873295, -0.1974401027, + -0.8294673562, 1.2558363676, 0.7330928445, 0.6681995988, 0.8794973493, 0.6108455658, 0.5544348955, -0.6794480681, + -0.7796459198, -0.7026695013, -2.1434984207, 0.0411658436, 0.3642963171, -1.1052713394, 0.2658634484, -0.452062279, + 1.2095198631, 1.5577833652, 0.3189541698, -1.2588919401, 0.8697476387, 0.2926436365, 1.0497710705, -1.7970030308, + -1.8265334368, -0.0994349569, 0.3744624853, 0.283995986, 0.5508910418, 0.5231243372, 0.7695473433, 0.2353003919, + 1.0889656544, -0.0385504179, -1.6064237356, 0.2855109274, -0.4909099638, 1.2451142073, 0.3549577296, -0.1303832978, + -2.4352939129, 0.550252676, 1.4097541571, -0.814353466, -0.4583834112, 0.5625880361, -0.05301442, -0.0092057148, + 0.0317580067, -1.3821700811, -1.1400830746, 0.2341952622, 2.0570058823, 0.6172062755, -1.9741103649, 0.9930515289, + 1.0489962101, 1.2614012957, -2.0655992031, -0.6154462099, 0.3555959165, -0.2700898647, -0.9979034662, -1.8507244587, + 0.9184408188, -0.3622143865, -0.1437021047, 0.9383545518, 0.0250540581, 0.5107842088, -1.4865230322, 0.6810082197, + -1.9815660715, 1.1557435989, 0.1040510312, 0.8280178308, 0.8028651476, -1.1024335623, -0.7035324574, -0.0274420045, + -0.6655241251, -2.0715312958, 0.2726945877, -0.6792376041, -0.1231326684, 1.4458146095, 0.2314967811, -0.6573718786, + 0.671246469, -0.7653050423, 1.4972485304, -0.9735265374, 1.5854916573, 0.2542545795, -0.15650253, -2.3489050865, + 0.0153308529, 0.7762720585, -1.4138087034, -1.5466600657, -0.2691728473, 1.6029889584, 0.7616153359, 0.9480590224, + 0.9128962755, -0.7814031243, 0.6315351129, -1.1406873465, -0.0793438703, 0.7408534884, 0.3598624766, -1.6224952936, + 0.7605880499, -0.4141521752, 1.9717255831, -2.0489830971, 0.3203971088, -0.5467629433, -2.4523425102, -0.9296472073, + -0.204058513, -0.5218498707, 1.471527338, 0.9998838305, -0.4258372784, -0.1646424234, -1.0052925348, 1.8012080193, + 0.7845478654, 0.8161594868, -1.8706011772, 0.0538863353, -0.520375669, 0.3057786524, -0.3377862573, 0.2710774839, + 0.139674902, -0.0968563706, -1.6479283571, -1.2091325521, -2.3561117649, -0.0236232337, -0.4046415389, 0.0204066318, + -0.2489682585, 1.7718049288, 0.7430356741, 0.3051402569, -0.3081843555, 0.6530711651, 0.665330708, 0.9015319347, + 1.21859622, 1.2392010689, 1.0117390156, 0.1708698869, -0.0968572199, -1.028801322, -1.4395042658, 0.4888134897, + -0.1481398195, 0.2349804938, 1.0387753248, -0.8918272257, 1.1819578409, 1.1469008923, -0.8863270879, -0.0768607333, + 1.6103775501, 0.2564200461, -0.6540455222, -1.4819751978, 0.3392748833, 2.3457913399, -1.9290598631, -0.5931926966, + 3.8038439751, 0.0150417322, 0.4764592648, -0.7765587568, -0.1422771513, -0.0276196878, -1.0998263359, 1.0197985172, + 0.7770087719, 1.2607687712, 0.3303723335, 1.3598996401, -0.1502128541, -0.9660602212, -0.2033868581, 1.8268421888, + 0.7102911472, -1.292470932, 1.4800399542, 1.2848676443, -0.6317282915, -2.0580847263, 0.7169486284, 0.8882303238, + 0.9122008085, -0.0191191155, -0.9266655445, -0.7308059335, 1.1142582893, -0.4701244533, -1.5005794764, -0.4836395681, + -0.5511965156, 0.8093124032, -1.2713971138, 0.4431983829, 0.5598557591, 0.1382537782, 0.5284568667, 0.0855464339, + 1.0339580774, -0.9627118111, -0.0867765024, -0.5620479584, -0.0449695885, -0.5436484218, -2.0981886387, -0.2393644899, + -1.0797698498, -1.1307771206, 0.2753635347, 0.7339200974, -1.4783803225, 0.0846191719, 0.4496826828, 0.4637614489, + -0.5138217807, 0.8895533085, 0.4025216401, 0.454090476, -0.2553262711, 0.0476168953, 0.3607804775, -0.9458797574, + 0.513006866, 1.0887874365, 0.0324329808, 1.7249981165, -0.5506155491, -0.2265087664, 0.1730436236, -0.8672905564, + -0.9517143965, -0.6819998622, 1.892563343, -0.5262590647, 0.2710691392, -0.0368213281, 0.2499300092, 0.1145922467, + 0.4249081314, 0.5221466422, -0.6290580034, 0.5858543515, -0.7500481606, 0.4885399044, -1.0888670683, -0.1751397997, + -1.0800218582, -0.5044698715, -0.6824820638, 0.3367467821, -0.0662877113, 0.0004860878, 0.3974931836, 0.9878262281, + -0.2203817666, -2.3339583874, -1.3713185787, 0.7010454535, -0.1792138517, 1.6398990154, -1.3528527021, -0.0485312343, + 1.6457034349, -1.522804141, -0.9622097611, -0.7212290764, 0.170836553, -0.1943217069, -0.1791012436, -1.5973223448, + 1.0700832605, -0.0263415724, -0.0783090517, 0.5096049309, 0.2359365672, -2.0904521942, 1.334338069, 0.0267197248, + 1.0169812441, -1.6574496031, -0.7635102868, 0.0978857651, 0.8636631966, 0.2661770284, -0.9758553505, 0.6706265211, + -1.1487759352, 0.727675736, 0.0401194058, -0.8232668638, 0.1121659577, 1.8414586782, -0.5288928747, -0.594255507, + -0.0549913421, -0.3535532951, 0.4613077641, -0.8000953794, -1.1293758154, 0.7078111172, 0.2381000668, -0.2260020673, + -1.028799057, 0.6059779525, 1.0500333309, 0.406240195, 0.5371391773, 0.0047277003, 1.6705203056, 0.4563495219, + 0.2244141847, -1.6428673267, -1.8438435793, 0.3145678639, -0.4614353478, 0.4700029194, -1.7696510553, 0.0000749491, + -0.097691074, 0.5977476239, 0.2733864784, 0.3712363243, 0.7553363442, 0.3672829568, 1.1928751469, 1.4054775238, + -2.325838089, -2.9297554493, 0.2743716836, -0.7235479355, 1.5969778299, -1.8682086468, 1.4272466898, -2.3928434849, + -0.7951687574, -0.3718027174, -0.211187005, -0.4080311656, 0.4804771543, 1.6419860125, 0.951487124, 0.6680909395, + -0.5509938002, -0.0222789478, -0.1015945151, 0.1699242294, -1.2516422272, -1.5921986103, 0.0323502608, 1.3214668036, + -0.0185927413, -0.488527298, 1.0027142763, 0.0604401119, -0.5876231194, -0.2673060298, 1.1417536736, -0.5216576457, + -0.908079505, 0.2505319715, 1.5503072739, -0.5802096725, -0.5431979895, -0.8207826614, -1.8523241282, 0.7910633087, + -1.5131099224, -0.53467381, 0.8551876545, -0.8079803586, 0.3514728546, -1.0119205713, 0.1222014651, -2.3043191433, + -0.5708674192, 0.554392457, -0.8940060139, 0.2141406089, -0.4124077559, -0.0373211876, -0.4836105108, 0.9895735383, + 1.3710926771, 0.3094007373, 1.0810010433, 0.7413520813, 0.0272918269, -2.6059725285, 0.7118025422, -0.3565561175, + -1.5837817192, -1.8069742918, 0.0314307399, 0.7519264817, -1.6187287569, -0.0656537339, -1.2725286484, -0.0628013238, + -1.2660244703, -0.2694690824, -0.9322804213, -1.7178848982, 0.3884723186, 1.1313183308, -0.8840425014, -1.5170679092, + 0.8701610565, 0.660443604, -0.3095566034, 1.1559892893, -0.0074164211, 0.9563302994, 0.5253620744, -1.1275501251, + 2.1611838341, 0.2815635204, 1.0019308329, 0.3967360556, -1.351703763, -1.6757366657, -0.4909931421, -0.2150374204, + -0.4196070433, 0.0863581672, -1.1695873737, -0.2097769529, 2.7132956982, 0.6640202999, -0.3107252419, 0.1927692294, + -1.1766229868, 0.5481172204, -0.0203474443, 1.5921030045, 0.8253238797, 0.2750462592, -0.3395743668, -0.1995105147, + 0.2876706421, -1.2705643177, -0.4173485339, -1.0307558775, -1.9259363413, 0.30101794, 0.5864936709, 1.1382341385, + 2.5246179104, -0.5178236961, 0.8482388854, 0.9648278952, 0.5560377836, -0.2276707441, 1.0964823961, -0.298150003, + -1.1091046333, 0.2975334525, 0.6693788767, 1.2441065311, 1.2527660131, 0.1742370129, -0.2687437832, 0.8906718493, + 1.1863725185, -1.3319261074, 0.1384135783, 0.9704707861, 0.6115167141, 0.1373640597, -0.4339033961, -1.5552423, + 0.6139218211, 2.3210573196, 0.5673650503, -1.5066421032, -0.9496950507, -1.8230872154, 0.2817157209, 1.3412139416, + -0.3125414848, -0.7926390171, -1.8839703798, -1.5029090643, -0.4812536836, -0.8076776266, 0.1639763117, -0.7107151747, + 0.9037547708, 1.1245650053, 0.4608503878, 1.4936001301, 0.8328832984, -0.1224921197, 0.8565199375, -0.8202630877, + -0.1175216883, 2.642729044, 0.7497962117, -0.1043440327, -0.5497339368, -0.1805608422, 0.2127023935, -3.0390629768, + -1.0456823111, 0.2500087917, -1.022548914, -0.7522569895, 0.1320671141, 0.0960535109, 0.2754767239, 0.7104935646, + 0.4646618962, 0.8646464944, 2.8653013706, -2.1563317776, -0.9281902909, 0.3972793519, -0.9229031801, -0.2998534441, + -0.3409955204, 1.2158575058, -1.6193940639, -0.4401818812, 0.1239653826, -0.1996781826, -0.8049672246, -0.3598818183, + 0.237965852, 0.7701300979, -1.6182599068, -0.8581345081, -0.2470516115, -1.749106288, 1.4807767868, -0.5614758134, + 1.2209767103, 0.2904929221, -0.0265204366, 0.5695201755, 0.1617171317, 0.7726086974, 1.0486824512, -0.3704072833, + 1.1730215549, -0.5312774777, 1.3397569656, -1.044319272, -1.3226132393, -0.2041894644, -1.5650993586, -0.099583976, + 0.2208478004, -0.4249693155, 0.9977360368, 0.5591554642, -0.0693533272, -0.9527857304, 0.7313643694, -0.1154942065, + 0.6147226691, -0.5344278216, -0.4461407363, 0.6166067719, 1.1970794201, 0.3441028297, 0.999579072, -0.1399023682, + -0.2110286802, -2.04464674, 2.6426510811, 1.7442144156, -1.2394208908, -1.1079133749, 0.2935610712, 0.0725700185, + 0.3695668578, 0.5065841675, -1.0672954321, 0.5645725131, 0.7228435874, -0.8897636533, 0.4221113324, -0.4366683066, + -0.4785924852, 2.0385699272, 2.5463235378, -0.9433593154, -0.9427928329, -0.7519164681, -0.6663823724, -0.3502293527, + -1.4659262896, 0.2184054852, 0.3883730173, -0.5445824265, -0.4340218902, 3.7029385567, -2.9254779816, 0.0942560732, + 0.7164333463, -0.4786452055, -0.1175122783, -0.6979387403, 0.2932125032, -2.5538980961, -0.6223775148, 0.2257152498, + -0.3763697743, 0.8137111068, -0.5992847085, 1.3243182898, -1.2376658916, -0.05292207, 0.3752489388, -0.2927281559, + -0.8624119759, -1.7237237692, 1.1811594963, -0.3744150698, -1.1541925669, -1.5252789259, 1.3609256744, 0.3352670372, + -0.7940573692, -0.5847789645, 0.0678094849, -0.2327625602, -2.0279872417, 0.0251677223, -1.405616641, -1.6464124918, + -0.2422740161, 0.837013185, 1.5657683611, -0.4537927806, 0.7318181992, -1.0169379711, 0.739254117, -0.3775894642, + 1.7589201927, -0.961266458, -1.5072410107, -0.9849436879, 0.2215117812, -1.233300209, -0.1126676127, 0.1513326466, + 1.5155856609, -0.8208940029, 1.8061890602, 0.175095126, 0.0165317189, -0.0252383649, 1.7736938, 0.5884373784, + -0.9119014144, -0.6989759803, -1.0164759159, 0.0299540386, -0.0303175766, 0.5049239397, -0.6621921062, -0.2147170007, + 0.2130482644, -1.016926527, -1.0796117783, 0.9682517052, -0.2484214753, -0.0983709693, 0.4231301248, 0.971411407, + -0.3323786557, 1.594147563, 0.0305444896, 0.4641273916, 1.1204073429, -1.7273485661, -1.9588909149, -0.0995916799, + 0.4214471579, 0.2391090691, -0.855042398, 0.5174822807, 0.643524766, 0.7362871766, 0.2990854383, 1.6299250126, + 0.0470980965, -1.4124903679, 2.000181675, 2.4043455124, 0.4756488204, 0.3924701512, 0.3098393083, -0.0730008855, + 0.0644879714, -0.5879397988, 3.1723389626, -1.130998373, 0.4812060297, -1.0504877567, 1.6183617115, -0.6508139372, + -0.3729372919, 0.8800085783, -0.1217752844, -0.7541463971, -2.0912880898, 0.017303925, -0.30266729, 1.9386875629, + -0.5450688601, -0.884093523, -1.0172849894, 0.2282519937, -0.7308015823, 0.017845476, 1.1036424637, 1.0490378141, + 0.0145709217, -0.657001853, 0.6453847289, 0.806860745, -0.9951968193, 1.635320425, 0.2871158421, -0.1186865047, + -0.7178679705, -0.2702004313, 0.7870482802, 1.235422492, -0.5233058333, -0.9856014848, -2.3766124249, -0.3460740149, + 0.8292262554, -0.1120812893, -0.5926383138, 1.5636755228, 0.5033448339, 0.0718692541, 0.041075401, 0.317248702, + 1.050745368, 0.015992675, 0.4478392601, -1.4229664803, 0.7920886874, 0.1866728514, -0.8899513483, 1.5150766373, + -0.7372040749, 2.3344931602, 1.7175177336, -0.2363054156, 1.2435344458, 0.1209539473, 2.1040270329, -1.0785930157, + 1.0357654095, -1.2035720348, 0.6071705222, -1.2331465483, 0.0831739157, 0.5158026218, 1.2514107227, 0.5857951045, + 0.5511865616, -1.0304999352, -0.7450944185, 0.8752056956, -0.8220462799, -0.5751981139, -0.3852460086, 0.4066129625, + -1.4922865629, 0.5390688777, 1.0325790644, -1.0658810139, 0.8860808015, -1.0557252169, -0.3435255885, -0.3831379414, + -1.5366101265, 0.7045727968, -0.4226921499, 0.2454482317, -0.9025840163, 0.5418877006, -0.0653132945, -0.654279232, + -0.2471905053, 0.6364162564, 1.2548311949, 0.8018607497, -0.0924706161, 1.7474905252, -0.0242728647, 0.7594467402, + 0.2591527998, 1.2631505728, -1.0255336761, 0.500228703, -1.4737606049, -1.7188454866, 1.5862935781, -0.7704221606, + 0.215885818, -0.685956955, -1.4657487869, 0.1420394927, -0.7383154035, -0.6743084788, -2.7707183361, -0.1151084825, + -0.6279640198, -1.658449173, -1.2487521172, -0.1758100241, -0.2976056635, 0.628154397, -3.0891396999, 0.6630514264, + -0.9883195758, 1.5522327423, 0.6034018993, 0.2812715769, -0.2210479379, 0.0146459658, -0.3543334901, -0.4833302498, + 0.9713264704, -0.2638811171, -0.687084794, 0.2799275219, 0.2579723001, 0.0368682183, 0.7310587168, 0.2262041271, + -0.201625526, 1.0671253204, 0.0625227988, 0.6604328156, 0.6529068351, -1.1744426489, 1.3701006174, -1.0094944239, + 0.5174626112, -0.8501479626, -0.378521502, 0.2888900936, 0.8252806067, 1.7142086029, 0.7759332657, -1.7127082348, + 0.5845321417, -0.3192206919, -0.1254154444, -0.191873461, 1.2321667671, 2.6393880844, 0.282404989, -0.6123250127, + -0.3582670987, 0.955358088, -0.5618331432, -0.2247440219, -0.8032472134, -0.4080768824, -0.9748763442, -0.2706478536, + 0.5201159716, 0.0428278558, -0.6018859148, 0.7460201979, 0.0247440431, -0.0502817854, -0.7423041463, -0.839297533, + 1.2616049051, -0.9946495891, 1.9058818817, -0.1542883366, -0.1210363731, -1.2415443659, -1.2345449924, 0.9470774531, + 0.3019158542, 0.8561933041, -2.6018064022, -0.7974361181, 0.2222371846, 0.4300654829, 2.8669002056, -0.5035877824, + -1.6985487938, 2.0215651989, 0.10903126, -1.6191835403, -0.0101143373, 1.0134818554, 0.4818102717, -1.9236172438, + -0.6230416894, -0.1731863171, 1.4452866316, 0.1037637815, 1.5183800459, -0.4374295473, -2.5311095715, 0.2603306174, + -0.4341614842, -0.0227584727, 0.0439706743, 0.5057605505, -1.7936534882, -0.5852804184, 0.167279169, 0.8425058126, + -0.6111262441, -0.9124225974, -0.2337473482, -0.0449558981, -1.8964269161, -2.0928378105, 0.8949176669, 0.9105094671, + 0.9112442136, -0.4834975004, 3.5092229843, -0.5729820132, 2.0387670994, 1.0817768574, 0.3173472285, 0.1624213457, + 0.8563386798, 0.4270950556, -0.3292297125, 1.1796474457, -0.0568520613, -0.6135614514, 1.0171507597, -1.0845253468, + -0.0473044775, 1.4754977226, -0.0622475371, 0.7117826343, -1.004101634, -0.9487560391, -0.0518494286, 1.4331901073, + 0.2149605602, -1.1410475969, -0.6128460169, 0.5419374704, 0.368984431, 0.8537623286, -0.7307296395, 0.4909996092, + 1.1410055161, -0.7519097328, 0.83678478, -0.4134968519, -0.3831160069, -0.1194213182, 0.2132193446, 0.8922790289, + 1.199452877, 1.8140201569, -0.5317217112, 0.7226940393, 0.4397925436, -0.4289795458, 1.2970182896, 0.5386045575, + -0.3921145797, 0.3799457252, -0.2168604136, -1.2815352678, -0.5558221936, -0.6706677079, 1.1508843899, 0.8142685294, + 0.0629897863, 1.0782709122, -0.3097993731, 1.1608967781, -0.0450324751, 0.9269484878, 0.1099951491, 1.0994768143, + 0.0873215795, -0.6024252772, 0.0804315135, 1.1702136993, 1.2390604019, 0.042295713, -0.2660755217, 0.0252159797, + 0.3653047979, 0.6382434368, -0.1962671429, 0.5976749063, 0.2093169689, 1.3053292036, -0.1818927377, -0.8006437421, + 0.752699852, -1.2449376583, 1.6166766882, 1.4126682281, -0.9880897999, 0.1460569501, -0.38672629, 0.8620718122, + -0.9725794196, -0.2764593959, 1.110212326, -0.817945838, -0.4496610463, 0.17125687, -0.5782694221, 0.7184853554, + -0.7871074677, 0.1874635667, -0.9851943851, 0.9395116568, -1.3483319283, 1.3027681112, 0.5989563465, 0.3927023411, + -1.0175455809, 0.785314858, -0.4428822696, 1.2068151236, 1.2453286648, 0.2258458585, 1.1729338169, -0.3745219409, + -0.1013393402, 0.7370291352, 0.2293027043, -0.5496422052, 0.402657479, 1.7350859642, 0.8466253877, 1.6243348122, + 0.2167896926, 0.0440245979, -0.114386715, -2.1155114174, -1.3466324806, 0.3417681754, 1.0367302895, -0.0448520556, + 0.1536931545, -0.1178123504, 0.0942037478, -0.2840364575, -0.8906734586, 1.0415467024, -0.347456038, 1.7721912861, + -0.6977778077, -0.6533368826, 0.27065745, 0.4579048455, 0.5070598722, 0.2563111782, 1.0382679701, -2.1179025173, + 0.1377092451, 0.020978028, 0.9947603941, -0.0382568911, 0.2360651493, -1.6812630892, 0.4709948599, 1.8487871885, + 1.1363065243, 0.679420352, 1.6432129145, 0.3331112862, 0.4847803116, -0.2373197377, 0.8562826514, -0.8727971315, + -2.7746782303, -2.3559737206, -0.2040310651, -1.7742786407, 1.958476305, 0.7933133841, 0.6449356079, 1.4588258266, + -0.0484815538, -1.0195758343, 0.2607858479, 0.366432786, -1.2107329369, -1.9957568645, -0.4150539041, 1.5697511435, + 1.9711836576, 1.5477201939, 0.0248154551, -0.7006254792, 0.6331615448, 0.5916293263, 0.0568252914, 0.1661783904, + 0.2813738585, 1.0866055489, -1.0118426085, -0.0859973654, -0.7634933591, 2.10333395, 0.3371011317, -1.1005963087, + -1.3655861616, -0.8443711996, 1.1577920914, -0.624120295, -1.8529772758, -0.6705492735, -0.314467907, -0.1968949288, + -0.2270013392, -0.1578439176, -2.0221607685, -0.1185465753, 0.4237858653, -0.0993085131, 1.3173325062, 0.1934987605, + -2.9459500313, -0.1461422294, 0.265147835, -0.841060102, -1.7123898268, 0.0538811646, 0.0466864482, 0.0800267011, + -1.7519488335, 0.2975313067, 1.4007811546, -0.9453305006, 0.597191453, -1.0898880959, -0.7380421162, -0.41643399, + -1.2008498907, -0.6115810871, -0.1443822831, 1.1616984606, 1.1686754227, 1.292023778, 1.4396482706, 1.3408201933, + 0.4317942858, -1.3623890877, -0.768044591, 0.5570045114, 0.4734558761, 1.1375391483, 0.5354587436, 0.4446857274, + 0.546785295, -0.1238997132, -0.685171783, 2.1651611328, -0.4368666112, 0.0831865296, 0.0198221132, 0.4435079098, + -1.6825557947, -0.1355063766, -1.637975812, -0.2781943679, -0.290491432, 0.8691003323, 0.2901981473, 1.5223109722, + -1.3436995745, 0.489536494, -0.6511492133, -0.3522801995, -0.8010972738, -0.3451113701, -0.1639397591, 0.6182901859, + -0.8302804232, -0.0971979052, 0.1578138769, 1.5443570614, 1.3465884924, -1.1086828709, 1.7096700668, -0.1851585954, + -0.0696520433, 0.8750807643, -2.055368185, -0.8725947142, 0.603656888, 1.8323498964, -1.1572742462, -0.2411930561, + 0.696511209, 0.6085639, -0.6458541751, 0.1013178676, -1.0230764151, -0.8841358423, 0.6133187413, 1.1686683893, + -0.1828366816, 0.1179393306, 0.6337798834, 0.4901778698, -0.9213451147, 1.1282690763, -1.3957413435, -0.934525609, + 1.4516988993, -0.3256015778, -1.7746162415, 1.1917959452, -1.2848377228, -2.0234019756, 0.6253730059, 0.5754631162, + 1.0525467396, -1.4490629435, -0.5101265907, -0.5352268815, -0.146167025, 0.4182570577, -0.8196110725, -0.2917360961, + 0.135776937, -1.4317878485, 0.5729535818, 1.0932507515, 0.999933362, 0.9448190331, -1.1056905985, 1.2392117977, + 0.0591306388, 1.4897656441, 1.606128335, -0.6775377393, -0.4090647399, 0.3424934745, -0.921212256, -1.3457553387, + -1.0322591066, 0.298605442, -0.8338737488, -0.0210380573, 1.5235228539, 0.1132932231, -1.1214870214, 0.2483399361, + 0.6102077365, 0.1721328497, -1.2462910414, -1.4098676443, -0.006886343, 0.6785459518, 1.0933088064, 0.0307702217, + -0.8330343366, 0.0852738246, -1.656801343, 0.0855158269, -1.0569945574, 0.331425935, -0.7124000192, -1.2863686085, + -0.0895156786, -0.0622664876, 0.4961340427, 0.1014336422, -1.3754044771, 1.357812047, -0.070522204, -2.0296418667, + -1.0720357895, 0.5115970969, 1.0631728172, -1.0660487413, -1.4533889294, -0.2905147672, 0.2778032422, 1.8945484161, + 0.6868228912, 0.5472155809, -1.9280380011, -0.4031965435, -0.5989333391, -0.2061021477, 0.8257248998, 0.9506226182, + -1.1330982447, 0.4963971674, 0.5451398492, 1.290678978, -1.5282840729, -0.8242005706, -0.0166608077, 0.0335856453, + 2.2408883572, 0.4733282924, -0.7696737051, -0.833573997, -1.4651881456, 0.938999474, 1.8702383041, 0.020253256, + -0.4591764808, 0.2830611765, 2.2367684841, -1.4029413462, -0.1545487493, 0.230300799, -0.1837261021, -0.8145059943, + -0.0218058843, 0.0932727531, 1.0467610359, 0.7866660357, 0.4435950518, -0.0753492266, 0.3163510263, 2.2630624771, + -1.5913091898, -1.3097940683, -0.8521066308, 2.0647218227, 0.2911355495, -0.9971901178, -2.6643984318, 0.1316338181, + -0.7985268235, 0.1305931062, -0.2064609826, 1.2719758749, 0.5087019205, 0.2554793358, 0.6482380033, 0.7646680474, + -0.6734172106, 0.2700004578, 0.0559221543, -1.0332484245, -0.4205034673, -0.9777092338, 1.4239164591, -1.2049342394, + 1.1088242531, 1.6507546902, 0.274897635, -1.1399236917, -0.5846256018, -0.4150563776, 0.1476821899, -0.7782986164, + 0.9938122034, 0.349894017, -1.1976610422, 0.458861649, -0.3367350996, -0.4915359616, -0.2937815785, 0.780074656, + -1.1308561563, 0.7726313472, 0.3986551762, 0.5029765964, 1.676268816, 0.470957011, 2.0376982689, -0.7127743363, + -0.139295131, -0.9906319976, -0.2955588996, 0.2931172252, 1.2992885113, 1.7970376015, 0.4209524691, 0.9865259528, + -0.9265616536, 0.5395507813, -0.2611883581, -0.0639136136, -0.080099158, 0.507971108, 0.2602309883, -0.4143621325, + -0.9424008131, 0.6740956306, -0.3937194943, -1.0629720688, 0.5936015248, -0.6519501209, 1.1757981777, -0.7144102454, + -0.1102670729, -0.3803231716, -1.3536223173, -0.8384763002, -1.8306593895, -1.6056002378, 0.2277152538, -0.5050942302, + -0.4376785755, -1.3809183836, -0.9032619596, 0.9237828851, 0.5372219682, 0.2870643735, -1.5153040886, -1.625921011, + -0.0451527424, 0.2230039835, -0.7418859601, -0.4045087099, -0.1136229634, 1.6879923344, -0.9585251808, 0.0452248342, + -1.4134316444, 1.5886644125, -2.2719659805, -0.8550316095, -2.3864667416, -0.4699884653, -1.4324147701, 0.2486818582, + -1.2270326614, -0.6884349585, -1.865439415, -1.2348514795, 0.4219813049, -0.3581189215, -0.3238225877, 0.7833189368, + -0.1920600682, 0.7204907537, -0.1709788293, 2.3878262043, -0.2370357811, 0.9252066016, 0.4822584987, 0.6451716423, + -0.6012758017, 1.0694143772, -0.1956869662, -0.857753396, 0.4864356816, -0.2107046247, 0.6681656241, -0.8437408209, + 1.2435525656, 0.6121364236, -0.5362357497, -2.3874721527, -0.7291497588, 0.676625967, 0.3310092092, 2.5184285641, + -0.9417285919, 0.3908450902, -0.9795922041, 0.4405451715, 1.6861338615, -0.8826841712, -0.3646148145, -2.1359474659, + -0.8896039128, -0.8913089633, 1.8602352142, -0.0924306363, -2.5201990604, -0.4996497631, -0.7356934547, 3.0227034092, + -0.2779353559, -0.9125910401, -0.5229797959, -0.3131267428, -1.1275002956, 1.0743371248, -0.5666452646, 0.3104890287, + 0.670196116, -1.6568621397, -1.3614599705, -0.3111041188, 0.1598366499, -0.307831347, 0.1877021044, 1.6093233824, + 1.2444223166, -0.2770603597, 0.2751346529, -0.3467116654, -0.6917365193, 0.5257941484, 0.7689983845, 0.3357297182, + 0.1524437368, 1.6918798685, 0.3152635694, -1.0607805252, 0.6609638333, 0.3341110945, -1.0415834188, 0.8687285781, + 0.8544582725, 0.1155287027, 0.3381574154, 1.2941756248, -0.2241853923, 0.5553392172, 0.8699635267, 1.2132816315, + 0.102926828, -1.5269670486, 0.1696930826, -0.3773308396, -0.1566898823, -0.820332706, -0.5906712413, -0.5726389885, + 1.7057299614, 1.0661014318, -0.8808380961, 1.9740517139, -1.5351676941, 0.0559960082, -0.1033231318, 0.261194557, + 1.6715939045, 0.6242154241, -0.9938521385, -0.0939270034, -0.6858149171, 0.3675427139, -0.1992009878, 0.6083980203, + -1.510666728, 0.5414758325, -1.5780515671, 1.3849695921, -1.3922752142, 0.1662127376, 1.1939231157, 0.106904313, + 0.0348040052, -1.3020936251, -0.7385377288, -0.9714508057, -0.1246909872, -1.2599545717, -0.569160223, 0.091302745, + -0.3601581752, -1.2885582447, -0.6923422813, 0.0218632966, 1.1481493711, 0.319981128, 0.6208224297, 0.1437385976, + -0.0351644456, -0.2080980837, -0.7999038696, -0.0143128783, 1.8700890541, -0.8725613356, 1.9158043861, -0.5309497118, + 0.5074033737, -0.2050864398, 1.8342417479, 1.3920772076, 1.2333165407, -0.0904451087, -1.6107214689, -1.21507442, + 1.6213306189, 1.3490490913, -1.2004847527, 0.4088242948, 1.638158083, -0.033711385, -2.1315181255, -0.6664378047, + -0.3451897502, -0.5859259963, -0.7312455773, -0.8802397847, 1.0734250546, -0.2296246886, -1.1476899385, 0.0753600448, + -0.1252810806, 0.5062884688, -0.0693661049, 0.0646183267, 1.8327145576, 0.664776504, -0.3912880421, 2.0176594257, + -0.6505314112, 1.8023506403, -1.4049191475, -1.0420913696, 1.1070687771, -0.5325237513, -0.3083402216, -1.1807949543, + 0.1285699606, 0.1529561281, -0.1071198657, 0.6465570331, 0.2372447997, 0.6004552245, -0.3670341671, 0.1296212673, + -0.7611243129, -0.0786540359, 0.7158681154, -0.4898069501, -0.0783000439, -0.2104012817, -2.9151592255, 0.0618991032, + -0.8712686896, -0.9809957743, -1.3866854906, 0.2422163934, 0.7125367522, -0.1848194599, 2.3176703453, -0.4459954202, + 0.5021077394, -0.2677321136, -0.6174522042, 0.0102121448, -0.8748270869, -0.5692952275, -0.2101370692, -3.1677110195, + -0.9791932106, -0.4656033218, -0.8843027353, 0.0018855287, 1.6177743673, 0.7415726781, 1.284386158, -1.5041314363, + 0.3272034526, 1.0130852461, 1.0509754419, 0.138635084, 0.1534719616, -0.8860257864, -0.2906185389, -0.4992392659, + 1.0161581039, -0.3753769994, -0.868244648, -0.9607298374, -0.915730834, -2.2028121948, -1.2302342653, -1.0565544367, + 0.6787397861, 0.4913366139, 1.1512709856, 0.2273500413, -0.3140943348, 0.9650218487, 1.1202888489, 1.41439116, + 0.1416300088, -0.6327657104, 1.1599075794, 0.903527379, 0.3643698692, -0.1275601387, -1.2958214283, 0.4469485879, + 0.1940546483, 1.2936275005, 0.2017951459, -0.8351511955, -0.0646853894, 0.1063179448, -0.7791896462, 1.3193002939, + -0.066249907, -0.1504552513, 0.5341873169, -0.4398691654, -0.053759899, -0.829318285, -0.8617116809, 0.7136631012, + -0.3939204812, 1.5737469196, -0.0540837012, 1.4036841393, 0.137864098, 0.9466567636, -0.7069780827, -0.4565291703, + -0.1137186959, -0.1762137711, -1.0199981928, -0.2759044766, 0.7262592316, 0.2267369032, 1.0947389603, 0.2019783854, + 0.3519686162, 1.275377512, -0.0727279261, -1.5853526592, 2.0832924843, 0.9841842651, -0.9553976655, -0.103096962, + 0.1650699079, -1.0748144388, -1.802192688, -1.3359909058, 0.3166110814, -0.2559000254, 1.7907859087, -2.5822634697, + -0.7786031961, -0.8376648426, 0.3916146159, 1.1735594273, 0.1578970551, -0.0654573068, -1.0033574104, 0.4908643365, + -0.3393624723, 0.265625, 0.5900098085, 0.1851583868, 1.1900016069, -0.06368839, -0.6513484716, -0.1623256058, + -2.4267354012, -0.3015221357, 0.8572072387, -0.3075442612, 1.3093880415, 0.142673254, -0.0542080179, 2.3609998226, + -0.5969130993, -0.9994596243, -2.0351839066, 1.2536141872, -0.0141155524, 1.1488707066, 0.3340318203, 2.5600366592, + 0.3605966866, 0.6146651506, -1.4186687469, 0.272708118, 0.0324210338, 0.1732143015, 1.2016236782, 1.1515592337, + -0.8048486114, -0.4166365862, -0.8107392192, -0.2680552602, 0.7969276309, -0.253690958, -1.2414793968, 0.0307318419, + -0.7246635556, -0.0614210144, -0.098032251, -0.1273739636, -0.8733004928, 0.8253334761, 0.3285685182, 0.2195947468, + -0.4676854312, -1.7725604773, -0.070647873, -0.8255471587, -0.8020666242, 0.7796689868, 0.0053337635, 0.5974035263, + -0.5471351743, -0.5485429168, -0.0285736788, 0.014589454, -0.8462850451, -0.3286907971, 0.5849106312, -0.0293410309, + 0.3513242304, -0.6039078236, 0.6773921847, 0.8920910358, -0.3698989749, 0.8443539739, -0.9569555521, 2.1414206028, + -1.4383490086, 1.8881260157, 0.2543646097, 0.1823499501, -1.837998867, -2.362609148, 1.9306805134, 1.1447869539, + -0.7892955542, -1.358394742, 0.1193050891, -0.5391947627, -0.8748807907, -1.0574221611, 0.1377330273, -0.1817522049, + 0.3828250766, -0.6502447128, -0.40131405, 1.517744422, -1.1044421196, 0.408867389, -1.6362469196, -0.0767254755, + -2.1334729195, 1.6754659414, -1.0141512156, -0.2841005921, -0.7273792028, -0.1547815204, -0.3518456221, -1.610124588, + 0.3806446791, 1.5120161772, -0.3957258463, -0.3997440934, 1.0012264252, -0.5169299841, 0.2179621607, 0.0726020262, + 0.8056242466, -0.3302493989, -0.5640383363, 1.6068236828, -0.879558444, -2.0162665844, -2.8408839703, 0.047110796, + -2.4121069908, -0.4298157692, -0.2259212136, -0.2872554958, -2.6355597973, -0.0566891581, -0.32429263, -2.4704289436, + 0.1055299938, -0.9959416389, 0.3086238503, 0.9671957493, -0.5396192074, 0.6040809751, 0.5914162993, -1.0520744324, + 0.2196249813, 1.1837112904, 0.7854421139, 0.2140046954, 0.0103036715, -0.4791815281, 1.0802093744, 2.2894952297, + 0.5970520377, -1.0285168886, -0.8583711982, 0.5456027985, -0.4148845971, -0.335321039, 0.1510142237, -1.1208082438, + 0.4330037832, 1.5839723349, -0.451782465, 0.7348692417, 0.6062211394, 1.1804046631, -0.2156865895, -1.9402424097, + 0.7674831152, -0.6204615831, -0.9424259663, -0.7667592168, -1.7198344469, 0.1882339567, 0.3915354908, -1.2951434851, + -1.4637438059, 0.40997082, -0.37328282, 0.2660309076, 2.2915365696, 0.8822026849, 1.2864061594, -1.0476447344, + -0.5300865173, -0.8190235496, -0.7607998252, 0.6160025001, 1.4188951254, -1.2633959055, 0.9278722405, 1.2578333616, + 2.5271196365, 0.2058767378, 0.4043089151, 0.9949845672, -3.1527338028, 1.2946237326, 0.9710022211, -0.1420307904, + 0.5478397608, -0.8206241131, 0.3207755387, -1.1367980242, -0.3007896543, 1.067288518, 1.1049232483, 1.0061985254, + -0.6842412949, 0.4629309773, -0.6022585034, -1.816339612, 2.4398572445, -0.530216217, -0.1656367332, -0.4852881432, + 0.3775443435, 0.5550758839, 0.1274569929, -0.5471289158, -0.3199679852, 1.2949386835, -0.612483263, -0.1371923089, + -0.2731872797, 0.6984583139, -0.9401183724, 1.2994360924, 0.818151474, 0.7731116414, 1.0036376715, 1.5827988386, + -1.2974874973, -0.1434350908, 0.6647178531, 1.7826393843, -0.5892428756, 0.2183041722, -0.9415503144, 0.6296509504, + 1.4211704731, 1.8153684139, 0.4850921035, -0.8563700914, 0.695325017, 0.707475245, -0.9068002105, -0.7238519192, + 0.8457453251, 0.659127593, -1.3648034334, 0.9885088205, 0.989964366, -1.4283225536, -0.2611402273, 0.6861331463, + 0.6731824875, -0.9871585965, 0.3236202002, -0.2243195921, -1.3043832779, -0.9144351482, -0.0288481209, 0.3471129537, + 1.915776372, 1.3639667034, -0.0679871738, 0.0099768415, -0.7806731462, -0.3309215307, -0.5239000916, -0.7487209439, + -2.0122323036, -0.7074913979, 1.0903810263, -0.1148329824, 0.7587329149, -0.8750514984, 0.1420132518, 0.7049495578, + 0.9195414782, 0.0968873128, -0.573349297, 1.3557649851, 0.6867563128, 0.5227616429, 1.4819657803, -0.5568839312, + -0.4434660375, -0.6686267257, -0.2037937194, -0.2320554256, -1.274725914, -0.5040209889, 0.1536800563, 0.3864961267, + 0.1177268252, 0.4147295058, -0.4290784895, -2.1149220467, 0.1111558527, 0.5690610409, -0.5074170828, -1.311622858, + -0.3538000584, 0.9582650065, -0.4444060624, 0.4389349818, 0.668499589, 2.0895423889, -1.5145853758, -1.0995954275, + -1.9046037197, 1.443777442, -0.3302248716, -0.9572323561, 0.3254705071, 1.175822258, -0.331449002, -1.996950388, + -0.2365534455, -0.0082780914, 0.2744103074, 0.0309559889, 0.4002328515, -0.7249093652, -0.1263285577, -1.1013489962, + 1.3815333843, 1.8019288778, 0.0788859054, -0.8572096825, -0.7831746936, -0.6566607952, -0.5514259338, 1.156175971, + 0.0486259237, -1.4882011414, -1.7478359938, -0.4349352121, -0.5980690718, -0.0105753476, 0.6441072226, 0.8070641756, + 1.336645484, -2.4222583771, -1.7629585266, 0.4242415428, 0.5227168798, 1.2409411669, -0.9768437743, 0.5091602802, + 0.4706636965, 0.8562821746, 0.5442659259, 0.9753083587, -1.0318638086, 1.0895196199, -0.3157981634, -0.249818176, + -0.0072620874, 0.3074987233, 0.74050951, 0.0923283026, 1.531468749, 0.47128281, 0.7196969986, -1.2597471476, + -0.8728388548, -0.7292687893, 0.1062755734, -0.7407863736, -1.3908658028, 0.0886164233, 0.6232225895, -1.4311265945, + 0.9013275504, -0.3596685529, 0.1025697961, 0.0446388386, 0.6425230503, -0.2347142994, 1.9980522394, -1.0065909624, + 0.119044818, -0.2422155142, 0.0530792251, -1.4308447838, 0.2798071504, 0.6393198371, 0.4337556064, 1.0134214163, + -0.7661970258, -0.3400665224, 0.6894814372, -0.6211586595, -1.1139371395, -0.4133455455, -0.830860436, 0.1453806609, + -0.7555692196, 0.6801390052, 0.8128879666, 0.5958173275, 1.0729752779, 0.4843373299, -0.4979102314, 1.386418581, + 0.9193938971, -1.5006879568, -0.4991283119, -0.264837563, 0.4287530482, 0.8467736244, 0.9204974174, -1.7422208786, + -1.4175399542, 1.3389828205, -0.1382659376, 0.5003929138, -0.8001933694, -1.1260420084, -0.7873304486, -0.4730960131, + 0.1702415347, -0.4686396122, -1.4204618931, 1.7457896471, -1.9309419394, 0.6022258401, 1.0969513655, 0.2393837273, + 0.2116515785, 0.5585256219, 1.0960396528, 0.9194073081, 0.2306050062, -1.1204822063, 0.5107620358, 0.7941451073, + 0.1340462267, -0.8106143475, 0.3599536419, 0.5154025555, 0.0600135475, -0.723210454, 0.3722366095, 0.2504935563, + -0.0045491043, -0.6716938615, 0.2279936522, 0.1172791049, 0.5441622734, 0.7014442682, 0.1636167318, 1.924762845, + 1.3642557859, -1.3011333942, 1.4473772049, -0.2376226336, 0.6195828319, 0.2934015989, -0.569680512, 0.0819147378, + -0.0124860499, 1.4523462057, 0.4789505899, -1.6496356726, -0.0578171164, 0.6523512602, 1.5945521593, -1.2960835695, + -0.6454660892, 0.3898889124, -0.2493240684, -0.7321791053, -1.3518134356, -0.823004365, 1.4176563025, -1.4937674999, + 0.6788947582, 0.0714109913, -0.1779415756, -1.9323011637, 0.6027720571, -0.2723703384, 1.1922283173, 0.9429624081, + -0.1027375609, 2.0723633766, -0.8419672847, -0.7306387424, -1.5093916655, 0.6934100389, -0.0410907716, 0.7249060273, + -0.1354019344, 0.7563098669, 0.3674355447, 0.7718367577, -2.6049280167, -1.3262532949, -1.2036824226, -0.4017079473, + 0.4643644989, 0.3264178038, -2.6617326736, -0.7910155654, -0.3290653527, 0.2054002136, 0.9232746363, -0.3793618381, + -0.9501160979, 0.2249486148, -0.6229797602, -0.9222994447, -0.8020499349, -0.121800445, -0.1192131341, 0.1981703192, + 0.2027932554, -0.5831612349, -1.5477751493, -0.6242799163, -1.9537978172, -1.3120753765, -0.8792384267, -0.2546037138, + 1.8232898712, 1.9963171482, 0.4631770551, -0.2157828957, -0.003303682, 0.9925291538, -0.6906385422, 0.6020773053, + 1.8886865377, -1.2071678638, 0.0356135145, 1.9553414583, 0.7453075647, -0.5721513033, 0.3352523446, -0.8478366137, + -0.7228087187, 0.8866829276, -0.9401163459, -1.9854770899, 1.0203789473, -0.4592664838, -0.5595240593, 0.4180965722, + -0.1041441485, -1.3117289543, -1.1925373077, -1.3618315458, -0.2454625666, -1.3739359379, -0.1230784133, 1.3046419621, + -0.371345073, -0.1312476695, 0.7927514315, -0.8698234558, -0.1680863947, -0.6188244224, 0.3212174177, 1.1077984571, + -0.8575962782, -1.29112041, -0.1478271186, 0.8769837022, -0.4112337232, 1.2420055866, -0.2285336703, 1.3366562128, + -1.6899101734, 0.2851883173, -0.9931355119, -0.2546955347, -0.7716149092, 1.0934343338, 0.0426416881, 1.5614147186, + -1.0928755999, -1.6933665276, -0.4665859342, 1.6828256845, -2.1104826927, -0.0419604629, -2.0320513248, 1.1672431231, + -1.066367507, 0.4055701494, 2.9667816162, 0.3135769367, -0.1272612065, -0.0019367305, -1.7865858078, -0.7973675132, + 0.0983067825, -0.7250729799, -0.1266469806, 0.0654597431, 1.6557376385, 0.1442626268, -1.7148323059, -0.7256135941, + 0.2546228766, 0.9104588032, 0.4652565122, 1.3994613886, -0.7664901614, 0.1988223642, -0.6781148314, -2.5610532761, + -1.2301489115, 0.5389909148, 0.4202900231, -0.157492891, 0.714825213, 0.0710679144, -1.8049743176, 0.0158903282, + 1.6363402605, 0.1195532903, 1.5923948288, -1.0496184826, 0.0179251097, -0.7340781093, -0.0044836081, 0.2723886967, + -0.1416033208, 0.171603024, -0.4047521949, 0.2403499484, 1.2817729712, 0.328817606, -1.0603730679, 2.0009100437, + 0.3797760308, 2.0110740662, -0.2068622559, 0.7860251069, -0.5047575235, 0.7063904405, -1.1786493063, 0.3923666775, + -1.0244634151, 1.8500113487, 0.5193219185, -0.9555152655, 1.336432457, 1.4916113615, -0.5875380635, -0.2249176949, + 0.5363004804, -0.4077191949, 1.2315989733, -0.0209633969, -0.753888011, -0.4608057439, 0.1677348167, 0.6560636759, + -1.0530261993, -1.1236027479, 0.5489697456, 1.1629155874, 1.019634366, -0.0328121632, -0.7612766027, -0.3375090957, + -0.0431881398, -1.3949629068, 1.6447660923, 0.6821311712, -0.2217063755, 0.7762494683, -0.171598047, 1.7823339701, + -0.4120734036, 0.3940093219, 0.4754644036, 0.0328231864, 1.2554707527, -0.5431787372, 1.2304182053, -0.8765879869, + 0.9375509024, 1.1339820623, -0.3679790795, 0.9494005442, 0.9975679517, 1.0307329893, 2.1102905273, 0.7695582509, + 0.5826106071, 0.3467871845, 0.0634680912, 0.7141479254, 0.2264734805, 2.0048527718, -1.0984022617, 1.231752038, + -0.8595981598, -1.2654389143, -0.6585014462, -1.2234858274, 0.885256052, -0.4570990801, -0.5080608726, 0.1632690579, + 1.0896167755, 0.3817169368, -0.025935486, -0.4530935287, 0.2448261827, -0.024954211, -0.5475708842, 0.8203950524, + -0.0454053171, -0.1523360014, 0.1439412832, -0.6669614315, -0.2771725059, 0.3978259265, -0.4932720065, -0.9815487266, + 0.0112280538, 0.0622864105, 0.1676025093, -0.3985056281, -0.7404897213, 0.8559097052, -0.8888737559, -0.3696354628, + 0.7236633301, -0.8088818192, 0.1112069711, 0.8000018001, -0.282810986, -1.3591109514, 0.0597446077, 1.1427609921, + 0.9351323247, -0.5741488338, 0.8525617719, 0.3621784449, 1.7871932983, -0.1630001217, -0.4958277643, 0.3296086788, + 0.1071355641, -1.2501461506, 0.2655957639, 0.99552387, 0.3480997086, 0.5811783075, -2.4376964569, -1.1687315702, + -0.081340678, -0.5605207086, 0.8873816133, -0.6016888618, 0.6948810816, 0.3314882815, -3.5329918861, -1.4900625944, + 0.9414265752, -0.0608544908, -0.2282129824, 0.2961200774, 0.2064784765, 0.9235963821, 0.8165992498, 1.0421718359, + 0.6450840831, 0.3433330655, 0.4462094009, -1.2916414738, 0.2994377315, -0.678319037, -1.4601011276, 1.0403785706, + -0.2990740836, -1.3489027023, 0.4652444422, -1.8370354176, -0.8784723282, 0.9383602738, -0.9043878317, -1.5784652233, + 1.0723438263, 0.2476393133, -0.8018630743, -0.4048002362, -0.0732393563, 0.9851552844, -0.7021204829, 0.6982021928, + -0.6263809204, 0.7441608906, -1.228484273, -0.0449464247, -0.6855147481, -1.4545799494, 2.1253712177, 0.6591351628, + 1.0927282572, 1.2526097298, -0.6281160712, 0.4327580929, 1.6550632715, -2.2945992947, -0.0502533279, 1.5303075314, + -0.5409997702, 1.1727341413, -0.5400050879, -0.4364598989, -0.0967092067, -0.4712429643, -0.674793303, 0.5726812482, + 1.1124210358, -0.0922250971, -1.5018668175, -1.0531485081, 0.0086183911, -0.0545431152, -1.5454921722, -1.6756819487, + 1.5852866173, 0.0307595395, 1.1762250662, 2.2206773758, -1.2185657024, 0.514934361, 0.9203640819, 0.5588316321, + -0.0089860512, -1.4906351566, -1.3091335297, -1.5451923609, 0.4636520147, -0.8842917085, 0.2086382061, -1.3636584282, + -0.5502992868, -0.3902366161, -0.5923804045, -1.5842198133, -0.0137870312, 0.0795252994, 1.902962327, -1.1827250719, + 0.2084009647, 0.1835195422, 0.4632900953, 0.3212157488, 1.2559412718, -0.1729954481, -1.1393396854, 0.4833806455, + 2.6549761295, -0.0624392033, 0.2982380688, -1.1094950438, -0.4198685288, 0.0068994844, 0.3850246668, -0.5606642962, + 0.3175287545, -0.3674174547, 0.4738435745, -0.5514103174, -0.9766073227, 0.5305664539, -1.0486661196, 0.2787618637, + -0.8301656246, -0.1464786083, 0.4386092722, 1.008072257, 0.1367931962, 0.6738983989, 0.3898560107, 2.6003527641, + 0.8472453356, 0.8475563526, 0.4127884507, 1.4216381311, 0.4300921261, 0.4178426266, -1.4710381031, 0.2721470594, + 0.842400372, -0.2040570527, -0.8711925745, 0.6280260086, 0.2913725376, 0.5029097199, -0.7581620216, 0.1996175051, + -0.8232809901, 1.2004920244, 0.5533089042, -0.8662698269, 1.6752365828, 0.5223246217, -0.0690548792, -1.2152057886, + -0.0013798352, -0.4171872437, 1.5942960978, -1.9580565691, 0.9489240646, -0.5740866065, 0.211129114, 0.9112172127, + -0.2032184899, -0.8871902823, -0.3309149742, -0.7680382133, -0.235990569, -0.9237763286, -0.0109956544, -1.9898606539, + 2.5647330284, -0.6217227578, 0.006421735, -0.1358610094, -1.1649965048, 0.6981079578, -0.5372963548, -0.1233563721, + 0.2467169762, 1.5969997644, 1.508859992, 0.895187676, 0.3103065491, -0.2586609125, -0.0645775348, 1.147810936, + 0.7551135421, -1.5989308357, -1.0639597178, 0.8607670069, -0.9049039483, 1.0084027052, -1.0110167265, 1.8463071585, + -0.7842986584, -1.8329027891, 1.6607512236, -0.1428315938, 0.1744260192, 2.4861826897, -0.1852011085, -0.3658530414, + -1.5189673901, -0.8197247386, -1.4171614647, -0.7043625116, -0.0423857495, 1.9210053682, -0.2739804387, -1.6898438931, + -0.2022707313, 0.5238206387, -1.7040828466, -0.6559479237, -0.2088008374, -0.454674989, 0.6832018495, -0.1399490386, + -0.0158994384, 1.2031900883, -2.3218762875, -0.8002865911, 0.1409174502, -0.8941115737, 0.1592972279, -0.7806494236, + -2.2411077023, -0.6832921505, -0.2099120617, 0.2427671105, 0.5994983912, 1.7587484121, -0.4734762311, 0.9576066732, + 1.0439326763, 0.3215130866, 1.1165105104, -1.1664500237, -0.2707373798, 0.8627887964, -0.5434683561, 0.4097805321, + 0.8309146166, -1.2992010117, 0.805144608, -0.0502262339, 1.2870852947, -0.0100108348, 2.0543682575, 0.3049731255, + 1.5535672903, 1.2411839962, 0.9481426477, -0.8539407849, 1.0286288261, 0.0647694692, 1.0538676977, 0.1396375895, + 0.6957244277, 0.2910648584, -0.9009956121, 1.1273261309, -0.0948203057, -0.8096640706, -0.4723818004, -0.6017938852, + -1.5425246954, -1.3817493916, 0.0491434112, 1.0174921751, 0.2119679451, 0.1593198776, 0.2184775919, 0.0306259133, + -0.053840477, -0.8706930876, -0.2231848836, 2.4912929535, -0.5015062094, 1.0344709158, 0.2444898188, 1.4917860031, + -0.6608645916, -1.4219645262, -0.2831400335, -1.3320243359, 1.7224861383, 1.07934165, -2.1341109276, 1.2406805754, + -0.7852844596, 0.0782570988, 0.6343486905, -1.2520850897, 0.7410355806, -0.6997129321, 0.1451499909, -0.1370168477, + 0.9041714072, -0.1804198623, 0.0712918416, -1.4128985405, 0.751036644, -0.1180425957, -0.1724923551, -1.7639014721, + -0.0395201556, 0.7621546388, -0.522166431, 0.7228161693, -0.1106093898, 0.4198686481, 0.8827266097, 0.1813685149, + -0.6062692404, 1.4166896343, -1.0538520813, -1.7832826376, 0.1536631137, 0.7696893811, 1.4886592627, 0.2027274966, + -0.329967171, -2.1470396519, 0.1910541207, 1.2473070621, -0.6160305738, 0.9013956189, -1.1003696918, 0.0428022183, + -0.22400029, 1.3721675873, 0.2639842331, 0.9908525348, -0.6108818054, 0.6185465455, 0.8091144562, -0.0958564207, + -2.4742417336, -1.4627320766, 1.2571899891, 2.1967086792, -0.6468477249, 0.4778275192, 0.4487043321, 0.8870905638, + -0.5353265405, 0.8139606714, -0.9202001095, -0.9111188054, -0.4403496683, -1.0960507393, -0.7820392251, 0.3184137642, + -0.8955340981, 1.3307368755, 2.578925848, 1.6368669271, -0.1470758021, -0.5990946293, 1.8969904184, 0.0959065408, + 0.3653283119, -0.8044139743, -0.1963423491, 0.6994704604, 0.971632123, -2.4430494308, -0.0891370699, 1.6713135242, + -0.0061685285, 1.3528705835, -0.7780772448, -1.252560854, 0.5983073115, 0.7732192874, -0.6087434292, 0.9746813774, + -1.3182982206, -0.8068457842, -0.0047311722, 1.7748740911, -0.6146159172, 0.484575361, 0.6594731808, -1.1879068613, + -0.3992961049, 0.6266974211, 0.4242372215, 0.9081152678, 0.0307728127, -0.863060534, 1.9725608826, 0.960524559, + 0.525945127, 0.1010104865, 0.9442236423, -0.9346194267, -0.314132899, 1.5740138292, 0.8825586438, 1.2932610512, + -2.2646677494, -0.8570740223, 2.5405399799, -0.907728374, -0.0705576167, 1.1092141867, 1.1942255497, 0.1073936, + -0.7081599832, -0.1220684573, -0.1524242908, 2.7508671284, 1.3673774004, 0.2572293878, -0.7890204787, -1.9807367325, + -0.0600517057, -0.3794493377, -0.2172252089, -0.1736208946, 0.4301603138, 1.161413312, 1.8514386415, 1.1475257874, + 0.440248698, 1.6443941593, 0.866009593, -1.0846067667, -0.7280923724, -0.7247751355, 1.1563705206, -0.6895301938, + -0.2457161993, 0.6665600538, -0.1587394476, -0.9480696321, 0.6335174441, -0.8753589392, -0.3239900768, -0.4539276361, + -1.1788517237, -0.0075284201, -0.3648636639, 0.7042046785, -0.8619546294, -0.8080089092, -1.4834641218, -0.5682203174, + 0.064054586, -1.3926751614, -0.4957585931, -0.9867656231, 2.2077383995, 0.8689068556, -0.1288353801, -0.2259429991, + -0.3784595132, -0.1942718327, -0.4684728384, 1.3292363882, -0.5330204368, 0.9046695828, 1.682125926, 0.0649134219, + 0.9101820588, -0.6161113381, 0.5321943164, 0.1378296018, -0.7966747284, -0.3984784782, -0.7223089933, 0.1889540851, + -0.3044525981, -0.559907496, 0.2821009755, -1.0995750427, -1.1855823994, 0.140625596, 0.1761286408, -1.1918876171, + 1.7644279003, 0.8393975496, -0.1007546857, -1.5601830482, -0.2472936213, -0.6002095938, -0.5832691193, 0.5630375743, + -0.2304146737, -0.5821666121, -0.8668646812, 0.1507098377, -0.8167546988, -0.7604181767, -1.3662077188, -1.539408803, + -1.5751433372, -0.4525258243, -0.381041199, -0.2660856843, -0.7493767738, -0.8499608636, -0.3706573248, 0.0562004596, + -0.0263963435, -0.0762054101, 0.0347596668, -1.7043470144, -0.3087723255, 0.0925105289, 0.3055296242, -0.603808701, + -1.3270583153, 0.9827371836, 0.2591477334, -0.5748916268, 0.2182596624, 3.132065773, -0.1381565481, -0.7192556262, + -0.0967331678, -1.2724033594, 0.1888975799, 0.9075344205, 0.4408209026, -0.56383425, -2.3636741638, 1.3404798508, + -0.49567312, -0.1394995302, -0.5335831642, -1.9022147655, 0.7844576836, -1.7396374941, -1.0470457077, 0.0059125903, + 1.1089094877, -0.9378197789, 1.2084882259, 0.641561985, 1.1708856821, 0.9288407564, -0.4969819784, -1.6088763475, + -0.2479011863, 0.3180273175, -1.4168658257, 1.8286755085, 0.1195928678, 0.7719916105, -0.7462855577, 0.1041880324, + -0.967258215, -2.6459031105, -0.1165833101, -3.1117084026, 1.9623993635, 0.8309456706, 0.1377648413, -2.3812682629, + 0.689688623, -0.1855984628, 0.3543067873, 0.9753615856, -0.6475732327, -0.8925844431, -1.0086665154, 0.0782525837, + -0.6183305979, 0.6852272153, 0.1687427461, -0.8541080356, -0.2065338194, 0.408804208, 1.0348843336, -1.8947924376, + 0.0465237722, -0.457000494, -1.2192322016, 0.8203142881, 0.3576781452, -0.2713727951, -0.068323575, 0.243260473, + 1.3800150156, 1.1533381939, -0.929712832, 0.526130259, 0.9035075307, -1.2131354809, 0.2522619963, -1.5607283115, + 0.7069227099, -1.2718977928, 0.5051910281, -1.1626993418, -0.0957609937, 1.2475578785, 0.4460627437, 1.6918580532, + -0.3250173628, 0.6188752055, 0.3587437868, 1.6347857714, -0.5673042536, -0.6678325534, -1.512678504, -2.084353447, + 0.931620717, -0.7939562201, -0.1389047503, -1.0928068161, 1.322553277, -1.9624245167, -0.5996420979, -1.21978724, + -0.9119546413, 0.4276641309, 0.0259381942, -0.4532708824, -1.7074309587, -0.8331914544, 0.7614836693, 0.0791674033, + -0.6992869973, -0.8943839669, -0.2679222226, 0.2194266021, -0.8759810328, -0.5073649287, -1.5110708475, 2.2356791496, + -1.3427168131, 1.5245552063, -0.3868552744, 0.1256234497, -0.1761559248, 1.0805300474, 2.1072673798, 0.9131340384, + -0.5150635839, -0.5568994284, 0.1934793591, 0.2294926941, 0.0569185466, -1.5624272823, -0.3017155826, -1.1742011309, + 1.6733289957, 0.3321471512, -2.5649945736, -1.0484580994, 1.5249539614, 0.6937811971, -1.4968557358, -0.0413185954, + 0.0577384606, -1.482788682, 0.6641077399, -0.4808337986, -0.5935848355, 1.5506532192, 0.2863505781, 0.3010305166, + 0.7863500118, 1.0970948935, 1.0758353472, -0.6738184094, 0.3312270939, -0.4622066617, 1.8852907419, 0.0494275317, + 0.6119221449, -0.9082134962, -0.2488493621, 1.5805485249, 0.5710447431, -0.0100161182, 1.043441534, 2.6215713024, + 0.6912501454, 0.049708765, 0.8760806322, -0.3577581644, 1.4436415434, 0.0282163415, -0.4429470897, 0.0530390367, + 0.0762220472, 1.1364022493, -1.6470911503, 0.6877381206, 0.8901814222, 0.7812303305, 1.3263591528, 0.0477996878, + 2.5010333061, -2.1394217014, -1.9078707695, 1.3412349224, 0.4777317047, -0.0139821116, -0.1222880036, -1.0256145, + -0.3868508935, 0.4203441143, -1.087300539, -1.221771121, -0.5821444392, -0.8056239486, -1.0757553577, -0.1141380593, + 0.7272791266, 0.2058192939, 0.0688363239, -0.2044557482, -1.1473109722, 0.4968492687, -1.4591329098, 0.1536498815, + 0.5128298402, 1.3853830099, 0.3292523623, -1.7917298079, -1.6369482279, 0.8037596941, -0.3507469296, -0.9165260196, + 0.6277545094, -1.8771381378, -1.1168591976, 2.0002963543, 0.9762254953, -0.2480376661, -0.530287087, 1.9402929544, + 0.0267861206, -1.350504756, 1.7754563093, 0.7663806081, -1.2515767813, -0.4576311707, -1.6291935444, -0.0677957162, + 0.6024122238, -0.9290607572, -1.2449533939, 0.611321032, -0.1610737294, 0.037198469, -0.2587880194, 0.6847470403, + 0.3342157006, 1.4733811617, 0.6087473631, 1.1020613909, -2.3822624683, 0.6188970208, -0.6561591625, 0.2269476801, + 0.2247478813, 0.12878865, 1.0781495571, -1.5613390207, 0.2265433371, -0.3973863423, 0.8339469433, -0.6040529013, + 1.7165282965, 0.7048300505, 1.7899045944, 0.2359161973, 1.1899683475, 0.9303969741, -0.552811563, 0.8526928425, + 0.4013674855, 0.0542528853, -0.9132806659, 0.2976969779, -0.4440785944, 0.8972502947, 0.8655430675, 1.171574831, + -0.1977638453, -0.2246027142, 0.0634627566, -0.1137804464, -0.7993347645, -1.0984220505, -0.6201526523, 1.0808788538, + -1.2932568789, 1.0611051321, 0.5813468099, 0.4603781402, 0.5116732717, -0.1236280203, -0.3366009891, 2.3701324463, + -0.2713805735, -0.9819604158, 2.4698693752, -2.2890300751, 1.6352475882, 2.1706984043, 1.7595663071, 1.3014839888, + -0.3608497679, 1.2908350229, 0.0412799045, 1.0770276785, -0.8863621354, 1.3306670189, 0.6597825289, 0.4063103199, + 0.0115959998, 1.3941509724, -0.8768700957, 1.202483058, -0.2052872479, -0.3123206198, -0.106771484, 0.6414546371, + 0.4451971352, 0.8133208752, 0.4083485901, 0.7939832807, -0.425175488, 0.4888560474, -1.1338469982, 0.3686774671, + -1.5876305103, -1.1317766905, 0.3729013801, -0.0210948307, 0.1209617406, -2.4760849476, 1.0929088593, -0.2816660404, + 1.1428662539, 0.4579641521, 2.0584762096, -0.6132389307, 0.2567722499, 0.0170761682, 1.2307608128, 1.3749313354, + 0.8315657973, -0.40263924, 2.3707995415, -1.1325217485, -0.7696317434, 0.9405528307, -0.4137949049, -0.1175819635, + 0.7805142403, 1.8320804834, 0.3148280978, 0.3389058113, 0.4954504073, -0.0342098735, 1.2256599665, 0.6079592109, + -0.3224415183, -1.547088027, -1.8527430296, 0.7457096577, 0.0043871086, -0.3397135139, 0.6516956687, 0.8055987954, + -0.2371622622, -0.1931099892, 1.1936423779, 0.1004671603, 1.0995388031, -0.2976596951, -0.1392439753, 0.5259703994, + -1.7792139053, 0.7952412963, -0.2315692008, -1.1396455765, -3.1083474159, 0.2638598979, 0.1089628115, -0.7766565681, + -1.1014711857, -0.1453552842, -1.4054925442, -0.0237163752, 0.219532609, 0.5424352884, 0.8379007578, -0.216646269, + 0.2039635777, 0.6850985885, -0.2847076654, 0.7809556127, -0.308679074, -0.3514919281, 0.9503691196, -1.7364805937, + -1.2029470205, -0.1090737283, 2.3331315517, -0.7135651708, 0.2003588378, 0.1698276401, -0.8578826785, -1.7039403915, + -0.1923047006, -0.6373355985, 1.4842764139, 0.8991172314, 2.2821702957, 0.2180647701, -2.0747385025, -1.3818309307, + 1.2608627081, -0.5096740723, -1.3451678753, 1.1649746895, 1.5543422699, 0.647057116, 1.7453366518, -1.4800138474, + -0.8186712861, -0.6925798059, 0.3354967237, 0.0370089076, -0.0598824024, -1.0103763342, 0.2989828289, -1.28455019, + 0.1014768258, -0.5032425523, 0.8546702862, 0.4338257015, -0.5709214211, -1.6417970657, 0.2938322723, 0.7571172118, + -1.231605649, 0.5295363069, -0.3947353959, -0.5521669388, 0.8162702918, 0.0821020678, 0.5902984738, -0.0606680997, + -0.9304512739, -0.4575162828, -0.552828908, -1.0609980822, 0.1770114452, -0.7643995881, -1.8346927166, -0.3263114691, + -0.7260974646, -0.2625757158, 0.242162019, 0.8234714866, -0.3505697548, -0.1155276671, 2.2433609962, -0.6450213194, + 0.5869686007, 0.1855111122, -1.3059544563, -0.0481009148, -0.5584850907, 0.9967713356, -0.1201881021, -0.0914791599, + -0.616040349, -0.5912835598, 0.5793107748, 0.8839061856, -0.6082174778, -0.1807097793, 0.0818651319, -0.3470787704, + 1.5814223289, 0.3732798398, 0.0022905916, -1.1152783632, -0.8789777756, 0.3264580667, -0.0843966827, 2.0768249035, + 0.322358638, -1.4704591036, -0.3605157733, -0.0795432106, 1.3762940168, -0.3133580089, -0.3769643009, 1.0150228739, + -1.6130084991, 0.7662905455, 0.1537739336, -0.5736240745, -2.0595908165, -1.2742669582, -0.4551030099, 1.183103919, + 1.2629544735, -0.8028033376, -0.6116998196, 0.2680445313, 2.1303925514, 0.6933071613, 0.8110494614, 1.6245647669, + 0.0246582367, 0.1792008579, -0.6756305099, -0.2165194303, -1.7439608574, -1.0947178602, -0.5515912175, 1.1397629976, + -0.1814203858, -1.0873012543, 1.9065188169, 0.4820602238, 1.2316817045, -0.7144633532, 0.7393344641, -1.4779632092, + 0.8479858041, -0.6084827185, -1.4399133921, -1.2956974506, 0.291316241, -0.948726356, -2.4500293732, 1.2459511757, + -0.8626870513, 1.2747393847, 0.8515521288, -0.9107000828, -0.0041014827, -1.07412076, 0.1243414879, -1.6088092327, + 0.325825274, -0.5649567246, 0.2144881934, 0.1281290799, 1.3411060572, 1.1804949045, 0.6733310819, 1.5220293999, + 1.1019228697, -0.6039502025, 0.4356611669, -0.4059346914, -0.6738638878, -0.2382538617, -0.3904451728, -0.9828028679, + 1.2583773136, 1.6638858318, 0.0410357155, -1.3966635466, 0.1359305084, 0.0167859215, 0.6521763206, -0.2972988784, + 0.1731460541, 0.141123116, 1.0567188263, 1.6228011847, -0.579441905, 0.4272536039, -1.5739947557, -0.8606178761, + 1.0731964111, 0.1164292842, 1.1253268719, 1.0621339083, 1.8113048077, -0.2671763003, 0.648679018, 0.6535865068, + 2.1206243038, 0.3569327295, -0.3855935633, 2.1172261238, -1.2179837227, -0.3329633772, 1.1804958582, 0.4870519936, + -0.0225906167, -0.1032814756, 0.2909719646, 1.6734399796, 0.6995837688, 1.6279866695, -0.9171071053, -0.4649128914, + -0.7849975228, 0.1026836857, 1.7261559963, 1.4697047472, -0.9684790373, 0.0554991364, -1.7402436733, -0.2492827326, + -0.0431437008, -1.3587737083, 0.6815609932, -0.8693833351, 1.2369399071, -1.8863832951, -0.2015711665, 0.5212758183, + -0.8070146441, 0.6563775539, -0.6166521311, 1.0231083632, 1.2899951935, 0.6691089869, 0.5692141056, 1.3590040207, + -1.2761324644, 0.2012262344, 0.1072357595, 0.075214006, -0.5331254601, 0.2735618353, 1.3830242157, 0.4706042409, + -1.1795712709, -0.3537247181, -0.5190734863, -1.1926151514, 0.1233324781, 0.3509021699, -0.5091461539, -0.0536347479, + 0.5855531096, 0.5949400067, 0.2779593468, 1.2884949446, -0.9481160641, -0.4234532714, -1.1077837944, 1.2787302732, + 2.0269575119, 1.4635083675, -0.9697679877, 2.623547554, 1.2805155516, -0.1222272217, 0.3515428901, 1.001652956, + -0.0150964251, 1.6880726814, -0.2948833406, -2.3703005314, 1.8436559439, -1.2131029367, -0.2624935508, 0.943379581, + 1.8394038677, -0.8153470159, -0.9672814608, -0.2367526293, 1.2682460546, -1.8260550499, -0.6101045012, -0.8524032831, + 2.48741436, 0.6338421106, 0.7834047079, 0.626213491, 0.8847147226, -1.1235461235, -0.9794437885, 0.3526352048, + 0.4729247093, -0.2141827941, -0.7229529023, 0.0829834938, 1.3534119129, -0.4975259006, 1.0918790102, 0.5944721699, + -1.4659571648, 0.8361387849, -0.3421808183, -1.0087279081, -1.2426744699, 0.3281867206, 0.0251218807, -1.868596077, + 0.9150018096, -1.9452970028, -0.8615595698, 2.1733384132, -0.9754824638, 1.6710414886, 0.4690485597, 0.8657920957, + -0.4328330755, 1.2893782854, -1.0481760502, 1.3680763245, -1.3068273067, 0.9040389657, 0.9369824529, 0.8598939776, + -0.822717011, -0.3654539287, -0.6739743948, 0.319060266, -0.9016777277, -0.4370117188, 1.0818015337, -0.7992702127, + -0.8296168447, 0.5022249818, 0.341213733, -0.3512504399, -0.3503727615, -1.8021380901, 2.280469656, -1.1720472574, + 0.226327166, 0.2877822518, -1.1337782145, -0.3909066916, -1.2376701832, 1.009529829, 0.5217128992, -2.2821540833, + 0.5881370306, -0.2536352277, -2.5339996815, 0.0288899709, 0.1474454105, -1.5530334711, -0.187556088, -0.2964601815, + -0.1737500578, 1.6984698772, 0.9925410748, -0.18349123, 0.0390073396, 1.2886043787, 1.189961195, 1.674741745, + -0.0493365452, 0.6665617228, -0.3943178952, 0.4373920858, 1.0100117922, -0.2434471995, 0.4705701172, -0.0913033038, + -0.1496414989, -0.1203377172, -0.924895227, 3.0170164108, -0.2714706659, 0.4221477807, 2.1623134613, 0.874534905, + 1.3869328499, 0.716003716, 0.8574240804, -2.4605793953, 1.4067883492, 0.7826843858, 0.0132020181, 0.9728497267, + -1.4302023649, -1.5503321886, 0.7042499185, -0.0613900833, 0.6003428102, 0.6352524161, 0.4287099242, 1.4980370998, + 0.3880011737, -0.4563947618, -2.7111141682, -0.4926683903, -0.6083946824, 0.9790099859, 1.3553739786, 1.1713775396, + 0.4362692833, -0.8042359352, -0.7024526, 0.3011744618, -1.4273091555, 0.9567792416, 0.6883066297, 0.4607406855, + -0.5390653014, 0.6746558547, -0.8313179016, -1.0302064419, -0.0380053222, -1.8747175932, 1.3076663017, -0.2346269339, + -1.3506914377, -0.4520126581, -0.4520035982, 1.7138769627, 0.1253602654, 0.2660092711, -0.0731366202, 0.2919928432, + 0.0841064826, 1.7978950739, -0.3284988999, 1.1751443148, 0.5153539181, 0.2937392592, 0.7174130082, 0.499106288, + -0.1639733016, -0.3563329577, -0.4395076931, -0.2766478062, -1.0674500465, 1.8819682598, 0.7912315726, -0.1282933652, + 1.8472059965, -1.5106694698, 0.7845364809, 0.4449427724, -1.2240473032, 0.5322827697, -0.1730926335, 0.9488574266, + 0.4537747204, 0.0691529736, 3.4170293808, -0.9167636633, -0.3978354037, -0.5361738801, -0.4047685564, 0.7148522139, + 0.2225925773, 0.6639422774, -0.1292048544, -1.1110087633, -1.0102939606, 0.2644718587, 0.9000436068, -0.7264199257, + 1.363797307, -1.2778736353, -0.1999248862, 0.5343344212, -0.4080455005, 0.1374131441, -0.2867443264, 2.0778164864, + -0.9607052207, 0.9882478118, -0.3585515916, -1.4047431946, 0.9531259537, 0.208853811, 0.1369061917, 1.3903574944, + 0.4575279653, -1.3510797024, -0.4881621003, 0.7812165618, -0.4035978317, -1.0870518684, -1.5355210304, 1.029967308, + -0.0183984078, 0.1233158112, 0.265984863, -0.9376357794, -0.2414065301, -0.30263111, 0.0925273895, -0.0816137046, + -0.0960379541, -0.0317799374, -1.3813295364, 0.1347098649, -0.0820175707, -1.2389616966, 1.6740804911, -0.2374209315, + 0.9658219814, -0.7939558625, 1.2590600252, -1.5339493752, 0.3371162415, 1.4419755936, -0.4797958732, 0.0273850411, + 0.7507920861, -0.1079000458, 0.9697693586, -0.692587316, -1.4347451925, 0.3423879147, -0.6725934148, -1.7418110371, + -0.0797282755, -0.3020401299, -0.3803686202, 1.012589097, -0.9325743318, -0.1049213335, 0.0712086931, -0.2040427327, + -0.71098423, -0.7788132429, -0.4137320518, 0.5208038688, 0.129950285, -0.1351567805, -0.61292243, 0.0145029593, + 0.5655912757, -0.8317987919, 0.5818741918, 0.6020925641, 0.1391010433, 0.8798360825, -0.378537178, 0.8962466121, + -0.1627954245, -0.1554978937, -0.0491830073, 1.0199846029, -0.5086528063, 0.1819584221, -0.188606441, -0.5281379819, + 0.5540053844, 1.2801107168, 0.514561832, -0.2815166414, -1.8504830599, -1.496815443, 0.5677479506, -0.8508284688, + 0.467889905, -1.3412883282, -0.1465302259, 0.2389729619, -0.6580345631, 1.4656655788, -0.5119754076, 0.3634024858, + 0.8378620148, 0.682143867, -0.1599557549, 0.8418995738, -1.6232244968, 1.2753105164, -1.574437499, -0.3053387403, + -0.7655331492, 1.0510780811, 0.8004363179, 0.256003052, -0.6166889668, 0.0854177177, -1.9206666946, -0.5267802477, + -0.7869284749, -0.4115960598, -1.1991744041, -0.5750448108, 0.2946201861, -0.7443304062, 1.4293489456, -0.4902796745, + -0.0483880341, 0.6640558243, 0.8327726722, 1.8407005072, 0.7809294462, 0.0030927989, -1.5531117916, 0.9506762028, + -1.3810019493, 1.1338344812, 1.1597759724, 0.1388784498, 1.6293661594, 0.1739115119, 0.2015552223, 1.5030477047, + -0.4344612062, 1.8117796183, 2.225716114, 1.4357246161, 0.7157769799, -1.1085772514, 0.3848017156, -0.8877408504, + 0.5003702044, -0.8792350292, 0.423017025, 0.8809534311, 2.0490174294, 0.0204322394, -1.2171998024, 0.7011641264, + 0.5943517089, -1.5732725859, -0.719917357, 0.7867372036, 3.0451655388, 0.1843346208, 0.7179120183, -0.1636048704, + 1.5786978006, -0.7018404007, -0.4428640306, -0.0944580883, -0.4445796311, -0.9633267522, -1.416339159, 0.3170681596, + -0.8742064238, 0.0117640896, -0.9380337596, 0.4167654812, 1.0110545158, 0.8198906779, 1.4507848024, -0.4969290495, + 0.9055968523, -0.0989162475, 0.2817564011, 0.105491519, -0.2824602127, -2.7734065056, -1.1041206121, -0.9647773504, + 1.5364704132, 0.5445757508, 0.779150784, -0.0502580889, -0.9385029078, -0.9562464356, 0.5013201833, -1.3731353283, + 0.6837669611, 0.7879750133, 0.4322114587, -1.0507004261, -0.4315394759, 0.5607248545, -0.3958632052, 0.4185329974, + 1.0252966881, -1.0072593689, 0.8607437611, 0.4936594069, 0.7559320331, -1.0182080269, -0.1923506409, 0.5055880547, + -0.3494649231, 0.4047941864, -0.3316917419, 0.1759418398, 0.001305709, 1.2570570707, -0.2191038728, 0.9023769498, + 0.7408381104, 0.5125377774, 0.9699680209, -1.3627812862, -1.5679252148, -0.0293262303, -1.867888689, 2.1712396145, + -0.1571822166, -0.3564154208, 0.0553524904, 1.1599270105, 1.2627038956, -1.345942378, 0.6730185747, -0.0750857741, + 1.0460783243, -0.4429310262, -0.300150305, 0.007883979, -0.2567608058, 0.9423267841, -1.569760561, 0.6863792539, + 0.9789968133, -0.0081998017, 1.701934576, 0.2806222439, -1.4620214701, 0.5297275186, 1.1651798487, 0.8243795037, + 0.8680918813, -1.7472949028, 2.0696997643, -0.2578157783, -0.0249881465, 0.6565919518, 0.0272306334, -0.8412454724, + 0.2397221625, -1.7836779356, 1.220461607, 0.5548753738, -0.4932431579, 0.3310505152, 1.0874546766, -0.1795441955, + 0.9982895851, -0.2980313897, 2.0983877182, -0.7227540016, -0.2248633504, -0.1296203732, -0.949442327, 1.4522721767, + -0.9315572381, 1.8279565573, 0.1612818539, 0.2126344889, 0.6816353798, 1.1261162758, 0.9266378284, -0.3534713686, + 0.9973428845, 0.4953095913, 0.8687413335, 0.6141946316, 1.499601841, 0.1254296452, -0.7379559278, -1.2608875036, + 0.3750228584, -0.6231452227, 3.0864508152, 0.4766899645, -1.111789465, 0.2051137537, -1.7827329636, 2.1619787216, + 0.630366385, 0.5379341841, 2.342890501, 0.1024986655, -1.9776982069, -1.9109508991, 2.0136795044, 0.561409831, + -1.5266704559, 0.1959593594, 0.613363266, 1.1159074306, -0.5647493005, 0.4011000693, 1.7993389368, -0.0339073166, + -0.2392009497, 1.6570544243, 0.7138476968, 0.399107486, -0.8774254918, -0.4240868092, 1.0801563263, -0.1920657456, + 0.3216613829, 0.2953280807, -0.4288747013, 0.4682311714, -0.9422526956, -1.1518111229, 0.7867501378, -2.3118257523, + -0.9087553024, 1.6632435322, 1.0761674643, -0.2712795138, -0.8323598504, -2.2843811512, 0.220083043, 0.6697045565, + -0.9509277344, -0.8576626182, -1.9374886751, 0.8887458444, 0.5036352873, 2.0676424503, 1.0283118486, -0.2918054461, + -0.8564800024, 1.6496522427, -0.1889360398, -0.3224303722, -0.5871344805, -0.9989820719, -0.0417234078, 0.4708833098, + 0.8459716439, 0.3378955126, -1.3688849211, 1.9070968628, 0.6046031117, 2.032397747, -1.0468131304, 0.7598228455, + 0.1940415055, 1.2512792349, -0.3850702941, -0.1691117436, -0.8089761138, 0.8820098639, 0.2849083245, 1.297110796, + -1.0834826231, -0.1189776212, -1.1106203794, -1.3206923008, 0.7566649318, -1.9178347588, 2.7865297794, -0.5657482147, + 0.2699114084, 0.3090089858, 0.6460570097, -2.5136375427, -0.1902826726, -1.3483183384, -0.7845107317, 0.8349735141, + 0.8349094987, -0.9854658246, 0.1150932983, -0.3015092909, 0.43049559, -2.6301472187, -2.376023531, 0.2100565583, + -1.6220120192, -0.6598060131, 0.0390680023, 0.9663178325, -0.0312575251, 0.3434973955, -0.5051045418, 0.2603479624, + -1.6800607443, -2.0438206196, -0.7828196287, 0.8378771544, -1.0073713064, 0.3594104946, -1.0887169838, -0.285422951, + -0.6326141953, -0.7492433786, 0.1771231443, -2.0925412178, 0.7221005559, 1.0629680157, 0.8875825405, 0.9514683485, + 1.1898092031, -1.3159422874, 0.3789256513, 0.0052759089, 0.6215171218, -0.1703885645, -0.8301671743, -1.4931890965, + 2.1389789581, 0.0210836176, 0.0997546017, 0.3395195603, 1.5730198622, -2.4545269012, 1.4472402334, 1.2666022778, + 0.2692795396, 0.730927825, -1.1675630808, 0.1287209988, -0.2159086317, 1.9478616714, 0.6417044997, 0.4954462051, + 0.291803658, 1.104440093, -0.0565379076, 1.2288534641, 0.9528832436, 0.0863463283, 0.5586382151, 2.1897523403, + 0.1289473176, -0.8775374293, 0.5111732483, 0.6179109216, -1.8111522198, 0.0995398909, 1.3215231895, -1.1074717045, + -0.8939023018, 0.2247423381, -1.0083754063, 0.8858939409, -0.2505567372, -0.3213457167, 0.8018403649, 0.2690301239, + -0.5970544815, -0.9925628901, -0.549434185, 0.1522569507, 0.156330809, 0.6602344513, -0.0799589828, 0.8824433684, + 1.1563723087, -0.394353658, -0.8907910585, 1.6997411251, -1.1539968252, 0.2835911512, -0.9666313529, -0.9075029492, + -0.3648546338, -1.1380269527, -1.6632107496, 0.0931004658, 1.554848671, 0.6206492782, 0.0812515914, 0.504554987, + -0.0324226506, 0.957678318, 0.6753861904, 0.0415677503, -0.8783605695, -0.5465931296, -0.5524756312, 0.413133502, + -0.621612668, 0.9888315797, -0.3318295181, 3.0655612946, 1.0167248249, 0.0809800029, 1.0825935602, 2.0115580559, + 0.3990780115, -0.1417630613, -0.7643346786, 0.9107628465, -1.2469594479, 0.2185842395, -0.5608953238, 0.7581259012, + -0.578099072, -0.3210789263, -0.1193744466, -0.6779866219, -0.5087441802, -0.142415598, 1.1234807968, 0.1186617762, + -0.0176850781, 2.0666704178, 1.0098127127, 1.3752470016, -1.2679327726, -1.1970074177, -1.0551103354, 1.1164258718, + 0.37212345, -0.9255678058, -0.9442209005, 0.4268756509, 0.3172981739, -0.3741634488, -1.4125268459, -2.3680481911, + -0.1069736257, -0.4030350745, -0.4043666124, 0.1732717007, 0.4453865588, 0.083540827, -0.3626154065, 0.2124658823, + 0.7893753648, 0.802690506, -1.3991522789, -0.32001248, 0.9662565589, -0.9130623341, 0.4093767703, -2.2999207973, + -0.2824724913, 0.8781957626, 0.0921964645, 2.3364260197, -0.3582146466, -0.290328145, -1.2173844576, -0.5441349149, + -0.8577818274, 0.6779240966, 0.0227339007, 0.9655373096, -0.2647223771, -1.9813855886, -0.5777205229, -1.6076692343, + 0.3734553158, -0.2309042215, -0.0047361567, -0.1747259945, 1.4980055094, 2.3268282413, 0.0851788521, -0.3865151405, + 0.685734272, -1.9992141724, -0.5850980878, -0.8566595912, 0.5763618946, -0.4204704463, -1.0309052467, -0.3967194259, + 1.0643119812, -1.3884699345, -0.2525475919, 0.0347681716, -0.4270209372, 1.8029408455, -1.7515459061, 0.0540627949, + 1.4515020847, 2.2537171841, 0.7252607942, -0.3768343031, -0.421364516, 0.3329466283, 0.4443221986, -0.1684675515, + -0.5755594373, 0.6468083262, 0.6131626964, 1.2769823074, -0.3528927565, -0.2351228446, -1.2301682234, 0.4037817121, + -1.367872715, -1.0195753574, -1.1714248657, 0.4959396422, 0.7116174698, 0.340147227, -0.5646832585, 1.3907834291, + 0.2785235345, -0.8563492298, 0.3405274451, 1.1643620729, 1.2994824648, -2.8496544361, 0.0588610545, 1.9530397654, + 0.5605524778, -2.7157382965, 0.9060288072, -0.6560640931, 0.4947168231, 1.2521569729, 0.7251318097, 0.4450671673, + 0.1428324431, 0.5182865262, -2.0029828548, 0.4784449339, -0.3109569848, 1.4094113111, -0.4395599067, 0.0288746692, + 0.532702744, 0.9105619788, 0.711887002, 0.0834584162, 0.6378134489, 0.4777068794, 0.6714622378, -0.2473972887, + 0.9334355593, -0.0149712618, -1.2888498306, 0.3178930879, 0.3878506124, -0.4473615289, -0.020019237, -1.1375455856, + 0.2947454154, -1.6181722879, -1.4102656841, 0.6471197009, 0.0660516992, 2.5253288746, -1.4385683537, 1.1881508827, + -0.5137376189, -0.3100413084, 1.8618991375, 0.2196703702, 0.876473546, -1.6034924984, 0.960868597, 0.7578120828, + 0.1340373456, -1.2120584249, -1.081195116, -0.5332429409, -1.2666810751, 1.1997977495, -0.0147280395, -0.3411561847, + 0.0395528637, -1.0613685846, 0.8180955648, 1.3017721176, 0.8937417865, -0.7969278693, 1.0919103622, -0.6793391705, + 0.5171425939, 1.9261372089, -1.4655749798, -0.9694035649, -0.2225221097, -1.3643192053, -0.1500839889, 0.5843650103, + 0.7056804895, -1.0301253796, -1.0684210062, -1.0028663874, -1.5143984556, 0.0788298324, -1.7967107296, -0.3639734983, + -0.7513176203, 0.1762141883, 1.155023098, -0.4082490206, 0.9812905192, 0.4297397435, -1.0552676916, 0.4100736082, + 0.1593143344, -1.5990869999, 0.9750310779, -1.0146784782, -0.416033566, 1.6984248161, 1.1609507799, 0.7490220666, + -0.8482598662, -0.6165418625, -0.0323930122, 1.6698666811, 0.1386055946, -1.1053417921, 0.2234233469, -0.0349204689, + 0.5528994203, 0.7125429511, 0.0064929891, -1.0954294205, -0.4205610752, 0.8501464128, 1.0036913157, -1.4143588543, + 0.4902287722, -0.0818249434, 0.1800193787, 3.1680388451, -3.1549611092, -1.7138682604, -0.3571625054, 1.7889220715, + -1.300593853, -1.1199634075, 1.1873326302, -0.3849809766, -1.2680217028, 1.4615029097, -0.619169414, -0.2495485842, + 0.2082553059, 0.1791836023, 0.3728811145, 2.1315107346, 1.3774552345, -1.4320223331, -0.3597615361, -0.1586332172, + 1.0218647718, -1.1757861376, 0.7682100534, -0.3420245349, 0.7694000602, -0.1330372542, 1.1873819828, -0.3006245792, + 0.7143628597, -0.2423644811, -1.5537725687, 0.3462584019, 0.4230340719, 1.0040265322, 1.0997759104, 0.7828722596, + 0.4102944136, -1.109870553, -1.0867903233, 0.034697827, 1.1880047321, -0.5926411748, -0.5738988519, -0.4091166556, + -0.8370656371, 1.0624153614, -0.9222751856, -0.2183016688, 0.8524411917, -0.29833588, 1.0201835632, 0.5510687828, + -0.614343524, 0.0868408009, 0.6313892007, -0.6356560588, 0.937942028, -0.9612347484, 0.0437515527, 0.1527118981, + 0.0146253034, 0.1002622694, 1.37692976, 1.8511936665, -0.9757603407, -0.1710399836, -0.3755131066, 0.6657829881, + -1.4439826012, 0.8646513224, -0.5456988215, -0.3876164854, 1.1869660616, -1.09030056, 0.2324468642, 0.4489884079, + 0.2146653384, -0.3496420681, 0.2460367978, -0.3882636726, -3.5028512478, -0.8601097465, -0.3408805728, 1.043661356, + -0.1229604706, -1.1517763138, 0.6286780238, -0.5831050873, 0.2989288568, -0.8618805408, -1.0957497358, -1.658550024, + 0.4104961157, 0.3074675798, 1.788926959, 1.4891097546, -2.1270682812, -1.0630022287, -1.0487341881, 0.6423425674, + 0.222363174, -0.6816553473, 1.4914273024, 0.8645065427, 0.4738709927, 1.0744345188, -0.0626458526, -0.1355794221, + -0.5250419378, -0.5246269703, 2.2068521976, 0.8553270698, -0.0701120049, 0.0589456148, -1.384401083, 0.133604899, + 1.4933985472, -0.7632629871, 0.0417235643, 0.0002870396, -0.579652667, 0.8333060741, 1.2923172712, 2.185857296, + -0.3396995068, 0.5367954373, 0.9259405136, -0.2317183018, 0.5833922625, -1.8033591509, 1.9753354788, -2.316024065, + -0.5039364696, 1.1172219515, -0.567153275, -0.4029072225, 1.2319533825, -1.3085190058, 0.428566426, 2.4368367195, + -0.8638158441, 1.3917367458, -0.4627754688, -0.0249045976, -0.6280714273, -0.3255177736, 0.6238153577, 2.4476258755, + 0.3078250289, 0.2715431154, -1.6325097084, -1.1116009951, 1.1871554852, 1.631346941, -0.1071722433, 1.0070543289, + -2.4956753254, 0.106171824, 0.0120313754, -0.2095249593, 0.3418090045, -1.2988194227, 0.9380907416, -0.1236676201, + -0.4573471248, -0.7191598415, 0.8948004246, 0.4774148464, -1.7359133959, 0.6295673251, 1.4042685032, 0.4560325742, + 0.2498383373, -0.7552278042, -0.2820581496, -0.9741064906, -0.0094816862, 0.492772609, -1.5904263258, 2.0433969498, + -0.2484231889, -0.3923215866, -1.2565356493, 0.4341219962, -0.2114793807, 0.0118124252, 0.1367721707, 1.8070771694, + -0.6738863587, -0.7573686242, -2.5797410011, -0.0804657713, -0.4304643869, 0.3704101741, 0.0622019991, -0.3475724757, + -2.1042618752, 0.5381350517, -0.7691090703, 0.1761910468, 0.1809306294, -0.3777577877, -0.9449252486, 0.2289055586, + 0.2820708156, 0.4839225709, -1.6858013868, -0.8856335282, 0.9421400428, -0.0791686252, -1.6161797047, -1.0410964489, + 0.6739453673, 0.087825574, 2.3287050724, 0.708316505, -1.3314689398, -0.5426526666, -0.1750532389, -2.0199997425, + -1.9016313553, -2.2880182266, -0.6802806854, -0.5845252872, -0.3345496356, -1.3252086639, -1.4987232685, + -0.5198655128, -0.8556139469, 0.7470584512, 0.7125549316, 0.0654351264, -0.6348320246, 0.7843273282, -0.4739659429, + 0.2645100951, 0.7582881451, -1.4469571114, -0.87623173, -0.1305171847, -1.8916240931, -0.2047363669, -1.4006288052, + -1.4427716732, 0.4075613022, -1.5529645681, 0.4010265768, -1.2205121517, -0.5830441713, 0.7983804941, 1.381018877, + 1.2851274014, 1.6508965492, 0.8096008301, -0.7591167688, 0.7297912836, -0.7162643671, 1.0841537714, -1.2955800295, + -0.7949441671, -1.1049574614, -1.8323066235, 0.4911190569, -0.0560565628, -0.7176681757, -1.887206912, 0.5780738592, + -0.8776240349, 1.1596308947, -1.467441678, 0.7553941607, 0.1954972744, -0.5818178654, 0.2693494856, -1.0041868687, + 0.6039539576, -0.6923959255, 1.9953961372, 0.1902663261, -0.0727277547, 1.5628709793, -1.3869262934, -1.2224737406, + -0.9052775502, 1.8306998014, 0.1413167864, 1.7664381266, 0.7349786758, -0.1183590814, 0.8745171428, -0.1398411989, + 0.2598904371, 0.0656923652, 0.8621975183, 0.8937485218, 0.2206461132, -1.2316112518, -0.7846273184, 0.7935965657, + -0.7879238129, -0.7651246786, -0.1138043851, 0.6265539527, -0.1829637885, -1.1814017296, 0.0661041215, 0.954420507, + 0.3241200149, 0.108584471, -1.2307775021, 0.3755576015, -0.3521512449, 1.3882151842, 0.5725190043, -0.0776720494, + -1.3191725016, -0.4986121058, 0.3813388348, 1.4137277603, -1.5064461231, 0.044257503, -0.5795447826, -0.6121605039, + 0.7674696445, -0.3727608919, -0.1838898957, 1.0338747501, 1.9497634172, 1.0179313421, -1.1559066772, -0.388492465, + -1.3412394524, -0.8717449903, 0.7448266745, 0.4458397627, 1.6077286005, 1.6052932739, -0.5146309733, -0.3278999627, + 0.7633868456, -0.8159669042, 1.4002127647, 0.1569492966, 1.910246253, -0.1955651641, -0.6491927505, 0.2193007469, + -0.4692718685, -2.2204196453, -0.3630209267, 0.2141387612, 1.0269374847, 0.7454722524, 0.3479391336, -0.2595340014, + -0.0004230243, -0.5843359828, 1.0068081617, 0.5920389295, -1.4571993351, 2.0111148357, 1.6898576021, 0.1999664903, + -1.2243306637, -1.9395003319, 0.7388504744, 1.3946845531, -0.813585043, -0.8188219666, -0.1027977988, 1.2393451929, + 0.3642773926, -1.1666374207, -0.5038280487, 0.1114103869, -1.5347028971, -0.5841313601, -0.8017553091, -0.1922202855, + -0.3450426459, 0.3865180016, -1.2264298201, 0.588039279, 0.2358413041, 0.9229251146, -2.5078446865, 0.4116154313, + 0.6169677973, 0.3932493329, 0.734978497, -0.1033508405, 0.5472589135, -0.8508823514, 0.4239557981, 1.7755675316, + 0.0498641804, 0.0039831121, -1.101292491, -0.0702986047, 0.0500299931, 0.9911147356, -2.1317226887, 0.0189382583, + -1.286716342, 0.56494838, 0.5770050883, 0.6580603123, 1.4723309278, 0.0125505729, 0.7892917395, 0.5260727406, + 0.7284713984, 0.919890523, 0.4369905293, 0.1269310713, -2.4369902611, 0.2138117403, 0.655831337, 0.1240368336, + -0.6512229443, 0.7850050926, 0.844194293, -2.6291081905, 0.085959889, -0.8896072507, -0.6072485447, 0.5743405223, + 1.1331851482, -0.4991896152, -0.6477818489, -0.5778541565, 0.0418310277, 0.488165468, -0.9791178107, 0.1232551485, + -0.8317633867, -0.431512624, 1.2505896091, -1.6251081228, 0.3261093497, 0.7886345387, 0.2484288216, -0.5134832263, + -1.5124263763, -1.6093171835, 0.5770623088, 0.5730774999, 0.4694595337, -0.1032461897, -1.6306973696, 1.0383374691, + 0.3179350495, 1.6510140896, -1.4021530151, -1.6068631411, -0.9987185001, -2.0106415749, 2.4225859642, -1.471126318, + 1.0438575745, -0.682294488, 0.5343873501, -0.2162118554, 0.4941727519, -0.091969043, -0.0362560339, 1.7026308775, + -0.5808956623, 0.2818481922, 0.4702845514, -0.7051241398, 0.4703357816, 0.4183109701, -1.0918869972, -1.1447758675, + 0.1090682745, -1.0183391571, -0.0740790442, 0.8214829564, 0.2784597278, -1.2427382469, -0.8619667292, 0.9212391376, + -0.388351202, 0.0477222577, -0.8693955541, -0.127015084, 0.4906855226, 0.0592403039, -0.2530156374, -1.904866457, + -0.0264112484, -0.5457171798, -0.0354791954, 1.5265716314, -0.1019395888, 0.7486965656, -1.518704772, -1.0162277222, + 0.6233072877, 0.4643627703, -0.8993694186, 0.4188348353, -0.2046624869, 0.0254781116, 1.2895642519, 0.631018281, + 0.3446836472, -0.5590118766, -0.2556653917, -0.9896861911, -0.5274890065, 0.2978168428, 0.0847402886, 1.4692370892, + -1.3065133095, -0.6991641521, 0.3440778255, -0.2718342543, -0.5695889592, 0.017405834, 1.0984630585, 0.1190534905, + 0.979847312, 1.8879725933, 0.8673732877, -0.9161585569, 0.4036022723, 0.0035582194, -2.345140934, -1.0702661276, + -1.684953928, 0.5669997334, -0.0257244613, 0.0361120626, -0.0581826456, 1.0888381004, 0.4999228418, 0.5219503641, + 0.4908412993, -0.464889437, 1.2614723444, 0.3910034001, 2.043861866, 2.362282753, -1.1208287477, -0.5126113296, + -0.9887000322, -0.5191606879, -0.2261203378, -0.12525855, 0.0878077075, 0.0369837433, -0.3490452766, 1.1845042706, + -0.2965066135, 0.8207860589, 0.1675992906, -0.9627301693, 0.2979668677, -1.6763862371, -0.1788655072, -1.2550932169, + 0.7845742106, -0.0772865936, 0.3855877817, -0.7745981216, -0.1232291982, 0.776026547, 1.381819129, -1.0101274252, + -0.7251560092, -0.205671072, 0.0522477031, 0.1851748675, -0.5892301798, -1.8814272881, -0.8631243706, -0.6360574365, + -1.1729818583, -0.9179823995, 0.91771245, 0.7739092112, 1.4054862261, 0.8030353189, 0.449246943, -0.8796300888, + 1.2875020504, -0.9119425416, -1.7323316336, -1.3451622725, -1.0565350056, 0.044804506, 0.3449862301, -1.5712947845, + 0.5012857318, 0.5056712031, 0.2673935294, 0.2346226573, 0.8127566576, 0.8522439599, 1.3639987707, -1.5733017921, + 0.4449477792, 1.0757219791, -2.1031193733, 0.0343645252, 1.1781619787, -1.4266718626, -0.0131833591, -0.2667540014, + -0.0093084434, -0.5884740949, 1.7538708448, 1.1161477566, -0.1020128131, -0.2309615612, -1.2694759369, -0.5607418418, + -0.4304545224, -0.3253737688, 1.480864048, 0.731693089, -0.2684265673, 0.4855044782, 0.3031046987, -0.8914096355, + -1.4147173166, 0.038046021, -0.7299775481, -0.2678869963, -0.3101365864, 0.0350842513, 0.2402429581, 0.7029187083, + 2.7874162197, -0.1721138507, -0.6986640096, 1.1523491144, -1.3354657888, 0.0191495139, 1.1237381697, -0.3511058688, + -0.4177630544, -0.9081257582, -0.2498989403, -0.1846230924, -1.6133767366, -0.8762238026, 1.6221534014, 0.2161289006, + 0.4476101398, 0.2794209719, 0.8718365431, -0.1944708526, -0.6252462268, -0.7593362927, -1.4583418369, -1.4333637953, + -2.1012365818, 0.4250461757, 0.9667654634, 0.2156297415, 1.4574354887, -1.2711378336, 0.6589086056, 0.5638456345, + 1.1474407911, 0.1375724077, -0.2267200947, -0.1479162425, -0.0163359381, 1.4957658052, 1.5470947027, -1.1362988949, + -0.0993754491, 0.0944555551, -0.0559778437, 0.9665927291, -0.2777977884, 0.9807844758, -1.7313894033, 1.2457816601, + -0.7532542348, 1.5628550053, -1.8272314072, 1.1460046768, 0.5990837812, 0.6483633518, -0.8140592575, -2.5026910305, + 1.5262742043, -0.532572031, 0.1642222852, 0.3184698522, 0.9115745425, 0.9058817625, 1.224208951, -0.7914894819, + -0.5712547898, -0.2330745012, 0.7534739971, -1.3289783001, 0.2245698124, 1.4651367664, -0.6622340083, -1.448622942, + 0.4370337129, -0.464335084, 0.5815520883, -2.0180966854, 0.6800788641, 1.9025919437, 0.4159368277, 0.3808253109, + -0.3558321893, 0.2614868283, 1.4179209471, 0.3718845248, 0.9492228627, 0.151613459, 0.3136004806, 0.0753630325, + -0.8924691677, -1.5429160595, 0.2965213656, -0.5717129707, -0.0413963459, -0.946413815, -1.2638531923, -1.4999424219, + 0.4140037298, -1.3621689081, -0.109472014, 0.1787716299, -0.3219559491, -1.416744113, 0.5873966813, 1.1247311831, + -1.4185732603, -0.6824306846, 0.3787460029, -0.2558441162, 1.1735316515, 1.0506619215, 0.3373606205, -1.7914761305, + 1.0255435705, -0.4845902026, 1.3263299465, -1.1724784374, 0.5220450163, 0.8054077625, 0.009695014, 0.8125115037, + 0.3299151063, -1.003721714, 0.3730991185, -0.9277126789, 1.4822149277, 1.5176270008, 0.0745661706, -0.9604218006, + -0.1578906775, 0.2494293302, -0.9300476909, 1.5165371895, -0.5894943476, -0.1630633473, 0.0795842856, 0.3101577163, + -1.2102751732, 2.5860579014, -0.9084997177, -0.9838130474, -0.4032730162, 0.4376574755, -1.1266232729, 1.2498075962, + 0.5042888522, 0.226098612, 0.6913132668, -1.5524065495, 1.0065914392, 1.2285039425, -0.3059667349, 0.639975369, + 0.1240009218, -0.5298648477, 0.7409871221, 0.6777750254, 1.4533698559, 0.7625650167, 0.1595736295, -0.1319786757, + 0.8643478751, 1.0831538439, 0.08462888, 2.1185903549, 0.42227301, -0.573025763, 0.8299391866, -0.3804766834, + 1.1045529842, -0.5073445439, 0.1418423355, 1.2586370707, 0.8240965009, -0.0925577134, 1.7273045778, -0.3900260031, + -0.0798248723, 0.8808295131, 1.2586567402, 0.9773184061, 0.9998583198, -0.2488287389, 0.2702918947, 1.4333872795, + 0.5639662147, -1.0274194479, 1.891559124, -0.9012168646, -0.374877274, 1.9961894751, 0.3488658071, 0.2414206564, + -1.1801184416, 0.8474820256, 0.263838917, 0.428429544, -0.496113658, 0.5766240954, -0.8417623043, 0.4841005206, + -1.2339916229, -0.7195590138, 0.6247155666, 0.2961598039, 0.1626374722, -0.199369207, 0.4295589626, 0.1204819679, + 0.2459912151, 2.3836979866, 0.9892594814, 1.5916163921, 0.0971853957, -0.8566622734, -0.2674368918, 0.5222064853, + 0.9773113728, -0.3150422573, 0.8756898046, -0.4676228464, 0.2016017884, -0.7167613506, -1.4885647297, 1.2574212551, + -0.6553381085, -0.6623219252, -1.735632062, 0.2538641989, 1.0851593018, 0.5627361536, 1.1075919867, -0.7186845541, + -1.4439043999, -0.857933104, 0.5339972377, -1.0072786808, 0.690077126, -0.8863855004, -2.2532014847, -2.5111033916, + -0.4095038176, 0.2482353151, -1.2830238342, -0.8127713799, -0.0843408108, 0.1111695021, -1.0864380598, -1.5028867722, + -0.8787872195, -1.5936022997, -0.187183097, -1.039966464, 0.0147543494, 0.7644811869, 0.9782803655, 0.0003450581, + -0.2709909379, -0.1951631755, 0.3221687376, 0.3713282347, -0.4911470413, 0.7329746485, 0.0925365835, 0.2304435521, + -0.966812849, 0.4846392572, -1.1093183756, -1.3233888149, -0.0245773736, -0.0953248069, 0.1685880274, -0.0482572317, + 0.5383268595, 1.0802992582, 0.2973013222, 0.9245066047, -1.3101730347, -0.4364936352, -0.4648250341, -1.1351803541, + -0.8205749989, -0.8568386436, 2.3754029274, -0.9961820841, 0.836352706, 0.2676135302, 0.8208408356, -0.9117810726, + -1.0280570984, -0.979886651, -1.0432735682, -0.6724710464, -1.4416898489, 0.7651339769, 0.5950027108, -0.1433894634, + 0.6269071102, 0.8044335842, 1.0749381781, 2.0385212898, -0.133489415, -1.8284147978, 2.0971255302, 0.5444354415, + -0.7383652925, -1.5236394405, -0.5464919806, -1.5434194803, 0.3095881343, -1.1199891567, 2.2750618458, -0.4669438601, + -1.8398299217, -0.1546743661, 0.0634817109, -0.4727517366, 1.8044909239, 1.3376697302, 1.1377027035, -0.319876641, + 1.7948639393, -0.2277033031, -0.336995095, -0.5130826831, 1.2988376617, -0.7731146216, -1.0604265928, -0.2253106982, + 0.107471019, -1.8205831051, 0.7368350029, 0.7032628059, 0.9893723726, 0.6483827829, 1.4742196798, 0.0884756595, + 0.4978652, 1.0682324171, 0.6970139146, 0.8740690351, -0.9838154316, 0.2248925716, -0.55598557, 0.4227550626, + 1.199296236, 2.3643376827, 0.8882084489, -0.5913435221, -0.7380414009, -1.0349892378, 0.9173351526, -0.562187314, + -0.0949840769, -0.1317703575, 0.0631912276, 0.9709743857, 0.3090033233, 0.9268954396, -0.4655930102, 0.2861961126, + -0.2644225359, -0.3251528144, -0.82221663, -0.0960599184, 1.4646030664, 1.4194988012, -0.4227886796, -1.8527027369, + 0.2715824246, -0.5044975877, -1.8221150637, 0.1931934655, -1.5894869566, 0.2379000485, -1.0019147396, -0.2313501835, + 0.0035350423, 0.0740525126, -2.6869721413, 1.5776410103, -0.5823276043, 1.4910770655, -0.9430855513, -0.049944263, + -0.2272549123, -0.0936595276, -0.1898984909, 0.5837596059, -1.1511113644, 0.3232372105, -2.086288929, -0.0450896136, + 0.1430051774, -0.3782043159, 1.2295246124, 1.599044919, 0.4077310264, 1.0603466034, 0.1066178828, 0.9763474464, + 0.5174518824, -1.0154049397, 0.1633393317, 0.9158678651, -0.4462140799, 2.7762815952, -1.7528024912, -0.8473525047, + 1.3816362619, -1.4776809216, -0.0661653429, -0.5095384717, 0.1321265846, 0.3022744358, 1.0764505863, -0.8410828114, + -3.0817403793, -0.0300313104, -0.0764164105, -0.2109280974, 0.1390453428, 0.4264347255, 0.0728728324, 0.2737209201, + -0.4620195031, -0.049171228, -0.3356860578, 0.4319370985, -0.2530729175, -0.4461062849, -2.0072276592, 0.9238764048, + 0.1594048589, 0.0638244227, -1.3263802528, 0.1089418977, -0.5390468836, -0.5481974483, -0.1197349951, 1.0218429565, + -0.7934098244, -2.4163577557, 0.7732511759, -0.4387922585, 0.6461163759, -1.3936929703, -0.661878407, 2.1668913364, + 1.0993745327, -0.1202072054, -0.4973158836, -0.6462906003, 0.0609707199, -0.9450492859, -1.3187497854, -1.0022757053, + -0.1960598081, 0.7324171662, -0.4829072952, 0.4753527939, -1.4519374371, 0.8318330646, 1.3754912615, -1.1183576584, + 1.5637904406, 0.3519226611, -0.4841500819, 0.3794345558, 0.5975720286, 0.6764720678, 0.5199920535, -0.0438902751, + 2.0463252068, -0.5165079236, 0.0998032242, -0.9830651283, -0.6394013762, 1.126291275, -0.810318768, 1.0153911114, + -0.6205669045, 0.3662223816, 1.1925779581, 0.8172106147, -1.0794445276, 1.8628367186, 0.0463979691, -1.1959922314, + -0.0023014785, -0.366589427, 0.6613500118, -0.1001069471, -0.9814707041, 0.3034345806, -0.7231702805, 0.7263912559, + 0.8849028945, -0.0591529347, -0.7766273022, -1.2518745661, -0.6941793561, 0.5461867452, -1.4127789736, -1.1363685131, + 0.4137958586, -0.2157655805, -0.1393927634, 2.933562994, -1.3698664904, 0.4863412976, 1.7759577036, 0.9367753863, + -0.5121124983, 0.5831712484, -1.5519332886, 0.291321069, -0.5899180174, 0.0952703059, -1.8471230268, -0.0709084868, + 1.4827005863, 1.423795104, -0.5086781383, -1.6200858355, -0.1084599942, -0.3973819017, -0.7838751674, 1.9469268322, + 0.46529001, -0.6131108403, 0.4059070349, 0.2010302395, -0.1316693425, -0.07465709, 2.3412575722, -0.1811244637, + -0.7504181862, -0.3903382123, -0.2243826389, 0.9201111794, 0.4877253771, -1.4580579996, 0.8116889, -0.5697486997, + -0.4015645683, -0.4854067564, -0.6364825368, 0.9034591317, 0.6379844546, 1.5771756172, 0.5850499272, -0.6220704913, + 0.4983624816, 0.4711814821, 1.1179269552, -0.2089185417, 0.554084599, 1.2248898745, -0.597746253, -0.5361250043, + -0.0362544581, 0.8173483014, 0.1797466129, 0.6411272883, 0.5963133574, -3.6270735264, 0.31352368, 1.7770348787, + -0.5708009601, 1.2956660986, 2.3631596565, 0.6470772624, -0.1276730001, -0.4334301949, 1.7504278421, -0.7313968539, + 1.3321459293, -1.1168040037, 0.0644597635, 0.6098915339, -0.8870542049, -1.1227594614, -0.1024430543, 1.0980104208, + -0.1197945774, -0.7725059986, -0.285672158, -1.4923102856, 0.2849843204, 1.2012387514, -2.6904499531, 0.1604321897, + 0.0795088485, -0.9636630416, 0.4146036506, -0.2131204307, -0.5044959784, 0.3896358311, 0.4751556814, 0.2694335878, + -1.358423233, -1.5450501442, 0.2078277916, -1.4040329456, -0.9148842096, -0.554459095, -1.9398692846, -0.7526990175, + -0.2037417889, -1.1072591543, 1.958311677, 0.4932885468, 0.2148445249, 0.7477450967, 1.5735576153, -0.0146483416, + -0.7617738247, 0.5999017954, 0.7779759765, 0.5772922635, 0.2835288644, -1.2251069546, 0.0834239051, 0.745736897, + 0.5876018405, 1.0709481239, 0.5153665543, 0.7868348956, 0.9774563313, 0.1690707654, 0.4484441876, -1.3282804489, + -1.5179308653, 0.4773723185, -0.2764462531, 1.5602777004, 0.3877660036, -0.3111630082, 0.9336119294, 0.9268003702, + 1.2970597744, 0.4492572844, -0.5420606732, 2.1234147549, 0.4513804018, -0.7160360217, -0.3417129517, -0.39070189, + -0.0474371351, 1.138076067, 0.4578434527, -0.21611996, 1.1832199097, -0.5278459191, -0.7826381326, -0.9901517034, + -0.2069672644, 0.7864428163, 0.3632103205, -0.3682445586, -0.4018748999, 1.0661147833, 1.0399434566, 1.4891061783, + -1.6929762363, -1.0862518549, -1.6203837395, 0.1468081474, -0.3604899645, 0.8857752681, 0.4906992018, 0.0710786209, + -1.1928530931, -0.1335477829, 0.3187680244, 0.0093177333, -0.9354539514, 0.2795247138, -0.3294781744, 0.4063001871, + -0.9572349191, -0.8981993794, 0.3415729702, 0.879945457, 0.6367980838, 0.7841370106, 1.116324544, -1.9475696087, + -0.4421205521, 2.8911242485, -0.8780661821, -1.0232143402, 1.6205269098, -0.7261584401, 0.0078559443, 0.6348084211, + 1.1820709705, -0.1163733304, 0.8389843702, 1.2746939659, -0.1599865109, -0.9582620859, 1.6713591814, 0.6692322493, + -0.6660379171, 1.0564323664, 0.9545536041, 1.2530609369, -0.2479295433, 1.6680572033, -0.4401457906, 0.778175056, + -0.303876847, -0.4356323183, 0.6398789883, -1.5581569672, -2.0755450726, 0.6866158843, 1.319554925, -0.3794221878, + 0.5103654861, 1.9730210304, -0.7375587821, 0.686024189, -0.9076411724, -0.6199430823, -0.9175467491, -1.3471761942, + -0.9156367779, -1.3426939249, -2.0646798611, -0.6329957247, -0.0766262189, -0.540892005, 0.9520366192, -0.8571756482, + -1.1599135399, -0.5584220886, 1.6461673975, 0.1045306548, 0.2158393413, 1.7292610407, 1.2974575758, -1.3764995337, + -0.4452150762, -0.1526507884, -0.9902333617, 1.5345755816, -0.1589398384, 0.9030612707, 2.0708162785, -0.986179173, + 0.2067744881, -1.9495503902, -0.598511219, 0.9967989922, -0.8435174227, -0.2820928097, 0.3777058125, -0.3613773882, + -0.5519063473, -0.6273316145, -0.4378284812, 0.2569901943, 0.910485208, 0.0983464718, -0.2658705711, 0.3255655766, + -0.5762305856, -0.960234642, 0.2911734283, -0.5379109383, -0.9457253218, 0.7973366976, -0.7568753958, -1.7424373627, + -0.7140328884, 0.7866174579, -0.0874564052, 1.0776548386, 0.0858798251, -1.2913337946, 0.8008134961, -0.3137482703, + 0.538618803, 0.4172564447, -0.221272409, 1.0290312767, -0.6964595914, 1.6124269962, -0.5174486041, -0.6736907959, + -0.3899573386, 0.1325595826, -1.0444660187, -0.2226642817, 0.7306677103, 0.5076549053, 0.9035003185, -0.4636362791, + -0.5478364825, -0.5060825348, -2.3333342075, -0.9416838288, -0.0387029424, -0.1578006744, -0.6142289639, 0.8859317303, + -0.8811742663, -0.677290678, -1.1823346615, -1.332850337, -0.0093972646, 0.54914397, -0.6104214191, -1.2850006819, + -0.6465294361, 0.1817125827, -1.4026774168, -0.1775815934, -1.2878239155, -0.4031934738, -0.8606334329, -0.7982609272, + -0.6417425871, -0.6398243308, -1.3228656054, 1.2034947872, 0.8919556141, -1.8049753904, 0.4476211667, 0.2820806801, + 1.8818633556, -0.9953379631, -0.3909469247, 1.3604015112, 2.3987371922, 0.3861819506, 1.0936772823, -1.1391612291, + 0.8738053441, 2.6254327297, -0.107052125, -0.4421439469, 1.9917935133, -0.3215175569, 0.654234767, -1.0363366604, + 0.5616360903, -0.9750161171, 0.5296633244, 0.5032150149, -0.8450386524, 0.2101103216, -0.8270325661, 0.2830041051, + -0.9392392635, 0.8031272888, -0.8688564897, 2.0318152905, 1.5412871838, 0.3922415972, 0.3853695095, -0.1013855189, + -1.2406502962, -0.889899075, 1.6640088558, 1.4869363308, 0.014400946, -0.0533166006, 0.1196023002, -0.0499731563, + 0.0728715211, 1.6635298729, 0.1403089315, 0.2601655424, -1.2603138685, 0.5634941459, 0.5055314898, 0.7348325253, + -0.4419586062, -0.1415433139, 0.756772995, 0.9354738593, -0.0609624647, -0.3537159264, 0.863094151, 0.5925130248, + 0.1479303986, -0.5582378507, 0.849501729, -0.1681861877, -0.8794690967, 1.5341011286, -0.9373859167, 0.3684532642, + 0.2468343675, 0.5768260956, 0.1956495643, 1.7508788109, -0.2407533079, 0.0557939187, -0.3764891624, -1.4740674496, + 1.0650231838, -0.610912323, -0.8943587542, -0.2481622696, 0.550984025, 0.1316975355, -1.0856409073, -0.5210722685, + -0.4651280046, 0.0003967007, -0.9472005963, 0.326462388, 0.0406349227, 0.6955839992, 0.6747277975, -0.8340126276, + -0.6404592395, -0.4645507634, -0.5293129683, 0.18106094, 0.5685809851, 1.0409775972, 1.8969447613, 1.4060031176, + -0.9676909447, -1.140648365, -0.8645566106, -0.9631246328, -0.4495841265, -0.3670941293, 0.1041967198, 0.9390909672, + -1.9684011936, 0.2957823277, 0.0055266228, 1.9068297148, 0.2354781479, 0.0417030305, -1.7206138372, -1.1816716194, + -1.6864529848, -0.279574424, -0.4381642938, -1.3464711905, -0.2227810323, 0.4033103883, 0.2749841511, 0.2874121964, + -0.0273968987, -1.6804682016, -0.8865109682, -0.2472569197, -1.1258128881, 0.9342336655, -0.5807120204, -0.1418465823, + 0.0790987611, -1.0749927759, 2.2134726048, -1.2006694078, 0.2691707015, -0.2489442676, -0.8762915134, 1.6632809639, + -1.0335812569, 0.8721647859, -0.1475594044, -1.2235310078, 0.5650429726, 0.2195928097, 0.0491285175, -1.0111253262, + -0.8699862957, 0.19769907, 0.342112273, 0.4036723971, -0.0111169284, 0.1301707774, -1.9352202415, -0.3411969543, + 1.5464907885, -0.8455371261, -0.2012025714, 0.5543738008, -0.354948014, 0.9601488113, 0.5847229362, -0.9601101279, + 0.1428328454, 0.7909606099, -0.2072594315, 0.574973166, -1.2849420309, 1.2086113691, 0.4027648866, -0.9209063649, + 1.3428764343, -0.0497116633, 1.1252496243, -1.4034109116, 0.0854413658, 0.5364454985, -0.4646377563, -0.2525386512, + 1.5714304447, -0.3075014353, 0.7793367505, 1.7497104406, 0.1035423651, 0.41565606, -0.7896444201, 1.537280798, + -1.0925191641, -0.3885779679, 0.7863638997, -3.7716197968, 0.3558905423, 0.265760988, -0.0128362346, 0.2688941061, + -0.3216839731, -0.8197370768, -0.4061123729, 0.0722145662, 0.6458423734, -0.5728822947, 1.5331975222, -2.2644534111, + -0.7149686217, 0.7342334986, 0.0273310989, 0.4219648838, -1.8402411938, -0.5089277029, 0.5984560847, 0.6699381471, + 0.4165192246, -0.5552244186, 1.8353990316, -0.6733164191, 0.332133323, -1.0508931875, -2.3420100212, -1.1035705805, + 0.2500540316, 1.2323869467, 0.9139543176, 0.7953773141, -0.236880064, -0.8238989115, 0.929664135, 0.1124773398, + -0.4949807525, 2.1422438622, 0.3602790236, -1.2223575115, -0.5173635483, 0.2391503006, -1.1317293644, -0.8869965672, + -1.9696947336, -0.8611670136, -0.4780994356, 0.1703852862, 0.0392747857, -0.8513867259, 0.594198525, 0.7758460641, + -0.2394779474, 0.5881170034, -0.35261181, -0.9439957142, 1.4639183283, 0.8294926882, 0.2655101418, 0.2055927962, + 1.5004353523, 0.5081455708, -0.7707537413, 1.5194914341, 0.9345728159, -1.1830033064, -0.7755748034, -2.1746835709, + -0.1002500951, -0.9036408067, 1.1387488842, -0.0545942672, 0.7622455359, -0.3603307605, -1.1414390802, -2.1771762371, + -0.3917343915, 0.9779875278, 0.0251153242, -2.3134996891, -1.2564883232, 0.5975403786, -2.0236263275, 0.4483772218, + 0.4159247279, -0.9448549747, 1.5468273163, 0.448217541, -0.6612976193, -0.4731059968, -0.4449138641, -1.9738931656, + 0.7042369246, -0.00619527, -0.4430695176, 0.7511484027, -0.6052109003, -0.7535775304, 0.2447089404, -1.4141345024, + -0.6515182853, 1.1660512686, -1.821788311, -0.6141258478, 1.2125263214, -0.0212147497, -0.6908379197, -0.2760960758, + -0.3090609014, 0.0992453471, 0.3898756504, 0.6739951372, -0.2484564334, 1.1012392044, -0.4972129166, 0.4972700775, + 0.1244544089, 0.8972615004, -0.9175131917, 0.8274303079, -0.4539879858, -0.2072115093, 0.5159810781, 0.9847689867, + 1.0576518774, 0.4988316596, 2.120672226, -0.2258833945, -1.7573635578, -0.661401093, -0.5449556112, -0.3869622052, + -0.1445140392, -0.1908085942, -0.1185690537, 1.7395980358, 2.7544355392, 0.3639674187, -0.6550902724, 0.302347362, + -0.2460299134, 0.0533388853, 0.605373919, -1.3006967306, -0.2727494538, -0.8468128443, 0.976688385, -0.604534924, + 0.2835266888, 0.2119962424, 2.5724422932, -0.1248733848, -1.5877096653, 0.4133778512, 1.3906018734, 0.3611457348, + -1.4941810369, 0.9097679257, -0.7895452976, -0.0131430048, 0.4787768126, -1.4094642401, -0.7671945095, 0.4627577662, + -0.2127619982, -0.5586658716, -0.0810662135, -0.6329986453, -1.5000852346, 0.1569671482, 0.4610330462, 0.5216055512, + 1.0951989889, -0.6010218263, 0.5522876978, 0.4321692884, 0.6307811141, 2.0530083179, -0.5217092633, -1.4897885323, + 0.6250126958, -1.5613023043, -0.0225469321, 0.3653716445, -0.1923164874, 0.4022558033, -0.3239069879, -1.1409021616, + 0.2954473197, -3.0193588734, -0.4682822824, -1.477316618, -0.9042945504, 1.0454072952, -1.1082838774, -1.0444512367, + 2.1708672047, -0.4832859039, -0.67779845, 1.559556365, -0.2915486395, 0.022152245, 1.6878607273, 0.9222207069, + 0.500010252, 1.1645658016, -2.7195198536, -1.5850836039, -0.3821529746, 1.1708577871, 0.5796393752, 0.0682036281, + 1.1589673758, 1.6575613022, -0.766268909, -1.2816127539, 0.1619419008, -1.3800725937, 1.1070289612, 0.9855763316, + -0.9594042301, -0.8101201653, 1.4170614481, 1.6217786074, 2.547860384, -0.9287158251, -0.894159317, -0.7534239888, + 1.6682021618, 0.3101405501, -1.0944006443, -0.010388447, -0.6301780343, 3.0968067646, 1.1102194786, -0.8093426228, + -2.0855097771, 1.2799286842, -0.7997585535, 0.6396434903, -0.7613869905, 0.3158714771, 0.2002303302, 1.62756598, + 0.6539255381, 0.4313740432, 0.8388326764, 0.3235431612, -0.3483707905, -1.0462989807, -0.6488026977, -0.1168876439, + -0.2802293897, -0.3582161069, 0.7303908467, 0.0247646552, -1.3823878765, -0.670078814, -1.721804142, -1.5610544682, + -1.3730332851, 0.0397199988, 0.0339602269, -0.0213197358, 1.0941541195, -0.2352717072, -1.632289052, 0.0799121186, + -0.9556933045, 0.9889248013, 0.2835512459, -0.4392039478, -0.9414988756, 0.407256484, -0.9518223405, 1.3833876848, + -1.1340763569, -1.8409861326, 0.5475594997, 0.577278316, 0.0075433361, 0.4877021611, 0.7304438949, 0.3374955654, + -0.1783489287, 0.5135381818, 0.586237371, 0.4374061227, -1.2511309385, -1.0444641113, -1.2574287653, 0.8642635942, + 0.8503614068, -2.4733905792, 1.0161190033, -1.7650945187, -1.0526522398, 0.9574536085, 0.2752321362, 0.366633743, + -0.3609675765, 0.8975061178, -0.3459243774, -1.4031714201, 0.3312491775, -0.6045495868, 1.2702319622, 1.0439270735, + -0.9935119152, 0.2147451937, 1.1008656025, 0.429919064, -0.137211144, 0.616956532, -1.551684618, 2.0646662712, + 0.9198255539, -0.3870903254, -0.2804978192, 1.3506839275, 1.4641412497, -0.8443898559, 0.1116885245, 0.3858242631, + -1.1577074528, 0.0645114258, -1.4962903261, 0.5474752784, -0.3548987508, 1.0024415255, 0.5446375012, 0.8305513859, + 2.6467790604, 0.6494945884, 0.0595578328, 0.3597752154, 0.2516870499, -0.1181238145, 0.4422335625, -0.1153549701, + 0.0733081177, -0.2758054435, -0.1951264143, 0.1095378771, 0.3252094388, 0.8930382729, 1.0510355234, 0.9716653228, + 0.1504226327, 0.5727462769, 0.2539176345, 0.0424893796, -1.0405927896, -1.469029665, -0.0724262744, -0.1799088567, + 0.0264645424, -0.159874633, -1.4990167618, -0.2105566263, 0.1332618743, 0.7448723316, -0.974488318, -2.1181311607, + -0.7248430848, 2.7197012901, -0.5189481974, 0.6716082096, 0.1522336751, 1.0515916348, -0.3552295566, 0.0526108779, + 0.9851053357, 1.0241189003, -0.5028194785, -0.83018291, -0.3506364822, 2.1013507843, -0.2975785732, -1.1915485859, + -1.9310274124, 0.028161196, 0.7278511524, 0.0044026095, -1.3758076429, -1.2809020281, 0.718398571, 0.2994307876, + 0.9146254063, -1.880446434, -0.5685744286, -0.1684366763, 0.6454023719, -0.1555209905, 0.0017470572, -0.0461361818, + -0.4751440883, 1.6674766541, -0.2610110044, -1.3076088428, -1.0537695885, -0.1325166225, -1.659055829, 0.1996072829, + -0.4648935199, 1.6472010612, -0.7532877326, -1.2189908028, -1.2708369493, 1.7304326296, 0.9739592075, -1.6090298891, + 0.9269093871, -0.5141512752, 0.3343603611, 1.0514758825, -0.7026612163, -2.2228353024, 1.6996566057, -0.0153976502, + -1.189422965, 0.102931127, 0.98609519, -0.0424149409, 0.2471846044, -0.6132379174, 0.1702657193, -0.9761342406, + 0.1023765877, 0.9823054075, -0.2936163843, 0.524726212, 0.2902828455, 1.3442021608, -1.2850005627, 0.8672465086, + -1.5464787483, 1.5290105343, -1.3002258539, -0.4517161846, -0.303686142, 0.4617317021, 0.4716469944, 0.1666602939, + 0.2115351707, -0.5178134441, 0.9480272532, -0.0098326812, -0.2219161838, 1.0748243332, 0.0413280837, -0.3751921058, + 1.0054109097, 1.0878173113, 0.2635469437, 0.8403769135, 0.2879878879, -0.1068011448, -0.9250847697, 0.2024889141, + 0.190391019, 0.7410366535, 0.8781462908, -0.2524499595, -0.1668965071, 0.7493336797, 0.8561979532, -0.0669981241, + -0.2866696715, 0.0031576664, -0.3875811696, 0.4032322168, -0.0186206941, -1.0397504568, 0.5258228183, -2.0523731709, + 1.401163578, -0.3832056522, 0.2031720877, 0.6009286046, -1.0024389029, 0.9176901579, 0.1213238463, 0.4889194071, + 0.5418915749, 0.6136344075, 0.1356879771, -1.2291907072, -0.7746384144, -0.1509719342, -2.0120000839, -0.1013733819, + -0.308783114, 0.5470914245, -1.714197278, -0.2830403149, 1.5329728127, -1.1248511076, -1.0335241556, -0.5896264315, + -0.0678327307, 3.014480114, -0.1954812109, -0.8513020277, -0.8838554025, 0.839912951, 0.4587032497, 0.6862203479, + 0.4576050341, -0.9797825813, -0.9266083837, 1.2219574451, 0.1443065107, 0.6248232722, 0.2345218509, 0.0487408191, + 0.1535460949, 0.3320425153, -0.157616213, -0.659006834, -0.0338018723, 0.4617294669, 0.10086146, -1.274196744, + -0.3311012089, 1.3876305819, 0.9555911422, -0.8060911894, -0.4946635365, 0.9969357848, -0.1563356966, 0.2311514914, + 0.8098935485, 0.114401415, 0.3466364443, 1.6067898273, -0.4078532457, 0.8250998259, 1.1099538803, -0.0130652459, + -0.813041389, -1.2216724157, -1.2805823088, -0.7013052702, -1.1525663137, 0.5510089397, 1.4384489059, -0.0168083627, + -0.2640907764, 0.5070714951, -0.6443662643, 1.8311312199, 0.6864961386, -0.1773331016, 0.2223710716, -0.0704963654, + -0.9840225577, -0.3356443942, 1.0691854954, 0.1201403961, 0.5101134777, -0.8782663941, -0.5339717269, -0.9799844623, + 0.7834316492, 0.7693622708, 0.2057720423, -0.3445561528, -1.4284933805, -0.0017824746, 0.975543499, 0.7316427827, + 0.0141161242, -0.0398816057, -1.2709821463, -1.5649716854, -0.3071387112, -0.5473391414, 0.9616869688, 1.5145448446, + -0.7195694447, -0.3944427967, 0.4071395993, 0.1094340906, 1.9397739172, 0.0562009476, 0.5139475465, -0.0046406253, + 0.0536796823, -0.8677092195, -0.7403584719, 0.0448231101, 1.3504319191, -0.3382182717, -1.2779160738, 0.2713087797, + -0.4566406012, 1.0716338158, 0.2072720528, 0.3301466703, -0.2964983284, 0.5896486044, -0.4153626859, 0.5670648217, + 1.1750820875, 1.487398982, -2.3126528263, -0.8691516519, 0.457473278, -0.847524941, 0.8546934128, -0.6666801572, + 0.112912491, 1.2397251129, -0.3301310539, -1.1247928143, 0.1654882878, 0.298913002, -0.2470651269, -0.3026075363, + 0.19218418, -0.1730351001, 0.4377845526, -0.219367072, 0.611402154, 0.6966733932, 0.3748733699, -1.4609225988, + 1.5907051563, 0.9739543796, 0.8248856068, -0.3926510513, 1.5374946594, -1.139316678, -0.2162578404, -0.7730450034, + -0.4251903296, 0.5946242213, -1.1560473442, -1.5628254414, 1.1010065079, 0.2154533267, 0.7111494541, -0.0475142524, + -0.0388706252, -1.2525222301, -0.5174888968, -0.5561483502, -1.1154675484, 0.1784954369, 0.8350765109, -0.4459244013, + -2.4139649868, -0.8504996896, 0.5401726961, 1.978512764, -0.6393229961, -1.3613717556, 2.0546019077, 0.0595806055, + -0.4285869002, 0.9154852033, -0.3232243061, 1.5594203472, -1.1150901318, 2.0952014923, 0.502140522, -0.7830901742, + -0.7693719864, -0.1663081795, 1.4347996712, 0.2960758805, -0.0027330727, 0.2682686448, 0.0127709676, 0.2424747497, + 0.4638241827, 1.788949132, 1.1757079363, -1.0222588778, 2.6014802456, 1.5808367729, -0.2146649361, 0.7575861812, + -0.4495947361, -0.5908117294, 0.5592653751, -1.3259441853, 0.594884634, 0.4069502056, 0.8398963213, -0.4906890988, + 0.6471970677, 0.6398313046, 1.647198081, 1.4133006334, 0.8426824808, 1.0106039047, 1.0245624781, 0.094432123, + 1.4529879093, -0.6713413, -1.5175800323, 2.1336538792, 0.7717633247, 0.6927742362, -0.4853357077, 1.3379818201, + -1.6785788536, -1.0422717333, 0.5675963759, 1.6423405409, 0.1245919019, 0.9202539921, 0.0586088188, 0.4284663498, + 0.1830497682, -0.1064387262, 2.5498642921, 0.1319633871, -0.8298854828, 0.2510634661, -0.8929324746, 0.6934131384, + 0.8412130475, -0.3025356829, -1.3898062706, 0.7125902176, -1.8900271654, -1.2866756916, 0.3507175446, 1.0069307089, + 0.3439614475, -0.4223397672, 0.4167747498, -0.6913272738, 1.3721678257, 0.1986006349, -0.503113091, 1.3957043886, + 0.4102612138, 0.7169515491, -0.6730329394, -1.6226317883, 2.085852623, 0.0266461149, 1.1714679003, -2.1153361797, + 0.0740644708, -0.6488339305, 0.0858231783, -1.3241528273, -1.0434464216, -0.3803936243, -0.6672549844, -0.1567256898, + -2.313325882, 0.1390058398, -0.4018515348, -0.4512442946, 0.3724332154, -1.1800881624, -1.3332873583, 0.7908762693, + -1.3407357931, 1.6218533516, 0.1306812912, -0.6198000908, 0.0341969095, 0.6919595599, -0.1018244103, 0.3843306005, + 1.255138278, 0.183910653, 1.3701967001, -1.9215074778, 1.5717345476, -1.0818972588, -0.202425763, 0.0068036322, + 0.784630537, -0.4962382913, 3.0493257046, 2.2000374794, 1.3815038204, 0.5984432697, -0.646637857, 0.1070459485, + 0.0651153326, -0.4481697977, 0.4599678218, 1.3020391464, -0.7581306696, -0.275403291, -0.0371919386, -0.5418404341, + 0.7452659607, -1.1534259319, 0.938192606, 0.6659347415, -1.1937292814, -1.5376166105, 0.1310789287, 0.2398359627, + 0.5549139977, 0.2483216375, -0.6198633909, 0.8630862236, -0.1393041015, 1.0174250603, 0.3143958449, 0.0683760419, + 0.031554509, 1.3078721762, 0.4492118359, -0.4071181715, 0.5910757184, 0.374137938, 0.2453961819, -0.8749790192, + 1.2522603273, -0.3844586313, 0.0375177786, -0.6383576989, 0.7360663414, -2.3159997463, -1.3596284389, 0.4820798934, + 0.7575388551, 0.8861390352, 1.0024284124, 0.5143792033, -0.6864389181, -0.7257505059, 1.7803571224, 0.5731166601, + 0.8511525989, 0.8942019343, 0.3404513001, -1.7471883297, 0.865131557, 0.4115097225, 0.9011681676, 1.6878750324, + -1.6129397154, 0.5108485222, -0.2522997558, 0.7438052893, 0.5033487082, -0.4613233209, 0.4820011854, -0.4439652562, + -1.4911876917, -0.3602609336, -1.5907628536, 0.6927799582, -0.1477584839, -1.0334455967, -1.5674887896, 0.4550902545, + 1.5604319572, -1.4422808886, 0.5788357258, -0.2870239317, -0.4004207551, -0.8785344362, -1.4270888567, 0.9402923584, + 0.8992320299, 0.4155126214, -0.8877316117, 1.7329494953, -1.5584703684, 0.2766417265, 0.6156333685, -1.322099328, + 0.7813851833, -0.636836648, -0.6957759261, -0.5995090008, -0.3846778572, -0.0360092148, 0.2149695456, -1.0402828455, + -0.8459938765, -0.9112716317, 1.0995310545, -0.9367135763, -1.9902956486, -0.022774715, -0.4758028686, 0.9322866201, + 0.9273737073, 0.8070508242, -1.7838457823, -0.6699023843, -1.5915911198, -0.2805326581, -1.4233908653, -1.4749735594, + 0.1594439596, 0.0329884961, -0.8356202841, 1.3274855614, 1.0824410915, 1.0488785505, -0.4469273984, -0.9992522001, + -0.9932340384, 0.5085969567, -0.5421534181, 1.9483562708, 1.1397675276, -0.0622630306, 0.1688272506, -0.7671681643, + -1.1403740644, -0.7531850934, 0.3955881298, 0.6842200756, -0.5735817552, -0.5361065269, -0.7205488682, -0.034349829, + 0.471486032, -0.1568353325, 0.5368303061, 0.7607414722, -0.7243655324, -1.3951404095, -0.8374814987, 0.4954386055, + -0.0606812388, -0.668895483, -1.6458029747, 0.6280921698, 0.2495674193, 1.5667924881, 1.3704221249, -0.1882616132, + -0.3503639698, 0.6975366473, 0.4451564252, -0.6488027573, -2.6514444351, -0.9436893463, -1.0788868666, -1.0912772417, + 0.0611912012, -1.4206846952, -0.6495169997, -1.2007901669, -1.336017251, -0.0519311912, -1.2045214176, -1.1121664047, + 0.6280339956, -0.504868865, -0.4457834363, -0.4472849965, 1.1495735645, -0.5288956165, 1.2007362843, -0.4974692166, + -0.3109487891, -0.9244396687, -0.2693705857, -1.0468840599, -0.6721541286, 0.5465496778, 0.0884050056, -0.4098713398, + -1.0514574051, 1.4148094654, -0.4750121534, 0.6167279482, 0.9246222377, -0.4253928065, -0.6544781923, 0.7891964912, + 0.3140968978, 0.7648479939, -0.1695642024, -0.1479424685, -0.106425032, -2.2116746902, 2.3312244415, -0.667652905, + -0.9457675815, 0.9474021792, 0.7973690629, 0.1704794019, -0.7035692334, 0.7092891932, -1.8698717356, -0.2639527023, + 0.2181621939, -0.4548698962, 1.5478996038, -0.4820409119, 0.689889133, 0.6085611582, 0.019384183, 1.8152153492, + -1.6339917183, -1.333770752, -0.5393002033, 0.1599944085, 0.4317499101, -1.7887134552, 0.7140734196, -0.8148634434, + -0.4388350248, 0.6136690378, -0.8982139826, 2.4423866272, -0.9562060833, -1.4921243191, -1.753105402, -1.9354444742, + 0.1809691191, -0.9431200027, 0.1708678603, -1.913851738, -1.3267153502, -0.82376647, -0.1747481823, 0.8606752753, + 0.8452942967, -0.3969329, -0.7858321071, -1.0196638107, 0.1269257069, 1.0621590614, 1.530687809, -1.5189861059, + 0.9269375205, 1.2335311174, -0.4745801091, -0.6515474916, 0.7936541438, -1.3056498766, 0.2814712524, 1.4409999847, + 0.8073496222, -1.8721452951, 0.1184589267, 0.8932977319, -0.5317001343, 1.8536045551, -2.7512083054, -1.3216940165, + -1.3283517361, -1.1938714981, -1.2970254421, 1.1642961502, 0.3630233407, -1.1360250711, 0.4634298086, 0.2409296781, + -0.978255868, 1.8368214369, -0.092891112, 1.22283113, -0.4003975093, -0.3872050047, -0.2419685572, 0.1414249092, + -0.3762511015, 0.1452577263, -0.2219312191, 0.7660420537, -0.788363874, -1.6409637928, 1.1355031729, 1.3309619427, + -0.9560182691, 0.4649753571, 1.1633868217, -1.4728108644, 0.2295930833, -0.1990584433, 0.3435695469, 0.8488633037, + -0.3607235849, -1.8055906296, 0.2481548339, 0.7938757539, -1.8822200298, 1.2305692434, 0.9074109793, -0.3646234274, + 2.420481205, -0.8100681305, -0.592916429, 0.8905769587, -0.7271680236, 0.3828736246, 1.030172348, 0.7428522706, + 1.0397125483, 0.5743683577, 0.9277793765, 0.3855857253, -0.4105027914, 0.5453033447, 1.5967614651, -0.2897183895, + -0.9443405867, 0.9612666965, -0.2591313124, 0.7493833899, 0.9668287635, 2.2179422379, 1.4288818836, -0.3036374748, + 0.3314071596, 0.1685507894, -1.0392718315, 0.5757080317, 1.8846974373, -1.0078357458, 0.457788229, 1.0183068514, + -0.7346784472, -0.4650122225, 0.0640585124, -0.789033711, 0.7123513818, -2.1669125557, -0.7675073147, -0.9449701309, + 0.8574027419, 0.7751913667, 0.1898535192, 1.6693571806, -0.3673186004, -0.0210592635, 0.4653729498, -0.6247548461, + 0.1980665624, 0.737804234, -1.038138032, 0.8246774077, -0.1759186089, 0.6200713515, 0.3294046819, 0.2967543006, + -1.0276694298, 0.0227232017, 1.1291382313, -0.628159821, 0.804377079, 1.0822321177, -0.1657423079, -0.0776807144, + -0.1167014837, 0.3684995174, 1.9841905832, 0.4295887053, 0.6405870318, 0.6379342079, 0.8725138903, 0.3877270222, + 0.8504217863, -0.0968416929, -2.1198146343, 1.415941596, -0.3126500249, 1.5506500006, 1.0458365679, -0.3016704917, + -0.2235870957, -1.2391153574, -0.585118413, 0.5509126782, 0.4651997685, -0.4118579626, 1.5482922792, -0.0040421048, + -0.9912667274, 0.0142603684, 0.8469740152, 0.1916214526, -0.0247817542, -0.0518606752, -0.7906127572, 0.6237937212, + -0.2116433233, 1.8560798168, 0.6758502126, 0.432385534, -0.5427485704, -0.2471507788, 0.826669991, -1.2941006422, + 0.0277775917, -0.0114485594, -0.1420166045, 0.49240008, 0.4590295553, 2.5640699863, 0.3363261521, -1.5822482109, + -1.6178342104, 1.3771090508, 1.1515468359, -0.959502995, 1.7391210794, 0.6310431361, -0.818125248, 0.3020314276, + -0.802996695, 0.6402264833, 1.1647168398, -0.8939806223, 0.1350935549, -1.0642356873, -0.5717391372, -0.6346552372, + 0.5374536514, 1.3573206663, -0.3348610401, -1.6466457844, -1.3988031149, 0.6637595892, -1.4271485806, 0.4709821343, + -1.4963316917, 1.3809591532, 0.3187876642, 1.092176199, -2.2258255482, -0.504535675, -0.7421919107, -0.2157391161, + 0.7126739621, 0.6691911817, -1.1976441145, -0.8853336573, 0.824621141, -0.9868354797, -0.0254206806, 0.0362228155, + -0.1663735956, -0.9848557711, 0.7515419722, -0.7585852742, -1.0937254429, -0.1821856797, -0.6961805224, 0.333485961, + 0.4389159083, 0.2469871491, -2.0076756477, 0.4291914105, -1.2334452868, 1.3440158367, 0.0627860799, -0.9219018817, + -1.2558528185, -1.9622758627, 0.1995464712, 0.4981423914, -0.5179405808, 1.9443092346, -0.423240006, 0.0491162017, + -1.3236367702, -0.6165354848, 0.7170464396, 0.1112871245, -0.8130300641, 0.2534252405, 0.5796111226, 1.9850246906, + 0.4960811436, -0.2429900765, -0.4833355546, 0.6328579187, -0.6804760098, -0.1585241705, 0.3408620358, -0.4281844199, + -0.844176352, -0.8560928702, -0.5648352504, 0.0108333835, 0.3450529873, 0.7727462053, 0.5534866452, 1.6443219185, + 0.5270298719, 0.2769190669, -1.0014778376, 0.5765803456, -0.8796996474, 0.56878829, -0.0461753644, -1.2852069139, + 0.722194612, -2.7615418434, 0.0332008004, 0.2197542191, -0.299560219, -0.0586884245, 1.8317363262, -0.6810992956, + 1.508402586, 0.3555968106, -0.2981703579, 0.9358145595, 1.9291380644, 1.2278101444, -0.2416273504, -1.093652606, + -0.2135961056, 1.5356572866, 0.9269886017, -0.4677660167, 0.5069100261, -0.578017652, -0.2702128291, -0.5411428213, + -0.3239991665, 1.5921620131, -0.3274900615, 0.0973749086, -0.115943335, -0.7867313027, -1.3489117622, -0.6642484665, + 0.1416206062, -0.3015295565, 0.721963644, -0.5237560272, 0.3400763571, -0.1233913451, -0.2009309828, 0.8506157398, + -2.1546499729, 0.3547619581, -1.6757706404, -0.1415503621, -0.8680157065, -0.0768875107, -0.1592646539, -0.501475513, + 0.0249998868, -1.8573825359, -0.3155896068, 0.5905711651, 1.0066084862, -0.5826127529, -1.1200389862, 0.1239113286, + -0.4321572483, 0.2175883204, -0.167937845, 0.6261950731, 0.5056493878, -3.1710517406, -0.1413709968, 0.6767768264, + 0.3793789148, 0.3022807539, 0.7109302282, 0.2650648355, -1.0345375538, -1.64689219, 1.0483371019, 1.0237673521, + 0.3251764774, 1.2741376162, 0.2375988215, -0.7581788301, -0.5037139058, 0.0572597869, -0.8450796008, -1.1608557701, + -1.0911349058, -0.5320959091, 0.9157405496, 0.4893115759, 1.6712793112, -0.5092890263, -0.969032526, 1.4766815901, + 0.7314090729, -2.469050169, -1.3202705383, -0.330122292, 0.8962110281, 2.0390863419, 1.0254950523, 0.169573471, + -0.2835012674, -1.0160237551, -0.2788228989, -0.0651427954, -0.3828991652, 0.2328362316, -0.772413075, 0.5774948001, + -1.8650261164, 0.2756900489, -1.3820643425, -1.4922863245, -0.3723741472, -2.075343132, -1.7942260504, -0.347008884, + 1.7341159582, 0.8438899517, 1.0441874266, 1.4977054596, 1.0677449703, 0.1652990133, -0.1096124351, 0.1542658657, + -0.0562523417, -0.0727530718, -1.1196274757, 1.4136055708, -0.4164610803, -2.0809350014, 0.0478956066, 0.9895527959, + -0.8603312373, -0.6730191708, -0.580295682, 0.780267477, -0.9864706397, -1.9121707678, 0.6803776622, 0.1682149619, + -0.7673743367, 0.7056384087, -1.0421631336, -0.3231330812, -0.9202150106, -1.7474627495, -1.6890426874, -0.0504816063, + -0.7599089146, 0.6442566514, -1.418088913, 0.8134864569, 0.3692963719, 0.394467026, 0.1946570277, 1.3176888227, + 1.3182153702, -1.4753251076, 0.2395100147, -2.1885092258, 1.0353777409, 0.4226379693, 2.4927759171, -0.7165281773, + -1.2685643435, 0.7180500031, -1.0596232414, -0.1318729967, 1.2955181599, 1.4145418406, 0.3703507483, -0.2906166613, + -2.1202604771, 1.5874541998, -0.4480857253, 0.1233151332, 1.272590518, -0.4341225624, 0.8674485683, 2.0624625683, + 0.5839276314, 1.454433322, 0.3140803874, -1.1686724424, 1.4655153751, -0.1854373813, 0.0675033107, -0.1820190549, + 1.3975430727, 0.3684431016, -0.5828213096, 1.6327118874, -0.5973852277, 0.6849465966, -0.50439924, 3.1433739662, + 1.0341066122, 0.1156917736, 1.5954945087, 2.6153404713, 0.6946935058, 1.7668703794, 1.1358177662, -0.5453659892, + 0.321639806, -0.3820880949, -0.7366890311, -0.561440289, -0.6733281612, 0.51567626, -1.2313117981, 0.5289177299, + 1.3301786184, -1.70236516, -0.9341116548, -0.8916813135, -1.1652710438, -0.1437996477, 0.9670381546, 0.2372026592, + 2.4822874069, 0.5470020175, 0.4206858873, 2.6281704903, -1.5163463354, -0.5004493594, 1.2942957878, 0.617346406, + 0.2298103869, 0.435662508, 0.3032996058, 1.1061048508, -0.3733479083, -1.9930585623, 1.1398425102, 1.1698259115, + -1.224106431, 0.789984107, 0.238367945, -0.7305232286, -0.4423871934, 0.796492219, -0.4245458543, 0.3769742846, + -1.8120678663, 0.5874359608, -0.0313255563, -0.7554463744, 0.6911882162, -2.2524123192, 0.5145077705, -0.4655631483, + -0.5376864076, -1.6770755053, -0.6433816552, -0.0429741144, 1.1280231476, 1.1490014791, -0.0671586543, -1.2202082872, + 0.7045454979, -1.0823764801, 0.1428896487, -2.9295396805, 0.6375863552, -1.7725259066, 0.6920745373, 0.0506045334, + -1.8579263687, 1.0407875776, -0.136007458, -0.8596337438, 0.0067301448, -0.1954611391, -0.1238392219, -0.8143445253, + -0.6136426926, -0.9348247051, 0.4640007019, 0.7521933913, 0.6640645862, -0.1378400475, 1.1553994417, 1.0206215382, + 0.398673594, -0.4069051743, -0.0785310194, 0.4717287719, 0.2707085907, 0.1270379424, -0.4223307371, -0.3201220334, + -0.3389673233, 0.4850408137, 0.4809367359, 0.2361204922, -1.0482326746, 1.0621023178, -0.1028745249, 0.1858724207, + 0.3908754587, -0.6750885248, 0.2174529731, -1.0515180826, 0.2160267383, 0.2982191145, 0.8590397835, 0.0086025409, + 0.5641648173, 0.4481794834, -0.6979264021, 0.3443371356, 0.3175536394, 1.2855532169, -0.7491867542, 0.3338579834, + 0.7577729821, 0.3670987785, 0.2343304902, -1.9538394213, 0.7163391709, 0.3700796068, -1.7885614634, -0.9458172917, + 3.0109028816, 1.4560543299, 0.6147252321, 0.692037344, 0.6372101307, -1.3865582943, -1.7684077024, 0.5304525495, + -0.0079795672, 0.8801140785, 0.9465383291, 0.1581633389, -0.8426349163, 0.9479221702, -0.135411948, -1.5711832047, + -0.3637903631, 0.4112898111, 0.160242632, -0.1830785424, 0.7868187428, 0.4419188499, 0.0504920371, -2.2241265774, + -0.6185190678, -1.1892626286, 0.6705932617, 1.0291326046, 3.0448400974, -0.8008592725, 0.9581548572, 1.3260705471, + 1.1762444973, -0.9842439294, 2.0668766499, -0.3960740864, -0.1752684265, -0.7192801237, -1.4173226357, -0.5742908716, + -1.1648813486, 0.9344018698, -0.1113579199, 1.6854794025, 0.3993677199, -1.1008958817, -0.5278835297, -0.7492056489, + 0.7847382426, 0.4598958194, 1.8640118837, 0.4370495081, -0.9409788847, -0.5925995708, 1.2170940638, -0.493217051, + 0.7076863647, 1.2122285366, 1.3748151064, -1.1437553167, 0.1958882958, 0.1235001981, 0.0688811988, -2.385999918, + -0.574528873, 1.7441747189, -0.8688986301, 0.6938255429, 0.2857529819, 0.0937574208, -0.6805610657, 0.671264708, + -0.2787623405, -1.1043686867, -2.3983387947, -0.8090463281, -1.0024791956, -1.1571393013, 0.3918244541, 0.309342742, + 1.142587781, 0.9271572828, 0.705199182, 1.212475419, -0.4664890766, 0.003758874, 1.7412911654, -0.4158358276, + -1.5634813309, -1.3250594139, -0.2688057721, 0.2384223789, -0.5030126572, 0.855312705, 0.4374273419, 1.1957253218, + 0.046266675, -1.8070065975, -0.4504835904, -1.368678093, -0.305847466, -0.0495945141, 0.1645372808, 0.1849104613, + -1.7716939449, 2.3738782406, -0.1378646493, 2.4643244743, 0.5075989962, -0.1704922765, -0.0185646489, -0.0093221944, + 2.1728961468, 0.9254801273, -0.5384533405, 0.9051353931, 0.3683229089, -0.8445315957, -0.3709745407, -0.9525077939, + 0.6499077082, -0.0273034014, -0.4088584185, 2.1410124302, 0.8542435765, 0.965090394, -0.6568892002, 1.6100125313, + 0.7433479428, -1.6218360662, 1.149772048, -2.6727676392, 0.3415644169, -0.4711919725, -0.4807176888, 2.3651483059, + -1.6804189682, -0.7778606415, -0.5134579539, 0.8294714689, 0.3388239145, 0.5550401807, 0.3536906242, 0.8353669047, + -1.1603729725, -0.9736599326, 1.4669877291, 1.6135033369, -0.1117185876, -0.3129193783, 1.0819211006, -0.7731477618, + 1.1307908297, -0.6786795259, 0.2116177529, -0.073723726, -0.4597691596, -1.1927083731, -1.3991508484, -0.2123755366, + -1.209852457, 1.4069837332, -0.2333389074, 0.0752018467, 1.4358216524, -1.512827754, 0.406149894, -0.7061683536, + 0.2710811794, 1.2111703157, -0.4321515858, -0.3260831237, 0.0225785729, 0.2212020308, 1.410451889, 0.2452560216, + -1.5462257862, -1.2980943918, -0.1110542938, 1.1513741016, -0.348947227, -0.8876929283, -1.0408627987, 0.438375622, + -1.5169585943, 0.4438357651, -0.3842916191, 2.2116289139, 0.2712109387, -1.6035920382, 1.0682024956, 1.223680377, + 0.5410172343, -0.5111415982, -1.3180493116, 0.4625207186, -0.0136173591, -0.5168929696, 2.295532465, -1.3852297068, + 0.6380922794, 0.0593690909, 1.6699051857, -1.6007295847, -0.337901324, 1.0723598003, -0.9798635244, 0.8318992853, + -0.8471778035, 0.3142752051, 0.528488636, 1.1218874454, 1.8486001492, 2.7345709801, 0.4374895692, -1.2230619192, + -0.2786168754, 1.1966751814, 0.7694658041, -0.4521544278, -0.4873460531, 0.0760180429, -2.1347806454, 0.9052285552, + -0.5944761634, -0.3380056322, -0.1664792448, 0.5691460371, -0.5731565952, -2.200050354, 0.0652889013, 0.943287313, + 0.3104563355, 0.5494231582, -0.9663535953, -0.5229769349, -0.2445623577, 0.5183826685, -0.9060575366, -0.9137417674, + -0.1996527612, 0.1335192323, -0.443382442, 0.337777853, -1.6413617134, -1.7930675745, -0.1941461861, -1.8694553375, + -0.9999119043, -1.4513466358, 0.6723552942, 0.1838610321, 0.7941121459, -1.1660890579, -0.8116760254, -0.943413198, + -1.1249563694, -1.1655663252, 0.6973057985, -0.6014246345, 1.2728025913, 0.1407245845, 0.8612917066, -0.2324358374, + 1.4373520613, 0.8628004193, 1.5325776339, -0.188939482, -0.5824972987, -0.9653490782, 1.3446065187, -0.7162488699, + -0.1897031218, 2.0714435577, -0.612103045, 2.0374407768, -1.4945025444, -0.2567083538, -0.897205472, 0.1291142851, + -0.303760469, -0.8362293243, 0.706898272, -0.4486835897, 0.2427803576, 1.0932581425, -0.1559365541, 0.7241747379, + -0.7676721215, 1.5684889555, 0.7923648953, 0.95028615, -0.3227502108, -1.2624378204, 0.2234718055, 0.4752887785, + 0.2963661849, 0.2820369303, -1.3083859682, -1.8737363815, -0.3256417215, -0.1815035492, 0.3622895777, -0.2257685065, + 0.1857555956, 0.0977337956, -1.1289507151, -0.102993086, 0.0768001899, -1.2031559944, -0.1173039898, 0.0196279101, + -0.2452402562, 1.1445440054, -0.7530807257, -0.6296615005, -1.0584937334, 0.7693899274, 0.8202177286, -0.3264771104, + 1.0771063566, -0.4935064316, -0.5727998614, 0.1287579536, -0.9393902421, 0.9558954239, 0.7553883195, 0.6227222681, + -0.008468275, 0.2514541149, 0.8778777122, 1.0188686848, -0.2856886983, -1.8559024334, 0.0303529315, 0.1430030465, + -0.3618414998, -0.0351615176, -0.6785556078, -0.9759765863, -0.4848660827, -0.2929255962, -0.192584902, -0.7591896653, + -0.3228958249, -0.0205045063, 0.3483543694, 0.2820397615, -1.699509263, -0.7122277021, -1.391795516, 0.5476497412, + -0.3970116079, -0.0744653568, -1.1424483061, 1.3950189352, 1.2138121128, 0.7932989001, 0.3546606302, -0.163401559, + 1.4944585562, 0.7755617499, 0.7647002339, 1.2824169397, 0.3859403133, -0.1856594533, -0.9363436103, 0.4315616786, + -0.2700640857, 0.3939462602, 1.4889338017, 1.029790163, 2.0167706013, -0.5965355635, -0.8565047979, -0.9398768544, + 0.2297771126, -0.557441771, -0.1267592162, -2.3832242489, 1.1377506256, -1.1425361633, -0.524620235, -1.5346717834, + 0.1314383298, 0.0684951022, 1.1131851673, 0.2731709778, 0.6787238121, -0.5446536541, 0.0450214595, 0.8453890085, + 1.8095526695, -0.2790301442, 1.1491837502, -0.4293262064, -1.3085041046, 1.083266139, 1.3500005007, 1.1210151911, + 0.5666023493, -0.459720552, 1.0817568302, 0.7697666287, 0.8304558992, -0.2385064662, 0.8480877876, -0.7320706248, + -0.5562512279, -1.0011099577, 0.5937754512, -0.8616179228, 0.8863510489, 1.6711868048, 1.0623165369, 0.6543915868, + -0.1773722172, -0.0344006717, 0.5973542929, 1.2686825991, -1.5581994057, -1.1329184771, -1.2591944933, -0.695250392, + 2.6306145191, -2.2633259296, 1.0291699171, 0.9703497291, 0.7907989621, -0.9672769904, -0.7324648499, 0.5958577991, + 0.2923487723, 0.0744326934, 1.4750037193, -0.1998525858, -0.1739941984, -1.8254380226, 0.3562199175, 0.7012470961, + -0.2482330352, 0.4486927986, 0.0901318491, 0.7526713014, 0.2792355716, 0.525136888, 0.3370932341, 0.6470039487, + -1.2970519066, -1.4007022381, -0.9944904447, 1.5340650082, 0.7310197949, -1.6445587873, 0.4814043939, -0.5434415936, + -0.9484261274, -1.4867604971, -0.5797979832, -0.1667503268, -1.4086076021, 0.9149457216, 0.4772666395, -0.6579295397, + -2.5258929729, -1.9978051186, -0.2341778129, 1.2802121639, 1.7618249655, -0.8002349138, 0.373608917, 1.108386755, + 0.1761967391, 0.4046993256, 0.9638820887, 0.8057360649, 0.8382278085, -0.0438889638, -0.2375431359, -2.0383751392, + -1.0941091776, 1.5616539717, -2.0328569412, -0.9788680673, -0.6005727053, -0.5285338163, 2.7921683788, -0.714540422, + -0.8009266257, -0.2848567963, 0.6346355081, -0.4794748127, 1.5668632984, -2.405538559, 0.4379455149, 0.5932794213, + 0.6854198575, 0.9216139317, -0.3407145441, -1.3855520487, -0.7462887764, -0.3033876419, 0.0186376907, -0.0690334588, + -0.2632014751, 1.6265926361, 1.4949783087, -0.6602244377, -0.7783056498, -1.3226950169, 1.5882486105, -0.0956622288, + 0.7664166093, -0.5125342011, -0.7737212777, 0.6168346405, 0.7540829182, 1.1455770731, 0.3315310776, -0.1345494241, + -1.5078363419, 1.8647091389, 1.8537608385, -1.0891287327, -0.5876540542, -0.3828836977, 0.5380443931, 1.4859291315, + 0.1173877418, -0.0830619484, -0.2604106069, 0.9005637169, 0.1149029881, -0.8461684585, 0.964666605, -1.3376936913, + 2.1376085281, 2.3744444847, -0.1123782471, -0.6790237427, -0.2712702751, -1.2458635569, -0.279918462, -0.0585089289, + 1.2172613144, -1.3013261557, 0.4938486814, 0.0018817389, 0.1639826447, -0.1096468046, 0.1895873547, 0.665381074, + 1.379463315, 0.3325508237, -0.3157938123, -0.4053605795, -1.2119607925, 1.6195567846, 1.0380227566, 0.0044104871, + 1.2443182468, -0.5239819884, -3.1816990376, -1.602283597, -1.0422313213, 1.6971408129, -0.1422895491, -0.3386924267, + 0.0337778777, 1.3895584345, -0.6798459888, -0.8735042214, 1.460821867, 0.9804942608, -0.0700358227, -2.2575590611, + -0.5207765102, -0.5970131755, 1.4351145029, 0.5342422128, -0.5326063633, -1.2744994164, -1.6573332548, 0.1688603461, + 0.8684266806, -0.4371896982, 1.9104814529, -0.1397882998, 0.7860920429, 0.3916041851, 0.1504721791, -1.0214750767, + 0.2536700964, 0.0443325303, 0.485170722, 0.0727755502, -0.1179084405, 1.6902691126, 0.2719678283, -1.193975091, + -0.0545632914, -1.5358672142, -0.0898130834, 1.1942884922, 0.9992315173, 1.0113880634, -1.4582569599, 0.6580271721, + -0.8810248375, 0.7868432999, 0.6703838706, -0.4072601795, 0.8141466379, 0.7604040504, 0.2462893724, 0.00502352, + -0.7474465966, 0.6245143414, -1.0206460953, -0.8153722286, 1.1893461943, 0.4940040112, 0.4967643023, -0.2958534658, + 1.8670926094, 1.3553891182, -1.0535255671, -0.1981259435, -0.3524850905, -0.6183097363, -0.0779046416, 0.7972301245, + -0.5016496778, 0.4480767846, -0.2101167887, -0.0168276727, -0.2014111727, -0.5612958074, 1.3728827238, -0.3534809053, + 1.5735669136, 0.9426801205, -0.0221692715, -0.9934756756, 1.4621682167, -1.4462176561, -1.5750948191, -0.2356135994, + -0.3192728162, 1.409774065, 0.3186092973, -0.0515878908, 0.4262378216, -0.0413998328, -0.7294147015, 0.5786992311, + 0.5278693438, -0.2732734382, -0.0219900087, -0.5813630223, 1.7156662941, -0.3235935867, 2.4618074894, -0.6561592817, + 0.091040045, 1.2659327984, 0.8638816476, 1.0664783716, -1.2248061895, 0.6043577194, 1.0140352249, 0.4129702151, + -0.5681805015, -0.0218119808, 1.322513938, -0.0147479223, 0.0736440644, 1.1261093616, 1.4245935678, 0.9596525431, + 0.5288068652, 1.17108953, -0.7957918644, -0.1596978903, -1.3176041842, -0.3115763068, -0.0672747642, -0.3569861352, + 0.223451823, 0.3094016016, 0.9527436495, -1.2522807121, -1.2509135008, -1.6274449825, -1.2778787613, -1.091137886, + 0.2284249663, -0.3604622483, 1.1675195694, 2.0061020851, 0.7697836161, -0.9829636216, -2.200953722, -0.1629348844, + -0.7106205821, -0.4898200333, -1.4288221598, 1.0543422699, 0.1862355769, -1.5556902885, -0.2575588226, 0.580738008, + -1.8932569027, -0.4353618026, 1.5906252861, -0.996563077, -2.0895090103, 0.9025256634, 0.3491262496, -1.4236516953, + 0.1656542122, 0.2637915611, -2.3229284286, -0.7769226432, -0.4434509277, 0.2784052789, -1.7719700336, 1.9006904364, + -0.3290591836, 0.4922101796, -0.5404827595, -0.946156323, 0.644000411, -0.3489286602, -0.9171313643, 0.4032333195, + 0.5990763307, -1.7341868877, 1.2567689419, -0.2003704309, 1.5010881424, -0.1889965534, -0.6302958727, 0.1775143445, + 0.2809249461, 1.7796574831, 0.4534760118, 0.1546487063, -1.5418481827, -0.5078651905, -0.8182194233, 1.2638050318, + -0.1745502055, -0.4214827716, -1.0797538757, -0.1164133102, -0.741081655, -1.3497550488, -0.1168411151, -1.3411626816, + -2.0407903194, -1.227563262, -1.3231233358, 0.0243034586, 0.4815312326, 1.4609789848, -1.4686429501, 0.1677938551, + -1.0592018366, -0.2852744162, -0.0706676841, -0.1581604034, 0.9220636487, -0.1272540987, -0.2593966126, -1.7004094124, + -0.5371990204, -0.7370152473, -0.0971123576, -0.3767374456, 2.3517546654, 2.6098873615, 0.4989961088, 0.0687675998, + -0.3759937584, -0.8398221731, 0.9545980692, -1.4972980022, -0.9398316145, 1.1029561758, 0.2521598339, -0.0855884403, + -0.9977290034, 0.800835669, 1.574046731, 0.4187212586, 1.9298514128, 0.1145944372, -1.1502786875, 0.04346288, + -0.1572289616, 1.0625115633, -0.8050823808, 0.203238681, -0.0399338417, 0.5518578291, 0.8568918109, 1.7390502691, + 0.6615341306, -0.5819038749, -1.2263169289, 0.1351081878, -0.1532971412, 0.2919063568, 0.6675716043, -0.0507290736, + -0.6389257908, -0.1211285144, -0.1745242774, -0.2457411587, 0.2195800394, 0.6483494043, -2.5658056736, 0.9271953106, + -0.3155171871, 0.2342108935, -0.4574358165, 1.2141743898, 2.0983936787, 1.2039935589, -0.128772378, -0.0756367967, + -0.2917146683, -1.5107499361, -0.0836014524, 0.7631447315, 1.9176464081, -0.509134531, 0.0782249793, 0.1212063432, + 0.6442352533, -0.7711468339, 0.5957395434, 0.2253505737, -0.9019545317, 0.5706453919, -0.5385786891, 0.9147205949, + -0.7850139737, -0.1509184986, 1.2764766216, -0.5555887818, 0.5547939539, 1.4719022512, -0.2048540562, 0.163212955, + -1.7694426775, 0.36388731, 0.2493520528, -0.5556089282, 0.6050454974, -1.177803278, 1.2873336077, -2.7311754227, + -1.8287607431, -0.3213097453, 0.2433038205, -1.2711951733, 0.2429094762, 1.5860184431, 1.2297668457, 0.9442595243, + -0.8065596819, -1.2923262119, 0.850107789, 0.370593667, 1.401083231, -0.4744163156, -0.2130869031, -1.9867215157, + 1.2959045172, -1.9881888628, 0.1270659864, 1.1208313704, -0.1007476598, -1.1433990002, 0.1744137406, 0.2917715907, + 0.251193732, 1.7150257826, 0.928000927, 1.1453393698, -0.3360704184, 0.4720384777, -0.3854337335, -0.4944903851, + 1.6074732542, -0.7994801998, 1.4878766537, -0.0383373089, -0.4597311318, 0.4766893387, 0.7497329712, 0.7272310853, + -0.5855666399, -0.1302246153, 0.3075602651, -2.5834276676, 1.1175756454, 1.2175463438, -0.4559751749, -1.0002273321, + -0.4586575031, -1.1881129742, -1.0883032084, 0.4656453729, 0.193144843, -1.4194663763, -0.1684705317, -0.0929002762, + 1.4055173397, 0.1011286005, -0.2336747944, -0.7242429256, -0.4713487029, -1.6743985415, -0.4759764373, 0.6226197481, + -1.036077261, -0.737475872, 0.3776315451, 0.7032527328, 0.3570717871, 1.6821124554, -0.7404009104, -0.6392166018, + -1.8168293238, -0.2498717159, 0.9376166463, 0.3249538541, 1.8151599169, -0.8932920694, 0.8224828243, 0.2315905243, + -0.44716084, 0.3912411332, 0.986790657, -0.1927725524, -0.5247645974, -1.5280073881, -0.149546653, 0.0160353705, + 0.0425342433, 0.715267837, 0.3655344248, -0.9652132392, -0.8394863605, -2.0853965282, 1.5263340473, 0.8999857306, + -0.9665651917, 1.3215459585, 1.6256463528, -0.6425731182, -0.300286293, 1.3954046965, -2.0651483536, 0.3873505294, + 1.7838572264, 0.8483130932, 0.7518290877, 0.5456620455, 1.5536112785, -1.3005512953, -0.0011652977, 1.1804986, + -0.3673217297, 0.0885236189, 0.8989169002, -2.2710711956, 0.1494538188, -0.0522320829, -0.7923706174, 0.2892282903, + -0.2980457246, -1.0174229145, 0.9635899067, -0.8385112286, 0.613693893, 0.2540693581, -0.9374857545, 0.9380664825, + 0.118103303, 1.1129386425, 0.9579056501, -0.9558597207, 1.0601702929, 0.7341737747, 0.2400165498, 1.3471019268, + 1.6240410805, 0.8954927325, -0.2616872191, -1.5816322565, -0.2222897261, 0.1012802795, -0.6242704988, 0.4884990752, + 0.9954836369, 1.213111043, -0.7540560365, -1.005181551, 0.6316062212, -0.3438287973, 0.2564253211, -0.3662753701, + -0.4446938932, 0.6212993264, 0.5648611188, -0.1582486629, -0.5771440864, 1.294560194, 1.422223568, 0.9416752458, + 0.6796181798, 0.1929067373, -0.8631902337, -0.006578777, -0.2801783681, 0.1711493433, 1.6927223206, 1.9421662092, + -0.6135012507, 1.3712947369, -0.6469724178, 0.0916923508, -2.0832099915, 0.3947067261, -1.032867074, 1.3029398918, + 0.2731808722, 0.1960372478, 1.0402327776, -0.0111813899, -0.0176756624, 1.65817523, 0.6408863068, 0.2431170642, + 0.1895090193, 0.5048427582, 0.7047714591, 0.9869223833, 0.2082526386, -0.1569980681, 1.8514502048, -0.1799520552, + 0.4686902165, -0.7296008468, 0.9013362527, -0.1100251153, -1.0055503845, -0.9817690253, 0.8043930531, 0.5625268221, + 1.871991396, -1.146314621, -0.0346449055, 0.1817469299, 0.9270682931, -0.2574214339, -0.0812553093, -0.5912104845, + -0.3345954716, -0.8301431537, 1.0862048864, -0.7808485031, -0.0158352572, -0.3031056821, 1.6571618319, -0.8905954361, + 0.0837379172, 0.6826679111, 0.5788830519, 0.216819033, 0.5412689447, 1.2712599039, 0.7540125847, 0.6827997565, + -2.8907747269, -1.5387016535, -1.5241500139, -0.3924700022, 0.089230381, -0.5330017805, -1.7088195086, -0.1490052342, + -0.3517466784, -2.0205872059, 0.701213181, 0.9212424755, -1.2042565346, -0.8458803892, 1.0954351425, 0.1554866433, + 0.6053807735, -1.4512552023, -0.0093505876, 0.715982914, 1.6241915226, -1.0060654879, 0.5553455949, -1.4876133204, + -0.980558753, -0.6491589546, 0.0377813093, -0.4374382496, -0.4266566336, -2.0373737812, -0.3526954651, -1.3506067991, + 0.7612988949, -1.132660985, -0.2315673083, 0.4062868357, -0.4989110529, -0.0301045813, -0.2450016141, 1.1841666698, + 1.1055570841, -0.31159091, 1.5708198547, 0.0280597452, 0.0123594552, 0.4701385498, -2.1805176735, -0.4992506504, + -1.801261425, 0.6283216476, -0.8813948631, 0.6601570845, 1.7074941397, -0.0323648006, 0.8825834394, 1.391237855, + -1.6596704721, -1.6631295681, 0.8406025767, 0.0631161332, 0.1085712463, 2.0449030399, 0.0345824733, 1.1145036221, + 0.4704167247, -0.1383501887, -0.4539908171, -0.0641246885, -0.3558729589, -0.9145979285, 2.0010707378, 1.6858053207, + 0.3380937576, -1.3622864485, 1.6141508818, -1.9733695984, 0.9540565014, -2.1892340183, 1.3951656818, -0.5408843756, + 0.6286481619, -0.7919251323, 0.0105986586, 0.847881794, 0.0002034874, -0.9074158669, 1.5799069405, -0.2770311236, + 1.0688809156, 0.9766724706, -0.7193752527, -0.4294345379, -0.1861296296, 0.7368682027, -0.1072331071, -0.8955709338, + -0.2778291702, -0.2356924266, 0.0711850822, -0.6330330372, 0.2691031694, -0.5513830781, -0.7187303901, 0.0601756237, + -1.5095027685, 0.8429980874, 0.4193808436, 0.0188407283, 1.1542465687, 0.9463533759, -2.3277208805, 3.1905584335, + -0.8127261996, 1.6442073584, 1.6567442417, -0.8463044763, 0.1784670353, -2.0980811119, 0.8293775916, 1.9536508322, + -0.7747604847, 1.139804244, 0.9690032005, -0.2423246056, 1.3939158916, 0.145404622, 1.7181164026, 0.0453010388, + -0.0042198766, -1.3608663082, -0.5003177524, -0.8680332303, -0.9361079931, -0.3540412188, 1.544303894, 0.1527195871, + 1.9295225143, 0.8829023242, 1.0667285919, 0.7185322046, -0.1005984619, -0.5712147951, -0.2969015241, -1.0879497528, + 0.1453319192, 1.1827607155, -0.6063740849, -0.551472187, 1.3078466654, 0.837927103, -0.6013044119, -0.9620295167, + 1.0878808498, -1.4823607206, 2.0232403278, 0.6163513064, 0.5846143365, 0.1666686833, 0.4976269603, -0.1785562485, + 0.7540314794, -2.4182591438, 1.3574743271, -0.5127028823, 2.2171654701, 0.8127683997, 1.0364259481, 0.0117332144, + -0.7456771731, -1.8012324572, 0.5935599804, 1.0617488623, 0.1362540573, 0.5942974091, -0.2413583249, 0.8704653382, + 0.6090841293, 0.8453356624, 0.2453041673, -0.7767860293, 0.4689100981, -0.2965798974, -0.2062119991, 0.3263522387, + 0.2172193527, 1.1833193302, 0.2821285129, 2.3209342957, -0.1554056257, 0.1805481464, 1.7754137516, 1.7161456347, + 1.2346943617, -0.8394340277, 0.3948509991, -1.2444956303, 0.7143678665, 0.129547134, -1.6973470449, -0.974058032, + 0.9478079677, 0.0702200681, 0.6023330688, 0.3383901715, -0.5129318237, -0.934630096, -0.2646407187, 0.5493919849, + 0.3167619407, 1.0960144997, -0.1926865131, 1.1150927544, 1.4298577309, 0.563436985, -0.8687397242, 1.0241733789, + -0.7390829921, -2.4886791706, 0.1626223028, -0.0862197801, 2.2243971825, -0.4995155036, 0.1662081778, -0.3019536138, + 1.2557128668, 0.2725491226, -0.4110666811, -2.0384042263, 0.4620322287, -0.9412257075, -0.3955143094, -0.992405951, + 0.1638202667, 0.3578505516, -0.4322696328, -0.7486923337, 1.4323714972, 0.4394994676, 1.2358547449, 0.6357761621, + -1.2816650867, 0.3573113084, -1.6242008209, -1.2238067389, 0.1763255596, 0.7219309211, -1.1676596403, 0.3330031931, + 1.0878335238, -1.0375856161, -0.5326374769, 1.8756786585, 1.5115497112, -1.2856667042, 1.1450330019, -1.0966980457, + 1.1074422598, -0.6321702003, 1.5199065208, -0.506542623, -1.0368436575, -0.0203417726, -1.3390274048, -1.2279171944, + -1.0808128119, 0.3871849775, -0.3497922719, 2.311747551, 0.6136760712, -1.007806778, -0.8818475604, 0.8308844566, + -0.2642922997, -0.8865725398, -0.2153000832, -0.2417999208, -2.1490194798, -0.7199160457, 0.0679587796, -0.2582596838, + -0.8022152185, 0.9388174415, -0.9667415619, 2.2158970833, 0.9668938518, -0.6219958067, -2.9191241264, 0.7569295764, + -0.3887217045, -0.9876939654, -1.3517054319, 1.3579764366, -0.4132209122, -0.3938776553, 1.0867658854, 1.0614277124, + -0.3257678151, 0.5012996197, -0.9414650202, 0.8639216423, -0.1593751311, -0.8448317051, 0.5117835999, -0.084699057, + -0.3059445918, -0.5071154237, -0.5131493211, 0.0728861243, -0.0135237006, -1.0407599211, 0.1897208542, 0.8545592427, + -0.5512021184, 2.0016546249, 2.1962902546, 0.6786051393, 0.6614071727, 0.3245737553, 0.7180817723, 0.5551066399, + 0.0685995594, 0.1573880464, 2.0783345699, 0.5659430623, 2.3344035149, 0.3795775771, -1.1248421669, -0.6414177418, + 2.1331074238, -1.0174721479, 0.3696995974, 1.3464163542, 0.4752027988, 1.4939831495, 0.4542889595, -1.4727809429, + -0.4702996016, -0.3798926771, -0.0606959425, -2.7277064323, -1.2520660162, -0.1419366747, -1.7190331221, + -0.6506875753, 0.0628099963, -0.7629907727, 0.6080714464, -1.9897142649, -0.3891165257, 1.0277502537, 1.1713209152, + 1.4797284603, -1.3836252689, -0.2505295575, -0.4447467029, 0.1925516874, -0.6498235464, 0.2901880443, 1.6240186691, + 0.4743281007, 2.1063592434, 0.528439343, -0.8047794104, 0.2104256451, 0.75663656, 0.9716638327, -0.2522500753, + -1.2101258039, -0.9453462958, -0.878762126, -0.0724296495, 0.6382610202, -1.0404309034, -0.4261433184, 1.5532246828, + 0.5275081992, -0.357436806, -0.7761614323, -1.7335830927, 1.0692806244, -0.5937536955, 0.4269003272, -0.3536632359, + 0.9446827769, 2.5059707165, 0.0690293163, 0.2944066226, -0.7414646745, -1.0082733631, 1.1343686581, 0.2710540593, + 0.7274960876, -0.2651674747, -1.4867268801, 0.507060349, -1.2814332247, -0.3046406507, 0.5114221573, 0.3708107173, + 0.1999140978, 0.7607744932, 0.0477416702, 0.4222696722, 0.2854658961, -0.9390783906, -0.7843756676, -0.8260797858, + 1.4266068935, 0.8196808696, -1.190307498, -0.4611110985, -0.495243758, 0.6804166436, -0.6994231939, -1.1552095413, + -1.7887793779, 1.3153162003, 0.6558619738, 0.4816769361, -0.0126672778, -1.3285335302, -1.2688424587, -0.152387321, + -0.4339653254, -0.1709483713, 0.2231142521, 1.4828188419, -1.4240397215, -1.4417916536, 0.4451074302, -0.1589459926, + 1.2505066395, 1.3375947475, 1.1642736197, 0.3594298959, 0.7713550925, -0.6801846623, -0.498046726, 0.950465858, + 1.6608889103, 0.415817976, -0.2972727418, 1.2367286682, -1.0620138645, -1.8265507221, -0.5331158042, -2.1153428555, + -0.6209367514, 0.4675408602, 0.61438936, -1.7113894224, 0.2891764641, -0.6705935597, 0.4754212797, 0.3198952973, + 0.7838545442, 0.3976619542, -1.1661629677, 0.4603621066, 0.9248743653, 2.1145966053, 0.0825881287, 0.6749655008, + 0.8121272326, -0.218945995, -0.1639946699, 0.3587153256, -0.7834233642, 0.6059847474, 0.5444562435, -1.4124641418, + -0.023319602, 0.0880037472, 0.1275142431, 1.0809987783, 0.640211463, 0.763471067, 0.9324608445, 0.3846043348, + -1.7244272232, 0.3992971778, -0.3185180128, 0.1687958091, -0.0704131722, 0.6610387564, -0.6090794802, -0.4523200393, + 1.0825520754, 1.0088615417, -0.5682323575, -1.3370556831, 1.0058012009, 1.6292598248, -1.2862094641, -0.6961910725, + 0.2314819843, 0.7249957323, 0.6836280823, -0.1757106632, -0.9063949585, -1.3477391005, -1.1346484423, 0.3227340579, + 1.3607194424, -2.8635163307, 0.2292383462, 0.4060978889, -1.3265417814, 0.2751484215, 0.7121296525, -0.6921774745, + 0.6154708266, 0.220054388, -0.57544595, 0.3323008418, 2.1421134472, 0.7250728011, 0.6870709658, 0.5515963435, + -0.5132011175, -0.16443865, 1.9557372332, 0.5852532983, 0.7971339822, -0.4506426752, 1.4849123955, 0.2836766541, + -0.6032394171, 0.4705572426, -1.0361155272, 0.2024379373, 2.0730745792, -0.1682272553, 0.3044758141, -0.1541289538, + -0.691054225, 1.406170845, 0.4611213803, -0.2320941687, -0.4938946962, -0.2043031901, -0.0456889868, 0.9397354126, + 0.9698880315, 0.0257637091, -0.2238553017, -0.2935015857, 1.000363946, 0.893838644, 1.1174061298, -1.4390172958, + -1.3158385754, -0.4139026999, 0.4302385151, -2.2730138302, -0.6109037995, 0.6164110303, 0.3562093377, 0.9595016241, + -0.5901470184, 1.8615894318, 0.3402916193, -0.0181768406, 0.8151611686, 1.2026921511, -0.9299021959, 0.6094628572, + 1.2707104683, 0.4547021091, 0.9683445096, -1.0731282234, 0.7785558105, 1.6914439201, -0.2198672742, -2.2547419071, + 1.2058824301, 0.6307622194, -1.8844203949, -0.3400211334, -1.4175158739, -0.1408693939, -0.2282040119, 0.6934574246, + 1.0840233564, -0.1311188787, -0.4547898471, 0.0308669638, -2.9230649471, 0.1924819946, -0.0251757074, -0.1361604929, + 1.3143212795, 1.3681744337, 2.502099514, -1.7766501904, 2.9016273022, 0.4275854528, -0.0154027585, -1.1051633358, + 0.2060504258, 0.1583422422, 0.3727222979, 0.9876830578, 0.062621437, -1.1221803427, 3.4378697872, -2.8637402058, + 0.9245373607, -0.2257023752, -0.5427214503, -1.8706995249, 0.5202276707, 1.4523717165, -1.8733434677, -1.2647411823, + -0.5458576083, -0.6326601505, 1.9794954062, -0.0096601248, 2.2758998871, 0.3492978215, 0.2012365162, 0.2095893174, + 0.6796535254, 0.0502694286, -0.0435023643, 0.2123025507, -0.4695489109, -0.3350050747, 0.2190171927, -1.0715231895, + 0.3171286583, -0.2802983224, -0.6058686972, -1.5530456305, 0.9496842623, 0.2735980153, -0.4321633577, -1.6320595741, + 0.8468621969, 0.6839948893, 0.294350028, 1.5179771185, -0.3009389341, 1.1591215134, -0.4598817229, 1.6021217108, + -0.2987172902, 0.1620407104, 0.00225092, -1.0108187199, -0.9158037305, 0.6183546185, -0.0589140914, 1.91885674, + -0.0930142999, 0.4509327114, 1.3160575628, 0.1009306461, -1.2808429003, -0.3061289489, 0.2605623901, 1.1934047937, + 1.3779098988, -0.8680241704, -1.080051899, -0.0498448424, 0.4656108022, 1.0705919266, 0.5382865071, -1.0938647985, + 0.665158391, 0.1397799551, -0.7773083448, 0.6970692277, -1.1914598942, 0.4689689577, -1.5771685839, -1.7258087397, + 0.9759751558, 0.9858368635, 0.9479118586, 0.8612651229, -0.4446322322, -0.3175063431, 1.2068784237, -0.5929441452, + 0.1791196018, -0.9298995137, -0.4742261767, -0.433457464, 1.3930308819, 1.5312166214, 0.5114341974, -1.9366881847, + -0.012031151, 0.2527293563, -0.3314227462, 0.519421041, 0.1215722114, -0.5180037618, -1.5782446861, -0.3423944712, + 1.1970065832, -0.0611416213, -1.3710052967, 0.8990535736, 0.5925429463, 1.5193586349, -0.4414147139, -1.0274288654, + 0.3192766309, -0.2304987013, -0.0761491209, 0.0690865219, 1.3222659826, 0.0257438123, -0.2477024496, 0.2511856556, + -1.5257942677, 1.4712384939, -0.0396799296, -0.0264192075, -1.6288158894, -0.7242621779, 1.9021406174, -0.509208262, + -0.0244931318, -0.5751573443, 0.915258348, 1.1320323944, 0.3048408628, 0.7192915082, 0.0029749731, 1.7288789749, + -2.0123455524, -2.408012867, -1.7593473196, -2.4347224236, 1.6136039495, 0.4126974642, -0.7342951298, -1.0291619301, + -0.2701182067, -0.2743706107, 1.5435656309, -0.4356430173, -0.3694144189, 0.5576394796, -0.2556772828, 0.4563857317, + 0.2570762634, 0.3890536427, -0.8774389625, -0.2383845448, -0.5045922399, 1.0469880104, 1.6212552786, -0.2120764405, + 0.6647508144, -2.0476558208, -0.8174135685, -0.8982970119, 0.7912128568, -0.7010203004, -1.3018070459, -1.6871378422, + 0.5631584525, -2.1441884041, -1.6575580835, 0.9514712691, 1.6940368414, 0.0827083439, -1.3294876814, -1.1565612555, + -0.1200775355, 0.4073521793, 0.0284242388, 0.0219066888, 0.594206214, -0.4101213515, 0.8342248797, 0.3034593165, + 0.2702042758, -0.8202449083, 0.8972294331, 0.136271596, 0.6182371974, 0.3332054317, 0.3803861737, -0.0642565563, + 1.5682134628, 0.026644405, 2.2625157833, -0.8821482658, 0.9058094025, -0.9818913341, -0.655893147, 2.1423466206, + 0.8509710431, -0.346679002, 0.8928981423, 1.8331450224, 1.0823125839, -2.212146759, -0.204287827, -0.8251465559, + -0.3494953811, 0.5181334019, 1.1187945604, 0.8085275888, -0.9451194406, -0.1899499297, -1.5023754835, 0.574662447, + 0.3227597475, 0.9226501584, -0.6544494629, -1.2606118917, 1.4417942762, -1.2978820801, -0.091638878, 0.2793105245, + 1.1175570488, 1.7324228287, -1.078258872, -0.0125431186, 0.6125292182, -0.2632619441, -1.0598345995, 0.2111615837, + -0.3366095126, 0.9723577499, -0.0001053959, -0.9998166561, 0.3668155372, -0.1650307626, -2.6319227219, -1.3921569586, + 0.5988414288, -1.7351586819, 1.466791749, -0.5279781222, -0.3885532022, 0.3108111024, -0.1206910387, 0.8990362287, + 0.1039673463, 0.1421874166, 0.4403844476, -0.5696710944, -0.2248260379, 0.9770126939, 1.2786602974, 0.8683383465, + 2.3025348186, 0.0278422982, -0.1820368022, 0.8733520508, -0.3343454897, -0.5557032824, -0.5515244007, 0.5276218653, + -0.7114800811, 1.7720230818, -0.397092253, 0.4389536083, 0.06503506, -1.1340105534, -0.7053775787, -1.8313711882, + -1.6354445219, -0.4521007836, 0.3524754345, 0.4045782983, -0.158671841, -1.0496007204, -0.8052915335, -1.4610325098, + 0.3669247329, -0.9069761038, -0.7325763106, -0.9586330652, -0.1848229915, 0.1050765216, -0.1473184377, -0.1583449841, + -0.3924146891, 1.3609659672, 0.5217448473, 1.9404394627, 1.077704072, 0.3909571171, 0.6589066386, 0.1673523486, + 1.0541881323, 0.3378158808, -0.706555903, 0.1609089524, 1.7601629496, 0.2293126136, 0.9480530024, -1.233520627, + -0.0344778039, 0.7309923172, -1.5902619362, -0.4351943135, 0.6615905762, -0.3688139915, 2.3102419376, -0.942620337, + -0.5544672608, -0.634354353, 1.0669492483, -0.2379402369, -0.4261119664, 1.8326580524, -0.7513182163, -1.4482220411, + -0.7471646667, -0.8635528684, -1.2731425762, 0.6533293128, 0.6602415442, 1.2218433619, 0.6049968004, -0.5613385439, + 0.061361257, 0.9906570315, 0.5033934712, -0.6237265468, -0.0041219913, 0.8261147141, 0.242782414, -0.3063735664, + -0.0811720788, 0.1534022242, -1.1207720041, -0.6678703427, -0.2377390862, 0.8940547705, 0.2770272493, 1.3696693182, + -0.0493086502, -0.074567467, 0.4672318697, -0.3150355816, 1.4334459305, -0.1679604053, -1.9706282616, -0.3613967896, + -1.6547517776, 1.1160451174, -1.600356698, 2.041585207, 2.0366399288, -1.0523581505, 0.3376710713, 1.0529056787, + 1.693002224, 0.9688546062, -1.4531956911, 0.8070805073, -1.3145008087, -1.4333742857, 0.0553366765, 0.4915426075, + 0.3531095684, -0.7884507179, -0.1045462191, -0.5995621085, -1.3206208944, 0.6596292257, -0.988484025, 1.9658976793, + -0.434037894, 0.0516867973, -0.5761942267, -0.4747160673, 2.0759608746, 0.9117660522, -1.3595043421, -0.0750775263, + 1.0767716169, 0.8811606765, 1.1698845625, 2.6263203621, 1.5705279112, -1.4361846447, 0.8416768312, -0.7291257381, + -1.9000356197, 0.169265151, -0.5643911958, 2.2524120808, 0.3646518886, -0.2983020544, -0.4583005309, 0.9823272824, + 0.0525144637, -0.716845572, 0.5617127419, -1.3276793957, 0.0449519083, 1.7765147686, 0.3622149229, -0.7156533003, + 2.787749052, 1.170342803, 1.6707651615, 0.925880909, -1.0642477274, 1.1153731346, 0.5419448614, 0.0624054596, + -1.0790256262, -0.2572177947, -1.1862916946, 0.9607563615, 0.1119695157, 0.5639559031, -1.7139394283, -1.2567867041, + -0.2268253267, 0.3858694136, -0.0999460742, 0.4597186148, -1.6977158785, -1.0717468262, 1.4142743349, 0.2119618356, + 1.3924894333, -0.9887067676, -1.0531584024, -1.2928825617, 1.2426022291, 0.5878120065, -0.9949681759, 0.8283343315, + -0.2635304928, 0.4014886022, -0.6090260744, 0.5791243315, 0.5834465027, 1.5511604548, -1.2230901718, -0.6187438369, + -0.3775131106, 0.9911983013, -1.7839671373, 0.1290750504, 1.6611936092, -1.9548208714, 0.5270512104, 0.9121604562, + 0.4895628095, 0.0196124874, -0.4402401149, -1.8178555965, -0.2203289568, 1.2370438576, -1.3454525471, 2.4535121918, + -0.1176287308, -1.0192205906, 0.5798735619, 0.0242904909, -0.0841123089, 0.5548579097, -0.7952302098, -0.8613741398, + 0.8380604386, 1.0689024925, -2.4395861626, 0.344841063, -0.5043354034, 0.0641216338, 1.1720117331, 1.290399909, + 0.4812498987, 1.1072002649, 1.0949929953, -2.3961193562, -2.79017663, -0.2823035121, 1.2701352835, -2.0818095207, + 2.6965289116, -1.3935769796, -0.2706691027, 1.0988687277, -2.1704502106, 0.6163380742, 1.3522902727, 0.7691040635, + -3.0363001823, 2.5481321812, -1.5075689554, -2.3067941666, 0.817728579, -2.4801552296, 0.957233429, 1.1474175453, + -0.5582699776, -0.2533708811, 0.1953659654, 0.0904167295, 0.6058718562, 0.3594837487, 0.5418453813, -1.2951164246, + 0.4690193236, 1.733002305, 0.1667902321, 1.1768552065, -0.0910997316, -0.2359167486, -0.0121873543, 0.4238246381, + -0.0331050605, -0.5837310553, 0.5397078991, 0.3845285177, 0.1106715724, 0.125855729, -0.4165729582, 1.0588035583, + 0.454154253, -2.6346459389, -1.2074881792, -0.1499014944, -0.3375472128, -1.5428763628, 1.283778429, -0.6475168467, + 0.3657090068, 0.4615589976, 1.6139746904, 1.0400425196, 0.8091872334, 0.0503223762, -1.4139139652, 0.1132474169, + 1.5251283646, 1.6179705858, 1.2431045771, 1.7049555779, 0.1189959124, -0.2425130904, 0.1800673753, -1.4013088942, + 0.648537159, 0.8376440406, 1.1608923674, 1.1170085669, -0.8883395791, -0.1524236053, -0.871545136, -0.1062527671, + 1.8281518221, -0.6069445014, -0.681636095, -0.3067930639, 0.9655979276, -0.2940889299, 0.9251574278, 1.1493262053, + -0.5966495275, 0.5556038022, 1.9187790155, -0.2040707618, -0.4193641543, 0.234103784, -0.2179090828, 0.7499462962, + -0.2418686002, 0.511359334, -1.8201842308, -1.1509025097, -0.7798062563, 0.1130120382, -0.3003650606, -1.9360016584, + -0.9553108215, 0.9728742838, -0.1972751766, -1.7404620647, -0.4687793553, 1.1957448721, -0.5498569012, -0.788305223, + -0.1498728544, 0.268127203, -0.2486549169, -0.4183347225, -0.3109455109, 0.1175777838, 0.7868638635, 0.9115644693, + 0.107327722, -1.0881794691, 0.8313896656, 0.4506823123, -0.9034633636, -1.0354187489, 0.693577528, 1.1028820276, + 0.6876826882, 2.0347700119, 0.5668647289, -0.3477827907, 1.6544166803, 0.3295305669, -0.1434911638, -0.1425676346, + -0.4272623062, -1.2900912762, -0.2381984293, 0.6456766725, -1.0504271984, -0.9134973884, -1.0105756521, 1.1871837378, + 0.2558339238, 0.9838050008, -0.5840255618, 1.6918026209, -0.7227749228, 0.557706356, -0.2009231299, 0.9748980999, + 1.0686962605, 0.1406216919, 1.4599475861, -1.113435626, 0.4520905316, -0.3960721493, 0.9606674314, 0.4791612625, + -0.5085137486, -1.1975919008, 1.2257055044, -0.7944650054, 1.0772857666, -0.8134288192, -0.1460259855, -0.7566825151, + 0.548376143, 0.4096541405, -1.1490131617, -1.2600245476, 0.4720077217, -0.8848083019, -0.3584946394, -0.3885389566, + -1.6692073345, 1.8913199902, -0.943598628, -1.6560325623, -0.4170581698, 1.4248950481, 0.7457003593, -0.2701747119, + -1.4329892397, -0.9257540107, -0.5308506489, 0.2141064256, -0.7413557172, -0.7860522866, -1.6483081579, -1.3483446836, + -1.2292420864, -0.5480573773, -0.5060109496, -0.5933606029, -2.0655674934, 1.2769864798, -0.0294818971, -0.5929264426, + 0.6686656475, 0.5973464251, 0.2934952974, -1.2685967684, 1.0854260921, 0.0394030698, 0.684273839, -0.731549263, + 1.6883585453, 1.6437082291, -0.8642318845, -0.1803095788, -0.1081145182, -1.4840042591, -1.0925523043, -0.0899927989, + -0.3712283671, -0.8431726694, -0.9773939252, 0.5591737628, 0.4611403346, 0.073404938, 0.5970427394, 1.9101938009, + -2.3871018887, -0.4583065808, -0.5112628341, -1.3271329403, 0.7063751817, -0.6450681686, -2.1740829945, 2.9771606922, + -0.7224324942, -0.6503081918, 1.5257606506, -0.2274675965, 0.4022358656, 0.4434968829, -1.02186203, -0.131502524, + 0.0179176256, -0.4155089855, 0.485801965, -0.8543961048, -0.5012856126, 0.8567308187, 0.2221969515, 0.1999620646, + 0.6042551994, 0.6662653685, 1.0663129091, -0.4896272123, -0.2026205212, -1.1394944191, -1.2054032087, -1.122635603, + -0.4939437509, 0.1943001896, 0.6055281162, 0.7169389725, -0.3576804101, 0.6503378749, 1.652549386, 0.5573248863, + 0.1776629537, -0.4948503077, -0.0657189265, 0.1559060067, -0.1242087036, 0.0716841519, -1.593021512, 0.0682995692, + -1.2083141804, 0.9281802773, -0.0046851207, 0.9349762201, 0.2173268646, 1.3025127649, 0.0904640332, -0.3832762539, + -1.6360230446, 0.4152020812, -1.4499077797, 0.8201241493, 0.8912186027, 0.0771826804, -0.515427053, 0.9378012419, + -0.4901067615, 0.5525051951, 1.2330327034, -0.3991430104, 1.4831937551, 0.7175683379, 0.2221147567, 0.3608321846, + 0.2894625068, -1.6595556736, -1.9314495325, 1.875131011, -0.4770455658, -0.5211828947, -0.6297601461, -1.1078292131, + 1.9312903881, 0.2273961604, -0.3932147026, -1.0034306049, -2.273072958, 0.0832397044, -0.516262114, -0.9493662715, + 0.7647309303, -1.4768458605, -0.7454246283, 0.2828139067, -0.3133463562, 0.0699866787, -0.825873673, 0.9094543457, + 2.2345933914, -0.2716061175, -2.0914297104, -0.8450802565, -0.1864923686, -0.2835510671, -0.1033757925, -1.5680092573, + -1.2161769867, -1.6124955416, 1.3700754642, 0.7851352096, -0.382365793, 1.3108464479, -0.8988699317, 0.5083639026, + 0.349350214, -0.0577305481, 1.0597113371, 1.0081275702, -0.6358467937, -0.4504096806, -0.3147639036, 1.0732730627, + -0.8271607161, -0.6222040057, -0.7991218567, 0.7039133906, 0.3510959148, 0.5554497242, 1.4979805946, -2.1750752926, + 0.2891605496, 1.9272480011, -0.9401828647, 1.3731950521, -1.7251560688, 1.3734343052, 0.335614413, 0.9673383832, + -1.101739049, -1.1915374994, -1.7516787052, -1.0826570988, 0.6179661155, 1.1888171434, -1.0887053013, -0.2124068141, + -1.156745553, -1.0044180155, -0.9566497207, 0.7797390819, -1.7934116125, -0.3947986662, -0.4438236058, 0.4794886708, + 1.2552320957, -0.7013828158, 1.3951803446, -0.0517238714, -1.4133031368, -1.8694245815, -0.5054339767, -1.2462067604, + -1.2365274429, 0.3690735698, 1.277148366, 0.0578073971, 0.3081986904, -0.2649683654, 0.5571885705, -0.5460993648, + 0.5755186081, 1.1222224236, 0.0097143548, -0.1952548772, 1.3565348387, 0.9633554816, 0.7406532764, 0.4492635727, + 0.3314831555, 0.1872891337, 0.5805309415, 0.3974446356, -0.5829093456, -0.0477444232, 1.0294648409, 1.5680623055, + 1.6048808098, -1.7844184637, 1.3980298042, 0.5945453644, -0.5468156338, 1.2185471058, -1.0988667011, -0.5286205411, + -0.5052637458, -0.1807851791, 0.1174189076, -0.9720669985, -1.5364803076, 1.394192338, 2.1483066082, 0.4284505546, + -0.1856944412, -0.7900459766, 0.0108980974, 0.954018116, 1.220533967, 0.4898815155, -0.9313154221, -0.9521727562, + -0.5750778913, -0.2174461782, 2.1930093765, 1.5066055059, -1.082428813, -0.264172107, -1.2634152174, -0.1384104043, + 0.4317926168, -0.6106199026, -0.4305661917, -0.2218575478, -1.1112926006, 0.1515053213, -0.3358800411, -0.1186274439, + -0.7633775473, -0.2121664286, 1.9252479076, -0.5415530801, -0.4101755917, -1.9593467712, -0.1169006303, 0.1504407674, + 1.2334483862, 1.0831296444, -0.4920203984, -1.1058235168, -1.3844621181, 0.1942979842, -1.2118817568, 0.9645847082, + -2.0245478153, 0.2150682956, -1.8037940264, 2.1545493603, 0.2532272041, 0.332259655, 0.8775139451, 0.0413930006, + -0.5169070959, 0.8127090335, 3.4397461414, 0.8755329847, 0.6949456334, -1.6751369238, -0.7122853398, 0.5115014315, + -1.2610419989, -0.0193399414, 1.1886892319, 0.3200702965, -0.415114373, -0.4470207989, -0.7033379078, 2.1508812904, + 0.2372479588, -0.8369963765, -0.6052927971, -0.6665679216, -1.3898322582, -0.1554756016, -0.9192994833, -0.7518845797, + -0.3134998679, -0.2572743595, -1.5091480017, -0.5846824646, 0.3287142515, 1.6392349005, -0.0196348205, 0.5276853442, + 1.1864744425, 0.7721220851, 0.6423051953, -0.7868347764, -0.1904338896, -0.0519685, 0.2901331782, -0.0316568166, + 0.3051229119, 1.2303379774, 0.222715646, -1.8869382143, -0.0082769394, 0.2376345396, 0.8816763163, -0.163767159, + -0.8250055313, 0.9399932623, -0.258022964, 2.0155923367, -0.1516564339, 0.1265739948, 2.1453938484, 0.8217768669, + 0.9791879654, -0.226326257, -0.4864189625, 0.0454811975, 1.37108922, -0.9420208931, 0.9791120291, -0.4800106883, + 0.8337278366, -1.3876479864, 0.8446266651, 0.8098564148, 0.5751532912, -0.9790716171, -0.0171645191, -0.50267452, + 0.6194605827, -0.8599231243, -0.3917999566, -1.4034454823, 0.8840796947, -1.6543312073, 0.0696845874, -0.4744838774, + 0.8552336097, 1.8941549063, -0.4313303828, -0.2739033401, 0.3928846419, -1.5880547762, 0.934129715, 0.3463015854, + -1.3363854885, -0.0499476194, -2.963932991, -0.5594952106, 0.7434971333, 0.1999131292, -2.0764930248, -0.5285277367, + -0.2470802069, -2.0624265671, 0.9572924376, 0.39032197, -0.6605809927, -0.6549845338, -1.0186446905, -0.0800478607, + 0.8186472058, 0.6616176367, 0.0518838763, -0.9223122597, -0.5421885848, -0.2825040221, -0.3912544847, -0.2029047906, + 0.689384222, -0.8635937572, 0.5363397598, 0.6943371892, 0.0873916373, -0.2490534633, 1.2992305756, -0.7386673093, + 2.0405597687, 0.8024853468, -1.4069356918, 1.1822263002, -1.3656258583, -0.5556980968, 0.1787927747, 0.1019315794, + -1.3714215755, 0.1987746656, -0.3629374206, 1.8519080877, 0.6735958457, 0.4217328429, -0.3506659269, -0.1316977292, + 1.2174890041, 0.3776035905, -0.8396139741, -1.1620602608, 0.3407081068, -0.3355799913, -0.7459722757, -1.8262302876, + -0.8597204685, -1.4879345894, 1.1369839907, 1.1803423166, 0.0483212918, -0.3535215557, 1.7021528482, 0.1325516403, + -0.1556667686, -2.0734696388, 0.3474398255, -1.130600214, -0.5391064882, 0.0367188156, -0.1031585932, 0.5129575133, + 0.1265309304, 0.0982659385, 0.4955267012, 1.3003282547, 0.6503933668, 0.3970629275, 1.8765217066, -2.2937936783, + -1.048953414, -0.3891129792, 2.0643260479, -0.1525699496, -0.3799881637, 0.4029478729, 0.8279522061, -0.6166064143, + 1.0913140774, 0.1232835948, 0.0043251989, -1.2592334747, 1.1358189583, 1.395740509, -0.0802572221, 0.3133191466, + 1.022424221, 0.5248175263, -0.6712270975, -0.6747437119, 0.0586817972, -0.450971216, -0.9520729184, -0.7986681461, + 0.9456746578, 2.1470000744, 1.4799757004, -1.8066306114, -0.0310747288, 0.8656225801, 0.511262536, 2.5125331879, + 0.2004410326, 0.2644173801, -0.5642243028, -0.3665525317, -0.8501471877, 2.1454489231, 0.0146866925, -0.2753212452, + -2.2508983612, 0.4200601578, -0.5757294893, 0.3302652538, 0.6833993793, -0.1050571799, 1.3361978531, -0.8743016124, + -0.1878415346, 0.5748300552, 0.4990630448, -0.9741004705, 0.2689557374, -0.8159407973, 1.5243690014, 1.1392233372, + 1.6356216669, -1.5474957228, -0.0423558354, 0.0719309151, 0.0674327686, -0.4663897157, -1.006231904, 1.1016836166, + -0.3533191681, -0.9534746408, -0.5174071789, 0.3306112587, 1.3137228489, -0.4841048717, -1.5414144993, 0.7894215584, + 0.7925677299, -0.2099342644, 1.6130772829, -2.2307887077, 0.6066238284, 0.4182311296, -0.8662330508, -0.1302055269, + 0.6588820815, 0.7003934383, -0.6792898178, 2.0538380146, 1.4943599701, -1.263487339, 0.2456917167, -1.6332542896, + -1.1893531084, 0.7613589168, -0.3110498488, 0.1274812669, -1.4536637068, 1.2830148935, 0.3669683635, -0.6743721366, + 0.3679584563, -1.8977421522, 0.8388814926, 1.7857834101, 0.3952881098, 0.9302375913, 0.1583839953, -0.4621100724, + -1.2903282642, -1.6294634342, 0.7264854312, -0.0749876797, -1.2859839201, -0.3973017633, 0.220641762, -0.6645338535, + -0.2155216634, 0.5685132742, 0.1122510657, -1.3511683941, -0.8059957027, -1.0774103403, 0.4130584002, -0.2617705166, + -0.1687471569, -0.2825335562, -0.3444823325, -0.9686818719, -0.1723157912, 0.2521053255, -2.1374604702, 0.4649966657, + 0.5567176342, 2.4056639671, 0.2969538569, 1.8013700247, 0.0617722496, 0.4764775336, -1.2795540094, 0.6798602343, + 1.4741630554, 0.7309804559, 0.3686659932, 0.0889440775, -1.4905848503, 2.1611554623, 0.4314791262, 0.1953540742, + 1.5225317478, 0.7390133142, -0.4725934565, 1.1161459684, -1.9433223009, -0.139365688, 0.2824656963, 3.1519126892, + -0.5079812407, -0.8862577677, 0.6268798709, -1.2120158672, 0.7088871598, -1.6071879864, 0.8341999054, 0.653396666, + -0.1934999079, -0.1612865776, -0.1745747179, 0.6138933301, -0.2608250678, 0.0169208851, 1.4444025755, 0.053476654, + 0.2234792262, -1.024251461, -0.7009769678, 0.4972992241, 0.1313402355, 0.2999706864, -0.9448517561, 0.2542484105, + 1.3423204422, -0.7973331213, 0.4570710957, -1.5696889162, 0.8125736117, -1.5350893736, 0.5826305151, 0.259604454, + -0.8103986382, 2.3475239277, 0.2638120949, 1.52597332, 0.5666651726, -0.9071298838, -0.8720138669, -0.9882591367, + 0.4064132273, 1.3104044199, 0.1794917881, -0.3529058397, 0.8675439954, 1.5312627554, -0.1812909395, 0.4155770242, + 1.4033385515, 0.1539124548, -0.124418363, -1.5379589796, -0.8867199421, -0.654812634, 1.8252388239, 0.6651643515, + -0.6815838814, -0.0382827222, 0.4838942289, 0.7248817086, 0.0481229275, -0.5961760879, 1.7160128355, -0.5742226243, + 0.4242486656, 1.3640313148, -0.0682704076, -0.1149882078, -0.7724986672, 0.5856184959, -0.5331230164, 0.2725982368, + -2.2121868134, -0.5297753811, 0.328214705, -0.2310766876, 0.9220627546, -0.4692978561, 0.9146265388, 1.2192900181, + 1.1941511631, -0.1149736866, 0.9485147595, -0.4857148528, 0.6253182888, 0.1254618019, -1.3645582199, 0.4393002987, + -0.9393618107, -0.3738214076, 0.3530284464, 0.3340075612, -1.0520275831, 0.3124981225, 0.2227747589, -0.3774113357, + 0.3376967609, -0.1335430741, -1.423912406, 0.3777493238, -0.6754847169, 1.755866766, -0.341999352, -0.5435870886, + 1.5623818636, -1.0864465237, 2.7157764435, -1.1701687574, 1.0629879236, 0.1548271179, 0.2290085405, -0.52356565, + -1.2878988981, -0.5667066574, -0.050169237, 1.7568033934, -0.1276576668, -0.8953829408, 1.0946452618, -0.3542604744, + -1.2604600191, -0.395377934, 0.2435953319, -0.794017911, -0.5217481852, 0.4265375137, -0.3192216158, -0.8071255088, + 0.5322649479, -0.3526906967, -0.0918452591, -0.6988605857, -0.2911368012, -0.6488785744, -0.6978461146, 0.3133989573, + -0.7867271304, 0.3081840575, -0.1553696841, 1.6520466805, -0.8007677197, -1.912730217, -0.8846508265, 0.7461178899, + 1.0180773735, 0.9306701422, -0.1126613319, 0.1929772198, -1.0579559803, -0.2422025204, 1.8559801579, 0.3720010519, + 1.1825789213, -0.1039613783, 1.0414545536, -0.3254982829, 0.9571298361, -0.438216567, 1.0003467798, 1.5939487219, + 0.542948842, -2.0420072079, 0.5728467107, -1.8618476391, -0.291846782, -0.0487218536, -0.9199935198, -1.0266177654, + 1.6822305918, 1.4191178083, 0.6947760582, 1.0251603127, 0.6672874093, 1.2495917082, -0.8335829377, 0.2156088799, + 1.1924821138, -0.439566046, 0.652263999, -1.6726173162, -1.0532317162, 2.1165602207, -1.9447240829, -0.0893126354, + 0.2683942318, -0.1623480618, -0.2299717814, -1.2482939959, -1.4748595953, -1.1440454721, -0.1509122998, -0.5654972196, + 0.9534760118, 2.3310527802, 1.1738048792, 1.2242695093, -0.1066419408, -0.4332847297, -0.8702556491, 2.0648863316, + -0.9727774858, -0.3140878677, -0.5490342379, 0.6551995277, 0.4908427596, 1.0332645178, 1.1219984293, 1.313595295, + -0.4913543463, 0.6445788741, 1.7172362804, -2.7000076771, -1.9069814682, 0.5195291638, -1.2169370651, 0.2950018048, + 0.556849122, -0.620256722, 3.0056195259, 1.6280162334, -1.7385234833, 1.4424477816, 0.8223228455, -0.0615691058, + -0.8732482791, -0.0132957678, 1.3641716242, 0.8280566931, -0.663374424, -0.0640525073, 0.1176194623, -1.9407721758, + -1.8422350883, -1.4371339083, 0.1744921356, 2.3886828423, 0.189862594, -0.5868138671, 0.9374192953, 1.4271277189, + 0.1327908039, -1.2658762932, -1.1797477007, -2.2054107189, -1.2667415142, -1.1865519285, 0.3430148959, 0.7459679246, + -1.5639922619, 0.6891250014, 0.6442363858, -0.1363123357, -0.3265230358, 0.8321313858, -0.031406492, 1.1229662895, + 1.1464596987, -0.6990435719, -1.4267598391, 0.825956285, 1.7598297596, 1.294709444, -0.5276837945, -0.2367414087, + 0.5686634779, 0.6113168597, -0.1315857321, -0.0734574869, 0.043616239, 0.1786444336, 0.6293717623, -1.1854665279, + -1.8017184734, 1.1474248171, -0.2221667469, -0.831802249, -1.176964879, -0.6398457885, 1.1581661701, 1.0694650412, + -1.1927752495, -0.3782918751, -0.5945242047, 1.5984972715, -0.4153506756, 0.9948699474, 1.1457722187, 0.2799803019, + 0.0362116992, 0.116950959, 1.198417902, -2.1507964134, -0.2818993628, 0.1193391681, 1.1043921709, -0.1576315612, + 0.7816631794, -0.1992943287, -0.7222493291, -1.6471685171, 0.5236202478, 0.3679266572, -0.2783089876, 0.191120699, + 1.7007887363, -0.2828701138, -0.6807302237, -2.0343830585, 0.0755103827, 0.1925597936, 1.1212855577, -0.6325791478, + -1.4917219877, 0.1507131606, -1.4023673534, -1.4923455715, 0.2636044025, 1.2325544357, 0.8019176126, 0.7070560455, + -0.4439917505, 0.3190809786, 0.3905167878, 1.6310776472, 1.1720501184, -1.2261582613, 1.4022692442, 0.60786587, + 0.8062526584, -2.9621202946, -0.3987344801, 0.3414399922, 1.7619208097, 1.5134036541, 0.6041021347, 0.5934362411, + -1.1736227274, 1.3398493528, -0.5730978847, 0.1356645226, 0.2863060832, -0.0154768359, -1.017860055, -2.3243145943, + -0.1675287634, 0.6049609184, 0.2159761786, 0.0666745231, -0.0865136832, 1.2352000475, 0.0394294672, 1.010030508, + 0.2578782439, 0.6886412501, -2.9555711746, 0.3245435357, -1.1066570282, 0.0578106418, 0.8995000124, -0.557805717, + 0.8344925642, -0.3650110662, -1.9382914305, -0.9237997532, 0.1845855862, 1.0926511288, -1.4047546387, 1.5311555862, + -0.8047308326, -0.7788903713, 0.4715638757, 0.4318743646, -1.687484026, -2.7890527248, -1.5477393866, -0.4640494883, + 0.4432340562, -1.0020309687, -0.5192461014, 0.1724080592, 1.3290741444, 0.6016322374, -2.4097959995, 0.5145076513, + -1.1226621866, 0.5319163203, -0.9135279655, -0.3886004984, 0.2594231069, -0.8287024498, 1.3806180954, 0.2069475651, + -0.8147791028, -1.8920502663, 0.3105571568, -0.6040369272, -0.5843714476, -1.3048652411, -0.9555811882, 1.6718477011, + 0.2061201781, 0.2449650019, 0.6344435215, 1.8947550058, -1.1782568693, -1.352202177, 0.5857774019, -1.2353422642, + 0.5616509914, 1.3375346661, 1.3691686392, -1.7339766026, -0.5559787154, -0.4727867544, -0.9000478983, 1.2659494877, + 0.4353246093, -0.0236592907, 0.9436045289, -0.6716923118, 1.0447865725, 1.3527976274, -1.0631425381, 2.4571130276, + -0.119058691, -1.3206595182, 0.210131824, -1.4100403786, 0.7463139296, -1.598303318, -0.1158415601, -0.3557868004, + -0.103559278, -2.1708722115, 0.373275578, 0.8958846927, -1.5255739689, 0.0184564441, 0.5205706954, 1.0403897762, + -0.03085877, -0.9651818871, -0.293672055, 0.0902625993, 0.4703084528, -0.3178536892, 0.3725000322, -0.5491930842, + 0.6766549349, -0.5850317478, 1.9644398689, 2.4331896305, 1.319794178, -0.5910408497, 0.5551754832, 0.7306241393, + -1.0116714239, -0.7693768144, 0.1477881372, 0.5307281017, -0.5618506074, -0.3604781926, 0.5028930902, -0.5547525883, + 2.3241920471, 0.7301399112, -0.0238630101, -0.3112625182, -0.0513433814, 0.0332490802, -0.3835499585, -0.3944619596, + -1.0770056248, -0.828463912, -2.270683527, 1.1904422045, -0.73837322, -0.7856744528, 0.2669454515, -0.4751650691, + -0.3949821889, 2.0143547058, 0.1436878145, -1.2537568808, -1.7973768711, 0.3158451319, -0.2288792729, -0.6633766294, + 0.3909885287, 1.5668081045, -0.8202961683, -0.2624257505, 0.0357421786, -2.8803546429, 1.0226624012, -1.6296515465, + -2.3747596741, -0.0938686728, -0.4877255559, 0.4899860322, -0.5391430855, 1.3695386648, 0.6441672444, 0.7667090893, + -1.3685532808, 0.6206942797, 1.2448111773, -0.8042119741, -0.5956533551, 0.0014253046, -0.888751626, 1.6678035259, + 2.0496942997, -0.1034380123, -1.06039536, -0.4802497625, 0.1270350516, 2.1686303616, -1.5617771149, 0.4015067816, + 0.1245800033, -0.3452774882, 0.8196158409, -0.1079464853, 0.8407748342, 2.0225064754, 0.1155442074, 0.5847235322, + 0.4388331473, 0.1234409586, -0.2910670638, -0.6586142182, 2.0476639271, -1.8610835075, 2.2706551552, -0.1068520844, + -1.3966004848, 0.8132696152, -0.4033440351, -0.1480889022, -1.0043388605, 0.393604964, 0.1324205846, 0.5566450357, + -0.1675183326, 0.5736991763, -0.684972167, 0.9904925227, -1.8894196749, 1.59811306, 0.7703539729, -0.1610601544, + 0.9238270521, -0.051518295, -0.8868377805, 1.0417042971, 0.6102308035, -1.8677076101, -0.3840411901, -0.1164660156, + 0.0456374995, -1.847597599, 0.535563767, -0.6964988112, 0.7957055569, -0.1288603097, -0.3235868216, -1.6325315237, + -0.5247679353, 0.7241875529, 0.7006774545, 0.6510369182, 0.2127076685, 0.3019182682, 1.7634776831, 1.0604306459, + -0.0160322711, -2.0777280331, 1.1360679865, 0.4793742299, 0.4298013747, -0.9959617257, -1.0719579458, 0.377034694, + 1.4366446733, 0.7699731588, -0.9030251503, -0.8420140147, -0.2891960144, -1.3440425396, -1.4827768803, -0.8795897365, + 0.8493244648, 0.1213431358, 2.4658744335, -0.5044754148, 0.8377598524, -1.3034893274, 0.466124773, 0.5391213298, + -1.0591400862, -0.0326998606, -2.0926170349, -0.3239274919, -0.9163483977, 0.7162846327, -0.0685323477, 0.4281194508, + -1.1246926785, -0.1664071679, -0.6484211087, -2.1521315575, -1.0705305338, -0.8617205024, 0.2989324927, 1.2873754501, + -0.2156222463, -1.4065039158, -0.608348012, 0.0496303663, -0.0799441859, -0.3430354595, -0.5707333684, 0.2139833272, + 0.1441838294, -1.6315569878, -0.4222122729, 0.728757143, 0.4752489328, 1.471482873, 0.7369390726, -0.5534162521, + 0.463776052, 0.8952754736, -1.360429883, -2.1174213886, 2.2016246319, -0.2555569708, 0.5857450366, 0.1036471277, + -0.6595315337, 0.5226187706, -1.8577984571, 0.8471649885, -0.5092989802, 0.8184267879, 1.6758291721, 0.4162685573, + 2.5203919411, -1.0321208239, -1.4705890417, 0.5317592025, 0.8014125228, 0.9071531296, -1.5176868439, 0.4063048065, + 0.7387344241, 1.2877237797, 0.340960443, 1.8790210485, 0.9491173029, 0.2067094594, -0.9716271162, 0.3574623168, + 1.0916240215, -0.287157774, -1.7678191662, -1.4303933382, -0.2483468205, -0.1160075366, -0.1474684626, 0.4271591902, + 0.7722973824, -0.8035597205, 0.2369090319, 0.5585380793, -1.6493217945, -0.9682631493, -0.2224204242, -0.3922516108, + 0.8767914772, 0.9763500094, -0.3122895956, 0.9651550651, 0.6296004653, -0.1026753411, -2.067661047, -0.7020508647, + -0.1088828817, 1.3923741579, 0.1279061884, -1.0830278397, 1.7001254559, -0.7274262905, 1.5997858047, -1.7580193281, + -0.1680758595, -0.7228416204, -2.0124907494, 1.3119337559, 0.2128693163, 1.7944684029, 1.875608325, -0.3741932511, + -0.2608598173, 1.098362565, 2.3297736645, 0.3219519854, 0.4034484327, 1.2642672062, 0.8221021891, 0.4798425138, + 0.0399289317, -0.2851095498, 0.5849317908, 0.7732047439, 1.2581137419, 1.8532098532, -0.6349226832, 0.4174361527, + 0.4140231311, -0.6864744425, -0.1428144574, 0.4959804416, 0.7714887261, 0.2804813683, -0.5753896832, -1.2983716726, + -0.5563231707, -0.0272231661, -0.4999603927, -0.2157250941, -0.7681286335, -2.0508408546, -1.0966194868, 1.6365146637, + -0.5183550119, 0.6196789742, -1.3453786373, 0.5836728811, -0.4710648656, -0.5288444161, -0.2772250473, -2.3445336819, + -0.6098615527, -0.3629501164, -0.1410931945, -0.4874231517, 0.7105670571, -0.5983030796, 0.5260640383, -1.0717720985, + 0.3782913387, 0.7160261869, -0.8814377785, -0.2456881255, -0.6174123883, 0.210847646, -0.3944846392, -1.3366764784, + 0.0207539462, -0.5891013741, 0.2604995966, 1.692429781, -1.1274348497, 0.5514831543, 0.6292963624, -0.7273381352, + -0.1221026108, -1.3238046169, -1.8603323698, 0.0118839173, -0.049451109, -0.7719197273, 1.1183060408, 1.12718606, + -2.070296526, 1.1230894327, -0.5023233891, -0.523896277, 0.1952285916, -0.2513331473, -0.3816655576, 0.6158700585, + -0.7880089879, -1.8909306526, -0.7469483018, 0.0433481671, 0.1173256263, 0.4212864637, -0.37611866, -0.9839541912, + 2.0143651962, -0.3616572618, 0.264983356, -0.1013830006, -0.6988646388, 0.6318305135, -1.3341007233, 0.5088815093, + 0.2114373595, 0.6875721812, 0.2607598007, 0.0316194594, 0.3898535371, 0.7478242517, -0.9930844903, -0.5001050234, + 0.8352737427, 0.3108315766, -0.0316842087, -0.7823688984, 0.1578320265, 0.9126993418, -0.2352722585, 0.940818131, + 0.6109023094, -1.9303262234, 0.5498456359, -0.6723092198, -1.4504003525, 0.5355149508, 0.349703759, 0.188963145, + 0.1326940656, -0.6038624048, 0.5095413923, -1.0285254717, 0.2388528883, -0.2497551739, 0.4331155121, -0.0697732419, + 0.6253356934, -0.1688880771, 0.9176494479, -1.8235207796, -1.0847314596, -0.5756394863, 0.3497035503, 0.2342435122, + -2.6334090233, 0.5881343484, 1.7326449156, 0.4294790924, -1.3273426294, -2.0741112232, -1.2210987806, -0.1957486868, + 0.2234403342, 0.4510703385, -1.2828766108, 0.2367241681, -0.293394655, -2.7297432423, -0.3880361617, 1.3037126064, + -0.3852106035, 0.5652311444, -0.332161516, -0.5173915625, 1.3139929771, 0.8717244864, -0.6854110956, -1.9135602713, + 0.6436522007, -0.8172343969, 0.2767552435, -0.157547161, -0.5616329312, 0.4937283993, -0.3603928089, 0.4888756573, + 0.436321795, 0.7434330583, 1.0488585234, 0.2988363504, 0.8631799817, 0.4911931753, 0.5605632067, -1.2499432564, + -1.8365777731, -1.5436005592, 0.2294761688, -0.9752155542, -0.7505861521, 0.8158047199, 0.8112878799, -1.1278395653, + 0.100207977, 0.1714561433, -0.0902783796, 0.103200905, -0.4986415505, -0.1339252293, -1.1308209896, -1.2856656313, + -0.6171336174, 0.0464790165, 0.8600177169, 0.7068345547, -0.5624985099, 0.4751739502, -0.3413746953, 1.0102072954, + 0.023076551, 0.2426536977, -1.8445314169, 0.7333210111, 0.5530741811, 0.2356170565, 0.1776789725, -0.2307106107, + -0.0811266378, 0.7031916976, 1.5869663954, -0.3827952743, 2.095795393, -0.0665417612, -0.5297813416, 1.3718634844, + -0.2815313339, 0.20855847, -0.3606263101, -0.4346255958, 0.9304487705, 0.6789392829, 0.3673276603, 0.1621620655, + 0.4276526272, -0.1493246108, 0.898170054, 0.7842456102, -0.7916181684, 0.1158784404, 0.4618153572, 0.3543474972, + 1.4618315697, -0.0058341846, -0.890088737, -0.4046399891, 0.912337482, 0.5789139867, -0.4968176186, 0.1236161813, + -0.4920249581, 1.8629844189, 3.1188952923, 2.1145527363, 0.4688876569, -0.9595867991, -1.0293675661, 0.6830950379, + 1.3771774769, 0.1248709261, -0.4470041692, -1.235150218, -0.0911605358, -0.3967476189, -0.0899577588, -1.3996888399, + -0.5305298567, 0.7499350905, 0.5719929934, -1.4103066921, -0.3479000628, -0.2184364051, 0.1737931967, 0.0222933087, + 0.5647415519, 0.8052543998, -1.0294834375, 0.843118906, 1.5975235701, 1.1170238256, 0.667299509, -0.8730934262, + -0.567299366, -1.2327417135, -1.4132713079, 0.9281820655, 0.7359776497, 1.0769482851, -0.1153248027, 0.2036904693, + -0.8216454983, -0.7670912147, 1.1390515566, -1.3738186359, 0.3531615138, 0.4086511433, -1.426813364, 1.0887863636, + -0.467073679, 1.593881011, -0.6779985428, -1.6609425545, -1.1497362852, 0.0858812928, 0.3081794083, 2.7873344421, + 0.0017950319, 0.7034717202, 0.0402048379, -0.0539211519, -0.8005341887, 1.2653822899, 1.1613918543, 0.0606069304, + -0.9181155562, -0.2290524691, -0.1122236475, 0.0549350791, -0.8877182007, -0.3766615987, -0.5949606895, -1.6478073597, + 0.8510466218, 0.219623372, -0.3607971072, 0.8401561379, 0.0543761253, 1.4959983826, -0.5632653236, -0.242505759, + 0.0648398325, 0.7764827609, 0.7312174439, -1.112113595, -0.6776387691, 1.0912896395, 0.9742969275, -1.9399904013, + -2.180277586, 2.1129066944, 0.8291311264, -1.1868286133, 0.5817332864, -2.1304891109, 1.0515449047, 0.4106768072, + -1.2035242319, -0.7135511637, -0.4709822536, -0.5258688331, 0.750594914, -0.8277429938, -2.781924963, -1.1523625851, + -0.8028509617, -0.502605319, -0.1736410111, -0.3603467047, -0.2416286469, 0.1397867203, -0.1340719461, 2.9043488503, + -1.288079977, -0.0549019389, -0.6406171918, -1.3738036156, -0.4437952936, -0.6030911207, -1.5600773096, -0.317884028, + 0.7513098717, -0.0685902163, -0.5909373164, 0.0339408405, 0.0979840606, -1.9291602373, -1.1436108351, -0.0531030297, + 1.490005374, -0.8120594025, -0.4823431373, -0.6355569363, -0.2808527946, -0.0437979996, 1.9277224541, 0.9682134986, + -0.3746079803, -0.2915026248, -0.4581932127, 1.6945850849, 0.6297083497, -1.9033675194, 1.3773635626, 1.8451112509, + 1.3157194853, -0.4916698933, -0.7966602445, -0.3494751751, 0.7045466304, -0.4455379248, -0.3833731711, 1.3972334862, + -0.5082765222, -0.1657868773, 0.0295438245, -0.1786982268, 1.2381014824, 0.0978887677, -0.6584629416, -0.2192865759, + 0.946775198, -0.0771661103, -1.0597406626, -0.174882248, 0.7894371152, -0.4872848988, 2.283346653, -0.5168839693, + -1.3883464336, 1.3372455835, 0.2018319666, -0.2333852649, -0.3624745011, -0.5905905366, -0.7401220202, 1.0021631718, + 1.2818202972, 0.2926157117, -1.0420081615, 0.4264304936, -0.0421497524, -0.5193667412, -0.8652704954, 0.8540445566, + 1.0223616362, -1.1298987865, 1.0555826426, 0.0991955176, 0.4002920985, 1.1874296665, -1.5832803249, 0.9813435078, + 1.2280945778, 0.5722233653, -0.9180369377, 1.3107286692, -0.224770695, -1.1927497387, -0.7917345762, -1.1626080275, + 0.9272098541, 0.5459935069, -0.6274787188, -0.0236869771, 0.4932527244, 1.1298884153, 0.0539514609, -0.5518273115, + 1.1233708858, -0.068791382, -0.1571341753, 0.1179229915, -0.332598418, 0.2601344585, -0.1911605597, -0.4110339582, + 1.2266099453, 0.2822836637, 1.2508134842, -0.351095587, -0.1616224051, -1.658770442, 0.172863245, -1.3107187748, + 0.9391930103, -0.0142953722, 0.7546882629, -0.8996400237, 0.994025588, -0.2330982387, -0.4980289638, 0.2528294027, + 2.6544928551, 1.578119278, 0.4817900956, 1.1860171556, 0.3339211643, 1.6164300442, -2.9351656437, 0.2499151379, + 0.7760117054, 0.7523182631, -0.1247479841, 0.3462697268, -1.0257136822, -2.8691601753, -1.1061319113, 0.764842391, + -0.9595790505, -0.0078468043, -0.2652287781, 0.9949512482, 0.5908301473, 0.7397772074, 0.2819495201, 0.962739408, + 0.1467755586, -0.7852812409, -0.3648975492, 0.7329995036, 0.9112494588, -0.6349129677, 1.0441013575, 1.1536734104, + 0.7727792263, 0.1085980162, 0.3048982322, 0.2045264691, -0.0964837223, -1.162161231, -0.1049908698, -1.808652997, + 1.1371610165, 0.3990722299, -0.234031871, -0.8070739508, -0.5447965264, -0.9057466984, -0.705632627, -1.3920232058, + -2.249683857, 0.6314688921, -0.0317909122, 0.5471078753, 0.2917467952, 1.1517522335, -0.2557494044, 2.4834494591, + 0.1827259809, -1.1629668474, 0.0617253222, -1.1677007675, -0.6916891932, 0.1345950365, 1.0560717583, 0.725982666, + -0.9369471669, -1.2553867102, 0.8967444301, 0.0060753874, -0.124295935, -1.3210841417, 0.0899388492, 0.8379094005, + 1.1313247681, 0.3248853981, 0.3055925071, -1.3190481663, -0.4589845836, -1.0276916027, -0.4143671095, -0.2306914777, + -0.7529071569, -0.398645103, -0.4679827392, 1.0484802723, 0.7876905203, 0.3911187947, 0.9792061448, -0.1854469031, + -1.1137851477, -0.4035208821, -0.8948764205, -1.0624626875, 0.409347415, -2.7420592308, 0.5685927272, 0.1045850515, + 0.8899027109, -0.6605038643, -0.0338754356, 0.4368726313, -0.56986624, 0.3048413694, -0.9810655117, -2.1477074623, + -1.0738272667, -0.4583679438, -0.1335805207, -0.6811560988, 0.6706511378, 0.0815103278, -0.0946848914, -0.8044914007, + -0.1711455286, -0.2423008829, 0.8169430494, -0.7940458059, 1.618157506, 0.2855857611, 0.8950667381, -0.6162665486, + 0.1139321849, -0.6352536678, -0.0765659958, -0.7508867383, 0.1942287982, -0.7451517582, -0.8653050661, -0.2339722216, + 1.0282814503, 0.2243474871, 0.0027308404, 1.3209453821, 0.2174192816, -0.2634245455, 0.1675521731, 1.2263836861, + 0.0566299632, -1.2975367308, 0.3696041107, -0.9182784557, -1.3032855988, 2.0671389103, -1.4618188143, 0.4181285203, + -0.1183236837, 0.4636798799, 0.7680442333, -1.1236658096, -1.3899666071, 1.2378437519, -0.6141276956, 0.0449728668, + 0.3780954778, 0.5110079646, -1.5044722557, 0.564588666, -0.7422678471, 0.9555368423, -0.8196920156, 0.540176332, + -0.5338007212, -0.0242628828, 0.1132424623, -0.6125180125, 0.7859786153, -0.0349822044, 0.073287949, 1.1536586285, + 0.1490181834, 1.1301728487, 0.7858697176, 1.2088547945, -1.8960126638, -0.0871836841, -0.8826141357, 2.8862614632, + -0.8807513714, 0.0494962074, -1.1702387333, -0.6589772105, -1.681849122, 0.9417175651, 0.7542197108, -0.8279682398, + -0.4384127259, -0.1200602949, -1.6220785379, 0.1089254692, 1.3359794617, 2.4555397034, 0.0173700582, -0.0874115005, + -3.2741274834, 0.1969607472, -0.2217420191, 1.3908416033, -0.3902492821, -1.8578752279, -0.8916897774, -0.4912000895, + 0.9974804521, 0.2037437856, -0.3271367252, -0.6474327445, -0.1907690018, -1.6302834749, 0.6798949838, -1.6188380718, + 2.0891149044, 0.4113075733, 1.0672979355, -0.1462323815, -0.1751722842, 0.3902901411, -1.0913881063, -1.5157181025, + 0.9157704711, 0.7945489883, 0.7722069025, 0.4243962467, 0.9691821337, 1.4120765924, -1.080982089, -0.6280459762, + -0.633805573, -0.4000754654, -0.7342044711, 2.2752947807, -1.5868879557, -0.5589603782, -1.3043125868, 0.3147029877, + -0.2022144794, 0.8512126803, -1.4063329697, -0.6932082772, 1.449349165, 0.056066826, 0.9236955643, -0.5947605968, + -0.205028668, -1.2416573763, -0.6073765755, 0.4851435125, 0.4411651194, -0.1564729959, 0.2195530385, 0.3204922378, + -1.1177259684, 1.028907299, 1.1188204288, -0.0411395468, 0.6005723476, 1.5676715374, -0.1191437095, -0.5251495838, + -1.5412362814, -1.2549991608, -1.7545846701, 1.3483644724, -0.9670109749, 0.8642841578, 0.3205362856, -1.7713440657, + 1.1340459585, -1.0328261852, -0.1334087253, -0.3448979259, 1.2247921228, 0.7575573921, 0.6027758718, -0.6131908894, + 0.7743551135, 0.5759877563, -0.1214414164, -0.0009457574, 0.8447682858, -1.7850353718, -0.1575969607, 1.1574027538, + 0.1245122924, 0.6179469824, -0.9759038091, 0.1979667097, -0.5714919567, 1.1229913235, 0.311383456, -0.4361872375, + 0.0621054992, -0.8684849739, 1.5532866716, 0.4511200488, -0.5184523463, 0.4275344014, 0.4822023511, -0.5793940425, + -1.2044733763, -0.0556597859, 0.3327965736, 0.1595038027, 1.5718646049, 1.1590943336, -0.7317303419, -1.0252996683, + 0.303444773, 0.0385221504, -1.4219295979, 1.6513744593, 0.5207285881, -0.5225039721, -0.5949496031, -0.2466515452, + -0.7081933618, 1.7684363127, 0.211573869, 0.1667692959, 0.9263616204, 0.51992172, -0.8082281351, 2.0617651939, + -1.6870878935, -0.5724027157, -0.0029290456, -0.8472099304, -0.3068249524, -0.7209590673, -0.4516503513, 1.211851716, + -0.5764548779, -0.6438353658, 0.3038035929, -0.4023731649, 0.5642825961, 0.1920437813, -1.0712314844, 1.2746276855, + 1.6927058697, 0.4486570656, 1.3200535774, 0.0160080902, -2.3641381264, 0.5951035619, -0.1099106371, -0.1813999414, + 0.6511411071, -1.0492880344, -0.9243508577, -0.5737870932, -0.9042535424, 1.7057296038, -0.6014401317, -0.3643075228, + -0.2186646163, 0.1627379209, -0.8163861036, -1.1460425854, 0.9978126884, 1.1337602139, -3.2709360123, 0.9469668865, + -2.5101165771, 0.6990010738, 0.8786799312, -0.5839535594, -0.6743929386, -2.4371728897, -0.050307624, 0.8705804348, + -0.2608596385, 0.0898400098, -0.3027840257, -1.2079818249, 0.0692925304, -2.0684671402, -0.0220023058, 0.3078320622, + -0.7879421711, -1.0444283485, 1.2165591717, 0.1952220052, 1.4552105665, 1.0593975782, -1.0149605274, 1.2875981331, + -0.466309011, 1.5024882555, 0.96856004, -0.2157099992, 0.2602674961, -0.9132912755, 0.0151141891, 0.4012723863, + 1.0047228336, -0.9285416603, -2.0817165375, -0.2928998768, 1.5027165413, -0.1005974039, -0.375897944, 2.035009861, + -0.4853464663, 2.9407486916, -0.5036264062, 0.207628876, 0.2921140492, -1.1655380726, -0.9878220558, 1.4906018972, + -0.8561943173, 1.838958025, -0.1549417078, -0.2442326397, -0.7554346919, -0.8123953938, 0.4190253019, 0.6878544092, + -1.6918449402, -0.0898365825, 1.0332804918, 1.43141222, -2.1892902851, 0.0718886927, 0.7476850748, 1.857989192, + -0.8819519877, 0.9258650541, -0.9806548357, -2.4932901859, 0.6940491796, 1.670899272, 0.1564088911, -0.5294389725, + 0.7051659226, -0.4034671485, 0.8142341971, 1.4990714788, -1.3586189747, -0.5893127322, 0.264239639, -1.9446407557, + -0.2521522045, -1.6591632366, 0.6953535676, -1.0761489868, 0.5135737658, -0.8951653838, -1.4820936918, 1.6783659458, + -1.335044384, 1.3742983341, 1.4251997471, -0.4624463916, 0.2494481504, 0.8023421764, -0.5172142386, 1.50712955, + -0.1262708008, 0.1829024106, -0.3753479421, -0.7461107969, -0.9378911257, 0.8594884276, -1.399626255, 0.2003267109, + 1.0123081207, -0.7833893895, -0.39726457, -0.6808474064, 0.4937455356, -0.5152196884, -0.7318217754, 0.2788423002, + 1.9877916574, 1.0418436527, -0.6853435636, 0.0596736781, 1.0391395092, 0.739816606, -0.9924521446, 1.1051650047, + -1.2520617247, 2.8686056137, -0.1694054306, 1.9018117189, -1.0746030807, -1.22655797, -0.8510357141, -2.1456563473, + 0.6359826922, 0.5066269636, 0.9674390554, -1.1224880219, -1.0891484022, -0.1846278459, -0.5367618203, 1.8058052063, + -1.1354886293, -1.9588290453, 0.7469393015, 0.1361483037, 0.1992729604, -0.8409942389, 0.1434929073, 1.8949650526, + -0.5321903825, -0.238239646, 0.0410348624, 0.579713583, 1.5907917023, -0.2758657932, 0.1504357457, -0.5587373972, + -1.4018324614, 1.4326224327, -0.6219562292, 0.4503026307, 0.4008595347, 0.393481791, 1.2696865797, 1.8898544312, + -0.1165970489, 0.64577806, 2.2075743675, -0.9847111702, -1.2228060961, -1.0882190466, 1.0747212172, 1.1284934282, + -0.7757837176, -0.1252997965, -0.1738859862, -1.0792155266, 1.751106143, -0.1438600868, -0.9502803683, 0.261957109, + -0.2889937162, 0.0514364801, 0.596227169, -1.3032315969, -0.3775050342, 1.3788658381, -0.5376601815, -0.3634388149, + -0.522013545, 0.6863537431, -1.0816643238, 0.8089571595, 1.128963232, -0.1704909503, 0.0241376441, 0.9559123516, + -0.2972258627, 1.2451685667, -0.7107396126, -0.4264647663, -0.2931824625, 0.518529892, -0.1059233323, 0.6447357535, + 0.7338988185, 0.5817427039, -0.6184529066, 0.1341575831, -0.4200459421, 0.8393083811, -0.3927664757, 0.4707723856, + -0.067355983, 0.3716157675, 0.3322022855, 0.0640629455, -0.713299334, 0.0691948086, -0.8344638944, -0.1031417176, + -0.4747044742, -1.6690871716, 0.6154571176, -0.6817176938, -2.0737211704, -0.3878850639, 1.4523063898, -0.6992966533, + -0.4581898749, 0.1936287731, 0.2572551072, 1.4544843435, -1.6571730375, -1.7270624638, 0.0417574421, -0.9110734463, + -0.0972457156, 1.5952712297, -0.8988962173, 0.5708675981, 2.3974201679, -1.5280815363, -0.1108923852, -0.3071365356, + -0.9979051352, -0.1661987454, -1.075140357, -2.5248780251, -0.2498296946, 0.9437659383, 0.921723783, 0.7171913981, + -1.4578920603, 1.2408026457, -2.4817552567, 0.2420867234, -0.3377861381, 0.0360229239, -0.5133728981, -0.3208512962, + -1.3301918507, -0.6975618005, 0.6498871446, 0.8788000345, 0.0332687683, 1.0863420963, 0.9952074885, 1.0205569267, + -1.5511695147, 1.1222990751, -0.2344319969, -0.6389635801, 0.2854325175, -0.7309339643, -1.9008569717, -1.2902566195, + -1.408972621, -0.0378140882, 0.8407415748, -0.6611420512, -1.2427229881, -0.5391062498, -0.7145795226, -1.0734699965, + 1.3682132959, -1.0783115625, -2.2720541954, -0.7096360922, -0.2335556746, 1.0443377495, -0.4696555734, -0.3875656724, + -0.8236765265, 0.2266024798, 0.1619909555, -0.0944048539, 1.6084132195, -0.3988568187, 0.1957289577, 1.5395137072, + -0.1689223051, -1.5008987188, -1.3173402548, 1.1269226074, 0.3471261263, 0.3052436709, 0.3154096305, 0.0921308771, + 0.1269512475, 1.8258371353, 0.1363988519, -0.9507242441, 0.7849888802, 0.3052140176, -0.2709810436, -0.8993048072, + 0.2169116437, 0.1867516041, 0.7598631382, -0.8012745976, -1.1976956129, 0.0239624623, 0.307475239, 1.2831456661, + -1.340269804, -0.451615274, -0.00130616, 0.4203725457, 0.3012847304, 0.2762047648, -0.9804582596, 1.1610437632, + 0.5745239854, 0.6747921705, 1.4261837006, -0.5042745471, 0.5857908726, 0.8970323205, 0.1667999625, -0.4011804461, + 1.7648248672, -0.808714807, -0.2742171586, 0.4606503844, -0.0885505006, 0.2718375921, -0.8004333973, 0.6516600847, + 1.3673778772, -1.5335977077, -0.0962385684, -0.8232393861, 1.6774146557, 0.2271115631, -1.5541958809, 0.3077866137, + -1.7232172489, -2.4555950165, 0.8917973042, 1.7451490164, -1.7838643789, 0.618072927, 1.0859361887, 1.1453979015, + 0.9061566591, -0.3431972563, -0.0705898181, 1.0991281271, -0.2261981666, 0.3282406032, 1.0704436302, -1.1716351509, + 0.9848763347, 0.2437052131, 1.9884727001, 0.4174208343, -0.1021214947, -0.3435896039, 1.3310985565, -0.5973044634, + -1.0328304768, -1.0166631937, -0.2418605387, -1.0737953186, -1.5078314543, -1.9658055305, -2.4816696644, 0.0847596675, + 0.9371824861, 0.5712789297, 0.1847821474, -1.601680994, -0.5153174996, 0.3281519115, -0.0960697681, -0.7360475659, + -1.3864686489, 1.0394927263, -0.0865700766, -1.2883691788, -2.029296875, -2.0399634838, 0.6458489895, 0.4366787672, + -0.2919606566, -0.8011184335, -1.1781026125, 1.2439732552, 0.7523661256, -0.4787828326, -0.1176917329, -0.3622176647, + -0.9125710726, -0.3694320023, -1.2082426548, -0.5479109883, -0.831525445, -0.7423962951, 0.1000797302, -0.2114170194, + -0.6813454032, 0.839081645, 0.4109891355, -1.2436894178, 0.5534462929, -1.4438923597, 0.8049284816, -0.8555861712, + 2.1477587223, -1.3949433565, -0.2616662383, -0.9542909265, 0.1196367517, 1.5450251102, -2.3118369579, 2.7454116344, + -0.5705853701, 0.0806028023, 0.2696255445, 1.1088483334, -0.6098455787, 0.2533075511, -1.6156879663, 0.4766279757, + -0.9498989582, 1.3911211491, 0.0607453063, 0.3484802246, 0.254090786, -0.9823598862, -0.6200393438, 0.6513434649, + 0.6371821165, 1.2473409176, 0.4007479548, -0.6293382645, -0.3995212615, -0.3992503285, 2.1516108513, 0.8495406508, + -1.1839305162, -1.5761988163, -0.3321847916, -0.6933479905, -0.5461527705, 0.2077549547, -0.0470405109, 0.9233145118, + -0.3973110914, 0.0615227558, -0.0844099149, -1.7535184622, 2.8657610416, 1.7541314363, -2.3690114021, -1.1117147207, + -0.9374561906, -0.7801645994, 1.7342389822, 0.5957742929, 1.4701598883, -0.4405146837, 0.6708141565, -1.2153530121, + -0.1325355917, 1.0050604343, -1.2139691114, -1.3798935413, 2.3798618317, -1.9887228012, 0.3868185282, 0.8959914446, + 1.6038486958, 1.5363543034, -0.7630540729, -1.4995023012, -1.8495545387, -0.2919710279, -1.577684164, 1.768560648, + 1.1297414303, 2.3360943794, -0.1433131546, 0.0687443092, 0.5931475163, 0.3375712037, 1.2554653883, 0.247423768, + -0.9403129816, -0.2061767131, -0.4198792279, 0.314173907, 1.7077875137, -1.4152840376, 0.1187793538, -0.7630447745, + -0.6395958662, 0.0102028055, 0.1042164192, 0.1145903766, -1.4752571583, 0.2472184002, -2.1607117653, -0.4515348971, + 1.2877726555, 0.8726791143, 0.5221362114, 0.0558537394, -0.7062091231, -1.0879805088, 0.5266829729, 0.1596421599, + 2.6657764912, 0.8143402338, 0.9257330298, 2.1734650135, 0.5997606516, -0.1436795443, 0.3496937156, -0.9546177983, + -0.1620016545, 0.9732399583, -0.5467224121, -0.22620143, 0.67310673, 0.2159280777, -1.3774738312, 1.1656154394, + 0.6550341249, 1.9122684002, -0.9768811464, 0.9356287122, -1.2053273916, 2.4479525089, 0.6917709708, -1.5790313482, + -1.4568662643, 1.2126783133, 0.6390294433, -0.5516815782, 0.8256443143, 0.4482912719, -1.8841407299, -1.3875689507, + -0.1513385475, 0.4152318239, -0.6240538955, -0.2882059515, -0.1251111031, 0.0627681017, 0.2525975108, 1.44931674, + -1.2855988741, -0.0614147782, 1.2215783596, 0.3575677872, 0.3007901907, -2.106682539, 0.6250435114, -0.6612740755, + -0.1341212541, 0.2166793793, -0.9497941732, -1.2139436007, 1.211656332, -0.9395774007, 0.3062827587, 1.1016186476, + 0.0750297382, 0.1435457021, -0.8186900616, -0.4630457759, 0.5266259909, -0.0092119304, -0.5354993343, -2.7169761658, + -1.1486746073, 0.2088882625, -0.680782795, -3.0617961884, -0.331330955, -0.1758318841, 1.4389998913, -1.4673558474, + -0.7488585114, -0.0289274994, -0.3636911213, -1.2437512875, -1.5300729275, -1.1790323257, 0.3857260942, -1.5467594862, + -0.1613754779, 1.4048904181, -0.5613690019, -0.7192589045, 1.7300932407, -0.5238711834, 1.0657387972, -0.9189323783, + -0.5509738326, -0.529923439, -1.8563530445, 0.7000102401, 1.3967370987, 0.1085478887, 0.9389107227, 0.6333724856, + 1.0824018717, 1.2884047031, -0.487932235, 1.5856468678, -1.3458198309, 0.4698221385, 0.9904260635, -0.7995867133, + 0.4108642042, 0.8107822537, 1.3460342884, 0.7748122215, 0.6732077003, -2.0124661922, -0.1145293713, -0.4353868663, + 1.0582432747, 0.4740674198, -0.804463923, -0.0220145155, -1.1738559008, 0.1407169402, 0.1516216695, 0.4735494852, + 0.907776475, 0.9353476763, -1.690212369, -0.061753124, 1.0522574186, 1.1403518915, 0.4502256215, 0.3180954456, + -0.8513272405, 1.7308795452, -0.9569784999, -1.1495845318, 0.0731476098, 1.3367174864, -0.173679322, 1.0153282881, + 0.7569540739, -0.4068577588, -0.9060294628, -0.1295568198, 1.8163871765, -1.3072237968, 0.6215203404, 0.6559920907, + 0.6238611341, 0.8602724671, 1.3712561131, 1.7863894701, -0.1854007989, -2.0719249249, 1.9330905676, -0.2852199376, + -1.1075080633, -0.1679364741, 1.5029848814, -0.3086349368, -1.5096340179, -1.3769066334, -1.7379231453, 0.3038515449, + 0.5172749758, -0.6259486675, 0.7043590546, 0.6408320069, 0.4185501933, -0.164610371, 0.3187517822, 0.8196350932, + -0.4609601498, 0.3704506457, 2.3777439594, 0.5094441772, 0.5521851182, -1.3909140825, 1.1121610403, 0.8421571851, + 1.1006048918, 0.6569547057, -0.8560597301, -1.248324275, -1.7567801476, -0.8713760972, 0.2235589772, -0.2905384302, + 0.6802270412, -0.0276177991, -0.9667946696, -0.3455171287, -1.4121873379, 0.2059963942, -0.6952722073, -0.7459636331, + 1.0301487446, -0.6903392076, -0.1190134883, 0.2581081092, 0.2567854524, 0.7716189623, -0.2509430051, 1.0092092752, + -0.5644721389, -1.3445675373, 1.3076673746, -0.9773423076, 0.3826100528, -2.6880400181, 0.4268960953, -1.1517989635, + -0.869155705, -0.6256707907, 0.5513302684, -1.1145905256, 0.884999454, -0.8217748404, 0.9004893899, -0.5353831649, + -1.2508430481, 0.7113912702, -2.6005218029, -0.7853864431, 0.3203434646, 2.5373580456, -2.3225741386, -0.2459121794, + -1.1617994308, 0.7776864767, -0.1386852562, 0.8962039948, -0.3026582301, 0.0292508341, -0.2019753456, -1.3439552784, + 1.8885324001, -0.2357038409, 1.0730520487, 1.1235663891, 0.195359692, -0.2643015087, -0.0000123232, 0.8602338433, + -1.4039980173, -0.5216125846, -0.0435859486, 0.3864676356, -0.6059318781, 1.2893551588, -0.7495974302, -0.7594406009, + -0.2251145393, -0.861530602, -0.3031273782, -0.7514218092, -0.0263201371, 1.0012412071, -0.4263814092, 0.3582890928, + 0.3132919073, -1.7429720163, -1.0658556223, -0.5562067628, 0.6188708544, 1.2195292711, 0.236476779, -0.7100563049, + 0.6203096509, -0.9709291458, -0.7118019462, -1.3894826174, 0.1876191944, 0.7731317282, 1.787022233, 1.3483870029, + -0.2876165211, 1.2424424887, 1.0495731831, 0.2199662328, -0.6506385803, 1.4809036255, 0.1745363027, 0.5330241919, + 0.2584872544, 1.7948721647, 1.2031013966, 0.2966628075, 1.06485641, 0.2883406579, 1.7498236895, -0.3993926644, + -0.5972360969, 2.3710198402, -0.1631287187, 0.6456073523, 0.138722524, 0.9679862261, -0.4325176179, 0.398437351, + -0.1760327667, 0.6858507991, 0.1566565484, 0.7886711955, -2.6216802597, 0.6207202673, 0.0285687726, 0.6761151552, + -1.335641861, 0.7205585241, 1.2382751703, -0.6817107797, -1.1695361137, 1.7380303144, 0.80159235, 0.258544594, + 0.3077518046, -1.6452590227, 0.4001936316, -0.7441572547, -1.4529861212, 0.250621438, -0.0533802733, 1.1744852066, + 0.7447588444, -0.3415437043, -1.0891363621, 0.6034783721, -0.1482316405, -0.4128837585, -0.0329800732, -0.7001284957, + -1.2899012566, -0.7876139283, 1.2155237198, 0.0087155225, -0.0377709866, -1.3937059641, 0.7941431403, 0.1870978177, + 0.6264303327, 0.8145871758, -0.7728582025, -0.2493467182, -0.5739196539, -0.5565655828, -1.1334906816, -2.2793505192, + 0.4410243928, 0.4123649299, 0.0763852969, 1.4099802971, -0.7776322365, 0.9002335072, -1.7927150726, 0.3387904763, + -1.5426032543, 0.1109750047, -0.1004541144, -0.7143050432, -0.9074044228, 0.194692716, -0.6922547221, -0.5126389265, + -0.2491152287, 0.8359513879, -0.5823138952, 0.1778424084, -0.1264958382, -1.2308934927, 0.0432014875, -1.7107870579, + -1.2794522047, -1.4112915993, 0.2468446046, 0.2457828671, -0.3186832964, 0.7732830644, 0.9469830394, 0.5959275961, + -0.2578312159, 0.3627173305, -0.3071349859, -0.1745721549, 1.1378543377, 0.793808043, -0.5381634235, 0.4013376534, + -0.9682885408, -1.1399817467, -0.9329072237, -0.580330193, 0.17868644, 0.6346725225, 0.5647393465, 0.0286316723, + 0.099219963, -1.089435339, 1.3608300686, -0.4605360329, -0.8283517361, -1.8477090597, -0.7479529381, 0.4846981764, + -0.810211122, -2.7513906956, -0.8704450727, 0.0546552204, 0.9808416963, -0.452450633, -1.1581110954, -1.8916167021, + 1.5128071308, -0.2710370421, -0.0432773046, 1.0887061357, 0.825360775, 0.928915143, -0.1334707141, -1.1068481207, + 1.0271012783, -0.4083566964, -0.9534019232, 0.9252843857, 1.2556301355, -0.3255678713, 0.6176265478, -0.126192376, + 0.7121532559, 1.1629872322, -0.7318741083, -0.0021026048, -0.6439540982, 0.7954640985, -0.5480089784, -0.91572541, + -1.1337063313, 1.040410161, -1.9267649651, 1.2752271891, -0.6368082762, 0.1870581359, 0.9406405687, -0.3973135352, + -0.0837642848, 0.1083026305, -0.1242073551, -0.2883494198, 0.042162437, 0.0474995077, 0.6321162581, -1.5836554766, + -1.1032531261, -0.5887776017, -0.1524914503, -1.6673083305, 0.9382166862, -1.0333873034, 0.4561629593, 1.1972030401, + -0.6820040345, 1.9431983232, -0.2159686685, 1.8049536943, 0.560254097, 0.0748924091, 0.5605863333, -1.7343138456, + 0.6010981798, 0.4802421331, -0.8561789393, 0.1013424918, -0.4451296926, -0.3943363428, -0.0749234781, 1.0080494881, + 1.6752249002, 0.3181442618, -0.2150738686, -0.0598962717, -0.6142386198, -0.4861352444, 1.5881255865, -0.0372432843, + 0.1362068504, -0.6435383558, 0.3061073124, -0.1080607101, 0.9142783284, -0.6750063896, 0.1442564428, -1.9035853148, + -1.9769639969, -0.2643598616, -0.1542481184, 0.6130289435, -0.9667575359, 0.4809058309, -0.8523111939, -1.5576803684, + -1.718798995, 0.3377987146, 0.7529808879, -1.0509667397, -0.7730994225, -1.2046824694, 0.4276761115, -0.8403949738, + -0.4825850129, -1.4747754335, 0.721634388, 0.4391319156, -0.2775903642, 1.837463975, 0.8860115409, 0.5017250776, + 0.1924185902, -0.3279211819, 0.5628093481, 0.9199988246, 0.2608970404, -0.1163030937, 0.9977791309, -0.1468842328, + 0.8259064555, 0.8571233153, -1.1635246277, -1.2943441868, -0.6337320209, 0.0078612473, 0.2800707519, -0.4688892663, + -1.5412379503, -1.2810702324, -0.9014613032, 0.7189544439, 0.676576972, -1.1631652117, 0.4434119165, 0.9910751581, + 0.3494699001, -0.4065314829, -0.37068066, -1.8773276806, 0.2003043443, -1.7980109453, 0.4200835824, -2.1893362999, + -0.2583111823, -2.0468666553, -0.2437464893, 1.0890002251, -0.0624531172, 0.3706884086, 0.4278266132, -0.170308575, + 0.8178662658, 1.0959708691, 0.5633809566, 0.410597831, -0.4165204167, 0.4329338372, -3.3593549728, -0.7902920246, + -0.5976426601, 0.2041165531, 0.7518958449, 0.9105246067, 0.6583688259, 0.8852194548, -1.0034178495, 2.1018614769, + -1.3160889149, -1.2050503492, 1.3702383041, -0.9215651155, 1.1412268877, -0.5294218063, -2.0968155861, 0.9883624315, + -0.4318448901, 0.9150150418, 0.6191473007, 0.9672363997, -0.5683717728, -0.9324068427, 2.0865449905, -0.2670659721, + 0.3249341547, 0.2030726075, 0.2451879531, -1.6215312481, -0.5928865671, 1.1713583469, 0.9839522839, -0.0872299895, + -0.3621385992, -0.98294276, 0.8884603977, -0.179382205, 0.5179939866, 1.3586529493, -0.9791272879, 0.323431313, + 0.5289196372, -1.9766300917, -0.0034390925, -0.7666292787, 0.7933413386, 0.8603540659, 0.9405009151, 0.6027413607, + 0.5473909974, 0.6982603073, 0.3897379637, 0.3500108123, 0.1734568626, -0.6509557366, -1.7006138563, 1.1740543842, + -0.286048919, 0.7598106861, -1.4153439999, 1.2704614401, -0.1627092808, 1.0294121504, 0.4012169838, 2.0456750393, + -0.036747802, 0.6690829992, -0.3728141785, -0.2102022916, 0.0779081285, -0.9818955064, 0.159858644, -0.788756907, + -1.6699723005, 1.191488862, 1.7864699364, -0.5499423742, 0.5733178854, -0.5447788239, -1.7513740063, -0.9034187198, + 0.5524613261, -0.1586202979, 0.0848929808, 1.8023984432, 0.4640448987, 0.3638080955, 0.264643997, 0.1547241062, + -1.4154069424, 1.4598560333, 0.8310509324, -0.4224171937, -0.0165275075, 0.261567086, -1.19160676, 0.2750308812, + 0.6544116735, -0.3800196648, -1.86604321, 0.2894992232, 1.1039299965, 0.1959735453, -0.0791411027, 0.1106350198, + 0.1640786827, -0.1299720556, -1.6187663078, -1.1956890821, 1.1165030003, 0.6533244848, 0.3864424229, 0.2913912237, + 1.0975930691, 1.423050642, -0.0867393687, -1.6922757626, -0.2748315632, 1.2141071558, 0.5547963381, 0.0646452904, + -1.1866117716, -0.0320456326, -2.1211907864, -1.9493031502, -1.0958501101, -1.0897547007, -0.1803523153, 0.3207212687, + 1.2608158588, -0.5926650167, 1.2983776331, -1.7294532061, -0.493960619, -0.8452877998, -0.4836902916, 0.6845428348, + 0.1369161159, 1.1284254789, 1.4544321299, 1.5625711679, -0.1469358951, 0.192761302, -0.705697, 2.1935093403, + -1.0594838858, -0.1013154238, 0.1026509628, 0.8066827059, -0.2695352435, -0.5729221702, -0.384919852, -1.0156600475, + -1.5466378927, -0.1314595789, 0.3548667729, 1.6491620541, -1.0673861504, -0.5086348653, 0.5900128484, 0.5537997484, + -0.902885139, 0.3827905357, -0.4903090894, 0.147182703, 0.5189530253, -0.3839559853, -0.0064701196, 0.0774409026, + 1.1993261576, -1.8423675299, 0.8041459918, 0.0865443349, 0.943895936, 0.4559169412, -1.9510413408, -0.0187463369, + -0.597168684, -2.1307387352, -1.0078853369, -1.1159837246, 0.0679549426, 0.3910646141, 0.6450982094, 0.2970682085, + -1.4807668924, 1.1750893593, 0.641859889, 1.7684969902, -0.5421749949, 0.0230772309, -0.5444252491, 0.6334091425, + -0.1794523001, 0.89459759, -0.32392627, -1.0767819881, 0.3691432476, 0.6942480206, -0.0642852709, -0.8203831315, + -1.1774146557, -0.2505559921, 0.8347317576, -0.1928883344, -0.5916996598, -2.2447366714, 1.4082713127, -0.2975973487, + -1.0574928522, 1.0062141418, 1.1215678453, 0.6743121743, 1.5402876139, 0.5045122504, 0.4825377464, 2.3591935635, + -0.1581576616, 1.3925447464, -0.444997251, 0.6436666846, 0.6480388045, 0.6492596865, -0.3070269525, 0.5588863492, + -0.834810853, 0.783921361, 0.6336535215, -1.4643620253, -0.8206500411, -0.7092571259, 1.5029654503, 0.9617568851, + -1.583635211, 1.09060359, -0.5501468778, -0.988499999, -0.1372122318, 1.2027401924, -1.1109777689, -0.5006306171, + -1.2436493635, 0.8456214666, 0.9922400117, -0.5578774214, -1.5881406069, -0.0128620062, 0.7343695164, -0.6115727425, + -1.6536990404, -0.0360801816, -0.209356755, 0.7303119898, 0.3931238949, 0.9025912881, -0.2072690576, 0.2031912059, + 1.179284811, -0.8231495619, 1.9168200493, 0.2706981301, -0.7323203087, 0.8667071462, 1.5296094418, 0.2382735461, + 1.0494682789, -0.3883500099, 0.1169275641, 0.917145431, -0.105467245, 0.0179931466, -0.9391468763, -1.300367713, + -2.875446558, -0.124176167, -0.1267907768, -1.4475177526, -0.017956106, -1.787997365, 0.7654473186, -1.1107738018, + 0.1945697963, -1.0288122892, 1.6509739161, 0.126649186, 0.4879723191, -0.2690182924, 1.3367944956, 0.5753632188, + -0.096810624, -0.9281479716, -1.2006169558, 0.0849150419, 0.9885011911, -0.5190308094, 1.0386395454, 0.145676285, + 0.477509886, -0.4643878937, 0.6115694642, -1.2517410517, 0.8366264105, 0.4481097162, -1.3137805462, 0.1005480215, + -1.1128195524, -0.0262514874, 1.1235595942, 1.6695141792, -0.1654336303, 0.7355045676, -0.8682185411, 0.0562831461, + -1.432711482, 0.025044689, 0.0975233465, -1.184161067, 0.7637282014, 1.5198569298, -0.7049927711, 0.8754818439, + 0.3610333502, -0.6621111035, 0.2180406004, -2.002440691, -0.8863433003, -0.1631226391, -0.387465328, 0.5548259616, + 1.1022121906, 1.052489996, -1.255136013, 0.9903590679, 0.8982601762, 0.8245859742, -0.3155473173, 0.0082518505, + 1.3746151924, -1.0334572792, 1.6923905611, 0.3971545994, 0.2894242704, -0.5514086485, -0.3389030099, -1.0362766981, + -0.5482236147, -3.2779073715, 2.1528837681, 0.1756819487, 0.34804672, 1.8974837065, -0.7496224046, -0.3268892765, + 1.397282958, -0.3456662893, 1.4522365332, -1.6095561981, -0.0210978836, 1.5160992146, 1.0965744257, -0.2358710319, + 0.6267479062, 1.7261326313, -0.3205836713, -0.1390050799, -0.7758511901, 2.0753962994, 0.175767675, -1.7555754185, + -0.2505002618, 0.2840710282, -0.5393370986, -0.4869838059, -0.1303175837, -1.1189780235, -1.0521354675, -0.0231210198, + 0.0181847401, 0.2078745663, -0.0338686258, -0.481885016, 0.0961250514, -0.9138529897, 0.9418380857, 1.3300968409, + 1.5610092878, 0.4450918734, -0.1296869665, -0.2519723773, -1.585948348, -0.9557150602, -0.2045584917, 0.0128896115, + -0.2095763832, -0.4511358142, 0.5498040318, 1.8048099279, -0.0429422446, 2.2919325829, 0.0038200787, 0.2721864283, + 0.4414996207, -1.3005160093, 0.1768380255, -0.9363270402, 0.4566507041, 0.3796249628, 0.4649937451, 0.7009580731, + 1.081979394, -0.547087729, -1.1549626589, -0.2274688035, -0.4943396151, -1.7293069363, -0.1460026801, 1.5145381689, + 0.1582663655, -1.7069764137, -1.0666083097, -2.0992667675, -0.3120955825, 1.5823105574, -0.2526357174, 0.6126517653, + 0.7511574626, 1.9334533215, -0.1653770506, 0.0007328019, -1.1496319771, 1.0879269838, -0.4144269824, -0.178288728, + 0.2705714405, -1.3183277845, -0.7594566345, 2.8128893375, -1.7517324686, -0.1413636059, 0.4365155399, 0.8948895335, + 0.3178620934, -0.6415089965, -0.0946490541, -0.0807673633, -1.0004671812, -1.5345644951, -0.2357628345, -1.5820407867, + 1.0702680349, -1.8865656853, -0.0901094601, -0.0760608092, -0.1922454238, -0.5639578104, -0.5438117981, -0.2419601381, + 0.9866610169, 0.3484502435, 0.214400664, -0.5236511827, 0.2716521621, -1.1190679073, 1.0188894272, -2.0297060013, + 1.5627001524, -1.2868920565, 1.2256826162, 0.2894935012, -0.7158158422, -1.3701560497, -1.0779329538, -0.0256836489, + 0.3960071802, 0.4327994287, 1.2228806019, -0.175721243, -1.3786426783, -1.9703372717, -0.586366415, -0.008004589, + 0.4041854441, -1.3040728569, -2.0099992752, 0.8277711868, 0.7524700761, -2.8358297348, 0.3762879968, -0.0772758722, + -0.1378519088, 0.0027876387, -1.0244839191, -0.3540144861, 1.7863705158, -0.3465160429, -0.5774444342, -0.2480545044, + -1.1455147266, -1.4086068869, -0.7194760442, -0.4547182322, 1.7560970783, -0.0071993573, -0.6203646064, -0.1874046624, + 1.5937808752, 0.5413727164, -1.4341344833, -1.6528888941, -0.245819509, 1.1216475964, 1.8508564234, -0.0923150182, + 0.1672917157, -1.5417040586, 1.4463324547, 0.5009288788, 2.8749001026, -0.706110239, 0.0816367939, -0.2914707661, + -0.0285660401, 0.0983645543, 0.2963778079, -0.3110705614, 0.8581354618, -0.7723867297, 0.8028447032, 0.2162812054, + 1.0721161366, 0.0564372241, 0.6005313396, -0.183187142, -0.4489869177, -0.9456906915, -0.0371265896, 0.4959995449, + -1.7010400295, -0.6790872216, 0.0206640214, -0.1886631548, 0.1214666665, 0.537138164, -0.626128912, -1.1847596169, + -1.1002988815, 1.4077138901, 0.3684228063, -1.1791006327, -0.0171466414, 0.148563534, -0.1480452716, -1.2246426344, + 1.071719408, 0.5924861431, -1.588218689, -1.8824286461, -0.7987720966, 1.6857186556, -1.9873899221, -0.6040264964, + 0.9996188879, 0.7584842443, -0.5855907798, 1.0974962711, -1.0957789421, 2.0606269836, -0.5865968466, -0.8793839812, + -0.7873229384, -2.5463385582, -0.6912784576, 1.2159292698, -1.9346731901, 0.3178563118, -1.4861592054, -1.6317461729, + -1.258656621, 0.9521486163, -0.2169671655, 0.7148294449, 0.7958927155, 0.9093554616, -0.1415878832, 1.3334403038, + 0.5828847289, 0.8194612265, -0.1050379872, 0.4659985602, 0.6288198829, -1.1417542696, -1.3998000622, -0.3798598349, + -0.4254036546, -0.3694149554, 0.5209847093, 0.8141931891, 0.2401541024, 2.484348774, -0.5280447602, -0.9274998307, + -0.1653894037, -0.1363191158, -0.8200877905, 2.1133174896, 0.8898195028, 0.8735603094, -0.0686016232, -0.9245443344, + -0.7718877792, 0.4842652678, -0.291589886, 0.7432041168, -2.115319252, 0.9568510652, -0.2215748578, -1.8422077894, + -1.2303696871, -0.1241944283, -0.7307086587, -0.6680089831, -2.3341002464, 2.207608223, -0.2407692969, 0.5288803577, + 0.2479257435, -0.1337349117, -0.5434597731, -1.7410125732, 2.0310096741, 1.1825866699, -0.5783034563, 0.2525941133, + 1.1653379202, 1.0282540321, -1.0832226276, 0.1212414354, -1.0867486, 0.2782225609, 1.0789091587, 1.1128096581, + -0.7514941692, 0.4164353907, -1.0873526335, 0.5424474478, -0.2048412859, -0.2030930966, 0.5863599181, -0.8489893079, + -0.3559145629, -0.5795920491, 1.5493372679, 0.4460066557, 0.0156894699, 0.1472632438, -1.3260676861, 0.7402061224, + -0.6366640329, -0.3111352026, -0.1385994852, 0.0820364133, 1.1148211956, -0.095073536, 0.2773782015, 0.9351531863, + 0.1982546598, 1.303161025, -1.2071324587, 0.5444293618, -0.4473699927, -0.410842061, -0.0568518825, 0.4197574854, + -0.6447360516, 0.3293173313, 2.5226984024, 2.6850180626, 1.9191200733, 0.0876055658, -1.8289321661, -0.318839103, + 0.175017029, 0.7548211813, 0.6596356034, 0.338653028, 1.7292153835, -0.1219225526, 0.6411107183, 0.7875508666, + 0.2660456002, -0.1457971931, 0.7125737071, 1.7682244778, -1.140966177, 0.6875343919, -0.9086990356, 1.6409335136, + 0.8345350623, -0.913865149, 1.2705948353, -0.2345217317, 0.4959183931, -0.6939529777, -1.386520505, 0.0969705433, + -1.442183733, -1.902564764, -1.1793817282, -1.9167758226, -0.3548213243, -1.7836306095, 0.4976726174, 0.9922037125, + -0.0509538837, -0.7649970651, 0.8111050725, 0.1019998342, 0.2750899792, -0.0343734659, 0.913341403, -1.3589154482, + 0.5406615138, -1.3692927361, 0.7702706456, -0.8848457336, -1.3492389917, 1.5141055584, -0.8034302592, 1.4701484442, + 0.7194578648, -0.3280103207, -0.1737902015, 0.3155027628, 0.8393989801, -0.7880792618, 1.4342643023, -0.2792739272, + 0.7217347622, -1.1199485064, -1.6488090754, -1.158880949, 0.2449669391, 0.9734916687, -0.8612310886, 0.2776378691, + -0.1442465335, 0.2899083197, 0.1926309317, 0.2951425612, 0.1448704749, 1.045593977, 1.5262594223, -1.8003038168, + 0.2336754799, -0.9080817699, 1.270406127, -2.140308857, -0.9260414243, -0.184079811, -0.3402787745, -1.6307851076, + -0.2041860521, -0.1278241426, 0.509517014, -0.6179625392, 0.0498966575, -0.4110610485, -0.5157909989, -0.6018150449, + -0.4285067618, 1.0633392334, -0.784820199, 0.1631879508, -0.214952454, -0.3020791411, 0.6054601073, -0.0504952818, + -1.0965297222, -0.7816454172, -0.2012111992, -0.6565100551, -0.1104105487, -0.2088105083, -1.911593914, -0.2466346174, + -0.2519866526, -0.4590988457, -0.0494616181, -0.6155298948, 0.2704988718, -1.8088672161, 0.7919092178, -0.1851701885, + 0.466101706, -0.3695489466, -1.0320540667, -1.1022082567, -0.6764156222, 0.4022864997, -0.2559004724, -1.2627768517, + 0.2470270246, -1.8833502531, -1.2920002937, -0.556438446, -2.3891890049, -1.1999177933, 0.7154252529, -0.1808043569, + 0.1423880011, -0.0719283819, 1.196506381, 1.0246064663, 0.2847369015, 0.0961781964, -0.2521937788, 0.7456894517, + -0.0504549034, -2.1432087421, 1.7391443253, -0.020690538, 0.9230058789, 0.1440964341, 0.3340483606, -0.563921988, + 1.1893047094, 0.8010678291, -0.0857279226, -1.6603605747, -1.8865714073, -1.5158432722, 2.2416851521, 1.303437829, + -1.2954757214, 1.3497186899, 0.6987150311, -0.537832737, 0.9773977399, -0.6292833686, -0.2258862704, -0.0231768172, + 0.2287255973, -0.0307552647, 0.2602588534, -1.1946291924, -0.470148772, -1.6524150372, 1.5998086929, 0.8542186022, + -0.8980391622, -0.3424322009, -0.7620440722, 0.5442741513, -2.6877915859, -0.6870270967, -0.1067433506, -0.5056813359, + -1.1792836189, 2.6766495705, -0.7369825244, -0.4661085606, -1.5385745764, -0.0672003403, 0.3695683777, -0.7869833112, + 0.4003332257, 0.3783661425, 0.5367749333, -0.5993347168, -1.6679698229, 1.3760275841, -0.1786604971, -0.0802356526, + 1.0228990316, -1.9961047173, -1.0266917944, -0.5655768514, 0.8560996652, -1.4708665609, 0.7181494236, -0.1992621869, + -0.3848416209, -1.4284293652, 0.0078248149, 0.0301324613, 1.0360671282, 0.0559637584, 0.7436648011, 0.2172421217, + -0.4548107982, -1.8581829071, -0.2697221041, -0.7858588696, 0.2048793733, -0.167439267, -0.5469172597, 1.3462063074, + 1.0827282667, 1.122854948, 1.032607913, -0.9947468042, 1.4552406073, -0.3257787228, -0.7388832569, -0.786190927, + 0.2828303277, 0.305668056, 0.2146909982, -0.277215302, 0.3958362639, -1.3230555058, -0.8603905439, -0.282733202, + -0.3374444246, 1.5174309015, -1.3406960964, -0.7753478289, -0.6090564132, 0.4148904383, 0.1143402532, 0.6358146071, + -1.018995285, -0.247077629, 1.8384991884, 0.2994590998, -1.3782683611, -0.9034779072, 1.0411815643, -0.8380994797, + -0.0788478255, -1.2593122721, 0.0735025629, -1.2232187986, 0.0042018746, 0.4956058562, 1.079344511, 0.3841406405, + -0.5286387205, -0.8840914369, 0.1363095641, 0.2901922762, 0.5978170037, 0.2368114442, -0.1575534791, -1.1024419069, + 1.1252269745, 1.5449730158, 0.3530938923, 0.7228652835, 0.1168344319, -0.0158468988, -0.1661573797, 0.538161397, + 0.3136244714, 0.0325458795, -1.2324377298, 1.0933052301, -0.1038841233, -0.2963826954, -0.9586788416, 0.720012784, + 1.4924416542, 1.7752082348, -0.0550629981, -1.6644073725, -0.5077100992, 0.2773285806, 1.0041874647, 0.4742742479, + 0.4997110963, 0.2690739036, 1.5814677477, 1.5842721462, 1.115316987, -2.0206856728, -0.6906757355, 0.8339030147, + -2.4003989697, 1.7535443306, 1.4520895481, 0.5084596872, -0.1650930792, 0.1084622741, 0.5147604346, -0.7298306823, + -1.9664291143, 0.6762105227, 0.5794365406, 0.7264261246, 1.2572396994, -1.8034398556, -1.4639929533, -1.3501420021, + 0.3714019656, 0.7283082008, 0.5316600204, 0.4573111832, -1.6541035175, 1.7793091536, -1.6135524511, 1.4555981159, + 0.8226402402, 0.7780967951, 0.1016966924, 1.1728751659, -0.4354915619, -0.426864028, 0.8830320835, -0.7973753214, + -0.8927229643, 1.0299344063, -1.4835407734, 1.2919406891, 0.9132064581, 0.3831681311, 0.383402437, 0.9610646367, + -2.4891815186, -0.8557786345, 0.2069403827, -1.5988606215, -0.9463294744, 1.0044388771, 0.5957759619, 0.3084153235, + 0.2008418739, -1.1726783514, 0.2280961126, -2.1500291824, 1.962198019, 0.0185094886, 0.4452189505, 0.921641767, + -1.0115605593, 2.1943533421, -0.164006725, -0.4602047801, -0.2296462357, 0.9627048373, -1.0101568699, -1.4202458858, + 0.4832316637, 0.046259284, -1.5302428007, -0.3245599866, -1.0381706953, 1.2537368536, -1.6339751482, -0.165242821, + -0.3389556408, -0.0146003719, -0.7025259137, 2.6607224941, -0.6276010871, -1.0365874767, 0.4586429, -1.0496587753, + -0.2999071777, 1.3842225075, 1.0823534727, -2.3419559002, 0.8761150837, -1.8273769617, -0.2215786427, -0.3491138816, + -1.9336280823, -0.0474423543, -2.4403247833, -1.2015104294, -0.2873283327, -0.8806145191, -0.8555080295, 0.0481235869, + -0.8469879031, -1.1857453585, -0.9132013321, -0.4592289925, 0.0136311175, 0.6643366218, -0.0491968133, 0.2498437613, + -0.8947763443, -0.0383777991, 0.0546499304, -0.3900771439, -0.4424458146, 1.0053803921, -1.643740654, -0.235190779, + 0.0837585628, -0.8065138459, 0.3854508698, 1.7295747995, 1.0369310379, 1.0545397997, -0.1897726953, -0.660972774, + -0.6300903559, 1.0252816677, 1.381695509, 0.0301201232, 0.455262661, -0.0021572479, -1.2396833897, 1.6422270536, + -0.9795646071, 0.3572402298, -1.4496890306, 1.416897893, -0.8599024415, -0.1259931624, -0.8222708106, 0.3623867333, + 0.1708000451, -0.3181733787, -1.9245707989, 0.0009699502, -1.5193839073, 0.6653414369, 0.2419777066, 1.6192805767, + 0.9414151907, -0.694175005, 0.4210597575, 0.2198369801, -0.5225008726, 0.5529451966, -0.1377501786, -0.0109302262, + -2.6844522953, 1.0686687231, -1.0907949209, -1.6353297234, 0.2023297548, 0.6188598275, -0.2628114522, 1.0546277761, + -0.1554549485, -0.4642913342, -0.047121767, -0.0422636569, 0.7548336983, 0.4991921484, -2.0590631962, 0.3868599534, + 1.4013535976, -0.9825395346, -1.3489254713, -2.1613402367, -1.1077320576, -0.011571967, -0.1067917049, 0.2030382305, + 1.0208203793, -0.9721820354, -0.8007465005, 0.7475744486, -0.1014548764, 0.1717854142, -0.890086174, -1.1787598133, + 0.283629179, 0.6105752587, 0.0714654922, 0.2032693624, -0.0388820209, 0.0560920835, 0.2171260417, 1.4609282017, + 0.339767158, 0.6166418791, 1.0261284113, 1.1398640871, 0.0585809164, 0.3839966655, 0.121096082, -1.448605299, + 0.9515943527, 1.169459939, -0.4625164866, -0.5766818523, 1.3717787266, 0.4527533352, -1.0115367174, -0.2389606684, + -2.1135818958, 0.920004487, 1.2121772766, -0.0131268874, -1.0547879934, -0.4625411332, -1.1228022575, -1.9511053562, + 0.2523438334, 0.033521343, 3.1744377613, -0.3097344339, -0.0796215609, 2.3843185902, 0.1680177748, 1.1310538054, + -0.2883731723, 1.0993871689, -0.0557040833, -1.380363822, -0.1418625414, -0.0994756371, -0.3607069254, 0.1630599797, + -1.871673584, 0.5809935331, -0.088757284, -2.0139195919, -0.1107501611, -0.1171881333, 0.0923445001, -1.1246478558, + -0.0643767715, -0.6560503244, -0.0982639194, -1.1385906935, 0.3597646356, 0.7687802911, 1.0907343626, 0.9932415485, + 1.5794206858, -0.4556078315, -0.084510304, 0.195314303, -0.4470531642, -0.31480968, -0.5831922889, 0.7251600623, + -0.366489917, 1.1142308712, -0.2529630065, 0.1108265817, -0.0751002133, 1.6626136303, 0.1881306767, 1.1572419405, + -1.509215951, 0.4438718259, 1.0644911528, 0.0690576583, -0.5484440327, -1.1120855808, 0.2062901407, 1.7126512527, + -0.6370053887, 0.4516954422, -0.6429297328, -0.4736404121, 1.9491024017, -1.1057304144, -0.0583164655, 0.0027293719, + 0.0433787964, -0.9135349393, -0.7275012732, 0.1881026775, -0.6704826951, 0.3486644924, 0.7248296738, -0.304523617, + 0.4539546967, 0.5046046376, -0.4356022477, 1.3943544626, 0.8857178092, 1.4404188395, 2.6176686287, -0.5996223688, + 0.9162171483, -0.5749520063, 0.0330234617, -1.6783542633, 0.207101956, 0.2668921053, -0.2316341698, 2.5724213123, + 0.0771679357, 0.02264167, -1.010440588, 2.0703089237, 0.2559503615, 0.3081150055, 0.4898057878, -0.8981673717, + 0.1386307776, -2.3951253891, -1.0491285324, -1.408564806, 2.2214100361, -0.090914242, -1.263204813, -1.383914113, + -0.4299320579, 1.6684657335, 2.2021830082, 0.5257831812, 0.573987484, 1.2139933109, 1.1535638571, 0.1974461824, + 0.5228608251, -0.4663076997, -0.8205826879, 1.2096979618, 0.4772752225, -0.2883346677, 1.1037921906, -0.4656058848, + -0.0572867543, 0.1929015964, -1.2480163574, -0.2613046765, 0.3618875444, -1.8665893078, 0.4445092082, 0.3430060148, + -0.3016341925, -0.671249032, -1.964758873, -1.4762607813, 0.6007431149, -2.1796936989, 1.7869907618, 0.4041797519, + 0.7283347845, 0.2149192095, 0.0791092888, -0.0756125897, 2.0927040577, 0.6142238379, 0.6972085834, -0.2808259726, + -0.6297846437, -0.6537150741, -0.6563082933, 0.0635813102, 1.1474578381, -1.3920365572, 0.8224881291, -1.2620323896, + 2.2960383892, -1.534919858, -0.7157036066, 1.8768742085, 0.648032248, -0.0833342448, 1.9466234446, -0.9626903534, + 0.1901564449, 0.2450418174, 0.6438478827, 0.5414466858, -1.6009700298, 1.2528609037, -0.5713541508, -0.1698438674, + -0.0962642208, 0.7907935977, -0.3675736487, 0.2545646727, -0.1731839627, -2.0102469921, -0.0823436901, 0.4109261632, + 0.9124290943, -0.5108228922, -0.170289591, 0.5690754056, 0.1842122078, 1.1614910364, -0.7973006368, -1.7424471378, + -0.1686261892, 0.9480429292, 1.2066537142, 0.9066698551, 0.6930658221, 0.3705970645, 0.516245842, 0.6608072519, + 0.4866171181, -0.4750882685, 0.9606438875, -0.1774173826, -1.1164638996, 0.656550169, 0.2430785298, 1.3326601982, + 0.2276160568, -0.763877213, -0.6724875569, -1.394546032, 0.7054424286, -0.347019881, 0.7814444304, -0.9647708535, + -0.846544385, -0.5008096695, -0.5663548112, 1.0299090147, -1.2219821215, -0.9223409891, -0.0413170531, 0.732734561, + -0.4150656462, -0.3697193563, 1.3278313875, 1.1300793886, 0.8595128059, -2.1058371067, 0.411795795, 1.4069085121, + -0.8631376624, 0.9940280318, 0.0828463808, 0.6927403212, -0.5555388927, -2.1278247833, -0.2419712394, 0.2147070467, + 0.8770046234, -0.8252259493, -0.3071250319, -0.4251047075, 0.4736202955, 1.4847452641, 0.7876216173, -2.3725543022, + 0.8668217063, -0.5885546207, -2.0502035618, 0.1267351955, -1.3493905067, 0.6182358861, 0.1972312331, -0.8721260428, + -1.7464439869, 1.3869823217, 0.1516992599, -0.0960684121, -0.5976011157, -1.6084567308, -0.1104261652, -0.326630652, + 0.9532612562, 2.8422458172, 0.7323229313, 2.3837733269, -1.4173332453, -0.2441341728, -1.059849143, 0.0659141317, + 0.1451799124, -1.3646274805, -1.3189326525, 1.0868996382, 1.1407871246, -0.7739912271, 0.2757473886, 1.0186146498, + 0.3553026319, 0.0994194523, 0.4954006076, 1.3101518154, 0.9655687809, -1.3013892174, 1.6685962677, -1.6873700619, + 1.2311973572, -0.7829509974, -0.5541905165, 0.2968224883, 0.1373548359, -0.3030631542, 2.0867037773, 0.2923654318, + 1.014239192, -0.3932260871, -0.0352618359, 0.5864498615, -0.5295163393, 0.685231328, -0.164385289, -0.3441419303, + 0.2067484409, 0.1120802909, -1.8413914442, 1.0845415592, 0.7977465987, -1.6193389893, -0.3356162012, 0.5115650296, + 0.1433262229, 0.618511498, 1.3554399014, 0.7320787907, 0.7957426906, 1.4062149525, -1.7205719948, -0.250341773, + 0.5847280025, -1.2508269548, 0.0660410076, 1.6999821663, -1.6192164421, -0.5963765979, -2.1174936295, -0.8630749583, + 0.3964715302, -0.6267700791, -2.0068068504, -1.7333778143, 0.3489642739, -0.3829937875, 2.0327324867, 1.9875861406, + 0.2677262127, -1.4474372864, 0.3494439423, -0.8642144203, -0.5014429688, 2.0740737915, -0.3882977068, -0.4317372143, + -0.4059042037, 1.0080896616, -0.6950193048, 0.5184195042, -0.9137551188, -1.440993309, -0.7854880691, 1.8851081133, + -1.7892971039, -0.815849781, -0.3761253655, -0.2095122784, -0.7854520679, -1.0257658958, 0.3675001562, -0.7535496354, + 1.1216030121, 1.0277554989, 0.1140085235, 0.3061859906, -0.8787401319, 1.1658949852, 0.1283266991, -0.236714825, + 0.6065468788, -0.2742420435, 1.1453546286, -0.0845240206, -0.0997853056, -0.4292584658, -0.9366860986, 0.7969179749, + -0.0418951027, -1.9022171497, 1.3403178453, -0.2650252581, -0.1395718455, -0.1130125746, -0.2644657791, 0.8363052011, + 1.4173330069, -0.0139653347, 0.014096952, -1.3867497444, -0.2896922827, 1.4394404888, 0.0371060893, 0.4729910493, + -1.6448743343, 1.9283530712, -0.0540869758, -1.5597012043, 1.3833075762, 1.4959639311, -1.2113410234, -0.80359447, + -0.0742011741, -0.0012471536, 0.5972085595, -0.5049758554, -0.8977391124, -2.4309682846, -0.7694957852, -1.2447004318, + 1.8496736288, -0.1600045711, 0.3851931393, 1.6098812819, 1.3233433962, -0.5853709579, -1.4895451069, -1.6313624382, + -1.0789774656, 0.1750666648, -0.8689029217, -1.2971252203, -0.1602051109, -0.4810235202, 0.8413378, 0.4719519913, + -1.443687439, -0.4337729514, 0.1231140718, -0.1029697135, -0.2789793313, -1.8605657816, 0.9095398188, -0.3967422843, + 2.4552280903, 0.700719595, -1.0971454382, 0.1571447253, -1.6993728876, 1.1674585342, -0.6445943117, -0.3044758141, + 0.682256043, -0.644367516, 0.2809943557, -0.8231162429, 0.3418474495, -0.9646231532, -0.9446858764, -1.1312217712, + 0.2950759232, -2.0998363495, -0.9623675346, 0.5983527899, -0.570690155, -2.814915657, -0.96443367, -2.2830367088, + -1.4362345934, -2.5027389526, -1.0116815567, -1.3881716728, -1.0808703899, 1.1213512421, -2.9426026344, -0.8580161929, + 0.8869637847, 1.3504574299, 1.6489382982, -2.0368595123, 0.4648270607, 0.4125159681, 1.508998394, 0.1617003679, + 0.2972085178, 0.3435890079, 1.2503364086, 1.6973853111, 0.5223636031, -0.6074130535, -1.4800554514, 1.0115360022, + 1.2797082663, -0.9638424516, 0.023859363, 0.700168848, 1.0566946268, -1.2123521566, -1.5452622175, -0.7135031223, + -0.2995873392, 1.3495112658, 1.0317986012, -2.151848793, -0.260861367, 0.4728642404, 0.14328897, -0.5136743188, + 0.8816134334, 0.4160916507, 0.9742739797, -0.5911037326, 0.5096975565, 0.732976079, 0.1781499535, 0.4407790899, + -0.7507807016, 0.9301936626, -0.1136841103, 0.2096375674, -0.3831914961, 0.1437592804, 1.9191459417, 1.1668577194, + -0.0390432589, 0.7552515268, 0.7185825706, -0.1992563307, 0.2191366404, 0.4416317344, -1.780610323, -0.5829799175, + -1.6506224871, -0.380040437, 0.5495235324, -2.4511246681, 0.2122054845, -0.6588183641, 0.2381319553, 1.413872838, + 0.1893429458, -0.2653420866, -1.4341834784, -0.0134915356, 1.0526467562, -0.4494713843, 0.3941705823, 0.4576940835, + -0.6274823546, -0.4867767394, -0.3145232499, 0.7940014005, 0.2057987899, -0.9098162651, 0.3779762983, 0.4768439829, + 0.5508027077, -0.2443206012, 0.377124548, 0.935810864, 1.0886226892, 0.9422910213, 0.5694215894, 0.1278016269, + -1.6078619957, 0.9920114875, 2.0334231853, 0.8720038533, 1.2157073021, 1.0835859776, 0.0771418586, 0.9433466792, + 1.1806234121, 1.713340044, 0.8349636197, -0.340929538, -1.4217534065, -0.9918186665, 1.3714574575, -2.8138613701, + 1.5928198099, 0.051456999, -0.3350365162, 0.1681042314, 2.0830357075, 0.1723357737, -0.7525523901, -0.6203945279, + -0.431047827, 0.8727289438, -1.6561784744, -0.0651366413, -0.2049668729, -0.6367900372, -0.4473701417, -0.4513550401, + 1.0316622257, -0.6272398233, 0.8326088786, 0.6830444336, -1.3253782988, -0.5727469921, 1.1235693693, 0.3231909275, + 0.7557680011, -1.1440552473, 1.2230265141, 0.4768500626, 0.2638700008, -0.3666841686, -0.1768282652, -1.6205668449, + 1.7069422007, 0.8102005124, 0.3011316061, 1.5844978094, 1.3711355925, -0.9427987337, 1.6457824707, -1.0328581333, + -0.2671949267, -1.4802416563, 1.9849010706, -0.56262362, 0.0849812925, 0.282217294, 0.7228338718, -0.7783156633, + -1.247341156, 0.2193592489, 1.0145031214, -0.0329789929, 0.2228203714, 1.1445417404, -0.709403336, -0.7841330767, + -1.0221625566, -0.5994387865, 2.6038806438, -0.0352037288, -1.0069522858, 0.7614061236, -0.3151522279, -0.4787478149, + 1.0351151228, 0.9559835196, -1.6696609259, -1.5952768326, 0.8844750524, -0.1393707395, -1.933978796, 0.5813475251, + 1.3983411789, 0.7789682746, 0.6822609901, 1.1423463821, -2.8080708981, 1.2361961603, 0.179365471, 0.2740286887, + 1.7551431656, 0.803304255, 1.5408403873, 1.2425165176, -0.3679214418, -0.4071923494, 1.0675301552, 1.0157678127, + -1.6916062832, -0.0623279475, -0.0539634116, -0.861355722, 1.2769105434, 1.3883987665, -0.0332604498, -0.3398702443, + -0.6552860737, 1.4018083811, 1.0553525686, 0.1255802065, -2.8219633102, 0.5146217942, 1.4022740126, -0.0046099331, + 0.8136485219, -0.919590354, -1.3112980127, -0.4670576155, 1.4047838449, 0.5764878988, 0.3580507934, -1.571639657, + 0.6349464655, 0.7771478295, 1.0435512066, -0.3213168979, -0.8127188683, -0.2205226868, -1.217915535, -1.9275535345, + 1.7975726128, 0.5448293686, 0.7044969797, -0.399260819, -0.5087509155, 2.109474659, -0.7843719125, -0.229173705, + -0.7270941734, -0.7784538865, 0.4416177571, -0.2448096573, 0.8384055495, 1.4899570942, -1.1972079277, 0.3306650817, + -0.5491546988, 0.3423768878, -0.7401416302, 0.6068357825, 0.3473240435, 0.317515254, -0.0742286593, 0.3980647922, + 0.7580665946, -0.0345872045, -0.8518533111, -0.4360183477, 0.6210014224, 2.7143337727, 0.799873054, 1.5790160894, + -0.4784846306, -1.361552, -1.1311392784, -0.8737077713, 0.4509058297, -0.9993168712, -1.9487090111, -1.0683714151, + -0.6897867918, 0.1995844096, 0.6471304893, -0.7248669863, 0.5458530784, -0.019575296, -0.6879757643, 0.0733593181, + 1.414932251, 0.6252916455, -1.2030237913, -0.8833094239, 0.4984725118, -0.8347005248, 1.1032197475, 0.3863393962, + 0.4053649902, -0.3788195848, 0.0324828625, 0.3399371207, 2.4221336842, 0.5677464008, 1.5449701548, 1.0187703371, + 1.1051464081, -0.0787986144, 0.7276761532, -1.7961450815, -0.7372569442, -0.496116966, -1.8179187775, 0.4991966486, + 0.4435710609, 0.6528558731, 0.0615191497, 0.5835493803, 1.1446419954, 0.1317789853, 0.4888918102, 0.758017242, + 1.5825773478, -0.4546769559, -0.4600296915, -0.237854749, -0.0576866977, 0.900713861, -0.578356266, -0.936052978, + 0.8583307266, -1.1411458254, -0.2024374753, -1.1240649223, 0.5279912353, -0.4751847982, 0.6631527543, 1.6318333149, + 0.096947737, -0.4408459961, -0.4316680431, 0.5758231282, -0.7765583992, -0.3135903776, 0.1644244492, -0.9466973543, + 2.4841709137, -0.1300010383, 0.997806251, 0.7827248573, 2.0063924789, 1.5243164301, -0.3948339224, 0.0537491739, + 0.7989837527, 0.224097684, -2.4085738659, 0.7977293134, 0.8477253914, 1.0057256222, 0.8337087631, -0.4097576737, + -0.4895608127, -0.6883573532, 1.0892106295, -0.043151509, -0.6405534744, 0.6923466921, 2.7715198994, -0.0121520748, + 0.4013367295, 0.2561378479, -2.07761693, 1.7508301735, 1.3922433853, -1.0740218163, 0.5858798027, -0.8643900752, + 1.1791176796, 0.5617208481, -0.2729750872, 0.4421900213, 1.9618458748, 0.1082156897, -1.0202893019, 0.6061573029, + -0.9337441325, -0.6937928796, -0.6611673832, 0.5429068208, -0.4369900823, 0.4420260191, 0.2651502788, 0.1907901913, + -0.1864834428, -0.6720966697, -0.1947799325, -0.4772402048, -0.3070857525, 0.5616519451, 0.4010860026, 1.2816871405, + -0.1345330328, -0.3634308279, 0.2095918655, 0.5743795633, 0.5211598873, -0.3771933019, -0.5893455148, 0.4899389446, + -0.5980780721, -0.2535832822, 0.028210666, -0.7644257545, -0.4702759683, 1.3134050369, -0.1494729519, -0.7538666725, + 0.0136112459, 0.077715762, -0.1643834263, -0.2342753261, 0.8124720454, -0.6758717299, 0.1944087893, 1.5166828632, + -1.3424445391, -1.7649502754, -0.8097494245, -0.0012850497, 1.4531955719, -0.4727535844, -0.8327094913, 1.0155029297, + 0.3293326497, -0.645091176, 0.3764901757, 0.1045299768, -0.1445874125, -0.2936522067, 0.923566401, -0.2783232927, + 1.3137370348, 0.0172006525, -1.3841036558, 1.5561493635, -1.863902092, 1.0495033264, -0.5255575776, -0.1408940107, + -1.9543750286, -0.1556380987, 0.1417855322, -0.2631154954, -0.4426996112, 0.5870085359, -0.500051558, -0.5050081611, + 0.546302855, -1.0903365612, 1.5628612041, -2.7882788181, -1.334471941, 0.8784140348, -1.6840302944, -1.8166384697, + 0.0311815683, -0.4051390886, -0.0798487365, -1.5385483503, 0.9227674007, -0.5343394876, 0.0507932045, -1.4572614431, + 0.358484596, 0.3457713425, -0.5961431861, -0.6469150782, 0.1584200561, 0.4568893313, 0.3769147992, 0.4354852736, + -0.5486419201, -0.2239340246, 0.6698993444, -1.0490089655, 0.5744723082, 1.5347912312, 1.5397765636, -0.1221618131, + 0.5470622778, -0.6007783413, -1.233623147, 0.93685776, -1.1393072605, 0.0572789684, 0.5984082222, -0.1399062723, + -0.9106681943, -0.806753397, 0.1479307711, 0.921500206, 0.3112674356, 1.3075610399, -1.7026318312, 1.3720930815, + 1.2918262482, 0.5612526536, -0.9967388511, 1.2426233292, -2.2951490879, -0.015267496, -0.9043204188, -0.5141695142, + 0.4446947277, 1.1492751837, 0.0521705337, 0.6528357267, -1.2749031782, 1.0507358313, -1.0188709497, 1.7837384939, + -0.9868627191, -0.2265499085, 0.2017863989, -0.9687949419, -1.973107934, 0.169619441, 0.5233901739, 1.4001473188, + 0.4637394249, 0.7948895693, 0.0983602554, -0.4224130213, -1.2093416452, 1.1387294531, -0.9182177186, 0.5414411426, + -1.11868608, -1.8909265995, -3.0632636547, 0.4568120241, 2.0387444496, 0.4237249792, -1.9272114038, 0.9853472114, + 1.338927865, -0.1318121105, -0.8920201063, -0.277359724, -0.4517774582, -0.7616629004, -1.1646945477, 0.9879109263, + -0.3608299196, 0.4053466022, -0.4165501297, 0.3574571311, -1.2699836493, -1.6300295591, 0.5598648787, -1.4674304724, + 0.4131439328, -0.4219754934, 2.0304031372, -1.4413354397, 0.4799681306, -0.0420383178, 1.6915184259, -0.5232487917, + -0.8039526939, -1.060140729, -1.5404548645, -1.0749971867, -0.2996744812, 1.3575615883, 1.0603859425, 1.0530307293, + 0.1001334339, 0.3675707281, 1.1156344414, -0.7672547698, -2.4473090172, 0.3544388413, 0.7223312259, 0.827989459, + -0.675761342, -0.1550412029, -0.0579219274, 0.1946964562, -0.6854659319, -1.0218989849, -1.1483523846, -1.4241236448, + 0.5684677362, -1.2633242607, -0.5404099822, -0.6181235313, 0.8761564493, 0.2720177472, 0.6743654013, -1.391789794, + -1.3827804327, 0.0717442855, 0.117510654, 2.1652770042, -1.1354564428, -0.6457980275, 0.0317389071, -0.7400742173, + 0.961979568, -0.0593260564, -0.6544432044, -0.1337867081, -1.2988967896, -0.355589062, -0.604587853, 0.2226153016, + 0.9822761416, 1.1462154388, 0.2895379364, -0.4104592204, -1.1960166693, -0.1224415079, 1.1972869635, 0.6265248656, + 0.3610025048, -1.7972739935, 1.3773232698, -0.652213037, -0.7375943065, -0.4990181625, -0.3867849708, 2.1639332771, + 0.1491455138, -1.363096714, 1.8294426203, -0.8609524369, 1.442792058, -0.4151449502, 0.1516723335, 0.2960756719, + 0.3308898211, 0.4983998239, 0.1312209517, -1.0052082539, -0.8411090374, -0.6049742699, -0.0483746789, 1.0027732849, + 1.0322577953, 0.2257779986, 2.2114481926, 0.2201044112, -1.3947371244, -1.0045163631, 0.5725672245, -0.4024380744, + -0.1606439054, 0.5383403301, -0.9939112067, 0.4404547215, 0.477861166, -0.797209084, 1.2639709711, -0.0904689953, + 0.0119346408, -0.2128958404, 0.1294909567, 0.6935775876, -0.8069289327, 0.0381242223, 0.0640896633, -0.851903975, + -1.1961863041, -1.6041916609, 0.3708937764, 0.4002925456, 0.624664247, -0.3795958757, -0.2372878045, 0.5787289739, + -0.6773391366, 0.1989562958, -0.0726481527, 0.6693786979, 0.597175777, -0.1213830337, -1.7431809902, 1.4139084816, + -0.3425191939, 0.2435627282, -0.0741600394, -0.9220610261, 1.0343546867, -0.8678551316, -0.3198132217, -0.6899349689, + 0.4179919362, 1.2124581337, 0.0375941433, 2.2486476898, -1.022020936, 0.6465313435, 0.427898854, 0.9193848372, + 0.422223717, -0.0933749005, -1.0670326948, 0.7879496217, -0.9432157278, -0.9096699357, -0.7628371716, -1.6910816431, + -0.1087954193, 1.1553153992, -0.2835746109, 0.9786539078, -0.1439840198, -0.591253221, -0.7626441717, 0.2139990479, + 0.8680096269, -2.1934850216, 0.7954643965, 1.2878558636, 0.307228893, 0.9573891759, 0.5701214671, 1.2529802322, + -0.0815569162, 0.812897861, -0.981122613, 0.2701521218, 0.9489287138, -1.9259961843, 0.27530393, -1.3883477449, + -0.5270357132, -0.2019829303, -1.1113721132, 0.105697453, 0.496596396, -0.1771866232, 2.482167244, 0.8626716137, + -0.1475741863, -1.8463534117, -0.1793068349, -0.8907314539, -0.4722703099, -1.5586285591, 0.1077410355, -1.9330302477, + 0.755890429, 0.2947430611, -0.6818034053, 0.8157358766, -1.2121231556, 0.350235194, -2.2251851559, -1.0909916162, + -0.0607460439, -0.7485980392, 0.5062255263, 0.2378816903, 1.2893656492, -0.6041642427, -0.6925551295, -1.1607208252, + -0.2876462042, 1.0311911106, -0.0499792546, -1.3574689627, 0.824996829, -0.8970457315, -0.1135150492, 0.2143322527, + 1.3763307333, 0.8509597182, 1.7496386766, 0.6001273394, 1.4015005827, 0.3860958517, 0.5434395671, -0.4725933969, + -0.287702769, -0.6129447818, -1.4196848869, 0.3062418699, -0.1553191394, -0.9508764744, -0.0760941654, -0.8062614202, + -0.8954066038, 0.04842427, -1.0906312466, -0.173253566, -0.3397390246, 0.3176231682, -1.5844293833, 1.2997056246, + -0.6607711315, 0.1271229833, 0.0425397344, -0.4639439285, -0.9103606939, 0.3158217371, -0.3238605857, 1.6766819954, + 0.9372931123, 0.2473313659, -0.8097632527, 0.0890621245, -0.8043243289, -0.3928592503, -0.3789885342, -0.7877340317, + -0.7610335946, -0.4013801515, -0.0189523175, 2.329908371, 0.8038778305, -1.9815123081, -0.7011249065, -0.9096357226, + 0.9332553148, -0.2004610598, 1.7981244326, -0.0330081321, -0.2495200932, 0.8726334572, -0.6514548063, -0.5128629804, + 1.6354423761, 0.3905225694, -0.839022398, 0.8316834569, -0.0595287457, 2.0173168182, -0.8562936187, 0.6865690351, + 1.3743298054, 0.39076823, -0.2398041636, -0.1251194626, -0.6344032288, 2.2980499268, -0.4630606771, 0.2461500913, + 1.3341190815, -0.3485464156, 1.2087879181, 0.1016988084, -2.199429512, 0.1064224765, -1.8571059704, 1.5093195438, + 0.1532788873, -0.5053347945, 0.3831263781, -0.1220782623, 1.1170195341, 1.0353970528, -0.7229524255, -0.3387831151, + 1.6032934189, 1.7609171867, -1.2161747217, 0.5180673003, -0.6836446524, -1.6527055502, -0.8767384887, 1.046276927, + 0.2828881741, 0.4827982187, 0.2307805121, 0.7823326588, 0.9507107735, 1.4595805407, 0.6798090935, -0.8676077724, + 0.3908489645, 1.0838125944, 0.6227587461, 0.0919146538, 0.6267312169, 0.7369835973, -0.4665488899, 1.537971735, + -1.0313144922, 1.039896369, 0.8687855005, 0.2055855989, -1.771664381, 0.2428264916, 0.1570801437, -0.8153182268, + -0.202206254, 0.5724145174, 0.5329394341, 1.667875886, 0.5379707813, -1.2548235655, 1.5401520729, -0.22708489, + -1.1637035608, 0.7588675022, 0.6385750175, 0.2570756972, 1.0582165718, 0.3091140985, 1.6547634602, -0.2367554605, + 1.257604599, 0.0599439889, 0.0446613617, -1.8018302917, -0.2758919001, 0.6777992249, -0.1838328093, -0.9692851901, + 0.9890301824, -0.2224184275, 0.5610032678, 0.7233167887, 0.0912953764, -1.4654313326, -0.5956678987, -1.0447202921, + -2.0769333839, 0.9551025629, 1.1798607111, -0.5978704691, 1.7572724819, -0.1310936958, -0.2408575267, -1.555511713, + 1.5630480051, 0.4313979149, 0.6554265618, 0.0821268037, -2.1948366165, 1.2969125509, 0.8677711487, 0.3639212549, + -0.5787127018, 1.5105884075, 1.0996694565, -0.5503646731, -0.4026169181, -0.0874640346, -0.4514757693, 1.4189465046, + -0.4797129035, 0.373319298, 0.2657961547, -0.8370972872, 0.3150520921, -0.9210009575, 0.1015821472, -0.5309605002, + 0.0664992332, -2.0074801445, 2.2297945023, 0.0819370598, 0.147999227, 0.1758866161, 0.8668915033, -1.0901758671, + -1.8159155846, 0.5403104424, -0.1107598692, 1.0183703899, 1.9810978174, -0.4993706942, -1.5936735868, -2.0820102692, + 0.8839993477, 1.2424896955, -0.375447005, -0.4873703122, -1.3391138315, -2.8575394154, 0.894562304, -0.0517046452, + 1.135389328, 1.0172095299, 0.1628982425, -0.3798680305, -0.8960040212, -0.2011121809, -0.0567418709, 0.2119727731, + 0.6210333109, -0.1791775525, 0.8862378597, 0.8935353756, 0.8979471326, -0.810266912, 0.0424867161, -0.6294496655, + -1.0798614025, -0.2119414806, 0.7185308933, 0.827639401, -1.5393027067, 0.799536705, 0.6526834369, 0.3812628984, + 1.6862120628, -0.5823438168, 0.5357362032, -1.8718117476, 1.8158414364, 0.0115653146, 1.009010911, -0.0481402576, + -0.0621399991, 0.5543729663, -0.0510954261, -0.4064195454, -0.5600697398, -0.1420308799, 1.2426292896, 0.2519005239, + -0.0725310817, -0.871997416, -0.6856629848, 0.0003807768, -0.1563270241, -0.4662569165, -0.0164176356, -0.3071641624, + -0.4057198167, 1.3780448437, -0.9845128059, 1.2129591703, -0.2401970625, 1.7031100988, 1.1683377028, -0.9992445111, + -0.8173805475, 0.2220273167, -0.3547341526, 0.4088989198, 0.3500408828, -0.4819968045, 0.3505795598, -0.8347722888, + -0.6508687139, -1.4876539707, -0.2163732499, -0.241728425, 0.9192639589, -0.0174811445, -0.6125581861, -1.7423535585, + -0.2791055739, 0.3562209904, 0.2949730754, 1.1177265644, -0.5972783566, -1.7783836126, -1.120847702, -0.2938118279, + -0.4967626035, 1.0432761908, -1.0701702833, 1.0008829832, 2.2375409603, -0.0449116081, -1.3642407656, 1.4596179724, + 1.1632910967, -0.5697431564, -1.7598483562, 0.0133777484, -0.4007295072, 0.7930163145, 0.9166504145, -0.4451917112, + -0.3771822751, 0.5663695931, 0.6020166278, 0.6256309748, 0.3488479257, 1.4128754139, -1.1541855335, 1.3467293978, + 0.0763891712, -2.218079567, -0.8790378571, 0.7706360221, -1.0272171497, 0.3823670149, -0.4660917819, -0.5811817646, + -0.9728909731, -0.3998017013, 1.3444324732, -0.2047507763, 1.6922044754, 0.7689399719, 0.7740138173, -0.928178966, + -0.4968115091, -0.7952126861, -0.0446061157, 0.2427589148, 1.3154057264, -0.963829875, -2.4491629601, 1.8243825436, + 0.6550926566, 1.3024812937, 1.2062610388, 1.5797829628, 1.6227316856, -1.1122174263, -1.0028078556, -0.3198828399, + 0.6408913136, 0.541169703, -0.3132085502, 0.0905704945, 0.4082139432, 1.0586953163, 0.0793558359, 0.2908940911, + -0.4207540154, -1.0434504747, 0.8331912756, -1.278096199, -1.4766488075, -1.6978293657, -0.0705931783, 0.2020439953, + -0.0928261653, 0.6194707155, 0.0804834291, 0.3376404047, 3.4837553501, 0.2669399977, -1.4626413584, 0.8958411813, + 1.1550073624, 1.0528649092, 0.7435577512, -1.5690900087, -0.4255738258, 0.9140344858, 1.2361495495, -1.2471395731, + 0.762667954, -0.192863971, -1.2733954191, 0.7811949253, -0.4019659162, -0.4094708264, 0.0163625069, 1.4163241386, + 0.2105273604, -0.4444972277, -0.5089505911, 0.4650335014, -0.2184793502, -0.4025595784, 1.0784583092, 1.0624145269, + 0.0769374445, 0.0645173937, 0.8455424905, 0.9994160533, 0.9331492186, -0.7005475163, -0.2368602306, -1.2239063978, + 0.2130108923, -0.5972399712, 1.8470237255, -0.6240378618, 0.58332026, -0.5017367601, -3.0102710724, -1.3837611675, + 0.1786506176, -0.3187453449, -0.5781022906, 0.031528078, -0.4391703606, -0.2296233028, 2.3488371372, 0.3843484819, + -0.5347214937, 0.1268615276, 0.8902928829, 3.8520202637, 0.7244234681, 1.1944116354, -0.6678529978, 1.0415666103, + -0.8658940792, 0.9077596664, -0.3378550708, 0.9775423408, -0.0754776895, 0.6063098907, 0.6713734269, 0.019454537, + -0.3463670015, 2.1391818523, -0.4366911352, 1.7306786776, -0.1830381155, 0.2859286666, -1.40769732, -1.0983570814, + 0.2282403558, -1.1998163462, 0.4056214094, 0.9875051379, -2.2728385925, -1.3111302853, -1.8743584156, -1.2082616091, + -1.5854942799, 0.4378720522, 1.414738059, 0.3267107308, -0.5729110837, 1.2912527323, -0.6939992309, -0.083363913, + -1.6856313944, 1.0955225229, 0.5547582507, -0.9104179144, 0.4392534792, 1.9463402033, -1.1000357866, -0.7706585526, + 1.2468438148, -0.4902793765, 0.5345413089, -0.9500870705, 0.1477532536, 1.250536561, 0.0899634138, 0.3677219152, + 0.8650166392, -0.2937146723, -0.129063502, 0.3401563466, -0.3108875155, -0.7258995771, 1.3177022934, -0.9953907728, + -0.0467900336, 1.0885127783, 0.1454632878, -1.2228176594, -0.7175816894, -0.7583139539, 1.9346177578, -0.7771400809, + -1.0648733377, 0.1046056002, -1.6488226652, -1.0661364794, 2.0642158985, -1.8892747164, 0.1650791317, 1.084615469, + -0.1468636394, -1.1351752281, -1.2594205141, 0.4703114927, -0.3027814627, 0.2559323013, -1.8508899212, -0.9306232929, + 0.9595783949, 0.1062435508, 0.8443471789, 0.2098277062, -0.8347812891, -0.7564993501, 1.0179579258, 1.0825403929, + 1.3440455198, 0.1753898412, 0.4277119637, 0.2193833888, 1.4308446646, 0.924914062, -1.7949538231, 0.0283557717, + 1.7641273737, -0.7250720263, 0.6685691476, 1.1260482073, -0.3413906991, -0.4857299626, -0.0957151726, -0.4632709324, + -0.718337059, -0.0102504687, 1.3925209045, -1.126565814, 0.8746911287, -0.9904094934, -0.4190586209, -0.2849096358, + 0.6538196802, 0.7931527495, -0.3543632627, -0.8418226242, 0.6238386035, -0.7723533511, 1.4631421566, 0.1103246212, + -0.8867618442, 1.6526117325, 1.2548710108, 0.2880513072, -0.4933074713, -0.5117329955, 0.6032633185, -1.3497583866, + -0.5111608505, 0.667542994, 1.833605051, 0.3924017251, 0.5415292382, 1.6077739, -1.6158584356, 0.5651822686, + -2.9483938217, -0.1493530571, 1.1534879208, 0.2299067229, 0.254866749, 0.3125708103, -0.1421936601, 0.0962879658, + 1.4915516376, -1.4980111122, 0.254226774, -0.3468973637, 0.4250290394, 1.9612369537, -1.1135908365, -1.4034284353, + -1.3214765787, 1.4184826612, 2.2413375378, 0.5875048041, 0.0437724106, 0.7939956188, -0.6215597987, -0.5815342665, + -0.0857137591, 1.4495682716, -3.0346090794, -0.59042871, -1.1807073355, -0.8728227615, 0.1840069443, 0.5226079226, + -0.7583761215, 1.5459980965, 1.1350790262, 1.2372657061, 0.2346145958, 0.9069361687, -0.1464601457, 0.8803369403, + 1.6036959887, -0.0359401405, -0.579418242, -0.8478991985, 0.4720226228, -0.0823028833, -1.2614284754, 0.4648005366, + 1.1294105053, 1.5758064985, -1.3074091673, 0.4784797132, -0.0898916945, -0.4759197831, 1.2124656439, -0.2539686859, + 0.096758917, 0.0534103699, 0.2857500017, -1.3306634426, 0.4249919951, -1.1950973272, 1.0747199059, -0.2170769274, + 0.0450050756, 0.1741701663, -0.2596285939, -0.7920688391, -0.4063050151, 0.9191468358, 1.7260661125, 1.4962009192, + -0.2412421852, 0.3035558164, 1.5768409967, 2.0336244106, -1.6690231562, -1.3676552773, -1.2393416166, -0.5456511378, + 0.8899183273, -0.1883179098, 1.1415015459, 0.3300242722, 0.6155939698, 0.7084887028, 1.5292983055, -0.3306114674, + -0.0788572133, -0.4493339062, -0.2701256275, 0.5901252031, 1.5623044968, 0.3643705249, -1.4534931183, 0.5249486566, + -1.2966890335, 1.1808009148, -0.022437986, 0.3152523935, -0.2782708406, 0.8091103435, -0.4187511802, -0.4770900905, + -0.3365066946, 0.5623541474, -2.0182147026, -2.1983170509, 1.1045867205, 1.2624795437, -0.0276180673, 0.1718224883, + 0.1991921812, -0.2634349763, -0.0887101442, -0.8009012341, 0.347078979, -1.4324259758, 1.4175089598, -1.6810934544, + -1.0911394358, 0.5939617157, -1.1652457714, 0.7605130076, -0.6547212005, 0.384557426, 0.7944753766, 0.6379547119, + -1.1523764133, 0.1821886748, -0.5537084341, 1.544867754, 0.8237330317, -0.5419313908, -0.7200653553, 0.693539083, + 1.1008996964, 0.9097881913, -0.9642880559, -0.4383548498, 0.8910411, -0.3298941553, 0.9730165005, 1.2895667553, + 1.1915460825, -0.6843030453, -0.9302793145, -0.2390873879, 0.1579615325, 0.2212390304, -0.6818502545, -1.7127672434, + 1.1771396399, 1.1114701033, -0.3492176831, -0.047280997, 0.7482308745, -0.0730901062, -0.5841656327, 0.4504536092, + -1.102589488, 0.0581932291, 0.6327283978, 0.1792763323, -0.8223001957, -0.228428781, -1.2400608063, 0.4701416492, + -1.1249814034, -0.4419503808, 0.4520464242, 0.4384505749, 0.445894599, -0.4454752505, 0.6874499321, -1.9018042088, + -0.8928960562, 1.0825363398, 0.2178558558, -1.2581878901, -2.8035640717, 1.6928415298, 0.0167334545, -0.7488485575, + -0.6693356633, -1.2117948532, 0.1265929341, 0.52913028, 0.38996768, 0.4554530382, 0.4301682711, 0.4348187447, + 1.0085790157, -1.7501940727, 1.137352109, 1.1931743622, 2.0794131756, -0.2773678005, 0.8379659057, 0.6542209983, + 0.2838761508, 0.5350176692, 1.3807713985, 1.7053838968, 0.8826751113, -0.3271561265, -0.3581827283, -1.2562394142, + -0.8812279105, -1.0632889271, -0.1390643716, -0.741725266, 0.5785334706, -0.584240973, -2.0249407291, 0.0031048066, + 1.6786370277, -0.1028214321, 1.4051040411, -1.2307188511, 0.0745233521, -1.3036009073, -0.4741173089, 0.792325139, + -1.6625601053, 0.5009847879, -0.4260414243, 0.4607705772, -1.4588941336, -0.8828140497, -0.2869668007, -2.0858445168, + -0.6617110372, 0.9500411749, -0.4903324246, -0.1242794171, -0.6876080036, 0.9306303859, -0.230411306, 1.0719676018, + -2.1756176949, 0.5917387009, 1.5272648335, -1.1067727804, 0.3803062737, -2.1274337769, 0.5029523373, -0.2445702404, + -0.0006700782, 0.963563323, -0.226187855, -1.6574515104, 2.6968736649, -1.1250771284, 1.0807653666, 0.0584954619, + -1.4129952192, 0.862064302, 0.8713108301, 1.6652963161, -1.61356318, -0.1984029859, -0.2902413011, -0.6188423038, + 0.7531723976, 0.108723931, -1.6153539419, 0.4767957926, -0.4382492602, -1.0736072063, 1.2319749594, -1.2424856424, + -1.4469009638, 0.5112141371, -0.2780409157, -0.931884408, 0.4025871754, -0.7289595604, 0.4709553123, 0.1000782549, + 1.2074514627, -0.2669787109, -0.3595815599, -2.1342899799, -0.4210056067, 0.4573920667, 0.9248502851, -1.2482802868, + 0.6569746733, 0.417584002, 0.0368951969, -0.060740836, -1.8906854391, -0.0682709813, -0.5059621334, 0.2151026875, + 1.887295723, -1.1071970463, 0.1205267534, -1.0122386217, -0.6658754945, 1.1404993534, -0.5657894015, -0.8201801777, + 0.6875778437, 2.0678489208, -0.6186278462, 1.0876693726, 1.6158015728, -0.1567347497, -1.2611894608, 1.4985532761, + 0.4219383597, -0.1459040344, -0.6523817182, 0.7554470301, 0.2956840992, 1.1193044186, 1.610765934, -1.5123630762, + -0.4555642009, 0.7889720201, 0.8956725001, -1.3317306042, 0.6401042938, 0.2166453004, 0.82151407, 0.0503329076, + -0.0965074822, -0.1113443226, -0.2042803764, -0.6873565316, 0.5317636728, 1.1151205301, 1.5243155956, -1.2777767181, + 1.765458107, 0.0725174472, 1.0041288137, -1.6742922068, -0.1915116161, -0.658370316, 0.0271707252, -0.7335672975, + 0.1892032921, 0.29531914, 0.0094617, -0.157551527, 0.33232072, -1.2621731758, 0.1978865266, 1.3326668739, + -0.634319365, 0.9134386778, 0.0729104951, -0.1353257895, -2.0858786106, 1.0808997154, -0.3004504144, -0.2755873203, + -0.7367097139, 0.3021540642, 0.2700982988, 0.4530409575, -0.7007525563, -0.8959960938, -1.1999323368, 0.493532151, + -0.5960142612, -0.963967979, -1.2851704359, 0.4559888542, -2.5519254208, 1.441354394, -1.0547283888, -0.4198956788, + 0.2472599745, 1.085387826, -0.522380054, 1.9698237181, 0.5240100026, 0.7831386328, 0.4234170914, -0.1564492285, + 0.1359184831, -0.1162117422, -0.4195275009, -1.175904274, 0.355265826, -1.9931274652, -1.4269702435, 0.632896781, + 0.4862891734, 0.0348587781, -0.0004265035, 0.1926831156, 0.8282247782, 2.8950171471, 0.4765744507, -1.097668767, + -0.7158638239, 0.7778658867, -0.2204324454, 0.0522998534, 2.3419752121, -0.2337766886, 1.5526149273, -0.2743647099, + -1.2966957092, -0.5145607591, -0.6441264153, -0.943624258, -0.5575792789, -0.2886804938, -0.5300575495, -0.7995063663, + 0.4609216154, 0.050342299, -0.1202928945, 1.2408776283, -0.5033631325, -0.044819463, 0.2108783871, 0.0507609658, + 1.4534044266, -0.9200549722, 0.0032031226, 0.6261848807, 0.2485037446, -0.7718658447, 0.2863176465, 0.0988020748, + -0.707513392, 2.0979690552, 0.0536587685, -0.4469783306, -0.691696763, -1.4713886976, -0.6406098008, -0.975110054, + -0.725135386, 0.7354019284, -0.025598662, 2.1644103527, 0.187954843, 0.9535272121, 1.1498577595, -0.9122163057, + -0.8776962757, -1.5234766006, -0.9056487083, 0.4926247299, -0.389721334, 0.4013664424, -0.1390452832, 0.077755101, + 0.8162872195, -0.3259987235, 0.1420471519, 0.1295469105, -0.5685203075, -0.0366480462, -0.749322772, -0.0521788187, + 1.35440135, 0.9088275433, 0.9768580198, 0.5170670748, 1.2871779203, -0.1010567024, -0.0856445506, 2.627364397, + -1.6656155586, 0.5624790788, -0.5161991119, -2.1735665798, -0.341704309, 1.9319416285, -0.9397265315, -1.7080259323, + -0.7614494562, -1.2761473656, 0.4220181406, 0.9958624244, 1.0256894827, -0.1235863641, 1.8414309025, 0.0351293795, + -1.0325827599, -0.4244602025, 0.1708007455, 0.5898537636, 0.2644017041, 0.1715549082, -2.2165124416, 1.0189716816, + -0.505545795, -0.5834990144, -1.2355498075, 0.8014555573, 0.3301530182, -0.8047369719, 0.2689402997, -0.8028509617, + 0.8982989192, 1.5976356268, -0.2384607941, 0.5498903394, -0.3153492212, 0.0371826515, -0.2799673378, -0.2572603822, + 0.8187432289, 0.8705870509, 0.7939828634, 1.4407110214, 0.0046773427, -1.0408636332, -0.4254775345, -1.0005455017, + 0.1042390913, 1.2375731468, -0.0690675676, -1.830103755, -0.2057546228, -1.1653020382, -0.9878067374, -0.1361900568, + 1.1316952705, 1.0342150927, -0.6592921615, 0.240857318, 0.2436449975, -1.2514510155, -0.5721936226, -0.0520525165, + -0.4139078557, 1.8763142824, 1.1753531694, 0.522654593, 2.1683094501, 0.6907484531, 2.2160840034, 1.1130344868, + 0.4593990743, 0.7844545245, 0.6997361779, -3.126157999, 1.5720311403, 1.7266691923, 0.3456651866, 0.4389714897, + -1.6385536194, 0.4049912691, 0.2712102234, 0.1878780574, 1.3390874863, -0.0299388077, -1.3081719875, 0.0632864684, + 1.2408345938, -0.9132910371, 0.51475209, 1.1721259356, 0.0147358524, -0.3792796135, 0.8482502699, 0.965495944, + -1.4460035563, 0.4597578347, 0.170464769, -1.1115249395, -0.7208780646, -0.3793327212, 1.2741154432, -1.6364229918, + 1.5149157047, 0.0631237701, -1.2959022522, 0.4598662853, 0.0281794146, -0.7976759076, 0.3872869909, -0.8583239913, + 0.1689493805, 1.5861971378, -0.8286434412, -0.9093782902, 0.0804205164, 0.0313321017, -1.8652266264, -0.3101404309, + 1.6558412313, 0.423032552, -1.1583219767, 0.9033274055, -0.4117244184, -1.060433507, -0.5190912485, -0.5632234216, + 0.1435869932, -1.5192936659, 0.0426138528, 1.49241364, 1.2707833052, 1.986461997, 0.5108605623, 1.2856057882, + 0.8407601118, -2.0035340786, 0.8936482668, -0.3260267377, 0.8181855083, 1.070858717, -1.8654093742, -0.4303693771, + 0.3521697521, 0.1649127901, 0.2585572302, -0.7880253196, 0.269569844, -1.3194481134, -0.6205232739, -0.0030871087, + -1.2652636766, 0.5406863093, 0.4429259598, 0.4298315346, -1.2147737741, -0.1896856129, -0.4850975573, -0.3081047237, + 2.378013134, 1.201597333, 0.2664550841, 0.7288299203, 0.7034993768, 0.0048138006, -0.3591594398, -0.7174685001, + 1.7085003853, -1.3032776117, 1.1584476233, 1.0995483398, 0.5414423347, 0.9730444551, -1.0727057457, -0.5748537183, + -1.3290205002, 0.7744051814, 1.4045319557, -0.2159052491, 1.7948094606, 1.6460920572, 1.3411537409, -0.4496222734, + -0.560951829, -0.0992444083, -0.0853365064, 1.2166137695, -0.0213507153, -1.4752011299, 2.1615161896, 1.2456383705, + 0.2582988143, 0.2717613876, -0.1682876796, -1.4384615421, -1.06072855, -0.1907466799, 1.6710277796, 1.2433642149, + -0.7574949861, -0.0647511855, -2.9306302071, 1.592397809, 0.0510240272, 0.396674931, 1.0205726624, 1.1665779352, + 1.6779688597, -2.35714221, -0.5891851187, 0.3185988665, 1.854160428, -0.0838108212, -0.4632383883, -0.1345472634, + 0.8540049195, 0.7585686445, -1.0865671635, -0.8296186924, 0.4694327712, 0.3256563544, 1.4290058613, 0.7655954361, + 1.2069232464, -0.1459943205, 0.8065757751, -0.3280249536, -0.0742716119, -0.4548668861, -0.0853952095, -1.1056786776, + 0.9523906708, 1.7686954737, -3.2922542095, -1.5821778774, -1.3896070719, -1.2549228668, 0.3908016682, 0.6844573021, + 1.4914137125, -0.4642134607, 1.1045403481, -0.4899351001, -0.9562233686, -0.280792743, 0.0053708674, 1.1767382622, + 0.1583883911, 0.2319228053, -0.8078649044, -0.1561281085, 0.3615372777, 0.4036455154, 0.9082906246, -0.0023141834, + -0.0452877991, -1.5662910938, -0.103378132, 0.5418262482, -0.937784791, 1.0195208788, -1.1293481588, 0.0335480943, + -0.4405394495, -2.2315773964, -0.4775855541, 2.0507366657, -1.3063079119, 1.6552379131, -1.1819411516, -0.0324509963, + -1.4311203957, 0.8767514229, -0.1345372945, 0.8536100984, 1.5587157011, -0.236899808, 0.1880593002, 0.2717109025, + 0.6395956874, -1.2362473011, -0.0319846682, -0.8295824528, -0.205554232, 1.5347025394, 0.7827878594, 1.270387888, + 2.7300498486, -0.2844167948, 1.1753647327, 0.4245087504, -0.5369454026, 1.207328558, 0.0930977017, -0.5196133256, + 1.0421657562, 0.1690351069, -0.4875896275, 0.677097261, 0.0044279699, 0.3105448484, -1.2954131365, 1.3982955217, + 1.7429810762, 3.6478598118, -0.7394582629, -1.1202218533, -0.4658226073, -0.9041526914, 1.1250499487, -0.1801972389, + 0.1294232458, 0.7745076418, 0.5126174688, 1.498057723, -1.0465172529, -0.4988512099, 0.5188845992, 1.1863158941, + -1.1096326113, 0.5208597779, 1.2098367214, 1.0017185211, 0.6673674583, 0.5668189526, -0.0521996841, -0.8716872931, + 0.168119818, -1.2476809025, 1.9259685278, -0.5453615189, -0.8922271729, 1.9886724949, -0.313586086, 0.7334384918, + 0.5198380351, -0.4526397884, -0.9506946802, -0.2661958933, -2.5570335388, -0.0557328612, 1.162582159, -0.4434820712, + 1.1122316122, -0.0545103103, 0.2586460412, -0.6618434787, 1.4436861277, -1.3688731194, 0.7621035576, -0.2985791862, + -1.0211650133, -0.135747239, 1.0373653173, 0.3776987195, -0.4136635363, -1.6953018904, -0.1204522103, -1.1567699909, + -0.7138453722, -0.327661097, -0.6435422897, -0.7366944551, -0.1425680071, 1.7642153502, 2.8425951004, 0.0610087626, + -0.4151884615, -0.1082942411, 0.0857538283, -0.8597403169, -0.9152332544, 0.1713453978, 0.9422041178, -1.008261323, + -0.7561030388, -0.3161784708, -0.1782092303, 0.0957031474, -2.5437932014, -0.6769134402, -1.45527637, -0.1227465048, + 0.4310432673, -0.9728448391, 0.3342837393, 1.1829782724, -0.0065461015, 0.5665283799, 0.16956155, -0.0044607525, + 0.0285913981, -0.8989881277, 1.15939641, -1.4732522964, -1.460070014, 1.7094210386, 0.0207724255, 2.096357584, + -1.27477777, -0.6057670712, -0.8993343115, 0.2116632611, -0.1160674915, -1.2055330276, 0.7836779952, 0.541559577, + 1.04651618, -1.6241914034, -0.805503428, 0.5579012632, 0.8232837319, 1.6447900534, -1.231140852, 0.2137642205, + -0.9106723666, -1.9084692001, -0.2605872154, 0.2076506913, -0.9598652124, -0.9803130627, 1.2351433039, -0.9859101772, + -0.3903642595, -1.0345238447, -0.31240502, 0.7462546229, -0.5244422555, -2.4146971703, -0.1631130129, 0.5022974014, + 0.942902863, -0.8194223046, 0.0069113285, -0.2531582713, 0.292845577, -0.6136545539, -0.3634734154, 0.8031544089, + 0.0733277798, 0.5689120293, 0.9162364006, -1.4241131544, 0.6944862008, 0.1126557738, 0.2768815458, 0.0754733682, + 0.4862255752, 0.3217608333, 0.3620449007, -1.7405321598, 1.1516690254, 0.9695023298, 1.0705699921, 1.113604784, + 0.792557776, -1.7781143188, 0.8929021358, 2.069070816, 0.5849423409, -2.1492705345, 0.5832387209, -1.0383287668, + -0.4568869174, 3.1900093555, -0.7241430283, 1.1837641001, -0.102271542, 1.8591374159, -0.3411387801, 0.3150487542, + 0.0275884047, -1.3723717928, 0.0300342757, 0.4547230303, 1.8566195965, 0.2995341718, 0.6253018379, 0.4939307272, + -0.0265730321, -0.3234100342, 0.3595822155, 0.6894904375, -0.64387393, -0.9093788266, 1.2942886353, 1.2176066637, + -0.9077116847, 0.1113884673, 1.0686095953, 0.1878102571, -0.5059827566, -1.6027270555, 0.0214889795, -1.3829032183, + -1.7231186628, -0.3605511785, 0.5595287085, -0.424793303, -0.3993293941, 0.0908166617, 0.1786594391, 0.753502965, + 0.6296449304, -1.5375419855, -0.2698430121, -0.7669034004, 1.2986503839, -0.5635685921, 0.1221668199, -0.3815145195, + -0.4466152489, -1.1692444086, 1.6965802908, 0.3721182048, 1.7709367275, -1.6176935434, 0.2316016853, -0.8005692959, + 0.7475548983, -0.8234938383, 0.7365947962, 0.7701295614, -0.9460060596, -0.4202794731, 0.3530687392, -1.8267436028, + 0.2953773141, -0.6090833545, -1.0919172764, -1.6189069748, -0.032228902, 0.4412971735, -0.4813476503, -0.6603649259, + -0.8035909534, -0.8457508683, 0.2187346816, -0.9387763739, 0.0936134532, -0.0921785682, 2.2268385887, -0.4825090468, + 1.5371801853, 1.9999849796, -1.396905303, -0.0445936732, -1.4784121513, -1.8323581219, 0.3004155457, -0.3889199495, + -1.3225893974, 1.8505661488, 0.0649111494, 1.6666123867, 1.4079970121, 0.2198562622, 0.4401271045, -1.1840212345, + -1.4271931648, -0.7065832615, -1.2413952351, -1.3692640066, -0.0096538514, -0.6498388648, -0.2452564836, + -0.9085732102, -0.1391163319, -0.8336672187, 0.5473741293, 0.8369570374, -1.1456743479, 0.0624656156, 1.8641681671, + 1.67497015, -0.5735353827, -1.4077433348, -1.9448838234, 0.5631722808, -0.6609920859, 0.2506439686, -1.1130369902, + -1.0673143864, -0.3806003332, 1.4953833818, 0.6200692058, -0.6979174018, -3.6335635185, -0.8773848414, 1.7083442211, + -0.7415100336, -1.0148513317, 1.2024078369, 0.7076079249, -1.291672945, 1.0737441778, 1.0685819387, -0.5960540175, + 1.1803132296, -0.033334557, 0.0980365053, -0.4779715836, -0.8072968125, -0.0824001506, -1.9273227453, 0.717800498, + -1.0592756271, -0.9261478186, 0.1021981537, -0.2795476615, -0.9590332508, 1.0488163233, -0.4690090716, 1.6720734835, + 0.6879519224, -0.0157241132, 0.5268683434, -0.5965974927, 1.6848707199, -0.8259072304, 0.7594338655, 1.2602584362, + -0.6720221639, -0.0584140681, 1.0932010412, -0.5520174503, -0.6187421083, -0.8900236487, -0.8719530106, 1.2347486019, + -1.3540980816, -1.2299486399, 0.6464612484, -0.0974468589, -0.3091480434, 0.5283569694, 1.0791188478, 0.2561168075, + 1.4158717394, 1.7008452415, -1.4289003611, 1.3387390375, 1.1170512438, 0.5130531192, 1.0400758982, -0.6153922081, + -0.1668823063, 0.7639955878, 1.0470120907, -0.6455356479, 0.7287098169, -0.5354412794, 1.253111124, -0.4258435369, + 0.3980273902, -1.651669383, 0.5757321715, 1.1960839033, -0.4860200882, 0.3503985405, -0.0763770789, 0.0167850349, + 0.8753983378, 0.5204891562, 0.8198471665, -1.4274868965, -0.5994745493, 1.2439334393, 0.8900793195, -0.3447135091, + 1.6019076109, 0.4453103244, 0.3134413362, 0.2098031342, 0.8220742941, 2.1609876156, 0.4291853309, 1.9126983881, + -1.136916995, 0.1236273199, -0.0741692111, 0.1741669476, 0.1106243953, 0.4574111104, -0.7266279459, -1.676523447, + 0.8124452233, 0.4615250528, 0.2150113583, 1.4487680197, 0.6443644762, -1.3313271999, 0.6483889818, 0.0551732592, + 0.0946426168, -0.51473248, 1.3383497, -0.6886813045, -1.3321741819, 1.4576708078, 0.3417120576, 0.1916114688, + -0.0513381623, 1.6174348593, 0.7993416786, 0.1274137199, -0.844842732, 1.2690343857, -0.5826838613, 0.0557822697, + -0.7457270026, 0.0534833819, -0.5319348574, 0.5449818373, 0.0617729798, 0.1800281107, -2.3204801083, 1.0729317665, + 0.3631948233, -0.4377925098, 0.1569657326, 0.5283293128, -0.5462140441, 1.2347840071, 0.505415678, 1.6532857418, + -0.6099229455, -0.6667820215, -0.5278279781, -0.4208771884, 0.4319642186, -0.1246592775, -1.0448354483, 0.0785995051, + 2.6429173946, 0.0422035158, 0.2535940409, -0.9304233193, 1.0765348673, 0.3263046741, -0.6096877456, 0.679469347, + 1.5073816776, 0.3643631041, -0.7833818197, -0.8042606115, -1.1636455059, 2.1159131527, 0.6903854609, 0.1691145897, + 1.3395061493, -0.365552038, 1.3998910189, -0.4119296074, 0.156557709, -0.9600688219, 0.1500866711, -0.4632772505, + -2.962240696, -1.1724597216, 0.6507877707, -0.5097853541, 0.365983218, 0.4810813665, -0.0095656291, 0.4939456284, + 0.1545771658, 2.0188348293, -0.3500584066, 1.2580102682, -0.3938673437, 1.1757705212, 0.5819926858, -0.1100534201, + -0.4838815629, -1.1713180542, 1.0384311676, -0.4346498549, -0.6087762117, -0.5977138281, 1.2044967413, 0.5018853545, + 0.3364687562, -0.2894819081, 1.2561717033, -0.1431188136, -0.0513663627, 0.1945189983, -0.1383751035, -1.2002265453, + -1.5160598755, -0.3494048119, -1.1222406626, -0.156464234, 0.1808167845, -0.3393794, 0.590700984, -0.9833743572, + 0.9756684303, -1.3281390667, 0.2585115135, -0.3627780676, 0.8321187496, -1.8786463737, 0.4968658686, 0.0689388067, + -0.007911047, 0.3008804023, -0.7525809407, -0.3469925225, -1.5925863981, -0.7068521976, -1.3115445375, -0.2572110593, + 0.1371918172, -0.6321007609, -0.4874186814, -0.0709755793, 0.0640492663, 0.3276489973, 0.39328143, -0.2793305516, + 0.4494642913, 1.782168746, -0.9390084147, 1.541377902, 0.0079562068, 0.1199712157, 0.1818806082, -1.7790522575, + 0.0833725855, 0.3141438663, 0.2376887649, 0.3440466821, 0.7322938442, -0.642346561, -0.9430661798, -1.0507161617, + -1.1356643438, -0.9131414294, -0.1980059296, -1.0524215698, 2.0543701649, -0.5051992536, -0.2961077988, -0.1411919743, + 0.2223303318, -0.5895858407, -0.5231840014, 0.6206701398, 0.8080673814, -1.3365075588, 0.3356038332, -1.611944437, + 0.8270612359, -2.3478622437, -0.1573795974, -0.8355489969, -0.1855920851, 0.2819520831, 0.162715748, -0.495790273, + -0.2017339319, 0.0587787591, -0.8486970067, -2.2888104916, -0.9550905228, 0.0425533839, -0.8235985041, 0.2843135595, + 1.348331213, 1.6403613091, -0.1185661405, 0.2167840004, -0.4161785841, -1.7830762863, -0.5561192036, -0.0708618909, + -1.0473921299, 1.0332918167, 0.1671882719, 1.5324164629, -0.6358706355, -0.2964316905, -1.5015150309, -2.2901973724, + -0.2640973926, -1.3396550417, 0.7526706457, -1.1424431801, 0.2186951339, -0.4216327071, -0.4880354106, 0.5038363338, + 1.6515885592, -1.1511272192, -0.6911903024, -0.8230931759, -0.2474271357, -0.3428781927, 2.3004641533, -1.2634423971, + 1.2604916096, -0.4096618295, -0.2799764574, 0.79180336, -0.6636201143, -0.0015233173, 1.6005517244, 1.3663774729, + -1.7475005388, 1.0692484379, 0.2425226271, 0.491150409, 0.6091113687, 1.120041728, 0.6362381577, 0.1359951049, + 0.1392289251, -1.5782338381, 0.9691632986, -2.3665611744, 1.0742968321, 0.5516464114, -0.5444959402, 0.8318801522, + -0.750164628, 1.2486605644, 0.3589930236, -0.3600519598, -0.7901878357, 1.5135924816, -0.2313470095, -0.7407914996, + 0.8029611111, 0.2708649933, -1.6062647104, 0.5937306881, -0.315484941, 0.1361830235, -1.0001647472, -0.0763395801, + 0.0344249457, 0.3669148684, 0.5293010473, 0.0763758123, -0.2572541237, 0.5138447285, -0.1288889498, 0.643945992, + 0.57945925, -0.7824993134, 2.2121942043, -0.3496154547, 0.4119117856, -0.842056036, 0.4544038773, 0.0109467581, + 0.0010534312, -0.295067668, 0.1750898808, -1.2973902225, -0.0623139627, 0.2126978934, 0.6877377033, 0.3352945447, + 1.7457261086, -1.0843807459, 0.7854700685, 0.060095489, -0.0855508447, 0.7329173684, 0.2756085098, -1.0048882961, + -0.7781894207, 0.8054320216, 0.0727083459, 2.3196663857, 0.300604403, -0.2822029293, 0.4725848138, -1.5897241831, + 0.0941874236, -0.9508988261, 1.4989129305, -0.306881398, 0.2385282964, 0.4217751622, 0.7946755886, 0.7492550611, + 0.5127679706, -2.2465128899, -0.1663811803, 0.5605801344, -1.8675581217, 0.4418747425, -1.0016011, 0.7059368491, + -0.0510153249, -0.2325836271, 1.5391352177, 0.9156982899, -0.870234549, -0.5608828664, 0.8970757127, 0.3895307481, + 0.6618192792, 1.2001011372, -0.1240015626, 0.4234113991, -0.794921875, -1.7483150959, 0.1998164356, -1.510635972, + -1.1773667336, -0.6218593717, 0.3076383173, 0.5031841993, 1.5083596706, -0.7131744623, 0.2623642981, -0.0309111103, + -0.1339277327, -0.1106061265, -0.1045916006, 1.086977005, 1.6638536453, 0.6696953177, -0.2361247987, 0.9860504866, + 0.4088005424, -1.0221886635, 0.0886315182, -0.4157384634, 0.1207668409, 0.4294110239, 0.1377238184, 1.2307782173, + -0.1232055947, -0.8324245811, -0.3747373223, 2.4342443943, -1.1951713562, -1.1546982527, -0.9615500569, 1.2484122515, + -0.3975964487, 0.8206714392, -0.8452029824, -0.2450099438, -1.6266416311, 1.147261858, 1.0578019619, 0.1282176673, + 1.1876020432, 2.5764918327, -0.082369253, 1.1622513533, 1.2577518225, 0.7237423658, 0.4700427651, -0.7886118889, + -0.4397766888, -0.8123567104, 3.0631451607, 0.5537109971, -0.0900671929, -2.6399536133, -0.1701684147, -0.6035872102, + -0.6521043777, 1.1507827044, 1.2750959396, 0.2453898042, 0.38722983, -0.8278653026, 0.9271902442, 1.6431338787, + -0.4256422222, 0.5522973537, 0.1817890704, 0.4363834858, 1.0876022577, -0.4799385071, 0.9566588998, 1.3544300795, + -0.1174629778, -1.2165155411, 0.8368718028, -0.8922112584, -1.5480458736, 0.0400244184, 0.3244729638, 0.0817489848, + -0.9257849455, -0.7675449848, -0.7365167141, 1.6259465218, 0.62986058, -1.4840712547, -1.4950245619, 0.1297564805, + -1.0976947546, -1.1410716772, -0.928509295, 1.0353862047, 2.7001140118, 0.9804233909, -0.3006408811, 0.1535374373, + 1.3037381172, -2.0147192478, -0.1158716157, -0.6375645399, -0.1695705652, 0.6505923867, 0.6162424684, -0.8195439577, + 1.2143636942, 1.0763442516, -1.8476772308, 0.3398576081, -0.2474824041, -0.904543519, -1.1834901571, 1.6120089293, + 0.401511848, 0.3753013313, -1.0195120573, 0.3743047416, 1.5763468742, 0.2818703055, -0.0415413007, 1.1435390711, + 1.0312833786, 0.5930593014, 0.4299762845, -0.7077791095, -2.0817489624, -0.857321322, 0.8970362544, -1.1242753267, + 2.1089203358, -0.1735206395, 0.7554202676, -0.649245441, -1.1986908913, 0.3451207876, 1.0742040873, 0.2218725234, + 1.5225878954, 0.1871998757, 1.1086134911, 0.1162764803, -0.2187245935, 0.341475606, 0.1085516512, -0.7073196769, + 1.2486360073, -0.9194564819, -0.8338657618, -1.0484052896, -0.16230762, -1.9373788834, 0.5603187084, 0.542742908, + 1.506090045, 0.0874666423, -2.4002182484, 1.3652335405, 0.5865104795, -0.3230989277, -1.392999649, 1.1904447079, + 0.3914655149, -0.6465815902, 2.4218268394, -0.6179955602, 0.0971411094, 0.0927094892, 1.1953548193, 0.6744587421, + -0.6237062216, -1.4494575262, 0.5976842046, -0.3370549381, 0.0000538884, -0.97510463, -1.4531168938, -1.2553899288, + -0.5801687837, -0.0705595762, -0.6704121232, 1.3072650433, 1.5074343681, -0.162419036, -1.0658824444, -0.6713882089, + -1.2154396772, -1.0532267094, 1.3715112209, -1.1906760931, 0.8829891682, 0.1461430639, 0.30256778, -1.0018360615, + 0.759761095, 0.4627263546, -0.9727967381, -1.833081007, 0.6842470765, -0.0457889512, 0.0743883923, 0.116020754, + 0.4871888459, -1.3810641766, 0.7513743639, -1.653532505, 0.2805307209, -0.6730520725, -0.6538075805, -1.0937461853, + 0.8920948505, -0.5652847886, -0.2217692137, -0.9390385151, -0.2413975745, -0.0277992953, 0.4737479687, -0.089634344, + 0.4736139476, 1.7478946447, -1.3817198277, -0.5763424635, -0.7620200515, -1.222391367, 0.0114631774, -1.4424446821, + 0.1032015532, -0.4778788388, 0.639183104, -0.334621042, 0.7208385468, 0.6453597546, -0.6174742579, 1.3672366142, + 0.4193812609, 0.2484990656, -1.2752428055, -0.4317915738, 1.3278837204, 0.43123281, -1.575807929, -0.8080574274, + -0.0961645246, 0.2024365366, -0.22574462, -1.4323306084, -1.1698937416, -0.1322149932, -0.2605111599, 0.1435681283, + -0.3786023855, 0.9958216548, -0.0179624446, 0.3827536106, -0.9316131473, -0.9425467849, -0.8002999425, 0.944698751, + -1.1967359781, 0.5227084756, 0.3323342502, 0.146741569, 0.3252617717, -0.2421308011, -0.3801048696, 1.5932736397, + 0.8452807665, -0.3431094885, 1.2928600311, 0.0758657232, -0.8354057074, 0.6789767146, -0.0734707043, 0.4803312421, + 1.3606332541, 0.8671076894, 0.9994120598, -1.1754306555, 1.4058384895, -0.9871997833, 1.0385127068, -0.4434279203, + 0.8501870036, -0.6956353188, -0.6379371881, 0.8698224425, 1.4933327436, -0.9885481, -0.6133674383, -2.2802202702, + 0.9688157439, -0.2850471735, 0.0442743227, -0.3362223208, 1.1406686306, 0.5380051732, 0.6882110834, 1.2516015768, + -1.3449673653, 1.078242898, 1.6350847483, 2.2968215942, -0.7110384703, 1.6386603117, -0.9126443267, -0.3877492547, + -0.1043018326, -0.0090003163, 0.6059634686, -1.0972509384, 1.7331362963, 1.3298485279, -0.6946768165, 0.8652173877, + -0.8342711329, 0.3025682271, -0.8910675645, 0.624876976, -1.6545723677, -0.9224897623, 1.7043474913, -2.16061759, + -0.7243913412, -2.4045393467, 1.6853871346, 0.8936536908, 1.0344368219, 0.1707872897, -2.0846495628, 1.315420866, + 0.2850298584, -0.3303071558, 0.9252412319, -0.5945811272, 0.2951497138, -0.4839909971, -0.2808298469, -1.2129616737, + -0.2385444343, -0.9515303373, 1.8470141888, 0.4530581832, -1.33551085, -0.1361455619, 0.8572332859, 1.6664037704, + -1.7786149979, 1.1624349356, 0.4030810893, 1.3191045523, 1.9514727592, 0.1954828501, -1.1131478548, 1.876091361, + -0.4106545448, 0.9871078134, -0.3514513075, -1.1491596699, -1.0029109716, -0.4375024438, -1.7376359701, -0.1112331674, + 0.3778693378, -1.2642121315, -0.9193267226, -0.4944682419, -0.7798122764, -0.4271022081, 1.0683219433, 0.1328333765, + 0.74677068, 1.3215091228, -1.1968958378, -1.144366622, 0.6172171831, -0.0051761493, -0.2794991434, 0.3744995892, + -0.3662587702, 0.4500087798, 1.5653235912, -0.2852126658, -2.0067307949, 1.353405714, 1.2254853249, -0.3875033557, + -0.4426376224, -0.959294796, 0.6190398335, -0.3124010861, -0.5994002223, 1.5445845127, -0.0053672073, 0.9292419553, + -1.4328645468, -0.9411212206, -2.3532216549, 0.0921249315, -0.3608577251, 1.1292972565, 0.7657831311, 2.4220712185, + 0.1606874019, -1.4992787838, 0.2326702625, 1.0695062876, 1.6562827826, -2.1346623898, 0.8291113377, 1.9936954975, + -0.0670990944, 0.4760950208, 0.6264278293, 0.3247528374, 0.6127083302, 1.3447989225, 2.1764240265, -1.0073144436, + -1.2598137856, -0.3319583833, -0.9408110976, 2.1974444389, 1.1426124573, -1.1883490086, -0.6941516399, -0.8429222703, + -0.4689262211, 0.1896196008, 2.4364590645, 1.4495763779, 0.9550628066, -1.374941349, 1.0702964067, -0.7423433065, + -1.6166442633, 0.3353677094, 0.8143854737, -2.1510691643, -1.4398878813, 0.4295713007, -0.6825832129, 1.4495866299, + 0.0767971873, 0.8710640669, -0.9394101501, 1.2120714188, -0.1885681599, -0.6676308513, 0.5666903853, -0.5110077858, + 0.8325109482, -0.9449007511, 0.3893716335, 0.0370208956, 0.3440933228, 0.0902620628, 0.1622183025, 1.9678138494, + 1.0434346199, -1.4853209257, -2.2796955109, -1.0654275417, -0.7173523307, -0.8523059487, 1.6222326756, -0.6020047069, + -0.1935931742, -1.0439174175, -0.8322221637, -1.7539211512, 0.6675662994, 1.5207853317, -0.7924110889, 0.3303536475, + -1.4821587801, -0.2574607432, -0.7888179421, -0.2782670259, 1.1471936703, -1.1040791273, -1.162914753, 1.2700695992, + -0.4843160808, -0.5253778696, 0.8253301978, 1.6041414738, 0.3806031942, 0.7163059115, 1.0897123814, -0.9337714911, + -2.2876377106, -1.0739610195, -0.3832927644, -0.1494626701, 2.3470876217, -0.1703584939, 0.3322209418, -0.865051806, + 0.5197970271, -0.820941329, -0.6846882701, 0.6192402244, 2.3423302174, 1.3338751793, 0.137381807, 0.7219576836, + 0.972622633, -0.1536917388, 0.9913292527, 0.2540746629, 0.1626318097, -0.3465512991, 0.4595924914, 1.2181417942, + -1.0088903904, 1.2518771887, -0.1303908825, -0.9561480284, 1.8820406199, 1.20695889, 0.3529352248, -0.8306714892, + -1.4193843603, 0.1155640781, -0.5738064051, 0.6434262991, 0.4984490573, -0.1118573099, 0.7238074541, -0.5256049037, + 0.6390516162, -1.1183315516, -0.0976157486, -0.1260827035, -0.5548433065, 1.766212225, -0.2686588168, 1.0087834597, + -1.4268404245, 1.1659404039, -0.9612586498, -0.334002465, 1.5359613895, 0.123542957, 2.9805519581, 1.0028824806, + -1.0232834816, -1.4397224188, 1.3039492369, -0.7188103199, 0.5913882256, -0.9829553962, 0.2619152367, 0.0651016235, + 0.142249465, 0.0322833695, 0.7933985591, 0.3038003445, 0.6963039041, -0.451025337, -0.0787391812, 1.2138137817, + 2.1563596725, 1.1974829435, -1.3827234507, -0.5387663841, 0.3749031723, 0.3817621768, 0.5126075745, 0.7817907333, + 2.8445768356, -0.7148271799, 0.1042771265, 0.0861898214, -0.2078901976, 0.1141170561, -0.3227742314, 0.0504558496, + -0.5519875884, -0.2047938854, -1.8481737375, 1.2803936005, 1.1041901112, -0.1439001858, -0.2400241643, -1.0030885935, + 1.1916694641, 1.3330214024, 0.0078061824, 0.0833170936, -1.3876982927, -1.3872941732, 0.8939967155, 0.2273259908, + 1.3578511477, -0.1441743076, -0.7695208192, -2.5133471489, 0.1119075045, -0.4572762549, 1.0314948559, 0.9591494799, + 0.3220496476, 0.1193715185, -0.0206195451, 0.6939818263, 0.0383000039, 1.0197111368, -1.3477758169, -1.8404810429, + 0.8510962725, 0.8117278218, 0.0951100439, 0.661123395, -0.7656561732, -0.992279768, -0.917963922, -0.3361779451, + -0.5715629458, 0.5896957517, 0.1407307684, 0.7236926556, 0.7947764397, 0.4836243689, -1.3869879246, -0.1118176356, + 0.299215287, -0.4100322425, -0.7881225944, -1.8818029165, 0.9634225965, -0.0309839323, 0.8337911963, -1.9074735641, + 0.7431362867, 0.4745285511, -1.1356483698, 1.0912343264, 1.2545942068, -1.4796434641, -0.4746834636, 0.3405517042, + 1.1815891266, -0.8854237795, 0.0957699418, -0.2880924642, -0.0463199876, -1.3265682459, -0.1858589202, 1.2988238335, + 0.6762433648, -0.5991950631, 0.3327338696, -0.5831449628, 1.4332697392, 1.9494212866, -0.7886651754, 0.5240651965, + 0.1793854237, 0.6290607452, 0.4811582565, -1.4723852873, -0.0745147914, 0.5363513231, -0.8404342532, -0.484677285, + -0.9714007378, -0.214109987, -0.2834431529, 0.1940501779, -0.5316337943, 0.9639087915, 1.6239774227, -1.3215353489, + 0.9414067268, 0.7094277143, 0.800362289, -0.8477427363, 0.916526258, 1.6716412306, 1.2298988104, 1.4809641838, + -0.4254212081, -0.4077859819, 0.3305155039, 1.0415029526, -1.1496744156, 0.1712993681, 1.4701676369, 0.4293683171, + 0.1795604676, 0.0516814254, 0.2441919297, -0.3086892366, 1.1564617157, -1.2884559631, -0.7572581172, 0.6286239624, + 0.5937031507, -1.189909935, 0.3375867009, -0.4291598201, 0.5017452836, -0.8552255034, -0.8198128343, 1.4330694675, + -0.2992851734, -0.49246189, -0.1553115398, -1.0980613232, -0.1505965292, -1.7112737894, 0.5384337306, 0.9439564347, + -0.435762614, 0.5460928082, -0.8451873064, -1.3298441172, -0.5760731101, 0.2821652591, 0.7656444311, -0.0708712041, + -0.7376880646, 0.7219296694, -0.7072268724, -0.2859232426, 0.6533915401, -0.8342830539, 1.1105629206, 1.6008365154, + -0.644862473, 2.8344218731, 0.6748697162, -0.3423575163, -1.4236814976, -1.195089817, -0.5678108931, 0.7195250988, + 0.5357619524, 0.4457416534, -0.4799274206, -0.1652086526, 0.1340560615, 0.6014035344, -1.3409739733, -0.5987482071, + 0.076954864, -0.358191222, 1.1240202188, -0.2238033116, -1.4019105434, 1.6488307714, -0.2175414711, 1.9418623447, + -2.5849790573, -2.4083001614, 0.3356060684, -2.0707116127, 0.9840598702, -1.2379816771, 1.0672813654, 0.2889554203, + -0.0074083852, 0.4752945006, 0.1841205209, 1.2986530066, -0.059170913, 0.1742814332, -0.0644250885, -1.1764115095, + -1.7949217558, 0.7206540704, 0.4559027553, 0.3954004347, -0.7530158162, -1.8091009855, -0.3017390668, 0.2449345738, + 0.745734632, -1.5417525768, 0.8053346276, -0.5716369748, 1.6070737839, -1.2270644903, 1.9155560732, 1.004330039, + 1.8278682232, -0.6639636159, 0.6661688089, 0.4428050816, 0.0892480984, 0.2309782803, 0.8315519094, 0.1459945887, + 2.3326561451, 0.5832629204, -0.2406825274, 1.9596458673, -0.6441795826, -0.8311957121, -0.9647058249, -1.5046192408, + 0.5703581572, -0.5187826157, 1.4320012331, 0.2922801673, -1.2171894312, -0.6377372742, 1.4113386869, 0.5109692216, + -1.4242004156, -2.1111421585, -1.6401022673, 0.3583278954, -0.0144035704, 0.8650972247, -0.0165269319, 0.9271504879, + 1.5814197063, -1.2962620258, 1.4669339657, -1.8920297623, -0.5688353777, 0.1828519851, 2.2016677856, -0.1028954163, + -0.9203289151, -0.1486750543, 0.381672591, 0.4249047637, -0.5387316942, -1.5233194828, -0.8753087521, -0.234172985, + -0.2465784848, 0.0562043898, 0.1882509887, -1.014081955, -0.2454162836, 0.8557434082, -1.3931586742, -0.4529600143, + -1.4558101892, 1.3878477812, 2.2907056808, -0.0797444135, -0.4271253645, -0.2662831247, 0.5487980843, -1.0244842768, + -0.8371625543, 0.8822185993, -0.959805429, -0.0063711633, 0.8817792535, -0.8519062996, 0.0839718059, 0.6059336662, + -0.8637058735, 0.5584779978, -0.0299070161, -1.4362994432, -2.0078036785, -0.2094628215, -2.6569430828, -1.1245808601, + -1.3522570133, -1.3392878771, 0.2719299793, -1.0510017872, -0.5297577977, 0.029357085, 0.3279094696, 0.9607840776, + -0.0345142111, -0.0836286321, -0.421009779, -0.3227880597, -0.4815520048, 0.4784446359, 0.8643121123, -0.4473959506, + 1.6125975847, -0.3212073445, 0.2659475207, 1.1676646471, 0.5559692383, 0.777970016, 0.6278859973, -0.2657962441, + -1.6537842751, 0.5440248251, -0.3830282688, 0.7568864226, -1.995346427, 0.2166253179, -0.1360926181, 0.3883821666, + 1.4031965733, 0.1071888581, -1.0993431807, -1.4928320646, -0.0251265056, 0.4121911228, -0.7856203318, -0.3717033565, + -1.3687229156, 1.2271392345, -1.2881999016, -0.6959694624, -0.887499392, 1.455811739, 0.3226454854, -1.3846375942, + -1.086062789, 1.0846112967, 0.4653168321, 2.5614218712, 2.7988910675, 0.9378732443, 0.0436836891, -0.2922166884, + 1.7467682362, -0.9949976802, -1.1876443624, 1.5535912514, -1.5948337317, 1.3830382824, -1.7654812336, 1.8867820501, + -0.0235525575, 1.3374916315, 2.3650345802, 0.6751262546, -0.6060769558, 0.0485105924, -0.1316827983, 0.0151644247, + 0.4798516929, -0.747351706, -0.9493153691, -0.5720299482, -0.1864403486, -0.9693927169, -0.0035792037, -1.6661548615, + 1.3482993841, 2.027743578, 0.3658308387, -0.8208331466, 0.4718213677, 0.6236744523, 0.4980045259, -1.3271654844, + 1.396787405, -0.1287742406, -1.1586636305, -0.2044127733, 0.2533079088, 1.2015191317, 0.1085055918, -1.5884567499, + 1.0797991753, -0.5118536949, 1.7802431583, -0.3157459795, -0.2945337296, 1.5226759911, 0.0407008827, 0.9528471231, + 0.7287182212, -0.7189680934, -0.0266107712, -2.0186710358, 1.220303297, 1.1047537327, -0.8241505027, 0.8184968233, + -1.7929810286, 0.9446066618, 0.0339597128, -0.3622136414, 0.4354104698, -0.4571644366, 1.4052172899, -0.2578752041, + -0.1565036923, 1.5309950113, 1.0972181559, -0.2565720379, -0.434812367, 0.0947441384, 0.9954605699, -0.5722588301, + 0.3652120829, 0.572879374, 0.1401024908, -0.1164690852, -2.001922369, 0.2620675564, 0.8731961846, -0.0032438957, + 1.2527974844, -1.0324943066, 0.9453257918, -0.8272736669, 1.6740643978, -0.9105581641, -0.3780149817, -0.0894450843, + 2.1181685925, -0.4071816206, 0.7425952554, -0.7459664345, 2.4063830376, -0.4379978478, 0.9473155141, 1.5492707491, + -0.0160185508, 2.9175112247, -0.3762186766, -0.8467391729, -0.0670067072, 0.0901584849, -0.4757851958, 0.095622234, + -0.3810622394, -0.9159494042, -1.2364341021, -1.1209826469, 0.8402428627, 1.3614509106, -0.6751222014, -0.3164610267, + 0.5810042024, -1.000438571, 0.6155641079, 0.8530336022, -0.659414947, -0.4928688407, 0.7073107362, -0.453320682, + -2.0503511429, 0.7237859964, -2.3081104755, 0.7931211591, -2.2254080772, -0.5442180037, 1.7981696129, -0.4281713963, + 0.3618839681, -0.5407407284, -0.2953153551, -0.209908396, 1.0288715363, 0.8415134549, 0.2290135175, -0.4205887914, + 0.0023723538, 1.2285922766, 1.1784408092, -1.0734616518, 2.3597648144, 1.1720961332, -0.6565869451, 0.7126896977, + 0.1096705943, -0.026885597, -1.7138684988, 0.710698843, -1.0446763039, -1.2062015533, -0.340744704, 1.346637249, + 0.6082682014, 1.3727915287, -0.057184156, 1.0773525238, 0.2110953927, -1.5239913464, 0.6126305461, 0.6644054651, + -0.9984656572, 1.3315540552, -0.3504710495, -0.118561931, 1.3879070282, -0.9998387098, 0.5702096224, 2.1872117519, + 0.735661149, -0.3437471986, -0.6454073191, 0.6962169409, -0.4820179045, -2.4766716957, 0.9680387378, -1.1541639566, + -2.059789896, 0.1503677368, -0.7456140518, 1.4302666187, 0.8453559279, -0.9875950813, 1.8884847164, 0.7621361613, + 0.6842812896, -2.55351758, 0.1136048585, -1.435904026, -0.9684360027, -0.2280776203, -1.2567373514, 0.4444446266, + 0.6932767034, 0.5163866282, 1.1237536669, -1.4660167694, 1.9476058483, 2.8177776337, -0.6734972596, 0.5416264534, + -1.4821751118, 1.6413025856, -0.6007871032, -1.6072694063, 0.3414277434, -1.166780591, -0.3343241811, -1.9332513809, + -0.1265669763, -0.186268121, 0.1386926919, -0.4867524207, 0.4340206087, 0.0739651024, 0.9674845934, 0.8658832312, + 1.0888012648, -1.3989909887, -0.0956165418, -1.4477106333, 0.662964046, -0.2317875922, -1.2718285322, -0.9693523049, + 0.5948191881, 2.1844816208, 0.5021012425, 0.0804309994, 1.8132755756, -1.8225727081, -0.848118782, 0.2896516323, + 0.6112565994, 1.3894894123, 0.8772185445, 0.5663446784, 0.7064805627, 0.5084221363, 0.0819462836, -0.497012347, + -0.6747379303, 1.2025511265, 1.6175380945, -0.884711802, -0.4290374517, 1.5003818274, 0.4689340889, 1.6352735758, + -1.122789979, 0.845346868, -0.2696839273, 0.7648316622, 1.3724489212, -0.1384429038, -1.1072838306, -2.4854152203, + 0.1164309531, -0.0418152809, -0.8732971549, -0.314267993, 0.7281127572, -2.0499973297, -1.535490036, -1.2159559727, + 1.0636960268, 0.0742390528, -0.408683449, 0.634457767, -0.059196692, -2.1613221169, -0.1440149993, 0.3146380484, + -1.0171301365, -1.6388372183, -0.9077087045, -0.2367976457, -1.8067845106, 0.7331464887, -1.2680211067, -0.5259135365, + -0.2642040253, 0.4714785516, 0.4978014529, -0.4443696141, 0.4366762042, 0.96599406, 1.0915999413, -1.3117097616, + -0.4258576334, 0.2191979438, 0.5577743649, -0.3677088618, -0.2587479949, -0.2951894403, -0.128519401, -1.741038084, + 0.2037728727, -0.0169256441, -1.9258970022, 1.1891771555, -0.1056173444, -0.2551109493, 0.0803601369, 0.3078361452, + 1.4552494287, -1.7418527603, -0.1786758006, 1.3843970299, -1.8449815512, 0.2047158927, 0.7096581459, -0.232886225, + -0.3915565908, -0.6430918574, 1.163515687, 0.7798740864, 0.3655540943, 0.2442674339, 0.9248095155, 1.3240067959, + -0.3801167905, -1.3439861536, -0.6244315505, 2.141053915, 1.2676112652, -1.6609078646, -0.8470503092, 1.0326119661, + 1.1942317486, -1.9800231457, -0.7131582499, -0.3807858229, -0.8833439946, -1.1810083389, -1.3195772171, -0.0540605076, + -0.0507104397, -0.0006503842, 0.284358263, -0.1849077493, -0.9837927222, -0.4980651736, 0.506847918, -0.0115457019, + -0.1425283551, -0.1853843629, -1.3138334751, 0.678986311, -0.1799073815, 0.1523042619, 0.8186873794, -2.3586330414, + -1.1386350393, -1.8707106113, -1.399725318, -1.6075724363, -1.7040657997, 0.5580219626, 0.8402561545, -0.4480331242, + -0.8665820956, 1.6506772041, -0.8412654996, -0.8535141945, 1.0686321259, -1.8647556305, 1.6807284355, -1.4227255583, + 0.7940302491, 1.1190499067, 0.1854119748, 1.0127215385, 0.4834828973, -0.0771656111, -0.3799327314, -0.032143116, + 0.42833215, -0.2940807045, 0.4353268147, 1.0631655455, 0.1714275032, 0.8127216101, -0.4509384334, -0.177013427, + -0.6772844195, 0.1549729407, -0.0158453472, -1.1719727516, 1.0151515007, 0.5892142057, 0.7689551711, 1.2890911102, + -2.1213917732, 0.7964041829, -0.7404226065, -1.7036547661, -0.2855556011, 0.8033329248, -0.1386539191, 0.5521915555, + -1.6757645607, 1.1778060198, 1.4586355686, 1.4529005289, -0.1698000878, -0.6933089495, -0.2682672143, -1.6710566282, + -0.0512348413, 0.6260530353, 0.7085033655, 0.727220118, 0.3297210336, 0.3958292603, 0.2138654739, -1.0701493025, + 0.9027658701, 0.666413784, -0.4717260897, -1.6510242224, -1.2329187393, 0.328897953, -0.5451109409, 0.5936804414, + 1.3355246782, 0.130157277, -0.2022518814, -0.8950264454, 1.2793928385, 1.5864177942, 0.4107882977, -0.0241710469, + 0.5844276547, 0.5538517237, -1.6992001534, 0.6862621903, 2.2658751011, 0.8761395216, 0.3837254047, -0.2647534311, + 0.4720512033, 0.1841666549, 0.2001533508, 0.0668039396, -0.1149130762, -0.4432745576, 1.1688767672, 0.3746031225, + 1.0524545908, -1.1692347527, -1.2809635401, 1.3166548014, -0.6610518098, 1.437692523, -1.0611702204, -0.5353015661, + 0.1217178032, 0.6271507144, 0.7130964398, 0.5698034167, -0.0544330068, -0.0827762783, 0.4918554723, -0.5561770797, + 0.9431702495, -1.2986550331, -0.9600256085, -0.1253585219, 0.6193585992, 0.2552787066, 1.2878757715, -0.5704673529, + -0.3831481934, 1.0959254503, 2.0086066723, -2.1474649906, -0.1529575735, 0.8048326969, -0.4581208527, -0.0162758399, + -0.2110669166, 0.1082363203, 0.6949726939, -0.5438286662, -1.1747916937, 1.6570202112, 0.5229940414, -1.2811999321, + -1.8111737967, 0.4468028843, 2.0589504242, 0.7505765557, 1.5820052624, -0.9668190479, -0.3587667346, 0.3426084518, + -0.4487540424, -0.5114123821, 1.757440567, -0.4817022383, 0.6514472961, -0.7424803972, -0.5344078541, -0.1580218077, + 0.3720195889, 0.5527791381, 0.4424994588, -0.1315764487, -0.4980100691, -0.5082452297, -0.1763692796, -0.4118542671, + -0.7443788052, 1.9393750429, 0.802916944, 1.1061604023, -0.0243216679, -1.8400745392, 0.6343280077, 0.2006740719, + 0.5488215685, 0.2727405727, 1.0560905933, -0.6984013319, 0.3588303328, -0.1235076785, 0.0187691264, 0.5021178126, + 1.6440634727, -1.8855284452, 0.6837254167, -0.3057632446, 1.5436513424, -1.0427814722, -0.512901783, 0.6372142434, + -1.2669779062, -0.0673971698, 0.4885091484, -1.0358808041, -0.4340546429, -0.3351761401, -1.059466958, 0.4214607775, + -0.235963434, 0.1719900966, -1.6630712748, -0.7779294848, 0.7398859859, 0.9763131142, 0.9751464725, 0.3020714223, + 0.7720235586, 0.8978174329, -1.376331687, -1.1374385357, 0.4448396564, 0.0724404156, -0.7544128299, 1.1938458681, + -1.3248474598, 0.0271121897, 0.354592979, 0.1016891822, 0.8709347248, 1.2646727562, -1.1754066944, 0.7666998506, + -1.011903882, -0.3860526681, -0.8156091571, -1.6459562778, -0.5340557098, 0.7559775114, 0.2526681721, 0.3399650455, + -1.1079380512, -2.3619008064, 0.1570393592, 1.3197020292, 1.2027004957, -0.4237133265, 0.7454201579, 0.6623315215, + 0.1792276502, -1.3496153355, 0.3558274209, -0.6212102175, -0.8429967761, 0.0761769116, -0.9115606546, -0.1469836384, + -1.2940363884, -0.3781982064, -0.3462474942, -0.8051198125, 0.9975365996, -0.4378167391, -0.365218848, -0.4983713627, + -0.3541530967, 0.4649488926, 0.4458468854, 0.121297054, -1.2046818733, 1.124560833, -1.0488841534, 1.5659842491, + 0.3328139484, 0.423891902, -0.0850975588, -0.220940426, 0.253287226, -0.3511019945, -0.0293736942, -1.6951823235, + 0.3349150717, -1.3477668762, -1.0378328562, -0.074883163, -0.6586401463, -1.7394788265, 0.2208534479, 0.3594329655, + 0.4248667955, -1.0971237421, -1.8624976873, -0.8188779354, 0.5210671425, 0.1090878546, -0.7082766294, -1.1870042086, + -1.0185188055, -0.0105035771, -1.0859087706, 1.0135194063, -0.2151187509, 0.8128567934, 1.1123318672, -0.2369445115, + -0.7196567655, 1.3356708288, -2.0030705929, -1.7887951136, 0.5355278254, -1.9258182049, -1.0679100752, 0.4666056633, + 0.6799566746, -0.6068207026, 0.0376300998, -0.8954614997, -0.1887252182, 0.0670508146, 0.2367895395, -0.7261124253, + 0.1988874674, 1.1370029449, 0.2628233731, -0.1744217128, 1.038582325, 1.9289591312, -0.6241374612, -1.070802927, + 0.7845878005, 0.221374765, 1.2395253181, -1.6699419022, -0.5792590976, -0.7590466142, 0.1721247435, 0.679644227, + 0.2983916998, -2.5116040707, 0.4435839653, -1.0932787657, 0.3189210296, -1.4347689152, -0.414155066, 1.2627629042, + 1.2916916609, -0.7968822122, -1.6745941639, 0.6268520951, -0.2823364735, 1.5425739288, -0.6658401489, -0.2700735033, + 1.0813314915, -1.7792905569, 1.3893454075, -0.2835470736, 1.1381509304, -0.5500882268, -0.3804549575, 0.2835711241, + 0.640645802, -1.932151556, 0.4521977603, 0.0565207116, 0.0297215879, 0.1266185045, -1.1317875385, -0.0913078189, + -1.4813172817, -1.6310836077, -0.133481577, -0.5777752995, 2.1017003059, 1.8821809292, -1.0327913761, -0.468711555, + 0.9024651051, -0.2668906152, -0.3431535661, 0.9062344432, -1.4410095215, -1.8423423767, 0.1403119117, 0.3281984925, + 1.4122068882, -1.4440245628, -0.2864913046, -1.1767127514, -0.2729947269, -0.3813755512, 1.2839496136, -0.3271493614, + 0.1473392993, 0.5373675227, -0.5618190765, -1.8962076902, -0.4639317989, 1.9236954451, -1.6677190065, 0.146439895, + -0.346611172, -0.0322197936, -0.421761781, 0.6667121649, -0.6521687508, -0.1843066812, -1.4433963299, -0.0677214116, + 0.1818892509, 0.2523166239, 0.0736405179, -0.3877593279, 0.8917374611, -0.3416461349, -0.9169380665, 0.5122210979, + -0.4665381312, 0.576746881, -1.4800413847, 1.7983590364, -0.6339222789, -0.2424547374, -0.4834831655, -0.8287428617, + 0.3135240376, 0.8550209403, -0.08552479, 1.5032401085, -1.1833488941, -0.0465497859, 1.0746041536, -0.9027399421, + -0.5185764432, 1.8878662586, -2.182446003, -0.5935040116, 1.2031533718, -1.2403950691, -1.1820745468, 0.2421696186, + -0.3005659878, -0.5867491961, -0.1843579561, -0.0163780041, 0.4539252222, -0.9440818429, -0.3242641687, -0.919557631, + 0.175736621, 0.5645468235, 0.6839561462, 1.7646182775, 0.0367704555, 1.0817803144, -0.3612675667, -0.8710808158, + 0.6322647333, -0.3519022763, 0.71560812, 0.2653824687, 0.0456245095, 0.6150549054, -0.2387576997, -0.9838037491, + 1.111576438, -0.7091395259, 0.5565314293, -0.1952365786, 0.7066562176, -0.1020995602, -0.7186366916, -2.537869215, + -0.2224598378, -2.9098627567, -0.6451359391, 0.3340830505, 0.3082834482, -1.3182439804, -0.3153700233, 0.372523725, + 0.6292732954, -1.1076341867, 0.1932128668, -1.1732625961, -1.2407459021, 0.0289576929, 0.4187066257, -0.10232535, + -0.512676239, 0.3325288594, -0.9176725149, 0.3762895465, 0.4857420325, 0.6293258667, 0.477483362, -0.6179270744, + -0.7745063305, 0.2900193036, 0.6556027532, 0.7161750197, 0.0969872698, -0.277276963, 0.9734714627, 0.9022426605, + 0.5066912174, -1.3773590326, -0.4419030547, -0.9061026573, -1.2645193338, -0.6771960258, -0.7416522503, -0.4033834934, + -1.7905031443, -0.7197990417, -0.1203307286, 0.1458987892, 1.0860456228, -1.3431071043, 0.5452275872, -0.8861137033, + 0.0133407973, 1.8350932598, -0.749422431, -0.9539094567, -0.1490415484, 0.4838488698, 0.1974841207, -0.1861835718, + 0.4435926378, -0.8599298, 0.801739037, 0.8421186805, 0.1312466115, 0.6086190343, 2.2241444588, 0.9180830121, + -0.1491888463, 0.3608322442, -1.1499377489, -0.3584724963, -0.3109835982, -0.0412371941, -0.2816070318, -0.3876631856, + -0.2826207876, -0.3808020353, -0.8287383914, -1.2302982807, -1.8592271805, -1.9187139273, 1.2635271549, 0.0478380919, + 0.5384370089, 1.9528542757, 0.0862558335, 0.0315737054, -1.4575328827, -0.6429215074, 0.2418305725, -0.8390690684, + 0.2132374197, 2.1373596191, -0.7756822109, 0.7898190618, 0.3226329386, -0.6459203362, -0.8996171951, -1.1986262798, + 0.5406119227, 0.3710613251, 0.0836729556, -1.3073230982, -1.7027620077, -0.7785076499, -1.2514255047, -0.740796566, + -0.6227626204, 0.7248088717, -0.9243300557, -2.0425086021, -0.1531879455, -0.8591698408, 0.2854239345, -0.8992351294, + 0.6543528438, 0.2941486835, -1.4519603252, -0.4732797444, -1.6374208927, -0.0668385923, -1.9343371391, -0.7832041979, + -0.910041213, 1.6664811373, -0.2630090714, 0.0338229686, 0.2412451953, 0.6096515656, 0.3015289009, -0.1897550225, + -1.348678112, 1.5449596643, -1.4853315353, -1.6852138042, -0.1775777191, -0.191505596, -0.2492433488, -0.5336878896, + -2.4988777637, 0.8858756423, -0.8840622902, 3.1992139816, -0.1212008819, -0.2876134515, 0.0497608893, 0.4297440648, + 1.5458735228, -0.1417457461, 0.227266103, 0.4704810679, -1.0789257288, -2.4185669422, -0.8468856812, 0.4660403132, + -0.5138173103, 1.7465744019, -1.1475670338, -0.1167239025, -1.489628315, 0.5956840515, 0.9185001254, -4.8521175385, + 1.9427913427, 0.1110671237, -0.8844205141, -1.5047377348, -0.0306469593, 0.4130496979, -1.3862971067, -0.1759836525, + -0.0979491323, 2.197865963, -0.358156532, 0.0429174267, -0.4899995327, 1.6953723431, 1.6068502665, 0.8885279894, + -1.8128461838, 0.8054482937, 0.3749721348, -0.1091318503, -1.4783062935, 0.478131175, 1.1914623976, 0.8886550069, + 0.9224624634, 1.4349462986, 0.6760825515, -1.1191790104, 0.983936727, 0.5592536926, -0.3300490081, 0.9047982693, + 0.6609485149, -0.0711592138, -0.9454471469, 0.9492801428, -0.0225257389, 1.1091521978, -0.3238544762, -1.5080913305, + 0.8890247941, 0.1120769978, -0.3998112082, -0.0686101541, -1.0087525845, 1.1175528765, 0.7182284594, 1.0960410833, + -1.1370993853, 0.5957803726, -1.2771836519, 1.3723937273, -1.0925372839, -0.0115856826, 0.5942286253, -0.4304260015, + 1.0643801689, 1.0266114473, 0.5688973069, -1.3226926327, -0.0613019504, 0.1347569972, 0.3081897497, 2.7131412029, + 0.4377599359, 0.6334095001, 0.3660160601, 0.0500705987, -2.2779371738, -1.4221690893, -0.635849297, 0.1561469287, + -0.9243812561, -0.2980656326, 2.021907568, 1.4666409492, -2.5164093971, -0.3836316168, 0.8046503663, -1.5332547426, + 1.2595324516, 0.9782047272, -0.6557393074, 1.0916570425, 0.5810801387, 1.0126934052, 1.5139583349, -0.3119343519, + -1.6407750845, 0.7864783406, -0.8549495339, -0.7213819623, 0.3934730887, -0.7415456176, 0.394276619, 1.1725586653, + -0.3623433709, 0.6115031838, 0.300879389, 1.5449849367, 0.318126142, -0.6514180303, 0.2031024098, -0.2640877068, + 1.7698686123, 0.6486811638, 0.4432561994, -1.1322586536, -0.0290353186, -0.0781910121, -0.8639219999, -0.1526577324, + 0.1938848794, -0.5969279408, -0.4834834635, 0.1573596299, -0.0592252091, -0.2702434063, -0.1515217274, -0.6052051783, + 1.9567449093, -0.4848371446, 1.4323050976, 0.0834007561, 1.0406645536, 0.0405718312, 0.4692253768, -1.5332688093, + 0.2604510486, 0.1545928121, 0.5367847085, -0.3339368403, -0.4093825817, 2.1708376408, -0.779700458, 2.433300972, + 1.3753080368, 0.2541124821, -1.9115686417, -2.1534113884, 0.785602212, -0.3899005949, -2.4047720432, 0.1866433322, + -0.6678485274, -1.3123197556, 1.2337210178, 1.6666272879, -0.1272123754, -0.927986443, 0.7762946486, 0.9160736203, + 1.7719123363, 0.7667344213, -0.159054324, 0.6486815214, -0.6689631939, 0.510384202, 0.4520286322, 0.156618461, + 0.3792171776, 1.0502470732, 0.4308493733, -0.3508707881, 0.7412344217, -0.327429831, 0.9234266877, 0.9893772602, + -0.8493971825, 0.0270343702, 0.4415463209, 0.6724033356, 0.1209470704, 0.5693858862, 0.0050581717, -2.1161911488, + -0.6223433614, -0.5580531955, 0.2278435379, -2.5865576267, -1.7090963125, -0.0353317894, 0.5161625147, 1.2569897175, + -1.4674524069, 0.3912377357, 1.5026664734, -0.4857432544, 0.0476039536, -1.3667999506, 0.2982648015, 0.2895137668, + -1.2085553408, 0.1725535691, -0.1539426297, 0.6676985621, 0.1313693672, 0.3164666891, -1.0863517523, 0.0785836726, + 0.7611423135, -2.1127955914, -1.4819056988, -1.0567213297, -0.8317061067, -0.4102806449, 1.3269690275, -0.4393536747, + 0.0698533207, -0.6893197298, 2.1084895134, 0.2268670052, 0.8511615396, 0.385448724, 0.4431305826, 1.0205435753, + 0.4819956422, 0.5102502108, 1.545058012, 0.8968815207, -1.0848166943, 0.7952970862, 2.0239479542, -0.7240387797, + 0.0220920593, -1.1563844681, -0.1014404744, 0.3656550944, 0.5663932562, 1.0644277334, -0.5995697379, -1.2106146812, + -0.8576260209, 0.5674060583, 0.600780189, 1.5416058302, -0.690805614, -1.0867762566, 0.2649148703, 1.4798949957, + 0.7393624187, 0.296794802, -0.2771933377, -1.1488587856, 1.6003367901, 1.6553497314, 0.6626985073, -0.6280882955, + 0.09365841, 0.4981217682, 0.9492636919, -0.4618748128, 0.2677331269, 1.2989481688, 0.0265531186, 0.3216917515, + -0.2674317956, -0.0111542614, 0.2487320751, -0.374316901, -0.9511997104, 1.6651052237, -1.6196660995, -0.5902080536, + 0.3614725173, -0.4152885973, -0.7183656096, 0.3520698249, 1.4739658833, 2.4271173477, -0.5691303015, 0.9813193679, + -0.5925389528, -0.5128179193, -1.1542140245, 0.5358704329, 1.3890676498, 0.5996650457, -0.271925509, -0.0948925391, + -0.7808255553, -0.6444920897, 0.9755622745, -0.2208294421, -0.3493718505, 0.2699482143, -0.7280527353, 1.3917051554, + 1.4498575926, -1.2113507986, 0.3349868953, 1.3251229525, -0.9171952009, 0.4963794351, -1.7986804247, 0.0789784789, + 1.2199368477, 0.3269993365, -0.1948697865, 1.3435184956, -1.042525053, 1.3683353662, 0.2499956936, -1.4721306562, + -0.295694828, 0.5207143426, 0.4645217061, 1.4431642294, 1.2225159407, -1.3223319054, 1.0886017084, 0.9286890626, + -0.1376378387, -0.59153229, -1.0464158058, 0.5867432356, -0.8797436953, -0.7235412002, -0.6804904342, -2.0942678452, + 1.029438138, 0.7672358155, 1.0971862078, 0.6071217656, 0.602509737, 0.8277061582, 1.1057502031, 0.5251725912, + -1.1081231833, -0.4811174273, -0.3702764511, -1.3508657217, 0.2259329855, -0.0718035176, 0.1823831201, -0.2373090535, + 1.1184384823, 1.3183101416, -1.9148426056, -0.4826577306, -0.4699207842, 1.278039217, 1.4454777241, -0.2684786618, + -0.2248070687, -2.3880140781, 0.4959293306, -0.326710552, 1.3605651855, -0.5306251645, -0.0932557359, -0.505015254, + -0.7892034054, 1.0203313828, 1.2451971769, -0.4140982628, -0.3513950109, -0.9037069678, -0.0241906717, -0.9075904489, + -0.6557211876, -0.1932841986, 2.3157627583, 0.5288925171, -0.6291821003, 0.9991913438, -0.4957025051, -1.1099767685, + 0.0842455551, 0.0248599015, 0.0334466957, -1.648489356, -0.8135964274, -0.0473386273, -0.7118042111, 0.2833947837, + -0.0167807993, 0.2662077546, 0.6260454059, -1.7930265665, -1.1567467451, -0.5512157679, 0.6015375853, -1.2865725756, + -1.9408442974, -0.1325186938, 0.4100147486, -0.8295570016, 0.1938338429, 0.0979138017, 2.5477495193, -0.4140664637, + -1.7858626842, 0.642950356, -0.3502498269, -0.2588729262, -1.0729311705, -0.3541617393, 0.3570177555, -0.6643162966, + -1.4513443708, -1.697350502, -0.0602100231, 0.249682188, -0.9163889885, -1.5405261517, -0.4512024224, -0.6341095567, + -0.0097503057, -1.2270138264, -1.3736895323, 0.1918285489, -0.919177413, -0.656560421, 0.6039719582, -0.1332715899, + -0.8285505176, -1.0401451588, -2.4385795593, 2.2394487858, -0.2572565675, -1.8150984049, 0.4597521126, 0.4808021188, + 0.5467767715, 0.6092917323, 1.1429659128, 0.2309983224, 1.5645856857, -1.2469551563, -0.257730633, -1.1540452242, + -1.364990592, 0.670242548, 0.2360917628, -0.1505737454, 0.3084661663, 0.91372329, -0.8299762607, 1.7046604156, + 0.4507624209, 1.6921821833, 0.0341390707, 1.4222145081, -0.5597399473, -1.0490896702, 0.6614012718, 0.7688275576, + -1.1840931177, 0.3911654651, -0.4891320169, -0.7211934924, 0.8481540084, -1.0097805262, -0.3961494267, -0.4591137469, + 0.1611833125, 0.1956343353, -1.2476583719, 0.4416362345, 1.136171937, 0.0931860134, -0.9278345704, -0.7907865644, + 0.6913827062, -1.3883576393, -2.3996989727, -0.3636757135, 1.1655604839, -1.4245017767, 1.220895052, -2.0990407467, + -0.9538810849, -0.5822237134, 0.1402315944, 0.0464295745, -0.500885129, -0.2975231707, 0.808278203, -0.3997581005, + -1.6819230318, -1.0130381584, 1.7739200592, -1.0784034729, -0.1895323843, -0.7823113799, 0.8008701801, -1.5388237238, + -1.5723116398, -0.4203703105, 0.1166450381, 1.0583444834, 1.543982625, -0.5834670067, -0.9337796569, 1.9155551195, + 0.1372870356, 0.75055933, -0.8319081664, 0.6255533695, -1.4047561884, 0.1378288567, -0.8832240701, 0.5066967607, + -1.387057066, -0.294968009, -0.5365743637, 0.7241915464, -0.038038291, -0.4298193157, -0.3633871377, -0.1892514825, + -0.9280431271, 1.6019604206, 0.9871795177, 0.4851090908, 1.4912133217, -0.0962753594, 0.2499185055, -0.5457340479, + -0.4101860225, 0.2294923216, 2.2696387768, -0.3302621543, -0.2712452114, 1.5598413944, 0.2520926595, 3.1268947124, + -3.2329590321, -0.2350266725, -0.1970554143, 1.6455147266, -0.4833549261, 1.8614071608, 0.1210813671, 2.4485468864, + 0.3696423173, -1.1890643835, 1.1097162962, -0.9812495112, -1.5117832422, 0.46520859, 1.0399012566, 0.4068359435, + 1.6711966991, 0.4793457091, 0.3833797872, -1.2494162321, 0.1649812311, -0.4304262102, -0.7297959924, 0.8276520371, + 0.7847200036, 0.5139238834, -1.9722926617, 1.0811411142, 0.1848393828, 0.0775561258, -0.2357782871, 0.1912350357, + 0.5073704123, 0.0564742349, -0.8233909607, -0.8220529556, 0.1913980395, 0.8005524874, -0.1441638619, 0.7258716822, + 0.2305646241, 0.9593602419, -0.1887491792, -0.6131626964, -0.2583982646, -0.7700645328, -1.6128127575, -0.614605546, + 1.2405661345, 0.4227060676, -1.0741027594, 0.3241637647, -1.4035487175, -0.0658114403, 0.6804963946, 0.5681362152, + -1.392149806, -1.0300476551, -0.2371842414, 1.8360530138, -0.9216187596, 0.9207280278, -0.5574217439, -0.471216321, + 0.2855410874, 0.3498257697, 0.5446513295, -0.0277582034, 0.9110357165, 1.0241811275, -0.4904206991, 0.0496969819, + 0.6285252571, -2.986168623, -2.1029310226, -0.3938883245, -0.2817675471, 0.2416146547, 0.9426638484, 0.3875665367, + 0.1224803925, 1.0414155722, -0.3351289928, -0.4107232392, -1.5650410652, -0.8893459439, 0.0849630237, -1.7995682955, + 0.9912497997, -1.8885445595, -1.1762053967, -1.2450914383, 2.738077879, -0.3616687357, -0.2209551036, -1.7513599396, + -0.8957287669, -2.2897720337, -0.0876673013, 0.6963365674, 0.3551538885, 0.9297693968, 0.060967423, 2.47123456, + -0.4208989441, 0.5249027014, -0.2286021709, 0.2329783738, 0.1197842136, -0.9520625472, -1.8651957512, 0.2399929166, + -1.2985645533, -0.6591146588, 0.2112485319, -0.6970937252, -0.6887322068, -2.0674235821, -0.0465840735, -0.9805367589, + 0.4654271901, 0.5672482848, 0.7053048015, -0.6611399651, 1.5472348928, -0.9092199206, -0.0546701252, -1.0351397991, + 1.314000845, -1.5395072699, 0.0404680595, 0.9997606874, 0.6848905087, 0.4523021281, 0.4604639709, -0.1260150522, + 0.1083656922, 0.5990031958, 0.7269591093, -1.7155878544, 0.668569088, -0.6821148396, -1.3120325804, -0.585201323, + -0.380689621, 2.048671484, 0.6823633313, 1.091332674, -1.6782044172, 1.5952193737, 0.6944016814, -1.187133193, + 0.9472473264, 0.5641186237, -1.0589094162, -0.8352508545, 0.8253346086, 0.5406584144, 1.056460619, 0.6108237505, + 1.3554942608, -0.0652598366, 0.3243359029, -0.484171629, 1.2476578951, 0.2305612564, 0.9184203744, 0.7574568391, + 1.0057890415, -0.4710326791, 0.0801935941, 0.002397994, 0.6727606058, -1.4283015728, 2.0315153599, 2.1044881344, + 0.807970643, 0.2700591683, -0.1420193762, -0.4140471816, -0.838368535, 0.3478310406, -0.110237211, 1.3906400204, + -0.4889595807, -0.1187727004, -0.8679751158, -0.0362039842, -0.0926602483, -1.0390424728, -0.52579844, -0.0478054583, + -0.9813799858, 1.6373766661, -0.0322443843, -0.47115767, -1.7374867201, -0.3807227612, -0.161516279, -1.1044647694, + 0.1208630577, 0.8739864826, 0.4768305421, 0.6930779815, 0.3838321269, -1.5314662457, 0.3809277415, 0.1716790795, + 0.3956367671, 0.9040478468, -1.4133884907, 0.8503904343, 1.1443232298, -0.0336308964, 1.1579585075, -0.3186286688, + -0.195381403, 1.194283247, -0.5953484178, -0.955027163, 0.2698577642, 0.1056953147, -0.0633471906, 0.3749876022, + 0.1402860582, 1.2944872379, -0.4121560156, 0.481793046, -0.0993803889, -1.5939522982, -0.4357390404, -0.4619060159, + -2.3683354855, 0.2805862129, -0.3046934605, -1.2935652733, -1.155467391, 0.1633427739, -0.5986722112, 1.2634762526, + 0.9150058627, -1.0899602175, -0.5049229264, -0.0143814981, 1.5127053261, -0.8898098469, 0.3804249167, -1.165882349, + 1.2145162821, 0.1391834766, 0.9084006548, -0.0797242448, 1.7454173565, 0.8128961921, -0.3380572498, -0.8773782849, + -1.1081911325, 0.7548649311, 0.2150626332, 1.183318615, -0.3489762843, 2.1793832779, 0.301951766, -2.0800480843, + 1.3498222828, -0.646951735, -1.0101433992, -0.0867938995, -0.3999692202, 0.5472961068, 0.4918823838, 0.9543326497, + 1.3563923836, -0.8218570352, 0.0116919894, 1.2118961811, -1.2016319036, 0.4808796048, -0.428486228, 0.2089256644, + 0.8705192804, -0.3592517376, 1.0025163889, -1.3868917227, 0.2231241167, 1.6292181015, -0.7550464869, 0.4189785719, + 1.3076460361, -0.3605156541, -1.1180034876, -1.1126116514, -0.6930063963, 0.3895854354, -1.181166172, -0.7325514555, + 0.1279658824, -0.5388088226, -0.3408534229, -0.2591611445, -0.1481301636, 1.1229610443, 2.1432387829, -0.3806581497, + 0.8855195642, -0.5941774845, 0.8604633212, 1.0511958599, 1.0734173059, -0.2655522227, -0.3933710754, 0.3349715471, + -0.8550754786, -2.2061393261, 0.9727731943, 0.7498283982, 1.6936372519, 0.5487921834, 0.0691117644, 2.7273132801, + -1.8114776611, 1.1478933096, 1.0795128345, -1.0359307528, 2.3957827091, -0.7863538265, 0.5545166731, -0.296685189, + -0.2659127712, -1.2508859634, 1.1771451235, 0.492393136, 1.2278065681, -0.7286225557, -0.0930251777, -0.599870801, + -0.2299500108, -0.4579644799, 0.5729542971, 2.3201682568, -0.8726349473, 0.3805692196, 0.8630654216, 1.6897252798, + -0.8851308227, -0.3429644406, -0.7624091506, 1.3988976479, -2.7959020138, 0.4372125268, 0.0636285543, 1.8906742334, + 0.0905186236, -1.0840857029, 2.0455691814, 0.9350713491, 0.1695361584, 1.2804718018, -0.6724713445, -0.3662121296, + 2.0804431438, 1.776165247, 2.867852211, -0.0991531014, -0.3440111876, -0.9633069038, -1.3825284243, -1.4679977894, + 0.2173433304, 0.0366753228, -0.7773872614, -0.0060850084, 0.242557168, -0.3767814338, 0.8276780248, 2.0392413139, + -0.2837807238, 1.2338672876, -0.3843937814, 0.5756478906, 1.6414058208, -0.3666916788, -0.9714407325, -0.2356366962, + -1.2913995981, -0.8960181475, 0.1272795498, -2.2407054901, 1.1917226315, 0.4333340824, -0.3930523992, 1.1191014051, + 0.6791875958, 0.4361049235, 1.0977270603, 1.0344529152, 0.3062209487, -0.0446278788, 0.0910232663, 0.5822839737, + -0.1521469802, -1.1190607548, -0.247605443, -0.7367978096, -0.4856684804, 0.6659203172, -1.2921715975, 1.8827733994, + 0.583848238, -0.2108717859, -0.0243280269, 0.1365130842, 1.4073339701, 0.9856215715, 0.3627391756, -1.3479270935, + 1.1825037003, -0.2711353302, -1.2824739218, -0.6591538787, -0.5253095627, -0.4016566873, 0.4823636115, -0.6241627932, + 0.4012881219, 2.4049458504, 1.8389296532, -0.8160229921, -0.8917958736, 0.2054117322, -0.5678172708, 0.0877340585, + -1.3987337351, 0.3651104569, -1.0884479284, -0.0357880071, -0.7008450627, -1.4183855057, -1.0605516434, -0.5557442904, + -1.4653967619, 0.3975590765, 0.969391346, -0.5058177114, 0.1420748681, -0.1394046992, -1.1864151955, 0.5770588517, + -0.4497047067, 0.6133778095, -0.2091179043, -0.8822066188, 0.9266041517, 1.9369000196, -0.9379522204, -0.5523123741, + 1.6441167593, 2.0208413601, -0.5548222065, 0.0124798529, 0.5058183074, 1.1044448614, 1.3189389706, 0.1909236014, + -0.3080491424, 0.5630736947, -0.0837698281, -0.3891959786, -0.9374899864, 0.6200323701, 0.7414302826, -1.2315765619, + 1.9131008387, 0.8843234777, -3.2155885696, 1.7159427404, 0.2663838565, -0.0736449733, 1.1531600952, -1.0004495382, + 1.8306009769, 0.4198108017, -0.5446417332, -0.3730129302, -0.5347300768, -1.3494056463, 0.569737196, 0.3700086176, + -0.8028948307, 0.1239058226, -1.1565580368, -0.9970475435, -1.4502310753, -0.5761058331, -1.4261182547, -1.5865499973, + 0.8991324902, 0.6901183128, 0.3546708822, -0.3055213392, -0.1828400046, 0.0213740449, -0.7595441341, -0.1451109946, + 0.2397838533, 1.002994895, 0.7565121055, 1.3437296152, 0.9344487786, -0.0852555111, 0.8469684124, 0.5529686213, + -0.2060049176, 0.1530812085, 0.6497737765, -0.7188387513, -0.6574992537, 1.206839323, 1.4107749462, 0.5801166892, + -1.9565601349, 2.329420805, 1.6649837494, -0.1143305302, 1.1704581976, 0.1861006618, -0.3432528973, 0.7738602161, + -0.7633075118, 1.662093401, -0.0148074497, -1.5225170851, 0.4448566735, -1.0804424286, -0.2595146596, -1.2039898634, + 1.1865116358, 0.1244517788, -1.7411261797, 0.6327655911, -1.425432682, 0.6072432399, 2.2639195919, -1.7797319889, + 0.1546354294, -1.6730787754, -0.6163903475, -0.3629196286, 0.1454897076, 0.6794376373, 1.9794061184, -0.4524740875, + 1.8563537598, -0.1063185409, -0.9688279629, -0.1407084316, -0.5214707851, -0.2364092022, 0.1224080771, -1.4739046097, + 0.2961368263, -1.8272217512, -2.0639176369, -1.3346837759, 0.584385097, -0.5584329963, 0.0578550063, 1.035720706, + 1.7963436842, 1.2943576574, -0.7003925443, 0.8481504321, 0.6891615391, 2.0482206345, -1.2533652782, 0.2402896881, + 0.6737480164, 0.4490898848, -1.6458679438, -0.9338932633, -0.3591641188, -0.0254199263, -0.534193933, -1.2297190428, + 1.7889677286, -1.4703223705, -0.1667094529, -0.8333431482, -0.8809360862, -0.0065073199, -1.0043187141, -1.02348423, + 0.3805767596, -0.4275160134, 0.5769917965, 0.9083298445, 0.7803912163, -0.8485795259, -0.3394566476, 0.6788250804, + -0.5510795116, 1.0690231323, 0.6100328565, -1.1385766268, -1.2801609039, 1.3604898453, -0.169298023, -0.9945854545, + 0.1831673235, -1.6491280794, -1.4920870066, 0.5627005696, -0.2753271461, 0.1657936871, -0.5342975855, 0.2055897117, + 1.9000588655, 1.7738777399, 0.058124084, 1.7368767262, 2.5812046528, 0.3220744729, -0.3783294261, -0.3094934523, + 0.8187251091, 0.9548506141, 0.9769791961, 2.0029132366, 1.7150564194, 0.0704670697, -0.3864088058, -0.6378495693, + -0.0315747187, 0.3025371432, 0.4778320789, 0.3217836022, 0.6492074132, -0.9109751582, -0.7691422701, 1.4026347399, + -0.9658105969, -0.1002218947, 1.5368416309, -1.2793962955, -0.1795984358, -0.3374651372, -0.8700996637, 0.4942047596, + 0.1025737524, -0.9360316396, 1.4573398829, -1.1856033802, 0.3710526824, 0.5413604379, -1.3624647856, -2.2412455082, + -1.4766739607, 0.7899505496, -2.7598965168, 0.4047561288, -0.6828455925, 1.9673783779, 0.662699461, -1.0715668201, + 0.2047873735, 0.0702401102, 0.2123592794, -1.3596889973, -0.6493543983, 0.702453196, -0.7617487907, 0.2701660991, + 0.5384673476, 0.4484993517, 1.4303277731, -0.2872730196, 0.2255844325, -2.0188221931, 1.1860226393, -0.0449120253, + 1.4178494215, 1.1506255865, 1.9027528763, -1.01516819, 1.4701216221, -0.3491511941, 1.9576206207, 1.709452033, + 0.8521990776, -0.6261596084, 1.6764523983, 0.7147725224, -0.4068088233, 0.630844295, -0.0767498091, 0.6154634356, + -0.5383847356, -0.322537154, 0.4823666215, -0.3547261953, -0.2532891035, 0.6753273606, -0.5546728969, 1.0751554966, + -1.3161867857, -0.9454118013, -2.4545342922, -0.051829733, 1.0433616638, -0.5003373027, -0.3093115389, 1.7492716312, + 0.2976246774, -0.8289340138, -1.5835789442, -0.3375042379, 1.9913307428, 1.0772083998, 0.0367077291, -0.0472101569, + 0.465823859, -2.6238150597, 0.9969777465, 0.0754188821, 0.3507779837, 0.4585555196, -0.0999287292, -0.392849654, + 1.7388290167, -0.8560393453, 0.0992961749, -2.1302506924, -1.3153241873, 0.8314374089, 0.0599960461, -0.1368577778, + -0.3394154906, -0.5296584368, 0.2793669999, 0.7099635005, -0.0835562423, 0.602160871, -0.1196800545, -1.3378901482, + -0.3641176224, 1.2721914053, -1.4890229702, -0.6869053245, -0.4686065614, 0.6426337957, -0.5083370805, 0.2268973142, + -0.1974736899, 0.2527569532, 1.7184084654, 0.8922979236, -1.5970692635, -0.4582478404, -0.4076239169, -0.1977892369, + -0.7555869222, -0.3449466527, -1.2325458527, 0.1456603408, -1.2386804819, 0.1323075742, -1.8673850298, -0.0677953959, + -0.83909446, -0.2440842092, -1.1514731646, 0.3661558926, 1.9396024942, 0.5101702213, -1.1429055929, -1.1398406029, + -0.5165202022, 0.3982322812, 0.5776135921, -0.2317762971, -1.4540951252, -1.3447998762, 0.8522616029, -0.557813704, + -0.2578280866, -0.0890806839, 0.0349463075, 0.6758262515, 1.1467132568, -1.6023062468, -1.1934000254, 0.7290937901, + 1.1782319546, 0.3880271018, 0.0174299795, 0.7336113453, 1.013944149, 0.5473438501, 1.4955612421, -1.4451948404, + 0.6801576614, -1.3201237917, 0.6385329366, 0.0782859474, -0.0863106698, 0.6152905822, 1.3551502228, -0.0890230834, + -0.0486132428, 0.8171393275, -0.1492211223, -1.7590962648, 0.9003215432, 0.1985468268, -0.2245959789, 0.670906961, + -0.9071885347, -0.0217190348, 1.0644416809, 0.2005730122, 2.5758602619, -0.1752953529, -0.4584687352, 1.048686862, + -1.1132804155, 1.2848652601, 0.0694471598, 1.1292618513, 0.9819657207, 0.8070746064, -1.1838014126, 0.9127116799, + -0.0829647705, -1.8536667824, -0.0619276203, 0.0663916543, -0.9791166782, 3.1375920773, -1.5782490969, -0.0379903316, + 0.9323066473, -1.2534710169, -0.5725334883, -1.3511468172, 0.7215948105, -0.5781445503, 3.3989739418, -0.2205531001, + 0.3763498962, -1.2892030478, 0.6944087744, -0.0149582736, -1.7329707146, -0.1396349519, 0.8098288178, 0.1786913425, + -2.2183401585, -0.0800998956, -0.074224107, 0.3845080733, -1.6463791132, 0.710739255, 0.9891936779, 0.7867619395, + 0.0749255121, 0.200166598, -0.1341113001, 0.0893330351, -0.9379463792, -0.9581400156, -1.2719728947, -2.7973825932, + 0.5311394334, 0.5251041651, -0.4277549386, -0.2632635534, -0.0099409046, 0.7350210547, 0.41928038, 0.0018239388, + -0.0443116762, -0.0689535663, 0.7293576598, -0.4967725575, -0.5072520971, -0.1359933764, -1.2276622057, 0.6094608307, + -1.6442064047, -1.6363502741, 1.2297830582, 0.0999848545, -0.098648563, -0.0178937595, -0.2287111878, -1.5501198769, + 0.2100454867, 0.8902381063, 0.1387624741, -1.6011765003, -1.2235500813, 0.3127393425, 0.3142060637, 0.8466959, + -0.4800876677, 1.5377589464, 0.2422349155, -0.9983308911, -0.0291883871, -0.1622420102, 1.0121430159, 0.6871752739, + -0.4247593284, 1.0550050735, 0.3513199985, -1.4561393261, 2.1552989483, 1.3274356127, -0.5354955792, -0.6845734119, + 0.447994709, 0.3242218196, -0.5768624544, -0.3779707849, -1.0639026165, -0.2439878583, 0.0086092334, 1.6724859476, + 0.0878778622, 1.175532937, 0.1444046646, 0.6706321836, 1.2580265999, -0.4368670881, -0.3676288128, -0.1864498854, + -0.520157218, 1.1724785566, 0.2010924965, 1.6923856735, 0.2290286273, 1.6569188833, -1.7776489258, 0.457344532, + 1.3080205917, -0.374712944, 1.2378357649, -0.5824361444, 1.135733366, -0.9598888159, 1.1630618572, -1.5749995708, + 0.7833538651, 0.1442527771, -0.2554296255, -0.9792585373, 0.4596745968, 0.6203821301, 0.5021705031, 0.9194006324, + -1.0334367752, 1.6282829046, 0.8093135357, -0.223484695, 1.261253953, -0.9625234604, -0.6355591416, 0.4715775549, + 0.006870104, -1.0172108412, 0.2494076043, -0.5978446007, -0.7592504621, 0.8392009139, -1.3911912441, 0.4128962755, + -0.773578465, 0.0836772174, -1.5262907743, 2.5723426342, -0.1008686349, -0.2837621868, 1.0058437586, -0.7359182835, + 1.1496107578, -0.8255521655, 0.7245010138, -0.8101114035, 2.0787091255, 0.8559275866, -0.5351945758, 0.6291060448, + 0.0856874585, -0.0063943989, 0.3543403745, -0.5699222088, 0.2983883321, 0.7868961096, -1.0871948004, -0.2908948958, + 0.0930618271, -0.8280441761, 1.1082425117, 0.2538062036, 0.2027538866, 0.1541826278, 0.2480404079, -1.4028227329, + 1.1533126831, 1.6422873735, 1.0832636356, 0.8322021365, 0.8517474532, 0.7841898203, -1.744032383, 0.4765495658, + 1.0487160683, -0.7914233804, -0.4405639768, -0.2160148919, 0.1842859089, 1.1629821062, -0.076724343, -0.7312394381, + -0.6774958372, 0.3769921958, -0.5758907795, -1.5134738684, 1.418164134, -0.7427386642, -1.0262612104, -1.0112211704, + -0.8954152465, 1.0703066587, -0.3507716954, 1.0855424404, -0.3428264856, 1.174672842, 0.3893014789, 0.9072918296, + -1.5879071951, -1.7463401556, 1.5358440876, -0.2369948775, 0.2931667566, 0.4586500227, 0.2925986946, 2.3936650753, + -1.6313507557, -1.3064545393, -0.2756645977, -0.1694798321, -1.8411900997, 0.1854819059, -1.0566730499, -0.1226647571, + 0.0523388982, 1.1009833813, -0.8073753119, -0.0405311659, -0.1907524914, 1.6200549603, -0.8034185767, 0.9933840036, + 0.8365669847, -1.0088229179, 1.3915550709, -0.6660532951, -0.4306976795, -0.2386864126, 0.0843213871, 0.5830325484, + 0.1325431019, -0.7190958261, 0.4042440355, 0.1904487908, -0.3511888981, -0.0677566752, 0.7692873478, -0.9150775671, + -0.2478805482, -0.1723368913, -1.7062830925, 0.1571991444, -1.2567185163, -1.2486581802, -0.3304790258, -0.1429319084, + -2.0155272484, 0.1789071411, -0.6599000096, 0.2713014483, -1.515393734, 0.542927444, -0.5614190698, 2.1147344112, + 0.1305354685, 2.3193845749, 1.093236804, -1.4592151642, 0.8998706341, -0.561953187, 0.1160965636, -0.1549596637, + -1.3603447676, -0.1224236861, 0.1485626996, 0.2863123417, -0.7079705596, 1.2752975225, -1.8051139116, -2.4880578518, + 0.5680893064, 0.7016727328, 0.1439006329, 0.4267070591, 0.1790274084, -1.6500613689, -0.8564890027, -0.9328461289, + -0.1378492862, -0.9564430118, -0.2885970175, 0.264821738, 0.2335142493, 0.8945885301, -1.3390487432, 0.6258945465, + 1.6428123713, 1.6459735632, 0.5991826653, 0.1086787358, -0.7074826956, 0.9272280931, 0.474496752, -0.4278449118, + 1.0480604172, -0.4526143372, 1.3277521133, -0.0564636923, 1.3267620802, 0.2104748785, 0.3823283613, 2.0361435413, + -0.5682298541, -0.9197977185, 0.2950363457, -0.0598035455, -0.3787401319, 0.7625000477, -2.9526107311, 1.0240620375, + -0.1243128777, 0.988304913, -0.2431208044, -0.5595453978, -2.286894083, 1.2129172087, 1.8089084625, 1.2684593201, + 0.5851132274, -0.2312829345, 1.8950910568, 1.1503691673, 0.6162592769, 1.1002618074, -1.1529587507, -1.5807942152, + 1.0720236301, -0.8970527649, 0.7691181898, -0.3447100222, -1.088108182, 0.6037220359, 0.1806760728, -1.5382072926, + -0.640678823, 1.2235890627, 0.6681796908, 0.5669136643, -0.9254377484, 0.489014864, -0.3914958239, 0.3539678752, + 0.9485787749, 0.3038055897, -0.1886343509, 0.5120302439, -0.156928122, 2.2453000546, -0.424143374, 0.7208776474, + 0.3618130088, 0.5907598138, 1.0482422113, -0.7412730455, -0.142845422, 0.0379181169, 0.2372295856, -0.2962428927, + 0.6757543683, -0.6153737903, 2.5128779411, 0.179912135, 1.3834085464, 0.5711925626, 0.936663568, -0.7422040701, + -0.5731911659, -1.0898987055, -1.5423468351, -0.4778312743, 1.5007041693, -0.7780981064, 0.2048971504, -0.5669568777, + 0.374655813, -0.4002239704, 0.6586911678, -0.361305654, -0.9264248013, -1.0720075369, 1.2189369202, -0.3600791097, + -0.7939486504, -1.1968816519, -0.6835036874, -0.2224785089, -0.8625183702, 1.2658147812, 2.2403526306, 0.8670475483, + -0.9484440684, 0.6970045567, -2.1961770058, -1.6428921223, 1.0440677404, 2.1168622971, -0.0151213622, -2.2564005852, + -0.6929907799, 0.2016869783, 2.428062439, -0.0699802339, -0.5621324182, -0.7554766536, -0.6078110337, 0.8083912134, + -0.8453896642, 2.1699969769, -2.6128845215, -0.0212052483, 0.4015052915, -0.5356868505, 0.9977837801, 0.1122059673, + 0.0778343603, 1.3476768732, 0.2835381627, -0.0142331179, -2.0367105007, -0.7371923923, -1.2246629, 2.2353093624, + -0.7961319685, -1.9554548264, -1.2512631416, -1.0218428373, 1.2124526501, 1.1355682611, 0.6193997264, 0.2487773597, + -0.2672690749, -0.454534322, 0.791122973, -0.3282171786, -0.1699972153, -0.6668633223, -0.4596285522, 1.5497270823, + -0.0206197053, -1.1669906378, 0.6233358383, 0.745354414, -0.4479801953, 1.0420253277, 0.1992836148, 0.5260112286, + -0.7913386822, 0.5561696887, 0.969568193, 0.4419442713, -0.2964356244, 0.1331102252, 1.4653676748, -0.4023957253, + -1.9205198288, -0.1914123297, 0.5629822612, 0.4740603566, -1.2222735882, 0.2560369074, 1.1243366003, 0.3371331096, + 1.7473640442, -0.4876609147, 1.2396174669, -1.2924531698, -0.8329555988, 0.810618937, -0.3956554234, -0.5539463758, + -0.2932499051, 1.0425081253, -0.3843310177, -0.2666507065, -1.8152126074, -0.6074080467, -0.0640053749, 0.3151269555, + 0.618372798, -1.3044564724, 0.8262851834, 0.3810087442, 1.1846222878, 0.3196219802, -1.6368120909, -1.0149875879, + 0.5286067128, 0.2212347835, -1.354003787, -0.2165237516, -0.098024942, -0.1607593447, 0.6369425654, -0.1619250774, + -0.5857174993, 2.6423957348, 0.9990339279, -0.316839993, 0.338101685, -0.3765596449, -0.3019950092, -1.2485268116, + 0.0268364325, -0.4783943295, 0.1249814257, -0.4447103739, 1.1281132698, -1.7312458754, -1.779157877, -0.5942288041, + -0.5394236445, -0.3606801033, 0.0106915636, -0.0157427508, -0.8622555733, -0.0226995777, -0.0577265061, -0.1762067825, + 0.2407553047, -1.0976681709, -1.3848628998, -1.8822962046, -0.0017791095, -0.5731220245, 1.9252378941, -0.4404511452, + -0.4575495124, -1.0234162807, -1.661216855, 2.411413908, 0.2933978736, 1.0817257166, 1.0481520891, 0.3456228673, + 0.0791619942, 1.0115976334, 3.3180394173, -1.0060584545, -1.0057104826, 2.2909924984, -1.4247964621, 0.7731633782, + 2.4017169476, -2.6709401608, 0.1828530282, 0.2281860262, 0.2734143734, 2.3842585087, 0.7326384783, 1.1197537184, + -1.3578523397, 0.9588159919, -1.0450409651, 0.7155377865, 0.1096529886, 1.2337069511, -0.2804929018, -1.8858106136, + 0.3575464189, -0.0844301283, -0.8718315363, -0.9173175097, -0.6598443389, 1.4191524982, -1.0103415251, 1.174100399, + 1.8414045572, -0.3743493259, 1.0813381672, 0.4680810869, -1.5805219412, 1.534080863, 0.7638397813, 2.2288279533, + 0.1072080508, -0.7255489826, 1.1193445921, 0.1728860289, -0.6225542426, 1.1737477779, 0.5976502299, -1.7421793938, + 0.2293184102, 0.8057854772, -1.6511553526, 0.4416771233, 0.346631974, -0.0454043299, -0.1209124625, 1.6247614622, + -0.7286786437, 0.5841590762, -0.1831379086, 0.5785822272, -0.4785403013, 0.9208111167, 0.3044312298, -1.4587692022, + -0.1678542942, -0.6752638817, -0.249626264, -1.6186631918, 0.7310032845, -0.4667387307, 0.083991237, 0.0778162628, + -0.8575924635, -0.2125936151, -0.6107373238, -1.1801326275, 0.6009773612, -1.1573953629, 0.7150562406, -1.465051055, + 1.7268512249, -1.0357637405, -0.4485883117, -1.457937479, 0.8677504659, -1.4565110207, 1.5130494833, 1.5456116199, + 0.0075432993, 0.0928202122, -0.4449352622, -1.2877678871, 0.8085286021, -1.37847507, -0.056153547, -0.4697008133, + 1.3949416876, -0.439884901, -1.9523414373, -1.8618255854, -0.4945134521, -2.0245842934, -0.7269943357, -1.2706829309, + -0.8815476298, -2.0346591473, -1.1727267504, -0.7687079906, -1.7004654408, -0.2370119691, 0.4915896654, -0.795091331, + 2.6508188248, 0.6726636887, -0.4534219801, 1.8084821701, 1.0631934404, -0.7404429317, 0.1299059689, 0.2656057477, + 0.7115128636, -0.0633414313, -0.6535018086, 0.7916250825, 0.3691915274, 0.0040150597, -0.662014544, 0.2596068382, + 0.4594883025, -0.5084525347, -2.4214904308, -0.9198400378, 0.5192216039, 0.4900861979, 0.8938479424, 1.7531205416, + 0.2292024791, 0.2872477174, 2.1692998409, -1.0889079571, 0.844697535, 0.0144895865, -0.4923832715, 0.2821266651, + -0.1231191456, 1.4335643053, -0.2643232346, 0.8737241626, 0.9721201062, -1.1100924015, -1.3487612009, -0.247786805, + -1.1834433079, -1.2005623579, 1.019151926, 0.7395281792, 1.1104048491, -0.0219590571, 2.0232183933, 0.5489047766, + -0.0274477396, -0.7132084966, 0.2385355234, -1.7889448404, 0.7535198927, -1.0275415182, 0.0347306617, 1.3003791571, + -0.1093231812, -1.304019928, -0.202965796, 0.5065885186, 2.0733292103, 1.369636178, 0.9754089713, -2.0454306602, + -0.0382960923, -0.5714712143, 0.2167275846, 0.6750763059, -0.3483577669, -0.774658978, 0.6165201664, 1.3618383408, + 1.2122330666, 1.3800063133, 0.5365054607, -1.917730689, -0.5251973271, -1.0988540649, 0.0278137494, -0.7636909485, + 0.6048128009, -1.1625010967, -0.7021710277, -0.6840939522, -0.2839722633, -0.9208801985, -0.3885153234, -0.9178700447, + 1.5394451618, 1.4378056526, -1.4322452545, 1.8636082411, 0.4008088708, -0.4350753725, -1.1601147652, -1.1638344526, + -0.032214839, 0.4595857859, 0.9118782878, -1.5388293266, 0.6242665052, -1.0804662704, 1.2000719309, -0.1710569859, + -1.0350323915, 0.4459679723, -0.1440854073, 1.3036524057, -1.7022899389, -0.9515473843, -0.6042004228, -0.5069737434, + -0.2445824593, -0.6166288257, -0.1103350669, 0.0383932628, 0.3011859059, -0.5186234117, -1.4050905704, -0.3328391314, + 1.2396959066, 1.4162265062, -0.339807421, -0.1771123707, -1.0423727036, 0.9640633464, -0.4511846006, 0.90804106, + 0.5163629055, 0.9133321047, 0.2308627367, 0.9364045858, 0.4994279742, -0.9036644697, -1.0831034184, -0.4359258115, + 0.0862119645, -0.6307891011, -0.0972120389, 1.4832203388, -0.3554448485, 0.2293844819, 0.7009916902, -1.2562806606, + -1.1880155802, 0.8979741931, 1.0003473759, 0.8966107965, -0.1492953151, -0.1308869272, 0.2263855487, -0.013005564, + 0.4222289026, 0.4016860127, -0.4904920459, 0.7437108755, 1.9387946129, 1.6307559013, -0.5204173326, 0.351731956, + 0.0115969433, -1.4235920906, -0.4553895593, -0.1439766139, 0.7038559318, -0.2786969543, 1.5749616623, -0.0669014901, + -0.8004282713, -0.7990862727, -0.4329472184, 0.2307552397, 1.6242434978, 0.5721014142, -0.7301663756, -1.3531529903, + -0.8805804253, 3.4693908691, -1.3049875498, -0.4333794713, -0.2324779332, -0.7562892437, -0.0847490132, 0.12380182, + 2.0294234753, 1.1775977612, -0.7600325942, -2.2919991016, -1.6500588655, -0.9651675224, -0.0731742159, -1.8575273752, + -1.3492054939, -0.1087381393, -2.6830763817, -1.9446489811, -1.1404054165, -0.3651441932, -0.5104267001, 0.8189151287, + 0.6377196312, 0.5000778437, 1.4043917656, 0.2186368108, 0.561602354, -0.7406401038, 0.7284206152, -1.1032539606, + -0.1957814097, 0.6142774224, -0.1744652241, -0.8923316598, 0.5519254804, 0.0332063623, -0.6735925674, -1.1467906237, + 0.5041069388, -0.0882616341, 0.5556857586, 1.6077281237, -1.5892181396, 3.5689439774, -0.528914988, -1.3064787388, + 0.1786384881, -1.1435884237, 0.4807915092, -0.4079792202, 0.039475508, -0.6162922978, -0.6694833636, 0.8787062168, + -0.8178895116, 2.6429357529, 1.2247593403, 0.0740591511, 0.5969020724, 0.4470560551, -1.7656972408, -0.9531686306, + 0.684750855, -0.746040225, -0.0438507125, 1.1078300476, 1.3620145321, 0.3313216567, 1.3880150318, 0.4393956661, + 0.8094944358, 0.4581452608, 0.430321008, -0.1151056662, -0.8882232308, 1.1301658154, 1.4888341427, -0.5208579302, + -0.5673535466, 0.0692926571, 0.2035409361, 0.4037210345, -0.4218095243, 1.1342378855, -0.4237312078, -0.334481895, + -0.0618350804, -1.1918430328, -1.4559003115, -1.0172894001, -0.8198907971, -1.1291286945, -1.2913620472, 1.1161898375, + 0.9469137788, 1.3321481943, 0.6899978518, 0.6809046268, 0.203261584, 0.0857793987, 0.1699928343, -0.1400194466, + 0.4252460599, 0.1930265427, -0.6893171668, -0.0112007195, 0.5478432178, -1.6128880978, 0.5252740979, 1.9394230843, + 0.273134917, -1.6321368217, 1.1112415791, -0.9279717803, 0.1051486731, -2.1612613201, 0.8048269153, -2.2167458534, + 0.2070944011, 0.3835910261, 1.3284368515, 0.1795494854, 0.3918175399, -1.320376873, -1.4642324448, 0.3817415237, + 0.5377549529, -0.2622683346, 0.6836646795, 0.397208482, -0.4240120351, 0.0491578691, 0.1181937605, -0.7205049396, + 1.6013940573, 0.1794056743, -0.3333885372, 0.867318809, 0.727394104, -1.3895088434, 0.8160765767, 1.0607300997, + 2.6599748135, -1.0260976553, -0.4237062633, 0.6025332212, -0.3183956444, -1.0793176889, 1.1519999504, -0.4337845445, + -0.2645676732, -1.4520622492, 0.3616208136, -0.790453732, 1.5489475727, 0.0706833676, -0.7320204973, 0.5462500453, + 0.9109166861, -0.2380175889, 0.8746619821, -0.5622177124, -0.7081284523, 0.1509067416, -0.9439134002, -1.568064332, + 2.3613348007, -0.4723900259, 0.2858115435, -1.2789443731, 0.4329091311, -2.0931222439, -0.1401796043, 1.3160349131, + -0.5561891794, 2.8609473705, -0.9401915073, -1.1080731153, 0.3751921356, 1.6322127581, 0.6731638312, 0.0600589253, + 0.4372738302, 0.4696765244, 0.9339655042, -1.3887944221, -0.286308825, 0.7338685989, -0.1506843418, 2.5223164558, + 0.8215770125, -0.2824140787, -0.1048718765, 0.8483038545, -0.806270957, -0.2444159091, 1.4299122095, -2.1488876343, + 0.4855590165, 0.7521313429, -0.0362242311, 0.9838863015, -0.9353536963, 0.0884423181, 2.2920429707, -0.1700564772, + 0.2196080536, -0.7678773999, 0.1562586427, -1.7027182579, 0.6213787794, -0.9202602506, 0.6407473683, -0.1986954063, + 0.6446263194, -1.6563129425, -1.0442481041, 1.4251111746, 0.0319977812, -1.0316035748, 1.1146814823, 0.9316073656, + 0.4386779368, 0.3499840796, -0.3451722562, 0.1396140605, 0.6647171974, 0.8718655705, -1.3025929928, -2.4178709984, + -0.290720582, 0.3312182128, -1.2822395563, -0.1600407064, -0.1754976213, 0.9503936768, -0.2703380287, -0.1025897637, + -0.9934663773, 0.024925895, 1.2744728327, -0.8118573427, 1.1149960756, 0.1397129893, -0.7670947313, -0.6668843031, + 1.3282564878, 0.544796288, 0.5307455659, 1.3833870888, -0.0055647413, 1.0632278919, -0.5771430731, -1.2756719589, + 0.1890316457, 2.1345887184, -0.8619757295, -1.064645648, -0.5164789557, 0.5170358419, -0.2600931823, -0.4217748642, + -0.4166208506, -1.8200933933, 0.1230064183, -0.0741620585, -1.4303330183, -0.4159705937, 0.3553825617, -1.4155803919, + 1.0580601692, -0.1156407297, 0.594866991, 2.3360552788, 0.2601666749, -0.009458866, -0.9592040777, 0.6389791965, + -2.1392457485, -0.7021299601, -0.5663596988, -0.7259340286, 2.0994577408, -2.1976509094, 1.4211015701, 1.4037487507, + -0.5544083118, 0.4942214787, -1.3881099224, 0.5758545995, 0.5089108348, 0.7930374742, -0.958280921, 0.7822327614, + 1.4710839987, -1.6592271328, 0.6535981297, 0.3041735291, 1.0828449726, 0.4052551985, 1.308652401, -1.1172833443, + -0.6074464321, 0.3001531959, -1.0475873947, -1.217404604, 0.0880611092, -0.390185982, -1.6000955105, 1.0908169746, + -1.0064556599, -0.0125739658, 1.0592347383, 0.4535114467, 0.9690465331, -0.9640182257, -0.8309549093, -0.0977261811, + 0.3498162031, 0.6293475628, -0.2722138464, -3.0948634148, 0.9942316413, 0.7735679746, -0.2930199504, 0.3510787189, + -0.7872864008, 0.3636801541, -1.6712719202, -0.5944473147, -0.7780117393, -0.084328346, -1.4538215399, 1.6016918421, + -0.7877728939, -0.3877354562, -0.1187206879, -0.0575074181, 0.7608479857, -0.7298144102, -0.8270982504, 1.1454995871, + 0.9177365899, 2.6103880405, 0.0275212266, 0.3144996762, -0.1462692618, -0.9897634387, -0.5029512048, 0.6674743891, + 2.3210890293, 1.0447092056, -0.4356173873, 0.718896389, 0.3660807908, -1.3855001926, 0.8256156445, -2.0150454044, + 1.1064456701, -0.6010576487, 1.2496664524, 0.1507250816, 0.648619771, 1.2184954882, -0.1510147303, 2.0641293526, + -1.449816823, -2.0317718983, 1.2131361961, 0.8736751676, 0.111203596, 0.0250869896, -0.3772203326, -1.6222440004, + -0.5841495395, -0.4699107707, -1.3665386438, -0.2026459277, 1.0634649992, -1.0488432646, 0.2799955606, 0.5228345394, + 0.567697227, -0.7177141905, 0.834364295, -1.1448087692, 0.4393841922, 0.5103766918, 1.5104135275, 0.0295173712, + -0.824334383, -0.7828230262, -0.6596770883, 0.6153479815, -0.2708790898, -1.9587074518, -0.3796555698, 0.2415509522, + 0.5919256806, -1.1046775579, 0.1845662445, 0.2122246623, 0.6119584441, -0.3259581625, -0.3889915943, -0.7639250755, + 0.6078098416, -0.0667440817, -0.30670771, 0.5324385166, -0.4453656077, -1.1343411207, -0.5743299723, -0.2151301205, + -0.2456267476, 1.0301148891, 0.4816589355, 0.2701259255, 0.0924869999, -0.7086822987, 0.3224029541, -0.867482245, + 0.1477069706, -1.4585555792, -0.7812615037, 0.7472718358, -0.2691109478, -0.2376997769, -1.375187993, 1.082647562, + -0.4113312662, 0.2539284527, -0.1638429761, 1.3389561176, -1.0764062405, 0.550165832, 0.7915554047, 1.5759218931, + -0.6999486089, 2.9310317039, 0.1950336695, 0.4499127269, -0.5996899605, 1.44818151, 1.661687851, 1.1369335651, + 0.2755799592, -0.4852996469, 1.3345595598, 0.3228714168, -1.3306968212, -0.4727328718, -0.6471650004, -1.1132016182, + -0.0713217631, 0.356254369, -0.3879558742, -0.8892503381, -1.2379481792, 0.8939266205, 0.384852469, -0.0012620862, + -1.1376874447, 0.5002755523, -3.1173944473, -0.3279280066, -0.8613476753, -0.2599486709, -0.5934633017, -0.5903510451, + 0.8368667364, 1.4305448532, -1.0941609144, -1.2185326815, 1.2903679609, -0.1296792477, -0.4799862504, -0.5509805679, + 0.4149641097, -1.7689479589, -1.5645645857, 0.7041118741, 1.1712943316, -1.5331878662, 1.742655158, -0.9360130429, + -0.0077561252, 1.1543563604, -0.4171964824, 0.8241519928, -0.5553875566, -0.1821218431, 0.5545003414, -0.9405351281, + -0.7519527078, -0.1459754258, -1.12589252, -0.0645399243, -0.0919869691, 0.4392310381, -0.3822971284, 0.9538373351, + 2.58233881, -0.0202496629, -1.1847659349, -1.6862163544, -0.3795819581, -0.3198311329, 0.2588284314, 1.2887588739, + -0.1577174366, 0.3362316787, -0.3093566597, 2.0915386677, -0.133646965, -0.7076271772, -0.2241379768, -0.9879319668, + 0.3666142523, 0.5691226721, 0.820240736, -1.743991971, -0.5116857886, -2.328826189, 0.0181529243, -0.2852157354, + -0.6766232252, -0.6026852131, -0.2991698682, -1.4322966337, 0.4033516049, 0.4984943569, -0.6238273978, 0.651202023, + -0.1294459999, -0.256364584, -0.085073486, -1.6635020971, 0.1540960521, -1.0692788363, 1.2856413126, 1.388676405, + 1.2394807339, -0.3786866367, 0.0405688733, 0.0261330679, 0.7440382838, 1.1676402092, 0.9192047715, 0.3690302074, + 0.691814661, 1.0192283392, -1.1002117395, 1.5993460417, 0.0842537582, -0.2882339954, -1.664116025, -0.225485608, + 0.2086762488, 0.1024906188, 1.9029095173, -0.1601699591, -0.1618199199, 0.076127395, 0.7380160093, -1.0263552666, + 1.2613258362, 0.7727131248, -1.4276200533, 0.2427285612, 0.9233678579, -0.6908003688, 1.1374328136, -1.5583342314, + 0.3230153918, 0.5732840896, 0.5374802351, 0.0478959084, 0.6080489159, 1.9260646105, -0.124957785, 1.1183328629, + -0.2025958151, 0.9080084562, -2.0576729774, -1.0507560968, -1.0327750444, -0.2893113196, -0.5023987293, 0.6811234355, + -1.2514544725, 0.3200329244, -1.2652056217, 0.3359721005, -0.0252995491, -0.7358947992, 1.0601046085, 1.85169065, + 0.8605123758, -0.3745788634, 0.5313572884, -0.7876136899, -0.6817808747, -1.7882242203, 0.7149001956, -0.8047255874, + -0.2163498551, -2.728982687, 0.0985979512, 0.5790400505, 0.2990364432, -0.3108656704, 0.4906449318, -0.0220372509, + 0.315343082, -0.6366631985, 0.5582022667, -0.0725143254, 1.6017705202, 0.3281800449, 0.0548433438, -0.6032658815, + -0.0313083753, -0.6846083999, 0.8272629976, 0.3764564991, 1.2219976187, 0.342451185, -1.9520853758, 0.5699878931, + -0.2838295102, -1.2962739468, -0.352042377, -0.0343406647, -1.7270351648, -1.5421413183, 0.1779328436, -0.9161617756, + -0.4136451185, 1.1171588898, -0.4643569887, -2.5890705585, -0.0978169665, 0.7960562706, -0.8719828725, -0.5912626386, + 0.6984806061, -0.5227940679, 0.4376514256, -1.088471055, -0.2189821005, -0.1773026586, -0.2215059102, -0.3727942407, + -1.6285271645, -0.90068537, 0.0758861899, 0.5086434484, 0.3348540664, -1.3667118549, 1.299120307, -0.4577853084, + 0.2003161907, -0.0515099727, -0.8061420918, 1.6344506741, 0.0430850051, 0.3335125148, 0.4028064907, -0.2435404509, + 1.12550354, -0.3624939919, 1.339214921, -1.1797457933, 0.3497534692, 1.7610549927, 1.1116669178, -0.1403288543, + 0.5325508118, -0.473656714, -1.1872699261, -0.8908538818, 0.5292066336, -0.6279459596, 1.1363736391, 0.0741886124, + -0.061268542, 1.8719406128, -0.7305373549, -0.7488399744, 1.4618368149, 1.0680894852, -0.5133447647, 0.3789470494, + 0.6920509338, -0.0438605398, 0.6057320237, 2.3371551037, 1.6273084879, 0.4970181286, 0.1759300977, -0.4805933237, + 2.0895617008, 0.2881127298, 0.14097175, -0.9227795601, 0.234462142, 0.1607084423, -1.3211661577, 0.2385593355, + -0.5965131521, -1.2087808847, 0.2794382572, 0.1888812184, 1.9271669388, -0.6863006949, -0.7454478145, 1.3094059229, + 0.087384291, -1.5320618153, 0.568331778, -1.1412267685, -0.0090721669, 0.4966467023, -0.9476978183, 0.3827875555, + -0.1609680057, 0.6752560735, -0.7131679058, 1.4439325333, 0.827676177, 0.4239243269, 0.0850653648, 0.4328988194, + -0.4906337261, 0.0462160818, -0.0169979334, 0.731513083, -2.473181963, -0.3385759592, 0.8918678761, -0.3003723025, + 1.4887953997, -0.5745051503, 0.1477561146, 0.9416487217, -3.4703557491, -0.5359448791, 0.7355026603, 1.0419493914, + 0.2170319855, -1.0533621311, -1.3572306633, 0.2210417986, -0.2556262016, 0.8509920835, 1.1125905514, 1.2063499689, + 1.5522272587, -1.2215622663, -1.2061839104, -1.2950669527, 0.202515319, 0.8298991323, -1.6604008675, 0.6038448215, + -1.3068019152, -0.0830953941, -0.1207791269, 0.1019082442, -0.4354915023, 1.0499731302, 2.1721775532, 0.8277935386, + -0.8255026937, -0.3824424446, -0.6085035801, 0.4934102297, -0.3934786618, -0.3122988045, -0.6388264894, -0.4257539213, + 0.198328808, 0.178788498, -0.6914410591, 0.3757758439, 0.3676111102, 0.0018327866, -0.3925342262, 0.007220618, + -0.7803044915, 0.7397019863, -0.3460148573, 0.6108574271, -0.1799765527, -0.5952509642, 1.7402403355, 1.2058306932, + -1.7820718288, -0.4921284318, -0.1624327749, -0.4435231984, -0.9929452538, -0.2207475901, 0.940410912, 0.5551370382, + -0.2299775779, -1.3604174852, 0.6192497611, -0.1024679542, 1.5234620571, -1.3118313551, -0.4637701213, -0.3026833534, + -0.6559758782, 0.7063180208, -0.1408954412, -0.2510201633, 0.9387018085, -1.2084950209, 0.9204330444, 1.0249712467, + -1.1086518764, -0.62194556, 1.0969376564, -0.9379596114, -0.8758180141, 0.6695581079, 0.4155954719, 0.1114221439, + -1.5905003548, -0.6057395339, 1.1781516075, 0.5552685857, 0.0532497801, -0.8565030098, -0.0965542048, 0.4256413877, + 0.5131956935, 0.71272403, -0.9340515137, -0.2032660544, -0.7067037225, 0.8651694655, 0.427988261, 0.0549685322, + -0.3155857027, 0.9081064463, -0.7040295601, 0.54886657, -0.7164933681, 0.645773232, -1.0947531462, 0.569427371, + 0.2458718419, -0.9906666875, 0.2122940868, -0.1173533797, -0.4974184334, -0.6052320004, -1.2996211052, 1.6052107811, + 0.016700767, -0.8896363974, -0.1235675514, 1.2180057764, -1.2930305004, -0.0934745148, -0.866370976, 0.5964619517, + 0.0963961259, 0.7674152851, 0.8012778759, 0.5961014032, 1.0097689629, -0.7147139311, -0.874930501, -0.6941998005, + 0.9761347175, -0.4838216305, 0.8083631992, 0.0955365077, -0.7880268097, -0.0426202081, 1.8439741135, 0.428255111, + -0.0741682723, 1.0584558249, -0.6867261529, 0.8829703331, 0.5617801547, 0.3434916139, 0.8344439864, 0.479727447, + -0.3557169139, -0.340008229, -1.2465457916, -0.0580307133, 0.3834264576, -0.2598493397, 0.3235251904, 1.4750258923, + 1.1747642756, 0.3843635023, -0.698595643, 1.5027586222, 1.4956634045, 0.8067368865, 0.1969479024, 0.0862167776, + 2.6182115078, 1.2178329229, 0.4351801872, -0.2157924771, 0.0267683528, -0.2018048316, -0.2664071023, 2.3273704052, + -0.2287864387, -1.287966013, -0.2599785924, -0.9273023009, 0.564144969, 0.7914847732, 0.9565588236, -0.8911844492, + -0.0868590698, 0.8247932792, 1.1331245899, -0.7190009356, -0.5144978166, -0.2154463977, 0.4985496998, 0.9098943472, + -0.2854295969, 1.0122947693, -1.0168125629, -1.7378758192, 1.9295582771, 0.2372324765, 1.4199649096, -1.4571065903, + 0.9987430573, 1.4982053041, -0.1646643132, -1.0409728289, 0.2996204197, -0.3438556194, 0.1763267219, -1.2381007671, + -0.5269424915, 1.0394705534, -0.5188234448, -2.2872128487, -0.8193461299, 0.7512777448, 0.5032290816, -0.2287727147, + 0.098364763, -1.3239839077, -0.3555992246, 0.3286261261, 0.3280561864, -0.0815626234, -1.0128548145, -0.6927438974, + 0.8964392543, 0.8159549236, -0.3390179276, -0.301546663, -1.4631524086, 0.449729383, 1.3367420435, 0.3859525323, + 0.7919450402, -0.7560143471, -0.4574146271, -1.0860054493, -2.2208795547, -1.6294802427, -0.0413829871, -0.242851764, + -0.4857134819, -1.166225791, -0.9579188824, 0.7621256113, 1.3296331167, 0.313836962, -0.4716928005, 0.6125260592, + 0.3406782746, 0.0522802398, 1.0202609301, -0.0340798423, -0.925927639, -1.2390106916, -1.5818425417, 1.156085372, + 1.09050107, 0.7594812512, -0.5976432562, -1.1142151356, 1.5844764709, -0.3622460365, -0.1226565912, -1.9871875048, + 1.4768576622, 0.2379653603, -0.9133228064, -0.7880818844, 0.923732698, 1.8276497126, 0.7280939817, -0.5917063951, + 1.3107105494, 0.7642640471, 0.8204598427, 0.5962021351, -0.3783559799, -0.4161889851, -1.4495459795, 0.0745454207, + -1.3453316689, 0.9977020025, -0.434227556, 1.0422127247, 1.1708983183, 0.4311306477, -0.6837021112, 2.1621861458, + -0.5827428102, 0.4477067292, -0.0211558007, 0.1824309528, 0.4264740944, 0.1203467995, 0.9909948707, -0.185976848, + -1.0240132809, -0.3639334142, -0.0936418921, 1.0512423515, 0.3733913898, 0.6839901805, -1.9282292128, 0.5622627139, + -1.209102869, -0.1106549725, -1.2581288815, 0.8361244202, -1.1004523039, -0.1258943379, -1.5989625454, 1.8102275133, + 0.4441590011, -0.5214574933, 0.9797497988, 1.2888114452, -0.8276115656, -0.0220992491, 2.4498775005, -1.8377934694, + -0.8514962792, 0.9489679933, -0.0830500126, -0.035930194, -0.1420495808, 1.0556294918, -0.5497905612, 1.0126923323, + -0.7473862171, 0.40529719, -1.0751425028, 0.1719949245, 0.3107260466, 0.4252511263, 1.0308989286, 2.1891362667, + -0.7951731682, -0.928825438, -0.8406194448, -0.5870738029, 1.4166525602, -0.0508782193, -0.5263801217, 1.7727472782, + 0.16188173, -1.6156774759, 0.9979695082, -1.5955677032, -0.1549735814, 1.277810812, 1.1898374557, 1.2261581421, + 0.1232592538, -0.4701025486, 0.8268409967, 1.4406825304, 2.0723600388, 0.6214050651, 0.1583388299, 1.0687154531, + 1.2600852251, -1.7723824978, 1.7461088896, 1.7796293497, 0.1533010453, -0.4502541423, 2.8840515614, -0.0278098118, + 0.2774529457, 1.235609889, 0.9059458971, 1.3719466925, -0.1427477598, -1.5313657522, -0.1988708526, 0.0918548554, + -0.7983700037, -0.7351155877, 0.0807933062, -1.1822363138, 0.4204095602, 1.6773831844, -0.6493386626, -1.381085515, + 1.8829346895, 2.238175869, -0.3106609285, 0.1599945575, 0.5009009242, 0.2571044564, -0.2493799925, 1.4916465282, + -0.0642954409, 0.1002008095, 0.0911449566, -0.2840108871, 0.0648470521, -0.5927429795, 0.6111506224, 0.2633831203, + 0.6087102294, -0.131420061, -1.9108045101, 0.3572774529, -0.2191513479, 0.4376700521, 1.1833018064, -0.8609423637, + -1.1047463417, -1.0791573524, 0.6086138487, 2.6700644493, -0.7331061959, -0.426273793, -0.6036394238, -0.7591724992, + 2.04926157, -0.4318020344, -0.4356160462, 0.4063673317, -0.0951606557, 0.1538648903, -0.7921331525, -0.5645645261, + 0.6250701547, 0.2017248124, 1.6619211435, -0.0490566455, 0.8955783844, 1.0819174051, -0.8749611974, -0.5747096539, + -1.3129776716, -0.8326802254, -0.5609090924, 1.6952314377, 1.0350174904, 1.0616799593, 0.9478091002, 1.2279448509, + -0.0191568751, -0.1780776232, -0.5881857872, -1.0479393005, 0.283336699, 1.5692890882, 0.014969497, -1.1679285765, + 0.6675914526, 0.2725379169, 0.5069898963, -0.8566572666, 0.2730761468, 0.7228215337, -0.7045961022, -0.8416188359, + 0.450838089, 0.1944348961, -0.4541225731, 0.7563244104, -0.113181971, 0.7128592134, 1.4402623177, 0.1528645456, + 1.0313960314, 0.6298319697, 1.2467131615, -1.108582139, -0.9003415704, -1.4343361855, 1.0231429338, 0.0072061568, + -1.8835331202, -0.7989682555, 1.0520348549, 0.3447473049, -2.5748610497, 1.67038095, 0.0138393026, 1.140909791, + -1.1738827229, 0.7495995164, 0.5710754991, -1.0748022795, -0.6461317539, -0.2453123629, 1.1448947191, 0.8853188753, + 0.7727425098, -0.0282142591, -0.1457471848, 2.4659855366, -0.7119729519, -0.1440470964, 0.3802301586, 0.0594930463, + -0.793320477, -1.5470353365, 0.990305841, -1.0986013412, 1.3785964251, -0.618201375, -0.2940633595, -1.6926203966, + 1.8205765486, -0.0862483159, 1.7647430897, -0.7206363082, -1.1045497656, -1.6156738997, -1.0962505341, 2.8444337845, + 0.5576008558, 1.6882987022, -1.1970424652, 0.451341331, 0.9049255848, 0.2253855616, -0.6835092306, 1.8480138779, + -1.3671431541, -1.0080400705, -0.992570281, 1.2446583509, -0.5805303454, -0.1164868474, -0.5888524652, 0.2782382667, + -1.0922057629, 0.9598587155, -1.089987278, -0.7082154155, 0.3065707684, -1.5383666754, 2.1593325138, -0.5230810642, + 1.0688405037, 0.5502248406, 0.2891297638, 0.3945007026, -0.7157661915, -1.4161725044, 0.5869718194, 0.1101675332, + -0.9291577339, 0.9818926454, -0.27811113, -1.0967657566, 0.1139538214, 1.1031048298, 1.0086518526, 0.6278707981, + -0.1493199915, -0.4495257139, 0.2201409191, 0.4300591052, 1.2368929386, 0.6283149719, 2.0061483383, 0.7451803088, + -0.2425652146, -0.2525975406, 1.1054331064, -0.5970991254, 0.9908251166, 0.4830693007, -2.2409613132, -0.8885762095, + -0.0143143935, 1.0882319212, 0.2041956186, -0.9607824087, -1.1832842827, -0.3721539676, -0.3367851079, 0.2151497006, + 0.0878699198, -0.6686208844, -0.3243316412, -0.5673260689, 0.2042728662, -0.0433752351, -1.7372738123, -1.4927453995, + 0.2947275341, 1.8073326349, -2.2004306316, -0.1771846712, 0.5147547126, 1.0263893604, -0.3667627871, -0.3732538819, + -0.8672274947, -1.5185539722, 0.1291330457, -2.3146927357, -0.0381119587, -0.6768706441, -1.1104094982, 0.1284427047, + 0.5935358405, -1.7596523762, 1.6137292385, 1.4737104177, -0.3111882508, -1.140106082, 1.3278982639, -0.7087484002, + -0.5006707311, 0.9336168766, -1.228528142, 1.185261488, -0.6464233398, 0.3168686628, 1.0129629374, -0.9842917323, + -0.8322681189, 0.3770053089, 0.4055832326, -0.7535272837, -0.5763852, 1.2844207287, 0.2033589929, 1.0656037331, + -2.3893010616, 0.2218722403, 0.526931107, -0.5230823159, 0.2871558368, -0.6817102432, 1.0522680283, -2.2263123989, + -1.4442704916, -1.7066681385, -2.1534831524, -1.1033091545, 0.5186153054, 0.9830374122, -1.4134610891, 0.7257140875, + -0.3652280867, -0.8273479342, -0.012344094, -0.7055724263, -0.0065825772, -1.4281263351, 1.0454120636, 2.1973111629, + 2.1394906044, -0.2185653597, -0.7726922631, 0.0578657836, -0.1241003796, 1.3615926504, -0.4700821936, 0.6276119947, + 0.7610633373, -0.3084032834, -1.5049169064, 1.1694749594, -0.3002104461, -1.7592983246, -0.7689751983, -0.6482440233, + -1.394374609, -0.668535769, -0.2740963697, -0.1009262577, 1.3430944681, -0.9573187232, -0.4756442606, -0.1120443791, + 0.4514842033, -0.1808938533, 0.0360276587, 0.7046375275, 0.5217391253, 0.176985085, -0.3516299427, -2.1484513283, + 1.0110119581, -2.1996293068, 0.8975638151, -1.2163029909, -1.0508220196, 0.6954064369, -1.2345478535, 0.6365551353, + -0.1546197087, 0.5181404352, -1.811375618, -0.5626225471, -1.3982005119, -0.450592041, -0.2327025235, -0.0388276242, + 1.5718796253, -1.1048280001, -0.1993524432, 0.4389081597, 0.7646227479, -0.5730227828, -0.5616265535, -0.32967484, + -0.7627649307, 1.8219025135, 1.0186827183, -0.7380231023, -0.8434823751, -0.6264718771, 0.7264119387, -0.5833688974, + -1.6604254246, 0.0730206072, -2.4509689808, -0.5503947735, 0.6281988621, 0.3269348443, 0.092516534, -0.4955527484, + -0.2733169198, -0.5889083147, 1.7769594193, -1.1998845339, -1.7700980902, -0.8073721528, 0.0494673774, -0.8524341583, + -3.218716383, 0.5676971078, -2.2943770885, -0.157933116, -0.795648694, 2.0401656628, -0.1461989731, 2.1896297932, + 1.5324863195, -0.5835031867, -1.5549209118, -0.4209410548, -0.0279977787, -0.0782606602, -0.7426626682, 0.0121981045, + -1.5553230047, 0.5819070339, 0.0326453373, 0.6056950092, -0.4712967277, 0.4049454927, -2.1062376499, -1.1619187593, + -1.2910219431, -0.6611953378, -0.43653211, 1.7293006182, 0.4786488712, -0.2935953736, -0.4926992655, 0.7536605597, + -0.3894644082, -0.7081032395, 1.0595657825, -1.0791609287, -2.6619422436, -1.6152977943, -1.1396865845, -1.2950086594, + -1.2873415947, -0.1941757053, 0.5377328396, 0.8336847425, 1.3057926893, 0.7935741544, -1.1920603514, -1.2580881119, + -0.1752467602, 1.4270538092, 0.353110522, -0.2798886299, 0.2382898629, 0.5952281952, -1.3373407125, -1.5224821568, + 0.6214637756, 1.1671440601, 0.1557538509, -1.3565181494, 1.1534074545, 0.0552476197, 0.8227424026, -0.2473755926, + 1.7100614309, -0.6010099053, 0.0952295437, 0.7519122362, 0.6125386953, -0.1340970695, -0.2649757266, 1.2478978634, + 1.3848875761, 0.235185802, -0.7321636677, -0.7952386737, 0.4714525342, -0.7676478624, 1.6104269028, 1.1910309792, + 1.6014332771, 0.8937367201, -0.50939852, 0.7270994186, 0.1354524046, 1.1415119171, -2.6321196556, -1.849526763, + -0.5692487955, -1.5690562725, -0.2997058034, 0.9866194129, -0.0548178814, 0.1174306124, -0.1186611429, -1.4897632599, + -0.0651347712, 1.4272356033, 0.8654854298, 0.3896121979, 0.0904301852, 0.0244684536, 0.9569140673, 0.5948505998, + -0.6984776258, -0.2093743682, -0.1100684255, -0.435618639, 0.9230844378, -0.0802567452, 1.0543168783, 0.8095011711, + -0.9505899549, 1.5887154341, 0.9821254015, -0.4611521661, -1.1893174648, 1.1560828686, 2.1422307491, -0.3830331862, + 0.2881630659, -1.006962657, 0.9505732656, -0.6370865703, -0.5005722046, -0.5218068361, 0.0570890643, 2.1391377449, + -0.3942484856, -0.0125554344, -1.0029050112, -1.6481519938, -1.3115295172, -0.6975313425, 1.4723504782, -0.5125975609, + -0.7702323794, -0.043054726, -0.0723921731, 0.3706169128, 0.981136024, 0.0741774514, -1.2132822275, -3.3102068901, + 0.2480957657, 0.1500856727, -1.3044787645, -0.7662258148, -0.5189638138, -0.7032186985, 2.0692028999, -0.4092837572, + -1.9459711313, -1.0947782993, -0.8841983676, -0.0839635059, -0.8565853834, 0.7222669721, 1.4330573082, 2.0029449463, + 0.6141778827, 0.4747509956, -0.5246588588, -1.0898851156, 1.2181375027, -0.7382065654, -1.0789153576, -0.4607920051, + -1.2100571394, -1.8802586794, 0.2697679102, -0.0484813824, -1.1286646128, -0.075433597, -0.4993629456, -0.9535911083, + -1.2571040392, -0.3249886036, -1.7524542809, 0.1891974956, 0.5681154728, -0.1350892484, -0.1838773489, -1.8538595438, + 2.162504673, 1.080447793, 0.8050185442, 0.0583708286, -0.8403818011, 0.4379777312, 0.2320236266, -0.5907236934, + 0.5305605531, -0.23558788, 0.8831157684, -0.3832046986, 0.1206885651, -0.2441270649, 1.465282917, 0.1251680106, + 1.6854983568, -0.5830694437, -0.8190350533, 1.2951843739, 1.1042377949, 2.4435899258, 0.6359903216, 1.0345590115, + 0.0918972865, 1.2627774477, 0.6608592868, -2.090031147, 0.3947992027, 1.163738966, -0.5153884292, -0.8478496671, + 1.4432096481, -1.4082688093, -0.2457654625, 0.312525183, 0.492485702, -0.045840174, 1.0880835056, 2.3190202713, + -1.3728237152, 0.9819077253, 1.4168225527, -0.8269272447, -3.1057460308, -0.2784600556, 0.0084761279, 1.1402667761, + -0.1192869022, -1.1153726578, 0.4603817463, -0.4175572991, 0.5515987873, -0.8892507553, -0.9335702062, 0.1421700418, + 0.8622007966, -0.1144793853, 0.7831965089, -0.8715204, -0.0539018773, 0.7396158576, -0.2736086249, 0.1636993736, + -0.3604790866, 0.6992456913, -0.4008758366, -0.5472824574, -1.3291764259, -1.1045629978, 1.3297357559, -0.8264792562, + -0.6032384038, 0.1439969242, -1.2441627979, 0.7882626057, 0.2286830693, 0.4731123149, 1.1700091362, 0.3139848411, + -0.3568086028, 0.3434693217, -0.7872848511, 0.123797752, -0.9416929483, 0.4094843268, -2.0613017082, 0.8186947703, + 0.279930532, 1.6776723862, -0.9916943312, -0.6852881312, 0.876049757, 0.3148263097, 0.6045241356, -0.8686185479, + -0.6712832451, 0.0449492224, 0.1750403196, -2.0695581436, 0.2488401681, -0.4023043811, -1.9713195562, 0.9366938472, + 0.397397846, -0.8258979321, 0.259359926, -0.4171347618, -2.0138168335, -0.2195019126, 1.3088977337, -1.0805025101, + -1.2335897684, 1.7145081758, -0.7687286735, -1.5577871799, -0.7377884388, -1.090277195, 1.3249225616, -0.0432096124, + -1.5101686716, -1.4007518291, -0.003004944, 0.5537450314, 1.1865566969, -0.5845212936, 1.2676486969, 0.6573771834, + 0.4485799372, -1.3348814249, -0.2957971096, 0.7416982651, -1.2257262468, 1.2528117895, -1.4885023832, 0.5322642922, + -0.601911068, -1.2413516045, 0.3678843975, 0.5308324695, -0.1434124857, -0.019594783, -0.3229777813, 0.5714412928, + 1.252753973, -0.1473772079, -0.0419942997, 0.0068792035, 0.9574351311, -0.2035091221, -0.0903420448, -0.3691366613, + -0.5072920918, -0.5398548245, -1.3546386957, -0.628228724, 0.5655155778, -0.5688884854, -1.9287480116, 1.2996890545, + -1.3261818886, 0.2849215567, 0.6106883883, -0.1060630158, -0.4809936285, 0.034017358, -0.9125748277, 0.7783385515, + -0.1310227066, 1.2201029062, -0.3814059794, 1.3374848366, -1.2288342714, -0.1551678479, 1.0072926283, -0.6144304872, + 0.0839847699, -0.646237433, -0.0756285638, 0.7238970995, 0.2455556691, -1.412224412, -1.884319067, 0.2838617563, + 1.0761822462, 0.2097860724, -2.2004213333, 1.275483489, -0.4360707998, 0.8155106902, -0.0288391188, -1.7672243118, + 0.2476938218, 1.0521885157, 0.719145, -1.6686151028, 0.0634164885, -0.3962253332, -0.9131394625, -0.3257185817, + 0.9493992329, -0.1860646755, 0.4772316515, 0.7308128476, -0.3646406233, -0.1680960655, -0.6723977923, 1.857922554, + 0.3541227877, 1.3605973721, 0.8575440645, -1.5376170874, 1.1852170229, -0.8388038278, 0.6530769467, -0.5707948208, + 0.1520410031, -0.5276001096, -0.6008660197, -0.7531970143, -0.1710914224, -0.0899885967, 0.5186805725, 1.0073469877, + 1.0555337667, -0.9564317465, 1.0060201883, -0.3865070343, -0.2376815975, -0.2118640542, 0.9394926429, 0.6976744533, + -0.2015943229, -0.9899131656, 0.5405406356, 0.8071326613, -2.0545885563, 0.4489324391, -0.715929389, 0.7658372521, + 0.8533259034, -0.295191884, 0.5808369517, 0.2168655097, -0.5482198596, 0.3273206055, -1.5042330027, -0.4117659926, + 0.0382566266, 1.1967242956, -0.8289934397, -0.560023129, 1.0414994955, -0.1932150424, 0.0411262065, -0.4130541384, + -2.04251647, 0.2735721767, -1.5550554991, -0.7226807475, 0.7977443933, 0.1485011876, 0.9446786046, -0.4927309155, + 0.6173900962, -0.3243460059, 1.2881433964, 2.2453174591, -1.1089458466, 0.6956653595, -0.9906356335, -0.0505813882, + 0.3978154063, -0.9886980057, -0.2622124255, 0.0275835395, -0.3144522607, 0.932692647, -0.3414547145, 0.4837387204, + -0.2374359816, 0.3685643673, -0.896337688, 0.6249161959, -0.2738130987, -1.0066910982, 0.5856098533, -0.2894586325, + -0.0821105018, -0.3100988269, -0.4248235822, 0.2665741146, -1.7740272284, -0.1976617873, 2.3445346355, -0.7961371541, + 0.3188365102, 0.3922545314, -2.0804495811, -0.6469821334, 0.750434041, 1.1765389442, 0.9240966439, -0.3588912785, + 1.2186727524, 1.124506712, -1.769438386, -1.4732788801, -0.2784310579, 1.3830229044, 0.1213222444, -1.1693680286, + -0.7890093923, 0.2241205424, 0.004344244, 1.6878660917, -0.1504489183, -0.2639863193, -0.0475605465, 0.4061010182, + 0.6480402946, 0.9678143263, 0.884244442, -0.2457452416, 0.9848177433, 0.4075931609, -0.6050483584, -2.1982643604, + -0.9470968246, 0.6483018994, -0.9678875804, -1.0634075403, 0.1625384986, 1.2762326002, -0.8872547746, 0.1652131081, + 0.5170665979, -0.0231691115, 0.6141547561, 0.3632443547, 1.0437520742, -0.40992257, -1.5331041813, -0.1598736197, + -0.8773027062, 1.136456728, -1.703494668, 0.9508250356, 0.0975447968, -0.6070606709, 1.7351464033, 0.4743512869, + 1.2093871832, 1.2255852222, -1.2209358215, -2.1459023952, -0.5637799501, -1.3911374807, 0.4593183398, 0.5979510546, + 0.4527249634, -0.0445172526, -1.0204105377, 0.6146193743, 0.1513276845, -0.504630506, 1.2186865807, 1.6874295473, + 1.6179510355, 1.0376192331, -0.094381921, 2.20982337, -0.5462614894, -0.8779112697, 1.2222505808, 1.2055162191, + -1.5389888287, 1.5902979374, -0.4417829216, 1.7803531885, -0.5176959634, 1.8613972664, 0.7545554042, 0.6129772067, + 0.446842432, 0.9953684211, -1.3956910372, 2.0089464188, -0.4462093711, 1.578414917, 0.3510382175, -0.0703873858, + 0.2534176111, -0.1998426467, -0.8111057281, 0.3384461999, 0.6583834887, 0.8084661365, -0.990370512, 0.4196079671, + 0.3588507473, -0.564098835, -0.1225297973, 0.2798833847, 2.6040446758, -1.2985949516, 1.3740561008, -0.1327347904, + -0.347810477, 0.6357547045, -0.8267017603, -0.0101069696, 1.1574569941, -0.589189291, -1.2464402914, -0.3473787606, + 0.3087954521, 0.2835386992, -0.4206701517, 0.2591592669, -1.2195488214, -0.1933093965, -0.5647271276, -0.8968281746, + 0.1931795776, 1.3121608496, 0.0971596316, 0.9895777106, -0.4723748267, -0.5463014245, 0.0892185643, -0.0195480473, + 1.8247439861, 1.5372071266, 0.0110428948, 1.2742878199, -0.2674755454, -0.3730522692, -1.5067985058, 0.4618104398, + -0.1699099392, 0.7135494947, 0.6154643297, 0.4335562885, -0.2648655772, -0.051324442, 0.5973302722, 2.1014957428, + 0.2783280611, -0.5136555433, -0.7486355305, -1.0634144545, -0.532333076, -1.5201735497, 0.5931404233, 0.4664847553, + -1.2523989677, 0.602750361, 0.0915953219, -1.3840013742, -0.8534832597, -0.3615029752, -2.4294033051, 0.1112238094, + 0.017202789, -0.2286780924, -0.8285278082, 2.2321007252, 1.968764782, 0.2778130472, 0.5375308394, -0.8006395698, + 0.2198387384, -0.3095584214, 0.8869483471, -2.8386275768, -0.9168944955, 1.2239718437, -1.0722330809, -0.5158202052, + 0.6645996571, 0.8560354114, 0.1393965185, 0.9551382661, 0.4548152685, -1.9653131962, 0.8772224784, -0.2593773305, + -1.1952117682, -0.3621657491, 0.0389585756, 1.1604454517, -1.0822688341, 0.5837280154, 0.5754579306, -0.5814859867, + -0.2461313754, 0.0065278327, 0.4200200737, -1.5244244337, -0.2629826665, 1.311732769, 2.0171401501, -0.8675763011, + 0.2327602357, 0.1637782604, 0.4368565083, 0.9518216848, -0.7166954875, -0.9328627586, 0.8369590044, 0.3547633886, + 0.1785100549, -0.0237964932, 0.8859897852, -0.6042553782, -0.3762065172, -1.6474996805, -0.3082104325, 1.0396336317, + -1.5162066221, -0.906773448, -1.0850670338, 1.2581267357, -0.2214823216, -0.8220285177, 0.4123277068, 0.7663524747, + -0.8339322209, 0.6646717787, -1.0077667236, -0.564473629, -0.9657685161, -0.0941603929, 0.4566901326, 0.3407334983, + -0.7013095617, 1.0366376638, -0.1873145849, -0.3645239472, -0.5983661413, -0.0358053558, 0.9808912277, -0.3805266619, + 2.4766175747, 0.9397842288, 0.6496300101, 0.0903372765, 0.1319412291, -0.3573524952, 0.7131528258, 0.7749145627, + 1.8421769142, -1.1503663063, 1.0779078007, 2.4074707031, -1.2194875479, 2.3397269249, -1.4365357161, 0.403811723, + 0.2114246339, -0.7000735402, 1.7133610249, -1.6811267138, -1.3434336185, 0.3275044262, -0.9965205193, 0.6525971889, + 0.1109063923, 0.5218975544, -0.2513494194, -0.1506602168, -1.067571044, 0.7060869336, -0.293902874, 0.7074757814, + -0.1937825084, 1.8526563644, -0.6828480363, 0.1911466569, 0.1817938238, -0.8393192887, -1.2712761164, -0.2967023253, + -1.5580698252, 1.0618728399, -0.732779026, -0.045339983, 0.723189652, 0.2260579467, 0.0045189788, -0.0292946324, + -1.5553299189, 0.3317606151, 0.7949090004, 0.6328572035, 0.4006032944, 2.1425490379, -0.6258561015, -1.3994067907, + -0.5250332952, -0.5599845052, 1.0373660326, 0.8478179574, 0.0953366831, -0.6932147741, -1.3818480968, 1.0562552214, + -0.4130301178, -0.1007573754, -0.6099736094, 0.2333106846, 0.9275327921, -0.7962839007, -0.6180340648, -1.5996370316, + 1.8704158068, 0.8759252429, 1.3884956837, 2.4303166866, 0.4895366132, 1.3197805882, -0.1183772013, -0.136992082, + 1.3485703468, 0.6114919782, -0.0323543325, -0.6448656321, 1.203864336, 1.1820948124, -0.2048023045, 0.679046452, + 0.4966803193, 1.5222219229, -2.9318621159, 0.4659831226, -0.9096521735, -0.1747777015, -0.0647855178, -0.8331367373, + -1.5714011192, -0.2310294956, 0.4662609696, 1.365888238, -0.5742117167, 0.4292911887, 0.5996888876, -2.3400518894, + -1.5466567278, 0.760694325, -0.7578786016, -0.2359795421, -1.0300453901, 0.1930342764, 0.003607118, -0.0514582843, + -0.461661607, 1.7474654913, -1.259904027, 0.977851212, 0.371887058, 2.0573425293, 0.0001507712, -1.3301340342, + 1.2774391174, 1.6158695221, 0.9101704359, -0.3199186623, -0.4357638061, -1.6184130907, 0.4685378373, 0.718316853, + 0.1964053959, -0.0726887211, -1.1159377098, 0.520781517, -0.9250515699, -0.8146038651, 1.5330342054, -0.6654334664, + 1.2355058193, 1.2149068117, -0.8081433177, -0.1008972526, -2.6701030731, 0.1122501418, -0.156844452, 0.6637252569, + 0.8165430427, 0.2798295319, -0.7888636589, -1.4502432346, 0.2165211886, -1.3123550415, -0.0796058998, 0.9572609067, + -0.3779307306, 0.8503680825, 0.4904717207, 1.5245455503, 0.1286518425, -0.347715199, 0.2938793302, -0.6671968102, + -0.0250478294, -1.3159838915, -1.5637085438, 0.7293962836, -0.0600265227, 1.3219997883, -0.7478125095, 1.6180843115, + 0.7206456661, 1.0755368471, -0.6887121797, 1.2116334438, 0.1095357239, 1.8574286699, 0.5284230113, -1.0005639791, + -1.7658504248, 0.8115992546, 0.1519138515, -0.8634884953, 0.0946448296, -0.6255034208, -0.546133101, 1.1926347017, + 1.6944109201, 0.7403153777, -0.4044455886, 0.7798045874, 0.7493108511, 0.643138051, 0.1134475395, 0.2037412971, + 0.2755376995, 1.114153266, 0.9121242166, 1.5169768333, -0.9620696306, -1.9707722664, 0.8506955504, 0.3520783484, + 1.6420823336, 1.1664842367, 0.0395719223, 0.5504347086, -0.5065367222, -0.7530210018, -0.1424470097, 0.3533922434, + -0.5853402615, 0.204618752, -1.9142156839, 0.9022826552, -2.0429213047, -1.1913815737, 0.2445087582, 0.60970366, + 0.3708125651, -0.1089679971, -0.4501316845, 1.0040342808, -0.7449307442, 0.3174760342, 0.1585830599, 1.1094741821, + 0.2051526755, 0.2611257434, -0.9332591891, 0.5158112049, -0.0843781233, -0.5690991879, 0.9467744827, 1.3892228603, + -0.1915261894, -1.4694588184, -0.6829240918, 1.8040553331, 1.4982194901, -0.6782018542, -0.2488974929, 2.024797678, + 0.7601909637, 0.2023352534, -0.0089879557, -0.3011207283, 1.298383832, -0.6964088082, 1.2567225695, 1.4973249435, + -0.0151675921, 1.1256455183, 0.5787013173, -0.7115837336, 0.4392588437, 0.6161403656, -0.342659086, 0.4325609505, + -0.0037368375, -0.2693090141, -1.496006012, 1.1586462259, 0.7610878944, -0.5264061093, -0.7910407782, -0.3750860989, + -1.5029484034, 0.7323586345, -0.9829524159, -0.6052945852, 1.6173005104, -0.3960254788, -0.3167100251, 1.4021726847, + 0.1614335328, -1.7691595554, 0.4891624153, 1.7525867224, -0.6651031375, -0.2736934125, -1.5221942663, -1.3538130522, + 0.9329830408, 1.7201684713, -2.1362659931, 1.3983808756, 1.0712672472, 0.8699352741, 1.9718719721, 2.8391821384, + 1.1305669546, 0.162160933, -1.022364378, 0.1640578508, 0.3482623994, 0.0992343724, 0.9226043224, -0.5990541577, + -0.5642827153, -0.3903325796, 1.5199590921, 1.2961598635, 0.4010730088, -1.3141818047, 0.6916372776, 0.0341012813, + 0.253482163, -1.5459098816, 0.7012271285, -0.9198668599, -0.392231524, 0.571246326, 1.0828225613, -1.4264631271, + 1.8115274906, -1.2499611378, 0.8060184717, -0.5210914016, 0.265134424, -1.2977297306, -0.3151990473, -1.4129822254, + -0.3059104383, -1.2792009115, -1.3503084183, 0.3274895549, -0.896556139, 0.1319619566, 0.2559824288, -0.8015326262, + -0.8983778358, -0.8235607147, -0.4976842105, 0.9133901596, -0.9979527593, -0.0663572326, -0.1228386909, -0.3515924215, + -1.6459765434, -1.1646555662, -0.5235185623, -0.3147287667, 0.8435072899, 0.6037076712, 0.1352328509, -0.9873789549, + -1.3439757824, -0.5656504035, -0.7461355925, 0.1942629516, 0.4915701151, 0.9518358111, 0.365267992, -0.8218551874, + 0.0957542583, -0.4124514759, -0.3918253779, 1.0724167824, 0.150868848, -0.1930464804, -0.3708569407, -0.235188514, + 0.2533005774, 0.3928980827, 0.1800833941, -0.1871147901, 0.1421864182, 0.8545504808, -0.2546977401, 1.2093913555, + -0.0946916267, 0.4536883533, 1.8203556538, -1.4522353411, 1.0122228861, 0.3969878256, 0.8579048514, -2.4725697041, + -1.1170048714, -0.3419044316, 0.221052289, -0.0589853376, 2.0522193909, 1.3139799833, 0.0032415872, 0.9737606645, + -0.3109631836, 0.6522809863, 0.1454812586, 0.3584970832, -0.6686333418, 1.0057399273, -0.4018355012, 0.427154243, + 0.7752248645, 0.7583116293, -0.0558623113, 1.9829217196, -0.0791059658, -0.1452606767, 0.6852729917, 1.0473220348, + -0.4100103974, 0.8070753813, -0.5444563627, 0.5194547772, -0.7474954724, 0.0800675452, -0.4973312616, 0.7176632881, + 0.3519951701, 1.1283892393, 1.4414153099, 0.7251556516, -0.2250899971, 0.7314395308, -1.5019141436, -0.7311096787, + -1.1236633062, 1.5846997499, 0.3824317753, -0.8789307475, 1.9165765047, -1.2047196627, 1.9510960579, 0.1713950783, + 0.2518723309, -1.0073115826, 0.0976815745, -3.2116572857, 1.0625407696, 0.3055147827, -0.1818564683, 2.421040535, + 0.2135395557, 1.0038594007, 0.294498533, -0.1435895413, -1.9485757351, -0.3004073203, 0.4409326613, 0.6442545056, + 0.5157012939, -0.5109453201, -0.3380121291, 0.4624716043, 2.507755518, -1.0816066265, -1.3965083361, 0.6884524226, + 0.2567251027, 1.2027677298, 0.276132822, -1.8016265631, 0.4354678392, -0.4259582162, -1.4475284815, -0.4208916426, + 0.9427179694, 0.4259283841, 0.0079847854, 1.1683820486, 0.6213946342, 1.0260797739, -1.8386904001, 0.5446011424, + -2.1929266453, 0.3169703484, 0.1466955394, 0.2231619656, -0.5830193758, -0.9312384129, -0.4481034577, -0.4660280049, + 0.0486355685, -0.0424672253, 1.1460434198, 1.0676603317, 0.2260905653, 0.7005288601, 1.4022908211, 0.0001941096, + -0.383166939, -0.0770072937, -2.1831009388, -1.5603170395, 0.4208289385, -0.9125955701, -0.5532537699, 1.820012331, + 1.6134670973, 2.5783603191, -2.3645694256, -1.2364205122, -2.1010518074, -0.3773110211, 0.3891334534, -1.8309109211, + 0.1862813532, -0.5885137916, 0.5469305515, -1.2611180544, 0.271168232, -0.2295575142, -0.8624431491, -0.2658065259, + -0.5441913009, -0.6111053228, 0.3815867305, 2.4132184982, 0.2860789001, -0.9591971636, -0.2013577223, -0.2921943665, + -0.5352737308, 0.2526368499, 1.0676268339, -0.0170707032, -1.2185895443, -1.6883766651, -0.027959913, -0.472879678, + 0.4600687027, -2.1366546154, -0.6944203377, 0.4398227036, 0.8040372729, 0.69551301, -2.2377107143, -0.195551753, + -0.8615193367, 0.063470304, -0.3660758734, 0.134787187, 0.2589198947, 1.4126286507, 0.633615613, -0.7764823437, + 1.5431591272, -0.7278642654, 0.6717827916, -0.588329494, -0.9275021553, -0.5374195576, 1.4585071802, 0.4842028618, + 0.7848344445, 0.1956220865, -1.4329868555, 1.4823243618, 0.9601696134, 0.3370892107, 2.0254490376, -0.1215440184, + 0.3890198767, 0.9085683227, 2.1455557346, 2.4146547318, -0.295337081, -0.1564641893, -1.0599550009, 0.9626013637, + 0.0099062221, 2.0847289562, -0.6303656697, 1.372354269, -0.7465828061, 0.3475526869, -1.6720502377, 0.4044115543, + -0.0562933162, -1.5195279121, 0.7755575776, -0.8021618128, -0.2751158774, -0.7458245754, 0.195694074, -1.0238747597, + -0.9840406179, 1.0258538723, 2.017386198, 0.1315372139, -0.5138539672, -0.5669877529, 0.540658772, -0.3071814775, + -1.996768713, -0.4333548844, -1.9966330528, -0.4374782145, 1.7048588991, 0.3344865143, 0.3502452672, -1.5361242294, + -0.2268669605, -0.4311481118, 1.0138232708, -0.5507349372, 0.5594305992, 1.0659108162, 1.4947098494, -0.7976589203, + 1.118155241, 1.3706774712, 1.2994995117, -0.1372869313, -0.0259376168, -0.3461629748, 0.4131499827, 1.1723839045, + -0.2778978348, -0.5928153992, 0.0675194412, -0.8313975334, -1.1776564121, -0.4460479021, -0.6112349629, 0.4268786907, + 0.8870689869, -0.618989706, -0.1257660389, -0.9239557385, -1.8860009909, 1.1535906792, -0.8335864544, -0.6902356744, + -0.1756162494, -0.7561747432, 0.5024242997, 0.5363253355, 0.082406424, 0.2639508545, -0.6364569664, -0.376978755, + -0.4377987981, -0.5338432789, 0.5736504793, 0.2441345602, -0.9038761258, -0.6077290177, -1.3279690742, -0.4976146519, + -0.4994116426, 1.3304718733, 1.0966929197, -1.5022242069, -0.1590254903, 1.655092597, 0.757339716, 1.3145182133, + 1.0289083719, -1.094563365, -0.8774670362, 0.1911343187, -1.0744937658, -1.028118968, -0.4112767577, 1.8617081642, + 0.2614100873, -0.1120274514, -1.1018739939, -0.5599132776, -0.9639128447, 1.4452749491, -0.237934038, 0.0965326279, + 1.2240991592, -1.1137310266, -1.5898432732, -1.2747541666, -1.228556633, -0.2418234199, -0.5687929392, 0.678483665, + 2.7191262245, 1.0439400673, -0.5211651921, -0.1766644418, 0.221312955, -1.2737783194, -1.0919522047, 3.2457404137, + -0.5371184349, 1.0131412745, 1.3599733114, -0.1014137343, 0.9044458866, -1.504991889, 0.3647313118, -0.7347620726, + -0.793651998, -0.4339566827, -2.1577720642, 0.3033457994, 0.6737972498, 0.2448626608, 0.6937257648, 2.6209950447, + -1.6615227461, -0.8978943825, 0.3889890909, -0.4596033096, -0.7707110047, -0.1208278388, -0.5201724768, 1.3842766285, + -0.4282974005, 0.7007796168, -0.4204046428, 0.1363129318, 0.4809338152, -1.1034513712, -0.4319312572, 0.4005286396, + -0.6485356688, 0.2712681592, -0.7505175471, -1.4745311737, -1.1564862728, 0.5677739978, 0.6589148045, -0.8751621246, + 0.1891540736, -0.5418350697, 1.8105150461, 1.7355394363, 0.2601662576, 1.4141949415, -0.4384791851, -0.7842199802, + 0.437135309, 0.6943714023, -0.5380707979, 0.4983506203, -0.5410212874, -1.1434106827, 0.9545881748, 1.3708180189, + 0.5112654567, -0.2825934291, 0.8243518472, -0.3324177563, -0.9993035197, -1.6045049429, -1.7449423075, -0.8640743494, + 1.4113116264, 0.3710772991, -0.3376179934, 0.5454092026, -0.9610939026, -0.6323919296, -0.3632386029, -0.7752295732, + 1.8468760252, -0.0391475186, 0.0493343733, -0.503307879, -0.4727648795, -0.5759646893, -0.1179095358, 0.1768748015, + -0.0848587006, 0.9794515967, -1.009221673, 1.5041515827, -0.2412413508, -0.3741708994, -1.3928172588, -0.1496126205, + 0.8959793448, -2.1168699265, -0.1839516461, -1.0776592493, -0.842291832, -0.2578078508, 0.7120755315, 0.5457919836, + 1.2602188587, -1.3638870716, 0.3252347112, 0.3103461266, -0.6843565702, -0.8641714454, -1.3515841961, -1.370978713, + 0.8442222476, 0.6913160682, 1.1721013784, -3.0055868626, 0.1678446978, 0.1083558276, -0.1259460449, -1.4384572506, + -0.4379824996, 0.6088418961, 0.3323244452, 0.1043943688, 0.0842534676, -0.7801011801, -1.071344614, -0.5946297646, + -0.0363405943, 0.6251944304, 0.8738729358, 0.841757834, -0.1302471012, -1.7174865007, 0.8975894451, 0.7157564163, + 0.7714152336, -1.2969895601, 0.2700895965, 0.6959099174, -0.758992672, -0.1790614128, -1.4486862421, -0.0582850389, + 3.2882657051, -1.0190426111, -0.2596707344, 1.2057558298, -0.9189699888, 2.0075521469, -0.6953464746, 0.5769160986, + 1.0798561573, 0.336289078, -0.9042438269, -0.6373935342, -1.2408188581, 0.5856894851, -0.6166279912, -1.0748144388, + -1.1937690973, 0.2725262344, 1.7097991705, 1.2231884003, -0.1864460707, -0.3886844814, -1.1401408911, 1.1001895666, + 0.0698222071, -0.8169481754, -0.2381762117, -1.0990309715, 0.0363042206, -1.0470657349, 0.5295069218, -0.8829963803, + 0.69883883, 0.0920695812, 0.2125919312, 0.203526929, 0.450448066, 0.523838222, -0.4745627046, -2.6972100735, + -1.2137219906, 0.8994110823, -0.5333787799, -0.2330003232, 1.0217889547, 0.1832010299, -0.1263355166, 0.6309781075, + -0.9253399968, 0.192734763, -1.19835639, 2.1006891727, -0.6179254055, -0.729115665, 1.511148572, -0.9217118025, + -1.3076606989, 1.3268530369, -0.0251848493, 0.7743625641, 0.3491370082, -0.278240025, 1.5292787552, -0.9830396771, + 0.0843514204, -0.6756237745, 0.493200779, 1.2645338774, 0.4777994752, 0.4024190307, -0.4145161808, -1.9489889145, + -1.147649169, 0.6487477422, -0.5789185166, 0.508746326, 0.6426893473, 1.1313562393, -0.1236293092, -1.0429756641, + -0.1709813625, -0.0481598303, 0.7611688972, 0.6133790016, 0.3980072141, -0.2242967188, -1.012344718, -0.6344790459, + 0.9931277633, -0.533351481, 1.0943918228, 0.0513154417, -0.0190032981, 0.6046923399, 0.6036578417, -0.7517727017, + -0.5252866149, -1.1066845655, 0.9470067024, 0.0642272905, 0.5968157053, -0.2527898848, -1.1888705492, 0.5340593457, + -0.0894497484, 0.4148004949, 0.1358723789, -0.1815864891, 1.2741400003, -0.4312350452, -0.502040267, 0.1918521374, + -0.3785336614, 0.3328542411, -0.9043675065, -0.1148370057, 0.2523318231, 0.5270742178, -1.7881046534, 0.9077923894, + -0.6153175235, -0.8822738528, -0.8405439258, -0.0023670495, -0.435415417, 0.047702197, 0.8350443244, 1.4262235165, + 0.6257942915, -1.564479351, -1.2305992842, -1.1948616505, -0.3577411771, 0.9498245716, 1.3089897633, -0.1266740113, + -1.2482118607, -0.758569777, 0.3164147139, -1.6025328636, 1.4389153719, 0.8901625276, -2.9274833202, -1.3023848534, + -0.105739817, 0.1712914407, -0.9100197554, 0.9962213039, -0.380978018, -3.3738229275, 0.8629325628, -1.3146237135, + 0.6146615744, -0.700944066, 0.7499541044, 2.5462694168, 0.2149894536, -1.3944144249, -0.238954708, -1.4857633114, + 1.2554066181, -0.7945663929, 0.1306199729, -0.476900965, -0.295427978, -0.4177624583, 0.7645667791, 0.0706775561, + -0.0036673227, -0.1686885506, -1.287853837, 0.9614015222, 0.9980438352, 1.6333302259, 0.3764960468, -1.7786319256, + -0.1212472469, -0.5497505665, -1.6330521107, -1.0370134115, -1.8117271662, 0.1047022566, -1.6284438372, 0.1362413913, + -0.6433253288, 0.5122199059, 0.8732233047, -1.8397277594, 0.3793027401, -2.209107399, 0.1155540869, -0.2137276232, + 0.8290930986, 0.4650845826, -0.8942251801, 0.417822212, -0.6271676421, 0.0223560892, -0.9844577909, 0.535944581, + -1.5864883661, -0.5337475538, -0.0250616819, -1.2855857611, 0.8331471086, -1.4578803778, -1.2561945915, 0.7204806209, + 0.5493844748, 0.9813920856, 0.6658095717, 0.2176280916, 0.2478718907, -0.618752718, 1.7733623981, -1.0680766106, + 0.3115855157, 0.9599409699, -0.6318791509, -1.7253450155, -0.158196792, -0.284778744, 0.7510251999, 0.6722778082, + -0.5759375691, 0.3976946175, -0.2699123919, 1.14670825, 1.2894232273, -0.7950692773, -1.2313041687, 2.591853857, + 1.4108102322, -2.5290796757, -2.7064659595, 2.0493443012, -0.1575528234, 2.5390417576, -1.0978960991, 0.6092931628, + -1.7137644291, 1.3925527334, -0.0829210207, 0.9157499075, 0.2611907423, -0.5531715155, -0.2612552643, 0.1815842986, + -0.207478568, -1.3900825977, 0.0094462279, -0.5616672635, 0.6902035475, 0.3310068846, -0.4598512352, -0.3554174304, + 2.5179774761, 1.7027835846, 0.7137155533, -2.5243444443, -0.0778169781, -0.7383882999, -0.4915468097, -0.4458041489, + -0.1211165935, 1.6788327694, -0.5277331471, -0.6074772477, -0.1313184202, -2.0344195366, 0.6652619839, 1.1473989487, + -1.1869680882, -1.285836339, 0.6587207317, 1.9654532671, 0.709600389, -0.7670360804, 0.3632927835, 0.1158852875, + 0.6583322883, -0.1609952003, 0.1934109926, 0.3165058196, -0.5613026023, 0.1166221797, -1.3770916462, 1.3263069391, + 4.241771698, 0.0803468376, -0.2049070597, 1.5271331072, 1.3036043644, 0.5373516679, -1.9896894693, 0.5142652392, + 0.6343153715, 0.0603445619, 0.5120731592, 0.4221506715, -0.469676882, 0.0600340888, -0.4477773011, -0.0307193249, + 1.6819882393, 0.2639681995, 0.2140350789, 1.3125169277, -0.3825906217, 0.0022184977, 0.1268048286, 1.5481674671, + -0.546862185, -2.6106348038, -0.1282699555, -0.4177289009, -0.2894179821, 0.9866001606, -1.2609921694, -0.9886783957, + 0.7946244478, 0.8661491871, -0.4253971875, 0.5601807833, -0.7023891211, -0.5714130402, -1.4841006994, -1.3401839733, + 0.0336159281, -0.02440276, -0.134780854, 1.3022232056, -0.4897793531, 0.6417346597, -0.8937379718, 0.1637545079, + 0.2157087028, 0.5360102654, -0.127539143, 1.7299357653, 0.8968551755, -0.8804937601, -0.3912613988, 0.8144260049, + -0.4776334465, 0.0370308645, -0.5445691347, -1.5247189999, -1.0484591722, 1.0209940672, -0.0507922173, 1.0969961882, + 0.0081091505, -1.0735074282, -0.4637985229, 0.5490329266, 0.770765245, -0.9320597649, -0.5035763979, -0.357188344, + 0.2904200852, -0.1153651178, -2.441321373, 0.540378809, -0.8432013988, -0.7396709323, 0.1283033639, -1.476256609, + -2.9589779377, 1.3033297062, -0.2565463483, -0.3692474365, -1.177446723, 0.5953117013, -1.084980011, -0.5788462162, + -0.9446442127, -0.9873202443, 0.8887941837, 0.5191269517, -0.0704374313, -0.5656064749, -0.298774451, 0.4930670857, + -0.4615590572, -0.2847803533, 0.4016345441, -1.1605231762, -0.1913904548, -0.120280616, 0.2625747919, 1.4581007957, + -0.5056554079, 1.7628393173, -1.4981478453, -1.3307580948, 0.0612610243, 1.5295269489, -0.3462225795, 0.8649011254, + 0.4291520715, 0.4492061138, 1.0830732584, 0.1221628636, -1.0343058109, 0.3313332498, -1.0550051928, -0.3262061775, + -0.2889346778, 1.5725835562, -1.2517917156, 0.0634046644, 1.1232205629, -0.2517988682, -1.6302595139, -0.2371418178, + 1.7263067961, -0.7344884276, 1.6452118158, 0.2126683742, -1.0070602894, -1.1667169333, 0.1198763698, -0.1139037609, + -3.2478482723, 0.1158405244, 1.287324667, -0.2967154384, -1.9113676548, -0.3062439561, 0.2123287916, 0.7192662954, + 0.2661412656, 0.7092028856, 1.0256335735, 0.450099498, 1.9605486393, 0.0655291229, -0.6529865861, -0.1378134042, + -1.7298293114, -0.1140466258, -0.0287944637, -0.3820255995, -1.4283573627, -0.2104176134, 0.8270501494, 1.6666053534, + -0.2273907214, 0.4807750881, -1.1465576887, -0.7090556622, -1.8215582371, -0.1210410222, -0.3808588386, 0.0259706769, + 0.1462689787, 0.276687175, -1.3793306351, 0.2024340034, 0.4679293633, 0.7783885598, 0.2412308306, 1.4358551502, + -0.5162473917, -0.3459844589, 0.3041249514, -1.2383747101, -0.7322098017, 0.1910422891, 1.805924058, 0.9277132154, + -2.0171482563, 0.1951866299, 0.6639137268, 1.2373590469, 1.2164707184, 0.1519757211, 0.6530285478, 0.9477738738, + 0.2688260674, -1.25827384, -0.9600851536, 1.0390130281, -1.0648518801, -0.8012365699, -0.2251798809, 1.1142963171, + 0.9341740012, -0.4841320217, -0.0355923399, 0.3871592879, 0.5604581833, -0.4087530673, 2.0429780483, -0.4825588167, + -0.6649580002, 0.8005616665, -0.3599886, 0.1193309203, 2.4247162342, 1.1964256763, -0.0806443915, 1.5196145773, + -0.4052409232, -1.2675876617, -0.6781725287, 1.5818355083, -0.9401290417, -0.559127152, -0.6824262142, 0.4200727046, + -0.0844191387, -0.2632116973, 1.2377724648, -1.8268915415, -2.0282392502, -0.7599870563, 0.4133173823, -0.30045259, + 0.3071993589, -0.0633047372, 0.4281289279, -1.268329978, -0.4179551601, -0.3186133206, 1.1701862812, 0.9885575175, + -0.108087346, 0.2283486128, 0.3161881268, 0.6529545784, 0.7720674276, -0.1712777019, -0.0354263894, -0.210274592, + 1.9657728672, 1.0205694437, 1.4390608072, -0.5366148949, -0.7892500162, 1.9705640078, 0.3855912387, 0.062941432, + 0.626522541, 1.1438483, -0.9780292511, -0.6935688853, -0.9762239456, -1.4685491323, -1.4372947216, -1.0730566978, + 1.4005103111, 0.5869930983, 0.0406822041, -0.3796490729, -1.4310114384, -1.5541208982, -1.1360594034, 0.1388325095, + -2.1530423164, 0.1147642508, 0.0471051075, 0.3919199407, 0.7114022374, 1.1730850935, -1.3012977839, 0.3481751382, + 0.2530570626, 1.7267895937, 1.5392260551, -0.9095569253, -0.5668856502, -0.4846865833, -1.9252877235, 0.0159935709, + -0.2737687826, 0.8173170686, -1.459823966, 0.4550220966, -0.4915318787, 0.394744277, -1.4720059633, 1.1339253187, + 1.3018774986, 0.6073305607, -0.0294520799, -0.0245533902, 0.829985261, -0.2093410045, -0.8937062025, -0.2104247361, + 0.4905937016, 0.9270766973, -0.8489860892, 3.0901689529, -0.9478366971, -0.734703958, -0.0914564133, -0.1481568217, + 2.1250960827, -0.6915543675, -0.7773598433, 0.7704299688, -0.8429703712, 1.2658998966, 0.1026027575, -0.9573163986, + -1.08586061, 0.248424679, 1.5868668556, -0.5566447377, -1.2599195242, -1.3841241598, 1.1235691309, 1.7500667572, + 0.0562867485, -0.2367135286, -0.5502758026, 0.8646404743, 0.2884162962, 0.2858077288, 0.3000690043, -1.2110253572, + 1.433480382, 1.3211159706, 0.107760638, -0.5899074078, 1.2182687521, 0.9392931461, 1.7326339483, 0.6656506658, + 1.1504017115, 2.5321750641, -1.3975093365, 0.102698572, 0.079793632, -1.2145488262, -1.6663728952, 0.1640934795, + -0.7657446265, -0.9649801254, -0.2156695276, -0.3802717328, -0.0361323729, 2.2739071846, 0.5935225487, -0.7992947698, + 0.5043234825, -0.0635420382, 0.0635460094, -0.4986944795, -1.2183550596, 0.8497512937, 1.3682345152, 0.0592218079, + 1.817646265, 0.0380014367, -0.1648121178, -1.1811887026, 1.6452852488, -1.1771593094, 0.9260467887, -0.2866005898, + -0.3300427198, 1.053591013, -0.4557752013, 0.9618560672, 0.3766882122, -1.8635056019, 1.7812006474, -0.6835395694, + 0.2296070904, 0.0775303841, -1.5565257072, -0.9657327533, -0.1612064391, -0.9848763943, -0.7570252419, -0.5434094667, + 0.0870989487, -0.3932954669, -1.4176454544, -0.6030968428, -0.5313537717, -0.7281560302, 0.2537410855, 0.8596052527, + 0.5377355814, 0.0889668092, 0.6040338874, -0.8646016121, 0.4936359227, -1.3471070528, 0.1851646155, 0.5584734082, + 2.068308115, -0.6238692403, 2.4669466019, -1.0006500483, 0.4998898208, 0.5908782482, 0.1898878664, 0.9036785364, + -2.6795573235, -0.6285718679, -2.2651124001, -0.0100735221, 1.6246125698, 1.2570762634, 0.9649873972, 0.4480108619, + 0.3538306952, -0.6394305229, 0.6310080886, 0.2673046887, 1.3926157951, -0.5519245267, -0.6487637758, 0.6073168516, + -0.4114406705, 0.3761738241, -1.4606273174, -1.475922823, 1.7613903284, 1.2103283405, 0.6520544291, -0.0654612854, + -0.8724196553, 1.2886662483, -0.9957754016, -0.2996768653, -0.518242538, 1.1075606346, -1.5807965994, 0.161800161, + 0.024378825, -1.6595828533, -1.7371256351, 0.1204244867, -0.2156693637, -1.693784833, -1.0714200735, -0.2341331691, + -0.3915313184, 0.2276837975, 0.2442232966, 0.6898937821, 0.830057025, 1.6709381342, -1.4706568718, 0.66466856, + -0.718167007, -0.0028348088, 1.402259469, 2.1807963848, 0.6828091741, -2.4582383633, 1.12812078, -0.6115419865, + -1.121293664, -1.2312363386, -0.4915806353, 0.548778832, -0.4697555602, -0.2441457063, 0.4054579735, -2.1404464245, + 1.5693150759, -0.5173771977, -0.4552463293, 1.1641325951, -0.4407202303, 2.2006056309, 0.2322905511, 0.1107065305, + 0.2862088978, -0.2815102637, -0.3408988416, 0.2058108151, -0.199660629, 1.8439724445, 0.8755335808, -0.249684602, + 1.5357745886, 0.2453305572, 0.6203836203, 0.8212997913, 1.302516222, 0.1074199975, 0.8545994759, 2.0262827873, + 1.6857354641, -0.5158991218, -0.981493175, -2.5545742512, 0.5971880555, -1.2477747202, -0.8447640538, -0.271122545, + -0.1848308742, -0.6540018916, 0.2878918946, 0.3621478677, 0.6957350373, -1.6501054764, -1.1784461737, -0.8048467636, + 1.2036799192, -0.7421025038, 1.2379450798, 1.7582762241, -1.5390353203, 0.4638553858, -1.3758928776, 0.1921562254, + -0.2725992501, 2.1471478939, -1.2595988512, -0.3549736738, 0.2839905918, -0.1939975917, -0.0150380591, 0.9684531689, + -0.8801771998, -0.6602508426, 1.1853135824, -2.7470576763, 0.5793197155, -1.2005586624, 0.9979766607, 0.1249912754, + -0.7145936489, 0.0190785658, -0.0678644404, -1.1773444414, -1.3656818867, -0.9308581352, -1.5273888111, 0.6262164116, + -0.9275572896, 0.630723238, -0.3932364285, 0.367651701, 0.109542191, 0.4901863337, -1.3060173988, 1.4643207788, + 1.2106331587, 0.303393811, -0.7580705881, -0.7045764923, -0.2487854362, 0.7929059267, 0.2234160602, -1.1094235182, + 0.152346909, 0.6313382387, -0.3104008734, 1.2057654858, 1.2911474705, 0.1881976724, -0.0363846235, -0.6520819664, + 0.7624713182, 0.9030723572, 1.40127635, 0.980956912, -0.1520080268, -1.1902999878, 2.4968516827, 0.5791797638, + -0.5331690311, 1.884930253, 1.2531266212, -0.574162662, 0.6255322099, -1.2660032511, 0.0748630986, 1.6345337629, + 0.2266604304, 0.6084037423, -0.7702188492, 1.9156914949, 0.4047849774, -1.2006857395, -0.1776676178, -0.1083059758, + 1.7594144344, -0.1029189825, -0.5665433407, 0.6066942215, -0.5196262002, -0.2490082681, -0.9327793121, 0.3236896098, + -0.3677179217, -0.1818056256, -0.5839886069, -0.2038229257, -0.0597114004, 1.140239954, -0.0260799173, -0.6193695068, + -0.3960160315, -0.955229938, 0.6448193789, 1.4817017317, 1.5544289351, 0.9933441281, 0.4653750658, 0.3257007897, + 0.1263968647, 0.1049721017, 0.7257955074, -0.3700866103, -0.5341292024, 2.2867617607, 0.2005052119, -1.9354718924, + 0.8988186121, -0.0689575225, -0.6440743804, 0.5772926807, -0.454706341, 1.4799640179, 0.0647191256, -0.4898588955, + -0.8096262217, -1.0249881744, 1.6329885721, -1.0937043428, -0.6664443612, -0.2176919729, 1.8012778759, -0.9251882434, + -0.5116018653, -0.1121688411, -0.2361086607, 1.7645183802, -0.9666455984, -0.8906248212, 2.5078215599, -0.3365430832, + 1.4512392282, 0.2457870543, -0.7407913804, -0.5314186215, -0.2175210267, 1.616078496, 0.1030726433, -0.2955012023, + 0.393093884, 0.3691558838, -1.4468399286, 1.4991459846, 0.786123693, 1.4582768679, 1.0606905222, 1.4576917887, + 0.4594173431, 0.9900460839, 0.036754135, -0.0919883996, -0.4150067866, 1.1121563911, -1.899116993, -0.0029766932, + 0.9736584425, 0.5819031, -0.3772553504, -0.3100667, -0.2848064303, 0.2640193999, -0.3516303599, -0.4092839956, + -2.0935854912, -2.2584433556, 0.3784409761, 1.2266635895, -0.656645596, -0.0365018025, 0.3758405745, -1.1574118137, + -1.6608725786, 0.3360662758, -0.4174785316, 1.7872010469, -0.576220274, -0.9449684024, 0.1880954653, -1.2142983675, + -1.3987449408, -1.0537490845, 0.0820185915, -0.5293899179, -0.5560578704, -0.5497375131, 0.2450578064, 0.4957640767, + 0.8905921578, -0.9192040563, 0.5279426575, -0.0151319457, -0.3531607687, -1.6664785147, 0.586068511, -0.1222635657, + -0.4696131647, -0.8306789398, -1.721363306, 0.4148206413, -0.9287552238, 0.5041882396, 0.6945232153, -0.701837182, + -1.7570469379, 0.3231323659, 1.0354024172, 0.1899425387, 1.2799785137, 0.5467972755, 1.1144099236, -0.1551059335, + -0.8696814179, 0.6797798276, -2.4373333454, 0.6826940775, 0.5466501713, 0.849196136, 0.5381039381, -1.3631504774, + 0.6576964855, -1.6812366247, -0.1420921236, 0.0644702837, 0.356861949, -0.4917500317, 0.0291998181, 0.5068673491, + -1.1943705082, 1.3364574909, 0.0296131652, -1.1348272562, 0.3270067573, -0.7610291839, 0.1490225941, 0.1008909866, + -1.4996412992, -0.6174682379, -0.6078441739, 0.206440255, -0.894235909, -2.6421942711, -1.3883210421, 0.1245091781, + 0.6594743729, -1.2438187599, 0.7344162464, -0.3856297135, 1.3615497351, -0.6648976207, 0.1783328503, -0.0513411611, + -0.3603737056, 0.3984665871, -0.4077322781, 1.3554097414, 0.2356388569, -0.217421934, -0.1714425683, 0.4619775414, + 1.7577792406, -0.9965714812, 1.1256047487, -1.0318431854, 0.0069990228, 0.1054399237, -1.0228053331, -0.3113851845, + 0.8585723639, 0.2263864875, -0.6888257265, 1.6379286051, 0.7351904511, -1.3622685671, -1.4697754383, 0.6048600674, + -1.0446178913, -1.6048693657, -0.0697253868, 0.7481107712, -0.8034046292, 0.2074136585, -1.5064373016, 1.5586475134, + 0.0487470403, 0.274621278, 1.312395215, -0.0130932564, -0.5733627677, 0.108277373, -1.032479763, 1.4006639719, + 0.1419160068, -1.2351351976, 1.4697282314, -0.4961551726, 0.3234536946, 2.5705366135, 0.6191286445, 0.2001783103, + 1.8302137852, 1.4770355225, 1.280855298, -2.0362477303, -0.7708904147, -2.2161989212, -0.6043381095, 0.1801552922, + -1.8412429094, 0.2060479224, -0.2533358932, -0.8370944858, -0.7637611628, 0.3168261349, 0.5018517971, -0.2618725598, + 2.0702135563, 2.1030116081, -0.0092163961, -0.9284299612, 0.5606794357, -0.2881985605, -1.1079137325, -0.0594206415, + 0.230317384, 0.0974219963, -1.1072945595, 0.6925656199, -0.3535038233, -0.6043095589, 1.5273171663, 1.1504018307, + -1.569535017, -0.6234639883, 2.2262411118, 0.5078104138, 0.5744566321, 0.9775137901, -0.2812677026, -0.6070799828, + -0.6489948034, -0.2179257274, 0.9815560579, -1.8020489216, -1.393945694, 0.2427239269, -1.1940877438, 0.7539755106, + 0.2131537497, -0.9054090977, -0.9812750816, 0.237539053, -0.7263105512, -0.4075903893, 0.4848812819, 0.7323713899, + -0.2195205986, 0.7746742368, -0.5940266252, 0.5959823132, 1.502745986, 0.7207845449, -0.9153077602, 0.714464426, + -0.4492384791, -0.1792533398, 0.4524716139, -1.4900296926, 0.1651769876, -2.2085511684, 1.5511286259, 0.7659050822, + -0.324454397, -0.4670624137, 0.2195701599, 0.7060580254, -1.4186925888, -0.3362497389, -0.8520848751, 0.886744678, + 0.3390224874, 1.0442818403, -0.9417509437, -0.737760365, 0.0769798011, -0.7142660618, -0.7156736851, -0.1892230809, + -0.5361557007, -1.3213405609, 0.2317953408, -0.6825730801, 1.0135622025, 0.53093642, 0.2421779037, 0.4017920494, + -0.4618558586, 2.3104119301, 1.6827931404, -0.8894057274, -0.3898538053, 0.8753790259, -0.6747983098, 0.3014372587, + -0.6322235465, 0.0239859428, 0.9638617039, 0.9551012516, 0.7515984774, -0.0033408087, -0.9071614146, 0.3515233696, + 0.586515367, -0.2021835446, 0.4500505626, 0.9413334727, -0.5805366039, 1.7458322048, 0.0380769074, -0.0990866572, + -1.0987000465, 0.0226462241, 0.5436627865, 1.150097847, -0.444408685, 1.5100064278, -1.8368489742, -1.3223434687, + 1.0303223133, 0.6480669379, 0.4582530856, 0.7627970576, 0.1246709898, 1.7402290106, -1.6799961329, -0.5588530898, + 0.7539991736, -0.6544169188, 0.0672161505, -0.3272388577, 0.5595880747, 1.220200181, -0.3627043962, 0.8311170936, + 0.3439565897, -0.1743943244, 0.2378960103, -0.4759786129, 0.0559345298, -0.4318015277, 0.3085387945, 0.7614166737, + -0.675260663, 1.1796420813, 0.3769035339, -0.0317898244, 1.9001022577, 0.9514611959, -0.0556233376, 1.3591566086, + -1.2247810364, 0.1007181108, -0.7172840834, -2.5895702839, 0.4835788608, -0.9515837431, 0.4092848897, -0.5652714968, + 1.6664245129, 0.1597400755, 0.3711966276, -0.633865416, 2.0866260529, 0.5391490459, 0.1859727055, -0.5546110868, + -0.5572327971, -0.6505861282, -2.2647030354, 0.4426457882, 0.1652098149, -0.2662654519, -1.3499914408, -2.2734627724, + 0.5519658923, -0.0034194007, 0.3603643179, -0.247141555, -0.1274028271, -0.0114346435, -0.9155646563, 0.1687090397, + 1.8955256939, 0.2796881795, -0.5321885943, -0.7036546469, -3.1717319489, -0.783003211, 0.9552480578, -1.7417746782, + -1.4782881737, 0.207234323, -0.342202723, -0.000003918, -0.7132492065, 0.4970744252, 0.2872682214, -0.0240418799, + -0.0924070626, 0.2005609572, -0.2416967005, -0.4522222579, -0.7911132574, 1.1676659584, 1.0429853201, 0.4757418931, + 0.6947637796, -0.4414412677, -0.3858654201, -0.0315578692, -0.0620186105, 0.7743752599, 1.6831254959, -1.543410778, + 0.2417434901, -0.4039699435, 1.050511241, -0.0232733302, 2.446007967, 1.8306061029, -0.2217491418, -0.839137733, + 0.4859440923, -1.8701001406, 1.6040929556, -0.7600015998, 1.1947399378, 0.8387134075, 0.2391007692, -1.1038827896, + 1.5782461166, 1.1515152454, 0.8457059264, 0.5228255391, -0.7674822807, -0.2895836532, -0.6218723059, -0.5329485536, + 1.9727894068, -0.8545120358, -0.0130121699, -0.2113794982, 1.2866762877, 0.4343684018, -0.2603058219, 0.4808883667, + -0.7769899964, -0.2809680998, 0.6315764785, -0.2057825625, 0.6242778301, 0.3901982903, 0.5251529217, -0.3042872846, + 1.0285104513, 0.1606976837, 0.1045264378, 2.1321480274, -0.176521644, -1.4004218578, -0.4953492284, -0.317607671, + 1.2840528488, -0.0970956907, -1.2646052837, -2.8805596828, 1.0095061064, -1.6003195047, 1.3290346861, 0.185082823, + -0.4360282421, 0.7396296263, -0.9351475835, 0.3767962754, 1.6771639585, -0.7094474435, 0.6432923675, -0.29638502, + -0.9941192269, -0.4628743827, 0.8353748322, 0.6730687618, -0.1000754759, -1.0190597773, 1.696835041, 0.6228394508, + -0.8952073455, -0.7015125155, 1.4203540087, -0.0927628949, -0.2419510335, 1.0769065619, -1.0362827778, 0.058885362, + 0.4759929478, 0.1233649552, -0.89650172, 0.2282161117, -1.5211969614, 0.6221343875, 1.4138190746, -1.0571297407, + 0.7189363241, 0.6118679047, 1.3299641609, 0.8587504625, 0.0770226419, -1.5501102209, -0.6436623335, -0.1981956661, + 0.5344657898, 0.0764187127, -0.2980852723, 0.1402880549, 0.4510383606, 0.1825833172, -0.6221678257, -1.8053606749, + 0.3611282408, -0.8057336211, 1.4318394661, 0.5070827007, 0.5489898324, 0.9191237092, 0.6925198436, -1.1693946123, + -0.9724825025, 1.0652650595, -1.3838489056, -0.4112027287, -1.3346097469, -0.5550889373, 2.1472911835, 1.1219021082, + 0.3011842966, 1.1503249407, -1.3700573444, -0.2416723967, -0.8239528537, 0.2148872912, -0.1503032893, -1.6401677132, + -0.4880145788, 0.1143725961, 0.0351575762, -0.2061207592, -0.7204528451, -1.8366031647, -0.1839381754, -1.5259851217, + -1.1155805588, 0.1875498742, -0.9459524155, 0.1837504357, 0.243622154, 0.1203817278, -0.0044349479, -0.6723968387, + 1.5836912394, -0.0804802477, 1.4106041193, -0.6819021106, -1.0202736855, 0.9404947162, -1.2492835522, -2.0210082531, + 0.0438118316, -1.1920198202, 0.2237372845, 1.3341157436, -0.467884481, 0.5081447959, 1.552603364, -0.8240080476, + -1.7554879189, 0.2668016553, 0.0097025707, -0.1617574394, -0.3676709831, 0.5528894663, -2.0743434429, -0.5731478333, + 0.1601055115, 0.3278245628, 1.2261792421, 0.5595084429, 0.856582284, -0.0552693568, -1.5954004526, -1.1731684208, + 0.2836863399, 0.0900228396, 0.3806756735, 1.6710040569, 0.4169368446, 0.0130567746, -0.383436501, -0.6937999725, + 0.7352904677, -0.4927332103, -0.1502003819, 0.6302086115, 1.2963200808, -0.43254444, -0.5431685448, 0.7643723488, + -0.3315337896, 1.43108356, 0.6894853115, 1.2302139997, -2.7370042801, -2.0758631229, 0.8194510341, -0.4422242343, + 0.4619798958, 0.4433602989, -0.4337116778, -0.9711326361, -0.758174777, 0.1246169358, 1.2777051926, 1.1372745037, + -1.4670459032, -0.4377576411, 0.5218424201, -1.3545349836, 0.4560755789, 0.5561665297, -0.2870936692, -0.9668313265, + -0.5786038041, -0.4808922112, 0.6795433164, -0.9512211084, -0.0520349778, 0.6492468119, -0.4023033082, -1.4939315319, + 0.1896193027, -1.44848001, -1.0535236597, 0.4588146806, 0.8064754605, -0.6888238788, -0.2907008529, -0.2247964591, + 0.5738497972, -0.3463048637, 0.7758319378, -0.8346418142, 0.3204473555, 0.067571044, 0.6141188741, 0.0013366932, + -0.741021812, 1.6322492361, -1.270075798, -1.034507513, -1.0681058168, 1.1929841042, -1.1688381433, -0.5785624981, + -1.2230278254, 0.5554084182, -0.4128984511, -2.2871227264, -1.1279395819, 0.843323946, 0.1518727094, 2.0980987549, + 0.4355578423, 0.8607432842, 1.7625917196, 0.0613590404, -0.1310444772, -1.1538994312, -0.2084873766, 0.6174628735, + -1.7004872561, -1.0596629381, 0.8424559832, 0.6678346395, -0.7544751763, 0.0714253187, 0.6278148293, 0.4992212653, + 1.0457350016, -0.1810946763, 2.0991773605, -0.8590780497, 0.2861403227, -1.4618811607, 1.028239727, -0.5337978601, + -0.1446364969, -0.9851919413, -0.0448441878, -1.3567535877, -0.4009573758, -0.5194885135, 1.9878838062, 0.6508784294, + 1.0800508261, 0.7166387439, 0.2542805076, -0.1705901474, -0.8281711936, -0.2093469799, -0.3811714649, -2.3445951939, + -0.3831149042, -2.7244744301, -0.8163167834, 1.1056801081, -0.7393755913, -0.0141836274, 0.7436538935, -0.7740547657, + 0.373583436, -0.218448326, 0.9375358224, -1.2539305687, 0.5076622963, 1.3608239889, -1.1145510674, 0.3206633925, + -2.1811640263, 0.3985752165, -1.3613519669, 1.0203813314, -0.0525459312, 1.2631360292, 2.2825152874, -0.8123476505, + -1.4406666756, 2.0423271656, 0.1090389937, 1.4997259378, 1.4937498569, -2.899528265, -0.6637921333, -1.2237437963, + -2.7321140766, -0.8622496724, 1.9248254299, -0.0118800914, 1.1111546755, 0.4902781546, -1.1836172342, -1.7035608292, + -0.6081807017, 1.3975087404, -0.7155966163, 0.2222000808, 0.1491065621, 0.5913746357, -0.5024318099, -1.7523351908, + -0.8049672246, 0.0088898782, 0.5498868823, 1.2858682871, -0.8413038254, -1.256223321, 0.8540031314, 2.7723174095, + -0.0660058931, -0.0704578236, 1.4507570267, -1.7885080576, 0.0580867492, 0.0526900925, -1.242457509, -1.1932390928, + 0.053660728, -0.548391521, -1.1195905209, 1.2937419415, 0.4144541919, 0.5000180006, 0.2320733964, -1.2249164581, + 1.0522677898, 1.1093354225, 1.0206264257, 1.8482019901, 1.0249714851, -0.6673058867, -0.4649356008, 1.1188815832, + -2.9661209583, 1.1700307131, -0.8108969927, 1.0020540953, 0.1462125331, 0.7842738628, -0.7974629402, 0.2370982617, + -0.2903953195, -2.3647882938, -0.4633262753, 0.3321042359, 0.0682333335, -1.5955102444, 0.4221783876, -1.0460327864, + 0.0833548754, -0.0800244212, 0.0916623548, 0.8428997993, -0.0078278603, -0.0038369715, -1.8239731789, -0.6578385234, + 0.5915154815, 1.1527293921, -1.2100425959, 1.4766799212, 0.2016633749, -0.1270681322, 0.2116021514, -0.7006193995, + -0.3207107484, -0.5239910483, -0.2711711824, -0.0808895975, -0.2620672882, -0.5259278417, -0.2087262869, + -0.0847980306, -0.6684075594, 0.1318341643, -0.3069368303, -0.3217082024, 1.2094240189, 0.3053298891, 0.0364941768, + 0.4884267449, -0.279094398, -0.998744607, 0.0164896939, -1.4116181135, -0.0203813892, 2.0271334648, -0.4562243521, + -0.7777702212, -0.0108297598, 0.1521138549, -1.5504790545, -0.4843142927, 1.1425955296, 0.9327201843, -0.2901050746, + 0.5929782987, -0.7860559225, 0.2315905243, -0.1417619437, 0.0613079369, -0.0808374882, -1.5937153101, 1.0773460865, + 0.2746188343, -0.7450028062, -0.6539436579, 0.8430441618, -0.8579425216, 0.8792074919, -0.1914065927, 0.8935930133, + -2.3076658249, -1.2254799604, -0.9316254854, -1.3976552486, -0.3991250396, -0.6948458552, -1.5662037134, + -0.0899952948, -1.2958993912, -0.2588024437, 0.024290707, -0.1605933458, 0.1624411196, 0.6484341621, 0.078612864, + 0.167019397, -0.7773826718, -0.7471885085, 0.2092164755, 0.2134766579, 0.5705438852, -0.4578116536, 0.5587601662, + -1.0892243385, 1.0605726242, -0.3094975352, -1.4312770367, -0.173045814, 0.43375054, 1.0741657019, 1.6160172224, + 0.1272350997, -0.193865791, 0.6725165844, 0.5144274831, -0.5641947389, -1.0385379791, 0.2151829004, -0.4242037535, + -1.549071312, -3.3838853836, 0.3964085877, 0.4213456511, -0.3092971146, 0.5519814491, -1.0131312609, 0.165293932, + -0.7183796763, -0.2181751877, 0.4323822856, -0.4072811007, -1.3852882385, 0.0991055146, -0.923253417, -0.0023331596, + 0.5881130099, 0.4912368953, 0.5116588473, -0.4789597988, -1.3557976484, 0.867471993, 0.8575125933, -0.1776522994, + -0.1775404066, -0.1856035888, 1.340482831, -0.9878146648, 1.6222991943, -0.259506464, -0.5972997546, -0.5425067544, + 0.5912622809, 0.3834866583, 1.322278142, -0.819251895, -1.0907922983, -0.6246671081, 0.6052445769, 0.4081635475, + 0.2373645455, 0.1690674126, 0.5802407265, -0.5613754392, 0.2456480712, -0.9186141491, -0.276920408, -1.770632863, + 0.4763954878, 1.5354692936, -0.0598922297, -0.5450186133, -0.1883676797, -2.5338580608, 0.4641127586, 0.3048112392, + -0.6876582503, -0.4315545857, 0.3876003921, -0.8581926823, -0.6158384085, 1.0436244011, -0.3341654837, -0.0467620641, + 0.7010356784, 0.1533711851, 0.9586766362, -0.0557326339, 0.3174902499, -1.2664761543, 0.169786945, -0.8404021859, + -0.4100980163, 0.2164599746, -1.5345907211, -0.3343243003, 0.173392579, 0.6227089167, -0.3400717676, 0.2302381098, + 0.7133636475, 1.0837763548, 0.6489784122, -0.4140874445, -0.4357428849, 1.0704756975, -0.1154135317, 0.483046174, + -0.255348295, 0.6317064762, 1.4388637543, -0.6082205772, 0.6572952271, 0.4606111348, -0.4769994318, -0.6360312104, + -0.0991303176, 1.0446186066, 0.9986180067, 1.2831765413, 2.1639351845, 1.1235325336, 0.2174135298, 0.1962851286, + 0.7651981115, -1.2645888329, 2.4407944679, 0.0277731884, 0.3911207616, 0.3047181964, 1.5580196381, -0.7807807326, + 0.1302722842, 0.9293032289, 1.018001318, -0.1589470506, 0.901288867, 2.011013031, 0.4158630371, 0.0888017491, + -0.3296423256, 0.235209614, -1.3284860849, -1.0254509449, 1.593988657, 0.128252089, 0.4186613858, 0.3527747393, + 1.8500404358, -0.6223271489, -0.6476612091, -0.2049963474, -1.3311686516, -0.1923779994, 0.9806227684, 0.0004467586, + -0.6268636584, 0.0827400163, 0.9971995354, -0.9771696329, -0.2499272972, -0.3006271124, -0.314887166, 1.7323715687, + 1.7476186752, 1.2388221025, 1.5113986731, -1.3835494518, -0.7499847412, 0.6338880062, 0.5752592087, 0.4825147986, + -1.0033938885, 0.3850116134, -1.2665108442, -1.2748463154, -0.0880842432, 1.234401226, -1.1817024946, 1.1284167767, + -0.3691191077, 0.079131715, 0.3606567383, -1.3921650648, -0.8959398866, 1.5028594732, -0.6054318547, 0.2944380939, + -1.0308992863, -0.06826213, -0.9367830157, -0.4790829122, 0.3819047511, -0.0056958185, -0.0107525261, -0.1028386652, + -0.040715348, 0.8296846747, -0.1679052711, 0.7480251193, -0.2704329193, -1.6717312336, -0.9499000311, 0.0938736945, + 0.0792115331, 0.93974334, 0.4047400951, -1.5396602154, -0.6735089421, -0.1467912346, -1.107530117, -1.2755281925, + -0.2567361891, -1.1061099768, -0.734452486, -0.3856717646, -2.1764931679, 0.0527051352, -1.4594818354, 0.1187220141, + 0.0322499759, -0.8149708509, -0.0294837058, 0.8411209583, 0.521153748, -0.07603167, 0.5130376816, 1.3642598391, + 0.096839495, 1.3154854774, -1.4872413874, 0.9520645142, 0.3005496562, 0.6140743494, 0.4355062246, -0.5848545432, + -2.530523777, 1.3488068581, 0.3234812021, 0.0880915597, -1.1336556673, 0.0930403545, -0.1541861147, -0.3016662002, + -1.4424922466, 1.5437906981, -0.6499189734, -2.3192703724, 2.1626596451, -0.924177587, -1.1621884108, 0.9141823053, + -1.0259217024, 1.8104969263, -0.351942569, -0.9066295028, 0.5648496747, -0.8370807171, 1.4850924015, -1.0320893526, + -0.591866076, 0.1176175773, 0.1124671847, -0.5896363258, -0.5832690597, 1.6353310347, -0.7493469119, 0.0465250574, + -1.0367507935, -1.4493075609, 0.7984340191, 0.0820988566, 0.5954594016, -0.318944782, 0.5058848262, -0.7114982605, + 0.5402135849, 0.9257064462, -1.4224647284, -0.7928759456, 0.0240264982, 1.6763641834, -0.3487647474, -0.1829279959, + -0.3225548267, -0.3663921356, 0.1824751198, 1.0975593328, 0.1602485627, -0.686121285, 0.7449244857, -0.1191331446, + -1.4907772541, -0.0717278123, 0.5842505693, 0.2929826379, 0.0632381737, -0.1342022121, 0.4378673136, 0.4098827243, + 0.8411206603, -0.0789814442, -0.2399690449, 0.5405627489, 0.627828002, -0.0108255902, 0.0505150706, 0.9220871925, + 0.4489594996, -1.0202002525, 0.0912503898, 0.9841045141, 0.9010125399, -1.1630496979, 0.0682095513, 0.8780198693, + 0.0305589475, 0.3894029856, -0.7775303125, -0.0655512884, -1.6206985712, -1.1411087513, 0.6450503469, 1.2038553953, + 1.471268177, 1.2446136475, 0.216468662, 0.2948817015, 0.0351893939, -1.1672149897, 1.1487790346, 0.4665854871, + -1.8246629238, -0.4153800309, 0.1016899049, 0.9141763449, -1.3728073835, -0.1546313763, 0.8691310287, -0.7926211357, + -0.1904437244, -0.6742334366, 1.5098134279, -0.7134387493, -1.3717981577, -2.2027521133, 0.1625714153, -1.5810571909, + -1.4009828568, -1.3369977474, -0.9206066728, 0.5045040846, 1.0087817907, 0.7085490823, -1.8204631805, 0.3505395055, + 0.1601599306, -1.2087808847, 0.4851200879, 0.6961211562, -0.8115411401, 0.6887942553, -1.4158912897, -1.6351356506, + -1.5797746181, 0.6322211623, 0.7213320732, 0.4606862962, 0.8185957074, 0.4297682345, -0.0461610332, -0.4848355055, + 0.0079860473, -0.2723667622, -1.7874740362, -0.9821856022, -0.1429887712, -0.025234865, 1.9776024818, -0.0204313695, + 1.231983304, 1.4091806412, 2.0734572411, 0.7006293535, -1.7150832415, 0.2069371343, -1.6790082455, -0.2211100459, + -1.1749776602, 0.0365302674, -0.3868663907, -0.0528737232, -0.9732688665, -0.3719446659, 1.6559091806, 0.3440146744, + 0.3946353495, -1.2677277327, -0.1625610441, -0.9379303455, 0.5799641013, -0.0261510685, -0.7596936822, -0.769477725, + -1.0063365698, 0.2434116006, 0.4409281015, 0.7339676619, 0.8679358959, 1.144506216, -0.8765382767, 1.2840873003, + 0.0781262815, 0.6481414437, -0.9263640642, -1.4005607367, -0.5750855803, -1.0007141829, -1.0111794472, -2.0524334908, + -0.644215107, 0.7671940923, -0.1145124212, -1.1316365004, -0.4282675087, -0.5749440789, 0.1833458543, -0.1921777874, + -1.4095654488, -0.87444067, -1.5981025696, -0.5336658955, -0.9894477129, -0.4347616434, -0.510778904, 1.367053628, + 1.3113130331, -1.3499810696, -0.3468316793, -0.0047309161, -0.7323764563, -1.0284543037, -0.0138079068, 0.1132538766, + -1.564699173, 0.0751108974, 0.8303509951, -0.1938802451, -1.9379101992, 0.0315455496, 0.6615291834, -0.3474954963, + 0.0518144444, 0.2939739525, 0.0353117324, -0.0989409313, -0.3005047441, 0.1867303848, -0.2230330557, 0.1489258558, + -0.3088251352, -0.8473169208, -2.1500792503, 1.2460508347, -0.5631950498, -0.0580349751, 1.0495109558, -1.5226836205, + -0.3884546161, -1.3195962906, -0.4702957571, 0.9313479662, -0.6823721528, 0.200000897, -0.5764540434, 0.8537899852, + 0.9402247071, -1.2445976734, 1.5359268188, 2.0948321819, 0.0036094575, -0.8047494888, 0.6427945495, -0.2275648564, + 0.9242594838, 0.535951674, 0.4261472821, 0.1482180059, 2.3247148991, -0.0195343848, 0.1890586466, 0.5467409492, + 0.1936537623, 0.1615436673, 0.7448188066, -0.1855718195, -0.0946201459, -0.7014371753, 1.3129265308, 0.2720538378, + -0.8413616419, -0.4604212642, -0.4750130177, 0.1501253098, 0.5798549652, 0.6560567021, 1.0006505251, -0.0545246713, + -0.8020230532, 0.1682970226, -1.3182489872, -1.1121965647, 0.4462005496, 0.6017032266, -0.9011870623, 0.0598643757, + -0.4081072211, -1.7386128902, -1.3758144379, 1.4552366734, -0.454362154, -0.0994410738, 2.2818775177, 0.5025957227, + 0.1134583354, -0.703055203, -0.4476456046, 0.254773438, 1.2222807407, -0.9206188917, 0.2277347744, 0.0041218023, + -0.5322578549, -0.6025855541, 0.7921522856, 0.7033787966, -0.5238165855, -0.3242940903, 0.22827591, -0.7225562334, + 0.2189976722, 1.8640956879, -0.2014419436, -2.0383541584, 0.7670707107, 0.0946207866, -0.9718177915, 0.5874319673, + 0.6024810076, -2.0453674793, 0.3536788225, 0.9645302296, -0.1440635771, -0.5780105591, 0.4737685323, 0.5964793563, + -0.6031044126, 1.7813662291, 0.2994776368, 0.0040594037, -0.4686329961, 2.2406263351, -1.0148507357, -0.1007227823, + 0.5790359974, -1.3669410944, 2.4542148113, -1.050291419, -0.3570873737, -0.5959746838, 0.1286456734, -0.273511976, + 1.1831076145, -1.9064669609, -0.0173027087, -0.8793388605, 0.9526354074, 1.7210581303, -0.5359464884, -0.4232902229, + -0.7482769489, 0.3254696131, -1.7439950705, -1.3261831999, 0.691868782, 1.3905178308, -0.2113317549, -0.682525754, + -0.3879581392, 1.7752315998, -1.2752637863, -0.1166420951, -1.2915318012, 0.183776468, -0.1601903141, -1.2379313707, + -0.0902454183, -0.2519405782, 0.5891952515, -1.2630279064, 0.6976277232, -1.1750415564, -0.5748518109, -0.6612970829, + -0.2794839144, -0.5347990394, -1.3255223036, -1.1630715132, -0.149652943, -0.2865560055, -1.6683949232, -0.9315761328, + 0.7481259704, 1.2013155222, -1.5000940561, -0.6404548883, 0.7500379086, -0.441299051, 0.5010219216, -0.5410768986, + 0.055248376, 0.4714125097, 0.0664171502, -0.5142256021, 1.946410656, 0.3117389381, 0.1133240163, 0.0764206946, + -2.1993992329, 0.5718014836, 1.3705084324, -1.5698078871, -0.5611788034, 0.9989655614, -1.3109512329, 0.2550405562, + 0.2179651111, -0.2458942831, 0.7524243593, -0.8888767958, -0.976498425, 1.2953237295, 0.4097941518, 0.1875261217, + -0.6974471211, 0.5086981058, 1.6450030804, 1.9019715786, 1.1486008167, 0.7689781785, 0.5361904502, -0.6677723527, + 0.6889824867, 0.986929059, 1.0165002346, 0.5444405675, 0.5614240766, 1.5270713568, -0.8393536806, -0.9333688021, + -0.0409526937, -0.0998738036, -1.0882169008, -0.3863084316, 0.3301858604, -2.1117844582, 0.484215647, 1.3418143988, + -0.574396193, 0.0791617855, -1.6336181164, -1.3499776125, -0.0084255254, -1.4727298021, 0.725723505, 1.0187690258, + 0.8479738235, 0.0947717726, -0.4799260199, 0.0153171076, 1.7028288841, -2.4398531914, -0.7412115335, -0.7696051002, + 1.3584727049, 0.537512362, -0.4170902073, -0.3068646789, -0.3780648708, -0.6893613338, -0.3763635159, -0.5504732132, + 0.6834804416, 0.1133769155, -0.8619261384, 1.0548527241, -0.3079719841, 1.3956831694, 0.245927915, -1.6134513617, + 0.0425924845, -0.2693678439, 0.4709191024, 1.9377353191, 0.7869468331, -0.0102772806, 0.7438308001, -0.914963305, + 0.0896701813, -0.4285502732, -1.3545906544, 0.3714318871, -0.9662501812, 0.0663880482, 0.0755720139, 0.8606848121, + -0.3789045811, -0.5214172602, -0.0249759257, 0.3855774105, 0.7961698174, -1.1770154238, -1.4023742676, -0.2600174546, + 0.4639261067, 0.4731233418, -1.4157626629, -0.8307561874, -0.4470773637, -0.3219674826, -1.9117525816, 1.8478777409, + 0.4157984257, 0.2571049929, 0.3644884229, 2.1297881603, -0.2326315641, 0.4425879419, 1.5757837296, 0.0731884092, + -1.9210509062, -1.3611035347, 0.1254009157, -0.7626289129, 1.3449469805, 1.727524519, -0.5753748417, 0.7083702683, + -1.1395683289, 0.900945127, -1.1356049776, 0.1987769753, -0.0978872925, 1.1407341957, 0.9220844507, 0.4430917501, + 0.6003719568, -1.2657593489, -0.32706514, -0.595653832, 0.1456205398, 0.6889383793, 0.1033993214, -1.3690428734, + 0.7404351234, -0.1215081289, -0.1990689635, 0.8810068369, 0.3059888184, 0.4480573535, 0.0953786969, -0.1013018936, + 0.4117246568, 0.3502552509, 0.0194713138, -0.2473152578, 0.0101099778, 0.9885329008, -0.8361511827, 1.9361438751, + -1.581187129, -1.1002520323, 0.9397823811, -0.0545123816, 0.7610992193, 0.5216606259, -1.0363000631, -0.76521945, + -0.038275443, 0.9650835395, 1.8669173717, 0.1112473533, -1.2015788555, 0.6443081498, 0.6186507344, 0.0816031545, + -0.4066605866, -0.4410473108, -0.590829432, 1.1830356121, 0.2105588764, -0.148993209, -1.367810607, 0.5889723301, + 0.3990076482, 1.5867253542, -1.541988492, -0.3135329485, 1.2928620577, 0.5041116476, -0.9222351909, -1.7613097429, + -0.4756738544, -0.7624484897, 0.4504918158, -0.4556908309, -0.0724610984, 0.7097553611, 1.1203337908, -0.3484529257, + 1.1659314632, 0.1397081167, -1.5629338026, -0.7076761127, 1.4508572817, 0.5759756565, -0.9922260046, 0.299719274, + -1.5346330404, -0.9537140131, 2.3760414124, -0.0492447056, -0.2149013877, -0.7276610732, 0.0869092569, -1.3743280172, + 0.0617098734, -1.3765540123, -0.3937661052, 0.5421155691, -1.4106866121, 0.4895611703, 1.1866769791, 1.5226407051, + -0.4637456834, -1.9443510771, 2.0126781464, 1.2011687756, 0.4509884119, 0.4688838422, 0.1416492164, 2.035171032, + 0.4427682161, 0.4046050906, 0.5470671654, 0.1857168674, -0.1370263547, -0.7957639694, 1.1775459051, -0.2308127433, + -0.3254511952, 0.6586336493, -0.6313273311, -2.5197975636, 0.6868247986, 0.9503057003, 0.5775336623, -1.1326794624, + -0.1656296253, 1.3421090841, -0.0567202605, -0.6803632975, -0.4050382078, 0.635546267, -1.5059229136, -0.2022885233, + -0.259174794, 0.3714067638, 0.8712681532, -0.3979974091, -0.9245500565, -1.0143244267, -0.4404507279, 0.59709692, + 0.2319602817, 0.553584218, -0.4240028858, 0.5902436972, -0.5997185707, 0.1466287971, 2.3729963303, 3.0086288452, + -0.5136756301, -0.4350767136, 0.9363536835, -0.0597128756, -0.8972352147, -0.6416056156, 1.2984263897, 1.8004604578, + -0.754509151, -0.3338066936, -0.2864007652, 0.4252581596, 0.5166036487, -1.0704407692, 0.3727474511, -0.4662492871, + -0.8777085543, 1.0085009336, 0.4567803144, -1.4343152046, -0.0693903938, 0.6386763453, -1.234125495, -0.0431989394, + -0.1082422808, 1.1039363146, -0.9819817543, 0.6192163229, -1.2208844423, 0.5299162865, -0.1968284845, 0.7186149955, + -0.2716750801, -1.0598012209, -0.652353406, -0.7307460904, -0.1305984706, 0.4185395837, -0.1593158543, -1.0495679379, + -0.3906728327, -0.2174431086, 0.1957010031, -0.8210510612, -0.7583345175, -0.6436064839, 0.6527817845, -2.2995562553, + -1.4217740297, 2.6572241783, -2.4107866287, 0.2148666978, 1.1167837381, 0.0689454675, -1.365388751, 1.1535874605, + -0.4121600389, 0.292952776, 0.3599597514, -0.6850985289, -0.440638274, -0.5719017982, -0.1960382611, -1.7868933678, + -1.3133436441, -1.1885946989, 1.0874711275, -0.5319527388, -0.6841382384, 1.2883000374, 0.0816733018, 0.5675491691, + -0.3255595267, 0.3317215741, 1.0300211906, 0.576263845, 0.8731001019, 0.8163179755, 0.7308938503, -0.6628636718, + 0.3519839942, 1.2436153889, -1.1196715832, -1.0711348057, -0.1543116719, -1.0863668919, 0.4676058888, -0.6846093535, + 1.3797492981, 0.3526509106, 0.1648032069, 0.0237876102, 0.2023786604, -1.1174907684, 2.2319457531, -1.531277895, + 0.6684376597, -0.8544011116, 0.6476187706, -0.7095187306, -0.5701030493, 0.2349684983, 0.7085313201, -0.2691114843, + 0.3251794875, -1.1168712378, -0.3028653264, -0.278865099, -1.0868864059, 0.4872075617, -0.5189303756, 1.1145070791, + 0.4584412575, -0.5998378396, -1.4327603579, 0.1275960505, 0.2901370525, 0.5808152556, -0.3115820587, 0.8584854007, + 0.8452209234, 0.3459075093, -1.5614558458, 1.6772382259, 0.3585601747, -0.8467258811, -0.4606466293, 1.7624496222, + -0.6848064661, 1.2684752941, 0.8637610078, 0.4877776504, 0.8418605924, 0.1541614383, 0.8735924363, 0.3841915727, + 1.6905543804, -1.1739689112, -1.3215125799, 0.1166850626, -0.5511772037, 0.103862904, 1.0686504841, 1.322982192, + -1.6473169327, -0.8972117901, -1.7887773514, -0.7082397938, 0.056337744, -0.730147481, -0.6179089546, -0.7773608565, + 1.2667914629, -0.5679482222, 0.7532033324, 1.0075652599, -0.5667064786, 0.8302335739, -1.4011286497, -0.004377522, + -0.7475999594, -0.7050182223, -0.8238686323, 0.0595666282, -0.9293041825, 0.3678091466, -0.5593569875, 0.8309092522, + 1.4071900845, -0.5506002307, -0.8832412958, -0.4212633371, 1.7079013586, -0.2129941732, -1.221564889, 0.974637568, + 0.5255259275, 0.1676276326, -0.7460688353, -0.3985492587, -0.2419589013, 1.0022572279, 0.3096496165, 0.0151867429, + -0.9989675879, -0.8324916363, -0.2698731124, 0.7522588968, -0.7222785354, -1.3158954382, 0.2006363124, -0.5149350762, + 0.006110514, -1.7563093901, 0.0626748428, -0.514252305, 0.9311300516, 0.2424508929, 1.6043307781, -0.328981936, + -0.0494096093, 0.7316811085, -3.0088012218, -0.371551007, 0.6926851869, 0.0006539202, -1.5461733341, 0.0995478183, + 0.2765178084, 1.4613583088, -1.3338665962, 1.1406615973, 0.3171734214, -0.4835242331, -0.2373184413, -0.0232107006, + 0.8536342382, 1.658654809, -0.5782043338, 0.4537277818, -1.6588265896, -1.2349920273, 0.0675332099, -0.2628900707, + 0.3805647194, 0.8191167712, -0.1620512605, -0.6835185885, -0.8386046886, -0.4493160546, 0.1507066637, -1.9121794701, + 0.5574362278, 0.7430413961, -0.2474150509, 1.0876133442, 0.423971504, -0.3730142415, -0.082982257, -1.4674832821, + 0.2024282217, -0.8522486687, 2.2314176559, -0.5353853703, -0.177971378, -0.2383777201, 0.5534749031, -0.7674822211, + -0.3580855429, -0.8130614161, -0.4385259449, 0.4330780208, -1.6723484993, 0.4503363967, 0.2866947651, -0.3895815313, + -0.2773104012, -0.2627112865, 0.8851501942, -0.460698694, -0.6227043271, -0.2819042802, -0.1450483352, -0.1862329692, + -0.9947724938, 0.1286654323, 0.86036551, 0.8581410646, 0.0987485275, 0.5210778713, 1.4589275122, 0.633640945, + -0.8249817491, 1.1077028513, 0.0143080968, 2.6831395626, -0.4208842516, 0.1807337701, 0.8042305112, -1.6470074654, + -0.5645323992, -1.4007233381, -0.1503272057, -1.035179019, -1.1351163387, 0.3737889528, -0.4462286234, 1.0661048889, + 0.3744573891, 0.9195076823, -0.4215391576, -0.5308960676, -0.2440245748, 0.2437709421, 1.8744490147, 0.0601186305, + -0.2889816463, 0.6083256006, -0.5951191187, -1.1753454208, -0.4446639717, 1.6190202236, 0.273111552, -1.2823290825, + -0.6856404543, 1.0023931265, -1.0596644878, 0.0099540399, -0.9112805724, -1.9877477884, -0.3559651077, 0.699265182, + -0.5291158557, -0.2777605951, -0.6945871115, 0.426331073, -0.4606139064, 0.5313073993, 0.3477262855, -0.6290251017, + 1.0485340357, -0.4984591007, -0.7014091611, -0.1268873066, 1.7174379826, 0.3756468594, 0.6778792143, 0.6780077219, + -1.9288370609, 2.1379055977, -0.3503865302, 2.6057658195, 1.4180355072, -0.8483371139, 0.4836727679, 0.2986367643, + -0.4045870006, -0.3841612935, 0.4206042886, -0.2121454924, -0.7215571404, -0.9440875053, -1.8669323921, -1.2715229988, + -1.316681385, -0.2099368423, -0.4971982241, -0.6165689826, -0.8177767992, 0.7123737931, 0.0018365026, 0.218935743, + 0.4399895966, -1.4153739214, -0.474537164, 0.8956039548, 1.8533095121, -0.6692598462, 0.8224695325, -0.4222893119, + 0.0309825372, -0.0985280126, 0.0038888101, -0.6720025539, -1.0864828825, -0.5846391916, -0.8959212899, 0.789226234, + -0.572771132, -0.2901080549, 2.345541954, 0.5100870132, 0.6484789848, 0.2203816473, -1.241977334, -0.2932655215, + 0.0602538697, -1.2372095585, -1.3545566797, 0.7277938724, -0.5110531449, 1.8365730047, 0.1518082768, -1.2500865459, + -0.8315503597, -1.67156744, -0.696826756, 0.1409083009, -0.4922994673, -0.7246807814, 0.0654167756, -0.7244126201, + -0.1597559899, -0.5303936601, 0.0489419326, 1.0108239651, 0.6513858438, 0.5965271592, -0.8281033635, -0.4502198994, + 1.3260207176, 0.1846620142, 0.319010675, 2.7237520218, -0.2407226712, -2.0167696476, 0.0360962264, -0.6404058337, + 2.037614584, 0.4976940155, -0.1475096196, -1.6457666159, -0.3195464015, -0.4240814745, -0.7984828353, -1.7798746824, + -0.5305024981, -0.9451339841, -0.3695907891, -0.619353652, -0.8740698695, 1.6382918358, 0.8859256506, -0.6783981919, + -0.6647996902, 1.8402383327, -0.466463536, -0.2869035602, 0.8843571544, -0.6794208288, -0.0783729777, 2.0344007015, + -1.1569439173, 0.5343900919, -1.2190382481, -2.7440197468, 0.3725993037, -0.9437746406, -0.8705223799, -0.2391330153, + -0.3168485463, -0.1414447427, 1.3143306971, -0.0398241282, 0.9941142797, 0.5481469035, 2.4456527233, 1.1136090755, + 0.8380909562, 0.8857203722, 0.4825400114, -0.4374621511, -0.3491562307, -1.1849820614, 0.9566195011, -0.6884231567, + -0.6400103569, 0.4962954223, -1.2663766146, -0.3680319488, -0.4868077934, -0.5154715776, -0.2976514101, -0.8406806588, + -0.0521839485, -0.2806237936, 0.2266739756, -0.2517160773, 1.0988744497, 1.2061139345, 0.1976041198, -0.5565751195, + -0.4206511378, -0.6106412411, 0.6980303526, 0.803899169, -0.5697152615, 1.1649491787, 0.7628110647, 1.1644734144, + 0.9731919169, -0.77038908, 2.5272583961, 0.2993666232, 0.9850234985, 0.7090337873, 1.272660017, -0.9547067285, + -2.2828862667, 1.8040145636, -0.3618632853, -0.2424062788, -0.036049895, 0.6348895431, -1.1561373472, 1.6774686575, + -1.1213855743, -2.1498403549, 0.4187663794, -0.8002408743, -0.7238284349, 1.1115944386, 1.5962899923, -0.8676059842, + 0.7034949064, -1.2499570847, 0.1972162724, -1.418418169, -0.1329640746, -2.0752580166, -1.3371758461, -1.7525701523, + -1.4658756256, -1.5818002224, 1.640129447, -0.4202954471, 0.604704082, 0.3399446011, -0.8635126352, 2.1736896038, + -0.6485803127, 0.7760526538, -0.5920584798, -0.1532118171, 0.0984346718, -1.1254554987, -0.4605285823, 1.1066592932, + -0.3280683458, -0.2730957568, 0.0873861089, 0.3761961758, 0.3713440597, 0.100237973, -0.3835586011, 0.5256533027, + 1.5230630636, 1.6018843651, -1.2051194906, 1.089709878, 0.7993661761, 0.0984100774, 0.5448901057, -1.2182017565, + 0.2122826129, -0.0533185825, -0.8356292844, -0.0336980745, 1.271222949, -1.2643465996, -1.6775107384, -0.9985657334, + 1.0351241827, -1.5880872011, 0.7903474569, -0.0167097095, -1.2681533098, -1.624812603, 0.6737528443, 1.4385950565, + 0.2779538631, 1.9929624796, -0.1199937686, -0.4443750381, 0.9745465517, 0.4621928632, -1.5144137144, 0.9511830211, + 0.8978304267, -1.1884974241, 0.0929282978, -0.5976312757, -0.9062644839, -0.4685940742, 0.0498959236, 0.1588799804, + 1.4182624817, -0.0872410312, -0.4276543558, 0.0140459212, -0.8659215569, 1.4454176426, -0.3340324461, -0.0349760242, + -0.5698040128, -0.9010173678, 2.1993246078, -0.8341708779, 0.8671241403, 1.1048197746, 1.0847196579, -0.254629463, + 1.2404844761, 0.4475292861, 0.271407634, -1.4715112448, -1.2379156351, -0.2507206798, -1.3513888121, 0.2730809152, + -0.0653217137, -0.1397357732, 0.5785194635, -1.1722716093, -1.1036603451, -0.0131531553, 1.6345367432, 1.2507511377, + -0.5973930359, -0.0155039188, -1.989133954, 0.3615313172, -1.4075814486, -1.5032497644, -0.1248913184, 0.6577493548, + 0.0023436123, 0.287497282, -0.8602231741, -0.0809271559, 0.1523856521, -1.0670419931, -1.0369086266, 0.299836576, + -0.667693913, 0.6504074335, 1.3342704773, 0.5072284341, -1.4595576525, 0.7439997196, -0.9475765228, 0.2244775295, + 0.4849691689, -0.3844098151, 0.1123687103, -0.6872268319, 0.3756891489, 0.6597490907, 0.7952565551, 0.4855103195, + 0.3044109941, 0.149011761, -0.5080056787, 1.2712522745, 1.2272012234, -0.3299134672, -0.0199540183, 1.8290190697, + 0.5677607656, -0.5968216658, -0.2418765873, -1.9487468004, -0.2772829235, -0.5381264687, 1.2586739063, 1.5063394308, + -1.3124256134, -0.2960510552, -0.7850624323, -0.6174619794, 1.1621369123, 0.5564032793, -0.7371488214, -0.3468227684, + 2.3980824947, -0.1111919731, -0.2277705222, -0.6066004038, 1.5664755106, 0.8420552611, -1.3558931351, -1.0245736837, + 0.8999151587, -0.5651986003, -0.8465386033, -0.4856346548, -0.9645081162, 0.1725240499, -0.7497085929, 0.9174042344, + -1.7963420153, 0.0882364661, 0.5786577463, -0.031309735, 1.8228253126, -0.1195402592, -0.3144756854, -0.7695646286, + 0.6737496853, 1.7059468031, 0.1110388115, -0.1290749758, -0.7515364289, 1.1298259497, -1.9274809361, 0.2750416994, + 0.9833395481, 0.0931785628, 0.595557034, -1.3676586151, 0.5912148952, -0.6878173351, -0.2396046817, 0.4571484029, + 0.3076282442, -1.1353645325, 0.54500103, 1.2716612816, -0.7891782522, -1.1442798376, 0.5127852559, -0.3669523299, + -0.8581065536, 1.3917527199, -1.8237631321, 0.1568117738, 0.6871304512, -0.8506605029, -1.0436689854, 0.7592877746, + -0.4107601345, -1.486756444, 0.6242988706, 0.4792506993, -1.1623834372, 1.296385169, 1.8081043959, 2.4934203625, + -0.2422652245, -1.7136925459, -1.8513816595, -0.8949121237, 1.1286860704, 0.344014585, -0.4634765983, -0.0613686703, + 1.7311720848, -1.2469245195, 1.2263395786, 0.3082263768, 0.2303123176, 1.1889343262, 1.2646365166, 0.0945713371, + -0.1564330161, -0.1214945167, 0.6576443911, -0.8273627162, 0.1350538135, 0.2720624208, -0.1212793067, 0.7692606449, + -0.7661889195, 0.6638042927, 1.2159714699, -0.6703962088, 0.4307232499, -0.5342184901, 1.0875924826, -0.5991690159, + 0.3697001636, 1.0889072418, -0.2163190544, -1.257085681, 0.6826377511, 1.3048549891, 0.8470559716, 0.3935773671, + 0.7606564164, -0.9260808825, -0.3522996008, 0.4411866665, 1.0888419151, 1.8529471159, -1.0159670115, 0.1586700678, + -0.2941544652, -0.7677201629, 0.6702014208, 3.0485541821, -0.7110427618, 0.0087685026, 0.2127590925, -0.6027239561, + 1.8547546864, -0.926764071, -0.9728785157, -0.5564861894, 0.1114080474, 0.6857814193, 0.5599179268, 1.0410881042, + 0.2579667568, 0.9110988975, -0.9568061233, 0.1526732743, -1.4196509123, -0.7998716235, 1.2206411362, 1.0975108147, + 0.8231616616, -0.0641085878, -0.6946839094, 1.602309227, -0.6245922446, -1.9093415737, 1.3474690914, 1.4625424147, + 1.6814835072, -0.1330091953, -1.6498638391, 0.076152809, -0.4358590245, 0.2756622732, -0.8825276494, -0.3384377956, + -1.3949745893, 1.0857973099, -0.4014986753, -2.3074398041, 1.1703572273, 2.3323669434, -1.2561129332, -1.0790011883, + -0.7676408887, 0.3213644028, 1.0556669235, -1.2354131937, 0.6065539718, -0.6644827127, -0.8000290394, 0.0954485089, + 0.318739593, -0.6467474699, -0.3926055431, -0.8689112067, -0.3884165287, -0.4145347476, 0.0493419617, 0.2418716103, + -0.3547745347, 0.6621610522, 0.8859947324, -0.7657930255, -1.9621956348, -0.6089704037, -1.1985352039, 0.7472391725, + 0.6400617957, -0.42649737, 0.2084112614, -0.427996248, -0.1868031621, -0.1573167592, -0.1913782507, -1.0503474474, + 0.1423900723, -0.7872502208, 1.3039880991, 0.270842731, 2.0053474903, 0.8214874268, 1.5796195269, -0.7677533031, + 0.6795278192, -1.0888278484, 0.7510353327, 2.0150184631, -1.5912657976, 0.8089207411, -0.1970883459, 0.8027809858, + -1.254894495, 0.5105749965, 0.4831301868, -1.5909609795, 0.5785495639, 1.3184320927, 0.0695535466, -0.2157524079, + -1.7929224968, 1.2852239609, 0.4923533201, 0.3263441026, -0.9354546666, 1.4339323044, 0.2739963531, -0.099575229, + 0.2425071448, 0.5357111096, 0.4545810223, 0.5341140628, 0.0805591345, 1.3591556549, 0.1434901059, 0.2359346896, + -1.257455349, 0.3136060238, -0.4058042765, -0.8217685819, 1.3852506876, -0.911300838, 0.7037917376, -0.7449426055, + 0.932091713, 0.8437697291, -1.9806908369, -0.0670251027, 0.5133256316, -0.4757016003, -1.2597001791, -0.4355548322, + 1.3151249886, 1.1659435034, 1.6419327259, -0.6083964109, 0.4444638789, -0.4170851111, -1.5645383596, -1.3208391666, + -2.3012502193, -1.00702703, -1.329857111, 0.1743980348, 2.5718021393, -0.6891092062, -1.6248441935, -0.5891755819, + 1.6138558388, -0.0993815511, 0.6511113048, -0.2385976166, 0.6658123732, -0.7941064239, 1.3413614035, -1.2250225544, + 1.1066839695, -0.7866426706, -0.7299267054, -1.1541323662, 2.560958147, 0.5317540169, 0.3519812822, -0.6689489484, + -0.138078779, -1.1013877392, 1.093274951, 0.9128538966, -0.9880322218, 0.7098346949, -0.3154917657, 0.6754376888, + -0.0766175464, -0.3399885595, -1.0069338083, -1.2817411423, 0.108287327, 1.1880060434, -0.3071840405, -1.3175830841, + -0.3208683729, -0.7482139468, 1.109187603, 0.0395907052, -0.0068238205, -1.8176137209, -2.2272694111, -1.0444130898, + 1.7971816063, -1.3809732199, -0.8909279704, 1.7548052073, -1.9525624514, -0.4300846159, 1.0891311169, -0.3463200033, + -0.1930101216, 0.8065233231, 0.1266611665, -0.4590313137, 1.0066936016, 0.9566790462, -1.7197459936, 1.0318695307, + -1.4141339064, -0.0097696707, -0.1190411523, 2.09562397, 0.4579995573, -0.6332737207, -1.4304943085, 0.9629821777, + 0.3824220598, -1.4023016691, -0.5606012344, 1.1431181431, -1.8398458958, -0.06279549, -0.6901521683, 1.6339272261, + 0.2412263602, 0.1537550688, -1.1139428616, 0.887054503, -0.1872967929, 0.5684547424, -1.0961941481, -1.1251753569, + 1.188663125, -0.4543816447, -0.7960464954, 0.907317102, 0.6863700747, -0.4552413225, 1.5016720295, 0.0206240546, + -0.5202254653, 0.5245888233, 0.3571237922, -0.9080306292, 1.0753819942, 1.717802763, 0.7182201147, -0.5630775094, + -0.0887095183, 0.1610158384, -0.9418390989, -0.3211406469, -0.5363221169, 0.6615352035, 0.7728872895, 0.5593809485, + 1.576192975, 0.429497689, 0.4844272435, -0.8199804425, -0.6379592419, -0.8718496561, 0.4785815477, -1.6744025946, + 0.7056298256, 1.1006934643, -0.3888773322, 0.631499052, -0.3749686182, -0.5715098977, -0.9321445823, 0.6626054645, + -0.1253063679, -0.6241140962, -2.5891406536, 0.414178282, -0.6123164296, 0.5643692017, -0.7155497074, 0.5605821609, + 1.6867932081, 0.1108570546, -0.4897870123, -0.6119366884, -0.0666864291, 0.4495974481, 0.0085499445, -2.1522080898, + -0.7636897564, 0.2133529484, 0.4067107141, 0.8969731927, 0.715169847, -0.4244272411, 1.2850111723, 0.7844523191, + -0.1529647559, -0.1405523121, 0.3252138495, 0.2649473548, 0.5022157431, 0.0850721747, -1.4688378572, -1.3880082369, + 0.6504700184, 0.6187646389, -1.3998051882, -1.2288914919, 0.1766103208, -0.4094978273, -0.2433090359, 2.1143550873, + 1.4301925898, -0.4404291213, -0.0626156554, -0.4196424484, 1.0478527546, 0.9831517339, -0.4679268897, 0.3133228123, + -0.9002415538, -0.7844398022, -0.3946162462, -1.5743603706, 0.6414580941, -0.261870563, 0.6462222338, -0.6590774655, + 1.0195286274, 1.0634303093, 0.0653074756, 0.7577853799, -0.0516320206, 0.6106615663, -0.430214256, 0.8421626687, + -0.2350383252, -0.8129963875, 0.5303506255, 0.7106423974, 0.0993085951, 0.250638485, 0.9918402433, 0.8889755011, + 1.3261528015, -0.2485965937, 1.1315611601, -2.19704175, 1.41038692, -0.4955347478, -1.8461620808, -0.0154520124, + 0.2505555451, -1.5311112404, -2.526542902, -1.0538671017, -1.612021327, -1.6950901747, -0.5707432032, -0.3110536635, + 0.0624820627, -0.1097832322, -0.584302783, 1.3145704269, 0.2922441363, -0.4884521663, 0.1748099029, -0.8954635262, + 0.8497131467, 1.3345705271, -1.585932374, 0.182864368, 0.0375167504, 1.4893962145, -0.8841351271, 0.1239212006, + 0.1301903278, -0.217044428, -1.4712740183, 0.2646017671, -0.1447753906, 0.9968265891, 0.0993815586, -0.6090484858, + -1.3570221663, 0.7227269411, -0.0219510533, 0.7023817301, 0.042994421, 1.1319042444, -1.002949357, -0.9856308103, + -1.9643776417, -0.6212342381, -0.5674418211, -0.2722060084, 0.576230824, -1.7308312654, -0.1668733805, -0.3293681741, + -0.3582380116, -1.141156435, 1.1042435169, 1.644451499, -0.4203042686, -0.7046890855, 1.9541190863, -1.5065824986, + 0.1620152444, -1.4102603197, 0.4765975475, -0.2991090417, 1.2118850946, -0.3334017396, 0.3071345687, -0.6667149067, + 1.2665424347, -1.2411324978, -0.3781921864, -0.1119469181, 0.0351102464, -0.1019369289, 0.071337916, 1.8285521269, + 1.1005022526, 0.3116882145, 0.7197256088, 1.1275570393, -0.1129998118, 0.3050722182, 0.1734147966, 0.2428309172, + 1.0162949562, -0.5538579226, 1.0453534126, -0.2064165026, 0.2954626679, 1.1894056797, 1.696747303, -2.0918354988, + -0.5620151162, -0.6162993908, 0.1899436861, -0.1020427197, -1.0234582424, 0.4789095521, 0.0332386084, -1.4767955542, + -1.9037156105, 1.2354108095, -0.0018077961, -0.9863997698, -1.2346477509, 1.8885161877, 0.2936889231, 0.8233779669, + 0.0891269967, 0.4238564074, 0.4432381392, -0.854845345, 0.342248708, 1.925044775, -0.845469892, -0.6730789542, + 0.1415164173, 0.1184886545, 1.3533905745, -0.2967815101, 1.1134816408, 1.2478499413, 0.1484726369, 0.7938684225, + -0.0986338928, -1.1890305281, 0.2958755791, 0.1388797909, -0.6163766384, -1.4716683626, 0.820707202, -1.1493715048, + -0.217831865, -0.9332431555, 0.0315085016, 1.5580168962, -0.3341762424, -1.3798252344, 1.9283100367, -0.2898777425, + -0.9559110403, 0.7655615211, -0.431720078, 0.4280168116, 0.7353171706, 1.480581522, -0.273019284, 1.7999408245, + -0.6273670793, -2.6943187714, -0.6990944147, 1.1060009003, 0.8578431606, -0.0840007663, -0.5585980415, -1.2817488909, + -2.4378654957, 1.6060805321, 0.8997866511, 0.6551699042, -0.3740907013, 1.3194372654, -0.4168642759, -0.8414853215, + -0.7929033041, 0.3561357856, -0.3539623916, 0.277975589, 0.4590013325, 0.5880220532, -0.2773589492, -1.8300926685, + 1.2118127346, -1.0504593849, -0.900460422, -0.0812280998, 0.269687742, 0.0787571594, 0.1149807945, 1.3142724037, + -0.1294342428, -1.7291231155, -0.0914452523, 0.1939240694, 0.6503858566, 0.3664641976, 0.7926014066, -0.2039321363, + -0.4512749016, -0.5041785836, 0.1370467991, -0.3436326385, -1.7019400597, 1.3645384312, -1.0790003538, -0.0885153338, + 0.727312088, -0.096284613, -0.3853226304, 0.9186987877, 1.6411539316, 0.0192694329, 0.9914398789, 1.0116108656, + -0.2402564734, -0.2873272002, -1.0821862221, -1.9422683716, -0.5636457205, -0.9914990067, 0.7986121178, -1.1720125675, + -0.8651517034, -1.0168634653, 1.3929049969, -0.5326869488, 0.2972522676, -0.7363356948, -1.0323220491, 0.2945378721, + 1.2807190418, 0.2211526334, -1.824688077, 0.2985337377, -0.1622590274, -0.5336527824, 0.5530636907, 0.9003993869, + 1.0602345467, 0.5563013554, -0.4820825756, -0.374138236, 1.2548416853, 0.5277336836, 1.0442218781, -1.0164369345, + 0.9119832516, 1.8069756031, -0.845316112, -0.6892279387, -1.9548838139, 0.5399494767, 0.5839894414, 0.6357702017, + 0.4068482518, -0.8281987309, 0.7952207923, -0.5682151318, 0.6527551413, 0.4371876717, -0.8736358881, 0.7888579369, + -0.2305625677, 0.3886904716, 0.4261684418, -1.7041398287, 0.1460140944, -1.3941833973, -2.3413891792, 0.3794504404, + -1.5065003633, -1.0899549723, 0.5814636946, -1.8431659937, -1.9167656898, 1.0604321957, -0.6192001104, 0.1313293129, + -1.9399279356, -2.5218393803, 0.8841423988, 1.4313941002, -0.0698332638, -1.7999757528, -0.5638673902, -0.0389924608, + 0.8049888015, -0.9703688622, 0.3512552083, -0.2308388054, 0.104415521, -1.266988039, 0.4026793242, 0.9971115589, + -1.0468974113, -0.1251971573, 0.112914592, -0.6320928931, 0.7838298678, 0.4312362075, 1.1978577375, -0.6947177052, + -0.2477532178, 0.4473966956, 1.3458278179, -1.3238114119, 1.2147200108, -0.3629972637, -0.1120925844, -1.6106210947, + -0.6715474129, -0.3695737123, -2.1063737869, 0.3464091718, -0.1429023743, 0.0154739022, 0.2679836154, -1.359157443, + -0.4414421618, -0.5401853919, 1.2818124294, -0.8664167523, 1.2607386112, -0.5515830517, 0.0223816186, -0.9567921758, + 2.1468987465, 0.4018232524, 0.3902551234, 0.2271844745, -0.7034388781, -1.1465339661, 1.3632919788, 0.7479792237, + -1.4447779655, -1.314964056, 1.6014412642, 0.8386735916, -0.9777460694, 0.0764696151, 0.8212373257, 0.7903966904, + 0.209495768, 1.1794633865, 0.3876317143, 0.29455176, -2.288343668, -1.4445925951, -0.0050359364, -0.0154747693, + -1.0497438908, -2.1858596802, 0.3199483752, 0.4688971639, 1.3384841681, -0.1049553305, -3.510409832, 0.013980289, + -1.0582283735, 0.0157511942, -0.1317526698, 0.5070823431, 0.2266791016, -1.0741680861, -3.3275530338, -0.1029340774, + 1.3333551884, 0.1533930302, -1.3400937319, -2.1410186291, 0.6519215107, 0.0122133074, -0.089711912, 0.708886683, + 1.3721456528, 0.7374876738, -0.1000189185, 1.3357746601, -1.413944602, 0.6488098502, 0.5202904344, 0.3015293181, + -2.3389220238, 0.8091678619, 0.697851181, 0.9705064893, 0.3247336447, 0.0050228359, -0.807038784, 1.5278664827, + -1.6689298153, 0.723526895, 0.3391357362, -0.4543726444, 0.7102225423, 0.0603245422, -0.2386469692, -0.1376174837, + 2.226290226, 0.79782933, -0.1623223573, 1.3508191109, -1.1919469833, 0.5105102658, -1.2463465929, -0.7253215909, + -1.5177099705, -1.8005180359, -2.0953040123, -1.4494000673, 2.0138463974, -0.9422380328, 0.4424597621, -0.139709577, + -1.1371566057, -0.0423600972, 0.193037346, 0.2709112763, -1.1953920126, 0.5570302606, -1.5900931358, 0.485673666, + -0.5310302377, 0.1510527581, 0.3505887687, 0.6495220065, -0.3104924262, -0.2100895643, -0.6556578875, 0.0484873876, + -0.494926095, -0.5762988329, -0.0790554658, -0.8858715892, -0.7482577562, 0.4565393925, 0.8495110869, 0.5410699844, + 0.2003258765, 1.1066104174, 2.4233675003, 1.174393177, -0.3243298531, -1.0906335115, -1.0359903574, 1.1506870985, + 0.8038827181, 0.0065249666, 1.2016972303, -0.4348216951, 0.4592243135, 0.9285517335, -0.9519800544, 0.9002231956, + -0.0417470746, -0.6550382972, 0.3652853668, -0.4817460179, 0.4155755043, 0.2305550873, 0.0383341387, -1.380209446, + -1.0148710012, -0.4687513411, 0.24660936, -0.0788045675, 0.3197855353, 0.0394861288, -0.9513927102, -0.0540379882, + -0.9681669474, -0.632435143, 0.1304977834, -0.1444966942, 0.4706237316, 0.3779866993, 0.2013960183, 0.22346811, + 0.4384725988, 1.8610857725, 0.1288777292, -0.5215864182, -1.0086157322, 0.7050257921, 0.7817319036, -2.3805580139, + -0.2110639066, -0.3800990283, -1.5330798626, 0.8230214119, 0.2022407502, 1.2536604404, -0.3143420517, -0.3846403956, + 0.8717328906, -0.2717157006, 0.221435681, -0.7705176473, 0.7046155334, 0.6591244936, 0.0442096666, -0.8060303926, + 1.8267966509, -0.2754566073, -0.8256037831, -1.5357751846, -1.0315228701, -0.8241909742, -1.0270508528, 0.3138917387, + -1.6600333452, -0.3888295591, 0.0759017095, -0.5470116138, 0.9134837389, 0.918176651, 0.6794993877, 1.8896580935, + 1.2877893448, -0.575420022, 0.1308063716, 0.6196119785, 0.2646083534, 1.3591319323, -0.1376973838, -0.4108622372, + 1.0915858746, -0.4022491574, -0.2787691951, -1.4625638723, 1.5055365562, 1.3839673996, 0.30471313, -0.1136100814, + 0.0511076674, 0.9380768538, 1.2948635817, 1.8470802307, 0.0492418595, -1.2036857605, 1.1663081646, 0.4418370724, + -0.2655751109, -0.9233930707, 0.8207384348, 0.5034034252, 0.5235258341, 0.9936625957, 1.0459955931, -0.2367948443, + 0.40023157, 1.7345780134, -1.6753051281, 0.961633563, -0.5974237919, 1.1064232588, 1.8339977264, -0.28734532, + -0.2717796862, 0.6485736966, -0.7970598936, 1.290769577, -0.1626946926, 1.3069441319, -0.6765155196, -0.8155764937, + -0.4989302754, 1.5502585173, 0.621653676, 0.3171115816, -0.9816764593, 0.2284350544, 0.1353972405, -0.7532781363, + 0.598736167, 0.284614563, 2.6697471142, 0.8273726106, 0.365691781, 0.3345196545, 1.398778677, -0.6768500805, + 0.9154971838, 0.9169610739, 0.6782941818, -2.2053909302, -0.2868286967, 1.4951024055, 1.302043438, -0.1167226881, + 0.5561181307, 1.392895937, 0.8201711178, -1.354488492, 0.7482158542, -0.9934462309, -0.7618706226, 1.5368840694, + -1.092682004, -0.754465878, -0.7657099366, -0.2162702084, -0.6240744591, -0.6869540811, -1.3244251013, -0.0615085214, + -0.2740594745, 0.7680806518, 0.5850219131, 0.7697795033, -0.8452374339, -0.2424748093, 0.8591217399, -0.1297827959, + -0.327239722, 0.5281672478, 2.8159592152, 0.0707529411, -0.0019932245, 0.7365709543, -0.1870024353, -1.0456169844, + -0.0245733839, 0.3742526472, 0.0466749147, -0.9359126687, -0.5803662539, 1.2145210505, 0.2210874259, 0.8019478917, + -1.6911070347, -0.8182746172, -0.7799111605, 1.5378501415, -0.0670324489, 0.53529948, -0.9907878637, 0.0810974091, + 0.0742879882, -2.1321122646, -0.2070179731, 1.0230563879, -1.4774166346, -0.0569191352, -1.1915849447, 1.2854273319, + 0.5736584067, -0.3161622286, 0.0788122043, -2.6321368217, 0.7516192794, -0.6747380495, 1.7880039215, 0.0600294322, + 0.8084431291, 0.8202488422, 0.7850489616, 1.7138910294, 0.8183184862, 1.3371344805, -1.070442915, 0.792760849, + -0.7731685638, -1.5480746031, 0.9363201261, -0.8637107015, -0.5787624121, 0.5742868185, 1.2831314802, 1.143130064, + -0.1921418905, -0.1575302482, 0.7531200051, 0.110766381, -0.1392740458, 0.1642324924, 1.1048551798, -1.065731883, + 1.2152526379, -0.0280989539, 1.4245631695, 0.3038326204, 1.0398333073, 0.5144931078, 1.395950079, -1.4316306114, + -0.4561814964, -0.5418317914, -1.2976498604, 1.6599001884, 0.6544582844, 0.4120349586, 0.1889998317, -2.0116407871, + 0.0190515742, -1.0315045118, -0.2084806114, -0.9521855116, 1.3717107773, 0.8201537132, 1.2848557234, 1.0412549973, + 1.109770298, -0.7424427867, -1.3213529587, 1.416277051, -0.221823886, 0.1572814584, 0.042020712, 0.8158637285, + 0.2443248034, 1.5342217684, 1.2111642361, 0.7858352661, -1.0876142979, -0.3700317442, -0.2657727301, 0.4492015839, + 0.0319982916, -1.0240249634, -2.5414311886, 0.136154443, -0.2829069793, 0.5869057775, -0.8466492295, 1.4590594769, + 0.6824162602, 1.3178961277, 0.1956192702, 1.9053285122, 0.2270766795, 0.8468378782, -1.1426655054, 0.1628837287, + -2.0766322613, 0.3954115212, -0.7994513512, 0.8160585165, 0.2688303888, 0.6566452384, 1.4310846329, 1.2181339264, + -1.1336773634, 0.7861024141, 0.60408324, 1.0225002766, -0.0625130981, -0.9539570212, -0.5392764807, -0.9254257679, + -0.8865107298, 1.5495288372, 0.3416455984, -1.4592988491, 1.1174447536, -0.8456580639, -0.2513967156, 1.6444369555, + 0.4698045254, -0.3425119817, 0.4703255594, -1.1068733931, -0.6331372857, 0.083390452, 2.050989151, 1.1461318731, + -1.4606683254, -1.3410766125, 0.0828015357, 0.8186067343, 0.3983367383, 0.0698770657, 0.4072398841, -0.0359241553, + -0.1619289368, 0.8406882882, 1.8046275377, 0.1601787359, 0.6465020776, 1.1391314268, 0.0097278478, -1.3131502867, + -0.8829632401, -0.5586873889, -0.8721792102, -1.714135766, -1.6847779751, 0.9566531777, 0.0900609344, -2.167375803, + -1.5872809887, -0.4245087802, -0.6903084517, -0.3588181734, 1.3054128885, 0.7735430002, -1.561203599, 0.064148657, + 1.72266078, 0.4291057289, -0.8341003656, 0.627165854, 0.8506008387, -0.6141491532, 1.2932060957, 1.001757741, + 0.9150823951, 0.962816298, 0.2699362934, 0.0677945018, 0.6238765121, 0.8336200118, -2.0658693314, -0.8160885572, + 0.6131067872, -0.6992746592, 0.0867898762, -0.929186821, 0.312692225, -1.0321285725, 1.1907221079, -0.8579597473, + 0.368381232, 0.0951150134, 1.479777813, 0.1138498932, -0.1657631844, 2.1404304504, 0.6909690499, 1.0141973495, + 1.3627005816, 0.960005343, -0.2231254727, 0.8661641479, 0.6439171433, -0.3375835419, -1.4438884258, 0.5471693873, + 0.2623979449, 1.4910924435, 0.1808727682, 0.0957317352, 1.1674259901, 1.0773286819, -0.8375552893, -0.1509543806, + -0.3889933527, 1.2889469862, -1.6503235102, -0.6901810765, 1.3719030619, 0.2788748145, 0.2398491651, -0.1003404036, + 0.2019098103, 0.8351427317, -0.3547764421, 0.0477411337, -0.2419873178, 1.1113913059, -2.3828821182, -0.3928278089, + 0.2063228041, 1.437874794, 0.6241122484, 0.665427804, -0.8381136656, -0.1943056434, 0.8262708783, -0.8781173229, + 0.7365460396, -0.286786139, 1.0262185335, -1.0862541199, -2.2211563587, -0.0351699404, -0.1053142026, 1.0903381109, + 0.0490656979, 0.629034996, -0.1448164582, -1.0651451349, -0.2358892411, -1.5510635376, -2.0036041737, -0.8184807301, + -0.7312480807, 1.6621870995, 0.0102839842, 0.0925677046, 1.7449682951, 1.380156517, -0.656727016, 0.5415236354, + -0.2259770483, -0.6260111332, 1.5308971405, 1.0322775841, 0.9775959849, 0.1011903435, -0.1734205186, -2.5078294277, + 1.1471949816, -1.0667153597, -0.1465885788, -1.1242318153, -0.6100597382, -1.3902848959, -0.9408340454, -0.5747480989, + -0.7050228119, 0.2044974118, 0.1679736227, -1.5893906355, 1.638485074, 0.0945908651, -0.573420465, -1.4962567091, + 0.8425856233, -0.7955751419, -0.752364099, -1.3928989172, -0.6434774399, -0.0267408527, -1.3192676306, -1.1446229219, + 0.8909816146, 0.7566283941, 0.4858905971, -0.4653729498, 0.2230161875, -0.310647577, -0.9960952401, -1.9371960163, + -0.06249981, 0.2280373722, -1.4546812773, 0.7684928179, -1.3647917509, -2.4256286621, -0.8073800802, 1.0723882914, + -0.905554831, 0.897802949, 0.3257782757, 0.6538295746, -0.2891353965, -0.1892136186, 2.2979393005, 1.4039591551, + -1.9162375927, -1.5704979897, -1.2596937418, -0.5759724975, -2.3971576691, -0.5725220442, -0.8249366283, + -0.3085795045, 0.5204046965, -1.2902706861, 2.2250847816, -1.3025299311, -0.545333147, 0.472070694, -0.6122683883, + -0.6175191402, 1.1907383204, -0.6027181149, -0.1497769952, 0.3475134373, 0.0696816221, 0.437289834, 0.6333782673, + -0.1903668344, -0.5238707662, -0.2407862246, -1.7575255632, 0.6175248027, 0.4117534757, 0.5725713968, -0.1537111849, + -0.2685767412, -0.1302557737, 0.6916129589, -1.7661845684, -1.2384231091, -1.5353415012, -0.8544256687, 0.894800663, + -0.8968293071, 0.4587621093, -0.6570677757, -0.6455622911, -0.3647587895, 0.6582919955, 0.0151019888, 0.6143096685, + -0.484900713, -0.0224776696, 0.8556644917, 2.1596455574, 2.0912363529, 0.6864846349, 1.9000794888, 0.35351336, + -0.4887687564, 0.2296750844, 1.7741783857, 0.8200288415, -2.3570518494, -0.6121400595, 1.1244128942, -1.9312944412, + 0.2823550999, 0.2266518772, 2.0878908634, -1.7262382507, 0.3788723648, 1.0462868214, -1.2126829624, -1.5116736889, + 1.8529467583, -0.1404440552, -0.1386186481, -0.7274141908, -0.9291960597, -0.7300670147, 0.5603982806, 0.3851436377, + -0.198925063, 3.1476488113, -1.4545503855, 0.2226756215, 0.6318311691, -0.5034347773, -2.0605225563, -0.2405045331, + 0.7324491143, 0.260850817, 1.1732854843, 0.3615217805, 1.1910451651, 1.1258134842, 0.823638916, -0.1661823541, + 2.0450708866, 0.1467454135, -2.3809611797, 0.4373816252, -1.4531396627, 0.8588591218, -0.1570577621, 1.0039044619, + 0.2207947969, 1.0857644081, 2.3349044323, -0.4538405836, -1.0556931496, -0.1135712489, -1.3338731527, 2.0147054195, + 0.5743921399, -0.0406258553, 1.0636233091, -0.7739616632, -0.4744435549, 0.6629287601, 0.6593925357, 0.2389109284, + 0.324454397, -2.4939632416, 0.2376910746, 0.2401821762, 0.171485275, -1.6680035591, -0.2254704535, 0.1158540174, + -1.5890207291, -0.0886749774, 0.8084253669, 0.2941642106, -0.2246614844, -0.690297246, -0.9486091733, 0.1864258349, + 1.3744177818, 1.2856972218, 0.0242699496, 0.7165759802, -0.7738999128, -1.5016100407, 1.3694467545, -0.5406073928, + -0.5955885649, 0.8310559988, 0.7758463025, 0.0332392007, 0.0597205423, 0.7009345889, -0.1214630902, -1.2265552282, + 0.955165267, -0.9825314283, -0.0588454418, 1.3474606276, 0.2749947906, 0.7564658523, -0.9267882109, 0.2939739227, + -0.7862483263, 0.3147085011, -1.0929533243, -0.4037205279, 0.1726106852, -0.9854048491, 0.8076828122, 0.533447206, + -0.5711045861, 0.227794081, -0.3884009719, 0.095830366, 0.4074799716, -0.1783480793, 0.6015118957, -0.204326421, + 0.6595416665, 0.5929055214, 0.2067304552, -0.4159007668, 0.0456653237, -1.0317988396, -0.0439903848, 0.2529656291, + -0.5262223482, -0.0891434103, -0.5803508162, 0.2372836471, 0.1403294653, -1.1127064228, -0.727186203, -0.3711755276, + 0.4906193912, -0.9802835584, -0.4931763113, -2.42309165, -0.6911710501, 0.2911610901, -0.3813099563, -0.9066234827, + 0.4782035351, 0.0682695433, -1.2720994949, -2.062091589, -2.0388426781, -0.8398178816, 0.1875489354, -0.623960793, + 0.1227937043, -0.8136839867, -0.4940828085, -0.2377815545, -1.1428968906, -1.3174897432, 0.2686184347, 0.2657438219, + -0.0437186994, 1.7247594595, -1.2954945564, -1.5489299297, -0.0903909281, -0.2665699422, 0.8504773974, 0.9000029564, + 0.1670958251, 0.236568436, -0.6508274674, 0.6521868706, -1.2457232475, -0.4461270869, 0.0367440879, 0.8848665357, + 0.4277692735, 0.4192968607, -1.8041940928, -0.8850283027, -1.4226913452, -0.1611105055, 1.5754060745, -0.7368183732, + 0.870498836, 0.5925328135, 0.3334204555, 2.306322813, 0.5068302751, 0.6421422362, 0.2884857357, -0.6937939525, + -0.4742089808, -0.5211635232, 0.5846737623, -0.6871022582, -0.5160235167, 0.4397167861, -0.1327747852, -0.3461024463, + 0.8904767632, -0.3413029611, -0.7286113501, -0.3106502593, -1.1513842344, -1.4070318937, 1.4902381897, 0.7819204926, + -0.5711467862, 0.9897950888, 1.0421978235, 0.0064553972, 0.2257383913, -0.5662776232, -1.6784616709, 0.1300082803, + 0.3907846808, -0.1842308342, -0.5939362049, 0.4409166574, -0.4065026641, -0.2743496001, 0.281380862, 0.3920689821, + -1.1994462013, -0.4680491686, 0.3003554046, 0.8930982947, 1.3606835604, -0.8178442717, -0.9329233766, 0.8158513904, + -0.2013928294, -0.7077201009, 1.0480406284, 1.7602568865, 1.076713562, -1.1549855471, -0.431877017, 0.2878724635, + -0.1249971166, 0.0026210824, -1.9303877354, 0.2099825144, -1.8180750608, -0.5248698592, 0.5573206544, -1.3221145868, + 2.1918184757, -0.1596627235, -0.7318202853, -0.3619192839, -0.2752758861, -1.1489162445, -1.013694644, 0.8739019036, + -1.1305433512, -0.6433794498, 2.3157281876, 0.4867565036, 0.2869711816, 0.7111119628, -0.7375450134, -0.2039852291, + -0.2768211663, 1.3463346958, -0.3390847147, -0.678673625, -0.7262747884, 0.8902787566, 0.9133289456, -0.2505047619, + -0.0415848196, -0.3829526007, 0.5145270228, 0.5090532899, -0.8748589754, 0.5908644795, -0.8097217083, -0.6209503412, + -1.6769145727, -0.7063034773, -0.0019511768, -0.747931242, -0.4937320054, 1.2623711824, -0.0325878747, -2.1162991524, + -1.3957357407, -0.4022807777, 0.2463667393, -0.2883108854, -1.0714792013, 1.3542736769, 0.3475864828, 1.1947330236, + 1.4123615026, 0.4734445214, -0.0291386191, -0.7498828173, 1.8264600039, 0.8586798906, 0.893532455, -1.2798057795, + -1.243432641, 1.4402679205, -0.3074516356, -0.3824082613, 0.9012572169, 1.3327422142, 2.0704622269, -0.7559067011, + -0.6273303628, -1.3138438463, -0.5460834503, -0.1313429028, 0.3516915143, -1.2709006071, 0.2318837494, 1.3678478003, + -0.5695576668, 0.9467203021, -1.0783817768, 1.8729202747, -0.0971904844, 0.0755688325, 0.0776100382, 2.0316021442, + 0.1603736281, 0.5459352136, -0.9726063609, -1.1684632301, -0.6058312654, -0.889819324, 0.2162799835, 0.2188819796, + 0.6266080737, -0.9264500737, -0.3930732012, 1.2791380882, -1.4856559038, 0.6038267612, -1.5345782042, -0.8310987353, + -1.1575284004, -1.6151446104, -0.3164165914, 1.6876577139, 0.3008544147, -0.0813643858, 2.1535699368, 0.6083881855, + 2.0528795719, 1.0854481459, -1.8040492535, -0.850327909, -0.9169733524, -0.7187844515, -0.0188348703, 0.9217076302, + -1.1328121424, -1.0641452074, 0.6557211876, 1.6046416759, -0.8734141588, -1.1367805004, 0.7530630827, -1.2990561724, + -0.088278316, 0.0793868899, -0.1091432571, -1.5902625322, 0.3879348934, 0.0378575362, -1.3857095242, 0.0273315851, + 2.5557720661, 0.2602879107, 1.6669652462, 0.0515464433, 0.2788645923, -0.4719827473, 0.6808572412, -0.5266553164, + 1.5635540485, 0.6531999111, 0.561704278, 0.3659709394, 1.2030426264, -0.3417057991, -0.3226774931, 0.9697617888, + 1.1391057968, 0.655849874, 0.2402107716, 0.1402628124, 0.0865132883, -1.1623040438, 1.4959161282, 0.4355273247, + -1.5472781658, -0.1442041993, 0.4357748032, 0.37964499, -0.1988835186, 1.2006313801, -0.3266404867, 0.4909732342, + -0.1155063435, 0.7805097103, -1.5917422771, 0.2558749318, 0.002877926, -0.9973745346, 0.3408148885, 0.690751791, + 1.7726098299, 1.2931444645, 0.0731726885, 0.0033546537, -0.5160992742, 0.9919461012, -2.0193617344, 0.0540464595, + -1.0469379425, 1.8422071934, 0.2026942223, -0.2223332375, -0.8785908818, -0.4768011868, -0.6508824229, 1.4654546976, + 1.9984804392, -0.3018554151, 0.574395895, -0.9103906155, 2.3126950264, 1.136934042, -1.1978269815, -0.5591164827, + -1.3324406147, 1.4774297476, 0.4085949659, 1.087592721, 1.2534742355, -0.2782524824, -1.2699588537, 0.2338881344, + -0.1154674813, 1.3444168568, 0.5542261004, 0.5446771979, -0.7692145109, -0.8970652223, -0.4507069588, 1.7428719997, + -0.4185885191, -2.0615775585, 0.5384839177, -0.1812524796, 0.5966222882, -0.0884481892, -1.3890218735, -0.5953192115, + -0.8984060884, 0.2904509902, 1.3895179033, -1.2992860079, 0.3779320717, -0.0900823697, 0.1684620082, -0.2983181477, + 0.7044838071, -0.308624953, -0.476674974, -1.6568388939, 0.3046866953, 1.1033426523, 0.9387074709, 0.5648691654, + 1.1102232933, -0.5370892882, 1.6050131321, 0.3298608363, 0.8434912562, 1.5994970798, 0.3545402586, -0.9816116691, + 0.5793850422, 1.8203120232, 0.6507356763, -0.6160635948, -0.4756502509, -0.1226160377, -0.4512326717, 0.9120926261, + -0.0639616176, 0.6028991938, -2.1917812824, -0.7067122459, -0.1262857169, 1.8095263243, -0.6735818386, -0.0236892402, + -1.2794020176, -0.3109898567, -0.4389147758, 0.1079273149, 1.0574131012, -0.3642730713, -0.5820379853, -0.0673111752, + 0.6866626143, -0.9802171588, -0.4072963893, 1.501737237, -1.3176370859, 0.0456849113, 0.6719582677, -0.6977844238, + -2.4139885902, 0.9166274071, 1.9176933765, 0.0757182539, 0.268637985, 1.2910649776, -0.5725409389, 0.07635355, + -2.0364468098, 0.0009822916, 1.2169647217, 0.5885798931, -0.9567729235, 0.0846289247, 1.2598075867, -1.2678459883, + 1.2660022974, 0.5127959251, -0.312990427, -0.7242843509, -0.2958310246, 0.2941564023, 0.39088431, 0.1993192434, + 0.8601083755, -0.0118097821, 2.9144937992, 0.5598602295, -0.7121825814, 0.6126078963, -0.4042938352, 0.2696480155, + 0.7432195544, -0.3382290304, -0.3175045848, -1.0074145794, -1.1684331894, 0.079642579, -0.4121067822, 0.4740624726, + 1.311409831, 1.0700200796, 0.1490948498, 0.6387857795, -1.7708073854, -0.9917168021, -2.5573399067, 0.6741188765, + -1.3366583586, -0.5455180407, -0.2197612971, -1.4311057329, -0.6745821834, -1.5028071404, 1.0440351963, 0.7176719308, + -2.6579515934, -1.0510629416, -1.2848021984, -1.3853023052, 0.4791358113, 2.5045385361, -0.4729622602, -1.2650476694, + -0.7059856057, -1.0171307325, -0.7169947028, 0.10028781, -0.3277071118, -0.2671995163, 0.5931706429, 0.2614943087, + -0.1734369695, 0.0991713181, 0.1256472766, -0.3000682294, 0.715731442, 1.0789563656, 0.2905321717, 0.0915650576, + -0.245909676, 0.9417273402, 1.1695841551, -0.4629750252, 0.6636813879, 1.2860013247, 0.1320593655, -0.4724427462, + -2.493929863, 0.8686680198, 0.798030436, 0.0212606862, 0.0895598605, -0.6142240763, 0.2135329247, 1.568374753, + -1.3909196854, 1.9122843742, -0.1695288122, 1.0792137384, 0.2949759364, 2.9196517467, 0.1250986755, -0.9956979752, + 0.8259578943, -0.4130439162, -1.5986818075, -1.3872983456, -0.3145367205, 0.1179488599, -1.7167025805, -0.3398543596, + -0.2405494601, 0.1653799564, 2.2529299259, 0.15278171, -0.0522611253, 1.6368466616, 1.5746954679, -0.6853815913, + 0.783439815, -0.4030088484, -0.9495356679, 1.5865054131, 0.013678316, -1.1354285479, 1.209961772, -0.7505401969, + -0.3670379817, -0.9019443393, -0.0718230233, 0.3455559909, -1.0303230286, 1.2956593037, -1.3617696762, 0.6880182028, + -1.8390884399, 1.1746094227, 0.204252556, 1.8721073866, -0.2429490089, -0.9037572145, 0.4598532319, 1.4084200859, + 1.4145408869, 1.2590812445, 0.4491093755, -0.2917197943, -0.1804877669, 0.3747444153, -1.2223923206, -0.0042179539, + -0.0286030844, -2.1629972458, 0.8808540702, -0.4634902477, -0.4097259641, 0.1188818812, 0.8841651082, -0.7411962748, + 1.3089855909, 0.2433037907, 0.2072167397, 0.0030417852, -0.4322900772, 0.0580277666, -0.8421820402, -1.122734189, + -0.4095312059, -0.6351722479, -0.9240295887, 0.1515339166, -2.7080621719, -0.8268998861, 0.6793233752, 0.0793776214, + 1.547483325, 0.0869547799, 0.4061647654, -0.117038846, 0.753239274, 0.2103636712, 0.2250218242, -0.3768270612, + 0.3614977598, 0.9480288625, -1.6463083029, 0.4892472327, -1.7122375965, 0.5919700861, -1.829749465, -0.3791226149, + -0.4474929571, -1.0941311121, -0.6403060555, 0.1746183336, -1.7660150528, 0.0863045081, -0.5001140833, 0.6139918566, + 1.6994225979, 0.1999011487, -1.9983192682, -0.7136126161, 1.4435380697, -1.1255981922, 1.4526222944, 0.5327004194, + 0.0478152595, -0.1422421634, 1.5422103405, -0.4843623638, 0.5077458024, -0.4235121012, 0.4101985395, 0.2985644937, + -0.4474204183, -1.4437913895, 0.0946096405, -1.0242272615, 0.3150271475, -2.1535305977, -0.0214283168, 2.2918503284, + 1.6116689444, -2.050137043, 0.4185002446, -1.2304670811, 0.594556272, -0.4853458703, 1.2488714457, 0.2259249687, + -0.190879941, 0.0583935194, 0.4459559619, 0.4773775935, 1.6011041403, 0.7079492211, 0.4374597669, -0.5841044784, + 0.9688305259, 0.8779850006, -0.0789694786, -0.1578722596, -1.8777650595, 0.055707477, 0.2137283534, -0.0753122121, + -0.5718395114, -0.6800060272, 1.3663361073, -0.330904752, 0.4557212293, 0.444932729, 0.9501424432, 1.0727024078, + -0.9129831791, 0.7791337371, 0.8639063239, -0.7943357229, 0.9940410256, -0.117501393, 1.6619648933, 1.3453713655, + 0.1633823812, -0.1596832424, 1.5186958313, 0.9925870895, 0.7669295073, -0.2227122933, 0.9052174687, 0.1742046773, + -1.8046705723, -0.3167853653, -0.406090349, -0.3562828302, 0.9901017547, 0.5220876336, 1.082859993, -0.933524251, + -0.8265603781, -0.5601838231, -0.1037390828, -0.034783937, 0.8033310771, -0.7626441717, 0.1769310981, -0.8562979102, + 0.6401655078, 0.4897463024, 1.2890980244, 0.3583827019, 1.1658328772, -0.0718992352, -0.8952594399, -1.3356628418, + -0.9950582385, -0.6626952887, 1.5818070173, -1.613748312, 1.6730548143, 1.0554708242, -0.7988551855, 0.1265448183, + 1.4124367237, -0.472415477, -0.9337536097, 0.8365861177, 2.3900251389, 0.822938621, -1.1517981291, 0.69485116, + -0.148211211, -0.5633614659, -0.3132559359, -0.199488461, -0.8831216693, -0.1983086616, -1.2630894184, 0.5556268096, + 0.9699519873, -0.1344390661, 0.5338910818, -0.843167305, 0.2585937381, -0.5014234185, -0.9196692109, 0.6794525981, + -0.4677133858, -0.3580030501, -1.004778266, -0.4246050119, -0.8890936971, -0.1875797808, -1.3680918217, 2.4937102795, + -0.2065069526, -0.3412998319, 0.9275464416, -0.6399300098, -1.0326942205, -1.2631584406, -0.7057926655, 0.2132282406, + 0.1349920183, -0.0767279118, -0.0180238225, 0.9167872071, 1.2965246439, -0.4996848106, -0.1523783654, 1.3595687151, + 0.5616595745, -1.2922233343, -0.2067446113, -0.0955479667, 1.0408117771, 0.2260160744, 1.5209286213, 0.7850476503, + 1.2328828573, 0.457786411, -1.0894739628, -0.5421277285, 1.8188209534, -0.4353050292, 1.0453416109, 0.9334639907, + -0.8626065254, 1.1428796053, 0.4184126854, 0.8542534113, 0.2786234617, 2.2667417526, -1.342291832, 0.0365474224, + -0.6399766803, 0.2765336931, 0.6240792274, 0.941911459, 1.2190315723, 0.9540512562, 1.8149379492, -0.5880147219, + 0.5229048133, -1.8234910965, 0.5798783898, -0.4019498825, -2.4706156254, 2.2076125145, 0.0733084604, -0.8490743041, + -0.1897683442, -0.0908034369, 1.368440032, 0.3928494453, -1.5093868971, -0.9352346063, -1.6818646193, -0.3056127131, + -0.9864490628, -0.1267329901, -3.4295580387, -0.8379977345, -0.2364562154, -0.0146869794, 0.29027161, -0.3721041679, + -0.5221943855, 0.1014696434, -0.0193115585, 0.1473674327, -1.5494464636, -0.53990376, -0.0246628616, -2.0717842579, + 1.0729697943, -1.1848657131, 0.438480705, -1.310859561, -0.8152757883, -0.1412737817, 1.5141129494, -0.1638685614, + 0.858568728, -1.1072340012, -0.8543540239, 1.069614768, 0.1962230355, -0.1166522354, 0.4228607118, 0.3876480758, + -0.2862882912, -0.9716600776, -1.0824446678, -0.5052465796, -0.0500417948, 1.0491191149, 0.8568240404, -0.6495133638, + -0.3671525717, 0.0186419897, -1.5158751011, -0.0458600409, -0.4317787886, -0.0550946295, -0.8744986057, -0.1637722999, + -1.1921287775, -0.5725089312, 1.6396950483, -0.193561092, -1.8141798973, 0.5524504185, 0.0224844627, 1.7025898695, + -1.1939163208, 0.0611830056, 0.4557733834, -1.805393815, -0.1088439003, 1.3869347572, -1.3557333946, -2.6577615738, + -0.5621011853, -1.5449957848, -1.434699297, 1.6745887995, -0.708704412, -1.1405794621, 0.8468211293, -0.6259702444, + -1.0013346672, 0.8264898062, -0.0107424371, -0.0377501473, -1.6358803511, 0.1592251062, -1.2914931774, 0.4267860949, + -0.0591404252, -0.3762255311, 0.7003886104, 0.3074934483, 2.0389971733, 1.0119352341, -0.8226264715, 0.1964271665, + 0.6776129007, -1.9366357327, 0.2702591717, -0.7943894267, -0.5161536932, -0.9527539611, -0.15516451, -0.3698361218, + 0.5130124688, 1.6964564323, -0.406580776, -1.2760372162, 1.2567688227, 0.0966834277, 0.5076339245, 0.3789902031, + 0.8715313077, 1.5521655083, -2.2539381981, -1.0728610754, 1.2374900579, 0.6128914356, -1.1944071054, 1.9067157507, + 1.6737689972, 1.1818349361, 0.3899155259, 0.4014538825, -0.5103981495, 0.1652175784, -1.9009075165, -0.2527178824, + 2.0375125408, 1.6334018707, 0.099087745, -0.2214143127, -1.241792798, 1.4322711229, -0.8110809922, 0.6237356067, + -0.860029757, 0.9621957541, -0.1469984949, -0.7951014042, -1.2351981401, 0.3188866675, -1.0440903902, -0.9646935463, + -0.4229103625, 0.4964722693, 0.1531331837, 2.7971539497, -0.3278644085, 0.5300644636, -1.1382143497, 1.2793962955, + 0.2531116009, 0.8383103013, -2.0147705078, 0.6147590876, -0.2501372099, -1.67981565, -1.167953372, 1.9104994535, + 0.7335022688, -0.6242956519, -0.1997241825, 0.6580860019, -3.543803215, 2.2302262783, 0.2623988092, 0.4263668358, + -0.5162287951, 0.9116119742, 0.753780067, 0.814756453, 2.0275216103, -1.0469170809, 0.0447648279, 0.4066671729, + 1.4574295282, -0.5511431098, 0.1064528897, 2.2086167336, 1.0268939734, -0.6577744484, -0.1552726179, -0.0653077587, + 0.8309588432, -0.2720114291, -0.4248123765, 0.4521262944, 1.821269989, -0.2710549235, -2.6737802029, 0.8627644777, + 0.414057672, 0.7305349112, -1.1009577513, -0.0405872762, -1.7268170118, -0.9778028727, -0.3233233988, -1.1608653069, + 0.010632378, 0.0213840399, 0.5337206125, -0.5303680301, -1.8097007275, 1.0664070845, -0.0200915802, -0.8092259169, + -0.6417803168, -0.2247069329, 0.2727496624, -0.017360365, -1.0712687969, 0.225125894, 0.0471394435, -0.0443964601, + 0.7301927209, 0.3327662051, -0.1669893563, -0.0900482908, -0.1879023314, -1.1513732672, -0.3616277277, -1.6583201885, + -0.1897500455, -2.0509023666, 1.4391367435, -0.3599698842, -0.6990902424, -1.3491034508, -1.0897932053, -2.0706076622, + 0.7112004757, 0.0375067219, -0.6403739452, 0.4059659839, 0.6470164061, 1.8503149748, -1.6849238873, -1.3065844774, + 1.0666915178, 0.994643867, -0.6309731603, 0.2481388897, -0.6018763781, -2.1274530888, -0.4725838006, 1.338709712, + -0.3620197475, 0.4139246047, 0.5800728798, 0.0942340717, -0.3209901452, 0.0889385194, 1.1412287951, -2.3286304474, + -2.0180230141, -0.7359105945, 0.4361290336, -0.393599093, -0.9925333858, 0.5121065974, -1.0553890467, 0.0176953413, + -2.181075573, 0.4622453153, -0.2540527582, -0.7596648932, -0.0581332184, -1.7947191, 1.0270496607, -1.2321225405, + -0.3689308763, 0.6238868833, 0.1727206409, -2.8847465515, 0.2620530725, 0.9489654303, -0.3782636225, -0.2526799142, + 1.0940079689, 1.0400370359, -0.4539102912, 1.4904272556, 0.3527225256, 1.2626172304, -0.8670571446, -0.3333664834, + -0.3730029464, 0.2025904655, -0.332624644, -1.2971646786, 0.9655994773, -0.1379029453, 0.7102864981, 0.8918810487, + -0.9970547557, -1.4230805635, 0.8162118793, 0.7776215672, 0.1969143003, -1.3174074888, -0.584411025, 2.4673445225, + -0.5167017579, 0.6806137562, -1.1483550072, -1.0401893854, 1.7456251383, -1.6846861839, -1.0622183084, -0.0755550563, + 0.6051344872, 1.4599839449, 1.8236228228, 0.0921196342, 0.3357533216, -0.5934019685, -0.3730606437, -0.0822857097, + 0.665253222, 0.9473050237, 0.1076403409, -0.1182667017, -1.6469464302, 1.0899176598, -0.7156873941, 0.5861592293, + -0.8050276041, -1.7994321585, -0.5858718157, 1.1953302622, 0.8592127562, 0.5409115553, 0.5861743689, 0.9212389588, + -0.5880656838, -1.4463483095, -0.1815917939, -0.4911633432, 0.5372625589, 0.745003283, -0.7984898686, 1.067766428, + 0.8281040192, -1.918967247, 1.7005119324, 0.1223435998, -0.8320993185, 0.2740614414, 0.7001248598, -0.168896392, + 0.5390168428, 0.7814664841, -0.6030362248, 2.4221360683, 1.215541482, 0.1503422856, 1.1967055798, 1.4468495846, + -0.4375343025, -1.6593545675, -0.2992757857, -1.3680181503, -0.270593226, -0.8648747206, -1.6523784399, 0.6376203895, + -0.4645305276, -1.8024930954, 1.7780036926, 0.6793705225, -0.350246489, -0.3452021778, 0.7236866355, -0.081337899, + 0.4103395045, 1.2789365053, -0.8342955112, 0.2764317095, 0.1251170337, -2.4885394573, 2.0236468315, 0.4303716719, + -1.5654964447, -0.2343400568, -0.624237895, -0.0403054543, -1.211574316, -0.1085954681, -1.2910075188, -1.7384176254, + -2.4113729, -0.097853601, 0.6314791441, 2.3066551685, -0.3984035254, 1.6925071478, -1.2291654348, 0.4835025668, + 0.5373200178, -0.6602330804, -0.3534172177, -0.865768671, -0.0444904864, 0.1402515024, -1.3653799295, -1.6854676008, + -0.6546943188, 0.711402297, 0.3269849718, 0.7538878918, 0.8704966307, -0.2834851146, -0.368555367, -2.0719401836, + 2.0501718521, 1.5302041769, 0.1144342571, 0.0451931544, -0.3070267141, -0.479450196, -0.6803899407, 1.5648218393, + 0.6181089282, -0.7039632797, 1.2172878981, -1.4121437073, 0.5843098164, -0.1053195447, 0.5416721106, 0.3049403727, + -0.6772118211, -0.9164791107, 1.6576575041, 0.3724136651, 0.6646793485, 0.4738456309, -0.663623333, -1.9127037525, + 0.4893687069, -1.0458182096, 1.0213255882, 1.1951941252, -0.0156067144, -0.6898881197, -0.3947982192, -0.3666029871, + -1.5148080587, -0.8758003116, 0.0948660448, -2.5608656406, 0.7091881037, -1.9902096987, 0.204689458, 0.7916052938, + -1.756098032, 0.3696931303, -0.7017374039, -2.283413887, 0.0468963534, 1.396275878, -1.0620392561, 1.0181268454, + -1.5523796082, 0.8203259706, -0.3706235588, 0.2112499028, -0.8861809373, 0.9715576172, 0.0313248895, 0.3653339744, + 0.0832739323, -0.4625202119, 0.3381362259, -0.2845149934, 0.0662649721, -0.9863808751, 0.0047100959, -0.0938413143, + 1.2307792902, -1.4328401089, -0.2935240567, 0.2290964574, 0.844530642, -0.2453528792, -0.2585487962, 1.1594229937, + 1.3921138048, -0.6235087514, 0.7814606428, -0.7613408566, 0.0034697903, -0.2389897704, -0.3329078257, -0.2609840333, + -0.2696022391, -0.9208405614, 0.2603013515, 0.999586761, 0.0641251057, 1.4203132391, 0.7948572636, -0.6019089222, + 2.1973364353, 0.9349791408, 0.3494509459, 0.1695573479, 1.1671073437, 0.6311008334, -0.5451691747, 0.0396844149, + -0.1348823607, -0.7637632489, 0.995783329, 0.3538493514, -0.9998304844, -0.306956321, 0.0764340535, 1.2341115475, + -0.4459015131, -0.8853935599, -0.1158692837, 0.3361707628, 0.5471341014, -0.7158341408, -0.7225044966, 1.5734320879, + 1.5906124115, 2.3091294765, 0.505084455, -1.672390461, 0.1712281853, -0.2585093677, 1.0001472235, 0.5437983274, + -0.0820056647, -0.0909900889, 0.0230511352, 0.7223117948, -0.7696962953, -1.0347841978, -1.2189891338, -1.9741156101, + 0.9746890068, 1.5432999134, -0.9736856222, 0.405692637, 0.4569702744, 0.8798183203, -1.0623204708, 1.8637923002, + 0.37634781, -0.1089622602, -2.6937398911, -0.3388677537, -0.3510338366, 1.09327209, -0.4909926355, -1.4203675985, + -0.1821767986, -1.2154457569, -0.7117774487, 0.4508901238, -0.7958429456, 0.2701161504, -2.1759605408, -0.6888856292, + 0.1048809215, 0.3557719886, 1.4286407232, -0.9892821908, -0.9702765942, -0.3957818449, -1.2025412321, -1.6958194971, + -0.4899291694, 1.2200242281, 0.2535707057, 0.3699500263, 0.144706279, -1.5934619904, -1.171613574, 1.2759325504, + -0.8569272757, -0.6799893379, 0.8412258029, -0.3783779144, 0.6456711292, 0.7831376195, 0.2905963957, -1.3606551886, + -0.8964964747, -1.4888651371, 0.7162798047, 1.028906703, -0.8015437126, -0.1136556342, -0.2551667094, -0.6595488787, + -0.2111678421, 1.4372746944, -1.0267357826, -0.5512586236, -0.8835692406, 1.0588902235, -0.1691202819, 0.426189065, + -0.9193620682, 2.5551671982, -0.7390261292, 0.8471983075, -0.4127860069, 0.3208262622, -0.6716014147, 0.8648295999, + 0.0461724885, -0.8361611366, 0.4000117183, 1.2253652811, -0.8352629542, -0.4399746954, 0.2978938818, -0.6611793637, + 0.4268187284, -0.305351913, 0.8972523808, -0.3825258315, -0.2013663799, -0.3409064114, -1.400936842, -0.0572384521, + -0.8031398058, 1.5172399282, 0.6763442755, 1.4432848692, -0.2264365107, -1.4626077414, -0.1477045119, -0.3010220528, + -0.4390170574, 1.0616732836, -1.6102832556, -0.2703692913, 0.1356078684, 0.2474282086, 1.671178937, -0.138667047, + -1.0705966949, -1.0397030115, -1.6174699068, -0.1875222772, 0.3125074208, 0.7058945894, 1.6676181555, -0.8247151375, + -2.6883125305, -0.0254399497, 0.2976902723, 0.7683712244, -0.2267342806, -0.0494219884, -0.6753277779, 0.7129440308, + 0.3559135199, -0.3811956644, 0.9569373131, 2.0430958271, 1.715926528, -2.7088499069, 0.4763430059, 0.6436210275, + -0.3214740455, -0.0530350506, 0.8985423446, -0.578335464, -0.6321326494, 1.0727838278, -0.5652558804, 1.949313879, + 0.1443732232, 0.7849040031, -0.9399734735, -0.071398057, 0.8070620894, 1.4234772921, 0.637429893, -0.2836876512, + 1.9719129801, 0.2325410694, 0.8821958899, 0.3814108372, -0.2397420704, 0.1884869784, 1.9887346029, 0.9581700563, + 0.6938206553, 0.8666102886, -1.2881469727, -2.567732811, -1.0640289783, 0.3348835409, -0.0858363882, 0.4353652298, + 0.1455067396, -1.4057297707, 0.2277472913, -1.1727318764, -0.6120919585, 1.2771542072, -0.8003570437, 0.6429291368, + 1.9732037783, -0.7130243778, -0.1332945228, -0.2530682981, -0.2103462666, 1.7769855261, 0.3102103472, 0.1589248031, + 0.8054945469, 1.4725772142, 0.6171528697, -2.360347271, 0.2448849529, -0.0658212975, -0.4911062121, 0.3746935725, + -0.7771610618, 0.5732238293, -0.2027808279, -1.3332324028, 1.349496603, -0.3272345364, 1.5416948795, 0.395889461, + -0.5925759077, 2.2976679802, -1.9548562765, 0.716986239, 2.1682713032, 1.2674481869, 0.0668742955, 1.0733947754, + 0.7876006365, -0.4546663463, 0.0326386094, 0.0436380059, -1.1151885986, -0.2926286459, -0.2934510708, 1.1921510696, + 1.5980594158, -0.8130311966, 1.1409503222, 1.3313578367, 0.8444764614, -1.2648280859, 0.9731772542, -1.1700046062, + 1.0548166037, -0.5340769291, -1.8655465841, 0.1589542329, 1.6472337246, -1.118205905, 1.2130138874, 1.1797075272, + 0.5020463467, -0.7686650753, -0.1314456314, -0.7434322238, -1.5818883181, -0.6749847531, -0.0076208692, 0.7187939286, + -0.5591735244, -0.6265111566, -1.3190778494, 1.090613246, -1.0671056509, 0.0342655107, -0.4741897285, -1.1158161163, + -0.2803910077, 0.5985125899, 0.5886665583, -0.1324573904, -0.8394958973, 0.0530796871, 1.2963345051, 0.0079052718, + -0.9098715186, 1.1129853725, -1.6644388437, -0.6847685575, 1.1993128061, 2.5089540482, -0.3476056159, -1.9554597139, + 0.579816401, -1.9721982479, 1.0853871107, -0.3682597578, 2.2866818905, 1.1455234289, -0.002616741, 1.1169599295, + 1.3755278587, 0.5090430379, -0.6836943626, -0.4428147078, -0.0736249387, 1.4757091999, -0.8413479924, -1.172488451, + -0.7022691369, -0.3636963964, -1.044085741, -1.0499132872, -0.9251657128, 0.4470546544, 2.1343755722, -1.0937464237, + -0.3145466745, 0.0791752636, 1.8015995026, -1.1708307266, -0.3710770905, 0.0021474429, -1.2492738962, 1.2540581226, + -0.3887788653, -0.0979342535, 0.6381052732, 0.5091582537, -1.3069186211, -3.2205343246, -1.6814134121, -0.2490135878, + 0.6927216053, 0.3460028768, 0.416169852, 1.7263311148, 1.3670994043, -1.2537178993, 0.822396934, 0.1540791988, + 0.4974704087, -1.4824185371, -1.3710247278, 1.9001389742, 2.0547459126, 0.4271369278, -0.3725138009, -1.3944122791, + 0.2006481439, -0.2336889803, -0.9436457157, -0.6381720901, 0.3321398199, -0.2137336731, -0.637645185, -2.6190822124, + -1.4501197338, 1.065661788, 0.6423869729, 0.3586390316, 0.0616030321, -1.3555532694, -0.693508327, -1.4561247826, + -0.6963708401, -1.9475837946, -0.1860286593, -0.921077311, 0.7253800035, 0.7981371284, 0.4483519793, 1.6668821573, + 0.1371351928, 1.3965914249, 1.5389333963, -0.6738855243, 0.744081378, 1.6378698349, 2.2377979755, -1.6630915403, + 0.6449002028, 0.0226498768, -1.0483651161, -2.1157052517, 0.7034059167, 1.0860549212, 0.6332697272, 0.5163491964, + -0.7699266076, 1.0532444715, -0.2817136347, -0.1954266131, 0.646643281, -1.1061758995, 0.4786778092, 0.6414473653, + 1.2876604795, 0.5732532144, 0.3575452566, -2.2497246265, 1.2791950703, 0.500406146, -1.9408650398, -0.5976858735, + 0.3575026095, 0.2238463461, 1.0250608921, 1.5798437595, -0.7968079448, -1.54395473, 1.2245321274, -1.3009462357, + -1.3025891781, 1.0694528818, -0.6745738983, 0.0826234743, -0.1688699126, 1.3309227228, 1.3732751608, 0.7255052924, + 0.2665914893, 1.3750485182, 0.0715328604, -1.1448044777, 1.1675745249, 0.2949744761, -1.184378624, 0.142385602, + -0.6588349342, 1.2551316023, -0.1594646573, 0.6699225903, 0.6179960966, -1.7483422756, 1.3339719772, 0.3029723167, + -1.1223556995, -0.4683272839, -1.6160479784, -0.3782319129, -0.7951239347, 1.4735752344, 1.6484818459, 1.988049984, + -0.1242350116, 0.1590626389, -1.8769822121, -1.027700305, 0.3765939772, 2.0874798298, -0.9381197691, -0.2639953792, + -1.9528026581, -0.3390138745, -1.9990794659, -0.6516773105, 0.9337078929, 0.6412097812, 0.4076411426, 0.008739274, + -2.6370751858, -1.2452684641, -0.3792372048, 2.0947167873, 1.2018176317, 0.9371799231, 0.2011674345, -1.8033559322, + 0.5050754547, -0.563767612, 0.0107321963, 0.6286424398, 0.0492702387, -1.6498469114, 0.0104927039, -0.1102788448, + 1.2789262533, -0.2689329088, -0.9935606718, -0.8252071738, 1.4261518717, -0.1880145818, -0.9265387058, 0.4540956914, + -1.2168729305, 1.8058356047, -0.1168055758, 0.5073953867, 0.3392245173, 0.7426418662, 0.5837747455, -0.7182095647, + 0.3108665347, -0.0449238829, -0.6104008555, 0.5157542229, -0.997220993, 1.6061866283, -0.2779401541, 1.4404076338, + 2.3598353863, -0.0747601092, 0.8856165409, -0.4305108786, 2.070489645, -1.2632654905, -0.1376118213, 0.3399257362, + 0.4172295034, 0.0091022998, -0.5716640353, 1.1888803244, 0.1341378689, 0.701425612, -0.5142672062, 0.2883620858, + -1.7981014252, -1.5133697987, 0.6216871142, 0.1071367636, 0.4802518785, 0.718336463, -0.5698022246, 0.8356449604, + 1.3484818935, -0.5819205046, 0.2602949739, -0.1543977708, 1.7979315519, 0.4334428012, 0.3003485203, -0.4186342061, + -1.8175272942, 0.1426157504, 0.2628866732, 0.3613359332, -0.2564287484, -1.0144606829, -0.8692834973, 0.2546459138, + 0.5684943199, 1.2995219231, -1.7172603607, -0.2453630418, -1.2629826069, 0.7414638996, 0.2217936367, -0.9192535281, + -1.1625478268, -0.742744863, 0.6232370138, 1.4456577301, -1.3260273933, -1.3074417114, 0.3686677217, -1.728263855, + 0.1614782363, -0.8077552915, -0.5116407275, 0.9091966748, -0.8138747811, 0.8174273968, -0.2035060823, 0.1387581825, + -1.0483995676, -1.178976059, -0.141899243, 2.0072953701, 0.2946895659, -0.1563377231, 1.9827004671, -0.5443348885, + -0.6208754182, -0.0153734796, -1.0330175161, 1.5375193357, 2.0169827938, -0.8606604338, 0.7027775645, -1.1580990553, + -0.8982186317, 0.4647661448, 0.1343112588, -0.4590297639, 0.1715912819, 1.5083426237, 0.0586618483, 0.7613887191, + -0.606798768, -1.7963507175, 1.2548172474, 1.1760858297, 1.3762103319, -0.8332884312, 1.9168746471, 1.2767934799, + 1.7126957178, -0.8065787554, -1.2705796957, 0.5567392111, 0.6912044287, -0.1580438316, 2.1341280937, -0.5214887261, + 0.4928900898, 0.4675154984, -0.1240027398, -0.6425836682, -0.0069333049, -0.6486710906, -0.6996839643, 1.3014633656, + 0.2614509761, -0.2373386174, -1.3424488306, -0.4017966986, 2.2234640121, 0.6983535886, -2.3241012096, -0.9949077964, + -0.274348408, 0.5673701167, -0.8014136553, -1.0267834663, -0.3481470346, 0.2476348877, 0.0547130778, 1.3874765635, + 0.7338072658, -0.3730239868, -0.4653834701, -0.6865920424, 0.3276156187, -0.5956894159, -0.0898129418, -0.8099248409, + -0.943716526, -0.1692812443, -1.0413445234, -1.7066810131, -2.0119111538, 1.3718327284, 0.2448530644, -3.17816782, + 1.8929358721, -0.2453606278, 0.7510632873, -0.2731828988, -0.023019731, -0.6737012267, 0.8937125206, -0.3046015501, + 0.374214679, -0.1818317771, -0.4224560559, 0.4293473661, 0.0446226597, 0.2028374076, 0.6543111205, 2.0454571247, + -1.4786034822, 0.3524400592, -0.4629359841, -0.3411388695, 1.712942481, 0.4731816351, 1.0813529491, 1.3048049212, + -2.1584177017, 0.0670639798, -0.5799887776, -0.0091375699, -0.3846576512, 1.0352602005, 1.5867995024, 0.9555609226, + 0.3972346187, 0.1691245884, 0.7903192043, -0.7628286481, 0.7735763192, 3.3371245861, 0.5317189693, -1.3681658506, + 2.1529917717, 0.4164772034, -0.4630190432, 0.3562625945, -1.3067346811, 2.7096297741, 1.179417491, 1.2390013933, + -0.3905018866, -1.2902466059, -0.6624063849, 1.3344436884, -0.6159383059, -1.1763250828, 0.3439395428, -0.6466949582, + 1.2733309269, 0.5567304492, 0.1190240979, 0.4002852142, -0.1299002916, -1.4366146326, 0.5557325482, -0.3819403052, + -2.2948584557, 0.7538915277, 0.4088020027, -0.5706181526, 0.9400187731, -2.22336483, 0.2392009497, -1.452188611, + 1.496835351, -1.1174561977, 2.2601320744, -1.8304297924, 1.3039175272, -0.0048594456, 0.7367036343, -0.3838936687, + 0.5286387205, 0.1551837325, -0.4323429465, -0.6561080813, 0.5545196533, 0.5781207681, -0.3996987045, 2.3530459404, + -1.3647236824, -0.1340306848, 0.1753463745, 0.0249666255, -0.3483884931, -0.0333038643, -1.9605727196, -1.5999488831, + -1.3416832685, 0.2788104117, -0.7476895452, 0.8272824883, 0.986178875, -0.6861533523, 0.1893069595, -1.6422375441, + 0.5166320205, -0.3142879903, 2.8894968033, -0.3574573696, -0.7443041205, 1.932464242, -0.6711962223, 0.8798464537, + -1.0091282129, -0.5488491654, 1.5701944828, 0.2705782056, 0.873016715, 0.987690866, -0.0415039994, -0.6048167348, + 0.2426076084, 0.1948920041, -2.550142765, -1.7648794651, -0.0415776409, 1.1606342793, 0.3051763773, 1.4745252132, + -0.3646067381, 0.1290424615, -0.2389613539, -2.2449805737, 1.3227287531, -0.3557299078, -0.2465161532, 1.0724699497, + -0.013204244, -0.6840516329, -0.4048824012, 1.0555580854, 0.2012488693, 1.4333781004, 0.5459110141, 1.4253919125, + 0.1036763117, -0.8666305542, -2.1211733818, -1.3604879379, 1.2255884409, 1.098466754, -0.2646973431, -1.2453637123, + 1.2485244274, -0.4639970064, -0.1485658139, 0.4927731454, -1.1315159798, 0.6742309332, 0.1616810262, -0.2924068868, + -2.238001585, 1.5050231218, -1.1828123331, -1.0715100765, 0.2920324206, 0.4176152349, -0.261849761, 0.3900544941, + 1.2369613647, 2.2400150299, -0.6591055989, -0.3432904482, -0.9165864587, 0.3899152577, -0.8128656149, -0.6911546588, + -1.8697581291, -1.9872611761, -0.8085523844, -0.0751557872, 0.2399503887, -1.3846840858, -0.1106751859, 1.8108611107, + 0.2479185611, -2.0952146053, -0.0888442099, -0.1570831537, 0.0162983797, -0.7323496342, 0.9778578877, -0.4015278518, + 1.5470517874, -1.1965001822, 0.5501039028, -0.3973948061, -0.5402927995, 0.1135616377, -1.1342197657, 1.5787736177, + 0.7312040925, 1.3263958693, -0.9830656648, -1.5166749954, 1.2743954659, -1.6303781271, 0.5302878618, 0.4884847105, + -0.0564946122, 1.4196146727, 0.0485945493, -1.6874896288, 0.0264888797, -2.2721157074, 0.5597230196, 0.0342372134, + 0.3025023639, -1.1467289925, -0.1418615282, 0.4835216701, -0.4516725242, 0.2854830325, -1.2665178776, 1.5576566458, + 1.0947488546, 0.2143646628, -0.2931555212, -0.6761689186, -0.5095722675, 0.1104367077, -0.9266905785, 0.1388486475, + -1.7587862015, 1.1457693577, -1.7809176445, 1.7472233772, 0.243191734, 0.9257518053, -0.1105109155, 0.7692781687, + 0.8367552757, 0.7457382679, -1.5059551001, -0.8665480614, -0.8388282657, -1.1409242153, -0.6999360919, -0.3496262133, + 0.2825672925, -0.7251719236, 0.3119471371, 0.6827612519, 0.8235883117, -1.251296401, 0.2607354224, -1.1948734522, + 1.6742203236, 0.1868904084, 0.8913527727, -0.0905617997, -0.4602533579, -1.3090718985, 0.2370790094, -0.5549578071, + -0.3860284686, -0.3769266605, -0.3289939761, 1.2747739553, -1.1576405764, -0.7707039118, -1.100667119, -0.0534144416, + -1.0460067987, -0.0220385697, -0.0187210329, 1.0596003532, 0.4855110049, 0.9563537836, 0.6240862012, -0.2181169987, + -0.1297433525, 1.3240571022, -1.3595471382, -0.0788813084, -0.4473232031, -0.8702023029, 1.2506643534, 0.9834125638, + -1.0927263498, -0.6073045135, 0.3495458961, 0.1213660464, -0.4297527075, -0.3331126571, 0.7537350059, -1.9193907976, + -0.843812108, -1.9194872379, -0.2119607925, 1.823943615, -0.2754066885, -0.5554115176, -1.0301826, 0.7643379569, + -0.0227805395, 1.3933587074, -0.1937872171, 0.9693816304, 0.6298752427, 0.2584379315, -2.3164453506, -1.8396610022, + -0.3373851478, -0.4343889356, 0.5835508108, 0.5079726577, 0.7551559806, 0.8957632184, -0.5572155714, 1.4874306917, + -0.5413039923, 1.768809557, -0.1760699153, -0.4086333811, -0.0682857335, 1.2715420723, 1.3316938877, -0.6478120089, + 1.7098898888, -0.2466237396, -1.8732783794, 0.1492802203, 0.8813462257, -1.787643075, -1.2078424692, -0.5233929157, + -1.0958852768, 0.1002101004, 1.2844595909, 1.189183116, -1.2014337778, -2.2963385582, 0.9300718904, 0.7659554482, + 0.708158195, -1.4520958662, 1.1127053499, 0.2289859056, -0.7110806108, 0.4880263507, 1.5001052618, 1.5714887381, + 0.7933399081, -0.3028346896, -0.1017167792, 0.6995674968, -0.0198632907, -0.7587066293, 0.7734092474, -0.3478929996, + 0.0377644747, -0.6838935614, -0.7128896117, 0.5029635429, 1.9088362455, -1.1404583454, -1.6888059378, -1.8423115015, + -0.0389658883, 1.1948564053, 2.4157738686, -0.9063307643, 0.6310094595, 0.9897720814, 0.7520170212, -0.4465702176, + -1.6844987869, -1.9101190567, -2.3421952724, -0.4606425762, -0.5885396004, -1.0535298586, 0.6714470387, -2.0614287853, + -1.589578867, -0.9668141007, -1.8850803375, 1.016346097, -0.4743680656, 0.9278936982, -0.6074044108, 0.8148276806, + -0.1381165832, 1.0583986044, -1.5783662796, 0.7843630314, 0.3421233296, -0.8151394129, 0.830432415, -0.5892474651, + 0.0996279344, -0.1991706789, -2.5094156265, -1.5909996033, 0.2353384942, 0.6018269062, -0.8568947911, 0.2557218075, + 0.6682499051, -0.1879249215, 0.0074428706, 0.4798038006, -1.7355819941, 1.900359273, 1.5346397161, -0.6947375536, + -0.6060379148, 1.2424333096, -0.4308054745, 0.6093084812, -1.599724412, -1.5050390959, -0.3377222419, -1.2019016743, + 1.1436249018, 0.9114562869, 0.1259697229, 0.4765327871, 0.3271493912, 1.5688660145, -0.0834053159, 0.6043325067, + 0.0358087867, -2.0696275234, 1.1063140631, 0.7426227927, -1.2348821163, -0.2855467498, -0.1477694511, 2.1614141464, + -0.7326849699, 0.5784502625, -0.1212657541, -0.6860406399, 0.231204465, 0.7677243948, 1.4630963802, -1.4831662178, + 0.3842955828, 0.3330720067, -1.491437912, -0.6227321029, -0.6727771759, 0.4612464607, 2.0365641117, -0.8002539277, + -1.1648292542, 0.1289562881, 0.4260367751, -1.7791209221, 0.3649482727, -0.7779896259, -2.4400405884, -0.0435852557, + -0.3500059247, 1.1347149611, 0.3358536363, -1.8796350956, -0.6165884733, -0.3348190784, -0.5539978147, -0.6812824011, + -0.5439455509, -1.9715577364, 0.3464953303, 0.8795771003, 0.1512504965, 0.011326055, -0.7210302949, 0.4954958558, + 2.0371608734, -1.3999308348, 2.0279750824, 1.073867321, 0.7125077844, -1.752725482, 1.9098694324, -0.423073262, + -1.3026645184, 0.4003872573, 0.2172527611, 2.9619445801, -0.8010261655, 1.4232937098, 2.3403263092, 1.3790491819, + 0.1906539947, 1.5853165388, 0.1980482191, 0.5038337111, 1.2534674406, 1.1705026627, -0.99159199, 0.7790826559, + 0.5936439633, -0.753718257, -0.6383305788, 1.0891114473, -0.5446549654, -0.2027605176, -1.1356508732, 0.8898881078, + -1.1803863049, 0.0760592073, 0.3940411508, 0.8132078648, -1.2225940228, -0.2539710402, 0.925064981, -0.4512603581, + -0.0236611646, 0.2419966459, 0.5349957347, -0.2259923965, -0.7846670747, 0.4239006341, -0.0066497908, 0.8761689067, + -1.0638122559, -2.5720088482, -0.5335486531, -1.0095447302, -1.7223300934, -0.653532207, 1.1655402184, 1.1832163334, + -0.2269054651, 1.7193808556, -0.1380582601, 1.5151145458, 0.2277833372, 0.0959253907, -0.5170901418, -1.0309077501, + -0.4735969007, -0.0485035852, -1.1286866665, -0.7307674885, -0.546323061, -0.0409587808, 2.0975720882, 0.3434947133, + 0.9940972328, 0.3789162636, 1.0542325974, -1.8494417667, -0.4977275729, 0.7369968295, 0.5268564224, 0.1865140498, + 0.8466647863, -0.6316319108, 0.1136949435, -0.6331836581, 0.3402028978, 0.5535160899, -0.2889496684, -0.7305825353, + 0.4190462232, -1.0515617132, -0.4801098704, 0.0261303224, 1.5960645676, 0.1610219181, 1.7804647684, -0.3047503829, + -0.8188756108, -0.3621890247, 0.3808596432, 0.2823227644, 1.5666717291, 0.3734123111, -0.8837423921, -0.7322314382, + 0.1986591965, -0.0118880589, -0.715189755, 0.0778959244, 0.8643652201, 0.6962469816, -0.5422630906, -0.9411893487, + -0.8344305754, 1.1522097588, 1.3389163017, 0.0177985504, 0.5214101672, 0.6627396941, -0.0895537585, 0.320517391, + 1.108622551, -2.7512409687, 0.7842624187, 0.2301861048, 0.4868739247, 0.1914014667, 1.4830135107, 0.015636323, + 0.6475189328, 1.8308417797, 0.469170779, 0.314837575, 0.7041759491, -2.6743814945, -1.5270642042, 0.2455077767, + -0.5976601243, 0.9597811699, -0.411383003, 0.7531632185, -0.4996159077, 0.681307137, 0.766017139, -1.4191707373, + 0.3065551817, -0.1291158944, -0.497698307, -1.2929699421, -0.1371014863, 0.7562644482, 1.0583063364, -0.421266973, + -1.9234799147, -1.6065359116, -0.2558904588, -0.4901143014, -0.0949113965, 1.1031668186, -0.5381546617, 0.2360364795, + 0.0465177372, -0.3361516595, 0.127434656, 1.9163759947, 0.6101396084, -1.1195522547, -0.7814033031, 1.3373019695, + 0.2333422899, 1.0861701965, -0.0382700153, 0.8989006877, -0.021896055, 0.1018365696, -1.5967543125, -0.0113325082, + 1.1269840002, 0.055220291, 1.4069075584, -0.9980571866, 0.0247818157, -0.7040320039, 0.3176784813, 1.6605193615, + 1.0455915928, -0.8923811316, 0.9219143987, 1.1073287725, 0.7103539705, -1.4154820442, 1.0690660477, 0.1309919506, + 0.0383858383, 0.9466379285, 1.352427125, 0.8901629448, 0.4715458155, -0.1681349725, 1.7018618584, -0.4245993197, + 1.5963537693, 0.4084403515, -2.2818739414, -0.205872789, 1.1010887623, -0.7389399409, -0.277333796, -1.1447142363, + 0.57505548, 1.725002408, -0.9898491502, -0.4104329646, -1.6079535484, 0.2768232226, -1.6983526945, -0.5670870543, + 2.150793314, -0.2975871563, 2.1437575817, 1.333230257, -0.3730902672, -0.1122499704, -0.7847885489, 0.924862504, + -1.3942272663, 0.6543221474, 1.0042756796, -0.9440436363, -2.4518766403, 1.3270406723, -0.1127001345, 2.2061531544, + -0.3989170194, -0.4466468096, -0.5355738997, 0.0526149832, 0.606423974, 0.5198518038, -0.8466613293, -1.5090380907, + -0.4535782039, 0.4313685894, -0.1462003887, 0.1641013771, 2.1521577835, 0.3630537689, 0.2070374936, 1.7983050346, + -0.0564059503, 0.5928288698, -0.1816093922, -1.5518671274, -0.3621249795, -1.023958087, 1.024941802, -0.025839569, + -1.7892510891, 0.6218369007, 0.6613118649, 2.2723629475, -0.4432788789, 1.0698333979, -0.8403570652, -1.4873845577, + 1.5990829468, 0.3635856509, -0.1802307367, -0.3384521902, -0.2343396097, -1.44718647, -1.3438107967, -3.1347074509, + 1.3278874159, 1.4307368994, -0.2085703611, 1.5691628456, -0.0372373499, 1.5322495699, -0.8938466907, -1.6205263138, + 0.948767066, 0.0607111529, -0.0718811527, 0.4896041751, -1.2187587023, 0.8618543148, -0.2260780036, -0.4962435067, + -0.8952035308, 0.1894100606, 1.9990708828, 0.6714808941, -0.3252743185, -0.3147354424, -1.2198890448, -1.1942043304, + 1.2294464111, 0.9353618622, -1.7695857286, 0.3260254264, 0.8139547706, 0.1962550431, 0.1314067394, 0.5124615431, + 0.7095163465, 1.373000145, 0.7314730287, 0.8850992322, 0.5249949098, -0.0936656371, 1.0094020367, -0.4246652126, + -0.0342488736, 0.5519418716, 1.0054379702, 0.2137652487, -1.7681372166, -0.9254562259, -0.4854847193, -0.6538339853, + -0.276017487, -0.2612164021, 0.9103474021, 1.395219326, -0.3264450431, -0.0597991198, -0.0280044656, -0.7869258523, + -2.5064163208, -1.231456995, 1.4557712078, 1.2016288042, 0.4458014369, -1.4862548113, 0.9897671938, 0.9338101745, + 0.792671144, -0.1426515281, -0.9763342738, -1.1071892977, 1.87008214, 2.0336098671, -1.566755414, -0.5214136839, + 1.119997859, 0.7776375413, -0.1399716139, -0.0623685531, 1.1362810135, 1.0089765787, -1.3147529364, 0.6011255383, + 2.0578691959, 0.2968917489, 1.1136337519, -0.6109186411, -0.6683439016, 0.9962469935, -0.8060427904, 0.3595867455, + 0.7470183372, 1.0633322001, -0.9276279807, 0.300059706, 0.7063956857, 1.095036149, 1.4885321856, 1.4787135124, + -2.1218326092, 0.9264213443, -0.1775084585, 0.9011278152, 0.2840862274, 0.0977649391, -1.0456649065, 0.1681640744, + 0.0973941088, -1.7393004894, 0.2261245102, -0.0660531223, -0.3362882733, 0.8595430851, -0.4416444898, 0.0228420068, + -0.7061185241, -0.1840548813, -1.2924098969, -1.0702615976, -0.1731543988, 0.9668654799, 0.7544121146, -0.5534548759, + -0.1589929909, -2.7193152905, -0.5930914283, -0.4942319989, -1.1334577799, -0.1847745329, -0.8339127898, 0.1843493879, + -0.3052302599, 0.5634783506, -0.0959699973, -0.9182578325, -1.9924126863, 0.3829368651, 0.2503584921, 0.2333265692, + -0.3078962266, 0.5468981266, 0.1616246402, -0.4544194043, 0.2356493622, 1.1045236588, -1.3996573687, 0.558401823, + 0.5636180043, -0.8096659184, -0.1284091473, 0.4092279077, 0.2285577953, -0.3103590608, -1.3424509764, -1.2082949877, + -0.9283201694, 2.0955545902, 1.1210683584, -0.8812590837, 1.2313210964, -0.3197748065, 1.7898057699, 0.0698545128, + 0.7923595309, -1.0690809488, 0.6286915541, -0.1670196503, 0.9845463634, 1.0878648758, -0.1941708624, 0.501647532, + -1.1764376163, -0.7215655446, 0.3653467, 0.7173801064, 0.3487474024, 1.1008827686, 0.6648312211, -0.7699224949, + 1.8959935904, -0.1441157013, -0.2147849053, -0.7026571035, -1.2497316599, -0.7573789358, -0.5733095407, -0.4854148626, + -0.7615327239, -0.5698633194, 2.8097834587, 0.8722813725, 1.2352868319, -0.9432064891, -0.0974869877, 1.7055737972, + -0.1014531478, 1.0176905394, 1.570232749, -1.7046865225, -0.3277420104, -0.3331027627, -2.1215126514, -1.7561151981, + -0.2295200676, 1.6113495827, -0.2443063259, 2.5411062241, 0.3537022173, 0.474598676, 0.6965101361, 0.1384816021, + 1.1178592443, -1.1784735918, -1.1290528774, 0.2061873525, 1.0603878498, -1.1349711418, 1.2598598003, 1.7623924017, + 0.0733724684, -1.3333655596, -1.0912177563, -0.6205294728, 0.7761052251, 0.127167806, 1.2515132427, -0.5780774951, + 0.7281842828, -0.746543467, 1.1616883278, -0.6196599603, 0.302228272, 0.834777534, -0.049081821, 1.593927145, + -0.9503580332, -0.4347720146, -0.765621841, 0.7085364461, 0.9605593681, -1.016495347, -0.222249493, -0.8314278126, + 0.4303712249, -0.7721483111, -0.3019029796, 0.590039432, 0.0245243497, 0.1932301819, -0.0898328945, 0.456317246, + 0.6518187523, 0.0078258719, -1.2128522396, 0.5727971196, -1.3422386646, -0.8164447546, -0.011223915, 0.4942510426, + -1.7097381353, 0.6157289147, 1.2700591087, -1.0838717222, -0.4467307925, -0.2466057837, -1.0219964981, -0.3065997958, + 0.3694855869, -0.0713111088, 0.4026225805, 0.6370279789, 0.8591992259, 1.0705020428, 1.8353241682, -0.475053966, + 0.6103578806, -0.5137580633, 0.7581811547, -0.1050673276, 1.5978858471, 0.6333515048, 0.046098087, -0.7376776934, + 0.2096036524, -0.4071459174, 0.7349792719, -0.4330402315, 0.7938969135, -0.0671691522, -0.3470112383, 1.8795491457, + -0.1271699071, 0.9610880613, -1.4886234999, -0.8252080083, 1.3477144241, 1.55638659, 0.1703135967, -0.9434504509, + 0.0534256622, 0.1484180987, -1.2368420362, -0.139831543, 0.1595588923, 1.5863084793, 1.3536993265, 0.5934506059, + 1.1358667612, -0.1774367094, 0.9255916476, -0.153994143, -0.6215142012, -0.6159935594, -0.448861599, -1.4912188053, + -0.5317133665, -0.2063709795, -0.4096370935, 0.9561219215, 0.5284463167, -0.8182538152, -0.5056212544, -0.1462823451, + 0.0752253309, -1.2333616018, -0.5615788102, -1.0774196386, -1.4043681622, 1.4619164467, -0.6012640595, -0.2459688783, + 0.332450062, 1.0232548714, 1.4352263212, 0.1944244057, -0.1463443935, -0.2790006101, -0.6674974561, -1.3180520535, + 0.3201041818, 0.3282475471, -1.4190750122, 0.3450450897, -0.1171793342, 0.1504306048, -0.789146781, -1.047601819, + -0.3834323287, -0.1902684718, -0.4965841472, -1.3784673214, -0.1844371557, -0.4675067067, -0.6985540986, 0.4536924958, + 0.3140238225, 0.0564287789, 0.758397162, 0.6013430953, -1.8449608088, -0.178847447, -0.0510619581, 0.530407846, + -0.4194923639, -0.7391867638, 0.1276831329, -0.6782696247, 0.1311978102, 2.7735209465, -0.2934664488, 0.5471537709, + 0.0393295288, 1.0524917841, 2.4084842205, -0.1510079354, -0.075535953, 0.2978080213, -2.5932602882, -0.1261765659, + -0.0178737193, -1.1064251661, 1.6046415567, -1.8980734348, -0.2849923372, 0.4307873547, -0.7775550485, -0.9093212485, + -2.1181476116, 0.5486614108, -0.8518691063, 0.1899482012, -1.2635831833, 0.0362131745, -0.0570133552, -0.2774310708, + 0.5166860223, -0.6961334944, -1.1381798983, 0.0194949433, -0.2258192897, -0.0000388383, 1.0765069723, 1.1303399801, + 1.8657202721, -0.4969576895, 0.5364794731, -2.0242605209, -0.8213713765, -1.4851415157, 0.8490946889, -0.0753547922, + 0.3361081779, 0.0728952736, 0.0231189914, -1.2837551832, 0.9499085546, 0.1681417376, -1.4466546774, -0.297246635, + 1.1298607588, -0.2603873909, -0.9126073122, -0.4502425492, -0.5704441667, -0.906411171, -0.8553234339, -0.4430517554, + 0.2436235696, 1.4905276299, -1.0585029125, 0.4943399131, 0.7875627279, -0.3641681075, 1.1554255486, 1.2991687059, + 0.1732139587, -0.7331561446, 0.1793219149, -0.1800402552, 0.5449168086, 1.3240280151, -0.1309091151, 0.4784817994, + -0.4267643988, 2.078139782, -0.7498555183, 1.6521127224, -0.1664374918, -0.746060133, -0.944127202, -0.4832925498, + -1.5331821442, -0.4067618549, -0.7364491224, -0.9086607695, 0.3413515687, -0.819869101, -1.7870553732, 2.4673192501, + -0.2311452627, 0.3308919966, -0.1159708798, -1.772667408, -0.9126517773, 0.108493723, -0.2664954662, 1.111164093, + 0.1229815185, 0.6907859445, -0.1474541426, 0.9019960761, 0.2317667753, 0.8363870382, -0.3399315774, 0.7041403055, + -0.1264661849, 1.1791597605, -0.9016402364, -0.1811943799, 2.3676764965, 1.1302993298, 0.3110736012, 1.567784667, + -0.7050484419, -0.1518790126, -1.7081288099, 0.6985465884, 0.7089632154, -1.0309268236, -0.1347338855, -0.0365764089, + 0.1824831814, 0.5456715226, -0.0108612115, 0.184376061, -0.0527592488, 1.1165183783, 2.0685019493, 0.0236146916, + -0.1301397979, -0.1713315994, -0.7619674206, -1.6910823584, -0.522367835, -1.7465475798, -0.2006603628, 0.7275930643, + -0.4736891985, -1.4242618084, 0.0546379611, -0.3088788986, -0.133575961, 1.9706972837, -0.2325765043, 0.2274934202, + 2.238732338, 1.4907130003, 0.346250087, 1.3234370947, -1.988966465, 0.7430348992, 0.6448816061, 0.5218971968, + -0.1231725663, 1.5066103935, 0.8738765717, 2.7089717388, -0.8890984058, 0.0795818791, -0.0192832518, -0.9809086919, + -1.2750723362, 0.2867516875, 0.2137882411, -0.9008516073, 1.5888748169, -0.4282222986, 0.4386356473, -0.1085125059, + 0.6985945106, 1.974468708, 0.4545195699, 1.3060090542, -1.3972746134, -0.2608897984, 0.6921256185, -0.275888145, + 1.0756412745, -0.1134573221, -0.0426482968, -0.9878318906, 1.5196024179, 0.6308060288, -0.9928121567, -0.4773582518, + -0.5678960085, 1.1409707069, 0.0252071396, -0.9686629176, -0.1847696155, -1.1870638132, -0.4968124926, 0.7360694408, + -1.6462267637, 2.3052799702, -0.8024062514, -0.6898394823, 1.2083338499, -1.2181578875, -0.8410550356, -1.2503207922, + -1.3341989517, 0.545271337, 0.0004595034, -0.1027127653, 0.5961635113, -0.5245649219, -1.808401823, 1.0589570999, + -0.7794679999, 0.6349820495, 0.3862176836, 0.8346452713, -0.8713117242, 0.8153094649, -0.5405928493, 0.2869177163, + -0.6896800995, 0.05576979, 0.1182901114, -1.7857323885, -1.0742902756, -0.4063031971, 1.7793726921, -1.7563652992, + 0.6893250942, 0.8844146729, -1.0142682791, -1.7650473118, 0.2160642594, -0.7887262702, -1.1181463003, -0.1376193762, + 0.1754952371, -0.2765376568, -1.7079218626, 0.9067323804, -0.0235241614, -0.3631467521, 0.8013179302, -0.1235235482, + -0.1538935751, 0.5224968791, 0.8662751317, 0.2375682592, -0.8459567428, 0.3390309811, 0.6798582077, -0.9715719819, + -0.1630507708, -0.1906574965, -0.3275502622, 0.2688953876, 0.4053089321, 0.1773621142, -0.9372261167, -0.1691677719, + -0.3724011481, 0.8112956882, 0.1267861128, -0.5620681643, 0.2927173972, -0.8813909888, 0.0762910396, -0.0483648069, + 2.1920011044, 1.7463549376, 2.3207309246, 0.2887925506, 0.7549450397, -1.4306452274, 0.3228493333, -0.0288458075, + -0.2087575942, -0.8381208777, -0.9550005794, 0.7841243148, 0.2179069519, -1.0709420443, 0.3135614693, 0.0914136097, + 0.0320585743, 0.3876436651, 0.3842196763, 0.8502239585, 1.0612168312, 1.8604735136, 0.0568598658, 0.2732332349, + 0.0278589707, -0.8741342425, 0.3974182904, -1.3401019573, 1.6500184536, 0.53450948, 0.4902154505, 1.3779866695, + 1.4287627935, 0.5794705153, -0.4708151221, -1.2481455803, -0.9796716571, 0.1646438241, -0.2908467948, 0.1688180864, + 0.2806825936, 0.394189328, -0.5539347529, -0.0067497804, -0.2968336046, -0.4971628189, 1.9962546825, 0.2005653828, + -0.6932837367, -1.6317993402, 0.3809179664, -1.5123542547, 0.1992826313, 0.3300321996, -0.3034650087, -0.1181315854, + 0.088237457, 0.1668884158, 0.3019710481, 1.4882793427, -1.1674114466, 1.4780186415, -0.339595437, 1.621740818, + 1.3903936148, 0.0755978227, -1.1194069386, 1.7365732193, 0.1781414896, -0.9232194424, 1.8039987087, -0.8838068843, + -0.4083239436, 0.30072999, 0.1699735075, -0.8590050936, -1.73926723, 1.5597413778, -1.3260040283, 0.2854619622, + -1.9159833193, -2.3440728188, 0.4461363852, -0.0687278062, 1.9588936567, -1.1906564236, -0.7276904583, 0.2522965074, + 0.9506995082, -0.0913084596, 0.7821321487, -0.0195057746, 1.2213931084, -0.1069381684, 0.7629193068, 0.1845369637, + 0.3870324492, -1.0695841312, 1.0488708019, -0.5519348383, 0.5487302542, -2.577201128, -0.2137518078, 1.2179993391, + 0.9156683683, 0.3357705176, 0.5025701523, 0.3491545618, 0.7370117903, 0.3278817534, -0.7132780552, -0.5390459299, + -0.7518448234, 0.5354685783, 0.0184270069, 0.2321900129, -2.1776525974, -0.0709908977, -0.3209287524, -0.2798088789, + 2.0468642712, 0.9956209064, -0.2023959607, 1.3509565592, -0.1920386255, -1.5777788162, 1.6549317837, 0.4675681591, + -1.9365965128, 0.9573156834, -0.7165775895, 0.9248271585, 2.1137826443, 0.0793551803, -1.1837171316, 0.7460383773, + 0.6538752317, 1.3912616968, -0.1166813821, -1.7531785965, 0.2474077493, -1.1580266953, -0.712177515, 1.8413614035, + 1.9593071938, -0.2458700389, -0.5498188734, 1.1876565218, -0.3367114961, 0.895056963, -0.8747928143, -0.6351636052, + 2.0111460686, -1.3398618698, -1.7623288631, -0.3162357509, -0.3991983831, -0.1123126596, 0.4193961918, -0.8965550661, + -0.3267290592, -0.8449197412, -0.9209045172, -0.2399897277, 0.447686553, -0.7418269515, 0.5197879672, 0.0386816151, + 1.1803443432, 0.2628131509, -0.2394232601, -0.372253418, 0.6683313251, 1.3366475105, -1.4936909676, -1.4146258831, + -0.237601012, -0.2817085683, 1.8941197395, 0.4649803042, 0.8323036432, 0.4888179898, 1.1489104033, 0.6556180716, + -0.700019896, -0.6820146441, 0.4848237932, -0.5177137852, 0.082417503, -0.8797442317, 1.1639926434, 1.1476025581, + -0.8527011275, 2.0083818436, -0.2703168988, -1.2097411156, -0.2276968956, 0.2739947438, -0.53345716, -1.5935918093, + 1.2445474863, -0.3134967685, -0.2985264361, -0.7968905568, 0.855491519, 1.6267149448, 0.6216568947, 1.5030903816, + -0.115123257, 0.8909834027, 1.8018869162, -0.0360328667, -0.820215404, -0.2220973074, -0.351773113, -0.5957280397, + -0.151414752, -0.4198016822, 0.2551528811, -0.1152595282, 0.2171547413, -1.4629511833, 1.1438225508, 1.208429575, + -0.8150461316, -0.7321365476, 0.3776405454, -0.9554858208, -0.4959684014, -0.2907817662, -1.0054425001, -0.4517457485, + 0.1696795672, -0.6147547364, 1.1529808044, 0.0660743788, 1.575302124, -0.4344066083, -1.7833483219, 0.0277798567, + -0.5330213308, -0.9183149338, -0.608682096, -0.4047652185, -0.6416500807, -1.0837899446, 0.0532945246, 1.1404436827, + -0.0453740098, 0.7457920313, -1.9460426569, 1.7987947464, 0.9324730635, -0.8482402563, 0.6843633652, 1.3739305735, + 0.3718565106, -0.1377663314, -0.963093996, -0.304323405, 0.0718399286, -0.2703020275, -1.1004296541, -1.3805667162, + -0.5695853829, 0.4196306765, 1.997163415, 0.8231883645, 0.2833084464, -0.2101227045, -1.8163676262, -1.7911117077, + 0.1537543535, 1.9449908733, 0.1513811201, -1.1334222555, 0.5895084143, -0.5986622572, 0.3019756973, 0.7390938997, + 0.9933456779, 0.680763483, 0.9933760166, 0.5551660061, -0.8488301039, -0.5885685682, 0.4313100278, -1.3862833977, + 0.7359342575, 0.9195241928, -0.0853480026, -0.1070248708, -1.2493082285, 0.5755701661, -1.0534989834, 0.040649306, + -0.5918547511, 0.0460599251, 0.7082794309, 0.7456382513, -1.0815974474, -1.284815073, 0.7570005655, 0.9823464751, + -0.433247596, 1.9694807529, -0.5031172633, -0.8139947653, -1.9751011133, 1.2804644108, 0.5563730001, -0.4628264606, + 1.1694854498, -0.4353146255, -1.6423184872, -0.5444234014, 1.8026432991, -1.5473425388, 0.3108020425, 1.2917841673, + -0.3807676435, 1.765412569, -0.6993806958, 1.1027238369, 0.6636332273, -0.684360683, -1.4899740219, 0.2734349966, + 1.2600288391, -0.2286336422, 0.2327901125, 2.4362354279, 0.1817132533, -0.7989073992, 1.1250274181, -1.0452672243, + -0.814961195, -0.2601708174, -1.3295027018, 2.2031581402, 1.180025816, 0.2624831796, -0.0770635083, 0.7740607858, + -0.3567553759, -1.1034004688, 0.1847368032, 0.6796195507, -1.0074751377, 1.1585245132, 1.4195199013, -0.6195434332, + 0.7116128802, 0.6401365995, 0.5280639529, -0.9293158054, -0.0831103027, 0.5697512031, 1.0032013655, 1.0931603909, + -0.4489105642, -0.2979501188, 1.0878436565, 1.6233495474, 1.4550083876, -1.1979384422, -0.9113218188, -1.2620170116, + 0.1533333361, 0.3634153008, -0.3303910196, 0.1722114384, 0.178200841, 0.9415059686, -0.7712236643, -1.5482803583, + -1.4313429594, -0.3579024374, 2.3041453362, 2.1099629402, 1.6484801769, 0.1672390848, -0.0169916637, 1.7207933664, + 0.2674842775, -0.4923659265, -0.6619585752, 0.8079488277, -1.6243458986, -1.7960036993, -0.7675559521, -0.0231633689, + -1.0103166103, 1.2741718292, -0.641900003, -0.773016274, -1.4375553131, 1.1895669699, 0.3485536277, -0.4232673645, + 1.2198886871, 0.4842070043, 0.022746386, 0.5305594206, -0.8054476976, -1.77348876, 0.3406913579, -2.7052669525, + -0.0847135931, -0.6385948658, -0.5110730529, 0.3484685719, -1.3105498552, -2.5472373962, -0.3775078654, -0.0988472104, + 0.4710415006, -1.2057213783, -1.7653845549, -0.0680527538, 0.7711173892, -0.7321217656, 1.0039491653, -0.7371895313, + 0.5678637624, 0.3336027265, -0.5274707079, -0.9774408937, -0.378677845, -1.4249675274, -0.7147436142, 0.3129166365, + -1.778392911, -0.4209950566, -0.5415373445, -1.2222980261, 1.3970868587, 0.8098871112, -0.2767983675, -1.8499927521, + 0.150241971, -1.5492517948, 0.7092196941, 1.4950456619, -1.1154440641, -0.5161579847, 1.2957165241, -0.579665184, + 0.6269744039, 0.9531516433, 0.2816024125, 0.473282963, -0.7617855668, 1.6947957277, -0.0578788295, -0.4390718937, + -1.1987463236, -0.434127748, -0.042696882, 0.7203280926, 0.3357464373, 0.861245811, 1.0400627851, -0.0488214567, + -1.298791647, 0.8273304105, 1.0139622688, -0.0649127662, 0.7446480393, -0.1540967673, 1.9260265827, 1.2363505363, + -0.4862475693, 0.4868167043, 1.7191879749, -0.0682080835, -0.9640083909, 0.3089770079, 0.9302484989, 0.9873762727, + -0.5898210406, 0.4689652324, 1.5302232504, 0.7320433855, -1.3513690233, 0.7897057533, 0.2824765146, 0.5834311843, + 0.1131865606, -0.8406014442, 0.4050630033, -0.4101101756, 0.5337298512, -1.303629756, -0.6484665871, -1.1359941959, + 2.057151556, 0.6670948267, -0.4131903946, -0.5690752864, 1.4522426128, -0.9800069332, -0.1403042823, -1.0196304321, + 0.9959092736, -0.2827495635, 1.9643141031, -0.6609107256, -0.7525837421, 0.5954794288, -0.3523457646, 0.3810907602, + -1.0135425329, 1.4329707623, 0.8080863357, 0.889698267, 0.2208904177, 0.3672073483, -0.6885126233, 0.4308250546, + 1.1822276115, -2.0149857998, 1.9600487947, -0.5171279907, -0.1703243852, 0.8568869233, 1.2518591881, 0.2865099013, + 0.8115671873, -1.4276633263, 0.5710371733, 1.0781027079, 2.2357771397, 0.7279140949, -0.2229265273, 0.5872340798, + 1.4881185293, 2.3195126057, 0.5637220144, 0.6914354563, 0.2569299936, -0.2285066694, 0.4804783762, -0.2613047361, + -0.4131895602, -1.4262596369, 0.422824502, 1.0623100996, 0.2604335845, 0.6574383378, -0.0409760214, -0.1292385161, + -0.6623541117, -0.6476683617, -1.6716749668, -0.1830161214, -0.3365137577, 0.6030265093, -2.0935566425, 1.2513388395, + 0.3918113708, 0.7372437716, -0.0178348534, -1.1537516117, 1.0530462265, -0.8401392698, 1.8309344053, -0.9686001539, + -0.3691553771, -1.4921547174, 0.0017514684, -0.4581293762, -0.6935526133, 1.085513711, -1.0821048021, 0.796212852, + -0.1281221062, -0.8133049011, -1.2505276203, -2.2208952904, -0.2130862474, 1.009906888, -1.4203333855, -0.2492176443, + -1.3636775017, 0.1963888705, 1.9370468855, 0.5962476134, -1.6595464945, 0.1022451743, -0.5378738046, -1.8219336271, + 0.0530054718, -0.3030683696, -0.0812117681, -1.8513782024, 0.3097834587, -1.5337352753, -0.2538897991, 1.3182882071, + 1.1397893429, 0.4829955697, -0.9046905637, -0.8380981088, -0.2948737741, 1.9916062355, 0.0728184804, -0.1014356986, + -0.1235939339, -0.5081471205, 1.2604811192, -0.1343659312, 0.2073383778, 0.3723934889, -0.4487771392, -0.4661149383, + -0.3359813094, -1.3195090294, 0.354013443, 0.3601185679, 0.0083168242, 0.3976401091, -1.6742360592, 0.2504509389, + -0.6635281444, 0.8641865849, -1.1257250309, -0.3801716566, -0.1833992749, 0.3565971553, -1.3327323198, 0.6035583019, + -0.5465292335, -1.5566965342, 0.6932677031, 1.622811079, 0.6801456809, -1.5924171209, -1.5193947554, -1.008433342, + 0.4458001256, -0.8410766125, 1.5464582443, 0.6618500948, 1.311589241, -0.8060818911, -2.0020639896, -0.7427703142, + 0.9982657433, 0.0429815277, -2.2929155827, 0.7949628234, -2.0755562782, -1.1538249254, 2.2420399189, 0.3406197131, + 0.0048286184, 0.2839885652, -0.4365164936, 1.3366078138, -1.8391609192, 0.3603280187, -0.0859675929, 0.5570289493, + 0.5718832016, 0.610673368, -0.3083177805, 0.014493119, -0.2672089338, -1.2353001833, 3.0229272842, 0.3395426869, + 0.5264291167, 1.2634595633, 0.1770529449, -1.4849345684, -0.6991217732, -0.7283034325, -0.6939549446, 1.5446032286, + -0.2754387259, -0.2167219073, -0.7424051166, -0.9166474342, 1.5751912594, -1.6181910038, -0.8253030777, -1.0706801414, + 0.8698484898, -1.1994905472, -0.8146388531, 1.2920223475, -0.462587893, -0.3836516738, 1.0654515028, 1.6666485071, + -0.1208937168, -1.4995495081, 1.2321619987, -0.6949200034, -0.5739510059, -0.1775606424, -0.9272752404, 0.5301542282, + -1.1949777603, -0.4780461788, -0.5277665854, -0.9728552699, 0.4626088738, 0.4503042698, 0.9948613644, 0.2734299004, + 0.1685026735, -0.6112354994, -0.9500792027, 1.8824837208, 1.7905997038, -1.1740034819, 0.0983359888, -1.16132617, + -0.3503814936, -0.8911704421, 1.0788980722, 0.5437412262, 0.6564418674, -2.4974653721, 0.4571970403, 0.0749873742, + 0.0620500483, -0.2306726277, 0.1126581952, 0.6336370111, -0.4393058419, 0.6253045797, -1.3444340229, 0.3629311323, + 0.9891084433, 1.3607655764, -1.6233907938, 0.3538567126, 1.2099943161, 0.7256388068, -0.4102138281, 0.4880381823, + -0.6662564874, -0.3059380352, -0.1223294958, 0.9289811254, -0.9578050375, 0.7637707591, -2.6466319561, -0.8069033027, + 0.2090090364, -2.1910057068, 0.8204702735, -1.6458770037, 0.1837251335, -0.4417119026, -0.3663473129, 0.7258780003, + -1.0395754576, 0.3824823201, -1.3599922657, -1.366765976, 0.226786986, 1.066079855, 0.7252836823, -0.0433388688, + -0.8327400088, 0.5989152789, -0.1539460868, 0.8072755933, -0.1370912343, -0.3414518237, 0.685947299, -0.0732531026, + 0.4887581468, 1.4984587431, -0.8649017811, 0.1688008904, -0.1289001107, -0.921831429, -0.3603636324, 0.9271414876, + 0.0079463189, -0.338370949, 0.8675869703, 0.124982737, 0.465118885, 1.1462744474, 1.2493416071, -0.4183758795, + -2.5614197254, 0.5680629611, -0.6206008792, 1.7465558052, 0.3847604096, 1.4685661793, -1.1315544844, 1.1918085814, + -0.6606284976, 0.404160291, -1.473968029, 1.1007773876, -0.4919222891, -0.1771818995, -1.2822349072, -1.0434724092, + 0.3237209916, -0.7618917823, 0.3099120855, -0.5639561415, -0.0917711481, -0.5850586891, 0.6370205283, 1.0494756699, + -1.9202592373, 1.2494323254, 0.5849095583, -0.8469260335, 1.3565355539, -0.0963294879, 1.2453507185, -0.1400534064, + 0.8450857997, 0.4133973122, 0.7155808806, 1.4432688951, 1.5716166496, 0.6924489141, 1.4065362215, -0.41331622, + 1.0888381004, 1.3608398438, -1.0978585482, -0.2764387131, 0.5563209057, 0.8842734098, -0.3509296477, -0.9768342376, + -0.7402306199, 0.2903321981, 0.1414962411, -0.4799614251, -0.3082216084, 0.0267795082, 1.2097295523, 0.2476162165, + 1.1630425453, -0.0845261142, -0.2282030135, 0.2696264684, 1.2454012632, -0.1312718689, 1.4098299742, 1.0410118103, + -1.6086004972, -0.51749295, 0.8974530697, 1.0401508808, 2.2852160931, -1.0753257275, 0.0802447274, -1.2287327051, + -0.0713328272, -0.8569629192, 1.1176137924, 0.511484623, 0.6936994195, -0.8175045848, -0.6783365011, -0.7737123966, + -0.3651148975, 0.6318411231, -0.6266897321, -0.6617985964, -0.5669463277, 0.2499994934, 1.1892088652, -1.9240505695, + -0.3544670045, -1.0515387058, -1.8288736343, -1.2691622972, -1.308947444, -0.0297324564, 1.2603071928, -0.4449788332, + -1.7621899843, -0.8053673506, 0.5204708576, 0.2721701562, 0.2346938401, -0.6873981953, 0.2655944824, -0.0325214528, + 0.5738306642, -0.5787928104, -0.8237167597, -1.2874125242, 1.135076046, -2.1356105804, 0.4515221119, -2.1500139236, + -0.4114108384, -1.1628191471, 0.1297886521, -0.2495429516, -0.0260325857, 0.9392570257, -1.3046522141, 0.6903501153, + 0.6977592707, 1.0701305866, -0.288767457, -0.4104785323, 0.1533241421, 1.3199142218, 0.3096901178, 0.4101806581, + -0.7352973223, -0.9126303792, -0.7222605348, -0.4227232933, -0.2477057576, 0.5480054617, -1.1432491541, 0.3385492861, + 0.2351884991, 0.0385535322, 0.8181906939, 1.5828475952, 0.7214038968, 0.0897340551, -0.3189024925, -0.3974009156, + 0.9097927213, 1.9650508165, 0.1053364798, -1.2227591276, -0.0153107131, -1.2919523716, -0.7455282807, 0.9781656861, + 0.6193071604, 0.4077815115, -0.7046490908, 0.1537861079, -0.0643131956, 1.2573903799, 0.9574343562, -0.5834718347, + 0.1090049073, 0.5478889346, 0.3504471183, -0.2250039279, 0.8269471526, -0.0169237554, 0.6220702529, -0.2975426614, + 1.2149496078, 1.1151980162, -0.4507243931, 2.220685482, -1.8293071985, 2.6430711746, -0.1439989805, -0.0610520355, + -0.2829388976, 1.0629047155, -3.1820971966, 0.4401958883, 0.7499151826, 2.5593225956, -0.996786952, -0.2721943557, + -0.0896866843, 0.6282408834, -0.0261002425, -0.9709675312, 0.0230096858, -0.0140103968, -1.6569482088, -0.1382927299, + 0.7253227234, -0.7418099642, 0.9728586674, 0.4095517993, 0.048398912, 0.097918354, 0.3018720746, -0.3589890599, + 0.5353608727, 0.5360045433, 0.7536387444, 0.7505097389, 0.5256783366, 1.3380362988, -0.2981445193, 1.8530151844, + -1.1281915903, -0.0498322956, -0.733025372, -0.6458021402, -0.5024451017, -2.2123041153, -0.9805191755, 0.8008458018, + -1.007724762, 0.6239641905, -0.8552334309, -0.2744834423, -0.1157714501, 0.0847591385, -0.3774202764, -0.3264375031, + -0.0360224955, -1.0819702148, 0.326648891, 0.5532034039, -0.3854060173, -0.1618631631, -1.9549201727, -1.7788834572, + -0.1174470335, -0.2493743002, 2.1404275894, 0.559346199, 0.6229158044, -1.8816431761, 1.460729599, -0.3706546724, + 0.0042911167, 0.3046770096, -0.0710433796, -0.1237470731, 0.4302512109, 0.4529004395, 0.6425746083, -0.112278454, + 0.9161322713, -1.1342129707, -0.5450671911, 0.2877930403, -0.2188682407, 1.2186625004, -1.1504718065, 0.556840837, + 1.3841053247, -0.1620552093, 0.7049739957, -1.2413967848, -0.9855633974, 1.3243196011, 0.3625219762, 0.2983141243, + -1.2990237474, -0.2681641281, 0.1363256872, -0.1956966519, 0.2655187845, -0.1531553864, 1.2532037497, 1.8852713108, + -0.088271983, 1.7805033922, -0.4716087878, -0.9298340678, -0.318084389, 1.2743237019, 1.0903788805, 1.0813274384, + -0.699676156, 0.7500818372, 2.1777994633, 2.2021887302, 0.2121428996, 1.6765725613, -1.2105097771, -1.5527480841, + -1.3053249121, 1.9286055565, -1.3529680967, 1.0474323034, 0.2311239541, -1.3959530592, -0.6062406301, -1.8592184782, + 1.0289849043, -0.1385550201, 2.3706924915, 1.1001138687, -2.100913763, 0.680942893, -1.6257436275, -0.6237348318, + 0.6981055737, -1.8643096685, 0.4661882818, -0.2186380774, -1.3467729092, -0.952757895, 0.2725820839, 1.3400031328, + -0.5603945851, 2.5774965286, -0.5632506013, -0.3768528998, 0.0353212729, 1.4043915272, 0.0230951086, -0.006158419, + 0.6321358085, -1.9023759365, 1.5614373684, -0.1971298605, -0.7250073552, -1.0256675482, -0.4578739703, -0.644329071, + -1.0963523388, -0.0895931944, -1.4758558273, 1.6121660471, 1.1630821228, -1.7796010971, 0.0145237353, -0.5974840522, + 1.0503715277, 0.369513154, -0.3743128181, 0.0213968288, -1.0481902361, 1.0413702726, 0.3212760389, 0.3309848011, + -0.6946014166, -0.7083328366, 0.9349833131, -0.1450703889, 1.115272522, -0.8652854562, -0.4565080702, 0.3007369041, + 0.9256248474, 2.0625565052, 0.2747337222, -0.2963839471, -2.6546571255, 1.2803245783, 0.1107093021, -0.6835398674, + 0.4723945856, 0.9344331622, -0.7295447588, -0.2803449929, 0.1233135983, 0.6120019555, 0.5841313004, 1.753385663, + -1.05430758, -1.2622847557, 0.4116769433, -0.6446053982, -0.2465761304, -0.7146756053, 1.3107023239, 0.6113011837, + -0.1636191308, 0.4882713854, -0.3482097387, 0.1603152454, -0.4162207544, 0.1293164194, 1.7988963127, -0.8851790428, + 0.3992467523, -1.7737257481, -0.3428349793, 1.8912366629, 0.0722259954, -1.653747201, -1.6307649612, -0.4667405784, + 1.1868702173, -0.7915568352, 0.45787552, 0.2519705594, -0.9535153508, 1.2609884739, 0.4392801523, -1.3256343603, + -1.0367951393, -0.2201278061, -0.6169109941, -1.0181512833, -0.410338819, 0.1084682569, -0.6541967392, 0.7603313923, + 1.3501311541, -1.6931246519, -1.5221095085, -2.0480751991, 0.4730706215, 1.3266686201, -0.0894597024, 0.3304823041, + 0.1989917606, -0.4702607393, 0.2213799506, -1.5739086866, 1.7835437059, 0.3327397406, -0.4354090691, -0.1039255261, + 1.8387240171, 0.3680784702, 0.6319974065, -1.5963237286, 0.0214680173, -1.0597387552, 0.1692428887, -0.1024794206, + 0.3460634351, 2.1404290199, -2.7088286877, -3.3357634544, 2.4715435505, 0.5048002601, -0.0024718831, -0.3783724308, + -1.8512169123, 0.0197386872, 0.5260105133, 0.0301570203, 1.1527439356, -0.6599699259, -0.7668974996, 0.9182029963, + -2.0533874035, -0.5711094141, -0.83331424, 0.5297877789, 0.1696676463, -1.1874402761, 2.6695325375, -0.3015936315, + 0.0863558426, 0.6479152441, 0.4200901091, 0.083659485, 1.3033480644, 0.6622453928, -1.594612956, 1.1357042789, + -1.2606321573, 1.0469983816, 1.1802233458, -0.1032438353, 1.1054823399, -1.2712923288, 0.0872885138, 1.3110666275, + -0.3147211671, 0.7948974371, -0.652086556, 2.3930139542, -0.6381352544, -0.1903901398, 0.7538375258, -0.6007530093, + -0.4748378098, 0.4931529164, -0.3945479691, -0.7058361173, -0.4707331657, -0.6427865028, 1.1003127098, 1.2145934105, + 0.6543659568, 0.1378059983, 0.2667719126, -0.4505184293, 0.7668704987, 0.3069391251, -1.0402356386, -1.0768088102, + -0.358476311, 1.454406023, -1.4216730595, 0.3472038507, 0.2086229771, 0.5839641094, -1.4341008663, -0.6708384156, + 0.250837326, 0.8319552541, 0.5872681737, -0.4998468161, -1.1823883057, -0.305410713, -1.0352274179, -0.6697105169, + -0.878449142, -0.8758939505, 1.3824001551, 1.103790164, 0.5120603442, 0.2342875302, 0.7024837136, 1.1357293129, + -1.0685719252, 0.1360779256, -1.2616283894, 0.195842281, -0.7124678493, 0.4309418797, -0.8070568442, -3.6666617393, + 1.2247881889, -1.8534743786, -0.8791117072, -1.1550799608, 1.3362749815, 0.6916596889, 0.1911562085, -2.1766350269, + -0.2334984988, 0.1585360169, 1.7308087349, 0.2101554424, -0.4219810665, 0.6413149238, 3.6585171223, -1.6798986197, + 2.157225132, -0.9573594332, 2.1295564175, 1.6554572582, 1.41738379, -0.1184742749, -1.3791389465, -0.1836668104, + -2.5507338047, -1.8902881145, -0.2113366872, 1.793415904, -0.4378238618, -1.6616495848, -0.5122920871, -1.7967692614, + -1.2768464088, 1.4960579872, -0.4098713994, 0.279255271, -0.6689916253, -0.2977707684, -0.5372231603, 0.6325138211, + -0.3380914032, 0.1361745149, 0.5060076714, -2.7306387424, 0.5758006573, 0.0367980748, 0.494895041, 1.3093698025, + -0.6927099228, 0.5162115693, -2.8285930157, 1.4057217836, -0.8556907177, -0.5703662634, 0.1480660737, 0.2890440822, + -1.7777055502, 0.6198061109, 0.9095965624, 0.2691595852, 0.0894911662, -0.0680072829, 0.8367866278, 1.0884227753, + -0.7422149181, -0.37372756, -1.6788115501, 0.1495314837, -0.9467903972, -0.1744271517, -0.7147907019, 0.5539358854, + -1.1186755896, 0.6251395345, 0.6120824218, 0.1489314586, 0.7221364379, -0.667322278, 0.5348725319, -0.0781799033, + -0.4313751459, -1.4768824577, 0.6255025864, 0.5036774278, -2.0770540237, 0.8228256106, -0.2019738853, -0.063351728, + 0.7215458751, 2.4272737503, -0.4849633276, 0.7702387571, 0.7469590902, -0.1873421669, -1.3352429867, 0.8034677505, + 0.5133347511, 0.3616528809, -0.0800107121, 1.6482689381, -0.2358781248, -1.1339635849, -1.1484259367, -0.2858934999, + -1.7178094387, 0.042222131, 0.7282291651, -0.5086132288, 0.2948485017, 2.0248792171, 0.9847933054, -2.2134039402, + 0.1210705861, 0.9005804658, -1.793821454, -1.1630740166, 0.6061529517, -1.3917492628, 0.0659918785, -1.5254364014, + -0.8436492085, -1.4030380249, -1.1273025274, 0.6605858207, 0.524428308, -0.5535778999, 0.5154033899, -0.0494096726, + 1.9339607954, 1.0602059364, -0.227583468, 0.1745944023, -0.398829639, 0.2007772624, 0.4210469723, 1.1622320414, + -0.1475005299, 1.677549243, 0.3825560212, -1.4785602093, -1.0011734962, 0.9199843407, -0.3728865385, 2.1775677204, + 1.0654608011, -0.3552238345, 1.2858337164, -0.0408678167, 0.7288712859, -0.6996934414, -0.951554656, 1.4982056618, + -0.841452539, 1.5781154633, -0.8477112055, -0.2554596066, 0.7263152599, -0.8979797959, 1.9918254614, -0.0547553524, + 0.2416841537, -0.0709533319, -0.8204307556, -2.0357275009, -0.1745917797, 1.0008513927, -1.1479756832, 0.6434391737, + 0.3278440535, -0.8116710186, -1.07523036, 0.3474791348, 0.0802315548, 0.1050836816, 1.6445997953, -0.6685065031, + 0.2889428735, 0.1904595792, 1.9781349897, 0.067267023, -0.0199888926, -0.319663316, 1.0699506998, 0.5876069069, + 1.4938871861, -0.2294600457, -0.6761348248, -0.9675368667, 0.390103817, 0.9939051867, 0.1740347892, 1.2410316467, + 0.2331166565, -0.4013488293, 0.0780516416, 0.1232619882, 0.4011231065, -1.1274694204, 1.7268871069, -0.3178609014, + 1.1595098972, 0.5392588377, 0.5934121609, 0.0710647479, -1.4837100506, -1.5382093191, 2.3655643463, 0.4086492658, + -1.4912976027, -0.209675014, -1.2068072557, 0.1913460344, 0.9109123945, 0.3377050161, -0.8817027807, -1.7224570513, + -0.7705970407, -0.559679091, -1.0413635969, -0.4826701283, 2.7578041553, -0.789506197, 0.2393582165, -0.1677271277, + -1.5210280418, -0.9905596375, -1.2625994682, 1.8897997141, -1.3356403112, -0.2018123269, 1.1257551908, -0.6290640831, + 0.6600694656, -0.0313108787, 0.337107569, 0.849116385, 0.9079491496, 0.7914938331, 0.5391131043, -0.4028544128, + -0.3595976532, 0.9391801357, -0.934005022, -1.5900048018, 1.0865169764, 1.5760774612, -0.9845061302, -0.4753736556, + -0.4715046287, -1.0118333101, -0.3843485117, -0.0267880801, 0.0341033973, 1.6630090475, 0.7196737528, -0.9001411796, + -0.1763302237, -1.8384820223, -0.5711111426, -0.6256062984, -1.0332602262, -0.2247431427, -1.4039026499, + -0.6790704131, -1.2205200195, 0.5722601414, -0.8030456305, -0.4784704745, -0.2942892313, 0.6278070807, 0.1514698267, + 0.4336849153, -0.3661702573, 1.2590053082, -0.336417079, -0.215532437, -0.0285432246, 0.717622757, 0.2905178368, + -0.4122419655, -0.0120573184, -1.0927163363, -0.4791768491, 1.0728253126, -0.4578598142, -0.1820637584, -0.6342881322, + -1.2003618479, -0.5084941983, -0.1252528578, -0.5457894206, 0.3418527246, -0.2050891072, -0.3844342828, 0.8712399602, + -0.0385699309, 0.0265888497, 1.354788661, -0.3125000596, 1.2956840992, 0.9276458025, 0.3030017912, 0.9541946054, + -0.7833327651, -0.9277109504, -1.581602335, 1.3954637051, -0.0899096355, 0.9990671277, 0.7146677375, 0.2361557186, + -1.3013103008, -0.1263361424, -0.2064883858, -1.68686831, -1.2527776957, -0.4654269218, -1.3014801741, -0.1094226167, + -0.144488126, -1.4770342112, -1.982450366, -0.3436704278, -0.8657111526, -1.2764846087, 0.4240189195, 0.5265209079, + -0.7517572045, -0.8044191599, 0.8929079771, -0.3144601882, 1.0459331274, 0.3026503921, -0.8141273856, 1.7526532412, + 0.5301589966, -2.1711890697, 0.205947727, 0.8248731494, -1.6328703165, 0.4597865939, 0.8475491405, 0.2477189749, + 0.0925393179, -0.4595969319, -0.1853267998, 0.3266243339, 0.6708236933, 0.6769939065, -1.0828754902, 0.2627280354, + 1.3661319017, 0.1279993355, 0.9695571065, 0.143279478, 1.1143633127, 1.1418329477, 0.1405775994, -0.4752911925, + -0.0177135766, 1.0221664906, -0.3322848976, -0.5167743564, -0.7432743311, 0.3890959322, 0.1556181014, -1.8614654541, + 1.6840809584, -0.7621278167, 0.1582335532, -0.2684752047, 0.5648133755, -0.1776323318, -0.6139817834, 0.1006056443, + -1.014852047, -0.0685680658, 0.9740679264, -1.0096333027, -1.2929003239, -1.1497299671, -0.2576673329, 0.2650620937, + -0.5298980474, 0.1767422408, 0.3737693727, 0.0116174156, -0.8848586679, -0.2841534019, 0.2786668837, 1.2182451487, + -0.8785102963, -0.6624893546, -0.2506814599, -1.6583607197, -0.0440883674, 0.7125759125, -1.9737573862, -0.4872403741, + -0.1577950418, -0.8622025251, 0.1490759254, -1.1009280682, -0.7130812407, 2.9556460381, 1.6436719894, 0.6758390665, + 1.0099107027, 0.0647838414, 0.3598891795, -1.5434740782, 0.2607182264, 0.7817473412, -1.9403500557, 1.4225147963, + -2.151982069, 0.5616424084, -0.8769695759, -0.2707855403, 2.4196352959, 0.2859359682, 0.0165289156, -1.7499842644, + 0.3692513406, 0.503105998, -0.1664648801, -2.0056574345, -0.7654278278, 1.0434603691, -0.6375411749, 0.2848365307, + 0.073513329, 0.8452553749, -1.4876236916, -0.2486355007, 1.412117362, 0.7177804112, -0.7401977777, 0.354580313, + -0.5262724757, -2.8600194454, -1.9175211191, 0.445181936, -0.0762447342, -0.131458506, 0.8150295615, 0.1831329763, + -0.0879756361, -2.0604195595, 0.2432845235, -0.1897565573, 2.0000879765, 0.2861734331, 0.0464978926, 0.1709866971, + 1.3898837566, -0.3738046587, 1.2233188152, 1.0814232826, -2.1520938873, 1.0503945351, 0.7663048506, -0.7665901184, + 0.5697636604, 0.7073093057, -0.7511551976, -0.9094853997, -0.4420854747, 0.9772966504, -0.1575781852, -0.1842168272, + -0.3205026686, -0.6077862382, -0.0882692859, 2.2927906513, 0.9862863421, -0.2564762235, 1.492082119, -0.2900837064, + 2.267169714, -0.0333347134, -1.1995899677, -0.3519096971, 0.0096649854, -1.1579176188, 0.1301806569, -0.3239947259, + 0.2254819572, 3.1275162697, -2.1915900707, 1.664260149, 0.3813494444, 1.1953544617, -0.192396313, -1.3483207226, + 0.6332259178, -1.1693799496, -0.8710323572, 2.1890964508, 0.5400183797, 1.4145956039, 0.7931981683, 0.0518532507, + 1.3498840332, -0.3464334905, 1.8504086733, 0.2446140349, 0.648283124, 0.99840343, 1.3537937403, 1.1133658886, + -0.3245791793, 1.3398704529, 0.4796682596, -0.4233224094, -0.6885091066, 0.1215857938, 0.6505106688, -0.4377563298, + 0.6642935276, -0.7825295925, -1.0611126423, -1.0111138821, 2.4128932953, 0.8924791813, -0.4122083485, 1.204608202, + 0.5568127632, 0.743228972, 1.346298337, -0.4105149806, -0.0584207624, 0.8289735913, 0.014942904, -0.9931199551, + 1.993437171, -0.4420913756, -0.3624625206, -1.1244492531, 1.4691061974, -0.0499073863, 0.2002401203, -1.1248832941, + -1.272618413, 0.9452376962, -0.4676527977, -2.237070322, -2.2448759079, 0.9237034917, 0.4242494106, 1.7204461098, + -0.397649914, -0.0906097963, 1.4850599766, -0.1435298324, 0.3990937471, -1.3640803099, 0.1675154865, 0.9451347589, + 0.1672854722, 1.1541965008, -1.3738102913, -1.6310482025, 0.4398053586, 0.9419565201, 0.4221067429, 0.8890461326, + 0.9389849901, -0.5344372392, -0.2121012062, 0.1934045106, -1.148943305, -0.1732483953, 1.6298263073, 0.7644013166, + 0.006804368, -1.4946343899, -0.1486235559, 1.0825355053, 1.0867308378, -1.5739576817, -1.102507472, 0.3009252548, + 0.1753404289, 0.1530693769, 1.4307221174, -0.9575708508, 1.3203545809, -0.6723961234, 0.4719530344, -0.2558166087, + -0.4151659906, 0.2092033029, -0.3377778232, -1.7142255306, -0.078047581, 0.1520982683, -0.6602406502, 0.8542318344, + 0.0446649306, -0.1880837232, -0.8102146983, 0.1999365538, -0.8471016884, 0.660972774, 0.0869688913, -0.823472321, + -0.0038673137, -0.7962244153, 0.4736574292, -2.1708366871, 0.5728909373, 0.0155894784, 0.101915516, -0.9545924664, + -0.041735705, 0.0830023661, 0.3825495839, -1.5725542307, -0.5406516194, 1.8002802134, -1.1717652082, -0.19483684, + 1.2039487362, 0.5995358825, 2.4622888565, -1.4696532488, -1.8450510502, -0.8768398762, 0.0656154454, -0.6295272112, + 0.0151507873, 0.9739693999, -1.3466656208, 1.7466659546, -1.2967122793, -1.5379266739, 0.0025664088, -0.525993824, + -0.74753654, 0.1608507335, 0.2720134556, 0.6598511338, -0.2686775327, 0.2295012027, 0.1086877584, 0.2343160212, + 0.4769563675, -1.0597660542, -1.9808396101, -0.7161743641, 0.867631793, -0.5259642601, -1.6665190458, 0.2771702707, + -0.5351759791, 0.5666056275, -0.0272630919, -1.2385288477, 0.603638947, 0.5278122425, 0.0797868595, 0.0228599031, + -1.909894228, 1.5135689974, -0.2744904459, 0.3447202146, -0.2918914258, 0.0123673119, -1.0660989285, -0.7806712985, + 0.4060901105, -0.3038170338, -0.5685398579, 0.7254636288, -1.426202774, 0.3587500751, -0.0250621587, 0.4670973122, + 1.7571234703, 1.2794920206, -0.782592535, 1.7953877449, 1.444047451, 0.2549488842, -0.5291935802, -1.8028976917, + 0.2191513032, 0.2555356026, 0.059410125, -0.2747816145, -0.8839666843, 0.5966591239, -0.242684871, -0.2062047273, + 0.6629035473, -1.1385248899, 0.0354150161, -1.4973627329, -0.4372212291, 0.1723114401, -1.4453716278, -2.5439577103, + 1.0714870691, -2.3216881752, 0.6471449137, -0.2535232008, -2.476880312, 1.8743288517, 0.3274333775, -1.4912362099, + -0.4837066829, 2.1048803329, 1.4479202032, -0.6346545815, 0.2597027719, -0.5986030102, -0.9634928703, 1.1574920416, + 0.4726140201, -2.7617619038, 0.4451379776, 1.5339012146, 0.6199848056, -0.6614613533, 0.493193835, -0.7092412114, + 0.4458418787, -0.7853662372, -0.2501262426, 0.1611269265, -0.5285350084, -1.6091034412, -0.190481469, 0.511742115, + 0.3120868802, -0.400059551, -0.7666798234, 0.9289351702, -0.2531622946, 1.1696226597, -0.4199027717, 0.355771184, + -0.4890812635, -0.5624075532, 1.2869091034, 1.1910554171, -0.3527726829, 1.604416132, 1.2182590961, -0.0506892353, + 0.2301639915, 2.112739563, -1.8038836718, -0.1752304137, 0.3366157413, 0.1188599542, -0.3038607836, -0.6614480019, + 0.6676669121, 0.8247133493, 1.1330426931, -0.3428809941, 1.383533597, 0.7142785192, -0.2841734886, 0.8137839437, + -0.9763744473, -0.5805509686, 0.8007320762, 0.753821373, 0.6759210825, 0.6667888165, 0.1327999085, 0.5388278365, + -2.5514461994, 0.2968763709, 0.0856194794, -1.2785900831, 1.3809236288, 0.1545603722, -1.6245212555, -0.9858641624, + 0.0683231354, 0.9755828381, -0.1573059112, -0.5441203117, 1.4863932133, -0.3820349276, -1.8454742432, -0.9734540582, + -1.0773816109, -1.5850419998, -0.7565042973, -0.8189355731, 0.4546409547, 0.1463429332, 0.2750940919, 0.3259109557, + -1.6890685558, 0.646977365, -0.545937717, -0.39983055, 0.8339851499, 2.4585688114, 0.1916992962, 1.0748101473, + 0.935746789, -0.0929414183, -0.6584252119, -0.3570420742, 0.0665325448, 0.7298585773, -0.8224898577, -0.6889728904, + 1.1683588028, 0.0241510794, 0.6844079494, 1.1921299696, 2.1824836731, 0.4918388128, 1.9142444134, 0.480209142, + 0.7324468493, 1.3169702291, -0.0847907364, -0.4453571439, 0.3699448407, -1.0258462429, -0.3116862476, -0.0516151153, + 0.795312047, 0.6979629397, 2.1893255711, 0.3988084495, -1.166588068, 0.6708530784, 0.6878688931, -0.8248539567, + -0.5847064257, 0.5866395235, -0.3840931952, 1.4220393896, -1.101864934, -1.1234416962, 0.4223946333, -1.5349240303, + -0.0431141518, 0.2294328213, -0.6951954961, -0.4299486279, 0.9124315977, -1.1123651266, -0.0226851795, -0.6936195493, + -0.0072121215, -1.1652355194, 0.1803177744, 0.5420455933, -0.1974164546, -0.1034566686, -1.1659656763, 1.4620234966, + 0.067657344, -0.1860376447, -0.0255707297, 0.5868535042, -0.712444365, 1.873052597, -1.4280098677, -1.2111260891, + 0.0161925871, -1.0231288671, 1.153349638, 0.0843438879, 1.8062423468, 0.4847639501, -0.1865802705, -1.1985164881, + -0.7404387593, 0.4595836401, 0.3563097715, 1.2884920835, -0.1245478317, -0.0213925559, -0.2822938859, -0.7291942835, + -0.8705769777, 0.9221906662, 1.9151195288, 0.2899247408, 0.18491669, 0.061702773, 0.9693223834, 1.1434739828, + 1.3673071861, 1.3153882027, 0.0179758314, -0.644585073, 0.1999620199, -0.6685073376, 2.1232419014, -0.571973145, + 0.6747733951, -0.0902681053, 0.5864809155, -1.6446373463, 0.9344949126, 0.1072397977, 0.9640066624, 0.2265440077, + 0.1202564687, 1.8057010174, 1.2321231365, 0.1216363013, -0.8128648996, -1.1337174177, -0.4002026916, -0.3188920021, + -1.5820558071, 0.6039871573, -0.986486733, 0.6012089252, 2.4563450813, -0.5732899904, 0.9521592259, 0.3260547221, + 1.8853037357, -1.3204982281, 2.0496821404, -2.2340407372, -0.6887130737, -2.2608993053, 2.0778744221, 2.7424345016, + 1.0892106295, 2.5908606052, 0.7477040887, -1.4859695435, -1.3533649445, 0.5172604918, -0.2675825357, -2.2346560955, + -0.7207927704, 0.6210254431, 0.4351610541, -1.5440757275, 0.7776510715, 0.8183146715, -1.9388126135, 0.6442348361, + 0.1557279527, 1.6979936361, -0.487049371, -0.206946969, 1.2790093422, 0.0868159607, 1.1734422445, -2.376175642, + -0.2298842072, 1.1400439739, -0.6254145503, -0.4515355527, -0.3749254644, 0.8611729741, 0.4854235649, -0.1822100878, + -2.0930531025, 0.222231999, -1.4868695736, -0.3692798316, -1.3354876041, -1.3781586885, -0.2719875872, 0.9334027171, + 0.5190452933, -0.8337520361, 0.4389167726, -1.2404805422, -1.358682394, 0.8238016367, 0.0736838952, -1.8239998817, + 0.67038095, 0.2388516814, -0.8363975883, -0.5493038297, 1.1531976461, -0.220398441, 0.8369795084, -0.300458461, + 1.3316445351, 0.2204501927, -1.3941072226, 0.5796142817, -1.4743403196, 0.2360322624, -0.0470898226, 3.3544440269, + -0.038329646, 0.5620162487, 0.3400013149, 1.66984272, 0.3058384955, 1.0403901339, 0.7896620631, 2.2139503956, + -0.8617098927, 0.0116197933, 0.2294577211, -1.6858422756, 0.8578336239, 0.0620743819, -0.1545120627, 0.3085938692, + 0.7593377829, 0.606554985, -0.5367869735, -0.5062915087, 0.9420825839, 0.3617729843, 1.5440033674, 0.1615864933, + 0.065919973, 2.2409822941, 1.7344744205, 0.8405517936, 1.2798552513, 0.2383038104, -1.1642180681, 1.2421092987, + -0.6393301487, -0.7457547188, 1.6431002617, -1.1643340588, 3.0044844151, 0.3767578304, 0.5810221434, -1.0409605503, + -1.0302780867, 1.0567331314, -0.5488164425, -1.0528279543, -1.1218669415, 1.9058232307, -0.3550024033, 0.3868098855, + 0.3766503632, 2.7125041485, 0.2050943375, -0.1935515255, -0.2608304918, -0.7655370235, -1.3006209135, 1.7410725355, + 0.3444109559, 0.9625317454, -1.5197042227, -2.2566416264, 0.11587134, -0.3307718933, 0.0338330679, -0.2279780209, + -0.6273221374, 0.589268744, 0.0315760486, -2.4211452007, -0.5741143823, -2.9741172791, 1.8141866922, -1.2270373106, + -1.7089072466, -1.247256875, 0.2550107539, -0.2996766865, 0.6542093158, 1.1454129219, 0.3152971268, 0.0964322165, + 0.3907919824, -2.0905296803, -0.6558496952, -0.3131229579, -0.4145734608, -1.6045930386, -1.1430335045, -1.1225223541, + 0.574215591, 0.2588180602, -0.8291150331, 0.327159673, 1.0199117661, 0.4195581079, -1.231264472, 1.2604261637, + -0.1361154765, 0.9647939205, -0.8266542554, 0.4887631536, 1.7701907158, 0.7247890234, 0.4453731775, -0.8973620534, + 0.3199851513, 0.0539685972, -0.810649097, 0.0733280629, 0.0133526186, -0.6579945087, -0.3815068007, 1.3540554047, + -1.3347084522, 0.4231979549, -0.3235702217, 0.0383079089, 0.2308514863, -0.996044755, 0.0932694674, 0.1048167944, + -0.6200649142, 1.2804870605, -0.0674211308, 0.6397436261, -0.1728785187, 0.1322377771, 0.6113134623, -1.3866189718, + 0.2125978023, 0.0523288436, -0.3402370811, -0.2536427975, 1.3289234638, -0.403377533, 0.6017901897, -0.8228362799, + -0.7473247647, -1.4831603765, 0.3024454117, 0.1503181756, -0.6277262568, 0.4740160704, -0.1196713299, 1.7544775009, + -0.0974104479, -0.1266327649, 0.9487879872, -0.4919475019, -1.539259553, 0.6162174344, 0.5011700988, 0.9101887941, + 0.8777204752, 1.2595125437, 0.4018152654, -1.7166287899, -0.8698635697, 0.4974375665, -0.0144640859, -1.7648240328, + 0.9489676356, -0.4182487428, 0.4941950142, -1.1213845015, 0.2394562066, -1.8312802315, -1.4354618788, 0.9216833115, + -0.8544840813, 1.0875998735, -0.917181015, -1.139903903, 1.3363617659, 1.1059136391, 0.8108481765, 0.2172601074, + -0.6312165856, 0.6373825073, 0.4367862642, -0.8210284114, -0.7013685107, -0.4239511788, 0.5677524209, -0.2321190834, + 0.2549104989, -0.988058567, 1.1797896624, -1.8412686586, 1.3705574274, -0.4650182724, 2.6413793564, -0.4931051433, + 0.0091245165, 0.2830466032, 0.3595472872, -0.4690435529, -0.6955348849, -1.0818399191, -1.2531290054, -1.535441637, + 0.6554519534, 1.2130562067, 0.1278675348, 1.0614162683, 0.0805788711, 0.1987828314, 0.7905623913, -1.1146622896, + -0.7665066123, -0.4313217998, 0.2837044001, 0.1385461688, -0.6566702724, -0.7525277734, -0.3352095187, -0.048835054, + 0.6274835467, -1.3588238955, -0.6190199256, 0.0382770114, 0.0188390687, -0.311743021, 0.7832928896, -0.0662060976, + 0.0303651243, 0.4428240955, 1.100804925, 0.4989125729, 0.3406849802, -1.3838136196, -2.5580713749, 0.1072607487, + -1.701023221, 0.501591444, 0.3309070468, -0.2240238488, 1.1814460754, 1.0675925016, 0.2472229749, -1.1753770113, + -1.4115841389, 0.659979105, -0.8903461695, -0.7513751388, 0.4441344738, 0.0984115377, -1.632835865, -2.7814333439, + 0.0352627784, -0.1952062249, 2.5094332695, 0.2350155562, -0.7036231756, -0.6226969957, 0.1006892025, 0.2735290527, + 0.3248717487, -0.9859005213, 0.588406086, -1.6339645386, 0.6399517655, 0.0949723125, -0.8603503108, 0.7330551744, + -0.4018296599, 0.0621890053, 0.9158736467, 1.1411347389, 0.4787520468, 1.3159184456, 0.6555212736, -0.105064854, + 0.5479673743, 0.1422740966, -0.0826835856, -1.1075340509, 0.2643381357, -0.1198114604, -1.2939515114, 0.4103282094, + 0.9645326734, -0.5595097542, -0.3438761234, 0.90686059, 0.7637982965, 1.2814041376, -1.3839570284, -0.5809727311, + -0.3262540698, -1.5268710852, 1.2061607838, 0.9503488541, 0.056506779, 0.5170537233, 0.8136867881, 0.9898092151, + -0.554445684, -0.2870925963, -1.6100064516, 0.2155759931, -2.0440261364, -2.6521677971, 0.64103055, 1.6874045134, + -0.6198192239, 0.6183931231, -0.3552034199, 0.3808440566, -1.5048646927, -0.7682568431, -0.3286943138, -1.2153249979, + -0.8321967125, 0.6857488155, -0.7768926024, 0.4683583379, 1.4393649101, -2.0580306053, 0.24175556, -0.1287895143, + 0.9849979281, -1.2673319578, 1.4937902689, 0.6139543056, -0.701105237, 1.6358752251, -0.5591640472, -1.8699896336, + -1.203764081, -0.4650449753, 0.4130979478, -0.4781028628, -0.3773052096, 0.48969841, 0.5291000605, 0.2909781933, + -0.1239582077, -0.2593092024, -0.755155623, 0.0570368096, 0.7843011022, -1.3545408249, 0.3017587662, 0.3814600408, + 0.1865427494, 0.3018524945, 1.1108403206, 1.438593626, 1.2737234831, -0.1687798649, -0.2700041831, 0.0939677283, + -0.5982590914, 0.0442983992, -1.2631759644, 2.1559460163, -1.0446652174, 1.4373403788, -0.5136585832, 0.5201707482, + -0.193032071, 1.4882138968, 0.1718825847, -0.6136702895, 0.1616206765, -0.1911924034, -1.360652566, -0.6224917173, + -1.8901438713, 2.1093156338, -0.5344481468, 0.5858753324, -0.1767421663, 0.5121246576, -0.4941667914, 0.424859345, + 0.316167593, -0.8331077695, -1.4626350403, -1.7189588547, -0.2488492578, -2.32467556, 0.8617739081, 0.4979015291, + 0.7135391235, 1.3816496134, 1.7785661221, 0.1185933501, -0.0692301467, 1.3845703602, 0.9387071133, 0.1926213652, + 0.1305808425, -2.9852871895, -0.5626637936, -0.8844199181, -1.3015922308, -1.2187414169, -1.1000576019, -0.3812155724, + 0.7491910458, -0.7949401736, -0.1017555743, 0.5167959929, -1.2674736977, -1.3182394505, 0.3694709241, 1.0132818222, + 2.0066077709, 0.0588135272, -1.0413175821, 0.4451495111, -1.5961176157, -0.5127106905, -0.0736058503, 1.2943279743, + 0.9867642522, -0.3749952614, 0.021950921, -0.4264596999, 0.6405826211, -0.2793408334, 0.3446552455, 0.2953101695, + 0.4174514413, -1.3424669504, -1.2077305317, -0.5029827356, -0.9704607725, -0.579139173, -0.341024816, 1.220328927, + 0.3139457703, -0.6450718641, 1.9737294912, 0.0937890559, -0.7589262724, -0.000452621, -0.1392761469, -0.5184856653, + -0.6445096731, -2.0933535099, 3.6174440384, -1.401493907, -0.3285408914, -0.0851450935, -0.4968545437, 0.8777781129, + 1.2304735184, 0.9676017761, 0.299245894, -1.0884692669, 0.7705311775, 1.2788481712, -0.4678036571, 0.8469130397, + 0.569797039, 0.3013136983, 0.7260673642, 0.2109190971, 0.9467196465, -1.5477573872, -0.7547515035, 1.0165404081, + -1.2013443708, -1.0009258986, -1.038112402, -0.9545734525, 1.0061957836, -1.3585246801, 0.2498244196, -0.6100196242, + -1.931907773, -0.3646067679, -1.4917006493, 0.7829834819, 0.7965960503, -0.8203605413, 0.7800762057, -0.1055379063, + 0.3846244514, -0.903345108, 0.9355486035, 1.3010201454, 1.5083156824, 1.0601898432, -2.1822016239, 0.0641560182, + -0.1708367616, 2.2009952068, -1.4505349398, 0.6033412814, -0.3475028276, -0.0245241802, 0.9902088046, 0.787185967, + -0.2820515037, 0.683760643, 1.7600520849, 1.7086303234, -1.3337498903, 0.5148547888, -0.1411535144, -0.5787584782, + -0.1753298044, 0.7662317753, 2.2890543938, -0.3373456299, -0.7940471768, 0.0870957598, 0.2046343088, -0.3655799031, + 0.1403742582, 0.7487806678, -0.0493908785, -1.0613024235, 1.6651679277, -0.07211034, -0.9661730528, -0.0118546663, + -1.2443343401, -1.8370332718, -1.1943985224, -1.3811161518, 0.0265875105, 0.7113240957, 0.4174372852, 0.7321901321, + 0.316585362, -0.8200309277, 0.910449326, -2.0742957592, -0.8789162636, -0.6044740081, 1.7389211655, 0.302746594, + 0.8017164469, -0.1329290718, 1.1411834955, -1.2318832874, -0.2818616629, 0.3668227494, -0.1943957955, 0.1467296183, + -0.9400892258, 0.621647954, -0.3850940168, -0.2756251991, -0.0756106824, 0.6708564162, 1.7877844572, 0.2348715514, + -1.1913688183, 0.1658644378, 0.3144343793, -1.804308176, 0.8749025464, 1.137815237, -2.594316721, -1.2024546862, + 1.2210763693, 1.1203122139, 0.1245990917, -0.9790798426, -1.1268764734, -0.4267218709, -1.6712464094, -0.2931473255, + 0.9772987962, -1.3596971035, 0.0209441744, 0.3558107018, 1.1550899744, -0.5986868143, 0.31850788, 0.6811698675, + -0.3164308965, -0.1549912542, 0.0994456187, -0.1038790345, -1.7121478319, 0.2452230304, -1.0489326715, -0.2093195915, + -0.4916971028, 0.8829078674, -0.1305598617, 0.0435559079, -1.498083353, -1.2615302801, 0.0852286965, 0.5818434954, + -0.8840133548, -0.4041324556, -1.0049831867, -0.5677416921, -1.8189404011, 0.6888154745, 0.4762073457, -1.6676757336, + -0.0117815798, 0.9636470675, 0.2832666636, -0.356367439, 0.9574931264, 1.1856490374, 0.193058297, 1.137298584, + 1.4829488993, 0.4178263247, -1.0189751387, 1.3939164877, -1.504362464, -0.2485114038, -0.4893157482, -1.0204097033, + 1.2906845808, 1.1540821791, -0.4610202312, -0.4744220972, -0.0785018057, 0.5601623058, 0.2905760109, 1.2008045912, + -0.9055359364, -1.2546924353, -1.3627620935, -0.4191326201, -0.2417927384, -1.6857676506, -0.6772042513, + -0.7309972644, 1.0813498497, -2.3207206726, 0.3441968262, -0.6235502958, 1.6584020853, -1.7576291561, -0.8164684176, + 2.6233417988, -1.4983351231, 0.0849152654, -0.2290281355, -0.655557394, -0.1725483537, -0.3922250867, 1.2119016647, + -1.9553462267, -0.6105675101, 1.1522092819, 0.6248836517, 0.0559881888, 0.4049755335, 0.0688843802, -1.0096157789, + 0.3500415385, -1.3688995838, -1.1148210764, -0.258626461, 0.0292662345, 0.2617202699, -1.1088030338, -0.2185048759, + 0.1528363377, -0.1823088825, -0.7560430765, -0.8633227348, 1.8211431503, 1.2482187748, -1.0431731939, -0.1619359106, + -0.2505675554, -1.1278392076, 1.4434571266, 0.1162277162, 0.8356947899, 0.2004559189, 2.7481603622, -0.6122629046, + -0.1336817294, 0.9449667335, -0.2098537385, -1.0220044851, 0.1911619157, -0.6354675889, -2.6473999023, -0.4538244307, + -1.0034236908, -0.4797924757, 0.3036291897, -0.7502538562, 0.3391863406, -0.3267144859, -1.5663520098, 1.5844787359, + -0.1541496515, 0.0080233496, -0.245767653, 0.580242753, -0.2375820726, 0.4829804897, -3.2749388218, 0.69980371, + -0.8014594913, -0.985634625, -1.3622802496, 0.9920208454, -0.8667515516, -1.1467056274, 0.8337497115, 1.4432774782, + -0.4017332196, -0.1752787232, -0.1312951446, 0.5203475952, 1.6061456203, -0.3765571713, 1.2273452282, 1.0681328773, + 0.5741702914, 1.6537784338, -0.1392436624, 1.5222073793, -0.4666440189, 0.8264855742, 0.2139969468, -0.7227970362, + 0.1318987459, 0.6431787014, 0.0269627497, 2.9194891453, -1.3445217609, -1.3357516527, -0.3646216989, -0.3339246511, + -0.9061585069, -1.7167688608, -0.2931183875, -1.2002370358, 0.0027208761, -0.8410323262, -0.851352036, -0.8169867396, + 1.7177858353, -1.078605175, -0.9716501236, 0.7862368226, 0.4703477919, 1.5872616768, -0.6943163872, 0.579515934, + -0.4428988099, -0.0336347744, -0.0675015002, -1.1188058853, -0.0059059928, 0.3079329729, -1.5865097046, 1.1954914331, + 0.010738885, 0.2328452766, 0.3771139979, 0.1556452364, 0.5254788399, 0.7656033635, 1.8018838167, 1.3587571383, + -0.1060156971, 0.5899567604, 1.1444541216, -0.3648647964, 0.3766710162, 0.0900015309, -1.0156743526, 1.4167870283, + -1.1703493595, -0.6448116302, -0.1051116288, 0.0020963072, -0.0745361373, 0.8696280718, 2.8341960907, -0.351367861, + 1.3280119896, 0.1946055442, -0.5135858655, -0.5002872944, -0.3048385382, 1.4506249428, 0.0044972659, -0.0088738408, + 0.6910936832, 0.6415634751, -0.6344572902, 0.2697565854, -1.0585714579, -0.5347191095, 0.4512789249, -0.7875731587, + -0.1061345711, -0.3123532832, -0.6738702059, 0.7054605484, 1.8631844521, 0.6854217649, -2.4223566055, -0.3866092861, + 0.4214096665, -0.6705033183, 0.6293103099, -0.96065557, 0.4024822712, 0.9286620617, -0.2251343727, 0.0375308469, + -0.6891617179, -0.4474659264, -0.4347704947, -0.248887673, -0.6395900249, -0.6902248263, -0.8352594972, -1.1157217026, + 1.1579307318, -1.0021015406, -0.9917744398, -0.5251912475, 0.3097694218, 0.9646864533, 0.4288187623, -1.4920967817, + -0.5031630397, 2.0002958775, -0.8010430932, -0.1773892045, 0.707854867, 0.7890493274, -0.7094715238, 0.0394469835, + 1.513094306, 1.0473628044, 0.7980496287, -0.2446120083, -0.8357499242, 0.3035597503, -0.0023617276, 1.8378235102, + 1.0127995014, 1.0019253492, -2.0041329861, 0.5986630321, -0.8298110962, -0.497765094, -0.7103406191, 1.1140469313, + -1.0463049412, -1.1186000109, -0.6619963646, 0.4847993851, 1.1088175774, 0.1798587739, 0.6712608337, 1.7970820665, + -0.7250568271, 0.5614169836, -0.3647833765, 0.2266235948, 0.4138481319, -1.9311686754, -0.9302152395, 1.2558653355, + -0.9853758812, 0.7505119443, 0.8275774121, -1.0908306837, 1.4267879725, 2.1317381859, -0.0587358475, -0.6239714026, + 0.5322213769, 1.2944272757, -0.541590035, 0.3425603509, -0.0551128164, 1.2260411978, -0.3073526919, -0.0158004314, + 0.044610437, -0.287443161, -1.3118320704, 0.3087975979, 0.4541290104, -1.3672093153, 1.0977481604, -1.3857321739, + -0.3321656585, -0.7112305164, 1.7794216871, 0.7596542239, 0.9350003004, -0.6077075601, 0.311758846, -1.4983228445, + 1.2511718273, 0.2724351883, -0.1407505125, -0.5702785254, 1.9123885632, -0.0837195367, 2.3620803356, 0.5817832947, + -0.6662903428, -1.4938615561, 2.1392271519, -0.7084274292, 0.35443905, -0.1004240811, -0.7890850902, -0.6086986065, + 0.4826420844, 0.5797073841, -0.9093092084, 0.5444802046, -2.0700707436, -0.4536957741, -1.0652302504, -0.5660454035, + -0.6453261375, 0.5172896981, -2.2897562981, -0.8132987022, 0.9573528171, 0.1642129719, -1.1041778326, -0.2960029244, + 0.8012885451, -0.6051740646, 0.2041897923, -0.2072525769, 1.1589853764, -0.4625106752, -0.4647492766, -0.1737691313, + 1.1656908989, 2.6465435028, 0.7356799245, -0.6035447121, 0.7761955261, 0.125859648, 1.3203146458, 0.042809274, + -0.5732164979, 0.5334172249, -0.4383377433, -2.6443896294, -0.4882341325, -0.4131014943, -0.6506836414, -0.0589487515, + -1.1589503288, 0.0197763573, -0.4185853302, 0.7655056715, -0.3029468656, 0.7333875895, 0.5726686716, -0.283606708, + 0.0208763424, -1.9726077318, 1.9458686113, 0.8031986356, -0.5565538406, 0.3064076304, -1.3078083992, 1.3880399466, + -2.498611927, 0.2955805659, 0.4166693389, 0.3991940618, -0.3132807612, 1.9816641808, 1.2151714563, 1.7478718758, + 0.2781778276, -1.2538698912, 0.3590858877, -1.6911876202, -0.324239254, 0.0751941875, 2.0730650425, 0.8241178393, + 1.5471822023, 0.4346613884, -0.2523943782, -1.6861196756, 0.3959576786, -0.3940330148, 2.2799172401, -2.1057817936, + -0.6796046495, -0.2385020703, -1.6790004969, 0.6090376377, -0.2106702179, -0.5197761059, 0.8246834278, -0.6630619764, + -0.6153048873, 0.3878263831, -1.6378360987, 0.2738104463, -0.695607543, -0.6798497438, -0.0288074967, -1.8039088249, + -1.1410199404, 2.5300855637, -1.3932182789, 1.190870285, -1.0227982998, -0.9062312245, 0.8252307773, 1.0381580591, + -0.2450716347, -1.2224311829, -0.5532920361, 0.0643740818, 0.4217404425, 0.9086120129, 1.4833407402, 1.8077830076, + 0.187952593, -0.2831076384, 0.8077802658, -0.0759647638, 0.7265745401, 1.4762508869, 0.3692570925, -0.8803898692, + 0.5382549167, -0.4830761254, 1.4964990616, -0.4836547375, 0.4294926524, 1.5498590469, -1.8430325985, -2.7364418507, + 1.1671922207, -0.4623150527, -0.0125561962, 1.8133157492, 0.441544503, 1.3514368534, -0.6283529401, 0.9533058405, + -0.9504081607, -1.3233529329, 0.0559342392, -0.3043320477, -0.6132194996, 0.2827467918, 0.0211385582, 0.6981754899, + -0.3219046593, -1.182108283, -1.6019649506, -0.7358622551, -1.5021909475, 1.3134816885, 1.0149642229, -1.4239060879, + -0.4501751363, 1.4480149746, -1.8850461245, -1.0855251551, -0.0552835427, 1.112655282, -0.3457433283, 0.3627731502, + -1.2939021587, 0.0297653861, -1.0057828426, 1.3407930136, -0.0574732423, -0.0764587745, 2.4194180965, -1.4760574102, + -0.5405495167, 1.348089695, -0.982319355, 1.7727591991, -0.7762312889, -1.1459913254, -0.969076395, 0.320540905, + 0.2968346179, -0.0867063925, 1.4222966433, 0.0621957928, 1.0828131437, 0.5762202144, 1.8638826609, 0.0221075136, + -0.4786196649, -0.5847828388, -0.0353326574, 1.8716874123, 0.34403193, 1.1833447218, -0.8264019489, -0.4332354665, + -1.6377058029, -0.2957936227, 0.4296649694, 0.033003483, 1.4408249855, -0.9070200324, -0.22335352, -0.5568699241, + -0.0201630127, 2.8606996536, 0.1218447164, -1.1993663311, -0.1101554483, -0.0428591706, 0.5230171084, 0.9578502774, + 0.3164121807, 1.4629195929, 0.7499135137, -0.6314778328, -0.8180010915, 0.9594846964, -0.0734098107, 0.353479147, + 0.2100719959, -1.3744202852, 0.9371819496, 1.8197331429, 0.0385162905, -1.4419538975, 0.4320627749, -1.0061644316, + 0.3089143634, -0.1311210543, -0.8641072512, -0.7125442624, 0.9392834306, -0.6008676887, 2.2745432854, -0.0422098339, + 1.4438676834, 0.7602827549, 1.7542577982, 0.3981570899, 1.5356993675, 0.2983169258, 2.0158410072, -1.3415718079, + 1.8989692926, 1.7546209097, 1.2540712357, -1.6169677973, -0.8762540221, 0.9787555337, -0.6943745017, -0.0487157442, + -1.8384969234, -0.075906828, 0.4606977403, 0.4347637594, -0.4993920028, 0.2148143649, -2.0123169422, 1.6227184534, + -0.2299919575, 1.4253363609, -0.383814007, 0.2162957191, 1.7839958668, -0.6574246287, 0.2178135365, 0.4388503432, + 0.5152842999, 2.0197911263, 0.3589576781, -0.1519799829, -1.3294918537, 0.3256805837, -0.3265584409, -1.4352842569, + -1.0348974466, 0.6977605224, -1.468108654, -1.1425429583, 0.6803500652, 0.4048239589, -1.0909260511, 1.1290786266, + 0.8217989802, -0.9025979042, 1.1533937454, 1.0704193115, -0.4884494543, 1.4770652056, 0.0373433903, 0.0077836541, + 0.6826797724, -0.8579919338, 0.2251290381, -0.9385836124, 0.7698971629, -0.1225737706, 0.121875979, -0.38051337, + 0.0967485979, -1.884447813, 2.3024020195, -0.6849756837, -0.3304445446, -1.2974334955, -0.6761263609, -1.4177010059, + -1.3832147121, -1.3262499571, -0.3938881457, -0.6269910932, 0.2355906516, 0.5818787813, -0.0156290065, -0.4996424615, + 1.8249180317, -0.2702373266, -0.0378957987, -1.3491808176, 0.831627965, -1.3577632904, -0.7994315624, -0.3274593353, + -0.8930548429, 0.6743643284, 0.5958985686, 0.0216204133, 1.6101511717, -0.9585517049, -0.3917265534, -1.8435053825, + -2.2900974751, -0.6511493921, 2.3449501991, 0.133549422, -0.115485087, -0.0498552248, -0.5847663879, -0.7291586995, + 0.2750283182, 0.7288957238, -0.2256766409, 0.7525697351, 0.9032928348, 1.1697378159, 0.3740186095, -0.6911426783, + 0.3261582851, -0.2271312475, 0.464794606, 0.0876392424, -1.1337498426, 0.8469501138, 0.7095554471, 1.2220104933, + 1.0301719904, -0.7379205823, 0.9471271634, 0.3801421523, 1.1546025276, 0.5475896597, 0.0115259765, 1.3954277039, + -0.7114993334, 0.9818466902, 0.1740345955, -1.672232151, -0.5188888907, -1.2580188513, -0.0774400756, 0.3143561482, + -0.5942593813, 0.4429920316, 0.6551231146, 1.8638199568, -0.8231512308, 0.9583299756, -2.8441357613, -0.4623622894, + -1.1016976833, -0.3292089701, -0.349047482, 0.7918364406, 0.101052247, -0.5955529213, 0.8099021912, -0.6571288109, + -0.5177548528, 0.7080375552, 0.4156391323, 0.6487434506, 1.0146337748, -1.5045164824, -0.4959926903, 0.1978851706, + 1.0364204645, 0.0211838745, 1.3547075987, 1.0349222422, 0.2016938329, -0.7771456838, 0.3141413033, 0.4111408889, + -1.7946816683, -0.8617743254, 0.4630215764, -1.4796572924, 0.2156282216, 0.0648754835, -1.1287294626, 0.8153375983, + 0.8462402225, -0.9069088697, -0.2586428821, 1.5503832102, 1.2572857141, -0.8906383514, -0.1220265105, -0.3822940588, + -0.1107923314, 0.3378605247, -0.4759807289, 0.8223170638, 0.5999978185, -0.5032872558, 0.7468966246, -0.5116183758, + -0.641674161, -2.3637897968, 0.5536193252, 1.0693031549, -0.1984776855, 0.5212368965, -0.101035811, 0.1642877162, + 2.542027235, -0.8539747, 0.0189713798, 1.4053024054, -1.0632971525, -0.9598603249, 1.3750352859, -0.4135048091, + 1.8846297264, 1.1503682137, 1.0024423599, -0.021284353, -0.7975702882, -1.5567365885, 0.1432193369, -1.2462441921, + 0.1648118943, -1.9669402838, -0.0362720527, 1.8989335299, -0.7362707853, -0.0263065547, -1.307494998, -1.6733379364, + 0.4589193165, -1.5560327768, -0.2851602435, -1.1524580717, -0.7894440293, 0.2129414976, -0.0265334882, -0.9173115492, + -0.1233007684, -2.1116597652, -0.2548934221, -0.1000629812, -0.2341962755, -0.5075214505, -1.009760499, 1.6759552956, + -1.1805329323, 0.3522910178, 1.1721547842, -0.8795605898, -0.2225883007, 0.3419721127, -0.553140223, 0.5414720178, + 1.1503173113, 0.8090146184, -1.1797549725, -0.4781074524, -0.4606604576, -0.6850347519, -1.0958294868, -0.8130276799, + -0.4801674187, -0.5496889949, 0.1198312268, 0.9770823121, 1.0006096363, 1.5605578423, -0.2776606977, 1.5436390638, + 1.3431284428, -1.0694115162, 0.0319580436, 1.0235497952, -1.6327320337, 0.2094062716, -0.2779122591, -0.2549938858, + 0.923529923, -1.7200658321, 1.3078080416, 0.314160645, -0.9713298678, 0.6507166624, 0.5240988731, -0.8743537068, + 0.2245029956, -1.6577179432, -0.89956218, -0.5963401794, -0.302806437, 0.6373192072, 1.0106426477, -1.1714172363, + -1.1551836729, -0.1290144324, -0.4418173432, -0.5398723483, 0.7920086384, -0.1006233692, -1.2925938368, 0.4630675614, + 0.5318786502, 1.0925804377, -1.8792281151, 1.2360200882, -1.088206172, 0.2990363836, 2.0535075665, -1.3437252045, + 1.7961989641, 1.0472359657, -0.6580789089, 0.363787204, 0.8887823224, -1.0567698479, -1.4380348921, 0.3630021513, + 1.080145359, 0.0848029777, 0.3457524478, -0.5923113227, -1.1642155647, -0.6858039498, 0.2838497758, 0.1613612771, + 0.3430170417, -0.0750150234, -2.2998411655, 0.1167422906, -2.1216418743, -0.7399117947, 1.0929222107, -0.8083111644, + -0.4524880946, -0.5343817472, -0.2154788822, 0.5326138139, -0.4642713368, 0.3502049446, 0.2950757146, -0.3348174989, + 0.6952251792, -0.7663141489, -0.1191459745, 1.8016871214, 1.1503630877, 0.0879920721, 1.6557919979, -0.9713310003, + -0.0952440724, 0.0566643141, -0.4121611416, 0.3589834869, -1.2417886257, -0.398178786, -0.0955326259, -1.1746367216, + -0.0903539136, 1.8228377104, 0.1594277769, 1.3675057888, -0.8630368114, 1.4712395668, 0.105400987, -0.236863032, + 2.3829298019, -1.6929466724, -0.7913834453, -1.4271126986, 0.2466607392, 0.1234057769, -0.3978918791, 2.7214033604, + -0.6303295493, 0.019805301, -1.1812092066, -0.1202231199, 0.3901976645, -1.0169278383, -0.311868906, -1.2093325853, + 1.5801656246, -0.126261428, -0.277284205, 1.7430753708, 0.7829131484, -0.9974278808, 0.5059066415, 0.2753480971, + -0.817070663, 1.4233903885, 1.3587424755, 0.3708223104, 0.2664794624, 0.0544346385, 1.0021533966, -1.4790313244, + 0.5714965463, 0.5185027122, 1.2404508591, -0.3423627019, 1.043320179, -0.5620381236, -0.799950242, 0.3974117339, + 1.3396379948, 0.5925657749, 0.5062606335, -0.9846734405, -1.2468835115, 0.1999926269, -0.7213277817, 0.500249505, + -0.7886040211, 1.4698174, 0.5244092941, 0.2752928734, 0.4098138809, 1.4521061182, -0.7069355249, 1.2058763504, + 1.6311770678, 0.2563337386, 0.5263522267, 0.1898272932, 0.8347653151, 1.3658587933, 1.1031242609, -0.0868932381, + -1.0478790998, -0.6240808964, -1.3151839972, -0.683198452, 0.8852385879, 1.6934367418, -0.3677411377, -1.4583725929, + -0.6255928874, 0.8111643195, 2.1374673843, 0.7400379777, 0.1656147391, 1.7086645365, -0.0734900981, 0.8953284621, + -0.6813739538, -0.0614439286, -1.2261948586, 2.0596497059, -1.5261852741, 0.6271134019, -0.3758432567, -0.9482771754, + 0.0166640133, -1.3925417662, -0.6260951161, -0.0622643456, -0.3813502789, 0.5994868875, 1.6862668991, 0.5603588223, + -0.044913806, -0.1375849396, -1.6965512037, 0.3292586803, 0.3680608571, 1.5089581013, -1.29354918, -1.4540292025, + 2.0181722641, 0.1847225428, -1.5040644407, 0.8418682218, 0.3571032286, 0.1277844757, 0.6452940702, 0.8302066922, + 0.3316073716, -0.4937435985, 0.1727012694, 0.3508908153, 0.49429667, -0.1890991032, 0.1464315653, 1.2672983408, + -0.542001605, 0.3489682674, -0.1656922847, 1.8272436857, -0.0872897953, 0.6986168027, -1.1467864513, -3.086946249, + -0.6514915228, 1.3085490465, -0.1464149803, 0.5489206314, 0.3809079528, 0.1223399192, -0.2563851178, -0.3303251863, + -0.8524194956, -1.043862462, 0.9942628741, -0.7164640427, 0.2523762882, 1.8409081697, -0.0395202041, -1.9294208288, + -0.4429220259, -0.2262780219, -0.6784824133, -0.4743759632, 0.1318203062, 0.1481006593, -0.0424164087, -0.5459465981, + -0.7982281446, -0.4270841181, 0.8304693103, -0.3444064856, 0.0296886452, -0.025515141, 0.2025533468, 0.6004497409, + -0.5635874867, -1.3864352703, -0.5710804462, 1.3912957907, 0.1319333613, 1.6396538019, -0.833629787, -0.6034071445, + -1.9802199602, -0.0118512791, -0.1108769551, -0.0129075134, -0.2374236435, -1.5954982042, -1.3275305033, + -0.4772657752, -0.2762099206, 0.856154561, -1.011208415, -0.6464535594, 1.1537920237, 0.2840941846, 0.1511519849, + -0.1263342947, -0.3606207073, -0.984084785, 1.4167820215, 0.6281455755, 0.8761416674, 0.0240065102, 0.0428546667, + 0.7045249343, 1.3199563026, -0.2455899715, -0.4333233237, 0.0839606822, -0.5357459188, -0.5189141631, 0.0773424804, + -2.4033913612, 0.5579027534, 0.2220277339, -0.1305405945, 1.1741777658, 0.184239015, -0.1543905437, 0.2372447699, + -0.0578634739, 1.126814723, -0.6168632507, -0.6207220554, -0.3247307837, -0.6050617099, 2.4619061947, -0.5523837209, + 1.7028896809, 0.0241982024, -0.3090949655, -0.1183786169, 0.6874657273, 0.597743392, -0.3424105048, 1.0477715731, + 0.0600404032, -0.4835692644, 0.2377821803, -1.9360288382, -1.1095243692, -0.2601641417, 0.7298178673, -0.9078957438, + -0.7949860692, 0.5281986594, -0.0193301439, -1.4828484058, 0.4641183615, -0.6966081858, 0.6504861116, -0.7225518227, + -0.0420571826, -2.2333300114, -0.6292539835, 0.3642581701, 2.1744987965, -1.4005479813, 0.6594906449, 0.0190161932, + 0.7265573144, 0.4081478715, -2.0283536911, -0.227753371, 0.2533299625, -0.2692781985, 0.8519235253, -0.9961074591, + -1.3291726112, 1.1561888456, -0.1695564687, -0.6412171721, -0.5963202119, -1.2543619871, 0.3706256449, 0.2367728949, + -0.8329231739, 0.121282734, -0.1572631747, 0.4193502367, -0.5477141738, 0.4441763759, -0.1068404242, 0.6890825033, + 1.2757037878, -1.3237390518, -0.7205080986, -0.2300838381, 1.9304093122, -0.8222891092, 2.3237411976, -1.5258569717, + -0.2129818201, 1.1545015574, 0.1849959046, -0.4873098731, 0.579754293, 0.4350897372, -0.4880842566, 1.4818840027, + 0.704197824, -0.0506795347, 0.4129129052, 1.2196661234, -1.2100301981, -0.6907811761, 0.2639520168, 0.6720523834, + -0.1672959328, -1.3558725119, 1.5750267506, 0.5315433145, -1.3783342838, -0.5600621104, 0.1594666988, -0.125261873, + 0.1798083037, -0.3277032673, -0.8285724521, -2.2868967056, -1.3793725967, -0.7088655233, -2.1242513657, 1.8299680948, + -0.048720222, -1.1619849205, -0.7737154961, 1.1845551729, 0.0657233149, 0.5641449094, 1.8346886635, -1.1153488159, + -0.8920660019, 0.1958157718, 0.3952474594, -0.2617920339, -1.6110399961, -1.3485546112, -1.3979731798, -0.6749272346, + -0.2331542522, -1.0221537352, -1.5719534159, 0.078754425, 1.4476664066, 1.0816694498, 0.5359908342, 0.5086901784, + 1.3539590836, 2.1905260086, -1.3281347752, -1.5861293077, 1.0052930117, 0.2073535621, -0.2195786089, -0.6525210738, + 0.1171994656, 0.2404762059, 1.7054648399, -0.0166308656, -0.9980779886, -0.3845568895, 0.2131299078, 0.8598623276, + -0.232081145, 1.2193504572, -0.7898730636, 0.5503804684, -0.6646599174, -0.4484573305, -1.3752053976, -0.0077703991, + 0.4516531229, 0.5158145428, 1.5019677877, 2.3400790691, -0.1689572185, -0.7131705284, 0.0862102732, -1.8778115511, + -0.5737338662, 0.3488899767, 0.0695413202, 1.4736529589, 0.1018898711, -0.3780619502, -0.3608337045, -0.367949158, + -0.5431326032, -1.0214086771, -0.1403140426, 0.3082767725, 0.1509161294, 0.6119741201, 0.7313207984, 0.8829240799, + 1.8567088842, 0.5742434263, 0.4984557033, -0.418687582, -0.9313029051, -1.6411021948, -0.5562921762, -1.4994580746, + -1.5915665627, -0.0610120445, 1.5467461348, -0.7506592274, -0.4631983638, -0.1926139444, 1.70246315, 1.6659804583, + 0.5192429423, -0.5472186208, 0.0565663762, 0.2284213901, 1.534834981, 0.228663072, 0.039460402, -0.8655991554, + 0.8045617938, 1.2748690844, 0.5713320971, -0.1608036757, 0.7733766437, 2.122333765, -0.974427104, 0.7814424634, + -0.567168951, 0.4748123884, 0.9607690573, -1.0613287687, 1.2581557035, -0.7631398439, -1.7736225128, 0.0356541537, + -0.6820560694, -0.7282853127, -0.1053154469, -0.9815471172, 0.4679682255, 0.1102410853, 1.7661479712, 0.9696770906, + -0.6157441139, 0.0832946599, 0.0154042337, 1.4200258255, 0.191279456, 0.8820790052, -0.756431818, -0.981339097, + 2.7474064827, -0.430970937, -0.536345005, -0.1029144824, 0.4400387704, -1.0086545944, 0.8715492487, -0.4610286951, + 1.2774317265, -0.3406333029, 1.0627976656, -0.0177198425, -1.4871954918, -0.3110130727, -0.1273606718, -0.5646942258, + 0.3632155955, 1.1745493412, -0.550314188, -1.6987376213, 0.526229918, -0.5710070729, -1.2713433504, 0.8851079941, + -0.6829869151, -1.9171721935, 0.7940423489, 0.5627143979, -0.9600135088, -0.2346548587, -2.2996087074, 0.8724299669, + 0.0616741218, 0.4606336057, -1.6986548901, -0.1236542985, -0.8901436925, 1.6886969805, -0.6276292801, -0.7237911224, + 0.559099257, -2.4663658142, -1.0565769672, -0.402284801, 1.6344102621, -0.4803332984, -0.4069189131, 1.0568474531, + -1.2874617577, 1.5985314846, 0.8697004318, 1.518707633, 0.3975264132, -1.4097440243, -0.0381349325, -1.1354163885, + -0.4750063717, -0.2226876616, 0.7452670336, 0.2666867077, 0.1722257733, 0.4386547804, -0.4073028862, -1.2752696276, + -0.3434637189, -0.2251634151, -0.8087444901, -0.7511361837, 0.2216085494, -0.512127459, -1.8204050064, 0.7472478747, + 0.5685710907, 0.1281473041, -0.8394502401, -2.5131106377, -0.9077122808, -0.6943283677, -0.5469990373, 0.7462623715, + -0.3083970845, -0.8384279609, 0.8198192716, 0.4979269207, 0.0270626321, -0.1213922799, 0.7247827053, 0.334816426, + -0.2508352697, 0.7643464804, -0.4294463694, -0.1170479879, 0.0250977706, 0.743625164, -1.5160830021, -1.5851063728, + -1.5032289028, -0.4924083948, 0.6285675168, -1.1842933893, 1.1135993004, 1.2736849785, -0.0435120836, -1.3845635653, + 1.7388744354, 1.7109934092, 0.6870909929, -2.3529503345, 0.5297210217, 0.0182195548, -0.8128156066, -0.1349581033, + 0.5240533352, -1.1022468805, -1.2241221666, -0.2381365448, -1.0415886641, -0.1002316251, -0.400521934, -0.2848261595, + 0.0950556099, 1.7183667421, 1.2604315281, 1.8246142864, -0.2740058899, 1.5894554853, 0.2125496417, -0.8694303632, + 0.3586742282, -0.636924088, -0.3130733967, 0.1877637058, -1.3034642935, -0.5413097143, -0.9775701761, 0.3182064295, + -1.2245349884, 1.3321487904, -0.1348018348, -0.0079483762, 0.5871071815, 1.6216561794, -2.3066439629, -0.3211205304, + 0.0831940025, -1.015597105, 0.3312295079, 1.2365626097, 0.4100286365, 0.4295566678, -0.4415833354, 1.0282262564, + 0.7797985673, -2.6591732502, -1.3471249342, 0.7747009993, 0.7138849497, -0.1456113309, 0.9523909688, 1.2731977701, + -0.9705725312, 0.6225118637, -0.6567438841, 0.1674103588, -0.1905986071, -0.5853870511, 0.9797718525, -0.5967161059, + 0.4017387033, -1.3391740322, -0.7596985698, 0.9018880129, 1.2323490381, 0.6116399169, -1.200480938, 0.7040430307, + 1.9253069162, -0.1669967473, -0.477445662, -0.1453061104, 2.7242598534, 1.0761202574, -0.7772324085, -1.8398270607, + 1.1820985079, 2.2291193008, 0.1210172623, 0.5169967413, -2.0369746685, 1.333483696, 0.9594944715, 1.3979049921, + 0.0152120637, 0.3863286078, 0.0464983992, -0.8423812985, -0.4377827644, 0.6164746284, -0.630710721, -0.4342782497, + 0.2298891991, -2.0079159737, -1.4043928385, 0.1458393335, -0.6708733439, -1.6447790861, 0.0703957826, -0.2523188591, + 0.3924876451, 1.0161181688, 2.0849382877, 0.851662159, 0.9680776596, 0.1318573952, -0.7458209395, 0.1732912064, + -0.0171494074, 1.5169693232, 0.3570988774, 0.9281348586, -1.3707672358, -0.0427510217, 0.5875717402, 0.0559275597, + 1.6824957132, 0.8721467257, -0.81027174, -1.0185278654, -0.8793839812, 1.4426631927, 1.5465738773, -0.8688929677, + -0.1653910875, 0.3350679874, 0.9537213445, -0.9668954015, 1.6751704216, -0.6430878043, 0.3188067973, -0.3906269073, + -1.2710647583, 0.3388320804, -1.1807581186, 0.9608909488, -2.0899810791, 0.7109305263, -0.920455575, -0.9144626856, + -0.6868638396, -0.1635092348, -1.7601587772, 0.1764658093, 0.1667043418, -1.5872178078, -0.0366247445, 1.0080679655, + 0.4422006309, -2.4767754078, -0.9045382738, -0.7697851062, -0.1585956812, -0.2367852628, 1.1754802465, -1.1316013336, + 1.7630548477, 0.2800961733, -0.6288664937, -1.2302342653, 0.3262609243, 0.26601547, -0.0530349985, -0.4598177373, + 1.6693603992, -0.1160294041, 0.4715109169, 0.9127645493, 1.6281094551, 0.9660769105, 1.7898586988, 1.6077495813, + -0.9647401571, 1.1253098249, -1.2583026886, 0.8288027048, -0.2743187547, -0.407086879, 1.4383150339, -0.7290006876, + 0.1344997436, -0.1674019545, -0.362839371, -0.4540843666, 0.6296550632, -1.8585166931, -0.111775279, -0.1778820157, + 2.4086344242, 0.1753031015, -0.4950847924, -2.2426016331, -1.4452265501, -0.2448479533, -0.1808102429, -0.2288896441, + 2.1536924839, -1.3813554049, 0.2147695422, -0.019647995, 0.0244122334, -0.8968064189, -0.682864368, -0.1684126258, + -1.0011633635, -0.7751793861, -1.13942945, -0.8886438608, -1.8494819403, 0.1862669736, 0.3815818429, -1.2124689817, + 0.4131552875, 1.200299263, 1.5946217775, -0.5457906127, 0.4128240943, 0.2786887288, 0.2461876273, -1.3450722694, + -1.17765522, -1.2061234713, 0.2029906958, -1.4223995209, 0.5777701735, 1.6634222269, -0.2870059907, 0.2412759215, + 0.3775524497, -0.9314845204, 0.6768042445, -0.4252702296, -0.7470455766, 0.2802719474, -0.5464428067, 0.6813836694, + 0.7286756039, -0.540963769, -0.7058429718, -0.1084262133, 2.0533525944, 1.2147784233, 0.1359319836, 1.0503759384, + 1.0613586903, -0.2144398689, 0.192092225, -1.0345438719, -0.5036805868, 1.615098834, 1.6786446571, -0.4663047791, + 1.0681966543, -1.3721605539, 0.1843423843, -0.5531916618, -0.8321005702, -1.0742633343, 0.3251988888, -0.7832528353, + 0.7555800676, -0.1313978136, -0.0314237624, 0.5373218656, -0.730660677, 0.6202054024, 1.9043105841, -0.487598896, + 0.2367156595, -0.4076660872, 1.0004101992, 0.3512436152, 1.2557044029, -0.5128421783, -0.4611277282, 0.1007170677, + 0.0925083235, -2.1999547482, 0.1508994251, 0.6993888617, 0.7741886973, -1.5526758432, 0.7084724307, 0.1943209916, + -0.4375484288, 0.7226394415, 0.1368113905, 0.0707129464, -0.0306051858, -0.0026378226, -0.1765782833, -0.5268459916, + 1.9544335604, 0.2153434902, -0.570032239, 3.2406566143, -0.1734665334, 0.2326574624, 0.2949871421, -0.850058198, + 0.4187697768, -1.0791419744, 0.8719388843, -1.402349472, 0.4674481452, 0.4940485954, -0.4561758637, -0.2247166485, + 0.7698090076, 1.1066019535, 0.9135959744, 1.8430663347, 0.3033389449, -1.0240417719, -0.5697768927, -0.5450455546, + -0.7129164934, -2.1384212971, -0.4906723499, 1.0716369152, 1.0448619127, 1.197031498, 0.0851596743, -0.7071413994, + 0.4134632349, 0.5083128214, 0.432456553, 0.4515452981, -0.4726723731, -0.4617720246, -0.0498823039, 0.1511984169, + -0.1242134199, 1.7733763456, 0.6548894644, -0.9969044924, -1.0999536514, -0.4729947448, -0.8252610564, -0.324659586, + -0.2494323254, 0.8223640919, 0.5732952356, 1.1071861982, -0.9319651723, 0.3545930386, 1.3546044827, 0.3564473987, + 0.8952826262, -0.0207289252, -1.9850325584, 1.6648896933, 1.0103242397, -0.8624767661, -0.5156413913, -0.598675549, + -0.5133580565, 2.7740614414, -0.0843275264, 0.5370041132, 0.0354410969, -0.4008655846, 1.6665250063, 0.096517466, + -0.5183625817, -0.9195118546, 0.3387037218, 1.1137673855, -1.5738148689, 1.6057540178, 1.3714587688, -2.3321993351, + 0.3463236392, 0.7981258631, 1.7536504269, 0.09424375, -0.3396389484, -1.25408566, 0.7180249095, -1.1979964972, + 0.5125359297, -0.8158826828, 0.1937242448, 0.5850766301, -0.2552036047, -1.0627428293, -0.0171058923, -0.3047343791, + -0.5120671988, 0.6329017282, -1.247612834, 0.6401041746, -0.8136311769, -0.0626717582, -1.4570958614, 0.2782136798, + -0.8262432218, -0.527988553, -0.2686576247, 0.0438584201, 0.6822136641, -1.4326016903, 0.5378295779, -0.7443700433, + 2.060338974, -1.1167420149, 0.3034130335, -1.0690333843, -1.0751850605, 0.0629330426, -1.8225570917, -1.5243411064, + 1.2396709919, 1.9703440666, -0.4888984561, 0.4765799642, -0.3094685376, -0.9791085124, -0.1147989929, -1.6355508566, + 0.4577118158, 0.2286115885, -0.1039451063, 0.7752788663, -0.30306229, -0.0726639628, 0.26776582, -1.6213132143, + -0.4331697822, 0.1601847857, -0.7287859917, 0.3674771488, -0.1830540895, -0.8931375146, 0.4875233173, 0.9322209358, + -0.1905431449, 3.1566889286, 0.3486742377, 1.0539091825, 0.43532902, 0.6332775354, -0.7265618443, -0.7866077423, + 2.5195691586, -0.001707388, -0.6077119708, 1.2275959253, 0.718095243, -1.3357245922, -1.0510390997, -0.7974286675, + -0.4727028608, 1.5297054052, -0.4044028521, -0.7877702117, 1.648281455, 0.8431814909, 0.2029867172, -0.6682254076, + 1.6193115711, -0.5954051614, -0.390640825, 1.9035891294, 0.6554541588, -2.8776378632, 0.2603771389, 0.7601162195, + 0.5754011869, 0.7990735173, 1.1752868891, 0.4685513079, 0.974311173, -0.2307738513, -0.0264357254, 0.411028266, + -0.3004532456, 0.2818160057, -0.5710403919, 1.0028342009, 0.5024909973, 0.4595133066, 1.4817398787, 0.2799629867, + 0.5637354851, -0.6241150498, 0.8133111, -0.0602380522, 1.1828916073, -0.1272625327, -0.8460607529, 0.3959697485, + 1.4310905933, -1.0955809355, -0.2613841593, -0.1580035388, 0.365786016, 1.2321866751, -0.650336802, 0.0420608893, + -0.8093909621, 0.5546837449, 0.2265381217, 0.3556352556, 0.765699029, -0.324947834, -0.1872305423, -0.8028757572, + 1.8795111179, 1.195274353, 0.8303111196, -0.1781547517, 0.5080417991, -0.1168814152, 1.18128407, 1.0313570499, + -1.719655633, 0.2446504086, 0.1371421814, 0.0973915532, -0.4585001469, -0.8280373812, -0.4593352675, -0.6757261753, + -0.0793135092, -0.418040961, 1.2445529699, 0.2011100203, 0.9248659015, -0.42109707, -0.8320764899, -0.1646859646, + -2.5782234669, 1.1942738295, 1.5204107761, 1.2211294174, 0.7107045054, -0.1187882051, -0.8583485484, -1.0267019272, + 0.583016336, -0.1584341824, 0.6857743859, -1.6815145016, 0.2011470497, 0.177524969, 0.497938782, 0.83720541, + 0.5836708546, -0.1584636122, 0.2616901696, 0.5922822356, 1.0962525606, -0.224693656, 0.3583438396, 0.5079059005, + 2.4989459515, 0.7612602115, -0.6034088135, -0.6274229288, -0.0049325931, 0.4828433096, -0.1417066455, 0.5503855348, + 0.9566833377, -0.4469841719, -1.8436908722, 0.0132681746, 0.6910766363, -0.984488368, 0.6257191896, -0.0121382996, + 0.9449425936, 0.4866577685, -0.1009661183, -0.1784197092, 0.7964317203, 0.1096719578, -1.0981303453, 0.1085784137, + -0.2215659022, 0.6406838894, -0.7363584042, -0.1355459243, 0.1792862862, -1.5051630735, -3.0252084732, 2.3134453297, + -0.1067946255, -0.2164448351, 0.5656723976, 0.1987833977, -0.4938872755, 0.3542607427, 0.7917511463, 2.0004119873, + 0.1138286367, 1.0661466122, -1.2925044298, 0.0914441869, 0.6103685498, -0.9954180121, -0.4100271165, -0.4298735261, + 1.2885445356, -1.738765955, -0.5108031631, 0.1936938167, -0.297200799, -0.5979477763, 1.5313448906, 0.021962706, + -0.7502336502, 3.1279857159, -2.1839592457, 1.044080019, -0.6610156298, -1.2552039623, 0.4473415315, -0.9450294375, + -0.2153885067, 1.1292688847, 1.4167747498, 0.0083199078, -0.7387729883, -1.5310351849, -1.2331342697, -0.040593382, + -0.4422261715, -1.0382130146, 1.3626192808, 1.1903202534, -0.1882884353, -1.8005816936, 1.5561032295, 3.1526033878, + 0.4462724328, -0.5650293827, 0.2617058754, -1.4923347235, 0.1959274411, 1.6606786251, 2.1215653419, 0.4635251164, + -1.6947836876, 0.5675776005, -0.0769856125, 0.8061911464, -0.7121078372, 0.3398130536, 0.2747018933, -0.9738521576, + -1.0838885307, 1.6086019278, -0.1070212498, -2.4784710407, 1.256737709, -0.9551062584, 0.8460628986, -1.0296751261, + -0.36309883, 0.4910036623, 1.3033028841, 0.6093656421, -1.5684084892, 0.2002652586, 1.8276238441, 0.1794807613, + 0.7145086527, 0.4715159535, -1.3110510111, 0.3708418012, 0.5671648383, -0.1211298183, -1.9422543049, 2.7631845474, + -0.0019290138, -0.9331898093, 0.2469065487, 0.9991958737, 0.1478086561, 0.5288000107, -0.2993927896, 0.6493500471, + -0.5947993398, 0.0689935088, 0.3103188276, -0.5490578413, 0.5102764964, 1.004576683, 0.463475287, 0.3118042052, + -0.1784106791, -1.2324748039, -0.271527946, 1.3155361414, 0.6285444498, -0.7697691917, 0.38147071, -0.7372010946, + 1.6317893267, 0.0496188216, 1.8298569918, 0.2486533225, 0.2665860057, -0.5764042139, -0.1545846164, 0.5823374987, + -1.2349112034, 0.9288624525, 0.2240541875, -0.8932236433, 0.6563537121, -1.9804890156, 0.2280142903, -0.9330589771, + 0.8488634229, -0.0275313407, 0.7628030181, -0.5166394114, -0.0639637858, 0.5297335982, 0.0976115614, -1.2929050922, + -0.247390449, 0.0017580237, -0.0445541181, -1.2251801491, -0.9520522356, 0.3250408471, -0.9763738513, -0.3191157579, + 0.06396465, 0.3773847818, -1.7942626476, -0.3388437927, -0.7155359983, -0.9516233802, -0.8122008443, -1.0962382555, + 0.8137555122, -1.6893570423, -0.739246726, -1.0180219412, 0.3281373978, 0.8430277109, 0.6054344177, 0.9184139967, + -0.4063994288, 0.0855568647, -0.1104435921, -0.7943481803, 0.2338262349, 1.0993648767, -1.3479268551, 0.3901562393, + -0.3676171601, -0.5882406831, -1.7047501802, 0.0156326983, 0.3451995254, 0.1704274416, -0.5342517495, 0.1036691368, + 1.9168593884, -1.0093951225, -0.2074879557, -0.1844485551, -1.133918047, -0.7229844928, 0.3331287503, 0.3014786243, + 1.4839015007, -0.2690161169, 1.0232335329, 0.7889760733, -0.4552712739, 0.3501521647, -0.2285785526, 0.9389357567, + 0.0447394811, 0.1851441115, -1.235575676, 1.2031196356, 0.0116550243, 0.9264087677, 0.3385564387, -0.5845701694, + -0.6950528026, 1.0220985413, -0.731156528, -0.9815580845, 0.8116582036, -2.7727127075, 0.1836193055, -0.8430696726, + -0.9484882355, 0.3477781117, -1.2728915215, -0.9775258899, 2.0550086498, -1.1804845333, -1.6777393818, -0.2583949864, + 1.9016064405, -0.2666935325, -1.0596487522, 1.1103088856, -0.5217511654, -0.1671878248, -1.3836013079, 0.5602372289, + -0.7295765281, -0.0698853359, -0.5959703326, -0.6792480946, -1.0985150337, 0.495734483, 1.3550078869, -0.3935103118, + 1.1229667664, 0.8153097034, -0.6519557238, -0.430331856, -2.8154788017, -0.3087665737, 0.7753482461, 0.6616540551, + 1.1300858259, 0.6900553107, -1.8309692144, -1.0626448393, -0.7698283195, -0.8680559993, -0.7421313524, 1.8048762083, + -0.0947011113, 0.493558228, -0.139230296, 0.1740383208, 0.1270922571, -1.5548484325, -0.0411530435, -0.6951826811, + 0.3269871473, -1.4882113934, -0.3722811639, -0.3547021151, 0.1275018305, -0.4833881557, -1.8390951157, 0.1966317892, + 0.5947086215, -0.0949502289, 0.23178038, -0.9899123907, -1.4969880581, 1.9577594995, -1.1843186617, 1.5552152395, + 0.5649688244, -1.7155886889, -0.6562070251, -0.8054563999, -1.6628246307, 0.7222976089, 1.0663632154, -0.109490186, + -1.5984297991, -0.5933257937, -0.0686090812, 1.25844419, -0.3986067474, -0.4922445416, 0.2149075568, 1.6925339699, + 0.4467121065, 0.0721166655, -0.1689761132, -0.4769457579, 0.1210901141, -0.1196763217, -0.3491147757, -0.6679611206, + -1.1081523895, 0.8642325997, -0.3652341068, -1.4192044735, 0.5283550024, -0.4291144013, -3.9799249172, 2.5193560123, + -0.0001015828, -0.3741996288, 1.1290762424, 1.6821254492, 1.0898627043, 0.0934686586, 0.3777738214, -0.5232481956, + -0.5119860172, 0.83927387, -1.3982032537, -0.5136648417, 0.2465056181, 1.1420283318, -0.4828293025, 1.1170063019, + 0.215386942, -1.043369174, 0.7852531672, -0.3490794599, -0.5112475753, 1.0232989788, -0.0248605367, 0.6658914089, + -0.0275805313, -0.3348940313, 1.8200131655, -1.0081651211, -0.2610522807, 1.3033430576, -0.4144646525, -0.0354455411, + 0.8998509049, 0.5341755748, -0.4204404354, 0.2261348367, 0.2233097106, -1.1665488482, -0.5937159657, -1.4060828686, + 0.4686772823, 0.0984703451, -0.7751576304, 0.3141351938, 0.8974028826, -0.1393257678, 0.7376810908, -0.3796384633, + 0.7480918169, 0.2854343355, 0.4962151349, 0.0067210966, 1.3005772829, 1.0714277029, 0.6444802284, -0.5154283047, + 0.0870009586, 1.0096105337, -1.8330725431, 0.1132716388, -0.0708507001, 0.1738734245, -1.0237518549, 0.2748146057, + -0.2124217898, -0.1312001646, -0.7777321935, -0.8523564339, -0.553260088, -0.4056203365, 2.1330664158, 0.2694247961, + 0.0929921642, -1.1530809402, 0.5591195822, 0.189225018, 0.647649169, 0.0823355317, 0.4193497598, -0.6377058029, + 0.2406051308, -0.6672044992, 2.6748664379, -0.5676947236, -0.3393431604, -0.5449929833, 0.2807078958, 0.9032731056, + -0.6467321515, 0.8295060992, -1.8630459309, 0.4991222322, 0.4042034745, -0.088323608, -0.0470565073, 0.9142104983, + 1.0030266047, 0.2447029352, 0.6141192913, -0.8892118335, -0.7647240758, -1.1047742367, -0.8095286489, -2.0631930828, + 0.2100882679, 0.2161284685, 0.1404330134, -1.7657244205, 0.2368792892, -0.1763023734, -0.4331485033, 0.1648295075, + 1.7212885618, -1.1766096354, 0.1771905273, 0.0255289283, 0.0521093681, 0.2013487816, 0.8420627713, 0.991532445, + 1.5613195896, 0.6682843566, -1.4083592892, -1.2373524904, -1.365790844, 0.5665727258, 0.1114991754, 0.5536442399, + 1.0835049152, -0.0504580699, 0.2503991425, 1.9299334288, -1.5645395517, 0.4178295732, 0.1182594225, -0.2803184986, + -0.041264832, 0.1382355541, 0.7969234586, -0.1608946025, -1.3431527615, 0.2850189209, 0.2608601153, 1.9069812298, + -0.3040925264, -1.0234804153, 0.8924683332, 0.9798862338, 0.7105198503, -0.5560311675, -1.9237110615, -1.5857894421, + -0.0867523253, 0.7510196567, -1.6821100712, 1.7742727995, -1.1292693615, 1.2592233419, -0.5400198102, 0.4569769502, + -0.1657794416, 0.5541830659, 1.0131599903, 1.1774101257, 0.3166932166, 1.1890761852, 0.444001317, 1.7804197073, + -0.823045373, 0.0510413684, -0.8502710462, 0.2226673365, -0.8931104541, 0.7461739779, 0.5200843215, 2.4808294773, + -0.4306486249, 0.7000415325, -0.6627852321, -0.666603446, 0.6417964697, -1.3115973473, -0.4170653224, -0.0155315036, + 0.2604958713, -1.9038473368, 0.8179932237, -0.8048866987, 0.1132161394, 0.6200553179, 0.8735640645, -0.8754689097, + -2.9979059696, 1.8664747477, 0.2899555564, -0.3376359046, 1.4218786955, 0.0991161391, 1.554120779, -0.0542410761, + 1.2513942719, -1.3293449879, -1.5720999241, 0.2153496891, 0.4149667025, -0.3295794129, -0.2767211795, -0.0946821421, + 1.7693696022, 0.0545876808, -0.6418469548, 1.1964954138, 0.4129462242, 0.302703023, 2.1559007168, -0.6829319596, + -0.3651222289, -0.0442247801, 2.2708928585, -0.782386601, 0.4403840601, 0.1520252228, -1.2476013899, 0.5838144422, + -0.570078969, 0.0327484533, -0.8868691325, 2.3026103973, -0.3992435634, 0.4614451826, -1.6609683037, -2.1689975262, + -0.7229250073, 2.8979327679, 0.7089292407, -2.3434951305, 0.1656176299, 0.5335359573, 0.0808340311, 0.3161955476, + -1.3906550407, -0.6597616076, -0.3027254045, -0.3078902364, -0.3183090985, 0.2484171093, -1.8363064528, 0.1134862378, + 0.9222687483, 1.4002178907, -0.658896029, -0.506934762, -0.1029141247, 0.0792785361, 0.8484690189, 0.5411299467, + -0.2156495005, -1.4614349604, -0.0294835921, -0.0679289103, 1.7664188147, -0.3468401432, -0.9617422819, -1.04352355, + 1.4455068111, 0.4401999414, 0.02004195, 0.0252560489, 1.3682826757, -0.768327415, -0.8309261799, -1.9147306681, + 0.1773295254, -0.1637866497, 0.8641271591, -1.4150470495, 1.357070446, -1.2145545483, 0.1236755922, -0.0837656856, + -2.5834338665, 0.3076185882, 0.2000334412, -0.2788176537, -1.8437790871, -0.7380565405, 0.6632315516, 2.2895617485, + 0.6810886264, -0.4265203774, 1.3332300186, 0.9933365583, 1.0180410147, -2.1297695637, 2.29859519, -1.2535015345, + -0.7859506607, 0.311594516, -1.4633288383, -0.2197153121, 0.1873781085, -1.5290776491, -2.2650036812, 0.4986795783, + -0.4243268967, -0.4248904884, 1.2769355774, -0.3564965427, 1.3732653856, -1.4011700153, -1.5260056257, 0.6965202093, + 0.1845299453, -0.7892647982, -0.1872230172, 0.4882991016, 0.1650603563, -1.611395359, 0.2592717409, -0.1188143864, + 1.222895503, -0.8016638756, 0.6876689196, 0.7840186357, -1.5337510109, -1.1500921249, 1.2201095819, 0.580693543, + -0.8960040808, 0.8627079129, -1.1348323822, -0.9670757055, 0.3248357773, -0.4929454625, 0.136924088, -0.5122059584, + -1.0240994692, 0.8177993298, -1.5714014769, -0.9127979279, 0.3507647216, 0.5462158918, 0.01550256, 0.2486607134, + 0.437333554, -0.0667797402, 0.3301390707, 0.5512520075, -0.0004508996, 0.2623131573, 0.8791959882, -1.3433330059, + 0.034119159, -0.1302566528, -0.6102820635, -1.9780943394, 1.0417385101, -0.1486586779, 1.3084896803, -0.1083629355, + 0.2558193207, 0.6630388498, -0.7649769783, 0.0660102144, 0.6541601419, 0.1619965583, -0.234366104, 1.1309125423, + 0.9972749352, 0.3769946396, 0.9053672552, 0.0170451328, -0.2916249335, -0.0637479946, -0.8857896924, 1.0207086802, + -1.3605722189, 1.5603965521, 0.4978734851, -0.0114495857, 0.2822905183, -0.0966921449, 0.4231345654, -1.5016077757, + 0.5884187222, -0.8756873012, 0.5964536071, 1.5745950937, 1.0954363346, -0.8237411976, -0.2152891606, -0.2709789574, + -0.2081480324, 2.2277188301, 0.3763382137, 1.2043631077, 1.1044359207, -1.3858469725, 1.2034906149, 0.0602937639, + 1.5043460131, -0.4531169236, -1.3994597197, 0.9959958196, 1.4748657942, -0.6896502376, 0.5163658857, -2.1955311298, + -0.7591708302, -2.2448000908, 0.4303465486, -1.854395628, 1.4948334694, -0.3116846383, 0.4466024935, -0.0118529536, + 0.7244918942, -1.6666995287, 0.0236608721, -0.4630951583, -0.548410058, -1.1173944473, 0.4898535311, 1.6996483803, + -1.8060977459, -0.449734211, 0.4933337867, 0.0872113928, 1.6383810043, 0.2239727825, -1.2708234787, 0.3466352224, + -0.4335897863, -2.5197424889, 0.7378028631, -0.8447279334, -0.0559481047, 0.6839315891, -1.1025488377, 0.2024087608, + 2.9150803089, -0.3840768039, -0.0326391011, -0.0803115442, -0.8246007562, 0.3065483272, 0.0389659554, 0.8100610971, + -0.3687470257, 1.0887268782, 0.0036491603, -1.039409399, -1.0970540047, -0.7277394533, 0.268588841, 0.7355921268, + 0.9661358595, 0.5190473795, 0.05088301, 1.2438833714, -2.2499885559, 0.8982744217, -1.295492053, 0.8556146026, + -0.4744929671, -0.6942690611, -0.1644901037, -0.2620332837, -0.1451232731, 0.0785102472, 1.001665473, -0.2739449739, + 0.8009263277, -0.1702002585, -0.8886307478, -0.1733903736, -1.1252379417, -0.4982013106, -0.5461481214, -0.7811477184, + 0.1073800698, -0.7631527781, -1.3092365265, -0.1617819816, -0.0008865069, 0.571388483, -0.113634795, 0.1617997438, + 0.1273338348, -0.749863863, 0.8821802735, -0.0337238349, 1.3859173059, 0.5330554247, 0.1874614954, 1.6891919374, + 2.025167942, -0.4745604992, 0.0918694958, 0.1943952888, 0.6713520288, -2.0351748466, 2.6817276478, -0.1689636558, + -1.2043520212, -0.8034988046, -0.625087738, 1.4457765818, -1.4667338133, -0.8495544195, -0.3539527953, -1.0773371458, + -2.4111745358, 0.5679433942, -0.208184287, 0.9879924655, 1.2360608578, 0.7949596047, 0.4199788272, -0.69409132, + -0.883248806, 0.5228080153, -0.2757284045, 0.2805615962, -0.4129777253, -1.1507169008, 1.8317346573, 0.1299459189, + -1.3232452869, -0.2197397053, 1.6015273333, -0.7579594851, 0.5799200535, 1.2151949406, -0.2547016442, 0.1068254113, + 0.051626496, 1.16711092, 1.3634036779, 0.0900574327, -1.0950243473, 0.8401091695, 0.6654623151, -0.3086810708, + -0.7375400066, -1.0307489634, 0.1048286334, -1.5460332632, 1.8186627626, 0.8098951578, 0.9708928466, 0.710255444, + 0.9713087678, 0.3875834644, -1.1385778189, 0.540179193, 0.4986961782, 0.2263549715, -0.2634185255, -1.5598323345, + 0.3776816428, -1.7435592413, -0.6064981818, -1.0359470844, 0.704369247, -0.508058846, -1.9649239779, 1.1656636, + -0.8278691173, -0.3729766309, -1.5564032793, -0.8267266154, -1.193400979, 0.666959703, -1.0290228128, 1.0644114017, + 2.3462307453, -0.2566364408, 1.2686136961, 0.2236939818, -1.1905844212, -0.8348674774, 1.0824284554, -0.8072878718, + -2.0340442657, -0.1297576725, 0.1229395643, 0.4321765304, -2.756841898, -0.5900364518, -0.2194618881, 0.9851743579, + 0.5149931312, 0.7409499884, 0.9859756827, -0.7990174294, -0.9565790892, -0.6254098415, -0.5258603692, -1.1526063681, + 0.5984534025, 1.7542530298, 0.5825209618, -0.0108615747, 1.1506799459, 1.6939212084, 0.6322537065, -1.0341697931, + -1.4992163181, -0.9192206264, 0.2501222789, -1.6166472435, -0.3118333817, -1.5592268705, 1.236344099, -0.2899449468, + 0.2497586608, 0.8226853609, 0.0091154482, 0.5934258699, -1.0807846785, 0.6175705194, -0.2989517748, 0.0668154061, + -0.3421589136, -1.2376976013, 0.2341058552, -0.2281744033, 0.9363278747, 0.7818625569, -0.5937199593, -0.2155658305, + -0.2269501239, 0.0548860207, 1.2610039711, -1.1864619255, 0.2939851582, -0.1575176418, 0.3959463537, -0.5379269719, + 0.0852746218, -0.1205217764, 1.1457941532, -0.6422573924, 0.6109707355, -2.3347873688, 0.8817616105, -0.4318682849, + -0.2186090648, 2.3368148804, -0.8696759343, -1.3311178684, -1.494035244, -0.1126572788, -0.1654232144, 0.6756837964, + 1.0262820721, -1.5286720991, -1.7455735207, -0.0086124055, -1.3048062325, 0.7480476499, -0.1624615192, 0.8573369384, + -0.2427486479, 1.5718251467, -0.4005960226, 0.1661429852, -0.3388045132, -0.8788685203, 1.1277475357, -1.8028851748, + -0.9683129191, -0.2205161005, -0.3632950187, 0.9993163347, -1.1250728369, 0.2273952663, -1.6806476116, -0.5850839615, + 0.4633552432, 0.5404006243, -1.1591656208, -0.4043771923, -0.5775872469, -0.4467805326, -1.3486293554, 0.1647246778, + 0.53559798, 0.6689383984, 1.69871068, 1.0737128258, 1.5600349903, 0.5412341952, -0.2705770433, -0.5515835881, + 0.4355035424, -0.132042706, -1.2384092808, -0.3141611516, 1.3099900484, 0.6195878386, -0.0317559093, 0.4572177231, + -1.0924277306, 1.0926088095, -0.3314957321, 1.8907419443, -0.494348228, -0.0626017973, -0.0550512932, -0.0231284834, + 0.7892349958, 0.3658465743, 0.4307425022, 0.1753020287, 0.4385994077, 0.9858914018, -0.7419704795, 1.7252422571, + -1.0884103775, 0.9333866835, -0.4368148446, -0.6445410848, -0.7094064951, 0.5206435919, -1.9676936865, -2.0886249542, + -0.0491473936, 1.7515029907, -1.2138712406, -1.0226154327, -0.5423930287, 0.703881681, -0.8431472182, 0.7065833211, + 0.2752345502, 0.0155479768, 0.4675925374, 0.9834657311, 1.3818086386, -0.0449825265, -0.8379833102, 0.6575056911, + -0.941708684, -0.9865073562, -0.8108641505, 0.489517957, -0.2885791063, 0.6517304778, -0.0437750444, 0.9180089235, + 1.0069895983, 0.5761268735, 0.4679514468, 0.0979376882, -0.6210292578, 0.2446375191, -0.2866552174, -0.4697014689, + -0.6670892835, -0.2212103456, 0.1083477437, -1.3208975792, 0.251388669, -0.6949612498, 1.3961971998, 1.0441313982, + -0.8038179278, -0.6545550227, 1.0894525051, -0.8547613025, 0.4289109409, -0.9605471492, -1.311611414, -1.4649935961, + 2.2020881176, -0.7328217626, 0.246998772, -1.4316263199, 1.009419322, -0.5877754092, -1.2018294334, -0.4497393668, + -2.0317924023, -1.3781358004, 0.2250173539, -0.2393929213, 1.0711579323, 1.0380489826, -1.651154995, -0.3789921403, + 0.9080212116, 0.86968714, -1.6957534552, 0.3965432644, 0.0837741494, 0.001089211, -2.4933798313, 2.0837154388, + -0.2696723044, 0.7178445458, -1.4326989651, -1.0441292524, 0.9024427533, -0.2075345218, -1.0056159496, 0.8656446338, + 0.0663467273, -1.0112538338, 0.4815161228, 0.6747781038, 1.7164748907, 0.0540352389, 0.0186312608, 0.6076316833, + 0.5149070024, -0.6382617354, -0.2592832446, -0.1123041362, -2.329795599, -1.2326625586, 0.1074425578, -0.0259655807, + -0.4965038002, 0.4682292342, -0.7256876826, 2.5770611763, -0.5546184778, -0.7165570259, -0.598890245, 1.380533576, + -0.9438036084, 1.8827584982, 2.2911372185, -0.3109315038, -0.4171719849, -0.9282898903, -1.2628384829, -0.8774039149, + -0.1966391057, 0.1648458242, -0.045474939, -0.4523634613, -0.8597000837, -1.810516119, -0.5551453233, -0.4640676081, + 0.0456892885, 0.9407829046, -0.470086664, -0.4446507394, -0.941079855, 0.1821057349, -0.8256917, -0.5830290914, + 1.5628407001, -0.1577423513, 0.3348858356, -1.0220993757, 1.516420722, -0.4169793427, 0.0705198646, -0.968467176, + -0.7755367756, 0.8577855229, 0.7357011437, 0.8049449325, -0.5722336173, 2.4884157181, -1.0409582853, -0.5645226836, + -0.8657156825, 0.8756935, -0.0816876218, 1.616999507, -0.4836786091, -0.5187353492, -0.1280231029, 0.3786218464, + -1.0286502838, 0.9747040272, -0.4097430408, -0.04146621, 0.1704852134, 1.2174123526, -0.4135402739, -0.9620710015, + -0.6299701929, 0.7686001062, 1.6596417427, 0.116593048, 1.5519549847, -0.0122310994, 0.6999790072, -0.3696699142, + -0.6388676167, -0.3132658899, -0.3769345582, 0.4913886487, 0.9003452063, -0.6527366638, -0.9828684926, 0.0031222911, + 0.3023118973, 1.1393951178, 0.0686765835, 0.8947140574, 0.1511452794, 1.2494877577, 0.2830680609, 1.0252991915, + -2.0512757301, 1.0091516972, 0.8578301668, -0.431232363, -0.0823090598, -0.6327573657, -0.6221244335, 0.1637613624, + -0.4898373783, -1.0175414085, -0.1421252489, 0.7623457909, 0.6941013932, 0.8787897229, 1.0183321238, -1.3048707247, + 0.6710067391, -0.508153379, 0.7300412655, -1.0180243254, -0.6606916189, 1.65112257, -0.380915612, -0.8625769019, + 0.1733328998, -0.308006227, -0.4351976812, 0.6185950637, 0.1875175387, 0.2302682847, 1.6791144609, 0.6098973155, + -1.7957258224, -1.9296709299, 0.4632092416, 0.9872512817, -0.2040626854, -1.672678113, -0.7090438008, 0.145801723, + -1.1318336725, -0.2968883812, -2.6211783886, 0.1238219291, -0.3862033188, 0.1050975546, 0.409653753, 0.3024674058, + -0.8510958552, 0.7929092646, -0.2956811488, -0.1781456769, -0.4592222571, 0.6618961692, 0.7615174055, -0.330753237, + 0.0029948372, 1.0480338335, -0.973081708, -0.7652286887, 0.1419316083, 0.9494506717, -0.656883955, -1.5343198776, + 0.7911569476, -0.0277832802, -0.0588698722, -0.9085233808, 0.0808649138, -0.0074584479, 0.2145736217, -0.0665548891, + -0.332331568, 0.0640165284, -0.9991938472, 1.883318305, -1.0895928144, 0.8137967587, -0.4096502066, -0.293963939, + -1.3181260824, -0.7032576203, -0.8461838961, -0.0827098563, -1.9362289906, -0.3094807267, 0.0122073861, -0.4892766178, + 0.832687974, 0.8380709887, -0.5376721621, -1.5581637621, 0.4174664915, -1.3119213581, -1.4869244099, 0.8268741965, + -0.0097436709, -0.6998175979, -0.6954088807, -0.2588140666, 1.1530423164, -0.8297799826, 1.8891391754, -0.769659698, + 0.0943683162, -0.0774358884, 0.7215057015, -0.5595492125, 1.366130352, 0.7425178885, -0.0379569791, -0.5930621624, + 0.3185641766, 1.4783425331, -1.1458002329, -0.9837580323, 1.0978168249, 0.8367465734, 0.6999016404, 0.6078990102, + 0.6545804143, -0.9899599552, 0.6728334427, -1.1816710234, -0.8178920746, 1.1061612368, 0.3675162494, -0.5634465814, + -0.2326633036, -0.6539015174, 0.4468860626, -0.9113517404, -0.3453916311, 0.1714687198, 0.254717648, -0.226146698, + -1.6652747393, 1.0987795591, 0.7416546345, -0.5794039369, 1.2014195919, -0.4735201597, 0.7171515822, -0.3532316089, + 0.51273489, 2.0128924847, 0.9054009914, 0.0433341525, -0.2319250405, 1.2205764055, 0.7686790824, 1.440500021, + -0.3859676123, 0.6124944091, -0.7336784005, -1.2352366447, 0.7807996273, -2.3257813454, -0.3928811252, -0.2172492445, + 0.6651454568, 1.7893996239, -0.3957181275, 1.1372895241, 0.7369244099, -0.8327875733, 0.6632367373, -0.0397752263, + 1.4086065292, 0.4437205195, 1.4935532808, 0.0716269463, -1.0937371254, 0.4778392613, -0.4515686929, -1.5649410486, + -0.0638999194, -0.4206497371, -0.5077050924, 1.3147307634, 0.2272905707, 0.0551176965, 0.3449913859, -0.6504779458, + -0.0079302043, -0.6291233301, 1.4332242012, 1.2907489538, 0.3631163239, 0.5036269426, 0.5870404243, -1.583833456, + 1.8516979218, -0.1510378718, 0.0084957005, 1.7752424479, 0.3407488465, -1.7290748358, -0.1309578121, 0.1811762899, + 0.9766051173, 0.8586809039, -1.4115585089, -0.5120242238, -0.9084070921, -0.6975479126, 0.2765782475, 0.560316503, + 0.8318665028, 0.1136660054, -1.2513357401, 0.3720861077, 0.6408976912, 1.5998200178, 1.043672204, -0.3570035696, + -1.7902721167, 0.0918675587, -0.1112808436, 0.3380652964, 0.3301384747, -0.6644927263, 0.6445029974, -0.6061426997, + 1.9779821634, 0.1567000747, 0.1088435352, -0.830041647, 0.1776271611, -0.3211027384, -1.1594855785, -0.4041348696, + 1.4324586391, 0.2450418323, 1.3597365618, -0.2198139727, 0.7452784181, 0.5204197764, -0.1552402973, -0.0877770483, + 0.6449214816, -2.0652017593, -0.4502398968, 1.5628504753, -0.2074006945, 0.5728432536, 0.5312701464, -0.5582386255, + 0.4903011024, 0.4000514448, -0.3402361572, 0.1078620851, 0.1054711565, 0.076260142, -0.8976479173, -2.7556171417, + 0.6805824637, -0.8755759597, 0.5861801505, 1.0099159479, -2.0829658508, 0.8546541333, 0.4041488171, 1.4322775602, + 1.9776724577, 2.1114580631, 0.2207719088, 1.9176034927, 0.924467504, 1.6649698019, 0.2163754702, 0.0035872904, + 2.6416580677, -1.4437009096, 0.4020408988, -1.1299657822, 2.0063018799, 0.3601942062, 0.0552108772, -1.6590025425, + -0.6537028551, 0.6874204278, 1.6122521162, 0.2168688625, 0.9429037571, 0.5354552865, -0.963131547, 0.9434006214, + 1.5907050371, 0.2731074691, 0.9513245225, -0.2791555226, 1.1296684742, 0.7820475101, 0.1685398072, -1.9420115948, + -0.9730284214, 1.1653062105, -1.4316834211, -1.3316079378, -0.0116488738, -0.1106063351, -0.3327346146, -0.1284098923, + -0.4964047372, -0.3758531809, 0.4843265712, 1.5204824209, 1.113978982, -0.3578812182, 1.8609610796, 0.994836092, + -1.3479914665, 0.8106604218, -1.0499941111, -0.6323813796, -1.4502238035, -0.7411080599, -1.1738317013, 1.0985153913, + -1.7316554785, 0.5024092197, 0.6399983764, 1.8322696686, 0.2193556577, -0.2059195042, 1.5266751051, 0.8948894143, + 1.691824913, 0.5572015643, -1.3783254623, 1.2419376373, -0.1381992251, -0.3036934733, -0.4471315444, 1.3595137596, + 0.5195784569, 1.0076969862, -1.0152332783, 0.4372532666, -2.2233533859, 0.3535255194, 1.5505034924, -0.5713678002, + 0.0189786758, 1.5610871315, 0.6443794966, 0.3136890829, 2.5183229446, -0.1112032235, 0.4580637813, 0.4732072651, + -0.6347094178, -0.1455913633, -0.3562349081, -0.0463523492, -0.2493555695, 0.7978110313, 1.3423910141, 0.212078765, + -0.9567505717, 1.3303672075, -0.3680039048, 0.7403077483, -0.2130557746, -1.3168724775, 0.9083569646, -0.4936971068, + 1.0476306677, 0.5149489641, 0.5401264429, -0.3668811321, 0.5347924232, 0.4814083576, -1.0775488615, 0.93662709, + -0.320205301, -0.3182254136, -1.4235715866, 2.0460758209, -0.6138587594, 1.4505295753, -0.0747881457, -0.8538289666, + 0.0534842983, -0.2949616313, 0.3182134926, 2.0032804012, 0.2364036888, 0.994700253, -0.5805375576, 1.5063704252, + -0.9826948047, -1.603932023, -0.7312178016, 0.2631585598, 0.0081778783, -0.2120543271, 1.4288504124, 0.0310508497, + -0.4847147167, -0.3707052171, -0.1414912492, -0.1123282909, 0.5229693055, -2.4375815392, -1.912406683, 0.1451980472, + -2.0455174446, -0.4165692627, 1.6499553919, 0.0982848108, 0.9086429477, 1.1524801254, 1.1450995207, -0.8715981841, + 0.2962348163, -0.086425133, -0.7070257068, -0.0059363027, -0.0952185914, 0.9882470965, -0.2431317419, 1.0272905827, + -2.287706852, -0.0339677818, 0.2500078678, -1.6668512821, 0.3891637921, 0.5523136258, -1.7448424101, 0.6041775346, + 1.7510638237, -0.5160238147, 0.7353807092, -1.2460041046, 0.0510762073, -0.1354765445, -0.8791379929, -1.5496599674, + 0.1134271175, -0.2463372648, -0.0203294978, 1.5303599834, -1.0988429785, 0.3622785807, -0.7890076041, 1.4901959896, + -0.2522631288, 0.6070600748, 1.0430524349, -0.1125693843, -0.4349509776, 0.7843998075, 0.6623550057, 0.0715067312, + -0.2036272436, 0.0255890638, 1.2453645468, 0.1566366106, -0.4086671472, 0.8515979648, 0.4264606535, 0.0430518128, + 0.1734429896, -1.9741030931, 0.6002647281, -1.0860610008, -0.4001491666, 0.4027245641, -0.4328278005, -0.6476949453, + -0.0458221361, 0.4308312535, 0.818890512, 2.176787138, 0.5373866558, -0.9187107086, 1.3414472342, -0.8143109679, + -0.4182454348, -0.9356334209, 1.1228146553, 1.3687461615, -1.2463581562, 0.5486357808, 0.3156320751, 2.7218301296, + 0.4282638729, -1.6033006907, -0.2760243118, 1.5372369289, 0.340744704, 0.8939761519, 0.2236253321, -1.2835608721, + 0.5933554173, -0.8735864162, -0.1540386975, 1.7338123322, -0.2981918752, 0.692796886, -0.5642343163, -1.1485286951, + 0.7087337375, 0.7157472372, 0.1084082723, -1.2599521875, -0.1718678474, -0.1303246766, -1.6611258984, -0.1089953035, + -0.8575206399, 1.2285900116, -0.5913127661, -0.8356810808, -0.8497319818, 1.6891064644, 0.9818716645, -0.7118170857, + -0.0595040582, 1.1489208937, -0.1327075511, -0.7262676358, -0.6392194629, -2.7723453045, -1.0678972006, 1.4211807251, + -0.5049116611, 1.0029976368, -1.7353630066, -0.0004422014, 1.3126903772, 2.6282687187, -0.88568753, 1.2361621857, + 1.1301437616, -0.7847929597, -1.4580696821, -1.972286582, -0.357045114, 1.5762296915, 0.6130509377, -0.8741570711, + 1.8246018887, -0.4657349586, -1.2615884542, -0.4083859324, 0.329487443, 1.1362862587, 1.5787801743, -1.5691125393, + 1.1296247244, -0.8173444867, 0.0448391438, -0.2004632354, -0.1206745356, 2.1760234833, 1.4095352888, 1.714232564, + 0.1296830177, -0.0240912717, 0.1981743574, -0.5931743383, -0.6481423378, 0.2112238854, 0.0259035602, -0.771433115, + 0.4130635262, 0.4231062829, -0.1897049546, -0.247340858, -0.5636284947, -1.4844306707, -0.5463525057, 1.6333186626, + -0.4062886238, 0.671882093, -0.1990920752, -0.0755890235, -2.4272682667, -1.0069460869, 0.2937736213, -1.8922125101, + 0.038795162, 3.0649490356, -0.2021356225, -1.7997900248, 0.1907552779, 0.2254720032, -1.436473608, 1.7227665186, + -1.0507551432, -0.3714186549, 0.2494156957, 0.163033247, 0.5737173557, 0.3798969388, 0.676297605, 2.1938946247, + -1.3434695005, -1.8401567936, -0.497325927, 0.2549467981, -0.4350290895, 1.7625454664, 0.2511341572, 2.0254280567, + 1.4629654884, -0.2105290741, 0.1842921525, -0.8437554836, -0.1074019298, 1.3886370659, 0.6858979464, -0.7213442922, + 0.7010446191, 0.2083124965, -0.5340302587, -1.8905137777, -0.2197514623, 1.8318955898, 0.598732233, 0.5050485134, + -0.0544060431, -0.5782997012, -0.2975089848, -0.1296807826, -3.1675622463, 0.443628937, -0.8021137118, 0.6727771163, + -1.4421380758, 1.5984972715, 0.7499288321, -2.0262806416, -0.2081878334, -0.5387793183, -0.0523785017, 1.5313670635, + 0.7524619102, -1.2980279922, -0.486474812, -1.9687265158, -1.1095793247, -1.3467646837, 0.1210370436, -0.4014209509, + -0.3103523254, -0.5346525311, 0.282058835, -0.1820099205, -0.133124128, 0.2891933918, -0.2156425118, -0.4738779366, + -0.4227135181, -0.3396925926, 1.0411024094, 0.507951498, 2.2190010548, 0.1058152467, 1.4273592234, -1.4032130241, + -1.1333082914, 0.4115984738, -1.2759627104, -1.7923833132, -0.986641705, 0.0260736253, 0.2983654141, -1.088310957, + 0.1540415883, 0.7682629824, 0.1405778527, -1.7093214989, 0.8520715237, 0.3354863822, 1.0088881254, 0.9830012321, + -0.1587079316, 0.2750813067, -0.5337952971, 0.5333610773, 0.5658074617, 0.113386631, -0.5827506781, -0.1758695394, + -2.3300492764, 1.3145494461, 1.5094611645, -1.1486440897, -0.9897459745, -1.2299499512, 0.4605937004, -0.7130784392, + 0.9297976494, 0.1480864882, -0.6089158058, -0.8862819076, -0.0294247605, -2.0403492451, -0.4883415103, -1.0245062113, + 0.2432617396, -1.2315342426, -0.3076558113, -1.0241663456, 0.4212306142, 0.1273297518, -0.846550405, -0.7393798232, + 0.0760505572, 0.3653028309, 0.1351646036, -0.0163296815, 2.1622841358, 1.6225196123, -0.9306966066, 0.929228425, + 0.3719254434, 0.1162487194, -0.0589749292, 0.2543700635, -1.66794312, 0.4688638747, 1.8470935822, -2.0336110592, + 0.2948815525, -0.5645554066, -1.233504653, 0.6282685399, -0.3543842137, -0.7103201747, -0.4193950295, -0.7470821142, + -0.7791161537, 0.9769921899, 1.0773099661, 0.6259647608, 0.8145341873, 0.2484787703, -1.5553941727, 0.2921783328, + -0.8426584005, -1.1621177197, -0.0484674945, 0.8237134218, -0.8495957255, 1.6625444889, -0.5229098201, 1.4123066664, + 1.4815165997, -0.5415441394, 0.0697141588, -1.3264377117, -0.2319623828, 1.277661562, 1.8105273247, 0.4019567072, + -0.3616358936, -1.63781178, 0.3181915879, 0.9920549393, 0.4044793546, -0.6421396136, -0.7581509352, 1.0275832415, + 1.5470706224, -0.7398016453, 0.6584480405, 1.1294622421, -2.4815869331, -0.8624873757, 1.3350468874, -2.7070226669, + -1.4999361038, 0.158621639, 1.8153672218, 2.8114330769, 1.5783907175, -0.1268175691, 0.7761794925, -0.0535948388, + 1.4350873232, -0.3202698529, -0.6328254342, 0.619697988, 0.9736643434, -0.8059627414, -0.0634836704, -0.4779267907, + 0.8468277454, 0.9047194123, -2.0163111687, 0.8780838251, -0.442715168, 1.568228364, -0.0647773743, 1.9337058067, + -0.0634923875, -0.8278262615, 0.1841171682, -1.2062327862, -0.1774312556, -0.3325543106, 0.5048562884, 0.1616335213, + -1.3787573576, 0.2442163378, -0.4408593178, -0.1357885301, -0.5383255482, -0.9141966701, -0.1598681062, -0.3700854778, + -2.1424248219, -0.7458830476, 0.1234179586, 0.9672073126, -0.1455941498, 0.4572854638, 0.947009325, -0.1653638631, + -1.2481099367, 0.6318738461, -0.0626924559, 0.5399544239, 0.8403316736, 0.9862011075, -0.3642502129, -0.6327438951, + -1.3328721523, 0.6068063378, 0.8446694613, -0.6332240701, 0.5425485373, 0.7139165998, -0.0305935647, -1.4514397383, + -1.3369790316, 0.5513197184, -1.5224503279, 0.5453975797, 0.8725185394, 1.4529868364, 0.562425971, 2.0542755127, + 1.7089699507, 0.9274854064, 0.4328777492, 0.7026924491, -1.3295015097, 0.2746844888, 0.2033832967, -0.4538957775, + 0.1762087941, 1.7823884487, -1.4706496, -1.2204672098, 1.472951293, 0.1214189082, 1.087138772, -0.3612067699, + 1.7784131765, 0.9309613705, 0.2597780526, -1.4110622406, 0.2922568917, -0.6586437821, -0.0512520969, -1.3286775351, + 1.6530493498, -0.7626387477, 0.9156857729, 1.9149209261, 0.2932203114, -3.0808136463, -1.0101010799, 0.6143974662, + 0.2382051498, -0.0467596762, -0.0474947765, 0.9090418816, -0.2340825051, 0.5424991846, 0.4172537029, 0.4624036252, + 0.4270164073, 1.6592540741, -1.0672186613, -0.1578507125, 0.0752028897, -0.9551435709, 0.795369029, -1.1591863632, + 0.7421058416, -0.2349259704, 0.5437689424, 2.1095736027, -0.0088392152, 0.8944605589, -1.1591901779, 1.0720796585, + 1.0443638563, -0.4178381264, -1.0055652857, 0.2256257236, 0.1818790883, 0.8913904428, -0.2827850282, 0.538226366, + 0.555277884, 0.5970648527, -0.3059228361, -1.1920317411, 1.1359806061, -0.687625885, 0.9734085798, -0.1243617684, + 0.7628061175, -0.8110380173, -0.7298203707, -0.0372581482, 1.0960302353, 0.889718473, 1.0013744831, 1.2954847813, + 1.0943894386, 1.0337970257, -0.6451089978, -1.1438543797, 1.690788269, 0.6538919806, 0.2325033396, 0.7079269886, + -0.4387639165, -0.8021144271, -1.0609641075, -0.5739922523, -0.0819813982, -1.1191276312, -1.4699013233, 1.2190533876, + -0.7642792463, 3.6206753254, 0.2141495645, 0.5528623462, 0.1748252213, -0.6519388556, -0.6073905826, 0.3652521074, + -0.9204075933, -0.7603232861, 1.0630009174, -0.9325689077, -0.5900637507, -1.1881865263, 1.2027990818, -0.8413612247, + 0.2781607509, -0.2080128193, 0.1023407057, -1.2445551157, 0.6239708662, 1.8129197359, 1.0736453533, -1.8964418173, + 0.0017032215, -2.1157252789, 1.3135426044, 0.547411561, 0.2074623406, -0.4299831986, 0.8374266624, 1.6306321621, + -0.3326140046, -1.8029530048, 0.1280977726, 0.6147022247, -1.1669268608, -0.2353281975, 1.2309724092, 0.2109920084, + 0.5916821361, 1.1949048042, -1.6691788435, 2.2587573528, -0.8347861767, 0.7055326104, -1.2176433802, -1.5963435173, + -0.9394806027, 1.1430879831, -1.0527108908, -0.2372030914, 0.502189517, -0.1742438227, -0.6610577106, 0.9951126575, + -0.5641317368, -0.9586183429, -0.4543020725, 1.5888733864, -0.5602775812, -1.4585738182, 0.2766699195, -0.2458266318, + 0.0311310496, 0.3165929019, -0.4411346018, -0.716889739, 1.6787896156, -0.5344859362, 0.1416471153, 0.1917462647, + 0.55453372, -0.9684610367, -0.2502814233, 0.8965836763, -0.3063308001, 1.5524247885, -0.2281495482, 0.5966132879, + -0.0518924855, 1.4180803299, 1.103068471, -0.5906302333, -0.4166026711, -0.1812176853, 1.2438272238, 0.0661688223, + -0.4422826469, -0.079938069, 0.1919439882, -1.7107120752, 1.077452302, 1.3768286705, -0.4153911173, 0.5705907941, + -0.02985912, -0.6760396361, 2.0611596107, 0.6797024012, -1.9420374632, 0.1937771142, -1.4224283695, 2.3359291553, + 1.5439224243, -0.1088899821, 0.3045460284, -1.9224047661, -0.8653616309, -1.4767225981, -1.0221436024, 1.101013422, + 1.6597355604, -0.9422587752, 0.2524269819, -0.5980673432, -0.8463162184, 0.1441775709, -0.0865074918, -1.4574160576, + -0.6760374308, -1.1465848684, 0.651892066, 0.331667304, -2.189707756, -1.5613869429, 1.1978230476, 1.8515207767, + -0.1663241088, 1.5600320101, 0.6311469674, 0.5801112652, -0.6303533316, -2.2313139439, 1.1076989174, 1.474375844, + 0.0909270272, -2.3126523495, 0.0237566549, -0.5718167424, -0.2207095027, 2.1772885323, -0.4963387847, -1.0081264973, + -1.5023629665, 0.7746482491, 0.5341107845, -0.566675663, -1.3972266912, -0.6807674766, 0.9254412055, 0.5504223704, + 0.660562396, 0.8508396149, 1.3720737696, 0.1541136503, 0.875713408, 0.5460981131, -0.3596907854, 0.1870216429, + 0.0117444582, 0.6488144994, -0.5489287972, -0.371376276, -0.7516688704, 1.4095368385, -0.9506681561, 1.2551702261, + -0.2971719801, 0.7826270461, -0.1850647628, 0.0467204042, -0.5125409961, -0.4186106026, 0.6029446721, -0.1644520611, + -0.7338615656, 1.011911869, -0.9809918404, 0.109882772, 0.0214030836, -0.0427952483, 1.5712121725, -1.2539938688, + -1.100281477, 1.1327694654, 0.7072475553, 0.3967822194, -1.5087244511, -0.7145330906, -0.3722834885, 0.6798279881, + -1.1214778423, 1.6043719053, -0.5292537808, 0.6880461574, 1.8885463476, -0.0577552915, 0.2836357951, -0.5647696853, + 0.2792871892, 0.8215509653, -1.3532710075, 1.7211893797, -0.0139528438, 1.830883503, 0.7426056862, 0.7111511827, + -1.6903294325, 0.1072090045, -1.0851238966, 1.300535202, 0.0922427997, 0.3189244568, -0.2317275256, -1.6285777092, + 0.2906110287, 0.5595755577, -1.5583685637, -0.5369408727, -0.2023313344, -0.4653785825, 0.2014144212, -0.7816708684, + -0.359254986, 0.85832268, 0.817794621, 0.5941096544, 1.9991146326, -0.1164116636, 1.6596740484, -0.1440827549, + 0.4968259335, 0.6306084991, 0.697843492, -0.7464147806, -0.2029277682, 0.0740947649, 1.0179958344, 0.3487094343, + -0.9844735861, 0.5505439043, 0.2724183202, 1.6677926779, 2.0806522369, 0.4009736776, -0.5573444963, -1.5428788662, + 0.3109628558, -0.1744219512, 1.1310318708, -1.1780905724, 0.2007820308, -0.7422007322, -0.9340967536, 0.5350461006, + 0.0442560837, 1.1695052385, -1.3321918249, 0.649115026, -0.4747289419, 0.5556890965, 0.7429620028, -2.0583868027, + 1.9008646011, 0.3469739258, 0.0191483814, 1.1078541279, -2.2555680275, -1.9164475203, 0.2035084963, -1.1060945988, + 0.3864742815, 1.8186519146, 1.0955337286, -0.1587141752, 1.2405792475, 1.12906003, 0.184834525, -1.3021864891, + -0.5888038278, 0.5011674762, -0.2290555686, 0.194175452, -0.0028979329, 0.1620416641, -0.1024544761, 1.34281528, + 0.5823216438, 0.5299244523, -0.4311875105, -3.9000253677, 0.1455959678, 0.1971248835, 1.5607292652, 1.1137356758, + -0.4552126825, 1.48942101, -0.2594603002, 1.3953379393, 0.0575970933, 1.161667943, -0.5125772357, 0.2737622857, + 0.6855733395, -2.2379720211, 0.0204583369, -0.4642761946, 0.5056542158, -1.1518577337, -0.0480799004, 0.8714804649, + -0.4403902292, 0.9177758694, -0.2967298031, -0.1093246862, -0.3690237701, -0.8198360205, 0.8055944443, -1.2107851505, + 0.3110791147, -0.1688169837, -0.3388747573, -1.0188363791, 0.5383563638, 0.2944939733, -0.4924473166, -1.0070977211, + -1.6481902599, 1.4362820387, 0.6015846133, 0.5694240332, 1.6722046137, -1.7027004957, -1.3625906706, -0.1457322389, + -0.5113507509, 0.2680238783, -1.7027720213, 0.7206459045, -0.5888085365, -0.6532110572, -1.0642852783, 2.3046946526, + -1.4179235697, 0.2645181417, -0.845436275, 0.4878188074, -1.3037599325, 0.7964784503, -0.1442486495, 0.3195949793, + 1.460523963, -0.6226558089, -1.4823346138, -0.4593512416, -0.9331763983, -2.1541390419, 0.6264881492, 0.0523369238, + 1.151204586, -0.4332700968, -0.9674804211, -0.1992558837, 1.5613337755, -0.3819993436, 0.6795611978, 1.0330165625, + -0.6436550021, -0.0710420236, -0.8683775067, 1.9464271069, 1.7365958691, 0.8267059922, -0.2149627805, 0.3993192315, + -1.198147893, 0.6476678252, 1.6629068851, 0.1144966111, -1.2598162889, 1.8402992487, 0.1836557686, -2.4232974052, + 1.7620264292, -1.8486828804, -0.9964275956, -1.1717942953, 0.645668447, 0.2873594165, -1.382085681, -0.7862964869, + -0.2583193183, -0.8816519976, -0.5542247891, -0.6523939967, 0.5725956559, 0.4938937128, -0.7512942553, -0.0124218957, + -0.9071369171, 1.4349648952, 1.1218518019, -0.1233512685, 1.0522289276, -1.6539301872, -0.1291158497, -0.2237756848, + -1.1045513153, 0.452182889, -0.950296104, -0.1316948235, -0.7792828083, 0.8250408173, -0.8836473823, 1.2532879114, + 0.7888385057, -0.8419920206, 2.764367342, 1.0004105568, -0.4344625175, 0.2776719928, 1.3631216288, -0.7419697642, + -1.471639514, -0.1492524296, 0.0200016722, -0.5150440335, -0.4084215462, 1.496860981, 0.4010550976, -0.7996406555, + -0.3596092463, 0.5699978471, -1.6187551022, -0.2355066538, 0.4505786896, 1.0382069349, 0.1090804636, 1.1643670797, + -0.995829463, 0.840654552, -0.6185593605, 0.4861762524, -0.1435554177, -1.1838173866, 0.6962852478, 0.8449316621, + -0.5324366689, 0.0854075029, 0.3886263371, -1.1088260412, 0.0637926683, -1.5521410704, -0.8580669165, 0.552765727, + -1.3862566948, -0.3908568025, 0.9630132914, -0.7347410917, 1.8605796099, 1.0593957901, -0.3667660952, -0.6616054177, + -0.5578662157, -1.0552052259, 1.458058238, 1.1121358871, 0.9594700933, 0.2913878858, -0.1537316144, -0.5127632618, + -0.9405737519, -0.6017516255, 0.2945948243, -0.3719144464, -0.9353292584, -1.34468472, 0.942280829, -0.6510933638, + 0.8299900293, -0.3449546695, 0.6160442829, 0.405267179, -0.6935716867, 1.0162554979, 0.6377590299, -0.4352501035, + -1.425714612, -1.2524747849, 0.7853822112, -1.5440671444, -0.1379649192, -1.7845451832, -0.3356660903, 1.3356161118, + -0.1294857413, 1.7964646816, 0.0304738451, 0.7768535614, 3.1488924026, -0.255810976, -1.0679833889, -0.7244794369, + -1.2258969545, 0.6932333112, 0.021139862, 0.1776879132, -0.5041844249, -0.2590360343, 1.1173756123, -0.4724331498, + 1.3155813217, 0.4622018635, 0.6426978111, -0.5433134437, 0.4678083062, -0.3611486554, 0.8685443401, 0.8873092532, + 0.960259676, 0.2302647084, 1.2853378057, 0.5569596887, 0.0047805822, -0.61126858, -0.6782135963, 1.868454814, + -0.0579861216, -0.5789955854, -0.5955775976, -0.014270395, -1.9806233644, -0.3151291013, 0.1911353171, -0.7444159389, + 0.3003838956, 0.3280220032, 0.3322880864, -0.4767027795, 0.2453860193, -1.5312238932, 0.4211049378, 1.9572474957, + -0.2563537657, -0.7224268913, 1.6377799511, -0.7879798412, 0.3240051568, 0.9042937756, 0.7157511115, -2.7979767323, + -1.2734445333, 0.9677686691, 0.9257705808, 1.2029485703, -1.3839800358, 0.7151804566, -0.2824457288, 1.1473516226, + 0.274739027, -0.7925121188, -0.7553021908, 1.7981562614, 0.6151124835, -0.2200139612, 0.2743393481, 0.9763574004, + -0.3318104446, 0.3161179721, -1.2327262163, 0.7387780547, 1.0659815073, 0.5092077255, 0.4646466076, -0.1616929471, + -0.3656149805, -0.935983777, -1.6265611649, -1.7118582726, 1.0020611286, -1.0089641809, -0.5619198084, 0.0407424457, + 0.4716152847, -0.7087352872, 0.2111394554, -0.035624031, 0.1253914833, 0.3591753542, 0.6934660077, 0.6154317856, + 0.548766017, -0.6675722003, 1.3222116232, -1.3435800076, -0.362123847, 0.60568434, -1.4640836716, -0.1939837933, + 1.3377373219, 1.3163279295, -0.2840470374, 0.1725505888, -1.0558664799, -0.549233079, -0.2993440926, -1.0710476637, + 0.0941991359, 0.1093792766, -2.4019165039, -0.7428352237, 0.9365871549, -0.1508529186, -1.027930975, -0.2757891715, + -0.3821061254, -0.1312558502, -0.9542873502, -0.9391035438, 0.7704802155, 2.5137343407, -1.8576669693, 0.8858221173, + -1.060721755, 0.8156251907, 0.7083178759, -0.2483287305, -0.3928205669, 1.565828681, -0.4305017591, 0.7362316251, + 1.7274297476, 0.6333814859, 0.7388486862, -0.0623305477, 0.3513028622, 1.0972409248, -0.474072516, 0.1975655705, + -0.0587218367, -0.9982358217, -1.9500787258, 0.6160622835, 0.8414084315, 0.1016046256, 0.6070315838, 0.1194629371, + -1.4341905117, -0.1593689024, -0.6355468631, -2.6104624271, -2.0266444683, 1.4117767811, -0.3176827431, 0.9845973253, + 0.0557049438, 0.4061246812, -0.8875346184, 0.6713454127, 1.0031460524, 0.3599224389, 0.9649901986, 0.0233377106, + 2.1343255043, -3.0345256329, 0.0627000332, 1.7538636923, 1.626838088, 0.305634588, -0.3472956717, 0.4976058006, + 1.6890598536, -2.3212182522, 0.3656421304, 0.1159397736, 0.8868479133, 1.6109799147, -0.6043145061, 0.0901816487, + -0.504140377, 0.1524684727, 0.4275237024, 0.8015805483, 0.1325070113, 1.792290926, 0.0355416387, -0.0134482626, + -0.133760184, -0.4896154702, -0.4701613188, -1.1700284481, 1.0802490711, -0.3751786947, 1.895955801, 0.7834692597, + -0.0290208533, 0.2484013289, 0.5301579237, 1.0153846741, -0.1129957139, 0.010242613, 1.1725256443, 1.3199801445, + -2.3764221668, -0.0671974123, 0.1287298054, -0.0941253453, 0.4301971197, 1.1682566404, -0.8586180806, -0.0630043671, + -1.1315516233, 0.8523266912, 0.8010767102, -0.5508226752, -2.2161388397, -1.2388525009, 1.3747489452, -1.3621162176, + -1.391389966, -0.818629384, -0.4310851693, -0.3265868723, -0.6595625281, 2.3377609253, -1.4617418051, -0.3850235641, + -0.5001681447, -0.7882581949, -0.6133599877, -0.7521061897, -1.3350371122, 0.8898956776, -0.1522801816, -0.1465325207, + -0.3226323426, -0.4473139346, -0.5643959045, -0.9613133669, 0.8519867659, 0.3872238696, 1.4215050936, 0.3426579237, + -0.9598645568, 1.6452548504, 1.7389665842, -0.6744043231, 0.3472268283, 0.2202254236, 0.286563009, -0.6780747771, + 2.7566978931, -0.873180747, -0.7633216977, 0.6871228814, -0.6211286187, -0.4921645522, 0.0778925493, 0.2215663344, + -0.2430664897, -0.3674600422, -1.3664894104, -1.6891640425, -0.6190827489, 0.6096336246, 0.4023823142, -1.6844097376, + -1.2404732704, 1.2487276793, 1.0760413408, 0.7050176859, 0.2361517102, 0.0590851456, 0.6469197273, -0.0474967249, + 0.441259712, 0.5177218914, 0.2961484194, 0.6438617706, -1.998831749, 1.8926148415, 0.1096209288, -0.1981773376, + -0.4132628739, 0.1424571574, 0.2664468884, -1.3339275122, -0.5177214742, -1.3208273649, 0.3496943712, -1.0425800085, + 0.9637414813, 1.1737784147, 0.4498517811, -0.0644505918, 0.5101744533, 2.1366763115, 1.4451804161, -0.4666092992, + -0.4894590378, 0.3287404478, 0.3134740591, -1.2987185717, 1.3868933916, -0.2306082249, -0.6893220544, 1.3180077076, + 1.3273700476, 0.4140501618, 0.7191207409, -1.2703672647, -1.2914323807, 0.7756549716, -0.5866320133, -1.075428009, + 1.334677577, -1.1625427008, -0.087440297, 0.3637840152, -0.7374979258, 0.050130114, 2.0589954853, -0.1709011495, + 1.175037384, -0.791660428, 0.6599710584, -0.1943487674, -0.7274425626, 1.404025197, 2.2787554264, 1.5396624804, + -0.0670272559, 0.2121014595, 1.2338556051, 0.1547452658, 0.0879635513, -0.7265217304, -0.2062857002, -0.5102232099, + -1.6904525757, 0.6855853796, 0.4538678527, 0.6846259832, 0.2891429365, -0.3029614091, -0.3062827587, 0.7371539474, + -0.2199067771, -0.1700534672, 1.6199733019, 1.2885725498, -0.7799361944, 0.1090501919, 0.4491660595, -0.0288286079, + -0.0628983006, 0.8857010007, 0.2705981135, 0.3398106098, 1.2366462946, 2.3887815475, 0.2669627666, 1.2540435791, + -3.3561549187, 1.2307398319, -0.9899719954, -0.8115420938, 0.3570990562, -1.3176939487, -0.5587753654, 1.2871930599, + 0.5928227305, -0.1087322533, -0.9933822751, 1.3560775518, 0.1624943316, 0.0694571063, -0.0019136409, 0.7378163934, + 1.8368467093, -0.5628502965, -2.1004903316, 0.106691055, 0.9081601501, -0.0222555753, -0.3945684731, 1.4343575239, + -0.5552595258, 1.7829042673, 0.0356468856, -0.2347169667, 1.4369341135, 0.89300102, 0.4602114558, -1.9390178919, + -0.4052565396, -1.125434041, -0.2811224461, -0.5239998698, -1.0315814018, 0.1420727074, 0.3060365021, 0.0850403309, + 0.0480993278, -1.2978804111, 1.0131076574, 1.3917434216, -1.814162612, -1.2823776007, -0.1916575879, -0.3455839157, + -1.2886086702, -0.8586668372, -0.6362670064, -1.4075217247, -0.9333543777, 0.1762785763, -1.3649258614, 1.2995932102, + -1.1005318165, 0.403326869, -0.3083316386, 0.0538614839, 1.3773829937, -0.0019546524, -0.2184900641, 0.2411379069, + 0.8984738588, -0.2639446259, 0.2973072827, -0.1650132984, 1.6599066257, -0.5840214491, 0.201785773, 1.3713948727, + -1.002097249, -0.4293357432, 1.4016997814, 0.1269748211, 0.9718328714, 0.1917524785, 1.134180069, -0.8607709408, + -0.6005527973, -1.3925638199, -0.3704949021, -1.1400412321, -0.1199970022, 0.3022707105, -0.3858364522, 0.2210528702, + 0.0352988578, -0.2549173236, 0.2986409068, 0.4361649752, -1.0413330793, 0.3294892013, 1.4552787542, 1.5862495899, + -0.0227510352, -1.0812748671, -2.4277453423, 1.2509670258, 0.2331276834, 0.4919901788, 1.9083909988, 1.1447935104, + 0.7911493182, -1.0623035431, 1.0173264742, -0.5506180525, 1.308678627, -1.1312993765, -0.2539741099, -0.7769720554, + -0.8569401503, -1.0207500458, -0.4745619595, -0.0598216392, -0.8905045986, 0.7787166238, 1.3677231073, 0.1858465374, + 0.4457555711, 0.7118093371, 0.296264112, 3.0088768005, -0.4178437889, 1.5481282473, 0.4459330738, -0.9167686105, + 0.8193830848, 0.7471025586, 1.5379596949, 2.2011966705, 0.374604255, -0.7496331334, -0.9353886843, 0.0856559277, + -0.2704099715, -0.2366278768, 1.7826231718, 1.665407896, -0.1156392843, -0.3040034175, -1.1702992916, 0.3079847693, + 0.250503391, -2.8715040684, -0.2713453174, -0.6889963746, 0.9085056782, -0.4304555953, -0.8376456499, -0.5170556307, + -0.3983263373, -0.1063844338, 0.5968197584, -0.884386003, -0.5697482824, 0.9696322083, 0.4466669858, 2.6486330032, + 1.0537792444, 1.1315171719, -1.6960200071, 1.4721640348, 0.9752472043, -0.7270838022, -0.0512396209, -1.278159976, + 0.0176169593, 1.8218171597, -0.748116374, 0.5921722651, -0.3314355314, 0.5687924027, -0.0314355269, -0.1451000571, + 0.0710702613, -0.9201598763, -0.7968252897, 1.6790449619, -1.2463930845, -1.1037224531, 0.2885740697, 1.1588948965, + 0.6854236126, 0.2255977839, 0.2921647429, -0.6920856237, -1.1240699291, -0.3644988835, -1.7979272604, -1.1228899956, + 1.2272027731, -0.5487995744, -1.3136093616, -1.0297425985, 0.7001258731, 1.7890787125, -0.7551582456, -0.8016943336, + 0.0867572725, -0.5807051063, -1.9119019508, 0.5016669035, -0.7634596825, 0.4129818976, -0.6169055104, 0.2314937115, + 0.0343069099, -0.3614818454, -0.0572039559, -0.0302359294, -0.4526371956, -1.9301646948, 1.3086107969, -0.2420634627, + -0.4892685413, -1.1492084265, -1.3499071598, 0.694583416, -2.6993854046, 0.1622554362, 1.8245487213, -2.3775310516, + 1.2132954597, 0.4981803596, -0.4224981964, 0.6930828691, 0.7331420183, -0.8765794039, -0.1939884126, -1.336493969, + 0.996937573, -0.7817802429, 0.1041869819, 0.5689641833, -0.1894062161, 1.7746828794, 3.4010379314, 1.7501906157, + 1.1160522699, 0.5270024538, -0.5151191354, 0.7056614161, 0.3733058274, -2.1757833958, 0.7578504682, 1.2810604572, + -1.3550686836, -0.0728973374, -0.894169867, 2.7244987488, 0.6562985778, -1.3424791098, -1.4879219532, -0.4622645676, + -0.8685433865, -0.8274912834, 1.8957636356, -0.2304519713, 0.7528501749, -0.4163318872, 1.2387114763, 0.4693082869, + 0.5144113302, -0.7112178802, -0.5271394253, 0.2068586797, 0.3400960863, 0.4101056755, -0.769538939, -1.8163501024, + 1.2588369846, -0.7120572329, -2.1530566216, -0.3808211088, 0.1169305518, -1.2409464121, -0.4366751611, 0.2634794712, + 1.7055178881, 1.6841148138, 1.5426491499, -0.9426856041, -0.3110214472, -0.6535518765, -0.9700681567, -1.0188583136, + 1.0102300644, -1.3473342657, -0.9368382692, 0.2325300127, -1.4934231043, -1.2163499594, -1.3792191744, -1.7362242937, + -0.4512777925, -0.5170749426, 0.4252825677, 0.7567505836, -0.5467865467, -1.1445674896, -1.5563454628, -0.2236038148, + 0.1928770691, 0.7539950013, -0.2075280994, 0.5398771763, -0.9476968646, -0.9016711712, 0.2438880652, -0.0737104565, + 1.0209364891, -0.9426563382, -0.4375885427, 0.4001968503, 0.2803052068, -0.2396769971, -0.5233165026, -0.0707564503, + 0.8131171465, -0.3948679268, 1.0977296829, 0.9422441721, 0.0974572301, 0.7161006331, -1.0236706734, 0.3119589984, + -1.7411181927, -0.1571304351, 0.9331872463, -0.3369457722, 0.4094284177, 0.4208583236, 0.4179211259, 1.1235785484, + 0.7556237578, -0.3103762269, 0.8064317703, 0.0034907553, 0.0354942977, -0.5652838349, -1.3458013535, 0.3002234101, + -2.1501505375, -0.0334357657, -2.6188161373, -1.2006733418, -0.0334124565, 0.6445909739, -0.66778934, 1.4247175455, + 1.0710269213, 0.4332047105, 1.3313224316, -0.4722385705, 0.6907301545, 0.1094585806, -0.2851660252, 0.3637922108, + 1.1852264404, 0.1758918315, -0.758430779, 0.2633218169, 1.062117219, 0.2851718664, -0.6434780955, -0.1335996836, + 0.1274035126, -0.5857658982, 1.0504328012, 2.0061223507, -0.488628298, 0.0543444939, -0.2162028104, -0.6167577505, + -0.7822800875, 0.9975462556, -0.0760741457, 0.8697055578, -0.5896819234, 1.4034289122, -0.6588875651, 0.1298187226, + 0.3436029553, 0.2405471802, 0.8691177368, -0.2007995248, -2.4776923656, 0.1163100004, -0.3875218034, -0.1351628304, + 0.427944988, 0.0200409684, -1.2814878225, -0.0035458973, 0.5171042085, -0.7989640236, -0.5903617144, 0.7532331944, + -1.8532392979, -0.701844573, 1.1726995707, 0.8857141137, -0.625141263, -1.4943467379, 0.8706994653, 0.1993800104, + 0.6574698091, 1.3126466274, -1.0984554291, -0.3523005247, 1.7237235308, -0.4371421337, -0.253087163, -0.3125239313, + -0.1090791225, -0.244288072, -2.3474428654, 1.0265904665, -1.1621482372, 0.5418043733, -0.1000503302, 1.6922651529, + 0.4630069435, 0.1329090595, 0.6170014739, 0.7838420868, -0.5633745193, -0.8491060734, -1.1731932163, 1.7671117783, + 0.2489637136, 0.3668170869, 1.0373156071, 0.4797249138, -0.306450367, 1.5058437586, -1.7131545544, 0.5895314217, + -0.1014877111, 0.0677429512, 1.6819930077, -0.5216151476, 0.2966107726, -0.6731379032, -2.9088072777, -0.1597213149, + -0.800947547, -0.3718868494, -0.5039060712, -0.8859555721, -0.1667399555, 0.8699729443, 0.2995379269, -0.0808590502, + 0.1149650365, -1.2343654633, -0.8192324042, -0.2976688147, 0.6526411176, 0.8078739643, -2.2390789986, -1.3788408041, + -0.0203030016, 1.0580019951, -0.167591393, -0.3040016294, 0.407705158, 1.6256030798, -0.480630964, 1.5464959145, + -0.2882610261, -0.6253515482, 1.1862369776, 0.2702769339, -0.0170092937, -1.1964570284, 0.9761407971, -1.380710125, + -0.0267551281, -0.7193158865, 0.145432502, 0.8919139504, 1.2186563015, -0.5411350727, -0.0417981744, 0.4048648477, + -2.4425880909, 1.4544825554, 0.9795028567, -0.9254541397, -1.0124781132, -1.2881475687, 0.0540674552, 0.0661320314, + 0.2954331338, 1.0461391211, -1.0540885925, -0.4005309641, -0.1517889798, 0.421634078, 0.0530298762, 0.1122975871, + -0.3990632594, -0.7042989731, 0.1255299598, 0.3206685483, 1.1385912895, -0.4752325118, 0.6582928896, -0.153814435, + 0.6831755042, 1.7123292685, 0.567147851, 0.6366145015, -0.3570763469, -0.0657979697, 0.4211172163, -2.2837688923, + 1.0036052465, 0.2398010492, 1.0281908512, -0.4071367979, 0.9219275713, 0.072214976, -2.6470177174, 1.3578057289, + 0.1536241025, 0.46962744, 0.8234762549, -0.4083556831, 0.3090576828, -0.6590387225, 0.2341024876, 0.1462763995, + 0.2002189904, 0.2424708307, 2.4530985355, 0.1110666841, -1.9045937061, 0.6433965564, 0.4160172939, -1.7808061838, + -0.1339179873, 0.8255435228, -0.2238264829, 0.4268227518, 1.0249240398, 0.8471112847, 1.3706696033, 1.1877846718, + -0.938388586, 0.3343340456, -0.4794832766, -0.4944494367, -0.1750551313, 0.3527951539, -0.8698111773, 0.1937713474, + -0.1925773323, 0.9743717313, 0.60551548, 1.2223517895, 0.361420691, -0.2067714334, -0.9952375889, 0.3734723628, + 0.6979523897, -0.4219244421, -0.5955637097, 0.9482497573, -0.751968205, -0.7860441804, 1.374088645, 0.9647676945, + 1.7791903019, -0.7668116689, 1.3360780478, -0.6458644271, -0.1355869919, 2.8971319199, -1.1330628395, -0.6012628675, + 0.5005002022, -0.4042484164, 0.4834759235, 0.3865878284, -0.3293069601, 0.8250538111, 0.2771557271, -0.5596065521, + 0.9277037382, 2.3185040951, -2.0182914734, -1.8434972763, 1.8513425589, -0.205195725, -0.3890289664, 0.3600519001, + 0.9884135127, 1.2457922697, -1.3364551067, 1.7537808418, 0.2910317779, -0.223388195, 1.5224063396, -0.4635525346, + -1.0450754166, -0.4129071236, 1.3809294701, -1.6089481115, 0.3078214824, 0.9460044503, -0.4184794128, -1.7909796238, + -1.0131839514, -0.3165536225, -2.1457698345, -0.9870025516, -0.9171952009, -0.1917024702, -0.7953843474, 0.6767178178, + -0.3210875988, 1.3021671772, -0.4075162709, 1.5203324556, 0.3550294042, -1.4809036255, -1.2452964783, 0.1944308579, + -0.9956462979, -0.3705863357, 0.5113051534, -0.5084799528, 0.7373731136, -1.0020056963, -1.228014946, 0.0769010037, + -1.0816389322, 0.6120415926, 0.5528837442, 0.9699832797, -1.6074030399, -0.3329996169, 0.2555321753, 0.7930832505, + 0.5816390514, -0.6598396897, -0.2890957296, -0.7990741134, -1.4835071564, 1.6605551243, 0.8653522134, -1.0595493317, + 0.9085577726, 0.3510276079, 0.551412344, 0.852827549, 0.0775258243, -0.0942507908, -0.5741663575, 0.42728585, + 0.4936881065, -0.4890993237, 0.8531798124, -0.5760458112, -1.8211534023, -0.6887232065, -1.4060014486, 0.7858404517, + -0.753747344, -1.0371315479, -1.1446654797, 0.8815869093, 1.2654161453, -0.6383075118, -0.825786829, -0.9015462995, + 0.1437274814, 1.3519058228, -0.1625126898, -1.9967465401, -1.8057687283, -1.2218840122, -0.4923840463, 0.6176373363, + -0.7052366138, -0.7661755681, -0.2294089645, -0.014024321, 1.3474508524, 0.9664565325, -0.5530868173, 0.5022634864, + -0.4175859094, 1.2790845633, 0.3473213315, -0.548166573, 0.171270743, 0.5872876048, -0.275380671, -0.7414954305, + 0.4202188551, 1.1896193027, 0.8167036176, 0.0596480407, 0.9580199718, -1.3611825705, 1.7055370808, 0.0063230065, + 1.8501033783, 1.4732143879, -0.0210349392, -2.0528321266, -0.0954066589, 1.0599880219, 0.7781971097, -0.4838570356, + 0.4811122417, -1.8912461996, 0.3263382018, -0.2272473574, -2.0044629574, 1.187384963, 1.5935777426, -2.1323070526, + 0.3736905158, 1.1431974173, 2.2025403976, 0.5080515146, 0.7770988941, -1.9484568834, 1.8847243786, -1.0159929991, + -0.3248388767, -0.1660611182, 0.4894922078, 0.1777799129, 1.0510669947, -2.4797639847, -1.1504589319, -0.8618552685, + 0.9332055449, -0.4171830714, 0.1696135104, 0.4340079725, -0.0387988202, -0.3269042671, 0.1180056855, -1.0725272894, + -2.8303813934, 0.2598698735, -1.9996215105, 0.7559278011, -0.9798888564, 1.3117982149, 0.0267896838, 0.7077409029, + -1.3086125851, 0.4044201374, -2.3094742298, 1.6848480701, 0.1338439882, -0.624820888, 1.6932362318, 0.0373727605, + 1.5558153391, -0.1714841425, -2.3042349815, -0.4278883338, -0.9955630898, -0.5958486795, -0.0447826646, -0.1579531431, + 1.5243920088, 1.9227956533, 0.0402987376, -0.5851413012, 1.5017855167, 2.1803050041, -3.0837733746, -1.4648975134, + -0.3116869926, 1.9565404654, -0.3280645013, 0.4791809916, -0.5352160931, 1.1737276316, 0.478749603, 0.4083316028, + 0.3431856334, -0.6605724096, 2.7108654976, 0.114797242, -0.4463745356, -0.5844126344, -1.1667927504, 0.5431652665, + -1.9812204838, 2.9475674629, 2.6613872051, -1.2210031748, -1.1133307219, 1.1255795956, 0.5629199743, 2.0009100437, + 1.5682934523, 0.3448376358, 1.2724161148, 1.6458244324, -0.6888008714, 0.2147175968, 0.7798329592, -0.3226068914, + 1.0111198425, -0.5555141568, 0.0550549068, -0.4487963021, -0.0010088464, -0.2460303754, 0.3926325738, -0.4658337235, + -0.0550008826, 0.9606356621, -1.3934432268, 0.2840017378, 0.4586493075, 1.6391483545, 0.2773736715, -0.4988467097, + -1.2484349012, 0.6145244241, -0.2343735695, -0.6073554158, 0.10373234, -0.4924787283, -0.8200624585, -0.8451112509, + 0.3545969725, -0.9189939499, 1.3295829296, 1.4435455799, -0.4522539079, -0.6177167892, 0.463969171, -0.1216813028, + -0.2014279813, -0.388800323, -0.7420611382, -1.0614147186, 0.1071903482, -0.1916001439, -0.8809502721, 1.1320753098, + 1.8845841885, -0.6628830433, -1.5071902275, -0.1309629083, 0.3128623366, -0.868842721, -0.6582813859, -0.2740010321, + -0.7021917105, -0.0590858348, 0.5003613234, 0.443534106, -0.253287673, -0.8129278421, 0.0408533216, 0.9117563963, + 0.136304602, 0.2125895768, 0.2870524526, 0.4323830903, 0.8272413611, -0.8387100101, -0.5534974933, -1.448323369, + 0.5585784912, -1.7981764078, 0.2371001542, 2.4801561832, -0.3021345437, -1.925645113, -1.3350820541, -0.2666696012, + 1.0199847221, 0.4717119038, -1.3698065281, 0.4468599856, -0.0044480967, 0.1817408204, -0.452727288, -0.1334051341, + 0.3836607635, -0.4943971932, -1.4046680927, 0.950497508, 0.0615183525, -0.5815150142, 1.3562990427, -0.6733461618, + -0.1815000921, 1.1351847649, -1.8547165394, 0.0427258536, 1.2927519083, -0.7696661353, -0.8274409771, -0.2532393634, + -0.0308168735, -0.7520497441, 1.3307759762, -1.3623781204, -0.4073944986, 1.5803796053, 2.0406692028, 0.556553781, + 0.2322279662, -1.0841896534, -1.77896595, 3.2291426659, 1.6942933798, 0.970133841, -1.2909091711, -1.889105916, + 1.4711436033, 0.4616388381, 3.1894185543, -1.5284318924, -0.4539346397, 1.7737467289, -1.0063527822, -1.0183699131, + -0.7966518998, -0.6973011494, -1.8228462934, -0.6940974593, -1.1141934395, -2.074890852, -0.6731943488, -0.1411335617, + -0.5918131471, 0.3981718421, -0.4185449481, 0.6575914025, 1.203417182, 0.7911134362, 0.4504041076, -0.1689087003, + -0.6241304278, 0.1604327261, 1.159966588, -0.5865268111, 1.4177463055, 0.7862163782, -0.9866256118, 1.36104846, + 0.1662872732, 0.7623544335, 0.4777636528, -0.4978094697, -0.9205987453, -0.6019160151, -0.5025660992, 0.2650274038, + 1.7796533108, -0.6799931526, -1.1500374079, 2.1551897526, 1.2656960487, -1.8137335777, 0.8788180947, -0.1766525656, + 1.0173312426, -0.3976323307, -0.4874837101, 1.3260022402, 2.5298173428, 0.3581320345, 0.6151618958, -0.9057765603, + 0.1278074235, 0.4101307094, 2.0343420506, 3.157916069, -0.2835023105, -1.6285960674, 0.2310625762, -0.1825703532, + 0.7172837853, -0.9383327365, 0.7119765282, -0.1827139258, -1.0331274271, -1.5335197449, -0.0797828063, 0.9077846408, + 1.898293376, 1.4115979671, -0.4417716563, 1.4773440361, -0.0987058356, 0.1569772065, 0.1336328238, 1.4706661701, + 0.39627859, 0.3535576165, -1.0396783352, -0.8096060753, -0.9630953074, -0.7505313754, -0.1620675176, -0.0327635854, + -0.5966364145, -0.0887803882, 0.2664997876, 0.6335312724, 1.0054351091, 0.0889114439, -0.5581123829, 1.3313112259, + -0.0271414258, 1.7692632675, -0.3311189711, 0.2609533072, 0.4870017171, 0.5392374992, 1.2806769609, -1.3460060358, + 1.5021263361, -1.1109247208, -1.3770757914, -0.5652141571, 0.5334227085, -0.3018633425, -0.9164126515, -0.4580081999, + 0.1177384034, 0.8895198107, 0.8998060822, 1.0108145475, 0.6404081583, 1.3359845877, 1.2474398613, 3.1175408363, + -1.2394305468, 1.561879158, -0.8826349378, 0.3026507795, -1.4841973782, 1.9171879292, 0.6733652949, 0.2914884686, + -0.0425878204, 0.7053133845, -0.2756962776, -1.1116207838, 0.2003324777, 0.4464299381, -0.4472725391, -0.5560350418, + 0.5862920284, -1.1646692753, -0.7891066074, 0.0170574617, 1.8001844883, -0.3394494653, 0.5136883259, -0.5891038775, + 0.0483943895, 0.462013036, 0.4717587233, 2.6874232292, 0.8009564877, 0.0847277343, 0.5359853506, -0.5240750313, + -0.2925489545, -1.8751555681, -0.049036175, 0.9783039689, 1.7588734627, 0.6002600789, -1.5460512638, -0.3047045469, + 0.1539754272, 0.0915840715, -0.5992405415, -0.8042455912, 1.4659844637, 0.1012221351, -0.1497529149, 1.3030563593, + 0.1541244388, 1.2717978954, 0.8867399096, -0.4318663478, 0.0770084262, 1.625818491, -0.6968182325, -0.3166991472, + -0.748390913, 0.5786557198, 0.0780947804, 0.2426024377, 0.0229945462, 0.6200746894, 0.2310543954, -1.1079101563, + -0.4020124376, 1.2420753241, -0.667966485, 0.2542519271, 1.062983036, -0.2348063737, -0.0438308194, 1.3501619101, + -0.7894948721, -0.5703001022, 0.308989048, 1.5118911266, 2.1752941608, -0.4885034859, 0.8232432008, -1.0765361786, + -0.0186190307, 0.3972360492, -0.625990212, -0.7424067259, -0.0163867436, 0.1629671752, -0.0893045589, 0.4563429058, + -0.3665952981, -0.0754317641, 0.5265722871, -3.5460734367, -0.6457802653, 0.7653337717, -2.1300947666, -0.6183684468, + -0.140688017, 0.5203972459, -1.0640109777, -1.0158450603, -0.4575025737, 0.2972842455, -0.8521395326, -0.7556797862, + 0.9271347523, 0.7557883263, 0.9758871198, -1.1998525858, 0.7437992096, 1.5684306622, -0.5971830487, -0.5554358959, + -0.2583679557, 1.1155749559, -1.0676947832, 1.0032776594, -1.8513797522, -0.351721406, 0.6328516006, 1.7444175482, + -0.8807442784, 1.4790461063, -0.1968304813, 0.4180056751, 0.7282510996, -1.6500500441, 0.3640683889, 1.1129844189, + 0.3351568282, -0.0096940594, -0.8879166842, -0.2117554396, -0.6859401464, 0.3963009417, 0.4607585669, -0.2736138701, + 1.7940083742, -0.1557259709, 0.4512560666, 0.7477252483, -0.5220136642, -0.0076781982, 0.2178294808, -0.6283373833, + 1.9523649216, -2.1755685806, 0.328450948, 0.0459350087, 1.3447287083, -2.9746835232, -0.4574049115, -0.4559212029, + -0.7927967906, 0.9932083488, 0.5941705704, -0.0860538781, 0.4814716876, -0.5481458902, -1.3757659197, -0.6130162477, + -0.9668075442, -0.2767145038, 1.1864753962, -0.2110439092, 0.0695132017, -0.1974823922, 0.2356964946, 1.3622299433, + 1.236918807, -1.0267732143, -1.3356039524, 0.4908373058, -0.4819887877, -0.403909415, -0.6929343939, 1.2614177465, + 0.1905747056, 1.1455303431, -2.1158614159, 0.2583775818, 0.4038105011, 1.1752716303, 0.4600075483, 1.1974021196, + -0.870752275, -0.2817451358, 0.058477167, 0.0356177837, -1.0699961185, -0.8630678654, -1.3466277122, -0.6549223661, + 1.1585097313, -0.1777383983, -0.2447415143, -0.0686794594, -0.42240569, 0.110006839, -0.2732768059, -0.0694849864, + -1.6778137684, -1.1774704456, 0.2881167829, -0.3823485672, -0.2653631568, 1.6647901535, -0.6484985948, -0.3476527035, + 0.0990425199, 1.2877132893, 0.2625562549, -1.7195298672, 0.1339644045, 0.934782505, 0.6773042679, 1.3379974365, + -1.1952675581, -1.4742416143, 0.4088601172, 0.5837417245, -0.8978670835, 0.9447718263, 1.2271732092, -0.1702542156, + -0.7172225118, 0.8332493305, -0.960885942, 0.6667991877, 0.1675264537, -2.4551825523, -1.3160276413, -1.3327628374, + -0.3683435619, 0.2090760469, 0.2522863746, -0.3697250783, -0.6468358636, -1.3560963869, -0.2139449418, -0.0944914892, + 1.3924498558, 0.8243910074, 1.6508191824, 0.0590403564, -0.2889220715, -1.5590000153, -0.1294312924, -0.6941680312, + 1.7140065432, 0.321303308, -1.266453743, -1.2225905657, -0.4669961035, 1.2360336781, -0.0267958753, 0.7786743045, + 0.3648271859, -0.2769484818, -1.7265735865, -2.1605618, 2.6050536633, 0.5951356888, 0.1564329863, -0.4526445568, + 0.3408089876, 0.7182588577, 1.1662245989, 1.1812388897, -1.608027935, -0.6149919629, 0.0630393922, 1.1043940783, + -0.3757201433, 2.8040859699, -1.2027796507, 0.475376606, -1.024741292, 0.0444119908, -0.0440445766, -0.9484578967, + -0.9130100608, 2.2063055038, 1.815500617, -0.4957681298, -0.098956883, -1.0796426535, 0.782289505, -1.5829148293, + -2.0142185688, -0.2487754971, -0.555415988, -0.4700220823, 1.3454676867, 1.0648335218, 1.0868573189, -1.7082974911, + 1.4550259113, -2.060905695, 0.119092539, -0.3908568621, 0.7174708843, -1.6193270683, -0.8048923016, 0.3411201835, + -0.483995378, 0.284196943, 1.0325852633, 0.4843482375, -0.3298141658, 0.8892413974, -0.3105459511, -0.9782136679, + 0.9867196679, 0.3042748868, -1.2289379835, 1.2453569174, -0.908875823, 3.6785209179, -0.8134478331, 0.113195911, + 0.1259584725, 0.1765042692, -0.428879261, -0.1435288638, -1.2279988527, -1.8669244051, 1.1203285456, -0.7590832114, + -2.0584406853, -0.3421135247, -0.6633723378, 0.3519513607, -0.0436158255, 0.2055463493, -0.3620091081, -0.6658552885, + 0.895285964, 0.4214867353, -1.3065363169, 0.5173885226, -0.2587612569, -1.5498518944, -0.7420065403, -1.0491241217, + -1.3573287725, 0.8090244532, 1.1611310244, 1.3288847208, -0.1811762154, 1.1714485884, -2.1874475479, -0.5001651645, + 2.5885710716, 0.0558268018, -0.2819325328, 0.3446589708, -0.4038097858, -0.1715606302, -0.100505963, 0.0135818729, + 1.76826334, -1.954757452, -0.6286581755, 0.5792235732, -0.7384209037, -0.5796393156, -0.0029503813, 1.5651570559, + 2.1308877468, 0.377083689, -0.2992276251, -0.4751704931, 0.9646815658, 0.8811886907, 1.2541283369, -1.8058665991, + -1.219558835, -0.2300940603, -0.2072250694, 0.3269861937, -1.7808606625, 0.9240894914, -0.2287798822, -0.7127582431, + 2.2856419086, -0.9465098381, -0.1695698649, -0.2585377395, -1.0501010418, -0.7296738625, 0.5356189013, 0.0110701267, + -0.4649605453, -0.1267327815, 0.3069141507, -0.2413745672, -1.9641823769, -0.4948186278, -0.3253749609, -1.1279431581, + -0.2000069767, -0.0331251286, 0.9191393852, 0.2092423439, -1.7219876051, 0.2334833145, 0.5516022444, 0.1393381953, + 0.8058815002, -0.628341794, 0.5322570205, -0.1071301252, 1.449110508, -0.4998187125, -0.8268104792, 0.0094867535, + -1.2482749224, 0.4494889379, -0.0147008393, 2.0177221298, -1.5565807819, -0.9726316929, -0.7886752486, -0.9195621014, + -0.3232328296, -1.6523182392, -0.6833917499, 1.123920083, 0.1679050326, 0.3240798414, -0.773694694, -0.5426825285, + 0.5655519366, -0.5882941484, -1.1837854385, 1.1089788675, -0.5024980307, 0.5236488581, 1.0887473822, 0.1232571155, + -2.0052480698, 0.4221430421, 0.4283335209, -0.4680225849, 0.8110977411, -1.0689373016, -0.5722622871, -0.9641005993, + 0.1786365956, 0.410934478, -0.2174949795, -1.2787374258, -0.2087196559, 0.5712300539, 0.4369576275, -1.6268904209, + -2.0347113609, 1.1750626564, 0.3646789193, 0.1261532754, -1.700643301, 2.5722634792, -0.4614850283, 0.4970600307, + 0.4907185733, -0.0615386628, -0.0598403178, -1.1332823038, 0.3685927987, -0.9918488264, 0.2320727259, -0.3870346844, + -0.2509341836, 0.0421222299, -0.326113224, 0.1328040659, -1.4239165783, 0.4410168231, 0.8100617528, -0.0148307206, + -0.5331758857, 1.357920289, -0.4871828556, -0.5692438483, -0.0303262174, -1.2603951693, 0.3815560937, -0.272867471, + 2.5167510509, -0.0868564248, -1.030313611, 0.7523828149, -0.0511697941, -0.8479565382, -1.6042995453, -0.747102201, + 0.1003591493, 0.9704436064, 0.2647618651, 1.909940958, 0.7866731882, 0.1858402044, 0.132539317, 0.9469413161, + -0.4874721766, -0.0009565527, 0.8496548533, -0.6209245324, 0.2415722907, -1.9862576723, -1.4180949926, 2.0506248474, + -2.196574688, -0.0406296737, -0.3715413809, 1.2954125404, 0.6550036073, 1.6960650682, -0.6649290323, 0.65702039, + -0.0266126283, 1.8540788889, -1.2913211584, 0.3372913897, -0.4722357988, -1.3040305376, 0.062172126, -0.0789120272, + 0.0933005512, 1.3070337772, 0.4582025707, 0.7568929195, -0.0107256742, -0.1645700037, -1.1813340187, -0.2204653174, + 0.2581693232, 0.8963260651, 0.0670128316, 0.8854981661, 0.1641241163, -1.2728308439, -0.9655811191, -0.438452065, + 1.6505980492, -0.5964840651, -0.2924530804, 0.1418313682, -1.128162384, -0.1900935769, -1.4205986261, -1.0110018253, + -0.8043029904, 1.203407526, 0.236041218, 0.7618456483, 2.4332990646, -0.2489451468, -2.5425071716, -0.7711074948, + -0.4524628222, -0.8661909103, -0.7690161467, 1.0050204992, 1.8060809374, 2.0945205688, 0.6686277986, 0.6050437689, + -1.2227077484, 0.4604870081, -0.7087969184, 1.8917765617, -0.0848279819, -2.1807665825, 1.702693224, 0.1401837468, + -0.4388398528, 0.0585128926, 1.5256692171, -0.2458079308, -1.3954952955, -0.8067660332, 0.4578137696, -0.0693819672, + -0.5427391529, 0.574893713, 1.9503580332, -0.9398818016, 1.0572952032, 0.7284172177, -0.4724606872, 0.7204971313, + 0.7258913517, -0.2430327237, -0.3732158244, 0.8272249699, 0.496219784, -1.8620917797, -0.1028145254, 1.1597520113, + -0.4121288359, -1.2027361393, 0.69763273, -2.4462964535, -1.7038713694, 1.3121316433, -0.5465721488, 1.1759943962, + -0.0005320666, 0.1727978289, 0.4999870956, 1.2192925215, 0.0659877881, 1.3122242689, -1.5925445557, -1.8933696747, + -1.5688316822, 0.7063481808, -0.0540814176, -0.4093583226, 0.5415523648, -0.2810840607, 1.2379930019, 1.8455535173, + -1.9942268133, 1.9342218637, 0.2190882415, 0.280267626, -0.6883954406, -1.4517098665, 0.7597011328, 1.3933690786, + -0.4069502056, 1.2743493319, 0.7263096571, -1.1906430721, -1.7904323339, -0.7842006683, 0.0496981777, 1.1656367779, + 1.214037776, 0.5458866358, 0.108889319, -0.728702426, -0.3762235045, -0.0407645404, 0.0176126137, -0.3848236799, + -0.3484652638, 0.4573885798, -0.7914643884, -0.5282921195, -1.6176098585, -1.3753209114, -0.7362214327, 0.2440520674, + -0.5911464691, 0.0714291632, 1.3157017231, 0.8958864212, 0.7456697226, 0.5918785334, -0.8514651656, 1.1709183455, + -0.0985445157, -0.7902092934, -0.8238563538, 0.6776641011, 0.6242868304, -1.7112609148, 1.1113905907, 0.3983590603, + -0.3072124124, 0.9468228817, 1.0867260695, 0.042796839, -0.237887904, 1.1288268566, 0.1591834277, -0.8023855686, + -0.0328822881, 0.9165640473, 1.8892006874, -0.554543376, 0.2005936652, -0.1401738226, 0.7532416582, -0.7191939354, + 0.1173081622, -0.9961249232, -0.0623728819, 0.8635931611, -1.3111095428, 1.060090661, 0.3490823209, 1.0388455391, + -0.1214415208, -1.2302621603, -0.3991114795, 0.6279140115, -0.7386919856, -1.3221846819, -0.825624764, -1.4266526699, + -0.1054395214, 0.1213134825, -1.1871228218, 1.2489768267, -0.6177254319, -1.7859925032, -1.0651925802, 1.650688529, + -0.0826005265, -1.7071485519, 2.9751720428, 0.7023817301, -0.5732915401, -1.423977375, -0.456669867, -1.0727081299, + -1.4537141323, 0.1222363412, -1.3030611277, -1.7162252665, 0.1611646712, -0.0376786999, -0.5798072219, -0.8318155408, + 0.3107450306, 0.3105241358, 0.1700328141, -0.7377840281, 0.1470898688, -0.0813722014, 1.3564113379, 0.1340189725, + -0.6625532508, -0.0410240777, -1.3023015261, -1.0368205309, 0.5293307304, -0.5021158457, -1.0542820692, -1.1481188536, + 0.1947138011, 0.317168951, -1.0173329115, 0.518717587, 0.1057950556, -0.7455425262, 0.4904182851, -1.0010027885, + 0.3528049588, -0.0746711195, 1.0803209543, 2.0294268131, 0.484289974, 1.8676234484, -0.5828618407, 0.7272090316, + 0.0941341445, 0.9208273888, -0.4615549743, 0.3433523774, 1.022562623, -1.3546812534, 1.1875417233, -0.1132918969, + -1.1203707457, 1.2187744379, -0.4989327192, -0.9112264514, 1.1047421694, 1.005656004, 1.5598826408, 0.6722717285, + -1.3777923584, 0.6470066905, 0.2687519193, -0.2030589879, 0.5464590192, -0.0320212431, -0.2359107584, -1.0255286694, + -0.3290923834, -1.6468341351, 0.0409779586, 0.3232469857, 0.109300077, -1.0682225227, -1.302293539, -0.1504627466, + -1.0588222742, -0.3715017438, -1.1889908314, 0.2288609296, 0.2993321717, 0.4552179277, -0.5519235134, 0.0778525472, + -0.1051733196, 1.2543287277, -2.6627442837, -0.5184801221, -1.8136134148, 0.1367356926, 0.0721394643, -0.7105522156, + 0.7686612606, 0.3240852356, 0.8016172051, -0.2594587207, -1.36510396, 0.7902607918, -0.0750836357, -0.0406575575, + -1.5975726843, -0.9080748558, -0.894898355, 0.7329773903, 2.6953494549, -0.8728044629, -0.476546973, 1.2926892042, + -0.85329777, 0.227387175, 0.8500044942, 0.8162901998, 0.3053658307, 0.1576725543, -1.2945351601, -0.2502624691, + 1.2744140625, -0.72503227, -0.2637364864, -1.2683051825, 0.9549968839, -1.9983717203, -0.9407818913, 0.2056222409, + 0.9628034234, 2.5071811676, 0.4945580959, -0.2393418849, -0.4995599389, -1.2183736563, 0.6175827384, 0.353025496, + 1.8969041109, -0.7900554538, 1.6417257786, 0.5082850456, 0.7210969925, 0.1719370484, -0.8770158291, 1.2253770828, + 0.0307714008, -0.5999941826, -2.0702910423, 0.139215216, 1.5867739916, -0.277441889, -0.396894455, -0.6462703943, + -1.8079203367, -0.143543303, 0.2059432119, 1.648946166, -0.2428348064, 0.8678718805, -2.1709468365, -0.0419791229, + 0.5046077967, -0.6470251679, -2.1490387917, 1.5061701536, 1.2396297455, -0.4780521691, 0.0269159973, -0.7107182145, + 0.2932947576, -0.0467100739, -0.6241620183, 1.5232892036, 2.2675340176, -0.1043779999, 2.0489764214, 2.2696111202, + 1.2227553129, 1.6606631279, -0.5712388754, 0.0546040423, 0.2590203583, 1.2644896507, 0.2683848739, 2.7493901253, + -0.9891241193, 0.4144333899, 0.3645968735, -1.191331625, 0.0431974605, 1.7358802557, -2.4658632278, 0.0826712474, + 0.4959769845, 0.5519586802, -0.2668684125, -0.9466699958, 1.6705639362, 0.735843122, 0.7760394216, -1.1162991524, + -1.0943129063, 0.5646335483, 0.5407114029, -0.5756079555, 1.8289971352, 0.8284856081, -1.6793274879, -0.0482726954, + -0.3428310454, 0.4674871862, 0.4687924385, -0.7644754052, 2.9350652695, 1.5090997219, -1.2739346027, -0.8650171757, + 1.0715694427, 0.7076815367, 1.1324560642, -0.7596591711, 0.4681403041, 1.6337355375, 0.3445463777, -0.3208348751, + 1.2135955095, 1.3381587267, -0.1650899053, 1.0665588379, -1.1150864363, 1.0701800585, -1.305262804, 0.0422085188, + 1.9998065233, -1.7469418049, -0.2975669801, 0.5028178692, 0.8254718781, -0.4733499885, 0.409520179, -0.4338210821, + -0.4989029765, -0.9439502954, 0.1678249538, 1.9921586514, -1.6073846817, -0.8297287822, 0.0909254551, -0.6161510348, + -0.5609905124, -0.2859306931, 0.6985344291, -0.6712636352, -1.4290097952, 0.5024514794, -0.6953155994, -0.8284509182, + 1.5240137577, 0.3114162683, -0.568857491, -0.5349234939, -0.4808453023, 0.1530985087, 0.2676455081, -0.2223212123, + 0.1744278967, 0.2862839401, -0.6046664119, 0.4904140234, 0.0750555247, 0.7289562225, 0.6942309737, -1.0967652798, + -0.7154685855, 0.4513160884, 2.0987625122, 0.9161058068, -0.9617047906, -0.010194405, -0.3066106141, 0.0998871475, + 1.0319311619, 0.2301389426, -1.0832765102, 1.8243718147, -0.9366260171, 0.1783067882, -0.1649248004, 1.3017970324, + 0.6445472836, 1.7660093307, 1.3376543522, -1.119163394, -0.1635971516, -1.6489555836, 0.0993696302, 0.6865174174, + 0.9365585446, 0.2498519421, 0.1184616387, 0.6225427985, 1.2603803873, -1.4978742599, 2.1375963688, -0.1365803182, + -0.1895365268, -0.2252049595, -0.1031861082, 0.458897233, -0.1754950583, -0.7891124487, -1.4106558561, -0.2436112761, + 1.3145904541, -0.2643491924, 0.2929087579, -0.2023253739, -0.3809172213, -0.2256442457, -0.7095449567, 1.6255832911, + 2.3382439613, 0.493896991, -1.9099097252, 0.4098784924, 0.9579098225, 1.1237193346, -0.0052647912, 0.0314161777, + -0.2493994832, -0.8705860972, -0.8726430535, 0.7882552743, 0.7331334949, 1.7048001289, -0.8281053901, -1.4328604937, + -0.6085548997, 1.3891786337, -0.5192667246, 0.4646701813, 0.1095870212, 0.7222380638, -1.0051553249, 0.902142942, + -0.3742950559, -1.192548871, 0.6312025785, 1.0276609659, -1.8227084875, 0.1302038729, 0.5725678802, 0.7566816211, + -0.6131682992, 1.6283639669, 0.5575514436, -1.5517416, -0.3973201811, 0.3933172822, -0.6209436059, 2.229944706, + 0.9194506407, 0.112779133, -1.3650295734, -0.3201951385, 0.3234144151, 0.8839156032, -1.6540412903, -0.6980065107, + -0.6564571857, -0.7529318929, -1.6853379011, -0.8302558064, 0.9642930627, -0.3338047266, 1.1360625029, -0.1617259681, + 0.8039368987, -0.7213765979, 0.9166084528, -0.277877897, -0.1063275859, 0.2079641819, -0.0063563455, 0.2102287859, + -1.0888133049, 0.4468370378, 1.1374158859, -0.5253376365, -0.4778427184, 0.2243154347, -0.6749815345, 1.0322270393, + -0.9930639863, -0.485909611, -0.3069780767, 0.4539842308, 0.7087320685, 1.3813514709, 0.0334968083, -1.5020490885, + 0.2795063853, 0.9115028381, 0.0795381293, -0.9493045807, 0.0057000839, 1.8318384886, 0.2391988933, -0.299428761, + -0.124549754, 0.3006445765, -0.4049408138, 0.0507116504, 0.1041309908, -0.447237283, 0.2908937633, -1.3848526478, + 0.9086578488, 0.3378473818, 1.4619905949, -1.5845800638, -1.1525335312, -0.6863923073, -0.1426220536, -0.0538095944, + -0.9843934178, 0.7708935142, 0.36342749, 0.722207129, -1.4486782551, 2.147939682, -0.916739881, -1.013882041, + -1.2438874245, 1.6870024204, 0.0624750219, -1.7277748585, 1.0282175541, -1.0794452429, -0.9668543339, 0.6164269447, + 1.0389000177, 0.6272831559, -0.0910195485, 0.3704117835, 0.0858492926, -0.6236388683, 0.6556786895, -1.1343281269, + -0.6852283478, 0.418790549, -0.3736714423, 0.4399876595, 0.4863699675, -1.2893429995, 1.2970787287, -0.9376946092, + -0.070892714, 0.4519757032, -1.2560162544, -0.7564775348, -1.2853606939, -1.4764347076, 0.0187401716, 0.5181655288, + 0.1931071728, 2.0165812969, -0.6870343089, -0.5474315882, -0.9243340492, -0.0350501649, 0.4463641942, 1.0694886446, + -0.3940467834, 0.8290531635, 2.7378354073, 0.6988120079, 1.1682595015, 1.256583333, 2.2958664894, 1.0740492344, + -1.1948891878, 0.7294963002, -0.8258320689, -2.4308962822, -0.2404142767, 0.3294350803, 0.5455643535, 1.1034344435, + 0.1110701412, 0.3185352981, 0.4520530403, -1.4553079605, -0.5798675418, 0.3087005615, 1.6675961018, -0.4612086117, + -0.8659790158, -0.8224008083, -1.1954746246, 2.3250622749, -0.047440581, 1.1397987604, 0.4894039333, 0.6380180717, + 0.872040987, 1.3701871634, -0.6702001691, 0.1365573555, 0.8938791752, -2.2082872391, -1.5051922798, 0.4718648493, + 0.4459237456, 1.0747903585, -0.3032374978, -1.9131064415, -0.9425461292, -2.194896698, -0.5122132897, -1.1340646744, + 1.0650100708, -0.0310556535, -0.391920507, 1.9453985691, -0.9041585326, -1.137519002, 0.5593029857, 0.3512958884, + -0.2719665766, -1.2004096508, -0.9829906225, -0.559450984, 0.7834479809, -1.0296547413, -2.9886469841, -1.3362042904, + 1.396171093, 0.0321802497, 1.6879734993, -1.9495279789, -1.314661622, -0.605917871, -0.1589753181, -1.5342533588, + -0.0959366262, -1.0127555132, 1.658520937, -1.097055912, -0.0442612171, 1.0565162897, -0.4931052327, -2.3154871464, + 0.889305234, -0.5490179062, -1.0743147135, -0.7600001097, 1.48082757, -0.6100429893, -0.0965769142, -0.1723432541, + -0.303166002, -0.9866677523, -1.1144934893, -0.0944731832, 1.2081950903, -0.5706077218, 1.48376894, 1.4544682503, + 0.3421855569, 0.5417101383, 0.1148955226, -0.1729538888, -0.6006920934, -0.8390375972, -0.8688585758, 1.9264659882, + -0.5148521662, 0.0482680723, 1.4802362919, 0.0934116393, 0.1687042266, -0.5380268097, -0.1822315454, -0.6247577071, + 1.0951794386, -0.55205971, 1.1341189146, -0.9410278201, -0.6713935137, -0.7394921184, 0.4502103925, -0.6198716164, + -0.6839472651, 0.1225380972, -0.2928015292, 0.5678059459, 1.391798377, 1.9239299297, -0.2305802852, -0.5392155647, + 1.9057199955, 0.111313276, 0.2179827541, -0.3769581318, 0.5038686395, 0.5441030264, 2.1462361813, -0.1754538417, + -0.2272842228, -0.7777884603, 0.3594806194, 1.019361496, -1.1204891205, 0.9485693574, -1.236384511, 0.6520394087, + -0.2308014482, 1.6299146414, -1.1982326508, -1.4894257784, 0.1250338554, 1.6823540926, -0.0901871324, -1.1973161697, + -1.0665248632, -1.6871834993, -0.8226858974, -0.2290683836, -0.2399158925, -1.1904006004, -1.1496270895, 0.4385099411, + -1.4581204653, 1.4406924248, -0.3567754328, -1.2256165743, 0.6519488692, -1.6003174782, 1.6349955797, -0.4684672058, + -0.8184659481, -1.4700213671, 0.9492305517, 0.9033931494, 0.0192416534, -1.096180439, -2.7277271748, -0.6291338801, + -0.4750710428, -0.9310365915, -0.405182153, 0.6260236502, -1.258476615, 0.1520262361, -0.509832859, -0.5226279497, + 0.5744693875, 1.2434821129, 0.0292647406, 0.1323002875, 2.9719250202, -0.2966171503, 0.2232382149, -0.8948405385, + 1.9650298357, -0.4943556488, 0.2295539081, 1.1664227247, 1.3640789986, 1.3521430492, 1.5934813023, -0.132076934, + 1.0461800098, -0.6914286613, 0.5779567361, -0.556091547, -1.5874744654, 0.224706769, -0.376129806, -0.6025452018, + -1.5737394094, -0.8176524043, 0.1051435396, -0.5349892974, -0.1311412752, -0.2104492337, 1.1861252785, -1.3101953268, + 0.0564993545, -0.6865065694, -1.7655328512, 0.8406751156, 0.9682949781, -0.3303029239, 1.2768537998, 0.5624393821, + -0.2575190067, 0.1811937392, -1.0224636793, 0.0395928435, -0.6465151906, 1.3817548752, -0.84987849, 0.960539937, + -0.5322082043, -0.5752568245, -0.2549653947, 1.0302226543, 0.1062326059, -1.2118384838, 0.1191878691, 0.0014828539, + -1.1837663651, 1.0874757767, -2.8219051361, 0.3327438831, 0.3325736225, -0.9217550159, 0.7638429999, 1.3450644016, + -1.1933127642, 0.5198947787, -0.5931326151, -1.2922502756, 0.1143693775, -0.0845904127, 1.0581725836, 0.9305245876, + 0.4070013165, -0.734107554, -0.1060848758, 2.1465601921, 0.1787221581, 1.7992449999, -1.2903478146, 0.1223225221, + 1.4852894545, 0.2455696911, -0.8079850078, -0.9959421754, 1.3645406961, 0.8025732636, 0.2571508884, 0.4182025492, + 0.7682970166, -0.2245483398, -0.9194589257, -0.4008037746, -1.7039490938, 0.732180953, 1.0105509758, 0.8314722776, + -0.9105592966, -1.0720477104, -0.4215989411, 0.7376125455, -2.403657198, -0.3848825991, 0.8627403975, -1.0709260702, + 0.9025353193, -0.2341202199, 1.4916242361, 1.0881841183, -0.4007686973, -0.3403339386, 0.5308698416, 0.7718102336, + 1.6546257734, 2.7061583996, 0.3537329733, -0.04481465, 0.1036679819, -0.7673404217, 1.4605641365, -1.6149725914, + -1.0541573763, 0.0763381571, -0.8486981392, 0.038647797, -0.4559693038, -0.8339561224, -0.4026286006, -0.4288522899, + -0.3586120307, 0.1533448994, -0.113654986, -0.8437499404, 0.6916508675, -0.4252757728, -1.9518626928, 0.4714142382, + 0.5827259421, -1.2929222584, -0.3891405165, 0.4851530194, 0.5295843482, 1.349011302, -0.5542256832, 0.0399686582, + -0.6475527883, 0.7677624822, 0.1303908378, 1.0854752064, 1.7191438675, -1.0001112223, -0.6612618566, -2.0385735035, + 0.9662070274, -0.922203064, 0.2547031045, -0.11736577, 1.5544829369, -1.2023463249, 0.2614167929, -1.9884563684, + -0.0514406934, 0.4254758358, 0.2848817408, -1.1909495592, 0.4748627841, -1.1672532558, -1.2991082668, 0.2625207603, + -0.2106069028, 0.1302159131, 0.6869119406, -1.2869962454, -0.439822644, 0.1023867726, 1.9681735039, -0.3628941178, + -0.3845193088, -1.810629487, -0.3800882399, -0.3710056543, 0.0102245891, 0.5141667724, -0.9211145639, -0.1126588136, + -1.150165081, 1.9226061106, 1.2949194908, -0.2108839899, 0.7516497374, -0.6861072183, 0.427318126, 1.4809700251, + -0.2807698846, -0.6138682961, 0.1348924786, -0.1911712438, -1.208866477, -1.3775349855, -1.5261063576, -0.3294872344, + 0.9192034602, 0.6944690347, -0.2111102492, 1.3722932339, 1.0175527334, 0.1142073944, -1.1281518936, 0.5902181268, + 0.8330125809, 0.6166064143, 1.223611474, 0.4062391222, 1.2697188854, -0.8363413811, 0.1143634394, -0.418456614, + -0.3388504982, -0.0837198272, 0.2457090765, -0.2588721216, -2.6595571041, -0.2221146077, 0.2140495479, -0.8823900223, + -0.4630803168, 0.2623826265, 0.4191049337, 0.8740573525, 0.9312805533, 1.6630910635, -1.1229330301, -0.3988712132, + 0.3089698553, 0.6604155898, 1.0093617439, -1.6651716232, -0.7364777327, 0.3452317119, -0.4719576538, 0.0853512287, + -0.6963783503, -0.2385855615, 0.4833333492, -0.095310621, 1.8122999668, 0.3582427204, -0.7948063612, 0.4761179686, + 0.2154228389, 0.6026530862, 0.3933068812, 0.692884028, 0.2977566421, 0.6478030682, 1.0729994774, 0.4346579313, + -0.951159358, 0.9497818351, 0.8753393292, -0.328435272, 2.1367778778, 1.6212879419, -0.6599621177, 0.4766357243, + -1.4166018963, 0.7105426192, 0.1458755434, -0.1393823624, 0.1677254587, 0.393062681, 0.0387067795, -1.0487891436, + -2.1851563454, 0.4409761131, -1.3168141842, -1.2756685019, 0.4949780107, -0.005367314, -0.3223702908, -0.6519203186, + 0.5039027929, 0.2957015634, 1.2806518078, -0.7631545663, -0.7418268323, 1.3974416256, 0.4859984517, -0.2325882018, + -1.1511465311, -0.0982916951, -0.2832758725, 0.0918571278, -0.1249718368, -1.4539741278, -0.2667857409, -0.5932501554, + 1.5480179787, 0.1944077015, -1.2783476114, -0.1039233878, 0.2209801972, 0.5416983366, 1.8491382599, 0.778920114, + 1.4660717249, -0.7854235172, 0.7227502465, -0.003187903, -0.3045358062, -1.3084830046, 0.7555395365, -0.3509569466, + 0.8722602725, 0.2640450895, -0.0512377284, -0.3850245178, 0.2748367488, -0.8619273305, -0.5983606577, -0.2911280096, + -1.1638661623, -0.1225519106, -1.1247522831, -0.724566102, 0.317214191, 1.0484007597, -0.6781160235, 1.6836032867, + 1.7057974339, -0.7776958346, -0.7127845287, -1.7799401283, -0.942446053, -0.256798476, -1.7354787588, 0.5987724662, + 0.6738944054, -0.7204313874, 1.4037210941, 0.9783397317, 0.1899294406, 0.8302225471, -0.8875858188, -0.1858076006, + -0.8468185663, -1.0604618788, 0.0126434006, -1.1486490965, -0.5749979019, -0.417493552, 1.3039525747, -1.1012734175, + 1.0699433088, -1.4980803728, 1.2565586567, 0.4683552682, -0.4248012006, 0.566509366, -0.8894879222, -0.9242884517, + 0.5567165017, -0.2315455079, 0.6107094288, 0.0718754381, -0.405322969, -0.1032371223, 0.1640097946, 0.0202594232, + 1.6416261196, -1.9592071772, 0.7429304123, -0.7617667913, -0.9404531121, -1.0880265236, -0.4952817559, -0.1792133898, + -1.0586580038, -0.2037551254, -2.7976267338, -0.2782055438, -0.3884856105, 1.4003995657, -0.7439337969, 0.1906057298, + -1.2973126173, -0.5760190487, 0.0010075861, -0.3164952993, 0.4198083282, 0.5122329593, 0.6419844627, 1.5902930498, + -0.9253531694, 0.4934574664, 0.1158690378, -1.2287720442, 0.8400771618, 0.8152031302, -0.9727423191, -0.520057857, + -1.635043025, 0.766995132, -0.7027513385, -0.2783911526, 1.275676012, -1.0061872005, 0.5207966566, -0.1774211377, + 0.1268888563, 1.1396467686, 0.2380308509, -0.2564617991, 1.5399690866, 0.1576723307, 0.7258236408, 0.9801822901, + -1.7694141865, -0.4557214975, -0.4337657094, 1.1572785378, 0.5312779546, -0.2003088146, 0.6846209168, 1.2052086592, + -0.2296351045, 1.1039553881, 1.3138203621, 2.8796958923, 1.0311387777, -1.8142951727, -0.3141567707, 0.2261027247, + 0.5151367188, 3.0695443153, 0.2548579574, -0.9201954603, -0.363974303, 1.498210907, 0.2461914569, -0.2713237107, + -0.9528974295, 0.7874175906, 0.3267644346, -0.8727814555, 0.1782025397, -1.1037790775, 0.1650889963, -0.1240965798, + -1.1618554592, 0.1651325077, -0.6387265921, 0.2335938811, 1.391895175, -0.9376947284, 1.0478419065, -0.3835449815, + 1.6917550564, 1.0707421303, 1.5578179359, -0.4176296294, 0.8883716464, -0.0825842023, 1.0968365669, 1.4495837688, + 0.3236922026, -0.0004275652, -0.0215025973, 0.0394743606, 0.8524720073, 0.8768084645, 0.8922595978, 0.2185391933, + 0.4017852545, 0.8576724529, 0.8088468909, -0.3175498545, -0.4993957877, 0.4370413125, 0.0653270409, -0.5538098812, + -0.8825448751, -0.1844616681, 0.0126108462, -0.5641058683, 0.2735268176, 0.3900638819, -1.4210958481, 1.3800935745, + 1.7626299858, 0.2206579298, 0.2094408274, 0.1169288829, -0.0439985879, 1.6005190611, 1.9413633347, -0.9205535054, + 1.0154896975, 0.5654467344, 1.1234375238, -0.0849402025, -0.5356362462, -1.8453865051, -0.59122473, 2.3808486462, + 0.6380431652, -0.0779390782, -0.5372304916, -1.0714815855, -0.9567815661, -1.9812661409, -0.8885300756, 0.3465723991, + -1.5381587744, 0.5294940472, -0.8159481883, 0.1816445738, 0.5993745923, -0.0688724965, 0.491705209, -2.167361021, + -1.298394084, 0.6069096327, -0.1220805272, -0.3988957107, 1.2535202503, 1.5654284954, 0.2309513092, 1.1095582247, + -0.2400104105, -0.307990253, 0.274458766, 1.0943692923, 0.2639151514, 2.7983736992, 1.5682145357, 0.2655566633, + 1.0198340416, -0.1856144965, 0.0719759017, 0.697409153, -0.3650955856, -1.0268156528, -0.0775278434, 0.3819551766, + -0.2707291245, 0.4601927996, 0.1960742921, -2.8733341694, -0.7153529525, -1.5700154305, -1.1252595186, 0.8889979124, + -0.1681040972, 0.4190223217, -0.1275238544, -2.1446073055, 0.4539523423, -1.7821577787, -0.7988014817, 0.9233134389, + 0.0920516923, 1.926050663, 1.1535536051, 0.1917728931, -0.8712940812, -1.3023717403, 0.2304571271, -0.2696764469, + 1.7969834805, -0.2386470139, 0.3282249868, -0.6356702447, 0.538744688, 0.8461692333, -0.2104572505, -0.8630337119, + 0.7488220334, 0.9744762778, -1.9335272312, 0.2642577291, -0.7576102018, 0.1086469367, 1.0653381348, 0.545422256, + -0.3583743274, -0.2401515096, 0.8858023286, -1.5596271753, 1.08708179, 0.4798313379, 0.9968619943, 1.076174736, + 0.0166343134, 0.7263668776, 3.0349943638, 0.2674559653, 1.0315163136, -0.609131813, 1.3296933174, 1.1060048342, + 0.179162994, 0.7824376822, 0.3643795848, -0.0688682124, 0.3397498429, 0.0978621468, -0.6770811677, 0.613925159, + -0.5844218731, -1.0284618139, 0.8847949505, 1.6860802174, -0.1588840932, -1.4511556625, 0.9644990563, 0.1010972485, + 0.7338010669, -0.1568467021, -0.9706460238, -0.6732884645, -1.0313397646, -0.8497923613, -1.4788682461, 0.7079484463, + 0.3125767708, 0.0050403099, 0.4007194936, -1.1395459175, 2.0679659843, -0.0851880386, -0.5869293809, -0.4736531079, + 0.7341102362, -0.3778316677, -0.5041046143, 0.6410043836, 0.0255725123, -0.6730322838, -0.4380423427, -0.6478739381, + -0.0050521214, -0.3049477041, -0.8393627405, 0.7373325229, 0.3903099298, 1.0192760229, 0.7384288907, -0.3072429597, + -1.5440155268, -1.226192832, -0.6180872321, 1.372725606, -0.3824479878, -0.0834695697, 0.7977703214, -0.7664447427, + 0.3092956245, -0.8667956591, -0.0599133223, -1.5001881123, -0.5292657018, -2.3725910187, -0.4090963602, -0.3331638277, + -1.2272868156, 0.8172550797, 1.5381202698, -1.1170098782, -0.88769418, 0.1524083763, -1.979105711, 0.377138257, + -0.5076460838, 1.2998002768, -0.8550341129, -1.0795487165, -0.1310768127, 0.5569698811, -1.9104845524, 0.680301249, + 0.1322748959, 0.3465833664, -1.1199702024, -0.3691485822, -1.7317962646, -0.8497638106, 3.6870191097, 2.2949135303, + 0.5006017685, 1.6048829556, 0.9236067533, 0.5055042505, -0.6939823627, 1.190015316, -0.1262883246, 2.3308765888, + 0.1819272786, -0.5119418502, 1.1648005247, 2.2314093113, 0.6448895335, -0.6988681555, -0.0384671949, 1.5574637651, + -0.6268103123, -0.4058221579, 0.4050198793, 1.0012731552, 0.7926679254, 0.1292645335, -0.0604107268, 0.3225554526, + -0.4775817096, 0.8939678073, 1.1663762331, -0.5386640429, 0.9164229035, -0.1918735504, 1.4974851608, -0.6885712743, + 0.0340448506, -1.2865372896, 0.745116055, -1.6031799316, -0.4937097132, 1.3747198582, -0.5014317036, 0.8943790793, + -1.3215848207, 0.5586235523, 1.5413256884, -1.4550051689, -0.9163423181, -0.5487048626, 0.1736886799, -1.1643437147, + -1.8016388416, 0.9181058407, 0.4756911993, 0.0509872176, 0.1600379348, 0.1163054481, 0.594217658, 0.2267961651, + 0.4649511874, -0.2198812366, 1.7069232464, 0.0407197364, -0.001057094, 2.6112511158, -0.8208794594, -0.8140652776, + 0.935097456, -1.2511539459, 1.4331966639, -0.6402844191, 0.6937068105, 0.536654532, -1.0673049688, -1.0099349022, + -0.7698056102, -0.1967914104, 0.4551593065, 0.6804695129, -0.2212719023, 0.1560983211, 0.2077799588, -0.2559347749, + -0.6590756178, 1.8647357225, 1.470766902, -1.7711633444, -0.0389776789, 1.2798991203, -0.2931283712, 0.4195695221, + 1.2389466763, 1.4354935884, 0.8050691485, -0.7181984186, -0.5427057147, -0.0143227829, -2.0996563435, -0.2624518871, + -0.0271753389, -0.4848319292, 0.1522143483, -0.3941994607, -1.3695958853, 0.8463138938, 0.7625041604, -2.6974196434, + 0.1153355688, 0.9856745005, -0.1841914952, -1.1387770176, 0.5851966143, 0.9297739267, 0.7000173926, -0.7721249461, + -1.0423361063, 0.6085122228, -0.1843611747, 0.2995264232, 1.6914433241, 0.1621672064, -0.6695007086, -1.583827734, + 0.1919981539, -0.2652933002, 1.2727167606, 0.755771935, 1.3111314774, 1.0354379416, 0.0457438529, 1.836851716, + 0.5285716057, -0.0358069725, -0.3260233402, -0.010996894, 1.7571246624, 0.8397163749, 0.0457721874, -0.2342656553, + -1.1719472408, 0.4112628996, 0.4550276399, -0.2209479064, -0.3792432845, -0.519667089, 0.6338948011, -0.4687461257, + 0.3789885342, -0.6974380612, 0.6244715452, 0.6647689939, 0.198935166, 0.9490326047, 0.953872323, -0.3232532144, + -1.2485311031, -1.1898362637, -1.3543343544, -0.1478466094, -1.7027926445, -0.2219823599, -1.3504548073, + -1.4105155468, 1.4693017006, -0.9841487408, -0.1953340322, 0.8112298846, 1.3687382936, 0.2290214747, -0.8213371038, + -0.5722841024, 1.8054988384, -0.2536306977, 0.0729738325, 0.4649703205, 0.0422217771, -0.3143117428, 1.3984079361, + -0.0015608553, -0.5787816644, 0.5725606084, -0.3906839788, 0.0330548063, -0.5729920268, -1.3764246702, 1.0837403536, + 0.8048295379, 1.1178059578, 0.9453338385, 0.0617002957, -0.6828507781, 0.8997985721, 1.0651228428, -0.1373525262, + -1.5338754654, 0.1621236652, 0.2117942125, -0.9399450421, 0.9874948263, -0.6034541726, 0.1361092329, -0.3756698966, + -0.0457318723, -0.6480113268, -1.4728063345, -0.352627784, -2.5419843197, 0.2226303667, -0.0023718607, -0.2957418263, + 0.4968234003, 0.7623850107, 0.4839349389, 0.0289388001, -1.1439795494, 1.4620765448, 1.2326036692, -0.9133926034, + 0.4964179397, -1.0620882511, 0.7359864712, -2.2167191505, -0.7982082963, 2.133181572, -0.9304955602, 0.1575941294, + -0.7669993639, -0.3956198692, -1.8070354462, 0.3882973194, 2.8525314331, 0.9374451041, 0.988722682, -0.6674115062, + 0.204129383, -0.6884194613, 1.2304478884, -0.2918583751, 0.3572739363, -0.439281702, 0.7722851038, -0.2283833772, + 0.223445937, 0.600650847, -0.5135402679, 1.1010036469, 0.0592561252, 0.937274158, 1.2490446568, 0.0454107709, + -1.214318037, 1.2831765413, -0.2877854705, 1.1066776514, 1.7132198811, -1.5615347624, 1.2326842546, -0.6733837128, + 0.5636820793, 0.2575648725, 1.9115114212, -0.6896926165, -0.9419258237, -0.011774186, 0.1123029664, -0.2908022702, + -0.3897866011, 1.2393567562, -0.5410919189, -0.0594159551, 0.5686154366, 1.2410963774, -0.565471828, -1.1199505329, + -1.6332823038, -2.390982151, 0.7570685148, -0.1796463877, -1.0146815777, -0.6059055924, 0.8664308786, -1.8528240919, + 0.6743731499, -0.6671823859, -0.8835974336, -1.0965219736, 1.5275717974, 0.730016768, -0.2790175378, 0.74637115, + 0.1410504282, -0.8136600256, 0.7124322653, 0.6585643291, 0.4684002995, 1.6137416363, 1.1167794466, -0.6949005127, + -0.1380605549, -1.5743788481, 0.1458098441, 0.1653126776, 1.1618109941, 1.2810046673, -1.1934560537, 0.2221141905, + -1.3247392178, -0.9758756757, 1.7848703861, -0.4239293635, -1.549639225, -1.0143722296, -0.9373916388, -0.0033001278, + 0.4032337964, -0.0522733368, 0.5052266717, -0.3572324216, -2.1708812714, -0.8520315289, 1.2847210169, -0.5304069519, + -0.4453616142, -1.2954775095, -0.3580422103, -1.8790763617, 0.911773324, -0.7384397388, 0.3458448648, -1.1715149879, + -0.5691010952, -0.3036805391, -1.4098423719, 2.2985846996, -1.0172985792, 0.4456582069, 0.1196669713, -0.1597136408, + 1.3163573742, 0.6440555453, -0.4741426706, -2.1343107224, 0.7861979604, 1.0434623957, 0.1084718406, -0.0941078067, + -0.1117874235, -1.9170396328, 0.313252151, -0.3455376625, -0.5181628466, -1.0792073011, 1.1498949528, -0.3038112223, + 0.3882457614, 0.5555512309, 0.8595563769, 0.9541366696, 1.4233583212, -2.9718353748, -0.7919180989, 1.3287876844, + 0.6337758303, -2.0233647823, 0.199474588, -0.0833952278, -0.8845870495, -0.2299005687, 0.318898499, 0.4911392033, + 1.5346169472, -0.2562862933, 0.3037653565, 0.6775609255, -0.2594868243, 0.9171200991, -1.1272230148, -0.0771622583, + 1.9170622826, 0.0905564949, -0.1810506284, 0.0498206317, 0.1376063973, 0.8997771144, 1.0737489462, 0.0820906535, + 1.3511236906, -2.0293605328, -1.1584099531, 0.216881603, -0.0768081844, -0.5279827118, 0.7440552115, 2.0216920376, + -0.1949700266, 1.0104807615, -0.7675292492, 0.1056777388, 0.4347531796, 0.7299080491, -0.7642510533, -0.0106105693, + -0.2643010318, -1.8072508574, 1.3940663338, 0.3064333797, 0.4452610612, 0.6079790592, 0.3127636611, 0.5288425088, + 0.0853652284, 0.1245446801, -1.2992873192, -1.6149802208, -1.0670560598, -0.6736964583, 0.692974627, -0.7262415886, + 0.9602357745, -1.0777587891, -0.2623558342, 0.214811489, 0.8735753298, 0.0214401037, -1.0976064205, -0.4945487976, + 0.7895449996, 0.2681889236, 0.7866907716, 1.1217195988, -0.0987510309, 0.4238417447, 0.6273287535, 0.4225327671, + -0.8348941207, 1.6016408205, 1.5246837139, 1.499286294, 1.3512203693, 0.9674935341, 0.0298249535, 1.2098042965, + 0.8318428993, -0.2006926239, -1.1404662132, -1.2379252911, -0.3444960713, -0.5028432012, 1.110363245, 0.7753596306, + -0.6887470484, -0.8987953067, -0.0610145554, 1.9189139605, -0.1576679349, 0.0352119133, -1.6327770948, -0.4427270293, + 0.7562611103, -0.2466283292, -0.0400478803, 0.9635592699, 0.5934650302, -0.8815698624, -1.0712459087, -0.6394456029, + 2.0791168213, -1.5084906816, 0.1330436021, 0.5975986123, 0.3697303534, -0.6510151029, -1.2109297514, -1.4117516279, + 0.4338284135, -0.0864954367, 0.0024174221, 0.9538350105, -0.4261922538, 0.4513969421, 1.9549031258, -1.6480233669, + -1.2982463837, 1.685872674, -0.8666954041, -0.3963478506, -0.83705616, -0.6677888036, -0.080201447, -0.9439086914, + -0.4302936494, -0.654969573, 0.219273448, 1.8352367878, 1.7390035391, -0.4004605711, 0.320004344, -0.2482670993, + 0.8343432546, 0.901057601, -0.6557250619, -0.3174437582, -1.4815505743, 0.3341366053, 1.3810726404, 0.3408678174, + 0.2780138254, 0.4463123679, -1.0640423298, 0.5948966742, 0.9701595902, -0.3354811668, 2.1228146553, -0.3853601515, + 0.8973402977, -1.6078014374, 0.4986139536, 1.5752862692, 1.0740270615, 0.5252494216, -0.9065878987, -0.3239499032, + -0.8208144307, 1.425224185, 0.7748389244, 1.6811554432, -0.4814466238, -0.4224803448, 0.3014148474, -0.488743186, + 0.5419479012, -0.2225292623, 0.3341558278, 1.3281743526, -0.7061454058, 1.1406314373, 1.7456609011, -0.3581234515, + 1.8958735466, -0.9984493256, 0.9563930035, -0.5737659335, 0.8312965035, -1.046071291, 0.2084058076, -1.1228160858, + -0.3064347208, 0.0921172574, -0.1723273247, 0.2616755962, 1.8572127819, 1.2639824152, 0.0297166966, 0.7248386741, + -1.0261186361, 0.6415510178, 0.5504319668, 0.0855867118, -0.2484924197, 1.094758749, 0.6734647751, 0.0738114491, + -0.6452680826, 1.9789581299, 0.3102551699, -1.3629002571, 0.0274566971, -0.0190395452, 0.2973560095, 0.1557310671, + -0.1468652487, 1.421604991, -1.3144340515, 0.8182174563, 1.2978197336, 0.6167443395, 0.2798875868, -1.1098065376, + -0.4280781448, 0.2754967213, -0.083178848, -0.6103398204, 0.4578257203, 0.8553571105, -0.5358012319, -0.1420752406, + 0.3383913934, -1.3604153395, 1.0594539642, 0.6419425011, 0.3380404115, 1.0207705498, 0.6028524637, -1.0487345457, + 0.3747584224, -0.9873114228, 0.5715779662, 0.8900516033, -0.3863794208, -0.3268699944, 1.1698690653, 0.8926932216, + 0.2617246211, 0.1278757006, -0.8974625468, -0.4251092672, 0.7840434313, 0.2114642859, -0.4872782528, 1.1878559589, + -0.0447122194, -1.631295681, 0.9626309872, 1.5028502941, -1.1069815159, 0.5493133068, -0.0670908988, -0.9915824533, + -0.5925250053, -0.9678844213, 0.6036627889, -0.1400649548, -0.9178651571, -0.0356261842, 1.515106678, -0.1383053213, + -0.3510780334, -0.4292304814, -0.5429307818, -1.5706568956, 0.1042975038, 0.7102490067, 1.855237484, 0.3347614706, + -0.7081097364, 1.1634874344, 2.103618145, -0.7794679403, -0.5313645601, -2.0222191811, -0.6882897019, 1.2757804394, + 0.9143882394, -0.778015852, 1.6167298555, 1.092515707, 0.7997589111, -1.658087492, -0.3671254814, -0.1214561462, + 0.533323288, 1.8171951771, -0.5902642608, -0.7296072245, 1.4643578529, 0.6638869047, -0.5257128477, -0.1212170571, + -0.9509884119, -0.6017122865, -0.3032298088, 0.3008897901, 1.7487587929, -1.471619606, -0.4065019786, 0.1656065583, + -1.1072632074, 0.7372105122, -1.1134939194, 0.6655398607, 0.5232836604, -1.3998881578, -0.2136789113, -0.316932857, + -1.0540878773, 0.0523890071, -0.3415353894, 0.2425192446, 0.2672145963, -1.0849430561, 0.1197969317, 1.6511855125, + 0.8567194939, -0.4198167622, -0.006153075, -0.2666466236, -2.3022949696, -0.1626988351, -1.1963500977, 0.0330941156, + -0.2138646841, -1.1792644262, -0.8235653639, -0.573800981, -2.5206964016, 0.9328417182, 1.1077494621, -0.1811641604, + 0.245924592, -1.6585836411, -0.5189835429, -0.2116440684, -1.9794597626, -0.3549507856, -1.1766176224, -0.1413746923, + -0.9840304852, 0.2118366063, 0.1956791133, 0.0256031454, -1.7828342915, -0.9711146951, 0.9384088516, -0.9248518944, + -0.1011454016, 0.3087741137, -0.8797972202, 0.3986951411, -1.6176860332, 1.1128709316, -2.2385592461, 0.6260812283, + 0.1871027201, -0.025499925, 0.3770545125, 0.3706595004, -1.7061337233, 0.35559389, 0.3026677072, 2.3950519562, + -0.847720325, -0.2803919017, -0.5236788392, 1.4797307253, -0.2061602622, -1.2524269819, -0.4490454495, 0.3581798375, + 0.4895872772, 1.5629991293, 0.832724154, -0.3907397389, -0.653103888, -1.06582582, 0.8748501539, -0.7687430978, + -0.7552185655, -1.2149530649, 1.1354509592, 1.5423836708, -0.5928421021, -0.6696397662, -0.8266085982, 0.5995821953, + 1.6138184071, -0.3615201712, -0.8327620029, 0.4664305151, 0.9396260381, -0.6726012826, -0.3961285055, 1.1466346979, + -1.1610549688, -0.3767644167, 1.1379449368, 0.1347682774, -0.0495987386, 1.2985827923, -0.7667092681, -0.2375340462, + -0.7819229364, 0.4346813858, 0.9445708394, -0.5190451145, 0.922860086, -2.0988132954, -0.2211748511, 0.091524072, + 0.5281891823, 0.573053658, 0.3545318246, 0.9084903002, 0.7303026915, -0.6365323067, -0.2045491636, 1.2701267004, + 0.0289865974, -0.0711520687, 1.9361691475, 0.1886532605, 1.2679781914, 0.706278801, 0.216896832, -0.2863503993, + 0.2347160429, -0.6281237602, 0.0405537225, -0.2235246599, -0.2665000856, -0.8118832111, 1.4879057407, 0.3624395132, + -0.2154130787, -0.6729236245, -0.9089426398, -0.1334685832, -0.1044594646, -0.6322259903, -1.7956866026, 0.1443674415, + 1.1078892946, 0.1278653294, -1.4188404083, -0.8868185282, -0.375521034, 0.6156448722, 0.2973950207, -0.3261060119, + 0.3075840473, -1.0595344305, 0.6999576688, -0.1738804132, 1.1124271154, 0.0801854208, 0.5716896653, -1.0374674797, + -0.0721909776, 1.9828381538, -1.3460509777, -0.5868654251, 2.1197776794, -0.8811689019, -0.5918867588, 1.3096985817, + 0.5816102028, 0.6569513679, 2.4478139877, 0.0861110836, 0.5811345577, 0.4229134023, -0.3605940342, 1.5369105339, + 0.4504128993, 0.3325541914, -2.6560053825, 0.0780802891, -0.5812519193, -0.1294345409, 0.2331547439, 0.5030118823, + 0.5096856356, 1.6935214996, -0.5959262252, 0.230514124, 1.0273890495, 0.2305488288, 0.8759493828, -1.8008491993, + -0.7317401171, 1.7506126165, 0.4269411564, -0.0429548435, -0.1476143003, -0.2250723988, 1.7548139095, 1.69873631, + 0.4552177787, 1.5571171045, 0.6796240807, 0.2440751046, 1.0473498106, 0.5143606067, 1.4031444788, -1.2559754848, + 2.0805716515, -0.0157355964, 0.3213089406, -0.2585878968, -0.9314686656, -0.2365136594, -0.592073977, -1.4044491053, + 0.3690233231, -0.7666178346, -0.3709909916, 0.2319030166, -0.9386507273, -1.5684202909, -0.9699392319, -0.163621366, + 0.1689850539, 0.2926900685, -0.6215610504, 1.4952127934, 0.7245684266, 0.4298216999, -0.6791428924, -1.4297268391, + 0.224003762, 0.8946802616, -0.6121846437, -1.0005315542, -0.9501293302, -0.2909827232, -0.5344090462, 2.3198983669, + -2.2879838943, -0.9288844466, -0.003408117, 1.0812544823, -0.8310899734, 0.8552720547, -1.0219707489, 0.2177965343, + -0.973344028, -0.0174913909, 0.4193081558, -0.3332124054, 0.4880933762, -1.5816885233, -1.4639986753, -0.6394988298, + 0.2832532227, 0.1952934414, -0.8858428001, -2.3023381233, 0.0895171762, 1.8412590027, -1.1203542948, -0.8483638763, + 0.2196273506, 0.3113439679, 0.1000621319, 1.1735875607, -0.8860414624, -0.8599038124, -0.6715561748, 0.1867471635, + -0.2337619066, -1.1266306639, 0.9036043286, -0.9000715017, -2.0205488205, -0.9581099749, 0.7905055285, -1.2348706722, + 0.4671658576, 0.4668186605, 0.3785419464, -0.0996996388, -0.1534485519, 0.4217807949, -0.4923402369, -1.4948923588, + -0.1059649363, -1.4504761696, -1.2151101828, -1.5624502897, -1.6301554441, -1.0333613157, -0.6717498302, 0.1625663489, + -0.9796378016, 0.2504408658, -0.4498012662, -1.3315489292, 0.5227864385, -0.4967396855, -0.7746353149, -3.2565047741, + -0.7625097036, -0.2435188144, -1.6264389753, 0.2406946421, 0.375044167, -0.5929222703, -1.793833375, -1.2085139751, + 0.0064371475, -1.7667037249, 1.7038869858, 0.4753684402, 0.5051966906, -0.2259977311, 1.6209121943, -0.4586403966, + 0.4619432092, 0.7081202269, -0.1198732406, -1.904065609, 2.5461783409, -0.5098463893, -0.5149093866, -0.6470791101, + 0.059874475, -0.0804928392, -1.1862183809, 0.7540088892, 0.5231956244, -0.7941627502, -0.5351686478, 0.1464129686, + -3.2503798008, -0.9900084138, 0.0208800603, -0.0939341038, -0.7024986148, -1.4116461277, 3.3354561329, -1.6807198524, + 0.7628878951, -1.1663935184, -0.9231708646, 0.5788217187, -1.5420737267, 0.3719091415, 0.4810803533, 1.2950202227, + 1.1624336243, 1.7827768326, 1.2083466053, 2.1456758976, 0.0785913095, -0.7186422348, -2.0778264999, -0.7815722823, + 0.255487144, -0.2430197746, 0.3738383651, -0.1691911221, -1.5751345158, -0.6850867271, 0.9226065278, -0.4163829684, + 0.2016043663, 0.243060559, -2.0118079185, 0.6240944266, 0.4783047438, -0.2266190797, -0.0495828427, 1.2547620535, + -0.7426257133, 0.0852039978, -0.3938572705, 0.3231543005, -1.2266924381, -0.7905484438, 0.7264937758, -0.143662408, + 0.6927309632, -0.179950282, 0.7293747663, 0.2032651603, 0.9094336629, -0.4490212798, -0.5067827702, 0.2291303724, + 1.01742661, -0.5093548894, -1.4442439079, 2.3562941551, 1.0144230127, 0.820512414, -0.3604024351, 0.5040035844, + -0.0327425338, -0.9325399995, 0.7155613899, 0.1095617339, -1.8171060085, 0.126147747, 0.8790358305, 0.9427734017, + 0.8065360188, 0.9868785143, -0.6248038411, 1.1574034691, -0.4969314933, -0.9548960328, 0.2056397945, 0.6338357329, + 0.7086056471, 0.3203323781, -2.4203219414, 0.591522634, 0.7968711853, -0.754875958, -0.781793654, 1.4170876741, + -0.5229552388, -0.2530987263, 0.1287870258, 0.1348793209, 0.3662788272, 0.9481594563, 1.551836729, -0.1748871803, + 1.5927872658, -0.5910189748, -0.2056038827, 1.4960036278, 1.5196142197, 0.669852078, -1.1990022659, 0.443354696, + -0.9905802011, -0.8024225235, -0.3416491747, -0.1046441644, -1.0017228127, 0.485733062, 0.3659887016, 0.1782243699, + 2.0004279613, 1.5760009289, 1.3417978287, 1.2599104643, -0.5527366996, 2.0692360401, 0.4941767156, 2.0470237732, + -1.0875812769, 0.7576946616, 1.7907387018, -2.9291129112, 0.8575381637, -1.3554950953, -0.483921051, -0.0655705929, + -1.1057314873, -1.3319424391, 1.8408344984, -1.6634352207, -0.4494746327, -0.1036276221, -0.6675081253, -0.560828805, + 0.0666391999, -0.5574812889, 0.2405882627, 1.4979455471, -0.3060584068, 0.0120285843, 1.6143784523, 1.1359167099, + -0.9106744528, 1.2418780327, -0.9291626811, -1.9791833162, -0.9713079333, 0.3243151903, -1.4647428989, -1.2395029068, + 0.0382350758, 0.8031321168, -0.8530051112, 0.4882732034, 0.8558873534, 0.646030426, -0.5682061315, -0.9189545512, + 0.8990505934, 1.2603000402, -1.0781060457, -0.7336502671, 0.8740951419, 0.7658302784, -0.223807022, 0.6157169938, + 0.6769030094, 1.2593274117, -1.8752324581, -0.0772253424, -0.2439778447, 1.860568881, 0.3804485798, -1.8733338118, + -0.5691103339, 0.5537204742, -0.6699575186, 0.4479410946, 1.0299412012, 0.7603972554, -0.4966503382, 0.3634217978, + 0.8501811028, 1.6847851276, -1.21448946, -1.4988577366, -1.1940227747, -0.5858005285, 0.6833459735, 0.4837764502, + 0.8482929468, 0.9312326312, 0.5123922825, -0.9934224486, 0.7389886379, 1.5904425383, 0.1515328288, 1.8001233339, + -0.5165967941, 0.6810074449, 1.1736761332, 0.4009504914, -0.1953288466, 0.5581561327, 0.1997068077, 2.1620819569, + -0.0908827558, 1.0417481661, 1.6549855471, -0.7760302424, -0.3316659927, -0.211549595, 0.5966792107, -1.088747263, + 0.2982098758, 1.5184670687, 0.4310917556, -1.4303095341, -1.6879490614, -0.5256771445, 2.3723435402, -1.1201488972, + -1.6246181726, -0.7182115316, 2.2989356518, -0.7916751504, -0.1085834578, -0.0711057559, 0.3724485934, 0.3015347719, + 0.2816698551, -0.5369709134, -0.7400909066, -0.4385055602, 0.4664757252, 0.7917868495, -0.0000355124, -1.0004467964, + 2.1101815701, 0.9932739139, 0.8110388517, 1.0303093195, 2.1443128586, 0.2792387009, 0.8437840939, 1.1218912601, + -1.391854167, 0.4506911635, -2.0793647766, -0.012149794, -1.0440405607, -0.9657757878, -0.508748889, -0.0789047405, + 1.4459255934, -1.5358483791, -0.4629052877, -0.3632760942, -1.0295374393, 0.1215865463, -1.599029541, 0.93786937, + -1.1836384535, -1.063141942, 0.6355529428, -2.4377219677, -0.090441972, -0.4806424975, 0.2118658572, 0.4217100441, + 0.1558341831, -0.9841300845, -2.7493028641, 0.9413385987, 0.3539286554, 0.6233276129, -0.9138478041, -0.5024273396, + -1.6548289061, 1.0006732941, 1.9455966949, 0.093309775, -0.1363495439, 0.0907459259, 0.0056755515, 0.3079532683, + 0.9652287364, -1.1859726906, 2.0238280296, 0.278157711, 0.5562726259, 0.759162128, -0.1311170906, 0.9709328413, + -0.8000256419, -0.3964389563, 0.3583988249, -1.2603985071, -0.6288074255, 0.199747622, 1.5333764553, -0.9561508894, + -1.1526873112, -2.0702159405, 0.2626678348, 2.6558797359, 0.305796802, -0.0556512699, 0.4347166121, -0.25246647, + 0.5330020189, 2.1679821014, -0.0680899248, 0.0938287526, 0.3151662648, 1.317794919, 0.2194497287, 1.4449121952, + -0.203034386, 0.3360009193, -0.9564311504, -0.8714737892, 1.4866508245, 0.6670100093, 1.0294823647, -0.806984961, + 0.7517868876, 0.6363819838, -0.2490818948, -0.2208531499, -0.7862807512, -0.0412395597, 1.8023437262, 0.889354229, + 0.8283433318, 1.1427662373, 1.099064827, -0.138019979, 0.0603353344, -0.6218895912, 0.6183639169, 1.6191837788, + -0.2276409566, -1.7644103765, -1.5434100628, 0.5247124434, 0.5242751837, 0.7079523802, 0.1106121019, -0.4096989632, + -0.9592539668, 1.7692834139, -0.439075917, 0.9115946293, 3.0482261181, -0.08877334, 0.4471243024, 0.1182788983, + -0.0481228195, 0.2647619545, 0.1651706994, -1.0986613035, -0.2626098692, 0.8710223436, 0.2023158371, 0.0185922198, + -1.6146917343, -0.7584802508, -1.8991247416, 0.1000484303, 0.0444046557, -1.0100754499, 2.0759148598, 0.6520631909, + 2.0937871933, -0.1748518348, -0.0945110694, 1.4562783241, -0.3171853125, -1.3235573769, -1.0152374506, -1.1026420593, + 0.2675947845, 0.6974791884, -1.4816414118, -0.5089939237, 0.8205317855, -0.6032758355, 1.1610811949, 0.2848510146, + -0.2113544494, -0.069358483, 0.460162729, 0.2715222836, 0.3543163836, 1.1241178513, -1.0009111166, 0.4233255386, + 0.8821615577, -1.2673573494, 1.0599933863, -1.9858329296, 1.747335434, -0.8925181627, -1.5392049551, 0.3679618537, + -0.9061989188, 1.6234297752, 0.3026809692, -1.252163887, -0.9746393561, -1.6885068417, 0.1270830184, -1.179715991, + -0.1793961972, -1.6843693256, 1.1783792973, 1.2475259304, -0.2204871029, 0.7822663784, -0.7288885713, 0.5897322297, + 1.589458704, -2.0798897743, -0.9088625312, 1.0042586327, -0.4040690362, 1.0435874462, 1.0213680267, -0.5034691691, + -2.8381204605, 0.5957017541, -1.7376792431, -0.3987622857, -0.5514874458, -0.3678982854, -0.1919072121, 0.9552351236, + -0.2671971619, -0.7120574117, 0.7922269106, 0.782146275, -0.8510670066, 0.4528163671, -2.8724989891, -1.7404062748, + -0.035872668, -1.0349525213, 0.9958155155, 0.7042294741, 1.8772702217, 1.2644282579, 0.5117878914, -0.7683165669, + -0.3760642409, 0.3992835879, -0.6319594383, -0.123412475, 1.3657724857, -0.4243614376, 0.3409079909, 0.8824703693, + 0.3096629381, 1.1415899992, -0.360165149, -0.4110813737, 1.4603716135, 0.2897032797, -0.6120595336, -0.687793076, + -0.0798668489, -0.9543554783, 1.1657077074, -0.7224388719, 0.5840330124, -0.4707277417, 0.9872319698, -2.450650692, + 0.0268113595, -0.4014832675, -0.9910459518, 1.8364913464, -0.1808601767, -0.6913096905, -0.4763865769, -0.8570129275, + 0.6800124645, 0.2375830114, 0.299380213, 0.6163609624, 1.0929050446, -1.2402175665, -0.9390913844, -1.3111484051, + 1.508805871, 1.3480857611, 0.501648128, -0.2476610988, 0.7036614418, -0.0966909081, 1.3176031113, 1.0656447411, + 0.2396778166, -1.9526786804, 0.8595772386, -0.2595057487, 0.9080550671, 0.0765460432, 2.1173491478, -1.0088042021, + -1.7454794645, 1.2033076286, 0.4952604175, 0.1535671651, 1.004206419, -0.2208959013, 0.5841389298, -0.3922788501, + -0.3614006042, -1.8522236347, 0.2663365901, -0.4901424944, -0.7449171543, -0.3399548233, -0.3400003314, 1.3681870699, + 1.0906018019, 1.064904809, 1.2599071264, -0.1997389942, -1.5190547705, 0.978467226, -0.8858841658, -0.7331888676, + 1.7371307611, -0.9528511167, 1.2391638756, -0.6803607941, -0.8854863644, 0.5288819075, 0.0407255515, -1.7051877975, + -1.1911907196, -0.6170998812, 1.8401297331, 1.2869774103, 0.7416225672, 0.1012784541, 0.950671494, -0.6890847683, + 1.1691758633, 0.2125397325, -0.5651474595, 1.1363813877, 0.3282095492, 0.2325947732, 0.8333733678, -0.3224644661, + -0.043505419, 0.8779395223, -0.1092095077, -1.3758436441, -0.8854057789, -2.187015295, 1.4359880686, -0.5213032365, + 0.3130353987, -0.3004281521, 1.5077716112, 0.7161954641, 0.4850605428, -1.3312293291, 0.1999393255, 0.7143920064, + -0.2711220086, 1.047033906, -0.5351563096, 2.1122450829, 2.2901554108, 0.1676862389, -0.3756659031, 0.2262535393, + -0.4149861634, 0.7650973797, -0.7531386018, 1.2070817947, 1.2787936926, 0.1595245451, 0.1642178148, 0.2609710991, + -0.7997441292, -0.1890465617, 0.4980888069, -0.8788653612, -1.492616415, 0.284234941, 0.1910644174, 1.9113937616, + 1.113723278, 1.0943866968, 0.9748689532, 0.8634682298, -0.2590862811, -0.0192987844, -0.8789740801, -0.791351676, + 0.6180747747, -0.7121517062, 0.3878835738, -1.3793500662, -0.1918176562, 0.0958151296, 3.109470129, 0.3986200392, + 0.2136057466, 1.1821939945, -1.1471401453, 0.8588299155, -2.0046691895, -0.1928652674, -0.6466591358, 0.0150989927, + -1.0306770802, 0.9040096998, -2.1417479515, -2.7447814941, -1.1748067141, 0.5511487126, 0.0278319884, 0.3978701234, + -0.4533764422, 0.6338236332, 0.2078187764, 0.6372888684, -0.6748731136, -0.1286127865, -0.5645707846, 0.4383159578, + -0.7623828053, 0.79043293, -0.1006841809, -0.4627493024, 1.0368299484, 0.4300449491, -1.7973104715, 0.7144021392, + -0.4045287371, -0.8542004824, -1.1299022436, 0.7849571109, 1.1772171259, -0.8059206009, -1.138379693, 0.4343900383, + -0.2633340955, -0.4062776566, 0.1033182815, -0.5581795573, -0.0883774608, 1.0320638418, 1.4132361412, 1.6514214277, + 0.1695428044, 0.2159408629, 0.8343988657, -1.1636316776, 1.0585942268, -0.1515603811, 0.8289833069, -0.0556437746, + -1.2486417294, -0.3393330276, -0.3956955671, -0.1733885854, -0.6103331447, -1.6589229107, -1.3826439381, 0.8436100483, + 1.1876813173, -0.5175749063, -1.0741704702, -0.2104587704, 0.8762942553, -1.0773400068, -0.2500136793, 1.3766224384, + -0.4211629629, 1.6774389744, 0.4335694313, 0.1595920026, 0.741537869, 0.6724870205, 0.3878264725, -2.0489420891, + 0.8812448382, 0.1120989919, -2.1312644482, -0.3068031967, 1.4072669744, -1.8038721085, -1.9736406803, 0.0415054634, + -0.0308436342, 0.9076535702, 0.3400208652, -2.2132844925, 2.3224930763, 1.3219075203, 2.3032946587, 0.610896647, + -0.1145442501, -1.5732045174, 1.1812853813, 0.2263955772, 0.4435280859, -0.4413294494, -0.219157666, -0.4763602614, + -1.1287884712, 0.9238072634, -0.2126406729, -1.4508607388, -1.0319195986, 0.1644870937, -1.5002006292, -1.2616881132, + -1.5085011721, 0.1622222662, 0.4869650006, 0.5460504889, 0.1898836493, 2.0961461067, -0.3474938273, 1.862806201, + -1.1646004915, -0.9452017546, -0.5434473753, 0.2812504768, -0.5410401821, 1.7726508379, 0.5803670883, 1.0367780924, + -1.6005064249, -3.0092163086, 0.139212504, 2.4194037914, 0.3260611594, -0.9767702222, 0.5747098327, 0.1420334429, + 0.2335471809, -0.0718801618, 1.0421361923, 0.5592299104, 0.5113453269, 0.2498618364, -0.9558623433, -0.3218068182, + -0.1402815431, -1.6505886316, 0.083599478, 0.9163863063, -2.8156573772, -0.7224086523, -0.2607764006, -0.7745448351, + 0.783949554, -0.7016636133, -1.2114204168, -1.393553853, -0.1395538896, -0.5087388754, 0.8473874331, 1.3882595301, + 2.1699202061, -0.2208291292, -0.3559795022, -0.7718069553, 1.0199204683, -1.1986038685, 1.2818330526, -0.8575738668, + 0.7588049769, -0.3571656942, -0.8376092315, -0.1244146153, 1.022251606, -0.2545220852, 1.8373160362, -1.4680243731, + 1.333676219, 0.2705392838, -0.7611726522, 0.6549308896, -0.0792744756, 0.9494455457, 1.1246320009, 0.0557211973, + 0.8274643421, -0.0141875586, -0.4157760143, -0.2442740798, -0.1689703465, -1.4288641214, 0.2172202319, 0.7753660679, + 0.6355167031, -0.6720003486, -3.3398942947, -0.3721321821, 0.7748588324, 0.2912347913, -0.0677062869, 0.2498321682, + -2.0455522537, 0.359957546, 0.8134485483, -0.7892555594, -0.9455010891, -2.1506998539, -1.1472947598, 1.6073971987, + 0.3767109215, -1.2686046362, -0.3529419899, 2.0551450253, 0.9534871578, -0.3973580897, -1.4923707247, -0.5456050038, + 0.0431090258, -0.275804311, -0.2455203533, 2.1469547749, -0.9647199512, -2.1054956913, -1.6152031422, 0.6804012656, + 0.7725505233, 0.663980186, -0.5187103152, -0.65980196, -1.04910779, -1.5657329559, 0.5533331037, 1.2845594883, + 1.1052020788, 0.9238629341, -0.4194052517, 0.5052201748, 0.6276740432, 0.4903647304, 0.5449354053, 0.8436488509, + 0.5930407643, -1.233761549, -0.7152583599, -0.7161428332, -0.5219246745, 1.1452192068, 0.6020815969, -0.6623034477, + -0.3540771306, 0.2188376784, 0.2990494668, -0.3308923244, 0.3350869715, -0.0748877674, -0.0690385029, 1.8809734583, + -0.6586229801, 0.3756047189, 0.4063786864, 0.9886311293, -0.9031563401, -1.2128840685, -0.5440398455, 0.8093140125, + 0.114167653, -0.3551281095, -1.1269905567, -1.5992106199, -1.0362365246, -0.380224973, -0.0893609747, -1.0580019951, + 1.293392539, -1.9946708679, -0.784427762, 1.2969027758, 0.4970777929, 0.8003904223, 0.230045706, 1.2736281157, + -1.0021532774, 0.4828888178, -0.1670626998, -1.8273473978, 0.234064132, -0.6276967525, -1.6696863174, 0.004874907, + 0.9814209938, 0.6604838967, -0.558742404, -0.5823022723, 0.1978456527, 0.8078650832, 0.8510124087, -0.6664382815, + 0.8562269807, -0.6985203028, -0.3025896847, -0.7559245229, -1.0003705025, 1.5326434374, -0.0137318987, -0.6858326793, + -0.3156582415, 0.416240871, -0.6101112366, 0.4867403209, -0.3826802969, -1.2199368477, -0.4200175107, 1.0042294264, + 0.3964896202, -2.3662467003, 0.9675166011, -0.3118633628, 0.0873739272, -0.4918978512, 0.6635258794, 0.3169205189, + -0.3862748146, -0.7754532695, 0.7976115346, -0.9872649908, -0.9692402482, -0.2291807681, -0.7056533694, 1.3953976631, + 0.3147648871, 0.4875667989, 0.6540688276, -0.9398791194, 0.7224289179, 1.177734971, -0.991512239, 0.9375629425, + -0.5861776471, 0.4290914237, -0.8124514222, -0.2063853294, -0.9410168529, -1.1546858549, -0.1660162508, -0.2981323004, + 1.5257365704, -0.688704133, 0.4322051406, 0.0187902357, 0.3851979673, -1.5070592165, -0.0877329856, 1.6083472967, + -0.7919498086, 1.7719179392, -0.500854671, -0.7702132463, 1.5552997589, 0.0259561371, 1.3426429033, 0.017033549, + 0.5972861052, -0.3192002177, 0.6835110784, 0.457285136, 1.8811956644, -2.5470488071, -0.4798873067, -0.4972526431, + -0.489233166, -0.717247963, -0.0641170889, -0.0721785799, -2.2250163555, -0.7003098726, -0.9463029504, 0.5387721658, + 0.1171965152, 0.7794079781, 0.987354815, -1.2788540125, 2.0102021694, 0.1099134684, -1.4208669662, 0.1849313974, + -0.2944383323, 1.1591405869, -0.2540302277, 0.5338650346, 2.5842995644, 0.4451530874, -0.3505676389, -0.1859664619, + -0.1787521392, -0.0542083494, 1.6706476212, 0.9630910754, 0.639138639, 1.644287467, 0.0071885237, -0.5470194221, + -0.0029828497, -0.0276721809, -1.6777534485, -0.8231400847, -1.2297281027, -0.7362014651, 1.1312052011, -0.3959090114, + 0.292863965, 0.0256736502, -0.9436841011, -0.8668084145, 0.1719511896, 1.7600250244, -0.3097595572, -0.7261739969, + -0.0894311666, 2.0879607201, -1.082729578, 1.1696344614, -1.8928852081, -1.40667665, -1.6461080313, 0.0934822261, + -0.0529018976, 0.1754294932, -0.4250826538, -1.6005401611, 0.2298563123, -0.502617836, 1.5759580135, 1.0479354858, + -1.3923493624, 1.5411509275, 0.5450043082, -1.5957812071, 0.0078355968, -1.0235074759, 1.4455271959, 0.2516079247, + -0.0059909956, 0.5103890896, 0.6152398586, -0.1133571044, 0.0452356748, 0.8750831485, -1.550822258, -0.8830829859, + 0.2080126405, 0.0176873859, 0.0009350795, 0.3643147647, -0.3425868452, -1.1389331818, 0.267998904, -0.2351417392, + -0.3743028641, -0.2967391312, -0.3949703872, -1.2074548006, -1.5331141949, 1.0537494421, -0.6973699331, -0.3979943097, + 0.9710779786, 0.148633182, 0.7276759148, -0.3589974344, 0.1361308545, 0.5942563415, -1.1173524857, 0.1162814796, + 0.170878768, -0.9081650972, -1.2323310375, -0.2043872625, -0.9505392313, -1.720944643, 0.0769074261, 0.3739518523, + -0.955945611, 0.6215204597, 0.5835911036, 2.1823852062, -1.1971487999, 0.4832358956, 0.6317840815, -0.8399761319, + -0.8457883, -0.2453269064, -1.3662616014, 0.225995481, -0.871108532, -1.0088886023, -0.079512246, -0.2749667168, + -1.4504717588, -1.1735156775, -0.1123355925, -1.2269114256, -0.8250812888, 0.0331604481, 1.8441269398, 0.6902368665, + 0.6502194405, 0.4802848697, -0.4361600578, -1.9481081963, -0.9514036179, -1.0143113136, 0.4540541172, -1.0325177908, + -0.1135502532, 0.8384748101, -0.1321249306, -1.8348624706, -0.9096595049, -0.0661195368, -1.1773709059, -0.2655218244, + -1.0226361752, 1.7931406498, -0.5638654232, -0.8700715899, 0.1031277925, -0.3818658292, 0.9453787804, 0.2722228169, + -0.4883063138, -0.7425808311, 0.3954738379, 3.5413982868, 1.1422576904, -0.117706567, -1.3207576275, -0.4200673103, + -0.9338312745, 0.4874849916, -0.7146152854, 0.5772513151, -0.251796931, -0.5349732637, 0.9662621617, -0.63987571, + -0.2928552926, 0.3574216366, -1.0193123817, -0.5647442937, 1.3439898491, 0.9467440844, -1.8994320631, -2.3763782978, + -0.0155165065, 0.9333648086, 1.2560585737, -0.5713263154, -1.1139186621, -0.6125965118, -1.5679283142, 2.054902792, + -0.7713843584, -0.5557987094, -0.5585767031, 0.1265952587, 0.949757576, -1.6862744093, 0.4159049392, 1.6351566315, + -1.099609971, 0.1305427402, 0.2132267654, 0.2193509191, 0.117114678, -2.9186856747, -1.6857429743, 1.2380404472, + 0.1488410085, -0.562833786, 1.2209196091, -1.0582157373, -0.4046570361, 0.1282916665, -0.8336083293, 0.6628674865, + -0.6343099475, 0.4895289838, -1.5728354454, 0.117427364, -1.0989309549, 0.762387991, 0.636485219, -1.3394111395, + -0.9577367902, 1.2531023026, -0.0068191397, -1.0997195244, 0.5822053552, -0.8811379671, -0.9198532104, -0.0741320997, + 0.0454016849, 0.2210511118, -0.3389450312, 0.2945863605, 1.6904438734, 0.2295662761, 0.3174210787, 0.8400560617, + -0.5025610328, 0.4230135083, 2.0097754002, -0.6062899828, -1.3862564564, -1.6698477268, 0.5712623, 0.1846959591, + 1.3817620277, -0.4764849842, 0.065992929, 0.3075664937, 2.1360414028, -0.3807438016, -0.2041121721, 0.4065637887, + -1.411706686, -0.2051517218, 0.6111496091, -0.4619669914, -0.3576725721, 0.0207850803, 0.5707749128, -0.5527526736, + -0.1327189803, 1.0202493668, 0.6725012064, -0.1995927095, 0.4116949141, 1.3201146126, -0.8511425257, -0.4216827452, + 1.098500967, 0.5239596367, 1.673864603, 1.0952597857, -0.4176313579, 0.6746681929, 2.045994997, 0.9361134768, + 0.5849192739, -0.8187872171, -0.8112853765, 0.6149257421, -0.0066334433, -0.8003438115, 0.0657561496, 0.3939533532, + 0.1361585706, -1.2089350224, -0.2615604103, 0.9463102221, -1.806142807, 1.6406424046, 1.3682647943, 0.6324747801, + 2.7865254879, -1.130330205, 0.3894205093, -0.0782135278, -1.0114086866, -0.6274721026, 0.5245721936, -1.5063163042, + -1.9922429323, 0.3584777415, 0.516646862, -0.1857368648, -0.8542599678, -0.9650046229, 0.423440814, -0.3074883819, + -1.7931255102, -1.5989216566, -0.3567943275, 1.4546153545, 0.6844121814, 0.5107967257, -0.0391141847, -1.4022755623, + 0.394605428, 0.6230074763, 0.357550025, 0.6456065774, -0.8244645596, 1.6284826994, 1.3106117249, 0.542526722, + -0.046828106, -0.1053166837, 1.5829575062, 2.1437420845, -2.6331455708, -0.8834359646, -0.0580697283, -0.2573893964, + -1.0412811041, -0.9003218412, -2.2390277386, -1.465110898, -0.1499534696, 0.3560865223, -0.8711300492, 0.4428383112, + -0.7426754832, 1.9199404716, -0.1389176399, 0.8840380907, -0.084664546, 1.1519436836, 0.6512896419, 0.4417738318, + 0.5237726569, -0.0788306445, -1.0378000736, -0.0144220442, 3.2748272419, -0.4563313723, 0.181278035, 1.0921074152, + -1.0814076662, -0.7821266651, -0.3949780762, -0.3073712885, -0.4651679397, -0.1078325585, 0.8263167739, 1.2388310432, + -0.0984496921, -0.9567881227, -0.2131212503, 0.4681727588, -0.8755455017, -0.3477372825, -0.3609948754, 0.2883796096, + -0.1543822289, 1.0686825514, -1.2054982185, -0.2616977692, -0.2440364957, 0.3487615287, 0.359159708, 0.8647454381, + 0.0454029441, 1.3971421719, 0.4091089666, -1.137470603, 0.3737558722, 0.0758722574, -1.3365100622, 0.325042963, + -2.3053030968, -0.0668937638, -1.0083193779, -0.7527424097, -0.0073583261, 0.4523725808, 1.3834358454, 1.5274974108, + 0.5206997395, -0.1829435676, 1.9268072844, 1.704174757, 1.2395449877, 0.8001048565, -0.6456826329, 0.1719383746, + -1.1980223656, 0.1657909304, -0.3878783286, 0.186910674, -0.5592908263, -0.5458331704, -0.7450099587, -0.0316931196, + -0.0618060678, 0.3835448027, 0.4217584133, 1.1206994057, -0.4465995431, 1.7511516809, 1.3176025152, -1.5822561979, + 1.2087854147, -0.0655139759, -0.271492064, -1.017285347, 0.888584137, 0.60892874, 0.7097648382, -1.0400695801, + 0.756069243, -0.152736038, -0.0720087662, 2.0048029423, 0.9776907563, 1.8429362774, 0.5951318145, 0.9638172984, + -1.4097329378, 0.9143978953, -0.6318609118, 0.3108898103, -1.0307670832, 1.5938689709, 0.1314638257, 0.1371712685, + 2.2998940945, -1.1544933319, 0.9436885715, -0.1268677711, 2.5043098927, 1.9020754099, 0.010769275, -0.6744157076, + 0.4011289477, 0.3623802662, 1.7662875652, -0.9019196033, 0.2089881748, 0.7885096669, 0.1734537929, 1.3288722038, + -1.6579455137, 1.5910657644, 0.4592954218, 1.3853743076, -0.4122804701, -0.6964764595, 0.1028952003, -0.2327424735, + 1.3980441093, -0.2943899035, -0.1668646485, 0.7435558438, 0.1972083002, 0.6509979367, 0.2048090845, 0.6409730315, + 0.0838581249, 0.9075406194, -1.0100653172, -0.8159732819, 1.1770539284, -1.1766952276, -0.4897406101, 1.5740053654, + -0.5039058328, -0.0056537632, 1.2350809574, 1.9353353977, 0.799289465, 1.1764726639, 0.5102623701, 0.1331552863, + 1.6801360846, -1.463870883, -1.4318088293, 0.7316586375, -0.0776355043, 0.132610023, 1.3219194412, -1.2926105261, + 0.5352171659, 0.2413900346, -0.5880570412, -1.6252239943, -0.2039538324, -0.2277193218, -0.7866405249, 0.4781764746, + -0.2251786292, 0.4531523883, -1.5962477922, 1.4734230042, 0.5247167945, 1.3522722721, 0.8866689205, 1.1717010736, + 0.40886724, 2.3660075665, 0.4089567363, -0.2065753043, 1.220846653, 1.6604276896, -0.8562346697, 0.3405393362, + 0.0647998601, 0.828751862, -0.6682997942, 0.9128044844, 0.8960058093, -0.5783953667, -1.8637040854, 0.9895142913, + 0.1827133447, 0.3518616557, 0.5791466236, -0.6660627127, -0.6760500669, 0.2832719982, -0.3868727982, -0.6564489603, + -0.5221094489, 1.2264560461, -1.3206096888, -2.1526074409, 0.3476690948, 0.3220793307, -0.7065263391, 1.2328867912, + -0.0474791229, 0.6002050042, -0.6559346914, -1.1499810219, -0.2271601856, 0.0775771588, 1.4095139503, 0.324590832, + -0.6881970167, -1.1337358952, -0.4698321223, 0.0208422132, -0.2039146572, 0.6458313465, -0.1945850253, -0.2234966606, + -0.4036347568, -0.1006233916, -0.5893812776, -0.3851362467, 0.6804109216, -0.2284515202, 1.5971822739, -0.5365006924, + 0.3082237542, 0.5073539615, 0.1667853743, 0.5216529369, -0.5112001896, -2.3981661797, -0.5508834124, -0.4447124004, + -0.162675947, 0.1065026373, 0.2490579486, -0.6605647802, 0.180701226, 0.9926020503, -1.1432589293, -0.6874733567, + -0.0878316462, 1.0072650909, 1.5095521212, -1.6570911407, -3.3662109375, 0.3644823432, 0.9877869487, 1.381125927, + 0.146974504, 0.6534839272, -1.9952636957, -0.6510771513, -0.7774798274, 1.4520498514, 0.2092368752, 0.4919971526, + 0.1677229851, 0.689991653, -0.361889869, 0.2964192331, -2.1922900677, -2.8469946384, 1.2499256134, -0.305695802, + 0.2330211699, 1.8649996519, 0.618499577, 0.0053699506, 0.3032593131, 1.4434729815, 0.7936376929, 0.1969661117, + -1.3081755638, -1.2562611103, -2.0427565575, 0.893239975, -0.4132222235, 1.3045953512, -0.9867917299, 0.1995005459, + -1.7860189676, 0.7441645861, -0.3486237228, 0.0734504163, -1.0310095549, 2.6190226078, -0.2775891423, 0.9633615017, + 1.5110583305, -0.851804316, -0.3761514425, -0.1686878651, 0.2582244277, -0.1115956157, -0.7016026974, -0.4886007607, + 0.2954337895, -0.7916867733, -1.0443811417, -1.2603008747, 0.9914335608, -1.0003927946, 1.2466765642, -2.2859148979, + 0.992685318, -0.622835815, 0.232824713, 0.1546843797, -1.4545462132, -0.3578131497, -0.7590592504, -2.1569862366, + -0.8818256259, 0.697879374, -2.1174297333, 0.7130247355, -0.3263854086, 1.4276014566, 0.9877415895, 0.5409177542, + 1.0951485634, 0.1220243201, -1.732118845, 0.4447348714, 0.6616247296, -1.3816518784, 0.8129363656, -0.5154392123, + 1.1574823856, 2.6286344528, -0.505014658, 3.4021975994, 1.4216302633, -1.0183618069, -0.3884378374, 0.8395509124, + -0.2105975747, 0.474067688, -0.0842759758, -1.9411085844, 0.4352273345, -0.1354239732, -0.9024779797, 0.7749136686, + -0.4862678647, -1.89729774, -0.4917300045, -0.0748297572, 0.9854032397, 0.2509278655, 0.8058610559, 0.1157606617, + 0.7863579988, 1.4600559473, 1.1236486435, 2.3348710537, -0.5767028332, -0.670231998, -1.2023346424, 0.5142666698, + 0.2149520069, 0.6355566382, 1.5429649353, -0.2103935927, 0.3804515302, 0.6273841858, 0.3169680238, 0.3265507519, + -0.3104707897, 1.5206472874, 1.2834477425, -1.0403629541, -0.7318644524, -0.5680179596, -1.317510128, 0.0111222519, + 0.0148605723, -0.0837772042, -0.1081169844, -1.1673394442, 0.500895083, -0.8864564896, 0.472447753, -0.0436774604, + 0.171529755, -0.3525592387, -0.9352099299, 0.3690447807, 1.9065877199, -1.3537904024, 1.1824322939, -0.9419884086, + 0.1806846112, -0.2388978302, -0.478864044, 0.9938432574, -0.4293144345, -0.9021407962, -1.0721393824, -0.3390442729, + -1.4578844309, 1.4132852554, 0.5697637796, -2.359992981, -0.2966747582, 0.9824299216, -0.3056213856, -1.2084267139, + -0.4508726001, -0.6144681573, -0.236015901, 1.3597880602, -0.6465095282, -0.3063315749, -0.3036143482, -1.142283082, + -1.6548137665, 0.3659083247, -0.6401305199, -1.0536401272, 0.8842850327, 1.063980937, -0.7625054121, 0.7067868114, + -1.809543848, 1.6055014133, 1.9578210115, -0.0146530466, 0.1607527882, 0.0634327382, 0.9684318304, -0.6058360338, + 1.0671213865, -0.1546684355, -0.4690584838, 1.0974758863, -0.3586915731, -0.5239579678, 2.1667027473, -0.6392484307, + -0.5902347565, -0.5282523036, 1.4030483961, 0.5651695132, -0.2470132709, -1.3528504372, 0.7387406826, -1.3053969145, + 0.4459773898, 0.6248256564, -0.4102109075, -1.4706453085, -0.1719833761, 0.6154183149, -0.1918688715, 0.7560840845, + 0.2232549936, -0.4626301527, 1.8654347658, 0.4972397983, -1.4983967543, 2.1595275402, 0.4665803611, 0.0884945244, + -1.1619651318, -0.2765117288, -0.1715537906, -0.351865381, -0.9461241961, -1.1457321644, 1.2026308775, 2.4595475197, + 0.4014116824, 0.6902657747, -0.2663109899, -1.3605632782, -0.5054963231, -0.4462118149, -0.6951832175, 0.6664215326, + -0.1848514378, -1.6823832989, -0.3947536945, -1.2504912615, 0.6512746811, 0.1747264266, -0.0348788761, -1.116877079, + -2.116468668, -0.6573825479, -0.4557669163, 0.448318094, -0.328087002, 1.1538000107, 0.6581790447, -0.1787044406, + -0.6257719398, -0.2563052475, 1.0647335052, -0.677636683, -0.044189468, 0.8303117156, -0.6585288048, -1.7951769829, + -0.486082226, -1.2639374733, 0.8270537853, -1.5556081533, 0.4140720665, -1.3718259335, -0.4767510295, -0.7637899518, + 0.2245294452, -0.2684869766, 0.9843692183, -0.5093818903, -0.81652987, -0.0653958842, 1.1830229759, -0.5425726175, + 2.0562729836, -0.5610432625, -0.597712338, 0.9381351471, -0.2507341206, -0.3926568329, 0.697996676, -1.939247489, + -0.5521243811, -0.9458277822, -1.1004375219, -1.6574097872, -2.4388780594, 0.7281301022, 1.3262432814, -0.3952213824, + -1.276106596, -0.4463176131, -0.1996756494, 0.0460203737, -1.8395447731, 0.8358345628, 0.0776033774, 0.3844222426, + 0.2353907377, -0.5447943211, 0.9198400974, -1.0590447187, -0.7494023442, 0.7968676686, -0.1726324707, 1.8498902321, + -0.1682839394, 0.1879395097, -1.7048875093, -0.4969268739, -0.1124747172, 2.0928378105, 0.1882959604, -0.1514537334, + 2.7660396099, 0.4743964076, -0.1937914789, 2.7596483231, -0.7834467888, 1.0347872972, 0.01522783, -0.7610386014, + -1.9078309536, 0.3805552125, 0.3727011681, -0.0694252625, -1.4736522436, 0.2938594818, 1.3245332241, 1.7787688971, + -0.0070120962, 1.6617984772, 0.8333523273, -1.7519874573, -0.2134312093, -0.0100032743, -1.4998146296, -1.8115137815, + 0.9965004921, -0.3041839004, 0.4738995433, -1.0041937828, 0.5569674969, 0.8938269019, -0.8305382729, 0.0593917184, + 0.362752825, -2.4793670177, -0.0537039153, 1.3435860872, -0.1680946201, -0.232386291, 0.303629905, -0.5398108363, + -1.0809445381, 0.363244921, 0.6647271514, 0.7428128719, -0.136968255, -0.0496443063, -0.1413195878, 0.9341860414, + 1.8201687336, 1.4392632246, -0.4426941872, 0.598859787, -1.0540181398, 1.5845466852, -1.844596386, -0.6951264143, + -0.7396306992, 0.6659613252, 0.5334790945, -0.1635098904, 0.0039233668, -0.626750648, -0.6743814945, -1.3609571457, + 2.2019507885, 1.0629549026, -3.3453154564, -0.4029050469, 0.1154041514, 0.7916713953, -1.0441731215, -1.8813159466, + -0.8272339106, -0.0320983604, -0.6287982464, 0.2015765011, 0.4855963588, 1.6028063297, 0.8580584526, 1.3570153713, + 0.7573254108, -1.0525548458, -0.8210426569, -0.3900167942, -1.5697445869, -0.6533695459, -0.0810939893, 0.5408882499, + 0.751378119, -0.4506444633, 0.9149255753, 1.4994388819, -0.0303670596, 1.0417119265, -0.2023945749, 0.8270350099, + -0.179283306, -0.0137997605, -0.6589713097, -0.3070053756, 0.0456016734, -0.0929416865, -0.8315680623, -0.9879750609, + -1.9678112268, 0.4647029638, 0.3763283193, 1.1709362268, 0.8068950772, 0.3331092, -0.2832021415, 0.1535404325, + 0.0047497978, -0.6976765394, 0.0749599189, -0.1627242714, -0.6791628599, 0.5772633553, 1.5324664116, -1.1410440207, + 1.7173656225, -0.3408393562, 0.9652553201, 0.2716450393, -0.7487616539, -0.1968285292, 0.1606321335, 0.6696608663, + -2.2959189415, -0.8271072507, -0.0054756412, -0.2375295013, 0.0163776018, -0.8759958148, 0.5110145211, 1.9992854595, + -1.2928618193, 0.5799829364, -0.7743336558, 0.9561066628, 0.0935266614, 0.3667050898, -1.1060663462, 1.1112999916, + 0.8064696789, -0.7583508492, 1.5314108133, 1.2391928434, 0.0666859671, 1.9098252058, 1.2984734774, 0.4810087383, + 0.2941254973, -0.0169484559, 0.4986978769, -0.3291710019, 1.648008585, -0.9981449246, 0.5191267133, -1.3664671183, + 0.2130313367, -1.1082155704, -1.0726953745, 0.0305134151, -1.2059307098, 0.3432687521, 0.2289526612, 0.8410323858, + 0.9339575768, 0.9122983813, 0.1333952397, -1.737005353, -0.3468855321, 0.2191209644, 0.5838090181, -1.1512639523, + -2.1934931278, -0.4012824297, -0.5996697545, -2.5864920616, -2.8078482151, -1.9428218603, 0.5865498185, 1.0440528393, + 0.2802296579, 0.272621572, -0.7898737192, -0.5721588135, 0.9211881757, 0.9148751497, 0.1910182387, 1.4056829214, + 0.4825052023, 0.3429075181, -0.5708855987, 0.3786260784, -0.9315177202, 1.0208618641, -0.9725951552, 1.0935645103, + -1.2232342958, 1.0409260988, 0.6748644114, -0.8847046494, 1.7760386467, -0.0125171226, 0.8016899228, 1.8771826029, + 0.273635745, -0.6259844303, -0.9930151105, 0.3236394823, -0.2595492899, -0.1605339348, -0.1315153837, 0.623575151, + 0.6957799792, 1.6935269833, 0.4405800402, 0.0049002608, -0.5700479746, 0.2159934789, -1.433668375, -0.3797477186, + 1.4713785648, 1.8703402281, 0.0075660832, -1.4935919046, -0.8821055293, -0.6234281659, 0.9677629471, -0.7328437567, + -0.2575615942, 1.0310820341, 1.8457337618, 0.0857489705, -1.4493061304, -1.2911778688, -0.0060188952, -1.2698920965, + -0.5432638526, 0.157918185, -0.7544699907, -1.0726186037, 1.2530040741, 0.0434547551, 0.6073220968, -0.6502922773, + -0.3982699513, -0.2588134706, 0.0140502499, 0.7154316902, -2.1796958447, 1.3421326876, 0.9615692496, -0.5703505874, + 2.5212097168, -0.0208987631, 1.0348778963, 1.9658333063, 0.3773489296, 1.4068762064, -2.7714827061, -0.5579730272, + 1.2298541069, 0.6545353532, 0.8766176701, 1.4339731932, 1.1497399807, -0.5089753866, -0.5128499269, 0.5389691591, + 1.3455309868, -0.8251724839, -0.8975332975, 0.8422950506, 0.8494792581, -0.1416618824, -0.6297848225, 2.3947386742, + 0.1711565703, 1.2305666208, -1.055234313, 2.2050673962, -1.1041059494, 0.075780794, 0.5562387109, -0.3192164898, + -0.7332569361, 0.2332962155, 0.8301983476, -1.3935382366, -0.1565247476, 0.2479268014, 0.0560801663, 1.7070498466, + 0.7718081474, -0.7962634563, 0.7645039558, -2.1454570293, 0.6315026879, 0.4187367857, 1.1163557768, 1.245718956, + 1.1284046173, -0.0940276459, -2.3251667023, 0.5586260557, -0.3234356046, -0.3314171135, -0.7101279497, -0.1197030023, + -1.7641125917, 0.6344687939, -0.3916080594, 2.176202774, -0.9665816426, 0.0275986735, -1.0265176296, -0.7908039093, + -0.2755824327, -0.1384730488, 1.0248076916, 0.8314927816, -2.0504336357, 1.2907943726, -0.234194383, -0.6094402671, + 0.5007750988, -0.3549800217, 0.1185565591, -1.1103465557, -0.240551278, 0.4953965843, -0.0646155775, -0.4671186805, + 1.1927411556, -0.6523253322, -0.5857589245, -0.2545292974, -0.1239542216, -0.0203897934, -0.0034907917, -0.664000392, + -1.3702145815, -0.8654106855, 0.0326672718, 1.3138712645, 0.4208591878, -0.9769559503, -0.8214844465, 0.129774943, + -0.1297391802, 1.0146135092, 1.794064641, 0.219792828, -0.1319720149, 1.0318607092, -1.8993104696, -1.7712563276, + 0.281063199, 0.4633574188, 1.6809766293, -0.3751383126, 0.7755542994, 1.0474252701, 0.2971350551, 0.5951340795, + 1.6116594076, 0.1424589455, 1.2979151011, -0.4820315242, -0.1617800742, 0.0396738835, -0.8928088546, 1.1956772804, + 0.3390346169, -0.4060118496, 2.4652819633, 0.8918821812, -0.0780620202, 0.7143768072, 0.3408457935, -1.7165350914, + -1.1632332802, 0.3031347394, -0.0014043999, 0.3238669932, 0.6181593537, 0.0723976716, 1.0229631662, 1.1097664833, + -2.3270466328, 1.3248306513, -0.2984437943, -1.4610385895, -0.0516262911, 0.507930696, -1.0296018124, 0.0228735339, + 1.1103858948, 0.0523694046, -0.0578812994, 0.1035495922, -1.4611114264, 0.3591971695, -0.9242418408, 0.3373346329, + 0.5315905213, -1.1278209686, -0.1850767732, 0.0478607044, 1.8553361893, -0.1041360721, -1.0382961035, 0.5020739436, + 0.0162114426, 0.494656533, -0.3373891413, -0.8022236824, 1.7341907024, -0.0187101774, 0.7622405291, -1.3417707682, + 2.0679044724, -1.0047054291, -1.5931515694, 0.6079227328, 0.6830322742, 0.1589563638, -1.3811666965, -1.2644420862, + -1.9886835814, 1.9554864168, 1.1086750031, 1.0685912371, 0.0946351141, -0.1953218877, 0.303999722, 0.4832267761, + 1.211661458, -0.5229575038, -1.0833784342, -1.9380421638, -0.1046403423, -1.2439750433, -0.1244251058, 1.0000693798, + 0.9575945139, -1.6811643839, 0.2811778784, 0.8408188224, -0.7864719629, -2.227602005, 1.8322992325, -0.4967197478, + -0.7136280537, 0.0266603082, -1.49429214, 0.8555268049, -0.7208786607, -0.8286910653, 0.0459153466, -2.0120952129, + 0.3852713704, 0.0434668995, -0.9490215778, -1.5576071739, 1.1132159233, 1.4050958157, -0.4533327222, 0.4062691331, + -0.771066308, 0.4899501204, -0.3605414927, -0.7879081964, -1.4783047438, -0.6426596045, 0.029168034, -1.8412855864, + 0.3601514101, -0.160208866, 1.1215077639, -0.6920269132, 0.4370068312, -0.6374166012, 0.9822850823, 0.0243866947, + 0.1872158647, -0.0480282828, -0.2081749886, 0.2828293145, -2.1054990292, -0.4270705283, -0.7249308825, -0.9879758954, + 0.0718391016, -0.5815575719, -1.1283096075, 0.1646392792, 2.2088565826, -0.8298310637, 0.1257507503, -2.0224769115, + 0.6178207994, -1.2828671932, 0.483127892, -2.5446667671, 0.0235447213, 0.6328905225, -0.2720804214, 0.2828456461, + -0.2629654408, 0.2357223034, -0.2633309066, 0.3823617697, -1.061281085, 0.8905143738, 0.2787717283, -2.9553375244, + 0.4997931123, 0.3578976393, 0.5189617276, 0.3165110052, 0.1713823676, 2.0032389164, 0.5444811583, -1.5100010633, + 1.658331275, 0.4102133214, 2.2827858925, -1.4170377254, 1.0672702789, -1.0848878622, -0.9437910318, -0.7768186331, + -0.7263257504, 1.1376026869, 0.1669677347, 0.1908601671, 1.609513402, 1.1411566734, -0.1959963888, 1.8457901478, + 2.7180738449, 0.0899037942, -0.4714163244, 1.5490199327, -0.0940073505, -0.6156017184, -0.8397650123, -1.5853828192, + 0.6788233519, -2.0469789505, -1.0404422283, 0.6478714943, -0.5592913032, 0.7406380773, -0.6209233403, -1.7690067291, + -0.3744283617, 0.5275703669, 0.1906655729, 0.1695944369, -0.1484553218, -0.5499172807, 0.6520490646, 0.1473938972, + -0.8528057337, -0.6439852715, -0.2095579505, -0.1239432767, 0.3361501396, 0.2245066762, 1.9661922455, -0.0664852038, + 0.4860768616, -0.1386903822, 0.9536022544, 1.0937627554, 0.1194592714, -0.6387403607, -0.5548762083, -0.5451083779, + 1.489456892, -0.7443156242, 0.7375551462, 0.306742698, -2.0427732468, -0.4271575809, -1.3816052675, -0.5549044013, + -1.5412914753, 0.9646945596, 1.0175510645, 0.8287231922, -0.6588662267, -0.8034091592, -1.0398589373, -0.199035272, + -0.2321966738, -0.8626244664, 0.7902417779, 0.5957292914, 0.0277387053, -0.0978775173, -1.7130082846, 0.765147984, + 0.6190039515, -1.8823497295, -2.8895819187, -0.3021363914, 0.6384620667, 1.129316926, 0.8372123837, 1.8616006374, + -1.3465864658, -0.9666275382, -0.8175053, -2.2610628605, 1.1906888485, -0.8104630709, 0.0317354426, -0.2019810528, + 2.2502446175, -0.2259142995, -0.2013495713, -0.4183434844, -1.751052618, 2.2945125103, -0.7594260573, 0.3623003066, + 0.2451833487, -0.553483367, 0.8765788078, -1.2913513184, -1.5042854548, 0.7121409178, -1.0445988178, -0.9468733072, + 1.0692250729, 0.2658461034, -0.5082159042, 2.3868613243, 0.3205399811, -1.053047657, 1.8602855206, 1.8128275871, + 0.6259533167, -0.7656450272, 0.3985169232, 0.386706084, -0.1872877032, 0.4220613837, 0.8917585015, -1.4155749083, + -1.2021927834, 2.240973711, 1.1562517881, 0.3536393642, -1.7080003023, 1.5424200296, 0.9600786567, -0.0872785896, + 0.7514562011, 0.949688375, -0.6002808809, 1.6835938692, -0.2155499607, 0.9516291618, 0.4370562732, -0.4840465486, + 0.1115614027, 0.2884726524, 1.3234615326, 1.0874466896, -0.500737071, -1.0555545092, -1.3426496983, -0.3183835149, + -0.0679995045, 0.3516796231, -0.7929608226, -1.4250048399, 0.3407011926, -0.5564637184, -0.5598407388, -2.0848259926, + -0.3684155047, -1.5428141356, 0.0320821367, -0.7246804833, -0.578497231, -0.0024182077, -1.0722943544, 0.6343519688, + -0.2621089816, 0.2908956707, 0.8434097767, 0.7944604754, -0.0688873604, 0.204967767, -1.0564239025, -2.9353809357, + -1.107078433, 0.8343291283, -0.2105655819, 0.8942486644, 0.1070115343, 2.8148813248, -0.1915903836, -1.2917917967, + 0.6141395569, 0.2729116678, -0.0089775594, -0.9163486362, -0.3805558085, 0.4296191335, -0.5568725467, 0.0454204902, + 0.3127158284, -1.2098184824, 0.5218726397, -1.8089548349, -1.7078270912, -1.0075867176, 0.2304183394, -0.6987965107, + 0.6294561028, 1.4788361788, 0.2974897623, 0.9382640719, 0.6637336016, 1.1047103405, -0.1571140289, -0.9894824028, + -0.5497223735, -2.0647106171, -2.5246694088, -0.3880341649, -0.2562047243, 2.0650627613, 0.281472832, 1.5140551329, + -1.5470811129, -0.5152064562, 0.2855536342, -0.7161605358, 0.1456434429, -0.7985317707, -0.1925467849, 0.7353378534, + 0.8663336039, 0.0977301821, -1.6826072931, 0.3238239288, 1.8810269833, 0.0977288559, -0.6490523815, -0.7416719794, + -0.4745566249, -0.4449836314, -1.5103685856, -0.0510294065, 0.3497232795, -1.3869361877, 0.1665868908, 1.4021207094, + 0.9121657014, -0.4573785961, -0.7126724124, 1.1894726753, -0.7016700506, -0.1637506485, -0.167248711, -0.2228942066, + 0.7889564633, -1.7819786072, -1.0300257206, 1.5504140854, -1.205467701, -0.5473297238, -0.6004752517, -1.4439833164, + 0.7139390111, 0.3109297752, -0.390219152, 0.9313625693, -0.0723820999, 0.5176621675, 0.1685560048, 0.6693775058, + 0.438849777, 0.400919646, -0.7448923588, 0.1883382797, -0.0165072586, 0.1768764108, 1.0786801577, -0.4834615886, + 1.3717924356, -3.5873508453, 1.6853481531, -1.1144967079, -0.6112350821, 0.424543649, -1.7847050428, -0.1747217029, + 0.1853655428, 0.1908560395, -0.6552680135, 1.0942722559, -1.4203670025, 0.0901684761, -0.8357254863, -1.3958472013, + -0.6363635659, -0.3363048434, 1.3161414862, 2.3062155247, 0.2548306286, -0.5943790674, 0.1230811551, 1.3223766088, + 1.088137269, -1.4070535898, 1.0152657032, -0.4547869563, -2.4484944344, -0.7348918319, -0.1146792397, 1.8282408714, + 0.4467991889, 0.5553500056, 1.0960659981, 1.1745150089, -0.6352566481, 0.9568100572, -0.1503251493, -0.6595150828, + 0.465613842, -0.2699167728, 0.3962543607, 0.0893835947, 0.9601736665, -0.2942351103, -0.080504559, -0.1939863265, + 0.709248662, 0.7895736694, 0.5779416561, 0.3850767314, -0.4842936695, 0.6331396103, 1.1849069595, -1.2239178419, + 0.639981389, -0.1655349433, -0.2754193842, -0.4561723173, -0.0982396007, -0.7950536609, -1.3405947685, 1.4434165955, + 1.4510871172, -0.5008798242, 2.3326554298, 1.7171764374, -1.121494174, -2.1384959221, -1.4371384382, -1.2622073889, + 0.3689718246, 0.3668732345, -0.1287642419, 0.4816688895, -0.7438533306, 0.795447886, -2.9465436935, 0.028052181, + 0.5243663788, 0.8543690443, -0.5550677776, -0.9916635752, 1.0783920288, -0.2361106575, -1.0624667406, -1.0621988773, + -0.3515598178, 0.0059884796, -0.2377974391, -0.2549857199, -0.5997722745, 1.4417372942, -1.2261022329, -1.3927828074, + 0.3786606491, -0.8822529912, 1.9552049637, 1.3698495626, -0.7608377934, 0.4118162394, 0.3870486319, -0.1944354028, + -0.6407830119, -0.4655601978, 0.3296374083, 0.3511639833, 0.6457598209, -1.674987793, 0.364812851, -0.3509193361, + 1.3478113413, -0.6998479962, 0.1091958135, -1.264811039, 0.691953361, 0.8096422553, 0.4792396128, 2.1586918831, + -1.014526248, -0.4494864345, 2.100425005, -0.8175516129, -0.1288737357, 0.6267175078, -0.9657980204, -0.3166680932, + 1.2221369743, 0.6191287637, 0.8959646225, 0.2814862728, -0.3159213364, 1.3342118263, -0.9356304407, -0.7985250354, + 2.5087397099, 0.218711406, -0.3500434756, -0.5621758699, -1.1118510962, 2.3423166275, -0.8084353805, -0.6880099177, + 0.9092693329, -0.4087174237, 1.1080206633, 0.9253252149, -0.9031172395, -0.6476074457, -1.5008963346, 0.4107389748, + 0.5725745559, 0.0407793745, -0.892983079, 0.7959543467, 0.6446728706, 1.539386034, 0.2424186319, -0.7756873369, + -0.3757202029, 0.9156033993, 1.549139142, -0.2052761167, -0.7376536131, -1.8269327879, -0.6759383678, 1.0747044086, + 0.3764349818, -0.0615763552, 0.0539816134, 1.383004427, -0.2138948143, 0.6070758104, 2.2050757408, -0.5970668197, + 1.5818897486, -1.7589093447, 0.2374013215, 0.6174883246, 1.5783377886, 0.276715219, -2.0720968246, -2.1631407738, + 1.1022502184, 0.9568095207, -0.7925844789, -0.012993224, -0.4571443796, 1.1118091345, -0.080276981, 0.5072802305, + 1.49941504, 0.959594965, -0.5461329818, 1.2634196281, -1.2565197945, 0.0333052836, 0.460436821, -0.5963924527, + -0.4048521519, -0.0185353886, -0.443354249, 1.0058584213, -0.6991336942, 1.2530970573, -1.8591336012, 0.1965983361, + -1.3790326118, 0.6991924644, -1.1815651655, 0.5590909123, -0.5781280994, -0.2810287178, 0.9894128442, 0.5948468447, + -0.2116240114, 1.6549823284, 2.1434628963, 0.1538797021, -0.2101962715, -0.2762024403, -1.0265514851, 1.2561662197, + -0.0961916596, 1.8024312258, -1.069501996, 2.2832481861, 1.1988962889, -1.309589386, -0.6166658401, -1.0923980474, + -0.4167923927, -1.1538887024, 0.6146585941, -1.0539424419, 0.2147403657, -0.9397309422, 1.24033916, 0.692479372, + -0.1568285823, -0.2127067894, -0.4619454741, 0.446687609, -0.8593928218, 0.3885909915, 0.5803668499, 0.3129754663, + 0.5921312571, 0.2810893059, -1.0458991528, -0.3443108499, -1.374481678, -0.3332820535, -0.8077567816, 0.4288160503, + -1.7361116409, -0.1163452491, -1.3128036261, 0.0584229752, -0.1550195813, 0.5011024475, 0.9355930686, 0.5465435386, + 0.4411371946, 0.1784846634, 0.4730665684, 0.3743475676, 0.3358268142, 0.3381077945, -0.0342798606, -0.8083887696, + -0.3979845345, -1.1604353189, -0.0066471668, 0.1081213802, -0.0444181934, 0.1806796342, -0.7541006804, -0.7393528223, + -0.9072701335, 0.2659946382, 0.8296968937, -0.2166975737, -0.081805177, -0.1148054823, -0.7135875821, 1.2623482943, + 0.9717949629, 0.6293833852, 1.6772850752, 1.0530080795, -2.5207023621, 0.0990564898, -1.2991740704, 1.438439846, + -0.5041558743, -2.4514865875, -0.7514006495, 1.0182894468, -0.4337368309, 1.8021686077, -0.4107547402, 0.007783521, + 0.2561873496, 1.2580149174, -0.2291361839, 0.1945354342, -0.7990037203, -0.4128118157, 0.3472887278, 0.6855760217, + -0.0667856112, 0.5450399518, -1.0061272383, -1.0191876888, 0.82111305, -1.1527760029, -0.5438255668, -1.2694709301, + 0.2857372463, 1.1246901751, -0.3271239996, -1.5309205055, 0.9586626291, 0.7188817263, 1.3707944155, 2.0927855968, + 0.9110329747, -0.4163654447, -0.2413679957, 0.1141957939, -0.3054531515, -0.1258421391, 0.4647783935, -1.0801485777, + -0.4261832237, -0.916267395, 0.792437613, 1.0909430981, -0.6960784197, -1.6909022331, 0.2807614803, -0.9859634042, + 1.3558187485, 0.4552947879, -0.6819797754, -0.5628001094, -1.1365072727, 0.0257628281, 1.3203532696, -1.7315850258, + -0.2278526872, 1.1781377792, 2.34634161, 0.1275173873, -2.5863084793, 0.6135267019, -0.8700727224, -0.8105805516, + 1.5111283064, -0.3862929642, -0.4356092811, 0.0636376143, -0.5927600861, -0.5895982385, 0.1878833175, -1.9611967802, + -0.3901644945, 1.0398082733, 1.2147284746, -1.1976518631, 2.3415234089, -0.7130673528, 0.2361291051, -0.3015916646, + 0.5939913988, -1.4054470062, -1.050339222, 0.6779701114, 0.5623335242, 0.0663100109, 0.4308245182, 1.0027855635, + 0.8165775537, 0.4989019632, -0.0002661952, 1.5691658258, -0.7713332176, 0.1407069266, -1.0722569227, 1.591739893, + 0.6614595652, 0.2007022649, -1.0523856878, 0.0822489485, -0.6039589047, 0.468126893, -0.5547893047, -1.6950765848, + -0.6791362166, 0.1981026828, 1.9102047682, -0.5541394949, -0.9890259504, 0.7984296083, 0.0003176213, 0.0550370589, + 0.4107954204, -0.0231982525, -0.7725265622, 0.6694859266, 1.2758612633, -0.1744779348, -0.0360984839, -1.679458499, + 0.4439693987, 1.3904777765, 0.5694403648, 1.7294931412, 1.5751372576, -1.9432759285, -0.3927997947, 0.9067459106, + 0.5820047259, 1.2948682308, 0.1216424406, 1.1153415442, 1.5315512419, 1.1464210749, 1.7029515505, -1.0568026304, + -0.0944661796, 0.3944582939, -0.1618760973, 0.0606435351, 0.6873081326, 1.0236778259, -1.4742099047, -0.4439935684, + 0.6182740927, -0.05598161, 0.4584692419, 0.9900916815, 0.5068622828, 0.1548262686, 1.0944187641, 0.4731070399, + 0.9248341918, -1.4233351946, -0.8062060475, 0.1411530674, -0.767598331, -0.8649474978, -0.031737186, 0.7700589895, + 0.7849109173, -1.3150564432, -0.165059641, 0.1696455181, -0.0934922174, -0.6370592713, 0.557528317, -1.4024553299, + -0.2018749118, 0.2528863251, 0.1751198769, -1.125703454, -0.1473133713, 1.020611167, 1.2502821684, -1.1858514547, + -0.4971847236, -1.9140037298, 0.1850125492, 0.6661189198, 1.7885531187, 0.4540091157, -0.543187201, 0.5952700973, + 0.3110172749, 0.7823548913, -0.3349719644, -0.3264983892, -0.7418109775, -1.7509810925, 0.1852183491, 1.0977188349, + 1.5520267487, 0.3697099686, 1.779271841, -0.1528856754, 0.2824684978, -2.4584684372, -0.233856827, -0.1353407651, + -0.7570917606, 2.032501936, 0.3802107573, 0.0842941403, 0.1059182584, -0.0346744955, -1.6290546656, 0.549362123, + -0.3867263496, -1.4424030781, -0.6036384106, 0.0387400873, 1.515294075, 0.1151001677, -1.0722410679, -0.2107968777, + -0.4670877755, -0.137523517, -0.1439756453, -1.0298039913, 1.0332676172, 0.817024529, -0.1887505949, -0.0494192839, + -1.0711476803, -0.8699306846, 0.4188597202, -0.3706445992, -1.1961505413, -0.7853118181, -0.4474318326, 0.4565109611, + -0.3028509021, 0.0739333481, 0.5674366951, 0.1040408462, -0.0226907004, -0.2704212666, 1.5229213238, 1.6927081347, + -0.4871771336, 0.7022641897, 1.0417212248, 0.6593301296, 0.6112542152, -0.9994509816, 0.6857087016, -0.1322730035, + -1.0452054739, -1.302945137, 1.2493374348, 0.0080011049, -1.2995612621, -0.0949502289, -0.3533111811, -0.8815700412, + -1.484903574, 0.6015857458, 0.3696425855, 0.121667482, 0.180739373, 0.3852241039, -0.8649283648, -0.2445823848, + 1.3928322792, 0.824162066, -0.104998894, 1.2019417286, -0.8042196631, -0.1875663549, 2.1202955246, 0.5893884301, + 0.66506809, -1.4238115549, -0.4695525169, -1.4288089275, -0.3693912327, 0.828869462, -0.1480082422, 0.8329437375, + -1.5620113611, 1.493350625, -1.974832654, 0.3324063122, -0.8589459658, 0.518810153, 1.1035842896, -0.2568058074, + 0.8886639476, -0.7919666171, 0.486992836, 1.851678133, -1.1125978231, -1.166339159, -0.2702799141, -0.9070065618, + -1.8252818584, -0.3983536363, 0.9135220051, 0.6276210546, -1.2996852398, -0.8030201793, -0.8869251013, -0.100630708, + -0.1849675477, 0.4097519517, 1.1918514967, -1.174690485, -1.5114037991, -0.0913629159, -0.5989208817, 0.941046536, + -0.8433012366, -1.2563877106, 1.0473858118, 0.9126477838, -0.5827721953, -0.5856482387, -1.7571837902, 1.3324482441, + 0.4234672189, -0.6457720399, -1.0114756823, -0.057540413, 0.4846711755, 0.5327658653, 0.082765907, 0.2714155316, + 0.4643567502, 1.9540315866, 1.3832021952, -1.0131411552, -1.0373722315, 0.80325073, 0.2130549699, -0.8439952135, + 0.9219255447, 1.1542927027, -0.0212097038, 1.6666793823, -0.5585919619, 0.2945807576, -0.0132242423, 0.5881583691, + -0.6531445384, -0.2318715155, 0.0456866808, 0.0064122831, 0.492230773, -0.6649486423, 1.2209202051, -2.3153216839, + -0.818864882, -0.7945204377, -1.234662056, -1.286028266, -0.8244218826, 0.7727444172, -1.7617459297, 0.0262414347, + -0.3023742139, -0.0454284027, 0.5600838661, 0.3081323504, -0.6677283049, -0.0851749256, 0.4230430126, 1.1981501579, + -0.5143482089, 0.1208445281, -0.330252409, 1.4326996803, -0.4619111121, 0.8303595781, -0.2305427641, 0.4566539824, + 0.0284742471, 1.1725553274, -0.67789042, 0.7474908233, -1.435706377, 2.0686724186, -0.6995326281, 0.1032049581, + -0.9478116035, -0.1820008606, -0.8253668547, 1.1953212023, 0.3244872391, 0.6627004743, 1.005304575, 0.2691727877, + 0.2567492425, 0.6107055545, -0.787951231, 0.9819718599, 0.6871561408, -0.8443669677, 0.0294165127, 0.6981332898, + -0.4156535268, -0.4417705238, -1.1484087706, 0.4935772717, 0.9644652009, -2.2177762985, 1.2895581722, 1.9430149794, + -0.1687173247, 0.2524688244, -0.0231861938, 0.2763607204, -0.8558312058, -1.3785704374, 0.9749888182, -0.0315952413, + 1.2336918116, 0.8569123745, -0.1242811829, 1.0706355572, 0.0651801452, -1.0987329483, -0.0845275149, 0.3220182061, + 1.3133853674, -0.3922113478, -0.874510169, -1.6545143127, 1.3099434376, -0.3884691894, -1.0207983255, 0.9145443439, + 0.6784790158, -0.467972815, -1.8396611214, -0.650100112, 1.0174416304, -1.2393320799, -0.0569090955, -1.5452183485, + 0.4984608293, -1.0995006561, 0.4160440862, -0.2431684881, -0.0810485184, 0.167301476, -1.2867910862, 1.1799737215, + -0.2366669923, 0.2107269764, 0.1286269724, 0.7097382545, -0.7196391225, 1.0831000805, 0.2915651202, -0.802867353, + -0.4497925341, -0.2961663902, -0.393861115, 1.3102715015, 0.1274573952, -0.3415600657, -1.3402360678, 0.3736258149, + -0.155401662, -2.035089016, -1.6971189976, 0.2403908372, 0.2295648903, -1.4248719215, 2.1251647472, -1.4979672432, + -1.2219846249, 0.3304457068, 0.0374567807, 2.1840059757, 0.5777245164, 0.1611160338, 0.8961535096, 0.3680781722, + -1.9025293589, -2.964628458, -0.6679293513, 0.0742716938, 1.4247859716, -1.4310384989, 0.6191782951, -0.2454420179, + 1.8304854631, 0.5033181906, 1.540464282, 2.0885241032, -1.3709269762, 1.6574317217, -0.573811233, 0.4851473868, + -0.5364739895, 1.9374666214, 0.5323956609, -0.7937283516, 0.7213377953, -1.9963128567, 0.5997330546, -2.5905666351, + 0.4053169489, 1.0426921844, -0.2191019654, -0.5558608174, 1.5116729736, -0.825697124, -0.2864851356, -0.501013577, + 1.4569622278, -0.4448128939, 1.1936591864, 0.6703691483, 2.1985344887, -0.6182096004, -0.7770881653, -0.7601132393, + 0.8608002663, 1.1269603968, 0.0908432677, 0.1105712205, 0.9951350093, 1.0663802624, -0.6953923702, 0.0459341668, + -1.2705870867, -0.4319158792, -0.7496430278, 0.5289142132, -1.6569365263, -1.0187835693, 0.9269422889, -1.4888494015, + -0.432164073, -0.1888191402, -0.4988208711, -0.7500018477, 0.5415527821, 1.2704626322, -0.5392972231, -0.5853786469, + 2.0392589569, 0.8061009049, 0.4328102469, 0.1999326795, -0.1828068048, 2.0369491577, 0.5376186967, -0.945645988, + 0.2697933614, 1.689740777, -1.3979105949, 0.2796856165, -1.2426117659, 0.6467071176, 1.0034134388, -0.5081450939, + -0.1762165129, -0.9470931292, -0.9216216803, 0.0103546353, -0.9105349183, -1.5967898369, 1.6333882809, -1.1184823513, + 0.7191648483, -0.1556680799, -1.1775581837, 0.6844239235, -0.0761843994, -0.8918274045, -0.9387372136, -1.4445216656, + -0.8445951939, -0.1898192763, -1.2781102657, -1.6075053215, 0.6881842613, 1.5046265125, -0.6197365522, 0.2504410148, + -0.26260221, -0.5783621669, 0.90598768, -1.2948360443, -0.2569444478, -0.8420674801, -1.3039224148, 0.5142272115, + 0.4427238107, 0.1815748215, 0.4946224391, -1.3786232471, -0.2891066074, 0.4617694318, -0.8750137687, -0.6624167562, + 0.229928419, -0.3934533298, 0.1057336032, -0.5486158133, -0.7816815972, 1.4666053057, 1.4891735315, 1.424190402, + -1.1920310259, -0.6360286474, -0.425075531, 0.0566578321, 0.7702762485, 0.1289665252, -1.5876783133, -0.0016417794, + 0.4250714779, 1.0069613457, 0.9110912085, 0.6452820897, 1.2802551985, 0.873688221, -0.1176333576, 1.3896194696, + -0.8711903095, -0.8319627643, -0.2103565633, -1.545273304, -0.2017096281, 0.0036522455, 0.3344618678, -0.4068647623, + -0.7161149979, -1.225897193, 0.5839748979, 0.6048594713, -1.143158555, -1.730232358, -0.0968581066, 0.1390904784, + -0.3141165972, 2.1717050076, 1.9471942186, 0.5632810593, -0.2581654489, -0.8188413978, -0.7301347852, -1.945132494, + 0.146177128, -1.303145051, -1.2256352901, 0.2075386643, -0.3776623309, -0.6919597387, 0.7050512433, 1.5114662647, + 0.1402460635, 0.9202152491, 0.4513795972, 0.7388632298, 1.0826296806, -0.3678231835, 0.3671057522, 1.1094573736, + 0.3479338884, -0.6016224623, 0.0073265564, 0.4310854077, 1.7144032717, -0.3383898139, 1.0131033659, 0.2747268379, + 0.7387757301, -0.4018067122, 0.6781775355, -2.1581020355, 0.2278467268, 1.7021756172, 1.3773645163, -2.0554974079, + -0.6872193217, 0.1226048097, -1.9852946997, -0.3543234169, 0.1991903782, -2.1077291965, 0.952401042, -0.8265848756, + 0.0515594371, 0.7495928407, -0.5910230279, -1.9738554955, -0.4401849806, 1.2871997356, 0.3963395059, -1.3662760258, + -1.0966602564, -0.1497679204, 0.2017935365, 1.5538893938, -1.4132012129, 0.8584647775, 0.0906719267, -1.0717674494, + 0.1683136374, -1.6558039188, 0.5440172553, 1.232401967, 0.5137600899, 0.247241959, -0.0660363659, -0.3757608831, + 0.5444558263, -1.7358322144, -0.0051293653, -0.250359267, -0.4951822162, 1.2275048494, 0.2725945115, 0.3664792776, + -0.6326197982, 0.0382645912, 0.7879148126, -0.1890475899, 0.626070261, 0.6560769677, -0.8796280622, -1.0355696678, + -1.1185706854, 1.8544151783, 0.7461084127, 1.7544984818, -0.6223727465, -0.4497933388, 0.8481234908, -0.3922756314, + -0.4858475626, 0.0968091264, 0.0066539571, 1.0293912888, 0.227826044, 2.0721802711, 0.4783202708, 0.7750809193, + 0.3829811513, -1.083496213, -0.6774073839, -1.5615712404, -1.6606448889, 0.3167343438, -0.4906793833, 0.0483574681, + 2.2943816185, -0.0707739368, -0.4499971867, -0.1112928838, -0.2830072939, -2.6263105869, -2.1136035919, -1.1006478071, + 0.7729149461, 1.4741439819, -1.2733880281, 2.3177292347, -0.5778938532, 0.0909742787, 0.4740823805, 0.5157712102, + 0.5300472379, -0.8119449019, 1.2384713888, 0.5614928603, 0.2497849166, 1.2373347282, 0.1882596016, -0.119956933, + 0.51253438, -0.4821256101, -0.5073617697, -0.3014651537, 0.6116203666, 0.1299709827, 0.694293797, 1.1415054798, + -0.2746116817, 0.1055720225, -0.5667106509, 0.4699902534, 0.3701259792, -0.466499716, -0.0554599166, -0.9459332824, + -0.7991710901, -0.0254140403, -0.1795408279, 0.5957148671, -0.9031828642, -1.5857150555, 1.0605216026, -1.5644696951, + 2.2349119186, 0.2240771055, 0.9779759645, -0.3761295676, -0.6323259473, -1.1920045614, 1.5147486925, 1.5310157537, + -1.3137631416, 0.0094543528, -0.2456318289, 0.5364572406, -0.9972238541, 1.2738656998, -1.3176814318, 0.3259899318, + 1.0292425156, -1.3389029503, 1.4183219671, -0.4529511333, -1.0125648975, 2.5792348385, 0.6706108451, -0.4555190206, + -0.8167887926, -0.2441108376, 1.4933758974, 2.3693647385, -0.0329419933, 0.2555276155, 0.1001068726, 0.4355405271, + 0.797778964, -0.3352335989, 0.1421558112, -0.2073267847, 0.0726978779, 0.4240096211, -2.366361618, -0.8102269769, + 1.0085755587, 0.2688770592, -1.0159114599, -0.1881680489, 1.825368166, 0.891818881, 0.0901473612, -0.1998090148, + 0.6020976305, 0.9907689691, -3.2210643291, 1.6036646366, -1.0785632133, -0.4379940927, -0.7611535192, -0.0714974627, + -0.6375125051, -0.3485542536, 0.3473993838, -1.256885767, -1.3050128222, 0.0136722717, 0.7082781196, 0.8472917676, + 0.80572927, -0.1659359187, -0.5133125186, 0.3766638637, -0.2679806054, -1.4026973248, -1.0416235924, 0.7020118833, + -0.150300324, -0.5658562183, 0.1204976216, -2.671785593, -1.9358696938, -0.8094495535, -0.6051175594, -2.0002884865, + 0.7022117376, 2.1806385517, -1.7201800346, -0.0582118407, -0.1393259019, -0.101640217, -0.2271406353, -0.0488020889, + 0.1912101656, 1.2248835564, -2.2081222534, 0.0591728874, -1.0548201799, 0.2093756348, 0.7086314559, 0.4830908477, + 2.0755898952, 0.0622914173, 0.9292717576, -0.4380646348, -1.6233458519, 0.1461371183, -0.5482233763, 0.7338901758, + 0.0389567427, 0.6998253465, 1.0116010904, -0.3618020415, 1.8255698681, -0.944807291, 0.1480549872, 0.9181790352, + 1.1242004633, -0.7497963309, 0.5569706559, -0.383071959, -2.8234889507, -1.1781505346, 1.4321072102, 1.2316467762, + 0.2388788015, 0.0512132496, -0.4228218794, 1.1188286543, 0.3400440812, -0.4093388915, -0.3253835738, -0.556640029, + 1.2506176233, -0.511993885, -0.7112380862, 1.1241469383, 0.2668454647, -1.7113490105, 0.2358381599, 1.1011041403, + 0.8496887684, -1.2886971235, -1.3477289677, -2.8305227757, -1.0628187656, -0.2909052968, -0.1643280834, 0.0555402003, + 0.5318995118, 0.5488132834, -0.3408282399, 2.4728338718, -0.0778830498, 0.2826209366, 0.3594366014, 1.1223710775, + -0.2526025772, -1.8722442389, 1.2654098272, -2.6454839706, -0.4887316823, -0.4427509308, 1.2608346939, 2.1664521694, + 1.1900120974, -2.3902049065, -0.6655550003, -0.1544005424, 0.5118381381, 0.0688272491, 0.3676896989, 0.1625170857, + 1.4110800028, 0.0116869053, 0.6106952429, 0.0455630608, -0.1926245689, -0.2303574234, 0.8177344799, 0.1466995478, + 0.0532553457, -0.6141367555, 0.5387769341, 0.029593993, -0.0525368638, 0.5687243342, 0.6703144908, -0.6449947357, + 0.3593075573, 0.7457771301, -2.0517790318, 0.0016169018, -0.0653042272, -0.1865885556, -1.469399929, 1.1893911362, + 1.0076799393, -1.4579092264, 1.3490563631, -1.6361253262, -0.5041018128, -2.0277647972, -1.4027677774, 0.4853744805, + 1.196611762, -1.9860762358, -1.1433326006, -0.4991798997, 0.8099403977, 0.9741308689, -1.1231752634, 1.2916612625, + 1.2223510742, 1.1004766226, 0.1277393401, 0.9839468002, 0.0020423641, -1.3422156572, 1.1989815235, 1.0622923374, + -1.0130317211, 0.0652642846, -0.5992264152, 0.4082034826, 0.0806819052, -0.3798908591, 1.2465872765, -1.0993893147, + -0.5118710399, -0.2986849844, 0.5246425867, 0.6732012033, 0.0628702417, -0.913842082, -0.9044297338, 0.0181843303, + -1.6680605412, -1.172490716, -0.883267045, -0.2367167175, -0.0361848995, 1.4360933304, -0.2679459751, -0.8920229673, + 1.0423166752, -0.0651038066, 1.7097898722, -0.954364121, -0.7677184939, 0.1742484719, -0.2672248483, -0.4275380373, + -0.1414251775, 0.9008878469, 0.8739157319, -0.3322092593, -0.5973111987, 0.2851661444, -0.1468812525, -0.290792942, + -1.0881502628, -0.6024230123, -0.5802869201, -1.2372754812, -0.4289747477, -0.5685067177, 0.9802915454, 0.0765238106, + 0.9593495131, 0.6458209157, -0.638489902, 0.6581201553, 0.4170886278, 1.3364971876, 0.8242484927, 1.4422096014, + -0.4826723039, 0.2676834166, -0.1370688677, -0.3821313083, -0.9061530232, 1.1765571833, 0.4614237249, 1.9140841961, + 0.0065699657, 0.4581893384, 2.2392342091, -2.1551437378, -0.650562346, 0.1773225814, 0.1001090482, 1.1466196775, + -0.5088146329, 0.9910753965, -0.6102650166, -1.6703640223, -0.5117351413, -0.6359770894, -1.0455538034, 0.3068882227, + -2.81392169, -0.7243748307, 2.3602602482, 1.1162489653, -0.5636335611, -1.3498125076, 2.0970036983, -1.6311956644, + -0.3248442113, -0.7526709437, -0.636038363, 2.2367043495, 0.8790027499, -0.4985416234, -0.4463484585, -0.719070375, + -0.3197208345, -0.1645631343, 1.6601192951, -0.0426488407, 2.3123860359, -1.5778800249, -0.0058000362, 0.1096969396, + -0.0175224114, 0.9351284504, 0.9580059052, -1.3353056908, 0.1352744251, 0.7962580323, -0.7297627926, 0.9289662838, + 0.7584497333, -1.0704288483, -0.141263172, -0.2476228029, -0.668230176, 0.0307615045, -1.4234244823, -0.762370944, + -0.936634779, 2.0120165348, -0.5410431027, -0.4628232121, -0.1133372635, -2.6215143204, -0.1878034025, -0.1376096606, + 0.2618097961, 1.3662329912, -2.2204368114, 0.8991046548, 0.7960936427, 0.408290416, 0.3135900199, 1.0021790266, + 2.2778322697, -0.6833299398, 0.282828182, 0.4902434647, -1.6065645218, -1.2876976728, 0.4138703048, 1.4634865522, + -0.8037552238, -1.8263963461, -0.1062341779, -0.4714684784, -0.2142926008, 0.8328797221, -0.2681073248, 0.4731663764, + -0.6831670403, 1.0777174234, 0.3799136877, -1.1204904318, -0.1482727826, -2.2189519405, 1.4719551802, 1.0429495573, + 0.2535926402, -0.9038581252, -0.2051886171, 0.2231454849, -0.9873346686, -0.1028130278, -0.949097693, 0.5669447184, + 1.3465336561, 0.5354964137, -1.4442919493, -1.3446625471, 0.1368197799, 0.3121242821, 0.6082185507, -1.9605544806, + 0.7699592113, -0.916199863, 1.6719350815, 0.0406786539, -0.2060671747, -0.3644065261, -0.4067469239, 0.649687767, + -0.4569232166, -0.4409435093, 0.1681868136, -0.8629373312, -1.1391000748, -0.5719874501, -0.6937422752, -0.3806343377, + 1.2496166229, 0.1289080679, 0.9666724801, -0.5838910937, 0.118635878, -0.7255809307, 1.3304361105, 0.2326592952, + 0.8757634163, -0.7049357295, -1.0692155361, -1.2293150425, 0.295987308, 0.0319055319, 0.1620924175, 1.4239611626, + 0.756678462, -0.3976113498, -0.4200448394, 1.8963367939, -0.5100295544, -0.1136146113, -0.7116947174, -1.1979464293, + 0.062881954, 1.6701619625, 1.3206782341, -0.3954262137, 1.6946469545, -0.184242487, 2.0869755745, 0.4656747282, + -0.9359200001, 1.0937289, -0.2609280646, 0.8597438931, -0.4747339189, -1.7674329281, -0.7370138168, 1.6124833822, + 0.8634741306, 1.2746123075, 0.4331390262, -0.2857427001, -1.2503889799, -0.4103792012, 1.2073097229, -0.2294325531, + 0.1557102054, 0.1661618203, 0.1306845248, -0.3510292768, -0.7382842898, -0.1517895609, -1.5608966351, 0.011345176, + -2.5729622841, -0.2821547389, 0.218286112, -0.0131761897, 0.454901278, 0.2538626492, 0.8881043196, -0.2298544347, + -0.0876468346, -0.3201176524, 0.2374811918, 0.8972510099, 0.4730105698, -0.6594987512, -0.0209075324, 1.3408588171, + 1.425974369, 0.6906683445, 1.4695892334, -1.7932443619, -0.3990622759, 0.388320744, -0.1653114706, 0.7263434529, + 1.0113916397, 0.7325154543, 1.0358587503, 0.2038902938, 1.6042402983, 0.0524286889, 1.002392292, 1.1868354082, + 1.618085742, 0.8422029018, -0.364919275, 0.612275064, 0.4988044798, -0.5457030535, -0.4046074748, -0.2460051328, + -2.1963894367, 0.2778351903, -1.2490707636, -0.599826932, 0.4359167516, 0.9332191348, -0.2432841212, 0.1132514253, + 2.0727136135, 0.7468464971, -1.4363973141, 1.655472517, -0.5935822129, -0.0301943701, -0.0096276281, 0.9447058439, + -1.1380391121, -0.3193050027, 0.3661886156, 0.7435558438, -0.1640613824, 1.1098930836, -0.3936080635, -0.4477424622, + -0.3403979838, -2.5856881142, 0.908218801, -0.8674103618, 1.4339728355, -0.8392519355, -0.5988446474, 0.1905030608, + -1.3781613111, 1.0868411064, 1.0486859083, 1.1246263981, -0.7191772461, -1.0842479467, -1.6448795795, 0.832852602, + -0.9384015203, -0.421794802, -1.3769412041, 1.9037914276, -0.5599355698, 0.1158174872, -0.1574285477, 0.4571927786, + -1.740403533, -1.8275996447, 0.7204089761, -0.2950896919, 1.4025130272, 0.2427419722, -0.0037648869, 1.3575364351, + -1.1893963814, -1.117893815, 0.3041092753, -0.8188020587, -1.1610109806, 0.2950367033, 0.0649628937, -0.426086396, + 1.3116868734, 0.5123817325, 0.3020256758, 0.1874590069, -1.5938930511, -1.7766227722, -0.2056816667, -0.1434836537, + -0.6319875121, -1.3853851557, 1.7522269487, 0.1705312729, 1.9834896326, 0.0428273194, -0.281368047, -0.0961206928, + -0.6106506586, -1.2427818775, 1.4810787439, -0.6395637393, 1.454415679, -1.0006572008, 1.0430054665, 0.2761348486, + 0.318027854, -0.5181749463, -0.0602431931, 0.0929836407, 0.4769335091, 0.3015520573, 0.5975839496, 0.6896985769, + -0.1892197728, -1.0921987295, -0.4295704961, 0.4336581826, 0.3824291527, 0.1809328645, -1.0461263657, -1.4477847815, + 0.6859626174, -0.764511764, 1.0940294266, 1.480203867, -0.9201808572, -1.0781209469, 0.9212292433, -0.3049114645, + -0.0715369731, 1.0498589277, 1.0016895533, 1.418211937, -0.5187898278, -0.1311899126, 0.9670145512, 0.5622414351, + 0.4447497129, 1.1318860054, 0.7751047015, -0.3009999692, -0.4801048636, 0.0647643581, 0.9612099528, 0.8127611876, + 0.6242893338, -0.0070319353, 1.0763334036, 0.3677817285, -1.3627214432, -1.0657974482, 0.831104219, -1.393512845, + -0.2092558742, 0.4993962944, -0.960169971, 1.0647552013, 2.2043251991, 0.3423570991, 0.1696930826, -0.2994166017, + 1.0733228922, -0.3528176844, 0.4736300111, -0.5256693363, -1.5099061728, -0.2726048827, 1.8399487734, 1.0151726007, + -0.4483799636, 1.0994441509, -1.8038136959, 0.4645211697, 0.301191926, -0.7694646716, 0.9885981083, -0.3152141571, + -0.8028303981, -0.1730686873, -0.6892525554, -0.9899894595, 0.626301229, 1.6653257608, 0.3095535338, -0.5246341228, + 0.0186689477, 1.679993391, -0.5161258578, 1.8456840515, 1.9402329922, -1.664390564, 0.7645756602, -1.0416288376, + 1.8423246145, 0.5390047431, -1.9061768055, 0.8301377892, 1.0769793987, 0.6682855487, 0.9632487297, 0.64516294, + 0.0955077112, 0.6230443716, -1.112595439, -1.1393494606, -0.2665373385, 2.2958316803, -1.8586397171, 0.1168465689, + -0.0136828171, 1.4055063725, -1.3613090515, 1.2799606323, -0.8697892427, 2.4187178612, -1.5788184404, 0.5349386334, + 0.4891916215, 0.6985910535, -2.4071002007, 0.6912989616, -0.1731216162, -0.3386763334, -0.6762531996, 1.8666601181, + -0.0154876197, 1.4744048119, 0.8798419833, -1.8359698057, -1.4010410309, 0.1690005064, 0.4600860775, -0.2688275576, + -0.1073251069, -0.6607923508, 0.0372763202, 0.120187901, -0.1509473771, -1.0607008934, -1.1784601212, 0.083729513, + -1.1999645233, -0.7227930427, -1.1312910318, 1.4536602497, -0.3281475008, -0.282088995, -1.9610961676, -2.2980158329, + 1.6167727709, -0.9151739478, 0.791405499, 1.4067481756, 0.5194048285, 0.877759099, 0.5513826609, 0.2247539461, + -0.0472301021, 0.9914721847, 2.1558043957, 1.8301255703, 0.1900593936, 0.2965781391, -0.0984601229, 1.0304844379, + 0.4766424894, -0.7833252549, -0.5008711219, -0.5573242903, 0.4439268708, -3.2847006321, 0.4752749503, 0.5018771291, + 0.222138226, 0.7174639702, -0.7699761987, 0.3723175824, 0.5160827041, 0.428401202, -0.8318826556, -0.3510650694, + 0.6850978136, 0.6224149466, 0.146541819, -0.388050139, 0.1311548799, -0.3739495575, -0.0982051417, 0.0241817795, + -0.2103700042, 2.3744344711, -0.5839608908, -0.1087427288, -0.249864012, -0.0379346982, 0.3635368645, -1.4021166563, + -0.3856891692, -0.5266512036, 0.5923498869, 0.5811980963, -0.1913233995, 0.2475237846, -0.6341478229, -0.4015057981, + -0.2930896282, -1.6198561192, -1.5492149591, -0.4098072052, -1.1009782553, 0.0696988776, 2.2207129002, 0.3850325644, + 0.1232785955, -0.136088863, 0.5543779135, -0.0335183479, 0.1661666334, -0.9750319123, -0.3781283796, -0.6851177812, + -1.3397881985, 1.8235151768, 0.7576472163, 0.4756061435, -0.1756661981, -0.7518137693, 0.883395493, -0.1723460406, + 1.4779287577, 1.1817060709, 0.657663703, 1.7607759237, 0.3329871595, 0.384115696, -1.6105310917, -3.4629151821, + 1.5630116463, 0.1894923598, 1.1110873222, -0.4295303226, 0.0688258111, -2.6791574955, -2.3411090374, -0.6443280578, + -2.5961453915, 1.8770301342, 1.6789271832, 1.1087728739, 0.4900375903, 1.0108305216, -0.7254547477, -0.8507792354, + 1.0462187529, -0.5669525266, 1.7076981068, -0.2117697448, -1.2549630404, 0.7878744006, -0.6559647918, 2.6261720657, + 0.0378729068, -0.9183604121, 1.5393013954, -0.1139022857, 1.5634179115, -0.0301232282, 0.0856970623, 0.2333744764, + -0.3873595893, 1.9680051804, 1.4474378824, 1.2159805298, -0.0786215439, -0.8479925394, 0.374147743, -1.3048787117, + -0.6006184816, -0.1725184321, 0.3311712146, -0.2673325241, -0.3190022707, 0.5827477574, -0.7233198881, -1.2103803158, + -0.0765999481, -1.9542196989, 0.3852671683, 1.4858161211, -0.0310763177, -1.7405352592, 0.8110358119, 0.1677609235, + -0.3663225472, 0.4820788801, 2.043097496, -0.2657999992, -0.4802150428, 1.6891940832, 0.6045791507, -0.2234309465, + 0.8571979403, -0.2686817646, -1.530780077, -1.0786039829, -0.9064611197, -1.1571456194, -0.0541361533, -0.5406714082, + -0.2749684751, 0.1239802092, -0.5381905437, 0.6174876094, -0.9688651562, 0.9094956517, 0.2015793473, 2.0235207081, + 0.26425156, -0.710765481, 0.6661833525, 0.7415869832, 1.9120591879, 0.998932302, 0.4370322526, 0.5388150215, + 0.2214304805, -0.438877672, 0.0455226041, -0.9726260304, 1.4213956594, 0.7784917951, -0.8738764524, -0.6479167342, + 0.947870791, 1.3753795624, 0.0296977572, 0.8786270618, -0.5038436651, 0.1264273673, -1.8705068827, 2.3100185394, + -0.8938060999, 0.3092682958, -0.295812279, 2.1298017502, 0.2210101187, 0.8279167414, -1.3819217682, 1.0468441248, + 0.7928908467, 0.615198493, -2.1460978985, 0.0850671232, -0.2827851772, -1.4269472361, -0.7818253636, 2.2002530098, + -0.9858335257, 0.5671643615, 1.5863406658, -0.0924895555, -1.0210804939, 0.6836526394, -2.2170433998, 1.1493161917, + 0.3413541317, -0.2154352516, 0.5662803054, -0.7847980857, -0.479149282, -0.8131125569, 0.8970845938, -0.4572354853, + -0.7225107551, -0.5756103992, -2.2434556484, 1.0185506344, -0.5351034999, -1.3657653332, 2.0675470829, -1.0386697054, + 1.4762983322, -0.798207581, 2.0018270016, 0.2635194659, 1.2353080511, 0.4287237525, 0.0174695142, 0.9563567638, + 1.6330941916, 1.6011214256, -1.2320027351, 0.1984476298, -0.9122123718, 0.7111468911, 0.7488287091, -0.3852639496, + -0.1148628294, -0.2698810697, -0.3712545931, 0.2244575918, -0.0854918435, -0.0593928993, 0.1030734554, -0.4511945546, + 0.54798311, -0.6317163706, 0.6489620805, -1.0175821781, -0.1811434031, 1.5832920074, -0.6779805422, 1.3851190805, + -0.3345347941, -0.104651317, -1.6282833815, -0.939248383, 0.272808075, -0.0925905555, 0.2160407156, 0.6644548178, + -0.2666618228, 2.6946973801, 0.0434410423, -0.6470096111, 1.7980229855, -1.2989336252, 0.3984160423, 0.6778487563, + -0.0981895402, 0.9798938036, -1.2538865805, -1.436040163, -0.590284586, -0.8581837416, -0.2199495137, -0.3045339286, + -0.5929993987, -1.2001744509, 0.4193471968, 0.4130449891, -0.0643541962, -0.3918884695, -1.9008547068, -0.6400154829, + -0.0310537405, 0.3388310373, 0.7863161564, -0.7796239853, -0.691470027, -0.8911319971, -0.1382533163, 1.1118685007, + -0.6569674015, -0.1794133633, -0.5717086792, -0.4314243793, 0.735769093, 0.2798558176, 0.8829190731, -0.3237231374, + -0.6520662904, 0.2529103756, -0.3372556865, 0.5908755064, 0.5626513362, -2.2970151901, -0.2403149754, -0.3434230983, + 0.6380447745, -0.5477387309, -1.4343986511, 0.8501843214, 0.6045268774, -0.5088319778, 0.1553441733, 0.7751315236, + -0.556430757, 0.0922820196, 1.0430363417, -0.0166171789, 0.0004913778, -0.3558220565, -1.0550065041, 0.5611869097, + 0.5342825055, -0.030486932, 0.2164323777, -0.186460495, 0.030179115, -1.0917770863, -0.1840087622, -0.0184875894, + -0.6151685119, 0.3353316188, -0.1206564009, 0.0764194801, -0.2989043295, -1.5547710657, -0.6537920833, 1.8045568466, + -0.1564288735, -1.1329820156, 0.5988346338, -1.8747942448, 1.9920927286, -0.2383167297, -0.005037291, 1.7662442923, + 0.4502291381, -1.6901876926, 0.2092062235, -0.3719630539, -1.4031659365, 0.818697989, 0.3760634363, -2.2954051495, + 0.5926311016, 0.0171566214, 0.2273662835, -0.4911201298, 0.2143833786, 0.5893830061, 0.1842756271, 0.9189839959, + 1.7500014305, -0.022472905, -0.038039729, 0.3788199723, -2.2946538925, 1.7362905741, 0.5558519959, 1.1632210016, + -0.3035589755, 0.7126848698, 0.2978425324, 1.0315711498, 0.43825984, 1.0446311235, 0.1455101073, -0.7554751635, + 0.1581776291, -1.165858984, -1.2868412733, 0.7790217996, 1.1975550652, 0.5179507136, 0.416786164, -0.1070448756, + 0.8847790956, -2.1269643307, -2.1746633053, 0.980933547, -1.8558607101, -0.0589242019, -0.3949842155, 0.1342334598, + -1.9917581081, 2.0874900818, 0.2646040916, -0.3620138764, -0.4476041794, -0.0092560723, 2.7727761269, -0.9875227213, + -1.1261665821, 0.8644894958, 0.0200013202, -0.5129029155, 0.473431021, -0.0488065369, -2.4048309326, -0.156499967, + 1.1135571003, 1.139706254, -1.4627355337, 0.7660913467, 1.1386791468, -1.7050300837, -0.8706223369, 1.374735117, + -2.1854331493, -0.7849680781, 0.5419611335, -1.3487257957, -1.3122342825, 0.1711963266, 0.6263733506, 0.1525226533, + 1.4732654095, -0.0650783703, -2.6287243366, 1.1032720804, -0.2081544995, 0.277385056, -0.8050147891, 1.7604209185, + -0.4776040614, 0.3857266903, 1.1773180962, 0.534604013, 0.7014524937, -0.2645107806, -0.1771366298, -0.8814995885, + 0.1855238378, 0.5930702686, 1.321105957, 0.3621626794, 0.4415043592, 0.9820915461, -1.1620858908, -1.5575093031, + 2.3486135006, -1.4105807543, 0.5415712595, -0.3308941722, -1.2917026281, -0.1719277054, 0.1799248606, -0.0432348475, + 0.2673465908, 0.194612354, 0.8462187648, -0.8374105692, 0.1203589514, 1.9621579647, 1.5041606426, 0.632578373, + 0.4140176177, -1.5472197533, -0.8060904741, 1.3864337206, -0.7399890423, 0.3658272028, 1.8032287359, -1.0524270535, + 0.2010727376, -0.5947147608, -0.4959990084, 0.5370004177, 0.4044150114, -0.5982482433, -1.7088147402, -1.0533634424, + 1.2031201124, -0.1458389908, 0.5778471231, 0.096505478, -0.5388431549, 0.8363574147, 0.4032280743, -0.2996425927, + 0.0294992831, 1.918603301, 0.931645155, 1.4993157387, -1.7577295303, 1.2611371279, 1.0125068426, -0.2110064179, + 0.6125735044, 0.786341548, 0.5930656195, -0.4154962897, -0.7229909897, -0.7670542598, -0.4934742451, -1.7241714001, + 0.9628956914, 1.395590663, -0.4624428153, -0.7550997138, 0.2275715172, 0.8299591541, 0.9396640062, 0.9205953479, + -1.9562321901, 0.534733355, -0.3697306812, -1.0418801308, 0.7764693499, -0.5618635416, -1.3113641739, -1.2335938215, + 0.7353008389, 0.1957557499, -0.7724125981, 1.1139376163, 1.351878643, 0.0805120543, 1.5585693121, 0.5469241738, + -0.505898416, 0.8069629669, -0.7987787724, 0.1504934281, -1.6120203733, 0.0503893793, 0.7792242765, -0.3512535393, + 0.0884182081, 1.1663037539, 0.6744574904, -0.3506546021, 1.3014886379, -1.0340659618, -0.3779429495, -0.9123903513, + -0.3398987949, 1.0012029409, -0.2418974638, 0.832235992, 1.2388926744, 1.4504948854, -0.084682852, -1.9022624493, + 2.3461015224, 1.576161623, -0.4713822901, -0.2990472019, 1.4670183659, -1.4660875797, 0.1758549064, 0.5109443665, + -1.3963633776, 0.3641264141, 0.4785705507, -0.7390723825, -0.1571729332, -0.0894001424, -0.8202293515, -0.0035593198, + -0.3045049012, -0.6465057135, -0.5934047699, 0.8569859862, -0.4925061762, -1.3001301289, 0.1930694282, 0.0667027608, + 1.0578979254, -1.4051775932, 0.5545969009, -1.9266557693, -0.3564795852, 1.1653716564, -0.6970770955, 1.0272433758, + 0.1583375931, -0.3123612106, -0.9408250451, -0.0537493266, 0.4240416884, -0.1350065917, 0.4084877074, 0.0649588257, + 1.2394356728, 0.0960153639, 1.5031138659, 0.2776180506, 0.7171580195, 0.869905889, -1.8727498055, 0.391726315, + 1.8253725767, 0.2035031319, -0.3448802531, 0.8481007814, -0.4494965672, 0.8984521031, -0.314597249, 0.1103251651, + -0.2218849212, -2.0152313709, 1.2233344316, 0.6462559104, -0.185182482, 0.5452057719, -0.1294742972, -1.738134861, + 1.4482873678, -0.0049621151, -1.7968306541, -0.4029459059, -0.3125780225, 0.9872809052, 0.7336838245, 0.1305475235, + -2.8211119175, 1.8661111593, -1.2324781418, 0.2694059908, 0.9574196935, -0.4235167801, 1.3931517601, -0.5280845165, + -0.7973154187, -0.1673012674, -1.2300739288, -0.1831893921, -0.9138897657, 0.5805856586, -0.0222635027, -0.4146025181, + 0.9250200391, 1.16545403, 0.1428458989, 2.0506296158, 0.8355020285, 0.6833344102, -0.6771549582, -0.139218092, + 1.3074415922, 0.6128761172, 0.9603426456, -0.9988200068, 1.3938060999, 1.4483420849, 2.3093905449, 0.8961781263, + -0.4832390547, -2.5290327072, 0.6685495377, -0.9248668551, 0.5174524784, 1.562430501, -1.0747776031, 0.0684774816, + 1.2940604687, -0.2854608595, 0.8098345399, 1.0701078176, 0.0960196704, -0.7887099981, 0.3971018493, 0.3612840474, + 0.0241373852, -0.2990406454, 2.1660528183, 1.1026490927, -0.9874019027, -0.0388727337, 0.2446159571, -0.5563523769, + 0.2279099971, -1.0013686419, 1.0143290758, -1.5527062416, 0.8506965041, 1.2558175325, -0.2148320824, 0.8770825267, + 1.1198774576, 0.3611235023, -0.2671338916, 0.0430668853, -0.165392518, -0.9529352188, 0.0276208688, 0.1230975538, + 0.8873025179, -0.1752104014, 0.2513716519, -0.23484914, 2.1551887989, 0.7347248793, -0.4261212051, -1.4302924871, + 0.9446163177, 2.5085418224, 0.472451061, -0.1860275865, -0.5170155168, 0.8182741404, 0.5141733289, 0.032766033, + -1.5501236916, -1.9620072842, -2.0062484741, 0.9044618607, -0.1077708378, 0.6405754089, -0.5198460817, -0.1346986145, + 1.0445538759, -0.0471237898, 0.6623798609, -2.9060950279, -2.2693784237, -0.9272943139, -0.7652207613, 0.6250887513, + 1.0728448629, -0.3229994476, 0.6231277585, -0.8498978019, -0.7956701517, 0.2162239701, 0.3675494194, -1.1451079845, + -0.965397656, 0.2594099939, 1.9920861721, -1.0531497002, 1.016400218, -2.6073150635, 0.1700922847, -0.6301968694, + 0.2218909413, -1.0393652916, 0.1635822654, -0.8220946193, 1.21322155, -0.2270285189, -0.0932268277, -1.9150704145, + 0.5888198614, 0.8222286105, -0.924788475, 0.592399776, 1.2341030836, 0.2066896558, 0.0557046607, -0.412302196, + -0.5475937128, 0.0371494219, -0.4496034384, -0.3558986485, -0.0194285549, -0.2425739467, 1.0339695215, -0.9851918221, + -0.5976397395, -0.8841294646, 1.6174160242, -1.9489552975, 0.7389916182, -2.6600670815, 0.4461476505, -0.8088853359, + 0.8462277651, -0.6602464914, 1.6914891005, -0.2079225481, 0.1770420671, -0.1914528757, 1.8777939081, -1.0028346777, + -0.3571747243, -0.5823912621, -0.3817023933, -0.7646320462, 0.3977974951, 2.1370313168, 0.022801986, 1.0142006874, + -0.509018898, 2.4213712215, 0.2384048551, 0.4153284132, -0.5815684795, -0.3279374242, 2.0014894009, -0.225949645, + -0.7761495113, -0.7924335599, -1.6703323126, 0.2091366947, 1.5131661892, -0.2143556774, 0.4151538014, 1.4834935665, + 1.0899714231, 0.3293718398, 2.0831754208, 0.1978849769, 0.2735405862, -0.6502671838, 1.2972633839, 0.1335616857, + -0.3772461116, -0.2008029372, 0.0285819676, -0.5361480117, -0.2193754762, 0.2928190529, 0.1224274337, -0.988501966, + 0.0658708662, -1.2322801352, 1.8402957916, 0.6772176027, -0.7635117769, -0.2598209679, -0.975230217, -0.936865747, + 0.5052095056, -0.549377501, -0.7561277747, 1.1606968641, -0.8948866129, 0.7956269383, -1.0711044073, 0.4195824265, + 0.4358394146, -0.5332286954, -0.7573457956, -0.6774635911, -1.6076130867, 1.3072478771, -0.5927714705, 0.1389958411, + 0.7185947895, 3.7669422626, -0.0290491264, 1.9280542135, -0.7334471941, -0.6078340411, 0.8206052184, -0.7893049717, + 1.1871837378, 0.5642030239, -0.4392837882, -0.5427054763, 1.4480323792, 0.9012516737, -1.447822094, -0.2742679417, + 0.3881469667, -0.7936916351, 0.9068234563, -0.269092679, 0.6635046005, -0.819481492, 0.8768583536, -0.2403390408, + -0.4118672311, -0.1585797518, 0.7974650264, -1.6701654196, 0.2306298316, 1.2565150261, 0.7238920927, 0.2698653042, + -0.1637378335, -1.1882640123, 0.1818947494, -0.7447010875, -1.3373509645, 2.0189678669, -0.2577935159, -1.8308736086, + 0.5547665954, 0.5500036478, -1.5290178061, 0.2087140232, -2.4184942245, 0.1614990234, -0.5703580976, -0.3850896358, + 0.365735352, -0.6663386226, -0.5914227366, -0.159402892, 0.5978386998, 0.6462613344, -0.510058701, 0.9332790375, + 0.1504412591, 2.2288496494, -0.0264447983, -0.3791185021, -1.087420702, 1.3430011272, 0.1849463731, 0.1412463486, + 0.4610200822, -0.4325022697, -0.1002900004, 0.4237989783, -0.0037172488, -0.7439040542, 1.3982913494, 0.6422342658, + 0.2297436744, -0.3174774945, -1.8848919868, 0.4019989967, -1.0464760065, -1.4771206379, 0.980802238, -1.1731636524, + -0.5929113626, 1.4529060125, 1.8952001333, 0.8750221729, -0.8161361217, -0.8773684502, 1.5960000753, -0.0505642667, + 2.1601340771, -0.545307219, 0.0826762095, -0.7931586504, -0.4187310934, 0.8851934075, -0.0452485234, 0.7194694877, + -1.1667468548, -0.8115680814, 1.0736287832, -0.0052045393, 0.2035568357, -0.2131816298, -1.407793045, 0.4754085839, + -1.6127541065, 0.9811051488, 0.3119699657, 3.0805301666, 1.3608472347, -0.4485848546, -0.5215060115, 2.0166110992, + -0.3327984214, 1.2407314777, 0.6968078017, 0.0539997965, 0.0699510276, -0.1169878095, 0.8041012883, 0.1101086438, + 0.033701539, 0.641014576, 1.6915745735, 0.0526624918, -0.2966575623, -2.1406083107, -0.8456923366, 0.7050642371, + -0.0481108874, 0.167725578, -0.3968006372, -0.2574980557, 1.8308932781, 0.7751365304, 1.786462307, 0.4759546816, + 0.3503513336, 1.3485484123, -1.1443794966, 0.4006808996, -0.9962391853, -1.1875445843, -0.9584485888, 0.6679587364, + 0.8440365791, -1.6700847149, -1.6379746199, 1.4682731628, -0.1765896976, 0.0353947654, 0.1196492165, 2.1720237732, + 1.5219050646, 0.2371326536, -0.2789554, -0.6909232736, -0.1486644447, -0.7018318176, -0.637270093, 0.4759524167, + -0.689399004, 1.1211477518, -1.20025599, 0.2479523867, -0.1926452816, 1.7607023716, -0.566452682, -1.9813816547, + 1.9055066109, -1.4104237556, -0.557415545, -1.0331728458, -1.3837974072, 0.2761999965, -1.9508929253, -0.0858562961, + -0.4836938679, 1.6077718735, 0.7905129194, 0.2117312104, -0.405772537, -0.2354757786, -0.2259673476, -0.3836088479, + 0.3403173387, -0.2910141647, 0.2482576072, -1.55595994, 0.3220538497, 0.7779824138, -0.2298941314, 0.7137753367, + 0.0410445072, 0.8990941048, -0.059165474, -1.2160205841, 0.727684617, 1.3633673191, 0.2227507532, 0.0442474857, + -0.0720062032, -0.4402479529, -0.2421229333, -0.1403012723, -0.8662195802, 0.7516864538, -0.526076138, 0.3029883206, + -0.1204497144, -0.8628455997, 0.671194613, -1.5811458826, -1.0912187099, 1.574988246, 0.8000087738, 1.4918595552, + -0.0239492729, -0.6851808429, 1.6194691658, -0.6268472075, 0.7402077913, 0.3828008473, 0.2770670056, -1.6399253607, + -0.7085242867, -0.4483987689, 1.1894177198, 0.1778671741, 0.7329412103, 0.2275713235, 0.9885006547, 0.336589843, + 1.0390247107, -0.3508904874, -0.7135981321, -0.5375814438, -1.8914824724, -0.8740919828, -1.0973818302, -1.7287472486, + 1.2013589144, -2.6296367645, 0.7503966689, 0.1960070133, 1.0780261755, 0.5065403581, -0.5458502769, 0.3345984817, + 0.1483134329, 0.9152549505, 0.1478965133, 1.5200810432, -0.7546271682, -2.1418476105, -0.2708940506, -0.2287595272, + 0.6522660851, -0.2509295642, 2.2269825935, 0.5684635043, 1.0577745438, 0.7382932305, -0.0012409586, 1.4664787054, + -0.1449816078, -1.0437244177, 0.6076418161, -0.4137753546, 1.8593870401, -1.4749391079, 1.8089412451, 0.0769915134, + 0.5412765741, 0.3424822688, 1.3275287151, 0.1800303906, 0.0366178341, 0.3738724887, -0.7425840497, -0.096795328, + 0.6599724293, 1.0047409534, 0.9127472043, 0.5290979147, -1.2235962152, 1.8528863192, -0.3413074315, -0.302752614, + 0.4114413261, 0.9746417403, 0.1835276186, 1.0362179279, -0.6989639401, -1.2286016941, -1.2848297358, -0.9485433102, + 1.5757834911, 0.2003630102, 0.3445673585, 1.0008212328, -0.034992177, 3.7082657814, 0.829826355, -0.6615275145, + 1.3744132519, -1.6828603745, 0.5283031464, 0.6071580648, 2.1209676266, 0.9397947192, 0.5499040484, 1.2169115543, + -1.5446734428, 0.0012747148, 1.77346766, -1.0784699917, -0.9334080815, -0.3895108104, -0.4134129286, 2.5833759308, + -1.1176213026, -0.5504791737, 0.867528975, -0.5212416053, 0.4319742918, 1.1117717028, -1.8729016781, -1.6570641994, + -0.9629516006, 1.2397440672, 0.0037459065, 1.0992046595, 0.0913702697, 1.1402840614, -1.0717334747, -0.9748516679, + -0.2703653872, -1.298052907, 0.6257337332, 0.6659516692, 0.3891419768, 0.8163871169, 1.4753880501, -0.2891272604, + -0.5772545338, -0.3888491094, -0.7375437617, 0.1387289315, -0.0836863145, 0.1055305451, -1.0039715767, -0.2395810485, + -1.6525434256, 1.6949305534, 0.3663100302, -0.7106671929, 0.3623050153, 0.1398703009, 0.0709123462, 0.4497546256, + -0.4463917315, -1.8335397243, 0.1431326866, -0.5487794876, 0.2520763278, -0.4617098868, -0.6493166685, 0.8026529551, + -1.4981682301, 1.4404788017, 0.2838287055, 0.7307789326, -0.5151305199, 0.7872204185, 0.8811286688, -0.1221335679, + -0.0872639865, -1.3045835495, -0.4357743859, 2.2551152706, 0.2483468205, -1.9551292658, -0.418840915, 0.0355005972, + 0.7761195302, 0.5764486194, -0.911421597, 0.4186478853, 0.0519385114, -1.37200737, 0.9566460252, 1.0162568092, + -1.284922123, -0.1405265629, 1.1921300888, 2.2774107456, 0.6626639366, 1.2861585617, -0.4691481292, -0.5023907423, + -2.0549042225, -0.595403254, 0.6965740919, -0.0113108791, 0.9470972419, -0.4827988446, -0.7364525795, 1.5049593449, + -0.5338101387, -0.599999547, 0.2748598456, 1.2512134314, 1.3383157253, 0.8594609499, 0.2186160684, 0.7017844915, + -0.4627053738, 0.0034496156, -0.1348692179, 0.3913027644, -0.7634017467, 1.2350702286, -0.2394351661, -0.3701135516, + 0.5651393533, -0.0991172194, -0.002540621, 1.0179543495, -1.3121225834, -0.4948684275, 1.259996295, 0.161628142, + 0.6271054745, 0.3267571032, 1.7896078825, -0.1520906836, 0.7437182069, 0.1602447033, -1.1462504864, 0.7538537979, + 0.1994169801, -1.5422637463, -0.1115837023, -1.1347322464, -1.56034863, -1.3231898546, -0.5864630938, 0.2438378185, + 1.0190917253, -1.4585080147, 0.2916617692, 0.1212151349, 1.8103116751, 0.0997496024, 0.8982300758, -0.6879515052, + 1.4924706221, -1.4564908743, -0.7765069604, -0.9859484434, 0.2000730485, 1.2155988216, 0.0159493014, 1.4958109856, + 0.181131795, 0.5959467888, -1.3172075748, 0.2131920159, -1.2470915318, -1.26930058, -0.5841072202, -0.0466538183, + 1.4094572067, 0.7706953287, 1.0238623619, 0.5501586795, -1.9324756861, 0.8537841439, 0.0228950474, -0.9649195671, + -0.1006398126, 3.7234966755, -1.4024811983, 1.4509285688, -0.0061165541, -2.3573803902, -1.7164319754, 1.436712265, + 0.4027778208, 2.0568888187, -1.4577573538, 2.1596512794, 0.0112678483, 0.4823514819, -1.0151923895, -0.2748779655, + -0.1498049647, -0.9562303424, -0.4943629801, 0.9176456332, -1.1512298584, -0.6620446444, -0.7779641151, 0.3872365654, + -0.9894063473, -0.7422857881, -0.3691743314, -0.7506567836, -0.1978930682, -0.8630726337, 1.1947299242, -0.6482266784, + 0.6255560517, 1.0509376526, -0.1812707335, 0.3463947773, 1.2976157665, -0.3504452705, -0.4335976541, 1.2804650068, + -1.0233523846, -1.5230047703, -1.8323204517, 1.0930193663, -0.9281481504, -0.5940221548, -0.7265738249, -1.2965354919, + -1.0185232162, 0.7093110681, 1.1391676664, -0.7207520604, 0.0884170756, 0.2882946134, 0.5193282962, -1.4298005104, + -1.608170867, -1.2717075348, 0.4682482779, -0.0170615129, 1.7580053806, -0.9173281789, -0.4693002105, -1.9680835009, + -0.329924345, 1.0726827383, 0.8806637526, -0.7417538762, -0.6689109802, -1.7082813978, 0.4313643873, 0.0347285047, + -0.9227795005, -1.4209941626, 0.7686933875, 1.9805835485, -0.8032012582, 1.6413334608, 1.3727482557, -1.029957056, + -1.0851159096, 1.5018138885, -1.3383134604, 0.9689275622, -0.9780363441, -0.4031761587, -0.3334401846, 0.6129492521, + 0.1054987162, 1.3304780722, -0.1858203262, -0.4620821774, -1.9098011255, -1.3124620914, -0.7047039866, -0.725270927, + -0.1312124729, -0.9187059402, 0.6097781658, 0.2633499205, 0.6997118592, 0.8780248761, -0.1637497842, 0.2091602236, + 0.5623223186, 2.0462377071, -0.8705199957, -1.1179158688, -0.5697802305, -1.0332211256, -0.301356107, -1.1498878002, + -1.2747392654, -0.5573811531, -0.4904537797, -0.7212755084, 0.3405832052, 0.2075432539, 2.3557858467, -0.3203197718, + -1.0107301474, -0.4470166564, -0.8744552135, 0.9583758712, -0.3872155547, -0.3068799078, 0.2179597914, 0.5574518442, + 1.4925589561, -1.0170717239, -0.7130813599, 0.1082530543, 0.7955113649, 0.427572459, -0.7770849466, 0.3904846013, + -2.1188902855, -0.8035373688, -1.8661222458, -1.3831884861, 1.5261973143, 0.9782083035, 2.0999190807, -0.9385385513, + -0.7025492191, -0.5098134279, -0.0868382528, 0.6528349519, -1.4956269264, 1.7219619751, 0.6622504592, 0.0382152312, + 0.461432904, 0.5472880006, 0.5798900127, 0.5045868754, -0.6498355269, -1.9459872246, 1.3929944038, -0.6809290648, + -0.2962422967, 0.0108508496, -0.9638430476, -0.9484646916, 0.5165789723, -0.16406703, -1.7002995014, 0.8765365481, + 0.1269982159, -1.2878123522, 0.6062132716, -1.5158621073, 1.2426468134, 0.0607079677, 0.492431432, -0.1854637265, + -0.1353620142, 0.2781190872, 0.2474597394, -0.9971805215, -1.0900882483, -1.0746543407, -1.8340034485, 0.3812614679, + -0.8598755598, -0.1040497944, 1.3925131559, 0.3986272812, -0.0415031575, -2.3675251007, -0.0305877812, 1.6660884619, + -0.107064873, -0.5445333719, -0.7710431218, 0.3810178041, 0.254781276, 0.0593349338, -1.8837507963, 0.5730901957, + -1.0793691874, -0.414506644, 0.8921239376, 1.0510808229, 1.2406498194, 0.1838686913, 0.28704983, -1.5952960253, + 0.3279765248, -0.4117076099, -1.3453356028, -1.2739416361, 1.5920748711, 0.5261922479, -0.0942941159, -1.0936295986, + -0.6000131369, 1.055436492, 1.1460963488, -0.8146736026, 0.8606137037, 1.5689191818, -0.596134901, 0.0758933052, + -0.3385274708, 1.3630273342, -0.5600120425, 0.9728752375, -2.6392047405, 0.3673083484, 0.990062654, 0.330445379, + -0.1471444517, -0.2834138274, -1.0353995562, -0.5525274277, -0.5576259494, 0.1510661095, -0.2260467261, 0.2252246886, + -0.6449528933, 0.5770357251, 0.693538487, -0.1395560056, 0.2972361147, 0.1321164519, 0.164740786, 0.3600349426, + 0.2307815105, -2.8135678768, 0.0207150485, 1.1604722738, -0.6801362038, 0.8473317623, -1.2867816687, 0.9362281561, + -1.0985594988, 0.3639356196, 0.0338978171, 1.3219554424, 0.1933799237, -0.4506433904, 0.8257185221, -0.2247683406, + -1.3679728508, 1.0385216475, 0.9364742041, -0.6909128428, 1.5373262167, 0.6860220432, 0.4178827405, 0.6212495565, + 0.4344584346, -0.8601510525, -0.321854651, -0.8268820047, -1.5539178848, -0.0130258258, 2.2126760483, 1.7009296417, + 1.0740090609, -0.3324290514, -0.8985465169, 1.4576840401, 0.4782959223, -0.3509194255, 1.1262203455, -1.2219204903, + -0.2200453132, 1.3531450033, -0.1954530925, 2.3975813389, 1.8100578785, -0.5661913753, 0.1861822009, 1.3492763042, + 1.3133230209, -0.6185108423, 1.3017319441, 0.9068949223, -1.0815957785, -0.4340805113, -0.3503829241, 1.4641578197, + -2.056978941, 1.0820784569, 1.7439060211, 1.824860096, -0.7774598002, -0.4939185083, 1.0127602816, 0.7717211246, + -0.336789757, -1.2080198526, -0.6399074793, 1.1590770483, -0.1210201681, 1.1723109484, 0.8146342635, 0.1039312407, + 0.8836551905, -0.59245646, 0.1072652787, -0.397493571, -0.2205309421, -1.1659206152, -0.8362118006, -0.8025512695, + -0.2125316709, 0.7141345739, 0.629503727, 1.1987661123, 0.1260221899, -0.1531082541, -1.0310268402, 0.0731412917, + -0.1965200156, -0.4568440616, 0.805356741, 0.2883935869, -0.6044726968, -0.1260431856, -0.0165450405, 0.6680634618, + -0.2518533468, -1.0752733946, 0.3414058983, -0.778150022, 1.3908762932, -0.4280652702, 0.3502120078, 1.5740196705, + 1.5462254286, 1.3005847931, 0.2207820117, 1.2206280231, 1.2158526182, -0.4125004411, 0.3144003749, -1.4685095549, + -0.0741400197, 0.5391044617, 1.2650680542, 1.1636080742, -0.6286639571, 0.3842039406, 0.4505725801, 1.3273755312, + -0.7348456383, 0.7658395767, -0.4287714362, 0.3170690536, -1.6846287251, 1.2574837208, 2.2304196358, 0.1366726011, + 1.1004315615, -0.176546976, -1.1436213255, -0.4769022167, -0.0776945502, -0.5553138256, 0.6878874302, 0.7855275273, + 1.6607589722, 1.035887599, 0.4534233212, -1.6446279287, -0.197626695, 2.1636257172, -0.7871826887, -0.2852320671, + 0.4802152514, -1.8419892788, -0.201628685, -0.0867040604, -1.064545393, -0.8415598869, 1.5475199223, -0.3730809987, + -1.4787642956, 0.2056966722, -0.3578105569, -0.110974364, -1.2149100304, 1.2062696218, 1.3023071289, 0.9274048209, + -0.7516996264, -1.3269295692, 0.3645735383, 0.2758433521, 1.9448007345, -1.4305678606, -0.0758651718, 0.0477598943, + 0.7821953893, -0.5015829206, -1.6125231981, 0.1059435233, 0.6842874885, 0.9025937915, -0.6946648359, -0.218394354, + -0.3142189384, -0.0116561214, 1.1320439577, 0.6315576434, -1.1208635569, -0.3343107104, 0.5499612093, 0.8175386786, + 1.5596295595, 0.5662127733, 1.511939168, -0.1291352212, -0.1208290309, 0.591481626, -0.8418577313, 2.0425741673, + -0.2564697862, 1.2515211105, 0.636874795, -1.1409413815, -1.0605794191, -0.1664215922, -0.925919354, 2.5111291409, + -0.0861898288, -2.0625565052, 0.6647928357, 0.0328417681, 0.5346663594, 1.9692085981, 0.4651908278, 0.0526132919, + -0.4012923241, 1.6575239897, 1.1805459261, 0.5314475894, 0.7792928219, -0.5494493246, 0.381816417, -0.0567653663, + 0.4041859508, 1.4742921591, -1.0135000944, 0.4748797119, 0.7541258335, -1.0927159786, 0.0926267952, 0.9003172517, + -0.5001785755, 0.5012148023, -0.6418183446, -0.9861421585, 0.9376791716, -0.5699564815, -0.6094684601, -1.0713261366, + 1.9327700138, -0.9455596209, -0.971960783, 0.6471062303, -0.0367334001, -0.5560221672, -0.3756830692, 2.0556206703, + -2.3344113827, 0.3166075051, -0.093594633, 0.9930018783, 0.5013293028, -0.1114913821, 1.7273072004, -1.0956972837, + 0.1108219996, 0.0784082487, -0.169126302, 0.2886268198, 1.7784488201, 0.1265564561, -0.5149015784, -0.2519254982, + -1.0531100035, 0.7891155481, 0.4315459132, -1.5275148153, 1.4729213715, -0.330255717, 0.0881882012, -0.8817841411, + -0.754036665, 0.877907455, -0.8743508458, 0.2878976464, -0.5434914231, 1.0279676914, 0.995314002, -0.8819229007, + -1.3638242483, 0.3675503135, -0.390589118, -0.7033363581, 1.2411277294, -0.3832196891, -0.5711125731, -1.4024157524, + -0.3557167053, 0.3662314713, -0.693849802, 0.0533289164, 0.3695681691, 0.1856286973, 0.0036913755, 0.1313543767, + 0.8270304203, 1.3178888559, -0.3671407402, -0.2499872595, 0.3193106651, 0.3666144907, -0.4536692798, 0.0637796372, + 0.62468642, 0.0064440314, 0.4970657527, -1.6432136297, 1.0414912701, 0.5748828053, 0.1528365761, 1.0264930725, + 0.028977206, -0.7684674859, 1.8304229975, 1.9216315746, -1.1279611588, -0.2746619284, -0.1850537807, 0.7062392831, + 0.3555676937, 1.0713543892, 0.4431940615, 0.143988058, 0.9895448685, -0.0911555588, -1.7978384495, 0.5766109228, + -0.096674405, 0.0376248136, -0.9085863233, 1.7782652378, 1.0522457361, 0.651704073, -0.8900560141, 0.6581432223, + 0.6606887579, -0.4885232449, -1.1564961672, 1.9684470892, 2.1824321747, -0.3049057424, -0.8701323867, 2.3631441593, + 0.3133211434, -1.1149035692, -1.3495191336, 1.9155670404, -1.0757849216, -0.6060916781, 0.3758997321, -0.9581190348, + 0.6761481762, -1.5759015083, 0.0877688527, 0.9830061197, 0.5539374948, 1.0762681961, 0.2258782238, 1.5641163588, + -1.3022426367, 0.4803126752, 0.6107187271, -1.0131540298, -1.5784831047, -0.8989061117, 0.4761588275, -0.9230661988, + 0.5590661168, -1.0126085281, -0.3330108821, 0.4091787934, 0.8562009931, 1.3837891817, 0.9529459476, 0.0378294997, + 1.7116134167, 0.1376933604, 0.4267888963, 1.4159948826, 1.1380883455, -0.8711742163, 1.3790419102, -1.111015439, + 0.0842593387, -0.2383049726, 0.3928242922, -0.031951502, 0.6350234747, -0.5745252967, -1.0377408266, -0.5247514844, + -0.3461388052, 0.2433131039, 1.971648097, 0.821929574, 0.660153091, -0.9692701697, 0.3216661215, 1.2229069471, + 0.9288674593, 0.3407813609, -0.0449075103, -0.6433902383, -0.351098299, 0.4039245546, 1.4285668135, 2.1478550434, + 0.1891006231, 0.5928854346, -0.0630526319, 1.3296774626, -0.2089577764, 1.178984642, -0.8879231811, -1.120034337, + 0.50149858, -0.6400913596, 1.3707021475, 0.8418042064, -0.0632963851, -1.1129459143, 1.2401936054, -0.226952523, + 1.8008857965, 1.1790270805, 0.5483096242, -1.9282461405, -0.009120835, -0.0526960641, -0.5831608176, 0.7987315059, + -1.6418938637, -0.9462875128, 0.3626517355, 0.7144135833, 0.092009984, -0.116061464, -2.1590559483, 0.8512916565, + -0.9435035586, -3.0365452766, 0.3538107574, -0.9204629064, -1.2248587608, -0.4802761674, -0.0648367479, 0.3905614316, + 0.5931641459, 0.4110111594, 1.9805357456, -0.5985766649, 1.4174280167, 0.2611472011, 0.4249542952, 0.8081253767, + -0.4066265523, 1.3087968826, 0.3670448959, -0.4409090877, 0.1955190897, 0.8306531906, 1.0105479956, -1.2028720379, + 1.6242797375, -1.0599883795, 1.1703038216, 0.3944687247, -0.0508274548, -1.7612975836, 0.9173631072, 0.1352318525, + -0.9668301344, 0.9786379337, 0.9339951277, -1.3411684036, -0.8798589706, 1.2675123215, -0.3759378195, 1.0647661686, + 1.0037868023, -0.5811907649, -2.7897138596, -0.1828412116, -1.3186894655, -0.685911417, 0.3702635467, 0.1879754215, + -0.2166812122, -0.4224203527, -1.1869359016, 1.476850152, -0.1624441296, 1.3615174294, 0.0276617203, 1.2067369223, + 1.877655983, 0.4511460364, -1.2373962402, 0.7331387997, 1.7680873871, 0.9055304527, 0.343178004, -0.719012022, + -0.823603034, 0.3431842923, -0.2256057709, 0.1887262464, 0.7279495001, 0.1026036218, 0.003720945, 0.2864089906, + 0.1306706518, 0.3032578826, -1.969022274, -0.3773420453, -0.3418140411, -1.1602931023, 0.6077716947, 0.917735219, + -0.7473893762, -0.3076132238, -1.185021162, 0.1065358967, 1.5186152458, 0.7725510597, -1.0014253855, -2.1937179565, + 0.3250127137, -0.6440759301, -0.1811335981, -1.1045614481, -2.1818692684, -0.2243866771, -0.0173453316, 0.3536208272, + -0.0725474954, 1.880969882, -0.2315787226, 0.879331708, 1.1665952206, 0.0993929505, -1.4947397709, 1.0953342915, + -2.2650103569, 1.1013573408, -0.312499404, -1.2784965038, -1.7349416018, -0.7721288204, -0.940512836, -0.0988894254, + 0.9771395326, 0.6489016414, 1.6465309858, -0.1293012649, 0.0067455, 1.667578578, -1.0477951765, 0.4693665802, + -1.3260034323, 1.612259984, 0.821931541, -0.2401393354, -0.4720887244, 1.10219419, 0.4860531688, -2.6774544716, + 0.7096341848, 2.5483486652, -0.2957075238, -0.6031370759, 0.192630738, -0.4034855664, 0.1463181674, 0.5350070596, + 2.0819504261, 1.8139798641, -1.0643401146, -0.3128781021, -0.144263804, -2.1851909161, -1.5748522282, -1.0711203814, + -0.4753435254, 0.0661187768, 1.1281665564, 0.1130188406, 0.8959493637, -0.0683412403, -1.3801412582, -0.9871893525, + -0.7403144836, -0.8445615172, 1.6470441818, 1.0460041761, 0.6926950812, -0.7393996716, -0.9453443885, -0.2465624362, + -1.2683348656, 1.9672598839, 0.9712939262, -0.7164001465, 1.2384980917, 1.3134400845, -1.2783517838, -0.9249799252, + -0.9393361211, -0.6579603553, -0.218201369, 0.9198998809, 1.2773807049, 1.1855596304, -0.6381624937, -1.0942879915, + 0.4838123024, -0.4306229949, 0.1810165793, -0.1996294707, 1.2885905504, -0.167863816, -0.1881410182, 1.3225277662, + 0.0953734741, 1.8875477314, 0.0770172328, 1.6916360855, -1.7926950455, 0.4905884266, 1.0937842131, -0.0595675372, + 0.9946762919, 2.0324313641, -1.017023325, 2.0547215939, 1.6750184298, -1.0087105036, -1.6904520988, 0.3167631328, + 0.6377083659, -0.758546114, -0.6136844158, -1.8868082762, -0.1847042292, 0.839595139, -0.1964798272, 0.0806577355, + 1.1836705208, 0.6784030795, 0.8249893785, -1.2950379848, -1.1152267456, 0.691161871, -0.4725620151, -0.6914433241, + -0.2887046039, 0.8318896294, 0.5734977722, 0.7145007849, 1.7885981798, 0.0377317369, 0.7398540378, -0.6245130897, + 0.75828439, 0.8068283796, 1.8076828718, 0.6233335733, 0.6361873746, -1.2487183809, 0.2187319547, -0.6943225861, + 0.3531611562, 0.8272674084, -1.9904072285, -0.936714828, -1.0429241657, 0.6981034875, -1.5150380135, 1.4994618893, + -1.46638906, 2.2427587509, -0.3023525774, -0.6387372613, -0.8940060735, -0.13220644, -1.0280362368, -0.4068548679, + 0.225551948, 0.941387713, 0.0257321727, -0.1329892278, -1.6131180525, 0.8192076683, 0.1125036925, 1.3352439404, + 0.63923949, -3.1156716347, 2.0869877338, 1.0112729073, 2.4250719547, -0.1496810317, 0.7387430668, 1.2361007929, + 0.0684093386, -0.9277183414, -0.1533320844, -0.7304266691, 0.6191169024, -0.7954546213, -2.141217947, 1.249912262, + -1.3871273994, 2.1028695107, -1.0435626507, -0.5314572453, 0.2357278168, -0.7836205363, 1.6709499359, 1.4669779539, + 3.1746845245, 1.3023787737, 2.3591947556, -0.1380295604, 0.9297934175, -0.5155693889, -0.1036393195, -1.1186670065, + -0.1851234734, -0.2512214482, 1.1714904308, -0.2232470512, -1.4790050983, 1.2210992575, 1.7563029528, 0.41022861, + 0.0601698495, 0.2168567479, -0.876223743, 0.9252765179, -1.7906960249, -1.3530749083, 0.0037942464, -0.6046807766, + -0.4491837025, 0.1465787441, -0.21877864, 2.6423318386, 1.8395512104, -1.2164244652, -0.0062938496, 0.751498282, + -1.7471815348, 1.3979443312, 0.4519581199, 1.2722970247, 0.0478293486, 0.0334270969, 0.5252046585, 0.8231018782, + 0.4410232306, -0.2736770213, -0.6498092413, 0.6456122398, -1.5126706362, -0.9126222134, -1.0825484991, 0.8857665658, + -0.4664177299, 1.2132717371, -1.1514225006, -1.073979497, 0.1377086192, 1.916433692, -1.2203828096, -0.7694478035, + 1.3315281868, -0.7050071955, 0.8304207921, 0.6928241253, -0.4450389445, 1.1498022079, -0.6999378204, -0.6708523631, + 2.8639185429, 0.7906737924, 0.6672154069, 0.7954690456, 0.1095909402, 0.1944302619, 0.0010998135, -0.4005476534, + 0.2124238312, 0.4286309779, 0.2146281302, 0.6275988817, -0.0620207116, -0.4323121309, -1.7828309536, 1.5191432238, + -0.3685704768, 0.3279248774, 0.2474352568, 0.7215018868, 0.7299074531, 0.0056346082, 0.6240631938, -0.7521722317, + 0.7414829135, 1.3525691032, 0.20477736, 0.865862608, -0.2844838798, 0.5375939608, 0.0502211004, -1.9202650785, + 0.6328778863, -1.0243452787, -0.3291671872, 1.2854202986, -0.3071571589, 1.1487460136, -0.672442615, 0.9937167764, + 0.0755469427, 0.0181107987, 0.3345252872, 0.0915125236, -0.158737734, 0.9943240285, 1.0686699152, -0.0836843699, + 0.8532247543, -0.128310889, 0.583095789, -0.5074785352, -0.8843220472, 0.9858810306, 0.4600271285, -0.9244024158, + 0.2015917897, -2.2051551342, -1.3684561253, -0.0070179529, 0.9507652521, -0.8961302042, 1.3040012121, -0.4097203612, + 0.5474057198, 1.3817955256, -1.2054364681, 0.5918625593, 0.291276902, 0.3815670609, -1.7695758343, 0.2565854192, + 0.667858839, -1.9968492985, -0.4847605526, -0.4586411417, -0.2693426907, -0.1771221757, 1.7575697899, 0.0226126239, + 1.3108720779, -0.1741402, 0.5192768574, 1.5016207695, -0.3459168375, 0.8827842474, -1.0666747093, -0.6622051001, + 0.2035106122, -0.033603508, 0.4757933319, 2.3770163059, 0.7890660763, -0.4296334386, -0.6260621548, 0.8593677878, + 0.9754520059, -0.5508008003, -1.9562290907, -0.4794707298, 2.1985228062, 0.7364495993, 0.254262358, 0.2583675385, + -0.0006999811, -0.0937647223, 0.0307967123, 2.1079499722, -0.9306992292, 2.4908797741, -0.0683824047, 0.8416444063, + -1.4192576408, -0.2434727401, 0.7902024388, -1.5382992029, 0.9410758018, -0.7255437374, -2.1972353458, 1.435349822, + 0.6533204317, -2.7115106583, 0.6271278262, 0.3922728002, 0.1899161339, -0.2647828162, 2.3061597347, -0.3845082223, + -0.2433109134, 0.4348921478, -1.5491979122, 0.1541192085, -0.4593312144, -0.9138321877, -0.1297478825, -0.2293144763, + 1.6444797516, 0.9206303954, 0.2121412903, -1.3027334213, 0.8136668801, -0.7190756798, -0.3822887242, 0.2437139153, + -1.1598749161, -0.2366128266, 0.9961916208, 0.9275527, 1.0301316977, 0.871627748, 1.1247831583, 0.7137174606, + -0.0485413894, 0.5693393946, -1.948620677, -0.4884814322, 1.6192941666, 0.8910787106, 0.0180339478, -1.7390911579, + 0.2681433856, -0.1390723884, 1.0840507746, -0.3824338019, -0.5290316939, -0.6295898557, -1.5379174948, 1.1584496498, + 0.6609149575, -0.6455150247, -1.4774763584, 1.3007858992, -0.8344992399, 0.2422126979, -1.0668669939, 0.7216842175, + -0.2747242153, 0.6934828758, -0.3771536648, 0.2721296549, 1.6877368689, -0.3436425626, -1.3526052237, 0.6161730289, + -0.3104036152, 0.403837949, -0.8696197867, -0.0881191045, 0.8002542853, 0.2152355313, -2.1688718796, -0.1544931531, + 0.5612537265, -0.7872266173, -0.6685209274, 1.3880770206, -0.0438574255, 0.6691686511, -1.1393299103, 1.5715401173, + 1.7690942287, -0.1770737022, -1.2838332653, -0.1482763737, -1.1807324886, -0.1246396676, 0.5556858778, -0.5587546825, + 1.9595792294, -1.0273351669, -0.2892897129, 2.1519374847, 1.4404784441, -1.6324875355, 0.9220415354, -0.8804201484, + 0.908628881, 1.3144823313, 0.1263292283, 1.1237426996, 0.1560661346, 0.9178130031, 1.0348485708, -0.0764593482, + -0.1803882867, 0.4778284132, -2.6791322231, -1.4770958424, 0.0729591846, -1.4535052776, 0.1024222225, -1.0942270756, + 0.3704869747, 0.4322766662, 0.2548621595, 0.6323297024, -1.346924901, 0.9590857625, -0.7356510162, -1.4300709963, + -0.8788210154, 1.3715491295, 1.1217643023, -0.5817310214, -0.6780789495, 0.184761256, -2.2621667385, -1.3844285011, + -0.4063298106, -0.4010620713, 1.0016220808, 0.0181291588, -0.3874219656, -0.6327757835, -0.6283560991, -1.4798924923, + 0.0586887263, -0.3952905834, -1.0938864946, 0.9593856335, -1.2852833271, 0.5518447161, -1.1919951439, 0.4875165224, + 0.4057821333, 0.993730545, -0.923879981, 2.6145756245, 0.4748609662, -0.3027443588, 0.260014683, -0.2662793696, + 0.5243310928, -0.7458996773, -1.3094813824, 0.2878949642, 1.0456981659, -0.3525495529, -0.8172661662, 0.2186447978, + -0.5194003582, -0.2409159392, 1.5012190342, -0.381442368, -0.2719659209, -1.6522637606, 0.8976294994, 1.6063685417, + -0.3337241113, -0.7124217749, 0.8000403643, 0.0348635353, -1.2435899973, 0.274291724, 1.2672042847, 1.3071616888, + -0.3089774847, -0.5630499721, -1.6949775219, -0.3910141885, -0.4686586857, -0.4318181872, -0.4553795457, + -1.5290528536, 0.7596347928, -1.2247896194, 0.7929475904, 3.2648231983, 0.0765919611, -1.7044337988, 0.5527252555, + -1.2542990446, 1.0776225328, 0.7700014114, 0.3957244158, 1.0734199286, -0.3395042419, -2.0320532322, -0.7339397073, + 1.708894372, -1.7991150618, -0.3706928492, 0.2754571736, 0.2273407429, -1.0307626724, 1.1256923676, -0.8246914744, + 0.3956819177, -0.9917507172, 0.7536754012, 0.6936249733, 1.8786382675, 0.5164870024, -0.5184623599, 0.1207001433, + 0.2281433642, -0.9246230721, -0.0446610264, -0.3871702552, -1.504204154, -0.0066607548, -1.5743414164, -0.2049447745, + -2.2182295322, 0.2431137711, 0.5944489241, 0.5098665953, 1.4379987717, -0.4044253528, 1.0512136221, -0.6692307591, + -0.515927434, -0.551248908, 0.5259061456, 0.2661730647, -1.510694623, 1.9273676872, 0.5774011612, -0.4199075699, + 1.3673183918, -0.5175925493, 0.027776463, -1.0282031298, -1.2392059565, -0.3175444007, 0.0651226565, 0.1687745154, + -0.7958122492, -1.137167573, 1.8399970531, 1.0105547905, -0.5101677179, -2.0513987541, -0.236571759, 1.0404173136, + 0.8387218714, -1.5863597393, -0.2953415215, -0.3548167348, -0.8969500661, -0.5921047926, -0.4963432848, -0.7090011239, + -1.4159350395, 0.0659552068, 0.608322382, 1.4280581474, -2.7973577976, 0.2793337703, 0.4457551241, -1.1316871643, + 0.7324762344, 0.046525877, 1.2708383799, -0.899091661, 0.9488687515, 0.9713152647, -1.1941430569, -0.3017987013, + -0.9432987571, 0.7103397846, 0.1358730197, 0.1415656805, 0.5150106549, -1.7309122086, -1.9883096218, 0.7167133689, + 0.0778244287, -2.1529717445, -0.967305243, 0.3667652607, 0.1836275011, 0.5833052397, -0.457836926, -0.4256786406, + -0.9554052353, 1.3549624681, -0.4652006924, -0.2363625318, 0.099400647, -0.6568480134, 0.0348669849, 0.3077637255, + 0.3547363579, 0.8136194944, -0.679463625, -1.0101652145, 0.7936237454, 0.7654732466, -1.396774292, 2.0011563301, + -0.8323894739, -0.1461954713, 1.0044622421, -0.6343291402, 0.2242664993, 1.7496575117, -0.4828544855, 2.1647851467, + 0.7960585952, 0.0863240808, -1.8356450796, -0.1754117906, 0.9070207477, -1.2061300278, 0.666480124, 0.2954353392, + 1.9272356033, 1.0407719612, 0.4945245683, 0.5699928999, -0.1160124764, -0.4865684211, -0.017062027, -1.6850682497, + 0.6151177287, -0.6133508086, -1.4380831718, 1.6350381374, -0.2955036759, -0.4080443978, 0.6777896285, -0.7060639858, + -0.4976985455, -0.9679428339, 0.0706002116, 0.0416285954, 0.2848752439, -0.8778271079, -0.1663546264, -1.479462266, + -1.9278879166, 1.697842598, 1.7794172764, -2.9531173706, -1.2205433846, 1.5037174225, 0.5455800891, 0.6231148243, + -0.163787052, -0.1267165393, -0.6366458535, 0.4950649738, 0.3843171895, 0.3920426071, -0.8354402184, -0.2788834572, + 1.0194483995, 0.0986561626, -0.5203149319, -0.0823765323, 0.0222817399, -1.2570695877, 0.0349741466, 0.2028528899, + 0.2815420926, -0.1766107976, 0.2764383554, -1.3478579521, 1.486269474, -0.4602116346, 0.106000036, 0.6406856775, + 0.685138166, 0.9093105793, 0.5848791003, 0.1880259067, -0.9595815539, -0.2873590291, 0.5662950873, -3.1337368488, + 1.4183876514, -0.3170253038, -1.9341831207, -0.7753921151, -0.5650481582, 0.9571687579, -0.0570281744, -0.2114823312, + -0.1237578094, -0.5994918346, 1.2810485363, 2.4784626961, -1.4082845449, 0.660708487, 1.2495912313, -0.8925880194, + -0.8004648685, -0.1284520179, -0.9761826396, -0.3523084521, 1.5950284004, 1.3361389637, -0.4479740262, 1.9581365585, + -0.1791668683, -0.7813001275, 0.9748125076, 1.9654608965, 2.1079697609, -1.1303747892, -0.3680176139, -0.1541169137, + -0.4737612605, 0.2893137038, 0.0942446738, -1.2750767469, -1.6875716448, 0.0291447006, 0.910426259, -0.7338591218, + 0.1654359996, 0.4833254218, 0.1837635785, -0.0783622116, 2.0477280617, 0.4575521946, 1.4642084837, 1.8992501497, + 1.310151577, -0.8264897466, 1.1015996933, -1.8358174562, -0.5262581706, -1.342713356, -1.8201973438, -1.3885704279, + -0.7330588102, 0.9829092622, -1.1346485615, -1.8879934549, -0.4256469011, -0.5990062952, 2.077419281, -0.2175528258, + -1.3139890432, 0.8544276953, -0.8505318165, -1.5247815847, 1.0540881157, -0.7676452398, -0.0154721728, 0.0645280629, + 1.196513772, -0.7829078436, -0.7461743355, -0.9474745989, -0.4311519861, -0.1322558373, -1.4352858067, 0.302203536, + 0.8314113021, 1.5980254412, -1.2497850657, -0.4789477289, -0.4042346478, 0.9194238782, -1.9574488401, -1.5083035231, + -1.0556405783, 0.3304715455, 0.4454304576, 0.7204989195, -1.4876512289, 2.3934466839, -0.365711242, -0.6892605424, + 0.7944124937, 1.1503497362, -1.143671155, 0.4530783594, 0.1073921546, 0.2563025057, -0.2650616765, -0.5858703256, + 0.3914135396, -0.0370595977, 0.6986816525, -0.6059454679, 0.743803978, 1.5383099318, 1.5709109306, -0.0677266866, + 1.0556417704, -1.0941773653, -1.9463193417, -1.5928672552, 0.7118583918, -0.107823588, -0.1363062114, -1.1848173141, + 1.0763760805, -2.1852428913, -1.017056942, 1.0829125643, 0.2023819089, 0.3322030008, -0.8313293457, -1.2125116587, + -0.7498506904, -0.6480713487, -1.0642518997, -0.053565897, -1.5605756044, -0.3149810433, -0.6010142565, -0.4871916175, + 0.8242281079, 1.8240424395, -0.0996669456, 1.5988140106, -0.5990390778, 0.0666736066, 0.0582151599, -0.4938335717, + 0.1771529615, -1.6437077522, -0.5018564463, -0.3862938881, 0.2370947152, 0.4438247681, 1.8506821394, -0.839933157, + 1.2295398712, -0.0405258946, 0.5014107227, 0.3826455772, 0.0491048954, -1.0085386038, -1.4686864614, 0.6855700016, + -1.0127818584, 0.3318201005, 1.3520195484, -1.1127836704, 1.1357103586, -0.9928646684, 0.8556365967, -1.057009697, + -1.6995784044, -0.9159128666, 0.6399106979, -1.0972138643, 0.7753602862, 0.4758385718, 2.3228681087, -0.0455329157, + 0.8702580333, 2.2876014709, 2.266702652, 1.0052275658, -0.5927371383, 1.3670648336, -1.1437461376, 0.3765378594, + 0.794419229, -0.1012149379, 1.097966671, -0.3328878284, -0.5348561406, -0.031679593, 0.9100095034, 0.7350540757, + -0.7042039037, -1.0100349188, -2.6791682243, 1.096280694, 0.802596271, -0.0379705727, 1.4441269636, -1.508533597, + 0.0003205369, -0.0880573839, 1.105301857, 0.1118759215, 0.9201207161, 3.1936144829, -0.5558418632, 0.4877890944, + 0.0970641673, 0.4611878693, 0.2145508379, 0.0961457565, -0.0012075664, 0.4158501625, -0.0128498999, 2.2061691284, + 0.3245992959, 0.5149602294, -0.8647653461, -0.477853477, 0.1767767519, 1.1144613028, 0.7067543268, 0.295345813, + 0.4151735902, 1.3802677393, 0.4514097869, 1.431019187, 0.1890203953, -0.0607744493, -1.014528513, 0.4822328091, + 0.0662695393, 0.5966459513, -0.3585332334, -0.4946506321, -0.5472767353, -0.0253793262, 1.2802063227, -0.5363033414, + 0.4587896466, 0.2496608347, -0.7562409639, 0.6417131424, -0.329246819, 0.4829611182, 0.010742072, 1.8334723711, + -0.8969556689, -0.5865179896, 1.4124860764, 0.9335811734, 0.680356741, -0.7399356961, -0.9453975558, 0.0589627735, + 0.9332634807, 0.2295327932, 1.214405179, -0.9396538734, 0.7404459715, -1.4058126211, 0.3758881092, -0.54158324, + 0.360917747, 0.4216291308, 0.0672683716, 0.495478332, -0.3137744963, 0.0770393088, -0.7609525323, 0.6436778903, + 0.6758462191, -0.2501106262, -0.1796221882, -0.4029569924, 0.2886023521, 0.1287038326, 1.7206531763, -0.2571421862, + 1.5516285896, 0.1779292226, 1.8721263409, 0.4874676168, -0.3857848346, 0.7131745219, -0.1883796006, -1.1051175594, + 1.0015405416, -0.0806301087, 0.5015828013, -0.7649217844, 1.2179169655, -0.6834611297, -0.3220885992, 0.1348572373, + 0.3637213707, -0.0528043061, 1.0957769156, 0.2416266203, 0.3221211135, -0.1729038656, 0.4899542034, -1.3926836252, + -0.8075534701, -0.4263211191, -0.318539381, 1.8184756041, -1.4812299013, 0.4924119711, 0.1793278903, -0.3062870204, + 0.7527695894, 0.6813973188, -0.413672477, 0.1930301487, 2.4636559486, 1.0544172525, 0.5969682932, 0.3538553417, + -0.7953445315, 0.4444134831, -0.9988148808, 0.270871073, -0.2231728882, -1.5424858332, 0.0671981946, 0.716586113, + -1.7390002012, 0.117527768, 0.5987126827, 1.2449854612, -0.4765720367, 0.9063929915, 0.5871992111, -0.2316968739, + -0.477085799, -2.0407674313, -0.8889138103, -0.4778654575, 1.053514719, -0.8856458068, -0.0943486169, -1.9650886059, + 1.5634150505, 0.9272034764, 0.870450139, -1.23990345, -0.0045439149, 0.0171208791, 1.594040513, 0.5065575838, + -1.0628005266, 0.6307820082, -0.045637209, -1.1207317114, 0.0359663069, -0.6097961068, 0.2768594623, -0.9132888913, + -0.8086346388, -0.5995755196, 1.0584326982, -1.3386423588, -0.091085963, 1.2630821466, -1.1991431713, -1.0497963428, + 0.6557671428, -2.8756728172, 0.0049800058, 1.1699956656, 1.7030316591, 0.504610002, -2.2967424393, -0.4492062628, + -0.4919267297, -0.8143878579, -0.7950159311, -0.5516642928, -0.1837606877, 2.1352300644, 1.1462190151, 2.0455040932, + -0.504881382, 0.8189655542, 0.1658494473, 0.3154302835, 1.2556283474, 0.7457754612, 0.3385994136, -1.6795654297, + -0.6067926884, 1.2469490767, 0.5089952946, -0.0530367568, 0.5155069828, -0.6019174457, -0.1175310239, 0.3800863326, + 1.4116129875, 0.4822998345, 0.6734839082, -0.7265940905, 0.9609754682, -1.0695693493, 1.2773134708, -0.0383228734, + -1.1684441566, 0.6060315967, 1.6832801104, 0.7533211708, 1.5771530867, 0.4684437513, -0.2532663345, 1.582400322, + -2.667798996, 0.7695742846, 0.4340322316, 0.6323025227, -1.0616002083, 0.6552160978, -2.0156300068, -0.2300008535, + 0.632415235, -0.8441838026, -0.7557621598, -0.174821794, -0.6759279966, -0.8832311034, 2.3019340038, -2.3870930672, + 0.0982676297, 0.1205674782, 1.3445794582, -0.2255969346, 0.6980847716, -0.4308630526, 0.8111328483, 0.9373266101, + -1.6052649021, 1.4621964693, -0.2540515065, 0.8156651855, 1.0076911449, -1.7301025391, -1.6204510927, 0.7440069318, + 0.0341309048, 1.5476413965, -0.8900391459, -0.3766621947, -0.6074256301, 0.3939062655, -0.5218016505, 1.2918245792, + -1.3143782616, 1.5072596073, 1.023116827, -0.2359389961, -1.1725305319, -0.9327100515, 0.6893956065, -0.2224030793, + 0.1603256017, -0.4459508359, -0.1136763841, -0.1959608495, 0.7789053321, 1.0510292053, -0.0700007603, 0.5266662836, + -0.9966610074, -0.9432050586, 0.7437862754, 1.3008739948, 0.3434124291, 0.0258266907, 0.0869140998, 0.6960690022, + 0.7120946646, 0.0515276678, -0.0726527721, -0.341178149, -1.3804582357, -0.2881645858, 0.5035392642, -1.3463668823, + -0.6638413668, -0.5775796175, -0.5389131308, 0.434350282, -0.2203941643, 1.6989192963, 0.5641354322, 1.6838576794, + 1.241088748, 0.1104821563, 1.7673959732, -0.8824916482, 1.3487502337, 0.5774065256, -2.2027637959, 0.3938376009, + 0.2434094995, -0.4469590783, -0.1877329051, -1.0865863562, -0.6238707304, 0.1701171249, 1.0134552717, -2.2195823193, + -0.5561084747, 0.0621400401, 0.2244819254, 1.0336713791, -1.3963009119, -0.2985310555, 0.3228592873, 1.3612934351, + -1.488037467, -1.6463325024, 0.4461197257, -0.3382137716, -0.4326903224, 1.2684216499, 1.264323473, 1.0895330906, + 1.2925497293, 0.13507846, -0.4523508847, -0.8258852959, -1.7149457932, 0.6874905229, -0.729614675, 1.2389507294, + 0.91463691, 1.3814866543, -0.0028754754, 2.3910377026, 0.1634847671, 1.5939153433, 0.1600411683, 0.3318611383, + 0.4221729338, -0.9187315702, 0.3347060084, -0.4368286729, -1.2759553194, 1.1613256931, 0.426402837, -0.2972605228, + -0.0180641264, -0.6553592682, -0.5903983712, -0.5169649124, -0.4399635792, 0.0741655752, -1.223326087, 0.2017238438, + 0.9079591632, 1.0736171007, -0.4128850102, -1.1717312336, 0.60356462, 1.5451973677, 0.6227061152, 1.2984673977, + 1.6092420816, -0.9485616088, 1.8946329355, 1.295769453, 1.0307075977, 1.4255412817, 1.7190335989, -1.3016798496, + -0.9480474591, 1.1068694592, -0.8514854312, 0.3590765297, 0.488416791, -0.2413618565, -0.2864337265, 1.9658122063, + -1.2297976017, -1.3506499529, -1.0592341423, -1.296299696, 0.6311379671, 2.3245151043, -0.8188385367, 0.687038362, + 0.0071533509, 0.4189999998, 0.5118589997, 0.928245306, 0.1976849586, -0.2832446694, 0.4292204082, -0.1534999758, + 1.5900549889, -0.2832624912, 0.9434610009, 0.782217145, 0.76150316, -0.3012326658, -0.1083905846, -0.389005661, + -0.5637946725, 0.0940228626, -0.1532761008, 0.4407454431, 1.1213968992, -0.7484930754, 0.4968990684, -0.8124283552, + 0.8374453187, -0.5514011383, 0.7271595001, 1.190144062, 0.4425831437, 0.7223262191, 0.0920367613, 0.1827518195, + -0.9553514719, 2.2778782845, -0.0951565281, 0.6599346399, -0.4985764623, -1.2338274717, -1.0685179234, 0.5681238174, + 0.4908271134, 0.2003903836, -0.104392916, -0.6512681842, -0.0636266619, 0.0732113644, 0.4932597578, -0.9207543135, + -0.1076298058, -1.6838189363, -0.2428099662, 0.7228756547, -0.4640580118, 0.6245583892, -0.7864403129, 0.9854980707, + 0.1483794004, -0.1238286272, -1.9773298502, -0.6761142612, -2.0313007832, -2.1170983315, -1.5734508038, -0.8779585361, + -0.0909841582, 1.4897482395, 0.6401346922, -0.4880248904, -0.4623247981, -0.2730410695, 0.2345179766, -0.2584047318, + -1.0733059645, -0.6118106246, 1.8113634586, 2.0679802895, -0.9476329684, 0.7383434176, 0.0674313679, -1.6945581436, + 0.3529974222, -1.2724621296, 1.0977891684, -0.817912519, -2.8983523846, -1.2201880217, -0.1745642573, 0.0033349809, + 0.2662228346, 0.7162650824, -0.4651221633, 0.5385454893, 1.1434221268, -0.4105019867, -1.6019604206, 0.6570641398, + 0.3827970028, -0.8969772458, -0.6783589125, 0.4421870112, 0.3902520239, 1.2652155161, 0.8713499904, -0.1916929632, + -0.1945413202, -0.4036102295, -0.0592381246, -0.7947420478, 2.4768147469, -0.559638381, 0.0513080209, 2.2183132172, + 0.7428569198, -1.1224207878, 1.2905070782, 1.6988288164, -0.0087889144, -0.3099016845, -1.0261619091, 1.28157866, + -0.3887642324, -1.8203357458, 0.6565842628, 0.8482696414, -0.365709722, 2.5571284294, 0.964628756, 0.5014576912, + -0.7785434723, -1.0838786364, -1.0007174015, -0.6832125783, 0.6869196296, -0.8909994364, 0.7105440497, -1.5718376637, + -1.0136063099, -0.4651289284, -0.9581088424, -0.4869917929, 0.8937326074, 2.2701437473, -0.5487756133, -1.2599574327, + 0.2497866601, -1.0012441874, -1.0906326771, -0.0996188372, -1.5389875174, -0.3022162914, 2.1879057884, -0.7253212333, + 1.062497139, -1.2916557789, -0.3524868786, -0.9313794374, -0.7848801613, 1.5815815926, 0.110680677, 0.4807272553, + 0.6900759339, 1.2145121098, 1.1435748339, -0.7682368159, -0.1096613705, 0.671540916, 0.0713482127, 0.2610453367, + -0.2741608322, -0.2731364667, -0.6862300038, -0.4789772928, -1.3881918192, -0.6710447669, -0.2162043303, 1.2445957661, + 1.1760710478, -0.560895443, 0.2300017178, -0.523763895, -1.4979652166, -0.4840055704, -1.016023159, 0.06339439, + 0.2442258596, -0.1619214714, -0.1240627095, 0.2674188316, 2.13473773, 0.7680336833, 0.713157177, -2.2288031578, + 0.3683202863, 1.3970509768, 0.2402867228, -0.3467687964, 1.0369762182, 0.9858167768, 1.724110961, 0.3450718224, + -0.3579460382, -1.4150452614, 0.3929713666, 0.4741328359, 0.2615441382, 1.355825305, -0.1826655865, 0.7189281583, + 1.1006554365, -1.2778162956, -0.6737187505, 0.2032980323, -2.3750617504, 0.5275279284, 0.069925949, 0.0522095188, + -0.0179084744, 0.7750706077, 0.3565326333, 0.2300423533, -1.4687960148, -0.0426535085, -3.7455356121, -0.7975733876, + -0.2791737318, 1.7593774796, 0.0835426897, 0.8876459002, 1.1769098043, -0.8923800588, 0.6272987127, -0.8653988838, + 0.550703764, -0.130911231, -0.7270892262, -0.5536189675, 0.1476335227, 0.9601663947, 0.4076004028, -0.8485045433, + -0.1765632182, 0.2317116857, 0.03721359, 1.3644959927, 1.3756741285, -0.2507399023, -1.8323187828, 1.4180147648, + 0.3964681327, 0.204127118, -0.3245566487, -0.4420765638, -1.3968116045, -1.3434318304, -0.910826385, 0.6881069541, + 0.6643660665, 0.2395091802, -1.3126059771, 0.954883039, -0.2024228126, -1.4638279676, -0.4380912483, 0.1316522658, + -1.5384185314, 0.2050340176, 0.6454075575, -0.9426968098, -0.5764552951, 0.6355412602, -1.1904445887, -0.0340364538, + -0.8278380632, 0.5902572274, 0.3412825763, -0.1369599551, -0.0623027273, 1.5578794479, 0.7105544806, 1.0725549459, + -1.9698865414, 0.8213605285, -1.2326803207, -0.4292006195, -2.210242033, 0.7281572819, 0.3447653949, -1.3590006828, + 0.3094686866, 0.232550621, 0.1171084866, -0.0100068245, -2.908249855, -0.039407406, -0.7112797499, 1.0732913017, + 1.0485405922, 0.8922514915, 0.003764997, 0.3218860924, -0.2153628469, 0.1521495283, -0.9304068685, -3.3970711231, + -0.5037402511, 1.1651905775, 0.7021167278, -0.7433487773, 0.3981168568, 0.9380275011, -1.5853767395, 0.0831920207, + 0.0841076896, -1.0592501163, -0.9714565873, -0.7586913109, -0.6948418021, -0.4219135642, -0.8064761758, 0.712687254, + 0.4738564491, 0.3092348576, 1.3096922636, 2.0170652866, -0.8423181176, -0.0324107222, 0.6601939201, -0.5238676667, + 1.1682136059, 1.557218194, -0.7529825568, 1.6637852192, -0.4154839218, -1.3779836893, -0.1081061214, -1.5806005001, + 1.8208845854, -0.381904155, 0.5165681243, 1.8766587973, 0.8654612899, -0.9601491094, -0.3456733525, -0.6894811392, + -0.7221453786, -0.6066665053, 1.0309771299, 0.820055604, -0.7337735891, -0.1614723206, 0.9861069918, 1.4574701786, + -2.1444618702, 0.3525089025, 1.7056667805, -0.9310776591, 0.6707212329, -1.3782510757, 1.1024730206, 0.8600340486, + -0.2841083705, -0.4831273854, -0.1850067079, 0.1130082682, 0.2305518389, 0.3413489461, -1.003488183, -1.0885648727, + -0.9350720048, 0.1794212759, 0.4361413419, -1.8060265779, -0.1309453547, 1.4649746418, -1.3094321489, -0.3479111791, + -0.8606664538, 0.3332029581, 3.0923016071, 1.3583788872, 0.0134683866, -0.886022985, 0.2574064434, 1.1946133375, + -1.1781209707, 1.3553206921, -0.6204507351, -0.6351287365, -0.0614457428, -0.544169724, -1.1895301342, -0.1810240746, + -1.1449270248, -0.1968882829, 0.5040771961, -0.440343976, -0.4055637121, -0.4553186297, -0.9085854888, 0.0759990811, + -0.186061427, -0.2720640302, -0.1599345505, 0.3134514391, 0.4481948316, 1.934677124, -2.1949660778, 0.8848531246, + 0.6827428937, -0.9667618275, 0.1164045185, 0.3335077763, -0.9087823629, 1.8471758366, -0.6295967698, -0.8704705238, + -1.4105505943, -0.759506464, -1.2473758459, -0.3623605371, 1.0579477549, 0.0246553812, 0.5469079018, 1.0893458128, + 0.4062927067, -0.3033017218, -1.2926683426, 1.052456975, 0.2503056228, -0.3500367701, 0.6117320657, -0.6270340681, + -0.2911286056, -1.0969469547, 1.0318131447, -2.5585491657, 1.3501057625, -0.2241195887, -0.4697246253, -0.5922012925, + 0.3770401776, -0.158528313, 0.8999029994, 0.2463238984, 0.3050529659, 0.0677323788, -0.6213287711, 0.5435842276, + -0.3985887468, -0.9317046404, -1.2294517756, 0.0828140751, 1.2535772324, 0.0256637987, 2.8696305752, 1.4507285357, + -0.4330395758, 0.8850038052, 0.461982429, 0.5875666738, -0.3392009139, -2.4040269852, -1.2309052944, 0.8450149894, + 1.1948267221, -0.4159831703, -1.7273284197, -0.4782824218, -0.0359106883, -0.4035047591, -0.1818247736, -0.6230558157, + -1.1475069523, 0.4307565391, -0.7822400331, -0.4539892375, -0.5645713806, 0.7916404605, -1.2734173536, 1.1932449341, + -0.3262642026, 0.1361260116, 0.4524342418, 1.8424292803, 0.2679949403, -0.715734303, 0.9898098707, 0.4705828428, + -0.5157236457, -0.0149328671, -0.3967804015, 0.2779393494, -0.6822986007, 0.1624890715, -2.052511692, 0.0262571834, + 0.2762793601, 0.4157950878, -1.2589560747, -1.023624897, -0.8549474478, 0.4833740294, 1.2150045633, 0.3890248537, + -0.0069801174, 0.9563995004, 0.1099641994, -0.3607292473, -1.0780054331, -0.1775603443, -1.5771030188, 2.8553757668, + -0.6350323558, 1.403570652, -1.5484172106, 0.4918170571, -1.0095106363, 2.1850802898, 0.9022112489, 0.4329253137, + -2.1208972931, 0.9020392895, 0.5670707226, 0.2932744026, -1.7365777493, 0.377407819, 0.7109208107, -0.1204144135, + -1.3939466476, -1.0072985888, -0.1054091528, 0.628005743, -2.468208313, 0.2006152719, -0.9499309659, -0.8038668036, + 0.5076775551, -0.9942888618, 1.0489151478, 0.1733068526, 0.0147161372, -1.79728508, -0.1931378543, -0.4037202895, + -0.7168515921, -0.370094955, 0.2424467951, 1.35367167, 0.5044452548, -1.102350235, 0.1263127476, 0.1913612634, + 0.4485045075, -0.0773018971, 2.0170025826, -1.0194779634, 0.3922486901, 2.9099795818, -0.1763591021, -0.5611923933, + 0.2001597732, 0.4984797239, -0.4362840652, -1.5781536102, -0.0572126582, -1.6782734394, 0.1083617732, -0.4752859175, + 1.9072747231, 2.0408916473, -0.8214539289, -1.2110806704, -0.0955808163, -0.7157170177, -1.5102883577, 1.847178936, + -0.6968463063, 0.5167600513, 1.8500298262, -0.6309816837, -0.0008967539, 0.6174471974, 0.2788871229, -0.8685209155, + -0.1644606888, -0.6464869976, -2.1174771786, -1.7138003111, -0.1598047316, -0.3160598576, 0.6028695107, -2.0008893013, + 0.532296896, 1.446978569, 0.646897614, 1.1313585043, -1.0836691856, -1.6371321678, 0.1979190111, -0.4971550107, + 0.3789435327, 1.2085425854, 2.3498613834, 0.2326178402, 0.6639389992, -0.2816003561, -1.1688593626, -0.7957587242, + 2.1797263622, -1.2281219959, -1.0931417942, 2.4704101086, 0.3591396511, 0.3633414209, 1.7679173946, -1.5819662809, + 0.5613010526, 0.8031804562, -0.9179223776, 0.3878885508, -0.1153258309, 0.2231075317, -0.1290087104, 0.7834047079, + -0.2219590694, -0.0516575351, 0.7322729826, -0.6734268069, 1.3610804081, 0.7266793847, 0.7462473512, -0.9291234016, + 2.1887683868, -0.946886301, -0.3495929539, -0.042898573, 1.3444181681, -0.0642006993, -0.4990572035, 0.9972393513, + -0.1914417893, 1.2694454193, -0.6293994188, -0.1585151702, -0.2537268102, -0.0725091919, 0.7362402081, 1.1210161448, + -0.4297934473, -2.9094355106, -0.1323205382, -0.2460999191, -0.7158421278, 2.1082756519, 1.1742449999, 0.9783309102, + -0.2963083088, -1.1627272367, -0.0309837069, 0.832519412, 0.3749943376, 1.0111228228, 0.1109903753, 0.055838149, + 0.2111046016, 0.0354266241, 0.9828637242, 0.5850839615, 0.0928330123, -0.9776461124, -0.8418869376, 0.5141755939, + -0.1413520724, 1.1167169809, 0.8080258369, 0.8365648985, -0.6641654968, -1.2707079649, 0.140954569, 0.9196810126, + -1.2050665617, -0.6511962414, 0.4858438671, 0.5146605372, 1.5368059874, -1.4482113123, 0.7256953716, -0.4815798998, + -0.4271739125, -0.7080703378, -0.7192265391, 0.7303133011, -1.1464543343, -0.0006264384, 1.9445780516, 0.036707066, + -1.9715096951, -0.9793316126, 0.9981327653, 0.4227823615, -0.3801508546, 0.8276200891, -0.3732515275, -0.5242275596, + 0.7299136519, 0.9283463955, -0.9516673088, 0.0363494493, -0.4172412455, 0.6668561697, 0.7712953687, 1.24201262, + -1.0641741753, 1.0731617212, -0.3424093425, 0.0912520811, 0.8670433164, -0.239088431, -1.2840259075, -1.0081032515, + -0.4506661594, 0.031823121, 0.9985192418, -0.4479965866, 1.9789948463, 1.1024099588, -0.8284841776, 0.9265839458, + 0.8247851133, 1.1524419785, 0.6611723304, 0.8174999952, -0.0465653911, 0.716170311, -1.5024360418, -0.6508199573, + 0.2619676888, 0.8435713053, -0.8028890491, 0.7184874415, -0.9584380388, -0.5889627934, 1.105189085, 1.0269550085, + 1.114210844, 0.8566098809, -0.1889745146, 2.1708762646, 0.3211729527, -0.7073199153, 0.2713794112, 2.1762907505, + -1.6629705429, -1.5230276585, 0.2944081128, -1.8447911739, -0.485612601, 0.1250060797, -2.6290686131, -0.7232851386, + 0.4715391695, 1.0080659389, 0.0524155572, 0.4955901802, 0.0261317994, -0.4716481268, -0.0053549618, 0.9015104771, + -1.0712935925, -0.8792697787, 0.295165062, -0.799376905, -0.7291873693, 0.1309042275, 0.8772374988, -0.8512756228, + 0.6310116649, 0.2843870819, -0.6464396119, 0.419382304, -2.7665982246, -0.6511185765, -0.6155664325, -1.3428583145, + -0.3334512115, -0.3145128787, -0.3880962133, -0.0138087487, -0.073211208, 0.8911177516, 1.0543974638, -1.6987104416, + -0.9329395294, 0.6918064356, 0.4133537114, 0.9851148129, 0.502140522, -0.4187388122, -0.3045681715, 1.2685724497, + 1.5336577892, 0.4741467834, -0.4501512349, 0.4564183354, 0.3882172406, 0.5919806957, -0.4965659082, 0.3365334868, + 1.690761447, -0.7521701455, 1.6877909899, 0.643643856, 1.6518549919, 1.0253766775, 0.9109950662, 0.7273064256, + 0.528617382, 1.1155961752, 1.8448877335, -1.5188112259, -1.7974079847, -0.9361957312, -0.5099250078, -0.1010021567, + 0.8071030974, 0.1876153201, -0.0064344634, -0.0497765839, -0.547557652, -1.0387189388, -0.3532833457, -0.5067877173, + -0.903539598, 0.7844749689, 0.9171721339, 0.825538516, 1.1045073271, 0.9061017632, 0.832018435, -0.3664151728, + -0.6954748034, -0.3559719622, 0.1738903522, 0.910586834, 0.2641392946, 0.5053906441, 0.4349961579, 0.8912056684, + -0.1841396093, -0.7150786519, -1.3447219133, -0.4978642464, -0.0933635756, -1.1518702507, -0.6728532314, + -1.6219307184, 0.3163990974, -0.7288520932, -0.5077275038, 0.3367995322, -0.717535615, 0.4415037036, 0.7889863849, + 0.6716121435, 0.9814752936, 1.2690737247, -0.6693392992, -1.1873300076, 1.410833478, 0.3188565969, -0.2024255991, + 0.741214931, -0.4959668815, 0.0802198648, -0.7489406466, -0.1091844365, 0.9267287254, 0.0638568923, 1.1230969429, + -0.248650834, -0.2947012782, 0.2912669778, -0.3035437167, 1.0478081703, 0.9640623331, 0.7009201646, -0.8394269943, + -0.4298658669, -0.0208310578, -0.9664135575, -0.4727172256, 0.3689211309, 0.8614180684, 0.8856139779, -1.0648728609, + -0.4798837602, 1.6359280348, -1.5494107008, -0.2393066734, 1.6723638773, 1.0869294405, -0.150375098, -1.3417633772, + 0.3851701319, 0.8203778267, 0.2636116445, 1.2380123138, -0.2437708676, -1.6408116817, 0.945915103, -2.6160981655, + 0.1274162382, -0.8868399262, 1.2920694351, 1.234516263, -0.155479759, -1.2826472521, 0.3236345053, -1.3748104572, + 0.1620595008, -0.502872169, 0.7731192112, 0.0074709491, 1.0263241529, 0.3440847397, 0.4407630861, 0.25807181, + 0.4818874002, -0.9904689193, 0.3456379175, -0.7643799186, -0.5512456894, 0.6247019768, -0.0195069723, -2.3036928177, + 0.4286721349, 0.3994229734, -0.3317076266, 0.9082452059, 1.3464412689, 0.8724412322, -0.2232536077, -0.9121289849, + -1.0593949556, -0.9844374061, 0.4946773946, -1.2179546356, 0.8431268334, -1.0629291534, 0.9424785376, 0.6598713994, + -0.5156948566, 1.26514256, 0.6092521548, -0.9670048356, 0.5924138427, 0.8206498027, -0.1055323258, -1.3936834335, + -0.250921458, 0.4976290762, 0.7790489793, -0.6068552732, 0.7373483777, -1.023167491, 0.797503531, -1.8134320974, + -1.6039186716, 0.0184440892, -1.5174918175, 0.1511792094, 2.4891557693, -0.7333879471, 0.5969586968, 1.1847419739, + 1.4520896673, -0.1143778041, -0.4433355927, 1.7384566069, -0.392591238, -0.0808646306, -0.4252757728, 0.8303156495, + -0.0310105458, -0.4736564159, 0.0218356308, -0.5272080898, -0.3808960319, 1.7675691843, 1.558216095, -1.0983140469, + 0.5440816879, 1.2187278271, -0.4388285279, -0.2428838164, -0.482010603, 1.0899262428, -1.1954586506, 0.8806062937, + -0.0880520642, 0.1150913313, -1.0539691448, 0.6986237168, 1.8885309696, 0.9215537906, 1.8435418606, -2.1448302269, + 0.3851986229, -0.713119328, -0.3901919425, -1.3624395132, 1.5063632727, -0.4614166915, -0.3000406027, -0.101355955, + 0.0810948461, 1.5957373381, -0.5460469723, -1.3816664219, 0.537984252, -0.6066759229, 2.2901933193, -0.7612150311, + 0.5551570654, -0.9203477502, 0.7038357258, -0.6596065164, -1.1327278614, -0.743524611, 1.0183490515, 0.6444005966, + -0.6632887721, 0.1449518502, -0.9932124615, -0.7061646581, 0.6948489547, 1.6899902821, -0.303655684, -0.7680572867, + 0.4792656898, 0.4494149387, 1.9874323606, 0.1310714483, 0.5772669911, 0.427146554, -0.3796473444, -0.5137271881, + 1.3119901419, -0.6844062209, -0.5254566669, 0.064529404, -0.2315711081, -0.9539589286, -1.5046663284, -0.3089866936, + 1.3342427015, -0.7204396725, 0.338465035, 0.0651963726, 1.038751483, -2.1739177704, -0.7222473621, -1.8249527216, + 0.5022072792, 0.0201506056, -2.222114563, -1.7429068089, 1.2421858311, -0.2116023302, -0.7000771761, -1.1120636463, + 0.2420840859, 0.5119414926, -0.9397857189, -1.3358485699, 2.844483614, -0.96197474, -0.8597752452, -0.3271184266, + -0.5138223767, 0.0424317084, -0.0836657956, 1.0398344994, 0.1050056592, 0.702362299, 0.0821461901, 0.9920848012, + 0.6409959793, 0.3868029118, 0.167946294, 0.4380161464, -0.8118830323, -1.0857101679, -0.8440061808, 0.8092541099, + 0.1587680727, -0.5558717847, -0.2662746608, -0.78280586, -1.8595489264, 0.6069732308, -1.0864323378, 0.0739274174, + -3.2514317036, 1.3766409159, -0.4158675373, -0.6441162229, 0.5918098688, -0.3352716565, -0.6861219406, 0.6173312068, + 0.8340231776, 2.1576929092, 0.7559766769, -1.9395177364, -1.506803751, -1.6640449762, -1.0494740009, 0.3865607977, + -0.8776586056, -0.3444928527, 2.268889904, 0.1278932095, 1.4168598652, 0.540800035, -0.4373477995, 0.7047700286, + 1.6746137142, 0.0112737603, -0.4115543067, 0.4049486816, 0.3209570348, -0.0363627002, 0.0535618663, 0.9652701616, + -1.0335603952, -0.8917180896, -1.021289587, -1.2253913879, 1.3610954285, 0.5986154079, 1.2577533722, -1.1704236269, + -2.7986218929, -0.2227247208, 0.6540288329, -0.5734651685, -1.3834633827, -1.4270046949, -0.7254546285, -0.6367143393, + 1.8409622908, 0.0058467253, 1.426265955, 0.1178915799, 0.5660122037, 0.9328692555, -0.3919641376, -1.2900167704, + 0.597819984, 1.0307321548, -0.6817595959, 1.572832942, -0.9726041555, -0.3166731596, 1.4570447206, -2.8043234348, + -0.1258659363, 0.1362825036, -0.2868614495, -0.8499239087, 0.7297567129, 2.0664722919, -1.0674616098, -0.0646936595, + -0.4705346525, 0.8866371512, 0.0606195629, -0.2033787519, -1.0553119183, 0.27349931, -0.1094169468, 0.2509588599, + -1.0711268187, 0.2432459742, 0.7302077413, 2.0591175556, 0.9453964829, 0.7122648954, 0.1843675375, -0.8156602979, + -0.9698758125, -0.3812840283, 0.5082962513, -0.6116515398, -1.4949227571, -0.8798989654, 0.1354723424, -0.3616631031, + 0.4147650898, -0.3228835464, -0.5915602446, 1.3671255112, -0.5830543637, 1.1036515236, 0.0076271435, -0.8378448486, + -0.9426112771, 1.0647289753, 1.1454114914, 0.6047657728, -0.5769218802, -0.342354387, -0.0147391697, -1.2193109989, + 0.87343961, -0.5175681114, -0.8919221759, 0.6767447591, -0.3358008564, -0.5971326232, 1.1393744946, 0.1059352309, + -1.0928663015, -0.0023749452, -0.8992219567, 0.5955408216, -0.1915006489, 0.9519176483, -1.6528651714, 0.4768061042, + 0.2691729665, 1.0863753557, 1.7779698372, 1.6851940155, -0.5937855244, -1.2471388578, -1.4843024015, -1.6690483093, + 0.8079186678, 0.6009854674, -0.1532800347, -0.4540135264, 0.8403998017, 0.0214106571, -0.6578392386, 1.58334589, + 0.3572075069, 0.0490770936, 0.3193014264, -0.0974152535, -0.2502352893, 0.7973176241, -0.7291021347, 0.0530070215, + 1.3097430468, 0.3382050693, -0.4680342078, 0.5104855895, 0.3980289996, 2.761702776, 2.8023548126, -0.9081757069, + 0.0257167872, -0.67206043, -1.02782619, 0.5908465981, 0.1360614896, 0.0536954999, -0.6864715219, 0.2259481102, + -1.7827547789, -0.4555638433, 0.429068625, 1.1622430086, -0.4761041105, -0.1950169206, 0.2584655583, 0.9476106167, + -1.285574317, -0.1756140739, -0.1077017039, 0.972704649, 2.2783825397, -0.7615939975, -0.0914252028, -0.4492025077, + -0.1590934247, 0.3942250311, -1.8457733393, 2.9138922691, -0.6026506424, -0.646030128, -1.1496130228, 0.2545246184, + -0.1576082557, 0.4011459947, -1.0190671682, -1.5612306595, -0.8178557158, 0.1179975867, -0.1237922013, -0.1505875736, + -1.5492738485, 0.564011395, 0.4910785556, -1.4756758213, -0.0605845712, -0.7968961596, -0.3090079427, -1.4476984739, + -0.044636298, -0.7001911998, 0.9888365865, 0.0728237554, 0.5284053087, 0.192195639, -0.0171768777, 0.6343825459, + 1.2951797247, 0.6299999356, 0.5879244208, 0.2705804408, -1.6909981966, 2.4678122997, -2.3150990009, 0.7861059308, + 1.1524168253, 0.0536516793, -0.7031561136, 2.6576049328, -1.3356398344, 0.4453574717, -0.0873836875, 0.8940993547, + 1.7681417465, -0.9471057057, 0.7181583047, -0.9346099496, -0.8268125057, 0.8860337734, -1.6342958212, -0.982303679, + 0.2693607807, 1.3396952152, 0.0485697836, -0.3400638998, 0.7500931025, 0.322532773, 2.6488277912, 0.3102334738, + 0.8130268455, -1.1668528318, 0.9298003316, 0.3419047296, 0.3981050849, -0.7024795413, -0.0838392451, 2.1503913403, + 0.3166868687, -0.4655977488, -1.0422612429, 0.5906660557, -0.3481139243, -0.0162188802, -0.1142532825, -1.6149265766, + 0.0337558053, -0.8138551116, -1.9581266642, 1.8291319609, -1.5578610897, 2.1736629009, -0.7472221255, -1.7286211252, + 0.793204844, -0.5200570226, 0.1771980226, 0.7093726993, 1.9725366831, 1.6122074127, 1.6713001728, -0.2878654003, + 0.9476270676, -1.9848715067, 0.6367865801, -0.8831424713, -1.0610102415, 0.6461561322, -0.9139950275, 0.2092022151, + 1.7103219032, -0.3820849359, -1.5692948103, -1.8255572319, 0.396294862, -0.1347055435, -1.369238615, -1.3420454264, + -0.0727353171, 0.6803857684, 0.2496832758, -0.7072216868, 1.5534228086, 0.5460235476, -0.1979304999, 0.4633287787, + -0.376190573, -1.1127810478, -0.2559715807, 0.0235608853, -0.6353579164, -0.6384484768, 0.6815594435, -0.4563060701, + 1.2554326057, -0.453402251, -1.7506196499, -0.5014964938, -0.2295739204, -0.1924448907, -0.4733704925, -0.2241870314, + -0.8210021853, 0.5572533607, 0.2077593505, 1.322603941, 0.8503068686, 0.3388375938, -0.5830029249, 2.0334277153, + 1.0397149324, 1.2391461134, 1.0362479687, -0.5698149204, -0.6259616017, -0.2362915277, -0.3661133647, -0.8876191974, + -1.669980526, 1.5485368967, 0.0311318263, -0.7217914462, -1.2424839735, -0.0392079912, 0.313965559, -1.0111051798, + 0.7933912873, 0.3894520998, 0.2327877879, 0.6048811674, 0.861593008, 1.2502133846, 0.3906288147, -0.5203686357, + -0.1070114747, 0.857768774, -0.7629805207, -1.5210009813, 1.3381309509, -1.6148548126, -0.238740012, -0.1157045662, + 0.1873877794, -0.9930270314, -1.7484232187, -0.9100748301, -0.2736967206, -0.8384456635, 0.0644456372, -0.6747201681, + 1.2409303188, -1.3965411186, 0.5551806688, -0.2347596139, -1.5017775297, -0.4084243178, -0.6948349476, 0.6206647754, + 1.0374354124, 0.8068956733, -0.925861299, -0.3243401945, 0.3644148707, -1.1015172005, 0.7313768268, 0.8892873526, + 0.14803873, -1.0648075342, -1.4160317183, -0.9014066458, -0.4222130179, 0.24458161, -0.5626324415, -0.4851743877, + -0.3403742909, 2.9591856003, -0.0881588683, 0.5897176266, -0.2818697095, -0.4818490148, -0.0522636548, -0.7201578021, + 0.8085952997, 0.7062283158, 1.3574514389, 3.1008806229, 2.4156870842, 1.3525607586, -2.009125948, -0.0851096436, + 0.9077156186, -1.2800422907, -0.8717706203, -0.0972527489, -0.501840353, -0.3444746137, 0.719101131, 0.1668957919, + 0.5495115519, 0.8817923069, -0.9869719744, -0.4999747574, 0.4192822874, 2.0949213505, 1.0182723999, -0.9415771961, + 2.1363947392, -0.1266851574, -0.1686273217, 0.1555329263, 0.2692514956, 0.0107193282, 0.6864767671, -0.3113112748, + -0.6079178452, 1.038421154, 0.3583306968, -0.0989136025, -0.1000434235, 0.11194738, 0.9623701572, -1.6869838238, + -1.770242691, -0.5314478874, -0.1993282437, -0.2009946853, 1.0972038507, 0.1889088154, 0.7660380602, 0.69591856, + -0.090324007, 0.4758541286, 0.4996165335, 0.3103198409, -0.2523146272, 0.0269732401, 0.7140724659, -1.4831380844, + 1.7946801186, -0.2277995795, 1.5964488983, 1.7150933743, -0.1319871843, -0.3674093485, 0.7914146185, -0.3072839379, + -0.8771335483, 1.3631716967, 0.6096215248, 0.0368815847, 1.0796775818, -1.5741424561, 1.8392524719, -0.1673394144, + -0.0709104463, 1.3131312132, 0.1592441201, 0.789698422, -1.4784001112, -0.2822154462, 1.2148447037, -0.096761182, + -2.2488405704, -0.1258734167, 0.1380659342, -0.7507057786, -1.7866828442, -0.1211231351, 0.4181524813, 0.3321387172, + -0.1422798783, 0.59919101, 1.8145097494, -0.2987695634, 0.1185233369, 1.7562841177, -0.0889143497, -0.8222903013, + -1.4978560209, 1.5606752634, -0.7209838033, 0.9876718521, 0.7995440364, 0.3725219369, -0.1506541669, -1.4730818272, + 2.0495085716, -0.4954752922, 1.1434779167, -0.5692482591, -1.4061460495, 0.6421436071, -1.8218369484, -1.2275563478, + -1.0374466181, 1.6718900204, 0.3865244985, -0.726398766, 0.5036387444, -0.1251687109, 0.0561733358, -0.0534702614, + 1.3122061491, 0.3336322904, 0.4826311469, 1.7704149485, 0.1591441482, 1.5266855955, 1.2783801556, -0.698618114, + 1.0752340555, 0.4369335771, -0.4910381734, -1.2765337229, -1.5475559235, 0.1101098582, 0.4548444748, 0.4179526865, + 3.5148334503, 1.3793034554, 1.2272132635, -0.777541101, 0.1388985366, -0.9853470922, -2.1588702202, 1.4759497643, + 1.0479900837, -0.2329456359, 0.4264881909, 1.6505819559, -0.6207741499, -1.3017786741, 0.8918532729, -1.838476181, + 1.6479315758, 1.4943436384, -0.2758189738, -0.4083052278, -1.7543193102, -0.8631698489, -0.3464847505, -1.0863679647, + -1.043967247, 0.7048197985, -0.6013585925, -0.5195314288, -0.4424979389, -1.3421670198, -0.1133228242, -0.1815241724, + -0.4386858344, 1.2019025087, -0.551838398, 1.4825443029, -0.1924960464, -1.3046330214, 0.8492895961, 0.3339430988, + -0.4778641462, -0.7398019433, -0.1873675436, 0.9931180477, 0.175874263, 1.1829441786, 0.568086803, -1.5838301182, + 0.1504982114, 0.6607076526, -0.0231101718, -0.1185555682, -0.1340669245, -1.0390249491, 1.7121312618, -0.0431025848, + -0.3924097121, 0.5211667418, -0.8721234202, 1.0714064837, -0.264234066, -0.4705439508, 1.507091403, 0.0275213439, + -0.8787099719, 0.2398306876, -0.9827113152, 1.2846596241, 1.2042113543, -0.2682869136, -0.0602881312, -0.1187253222, + 0.1935069561, 0.6068314314, -0.9962551594, 0.1362517178, -0.5295902491, -1.4795718193, -0.3208876252, -0.0433504656, + 1.3398160934, -0.5696412325, -0.1615510434, 2.2393598557, -0.4070459902, 1.1034712791, 0.8850687742, 0.4269449711, + -0.0309651364, -0.3605507016, 0.7600423694, -0.7894233465, -0.197464779, 1.5508267879, -0.8302157521, -0.3430190384, + 0.0971933901, 0.7561179996, 0.1921995878, 0.6613284945, -1.3063372374, -1.8925228119, -0.5819588304, 0.0686352998, + 0.7780308723, -0.1821022481, -0.278435111, 0.9828819633, -0.3580800891, -1.4925870895, 1.1827394962, -1.2048211098, + 0.0015660966, -0.705604434, 0.3516597152, -1.3311002254, 0.1076234132, -0.9575064182, -0.5319263339, 2.2485411167, + -0.8890992403, -1.5095508099, -1.4435843229, 1.2062375546, -1.037350893, -0.960043788, -0.2674483955, -0.8744071722, + -0.8395624161, -0.2602224052, -0.0716149807, 0.1754660159, -0.0509066172, -1.3418159485, 0.9362290502, 2.050160408, + -0.8092800975, -0.2566420734, -0.9628132582, 0.4812192321, -1.7650332451, 1.6551828384, 0.2969235182, 1.9384123087, + -0.7422243357, -0.8657963872, 1.9764961004, 0.2587822676, -1.2811017036, 0.8559010625, -0.2178717405, 0.551301837, + 0.6288032532, 0.3456377685, 0.0518872105, -0.2260817885, 1.3474808931, 0.4960836172, 1.1231657267, -0.2785956562, + 0.1864937544, -0.9686026573, -0.4685764611, 0.0343641862, 0.8239734769, -0.038208656, 0.8648043871, -1.519274354, + -0.3801605999, -0.7757578492, 0.6177380085, 1.1645232439, -0.3902976811, -0.4834443033, -0.509975493, 1.1100440025, + 1.9989259243, 0.012094724, 0.7738932967, -0.1626637578, -0.274882853, 0.1500775963, -0.1423937976, 0.755895555, + -0.2406939566, -0.8073249459, -0.8291538358, 0.5597535968, 0.6038845181, -0.4026309848, 0.6417809129, -1.0559430122, + 1.4719893932, 0.5502031446, 0.4619366527, -0.3297341466, 0.9770031571, 1.1077107191, 0.6487148404, 1.059276104, + 2.2452018261, -1.4517990351, 0.3241731226, 0.5708991289, -0.2178623378, -1.4555898905, 0.8619402647, -0.7125315666, + -0.4648037255, -1.1987832785, -0.387580961, -0.8089615107, -1.665220499, -0.6737309098, 0.4696156383, -0.9500765204, + 0.5246605277, -0.3600152433, 1.0752583742, 0.363026768, -2.2392160892, -0.4884197116, 0.0897057503, 0.5078607798, + 0.2434695959, 0.6669661999, 0.1939474046, 1.1956789494, 1.2731165886, -0.2553974092, 0.5463133454, 0.7415204644, + 0.8253844976, -2.2207424641, -0.5939807892, -0.540551722, 0.5992439389, 0.552749157, 0.2647654712, 0.3965257108, + 0.7488173246, -0.6501255035, 0.7335247397, 2.3412547112, -0.2428223044, 1.3753275871, -1.7682363987, -0.081121482, + -0.1482257694, 0.0008704733, -1.155954361, 0.4070131183, 1.3749901056, -0.3521507978, -0.5838592052, 0.7910311222, + -0.8108868599, -1.7694545984, 0.686096549, 0.6280745268, -0.0189835038, 0.7401046753, -0.0957614034, 1.5742759705, + 0.6285890341, 0.6735109091, -2.2882628441, 0.9412603974, 0.8516026139, -0.2982982099, 0.7832838893, 1.8826241493, + -0.6292356253, 0.5742823482, 1.9699435234, -0.9881187081, -0.6871194839, -0.7571073174, 1.7136073112, 0.0445418991, + -1.3317672014, -0.0278986376, 0.1168358251, -1.9115582705, -0.3436582088, -1.2878416777, -0.4543692172, 0.4965259731, + -0.3469325006, -0.2261100411, 0.7186712027, 0.4477775395, -1.1620095968, 0.6727824807, -0.0883801803, -1.8939939737, + -1.2754259109, 1.0608910322, -0.8201976418, 0.2681608796, -1.5161629915, 2.138453722, -0.0212910455, 0.6318595409, + 0.0462469086, 0.3144905567, 0.3767325878, -1.1331812143, -0.2977827787, 1.0825668573, 0.5229936242, -0.8243591189, + 0.2687449157, 0.4557905197, -1.6796916723, 0.0562063754, 0.5043262839, 1.0077110529, 0.6924237013, 0.991032362, + -1.1296902895, -0.8210905194, -1.4609053135, 0.942702353, -0.6383852959, 0.1021938547, 0.5141855478, 0.0296744183, + 1.2136639357, 0.652818203, -0.4292894602, 1.3012942076, 0.844517529, -1.8041859865, -0.0520955026, 0.6637779474, + 0.8166362047, 0.4969393611, 0.161291942, -1.2245982885, 0.8383113146, 0.1584201306, -0.6001465321, -0.6403214931, + -0.2489199936, -0.8059918284, -1.7376863956, 0.2539567053, 0.9096975327, 0.9964336753, 1.1921913624, 1.0994590521, + 0.0866026059, 0.1853996962, 0.3626529872, -0.600964129, -0.814129591, -0.1610737592, 0.0605895333, -0.697683394, + -0.6364158392, -1.6901087761, -1.4714292288, -0.815171361, -1.0487115383, 0.6838766336, -0.5414502025, -0.5800019503, + 0.4200898111, 0.8287611604, 0.2556479871, 1.024310708, 0.683275044, 0.906137526, -1.0559997559, -0.5638802648, + -0.0439743996, 0.1173364073, 1.6787053347, 0.3498084545, 1.0181390047, -0.5923074484, 0.354662329, -2.6732180119, + 0.7222507596, -0.952881515, 0.6282278299, 0.6948962212, 0.7244352698, -0.4419042766, 0.6062676311, 0.4268949032, + 1.2982889414, -0.0492773838, 0.1728408486, -1.8239735365, 0.084202379, -0.1465672702, -0.5029066205, -2.5519418716, + -0.8701648712, -0.3346950412, 0.8195809126, 0.9252887964, -0.4902196527, 0.773019433, -1.904671669, -1.5051252842, + -2.404897213, -0.2875409722, 0.8639270067, 0.7805999517, 1.4741975069, -1.3624743223, -0.8319619894, 1.3560540676, + 0.3230776787, -0.8606194854, -1.7348588705, 1.6464912891, 0.9878881574, 0.6745097041, -0.713613987, 1.6001394987, + 0.1300480217, -1.541040659, -0.5384830236, -1.4236744642, 0.5284870267, 0.1341856122, 0.2507516742, 1.0759317875, + 1.054361701, -1.2375645638, 0.1014309525, -1.2856109142, 1.5152353048, 1.0129420757, -0.5068862438, -0.0818387121, + 0.8557261825, 0.6897322536, -0.6936151981, 0.8198645711, 0.5045341253, 1.4971163273, 0.7517387867, -1.0433621407, + -2.2742910385, -0.5024763942, -1.5331497192, -0.663285017, 0.1812437326, 2.9718608856, 1.1071363688, 0.1692442596, + 2.0369729996, 0.4972907901, 1.4878046513, -0.1821295917, 1.4015305042, -0.8876495957, 1.7378798723, -0.8951967955, + 1.0968136787, 0.7477356195, 0.5420276523, 0.8818691969, 0.7651853561, -2.1793744564, 0.1379532367, -1.5338999033, + -1.6719213724, 0.8710910678, 1.4140412807, -0.8285297155, -0.4181405008, 1.0015592575, 1.0259017944, -1.0662993193, + -1.5625612736, 1.54251194, -1.5811508894, 0.0358812883, -0.45838359, -0.2951638699, 0.6391587853, 1.2410137653, + -1.0080453157, 0.0030940096, 0.8546661735, 0.5233162642, 0.1683357954, -1.0702836514, 0.6986927986, -2.6348586082, + -0.2744528651, 1.0474078655, 0.6944044828, 0.428208828, 0.5804508924, -0.2621594965, -0.1507897526, -0.6044706702, + -0.5499491096, -0.8979150057, 0.6255866289, 1.9500479698, -0.3619381189, -2.0538542271, -2.2297744751, 1.2849069834, + -1.6552209854, 2.3148140907, 0.7873542905, -1.1823868752, -1.3611557484, 1.6840388775, 0.8037516475, 0.1811046898, + 0.102583997, -0.0465708077, 0.9594902396, -0.5949816108, -0.4117023051, -1.0228437185, -0.0251171757, 0.8824501038, + 0.7591711283, 0.6231270432, 0.5917374492, 0.6219696403, -0.0495552123, 0.4270074368, -1.1682341099, -0.8261880279, + -0.5186452866, 0.9526984692, 0.2365787178, 0.7776110768, 0.7848405242, -1.3479496241, -0.6416763067, -0.33903265, + -0.5502781868, -0.9254025221, -1.2017199993, 0.104446806, 0.5422565341, 1.1859241724, 0.0673230439, 0.3402942121, + 1.9644356966, -1.2449916601, 2.0009057522, -1.7514717579, -0.1355766803, -0.0298841372, 0.0156432688, -1.6379914284, + 0.0300169382, -0.1188428104, 0.4865311384, -0.5542267561, 0.2956261337, 0.8642213941, -0.3620271087, 0.5115072727, + 2.4552910328, 0.1400547177, 1.0980756283, -0.9341176748, -0.0969975144, 1.026345253, -1.557536602, -0.6205061078, + 1.107848525, 0.9087997079, 0.0788982362, -0.2932177484, -2.6274516582, -0.5674450994, 0.8807153702, 1.8894174099, + 0.525729537, 1.7268207073, -0.0833458751, 1.6114909649, 0.5052893758, 0.8463229537, 0.4828009903, -0.0895236433, + -0.2982712388, 0.4179650843, -0.0710343793, -0.5111294389, 0.3934566081, 1.1269727945, 0.5989762545, -0.1793426871, + -0.562700212, -0.3595992625, 0.575331986, 0.3222674429, -1.3311716318, -0.5409787297, 0.1170743182, 0.1916641593, + 2.1233403683, -0.3985538185, 1.1539492607, 2.1156904697, -0.2566215396, -1.5207226276, 2.0685455799, -1.1869761944, + -0.8740059137, -0.424208194, 1.5217876434, -1.5788558722, 0.5758740306, 0.3150611818, -0.7949121594, 0.5349891186, + 0.4776623845, 0.4408864379, -0.5021479726, -0.2214682847, -0.4992967248, -0.0067575639, -1.8457427025, 0.9280284047, + -0.6053181887, 0.7470316887, -0.0616565011, -1.2198575735, 0.0267692748, -0.6104433537, 0.0101288538, -0.3280124068, + 1.1101564169, 0.3608153462, 0.4453727007, 0.9636499882, -0.830409348, -0.4685767293, 0.9103437662, -0.698238194, + 1.1686404943, 1.1610959768, -0.1441449672, 1.0166361332, 1.8670653105, -0.1394449472, -0.4043854177, 0.5049604177, + -0.6021443605, 0.2187743187, 0.3758377731, -2.1905653477, -0.439853102, 0.1216888949, 1.1135267019, -1.3173891306, + 0.5598527193, -0.0590468831, 0.6931667328, 2.4740109444, -2.0966489315, 0.1619170755, -1.5034503937, -0.6038945317, + 0.5554865599, -1.4479967356, -0.891702354, -0.6455559731, -0.4626631737, 0.4900054634, -0.3706803024, 0.5256991386, + 0.1678807884, -0.5502416492, -0.3375319541, -0.3431487679, 2.1183767319, -0.7996915579, -0.3146005273, 0.3703980744, + -1.0030088425, -1.9712535143, -0.2197760195, -0.2830720842, -0.166787535, 0.5648902655, -1.6655410528, 0.7426096201, + -0.1408229321, -0.3646937609, -0.3127844632, -3.034766674, 0.1353932172, 0.6488391161, 0.5635000467, 0.6422799826, + -0.5255937576, 1.3670353889, -0.1994901747, 0.2347858846, -0.5399846435, -0.2052275538, 0.776101172, 0.3517878354, + -2.4709758759, -0.561327219, -0.0516717657, -1.9915071726, -0.8145096898, -0.1598192304, -0.4733167291, 0.3067771792, + -0.4550936222, 0.492841661, -1.5474539995, -0.5095470548, 1.3454902172, 0.6438094378, 2.3404154778, 1.0623267889, + 0.260869801, 1.3165721893, 0.3916930854, 1.2871226072, -1.1001724005, 0.4859510958, -1.0528469086, 0.00485582, + 0.5584079623, 0.8512579799, -0.9370487928, -1.2440121174, 1.4365291595, 0.0317177959, 0.2058206797, 0.0645339563, + 0.2769898772, 0.0672572851, 1.3564913273, -0.8004226089, -1.0108019114, 0.2683846056, -0.3449343443, 0.5715727806, + 1.810556531, -0.4251840413, 0.0933929682, -0.0318874568, -0.0917476565, 0.2792342305, -1.3499195576, -0.3130746782, + 0.1089106649, 0.791143477, 0.1674464196, -0.5621147156, 0.0358672328, 0.37397331, 0.1566600949, 1.624791503, + -1.3720308542, 0.0518179424, 0.2691105306, 0.1931755841, 0.0992060304, -0.0557342619, 0.641598165, 0.2318139821, + 0.1195221543, -0.7894995809, 0.708668232, -0.2938629985, 0.4510083795, -0.2968471646, 0.9600773454, 0.8050220609, + 0.9683947563, 0.5477582812, 2.1819415092, 0.2233613133, 1.3260169029, -0.3495138288, 0.0223538298, 0.1567016244, + -0.7688352466, -1.020154953, -0.0924670175, 0.0193462633, 0.3662928641, 0.5027229786, 0.4168736339, -0.6279435754, + -0.4090660214, -0.2738506794, -0.7319854498, -0.7716166973, -0.4655268788, 0.0913858637, 0.6756829619, 1.0749363899, + -2.9845871925, -2.3411133289, 0.7401157618, -0.5512769222, 1.1327184439, -0.3372319043, -1.0306859016, -2.1232624054, + 0.1218878105, 0.2254609168, -1.8603311777, 0.1255722195, 0.1211966723, -1.5937081575, 1.2448704243, -0.4653194249, + -1.1432752609, -0.8448824286, 0.4323055148, -1.5212147236, 0.4646244943, 1.2543433905, 0.6006751657, -0.5522754788, + 0.6215143204, -1.3684450388, -1.291349411, -0.7055885792, -0.79358989, -0.2950033844, 0.8652331233, -0.3805498779, + -1.6659548283, -1.2524651289, 0.0942175016, 0.4701784253, 0.4993986189, 0.3036863804, 0.3379638195, -1.0666376352, + 0.9350460768, 0.0076516639, 0.8255095482, 2.0182163715, -0.2377916873, 0.425004214, -1.2792454958, 1.1763788462, + -2.410741806, 0.0559295639, -0.8411914706, 0.9756729007, -0.2996968329, 1.1991971731, -0.0036011224, 1.513070941, + -0.7111702561, -1.3614077568, 2.2163901329, 1.9284011126, 0.6578730345, -0.5633271933, -0.535007298, -0.6862948537, + -1.6068059206, -1.5318435431, 0.6679149866, 1.0064121485, 1.1902654171, 0.2330749482, 1.5748063326, 1.1538707018, + -0.9454938173, 0.4218579233, -0.6603856087, 0.5557044148, -0.3310923576, 1.267026782, 0.6889605522, 0.5879198909, + 0.8793924451, 0.5530157685, -1.3612712622, 0.6004394293, 1.5862592459, 1.7088806629, -0.3228707016, -1.5339814425, + 1.3532996178, 0.1337690353, 0.4033794701, 0.9362673759, 2.5070328712, -1.4719178677, 1.1299579144, -1.258912921, + 0.8528534174, 0.8711306453, 1.6040962934, 1.7402243614, -0.6684724689, -0.8084316254, -1.1939450502, -0.2090555429, + -1.565328598, -1.6939487457, -0.7268587351, -1.823761344, 0.1104834676, -0.5062472224, 1.1678825617, -1.4700238705, + -0.8294458985, -0.4625340104, -0.2558137476, -0.5204338431, 0.5611996055, -1.4619174004, -0.6257733107, -0.7569713593, + 0.7612380385, 0.6510775685, 0.4265863895, 0.8792460561, 0.0824565366, -0.6086297035, -1.2662295103, -0.5894017816, + 1.4452910423, 0.6569434404, -0.3121954501, -1.8380763531, 2.0977277756, 1.160641551, -0.8928475976, -0.2812048793, + -0.7891488075, -0.5135432482, 0.1404644102, 1.7727484703, -0.7247069478, -0.4047034383, 1.1784008741, -0.0882060081, + 0.4330866337, -0.239893198, 0.6297299266, -0.7113015652, -0.288808167, -0.6917343736, -1.0160704851, -0.0501448251, + -1.7557926178, 0.8874514103, 0.6896318197, -0.9837778211, 1.9327976704, -1.7024279833, 1.1284931898, -1.739287138, + -0.185694173, 1.372315526, 1.3488906622, -0.2660662234, 0.9858436584, 0.3364506662, 0.4291782975, 1.2164518833, + 1.5936523676, 0.5462658405, -1.1891343594, -0.3331855237, 0.0216330234, -0.372012645, 0.6676066518, -0.1610603034, + -0.6453488469, -1.2660588026, 0.1885916442, -0.1913194507, -0.2533226907, -0.4697803855, 0.0147942333, 1.9812374115, + -0.0728941634, 0.4952958822, 0.0687560663, -0.6622215509, 0.04221531, 0.0999927744, 1.8953807354, -1.499627471, + -0.581481874, 0.7663285136, -0.6812976599, -0.10662058, 0.2546959221, 1.2007323503, 1.3327698708, 0.2031353116, + 0.7176383138, 1.2447898388, 0.489120543, -0.9856312275, 0.8673879504, -0.6054337621, 0.4199489355, 0.1581125259, + -1.4761838913, 1.122459054, 2.9868655205, 2.0953581333, -0.6189078093, -0.7180119157, 1.2323864698, -0.4477436841, + -0.414280802, -0.1765896827, -0.9405736923, -0.3397848606, 0.6380889416, 1.3421542645, -2.2330129147, 0.2280873209, + 0.7671604753, 1.4022625685, -1.3546260595, -1.7892752886, -0.9778614044, 0.2651600242, -0.7413028479, 0.2085521221, + 0.673130393, -1.5684994459, -1.0101099014, -0.502391994, -0.670014441, 0.7095361352, 0.802500546, -0.2038030177, + 0.4760249555, 0.4454511702, -0.5939602852, -0.7164628506, -1.5171319246, 1.4800959826, -0.0717306584, 0.9497123361, + 1.4563376904, 1.543345809, 2.4010305405, 3.3334319592, 0.4822435677, -0.5614119172, -0.90171206, 0.9639977217, + -0.2467245311, 0.6018739343, 0.6744873524, -0.7295719981, 0.2263079584, -0.0595782287, 0.4756217003, -0.1380271614, + 1.4944998026, -1.1411798, 0.4533945322, -0.5606918335, 0.6212491989, -1.1574071646, -0.2401100546, -0.540107131, + -0.8303443193, 0.3478609622, -0.8683995605, -1.3129228354, -0.190875411, -1.869515419, -0.3507457078, -1.6960946321, + -1.410905838, -0.0006375873, -1.9163777828, 2.3475019932, -0.9438844919, 0.9024425149, 1.2787234783, 0.2669394016, + 1.0342036486, -1.1763765812, 0.2994127572, -1.5218186378, -0.6456666589, -0.0896530226, -0.3566700816, -0.5822973251, + 0.2027257532, 1.200707078, -0.9537147284, -1.7942665815, -1.650211215, 0.379476577, -2.1909353733, 0.3905528784, + 1.6661679745, -1.2986001968, -1.2059516907, -0.9303827286, -1.6575475931, 0.2639370561, 0.2804372013, -0.1337700784, + 0.4575373232, 1.4409017563, -1.3529820442, 1.1944533587, 0.1142227128, 0.1391180605, 1.3320208788, -0.5805708766, + -0.4466572404, -0.8611194491, -0.1826741546, 0.3247959912, -0.4794469774, -1.551228404, -0.698762536, 0.7923681736, + 0.3309248388, -0.527467072, 1.7341567278, -0.5651237965, -1.1047180891, -0.87570858, 1.9002363682, -0.5654552579, + -0.1503885388, 2.3177163601, -1.0674678087, 0.4179449975, -0.8482495546, 0.150803566, -0.2906613052, 1.7630039454, + -0.4032920003, -0.8586524725, -0.8267387152, -1.0485448837, 0.4945226312, 0.8998538852, -1.2160298824, -0.4785618782, + -0.3782664239, -0.1571599543, -0.7503957748, -1.5480009317, 0.2291377932, 0.6442772746, 1.8228875399, -0.0811340883, + -0.9858629107, 0.1007367, -1.023124814, 0.8747323155, 0.7531514168, -1.6565316916, 0.9526207447, -0.0294028688, + 0.2464197874, 0.1333850771, 0.5864880085, 1.0717082024, 1.4090615511, 0.8718538284, -0.0508552119, -0.0712610632, + -0.1940155625, -0.7806551456, 0.5808362961, -0.0453044698, 0.9831092954, -0.0407605805, 1.6183751822, -0.4711570144, + 0.9464051723, -0.1902614683, -0.5595943928, 0.7917163372, 0.8945364356, 2.0407261848, -0.0378948264, -0.5753856301, + 0.7319956422, 0.7065110803, -0.1146564707, -0.3133381903, -0.6908829212, 1.3543372154, -1.2197914124, 1.0682621002, + -0.4357069135, 0.414268136, -0.8415632844, 0.0666707754, -0.1261732876, 0.4309399724, 1.7831349373, 0.2475240082, + 0.5416277051, -2.3900408745, -0.0873001814, 0.4318037629, -0.0842064768, 0.0386220776, 0.0086299293, 0.4828562737, + -0.312692076, 0.6790862679, -0.0472784191, 1.0052809715, -0.7735071182, 0.4777276814, -0.1993416548, -0.7341573834, + 2.2931449413, -0.801712811, -1.2624527216, 0.4948807955, 1.9594209194, -0.233358264, -1.1403502226, 0.7428901792, + 0.4308326542, -0.0369284041, -0.8011110425, 0.2558170557, -0.8303340673, 0.4260979295, -0.7176937461, 0.3255190253, + 0.2934720814, 0.014097508, -1.6804726124, -0.3438348174, -1.4502503872, -0.9531344771, -0.1847796291, 0.1688913107, + 0.657138288, 1.5159125328, -0.1185081005, -0.9134144187, 2.3134839535, 0.9210193753, -0.1931522787, 1.1115853786, + -1.5775060654, -0.4333670139, 0.9147577286, -0.8540613651, 0.4533645511, -1.5374147892, 0.3218281269, -2.0726091862, + -0.2654472589, 0.4145475924, -2.7371721268, 0.0493369773, -0.8245742321, -0.7906406522, -0.4056213796, -1.2431070805, + 0.1490028054, -0.5710224509, -1.1668577194, 0.3953489661, 0.706874907, -0.3533940911, -1.9965847731, 0.8758977056, + 0.4603376687, 1.2675856352, -0.7088031769, -0.6654269099, -0.9213801622, 0.4947441518, -0.0715525448, -1.0028457642, + 0.383095324, 0.4520997703, -1.2615735531, 0.9056553841, 0.3861218393, 0.1425308436, -0.1260088682, 0.9447017312, + 0.6559101939, -1.8171663284, 1.4004011154, -2.0061945915, -1.8255103827, 0.1024764478, 0.1558491588, 1.2420189381, + -0.4764030576, 0.3463437855, -1.7062416077, -1.5446808338, -0.32154724, -0.4196771085, 1.8047077656, -1.8244951963, + -1.2479240894, 0.8842428923, -0.737593472, -0.4316256344, -1.1759667397, 0.3775776029, 0.3401539326, -0.7903994322, + 0.4455604553, 0.514826715, 1.0482620001, -2.2607221603, 0.0069156969, -0.9996435642, 0.4997765124, -0.8113646507, + -0.2739197314, 0.7623291612, 1.9041544199, 0.0038511909, -2.2380661964, 1.2144907713, -1.3699985743, 0.5216916203, + -0.995395422, -0.067885533, -0.9681578875, -1.0197651386, 0.4510965943, -0.9384776354, 0.4080997109, 0.2205782682, + 1.4572985172, -0.0716064721, -1.3010287285, 1.0668503046, 0.5560036302, 0.0169553459, 1.3414565325, 0.3216943741, + 0.4991309047, 1.4584230185, 0.2209969759, -0.6442297697, 1.269141078, -0.0391359441, 1.1090129614, 0.3669699728, + -1.2093535662, -0.2478190958, 1.0072946548, 1.3478624821, 1.4052371979, 0.7991831899, -0.5470215678, 0.1076327264, + -1.220903635, -0.2053703666, 0.6416805983, 0.8527611494, 0.8009208441, -1.1441555023, 0.5289140344, -1.3059980869, + 0.8233359456, -0.9994716048, 0.4629640877, -0.9534198642, 1.9949338436, 1.0057520866, 0.4678486586, -0.4734914899, + 0.0677830651, 0.3521122932, -0.110740155, 1.0441912413, -0.4773075581, 1.387367487, 0.5615459681, -0.797694087, + -1.3771500587, 0.8169613481, 1.3486270905, 0.5091228485, -0.3491946459, -0.4665772915, 0.2233534604, 0.6446563601, + 0.9125355482, 0.925767839, 0.8465470672, 0.0578327812, 1.3858836889, -0.2434680015, 1.6562070847, 0.9416037202, + 0.5632153749, -0.5659677982, 0.5274534225, 1.1877981424, 1.4489836693, -0.74511832, -1.5661666393, -1.183560133, + -0.9559128284, 0.1651993841, 1.136875391, -1.0665529966, -0.4836068749, -0.8145627975, 0.3149281442, -0.188391, + 0.421684742, -1.1827241182, -0.0994306877, -0.343863517, -1.9663894176, 0.2089749277, -1.4949587584, 0.3206232488, + -0.6770358682, 1.1477482319, -0.2624453902, 1.4652047157, -0.0285696778, -0.0104226936, -1.3233613968, -0.5543357134, + -0.1505497992, 0.2329614758, -0.50390172, 0.2137409151, -1.2017041445, -0.6092761159, 0.5041880012, -2.6073977947, + -0.5180581212, -1.2378791571, -0.7136105895, -0.7491711378, 0.8616729975, -0.64713943, -2.42273283, -0.1132138893, + -0.6853970885, 0.3431085646, 0.8768229485, 0.2715342343, -0.3802629411, -0.8611323833, 0.3513724804, 0.5549112558, + -1.283308506, 0.7726469636, -0.4660710394, 2.559530735, -1.7120479345, -0.4161309004, -0.2351716012, 0.3630282879, + 0.9382425547, 0.6695708036, -1.7179670334, -0.5959632993, 3.7025876045, -0.2213580161, -0.1287264526, 0.6192150712, + 1.0531377792, -0.2467512041, 1.4417458773, -0.3152952492, -0.7391575575, 0.159034282, 0.8058029413, -0.1784851551, + 2.3034143448, -0.4181099534, 1.3932461739, -1.1737822294, 0.75385499, 0.6269468069, -0.7819752693, -0.7092577219, + -0.5887012482, -1.0844168663, 0.9721927047, 1.2547427416, 1.7547675371, -0.7578601837, -0.303802371, 0.6221553683, + 0.210560903, 0.6844446659, -0.0726488233, -0.8142358065, 1.5024870634, -0.959941566, 0.804161787, 1.2129323483, + 0.2786012888, -0.4806325436, -1.5507179499, -0.6431815624, -0.9598134756, -0.0414928049, 0.9750754833, 0.213462472, + -0.7340024114, -0.9867333174, -0.9676715136, -0.3153736889, 1.736905098, 0.1728345603, -1.6357651949, 0.5001330972, + 0.0361833759, -0.3400045931, 0.6917695403, -0.6486070156, 0.586575985, 0.6650483012, 2.3782908916, -0.7281708121, + -0.1784517318, -0.6568906307, -0.0668870881, 0.4001824856, 0.598364532, 1.4374731779, 0.8282849193, -0.2202301174, + 1.4063117504, -0.2658022344, -1.0646981001, 0.2660436034, 0.2665685117, 0.8515069485, 0.0041442462, 0.3150144517, + -2.1227982044, 0.7639856339, -1.4190670252, 0.7797390819, 0.9185681343, 2.0322315693, -1.4458156824, 0.1613995284, + -0.4561886489, -0.8995773196, -0.2119886428, 0.1786645055, 0.1776530445, -0.3201810718, 0.1161821634, -0.5768741369, + 0.6252367496, -0.1033955812, -1.0653221607, -2.6090035439, -1.975523591, -0.064329654, 0.356764555, 0.191804111, + -0.298648864, 1.0968306065, -0.4158258736, 1.2320274115, 0.6485459208, 1.6077394485, -3.1362752914, 0.3075769842, + 0.4591005147, 0.3467891812, -0.398265928, 1.1793015003, -1.7780370712, -1.3126175404, 0.4909677207, 1.6737562418, + 0.012473233, -0.3899201453, -0.1232452691, -0.610080421, -0.9292196035, 0.8099145889, 0.6836316586, 1.4735952616, + -2.2071619034, 1.993427515, 0.6117762327, -1.5051028728, -2.4555799961, -1.0627012253, 0.9527903199, 1.5368833542, + 0.0395082273, -1.3321162462, 0.5243310332, -0.1798415333, 0.5129242539, -0.449311018, 0.0150246527, -0.9672916532, + 0.9956399202, 0.2072731555, 0.5924943686, -0.508736372, -0.1341209561, 2.0133500099, 1.2745864391, -1.7311307192, + 0.8783261776, 0.2382151335, -0.5218320489, -0.7136888504, 0.9078969955, 0.1662100703, 0.6880350113, 0.6426402926, + -0.1699856371, 0.8449928761, -0.2059611827, 1.2312691212, -0.1832074076, 0.7024871111, 0.0767141655, -1.0377204418, + -1.2589073181, 1.2890216112, -1.6496952772, 1.3731424809, -2.5840425491, 0.8842554688, 0.7858142257, 1.2424460649, + -1.1142414808, -1.6087180376, 0.5588724613, -0.3181532919, 0.1282300502, 0.3226558864, 1.7192137241, 1.8144487143, + 0.0832170099, 1.0794529915, 1.0780323744, 0.18569085, -0.6103316545, -2.1893501282, 1.1166290045, 0.7507947087, + 2.0451416969, -0.0583368354, -0.7521981597, 0.1606955081, 0.9020569921, 0.291519016, 2.0094237328, -0.5653720498, + -2.0505139828, 0.3951239884, -0.1658412069, 0.1319901049, -0.807307601, 1.1072100401, -1.6461715698, -1.6490888596, + -0.7021602392, 0.1291684657, 1.0130834579, 0.4326122403, 0.0710866079, 0.652215302, 0.9110949039, 1.2549139261, + 0.3565925658, 0.4046155214, 0.4020137191, 0.3690601587, -0.4672718048, 1.391238451, -0.4798047543, 1.5850034952, + 0.2715241313, -0.0765904635, -0.1810461581, -1.1558505297, -0.3667913377, -0.3131943941, 1.6469752789, 0.13430655, + -0.6560097933, 0.5086302757, 0.4044632912, 0.6018323302, 1.7113457918, -0.1906548142, 0.0425776057, 0.0373008773, + 0.1381624639, -0.415630579, -0.798163116, 0.058209952, 2.6061866283, -0.7722873688, -0.0470007211, 1.5131361485, + -0.0309810881, -1.0579044819, 0.8854081631, 0.7483155727, -0.2261427641, -0.7398789525, -1.0611298084, -1.4868919849, + -0.4077556431, -0.5551923513, -0.3160439432, 0.7666338086, 1.4771444798, -0.1199424937, 1.2570329905, -0.6283643842, + -0.6694485545, 1.3534792662, 0.1671885401, -0.9664984941, 0.1351937652, -2.2209308147, -1.7459772825, 0.8721058369, + 0.4668622911, -0.9920146465, -0.3378461897, -1.5689595938, 0.036912661, -1.8374615908, -0.9583182931, -0.0569251254, + 0.061463818, 0.3806518018, -0.9281975031, -0.3982549608, 0.6343744397, 0.5360945463, 0.4420194328, -0.1513541192, + -0.1408912539, -1.2138690948, 0.9535938501, -0.1115452573, -1.2844252586, 0.2494014949, 1.4498769045, 0.8719550371, + 0.0237522461, -1.6092516184, 0.1648471653, 0.5427899361, -0.4420486987, -1.4820035696, -0.0689525232, -0.7968429923, + -1.6705019474, 0.769844532, -0.1265096515, 0.7726453543, 0.1753320694, -0.5076130033, -0.1544819772, 0.2653084695, + -0.0847224519, 0.6755714417, 1.0591664314, -0.0757832155, 0.0805232376, 0.0671821758, 1.6652826071, 0.2529174089, + -1.0575348139, 0.0438446961, 0.6698242426, 0.5310724378, -0.4435330033, -0.3427950442, 1.0558329821, -0.9846804738, + 0.5860679746, 1.3339457512, -0.8269437551, 0.9077727199, 0.1672893316, -0.8939241171, 0.3120681345, -0.6364495158, + -0.7267069221, 2.6667218208, 1.1729916334, 1.2637227774, -0.3764693141, 0.1535074413, -0.2704104781, 0.0951040611, + -0.7366018891, -1.2720896006, -0.6093081832, -0.2956297398, 0.1220130399, 0.9173392057, -0.2534488142, 0.452028662, + -1.8082159758, 0.7244623899, 0.7396792769, 0.6426346898, 0.0797319785, -0.5158020258, 0.5891546011, -1.4976643324, + -1.2477073669, -1.7936444283, 0.8376747966, -0.7089396119, -0.1811517924, -0.768851459, -1.4071519375, 0.278472811, + -2.5875277519, 0.9116972685, -0.5199452043, 0.1479708701, -0.8809148073, 1.8356801271, -0.8060521483, 0.4518039227, + -1.6225919724, -2.009884119, 0.1720021516, -0.4275765419, 0.1004268378, 0.1585029215, 0.8063095808, -0.1378083378, + -0.0826101378, 0.6346687078, -0.3701512814, 0.4816154242, 0.3261772096, 0.7613685131, 0.6079658866, -0.6945112944, + -0.2238053679, 0.0034116469, 0.0198742934, -0.6288275123, 0.3040928245, 1.0772180557, 1.1524056196, 1.162930131, + -0.3494142294, 0.5766470432, 0.3408490717, 0.4503265023, -1.014472127, -0.0498800389, -0.5482375026, 0.3489536345, + 0.7263273001, -0.9238932133, -0.3699231446, -0.8713849783, -0.7335543633, 0.8255431652, -1.5280839205, 0.5197145939, + 1.0876455307, -0.275759995, 1.5692808628, 0.7538465858, 0.9047079682, 1.154747963, 1.016384244, -1.1070152521, + -0.2055583447, -0.929723084, -1.8402305841, -0.0856739655, -1.4860048294, -0.5312367082, -0.2028853595, -2.2556784153, + 0.3083379269, -0.6643678546, -1.4581902027, 0.1362811774, -0.261212796, -0.3958458602, 0.2158193737, 2.3531103134, + 0.573025465, 1.5000845194, -1.6561217308, -0.9346296787, -0.0294601489, -2.1529641151, 0.3335566819, 1.1823263168, + -0.518162787, 0.6104934812, -0.7329621315, -1.1848534346, 0.4069354832, 0.0345559642, 1.9944534302, 2.3979656696, + -1.133660078, 1.2679555416, -0.4079175293, 0.0792932883, -0.4174874723, -0.2649638653, 0.9532611966, -0.3875336945, + 0.6469477415, -1.6494807005, -1.524176836, -0.9117911458, 0.9734886289, 0.2089319974, 0.542832315, -1.9180088043, + 1.2095471621, -0.2803136408, -0.865023613, 0.3140363991, 0.2163758725, -1.3617240191, -0.9943023324, 0.6911141872, + 0.7621330023, -1.2232488394, 1.651037693, 0.261226356, 0.1864361614, -0.0706841946, -1.0403263569, -2.0321514606, + -0.7808988094, -0.8977251649, 1.6592231989, -1.3123985529, -0.574929893, 1.1344422102, 1.6615151167, 0.1504340172, + -0.0827697366, 1.0395177603, -0.731326282, 1.0351142883, 0.2846813202, 0.3578853905, -0.8776550889, -0.0276330616, + -0.2406794727, 0.2422078401, 0.2753272355, -0.9000979066, -2.1857159138, 0.2421487421, 1.9852120876, 0.683182478, + -1.3812738657, 0.2342664003, 0.7960075736, -1.0990927219, -0.6038036942, -1.5455021858, -0.2055137306, -1.2040677071, + 0.1401914656, -1.1692546606, -0.7095637321, -0.2126831561, -1.3855490685, -0.2365769148, -0.3908159137, -0.018170869, + -0.4164932966, 1.7714226246, 0.8974324465, 0.5611874461, 0.8519725204, 0.9009156227, -0.134793371, -0.3339865208, + -1.3960329294, 1.1774704456, 0.2161447108, -0.6004638672, -1.0433120728, 1.2550470829, -0.3633813262, -0.5906378031, + -0.0185135938, -0.1028014421, -1.7445312738, 1.6993048191, -0.6432486773, -0.9254992604, 0.5182227492, -1.2138725519, + 0.8419089317, -0.6030687094, -0.1839088202, 0.4044023156, 0.1647076309, 2.3706243038, -0.8371855021, -0.3153517246, + -1.0361464024, -0.1055759564, -0.8192484975, -1.3087396622, 0.8839029074, 0.8903806806, -0.1596081257, -0.3812036216, + -0.8509666324, -2.1042964458, -0.1953709871, 0.7087575197, -2.1301450729, -0.0047883722, 1.4961576462, -0.6381576061, + 2.376863718, -0.9427425861, -0.1516778916, -2.2839558125, 0.5090414286, -0.222154513, 0.450240612, 1.1437622309, + -0.1963302344, 0.3094167709, 1.3509380817, -0.5044822097, -1.6174205542, 1.5378000736, 1.324118495, -0.2176084369, + 1.0739580393, -1.3880198002, 2.6526143551, 1.3435379267, 0.971925199, 0.1656426191, -0.4877803326, -0.9836961031, + -0.7674241066, -2.3378081322, 0.3354743123, -1.1810867786, 1.2881627083, -0.2078816146, -1.2664439678, 0.5565501451, + 4.0197734833, 0.8854044676, -0.5009924173, 1.0933628082, -0.4822470546, 1.1983449459, -0.7168338299, 1.0617597103, + 1.4151138067, 0.2771531641, 0.703099072, -1.2996754646, 0.5242429376, -0.5445105433, 0.713029325, -0.3225224316, + -0.6599298716, 1.452616334, -1.081367135, -1.3591839075, 0.8215834498, -1.0169330835, 0.1585911661, 1.6827707291, + -0.9877544641, -0.8410540223, -1.2568205595, 0.6768353581, 0.3739871085, 0.2208058387, -0.3934979141, -0.466260463, + 0.5557742119, -1.4550930262, 0.6333280802, 0.2107170522, -0.0745086297, 0.4422843456, 1.3056447506, 0.2425055355, + 0.0369345658, -0.1842762232, 0.6566666365, -0.2707042992, 1.6456437111, 0.3681226671, 0.6295041442, 0.9925812483, + -0.3826599419, 0.1413362175, 0.4062003493, 2.3438417912, -0.3850591481, 1.5470700264, -0.8475514054, -0.6330932975, + 0.4426223338, 1.113519907, 0.0156516992, 0.9530420303, -0.2288440615, -0.5985863209, 0.8398433328, 0.3938765526, + 1.7500195503, -0.6720721722, 0.2872419059, 0.6539419293, 0.1856593937, 0.1378008425, -1.3960168362, -0.1134697646, + -0.2837387621, -0.8654352427, 0.3288089037, 0.0301165637, 1.1624650955, 0.0011483978, -0.6361009479, 0.518209219, + -0.0406220965, 1.7414946556, -1.654866457, -0.6029675603, -0.5882458687, 1.4716166258, 1.1737931967, -1.1955555677, + -0.159091711, 0.2381560504, 0.9164401889, -0.1090425402, 0.589989841, -1.2650150061, 0.5999732614, -1.0951660872, + -0.0711921379, -0.7832251191, -0.6987342834, -0.0219315849, 1.1395345926, 0.237502262, -1.7151470184, -1.5024656057, + 1.7313393354, -0.5030255914, -1.239238739, -0.1868620217, 0.9655178785, -0.5649629831, -0.6893165112, -0.7033599615, + -2.2348511219, -0.0525545701, 0.3070724905, 0.6070462465, 1.1996613741, -0.5176995397, 1.0299232006, 0.86958462, + -2.1147446632, 0.4078527093, -0.8786563873, 0.436299175, 1.1177811623, 0.5423116088, 0.9149170518, 2.4281659126, + 0.2401718497, -0.5961187482, 0.0141318729, 0.3701690435, 0.1808289289, 1.2599830627, 0.2183745056, -0.3465143144, + 0.8355005383, 0.2451741993, -0.1894374192, 0.6959276199, 1.5179269314, 0.2976191342, 0.5701390505, 1.4372801781, + 2.0795273781, -0.375684917, -3.5909032822, 0.0716620237, 0.6304141879, 0.0261821225, 0.804248333, 0.9069849849, + 0.3464861512, -0.5794659853, -0.543874979, 0.0289033912, 0.9105071425, -1.499230504, -0.4793045819, 0.8542497158, + -1.0811475515, 0.2171867788, -0.5041297674, 1.7892602682, -0.0283070989, -0.044125367, 1.2115254402, -0.7234268785, + -1.1590812206, -0.152264446, -0.9474188685, 0.17177926, -0.2749402225, -1.0617312193, 0.6321954131, -1.3946050406, + -0.5197392106, 0.8903101683, 1.0188506842, 0.0586597063, 0.368801415, 0.7033883929, 0.5548697114, -0.927474916, + -0.6818982363, 0.4796386361, 0.2311522514, 1.9238237143, -0.6357836723, -0.1479309797, 2.640942812, 0.5992001891, + 0.0839401186, -0.3585545421, 1.6161761284, -1.1302142143, 1.3481178284, 0.5973325372, 0.5636794567, -0.0097401869, + -0.3516861498, 0.8041421175, 2.3142130375, 1.7594890594, 1.5309214592, 1.8990132809, -1.827277422, 0.8267484307, + -2.2523925304, -0.1968108118, -0.2863500416, 0.405759275, -0.7191252112, 0.2487123907, -0.656611383, -1.3493041992, + 0.1164432839, 0.1086965054, -1.4072995186, -1.7230648994, -1.9000509977, -2.4684510231, 1.2062046528, 0.4911671579, + -0.0894651636, -0.3995863199, 0.0991533101, 0.0014761668, -0.7353255153, 1.0571197271, 0.3556884527, 1.1477404833, + 1.5356293917, 2.0558340549, 0.2317831367, -1.1191799641, 1.3284108639, -1.4650167227, 1.5791805983, 0.2670737803, + 2.0296282768, 0.7951829433, 0.4688805938, 0.0782255381, -0.3811810315, -2.041220665, 0.9424459338, 1.4058378935, + 2.0227613449, -0.4164577723, 0.1712241471, -1.2878608704, 0.2662688792, 0.4602661729, -1.942009449, -1.0917539597, + 1.0351030827, -1.3396145105, 0.4247620106, 0.4522379935, -0.1753645241, 0.3741957843, 0.6832326651, 0.2857375145, + -0.7751410007, 0.2919989228, 0.3030637205, -0.7733544111, 0.2354594618, -1.6997842789, 0.8201661706, -0.2567533255, + -0.4506866932, -0.3111549914, -1.0207248926, -0.5771256089, -0.9786616564, 0.1340002865, -0.8608180285, 0.5694761872, + -0.4418152273, -0.1610226035, 0.2886717916, 1.9575083256, 0.7234182358, -1.0948028564, -0.2901492417, -1.3798342943, + -0.6869062781, -0.5215283036, 0.2655810118, -0.2533085644, 0.2296121866, -0.6031663418, -0.8315091133, -0.5224909186, + -0.4015553594, 0.2074885517, 1.670953989, 0.8634210825, 1.5834872723, -1.7893948555, -1.3206269741, -0.6768729091, + 2.1363854408, 1.2582120895, 1.0345571041, -0.1696926504, -0.732622683, 1.0371384621, -0.9781098366, -0.2509648204, + 1.0754765272, -0.5080704689, -1.7204457521, 1.3550037146, -0.7376111746, 0.2516528964, 0.0143696088, 1.4959465265, + 0.9013447165, 0.0666519925, 1.254619956, -0.6876458526, 0.1289302558, -1.2125207186, -1.3062785864, 0.1477067918, + -0.9687612653, -0.6614953876, 0.4936519265, -1.0251137018, 1.556327939, -0.0668517277, -0.6016780138, 1.2578229904, + -1.6711659431, -1.7495858669, -0.6962295771, 1.7163276672, -0.6159476042, 0.8581643105, -0.0230642557, -0.1786852777, + -0.5286377668, 0.2368431985, -1.600663662, 1.2182400227, -0.985019207, -0.7063335776, -1.0004578829, 0.2919587493, + -0.1049265787, -0.7563028336, 0.4225782156, 0.0824065655, 0.2042005062, 1.2740459442, 0.1095527783, 1.1274046898, + -0.6521725059, 0.0609520078, -1.1165735722, 0.9280680418, 0.1987430453, 0.4761828184, 0.1669905335, 1.0124512911, + -1.2776417732, -0.3814474642, 0.7289512157, -0.3052847087, 0.7282732129, -0.5393836498, 1.2419661283, 0.591160357, + 0.3793136477, 0.1260632575, -0.1371300519, 1.8880878687, 2.8134269714, -0.292400986, 0.3732911646, -2.3748250008, + 0.3623911738, -1.5661566257, 1.380892992, 0.9725285769, 0.2446972132, 0.7711442113, 0.3922756314, -2.1892728806, + -0.0823605731, -0.2208417803, 0.4101850986, 0.2744546831, -2.2105195522, -1.3529791832, -2.0533165932, 0.7840827703, + -1.2388772964, -0.009182862, 0.2710341811, 0.7293034196, -1.9300572872, 0.2674436867, -0.6061401963, 1.2984786034, + 1.4081494808, -0.7296541929, 0.4568593502, -1.4688404799, 0.3038083017, -2.5448539257, -0.9092229009, -0.3816877902, + 0.7162517309, 0.7011740804, -1.4708878994, 1.0043964386, -0.0533178635, 0.1780886203, -0.0656738058, -1.8832274675, + -0.7870368361, 0.2258797288, 0.8136019707, -1.613280654, -1.6500467062, -0.7262764573, -1.8060714006, 0.1261256337, + 0.0837224349, 0.0827596188, 0.7586573362, 0.6176240444, -0.3255368769, 1.431853056, 0.0577022061, -0.2958157361, + -0.6132124662, -0.8152903914, 0.8220098615, 0.2450569719, 1.2573981285, 1.5494660139, -1.2309507132, -0.9299182892, + -0.6454734206, 1.046880126, 1.1484909058, 0.5869446993, -2.1177897453, 0.4626471102, 1.019874692, -0.11382889, + 0.4247196913, 1.1570379734, -1.4135748148, 0.0725923181, -0.2679024637, 2.7661833763, 0.2679988146, -0.5027480125, + -0.0181943942, 0.6711435914, -0.094197467, 0.1855315417, 0.2543438077, -1.4764968157, -0.9377606511, 0.3014186025, + 0.2370459586, 0.7084241509, 0.162636891, 0.3276515603, 0.1585559845, 0.2503229976, -1.1399179697, -1.0920814276, + -0.6667899489, -0.8548904657, 0.703368485, -0.7761536837, 2.1346483231, -0.2393279821, 1.3535968065, -0.9506493211, + -0.407692045, -0.558154881, 0.1968198419, -2.0824365616, -0.6504297853, -0.7817162871, 1.599916935, -0.4707145393, + 0.2664442956, -0.0279191937, -2.3622436523, -1.2645890713, -0.0324613638, -0.4157408774, -1.9002436399, 0.8337079883, + -0.5889626145, -0.5031498671, -0.0618600398, -2.4662024975, 0.0627399012, 0.8152358532, 2.1090805531, -0.063007772, + -0.1326286197, 0.1434296221, 0.8538603187, -0.1592878252, 1.6691845655, -0.4810115099, 0.4189854264, 0.2810520232, + 1.4511069059, 0.1108039841, -1.6083573103, -0.2608066201, 0.6873603463, 1.0323524475, 0.3345609605, 1.4037721157, + -1.1845630407, -0.2300915718, -0.1948073506, 0.5498065948, -0.2714291513, -0.7518230081, -1.1877788305, 0.3030099869, + 1.2471328974, -2.281747818, 0.5460087061, 0.8085818887, -1.4102207422, -0.7649542093, 1.1998691559, -0.3109331429, + -0.5489453673, -1.1739296913, -0.75738132, 0.3622814119, -0.1803682745, -0.50115484, -1.000983119, 0.1868225932, + -0.6029005051, -0.8547886014, -0.1348072588, -1.1864544153, 0.766407907, -1.4393889904, -0.9475734234, -0.55732131, + 0.892570138, 0.5009971261, 0.7198488712, -0.5231234431, -0.1421491206, -0.6183432341, 0.0882850811, -1.6847449541, + -0.5839746594, 0.2101413608, -0.6959885955, -0.4180793464, 1.7377842665, 0.5398337245, 2.4762804508, 1.5915863514, + -0.794442296, -0.3500894308, 0.1223903745, 1.8400007486, -0.0912151709, -1.1437829733, -0.3499307334, 0.8078536987, + -1.0026249886, 0.2237447202, -1.0386419296, 0.2516576052, 1.2548787594, 0.0778929368, -0.4539818168, -0.5510498285, + -0.0578782186, 0.4725125134, 1.887001276, 2.4323177338, 0.2010755539, 1.1056728363, -1.8366775513, 0.9536247849, + 0.7939686775, 1.100391984, 2.3458998203, 1.4692678452, 0.6490464211, 1.9670273066, 0.4042147398, 0.6566967964, + -0.7697871923, 1.5224796534, -1.0281040668, -1.0950347185, 0.8894008994, -0.7297667861, 0.6717054844, -0.2670283914, + -0.5510465503, 0.0973181725, 1.1938539743, -0.0754729062, -0.4562895, -0.8172528744, -0.0423791744, -0.5283162594, + -0.3101071119, 0.1037842855, 0.3862933218, -2.5298702717, 0.0148019399, 2.0022518635, 0.4043906629, -1.8893733025, + 2.078132391, -0.2799007893, 1.567792654, 1.049691081, 0.210914731, 0.7038741112, -1.3184523582, 0.7989603281, + 0.2703145444, -2.6894779205, 0.5198162794, -2.2797818184, 1.5013480186, 0.9218204618, 0.8572191596, 0.8756232262, + -1.7740607262, -0.4072049558, -0.0811734796, 1.390606761, 0.8266698122, -1.7439453602, -0.0620697737, 0.1208140701, + 0.1889812201, 1.771453619, 2.0588123798, -2.7417387962, 1.1500811577, -0.4305594563, -0.8185398579, 2.0702614784, + 0.5266123414, 1.0601838827, -0.5946053863, 0.8639861941, -0.1706417352, 0.6222539544, 1.3736292124, -0.7181694508, + 0.0831693858, -1.1598395109, -0.4952351451, 1.2962372303, 0.0690178201, 0.1662487537, 0.3988175988, 0.1684028208, + 1.8821505308, -0.5882483125, -1.0507441759, 1.725412488, 0.1957102418, -0.3709122241, 1.4042637348, -0.2510891557, + -0.4316080213, 0.0685362518, 0.6092994213, 0.7451376319, -0.4354406893, 1.3262227774, 1.4801108837, 1.3739769459, + 0.1878964752, 0.4108370543, 0.9605338573, -1.5134578943, -0.1964982003, 0.6435061097, 0.0736133829, 0.8728601336, + -1.3197245598, -0.1270552576, 0.0426341854, 0.8820625544, 1.1046253443, -0.2755198777, 0.2538744807, -0.990070641, + 1.364759922, -0.802975297, -0.9458059072, 1.7950054407, -0.3628331125, -1.4039831161, -1.116209507, 0.4925628901, + -2.0292842388, 1.5619550943, -1.8280488253, -0.0055643721, -0.5366774201, -0.7328761816, -0.8478962183, 0.012186965, + -1.6183778048, -0.4681866765, 0.238083899, 0.3942469358, -0.001747111, 0.645719111, 0.161822021, 0.3286625147, + 0.194993794, -1.8389343023, 0.0252901614, -1.13027215, 0.5937021971, -0.1768487543, 1.4522219896, -0.4664727151, + -1.4856642485, -0.9684375525, -0.6833172441, -0.4522916675, -1.3983139992, 0.2946139574, 0.7114067674, -0.4360235631, + 1.3628817797, 0.3709173501, -0.1819907874, -0.1708724201, 0.6615654826, 0.5053963065, -1.2913050652, -1.1293932199, + -0.3762286007, 1.4005522728, -0.3681354821, 0.2439703345, -1.9376685619, 0.0061770533, -0.3084800243, 0.0341180898, + 0.6517161727, -1.0235981941, 0.3485942483, -0.8717853427, 0.1752543598, -0.8681605458, 0.5755802989, -0.4126141667, + -0.7222152352, 0.9932783842, -0.8108548522, -0.8651838303, -0.4406715333, 1.263420105, 0.3228797913, 1.7299368382, + -0.2031331807, 0.7388085127, -0.365239501, -1.0800300837, -0.4905096591, -0.386654377, 2.2770588398, -0.6903892756, + 0.9328139424, 0.8298351765, 0.0020154689, -0.4209246635, -0.6973096728, 0.0860553086, -0.5382195115, -0.3424751163, + -1.3047096729, 3.0107023716, -0.2132201046, -1.7896158695, -0.2584707439, 0.7357210517, -1.6454079151, -0.1919890344, + 0.8854669333, 0.5473588109, 2.1477603912, -0.3015838265, -0.3280054033, -0.5345777273, -0.0564358309, -1.0776684284, + -0.0625013635, -0.8091907501, -0.9522696733, -0.0291139688, 0.815184176, 0.4640530646, -0.4346605241, 0.7263224721, + -0.9717104435, 0.0229827929, 1.1674512625, -1.3929512501, 1.2918885946, -0.2988780737, 0.2283933908, 0.3405737579, + 0.3639356792, -2.1020929813, 0.8405295014, 1.0143632889, -0.1635631919, -0.2963094711, 0.120346278, -0.5817037225, + 1.0243686438, -1.1446744204, -0.1163422912, 1.07791996, 0.7442581654, -0.5289862752, 0.3235702515, 0.8104526401, + -0.6944915652, 0.710503459, -0.4998841286, 1.3602881432, 0.9865704179, 0.9607505798, -0.5986943245, 0.3859920204, + 0.8108100891, 1.360337019, 0.145348683, 0.4959866405, 1.0660791397, -0.39271155, 1.5472337008, -0.9704090357, + 0.6275779605, -0.161868006, 0.5084855556, -1.0714122057, -0.8444173336, 2.5354545116, -0.41430825, 1.4401415586, + -1.8746173382, 0.0717201754, 0.9315521717, -0.1924583465, 0.2826135755, -0.4956521988, -0.5171129704, 2.2835865021, + 1.2014240026, 0.4965412319, 0.6352142096, 0.2207820266, -1.520481348, -0.2159054577, 1.4612492323, 0.483609885, + 0.7791002393, -0.7924147248, -1.9963259697, -0.9082238078, -0.0739156827, -0.1735779345, -0.6885651946, -1.6898833513, + 0.1898370534, 1.3742725849, 0.4149084389, 0.9179326892, 0.1505246013, -2.1365816593, 0.6585453749, 0.0833003744, + 0.166491732, 0.2179910988, 0.1975180507, -1.2237678766, -1.479863286, -1.5096775293, -1.6420594454, -1.0052191019, + -1.4127585888, 0.2579631805, -0.4421169162, -0.0934734941, 0.4567604363, 2.2722504139, -0.3473166525, 0.1571355462, + -1.1206731796, 0.4965228736, 0.549893558, 0.1304169148, -0.7870458961, 0.8281716704, 0.4544727802, -0.0937828198, + -0.8460122347, -0.0507329628, -1.3765958548, 2.1486096382, -1.7733092308, -1.1574308872, -1.3433600664, -0.3764662147, + 0.2813237309, 0.2202699929, 0.6045076847, -0.1821339726, 1.2025723457, -1.3828216791, -0.9747838378, 0.2388301194, + -0.8707327247, -0.1252780706, -0.6416910291, 1.3086551428, -0.5332537889, 0.0063522253, -0.6723710895, -1.6051152945, + 0.3130868971, -0.1302162409, 1.4862173796, -1.0393095016, -1.2276927233, 1.7093112469, -1.7208932638, -0.3173751235, + -1.1881891489, -2.3398308754, 0.2897851169, -0.55401057, 0.3708947003, -0.6902725697, 0.4827075303, 0.515208602, + -0.8001226783, 0.5289755464, 0.6751053929, 0.197758019, -1.8228195906, -0.5684699416, 1.7509375811, -0.7015925646, + 0.6359348297, 1.3688038588, 1.0106269121, -0.665433526, 1.0200300217, 0.0526707098, 0.448964119, 2.037671566, + -1.5846176147, 1.3363882303, 0.4211618304, -2.3855931759, 0.4183519781, 0.715967834, 0.1074562818, -0.273062706, + 0.3309553862, 1.5496168137, 1.1344338655, 0.9619284868, -0.834756434, 1.0374566317, 1.4408031702, 0.1390461475, + 1.7395902872, 2.9890756607, -0.3393157423, -1.5076727867, 1.4666700363, 0.2921347022, 0.3553029597, 0.9788808227, + 1.2384502888, 0.3073142171, -0.6225633025, 1.0165023804, -0.7128052115, -0.0668653473, -0.5550617576, 0.4804181457, + 2.0454192162, 0.0330334306, -0.2663131058, -0.7029079199, -0.2169049233, -1.0697338581, -0.8404394388, -1.1840552092, + -2.3508896828, 0.1685397476, -0.1027170047, 0.5997434855, -1.9493203163, -0.8024225235, -0.4092237949, -0.4173745215, + 0.2873328328, 0.411768496, 0.2399783283, 0.2981419265, -1.6334201097, -0.9804607034, -0.3757415116, 0.6015896201, + -0.7534538507, -1.1112320423, 1.6509275436, -0.1514259428, -0.4161066115, -0.3126336038, 1.3812828064, 0.816188395, + -0.0387242921, 0.7398338914, 0.0209227726, -0.4717726409, 0.160180226, 0.7710543275, 0.1447940767, -0.0283841789, + -1.6753015518, -0.8868216276, -1.0859651566, -0.644448638, -2.2279274464, 1.3281667233, 0.035190206, 0.0617455207, + -1.5774900913, -0.5398665667, 0.7255911231, -0.4908719063, 2.2670347691, -1.9021373987, 1.2350738049, -0.9386199713, + 0.7089691162, 0.7957819104, -0.9514808655, 1.2497242689, -0.3672064841, -1.3906115294, -0.5919629335, 1.7621365786, + -1.4293707609, 0.3684018254, -0.7765325308, -0.1114501879, -0.9075161219, 1.2576494217, -0.866994977, 0.493511647, + 0.1877672523, -1.3370648623, -0.7650950551, 1.1577278376, -0.6422299743, -0.6276326776, 0.1233862042, 0.2219813317, + 0.0170367789, -0.7312810421, 0.6946656704, -0.7900857925, 0.5711570978, -0.6337569356, -1.256493926, -1.9684580564, + 0.7597616911, -0.6197546721, 1.0595633984, -0.1620984077, -1.4307351112, -1.242587924, 0.3334033489, -0.8551697135, + 0.7142262459, 0.2552497387, -1.4737071991, -1.2400416136, 1.225383997, -0.4654192924, -2.1136255264, 0.633979857, + 1.66076684, 0.7691323161, -0.0107232919, -0.3207734525, -0.8382658362, 0.3205773532, 0.0976580307, 0.2763164639, + -0.44150123, -0.7790068388, -0.6566889286, 1.4151773453, 0.4216744602, -0.8975771666, -0.4491711557, 1.3207405806, + 0.9556534886, -0.2062499523, -0.4255151749, -0.5410502553, 0.7635242343, 1.0545524359, -0.4757571518, -0.382324338, + 0.3522265255, 0.6711670756, -1.7673711777, 1.4733440876, -0.532431066, -1.6187958717, 0.6993540525, -0.942635715, + -1.1725157499, -0.3552233279, 0.5078729391, 1.429813385, 0.2571879029, 1.4719634056, 0.5778535008, -0.2065822333, + 2.3589992523, 0.2131077051, -0.3065221906, 0.4680456221, 0.1980422735, -0.8443328142, -0.2465468198, 2.7550952435, + -0.0163592007, 0.070819661, -0.3586863875, -0.1086756513, 1.2919684649, 0.9084424376, 0.7995363474, 0.3683059812, + 1.1267640591, -0.0028436235, 0.1808570176, -0.1837261468, -1.2601875067, -0.2753442824, -0.0100960284, -0.1514759511, + 1.377477169, 0.2780973613, 0.1607485414, -0.3234707117, -0.653100431, -0.4414724708, 1.2662265301, 1.3459706306, + -1.0425080061, -0.2603740394, 0.0437238626, 0.2833698094, -0.074864082, -0.3282703161, 0.6336637735, 0.0157164261, + -1.1069000959, 0.0525508635, 0.2700309157, -0.3761922717, -0.4791140258, 0.4749079943, -0.2400727868, -1.6324510574, + 0.1481562406, -0.2036515921, 0.57304883, 0.3368732631, 0.6147609949, 0.8890558481, -0.740000844, 2.0510735512, + 0.0945650861, -0.3494800329, -0.6844366193, 0.1977184117, -1.5378758907, 1.758076787, 0.4568970799, 0.7572392821, + 1.4373345375, 0.2000212222, 0.0556829832, -0.2715509832, 1.1920673847, 0.8942832351, -1.2035263777, 0.4194567502, + 0.400519222, 0.5703665614, 0.5575336814, -1.3979532719, 1.0963864326, 0.0250807907, -0.0674761832, -1.3193664551, + -0.3257948756, -0.1157574356, 0.1749069393, 1.500002861, 1.1391853094, -0.954719007, 1.0541182756, -0.2260276377, + 0.7414301634, 0.9308434725, 0.1472192556, 0.2028086632, 1.0589454174, -0.3633924425, -0.3617959023, -1.1625291109, + 2.2101442814, 0.2819685638, 0.1859583557, -0.2687607408, 0.0440233089, -1.0015631914, 0.6896772385, -1.3712488413, + -1.0608513355, -1.1808810234, -0.472846806, 1.0679525137, 0.9100573063, 1.6535276175, -0.5239212513, 0.5605090261, + 0.9432093501, -1.9324355125, 0.8190538883, -2.1978337765, -0.2977302969, 0.6257901192, -0.1263576597, 0.9088796973, + 1.5055203438, 0.1521550417, -2.2133748531, -0.1194746345, -0.5715026259, 1.5380450487, -1.0065170527, -0.5844327807, + 2.016471386, 0.0378994644, -0.1642175913, 0.5951735377, -0.7040801644, -0.2119091898, -1.3055820465, -0.0513718873, + -0.3308599591, 0.0339758396, 0.8075446486, 0.1187833175, 0.6131482124, -0.4814960957, 0.0764794052, 0.982042253, + -1.7076627016, 1.372325182, -0.7145006061, -0.5938451886, -0.0183429793, 0.7288543582, 0.8106418252, -1.5039621592, + 0.3948372304, 1.0601956844, 1.0729640722, -0.2177887261, -0.361481607, 0.6474339366, 0.4636586905, 0.1736662537, + 0.7257980108, -1.3463358879, -0.1328872144, -0.4435177147, 0.2674212754, 0.8134050369, -0.8270956278, -0.7177349329, + 0.6141757965, 0.6915240884, -0.4994766414, 0.5097733736, -0.1994809657, -0.9650039077, -1.3885537386, 1.5378166437, + 0.5882808566, -1.0985815525, -0.85559237, -1.366435051, -0.5528749228, 0.2774377763, 0.6846002936, -0.6543120742, + -0.9933399558, -2.6504812241, 0.3394016325, -0.2626033425, 0.4674544036, -0.2633951604, -0.2068358809, -1.0403506756, + 0.4053127766, 1.1273319721, 0.1939062625, 1.3327549696, 0.7872596979, -1.1306591034, -0.3493178189, 0.1557210684, + 1.1165831089, 1.3770676851, -0.794978261, -0.6838003397, 0.6526792049, 0.6445679665, -1.1254947186, -0.2173337489, + -0.8494017124, 1.1666642427, 1.253293395, 0.9628742337, 1.0837029219, -0.6331955194, 0.8385151029, 0.336152643, + 0.3915138543, -0.0933211073, 1.1968898773, -0.5742031932, -0.0500956103, 0.9402880669, 0.7142255902, 0.5690819621, + 0.7714705467, -1.5002479553, 0.3130998313, 1.1639127731, 0.6727718711, 0.0101976758, 0.9451437593, 0.5655166507, + 1.6275627613, 0.8402985334, -0.341132611, -0.3251051605, -0.7312197685, -0.2371633053, -0.1245433688, -1.7427054644, + -0.6266471148, 1.6334964037, -0.0915187076, -0.3417382836, -0.0914409012, 0.6394451261, -0.9623674154, -0.2364961803, + -1.0329637527, -0.1231606677, -0.2556661069, 1.105153203, -0.3228335083, -0.9258052707, 0.6563531756, -0.4999623001, + -1.6209917068, -0.1153591797, -0.8811206222, 1.0089468956, 1.2612160444, 0.594771862, -0.2692162991, 0.20563519, + 0.5102504492, 1.7642725706, -0.5403218269, 1.0996212959, -1.2504529953, 1.0675100088, 0.5051488876, -0.8187961578, + -0.8085387945, 0.094660908, -0.1569521129, 0.7736035585, -2.0229930878, -0.5482857823, 1.0867170095, -0.1797525287, + -1.0244921446, -0.323600471, 1.092751503, -0.2026444674, 0.4056845307, -1.0475788116, 1.4953615665, 2.010819912, + -0.3379966319, -0.3342337012, -0.4520601332, 0.9962898493, -1.3105881214, 1.2578663826, 0.2881660163, 0.5212141275, + 2.0398442745, 0.8010252714, -0.7030718923, -1.5192036629, -1.2763825655, 0.7861399651, -0.5948548317, 1.0182152987, + -2.0379059315, -1.1396664381, -0.4048861265, 0.0318119638, 0.8137828708, -0.8330386877, -2.0578346252, 1.3120894432, + -0.2637521923, -0.4078529477, 0.2702302933, 0.7227398157, -0.8606963754, -0.5009006858, 0.4711194634, 1.6186574697, + 1.412137866, -0.0002848467, 0.6598795652, 1.2394162416, -0.5023958683, 0.4566825926, -0.8102485538, -0.018509645, + 1.566264987, -1.0101697445, 0.5655524731, -0.2134593427, 0.0219880417, 1.3343462944, -0.9169719815, -0.1619948745, + 1.0586124659, -0.3841233253, 0.1626750678, 2.1752021313, 1.552598834, -0.2626132071, -0.6253407598, -0.302103579, + 0.504468739, -0.1912412196, -0.0795418695, -0.6908488274, -0.4781500995, 1.0784960985, -0.442291528, -0.4586786628, + -0.1436938047, -1.048422575, 0.3351688981, 0.921461761, -0.1563158184, 0.3626534641, 0.6382313967, 1.2679969072, + -0.0452971682, 0.7486544847, 0.5606036186, 0.9569472671, -0.0700276718, -0.3959464133, 0.1904693246, -0.7078367472, + -0.0979526788, 1.9592298269, -1.1198773384, 0.4000999331, -0.387529254, 1.4898318052, 0.6270580292, 0.5690717697, + -0.3728976846, -0.5502703786, -1.1284275055, -0.0041970341, -1.6097604036, 1.1527045965, 1.6746832132, 1.5408614874, + 2.0273838043, -0.5349593759, 0.7125822902, 0.7540348172, -2.8705582619, -1.8638910055, 0.5038121939, 0.6373669505, + -0.5574759841, -0.5050622821, -0.8507771492, -0.5713256001, 0.8568009734, 0.519043982, 0.0653787851, -0.9294126034, + -0.652382195, 0.4704572558, -0.8607774973, -0.1529620588, 0.082667999, -0.1757801771, -0.5495941639, 0.7834180593, + 0.0671116933, 0.7145394087, -1.3842253685, -0.7460412979, -0.6277463436, 1.0182669163, 0.0907923281, 0.9149090052, + 1.0882586241, 1.7943143845, 0.4608672261, -0.0809834972, -0.8602779508, 1.1938617229, 0.6517693996, 0.0092181843, + -0.7635804415, 1.2017304897, -0.8502430916, -0.1846573204, -1.6849205494, -0.2419226319, 0.4188693166, 1.2817186117, + -0.4473271072, -0.1569877714, 0.7320977449, -0.0141397016, 0.4355955422, 0.4715900123, 0.6773759723, -0.4215749204, + 0.3264049292, 2.4344141483, -0.0604711324, -1.0446228981, 1.5301111937, 1.3959794044, -1.4553323984, 1.7583258152, + 1.5257213116, -3.0210578442, -0.9142537117, 1.7957469225, 1.1200355291, 0.5840203762, 0.5999845266, 0.0407632738, + 0.6290143728, 0.205854997, -1.1277829409, -0.8097259998, 1.6846119165, -1.2507945299, 0.1569381058, 0.7785435915, + 0.7929396629, -1.8754302263, -1.1775150299, -0.9298060536, 1.7393478155, 0.494544208, 0.416372776, 1.5628179312, + 0.250227958, 1.3238953352, 0.4312912524, 0.0220150761, -0.214738518, -1.8523584604, -2.0134761333, 1.4432740211, + -0.5076486468, 1.3906644583, 0.5807424188, 1.2673971653, 0.2372799963, -1.507085681, 1.0928071737, -1.5873508453, + -0.1693418473, -0.4200076759, 0.2688405514, -0.36012429, -1.2954751253, -0.7431051731, -1.2575507164, -0.2012025267, + 2.2574408054, 0.1104647666, -0.1512969583, 0.0174025111, 0.4458542466, -0.7248215079, 0.9082215428, -1.3589265347, + -0.9368333817, -0.731205225, 1.0721185207, -0.7326382995, -0.5639464259, 0.6095701456, -2.0346000195, 1.0954475403, + -0.2311936021, 1.4384429455, 0.5641620755, -0.2077282071, 2.3088765144, 0.9453276396, -0.1790513992, -0.6986765265, + 0.0849507675, 1.8025000095, 0.4350953996, 0.773468554, -0.3476094306, -0.381401211, 0.4308768213, -0.9413963556, + 0.5490882397, -1.2022879124, -1.0516980886, -0.9482901096, -1.6367952824, 1.8386996984, -0.7118865252, 0.1055972502, + -0.702675283, -1.0756582022, -0.1422663033, 0.3937110305, -1.8437414169, -0.2732995152, -0.2043423504, 0.59921664, + 0.6439359784, 1.7993170023, -0.7580192089, -1.3359285593, 1.496248126, 0.173010394, -0.6356427073, 0.0779678747, + -0.38101843, 0.4025068283, -1.0337539911, -2.1191465855, 0.2678066492, -0.5662587285, -0.5005620718, -1.0199508667, + 0.2415617257, -1.9484695196, -0.5845148563, 2.9574551582, -0.132973209, -0.2781083882, 2.0026571751, -0.6654509902, + -0.9315814972, -0.5124284029, -1.0220663548, 1.5914081335, 0.724794209, -0.8515052199, 0.6342797875, -0.4960220754, + 0.5928196907, -0.9952784181, 0.8246176839, 1.0320022106, -1.9398835897, 2.0664064884, -0.9641517997, -1.863327384, + -0.0337739438, -1.3035702705, 0.1331416517, 0.1698399037, -0.1870108247, 0.3671292365, -0.4189546108, -0.4695348442, + -2.662468195, 0.5423961878, 1.5010020733, 0.3459192812, 0.0675365776, -0.8721294999, -0.4595796466, -0.5068891644, + 0.5873795748, 0.3420045674, -0.0998604968, 0.4836119413, -1.3472015858, 1.6239326, 0.6348768473, 0.0179399494, + -0.4565315545, -0.2640585005, 0.8355404139, 1.1033011675, 1.511030674, 1.1274770498, -0.7093459368, -0.0744580925, + 0.2659905851, -0.1485776901, -1.6719353199, 0.7489042878, 0.0443355255, -0.9490557909, -0.8815689087, -0.6441028118, + 1.2353124619, -1.6454527378, 0.3230223954, 1.0776292086, -0.8387464285, -0.5173830986, 1.4620894194, -0.0286578313, + -0.78142941, 1.4929542542, -0.7920092344, 0.3892004192, -0.4025924206, -0.9289677143, 0.8831150532, -2.4916441441, + -0.7269167304, -0.3389181793, 0.0518149436, 2.3087661266, -1.0090583563, 0.9877404571, 0.1650268286, 0.955380559, + -0.7569466829, 0.7209989429, -1.1299874783, -1.306704402, 1.100279808, 1.8736176491, -0.1802768111, 0.9645875096, + 0.7066676021, -0.1683974713, -0.9512957931, -0.8372158408, -0.3797715008, -0.286760062, 1.0953788757, -0.4406148195, + -1.3737680912, -0.8403751254, 0.7122806311, 0.6732238531, -1.2772501707, 1.4470598698, -1.6477565765, 0.8578764796, + 0.918266952, 1.3492974043, 0.6436387897, -0.119959712, -1.4940854311, 0.1026622728, 0.7803411484, -0.578787446, + 0.9917155504, 0.490953505, -0.5574346185, -0.6866763234, 0.2321932614, -2.1183209419, 0.4316413403, -0.4042158127, + 0.8837202191, -0.1353183091, -0.7172310352, 2.7005834579, 1.1152646542, 0.8556065559, 0.3109346032, -1.0019065142, + -0.1889768243, 0.6665068865, 1.8737750053, 0.560968399, -0.468203634, -0.334058404, 1.0639505386, 0.1632687896, + -0.2742658556, 1.0798113346, -0.6057754159, -0.274979949, -1.1890770197, -0.2930025756, 1.873511076, 2.2746007442, + 0.821944356, 1.9643771648, 1.3195849657, 0.1458032131, 0.5102447271, -1.6404271126, 0.6829751134, -0.6760859489, + -0.75914222, 1.1757338047, -1.2378255129, 0.8542348742, -1.6906770468, -0.5590405464, -2.0516254902, -0.7075557709, + -0.6136775017, 0.7814898491, 0.3277451098, 0.7363686562, -0.7694044113, 2.55412817, -0.9461388588, -1.086627841, + -0.6960321069, 0.3335900009, 1.2417874336, 1.3287516832, 0.9328956604, -1.0503815413, 0.263133496, 0.5054531693, + -1.5257029533, -0.2071426213, 1.181478858, 0.2966313064, -0.9725993872, 0.3309081495, -0.3167668879, 0.6853064895, + -0.2060380578, 2.7066907883, 1.5249216557, 1.2280702591, 0.50858742, -0.3147315979, -0.1998735368, -0.7020621896, + -0.7529008389, -0.6573159099, -0.4857104123, 0.241912961, 0.422192812, -0.8887619972, 0.4519138634, -0.5847700834, + 1.5164148808, -0.3560203314, -0.9716092944, -1.1448581219, 0.1373418719, -1.601465106, 1.3189338446, 0.2547961473, + -1.4622094631, -0.1789774597, 0.8794451356, -0.3040826917, 1.5860936642, -0.712541163, -1.5092651844, -0.4747304022, + 0.4026572704, -1.7841160297, 1.4312634468, 0.6950429678, 0.4651306272, 0.8870432973, 0.0887216479, 0.4096937478, + -0.5062332749, -0.296277374, 1.1971416473, 1.3719564676, 1.956384778, 0.8283421993, 1.7993576527, -1.2152526379, + -0.0858739465, 0.2326095849, -0.2911576033, 1.0595628023, -0.5787106156, -0.4047865868, -0.50177145, 0.0693776011, + -0.4276338816, -1.3622661829, 0.4445276856, -0.7927712202, 0.9814260602, 0.5316746831, 1.5762796402, 0.8111576438, + 1.9288363457, -2.2223255634, -1.3883488178, -0.3999559581, 0.1310270727, -0.354417026, 0.9905593395, 0.230695039, + 1.9439210892, -0.5027143359, -0.0143833691, 0.316568166, -0.111524865, -0.0917987972, 0.241566658, -0.0787839368, + 0.4116333425, 0.5505738258, 1.1692513227, 0.7651976943, 1.2653208971, -1.2472923994, 1.1245467663, 0.4015773833, + -0.2108438611, 1.5653553009, -0.0090202373, 0.3653865457, -1.0638052225, 0.3883264959, 1.2481312752, -0.1546858996, + 1.3234074116, -0.8675174117, 2.0376651287, -0.7730429769, 0.4148543179, 0.2054794282, -0.8716959357, 0.5587248802, + -1.0899597406, 0.5063377619, 0.2100979537, -1.6693204641, -0.4869732261, 0.8901972771, 0.7649075389, 1.4790863991, + 0.198412627, 0.2106683105, 1.219671011, 0.4870115221, -0.8584403992, -0.6259924769, -0.4319318235, -0.2345139086, + 1.1433793306, 1.2349792719, 1.1137609482, 0.3417917192, 2.7702353001, 0.5551794171, -0.7779662013, -1.338943243, + 0.3691887856, 2.0352487564, 0.1049689651, -1.3625838757, -1.2054003477, -0.1510334313, 1.4791287184, 1.5493704081, + -1.2234296799, 1.1098680496, -0.3641369641, 0.268985182, 1.0093431473, -1.0931015015, 0.8034202456, -0.1910215169, + -1.2416673899, -1.4777083397, 1.0865781307, -0.2192025781, -1.4991483688, -0.389699012, 0.7066301703, 0.6640823483, + -0.2975024283, -0.1652295887, 0.2889887094, -2.8535153866, 0.6054579616, -0.0322866999, -0.8152453303, -1.0316278934, + -0.4888164401, -1.3081847429, -0.1466890872, 2.9084668159, 2.2889723778, -0.4269299209, 1.8235203028, 0.6112687588, + 0.1520540267, 0.2729745209, 0.4491570592, 2.550151825, 1.4125373363, -0.3937563598, 0.6757388115, 0.1855499148, + 0.8891111016, 0.4965530932, 0.6705762148, -1.0051658154, 0.4118530452, -0.3306933641, 0.7756954432, -0.1614267975, + 0.309818536, 1.0678449869, 0.8791055083, 1.5784460306, 0.1212876365, -2.1881835461, 0.2398423702, -0.6166628599, + -1.0495116711, -0.2046049982, -1.5786684752, -0.4201811254, 1.0646731853, 0.6574370265, -0.4980138242, -0.956808567, + -0.3948968053, 0.5613503456, -0.2417133749, 0.0204319879, 0.4374487698, 0.9105584025, -0.1001281738, -0.0798568353, + 0.0035209819, 1.7699304819, -0.8864417672, 1.1483435631, 0.9128133655, 2.3566586971, 0.060965918, -1.8903415203, + -0.9600875974, -0.0770855024, -0.261654228, -1.2499434948, 0.5119954944, -1.7796143293, -1.5820428133, 0.89775002, + -0.7375071049, -0.7488090396, -2.2484743595, -0.8623650074, -0.7743161917, 1.3640680313, 0.4618594646, -0.4605868459, + 0.1531334072, 0.2061138004, -0.7647488117, -0.0337435305, -0.7385146022, -0.5625520945, -1.2569856644, 0.2129893452, + -0.9553509355, 0.0948104262, 2.5250504017, -1.68780756, 0.6934902072, 0.6625792384, -0.5822758675, -0.741081357, + 0.0621082224, -0.0299436729, 1.1133687496, 0.4249279499, 0.5673895478, 0.1886189878, 0.0354875848, 0.1282968819, + -0.6992625594, 1.156134963, 1.9655958414, 0.4005120397, -2.1143636703, -0.586388886, 0.7493094206, 0.5219535232, + 0.8459887505, 0.5666259527, 0.1399505585, -1.247687459, -0.499894768, 0.3239963055, 2.3878009319, 0.4304938018, + -1.2388671637, -1.0990287066, -0.3986670673, -2.1690292358, 0.5610336661, -0.2620897889, -0.7111989856, 0.2920810878, + -1.6883717775, -0.1379259974, -0.9189206958, 0.4376925528, 1.5696545839, 0.6147102118, 0.5508036017, -2.5583667755, + 0.3781401813, -0.5038151741, -1.7127869129, -1.4350970984, -0.1412201822, -0.0816503242, 0.408158958, 0.7809235454, + 0.6255474687, -0.2427212447, -0.2043065876, -0.6814991832, -1.8603205681, -0.5025548339, -1.900010705, -0.1304477006, + -0.6851273179, 1.0265516043, -0.6661650538, -2.3975861073, -1.7486999035, 0.0605677813, 0.6212993264, 0.4197052121, + -0.3831737936, 1.3025627136, 1.1073590517, -0.8643981814, 1.3570622206, -0.4238911569, -1.2117905617, 0.1408114433, + -0.1960694492, 0.6899011731, -1.3563886881, 1.4247977734, -2.2074992657, -0.590665102, 0.6465181708, -2.1144294739, + 0.895678699, -0.912974596, 2.0979588032, -1.1935856342, -1.2795675993, -0.8881188035, 1.0661122799, 1.6177762747, + 1.107930541, -2.0232996941, -1.2102463245, 1.5625468493, 1.1707061529, 0.2248326093, -2.2631869316, 0.3136663437, + 2.0882434845, -1.1118528843, 0.8269920945, 2.2001664639, -1.0525869131, 0.1732597351, -0.6301019788, -0.2861230671, + -0.7035486102, -0.615886867, 0.6836638451, 1.2540742159, 1.1350761652, 1.1168063879, -0.0671314672, -0.5278354883, + -1.6708488464, -1.8426793814, -1.4898799658, 1.5074266195, 0.8699860573, 0.4585454762, -1.240521431, -0.3520327508, + 0.2623713315, 1.2189782858, 1.9564009905, -1.8678971529, 0.2386119515, -0.393491894, 0.0209807158, 0.0772104561, + -1.7392042875, -3.5995438099, 0.902064085, -0.1195738018, -0.5754822493, -1.109787941, -0.1072186753, -0.934309721, + 1.1105796099, -1.1826517582, -0.1520720869, -1.3386286497, -0.6448604465, -0.0941165313, -1.3919219971, -0.0296481308, + 0.1762068868, -0.2783095539, -1.6376761198, -1.0517594814, -0.6948207021, 0.0998614058, -0.6569946408, -1.8207826614, + -1.1987988949, 0.8665890098, -1.1092697382, -1.3847301006, -0.3812083602, -0.3967207372, 0.7238845229, 0.1558206677, + -0.3647925258, -0.5851247311, 0.4368338585, -0.7570932508, 0.0958884582, 0.764698565, 0.6894189119, -1.3329033852, + 0.0163381044, -0.3504721224, -0.7617780566, -0.8003528714, 0.9703143835, 0.2425616533, 1.4180577993, 0.8548147082, + -0.4770228565, -2.0487129688, -0.419829011, -0.5687003136, -1.3870117664, -0.5220409632, 1.4553519487, 0.5901443362, + -2.1908631325, 0.0048135603, -0.9869437814, -1.1687397957, -0.6182921529, 0.3242558539, 0.1612989306, -0.5659643412, + -0.6204778552, -0.635756433, -2.4414963722, 1.7249587774, -0.4532583356, 0.7349098921, 0.6877690554, 1.607247591, + 1.3938087225, -0.1504776627, 0.17853719, 1.7748429775, -0.251704216, 1.1803649664, -0.4024221003, 0.201550737, + 0.23574166, -0.1340533942, -0.1057958901, 1.6359223127, 0.3880910873, -0.3377050757, -0.42427966, 0.1702330261, + 1.4504141808, -0.2115017474, 1.4328291416, -0.5159255266, 0.0500065312, -1.7297106981, 1.3677421808, -1.0256661177, + 0.7512863278, -0.584046185, -0.9218277931, -1.3074322939, -0.7596263885, -0.130311057, 0.6998056173, 1.6276044846, + 0.9300687313, -0.6382806897, 0.692493856, -1.4637494087, -1.0807045698, -0.7944297791, -0.2523753047, -0.976949513, + 0.0696765333, 0.0790520534, 0.4146587253, -0.3838759363, -0.8621741533, 0.5710561872, 0.5936986208, 0.4419238269, + -0.2544811368, -0.0549358837, 0.2354987264, -0.5314922929, -0.5649043918, -2.2214460373, 0.5590788722, 1.1864672899, + -0.7585781217, -0.6145302057, -1.5558300018, -1.4099539518, 0.8280416727, 0.9231147766, 0.7842741013, 0.9364667535, + 0.1571408212, -0.0711527541, -0.3171508014, 0.508289814, -0.4674690962, 0.2489854246, -0.6435582042, 0.1705356985, + 0.0941540748, 2.0618970394, -1.3521838188, -0.674221158, 1.9083428383, 0.3393023908, -1.2060261965, -0.3309186101, + -0.127485618, 1.2129625082, 0.0350924097, 0.8869325519, 0.4675163925, 0.3396925926, -0.6079598665, 0.8370874524, + -0.9059494138, 1.4852802753, -0.2368526459, 0.5075811744, 1.3175470829, 0.9353399873, -0.5524255037, 0.1175686345, + -2.5573158264, -1.6868667603, 0.2753569782, 1.0403324366, -0.6371220946, -0.2227719426, -0.2769407034, -0.5384197831, + -1.2360104322, 1.6299774647, 0.341798991, -0.1112552434, 0.3643215597, 1.7209881544, 0.5956207514, 0.1271493584, + -0.3662891388, 0.8358281851, -0.4693106115, -1.0826193094, 1.5552965403, -0.3990328312, 0.3532243371, 1.3296083212, + -0.1214048937, 1.4217294455, 0.2872732282, 0.0609251931, -1.265054822, -0.214612186, -0.5631961823, 0.9530636668, + -0.5803635716, 1.039637208, 0.0411144495, 0.4864621758, -0.6175361276, -0.090116702, -0.4780751169, 1.1069477797, + -0.1862807423, -0.8247175217, -1.6179413795, 0.7025146484, 0.3208766282, -0.197042346, 0.7278860211, 1.6373358965, + 0.6480888724, -0.8358708024, 0.6518102288, -0.117141664, -1.0953273773, 0.3416704834, 0.2952704728, 0.0544999093, + 0.1129286736, -0.2682801485, -0.7968363166, -1.391556263, -1.0005905628, 0.0861226767, -0.2342195213, -0.2970535755, + 0.3015836179, 0.6606718898, -0.3637237549, 0.2571111917, 0.4363758266, -0.2371700704, 1.7235711813, -0.294847846, + 0.4730113745, -0.1083832458, 0.9850977063, -0.3806095421, -1.6842314005, -0.3037002683, -1.1704878807, 1.0020384789, + 0.3830957711, -0.6013025641, 1.1467078924, 0.0981238931, 1.7418649197, 0.6734358072, 0.383761555, 0.2948663235, + 1.7496265173, 0.6189327836, -1.7904872894, -0.4210635424, 0.924200058, 0.607111752, 0.6344060898, -0.7756280303, + 0.8779548407, -1.7009711266, 1.813863039, 0.3526122868, 0.1569912732, -0.2284603566, 0.4965924919, 0.1646198183, + 0.5903906226, 0.6860850453, 0.9792392254, 0.8350661397, 0.2694632113, 0.5770038366, 0.6414442062, -0.0007064881, + 0.1891670227, 3.3849787712, 0.343611449, 1.0508141518, 0.8994019032, -1.4829807281, 0.5896140933, -0.7613607645, + -0.2228245735, -2.2727417946, -0.7928166986, 0.8713169694, 0.7702066302, -0.2003716528, -1.1520656347, 1.3296504021, + 0.1453818381, 0.185029164, 2.170217514, -0.0070129517, -0.9936382174, 0.7370295525, 0.677577734, -0.3520190716, + 0.226910755, 0.3641117215, 0.2620734572, -0.3037872612, 0.7699797153, -0.590083003, -0.0836289078, 1.4655891657, + -0.4953507483, 0.9964833856, 0.6668241024, 1.6373746395, -1.0739023685, 1.5138012171, -0.9158896208, 0.3178542852, + 0.186496675, 0.7493636012, -1.6645890474, -2.7454783916, -1.230625391, -1.6678169966, 0.2192802429, -1.4617450237, + -0.8441195488, -0.5457106829, -0.5780082941, 1.8181878328, 0.0347079597, -0.3133533299, -1.1121459007, 0.7268883586, + 0.3151122928, -0.5868066549, -1.7393980026, 1.4476518631, 0.4207965732, 0.6836621165, 1.8285927773, 2.0717456341, + 1.6458361149, -0.265371263, 1.2877157927, 0.4153696597, -0.8352056146, -2.264906168, 0.0756139308, -1.136228919, + 2.347114563, 0.6214581132, 2.1959691048, -1.1375454664, -2.3548367023, 0.2680402696, 0.2878903747, -2.3156638145, + 0.7746370435, 0.5787066221, -0.5267652869, 0.7834333181, -0.608260572, -0.2690319419, 0.3098383546, -2.3032941818, + -0.5287114978, -0.4524430037, 0.5710779428, 0.2465500385, -0.0645666569, 0.351950407, -0.501552999, 0.395660013, + 1.3372106552, 0.8897716999, -0.4648024738, -0.2677031755, 0.2189188153, 0.4962541163, -0.479170084, 2.3462817669, + -0.5984350443, 1.2644433975, 0.1036138311, -0.6658110619, 0.036241211, -0.2366671264, 0.1581058204, 1.3862762451, + 0.6495568156, -0.2329453528, 0.0977031738, -0.5559794307, -0.844199419, -0.0818201452, -0.1046767831, 0.1273758411, + 0.4763332605, -0.1459098011, -0.1045340598, 0.7774121165, -1.0574012995, -0.3140885234, -0.1191266701, 0.8644908071, + -0.0673007965, -0.6035963893, -0.5750159621, 0.1821621656, 0.6175658703, -0.713314116, -1.461645484, -1.5156626701, + -0.5073814392, -2.4346702099, -0.7047346234, 0.9782006741, 0.8120400906, -0.4308604598, -0.499655664, -0.5441598892, + -0.2324918956, -0.7524700165, 0.4344911575, 0.1049314365, -1.2540309429, 0.8012621999, 1.1741023064, 0.1364507526, + 0.0647116527, 1.0092266798, -0.9059830308, -2.1721153259, 1.1897959709, -0.1393132359, -0.8553556204, 1.7093845606, + -1.1029998064, -0.1866924912, 1.3107669353, 1.1628562212, 1.0969941616, -1.2107185125, 0.5536623001, 1.1172728539, + -0.2946329415, 1.9040652514, 0.0030044951, 0.0876778588, -1.6686580181, 0.0381268524, -0.3123620749, -0.5600023866, + -1.0734754801, -1.362732172, -1.2353109121, -0.0829710588, -0.1355157346, -0.9162235856, 0.3678059578, -0.2945487499, + -0.4046669006, 0.8659502268, -0.534288764, 0.8775099516, 0.2651894093, -0.037718419, 0.7347764373, 1.7639116049, + 0.0837946832, 1.2767306566, 0.5433607101, -1.1277854443, -0.4092319906, 0.3871065974, -1.373226285, 0.0484902039, + 0.3826854825, -0.8100257516, 0.5566810369, -0.0652687475, -0.5655643344, -0.7411604524, -0.2269089818, -0.8638867736, + 0.9950011969, 0.2840652168, 0.58986938, 0.1182757393, -0.6138235927, -0.419510752, -0.6143563986, 0.2658936679, + -2.7899060249, 2.232057333, 1.3054738045, 0.5085213184, -2.8490052223, 0.5092891455, -2.4805524349, -0.7394009829, + 0.6821433306, 1.6671719551, 0.4611730278, -1.3810774088, 0.7877162099, 1.0247899294, -0.4438346326, 1.6174777746, + -0.5054686666, 0.1760485619, -1.3114635944, 0.4309389293, 0.480030477, -0.1087075472, -0.5780231953, -0.7047863603, + -2.1476862431, -0.213953197, 0.8352521062, 0.8809152246, 0.2713364661, 0.3603095114, 0.3651247323, -0.8552098274, + -1.1180651188, -0.6216140389, 1.9746416807, -1.6354407072, 0.6205993295, -0.3181858361, -0.5416350961, -0.8335084915, + -1.0118873119, 0.4987774491, -0.3509887457, -1.1358166933, -1.7522422075, 0.6429727077, -0.1995020509, -1.5381036997, + 0.1544527858, -1.2883707285, 0.5439504981, -0.0020331419, -0.2399383932, 2.7470574379, 0.5867281556, -1.384845376, + -1.5909763575, -1.3414326906, 1.2320175171, 0.9906088114, 1.5391710997, 1.7031075954, 0.1598866582, 0.5140388608, + 0.7190224528, 0.2349463552, 0.8574712276, -1.189602375, -1.2586706877, 0.2605868578, -1.1289823055, 0.569558382, + 0.5411376357, 0.36982885, 0.3675069809, -2.2430713177, -0.6659237146, 0.8024030924, -1.3820905685, 1.0470803976, + -1.4281877279, -0.3887173235, 0.3055648804, -1.5657507181, -2.1697707176, 1.4391497374, -1.5002782345, 0.8511645794, + 0.5123485923, -0.0351729281, -0.1442015767, -0.3420092463, 1.5379468203, 0.9169666171, 0.0578503907, 0.2137975246, + 0.1961234212, -0.5389728546, -1.6089800596, 0.4754639268, 0.2233437747, 0.1733196378, 1.2684612274, -0.2865017951, + -0.1468806267, 2.4246311188, -0.013609984, -0.1019738093, -0.6110169291, -0.8038156033, -0.0695337504, 0.4967861176, + 1.9961833954, 1.2340877056, -0.0171101298, 0.0730238631, 1.2438621521, -0.5428292155, 0.5201815963, -2.0732119083, + 1.0970755816, 1.7306132317, -1.7191520929, -1.0230888128, -1.6075240374, 0.6967043877, 1.0618695021, -0.3732878268, + 0.6697552204, -0.9198107123, 0.7653980255, 0.6345857382, 0.3547610641, 0.75049299, -0.3338160217, -0.5197306275, + 0.947227478, 0.2227191478, -0.1130388081, -0.0185331739, 0.5474200845, -2.255543232, 0.4503259957, 0.9500397444, + -1.8120361567, -0.9349394441, -0.0216028914, 0.5007613301, -1.4258812666, 0.9653455615, -0.2123300284, -0.9972632527, + 0.459982276, 1.4621566534, -0.9623032212, 0.0821985975, 0.7254318595, -0.8844993114, -1.1279693842, -0.0905174986, + 2.1163721085, 0.5569891334, 0.4357909858, 0.1275379509, -0.3727503419, -1.5048179626, -0.9216700792, 2.6693191528, + 1.8621063232, 0.0340112634, -0.2996329963, 0.1685769856, -0.0407568179, 0.2233879268, -1.7338620424, 0.419311434, + -1.7407432795, -0.3416656554, 1.9146230221, 0.7406899929, -1.3047709465, 0.4453069568, -1.8995198011, 0.1776600182, + -0.1196291074, 0.6559990048, 0.4963692725, -0.4981673658, -0.2931072414, -1.5256278515, -0.3368673921, -0.0629800633, + -0.3711330593, -0.4460727274, -0.1216611713, -0.7857735753, 1.782925725, 0.5151084661, -1.0354783535, 0.3958749175, + -0.7858343124, 0.3499429822, -0.4504361749, 1.8571742773, -0.5264532566, 0.8362266421, -0.6549919248, -2.2250118256, + -0.3075691462, -0.7183296084, 1.306358695, 0.2724380791, -0.7761501074, -0.356736213, 0.0337915644, -0.6230852008, + 1.2878644466, 0.8142136335, 0.7467980981, 0.0545031875, -0.7823157907, -2.0375680923, -1.5598759651, 0.7258884311, + 0.2529396415, -0.1873801351, -0.2569098175, 0.9535322785, 0.320266664, 0.937227428, -0.7806515098, 0.005757513, + 2.1948187351, 2.1471142769, -0.3790979385, 1.2801339626, 0.6664164662, 0.839004755, 0.279363662, 0.3506715596, + -0.8946903348, -0.1892145276, -0.2091954798, 0.8307814598, 0.7596340775, -0.6366750598, -0.2397034466, 0.0246799253, + -0.7540863156, 0.6899034381, 0.7105519772, 1.9139291048, -0.9092925787, 1.0814040899, -1.6866900921, 1.2264014482, + -0.0857531503, 1.1177709103, 0.0718116313, 0.6214321852, 0.8597166538, 2.5825061798, -0.0952331051, 0.2181185037, + -0.2722103, 2.0228359699, -0.4731457233, -0.4897209406, -0.8466237187, -0.7927527428, 0.253584832, -1.7146792412, + 1.4753947258, 0.128921032, 1.0652494431, 0.8515291214, 0.4173741341, -2.0765564442, 1.2504419088, -0.0443437658, + 1.5116868019, 1.8558517694, 0.349113524, 1.693716526, -1.0338196754, -0.406738013, 0.8262225389, 1.4143344164, + 0.8692837954, -0.237712428, -0.3093731403, 2.453953743, 1.8264842033, -1.1981890202, -0.0252850149, 0.4000261128, + 1.0661538839, 0.8577992916, 1.723626852, -0.3746747077, -0.6475515962, 1.0553491116, 1.0886489153, 1.0331463814, + 1.4672757387, -0.2489519864, -1.0970305204, 0.9412765503, 1.0543107986, -0.0536026321, -1.0659681559, -1.0156000853, + -1.5400930643, 0.4246522188, -0.0187172014, 0.8591113091, 0.5056961775, 1.0604348183, 0.4011115432, 0.6088192463, + -0.437376976, -0.4630948007, -0.1633478701, -0.0268928893, -0.9721285701, -0.0090062944, -1.8252615929, -0.8835651875, + 0.8288798928, 0.9291929603, -0.6319452524, -0.7508799434, -1.235865593, -0.2250781059, 0.8632010818, -1.3284317255, + -0.1848070771, 0.9850524068, 2.746587038, 0.3367196023, -0.1066792235, 0.6596503854, 0.5575050712, 1.2563635111, + 1.6511420012, -2.0832810402, -1.7445597649, 1.0956785679, -0.3525366783, 0.7681734562, -0.8345808983, -0.4927855432, + -0.7883468866, -0.7326194048, -1.2440841198, -0.0345288664, -2.7205607891, 0.6942610145, 0.7805992961, 1.9402210712, + -0.3773797154, 0.686152935, 1.487428546, -1.1206152439, 0.4860053062, -2.234680891, 1.6082966328, -1.4920960665, + -0.089771688, -0.9688981175, 0.2630314231, -0.2303248346, 0.7283701301, -0.2108328491, 0.8876338601, -0.0404112227, + 0.3710825443, -1.7251782417, 1.6026358604, -0.5407242775, -1.5847551823, -0.2540806532, 1.0504814386, -0.64516294, + -0.2521845698, -0.733525157, 1.4679886103, 0.987013936, -0.2953719795, -0.6325708032, -0.2677554488, -0.6401776671, + -0.9570604563, 0.7377889156, -1.1807512045, 0.2154497951, 2.0238044262, -0.0856862068, -0.9026969671, -0.7318025231, + -1.8274935484, -1.2555172443, 2.3201255798, -0.0519613996, 0.1016197801, -1.6232725382, -0.1265503317, 0.3801241219, + 1.2250181437, -0.8491208553, -0.0472059064, 0.8237924576, 0.0123016173, 2.5513939857, 0.429420501, 0.9571111202, + -1.0746427774, 0.7808172703, -0.0097871711, -1.0527443886, 1.9884264469, 1.4375798702, 0.1371785998, 1.1927306652, + 0.5296163559, 0.707614243, 0.708240211, -0.0101034651, -0.9877721667, -0.7654364109, 0.8536295891, 2.0100181103, + 1.7068982124, -1.0156911612, -0.3960444927, 1.1031227112, -0.5324784517, -1.4763936996, -1.0825276375, 1.8315578699, + 0.2433653921, -0.8337994218, 0.436499238, -0.0291025154, -1.1196365356, -0.6079728007, 0.3150257468, 0.9560776353, + -0.46412462, 0.0915727168, 1.4087785482, 0.588257432, -1.0789182186, 1.1352727413, 0.3621936738, 0.7451221347, + 0.9481421113, 1.1590278149, 0.3194058836, 0.2874425352, 2.1013104916, 0.5960393548, -0.9192075133, 2.1953134537, + -0.2614995241, -1.1423128843, -0.6494238973, 1.2167494297, -0.4384835362, -0.4017018974, 0.95024544, 1.7171781063, + -0.3878672123, 0.1367998719, -0.2946698964, -0.3433934152, -2.0157806873, 0.3329694569, 0.1684727818, -0.611179173, + -1.2262228727, -0.3766339123, -0.0963002965, 2.6844952106, -1.4412274361, -0.3843735456, -0.6183712482, 0.2814792395, + 0.4891471267, -1.6365194321, -0.5198187828, -0.436417222, -0.1316254586, 0.7158564329, 0.9850757122, 2.1309149265, + 1.7007933855, 0.4094660878, -0.4367023706, 0.1017921567, 0.9821092486, -1.8584427834, -1.8049651384, 0.3871385157, + -0.7662376165, 0.8493132591, 0.8043100834, -0.7121513486, -1.0511052608, 1.5637362003, -1.4827083349, -0.5826970339, + -0.1382329762, -1.4593697786, 0.8752971292, 1.5086021423, 0.0051624221, -0.6862916946, -0.0043434026, -0.1981390715, + 1.6246167421, -0.7251117826, 1.4283695221, 0.3859604895, 1.3972984552, 1.5540999174, 2.507796526, 0.610691607, + -0.2925674021, -0.6402983069, 1.1182700396, 1.3853303194, -1.2084366083, -0.0332357697, 1.1627514362, 0.3403298259, + -1.474214077, 0.1268104017, 0.0190874953, -0.2759317756, 1.9947268963, 0.3381502628, -1.2353051901, 0.1884480715, + -0.0715656877, -0.4184769392, 1.6307207346, 0.8701319098, 1.6656786203, -0.2166256756, -0.849594593, -0.9305421114, + -0.2624989152, -1.0245912075, -0.3905347288, -0.8387540579, -0.7649152875, 0.745021224, -0.1490360945, -1.2048982382, + 0.0052565383, 0.2848755121, 0.2007502466, 1.8125782013, 0.6278348565, 0.3501205146, -0.778015554, 0.2294713855, + 0.2744221985, -0.7625269294, 1.2621465921, 1.7222411633, 2.0579175949, -2.1386463642, 0.1349654347, 1.3889241219, + 1.0150574446, -0.1360161752, 1.1493418217, 0.9397243857, -0.286726743, 0.1947177649, -0.4196768999, -1.1011104584, + -0.4494042397, -2.112370491, 0.8957493901, -1.3408659697, -1.5817927122, 0.528788209, -0.4619643688, 1.8015409708, + -0.3952269852, -1.9611263275, 0.7645410895, 0.0038085454, -0.5192066431, 0.646792829, -1.2985756397, -1.0088950396, + 0.0489339791, 0.7028077841, -1.9100688696, -0.2068070322, 1.0011336803, 1.4111698866, -1.7828242779, 1.2758779526, + 1.0975503922, 0.1588366926, 1.1677552462, -0.1960469037, -2.4964635372, -0.5020163655, 0.4433894455, 1.3550033569, + -1.814002037, 1.3322262764, -0.0272594821, 0.5605358481, 0.6819627285, -0.3883218765, -0.4051531553, 1.9179229736, + -0.189830929, -0.4401783049, 0.3061546683, 0.5527454019, -0.0615562722, 1.1755992174, -0.357942462, 0.6841399074, + 0.8924797177, 1.0648961067, 0.3632277846, 0.5677139759, 1.2489463091, -0.1964088529, 0.6993002892, -0.3229619265, + 0.2260445952, 0.9134680629, -1.1335862875, 0.8838149905, -0.2615242898, -0.5182797909, -0.7718955278, 0.609728992, + -1.0060567856, -2.0341730118, 2.3055205345, -0.0929920897, 0.8716686368, -0.9269929528, -0.2685537636, 1.5324709415, + -1.0759367943, 0.1769119054, 0.6477789879, 0.6450597644, -0.0311753843, -0.3823924959, 0.9851641655, -0.009995955, + 0.3076856434, 0.8313928843, -0.9556804299, 0.9590794444, -1.6914818287, 0.1404424012, 0.1872563809, 0.6698793769, + -0.6741681695, -0.6608606577, -0.526224196, 1.773422718, 0.5527629256, 1.2757896185, 0.1524516791, -1.0622953176, + -1.8591362238, 0.6258513927, -1.0650826693, 0.1954589635, 0.0974331871, -0.5126291513, 0.72991997, 0.3523078263, + -0.3958586156, 0.3189874291, -1.6703007221, 0.1114622653, 2.765781641, 0.3965610564, -0.3496138453, -0.9666339159, + -2.0601592064, -0.5482038856, 0.7389851809, 0.7662830353, 0.6029362679, -0.3516857326, -0.299818337, -1.4955811501, + -0.3838070035, 1.3036487103, 0.5547218919, 0.3298881352, 1.1064683199, 0.9430986643, 0.3839015961, 1.4636781216, + 0.5495438576, -1.0143105984, -0.1891726404, -2.5100672245, -1.193549633, 0.2183128446, 0.9599092007, 1.5681704283, + 0.8648939133, -0.5642094612, -0.3421497941, 1.467993021, 0.1009292603, -0.1126660332, -0.0972139761, -0.9727141261, + 1.3819562197, -0.257573992, 0.2227812111, 1.6426393986, 0.52660954, 0.3665766418, 1.4545422792, 0.8404076695, + -0.8013294339, 0.9210820794, -0.6172357798, -0.4117927849, -0.7112870812, -0.2017239034, -0.0910126418, -0.8601288199, + 0.0719281286, 0.7666918039, -0.0444614887, 0.222136125, -1.0537574291, 0.6026690006, 0.1948057115, -0.5820829868, + 0.9025380611, -0.1448483169, -0.127486214, 0.0873810202, 2.6046392918, 1.4802066088, 2.0170738697, -2.2271463871, + 2.023566246, 0.1746399105, 1.1856992245, 0.3476963341, -0.1823394597, -0.9577738643, -0.6233409643, -1.0143755674, + 0.8863685727, 1.2911611795, -0.7955857515, 1.9125989676, -0.7551600337, -2.2882008553, 0.6161273718, 0.1451403648, + -0.7093462944, 1.2617323399, -0.6054198146, 0.2747418582, 0.4786858857, 0.6184700727, 0.0912145898, -1.2048335075, + 0.3290942907, -0.236095503, 0.5835716724, -0.9597758055, 1.7403790951, 1.5781999826, -0.7483271956, 0.5618293881, + 1.2583650351, 1.1227834225, -0.4328562021, 0.1996002942, -2.6929018497, -0.8850705624, 0.3370223641, 1.0766296387, + 0.2751036286, -0.0249971207, 0.3484513462, -1.466181159, -0.5508713126, 0.7615688443, 0.2132720649, -0.5305895209, + 0.5651596785, -2.1194589138, 1.5398962498, -0.1179601401, -0.0704612285, 0.8395457268, 3.844824791, -1.6787865162, + 1.2805011272, 0.5926063657, 1.036973238, -0.9114980102, 0.7235304117, -1.1771003008, -0.8924003839, 1.5978136063, + -0.9991945624, 1.4228422642, -0.2267849296, -0.8862344027, 0.7951184511, -1.0446032286, 1.5943152905, 1.021911025, + -0.5544071198, 0.0632716194, 1.3749527931, -0.3679391444, 0.8503480554, -0.5020872355, 0.6588804126, -1.8511382341, + 1.3213031292, 1.8603336811, 0.5004802942, 0.3071632683, -0.2847483456, 0.2404857427, -1.5341200829, -0.3211204112, + 2.2744309902, -0.136551857, 0.89236027, -0.3667230308, -0.5734806657, -0.3486274481, -0.1186143011, 0.8307850957, + 0.6011481285, -0.7103462219, -0.6508090496, -0.8464833498, 0.604369998, 0.2763639688, -0.1737786531, -0.0291063003, + 1.4368228912, -1.5170634985, -0.9887233973, 1.1650506258, -0.8643849492, 1.2665343285, -1.3787747622, 0.3148807883, + -0.8181608319, 1.1779116392, -0.7715457678, 1.0275965929, -0.1303185225, 0.1004789919, -1.210690856, -0.0878942758, + 0.1088947505, 0.6320188642, -0.9480621219, -1.3948607445, 0.0503652915, -0.3959770799, -0.1595087647, -1.2462719679, + -0.8731278181, -0.3450042605, 1.7942147255, 0.4963313341, 1.0791658163, -0.0937815085, -1.0531029701, -1.2803995609, + -0.3876163363, 0.3790248632, 1.1142001152, -0.4398929477, -0.8452531099, -0.3301915526, -0.3507989347, -0.9891392589, + -1.354449749, 0.9459623694, 0.2598392963, 0.568295598, -0.9399594665, -0.26056844, -0.8619480729, -0.5104118586, + 0.519477427, -0.9169836044, -2.6900908947, 2.7366669178, -1.4323606491, 1.6291747093, -1.4959498644, -1.1548160315, + 2.5480496883, 0.2900446653, 1.4242911339, -1.2634080648, 0.1963342428, 1.4480313063, 0.3778089583, -0.6415191293, + -0.2120681107, -1.3008939028, 0.3545155227, -0.2053026557, -1.9529192448, -0.0525757596, -1.0794268847, 0.6703519821, + -0.4758709371, 1.1867605448, -0.3449138403, 0.3547198176, 1.6804623604, -0.9776315093, -1.9091552496, 0.6955775023, + 0.9033918381, -0.1566496491, 1.4611063004, -0.8640043139, -0.9245055914, -1.2249439955, 0.736941278, 1.0058851242, + 0.5710602403, 0.1333852112, -1.2250558138, -1.7569497824, -0.5837014914, 1.0665876865, -0.8548253179, 1.4985412359, + -1.5736359358, 1.4790285826, -0.5080267191, -0.4287172854, -1.9432892799, -0.6099470258, -0.201536715, -0.8354988098, + 0.1913418621, 1.0483424664, -0.2596043646, -1.7170075178, 1.5210067034, -0.6716116071, -0.0163926631, -0.4215934277, + -0.0219555702, -0.7757620215, -1.5904581547, -0.2381323576, -0.9930461645, -0.7130764127, -0.0591275357, 1.0727508068, + -0.3543343246, 3.0782167912, 1.2767871618, 0.7470397949, -0.9672718644, 1.4354689121, -1.2770084143, -1.4952831268, + 0.6237402558, -1.3215762377, -1.4172451496, -1.2935512066, 0.5550708175, 1.3703895807, -0.5524062514, 0.4399808049, + -0.4097305834, -0.3165017962, 0.349576205, 0.7616158724, -1.1521909237, -1.0199534893, 0.7851632833, -0.7123095393, + -1.3383508921, -0.6731940508, 1.0400739908, -1.7057328224, -1.6736978292, 1.1462876797, 0.6484333873, -0.7210823298, + -1.1814935207, -0.0193868037, 1.2531992197, 0.1176470742, 0.1281784475, 1.019041419, 0.3068197668, 0.28438887, + 0.6067525744, -0.4399292171, -1.8810433149, -1.7169803381, 0.1544450819, 0.3690387607, 0.1635134518, 1.89126122, + -1.024371624, 0.8578745127, -1.1951819658, 1.082007885, -0.0740952268, 0.4703108072, -0.4310616255, -1.6714330912, + -0.6286044717, 1.5786759853, -0.2143421322, 1.080947876, 0.4545911551, -0.67446661, 0.0244885739, 0.5634146333, + 0.1647529304, -1.387524128, 0.2178342938, -0.0701511055, 1.8721164465, 0.216697678, 0.5953648686, -0.3440511525, + -0.3522693515, 1.8573738337, -1.2786791325, -0.6153733134, 0.7561426759, -0.5053442717, -0.0918319449, 0.5894739628, + 0.1524143517, -1.6383651495, -0.4843915999, -0.2537766397, 1.384152174, -0.7449327111, 0.0421048775, 1.2323815823, + -0.7230997086, -2.1666941643, 0.0070414278, -0.3546690643, -0.6129224896, 0.5168722272, 0.0161491167, -1.3249355555, + 0.2833559513, 0.2064211667, 0.6386342645, -0.2798440158, 1.6235107183, -1.912124753, -1.0733910799, 0.7745764256, + -0.2634502351, 0.1581316441, -0.2726663649, 0.2395518273, 0.0382109508, -0.9823060632, 0.2630215287, 1.1353650093, + -0.9041807652, 0.3829956353, -0.0649039596, -1.3555053473, 0.7701690197, -0.861092329, 0.8052645326, -0.8781912923, + -0.7311577201, -2.9039270878, 0.0947883651, 0.4915755689, 0.6707758307, -0.384303242, -0.0357921906, -0.5924118757, + 0.9842528701, -1.4029403925, 1.2588713169, 2.0025391579, -0.3116514683, -1.9610450268, 0.6682580709, -1.6717112064, + -0.5060207844, -0.3277585804, 1.4305614233, -1.0951304436, 0.2470769286, -0.0456573442, -0.3003408611, 0.5671326518, + 0.0664090812, 3.3978607655, 0.1929901093, -0.3330067396, 0.0479260944, 0.6180526018, 1.0526547432, -2.1311256886, + 0.1027629226, 0.8785018921, 0.060810741, 0.4887917042, 0.6694629788, 0.3460426033, -0.452218622, -1.480325222, + 0.0475699566, -1.0768768787, 0.2929372489, 0.2556186914, -0.4252198935, -1.8915692568, -0.2100862265, -0.0845040902, + -0.7917732, -0.467776835, -0.4222314358, 1.2808054686, -0.3017964065, -0.1799859554, -2.1371099949, -1.6400431395, + 0.5384729505, -1.4935162067, 1.4454184771, 0.4328987002, -0.4091602862, 1.2936794758, -0.7945672274, 1.1871507168, + 1.5372850895, -0.8579943776, -0.7523997426, -1.3768255711, -0.5170516372, 0.5266361237, 0.5500448346, 0.2686732411, + 1.1339052916, 0.150580138, 1.0301640034, -0.5608243942, 0.5116033554, -0.1938695461, -0.231837973, -0.6758121252, + 0.6146999598, 0.7851496339, -1.3886620998, -0.3124918342, -0.1945108175, 1.3500403166, 0.5355877876, -0.6446334124, + -0.3353732824, 0.1246494949, 1.4483478069, -3.047611475, 1.8138883114, -1.7988743782, 1.6526031494, -0.1701273024, + 1.5951917171, -0.4962559342, 0.513864994, -0.1693724394, 0.2989767194, 0.9507718682, 0.1399330646, -0.2367779166, + -0.5848656893, 0.0408673994, 1.1533704996, -0.1025816724, -1.8772822618, 0.7537982464, -1.0198754072, 0.0566727556, + -0.8193967938, 0.6501716375, -0.6657895446, -0.7310741544, -0.4085451663, -0.9486625791, -0.0811254904, -0.2931586504, + -0.2771906257, 1.2176634073, -0.7611948252, 0.5342000127, 0.2206405699, -0.3270626366, 1.6594908237, -0.900023222, + -1.8313491344, 1.1096508503, -0.1459466666, -0.6582320333, 0.3887246549, -1.8797705173, -1.1226110458, 1.8616946936, + -2.1927931309, 0.0301647671, 0.0473821871, 0.6955246329, -0.5873502493, 1.2350827456, -0.7400141358, 1.658225894, + 0.8974621296, -0.838383913, -0.1603887081, 0.4101619422, 2.2152121067, -0.6797272563, -0.26356408, -0.3556258082, + -0.7574476004, -0.1034703329, 0.2876872122, -1.0428086519, -0.5722566247, 1.1083568335, 0.5434480309, 1.1623055935, + -0.1919558942, -1.3977537155, 0.3964772224, -0.3976658583, 1.0213907957, -0.6081345081, -0.1984753758, 0.7719884515, + 1.6116856337, -0.5647926331, -2.0718548298, 1.2286254168, -1.5091139078, -1.1186282635, -0.2798033059, 0.0749905184, + 0.3844977021, -0.0438706018, -0.2827286422, 1.2734726667, 1.2332676649, 0.5621038079, -0.1019901857, -0.4522658288, + -1.5339000225, -0.7295792103, -1.2359548807, -0.5382317901, 1.6926423311, 0.0574849769, 0.5758835077, 1.9828463793, + 0.5544055104, 0.1886905134, 2.5439355373, -0.3392686546, -0.6245530248, -0.4217739999, -0.122637853, -1.1134990454, + 0.3403982222, -0.2209866643, -0.0216140505, 0.8030695319, -0.5919985175, -0.0856432617, 2.3269383907, 0.2625982463, + 1.1156468391, 0.2020006925, 1.2754621506, -0.8897251487, 0.9669903517, -0.5493559241, 1.4233219624, 1.3478831053, + 0.4568857253, -0.0930040702, -1.2832940817, 0.2640421391, 0.6426716447, 1.6632509232, -1.4980686903, -0.5740880966, + 1.1556472778, 1.3272485733, -2.161659956, -1.6268901825, -0.5095205903, -0.1517010182, 0.0697079748, 0.6218604445, + -1.7932162285, -1.5523602962, -0.236483261, -0.2116670161, -0.9998782873, -2.7679753304, 1.1789580584, 1.2540689707, + 0.2540247738, -0.4325055182, -0.3744247854, 0.5653214455, -0.248746708, 0.9951139092, -0.3737806082, 1.478358984, + -0.4989001155, 0.1346275359, 0.4608412683, 1.2888094187, -0.4664494693, 0.9327733517, 0.6842293739, 0.4536570907, + 0.7156196237, -0.888196826, 2.7164895535, 0.3652488589, 0.6087380052, -2.649926424, 0.4615913928, 0.5398000479, + 0.6077411175, 0.1409384161, -0.6123158336, -1.3663132191, -0.8288936615, 1.7153819799, -0.5907678604, 0.9421477914, + 1.1129484177, -1.4384629726, 0.5338668227, -0.7236166, -0.3594409227, 0.3317614794, -0.0182189792, -0.9622032046, + 1.2848628759, 0.0738611221, 1.8387027979, 0.9678576589, -0.506265223, -1.4060206413, 0.7187169194, -0.0001753581, + -1.2740622759, 0.3961002231, -0.4440979064, 0.2215769291, 1.1455968618, -1.5288711786, -0.1165431365, 0.1862287372, + 0.4621602297, -1.2539870739, -1.9266433716, -0.3532809019, -1.2628905773, 0.6617218256, -0.4527367353, -0.2476387024, + -0.3344658315, -2.1655943394, -0.0272593759, 1.5402753353, -0.8876109123, -0.574072957, 1.4609684944, 0.8156918883, + -0.6739629507, -2.1460916996, 0.1425817907, 1.2147607803, -1.1786000729, -0.6290073991, -1.2190272808, 1.9812610149, + -1.8409180641, -0.5344301462, 0.0046728416, 1.4701166153, 0.0316930152, 0.6217797399, 0.3374963999, -0.0923807099, + -1.0196141005, 0.2970777452, 0.5648963451, 0.0846193135, -0.5526602864, -1.0114645958, 0.0666290522, 0.7835562229, + 0.254948765, -0.5999336243, -0.9358597994, -1.2035146952, 0.0867796391, 0.2015919834, -0.6562302709, 0.5852459669, + 1.0319597721, 1.6525110006, 1.0681165457, -0.3666232228, 0.4162625074, -1.4362779856, 0.9617007971, 0.2182102948, + 0.4531165659, 0.0359582119, 0.2627207041, -0.6436700225, -2.5046739578, -0.1782875061, 0.6615344882, -0.8519901037, + 0.2686338723, -0.6474667192, -0.1683191508, 0.6466437578, 1.440961957, -0.2617304027, 1.9130183458, -1.5077996254, + -0.9462426305, -0.2838377357, 0.0526938327, -0.623619318, -0.4251126945, -0.0550731048, -0.813269794, -1.2440909147, + -1.0892269611, 0.313657105, -0.0490135439, -0.6237413883, 0.6349942684, -1.0433175564, -2.0065948963, -1.9424735308, + -0.6845101714, -0.6202213764, -0.3914147615, 2.2720336914, 0.0739588216, 2.2880032063, 0.5641351938, 0.4740304947, + -1.8853971958, 0.4114308357, -1.1214060783, 0.4880087078, 0.4406731129, -1.2576910257, -0.6754882336, 2.2553937435, + -1.3919758797, -0.6938131452, -0.0537123717, -1.183159709, -1.1901445389, 0.6069281697, 0.8246663213, 0.3340826333, + -0.2523243427, 0.0757556856, -0.2096677721, 0.7798483372, -0.8629242182, 1.6895529032, 0.1870408505, 0.3471640348, + 1.1528530121, -0.5211679339, -0.3400958478, -1.814909935, 0.1189164966, 0.4202474952, 0.2755539119, 0.306302458, + -0.1489593983, -1.3223544359, -0.1619068384, 0.9510185719, -0.0225095376, -0.8107722998, -0.387067765, 1.5546485186, + 0.0615551658, 1.6332503557, -0.7618871331, 0.9830802679, 1.2946121693, -1.3857856989, -1.5067552328, 0.2777404487, + -0.460618645, -0.4907822013, 1.3923071623, 0.6343035698, 0.9364335537, -1.700499773, -0.4155659676, -0.1267781258, + 0.3403526843, -0.5315839648, -0.7173085213, -0.0580628328, -0.4464083612, 1.3359794617, 0.0476373993, -0.2086803317, + -0.1372452974, -0.0591464713, 1.3616489172, 0.0903304443, -0.3211252391, -0.9177269936, -0.9550664425, 0.3909903765, + -0.2268156558, -0.008225794, 1.2424693108, -1.3258881569, 1.435270071, 0.7880265713, 0.1414163709, -0.2054441571, + -1.101452589, 0.659525454, -2.318100214, -0.0876651481, -0.6974890828, -1.4716603756, 0.7876362205, 0.1344156265, + -1.3554036617, 0.6036042571, 0.1190322861, 0.9254586697, 1.250878334, 0.2331293225, 0.4055940509, 0.7998869419, + -0.5757550597, -0.913511157, 0.7675039172, -0.7781230807, 2.4180750847, 2.7852742672, 0.1045434698, 0.6787592173, + 0.4007455409, -0.3564361036, 1.534771204, -1.4705452919, -0.7479464412, -0.956625402, 1.2649875879, -0.164669618, + -0.515560329, -0.7206394076, 2.1404452324, -0.7790234089, 0.7116395235, 0.9158282876, -1.4436525106, -0.4211129844, + 0.7956809998, -0.9565706253, -1.3517844677, -0.3119147122, 0.2453809679, 1.4581965208, 0.7543629408, 1.6049604416, + -0.4158651829, -1.2043303251, -1.0034831762, -1.1723743677, 1.0647040606, 0.2321242392, 1.0505148172, 0.8940162659, + -0.1205676943, 0.393345654, -0.4981866777, 0.8221628666, -1.1024289131, 0.9230841994, 0.1395951062, -0.27517277, + -0.4984712899, -1.3625754118, -0.4306615889, -0.5384787917, -0.9555833936, 2.1937851906, -1.1307214499, 0.4357461333, + -0.8771927953, 0.85781914, 0.3055385947, 0.2204068154, 0.6302809715, -0.0163004622, -0.8319802284, -1.3126729727, + -1.3170480728, 0.5569218993, -0.3531013131, 0.364179492, 0.3810200691, -1.4238847494, 0.1009590551, -0.3800279498, + 0.7649206519, -0.6368266344, 1.7794678211, -1.1880887747, -1.4316164255, -1.6969466209, 0.5561639667, 1.1471374035, + 0.9899902344, -0.1633966267, 0.6074290276, 0.5961022377, -2.8764624596, -1.0727797747, -0.8768104911, -1.0192153454, + 2.8190350533, -0.2256239206, -0.394317776, 0.8255993724, -1.1556965113, -2.1723108292, 0.7178436518, 0.6824865341, + 0.5922962427, -0.3120145798, 1.0898365974, -0.301110059, -0.1291559339, 0.413125366, -0.3478083014, 0.3667017221, + 0.333096683, 0.3752444685, -1.4574064016, -0.2556218207, -0.3968566358, 0.5036401153, -0.9107782841, 1.3879652023, + 1.2289830446, 0.7992539406, 0.6849098802, 0.0707288608, -0.0696446821, -0.1699579954, 0.4269837737, -0.5689053535, + 1.0672354698, -0.7523844838, -0.6921916008, 0.7129670978, 0.0622992143, -2.1855492592, -1.0172541142, 0.660946548, + -0.2331690043, 0.2233446985, 1.7745434046, 0.096902959, 1.6294189692, -0.6170974374, -1.2387092113, -2.4741020203, + -0.0289155487, 0.2518738508, -0.1491267532, -0.3006697595, -0.942897141, 0.3010059893, 2.3177731037, 0.161162883, + 0.6096910834, -0.534463644, -1.1325211525, 0.5708059072, -0.2217664272, -0.1881082803, -0.2953444421, -2.7062401772, + -0.0275921281, 0.9700416327, -0.5384776592, 1.4731795788, -0.691036582, -0.8083460927, -0.2849730253, -0.9540877938, + -1.0074419975, -0.3939363658, 0.8493119478, 1.3113639355, 0.1255604029, -0.5570324659, -1.1712133884, -1.6394242048, + 1.0471559763, -0.6554031372, 0.3733699918, 0.8540666103, 0.1184398606, -0.1343704611, 1.3181189299, -0.0528781712, + 1.9076501131, -0.1207094342, 1.092028141, 0.5713807344, 1.3109537363, 0.7840664983, -0.7930327654, 0.7855635285, + 1.5472874641, 0.6432893276, -0.02428375, -0.3870694935, -0.5971293449, -0.2899690568, -0.7334938049, -0.0300292429, + -0.9743447304, 1.1392588615, -0.9915491343, -0.8986487985, -0.8678231239, -0.6919215918, 0.4460268319, 0.7036303878, + -0.3525555134, 0.2887427211, -0.7344346642, -1.1392246485, -1.1486465931, -1.125623107, 0.2172904909, 2.2096951008, + -0.276812613, -0.4194982052, 0.0895349309, -0.4994725883, -0.4294939935, 1.5925871134, 0.9207655787, 0.1646861136, + -0.3742833734, 1.3894538879, -0.4878883362, -1.207113862, -0.1191699728, -1.4390913248, 0.2861081958, -0.1579031646, + -0.397436738, 0.175246343, 0.3748835325, -0.3617827296, 0.8169750571, 1.3362919092, -0.148403123, 0.8671530485, + -2.853600502, -0.0906554833, 0.0088043632, 1.6732629538, 2.1423466206, -0.7370496988, -1.2664498091, 0.6641715765, + 1.2869904041, 0.6079743505, 1.3022139072, 1.350084424, -1.5029324293, 0.6907622218, -0.4061397612, -0.8483211398, + -0.3681233823, -0.8578148484, -0.1548754722, -0.5499112606, 0.2328155786, -0.6580201983, -0.0703464821, 0.5699104667, + 0.1111837327, 0.778128922, -1.5467842817, 0.5690723658, 0.4452523887, 0.0673167929, -0.0463277884, -1.8743733168, + -2.8230288029, 0.5497969389, 1.9723832607, 0.5564820766, -0.361564815, 0.0729349479, -0.0699678808, -0.7118794918, + 1.3303546906, 0.0751053691, 0.5226886272, 0.9767999053, -1.7849285603, 1.5602053404, 1.074296236, -2.6806015968, + -0.4691926837, -0.536178112, -0.2826193571, -2.2090110779, 0.9901263714, -0.0261297319, 0.8651404977, -0.2917624712, + 0.4948405921, -0.7538119555, 1.5201109648, -0.7561060786, 1.1786170006, -1.1826119423, 0.7336524725, 0.9188173413, + -1.9997373819, 0.4963880479, -0.8404771686, 0.4128607512, 0.4337054193, 0.2035663426, -0.7117573619, -1.7409338951, + -0.5598160028, -0.9008379579, -0.4741972387, 0.0416170508, -0.7776945233, -0.2547941804, 1.123453021, -0.3588818014, + -1.5244874954, 1.1329869032, 1.7894061804, 0.7349005342, 0.1345884353, -0.5785191655, -0.126729846, -1.1764208078, + 1.3696135283, 0.4106918871, -0.0976169482, -1.219037652, -0.9109613299, -0.0955943689, -1.0170726776, 1.0108891726, + 0.1099565029, -0.7064110637, 0.29428792, -0.5495336652, -0.4723607302, 0.577761054, -0.7016943693, 0.7423120141, + 0.0810565427, 0.8770937324, -0.1352943182, 0.685725987, -0.5274185538, -0.3148475289, 0.431271255, 0.818038404, + -0.1410973966, 0.5621446967, -0.8120179772, -0.0752384365, -0.0236309376, 0.9926939011, -0.5143352747, 0.1516641676, + 0.7576454878, 0.1885048598, 0.8092653155, -1.4317138195, 0.7512933612, -1.785358429, -0.3403401673, 0.5114456415, + -1.0479772091, -1.7917723656, -0.7522316575, 0.9491505623, -1.5872008801, -0.1898578852, 0.7266498208, -0.961915493, + -0.1413860023, 0.9052723646, -0.3882459998, 0.1237693802, -0.2326326221, 0.3206429183, -1.362947464, 1.1452333927, + 0.7874519825, 0.4181374013, -1.5147526264, 0.0730068237, 1.3311444521, 0.7093572021, -0.9712299705, 2.1352322102, + 1.023103714, -1.1636049747, 1.0286316872, -0.5036383271, -1.6746673584, 0.4073672295, -0.0182898492, 0.1493997425, + -0.7960625291, -0.4407243431, 2.3877747059, 0.4815349579, 0.5813381672, 2.227905035, 0.935613513, -0.4409787059, + -0.8286496401, 0.7311822176, 0.2700185478, 0.5507662892, -2.5871624947, 0.6772342324, 0.2074013352, 0.4615665972, + -0.4190964699, 0.4770605862, 2.4217619896, -1.9182502031, -0.8544636965, 0.8381118178, -0.4485734701, -1.0919756889, + -0.2648122609, 1.009899497, -0.5472998023, 1.234803319, -1.4701932669, -1.9155840874, -0.1090629399, -0.1855992675, + 0.1095966473, -0.6782081723, 0.1180862114, -1.2295197248, 1.527453661, 2.3235061169, 0.2913398147, -0.3180084825, + -0.9371327162, -0.5686488748, 1.8743900061, 0.0845806673, 1.3588453531, 0.1544833183, -0.4382197857, -0.6617422104, + -0.2704090774, -0.0473123975, -0.1375723928, 0.5586237907, -1.475104928, -0.3098645806, -0.8870976567, 1.3249599934, + -0.2478749007, -0.4527670145, 1.0433957577, -0.4988560379, 2.0353519917, 0.1222634986, 0.8268195987, -0.2070628256, + 0.4064068496, 0.7379081845, -0.1530139744, 1.1486705542, 0.7987783551, -0.014631399, -0.8424440026, 0.2351379693, + 0.5839104056, 1.9307159185, -0.1338217556, -1.272960186, -0.9533520937, 1.4415456057, -0.095150061, 0.3972956836, + 0.2098439634, 0.5354406834, 0.877635479, 0.5473576784, -0.2294035405, -0.8871148229, 1.8933590651, 0.1261401772, + -0.5996055007, -0.0468349196, -0.4060138166, 0.0416313224, 0.0498172343, 0.5637643337, -2.2129881382, -1.1236852407, + -0.1304418892, -0.9155464172, -2.054723978, 0.6958734989, 0.010473731, -0.0415819399, 0.4621022642, 0.0875720531, + -0.5839158893, -0.1784689277, -0.4025821686, 0.9536439776, -0.1893357337, 0.469756633, -0.8019378185, 0.4339478314, + -0.4863450527, -0.7643893361, -0.4413174093, 0.7450090647, 0.4705619812, -0.5967475176, 0.2144325823, -0.048731979, + 0.423945576, -1.873352766, -0.6309217811, -1.3656258583, 0.5353654027, 0.312312007, 1.3560433388, 0.023187425, + -0.7732568383, -1.416018486, 1.1718209982, -0.6379296184, 0.9241999984, 1.1896660328, 1.4317412376, -0.1303557307, + 0.5576506853, 0.7538163662, 0.4692847729, -1.0503007174, 2.2192955017, 0.7662305236, 1.4199377298, -1.1396961212, + 0.6984863877, 0.8586908579, -1.4875825644, 0.1292233914, 3.3051817417, 0.7467623949, 0.8142894506, 0.574416995, + 1.0687381029, -0.8679308295, 0.2648360729, -1.8214925528, -1.5498822927, 1.0336124897, -0.3167379498, 1.6213614941, + 0.0680482686, -0.0182913449, 0.0870022327, -0.7723815441, 1.0164847374, -1.1489291191, 0.3398660421, 0.4741336107, + -0.1662758589, 0.0326907784, -0.3206206262, -2.1174454689, 0.3675934374, 0.3425858915, -0.5936652422, -0.7317870259, + -0.8706053495, 0.3625514805, -0.7185558677, -0.3813236952, 1.6017394066, -0.4086554348, 1.1893210411, -0.3677315414, + -0.8534657359, 0.241965428, -0.260107398, -1.7017725706, -2.0002150536, -1.2726695538, -2.8272268772, -1.3180217743, + 0.269580543, 0.8193210363, -0.0601939671, 0.2057047337, 2.1258807182, -1.0387762785, -1.0656303167, 0.8474498391, + -2.0752680302, -0.7518011332, -1.0824229717, -0.0520494208, 0.867300272, 0.70772928, -0.6896764636, 0.5508205891, + -0.5087099671, -0.7953282595, -0.7552286386, 0.3783166111, 0.1480294019, -0.4080043733, 1.3215683699, -0.2240578383, + -0.9652453065, 1.6936491728, -0.5004338622, -0.4313458204, 1.8143146038, -0.8686926961, 1.2914714813, -0.2357162833, + 1.4363687038, -1.2961885929, 0.1975327134, -0.8971417546, -1.4519535303, -0.4755281806, 1.1832439899, 0.5823754072, + -0.7990812063, -0.1475500166, -1.5841269493, -1.0030679703, 1.5403479338, 0.8109509945, -2.1969048977, -1.9337809086, + 0.9102554917, -0.2021962404, -0.8042155504, -0.3982497156, 2.4267811775, 0.6462002993, 0.5270777345, 0.2776626945, + -0.3879787624, -1.2539374828, -1.0608892441, 0.8798408508, -1.0080276728, -1.2297723293, -1.1807438135, 0.7539607286, + -0.3988789618, -1.207583189, 1.951772213, -0.0741142184, 1.6240398884, 0.2602418065, 1.8968186378, 0.925257504, + -0.6450889707, 1.4229569435, -0.1587112993, 0.8568664789, -1.0669229031, 0.6148740053, 0.7432900667, -2.3107280731, + -0.7096374631, 0.1439763308, -1.7630770206, 0.8053269386, 1.0544917583, -0.2164501399, -1.1995971203, -1.1014965773, + -0.6774827838, -2.0162796974, -1.3040640354, 1.7306530476, 0.4679165184, 1.5393271446, -1.1890480518, 0.1019532531, + -0.9641910195, -0.6676917076, 0.3440614343, -0.2543410659, 0.5562074184, 1.3031641245, 0.3274115324, -2.5846605301, + 1.2806965113, 1.9282523394, -0.1295706928, 0.4334105253, 0.8793066144, -0.5240471959, -0.1192059442, 0.2685222328, + 0.6581997275, 0.3720701039, 1.0289461613, 0.6471891999, -1.3104859591, -0.7705357075, -0.6850705743, 0.2172274739, + 1.480706811, -0.2180891037, -0.677141428, 1.5424208641, 1.0833897591, -2.8045880795, 0.4607556164, 0.787232101, + 1.3725421429, -1.5756440163, -0.3378772438, 1.1134512424, -0.0857403502, -0.7604584098, 2.451726675, 1.1246706247, + -1.8834089041, -0.3396808505, 0.446819365, -1.37545681, 0.2401239425, 0.2437317073, -1.6011885405, -0.6616942286, + 0.3145923913, -0.579811573, 1.6361236572, -0.828322351, -0.0387554541, -1.4568865299, -0.9266756773, -0.6654282808, + -1.0409642458, 0.1891269684, -1.0281019211, -0.6576402783, -0.2294373065, 0.3463232517, -1.1547359228, -1.8444094658, + 0.9560483694, -0.6993877292, 0.3474283516, 0.2573563457, -0.5045565963, 0.6014789939, 0.0792550221, 2.0729916096, + 0.5574637055, 2.2566828728, -0.7126176953, -1.8690760136, 1.1867282391, -1.2382060289, 0.5142056346, 0.9849852324, + -0.9336848855, 0.1257813275, 0.0927541032, 1.397158742, -0.3119037747, -1.1926451921, -1.2881635427, -1.3171620369, + 0.4146163762, -0.4774722159, -0.3868423402, -1.0103545189, -1.1745402813, -0.20919016, 1.3277802467, 1.1256504059, + 0.2741110325, -1.3244829178, 1.5284399986, -1.0842255354, -0.8799241185, 0.4729141891, -1.9505088329, -0.4351518452, + -0.8081485629, 0.3269541264, -0.7062594295, 1.648183465, 0.4895448983, -0.9180828333, -1.4240669012, -0.1890579164, + -0.9585830569, -1.0736232996, -1.2009921074, 0.0086217457, 2.2900185585, 0.9107310772, 0.3459389806, -0.2933109701, + 1.7081165314, 0.7132967114, 0.1095507592, 1.3954622746, -0.0916409269, -0.4428087771, 0.3978556991, -0.9287421107, + 0.6775330901, -2.030949831, -0.2861202955, -1.3187100887, 0.686845243, -0.128017351, 0.3954797983, -1.4868066311, + 2.6867311001, -0.2837397456, -0.4692958593, 0.8649511933, -0.4000707567, -1.3636385202, -0.4336688221, 0.4807041883, + -1.1696223021, 0.4139298797, -0.3658573031, -0.8346003294, -0.6913728714, 0.6472249031, -0.9495275617, 1.0565907955, + -0.1551950276, 0.0402307771, 0.5411900282, 1.9618538618, 0.3323952258, -0.188054353, 0.3495495617, -0.2323200107, + -0.0774672851, 1.1608976126, -0.6110397577, -0.0833180025, 0.5343641639, -0.1402324885, 0.7121111155, 1.1572567225, + 0.6025365591, -0.0661304966, 0.9814050198, -2.0910024643, 0.6004716754, -0.8897766471, 0.5802534223, 1.2903648615, + 1.0397731066, -0.8031101823, -0.8996082544, -0.2524068058, -1.2267825603, -0.9092355967, -1.088965416, 0.8441944718, + 0.8110027909, -0.0405239128, -1.071516037, -0.1124812588, -1.5997368097, 0.142053932, 0.6181820631, -1.480745554, + 0.2736857831, -0.0874448717, 1.4611581564, -1.0566525459, 0.487016201, -0.0450987816, -1.0364639759, 0.7334445715, + 1.5605502129, 0.7317325473, -0.8760612011, -0.3242733181, 0.5894088149, 0.5113537312, -0.2457536161, -1.0911314487, + 1.1978468895, 1.4237911701, 0.2477284819, -0.2938754857, 0.5031723976, 0.0124401199, -0.4126176238, -0.7320761085, + -0.4052883387, -0.2108996511, -0.7781730294, 2.1468038559, 2.6817145348, 0.251696974, -1.082277894, -0.0529402457, + 0.8459635377, -1.2501021624, -1.1299482584, -0.7857146263, 0.1984169632, -1.630825758, 0.9140481949, -0.2152125388, + -0.2536766827, 1.7120695114, -1.6373603344, -1.5643184185, -0.4590578377, 0.4787595272, 0.057751555, -0.8291638494, + -1.4593600035, -1.9532253742, -0.7408310175, 2.6602454185, 1.3658504486, -0.4614217579, 2.1605172157, -1.6152997017, + 0.0586317293, -1.250598073, 1.0217580795, 0.0332866982, -0.1231489927, 0.8719854951, 0.3502269387, -0.3011886775, + -0.3683407009, -1.3110753298, -0.5376300216, 0.3520507216, -1.2554615736, -0.3561529517, -1.4860554934, 2.0891554356, + 0.4023406506, -1.2871041298, 0.4452855885, -0.3306802511, -1.0909045935, 1.2342441082, -1.396856904, 1.2671681643, + 0.3808578551, 0.1622464359, -0.8135055304, -0.2238749415, 0.1271271706, 0.3600368202, 0.1486675888, -0.3422999382, + -0.9236380458, -0.1554073095, 0.7903410792, 0.1860257089, 0.1308351606, -0.2578380704, 1.5718585253, -0.7012122273, + 1.0408076048, -1.0936492682, 0.8577693105, 0.4340395927, -0.2430948913, 0.2685880661, -1.8785663843, 0.9641314149, + 0.3043458462, -0.6693259478, 0.6128401756, -0.5462137461, 2.3161671162, 0.0049466984, 0.0762785673, -0.8627022505, + -0.1909276098, -1.7148029804, 0.8741716743, -1.0369155407, -0.9876949787, 0.0601231158, -0.9681298733, -0.8266518116, + -0.0769524872, -0.5266578794, 0.6762766838, 1.3591698408, 0.6121618748, -0.323361367, 0.0347821042, 0.8331773877, + 1.1339416504, -1.0403983593, 0.1039372236, 0.3434944749, 0.7209177017, -0.6197436452, -0.6891433597, -0.7516368628, + 0.9467796683, -0.263591826, 0.6381617785, -0.5782182217, -0.349732101, 0.9256712794, -0.6284171343, -1.8411649466, + 0.2277844101, -0.4046567082, -0.2888169885, 0.7736723423, 0.7876480222, 0.9130166173, 2.5497612953, 1.3560099602, + 0.5737367272, 0.2998895347, -0.725348115, 1.6977071762, 0.1428591907, 1.6922923326, -0.7899493575, -1.6153711081, + 0.8779649734, 1.6200410128, -0.7291763425, -1.0820019245, 0.7858555317, 0.2406725436, -0.2910236716, -0.0595621802, + -0.4121816158, 0.3560032547, 0.9713022709, -0.3304999173, -1.7688531876, 1.1638083458, -0.9774751067, 0.4061269462, + 1.4668464661, 0.2371457219, -0.1761687845, -0.291249156, -1.8847373724, -0.6073658466, -0.581833899, -0.3286408484, + -0.6674704552, 0.3853674531, -1.2600563765, -0.0117033292, -1.2790175676, -0.0959654301, 2.4882016182, 0.3786404729, + -0.7029803395, 0.7567839026, 0.1165871844, -0.1981320381, -0.4176677465, 0.7999218106, -0.3878305852, 2.3828504086, + 0.4363039136, -0.3107819259, -0.3244489431, 1.2963690758, -0.5949802399, -0.3192541301, 0.118401736, -1.0748354197, + -0.2322329283, 0.0255772974, -0.1782385856, -0.4525050223, -0.9569429159, 1.733569622, -0.5961167216, -0.9838139415, + -1.5097740889, -0.5643052459, -1.0459479094, 2.0024902821, 1.1414196491, -0.7664759755, -1.2552784681, -0.1251813024, + -0.2468750924, -0.2969430983, 0.281127423, 1.1297291517, -0.4285236895, 1.6837493181, 0.1570269614, -1.3796472549, + -0.0221588574, -0.9108480811, -1.4940923452, 0.3765714467, 0.1872464269, 1.0197986364, -0.4883226156, -0.377173394, + 0.0635235235, -0.3010345995, 0.2305924147, 0.3498499691, 0.6820290089, 0.7376207113, 0.2440648973, 0.2061410099, + 1.62315166, -0.4384661913, -1.0267047882, -1.4744080305, -1.1771376133, 0.18270953, -1.0081615448, 1.2591556311, + -0.1388425082, 0.4758206606, -0.2766729593, 0.5053372383, -0.0261183511, -0.1096292585, 0.3588334322, -0.1530779451, + -0.1198340133, -0.2816464007, 0.1439685822, -0.2829401791, 1.0409681797, -0.0788520947, -1.1657164097, 2.2557945251, + 2.0186963081, 0.2609864473, 0.6588216424, -0.0292505622, -3.0369510651, 1.2542692423, 0.5731019974, -0.0044440515, + -0.4187056422, 0.6035118103, 1.539525032, 0.9933514595, -0.5339363813, 0.7204960585, -0.2520633638, 0.1129418686, + 0.3106788397, -0.1949516982, -0.7873948216, -0.9607906938, 0.3240345418, 1.3103933334, -1.2638764381, 1.3863197565, + 1.8211445808, -0.3672892451, 0.4053455591, 1.7521601915, 1.6447889805, 0.7403008342, -0.8374760747, 1.8835134506, + 1.4278148413, 3.0550069809, -1.2181924582, -0.8227337599, -0.1327370256, 0.3542967737, 0.6749712229, -0.3170649409, + 0.9784115553, 0.308668673, -0.1767462045, 0.0843835175, -0.6492677331, 0.3701886237, -2.1043498516, -0.0279286541, + -0.8700038195, 0.6007041335, -1.9832814932, 0.2308917642, -1.3054196835, -0.3247613013, 0.2073209584, -1.3216863871, + -0.1985991448, 0.9323601723, 1.6048812866, -0.0951557308, -0.2890453935, 0.6215823293, -0.0441857241, 0.9499992728, + 1.80838871, 0.1037293598, 0.8567683101, -1.0534691811, 1.965110302, -1.956931591, -0.4348264337, 0.6502805948, + -0.916834712, 1.1094492674, -0.9395704865, 0.8174906373, 0.9895029664, -0.1846548319, 0.4872570932, 0.3263651729, + -0.6341340542, -0.1032819226, -0.734614253, 0.1689246595, -0.1534329206, -1.5958054066, 0.2307239473, -2.1755774021, + 0.4595609605, 1.0350043774, 1.1936333179, 1.2886185646, 0.5671181679, 0.0456784628, 0.4965856373, -0.8134568334, + 0.9582699537, -0.0257120635, 1.0541176796, 0.1182258353, 1.0523356199, -1.8147698641, 0.7733538747, -1.3099697828, + -0.9093947411, 0.5400250554, -0.3680446744, -3.243642807, 0.159474209, -0.6183111072, -0.5293322206, 2.0307416916, + -0.1469859183, 1.3975157738, 1.4203033447, 0.5249443054, 0.7566241026, -1.0997810364, 1.1431112289, 0.855368197, + 1.1881549358, -0.3714130521, 0.1984697133, -0.5287451744, -0.3881629407, 0.8084456325, -1.3102331161, 0.2904533148, + -0.6494663358, 0.3399093449, 2.3053667545, -1.9359093904, 1.729039073, 1.5100733042, -0.2926071882, 0.3544541597, + 1.9625288248, -0.6443831325, -0.4173543453, 1.1030114889, 0.328299731, -0.0072064842, 0.4895175695, -0.5674248338, + 1.6213970184, -0.436298281, 0.3757034838, -0.8909569979, 0.5226764083, -0.6865759492, 0.8143765926, 1.2320840359, + -0.7808359861, 0.0008738514, -0.8514294028, 0.4705692232, -0.333396256, -0.3492262959, 0.2567463517, -1.1781015396, + -0.4792070985, -0.3375956416, 0.8531564474, 0.851788342, -0.1833593547, -0.3668282926, 0.4279274046, -1.133012414, + 0.6293390393, -0.1875369698, 0.1160475165, 2.1682090759, 0.8720598817, 1.434933424, 1.2770864964, -0.1004557535, + -0.5276843905, -0.1601087302, 1.3145697117, -0.0181776304, 0.5276513696, 1.374607563, -0.859161675, 0.015372809, + -0.1448028535, 0.6654556394, -0.8472108841, 1.1001250744, 0.4171614349, -0.0177354254, -1.121669054, 0.7256075144, + 0.1507796347, 1.0267204046, 0.6718088388, 0.2002222389, -0.829731226, -0.810135603, 2.3435692787, -0.4786757231, + 1.0909048319, -1.7758495808, 0.2627611756, 0.2653958797, -0.5927811265, 1.5539902449, -0.9272117019, -0.2532606721, + 0.0267162919, 0.5292546749, 0.3089748025, -0.3464745879, 1.7746504545, 2.9259448051, -0.6218938828, -0.3926011324, + -0.3428994119, -1.1926394701, 1.50499928, -0.8424344659, 0.7986744046, -0.7885806561, -1.1607004404, -0.013504223, + 0.9922061563, 1.9919799566, -1.2437075377, -0.4395283461, -0.5311597586, -0.0297754165, -0.5898804665, -0.7635480762, + -1.5769889355, 1.0587168932, -0.0034756528, 0.1553152949, -1.94551301, 0.2943831086, 1.3622395992, 0.4102196097, + -0.4908825755, 0.4014503062, 0.0278171897, -0.0536309853, -1.2789026499, -1.2796289921, 0.4953480065, -0.4660226703, + -0.9548496604, -0.9615236521, 0.9491387606, 0.3494040668, -0.9034793377, -0.874679029, 0.3864723444, -0.7408620119, + 0.8857078552, -0.9054695368, 0.3242028058, -0.9857577682, -1.77942276, 0.7796273828, -0.2548395693, -0.9350469112, + -0.0115598422, -0.0557284057, 0.4348230958, 1.1245038509, 2.6359810829, -0.2186294347, -0.0949227884, -0.2960619032, + -0.7614319921, 0.6499288082, 0.0611613914, 0.4410744905, 0.7678567767, 0.093086049, -1.0300735235, 0.3483096361, + 0.7597416639, 0.001120927, -1.1556539536, 1.1331659555, 0.9468092322, 0.2521147132, 0.122479409, -0.5496848226, + 1.5198215246, -2.1303267479, -2.2218475342, -2.5806076527, 0.0837756246, 0.4271501005, 0.8224028349, 1.1306557655, + 0.3919700682, -0.0115966676, 0.0475504175, -0.600425303, -1.2305142879, 0.5945131183, 1.0072363615, 0.3247313201, + -1.2197523117, -1.1868721247, -0.9118242264, 0.1778739989, 0.3262349665, -0.8597450256, 0.0205650963, 1.753029108, + 0.7721672654, -0.1331358552, 1.0669914484, 0.861468792, 0.9448447227, 0.4930521548, -1.0212017298, 0.7986354828, + -0.7440475821, -0.194400236, 0.3420980573, 0.5632216334, -2.4997861385, -0.4994763136, 0.6333222389, -2.0620503426, + 0.8145817518, 1.4459090233, 0.9552916884, -0.7975873947, -2.1032149792, 0.0418324843, 0.5111634135, 1.7133549452, + -0.3090857565, -0.605828464, -0.8708721995, 1.2175831795, -0.2389851511, 0.4239602387, -1.5448274612, -0.3783124983, + -0.0029062431, -0.6120293736, 0.2799707651, -0.0570160225, 2.0717158318, -0.3598082066, 1.4251867533, -0.0134970779, + -0.9720110893, -0.225266993, 0.5460293293, 1.5419213772, -1.5147491693, -0.3293933272, -0.0275527146, -0.9521688223, + -0.3834776282, 1.4057289362, -0.7203474641, -0.9101272821, -0.1940222532, 1.3746294975, 0.4223842025, 1.1517481804, + -0.3333800137, 0.0154191507, 2.1487598419, -0.9099595547, 1.2981448174, -0.4607750475, 0.7508655787, -1.1511445045, + 0.685288012, 0.3033760786, 1.1724207401, 0.0635844842, 1.9570583105, 0.8574123979, 0.5666555762, 0.7369867563, + -0.3596095443, 0.071269393, -0.2050676346, 0.7476635575, -1.59793818, -1.6696869135, -0.0033412154, 0.2548270524, + -0.4833313227, 1.0923733711, -0.2952604592, -0.8811125159, -0.4041282833, 1.2807453871, 0.1407522559, -0.2607857287, + 0.8139761686, 0.2080699205, -1.0974228382, -1.0547447205, -0.5768285394, 1.7892030478, 0.470382005, -0.7589623332, + 0.473944962, 0.3060959876, 1.4044001102, -0.4405074418, 1.5767858028, 0.2276372015, -0.0085633667, 0.1122219488, + -0.1186968386, -0.7556450367, -0.2551757693, 0.2367250472, -1.3682280779, -0.0868984833, -0.9292290211, 0.476797998, + 1.2660095692, 0.7017489076, -0.0994677246, 0.4604631066, 0.5536651611, -0.6214803457, -0.1921214759, -0.9230517745, + 0.2861795425, 1.9730838537, 1.5194038153, -0.2218993008, 0.0676458031, 0.8111193776, 0.5127606988, -0.0850184634, + -0.3213681579, -0.2438399494, -0.1359906793, 2.0709638596, 0.3468191326, -2.5300788879, -0.7631182075, 0.219156906, + 0.0090567889, -0.7353634834, -1.5984612703, -2.1198539734, -0.1774644852, 0.7098138332, 0.8213640451, -0.0107929576, + 1.2051004171, 0.0632010624, -0.3080267012, 0.9183343053, 0.0939481556, 0.8973917365, 1.3931572437, -0.2151860446, + -1.0463820696, 1.2186774015, 0.4525365233, 1.2896789312, 0.3542840779, -0.4334890842, 0.0643699095, 0.1865993589, + 0.5796870589, -0.7730751634, 0.4719973505, 1.7717124224, -1.5757242441, 0.2662694454, -0.4041916132, 0.4621180892, + 0.6618397832, 0.1943725944, -0.9175354242, -0.0798297524, -0.7954104543, 0.4863788784, -1.499637723, 0.8618410826, + -2.9106974602, 0.3565086722, 1.5209159851, 0.5370289087, -0.1094295308, 2.1429982185, -2.2595870495, -0.4742313921, + 0.4032390714, -1.3632237911, 2.1153512001, -0.8269336224, 0.4764483869, -0.3866333365, 0.4835948348, -1.0510087013, + 0.9150114655, -1.4388750792, -0.3364607096, 0.0429121219, -0.1839305013, 0.384893477, 1.512820363, -1.140039444, + -1.4442991018, -0.4257532358, 0.835429132, -0.2160586119, 0.9489045739, 0.3786438107, -0.6682091355, 1.0235065222, + -0.838280499, -0.1399486065, -0.9926248789, -1.2264190912, -1.3117069006, -0.1271556914, 0.0079912404, -0.37605685, + 0.5664597154, -0.8595212698, -0.1183861569, 0.8529757261, -1.9854843616, 0.2800190151, -1.7601602077, 0.666497767, + 0.6719502211, -0.7664304376, 1.0983656645, 0.2911262214, -1.1661839485, -0.8158940673, -0.2933756411, 1.4010317326, + 1.6039435863, -0.5165402889, -0.1408138573, 1.1347715855, -0.4194507301, -0.5617449284, 0.5707189441, -0.0715572983, + 1.7359468937, -0.6072747111, 0.2172731906, -1.6416498423, 1.1322650909, -1.7049622536, 0.2442215234, 0.7345991135, + 0.9624508023, -0.70128268, -0.4934635758, 0.2794271708, 1.1199611425, 0.0138948634, 1.3469048738, -0.5083768368, + -0.3632907867, -0.4739925861, -0.8815130591, 2.1984884739, 2.9767618179, 1.0400345325, 0.5973387957, 0.6966767311, + 0.3020858765, 0.7583796382, -0.7667793036, -0.0830394998, -0.6338041425, 0.4115710855, -0.0886307508, 1.4750047922, + 0.6065263748, -0.6084166765, 0.4203138649, -1.1035499573, -0.1466142833, 0.0930199549, -0.434664607, -1.3677084446, + 1.7228507996, 0.7114614844, -0.7142797112, 0.3464543819, -0.612234652, 0.7374718189, -1.223718524, -0.4646267891, + -1.4108309746, -0.4445342124, -0.4988172054, 1.830152154, -0.7865855694, -1.0325416327, 0.3002009392, 0.1759860516, + -0.3930571973, -0.0841103196, 0.6128829122, 1.1748423576, 2.0594334602, -0.1751677841, 1.9157706499, -2.0087039471, + 0.0548449084, 0.9300742149, 0.78661412, 1.1222592592, 0.1036242396, 0.6618089676, 0.0268117934, -1.9981175661, + 0.9294196367, 2.258462429, 1.0756754875, 1.136308074, -0.2930243909, -0.0277448576, 0.8949297667, -1.3616064787, + 0.3977112472, -0.7987060547, 1.2334747314, 0.2763086557, -2.1072409153, -0.2869181931, -1.5621356964, 0.7045946717, + 0.8275618553, -0.4897731841, -1.0612022877, -0.2257146686, -0.4813244045, 0.8550677896, 0.4653412998, -1.9319355488, + 0.0123473499, 0.6307618022, 0.1360304952, 0.3419711292, 0.2482180744, 1.0112982988, -2.8517372608, 1.024230957, + 1.394646883, -1.4900366068, 1.3303142786, 1.1665626764, -0.0065014083, -1.8222254515, 1.113915801, -0.473700881, + 1.4344037771, -1.1761858463, -1.6211301088, 1.0432368517, 1.0384088755, 1.0714992285, 1.5375100374, -0.7071874142, + 0.0438755527, -1.1680675745, -0.113387756, -0.8412772417, -0.7477636337, 0.6549735665, -1.6748837233, 0.1416903734, + 1.8518723249, 0.5723341703, -0.2291723639, 0.4399379194, 0.8588612676, 1.9773676395, -0.4936513007, 0.2287907153, + -1.0384471416, -0.159702912, 0.1248741448, 0.7425230145, 0.551292479, 0.7303834558, -0.8165476322, -0.7640091777, + -0.1144194901, 0.8935913444, 1.6052113771, -1.25388062, 0.2855737209, -0.4613464773, 1.2086780071, 0.4985507429, + -0.340546459, -0.8937238455, 1.2616927624, -0.9317969084, -1.0411241055, 0.8100412488, 0.7059498429, 1.3697428703, + 0.909473896, -1.9717726707, 0.242030561, -0.9077606201, 1.6671775579, 2.3022015095, -0.179051131, 0.8325935602, + 1.3162128925, -0.2899599671, -0.4036357999, -1.3132460117, 0.1316954643, 0.9602703452, -0.1307659447, -1.0357890129, + 0.583243072, -1.4192433357, 1.2996268272, -0.1998086125, -0.6707410812, 1.8675396442, -0.2962323725, 0.9742482901, + 0.261175245, -0.143778041, -0.6985815167, 0.62979424, -0.907771349, -0.3890576065, 0.4322726727, 0.1401295662, + -0.0165128782, -1.402230382, 0.3342009485, -0.0561159886, -1.207624197, 0.026958514, 0.0797272325, 0.1862457544, + -2.2476606369, 0.9444752932, -0.2633162439, 0.5973744392, -1.3259795904, -0.436987251, -0.6111346483, 0.461946696, + 0.1574052423, 0.4900255203, 0.1863169968, 0.2730141282, 0.0945252627, 0.6730496883, 1.2070502043, -0.7237103581, + -1.586427331, -0.5616668463, 0.8356405497, -0.0633497909, 0.1185418442, -2.5133163929, -0.2127508223, 0.9225611091, + -0.4511755705, -1.3210129738, -1.503885746, 0.3074418604, -1.4114911556, -0.9896835685, 0.4621183872, -0.1546157897, + -1.0632112026, -0.6646524668, -0.2710254192, -0.0559235252, 0.2106004804, 0.3330169618, 0.211570397, -0.1708970219, + -0.2765752971, -0.3595123887, -2.1213698387, -0.0695509166, 0.9423075318, -0.6175131798, -0.557375133, 0.0207770932, + 0.8922007084, 0.4503358305, 0.0453439653, -0.9838991761, -0.1429029554, -0.01011544, -0.3242063522, 0.8762276173, + -0.1310543418, -1.3132834435, 0.1048069224, 0.9953035712, 0.0019832081, -0.5763996243, -1.5993032455, 0.2357865274, + -0.5236660242, 1.2498191595, -0.3972760141, 0.5428637266, -0.3759145141, -1.0959819555, 0.4462662935, -0.4387346506, + -1.1529084444, -0.0285182241, -0.1020001173, 0.5932555795, -0.5795496702, -1.0888371468, -1.7439676523, -0.2361356318, + -0.0777337477, 0.739438355, 0.0782520548, 1.6987942457, 1.7381364107, 1.1641181707, 1.4951943159, 0.1576152593, + -0.6602454782, -1.6606831551, -1.8109960556, -1.5184327364, -0.6278802752, 1.0903507471, 1.0761795044, 1.2518355846, + -1.6058274508, -0.3573199511, -0.9369678497, 1.4489934444, -0.0281910524, 1.0515197515, 1.3035051823, -0.79085356, + 1.5493855476, 0.1785422266, -0.2503399253, 0.544200182, 1.4513047934, 0.2108101994, -0.7557499409, -0.86264503, + -1.3776224852, 1.0434657335, 1.1152778864, -0.5381469727, 1.1608798504, -1.1071029902, 0.7692725062, 1.7361100912, + 0.6548727751, -0.2329286039, -0.2109164447, 0.8669708967, -0.5419610739, 0.3878645599, 1.0662782192, -1.9696036577, + 0.895776391, 0.0708186775, 0.845390141, 0.0108403713, 1.4044237137, 0.6272301674, -0.7871339321, 0.7302926779, + 0.5642443895, -2.1129529476, -1.1371386051, -0.0070197177, 0.9867774844, 0.0979930758, 0.2202437371, -0.3924337029, + 0.5245616436, 0.968475163, -0.3208032548, -0.6954401731, 0.2925103903, 0.6001781821, -0.2031298876, 2.566421032, + -0.7845811844, -0.0679450184, 0.0334720835, 1.3929741383, 1.5113071203, 0.2075864077, 0.6620129347, -0.64526999, + 0.7408705354, -1.7304400206, -0.1776096076, 1.555316329, -0.105694063, -0.6364824176, 1.532774806, -0.9357856512, + -0.2761799097, 0.4746173322, -0.8172100186, -0.6547473669, 0.5243036151, -0.0618794486, -0.2851223946, -1.0006905794, + 0.787664175, -0.8730727434, -0.6232350469, 1.6723668575, 0.5514597893, -1.053303957, -0.3889478743, 0.4371635914, + 0.9450132847, -2.1121516228, 0.7922255397, -0.3742645383, -0.1040292904, -0.1706566215, 0.8582338691, -1.1603547335, + 0.6076740623, 0.9498484135, -0.8680899143, -0.8084941506, -0.50087291, -1.4534268379, 1.1655235291, -0.9484149814, + -0.0762682483, 0.0358931646, -0.2384106368, 0.9499883652, -0.9772548676, -1.0445420742, 0.1405598968, 0.5456544757, + -0.5860677958, 2.0359721184, -0.7959108949, 1.8235174417, 1.8872886896, 1.1418535709, 0.3126354218, 0.3064375222, + -0.2798117399, -0.4689850807, -1.6476761103, -1.5992029905, -1.2629358768, -1.754114151, 1.169588089, -0.0457241274, + 0.4733829498, 0.0854842886, 2.0468397141, 0.2154959887, 0.0350889787, 0.2971332371, 0.9285229445, 0.9239901304, + 0.4604280591, -0.5467797518, 0.4883889854, -0.9885988235, -0.5728197694, 0.9264045358, 0.781080544, 1.0949702263, + 0.1750663072, 1.4096968174, 0.2180642933, 0.7436999083, -0.1266501397, 1.356618166, 0.3130574524, 1.2390726805, + -0.1934143156, -0.7612330914, 1.0759313107, -0.3289625347, 0.1660896689, 0.0740403831, -1.1717393398, 1.1129521132, + -1.1576689482, -1.7789555788, 0.9600282907, -0.7468833923, 0.5374038219, 0.9328088164, 1.5861493349, 0.8423115611, + -0.405275166, 1.0446491241, 0.0374817997, -1.1891011, -2.3277878761, 0.3875864446, 0.2966091335, -2.2180492878, + 1.0663291216, 0.2598075867, 1.9161059856, -0.728261888, -0.6266215444, -0.673997581, -0.6415785551, -0.6179529428, + 0.604726851, -0.2844314575, -0.4305409491, 1.9450337887, -0.1466508955, 0.4638362825, 2.053699255, -1.2035881281, + 0.2433279604, 0.322644949, 0.2997124195, -2.02409935, 1.5049318075, 2.5287919044, -1.6473007202, -1.8275324106, + 0.7434623837, 0.30668661, -1.1217963696, 1.3457329273, 0.634057045, 1.1217298508, -0.0488672554, -1.2668669224, + -0.4204682112, 1.2064194679, -0.1509321928, 2.8461978436, -0.0451924764, 0.4221574366, 1.7345610857, -0.5981693268, + 0.7031428814, -0.0062330775, 0.8340855241, 1.6620643139, -2.1220414639, 0.2365728617, -0.151655823, 0.5030402541, + -1.7541236877, 1.396024704, -1.2516578436, 0.9715057611, -0.1300617158, 0.2552434802, 1.9452192783, -1.0372388363, + 0.5538521409, -0.3709153831, -1.3116137981, 0.6361788511, 0.9690408707, -0.9008204341, -1.6484543085, -0.0956472978, + 0.321606189, -0.4470887482, -0.7181816697, -0.456474185, 0.0436974354, -0.8783827424, -0.2153731734, -0.7284212708, + 0.0316979624, 0.5592319369, 0.3584336936, 0.3528334498, 0.7266294956, 1.2041256428, 0.6806427836, 0.3226889074, + -1.6938356161, 1.0152925253, -1.2883669138, 1.5473442078, -1.6940101385, 0.7440575957, 0.5449872017, -1.5002492666, + -1.1375263929, 0.4404759109, -0.9481218457, 1.061839819, 0.3651114106, -0.1956363469, -0.0600685142, 0.2220172286, + -0.2049867213, 0.7872170806, 0.5148497224, -0.4739772379, 1.0607751608, -2.2600011826, -0.2448202819, -0.5458866358, + -1.6628972292, 0.6307308674, 0.6686230302, -0.8363482356, -0.5782997608, -0.6807925105, -0.1028094068, -0.3188337684, + -0.2476856112, -0.8180071115, 0.1356047243, 1.5968712568, -0.8921045065, 0.7458104491, -1.2947020531, -0.0416521616, + -1.527349472, -0.4211159647, 0.4188219309, 0.0392890759, 0.6555977464, 0.9114678502, 0.3619571626, -0.5588787198, + 0.2664752603, -0.3256011307, 2.4297068119, -0.5743183494, 0.2944850326, 0.9484425783, 0.9825353622, 0.3974099755, + -1.0577732325, 0.6464989185, -0.202670753, 0.3146737516, -1.5660982132, -1.009305954, 0.9294809699, 0.9666360021, + 0.3079728484, -0.065880239, 0.5567436218, -0.4141434431, -0.9001114368, -0.2555243075, 0.4303688407, 0.6368939877, + -0.3189966381, -0.176717788, 2.1670389175, -1.1297926903, 0.06418363, 0.1511009932, -0.8907510042, 1.969088316, + 0.8412009478, -0.9752152562, -1.5275386572, 1.0577732325, 1.3252483606, 0.8089088202, 1.4796154499, -0.2566390634, + -1.3153479099, -0.8288609982, -0.2103146762, 0.1020352095, 0.92536062, 1.2352576256, 0.52936095, 0.4743773043, + -0.8591988087, -0.1014773473, 0.5960752368, -1.3404738903, 1.1582435369, 1.2524724007, -0.6086274385, -0.7040278912, + 0.8515852094, 2.5486783981, -0.6445094943, 0.4089204371, 0.3661203384, 0.1784386188, -1.1837905645, -1.6509048939, + 1.114566803, 0.2557139695, -0.0395323709, 0.0242085606, -0.4647791684, -0.2464168668, -0.5249590874, -0.0612839907, + -0.1260320395, -1.0659192801, 0.7829201221, 1.197508812, -1.8215229511, 1.2382860184, -0.5807151198, -0.2608066201, + -0.0539864413, -1.5416053534, 0.771429956, 0.5916702747, 0.5156317949, 1.1404858828, -1.3494912386, 2.1378667355, + 0.3047274649, 1.2195792198, -0.357860148, 0.0984548479, 0.721251905, 2.6335790157, -0.4315360487, 0.5843237042, + -0.0755212381, -0.2289883345, 0.9112005234, -1.0294852257, 2.1142601967, 1.0679942369, 0.5550442338, -0.1199776754, + 0.5793484449, 1.8686089516, -0.6061916947, -0.0292256158, -0.1874776036, 0.4629638493, 0.4734807909, -1.0361982584, + -2.4138829708, -1.133038044, -0.530693531, -0.6419487596, -0.5470802188, 0.164369598, -1.6450990438, -0.2671853602, + -0.1303537935, 0.0227936525, 0.9756251574, -0.0457911752, -0.4323091805, -1.259914875, -0.1694476306, 0.4077905118, + 1.0774275064, -1.1228400469, 0.2199149877, 0.4889201522, -1.2091072798, 0.4924613833, -1.7255488634, 0.9194186926, + 1.4995775223, -1.0543442965, 0.4016973972, 0.9137138724, 1.4287455082, -0.7213507891, 0.5033758283, -1.1633116007, + -0.7225621343, -1.4303677082, -0.2655269504, -0.8245450258, -0.6388269663, 1.198040247, -1.7719768286, -0.5820679665, + 1.0126674175, 1.2914206982, -1.1844006777, 0.3093956411, -1.2403331995, -0.4625792503, 1.7663393021, 0.6885182858, + -0.1327944398, -0.8755931854, -1.5265610218, 0.2222946286, -0.3382628858, 0.616719842, -1.0755565166, 0.0484146737, + -0.9836882949, -0.3923490345, 0.5466002822, -0.3768848777, -0.7443243265, 0.3661516309, -0.1037210673, -0.6928908229, + 0.7701465487, -0.2680769861, -0.1214702353, -0.621366322, 0.2482643723, 1.5134902, -0.0739834234, -1.4493509531, + 1.1660684347, 0.1881067455, -1.2092013359, 1.274297595, 0.3987053037, 0.3768714368, 1.41386199, -0.8284464478, + -0.0801821947, -1.1233460903, -0.691812098, 0.5208147764, -0.0682908595, -0.9105952978, 0.1875498742, -0.5142341852, + -0.52749753, 0.7494561672, -0.715203166, 0.431019634, -0.4823740721, -0.251013726, 0.1944553405, -1.3107248545, + -0.1923373193, -0.1888710707, 0.2006835639, 0.8063291907, 0.7279618979, 0.2301612198, 0.502204299, -1.660076499, + 1.0828719139, 1.8728606701, 0.6034314036, -0.4063622355, 0.0974950045, -0.899753809, -1.5935285091, -1.0190300941, + 1.062990427, 0.0831695795, -0.4738741815, -0.448551476, 0.341629684, -0.1248249412, 1.1692199707, 2.2329859734, + -0.3595784605, 2.1218981743, -0.0728280321, 0.4060373604, 0.5449692011, 0.8206561208, -0.4518414736, 0.2907862067, + -2.1724636555, 1.1614646912, 2.5593364239, 0.7427705526, 0.9906321168, 2.0261092186, -0.0148052406, -0.2360571027, + 0.0363243632, 1.2760270834, 2.2971293926, -1.1610804796, -1.7893850803, -0.3227211535, -1.877948761, -1.3441138268, + -0.8956089616, -0.0985141471, 0.4440960586, -0.9870734215, -1.173309803, -0.4680004716, 0.035509631, -0.9436638355, + -0.1876551807, -0.2832317352, 1.1657112837, 1.5924739838, 1.032859683, -0.4097533226, -0.4622452855, -0.5567474961, + 1.1893956661, -0.358957231, -0.817184031, -0.3599012196, 0.5284134746, 0.6601926684, -0.2853067815, -1.5502932072, + 0.678314507, -1.3337225914, 0.999574244, -0.2768847942, 0.7775377631, 0.6332675219, -0.1205610335, -0.9084852934, + -0.1494361758, 0.346765399, -0.8398606181, 0.4216800332, -2.1474878788, 1.0741838217, 0.5535035133, 1.4500633478, + 0.596211195, -0.3862569332, 1.0310724974, -1.6946784258, -0.474883765, 0.9095218778, 1.2876939774, -1.8530343771, + -0.6701546907, 1.8218663931, 0.648442626, -2.14534235, 0.1260983646, 0.6405251026, -0.1364991963, -0.579033196, + -1.1921503544, -0.0568375923, 0.2709504068, 0.9835256934, 0.8560069799, -1.0371228456, 0.175641343, 0.4604872167, + 0.1207154393, 0.0869964808, 0.109909229, 0.77367872, 2.4697232246, -0.8884851933, -1.8836847544, 0.403322041, + -0.9149255157, -1.0660659075, -0.1941040903, -0.9507152438, -0.6525584459, -0.2845203578, 0.5010703206, -1.1385391951, + -2.5650165081, -1.0482982397, 0.7601513863, 1.0343254805, 0.1622663587, 0.4804539382, 0.4948939681, -1.1310155392, + -0.4456132054, -0.0148028927, 0.6583849192, 0.870546937, -1.4775637388, 1.5122822523, -2.5054395199, 0.6433568597, + 1.1670595407, -2.4150571823, -0.7000072002, 0.452010721, 0.2669504285, 0.0745046884, -0.096190311, 0.8950932026, + -0.0153444046, 2.3216211796, -0.0087271752, -0.7285081148, 0.8591826558, -0.0213805623, -0.9274692535, 0.8245937228, + -0.0500126071, 0.9498620033, 0.093976438, 0.2396673709, 0.3366479874, -0.0664266646, 1.4263436794, 0.2282274365, + -0.6703722477, 1.6196011305, 1.5359443426, 0.8145934343, 0.0678382739, 0.0837390274, -0.2199727595, -0.4387906492, + 0.320017457, 1.2475085258, -0.4494763911, 1.463516593, 0.7197579145, -0.1485113055, 0.0235467963, -0.0737998858, + -0.1217009351, 1.1287385225, 0.3565534651, 0.0661123544, -1.4903062582, -0.1748026311, -0.3600355685, 0.48828578, + 0.7067445517, 1.7316313982, -1.5993480682, 1.1871122122, 0.0806279257, 0.1233804226, 1.4097801447, 0.0073844674, + 0.4032472372, 0.1401428878, 1.4815948009, -0.3940936625, 0.9161916375, -0.1888489723, -0.2546358109, 0.1415531337, + 0.2554948926, 0.5829980373, 0.5339160562, 0.1090676412, 1.0032021999, -0.1615457684, -0.6464024782, -0.5283038616, + 0.3620505929, 2.9733176231, -1.0681328773, 0.7487841249, 0.8224366307, 1.5359381437, 2.7004611492, 0.6946715117, + 0.9688691497, -0.2185768485, -1.7118986845, 0.6170027852, -1.4078933001, 0.2380145192, 0.9218633771, 0.8282817602, + -0.2167852372, 1.2319794893, 1.195389986, -0.7662591338, -1.2329901457, -0.6564483643, -0.7983369231, 0.4234818816, + 0.4227693379, 0.366274327, 0.3555461764, 0.3225057721, 0.0377100483, 0.718554914, 0.127601251, -0.843091011, + -1.1099169254, -0.707765758, 0.988333106, -1.2329790592, -1.648340106, 0.0518403128, 0.427654177, -0.2361366451, + 1.1640164852, 1.8784108162, 1.5808711052, -0.7807156444, -0.8628751636, -1.4693769217, 1.1178039312, -0.8612729311, + 0.3775274754, 0.0553550571, -0.2481898218, 1.1510961056, 1.4155236483, 0.4141672552, -0.1486062407, 0.1500177085, + 0.7754682302, 1.1698340178, 1.0434730053, -1.381114006, 0.4370983243, 0.5352761745, -1.8544534445, 1.2646948099, + 0.2929232419, 0.0995730236, 1.7987678051, 1.3470214605, 1.2089182138, 0.1961900741, 0.1137968972, -1.6796602011, + -0.0636957809, -1.4094570875, 0.2016211897, -0.8527985215, -0.3630916178, 0.8872061968, -1.0532958508, 0.364942342, + 0.8411453366, -0.3478016555, -0.1131411865, 0.4069535732, 2.3565943241, -0.6662643552, -0.9734390974, -0.6908809543, + 0.9773233533, -0.1573923081, -0.7164798379, -0.4443368018, -0.1431108266, 1.3523162603, 1.8951483965, 0.3178819716, + -0.5887733102, 0.873277843, -0.6213280559, -1.3105956316, -1.8258597851, 0.3260253668, -0.9911643267, -0.7561984658, + -0.2424144, -1.440669775, -1.8866000175, -0.4525777102, 0.4981562197, 2.9362752438, -0.4877498746, -1.0544553995, + -0.3383483291, 1.2915300131, -1.2027258873, 0.3907198012, -0.0700768232, 0.8171388507, 2.8624243736, 1.7433649302, + 0.0142839653, -0.7587402463, -1.0983080864, -0.1429131776, 0.9946195483, 0.2118909806, 0.2142890394, 0.7555453181, + -0.7680301666, -0.7556154132, 0.1945812553, 0.9759526253, 1.1216096878, -0.0747907311, 0.7729748487, 1.2828271389, + 0.241437614, 1.2615263462, 0.637981236, -0.4018948674, -1.706985116, -0.4766686261, 1.3859781027, 0.9483999014, + -2.443584919, 0.9283960462, 0.1634889543, -0.3825234175, 1.8444286585, 0.219479233, -0.9868534803, 0.5217725635, + 1.04953444, 0.8497440219, 0.6917409897, 1.0312966108, 1.2406227589, -0.3547858298, 1.9061973095, -0.724198401, + 0.4865470529, 0.6772283316, -0.7669066787, 0.3942653239, -0.8978323936, 0.8897718787, 0.2239701748, 2.4911932945, + 0.3996796012, -0.5503692627, -0.8688344955, -0.4812298417, 0.0351235606, 1.981366992, 1.5126305819, -2.0804917812, + 1.2661659718, 0.0236697476, -0.6080989838, -0.9334201813, -1.1945544481, 2.2148840427, -0.0787384063, -0.4709452689, + 0.3463014662, 0.2351722717, -0.6441224217, 0.7173498273, -1.0471272469, -0.9710624814, 0.3333386481, -0.0502374433, + 0.0522217862, 0.7412327528, -0.9452767968, 0.4947839677, 1.9146962166, 0.4911620319, 0.6288027763, -0.2933082283, + 0.0901089683, 0.7404099107, -0.1309597939, -1.9170587063, 1.629363656, -1.7506906986, 0.475815028, -0.6292086244, + -0.1218387485, 0.2569647133, -1.7762563229, 1.1726000309, -1.1609822512, -0.497337997, 1.3849647045, 0.2108934671, + 1.750107646, 0.1977767199, -1.506114006, 0.2052410543, 0.8849083185, 1.0420837402, -1.5378690958, -0.9945856929, + 0.3950080276, -1.1667097807, 0.7336266637, 1.0541245937, -0.760473907, 1.0298671722, 0.4831345081, -0.9305076599, + 2.3098583221, 0.8978148699, -0.7780020237, -0.0763000399, 0.1405724138, -0.9309204221, -1.2948073149, -0.9992104173, + -0.7626069784, -1.194647789, -0.0887558684, -1.1694561243, 1.418192625, -0.5647112131, 0.1377933472, -0.8132561445, + 1.978047967, -0.2693868876, 2.5489280224, -0.4812024236, 2.1438763142, -0.6436809897, -0.2257929593, -0.1043324471, + -0.0241426136, 0.3608437479, -1.313233614, -0.2473047823, 1.967900753, -0.0772148073, -2.0944638252, -1.268985033, + -0.3390084207, 0.0193167645, 1.2736999989, 1.4182841778, 0.7875558734, -0.5130640268, 0.07682731, -0.978646338, + 0.2218512148, -0.9420463443, -0.2778419554, 0.2273272276, -0.4655575454, -1.0925114155, -0.1088153049, -0.8575080037, + -0.7718771696, -2.1138706207, 0.1061449572, -1.2214846611, -0.4387984276, 0.652520299, 0.7284477353, -1.1624752283, + 2.0951714516, 1.4666159153, 0.5122377276, 1.6254560947, 0.5767518282, -1.4740482569, -0.3197341561, 0.0622204207, + 2.2914700508, 0.5785361528, 0.5546657443, 0.7368097901, -0.2011972219, -0.3459620476, 1.4479689598, 0.7183705568, + -0.7114289403, -0.244543612, 0.9475785494, 0.1670360416, -0.1054515019, 1.5192409754, -0.2389630973, -0.3069087863, + 0.3849918544, -1.9849205017, -0.8939456344, 0.1685190648, 0.6565925479, -1.5131690502, 0.348737359, -0.4754433334, + -0.5820451379, 0.9503807425, -0.6067024469, 0.4588730037, 1.6100572348, 0.5035930276, 0.4674057364, -0.3812543452, + 0.4779359996, 0.5542572141, 0.8604867458, -0.0800580233, -0.5947277546, 0.387737304, 0.9289138317, -2.036952734, + 0.8429705501, -0.8200830221, -0.3597954512, 0.1188161224, -0.8078942895, -0.6227641106, -2.1208841801, -1.0918895006, + -1.2143417597, -0.9062018991, 0.2425887883, 1.0418492556, -0.8915598392, 1.4448651075, 0.5658872128, -0.6691966057, + 0.0779437646, 0.3703321815, 1.0202715397, 0.5159808397, -0.3667911887, 0.1917651892, -0.015597295, 0.6114939451, + -0.5516857505, 2.0143985748, -1.4417407513, 0.1094853356, 1.6910899878, -0.5058087707, -0.2841334641, -0.4427628219, + -0.779877007, 0.318493396, 1.5184088945, -0.3982077539, -0.3256989717, -1.9115608931, -0.4265502393, 1.9067032337, + -0.579580307, -0.946416676, 0.1618944108, 0.2046693861, 2.7043745518, -1.1141778231, -0.2270487696, 0.067758888, + -0.8169810176, -0.0516205356, 0.2156272531, -0.0458132848, 1.1395378113, -1.9288947582, 1.0327042341, -0.6658371091, + -1.0002037287, 0.7938078046, -0.5091620684, 1.1180939674, -0.8911152482, -0.6446077824, 0.1085245833, 0.1545051485, + 0.7162056565, 0.0998768061, 1.546305418, 0.339273423, -0.1677765995, 0.0178067535, 2.2100381851, 0.1243686378, + -0.4336081743, -1.1434708834, -0.2915322185, 0.2938709855, 0.1741888076, -0.9570773244, 0.2976694703, -0.8821976185, + -0.0567142293, 1.8015016317, -0.0966258571, -0.874427557, -0.3556698859, -0.2422062755, -0.008815717, 1.0579258204, + 0.6251289845, 2.1922950745, 0.8293181062, 1.1037898064, 0.116175808, 1.3735295534, 1.8517149687, 1.2776745558, + 1.1805377007, -1.1309832335, -1.4316225052, -0.7249827385, 0.4579662681, -1.0276892185, -0.9429395199, 0.7407530546, + -1.1371870041, 0.8070212007, 0.8429144025, 1.3206818104, 0.6324065924, 1.9122589827, 1.9089622498, 0.9503044486, + 1.8724390268, -0.3448031545, -0.064375706, 0.5141147375, -1.0741199255, -0.6546777487, -0.2585322559, -0.4660071731, + 0.212321043, -0.68284446, -0.3794018924, 1.5062401295, 0.1076194942, 1.1968497038, 1.3637975454, -1.5723030567, + -0.2526699901, -0.8103145957, -0.7729591131, -0.3791863918, -0.5915085673, -0.0657836497, 0.5478895903, 1.4897552729, + 1.2893457413, 0.3316682577, -1.2735449076, 0.3352213204, -0.1605404168, -0.6274160743, 0.0444982313, 0.4427059889, + -0.1887391508, 0.0424868092, 0.6873580813, -0.5684332252, -1.8209024668, -1.5618481636, 1.1418203115, -0.1679338664, + -0.1575482935, 0.8625968695, 1.7374920845, -0.6851282716, -0.7020391822, -0.5403820276, 0.0701741204, 0.6840214729, + -1.0883448124, -1.0662660599, 0.3783966303, -1.280700922, -0.6299644113, 1.1646709442, 0.6178892255, 0.2659975588, + 0.5481295586, 0.862960875, 0.3323490322, -1.7330682278, 0.717028439, 1.3835469484, -0.1560150534, 0.6267575026, + 0.0135885328, 0.5174806714, -1.3381071091, 0.2403987944, -0.6325420737, -0.3140203655, -0.5688653588, 0.0899808258, + 0.2951270342, -0.3967520297, 0.8154203892, 0.6676385403, -1.0550323725, -1.7451119423, 1.2019145489, 0.8572792411, + 0.5403226018, -0.3976074755, -0.5785681009, -1.1575276852, -0.7872358561, -0.7130684257, -0.6214036942, -1.0228501558, + 0.0767670125, -0.4886718988, 1.1801239252, -0.2055412382, -0.6231933236, 1.3826036453, -0.8254976273, -0.2961417437, + 1.4713494778, 0.2379731238, 0.8579406738, 0.3441528976, -0.5790320039, -1.0394935608, -0.3038409948, -0.4149534404, + -1.0315365791, -1.7151025534, -0.5805560946, 1.2495222092, -1.4802988768, 0.2671444416, -0.6707246304, -1.2410545349, + 0.1354297549, 0.9997917414, 0.4972026944, -1.0840744972, 0.6837875843, -0.3927797079, 0.3305899799, 0.6962628365, + -1.0900052786, -0.6791628003, 0.3703728318, -0.3813745379, -1.293976903, -0.4187581241, 0.2346390933, -0.2559554577, + -1.0008970499, -1.3414121866, -0.4729372263, 1.4051200151, -1.5527420044, -1.2766270638, -1.0660550594, -0.5740276575, + 1.2553514242, 1.3542720079, -1.4046258926, 0.3287573159, -3.0902717113, -0.8251926899, 1.3747756481, -0.5134324431, + -0.0683978125, -0.5844672918, 2.312271595, -0.1144952849, -0.1771259159, 0.6621459126, -0.9766175747, 0.9550002217, + -0.2011980265, 1.0007474422, 0.2201173604, 0.5645438433, 0.1237144545, -0.7314903736, -0.0032809498, -0.6201736331, + -0.3656804562, 0.4783496261, -0.1402065754, -0.8107504249, 0.4245607853, -1.9665911198, 0.0242772475, -0.2220647484, + -1.0378764868, 0.8202825189, 1.1987079382, -0.349814713, -0.120822832, -0.764495194, 0.0111101391, -0.5653514862, + 0.5157155395, 1.1558949947, 0.1688937247, 1.6910996437, -0.8339630961, -0.7835124731, -0.0265033338, 0.7289951444, + -0.0396559015, -0.6672050953, -0.9940689206, -1.0564441681, 0.9359007478, -0.748372674, 0.7249618769, 0.759308219, + 0.7683255076, -1.2546075583, -0.12015488, -0.1855690032, -1.3772150278, -1.6465450525, -0.4068576992, 1.6283794641, + 0.1573139578, -0.450879246, 0.4044491053, -0.5097197294, 1.2035160065, 0.4231516421, 1.4437040091, -0.1109154448, + 0.2013794035, -1.0002640486, -0.312107712, -0.6141272187, 0.1143021211, -0.3780872822, 1.004653573, 1.850874424, + 0.5487187505, -0.7260112166, 2.1805567741, 0.3423650563, -0.8168572783, -0.4555746317, -0.3628090918, -2.2633161545, + -0.6448135972, -0.7452431321, 0.2334146351, 0.8234783411, 0.5006471276, 0.4734275937, 0.6055223942, 0.5627831221, + -0.4720727503, -0.1004450172, -0.2453504503, -0.3004291356, 0.2103607357, 0.8166112304, -0.9881518483, 0.6973307133, + 1.4465472698, 0.7168634534, 0.5701670647, 0.9973092675, 0.7807003856, 0.0557702519, 0.896476388, -2.2280788422, + -1.1141041517, 0.7094801664, 1.4749150276, -0.1043331474, 1.5968731642, 0.6388558745, -1.866484642, -0.9645528793, + -1.4716819525, 0.1554246396, -0.7584255934, -0.612917006, -0.1678290069, -0.2931369245, 0.8345580697, 0.4046899974, + -0.2836818397, -0.1639537364, -1.3903989792, -0.4709609151, -0.1503601223, -0.4822956324, 1.0982751846, 0.771007061, + -0.7754664421, -0.2240831107, -0.0304530412, 1.0826807022, -0.5305797458, 0.6023666263, -2.1382906437, -0.0566323511, + 1.1664443016, -0.7720962763, -0.908987999, -0.4142166376, 2.5208303928, -0.1248839349, 0.0180679932, -0.9986228347, + -1.2627335787, -0.565106988, -0.4552381933, 0.5557269454, 0.9943681955, -0.2865622938, -0.5457049608, 1.6967656612, + -0.5081860423, 0.0036205626, -1.018514514, 0.2515618503, -0.3381818235, 1.0141428709, -0.5825280547, 0.6387898326, + -0.3677871227, -0.5683578253, -0.7212477922, 0.1982797086, -0.2174220383, 0.9147565365, 0.44375664, -0.3062036335, + -0.9490559101, -0.4480834901, 0.4285705388, -0.1649990529, 0.8649626374, -0.6476624608, 0.7200577259, -0.3377147615, + -2.0285484791, 0.7261819839, -1.1678304672, -1.2852076292, -0.4837974906, 1.2880570889, -0.1298787147, -0.1980783939, + -0.3344875872, -0.391443193, -0.6124061942, -0.6765239835, 1.327229619, -0.448695451, -0.3164072931, 0.0308305565, + -0.3133567274, -0.1732591838, -0.3273687065, 0.9443682432, 1.1220173836, 0.1123387292, 1.3723402023, 2.0625617504, + -2.4485590458, -0.5619884133, 0.3550988138, 0.6343781948, -0.3924500942, -0.813156426, -0.232873261, 0.2468012124, + -0.5624132156, -0.8416020274, -0.9421200156, 0.9453729987, 0.1409107, 1.7535657883, -0.3472236991, -1.4894933701, + -0.5080354214, 1.992650032, 0.5554619431, -1.6960769892, 1.7523661852, -0.5975508094, -0.4664914012, -1.0947922468, + -0.6454249024, -0.2021548301, 0.2050734758, -0.2703858316, -0.3102994859, 0.3622126877, -1.8181655407, -0.1004303396, + -1.0705139637, -2.0765106678, 1.7234400511, -0.1522772014, -0.3638286889, 0.3420642316, 1.4070423841, -1.3161656857, + -2.1506977081, -1.5808782578, -0.3616223037, 1.1524333954, -0.4334156513, 0.7738724351, -0.8342115879, -0.7282395959, + 0.674975276, -0.4777715802, 1.4923013449, -0.6583909392, 0.5604837537, -0.5135775208, -0.4712557197, 1.6082854271, + -1.3844133615, 2.2784225941, 1.3843681812, -0.9408109784, 0.0214956999, 0.1947668046, -1.2912441492, -0.3801298738, + -0.8062320352, -0.7280040383, -1.0826486349, 1.0985850096, 0.1326422393, 1.8456447124, 2.1873707771, -0.7083841562, + 0.6465144753, -0.5518972278, 0.2373841107, -0.0164395105, -0.0291097742, 1.6453253031, -0.5479516983, 0.1853130013, + 0.6488700509, -0.3811258376, 0.0817243606, 1.0087109804, -1.1935225725, 0.2637767792, -0.899497211, 0.3363832235, + 0.271378845, 0.5522467494, -0.6908838749, 3.2648844719, 1.3637685776, -0.5434085727, -0.8160778284, 2.593952179, + 0.5945166349, 0.0170803964, -0.8449776769, -0.8151623607, -0.6342274547, 0.906657815, -0.6744567156, 0.2777738869, + 0.2134030014, -0.6038596034, 0.5620812774, 0.4132402539, -0.9826997519, 1.071510911, 0.4687927365, -0.1042525694, + -0.4841112792, -0.229617998, 0.9663137794, -0.5415360332, -0.3242196739, -0.0827071369, 1.367410183, -1.2061275244, + -1.1793091297, 2.2461023331, -1.5597070456, -0.7396000624, -0.1240326911, -0.0979401693, -0.8028639555, -0.961119771, + -1.2690706253, -1.4909585714, 1.5873177052, 0.121660836, -1.4530825615, 1.1822804213, 0.60365659, 0.6341340542, + 0.6647869349, 1.0432860851, 0.1756239235, -0.1246411651, -0.0421862118, 0.787335813, 0.0727108419, -1.8087786436, + 1.8381971121, 1.0782800913, -0.3556542397, -0.9404379129, 1.1988965273, -0.3806185126, -1.193952322, 0.2033593506, + 1.0147236586, -2.7281723022, 0.7938317657, 0.1125748605, 0.5684316754, -0.6089876294, 0.2789086998, 0.9851705432, + 1.7537573576, 0.2681056559, 0.8519150019, 2.4660148621, -0.298948735, 0.0854466408, -0.4715458453, -0.5302187204, + -2.3346014023, -0.4460463226, -0.5775428414, -0.6922178268, -0.3119456172, 0.3294471204, -1.3128342628, 0.3397966027, + -0.2910468876, 0.9310884476, 0.5599357486, -0.0645182207, -0.0022406222, -0.5151447654, 0.5345206857, 0.3004088998, + 0.2320223451, 2.1810531616, -0.100160487, -0.605132997, -0.5047010779, 0.01762316, -0.5135729313, 1.3429766893, + 0.4130504131, 1.0463596582, 0.861756146, 0.0478619747, 0.0463153683, 0.3848271072, 1.6161820889, 0.8716033101, + -0.7510064244, 1.6390513182, 1.7839026451, 0.5109132528, -0.4672897458, 1.1222280264, 0.9888499975, -0.9561136365, + 0.5663571358, 1.4470038414, -0.7865455747, -0.4490454197, 0.1197444052, -0.0093231238, 0.5896588564, -0.2719801962, + 0.1982195675, -0.2045348287, 0.4862102866, -0.9825719595, 0.2153809816, -1.1695139408, 1.4600381851, -0.4786804616, + -0.2161083519, 1.3162412643, -1.0952185392, -0.2379431874, 0.0441102535, -0.449662298, -0.5129234195, -1.9090203047, + 0.5068237185, 0.2302060127, -0.7661902905, 0.0725760013, 0.9885923266, 1.0863655806, -2.902823925, -0.5360904932, + -1.9112136364, 1.8043782711, -1.2130129337, 1.380145669, -0.3277495205, 0.2450582385, -0.7642333508, -0.3404273093, + 0.1624981314, 1.7061364651, 0.8927001953, 0.8685998917, -0.5195849538, -0.0039161691, -1.3448412418, -0.3250283897, + -0.7400012612, 0.1771302372, 0.6164767146, 1.7528487444, -0.3680059314, -1.0127396584, 0.7688501477, -0.2467727959, + 0.7563650608, 0.935718298, 1.0622066259, 2.3305165768, -0.5720127225, 0.5467406511, 0.5635195374, -0.924911499, + 2.7588467598, 0.8314345479, 0.1939035803, 0.762848556, -0.4104726315, -1.9406030178, -0.303229183, 0.4363195598, + 1.2151136398, 2.1058390141, 1.1828629971, 0.3339031935, -0.8795049191, 1.2889955044, -0.8493562937, 0.211114794, + -1.2545552254, -0.6699841619, 0.1545667648, 0.9607257843, 0.9349159002, 0.8397400975, 0.6369614005, 1.0919691324, + 1.81359303, 0.9556264877, -0.1990593225, -0.8042902946, 0.6528923512, -0.055343613, -0.9927421808, -0.5951382518, + -0.0551041886, 0.6262081265, 2.3066689968, -0.2077073157, 0.7109154463, -1.1168620586, 0.5868679881, -1.0205169916, + -0.4096455276, 0.5808160305, 1.0296586752, 0.6482652426, -0.2194568217, -1.4834964275, -0.1184953302, 0.4194943607, + 2.1360015869, -0.4918103814, -0.7194541097, -1.3561576605, 0.2670113444, 0.65461272, -0.2104466856, -0.1670428365, + 0.5703315735, -0.455941081, 1.0440343618, 1.2773948908, -0.5565972328, 1.6024007797, 0.2661893368, -0.4304800034, + 0.2327338457, -0.6957453489, 0.852960825, -0.170496121, 1.0020779371, -0.4330396354, -0.1417545974, -0.1366312355, + 1.1569111347, 1.1959494352, -0.6120578051, 0.3761216402, 1.3039016724, -0.6344389319, 0.5409040451, -0.2106793523, + 1.7126660347, -0.1599847823, 1.6979123354, -1.2285583019, -1.1358175278, 2.6169531345, 0.8238010406, -1.1758143902, + 1.1397869587, -2.3761627674, -0.2448349744, 0.1050523967, 1.4465601444, 0.3278667629, -0.9939356446, -0.9700256586, + -1.2412242889, 1.1203885078, 1.4587260485, -1.9321591854, -0.2354511768, -0.0673358142, 0.4001037776, 0.2343670577, + 0.739084959, -0.2944712937, -0.3466485143, -0.1584270895, 0.3662830889, -0.6116271615, -0.2264357954, 1.521032691, + -0.6150326133, -1.5202091932, -0.5913832784, -0.4052457213, -1.4865701199, -1.9483112097, -0.5207968354, 0.4274829328, + 0.3046709895, -2.0096416473, -1.5396296978, -0.4011812806, 1.5112646818, -0.7303193808, -0.5129240751, -0.8286438584, + 0.0695798472, 1.7603245974, -0.3305148482, -0.845502317, -1.4774661064, 1.217535615, 0.304644227, 1.5573654175, + 0.2028430849, 0.1601100266, 0.9338047504, -0.1322722286, 0.562312901, -1.1053166389, 0.3339771032, 0.738848269, + -0.5675597191, 1.4587401152, 0.9002025127, 0.7754671574, 1.2447451353, -0.9453841448, -0.0203836951, -0.7514674067, + 0.2120767683, 0.2850379646, 0.1254609972, 0.2035339177, -0.3764954805, -0.9387801886, -0.1428789049, 0.5332627892, + -2.6065831184, -0.8216148615, -0.7328824997, -1.4360533953, 0.2980169356, 1.723552227, -0.126785174, 1.2048579454, + -1.2153682709, -0.4437190592, 0.744056046, 0.9141807556, 1.5864833593, 0.6928018332, -0.9534311891, 0.6793599129, + 0.5651528239, 0.2193024904, -1.1105041504, -1.0860613585, 1.1356219053, -1.1252977848, -0.3664375544, -0.0169660207, + -0.5677758455, 0.5198579431, -0.4156208634, -1.2413494587, -0.4517956972, 1.2629374266, -1.960631609, -2.0649142265, + 1.2586480379, -1.0318564177, 0.6451462507, -0.0639000982, 0.3058444858, 0.3714894652, 3.2189693451, 0.8671776056, + -0.6356307268, -1.2256245613, -0.6236977577, 2.0042676926, 0.3193460405, -0.2986065447, -0.0811628103, 1.1276055574, + 0.4359809458, -0.8637416363, -0.8411214352, 0.0813471526, -2.5876824856, -0.4164364338, -1.0778590441, -0.4280856252, + -0.1837351769, -0.4342537224, -2.1249547005, -0.7090559006, 0.4856309593, -0.225165233, -0.422529757, 0.7283768058, + -0.4008677304, 1.7381820679, -2.5891318321, -0.0358014069, 0.7630400062, 1.2215707302, 0.562327981, -0.2767444849, + -0.7788773179, 0.6425501108, -0.2790244818, -0.0601394959, 0.922658205, -1.2856285572, 0.5124117136, 0.654319644, + 0.6985861063, -1.1863965988, -0.7743391395, -0.8036898375, 0.1511544138, -0.2061739713, 0.2215616107, 1.4245580435, + 0.6433502436, 0.2171405405, 1.023177743, 0.884522438, 1.2237645388, 0.7285240889, -0.2870639265, -1.1345304251, + 0.4285645187, -0.9715670943, 0.5583679676, -1.2529093027, -0.0554292351, -1.1577489376, -0.8337481618, -0.909581542, + 0.5952699184, 0.427646786, 0.4741272628, -0.4778809249, -0.5791444778, 2.0132668018, 0.064312838, -1.7063057423, + 0.2727234066, 0.1687286496, 0.6589840651, 0.2412974089, 0.3876089454, 0.1535113156, -0.7328495979, 0.6013470292, + -0.8155531287, -1.5449550152, 0.8408113718, 0.0877092257, -0.5942927003, 1.5020433664, 0.5605551004, 1.140963316, + 1.9613232613, 1.1202725172, -0.3546351194, 2.1160829067, 0.5874300599, -0.6321915388, -1.210894227, 0.1716439277, + -0.2549261749, -1.2034045458, 1.0263698101, 0.9422594905, 0.208889097, -0.1047871783, -1.2705695629, -1.1836208105, + -0.7867333889, 1.7524260283, -0.7368371487, 0.3624839783, -0.5364046097, -1.8370509148, 0.1137978658, 0.6024752259, + -0.2508539855, -0.2528652251, 1.6051051617, 0.0342720747, 1.5153194666, -1.0420209169, -0.4630776942, 0.1474878788, + -0.9713253379, 0.0588521026, 0.3362514973, 0.2530673146, 0.3107353151, 0.1848080754, 0.276437819, -2.1524662971, + 2.7178449631, 1.1053645611, 0.8582649827, -0.1122928783, 1.1051639318, -0.7339845896, 0.0696830601, -0.267444402, + -0.2647155225, 1.1227550507, 0.2607275844, 1.8020198345, -0.689267993, -0.0933775827, -0.2251587808, -1.3664307594, + 0.3179258406, 0.0487223379, 0.4735718071, 0.0241525117, 0.8647046685, 0.6103027463, -0.2139733285, -0.4484854937, + 1.4012920856, 0.3160155714, -0.3197103739, 1.7200762033, 3.0469586849, -0.2641649544, -1.4224961996, -0.7580975294, + -0.9873674512, 0.1957168132, -0.4102197289, 0.21446383, -0.7272182703, -1.281852603, -0.3538502753, 0.5934340358, + 0.0904515535, -0.5685857534, -0.7609325647, 0.4194073081, 0.8674047589, -1.390444994, 0.0177442655, 0.8740746379, + -0.5924335122, -1.7502161264, -0.0792060792, -1.3580681086, 1.1974959373, 1.0274500847, -0.8471487761, 1.3548214436, + -1.0140715837, 0.9863840938, -0.9353408813, -0.8694415092, 0.3170388937, 1.4484037161, 0.6906737685, 0.8037082553, + -1.4583121538, -0.3531333804, -0.3408255875, 1.5303416252, 0.5340528488, 0.6250340343, 1.3767137527, -0.5115512609, + 2.1108081341, 1.5340073109, -0.001663229, 0.0813266411, -1.1583846807, -0.717936933, -0.7177065015, 1.1551008224, + 1.654057622, -0.4208811224, 0.4496422112, -0.9338514805, -0.561655283, 0.6697068214, 0.3913882077, -0.3269231319, + 0.2208180726, 0.5489981771, -0.862480104, 0.0121480618, 1.1665678024, 0.1535249054, -0.1479054093, -1.0810278654, + 0.5306854844, -0.4219224155, -0.4571480155, -1.6084355116, 0.9218780398, -0.2359026372, 0.2739748061, 0.2933753133, + 2.9100708961, -0.9172291756, 1.7333257198, 1.4234604836, -0.3695767522, 1.8046455383, 0.5196769238, -0.0223775655, + -0.0609745122, 0.4093607068, -1.43131423, 0.4745879769, -0.2658665776, 0.1218895316, 0.009201183, 0.6915896535, + -1.2806612253, 0.4025485814, 1.1575285196, 0.4067355394, 0.9415536523, 0.4428307414, -0.3000774086, -0.9426550865, + -1.0320085287, 0.7782731056, 0.6642094254, 0.8447062373, -0.7672371268, -1.0206696987, -0.1935468763, 0.6972218752, + -0.854984045, 0.0458985455, -0.0316515081, -0.9947295785, 0.0599444099, -1.6356289387, 1.4886174202, -1.1804332733, + -0.5649894476, -0.3141291738, -0.5540065765, -0.0268782862, 0.1907479763, 0.3300601244, -0.0094888257, 1.2847651243, + 0.7848905921, -1.8625837564, -1.5045292377, 0.775704205, -0.5151198506, 3.4884924889, 0.6410551071, -0.8507729769, + 0.2530885935, 0.4635319412, 1.5692179203, 1.851817131, -1.38781178, 0.6403602958, -1.1527994871, 0.5967409611, + 0.1180173531, 0.574492991, 0.2153960019, -0.4859421551, 0.2957971692, 0.4451091886, 1.2154741287, 0.3185328245, + 0.1403361112, 0.0406874493, 0.5657766461, -2.6195344925, -0.7967351079, -0.9214567542, -0.7220990062, 1.1061993837, + -1.4456450939, -0.2186345011, -2.0822770596, -1.3654150963, 1.8305156231, -0.0043937741, -1.7268742323, -0.4598450661, + 2.7442691326, -0.7711686492, 0.2119555622, 0.6657399535, 1.8725705147, 0.871308744, -0.0707813352, -0.2834530771, + -0.1813057214, 0.8837855458, 1.0758835077, -0.094357945, -0.2998608947, -1.2143330574, 0.156408295, -0.6589041352, + -1.5153027773, -0.4579784274, 1.2980852127, 0.2589216232, -0.6551944017, 0.527018249, 0.7990094423, 0.5013885498, + -0.5969684124, 0.9251852036, 0.1497516632, 0.3835472763, 0.2245106548, 0.3399053216, 0.9988560081, -0.2961629331, + -1.244122386, -1.0278291702, 0.665102303, -1.1447552443, -0.9833480716, -1.8347622156, 0.775775373, 0.477024734, + -1.574313879, -1.1904482841, -1.2004079819, 0.4256134331, 1.4869117737, -0.0860315859, -0.2575958669, -0.0120158978, + 0.4862571061, 0.0525990017, 0.4884842336, 0.298373282, -1.5491154194, -0.9905139804, 0.6269329786, 0.1086431965, + -0.2456014603, -0.1656596661, -0.9914613366, -0.2911224961, 0.3206650615, -2.0059871674, -1.4480019808, 0.7958505154, + -0.9722334743, 0.0591765344, -0.6312087774, 0.2814213037, -0.4718524516, -0.4777416587, -0.8816665411, 0.5701669455, + -0.8234921098, -1.6473771334, -0.2114145905, 0.7337220311, 1.7068860531, 0.1092660576, 0.508482039, -1.0156943798, + -0.682323575, 0.4121778905, -0.0907771587, 0.0038814421, 2.609000206, 1.1189103127, -1.9125928879, -0.3776756823, + 0.4361971617, 0.0557256676, -0.0821820721, -0.7631011009, 0.4519874156, -2.4382345676, 0.108676523, 0.7393144965, + -0.048188515, -0.3635574579, -0.3686617911, -1.4666473866, 1.1164562702, -0.9669422507, 0.7040798068, 1.2670004368, + -1.7580957413, 0.0831064582, 1.8570041656, -0.5323807597, 0.7726399899, -0.5263054371, -1.6371046305, 1.4653873444, + 1.3102437258, -1.8714300394, 0.7401259542, 1.46407938, -0.3641062081, 0.5393807888, -0.4796035886, -1.0403650999, + -0.4575759172, 1.8171423674, 1.2859230042, 0.8897191882, 1.0549505949, 1.360030055, -0.3504465818, -0.6137373447, + 1.4029437304, 0.7413427234, 1.4288338423, 1.394063592, 1.4501439333, 0.7185511589, 0.4196183681, 1.1800745726, + -1.0972715616, 1.0779728889, -0.3046537638, 0.1432365626, -0.7692264318, 0.4684534371, -0.452758193, -0.0037421312, + 0.9633156061, -1.6476392746, -0.6606883407, 0.7935672402, 1.4174605608, 1.2771332264, 0.116006054, 0.8817456961, + 1.2700384855, 0.5530409813, -1.2621611357, -0.3488104641, -0.017437527, 0.5478835106, -1.4185255766, 0.0217602048, + -1.1966099739, -0.6348711252, 1.1889677048, 0.0976005048, 2.5740497112, -0.3773222566, -0.4613899291, -0.0986436456, + 0.0541701391, 0.2876920104, -1.754883647, 0.9253419638, 0.2831991613, 1.9411002398, 1.4710776806, -1.4093031883, + -0.5841726661, 0.6404128671, -0.8920534253, -1.5517531633, 0.482891202, -0.2645669878, 1.1087429523, -0.2828297615, + -0.015807027, 1.5413781404, -0.8813383579, -0.4438351989, 1.062240839, 0.9529253244, 0.625320375, 0.9075292945, + 0.9945212007, -1.6742419004, -1.6183062792, -0.2126778513, 0.640255928, -1.2418143749, 1.5323899984, 1.8869425058, + -2.1036224365, -0.2886890471, -0.2596866786, -0.2835617661, -1.5854977369, 0.6081105471, -0.1809121221, 1.2577123642, + 0.2052631229, -0.8163881898, -1.106359005, -0.0912579298, 0.3450472057, -1.5712219477, 0.8036522269, 1.0187789202, + 0.4720780253, -1.2311170101, 0.5175920725, -0.4290986657, -0.3666216731, 0.6965180635, -0.1685263962, -1.5898982286, + 0.0220934488, -0.1997891963, -0.0530815497, 0.8660960197, 1.2025402784, -0.2280056924, -0.4191038013, 0.9244895577, + 0.3037866652, -1.022559166, -0.3245607018, -2.1816282272, -1.6213059425, -0.0621134415, 0.5913257599, -0.132305041, + 1.285056591, -0.9554300308, 0.2916534841, -0.160019964, -0.025158599, -0.8426494002, -0.2910325229, -0.0537761226, + 0.9424139857, 0.6624855995, -0.5286464691, 0.707658112, -0.6090992689, 1.5335679054, 0.0755734891, -0.1748557091, + -0.2534921765, -1.8603761196, 1.1692599058, 0.604290247, 0.9103702903, -0.1232990026, -0.4136359692, 0.435008049, + -1.5793688297, 0.6769706011, -0.4317162931, -1.4103405476, 2.2864291668, 0.0951946005, -1.4713804722, 1.1892334223, + 1.1890237331, 0.4429376125, -0.838743031, 0.0935311168, -0.7773849964, -1.8710905313, 1.7024439573, -0.3445017934, + -0.4553095698, 0.7642885447, 0.9821681976, -0.4583004117, 0.0066860346, -2.2333476543, -0.1283345819, -0.5246235728, + 0.9105899334, -0.862911284, -1.2106477022, -0.4193559587, 0.0832006633, 0.858348608, -0.7869291306, 1.7270901203, + 0.6822558641, -0.7230071425, -0.9777082205, -0.3344391882, -0.3701584637, -1.7645907402, -0.4649545252, 1.0170435905, + -0.0217694566, -0.9039642215, -1.6144140959, -0.7381874919, -0.6702867746, -1.3525016308, -0.4430875778, 0.7287974358, + -0.2385735363, -1.9752480984, 2.0346944332, 0.7689108253, -1.3528065681, 0.6410573125, 1.3192390203, 0.3270509541, + 1.3804658651, 0.2953875363, 0.2034599483, -0.064583011, -1.0361405611, 0.5138510466, 0.4093931317, -0.1102928594, + 0.0347731411, 1.5495173931, 0.466495961, -0.3283931017, 0.8254403472, -0.5107836723, -1.5615645647, -1.3665698767, + 0.300765276, 0.2336972654, -2.3706405163, -1.4505566359, 0.3662475348, -2.1614456177, 0.1082526296, 0.0599631332, + -0.456930995, -0.0464944579, -0.8626391292, -0.521053493, -1.3991318941, -1.0450747013, 1.2357361317, 0.7472088337, + 0.0294626709, -0.0323381051, 0.8234859109, -0.6799733639, 0.4621934593, -2.5489547253, -0.9245632291, -0.7865313292, + 0.6090202332, -0.35975945, -1.5277130604, -0.7501274347, 0.0724710599, 0.3506417572, -0.0656960309, -0.4374740124, + -0.4982353151, -0.1413731575, -0.6359506249, 0.5705936551, -1.5379847288, 2.0364022255, -0.4719463289, 1.2827460766, + -0.0661825612, 0.2151302248, 2.1430366039, -1.1678416729, -0.7821418643, -1.0774587393, 0.0208406113, 2.9643104076, + -0.7014997602, -0.6581448317, 0.8276968598, -1.2026946545, 0.2845969498, -0.2574639916, -2.1206636429, 0.2223912179, + 1.0973002911, 0.5591518283, 0.4466454387, 0.2330162525, -0.7495750189, -0.0029619916, -0.4267501831, -1.6162149906, + -2.1914863586, -0.6577326059, 0.4989123344, -0.6556199193, -0.0895094723, -0.0112790493, 0.0701447576, 0.267929107, + 1.560393095, -0.9185328484, 1.2158505917, 0.6496582031, 0.9756454825, 1.3745002747, -0.8222441673, 0.2244423032, + 0.1343432516, -0.3055539429, -0.9232123494, -0.1694074422, -1.176579833, -1.1712293625, 0.3721295893, -0.6939271688, + -1.7612162828, -1.1052387953, -0.803353548, -0.2181822509, -0.8658139706, 0.2206589878, 0.6181307435, 0.5405413508, + 0.5935147405, -0.4217613637, 0.4479676485, 1.5241919756, -1.2515456676, 0.3748424947, 2.0765490532, 0.3203200698, + 0.8813945651, 0.8924462795, -0.1924320161, -1.5929996967, -2.3032474518, 0.1078558564, 0.6173242927, -0.8837097287, + -1.4029815197, -0.5150201917, 0.1820349246, 0.8237689137, -1.0956190825, -0.6264654398, 2.0228900909, 0.575214982, + 0.0658197179, 1.3183259964, -0.6357634664, 0.8268523812, -0.3430708945, -0.0185604282, -0.7815250754, -1.1980940104, + -2.0872871876, 0.433690697, -0.4385131896, -0.5323140025, -0.3113310635, -0.3358350396, -0.8802808523, -0.1359132677, + -1.0820661783, 0.6475699544, -0.27140522, 0.3617736399, -0.219901219, -0.2596733272, -0.9010024071, 0.7449892759, + 0.4877879322, -0.9734915495, -1.076452136, 0.6607186198, 1.9671131372, -1.532386899, -1.6164841652, -1.3796384335, + 0.9423570633, -0.2951205373, 1.3519340754, -0.2381277531, -1.0184181929, -0.8733766675, 0.4789345264, -0.883617878, + 1.3279944658, -0.9801152349, -0.1271719635, 0.266181618, -0.9542296529, 1.6332507133, -2.5235753059, 1.0538122654, + -0.7360922098, -0.3780718446, 1.5566005707, 0.2872518003, 0.8437467813, 0.3021098971, -0.5063041449, -0.5947359204, + -1.4161554575, 0.5075585842, 1.083231926, -1.0159112215, -0.7424957156, 0.4478953183, 0.607596755, 1.0550105572, + -0.1584615558, -0.7829976082, -0.7657365203, -0.1861712188, 0.2837609649, -0.3579142988, -0.1085585579, -0.2172659487, + -0.5554970503, 1.228867054, 1.9843388796, -0.7815829515, 1.4802480936, -0.8235428929, 0.8025032878, 2.2790677547, + 0.9906148911, -0.6867852211, -0.7537479401, 0.1955792606, 0.0749062449, 1.9827543497, 0.9090567827, 0.9319398403, + -0.7689310312, 0.2998859584, 0.0846697241, -0.3599868119, -1.577927351, -0.6001316905, 0.7877557874, 0.0443977341, + -0.5797268748, 0.2533348501, -0.2036195248, -1.3632600307, 0.8793420196, -0.4388233125, -0.7233103514, 0.569244206, + 0.4922772646, -0.163016215, 0.3571025729, 0.1961718649, 0.2645778954, -0.7818415165, 0.7580390573, -0.0369912013, + -0.7612245083, -1.0428425074, -1.6256395578, 1.5037935972, -0.1167479455, -2.5956823826, -0.7661041617, 0.3693991005, + 0.4504629374, 0.3117121756, -0.561388731, -1.1832345724, 1.2855526209, -0.6030053496, -0.6560151577, 0.1852611452, + -0.5990884304, 2.4433631897, 0.0511516444, 0.4812693, -0.0832996145, 0.2482223809, -1.9432893991, -1.6592720747, + -0.4858410358, 0.5000698566, 0.1994387358, -0.138488397, -0.9286952019, 1.1757085323, 1.1086024046, -0.8868203759, + -1.0367414951, -0.1277745217, -0.8232452273, 0.4371286631, -0.1243734136, -0.3757143617, 0.1735518128, 1.7695791721, + 0.0277947448, -1.3792670965, 0.3176753223, 1.3203235865, -0.3832557797, -1.4734238386, -0.2980696857, -1.0584447384, + -0.5828962922, 0.5312491655, 0.3283676207, 0.9943018556, -0.7106354237, -0.9073405862, -0.5333749056, -1.0341758728, + 0.1330567151, -1.052549839, -0.2770160139, -0.2599232197, 1.0627063513, -0.0400909074, 0.4328006506, 1.7536995411, + 1.3945586681, 1.4096744061, 0.2681570947, -1.3833025694, 0.3761285543, 1.285800457, 0.6580190659, -0.1391668916, + -2.1075122356, -0.6969650984, -0.4540668726, 0.267080605, -0.2743560374, -0.0209443346, -0.7997515202, -1.1989635229, + 0.0803686678, 0.7327975631, -1.4023789167, 0.1931434423, 0.9743856788, 0.8532840014, 1.1824666262, -0.7256034613, + 1.2055327892, 0.5179441571, 0.4593677819, -1.0894452333, 0.9806094766, -0.2745089829, -1.4509284496, -0.4190232158, + 0.7034731507, 0.5885317326, -0.8590492606, -0.1408797503, -0.1429534405, -0.1686502695, 1.5083961487, 0.0664177239, + 1.6594139338, 1.6427066326, -0.3360191584, 1.2271697521, -0.6477968693, -1.8092172146, -0.9437155128, 0.2422796041, + 0.9709712267, 1.1938385963, -0.2580324411, 0.2235572189, -0.0080338093, -1.0137414932, -1.0294257402, -1.2949119806, + 0.4745123088, 2.0134837627, -0.3586051464, -0.7135395408, -1.3953684568, 0.3262714148, -0.9641054869, 1.4204113483, + -1.4024853706, 2.118925333, -0.5846406817, -1.1655416489, -0.8957322836, -1.1574605703, -0.1748732775, -0.4009687603, + 1.1054528952, 1.9881278276, 1.3893102407, -0.7504013181, 0.7380410433, 0.2013456821, -0.4352020621, -0.1771009415, + 1.5475465059, -1.0222883224, 0.6397832632, 0.8793185949, -1.1897361279, 2.3307409286, -0.0984229222, -1.2100880146, + -0.3881158829, -0.519969523, 0.4241195917, -0.0116548957, -1.4528745413, 0.629833281, -0.6663973927, -0.4127940536, + 1.3213293552, 2.1988401413, -0.1545394957, 0.6720430255, -1.5908136368, 1.194768548, 0.612634778, 0.2747550309, + -0.6444818377, -0.3922859728, -0.2779766321, -0.5158533454, 1.0888648033, -0.4051799178, 0.0381805673, 1.0520000458, + 0.4421851337, 0.7295815349, 0.2826419771, 0.3008019626, 1.0624518394, 0.0210728142, 1.0455101728, 0.0507967658, + 1.4170062542, 0.6779723763, 0.128057614, 1.0865745544, 1.463760376, 0.8787689209, -0.3339741528, -0.9834817648, + 1.2178926468, 0.2774706781, -0.3207702339, 2.3072702885, -2.0267996788, -1.0228863955, 0.2627939582, -0.6198943853, + 0.2880648971, 0.101734668, 0.0353729799, -0.5069180727, -1.6419990063, -0.7368588448, -1.0442868471, 1.7887995243, + -0.0079993038, 0.1718894988, -0.6887407899, -0.3678089082, -1.5573518276, -0.4891292155, -1.291433692, -0.5052575469, + -0.6315882206, -0.901153028, 0.1310378164, 1.2318689823, -0.7219327688, 0.8740233779, 2.0904352665, 0.248789534, + -1.0377489328, -0.4964048266, 0.8279573917, -0.3556987345, -0.4572505951, 1.044762373, -0.7082029581, -0.1460758001, + -1.6420407295, -0.5102956891, -0.6610686183, 0.6488505006, -1.132324934, -0.3774205446, 0.6173532009, -0.2405151129, + -0.0985287949, -1.2055841684, -0.2576752603, -0.372951299, -0.9217440486, -1.7550470829, 0.435220778, -0.4867249429, + 0.5257884264, 0.655595243, -0.1585087776, -0.3430123627, -1.8562735319, -0.3113770783, 0.5841275454, 0.5621509552, + -0.3464486003, -0.5415142775, 0.0917498544, 0.2995837927, 0.3927473724, -2.8245084286, -0.3212784827, -0.3785587549, + -0.7113556266, -0.6022580266, -2.611979723, -0.0254186876, 1.0269163847, -0.5338106155, -1.4207351208, 0.860996604, + 0.9684557319, -1.1536953449, -0.1923975646, 0.7043721676, 0.8859874606, 0.4263644814, 0.8193140626, -0.1051984951, + 0.1981133819, 0.6787722111, 0.4743790627, 0.4614576697, 0.464294821, -0.9053800106, 0.2947457731, -1.3450095654, + 0.4394025803, 0.4799166918, 0.415091753, -2.1966297626, -0.0429796278, 1.6986823082, -0.5377891064, -0.6587689519, + -0.8812151551, -0.5194984078, 0.0733721107, 0.5582324266, 0.3964279592, 0.2120293975, 0.305482626, -0.287112534, + 0.7834923267, 0.390376687, -0.0846089721, -0.170570761, 1.2015510798, -0.6100164652, 0.5426404476, 0.0102491574, + -1.3187043667, -0.3852408826, 0.4882010818, -0.6264355183, 0.6432433724, 2.6491410732, -0.7734444737, -2.0508220196, + 0.347373575, 0.4667849839, -1.8796936274, -2.5656268597, 0.2532318532, 1.7867356539, 1.5840818882, -0.9908537865, + -0.1217880398, 0.1486516148, 0.5512774587, -0.2852463126, -0.7899572849, -0.3199961782, 0.0614964701, 0.0901733115, + -0.3096054196, -0.1612850279, 1.200091958, 1.2057310343, 0.1887879372, 0.4619420469, 2.267359972, -0.009924097, + -1.8448913097, -0.8179546595, -0.8862370849, 0.2955748141, -0.1304718554, 0.9787134528, 0.8472347856, -0.1288524419, + 0.5706324577, 1.2143545151, -0.538954258, 0.1138983741, 0.7284115553, 2.3312344551, 1.2056900263, -0.956209898, + 2.7902858257, 0.1274458468, -0.5790623426, 0.5577117205, 0.6300501823, -0.1559722424, 0.5293494463, 1.9820027351, + -1.3815310001, 1.7998952866, 0.7246081233, -0.1543004215, 0.613143146, -0.6942011118, -0.3525010645, -0.5144149065, + -1.2278832197, 1.4018414021, 1.7004867792, 0.6758140326, -1.8631590605, -0.0994367823, -1.4539935589, -0.84433043, + 0.0253531449, 0.1577637196, -0.8598079681, -0.1473255455, 0.8919650316, -0.7243660092, -0.1229981408, -1.6209475994, + -1.6732126474, -0.82558465, 1.2784086466, -0.3470903039, -0.1857288927, 0.4499431551, 0.5625912547, 1.1732017994, + 0.1230131313, -1.8694161177, 1.3007078171, -0.3756277859, -0.2890734673, 0.0999187604, 0.0808265805, 1.2099618912, + 1.0885607004, 2.255058527, 0.8889443874, 0.703522861, 0.8246964216, -0.6405169368, -0.3325651288, 0.0771268159, + -0.6547657251, -0.8956646323, 1.3768603802, -1.491268754, -0.2551057935, -0.9616905451, 0.4821599722, -0.179667592, + 0.2831281424, -0.1340553463, 1.0645695925, -0.6067219973, 0.8581216931, -0.8533557057, 0.1947769821, -1.3405125141, + -0.0545026809, -0.0804695264, 1.3081027269, -0.3672732115, -0.9950604439, -0.1673544943, -0.6271149516, 1.0561723709, + -0.8029696941, 0.1047154367, -0.6536308527, 0.412845701, -0.3468890786, 0.2208393216, -0.3895644844, -1.8310519457, + -0.2431140691, 0.1881937236, -0.7013317347, 0.0772262961, 0.3569529653, -0.5789977908, 0.8872517347, -0.5732261539, + 0.4532896876, 1.199988842, 1.3070069551, 0.5669031739, 0.6928222179, 0.1783494949, -0.8095983267, -1.6969149113, + -0.244948253, 0.8840457797, -0.4317087829, 0.2946268618, -0.7384603024, 0.8370640278, 0.2964679301, 0.666121006, + -0.0482210517, 0.2334891409, 0.2837832868, 0.5236741304, -0.491881609, -1.4834574461, 1.5049879551, 0.3132415712, + -0.0655054599, 0.2337341458, 0.5793153048, 0.4204308987, 0.1527949274, -0.5522327423, -0.3710898757, -1.4416307211, + 0.3492567837, 1.9169337749, -1.1547886133, 0.1601953954, 1.6751732826, -0.0111167338, 0.3223155439, 0.7473372221, + -0.8906780481, -0.5188031793, -0.2556838393, 0.7918527722, -0.110098131, 0.1180559546, 0.8671013117, 0.9141765833, + -0.2264145017, 0.9463275671, 1.2277970314, -0.291000098, 0.3737040758, 0.0451757126, 0.0928840712, 0.1828407347, + -0.7114292979, -0.702684164, -1.1814341545, -0.4881572127, 0.0155485887, -2.7573442459, -0.6148686409, 0.0310324896, + -0.7967752814, 1.13019979, 0.8300131559, 0.2524907291, -1.0185047388, 0.6041662097, -0.6465168595, -1.6469916105, + -1.1552380323, -0.2510072887, 1.3071713448, 0.2094026506, -0.8110154867, 1.0590174198, 2.1924555302, -1.120218873, + -0.8820242882, -0.2305018008, 0.4774096608, 0.40561831, 0.3316685855, 0.724674046, -0.2441137731, -1.1167860031, + -1.3302159309, 2.1725409031, 0.8256790638, 0.8306998014, 0.043392133, -2.6837403774, 0.1183398664, -1.574203968, + 1.3130691051, 0.5735969543, 1.3894512653, -0.2349755168, -1.486846447, -1.5704554319, 1.2836638689, -1.4032113552, + 0.0997329354, -0.3284315169, -0.7569980025, 0.4101175666, 0.2967536747, 0.0999957025, -1.7917844057, 0.116678983, + 0.9223045111, -0.520825386, 0.3779269159, 0.3759181201, -0.9334786534, -0.4578769207, 0.3737753034, -1.1865646839, + 1.4694766998, 2.1069328785, 1.4723044634, 0.8738681078, 0.800830245, -0.6091771126, 0.6025853157, -1.7750355005, + 2.5449066162, 1.9469372034, -0.0892248526, -0.7289734483, 1.7631760836, 0.3075451553, -1.0003085136, -0.4178240597, + 0.8397405148, -1.3949640989, 1.2439329624, -1.2816982269, 0.5767304897, 1.1978013515, -0.009512444, 1.4640440941, + 0.9479848742, 0.4466987848, -0.4483757317, -0.1509431601, 1.0327948332, -0.4387851655, -0.7053198814, -1.7758510113, + 2.3635933399, -1.2871538401, 1.2330980301, -0.0103951599, -2.0432476997, 1.1372212172, -0.2039745152, 1.1895712614, + 2.1988720894, 0.4431562126, -0.6325745583, 0.7957141995, 1.5974450111, 0.2394031286, -0.7119681835, -0.5758239031, + 0.2845700085, 1.1215269566, 0.3454354703, -1.1157178879, 0.7630261183, -1.0396157503, -1.2194751501, 0.4127437174, + 0.8683571219, -1.407274127, -1.0504204035, 1.4434605837, 1.7263585329, 1.0688557625, -0.6204966307, 0.2786242962, + 0.0499957725, 1.7350540161, 1.0227462053, 0.0887895748, -0.1811278611, 0.0582000278, -0.4657486677, -1.7719552517, + 0.8368805051, -1.1324976683, 0.3575865328, 0.5382347107, -0.8788229227, 0.5577881932, -1.4245994091, -1.3215843439, + 1.158349514, 0.6064372659, 1.8785479069, 1.266928792, -1.6431622505, 1.4687012434, 0.1747233868, -0.7408152819, + -1.7918393612, 0.0706328824, 2.3624007702, 1.3255273104, -0.8967608809, -1.8747004271, 0.0701705366, -1.8117138147, + -1.1072317362, 0.4218684733, 0.9634417892, 0.2764050663, -1.0511800051, 1.2283619642, 0.5277022719, 0.9080645442, + 0.8044661283, 0.7120621204, 1.1845030785, 0.6737482548, 0.257016629, 1.1729450226, 0.9283907413, -0.2583913505, + 0.289655298, 0.4090211391, -1.518794179, -0.1357347518, -0.4136520922, -0.9496188164, -0.784568429, -0.687762022, + 1.4111977816, 0.7903782129, 0.232904762, 2.445043087, -1.2297238111, -0.362329036, -0.1056897566, 1.4517501593, + 0.0444726944, -1.6526907682, 0.1572376639, 0.8969747424, -0.4539208114, 0.3395579457, -0.7769137025, -1.1884061098, + 1.7207614183, -0.2107622027, -0.3655122817, 0.7336954474, 3.9021322727, -0.1486244053, 0.0116885044, -1.4245262146, + -0.8629705906, -1.4355378151, 1.3567553759, -1.2594320774, 1.1831315756, -1.1354767084, 2.2162899971, 1.4533467293, + -0.6889243126, 0.683400631, 0.1057725549, -0.8852538466, 0.1678477079, -1.3591594696, 0.5192753077, 0.3029523492, + 0.7172673941, 0.9541074038, -1.1572390795, -0.23473683, -1.7002626657, 0.2449831665, -1.1469874382, 0.8641168475, + 1.4774310589, -0.0520692803, -1.3869181871, -0.2344624996, 0.1029674485, 0.814022541, -1.2963079214, 1.6603183746, + 0.0933022127, -1.0267788172, 0.7393246293, 1.4649448395, 0.3346224725, -0.4709796906, 0.3763844967, -0.2554529607, + 1.2848366499, -0.1008833647, -1.4221745729, 1.3263037205, -1.5512310266, -0.0674574524, 0.1974201351, 1.9573367834, + -0.5765719414, 2.5311250687, 0.0921669155, 0.5961879492, -0.5765373111, 1.1144328117, 1.0982080698, -2.1409747601, + 1.4250926971, 0.9062033296, -0.4229671955, -1.7703527212, -1.4376366138, -1.2039889097, 0.4187853932, -0.9995331168, + 0.0991715044, 0.5590418577, -0.3176335394, -0.7645334005, 0.1076866239, -0.2528138459, -0.584133625, -0.456325829, + 0.695941329, -0.3995080888, -0.2161872089, -2.4993913174, 0.1716826558, 1.9722093344, -0.1077965498, -0.2359120846, + -0.692469418, 0.3745718896, -0.6471085548, 1.1404736042, 1.0013725758, 0.0168315694, 1.0300970078, 1.0599291325, + 0.0489125997, -0.7580710649, -1.4751648903, 0.6038507819, 0.0657226518, -0.1146567091, -1.2612990141, -0.1839995682, + 1.040112257, -0.4304883778, 0.1605222672, 0.3470155001, -0.2415146828, 0.6425074339, -1.8182214499, 0.5159596205, + 0.1558146328, 0.0451287888, -0.031179199, 1.4505674839, -0.9712655544, 0.7230480909, -0.5097474456, 0.1868300736, + -0.7318282127, -0.4006540775, 0.0385716334, -1.077801466, 0.9501018524, 0.2879245579, 1.0167944431, -0.4306978285, + 0.3810772598, 2.106600523, -1.9030117989, 1.2764573097, 1.3993682861, -1.0606230497, -1.3270933628, 0.8174833655, + -0.8962209225, 2.0776956081, -0.2050100565, 0.9393951297, 1.335452795, 0.974398315, -0.3406037092, -0.547752142, + 2.6748812199, 0.4349660575, 2.3099956512, 0.7869509459, -1.4177607298, 0.9141976237, 0.6136193871, 0.6456041932, + -0.6823461056, -0.4874903858, -0.1170524731, 1.9651896954, 0.0810671002, -2.3023612499, 1.183506608, 0.8766115904, + -0.9631479383, -2.1853756905, -1.2428277731, 0.0720189661, -0.4796108902, -0.1266144216, -0.9395406246, 0.8748876452, + 0.4869423807, 1.9948581457, -0.6947699189, 0.2270700186, -0.3317213953, 0.6422330141, -0.4053525925, 0.6357408166, + 0.1552224904, 0.1389403045, 0.9798236489, 1.6588976383, 0.624899745, 1.3167870045, 0.1932007372, -0.876160562, + -0.5672311187, -0.2326073647, 0.3890257478, 0.2928788364, -1.320325017, -0.9401980042, 0.3664203882, -0.5633349419, + 1.0236297846, -0.0916399956, -1.0432430506, -0.7348905802, -1.4612178802, 0.0253731403, -0.0812676325, -2.3844251633, + 2.1396183968, -0.3534555733, -0.5941804051, -1.4541046619, 0.3458630145, -2.0107643604, -0.4030187726, -0.5923594832, + 0.2931079268, -1.4421180487, -0.9520923495, -0.9846225381, -1.5098954439, -0.7086515427, -0.0347315706, 0.2972258031, + 1.1616653204, 0.1510649323, -0.50603652, 0.0093106842, -0.0073053623, 1.0132656097, -0.3046438992, -1.3726711273, + 0.0134564815, 0.8839237094, 0.9101039767, -1.4731736183, 0.2599923015, -2.1118168831, 0.928753674, -0.9762788415, + 0.2646948993, -0.3983414769, 0.82495749, 1.6295404434, 1.0062322617, 0.1468868256, 1.060112834, -0.1219236851, + 1.4774035215, -0.1063908115, 0.3392222524, 0.2582385242, -0.8551683426, 1.0945085287, -1.0423394442, -0.4286342561, + -0.9640535116, 2.5036330223, -0.0431590155, 0.9850620627, -1.0826802254, -0.005179889, -0.8156575561, -1.6702399254, + 0.655618906, -0.6202479601, 0.8388648629, 1.3374948502, 1.1133385897, -0.66391325, 0.8211407065, 0.7570949197, + 0.6676589847, -0.1204034463, 0.2454028726, 0.6149377823, 1.1963888407, -0.5744004846, -0.7452492714, 0.194577083, + -0.9737981558, -1.4163233042, -0.4329152703, 0.0736613274, 1.3573538065, -0.1728477329, 0.2341295928, -0.1851958036, + 0.8775706291, 0.1613099128, 1.1886209249, 0.9928414226, 0.5726636648, -1.0495097637, -0.7697876692, -0.0529748313, + -1.2455561161, 0.8108440042, -0.8752728701, 0.4357014596, -1.5372251272, -0.7729937434, 0.2567974627, 0.4485482275, + 1.8845136166, 0.256444037, 0.184403047, 1.7274739742, -2.3057599068, 0.7775979042, 0.562300384, 0.2061211616, + -0.5265920162, -0.3165593147, -0.7587300539, 0.5017391443, -0.0206113029, -0.576685071, 0.9890679717, -0.6054541469, + -0.4035939872, -0.5519093871, 0.3898775876, -0.8180458546, 0.8589459658, -0.4786759317, 1.0392462015, 0.2402326465, + -0.3096106946, 0.2151809037, -0.6961288452, -0.422306776, 1.2795596123, -0.2458327711, 0.1790923178, -0.7446967363, + 1.5123780966, 1.8332709074, -0.1309396625, -0.5887723565, -0.1028404683, -0.8091694713, 1.5737030506, 0.0129924612, + 1.7106083632, 0.3016880155, 1.5860959291, -0.7288613915, -1.2153372765, -0.2323260754, -1.5699255466, 0.4336345196, + -1.5333116055, 0.0587876514, 0.6924380064, 0.9327794909, -0.1513533443, 1.1799548864, -2.2671871185, 0.1525774598, + 0.8967125416, 0.6222859025, -0.2084840834, -0.1403931379, 0.1346957684, -2.0565283298, 0.4950318336, -0.431996733, + 0.916270256, 2.7992014885, 1.5372692347, 0.8877406716, 1.0195660591, -0.4253476262, 0.5052951574, -0.864707768, + 0.2749290466, 0.1537522674, 0.5428519249, -0.6285081506, -0.4747620225, 1.778097868, 0.5352087021, -1.5661109686, + -0.5283264518, 0.0906709209, 2.0831224918, 0.7579495907, 0.5779919028, -0.2779310644, 0.1220835596, 0.6336193681, + -1.0817463398, -1.154959321, -1.4704773426, -1.1104469299, 0.3906410336, 2.1418421268, -0.4694980979, 1.9122390747, + 1.2186927795, 0.2590028644, -0.0949972644, 0.5684119463, -0.952311933, -0.1190907806, -0.6136029363, -0.0960134193, + 0.6986835003, -0.9704755545, -0.6268044114, -0.5610452294, 0.6267525554, -0.4279605448, -0.3012984395, 0.0593986809, + 0.992524147, 1.3790812492, 1.0318965912, 1.04157722, 0.2689839602, 0.3476128876, 1.5841513872, -1.3008955717, + -0.6530005336, 0.2141337395, 0.9915444255, -0.1424658149, 1.3862416744, -0.9926421642, 1.7042853832, -0.8251213431, + -1.5188190937, 0.4262528419, -0.4792524576, -0.9867950678, 1.006161809, 0.5120648146, 0.5273358226, -1.1984391212, + 0.7163698673, 0.6981152892, 0.1147046685, -1.1462678909, -0.7785617113, 0.9478487372, 1.5295920372, 1.420050621, + 0.3724110425, -0.542001009, -0.4563983381, 0.6563023329, -0.4331812859, 0.0931108072, -0.195166707, -0.3696748018, + -0.5538032055, -0.6306383014, 0.8567004204, -0.2205395103, -0.8111694455, -0.8887060285, 1.253062129, -0.3134068251, + 2.209748745, -0.7303216457, -0.8344842196, -0.4096687436, -2.4196662903, -0.0106813936, 0.4485253394, 1.8782069683, + -1.8911976814, -0.1464397758, -1.3518520594, 0.7725373507, 0.0136093041, -0.6495004296, -0.5794745684, -1.0514913797, + -0.2449943721, 0.5634900331, 2.031028986, -0.7452318072, -1.1391593218, 0.1187069863, 0.6543679833, -0.0734154284, + -1.2560356855, 0.7408869863, -0.4925400317, -1.0945181847, 0.0686069354, 0.3952773809, -0.1935277283, 0.4949653149, + 2.5847566128, -0.697308898, -0.1285281926, 1.4140560627, -1.1363401413, -1.052495718, -0.5918847322, -1.4523485899, + -1.9308159351, 0.0701744705, -1.3957195282, 1.1885744333, 1.2093832493, 0.2166377157, -0.303034097, 0.059717644, + -0.5784593821, -0.1520032585, 0.0584271438, -0.8972605467, 0.6736978889, 0.6967254877, 0.4667727053, 0.0286635868, + 0.2837365568, 0.4581332207, 0.3056941926, -0.0116381422, 0.9084653854, -1.3365603685, 2.85029459, 1.0096521378, + -0.8975444436, -0.3106841445, -0.1088178307, -0.8972753286, 0.9920865297, -0.0723804459, 0.5263554454, -1.0233750343, + 1.2341985703, -0.3395036757, -0.0130303865, -1.0015542507, -0.3587833345, -0.5115778446, -0.9865487814, -0.1158994958, + 0.8093836904, 1.4579401016, 0.3082989156, 0.2266820669, 0.9964211583, 0.0073694857, -2.0784134865, -1.7294149399, + -0.4265480638, 0.4939056933, 0.7890198231, -0.4054355621, -0.5412698984, 2.1344156265, 0.7287756205, -1.2158207893, + -1.0318105221, 0.6429752111, 2.7805309296, 1.1857364178, -1.5435954332, -0.1381753832, -0.253826648, 1.1751824617, + 0.0941778049, -0.4272075593, -0.4489406049, -1.2893304825, 0.3536476791, -2.106659174, -2.2367551327, -0.5366755128, + -0.5199564695, -1.318344593, 0.8450385332, 1.8122462034, -0.1849884093, -0.5415422916, 2.2770223618, 1.5768443346, + -1.4913719893, 0.6609851718, 0.9181861281, -1.9391117096, -1.4061818123, 0.2801476419, -0.3844480813, -1.1504819393, + 0.3682684898, -0.6189881563, 1.1590030193, 2.674311161, 0.4546943903, 0.2690356374, -0.185342595, -0.2681950033, + 1.4984539747, 0.0044779256, -0.3983008564, 0.1030340418, -0.0268113017, 0.1630320698, -0.4327528477, -0.7730445266, + -1.058860302, 1.5333759785, 1.5113227367, -0.3076021969, 0.1370654255, 0.0941180363, 0.8745601773, 1.1456735134, + 0.4186946154, 0.3277677894, 1.2020785809, -1.2507486343, -0.4188847244, 0.6161471605, 0.3914790452, -0.9654144645, + 0.275860399, -0.0457552262, 0.6747549772, 0.9733185768, -0.6183296442, 0.0650520474, 0.7692757845, 0.5387182832, + -0.8589666486, -1.7312017679, 0.0673047602, -0.0327091403, -0.1677000821, 0.6749193072, -0.8480613828, -0.4110155404, + 0.1744018346, 1.9193584919, 0.2909437716, 0.2042945921, 1.2015007734, -0.1746187657, 2.0067448616, 2.2541844845, + -0.9878281951, -1.708101511, 1.0036889315, 0.8530163169, -0.0468556173, 0.9961929917, -0.9784662127, 0.486310035, + -1.168038249, -2.0089857578, 1.6244140863, 0.0916079283, -0.3821515739, 2.153744936, 0.3477901518, 0.4862693548, + -1.6556663513, -0.9747734666, -0.6179747581, -1.8434002399, 0.2441639751, 1.2477802038, 1.0027505159, 0.7601565719, + 0.4941864014, -0.8031545877, -0.1345568299, 1.3695721626, -0.6639223099, 0.324795872, 0.0043942472, 0.1913578659, + 0.0745675713, -0.6932394505, 0.0181727502, -2.3302776814, -0.7034760118, -0.3380787969, -0.1769035012, 0.785654068, + 0.1328079104, -0.3098344803, -0.9356276393, -0.0556659177, 0.2006022036, 3.4013428688, -0.1138542965, -0.7904957533, + -2.3656320572, -1.6644995213, -0.0752599388, 1.2415909767, 0.4848107994, -0.2712499797, 1.0699157715, 0.6268231869, + 0.6100659966, 1.6827350855, 0.2057249993, 0.4664883018, -0.8904610872, -0.6790813208, 0.4590415955, -0.0912852958, + 1.3914935589, -0.7131012678, 0.2295179665, -1.3685091734, 0.4473334253, -1.7683360577, -0.5036785007, 1.3914653063, + 0.5441012383, -0.5553440452, -1.2935613394, 0.8311233521, -0.6089043617, -0.1083713174, -1.0062488317, 1.0542385578, + -1.4220438004, 1.4223126173, -0.5420668721, 0.7962802052, -0.4968725145, 0.722412467, -0.9014311433, -0.01732268, + -1.8692378998, 0.744263351, 1.1637054682, -0.9639398456, -0.1304800659, -1.3041782379, 0.1481969059, 0.1446544379, + -0.3365060687, -0.5480625033, -0.58526057, -0.5312329531, 0.2836891413, 0.4132503867, 0.4652761221, -0.3472861648, + 0.1682231873, 2.2558338642, -1.2319662571, 0.5227214694, -0.4734502733, 1.7072815895, -0.3913713694, -1.9416004419, + 0.1609739214, 1.0534284115, 0.6118378043, -0.8480007648, -0.6930434704, 2.4445428848, 0.3759610951, 0.0456087664, + 0.3976513147, 0.1482326239, 0.0915998146, -0.1041516364, -1.3221958876, -0.8823789954, -0.9341890812, 1.6293078661, + -0.2838116288, 0.0902046338, -1.2891747952, 0.9338698983, 0.0727711618, -1.2760754824, 0.3651596606, -0.1811099648, + 1.4663398266, -1.3555800915, 0.5154141188, -0.6398217082, -0.9735441804, 0.9723172188, -1.4711934328, 1.0343658924, + 1.1213243008, -0.2257323861, -1.5045515299, 1.3349263668, -0.2323711216, -0.1518178135, -1.8108577728, 1.8254790306, + 1.2762485743, -1.0044380426, -0.8060824275, -1.1536781788, -0.0594115667, -1.5260562897, 0.6320920587, 0.5781828165, + 1.8738344908, -1.7082090378, -1.2055032253, -1.6750184298, 0.9773060679, 1.7373665571, 2.0059866905, 2.3705921173, + -0.9223784804, -0.6740148664, -1.4445827007, 0.510856986, 0.4014914334, 1.7079445124, -0.9667310119, -0.0251678526, + 1.265525341, 0.5475633144, -1.3689777851, 0.9426730871, -1.2328010798, 0.9257682562, -0.2959577143, -0.6005290151, + 0.5494224429, 2.0729205608, -0.6353592277, 0.319213897, 0.6131855845, 0.1523712426, 0.0587622598, 0.2394811511, + 1.7130912542, 1.2879834175, 1.1557379961, -0.3637089729, -0.2145810127, 0.9560777545, -0.050856445, -0.1313996017, + 0.7307595611, 0.5367805362, 1.8643679619, -0.9024128914, -0.2627148032, 2.0112290382, -0.5909074545, 1.4932234287, + -1.0802291632, 0.6225048304, 1.3895535469, -1.450671196, -1.3074595928, 0.2020994872, 0.3432753086, 0.227884084, + 0.636040926, -1.077996254, -1.0535291433, 1.5352840424, -0.2123942673, 1.2253196239, -0.8935346603, -0.9941996932, + 0.3262534142, -1.1904532909, -1.7328804731, -0.2980934978, 0.1107948944, 0.559944272, -0.4482952654, 1.2198443413, + 1.1387603283, -0.1491803825, 0.1041010097, 0.4254328609, 0.3654618561, 0.9308492541, -0.3119447827, -1.3580926657, + 1.0101203918, -1.5451142788, 0.2026536763, 0.3477017283, 2.3403952122, -0.072437726, -0.1430427432, 0.3848078549, + -0.1609339267, -1.2239019871, 0.0277106408, 1.5609391928, -1.3043521643, -1.164522171, -0.2278364003, 0.7276721001, + -0.1473096013, 0.2433789521, -0.9658976197, -0.2630626559, -1.342762351, -0.3987060785, 0.6780408621, 0.3158074319, + -1.4230879545, -0.2691633701, -1.512804389, -1.4413479567, 0.0664281994, 0.2924026251, -0.0307732169, -0.0908246115, + -0.6818583608, -0.3328570724, -0.8593428731, -0.4004930854, 1.3459855318, 1.1941367388, -0.5967947245, -0.0030466982, + 0.7044922113, 0.5484733582, 0.1524624825, 0.1162964776, -1.1390522718, 1.6581176519, 0.0612685196, -1.6157741547, + -1.9226813316, 0.7732533216, -1.389385581, -0.9835121036, -0.4904064536, -0.7418014407, 2.0079159737, -0.5394204259, + -0.4050091803, -0.8270653486, -0.3081693947, 0.2111128122, -0.2667162418, 0.2949900031, 0.1134409904, -1.0153115988, + 0.049362395, 0.2900373936, 0.7097696662, 0.708212316, 0.3717222214, 0.2401635796, 0.0780070871, -0.9557723403, + -0.1404657364, 0.0148379868, -1.7255346775, -0.7337841392, -0.8126275539, -0.2047343999, -0.6537588239, -0.1437726617, + -0.3824236989, -1.8198882341, -0.369810462, 0.7416635752, 0.7381506562, 0.3432342708, -0.6773697734, -0.5082986951, + 0.0642926022, -0.0629437044, 1.255466938, -0.1163146794, 0.5489455462, 0.6377999783, 0.4149386287, -0.7792364359, + 2.1353731155, -0.5781716108, -0.8798395991, -0.9598072171, 0.9588785768, -2.1271765232, 0.6209558249, 0.1527183652, + 0.3872463405, -0.513805449, -0.0146184405, -0.2630323172, -0.9618073702, -0.371211499, -0.8843356967, 1.9723078012, + -0.419510752, -1.619076848, -2.0020143986, 1.8401244879, 0.2102288306, 0.0879932866, 0.049519144, -1.115908742, + -1.1406750679, 0.5224584341, -0.2365093976, 0.3528335094, 0.582557559, -0.0848055333, -0.1709183455, 0.3926368952, + 0.7267042994, 0.9824547172, 2.0305740833, -0.3654267192, -1.7048155069, 1.1908239126, 0.5972874165, 1.150935173, + 2.343378067, 0.5069172382, -0.3373184502, -1.2413910627, -2.4824178219, -0.7841681838, -0.2749174833, 1.4181344509, + -1.1041259766, -1.2695769072, 0.4413174987, 1.4447129965, 3.0843203068, 1.1354111433, 0.95969522, 0.0692582726, + -1.8266723156, -0.1291946471, 1.199442625, 0.1244117692, 0.5631824732, 2.212136507, 0.4624514878, -0.7957055569, + -0.0160569772, 0.1778953522, -1.3429569006, -0.016564576, -2.1498680115, 0.4199761152, -0.30321455, -1.1267306805, + 1.4630862474, -0.0667405128, -0.182357654, 0.8276292682, 0.2431415319, -0.0560194775, 1.2737932205, -0.1540903896, + 0.5906959772, 0.8791603446, -0.3834092021, 0.0394203626, -0.525298059, -0.2408296615, 0.7998421788, -0.6245598793, + 0.8748078346, 0.6978314519, 1.8217324018, 1.1725424528, -0.5058450103, -1.1825522184, -0.1523513198, -0.9517591596, + 0.3418970406, 0.8446737528, -1.1665372849, 0.3165706992, 0.9696199298, -1.2162469625, -0.5531826019, -0.3029631674, + -0.1280330271, -0.2350587249, -0.9241914153, -0.0322184227, 0.0353361554, -0.5270760655, -0.2926283181, -1.0359057188, + -0.5217298865, -0.0545432195, 0.9752314091, 0.4386629462, -0.1634233445, 0.3504447937, -1.6003768444, 1.5135135651, + 0.6002835631, 0.806509912, -2.4900567532, 0.8633902073, -0.6167137623, -0.3883438408, -1.3907675743, 1.3066443205, + -0.765855968, -0.5670421124, 1.6960184574, 1.9653801918, 0.6198975444, -0.7111523747, 1.6282720566, 0.4226017296, + 0.2790413797, -0.9668534398, 1.1160160303, 0.6634340882, -0.2094600797, -0.4581094086, -1.0761604309, 1.4729379416, + -0.6079205275, 0.6071959138, 0.3631769419, 0.0164318662, -1.3065373898, 0.6455099583, 0.1708582193, 0.0014818548, + -1.8358229399, 0.8673004508, 1.3817694187, 0.7489470243, 0.122879833, 0.7249348164, -0.2352134287, 0.4495169818, + -0.9030604362, 1.061057806, 0.8425629735, 0.6626394391, 0.7027125955, -0.8264446855, 0.4003860652, 0.1967862993, + -0.5250782371, -0.0714196265, -0.6816290617, -2.0005903244, -0.1332174838, -0.9352809191, -0.0467789285, + -0.3418357372, -0.5217453837, 1.4358524084, -2.8482091427, -0.1477034539, -1.8174880743, -1.4565387964, 0.5249419212, + -1.3412015438, 1.0536248684, 0.69910115, 0.984777987, 0.0895238072, -0.2042881399, -0.1511867195, -0.1911108941, + -0.8483758569, -1.1394416094, -0.6263279319, 0.3262504339, -0.4187115729, -0.9000268579, -0.5546446443, -0.8508963585, + -0.4535124004, 0.0920558199, 0.0759566426, 0.2565580606, -1.8011915684, 2.1070511341, -0.3016174436, 0.5993249416, + -0.6456158757, 0.2734361589, 0.2095994651, -0.9430122972, 0.0983353779, -0.7922813892, 0.6698214412, 1.5299458504, + 1.0799561739, -0.4676948488, 0.8438532948, 1.4016919136, 0.5662866235, 0.6506659389, 1.3225227594, -1.1737947464, + 0.0492078066, 1.6108115911, 1.2239793539, 1.2101303339, -0.017006347, 0.1157550141, -0.50278759, -0.5176725388, + 0.8887032866, 0.5435528159, 1.512057066, -0.1064564437, 0.6360615492, 0.602030158, 0.8799878359, -0.0621630587, + 2.2621920109, 2.6340875626, -0.5016446114, -1.1367765665, 1.3416843414, 0.4375230372, 0.7510082126, 1.693195343, + 0.9512465596, -0.8695816398, 0.9354771376, 0.5091691613, -0.4463708401, -0.033057373, -1.3820322752, 1.2793287039, + 1.1265002489, 0.3270427585, 1.1429853439, -0.3402656913, 0.3560847044, -1.0059175491, 0.2028916031, -1.1150841713, + -1.3619811535, 1.0493425131, 1.5576870441, -0.5290608406, 1.1438901424, -1.5659375191, 0.2392479181, -0.3553093076, + 0.06941019, 0.8125998974, 1.6412402391, 0.0621431805, -0.258010447, -1.681571126, 1.6350235939, 1.7907772064, + -0.3013070822, -1.3498184681, 0.9766227007, 0.802077055, 0.1571407765, -0.3929232657, -0.3565121293, 0.8001793027, + 0.7584725022, -0.9664206505, -2.0399837494, -0.7562393546, -0.0191347543, -0.1659532487, 0.2461894006, 0.053450115, + -1.4511636496, 0.8290471435, 1.420263052, -0.6461420059, -1.1758359671, -0.9557312131, 1.4096255302, -1.0442581177, + 1.816098094, -0.3281961679, 0.1080035195, -0.4689996839, -0.4098793268, -1.8007936478, -1.4797694683, 1.2166144848, + 1.312156558, -0.6322200298, -0.3365573585, 0.7352458835, -0.2050330043, -0.4896292984, -2.1675162315, -0.0871381313, + -0.6976063848, 1.2434237003, -0.2033266723, -0.0167122856, 0.1015309244, 2.7080247402, 0.2532948852, -0.8676658869, + 0.086644873, 0.9485441446, 0.1438010484, 0.1264382154, -1.1578149796, 0.5896145105, 1.3902870417, 1.6312388182, + 0.3860552907, -1.3228954077, 0.6822083592, -0.8747211099, -0.1168340445, -0.0816032961, 0.0949813724, -0.2675711513, + -0.285004586, 0.6082111001, -0.3288976252, -0.7892969251, 0.8910753727, -0.4391539991, 0.4801815152, 1.5932966471, + -0.718842268, -1.0578689575, 0.4190469682, -0.3070425391, 0.449621439, 0.3089589775, -0.6861286163, 1.1116139889, + 0.5191278458, 0.7216537595, 1.0761941671, -0.1724572033, -0.2763061225, 0.1145950407, -0.0036275154, 0.1950309277, + -0.4134352207, 0.2700786889, -0.4687091112, 0.3374997079, -1.2691653967, -0.9487433434, -2.332783699, 0.4507500529, + 0.9267107248, -0.3292925954, 1.1686035395, 0.2126315683, 0.194295764, 0.5142114162, 0.8292499781, -0.2244424075, + 0.4714294672, 1.2915810347, -1.1542066336, -1.3901450634, -1.0315078497, -0.5843418241, -0.3625900745, -0.681147933, + 0.0109514073, 0.4034639895, -0.7629212141, -0.699475348, -0.5534796715, 2.0600101948, 0.962893188, 0.0250039492, + 0.1217478886, 0.6854715347, -0.3456495404, -0.6771116853, 3.5718197823, -1.3524976969, -0.7330499291, -1.1353269815, + -0.6868650913, -0.1242099255, -1.8488539457, -0.1784221828, -0.5338147879, -1.4749981165, -0.9773634672, 0.1918828785, + -1.6867041588, -0.9012171626, 0.9544080496, 0.3894421458, 0.8154364228, -0.5928393602, 0.7729503512, -1.2539441586, + 0.9535008669, -0.4108581543, 1.1859742403, -0.7260681987, 0.0907370001, 1.5868970156, 0.1683713347, -0.443891257, + -0.3875832558, -1.8504856825, -0.8048030138, 1.2810553312, -1.0632429123, -1.1179351807, -0.6259436011, 0.245703876, + 0.705165565, 0.5252198577, -0.744189322, 0.3223232329, -0.8422292471, -1.6582146883, 0.2706842124, 0.529595077, + -0.6153351665, 0.4503405988, -0.6227647662, 0.5138043165, -0.222437501, -0.1313886046, -0.9083277583, 1.6377744675, + -1.3036310673, 0.9719820619, 0.6772412062, 0.5541941524, 2.06960392, 2.1902463436, -0.9359971881, 1.5101017952, + -0.8271532059, 1.1484556198, -0.785813272, -0.8876923919, 0.9454967976, 0.4654867053, 0.8108379841, 0.9280185103, + -2.050211668, -0.2926620543, 0.4862718284, 0.8723092675, 0.6239894629, 1.6616897583, 0.462648958, -0.6597118378, + 0.7611908317, 0.4519271851, 0.1392660737, 0.3012660742, -0.1104904786, 0.5151509047, -0.453591913, -0.574491024, + 0.1589653343, 0.6228471994, 0.6753728986, 1.4053241014, -0.3785912097, -1.3496842384, 0.0238295868, 1.2929308414, + -0.7779426575, -0.0595474653, -0.0276483335, 0.2683479786, 0.3438584805, 0.5323349833, 0.09694013, 0.7111643553, + 0.6105911136, 1.3095695972, 0.3804032207, -1.2960375547, 0.0383879021, 0.4270890057, -0.9619238973, -0.7499616742, + 0.1058324948, 0.6600143909, -0.1229051799, 0.8982565999, 0.6313751936, -1.2400015593, -1.3406934738, -0.7260510325, + 0.1453833431, -0.2229319066, -0.7966413498, 0.0715794265, 0.8668941259, -0.2490485162, 0.9793452621, -0.4966464639, + -1.357347846, 0.2178915888, 0.089386411, 0.7565530539, -0.3809821308, 0.3454945385, 1.0413463116, -1.5530769825, + 0.6615539193, -0.6907436252, -1.0928965807, -0.3175019026, 2.4032316208, 0.1700476259, -0.2063445449, 0.4634450078, + 0.9587469697, 0.1602792293, 0.4382282197, -0.6603542566, -0.1854121238, -0.7110162377, -1.050206542, 0.3033640385, + -0.0090368362, 0.9971413612, 0.0437622704, -1.6310248375, -0.8269742727, 1.7787942886, -0.7838104367, -0.0933950394, + 0.7300506234, 0.863971293, -0.7480256557, 1.2835432291, -0.9399489164, 0.738550961, -1.0714541674, 0.4192541242, + 1.2823365927, 0.4535315037, 1.6193950176, -0.8308219314, 0.6912407279, -0.2242636681, 1.3361150026, 0.6657164097, + 1.0476800203, -0.3936673701, 0.3589158058, -1.9339230061, 0.4487364888, 2.07239604, -1.0328774452, 0.7694115043, + 0.2298396081, -1.9235595465, 0.8481762409, -1.0481160879, -1.7839934826, 1.8505026102, -0.1471647471, 1.4117530584, + -0.4248147607, 1.0637511015, -1.6170943975, -0.1204279289, -0.8135151863, -0.991651535, -1.3610657454, 0.2157028317, + -0.4446689188, 0.737796545, -1.4382053614, 0.8609056473, 0.4337145686, 0.4578846097, -1.0002191067, -0.2169005722, + -0.3418893814, 1.4400826693, -0.666333735, -0.9091744423, 0.3776062727, 1.3034206629, -0.6550186872, 0.0032101073, + -0.8028377891, -1.3056483269, -0.1703900844, 0.693892777, -2.5968184471, 0.6109979749, -0.1903804541, -1.7227438688, + 0.0623724312, -1.3457913399, 0.399965167, 0.4954300821, 1.3090932369, -0.4598393142, -0.6244497299, 1.5473086834, + -0.1307564676, 1.5282249451, 0.0975896195, 1.385881424, -0.4262283444, -0.0787541643, 0.0616688319, 0.5138702989, + -0.3498030901, -1.3233053684, 0.4028116465, 0.3263849616, 0.5358191133, -1.7932841778, 0.9994078875, -1.3617011309, + 1.1623231173, -1.7890124321, 0.6985490918, -1.1428382397, 0.2147274613, 0.1396360397, -1.1729005575, -0.6266290545, + 1.2859871387, -1.0260407925, -0.5826871395, -0.1028865278, -1.794005394, 2.0454301834, 1.0318255424, -1.1083452702, + -0.4782355428, 3.4777047634, 2.4325971603, 1.7189693451, -1.4776905775, 0.5881302357, 0.5027113557, 2.8661079407, + -0.1098669693, -0.1802531779, 1.1672160625, -0.0681959763, -0.5658228397, 0.3528211415, 1.2640615702, -0.4119260609, + 0.4474448264, -0.6144564152, -0.367321223, -0.0331863575, -0.232552439, -0.5525498986, 0.445153892, 0.3916987777, + 0.0216711983, 0.8088118434, -0.2224570215, 0.5602177382, -0.8138303757, 0.0004522767, 1.0792688131, -2.1361529827, + 0.9336476922, 1.6088411808, 1.8209517002, -0.8839716911, -0.2459857762, -1.2426134348, -0.1604559571, 0.85432899, + -0.8487345576, 0.7471719384, 0.0556920283, 0.4832492471, 0.7741348147, 1.4826248884, -0.9840801358, 0.7220378518, + 1.0715200901, -0.4242345691, 0.0419250503, 0.8400822878, 0.0718306378, -0.2302375734, -1.6227520704, 1.2532012463, + -0.6595457196, 1.4351598024, 0.4085188508, -1.9150269032, 1.5044716597, -0.0597980022, 1.1048128605, -0.487814337, + 0.3595606387, -0.8408216834, -0.6972226501, -1.1642152071, 0.9077614546, 3.1851241589, -1.2781811953, -0.9502065778, + 1.4101806879, 1.1578328609, 0.575532794, -0.3855011463, 0.139449358, 1.5561326742, 0.3201376498, -0.3746150136, + -3.3304371834, 1.5891109705, -0.4015725553, 1.0671237707, 0.4332732856, 0.551548183, 0.8586447835, 0.1360096633, + -0.0430612415, 0.8356793523, -1.897034049, 0.5594943166, 0.8892461061, 1.5231126547, -1.9689277411, -0.47914657, + -0.1135723814, -1.3317320347, 1.2973388433, -0.7804918885, 1.8386099339, -0.463948369, -0.1304014027, 0.4642805159, + 0.4224203527, 1.5378631353, -0.6809688807, -0.7566910386, -0.8838561773, -1.6089427471, -1.5269782543, -0.5458895564, + -0.0781098157, 2.1578493118, -0.1167186201, -0.763681829, -0.575081706, -1.4051170349, 0.8595709205, 0.2047751695, + 0.5402824283, 0.0225952975, 0.5965875983, 0.0429086573, -0.8807626963, 0.2503642142, -0.2607371807, 0.7006023526, + 0.1024034098, 0.2675665021, 0.8997215629, -1.3800114393, 0.6278210282, -0.6009278893, 0.0229070876, -0.8209497929, + 0.6459999681, -1.365167141, -0.9422188997, 0.8445447087, -0.5556010604, -0.2866741419, -0.698892355, -0.2834370732, + -1.558445096, -0.3284163177, -0.223573491, -1.2259905338, 0.5285528898, -1.0578813553, 0.3370731175, -0.1701500416, + 0.2106822878, 0.1954178661, -1.2928462029, -1.0101048946, -1.0162965059, 0.7101376653, 1.1929751635, 0.2930506766, + 0.328364104, 1.8373104334, 0.1537463218, 1.6340095997, 1.5657008886, -0.165584296, 1.236795187, 2.0852239132, + -0.3394646943, -1.6677970886, -0.1699476838, 0.1307020038, 1.3757307529, -0.1364614964, 0.5837905407, -0.6506878138, + 1.0382732153, -1.1101716757, 2.2023341656, -0.5978506207, 1.2223081589, 0.0622529648, 1.0693994761, -0.1176077351, + -0.5627841353, 1.407656908, 1.7500611544, 0.6664909124, 0.2402775288, 0.5856772661, 0.186956659, 1.1902452707, + -0.3557678163, -0.2289677262, -0.5311463475, -0.7184414268, 0.8175365925, 0.2107467204, -0.5429624319, -0.1168661341, + 2.7603781223, 0.7776145935, 0.1007762924, 0.1165065393, 1.5572880507, 0.3648286164, 2.0247426033, -0.3560695946, + -0.0204400718, -0.7988411188, -0.9985968471, -0.5758203864, 0.2325834781, -1.2333204746, 1.3030353785, -0.7864224315, + -0.5838130116, -1.3188313246, 0.25025931, 1.2273973227, -0.2414512187, -0.890068531, 0.4520162046, 0.5013954639, + -1.2339198589, 0.5234656334, 1.8722342253, 0.2422109544, -1.3943357468, 1.5739291906, 0.3023069799, -0.1267141402, + -0.453445226, 0.7923907638, -2.1231665611, -0.2892504334, -1.2547494173, 1.1192709208, 0.1841019541, -0.5269345045, + -0.3538885415, -0.3898421228, -1.295268774, -0.7927324176, 1.1888612509, 1.382904768, 1.0012235641, 0.150917992, + -0.5995969176, 1.071739316, -0.6755110621, 1.8635855913, 1.7817964554, -1.5924193859, 0.7871559858, 0.182264328, + 0.6299715042, -0.4798375964, -0.2566851377, -0.8125913739, 0.0916184112, 0.3510672748, 0.7465915084, -1.2982705832, + 0.4566431642, -1.4501985312, -1.0551677942, 1.1857924461, 0.2242699265, -0.2082041055, 0.1747808009, 1.4196221828, + -0.8689292073, -1.552716732, 0.0466211066, 0.3829758465, 1.4496682882, -0.6000432968, -0.2342979163, 0.9764523506, + -0.1101170778, -0.274309963, 0.5450106263, -0.6299778223, -1.0088422298, 0.5787731409, 0.6363965869, -0.9875950813, + 0.4465334415, 1.6913824081, 0.8224819303, 0.6353470683, 0.6847267747, -0.8218975067, -1.789312005, -0.3205640018, + 1.1568148136, -0.6012837887, -0.0253048092, -0.8224580884, 0.436873436, 0.592203021, 0.2948924601, 0.471137315, + 0.2339244038, -0.8675713539, -0.1623468995, 0.2907239795, 0.0648862347, -0.7679846883, 0.4781250954, -0.9584442973, + 1.2950092554, 0.4279106259, 0.1744094789, -0.2890577018, 0.4377071559, -1.0612857342, 0.6737443805, 1.4462653399, + -0.0192514602, 0.4609615207, -1.7821609974, -0.3013353348, -0.3335744143, -1.1731162071, 1.3955233097, -1.2123579979, + 0.2251206934, 1.1979632378, 0.088976793, 0.5139861107, 0.9769540429, 0.375487268, 0.7002015114, -0.4718477726, + -0.956174612, 1.3625870943, 0.5210314989, -1.7651660442, -0.5209172368, 1.1049113274, 0.0181649495, 0.4430385828, + 0.0258633532, -1.1045073271, -1.0388607979, -2.284526825, 0.8429036736, -1.1021239758, -0.2099017054, -0.6958201528, + 1.9615095854, -0.3146707714, 0.7117929459, -0.9054128528, 0.3786839545, 1.2535066605, -0.5864236355, -0.6019744277, + 0.3552685678, -0.7152664661, -1.2186499834, -0.8128777146, -0.1254124641, 0.5544507504, 0.803324461, -0.0788029656, + -0.3765355647, -0.1530294567, -0.0445062034, -1.0340093374, 2.1138308048, -1.4381253719, -0.364176929, -0.7461310029, + 0.5013814569, -0.4317185283, -1.5411124229, -0.0315037817, 0.1206132025, 0.3322246075, -0.3178224564, -2.4873731136, + 0.9532303214, -0.2243309021, 0.8475925922, -0.1884335577, 2.1482484341, 0.1499400139, 0.5643538237, 0.4252497256, + -1.0068868399, -0.1776017845, -0.861446023, -0.3621585071, 0.3836019039, 0.9026619196, 0.9432954192, -0.3222702444, + -0.6358183622, -0.6205145121, -1.2305152416, -0.145920679, 0.9727852941, -0.6101299524, -1.1514422894, -0.5444167256, + 0.2890828252, -0.1478310674, -1.2646784782, -0.7198884487, 0.7411797047, 0.3236621618, 0.6102467179, 1.9273406267, + -0.7630124092, -0.8950296044, 0.1038967371, 1.3054035902, 1.1023359299, 2.0166347027, 1.2310870886, 0.3453706503, + 0.4032297432, -0.3820646107, 1.432798624, 1.2221440077, -1.3450983763, -0.6113471985, -0.0736481622, -0.4696511924, + 0.0348328836, 0.2735553682, -1.75798738, -0.2284794301, -0.2847909033, -1.1847519875, 0.9780002832, -0.027945077, + 1.1050629616, 0.5406913161, -0.4539557099, 0.3432274759, -0.5386041999, -2.3486204147, 1.0494381189, 1.0514642, + 0.1160023734, 0.4832822382, -0.0234396216, 0.0183158182, 1.3490015268, -0.5867910385, -0.593444109, 1.64184618, + 0.8020620346, 0.3180578947, -0.0109635685, -0.8504745364, -0.3389580846, -0.4799004793, 0.2578036189, 0.4269354939, + -1.3231627941, -0.575404346, 0.1770341992, 1.9017140865, 0.4532558918, -0.7606176138, 0.7406585813, -1.0882092714, + 1.803142786, -1.3217358589, 0.4403271973, 0.3200185895, -0.0844190046, -1.0422834158, 1.3751612902, -1.3435511589, + -2.2676715851, 0.1229116991, 0.4220400751, 0.8152249455, -0.5771619678, -1.5192883015, -0.1184898242, 0.0107239718, + -1.6067227125, 1.5956927538, 0.0263506193, 0.966971755, -0.8889227509, -0.4053593278, 1.3851294518, -0.4103517532, + -1.2005337477, 0.8040002584, 0.069751285, 0.6278099418, 1.3422721624, -0.1635767967, -0.1250185519, -0.3778596222, + -1.0309101343, 0.5122585893, 0.3585168719, -0.3668381572, 0.7736611962, -0.5901617408, 1.0048699379, 1.6593602896, + 0.0736119524, -0.5228585601, -1.1776105165, -1.26935637, 0.7466336489, -0.4147734344, -0.6222800016, -0.436966002, + 1.1900970936, -0.0045385598, -0.3916423321, -0.4234701991, 0.4515590668, 1.6646592617, -0.7858273387, -1.0369464159, + -0.8603183627, 1.8155955076, -0.968609035, 0.205502823, -0.0671775788, -0.1541100144, 0.1235477552, 0.6986100078, + 1.5323183537, 0.3527896404, 0.5008907914, 2.1498534679, 0.352080524, 0.8896867037, 2.5267851353, 1.0206768513, + -0.83513695, 0.4967375398, 0.8105723262, -0.7931277752, 0.2910664976, -0.796767652, 0.2498087585, 0.3448672295, + -0.1164075732, 0.0368722863, 1.3828399181, 0.4213814735, -0.9003941417, 0.5536766052, -0.418063879, -0.4147278368, + -0.9282360077, -0.7860546708, 1.1377804279, 0.4159342051, -0.7434610724, -0.7378995419, -0.0775714889, -1.1062474251, + -0.1626705676, -0.0320903845, -0.6710093617, -1.9599610567, -1.0496373177, 0.4051431119, -2.0050468445, 0.3016331196, + 1.1520593166, 1.2890785933, 0.6122150421, 0.4631689787, 0.2665107846, -2.0319108963, 1.7829045057, -0.5972828865, + -0.2010582238, 1.9431426525, -0.1263195872, -2.0065937042, 0.9118897915, -0.4932822585, -1.6785792112, 0.7633743882, + -1.4086085558, -0.7630506754, 2.4220027924, -1.4050699472, 0.3170969188, 0.3332512081, 0.5363234282, 1.2329015732, + -1.1386669874, 0.7243200541, -0.5739594102, 1.1940883398, -1.3103320599, 0.0189716071, -1.0934224129, -0.6630554199, + 0.6524068117, 0.4000760615, -0.4352589548, 1.88649261, 0.180518344, -0.5843188763, 2.0612359047, 0.2389136702, + -1.0740573406, -0.3438945413, 0.5787284374, 0.6672785282, -0.3425982594, -0.2763700783, -0.0430908315, 0.3072268665, + 0.4272223711, 0.746332109, 2.30316782, 1.1491247416, 0.7463536263, 1.6505769491, -0.7130047083, 0.448415041, + 2.5032739639, 1.5361375809, -0.0852901042, 1.7603957653, -0.7834419012, -1.5477027893, -1.2571730614, 1.3132101297, + 1.6227086782, -0.1173110008, 0.7305071354, 0.3547957242, 1.1275627613, -1.3428343534, 0.1347589195, -0.2234453708, + -1.6528010368, 1.1485866308, 1.3285199404, -2.2826619148, 0.2097360492, 0.7691443563, -0.3663109541, -0.9105324745, + -2.1862375736, 0.4142344594, -1.2459869385, -0.5919961333, -1.1263803244, -0.7219035625, -1.2844762802, -0.6319314837, + 0.4255679846, -0.9710791111, -0.1546536833, -0.9671045542, 0.84084934, 0.4944689572, -0.9499318004, -0.9606438875, + -1.6236588955, -0.0765073076, 0.1454095095, -0.6725363731, 1.5028852224, 0.3382230401, 0.9947757721, -1.5230675936, + 0.3305849135, 1.0095059872, -1.232318759, -0.9129067063, -0.649097085, 0.7627770901, -1.5042232275, 1.9205620289, + 0.6990779638, 0.3981493115, 1.7094851732, -0.8547058105, 0.6071660519, 0.3208642602, 1.3405076265, -0.8251224756, + 0.7542603016, 1.5279054642, -0.0644014403, 0.0308947098, -0.4144746959, -1.2328224182, 1.3450195789, 0.5506920218, + 0.7623227835, 0.4588803649, 2.4532387257, 0.4284676611, -0.6673672199, -0.7856223583, 0.679823041, 1.3754965067, + 1.2486560345, 0.8557427526, -0.657880187, 2.8154249191, -2.0665171146, -0.8970668316, 0.8705096245, -0.5161067843, + -0.877473712, -1.3747942448, -0.0044820942, -0.0629592091, 0.8383932114, 0.1018836051, 0.2315552235, 0.8842407465, + 1.9258217812, -0.3826536238, -0.7059099674, -0.9088483453, -0.0775755346, -0.8568040133, 0.6119330525, -1.1394847631, + -1.072956562, 2.5123028755, -1.1320472956, -0.0720144957, -1.3061287403, 0.0605295226, 0.5201559067, -0.7216553092, + -0.0817440078, 0.4655059576, -1.005934, 1.6584295034, 1.3138953447, -0.1685477644, -1.7573693991, -0.5177462697, + 0.256593734, -0.7753594518, -0.3755358458, 0.9658132195, -1.6226822138, 2.0549082756, 1.1139340401, -0.4460828304, + 0.3770333529, -1.0984185934, -0.79142946, -0.7182283401, 0.8725944757, 1.4336870909, 0.1247830093, -2.4568533897, + 0.8807242513, 1.4794603586, 0.5188699961, 0.1264361292, -0.909968257, -0.3541872203, 1.0382727385, -1.1467587948, + 0.0937129781, -3.08796525, -0.7070456743, -0.8758177161, 0.7819408178, -0.7893208265, 0.3356752098, -0.3563073277, + 0.4893903732, -1.0363898277, -0.9055857062, -0.733756423, 0.1480658501, 0.9461278319, 0.3862171173, -1.0495040417, + 0.9934561253, -0.2928678691, 2.2781779766, 0.4375535846, 1.4886761904, -0.2329892665, 1.160622716, -1.1704735756, + -0.8371050358, 0.4440965652, 0.0336679667, 1.2123416662, -0.3476849496, 0.5047299862, 1.0939006805, -0.1639223248, + -1.1171123981, -0.8182387948, 0.560672164, -0.4868011773, -0.162299186, -1.1784236431, -0.0316150524, -0.6546902657, + 1.9915369749, -0.1884418726, -0.1821149737, -0.5000926256, 1.5627294779, 0.5795538425, 1.721906662, 0.3575980067, + 0.7396416664, -0.7974137664, 0.1111887917, -1.3111822605, 0.168863669, -1.2101415396, 2.0626072884, -0.1517615914, + -0.1261129677, 0.5988250971, 0.3151803315, 0.2292727828, 1.5950623751, 0.7607192397, -0.6130860448, 1.2753077745, + -0.0473849252, 1.0907490253, -0.5991789103, 1.1112835407, -0.7966700792, -0.9286405444, 1.1475811005, 0.7448164821, + -1.0517472029, 1.881509304, 0.4007554352, 0.5530241728, -0.3934260905, -0.0581542328, -1.2024121284, -1.1866624355, + 0.4203956425, 0.9341752529, 1.2243565321, 0.8899989724, 0.3466911018, -0.7389758825, -0.9940132499, -1.0827097893, + -0.6211391687, 0.0189784765, 0.6920895576, -1.3577948809, -0.1852061152, -0.3256109953, -0.3312273026, 2.7818863392, + -0.6032305956, -0.5881502032, -0.2108903974, 0.9609686136, -1.7761542797, 0.1638919264, -1.8034422398, 0.343854785, + -2.0366148949, 1.2626676559, -1.0085458755, 0.8398509622, 1.1671663523, -1.6237409115, 1.2003210783, -0.6494108438, + -0.3809467852, -0.8366717696, 1.0897408724, 0.7005752921, 1.8595799208, 0.7068119645, 0.2377082705, -0.4191710055, + -0.0960142314, -0.4157134593, -1.4508297443, 0.6521006823, 2.3216221333, 0.6430325508, 1.4736698866, -0.4491530657, + 1.0629155636, -0.9583804607, -0.6451090574, -0.6868199706, -0.04339182, 0.9207156301, 1.4857054949, 0.392095089, + -0.4053091705, 0.8437995315, -1.5179128647, 0.1888910085, 0.0703740716, -0.7147838473, 0.2936773896, -1.1163834333, + 0.4440954924, -1.5620125532, -1.4867972136, 0.9728970528, 0.0287208781, 0.2518751621, -0.8563625813, -0.0962809995, + 0.9173402786, 0.1593800485, 0.3545618653, -0.5275490284, -0.1848464012, 1.1037555933, -1.7516676188, 1.1288124323, + 0.4776148796, -0.0878350437, 0.8084073067, -0.5648819804, 1.1433855295, -2.9104449749, 0.8359450698, 0.0287205018, + -0.3140828609, 0.2962246537, 2.6138598919, 1.9440122843, 0.2640841007, -0.9142881632, -0.5235984325, -1.0183387995, + 0.2797614336, -0.6935437322, -0.2669579685, 0.8215245605, -0.2807157934, -0.4905641377, 0.4833571315, 0.2829817235, + 0.5185962915, 0.6601308584, -0.3351995051, 1.064953804, 0.1437657326, -0.1996699721, 0.1168802828, 1.0141957998, + 0.136444062, 0.6416521668, -0.0714805797, -0.1246618554, 0.648221612, 0.7308468819, 0.2386373132, 1.0028398037, + 0.5547579527, -0.5872223973, -0.7867373228, -1.1379771233, 0.0934178531, -1.1745666265, -0.7475016117, -0.5521036983, + 0.1610332578, -1.022264123, -1.0741324425, -0.068106018, -0.5505965948, -0.0340255834, -2.0789461136, 1.2974512577, + -0.2434522808, -0.6320980787, 1.6777137518, 0.202044189, 0.7013676763, -0.9742774963, -0.4643732905, -1.7642954588, + 0.2217412889, -0.8830285072, -1.1129447222, -0.6823812127, 1.3527050018, -1.2479234934, -1.7996045351, -0.8925056458, + -0.0426734425, 0.5319902301, 0.2391276062, 1.0110605955, -1.4177103043, 0.4677368701, -0.4861982763, 1.6502017975, + -0.2858231962, 0.4730424285, 0.4991550446, 1.8836057186, -0.4640003443, -0.0351408608, -0.4028859138, -0.2978712618, + 0.0881469771, 1.7128058672, 0.0741602257, -2.0762367249, 0.6053909063, -1.3824832439, 0.5659181476, -2.0131797791, + -0.3630668521, 0.6377583742, 1.125579834, 0.148271665, 0.0555110313, -1.0066103935, -0.0993747562, -0.5288520455, + 1.3735204935, 0.4501582086, 0.9103261232, 0.5915299058, 0.8719922304, -0.1844073534, -0.4059509635, -0.7417193651, + -1.1776884794, -0.2048167139, -0.7765574455, -0.3557467163, -0.4653972089, 0.115552187, -0.034224432, -1.6729363203, + 1.5951782465, 0.39363873, 2.1581971645, 0.0029275578, -0.2868529856, -0.9359773397, 1.2794549465, 1.4388250113, + -0.28051579, 0.1168797389, 1.3458018303, 1.0483114719, -0.6029849052, 0.7616730928, 0.5633711815, -1.0731381178, + 1.0358542204, -0.774164021, 1.062739253, -0.4310510159, 0.1969968379, -1.5273967981, 0.9693744779, 0.4679141045, + -2.0622494221, -1.494182229, -0.2936666906, -1.3504440784, -0.4829608202, -0.4429127276, 0.8962433338, 0.4110181332, + -0.7450675964, 0.3003093004, -0.1053996682, 0.5656231642, 0.0190361906, -0.5192342401, 0.3490352929, -0.2058995962, + 1.3725743294, -0.8968298435, 0.5423145294, -0.8962261677, -0.149121955, -2.027538538, -0.6608038545, -0.9174212813, + -0.3269410431, -0.6984471083, 1.6944645643, 0.4648699462, -2.1589312553, 0.0426462181, -0.4002126157, -0.9844839573, + -0.9373098612, 0.3330574632, 0.8121154308, 0.1654017717, 0.0265124217, 0.895848155, 1.0384033918, 1.331289649, + 0.2691825032, -0.5273260474, 1.1580491066, 0.913648665, -1.8261531591, -1.6294533014, -0.4599237144, 1.3166241646, + 1.2717188597, 0.3420768678, 0.1444726288, -0.9680743217, 0.4697493017, 0.8182046413, -1.4236667156, 0.7308368087, + 1.0863107443, -1.4559316635, -0.0180493183, 0.0013391395, -1.5703587532, -2.0040662289, -0.1724464595, -0.7469660044, + -1.5486024618, 0.9595509768, -0.974363029, -0.063914299, -0.3483835161, -0.5184774995, -0.1823514253, 0.2897956967, + -0.257049799, -0.018302558, 0.1666794717, -0.4107077122, 0.3243245482, -0.6374425292, -1.3727964163, -0.7992866039, + 1.1616351604, -0.0549143553, 0.0692056417, 0.4817972779, 0.3330696821, -0.3786138296, -1.9377900362, -0.8723055124, + -1.9915663004, -0.724067986, -0.548091352, -0.021815272, -0.1139964089, -1.6564424038, -0.9848123193, -0.5869332552, + 1.3057488203, 1.0492138863, -0.312911272, -0.9047678113, -0.7177250981, -1.2049781084, 1.3314702511, -0.6231637597, + 0.7844091058, -0.0176781621, 0.4116369486, -1.3127673864, -0.2670100331, -0.0723978579, 1.0006428957, -1.9221795797, + -1.2662967443, 0.532976687, 0.0479580536, 1.1082743406, -0.0548312664, -0.8269295096, 1.1963032484, -0.2248819619, + -1.2792636156, 0.4042378664, 0.0060892166, 0.2407629043, -0.286362797, -1.7510541677, -0.8826270103, -0.1805585325, + -0.8399214149, -0.3694585264, 0.6691579819, -0.6126208305, 0.5864830017, 0.3455734253, 1.098271966, -1.2218780518, + -0.7412814498, 0.6595743299, 0.6852849722, -0.4938407838, -0.8290623426, 1.8494502306, 0.7113271952, -1.3318347931, + -1.2668334246, 0.6168457866, 0.0138242068, 2.3361804485, 0.0133694801, -0.9318174124, 1.0154223442, -1.8149859905, + 0.1063761935, -0.4912840724, 0.0053320178, 0.1622054279, -0.372056812, -1.706153512, -0.3411099017, 1.8075840473, + -1.4172304869, -1.3801350594, -0.1177887693, -0.4706535637, -0.5100216866, 0.0099745048, 1.0853533745, 0.3263893127, + 0.0064063426, 1.8728448153, -0.5153175592, -0.0248616636, 1.0729645491, -0.9651572704, 1.2770721912, -1.1947435141, + -0.4683704376, -1.5828979015, -0.2075870931, 0.7596347928, 1.1891981363, -0.2871383727, 0.7696259022, 1.1756484509, + -0.2555998862, -1.1806615591, -1.5777649879, 0.7371015549, -0.8200165629, -0.34796682, 1.5302962065, -0.8369179964, + 1.9417058229, 0.3632695973, -0.5283840299, -1.4799474478, -1.0299297571, -0.3006336093, 0.7646048069, -0.7382662892, + -0.0858026668, -2.0297603607, 0.7612405419, 0.4500703812, 1.1386395693, 1.041593194, -0.652931571, -0.1752320975, + -0.0934556127, -0.3674602807, 1.1684161425, 1.7406518459, 0.214056477, 0.1849590987, -0.4445253611, 0.9117878675, + 0.6770923138, 0.8259384036, 0.0250431057, -0.6785590649, 1.5031665564, 0.4678463638, -0.296120137, -0.83322227, + -1.7620338202, -0.5066124797, -1.4213819504, 0.0325794555, 0.4598464966, 0.8975044489, 0.7793223262, 0.2708227634, + 0.3689299226, -0.2866435945, -0.4612148404, 0.2356104404, 0.4840772152, 0.0035614318, 0.561660409, -1.1055561304, + 2.8946905136, 1.2669999599, 0.4352328479, -0.6449033618, 1.0168118477, 0.1424993426, -0.6114996076, 0.1845914721, + -1.2095587254, 0.1187560558, 0.1327622831, -0.9325071573, -0.0071629351, 0.8303387761, -0.0023879316, -0.4078947604, + 0.511690855, 0.5126677752, -1.8852918148, -0.6545630097, -0.8021213412, 1.7759143114, 0.0790987164, -0.037274573, + -0.5091186762, 0.3631534874, 0.156399563, -1.176223278, -0.2444291711, -0.954066813, 0.8484722972, -0.209448114, + 0.2584297061, 0.4090232253, 2.4077796936, -0.6442091465, -0.35126701, -1.6794028282, 0.615796268, 0.9134595394, + -3.0511646271, -0.1610290557, 0.0838241577, -0.2765303552, 0.5775899887, 0.5077181458, 0.6141081452, -0.2548968792, + -2.2971007824, -0.4871230423, -0.7298045158, -0.291554749, -0.8250328302, -2.1933531761, 0.5092428923, -0.9196913838, + -0.2856418192, 0.4852777123, -0.5238398314, -0.8249314427, -0.2213008106, 0.4922359288, 0.0046398826, 0.0410495177, + 2.0978188515, -0.6671367288, -0.6185826659, 0.9899863005, -1.026827693, 0.9838751554, 0.1415936202, 0.960201323, + -0.4019086659, 0.0917325616, -1.7731301785, -0.6001939178, 1.4872521162, -2.1950342655, 1.4718630314, -0.4139128923, + -0.9561069608, -0.8113186955, 0.3326387703, 0.8214855194, -0.2038237303, 0.1721137315, -1.4140814543, 0.8006810546, + -1.1539144516, -0.4913604856, 0.0820094123, -1.4642955065, -0.1441533267, 0.3502728939, -0.5427587628, -0.1549838632, + 0.9814139605, 1.6057529449, -1.7895412445, -0.5796220899, 0.1910269558, 0.1117242649, -0.8288728595, 1.0306375027, + -1.0849578381, -0.6961807609, -0.8261684179, -0.1974864304, -0.8071389794, 0.9624972939, 1.9254288673, 0.3915759921, + -1.8992302418, -0.6777492166, -0.3872167468, 0.3622063696, -0.8133463264, 0.4327911437, 0.5757126212, 1.9948111773, + -0.8023193479, 1.4258333445, -0.3936565518, -0.7623519897, -0.1646928489, -2.381875515, -0.3824919164, 1.1486035585, + 0.4143595994, 0.5045929551, 0.26773417, 1.3893061876, -1.6509420872, -0.1595229954, 0.5341352224, 0.5419927239, + 0.5675623417, 0.0678644925, -0.4693374336, -0.2899969816, -0.2941041589, -0.3687418997, 1.0642687082, 0.3990949392, + 0.2112073898, 2.1691763401, 2.5314116478, 1.1707247496, 0.7853136063, 0.828122139, -2.0882747173, 0.2841241062, + 0.3198890388, 0.1984391659, -2.4289112091, 1.0632315874, 1.9254181385, -0.216633141, -0.5206612349, 0.3861836493, + 2.1343843937, -0.931689918, -0.452557683, 0.0293869525, 1.5127466917, -0.5325924158, 0.2071255594, 0.655985415, + -0.4750492275, 0.6517692208, -2.026058197, 0.5454990268, 0.9007616639, -2.1234264374, -0.6924746037, -0.2750160992, + -0.7721719146, 1.6402645111, 0.1960601807, 1.0715852976, -0.8867476583, -1.2654846907, 0.8506244421, -1.002618432, + 0.423980087, 0.0143493805, -1.0331511497, -0.2458608299, -0.2627170682, 2.2830805779, -0.4507263899, 0.4234290123, + 1.9715867043, 1.0045151711, -0.8947780132, 1.0483188629, -0.2448585927, 0.9080960751, 0.6717668176, 0.7670707107, + 2.6760594845, 0.2887377441, -0.5765333176, -1.3535066843, -0.1563234329, -1.6242492199, 0.8874552846, 0.4395448565, + 0.2620094121, 0.8149400353, -0.7656787634, -0.1232830957, -0.6337431669, 0.0293763019, 1.4243355989, 1.0572086573, + -1.8027933836, -0.5571980476, -0.312403053, 1.2649337053, 2.0032932758, 0.9319395423, 0.1501328796, 0.1547182649, + 0.076401636, 2.4216063023, 0.7080580592, 0.2585445046, -0.2951288521, 1.159072876, -1.4281768799, -0.6427973509, + 1.077891469, 1.3738418818, -1.0305179358, 1.283449173, -0.111188449, 0.041600652, 1.2782590389, -1.3953489065, + -0.2880483568, 0.203002274, -1.4335784912, -0.8353443146, -0.7202455997, 0.5462498069, 1.4243865013, -0.1032523811, + -0.04415318, 0.1812570095, 0.6535425186, 0.7359706759, -0.3278496861, 1.6425333023, 2.3137261868, -0.1360592395, + 0.5812934637, -0.6448676586, 0.0685226098, 0.8798252344, -0.7275282145, -0.6837694049, 1.217987895, 0.5052300096, + -0.1817120165, 2.7077167034, 0.5897852778, 0.0560361706, -0.2262458354, -0.1569620222, -0.8156437278, -2.8309299946, + -0.0347006284, 2.3700158596, -1.451705575, -0.7827415466, 0.2200433016, 0.6763939261, 0.5266736746, -0.3205535114, + 0.4175000787, -1.4401388168, -1.2638221979, -0.0063566575, -0.4596130848, 2.0484826565, 2.6739189625, 0.1921385825, + 0.8656622171, -0.7989099026, 1.2951737642, 0.5948476791, -1.1622223854, -1.0827726126, -0.6607543826, 1.0801876783, + 1.7353651524, 0.2039402127, 0.4578662515, 1.4513297081, 0.678201139, -1.0781478882, 0.922752738, 0.838958919, + -0.3721253276, 1.6220294237, -1.571125865, 0.509218812, 1.677267909, 0.2103672624, 0.3513631523, -0.6458117366, + -0.1160704643, 2.5399868488, 0.2986964285, 0.7530531883, 2.7717247009, 1.3016248941, -0.5547922254, 0.812480092, + -0.5440471768, 2.9482123852, -1.9910891056, -1.2753846645, -0.802262485, -1.4422289133, -0.5684272051, -0.132527858, + 0.643319726, -0.0040892162, -2.0867819786, 0.3624523878, 1.7563529015, 0.1436444223, -0.7461550236, -1.4902784824, + 0.2751983702, 0.2716933787, -0.5269842744, 1.3409408331, -0.5586332083, 0.5571196079, -0.4478425086, 1.0341912508, + 0.5109900236, -0.9873884916, 0.0708701387, 0.3049991429, 0.5304082632, 0.1405647397, -1.0756629705, 1.1812801361, + 1.675404191, 1.539195776, 0.154172793, -0.3437381983, 0.8482227325, -0.1725202948, 0.8681633472, -1.2652460337, + 0.9696620107, 1.318757534, 0.1618376225, -1.4064910412, -0.4977366924, -2.9630827904, 0.2724413574, 0.5373820066, + -1.1703877449, 0.271938771, -1.054997921, 1.4473180771, 1.9692100286, -0.1396738887, 1.2972766161, 1.3983153105, + 0.7203134298, -0.4064352512, -0.5069192052, -0.7329676747, 0.4564698935, 1.4903695583, -1.5688288212, -0.2548439503, + 1.0869340897, -2.3693585396, -0.0668379068, -0.276605159, -0.568567872, 0.1007213444, 0.4818153977, 0.3051174581, + -0.6083016396, -0.4800639451, 0.2737148702, 1.964135766, 0.9281412363, 0.3207195699, 0.2103534937, -1.6923233271, + 1.1626750231, -2.2308335304, 1.466296792, -0.057854183, 1.0219566822, 0.8956917524, -0.4066852629, 0.6047781706, + -0.2009098828, -0.0700096786, 1.5064666271, -0.0695334747, -0.8002229333, 2.0655736923, -1.874896884, 1.4135584831, + -0.1391232759, 1.5362677574, 0.2097577006, 0.2475161254, 0.9883912206, -1.5831539631, 0.437376976, 0.3146182895, + 0.6461459994, -1.4481978416, 0.4126372039, 0.2698713243, 0.2971876562, 0.6936231256, -1.7687585354, -0.1024047658, + 1.8644307852, 0.1501193047, 1.4666852951, -0.0993625149, 0.8320145011, 0.2680338025, 0.9386171699, -0.4379406571, + 0.0308498964, -0.5973451138, 0.1201213524, 1.8185228109, 1.2896347046, -0.7865766883, -1.1671062708, 1.0264364481, + -0.4385924637, 1.1909672022, -0.2365868241, -1.2961139679, 0.7524974346, 0.2822886109, -0.8649634123, 0.0341063626, + -2.801232338, 1.8497134447, -1.4406055212, -0.8967682123, 0.473724544, 1.4397727251, -1.7417879105, 1.3006533384, + -0.5665988922, -0.8679270744, 1.1672435999, 0.8426421881, 0.5777239799, -0.0019734991, 0.2628566623, -0.6765850186, + -0.9454251528, 0.696310997, -2.0113916397, 1.2220158577, -0.3644271493, 0.3940259516, -0.4764729738, 0.6744356155, + 0.4133459032, 0.7129043341, -0.1390728951, 2.4798042774, 0.4449064732, 1.0364000797, 0.3874957561, -0.2127955854, + -2.7277810574, 0.8964817524, -1.1030762196, -0.9547590613, -2.6085407734, 0.8240185976, -1.002441287, 0.5572627783, + 1.22012043, 0.6980441809, -0.318287015, -1.0811100006, -0.8984940052, -0.9392712712, 2.1252901554, -1.0693789721, + 0.6708747745, -1.2933703661, -0.4726088941, 1.1888222694, 0.2114872038, -0.4543708563, -1.3946108818, -1.3129746914, + 1.8129559755, -0.6399911642, -0.3761229515, 1.0799931288, -0.8454584479, -1.1660637856, 1.2091180086, -0.0841020271, + -0.6888543367, -0.2568129599, 0.1405620426, 0.339440763, -1.4461472034, -1.1847535372, 1.1745417118, -0.5321114063, + -0.0360228755, -1.2600207329, 0.2216902971, 0.3386104107, -0.4858584404, -0.2366298586, -1.5974326134, 1.6561534405, + -0.065924041, -0.1518712789, -0.2975880206, -1.6202889681, -0.511151135, 0.4328710437, 2.2999274731, 0.1036824062, + 1.0497152805, -0.6470173001, 1.293528676, -0.8573095202, 0.2456389517, -1.6096886396, -1.516697526, 2.222905159, + 1.7827144861, 0.072299622, 1.2876883745, 3.446161747, 0.7335449457, 1.220422864, 0.053643126, 0.0680795535, + 0.1912591606, 1.3810964823, 1.6709645987, -0.5143932104, -1.089948535, -0.7233867645, -0.6821279526, 1.3069764376, + -0.293979764, -0.5712470412, -1.4585288763, 0.695281446, -1.2076721191, 1.0499768257, -0.0916740969, -0.0482324064, + -0.5674934983, 0.5605602264, 0.7756689787, -1.172837615, -1.5867017508, -1.2057219744, -0.2544875145, 0.2107366025, + 0.5100553036, -0.3370763659, -0.9028173089, 0.3074392378, 0.0235144868, 0.4365579486, 0.2447894067, 3.3895692825, + 0.7273297906, -1.8519378901, -0.7392191887, 0.6342939734, -1.165948987, 0.277831614, 3.2687973976, 0.8361719251, + 1.5480146408, -0.3752118051, -1.6580158472, -0.147878781, -1.514659524, 0.6179021001, 0.7550742626, -0.0943882689, + 0.775595665, -1.5603001118, 1.3169560432, -2.0728368759, -1.082521677, 0.6124401689, -0.2606959045, -1.1539610624, + -0.7913170457, 1.805934906, 0.4528495371, 0.1427119225, -1.534499526, 0.1410109401, 1.0175800323, -0.6247666478, + 0.9975888729, 0.1294607967, 0.1843679994, -1.1771456003, 0.9625459909, 0.9107032418, -0.7806379199, 0.3773173392, + -0.6000570655, 0.5929875374, 0.6998752356, -1.2417523861, -1.2792830467, -0.0448341966, -0.0431805402, -0.4964704514, + 1.9926270247, 0.7569426894, -0.7253473401, 0.1321403235, -0.0756466463, 1.7732292414, -0.3561931551, -0.3286891282, + 0.7018263936, -0.811992228, -1.1326178312, 1.7631685734, 0.4812170267, -0.1956695765, 0.4439469278, -0.2367948741, + 1.3929479122, -1.0372287035, -0.0327260606, -1.0332548618, -0.6647860408, 0.3720833957, 0.1972508132, 0.446526438, + 1.3022334576, -0.3980585933, -1.0992186069, -1.1671767235, 1.2631903887, 0.3971188068, -1.5323983431, -0.4032920003, + -0.6760450006, -0.209484756, 0.3652860224, -0.308165431, -1.8190023899, -0.1701465398, 2.2619700432, 0.2899451852, + -0.7703804374, -1.1064257622, 1.2357764244, -0.2967175245, -0.251801461, -1.568998456, -0.0665395111, -0.0862559229, + -0.9216248393, 1.2766802311, 1.5393574238, 1.0558137894, 0.0327471532, -1.6642035246, 0.8495980501, -1.7295979261, + 1.3477027416, 0.1795098633, -0.2721120119, 0.7435341477, -0.487387687, 0.5400074124, 0.4466554821, -0.152212128, + -1.0432454348, -0.0845364034, 1.7754360437, 0.3426231146, 0.4469730258, 2.3664221764, 0.6919433475, -1.1116325855, + 0.8461518288, -0.23830311, 0.8409350514, -0.7595874071, 0.3608250618, 0.8970346451, 0.2595388591, 1.0047931671, + 0.2540408075, -0.3400612473, -0.0989332497, -0.0843240842, -0.3543157279, -1.7633622885, -2.1017308235, 1.2253223658, + -1.1555352211, -1.7978022099, -0.3463512659, -0.0117409742, 0.5840808153, -1.0323102474, -0.4460191131, 0.0180029366, + 0.5165215135, 1.0082906485, 0.4918971956, -1.4555004835, 0.4997964203, -1.1232254505, 0.998737812, -0.8648818731, + 0.1568584144, -0.7785245776, -0.3282842934, 1.8889665604, 0.1762571484, 0.1230012551, -0.1905523986, -1.9035918713, + 0.6908513308, -0.4261215627, 0.1221275926, 1.0988082886, 0.0977977887, -1.7845711708, 0.7103321552, -1.1468501091, + -1.2720302343, 1.1274603605, -0.8638828993, -0.8295898438, -1.3732126951, 0.1212136671, -0.7930681109, 1.4917933941, + -0.471403569, 0.2895286381, 1.6895601749, -0.8141436577, -0.8679010272, 0.1823181361, 1.4328541756, -0.4204801917, + 0.2739147842, 1.2020156384, -1.8207857609, 0.0096109519, -0.8583530188, -0.9887015224, -0.1826705188, -0.6696085334, + -1.5090953112, -0.1405836046, 1.4303534031, 0.371781379, -0.6468277574, 0.6109654307, -1.4839514494, -1.3144893646, + -0.7689852715, 0.6979426742, -1.9050546885, 0.5673009753, 1.0644997358, 1.4237437248, 0.8367416859, 1.4612578154, + 0.935669899, -0.586897552, 0.8214159012, -0.3272928298, 0.4603173733, 0.0749733821, 0.1287813038, -0.2579364479, + -0.1763682663, 0.3552583456, -0.6590710282, 0.8675601482, 0.1804513335, 0.0760865286, -0.273011148, -0.7868251801, + -0.1163439304, 0.0811429247, 0.1231359839, 0.5234337449, 0.1796350628, 0.948948741, 1.6153148413, 0.9410284758, + 1.028447032, -0.9127117395, 0.2013400793, -0.4045197666, 0.7818467021, -0.3640500903, -1.8174712658, 0.4952382147, + -0.3121580482, -0.2593118548, 0.1520194411, -0.0602648407, 1.1699638367, -0.4944905341, 2.1621308327, -1.3320986032, + -1.6290991306, -0.7247669697, 1.2197005749, -0.4413643777, -0.3647455573, -1.7348531485, -0.3638899028, 0.0509795621, + -0.5163988471, 1.0410149097, 1.0232046843, -2.2675664425, 1.18896842, 0.4370892942, 0.64503932, 0.7288362384, + 0.1710212827, 1.3312356472, 1.3694489002, -2.7367355824, -0.8831370473, 0.4819488823, -2.1779723167, 0.5980419517, + -0.51206249, -0.3950772583, -0.9564168453, 0.3127147853, -0.3291445673, -0.9316582084, -0.6530855894, -0.5801360607, + -0.8719137311, 0.6725584865, 0.3189466, -0.9949298501, 2.0379827023, -0.3290540576, -1.4721562862, -0.5032038689, + -0.9637928605, -1.2094340324, 0.7158033252, -0.092706643, -1.2442517281, -1.0542521477, -1.1061631441, -1.238907218, + 0.5120587349, 0.224649027, -2.1872861385, -2.1402411461, 1.5952260494, -0.0812475979, 0.609364152, -0.5080390573, + -0.2121757418, 0.2089391798, -1.540004015, 0.3724039495, -1.1847088337, 1.513058424, 0.7076172829, -1.5021262169, + -0.6401950717, 0.4719422758, 0.0465151928, 0.58962363, 0.1516773552, -0.7396040559, 1.5477974415, 0.4146561623, + -0.0829181895, 0.0063156439, 1.1727257967, 1.2963408232, -0.4674797058, -0.1541069448, -1.4523546696, -2.4150819778, + 0.3667570949, 2.629178524, -0.4988396764, 2.0458302498, -0.074735105, -1.2224282026, 0.2986982167, -2.0429217815, + -0.958329618, 0.8893783092, 0.248131156, -0.5463197231, -0.1864299476, 0.8800899386, -2.0384750366, -0.5730707049, + 2.2102062702, -1.3429448605, 0.9100778103, 2.2369208336, 2.9532630444, 0.2449691147, -0.042385716, -1.2589607239, + 1.9544759989, -2.0986361504, 1.1010017395, -0.6761249304, -0.5158253312, 2.1491205692, 0.6918260455, 0.4865469933, + -0.0197637565, 0.3024237752, 1.2770613432, 1.5790829659, -1.3644719124, 0.1178247705, -0.2447064966, 2.2056901455, + 0.5842333436, -0.811285913, -0.884548068, 0.5018767715, -0.9628272653, -0.6917787194, 0.5183368325, 0.2223260701, + -2.4080696106, -0.6258693337, -0.2220265567, -1.1970661879, -0.4511078, 0.1818592101, 1.0391007662, 0.1656878889, + -0.1195623577, -0.4278938174, -0.3380023241, 0.7096031904, -1.2523366213, -1.0001627207, 2.1837749481, 1.115316391, + -0.3457722962, 0.279496789, -0.342471242, -0.4181531668, 0.5340260863, -0.9294694066, -2.6755039692, -0.5858883858, + 1.1506539583, 1.0913171768, -1.0706495047, 0.0423627459, -2.0051174164, -1.3628343344, -1.1141849756, -0.0660549477, + -0.968185544, -0.6248205304, 0.6539865136, -0.7431252003, 1.1930276155, 0.0813564435, 0.4269303679, -2.912681818, + 0.6502090693, -0.5792543888, -0.0636761934, -0.2226995528, 0.2611485124, -0.196376577, -0.7510466576, -0.4036752284, + -0.7355467677, 0.8295586705, 0.2841912508, -0.575340867, -0.4433884919, -1.4987837076, 0.7639639974, 1.1248340607, + -0.3037438393, 3.0878508091, -0.645288825, 0.1875440478, 0.0079111867, 0.2569694221, -1.0926113129, 0.2290089428, + 0.3807959557, -0.0390078202, -0.0512206107, -0.0093297828, 1.1520316601, 0.393053323, -0.6344077587, 0.0940024257, + 0.8543282151, 0.3782372475, 0.9214416742, -0.3992048502, 0.2794377804, -0.0629065409, -1.1470851898, 1.0025026798, + -1.7029709816, -0.3982113898, -0.1038763076, 1.7992355824, -0.7881760001, -1.4537860155, -0.4431024492, -0.0188008342, + 0.8453229666, 0.3609706759, -0.1380304694, 1.3005646467, -0.7697758675, 2.0646855831, 1.547998786, -0.6123995185, + -0.7303442955, 1.0699342489, 1.2121047974, -0.2541789114, 0.4415258467, -0.2636577189, -0.3476258814, 2.089730978, + -0.0466064326, -0.9225341678, 1.2898052931, 1.8792136908, 1.5108665228, -0.1160245165, -1.3695697784, -0.2568242252, + -0.8984883428, -1.3459892273, 0.3001153171, 0.2522737384, 0.4287333488, -1.4466867447, 0.4010054767, 1.7777253389, + -0.0489532314, -0.353355974, 0.1734737754, -1.0124557018, 0.0805245712, -0.1957098097, 0.104477115, -1.0432385206, + -0.3111307025, -0.6315842271, 0.2103316486, 0.9604236484, -1.4323203564, 0.0213550087, 0.25007236, 1.5048394203, + 0.8332036138, 0.5828694701, -1.1305952072, -0.5224618316, 2.7289142609, 0.575415194, -0.1905027777, -0.7241643667, + 0.1696766764, 0.3804264367, 1.3739337921, -2.0588717461, -1.2422560453, -0.2515717745, 0.0229164604, 0.0536120906, + -1.9283407927, 1.7888227701, -0.1094532013, 1.1283302307, 0.0836060122, -0.1131427437, -0.1455607265, -1.7971167564, + 0.4484315515, -2.793964386, -1.3108272552, -0.3902270198, 2.8373355865, -0.2132748961, 0.9357783794, -1.0359768867, + -0.140354529, 0.7936987877, 0.7273046374, -1.9549911022, 0.0507963784, -0.6482225657, -0.0779463053, 1.0098884106, + -0.4915691316, -1.795324564, 1.099986434, 0.3593125641, -0.2098834813, -0.6835131645, -0.0330367573, 0.1991713047, + -0.6592006683, -1.2774186134, -0.9763864279, -0.4536683857, -1.0885910988, 1.1693351269, -1.0799335241, -0.7590987682, + -0.8095877171, 0.2647846639, -0.3310623765, 1.2105258703, 1.8539288044, -2.3340659142, 0.1285315156, -0.3244792521, + 0.8191900849, 0.9074296355, 1.1251484156, -0.6740199924, -1.7290600538, -0.25226897, -1.2518934011, -0.3544958234, + 0.3565763831, 0.5419793725, 0.2216321081, 0.0744594485, 0.4009789228, -0.9030396938, 1.1985112429, 1.3050527573, + 0.2644869983, 1.2111719847, 1.4938938618, -0.3135474324, 1.6932300329, -2.1511843204, 0.876090467, 0.3790178001, + 0.1553075314, -0.7556515932, 0.4605605006, 0.1281558573, -0.5230821967, 1.4032703638, -0.2235340029, 0.7719467282, + -0.8938195705, 1.8719172478, 1.7318835258, -1.2508921623, 1.4505107403, -0.789044559, -0.1284002364, 0.522059679, + 0.3965850472, 0.3776007891, -0.8109610081, 2.5998513699, -1.2116770744, 0.6401030421, 0.0995526016, 0.2845474482, + -0.3137201369, 0.513802588, 0.5688924789, 0.0490821227, -0.5854231119, -0.1241295859, -1.2401731014, 1.7278945446, + 1.3531194925, 0.8374717832, 0.7225297093, 0.7827263474, 0.6421630383, 1.3519514799, 1.1704369783, 0.1243656427, + -0.4696682394, -0.5816171169, -0.0667436421, -1.6302013397, 0.2320342809, 1.2981059551, -0.3229315579, 2.4780550003, + 1.4481487274, -0.8240926862, 0.6625467539, 0.4279925823, 1.166212678, -1.0683534145, 0.6251668334, 1.0923655033, + -0.3942586184, 0.9659493566, -0.9605253339, 0.9597508907, 0.2220281959, 0.0806372091, 2.1207196712, -0.9710009098, + 0.1539418548, 1.8333917856, 0.56654495, 0.3243786395, 1.5739785433, -1.0496633053, -0.3769021332, 0.4410339892, + -0.351379931, -0.2858914435, -1.0758993626, -0.2779846191, -0.937769115, -1.519089818, 0.1464475989, 0.5293513536, + -1.0593185425, -0.7463225126, 0.6748778224, -0.92037642, -0.8092591763, -0.6285470128, 0.6317136884, 0.593888402, + -0.2016290873, -1.0690140724, 0.8877389431, 1.0266020298, 1.7298130989, 2.1594829559, -0.0914283618, 1.1662026644, + 1.1089171171, -0.5123221874, -0.3319963813, -0.3509967923, -0.823636055, 1.2866132259, -1.0179052353, -2.3028659821, + 0.2056182623, -0.5770489573, 0.6231693029, -1.2684029341, -1.0089328289, -0.6858816147, 0.2580859959, 0.5197789073, + -1.2355266809, 0.809825778, -1.1747789383, 1.2804471254, 0.4993601441, 1.1285796165, -0.1324673593, -0.3163600266, + -0.199327901, 1.16160357, -0.4632444382, -0.3264450729, 0.3072538078, 0.1358029395, 1.4254649878, 0.1142488122, + -0.037158493, 0.4293601513, -0.9944052696, 0.6163930893, -0.1263526529, 0.6469143629, 1.0459427834, 0.6449648738, + 0.3584982455, -0.3914584517, -0.858253777, 1.0382779837, 0.4811164737, -0.7321038842, 0.8452780843, -0.8298352361, + -1.4297674894, 0.8056114912, -1.3645051718, 0.2932583988, -0.4535759389, 0.8559157848, -1.0738148689, 0.267626673, + 0.0838424116, 0.1785915345, -0.0274679642, -1.0839809179, 0.1531840116, -1.6444801092, -0.5802404881, 0.6161803603, + 0.4401788712, -0.0861002505, -0.1942696422, -1.3705750704, -0.346930325, 0.41583547, -1.9293687344, -1.3931224346, + 2.0027859211, 0.7087925673, 0.537987113, 1.954652667, 0.7514656186, -1.3095040321, -0.0490565225, 0.5774003863, + 0.0596319139, 0.1235771477, -0.8998639584, 1.1102211475, 0.3734438121, -0.1030125245, -0.0789468586, -1.3038878441, + 0.060985446, 0.3799828291, -1.2476456165, 0.6118445396, -0.3204786479, -0.4230053425, 0.5840607882, -0.6879864931, + -1.793274641, 0.9541391134, -2.3621644974, 0.4547835588, -0.2293474674, 0.9833710194, 0.1935296506, 0.1290696412, + -1.5336457491, -0.7804637551, 0.8936599493, -1.0555058718, -0.8772373796, 1.6407520771, -0.3166005313, 1.5166699886, + 1.1298456192, -0.3969652653, 0.7104807496, -0.9392107129, -0.1705227792, -1.2460235357, 1.4000566006, 0.2025852352, + 0.2420491725, 0.6935530305, -0.4681382179, -0.7721756697, 0.9676588178, 0.119835943, 0.1922744066, 1.8341497183, + -2.7488372326, -1.0611772537, 0.1251877993, -0.3508950472, 0.8396126032, 1.1544494629, -2.1873486042, 0.1149946302, + -0.6635305285, -0.26942572, 0.6697966456, 0.4052609503, -0.4259499311, -0.0662061721, 0.0750824437, -2.0473349094, + 0.5177432895, 0.4888772666, 0.9255126715, -1.5766785145, 1.274889946, -0.7883622646, 0.2249861956, 2.6988117695, + 0.3158188462, 1.583480835, 0.1978325099, -0.2180462778, 0.5772840381, -1.1148155928, -1.2709002495, 1.0019147396, + 0.1085478067, 0.0644170269, -1.252910018, -0.0105301021, 1.6947497129, -0.2921498418, 0.6520886421, 0.726829946, + -0.5517195463, 1.1416976452, -0.8316757083, -0.1236225069, 0.7180331945, -1.7250076532, -0.5391926169, 0.7702272534, + -1.8290551901, -1.0975006819, 0.1231060103, 0.183674112, -0.2079072148, -0.3733049035, -0.2890796661, 0.1109581962, + 0.0841258988, 0.4721401334, -0.528740406, -1.0826221704, -0.0720474869, -0.5139278173, 0.6535246372, -0.1900931895, + 0.5698981881, -0.2145587355, -0.1457729191, 1.0641998053, 1.2511655092, 0.8574934602, 0.829151988, 0.4578750432, + -0.7188019753, 0.0051001688, 0.1767217517, -0.0890806839, -1.6345053911, 0.6368270516, 1.6084293127, -1.2352643013, + -0.0038276801, -0.9700303078, 1.0549601316, -1.450521946, -0.4465314746, 0.8876798153, 1.0627869368, 0.4874746203, + -0.5734726787, -0.5883601308, 0.5869722366, 0.2755430341, 0.0495398827, 0.6863536239, -0.8936468363, 0.9656808972, + -0.0415965989, -0.8703505993, -1.564948082, 0.7539380193, -0.8508267999, -0.7657111287, 0.9372233152, -0.5270434022, + 0.3940381706, 0.9115097523, -0.6412190795, -0.7600647807, 0.4493492544, 1.0575815439, 1.2218286991, 0.2423966229, + 0.5654261112, 1.1719374657, -1.371543169, -0.1721050143, 0.299890846, -0.6642464995, -3.1117630005, 0.3729720712, + -0.3114005923, 0.2432861477, -0.3534573615, -0.1880740076, 0.5819046497, -0.3220902979, -0.3700904846, 1.7209761143, + -1.057418108, -1.2687592506, -0.583030045, -0.6538046002, 0.6858478785, 1.8021428585, -0.0014441964, -1.8535352945, + 1.38423419, 0.5036410093, 0.8910794258, -0.2037441581, -0.8835229874, 0.2358111292, 0.8903995156, -0.649091959, + 0.1825971007, -0.4593852758, -1.3794941902, -0.5826588869, -0.2057380974, -0.1274713874, -0.0318536498, 0.5356215835, + 1.376536727, 0.6221526265, -0.5182808042, -0.0778893232, -0.118456386, -1.5069004297, 1.859416008, -0.6981487274, + 0.9367927909, 0.4855525494, -0.154757157, -0.5993320346, 1.1967276335, -0.2093621343, -0.0519363619, -0.8732603192, + 0.1621766239, -0.758613646, 1.8687325716, -1.0110545158, 1.7136559486, 0.2294831127, -2.1291050911, -0.0054081036, + 1.27727139, 0.4153493345, 1.1322646141, 1.2953122854, -0.4021786153, -0.8659353256, 1.36148417, 0.4887880385, + -2.2888154984, 0.7517309785, 0.7804059386, 1.4343571663, 1.1280318499, 0.4125819206, 1.6644282341, 1.0138138533, + 1.1136579514, 0.0347738303, -0.0656888932, 1.3539829254, -0.8064793944, 1.7992246151, -2.0517346859, 1.1155378819, + 0.339903146, 0.1162784547, 0.0452033058, -1.8890718222, 1.8050925732, 0.7577112317, 1.9084178209, -0.2905920446, + -0.8593422771, 0.5828835964, -0.0455377772, 0.5747262239, -0.8365653753, -1.5725414753, 0.6745752692, 0.4211437404, + -0.173394233, -1.3247904778, -0.3337387145, -1.0581274033, -0.1005994231, 1.0474176407, -2.918419838, 0.3160714209, + 0.689353466, -0.7181006074, -1.0671374798, -1.9399932623, -0.8578689098, -1.2643039227, -1.0543541908, -1.3231947422, + 2.0581784248, -1.4635936022, -1.8555091619, 0.593141675, -0.0641021878, -2.0411744118, 1.44876194, -0.9831895232, + 1.1797959805, -0.9788149595, 0.5968145132, 1.6935912371, -0.7220646143, -0.5078238249, 0.8034408092, 1.7207052708, + 0.6739747524, -0.0758223757, 0.5789842606, 0.9166283011, -0.2725763619, -0.3547967076, 0.9579622746, -0.4331351519, + -1.460979104, -1.009516716, 0.186131224, 0.0965674669, -0.5023012161, 0.7978777289, 1.1768301725, -0.2873516083, + -0.3553848565, 0.783178091, -0.3031035066, 1.0905922651, -0.3384682238, -1.5104107857, -1.4142198563, 0.5335105062, + -0.924947679, 0.3325738907, -0.6441063881, 0.3561105132, 0.1303441375, 1.3840107918, -0.7485288382, -0.9498573542, + 0.4881732464, -0.0074557588, -1.2329013348, 0.8200548291, 0.0354016982, -1.2749636173, -0.7796729207, -0.9187532067, + -0.7172759771, 0.4123795033, -1.2273064852, 1.5586960316, 1.1174397469, -0.2219770998, 1.9217811823, 0.6616954803, + -1.422278285, -2.0599975586, 0.0867804214, -2.2925868034, 1.3697549105, 0.8076735735, -1.4938260317, 0.0309710633, + -0.4543955624, 0.9160174131, -1.3730944395, -0.7710475326, -1.1737235785, -1.4549480677, 0.3577015102, -1.7589148283, + 0.092917189, -0.4369859695, -0.3473596573, -1.5033946037, -0.0985980779, 0.0101886811, -1.2029874325, 1.4330537319, + 1.2072029114, -0.0131212957, 0.7697699666, 0.1444311142, -0.0711760968, 1.4660404921, 1.2070227861, 0.2769919932, + 0.7466009855, 0.4890920818, -0.8605375886, -2.1168172359, 1.1051851511, -3.1067254543, 0.4607944191, 0.531258285, + 0.7263253331, -0.1775484681, -0.4622008502, 0.3566424549, 0.8464894891, -0.6093367934, 0.3593332469, 0.2175244391, + 0.7817227244, -1.7723919153, -1.4126907587, -0.3926410079, -0.5199172497, -0.5307080746, 1.0303177834, 0.2988476455, + -2.0974349976, 0.5404635072, -0.0937601328, -0.1606501788, -0.1147610173, -0.86842978, -1.1027407646, 0.556710422, + 0.6773251295, -1.6910611391, -1.4039698839, 0.0599403195, 1.223654747, -0.1871442646, 0.0593416244, 0.8148764968, + 0.371121645, 0.6319756508, -0.0623319261, 1.5143686533, 0.978941083, -0.7867607474, -1.035802722, -1.3657990694, + -1.8243933916, 0.4192204773, -0.2765286565, 0.347435832, 0.4425532222, -0.2964217961, 1.0173045397, -0.0976274237, + 0.6084778309, -0.559941113, 0.2848835588, -0.235268876, -0.1809513718, 0.1363043934, 0.1136598513, 0.4099833667, + 0.8103279471, -0.426353544, 0.4786857963, -0.4269832969, -1.9123014212, -0.806571126, 0.5510292053, -0.0150344782, + -0.3349220753, 0.0880308002, -0.8002303243, 0.3176805675, 0.8337778449, -1.5033525229, 0.5691682696, 0.0770459697, + 1.5434830189, -0.0361299738, -2.0033481121, -0.7982869744, -1.110183835, -2.1667561531, -0.892980814, 0.2909214199, + -0.0600078702, 1.8678102493, 0.6645435691, -0.5375238657, 0.3015767038, 0.8310984373, 0.8583566546, -1.284142971, + 0.2107521594, 0.9149329662, -1.4058991671, -0.7324476242, -1.663469553, -1.3212348223, -0.8275483251, -0.1830658913, + -0.9442102909, 0.6262663603, 1.0551890135, 0.8133642077, -0.4543934464, 0.971234262, -0.3185590208, -0.1727422923, + 1.0257860422, -0.2464818507, 0.5092759728, -0.3984328508, -0.7305040359, -0.5991800427, -0.7956777811, -0.184589684, + -0.030562954, 2.0064487457, 0.9583771229, 0.0363172144, -0.0191859677, -0.3577366471, -1.2744368315, -0.0630775541, + -0.0684572831, 1.8726197481, -0.1023565009, 1.0510714054, 0.4325604439, -0.8658845425, -2.0781784058, -0.0383642949, + -1.1078237295, 0.5350592732, 1.4228900671, -1.1049482822, -0.0801641643, -1.0005115271, -0.4297798574, -0.0559677742, + 0.2867806852, 0.3633767962, -0.2082037479, 1.1467409134, 0.7982702851, 0.0084525729, 0.1348223388, -0.0987749547, + 0.4950430095, 0.2327910811, -1.5314847231, -0.8182778955, 0.2929429114, 0.5952238441, 1.5427302122, 0.8737509251, + 0.7998639345, -1.2590091228, 0.4758330584, 0.5333705544, -0.8768574595, 0.3324282169, 0.0279628281, 0.3362767398, + -1.4143075943, -0.2139455825, -0.8838997483, -0.4397753775, -1.3462122679, -0.0181162562, 0.5175273418, 0.3846479952, + 1.2185842991, 0.677949667, 0.043993514, 0.0856824592, -2.0083913803, 0.2829786539, -1.2908842564, 0.9698345065, + -0.184206605, -1.7637593746, 0.8919836879, 0.4382879734, 1.2267940044, -0.1170026511, -0.2494598031, -1.7412210703, + 0.6522830129, 0.0244456157, -2.2340483665, -0.4830648899, 0.1403207183, -1.3167569637, 0.1011837199, -0.6489614844, + 1.0936598778, 0.1544923484, -0.9260298014, -1.3525762558, 0.7894437909, 0.1807664037, -0.6345968843, 1.0378496647, + -1.1073594093, 0.5320475698, 0.1034940556, 0.7239211798, -1.7146366835, -0.9290454984, 0.546040535, 0.6197391748, + -0.6808706522, 0.5027135015, -1.1057575941, -0.2300989777, -1.2203605175, -1.949198842, 1.2034761906, -0.4060276747, + 0.4978751242, 0.1822032332, -0.6505709291, -0.3541910648, 0.2075365186, -0.0094287647, 0.2557637393, 2.172773838, + -0.8296252489, -0.3163543642, -1.2971352339, -2.0529043674, 0.3074778914, -0.2195957899, 1.0099247694, -0.0117843701, + -0.1268891692, -0.9868423343, 0.3460584581, -2.3466484547, 1.3982958794, -1.0281090736, 0.6707727313, 1.4497638941, + -1.6454523802, 0.3650892377, 0.3026635051, -0.4742977619, -0.423301816, -0.663954556, 2.2567322254, 1.9358763695, + -0.4846771657, 0.6917907596, -0.0628971905, -1.6291610003, 1.356777668, -1.1375604868, -1.7353007793, 0.1414480656, + 2.2786235809, -0.5899149776, 0.1783048213, 0.749191165, 1.6066801548, 1.2810688019, 1.7628934383, -0.9193839431, + -0.1078255475, -1.4992743731, 0.196877718, -1.1903437376, 1.4254845381, 1.0927671194, -3.027200222, 1.9271652699, + 0.5826958418, 0.9965778589, -0.4075433016, 0.4611845911, 1.0407460928, -0.8860122561, 0.8657599688, -0.159580797, + 0.4464957416, -0.4966609478, 2.9157238007, -0.6837469935, -0.2011281997, 0.0069960882, -1.0792711973, -2.0461034775, + -0.2763215601, -0.1097814068, -0.2376969159, 0.8770941496, -0.9377326369, 0.6465483904, 1.5600159168, 0.4526254237, + -0.8150980473, 0.0279371645, -0.6981883049, -0.8752954602, -3.2129752636, -0.6134070158, -1.51562953, 0.4352482259, + 0.1551049948, -1.263530612, 1.9354977608, -0.6287520528, 0.5079177618, -2.1001939774, 0.3900247812, 0.5513725877, + -0.5999241471, -0.789934516, -0.7181108594, 0.1940894574, 0.6138250828, -0.4738227427, 0.8976388574, -0.8623569608, + 0.7657828927, -0.0611073673, 1.1355913877, 1.4761710167, -1.0551246405, -0.7247058153, -1.9813483953, -3.0640888214, + 0.1663405299, 0.0124569135, -0.2628451884, 0.8943400979, -0.2469936311, -1.9407814741, -2.2188706398, 0.4381474257, + 0.1332459599, -1.7151442766, -1.0381941795, 1.9939316511, 0.8085494637, -1.1738445759, 1.0872621536, -0.1853503287, + -1.1145530939, 0.4168367386, 1.0869874954, -1.6734377146, -1.0069420338, 1.4226447344, 1.3044387102, -1.275305748, + 0.2289368361, -0.3836416304, 0.0978016034, 0.281971246, -0.1764324158, 0.8378456831, 0.223602742, -0.2701498568, + 0.6950197816, -0.0077380328, -1.1970260143, -0.373449266, 2.0470554829, -0.4651390612, 0.9548599124, -0.2230303735, + -0.8019583821, 0.3957392275, -1.2221180201, 0.4072573483, 0.3880814612, -0.6441312432, 0.6174584627, 1.0846157074, + 0.6076990962, 1.3721759319, -0.0749501362, 1.0494583845, 0.1591409296, 1.214648366, 1.2344856262, 0.1549460143, + 0.9441838861, 0.8796211481, -0.5252056122, 1.134331584, -1.0764510632, 0.2324069738, -0.1777675897, -1.1545977592, + 0.7995833755, 1.0012146235, 0.0061407532, -0.3563856184, -0.2577395439, 0.7515842319, 1.1220419407, 1.0445507765, + -0.9168112874, 0.6538673639, 1.419574976, 1.0493332148, -1.3196792603, -1.7301003933, -0.7242970467, 0.6112730503, + -1.0061122179, 0.7732378244, 0.5763732195, 0.1579078883, -1.6517345905, 0.7781819701, -1.1136115789, 0.0968965143, + 1.172821641, -1.346957922, -0.0480953678, 0.8859339356, 0.1404125839, 0.4784304798, 1.3342672586, -1.2530455589, + -0.5268494487, 0.7873428464, 0.4130172133, 0.1780058444, -0.3267858326, -0.0826260373, -0.3123799562, -0.9598277211, + -0.0987945795, 0.7427921295, -0.7078848481, 0.4165566862, 1.3543208838, 0.405108124, -0.8848313689, -0.2286397219, + 0.2070284635, -1.6439064741, 1.2955049276, -0.2987741232, 0.9125178456, 2.1810588837, 0.2293576598, 0.8749178648, + -1.34034729, -0.5969886184, -0.4366630316, 0.0945704505, 1.6732033491, 0.4051296711, -0.4160036445, 0.9374626279, + -1.2810299397, 1.7304445505, 0.003009886, 0.4869622588, 0.8563162684, 1.0231707096, 0.3627135456, 0.2392707467, + -1.9643951654, -0.7161080241, -0.2974090278, 0.2324644774, -0.3435841501, -0.6919144392, -2.9642279148, 0.4640024602, + 0.0311744493, -0.1404165179, -0.4386716485, 0.4086935222, 0.182442233, 0.7120854259, -0.6734026074, -0.8858430386, + 0.3498681784, 1.5669513941, 0.9241248369, -0.8324046135, 1.1146484613, 0.9041340947, 0.2956512868, -1.0480246544, + 2.8630208969, 1.4399596453, 0.5258901715, 0.5015463829, -0.3171377778, -0.4555572867, -1.0919431448, 0.5997264385, + -1.7279002666, -1.0438963175, -0.0601046048, -1.2033896446, -0.1048328951, 1.7255532742, -1.2785211802, 0.8037407398, + -1.1056637764, -0.8321886659, -0.6981978416, 0.678316474, -0.6690093279, -0.4299170375, -1.980563283, 0.3072091937, + -1.4346629381, 0.2722908854, 0.3559779823, 0.5817649961, 0.9715235829, 0.981949985, -0.3409855068, -1.3291027546, + -0.8595953584, -0.2314220369, 0.511308074, 0.125980407, -0.008110675, 1.8190455437, 0.8666212559, -0.1718907505, + 1.001434803, -1.0544644594, 0.0663620755, 0.8409745693, 0.1343867183, -0.4915670455, -1.1927989721, 0.4487790167, + -0.3024437428, -0.9536862969, 0.0255348217, -0.2934833765, 1.4988203049, 0.1637242138, 0.1977759004, 1.1715903282, + 1.3605438471, -0.7619611025, -0.5757738948, -0.2096434981, -0.7292847037, -1.3548737764, -1.3679894209, -0.4481071532, + -0.6871653199, -0.1607779413, 0.3172212541, 0.0824580118, -0.007225235, -0.8245114088, 0.8536661267, -0.6266992092, + -0.1128967926, 1.2639377117, -1.9712094069, 0.5339668989, -0.2932064533, 1.5378162861, 1.1618890762, -0.861415565, + -1.0626561642, 1.5011287928, 0.0631416887, -0.6804838181, -0.1782898456, 2.5135641098, 0.4825144708, -0.4274825752, + -1.5566039085, -0.1402496248, 2.8049387932, -0.9801715016, 0.5661875606, 0.7939589024, -1.0236939192, 1.9633581638, + -0.1391828954, -0.2312912196, -1.1576309204, 0.5281303525, 0.9900379181, 0.2896926105, 0.0827321708, 2.2535164356, + 0.121235922, 0.5381548405, 1.5913234949, 2.0978007317, -0.7286148071, -0.5753691792, 0.0828324556, 0.0549454726, + -3.2569141388, -1.8817790747, 2.0503520966, -0.2591432333, 0.7470239401, 0.3248349428, -0.4882176816, -1.3225115538, + 0.4865359664, -1.0414841175, -0.7895792127, 0.8525590897, 0.7897837162, -0.6213835478, 0.0934152529, -1.9919574261, + -1.2485752106, -0.948712945, -0.5130205154, 1.1634507179, 0.3678902984, -0.7489489317, 0.8876307607, -0.1656009853, + -0.4229520857, 0.7181720138, -1.035451889, -0.3245650828, -0.0019222775, 1.852042079, -1.1361961365, -0.762716949, + -1.5301635265, -1.6102468967, 0.3663013875, -0.2587484717, -0.313888669, 1.6451128721, -0.4497563839, -0.171884805, + -0.431355685, 0.2476296723, -0.4489573836, 2.090316534, 0.7821831107, -0.0666693375, 0.7762039304, -1.5657635927, + -0.3966723382, 0.64820683, 1.2220047712, 0.2189141363, -0.3889785111, 0.1967448145, 0.0520267896, 0.4590506554, + 0.5041958094, -0.169732511, -1.2416745424, 0.1428915411, 1.6692961454, -0.0450778902, -1.6467303038, -0.8072274923, + -1.3155603409, -0.9456545711, -1.0992310047, 0.6658183336, -0.5641582012, -0.3236243725, -0.9900243282, 1.3859374523, + 1.8923567533, 0.1954327673, -0.5008239746, -0.8863476515, 0.0526065789, 2.1536448002, -0.2155486196, -0.8135938644, + 1.8556420803, 1.4562864304, -0.0517918803, 0.6744711995, -1.7987359762, 0.9923582673, 0.3135000169, -1.9504567385, + -0.1242371649, 1.5248242617, -0.1120917201, 0.2942447364, 0.4463695288, 1.0370858908, -0.2582800686, -0.5030901432, + 1.0489833355, -1.9220529795, -1.3229802847, -1.1880118847, -0.6967065334, -0.1832891852, 0.6462819576, -0.9041520357, + 0.8098919988, 0.814766109, -1.4799150229, -0.3029147983, 0.3950447738, -0.3467047513, 0.9894205332, 0.980854094, + -1.3005290031, -0.9212888479, 0.8779946566, -0.5321686268, 0.4928537011, -0.1064901054, 2.0072026253, 0.2842397392, + 0.0219647326, 0.2706302404, 0.4453656971, -1.02146101, -1.1261841059, 0.5503368974, 1.0498505831, -1.1867488623, + -0.3131522238, 0.2150351256, -0.7758720517, -1.2624981403, 1.5144072771, 0.5820170045, 0.127989769, -0.470628351, + -1.0356974602, -0.2843975723, -2.1004853249, -0.1418736279, 0.3538064361, 1.2380549908, -0.0495617092, -0.2308800519, + -0.6746603251, -0.5816107988, 0.1941962689, -0.7019876242, 1.4929260015, -0.8704730272, -0.3817136288, -1.3759821653, + 1.1188722849, -0.6615345478, 1.7322149277, -0.6132860184, 0.0772217736, 0.7857915759, 0.5138965845, 0.8683391213, + 1.0741430521, 1.1444586515, 0.2174246758, -1.2567451, 1.249232173, -1.227150321, 0.2029304504, -0.4345974922, + -0.5613096952, 0.9899421334, -0.7794497013, 0.9226804972, -1.4347459078, 1.8226745129, 0.2517725229, 1.3048853874, + 0.2598344386, 0.8284549117, -0.1853842437, 0.9909932017, 0.8433710337, 0.2945882678, 0.1580699831, 1.1083993912, + -1.2196359634, 1.0195169449, -0.7478786707, -0.7492168546, -0.7852820158, 0.8240640759, -0.1690352857, 0.3865447342, + 3.0318000317, -1.3104873896, -0.21064125, -0.0911137834, 0.1675297022, -0.4070737362, -0.5210168362, -0.6016403437, + 1.5758588314, -0.4493618309, 0.5540955663, 1.4807208776, -0.4585899711, 1.5710061789, 0.2264640331, 0.7540287375, + 0.2100552619, 0.1138534173, 1.2335205078, -0.1995334029, 1.2598119974, 1.9921194315, -0.1144331172, 0.1608610004, + -1.0974568129, 1.5505696535, -0.4277614951, -0.7436270714, -0.5684842467, 1.5652070045, -1.9541970491, 0.1121145114, + -2.2796773911, -0.4204390347, 0.307267487, -1.1443328857, -2.1288378239, -1.4380398989, -1.1068999767, 0.763210535, + 0.8052682877, 0.0307863411, 0.5012815595, -0.760453701, -0.1332142353, 1.9456522465, 0.9724579453, -1.014654398, + 0.4536070824, 1.9216108322, -0.9443646073, -0.4025148451, 0.5432344079, 0.229692772, 0.8836902976, -0.4197762311, + 0.226371035, -0.4735622704, 0.2265483439, -1.0051529408, 1.0260937214, 0.0039349413, -0.6438735723, -1.5596687794, + 2.2677609921, -0.0115529187, -1.9361091852, -1.2214096785, 2.3677110672, -0.2835217118, -0.4986249208, 0.0987454504, + -0.2859016657, 0.5878900886, -0.2068942785, -0.4712097347, -0.0293408167, 0.1004185751, 0.575476706, 1.2288657427, + 0.7598702908, -0.3827791214, 0.2701179087, 1.9307528734, 0.3766086996, -1.2595345974, -0.1427586228, 0.2123726457, + -1.0897004604, 0.9504085183, 0.0233728476, 0.0613599457, 0.1773449779, -2.6466653347, 0.4382828176, 1.071410656, + -1.0919705629, 0.2308921069, -0.5418452024, -0.6811359525, -0.0733657703, -0.1108241528, -0.6205454469, 1.3386415243, + 0.3169844449, -0.0132978726, -1.6194648743, -0.1214035675, -1.2176237106, 2.3920612335, 0.2677967548, 1.9048371315, + -0.1090479195, -0.2812086046, -0.8757746816, -0.1215230674, -0.8371799588, 1.356123209, -0.5343367457, -1.3576158285, + -0.052701816, -0.8965148926, -0.1940020174, -0.1157381758, 1.322385788, -0.0518980287, -0.5180981755, 0.7235001922, + -0.50346452, -0.9930452704, 0.503349483, 0.5044299364, -0.178418979, 2.0653004646, -2.3807713985, 0.2423002571, + -1.1575675011, -0.8651419282, -1.2484507561, -1.4254765511, 2.6023020744, 0.5604815483, 1.296173811, 0.779242754, + -1.0478221178, -0.475515753, -0.2933375537, -1.2906724215, -0.5171805024, 1.1661533117, -3.0772411823, 0.4945068955, + 0.8361061811, -0.4539458454, 0.6520614028, -0.0636517256, 0.1846643686, 0.4559874535, -0.7601983547, 0.7996939421, + -1.3556103706, 1.4006017447, -1.2842981815, 0.0201086011, -2.4067430496, 1.0017011166, -1.2208684683, 1.1259891987, + -0.1002016664, 0.4338685572, 0.5633941889, -2.0205998421, 0.707903564, -1.3134320974, -0.7481291294, -2.0741927624, + -1.3709870577, 0.2138299495, -1.316188693, -0.5571706891, 0.5849643946, 0.8160891533, -1.3734140396, 0.1693484336, + 0.4666670263, -0.1848581731, 0.6021742225, 0.7658632994, -0.2800158262, -0.8746697903, 0.6097396612, -0.6713853478, + -1.1039898396, 1.4990520477, 0.1935194135, 0.6815602779, 0.9476210475, 0.0892999396, -0.3394016922, 1.2948087454, + 0.2439201474, 2.0538434982, -0.0148545131, -2.3645238876, -1.2313162088, 1.4056997299, 0.3840621412, 1.3106213808, + -0.385237515, -1.1932288408, -0.1657445431, 0.0863959864, -0.2528146207, -0.2925288379, -1.4965672493, 1.0718343258, + 1.567907095, 2.0106396675, -0.0910225138, -0.4950281084, 0.9399472475, 1.1115689278, 0.4600949883, 1.2392388582, + -0.0673111305, -0.8725827932, -1.6198756695, 0.1760318428, -0.0825519711, 0.2308563888, -1.0177457333, -0.1170732826, + -0.8819388747, 0.2377493382, 1.0289160013, -0.8309114575, -0.8098101616, 1.5898245573, 1.0980596542, 0.3096333444, + -0.4698989689, 0.5669177771, -0.0059816218, 0.4326222241, 2.6160898209, -0.5428299308, -0.5957408547, 1.254562974, + -0.7029317617, -0.0110392943, -0.3283358514, 0.4800703526, -0.4944664538, -0.3524605036, -1.0188369751, 0.1142610535, + 0.4262864292, -0.7915928364, 0.473767221, 0.695422411, 1.0050495863, -1.1403791904, 0.0269745216, 0.8302710652, + -0.7582543492, 0.01697479, 1.6924520731, 1.5741794109, 0.1987948418, 1.1307752132, 0.6800326705, 0.371053189, + -0.7827582359, -0.8127122521, 1.0480321646, 0.3776837587, -0.8211373091, -0.1559403688, 1.6256326437, 1.0607466698, + -0.3728995621, -0.5707845092, -0.321793884, 0.4106550217, -0.955173254, 0.0835519657, 0.2593034208, 0.7858951092, + -0.0355189852, 0.4143232405, 0.3124325573, -0.6817540526, -1.0727124214, -0.8389334679, 1.4706026316, -0.7480475903, + 0.1054771543, -1.3369356394, -0.0947246999, -2.0778944492, -1.3957155943, 0.2285256088, -1.2759611607, -0.3343304098, + 0.0893022716, 0.7450934052, -1.3093935251, 2.0228989124, 1.3606815338, -1.8446570635, -0.5683281422, 0.2735865414, + -0.4449757934, -1.9793847799, -0.0671787336, -0.4893623888, -0.6754632592, -0.7179415822, 0.2092989981, -1.4558817148, + -0.0806349814, 1.6811379194, -1.4438048601, -0.7252404094, -2.2249646187, -0.850304842, -0.129468739, -0.4447180629, + -1.472002387, 0.9454625249, 0.5489059687, -0.0052853036, 0.4739248753, -0.6366956234, -1.6935415268, -0.7258015275, + 0.1571865827, -0.6548541784, 1.8914365768, 1.0652371645, 0.4324242473, 0.8018820286, -0.565339148, 2.6766371727, + 0.1969307512, -1.049887538, 2.2293496132, -0.6575648189, -1.5168567896, -0.3831220865, 0.0663847551, -0.0127926245, + -0.0289653186, 0.8270576, -1.2334251404, -0.1683523655, 1.026291728, 2.0759630203, 2.6905012131, -0.3199998736, + -1.9919358492, 1.3505409956, 0.4858950078, 0.4985644221, -0.0941948369, -0.1956441253, -1.8708121777, 0.5297023654, + -0.2530247569, -0.7849372029, 1.8887374401, -0.1904240698, -1.0549265146, -0.9172002077, 2.4479074478, 0.0858606398, + -1.1978263855, -0.40346542, -0.3708377481, 1.3119311333, -1.9337878227, -0.2400770187, 0.7398082018, -0.7001578808, + 0.2794561386, 0.1471390873, 1.7028954029, 0.4503670931, 0.6144703627, 1.8867530823, 0.1782859117, 0.503737092, + -0.8585119843, -0.9124016762, 0.952015698, -0.4813594818, 1.0137593746, 0.5279722214, -0.4412348866, 1.2565177679, + -1.2011139393, -1.2171599865, 0.3179094493, 2.3057527542, 0.0162226334, -1.0044425726, 0.8488297462, 0.8104820848, + -0.395848006, 2.2574179173, -0.8400303125, -0.0290416647, -0.8049724102, 0.1110918969, 0.1712533683, -0.3029280901, + 0.9060761929, 0.4949313998, 1.5811786652, 1.1496472359, 1.7891368866, 1.6989605427, -1.2844060659, -1.4256250858, + 1.9526252747, 1.4928870201, -1.081408143, 0.9162069559, 2.1888005733, 0.4808399081, -1.2371330261, -2.3750650883, + -0.5375353694, -1.4709631205, -0.9133584499, 0.0837792382, -1.8881543875, 0.6336411834, -1.2488851547, 1.1549003124, + 0.9698441625, -0.1542241722, 0.0810905918, 0.1434110105, -1.2068035603, -0.2149506211, 2.2364194393, -0.7714393735, + 0.1282031387, -1.6601262093, 0.2144560665, 0.2410408109, 1.5626209974, -0.1163768768, 0.999243021, -0.8798793554, + -0.5838215947, 0.3413982987, 0.1006489098, -0.071401082, 0.020374734, 0.4074044526, 1.355655551, -0.2700893581, + -0.9345957637, -1.3730533123, 1.3425372839, 0.514573276, -0.7645043731, -0.7455899715, -3.1266086102, -0.0076880553, + -0.8621249795, -0.9780056477, -0.464879334, 0.1431073397, 0.8786411285, 0.0829805061, -0.6876224875, 0.9151754379, + -0.4527014196, -0.3110263348, 0.1074373797, -1.1986666918, -0.6184980273, -0.9270381927, -0.2079146504, -0.4372631609, + 1.1997834444, 0.1383371651, 0.23982054, 0.4831244349, 0.6147862077, -0.6656706929, 0.8235280514, -0.5021594763, + 0.9050056338, 1.0267746449, -0.0839773044, 0.2934941649, 1.4526919127, -0.5227711797, -0.6307641864, 0.7450272441, + -0.6373867989, -0.2456774414, 1.133746624, -0.9645944834, -0.5025370717, 0.2286235988, -0.4299673736, -1.4565142393, + -1.0908288956, -0.6438586116, 0.9676718712, -0.7037091255, 0.0187808182, -0.8907798529, 0.9865032434, -0.2691493332, + 0.2577497959, -1.9395964146, -0.6774106026, -0.9088381529, -0.0304178633, 0.220190227, 0.8568982482, 0.738000989, + -0.5199701786, -0.7361801267, 0.6977995634, 1.9890062809, -0.2889457047, -1.9138393402, -0.9784683585, 0.7392961979, + 0.3418764472, -0.1733308434, 0.4325277507, 0.1451773793, -1.219810605, -1.4039171934, 1.1004782915, 0.1187280118, + 0.6469854116, 1.0802356005, -0.1612346619, 0.4949934781, -0.0387254246, -1.1470397711, 0.9689227343, -0.6782378554, + 1.5090565681, -0.1389405578, -0.2824213803, -0.1344258338, -0.1288654208, 0.1623164266, -0.1821363419, 1.1691294909, + 0.8031123281, -0.5740057826, 2.0071382523, -0.1318964064, -0.4972498715, -0.4756318033, 0.994324863, -0.6209115982, + -0.6978612542, -1.5944736004, 0.321210891, -2.1554422379, 1.2142683268, 0.9055288434, -0.3738659322, -1.6954593658, + 0.8965313435, 0.9389824271, 0.9087389112, -0.5691789389, -0.5289321542, 1.2088074684, -0.8341738582, 0.5690646172, + -0.8160740733, -0.2697964609, -0.8304342031, -0.7724876404, -1.3361012936, -2.0136146545, -0.7321896553, + -0.5210469365, 0.4472853243, 1.3969060183, -0.0323589183, -1.2332663536, -1.2633476257, -0.5402527452, -0.8164409399, + 0.8692822456, 1.5394263268, -0.6449768543, 2.7324981689, 2.2829384804, -0.0243462957, -0.4708231091, 0.7802814245, + -0.851726234, -0.5438752174, 1.3492876291, -2.1100623608, -1.0599167347, -1.5305445194, 0.9629749656, 0.384072125, + 1.6027978659, 0.615826726, 1.7967692614, 0.6978132725, -0.3588051498, 0.5557240844, 2.0012843609, 0.4117252231, + -1.2055360079, -0.8306830525, 0.7206227779, 0.1442007422, -1.0898617506, -0.5330889225, 1.3166472912, 0.7317251563, + 0.7280780673, 1.6997103691, 0.1930397451, -0.1861350387, -1.4679410458, -0.6894759536, 0.5577561855, -2.7302639484, + 1.7028381824, 0.4612136781, -0.4558180273, -0.344522804, 0.0529292449, -0.3675781786, 0.8226752877, 0.4586767554, + 1.3503264189, 0.8677229285, -1.7889962196, -0.906935513, -0.1365360618, -0.8261981606, -0.0284881555, -0.7588346601, + -1.0901699066, -0.9001386762, 0.9422703385, 0.5553904176, -0.2856693268, 0.4512157142, 0.1980567575, -0.6102285981, + 1.1556385756, 0.1393267065, -0.526391983, -1.1312519312, -0.3653927445, 0.8627732992, 1.068657279, 0.3649345636, + 0.0013756203, 0.1762937754, 0.1261652112, 0.0962752104, -0.7591469288, 0.04223435, 0.1832052916, -0.1315644085, + -2.0348117352, -0.5923904181, -0.5324992537, 1.1435881853, -0.9107784629, -1.7445204258, -0.4858583212, 1.5137287378, + 0.4766238034, -0.180645436, -0.968072176, -0.3028369248, -0.3065006733, -1.1280874014, -0.7446612716, 0.8452233076, + 0.3190322518, 0.8402855992, -1.6233057976, -1.4034744501, 0.4287578166, 1.1428534985, -1.5632708073, -3.8884437084, + -1.2155498266, 1.5331667662, 0.2305153459, 0.6118981242, -0.545950532, -2.5060958862, 0.9057552218, -0.0377277546, + -0.2225462347, 0.5662169456, 0.7287843227, 0.8154967427, -0.8809786439, 0.6194652319, 0.2452322841, -0.1912601143, + -1.1317753792, 0.6059587002, 1.3791689873, 1.5434559584, -0.3077296615, -0.0549331531, 0.6082119346, -0.4465995431, + -1.616435647, 0.7707487345, 0.3566562831, -1.0651414394, 1.2344359159, 0.2838335931, -1.4992698431, 0.9605651498, + 1.3660390377, 0.435472548, 0.1872466207, 0.6108676195, 1.2492525578, 0.1859040558, 1.0766217709, 0.2355428487, + 1.1754379272, 0.0057427166, -1.5887515545, 0.3769720495, -0.2890666425, 0.1181629524, -1.0365852118, -0.9767994285, + -1.2941398621, 0.4882920086, -0.9798254371, 1.8120832443, -1.213005662, 0.2267473191, -0.13878043, -0.3132337034, + 0.4717891514, 0.2309700698, 0.0566052124, 0.1241219193, 2.1627066135, -0.6082924604, 1.2542783022, -0.3301045597, + -1.0780427456, 2.403222084, -0.2280689329, -0.264516145, 0.1353555322, 2.1393721104, 1.4293290377, 2.6570754051, + -0.7824953794, 0.6957845688, -0.2106664479, 1.486736536, -0.6972081661, -0.046223063, -0.6337217689, -2.0922307968, + -1.1119211912, -0.070575282, 0.3467822969, 2.1771509647, 1.1771267653, -0.3236551881, -1.8883998394, 0.4537965953, + 0.2125834823, -0.3116625547, -0.0193837136, -0.7874299884, 0.0644968003, 0.430118233, 2.2707767487, 1.0474052429, + -0.5718730092, -0.6267511845, 1.4229493141, -0.5729410052, 0.8310288191, 0.5821508765, -1.0076065063, -0.1922570169, + 0.0469058715, -0.1675707102, 1.0838055611, -1.3790389299, 1.3507223129, 0.6134766936, 0.0176201425, 0.8428995609, + -1.4992263317, 0.0356088988, 2.2975597382, -1.0299751759, 0.2906056643, -0.5603120923, -0.5430343151, -0.5503050685, + -2.0349340439, 0.3507160246, 0.0798382014, 1.8635390997, 1.4128968716, -0.3009924293, -0.6323676705, 1.2433440685, + -2.6133000851, 1.0574719906, -2.4669671059, -1.0075842142, 0.7337694168, 0.4244298339, -0.5422949791, -0.5591009259, + 0.1210958511, 1.4105414152, -0.263222158, 0.7265729308, -1.68044734, -0.7905883789, 0.5711280704, 0.6042720675, + -1.0270519257, -0.5709877014, 0.4242979884, 1.0850281715, 0.5821233392, 0.2940220535, 1.1921521425, -0.3279542625, + -1.0906670094, 0.3363183141, -0.411521405, 0.2423718274, 0.9718721509, 1.3256907463, 1.3731383085, -0.3152098656, + 0.2616109848, 0.7625992298, -1.1046898365, 0.7405341864, 0.3569501936, -0.0304454751, 0.4198069572, -1.165456295, + 0.3820678294, 1.926722765, -0.4919791222, 0.2134685665, -0.5913387537, 0.396060884, -0.3911811709, 1.5581468344, + -1.794745326, -2.1093726158, 1.1553223133, -0.4462725818, 0.3671998382, -0.2049529552, -0.3518499136, 1.1037057638, + -0.8849042058, 0.6334500313, 0.8141261935, -0.384514153, -0.9080251455, 2.6200330257, -1.3253928423, 0.2427710891, + -2.1761622429, 0.3425274491, 0.4839399457, -0.1631598324, 0.8371133208, -1.6910206079, -0.5188969374, -0.5083132982, + -1.0096994638, -0.0340005644, 1.6234545708, -2.291998148, -0.8237686753, -1.6870236397, 0.2045819759, 2.6661920547, + -0.3744850755, -1.3754044771, -0.5262570381, -0.1487215459, 0.389995873, -0.3349808455, -0.2147201151, 0.8382616639, + 0.0128131611, 0.2007857412, 0.4351505935, 1.279337883, 0.4645488858, -1.1116894484, -0.2591662705, -0.4701961279, + 1.0315747261, -0.1856772453, 0.9001066685, -1.3104590178, 1.3114802837, -1.0081175566, 0.3077223003, -0.6241681576, + 1.4459326267, -2.0826654434, -1.4616817236, 0.570622623, -0.082124956, -0.4760001004, 0.5327296853, 1.5234986544, + 0.1988669932, 0.6964995861, 0.0093918424, 0.756847918, 0.5697199702, -1.8994301558, -0.6445646286, -1.0114517212, + -0.3073485792, -1.0358322859, 1.1701234579, -0.7295694947, 0.1950688511, -0.0414369553, 0.7513110638, -0.3562017083, + -0.3402531445, 1.0202345848, -0.1407631487, -0.7549223304, 1.602488637, -1.5254733562, 2.2856884003, 1.0988514423, + -0.2321708053, 0.5067417622, -0.819022119, -0.9867876768, 0.9519258738, -0.6780868769, 0.1301680803, 0.8194435835, + -0.4938240647, 1.2405018806, 0.6402520537, 0.1182226539, 0.7945907116, 0.0175350085, 1.5766327381, 1.1100355387, + 0.5462289453, -0.2211159617, 0.5913339257, 0.5664343834, 0.5663946867, -0.3709756434, 0.3571896255, 0.7610222697, + 0.1248397306, 0.0199591443, -0.4644696116, 0.4498883486, -0.7748786807, -0.2893411219, -1.7340050936, 1.2877976894, + 2.4911108017, 0.530549109, 0.7266719341, 0.1545901895, 0.9030400515, 0.3245202005, -0.18292813, -0.3200109899, + 0.3289081156, -2.9458432198, 0.8093186021, 0.3413748443, 0.5557262897, -0.1546023935, 1.4225945473, 1.158752203, + 0.2325889766, 0.5621083975, -0.9386121631, 0.0797256827, 0.5854457617, -0.8971057534, 0.2960605621, 0.4373312593, + 0.2856488526, -0.2587785721, 0.8635243773, 0.1729522645, 0.4400544167, 0.6298682094, -1.7541642189, 0.0078843795, + -0.4985109866, 0.1519829929, -0.4746786654, 0.6637639403, 1.1471449137, -0.2405385375, 0.5008134246, -0.4119012356, + -2.024721384, 0.6055507064, -1.024356842, 0.3559515476, -0.8437631726, 3.1102230549, 0.7065474987, 1.5697489977, + 0.2100787759, 0.3337875605, 0.358112365, 0.4796786904, -0.1394378543, 1.7159233093, 0.9836455584, -0.4811730683, + 1.2921022177, -1.4980825186, 0.3234030604, -0.9263525009, -1.9753719568, -1.2800205946, -0.6501467228, -0.4534287751, + 0.6986515522, -0.6066743135, -0.3495893776, -0.4151754379, -0.1613209397, -0.3423712254, -0.440741986, 0.3743268549, + 0.0228571836, -0.2950489223, 0.4956834912, -1.0063159466, 0.8071094751, -1.4763947725, 1.2184668779, -1.2583113909, + 0.4009124339, -0.9315493703, 0.3108949065, -1.0812360048, 1.2314478159, -0.00533891, -0.2175952047, -0.3266625106, + -0.6629793048, -0.6949992776, 0.1832964271, -1.3664089441, -0.7330182791, 0.0111999176, 0.3048385084, 0.3065909445, + -0.320535928, 0.3547713757, 0.238705948, 0.0288662184, 0.3407653272, 0.0688019916, -0.634637177, -2.9236137867, + -0.0657542571, 0.2381646484, -1.4751336575, -1.0005645752, 0.3903593123, -1.5890965462, -0.5685404539, 0.7253620028, + -0.4060972035, -0.7793660164, -0.9706671238, -2.1348261833, 1.4878499508, 1.654094696, 0.0158814453, -1.3564432859, + -1.208230257, 0.5394089818, 0.4960101247, 1.3246908188, -1.0439869165, -1.4069757462, -1.2993481159, 2.4255983829, + 0.904881835, -2.4917924404, 1.1100304127, -1.533077836, -1.1706732512, 0.1931117922, 0.2511897683, -1.375410676, + 0.3725407124, 2.4211819172, -0.4166229665, 1.7748960257, -0.3293336928, -0.3670873642, 0.200808242, -0.7868642211, + -0.7763853073, -1.8592094183, -0.5754011869, -0.4025988281, -1.4596866369, 0.6588805914, -1.7689900398, 0.5031039715, + 1.2791875601, 0.1997129023, 0.0951175317, 0.7077681422, -0.3682105243, -0.6120201945, 0.298949033, 0.4668666124, + -0.0516404063, -0.0072434973, -1.4731035233, -0.674297452, -0.1071094051, -0.0481653474, 0.334808737, 0.7697380781, + 1.0444390774, 0.6389073133, 0.7965302467, -0.5480006933, 2.1861627102, -1.718670249, -1.0547710657, -0.7335004807, + -0.4895069599, -2.5456478596, 0.4805270433, -0.2115930915, 0.6833215356, -1.2567358017, 0.5541188121, 1.4430524111, + -1.2658931017, 1.3923492432, -0.5163353086, -0.8217576742, 0.5181081295, -0.0065804077, -0.1548570544, -1.4562957287, + -0.6649558544, -0.2081828266, 0.7567382455, -1.9596194029, 1.1570088863, 2.8178348541, -0.9480741024, 0.3081744909, + 1.0048877001, -1.0370769501, -0.9271890521, -0.5718141198, 0.5977467895, -1.5901451111, -0.5971243978, 0.7271687388, + -0.3104576766, -0.7801139951, -1.4054712057, 0.5915648341, 0.6452729702, -0.5297361016, 0.090812698, -0.5574408174, + -0.835398674, -1.0422720909, -0.3353568017, 0.7226265073, 2.056450367, -0.5431280732, 0.664724648, 0.1695094258, + 0.0573868677, -0.949891448, -0.3513489366, -3.0019948483, -0.0066395034, -0.4072309434, -0.9640353918, -1.3792288303, + 1.2849546671, 0.4020608366, 0.5306547284, -0.1897467226, -0.9025427103, 0.2592071891, -0.2822673023, -1.5999060869, + 0.88147825, 2.0872652531, -1.8682709932, 1.2595149279, -0.780962944, -0.6400290132, -1.4980249405, 0.2437685728, + 1.3451523781, -0.0861069784, 0.0169560835, 0.8107209802, 0.050427977, 1.0673788786, -0.3041729927, 0.7378834486, + -0.2011504918, 0.2117267698, -1.3680343628, -0.7541540265, -0.8309316635, 0.0250439066, 1.0769543648, 0.1214284599, + -0.0662044212, 0.4549642503, -1.08568573, -1.6837859154, -0.1463906467, -0.495618701, 0.0208592359, 1.2435624599, + 0.5489192605, 0.2411355078, 0.3825907111, -1.6864269972, 0.6340034008, 1.2933397293, -1.2414149046, 1.3236659765, + -0.4560811222, 0.0856558979, -1.038334012, -0.0595628954, 1.1350011826, 0.8011539578, 0.3942179084, 1.4639997482, + -0.4066986144, 0.4662700593, 0.9133059978, 0.911911428, 0.2083911151, -0.2895689011, -0.6915959716, 0.5094326138, + 1.2007409334, -2.135289669, 0.2560206056, 0.2516901791, -1.3380346298, -1.4319194555, -1.0343267918, 0.6933841705, + 0.0523918718, -1.6278096437, -1.7473222017, -0.5706251264, 0.3746893108, -1.4037268162, 0.6328114271, 1.1285928488, + 1.0005843639, -0.0091215968, 0.2692708373, 0.5430057049, 0.6359573007, 0.6018438339, -0.9794576764, 0.4686716497, + 0.1191736385, 0.6245647073, -1.6013067961, -0.3516278565, -2.0193760395, 0.863143146, 0.6426948309, -1.2152938843, + -0.7574124932, -0.1954472661, -1.4739801884, -1.7282948494, 0.7948954105, -0.3243267536, 0.4970909953, -0.9655341506, + 1.0447359085, -1.6254166365, -2.441516161, -0.0110456059, 0.6514555812, -1.2094271183, 0.8311422467, 0.7294400334, + -0.7013913989, -0.9180595279, -1.5018708706, -0.219804436, 0.3838777542, -1.126504302, 1.1347600222, 0.8210456967, + -1.1263074875, 1.6014512777, 0.1510402262, 2.6066834927, -0.8219428062, -1.2476803064, 0.638946712, -0.400521785, + -0.7135859728, -0.6143370867, 0.6910892725, 0.25123927, 1.4253145456, 1.715215683, 0.3454139829, -0.9362812042, + 1.2939212322, 0.5791168213, -1.5516303778, 1.2336236238, 1.2780562639, -0.2307296097, 0.5151617527, 2.3914289474, + -0.8676834702, 0.1678168923, -1.874535203, 0.088753283, -0.0148388622, -0.5805263519, 1.8545913696, -1.0860618353, + 0.3407716751, -0.0286480375, 0.8063637614, 0.1843805462, -0.2964666188, 0.2472796142, -0.4235060513, 0.4835164249, + 1.420563221, 0.7961882353, 0.1411911696, -1.9163612127, -0.6891729236, -0.656678915, -1.4901683331, -0.6937078238, + 1.4161351919, -2.0617113113, -1.0494184494, -0.8323073983, 0.8514946699, -0.3380451202, -0.8639111519, -0.8786121607, + -1.7560200691, -0.759896338, -2.0147390366, 2.4679574966, -0.2002087235, 0.3709254861, -0.1325344741, -0.726536572, + -0.1155025512, 0.0221462883, -0.5978046656, 1.783136487, 0.3680877686, 1.3986713886, 0.2212256342, 0.8435522914, + 1.4509996176, 0.275642693, -0.0882249475, 1.178082943, -1.2781015635, 0.9661692381, 0.084952347, 1.4569551945, + 0.1979640424, 0.0714182109, 1.2154024839, 0.658569634, -0.3421055973, -1.0114430189, 1.7284212112, 0.1652764082, + 0.0440218449, 1.9963196516, -0.2177901864, -0.3685661256, 0.3754687011, 0.727371037, -0.0082708513, -0.8066374063, + 1.3471446037, 0.9464960098, 1.4551038742, 1.7335010767, -0.772706151, 1.2335720062, -1.0976076126, -1.2013162374, + 0.8994884491, 0.8080055714, 0.0058319694, -0.7987020612, -0.6682382822, 0.3353258371, 0.2434836775, 1.0560492277, + -0.6121442318, 0.4928761423, -0.3694842756, -1.8778828382, -0.0021931289, 0.4397992492, 0.0179698374, 0.660302043, + -1.2249333858, 0.3797037899, 0.0017936496, -1.1764934063, 0.1773265749, 0.2379674315, 1.8248631954, 2.0317924023, + 0.5488117337, 0.6360759735, -0.0691221654, 1.2608212233, -0.0978059471, -0.4273525476, 1.174741745, 1.1928589344, + -0.7382788062, -0.1795980632, 0.3162508309, 1.9766232967, -1.1666280031, -0.3134149909, 0.0035257055, 0.4764416814, + -0.4459216595, -0.0344706252, 0.9892446995, -0.7527502179, 0.1697129011, 1.0399791002, 0.8508217335, -0.1022319868, + -1.0322203636, -0.8765253425, 1.6454482079, 0.2713077366, 0.0806060657, 0.6563324928, -0.3451429307, 0.1096281931, + -0.4809369147, 1.7522681952, 0.2002703995, 0.1564730555, -0.9563501477, -2.6347720623, 1.6463611126, 0.2392531037, + -0.2259557843, 0.3380222619, 1.8624340296, -0.1859715879, 0.0106931049, 0.3789506555, 0.1891666949, 0.2392414361, + 1.61736691, -1.2887517214, 0.4338289499, -0.0806743056, -0.415286392, -0.4792827368, -0.3852518499, 1.1886054277, + 0.2293532044, -0.0757466853, -0.1865629554, -0.6457681656, -0.1063916758, 0.2182568908, 1.9584716558, -1.3472338915, + 0.7995253205, 0.1375773102, -1.4171931744, -0.077986151, 1.7121382952, 0.3812084496, 0.1072792262, -0.4451794624, + -0.480646193, -1.0805552006, -0.766700685, -0.2458909303, -0.5287251472, -0.1539849043, 0.4048659801, 0.4522774518, + 0.9267548919, 0.0533838384, -0.5965754986, -0.700001955, 0.6710319519, 0.8343346715, -0.7737452388, -0.6778567433, + 0.8769618273, 1.4523413181, 0.3435254991, -0.967386961, 0.1777562052, -1.7617540359, 1.0451806784, -1.2181231976, + 1.2019933462, 1.720879674, 2.4286599159, -1.6599638462, 0.6040220857, 0.6516717672, -0.2622128725, -0.7239272594, + -0.8162904978, 1.4671630859, 0.2137639672, 0.3574137986, -1.0039931536, -1.0461215973, 1.1023905277, 1.2569910288, + 1.0668817759, -0.0154753542, -0.9374274015, 0.462477982, -0.1082559749, 0.6684598923, -0.5393890142, -2.1180541515, + -0.9959486723, 0.2782751918, 0.2944386601, -1.7939523458, 0.4444533885, -0.1882642359, 0.5147325397, 0.292996943, + -1.8092688322, 0.1214284822, -1.0645792484, -1.6098444462, -0.5044631362, -2.3047981262, 1.7936631441, 0.5146069527, + 0.9426302314, -0.6366305947, -0.2010298967, 0.630566895, -1.2798579931, 0.1300441027, 0.1669493467, 0.7836005092, + 0.3279234469, 1.2725434303, -0.0735878423, 0.5170953274, -0.0156838894, 0.2086202949, -0.3578739464, 0.5611712337, + -0.184556216, -1.3503365517, -0.283880502, -1.0690042973, -0.1829974055, 0.7866693735, -0.2664945722, 0.8257446289, + 0.4535391033, -2.3860180378, 2.7660934925, -1.6022106409, -1.6800652742, 0.1000329405, 0.225518927, 0.4775266945, + 0.9800982475, 0.0695611909, -0.1636302322, 0.732549727, 0.9747005105, 0.7435159087, 1.4804545641, 1.2320071459, + -0.80164361, 0.4638025165, -1.3180469275, 0.9796977043, -1.6520098448, 2.0815844536, 1.7063485384, -1.1672502756, + -0.2736607194, 1.4327979088, -0.1547749192, 0.7636130452, 0.3382462263, -1.3285471201, 0.9728714824, 1.3283112049, + 0.5871783495, -0.383551538, 1.214640975, 1.5588822365, -0.4628805518, 0.1570315212, 0.7060463428, 1.1901321411, + -0.664919138, -0.7949004173, -0.2459549904, -1.0208480358, 0.6603729129, -1.2617355585, 0.2647471428, -0.2705723345, + -0.1136778742, -0.2293915749, -0.2497108281, 1.0774041414, 0.9895689487, 0.7714352608, -2.4308023453, 1.087916255, + -0.0287893172, -1.7348122597, 0.8923826814, 0.2280374914, 0.5680179, 0.0501384847, 1.2335151434, 1.3422961235, + -0.3221537471, 0.1614855081, -0.6970582008, 0.8141419291, -1.5891063213, -0.2522450089, -0.0983667821, -0.1677764803, + 0.3889777958, -2.3217234612, 2.255969286, 0.9853873253, 0.1528448313, 0.1335994452, 0.0960316658, -1.1012336016, + 2.152728796, -0.7543258667, 1.4281525612, -0.5952357054, -0.6522353888, 0.0763411149, -2.4124116898, 0.1143976673, + 3.1385512352, -0.6567717791, 0.5438843966, 0.2478468269, -0.8372309208, -1.0154943466, -0.0634565204, -1.0248450041, + -1.1556870937, -0.7422597408, -1.493676424, -1.846322298, -0.9808491468, -0.7588642836, -0.1710610092, 0.0920800194, + -0.7544130683, 0.6935185194, -0.3152893484, -1.2180192471, 1.5641496181, 0.2795628011, 0.5534697771, -0.3952704966, + 0.7293699384, -0.4047926664, -0.0643341914, -1.7703485489, 0.1241352558, -0.9134722948, 0.3001177013, 0.7077474594, + 0.8252443075, -1.1510851383, -0.5846912265, 0.2272734344, -0.1831062436, 1.2051370144, -0.1876637787, -0.5765454769, + -1.028080821, 0.3914548457, 0.9839670062, 1.0020608902, -1.4458919764, 1.3140779734, 0.0528018363, 0.236222893, + -0.4548761249, 1.6524966955, 1.7901469469, -0.2248424739, 0.1754400581, 0.9779208302, 0.5776523948, 0.902482152, + 1.1635148525, -0.3024394512, 0.3784768581, -1.791864872, 0.3735060096, 1.0666931868, -0.4633731842, -0.5668267608, + 0.9597026706, -0.7974790335, 2.2758290768, 0.9152048826, 0.9018004537, 1.3983670473, -0.9318888187, 0.3431453705, + -0.2198560387, -0.631058991, -0.5225726962, 1.9764684439, 0.3742882907, -0.4727636278, 0.2065766305, -0.2785574496, + 0.2065834999, 0.3348022997, -1.0158301592, 0.0557430349, 1.2103167772, -0.8823601604, 0.5185846686, 0.263456732, + 2.1054568291, 0.3655582368, 1.0914030075, 1.0806419849, -0.7831611037, -1.0495216846, 0.4184381962, -0.0781125873, + 1.3796223402, -2.1329607964, -0.6260906458, 0.1810334921, 0.5751695037, 0.2468598932, -0.114177011, 1.328712821, + -1.1890742779, -0.4207553864, 0.7122940421, -0.9073532224, -0.3651553094, -0.4226305783, -0.083083868, -1.0728796721, + -0.1376402676, -0.7822508216, 1.2550245523, 1.8266563416, 0.7291188836, 0.8544880748, -0.2885992229, -0.6249886155, + -0.1918189228, 1.0057471991, 1.3464815617, -0.0350044779, -0.7850279212, 1.2537226677, -0.7549847364, -0.7763412595, + -0.5457606316, 0.8749659657, -0.1705278009, -0.140703097, 0.1812559962, -0.2123323083, 1.0182181597, -1.2406775951, + -1.7901406288, -1.7229549885, -1.9905031919, -0.5597758889, -0.6072100401, -0.209266454, -1.9350706339, 1.2083387375, + -0.7741381526, 0.7506406307, 0.9133481979, -0.771512568, 0.6030091047, 0.5493309498, 0.4792211056, -0.2988275588, + 0.9531223774, -0.09666536, -1.4549390078, -0.5645372868, -0.37573421, 1.3526890278, 0.714458704, 0.2461370528, + 0.0577381253, 1.6676069498, -0.5236766338, -1.4429916143, -0.7393116355, -1.2088468075, 0.0605625138, -1.5278388262, + -0.9210611582, -0.2517165542, -1.9440078735, 0.6988514066, 0.1982673407, 0.3086035848, 0.5408528447, -0.923874259, + 1.0745069981, 1.2209699154, -0.5641684532, -1.5028772354, 1.5196889639, 0.2270999849, 0.5806286335, -0.1388664693, + 0.2372200936, 0.6519583464, -0.1114310697, -1.24520123, 0.8265328407, -1.1701641083, -0.942950964, -0.001447996, + -0.0517590232, 0.7875321507, 0.276322633, -0.3950987458, 1.4887293577, -0.0903558433, -0.6510680914, -1.0548905134, + -0.165521726, 1.2616093159, -0.012752316, -0.1354828477, -0.2113614231, -0.6180521846, -0.0597930215, -0.2407428026, + -1.5077199936, -0.197107017, -0.6861489415, -0.0931828097, -0.8914435506, 0.1905655414, -0.8744983077, 0.0098695075, + -0.3797313571, 0.7740601301, 0.0845667273, 0.2132222652, 2.2988576889, -0.1039733142, 0.7457541823, -0.8987375498, + -1.3461180925, -0.8154997826, -0.5025764108, -0.3514509797, -1.0883080959, 0.8634200692, 1.5210120678, -0.8854886889, + -0.7128968239, 1.0747821331, 0.7041067481, 0.823818326, 0.4915956557, -2.597029686, -0.5477147698, -0.9649059772, + 2.520072937, -0.3640636206, 0.8815293908, -0.9766589403, 0.4918274581, 1.3674652576, 1.017975688, -1.297701478, + -0.8691310287, 0.3466084301, -0.6623682976, -0.3450996876, 0.6613887548, 1.5178869963, 0.4877279997, 0.9343072176, + -1.0097370148, 0.6456452012, 0.317456454, 0.7257652283, -1.3117456436, 2.463632822, -0.6551507115, -0.2571562529, + -0.4730632901, 1.5332181454, -0.7421475649, -1.1132484674, -0.5764532685, 1.0589469671, -1.1869277954, -0.5670490861, + 0.6283428073, -1.1403493881, -0.9345607162, -0.4807460606, 0.3763595819, 0.4279716611, 1.1986782551, -0.237468034, + -1.2819801569, 0.1377163678, 0.4830263853, -0.5013511777, -0.671995461, 1.5218192339, -0.1730282307, 3.6219646931, + -0.1248321682, -0.1220605448, 0.283087492, 1.660425663, 0.5359668732, 1.3583760262, 1.6301083565, 0.6225463152, + -0.9911639094, -0.8537741303, -0.6471802592, 1.8175919056, -0.193553552, 0.0851218626, -1.014029026, -0.1194371432, + -0.7439462543, 0.360974431, 0.1996553689, 0.4417337179, 0.0744811743, 0.6526217461, 0.5125229955, -0.2765215933, + 1.2034013271, -0.4930281639, 0.6316803694, -0.8473200202, 1.132363677, -0.932531774, -0.1085536703, 0.2190643996, + 0.4257893264, -0.1137780547, -0.8615435958, -0.6558609605, 1.7273952961, -1.1156474352, 0.4715724885, -1.2323323488, + -0.9245020151, 0.2340586185, 0.4171338379, 0.5103055835, -0.803094089, 1.3934131861, -1.7207546234, 0.8516317606, + -0.7090355754, 1.300788641, -0.240940243, 1.5606890917, 1.2331166267, 1.1565121412, 1.1419471502, 0.4737171829, + -0.0646478087, 0.7538887858, 1.1985429525, -0.8085051179, -1.7302092314, -0.7214023471, 1.0235490799, 1.9192208052, + -0.063218534, 0.5950103402, -0.095592469, 0.0445052236, -0.2363787144, -0.6596962214, 0.9489222169, -1.8176273108, + 0.3249565661, 0.5321244597, -0.2519031167, -1.0410438776, 0.3578720987, -0.231840685, -0.4318566322, -1.0400800705, + 0.043287944, 0.2405186594, 0.6484411359, -1.4198623896, 0.5731082559, 1.6903151274, -1.2536605597, 0.8934561014, + -1.7532277107, 0.3545506299, 0.3714213669, -0.4971423745, 1.3633073568, -0.8850327134, 0.5577733517, -0.00021788, + -0.79895854, 1.0268219709, -2.0480480194, 1.0952467918, 0.4634559453, -0.0991200507, -0.2166755944, -0.1800895333, + 0.2274161875, -0.1490253955, -0.1709231734, -1.1723672152, -0.7563461661, -0.4348413944, 0.8389985561, 0.5278283358, + -0.0855753422, 0.6674067378, 0.1275337189, 0.139309302, 0.0813582242, 0.1333002299, -0.5479602218, -0.8135802746, + -0.7446947694, 1.0566511154, 0.8022787571, -0.8659976721, 0.3931536376, 1.5148967505, 1.2328475714, -0.4744767845, + -0.0396147296, -0.3586524427, 0.0859779865, 0.8946546912, -0.248616457, -0.336594671, -0.6286838055, 2.3325791359, + -0.075158909, -0.1462642252, -0.6692479849, 0.129731521, -1.5226391554, -0.3211878538, -0.5852881074, -1.2526824474, + -1.5365287066, 0.4731831849, 0.8354712129, 0.1848156005, 1.1968663931, -1.0546797514, -2.1675684452, -0.7382207513, + 2.6727535725, 0.596755147, 2.2287185192, 1.3105413914, 1.5683557987, 0.3387235701, -0.5780242085, -0.9694200754, + -0.0542619228, -0.7023670673, -0.3473659456, 0.1283979267, 0.9860328436, 1.8086926937, -0.2518500388, -0.7601784468, + -0.6687451005, 0.5814293027, 1.2638016939, -0.0553046763, -1.8108512163, 0.1957877129, 1.5420058966, -0.6303429008, + -0.0445778482, -2.4625091553, -0.2039029151, -1.0149819851, -0.312107414, 0.7373507619, 0.0069484706, 1.5634709597, + -0.4883809388, 1.6265809536, 0.4967319071, -0.6871525049, 0.5922659039, 0.8526945114, 0.6075148582, 0.2839967012, + -1.9847686291, 1.276700139, 1.7508671284, 0.2804496586, -0.090393275, 0.7302295566, -1.0770375729, -2.1788797379, + 0.0533087961, 0.518430233, -0.9022838473, 0.7812830806, 0.7872949243, -0.8752070665, -0.7053655386, 1.669706583, + 1.4777274132, 0.0331411175, 0.4019483328, 0.0795291141, -1.7472738028, -1.6027665138, -0.8463315964, -1.3971626759, + 2.2727987766, -0.7152912021, 1.2079150677, -2.5324273109, -0.220108673, -0.8586494327, -0.6715086699, 1.0920449495, + -1.436781168, -1.1334613562, 0.8020817041, -1.4378912449, 1.9518941641, 1.0430494547, -1.9164535999, -0.791446507, + 0.4349558949, -0.6983420849, 0.8788402677, -0.6938580871, -1.6382540464, -1.3454945087, 0.3314038217, 0.7301472425, + -1.6229919195, 2.4571003914, 0.9816461205, -0.1934306026, -0.6380050182, -0.6916678548, -0.0730158985, -0.6435752511, + 0.2499887049, 0.9054161906, -1.9165015221, -1.7656427622, -0.9856516719, 1.3381596804, -0.0236687176, -1.743347764, + -0.4669364989, -0.3746806979, -0.6021181941, -0.3435127437, 0.542940557, 1.6806927919, 0.3754731417, -1.7427126169, + 1.1184897423, -0.0914018527, -0.2547079027, 0.044479847, 1.2944244146, 0.9571075439, -0.9411146641, 0.0178249963, + -0.2201198488, 0.2704386711, 0.1415091902, 0.7426109314, -0.1449626833, -1.368191123, -0.9975286722, -0.7867771983, + -0.1971043646, 1.1083836555, -0.2619640827, -2.1241817474, 0.5822571516, -0.5158762932, 1.4686164856, 0.4476768076, + 0.1179724336, 0.8681359887, -1.6180802584, 1.3157556057, 1.3680702448, 1.2255792618, -1.2426224947, -0.5846403837, + 1.3134173155, 0.8510391116, 0.0566169582, 0.5327958465, 0.5105850697, -0.0755836368, -0.171999231, 0.5381946564, + 0.013844071, 1.1242705584, 0.3068951666, 1.7257516384, 0.9957590103, 0.8762136102, 0.122059539, -0.5659295917, + 0.2277036905, -0.5829985142, 0.2336221337, 0.5245922804, 0.6979594827, 1.2982851267, 0.6850818396, -0.5728030205, + 0.524813652, -0.3277309239, 0.452812165, 0.4383815825, -0.942335546, 1.1154732704, 0.1451929361, -0.7689108849, + 0.2972296774, -0.5694436431, -0.1806611866, -0.9186413288, 0.7959067225, 0.4119114578, 0.543425262, -0.0524524115, + 0.5843896866, -1.5658318996, 0.2693421543, -0.2651713192, -0.646296978, 0.9390318394, -2.3189029694, -1.9477659464, + 0.9899591804, -0.3546177149, 0.1199787855, -0.485471487, -1.631886363, -0.1745455414, -0.4783552885, 0.1253313422, + -1.0133267641, -0.1568865627, -0.9031783342, 0.0745390579, -0.1635649502, 1.6315912008, 0.3370809257, -0.5317426324, + 0.135867089, -0.7163832188, -1.076803565, -0.9230828881, 0.2219968587, -0.5246748924, 0.6829332709, -0.287722677, + 0.2317267507, 0.4880829155, 0.6605032682, 0.7699363232, 1.2062032223, -1.3281532526, -2.0703158379, -0.371656388, + -0.3761352897, -1.007732749, 0.0220914204, -1.0736358166, -0.5218760371, -0.6671406627, -0.3167509735, 0.266815871, + 0.7138624191, 1.67628479, 0.5364630222, 0.7131706476, -0.4521187544, 2.2354354858, 1.007024765, -1.4814945459, + -0.9544055462, 0.5616211295, -0.4388044178, -0.5384815931, 2.5188238621, 0.3578646779, 1.0072035789, -2.3006868362, + -3.0283837318, 0.1582179517, 0.078626886, 0.2975986898, 0.3020519316, 0.2252492458, -0.1169260144, 1.1698973179, + -0.2377756834, -0.9876517653, 0.9444678426, 0.7366877794, -0.2140249312, 0.6662899256, -0.1698795259, 0.159738183, + -1.1117084026, 1.5774035454, 0.7038061619, -0.8269827366, -1.2444053888, 0.604636848, -1.2741203308, -0.0075483327, + 0.1214978695, 0.1185389608, 0.1672204137, 1.4469048977, 0.9831426144, -1.2359778881, -0.0607702211, 1.0580685139, + 2.1470263004, -0.6063710451, 0.3545796573, -2.0619568825, -0.6264045238, -0.6515289545, -1.4760322571, 0.6560636163, + 0.1312911958, -0.6359328628, 1.0950239897, 0.8734268546, -0.0087732999, 0.2270132303, 0.2920324504, -0.5871611834, + -0.6498407722, -0.4679347277, 0.703779459, -0.3263746202, -0.6026700735, 1.5626196861, -0.3909978867, 1.2148580551, + -0.107424289, 0.2417563349, 0.8551151156, -1.1614420414, 0.4012592733, -2.682623148, 0.2988246977, 1.0284411907, + 0.9653552771, 0.0241382923, -0.6744859815, 0.0252455268, -0.5691433549, 0.9945526719, -0.7929928899, -0.0188295841, + 1.7620083094, 1.132661581, -2.1382300854, -0.4516732097, -1.7331445217, 0.9578317404, -1.9982173443, 2.0854375362, + -1.4002338648, -1.2631605864, -0.2547115088, -1.1759921312, -0.1266184151, -0.1415224522, -0.2777317166, 1.8104367256, + -0.8818674088, -0.1876362264, -0.6606785655, -0.8318985701, -1.3102446795, -0.1048089117, 0.2003894299, -0.494841516, + -0.6170853972, 0.3395398855, 1.1125634909, 0.8719718456, -1.1671817303, 0.1546787918, 0.1532687992, -0.7465642095, + -0.3725242317, -0.5178562403, -1.1987986565, 0.6836966276, -1.4780657291, 1.3997263908, -0.7279686332, -1.4971139431, + -0.7506303191, -0.8950587511, 0.386841476, 0.0534542501, -0.211781159, -1.50804317, -0.7876279354, 1.1501566172, + -0.3116948903, -0.376319617, -0.9797936082, 0.5246469975, -1.2769556046, -0.6016128659, 0.054315459, -1.8809392452, + -0.862552762, -0.4563853145, 0.5321665406, -0.2617306411, -0.6068289876, 1.8533170223, -1.9562035799, -0.5140955448, + 0.4745437205, 1.1698094606, -0.5805649757, -0.3693213165, -0.9228043556, -0.7345765829, 0.5629547834, 0.3122575879, + -0.349755913, 0.9135907888, -0.7911636233, 0.1847207397, 0.3809929788, -0.8879823089, -0.1338323057, -0.3490095735, + 2.1165955067, -3.1589138508, -0.5436285734, -1.7455108166, -2.1049289703, -0.1302325428, 0.4640696049, -0.7451955676, + 0.5188206434, -0.4138991535, -1.8001177311, 1.1008683443, 0.447447449, -0.178660363, -1.0551677942, 0.552346766, + 1.5565564632, -1.0508276224, -1.2913016081, 0.451328516, -0.7465084791, -0.2419379652, 2.0543141365, -1.3258612156, + 0.8564865589, -0.7004728317, 0.9789661169, 0.2529447079, 0.3756442666, -1.1552598476, 0.2251007259, -0.6217958927, + -1.2075531483, -2.1160759926, -0.5377485156, -0.4078000784, 1.2833286524, 1.2621468306, 1.9884413481, -1.9587829113, + -0.3365916312, -0.3414989412, -0.1485837251, -0.5208674073, 0.9343284965, -1.1504461765, -0.7001681328, 0.5539194942, + -1.4810436964, -0.6036912203, 0.9199162126, -0.3080572486, 0.4597660601, 0.0606138296, -1.4523596764, 0.0182523839, + 0.3977748454, 0.250418216, -0.0457268581, 0.1204058975, 0.809247911, 0.7734143734, 0.7709316611, 0.4113011956, + -1.3937188387, 0.4055718184, -0.417686522, -0.3609451056, 0.2942406535, 1.7711349726, -1.3721432686, 1.8080185652, + -0.667957902, -0.625942111, -0.4016775787, 1.0835027695, 0.9990584254, -0.1049466804, 0.0027226934, -0.859883368, + 0.596540451, 0.4464733899, -0.9998130798, 0.3802746236, 0.1903662384, 1.0069195032, 1.7607945204, -0.8770285845, + 0.0015625909, 0.1690426022, 0.4705689251, 0.2795690894, -0.3947535753, 0.2917557359, 0.4942769408, 1.7180832624, + 1.884911418, 1.0528432131, 0.0112085836, 1.9515383244, -0.8529167175, 2.5300376415, 0.9883424044, 1.5475788116, + 2.0330502987, -0.4147629738, -1.7989500761, 1.3826758862, -1.0269834995, 0.5999916196, 0.9867404103, -0.270205617, + 0.3600501716, -0.7583336234, -0.5758518577, -1.019791007, 0.6279180646, 0.5060213208, -0.1114388481, -0.7055656314, + -0.1577177644, 1.3694399595, -0.19053711, -0.6570346951, 0.3182444572, 0.6559875011, 0.1073881984, -0.8325852752, + 0.7134782672, -0.0001436342, 1.1665621996, -0.9761604667, 0.4922949076, 0.1762838662, 0.8394795656, -0.9334070086, + -0.6946863532, 1.1474127769, 0.0837756693, 1.0693693161, 1.5215953588, -1.8261275291, -0.5862078667, 0.8109973669, + -0.0215907376, -0.3971729875, 0.1443639547, 0.7105217576, -1.5630483627, 0.8906173706, -0.0771133453, -0.7070862055, + -0.6657230258, -0.203250289, 0.4337565005, 0.6398509741, -0.0961007103, -2.0606822968, -0.3801790178, -0.7287710309, + -1.1679856777, 0.8636924028, 2.0345959663, 0.8056660891, 0.0790649727, 0.1292844862, -0.2441989928, 0.6843965054, + -0.0466990806, 0.2574798167, 1.7390024662, -1.0807328224, 0.3902039528, -0.0904696211, -0.6639072299, -0.9807626605, + -0.5844775438, 0.7836155295, 0.0463408977, -0.5736125708, -0.2846724689, -0.8746067882, 0.199265644, -1.1177204847, + 1.564966917, 0.1965961903, 0.8586657643, -1.484739542, 1.437974453, -0.3827043474, 1.0768358707, 0.5697392225, + -2.5409808159, -1.108658433, -1.4590468407, 1.9061291218, -0.4039606154, -0.3141342402, -0.6788002849, 0.4221759439, + -0.6185811758, 1.2265267372, 1.3419264555, 0.9365577102, -0.8626218438, 0.0714093968, 0.3579553068, -0.7517531514, + -0.1326746047, 0.4824095666, -0.1637495905, -0.21932666, -0.7112823725, 1.6637583971, 0.6090463996, -0.3620583117, + 0.7486864328, 1.4172860384, -1.3887069225, -0.4702116251, -1.8121628761, -0.4067336619, -0.4508442581, 1.6809742451, + -0.6856459379, -1.096039772, 0.616910696, -0.512671113, 0.7367286682, -0.1227271408, -0.9381112456, 0.3682388067, + 0.5237234831, -0.1901168376, -0.7895736098, 0.0390522219, 0.1888903528, -1.9014731646, 1.7833452225, 0.351295799, + 0.0422377065, 1.1961449385, -0.4127797782, -1.7096159458, 0.4396434426, 1.6618039608, -0.2889024615, -0.4047232866, + -0.3430258334, 0.4502983093, -0.8993715644, -0.2819147706, -0.6409164667, 0.3729336262, -0.7371287346, 0.4244229794, + -0.9481826425, 1.7409205437, -1.9509413242, -1.0926223993, -0.7474913001, -0.3169195354, 0.2738073468, 1.0230799913, + 0.5049025416, -0.1530090719, -2.4460172653, 0.3451049626, -0.7874396443, 0.4234744608, 0.8010879755, -0.7266035676, + -0.028735755, 0.5261215568, 0.4974059165, -2.2859344482, -0.5524745584, -1.6442023516, 0.2132236212, 0.4708622992, + 1.544711113, -0.4303492308, 2.1815609932, 0.339143306, -1.699388504, 0.5555101037, 0.1248709261, -0.5245776772, + -0.8237133026, 0.0852307156, -0.6021905541, -1.9891923666, -0.2042742521, 0.066524066, -0.563069582, 1.3211286068, + 2.615077734, -0.8884028792, -2.7250652313, -0.7953874469, 0.4453403652, -0.0466313288, -0.8660322428, 0.9148148894, + 1.3114209175, 0.0853873789, -0.0865378082, -0.8240836263, 1.5242363214, -0.1447027177, 1.0685709715, 0.6887947917, + 0.3693505526, 1.2384396791, -0.1528254151, 0.4717794359, 0.2557708025, -0.2342842966, 0.2985180914, 1.4603908062, + 1.1556718349, -1.0860780478, 0.8485520482, 0.8186067343, -0.4889854193, -1.1824482679, -0.0552532971, -2.0472691059, + 0.3136096597, 0.0956232697, -1.247527957, -1.0659813881, -1.4372975826, 1.393966198, -1.554353714, -0.2287389338, + 0.8398764133, -1.0875582695, 0.3782944977, 0.5431341529, 0.8844070435, 0.0712101758, -0.7438293099, 1.4641083479, + -0.2514543831, -0.7803747654, -0.788462162, -0.5040911436, 0.1236531809, 1.370934248, -1.2878456116, -0.0993014053, + -0.5816023946, -0.1617263407, 1.465839386, -1.1843436956, 0.199621737, 0.7093799114, 0.64780581, 2.4174399376, + -0.9946103692, 0.9256981015, 0.2354338616, -1.5637323856, -0.4097500741, 0.9532274008, -1.7446402311, 0.3983721733, + -0.9129959345, -1.864151001, -0.0650398284, 1.8328038454, -0.3282188177, -1.4489845037, -1.230484128, 0.3586666584, + -0.2042628974, -0.3145161271, 0.9496209621, -0.3764860332, 0.7279493213, -0.891726315, 0.3433779478, 1.182403326, + 0.040870104, 0.4175057113, -0.6440492272, 0.9012810588, -1.0648696423, 0.9149550796, -0.5418872237, -0.3558420837, + 0.8348129988, 0.1753689051, 0.0140529331, 1.448730588, -0.0789629817, -0.0814047679, -1.5064017773, -1.0320729017, + 0.5171748996, -2.2602293491, -1.7476472855, -1.510140419, 0.3992056251, -1.5515506268, 0.7638925314, 0.6154313684, + -0.2482495755, 0.0194012262, 0.009877285, 0.4108774662, -0.0947879553, 0.4412504435, 0.109232977, -0.7233854532, + -0.5602306724, 0.9036995769, 1.243190527, 0.0285293981, -1.6290500164, 1.2356460094, -1.9054615498, -1.5224015713, + 0.4625911415, 0.1904840916, 1.5625308752, 0.4856654108, -0.0246778559, -0.1548504829, 1.2992460728, 0.1943925023, + 1.254462719, 0.6112693548, 1.4020404816, 0.81334728, -0.7494078279, 1.385669589, -1.6867324114, 0.189238891, + 1.2696735859, -1.3791120052, 2.2082250118, -0.9735414386, -0.2286798209, 1.3652757406, -0.8393858075, -0.6100654006, + -1.1962810755, -1.3717755079, -0.7170159221, -0.8828419447, -0.3372710645, -3.3247058392, -0.9084119201, 1.6302831173, + 0.8176118731, -0.0111802975, -0.2251095921, 0.5649040937, 1.4012663364, 0.7089836597, 1.2665133476, -1.1005299091, + 2.4844765663, 0.1761873364, -0.0088386908, -1.353454113, 0.5137736797, -0.5706036687, 0.8757398129, 0.0449838303, + 2.4435112476, 0.2079927921, -1.999691844, -0.6087223887, -0.638577342, 1.6442676783, -1.4658410549, -0.2207080126, + 1.0008113384, -0.7584369779, 1.4786957502, -0.4342084229, -0.0399412848, 0.0586465672, -0.5101655722, 0.0631559715, + 1.0645006895, 0.9889351726, 0.796007216, 0.9740015864, 1.7200036049, 1.4311993122, 0.3660484254, -0.0995860323, + 0.260607779, 1.2410806417, -0.9831237793, -1.6199501753, -0.1432815939, 1.027618289, 1.9477783442, -0.171554625, + 0.9028071165, 0.9455989003, 1.7721807957, -2.377051115, 0.042200584, -0.2649149299, 0.1626689434, -1.716574192, + 2.0142836571, 1.2888416052, 1.3182411194, -0.2988808751, -0.9702196121, -1.3273938894, -0.1208585128, 0.1018750072, + -0.3974203765, -0.9312421679, 1.5495072603, -0.2257322222, -1.5345994234, -1.2101567984, 0.5442845821, 2.3244996071, + 0.6885232925, -0.3893218637, 0.5857572556, 0.8583837152, 1.1273128986, 1.5923551321, -0.6475256681, -0.4328983426, + 0.3193134367, 0.3736357391, -0.0583607033, 0.9926229119, 1.1097198725, 0.0237506758, -0.3030325472, -0.4242801964, + 0.0150921475, 0.8205795884, -0.152379334, -0.1743751317, 0.1002234742, -0.5741091371, 0.4680297673, 1.3265185356, + 0.7591851354, 0.796848774, 2.4510006905, 1.0455299616, 0.1616481096, 0.4591381252, -0.5118848085, 1.3974906206, + 0.0444282293, -0.2367054075, -0.585085392, -1.7926813364, 1.0850917101, -0.0153463064, 0.8085225224, -0.065087907, + -0.819181025, -0.3907743394, -0.8836235404, 0.8422560096, -0.9372207522, 0.1334853172, -1.4340825081, -1.0172991753, + -2.9318859577, 1.740375638, 0.669504106, -0.5234505534, -0.4980879426, -2.2248792648, -0.3270122707, 1.4429141283, + 0.0257454775, 0.9544253945, -0.1030614227, -0.0222805012, 0.859565258, 0.7901018858, 0.0139517374, -1.5680670738, + -0.7101589441, -0.9396982193, 0.5569794774, 1.6559907198, -1.0252135992, -0.5993455648, 0.7724023461, -0.0052897935, + -0.7790496349, -0.5721173286, -0.1611474603, 0.1147837266, -0.4912993908, 0.2682353854, -0.1408393532, 1.1909285784, + 0.1201085225, -1.1754007339, 1.0866947174, -1.3127019405, 0.5852900147, 0.449496299, -0.0917720422, 1.5772259235, + -0.0028221165, -0.9338590503, 0.4315549433, -0.7911572456, -0.7792272568, 0.4389078021, 0.2131284922, -0.4663459361, + 0.0148027567, 0.6259170771, -0.8518497944, 0.0935833678, 0.2924852371, 0.3590088189, -0.5718174577, -1.1496263742, + 1.2068468332, -0.1130583733, -0.2927685678, -0.6665418744, 1.2084698677, -0.5074796677, 0.6037199497, 0.5330540538, + 0.0671800524, -3.1931815147, 1.3412168026, -0.0472922698, 1.2909542322, -0.0951048583, -0.3293198049, -0.3368616104, + -0.6205972433, 0.1633470356, 1.0400021076, -2.4417200089, -0.1430457532, -0.3949324489, 1.5079751015, -0.0933669582, + 0.7111688852, 0.4588423967, 1.0893750191, 0.671189189, -0.1723787934, 0.3056735396, -1.0339529514, -0.5147407651, + -0.0625401884, -0.4944783449, -0.2281164825, 1.8994734287, -1.1122488976, 0.8064043522, -0.9070198536, -0.7515420914, + 0.4880173504, 0.5601146817, -1.6990242004, -0.5601556897, 0.0330446623, -1.1386178732, -0.0413848385, -0.436436832, + -0.048449181, -0.8381305933, -1.9084656239, 0.3641952574, 0.4897067845, 0.2050378919, -0.5196628571, 1.1518422365, + 0.2143942863, 0.6736453772, 1.3390365839, -0.9382547736, -0.580216825, -0.2404362857, 0.0388144962, 1.2864723206, + -0.7813917398, -1.4558441639, -0.5873885751, 0.9965207577, 0.0476341769, -1.6072156429, -0.6474640965, 0.7038937807, + -1.2242337465, -0.3836533427, -0.3961207867, -1.0149700642, 1.0830006599, -0.2466066629, 1.1158556938, 0.6452320218, + -0.1450219601, -1.9907687902, 0.2957869768, 0.7098045945, -0.0348816589, 0.751809299, -0.5935727358, -1.2528318167, + -0.5177393556, 1.5163943768, 1.2004730701, -0.9606300592, 0.4015153646, 0.4090261459, -0.0634377599, 1.273255825, + -0.3282780945, 0.9231778979, 0.2382800877, 0.8408981562, -0.7702533007, 0.4584795237, 0.1061263978, 0.0769923702, + 0.4656309485, 1.1552935839, 1.3841668367, -1.3653978109, 1.5498673916, -0.3918735981, -0.0810078084, 0.6211736798, + 0.7627735138, -0.0829695016, -0.9319149256, -0.5280153751, 0.2751726806, 0.3330031931, -0.7518762946, -0.1446366012, + 0.1988864541, 1.2466605902, 0.4027922451, -1.2030483484, 0.4533600509, 0.7313265204, 1.093670249, 0.003789447, + 0.0050270087, 0.025108844, -0.0352713205, -0.5701832175, -1.9719990492, 0.4366341829, -0.1345392913, -0.1814393252, + -1.8553251028, 0.0617607608, 0.6062008142, -0.4244881868, -1.0817292929, -0.6807661653, -0.6261473894, -0.0540766194, + 0.2786253989, 0.8372100592, 0.0017704318, 0.5310544372, 0.6352730989, 0.9221379161, 0.44577384, 1.5647474527, + -1.6837626696, 1.2410209179, -1.0796965361, 2.2747447491, 0.5723548532, -0.5651129484, -0.1718373448, -1.6550757885, + -0.3474877179, 0.6547319889, -0.7872471213, -1.5143712759, -0.3837069571, 1.4854574203, 1.3285131454, -0.2988612354, + 1.3719160557, -0.342415601, 0.4441322386, 0.3561630547, 0.3292013407, -0.4663069844, -0.396474123, 1.4079635143, + -0.0168015026, 0.2487754226, -0.6136851311, -1.5734347105, -0.8163513541, -0.225418061, -0.0962739587, 0.2816110551, + -0.9428220987, 0.1577043533, -0.264301151, -1.3468902111, -1.6785992384, 0.6566977501, -0.1757939309, -0.4243683219, + -0.8836905956, 0.14858374, -0.725643158, 0.094081983, -0.7429986596, 1.3145816326, 1.5680030584, -1.3079791069, + 1.0795658827, 1.632250309, -1.3270734549, 0.2825237513, -1.8363772631, 1.4280408621, 0.8779270649, 0.1488070041, + -1.1796215773, -0.7179731131, 0.7257335186, -0.0448335893, -0.4180825651, -0.9488744736, 1.3562891483, 0.6680294275, + -0.453168124, -1.193954587, -3.9058244228, 1.6860084534, 0.0763802007, 0.8831697106, -0.0188103337, -1.641854763, + -1.3217287064, -1.7891827822, 0.3362942636, 0.3228811324, -0.1052464694, 0.3700760007, -0.2983788848, -1.7491821051, + 0.0411379486, -1.1203415394, 0.6413006186, 0.0217642933, -0.6283631921, 0.5370006561, 0.0651604682, -0.6565572619, + -0.4752445519, -1.2263764143, -0.6557531357, -0.1826541275, 2.3952448368, 0.1607136875, 1.0272328854, -0.8275399208, + 1.0438835621, 0.76194489, -1.1307396889, -1.2205406427, 1.3907771111, 0.6221396923, -1.040941, -0.785657227, + -1.1721094847, -1.8064625263, -0.3921511769, -0.2310555279, 1.513151288, 0.4917284548, -0.0432878397, 1.6977798939, + -1.3908723593, 1.4940390587, 1.8423306942, -0.1109176725, 0.2542709708, 0.2416193187, 0.1212384477, 0.2414720356, + -0.4855381846, -0.6720389128, -1.0101215839, 1.1480742693, -0.0514740795, 0.2556264997, 1.1470924616, 0.9148079753, + -1.1060256958, 0.4811087251, 1.2506557703, 1.3353089094, 1.7559952736, -0.1265173256, -0.80109936, 0.456631124, + 0.3428300023, -1.7524900436, -0.9317060113, -0.8634976745, 0.3061068654, -0.1965166926, 1.000322938, -0.1569621265, + 0.1014276296, 0.8939095736, 0.9408544898, 0.2834113538, -1.3292179108, 0.9167075753, 0.2990117371, -0.6239182353, + 0.9428245425, 0.2198539376, -0.4146504402, 0.7951261997, 0.2012115568, 0.6641840935, 1.9132390022, 0.0612025335, + 0.3415098488, -1.0602945089, 0.8366987109, -1.6226406097, 1.1113557816, -1.3292145729, -0.3143319786, 0.357010901, + -0.1764928848, -0.1717350632, 1.6343352795, 2.5383000374, -1.0527589321, -0.7758113742, -0.3192665279, -1.0465342999, + 1.9890724421, 0.3994129896, -0.5866478086, -0.895712018, -1.6844896078, -1.3510472775, 0.3692949712, -0.2429165691, + -2.378828764, 0.5294952989, -0.9295908213, -2.061548233, -0.6898310184, 0.027832875, 1.6711131334, -1.6555784941, + 1.4271929264, 0.0273575801, 0.2971141934, -1.1789822578, 0.9930096865, 1.0365034342, -0.1519527435, 0.4682734311, + -2.3577785492, 1.356528759, 0.9537298679, -0.2706686854, 0.2951039374, 0.388364315, -0.0566962734, -0.3984859884, + 0.2041887492, -0.9976084828, 0.7897940278, 1.4099681377, -0.3404171765, 0.3241531551, -0.4855938256, -1.2421112061, + 1.5360037088, -0.9463829994, -0.3573916852, -0.0232634433, -1.25131464, -2.2355549335, -0.7908390164, -0.4839990735, + -1.6056691408, 0.0734652206, -0.2260978222, -0.5341376662, 1.0534939766, 1.5730623007, 1.0264832973, -0.9042997956, + 0.7410283089, 1.2227886915, -0.9809672832, 0.8328786492, 2.728852272, -1.6969711781, 1.2512172461, -0.3696545064, + -0.2950987518, 0.051839266, 0.8288123608, 1.2777222395, -1.2569802999, -0.3112655282, -0.5696928501, -0.237707004, + 1.1983821392, -0.2934773564, 0.837857008, 1.7270666361, -0.8205666542, 0.3335210681, -0.8726528287, 0.6561540365, + 1.0646369457, -1.4809577465, -0.3941823542, -1.0625725985, -1.1441496611, 1.1643037796, -1.706309557, 0.1826176941, + -0.3895122707, -0.5045616031, 0.5522103906, 0.0773333758, -0.0574592091, -1.502142787, -1.7225257158, 1.7434196472, + -1.8855978251, -0.1019827873, 0.4856334627, -1.9518294334, -0.1191142574, 1.0445772409, -1.1645052433, 1.6964392662, + 0.5589596629, 0.6847245097, 0.6614169478, 0.482075721, 0.3499038517, 0.6179351211, -1.9481719732, 0.2576283216, + -2.2164435387, 0.2630864084, 0.066920355, -1.1707545519, 0.6772699356, 0.1684508771, -1.2875515223, 1.0062065125, + -1.1552302837, -0.8029338717, -2.2737193108, -0.7485864162, 0.6612769365, -1.1619497538, 2.1173989773, -0.3294250369, + 0.3562559187, 0.2107373476, 0.8565757871, 0.6712851524, 0.5338254571, -0.8010561466, -1.6697434187, 0.3606756032, + 1.286767602, -0.2094346732, 0.5576734543, 1.0525827408, 0.9210794568, -0.2470230609, -0.0034603099, 1.6976779699, + 0.633243084, 0.0199560001, 0.0755996332, -1.0569541454, -0.6732931733, -0.4159931839, -1.5330858231, 0.5702850819, + -0.1691996306, -1.8038196564, -0.9590678215, -1.5392922163, 0.3994826972, -1.082144618, 0.3027870357, 1.0220326185, + -0.3363763094, 0.0301486459, 1.513432622, 0.5621951222, -1.2312422991, 0.6054644585, 1.1600813866, 1.3731253147, + 0.5823098421, 0.1793181896, -0.9241508842, -1.3068791628, 1.0078873634, -0.0847553387, 0.693810463, 0.102977179, + 0.1699392349, -0.5331149697, -0.5968712568, 0.8790861964, -0.2934698761, 1.2495779991, 0.1272739172, -0.712521255, + -0.4451971948, 0.4075957537, -1.0298527479, -0.279171586, 0.3461883962, 1.6816877127, -1.6031706333, 0.0056235124, + 1.0078634024, 1.3490788937, -1.5436534882, 0.1696927845, -0.5270277858, 1.6223733425, -0.5162442327, 0.38283813, + 0.4506391287, -0.9998950362, -0.6521401405, -0.3246061206, 0.2585060298, 0.9276508689, -2.0880565643, 0.8682402372, + 0.0620451719, 0.2503739893, -1.0289133787, 0.127045095, -0.81628865, 1.4642271996, -0.3115217388, 3.0074081421, + -1.2791824341, -0.2708213627, 1.7376896143, -0.5052874088, 0.6811109781, -0.7712689042, -1.5408807993, 1.1143568754, + -0.4985656142, 0.7032669187, -1.3779296875, 0.0579764359, -0.366928637, 0.5524052382, -1.1774955988, -0.9593952298, + -2.5553278923, 0.3986499012, -1.860699892, 0.5338377357, 0.618224144, -0.3920603395, -0.9350994825, -0.6044998169, + -0.3034831882, -0.4526685476, -0.5963338017, -0.7564249039, -0.2662839592, -1.221095562, -0.612431705, -0.5627401471, + -0.4255528152, 2.0560801029, -0.8246173859, -0.9876614213, -0.6199842691, -0.4691637754, -0.1785079837, 0.5794753432, + -0.6497477293, -0.3748328388, 1.7727497816, -0.4439648986, -0.2879000008, 1.4938969612, -1.4431997538, -0.196699366, + -1.5506589413, -0.0824496299, -0.3735535145, 1.8474872112, 0.4143075943, -1.3707956076, 0.4110006988, 0.1122452915, + -0.8783571124, 0.1543612927, 0.0001337494, 1.3457558155, 0.1956868619, 0.0120426994, 0.4659405947, 1.0559220314, + 0.4118642807, -0.282782048, -1.0537084341, -1.7089247704, -1.2605371475, -0.6627028584, 0.028496461, -1.5919424295, + -0.8879739046, 1.337272644, -0.3084809184, 0.260401547, 1.5567058325, -0.9774645567, 0.920660913, -0.3910360932, + -2.0741565228, 0.6043616533, 0.8186147213, -0.2919317484, -1.8189321756, -1.3367571831, 0.0049841022, 1.1277798414, + -0.1117683128, -0.7106814384, -0.0921612084, 0.4363644421, 0.5508530736, 0.2112184912, -0.4217892885, -0.3625360429, + -0.5210886002, -0.7911268473, 0.6036680937, -0.9205818176, 0.9471231103, 1.3281573057, 0.5098133087, -0.2765147686, + -0.0400175266, 0.9152051806, -0.0791764036, -0.4207233191, -1.4149441719, 0.1290478557, -0.0053360481, -1.1818076372, + -1.2097790241, -0.635836482, 1.0997394323, -0.3663605452, -1.3995124102, 0.5268882513, -0.0040545431, 0.8065931797, + 0.5818359852, -0.7355961204, 0.2951637805, -1.85539639, 0.7826838493, 0.9054294229, 1.394852519, 0.4250205755, + 0.3838944435, -0.6590161324, -0.5383474231, 1.9159451723, -0.3733713031, 2.212959528, 1.896158576, 1.6835546494, + -0.5816136003, -2.1392905712, -0.9826152921, -1.5338691473, -0.4559504688, -0.1861871928, -0.4478240609, + -0.9198418856, 0.6889845133, -0.7898256183, -1.5680773258, 0.6147295237, -0.5621627569, -0.3072946072, 1.939363122, + 0.9291343093, -0.6737373471, 1.3822253942, 0.2642171383, 0.2372154593, 0.3773427904, -0.4426511824, -1.9745779037, + 0.8025727272, -1.0189781189, -0.6997631192, 0.2891789675, -1.1383354664, -2.0471360683, -0.1752144843, -0.0870466754, + 0.2797400653, 0.2387488484, -0.1481952071, -0.230271101, 0.8003568649, -0.6089862585, 0.0534715429, -0.5716961026, + -0.9841057658, 1.2828774452, -0.1688161492, 1.2798538208, -1.0940895081, -0.2482675761, -0.7160670161, -0.1450303942, + 0.3953606784, 0.6148098707, -1.0022808313, 0.3334307969, -0.9138579369, -0.8279646039, -0.2285257876, 1.1132116318, + 0.6443887353, -0.1507997662, 0.8884394169, -1.0409892797, -1.2017220259, 0.4876228273, 0.6594662666, 1.0187479258, + -0.8132072091, 0.4418626726, 0.6325352788, 1.2463976145, -0.1135608032, -0.9164980054, 0.7859613299, 0.4463684261, + 0.6968076229, 0.622725904, -0.6469994187, 0.9220806956, 0.7630829811, 1.0957705975, -0.4319012761, -0.4152270555, + -0.2044944763, 0.9506226182, 0.584728241, 0.2539539337, -1.7795450687, -0.6887845397, 0.6866399646, -0.0558012277, + 1.2429003716, -0.5696885586, -0.1877678037, -1.1906847954, -0.4526516199, 1.0057507753, 0.7095575929, -1.6089472771, + 0.6746912599, -0.0422934592, -0.1314605325, 1.1723577976, 1.3062764406, 0.0529669598, -0.3620713353, -1.5355778933, + 1.1157461405, 0.1266220212, -0.3168752789, -0.2654770017, -1.4859975576, -1.1428658962, -1.880870223, 0.7916238904, + -1.097866416, -0.3868590593, -0.0748722702, -0.5582896471, -0.3408991992, 0.0357785411, -2.8540141582, 0.1198951602, + -0.3569850326, 0.6131075025, -1.6270140409, -0.2847393453, 0.07919503, 0.712572515, 0.9216774702, -0.5362963676, + 1.0582467318, 1.0025253296, -0.4564027488, -0.9334833026, 1.2776427269, 1.3159724474, 0.9056265354, -0.0394703001, + 0.2864100337, -1.8664575815, 0.1179925725, 0.2843076587, 0.6929876804, -0.8222893476, -0.700869143, -1.175620079, + 0.0781022459, -0.9581169486, 1.2042080164, 1.228854537, -1.2023644447, -2.1400723457, 0.8589876294, 0.9031086564, + -0.6311286092, 0.2257191837, -0.2904500663, 2.5082805157, -0.7749772072, 0.4404409826, 1.5937997103, -0.6869628429, + -0.8768021464, 1.154227972, 0.337800324, 0.7085487843, -0.0843881667, 1.3874114752, -0.8350510597, -1.8387274742, + 0.0471214205, -0.6551354527, -0.8090748191, 0.6171238422, -0.1551373601, -1.3722908497, -0.7655444741, 1.6287691593, + 1.5615321398, 0.3192647994, -0.9870176911, -1.455399394, -0.6677874923, -0.0301759038, 1.0221860409, 0.2797620595, + 1.9955043793, 0.2484874576, 0.0276262611, 0.2522889674, -0.8351356983, -1.089212656, -0.1633870602, -0.4688637555, + 0.2814452946, 0.6965830326, -0.8071414232, 0.493393898, 1.1570245028, 0.5350809693, -1.7146855593, 0.3662984073, + 0.6917946935, 0.4543409348, 1.334612608, 0.8517884612, -0.8048650026, 1.4301743507, 0.5187414289, 2.5650734901, + 0.5571698546, -1.4397175312, -0.0305997543, -0.5573413372, -0.3947639763, -1.7622674704, -0.5569675565, -0.9407226443, + -0.4493946731, -1.6613689661, -0.8826978207, 0.3443049788, -0.1960539669, 1.6036450863, 0.2909748852, -0.1233137473, + -0.2173997611, 0.3150077462, 1.0498563051, -0.6585019231, 0.0957669914, -0.2687816024, -0.6586936712, -0.3349936903, + 0.9559844136, 0.2193197906, 1.3311969042, 1.7547625303, -0.4384146035, -0.5910891891, -0.0369080007, -1.7037577629, + 1.1412252188, -0.188038826, -0.6701797843, -0.2139253467, -0.4461108446, 0.460978508, -0.6667152643, -1.049413681, + -0.9170075059, 0.4246536493, 0.4500367045, -0.4323231876, -0.7817713022, -0.8252133131, 0.9703499675, 0.5069776773, + -0.5588415265, -0.5356715918, -0.2954487205, -0.6099143028, 0.0746136606, 1.6815915108, -0.3075112998, -0.8263124824, + -0.7620713711, -0.8745070696, -1.0211056471, -1.0041357279, -0.7308058143, -0.2631337643, 0.5446914434, 0.6488231421, + -0.5848956704, -0.232375443, 0.6658927202, -2.317022562, 1.2412644625, 0.727853477, -0.1591682732, -0.0863246992, + 0.0435153991, 1.1766989231, -1.3432213068, 0.7669236064, -0.8524904251, -3.0434315205, -1.0095849037, -0.0935433209, + 0.4370863438, -0.2978182733, -0.8723636866, -1.6289815903, -0.4529634416, -0.2159748822, 2.2257893085, 0.5159680843, + -0.0077975448, 0.6277788877, 1.8291573524, 0.783328414, -0.6949352622, -2.3123188019, 0.8569595814, -0.3096266389, + -1.2400895357, -0.3410450518, 0.5242138505, 1.9794309139, -0.1311748475, -0.6779469252, -1.001522541, -0.7074307203, + -0.6888180971, 1.0624884367, 0.6066510081, 0.8800684214, -1.3701462746, 1.2867304087, 0.5365315676, 1.2999631166, + 0.6271314621, 0.3918847144, 1.9875098467, -1.5191190243, 0.4580776691, -0.0840576738, -1.1077204943, -0.3676539361, + -0.517221272, 0.4895897508, 0.6502180099, 1.4189645052, 0.4343042374, -0.3245664239, -0.3949351311, 0.3454012871, + -0.0033489121, 1.3653379679, 0.7686623335, 2.212287426, -0.2360703945, 0.5532864928, -0.1661921591, 1.675183177, + 0.0132257845, 1.417688489, 1.7192947865, 1.6324951649, 0.3114824593, 0.7976205945, 0.4467043281, 1.492685318, + -0.2878831625, -1.6661862135, -0.0044908966, -0.2455088496, -3.2745137215, -0.2838715017, -0.151884377, -0.8731604815, + 0.1849374026, 1.0501680374, 0.2308520377, -0.1487602592, 1.1539299488, 1.0388782024, -0.7927692533, 1.0399427414, + -0.3865675628, -0.3344063163, -0.7397027016, 1.519084692, 0.0405279025, 0.9089628458, 0.3263829648, -2.2702953815, + 0.2929112017, 1.2355471849, 0.7129567266, 0.5659303069, 1.585965991, 0.3280636072, -1.5915364027, 1.1417033672, + -0.4248448312, 0.7930880785, 0.0883681923, 1.8440197706, 0.1610373408, 0.5732743144, 0.0075075594, 0.4905359447, + 0.667429328, -0.0319283381, 1.1117783785, -0.8937884569, -0.5062664151, -1.0149229765, -2.0016167164, -1.0205111504, + 2.2229752541, 0.011399758, 0.8003988266, 0.2961736619, -1.6971895695, 0.8078061342, 0.2169072777, 0.045191355, + 0.5088980198, 0.2208980471, 0.6954385042, 0.88635993, -0.3556869626, 0.5780002475, 1.171800375, 1.1406605244, + 1.0717451572, 0.4423497319, -0.5674478412, 0.2898722291, -0.9614549875, 2.5144340992, 2.3160614967, 0.8769077659, + -1.03700912, -2.4022161961, 0.6049721241, -0.4953610301, -2.3281629086, -1.4473972321, -0.9300103784, -0.9152269363, + 0.0122897141, -1.7381287813, -0.952154696, 1.2463902235, 1.2603173256, 1.0538812876, -0.4877656996, 1.4871590137, + 0.7009145617, 0.6607995033, -0.5052556396, -0.383058995, 0.2948637903, 0.695553124, 1.4680861235, -0.8497928381, + 0.3967521787, 0.3792177737, -1.8099541664, 0.8800607324, -0.2358582616, -0.0895350128, 0.4097339213, 0.1439082474, + -0.803925097, -0.5788547993, 0.6057286263, -0.0667697638, 0.5830227733, 0.9660890102, -0.2354748845, 0.4906316698, + -0.2285811156, 0.6608774662, 1.3144094944, -2.1506252289, 1.1890547276, -0.0107625481, 0.5143793821, 0.649328351, + -1.3720718622, 1.7808263302, -0.5661188364, -0.1417411417, 0.3248441517, 0.5483885407, -0.3008512259, -1.2304807901, + -0.3662090898, 0.140045166, -0.095951125, -2.2191183567, 1.1093850136, -0.0595243648, 0.9957280159, -1.1562790871, + 0.7081853747, 1.2150986195, -0.1032100692, 0.6972517371, 0.7193431854, -1.0294797421, -0.1768095046, 0.9343592525, + 0.2372649163, 0.7474091649, -1.5894510746, 0.7022696137, 0.8446638584, 0.7430752516, -0.6214725375, -0.4367303252, + -0.4456193745, 0.8655875325, -0.5149858594, 0.3280645013, -0.1024664417, 0.7322508693, -0.6337894201, -0.4929722548, + 2.4898169041, -0.8463423848, -0.5593562722, -0.5450578332, 0.8441916108, 1.4418475628, -1.0300234556, -0.6466807723, + 0.2288228869, 0.0954682603, -0.5915262103, -3.0876836777, -2.0283315182, 0.5751449466, -0.6132372022, -1.1095269918, + -0.0689608827, -0.0798729211, -1.4768925905, 2.1811816692, -0.2500698566, -0.5732578039, 1.0652742386, -0.8546937108, + -1.1292870045, 1.2695087194, -1.251052022, -0.8316658735, -1.6696878672, 0.454524219, 0.1797860861, 0.0970116705, + 1.2030805349, -0.7623143792, 0.8427641392, 0.2079904526, 0.750282824, 0.2300081998, 2.2469732761, 0.9968439341, + 0.6118012071, 0.4577815235, 1.2006202936, 0.4174729586, -0.2497812212, -0.2987058163, 1.5730762482, -0.7681244016, + -0.4798147976, -1.617280364, -1.7546819448, 0.2139769793, 0.361949265, 0.0847462118, -1.7089012861, -0.1561836153, + 0.3462845981, 0.618272543, -1.8326427937, 1.2170871496, -1.0436891317, -1.3648991585, -2.2823894024, -0.5620194077, + -0.5828886628, -1.7087174654, 0.6809772849, -1.0947186947, -0.210065946, -1.0447046757, 0.5272279978, -1.5686168671, + -0.1761078984, 1.0267621279, -0.9264883399, -0.5448895097, -1.1664751768, 0.9067573547, -0.1943168789, -0.9029732347, + 0.3409390152, -0.3423842192, -0.493380934, -0.1203116477, 0.6469014883, 1.4632275105, -2.2619640827, -0.4403368235, + -0.2874864936, 0.3995994627, 0.0293659437, 0.4649489224, 0.5351887345, 0.52583009, 0.208771348, 1.207945466, + -0.0458886884, 0.5520437956, 1.7916995287, 0.3296727836, -0.2645019591, 0.1053925529, -0.3000160456, 0.5894111991, + -1.7004368305, -1.1702919006, 0.7144211531, -0.3652415574, -0.4975321591, -1.2789793015, -1.5159935951, 0.9037019014, + 0.938651979, -0.2034149766, 0.0920588151, -1.9900647402, -1.4680039883, -0.842679739, 0.0067214174, 0.9794570804, + 0.5074473619, -0.4286257327, -0.6218476295, 1.3840569258, 2.5538566113, 0.6628007293, -0.2189400643, 0.4221946299, + -0.7699494958, -1.460631609, 1.2698231936, -1.3451348543, -0.1210730821, -0.9649879336, -1.0809884071, 0.5695738792, + 1.4865843058, -1.7563409805, -1.709590435, -0.8119915128, -0.5803133249, 0.2327409685, -0.686021626, 1.4256445169, + 0.5897830725, -1.0782427788, -1.7356255054, 0.8439821005, -1.0922048092, 0.3640676439, 0.1694461256, -0.2845337391, + -0.001591498, -0.6929503083, -0.380993396, 0.7967649698, 0.3464201391, -0.8488762379, 0.0735314563, 0.3796829581, + -0.3305215538, 0.1394914091, 0.2664026618, 0.5161311626, -1.1287683249, -0.262635082, 0.5476616025, 0.347605139, + -0.6108629704, -1.8545712233, -0.7726867795, -0.1765599549, -0.6290928125, -0.2056999356, 0.6018232107, -1.4811753035, + 0.9063700438, 0.5083891749, -1.283089757, -0.4046699703, 0.7701845765, 0.0314547308, 0.4233820736, 0.9221630096, + 1.7657654285, 2.3693754673, -0.102348119, 0.2427469939, 0.34537521, 1.0699369907, 0.3138153553, 2.0743460655, + -1.7169541121, -0.4115565419, -0.1496352702, 1.1596267223, -0.7840048075, -0.7558175325, 0.8825569153, 0.6057924628, + -0.0026302291, 0.6777153611, 0.7162336111, 0.8861199617, 0.9713836312, 1.057020545, 0.1008922532, 0.251919955, + -1.7796982527, 1.0196323395, 0.1301587075, -0.3126945794, -0.5350653529, 0.2415903062, -1.2447651625, 0.8951871991, + 0.1416310817, -0.5771242976, 0.3480791152, -0.5791205168, 0.5143607259, 0.6251235008, 0.4787263274, -0.5682345629, + 0.5818405747, 0.5476638079, -0.2344136238, 0.4926259518, 0.0020974108, 0.4648458064, -1.2469049692, 0.9685260057, + 0.2488428503, 0.8673420548, 1.3650695086, -2.1453146935, 0.0148590002, 2.2118170261, -0.479097724, 1.8335345984, + -0.401304245, 1.8113731146, 0.8131791949, -0.483818084, -0.5870887637, -0.3348998725, -1.5233494043, -1.4847657681, + 0.4049981236, -0.3059670329, 0.1298778802, 0.7187888026, -2.7429368496, 0.4560085237, 0.3684889376, 0.2669047713, + 0.5020672083, -0.0811798126, -0.007883206, -0.2715966403, 0.2410754412, 0.0067627095, -0.8049398661, -0.3467500806, + -1.1980543137, 0.3195302486, -1.2405413389, -1.0926430225, 1.2750275135, -0.2405105084, -0.1525734663, 0.574465096, + -0.3584517539, 1.9834860563, -0.0039220667, -0.2727905512, 0.8813328147, -0.8601807952, -0.0736739039, 0.319745481, + -1.5756418705, 0.5200622082, -0.4795474708, 2.6535255909, -0.9987680316, 1.2702453136, 0.3841578662, -0.4805614948, + 1.2172632217, 0.7606619596, -1.5414643288, 0.1976353973, 0.7160565257, 0.4035159051, 0.6984516382, 0.1601044387, + 1.0915095806, 0.3534328341, -0.1184051558, -0.4150804579, -1.8912463188, 0.4045003653, -1.8975316286, -2.2630052567, + -1.4463518858, 0.3579699993, 2.1300139427, 1.2352734804, -0.278960079, 1.3526080847, 0.3938015997, -1.3408533335, + 1.7260075808, -0.0077996096, 1.5074975491, 1.8468036652, 0.6475793123, -0.3252647221, -0.8967847228, 0.9662185311, + 0.1558922529, -0.1998231411, 0.6230989695, -1.4783391953, 0.6823682189, 0.8574786782, -0.8982612491, -0.0487452298, + 2.1404359341, -0.7900241613, 0.2257759124, -0.4074427187, -1.0557363033, -0.9133280516, 0.3864759505, -0.2905539274, + -0.7860685587, 0.7287256122, -1.2111824751, 1.0915997028, -0.574170351, -0.8632349372, 1.8330698013, -0.2431361377, + -1.3883429766, 0.5145610571, 0.4060795903, -0.3183524907, -0.0028131553, 0.1949463636, 0.1193532422, -0.5316559672, + 0.8666998148, -1.0010826588, -0.5808494687, 0.8329043984, 2.0336697102, -1.1984018087, 0.7143980265, 0.184846729, + 0.6511341333, 0.5259750485, -0.3475879431, -0.9058694839, -0.5467703342, -1.4293168783, -1.7306935787, 0.6718448997, + 0.5225819349, 1.116297245, -1.537299633, -0.7658146024, -0.6932194233, -0.5045186281, 0.7642450333, -0.5672447085, + -0.376285702, 1.3930920362, -1.0889377594, -0.9572563767, -0.0917122737, 0.6868191957, -0.4004735351, -1.3633692265, + 0.6427147388, -0.7196304798, -0.8512632251, 0.5361620188, -1.172545433, 0.1028381735, 0.5060002208, -1.3521600962, + -0.8992948532, -0.2606385052, 1.196321249, 0.446752727, 0.649058342, 0.6809411645, 1.4820773602, -0.7598612905, + 0.7339666486, 1.4499570131, -0.1634774804, -1.6448104382, 0.0809721798, -1.1142492294, -0.290120542, -0.1146303713, + 0.2195672244, 0.408021003, -1.0791637897, -1.8717880249, 1.6003428698, -0.1694111526, -0.3783018291, -1.603050828, + 0.2283682078, 1.0475113392, 0.7307556272, -0.4210613668, -0.3517955542, -0.4050840735, -0.5490471125, -0.3479705453, + 1.9079108238, 0.3872929811, -1.1613664627, -0.15164949, 0.3707110584, 1.4472540617, -0.2746278346, 0.4029833674, + -1.205196023, 0.2465004772, -0.70653826, 0.0371126421, 0.8646813035, -0.6913815737, -0.3071915507, -0.1538460851, + -1.7917917967, -1.2598940134, -1.8016839027, 0.9368255734, -1.3379613161, 0.5263180733, -1.578283906, -0.4033615589, + 1.0468375683, 0.8125714064, -0.4790661335, 1.0822108984, 0.530630827, 3.2135152817, 0.6620602608, -1.6667072773, + 0.0143323876, 2.9585022926, 1.22151196, 0.4183119833, -1.1557128429, -1.1458501816, 1.0365495682, -0.2553441823, + -0.4749603271, -0.4489164948, -0.1246030629, 0.9618656039, 0.05798392, -0.3051787019, 0.12026494, 0.0543751307, + -0.608612895, 0.0081361765, 0.4306674302, -0.0972862765, 0.3353385031, -0.2733195722, -0.1604502201, 0.9772319198, + -0.1361977905, -0.5129996538, 0.6338104606, 0.1387738585, 0.1811870933, -0.4650717676, -0.2434235364, 1.3702030182, + -1.0426175594, -1.5735248327, -0.5793191195, -0.3952281177, 0.6459346414, -1.9756667614, 0.348967135, 2.3008513451, + 0.0771680027, 0.6087843776, -1.4710805416, 0.3890483677, -0.529536128, 0.9832375646, 0.1260338128, 0.8573789001, + 0.2447784096, 0.3204292953, -2.5175051689, -0.7122991681, -0.8745144606, 0.014117429, 0.9317763448, -0.9803977013, + -1.5740404129, -0.3517892361, -0.8231508136, 0.0262164883, 0.6211560369, -2.0268793106, 1.0612952709, -0.355250001, + 0.953699708, -1.2097529173, 0.4185555279, 0.2573874295, 0.6497887969, 0.874068141, 0.4048483372, -0.4238315225, + -1.9540976286, 0.4655889571, -0.0313888192, -0.2161873132, -0.2317292094, -0.0759339109, 0.0675848275, 0.0878292397, + -0.9489600062, -0.1432806849, 1.1445298195, -2.7369377613, -0.5840117931, -0.5899749398, 1.2879940271, 1.3466374874, + 1.096208334, 0.2304671705, -1.7148902416, 1.3411163092, 0.1041158214, -0.078877911, -2.2844712734, -1.0280727148, + -1.2645610571, 1.1588771343, -0.4571908414, 1.2539838552, -0.2162689269, -1.7553088665, 0.2741356492, 0.7430927157, + -1.1741378307, 0.3358246982, 0.023806043, 0.0031688462, -1.3877177238, 0.5490756631, 1.1530783176, 1.6128815413, + -0.3410646319, -1.293766737, -1.6469665766, -0.7334685326, 0.1037245989, 0.8387489319, 0.0148075577, 0.5645905137, + -1.303996563, -0.5846779943, -1.5839500427, -0.2638729811, -0.0072477343, 0.8843932748, -0.3676111102, -1.5938299894, + -0.8872205019, -0.4249498248, -0.1557797194, -1.3146603107, -0.1697295159, -0.2765368521, 0.4457674026, 0.9021023512, + 0.1397904456, 1.7429642677, -0.4599343836, -0.6597484946, 0.4328436255, 1.4983532429, 1.2432944775, -0.4208336174, + 0.4489599764, 0.1689072102, -0.492606014, -0.0422246605, -2.3662722111, -1.8588395119, 0.3812257349, -0.7578253746, + 1.2569688559, -0.3351842761, -0.7692585588, 0.4607789814, 0.8273998499, -1.1147665977, 0.816270113, -0.2671040297, + 1.407335043, -0.7888681293, 0.1561743319, -1.2401427031, -1.2775328159, -0.764637351, -0.647551775, 2.0057315826, + 1.0876049995, -1.1954290867, -0.1807238609, -0.8135599494, -1.2610627413, -0.9346448779, 0.3905242085, -1.4709957838, + 0.6816416979, -0.4965876043, -0.1572820246, -0.4188430607, 1.1873232126, 0.930875361, -1.9551130533, 1.0496579409, + -1.0345253944, 0.8236737847, 0.5495346189, 0.5497707725, 2.3413565159, 1.648409009, -0.7264957428, 0.3208186626, + 0.282482475, -0.6003243327, 0.445769608, 1.7169154882, 0.0159275644, -1.6579325199, -1.0831270218, -0.5027672648, + -0.6477096677, 1.4063690901, 0.3528015018, 1.1226716042, -1.5352687836, 0.3197790682, -0.2060278803, 1.3496638536, + 0.6235291958, 0.042133145, -0.3542109728, -0.6579025388, -0.6250056624, 0.6840335131, 1.34918046, -0.679803431, + 1.031149745, 0.3708248138, 2.3034310341, -0.8823706508, 0.2779397368, 0.2376018465, -1.0999842882, -2.3625836372, + 2.5004153252, -0.0031369352, -0.5761529207, -0.9552867413, -1.1486686468, 0.2252877206, 1.3544378281, 1.1923971176, + -1.0452986956, 0.4250714779, -0.653412044, -0.9170339704, -1.8241276741, 0.6940741539, 1.0891760588, 1.1354733706, + 0.8429929614, -0.5788779855, -0.3875228167, -0.5509646535, -1.9952298403, 0.8218613863, 0.6798110604, 1.1460310221, + -1.0449521542, -0.5703985691, 0.5750790834, -0.7848528624, -0.5177422166, 0.2719036937, 0.5763064623, 1.7560209036, + 0.78673774, -0.8005876541, -1.3305873871, -1.3257182837, 0.7724911571, -1.8970799446, 0.9184693694, -0.5014103055, + 0.5121781826, -0.2338661253, -1.9732248783, -1.2685248852, 0.5421708822, 0.3566212654, -2.7719295025, 0.0120019102, + 0.2266089767, 1.5233207941, -0.5277122855, 0.899279058, 0.9162186384, 1.3245271444, -0.3380609453, -0.2191164792, + 0.1802497059, 0.7791525126, 0.3603124619, 0.6356837749, -0.0949871168, -0.1510977745, 1.0524718761, -0.8924908042, + 0.1134970784, 0.7762354612, -0.1041747034, -1.2717193365, 0.1911706775, 0.2469402403, -0.4907810986, -0.0449020043, + -1.1582369804, -1.8383409977, -1.4759110212, 1.8879642487, 1.220494628, 0.7254795432, -2.1488111019, -1.9087783098, + 0.836374402, 0.1254971474, 1.1508957148, 0.1561222225, -0.1453067958, -1.0493863821, -0.3168115318, 0.5137270093, + -0.6062394381, -1.0988081694, 1.2591933012, -0.1684797853, -1.2144109011, 1.3161044121, -0.2794598639, 0.630571723, + -1.1718168259, -0.5043300986, 1.329668045, 0.6659186482, 0.0582517385, 0.0609587096, -1.5843622684, 0.9506537914, + 1.3065859079, -2.2422685623, 0.5747953057, -0.1019831151, 0.1581490189, -1.2338908911, -0.7650310993, -0.4184915423, + -0.9221194386, 0.6965978742, -0.8460552692, 0.1583629102, 0.8735681772, -0.3400534987, -0.1723876595, 2.3087937832, + 0.6242477298, -0.3329307139, 0.1324429065, -0.5053774714, -0.9988173246, -0.9100036621, 0.0229380503, -1.2823932171, + -0.3242506385, -0.622523725, 0.7587878704, -1.69662714, -0.3292137086, -0.9888989329, 1.8447217941, 0.6552241445, + 0.5138090253, -0.7122284174, -0.68968606, 0.2713268697, 0.2952925265, 0.1329986453, -0.2784538269, -1.2005258799, + -0.4423667192, -1.3582398891, 2.2271566391, 1.731998086, 0.1650353372, 0.6235536337, 0.9041349292, -0.7492755055, + -0.6408665776, 0.5311431289, 1.135078907, -0.0610747412, 1.5564525127, -1.1107958555, -0.9086764455, 0.4045865536, + -1.2979991436, -0.3478908539, -0.6960718632, -1.78670156, -0.3869774938, 0.397544384, 0.3818458319, -0.9753320217, + -0.2342271954, -1.3683166504, -0.2547301948, -2.3559172153, 0.354280293, 0.6389033198, -0.2198933065, -1.5690653324, + -0.4407686889, 0.8176122904, -0.0587791465, 1.2063684464, 1.1797443628, -0.3437459171, -0.4739488363, -1.5506465435, + -0.3452513516, 0.8360907435, -0.8022053242, 1.5924566984, -1.5707868338, -1.0464003086, -1.2346476316, -1.5263248682, + 0.8003885746, 1.1033037901, -0.1054809988, 1.4715224504, -1.7682429552, -1.1850502491, -0.8126041293, 0.8842704296, + 0.9425088763, 0.0330735892, -0.2409315258, 1.5489830971, 0.6468773484, -0.1781851649, -2.7890059948, -0.0014940457, + 0.4603638053, 0.1230962947, 1.5464887619, 0.3794255853, -0.7880982161, 0.7934423089, -1.5169560909, 0.038055785, + -1.4559270144, 0.5339881182, 0.3679506779, -1.158629775, 0.0873472542, -0.5471687913, 0.0661044717, 2.198964119, + 0.2341248393, 1.7468538284, 3.7643828392, -0.9423438311, -0.0853690207, 1.9483058453, -0.2876728475, -0.1539317667, + 1.6529641151, 1.3316450119, 0.9574147463, -1.1216984987, -1.0181498528, -0.7338421345, -1.3882849216, 1.0699387789, + -0.6837269664, -1.2928775549, -0.1253340095, 0.4996267855, 0.9240604639, 0.5986737013, 1.7402137518, 0.3486900628, + -0.5245723724, -1.1849862337, 0.2726819515, -1.6281638145, 0.2654599845, -0.4116245806, 0.45746243, -0.1537874192, + -1.9013284445, 1.4959928989, -0.0532272644, -1.2966313362, -1.3777812719, -0.1085461006, -1.1366568804, 2.4738366604, + -0.6625595093, -0.3700547814, -0.6848813891, -0.9847663045, -0.3399543166, -0.779815197, 1.1458569765, 1.2416856289, + -1.1501663923, -0.6315066814, 1.1676069498, -1.4100657701, -0.568770051, -0.5040619969, 1.4950553179, -0.758646071, + 0.3278019726, 1.1096271276, -0.3833582699, 0.2235788554, -0.5815556645, 0.0966813415, -0.6273540854, 0.6732571125, + 0.0662461072, -0.1287237704, -0.8700714111, 0.8890676498, -0.3600372672, 1.6472837925, -1.6016446352, 0.8628495336, + 0.4772661924, 0.0748748258, -0.3812872469, -0.7134984136, 0.6940374374, -1.6486783028, 1.4736716747, -0.0254137758, + 0.0967500806, -0.1661897451, 1.1823667288, -0.6112408042, -1.540415287, 1.2952648401, 0.7924426794, -0.4812881052, + 0.8054927588, -0.2136539519, -1.7206912041, -0.3016053438, 0.2895011902, 2.0912322998, -1.9579486847, -0.8064804673, + -0.3919655383, 1.6497608423, 1.0967392921, -0.0155962491, -0.0089084962, 0.5606082082, -0.7090340853, 0.7310581207, + 0.0730704814, 0.6230039597, 0.4864089191, 0.4549812078, -0.2649352551, -1.1511001587, -0.9840397239, -0.2999227345, + 2.2628390789, 1.1271271706, 0.3714485168, 0.2622233927, 1.4365916252, 2.0530672073, -0.0107169645, 0.6136042476, + 0.0226049926, -0.0324297585, -0.772108078, -0.5181171894, -0.3055936694, 1.3205901384, -1.5773636103, -0.3167185187, + -0.1485596001, -1.1861242056, 0.1441131532, 0.7637791038, -1.986127615, -0.2936843038, 0.8477237821, 0.0517439954, + 0.0406466722, -0.970518887, -0.7261933684, -0.0312301386, 0.3390150666, -1.0390940905, 0.2602939308, 2.0953760147, + 0.0473578013, 1.2825541496, -0.3004450202, 0.541087687, -0.1447229385, 0.4664852023, 0.363292098, 0.58820647, + -1.5549762249, 0.0268624183, -1.0717278719, -0.1177723333, -0.4627850652, 0.3465367556, 2.2943594456, 1.7421190739, + 0.0722834393, 0.5992326736, -0.783626914, 0.5283228755, 0.032248836, 0.5551918149, 0.2175752223, -0.4546332657, + 1.4639328718, -0.6801419854, -0.0971610919, 0.6066857576, 1.3741084337, 0.2518433928, 0.6852304339, 0.2889463305, + -0.1472174823, 0.2218355238, -0.0487602502, -1.0502138138, -2.2987830639, 1.5475156307, 0.3123504221, 1.0007822514, + -1.753334403, 0.3010531962, -0.1631305069, 0.4981911182, -1.0523788929, 1.5803315639, -0.5132887363, 0.2444366068, + -0.7612324953, -1.0226480961, -1.5267606974, 1.2850830555, 1.5239545107, -1.4156295061, -0.8883552551, 1.0721236467, + -0.7571452856, -1.2760622501, -0.0873958692, 1.1551344395, -0.2928124964, 0.1826197952, -0.1817886829, 0.0830894485, + -1.1084549427, 2.3446435928, -0.1304149628, 0.8465356231, -0.087031506, -0.2174553275, 0.1470153332, 0.6346374154, + -0.2693883181, 1.3204683065, -0.3679193556, 1.1488084793, -1.1435592175, -0.4943830669, -0.2291122079, 0.2982085347, + -0.9264073372, 0.9086833, 0.8751946092, 0.3901867867, 1.0084059238, 0.2700186968, 0.4779162705, 0.2833504975, + 0.097134918, -1.3063620329, -0.7672454119, 0.1625791639, 0.173691541, -0.8138611317, -0.3182066679, -0.5231506228, + -1.3166358471, -0.2597752213, -2.854695797, 0.2950502336, -2.2095010281, -1.1995346546, 0.1285841912, -0.0192146059, + -2.2865560055, 0.8165867925, -1.3509417772, 0.7002499104, 0.3727229536, -0.4820721447, 0.8639489412, 0.8133208156, + 0.0887968391, -0.3125910759, 3.0393307209, 1.4080055952, 0.2269381732, -0.0300363377, 0.7396939397, 0.0493804477, + -0.4246927202, 0.1304106563, 0.9637285471, -2.9354915619, -0.3544369638, 1.2836763859, -0.8559589386, 1.8721460104, + 0.9731093049, 0.5492524505, -1.0334913731, 1.325191617, 1.310872674, 0.5195982456, -0.4179671109, 0.6543501616, + 0.469324559, 0.8555210829, 0.0848020539, -0.1515882611, -1.7304179668, -1.088332653, 1.010294795, -0.2386721522, + 0.8745925426, 1.3899519444, 0.7876927257, 0.6158488393, 0.5215525627, 1.4409991503, -0.0144396611, 2.2355680466, + 0.4180262387, 1.0790933371, -1.4335969687, 0.7017084956, -0.0270159505, -0.0620286353, 1.0418047905, 1.2607593536, + -0.8740250468, 0.3189888597, 0.2929864824, -0.8016648293, 1.1566418409, -0.38634938, -0.6131212711, 0.4015072286, + -0.3994033933, 0.5563696027, -0.38702932, -0.7484621406, 1.9729208946, 0.3187820911, -1.0970444679, -0.808655858, + -2.5966191292, 0.6420378089, 0.6515240073, -1.5672519207, -1.188709259, 0.1352421641, -0.1588215977, -1.1035181284, + -0.3870321214, -0.128594026, -0.0611574203, 0.5199727416, -0.6207996607, -0.8858322501, 0.2921783328, 1.7415742874, + 1.1214604378, 0.4722931385, -0.0375859216, 0.904214561, 1.5266809464, 0.9645444751, 1.194429636, 0.3133407533, + 0.0609702654, -0.7147462368, -0.9949486852, 0.0263745487, -0.9406294823, 0.6160652637, 2.3014707565, -1.1834588051, + -0.8900075555, -0.2471520454, 0.4672086537, 1.9268618822, -0.6749277711, 0.6205279827, -0.2686580122, -0.7099538445, + -0.9639384151, 0.7790831327, -0.5402551293, -0.0003102511, -0.8768327236, -1.068748951, -0.4675288796, -0.2242846638, + 0.8382201195, -0.3525581658, -0.7518466711, 0.4557478726, 0.2760375738, 0.619554162, 0.3318205774, 0.8327250481, + 0.0537931845, -0.3553763926, -2.0381026268, 1.6230796576, -1.5148580074, -0.186047852, -2.0974383354, -0.2627943754, + -2.4067049026, -0.476721406, 1.3863887787, -0.719640851, -0.1204650104, 0.7024926543, -0.8471753597, -0.4811016917, + -0.2101222873, -1.5753133297, 0.0518422872, -0.6725054979, -0.077130571, 0.2476974279, 1.1442660093, 0.821392417, + -2.0979964733, 0.0083712144, -2.8003196716, 0.5200743675, 1.1690288782, 1.6796238422, 1.7359300852, -0.3625329137, + 0.872977078, 0.0395113789, 0.4805897474, 0.897157073, 1.05087924, -1.1386889219, 0.2386064231, -2.1639914513, + 0.1895284206, 0.710801363, -0.1431214809, 1.1821506023, 0.4952346385, 0.0679816455, 1.960055232, -2.0621733665, + -2.3717496395, -0.020610204, -1.3767124414, 1.6856360435, -0.5215978622, -0.1548906118, 1.1633713245, 0.1333243102, + -0.9365465641, -1.1232398748, -0.1756432503, -1.5008443594, 2.0137960911, 0.5293657184, 0.4739171267, -0.0677911416, + 2.730640173, -0.8007552624, 0.8647549748, 0.1554780453, 0.2040397525, -0.1762325615, 0.3810936511, -0.2150106728, + 0.1929219216, 1.3094671965, -1.0703794956, -0.6601840854, 0.1119203046, -1.0493140221, 0.6418649554, 1.0578992367, + 0.3493487239, 0.0387381762, -0.7578765154, 1.7252588272, -1.1950592995, -1.0095664263, 0.8863735199, -0.933234036, + 1.0328786373, -0.3667743504, -0.6750990748, -1.0239139795, 0.6232453585, -0.4233544767, -0.6697765589, 0.3974470198, + 0.1741041839, -0.2741079032, -0.0697648525, -0.2788359821, 0.0967028365, 0.4162475765, 0.0730348527, 1.6830052137, + -1.7050038576, -0.9182111025, -0.0687336549, -0.4993008077, -2.6333050728, 1.2867982388, -0.8157199621, 1.813867569, + 1.3882590532, -0.6029289961, 0.0287784822, 1.1772009134, -0.2755854428, -1.2099580765, -0.2019699514, 1.2501586676, + -1.0892593861, 2.4252128601, 0.815489471, -1.0352143049, -0.2517317533, -1.3882302046, 0.9432877302, 0.7587483525, + 1.0898754597, 1.0566821098, -0.8384352922, -0.3188551664, 0.1994140446, -0.7795777917, 2.1310243607, -1.7256475687, + -0.3948467374, -0.7480053306, 0.7033433914, 0.5914207101, 0.0639219061, -0.3472526371, -0.246750176, 0.1587737948, + 1.3566329479, -0.1416103244, 1.3385957479, 0.9539729953, 0.0049228636, 0.9412178993, 0.6962132454, 0.8853695393, + 0.0664721727, -2.7985961437, -0.9155045152, -0.0428128801, -0.666603446, 0.9059969783, -0.3675763011, -0.5666050315, + -0.6845122576, 1.0391764641, -1.1581093073, -0.0269874949, -1.3750796318, 0.9732193351, 1.2611368895, 0.0356923081, + 0.2246537358, -3.0932531357, 2.3984165192, 2.297911644, -1.7785514593, 1.3218277693, 0.128021121, 2.0275268555, + -1.0245759487, 0.8668836355, -0.8607371449, -0.7002310753, 0.0155158956, -1.4728592634, 1.7080414295, -0.7406947017, + 0.8791487813, -0.4585764706, 0.3052116632, 0.0468687899, 0.5164999366, 2.0355801582, 0.6521666646, 1.8466851711, + 1.7116943598, 0.6319134235, 1.3719582558, -1.6670839787, 0.4300492704, -0.6846798062, 0.9375258684, 0.3836639822, + -0.0728900358, 0.0684805885, 0.308789283, 0.6202475429, -0.7178317904, -0.2522747517, 1.1459041834, 2.0370550156, + -0.2767766118, -1.3960233927, -0.9338543415, 1.1877619028, -2.6348557472, 1.9516296387, -0.1824237257, -2.0092451572, + -0.9741954803, 0.4679149389, 0.9008089304, -0.5722278953, 0.6044968963, 0.6506953239, -1.6755926609, 1.5076848269, + -0.5969001055, -1.0222656727, 1.9562164545, -1.2689777613, -1.7846150398, 0.1661764532, -1.5170683861, -0.7610163093, + -0.8992091417, -1.6415470839, 1.320432663, -0.2228368372, 0.7749367356, 0.4024796188, -1.3226431608, 0.2422006428, + -0.4162628353, -0.5555692911, 0.0719668418, -0.1871663779, 0.5951982737, -0.584553659, -2.1090695858, -0.1772703975, + -0.05487331, 0.4509508312, -0.931335032, -1.7773886919, -0.3563153446, 0.2669277191, 0.2997245789, -0.4658081532, + 0.5417457819, -0.2356391251, 0.4109375477, 1.5283123255, -0.335172683, -0.3406950831, 1.2914118767, 1.3758453131, + 0.8519734144, 0.4109028578, -0.3435279429, 0.842243433, -0.0266405381, -1.5175741911, -0.127677545, -1.5115371943, + 0.3101183772, -0.6066270471, 1.037628293, -0.0093769059, -0.0544994585, -0.5122949481, -1.2871826887, -1.0043041706, + -0.8428524733, 0.1637625247, 0.1111728325, 0.0281228572, 1.3473829031, 0.0723849237, -0.169296205, -0.8452322483, + 0.593793273, -1.5416975021, 0.5983489752, -0.2016807795, -0.496758461, 0.1199091077, 0.4734321535, -0.0088558868, + 1.2080721855, -0.3648279011, -0.695569098, -0.4260819256, -0.7084145546, 0.049147632, -1.5102821589, 1.0569622517, + 0.5366889834, -0.0563135706, 1.5393899679, 1.7595765591, -0.3918105364, 0.919729948, 0.3016016781, -0.1586421728, + 0.0058817188, 0.4183733761, 1.5566524267, -0.6086767316, -0.5249670744, -0.8945267797, 1.9990261793, 1.0346226692, + 0.9244108796, 1.8088890314, 0.4348047376, -0.7111964226, -1.3284702301, -1.1754543781, 0.3776286244, 0.4044982493, + 1.7677334547, -1.0616512299, 2.2402262688, -0.155071944, 0.1358435005, -0.1329102516, -0.7924153805, -1.354134202, + -0.0541118197, 0.7407044172, 0.1474341452, 1.3359956741, 0.740929544, -1.4758354425, 0.0812779739, 1.5620260239, + 0.1671449095, 0.3341617882, 1.3199590445, -1.4782437086, -0.5552400947, -0.2017293274, -0.4659951627, 0.2432397157, + -0.6974768043, -1.2883409262, -0.7465677857, -1.1168094873, 0.4712827206, 1.6376899481, 0.6912307143, -1.3686044216, + 0.1189413965, -1.4354121685, -0.1401813477, -1.1164814234, 0.3037294745, -0.3992435634, 0.2656225264, 0.313026011, + -0.8659200072, -0.4726854563, -0.0152176367, -0.0930923, 0.3841016293, 0.9208854437, -1.3471815586, -0.2411450744, + 1.6320923567, -0.6548956037, -0.4167873561, -1.5803978443, -0.1135653034, -1.2573654652, -2.0530848503, 0.9897403121, + -0.4235695899, 1.5027476549, -0.6127468348, 0.2498405725, -0.1621945947, 0.5481315255, -1.0397114754, 1.0767316818, + 0.6571477652, 0.8535944223, 0.3218203485, 1.0353807211, 0.2963234782, -1.5258238316, 1.6403651237, 0.4474198818, + 0.515997529, 0.0112749394, -0.4295137823, -0.0053783916, 0.8010345101, 0.0232382063, -0.5535251498, -0.7191053629, + -1.7811300755, -0.3628551364, 0.5310444832, 2.4867811203, 1.9475063086, 0.4156304598, 0.6378083229, -1.8176249266, + -0.4333888888, 1.0649061203, -0.7765557766, -1.1090966463, 0.0572323352, 0.2367252856, -0.1627569199, -0.0342329107, + 1.1516398191, 0.0576944612, 2.5441424847, 0.4243032932, 0.6389544606, -0.7369576693, -0.4054327011, -0.1950183809, + 1.2195286751, -0.7707237601, 0.3494344354, -0.8499855399, -0.4434051812, -0.8354090452, 0.6398029327, 0.0468047112, + -0.0552285872, 0.5982164145, 1.0310800076, 1.2464448214, 1.546749115, 1.9671247005, -0.7465594411, -1.246057272, + -2.2472889423, 0.7259353995, 0.686058104, -0.9589980245, 0.7132995129, -0.4153469801, -0.3921484649, 1.2021461725, + -0.0087545915, 0.3043210506, 0.5953631401, 0.1601187736, -0.7451269031, 0.2441005409, 0.3973066509, 0.2535099089, + -1.4309951067, -1.6279504299, -1.132307291, -1.2013375759, 1.3001255989, 1.8920334578, -1.2963359356, -0.4052232206, + -1.9754989147, 0.7988344431, 0.4170355797, -0.4807196558, -2.0655698776, -0.7232215405, -0.8220478296, -0.4829567671, + 0.0755685493, 0.6312243342, 0.5088500381, -2.4266726971, -0.6307898164, 0.1054759845, -0.3693656921, 1.7723187208, + 0.6556220055, -1.3453546762, -0.672090888, 1.1442575455, -1.4109114408, 1.2649291754, -0.8008374572, 0.0384092443, + -0.2519807816, -0.2426828742, 1.2038187981, 0.4667410553, -1.0764840841, 1.2552109957, 1.3426625729, 1.5059294701, + -0.9154779315, -0.0498299412, 2.0281126499, 0.683560431, -1.8105126619, 0.4737175107, -0.8432004452, 2.0750002861, + 0.2878215015, -1.1522181034, 2.0514914989, -0.7687619328, -0.6637822986, 0.6724092364, 0.6839038134, 0.0562897585, + -0.3016141951, 0.4957450032, 1.063783884, -0.6770959496, 0.2365283668, -0.2895208299, -0.8617882729, -0.9594106674, + -0.0157391503, 0.8399378061, 0.8110836148, 0.461168766, -0.7466703057, -0.0806623921, -0.9150440097, -0.9413416386, + 0.3335480094, -0.3684301674, 0.4436233044, 1.0678399801, 0.5630221963, 1.3437930346, -1.7708089352, 0.3103902936, + 0.6368618011, -0.4932948351, -0.2312989533, -0.3020412326, 0.092323564, 1.3628299236, 0.7628677487, 0.7790932655, + 1.5329159498, 0.2183266133, -1.2446256876, 1.0062347651, -0.0709650144, -0.7959281206, 1.2688463926, -0.817579329, + -1.027363658, -0.6656317711, 1.1612483263, -0.5840453506, 1.4325695038, -0.8769946098, -0.5628446341, -0.262191534, + 0.6548326015, 0.0389738902, 1.736939311, 2.3276939392, 0.2912586033, -0.1409829259, 0.8625109196, -1.4595911503, + 0.2316573858, 0.9324889183, -0.6206426024, 0.5359648466, -0.3008208573, 0.0612839088, -1.7155638933, 0.9352427721, + 0.1170468032, 1.0926513672, -1.5903171301, 1.6055085659, -0.127000615, 2.5916931629, 0.3588993847, -0.4123798013, + -1.4389734268, -0.4076504111, -0.3596978486, 1.8169152737, 0.3336016238, 2.4945390224, -0.6098358631, -0.3644248843, + 0.8882802129, 0.4999442995, 0.5015850663, 0.6149253845, 1.1175642014, 1.807929039, 0.2978225946, 0.61175704, + 1.7117923498, 0.4619747698, -0.2899212837, 0.7065873146, 0.172173053, 1.0118405819, 0.7275610566, -0.6780998707, + -0.1265953183, 0.9778655767, -1.3090860844, -0.4225935042, -0.1998132616, 0.0992397964, 0.9909891486, -0.8389635086, + -0.2723429799, 1.9301704168, 0.9522368312, -0.8642147779, 0.6867908239, 1.238142252, 0.8961113095, 1.7952609062, + -0.2819908857, 0.7153847218, 0.0273373686, -1.3802032471, -2.0942184925, 1.0688688755, 0.2658931017, 0.9404011965, + -0.0069303596, 0.5577315092, 0.2194401324, 0.525827229, 0.587608397, -1.1635379791, -0.5140573978, -1.4443894625, + -2.1708698273, -0.1201778799, -0.6402384043, 0.2971675098, 0.130451113, 0.1133562103, 0.6318150163, 0.1640680581, + 1.5028864145, -1.7749533653, -0.7292850018, 0.1292218417, 0.1633696705, 0.5901848078, 0.9318404198, 0.0090533029, + 0.5410732627, 0.6497133374, 0.0382000655, 0.2489194572, -2.0864832401, -0.4515062571, -1.2362923622, -0.2087910324, + -1.2355883121, 0.5569347739, 1.3323907852, 0.543851018, -0.1150219962, 0.0459278598, 0.4252981246, -1.4181237221, + -1.7148958445, 0.639929235, 1.3488681316, -0.524969697, -0.7036726475, 0.3729901612, 1.3503198624, -0.656224668, + -1.8335790634, -0.7283580303, 0.4336759746, -0.0378222503, -0.2591528594, 0.6934357285, 0.2126318961, -0.2649644017, + -0.5409034491, -0.1988546699, -0.09062998, 0.130639106, -0.6612063646, 0.3144090772, -2.131547451, 0.5624923706, + 0.6593207717, -0.6201909781, -0.5569365025, 0.3504077792, -1.3898166418, -0.326731205, -1.5478287935, -1.0569232702, + 0.408950299, 1.057407856, 0.3555086255, 1.3506741524, 0.7100051045, -2.4160699844, 0.2878858447, 0.1611437201, + -0.5060824156, -0.5658532381, 0.0795270875, -0.5061843991, 0.2112802863, 0.1915567666, -0.1671071202, -0.4966573715, + -0.3014395535, 1.4349435568, -0.008196977, 0.8687512875, 1.7044713497, 0.7172669172, 0.1723873615, 0.7683315873, + 0.8068082333, 0.737447083, -2.3381924629, 1.4708920717, -0.6122639179, 1.1907120943, 1.3497942686, -1.3654749393, + -0.3542251587, 0.6783241034, 0.74579072, -0.1441514641, 1.707339406, 0.104320161, 0.4953304827, 0.4898969233, + -0.7908129692, 0.3112324178, 1.28548491, -1.1699900627, 0.0307697803, -0.0978933945, 0.2470248342, 1.5309244394, + 0.0981095359, 1.4879208803, 0.6778614521, 0.1257022619, -0.6889806986, -1.7376300097, 1.6067085266, 0.2240911871, + 0.3167164326, -1.0415329933, 0.6432635784, -0.1780188829, 0.2714662552, 0.5061727762, -0.0400048196, 0.6168119907, + 1.1573162079, -0.6214919686, -0.0559455715, 0.2033772618, -0.0524638593, 0.4651843607, 0.7974411249, 0.9521196485, + -0.8156989813, -0.7175847292, 0.0430429354, -1.1026031971, 0.7501711249, -0.0570429079, 0.2406162471, -0.1664299071, + -0.4878765345, -0.8518081903, 1.0820053816, 0.2024823874, -0.6305008531, 0.5867401361, -0.111148268, 0.9543295503, + -1.55154562, -1.3526494503, -1.2814865112, -1.2083516121, 0.6300700307, 1.2377527952, 0.1157994419, -0.1324049979, + 0.8532496691, -0.2272783518, -1.9050981998, -1.4512780905, 0.5527977347, 1.9561060667, -0.5117322803, 0.2994587719, + -0.8818569779, 0.7253333926, -0.2888867855, -0.0488190539, 0.611141324, 0.872705996, 1.0785720348, 0.6621670127, + 1.1721650362, -0.5383167863, 0.7041527033, 0.8776189685, -0.1341997683, 0.5267609954, -2.2195818424, -0.0641778633, + -1.47656703, -1.6097735167, -0.2215120941, 1.0128235817, 0.3994425237, -0.6306587458, 0.8556500673, 0.5664199591, + -2.7598052025, -0.5542398691, 0.954669714, 0.2972911, -0.5923198462, 0.8346678019, -0.5135295391, -0.2254577875, + 0.3647433221, -1.1742988825, -0.0221651979, 0.2011860758, -1.1618353128, 0.3587828279, -0.3569490016, -0.6757637858, + 0.1543741524, 0.5523005724, 1.1413083076, 0.9759478569, 1.3029022217, 1.5852334499, 0.5111664534, 0.9931082726, + 0.9090556502, -0.8942973018, -0.8136970401, -0.3231808841, -2.9619100094, -1.726057291, 0.6305112243, 0.9046978951, + -0.6565795541, 1.1913491488, -0.6926817298, 0.8507476449, -1.4126199484, 1.5484261513, -0.353205204, -0.1554211229, + -0.5210480094, 0.5052769184, -0.5785877705, -1.8058321476, 0.4119521677, 1.2402284145, 0.5937663317, 0.9732915163, + -0.3283392489, 0.1560894847, 0.2356980294, 0.0013753889, 0.4547128677, 0.2108037323, 2.2417321205, -1.5689145327, + 1.9793784618, 0.6024902463, 0.114105843, -1.3041629791, 0.5927038789, -1.456930995, 2.2926297188, -0.7402815223, + -0.0437542982, 2.4251124859, 1.0239573717, -0.9977756739, -0.7223476768, -0.6301113963, 1.4681988955, 1.1038920879, + 0.2033595741, -0.6396667361, -0.1190782934, -0.0005420816, -0.1301973015, 1.563903451, 0.0902540758, -0.1481139511, + 0.6896650195, -0.5098571777, -0.3564096689, 1.5234655142, 0.850895822, 0.8980773091, 0.5878921747, 0.0211714022, + 0.1310488582, -1.7261478901, 0.4319587052, 3.3127100468, 1.2555725574, -2.4129700661, 0.1548143625, -1.3937963247, + -0.0669993684, -0.494586885, 0.6425649524, 0.4099414349, -1.2230517864, 1.1344254017, 0.2476155311, -0.0826025009, + -1.7094839811, -1.3960864544, 0.0779310912, 1.0671143532, -0.7367090583, -0.8694255948, -2.1651918888, 0.2056596577, + -0.6978781819, -1.3931280375, 1.168900609, -1.0735945702, -0.1320720315, 0.3157189786, -1.1467095613, -1.8069293499, + 0.3965733051, 0.6804736853, 1.1677420139, 0.1507781297, 1.5749038458, -1.6790566444, -0.4240026474, -0.0486205667, + -0.4190273285, 0.0764597952, 0.2051582783, -0.1262133867, -0.0686233491, 0.9195166826, 0.2387665063, -0.1942841411, + -0.9263069034, 2.2984178066, 1.1526581049, 0.8616171479, 0.3174169362, -1.7027870417, -1.7472238541, 1.0208576918, + -0.355627507, -0.1951083988, 0.7903609872, 1.3327525854, 0.8751086593, 0.2799882591, 0.1954333037, -0.39372769, + -1.7281918526, 0.0852415413, 0.93250072, -0.1659661531, 0.709115386, -0.4390468597, 0.0979182422, -1.1979483366, + 0.4096597433, 0.1257333606, -0.6742489338, -1.502848506, -0.7201532125, 1.8562434912, 0.0316390693, -0.5786090493, + 0.8689778447, -1.4990413189, 1.055202961, -1.6764425039, -1.5236849785, -1.5653573275, 0.4090256691, 0.1788931787, + -0.1072124392, -0.7379006743, -0.0220090747, 0.2177771926, 0.6614961028, 0.3497148156, 0.2820779681, -2.2396645546, + 2.371997118, -0.4914728701, 0.3381384015, -0.9512355924, -0.4113211334, -0.1319223195, -0.7636014223, -0.0705542788, + 0.0945843682, 0.5141342282, -0.2185685933, -0.5152382851, 0.0872560367, 1.344009161, 0.6572620273, 0.4007388651, + -0.531748414, 0.7063996792, 0.979529798, 0.9454191923, 0.4927286804, 0.2224742323, 0.0633541867, 0.1593330353, + -0.7465167642, 1.238628149, 0.2575991154, -0.4987689257, 0.204592064, 0.686719656, 1.4968909025, -0.3125460148, + -0.9242553115, -1.4892401695, 2.410143137, -0.0921221748, -0.9982684851, -0.1168525666, 2.1869966984, -1.4745687246, + 0.5221762657, 0.1889460534, -0.8488870859, -0.9581833482, 0.9912944436, -0.4461146593, -1.0186274052, 0.8116633892, + -0.7028707862, -0.2395506054, -1.3628484011, 0.6342271566, 0.48123613, -0.8224328756, 0.1313161552, 1.5504002571, + -0.9111961126, 0.2188706696, 1.0305371284, -0.0790315494, -0.9508096576, 1.2417500019, 0.4015571475, 0.2897460163, + 0.1677240729, -1.4348064661, -0.5332908034, 1.5793312788, -0.1691692472, 0.1776634902, -0.2642582059, -0.5794829726, + 0.8309162855, -1.6052863598, -0.9368858337, 0.955896914, -0.0408717506, 0.3745765686, 0.6062545776, 0.6897696257, + 0.66178298, 0.62597996, -2.4486322403, 0.3745160699, 1.1456580162, 1.0062994957, 0.3313815892, 1.0699118376, + -0.6684012413, 0.5727875233, 0.6733343601, -0.0626238659, -0.4325711727, -1.789806962, -0.7044024467, 0.2529786825, + -0.1920649707, 0.3323691189, -1.1825512648, 0.5753129721, -1.4658842087, -2.1032445431, 1.1631325483, -0.5351141095, + 1.3923389912, 0.8280168176, -0.7771325707, -1.1401008368, -1.7066495419, -0.6760823131, 0.4116258919, -0.6975342631, + 0.6350879073, 1.9184994698, -1.080302, 0.3992839456, 1.0008097887, 0.1050618738, 0.6947386265, 0.9541548491, + -0.4823937416, 0.0798426941, 2.0793166161, -1.0948320627, -0.7919138074, -0.3036155403, 0.2675095499, -0.3363015354, + 1.2337770462, -0.0565242618, 1.1298168898, 0.2538796067, -1.4344059229, 0.75432688, -0.4848037958, 0.1588084549, + -1.9065899849, 0.7605556846, -0.9614201188, -1.6162747145, -1.3088313341, 0.7706814408, -1.2203983068, 1.0250405073, + 0.1936548799, 0.6911200881, -0.9923204184, -0.7455840111, 0.4099641144, 0.4822587371, 1.1336737871, -0.3551127613, + 0.346765846, -0.264662832, 2.0391478539, 0.3230980039, 0.8732517958, 0.3943471909, -0.7295206785, 0.6893681884, + 0.6827322841, 2.2047653198, 0.2522270083, 1.046261549, 0.3333738148, 0.9523355961, -0.5945228338, 0.4556433558, + 0.6373681426, 0.7313504815, 1.3079185486, 2.0483045578, 0.9635858536, -0.7311703563, 0.8531662822, 0.1186441779, + 0.2476326227, 0.7424806952, -0.1205264479, 2.3297095299, 0.2212003767, 0.0787303224, 0.428293854, -0.7846913934, + 0.7370166183, 0.1164571047, 0.4009823501, -1.5018119812, -0.7576122284, 0.2048009932, 0.4468692541, -0.7943142056, + 0.9658300877, -0.0924994797, -0.5092731118, 0.1271789968, -0.5681103468, 1.2777352333, 1.3446389437, -0.4176205099, + 1.1254996061, -0.1987000555, 0.3697093427, 0.6449429393, 2.1140766144, 0.028761046, -0.2087999135, -2.222432375, + -0.107684195, -0.5155770779, 0.3130055368, -1.2204751968, -1.6488747597, -0.7013992667, 0.9725614786, 1.8311501741, + -0.042031303, -0.4865702391, -1.2558275461, 0.0240110978, 0.0409290753, 0.5420319438, -1.2074099779, -1.4793547392, + 0.0677488744, 2.0287189484, 0.1211663187, -1.0394985676, -0.2092629373, -0.5419185162, -0.2526287735, 0.630704999, + 0.7881709933, -1.3417301178, 0.51476717, -0.1236193851, 0.3639915884, 0.0800566152, -1.401248455, -1.3367093801, + -0.9948487282, -0.2640236318, 0.0116868606, -0.1084337905, -0.8910443783, -0.2605855167, 0.7310494781, 0.2275884598, + -0.4247497022, -0.3506610692, 0.5176494718, 0.8392418623, -0.1413768381, 0.4017984271, -0.8027892709, 0.0070667868, + -0.1382342279, 1.1400476694, -1.2793195248, 0.9133566022, -0.4161378741, -1.3781870604, 0.1653951555, 0.4276550412, + 0.1956777126, 2.8762161732, -1.1102243662, 0.1171223372, -1.68227458, -0.903254509, 1.269302845, -2.2613315582, + -0.8250658512, -0.2805194855, -1.4849926233, -1.2322430611, 2.0261244774, 0.0272019934, -1.8280910254, -1.6233180761, + -0.1065211222, -0.286221236, -0.4451537132, -0.2557170689, 0.4339169562, -0.9887716174, 1.2868506908, 1.1453354359, + 0.8280850053, 0.1992067993, 0.2173833102, -1.7708069086, -0.2707109451, 0.7886084914, 0.0197867677, 1.5219205618, + 0.4495322108, -1.8151134253, 0.150361836, -0.8707200885, 0.1044267043, -0.172767669, -0.3222731054, 2.0104050636, + -0.2804686129, -0.0797644407, 2.4352912903, -0.3499047756, -1.872302413, -1.0576988459, 1.5366865396, 0.2987216115, + -0.5741385818, 0.7206164002, -0.514046073, 1.1396903992, 0.4905533195, -0.7538064122, -0.0299488585, 0.6763259768, + 1.1116752625, 0.0127552878, 1.071075201, -0.6004653573, 0.2281350344, -0.9140645266, -0.3691907525, -0.337510705, + -0.8282238841, 0.7861650586, 0.3188356161, -1.5241420269, -0.7093237042, 0.6100569367, -0.1316596866, 0.3417309523, + -0.443887651, -0.8978509307, -1.0393338203, -0.8868865967, 1.954117775, 1.068980217, 0.0547712296, 0.5502784848, + 0.0277117081, 0.6421114206, -0.6505494118, 0.6176762581, -0.9987822175, -0.1520087272, 0.1977556646, 1.4567295313, + 0.94766891, 0.3120063245, 0.1578296274, 1.349044919, 0.907694757, -1.580264926, 0.0284059606, 0.3208372891, + 0.6578550339, 1.257297039, -1.092656374, 1.252104044, -0.6177709699, -1.0928300619, 1.1918451786, -1.0383467674, + 0.2914623618, 0.5544426441, -1.9991108179, -0.6491318941, -0.1269466877, -1.3599926233, 0.2060403973, 1.1349284649, + 0.5194821358, 0.8900290132, -0.7164104581, 0.5118864179, 0.218848899, -0.6501572728, -1.0021990538, 0.9629164338, + -0.6489469409, 0.1203286722, -0.3681460321, 0.0381681658, -1.0675135851, 0.2147252262, -1.4677051306, 0.9678803086, + 0.5567008257, -0.4400278926, 0.586022377, 0.77646631, 0.7028333545, -0.2341640592, -0.5149731636, 0.7935917974, + -0.5220533013, 0.6459440589, -0.2909165323, 0.6664276123, 0.5232625008, 0.984077096, 0.688719213, -1.1589708328, + -0.1337791681, 2.1475710869, -1.1999230385, -0.0397767313, 0.2972322702, -1.1360603571, -1.0197287798, 0.0860073194, + -1.0629270077, 0.7163521051, 1.6431040764, 0.8835981488, -0.8887983561, -0.4056135714, 0.5577527881, -0.535967052, + -0.6085321307, -1.0848847628, 2.3708302975, -0.3000078201, 0.912925601, -0.8528723717, 0.7104384899, -1.4673618078, + -0.0468426906, 1.5498622656, -0.6497247219, 0.1055054367, -0.6367157102, -0.7790260911, 0.1303004473, -0.8807298541, + 1.2931112051, -0.0242201276, -1.3028495312, 1.0931696892, 0.8489127755, 0.562055707, 0.3824717402, -0.8211005926, + -0.2894999683, -0.3295023143, 1.9161242247, -0.3875193894, -1.5950083733, -1.2387349606, 0.9860461354, 1.1215429306, + -1.4169552326, 0.7774617076, 1.378156662, 0.4257713854, 0.1041262969, 0.6187925935, -0.1452303976, -0.1544398069, + -0.3350002766, -0.790343821, 2.2526700497, 0.5864151716, -0.0685864314, -0.6246374249, -1.3993204832, -0.4303893149, + -1.2822613716, 0.1559318602, 1.5798255205, -1.07654953, 0.4107350409, 1.3614157438, -0.7937434912, -0.1587989628, + -0.0826069266, 0.1638277918, 0.3035634458, -1.0530942678, 0.3941660225, -0.3778450787, 0.5913537741, 1.7228548527, + -0.230835706, -1.0750149488, 1.7766871452, -0.2589304149, -0.6578678489, -1.3033595085, 1.015647769, -2.2127144337, + -0.7063292265, -1.1299027205, -0.87517941, 0.0943318456, -0.8357192278, -0.6747906208, -0.1819349229, 1.2726923227, + 1.1324168444, -0.0653668642, 1.781221509, 1.4365423918, 1.291192174, 0.6556486487, -1.8097792864, -0.4941692948, + 1.0009518862, 0.9566744566, 0.1753100008, 0.7363275886, 1.0797368288, 1.5626415014, 1.5590084791, 1.177069664, + 1.8266727924, -0.8828266859, -0.5780462623, 1.16140306, 0.0819185227, 1.1126433611, 0.2359033823, 1.5360554457, + -0.7368761301, 1.1381391287, -1.1523531675, 0.4186245203, 0.4560465217, -1.5258060694, -1.1486253738, 0.0944953263, + 1.1487392187, 0.443218708, 0.4212090075, 0.1783284396, -1.0721273422, -0.6282792091, 0.1184149534, 0.1077746376, + 1.6965463161, -0.0277585164, -0.191867277, 0.5346242189, 1.8567492962, 0.9038385153, -1.7754197121, 0.0008006179, + 1.320322752, -0.9212475419, -0.1841087192, -0.1914251149, -0.2672573626, -0.7262297869, 0.5493069887, -0.0501594692, + 0.406830132, -0.4298945665, -2.2442214489, -0.749753952, 2.2230682373, 0.104825519, -0.757666707, -0.296254158, + -1.4607772827, 0.6312759519, 0.2765136063, -1.7077609301, -0.3536328375, 2.0978047848, -1.0209709406, -1.9278744459, + -1.083540082, -0.6693260074, -1.7807040215, -0.0103057222, -1.2683321238, -1.4392585754, 0.5706706643, 0.2299688011, + -0.8338006735, 0.0692932904, -0.0159100499, -1.2371246815, 1.5750194788, -0.4039532244, 0.0204617586, -0.3619193733, + 0.6404605508, 0.3293938637, 1.23306036, 1.0708794594, -0.2778260112, -1.0820939541, -1.1345940828, -0.9574249983, + 0.1622495651, 1.4215382338, 0.458213985, 0.486674577, -1.1338460445, 2.6203932762, 0.3832954764, 1.014039278, + -0.975964427, -0.1634153575, -0.795409441, -0.3030864894, -0.3183051348, 0.4918797612, 0.8558522463, 0.3166932762, + 0.5860859156, -0.6056419611, 0.1423945576, 1.3445808887, 3.1942925453, 0.3613812327, 0.7262311578, -0.0039374535, + -2.8172578812, 1.2778655291, -0.5762477517, 0.8407689333, -0.7480339408, -0.7672458291, -0.1195229515, 0.2324158102, + -1.8714499474, 0.5519493222, -0.5039342046, -1.7590987682, 1.6869199276, -1.9298254251, -1.3470934629, -0.6425828338, + 2.0217587948, 0.6767479181, 0.3098316789, -1.402258873, 0.678384006, 0.8065295219, -1.1054807901, 0.5464166999, + -0.3851571679, 0.3955411017, 0.3208754361, 1.5504038334, -0.214410305, -1.5548576117, -0.2614115775, -1.442518115, + -0.2540749609, 0.3945147991, -0.7667369843, 1.4624339342, -0.0706093833, 0.2780528069, 0.8718714118, -1.7170612812, + 2.0644669533, 1.398195982, -0.0241681747, 0.0153257139, 0.1551327109, 0.8673528433, 0.4098148942, -0.4804344475, + 0.4392388463, -0.601723969, 0.0909047872, -0.6866038442, -0.8969714642, 0.9651571512, -0.6932944655, 0.6336821318, + 0.8397692442, 2.6203660965, -0.6895518303, -1.7960164547, -1.6501295567, 1.8551411629, 0.112815775, -1.751347065, + 0.8404824138, 1.3223236799, -0.5824505091, -0.0671811923, -1.2150722742, 0.9815346003, -0.3406918347, -2.1729745865, + 1.5029435158, 1.4895166159, -1.0849428177, 0.0340151675, 0.3322142959, -0.5848049521, 0.1907823086, -0.812936008, + -0.0226928703, -0.0279446561, -0.201694265, -1.1095571518, 0.8078178167, -1.1353489161, 0.2967233658, 0.5234735012, + -0.7270941138, 1.1792708635, 0.6389978528, 0.3985453844, -1.2015575171, 0.7863968611, 1.1112177372, -0.5595420599, + -0.5727396607, -0.8466938138, -1.9493989944, -1.086910367, -1.0681582689, 0.3008961976, -0.5245221853, -1.5388499498, + 0.6930798888, 0.5540941954, 0.9507279992, 0.8663878441, -0.4860620499, -0.1471722573, -0.1502821445, -0.4803615212, + 0.6171793938, 0.5383598208, 1.28604877, -0.1998111606, 2.9812784195, 2.1534991264, 0.6020771861, -0.2183421254, + 0.5264843106, 0.285196811, 0.4971400797, -0.9605002403, 0.9666528702, -0.0700143129, -1.3566243649, 0.3706783354, + 0.459598273, -2.5560221672, 0.351131767, -0.6403661966, -1.288497448, -0.6789479256, -0.6717274189, -1.2106477022, + -0.0163370986, 0.3457172811, 1.6352626085, -0.4889360368, 0.5581252575, 0.334942013, -0.1122701392, -0.9621224999, + 0.8743726611, 0.5053303838, -1.8802504539, 1.1275217533, -1.1256831884, 1.3232104778, 0.3116884828, 0.9008846283, + 1.4898868799, 0.0042057778, 0.1580962092, -0.9577461481, 0.0220026318, -0.4892366827, 0.1239973605, 1.1565297842, + -0.4127237499, -0.1431506574, 0.007537405, -0.2322238684, -0.3758442998, 0.4405148923, -0.2959225178, -1.9549883604, + 0.0191233903, -1.1686453819, 0.3244661689, -0.7563298345, -0.9059374928, 0.2940572798, 1.72633183, -1.4125913382, + 0.8717287779, 0.8929125071, 1.0991194248, 0.7424063683, -1.1658024788, 0.1678114682, -1.3147382736, 1.051358223, + 0.8278679848, 0.9144086838, -0.2248248011, -0.6977533102, 0.7616482973, 0.1096616462, 1.9541888237, 0.2071506679, + -0.0072634853, 1.6672128439, -0.2180464268, 0.2142009735, 0.6916992664, 0.8198504448, 0.2656022012, 0.4191500843, + -0.1563543826, -0.0766619965, -2.068454504, -0.5974961519, -0.317838937, 0.9397915006, -0.2236629725, -0.653934598, + -0.1499699354, 1.3334772587, -0.2018540204, -0.8706596494, 1.8530994654, -1.2432664633, 0.0694535226, -0.6399093866, + 0.5563447475, 1.1774454117, 0.3720839918, 0.0705601349, -1.5265114307, -1.3808004856, -0.7226364613, -0.0671254769, + -0.7904212475, 0.1652627289, 1.6826713085, 0.9410175085, -0.1707097888, -1.1935794353, 0.5031608939, 0.7144062519, + 0.3102995157, 0.0893526301, 0.411952883, -0.6044661403, 0.7267200351, -0.5432944894, -0.4802464545, -1.2587251663, + -1.6022361517, -1.0864841938, -1.4701102972, -1.3144232035, 0.993283391, -0.46096766, 0.4559967816, 0.9519225955, + 1.9400188923, -0.9149392843, -0.5548046827, -0.0177294016, -0.7559466958, 0.4510883987, -0.025515968, -1.1708710194, + -0.7565687299, 1.3700623512, -0.8828909993, 1.1024614573, -0.4919537604, -0.8594636917, -0.181248799, -0.5608417988, + 0.7042586207, 1.0489093065, -0.0738557726, -0.3878282309, 0.0897080898, 0.6622738838, 0.3745981753, -0.2529806495, + -0.2844143212, -0.0747609586, 0.3734287322, -0.3683740795, -0.9679385424, -1.5396726131, 0.1518522203, 1.1448954344, + -1.1830432415, 2.3214013577, -0.2190132141, -1.0381678343, 0.4893311262, 1.2217268944, 0.4482461214, -0.7320929766, + -0.0737974867, -0.4775159955, -0.29623878, 0.9918540716, -0.2520774901, 0.7377212644, -1.1158239841, -0.3469292819, + 0.7313711047, 0.6559993625, -0.942900598, -0.9391338825, 0.8579667807, 0.0583344996, -0.0099074114, 1.0966665745, + 0.1336360723, -0.1326661706, -0.9921869636, 0.5340189338, -1.0867534876, -0.4550673962, 1.355969429, -0.1116294712, + 1.0091249943, 0.1412471086, 0.5255767107, -0.3881579638, 1.3969186544, -0.1676418036, -0.1452837437, 0.9945383072, + -0.2506922185, 1.1986724138, -1.7370616198, -1.346794486, 0.8549793363, 0.2784049809, -0.6807608008, -0.69138515, + -2.2432849407, -2.3831932545, 0.7839045525, 0.0188699197, 1.0645942688, 0.1286784858, 0.438238591, -0.6687325239, + 0.5978592634, 1.1087765694, -0.1641141921, -0.3620709479, -1.7388533354, 1.3200438023, -0.2533108592, -0.4184384346, + -1.5299417973, 0.5822222233, -0.5063092709, -0.1981868595, -1.302193284, 1.2743741274, 0.0432033651, 0.456982255, + -0.5047770739, 0.1699194163, -1.3279764652, 0.3524358571, 0.1321837306, 0.5692359209, 0.6053616405, 0.2480343133, + 1.6470834017, 0.3169894814, -0.5630028248, -2.4546029568, -0.3362979591, -1.3944190741, 0.7804767489, -1.0859674215, + 0.4189290106, 0.8998404145, -0.6749925017, -0.769815743, -2.2536473274, -2.305850029, 1.2095606327, 0.1959027052, + 0.3622468412, 0.025693858, -0.9933300614, 0.4945476353, 0.916187942, 1.4648804665, -1.8006176949, 0.7049255967, + 0.8880855441, 0.4263364673, 0.2365619391, -0.3710543811, -0.7134770155, -1.323486805, -0.0384293981, -0.1907331049, + 0.2600144148, -0.8479497433, 0.5255256295, -0.5529755354, 0.13251701, 0.2094378769, 0.3922344744, -0.2805377841, + 1.1552339792, 0.0220841095, 0.70562011, -0.861707747, 0.5466896892, 0.8280608654, 1.7718749046, 0.5791893601, + 0.3954809308, 0.6250145435, 1.8468208313, -0.5212256312, -0.7269707918, -0.0188041087, 0.2731238902, -1.7006938457, + 1.2754198313, 0.4935974479, -1.1783540249, 0.6881445646, -1.0047477484, 0.8587782979, -0.4211801887, -1.1423093081, + 1.8459129333, 0.4986789227, 0.3107667565, 2.195235014, -0.2329679281, 2.2344813347, -2.3799045086, -0.6172450185, + 0.9939242005, 1.6428675652, -3.8169021606, 0.8213685155, -0.2383841127, 0.8085193038, 0.8943603039, -0.7287612557, + -0.8341719508, -1.6358424425, -0.0163045768, -0.3030619025, 0.0600189455, 1.0085133314, -0.7476360202, -0.5483891964, + -0.9263272285, 2.6085176468, -1.278023839, -0.9766176939, -0.5389821529, 1.3002591133, 0.9012833238, 1.6520648003, + 1.8740491867, 2.7003669739, 1.3751206398, 0.7383854389, 0.4513852, -0.078545846, 0.9784024954, -0.942009747, + 1.0711314678, 0.1228365153, -0.4089529514, -0.0938136727, -0.4688596725, -0.039530471, -1.4214097261, 1.961099267, + -0.813685596, 1.5312091112, 0.7010276914, -1.3808984756, -0.2077739984, -1.0954723358, -1.5649642944, 1.6708961725, + 0.0262108147, 0.4416314065, -1.0797450542, -0.4252988994, -1.1980069876, -1.4782294035, -0.9501484632, 0.0933405459, + 0.8175611496, 0.4934800565, -0.0887110531, -0.2513252497, 0.2430290729, 0.0722308606, 1.1764454842, -0.5189903378, + -0.4726536572, 2.1911048889, -0.4614456296, -0.155219093, 0.6430007815, 2.3364167213, 0.8803315759, 1.2821724415, + -0.1783988476, 0.6398929954, -0.6916404963, 0.068555668, 0.4741430879, 1.7757326365, 1.3293614388, -1.6313576698, + -1.1642336845, 0.3845895231, 1.0874531269, 0.8030692339, 0.9298844934, 1.1026318073, -0.4465782642, -0.906667769, + 1.6973699331, 0.3255869448, 0.4437576234, 0.6298837066, -0.1388432831, 0.4877704084, -0.5768527985, -0.6939834356, + -0.6422843933, 3.4686851501, -0.8099491, 1.0799697638, -1.1004024744, 0.4231131375, 0.113089487, -1.2025954723, + -0.412081778, -0.9697688222, -0.8534077406, -0.5020948052, 1.3400472403, 1.7938925028, 0.6689025164, 0.9888962507, + 0.2849170566, -0.0868029594, -0.2804565132, 0.2670521736, 1.1490031481, 0.2609162629, 1.0914986134, -0.1469503343, + -0.1726162434, -1.0124996901, 1.6172940731, -1.4287543297, 0.020736631, 0.4133826494, -2.1272759438, -1.0434956551, + 0.3534581065, 1.8912388086, -2.0706202984, 0.7521951199, 0.1733450145, 0.3660833538, 0.4582214057, -0.0752727687, + 1.0993863344, 0.7004218102, -0.2836722732, -0.3275241554, -0.9340184927, 1.6282463074, 0.6356199384, 0.0225061178, + -0.3679436743, -0.381706059, 0.697401762, 0.0895482525, 0.4078374803, -1.0503004789, -1.8791811466, -1.1724802256, + 1.0532171726, -0.005843624, 0.2517630458, -0.7201429009, 1.2702769041, -0.0458424352, 0.4193159938, 1.5528337955, + -1.1905040741, -1.3259557486, -0.5397362113, 0.7404883504, -0.9480809569, 0.7349120975, 0.2989366651, 1.1667926311, + -0.0275125522, -1.95307374, -1.0072118044, 0.5982735753, -0.781989634, 0.2409633547, 1.0072343349, 0.5993404388, + 0.145257473, 0.4981725514, 0.434838742, 1.0504794121, 0.9790147543, 0.6895599365, 0.1251991391, -0.8385702968, + 0.8198758364, 0.372495383, 0.5099990368, -0.4112640321, 0.1107642874, 0.3995991051, -0.3792087734, -0.1735995412, + 0.0200130008, -1.1897200346, -0.0422304757, -1.0703550577, -0.0569381416, -0.0801360905, -0.8206369281, 0.7945466042, + 1.302664876, 1.1943631172, 0.4166095257, -2.3133356571, -2.0431711674, -0.0859138668, -0.7850488424, 0.4934567809, + -0.0740535557, 0.5806821585, 1.1419591904, -0.5928174853, 0.3389694393, 0.933506012, 1.5325789452, 0.2682217956, + 0.6445912719, -1.1811283827, -1.3357715607, -0.2605241239, -0.1114650816, -1.0182495117, -0.1397437006, 0.4789614975, + -1.3894425631, -0.8259648085, -0.968984127, 0.7458997965, 0.2991378307, 0.8106826544, -0.3790820837, 0.7313722372, + 0.6382530332, 2.001326561, 0.2483182549, -2.0251369476, 0.1511827558, -1.8691866398, 0.3484821618, -1.3629926443, + 0.0344463214, 0.2344449162, 0.4313440025, 0.2729780376, -1.5452675819, -0.0550522581, -0.6612935066, 0.5417645574, + 2.0425043106, 0.2200262994, -0.1124477014, -0.3067903817, 2.6385672092, 0.0758075565, 0.9185811877, -1.1661971807, + 0.0555665419, -2.0132887363, -0.0612099841, -0.049862802, 1.1586894989, -0.4992930293, -1.0344942808, -2.0566396713, + -1.7438385487, 0.4182908833, 1.9617835283, 0.3961114585, 1.9309381247, -0.4613923132, 0.1689138561, -0.1322667748, + -1.2334487438, 0.9377317429, 0.7998334765, -0.6520880461, -0.1707964838, -0.5642157793, 1.2804228067, 0.0208851863, + -0.5527569056, -0.443479538, 0.0876937509, 1.7762702703, 0.8643834591, 0.7251709104, -0.2246964127, -1.1765624285, + -0.8831675053, -1.3195488453, -1.7548000813, -0.6290677786, 0.4152307808, 0.566660285, -0.2163264304, -1.6369053125, + 1.394143343, -1.7514255047, -1.9723445177, -0.7031470537, -0.9993395805, -0.8704144359, -1.2276570797, 2.4672963619, + 1.1786454916, 0.2572571933, 0.2190767229, 0.6950595975, 0.71499753, -0.0045571011, 0.5289281011, -0.6817349195, + 0.7423099875, 0.0222218968, -0.3022816181, -2.5626525879, -0.866037488, 0.5463693738, 0.1478862166, 0.4148804545, + -0.2576435804, -1.3388051987, -0.9884957075, -0.1858710945, 1.3034764528, 1.2491785288, -0.2166267633, 0.3619436622, + -0.5870447755, 0.4298285246, 0.4556368589, 1.477517128, -1.2154983282, 0.4434569776, 1.2889420986, -0.1644225568, + 1.5875742435, -1.2383381128, 0.1369165182, 0.8227247, -0.2720991671, 1.377248764, -1.0866830349, 0.5779238343, + -1.3674609661, 0.3796960711, -1.2340633869, 1.5236074924, 0.8480984569, 0.8815364242, -0.2750021517, 1.0931401253, + 0.3164792061, -0.6241439581, 1.0555865765, -0.3296152651, -0.9498324394, -0.6139930487, 0.007804458, 1.9462395906, + 0.1260036528, -0.0267669503, 1.500014782, -2.205889225, 0.2527365386, 1.4516202211, 0.032885924, 1.4210357666, + -1.8086668253, -1.2372293472, 1.3431107998, -0.3939828873, 0.3295665383, 0.0458708517, -0.8294584155, 2.3301115036, + -0.1783146113, -0.3502511084, -0.8924494982, 1.0734086037, -1.8520869017, -0.9093677998, -1.1956225634, -0.4636309147, + -0.2347074598, -1.09410429, 0.7002073526, -0.0075926357, -1.6863496304, 1.674351573, -1.3652117252, -2.9964680672, + -0.0707102716, 0.1781398654, 0.4942721725, -1.4362123013, -0.7788179517, 1.6206996441, 0.2547658384, -1.1822535992, + 0.9864816666, 0.3597769141, -1.1920862198, -0.5226871967, -0.6126774549, -0.7237797976, -0.1754818857, 0.2489106804, + 0.8328000903, -1.1851280928, -0.5307146311, -0.6191227436, 0.7989680171, 0.1682512611, -1.104274869, 1.3994650841, + 1.0414515734, 0.0627358332, 0.6830793619, -0.0892262608, 1.5641775131, -0.1822139621, 1.6051907539, 0.8997560143, + -0.0619025528, -1.2406721115, 1.5553014278, 0.6757091284, 0.23511599, -3.2029783726, -0.2392832935, 0.0999327451, + -1.0192216635, -0.5507404804, -0.4247370958, -0.1092737615, -0.4355481267, 2.0317144394, -0.2517910004, 1.1875435114, + 1.0763266087, -0.63415277, 1.2765887976, -0.608709991, 1.2905139923, 0.244071275, -0.2550278902, 0.6374529004, + 1.1602060795, -0.5558677912, -0.7458577752, -0.1815477461, 0.1130491644, -0.1535087526, 0.8310692906, 0.2297729254, + 1.5552196503, 0.3676000535, 0.1164899766, -0.2793305516, 0.0842381567, 1.1744824648, -0.5380910039, 1.1350588799, + 1.6307651997, 0.5054000616, 0.3415246606, 0.1714084893, 1.2019101381, 0.0502630584, 0.5542773604, 0.9386487603, + -1.0577836037, -0.283821702, -0.6229845881, 0.075635381, -2.2039809227, 1.0031237602, 0.846624136, -0.4926395118, + -0.3171692491, -2.5975430012, -0.9221938848, -0.4696512222, -0.1379987448, 1.6596388817, -0.7340003252, -1.3171730042, + 0.3707151115, -1.3485159874, -1.1177152395, 0.8394469023, 1.7678155899, -0.5140664577, 0.3884877563, 1.1650243998, + -0.7375556231, 0.0720298588, -1.3064266443, 0.8903331757, -0.4982529581, -0.2980082631, -1.1973793507, 0.4307799637, + 1.4663467407, -0.4940899312, -0.1184043512, 0.6036401391, -0.606133163, 0.1731641889, -0.4107045531, -0.2922571301, + -1.001303792, 0.1425794065, -0.476999104, -0.8599395156, -1.5917048454, -1.4707101583, -0.5162295699, 0.0312709026, + 0.9078719616, 1.056656003, -0.0541705601, 0.453425169, -0.3871499896, -0.1667667329, -1.3632845879, 0.8195942044, + -0.7354663014, -0.6091674566, 0.8308277726, 1.1752266884, 0.7835314274, 1.3266550303, -0.0654770806, -0.3728080094, + -0.8336992264, 1.1622248888, -0.3846301138, 1.0055280924, -1.2250599861, 1.1725132465, -0.1270800084, 1.9019786119, + 1.5142729282, -0.1225099191, -0.1151846126, -0.1686504632, -0.0648666248, 0.1656596959, -1.8448135853, -0.401976645, + -1.2433512211, -1.1153597832, 0.9793652296, 1.3056718111, -1.3503453732, 0.5518975854, -0.2453743219, 0.0945341364, + 0.9384822249, -0.4939763248, 0.1662771553, -0.0385320112, 0.4536897242, 1.6621969938, -0.8693246245, 0.5161611438, + 0.333915621, 1.29325068, 0.8945618272, -1.8559041023, -1.0705528259, -0.6615146399, 0.0996204913, 0.4900225997, + -0.2379509211, -0.0018551836, -0.0410420187, -0.6998842955, -0.6224127412, 0.7980476022, 1.6843181849, -1.3955712318, + -0.0199635271, 0.6951984763, 0.5448355675, -1.4337213039, -0.6472737789, 0.5337479115, -3.0123813152, 0.1207514852, + 0.3387083411, 1.02194345, 0.3195720017, 0.4922348559, 0.431878686, -1.5374253988, 0.2995702624, 0.6266925335, + -0.1475751251, -0.9628657699, 1.3692935705, 1.7332062721, 1.0504539013, 1.6112185717, 0.3021770716, -1.5211652517, + -0.0542259924, 0.7082381248, 0.2385789454, -0.5415235758, 0.2251457572, -0.7766765952, -1.1232200861, 1.4787577391, + 0.0738270581, 0.9700493217, 1.4055027962, 0.2390944362, 2.526515007, 1.1471470594, -1.9478795528, 0.3010020554, + -1.1164835691, 0.5054375529, -1.1840339899, 0.8414674997, -0.2105533332, 1.0772610903, 0.1378324628, -0.2625436783, + -1.2023355961, -1.2959524393, -1.9612358809, 0.421897471, -1.6659665108, -0.5268239975, 0.9753533006, 1.0594240427, + -0.2273750156, -0.7501193285, 1.5347290039, 0.6678853631, -0.0581064932, -0.1379352659, -0.2763449848, -0.2625544667, + 0.9622181654, -0.5553058982, 1.4604641199, -1.260296464, 0.0350733362, 1.3494240046, 0.0647262409, -0.2970011532, + -0.1286823303, -0.4147179127, 0.3933965564, 1.0783635378, -1.1027158499, 0.9179580808, -1.1704337597, -0.1262967438, + -0.6603304148, 0.2892201245, 0.3097912669, -0.406491816, 0.6283999085, -1.0411736965, -0.0379688144, 0.0183309894, + 0.4731063843, 0.9111999869, -1.3404321671, -1.8525221348, 0.4234216213, -0.0911732167, -0.1249522865, 0.3678356707, + 0.5566195846, -0.0299841147, -0.017534012, 1.2085926533, 0.6181845069, 0.7668458223, 0.2914898992, -0.3310023546, + 0.55734092, 1.2957259417, -1.1349855661, -1.5247069597, -0.1056646109, 0.8937266469, -2.436621666, 0.4809564352, + -1.0557091236, -2.0977416039, 2.2568325996, 0.8655489683, 1.5234045982, 0.7148271203, 0.9997466803, -0.3668726683, + 1.5002795458, 0.5295903683, -0.0688808635, -0.3074559867, -0.5956582427, -0.7585545778, -1.748190403, -0.7318330407, + -1.0182477236, 0.2035604119, 1.8202784061, -1.6629431248, 1.1729696989, -0.8748952746, 0.4623175859, 1.7992956638, + -0.2273533642, 0.8438876867, -0.5174407363, -0.3450641334, -0.2517184317, -0.4905411601, 0.6074772477, 0.8887094259, + -1.1760468483, 0.2600905597, -1.2200479507, 0.8933705688, 2.1258146763, -0.5572912097, -1.8600933552, 0.7779752016, + 2.5773346424, 0.17331402, 0.1253862232, 0.5314847827, 0.2223214656, -2.9037373066, -0.9753293991, -0.835187912, + 0.0942138582, -0.6895788908, 0.7909314632, -0.9552357197, 1.1238473654, 0.5297656655, 0.7592256665, 0.2255097628, + -0.8313544989, 0.9092111588, -0.3085229695, 1.8506548405, -0.2688187361, -0.0903450549, 1.1477758884, -0.815776825, + 0.576559484, -0.6213289499, -1.0924533606, 0.3988735378, -2.0458335876, -0.593906343, 0.9805639982, -1.0290400982, + 0.0781027302, 0.2894194126, -0.0519753769, 0.8758471012, -0.3554590642, -1.8353921175, 0.0100867106, -0.4113383293, + -0.2478044927, 1.4757231474, -0.1460000873, -0.1348475516, -1.9121975899, 1.1605008841, 0.4398345947, -0.8364595175, + -1.1910685301, -1.2645142078, 0.6124418378, 1.1392834187, -1.2183645964, 0.0038925342, -1.0627678633, -0.7069594264, + 0.4486484826, 1.2478134632, -1.8462580442, -0.6957844496, -1.531901598, 0.6585696936, 0.7199642658, -0.2957348526, + 0.6642016768, 1.3873531818, 0.9918613434, 0.2797018588, -0.4639515877, -1.5886434317, -0.4204191566, 0.8649352789, + 0.9510036111, -0.9391480088, 2.029214859, -0.1282894462, -0.7238674164, -0.1788964719, 0.0195331033, 1.0771375895, + -0.4234253764, 1.4801914692, -1.766674161, -0.5446242094, 0.6746259928, 0.1982609779, -1.159553647, 0.980132103, + 1.8839025497, 0.2379632145, 0.5130231977, -0.6771757603, -0.3835451603, 0.6720554829, -0.5601616502, -0.2693561912, + -0.7150922418, 0.9604054689, -0.1766158491, -2.114166975, -0.1035743877, -0.1573709249, -0.6674705744, -1.618799448, + -0.3529086113, 0.0866112337, 2.2035353184, 1.0520107746, -0.4452825189, -0.3899340332, 0.1289973855, -1.2968221903, + 0.3952779174, -0.2544807494, -0.4893265963, -2.1965639591, 0.2055465132, 0.7529613376, -0.3973491192, 1.2315872908, + 1.6232351065, -0.0800956413, 0.0522243381, -0.6569432616, -0.7473552227, 0.1069898829, -0.9588980675, 0.2506351173, + -0.096584864, -0.0504180305, 0.56096524, 2.0323703289, 0.077099897, -2.0426630974, -1.7376391888, 0.7450774312, + 1.9501069784, 0.6154040098, 0.9178984165, 1.4370058775, -1.7092440128, 0.5272009969, 0.5203163028, -1.1656514406, + -0.5942999721, 0.1818185747, 1.511136651, -0.0468265265, -0.554354012, -0.1215622202, -0.8664098978, -0.2492751628, + 0.0694557428, 0.1134820506, 0.31376791, -1.2232038975, 0.822979033, -0.7367380857, -1.8020118475, 0.0884521306, + -0.8212783933, 0.2604509294, 2.0971336365, -1.0609384775, 0.7672310472, 0.5581717491, 0.028428765, -0.7300484776, + 1.6223838329, 1.8920705318, 0.7585506439, 1.2013385296, -0.6682579517, 0.5687101483, -0.0458690971, 0.7914537191, + 0.6461397409, 0.5958306789, 0.3313758969, 0.5736564398, 0.1297451556, 0.6420159936, -0.3512704968, -1.6068793535, + 1.0904586315, -0.1694664806, 0.8543040752, 0.4681234062, 0.6300991774, -0.5073465705, 0.098179847, 0.5250322223, + 0.2505944371, -0.7383431792, 1.5344400406, 0.8768033981, 0.9915237427, -0.1485308558, 2.7769432068, -0.7796960473, + -1.1073904037, 0.6106311679, -0.1776532382, -0.7403364182, -0.0547751002, 0.1981050968, 0.4532022774, 0.9392779469, + -0.8190399408, -0.711104095, -2.2401287556, 0.0680859536, -0.5838615298, 0.2028556317, -0.4420544803, -0.5240891576, + 0.1586313397, -1.1596050262, 2.0908944607, -0.6640832424, -0.0376775339, -1.3674635887, -0.0834356248, -1.1543424129, + -0.2867710888, -0.2558217049, -1.2492008209, 1.9734691381, 1.3248716593, 1.6726819277, 0.1237697229, -0.5251456499, + -0.0927522108, 0.9765563011, 0.440659523, -2.035854578, -0.032204289, 0.2834545076, -0.2984555364, 2.5113687515, + 0.6123604178, -1.760966897, 0.1541956365, -0.1179339066, -1.6794335842, -0.0388058573, -0.3712675571, -1.3224407434, + 0.8247251511, 0.1571902931, -0.4441169202, -0.0230798498, -0.0669803545, 0.8565628529, 0.4665855765, -0.7799400687, + -0.8101128936, -0.5259451866, -1.4127696753, -0.9107655883, -0.0380207002, -1.1302808523, 0.2475105673, -1.0421621799, + -0.2518622875, -0.6521123648, 0.9967294931, 0.321533978, 0.1610585898, 1.0579377413, 1.0964981318, 1.0885875225, + 1.5951294899, -1.4319165945, 0.5318467021, 0.3024968803, -2.2370159626, 0.3017950356, -0.3017114103, -0.6175892949, + 0.8086286783, -1.0254920721, -0.7773222923, 0.3564308882, 0.852289319, -1.514451623, -1.2158509493, -0.0528383479, + -0.294518441, -1.1897754669, 0.1364751011, -0.3321232796, -2.0284500122, -0.6192065477, -0.9456180334, -0.1601357013, + 0.4249179065, 0.1432779431, -1.2779705524, -0.1355749816, -0.5009277463, 0.6132161021, -0.2418944091, -0.2416060418, + -0.2200713307, 1.8523660898, -0.15878506, -1.9892187119, 0.9731972814, 1.1787183285, -2.09486413, -0.8218100667, + 0.9060323238, -1.3545004129, 0.5676369667, 0.128479898, -1.0084096193, 1.4587696791, -0.5944750905, -0.5187753439, + -0.6267364621, 0.045086842, 0.259441793, 0.8670076728, 0.4846119881, -1.418084383, 1.0617189407, -0.2597389221, + 0.9757429957, -0.934695363, -0.4718877971, -0.1700360179, -0.2180638164, 1.1518630981, -0.5961496234, 0.1541005969, + 1.2585749626, 0.1049211174, 0.1370392442, -1.1218445301, -1.2547951937, -1.3814834356, 0.9695735574, -0.1086363643, + -0.828831315, 0.5897889733, 0.1763927042, -1.6123449802, -0.3767241836, 1.0482236147, -0.6818988323, -0.8554486036, + -1.0561922789, -0.9120386839, -1.0435223579, 0.7464059591, 1.5055519342, 0.5351999402, 0.1048421785, -1.5796937943, + -0.1231038421, -0.113189213, 0.0296576433, -0.1823898405, -1.0289748907, -0.8570144176, 0.3856546283, 1.2521356344, + 0.4814043343, -0.636838913, -0.4543634653, 0.7679942846, 1.6410802603, 1.9045054913, 0.1016824543, -0.9051506519, + -1.0915925503, 0.5618121028, -0.0764838457, -0.1261715442, -0.2757646739, -1.6904895306, 0.1201585308, 0.468580395, + -0.7667537332, 0.5887155533, 1.0020669699, -0.4119359553, 0.5783369541, 2.025693655, 1.3819185495, 0.92281425, + -0.8997434378, -2.1333208084, 0.5421010852, 0.5343675017, -0.124631688, -1.4611852169, -0.3485037684, -0.1807983965, + -2.3376026154, -1.5892693996, 0.0738651678, 1.8555306196, -0.372859925, -0.7936410904, -0.7694765329, 0.153729111, + -1.2192952633, 1.0588021278, 1.7063795328, -1.4852479696, 0.7988227606, -1.5708323717, -0.0804250613, -2.382358551, + -0.7975266576, -0.6703687906, -0.1327716857, 2.0303711891, 0.4827000797, -1.0179685354, -0.1614174098, 0.3180173337, + 0.4515491724, 1.3316066265, 0.6386704445, -0.2509791851, -1.0985279083, -0.5632628798, 0.0922431201, -0.0308225118, + -0.38740623, 1.075286746, 2.0628256798, -0.0924772248, 0.5879930258, 0.2235952467, 1.9383288622, 0.2087660283, + 1.0126709938, -0.9500865936, 0.818503499, -0.6236126423, 0.2088777721, 0.1101473123, 0.3424575925, -0.1206818819, + -1.379389286, -0.4113827944, 0.961491704, -0.9937870502, 1.7580798864, 0.0080232378, 1.3879599571, -1.9699418545, + -0.0177614167, 0.3617301583, -0.0824940875, 0.4315568209, 0.5943727493, 0.390971005, -0.2284035534, -0.0388397276, + 0.7088179588, -0.8342286348, 1.0389921665, -0.4749735594, -1.2656178474, 1.6008704901, 0.0157479066, -0.881264925, + -0.2172022909, 0.5726627707, 1.1687834263, 0.7123550177, -0.2866460979, 0.9056574106, -0.1671238095, 0.7700747252, + -1.4749193192, -1.987516284, -1.917791605, -1.0036017895, 2.3900575638, 0.1375515759, -0.6110166311, 1.5173581839, + -0.5640364289, 1.391332984, -1.1090196371, -0.4102989435, -0.4230274558, -0.8586001992, -0.0699972957, 0.5191432238, + -1.7878763676, -2.2792520523, 0.411600858, -0.5971567035, 0.6625709534, -0.1563580632, 0.051933907, 1.3340390921, + 0.3207374215, 0.7841516137, -0.1863603294, 0.8826067448, 0.8950135708, 2.3930306435, -0.1827965528, -1.4979075193, + 0.6857637763, 0.462567836, 0.2142915875, -0.656981349, -0.3911370039, -0.0136631001, -0.4137517214, 1.3745381832, + 0.9061549902, -0.6315728426, 0.388484627, 0.7096084952, 0.2195208967, -0.9828910828, -0.6491459012, -2.369004488, + -0.1559623629, -1.0859808922, -1.3553333282, 0.2614978254, 0.340033561, 0.7255932689, 0.096754387, 0.3278695047, + -1.0589563847, -1.6091902256, 0.5406217575, 2.1439728737, 0.6192141771, 0.9494862556, -1.4554423094, -0.0448695049, + -1.4860472679, 0.5595998764, -0.9465503693, -2.0627651215, 0.4471147358, -0.6683236361, -1.2262574434, -0.2228455693, + -1.3789155483, -0.5255289674, 0.1673466712, 0.5638135076, -1.4176610708, 0.5824736357, -1.4399206638, -0.2605627477, + -0.5131645203, 1.5817571878, 0.9342992306, 2.0273759365, -0.9074780941, -1.4963614941, 0.2098528743, -1.3330277205, + -1.0364831686, -1.1096246243, 1.2138468027, -0.6777035594, -0.9634899497, -0.2676663101, 1.7159404755, -0.5196566582, + 0.5119627118, -0.3616420925, -0.3848065436, -0.2256528139, 0.3118752837, -0.3490059674, 0.1993868798, -0.9058728218, + 0.443369478, -0.3112775981, -0.0912733003, -0.6117324829, -0.5883981586, 1.7798914909, 0.0368696302, 0.593578577, + -1.6113942862, -1.8226302862, 0.7137543559, 0.3825588524, -0.0519888066, -0.5621618032, 1.2645081282, -1.4425507784, + -1.0361926556, 0.5223254561, -0.3062395751, -0.6406183243, -1.5627833605, 0.769529283, -0.3185529113, 0.164670676, + -0.3141778708, 0.6940912008, -1.3859407902, 0.2595100701, 0.9433202147, -0.9889213443, -0.7876140475, 1.5091377497, + -0.0022732059, -0.9895153642, -0.7657221556, -0.3768515289, -0.7495852113, 0.9069278836, 0.8732688427, -0.6578397751, + -1.8318632841, -0.5395345688, 0.3903403282, 1.3636548519, -0.5079500675, -0.4028911889, -0.9917718172, 0.4559382498, + -0.0439116731, 0.6223576069, -1.9363251925, 0.2596221566, -0.4668768048, -0.1926385313, -1.1734788418, -1.9986387491, + 1.9325946569, -1.306876421, 1.1438997984, 2.0557627678, 1.9167425632, -1.3739305735, 1.8942967653, -1.3069814444, + 2.5766277313, -1.2845826149, 2.6390814781, 0.0117756752, -0.8140695095, -0.0189126283, -1.77001369, 0.1316619217, + 0.6881023049, -0.0800242648, -0.3123969436, -0.1349624991, 1.1459685564, -0.3061838448, 0.8619158864, -1.3219367266, + 1.340826869, -0.2174276561, 0.7989725471, 0.181991905, 0.3068866432, 1.5338616371, 2.0315186977, 0.7892776132, + -0.7427718639, 0.5892996192, -0.0023908424, 0.2674568594, 0.0645150989, -0.4013667107, 0.8512451053, 0.6213958859, + 0.8364474177, 1.9893764257, -0.1589120328, 0.4406788349, -1.8999271393, -0.0583184175, 2.8087897301, -0.6425076127, + 0.5418109298, 0.3948427141, 1.2454727888, 0.4545042217, -2.7257065773, -0.8574002385, 2.5853521824, -0.3502472937, + -0.5604780912, -0.6599280238, -1.1559455395, 1.3983881474, -0.8947708011, -0.344587326, 0.0215723384, -0.506149292, + -0.1462244987, 2.1528968811, -0.8219048381, -0.6240154505, 0.9768301845, 0.6534996629, 1.4312934875, 0.545165062, + -0.1355044693, -0.4385142028, 1.1829334497, 0.8356802464, -0.5545064807, -1.4946864843, -0.965125978, 0.8002617955, + 1.6885603666, 0.4508632421, -0.5405079722, -0.7677236199, 2.1276350021, -1.5085190535, 1.0470719337, -0.3742038906, + 0.4816255867, 1.2239198685, 2.200262785, -1.1459487677, -1.9393211603, 0.8348519802, -0.8973862529, -0.0270348825, + -0.4584574997, 0.286852926, -0.0345946364, -0.9449191689, 1.6783432961, -2.5124733448, 0.2714243531, -0.7285017371, + -1.1114827394, 0.4374779165, 1.2229865789, 0.118882142, 0.6417844892, -0.033985883, 0.1788398623, -1.2683531046, + -0.883431077, 0.0883188769, -0.7413329482, 0.407936275, -1.5605533123, 0.671053946, -0.3997884691, -0.865693152, + 0.5296225548, -0.1787042618, -0.630608201, 0.1262859553, -0.0460716784, 0.9800592065, 0.6499250531, 0.2291618437, + 1.3460974693, -0.4842807353, -1.3417708874, -0.3950604796, -1.0232306719, 2.1392402649, -0.4437207878, 0.3694180548, + -0.883506, -0.7907400131, -0.6032630801, -0.4702125788, 0.0179922599, -0.4642401636, -1.3101488352, 0.8742898703, + -0.7117217183, 0.1661468446, -0.5677089095, -0.8415204287, 0.5891016126, 1.4322475195, -1.4599040747, 0.4364635944, + 0.7957346439, 0.4348514676, 0.2555656135, 0.7927491665, 0.1485411376, 0.5828484297, 0.8439933658, -0.5871391296, + 0.0046702735, 0.2771545649, -1.2712996006, 0.2197576612, 0.0016449381, 0.9348805547, -0.172184661, -0.2281569988, + 0.4430972934, -0.7958605289, 0.9351830482, 0.1677804291, -1.0998831987, -1.485691309, -0.7987915874, -0.0081814257, + 0.3317958713, 0.02093626, 0.9280778766, 1.3373113871, -1.8254497051, -0.4517202079, -0.4237102866, 0.4339829683, + -0.0882978663, -0.8270207047, -0.5583283305, 1.0447891951, 0.3826203048, 0.6272954345, -0.4586470723, 0.5723845959, + 0.7396498322, 1.7548961639, 1.2826986313, -0.7351671457, -0.8461158276, 0.0586707927, 0.4825576544, 1.0927946568, + -0.8203950524, -1.0296913385, -0.1650319546, 1.304597497, -0.0735537857, -0.5020622015, -0.2131796926, -1.9353233576, + -0.0282856803, -0.0519692637, 1.2257838249, -0.3289196491, 0.0804954693, 0.6277905703, -0.4614386857, 0.8901169896, + 0.6736842394, 0.2361200452, -1.710432291, 1.4444857836, 0.6761213541, 1.8072758913, 0.5737406015, 0.148045525, + -0.5947783589, -0.0989431441, 1.468495965, 1.1539797783, 0.2363432348, -0.19578664, -1.4308358431, -1.0022342205, + 0.6599704027, 1.3189892769, -0.0529710427, 0.7598709464, 1.4087154865, -0.1161145121, 1.4070295095, 0.5922804475, + -2.0745668411, 1.0892683268, 0.6900909543, 0.2436967641, 0.5517532825, 1.2490776777, 0.16451478, 0.5463775396, + -1.2008447647, -0.6278283596, 0.5528708696, 1.0359449387, 0.0826989859, -0.2087807506, -1.0988688469, 0.8048434258, + -0.8141828775, 0.3546221852, -0.2129131258, 0.2873154879, 1.7163056135, 0.3986051679, -2.2500936985, 1.6220793724, + 0.1039571762, -0.696338892, 1.650716424, -1.1810199022, 1.0891958475, 0.4307694137, 1.2198220491, -0.9328013062, + -0.7104882002, 0.2273416668, 1.2003076077, 2.255011797, -0.9103827477, -0.5597643256, -0.432205677, -0.419213146, + 0.7286592126, 0.0349851511, 0.8051463962, -1.2571941614, 0.2547564805, 0.2583035529, -0.4347037077, -0.0791249797, + -1.6814187765, 0.5205547214, 2.3092405796, 0.7493299246, 0.9001592994, -0.1037041694, 0.7711718082, 0.3438462913, + 0.4822458625, -2.0766065121, 0.0221872889, -0.0421145484, -0.7678053975, 0.3982978165, 1.2170741558, -0.4540759325, + -0.7831273675, -1.0605846643, -1.6356533766, 0.2026299387, -0.1641400456, 1.0439503193, -1.0182771683, 0.161699459, + -0.2499357611, 0.7871867418, 0.1861835867, 0.5747888088, -1.7889155149, -1.9064621925, -1.0385804176, 0.7762565613, + 0.3348379731, 0.2335910946, -1.0033197403, 0.7750243545, 0.6567839384, 1.4885655642, -1.0188703537, 0.4090184867, + -0.0310165752, 0.5363311768, 1.5438086987, 0.6926738024, 0.9071796536, -0.1791453212, -0.274399966, 0.0375481956, + -0.0360734574, -0.0225227624, 0.7798106074, -0.310415566, -0.5394257307, -0.3660118282, -1.2562537193, 0.1709382087, + -1.0761003494, -0.09323553, -0.181150794, 0.519995451, -0.5508889556, -1.0994771719, -0.4694336057, 0.7088356018, + -0.0675911307, 1.3022845984, -1.4211859703, 1.2567162514, -2.3688504696, 0.7742468715, -0.427370131, 0.1674273014, + -1.3203834295, -1.8911298513, 0.5281402469, 1.3740572929, 0.3885111809, 1.0885382891, -1.7151808739, -0.3717588782, + 0.0876440331, -0.572568357, 0.0155486111, -1.0659922361, 0.4667593837, -0.0940362737, -0.4041534066, -0.165681988, + 2.3223657608, -0.7614206076, 0.9490546584, -1.4844082594, 0.7458498478, -0.0060643018, 0.7887188792, -1.1180588007, + -1.0001761913, 0.7314289808, 0.235721603, 0.3824612498, -1.7703744173, -0.2727081478, -0.1264617443, 0.6515104175, + 0.5096127987, 0.6367074847, -1.018414855, 1.2223472595, 1.3987852335, 0.7798677087, 0.6547874808, -0.3030628264, + 0.0454207473, -0.3884822726, 0.3867644668, -0.9542946815, -1.8427627087, 0.3048293889, 1.9156039953, 1.2040926218, + -0.2316040397, -0.5864921212, -0.2658803463, -0.4716253281, -1.5087419748, -0.0129999518, -1.6092796326, 0.7645639181, + 0.7615116835, 1.2913290262, -0.4876889288, -0.4697682858, 0.3820580542, 0.4084323943, -0.6136229038, 0.6022604704, + -0.3676231503, -0.7209435105, 0.558688581, -0.5583328605, 0.4996970892, -2.0316460133, 0.0585249402, -1.0543115139, + -1.0559836626, 0.3332637548, 0.0095748026, 1.8420743942, 1.0140199661, 0.0083231404, -1.5318380594, 0.6986145973, + 0.637319088, -1.8509548903, 0.2487269789, -1.2360033989, -0.3390091062, 0.4469988048, -0.1896353811, -0.3229845464, + 0.4780968726, -1.3126137257, -0.2899254262, -0.1851799935, -0.3376224339, 0.4259453416, -0.4082024992, -0.8978323936, + -0.6690765023, 0.2631308734, 0.5530337095, 0.1995165348, 0.2926838398, 0.8894163966, -0.0055672377, 0.7018143535, + -0.8826447129, 0.0749236047, 1.2906317711, 1.0046035051, 1.0409386158, 3.0276360512, -0.0133288782, -0.0506551601, + -1.8908251524, -0.2714906931, -1.303062439, -0.2462271601, -1.8104127645, 0.1279558837, 0.179331392, -0.7023834586, + -1.0055930614, -1.4191739559, -0.4562571943, 0.4048222899, 1.3166447878, 1.1341559887, 0.716673553, 0.5539758801, + 0.4354004264, 0.3141281605, 0.6505777836, 0.2128535211, 1.6090195179, 0.1628310382, -0.6526899934, 1.2286890745, + -1.2203204632, 0.4666250944, 0.7341588736, 0.1583673805, 0.1684402227, 0.1241835728, 0.7640827894, 1.2957168818, + 0.7631736398, -0.6601703763, -0.0008463254, 0.0685535297, 1.1067372561, -0.4385348558, 1.7345260382, 1.9808120728, + -0.6242682338, -0.0815576091, -0.1650884449, 0.4348444045, 0.5211656094, -1.6433618069, -1.7573856115, -1.489243865, + -0.4256701171, 0.2377105355, 1.536591053, 0.3241511881, -0.5333830714, 0.518992722, -0.3648990393, -1.9341444969, + -0.4795877635, -0.968536377, 0.3621700704, -0.4226962328, 1.9258793592, 0.5076354742, 0.2610789239, -1.2897127867, + 1.4333382845, -1.6838537455, -0.7709188461, 0.870544076, 0.1586957872, 0.295683831, -2.0230813026, 1.1002036333, + -1.1002752781, -0.5147218108, 0.1019927114, -1.0212808847, -0.5737935305, -0.7874208689, 0.435097456, 0.1936040074, + -1.3571660519, -0.4171037376, -1.6063512564, -0.2483906001, -0.269399941, -1.5144617558, -0.122614719, 1.574228406, + -0.2891094089, 1.2006629705, -0.3703657985, -1.6033035517, -0.4120010436, 0.2618357539, 0.0800257102, -0.0225607231, + 1.0052714348, 0.2401950359, -0.9681993723, 1.6243599653, 1.771173358, -0.4288421571, 0.8745658994, -0.7261585593, + -0.7740636468, -0.3783999681, 1.046892643, -0.1909528077, 2.1233911514, 1.6014511585, -1.4648680687, -0.2578746378, + 0.5449219942, -0.8318146467, 0.2432440072, -0.5521076918, 0.4936685264, -0.0429933108, -0.7929572463, 3.4898121357, + 0.6794958115, -0.6419728398, -1.2206847668, 1.3815455437, -1.5034804344, -1.4729547501, -0.7631402612, 1.4460397959, + 1.173551321, 1.1392821074, -0.3697892427, 0.1053928807, 0.1785945147, 0.1319828779, -1.2402095795, -0.7929094434, + 0.0239162408, 1.2175018787, 1.2581635714, -1.1096943617, -0.746757865, -0.1821890175, 1.7982856035, -0.9656202793, + 0.0464049689, -0.4019823372, 0.8537561893, -0.9632617831, -1.3833892345, -0.3336651325, -0.6310629249, -0.6288160682, + -0.6705541015, 1.1295614243, 1.2133406401, -0.1866526157, 1.8917940855, -0.2755779922, -0.6542409658, -0.3929320574, + -1.2494572401, 0.3466140926, -0.5797623396, 0.8853974938, -0.218918249, 0.6220045686, -0.3418531418, -0.9100940228, + 0.8505608439, -0.5887028575, -0.7855650783, -0.3946730494, -0.2303701043, 1.3030629158, 1.7425899506, 0.1629963517, + -0.1453389823, -1.2816724777, -0.6563048363, 0.0003808588, -0.66389364, 0.8562603593, -0.1051234752, 3.0289349556, + -1.4466205835, 0.1836807728, -0.5522636771, 0.5423675179, 2.7219474316, 0.891055882, 0.6465635896, -0.0759895593, + 0.1817708462, 0.3457686603, 0.723987639, 0.7132585645, -0.4586695135, 1.0333595276, -0.218935594, -1.1411225796, + -0.8677021861, -0.968847096, -0.6339297295, -0.0074916431, 0.0354148932, 2.4297785759, -0.8822140694, -0.9148740768, + 0.8378556967, -0.1476698518, 0.6026245952, -0.0974400416, -0.632502079, -0.8441191316, 0.510375917, -0.7266747355, + -0.7533026934, 1.4277828932, -0.731028378, -0.0555546284, -0.9097919464, 0.9007401466, 1.123857379, 0.0252667442, + -0.7156252265, -0.227729544, -2.1477272511, 1.593249321, -1.8628616333, -0.3776150644, -0.109005399, -1.5743252039, + 0.9123138785, -1.3972257376, -0.060060095, 0.3769355714, -0.4396723211, 2.1093904972, 0.3233568668, 1.2451854944, + 0.750290215, 0.8297964334, -0.0762333572, -0.079701744, -1.1705890894, -1.7427301407, -0.50952667, 0.3880380094, + -1.5055037737, 1.007158637, 0.5120072365, -1.0015641451, 0.6942522526, -1.163901329, -1.5982449055, 1.4353106022, + 1.3250426054, -0.766440928, -0.2600101531, -0.8542203307, -0.8446595669, -1.441726923, -1.6894496679, -0.7739345431, + -0.4729284644, 0.6903986931, 0.5380149484, -0.6231607795, 0.1010175794, 0.6848499775, -0.6755223274, 0.3829651773, + 1.0227255821, 0.0714008585, -0.0293932445, 1.82500422, 0.2873611152, 1.8083481789, 0.5629999042, -0.8379108906, + 0.4814782143, 0.9358680248, 0.303425014, 0.4835818708, 0.6362583637, -1.9723367691, 0.1129239202, -0.9730765224, + -1.2520319223, -0.6632204652, -0.5693321228, 0.0858491659, -1.6128265858, 2.4252493382, -1.2824521065, -1.2813147306, + 2.0825462341, 0.9443973303, 0.3961180151, -0.6054111719, -2.1568701267, 0.8435489535, 1.5585157871, 0.8996023536, + -0.1726988107, -0.2633880973, -0.3633803427, 1.7543785572, -0.5090419054, -0.1032537743, 0.2715066075, -0.4920640588, + -1.5715212822, -0.9911488891, -0.4591449201, 0.1021347195, -0.1885639131, -0.1514699608, 1.242990613, -1.2038488388, + 0.1201531067, 0.6239452362, 0.8239920735, -0.8424552679, -2.4820933342, 0.0825293586, 0.7349550724, 1.4615254402, + -1.8211261034, 0.7355304956, 0.0824137405, -0.0821021348, 2.4546854496, -0.6104809046, -1.4369820356, 0.3347872794, + 0.0953120217, -0.1711449176, -0.277568996, 0.2559177577, -0.619232595, -0.0518681258, 0.7144017816, 0.1674056649, + -1.9963171482, -1.2033586502, 0.1521248519, 2.5265574455, -0.6133159995, -0.3060063124, 2.1903588772, -0.0703226253, + -0.3838198483, -0.9298690557, 2.1403698921, -1.1335151196, 1.8761792183, -1.1630308628, 0.7195526361, -0.9941395521, + 0.2390076518, -0.5244604349, 0.217202574, -0.3227881193, 0.4246652126, -0.7177217007, -0.1237884983, 1.0893511772, + 0.3389956653, 0.673783958, -0.4500505924, 1.9005181789, 0.3046309054, 1.052827239, 0.6181700826, 1.2530003786, + 0.1073710024, 0.6634507179, 0.626190424, 0.9524511695, -0.3014968634, 1.7174031734, -0.7578988671, -0.4663391113, + -1.478277564, -0.262804538, 0.5235355496, 2.8543355465, -0.7934467793, 0.2137494832, 1.149220705, 0.7139776349, + 0.2760613859, 0.4369187057, -1.4526598454, 1.1321744919, 0.4283018112, 0.6453626752, -0.3679089546, 0.821631074, + 0.2988089919, -0.6367230415, 1.3324908018, -0.2185408473, 0.4428556859, -0.9793181419, -2.3876283169, 0.7414361238, + -0.5878328085, -0.1686553657, -1.0306122303, -0.5140874386, -0.6933035254, 0.8230751157, -1.2295557261, 2.267588377, + -0.0020896329, -1.530620575, -0.2049885243, -0.6176739335, -1.0552675724, -1.0267729759, 0.7805772424, 1.468093276, + -0.6374821067, -0.0440820456, 0.6838778257, 0.1650949717, -0.6097522378, -0.9951433539, -1.1233109236, 0.2587343454, + -0.6517683268, 0.6634348631, -0.1877324134, 0.0308681466, 0.0288206376, 0.5415495634, -0.5201122165, 0.4827626944, + -0.1858599484, -1.308380723, 0.2003160715, 1.1300369501, 2.4712626934, -0.2974512577, 0.7705679536, 0.0965008363, + -0.8537307978, 1.1313229799, -0.4410588145, -0.364133507, -0.4061614573, 0.2904089391, -0.2795744836, -0.6002675891, + 0.210987702, -0.0930366442, -0.0394295789, 0.2261722982, 0.8024736047, -1.842879653, -0.6576650143, -0.3111714125, + 0.8684728742, -0.5444998145, -1.928049922, -0.1636284292, 2.2250468731, -0.1079393625, 0.649095118, -0.6822468638, + -0.1159646735, 0.9660808444, -1.0916345119, 1.2806700468, -0.6005136371, 0.4279638827, 1.6419439316, -0.7441155314, + -0.5071685314, 0.2477568686, -0.649834156, 0.8419561386, -0.7465654016, 0.8345745802, 0.7719214559, 0.0275003444, + -0.8203216791, 0.7621380091, 1.841326952, 1.9317811728, 0.719006598, 1.2122613192, -0.5506513715, 1.2079052925, + -0.5110875964, -0.9887308478, -1.4687793255, 0.7604703307, 0.8583361506, -1.1693745852, 0.9667693973, -1.0014497042, + 0.9113854766, -0.8501291275, 0.1033337414, -0.2851611078, 0.4838745594, 0.030643139, -0.9261587858, 0.5031406879, + -0.720494628, 0.0854555964, 0.5342746973, -0.2392912656, -0.3483181894, -0.7283043265, -0.1952078938, -0.2268493474, + -0.5073602796, 0.4071733952, 1.789678216, -0.7856964469, 0.1932238191, -0.8698413372, -0.289447695, -0.437184155, + 0.6789008379, -0.5095900297, -1.1314054728, -0.9796065688, -0.9307839274, -0.2411198616, -1.8260837793, -2.1603901386, + 0.7138137221, 0.4682048559, 1.8073990345, 0.3030933738, -1.5624271631, -0.1223475486, -1.44574368, -0.1992979646, + -0.4670667946, 0.5985659361, 0.0050599673, 1.0435233116, -0.3494057655, -0.141980499, 1.0799071789, -1.1984112263, + -1.6463519335, 0.9736518264, 0.27602157, 0.4218560159, 0.2312800139, 0.0733595192, 1.0696476698, -1.1329557896, + -0.2230795324, 1.1043237448, 0.331156671, -0.1949632615, 0.4872407019, -0.5673235059, 0.3815425336, -0.5976793766, + 0.3133822381, 1.1188403368, 0.1023709923, -0.7640777826, 0.5128422379, -0.9548774958, -0.7417376637, 0.8232577443, + 0.6041470766, -1.510727644, -0.6352846622, -1.6938943863, -1.4230499268, 0.8208574057, -0.1627612412, -0.3808040321, + 2.1364395618, -0.9052449465, -1.3772284985, -1.680727005, -0.5424402356, 0.97037673, 2.039213419, 0.0691738948, + -0.1845367402, 1.0785111189, 2.0295569897, -1.2068397999, -0.4048538506, 0.3063526452, 0.0183172151, -0.792571485, + -2.4151265621, -0.5461390615, 0.5046216846, -1.1571860313, -1.0568937063, 0.0951267779, -0.2945894301, 0.64095819, + -0.5636038184, -1.2628661394, -0.596324861, 1.0266063213, -0.1695082039, -0.8970633745, -1.5442864895, -0.6414470077, + -0.6634951234, 0.0513509884, 0.4815643728, 1.3058356047, 0.4562318921, -1.1240118742, 0.8064363599, -0.2292824686, + -0.9644187689, -0.8825575113, 0.4957913756, 0.4160384238, 0.7359398603, -1.0344359875, 0.6110323668, 0.0616292097, + -0.8699955344, 0.9175645113, 0.5920697451, 0.2377380133, 0.1208677292, 0.1229188591, -1.1193079948, -0.5608552098, + -1.028652668, 1.412068367, 0.2869732082, -0.7669487, -0.4248317182, -1.6202235222, 1.1397325993, -1.1340955496, + 1.7128037214, -0.0321023352, 2.424258709, -0.3608433008, -0.3228870332, 1.5381108522, -0.1577602327, 1.7750029564, + -0.7555779815, -0.2008749545, -0.7190867066, -2.0994808674, 0.6139115691, -1.2123483419, 0.8159266114, -1.8295583725, + -3.5421888828, -0.3941495419, -1.0236091614, 0.2525290549, 0.5810935497, -0.1076203361, 0.4633731544, -0.4760022163, + -0.0666669309, 0.9731261134, -1.4544069767, 0.0888629779, 1.7643368244, -0.1727118343, 0.5579123497, -1.1497603655, + -0.3366352916, 0.875172317, -1.4169456959, -0.8309580684, 0.365921855, -0.3941937983, -0.3234885931, -2.141512394, + -0.2322276533, 1.7834504843, -0.4405650198, -0.1744079888, -0.4390559494, -0.8015988469, -1.1638343334, -0.5664111972, + 0.2518135309, -0.6597012281, 0.2770966589, -1.0669745207, 0.2963372171, -0.0308781285, -0.3477644324, -0.8671655655, + -1.2455052137, 1.2770495415, 0.1706280708, 0.1064133495, -0.7048476338, 0.6347349286, -0.7335917354, -0.8754142523, + 1.1479344368, 1.5040304661, 1.3156964779, -0.5855301023, -0.1134957299, -1.0665155649, 0.2300466001, 0.9959614873, + -1.3386521339, 0.4310475886, 0.4835477769, -0.5265149474, 1.6178389788, -0.052586738, -0.9931297302, -0.2980194092, + -0.8178262711, -0.7970831394, -0.5230959058, -0.2952790558, 0.151923582, -0.5994967222, 0.8724045157, 1.087582469, + -1.2039092779, 1.0752569437, -1.4313342571, -0.0718548223, 0.5625308156, -1.0406832695, -0.5584868789, 0.6927548647, + 1.2421534061, 0.244086951, -0.3585351706, 0.6971446276, -0.0839696378, 0.1699494272, 1.3358668089, 1.2711428404, + -0.5545876026, -1.3880506754, 2.2152044773, -0.8038774133, 0.5055804849, 1.775031805, -0.010820034, -0.422152549, + -0.0152974008, -0.7703688145, 0.0354482979, 0.3172935545, 0.6298582554, -0.8587480187, -1.3135603666, -0.5014687181, + 1.8155835867, -0.632845819, -0.3373099566, -1.5931397676, -0.2987871766, 2.0653538704, -0.363864392, -0.9729212523, + 0.7749390006, -0.7497231364, -1.8904943466, 0.8607858419, 0.1471386701, -1.5295069218, 0.5777686834, 0.8261218667, + -1.0119875669, 0.0897994936, -0.443056196, 0.0323836058, 0.2219475061, -1.2818908691, -0.2708592713, 1.457310915, + 0.8804024458, -1.5916829109, 1.0492521524, -1.1633678675, 0.8123183846, 0.4321608245, -0.8351872563, -1.6270632744, + 0.5444349051, 1.7567660809, -1.4698419571, -1.3057603836, 0.6106351018, -0.6856634617, -0.0027157622, 0.7870089412, + -0.18501468, 2.8850343227, 1.5643398762, -1.0507323742, 0.6868153811, 1.1048454046, 0.1835930198, 0.5201048851, + 0.7623929977, -1.469606638, 0.0583677441, 0.4692377448, -0.2277192771, 0.9734441638, -0.0795424357, -0.2654288709, + -2.202819109, -0.2876582742, -0.0065556336, -0.0743332133, 0.5298947096, -1.4907051325, -1.0873161554, -2.1639416218, + -0.4339273572, 0.3658332825, -0.2206286639, -2.2076971531, -0.4790238142, -1.8818588257, 0.4069420695, 0.2041137069, + -0.2685712576, 2.194082737, 0.3173443079, -0.5103394389, -0.389336288, -0.4261973202, 1.2880473137, 1.3300783634, + 1.0021003485, -1.7409325838, -0.1299262196, 1.4271765947, 0.1755771786, -0.13619712, 2.6091077328, -2.1213953495, + -1.487609148, 0.4027919471, -0.7992261648, 0.8391885757, 0.6907860637, 0.0751595125, 1.9657648802, 0.50342834, + -0.5381843448, 2.523252964, -2.2388384342, 0.5314210057, 2.4042863846, -0.1817212552, 0.4993635118, 0.2077349424, + 0.869763732, 0.4360201657, 2.336935997, 0.2676490843, 1.190371871, 0.8799911141, -1.1188682318, -0.9714317918, + -0.976785481, -1.3006596565, -0.2873510718, 1.4437073469, 0.9303485155, -0.3495375216, 1.2017552853, -0.9662505388, + -0.7631691694, 1.6332331896, 0.8243235946, -0.488433212, -0.0201347098, -0.7768230438, -0.7631254792, -1.2737504244, + 0.4627576768, 0.1729757488, -0.3228688538, -2.4766850471, -1.1090526581, -0.6864037514, -0.8046090007, -0.7138791084, + 1.6377116442, 0.6567335725, -0.0047580036, -2.2416980267, 0.1491056532, -0.0847144574, 0.2720263004, -1.6646059752, + -1.1872817278, -1.5886445045, -0.2330412865, 0.2284714878, -0.984437108, -0.1336304843, -0.5829446912, -0.2540107667, + 2.2281854153, -0.5904042721, -0.5926827192, -1.3128408194, 0.1390305161, -0.1672947854, -0.7939913869, -0.6221416593, + -1.5166251659, -0.1779445559, 0.0959212556, -1.6828132868, -0.7401673198, 0.5231422782, -0.3322941959, -0.178347975, + 0.4485481381, -0.3100477755, 0.0970409885, 1.1743543148, -1.8261427879, 0.4978103042, -0.0108789131, 0.5395866036, + 3.3376805782, 0.5630101562, -0.474368751, -1.9228357077, -0.0009492107, 1.3383150101, 1.5428452492, -0.2962970436, + -0.5699378848, -0.4364693761, 0.2970700264, -0.5584040284, -1.9995604753, -0.7018766999, 0.7856997252, 1.6371961832, + -1.1782302856, 0.5775887966, 1.2874151468, 0.6118171215, -0.5430070162, 1.025231123, 1.9605115652, 1.1515276432, + -1.1050601006, -0.3522197604, 0.3429833055, 1.9247678518, 0.1838604361, -0.4415161908, -0.7715782523, 0.1724594831, + 0.7692704201, -0.5029193759, -0.204146564, 0.6117989421, 0.2968843579, -0.9996942282, 1.7067486048, 0.6819940209, + -0.6585046053, -0.1444742084, -1.0080267191, 1.4498666525, 0.3252133429, -0.8631876707, -0.0172087178, -0.9234526753, + -0.1951841712, 0.8916925788, -0.4279014468, -0.4757214785, 1.1231888533, 0.5568086505, 0.5508191586, -0.1973502934, + -1.0614956617, -0.9130429029, -1.2311202288, -0.1490184516, 0.6185660958, -1.048815608, 0.4432644546, 0.8579077125, + 0.6526910067, 1.9192267656, 0.6657885313, -2.769951582, -0.8622987866, -1.532941103, 0.547709167, -0.3008966446, + 0.408968389, -0.2756463885, 0.2297792137, 0.7346068621, -1.2895530462, -0.6784411073, -1.2107373476, -0.4332395196, + -0.0472933054, -2.2021653652, -0.2635502517, -0.7713882327, 0.9504997134, 0.5086578131, 0.823700726, 0.6284089088, + 2.4425268173, 0.6307875514, 2.4813482761, 0.1044523641, 0.6090664268, 1.5078846216, 0.6996105909, 0.5948370099, + 0.2660599947, -0.2112916857, 1.5669039488, 0.9084113836, -0.6771945953, -0.1638096422, -0.4631693959, 1.1034935713, + -0.1055989787, 0.0793656483, 0.627127111, 0.7019786835, 0.3838609755, -1.073879838, -0.6967238188, -1.4907166958, + 1.2653003931, 2.0242471695, -0.3331431746, 1.3018358946, 0.2629842162, 0.0544529743, 0.5886738896, 0.7199140191, + -0.2402157187, -0.3608579338, 0.716006577, 1.2522007227, -0.878041029, 1.2056716681, -1.2108603716, -0.2572793365, + -1.8514751196, -0.1546487361, 1.5449539423, -0.2368666679, 0.0098899864, -1.0413780212, 0.2774117887, -0.2326158434, + 1.7425477505, 0.9690331817, 1.6429095268, -0.5832452178, -0.1323042661, -1.0757516623, 0.5345213413, -0.3577066958, + -1.2440371513, -1.1071386337, 1.0463796854, 1.0088303089, -0.0133500062, -0.3407829702, -1.4332808256, 1.2677539587, + -0.6842421889, -1.5895107985, 0.1031334102, 0.3260625005, -0.8146274686, -0.5703064799, 1.5360972881, 1.1497735977, + -1.0545229912, 1.1621849537, -0.0205927342, 0.0773499012, 1.5707740784, 2.3440666199, -0.0833226591, 1.2771021128, + 0.6326636076, 0.3524564505, 1.0547939539, 1.2561269999, 0.925457418, -0.4101853073, 0.7814167142, 0.5550388098, + -1.8132902384, 0.5165917873, -1.6028478146, 0.1231929883, -0.8797899485, -2.0823435783, 0.3851499259, -1.3730741739, + 0.3431421518, -1.287088275, -1.0696678162, -1.955116272, 2.1060843468, 0.5244371295, -1.8513286114, -1.8891903162, + 1.6993538141, 0.4485278726, 0.8354133368, -0.3720458746, -0.5648186207, 0.2110529244, -0.4747396111, -0.7716717124, + -1.2227087021, -0.3932309449, -1.0957214832, -0.3843332529, -0.4385857284, -0.2289460748, 0.1591261774, 1.8326412439, + 0.3320563436, -0.3171687424, 1.8090025187, 1.0536510944, 1.5990201235, 0.6480306983, 0.9056814909, 1.0043029785, + -0.2869877517, 0.1809553057, 0.9514772296, -0.042217955, 0.7730164528, 0.5366948843, -1.3359624147, -1.2184035778, + 0.5566676259, -1.3658822775, -0.4281991422, -1.7386028767, 0.4616151452, -1.1900107861, -2.471310854, -0.4954342842, + 0.2345984131, -1.8488981724, -2.1743729115, -0.6402022839, 0.0303491205, -0.7284300923, 1.9178283215, 1.6713473797, + 0.4037494957, 0.2346402109, 2.0459208488, 0.3015230596, 0.7130191326, -0.6341357231, 1.4106793404, 0.2356214225, + 0.1327618361, -0.223049596, -0.4091452658, 0.2005991936, -0.0833660811, -0.8700286746, 2.7954144478, 1.7317944765, + -0.6571676135, 0.6018900871, -0.0520828702, 0.3507285714, -0.5154905915, -0.1296486408, -0.50928092, 1.2773561478, + 1.0116991997, -0.6150847673, -1.4773579836, 0.7563268542, 0.8471134305, -0.4720822871, 0.4313528836, 0.0375151336, + 0.8350439072, 0.4294562638, -0.3305866718, 0.4861770868, 0.6976563931, 0.6272200346, -1.6637167931, -0.2475887835, + 1.0828968287, 1.9375406504, 0.0171681941, -0.2749762535, -0.7067273855, -1.8384919167, -0.6727235913, 0.4818950891, + 0.8734824061, 1.1389626265, -1.3718824387, 1.0223542452, 0.4262120128, 0.2025973946, 0.1423050314, 1.429890275, + -1.3199853897, 0.4568197131, 1.534573555, 0.5935459733, -0.4387113154, -0.1879886091, -0.3233093619, 0.4590752423, + -1.5666143894, -2.3096513748, -0.8251853585, -1.0219471455, -0.001492961, 0.4029170573, 1.0825065374, 1.4356482029, + 0.6444023252, -0.1995886266, -0.2893678248, -0.0991581753, -0.1651691198, 1.0189162493, -0.1947890669, -1.2835777998, + -1.7958240509, 1.9413176775, 1.4828227758, -0.8889564276, -0.5395320058, -0.5694774985, 0.0775188878, -0.7718951106, + 0.8657597899, -1.5139957666, -1.2930766344, -1.799372077, -0.2752868831, 0.91815418, -0.7155758739, 1.0465465784, + 1.2638782263, 2.2021529675, -0.9961844683, 0.0974123031, 0.0123674851, -0.208940506, 0.9067828655, 1.2267822027, + 0.3396924734, 0.1184439957, 2.0369150639, 0.3253271878, 1.8651583195, 1.4540983438, 0.5370510817, -0.7455057502, + 0.2601398528, 1.7201685905, -1.7035471201, -0.2939456701, -0.3423474729, 0.9926267862, -0.7185393572, 1.6899878979, + 0.096368812, 1.5225541592, 1.2421973944, 1.1041691303, 1.5041767359, 0.405082196, 0.5243073106, -0.1115907133, + -0.1680535376, -0.0969657302, 0.0803446621, 1.2012168169, -0.4391567707, 1.2089624405, -0.7686284184, 0.2084608078, + 0.524344027, -1.6587768793, 0.499050647, -0.6774152517, -0.4325406551, 0.6804471016, -1.4003276825, -0.1406010389, + -0.6582599282, 1.6774594784, -0.6680455804, 0.2592495978, 0.8286221027, -0.5804581642, 0.2537096143, 0.9645189643, + -0.315731436, 0.5982891917, 0.8521072268, 0.5036994219, 0.0840232447, -0.1938900799, 0.013851298, -0.2024308294, + -1.0314016342, 0.0266645644, -0.6234315038, 2.1404976845, -0.379652828, 0.8915473223, -0.7924473882, -0.2630101442, + 1.2968854904, 1.0652110577, 0.4945122898, 0.4680919051, 0.4252710938, 0.0305738803, -0.7643531561, 1.3036431074, + 0.1892702878, 1.0127239227, -0.4154120982, 0.1690457165, 0.2398145199, -0.2753032148, -0.0394092537, -0.1768219471, + -0.6261203885, -0.4798114896, 2.090259552, 2.4536385536, 0.2569797635, -1.3700937033, 0.2429075092, -0.0302436706, + 0.0957037061, -0.565009892, 0.482185483, 1.5858329535, -0.3087330759, 0.0644669831, -0.0620031543, -0.0495426171, + 0.6991023421, -0.1768588275, 0.2576231658, 1.049826622, 1.1218752861, 2.0640258789, 0.2962799668, -0.5372537971, + 0.0778273121, -0.6351861358, 1.9494534731, -0.7365251184, 0.2154163718, -0.8799818158, 1.1496148109, 0.3462239504, + -0.7713207006, 2.7176063061, 0.6472253799, 1.5203940868, 0.0201782063, 1.1566685438, -0.6539087892, 0.2394919395, + -1.7418583632, -1.1859192848, 1.3754141331, 0.5204149485, -0.1954313666, 0.4072748423, 1.2499068975, -0.2092721015, + 1.2599943876, 0.4698984027, -0.1057309136, 0.6285521388, -0.1283890307, 0.2182361186, 0.5527539253, -0.5691096783, + 1.1039172411, -0.0255232845, 1.281014204, -0.3833185732, 0.1088434681, -0.0079321684, -0.6392134428, -0.3211532533, + -0.6840104461, 2.2359540462, -0.7377978563, -2.1295697689, -0.8262901306, -0.2741989493, -0.7584269047, 0.266756624, + -0.1170935258, 1.2125899792, 1.390111804, -0.102547735, -0.5680760145, 0.573279202, -0.6226810813, 1.0726773739, + -0.755558908, 1.3011289835, -0.7514100075, -0.3121113777, 0.1953123808, -0.7970280051, -0.0469507203, -1.1711391211, + -0.5039377809, -0.1742249131, 1.7650339603, 1.0166648626, -2.3796470165, 2.1885800362, 0.6374771595, -1.4910366535, + 0.5055052042, 0.2328806818, 0.8630269766, -2.2999992371, -1.5238486528, 0.5972530246, 0.1055067182, -0.5324211717, + -0.5370553136, -1.2598272562, 1.6097830534, -0.7878819704, -1.7461416721, -2.0719652176, -1.1854764223, 0.3427107036, + 0.5295251608, 1.76111269, 0.970412612, 0.510055244, -0.6306912303, -0.4613394737, 0.9809895158, -1.7130533457, + -0.7521519661, 0.1366459578, 0.5631435513, -0.1118881255, -2.4540958405, -0.0765665099, 0.764223814, 0.6514412165, + -0.2037922889, 0.9903054237, 0.3785459697, -1.6247358322, 1.2173683643, 0.2166759223, -0.861212194, 0.4859002531, + -1.036490798, -0.4721792936, -1.6349135637, -1.4085305929, -0.8389165998, 1.2321178913, 1.3330185413, 0.3066735268, + 0.9116269946, 0.6791136265, 2.8482429981, -0.4379735291, -2.2370553017, -1.5435577631, -0.1815133095, 1.2109670639, + 0.5453848839, 0.4780768752, 1.5647675991, 2.2001993656, 2.1024439335, 0.8078509569, -0.3416246474, -0.6584426761, + -0.1349043101, 0.354772836, -2.2675919533, -0.2931696475, 1.0089668036, -0.6153686643, 0.1034570783, 0.6448723078, + -0.8765313029, 0.4534460008, -0.3699859381, 1.2004622221, -0.0722925514, -0.0325831361, 0.9020727873, -0.7152183652, + -0.8456809521, 1.1576007605, 0.617118001, -0.0472845919, -0.9105609059, 0.1960259825, -0.2576677501, -1.9657860994, + 0.9828581214, -0.930516541, 0.8664217591, 1.2800661325, -1.127836585, 1.8148369789, 0.2521477938, 0.890639782, + 1.5773588419, 0.4439918995, 0.0060209022, 0.8361096978, 0.4923763573, -1.1642525196, 0.7681359649, 0.2648225427, + -1.1226508617, -0.2650801241, -1.6352653503, -1.3773202896, 0.6504764557, -0.9845471978, 0.5976469517, -0.0603680871, + 0.3551152945, 0.9604079723, 1.4429877996, -0.9509329796, 0.4106124043, -0.8905282617, 1.4084507227, -1.2862893343, + 1.1871342659, -0.2408435643, 0.7524929643, 0.9669978023, -0.0317020342, 0.1478836387, 0.4667394161, -1.1262389421, + 0.4174720943, -0.4278752208, 0.0893254876, 0.312335521, -0.6510843039, 3.6935560703, 0.3481149971, 0.9524300694, + 1.2629102468, 0.9691338539, 0.8425455093, 0.4645085037, 0.8258065581, -0.2780044377, 1.0713196993, -0.7075175047, + -0.1032134444, 0.5142312646, 0.5319851041, -0.0098116705, -0.1779374182, -0.2449193746, 0.8509523869, -0.6144673228, + -0.4817785025, -1.2756514549, -0.6126600504, -1.1293950081, -0.1908688098, 1.0651584864, 0.3274653852, -0.8781397343, + -1.2023971081, 0.5885425806, 0.7167418599, 0.0696014911, 1.5573089123, -0.5623143911, 0.3726352453, -1.0666670799, + 0.7341268659, -0.7441030145, -0.5995749831, 0.4551900327, -0.1493398994, -0.0821552277, 0.1749963611, -0.5736764073, + 0.6820808053, 0.1590649784, 1.7094728947, -1.2093794346, 0.1417449266, 0.0874756873, 0.044552017, 0.1454997957, + 0.622664988, -0.7579197288, -0.8653601408, -0.8565465808, 0.088454634, -1.1490837336, 1.2844370604, 1.723474741, + 1.4080694914, -0.3957767785, -2.0336396694, 4.2858557701, 0.1105877906, -1.0418227911, 1.2223359346, -1.1886203289, + 0.1480172127, -2.7951111794, -0.509735167, -1.157558322, 0.9877367616, 0.2623551488, 1.2971171141, -0.9021095634, + -0.7333549261, 0.3958832324, 0.0376789942, -1.4897017479, 0.7928319573, 0.3467888832, -0.2384968996, 0.5339655876, + 1.0606970787, 0.6961131096, 0.5275928378, -1.0800560713, -0.6828938127, 0.7291389704, 0.4540881515, -0.9229554534, + -0.2239529192, -0.8285161257, -0.7912678123, -0.0725147203, -0.1320558935, 1.2266693115, -0.1467476189, -0.5098367929, + 0.1437175274, 0.0615985021, 1.1454741955, -1.6718358994, 0.2883616388, -1.0447431803, 1.8523039818, 0.0715519041, + 1.2537438869, -2.2294402122, -0.9726954103, -0.8541699648, -1.2510904074, -0.2680608928, -0.0982486233, -2.7065048218, + 0.4315496087, 0.4952709377, 2.3173794746, 1.7902907133, 1.0368921757, -0.4934299886, -0.6587244868, 0.2156995833, + -0.781696856, 0.1607544422, -1.4151940346, -0.4447843432, 1.6773577929, 0.3867525756, 1.1128669977, 1.8861371279, + 0.9591953158, 2.4224495888, 0.8388727307, -0.815992415, 1.5163911581, 0.6435745358, 0.409224093, 1.7183226347, + -0.0800361559, -1.0487719774, -0.2141771913, 1.0178449154, 0.7592806816, 0.5728220344, 0.6055765152, -0.8523482084, + -0.880854249, -0.4607036412, 0.7181840539, 0.5790495276, -0.3860639036, -0.6235859394, -0.3401636779, -1.3322459459, + -0.3735280037, -0.9619418383, 0.9170179963, -0.0155261103, -0.7936813235, 0.2904969156, -0.2934159935, 1.5998722315, + 0.2245161682, -0.6810392141, -0.717494905, -0.0229964331, -0.643334806, 0.8996737599, -0.1399249732, -0.9068041444, + 1.2186594009, -0.4671718776, -0.0194043443, -0.5684084296, -0.8678084612, 0.5519516468, -0.9348483086, 0.4797087014, + -1.7733447552, 0.5873536468, -2.0052974224, -2.0336976051, -0.21584557, -0.2398948669, -1.976691246, -1.7725622654, + 0.7912243605, 0.6274369359, 0.0156383421, -0.4388458133, -0.2509407997, -0.7350332141, 0.0592636503, -0.2649568617, + -1.1821020842, 0.105100058, -0.41783005, -3.0862278938, 2.1433157921, 1.8003720045, -1.333947897, -0.4993157387, + -0.0595764108, -0.0815746859, -1.8172090054, 0.9544544816, 0.0266386792, -0.7247435451, 0.4710936844, -0.0355378725, + 0.5382333994, -0.2017002255, -0.2736326456, -1.085050106, 0.4361391664, 0.727545619, -1.5133862495, -1.0869604349, + -0.4892189503, -0.2241794765, -0.780171454, -1.8050248623, 0.4219087958, 0.0985516831, 0.7518414855, 0.0099756178, + -1.3204857111, -0.7362210155, -1.362519145, 1.4659570456, 1.5852022171, 0.9222944379, -0.6225005388, -0.4121412635, + -0.1012708023, 1.0839953423, -0.1868243515, 1.3171703815, 0.7383409142, 0.7114495635, -1.3378200531, 0.4559955299, + -1.0297137499, -1.0663639307, 1.8599836826, 0.2518027425, 0.377658993, 1.6198328733, -0.1385766864, 0.0779930502, + -0.9513822794, 1.6096773148, -1.1503460407, 0.2158631533, 0.9789539576, -1.64714396, 0.3016359508, 1.4386115074, + 0.7306500077, -1.8357973099, 0.6295026541, -0.4132591188, -1.5983790159, -0.0675861537, -1.8248832226, 0.5449636579, + 0.6511113644, 1.1925294399, 1.4464730024, -0.6434930563, 2.7133228779, 0.9117081761, -0.4531750381, -1.2206915617, + -0.3705402911, 1.299778223, -0.8172878623, 1.0327092409, -1.2872046232, 0.3879989088, -0.3668969572, 1.4443743229, + 0.0700865909, 0.1676746309, 1.4242259264, -0.8452426195, -0.4409632683, -1.3721363544, 0.903327167, 1.2147731781, + -0.7221063972, 0.3519815505, -1.025509119, 0.2319916338, 1.253544569, 0.1925023496, -1.2753477097, -1.118670702, + 0.8844894767, 0.068343699, -1.258780241, 0.2794378698, 0.8379051685, 0.266982913, 0.3449877799, 2.3400497437, + 1.0804201365, 1.4391826391, 0.7339784503, -0.8790752292, 0.0026909518, -0.8914278746, 0.4804829061, 1.4641373158, + 0.6813607216, 0.8553986549, 1.709040761, -0.5028632283, 1.4325996637, 0.2645716369, 1.0826915503, -0.0516118817, + -0.3066533506, 1.0699689388, 0.1768194139, -1.2282488346, 0.2069570571, 1.3318647146, -0.942489624, -1.096419692, + -0.4572708905, 0.4500499368, 0.1980328262, -1.9181954861, -0.0174330324, 0.099959515, 0.0267650168, -0.5508563519, + 1.4106292725, -0.2244167775, 0.6556907296, -0.0054974109, -0.5443715453, -0.1919281334, 0.3812180161, -0.4736113846, + 0.6195918322, 0.7323521972, 0.9373790622, -2.6295375824, 0.3766013682, 0.5224608183, -0.8840683699, -0.7412922978, + -0.5194513202, -1.3004968166, -0.0051153982, -0.7945897579, -0.1301139295, -0.0011560072, -1.037950635, -0.6288818121, + -0.0096841361, -0.2014763355, 0.6976454854, 0.1354101002, 1.5714323521, 1.0308767557, -1.3190690279, 0.8940302134, + -0.585842073, 2.8178141117, -2.288684845, -0.1681453437, 0.5785136223, -0.8217912912, 0.3408507407, -0.6147227287, + -1.1310694218, 0.9431957006, -0.6122029424, -0.6093533635, -0.2190532982, 0.2843426764, 0.6691458821, -0.8678124547, + 1.5971509218, -0.1540083289, -2.2375392914, -0.5721747875, -0.3298413455, -1.0728195906, 0.536796391, 2.1423006058, + 1.492508769, -0.133224085, 0.7596751451, -0.9900237322, 1.6975897551, -1.1039967537, -0.2365738451, -0.8477472663, + 0.5158218741, 0.95381248, -0.1393971145, 0.2098560929, 1.4214780331, -0.6133620739, -0.344320327, 0.798725307, + 0.2965416312, -0.6252503395, 0.0912849978, 0.3837498128, -1.9019155502, -0.9714212418, 0.8765338659, 0.2010715902, + -0.3521747291, 1.3726044893, -0.2925174534, -0.6309738755, -0.1950662732, -0.5796111822, 0.2951392829, 0.3845759332, + -0.155666098, -0.2773683071, 0.2328125387, 0.7338165045, -0.17842637, 0.1823998541, 0.7299521565, 0.1716358215, + -0.0308698844, 0.2138171941, 0.3089756966, 0.7322928309, -1.0055240393, -0.4655968249, 1.4510535002, 0.8053041101, + 0.8307817578, 0.5806190372, 1.4012625217, 0.4137353301, 2.2663216591, 0.905375123, 0.2676714361, -0.2638470531, + -1.1524258852, -0.2055503577, 2.0920567513, -0.0389869474, -0.5045543909, -0.1704713106, 1.7036591768, 2.3972051144, + -0.3624917269, -0.0865611285, 1.2785141468, 0.6021286249, 0.2753924131, -1.730437398, -0.9938117862, 0.2796024084, + -0.3657841682, -0.0245826654, 1.224465847, 0.2047881931, -0.3773700595, 0.8032777905, -1.9749366045, -0.1891875565, + -0.0975503027, -0.0583613701, 0.5487793684, 0.3212392628, 0.7469420433, 0.4802857339, -0.0953975916, -0.0016161953, + 0.4400027096, -0.388923198, -0.2829461396, -1.256321907, 0.6948705316, -0.8324922323, -0.4046234488, -1.0711333752, + 1.3630745411, -0.4418192506, -1.3101440668, 0.5938716531, 1.8128287792, -1.2612177134, 1.0351736546, -1.6114523411, + 1.9638142586, -1.2056689262, 0.3683494329, -0.4289750457, 0.5871503949, -0.4308027625, -0.4693752527, 0.42376858, + 1.0735077858, -0.4528256953, -0.4611294568, -0.4493314326, 0.2348384559, 1.4725769758, 0.828672111, -0.8574910164, + 1.1002789736, 0.2178244442, -0.0682177767, -1.1096816063, -0.88330549, 1.1900689602, 0.8638876677, -0.7919912934, + -1.1155849695, -0.0368701331, -0.8000605702, 0.0575532131, -0.6001101732, 1.7475066185, -0.1024022102, 0.7054311037, + 0.88843292, 1.4535988569, 0.8446703553, 0.6319045424, 2.148068428, -0.3688235581, 0.6120865345, 0.6029073, + -0.9015443325, 1.8531484604, 2.4086322784, 0.5047215819, -0.4523896277, 0.0560955927, 0.0015819527, 0.7949462533, + -0.4127202928, -1.2027662992, -0.4916600585, 0.9999223351, -0.6061544418, -1.1319777966, 1.1700640917, 0.6804245114, + 1.5015945435, 2.0653812885, 0.0969319269, 0.2641748488, -0.0362505354, 0.6237525344, -0.8102051616, -1.5553128719, + 0.2032443285, 0.2953858972, 0.5768323541, 0.1966675222, 0.9187663794, -0.9852730632, -1.7754678726, 0.5656357408, + 1.5518661737, 0.1246112362, 0.7218389511, 1.1248434782, 0.730099082, -1.7761151791, 0.4202294946, -0.6030195355, + 0.481787771, -0.3983127773, -1.2921808958, -0.7133482099, -0.069513604, 0.026813522, -1.8523842096, 0.3018036783, + 0.5316495299, -0.1636061519, 0.3650557697, -0.2680281103, 0.0313414261, -0.615033567, -2.506336689, 0.8658521771, + -0.8896884918, -1.4359755516, 0.7071300149, -0.8117466569, -0.8193208575, -1.6796098948, 0.2288485318, 1.1684442759, + 1.3867622614, 0.3720430732, -2.2209444046, 1.0519523621, -0.3739921451, 1.1328148842, 0.4190898538, 0.5840306878, + 0.3622587621, 1.3552360535, -0.6779456139, -0.4645721912, 0.7942563891, 2.9545433521, 0.1648689657, 0.2273791283, + 0.839823246, 0.1645840257, 1.2705302238, 1.968981266, 0.5604508519, 0.2973692119, -0.3421580791, -0.7549017072, + -0.9641358852, -0.0671323538, -0.2883839011, 0.9323253036, -0.4751592577, 0.2069311291, -0.9538527727, -1.8852221966, + -0.1730320305, 0.0738568977, 0.7191287875, -0.1032047048, -0.5027757883, -0.6713217497, 1.1065231562, -0.4910871089, + 0.3194410801, -0.3272990882, -0.5864269733, -1.6019154787, -1.2150155306, -0.4830319285, -2.2106018066, 0.5272894502, + 1.1339933872, -1.6582157612, 0.1045286432, 0.9769923687, 0.6356340647, -0.0837953761, 0.8529375196, -1.1835395098, + -0.0311263781, 0.1229125187, 0.1845661104, 1.4570873976, -1.0240747929, 0.2515321076, -1.5033500195, 0.137875095, + -1.1685484648, -0.452460587, 1.0256450176, -1.7534796, -0.7314636707, -0.9282721281, -0.0200786255, 0.3444993198, + 1.2372258902, 0.2347012162, 0.0017177498, 0.7588968277, -0.8208673596, -2.9165871143, -0.53373909, 1.1897857189, + -0.4590893388, 1.1943334341, 0.6033994555, -0.9690102935, -0.4756906927, -0.5146775246, -0.6181944609, -0.473949641, + -0.8306716084, 0.785069108, 1.0141893625, -0.1255545616, 3.0548119545, -0.5503615737, 0.7137859464, -1.8925294876, + -1.6286408901, 0.1578745246, 0.2897020578, 1.141617775, 1.6445769072, 0.026600508, -0.6002950668, 1.8851222992, + 0.500651896, 0.80412817, -0.4171819687, 0.9126561284, -0.9665496349, -3.0324594975, 0.1772412509, -0.7743625641, + -0.7814670205, 0.5761278868, 0.14791058, -0.3336394429, 0.4467318654, -1.1148625612, -0.7398648262, -0.1982903183, + 0.2771024704, 0.0037587737, -0.7214294672, -0.7772885561, 0.369569242, -0.8413255215, 0.4420565069, -0.3661336303, + 0.2388688028, 0.7574204803, 1.8069114685, -0.3563021123, -0.6996699572, 0.4083276093, 0.9007179141, 0.9037804604, + -0.1237754449, 1.1282645464, -0.3496119678, 0.7314071059, 1.5345368385, -0.2547729909, -0.8683311343, 1.1891893148, + 1.1465867758, 1.3951969147, -0.3881577253, 0.5991099477, 1.2029726505, 1.23790133, 0.1110376492, -0.5402413607, + -0.4763735831, -0.6523308754, -0.4530446529, -1.2403632402, -0.4820930958, 1.9094609022, -0.8305430412, -0.5602543354, + -0.3380995393, 1.2139499187, -0.673038125, 1.8736811876, 0.5619761348, 1.2849764824, -0.7612153888, 0.6084617972, + 0.5260947943, -0.3612978756, -0.0199031364, -0.0179262515, 2.7262132168, 0.100155808, 0.0873316899, 0.4253403842, + -0.2572331727, 0.3998314738, 0.5780014396, 0.5289971232, 1.1858935356, 1.5703359842, 0.6258378029, -1.3216575384, + -0.3723444939, -0.7417381406, 1.0053710938, 0.2518371046, -2.2449259758, 0.7364364266, -0.7436603308, 0.2557405531, + -2.1114578247, 1.4893753529, -0.1315749884, 0.0937679037, 0.3575634956, 1.3543114662, -0.528098762, 0.092148833, + 1.1167320013, -0.1133646667, 1.3830109835, -0.3453722, -0.0628339872, -0.6401051283, -0.6774563193, 0.0201832801, + -1.3557044268, -1.7727380991, -1.3186904192, -0.8905112147, 0.6380245686, -1.9156514406, -0.6751238108, -2.330425024, + -0.0731968582, 2.6341967583, -0.144686684, 0.9468255043, 0.1266835779, 0.5929878354, 0.2527090013, -0.7906475663, + -0.1088170782, -0.0180691257, 1.7883660793, -0.7638135552, -0.3626271486, 0.7353001237, -1.934389472, 0.987759769, + -1.2362815142, 0.3096195161, -1.3171862364, -1.2322047949, 1.425327301, 0.0599365123, 0.4724906981, 2.3247697353, + 0.3512053192, 0.4358356893, -0.2270360738, -2.0736320019, 2.1042101383, 0.6262249351, 2.01780653, -0.4194451571, + 0.1140522435, 1.6493346691, 0.5421503186, 0.4119198918, 1.8837475777, -0.1114307493, -0.4739866257, -0.111843057, + 0.3266671002, 1.0846471786, -0.7667149305, -0.3911579847, 0.7709604502, 0.9599793553, -0.6258073449, 0.4235780239, + 0.2291588485, -0.5419658422, -1.3261935711, 1.47929883, -0.5172199011, -1.8417431116, -0.9530127645, -0.5386762023, + 0.5477579832, -1.3143244982, 1.282320261, -0.8449356556, 1.7781059742, 0.2892118096, -0.6741756797, -0.298407644, + 0.3891500831, 0.0456696413, -0.715615809, 0.1342495084, -1.8112068176, 0.9137851596, 0.066471085, -1.2650182247, + 0.294331491, 0.2052179128, -0.0621892735, 1.0672193766, 0.647384584, 0.4740798473, -2.3851220608, 0.1769553572, + -0.8922551274, 0.3362334967, 0.9756082892, 1.11157763, -1.6051492691, 0.3320700526, -0.5360628963, -0.4085548818, + -0.1155323014, -0.9104030132, -1.3911604881, -0.6406959891, -0.7174149752, 0.2314108014, 0.9844489694, -0.7310201526, + -0.7337293625, 0.1070518643, 0.1595049948, -0.2646666467, -0.6786507368, -0.1914107949, 1.4713796377, -0.9440070391, + 1.6280828714, -0.9151198268, -0.3460160792, 0.0264972281, 1.2194769382, 0.9777076244, -0.9459745288, 0.2136550546, + -1.1340179443, 0.6967772245, -1.0132279396, -1.6084231138, -1.2107805014, -0.7951170802, -0.9152131081, -1.5939664841, + 0.2302491367, -1.0035600662, 0.5383255482, 0.3087547123, 0.004202974, 0.5027353168, 0.4750975668, 0.0975661203, + 1.3311247826, -0.4950006306, -2.6560649872, -0.902561605, 0.8317630887, -2.5742125511, -1.1284319162, -0.0401342697, + -1.3941005468, -1.0090293884, -1.0960578918, 1.2098025084, 1.3029168844, 0.0013557881, -0.2298772782, -0.7874842286, + 1.1899797916, -1.789576292, 0.6294350624, 0.2206836939, 0.1826732308, -1.4839683771, -0.6505553722, 0.623360157, + -0.8338543177, 0.2824832499, 0.3885993659, 1.0900565386, 1.8766107559, 0.807503283, 0.1507251561, 0.8691424131, + 0.398609817, 0.5120561123, -0.0635230392, 1.1407741308, 0.9157882333, 0.4682558179, -0.5680037141, -1.6270081997, + -0.6732350588, 0.9897184372, -0.1337077469, -0.4015781581, -0.5095635653, 0.4383413196, 0.1368908882, 2.3518426418, + 0.2311750799, 0.4614313841, -0.6706026793, -0.9506882429, 0.6988849044, 1.1486055851, -1.3775639534, -0.1598063409, + 0.2637604177, -0.1926568598, 0.8263894916, -1.2977201939, -0.8600575328, -0.6402958632, 1.6776019335, -1.9129065275, + 1.3457714319, -1.0432997942, 0.3238283992, -0.1716978103, 1.4572438002, -1.0432966948, -1.507204175, 0.0903891772, + -1.2257448435, -0.6195468903, -0.8568475842, 0.2043592334, 0.2641375661, -0.8464022279, 0.2488178313, 1.0052314997, + 0.4492959678, -0.0295740031, 0.2290060669, -0.1275434643, 0.337359786, 0.1626713276, -0.6524628401, 0.7707580924, + 0.3476366401, -0.0531140119, -0.0087814219, 1.6692032814, 1.6984108686, -0.1209266335, -0.8074813485, -0.1444534808, + 0.6372165084, -1.3039739132, -1.8125053644, -0.1793181598, 0.4690181315, -2.4916374683, -1.8491213322, -0.5576793551, + 1.3404135704, 1.0666805506, -1.5593063831, -0.9231505394, 0.9490910769, 0.4438292682, 0.2828915715, -0.1954534054, + 0.001810798, -0.1907095164, -0.1145968288, 1.9409518242, 1.0856090784, -0.9538422227, -0.8621790409, -0.4659977257, + -1.7791017294, -0.5010645986, -0.6775425076, 0.7356759906, -1.7972897291, 1.5602645874, 1.2374145985, -0.0871757418, + -0.6793118119, 0.337543577, 0.8931931853, -0.2421072423, 0.8488683701, -1.2290204763, -0.269397378, -0.1366267353, + 0.0585083216, -1.7161861658, -0.5805538893, -0.9939773679, -0.265000701, 0.4637797177, 0.7559719682, -0.7087855339, + 0.1012896299, 1.106485486, 0.633346498, 0.2938173711, 0.2699801624, 1.7075775862, 0.9169011712, 1.4294006824, + 0.3349779844, -0.6877442598, 1.5435626507, 0.8220308423, -0.407074213, 0.7013475299, 0.194370538, 0.0186969098, + -2.3783740997, -0.3056056201, 0.2207050323, 0.9657750726, 1.0608078241, -1.1249374151, -1.8694682121, 0.7967307568, + -0.1668088734, 0.8929074407, 0.5497352481, -2.28094244, -0.0579407215, -1.5476003885, 0.8956011534, 2.7000272274, + -0.2422973365, -0.0058167744, -2.7817559242, -0.8345428705, 0.5110921264, 0.2318991423, -0.2348987013, -1.1566245556, + -0.9918349981, -1.8085412979, -0.5614330173, -0.5285215378, 1.1941301823, 1.4853051901, 0.341615051, 1.3896061182, + 0.8218294978, 1.3636242151, 0.2253000736, -0.5104549527, 0.3647124767, -1.9561990499, -0.8729413152, 0.0701007172, + -0.2375694811, -1.7378988266, -1.0403276682, -0.821831882, 0.3926897645, 0.1339692175, 0.1656624079, -0.2436903417, + -0.5954623818, 0.1061979011, -0.4252826273, -2.02414608, 0.274802804, -0.0702078119, 0.3288494349, 1.0060845613, + 0.4409485757, -0.6922742724, 0.2370910496, -0.5651920438, 1.8939553499, 1.2779444456, 0.789953351, -1.6924171448, + 0.9689711332, 1.3714234829, -0.1442247182, 0.5031644702, -0.2282197922, 0.1537615359, 1.8720436096, 2.1535537243, + 0.0067972033, 0.1998646408, 0.2613457739, -0.1279868037, -0.2985032201, -0.3642401695, -1.3701349497, 0.7696627378, + -0.5171828866, 0.079694137, 1.0161266327, -0.151673153, -1.4251996279, 1.0709221363, 0.9388007522, 1.3731763363, + -0.5839059949, -0.2922695279, -1.2067660093, -1.0474648476, 0.0075881016, -0.0970899835, 0.7804442644, 0.2210815251, + 0.0727487653, -1.4848616123, 0.4621598125, 1.549025178, 2.5317053795, -0.0357220359, 0.1732001901, 1.8565897942, + -1.5049402714, 0.9150194526, -1.2461922169, -0.656840384, 0.8576791883, -0.1446761936, -1.4876954556, 0.0227297749, + 0.6311181784, 1.8708921671, 0.5190147161, 0.9861489534, 1.2462815046, 0.1173469424, 0.9257962704, -0.9750080109, + -1.2085790634, -0.438873589, -0.3076315522, -0.0882748291, -0.7719042897, 1.8123188019, 1.5279533863, -0.8639286757, + 0.7459006906, 0.2987340391, -1.1948617697, -0.361463666, 0.7074557543, 1.8297299147, 0.5339940786, 0.8260959983, + 1.7657806873, 1.2677180767, 0.1828723848, 0.0288342815, 0.8607107401, -1.5287158489, -0.1524372548, -0.6711853147, + -0.3347103596, 0.0846325532, 2.3551928997, 1.0067535639, 0.3421706259, -0.5376572013, -0.1644151658, -1.3603549004, + 0.2899155319, 0.6658204794, 0.7675340176, 0.6614913344, -0.0999178067, -0.6015158296, -0.2123781145, -1.5590256453, + -0.3314684033, -0.34960109, 0.0747257844, -0.3252461553, -0.8702195883, 1.9684408903, 0.8418162465, -0.3862409592, + -0.812063396, 0.7752045393, -0.3333698511, 0.5466673374, -0.1422412992, 0.7192386985, 0.4905242622, -0.1880952865, + 0.2143013477, 1.3246078491, -1.2478592396, 2.0077860355, 0.5948082209, -0.2080378234, -1.5965000391, -0.2735635638, + 1.329436183, -0.7973580956, 1.4204609394, -1.1398384571, -0.0142109981, -1.5199676752, 1.1904004812, 0.3158183992, + -3.0604200363, 0.1238618642, 0.967194736, -0.2805726528, -2.0813367367, -0.3729003072, -0.1396138072, -0.5271163583, + 0.1263424456, -0.4353207052, -0.2924160659, -1.1753132343, -0.130860582, 1.1438410282, 0.1119249091, 0.3604819775, + -1.0717647076, -0.2294389606, 0.1563594043, -0.6368703842, -1.2792086601, 0.0777032673, 0.0775017738, 1.3998067379, + -0.6097219586, 0.4177627861, 0.4011989236, -0.5329536796, 2.3956975937, 0.1811924279, -0.8800264001, -0.4670289159, + -0.3687879145, -2.8602409363, -0.6590387821, -0.2655385137, -0.3368494809, -1.9276156425, -1.5855481625, 1.0563932657, + -1.3409841061, 0.3984279335, -0.2940606773, -0.5712441206, -0.0067037856, -0.6415054798, -0.4785518944, -0.1218238324, + 0.2206111699, -0.4235476553, -1.3250722885, 1.715247035, -1.3964438438, 0.2865219414, -0.4178703427, -0.6859941483, + 1.0773335695, -0.4156297147, -2.6461470127, 0.401206702, 1.0373991728, -1.4278997183, -0.2466971874, 0.0849356949, + -0.8817490339, 0.5450678468, 0.1807463765, -1.0566569567, 0.1781830043, -0.0064033647, 0.3077405691, 0.6102537513, + 0.0652264729, 0.2542940974, -0.2305352241, -1.6249768734, 1.2014248371, -0.2054571807, 1.1181812286, 1.1214034557, + 1.1425615549, -1.287042141, -0.1241030917, 0.5297012925, -0.0382554494, 0.3882488012, -0.6190707684, -1.5623250008, + 0.7568140626, -1.6866751909, 0.0804848298, -1.4858338833, 0.2297888249, 1.4524667263, -0.596870482, -0.0833020732, + -0.2826476097, 1.5136855841, 1.4851976633, -1.1327924728, -0.8760012984, -0.609419167, -1.4564394951, -0.7331520319, + -0.9318554997, -0.8895848989, 0.8252238035, 0.1218120083, 0.0662026778, 0.6619882584, 2.0303890705, 1.0554903746, + 0.7169943452, 0.1783896387, -1.1470445395, -0.3398191333, 1.3697793484, -0.0253568981, 1.1636499166, -1.2545666695, + -0.1280414611, 0.6935864687, 0.1563157439, -0.1740721315, 1.1867508888, -0.0169510152, -0.007843513, 0.7718135118, + 0.1622573286, 0.2028463036, 1.2996282578, 1.9638586044, -0.8999834657, 1.172244668, 0.48907426, 1.1593204737, + 1.3701916933, -0.2957761586, 0.7029923201, -0.2342174649, 0.3841736317, 1.0627040863, 1.0547840595, -0.3150112927, + 1.194513917, 0.4034687877, -0.5125347376, 1.0919033289, 0.4950831234, -0.5558901429, 0.3558287621, -1.0803325176, + 1.0500856638, -0.6788198948, 0.5517796278, 0.7566818595, 0.5830651522, 0.6025416851, 1.1403605938, 1.9247280359, + 0.5235610604, 0.4997765124, 0.7582163215, -1.1293796301, -0.301009208, -0.9889057875, 0.6745214462, -0.889567256, + 1.0809191465, 0.8366023302, 0.447157532, 0.6851827502, 2.1633660793, 1.8103870153, -0.3494542837, 1.1950857639, + -0.367896229, 1.7989248037, -0.7417379022, 0.5473921895, 1.0161283016, -0.3572591841, -1.0351872444, 2.6292521954, + -0.4950847328, 1.0285687447, 0.0339635722, -1.6448830366, -0.5516107082, 0.0174649954, 0.4552769065, -0.175462693, + 0.1529568881, -1.2097570896, -0.8168189526, 2.386182785, 0.6213911772, -0.815839231, 0.5483052135, 0.08785972, + -1.0948483944, 0.288916111, 0.3388940394, -1.2642379999, -1.5323306322, -1.0071874857, 1.0103991032, -2.4863183498, + -1.1070255041, -1.368335247, -0.4224180877, 0.7639471889, -0.5177192688, -1.0074887276, 0.1551092863, 1.3369476795, + 0.546685636, 0.3232005239, -1.6532018185, -0.7173513174, -1.0652648211, -1.3265746832, -0.5660467744, -1.3132909536, + -0.8130620122, -0.1815343946, 1.2690964937, 1.1019312143, 0.9516880512, 1.7226719856, 0.444635123, 0.5170425773, + 1.0413635969, 0.4556803405, 0.1972223371, 1.8935484886, -0.2192615122, -1.4354544878, 1.5602838993, -0.6460107565, + 0.8395658135, 0.8136681914, -1.7072492838, -0.764966011, -0.2882774472, 0.8429179788, -0.2447516322, 0.9172566533, + -0.2275722325, 0.2997744977, -1.0302278996, -0.1052929237, 0.3555447757, -0.0440536961, 0.2784536779, -0.5446269512, + -0.7629913092, 0.0162314177, 0.5546040535, 0.9613997936, 0.0616658404, -0.2609883249, 1.019719243, -0.6264053583, + -0.5688632131, 1.5122493505, -0.3373487294, -1.6997095346, 0.5993637443, -0.927251339, 0.0842745379, 0.8615155816, + 0.4361516237, 0.0753251612, 0.2608761787, -0.9517005086, 0.9069390893, -1.098120451, -0.8780823946, 0.7374699712, + -2.0681431293, 1.6813424826, -1.0838361979, -1.1617941856, -0.2509556115, -0.5042505264, -1.1139525175, -0.2048496157, + 0.1186023057, -0.3202336729, -1.1404109001, 0.255888164, -1.7212871313, -1.0247824192, -1.7450982332, 0.6630205512, + -3.1837379932, 0.4456369877, -1.1326383352, -2.210308075, 0.1183590889, 0.669236064, 1.2288067341, -1.907892704, + -1.5564306974, -2.0014181137, 1.4565919638, -0.3936092556, 0.1973627359, -0.0117214527, 0.2743053138, 2.0025804043, + 0.1375686824, 0.4163160026, -1.0364779234, 1.3307567835, -1.9111024141, -1.5484838486, -0.1650904715, 0.8083508611, + 1.1169708967, -0.3402090073, 0.9838241339, -0.1346430779, 1.8263845444, -1.7422721386, 1.0641328096, -0.4452352822, + -0.0513705388, 0.4752159119, 1.6146486998, 0.5102171898, -0.8978606462, -0.8856185079, -1.414911747, -1.1215506792, + -0.7647787929, 0.2960679531, -1.1323281527, 0.6728130579, 0.2450481653, -1.2277650833, 0.2975145876, -2.0824947357, + 1.9949676991, 0.1659021229, 1.0105559826, 0.2631520331, -1.9276918173, -2.7682528496, 0.4685620964, 0.2694377601, + 0.2202383578, -0.0813253671, -0.9782060385, -0.6891325712, 0.8377320766, 0.0159451328, 1.3094940186, 0.4035644233, + 1.0255818367, 0.515391767, -0.1808453053, 0.1277346462, -0.0179174189, -0.9238844514, -0.556296587, -0.3335781991, + -0.1112420335, 1.0880632401, -0.9739040136, -0.6805738807, -1.2655941248, -1.1422700882, 0.3249793351, -0.0527833514, + -1.7724030018, -2.8175151348, 0.8032355309, 2.127658844, 2.1617305279, -0.0527869426, -1.0185065269, -0.4677870572, + 0.2683751881, 0.0304780379, -0.1207695752, 0.0642614439, -1.6406875849, 1.1186835766, 1.4654172659, 0.7769879103, + -0.535151124, 0.3237947226, 0.2958904505, -0.1936709285, 1.359875679, 1.1916985512, 2.2793455124, -0.095668599, + -1.3434432745, -0.1309389323, 0.2118412554, -0.6874347329, -0.8510482907, 0.048511561, 2.1660628319, 1.873301506, + -0.4796108902, 0.7988507748, -2.673178196, -0.4153742194, -0.1474187672, 0.968110919, -0.4934926331, -2.7047929764, + -0.354976207, -1.0457595587, -0.5838010311, 0.0829716697, 0.0265663285, -0.913397491, -0.0864409208, 0.2548206151, + -1.3221129179, -0.9357287288, 1.3260126114, -1.9737194777, 1.4048113823, 0.4354310632, 2.7296981812, 0.4620052874, + 0.1094514206, -0.8226955533, -0.8031890988, 0.0278037265, -0.7649024725, -1.1145186424, -0.0622494183, -0.4565858245, + 1.1405748129, -1.0133868456, -0.5143136382, 0.6725979447, -0.0492859147, 1.0113819838, 1.1048659086, 0.6603216529, + -0.37273404, 0.7112011313, 0.798510313, -0.2034807801, -0.3387661576, -2.1463022232, -1.1241475344, 0.7797137499, + -0.2611505687, 0.9198236465, 0.8049122691, 0.3930318952, 1.0530589819, -0.3481652737, 1.6241984367, -0.2310409844, + 0.8785673976, -0.5285487175, -1.6051872969, -2.2492547035, -0.2764416635, -0.5564856529, -0.1424106061, -1.6674304008, + -1.1508232355, -1.133734107, 0.2225996703, 0.950073719, -0.830719471, 0.2994698584, 0.652641058, 0.3251613379, + 0.068922855, 1.1470413208, -1.4659957886, -0.0308823474, -1.1581293344, 1.3566701412, 0.0564573184, -1.8906033039, + -0.9888930917, 0.8690288067, -0.5142025948, -0.6776256561, 1.2080899477, 0.029538909, 0.55981493, -0.460472703, + -1.0156501532, 2.0301139355, -0.8149390817, 0.4358777702, -2.2680025101, 0.7438141108, 1.9459930658, -0.1377315372, + -0.0557070971, 0.6126846671, 0.4535076916, 1.3437209129, -0.4962809682, 0.7099696994, 0.7285888195, 0.5127623081, + 0.1487104893, -0.4102285206, 0.1795057654, 1.2648516893, 0.8477721214, -1.3445240259, 1.1553347111, 1.1411762238, + -0.1662096381, 0.9143199921, -0.0289703812, 1.4069156647, 0.3577559888, -2.875030756, 0.5885147452, 2.0400743484, + 0.7269452214, -2.0255157948, -0.712923944, -1.8075281382, -0.06341739, -1.1268689632, -2.0150179863, 0.8664655685, + -0.5846761465, -0.7784549594, 1.7345633507, -2.351354599, -1.0365632772, 0.8950498104, -0.2481182218, -1.4468442202, + 0.0471748933, 0.3714194298, -1.343798995, 0.1846590042, 0.1699056774, 0.004311387, -0.2608861625, -0.619017303, + -0.632881999, 1.0290852785, -0.0337157957, 0.4794288874, 2.3265194893, 0.6430379152, -2.372948885, 0.9642911553, + 0.1792990863, -0.7555418611, -1.6815297604, -0.7509630919, 0.5920519233, 0.5271238089, -0.3613370359, -0.881477356, + -0.4798953831, 0.4807034135, 1.0450673103, 0.4689154923, -0.8064729571, -0.126286, 0.5163205266, -0.0193388909, + 1.3125473261, -0.0543386117, -1.2151954174, 0.2638210654, -0.0364308245, -0.5281606317, 1.2426241636, -0.3205830455, + -0.1426075846, -0.4687280953, 0.1643962413, -0.3802402318, 0.313639015, -1.404184103, 0.5760033131, 0.1114661992, + 1.5098890066, 0.6955231428, 0.1370026469, -0.7484128475, 0.8863014579, 0.6602393389, -1.9834080935, -0.5476236939, + -0.1973284334, 2.7404897213, 0.3918314576, -1.0367541313, 3.367866993, 1.2490388155, 0.4868883491, -0.1266106814, + -0.3812051713, -0.0928058252, -0.6301029325, -0.292901963, 0.892423749, -1.1051132679, -0.5074141622, 0.8979958296, + 0.6536089182, -1.9230524302, -0.1654659212, 1.8929178715, 1.280959487, -0.0103674419, 0.3907116354, 0.7662822604, + 1.8371510506, -0.3340227604, 2.5882060528, 0.2204035223, 0.5281216502, -1.7063302994, 0.9104158282, -1.6062641144, + -0.7288155556, 0.2892820239, -0.9528056979, -1.0483649969, -1.4120820761, -0.4685563743, -0.9451056123, 1.8808521032, + -0.7579481006, -0.1606787741, 0.5887008309, 0.4289551675, 0.3829198778, -0.3382299244, -1.3812276125, 0.4090642035, + 1.3374681473, 1.2288401127, 1.576189518, -0.8516318798, -0.2723531723, -1.2398227453, 0.2986592054, -0.1322129071, + 0.0139572183, -1.0466662645, -0.2781076133, -2.0794694424, -0.0169874635, -0.2712719142, 0.0039244746, 0.4328824282, + -1.1713631153, -0.7448069453, -2.3252754211, 0.8434809446, 1.0628112555, 1.0627806187, 1.3218361139, -0.1161545292, + 1.3281513453, 0.2959490418, -1.1790206432, 1.448186636, 1.1699938774, -1.1192673445, 0.6433444619, 0.2693232, + -0.1480689347, -0.1910275519, -0.8702706695, -1.4614882469, 1.8815187216, -1.4435530901, 1.4433736801, 0.3612532616, + -1.4280672073, 2.8515341282, 0.6932016015, -0.9333375096, -0.3010189831, -0.5288223028, -2.0452833176, 0.00033031, + 0.039783489, -0.2597131431, 0.8163148165, 1.0304787159, 1.0927882195, -0.3876484334, 0.6974347234, -0.2137241662, + 0.0889874473, 2.0182070732, -0.6308559179, -0.4557030797, 1.8793838024, 1.0392211676, 0.3013942242, 1.0411463976, + -0.7474292517, 0.4135686755, -1.2054290771, -0.4202263951, 0.7777327895, -0.4293861985, -1.3665663004, -0.6443052292, + 0.934967339, -1.2924108505, 1.2160620689, 0.3794503212, -0.5429808497, 1.1152054071, -0.0982226357, -0.2433270663, + -0.5958116055, 0.1453744769, 1.3489847183, -1.0879634619, -0.7124319077, -1.0658148527, 0.6417328715, -0.9150858521, + 1.7110761404, -0.1847843677, -0.5252919793, -0.1499496102, -0.6333470345, 0.5339637995, -0.0101217143, 1.5284255743, + 1.4889923334, 2.0363731384, 0.2519434094, 1.1972477436, 0.1169527769, 1.0913250446, -0.7577394247, -2.2312619686, + 2.0685327053, 0.9227512479, -0.44381392, -0.7689087391, 0.501401186, -0.0705506951, 0.8355823159, 1.4453328848, + -1.801222682, 1.9324140549, -0.3285877109, 0.348564446, -1.0819559097, -1.6279023886, 0.325080812, -2.0706045628, + 0.3532761335, 0.1403892487, -0.1772062927, -1.8101980686, 0.4101774693, -0.0899073407, 1.7163796425, -1.1482729912, + -0.9280102253, -0.9309043288, 0.7067950368, -1.5563870668, 0.7764381766, 0.4183218181, -0.5949311256, -0.5479576588, + -0.3660928607, 0.1221372858, -0.8077557683, -0.7920037508, 2.3722608089, -1.5027210712, 0.014445019, 0.1528333724, + 0.7655932903, 0.4014534056, -2.3351640701, 0.4352296889, 0.4105211794, 0.6907932162, -0.9530596733, -0.6473321915, + -1.4276818037, -0.2839665115, -0.6459219456, 1.0340801477, 1.1909698248, 0.4201194346, 2.0286815166, 1.7382160425, + 1.2285472155, 0.3203367889, -0.1061791256, -0.0371501744, 0.1596977413, 2.924721241, 0.4545726478, 0.1455145329, + 1.137650013, -0.6597639322, -0.7237402797, 1.7943882942, -1.0624425411, 1.0409113169, 0.7168018818, -0.7416293025, + 1.651642561, -1.2652876377, 1.5150113106, -0.4677824974, 0.3317876756, -0.1702616215, 1.0125669241, 0.617475152, + 0.0796523988, -0.3447691798, -0.8938841224, -0.2084598839, -1.6965242624, -0.34709692, -0.5429576635, -1.2105997801, + -0.8608617783, -0.9803560376, -1.0367319584, -0.2582563162, -0.0054417914, -0.9185775518, 0.0305522084, -1.5969980955, + 1.0509661436, 0.4743795395, 0.3633412123, 2.1253325939, 0.270102948, 0.7550885081, -1.0644488335, -0.6703055501, + 0.5664753318, 0.2437788546, 0.9583575726, -0.763813138, -0.0029742755, -1.6142610312, -2.2065219879, -0.63289994, + -1.1739649773, -0.1321678013, 0.4885062575, 1.379265666, 0.968249023, 0.0666629449, -1.4227808714, 0.9389460683, + 0.6142101288, 0.4952200651, -0.356030941, -0.4492895603, 0.887373805, 0.4932395518, -1.5655148029, -1.1107832193, + 1.0344661474, -0.6064270735, 2.0916547775, 0.8920361996, -0.9328433275, -0.5210302472, -1.3629417419, 0.6946575642, + 1.2764936686, -1.5056940317, 0.1522615552, 0.5383676291, -1.5878702402, -0.4938810766, 0.8755227327, 0.9683454633, + -1.1522424221, -0.0225333683, 0.9137845039, -0.5549679995, -0.7432829738, 0.5882457495, 1.3948264122, -0.5563979149, + -1.2109256983, 0.6127566695, 0.7170585394, -0.9698428512, -0.0640512407, 0.9629530907, -0.6542029381, -0.4348601699, + 1.3914189339, 0.0691725537, -0.763974607, -1.0185455084, -0.6848862767, -0.8079086542, 1.0332250595, 2.0122599602, + 0.2306910008, -0.135491699, 0.6538707018, -0.5724883676, -1.4610589743, -1.1935203075, 0.2267056406, -0.8769122958, + -1.8110815287, -0.0701249689, -2.1590735912, -1.7739510536, 0.74104321, 1.1597032547, 1.0969405174, 1.9822311401, + 1.7125688791, 0.4174836278, 0.7853913903, 0.5818963051, -0.2479056716, -0.7231642604, -1.0702124834, -0.3364195526, + -0.1131938845, 1.1898450851, 0.3929497898, -0.990489006, 1.3256819248, -1.4747922421, 0.8332212567, -0.375176698, + -0.5573330522, 1.6865506172, 0.4411950111, -0.1255817413, 2.5350151062, -0.0580064729, -1.1477249861, -0.9363329411, + 1.0586061478, 1.639262557, -0.5135805011, 0.5801268816, -0.0548072122, -0.9464817643, 0.0946878791, -0.7109422088, + -0.3775828481, 0.6923879981, -0.1164232716, -0.0274552815, 0.9514126182, -0.438290894, -1.1965507269, 1.2529064417, + 0.2980563641, 1.3691887856, -0.0335965566, -0.5210404396, -0.0635088459, -0.6337655187, 0.4338080585, 0.0755116045, + 1.0962269306, -2.0093507767, -2.480451107, -0.4190257192, -1.1947860718, 0.7652868032, 0.1273288131, 0.8648121953, + 0.1008700207, -2.7048275471, -0.951045692, -1.4726403952, 0.0437071584, 0.0826288909, 2.010822773, -0.687650919, + 1.0703777075, 0.3906943798, 0.5436729193, 0.9461514354, 0.4150171578, -1.2524062395, 0.3780267239, 0.4788390398, + 0.1191774979, -0.2176552713, 0.6323692799, 1.2053620815, -2.3339111805, -0.6712306142, -0.2902439833, 0.9778840542, + -1.2306065559, 0.6382020712, 1.4408342838, -1.4152365923, 0.7717177272, 1.0857385397, -0.0721675083, 1.7905182838, + 0.2215190679, 0.346685499, 0.4562369287, 0.5969560742, 2.9985487461, -1.3164579868, -0.3309495449, -0.1202616245, + -1.3430130482, -0.3943373263, -0.2237624377, -1.012237668, 1.0934064388, 2.1965367794, -0.9623855948, 0.4112857878, + -0.7151125669, -0.286927551, 0.2724553049, -0.4762646854, -0.4325575829, 0.6262726784, -0.8784438968, -1.595249176, + -1.9096953869, 0.3377545774, -0.7852398157, -1.2339268923, -0.6910353899, -0.6821838617, -0.4460454285, 2.0578155518, + -0.8237828016, -1.160384059, 0.4606530964, 0.7554635406, -0.4197842777, -1.7064237595, -0.4686983824, -0.8817868829, + 0.2867316008, 1.2538535595, -0.1737776101, -0.2247789651, -1.5630481243, 0.4511615634, 0.6216961145, 0.0750527158, + 0.3924145699, -0.375416398, 2.8608353138, 1.5530757904, 0.0425318517, -0.1855948865, 1.3114998341, -1.9979593754, + -0.1392807513, -0.5736815333, -1.1196737289, -1.2200103998, -1.2405149937, 1.6866083145, -0.1392551512, 1.4387949705, + -1.4744572639, -0.1115004197, -0.1053058803, 1.5830054283, 0.5361398458, -1.1185491085, 0.1301326603, -0.1323783994, + -0.6407990456, -0.4196328819, -1.3846974373, 1.3309514523, -2.7046353817, 0.004547718, 0.8607456088, -1.1245253086, + 1.227412343, 1.0389893055, -1.9995344877, 0.8867872953, -0.7012874484, 0.438578099, -2.4129841328, -1.8402497768, + -1.1964808702, -1.0597640276, -0.4711083174, 0.9958802462, -0.7689711452, 0.436309427, -0.3747068644, -0.8480607271, + 1.2542796135, 0.2656555772, 2.2228662968, -1.8119665384, -0.9371265769, -1.4262866974, 0.1876880974, -1.0126883984, + -2.070070982, -0.080323346, -0.7962924242, -0.0414651409, 1.7242867947, 1.1771477461, -0.8121748567, -0.1645865291, + 0.9184431434, -1.0123202801, -0.3763069212, -0.1460562795, 0.2211588472, 1.1201910973, -0.019115096, 0.7085775733, + 1.4897265434, -0.0689364448, 2.1542754173, 0.499679774, -0.4819819331, -1.2270764112, 0.9048069715, 1.1497319937, + 0.1581166685, 0.983577311, 0.824744463, 0.0351414941, -1.9824454784, 0.2739833295, 1.2348875999, 0.7725579739, + 0.2573614717, 0.5969483852, 0.2761405706, -1.0226633549, 1.7934087515, 0.1439145803, 0.9556096196, 1.9798411131, + 1.5616306067, 0.4073262513, 0.8567109704, -0.5908481479, -0.4551822841, -0.6076927781, 3.1823654175, -0.2167487592, + 0.238218233, -0.1999024898, 1.5419658422, 0.5953208208, -0.5438700318, -1.2184040546, 1.0318024158, -0.3316418827, + -0.8802697659, -0.894713521, -0.0105047869, -3.3704369068, 0.4810324013, -1.9140502214, 0.39502123, 1.6429020166, + 0.8465449214, 0.4476325512, 0.4394526482, 0.6456232071, -0.1141211912, 0.3965323269, 0.4823193252, 1.1300865412, + -0.1235338151, -0.548838973, 0.564556241, 0.2612779737, 0.3265740275, 0.693601191, -0.2548986077, 1.5862183571, + -0.9947738051, 0.7125069499, -0.2931319177, 1.1054304838, 2.4689922333, 0.8357470036, 0.0130731547, 1.4690824747, + 1.7760980129, 1.712302804, 0.7116003633, 0.0806625262, -1.2783840895, -1.2734508514, -0.568164587, -0.6348869205, + 0.4688507617, 0.6399840117, -0.15463458, 0.0401923917, -0.4833675027, 0.7989139557, -0.5271605849, 2.2883720398, + 0.9557285309, -2.1976850033, -0.9270659089, -0.7950120568, -0.0018317529, 0.1464039981, -1.2294088602, 1.3516594172, + 0.9153459668, -1.5380679369, -0.8945394158, 0.4787234664, -2.2154150009, 0.4985513687, -0.3055807352, 0.3027708232, + 0.7394517064, -1.1887978315, -0.8729275465, 0.013680906, 0.2144620121, 0.1222232655, 2.0651092529, -1.3659356833, + -0.6718088388, -0.3926681578, 1.7661414146, 1.9525667429, 0.5477364659, 0.4586538374, -1.699947834, -0.9211118221, + -0.7009931207, -1.2132214308, 0.178910166, 0.1699265093, -0.579100728, -1.1458439827, 1.6576943398, -0.0798066929, + -0.5319992304, 1.1932622194, 1.2408850193, -0.9731871486, -1.6201738119, -0.44934389, -0.4226911962, -0.0897471532, + 0.7771114111, 1.4575105906, -1.3590695858, -0.2422187775, -0.0717459098, -1.5813609362, 0.3929780126, -0.6107853055, + 1.0224369764, 0.9272652268, 0.2391461581, -0.7454996109, 2.5418419838, -0.0836168155, 0.0664021298, -2.0217483044, + 0.0662804097, 0.8211984634, -0.5589304566, 0.2068057358, 0.06401667, 0.9859380722, -0.9006294012, 0.8219537735, + 0.138582617, 0.9545242786, -0.0526152104, 0.2759426534, 1.2005162239, -1.294139266, -1.358828187, 0.0705319345, + 0.719197154, 0.9778149724, -0.8361923099, -0.0056291926, 2.0522983074, 1.5833069086, -2.3987114429, 1.3274357319, + 0.0064704483, -0.6484159827, 0.9853000641, -1.3528258801, 0.9159484506, 0.2959030271, 1.7370500565, 1.2756021023, + -0.0047396058, -0.2977020144, -1.0068558455, 0.3262749016, -0.2303540409, 0.2995219529, -0.3161655068, 0.0587377883, + 2.1757032871, 0.7780051231, -0.6155528426, -0.6651592255, -1.9044895172, 1.0170710087, -0.2350578159, 0.8182260394, + -0.8092999458, 1.7549093962, 1.1859247684, 1.2325001955, -0.4970070422, -1.8003635406, 0.0549518168, -0.8563482165, + 1.9319586754, 1.1410189867, 1.4234589338, 1.0574718714, -0.3678317964, -0.6011454463, 0.9331198335, 0.4304300845, + 0.9622161388, 0.7820424438, 0.5289376378, -0.1422957182, -0.0972463861, -1.1529253721, -0.3259295225, -0.7833554745, + 1.3779989481, -0.8609403372, -0.1602535546, -0.0599776134, -1.4946795702, 0.2707850337, -0.5179989338, 0.8004550338, + -1.2054712772, 0.5004020333, -1.8651032448, 0.5174418092, -0.9989871979, 0.3034828305, 0.3723188043, 0.359762162, + 1.8270949125, 0.4796812832, -1.3419852257, -1.7499210835, -0.130830422, -0.8859434128, -0.416988045, 0.1174671724, + -2.3178379536, -1.3677680492, 0.3057938218, 0.4547121227, -0.3513031304, -0.2731293142, 0.0115191638, -1.1899770498, + -0.7389093637, 1.1789582968, -0.8494232297, 1.5048207045, -1.4718470573, 0.0784921274, -0.8367189169, -0.7885698676, + -1.6579880714, -0.3294337988, -2.630007267, -0.4856718183, -0.2715861797, 0.2706677616, 0.3428797126, -1.0286426544, + -0.4359491169, -0.8634329438, 1.7400062084, -0.6620771289, -0.8842269182, -2.4243388176, -1.9477770329, -0.2599925101, + 1.3951880932, 1.745451808, -0.835365057, 0.9496917725, -1.1362177134, 2.7656846046, -0.3285786211, 0.1080850959, + -0.3550520241, 0.5351243019, 0.0626995116, -0.9387552142, -0.343501389, 0.7270622849, 0.6199610233, -1.6607036591, + -0.6297575235, 0.7958660126, 0.2775168121, 0.1991933733, 1.5361841917, 0.067286931, 0.3522060812, -0.6162402034, + -1.731529355, -0.0968044847, 1.3629524708, 0.0375886112, -1.257828474, 0.4546712935, -2.2027161121, -0.7068659067, + 0.1386501193, -0.5204744935, 0.8022690415, 0.1464944929, -1.07315135, -0.0275365952, 0.3999854028, 0.6108346581, + 0.7355435491, 1.8661667109, 0.4773959816, -1.0730679035, 0.8396475315, 1.1034216881, -0.5024297237, 0.7762069702, + -0.0361183025, 0.6873787045, -1.626504302, 0.0699692369, 0.3768470585, -0.932276845, 0.0477588251, 0.9751135707, + -1.9907674789, 0.119563058, 0.3530760705, 0.3995818198, 1.1568886042, -1.2285298109, -0.2479773462, -0.0089573311, + 0.7797752023, 0.3299199641, 0.9332191348, -0.403470695, -0.311145246, -0.4305924177, 1.3256598711, 1.1262835264, + 1.1973778009, 0.1951432228, 0.2563470602, -0.2257311791, -1.058175683, 0.5406070352, 1.2327010632, 0.3645146191, + -0.94389081, -0.5273874998, -0.0965472907, -0.7064593434, 1.3101346493, -0.624376297, 0.5321087837, 0.8991381526, + -0.0843996927, -0.9281385541, -0.0536656491, 1.8132817745, -0.6429740191, 0.2113274634, -0.2402074486, 1.0136674643, + 0.3831409812, -1.0056535006, 0.6262342334, -0.0874363706, 1.3416323662, -0.4109298885, -0.014123667, -0.741165638, + 2.0815262794, -0.7702627182, -0.3985530734, -0.6752582788, -0.9599013925, -0.3416412175, -1.3532416821, 1.8661503792, + 0.130930379, 0.1339515895, -0.5823944807, 1.7389822006, 1.0031000376, -1.0844048262, -0.4892614186, 0.5706951022, + 0.7267456055, -1.5972158909, -1.3844085932, 0.1251437813, -0.1611333787, 1.2971414328, -0.4890547395, -0.2959007025, + -0.2359022498, -1.5221960545, 1.6418451071, 1.8629655838, -0.6008669734, -0.6448215842, -0.6749278307, -0.2803279161, + 2.2114477158, -0.2965689003, -0.3168765903, 1.3606915474, -0.1464030147, -1.2688233852, -0.8596234918, -0.2300802022, + -1.5350259542, -1.1681234837, 0.053282775, -0.6676311493, 1.1589723825, -0.2325885743, -0.1550059468, 1.2478905916, + 0.2482963949, 1.3774282932, -0.8201007247, 0.730791688, 0.3846693635, -1.3935933113, -0.5091059208, 0.187603876, + 1.2699453831, 0.0560138673, 0.8535129428, 0.5293108225, -1.3195542097, -0.3675530255, -0.5306439996, -1.362891078, + 0.4709477127, -0.4559128284, -0.2349215001, -0.9671003222, -1.4965330362, 0.3901738822, 1.034022212, -0.1132831424, + -0.8353191614, -0.2977720499, 0.4513333738, 0.8387823701, 1.0269012451, 0.7130354643, -0.3210241795, 0.6128639579, + 1.6848592758, 1.6609615088, -0.0710362568, -0.4100494087, -1.212777853, 0.8047491312, -1.7605817318, 2.9120903015, + 0.9917885065, -0.5696196556, 1.1640443802, -0.3759628832, 0.534863174, 0.8605149984, -0.432228893, -0.8272349834, + 0.897344768, -0.9950327277, -0.0557409078, 1.0292906761, 1.1893057823, -0.2426627278, -0.4762936532, -0.3401097953, + 1.956079483, -0.9409772754, -0.149242714, -1.4113221169, -1.7686339617, 1.7728070021, 1.4844536781, -0.6800952554, + 0.8788170815, 0.8911567926, 1.2230223417, -0.8783909678, -2.2849061489, -0.5757948756, 0.9280388951, -0.759596765, + 0.058739461, -0.1624921113, -0.2155980915, 0.2433040589, 0.0557866134, -1.1757665873, -0.1818657964, -0.2644596994, + -0.9477189779, -0.984495461, -1.338796854, -0.0450486951, -0.6944232583, -1.0707694292, -0.784297049, 0.6350764632, + -0.7319315672, -1.6097750664, -0.4874561727, -1.2056317329, -0.3934192061, -0.9384541512, -1.2435036898, 0.7331660986, + -0.1061901152, -0.2536563277, -0.4899016917, 0.2329620421, -0.898645103, 0.293543756, -0.6980230212, -1.5478031635, + -0.6342258453, 1.7035830021, 0.1028883606, -0.7894119024, -0.1351793706, 0.5689413548, -1.0633289814, -0.0086180344, + 1.7042182684, -0.6117020249, 1.2448474169, -0.6777845025, -0.2346623689, -1.9456766844, -0.0306932554, 2.1096534729, + -2.2844188213, 0.0728366897, 1.2431104183, -0.5718863606, -1.0966272354, -0.9830226898, 0.433262676, -0.6825378537, + 0.857529819, 1.3153325319, 1.9670081139, -1.3972771168, -0.1857836246, 0.1219161525, -0.5779262781, 0.6101424098, + 0.2377535701, 0.2397469133, 0.2591325343, -2.0442194939, -0.6908274889, 0.2541438639, 1.820902586, -0.7531303763, + 0.8614359498, 1.5990792513, 0.8102792501, -0.6263534427, 0.0995728076, 0.2731429636, 0.728279233, 0.0114688184, + -0.4514726102, 0.4547981322, -1.7314876318, 0.9617160559, 0.2156383395, 2.5990610123, -0.8828431368, -0.1147982627, + 0.1282157302, 0.4696044922, -0.5134382844, -1.5148773193, 1.6586340666, -1.0218036175, -0.0250433777, -0.2382687032, + 0.2340601683, -0.7567276955, -0.3305819333, -0.3038704395, 0.8338783383, 0.1608898491, 0.439627111, -1.8737742901, + 1.3429384232, -1.3435566425, 1.1009212732, 2.058298111, -0.940050602, 0.7694303989, 1.4895060062, 1.1229710579, + -0.4763310552, -1.1265016794, 0.4342498481, -1.0764023066, 0.1756174266, 0.2279533893, 0.4279670715, 0.2260316908, + -0.9843562841, 0.6740505695, -0.8490674496, -0.3237790465, -0.4662958682, 0.1734868139, -1.4428119659, 0.6804466844, + -1.0618598461, -0.7360239625, -1.2143082619, 0.4160400033, -1.0800274611, 0.3315010965, -2.1402599812, 1.2378108501, + -0.7899955511, -0.104110159, 2.0045559406, -0.4333100617, -0.4725388587, 0.1273653358, 1.4571205378, 1.3495620489, + 0.5959379077, 0.2545638978, 0.3057740331, -1.0019536018, 0.5784690976, 0.2518575788, 0.6918970942, 1.5384705067, + -0.2609039545, -0.2850797176, 1.3235375881, 1.1674975157, -1.4240127802, 0.6997848153, -0.815402627, -0.3378392756, + -1.8234149218, 0.6829866767, -1.2062163353, 1.6120146513, -0.7018817663, -2.2123842239, 0.8546330333, -0.4547747076, + -0.3642478585, -0.3706068397, -0.2988089323, 0.6899989843, -0.6115986109, 1.259567976, 0.2240811884, 2.6741890907, + -0.5876898766, 1.5658192635, 0.6845703125, 1.0701469183, -0.3652437329, -0.2096356004, 0.3791528642, 1.5315600634, + -0.1469570398, -1.56741786, 0.7937241197, -1.5094797611, -0.4463437796, -0.4219004214, -0.3260750473, 0.3198117614, + -0.9380064011, -1.2634960413, 1.2424186468, 1.466078639, -0.4180395603, 0.1620767266, -0.2839062512, 1.7759104967, + -0.8857923746, -0.5912535787, -0.5251594782, 0.3382563591, -1.5086387396, -0.3405946791, -1.8012282848, -0.0873163119, + -0.584220469, 1.2199001312, -1.4205188751, -0.296826303, -1.3448718786, 0.6785737872, 0.7722478509, -0.227252081, + 0.0527814403, 0.9790414572, -1.3844666481, -0.7844890356, -0.7075823545, -0.3223336637, 1.5800389051, -1.0154743195, + 0.392526418, 0.5471366644, 0.2460810691, 0.1381963342, -1.389493227, 1.9471534491, -1.5014412403, -1.041323185, + 0.3324744999, -1.687340498, -0.2129056156, 1.4749987125, -1.4523178339, -3.1190896034, -1.2718390226, 2.4424221516, + 0.995033741, -0.0496420674, 0.9837993979, 1.9826014042, 0.7137126327, 0.3330027759, 0.0999203622, -1.2657548189, + -0.486943841, 0.9282532334, 1.119882822, -0.368578285, -0.369115442, 0.2586824596, 0.4915171266, -1.1458977461, + 0.8304197788, -0.2539549768, -0.1996763498, -0.5544936657, -0.0025407872, 0.14073053, 0.4582334757, -0.4711025953, + -0.2920936346, 0.6538417339, 1.5560307503, 1.7619452477, 1.2360332012, -0.1315362304, 0.0920973346, -1.4905031919, + 1.2301188707, -0.4421279728, -0.6929170489, -0.7973194718, 0.0634542629, -1.2857584953, 0.0631699786, -0.0861530378, + 0.2839331925, 1.2970875502, 0.293333441, -2.3788189888, -0.6523681879, -0.030558167, -1.1570004225, -0.7451606989, + -1.381660223, -1.4926953316, 1.2165389061, 0.4167850018, -1.408052206, -1.4262783527, 1.2082084417, 0.6638391018, + -0.7060305476, 1.1353538036, 1.3180701733, 0.8578649163, -0.8731014729, -0.98295784, -0.5651094913, 0.6818859577, + -0.6653128862, -1.0673677921, 0.893332541, 1.2560358047, -1.1704576015, 1.429646492, 0.6040555239, -1.8464752436, + 1.3270595074, 0.1488941312, 1.6056982279, 0.501744628, -0.8903104663, 0.1706050634, 0.8819519281, -0.0030436872, + 1.6358895302, -1.279794693, 1.2676116228, 0.1627141535, 0.7670778036, 1.4692165852, 0.0669638589, -0.3648871481, + 0.4743653536, 1.0513372421, -1.1020389795, 0.7753785253, 1.0108804703, 1.0408326387, -0.5209835172, 0.6818500757, + 0.0904824138, 1.0239518881, 0.6365932822, 0.4699539542, -0.7060739398, -1.0360990763, -0.4540962279, -1.332698822, + -0.5124089122, 1.0929511786, 0.5940018296, -0.4353291094, 1.6788744926, 0.7090277076, 0.6970493793, 0.6935103536, + -1.5174489021, -0.6674986482, 0.3959916234, 0.0314268805, 1.186727047, 0.1292989403, 0.2488492429, -0.2043378651, + -1.3287620544, -0.7390286326, 0.8793639541, 0.5443399549, 0.4859343767, 1.2453608513, -0.3818763494, -1.6809335947, + -0.3598356843, -1.3391313553, 0.6595156789, 0.0735542253, -0.0190615188, 0.3803745508, 1.8210678101, -0.0958271772, + 1.841132164, -1.3670797348, 0.5427723527, -0.7703274488, -0.6727721691, 2.0768125057, -0.8670269847, -1.2214968204, + 1.0898650885, -0.0725031719, -0.0864036158, -0.4280133247, 0.4899945259, -1.1253395081, 2.076363802, 0.1353816539, + 1.4642211199, -1.5274518728, 0.9599250555, -0.7167305946, -0.146045506, -1.6847262383, 0.4852546155, -0.29239887, + -0.4610815942, 1.1864080429, -0.3434349298, -1.2183084488, -0.4544598758, 1.3759692907, -1.170229435, -0.8205097318, + 0.0596311018, 0.2823673487, -2.4523892403, 0.1126904637, 0.4746390879, -1.6707005501, -0.9480802417, -0.1634900272, + -0.4575511217, 0.6539748311, 1.3743329048, -0.2066034228, 1.9918875694, 0.0467024818, -0.5654628277, 0.5026557446, + 0.7354540229, -0.2884488404, -1.1007701159, 0.3083924353, 1.0963255167, 0.1424771547, -0.1030726954, 0.8625275493, + -0.7215863466, -0.9913249612, 0.6632069349, 0.4783222377, 0.3580340743, -0.1725240052, -0.6392794847, 0.2011111081, + -1.6484777927, -1.0174485445, -0.087234959, 1.1921215057, 0.5025959015, 0.2836691439, 0.8681715727, 0.3389258087, + 0.5296366215, 0.6545069814, -1.94619596, 0.5430054665, 0.5104394555, -0.7187666893, 0.4541369677, 0.9566402435, + -0.0594963208, 1.6902428865, 0.8972370028, 0.2773114443, -0.4134947062, -1.2408342361, 0.4204489291, -0.451628685, + -0.2110308409, 1.0829126835, -0.9779353142, 1.0323063135, -1.2429711819, 0.6037898064, -0.3205806017, -1.2381771803, + -0.3923279941, -0.0805774033, 0.4635975063, -0.2898182571, -0.2014379799, -1.4034485817, 1.1136484146, 0.0691273436, + 0.2618164718, -1.8693686724, -1.2310501337, -2.6746325493, -0.6870961785, 0.4724680781, -1.701328516, 0.7355017066, + -0.274130851, 2.2835941315, 0.7250497937, 0.7654329538, -0.5647279024, 0.1644261926, 0.5307115316, 0.574646771, + 1.9586399794, -0.5265694857, -0.4879961312, -1.4865173101, -1.1455962658, -0.4128835797, 0.6693022847, -1.5804158449, + 1.2603547573, 0.7857226729, 1.2067354918, 0.4648757875, 0.9003841877, 0.5806150436, -1.78802073, 0.5372216702, + 0.7575263977, -0.5589818954, -1.0746775866, -0.0021043734, -1.6893839836, 1.7304996252, -1.1568057537, -0.0617405735, + 1.0687190294, 0.5711197853, -0.4428283572, 0.155281648, 0.2527465224, -1.1368750334, -0.5381591916, 1.5881439447, + 0.2860608101, 0.3805446029, -1.66726017, 0.7602344155, 0.4308459461, -0.5576328635, 1.4369031191, 0.5004381537, + 0.6119653583, 0.7021585107, 0.3857577443, -0.7897416353, -0.6196731329, 1.0033321381, 0.5967955589, 0.6828916669, + -1.199436307, -0.9904943109, -0.3934526742, -0.473213613, 0.2426480353, -2.042548418, 0.8007996678, 0.5071797967, + 1.5479482412, -1.9100352526, -0.9601728916, 0.9510821104, -0.0823726431, 1.3400896788, 0.0834527016, 0.6438699961, + -0.9652031064, -0.485462755, 0.1482844353, -0.9956216216, -0.3950155675, -1.4705321789, -0.6609185338, -1.8514585495, + 0.1311995983, 1.6940715313, -0.133731693, 0.5798290968, -0.2847125828, 0.3875262141, -0.0368419625, -0.2958053052, + -0.2373793572, 0.3187682629, -1.4628130198, 1.7015430927, 0.3156693578, -0.07037168, -1.4071842432, -0.5739857554, + -0.6005715132, 0.0037154576, 0.3062636256, 1.849894762, 1.418845892, 1.4881933928, -0.9052850604, -0.126431033, + 0.3862965405, -0.8140952587, -0.3810549974, 0.6935589314, 0.2257216722, 1.0393418074, -0.1589675099, -0.157435894, + -0.8825321794, -0.1856806725, -1.1158484221, 0.0572987758, -1.77087152, -0.1011177674, 0.7603165507, -0.8440169096, + -0.2493463904, 1.7614215612, -1.5872883797, -0.1093700677, -1.3668683767, 0.0597839355, -0.404158026, 2.0201151371, + -0.8874104619, 1.008955121, 1.1857368946, 0.8527296185, -1.5749006271, 0.4625138044, 0.0153149329, 1.2475622892, + -0.180116415, -0.1654497087, 0.2987264693, -0.0666087642, -0.5388320088, 0.5844370723, -1.0518535376, 1.175871253, + 2.0751616955, 0.0651127324, 1.0435625315, 1.2183630466, -1.1029225588, -0.3894551992, 0.453733027, 2.0570921898, + -0.6587897539, 0.7516878843, -0.3802327514, 0.6569559574, 0.3319684267, -0.7577400804, -0.6714701653, 0.6479204297, + -0.0799216107, 0.8066828251, 0.1515915394, 0.4205271602, -1.3345781565, 1.2583372593, -1.6809546947, 2.859858036, + 0.6408307552, 1.4548523426, -2.0656576157, 0.9247038364, 0.1503020823, 1.2612864971, 0.1509641409, 0.4554774463, + -0.3452061713, 0.7462652922, -0.107367374, 0.9654961824, -0.1182610542, 0.4436274767, -0.989236176, -0.7423120737, + 0.0164196324, 1.1263713837, -0.9633116126, 2.3793332577, 0.0003982415, 1.7510664463, 1.4233546257, -1.73952353, + 0.7623349428, 0.3986560702, -0.3507902622, -0.9979709983, -0.2359415144, 0.1348109394, 0.1125656813, -0.6708725691, + 0.3356072605, -1.2268385887, -0.115557462, 1.5565766096, 0.4939498603, -1.1511844397, -0.2640740573, 1.2304129601, + -0.6129906774, 1.4380507469, 0.5469411612, -0.2832261324, -1.2993297577, 0.9013664722, 0.2450891584, -1.584012866, + -0.9167362452, -0.8300950527, 0.1757986993, -1.6784344912, 0.0636152625, -0.4752668142, 1.0027318001, -0.4386060238, + 0.4709543586, 0.2046563327, 0.7120774984, -1.0557335615, -0.1954088658, -0.3462091386, -1.493064642, -0.1731721908, + -0.0131932432, 0.1934194416, 0.6658257246, 0.6255763173, 0.7684777379, -0.294593662, -0.6855698228, 1.6016274691, + 0.4373116791, 0.2726550102, 0.8263636231, 0.829115212, -0.3335766494, -0.8821152449, -0.2419444174, 0.3788249791, + 0.771073699, 0.1886449307, -0.7076955438, 1.0469366312, -0.1463537216, 2.6089265347, -0.6633446217, -0.2353220284, + -0.2212995142, -0.7482500672, -0.2117432356, -0.648286283, 1.7328232527, 0.2244552821, -0.6652676463, 0.396427989, + 0.5592606664, -1.963783145, -1.8922384977, -2.4780626297, -0.1493539512, -1.4736962318, -0.5816019773, 0.9401268959, + -1.4714045525, -1.1942760944, 0.3668976128, 0.0830259994, -0.8098945618, -0.2031483948, 0.7353839874, 0.0058557466, + 0.1347817332, -1.1094521284, 0.202830866, 0.2542048991, -1.1559451818, 0.2734256089, 0.204160288, 0.7460332513, + -0.0899389461, -0.215478763, -0.2122800201, 0.9198871851, 1.8418318033, -1.5593268871, 0.2610054612, -0.7024561763, + 1.7462798357, 1.498622179, -0.8376168609, 1.0504339933, 1.7258865833, -1.9487813711, 1.1911542416, 0.2755780518, + -0.2877275944, -0.9894776344, -0.3523977399, 0.3716616035, 0.7340951562, 0.0465161428, 2.0946755409, -0.4287497699, + 1.2823368311, -0.1708106399, -0.3339754343, -0.3745219409, 0.0234510638, -0.5941810608, -0.6525736451, 1.0548883677, + 0.2085448205, 2.1524362564, -0.2876541615, -0.8876055479, 1.3150926828, 0.5178136826, 1.6735327244, 0.2665548027, + -1.426508069, -0.4362727702, -0.3537387848, -0.4326723218, -0.2196337879, 0.1769788712, -0.501675427, -1.9468058348, + -0.8031057119, 0.8652901649, -0.1611579061, 0.2561255395, 1.760627389, -2.100194931, -1.3642786741, -0.2298175246, + 0.2183056921, -1.8855527639, -0.4925869107, -0.2614548802, -0.8557839394, -0.1850143373, 1.1688899994, -0.621556282, + -0.7275066376, -0.3990510404, -0.0416359417, -1.7970087528, 2.5328645706, 0.2876232266, -0.967880547, -1.0853585005, + 2.2810258865, 0.5573899746, 0.7743658423, 0.681432128, 0.8439531326, 0.8247879148, -1.6703401804, -0.6495918632, + -0.5389128923, -1.3334633112, 0.5207111835, 0.6436123848, -0.6462132931, 0.3580046296, 1.6225868464, -0.4871959984, + 0.6803805232, -0.210057959, 0.1405427754, -0.5697072148, 2.1073331833, -0.9879789948, -0.5540517569, 1.3131885529, + -0.5549680591, 2.8242397308, -0.5965105891, 1.5914705992, 1.4811695814, 0.3065227866, -1.2098796368, 0.0168109611, + -0.1309269071, -1.2207504511, 0.6678852439, -2.1338050365, -0.6641706824, -0.3057371974, -0.0899235457, 0.1791422814, + 0.8580896258, -0.8787598014, 0.4738532007, 0.6654763222, -0.8824122548, -1.6115596294, 0.527980268, 0.0964465886, + 0.9635578394, -0.3902786672, -0.3802396059, -2.2409791946, -1.0808991194, -0.7525261045, 0.2250808775, -0.3743494749, + -0.1169842705, 0.061400637, -0.3293505013, 0.30971241, -0.799598515, 1.8154002428, -1.5777002573, -0.5507161617, + 0.6225386262, -0.3113619685, -0.9763633013, 1.4898904562, 0.9300459027, -0.5811542869, 1.2458498478, -0.2211971879, + -1.593437314, 0.0132478783, 0.9656499028, -0.1373882741, -0.0728489086, -0.5899522305, 0.1944191307, 0.4169383943, + 0.2829756737, 0.1644549668, -2.183242321, 0.6266455054, -0.5795871019, -0.9039760232, -1.7385983467, 0.2067382336, + -0.2576915324, -0.4712277055, -0.5019993186, 0.1468517184, -0.9671674371, 0.0666483492, 0.9021647573, -0.895858109, + 0.8980016708, -0.1871165037, -1.4828082323, -0.5323514938, 0.0343699008, -0.0326057225, -0.0458269492, -2.2640006542, + -0.2263824195, -0.0426686592, -1.0875192881, -0.0749526247, -0.1680147648, -1.7522611618, -1.0544925928, 0.532954812, + -0.4137636125, 1.4957363605, -1.1262655258, -0.9431248903, 1.1091076136, 0.3187142015, -0.4425956309, 1.912950635, + 0.1657711565, -0.1740225405, 1.1547033787, -0.4135216177, 0.0847586095, 0.6157559752, -0.2677897513, 1.056235671, + -0.4857402742, -1.3100956678, 1.5738106966, 0.3299025297, -1.1636645794, -0.5389083624, 0.3641978502, 1.1415319443, + 0.3955402672, 0.1479743123, -1.5591546297, -0.2825756967, 0.9462650418, -0.6458616853, -1.2211798429, -0.6016332507, + 0.7985215187, 1.0275365114, -0.0160687435, 0.4915259778, 0.1202829033, 1.1910266876, 1.351093173, 0.9124286175, + -1.5193203688, -2.6604340076, 1.6008164883, 0.106880866, -1.2210118771, 0.88221699, 1.0649386644, -1.458954215, + -0.7992488742, -0.1713563204, 0.4389387369, -0.2636434436, -1.6290132999, 1.1303752661, 0.1080426127, 0.8657753468, + -0.9457086325, -0.5738193393, 1.2187113762, -0.5768360496, -0.8167025447, 1.2510757446, 0.3992554247, 0.2217383087, + -0.6826551557, 1.1338157654, -1.2801879644, 0.955354929, 0.2114500254, -1.3725106716, 2.0755689144, 0.392516911, + -0.4047083855, 0.5372302532, -1.0917904377, 0.1228743196, 0.1735812575, 1.3295997381, -0.9710007906, -0.0175675768, + 0.6346111894, 0.5424829125, 0.4861537218, -0.5748277903, -0.4538476467, -0.6988639235, 0.3595512807, -0.3014974296, + 0.4904040098, -0.4762947261, -0.2976291776, 0.2722819448, 1.8400909901, 1.111210227, 0.3468321562, -0.7620072961, + 0.4823642671, -0.0431677178, -1.1301577091, 0.7625041604, 1.0072216988, -0.739777565, 1.2135487795, 0.434827894, + 0.2891020775, -0.2582736611, -0.4398835003, -1.1159187555, -0.4120377302, -0.3862161338, -1.0398606062, 0.5330690145, + 0.0991028398, -0.312397927, 1.4060606956, -0.2284294963, -0.285689652, -0.3457508683, -1.8428200483, 0.7488943934, + 0.1384963244, -0.2578194737, -0.1127146631, 1.1032286882, 0.559040308, -0.1274744719, 1.1027128696, -0.374514997, + 1.4169546366, 1.0180193186, 0.3566385806, -0.2235454619, -0.9186764956, -1.806368947, 0.6170316935, 0.8247284293, + 0.1426244229, 0.1843836755, -1.2132909298, -0.3551035225, -1.0385468006, -1.094614625, -0.6682890058, 0.0346868075, + 0.7390833497, 0.6645213962, -0.6030436158, -0.5423620343, 0.4705986083, -1.2859250307, -0.0684260353, -0.3965751231, + 0.0891710445, 1.4725625515, -0.5956141353, 0.2861987054, 0.1781372875, -0.1194024906, -0.2217310071, 0.9313843846, + -0.6242418885, -0.0836989135, -1.6565767527, 0.7462492585, -0.2159588784, 0.2116937339, -0.2267422825, -2.0483932495, + -0.0378425568, 0.7382618189, -0.8901466131, -0.163621977, 0.1239845902, 0.3381330073, -1.2129957676, 1.0842293501, + 0.9588112831, -0.4454301894, -0.7255096436, 0.5139003992, 1.0043842793, 0.4047205746, 2.6048500538, -0.7641742229, + -0.1398930699, -1.2959104776, -1.8625189066, 0.8397760987, 0.0908519179, 1.7395669222, -0.4368506372, -0.4642670155, + 0.8948456049, 0.0972507, -0.5477635264, 1.8051584959, -0.6752122045, 1.8902174234, -0.2260762304, 0.0208178144, + 1.9998450279, -0.6578727365, 0.1301973611, -1.1438729763, -1.0635344982, 0.3119478226, -0.4038535357, 1.0320700407, + 0.0470034257, -0.3322484791, 0.8958112597, -1.0423126221, -0.2093100846, -1.0931046009, -0.1595915258, -1.0094487667, + -0.2817739248, 1.2365338802, 0.1999276727, -1.5332267284, -0.7521827817, -0.0498312488, -0.1254887134, 0.2784412205, + -0.4777686596, 0.1808462292, 1.7320671082, 0.6485695839, -1.1794214249, -0.028768912, 2.1534762383, 2.1387667656, + -0.1862127781, 1.3411992788, 1.210734725, 0.9686575532, -1.3244681358, -0.3789440989, -0.5815922618, 0.3594802916, + 0.5171622634, -0.6009837389, 0.3175195158, -2.2224929333, -0.6074861288, 0.2733509541, 0.0802273899, -1.069200635, + -0.9597536922, 0.0113089839, -1.3741334677, 0.2265929431, -0.6278473735, 1.234061718, 0.0882001072, -0.31422019, + 0.222788617, 0.854596436, -0.0908002779, -0.2843574286, 2.4294245243, -1.6052583456, -0.2354816645, -0.7199215293, + -0.6534951329, -0.1538714468, -2.6277620792, 0.9282026291, 0.4786596, 0.7063364983, -0.9769585729, 0.584408462, + -1.4787604809, 1.595492363, -1.547077775, -0.0792327374, 0.7591784596, -1.0835412741, -2.8589627743, -0.0519933216, + 1.1929847002, 0.162751615, 0.992151022, -0.1297453046, -0.5478489995, -1.8640022278, 0.2769920826, 1.2735897303, + 0.747053504, -0.030487217, -0.0428298526, 1.0499415398, 0.4667961597, 1.2053909302, -0.0714367554, -0.5911626816, + 3.0160570145, -1.3844703436, -0.139788419, 1.4430978298, -0.6048903465, -0.7319226265, 0.073581852, 0.1856525242, + -0.37248981, 2.3749258518, 0.4259150028, -1.3816146851, -1.0676062107, 0.0282882024, -1.3178880215, -1.5067243576, + 1.7033506632, -0.3256493509, -0.3136684895, 1.1504480839, 0.3979339004, -0.8979489803, 0.6665918827, -0.217796579, + 1.7094330788, -0.020392213, 0.5821586847, 1.4792309999, -0.0451435968, 1.9510873556, -1.4385012388, 0.6818209887, + -0.6088625789, 1.1092604399, 0.2422867864, -0.4770748615, 1.6948552132, 1.1704604626, 0.4564086497, -1.0953822136, + -0.7527635098, -1.5625915527, 0.1791021079, 1.8587647676, 0.0916229114, 0.4258229136, -0.9329550266, -0.0671339333, + 0.1869338453, -0.1333879828, 0.6261107326, -1.5891088247, -0.2642643452, 1.154810071, -1.3183220625, 0.6512417793, + 0.968075633, 0.9950332046, -1.0700780153, -0.2943134904, 1.7982032299, 0.4225844443, -1.5542390347, 0.2829584479, + -1.2698465586, -0.8019006252, 2.0648713112, -1.2976447344, -0.2495082319, -2.922804594, 0.55531919, -0.6955707669, + -0.0912849903, 0.0168256983, -0.3094053566, 1.1338710785, 1.42771101, 0.6253098845, 1.1908096075, 0.2107233107, + -0.7185921669, -0.2519544363, 1.7649414539, 0.6261631846, -0.2532690167, -0.4259355664, -0.3002924323, 0.7058870196, + -1.5119395256, 0.6891105771, -2.2670624256, -0.3775601983, -0.7435219288, 0.6637009382, -0.6702621579, 0.211844191, + 2.0264430046, 0.295016259, -1.9733177423, -0.6014866829, 0.7231934071, -0.5663225651, 0.2073399425, -2.2557966709, + 0.0920352787, -0.1102471575, -1.1182092428, 0.8314582109, -0.6517904997, 0.572763145, 0.6002388597, 1.0145868063, + 1.2000041008, -0.3893697262, -0.2220023125, 0.0439428948, -0.0033232714, 2.1105318069, -0.7621703148, -0.1955248266, + -1.0612522364, 0.5935337543, -0.7442343831, -0.4376539886, -1.2502030134, -1.1209059954, 0.6724943519, -0.6831957102, + -1.3959691525, -0.3748416901, -1.3967071772, -0.6097630262, 1.0784497261, -0.0811343193, -1.4515217543, 1.7069116831, + -1.4116988182, 0.0189672094, 0.0360026099, 1.5870809555, -0.8664822578, -1.3608570099, 0.5752806664, 0.032778956, + -0.4369576275, -0.1481619924, 0.5401315689, -0.5292395949, -3.2350654602, 1.1074713469, 0.9541392326, -0.6092355847, + -0.6445279121, -0.1951347739, 0.6513268352, -0.7532553673, 0.30511868, 0.9178270102, -2.5410294533, -1.6669428349, + 0.42596668, 0.6748510599, -0.4968488812, 1.1697164774, -0.1687025577, -0.6268527508, -1.2338035107, -1.3931992054, + -0.3564191163, 1.4220254421, 1.0918205976, 1.2700427771, 1.514698267, -0.3999033272, 0.0118509382, -0.3351794183, + -0.4617187977, -0.253177762, 1.2234048843, 0.2188955843, -1.2126897573, 1.077498436, 1.5508300066, 1.3986558914, + 0.4946941733, 2.1584038734, 2.4771494865, 0.5729361773, -1.1950562, 0.5807843208, 2.3439888954, 2.180368185, + -1.5197203159, -1.3456399441, 0.0533661768, -0.7593796849, -0.4989078045, 0.0440334193, -1.8984165192, -0.4864933789, + 0.6840640903, 0.2822242975, 0.7824342847, -1.0771510601, -0.5577027798, 1.4288663864, 1.0138487816, 0.4544593394, + 1.0341511965, -1.6534334421, -0.5851719975, -2.5957257748, 0.6972800493, -0.2410648167, -1.1962827444, 0.6448838711, + -0.4857121408, -0.3649063706, 1.0979299545, -1.5546585321, 0.1901791841, -0.4854544401, 0.0275086965, 0.9509277344, + -0.7999033928, -0.1402400732, 0.0964038074, -0.1028219312, 0.5689355135, 0.3108150065, -0.3040729761, -0.4496122599, + 0.4359531999, -0.1692104042, 0.0689164475, -0.7930421829, 0.8997336626, 0.7421265841, 0.2194436193, 1.0569325686, + 0.0017485305, 1.0466918945, 0.3023291528, 0.3153903782, 0.8032365441, -1.1121325493, 2.6082203388, -1.3207836151, + -0.3867725432, -0.3457061648, 1.4187725782, -0.6497259736, 0.7847685814, 0.2821341455, -0.1602710783, 0.0889612883, + -1.4676092863, 0.6674157977, -1.0673069954, 0.2699068785, 0.1724976599, -0.371516794, 1.0822068453, -0.7078635693, + 0.4691339135, 0.3721350431, 1.1494282484, -0.0420525447, -0.4953653812, -0.4252645075, -1.8390085697, 1.0680310726, + -0.0759820119, 1.0406930447, -0.6761109233, -0.2665938139, 0.3006088734, 1.1225448847, -0.9760149717, -0.0417896174, + 0.0025571589, 0.401520431, 0.7486844063, -1.3603100777, -0.8001003861, -0.4906891882, -1.0416312218, -1.0722851753, + 2.4610190392, 0.2289647162, 0.3938124776, -0.3345311284, 0.5383934975, -0.2748134732, -0.6480213404, 2.1349983215, + 0.1050079092, 0.825882256, -0.4955825508, 1.7874985933, -0.3892707229, -0.7922250032, -0.3951547444, -0.0935009569, + 0.183989197, -0.8543516397, -1.0464440584, -0.7042970657, -1.1806395054, -1.2209229469, -0.2441308498, 0.6465824842, + -1.5547673702, -1.7660431862, -0.4821627736, 0.1407624334, -0.167861715, 0.9397349954, 0.2312805504, -0.0280464403, + 1.6767039299, -0.9470214248, -0.9351007342, -0.9674376249, 0.5599937439, -0.7846594453, -0.4185580611, 0.156263411, + -0.5272597671, -1.4458227158, 1.7874987125, -0.8945755363, -1.2059798241, 0.289878428, -1.5602114201, 1.3168905973, + 0.4170904458, -0.5218951106, 0.0991009474, 1.1913528442, -1.092266202, -0.8239323497, -1.3484790325, 0.547775507, + 0.6710631847, -0.4247452617, -1.6761363745, 0.4697081149, 0.0555586666, 1.6238911152, -0.6668378711, -0.7418172359, + -0.7404046655, -0.2535289526, 0.7424023151, -1.4185131788, 0.1802333444, 0.1009450033, 0.3009157479, 0.1991927475, + -2.3257699013, 0.6526278257, -1.610519886, 0.7812666297, -1.1860648394, 0.307379514, -1.543982625, 1.0786151886, + 1.268055439, 1.1521686316, 1.193544507, -0.132916972, -0.3085395694, 0.076197885, 1.8443210125, -0.2638729513, + -1.5977312326, 0.8382647038, 0.0859807804, 0.1356368512, 1.1917499304, -1.0192261934, -0.3402422965, -1.1250737906, + 0.2373281419, -0.599396646, 0.466196388, -0.5152217746, -0.5071100593, 0.5282868743, -0.1788586527, -0.1281480938, + -1.3527747393, 1.0704989433, 0.5577857494, 0.0059412615, -0.3464069664, -1.0306385756, -0.1926615536, 1.6605831385, + 1.3970597982, 1.7178465128, 0.5896280408, -2.2436287403, 1.4201089144, -0.6560614705, -2.3737287521, 0.0326512717, + 0.2078212202, -0.0501976386, -0.3021792769, 1.1992337704, -0.4503636658, -0.2515912652, 0.169175297, -0.0690513998, + -1.7739503384, -0.0254569277, 2.1342687607, -2.295835495, 0.4292617738, 1.1680651903, -0.082315661, 0.6136156321, + -0.1594337076, 0.3683827817, -0.0694643259, -0.4721207917, 0.3415882885, -0.6719304919, 0.0745203495, 0.0926815197, + 0.7809058428, 0.8021600842, 1.2536708117, 1.2047463655, 0.8457165956, -0.268928349, -0.0406811796, 0.712293148, + -0.0020184009, -0.7400744557, 1.5476503372, 0.7627727985, 0.6692178249, -0.502558291, -0.3137260675, -0.2285013795, + 0.3727241158, 0.3642551601, 0.6032511592, 0.833573699, 0.1891970634, -0.3147652745, 1.5904812813, 1.0627577305, + -0.6074346304, -1.1208091974, 0.5797903538, -0.5553388, -0.762616992, -1.4770214558, 2.1922209263, -2.2505557537, + 1.1951607466, -0.6032582521, 1.1439125538, 0.7489135265, 0.8095982671, -0.3108332455, -0.3310345113, -0.8971514106, + -1.5992891788, -1.404507637, -1.4514647722, -0.5385984778, -0.9099396467, 0.7821102142, 0.3216437697, -0.7002050877, + -1.6994129419, -1.0463931561, 1.0386457443, 0.1906262785, 0.0693022907, 0.3480342925, 0.6630804539, -0.964882791, + 0.1472559869, -0.0458867997, -0.9605195522, 0.265419364, -0.4124167562, 1.2029577494, 0.1682241857, 0.1582312435, + 0.6462152004, 0.7105493546, -0.5076053143, 1.287463665, 0.7914259434, -0.3501081765, -1.3159191608, 0.9087712765, + 0.3375329971, -0.0894550458, -3.3134696484, -1.0573728085, -0.4799038172, 0.1022162735, 0.0140804453, -0.4237525165, + -0.002914414, -0.4657649696, -1.2013605833, -1.8574804068, -0.7658002973, 0.2583065629, -0.7350707054, 0.5241965652, + 0.5456067324, 0.5849019289, -1.0737682581, -0.3010232449, -0.4734374583, -0.3524091244, 0.4543142021, -0.4802360535, + 1.5676404238, -0.0989632905, -1.248483777, -0.8684524894, -2.6856575012, -1.2519989014, -0.32951051, 1.1998020411, + 1.5729202032, 0.9265779257, 1.4141265154, -0.2236066461, 0.9494342804, 0.8590515852, 0.1530281156, 1.1916043758, + -0.1836208552, -1.341468811, 0.8105289936, 0.2061579078, -0.5158743858, -1.1998797655, 0.8480063677, -0.964810729, + 1.012059927, 0.1300519258, 0.1588593423, -0.1458848864, 0.4267154038, 1.5206574202, -0.2062469721, -1.081913352, + -0.9290098548, -1.7997145653, 0.7159577608, -0.5012516975, -0.9157263041, 0.1787528396, 0.0459793061, 0.5049911737, + -0.899374187, -3.0976221561, 0.7384113669, 1.585413456, 1.1512668133, -1.4262179136, -1.2774196863, 1.7157492638, + 0.8839167953, -0.6359609365, 0.8234870434, 0.8796422482, -2.343436718, 0.5187589526, 1.317248702, 0.2944667935, + 0.2227121741, 0.5968134999, 1.2236213684, -0.4995519519, -0.5660246611, -0.6994220614, -0.310690701, -1.2275322676, + 0.7521572113, 0.3444543183, 1.5920861959, 0.2251924723, 2.2333335876, -0.03961768, -0.1746587604, -0.1322690248, + -0.428915143, -0.7689406872, 1.230451107, 0.226140812, 0.6992877126, 0.845030129, -0.6699578166, -1.3206387758, + -1.4513704777, -1.8766469955, 1.6361585855, -0.378574729, 0.8501096368, -0.0773385093, -0.1470464617, 1.6808183193, + 0.3025913537, 0.2117206156, 0.0503673851, 0.2844220996, 0.3684289753, 0.9366687536, 0.6129627228, -0.6902558804, + -0.3202367425, -1.7368016243, 0.10831929, 0.2266173512, -0.220457226, -0.8055815101, -0.5609047413, -0.5874257684, + -1.4272302389, -0.4451175928, 0.400164634, -0.5392788649, 0.0617882907, 1.234994173, -1.5404955149, 0.6322777867, + 0.8958539367, -1.2067916393, -1.0665080547, -0.6116001606, -0.6186541319, -0.4733894765, -1.3370724916, -0.4977751374, + 0.6712226272, 0.0883457363, 2.0432891846, 0.0867749825, 0.2891819477, 1.6255686283, 0.5093495846, 0.8634660244, + 0.7550491095, -1.4651743174, 1.2748829126, 1.3423838615, 0.0865078941, -0.7244066596, 0.8706378937, -1.7124751806, + 0.5211428404, -0.5917902589, 0.5395089984, 0.0224716794, 0.4386703372, -0.8138235211, -0.2059317082, -0.9192074537, + -0.0604479648, -0.4525226951, -1.9594230652, -1.5452584028, -0.2895898819, -0.0253855549, 0.6934217811, 0.3090851307, + -0.2218995094, -0.0529302284, 1.2924019098, 0.9603215456, 0.3587602675, -0.955235064, 1.1490943432, -0.0335796215, + 1.6779471636, -0.3259856403, -0.1739709228, 1.5214538574, -0.6064954996, 0.1615271866, 0.6834179759, 0.3536682725, + 1.081657052, 0.3024944663, -0.6590800285, -0.8109408617, -0.1566258967, 0.4882825315, -1.2851366997, 0.6194458604, + -1.6078065634, 0.033487428, 0.9258344769, 0.3397276998, -0.0351016968, -0.8456002474, -0.4561108053, -0.891397357, + -0.1025945768, -0.2888323367, -0.2083857954, -0.1048913971, 1.9896476269, -0.4569800794, 0.0361020789, 1.0713363886, + -0.7877628803, -1.0399837494, 1.3942734003, -0.4270233214, 0.3786351383, 0.9357964993, 0.9731655717, -0.7636753917, + -1.6540989876, 0.8779069185, -1.4263557196, -0.0950654224, -1.5323438644, 0.0343191847, -1.1123816967, -0.270870477, + 0.1493589282, 0.5749483705, 1.4909499884, 0.0755190328, -0.9530516267, 0.6965177059, -0.686599195, -0.9001799822, + -1.1961323023, 0.1245036572, -0.3526382148, -0.4453476369, -1.8010739088, 0.5374770164, 0.2574934065, -0.3085855544, + -0.06407772, -0.8079072833, -0.5141606927, -0.5505889654, -0.1982488185, -0.3675305247, 0.4208337367, 0.0965360552, + -2.065694809, -0.1829688996, 0.2506989241, 0.2846823037, 0.3001767695, 0.23642914, -0.7418822646, 0.5268235207, + -1.3270870447, -0.8376921415, -2.0307159424, -0.4796929359, 0.7163648605, -0.4497404099, 0.0741514638, 1.1273583174, + -1.0137497187, 1.3068083525, 0.0346848592, -0.8894021511, -0.963206172, -1.5303732157, -1.1514923573, 0.8990085125, + 0.982822597, 1.2495281696, 0.5501637459, -0.7472378612, 0.8517258167, 0.4913127124, 1.109017849, -1.0322618484, + -1.5959858894, -0.341383338, -0.1173982024, -1.607052803, -0.2624657154, -0.6415647864, -2.6126191616, -0.5836005211, + -1.0906150341, -0.8369953036, 0.2202195823, 1.8754501343, 1.1174076796, 1.0884023905, -0.2120194435, -3.0440869331, + 1.4379463196, 0.1025658697, -1.5558474064, 0.6945379972, -0.3602610528, 0.0620819256, -2.5303983688, -1.4525141716, + -0.0484901033, 1.0190861225, -1.1029773951, -0.1772495806, -0.0186824985, -0.4372339845, -0.7663955092, -0.2264468819, + -1.8660597801, -0.0174309351, 1.289525032, 2.8766248226, 0.5093661547, 0.6372798085, 0.3782185614, -1.2775412798, + -0.9037016034, 0.7714995146, -0.7808824182, -1.0733382702, 1.5326451063, 1.6875671148, 1.1831212044, -0.3538039029, + 0.4219298065, 1.1515035629, 0.1067457125, -0.6593474746, -2.3907163143, -1.6215455532, 0.023235349, -0.4400199056, + -0.0634604543, 0.2586629093, -2.2663216591, 0.6431171298, -0.6066202521, 1.8293699026, -0.6815040708, 0.5783654451, + -0.8462299705, -1.7036626339, 0.2688787878, -0.1152593791, 0.0679218322, -0.4225247502, -1.4610382318, 0.5065841079, + -1.9560542107, 0.4685810506, -0.644481957, -1.4162796736, 0.9209262133, -0.9962162375, -0.8262240887, 0.9954686165, + -0.6650307178, 0.9970404506, -0.1991078705, -0.6442340612, 2.049696207, 0.0618126243, -1.0454064608, -0.6637465358, + 1.9695299864, 0.1250195652, -0.7327752709, -0.1359323561, -0.44128564, -0.367551893, -0.2591361403, -2.576924324, + -0.5419714451, 0.2259461731, -0.1193021312, 0.7141500711, -0.6071059704, 0.3218783438, 1.9557578564, -0.2104028761, + -0.6749036908, -0.4633462429, -0.5990371704, 0.9030663967, 0.6569451094, -1.579600215, 1.3999508619, -1.049612999, + 0.3546217382, -0.053015992, -1.196757555, -1.5856877565, 0.0531225428, 0.8695508242, -0.3861188293, -0.7244033217, + -0.1855974942, 1.0887128115, 2.3390982151, -1.725481987, 1.5232543945, 0.3753961921, 0.9166776538, 0.282879889, + -0.3334253728, -1.2294572592, 0.3655229807, 2.0233829021, 0.287946254, -1.4131339788, -0.7401593328, 0.6440915465, + -2.2614407539, -1.4203243256, 2.6897394657, 1.0188958645, 0.892279923, 1.5838291645, -0.3026787937, -0.4696189463, + 0.7466695905, -0.6594412327, 1.2971545458, 1.1126279831, 0.063364476, -0.5827593803, -1.2563552856, 0.1899198294, + 0.894716382, 0.4806729853, 0.0808907971, 0.8153989911, -0.5255755782, 1.4518349171, -1.5716581345, -0.5564303398, + -0.1252691299, 0.895802319, 0.7547018528, 0.6371154785, -0.1164987236, -1.7575292587, -0.8542814851, -0.7686762214, + -1.0782096386, 0.6460056305, -0.7257015109, -0.3034015298, 0.6748173237, -3.3844981194, 0.1262123883, -0.103563495, + 1.4074908495, 0.5247564912, -0.3472731113, 0.8271560073, 1.0331898928, -0.6009578109, 1.1177165508, 0.5174444914, + -0.2727499604, 1.3153707981, 0.4109996557, -0.1952133924, 0.3007640541, -0.5758360624, -0.5602527857, 0.3082463443, + -1.312093854, 1.7105407715, -1.5808700323, -0.8947734833, 1.3084439039, 0.5117423534, -1.4647477865, 0.0225376338, + -1.7247672081, 0.4059568346, -0.52979213, -0.4586297572, 0.5186428428, 1.1221458912, 1.1941851377, 0.70903337, + -0.1947846115, 1.9539064169, 0.2526306808, -0.7416341305, -0.3133064806, -0.3473016918, -0.002602838, -1.0973331928, + -1.1440614462, 0.583676219, -0.4917782247, 2.3554165363, 1.5738666058, 0.5428704023, 0.0142914858, -1.2510061264, + -2.2476670742, 2.6870701313, 0.8242061138, 1.8147623539, -0.3681277633, 0.8724951744, 0.4893138111, 0.4355538487, + 1.4844454527, -1.4029507637, 0.2526011765, 0.186914593, -2.3647630215, -0.4800653756, 0.9991058707, -0.52129668, + 0.1787936091, 0.296805501, -0.9514818192, 0.7149151564, 0.4679512978, -0.2365171462, -0.0139078815, -0.1421744227, + 1.4185181856, -0.8405714035, 0.110591948, -0.5550268292, 1.3210300207, 0.3122994602, 2.4679713249, -0.60521245, + 1.2478696108, 0.0954830274, 0.9173564315, -1.9533030987, -0.9786008, -0.3256475627, 1.0131014585, 0.1920856088, + 0.8135458231, 0.5758315325, 2.8805861473, -0.5539932847, -0.1677597016, -1.1043391228, 1.4870136976, -0.3989987969, + -0.7816363573, 0.905007422, -0.6455032229, -0.4766314626, 1.0585227013, 0.3848082721, 2.5556023121, -0.7868890166, + -1.9005753994, -0.7796630263, 1.699406743, -0.8025813699, 0.5371515751, 0.4411693215, -0.1469948888, 0.5937262177, + -1.2914032936, -0.0362044945, 0.7089365125, 2.9356086254, 0.0261324681, -0.0169340111, -0.0850357786, -1.181191206, + 0.5618770123, 0.1779046506, 1.4448437691, 0.1256714612, -0.9184864759, -1.1742694378, 1.025878191, -1.404962182, + -1.8019059896, 1.6122846603, -0.9469008446, -0.9792156816, -1.0730874538, -1.9244215488, 0.1242880449, -1.3025438786, + 0.9926157594, 0.0525438972, 0.1790150851, -0.8310004473, -0.1794541776, -1.1104866266, -0.2170728147, -0.4860383868, + -0.0960857049, -0.4243250787, -0.3056462705, -0.0738886967, -0.2791997492, -0.1564156264, -0.839922905, 1.1458208561, + 0.6837478876, 1.6160286665, -0.1099802181, 0.1030385345, -0.4512418509, 0.8318041563, 0.9506053329, -1.7757173777, + -1.9854574203, 0.3565828502, -0.3700554073, -0.6152406931, -0.9687829018, 1.3810563087, 0.232015729, -0.0397417285, + -0.4070185125, 1.0224226713, 0.6736516356, -0.1206513643, 0.3238360882, -0.7017626762, -0.0897023901, 1.4467226267, + -0.7196639776, -2.5757844448, 0.3970977664, -0.2733588219, -0.3398293257, -0.2725647688, -0.4187522829, 0.3255429864, + 1.5826820135, -0.5754086375, 0.0943736285, -0.4439761937, -0.1710792184, -0.4510376751, -0.0273558944, 0.2152557671, + 1.4247077703, 0.0805678144, -0.6716182232, -0.9144644737, 1.0538321733, 1.6822096109, 0.2016815394, 1.2589432001, + 0.4971260726, -0.4490357339, 1.7315534353, -0.4510636628, 0.1474699676, 0.9106471539, 0.1625524759, -1.4341237545, + -0.7749769688, -0.3517271876, 0.8197718859, -1.1186920404, 0.6920174956, -0.4592382312, -1.0409634113, 1.7210446596, + 0.100296773, 0.0334235467, 0.9438540936, 0.5847578645, 0.4156909585, -0.7136794329, 0.5987677574, -1.1312581301, + 0.4730856419, -0.913313508, -0.4913589358, 0.1282602251, 0.2038312554, 1.4765167236, 0.5084848404, -0.2917088866, + 0.351722002, 0.651781261, 0.6369057298, -1.2051205635, -0.6937068105, 0.0933035389, -1.1256998777, -0.8713313937, + 0.6497979164, 1.6654264927, -0.2665706575, 0.9316011667, 1.0475007296, -0.416318059, -0.2547314763, 2.2949197292, + -0.7823335528, 0.4881402254, -0.5845407248, -0.2045453191, 0.1332875192, -1.0624183416, -0.7866970897, -1.6789759398, + -1.4453302622, 1.1875790358, -0.9976070523, 0.7905008197, 2.677012682, -1.582963109, -1.4054129124, 0.2432076484, + 0.5539929271, 0.9461371303, -1.2753396034, -0.4961832166, -0.1548965722, -0.4539283216, 0.2310051918, 0.1122577861, + -0.3159879148, -0.1546914428, 0.9573659897, -0.9810982943, -0.0313256383, 2.7361254692, 1.1906349659, -0.1153252274, + 1.1036010981, 0.1202579215, -1.8402842283, -0.9810041785, 1.6234278679, 1.713136673, 0.9054279327, -0.0411528088, + -1.1291643381, 0.914257586, -0.1347265393, 0.7485822439, -1.1155381203, 0.8338834047, 0.0044410489, -0.1199790686, + -0.2514708042, 0.2934603393, 0.0102223698, -0.9591860771, -0.4407611191, 2.4567036629, -1.4015727043, 0.3956102133, + -1.2079521418, -0.3189548254, -1.0416499376, 0.3006887138, -0.2559400499, -1.5648876429, -0.5479289889, 0.9294615984, + -0.7143161297, -1.3360306025, 1.2542421818, 1.6548587084, -0.7020130157, -0.0768703371, 0.0540100858, 0.786657989, + 1.0969753265, 1.6252093315, -0.5440499187, -0.7300460935, 0.512105763, -0.1335268468, 2.5226573944, -2.042784214, + 0.1997319609, -1.1326947212, -2.2240474224, 1.7012556791, 1.6482611895, -0.0981576741, 0.6183930039, 0.7943008542, + -1.0404632092, -1.2540209293, 1.0974723101, 0.3400676847, -1.7999849319, -0.514913857, -0.1294233352, 0.2476343811, + 0.8727270365, 0.0723300055, 0.2251117826, 1.4213521481, 0.1532366574, 2.6486074924, 0.1167246997, -0.4805921614, + 0.3937732577, -0.9335401058, -1.4705386162, 1.1323963404, 0.0321465358, 0.910223484, 1.3990534544, 0.4905488491, + 1.0244057178, -1.6630067825, -0.3994784951, -0.3401413262, -0.3454761505, -0.0475850701, 0.4195607305, 0.1365256459, + 0.0498067103, 0.4276661575, -0.5091152787, 1.7417982817, -1.5653539896, -0.1948224455, 1.4137815237, -0.3796446621, + -0.6055162549, -0.4563442171, 0.9318701029, 2.0537283421, 0.7551569939, 0.1563235372, 0.4450795949, 0.2379143834, + -0.8415094614, 0.1656335741, 2.3153066635, 0.6370079517, 0.6397714615, 1.8445942402, -1.988930583, -0.8778341413, + -0.2747113407, 1.4435391426, 0.3957173228, -0.10960906, -0.8891395926, -1.2789076567, 0.0116699347, 1.0117725134, + 0.3835023642, -0.5092669725, -0.0680650771, 0.9934516549, -1.1740164757, 0.1203645915, -0.2318346053, 1.2257432938, + 0.1388643533, -1.1649215221, 0.5175055265, 0.2016887665, -0.3390520215, 0.637250483, -0.861718297, 0.3922643661, + -1.1405359507, 0.256953001, -0.4474111497, 0.044807855, -0.208746776, 1.6296164989, -0.0296883136, -1.2102688551, + 0.5677373409, 0.0009645627, 1.3742536306, 1.1661435366, -1.13382864, 0.7868994474, 0.4527561665, 0.2778838873, + 0.6215717793, -0.9352455139, -0.3557741642, -0.2322310805, -0.992110014, -1.4324650764, 0.6023430228, -1.1864603758, + -1.0976997614, 0.8242604136, 0.1729867607, -1.1119036674, 0.2921111584, 0.0507399924, 0.663118422, 1.2487870455, + 1.4756360054, -0.7475041747, 0.5366319418, 0.1717128307, 0.46519503, -0.0540710352, -0.2115193903, -0.2900735438, + 0.7111625075, -0.1079788059, -1.6012848616, 0.3743604422, -0.0169442687, -0.9762680531, 0.3801927269, 0.1165735647, + 0.4455650449, 0.1271342188, -0.584463954, -0.3766897917, 0.5482994914, 0.2216329426, -0.5788456202, 1.3263802528, + 0.6550196409, -0.7106993198, -1.1114065647, -1.2377024889, -0.9838712811, -1.253189683, 0.4703316987, 0.0795856193, + 0.1470217109, -2.2242867947, -0.6280842423, 0.3862711787, -0.2358767688, -1.0647182465, -0.2574432194, -1.4735280275, + 1.1477354765, 0.8785506487, 0.6193646193, 0.0978459045, -1.0593994856, -1.1262053251, 1.2516567707, -1.4200671911, + -0.3345801234, 0.2187118828, -0.1080835685, -1.2882615328, 0.7958784103, -0.6218714714, -0.2906329036, -1.4599126577, + -1.1279275417, -0.9053555131, -1.0980588198, 0.1504440308, 1.1394290924, 0.3642742634, -0.1579071581, -0.9825789332, + -2.1468319893, 0.0083792591, 0.7393897176, 1.4622263908, 0.1394752264, -1.5417640209, -0.2361054122, 0.7392612696, + 0.8448073268, 0.563716948, 0.0669474825, -0.0490082353, -0.1221956983, -0.0868485868, 0.003675669, 0.0283785351, + 0.9145377278, 1.3506923914, 0.2616867423, 2.4223361015, 0.3500064015, 0.5549456477, -1.2616983652, 0.2947146297, + 0.8523635864, 1.2621779442, 1.0800333023, 1.587610364, -1.9408265352, 0.2570088506, 1.7748100758, -1.6168836355, + -0.9866812229, -0.0237126984, 1.4818791151, -0.2154493928, 0.0660840422, -0.6549353004, 0.0116032315, 0.4643039107, + 1.312093854, 1.0078448057, 0.4175274968, 1.7760876417, -0.233787626, -1.1625869274, -0.5908479095, 1.109467268, + -0.5619422197, 0.2336943001, 0.5299299359, 0.7005144358, 0.9736207724, -0.4927281737, 1.4668943882, -1.0239930153, + -0.0770049617, 0.7348200083, 0.2523647845, -0.2476083785, 0.9233145118, -0.0127188815, 0.7690323591, 1.3147650957, + -0.0070816535, -1.9878875017, -1.5712317228, 0.7105522752, 0.527897954, 0.2327578664, -1.2572900057, -0.1001996845, + -0.1817302555, -0.3798861802, 2.3356816769, -1.6914775372, -1.1774146557, 1.2655371428, -1.5351748466, 0.7914337516, + -0.6201122403, -0.3057745695, 0.1126926094, 0.6709082723, 1.1037712097, 0.179088369, 0.6736957431, -0.4431216717, + 0.8462934494, -1.1090414524, 1.5360138416, -0.6972581744, -0.4059306085, -1.8871546984, 2.0013945103, 0.0334238783, + -0.2949000001, -1.3512518406, 0.6522342563, -0.765388608, 2.2844948769, 0.8337475061, 0.3221344352, -0.5305902362, + -2.4431941509, 0.8988071084, -1.0610204935, 0.8465533853, -0.1923000813, -1.3131548166, -1.5066918135, 0.6025505066, + -0.8746331334, -0.3928633332, 1.1593921185, 0.1034096554, -0.3026155829, 0.4849913418, 0.1135137603, 1.672033906, + -0.3694227338, -1.4470843077, 0.7193400264, 1.0495063066, 0.0959530175, -0.6709577441, -0.3056570888, -0.6415513754, + -0.5251059532, -0.6818318367, 0.3147960603, -0.4887236953, -0.9638143778, -1.1264886856, -0.4230669439, -1.3753056526, + 1.4559468031, 1.476587534, 1.2504413128, -0.4936591685, 0.3515748084, 0.2022776455, 0.9292532802, 0.8853971958, + -0.6428562403, 0.2419474721, 0.6410183311, -1.7333700657, 0.9614998698, -1.3203852177, -1.3492267132, 0.1798286587, + -0.5843139887, -0.3930367231, 0.0276744086, 1.1229655743, 1.2574152946, 0.5836015344, -1.835927248, 0.0817378908, + 1.3239192963, -0.4715490639, -1.7266557217, 0.3238314688, -0.2207290232, 1.0489692688, 0.9688036442, 0.4010276198, + -0.3819698393, 0.124832496, -0.0166277848, -0.9547690153, -0.4959850311, -0.5902844071, 1.8655183315, 0.0865403786, + -0.6640671492, 0.5868545175, -0.2740457356, 0.6969856024, 1.4407171011, -0.1463461518, 0.8920519948, 0.3390126824, + -0.0442162864, 0.4553397, -0.6127408147, 0.3977233469, -1.7088475227, -0.1218002737, 0.1388552785, 0.4274210334, + -2.0180900097, -0.1601694822, 1.6350325346, -0.4815888107, 1.4442528486, 0.1157166064, 0.284404397, 0.1153378934, + 1.5692323446, -0.2419142425, -0.5717042685, -0.1694380194, 0.877297163, -0.6982527971, -1.3658602238, -0.7143605351, + -1.2969588041, 0.326941222, 0.8335607648, 0.4132811427, -0.003594175, 0.5502625108, -1.2089297771, -0.4677336812, + 0.4932954907, -0.2773734927, 0.37932235, -0.2142858654, 1.416457057, -0.0279256701, -1.4179240465, 0.9715839028, + 0.3082867861, 0.3752784431, 0.9423430562, 1.3675347567, -0.6815214157, 0.5373745561, -0.475355804, -2.2577373981, + -0.1867559999, -0.4563869536, 1.1202806234, 1.1302267313, -0.9389406443, -0.7574245334, 0.526710391, -0.8715178967, + -0.1430505812, -1.9246406555, 1.8750369549, -2.5997474194, -0.8381543756, 1.5143324137, -0.5030655861, -0.5764772892, + 1.0302103758, -0.3347219825, -0.0474841893, 0.0351716802, -0.8788820505, -0.773219943, 0.1133688316, -2.5959587097, + 0.0701987743, -0.9390360713, -2.1080806255, 1.2983478308, -1.7246512175, -0.6754827499, 0.1538365036, -1.6606847048, + -0.6705852151, 0.4778603315, -0.4059040546, -0.4880833328, 0.2577357292, -0.1147083938, -1.2455481291, -0.5508422256, + 0.3719415665, -0.5658921003, 0.5245736241, -1.1117680073, 0.0928273723, 0.0218124297, -0.3010913432, 0.8775908351, + -0.2169012874, -0.8590472341, -0.3291174471, -0.5996320248, 0.1607422233, 0.4372586012, 1.5891768932, -0.0624184571, + 0.7525455356, 2.5343019962, 0.7479329705, 0.8544104695, 0.4639654458, -2.2253143787, -1.0417768955, -0.0010615842, + 0.2537246644, -1.074819088, -1.3404649496, -0.264074564, 0.3361747563, 0.29336676, 0.7682360411, 0.1233829632, + -0.7152925134, 0.7858465314, 0.2019590288, 0.5854577422, 0.9132457376, -0.3124257922, -0.6049257517, -1.7231265306, + 0.7158805132, 0.7621665597, 0.4707882106, -2.9688909054, 1.0587520599, -0.1631650478, 0.0793522522, 0.133652851, + 1.0867087841, -0.5280027986, 0.2855147421, -0.0667707622, -0.0035638765, 0.4216847718, 0.544318378, 0.2461861372, + -0.1809778661, -0.880510807, -0.143899709, 0.3478353322, 0.8228884339, -0.5667278171, -0.4600711167, 0.61766994, + 2.3540959358, -0.8628973961, 0.908832252, 0.6932885051, 1.0956834555, 1.0052500963, -0.4408296347, 2.0047576427, + -0.9447867274, 0.9418581724, -2.8230834007, -0.3410270214, 1.3397841454, 2.1751554012, -0.0430340357, 0.4309962392, + -0.0155594079, -0.6336702704, -1.5577777624, 0.1310043186, -0.4537871182, 2.4866731167, 1.1449908018, -1.5187022686, + 2.0298993587, -1.5842804909, 0.2514736354, 0.9716297984, 1.7878285646, -1.2653026581, -0.1265586317, -0.1470164657, + -0.7129474878, 0.4800057709, 2.8610293865, -0.1240404844, 1.0638287067, -1.566978097, 0.8731978536, 0.3589456379, + 0.2653459311, -0.5578699112, -0.6540279984, -0.2132600099, 0.0867705345, 1.278760314, 1.376999855, 1.2984076738, + -0.0174389817, -0.0729143023, 2.0917215347, 1.5554282665, -0.514136672, -1.5810707808, 1.3129007816, -0.3244799376, + 0.7690106034, -1.3313903809, -0.1335199028, -0.1562579721, -1.2194261551, -0.0974660292, -1.2154504061, -1.0153028965, + -0.9581129551, 1.4123982191, -0.1402374953, -1.2557382584, 0.6547852159, -0.9383400083, 1.0114247799, -0.7177949548, + 0.8543280959, -1.2188569307, -0.4752506912, -0.6735640764, 0.0805893838, 2.902731657, 0.0258577615, -0.2556987703, + 0.0209448729, 0.2968816459, 1.4511637688, -1.0195590258, 0.3860342205, -0.2076390535, -0.7492733598, -0.2612061799, + 0.2322777659, -0.0773505419, -0.8092628717, -0.392298013, -3.0591294765, -0.7700003386, -1.5647056103, -1.1685365438, + -1.1834771633, -0.7745651007, 0.6517621279, -0.6666411161, -1.2065341473, 0.883138299, -1.315354228, -0.0880349576, + 0.5406996608, -0.2709668577, 1.2457705736, -0.4655426145, 0.5110310316, 1.670232892, 0.0507460684, -0.6514158845, + 0.4647938311, 0.5530887246, 0.1307623982, 0.0550314337, 0.3614056408, 1.2339098454, -0.5118358135, -0.1313847899, + -2.1826581955, -0.1817007065, 0.0118881213, 1.1555757523, -0.5332305431, -0.7610717416, -1.1782858372, -0.1647985727, + 0.6561669707, -0.7847946286, 0.1190716103, 1.7935775518, -2.1962480545, -1.1013448238, -0.8153190017, 2.094855547, + -1.3238399029, 1.0909674168, 0.7659215927, -1.59696877, -0.5738921762, -1.4300869703, 0.7761298418, 0.1169549376, + -0.2567743063, -1.3555506468, -0.0286894329, 0.3896198571, 0.1592593044, -0.1276924163, 0.7255066633, 0.8067373037, + 0.9591949582, -1.695972085, -2.4361855984, 0.6476137042, -0.7000209093, -1.7535645962, 0.0522507057, -0.9426590204, + -0.1567277461, -0.2495714128, 0.314591229, 0.7321646214, -0.2300930619, -1.1882681847, 0.7567175031, -0.7333874702, + 1.4053243399, -0.32112813, -1.7157675028, -0.7250712514, -1.206998229, 1.3195250034, 0.2129811645, -1.8306376934, + 0.080107525, -1.1997556686, -0.3797031641, -0.1439069211, -1.375549078, -1.9295804501, 1.0497505665, 2.1053328514, + 1.3196328878, -0.0395816118, 1.261402607, -0.0005954857, -1.2713522911, -0.1604739726, 0.4342354238, -1.0333087444, + 2.0633223057, 1.0521577597, 0.3827154636, 0.7366225719, 0.4496108294, 0.0940372646, -0.7754995227, 0.1078162566, + -0.7633399963, 0.4329693019, -0.7188794613, 0.6669287682, 1.4806238413, -1.2925173044, 0.3922462165, -0.1607157439, + 1.3540416956, -0.269389987, -1.8579820395, 0.0982898772, 0.9795159101, -0.0613298379, -1.585100174, 2.1930634975, + 0.816522181, -1.4409997463, -0.8420747519, 0.8619980812, 0.3620576262, 0.0261950083, 0.1866548657, 1.8038645983, + -0.2240944952, 0.7091770172, 0.7871082425, -0.6826594472, 0.8542404771, -1.8168696165, -0.7128713131, -0.0538153574, + 0.190499261, 1.2892400026, -0.9406535625, -1.7142122984, -0.4913613498, 0.6450148821, -1.112611413, -0.2288775891, + -0.474439621, -1.3762102127, 0.5254834294, -0.5287557244, -0.5262985229, -0.1062486768, -0.6348058581, -0.9365763664, + -0.1497449428, -0.1949767023, 0.2172982693, -0.3022725284, 0.8047858477, 1.3903118372, 1.3883538246, -0.7042567134, + -0.112171948, -1.3455646038, 0.3870194852, -0.0965950713, 0.9518412352, -0.10917449, -1.1043176651, 0.6279343963, + 1.4129952192, 0.5325927734, -1.6628987789, 1.5105077028, -1.2438029051, 0.8583120704, 0.2078500837, 0.5437254906, + 1.4735174179, 0.2169694006, -0.1485404968, -0.7130903602, 1.422332406, -1.0756270885, -0.924222827, -0.7942515016, + -0.6728418469, -0.672952354, 2.3121747971, -0.0744164959, -0.2179881036, -0.4866858423, -0.8224667907, 1.1551148891, + 0.7958337069, -0.3938231468, 0.2431697249, -1.9529821873, -0.2154482901, -0.2813555598, 0.0592441037, 0.2069272697, + 1.7651711702, -0.3149431348, 1.1901835203, 0.9350205064, 2.1286346912, -0.1006811112, 0.0827367827, -0.6280285716, + -1.2208617926, -0.6480045915, -0.6513798237, 1.3888345957, -0.0509894826, -1.5703502893, 0.5715800524, 0.9913051724, + -0.1888523996, -0.3661287725, -1.8164740801, 1.6539181471, 0.270639658, -2.3285901546, -0.6339191198, 1.007819891, + -0.2167435288, 2.8713746071, -1.0747338533, -1.0448617935, 0.472514987, -0.4177502692, 1.1482754946, 0.792570889, + 1.6601495743, 0.0192887355, 0.2908635139, 0.2582688928, 0.7782739997, 1.9146323204, 0.743078053, 0.0700267404, + 0.0750506967, -0.8305863142, 0.303589493, 0.2465319186, -0.2787216604, 0.5338457227, -0.6506549716, 0.9350888729, + -0.179762423, 0.7599012256, -0.3284780979, -0.8421573043, 0.1916376352, 1.1291347742, 1.5996108055, 0.8662851453, + -0.1602092385, 1.8883359432, 0.3574674428, 0.2051007152, 1.5985630751, 0.8055735826, 0.7127355933, -0.3533496857, + -1.4823664427, -2.0089395046, -0.9939237833, -0.6550972462, -0.0262048952, 1.2165206671, 0.1078934073, -1.368970871, + 0.1513076723, -0.4456702173, -0.0554245599, 0.7030171156, -1.2767373323, -0.7908762097, 0.2892021835, -1.219653964, + 2.0823202133, 1.0406847, -0.2916181982, -0.3322509229, -1.2407140732, -0.1473717541, 0.5597736239, -0.3266303241, + 0.8758299947, -1.4328693151, 1.1302080154, 0.9464007616, 1.0138847828, 1.8907960653, -0.7582595944, 0.1726988256, + 0.1735392958, -0.5599799156, 1.8208374977, -0.7746500969, -0.6911838651, 0.0445401333, 1.2483352423, -0.7943223119, + 0.0519079305, -1.5848653316, 0.8621872663, 1.2930183411, 2.7784893513, 0.3236986399, 1.438828826, 0.7258377075, + -0.8048277497, 0.2800495028, -0.0499605834, 1.3089578152, -2.4130134583, -0.2753242254, -0.7478988767, -0.6888538003, + -0.8414610624, -0.8301863074, -1.1255892515, -1.0282196999, 0.5207557082, 0.2261744589, 0.3474826515, -1.0355030298, + 2.4439811707, -0.851559639, -0.1384771913, -1.0451205969, 0.6859315038, -0.9893190861, 1.7343578339, 0.1348031312, + 1.1066228151, -1.0953452587, -0.1847550869, 0.2814736664, -0.6099718213, 1.6427118778, -0.1525585204, -1.4401333332, + 0.5616949797, 0.703605473, -0.383969605, 0.0347902104, 1.3739222288, -1.3430659771, -1.5973757505, 0.3135956228, + -2.0644445419, -0.5595622063, 1.2138389349, -0.0590524115, -0.2654310167, -0.0230365172, 2.3398439884, -0.4614900947, + 1.2380152941, -0.2797059715, 1.4746888876, 0.2444090098, 1.7653659582, -0.4687747955, -0.3881003559, -0.3427613378, + -1.11548388, -0.9173331857, -1.2664217949, 0.8875035048, 0.6352165937, -1.1627904177, -0.6139476895, 0.5397555828, + -1.8344066143, -0.2994301021, 0.2945496738, -0.2418930382, -1.9963649511, 0.3640803993, -0.1844701171, -0.6950638294, + -1.4857170582, 1.1242765188, 0.7085320354, 0.2723022401, -1.5546014309, 0.1953181177, -1.5684660673, -0.6086485386, + -1.3542300463, -0.4276607335, 1.4777511358, 0.0993386284, -1.8139836788, -0.7365110517, 0.6629828811, 0.241477266, + 0.5044490695, 1.0643922091, -0.1175867841, 0.0788819045, 1.0972431898, 0.2484007776, -0.0112973209, 0.7241719365, + -1.8626170158, 0.0347400159, 0.1793256998, -0.8870456219, -0.0319259167, 0.818123281, 0.6993884444, 1.2714951038, + 1.4938253164, 1.2755190134, -0.7280711532, -0.0053603342, -0.6611225605, 1.2958151102, 1.1125426292, 0.0500253364, + 1.4127457142, 1.2092069387, -0.6113958955, 0.5983562469, -0.7948383093, -0.0255965069, 0.5676263571, -0.4503745735, + 0.8968400955, -0.5737510324, -0.8267991543, 1.5909577608, -1.5717008114, 1.0053443909, -0.1096132845, 0.4106061757, + -1.1032598019, -0.0910399705, -1.215747118, 0.9933787584, 0.3237740099, 0.1134621352, -0.1503658146, 1.2782334089, + -0.7552730441, -1.2234134674, -2.0203626156, 1.0978006124, 0.7394206524, 1.2319457531, 0.5734107494, 0.4472402632, + -1.949157238, 1.7882524729, 0.7341278791, -0.3616535962, 0.6778038144, -0.5595866442, -1.1381254196, 1.4615677595, + 1.6242483854, -0.5140312314, -0.2640652955, -0.0112548228, -0.3889789283, 0.6068689227, -2.8274755478, -0.008544514, + 0.490454495, 0.1616977453, 1.078925848, -0.061856363, 1.7721537352, 0.388766408, 0.9643759727, 1.4623794556, + 0.1064803451, -0.8805568218, 0.2923339605, 0.9559921622, 0.3187932968, 1.0508491993, -0.2954924107, -1.0405685902, + -0.0598033965, 0.9603899717, 2.1053576469, 1.3079080582, 1.2512524128, -0.6764339805, 0.4047291279, -0.8339336514, + 1.8518990278, 0.9332556129, 0.7688630223, 1.9514070749, -0.3171782494, -0.4678969979, -1.0559155941, 2.0887012482, + -1.8049836159, 0.0430028215, 0.3988151848, 0.4500122964, -0.2574366927, -0.3913790882, -0.6121475101, 1.0972211361, + -0.0593496226, 0.3291324973, -1.7988839149, -1.008338809, -1.6112517118, 0.1174412668, -0.3404005766, -0.4726842642, + -0.4491213262, -1.0615438223, -0.2107420564, -0.381773591, 0.2995887995, -0.9482329488, -0.2399285883, -1.4830079079, + 1.4051352739, 0.8220074773, 1.0181708336, 0.770584166, -1.4086661339, 0.1062365994, -0.3218088448, -0.0925237611, + -1.0620304346, 1.6652784348, 0.0058519463, 1.4551757574, -1.4438506365, 0.2192535847, 0.3335919678, -1.2820657492, + 1.2886893749, 0.3952491581, 1.1653424501, -1.0537530184, -0.0074237022, -1.2312995195, 0.4738241136, 0.2731259465, + 0.7465436459, -0.6233760118, -0.2805426717, 1.511051178, 1.1256532669, -1.1806602478, -1.3495339155, 0.3354279399, + -0.139137432, -0.8745224476, -1.7112647295, -1.4185328484, 0.168763876, 1.9717078209, 1.1529743671, 0.6822891235, + -0.4956736565, 0.0578047819, -0.718365252, 0.555143714, 0.347340852, 0.465367645, -1.8341126442, 2.2764511108, + 0.4477431774, -0.6344168186, 0.5948296189, 1.5689496994, -0.1255524755, 0.9398848414, -0.4700069427, -0.0290891398, + 0.9742378592, -0.8186925054, 0.4190974534, -1.6216185093, -0.3389663696, 0.5089208484, 1.5303941965, 0.3098924458, + -0.7619076371, 0.3587762415, -1.3091235161, 0.8170292974, -0.6985152364, -0.1834008396, -0.1097707674, 1.0684025288, + 1.367328763, 0.0024511134, -1.0490896702, -3.0076134205, 1.4514784813, 1.2511434555, -0.0860626996, 0.5120401382, + 0.6248494387, -1.5006062984, 1.89496696, -0.7988373041, 0.0659881309, -0.2443456352, -0.5105406046, -0.2946806252, + 0.8995938897, -0.6719914079, -0.9645525217, 0.4793780148, -0.3133210838, -1.4314814806, -0.994477272, -1.4454166889, + 0.0671993122, -0.5245435238, -0.3248140812, -0.0862735212, -1.2868779898, -0.206996873, -0.8418411613, -0.809877038, + -0.0245797615, 0.2288850546, 0.4888761342, -0.9548777342, 1.2134466171, 1.6297017336, 1.0540798903, -3.5775067806, + -0.5092924237, 1.5152270794, 1.3439284563, -1.3064225912, 0.5239573121, 0.637137711, -0.5815712214, 1.4705703259, + 0.2761515379, -2.2635154724, 0.8119996786, 0.2082707137, -0.3286717832, -0.2771964967, 2.2118780613, -2.1735358238, + 0.1249354333, 1.4037474394, -1.4499368668, 0.3003337979, -0.5304105282, -1.7573840618, -0.6856645346, -0.5914506912, + 0.7638018727, -0.2675991952, -1.0980226994, -0.4089368284, 1.1221373081, -1.0884951353, -0.6319181919, -1.2549594641, + 0.7170437574, 0.0045071896, -0.6356463432, 2.3410551548, 0.8706154227, 0.5790865421, -0.8792712092, -1.1271067858, + -1.8982055187, -0.6447094083, -1.5107764006, -1.7840856314, -0.5934742689, 0.6970037818, 0.813023746, 1.6075373888, + -0.1049850583, -0.2260528356, -0.8203536868, -0.2570720613, -3.0439462662, -0.831746459, -0.0221328903, -0.7338784933, + -1.195512414, 2.2275626659, -0.6152293086, 1.0770606995, -0.8655061722, 1.4497618675, -0.208034873, 0.0465875715, + -0.6258221865, 1.1146214008, -0.4552742243, -0.5624456406, 0.8417857885, -0.514264524, -0.2130188048, 0.2848901749, + -0.40789029, 1.4543926716, 0.9406331182, -0.4867027402, 0.076703608, -0.2662543356, 1.5841546059, -0.037182875, + -0.3927924335, 0.5836333632, 0.7966336608, -1.4907039404, -0.7028891444, -0.7504969239, -0.7478713393, -0.9128293395, + 1.1214281321, -0.9350854754, -0.4669199884, 2.3918759823, -0.2142266184, 1.8552978039, -0.9463956356, 0.4829190373, + 1.2582088709, 0.4328311682, 1.1292302608, 0.3805397451, 1.2985144854, 0.6846257448, 1.6851937771, 1.7153955698, + 0.8266667128, 0.3266970515, -0.9034817815, -1.9895290136, -0.1561795175, 0.7916913629, 1.231318593, -0.0866586864, + 0.8667936325, -0.9921289086, 0.2599111497, -0.5031987429, 0.2345968187, 1.1069636345, -0.6858910918, 0.6509312987, + 0.8513160944, -2.5334670544, -0.0781184584, 0.6531443, 0.220220834, 1.1924302578, -0.0056578512, 0.9925175905, + 0.4677110612, 0.4470631778, -0.7054750323, -0.3973045945, -0.4325635731, -0.6860013008, 1.0001733303, -0.9480412006, + -0.8789937496, 0.6653664112, -0.6843322515, 0.8633398414, -0.5817058086, -0.6112054586, 0.844810605, 0.6149102449, + -1.7258707285, -0.2807382941, -0.1708089411, 1.5577105284, -1.2645984888, 0.9760804176, 0.5516930819, -0.5967000127, + -0.3854245543, -0.1739615947, -0.0207591373, -1.2616332769, -0.4005171359, 0.3221673667, -0.2869417071, 1.0295534134, + 0.1294983327, 0.6947427392, 1.2161408663, 0.9053342938, 1.4678857327, 0.9029391408, 0.5970921516, 0.7944867611, + 0.4798160493, 0.5198258758, 1.2812861204, -1.1480890512, -0.0881863534, -0.2476950139, 0.4717128873, -0.6225486398, + 0.2505447567, -0.6700253487, 1.4420573711, -1.6963062286, -0.7611740232, 0.6617693901, -0.008676515, 0.5258134604, + -0.1621825248, -0.6918660998, 0.7783997059, 0.0281068888, -0.164178133, -2.5166752338, -1.4063049555, -0.4924475551, + -0.6959780455, 0.9172568917, -0.5700587034, -1.983541131, 1.5791540146, -0.4925122857, -0.0458450317, -2.0372576714, + -0.908788383, -0.6633548141, -0.7705920935, -0.3299379647, -1.0611827374, -0.1742917597, 1.025967598, 1.1829209328, + -0.9411280751, -1.0046323538, -0.7954505086, -0.466668725, -0.1476753652, 2.2875802517, -0.2079681754, -0.2876192033, + 1.2012648582, 0.6918829083, 0.0862621292, -0.7218672037, -0.0940898657, 1.8701169491, -0.0919047073, 0.4451364577, + 0.5785190463, 1.0394281149, 0.4340084791, 0.6246455312, -1.7443118095, 0.0707430169, -0.2417886257, 0.6761582494, + 0.2193481177, 0.0652367175, 0.2281389534, -0.1589985937, -0.0161593799, -1.1481174231, -0.8527640104, -1.998721838, + -2.2161722183, -1.1947005987, 1.86457932, -0.5195894241, -0.7349023223, 0.1043193266, -0.7930381894, -0.5610723495, + 0.955989778, -0.1279041469, -0.0052697291, -0.2292125374, -0.8965917826, 0.1681797057, -0.5898171663, -0.3136174977, + 0.353279233, -0.873450458, -1.3299645185, -0.7033492327, -2.1503171921, -1.2717120647, -1.088821888, -1.3648161888, + -0.1491083056, 0.5447972417, -1.782443881, 0.6282010078, 0.1593699604, -2.5262157917, -0.7317644358, 0.6677094698, + -0.2354516834, -0.7564174533, -0.0117295058, 1.3500658274, 0.6012318134, 0.6721284389, 0.4980325699, -0.7003022432, + 0.5756027699, -0.5126936436, -0.0571699105, -0.7423155308, -0.8981233835, 0.427296102, -0.0257868152, 0.8800768852, + -0.8634132743, 0.458640635, -1.4525709152, 1.0027289391, -0.2363725603, 0.7175219059, -0.8529829979, -0.4932558239, + 0.1452093124, 0.346465677, -0.5518008471, 1.5215642452, -0.3498942256, -0.8275839686, -1.7511603832, -0.5457261801, + 0.8822903633, 0.0703879967, -0.9963659644, 1.2804361582, 2.6976993084, 0.4033238292, 0.8038191795, 1.2802057266, + -0.2588358521, -1.165039897, 1.1707892418, -0.5047108531, -1.0936511755, 0.5469737649, 0.0263632089, 1.075976491, + -1.0194599628, -0.373452872, -1.9364116192, 0.0224650707, 1.0462511778, 0.4847756624, 0.1901340932, 1.2200636864, + -0.5608323812, 0.05201957, 0.0540600084, -1.313344121, 0.360401392, 2.1903557777, 1.2696301937, -1.7450065613, + 1.4612462521, 1.1277128458, -0.9614953995, 0.15911524, -1.0061297417, -0.3439558744, 0.585534811, -1.4501737356, + 1.5458877087, -0.6284275055, 1.8623217344, -0.2068486512, 0.0354135484, 0.3395684361, 0.264277339, -0.7321042418, + -0.5713635683, 1.0891259909, 0.3595553041, -1.1960923672, -0.3504222929, 0.4999573231, -0.5098363161, -0.8443207741, + -0.3192293346, -0.4329998493, -1.4102517366, -0.2385727018, 1.1790127754, 0.2475124747, -1.006639719, 0.9068338275, + -0.5423150063, -0.3165667355, 1.6968829632, -1.1119974852, 0.4216455221, -0.8087496161, 0.1220505908, 0.1811276525, + 0.2846711278, -0.9815238118, 0.0810643435, 1.3072894812, -1.5053919554, 0.8824597597, -0.9424833059, 0.5472854972, + 0.1866397262, -0.3782856166, -0.6489279866, -0.196005255, -0.7824270725, 1.1514835358, 0.9470567107, 0.6862918735, + 0.4898491502, -0.2240593582, -0.508294642, 1.5246375799, -0.7205083966, -0.7252399325, -1.2068340778, 0.6562124491, + 0.8725742698, -1.3504531384, 0.2655869424, -1.1543271542, -0.3576900065, -0.3631928563, 0.0644443333, 1.0960409641, + -1.2485544682, -1.3851460218, 0.4644928277, 1.5118932724, -1.6827667952, -0.1037741601, -2.8227734566, -0.4538195133, + 1.8951827288, 0.2947148085, -0.4407174885, -0.6552804112, 0.883620441, -0.7145662904, 0.2673783898, -1.005392909, + 0.0218670834, -1.379629612, 0.3507533967, -0.2442570925, -1.0691617727, -0.7232266665, 1.7802512646, 1.4755240679, + 0.28321141, -0.1803559959, -2.427257061, 0.9166278839, -2.0436441898, -1.2705802917, 0.5730054975, 1.5823352337, + 1.0499491692, -0.0399254858, 1.3576145172, 0.5052609444, -0.0344939381, 0.751506269, 0.9314097762, -1.3302785158, + -0.2806506157, 1.6494643688, -0.6945965886, 1.4947701693, 0.5611131191, 0.1360976994, 0.1329657882, 0.6428858638, + -0.8688668013, 0.5326808691, 0.1221128181, -2.017387867, 0.2001792789, -0.4099375308, -0.6947799921, -0.2808746397, + -0.1188127324, -0.5621849895, 0.1748513132, -0.6217819452, -2.3000860214, 1.0840605497, -0.7496613264, -1.5219525099, + -1.7810281515, -0.8950442672, -0.0703199431, 0.3249710202, 0.4448671937, 0.0597899482, -0.3028272986, -0.843675673, + -0.9046571255, -0.3266875148, 0.4347041845, 0.3949435353, 1.1973904371, -1.1560224295, -1.0398107767, -0.0699188486, + -1.4301743507, -0.0146584222, 1.3570151329, -1.6681015491, 1.2011176348, -1.062915802, -0.2667770386, 1.9444168806, + 0.8705314398, 0.1332209855, -2.6169438362, 1.2772220373, 0.4033893347, -0.6000118852, -0.9993430972, -1.0177826881, + 1.3402198553, -0.4007156491, -0.1191185564, 0.4988934398, 0.0814124867, 1.3495470285, 0.2988345027, 0.5763264298, + -0.2183794379, 0.4989469051, 0.3067570627, -0.2668756247, 0.0877958536, 0.508592546, 1.4055000544, 0.6140383482, + 0.0896825865, 1.3617206812, -0.3267118037, 0.6306826472, 0.6890478134, 1.1796201468, 1.0196118355, -0.5822272897, + -1.0949366093, 0.0220815465, 1.0912129879, 0.8769557476, 0.9900035262, 0.9397202134, -0.0994466692, 1.6669824123, + 1.4517176151, 1.3211481571, 0.2491372228, 0.0155243585, -0.6893531084, -0.1140175387, -1.8416621685, -0.2381248474, + 0.7401183844, 0.3654841483, 0.2882166505, -1.0167877674, 0.7473244667, -0.1891875267, 0.980866015, 0.9236414433, + 0.6881241798, 0.0554025508, -0.0573162176, 0.5692203045, 0.7792938352, 0.6142871976, -0.628834188, 0.2108489275, + -0.3727882206, -0.4873711467, -0.3820485771, -0.3673192561, 1.5540332794, 0.2947099507, -1.5285689831, 0.3804260194, + -2.0671718121, 0.0550171919, 0.8531175256, -0.6018936634, -0.8865386844, -0.556874454, -1.4733337164, -0.8281208873, + 0.3987645507, -1.1531097889, -0.1092760414, -0.9467664361, -0.7997373939, 0.322039634, -0.3594762981, -1.180349946, + -1.3892723322, 1.6811511517, -0.2709219158, -1.3034292459, -1.0962494612, 0.1192781776, 0.3181969225, 0.6427437663, + -0.4708162844, -1.8047537804, -0.1646451503, -0.2703527808, 0.6318225265, -0.4536555111, 0.1989347637, 0.8032560945, + -1.3178848028, 0.616630733, 0.2845878303, -0.9893379807, 1.2858288288, 0.7459064722, 0.917275548, -0.4152849317, + 0.612734437, -0.1464545727, 0.3386917412, -1.1799244881, 0.5358649492, 1.8083715439, -0.9430469275, 0.4336068034, + 0.8175193667, 0.6452999711, 0.8691123128, 0.2442887574, 1.809476018, -1.6751033068, 0.0677766576, -0.9925397635, + -1.0871496201, -0.2437263578, -0.4215831161, -0.1992474645, -1.310477376, -1.4547755718, -1.1687017679, 0.378120631, + 0.5475878716, 0.9851617813, 0.4662987888, 0.3638120294, 0.2394635975, 0.9616629481, -0.0387977324, 0.9407829642, + 0.0011507085, 1.8726496696, 0.1954480559, 0.4769034386, -1.0875762701, -0.7599243522, -0.8566319942, -1.9922207594, + -2.281298399, -0.2973401546, -0.5694825053, 0.0664883927, 0.4117467999, 1.1683961153, -3.0562281609, 1.761297822, + 1.7013229132, 0.2869657576, 0.0255660973, 0.315459311, -0.2584732175, -0.1614930183, 2.3610413074, 0.4873589873, + -0.5125331879, -0.3015183806, 0.36795941, -0.3626063764, 1.0938476324, -2.5488677025, -1.3180434704, 1.4499435425, + 0.7009496689, -0.1576300114, 0.404941082, 0.1778909564, 1.3396008015, -0.2206843495, -0.2286064029, 2.0505385399, + -0.4772749841, -0.062795952, 0.0254990458, -1.3595477343, -1.319052577, -1.0695114136, -0.6161350608, 1.0919641256, + -0.332131803, 0.7260578275, 1.1332423687, -0.2503430545, 1.1677489281, 0.7886906266, 0.2164149135, 0.7647698522, + -1.3076148033, 1.1607283354, 1.8137441874, 2.8209869862, -1.18296206, 1.2793636322, -0.4161130786, 1.4560747147, + -0.8382224441, -0.2064589411, -0.3601056635, -1.9282368422, 0.2948355377, 0.6405059099, -0.9806084633, 0.027497422, + -0.4893453717, 2.7329032421, 1.4204442501, 0.6902386546, -0.443839848, 0.8475421071, -0.8242413998, -0.2056256086, + 1.2381081581, 1.8283888102, -1.7836816311, 0.7437072396, -0.2981782556, 0.4307036698, 1.2446408272, -1.5674799681, + 1.7146155834, -1.9383628368, 0.3435726762, -1.5765607357, 0.0504746065, 0.8115888238, -0.3472369909, -1.1612019539, + 0.318633765, -0.6062232852, -0.7585208416, -0.5607734323, 0.5222164392, 0.7790774703, 2.6089880466, 0.6626429558, + -0.2798112035, 1.1184885502, -0.1381485909, 0.0895912275, 0.7735747695, -1.217576623, -0.2237391025, -0.1026925892, + 2.0417473316, 0.7975260019, 1.5041879416, 1.0822825432, 0.7253676057, -0.8952884674, -1.8488601446, 0.1530598551, + -1.9314616919, -1.6300439835, -0.8163452148, -0.5146376491, 0.5783777237, 0.0899859294, -0.2165891677, -1.5324651003, + -1.3432455063, -0.5275440812, -0.6659939885, 0.0604406931, -1.3241438866, -0.9218361974, -1.9925515652, 0.2451740056, + -0.3967302442, 0.1276450008, 1.2230695486, 0.0030670676, -0.2247872502, -0.0633816347, 1.469195962, 0.5458295345, + -0.5807732344, 0.937977314, 0.3422805071, 1.5076049566, 0.6746079326, -0.129007563, 0.5062861443, 0.1298588663, + 1.8845261335, 0.9324017167, -1.000831604, 0.1478935778, 0.5123214722, -1.5427743196, -2.1174151897, 0.0422072709, + -0.3248087168, -0.4121863544, -1.5678561926, -0.7964280248, 0.7105121613, 0.2873294055, 0.6519631743, 0.5355852842, + -0.6085993052, 1.1440550089, 0.971234858, 1.3347989321, 0.2167384177, -1.2789026499, 1.2023334503, -0.4959734082, + -1.8249573708, 0.3743883073, 0.0709712729, 0.2931367457, 1.6866817474, 0.1300894916, -0.158967793, 0.9902415276, + 0.104947336, 0.620898664, -1.75202775, -1.6000163555, -0.9802316427, 0.0425251871, 2.1325788498, -0.9563222528, + -0.4039032757, -0.6859712005, -1.1440685987, 2.8847551346, -1.4577374458, -1.6533602476, 1.5437217951, -1.6310477257, + -0.3676165342, -0.5928305984, 1.3807523251, -0.5501603484, -0.5219319463, -0.0825198963, -0.3111062944, -0.7352650762, + 1.171302557, -0.0221288241, 0.6046815515, 0.2135297805, 0.1448385417, 0.9258138537, 0.6199473143, 0.8385660052, + 2.1954982281, 1.4447660446, -0.2872459292, 0.2114256471, -1.0960211754, -0.819752872, -0.2152145207, -0.1540306658, + -1.6386111975, -2.5233354568, 1.2656054497, 0.9129872918, -0.6085659862, -0.6617404222, 0.6074315906, -1.9679963589, + 0.7266260386, 0.2714606822, 0.1947142482, 0.5195682049, 0.8111485839, 0.3197706044, -2.0950548649, 0.5762258172, + -0.8431512713, -1.2846280336, 0.9035053849, -0.3686189353, 0.817612648, 0.6898447871, 1.2300739288, 3.2548313141, + 0.9898021817, -0.7532128096, -0.9045040011, 0.5490559936, 0.8705734015, 0.7328756452, -0.8265963197, -1.5101081133, + 0.3340276182, 0.5381116867, 0.6491934061, -0.1450466812, 1.764580965, -0.7833189964, -0.5206372142, -0.3905070424, + 1.1084893942, 0.5302432775, -0.769215405, 1.2692584991, 0.9881228805, -0.5279560685, -1.0720012188, -1.6803950071, + -1.5877646208, 1.9102419615, 0.3213319182, -1.6464880705, -0.1613440216, 0.3271096349, 0.5641773343, -0.2901338339, + -0.6286158562, 1.0368025303, 1.4191545248, 0.3205574453, 0.8432882428, -0.4522081912, 1.1206735373, 0.9856461883, + -0.1103538498, 0.3788451552, 0.8254184127, -0.9615396261, -1.747684598, 0.3499236703, -0.8517538309, 0.7227854729, + 0.9791315794, 0.7726531029, 0.6913672686, -2.0398874283, -1.3073374033, 1.6918557882, -0.8667309284, -1.0342205763, + -0.3692653477, 0.5241845846, -0.4410466254, 2.1805980206, 0.5975066423, -0.6366894841, -1.4811692238, -0.3947469294, + 0.1086023152, 0.1037365198, -0.5710659623, 1.2462812662, 1.2071619034, -0.6543464661, 0.3778489232, 1.4369262457, + 0.8684048057, 0.9227760434, 1.9248412848, -1.0600451231, 0.5242900252, 2.4939887524, -1.4329419136, 0.5927869678, + -0.0053195218, 1.4319832325, -0.6679624915, 0.115429841, 1.2070343494, 0.1147793829, -0.6715605855, 0.0334689096, + 1.6597380638, -0.9170382023, -0.5053157806, 0.1027670279, 1.1581686735, -0.5237666965, -0.4403850436, -1.649627924, + 0.7673044205, 1.1748074293, -1.4838258028, -1.6586328745, -0.6399556398, -0.5451463461, 0.2890629768, -0.3449325264, + 0.566198051, -0.2247092426, -0.3704339266, 0.4762049317, -0.5505967736, -0.3622225821, 0.8294441104, -1.0188047886, + -1.3211250305, -0.5238136649, 0.071985811, 0.5811215043, 1.3551915884, 0.9022732973, 0.834820509, 1.7601321936, + -1.203556776, -0.1610284895, -0.6985741258, -0.8050824404, 1.6160351038, -0.263531059, -1.2230753899, 0.0442702919, + 1.4457842112, -0.2831886113, -0.552220583, 1.8225749731, 0.5256469846, -0.0092465924, -1.1489993334, 0.7133934498, + 0.7125946283, 0.4428358972, -0.2494825572, -0.8214784861, -0.3348659575, 1.7764191628, 0.3546428382, 1.4700632095, + 1.054256916, 2.1549079418, -1.7109314203, -0.4482811987, -2.1268780231, 2.0661754608, 0.1601428241, -1.0449494123, + -1.0156296492, 0.6733638048, 0.9290160537, -1.0412443876, 0.314900279, 0.7868452668, 0.8227619529, 0.152621761, + -0.1421793401, 0.6412929296, 1.3321976662, 1.2902623415, 0.0031562971, -1.4625291824, 0.280887723, 0.5652723312, + 1.1053085327, -1.2109456062, -0.3344887495, 0.9515791535, -0.9712296724, -0.4897898436, 0.5153864026, -0.5969720483, + -0.2086329162, 1.0944644213, 0.1678696126, 1.6910209656, -1.6885894537, 0.8107523918, -0.1487727761, 0.824105978, + 2.5300707817, -1.1119675636, -0.0557166263, -0.9830359817, -0.021858409, 1.2924665213, -1.5760532618, 0.2903743386, + -0.0360350795, 0.1165624261, 0.524497509, -0.1452632844, -0.7145482302, 0.9750678539, 0.4187014699, -0.1647199988, + 0.0827688649, 2.8011438847, 1.1906450987, 0.5398116112, -0.6014398932, 0.4039287567, 0.272762835, 1.3142924309, + -0.5986911058, 0.3755066097, 0.3850517273, 0.5240681767, 0.1509334147, -0.2982423306, -0.9690389037, 0.1482082903, + -0.5794170499, 1.1058530807, -0.665997088, 0.5248563886, 0.6544551253, -0.1016000733, 1.7019340992, 0.1335662603, + -0.3516343236, 0.7148193121, 1.2314994335, -0.9258267283, 0.0363452137, -1.1703430414, 1.7012137175, 0.2636000216, + 2.5404133797, -0.0304493718, 0.4889936447, 0.737637639, -0.383120954, 1.7555421591, 0.2273544669, -0.8490986824, + -0.1827587038, -0.7989795804, -0.8379164338, -2.0694205761, -0.5316456556, -0.2463656515, -1.363168478, -0.7051585317, + -1.6138539314, 1.3198417425, 0.3702345788, 0.0753858536, -0.0132740363, -0.9950203896, 0.6775140762, -1.5192737579, + -1.1931970119, 1.0480457544, 1.0526509285, -0.2511567771, -0.2708320022, -0.9000599384, -1.0730860233, -0.8332417607, + 0.6814241409, -1.1012221575, -0.5161744356, -1.9944025278, 0.5473926663, 0.2162017673, 0.6118625402, 1.6970700026, + 0.9290080667, -0.6630474329, 1.9621838331, 0.6916124225, -0.5143244863, 1.3465787172, -0.1014270186, 1.6098065376, + -0.4065241218, 0.2456360906, -1.0644011497, -0.6824391484, 0.9376380444, -0.4972450137, -1.3954156637, -0.7931784987, + 0.3863891661, -0.5077642798, 0.1169658527, -2.2643694878, 1.2981832027, -0.0722546279, 1.3718563318, -0.9511761069, + 1.163454771, -2.4079461098, -0.2811202109, -1.4747558832, -0.796032846, 1.6813354492, 0.1580020636, 0.4906089008, + -0.6557968259, 0.1914050281, 0.819614172, -0.5575736165, -0.1627945155, 0.2597014308, -0.4878998101, -1.5364331007, + 0.8920765519, 0.1526391953, 0.2662674487, -1.8847845793, 0.3603782356, -1.0658118725, 3.2456190586, 0.2545815408, + -0.0740487799, 1.0587692261, 0.4594543278, -1.2144246101, 0.8521980643, 0.1920867115, -0.6966613531, 0.9356654286, + 1.4123430252, 1.9032716751, -1.1575750113, 1.2239912748, -1.3523010015, 1.3675932884, 0.0028783996, -0.1164716333, + 0.0636274517, -0.1263964623, 0.6503781676, 0.4069949985, 1.0436509848, -1.474306345, 0.1385995448, 0.1789027303, + 0.0112371799, 0.2460647076, -1.1011744738, -0.5300943255, -1.6115192175, -1.9061876535, -2.5654923916, 0.0496643037, + 1.0157072544, -0.2320692241, -0.2537081838, -1.9836074114, -1.2122704983, -0.8500339389, 0.1666402519, -0.5580587983, + -0.7058231831, -0.63479954, 0.2047363073, 0.2284586877, -1.129953146, 0.7173625231, 1.1171007156, 1.0772426128, + 0.017743377, -1.2954846621, -0.5299506783, -0.5749281049, 0.5966389179, 2.7219719887, 0.6849224567, 0.8479590416, + 2.0062556267, -0.0862625539, 0.9452161789, 0.804523468, -0.3388015628, -0.2429846227, 0.6233448982, 1.2148296833, + 0.1562897563, -0.3656148314, 0.1104548946, 0.9932194352, 0.5684428215, -0.9437820315, 1.0924483538, -1.5989911556, + -2.0403063297, 0.8947772384, 0.3354680538, -0.8832319379, -0.9793969989, 1.6826566458, -1.0103543997, -1.2948708534, + 0.0603040457, -0.3768114746, 0.6062066555, 1.3397293091, 0.4506835639, 0.4326622188, -0.4533344805, -0.397192657, + -0.6595103741, -2.4956014156, 1.7504210472, 1.3513900042, -0.608001709, -1.0249046087, -0.1988066733, 2.139329195, + -1.8256448507, 1.2898792028, -0.9707172513, -0.6307196617, -0.329293102, -1.3354488611, 0.3118260503, 1.2624188662, + -0.3525214195, 0.0506781153, 1.5740100145, 0.916574657, -0.3342539668, -0.2621529996, -1.2329554558, -1.5453443527, + 2.1995866299, 0.6019462943, -0.3987810612, 0.5707879066, -0.4209889472, -0.004814201, -0.0332821496, -1.5761977434, + -2.1236410141, 0.4128189087, -1.1925446987, 0.4046672285, -0.3922690153, 0.9129861593, -1.204282999, -2.5270962715, + 1.1464778185, -1.040910244, -0.2294565439, -0.1564095914, 0.209813118, 0.4423882961, 0.6708213687, 0.0011970691, + 1.3835297823, -2.1146876812, 0.4195026755, -0.5974859595, -0.7789434195, -1.1835699081, -0.4481227994, -0.5926176906, + -0.5601764917, -0.2906090021, -0.0740258768, -0.4800468087, -1.0527486801, -0.7800763845, 0.300028801, -0.3290872574, + 0.9112530947, 0.1389426142, 1.1165764332, 1.5068144798, 0.5325995684, 0.4274400175, 1.1449474096, 0.7173746228, + 1.2336890697, 0.61687994, -0.5105078816, -0.4883999825, 0.2610085905, -1.3890395164, -0.2097653002, 0.1856197417, + -0.8605422974, -0.3273102641, 0.2982771695, -0.0288848169, -0.9086425304, 0.3567273021, -0.5856960416, 0.7619949579, + -1.1993529797, -0.4374361038, -0.0871637315, -0.837031424, 0.2818605304, 1.314558506, -1.1522951126, -0.1624574959, + 2.4466850758, -0.2131539136, -0.3643190265, 1.1231597662, -1.4967659712, -1.3696490526, 2.5906090736, -0.8502928019, + -0.0154352458, 0.0708632097, -0.0892392695, 0.9884635806, -1.4502840042, 1.9888542891, 0.0451550037, 0.202586323, + -0.3004295826, -0.0864960775, 0.2483033687, -0.1879534423, -0.3177562356, -0.572850287, -1.3048775196, -0.5676960945, + 0.9221876264, 1.3602030277, 0.2550102472, 0.5108075738, 0.6118447185, -1.2540539503, 0.7811601758, 0.13378416, + -0.5227097869, 0.6001027226, -0.5171794891, -0.4444061518, -0.9055517316, 0.3879831135, -0.377622813, -1.8549275398, + -0.4994918406, -0.5876417756, -1.6503987312, -0.2694072723, 0.9541515112, -1.4059816599, 0.6579794884, 0.800834775, + 0.8226274252, -1.1246813536, -0.0056366222, 0.5829159617, -1.517115593, -0.2439792901, 0.2839211524, -0.7109612823, + -0.727260828, 1.2907973528, -2.4604752064, 0.2687241733, -1.1931895018, 0.1179150194, -0.2157852799, -0.2656730711, + -0.8884975314, 0.7275415659, 0.2283545136, 1.6116662025, 0.7428886294, -0.0892703235, -0.0904256403, -0.1552596092, + 0.4787852466, 1.3613634109, 0.1748903543, -1.6370717287, 1.079022646, -0.1739098728, -1.0114746094, 1.4560087919, + -1.9859833717, 1.3460286856, 0.1526861787, -0.4367708862, -0.4582619667, 0.9152957201, 2.746291399, 0.1391252726, + 0.7504043579, 0.7596225739, 0.5596187115, -0.0583412908, 1.6963244677, -0.3965150118, 0.1869936138, 1.8145555258, + -1.3269416094, -2.2988479137, -0.5298420191, -0.8341919184, -0.8106333017, -2.5397062302, -0.0860494003, 0.4506426752, + -1.2943652868, 1.0642453432, 0.9367136955, -0.1269537657, 0.5206781626, -1.1788055897, -0.092521131, 1.0476361513, + -1.2335727215, -0.2922436893, 0.0496872887, -0.2639459372, 0.3845275939, -0.1538703591, -0.1169964671, 0.1776241362, + 0.6594055295, -0.5636582971, -0.9561285377, 0.4923869669, 0.240978837, 1.6332099438, 1.9169098139, 1.1394318342, + -2.5501418114, -0.3268522024, 0.9455291033, -2.0710549355, -0.1209253818, -0.9449245334, 1.5542948246, -0.2254855931, + 0.5607367754, -0.4980247319, 1.2718555927, -0.9843304157, -1.6917517185, 0.3631607592, 0.2028281391, 0.0599766299, + -0.0586545616, 1.1578779221, -0.1312680691, -1.6256289482, -1.0176999569, -0.1003823131, -1.0121793747, -0.4727144837, + -0.5200366974, -0.2728419602, -0.4269649386, 0.7875617146, 0.9885934591, -0.4017859101, -0.0173298735, 0.6428719163, + 0.4834312797, -0.2587702572, -1.1848987341, 1.4192327261, 0.1049401015, -0.3738996387, 0.7806690931, -0.6665983796, + 0.0297318734, 1.0643459558, -0.3537979722, -1.3078233004, 0.7726968527, 2.1866788864, -1.1002861261, 0.1728644818, + -0.375693351, -0.9906257391, -0.8670617938, 0.2038979679, -0.4590037465, -0.9317319393, 0.1539378166, 1.7603360415, + -0.7288731337, -1.2079353333, -1.7485420704, -0.2674083114, -0.7923513055, 0.8678576946, -0.8161421418, -0.5595346093, + 0.5180754662, -0.5601761937, 1.9338699579, -0.2529518902, -1.1536580324, 0.8240326643, -0.2938970327, -1.0393499136, + 0.0384243019, -0.1298382133, 0.6317511797, 0.9699698091, -1.261436224, -0.3775847554, -0.3486490548, 0.2697852552, + 0.713858664, 0.1024048105, -2.2221372128, 0.0392785184, 0.5322803855, -0.3420674801, -0.3462099135, 1.7591598034, + 1.8691898584, -0.1903523058, -0.5461303592, -1.8728995323, -0.3152549863, -0.1878576875, -0.8418833017, 0.4303056002, + -0.0654961094, 0.3263684511, 0.5223084092, -1.4092383385, -2.714145422, -0.6595085263, -0.6816119552, -0.3690533638, + -0.3258565962, -0.6590272784, -1.3374688625, 0.2712288499, -0.533549428, 0.3359538317, -0.5624163747, -1.7754486799, + -1.3497921228, 1.7255154848, 2.089174509, -0.1147161946, -0.4825686216, 0.1295297593, 0.3011428714, 0.9685909748, + -2.6775097847, 2.0935235023, 0.5985561609, -0.5186195374, 1.1494662762, 0.0178137068, -1.7103466988, 0.0695706159, + -0.4838339686, -0.6910316944, -0.3891272545, 0.4077689052, 0.1103762239, 0.3082531989, 1.6875544786, -0.8012143373, + -1.2962436676, -1.1299370527, 0.8236520886, -0.2105285227, -0.0350589901, -0.1153961793, -1.2768372297, -0.4285729825, + 1.0847262144, 0.7416942716, -0.3530087173, -3.1282429695, -0.9469532371, -0.6899254918, 0.8435842395, -0.286172092, + -0.3562988639, 0.2356502563, -0.5722347498, 0.5325630903, 0.2162115574, -0.2787752151, 1.9393185377, 0.2387497127, + -1.0231500864, -0.1833423823, -1.3151319027, -1.1783853769, -0.8859948516, 1.2054790258, -0.5636700988, 0.4386736155, + -0.6196897626, 0.8047269583, 0.1394855082, 1.4760224819, -0.7151355743, -0.3518398702, -0.6956925392, 0.4250043929, + 0.1587561816, -0.8085920811, 0.9429353476, -0.4326693714, 0.8953675032, 0.9709054232, -0.9297704697, -0.1016962975, + -1.19359231, -0.9966936111, 0.2610221803, 0.0391289629, 0.8596969247, -1.1022953987, -1.3328871727, -0.3936585784, + 0.3379068673, 0.3390775621, 1.8913849592, 0.1280214936, -0.1877435148, 0.7314977646, 0.8108587861, 0.2118465602, + 0.5429373384, 0.2095481604, 0.0367294289, 1.3247373104, 1.1130683422, -1.1776549816, -0.1899321526, 0.9921732545, + 1.9340195656, -0.7474932075, 0.5622502565, 0.2565377355, -0.5058898926, -1.1801614761, 1.1046266556, -0.242071569, + 1.0296734571, -0.4392384887, -1.2390613556, -0.6452093124, -0.3723985553, -0.027325049, -0.8667244315, 1.2947559357, + 0.6697645187, 0.8879160285, 0.1957534999, -0.1988423914, 1.2720395327, 0.2759205401, 1.7492319345, -0.2943438888, + 1.1912611723, -0.0809823349, 0.0359159783, -0.4873678982, 2.9271998405, -1.178669095, 1.0902714729, -1.0070717335, + -0.055971045, 0.5503617525, -0.2708517611, -1.4462407827, -0.0244226474, -0.9263724089, 0.3695653975, -1.0758725405, + -1.0543339252, 1.0808296204, -1.3966062069, 2.2895793915, 1.8400338888, -0.5700233579, -1.0836747885, 0.74172014, + -0.2145137787, 0.5379716158, 0.3843903542, 0.0347256139, 0.3680998087, 0.3415450454, 1.0920809507, 1.0413075686, + 0.0939790681, 0.7268617153, -1.1950058937, 0.4225138724, 0.7281823754, -2.2234709263, 1.2858834267, -0.9244327545, + 1.6425834894, -0.8119661808, 3.3916356564, -0.2394975424, -1.2916408777, -1.2434978485, 0.1182641983, -1.0540636778, + 1.0878865719, 1.0936306715, 2.7451908588, -2.4534094334, 0.0842225254, -0.7882358432, -0.261031121, -0.1405747086, + -1.2278044224, 0.467020601, -1.5480242968, -1.0367826223, 0.1100453958, -1.6257070303, -0.6632278562, 1.64801085, + -0.3857504129, 1.3263442516, -0.7813788652, -0.2630614638, 2.234749794, 0.0668686181, 1.6011503935, -0.2215524614, + 2.5348920822, 0.66281569, 0.6786739826, 1.7699764967, -1.7675346136, 2.8429641724, 1.7460889816, 0.1622756273, + -1.2240581512, 0.9790400863, -0.4723766446, -1.2521955967, 0.106891565, 0.24673599, 0.4016210437, -0.4117667079, + -0.4852364361, -0.0951911286, 0.6827812195, -0.2690612674, 0.6709222794, -0.4353961647, 0.8948027492, -1.9490350485, + -1.0914882421, -0.3209503293, -0.2963206768, 0.433911413, -2.2697405815, 1.220159173, -1.8413844109, -0.3661860824, + 0.7219944, -0.9503106475, 0.6586489081, 0.0980350003, 1.0423717499, -0.4973531961, -0.5744463801, -1.3544663191, + 2.0338106155, 0.0617796816, 0.591212213, -0.7075412273, 0.0460111462, 1.2361793518, 1.725744009, 0.7506306171, + 0.5277210474, 0.6417139173, 0.3805473745, -0.9311766624, 0.9438769221, -0.8593149185, -1.7188237906, -1.4166681767, + 0.7779759169, 1.1453680992, 0.2659092546, -0.7271529436, 0.1307234317, 0.7076218128, -0.6337662339, 0.8103998899, + -0.7279103398, 0.2717936635, 0.5227202773, -0.8961473107, -0.1444521397, -0.7144158483, -1.468411088, -1.8797703981, + 1.4193205833, 0.2078864872, 0.7992144823, 0.032060083, 0.8656871319, 1.2021867037, -1.216771841, 0.8329434395, + 0.1805313081, 0.3732955158, -0.646549046, -0.9415496588, 1.2734313011, -0.8172774911, -0.9249973297, 0.1996483356, + 0.4317770898, -1.0799595118, 1.4785776138, -0.0096156178, -0.8270172477, -1.0379046202, 0.2136165649, 1.1392287016, + 1.2750461102, -0.8241134882, -0.2134141624, 1.7874548435, 1.2697911263, -0.7215440869, -1.2200564146, 0.7094538212, + 0.2863227427, -0.0210470576, 0.3863923252, -0.3042067885, 1.0375249386, 0.6831886172, -0.8644843698, -0.3198086619, + 0.482370764, -0.2265983522, -0.4702896476, -0.5963839889, 0.9628387094, -0.3546466827, -1.3467926979, 1.0188089609, + -0.8363088369, -0.0953657553, -1.3766548634, 0.5656586289, -0.4472826719, -0.6763988733, 0.9349191189, -0.8283550143, + 0.5968904495, -0.5544840693, -0.1959493458, 0.0332162529, 0.4148295224, 0.0375486575, -1.0577303171, -0.9384614229, + -2.066775322, 0.4751504958, 1.048774004, 1.3003197908, 0.3228363395, 0.2529530525, -1.1515924931, -1.2190105915, + -0.9456254244, -1.188046217, 2.6874439716, -0.3045670986, -0.701410234, 1.5996931791, 0.3379813731, 0.9407749772, + 1.1743144989, 0.9814895988, -0.3301385045, 0.7717459202, -0.2328396291, 0.9203398228, -1.0166190863, 0.046233166, + 0.0152617535, -0.0070052808, -0.6647570729, 0.5429480076, -0.5906264186, -0.0308912378, 1.0884922743, -0.0040217643, + -1.153392911, -0.1063377857, -1.0902687311, -0.0371520258, -1.8188394308, -0.7905772328, 0.1596994698, 1.1226239204, + -0.6813367605, -0.1751530617, -0.0979226381, -0.8810763955, 1.1648347378, 1.3413946629, 1.1284626722, 0.5128263235, + 0.0187418163, -2.0666255951, 1.0853357315, 1.0145881176, 0.6455498338, 0.3209685683, 0.5687319636, 1.0641225576, + 1.4271905422, -1.3905673027, -0.9891104698, 0.0020802424, 2.3130781651, 0.6045076251, -0.8978734016, -0.3523695469, + -0.974142611, 0.3125937879, -0.1361470819, 0.7558745146, -0.6038464308, 2.2138009071, 0.2676672935, 0.4894275367, + -0.164646104, 0.2514430285, -1.4151527882, -0.1414795518, 0.3838063478, -0.8808335662, 1.9905422926, -0.3512460887, + -1.5725287199, 0.7633091211, 0.000013141, 1.6761398315, -2.1059546471, -0.3404865861, -0.5632696152, -1.5203379393, + -0.5280867219, -0.7296812534, 0.6876379251, 1.4581366777, -1.1583836079, 0.6405873895, -1.0695174932, -0.1391310841, + 0.7101902962, -1.3572121859, 0.1433014721, 0.6498459578, -0.2396032214, 0.4949466884, -0.0583442226, 1.3597508669, + -1.1603624821, 0.9705311656, 2.1088654995, -1.7841472626, -1.5925489664, 0.4765196443, 0.7140438557, -0.2969127893, + -1.0004702806, -1.448751092, 2.0203588009, -0.4833310246, -2.337231636, -0.5886305571, 1.6995788813, 0.0083491514, + -1.0568113327, -0.1681756973, 0.7782428265, 0.6581347585, 0.0151447775, -1.6557891369, 0.8034425974, -1.0629384518, + 0.7985153794, 2.1845128536, 0.5347851515, 1.6842222214, -0.6536903381, 0.9090065956, -0.6756687164, 1.9171681404, + -0.0657464713, 1.3801714182, -0.5541518927, 0.2358659059, -0.1883283705, 1.0601769686, -0.2588506639, 0.4196306467, + -1.2001607418, 0.5803898573, -1.4160250425, 1.7342479229, -1.1105753183, 0.071969837, -0.0096054645, -0.6200602651, + 0.1690012068, 1.243468523, 1.4427556992, -0.1093287393, 0.1923421919, 1.8308950663, -0.6960420012, 0.1550203562, + 1.0692973137, 0.2098853588, -0.3324133456, -1.273019433, 0.6015979052, 0.6712191701, 0.2805779576, -0.5934511423, + 0.9138393998, 0.0384552255, -0.0258487891, -0.88792032, 1.086712122, -0.2558456957, 1.340000391, 0.8616962433, + 0.9091723561, 0.3765018284, -0.0544774011, -1.1591389179, -0.1942774951, 0.9726710916, -0.9714103937, 1.3434149027, + -1.1338416338, -0.7891272902, -1.9806178808, 1.4280047417, -0.3443213403, 1.2054544687, 0.9668977261, -0.4083234668, + -1.2918647528, -0.6399744153, -1.3426039219, -0.5441907644, -0.0543023236, 0.1115766466, -0.4973062575, 0.0533691123, + -1.0189346075, 0.0490081087, 2.0632190704, 0.9324282408, 1.4523895979, 0.5729588866, -0.4189784825, -0.3286801577, + -1.1514205933, -0.880779624, 0.2938400507, 0.7655924559, 2.136608839, 0.0733786449, -1.6295683384, 0.177569285, + 0.8521859646, 0.4896481931, 0.5674389005, 0.2375758439, 0.0813688114, -0.6042775512, -0.5440589786, -1.2309296131, + -1.4950492382, 1.4114691019, 0.4880595207, -1.9063181877, 0.328184545, -0.397454977, 0.2618822157, 0.7912273407, + -1.7842062712, 1.4989305735, -0.2391272038, 3.0528898239, 0.3499550223, -1.4347679615, 1.0079482794, 0.4206511974, + 0.6000564694, 0.1201554537, -0.5846073031, 0.3514090776, -0.858854115, -1.0708264112, 1.9690668583, -0.0061912374, + -0.7901587486, 0.9585415125, 1.9639558792, -0.4290848672, 0.5445072651, 1.2167263031, 1.4984652996, -0.3440700471, + 0.3850102127, 1.1216851473, 0.6268048882, -2.3510096073, -1.3539459705, -0.0425043851, 1.0418293476, -0.2806175649, + 0.4425379932, -1.3477407694, -0.9427426457, -0.010152529, 0.9552149773, 0.2844652534, -0.0253380742, 0.4472802281, + -1.0420781374, 1.8255304098, -0.1858208627, -0.9919012189, 0.4774014056, -0.1065087095, 0.5237557292, 0.1012536585, + 0.4370443225, 0.4235878587, 0.6120776534, 0.66917032, 1.0026834011, -0.3116049469, -0.0213360675, 1.8255027533, + -0.4455459118, -0.0459221825, -0.7012569904, -0.1852261573, 0.5536851883, 2.1449239254, -0.189612478, -0.3305495679, + -1.0523796082, 0.5392750502, 0.7831043005, 0.3730578721, -0.1366892159, -1.0765298605, -0.440458715, 0.9915053844, + -0.05620794, -2.5473208427, 1.1598278284, -0.7649890184, 1.2011524439, -0.0606509931, -0.0063281334, -0.7450198531, + 0.6501030326, 0.2470915914, 0.3507081568, -0.8862549663, -0.6400193572, 0.8826782107, 1.1692306995, 1.7553559542, + -1.0607961416, 0.6163920164, 0.250528574, 1.2890933752, -0.5036508441, -0.5445509553, 1.3842186928, 0.3668037355, + 0.2400822192, 0.4661004543, 0.4137141705, -1.2596691847, -0.8630129099, -0.2596816719, -1.3117531538, 2.5076625347, + 0.8216830492, -0.830806613, -0.240257442, -0.3923582733, 0.2755875885, -0.8734244704, 0.0743628964, 0.1546310931, + -0.0208904427, 1.4379118681, 1.2219953537, 0.260266006, 1.0976809263, -0.079060182, 1.4060403109, -1.7074382305, + 0.1989279836, 0.7320793867, 1.0455595255, 0.898530364, 0.5794932842, 0.7482882142, 1.018142581, -2.1934535503, + -0.1195093766, -0.5527552962, 0.9271039963, 0.0382056795, 1.3007956743, 0.2055685967, 1.7423490286, -0.0785754547, + -0.0049815332, -0.0163416192, -0.4962151647, 0.100312531, -0.8750685453, 1.3657735586, -0.3143217564, 0.148693338, + -0.6111947298, 1.1490167379, -0.5325989127, 0.0778353959, -0.8201375008, 0.9185136557, 0.3281737566, -2.0297646523, + 1.1189615726, 1.0363020897, -0.2897744775, 0.3120375574, 0.7430668473, -0.1351819932, 0.2756820321, 0.2833786309, + 0.1408464015, -0.7921109796, 1.6592693329, 0.8912046552, -0.2330278158, -0.7310743332, -0.6375401616, 0.7888815999, + -0.5637577176, 1.5878105164, 0.5654777884, -0.7989003062, 0.652647078, -0.5024884939, -1.4605481625, 0.6715288162, + 1.0051063299, -2.2796263695, -0.0421458483, 0.5515695214, -1.6218701601, 1.2987296581, 0.1798663735, -0.5212946534, + 0.5497487783, -0.9817274809, -0.7634006143, -0.42528373, -1.6081527472, -0.574919343, -0.0845824331, 0.3179959953, + -0.8117060661, -1.260741353, -1.7419383526, -0.8477881551, -0.773632288, 0.0881378502, 2.0652372837, -0.6772291064, + -0.2555656135, -0.1456658989, 1.21359694, 0.633310318, 0.6250420213, -0.5774396062, 0.287956059, 0.8352848291, + 0.4350744784, -0.3484890163, 0.0795898214, 0.8474707603, -0.1157193184, 0.4633275568, -0.3415514231, -0.69899261, + 0.6122351885, -0.838819921, -0.7292807698, -1.0647550821, 0.4956947267, 0.1355170608, 1.2068425417, 0.2432746291, + -0.281750977, 0.229196012, -2.023509264, 1.2210216522, 1.1453696489, -1.3078383207, 0.5784826875, -0.1166832522, + 0.451825887, 1.1240378618, -1.8123457432, 0.6662940979, -0.9611188173, 0.731428206, -0.2969223261, -0.3550669253, + 1.4163671732, -0.9020425677, 0.019977266, -1.1304079294, 0.1079952568, 0.4287727475, -1.618398428, 0.6845467091, + 2.8033049107, -0.2084693313, 0.1491068602, 0.2246538848, -1.1328402758, 1.1970536709, -1.1747390032, 0.6738021374, + 2.5621573925, -0.6892337203, -1.5325818062, -0.872538805, -1.873180151, -0.8512567282, 1.2584059238, 0.6210688353, + 1.8926613331, 0.5126205683, 0.7967803478, -0.4531759024, 0.6966472268, -0.9069048762, 0.0096370932, -0.6075945497, + -0.7283154726, 0.5826425552, 0.2152446657, -1.2975306511, -0.5846914649, -0.4268600941, -1.0764298439, -0.7263673544, + 0.9428517222, -2.0351703167, 1.5888681412, 1.1721462011, -0.7234143615, -0.6291493773, 2.0337893963, 0.2800778449, + 0.0618867502, -1.0652469397, -0.1269562542, 0.0394340493, -0.2710518539, 1.149491787, 0.7313186526, 1.4539731741, + 0.4317398369, 0.1555168629, -0.6679779291, -0.6185320616, -0.4576709569, 0.8619299531, -0.3402082324, -0.0162530318, + -0.9234033823, 1.1426278353, -0.4658351541, 0.4760331213, 0.1220721081, -0.044911854, -0.7347796559, 0.4099939167, + -0.4844644368, 0.8656507134, -0.0493310839, -1.6068956852, 0.6101850271, 0.396155864, -0.5334519148, -1.2353732586, + -2.1528379917, -0.6461086869, -0.7687655091, 1.0920033455, -0.0443054624, 0.9873304367, 0.1205482185, -0.0901331529, + 0.2483174056, -0.0232608952, -0.9315232038, -0.4337712228, -0.7576855421, -1.4757883549, 0.4191368818, 1.0992763042, + -0.5225518942, -0.3033358455, 1.4686160088, 0.2693915963, -0.5548349023, -0.0744934976, -0.9019102454, -0.4306880832, + -0.4611977935, -0.8646348715, -0.9281977415, -0.2186366916, -0.7222694755, -0.5996643305, -0.7126638293, 0.9143796563, + -0.1718460768, -0.7571513057, -0.8897672892, -0.2077621669, 0.3679377139, -0.6376763582, 0.6803770065, 0.1529729366, + 1.6237425804, -0.7013158798, -0.7598114014, 2.4127118587, -0.061381463, 0.5617071986, -0.4261292517, 1.3765552044, + -0.1034885272, -1.5822913647, 0.2727092505, -0.439427942, 0.085513927, 0.5925198197, 0.9543700218, -1.3967151642, + 1.0356595516, 1.2689288855, -0.0545611903, 0.2998319864, 0.2138415426, -1.5542737246, -0.5578077435, -0.0780339167, + -0.718167901, 0.4998109639, -1.1115146875, -1.6112943888, 1.5544286966, 0.7367937565, -1.1129119396, 0.7780324817, + 0.4822565317, -0.8536413908, 0.4397369325, -1.3432642221, -0.9365406632, -1.238222599, -1.2970274687, -0.621432066, + -0.489356637, 0.1583636999, -0.2710636258, -0.145891875, 0.6112800837, 0.6005087495, -0.7187950611, 0.816907227, + 1.6199951172, -0.7268152833, 0.240435034, 0.2810488343, -0.4852738678, 0.992502749, 0.0956963748, -2.8951740265, + -0.3318829834, 1.3719614744, 0.5818605423, -2.0010683537, -0.4226765037, 1.0245097876, 0.7852441072, -0.4349224865, + 1.4291239977, -0.4860503674, 0.3763881922, -0.4843531251, -0.3523619175, 0.7469093204, 0.6595010161, -0.3882180452, + 0.9919152856, -0.2797157764, 2.4180109501, 0.0411199592, -1.805550456, 0.5286077261, 0.1346055269, 0.3227880299, + -0.3051802516, -0.3027456105, -0.0010736089, 0.4762355387, 2.2697131634, -0.3243034482, 0.1008412465, -1.4537488222, + -2.0363309383, 2.1591031551, 1.5303931236, -0.7778717875, 0.2341108471, 1.3119387627, 1.3180574179, -0.8847883344, + 0.5251903534, 0.2385541797, -0.3019807041, 1.0521885157, 0.0388435014, -0.1639668941, 1.707605958, -0.6597477198, + 1.3579747677, -0.7429273129, -0.0546745248, -0.1375604272, -0.9347351789, -1.1826816797, 2.0394957066, -0.4085650742, + 0.415129751, -2.3462462425, -0.3660867512, 0.262077868, 0.4003766775, -0.0485555828, 0.8496025205, -0.8509175181, + -1.4193309546, 0.8738920689, -1.3105102777, -0.1310589164, -0.0740571916, 0.193071425, -0.9857059717, -1.6849098206, + 0.4512572885, 0.1277438253, 0.3671044409, -0.13506639, -1.0645258427, -0.0029378785, -0.0521377474, -0.0649472773, + -0.6643292904, 0.5142106414, -1.7635880709, 1.6859691143, -1.0984498262, -0.7941613793, 1.1221563816, 1.3669830561, + -0.0905384943, 0.2765818536, 0.6256956458, -0.3617914617, -0.2852146924, 0.7979028225, 0.2126920968, 0.8998239636, + 2.2797007561, 0.2099189162, -0.3656977713, 1.4928067923, -0.4475935102, -0.4616768956, 0.2791537642, 0.2556216717, + -0.6943846345, 0.4273623228, 0.1741427183, 0.1316052079, 1.1936930418, 1.5984715223, 1.0562391281, 1.0298056602, + -1.2818797827, -0.8192679286, -1.9437376261, 0.6600036025, 0.0188401472, 0.4665989578, 1.4290597439, 0.785130322, + 0.2261232734, 0.7731981277, 0.5813441277, 0.5581420064, 1.3034487963, 1.0300573111, 2.0724573135, -0.7095886469, + -0.8896782398, 0.1834590137, 0.6919991374, -1.047991991, -0.9896458387, -0.2847566903, 0.7601591349, 0.5769826174, + 1.3861632347, -1.798169136, 0.5600209832, 0.1504398137, 0.6467001438, -0.3333204985, 0.288528949, -1.584713459, + -0.6807080507, -0.4037251472, -2.4674272537, 0.1292898357, -0.1086133048, -0.3344806433, -0.4761407077, -0.4093746841, + 0.8121746182, 0.9868445396, -0.4382044971, -0.7254872918, -2.4136452675, -0.317684561, 1.9473218918, 0.2170838863, + 0.2626359165, 0.1446496695, 2.986798048, -1.6840299368, 1.3493431807, -0.6842327714, 0.2324342579, 0.8585680127, + -0.6588760614, -0.3588640988, -0.3767255545, -0.5748527646, 0.2612748146, 0.1919667572, 0.9821797609, 0.4179340303, + -2.2200431824, 0.2395582497, -1.1190239191, 0.7308257818, -1.2480312586, 0.7303984165, -0.689825654, 0.3308303952, + -0.6568310857, -1.0560706854, 0.3887234926, 0.5087570548, 0.7185772061, -0.2959088087, -0.2250892967, 0.4436039627, + 0.7100724578, -0.3117805421, -0.721069634, 1.4668381214, -0.6216652989, 0.4426654875, 0.4567816257, -0.8505325913, + 0.8974496722, 0.8174543977, 0.4282577932, 0.8738188148, -0.38085109, -0.5091495514, 2.3714761734, 0.1522615403, + -1.2650282383, 1.3257935047, -1.489513278, 2.3313984871, -1.27929914, 0.7764997482, -0.7210823894, -0.1681635827, + 0.1529988945, 0.4695449471, 0.1967510283, 0.2921490669, 1.3127886057, -1.2193900347, 0.2852847874, -1.2616995573, + -0.7584261894, -0.1306209564, 0.9959502816, -0.8483362198, -0.6962991357, 0.3551653624, -0.228085503, -0.7159309983, + -0.3786600828, -0.4753340483, -0.1977416724, -0.9485037327, 0.329333365, 1.225736618, -0.1455384195, -1.4984012842, + -0.1919256151, 2.1786687374, -1.0019141436, 1.0610024929, 0.6823122501, 0.080049634, 0.9403626323, 0.5023782253, + 0.32142061, 1.618945837, -0.1983540952, 1.7617611885, 1.1387735605, -0.8849478364, -0.8603631854, 0.594263196, + 1.4637345076, -1.2320071459, 1.5357743502, -2.1328830719, 1.7089049816, 1.1534118652, -0.0069381776, 1.1776837111, + -1.5097141266, 0.2115106434, -0.1186552644, 0.1261516213, -0.3330809772, -0.1185161993, 1.160073638, 0.3577325046, + 0.7345383763, 0.7769987583, 0.7655192018, 1.6940709352, 0.6339361072, 1.0973848104, 0.4087703526, -1.7375053167, + -1.0483746529, -0.4302817583, 1.5430914164, 0.0006288328, -1.2928329706, 0.3590690494, -0.3027823269, -0.9697774649, + -1.5566012859, 0.514110446, 1.1575758457, -1.1170324087, 0.030596599, -0.1459143758, -0.7981154919, 0.4145491421, + 1.457115531, -1.3967839479, -0.0655855462, -1.0104351044, -1.1136292219, -0.1907861084, -1.8058137894, -0.2570574582, + -0.6587927938, -1.3274798393, -0.1549696177, 0.2305874527, -2.07422328, -0.0295557063, 1.3538379669, 0.3438618183, + -0.2380728573, -0.2246685326, 1.5747584105, 0.6863652468, 1.3693779707, -1.2951009274, 1.3435353041, 2.0449006557, + -1.6192568541, 1.7248616219, -0.1750580519, 0.3598082364, -0.8229542971, -0.9378738403, 0.109885551, -1.0314471722, + 0.0641856417, 0.67012918, 1.5685896873, -1.6793966293, 0.4545374811, -0.0591463894, -0.0386027545, 0.1191953644, + -1.2499835491, 0.9295192957, -0.54199332, 0.161977008, 0.1354142129, 1.5632513762, -0.3869238198, 1.2132548094, + 0.0554801188, -0.6512631774, -2.6216135025, -0.2254151106, 0.4330559969, -0.5367842317, -0.8901445866, -0.8257043958, + 0.5760731697, -1.5437245369, -0.7159849405, -0.957008183, -1.3737111092, 1.6673197746, 1.3580203056, 0.2791488171, + 1.0237982273, 0.9078584313, -0.8839287162, 0.0231411308, -0.3945089281, -0.2564010918, -0.5195775628, 2.2790925503, + -0.983974874, -0.114068374, 0.7237284184, 0.1794247627, 0.9464429617, -0.4277381003, 2.1282601357, 0.0217097141, + -1.7380595207, 1.3669571877, -0.2642624676, 1.5720680952, -1.8166810274, 0.5242646933, -0.8335030079, -2.0098788738, + -0.6536083221, 0.2945873141, -1.478299737, -0.1516771913, 1.1408663988, -1.4657688141, -0.3113844097, 0.7662166953, + -0.4563453794, -2.4438807964, -1.4533135891, -0.4236075282, 0.53185004, -1.8602722883, -0.6261865497, 2.0996797085, + -0.8635161519, -1.220408082, 0.4388450384, -2.0069413185, 0.2024406493, -0.8838145733, 0.0309155099, 0.7476049662, + 0.8999215364, -0.8639245033, 0.0988463908, -0.6415423751, -0.6678134799, -0.0940411165, -1.7194350958, -0.4066540897, + -0.4778663814, -2.6078004837, -0.9008126259, -0.2668288946, 0.7076120973, 1.3418669701, 0.4082632065, -0.4423490763, + 2.5291156769, -0.0829270333, -0.9171121716, -0.7369276285, -1.654784441, 0.3231929243, -1.0614206791, 0.3161898851, + -0.3398891389, -0.0626130924, -0.9866225123, 1.2956130505, -1.744633913, 1.8742061853, -0.0142730968, -0.3598657548, + -0.6989034414, 1.3945087194, -0.0364240184, -0.6663540006, -1.71806252, -1.2895328999, -1.8650425673, -0.2848217785, + -0.687266469, 0.6471204162, 1.3397916555, 0.3441358507, -0.6507552266, -0.0044669984, -0.5204245448, 0.3537707329, + 0.6218783259, 0.8653511405, -1.9395599365, -0.3520051837, -0.3968527317, -0.1872099787, 2.5866026878, 1.3923414946, + 0.4628205299, 0.0473618843, 1.5894398689, 1.1269013882, 0.328951478, 0.0482734181, -0.6642089486, 1.3771688938, + -0.0996530503, 0.3009798527, 1.1523993015, -1.0771466494, 0.8700125813, -1.5626024008, -0.1853292584, -0.4131501615, + 0.3208904266, 0.790494144, 0.1825299263, 0.0197186228, -1.1914066076, -0.9240799546, 0.8452393413, -0.1513461173, + -1.252669096, 0.1262753606, -1.6897244453, -0.4013103247, 1.9904233217, -1.3785617352, -0.0342551842, 1.2655111551, + 0.2004050314, -0.4384508431, -0.9500871301, -1.6665233374, -0.732057035, 1.6763832569, 1.4295755625, -0.240757823, + 0.8036060333, -1.8491408825, 2.9870183468, -0.6388540268, -1.883012414, -1.6932355165, 2.1526920795, 0.121680446, + -1.4847382307, 0.11243774, -0.0760384947, 1.3658516407, 1.2392852306, 0.0693709552, 0.2876286805, 0.0789157599, + -0.8022515178, -0.2305098027, 1.9006695747, 0.9412038922, 0.3962628841, 0.6482299566, -0.8974066377, -0.4834775031, + 1.2487920523, 1.1562736034, 0.6536567807, -0.3170304596, 0.2463564575, 2.417940855, -0.487822175, 0.8989579082, + 0.414928019, -0.3923274279, 1.286326766, 0.7034213543, -0.7199124694, -0.4644466341, 1.4654096365, 0.343274951, + -0.9306016564, -0.7491942048, -0.1750261039, -0.7223092318, 0.1536332071, -0.3865046799, 0.5169742107, -0.4115245044, + 1.6728409529, 1.1052545309, 0.250464499, 0.6183803678, 0.1082001925, -0.6866397858, -0.1700413972, 0.4843541086, + 1.3254795074, 0.1514006704, -0.2798740566, 0.4530131221, -0.1875061393, -1.5138655901, 0.2696782053, 0.3310975432, + -1.5183287859, -0.4288371205, -1.043377161, 0.3195703924, 0.2241828144, -1.7004652023, 0.8005896211, -1.3455075026, + -0.7087361217, -1.0131795406, 0.4448340237, 0.8383929729, 0.7657484412, -1.0465499163, 1.9463306665, 1.6850688457, + 1.6361572742, -0.4113813639, 0.820879221, -1.3112231493, -0.4735149145, -0.9699966908, 0.8628758788, 0.9517716169, + -0.973408699, -0.6572603583, 0.5387002826, -0.2033254206, 0.6137370467, 1.5639606714, 0.3512731194, 0.2677857578, + 0.1491088122, -0.685957551, -0.1748508811, 0.0057693808, 1.2078301907, -0.2483086884, -1.5793319941, -0.1355962008, + 0.5014082789, -1.3090702295, -0.990247488, 0.1836945713, 0.3580158055, 0.1922743022, 0.009568247, -0.228417784, + -0.5888280869, -0.9356576204, 0.5763784647, -1.0042114258, -0.3705872595, -0.2505876124, -0.7080980539, 0.1050026119, + 1.1257755756, -0.4953170419, 0.9546896219, -0.6923274398, 0.3183096647, -0.5688853264, -0.6310497522, 0.275006026, + 0.025487842, 0.2571436465, 0.5700058937, -1.7250375748, -1.4157315493, -1.4600043297, -0.8703076243, 0.065353632, + 1.1396144629, 1.4283490181, -0.6810770035, 0.5877169967, 0.1974487454, 0.0439355373, -0.547809124, -0.8501861095, + -0.1452676207, -2.0167658329, -0.1970911473, 0.070185937, 0.7894083858, -1.7675129175, 1.2736612558, 1.4884271622, + 0.5635340214, 0.6796386242, 1.2423328161, 0.0540213957, 1.3500727415, -0.2239092141, 1.495396018, 0.2478047758, + 0.5561262965, 0.2338157147, -0.1017286703, -0.3675415218, -1.7073664665, 1.6565083265, 1.6814539433, -0.0360563397, + 0.4497372806, 0.0980281234, 1.4531240463, -0.6414846778, 0.1412290037, -1.0449951887, -0.4438725412, 0.9779627919, + 0.7688708305, -0.5568965077, -0.9761307836, 0.7911739945, 1.4035484791, -0.5847625732, -1.4764374495, -1.2948927879, + 0.7119658589, -0.8156015277, -0.2008070648, 0.8081845641, 1.5236290693, -0.3609860241, -1.0343962908, 1.7678860426, + -1.1862468719, -1.7334928513, -0.8210963607, 0.3756120205, 0.2281047553, -0.8125753999, 1.4891103506, -1.8475048542, + -0.1294121295, -0.6484277248, -1.038995266, -0.2641805112, -1.4201703072, 0.9795006514, -1.3405352831, 1.4375221729, + 2.0169596672, 1.1405482292, 0.7233772874, 0.5449270606, -0.7012047172, -0.2516741455, 0.1970013082, -0.7681846023, + 0.5858729482, -0.3477722704, 0.2033023685, -2.0873692036, 0.9893494844, -0.5800985098, 0.6182278395, -1.9546772242, + -0.6086624265, -0.7773972154, -1.2600343227, 1.8167859316, -0.0987552106, -0.1810840815, 1.2722183466, -0.3335888088, + 1.5315827131, -1.3085680008, -1.2660052776, 0.9042910337, 0.3279466331, 0.3045103848, -0.315351367, -1.5934838057, + 0.4933577776, -0.3654850125, -0.57371068, 0.2879352868, -0.4627600908, -1.010882616, -0.6777721047, -0.8984144926, + 0.2504751086, 0.8091649413, 2.6401121616, 1.791156292, -0.8305351138, 0.8344239593, -1.4438226223, 0.3508011997, + 0.2592615485, -1.5862669945, -1.4240231514, 1.5163314342, -0.8924900293, -0.0843262747, -0.7113832831, -0.279625684, + -1.0860145092, -0.3189810216, 1.4416177273, 0.5681290627, -0.3779550195, 0.4941016138, 0.2960478067, -1.2442852259, + 0.0931274667, -0.0518829748, 0.1845656782, -0.733895421, -0.5237256289, 0.868447721, 0.6828365326, 0.5501427054, + 0.8220844269, 0.7082092762, 1.0605940819, -0.2782573998, 1.0126662254, 1.1477307081, -0.0826153383, -1.4017388821, + -0.7767349482, 1.1191364527, -0.4544364214, 2.3977463245, 0.558009088, 0.8164888024, -0.7969041467, -1.2697274685, + 1.5049589872, 0.1810080558, -0.2684362829, -0.3502424061, -0.4023967385, 1.2367614508, 2.0550661087, -1.4493792057, + 0.1685050875, 0.4869134128, 0.8313385844, 0.6722729802, -0.5500596166, 0.2919599712, -0.0776337832, 0.3386179805, + -0.5368257761, 1.80821383, -1.5536627769, -0.2598360777, 0.4972334504, -0.5991903543, 0.1945166141, 0.2947003841, + 1.3485603333, -1.8906611204, -2.3424110413, -1.2688889503, 0.0344363041, 0.2485752255, 0.9743855, 0.5960764289, + 0.3309855461, -0.518949151, -0.8919455409, 1.161046505, -0.5045477152, 1.3423473835, 1.5131756067, -0.6779407263, + -1.7057740688, 1.3286938667, -0.2861714661, 0.3773959279, -0.048730623, 0.9769710898, 0.0155381076, 0.2035691142, + 0.2230139375, -1.5775175095, 0.3229602873, -1.2306278944, 0.0244359765, -1.4809737206, 1.295561552, -0.0120471921, + -1.2050281763, -1.8280923367, -0.1050783247, 0.9775385261, 0.7549197078, 0.0924711451, -0.1297639459, 0.2104711384, + 0.2063230872, 0.0318034813, 0.6998687387, -0.0475344919, 0.0653456599, -0.4324573576, -0.2389912307, -0.0385269783, + -0.3596199453, 0.936660409, 0.2594126165, 0.8580753803, 2.4031043053, 0.6737225652, 0.6189863682, 0.3409185708, + -1.7746075392, -2.3424885273, -1.2195376158, 0.0443152338, -0.3048034012, 0.4648899436, 1.8452289104, 0.3149746358, + 0.0522343889, 0.319509536, -0.7438256145, 0.2410807163, 0.5562276244, 0.2206500024, 0.3171322346, -2.2169415951, + 0.5470215678, 0.9518302679, 1.1646939516, -0.4791328311, 1.3888785839, -0.3748681843, 0.7778351903, 0.8615957499, + -0.8165302873, 0.5390430093, -0.6619489193, -0.1029545069, 0.0851025358, 0.9509700537, -0.5260720849, 0.861305356, + -0.984424293, 1.3661401272, 0.5948407054, 0.1009211168, 0.0307289679, 0.1981360763, 0.8672862649, 1.1369253397, + -0.1251385957, 0.1661457717, -0.9388157725, -0.244974196, -2.4094924927, 0.0623265356, -1.2366584539, 1.8895184994, + 1.3102403879, 0.9462187886, 0.3420774639, 0.3925039768, 1.2095966339, -1.4361178875, 0.5183697343, 0.3537858129, + 1.2890650034, -0.2607053518, 0.2743812501, -0.6387026906, 0.6534357667, 0.1286210418, 0.5044686198, 0.181474939, + -0.4254333973, 1.5863105059, 1.7321563959, 1.526488781, 0.1210952625, -0.5436092615, -0.9529995918, -1.6551265717, + -0.1553141028, 0.2441254854, -0.7731710076, -0.2470936179, 0.2712610662, -0.6617076993, 1.0395247936, 0.684150219, + -0.9874541759, 1.33038342, -0.6565662622, 1.1300296783, -0.1293801665, 2.3106272221, 1.4594422579, -1.0526741743, + -1.0220749378, 0.057755366, -0.5097522736, 0.3840633333, -1.2838438749, 0.7513307929, -1.6153922081, -2.3277418613, + -0.6914343238, -0.4368054569, 0.3361124098, 0.8448717594, 0.4833911061, -0.4330910444, 0.6864856482, -0.748003304, + 0.5588150024, -1.5406918526, 0.8605827093, 0.0865264311, 0.6239672303, -1.1139910221, -1.511674881, -0.7817136049, + 1.5633437634, 1.6206901073, -0.1340485662, 0.5526981354, -0.0745343417, -0.5309984684, 1.1839113235, 0.3718740642, + -2.9650082588, 0.6733871102, 0.3198423088, 0.619756341, -0.0403066762, -2.3952093124, 1.2700175047, -0.8881990314, + -0.7429559231, -0.829051733, -1.1331794262, -1.859967947, 0.7857927084, -0.24517636, 0.3910550177, 0.1410217583, + 0.7675020099, 0.7578459978, -0.3758762479, 1.2606920004, -2.847244978, 1.4555310011, -0.2381768674, -2.2845680714, + 0.1599343717, 0.7724515796, -0.1817385405, 0.8262177706, -0.792822957, -0.8502887487, 0.1392326504, 0.4767868519, + 0.74698174, 0.4203766584, 1.9672571421, 1.5491867065, 0.0936574414, 0.1747819185, 0.1045727581, 2.1363508701, + -1.2314023972, -0.632989347, -0.4213211536, 0.86369735, -0.3888166547, -0.4820105731, 0.4317566156, -1.1235409975, + 1.3373652697, 0.7710515857, -2.714202404, -0.2182231843, 1.692991972, -0.0195358247, 1.3989555836, -0.387527436, + -1.0358554125, -1.1316094398, -1.5382269621, 0.9663111567, 1.0785235167, 0.3704659343, 0.2607283294, -0.2777065337, + 1.8606232405, -0.6065781116, 0.3053328991, 0.6207325459, 0.093035683, 1.2091175318, 0.1401986331, 0.8139212132, + 0.095925346, -0.803866744, -0.9163048267, -1.9060095549, 0.1097709686, -0.9959290624, -0.3285111785, 1.262365818, + 0.2582879066, 1.3890106678, 0.1220844612, -0.4873121381, 0.5140516758, 0.3178030849, 0.5869648457, -0.3526543379, + -0.3959585726, 2.3274693489, 0.1709618419, -0.9874722362, 0.3988903761, 0.3557094634, 0.9122059941, -1.7059065104, + 1.5565053225, 1.3327462673, -0.3147378266, 0.1606792957, -0.5181043744, -0.0744991302, -0.1525735259, 0.8446281552, + -1.9320089817, 1.4879050255, 0.1854588836, -0.1515202969, 0.2979521453, 0.5038195252, 0.8791267872, -2.6462893486, + 0.1011591628, 0.5374528766, -0.0020966744, -0.0970841497, 1.9185301065, 0.5449617505, -0.4810386002, -1.5802356005, + 0.3312494159, -0.8791120052, 0.3050711453, 1.0962580442, 0.5063979626, -0.0172869842, 0.9996516109, -1.5001869202, + -1.8311299086, -1.1142653227, 1.214084506, -2.3504610062, 0.3383857608, -0.2453690469, 1.0279306173, 0.034244433, + 1.4575858116, 0.7556669116, -0.2027938962, -0.3228623867, -0.1250157803, -0.2761982381, -0.091271624, 0.6139395237, + 0.1320572197, -1.7598555088, 3.8252158165, 2.3801681995, -0.5304226279, 0.4853073955, 0.4158081114, 1.9410279989, + 1.30932796, 0.4837481976, 1.0330768824, 0.1908234954, 0.8460777402, -0.4605898261, 0.4409380257, -0.0441601798, + 1.8047442436, 0.9391747117, -0.9743002653, -0.6022531986, -0.9103568196, 0.7067342997, 1.0348250866, -0.1873424798, + -0.412094593, -1.6666873693, 0.1700548679, 0.8848538995, -0.5189235806, 0.6518719196, -1.4336264133, 2.1102340221, + 0.6158944368, 2.075599432, 0.948687017, 1.4196146727, -0.6370040178, 1.4725530148, -0.2676182985, -0.1825240552, + 2.1773166656, 1.9086070061, -0.1137179285, 1.5164897442, -0.2023674399, 0.2179028988, 1.7951279879, 0.317183435, + 0.4730903208, -0.9259622097, -0.508965075, 0.798294425, 1.1375516653, 0.3526133299, 1.3780834675, -0.0489090681, + -0.1768110543, 0.078058064, 0.0144599462, -0.0084795738, -1.228151679, 0.9156061411, 0.2464201152, -0.0167766493, + -0.1420723051, -1.5855610371, 1.6599810123, -0.0597732589, -0.0273799822, 0.8296191692, 0.8847360611, -0.5626728535, + -1.74834764, 1.140334487, -0.0690325201, 1.396066308, 0.627583921, 0.5832805037, 0.011861736, 1.2410900593, + -0.6006539464, 0.2910424471, -0.5646578074, 0.4662118554, -0.5337926745, 0.3868106008, -0.4784782529, 0.554379046, + -0.4056519866, 0.7447139025, -0.0469487794, 2.4892342091, 1.3938800097, -0.1264778972, 0.4362581074, -0.8975135088, + -2.5608577728, -0.7694765329, 0.634498477, -0.1369070113, 0.4036124349, -0.2340947241, -0.9804391861, 0.4205627739, + 1.2156971693, 0.1035736427, -1.7539309263, 1.0600017309, 1.270337224, -1.295050025, -1.5065121651, -1.3031721115, + -0.1997547597, -0.5540348291, 1.370603919, 0.3994727433, -0.2424000353, -0.524504602, -0.0897789225, -1.1353756189, + -2.1022062302, 1.2222563028, -0.243542403, -0.0676702186, -0.8102147579, 0.3558183014, 2.0535726547, 1.0213717222, + -0.2912064791, -0.7373991609, 0.3800884783, -1.0866839886, -0.2113780975, -1.0243973732, -1.086124897, -0.1851570606, + 0.4320114851, 0.5590879917, -0.3961796761, 0.906259954, 1.5587188005, 0.7504378557, -0.4613761306, -1.9730011225, + -2.1190068722, 0.4325800836, 0.0537056699, 0.8598451614, 0.6354776621, -1.6893638372, -0.2476013154, 0.9518808722, + 1.566336751, 1.6191905737, -1.6549032927, -0.3134933412, 1.4668923616, -1.8313214779, -0.3367227614, -0.5707110763, + 1.6618161201, -0.3145177364, 0.0156628042, 0.1667782664, 0.8142173886, -0.3663666248, 0.2926310003, 1.5102934837, + -0.8687940836, -0.5283280611, -0.5114175677, 0.6322653294, -0.1110791191, 0.0009631776, 2.9895756245, 1.4097995758, + -0.5420150161, 0.9210902452, 0.583461225, 0.7994394302, -1.3424725533, -1.0264796019, -1.3861973286, 0.1247647181, + 0.1029771194, -0.4731315672, -0.592169404, 0.7910331488, 0.6274262667, -0.1472722888, 2.5348424911, 1.7897282839, + 0.656822145, 1.7179471254, 0.5924511552, 0.572443068, 1.4984492064, -0.5010377765, 0.0174681451, -0.5767454505, + -0.4235750437, -0.3686167598, 0.1869814843, 0.8584616184, 0.0341167487, -1.2190752029, -1.8360806704, -1.7777047157, + 0.3351447582, 0.2758966386, 0.2172588408, -0.1049501747, 0.4783955216, -0.3389906883, -1.5148092508, -0.2531677485, + 1.5903692245, -0.2204401195, 0.682334125, 0.6670246124, 0.3315284848, 1.3474885225, -0.6062452793, 0.0387766436, + 0.3242726922, 1.6093249321, 1.7843703032, 0.599347949, 0.9222139716, -0.7880330086, 2.2105967999, -0.7617409229, + 1.2312707901, 0.6148130298, -1.4690411091, -0.4746180475, -0.6721571684, 1.0992940664, -0.0940861106, 0.6958556771, + -1.2895159721, 0.2084652185, -0.783152163, 2.0253167152, -2.437571764, -0.0784258023, -0.291914463, 0.9683870673, + -0.2354955524, 0.5750846267, -0.3641513586, 0.8403220177, 0.5809874535, 0.6007576585, 0.0460261889, -0.3048984408, + -0.7436544895, -0.1375458986, -0.0768285319, 0.6623673439, 0.4524120688, 0.3483710289, 0.6208192706, 1.7647602558, + 0.4740043879, -0.2359790057, -1.0643504858, 0.4502330124, 0.465501368, -0.9948694706, -0.25857687, 1.3167483807, + 0.1989564151, 0.2323360294, 0.7958525419, 0.3262020648, -1.3898649216, 0.1671944559, -0.911916256, 0.2252446115, + -0.9267496467, 1.1519112587, -0.5130313039, 0.1882673055, 0.6804435849, -0.4746681154, -0.4878197908, 0.1800938845, + 0.1051743627, -1.05800879, 1.4008100033, 0.5489974618, 0.5481874347, -0.5832469463, -1.2305303812, -0.3625142276, + 0.0120345866, 0.2264911383, 1.2822241783, -1.2907737494, -0.8618292212, -0.943834722, 0.4134423137, -1.0703722239, + 1.4725133181, 1.4156024456, -0.4514758289, -0.5120148659, -0.6924622655, 0.3693538606, 0.834756732, 0.6099922657, + 0.8409538865, -0.2589316368, 0.1839996278, 0.3036150634, -0.0842262655, -0.2866791785, 1.1813234091, -2.3766260147, + -0.9739966393, -0.9959408641, -0.7160070539, 0.38166821, -1.7369004488, -0.7823039889, -1.6728433371, 0.5592993498, + 0.6593230367, -0.687734127, 1.5265905857, -0.0742725432, 0.8444102407, -0.7459825873, -0.0516187772, 0.2302361876, + 2.4707098007, -1.7039589882, 0.1352397501, 0.414293021, 0.1444460303, -1.1740654707, -1.2802608013, 0.1036694646, + -0.3136852682, 0.0832345337, 1.2571145296, 1.805437088, 0.7833987474, 0.2159276009, 1.3131119013, 1.0496573448, + -0.2494902462, -0.9532986283, 0.8174754977, 1.8209816217, -0.4751147926, 1.5540887117, -1.6372287273, -0.518229723, + -1.2041864395, -0.7944150567, -0.2081774175, -1.7688667774, 0.9372014403, 2.3383221626, 1.241953373, -0.1160321012, + 0.8310201764, 0.3418564796, 0.0724793375, 1.4042508602, -0.0997533277, -1.5711517334, -0.1969444603, 1.4441918135, + -0.7084956765, -0.458480984, -0.4085344374, -1.742934823, -1.4977319241, -0.2693070471, 0.9721183181, -0.4137994051, + -0.6265276074, 0.5437030792, -1.2866847515, -0.7732895613, -0.8717803359, -0.0661167651, 0.086836867, -1.4115611315, + -1.1569627523, -1.9649760723, -0.1715185195, -0.9807068706, 0.1386085302, 0.4682126045, -0.7425556779, -0.611279726, + -0.9979614019, -0.3386137486, -0.1766004115, -1.7047775984, 0.1936862469, 0.1481569558, -1.5413073301, 0.3674076796, + 0.0811279714, -0.9216552377, 2.4965655804, 0.8719742894, -2.0750610828, -0.8497855663, 0.5540226102, 0.2907184958, + 0.6172452569, -0.4571862221, 0.4977155328, -0.974817872, 0.5232276917, -0.0748741329, -1.2881364822, 1.3667689562, + 0.1484711468, 0.9896100163, 0.3713888526, -0.4138089418, -1.0227590799, 0.3866163194, -0.9294429421, -1.0626591444, + -0.0199987087, 0.0961680189, 0.2672078311, 1.2036789656, 0.7388323545, 1.2408499718, 0.6849725246, -0.2830341756, + 1.7859346867, -0.6817632914, 0.6170616746, 0.7021603584, -0.0052990373, 0.0670303106, -0.3759177029, -0.5266339183, + 0.5763165951, -1.1446790695, 1.0514925718, -1.2716163397, -0.3700241148, -1.7133955956, 0.463714391, -0.0871691108, + 0.42715469, 0.7751936316, -0.4274554849, -0.4503265619, -0.5333029032, 0.514921844, -0.2053171545, -0.6556538939, + 1.2024029493, -1.4963507652, -1.0015004873, 0.2347760946, 0.5991263986, -0.5835256577, 0.0645779371, 0.4332801104, + -0.8684640527, 0.6871785522, 0.2869982421, 0.0550472997, -0.6587293148, -0.5711126924, 1.2947942019, -0.7356818914, + -0.3393787742, -0.3914661109, -1.1938683987, -0.0813956112, -1.5593749285, -0.3439086378, 1.2804453373, -0.9656952024, + 1.699805975, 0.3437785804, 1.2053562403, -1.3430669308, -0.2202706486, -0.2032942921, -0.4607440829, 0.6888646483, + 0.949463129, -0.5992566347, 0.6588060856, -0.8213128448, 0.3451172411, -0.1872069687, 0.5875008702, 0.6419531703, + 0.8461623788, 1.4980093241, 1.5428068638, -1.0534813404, 0.1087473035, -1.966884613, -0.4938659072, 1.0318287611, + 1.4068181515, -0.1060440391, 0.1013416573, -0.379714638, -0.0020411925, -0.4893866777, 1.2483414412, -0.9816740751, + 1.0710183382, 0.3810484111, -0.229354471, -0.9001345038, 2.1937174797, -1.2616010904, -1.2372906208, -1.6419368982, + 0.205197677, -0.3173463643, 1.1138305664, 0.0690412819, -1.4165972471, -0.9509050846, -0.4597766995, 0.2946996391, + -0.7381731272, 0.9412861466, -0.6347444654, -0.238698408, -0.5287588239, -0.2509096265, 1.6997805834, 1.9507800341, + -1.3863464594, 0.0064332704, -0.7473371029, -0.590180397, 0.7893643975, -0.0761919171, 0.6964703202, -0.6725970507, + 0.2126092315, 0.7568253279, -0.9808959961, 0.1224446669, 1.5959967375, -0.4214015007, 0.7471168041, 0.4177250266, + 2.151471138, -0.2517547309, -0.5861119628, -0.7115761042, -0.2423496544, 0.4907200933, 1.3639013767, -0.0233906917, + -1.2201986313, 0.5158403516, 0.280921042, 0.1244746, 0.2069127262, 1.4315224886, 0.3899920881, -0.2881478667, + -0.4212123156, 1.2691807747, 0.1441033632, -1.9708248377, -0.3076345325, 0.6847977638, -0.2083214968, -0.9662112594, + 0.5662410259, -0.4710945487, 0.6587586999, 0.4371346533, 1.2881650925, 1.8142797947, -0.2653055191, -0.8061235547, + -0.2660584152, 1.1144868135, 0.4511666894, -1.0467418432, -1.2955060005, 0.4813936055, 0.0717912763, -0.2718241215, + -1.4206292629, 0.5015422106, -1.5696884394, -0.7510741353, 0.5357149839, -0.4761382341, 0.3027769625, 1.0439693928, + -0.2968443632, 0.4115947187, 0.1417464614, -1.768699646, 0.5488359928, -0.4652283788, -0.2023715526, 2.0392110348, + 0.9476948977, -0.5790069103, 1.3782595396, 0.0463112034, -1.4538191557, 1.079957962, -0.4495364726, 0.6995849013, + 0.995803237, 0.1410770565, -0.797442317, 0.7335600853, -0.8051303029, -0.5576012731, 0.6688166261, -0.6395130157, + 2.0262405872, 1.8946053982, 0.4527872503, 0.3898622692, -0.686583519, -0.8698310256, -0.1018036604, -1.2498087883, + -0.93371737, -0.6132207513, 0.1670824289, 0.5964810252, -1.0693768263, 1.1424970627, -0.405501157, -0.0484616831, + 1.4438123703, -0.3742063642, 1.9146231413, -0.8712691665, -1.6244757175, -0.9451323748, -1.8532702923, -0.4922710955, + -0.7652184367, -1.5269926786, 1.0519231558, -0.7186142802, -1.136928916, 0.1738671213, -0.8412277102, -1.2510764599, + -1.5560952425, -1.2814587355, 0.2802022398, -0.1892165393, -0.399066925, -0.4418022037, -0.1641026884, -0.0208841823, + 1.4467082024, -0.1773938984, -0.2656075656, 0.9284580946, 0.8337346911, 1.3918434381, -1.5541487932, -2.3029310703, + 1.2056473494, -0.7153151631, -0.6681523919, -1.8057876825, 3.062912941, 1.015860796, -2.2026958466, 1.0273900032, + 0.9297968745, 0.7835995555, 1.2467330694, 1.9681586027, 1.1947727203, -0.2920994461, -0.2260138839, -0.4726005197, + 0.7220215201, 1.1053067446, 0.6730644703, 0.2965455055, 0.5883324146, 0.9228509068, 0.1861357391, -1.1552476883, + -0.1277422905, 1.7361689806, 0.5216132402, -2.2289402485, -0.576202333, -0.3333890736, 1.0773743391, 1.546030879, + -0.4793303311, -1.2360799313, 0.8915560842, 0.5807973146, -0.9052379727, 1.8003457785, 1.5324009657, -1.0009678602, + -1.3704814911, -2.0461034775, -1.6933704615, -0.3919988871, 1.0435934067, -0.1997463107, -0.2654405534, -0.3796259463, + 1.1171686649, -1.162244916, 0.2430635393, 1.2648487091, 0.2460895479, 0.7015656233, -0.2465724051, 1.4588391781, + -0.3708950579, 0.1133627743, -1.8181365728, -1.2764829397, 0.1797037721, -0.9096319079, 0.1833432168, 0.6413455606, + 0.2378626913, 1.0471014977, 2.1745960712, -0.2824437916, 0.6198886037, 1.4454858303, -0.6241021156, -0.0874009505, + -1.2409427166, 0.6960406303, -0.4450871348, 0.4783905447, -0.7847806215, 0.3396017849, 0.840287447, -0.3396469653, + -0.5243570805, -0.4028583765, -0.4860184491, 1.648696661, 0.9750620127, -0.4632399082, -0.0831132308, 0.4595403671, + -0.3360282183, 1.2276799679, 2.9337465763, -2.7567064762, -1.8911068439, -0.5368624926, -1.2443982363, -1.9356986284, + -0.4737740457, 1.1805994511, 0.4548642337, -0.3293735385, 2.1251163483, -0.1460131258, 0.5125373006, -0.6775860786, + -0.3787424862, -0.4837478399, 0.126935944, -0.5968005657, 0.043448247, 0.0882226899, -0.4975458682, -0.824513495, + 0.5286591649, 0.0518661812, -0.1529803872, 0.2797895372, -0.2412377894, -0.3942654729, -1.4258618355, -0.1979169846, + -0.4607566595, 1.9837756157, 1.3194955587, 0.4016983807, -0.1167668849, 0.0360824801, 0.7133179903, -0.0223064348, + 1.4471542835, -0.4008077383, 0.9587165117, 1.2700641155, 0.2602819502, -0.1262758076, -0.7956354618, 0.9213441014, + -0.8105702996, 1.2343528271, 0.1792832315, 1.0454692841, 1.8160818815, -0.2565951049, 0.6567875147, -0.9121094942, + 0.0882756636, -2.3321690559, -0.2221315503, 0.4362458885, -0.4040724635, -0.9728463888, 1.8061887026, 2.82239604, + 1.92380476, 0.4281252325, -1.0113406181, -1.0569467545, 0.7463124394, 0.7058548331, -0.2373242229, -1.2442312241, + 1.4772787094, -0.1161244661, -1.1747477055, 0.0377737507, 0.3676355183, 1.0512756109, 1.0939421654, 0.326585561, + 0.5304086208, -0.4535779953, -0.1297783256, 0.9609361291, -0.6423221827, 0.1481865197, -0.1527392268, 0.2322229594, + 0.6704090834, -1.1654951572, -0.3747846484, 0.7840104699, 1.1033495665, 0.5778945088, 0.5689970851, -0.0741880238, + 0.8559090495, -0.6340079904, -0.2442087978, -1.2459036112, -1.0313720703, -1.2667640448, 1.8217892647, 0.857776165, + 2.7689638138, -1.173571229, -0.5874087214, -0.7750111222, -0.9776890874, -0.9262546897, -1.0075428486, 1.1539785862, + -0.2632883787, 1.9082475901, 0.7450637221, -0.4940591156, 0.6841157079, -0.553689003, 0.6943057775, 0.6760548353, + 0.9306396246, 1.3879038095, -2.4359529018, 1.0196198225, -2.3955872059, 1.2872189283, 0.4549034834, -0.0617699176, + -0.7158759832, -0.4316509962, -0.6489620209, 0.5559383035, 1.0439940691, -1.3500230312, 0.6517568827, 2.4761118889, + -1.4052060843, 1.4435579777, -0.4848107994, 0.0389968641, 0.7329373956, 0.0906467363, 1.3932663202, 1.6153687239, + -1.0152901411, 0.3226601481, 0.3640216887, -1.2530380487, -0.3811959624, 2.3525457382, -0.3899695873, -0.3235520124, + -0.5818331838, 1.0788103342, 1.2848529816, -0.5897274613, 1.8995616436, -0.0095527787, 0.4356729984, -1.2555909157, + -0.7084031105, -0.5457687378, 0.3907106519, 0.4804974198, 1.010540247, -1.1896303892, -0.9705888629, 0.7118433118, + -0.6612381339, -0.313483566, -0.685403347, -0.1347203255, 1.018887639, 1.8438681364, -0.5356816053, 0.8939056396, + -0.2387982011, 0.3773968518, -0.5067309737, 0.347597301, 0.1116873249, -0.3291538656, -0.4861176014, -0.1610072404, + -2.0568583012, -1.5355416536, -0.7158253193, -0.9671429992, 0.3337282538, -0.5167418122, 1.8286303282, -2.3692855835, + 1.1425521374, -0.4168982506, 1.1942421198, -0.5849003196, -0.4810088575, -0.2370169908, -3.2313024998, 0.1890334487, + 0.2700953782, 1.3857370615, 1.1544367075, -1.5452423096, -0.7408530712, 0.348102212, 0.4148260951, -0.374769479, + -0.6615316868, 1.5172027349, -2.183627367, 0.0456692502, -0.0833318532, -0.9288641214, 1.1208633184, -1.5847899914, + 0.8110761046, 0.2517983913, 0.3271596134, -1.8162002563, 0.4868193269, 0.9116107225, -1.9339040518, -1.372055769, + -0.6756509542, -0.1909210086, -1.2321888208, -0.0097519904, -0.6435344219, 1.5714240074, 1.3172254562, 0.7528502941, + 0.3804392219, 0.7566663027, 0.3085334003, 0.4007671475, 0.3258664608, -0.9499855042, 1.4211901426, 1.2636379004, + -2.1053454876, 1.0966620445, -0.2560794652, -1.1866722107, -0.1082164645, -0.9384649992, -0.4065252841, -0.3620557785, + -0.6806376576, 0.6351390481, -1.2025653124, -1.6817848682, 0.4998220205, 1.2873026133, 0.6916964054, -0.1651842296, + 1.1613186598, -0.5508473516, -1.3952718973, -0.7212381959, -0.2760586739, -0.9742767215, 0.9609985948, 1.8242496252, + 2.2517738342, -0.8537518978, -1.2370250225, 1.6758298874, -1.2859879732, 0.8290636539, -0.0007398854, -0.6669198871, + 0.7239009738, 0.493098259, 2.3166418076, 0.2593319416, -0.4904332459, 0.9100781083, -1.5406177044, 1.0337108374, + -0.0417323932, 0.1815911382, 0.8316265345, 1.168358326, 0.2908100188, -0.8651617765, 0.1349878907, 0.580945313, + 0.6313925385, 0.9107890129, -2.0079622269, 2.2667987347, 0.1362239718, -0.4542431533, 0.8893927336, -1.3563278913, + -1.4928052425, -2.5350847244, -2.5609161854, -0.525585115, 0.0438330211, -1.6740049124, -0.3690219522, 2.2857151031, + 0.9468349218, -0.3893817365, -0.058906462, 0.4195207953, -1.5684384108, -0.9302867651, -0.9671948552, 0.6613282561, + -0.8047224283, -1.7897052765, -0.2297337502, 0.0934528559, 0.2821525931, -2.0221195221, 0.5018086433, -0.160654977, + -0.0830269158, 1.6817605495, -1.3330610991, 0.2334875464, 0.93625772, -0.8867135048, 0.6424555779, 0.628513515, + 0.8862875104, -0.7600226998, -0.104861185, -0.1568768024, -0.1049152017, -1.1293969154, 0.4765573442, -0.4045842588, + 1.0629390478, -1.013692975, 0.1548542231, -0.0260496736, 0.7368959785, 0.6437106729, 0.8629876375, 0.9513613582, + 0.53457129, -0.342897445, -0.8951515555, -0.7072141767, -0.8290418386, -1.9441916943, 0.3352486789, -1.6981418133, + -0.6064324975, 0.9298272133, -0.045544222, 0.4545024931, -0.6905018687, 1.6557446718, -1.8656061888, -0.076416485, + 0.135248214, -0.9649400115, -1.1107592583, 0.8871802688, 0.3857004642, -1.347941041, 0.2313199341, 1.1432842016, + 0.9774471521, -0.8249517083, 0.9975424409, -0.4786781669, 0.9934655428, -1.5249751806, 1.4200520515, -1.365604043, + 0.1201347858, -1.4304561615, -0.5459815264, 0.3317955434, 2.7635042667, 0.5319283605, -0.4035831988, 0.1656674147, + -0.0348275118, 0.9128665924, -1.065988183, 1.5218554735, 0.4108059406, -0.8818579912, -1.8898864985, -0.8056340218, + -0.2248883545, -0.3115158677, -1.976103425, 0.2347872108, 0.0435139611, 0.8959118724, -1.463593483, -1.4139857292, + 0.5881743431, 0.463662982, 0.4652281404, 0.1577140689, -0.4330151975, -0.6331516504, 2.2929763794, 0.1627715528, + 0.4049665332, -1.0525262356, 1.3194918633, -0.2121516019, -0.8326429129, -0.1556195468, -0.2294962704, 1.7370721102, + 0.0576815419, -0.3365804553, -1.9751281738, 0.3499570787, 0.8850831985, 0.689742744, 0.3805027306, 0.8950417042, + 0.5748343468, 0.9603128433, -1.5605746508, -0.9406257868, 0.1844527274, 0.4658717513, 0.5011162758, -0.2088306248, + 1.1758521795, 1.163552165, 0.477255702, -0.717128396, -1.7251302004, -0.7932379842, -0.7980470061, 0.2869731784, + -0.9468921423, -0.0588519983, -0.9246168733, -0.4363086224, -0.7276189923, -0.0040393011, 0.1989732385, 0.8241624832, + 0.4181136787, 1.7991360426, 1.6254104376, -1.030441165, -0.8917178512, 1.1133543253, -0.891125679, 0.3151792586, + 0.9218831658, 0.9283659458, -0.7275673151, -1.8838251829, 0.8151659966, -0.3029778004, 0.3363099098, 0.7451679111, + 0.6459904313, 1.5648649931, 0.4582104683, 0.6197059751, -1.5433871746, -1.1824321747, 1.017752409, -0.7003726959, + 0.11402753, 0.5453913212, 1.4336909056, 0.2446464747, 0.3940807581, 1.9681952, 0.6926275492, 0.2997940183, + -0.587631464, 1.6486163139, 1.3615334034, 0.3137921095, 0.7396493554, 1.2286649942, 0.6699882746, 0.6917827129, + 1.3034600019, 0.4483648837, -0.1363343149, 0.9878246188, -1.0063430071, -0.3920277953, -0.2899178565, 0.5260047913, + 0.6267307997, 1.3453166485, 0.2274762243, -0.0629633963, -1.1903443336, -0.6259784102, -1.4462623596, -1.6484795809, + -0.9891631007, -0.6025660634, 0.4475584924, 0.2266521007, -0.0169600137, 0.3846054673, 0.3575282097, 0.6688492298, + -1.5007214546, 1.072892189, -0.992104888, -0.8433125615, -0.2272939533, -0.5822410583, -1.4138011932, 1.197521925, + 0.6921180487, -0.2646894753, -0.7491828203, -0.4853253067, -2.288536787, 0.1974256933, 1.454141736, -2.2559049129, + -0.7094967365, 0.4081711471, 0.0805931389, -2.1951055527, -1.2974768877, -1.3876715899, 2.2653400898, -0.9290544391, + -0.0399216227, -0.698250711, -0.5406550765, 0.2805226445, 0.2198031545, -0.5062025785, 0.1667801738, -0.1336404383, + -0.2559153736, -1.5829130411, 1.725610733, 0.3249048591, 0.7238846421, -0.0049705473, 0.1070211902, -0.0440496467, + -0.5861712694, -1.2517702579, 0.9920070171, 0.0184310395, -0.2521992922, 1.0478001833, -0.8511126041, -1.0877283812, + 0.8057253957, 0.5307689905, -0.2180033922, 0.8828327656, -0.4397656024, -1.9520184994, 0.7932648063, 0.5082966685, + 0.383371532, -0.9113702178, -0.364064157, 0.7479833961, 0.6907197833, -1.7358108759, -1.0114843845, 1.0597826242, + 1.433752656, -1.9482045174, 0.1001625508, -0.9070497751, 0.6013016701, -0.3366676569, 1.5244055986, -0.4733226001, + -0.4377292693, -0.6595449448, 0.9301330447, -0.4823285341, -0.4746858478, 1.0638920069, 1.8176459074, -0.0334640481, + 1.5302972794, -1.4440655708, 0.3651750982, -1.0116682053, -0.1984334737, -0.1631214619, 1.5133635998, -0.7044069171, + 2.1420927048, -0.1501505226, 0.0840540752, 0.5596846938, -1.3633971214, 0.6780669689, -0.2560397387, -0.3821427524, + -0.0927638486, -0.685566783, 2.3247995377, 0.0162809864, -0.8881989717, 0.5334579349, 0.1402356327, -0.9644435048, + 0.2259918451, 0.4266486466, 0.7260495424, 0.3118670881, -0.6226944923, 2.6717684269, -0.5756723881, -0.4234935641, + 0.3955070078, 0.6205416918, -1.346394062, 0.3289612532, 1.3118835688, -1.3313224316, 1.2080878019, -0.4787815809, + 0.1577800959, 0.0663677827, -1.1360330582, -2.5606052876, -0.6011534929, -0.3796326518, -1.1565338373, 0.1681053191, + -1.2738326788, 0.8146806955, 1.1786562204, 0.3972067237, 1.4141077995, -0.8077833652, 0.2641517222, -0.6645264626, + -1.1914525032, -1.9402074814, -0.1699234396, -0.1685755104, 1.9913597107, -0.5442168713, 0.7998579741, -0.2674789727, + 0.2076923251, 0.811855495, 3.0703585148, 0.6901968718, -0.7633002996, -1.9414342642, -1.852571249, -0.3263784945, + -0.7097280622, -0.3387582898, 0.5192115903, -0.0137907621, 1.2764714956, -1.2416212559, -1.1341321468, -0.2834493518, + 0.2832931876, -0.8440576792, -0.3899221122, -1.2861567736, -0.0039009314, -0.3991547823, -0.150786683, -1.0784094334, + 0.687351644, 0.2398162633, -0.891541183, 0.0160620846, 0.1190035343, 1.359566927, 2.2851662636, 1.2656277418, + 0.5647453666, 0.4386366606, -0.2786923051, -0.0450435877, -0.9073960781, 0.8157382011, -0.2528479397, 0.1099881604, + -0.5259025693, 0.9864002466, -0.3098907769, 0.1118538901, -0.1846686453, -0.4830997586, 1.3937410116, 0.6692713499, + -0.2855373621, -0.301530391, -1.2393440008, 1.0436235666, -1.3757392168, 0.3743044734, -1.0209194422, -0.974229157, + 0.4092015922, 0.2553415895, -0.6028506756, -1.3848016262, -0.2793629766, -1.3943332434, -0.2918968201, 0.9001582265, + -0.4785775244, -0.646492362, -0.0132998796, -1.1716102362, 0.2067309022, 1.0480587482, -1.4701331854, -0.2972986698, + 0.724111557, -0.4221785963, 0.379375726, 0.5570320487, 0.8278382421, -0.5132340789, 0.4097019732, 0.1758598834, + 2.0416235924, 2.2838354111, -0.460244894, 0.4201773107, -1.0172317028, -0.3338675797, -1.905230999, 0.0349817537, + -0.3715404868, 1.157558918, 0.4315404296, -0.6823685765, -0.2479079217, -1.3237612247, 2.5582401752, 0.6202364564, + -1.0272048712, -0.72029984, 1.8100709915, -0.2270940989, 0.4384859204, -0.450699836, 0.4351607263, -0.1438863873, + 1.5774437189, -0.4889984727, -0.7328954935, -0.9708195329, 0.1281945407, -0.1182762161, -2.0853116512, -0.9564751387, + -1.6145592928, 0.5195460916, 1.4585510492, -1.0158007145, 0.0924392417, 1.184497714, 1.8504533768, -0.3173408806, + 1.0457521677, -0.8087899089, 1.1489765644, -1.3961595297, 0.2893914282, -0.2376532108, -1.2573392391, -0.858584404, + -0.4192205966, 0.6898103356, -0.1702734679, 0.7137411833, -0.103814058, -0.5801587105, 0.3293689787, -0.1780804843, + 2.1423149109, 0.5859926939, 0.8150727153, 0.096085161, -0.0801161528, -1.5072997808, 0.3067455888, 0.9733224511, + -0.6691715717, -0.0896074921, 0.7155662775, -0.8350681067, -0.8200449944, -0.2977332771, 0.4310656786, -1.8563512564, + 1.2392419577, -1.5641089678, -0.0520131513, -0.3065806627, -0.1996008605, -0.1993302405, 1.4793595076, -0.6917536855, + 1.1229088306, 0.0617509261, 0.233041957, 0.9543156028, 0.323118329, -0.3006335795, -0.5459107161, -0.3147141337, + -0.0181828812, -0.292563647, -0.1001829058, -1.5876607895, 0.193260774, -0.644677639, -1.124697566, 0.7368519902, + 2.3475573063, -0.1616914719, 0.3552694023, 0.0810829923, -0.2951989174, 0.3914378285, 0.3118802309, 0.6587822437, + 1.0558242798, 1.598449707, -0.2858626544, -0.9805120826, -0.7844312191, 0.2835466862, -0.6526885033, -0.2016610503, + 0.8101894259, -1.3438426256, 0.1658969969, -0.5662457943, 1.345292449, -0.2444649488, 1.6518733501, -0.9791072011, + -0.7222418189, -1.0671290159, 0.4526766241, 0.4453455806, 1.247138381, 1.143253684, -1.8908467293, -0.4724683166, + 0.4400090277, 0.4122885764, 0.7332125306, -1.7321538925, 1.917778492, -0.2359334975, 0.7171579599, -1.1484898329, + 0.2975558341, 0.132421717, 0.8498703241, 2.0220580101, 0.0642231554, 2.0187501907, 0.6166564226, -0.3392534256, + 0.853977561, 0.3858638108, 2.0248098373, -0.1607054621, 0.4017896354, -1.4190493822, 0.3904750347, 0.2559507191, + -1.53193295, -0.1452561766, -0.4501852691, 0.3744405806, 0.754740715, -0.3966326714, -0.1949160248, -0.9319941401, + 0.5192106366, 0.1668777913, 0.7877882123, -0.5676600933, -0.5376181602, 1.7631980181, -0.4717208445, -0.2970747948, + -1.688795805, 0.8346431851, -0.2908143401, 0.4495654404, 1.1724085808, 0.3258660734, -0.3408461511, 0.9547800422, + 0.7426418662, 0.7121489048, 0.0964861736, 0.3108291626, 1.7955456972, 0.688637197, 0.6476287842, -0.9715218544, + 1.6482530832, -1.3654054403, -1.4465010166, 1.8486927748, -1.2850440741, 0.1249407083, -1.0885308981, -0.2485388815, + 0.276483804, 0.5420431495, -0.4004425406, 1.9209617376, -0.6851661801, 1.1391372681, -0.1613515317, 0.4473843873, + 0.4043840468, -0.2895264924, 0.5565383434, 0.7464129925, 0.6821542978, -0.6891804934, 1.7582477331, -0.0945984796, + 1.8338278532, -1.2337061167, 1.6532959938, 0.5494328737, -1.1798790693, 1.4739180803, -1.6404334307, -0.5586791635, + -1.6484837532, 2.4162697792, -0.3091666996, 0.0423371978, 2.1097922325, 1.0761109591, -1.7526555061, 0.172399357, + -0.3163443506, 0.399748832, 1.1593134403, 0.2288526297, 0.9422805905, 0.4081701636, -0.6158750653, 0.4793061912, + -0.7150249481, 1.4441509247, -0.4498966634, -2.6479845047, 1.2745366096, 1.1473503113, 1.8102370501, 0.1164595559, + -0.6753442883, -0.633044064, -0.3043009639, 0.6173820496, 0.4520477951, -0.9501532912, -0.4605540037, 0.0309729315, + 0.2326854914, 0.4442227781, 0.2579292059, -0.1524424553, -0.2695141137, 0.6597102284, 0.3571333289, -0.9604148865, + -0.1528694034, 0.4026290774, 0.8940368891, -2.1126663685, 0.6282519698, -0.9926656485, 1.4733834267, 0.6488913298, + -0.9213027358, -0.5731467009, -0.6374110579, 0.6401329041, 1.3533540964, -0.3756834865, 2.6135437489, 0.1940688789, + 0.0630342886, -0.1559038311, -0.8732242584, 1.2136697769, -0.4508092403, 1.0960631371, 0.3103138506, 1.1365141869, + -0.8697562218, 1.2769855261, -1.9234557152, -1.1386402845, 1.4014794827, -0.9552711248, -0.0660765618, 1.6641439199, + -0.8903948665, 0.0384727232, -0.9314847589, 0.764459908, 1.3544265032, -0.8408039808, 1.2758435011, 1.6310828924, + 0.8584744334, 0.7314692736, 0.2873908281, 0.0925639942, -0.1756385863, 0.7188848853, 0.1778239012, 0.0075021056, + -0.3179973066, -0.8962370157, 0.5907183886, 1.3393832445, 0.1291782856, 0.2163106054, -0.1918319762, -0.4468945563, + 0.1792847812, -0.223966673, 1.4377971888, 1.4812185764, 0.4640325606, 1.1958353519, -1.6090112925, 0.7192595005, + -1.8846025467, -0.4219196141, 0.8524013162, -0.3068114221, 0.716601491, 1.0810377598, 0.0509062372, -0.8165169954, + 2.6991014481, -0.4963667691, 1.1587369442, 0.673799634, -1.4490827322, 0.6106519103, 0.3198771179, 0.0267605837, + 1.4674906731, 0.4409443736, 1.1011567116, -0.495952338, 1.079048872, 1.3844223022, 0.1370456964, 0.4587925076, + 1.1820701361, 1.2755533457, 1.1850805283, 0.5455582142, 0.2740237713, 0.3107175529, -1.3007590771, 1.2341132164, + 0.5541449189, -1.490754962, -0.3145397305, -0.8253541589, 1.0124372244, 0.4967445433, -0.1998725533, 2.3858799934, + -0.2239804566, 0.6783373952, 0.6622564197, 0.5010342598, -0.8637469411, -1.2166178226, -0.7888168693, -0.4862669706, + -2.149699688, 0.2434635609, 2.2176091671, 0.6138218641, -0.1121539772, -0.0708785951, 0.2982955277, -0.8135273457, + -0.1176461875, -0.3864695132, -0.3397121727, 1.996573329, -0.4525742233, -0.7801883817, 0.1617140174, 2.044557333, + -0.6421329379, 1.0683028698, 1.4681972265, 0.4830242693, -0.7713213563, 0.9028714299, -1.1294329166, 1.1345814466, + -0.5910274386, 0.6970822215, 1.0826804638, -0.8912727237, 2.1045033932, -0.142750144, -0.0198568925, 0.4012412727, + 0.5061278939, 0.6106132865, 0.8168576956, 0.8838734031, 1.8924901485, 0.171057418, -0.7019839287, 0.3490320146, + 1.5296567678, -1.1244053841, -1.1642284393, -0.4193575084, 0.574608326, -1.168915391, 0.2877218127, -0.1881029308, + -0.3931901157, 0.4175453186, 0.7864643931, -1.7730191946, 1.7171610594, -0.5239853263, -1.65911901, 0.2596905231, + 2.7576310635, 0.3869003057, -0.9029765129, -1.6944363117, -0.6992952824, -0.1057624966, -0.2710611224, -1.0353348255, + -0.3324691951, -1.1543858051, -0.8658341169, 0.1334683746, -0.1229031235, 0.5339189768, 0.6564360261, -0.4034191966, + 0.4229221046, -1.0462310314, 0.4336838722, -0.2808940113, -0.6553801298, -0.0031763159, 0.1415689141, -1.3357542753, + 0.0714949444, -0.4073644578, 0.4600543976, 0.3203541636, -0.1955058873, -1.4824770689, -0.4383046925, 0.8585121036, + 0.007136899, 1.4751278162, 0.6233286858, 0.6207359433, -0.5246831179, -0.041466441, 1.7709965706, -0.070990555, + -0.2821904719, 0.1701576114, 0.8789879084, 0.8838764429, -0.3726766109, 0.7503628135, 1.8942296505, -0.5893586278, + -0.9376010895, -0.4995022118, 2.0414099693, -1.1939601898, 2.3895537853, -0.5800492167, -1.4941869974, 0.3914678097, + 0.7654280066, -0.371181488, -0.1482408494, -0.8229711652, 1.012542367, 1.9014531374, 2.1342532635, 0.8377076387, + -0.5943709016, 1.0816322565, -1.4450104237, -0.9806501865, -0.0139226625, -0.0261511095, -0.1476468891, -0.1782859713, + 0.065490149, -0.9970036745, 1.8520280123, 0.2998270392, 0.4222496748, 0.3607931137, -1.9088587761, -1.3702299595, + 0.1112247109, -0.3712612391, -0.8905547857, 1.5990093946, 1.0519772768, -1.6142657995, 0.9828546643, 1.1408561468, + 1.0751584768, -2.1395509243, 0.8739467859, 0.8484569192, 0.4239789844, 0.7949110866, -2.2604801655, 0.2834377289, + 0.1236173958, 0.6627572775, -0.1966073513, -0.8987166882, 0.1549092829, -1.7537448406, 1.3848297596, -0.0972593948, + 0.2573923469, -0.3925730288, -1.326176405, 0.6730273962, -0.0823751241, -0.201587081, 1.3150098324, -0.4746868014, + -0.9555039406, 0.056791883, -0.2349265516, -1.2320506573, 1.6329518557, -0.3194123209, -1.8545962572, -1.5797518492, + -0.7913144827, -0.5306677818, -0.7435374856, 0.0374403261, -1.5283485651, 1.6451562643, -1.7834663391, -0.1449975967, + 0.9374970794, -1.1378582716, -0.4348377883, -0.3451203704, 1.6907564402, -0.0922324732, -0.2340613306, 0.3029639721, + 0.6703021526, -1.2160876989, -0.107049197, -0.8925184608, -0.9153434634, 1.5998293161, -0.2169963121, -0.0921376273, + 0.7837740779, 0.3923157454, -0.4793142974, -0.6740366817, 1.2255915403, 2.2740068436, -0.3493728042, 0.7215506434, + 0.442787379, -1.2372415066, 0.3400833905, 0.3696044385, -1.1532834768, -1.3326276541, -1.3978134394, -0.7902693152, + -0.0793885812, -0.0871508643, -0.818579793, 0.3032013774, -0.9155107737, -0.4498315752, 0.0133975549, 1.2002675533, + -0.0543997772, -0.5718390942, -1.1672619581, 0.270686686, -0.6121038198, 1.5340633392, 1.3675135374, -0.3314547539, + -0.6407935023, 0.1904756725, -0.017669389, -0.1542854309, -1.0666533709, -0.8065037131, -0.5172939897, 0.1125126705, + -0.8618041277, -1.002704978, 0.1088037044, 0.8530612588, 2.4807577133, -0.4043349624, -0.6118181944, 0.4480062425, + 0.1232022196, 0.2338018715, 0.992005825, -0.8674075007, 0.354664892, -0.7531710863, -1.1711133718, 0.5628138781, + -0.4150498211, 0.3105407059, -2.4759883881, 1.6793575287, 1.7537196875, 0.191241622, 0.2514575124, -0.5988570452, + 0.0741735473, -0.2699765563, -1.2148730755, -1.7194465399, 0.2601687908, 0.6379894614, -0.1272419095, -0.5413345098, + -1.007584095, 0.4337921739, 0.4659135342, -0.3689009249, 0.0981860682, -0.5749191642, -0.5014486313, 0.3198375106, + -0.7704556584, 0.9145529866, -0.4085680246, 1.4911134243, 1.4047791958, 1.1867433786, -1.6885709763, -0.3014551997, + -0.1118771732, 0.7182075381, 1.0829957724, -0.851990521, 0.1300453693, -0.4334434271, 0.4877637625, 0.8054375648, + -1.4181320667, -0.4921872914, 0.4618836343, -0.6419098377, 0.4662364423, -0.5979802012, 0.3456205726, -0.3643333912, + -0.2508301735, -0.2602106929, -0.9041038156, -0.7807335854, 1.4818336964, -0.0963200405, 0.9439044595, -0.0088408943, + -1.5938279629, -1.6104105711, 0.170163855, 0.1085248068, -1.1758224964, 0.3988420963, -0.4401808977, 1.3763401508, + -0.4395669699, 0.4183611572, -0.8105944991, -0.6222549677, 0.2567108572, -1.8000807762, -0.3589302897, -1.5436463356, + -0.1948490441, -1.3861801624, -1.2604641914, -0.4003143311, 2.4831156731, 0.9226174355, -0.3849322796, 0.2759652436, + 1.2357858419, 0.5366231799, 0.2259910405, -0.2262105793, 0.9908719063, 0.6953120828, -1.4158452749, -0.011412845, + 1.1648558378, 0.0026331618, -0.6417639852, 1.7007479668, -1.0409736633, 1.2814551592, -0.6953024864, -0.6436872482, + 0.5956673622, -0.8900166154, 0.8791947365, 0.4307781756, -0.5199248195, 1.3481355906, -0.3190667331, 0.5465198159, + -0.1034876481, 0.282150954, -0.229832232, -1.256870389, -0.5725135803, 1.8433989286, -0.1977019906, 1.4076530933, + -0.4182282388, -0.0286837257, 0.4214601517, 0.2952394187, -0.142285198, -2.3230524063, 0.5700261593, 0.8659446836, + 0.4792743027, -0.0860511214, -2.4152247906, -1.1893260479, 0.6089113355, -0.3519750535, -1.0636354685, -0.9764991999, + 1.4291633368, 0.816980958, 0.7607301474, -0.8915486336, 0.2099952251, 0.7656538486, -0.9530802369, 0.9028717279, + -0.6837580204, -1.1406611204, -0.0980555266, -0.8678302169, 0.0618282855, -0.9474887848, -0.4634743035, -0.8415288329, + -0.2886526287, 0.3071372211, 0.2244463861, 0.3965576887, 1.1935093403, 0.7316077948, -0.6506578326, 0.208124131, + 0.6839416623, -0.9692512155, 2.087120533, 0.5729706883, 3.4624316692, 0.5383459926, 0.3396901488, -0.5575518608, + -0.572337389, -1.707890749, -1.6338896751, 2.9699966908, 2.5188298225, 0.0883686095, 2.0530881882, -0.6892683506, + 1.7217940092, 0.8135957122, 1.0825539827, -1.3073396683, 0.2213107646, -0.8297741413, 0.82298702, -0.2925997078, + 0.2938055098, -0.2028401792, -1.0501542091, 0.3662391901, 0.0436582863, 2.8220024109, 1.6359175444, -0.2000506669, + -0.6892738938, 0.6414157748, 0.181417346, -1.2759850025, 0.7353927493, 0.9251579046, 1.1306307316, -0.8013715744, + -0.3105247319, -0.2614181936, 1.4937690496, -1.1773779392, -0.9231160283, -1.9470348358, -1.2480545044, 0.1362063885, + 0.6162065864, -0.41166085, 0.441219002, -1.4277477264, 0.7063032985, 0.823775053, 0.4653929472, 0.2365056872, + 0.0285083521, 0.9960690141, -0.8011170626, -0.5131413341, -0.4017004371, -0.2410633862, -0.6117011905, 0.5667151213, + -0.4457055628, -0.719732523, -2.7344152927, -0.206412077, 1.0151226521, -1.3595682383, 1.3549883366, -0.1983778775, + 1.3015027046, -0.1049090922, 0.7218281031, -0.1797719151, 0.746745944, -1.6058382988, 0.8894509077, 0.2281947583, + 1.1969484091, -0.6350207329, 0.7831915617, 0.5507146716, -1.3282835484, -1.1195918322, 1.0832135677, 0.4004996419, + 2.0190610886, -2.1272804737, 0.5968118906, -0.6430553794, -0.9771640897, 0.4279308915, -0.8297137618, -1.1755281687, + 1.0167371035, -1.0099674463, -0.3996248245, 0.8061579466, 0.5100678205, 0.6430982351, -0.0116527425, -0.0569755547, + -0.8373223543, -0.1155486926, 0.8459715247, 0.3501706421, -0.7146452665, -1.3728239536, -0.6906177402, -0.8787280321, + 0.3087691367, -2.0644254684, -0.8531473875, -0.7981085181, 0.9267256856, -0.2735356688, 1.6844605207, -0.3576886952, + 0.459708035, 0.5911514163, 0.9546337128, 0.7858938575, -1.0806646347, 0.0153782917, 0.81661731, 1.3586717844, + 0.6759258509, -1.159947753, -0.9371449351, 1.904931426, 0.4763910472, -0.025285216, 0.5366802216, 0.1893805712, + 0.0235877261, -1.2631338835, 0.1262231022, -0.4659309089, -2.0677807331, -0.2172206342, 0.2418677211, 0.2863640487, + -0.5541240573, -0.4875922203, 0.9178158641, 0.8355688453, -0.3356583416, -0.4909035861, 1.3364617825, -0.5274421573, + 0.0552913696, 1.2746754885, -0.4226909876, 0.6258471608, 0.8982531428, 0.7511479259, -0.203313455, -1.7190890312, + 1.2277430296, 0.316319257, 0.2681086063, -0.3645800948, 0.3647791445, 0.5008106828, -1.0483267307, 0.0229089204, + -1.1120997667, 0.4731096923, 1.0203477144, 0.0132737607, 0.3177182376, 0.1482971162, -0.9006447196, 0.7418464422, + 0.8549311161, -0.4601553679, 0.4142823219, -0.5291186571, -0.2832478881, -0.9400891066, 2.0045392513, 0.9907512665, + 1.2803305387, -0.8706706762, -0.0438755862, -0.1437354237, 0.1352631003, -0.2147992402, -0.4306062162, 0.7384632826, + 0.1026570722, -0.919367373, -2.8592047691, 0.5031278133, -1.6948381662, 0.0623850375, 0.4504397213, -0.2354303449, + 2.3214147091, -1.8391581774, -0.0035846911, -2.344399929, -0.3101183176, 1.7663384676, 0.3807913065, 1.7143090963, + 0.2600724101, -2.4273955822, 1.1260516644, -0.1763039678, 1.6863145828, 1.0932096243, -0.2558988035, -1.1969647408, + -0.1792815775, -1.828945756, 1.5591448545, 0.8391063809, 1.2969179153, 1.6576949358, -0.413084954, -0.708807528, + -1.2217174768, 0.1126335263, 0.0402188487, -1.5738127232, -2.176902771, -0.2445770651, -0.3699555695, 0.332583189, + -1.2605797052, -0.0567351133, -0.0740334541, -1.6811589003, 1.3763895035, -0.4706969857, -0.9843922257, -1.1051831245, + -0.4698985219, 0.8479211926, -1.0044732094, 0.2730768919, 0.8285003901, -1.1652021408, 0.7067195177, 0.5655376911, + 0.4849031866, -1.040854454, 0.216511488, -1.6860473156, 2.1083023548, 0.680778563, -0.3152302206, 0.8114103079, + 0.0277315732, 0.8226593137, -0.7260422707, 0.0740356222, 1.3696192503, 0.4227825999, 1.0678523779, -0.6593800187, + 2.4530041218, -0.5130468011, 1.3998401165, -1.1113494635, 2.8427562714, -1.2515159845, 1.7911391258, 1.4213436842, + 0.1319545954, 0.9271252751, -0.553925693, -2.1196947098, 0.5384703279, 1.7564214468, 0.203749612, -0.4946107566, + -1.3231574297, 0.6391705871, -0.2147297114, -0.928642869, 0.3146469295, 0.3201300204, 1.6130293608, 0.912029624, + 0.2281010896, -0.9520408511, -1.7568795681, -0.0860790312, -0.3216405213, 1.5971487761, 0.2164636552, -0.8063322306, + 1.4201835394, -0.9114590883, 2.0482690334, 0.4544996917, -0.996599257, 1.7234151363, 0.4029419422, -0.0605051927, + 1.1774067879, -0.1526352167, -1.3627843857, 1.0119982958, 0.5999497771, 0.1030077115, 0.0237347633, -0.9818653464, + 1.2113623619, -1.0080310106, 0.6341429949, 0.3184710443, -0.6536894441, -0.3419989645, 0.8524641991, -0.037563581, + -0.4750849605, -1.1283820868, 0.0493629947, 0.1907393783, 1.8657075167, 1.6624958515, 0.4755136073, 0.3853852451, + -1.7855322361, 1.5675200224, -0.343901366, 1.4749809504, 0.4404431283, -2.3438589573, -0.6509875059, 1.7350389957, + 0.5399621725, -0.7919213772, -0.7674368024, 1.321082592, 1.8883692026, 0.7461881042, -0.1613261849, 0.9186052084, + 0.9145761132, 0.4075089395, 1.4331464767, 0.7037459612, 0.5462380648, -0.7761021852, 1.0948152542, 0.9146957994, + -0.7808047533, -0.9392088056, -1.2161570787, -0.4258204401, -0.0622376651, 0.6151955724, -0.1300780773, -1.2082298994, + 0.119171083, -0.4793582261, 0.3698245883, 0.5303626657, -1.438806057, 0.3178140521, 0.2438377589, 0.5394156575, + 0.069254227, 0.718039155, 0.0523633435, 0.5539424419, 0.2073472142, -0.2396894544, 0.8435296416, -1.1016947031, + 1.1617139578, -0.241123721, -0.212434426, 0.0503696166, 1.1276808977, -1.8850216866, 0.9905751944, -0.1987105459, + -0.0699739307, -1.5369192362, -0.4018937349, 1.0958739519, -0.5575975776, 1.7045712471, 0.7433077097, -0.5954273343, + 0.6866076589, 0.9778364897, 0.2530172765, -0.1848416775, -0.4636569917, 0.2392144501, -0.347438097, 0.8023971319, + -1.1096651554, 0.8329088688, -1.2316823006, -1.0217108727, -0.3689428568, -0.6006485224, -0.6255954504, -0.618560791, + 0.2374453992, 0.7998460531, -0.4682604969, 0.4123714864, 1.7706925869, 1.1507540941, 0.9583311677, -0.4108321667, + -0.1481068283, 0.0342794694, -1.1916863918, 0.8081879616, -0.966648221, 1.0906995535, -0.1639183015, -1.1320599318, + -1.5155814886, 0.3599909842, -0.9653348923, -0.7701853514, 0.754224658, 0.0639560819, 0.2171070725, 0.0094398977, + 0.4814985693, 0.6337531805, 1.2952977419, 0.0742636099, 0.6645027399, 0.1214422286, 0.6358388066, 0.5883584023, + -0.6672433019, -0.5090835094, -1.8338547945, -1.2418490648, -1.8587424755, -1.273886919, -0.4197821021, -0.191320166, + 0.8862715364, 0.2564136982, 0.2612314522, 2.2699978352, 0.9013975859, -0.6366124749, 0.480443269, -1.0621896982, + -2.1655814648, -0.9202276468, -0.6696566343, -0.540963769, 0.7462758422, -0.3009483218, 1.7442085743, 0.2338610142, + 0.0837169215, 0.3850113153, 1.1419742107, 0.551002562, 0.8352980614, 0.4338721633, 0.4724246562, 0.2723473907, + 1.7705891132, -0.2735621929, -0.6433638334, 0.6840257645, -0.2410134673, 1.8150671721, -1.8267018795, 2.3056502342, + 0.3518390059, -0.3171675801, 1.3055222034, 0.8078785539, 1.30204916, -0.9885943532, 0.8765869141, -1.5162200928, + 0.2587037385, -0.6520469189, 1.3673703671, -1.5630866289, 0.9796712399, 0.2590078712, 0.4991450906, -1.1541076899, + -1.1035073996, -0.3751842976, -0.904818058, 0.3524917662, -0.8524733782, -0.6322894692, -0.4022717774, 0.6911383867, + -1.1806863546, 0.0684107095, 0.582461834, 0.4333196282, -1.254401803, -2.2081205845, -0.980461359, 0.1319895834, + 0.9541259408, 0.3229891062, 0.0549656115, 1.725825429, 1.1441347599, 0.7627381086, -0.3379273117, -0.015578012, + 0.1145182028, 0.0303633697, 0.469664216, -0.2231311798, -0.113570407, -1.4808541536, -1.3070743084, -0.809109509, + 0.2676424682, 1.4319150448, -0.1194170862, 0.3829805553, -0.4280880392, -1.2592542171, 0.596758306, 0.0245815534, + -0.5553333163, -0.0784272552, -0.9085083008, -0.298856169, 0.0019547611, 1.6142442226, 0.0618199073, 0.1645226181, + 0.6071572304, -0.9973375797, 1.0976777077, 1.4667928219, -2.174621582, 0.3314406872, 0.0927470177, -0.2048122436, + 1.4143673182, -1.1663620472, -0.2159975767, 1.9280686378, 0.7685463428, -0.1528172344, 0.0260222536, -0.7631306052, + -0.7862910032, -0.2226518989, 0.5308263302, 0.8197928071, -1.6154203415, 0.3681326807, -0.7986581922, -1.6969778538, + -0.8310033083, -1.1390073299, 0.4657533169, -0.0444163941, -0.0632248893, -1.8191641569, 1.0638192892, -1.3606250286, + 0.6245934367, -1.3430202007, -1.1037573814, 0.2160263807, 0.856494844, 0.188469395, 0.1738087684, 0.0949733108, + -0.9783391953, 2.1088376045, 0.8860807419, -0.1600560844, -0.9818916917, -1.6848745346, -0.4343046248, 0.6651635766, + 1.9885319471, -0.2870945036, 0.9635787606, 0.0447185487, -0.4152676761, -1.3084661961, 0.5204074383, 0.5992215872, + 1.9145693779, -0.8939692974, 1.049528718, 0.2583296001, -1.0402622223, 0.6333838105, -2.7544460297, -1.5477565527, + -2.101307869, 0.0633282438, -1.1671156883, 0.2825079858, 0.6212230921, 0.2638114393, 0.5210747719, 0.2484542876, + -0.3608361185, 1.823866725, -0.1757961065, 0.4721578658, -0.6213430166, 0.207386747, 0.0125586027, -0.5172837973, + 1.1994928122, 0.4062629342, -1.2676839828, -0.5387573242, 1.6995825768, 0.4816310704, 0.8849418759, 0.2497922778, + -2.0610547066, -0.8003373742, -0.2149155587, -0.2607664168, 0.0678154752, -0.1214217842, -1.7614785433, 0.4538424313, + 1.5986852646, -0.5152428746, -0.9982887506, 0.2431342751, 1.0021549463, 0.7107254863, 1.2005827427, -1.3013552427, + -1.7587054968, -0.8021962047, 0.9416404366, -1.0701202154, 1.7020624876, 0.8600663543, -0.0366093032, 1.1781638861, + 1.1968842745, -0.5840277076, -0.0184764396, -1.8357027769, 0.4158545732, 0.327365458, -0.3873716891, 1.6004836559, + -0.2800341547, 0.7892519236, -0.1054666266, 0.5070289969, 0.3303568065, -0.4675278366, -1.6173273325, 1.1189441681, + 0.3584862351, -1.4084955454, 1.0983003378, -0.102977246, -0.9113822579, -0.6339533329, 0.0714032203, 0.6224611402, + -0.5115113854, 1.3892023563, 0.5634469986, -0.6348069906, 0.2799148262, 0.2578309178, -0.7327276468, -0.6066296697, + 0.548227489, -0.9846584797, -1.4991323948, -2.605697155, 0.593259573, -1.4395385981, -0.7592237592, -0.9646526575, + 0.6389320493, -1.6647413969, 0.7618963122, 0.5511775613, 0.563888371, 0.0919290781, 1.2376972437, -0.4143681824, + 1.660842061, 1.1134301424, -0.354955554, 1.1900693178, -0.2941959202, 2.0036094189, 0.1889229864, 0.2768132389, + 0.3631108105, -0.4527046084, -0.0876503065, 0.4518642426, 1.2216837406, -0.5853601098, -1.2460826635, 1.4365702868, + 0.3918838799, 0.4344147444, -0.3103542626, -1.4794760942, -1.1437619925, 1.40642941, 0.8123748302, -0.8287097812, + 0.0644502342, 0.5039708614, 0.0464049242, 0.6796227098, 0.2334593832, -0.0366540141, -1.4885165691, -0.5560668707, + 0.0822257921, -0.2212876827, 1.6971707344, 0.1416028738, -0.3375744522, -0.280933708, -1.0013574362, -1.1856667995, + -1.1524541378, -0.0177265145, -0.157273829, -0.4203666151, 2.2288005352, 1.6894711256, 2.2608036995, 0.057885658, + -1.6283227205, 0.5768634677, -0.1903793067, -2.0627646446, -0.4917488992, 0.8252843618, -0.912770927, -0.493848443, + 0.9456370473, -0.2809567451, -0.3177897632, 1.0033947229, 0.2217080295, 0.8518112302, 1.9643433094, 1.8874276876, + -1.5707550049, -0.8626135588, -0.2519744337, -0.1130561605, 1.0470582247, -0.1848319024, -0.7244028449, 1.4268809557, + 1.9367127419, -0.5947025418, 1.2139691114, -1.1336416006, 0.4106018245, -1.2320458889, -0.0817621946, -0.6174464822, + 0.8128951788, 1.5221180916, -0.2531063259, -1.698884964, -0.2455919683, -1.8654962778, -0.8597924113, -1.6687711477, + 0.0930599421, 0.9343118668, -0.5308892727, 0.9207680821, 1.6391845942, -0.0630735978, -0.5165376663, -2.3341619968, + 0.9599221349, 1.2102273703, 0.7616304159, 0.0274917819, -0.0581777953, -2.3147866726, 2.0967600346, 1.4149196148, + -1.0977212191, -1.6241617203, 0.0720105991, -1.2375843525, 0.3066580296, 1.5010496378, 0.2146603018, -0.1769921929, + -0.2609245181, 0.0112806298, 1.308539629, 0.151570037, -0.1343057156, 0.5356020331, -0.3263483346, -0.8350747228, + 0.9119567275, -0.5826714635, 0.1920842826, -0.7925053239, -0.3949542046, 1.8459690809, 0.3976787925, 1.0924711227, + -0.2221397012, -1.7229070663, 0.4710488021, -0.1177469268, 0.7858834863, -0.5207809806, -1.7956728935, 0.206307441, + 0.1493661255, -1.9783360958, -0.631071806, -0.5640435219, -0.796523571, -1.4358403683, -0.9247434735, 0.4182759821, + -0.7810117006, -0.1456603557, -1.8540166616, 0.9421648383, -0.9929693937, -2.0774114132, -0.7155947685, 2.6200604439, + 0.1311487406, 0.1741613895, 0.1489846259, 1.5386333466, 0.7290978432, 0.3322045505, -0.8202380538, 0.5158880353, + -0.6750556827, 1.3344002962, -0.4489007294, -0.1453179717, -1.0834563971, 1.0381031036, 0.2068814933, -1.0295704603, + -0.3696275651, -0.6469484568, 0.3838300407, -0.4384109974, -1.521105051, 0.6330561638, 0.1468900144, -0.2644926608, + -0.0833066702, -0.1666891873, 0.1699847132, 1.7822586298, 1.4239218235, -0.4095877409, -1.2577289343, -0.2261657417, + 0.1536862552, -2.4841010571, -0.1690602601, 1.1236718893, 1.3120075464, 0.4703026712, 0.7917539477, -0.002455944, + -1.0582803488, -0.8924607635, 1.9422979355, 0.1470964402, 1.5199949741, -1.4546091557, -0.249137491, 0.1628889889, + -0.0223796498, 0.0273962896, -0.862445116, -0.3553950787, -1.1562964916, -0.5350723267, -1.1832722425, 0.0762151852, + 0.8057109118, -2.6641361713, 0.9860156775, -0.3996573389, 1.4996862411, 1.6512048244, 0.969327569, 0.9770048261, + 0.5826814175, 0.713645637, 0.0839540139, 0.2687855661, 0.7190995812, 0.3238495588, -0.0822469965, 0.5498287082, + 0.8601994514, 0.4141937792, 0.1921910942, -0.5373055935, -0.0399440303, -2.9793040752, 1.1761871576, -0.5453553796, + -0.2182899714, -0.3996349275, 1.3795903921, 0.6229868531, -0.1509124041, -0.4743267298, 0.3084315658, 0.6045871377, + 0.2694589198, 0.8859691024, 1.3523759842, -0.3754374087, -0.0136016058, -0.577357471, -0.1826155484, 1.0299216509, + 0.9875227809, 0.3665340245, -1.8713101149, 0.477899313, 1.3742740154, 0.8267615438, -0.4324137568, 2.3989701271, + 1.5465426445, -0.7949463129, 0.8532446027, 0.9856741428, 1.3061232567, 0.8775233626, -1.6787419319, -0.3526584208, + 1.482768774, 0.3022454977, -0.1343125403, 0.823479414, 0.0794778913, 1.1625801325, 1.501914978, -1.1354607344, + -0.6904141903, 2.914816618, -0.5319117308, 0.8360420465, -0.8598858714, -0.3846859634, -0.8635641336, 0.7971241474, + -1.5385718346, -0.9597117305, 1.4342877865, 0.0260773115, -0.6131992936, -0.0396655016, 0.0818362907, 1.3144561052, + 1.8665846586, -1.1760950089, 1.0667315722, -0.205006972, -0.5495911837, -0.5504364967, 0.3499258161, 1.7730232477, + 1.0658493042, 0.0046089194, 0.5828529596, 2.8937945366, 0.7601087093, 0.4959368408, -0.3398263752, -1.1179248095, + -0.0759203956, -0.7791621685, 0.5058390498, 0.3832107782, 0.6314857602, -1.2179418802, -1.2486593723, 0.2801901996, + 1.0210988522, 0.3753940463, -1.4467526674, -0.6495608687, 0.0395036824, 0.2830541134, -1.389095664, 2.1286034584, + 1.4011929035, -0.0469790399, -0.0941228271, -0.0834299549, -1.4725753069, 0.73051548, -0.2272632569, 0.2950935662, + -0.7175719738, -1.7210181952, -0.235245958, 1.8049403429, 0.2901862264, 0.2384487092, -0.4335539639, 2.1697747707, + 0.5837168097, -2.0065824986, -1.5619883537, 0.5572479367, 0.6204081774, -0.6503604054, 0.3235428333, -0.6237254143, + 0.0254766438, -0.9556758404, 0.925632, 0.1110662892, -1.3950949907, 1.6628248692, -0.5550198555, 0.2506259084, + -1.2280722857, -0.8849002719, 0.2853524089, 0.7186892629, 0.3485122323, 0.4830940366, -0.9126710296, 0.0648288727, + 0.5861564875, -1.1012845039, 0.8903179765, -0.5021155477, 0.2146847993, 1.5970772505, -1.6596252918, 1.703899622, + 0.5897356868, -1.9231088161, 0.1841837913, -0.8422321081, -0.2690632641, 0.3078442216, -0.6378785968, -0.2733365893, + -0.4018662572, 1.1151080132, 0.1203839406, 0.5301672816, 1.9052218199, 0.5232292414, -0.5509648323, 0.1532472223, + -0.685235858, -0.0168571491, 0.2829575539, 0.9693676829, -1.3901803493, -0.8579546213, 1.6857061386, -1.8683937788, + 1.1424872875, -0.170678705, -0.9109064341, -1.0370491743, -0.5145337582, -1.4502618313, -0.8660738468, 1.111002326, + 0.4196021557, 0.2588478923, 0.2073096335, -0.7804108262, -0.7706721425, 0.2005842775, -1.2953560352, -2.0662872791, + -0.1776489168, -1.5487222672, -0.4867807925, 0.9630966783, 0.0749432296, -0.4267623425, -0.84475559, 0.5929803252, + -2.1236004829, -0.0424731523, 2.460944891, -0.9759138227, -1.7832497358, -1.6214101315, 0.5515912771, -0.7159795761, + 0.4605422914, -1.0591150522, -1.1180940866, -0.1050870642, -0.4247130156, 0.8251236677, -0.6458255053, 0.0270585772, + -0.7671965957, -0.6085761786, 1.5552158356, -0.6036732793, -0.9812249541, -0.828207612, -0.2138131559, -1.4566339254, + 0.5174087286, 2.0507590771, -0.1476765126, 1.0797405243, 1.3560801744, 1.0424228907, 0.3342956603, 1.2495017052, + 0.7392379045, 1.10747087, 0.1809802502, 1.7764987946, 0.2816728055, -1.9343605042, -0.0202827193, 0.3671101928, + 0.0815860778, 0.0512436032, -0.5376491547, 0.4952427447, 1.7752697468, -1.6656461954, 0.1051459163, -0.6446504593, + 0.8385035396, 0.6940054297, -0.5207248926, -0.1721844971, 1.7069374323, -0.5153077841, -0.56355685, 1.5965918303, + 0.1318876296, 0.3199602365, 0.8840111494, -0.2084402442, -2.4241857529, 0.9587558508, 0.4362331629, -0.9273656011, + -1.256300211, 0.1305574328, 1.1341838837, -0.4569153786, 0.0596981235, -1.3988307714, -1.5971320868, -0.4953704476, + 0.7124653459, 0.3637164533, 1.4194965363, 0.6654574871, 0.6962931752, -0.0628936514, 0.4574303627, -0.8212164044, + -1.2626589537, 0.7945659757, -0.1253741384, 0.2529629171, -0.5118837357, -0.5959960222, -1.439006567, -0.1195924282, + -0.1827707291, 0.3372287452, 2.5050127506, 0.5503866673, -1.8325817585, 0.2706216276, -0.237107411, -0.1965096891, + -0.6216363907, 0.4986001253, -0.024194248, 1.1589165926, -0.5790826678, 1.8832604885, 0.2265321314, -0.465023905, + 0.8145852685, 1.2787189484, 1.2368496656, 0.2810806036, 0.5590633154, 0.0165573135, -0.1671055108, 0.2981031537, + -1.7313406467, 0.0702708587, 0.9237394333, 0.7955741882, -1.0611020327, 0.104695119, -0.6292627454, -1.1767753363, + 1.6472417116, 0.9162951112, 2.419302702, -0.4519712627, 0.1546483189, 1.0768247843, -0.2482834458, -1.0319919586, + 0.9817290902, -1.2656478882, 0.3102760911, -0.6407822371, 0.274526149, 1.4232051373, 0.0962205753, -0.5079040527, + -0.2026175261, 0.4734267294, 0.3398221433, 0.116277352, -0.3965824842, -0.0524844863, -1.3785188198, -0.5009530783, + 1.3419600725, 0.4458302557, 1.6235131025, 0.5704522729, -0.5884652734, 0.1655925512, -0.5934273005, 0.8961495757, + 0.1395948231, 1.8811582327, -0.470482409, 0.6056877375, -1.8371515274, -0.3883416951, -0.226154387, 0.1075822636, + 0.8845273256, -0.2323669195, 1.0182594061, -1.2435951233, 0.1850990653, 0.6556530595, 0.7260800004, -0.0777541026, + 0.6657271981, -1.5444598198, -0.4093579352, -0.1104109064, -1.2403335571, -0.7037749887, -0.047528673, -0.0110759111, + -0.3843451142, 0.999535501, 0.2956174314, -0.1288992912, 0.8820962906, -0.7885088921, -1.3096528053, 0.1360455155, + 0.660564661, 0.4773285687, 0.1000278816, -0.2009449899, 0.9680691957, 0.9661629796, 0.3475872874, -1.0521339178, + -0.2399311066, -0.6726133823, 0.6403880715, -0.2364929765, -1.4091043472, -0.5644134879, 0.7580716014, -0.1551982909, + 0.0443324931, -0.6542751789, 0.1354361475, 0.1713111103, 0.3366525471, -1.1363209486, -0.8197965026, 0.9096105099, + -0.3897396922, -1.1618636847, 0.232304737, -0.16267322, -0.3283954561, 2.0063948631, -1.6640892029, -0.2251854539, + -0.5884788632, -0.745927155, -0.3304202259, 0.514534235, 0.0916930512, 1.8832346201, 1.8666164875, 1.2778718472, + -0.6346173882, -0.6968966126, -1.2571614981, -0.0928414315, -0.890717268, 0.4955960512, 2.0003273487, 0.3299041986, + 0.5431902409, 0.9838431478, -0.6571618915, 1.1528811455, -1.0470914841, 1.3171378374, 0.2243078053, 0.3119038641, + -0.3337868452, 2.0032920837, -1.085693121, -1.9538714886, -0.1341106296, 1.0241699219, 1.2208647728, -1.6466290951, + 0.2385760546, -0.1349076927, -0.947265327, 0.3611437976, 1.8478543758, -2.3713274002, -0.9970322847, -0.0145900678, + 0.6273401976, -0.2074701786, 0.3642231822, 0.8874557018, 0.6856731772, 1.0776827335, 0.4891940057, -0.6078050733, + -0.3043553829, 1.4372410774, -0.9145619869, -0.1745103747, 0.8110514283, 0.5476842523, 0.6497424841, 0.5543809533, + -1.0524549484, -0.6980483532, 0.379779458, -0.8720604777, -0.0382295512, 0.1213534698, 1.2860654593, 0.6915104985, + 0.9888854623, -0.474072367, 0.3520619273, 0.6744676232, -0.4462754428, -1.4237420559, 0.292542845, -0.4372058511, + 0.758058846, -0.1709490865, 0.27530545, 1.5881859064, -0.8896048069, -0.9051228166, -0.0149402972, -0.0148151759, + -1.553149581, 0.0139444396, 0.508456707, -0.8614171743, 0.5642536879, -0.5657557845, -0.1187821403, -0.4563186765, + 0.3088122904, 2.5398862362, -0.0289198011, 1.4139448404, -0.8513980508, -0.1655536145, 1.7412998676, -0.0283007547, + -0.691132009, 0.6281622052, 0.6107546091, 0.6955740452, 0.9466020465, -0.42553249, 1.3051526546, -0.6912388802, + 0.7697520256, -1.6392782927, -0.4025473893, -0.195459947, -0.0032584365, -1.1283636093, 0.8464527726, 0.1064395979, + -0.3436134756, -0.9426211715, 0.5683631301, 0.4941053391, -1.6244103909, 0.4565205276, 0.7516614795, 0.6100686193, + 0.267154932, -0.4684554636, 0.4916934669, 2.2799537182, -1.0597896576, -2.0844984055, -0.0247393716, -0.1110131443, + -0.019201912, -0.8450926542, 0.2091219872, 1.3058104515, 1.6750828028, 0.6700471044, -0.2928491533, 1.7783085108, + 1.0262509584, -3.0318641663, 1.6394308805, 0.499160856, 1.4980392456, -0.1323428154, 0.6211748719, 2.0379743576, + -0.5224591494, 0.3273642361, 0.1952998042, -0.4680666924, 0.420949012, 0.5322787166, -0.794246316, -0.5132656097, + 2.5295221806, -0.4084399343, -0.2231356502, 0.1975568682, 1.2763007879, -0.6899693608, 1.0642337799, -0.5653979182, + -1.2869952917, 1.2466315031, -0.1241233274, 1.0194280148, 0.2496183366, -0.1709581017, 1.7310829163, -0.1135782599, + -0.1945802718, -0.4631730318, -0.1747877598, 0.2316061854, -0.2133623809, -0.7444867492, 1.7741721869, -0.5213237405, + -0.0052383416, 0.6835482717, -0.2477262169, -1.1038888693, 0.3005446196, -0.9216147065, 0.0160131194, -1.3955249786, + 1.8256142139, -0.2967949808, -0.6049112678, 1.0554323196, -0.091092363, -1.7532095909, 0.6685379148, -0.227480486, + -0.7936704755, -0.6907336116, -1.1049113274, -0.4015493691, 1.2235264778, 0.014473415, 0.1218120903, -0.3425313532, + -0.0198845416, 0.4693568945, -0.1412683278, -0.1441329271, -1.2095980644, 0.3068394065, 1.4111222029, 0.1158419624, + -0.9842948318, 0.3015630543, 1.1471153498, 0.7848933339, -2.0293517113, 0.5302294493, 0.2043271512, -1.1321178675, + 0.694006443, 0.8048830032, -0.0286177434, 0.1219166294, 0.641643703, -0.454220444, -0.4865248501, -0.032393761, + 0.2326822728, 0.7127761841, -0.7575730085, 0.726364255, 0.0730553716, -0.2330107689, 0.6749507189, -0.0529052541, + 0.2778891921, 0.6335431337, -0.9314393997, 1.5075997114, 0.0337050445, -0.5642749071, -0.7681024075, -1.2881439924, + 1.7528229952, 1.3125530481, 0.1685075015, -0.4345751405, 0.6745186448, 0.4473234117, 3.4154362679, 0.0939195305, + 1.4169496298, -1.7073221207, 0.1352761835, 0.6206020117, 0.1212979928, -1.6183773279, 0.2478966564, -2.0915911198, + 1.3072786331, 0.0073723211, 0.1456651837, -0.511995554, 0.6050021648, 1.028326273, -0.7437700629, 0.6922110915, + 1.8326694965, 0.3287743926, 0.988795042, -1.2720338106, -0.8566733599, -0.4071277976, 0.6455544233, -1.4670102596, + 0.5637975335, 0.0863739476, 1.1576341391, -0.5866075754, 1.1902070045, 0.4292430878, -0.6513916254, -0.2522836328, + -2.7996482849, -0.0108595164, -0.3560985923, -0.0908001214, 0.9481230378, -0.9476252198, -1.5085779428, 1.0062683821, + -0.8160352707, -1.3991876841, 1.4791408777, -0.1391293257, -0.2057078928, -0.8553714752, 0.5186762214, 0.5040826797, + -0.86387676, -0.9191851616, -1.397918582, -0.6784217358, 1.230653882, -0.9332259297, 0.708381176, -0.4577125907, + -0.0620121956, -0.0351362042, 1.0652267933, -1.1760458946, 0.044630006, -1.5669469833, 0.4134811461, 1.5374922752, + 0.054462418, 1.064612627, 1.5449422598, -0.4001969397, 0.2695350945, 0.8955142498, -0.1994645745, -0.873827517, + 1.7183253765, 1.0541538, -0.6865471601, 0.8660798669, -0.9972230196, -0.098760359, -1.1042673588, -0.1311311722, + 1.1802910566, -0.4166555107, 0.1959019303, 0.1618142575, 1.2000273466, 1.7318041325, -0.7448762655, -0.6215144396, + 0.8590826988, -0.9501357675, 0.264769733, -1.0188965797, 0.1645448953, -0.5019816756, -0.112297684, -0.7125408649, + -1.6597757339, 0.0543932766, 0.6145295501, -0.9701308012, -1.8752157688, 0.5507056713, -0.3657512069, -1.3984634876, + -2.3039720058, 0.5814130902, 0.9320523739, -0.6677701473, 0.414024502, -0.223045662, 1.1848533154, -0.2327275574, + -2.3117311001, 1.0083969831, 2.0880084038, 0.7807578444, -0.2806711793, 0.3659831285, 0.3532699645, -0.1186335459, + -0.2383485287, -0.2226555645, -0.1092954203, -0.7526459098, 0.0635053217, -0.4191754162, -0.3093976378, -0.3990128934, + -0.5901996493, -0.6269081831, 0.5943827629, 0.9215744734, 0.6849617362, -1.1751044989, -0.1513048857, -0.434130162, + 0.8947159648, 0.0362598374, -0.6948597431, 0.9275332093, 0.5545841455, -0.4738935828, -0.150469467, 2.4883825779, + 1.1122415066, 0.1489479244, -2.0799446106, -0.3141900599, 0.5396690369, -1.3634753227, -0.9709356427, -0.3622013927, + -0.3671687841, -0.1727541834, -0.7378624082, 0.5973001122, -1.1517913342, 1.4300465584, -0.7156851292, 0.8373429775, + 0.2585847974, 0.1721901596, -0.0018438506, -0.8097422719, 2.1313259602, 0.796818018, -0.2775542736, 0.8631947637, + -0.8420573473, 2.7444453239, -0.6136727929, 0.3800564408, -0.21193102, -0.4017619491, -0.4494703114, 0.4593496323, + 0.5182594061, 1.0070230961, 0.3051910102, -1.7294261456, -0.3718368113, 0.8044009209, -0.5573958755, 1.2480124235, + 1.8836368322, -0.1714086086, 0.0244216826, 0.2147856355, 0.6537339091, -0.6575426459, -1.7292504311, 0.3809339404, + -0.5554701686, 0.8253012896, 1.0695204735, -0.8808111548, -0.4070812464, -0.5109980106, -1.3897756338, -0.0042871847, + 0.4558518827, 0.4185920954, -0.2674489021, -0.3960486948, 0.8053077459, -0.1883954406, 2.6233503819, -0.120338887, + -1.6325961351, -0.5712729096, 0.0376099385, -1.0410552025, -1.2952389717, 1.7780630589, 0.2537894547, 1.2101197243, + -0.5471873879, -2.176361084, 1.1458199024, 0.3720822334, 1.6003818512, -0.409553051, -1.9625519514, -1.5254100561, + 1.0795557499, 0.6412642002, -0.2453266233, -2.3478925228, 0.6769649386, 0.3459262252, 1.0892885923, 0.0059136492, + -0.4414263368, 0.0774223357, 0.40732795, 0.9646092057, 1.3409656286, -0.5068500638, -1.1570055485, 0.4112512171, + -0.8605152369, -1.1234155893, -0.958699584, -0.6890590787, -1.5872890949, -0.4864371419, 0.0497915, 2.1994481087, + -1.7377170324, 0.641623795, -0.7923098803, 0.1304780692, 0.3397642672, 1.4351961613, 0.231908679, -1.0006706715, + -0.3280332685, -1.0791562796, 0.972117126, 0.4853863418, -0.9484644532, 0.300989598, 0.3293378353, -1.512822628, + 0.9338934422, 1.1475496292, 0.016920384, 0.3695321083, 0.0343017913, 0.5545833707, -0.5545576215, -0.3831988275, + 0.8395510316, 1.210677743, -0.3786276579, -1.2317663431, -0.2997151911, 0.9177377224, 0.9696442485, 0.3414999843, + 0.8652888536, 2.6955928802, -0.3250256777, -0.9790326357, -1.0462377071, 1.8175184727, -2.4941484928, -1.0403255224, + -0.5982604027, 0.2539756596, -0.7462789416, -0.9838350415, 1.3585087061, 0.1825647354, -2.092900753, 0.4379278719, + -1.1159633398, 0.8405852318, 0.5710203648, 0.674898684, -0.30786255, 0.2797708809, 0.1595890224, 0.1293483973, + 0.2212487906, -1.0180786848, -0.6851283312, 0.5324478745, 1.7520087957, 0.766417563, 0.6118838191, 1.4230185747, + -0.0700611845, -0.3144167364, 2.0584418774, -1.1153713465, -2.3753750324, 0.0852801129, 1.0693234205, 0.363723129, + 0.5887388587, -0.4191713929, 0.1261838675, -2.0334804058, -0.4840212762, 0.2973466516, -0.5006974339, 0.9281368852, + -0.1265035123, 0.4268484414, -0.1641852856, -1.4899976254, 0.7738882303, -0.1064092964, 0.9350059032, 0.7224861979, + 0.6837131977, -0.2813137174, -0.2018849254, -1.4496183395, 0.2822894156, 0.6741409302, 0.5833388567, -0.3834654987, + 0.9216980338, -0.5402904153, 0.0449905135, 1.6210678816, 0.4038809836, 0.8260396719, 0.9907310605, -0.1848691553, + -1.2419217825, 0.9926421046, 0.6334283352, 0.8985478878, -0.5619766712, -0.8210536242, 0.1006678417, -0.0309645627, + -0.0446182489, 0.7577447295, -0.6273584366, 2.8296339512, 1.2464458942, -1.1661547422, -1.5976299047, -1.6750463247, + -0.6959130764, 0.4801782668, -0.3721280694, 0.2400489748, 0.3327723145, 0.3250359595, 0.5707746148, -1.3501437902, + 0.2438921332, 0.868412137, 0.037339054, -0.4162268639, -1.5516031981, 0.48938182, -0.9510130882, 0.4297042787, + 0.3235373199, 0.1469300836, 0.7171718478, -0.2045047581, -0.2003860474, -0.9752749801, -0.8899661303, -1.185564518, + 0.3116814792, -1.208383441, 0.3561777174, 0.3181398809, -1.3351159096, 0.2889765501, -0.3798525333, -1.2264633179, + 0.1558524966, -1.3657807112, 0.0333562158, 1.3740893602, 0.2170120925, 1.4955347776, 0.0376551785, 1.0529077053, + 0.9597856402, 0.1183744967, -0.0969234258, 0.659303844, 2.1102674007, 0.8496427536, -0.9985044003, 0.6058217883, + -1.0085011721, -1.039865613, -1.0336683989, -0.09883672, -0.6505918503, 0.9194741249, -0.7106096745, -0.8037624955, + -0.6252217293, -0.7874242067, 0.9015535116, 0.0489723794, -0.3165658712, 0.4750823081, -0.8362310529, 0.598562181, + 0.0831746012, -1.9769351482, 0.4109248817, 0.9616567492, -0.1925200224, -0.6872479916, -0.0291667711, 0.4817531705, + -1.2618397474, 0.804115355, -1.0452064276, 0.9234446287, 2.3404836655, -0.5770075917, 0.1780190021, -0.6452456117, + 0.1780572832, -1.1206645966, -0.7152308822, -0.9273412824, 1.554333806, -0.9651429653, -1.2783868313, 0.3413947523, + -0.3924708366, -0.6756599545, -0.1602455676, -0.1887249947, -1.0889669657, -0.3058025539, -0.9298772216, 0.9752748013, + -0.1857045293, 0.3902679384, 2.478345871, 0.6216580868, 0.8140361309, 0.5323762894, -0.1220407784, -0.1911884248, + 0.969501555, 1.7107357979, -0.8332494497, 1.0158033371, -1.3568849564, 0.320218116, -0.4249622524, 1.0535852909, + -0.0648548529, -1.1206247807, -1.331348896, 0.2760379314, -0.8660236001, -0.2355240434, 1.1059592962, -1.0518497229, + -0.8911786079, 0.4755552411, -0.4749928117, 0.861879468, 0.8533287644, 0.0164538156, -0.1435441524, -0.296487987, + -1.2023267746, -0.0720503479, -0.9484385848, -0.2501189113, 0.6416484714, 0.7757827044, 0.7773790359, -0.2722290456, + -1.0522669554, 0.5333345532, -1.8526387215, 0.3252865672, -1.0955603123, 1.5631155968, 0.673643589, 0.1962209195, + -0.0650429949, -1.5892469883, 2.2871513367, 0.592871964, 0.5669403672, 0.2304450274, -0.4885673523, 2.0260953903, + -0.5616394281, 1.27250278, -1.25986588, -0.720941484, -0.8498359323, -1.6869456768, -1.453582406, 0.63258183, + 0.8368428349, -0.0728568211, -0.8834574223, 1.3237099648, 1.5845621824, -1.4369770288, 0.1884049624, -0.3132542372, + -1.3461782932, -0.1914197803, -1.0135910511, 0.4060253203, 0.8252695799, 0.5558263063, 1.1091421843, -1.1206122637, + 2.4767508507, 0.5643259287, 0.9157356024, 0.5002053976, 0.790815413, 0.8274473548, -1.7692761421, 0.7141329646, + 0.4376039803, 1.3221139908, 0.1192799956, 0.1986379474, -0.6428962946, -0.8024330139, -0.6532709002, -0.6049788594, + -1.2296186686, 0.6375156045, 0.9582261443, 1.9821717739, 0.935814321, 0.8946135044, 0.0913714394, -0.6747932434, + 1.0523104668, 0.065347977, -0.7234938145, 0.1506555378, 0.2563973963, 0.642288208, -2.1984939575, 0.1423068494, + 1.3988722563, 0.9099609852, 0.4305366874, -0.0558515005, -1.2119708061, -0.4905354083, 0.4168024957, -1.112721324, + 0.274413079, -0.9005704522, -0.2425050139, 0.9652739763, -0.1550932974, -2.7414751053, 2.7117772102, -1.4189043045, + -1.0313910246, 1.4430273771, 0.3495107293, -0.160043627, -0.4971172214, -0.6566462517, 1.7511360645, 2.6167964935, + -1.6863998175, -0.8562343717, -0.901487112, -0.529111743, 0.0483883694, -1.544929862, 2.5941178799, 1.1498541832, + -0.8130968809, -0.9091265798, 1.7938588858, -1.9932663441, 0.148344323, 0.5673434734, 0.3636609614, -1.4151256084, + 0.9914378524, 0.3327944577, -0.7365987301, -1.1241701841, -0.3251023293, -0.1126096621, -1.0407176018, 0.2644003928, + -1.2129006386, -0.6472233534, 2.0263800621, -0.205563724, 1.1558588743, -0.5569451451, 1.0327348709, 2.9583289623, + -0.0690718144, -0.169674322, -0.2801229656, -0.1217102259, 1.6591004133, 1.0041955709, 0.7745190263, 0.4571551681, + 0.2016106397, 0.6540086269, 0.6006768942, -0.6057759523, -2.4989545345, -0.4389500022, -1.1566992998, 0.2245195806, + -0.1928787529, 1.0130279064, 2.8678760529, 3.4200766087, -1.1019076109, 0.7968271971, 0.3168827593, 0.9232071638, + 1.5975202322, -0.4766547978, 0.1227640808, 1.503300786, -0.1045565084, -0.5908822417, -1.4120235443, 0.3343747258, + -0.6939716339, 1.3138922453, 1.758251667, -2.0948252678, -0.3867600262, 1.4881784916, -0.2614794075, -1.0096803904, + -0.8288538456, 1.124289155, 0.8932532072, -0.7381454706, -1.570229888, -0.6367726326, 1.0390914679, -0.6599599719, + 0.1851871461, 0.2441084385, 0.1874911785, -0.2299124449, -0.0557615831, 1.2884424925, -0.4906115234, 1.0648677349, + -0.7498172522, 1.3501983881, 1.2616695166, 0.9143901467, 0.1215201989, -0.1740020961, -0.8299691081, -1.3438180685, + 0.689697206, 0.2989670038, -0.9304523468, 2.1257295609, -0.3191212714, -0.9800383449, 0.996139884, -0.3433336616, + -0.9051725268, -0.5238730311, -0.1880698651, 2.2426862717, 0.3711197674, 0.4215188324, 1.9264063835, -0.8985811472, + 0.9724038243, 0.9724006653, 0.5963121653, -0.1313816905, -0.9208067656, 0.0731222332, -1.0595364571, 1.7986855507, + -1.4451892376, -1.6628885269, 0.1031904817, 1.8886716366, 2.1079497337, -0.0436575674, 1.6163161993, 0.7489252687, + 1.0819302797, -0.6431999803, 2.6041235924, 2.1054654121, 0.1228456721, -1.3445225954, 0.2740955949, 0.806197226, + -0.7437826395, -1.1212561131, 1.0593879223, -0.7465335727, 0.6351316571, -0.1259510219, 0.7468909025, 0.9277933836, + -0.6623082161, 0.949542582, -0.3312621713, 0.3156095445, -0.0621979199, 0.2871080637, 0.5507833958, 0.7471680045, + -0.1918139458, -1.0566934347, -0.385450989, -0.909416616, 0.3269947469, 1.6029323339, -1.3439395428, -1.0700266361, + 0.8704138994, 1.7585107088, 0.8698053956, 0.1614292413, -2.1836338043, 0.4575574696, -0.3837276399, -0.7936035395, + -0.7575538754, 0.7196499109, 0.3993514776, -1.1120111942, -2.4084584713, 1.1744660139, 0.664257884, -0.1801867336, + -1.1095536947, 1.8082687855, -0.5784759521, 0.7034670711, 0.0047463123, 1.9643903971, -0.6102766991, -2.007437706, + -0.0763465017, 0.2575736046, 1.8768074512, -1.2388337851, -0.7563742399, 0.5345876813, -0.8474777937, 0.0104724141, + -0.0560626648, -0.225457415, 0.7342847586, -0.1823126227, 0.9410361052, 0.1615654975, 1.011179924, -0.9020431638, + -1.2960655689, 0.5210303068, -0.0611365028, 0.1001681834, 0.7305082083, 0.5266997218, -0.6311574578, -0.1671253741, + -1.4037280083, -0.244335115, -1.2517610788, -0.6421838999, 1.4461832047, 0.2268501073, 0.0399844833, 0.7946876884, + -1.2721235752, 1.2676312923, 0.3134599328, -0.3629707396, 0.5874877572, 1.3795229197, -2.0228421688, -1.0742843151, + 0.7796605825, 1.8933137655, -1.9481340647, -0.7232157588, 0.6457300782, 1.0992538929, 1.2602574825, 1.217335701, + 0.322552532, -0.8072761297, 1.9048274755, 0.2093349546, 0.0960786119, -1.5297433138, -2.1362874508, 1.6078487635, + -0.0083657373, -0.4866380692, 0.3900962174, -1.9635704756, 0.3925728798, -0.9276992679, 0.9480867982, -0.4484598935, + -0.2534022331, 1.1133691072, -0.401830703, 1.110588789, 0.0697086081, -0.0130785871, -1.2711316347, -0.4720092714, + -0.609328568, -0.3815086186, -0.2593854666, 0.6868306398, 0.2982982695, -1.0888745785, -0.0356637649, -0.7768434882, + -0.890272975, -0.7600454092, -0.4218118489, 0.3945529759, -1.7036703825, -0.6038737297, -0.6489652395, 0.7995288372, + -0.2697657645, -0.2542925477, 0.1636188477, 1.6742730141, 1.2430789471, -1.2469968796, -0.3124547601, -0.1815218925, + 1.0640125275, 1.8174276352, 0.1209504902, -0.2399097234, -2.0230894089, -1.1016820669, -1.4689011574, 0.1792734712, + -0.1051847711, -0.5941409469, 0.1108767465, 0.5730710626, -1.2479622364, -1.0237392187, 1.3488510847, 1.1845982075, + 0.3580740094, 0.9250638485, -0.2230274081, 0.1302635074, 0.6828508377, 0.721988678, 0.4433879852, -0.5854877234, + 0.7401592731, 0.8713111281, 0.2033105642, -0.5434444547, 0.3103612363, -0.2429424971, 0.3660286367, -0.9809601307, + -1.3397420645, 0.166838482, -0.2828427851, 0.4434334338, 0.53714329, 1.9583348036, 1.2049523592, 0.237208873, + -0.3331832886, 1.1592470407, 0.2292878628, -0.7659143209, -0.3226299882, 1.0478326082, -0.0462466627, -0.0130897462, + -1.5684120655, -0.3709748387, 0.9952441454, 0.5843552351, -0.555557549, -0.9959812164, -1.1858104467, 0.3064933121, + -0.3683856726, 0.9699641466, 0.9785125852, 0.0002325818, -0.4245741367, 0.3247098625, -0.111823149, -1.9157896042, + 0.2442909628, -0.55703789, 0.1214372441, 1.2457281351, 2.3516080379, -0.0346703567, 0.222761631, 1.0316162109, + -0.3360175192, -0.1249095425, -1.2381279469, 0.5380402207, 0.2509429753, 1.4545207024, 0.3763480484, 1.1317685843, + 0.1574275047, -0.4038485885, 1.0350737572, 1.5813468695, -1.2058871984, 1.8397190571, -0.5369747281, -0.1675504595, + -1.6808416843, -0.3973738253, 0.8955420256, -0.9474033117, 0.8863657713, -1.3639428616, -1.1407256126, 0.0768821016, + 0.1626100093, 1.1859166622, 0.8617249727, 0.0092263343, 0.5938783288, -1.6519448757, 0.4657230377, 2.0321743488, + -0.6253198981, 0.4228032529, 0.1740853935, -1.1310549974, -1.1406570673, -0.3442859054, 1.0565874577, -0.2801092267, + 1.8965030909, -2.4183242321, -0.1742828339, -0.7835971117, 0.2747937143, -0.617185533, -1.6374839544, -0.0998052806, + -1.5593715906, -1.2759281397, -1.4176751375, 0.7536286712, 0.8720196486, -1.2819939852, 0.7087141275, 1.9042751789, + 2.7620675564, 1.1157127619, -1.0292673111, -1.2326740026, 0.4892507195, 2.1081411839, 0.4370924532, -0.5593727827, + -1.4354031086, 1.0570830107, 0.4167571962, -1.1469852924, 0.4386380911, 0.462760061, 0.0152175874, -0.5675275326, + -1.2706890106, 0.3094842136, 0.335331887, -0.5180909038, 1.4484337568, -1.8907704353, -0.0004836629, -0.3969363868, + 1.063328743, 0.0843856484, -0.1612736881, -0.0583505481, -0.0020569484, 0.0918041766, -0.5388286114, 0.462813586, + -1.0131388903, -0.4627156258, 1.8314408064, -0.5217072964, -0.1163138002, -1.9294489622, -1.0067454576, 0.5082025528, + -0.3337702453, -0.2269964814, -2.1366028786, 0.1338530332, -0.3698782027, -1.0692406893, 0.3903188705, -0.0497018024, + 1.1616665125, 0.9621710777, 1.4915152788, 0.1182670668, 1.5708578825, 0.7640832067, -2.0470445156, 0.2740463912, + -1.6569459438, -0.208561182, -0.9933959246, 0.7703897953, 0.1919436753, -0.1551560611, 0.5901817679, -0.7839456797, + 0.5055692792, -0.6600452065, -2.1255404949, 2.5530233383, -1.4889702797, 0.6624996066, -0.8144878149, 1.2584605217, + -0.6314144731, -0.9057261944, 0.0311285201, -0.8325083852, 0.3457152247, 1.0724612474, -0.1779902279, 0.6224679351, + 1.1843028069, 0.3990680873, -0.3444859684, 2.2503702641, 0.5720024705, -0.652484417, 0.8113818169, 0.6207444072, + -0.2953625619, -0.2325160801, 0.5621783733, -1.18663764, -0.2479910105, 1.3240972757, 0.4694396853, -0.8371084332, + -1.1386457682, -1.586157918, -0.194088161, 0.5150237679, -0.7020881772, -0.1579501629, -0.3900207281, -0.9069029689, + 0.2974373698, 1.0060987473, 0.3582396507, 1.3689446449, 0.832598567, -0.625913918, -1.0219625235, 0.8717699647, + 1.5553936958, 1.9892309904, 1.7129807472, -1.7524341345, -2.4156734943, 0.3734627664, -0.9791836739, -1.1838378906, + -1.6001518965, -0.2521800399, -0.9588496089, -0.0467710644, 1.4703460932, -0.1281604916, 1.9166052341, -0.7853434682, + -0.8153104782, -1.2059153318, -0.0041961134, 0.8652752042, -0.1252185553, -0.3175365925, 0.0003913178, -0.8116727471, + -0.1722526997, 0.2703862786, 1.1430435181, -0.0179268271, 0.5940791368, -0.0597756766, -0.7731306553, 1.7648396492, + 0.6532765627, -0.0256540347, -0.2082199454, -1.412547946, -0.2929659188, -0.0797623321, 0.4935064018, 0.6900241375, + -0.871132791, 0.2377964407, -1.3421390057, -1.0594630241, 0.8106474876, -0.9261490703, 0.0168073885, -0.1170370802, + 0.4168663323, 1.3247480392, 1.9524668455, -0.7113932371, 0.8084810376, -1.1566987038, -0.2625491023, -0.1377955228, + 1.8415939808, 0.2191815525, -0.3335691094, 1.3335675001, 0.6392911077, 0.2304753959, 0.1254295856, 0.4711110294, + 0.5567567945, -0.1583541334, -0.1846426278, -0.3851806819, 1.0271519423, -0.0131389173, 1.4698441029, -0.5619645119, + -0.0572414175, 0.5521336198, -0.3570716977, 0.4461381435, 1.5787917376, -0.296446085, -0.6109013557, 0.5612183213, + 2.4743282795, -2.0427081585, 0.7436702251, 0.5880488157, 0.1136561483, 0.4198854864, -1.5047591925, 0.5283017159, + 0.4352711737, -0.8595504761, -0.1644246876, -0.3773303032, -0.6257966161, -0.6975237131, 0.4315404594, 0.1575031728, + 0.5167097449, -1.4270300865, 0.4468098283, -1.6486895084, 0.4399907589, -0.215984568, 1.4771642685, -0.0137156723, + -0.0051958985, -0.0996746719, 1.8157832623, 1.2126486301, -0.814196825, 0.0797947198, -0.3740171492, -0.0235440154, + -0.4075264931, -1.5856205225, -0.8143793941, 1.2097389698, -0.6563789248, 0.0917219445, -0.2388767302, -0.5819990039, + -1.9098675251, 2.0859701633, 0.4343566298, -0.4059936106, 0.4935959578, 1.1469419003, -0.8147927523, -0.0642666221, + 1.0216310024, 0.2484840751, -0.2188244909, -0.4161131978, 0.9300234914, 0.8221677542, 1.3278201818, 0.7848719358, + 0.7350556254, 0.327585727, -0.9404194951, 0.8318222165, 1.31128335, -1.7765289545, -1.7815247774, -0.3423713744, + 0.4871589839, -1.403445363, -0.3804571629, 0.4861087799, -1.2812838554, -0.083563596, 1.6544206142, -1.2440884113, + 0.8436793685, 0.7396528721, 1.1865768433, 0.0844733939, 0.1610046029, -1.5059672594, -2.0161046982, 0.4744549394, + -0.1027829498, -0.8932421803, 2.6681511402, 0.873378098, -0.6771495938, -2.1171841621, 0.417907685, -1.5294778347, + 0.6122385859, -0.5188607574, 0.025352722, -0.5863035917, -0.6137494445, -1.3239506483, -0.1866202801, 1.4357578754, + -2.6238973141, 0.9697104692, 1.3150304556, -0.174082011, -1.2808016539, -0.7015659213, -0.3883333206, -0.0155479601, + -0.5180083513, -2.6574621201, 1.2562646866, 1.7780845165, -0.8762903214, 0.4460975826, -0.5522505045, -0.1025809869, + 1.654764533, 0.4384832084, 0.8500418663, -1.0074121952, 0.8443838954, 0.3932457268, -0.2968220711, -0.8347958326, + 1.3171423674, 0.9378548265, -1.262395978, 0.7586356401, 0.2216345519, -1.1635854244, -0.2694393396, 0.7349928617, + 1.1965305805, -0.4751051366, 0.2625339031, -0.5044584274, 0.3648485243, 0.6711106896, 0.8469839096, -0.0794413686, + 1.4676808119, -0.5880222321, 1.2756909132, 2.1141371727, 1.2257579565, -3.1443977356, -0.8633837104, -0.4782708287, + 0.7528486848, 0.0728427917, -0.1478959173, -1.8716983795, -1.234164834, 1.9306218624, 0.4773486257, -0.7664555907, + 1.0502686501, -0.6320495605, 0.7806579471, 0.5659831166, -0.7911544442, -1.2014272213, -0.4031826258, 0.3939342797, + 2.0412855148, -0.560690105, -0.3510407507, 0.4227169454, -1.3822602034, -0.2495191246, -0.4121963382, -0.4797803164, + -1.6132888794, -0.1541571766, 0.5172279477, 1.8714196682, -0.8915430307, -1.0249711275, -0.4603399038, -0.8396726847, + -0.2851386666, 0.4890405834, 2.7800784111, 0.2114791274, 0.5173261762, -0.4926160276, -0.5128554702, 0.3635650575, + -1.2499142885, 0.1577661932, -1.1878240108, -0.1372671872, 0.2076225579, -0.9449370503, -0.6277039647, 0.0855376199, + 0.91688025, -1.4615525007, -0.8221495152, -0.0306883696, -0.3794527352, 0.6988317966, -0.3404355347, 2.0155558586, + -0.9869990945, 2.3109531403, 0.8517220616, -2.0357089043, -1.3717461824, 0.4539968669, -0.3938590884, -1.1531527042, + -0.6132876873, 1.6227045059, 1.5988278389, -0.4305523634, -1.5203722715, -0.2126695216, -0.7949711084, 1.0062519312, + 0.1088095903, -0.1143707111, -1.5254942179, -0.5971631408, 0.0266929027, 0.179889679, 0.6165832877, 0.1774144769, + -1.1522259712, 0.3164618611, 1.3300391436, 1.5971671343, 1.4609972239, -0.1620344818, -0.0415391847, 1.724650979, + -0.3874904513, 2.16076684, 0.3433647454, 0.3206478953, -0.626111865, 0.530407846, 0.0695448145, -0.0012609762, + -0.5348551273, -0.4886779487, -0.1492735595, -1.1154803038, 0.2743631601, -0.8677986264, -0.8241101503, 1.0104525089, + 0.6254281998, -0.9113668203, -1.6015820503, 1.7713805437, -1.2572556734, 0.1901635826, 2.1025061607, -0.0653650835, + 1.8718448877, -1.3963491917, 2.3231360912, 1.5577259064, -1.4847933054, 0.1091064811, 0.1189436316, -1.8201619387, + 0.9907189012, 0.7037143707, -0.1040920019, -0.3882758319, 0.6091170907, -0.3306565285, 0.2832741141, -0.2206534594, + 0.8937234282, -0.1409606785, 0.9197987914, 0.9479706883, 0.4320091307, 0.8930882215, -0.2672516704, -0.2465402484, + 0.113962546, 0.5704907179, 0.3211796284, -0.7757544518, 0.226250276, -0.6387628913, -0.564829886, -0.1335153878, + -1.9806940556, 0.8351049423, -0.6341540217, 0.2234416455, 0.7767619491, 1.0302518606, 1.2044047117, -0.6560946107, + -1.1046437025, -2.5660791397, 0.7642706633, 1.7174856663, -0.2373072505, -1.4493148327, -0.0723819956, 1.24322927, + 1.9301974773, -0.0527655259, 1.5347336531, 0.7458348274, -0.3054525852, 0.2830949426, 0.7241360545, 0.47996369, + -0.4515165687, -0.9522143006, -0.238651827, -1.5671073198, 1.1002331972, 0.9565708041, -0.075350225, 0.3522382975, + 1.5541101694, 1.0659878254, 0.2211657315, 0.7039881349, 1.331282258, 1.1425888538, -0.8043620586, 0.1118339002, + 0.7051146626, 0.2405101657, -1.2077591419, -0.7707319856, -0.4111624956, 0.8228642344, 1.347807765, 1.3317564726, + 1.2580941916, -2.1362700462, -0.6044573784, 1.3983079195, -0.2267834991, 1.1038742065, 1.830937624, 2.5118257999, + -0.746108532, 0.4706372619, 0.328369379, 0.5749509931, 0.009605526, 1.5103399754, 0.4314630032, 0.8736536503, + 1.0169622898, -1.6128311157, -1.136026144, 0.5721042752, -0.6031692624, 0.1187613904, 1.1165670156, 0.13689816, + -0.9850955009, 0.6313478351, 0.7843387127, 1.2135647535, 0.3128623366, 0.5757420659, -0.1311307251, -1.4725977182, + 0.2902924418, -1.6542005539, 1.3504993916, -0.3761866093, -0.0340541266, 1.3819690943, -1.8941106796, -0.2743933499, + -0.2576075792, -0.4365912676, 0.4990610778, 0.9072874784, 1.0279914141, -0.2289631665, 0.5705673099, -1.8134893179, + -1.4707256556, -0.1991883665, 0.1905540079, -0.1706116498, -0.4919151664, 0.8360471129, -0.4966766536, 1.3094147444, + -1.3342524767, -0.8660213947, 0.4778424203, -0.3906137049, -0.2144182622, 0.3572425842, 0.2118220329, 1.1288861036, + -0.0217239484, 1.0320818424, -0.3704183996, 0.1348206401, 0.0780876055, -1.1623704433, 0.0471805632, 1.8262777328, + -0.1326367855, 1.2541949749, 0.4579695463, 0.6132331491, -0.6418583393, 0.8945944309, 1.3853417635, 0.6127995253, + 1.7553474903, -0.895227313, 0.5639309883, 1.1167125702, 1.1573514938, 0.6090118885, 0.4605760276, 1.3694016933, + 0.3081550598, 0.4055664539, -0.4725796282, 1.7730118036, -0.0457734875, 0.0639425218, -0.6374250054, 0.5051111579, + 0.5209814906, -1.3633556366, 0.6776292324, 0.5936003327, -0.9643524885, 1.323857069, -0.9794591069, -1.8232733011, + -0.9560294151, -0.9466639757, 0.4216081202, 0.0111554582, -1.2830356359, 0.0037587516, 0.2466487288, -0.7067456245, + -0.1197778061, 1.3785123825, -2.2226142883, -0.1396190971, 1.3109309673, 0.0336780511, -0.589910984, 1.8874821663, + 0.4395863414, -1.2137041092, 0.9638198614, 0.5589596629, 0.1619139463, -2.0408895016, 0.056015227, 0.7049338222, + -1.8372228146, 0.089555569, -0.8652178645, -0.5274806023, -1.4498169422, 1.8824826479, -0.7552757263, 0.8409298658, + -1.4074972868, 0.2751502097, -0.0361059606, 1.3069361448, -0.4460712075, 0.7948856354, 0.2241593003, -0.0092800902, + 0.1511366814, -0.570077002, 0.9738789201, 1.4050635099, 0.7358398438, 0.3554930687, -0.535695374, 0.615432322, + 0.9979453087, -1.3390628099, -0.8583290577, -1.7452572584, 0.1104434729, 0.3890730739, 0.0756772608, -1.6073110104, + -0.3842329979, -0.5743327737, -0.5342398882, -0.594379425, -0.6329166293, 0.1348872036, 0.0209345836, -0.6921874881, + 1.2580894232, -0.1487711817, 1.4409718513, -1.9829041958, -0.3945930004, -2.0652801991, 1.9432833195, 0.8998360634, + -0.2134810537, 1.7895114422, 1.2492611408, -1.2575070858, 0.2093546093, -1.7946289778, -2.2766561508, 1.5815219879, + -0.6217867732, -1.5840293169, 1.0552384853, -1.4108628035, 0.0078826984, 0.0647610202, -1.2973845005, -1.4553879499, + -0.6940916181, -0.0104205608, 0.2180850804, -1.1110692024, -1.4055019617, 0.6910184026, 0.1690434515, -0.5238924026, + -0.9038918614, 0.1617193222, -1.5668437481, 0.5746982098, 0.7966463566, 0.3421330154, -0.1778702289, 0.0627256557, + 1.2577672005, 0.7419780493, -0.4220174253, -0.5558896661, 0.5636611581, -0.5715605617, 1.2305231094, -0.6542611718, + 0.5123797059, -0.5756513476, -1.2421853542, 0.9539251924, -0.7216297388, 0.2888312638, 0.0398992859, 1.9420181513, + -0.9858289957, 0.1439062804, -0.1981014162, -1.3955296278, 0.1860184371, 0.5092500448, -2.2733435631, 0.4448447824, + 0.7383634448, 0.9620494843, 0.9712896943, -0.5859873295, -0.4633949995, -1.1635951996, -1.0255144835, 0.9860011339, + 0.3003800213, -0.6828405857, -1.2880755663, -0.0181694888, 1.3963208199, 0.6787196398, -1.3546409607, 1.0398122072, + -0.0002420847, 0.4149239361, -1.3920470476, 0.4387226701, 1.7786114216, 0.0279869679, -0.5754590034, -2.8383243084, + 0.3669659793, 0.398978591, -0.3432056606, -1.4067237377, -0.5664580464, -0.7988797426, 1.9535807371, 0.9568747282, + -0.2729994059, 2.0905108452, -0.9002789259, 1.7589235306, -0.2031082958, 0.2045028061, -0.3391548991, -0.0187342484, + 0.6179451942, -0.1164130643, -1.0554273129, 1.1348347664, -0.5240642428, -0.0533059984, 1.1834615469, 1.4722721577, + -0.3002305627, -1.1545814276, -0.0434754863, 0.3521986306, 1.1709691286, 0.2513211071, -0.4330072105, 0.3237198889, + 0.2494965345, 0.2712747157, 0.1401934177, 0.052103769, -1.1359419823, -0.8886265755, -0.4292696416, -0.6217500567, + -0.2999503016, 0.223963663, -1.4546821117, -0.4629549384, 0.2481509894, 1.1152031422, 1.2186678648, -0.8037263155, + -1.8307890892, -0.9193554521, -1.9347736835, -1.7906540632, 1.4603732824, 0.6034803391, -0.7582035661, -1.456283927, + -0.4283702075, 0.2467783093, 0.8750617504, -0.5399234891, 0.0219904687, 0.1347843856, -0.6984317899, 1.2807254791, + 0.697206974, -1.1246480942, 1.2445069551, 0.074697651, -0.3634368479, 0.9292349815, -2.119328022, 1.9793330431, + 0.9654034376, -0.8357360363, 2.3896911144, 0.5750907063, -0.6683084369, 0.4982488751, -0.2650178075, 0.3913143575, + -1.9028433561, 1.2230871916, -1.6067589521, -2.1641135216, -0.6277225614, 0.8032400608, 0.6450325251, -1.3358204365, + -1.5891611576, -0.3048976958, -1.1766319275, 0.9003731608, -0.2710793614, 0.7207944989, 0.2262839079, -0.2502329051, + -0.2332939208, -0.3703612685, 0.4698289037, -0.7305675745, -0.2357319444, 1.5106195211, 1.0950709581, -0.6133319139, + 0.5051881671, 1.0278711319, -1.7371171713, -0.237027213, -1.0186152458, -0.5381708741, 0.6036685109, 0.0080919098, + 1.3370512724, 0.3532626629, -0.7991682291, -0.2605423033, 0.9962968826, 0.3493235409, 0.4128884375, -0.7413421273, + 1.0753172636, -0.1606328785, -2.4201703072, -0.7577661276, 0.9301439524, 0.3775624931, 0.3262410164, 0.8824862838, + 0.4710078835, -0.8032360673, -0.5725351572, -0.0582918525, 0.7470893264, -0.4320694208, -0.4195062816, 0.7359803915, + 0.9830491543, 0.1097064689, 0.5909559727, -1.5239113569, -0.5554866791, 0.1916795075, -0.2884576321, 0.4674206376, + 2.1317734718, 0.8106547594, -1.1282305717, 1.1774668694, 0.529761374, -1.5435117483, 1.0490826368, -1.4259819984, + -1.2291139364, -0.0065258709, -0.2216066718, 0.3152341843, 0.3517228663, 1.0046916008, 1.1837831736, 1.6787571907, + 0.5730426908, 1.1133731604, -0.7634158134, -0.4686076939, 0.7512238622, 2.1902413368, -1.108024478, -0.086619541, + 0.7111128569, -0.0059136329, 1.6001064777, 0.2407293469, 0.7014157176, 2.2532317638, -1.169208169, 1.0892179012, + -0.1247122213, 0.3142854273, -0.0842473879, -0.1432422101, 1.1002390385, 0.589838624, -2.9799461365, -0.5483270288, + -0.3715531826, -0.3583878279, -0.0210139882, -1.1149870157, 2.4004268646, 0.1063649058, 0.7702438831, -0.4968264401, + 0.0172923505, 0.2284315526, -1.0430088043, -0.9970272183, -1.6039516926, 0.2978511751, 0.3246447444, -1.1764000654, + -1.0792928934, -0.7115822434, 0.9049133658, -0.1356133074, 0.79021734, -1.860892415, -0.0342043675, -0.2184225768, + 0.275511831, -0.5773473382, 1.907980442, -0.9805600047, -1.7185441256, -0.2441821545, -1.562515974, -0.0510449111, + -0.6830695271, 1.469195962, 0.3331987858, -0.18617405, -1.2373799086, -0.2372961491, -0.153793335, -0.1583372951, + 0.9213557839, 0.1104177907, 0.7021344304, -2.2697911263, -0.9931976199, 1.3266222477, -2.088670969, 0.9214906096, + -0.49293679, 0.7904263139, 1.5942453146, -0.5685650706, 1.1563068628, -1.7574599981, 0.3507694304, 0.9195406437, + 2.1849930286, 0.4669177234, 0.0332165174, -0.9302831292, -1.1052159071, 0.5699044466, 2.7418849468, -0.8644914031, + -1.1204868555, 1.0906944275, -1.8325343132, 1.2423360348, 1.0562793016, -1.8252551556, -0.1053487584, 0.6263771057, + 1.5337488651, 0.3819944263, -0.3788675964, 0.4347829521, 1.0719298124, -1.9757854939, 0.453861624, 0.9466922283, + 2.0393373966, 0.815454185, -2.2556941509, 0.2045707256, 1.3789530993, 0.4618313015, 0.6645997763, -0.1469683647, + 0.9429551363, 0.3144655824, 0.5231790543, -0.3446117938, -0.9457993507, 0.7486024499, 1.3672702312, -0.7518332005, + -1.3094704151, 1.2875912189, -0.6445900202, -0.4857350588, 2.7472012043, -1.5506581068, -1.7447063923, -1.684907794, + -1.1065803766, -0.0241784956, -0.0330930389, 0.8838341832, 0.7734587193, 0.5042662621, -0.6122062802, 0.7282840014, + 0.97802037, 0.7290042639, 1.1951694489, -0.0285034478, -1.7318187952, 2.8072602749, -0.8139628768, -0.6801139712, + 0.336807102, 0.630359292, 0.0890115127, -1.2492383718, 0.6210021377, -1.3981107473, -0.0684296265, -0.8358044028, + 0.7615279555, 1.1252840757, -0.2928672731, -0.1489151269, -0.2545097768, 1.7402290106, 1.0581798553, 0.1409235895, + 1.313472271, -1.2648737431, 0.34410128, -0.933619082, -1.2345448732, -0.1902813017, 0.8853290677, -0.5469426513, + -1.2303242683, -0.2285664976, -0.2023745328, -0.4210486412, -0.1622483581, -0.6331458688, 0.667370379, -0.8797009587, + 0.1470505744, -1.6115312576, -1.7434673309, -1.1627935171, 0.2992941439, -0.7151190042, -1.2173782587, 0.2558501363, + -0.503192246, -0.103860639, -0.1561047882, -0.8796012998, 1.0886113644, 0.3119497001, -0.402297765, -0.1012258232, + 1.7479351759, 1.364773035, -0.0543092415, 0.2226750851, 1.6659430265, -0.5892763734, -0.316729337, 0.7162985206, + 2.7947816849, -0.2856855094, 0.3759886622, 0.6820854545, -1.9602570534, 2.3843588829, -0.8123612404, 0.6058959961, + 0.7391664982, -0.4000688791, -0.9828444123, 0.70605582, -0.7857539058, 1.1159673929, 0.2286228538, -0.466154933, + 1.4146889448, -1.5722010136, 0.8475800157, -2.18506217, 0.4052006304, 0.9268170595, -0.5286844373, 0.3858979344, + -0.9194214344, -0.8946732283, 0.0659045056, -1.2474843264, 0.4395863116, -1.1277976036, 0.734330833, 2.2652714252, + 0.2736219764, 0.8193798661, 0.4121380746, 0.967726171, -1.4630614519, -1.0397695303, 0.3285118639, 1.4500451088, + -0.1098707393, 0.8462182283, -0.6662430167, 0.5424329638, 1.0663647652, 0.315530777, -0.6716760993, -0.8097543716, + 1.6464439631, 0.5302342176, -0.3151896596, 0.2689172924, -1.2359784842, -0.1069266498, -1.5323109627, 1.3193717003, + 0.6514467597, 1.5726830959, -0.5646753907, 0.8270943761, 0.0647617579, -0.599774003, -1.9733934402, 1.2835294008, + -0.7041236758, 0.2832516134, -1.2470406294, 0.0342308544, 0.5632337928, 1.7738374472, 1.0023999214, 0.524348557, + 0.496639818, -1.9411910772, -0.5846640468, -0.1156490222, -1.8383711576, -0.6315868497, 0.2895682454, -2.7668647766, + 0.1243848652, 0.540370822, 2.5971651077, 0.9537038207, -0.5311449766, -1.9729572535, 0.1686208397, -2.2282452583, + 0.0519388616, -0.8657557368, 2.1935203075, 0.9435275793, 0.3583879769, -0.7221446037, 0.8322559595, -0.1130532399, + -1.4182372093, 1.7974859476, -0.6891320348, -0.2459898293, 0.3112476468, 0.2605895996, 0.4272195399, 0.5657240152, + 0.1126472205, 0.5242422223, -0.5227910876, 0.8922997117, -0.4843709171, 0.3712804914, -1.6282891035, 0.1348460317, + 0.3993672132, 1.3468558788, 0.7090018392, 0.4272810817, 0.3625778258, -1.5106115341, 1.8112719059, -1.1968251467, + -0.1324630231, -0.7746610045, -0.1489947736, -0.2863193154, -0.7271369696, 0.4484030902, 0.4039295614, -0.6630720496, + 0.2465493828, -0.1913393289, -0.5363966227, 0.0706059188, -1.9758604765, 1.2545558214, -1.2935758829, 0.1870326698, + 0.5147288442, 0.2047286779, -0.9113526344, -0.3674494028, -1.3195163012, -0.5636649728, 0.4023266137, 0.3050526977, + -1.3710098267, 0.72853899, -0.2600562572, 0.9642859101, 0.7061238289, 0.0804846361, 0.3684956729, -1.3706005812, + 1.7705264091, -0.0568827242, -1.1363366842, -0.5154197812, 0.4832886755, 0.1776915193, -2.1355118752, -0.2538057566, + 1.1987390518, -0.9549040198, 1.4837807417, -0.3976415396, 0.2713989019, -1.3256140947, 0.0872604623, -1.8873546124, + 0.4834865928, 0.7455752492, 0.0950498506, 0.2772811353, 1.2658462524, 1.5551054478, 1.7185579538, -0.2580177486, + -0.5866049528, 0.3638573885, 0.4724708498, -1.0699458122, 0.3302752972, -0.571736455, -1.9355258942, -0.416905582, + -0.3732923865, -0.4488600194, 0.1205200925, -0.661141336, 0.3152336776, 0.5914426446, 0.5891466737, -0.4318289161, + 0.5248982906, -3.0162057877, -0.7288278341, 0.5338007808, -0.5691620111, 0.0026917364, 1.3950619698, 0.9638216496, + 1.2086063623, 0.5523138046, -0.1347372085, 0.4186432958, -0.012545933, -2.3909592628, 1.2674869299, 0.8219062686, + -0.9020726085, 0.8937808871, 0.5497428775, -1.8376889229, -0.3232720494, 0.9673829675, -0.1577348262, -0.8051065803, + -1.4380515814, 0.5605085492, -1.6228570938, 0.8229484558, 0.6320642829, 0.8324034214, -0.795843184, -1.2507016659, + 0.358599931, -0.2646588385, 1.5732150078, 0.3994229436, -0.631878078, 0.211893931, 0.4288383722, 0.1017487049, + 0.3347709477, 1.3281470537, 0.5289729238, 2.2454297543, -1.1805934906, -0.155069083, -0.1861247271, -0.6157492399, + -0.2086265832, 1.8791502714, -0.5473974943, 1.2587167025, 0.0400549732, -1.2131153345, 0.4959487915, -0.6701539159, + 0.0377192609, 2.0914919376, -1.2017105818, -0.5418961048, 0.0715248883, 1.1804654598, 0.0372791365, 0.5071865916, + -1.1190364361, 0.1947530657, -2.2451906204, 1.811568737, -0.3882434666, 0.4428933263, -1.3330305815, 0.0781882405, + -0.1043641046, 1.0043901205, -1.0324101448, -0.4917244315, -0.5101444721, 0.772264123, -0.5372172594, 0.3941535652, + -1.0564483404, -0.11427439, 0.2367779464, -0.4811623394, 0.8114396334, 0.7052668333, 1.3426921368, 0.4971502721, + -0.4514482915, 0.1606788486, -1.0752604008, -1.564720273, 0.3447371721, 0.2896904051, 0.6959680319, -0.0190260354, + -0.1225974485, 0.6586026549, -0.3244411349, 0.7685539126, -0.1682316661, -0.978004396, 1.9468239546, -0.1223541796, + 1.4135782719, -0.3331348896, 1.5832772255, -1.2763670683, 0.352427125, -1.0963369608, -1.360070467, 1.3364082575, + 0.8700780272, -0.3765659034, -2.6367402077, -1.0929170847, -0.0520115234, -0.9117823839, 0.5583176613, -0.8233562708, + -0.1356477439, -0.5791643262, 0.2063644528, 0.0742090866, -0.91298002, -0.5781509876, -1.3166632652, 0.5495023131, + 0.6567738056, 0.5245886445, -0.56418401, 0.1216162369, -2.2587895393, -1.1103811264, -0.2331566811, 0.422216624, + 1.4316504002, 0.8986779451, 0.2228398025, 1.3977748156, 1.0694563389, -0.8107503653, 0.7228331566, 0.2350391448, + -0.1462830901, 1.1465845108, 3.0110960007, 0.1884022951, -0.2710390687, -2.4918198586, -1.3116731644, 0.6081784368, + -1.82741189, 0.323774457, -1.099689126, 1.6525988579, 1.7144389153, -0.7473198771, 0.1106017306, 0.060773842, + -0.4209593534, 0.5615531802, 1.1473829746, 1.3023934364, -1.0771951675, -0.0043456485, 1.1957966089, -0.6975986362, + 0.6175321341, 0.0798140764, 0.3990066051, -0.1930454522, -0.2801606953, -0.6360430717, 1.5740067959, -0.615062654, + -0.6657387018, 0.6328179836, 1.5874658823, -0.8234479427, -0.9082185626, -0.904949367, -0.1048155203, 1.4692788124, + -1.4920828342, -0.2135273218, 0.1324931532, 0.3250708878, -0.559564054, -1.6266405582, 0.6432067156, 1.0292233229, + 0.458058387, 0.1775811911, -0.0012351129, -0.4039856195, -0.862308979, -0.4011097252, 1.3185437918, 2.47210145, + 1.5110800266, 1.1565639973, 0.1544111222, -1.4040644169, 1.1386544704, 0.4006298184, 0.1019146889, 1.1850543022, + 0.5945206881, -0.3560276926, 0.8948068619, -0.3113974035, -0.5629203916, 0.8216427565, -0.8694606423, 2.0849277973, + 0.4553703964, 0.2011788487, 1.6399581432, 1.1543406248, -0.6563993692, -0.1601136774, 0.3659283817, -1.5479089022, + -1.6454467773, -0.5885052681, 0.4701368809, 0.8731890917, -1.0473310947, -1.6058140993, 0.5154587626, 0.0192641634, + -1.176155448, 0.3215034902, -1.0969194174, -1.1431628466, 0.9230197072, -0.8684829473, 1.2271327972, 1.0552119017, + -0.4195388556, 0.7144517303, -1.555383563, -0.5773956776, 0.9839149117, 1.9320902824, 0.468603313, -0.5418919921, + -0.2432720214, -2.3585970402, 0.6843538284, -0.5589225292, 1.4080122709, 0.5970636606, -0.6819794774, -0.7745859027, + -0.5762728453, 3.3780813217, 0.9202184677, -0.5481423736, 1.3764128685, -0.3434719145, 0.3977651894, 0.3125531971, + -0.3766749501, -0.9650712609, -0.6414336562, 0.2432779819, -0.0810078681, -1.4610075951, -0.5868371129, 0.6019322276, + -1.1608246565, 0.4770873189, -1.1839425564, -0.9647042155, -1.2911399603, -0.7851390839, 0.0474583209, 0.5524968505, + -0.4648094177, 0.6342483759, 0.2583498955, -1.6864966154, 0.009350732, 0.6306871176, 0.3638943732, -0.5551549792, + 1.9378409386, 0.4792116284, -1.3169698715, 0.3789154291, 0.5505794883, 0.3445309401, -0.2305428237, -0.5491927266, + 1.403927207, -0.1311127692, 1.2018909454, 1.4131186008, 0.6897209883, 2.8037290573, -0.9207084179, 0.3258124292, + 0.5043047667, 0.0766622126, 0.696993947, -0.2453171611, -0.0269711744, 0.1035700291, 0.1819505543, -0.5836421847, + -0.6208786964, -0.8684943914, -1.0072883368, 2.5586364269, 1.1484230757, 1.4538383484, 1.0172985792, -1.130661726, + -1.1712599993, 1.4082340002, 0.1663869172, 0.8057622313, 0.0210015643, 1.0863547325, -0.4501363635, 1.1340610981, + 0.394774884, -0.9205060005, -0.1627232879, -1.3064237833, 0.768411994, -0.2114374936, -0.4287933707, -0.4915237129, + -1.6247475147, -1.9873917103, -0.0473227836, 0.3810624182, 2.1965646744, -0.4863922298, -0.2136739194, 0.2542577088, + 0.6342818141, -0.6232274175, 1.3386460543, -2.8707752228, -0.8340262175, 1.6175956726, -1.5389409065, 1.0650939941, + 1.5738481283, -0.2559369802, 1.8801785707, -0.6821094751, 0.5025829077, 2.023266077, 0.7300717235, -0.7082805634, + -1.3114689589, 0.5112272501, 1.6427576542, 1.4437679052, -0.4480295777, 1.2616261244, -1.0043283701, 0.0544764996, + -1.6036715508, -0.1986960471, 0.7933214307, 0.6842283607, -0.9457077384, 0.3122385442, -0.3216295838, -1.5933513641, + -0.9579170942, 0.3627172709, -0.8289911747, 0.6612448692, -0.1123323664, -0.178104654, 1.4285470247, -0.7790344954, + 2.9845044613, 1.1620213985, 0.855866015, -0.2367271185, 0.3755499125, 1.6477419138, 0.1121707782, -0.9373643398, + -1.3632234335, -1.5604901314, -1.6682239771, -0.2411317378, 0.1953369826, -2.2244782448, 0.4661431313, -0.6613999605, + 1.1189903021, 0.4893060029, 0.8133631945, 0.1535202712, 1.6659163237, -0.6708444357, 1.8384982347, -2.3238289356, + -0.0551512279, -0.9679136872, 0.0428756699, -0.7018769383, -0.1918913126, 0.7778669596, 0.871606648, 0.6106519103, + -1.2859187126, -0.4537215829, -1.1330381632, 1.0173296928, 0.6480510235, 1.4370362759, 0.1523553282, -1.6252946854, + 0.6880706549, -0.4669993222, -0.1189476922, -0.0044371127, 2.1690118313, 0.264235884, 0.2700255215, 1.5732755661, + -0.3509848118, -1.871535182, -0.0526743382, 0.3962967694, -1.5842945576, 1.2396576405, -0.8333008885, 0.1840726137, + 0.7715519667, -0.3682126701, 0.360761553, 2.0035834312, 0.1541242748, -1.3954974413, 0.0325314477, -1.6350804567, + -0.945854187, 1.2335181236, 0.3805272579, 1.0706945658, 1.7222070694, -0.6014351249, -0.0275845937, 2.3488023281, + -0.9489246607, 1.0424493551, 0.5509977937, 0.5912781954, -0.3194181025, -1.8344695568, -1.5199538469, -0.2534407377, + -0.6822112203, -1.5001311302, -0.5672664046, -0.0814578012, -0.7873686552, -1.0422301292, -0.3025351763, 0.4241429865, + -1.5904347897, 0.1101631746, 1.0006101131, -0.6859989166, 0.97532022, 1.0051900148, 0.5923214555, -0.4300889373, + 0.7324078083, 1.2622574568, 0.0162067059, 1.2897980213, -1.6987493038, -0.7873823047, -1.1084727049, 2.4867002964, + -1.0069047213, -1.1833405495, -2.6878020763, -0.479925096, 1.2554645538, -0.5688960552, 0.0881453305, -0.4376583397, + -0.6516036987, -1.0665112734, 0.1584681869, 3.1608436108, 0.5720539689, -1.5262326002, 0.4792236686, 0.259724319, + -0.0070801945, 0.4739401639, 0.1779567897, 0.4280982018, 0.319599092, -0.8183332682, 1.4376466274, -0.318005234, + 1.3227945566, 0.3346593678, 1.6663300991, 2.1549162865, 0.5529408455, 2.3215246201, 1.6306368113, -0.2287237942, + 0.3626566231, 0.6241252422, 0.2874783874, -0.5562575459, -1.0645240545, 0.3074939847, 0.9751630425, 0.4938282371, + 0.4887374043, 0.0105593298, 0.6010999084, 0.1875414848, -1.4502644539, -0.5887443423, -1.1079670191, -0.7399981022, + -0.5830377936, 1.9610450268, 1.9490827322, 0.1687097102, 0.6483928561, -0.3631643653, 1.2609117031, 0.547011137, + 0.3083211482, 0.977927804, -0.2285307497, 0.6608920097, 0.4434262514, 2.3462135792, 1.2344197035, -2.0416243076, + -0.507887125, 0.6721323133, 1.3655580282, 0.6412608624, -0.1009380966, 0.8257616758, -0.8150367737, -1.0085000992, + -0.2928051651, -0.61507231, -0.4936757684, -0.2183852941, 0.9689996243, 1.4067459106, 0.2134040892, -0.4075092673, + -0.492028594, -1.7855901718, -1.0941070318, -0.2059654444, 0.6229280829, -0.7334624529, 1.2113645077, -0.4594071805, + -1.4258073568, 0.5498878956, -1.5167644024, -1.0164055824, -0.9841329455, 0.4166430235, -2.2984161377, -0.7978627086, + -1.9428042173, -0.4716677964, -2.6861188412, 0.2464052886, -0.7541234493, 0.0767890364, 2.4924387932, 1.0294005871, + 0.4078120291, 0.0231720693, -0.2605399787, 1.0949954987, -0.482562393, -0.8047713041, -0.9314247966, 0.1557550281, + -0.2464975119, -1.7501392365, -2.1452300549, 2.0917215347, -0.50788486, -1.150200367, 0.8368268609, -2.2316017151, + -0.6839256287, 0.8083926439, 1.5101549625, 1.7092049122, 0.3911790252, 2.3782274723, -1.8589886427, -0.3594858348, + 1.6014767885, -1.154191494, -1.0710375309, -1.0111941099, -0.3062404394, -0.2918458283, 0.4250952005, -1.4448601007, + -0.6035043001, 1.5781127214, -1.5689852238, -0.8176691532, 1.5150188208, 0.6178444624, 1.6630421877, 0.4960637987, + 0.2892667055, -0.4297368526, 0.3063223064, -0.3640555441, -1.3150182962, -1.525442481, -0.1548462957, 0.171724543, + -2.3199658394, -0.6687420011, -0.8737539053, -2.1310255527, 0.1657736599, 1.0154526234, -0.8788712025, 0.4433715641, + -0.6407283545, -0.1064218804, 0.9291561246, -0.4667377174, 1.0356763601, -0.2875490189, 1.7318445444, -0.1297231019, + 0.2333392501, 0.1582544744, 2.0523178577, -0.7429432273, -2.1222071648, -1.4895672798, 0.3120341897, -1.4317234755, + -0.6542963386, 1.3853491545, -0.8467838168, -0.7864772677, -0.7140951753, 0.7617847919, 2.6022748947, 0.4526357949, + -0.134485364, -0.7801381946, -0.3832502067, -0.0866161734, 0.4906598032, -1.0615791082, 0.8940999508, -0.3497473001, + -1.2624950409, 0.1075066999, -0.0659220442, -0.6305398345, 0.2686221302, -0.1823195964, -1.4534528255, 1.9937129021, + 0.1483629793, -0.2734782398, -1.5328689814, 1.9309226274, 0.0419135392, -1.9509328604, 0.3718533218, -1.223375082, + -1.3658379316, -0.2958777845, -0.4734799266, 0.7543007135, 0.2856521606, -0.4374417663, 0.8792541623, 1.3735964298, + -1.4071791172, 0.1599424481, 0.2732090056, -0.1884759814, 1.5184983015, -0.3780666292, 0.1182340458, -0.341712743, + -0.6154448986, 0.9049147964, -1.8434865475, -0.6616224647, -0.2895358503, -0.4325897992, -0.6810391545, -0.1942910403, + 1.0399843454, 0.7656468153, 0.8919506073, 0.8561698794, 0.597658217, 0.878040731, 0.2451337427, -1.2113918066, + -1.2457233667, 0.5290142298, 0.8976787925, -1.4235173464, -1.2115622759, -0.9235364795, -0.5710926652, -0.6926459074, + -0.8372098804, 0.1629962623, 0.7053339481, -0.090441674, -3.0984549522, 0.6686881185, -0.7333278656, -0.6111493707, + 0.7304154634, -0.8588292599, 0.8808065653, -0.6583173275, 0.7451996803, -0.2612974644, -0.7302530408, 0.4351638556, + 0.9296533465, 0.6713768244, 0.3829293251, 1.4064166546, -1.201390028, 0.1457719803, -0.9313827753, 2.6163449287, + 0.5473232865, 1.4893498421, 1.4373891354, -0.7347108722, -0.8683974743, 1.4311701059, 0.2228661329, 0.4464642406, + 1.1559196711, 0.0410200059, -0.1286565661, 0.2647444606, 0.6956012249, 1.3178719282, 1.0041838884, 2.1021845341, + 1.0517970324, 1.4445554018, -1.1228381395, 1.5592223406, 1.2020138502, -0.0028192063, 0.5974342823, -0.8048190475, + -0.9230668545, 0.3318743408, -0.8511945605, 0.0609234236, 2.2532401085, 0.2028496712, 1.1774448156, -0.5526928902, + -1.9647001028, -1.8609727621, 1.0291814804, 1.0270837545, -0.1857776791, -0.811963439, 1.0355705023, 0.2473882139, + 1.0378277302, 0.5087451935, -0.9540367126, 0.8271316886, -0.2665016651, -1.7770938873, -0.6815657616, 2.0232789516, + -1.2229034901, 0.2241365314, -0.0978290513, 1.214242816, -0.3724579513, -0.3604663312, -0.4075214565, -0.1006050706, + 0.7029295564, 0.9857544303, -1.3855587244, -0.7235353589, 0.1705339402, 0.2272443473, 1.5756491423, -1.0199034214, + -1.4712222815, -0.1937682778, -1.4571503401, -0.4014287293, 1.791383028, 1.4787840843, -0.8528799415, 0.8736353517, + -0.1563538909, 0.1690182835, 0.4658602774, 0.1371072829, 0.207834661, -0.4466711581, -0.9114081264, -1.0166107416, + -2.6908288002, -1.5399973392, 1.4427289963, 2.1239728928, -1.7548342943, -0.4824391305, -0.526209414, -0.5427834392, + -0.696646452, 0.4204410613, 0.4263037443, -0.4591600001, 0.2637559772, -1.9718030691, 1.6417837143, -1.1051946878, + -0.3639093637, -0.9486865997, 0.4432385862, 0.3481712639, 0.4060375094, -0.5423926711, -0.352758348, -0.4264259338, + -0.9308899641, 1.5440005064, 1.5066274405, -0.1226757243, -0.3284087479, 0.1419685334, -1.1529750824, 0.2755541205, + 0.7012867928, 0.093665421, 0.8950644732, -2.6700437069, 0.2992852926, 0.6254771352, 0.1787260175, 0.9335781932, + -0.5372442603, -0.983119905, 0.8023634553, 0.925265491, 0.0591549464, 0.6226165891, 0.2587251365, 0.83552742, + -0.7327592969, 0.6793955564, -1.4561997652, 0.7465295792, -0.7011393905, 1.5439178944, 1.182677865, 0.2308337688, + 0.3512136638, 0.143145144, 1.1339086294, -0.2589430809, -0.2183725685, -0.1566379517, -1.6944813728, 0.3345756829, + 1.6899503469, -0.0316444114, -1.1810456514, -0.3684019446, 0.3207881749, 0.7920659781, 1.64220047, 0.2716714144, + -0.5603635907, -0.3599757254, 0.1677870452, 0.00781981, -0.4939026535, -1.7546492815, 1.0226032734, -0.0200631488, + 0.5507588387, 0.4915273488, -1.8573807478, 0.8740385771, 0.0427967496, -1.6065392494, 0.7721800208, -1.1217762232, + 0.6055000424, -0.9973308444, 0.6799186468, 0.1740625948, 0.0296238065, 0.5217496157, 0.1923450679, -0.5879488587, + 0.5928028226, -0.5710805058, -0.7600550652, 1.1986136436, 0.8760007024, -1.8550120592, 0.724578023, 0.0701237619, + -1.0581716299, -0.1062726602, -1.1632649899, 2.3888280392, 0.0001293403, -2.5444760323, 1.6522936821, -0.4627757967, + 1.1748318672, -0.1822272688, -0.7353000641, -0.9973748922, -1.235553503, -0.4939834774, -0.9968354106, -1.772896409, + -0.0487909168, -1.1636132002, 0.7202252746, 1.982591033, -1.6155759096, 0.5454311371, -0.7507312894, 0.6600294113, + 0.0698041469, -0.8771593571, 0.4602817297, -0.5655164719, 0.0821633413, -1.6148333549, -0.2856899202, -0.9010733962, + -1.5962631702, 0.0608109497, 1.7148712873, -0.1972455084, 0.7661412358, 1.7797145844, -0.7024210095, 1.1253442764, + 1.9075862169, 1.8911184072, 0.2929170728, -0.4096447527, -0.0711998194, -0.7124832869, 0.2756503224, 0.8862338066, + 1.5982501507, -0.8595206738, -0.8688374758, -0.646166563, 0.7948951125, 0.219212234, -0.0730743557, 0.1788961291, + 0.0994319618, 2.5646259785, 2.1651239395, 0.6786749363, 0.8574656248, 0.1200354621, 2.7303805351, -0.4879829586, + 0.8700460196, -1.2592363358, 0.5971306562, 1.3760768175, 1.4629197121, 1.4793893099, -2.2686212063, -0.3273313642, + 0.497333318, -2.2781610489, 1.1125961542, -0.3504355848, 2.1755020618, 1.2387313843, -2.126335144, -1.7304564714, + 0.6072626114, 0.8712618351, 0.1535709053, -0.8973566294, 1.4609305859, 0.0118550872, 1.2186610699, -0.3652283251, + -0.0985303745, -0.437272191, -1.124651432, -1.907643795, 0.0822057426, 2.1654286385, -0.5866769552, -2.5962011814, + 0.7465396523, 1.0702034235, 0.3408767581, 0.8843899369, 0.9880162477, 0.3733038008, 0.7469571829, -0.3654667139, + -1.1835292578, 0.0639124513, 0.9607874751, -0.6897494197, -0.1239338443, -2.100944519, -0.1710033417, -0.0617053173, + -0.0188370664, -0.2777236104, -1.4326847792, 0.8153862357, -0.0844529122, -0.1488251239, -2.050773859, 0.6880062222, + -0.5953730345, 0.8839527965, -1.1588287354, -0.8564046025, 1.0334230661, -0.8303106427, 1.0943323374, -0.1897011697, + -0.7996029854, -0.3756458759, -1.0631002188, 0.621021986, -0.8794413209, -1.2669420242, -1.6641253233, -0.9473111033, + -0.1794932634, -0.7986416817, 0.4215012491, -0.3709406555, 0.175747484, 0.9827396274, 0.0277207959, -0.1375899166, + 0.910558641, -0.6598195434, 0.6502033472, -0.917106986, -0.082183212, -1.2704133987, -1.4377149343, 0.8652183414, + -1.9529612064, 1.0661842823, 0.9509752989, 0.792309165, -1.2883765697, -0.113207452, 0.0863654539, 2.7263689041, + -0.2265016735, 0.2427878529, -0.7156814337, 2.1491582394, 1.4603886604, -1.8682442904, -1.1941982508, -1.4207702875, + 0.2143935561, 0.687312603, -0.8676314354, 0.8319645524, 1.4122692347, 0.3956587911, -0.3590189219, 1.4693763256, + 0.0357302763, -1.7043617964, -0.5215309858, 1.2631664276, -0.526420176, -0.1750185192, 1.4218360186, 0.2109541893, + -0.8578353524, 0.034134917, -0.8854100108, 0.6071174741, 0.2590273321, 0.6369572878, 0.2007258683, -1.5683698654, + 0.0528304949, 0.2185943723, -2.0792095661, 0.3473087549, 1.5566731691, -0.9429470301, 0.3542098105, 0.1842521578, + 0.0781935975, 0.9226818085, -0.142378673, -0.4596142173, 0.4551231563, 1.8416955471, 1.6079021692, -0.8521170616, + 0.575678885, -0.5148565769, -1.2641240358, 0.1978517026, -1.4766743183, 1.1515684128, 0.1763038188, 0.264069289, + -0.8323398232, 0.0230683852, 0.6586131454, 1.5933395624, -1.4179666042, -0.777467072, -0.4964284897, 1.4293264151, + 0.2270773351, -0.016794106, -2.0283677578, 0.0885260925, 0.3764227331, -0.7332847118, 0.9534940124, -2.1248283386, + 1.4294171333, 0.7428011894, 0.3662443757, -0.0806344151, -0.0672872812, -0.1971713156, 0.2399710268, -0.5236250758, + 1.1410593987, -0.0949220136, -0.1947147548, 1.1396582127, -0.108009316, 0.3194012046, 0.2399757802, 1.7890506983, + -0.1936757118, 0.8872783184, -0.1072830781, 1.3524184227, -0.4339081645, -2.626172781, -0.5521342754, -0.3567785025, + -1.3351668119, -0.5639197826, -1.2869068384, 0.4983268678, -0.3498931229, 0.0223497171, -0.6007211804, -0.005224912, + -0.0424862429, -0.4661367536, 0.1067087874, -0.0690322369, -0.8722267747, -1.475307107, 1.1081073284, -0.3371511996, + 0.5770972967, 0.4407486618, -1.323777914, -0.4519773126, -1.7085222006, -0.8972691298, 0.9348768592, -1.0095119476, + 0.8008344769, 0.5961164832, -0.3867681026, 0.051639583, -0.5375924706, 0.7138876319, -0.9433989525, 1.0816320181, + 2.1809961796, -1.1811590195, 0.3935625851, 0.303032279, -0.6758750677, -0.9937831759, -1.3757630587, -1.3634648323, + -0.8317195773, 1.4114764929, -0.3476401865, 0.2501884401, 1.3920596838, -1.5477883816, 1.7170302868, -0.8295890689, + 0.661783576, -0.5374920368, 0.1471432447, 0.359703362, -0.1635111123, 0.840472579, 0.1525148302, 0.7160716057, + -0.8264759183, -0.5981168151, 1.0916924477, 0.942759037, 2.3003776073, 0.5416697264, 0.4278137088, -0.3079363406, + 0.1193876937, -0.2164104432, -0.0375090204, 2.0504729748, 0.2739741802, 1.0871514082, 1.1895177364, 0.0692935809, + -0.227511555, 1.4736508131, 0.6942522526, 0.1104047671, -0.8769634366, 0.7775915861, -0.3444183767, 0.0806557834, + 0.7060059905, 0.7481377125, -0.9507731795, -1.2001460791, -0.2362423986, -1.4188394547, 1.1630134583, -1.5362975597, + -0.594807446, 1.5993782282, -1.2341548204, -1.5226598978, -1.5064285994, -0.7967886329, -1.6548575163, -0.7267010212, + -0.2619487047, 0.8821213245, 0.9663928747, 1.4349234104, 2.9031307697, 0.6623058319, 1.7527112961, 1.4296424389, + -0.1722200811, -0.0848347172, 0.3168185651, 1.6467040777, 0.2583158612, 0.6035906076, 0.8671565652, -0.5262527466, + 0.3319886625, -0.5497463942, 0.420090884, 1.6204705238, 2.8567569256, 0.6891232729, 0.3979914188, 0.5920624137, + -0.7559434772, -1.0975944996, 1.1700562239, -0.4009858072, -0.7570546269, -0.8614937663, -0.8159902692, -1.5159968138, + -2.3159945011, 0.0993413925, -2.6141450405, -1.0592906475, -0.3929703832, 0.5702621341, 0.2737638056, 3.2217895985, + -0.4519669116, 1.0404402018, -2.1363830566, -0.0241962317, -0.0399352834, 0.8125180006, 0.9310963154, -0.2669395208, + 2.5663955212, -0.6801775694, -1.4735100269, -0.8673360348, -1.0219819546, 1.7570893764, -0.4413214624, 1.6531904936, + 0.0096711023, -1.3588843346, -1.0291464329, -0.2288335562, -0.2092395574, -1.4058778286, -1.1912089586, 0.3284628987, + -1.0475353003, 0.3501040041, -0.0520703569, -0.4176031649, -0.1001003236, 0.3600634038, 0.1698016822, -0.5551374555, + -0.0693989471, 1.827635169, -0.4938232303, 0.947429955, -0.3534296453, 0.8308686018, 1.282954812, -0.9371561408, + 0.2828264236, 0.8204187751, 0.681515038, -0.6391969919, -0.9756089449, -0.5878043175, 1.2785863876, -0.4788477421, + -0.9972364902, 0.5297797322, -0.4876992702, -0.9401187301, 0.1255615801, 0.2447793335, -0.2591195703, 0.2090267986, + 0.7089790702, -1.8272619247, -0.1440818161, 0.8749162555, -0.2225515842, 0.4995204806, 0.0576416738, 1.8956968784, + -1.2364346981, -0.703846097, 1.0908890963, -0.4718849063, 1.5693057775, 0.4428057373, -1.1780397892, -0.7212728858, + -1.7846194506, -0.1182599962, -0.7501379848, 0.2489561588, 1.8320907354, -0.6475961804, 0.3235092163, 0.1731548309, + 0.0735771284, -0.5053666234, 0.7075278163, 0.6965507269, 0.5890418887, 1.1716029644, -0.0515752882, 0.3394494951, + 0.7700596452, 2.5715339184, 0.6072596908, -1.3007305861, 0.0350546315, 1.1603693962, -0.4538965821, -0.9783593416, + 0.0265502688, -1.2858632803, 0.8167668581, 0.1688446403, 1.0662164688, -0.1026733741, -0.2595639229, 1.0778741837, + -0.4531909525, 0.7623999119, 1.2975021601, -0.0175253283, 0.5181298256, 0.279004097, 0.2507131994, 0.0025475521, + -1.6279962063, -0.1111964807, -1.8634821177, 0.6435146928, 1.0264328718, -2.0913350582, -0.5856692791, -0.10577254, + 0.984429121, -0.5320448875, -0.3761405051, -1.4245996475, 0.6602067947, 0.6311514378, -1.3559193611, 0.3137751818, + 0.0596246235, 1.0330663919, 0.2284503877, -2.2971618176, -0.2615343928, 1.0323364735, 0.8715969324, 1.4434144497, + 0.5397428274, 0.6451210976, 0.1844959557, -0.5831304789, -2.3598949909, -1.2856405973, -0.8049598336, 0.3824418187, + 0.3135951459, 0.5857704282, -1.8370773792, 0.0837134793, -0.7865746617, -0.0764674395, -0.9077297449, -0.0669379085, + -1.1441036463, 0.5880070925, 0.8309264779, 0.4098588824, 0.6063267589, 0.1993841529, 0.5601068735, 0.0649905801, + -1.5127788782, -0.6029203534, -2.0260241032, -0.0003807083, -0.1481437981, -0.8094789982, 0.0633503646, 1.7339324951, + 1.2790162563, -0.9811885953, 0.9675010443, 0.985316515, 0.5567837358, -0.3229420185, -2.2369308472, 0.8412714005, + 2.2719078064, 0.6248325109, 0.0663437992, -0.4816880822, -1.0125662088, 0.3245003521, 0.8556165695, 0.9044156671, + -0.4809673429, 1.5824408531, -0.6986125112, 0.1831489205, -0.3048543334, -1.6329776049, -1.0484548807, -0.6673472524, + -0.8022212386, -1.0551776886, 0.3699105084, -0.9840784669, 0.1571353376, 1.7181296349, -0.1393129677, -2.6459677219, + 1.3768317699, -1.6159496307, -0.008116575, 0.4292753935, -0.2024205625, -0.9072603583, -0.2654633522, 0.9579659104, + 0.167359978, -0.8797431588, -0.5267537236, 1.4190117121, 0.678506434, -1.144925952, 1.6081007719, -0.0469748788, + -0.1846182495, 0.2468699813, -0.2540178895, -0.7599125504, -1.4848744869, 0.3800463378, -0.3932013512, 0.1033055782, + -0.8647897243, 1.357962966, -0.6633557081, -0.2434872836, 0.5606272817, 0.6669448614, -0.8341302872, 0.3966738284, + -0.3269149959, 1.6633266211, -0.1126521826, 1.4816939831, 1.4156904221, -1.1166630983, -0.060655307, 0.0546188205, + 0.5445508361, -1.1936712265, -1.630979538, 0.8516145349, 0.5265679359, 0.1179899126, -0.5334897637, 0.5507861972, + 0.7433545589, -0.7290908694, 0.026658576, 0.2498948872, -0.4962490797, 0.9441946745, -0.5713911653, -0.0213359054, + -0.7809194326, -0.3588345647, 1.6766144037, -0.6612223983, -1.1081395149, 0.7486165762, -1.3002353907, -0.0150593566, + 0.5272737145, 0.7198087573, -1.7407058477, -0.8895874619, -0.9602290392, -1.239086628, -1.4357074499, 1.9074325562, + -0.7550415397, -0.6781569719, 0.4313832223, -0.8729441166, -0.1306226403, -1.0444041491, -0.3175023794, -0.0994322449, + -1.2217093706, -3.0405607224, -2.0784544945, -0.3157816529, -0.2450707406, 0.1222063676, 0.6923543811, 0.4367699325, + 2.0453593731, -0.1379508525, -0.2453946471, 1.9804742336, 0.8290540576, 1.7626791, 1.0024492741, 0.0583503172, + 0.4870532155, -0.5370153189, -0.3089361191, 1.2510309219, 0.3513412178, -0.9523450732, 1.0798521042, -1.5914729834, + -1.3701014519, -1.4990744591, 0.9432504773, -0.8200966716, -0.7967817187, -0.1315291226, 0.1992424875, -1.4237283468, + -1.0715271235, -0.3152555823, 0.6245658398, -0.5692147017, 0.6681869626, 1.0679280758, -0.0746023059, -1.1953831911, + 0.1121772081, 0.9854134321, 0.1716614068, 0.7160137892, 0.8524336815, 1.9281487465, -1.0551660061, -0.0363917984, + 0.8865175247, -1.9527336359, -1.4990662336, 1.0684392452, -0.6240852475, -0.333509177, 0.097398445, -0.1852093339, + 0.5368331671, -1.4069367647, 2.1364684105, -0.795529902, 0.8053387403, -0.2109974325, -0.276994735, 0.972743094, + -0.8858503103, 0.2244490236, 1.5067592859, 0.9171571136, 0.0369015187, 0.248874858, -0.4096579254, 0.1632209867, + -0.1903329939, -0.0624251887, -1.4613902569, 0.319244653, 1.052095294, 0.1580966562, 0.8568762541, 0.0363764167, + 0.0138445962, 1.7657972574, 0.0549255759, 0.9261724949, -0.2794926465, 0.2829901874, 3.4744529724, 0.6240840554, + 0.0514252074, 0.3288902938, -0.9306465983, -1.0744475126, -0.7351902723, -2.2935986519, 0.7545247674, -1.101978302, + -1.387421608, 0.7956593633, -0.2586257756, 0.8067504764, 0.6845870614, 1.1044504642, -1.3624535799, -0.0332132876, + 2.5060169697, 1.7505385876, 0.6042174101, 2.1284039021, -1.6996500492, 1.5683763027, -0.3298414052, 0.6837784052, + -1.2028763294, -1.4863746166, -0.4961459935, 1.916202426, -0.7335478663, -1.2341134548, -1.7722808123, 0.824097693, + -0.0894157216, -1.5428103209, 0.0126349842, -1.2780302763, 1.0979908705, 0.0222587101, 0.4325967729, 0.9945772886, + -0.5362792611, 0.1228516474, 0.2050954252, 1.4675050974, -0.5703064203, 2.197458744, -0.3568199277, 0.2641554475, + -1.1423335075, 1.1377191544, 0.0303159729, -0.2573347986, 1.0057265759, -1.4090272188, 2.4242238998, -0.6121561527, + -0.0515848696, -0.1749645323, 0.3523877859, -0.1276333034, -0.1103901342, -0.2866850197, -0.04641499, -0.307770133, + 1.4960175753, -1.3631552458, -1.7209351063, 0.6491242051, 1.4050065279, 0.2676798403, 0.2793314755, 2.0455369949, + -0.2602713704, 0.677464962, 0.2130657732, -2.2492074966, -1.394285202, -0.8942496181, -0.4105454981, 0.8247628212, + -1.2053675652, -1.0555409193, -0.4163510501, 0.9191569686, 0.0591878742, 0.8970375657, 0.0131746996, 0.3099085987, + -1.1245883703, -1.445835948, -1.0214380026, -0.4532108903, -1.0915752649, -0.2660917342, 1.9693787098, 0.0519596413, + 0.3412489295, 1.4262259007, 0.1354945898, 1.2808616161, -2.3592946529, 0.2309911996, 0.6223339438, 0.2537646294, + 0.3454696834, -2.0824322701, -0.1931213439, -0.322427243, 1.1653181314, -0.226078406, -0.421554178, 0.4131685793, + -0.3051755428, -1.334326148, 0.1708700806, -1.3212068081, -0.4973501563, 2.0076658726, 0.4784404337, 0.0108408937, + 0.6487086415, -2.2793097496, -1.5167176723, -1.121000886, 2.0984489918, -0.9964933395, -0.2537392676, -0.6362712383, + -0.6566887498, -0.4824739695, 0.9052526355, -0.9712961316, -0.1638876498, -0.0615659095, -1.1938039064, -0.2663016915, + 1.2792323828, 0.7501752377, 0.3072949052, -0.3662904799, -0.8046880364, -0.0044827433, 0.4288261235, -1.3418343067, + -0.8763881922, 2.3424198627, 0.4666526914, 0.4213204086, -0.4127517939, -0.7668270469, -0.8369839191, 1.0337042809, + 1.532060504, 0.9207615256, -0.477902472, 1.1084336042, -0.608812809, 2.3399221897, -0.8646865487, 0.243883118, + -0.5149421692, -0.530393362, -0.5218394399, -1.6868261099, -0.0578323007, 0.0224060658, -2.2675683498, -0.058044184, + 0.7456520796, -1.2059559822, -1.229221344, -0.2225447744, -1.3295269012, 0.0634491891, -1.059006691, -0.3777595162, + 1.3155578375, 1.4310772419, -0.5424057841, 0.144311294, -2.4531741142, -0.8215950131, -0.1773539037, 0.8877364993, + 0.1353154629, -0.6411932111, -0.5869292021, -1.4347361326, 0.0225070901, 1.1605197191, 0.6720536351, -1.4405599833, + -0.5473454595, 0.7145345211, -1.1814160347, 1.8402242661, 0.3987374604, 1.1327170134, -0.0116247721, 0.3855871856, + 2.2576406002, 0.3361343741, -0.6971358061, 0.0903513953, 1.9358855486, -0.0837212652, 0.7940992713, 0.6294739246, + -0.0230218563, -0.4086762071, -0.7781276107, -1.5784299374, 1.9371912479, -2.1188192368, 0.3531058133, 1.122048378, + -0.52646631, -0.1083615795, -0.0701917931, 0.1257195175, -0.3426410854, 1.4279152155, 0.8725541234, 0.2656742334, + -1.4155806303, -0.5311722755, 0.5770264864, -1.9181660414, 0.2317260057, 0.6019353867, 0.9077202678, -0.4718322754, + -0.5740461946, -0.1232953146, 0.9156028628, 0.4621352255, 0.4633850753, -0.717667222, -0.982486248, -0.1898862273, + -0.2449781001, -1.5985085964, 0.9512001276, 0.8413665891, 0.0192009527, -1.0423125029, -0.9620074034, -1.1568783522, + 0.0290435944, 1.140439868, -2.0211308002, 1.641094923, 1.1472212076, -1.1088819504, 0.851914525, -0.5757724047, + 0.0184833016, 0.5957829952, 0.5147176981, -0.7896971703, -0.9568346143, 0.360825032, -2.3002521992, 0.9077754617, + -0.6996142268, -1.3030370474, -0.4180361331, -0.2474314123, -0.0635405704, -0.4888866842, 1.1069529057, 0.4685696661, + 0.1609025151, -2.3913598061, 1.0130462646, -0.2157368809, -1.0683450699, -1.5078005791, -0.5091286302, -0.1590702087, + 0.3359768391, 0.590328455, -0.0485109314, -1.3737658262, 0.5323999524, 0.1814595312, -0.9770289063, -0.0009856647, + -0.5759761333, -0.8987975717, 0.5400237441, 0.9631063938, 0.7029232979, 0.1237453818, 0.6921179295, -0.9819133878, + -1.1649929285, 1.916878581, 0.0260932688, 0.5961437225, -1.0539348125, -0.1854109466, -0.4541092813, -0.8012022376, + -0.8627537489, -0.3639629781, -1.5960626602, 1.1273057461, 2.2912368774, -1.5819373131, 0.0768916383, -0.754157424, + 0.9644643068, 0.4963940382, -0.3556044698, -0.1880870759, 0.2791007459, 0.9201265574, -1.6708345413, 0.0320946388, + -1.5955154896, 1.6061308384, 0.0217349976, 0.3895410895, 1.7398505211, -0.1265877634, 0.4094446003, -0.6966269612, + -0.6312574744, 0.4016741514, 0.8904861808, 0.6256996393, -0.4016552866, 0.4941623807, 0.4165548086, -0.1249488592, + 0.784692049, -0.4188575745, -0.1406167001, 0.5847015977, -0.3898477852, -0.9432166815, 0.0343675576, 1.8963041306, + 1.1666419506, 1.905774951, 1.6193721294, -0.5440173149, -0.2137131691, 0.7101011276, 0.6619938612, -0.5311143398, + 0.6764826179, -0.9523943663, 1.308683157, -0.323214829, 0.3837288022, 1.1706738472, -0.158335045, 1.3312753439, + 0.2241350561, -1.6838308573, 0.5691562891, -0.45491153, 0.3088451326, -0.104514122, -0.0612401441, -0.7073890567, + -1.0161758661, 0.5968431234, 0.8028610945, -0.2996942997, 0.2950571775, 0.4948324561, 0.4771435261, 0.2741064727, + -0.2335633188, 0.2663442791, -0.0397798195, 0.5287874341, 0.33869645, 0.0797383338, -0.0556877255, -0.8294295669, + 2.1340575218, -1.6558796167, 0.3286934495, 1.661724329, 1.0909644365, -1.7356817722, -0.391674459, 0.6007047892, + 0.0267706569, -0.6286586523, -0.8454390168, -1.234082222, -0.5262479782, 0.2183321267, -0.7545596361, -0.9005653262, + -0.5328521729, -0.8601483703, -0.7806350589, -1.0522665977, 1.813657403, 0.9027171135, -0.726115644, -0.0490528308, + 0.5775359869, 0.5649013519, -0.7593803406, 0.3464302421, 0.6238087416, 0.6746863723, 1.7811609507, 0.0354143009, + -0.7106010914, -1.6929748058, 1.297750473, -1.0984780788, 1.1117619276, 0.1678503603, -0.5709893703, -1.7195818424, + -0.9556397796, -0.9034484625, -0.0908293873, -1.07008183, 1.3671873808, -1.8064297438, 0.7554394603, -0.5026817918, + 1.7806242704, 1.0917088985, 0.8868745565, -0.0075888634, -0.4598862231, -0.7556013465, 0.0549330562, 0.222143054, + 1.37296772, -0.9540419579, -0.3789446354, -0.1505113691, 0.7726684809, 1.7614964247, 1.0252877474, -0.3415622711, + -1.3802000284, 0.0690797642, -1.198510766, -0.5829547644, -0.0029087467, 0.6864536405, -0.7441490889, 0.9273821115, + 1.1335115433, -0.0438062884, -1.3134324551, 0.2154727727, 0.3803556263, -0.3672275543, -1.354621172, -1.5402970314, + 0.0953702331, -0.4527512193, 0.229119882, -0.7780883312, 0.3277203739, -0.0930765718, -1.032815218, -0.8990030289, + 0.9657142162, -1.7825680971, 1.2948658466, 0.8651069999, 0.5233416557, 0.6785563827, 0.1730827838, 0.670938611, + -0.2403714061, -0.3969297111, -0.0562244244, 0.9086267948, -0.0806159154, -1.3319112062, 0.4982792437, 0.0500809923, + 0.6967548132, 1.0448199511, -1.1299753189, -2.7560486794, 0.1868395656, 1.3268688917, 0.5976457596, -1.8544654846, + -0.6114086509, 2.1996905804, -0.0069061555, 0.9068157077, 0.0332768932, 0.5828394294, -0.3923009932, -1.1152610779, + -1.0476948023, -0.0980769023, -1.9471046925, 0.360255301, 0.6499018669, -0.3639253378, -0.6350816488, 0.126827389, + 0.4119163752, -1.2266123295, 1.4781122208, 0.3314739168, -1.3378620148, 0.2472490221, -0.8766486049, 0.0906429887, + -0.6079481244, -0.642796576, -0.8671147227, 0.8152963519, -0.0899893939, -0.0517604873, 0.2418456525, 0.3122246563, + -0.7654765248, 1.319752574, -0.1157104, 1.7435361147, -0.6417414546, 0.6864396334, -0.8152928948, -1.3649516106, + -1.5759655237, -0.1911571473, 0.9851586223, -0.1836736351, -0.1282128096, 1.4109607935, -0.3864745796, -1.0339030027, + -1.3751579523, -0.515873611, -1.0271582603, 1.2922033072, -0.2954572439, 0.486928612, -0.2285408676, -0.0162027627, + -1.9017342329, 1.6025589705, -0.4845978022, -1.2267167568, -1.0501669645, -0.6654804945, -0.955924809, -0.6065716743, + 0.0243174918, 0.749494195, -1.8077092171, -0.1077916324, 0.8796631098, 0.0062837857, 0.5151043534, -0.6206137538, + 0.1735114008, -0.9676117897, -1.3759051561, 0.0525254011, -0.5183722973, -0.106277585, -0.8050181866, 1.275572896, + 0.0143800322, 1.2767688036, 0.9166401029, -0.3082312644, 1.8080588579, -0.6768823862, 0.3165327907, 0.8092871904, + -0.4501982927, 1.8188048601, -0.9475402236, -0.0415148437, -0.8145132661, 0.2790819407, -1.1835186481, 0.7343748808, + -0.5032110214, 1.4122532606, 0.2738788724, 0.8091881275, -0.0099356575, -0.6308447719, 1.1316365004, -0.309695214, + 0.2567524314, -0.33510077, 0.8001866937, 1.6676236391, -0.884647429, -0.2603313923, 0.1370266527, 0.0493109673, + 0.973307848, -0.3513320982, -0.8878127337, -0.7262001634, 0.2246757895, 3.0239856243, 0.2840051949, -0.7080864906, + 0.475911051, -0.0502727516, -1.0398198366, 0.47208184, 0.3196711242, 1.2657147646, -1.112729907, 1.2408133745, + -0.3051033914, -0.1297694147, 0.6046590209, -0.4969549775, -0.7131097913, -0.9040707946, 0.6418151259, -1.321721673, + 0.0984766409, -0.9235069156, 1.1407945156, 0.2827794254, 0.2023810148, -1.7084463835, -0.1919159442, -1.6301255226, + -0.4870570004, -0.0667773858, 0.4956967235, 1.3667733669, 1.2660340071, -0.0160720777, -1.4300978184, 1.5479718447, + -0.5026729703, 1.6225996017, -0.462567687, -0.9789949059, -0.6550973058, 0.489295274, -0.091896072, 0.4369480312, + -2.7726590633, -0.3816050291, 1.4429813623, 0.797888577, 1.0307193995, -0.2216360867, -0.058747936, -0.1162854955, + -0.3884234428, 0.0990402028, 0.2731604576, 0.1190148816, 0.0518279746, -0.1054238603, 0.4520575404, -2.0491440296, + -0.3809584081, 0.300508678, 0.3459797204, 0.3234552145, -0.1599316448, -1.6980955601, 1.7123942375, 1.4055458307, + -0.8293477893, 0.1827742159, 1.4559041262, 0.0637789965, 0.0475166366, 0.6155928373, -0.9956529737, -1.4131263494, + -0.1182635501, 0.8190299273, 0.5125033259, 0.0770660043, -0.787178278, 0.4206069112, -0.0446137898, -1.1966786385, + -0.2150852829, -0.2339724153, -0.7401009202, 0.55665797, 0.6771113873, 1.4938442707, 1.3028098345, -1.32302773, + 1.6066470146, -1.3189405203, -1.7869796753, -0.8453440666, 0.1779462099, -1.0992565155, 0.8223231435, -0.3773572743, + -1.4823824167, 1.827401638, -0.9582762718, 0.8690104485, -0.1457026154, 0.4907839894, -0.4807015657, -0.1869495213, + -0.9083141088, -1.5402960777, 0.0317795537, 0.0290756747, 0.2935406268, -0.0085515557, 0.8803539872, 0.3078594208, + 1.2030415535, -0.8128335476, 1.6358748674, 1.1200956106, 0.4681635797, -0.2939386666, 0.9326472878, -0.6292216778, + -0.7046082616, 0.2003094703, -0.878418982, 0.2474409193, 0.5440397263, 0.1008563042, 0.5313048363, -1.4959849119, + 0.2413581014, -1.0873416662, -0.7164362073, 1.28110075, -0.7253606319, -0.319724679, -0.9055584073, 1.0824757814, + -1.0967745781, 1.4039075375, -0.8226977587, -1.5650757551, -0.1779900938, 0.3357891142, 1.6376110315, 0.2842205167, + 0.0611847453, 1.0054154396, 1.5567678213, -0.4624824226, 1.7156288624, -1.6495491266, -0.9886603355, -0.504073441, + 2.1461417675, 0.4368059337, 0.2772457898, -1.4140040874, 0.0257757753, 0.3154803514, -0.2752482891, 1.2735975981, + 0.9660745859, 0.3129498661, -0.9183510542, -0.0528000295, -1.4535831213, -0.4218615294, 0.2285152674, 0.4834912121, + -1.0394859314, 1.5353862047, -0.6263337731, -0.3788434863, -1.7689143419, -0.9368940592, -0.4472614527, 0.7502661347, + 1.1232037544, -0.2082219273, -0.3345964253, 1.1510394812, -1.1813848019, 0.5503615737, 0.5231403112, -0.8894044757, + -1.1481416225, 0.3089981377, -0.0089807743, -0.343549639, -1.4222484827, -0.6001983285, -0.2960148454, -0.6301397681, + -0.251753211, 0.5226249695, 1.6253954172, 0.6440001726, 0.6713175774, -0.9343277812, -0.4876067936, 0.2829792798, + 1.175691247, -0.6696252823, -0.0702424943, -1.6962444782, 0.5822570324, -0.300807327, -0.7424628735, 0.4427735806, + -1.6259888411, -0.2963338494, -0.9052641392, 2.0158989429, -0.0409712046, 0.0850246251, 1.2611733675, -0.5877819061, + 1.5001118183, 0.3374356329, -0.8833405972, -0.8129408956, 1.0231391191, 0.2039081007, 0.5219868422, 2.1710143089, + -1.5364967585, -0.9825080633, -0.457688272, 0.1181099117, -1.3131301403, -1.3747745752, 0.6685074568, -1.159865737, + 0.1115264669, 1.2732436657, 0.9837774634, 1.0079425573, 1.2042628527, 1.475716114, 1.9824581146, -0.083616145, + 0.6380442381, 0.6169739962, -0.6086562872, -0.5009913445, -0.5547283292, 0.9836614132, -0.1071657091, 1.2167388201, + -0.7316679955, -0.1268628389, -0.5843551159, -0.3292862475, 1.3337472677, 1.3200297356, 0.7653281689, 0.2057382762, + 0.2780999839, 1.9284055233, -0.4090837836, 0.1546208113, -0.2178405672, 1.8453789949, -0.0609560572, -0.8356684446, + -2.0992302895, -1.6502887011, 1.819221139, 0.5958074331, 0.6264472008, -0.6886128783, 0.0464336015, 2.2116112709, + -1.5227183104, 0.2625297606, 1.5642783642, -0.5167988539, -0.1535461694, 1.0193160772, -0.4149324, -1.3377883434, + 0.2785515785, -1.4212867022, 0.5633701086, -0.5416283011, -0.5272933245, 0.0087975692, -0.5657374859, -0.5035797358, + 0.5643779635, 1.5762873888, -1.0485948324, -2.0079891682, -1.645534277, 0.7365643382, -0.0382613279, 1.7036528587, + 1.3061082363, -0.6127634645, -0.4571321309, 0.9667922258, -0.2397709042, 0.7455832362, -1.3719718456, 0.1176320612, + -0.9625248313, -0.3331040144, -2.3206830025, -1.1050237417, 0.050568331, -1.6521037817, -1.1555784941, -1.8600842953, + -0.1436365545, -1.3095002174, 0.5672355294, 2.2935447693, 0.2653402388, -0.4710046947, 0.0420597941, 0.6235096455, + -0.3959354758, 0.6133328676, 0.8685811758, 0.3623816073, 0.859598875, -1.2475121021, -0.8317956924, 1.3300708532, + -0.6564030051, -0.319621861, -0.956577301, -0.991134584, -0.762910068, -0.931753397, 0.4946089685, -0.0070229843, + 0.5263068676, 0.109629631, -0.7030386925, 1.334117651, 0.0588235408, -1.3557839394, 1.3701558113, 1.3979157209, + -0.0241335556, -1.5421690941, 1.3926768303, -0.0572788082, 0.0924422741, 0.1306796372, -0.4506987333, 1.0594346523, + 0.2627052665, -0.7358296514, -1.7386627197, -0.8884651661, -1.5768609047, -1.2932181358, -0.3603904545, -0.5076446533, + -1.8667639494, 1.0743008852, 0.7913588881, 1.0181564093, 0.6479498148, -0.0823470876, -0.080659382, -0.4157681167, + 2.2641456127, 0.4007044137, -0.3426760733, 0.3771518767, 0.506162703, 1.5559914112, -0.4237650633, -1.1088336706, + 0.7923083305, 0.6938353777, -1.3250257969, 1.55359447, 0.0049045268, 1.1246401072, 0.0097699733, 1.5038679838, + 0.527956605, 0.612817049, 0.3623874485, -0.0392698757, 0.3612433374, 0.6001952887, -0.7416902184, -0.3430719972, + 0.16131787, -0.6219967604, 0.243240267, 1.3867510557, 1.4010163546, -0.6260728836, -0.278509289, -0.8145068884, + -2.1860978603, 0.4015526474, -0.5687218904, 0.0735837519, 2.3719646931, -1.2226122618, -1.7341774702, 0.5211261511, + -0.7689599395, -0.4643093646, -0.188065052, 1.8296451569, 0.1179625243, -1.2873387337, 0.245296225, 0.7529872656, + -0.465667069, -0.7779188156, -0.9317938089, 0.2511917353, -0.8010789752, 0.3875940442, -0.285476625, 0.2135651559, + 0.9496786594, 0.4434437156, -0.2921417952, -0.2893070579, 1.8729990721, -1.3912776709, 0.8823206425, -0.7693408728, + 0.8297691941, 0.6176412106, -1.6273237467, 1.3451734781, 0.7532227635, -0.91268152, 1.1919921637, -0.1777725518, + -1.3362666368, -1.0282952785, 0.7495453358, 0.7746673226, 0.5302920341, -1.1779735088, 0.4359086156, 0.937051177, + 0.6625077128, -0.2525390983, -0.1961964667, 0.6796283722, 0.1560912132, 2.0079288483, -1.3467699289, -0.9276216626, + -0.0741150156, -1.6958822012, -0.2605181336, -1.2530063391, 0.2627429664, 0.7165470719, -1.8141559362, -0.9000178576, + 0.7370605469, 1.4289104939, -0.6930576563, 1.7424666882, 1.6449006796, 0.538295567, -0.751021564, -0.2363715321, + 1.0369923115, 0.9657538533, -0.743178606, -0.8046639562, 1.4332410097, 0.1665688902, -0.6746644378, -0.3744138181, + -0.2142071873, 0.3782551587, -0.0284325425, -0.5066626072, 2.2650198936, 1.4231873751, -0.0743084699, 0.4235864282, + 1.5384422541, 1.3585460186, -0.0352351889, -0.2189443856, -0.8031013012, 2.030354023, 0.5452772379, 0.2255565971, + 0.0925863236, -0.4921898842, 0.2845351994, 0.2062941492, 0.3464781344, -0.0111541692, -1.7251620293, -0.7196274996, + 1.0001733303, 0.1533291489, -0.7373467088, -0.4225189388, 0.1528119892, -1.0180543661, -0.2779996693, -1.5780826807, + -0.4613038599, 0.5342951417, -0.155879721, 0.0374767967, -0.3804990351, -0.4957786202, -0.2577657402, 0.5751443505, + -1.0979690552, 0.0594886243, -1.0828264952, -0.1919242889, -0.3676927984, 0.5205117464, 0.1584236622, 0.1191426143, + -0.818456769, 2.6164002419, 1.8043608665, -1.4470647573, -0.7504413128, -0.0128210383, 1.7690523863, -1.0356879234, + -0.8855569959, -0.8161084652, 0.3014318943, 0.0012616556, -0.5786834955, -0.5376681089, 1.7274968624, 0.7023185492, + 0.0531656817, 0.0197559502, 0.0192194246, -0.4238943756, 1.0916885138, 0.3940524459, 0.6978895664, -0.5300963521, + -0.1750378609, -0.7282319665, 0.3309630752, -0.7242958546, 0.8023917079, 1.2333136797, 0.0600263327, 1.8488427401, + -0.7148504257, 0.4385460615, 0.9688469768, 0.0299088582, -0.9750109315, -1.0483665466, 0.0277658887, 0.2368310541, + -1.2071895599, 1.2570800781, 2.0445125103, 1.691845417, -0.6865190268, 0.2112120986, 1.5974457264, -1.1287384033, + -1.5620183945, -0.9195592403, -1.1469166279, -0.2893614471, 0.6627973914, 1.0217088461, -0.3918666542, 2.0864372253, + -1.0320661068, 0.3124392033, 1.3697936535, -0.3738217652, -0.1886551231, -1.0122405291, 0.8189871907, -0.3247868717, + 0.3251466453, -0.2431050241, -0.1908031404, 0.0159445219, -1.1716156006, 0.4313590527, -0.4181154966, -0.5454003215, + 0.3107697368, -0.4312063754, 1.6988054514, 0.3427794576, 0.5752515793, 0.3136224449, 0.0746937171, -0.2343776822, + 1.364444375, 1.7880711555, -0.8330552578, -0.6701244116, 0.0977286845, 0.6908764243, -1.6960651875, 2.1555716991, + -1.0845538378, -1.0772690773, 0.923838377, 0.1551842541, -1.7129218578, 1.0820883512, -0.6496840119, -2.10785532, + -0.8854192495, -0.0315521695, 0.1816882342, -1.6160395145, -2.0274572372, -2.2314357758, 0.3817986846, 1.3415185213, + -0.7032774687, -0.6273907423, -0.577213347, 0.8161108494, -0.353731215, 0.8900743127, 0.7412501574, -0.1986007243, + -0.0569934621, -2.0071425438, 0.8271296024, -0.2330507785, 0.300796926, -0.4647093117, 0.4949223399, -0.436894238, + -0.0580027997, -0.2060611546, 0.5465889573, -0.7176531553, 0.2781758308, -0.0540548712, -0.8538475633, 0.775267303, + -1.1576044559, -1.6881654263, 0.2807030082, -0.826253593, -0.0240261238, -0.9551573396, -0.2277644128, -0.280542165, + -0.2276842594, 0.8241704702, 1.1559234858, -0.7621541619, 0.1560282558, -1.3470283747, 2.002238512, 0.4317237735, + 1.2540224791, -0.1634758413, 0.8219774365, 1.1389209032, 1.5196316242, -0.1628244519, -1.0992746353, -0.9544483423, + -1.6510956287, -0.6569509506, 1.050057888, 0.6824148297, 1.5513504744, 0.4548636675, 2.7451868057, 1.0425418615, + 0.1934823841, 1.9569149017, -2.2074351311, 0.907561779, 2.0576922894, 0.8540446162, -0.9392482042, 0.022552602, + -1.3599926233, 0.0982640311, -0.4961391985, -2.2542142868, 0.7189049721, 0.5635581613, 0.7037670016, 0.3800044656, + 1.0090733767, 0.7960253954, 1.5524606705, -1.057831049, 0.0954674557, 0.6344092488, 0.2032889277, -0.2713959813, + 0.8102875352, -1.6120643616, -1.3914624453, 1.3278867006, 0.7482947111, 0.8191539645, -0.2149544358, 0.5363849998, + -0.9918892384, 0.8326933384, -0.4563343227, 0.9957206845, -0.391164273, -0.5761083364, -1.6257008314, 0.3507175446, + -0.6471960545, -0.6633731127, -1.1012862921, -0.1357158273, -0.4140460193, 1.1256126165, -0.2547148466, 1.1853294373, + -0.6736295223, -1.2852391005, -0.6020596027, 1.0396854877, -1.1734688282, 1.0483592749, -0.1930020899, 1.4001460075, + 0.6863822937, 0.1874726713, 0.1960242987, 0.3801824749, 1.2780096531, 0.0715012625, -0.572692275, -1.1324484348, + 0.3092543483, -0.1041374058, -0.7648612261, -0.6558532715, -1.1425851583, 0.3871780038, 0.9160779119, -0.252861172, + 0.3229587674, -1.3621455431, 1.0407729149, -1.5615122318, -1.7674455643, -0.1657711864, 0.3561912477, -1.053586483, + -1.3808097839, 0.0066822111, 1.7632035017, -0.5058322549, 0.4460215271, 1.8662033081, -1.425380826, -0.0295527857, + 1.3246070147, -0.482405901, -1.314474225, 1.6353757381, -0.7058399916, 0.6552345157, -2.3853127956, 2.0654399395, + -0.8080892563, -0.7019706368, 0.4695746005, -0.5398542285, 1.9267045259, -1.6482932568, -0.7667036057, -0.0920951143, + -0.3394153118, 0.4104304612, 0.0820508972, -1.052947402, -0.1035258546, -1.2655054331, -0.817312181, -1.5338441133, + 0.7748808265, -1.3071223497, 0.7862274051, 1.2642416954, -1.6465983391, 0.715624094, 0.0004608648, 1.3903490305, + 0.7563246489, 0.7296988368, 3.1193788052, -1.5182796717, -0.4620943666, 0.6188848615, -0.6592494845, 0.1667702049, + 0.1148974299, -0.4236586988, -0.6178045869, 0.5739185214, -0.7387426496, -1.9529211521, 1.4813373089, 0.9259881973, + -0.32751894, -0.5661215186, 1.0159183741, 0.3718490899, 1.7064806223, 1.063295126, 0.2158806324, -0.0558133088, + 0.9810810089, 1.078020215, 1.5175112486, -1.0642248392, 0.8798881769, 1.0489073992, 0.7985528708, -0.2425360382, + -0.5692839622, -0.4421700239, 1.1829074621, 0.1835972518, 0.4506121576, 0.9762408137, 1.1348419189, 0.5359632969, + -1.2192471027, -2.3011717796, -0.2138852626, -0.4985000491, -0.105958879, -0.0988596678, 1.0034368038, -0.5149103403, + -1.8779270649, -0.6865703464, 0.1736295819, 0.8265163302, -0.5225960612, -1.3647763729, -1.0260533094, 0.201070413, + 0.6330992579, -0.840461731, 0.3592998385, 0.3706113994, 0.5354285836, 1.0670536757, -0.1831074059, -1.4682694674, + 0.0098087247, 1.5302503109, 0.1058414206, -0.1238831207, 0.4766884148, -0.4761192799, 1.2386989594, 0.8832945824, + -0.0387233086, 1.376042366, 1.6366331577, -1.9266943932, 0.2121179402, -1.6006190777, 0.1265319735, -0.9488639832, + 0.327299118, 1.2126785517, 0.6757702231, -0.9969081283, -0.8930254579, -0.6828251481, 2.1810488701, 0.1021359116, + -1.7115709782, 0.7546977401, 1.587223649, 0.2561224401, -0.6409754753, -1.3000752926, -1.5575027466, -0.3797564209, + -0.2285472006, 1.1859147549, 0.0516077168, 0.9234830737, -0.8794897795, -0.2575468421, -1.937761426, -1.5830955505, + -1.5876456499, 1.1509450674, -0.4737126529, -1.1898517609, 1.3928337097, 1.6262747049, -0.4686792493, 1.0509574413, + 1.5402649641, -0.7110273242, 0.7389134169, -0.4548214078, -0.8832143545, -0.7396560311, -0.8138209581, 0.4599758983, + 0.0499489568, 1.7926896811, 1.0037494898, -0.0817498639, -0.9807576537, 0.1917232126, -0.7828310132, -1.9145452976, + 0.4286828935, 0.9644827247, 0.096113354, -0.380651772, -0.588075161, 0.0334974229, 1.4758988619, 0.0888777971, + -0.6958780289, 0.1805043221, -1.7607322931, 0.2534747124, 0.0275088325, 2.2588088512, 0.7110636234, -0.1102534533, + -0.0299374927, -0.5157200098, -0.4786728323, -0.7900257111, 0.4293768108, 0.329057008, 0.0805050284, 0.6053853631, + -1.1858336926, 0.1329994649, -0.8362782598, -0.4463221431, 0.2802517414, 1.5189036131, -0.9790352583, -1.0094639063, + 0.5211237669, -1.6937114, -0.1594283283, 0.6029412746, -0.0587336123, 0.0071533583, 0.0523125641, -0.2256063074, + 0.1295899749, 0.1687475741, 0.6759440899, -1.6508245468, -0.6614670157, 1.0911030769, -0.4605453908, 0.4364682734, + 1.3217781782, 1.1893281937, 0.1233901903, -0.9958592653, -0.3711001277, 0.537979126, -0.0070412341, -0.3989662826, + -1.0785380602, 0.1701700389, -0.3741233051, -1.2407640219, 0.4376882315, -1.1232664585, 0.472854346, 1.7027870417, + 0.3569022715, 1.6514447927, 0.0602583177, 0.31239748, 0.1193226576, -0.5213288069, -1.4381340742, 1.4283020496, + 0.5926224589, 0.1629691124, 0.5686670542, -1.0246697664, -1.1791366339, -0.9171492457, -1.4742364883, 0.7465749383, + 0.4492428005, 0.9631430507, 1.0591726303, 0.1239316314, -0.3596034646, -1.090734005, -0.6030093431, -1.1057633162, + -0.8140255809, -2.180883646, 0.854796946, -1.1567357779, 1.3341215849, 1.3263473511, -0.6043748856, -0.6644125581, + 0.830388248, -0.7894672751, -0.5509001613, -1.1912413836, -0.4110831618, 0.0052479375, -0.5508015752, 1.2821806669, + 0.893099308, 2.6927654743, -0.0384279191, -3.2195563316, -1.0180802345, -0.8228209019, 1.4848512411, 0.1804568619, + -0.0416801386, -0.4823452234, -0.3673158586, -1.7843573093, -0.6924807429, 0.5369516015, -0.6816094518, -0.7692908645, + -0.4790070057, -0.4438000023, 0.0430159196, -0.1231807619, -2.3414075375, 0.4058639705, -1.1069461107, 0.9379891157, + 0.5567139387, 1.6205422878, -0.0333523005, 0.4900620282, -1.5986202955, 0.5159187317, -0.822039187, 0.5268859863, + -0.1108082831, 0.9905723333, 0.6257894039, 1.155110836, 0.2970907986, -0.0550662689, -0.341768533, 0.4716485739, + -1.9665927887, 0.6737215519, -0.30180493, 0.1630557626, 0.437741369, 1.665043354, -1.2340313196, 1.0803861618, + -0.9714391828, 1.0315043926, 2.7991528511, -0.902318418, 0.3342669308, 0.8662059903, 0.4187904596, 1.6631202698, + 0.9461517334, 0.0383105762, 0.3874709606, -0.9331662059, -1.5427381992, -1.2080690861, -0.0268997028, -0.3367968798, + 0.8820804358, 0.8696154952, -0.9525085092, -0.139736712, -1.0950832367, 0.9954438806, 0.1454400718, -0.1136238873, + 2.0428493023, 1.1829013824, 1.1000951529, -1.106643796, 0.1360276341, 0.7086342573, -1.2057681084, 0.1230445802, + -0.0300690066, -1.3471719027, -1.1712793112, 0.4815954268, -0.0332318284, 0.018770447, 0.8783824444, -0.2106922418, + 2.4618752003, 1.7784832716, 0.2102992982, -0.280461669, 1.872779727, -1.032283783, -0.6775320172, 0.5041838288, + -1.9068819284, -0.4035941362, -0.4970909655, 0.4764173329, 0.7262157202, -1.3696603775, -0.2180223465, 0.9146516323, + -0.6380504966, -0.6836457253, -0.9392985106, 2.5385532379, 0.7848135829, -0.4739396274, -0.1609451324, -0.347320199, + 0.454739958, 0.0022027995, 0.3719330728, -0.2290373445, -0.837828815, -0.5939671993, -0.4501929879, -0.9564500451, + -0.7512276769, 0.3331740499, 1.706974268, -1.8661465645, 1.6704733372, -0.7440801859, -0.5513499975, -1.366415143, + 0.4946258068, 0.6614918113, 1.0545921326, 0.7613997459, -0.149404034, 0.1473492235, 1.0284640789, 0.1794055253, + 1.303078413, -1.0664352179, 0.8017191291, 1.0707521439, 0.4280396998, 0.7229521275, 0.6674688458, -1.4753994942, + -0.1161597595, -1.5815646648, -1.1041642427, 0.2921075225, -0.6162883043, -1.0617330074, 0.0474488698, -0.235459134, + -0.3827132881, 0.0709788352, 0.9242456555, -0.7282121181, 0.5422099233, -0.7606021762, -0.6083860993, -0.0204535741, + 2.1217327118, -1.1327162981, 0.5107544661, 0.0726600289, -0.052495297, -0.161055401, 0.5236122012, 0.4384548962, + -0.2347787917, -1.5538160801, -0.238657549, -0.0072724433, 0.5456941724, -0.1086401194, 0.7346530557, -0.5908902287, + -0.1918531358, -1.8580100536, -0.503783524, 2.0335335732, -0.957716465, 0.065110743, 0.906078279, -0.5345256925, + 0.1751286089, 0.4575206637, 0.3239696324, 0.0477281995, 0.8175007701, 0.9586806893, 0.2785039842, 0.5604625344, + 1.0212132931, 0.496663332, -0.0258158334, 0.9687435031, -1.353608489, 0.8649412394, -0.8730837107, -0.8804031014, + -1.6783584356, -0.5945875645, 1.2743442059, -0.6184026599, 0.1897069663, 0.0141431382, 0.2350640744, -0.7193506956, + 0.1511185616, -1.5639774799, -1.2819161415, 0.0610125959, -1.1097881794, -0.8521714807, 0.5019956231, 0.0409483574, + 0.1502437443, -0.7988834977, -1.8650946617, 0.5831124187, -0.7960220575, 0.2591686845, -0.0523419008, 0.6130117774, + -0.4703146815, 0.8446735144, 0.9293216467, -0.7193233967, -0.3462554812, 0.0266267434, -0.2921901047, -2.0190968513, + 0.8755489588, -0.1333952248, 2.0068006516, 1.4492278099, 0.1540557742, 1.7440308332, -1.0899720192, -0.3867556453, + 0.1545641422, -0.725471437, 0.731333971, 2.5498569012, -2.4311244488, 2.2926156521, 1.3991469145, 1.1989866495, + 1.3550738096, -0.9609283209, 0.3282889426, 0.8142353892, 1.597035408, -0.2387523353, 0.0792709738, -0.548579514, + 0.4264426529, 0.2009727061, 0.3822948635, -0.3160178065, 0.9924373031, -1.0522011518, 0.6819784641, 0.1449483186, + 0.734559238, -0.4123094082, -0.8291899562, -0.1473677456, -1.9918057919, 1.2308152914, -0.4426414371, -0.3787471354, + -3.0473160744, -1.6859333515, -1.3871006966, -0.0958412439, 2.0981168747, 0.5395963788, 0.5177062154, -0.646027863, + 2.3688600063, -0.7596668005, 0.8309730291, -1.3052463531, -1.1465224028, -0.2534221113, -0.0777573884, 1.5662372112, + -0.8439161181, 0.542381227, -0.4233368933, -0.0301173329, -0.1885342002, -0.7636304498, 0.6386103034, -0.3293936551, + -0.5986554623, 1.650728941, 0.6110025048, -1.1714577675, 0.2430572808, 1.4613201618, 1.2600826025, -0.5669208765, + -2.471095562, 0.7282733917, 0.0715143606, 2.3573234081, 0.2791848481, 0.3507069945, -1.4286094904, -1.3957622051, + -0.6828049421, -2.1207742691, -0.5035426021, -0.0339629166, 0.7257949114, 0.6201557517, 1.2286385298, 0.9077768326, + -0.3393974602, -0.8418522477, 1.1805078983, 0.0826563761, 1.4109766483, -0.1218153611, -1.1622179747, 0.6720657349, + 0.8871431947, -0.6016659737, -0.2201759368, 0.5747567415, -1.4447933435, 0.4896268249, 0.722895205, -2.449344635, + -0.7032957673, -1.5452859402, -1.4874507189, 1.7770699263, -0.5654845834, 0.9598588943, -0.2666018903, -0.1979894638, + -1.8093239069, 0.5844339132, 0.0779933855, -0.7883568406, 2.2556648254, 0.2092601806, -0.0397630557, 1.2062901258, + 1.1393060684, -0.5246899128, -0.6015848517, -0.101480253, 1.8655210733, -1.2383139133, 0.0829883963, 0.3803620636, + -0.4085579813, 3.0920526981, -0.8149982691, 0.2523723245, -0.312674433, 0.2925846577, 1.2427134514, -0.3900679052, + -2.2280981541, -2.0701429844, -0.5498985648, -0.3402158022, -2.2202494144, 1.0159556866, 0.8057820797, 1.4112379551, + 0.4200439751, -1.351703763, -0.4663037062, 0.8230061531, 1.4041137695, 0.0515968874, -0.3207317591, -0.9438809156, + 1.0704278946, 0.8321710229, -0.0838056281, 0.1407217234, -0.4895201027, -0.1014306247, 1.3761303425, 1.7014065981, + -0.2475039661, 1.0797243118, 0.2581546605, -0.0555630252, -0.7183734179, -0.4093923867, -0.4314723313, 1.6992679834, + -0.5810607672, -0.4299448729, -0.175719589, 0.4817943871, 0.8706088662, 1.1988463402, -2.6215486526, -2.0343215466, + 0.4191960394, 1.6816884279, 0.2876927257, 0.9413163066, 0.7395244837, 0.4954246581, -1.6228507757, -0.6659519076, + 0.6042791605, -0.3217880428, 0.1207242757, -0.2647857964, 0.2765117884, -0.1759828329, 1.1069335938, 0.4527967274, + 1.9177540541, -1.4181673527, -0.551715076, 1.4401162863, 1.2062914371, 0.1064064354, 1.1001257896, 0.5693667531, + -0.0823822916, -0.8558875322, -0.3975574374, 0.8107486963, -0.7338398695, -1.6810228825, 0.2814816236, 2.0815069675, + -0.8396160007, 0.7340915203, -0.1046710759, 2.3806743622, 1.1243662834, -0.7335973978, 1.3209965229, -0.0835166797, + -0.4221691787, -0.2683244646, -0.204737708, -0.8506658077, 0.3369838893, -1.3512299061, 0.5600090027, 0.4778011739, + -0.9195017815, 1.3022620678, 0.0175112654, 0.5426177382, 0.1755894125, 1.029921174, 0.7771252394, -1.3532475233, + -0.3722300828, -0.1029285714, 0.7554801106, 0.5151497126, 0.3328151405, 0.230454132, 0.1953039616, -0.5153769851, + 0.4043092728, 0.1988413036, -1.2689567804, 0.4159680605, 0.3145648837, 1.0199477673, -1.7042839527, 0.8625801802, + -2.2885460854, 0.4905623198, -0.5468719602, -1.4397684336, -0.2191286832, -0.3316198587, -0.0544967875, 2.1939680576, + -1.3659399748, -0.3305815756, -0.771304667, 0.9388977885, -0.7135739326, 0.18814753, 0.768255353, -1.1076250076, + 2.2674283981, -1.1733065844, -0.0992131382, -0.006583313, -0.7474772334, -2.5292699337, 1.3511906862, -1.0686225891, + 2.1275341511, -0.7644865513, 0.7966610789, -0.0352354646, 1.6254175901, -0.4221188426, 1.3619796038, 0.6780332923, + 0.3214618266, 1.1740883589, 0.0146083022, -0.9775192738, -0.8737570047, -0.3637194037, -2.3226566315, 1.026219368, + 0.3523386419, -0.8140775561, -1.0497467518, 0.1893426478, -1.9934339523, -0.4920479059, 0.0709401369, -0.2049642354, + 1.6265887022, 1.4623658657, -0.33805269, 0.6974494457, -0.6214071512, 0.6323260069, -0.1815361679, -0.2832997441, + 0.4412190616, 1.0376160145, -0.0181217846, 0.2928813994, -1.3679971695, 0.6803232431, 1.3326506615, 0.5246801376, + -0.4922191799, -1.0667096376, 0.5750662684, -1.2777228355, 0.4103414118, 0.0826276764, -0.019427998, 1.1380794048, + -0.7974613309, -0.1227394193, -0.4622454047, -0.9462473392, -1.0382105112, 3.0540573597, 0.3594521284, 0.5559291244, + 0.7019115686, -0.1078845412, -0.867127955, 0.354628861, 0.7513562441, 0.1686596423, -0.2308986932, -0.6836241484, + -0.9934930205, 0.0928095505, -0.4998281896, 1.3151831627, 0.7407268286, 0.5519161224, -1.9649449587, 1.5386253595, + 1.6443663836, 1.4250090122, -0.482216537, -1.0676637888, 0.3187181652, 0.4153170884, -0.8883006573, -0.2742860317, + 0.2505654395, 0.3850674331, 1.8112043142, -0.6003881693, -1.2677028179, -0.0657587349, 0.5034014583, -0.1584416926, + 1.029625535, 0.7896546721, -0.1844998002, -0.8324058652, 0.7251090407, 0.3456537127, -0.1612031162, 0.5519640446, + -1.2285329103, 0.4051709771, 1.738273859, -0.7669152617, 1.3024536371, -0.2334417999, -0.8495087028, 0.0963180736, + -1.4320399761, -0.400981158, -0.0825446695, -1.6872545481, 0.330380708, 1.4178494215, -0.7337759733, 0.9069579244, + -0.908046782, -1.1837409735, -1.2833039761, -0.7491318583, 2.5821473598, -0.5403444767, -0.4830243587, -0.2678615451, + 0.8788146377, -0.0934342444, -0.6283229589, -0.1921992749, -1.9643006325, 0.2488131225, -1.1531807184, 0.3248987794, + -0.2471186668, -0.7058179975, 0.542229116, 1.1079134941, 1.4611216784, 0.8116730452, -0.0140767116, 0.4220570624, + -2.0194842815, -1.1250903606, -0.9013854265, -0.1820059419, 0.3428933024, -1.2460854053, 1.4754422903, 0.9102709889, + -0.7721157074, -0.0860439911, 1.6187556982, 0.5236514211, 0.6717063189, 0.8059553504, -2.1456305981, 1.8775573969, + -0.8045200706, -0.7242151499, -1.2274599075, -0.3879765868, 0.0832767859, -0.9325447679, -0.5355188251, 0.7970010042, + -1.0122157335, -0.2169611752, -0.4314942956, -0.7536115646, 0.9737334847, 0.5086837411, -1.4131776094, 0.042465575, + -0.5832741857, 0.7751629353, 0.6793202758, 0.498190701, 0.6098150611, -1.0555416346, -0.4501825869, 1.2009423971, + -1.1430513859, 1.2606869936, -0.2908736765, -0.3532292247, 0.276009351, 0.0486681461, -0.985267818, -0.5179210901, + 2.9281203747, 1.8839042187, -1.2333828211, -0.5978958011, 1.6062750816, -0.3856277764, 0.335334748, 0.900805831, + -0.4921723604, 0.486066848, 0.149329409, -0.3788942695, 0.3776074946, -0.1087439433, 0.8221364617, -0.0039486336, + 0.0350735076, -0.7033908367, -0.3409045637, 1.2027546167, 0.0638573021, -0.49856022, -0.3220447898, 0.8035058379, + 0.0312587582, -1.0049045086, 0.0859072581, 0.4213287532, 1.384139657, -1.9018831253, 0.2462813258, 0.3927054703, + 0.8714232445, -0.5415591598, 0.9047995806, 1.5702162981, 0.5778482556, -0.3848070502, -1.4516043663, -0.1781129241, + 1.0578336716, 0.1071197763, 0.4987775087, 0.4444977641, 0.1904703826, -0.0500574149, 0.8652390838, -1.3767344952, + 0.6599958539, -0.1546868533, -0.4128006697, 0.4206206501, 0.7529597878, 1.6279267073, 1.6883649826, 0.3809396625, + 1.4642118216, 0.0701802224, 0.9007957578, -1.0695656538, 0.0756013691, -0.2558471262, 0.6178277135, -0.1640721709, + 0.5888280869, -0.0450142436, -1.9780269861, 1.5108190775, 0.020129649, 0.3490985334, -0.8458254933, -2.2395009995, + -0.1078830585, -1.2979288101, 2.2681913376, 1.1489452124, 0.5595183969, 0.6483691335, -0.8494003415, -1.200024724, + -1.7947679758, -0.3354310393, -0.8372511864, 0.4137484133, 0.4951325357, -1.3353157043, -0.4037382603, 0.136049673, + 1.7940540314, 0.514508009, -1.1026799679, 0.3898757398, -1.331176877, 0.6445837617, 3.1182668209, 0.7394161224, + 0.5409551263, 1.4241337776, -0.4103944302, -0.9392827153, -1.0108066797, -0.9068341255, 0.0709434673, 0.9242113829, + -0.2061729133, -0.5818979144, 1.0988814831, -1.0460087061, -1.2680871487, 0.4011656642, 0.7063562274, 0.5195142031, + 0.1841870248, 0.4354915619, -1.1544827223, 0.7519261837, -0.8682871461, 1.2139902115, 1.8845286369, -0.3824562132, + -2.9315984249, 1.0975605249, -0.6656762958, -0.3710460961, -0.4581338763, -0.1719742119, 0.6240089536, 1.4918496609, + -1.3402218819, 0.5351183414, 0.3458021283, 0.4096876383, 0.6907798052, 1.3452779055, -1.4073811769, -0.7307488918, + 0.4452004731, 0.9288562536, -1.3342907429, -0.9971263409, -0.23112607, -1.999778986, -1.1380411386, 0.5919696689, + -1.6074502468, -0.5450325012, 0.1557483375, 0.4483186901, 0.7535129189, 0.3043299913, 0.7550746799, -0.7720427513, + -1.07776618, 1.1778817177, -1.8641024828, 0.534455359, -0.0597600453, -0.5732216239, 0.9112659693, 0.1287456751, + 0.8489707112, 0.4421401024, 0.6027107835, -0.1285692751, -2.4745180607, 0.1951732039, 0.7277007699, -1.473252058, + -0.4286610782, -0.1154345125, -0.0769550353, -1.2591086626, -0.1017499194, -0.0210780762, -1.1737729311, + -1.1453151703, 0.3725708425, 0.8576273322, -0.4034656584, 0.1232902855, 0.4509639442, 0.3320712149, 0.233169347, + -0.6623501778, 1.1165158749, 0.3908354342, -0.275519371, 0.7766165137, 2.2021074295, 0.7839115262, 0.1298831701, + -0.8191106915, -1.3449116945, -0.276956141, 0.0589544252, 1.4789159298, 0.6346148849, -1.5675116777, -1.2349410057, + 0.0871513784, 0.4487423897, -0.2801265121, 0.8739984035, -0.6375115514, 0.2110447139, -0.3336372674, 0.9330590367, + -0.5646930933, 0.5073488355, -0.0384628698, -0.3513286114, -0.8750590682, -0.9063674808, -0.3104023635, 0.4549559355, + 0.023975892, -0.5857896805, 0.0329510607, 0.6853071451, -0.9402374029, -1.0898227692, 1.1488786936, 0.3411648273, + 0.7200110555, 0.1597515345, -0.3885217905, 1.3693848848, -0.3649668992, 1.1565055847, 0.0767926425, -0.2566693127, + 0.4097830355, -0.1426362097, 0.5309285522, -1.0245457888, -0.0216459669, 0.5516811013, 0.132758081, -0.2019371092, + 2.0907456875, -0.6933072209, -2.1148211956, -2.0299284458, 0.3427873254, -0.0116709834, 0.4638992548, 0.6261547208, + 0.572189033, 2.9009780884, -1.1405460835, 0.18778795, -0.1944549531, -0.184412092, -0.5303893089, -0.4590159655, + -0.19417952, -0.1404060721, -0.7878784537, -1.3694969416, -0.0244819149, -2.6898519993, -1.008695364, 1.1471830606, + 0.5464369059, 0.9971829057, -0.0929342508, 0.7358595729, -0.2085779309, -0.9564427137, 0.2623963654, -0.7120863795, + -1.033184886, 0.2814248204, 0.2566384077, 2.1200895309, -0.784763217, -0.9394590259, 2.1373596191, 0.4847322106, + -1.0768883228, 0.025718553, -0.3627569079, 1.1377524137, -2.327234745, -0.7009713054, -0.3798924983, 0.5566964746, + 0.2665447593, 0.2588733137, -0.4382838905, -1.5288709402, 0.745452702, -2.0549416542, -0.7336265445, 0.7902216911, + 1.0842144489, 0.8565483689, -0.5160650611, -0.2388527393, 0.1325882673, 1.2349766493, -0.5192912817, 0.6799807549, + 0.311198175, -0.1828193814, -0.6931616664, 1.0630458593, -0.3297859728, 0.3573651314, 0.1918357015, 1.0749788284, + 0.8603224158, -0.5975485444, -1.3843562603, 0.9666813612, 0.2949757576, -1.0964585543, 0.9764108658, 0.014988984, + 1.0665789843, -0.8470121622, 0.8645345569, 1.3421913385, 0.7372649908, -1.0292098522, -0.7991414666, 2.099455595, + -0.0386573002, -0.120942764, -0.1018707603, -1.8904802799, 0.2138135731, 0.5829991698, 0.1209255829, 0.2682153881, + 0.1597340852, 2.0694198608, -0.8160514235, 0.9405336976, -0.2612581849, -0.7488277555, 0.2938060462, -0.4454466403, + 2.0709934235, 1.0594415665, -2.0218315125, 0.1861803085, -0.3184541464, 1.0500028133, -0.7971460223, -0.4653572142, + -0.1952562183, -0.3340694904, -1.5124847889, 0.8677157164, 0.1723863482, 1.2384344339, -0.1841048002, -1.2000898123, + 0.407207191, 1.3923242092, -0.7195712328, -0.9771297574, 0.7300099134, 0.0627533272, 1.9138554335, -0.0584848188, + 0.8246739507, -0.4379732609, 1.9184089899, -1.5187605619, -0.8122234941, 0.8544716239, -0.3368932903, 0.4989197552, + -0.6576798558, -0.5772010684, 1.0729271173, 0.8953892589, 0.4057393372, 1.2137151957, -0.8393722177, 0.0525206178, + 1.3459855318, 2.1250915527, 0.124267377, -2.0543036461, -0.7189696431, -1.6973289251, -1.5774748325, -0.0314979739, + -0.2412691116, 0.2239166349, -0.5194889903, 1.0742644072, 0.16095227, 1.0746810436, 0.1200929657, -0.2726342082, + 1.4211553335, 0.0857824907, -0.2053765953, 0.3187888861, 0.5143779516, -0.5992152095, -0.6816874743, 2.9358263016, + 2.0151743889, 0.5622567534, -0.0935387388, 0.1492368132, 0.5007673502, 0.5098925233, 1.114995718, 2.1785109043, + 0.6689604521, -0.9561447501, -0.7765575051, -1.2729759216, -2.5599219799, 1.2151373625, 0.5340461135, -0.6273633838, + -1.3690152168, -0.7996125221, -0.2076777518, 0.5959313512, 0.031218186, -2.005168438, 1.3749988079, 0.5573381186, + -1.867675066, -1.1792148352, -0.4203329086, 0.098577179, 0.6573711634, 1.1733105183, 0.3345836997, -1.224630475, + -0.5836922526, 0.4716092944, 0.4792221189, -1.2958402634, 1.8630772829, 0.2784361243, 1.0937455893, -0.2099616975, + 0.4214741886, -0.5144574046, -0.2383110076, 1.2241157293, 1.1667163372, -3.0629582405, 0.2755071521, 0.9796141982, + 1.1982212067, -0.7435212135, 0.088808462, -1.1646779776, -0.8349477053, 0.1836696565, 1.0464693308, 1.4091336727, + 0.351298213, -1.1093584299, -0.0148777813, -0.7249640226, 0.5148887038, -1.1883825064, 0.7954053283, 0.0648263469, + -0.3492616117, 0.6866639853, 0.1444717646, 1.5906834602, 1.1906172037, 1.1974231005, -0.2618243992, -0.7974213362, + -0.7960732579, -0.3851014674, -0.9355871081, -0.6335410476, 0.1873655766, 1.1265091896, -0.0838515311, 0.1801059991, + 1.3423806429, 0.8518787622, -0.6987745166, -1.1183056831, 0.0339035653, 1.2098129988, 1.0811673403, -0.1526868492, + 0.586378634, -0.6288794875, -0.2684370577, -0.1966408342, -1.8438454866, -0.7123699784, -1.7283849716, -0.9004950523, + 0.4246796668, -0.3308639824, -0.0020428838, 1.0246882439, -0.8577266932, 0.6733812094, -0.9730071425, 0.5584130287, + 0.3536276817, 0.5739370584, 0.5155097246, -0.0672519654, 0.1801947504, 0.1836582124, 0.5291321278, 0.508674264, + 0.0655369684, -0.8849287629, 0.6907548904, -0.0488187782, 3.3209657669, -0.0501876213, 0.8470934629, 0.1091856286, + 0.5762174726, 0.104932107, 0.4455679953, -0.875890553, 1.8857425451, 0.7774903774, -0.0076641762, 0.8670355678, + -0.3381590247, -0.855735302, -2.0405881405, -0.2047748268, 0.5438323617, -0.9618906379, 0.7381688356, 0.3258624077, + 1.4617965221, -0.0028879009, -0.2676487267, -0.8923782706, -1.8217835426, -0.0186384395, 1.7530089617, -1.179117918, + -0.4352858365, 0.9670229554, -0.3449574411, -0.3940675259, 0.4946045578, 0.2536029518, -1.0679191351, -1.2482924461, + -0.1159172207, 0.8719373941, -0.331202656, -0.3494094908, 0.6839279532, -0.508485496, 0.7218002677, -0.2618828714, + 0.3507729471, 0.2381303906, 0.7938268185, 0.7570793033, 1.0622991323, 0.617544651, -0.9916316271, 1.6769894361, + -0.3215295076, -1.0892727375, -1.4173982143, -0.5432204604, -0.2167730033, 1.6159602404, -2.2631447315, 0.9030470252, + 0.6519251466, -2.469792366, -0.8317915797, 0.09727671, -1.272531867, 0.6019590497, 0.079588525, -1.1497843266, + -2.4003005028, -0.9797340035, -1.427369833, 0.6937153935, -1.8866250515, -1.213288784, 0.2422034889, 0.9020537734, + -0.6387479305, -1.2040439844, -2.5717265606, -0.982388854, -0.8603173494, -0.1113521829, -1.5185772181, 0.3711701632, + 0.7167190313, -0.2066891938, -0.6412582994, -0.9086228609, 1.2789639235, -0.5552526116, -0.273999989, 0.6681884527, + 0.2850576937, 1.1664259434, -1.3593558073, 0.3325866759, -0.298312366, -0.1339031905, 1.3430116177, -0.1880369335, + 1.969715476, -0.1896455884, 1.6410228014, -1.5998033285, 0.4156921506, 0.5480934978, -2.6319608688, 0.3182291687, + -0.4545027018, -0.0404811949, 0.5020309687, 0.4129009247, -0.9264763594, -0.8234125376, 0.6390948296, -0.001933459, + -0.5494630337, -1.3261779547, -0.7078437209, -1.0352882147, 0.875787735, 0.3657563031, 1.5296053886, 0.6850796938, + 1.3457660675, -1.2615861893, 0.0619928725, 1.7164348364, 1.1516953707, 1.252017498, -0.0763857737, -0.9964673519, + -0.6538204551, -0.7642871737, -2.7673952579, 0.0269780625, -3.5376372337, 0.2615314126, -1.8532675505, -0.3508562446, + 0.324418962, 0.4992468953, 0.2832391262, -0.87661165, 0.3057894111, 1.6057144403, 2.1141822338, -1.0781127214, + -0.9287056923, -0.8534093499, -0.2685569525, 1.3060340881, 0.1535290927, -1.2112205029, -0.4509466588, 1.3873354197, + -2.5044455528, 0.5372287631, -0.698158741, -0.4939994812, -0.2896173, -0.2453738302, 0.3176817298, 1.42382586, + 0.7012366652, 0.222651884, 0.8875376582, -0.2895725965, -0.5405652523, -0.5801152587, -0.6099621058, -0.179445833, + 0.352299273, -0.3782028258, 0.5201066732, 0.7829122543, 0.1191232353, 0.1265148669, -1.2816922665, 0.5576660633, + -1.7459415197, 0.218639791, -0.5908021331, 0.9046570659, -0.6815707088, 0.2523507774, -0.1003115773, -0.6361647248, + -0.2780383527, 0.8642255068, 0.9515980482, 0.982037127, -1.4303667545, -0.098335661, 1.4673168659, 1.1516301632, + 1.9530824423, 1.2597833872, -1.4902018309, 0.3255969882, 0.749614656, -0.0849756375, -1.0007236004, -0.5960429311, + -1.0154364109, 1.251183033, 1.2626070976, -0.5875334144, 1.4028255939, 0.4695758522, -0.02555665, 1.8417292833, + -0.0399172194, 1.1069836617, -1.2826505899, -0.1472184211, 0.9856489897, -0.17298612, -0.3876519799, 0.6959972382, + 0.2856332362, -1.0207430124, -0.9289630055, 0.063274838, 0.4820849895, 1.5037152767, 0.4867504835, 0.0797959343, + -0.1955450326, 0.7896358371, -1.1532626152, -1.120864749, -1.6553353071, 1.8035339117, -0.0838049203, 1.323943615, + -0.4971853793, 0.8107408881, -1.1551069021, -0.1953871846, -0.7771847248, -0.7813466191, 0.5065687299, -0.182082355, + 0.2684529126, 0.9292242527, 0.7593740225, -0.9009737968, 0.4765752554, 0.1643548906, -0.3488487899, -0.3658882976, + -0.2314924598, 0.4069265723, -0.9488435984, 0.7248171568, 1.4139008522, 1.5861266851, -0.1279027164, -0.0553276762, + 0.7255465984, 0.1429184526, 0.1820705831, 0.2178043425, -0.0077814292, 1.4773465395, -1.1627372503, -0.6053957343, + 0.4770019352, -1.0118191242, -1.329588294, 0.7362958193, 0.7915869355, 0.3331216276, 0.5359749794, -3.0860996246, + 0.3936527073, -0.7873288989, 0.1485450566, -1.2330771685, -1.2370146513, -0.5632748008, -0.491430372, 1.0046528578, + -0.7574470639, 1.2790346146, -1.956930995, -0.693257153, 0.3972877562, -0.1010534316, 1.6112462282, -1.3199983835, + -0.5487880111, -0.5936339498, -2.064152956, 0.5989998579, 0.8124501705, 0.3341778815, -0.7117627859, -1.7005486488, + -0.7905029655, -0.7358307242, -0.0822679624, -0.2129524499, -0.0102335811, 0.2852599919, -0.2062803209, -0.5369126797, + 0.9724613428, -0.3041396439, -1.0042915344, 1.0672525167, -0.228943944, 1.3452187777, 0.5357630253, -0.4374930859, + 0.6523374319, 0.0650269166, 1.2034343481, 2.504152298, -2.2119021416, -0.0325773247, -0.2486386299, -1.2621959448, + 0.9550855756, -1.0251768827, 1.357601285, -1.008217454, 0.4790438414, 0.7539923787, -0.2292823493, -2.0603711605, + 1.2167100906, -0.063260518, 0.6282228827, -1.287571907, 1.2758817673, -0.0361953229, -1.1444544792, 0.0995380729, + 2.0643885136, 0.0476284251, 0.3599074483, 1.3913724422, -0.8276139498, 0.4267857373, -0.9940422773, -1.6722874641, + -0.4820932746, 0.9585770369, -0.3583551347, 2.2475891113, 0.679574132, 0.0427838154, -0.0337097496, 0.281222105, + 2.2352130413, 1.5787955523, -0.0525405966, 0.7612043023, -0.2395873815, -1.162989378, 0.9450313449, -1.5587869883, + -1.0885256529, 1.2096309662, -0.6176126003, 0.2794592083, 0.4000840187, -0.2106546909, 2.1949429512, -1.7044574022, + -0.2265886366, 0.5426079631, 1.112590313, -0.5519072413, -1.1224460602, 0.836345017, -1.5743186474, -0.527137816, + 0.6508792639, 0.5543196201, -1.1395976543, 0.150606811, -1.3732875586, -0.5603883266, -0.3320862949, 0.050092835, + 1.4821004868, 1.3670789003, 1.0397155285, 0.9093261957, 0.2789103091, -0.4556762576, 0.9363845587, 0.5859700441, + -0.8330316544, 0.9558687806, -0.2014526874, -0.0478864685, -0.8698826432, 0.2509627938, 0.1928938031, -0.5245307088, + -0.7604442835, -0.9027975798, -0.8322229981, -0.2535308897, 0.2865951061, -0.8358671069, -0.0175675061, -0.4595412612, + 0.2229304463, 0.2540488839, 0.1446684897, -0.5048643947, 1.2162379026, 1.4006818533, -1.8685104847, -2.1495907307, + 0.3018081784, -0.9322087169, -0.6951150894, -0.3476719856, -0.8317773938, 0.5383685827, -1.4129815102, -0.1823303849, + 1.0443432331, 1.1775488853, 0.0203446262, 0.6534597278, 0.1316889226, 0.903783083, -0.8564657569, -0.2451224774, + 0.5288985372, -0.3417075574, -0.4940801263, 1.2461600304, 0.1253131926, -0.1442823708, -0.2593114078, -0.7173941135, + 1.5848474503, 1.3283705711, -0.4759116769, 0.561751008, -0.2803081572, -0.1529893428, 0.7441819906, 1.0778692961, + -1.6746370792, -0.0191578642, -1.6233841181, 1.3962148428, 2.4005887508, -0.7849439979, 1.6532175541, 0.8943389058, + -0.7218570709, 0.0025848437, 0.1503669173, -1.1533824205, -0.6082597375, 0.5895243287, 0.6123408675, 1.0880017281, + -0.8497795463, 0.2664059699, 0.1507609338, -1.1018321514, -0.7293382287, -1.2999854088, -0.5079394579, 1.9566550255, + -0.6045329571, -1.1847981215, 1.3479480743, -0.484253794, 0.4533431828, 0.2714575231, -0.0489397943, -0.0387133919, + -1.2142137289, -0.573877871, 0.4517196119, -0.0616835095, 0.7554846406, -1.2030466795, 0.2224065214, 0.8758687377, + -1.5098052025, -2.57898736, -1.304423213, -0.9159380198, 0.3439801037, 1.0308520794, -0.5655797124, 0.6416946054, + -1.5301198959, -0.2333142459, 1.3705869913, 0.5391677022, 2.1740953922, 0.6560552716, 0.4826991856, -1.5273411274, + 0.6695680618, 0.42467767, -0.1707382351, -1.0786836147, 0.3128767908, 0.5183787942, 0.5231448412, -0.7981930971, + 0.0068109701, -0.9226770401, -0.7949106693, -0.1485601366, 0.5388772488, 1.1333990097, 0.2188962549, -1.0067234039, + -0.3539472222, 0.7378255129, -0.2585050464, -1.1470578909, 1.2719910145, 0.6277831793, -0.632769227, -1.3171602488, + -0.6405596733, -0.4403110743, 0.5331921577, -0.0618506931, 0.1133509055, -0.2367716134, 0.0172743201, -0.9363154769, + 0.0419243276, 1.2715209723, -0.6324470639, 0.4981867671, -1.4744064808, 0.94328475, -1.3852499723, -0.0248926673, + -0.1987091005, 0.9218626022, 0.3695135117, 0.6386186481, 0.9051753283, -0.6882691979, 0.1940152645, 1.011574626, + -0.103915967, 0.0934223235, 0.6569828391, 1.5856434107, 1.378158927, 1.1807434559, -1.2077684402, -0.0713830218, + -0.689206481, 0.7983953357, -0.132079944, 0.9095534086, 1.0258624554, -1.0350824594, -0.1084372476, -0.7068145275, + 1.096694231, 0.2121248394, 1.601193428, -0.1354372799, -1.6426924467, 1.9219787121, 1.9771164656, -1.275485158, + 0.4517096877, 1.3728480339, -0.5387133956, -0.5070499182, 1.010591507, 0.7020894289, -1.4419972897, 0.0110328682, + -0.1098614261, -1.4754793644, 0.3179679811, 0.3669794202, -0.9281835556, 1.2898329496, -0.9199350476, -0.9801771045, + -0.9031108022, -0.3989333808, -0.3263574541, 0.1047135815, -2.055327177, -0.9773147702, -1.4125535488, -2.2337026596, + -0.9101406932, -0.2648207545, 0.5565056205, -0.6932720542, -0.880492866, -1.4365410805, 0.030259287, -0.1010962129, + -0.3346745968, 0.3059233427, -1.306797266, -0.0088376841, -0.3915492594, -0.6771771908, -0.5156219602, 0.1084053442, + -0.7851771712, 2.0248520374, 0.0768793225, 1.6671743393, 1.1379973888, -0.0037817969, -0.1691045761, 0.1110712513, + 0.0237912405, -0.2556541264, -1.9002453089, -0.7983082533, -1.8317855597, -1.2898895741, 0.0141506037, 0.2845778465, + 1.1239186525, 0.439024657, -1.0800429583, 0.9424997568, 0.0881775469, -1.6444958448, -0.899857223, -0.9650136828, + 0.296708107, -1.0165929794, -0.5798018575, 1.380091548, 0.6454607844, -0.0140456948, -0.5817818642, -0.1011662409, + 1.0112067461, -1.8833494186, 1.3017792702, -0.7716539502, 0.5666996241, 0.2956871092, -0.2049203664, 1.9108538628, + -1.3607987165, -0.0717590377, 0.0956634954, -0.5079314113, 0.3618172109, -0.3595963717, -1.4459455013, 0.2162457108, + -0.7750922441, -0.225304842, -0.6305879951, -0.628205657, 0.1342151314, 0.907918334, -0.3357201517, -0.9684320092, + -2.0011854172, 1.0298330784, -1.1672452688, 1.2127306461, -0.56323421, -1.1428827047, 2.3399078846, -0.8843747973, + 0.5320113897, -1.1435959339, -0.8313342929, 1.1637715101, 0.8253864646, -0.9990708232, 0.3957966864, 0.4645176828, + -0.676369071, -0.2837693691, -0.434797287, -0.7891721129, 0.8290168047, -0.3206014335, -0.3041936457, 0.7272228599, + 1.2169837952, 0.7897850275, 1.217559576, 0.9864512682, 0.3498557806, 0.9575622678, 0.176386252, 1.5062904358, + -1.4601914883, 0.8869418502, 0.4095101357, -0.0545322858, -1.0357341766, 0.0918669775, 0.7407202721, 0.4786416292, + 0.6654282212, 0.2292959541, 0.207693249, 0.2183427811, -0.7750036716, -0.8375609517, -0.8351103663, -0.9253761768, + 0.0818053335, 0.2907602191, 1.0790300369, 3.096118927, -0.4322378933, -0.5297884345, -0.718524158, -0.0790990219, + -0.5318148136, 0.3011080623, -2.3876340389, -0.6010844707, -0.6294558644, 0.9789693952, -2.1652061939, -0.9091853499, + -1.5246109962, 1.6593085527, -1.1628981829, 1.6147589684, 2.2718012333, -1.5532001257, -2.0527155399, -0.4091469049, + -1.0820819139, 1.5153158903, -0.4930484593, 0.8512840271, -1.1784952879, 1.0569536686, 0.0160085466, -0.0003073825, + -1.4744670391, -1.289280057, -1.2932577133, 0.6164194345, -1.7043364048, 0.2677577436, 0.6191200018, -0.271576345, + -1.5342735052, -1.0618538857, -1.2137271166, -1.9104957581, -0.5562978387, 2.0095219612, 0.4219472408, 0.2807143331, + 0.2929550111, 0.0925148204, -0.7408627868, -1.278621912, 0.5953165293, 1.1873878241, 0.7985800505, 1.1434313059, + 0.1420213878, 0.3704443574, 2.0830335617, 0.8558987975, -1.08632195, -0.6328001618, -1.0930259228, -0.7155646086, + 0.2989422679, -0.1714941859, -0.2596023083, 1.0251544714, 0.4840430021, 0.5426319242, -0.0317259394, -0.5928928256, + 2.336565733, 0.8119526505, -0.3559478223, 1.2486777306, 0.316121012, 0.3295256793, -0.2986513674, -0.8083889484, + -0.1058205962, -0.2012898922, 0.1898895204, 1.2744652033, -0.5763427615, -1.7786310911, -0.4619722664, -0.0343275331, + -0.0804154128, 0.0896555558, -0.2375993878, -0.6510353088, 0.5634438992, -0.275645107, -1.1919237375, 0.0106554357, + 1.0845719576, -1.4242180586, -0.791567862, -0.4528565705, -0.5867254734, -0.3834092915, 1.3105416298, -1.1719135046, + -1.8663834333, -0.4044742584, -1.0571340322, 2.1624724865, -0.3283438981, -1.6711210012, -0.2128783464, -1.1012598276, + 1.2401621342, 0.1001905724, -1.6413034201, -0.4412343502, -1.6417485476, 0.5818608403, 1.0299129486, 2.2170233727, + -0.7258693576, 0.3411789238, -0.0758841783, -0.1068310887, -1.5048621893, -0.7476377487, -1.0252985954, 1.2971277237, + 0.9907476306, -1.0029420853, -0.870300591, 1.2154511213, 0.1695734859, -0.6100532413, -0.2701125443, -1.8159172535, + 0.0744715631, 1.4320803881, 0.8319642544, -0.3548873365, -0.4736134112, 1.2513190508, 0.7541353106, -0.7968253493, + -1.1330760717, -0.4850624204, 1.3151828051, -1.8339599371, 1.2641755342, 0.6874196529, -0.1858444214, 0.2456031442, + 1.2378497124, 0.3065797091, 0.1393100023, 0.818638742, 0.5621598959, -0.2971632183, -0.9280245304, 0.5608353615, + -0.5151640177, 1.3092679977, -0.1564584374, 0.0101362988, -0.1147716045, -0.3308030069, 0.5426612496, 1.0478041172, + -0.7588689923, 0.9058098793, -0.6638476849, 0.0271008201, -0.599652946, 0.9415428638, 0.3311151862, -0.6850024462, + -1.6973967552, 0.8252288699, 0.5447505116, -0.5340859294, -1.0320228338, -1.9213482141, -0.3236763477, -1.1210227013, + -2.0754590034, 0.9175598621, -0.1582947224, 0.035503827, -1.8584797382, 0.8211516738, 0.5859157443, 0.9854813814, + 1.0377193689, 0.8087520003, 0.0553114042, -1.1089491844, 0.261727035, 0.7748783827, -1.3112766743, -0.2853017449, + -0.8751548529, 0.4537158906, -0.4724691808, 1.911477685, 1.120187521, -0.6998970509, -2.2755661011, 0.6124466658, + -0.4858125746, 0.1044009998, 0.6781061888, 1.0112067461, -1.005384326, 0.5832854509, 1.3902379274, -0.3954279721, + 1.4138845205, -1.1117755175, 0.0675625056, -0.7510002851, 0.1992310286, 0.1564755589, 1.4238003492, 1.1698158979, + -2.0644772053, -0.7029905319, 0.2314308137, 0.2684699595, 0.7005752325, -0.1916425675, 0.1933514178, -0.360077709, + -0.5549749136, -0.6029216051, -0.7787041664, -2.5662279129, -0.7273243666, 0.6202687621, -0.7350562215, 0.213755697, + 1.791179657, 0.5588005781, 0.041910097, -0.6966994405, 1.0583099127, -2.8149473667, -0.2643944621, -2.282741785, + -0.7935805917, -1.1352584362, -0.2278170884, -0.8056265712, 0.7685412169, 0.34966892, -0.3449663222, 0.3916354775, + 0.0579748861, -1.4494156837, -0.1893656999, -1.6724202633, 1.086194396, 0.5076280832, -0.0133326286, -1.2809752226, + 1.3494324684, -1.2507998943, 0.7153228521, 0.2078970075, -0.657359302, 0.7824165821, -0.5148826241, 1.3713448048, + -0.0101848487, -1.4278615713, 0.6900991797, -0.73800385, 1.6913758516, 1.6196644306, 0.9960871935, -0.6944152117, + 1.6037415266, 1.3314589262, 0.2126102298, 0.8190729618, -0.3324639797, -0.4693499804, -1.2738293409, -1.9276175499, + 1.8065828085, 0.6967000365, 0.1457846165, -0.8485788107, -0.0902344882, -0.443741709, -0.8114491701, 0.6733375788, + -1.0148701668, 1.2667295933, -0.2555393577, 1.0527654886, 0.0487716459, -1.0939552784, 1.0991251469, -0.9288706183, + 0.6616157889, -0.106421113, 0.5533397794, 0.4668231606, -1.074652195, 0.5423960686, 1.0720642805, 0.8632643223, + 0.1105926335, -0.4526108205, -1.0977783203, -0.8176969886, -0.2230648398, -1.1865390539, -1.0723834038, -1.044092536, + 0.9188759327, -0.1689279526, 0.3107523918, -0.1185576096, 0.386487335, 0.5850405693, -1.3451581001, 1.1591099501, + -1.721347332, -1.1616033316, -0.363091737, 0.9260309935, 1.9034808874, 0.7039475441, 0.8226540685, -0.2596986592, + 1.2070049047, -0.9120343924, -0.170183152, -2.9533367157, 1.2373387814, 0.7368846536, -1.1026964188, 0.7084195614, + -0.5575756431, 0.608302772, -1.9660063982, 0.0480993725, 1.7596119642, -0.2430192381, 0.5924292803, -2.454252243, + -0.1702857912, -0.8102533817, 0.3578571081, -0.3168414533, -0.7957355976, 0.8105921149, 1.2186963558, 0.256788373, + 0.9143864512, -0.0124621931, 2.1438231468, -0.7441107631, -1.0311625004, -1.0583885908, -0.3230136037, -1.2296295166, + -0.5679237843, -2.8217861652, 1.2539693117, -0.6278217435, 0.2693663836, 0.5483108163, -0.1207809523, -1.0742874146, + -0.6069313288, 1.5203852654, -2.7174751759, 0.3162423968, -0.9960474372, 1.1332710981, 1.0375409126, -0.0346815698, + -0.2378142923, -1.8274402618, -0.756524086, 0.3035017252, 0.6736583114, -0.3378650248, 1.4695996046, 0.8090537786, + -1.8708773851, 0.992518723, 0.3028483391, 1.4664566517, -0.6074188352, 1.0674394369, 0.1149998233, -0.0621099845, + -0.1732854992, 1.2566143274, 0.4596324861, 0.1921480447, 0.6472542882, -0.0070908745, -1.149587512, -1.5454713106, + -0.8810761571, -0.99329108, 0.4973982275, -0.0830497742, 1.3150237799, -0.8044264317, 0.3923761845, -0.8494360447, + -0.5066404343, 0.4646987021, 0.1593044102, -0.0949085504, 0.2508442402, 0.8306478858, 1.5014774799, 0.6009095907, + -0.2514753044, 0.5792323351, 3.3733355999, -1.7200666666, 1.0272295475, -0.0590384156, -0.4829144776, -0.7770543694, + 1.1213577986, 0.2282679379, 0.3859090507, -1.0854517221, 1.3076217175, -0.016823709, -0.7895203233, -1.0785923004, + 0.0915632099, 0.9873991013, 0.632091105, -0.6186110973, 0.6905904412, 0.6880133152, 1.5512328148, 0.9121033549, + 0.5840374827, -0.4260689318, 1.5989313126, 1.5102443695, 2.873103857, 0.1307470798, -0.03511516, 0.4154373407, + 1.0803951025, -0.7689779401, 0.2349200249, 0.2127694488, 0.1637901515, 0.2540091574, -0.5789597631, -0.2085085064, + -1.4617660046, -1.2019745111, 1.3285419941, -0.5355551839, -1.0052437782, 0.8944669366, 0.6750456095, -0.3523706496, + 0.5630317926, -0.2512718141, 1.2605104446, -0.1540245712, -0.7847375274, -0.5049604177, 0.5393610001, -0.1454569995, + -1.9208295345, 0.1988556087, -0.5276432037, -1.9898313284, 1.3303182125, 1.196695447, 0.846690774, -1.3549520969, + 0.1534716338, -1.6951408386, -1.0888959169, -0.784604013, 0.0208831783, -0.5135362148, 0.1377027631, -1.1420041323, + -1.0348410606, 1.0945382118, -1.6735677719, 0.8930306435, 1.2586365938, -0.4186193049, -0.5548886657, 0.752084136, + -1.2721277475, 3.231153965, 0.4641966224, -2.048148632, 1.9270210266, 0.4723309278, 0.3861116469, -0.5980855823, + 2.4221987724, 1.1139601469, 0.7150088549, -0.50167799, -0.2652854025, -0.5569392443, 0.5937147141, 0.7529249787, + 0.9008342028, 0.4063133895, 0.1512439102, 1.2978001833, 0.2491936237, 0.289598912, 0.8108627796, -0.213408649, + 1.6224154234, -1.1592159271, 0.2234223038, 0.1212291792, -0.9138811827, -0.420507431, 1.5794224739, 0.1617780775, + -1.6059589386, -0.4434491992, 0.6146141291, -1.1083737612, -0.3466961682, -0.4387931228, -0.2230413556, -0.1678518355, + -2.6264977455, -0.1727611125, 1.035525918, 0.344330579, 0.5022798181, -0.5143413544, -0.4986781478, -0.8272845745, + -0.0147204055, -0.5727688074, 0.0031921251, 0.3674898148, 2.0267584324, 0.5630730391, 1.0627936125, 0.2569692135, + 0.391680479, -1.0073970556, 1.2933391333, 0.0424646772, 0.5398423076, -0.5044786334, -0.5983367562, 0.7175628543, + 0.4539347291, -0.8410576582, 0.2607088089, -0.2576574683, 0.1949142963, -0.262316823, 0.6356629133, -0.1043076217, + 0.1324877888, -1.0602743626, -0.2008478791, 1.2160608768, -0.0292315781, -0.1890411377, -0.8686054349, -0.9382474422, + -1.0121945143, -1.4328993559, 1.1785588264, 1.5638674498, 0.1427608132, 2.0439651012, 0.9626225233, 0.2164034098, + -0.315176338, -0.4807561934, 1.9710719585, -0.4390293062, 1.7081115246, -0.3730249107, -0.8752344847, 1.0402947664, + 1.0650632381, 2.2234606743, -0.2990089655, 0.1338202506, -0.0058257026, 0.8717163801, 0.4131239653, 1.7113682032, + -0.3095157444, 0.458919853, -0.6647123694, -1.9829771519, 0.2398172468, 0.730373323, 0.0065799267, -0.2386463732, + 0.7785472274, 0.1026007161, -0.9697332978, 0.9232811332, -0.3040901721, -0.3353936076, 0.4633235931, -0.3067607284, + -0.1129981503, 0.0151031548, 1.4305889606, 0.2822506726, -0.3901175261, 0.2373402417, -0.3301363885, -0.4907036722, + 0.3101215363, 1.656642437, -0.1352761388, 2.0479047298, -0.8596891165, 1.3939336538, 0.5532745719, -0.1697778255, + 1.0746655464, -0.6602277756, 0.4712713957, 0.8705766201, 0.2959489226, -0.1473409534, -1.7874796391, 0.4816951752, + 0.0301115476, -1.0984210968, 0.3432916701, -0.6739798784, -0.8314334154, -0.0407379083, 0.4170181155, -1.1367658377, + 0.7947146297, 1.3205595016, 0.4236109555, 1.4152296782, -1.2873961926, 0.5734673738, -0.1166800484, -0.4258343875, + 0.7109622359, 0.9978282452, -0.7153664827, -0.1323070973, -0.1627074182, 1.2122015953, 0.7887623906, -3.2201621532, + -0.1679748148, 1.3945446014, 0.7399389148, -0.2768034637, 0.4165839553, 0.8265034556, 0.9802414775, 0.4776431918, + 2.016610384, -0.0249875244, 0.4829532504, -0.7448346615, -2.0533394814, 0.9954663515, 0.5559939742, 0.1557032168, + 1.2560248375, -0.0910743177, 0.7448199987, 1.5151149035, 1.068236351, -0.3936732411, -0.4404679239, -1.2789002657, + -0.7345156074, -0.8073781729, -0.2055337727, 0.896699369, -0.011800752, -0.7772536278, -1.2498084307, -2.0847239494, + 0.4443413317, -0.9075754285, -0.070724085, -0.3365614414, 1.1858187914, -0.7117362022, 0.9870203733, -0.66842556, + 1.4725475311, 0.1366336048, 0.7424795628, 1.4361493587, -0.2917276919, -0.3563250899, 0.6698901057, 0.8398872614, + -0.8428919911, 0.7355796695, -0.0806103125, -0.4388633668, 0.4438080788, -0.6025252342, 0.1011375487, 0.4766345918, + -2.1126976013, -1.3606692553, -1.0401051044, -0.0643365011, 1.7286696434, 0.7811232209, 1.2519133091, 0.1582637727, + -0.1840040833, -1.0580223799, 2.1860694885, 0.742046237, -0.6358695626, 0.3461574614, 0.0260392353, 0.2544353902, + 2.4137811661, 0.5811787248, 1.4372696877, -1.1470407248, 0.0356767289, -1.9682257175, -1.682590723, 0.7045783997, + 0.9582905173, 0.4860132933, -0.4299276471, 0.4619325399, -0.3726094365, -0.4181045592, -0.67139256, -0.4985078275, + -0.609192729, -0.6080089808, 0.3473231494, -0.0035682917, 1.2791190147, -0.2127529532, 1.0742793083, 0.7116464376, + -0.6488238573, 0.2859148681, -2.0417239666, 0.4539825618, 2.0291399956, -0.5095365644, -0.9993411303, -1.1150147915, + -0.6259767413, 0.1875912845, -0.2886156142, 1.013499856, -1.1804151535, 0.1758203655, -1.2308334112, 2.5587472916, + -0.9636149406, -0.0713531971, 1.5979670286, -1.5108559132, 0.1449113637, 1.1441174746, 0.231245786, 0.2274304181, + 0.1459915936, -0.6081528664, 0.0709826797, -0.0125633776, -1.318046093, -0.326025933, 0.4805007279, -3.2030875683, + 0.4306159019, -0.5212286115, 0.8575561643, -0.8960441351, -0.1932385713, -0.706309855, -0.9964183569, 0.7934882045, + -0.48025015, 0.3568688333, -1.0943177938, -1.6923885345, 0.7779947519, 2.6947827339, -1.0811645985, -1.4731924534, + 0.0109302318, 0.3299140036, -0.1448013633, 2.4050495625, 0.1636990309, -0.1965565681, 1.5348142385, 0.2748448253, + -0.9842527509, -0.4361257255, -0.5287380815, 0.7196028233, 0.2204200625, -0.54184407, 1.3916079998, 0.7451648712, + 0.2643483579, 0.6969248652, 0.2191476822, -0.3153337836, -1.1294671297, 0.2236620039, 0.8282073736, -1.0530409813, + -0.4204666913, -0.2162797153, -0.7607799172, 1.0307723284, 0.7421389818, 0.4817281663, 0.3772906065, -0.2255851179, + 0.2419869155, -0.2462873459, 1.2878042459, 1.2064702511, 1.9481141567, -0.3638069034, -0.245862484, -0.8163990974, + -1.3361914158, 0.1759304553, 0.8073284626, 0.2768845856, -0.163111046, 0.7782697082, 0.2213267684, 0.6580312848, + -0.8218443394, -0.5532718897, -0.5647550225, -1.2183798552, 0.5782849789, 0.5329989791, -0.6715250611, 0.8244873285, + 1.0194652081, -1.1014153957, 1.6967984438, -0.0429516323, -1.0793919563, -1.1583365202, 1.1959785223, 0.843132019, + -0.419277817, -0.3327940702, 1.9657697678, 0.3050765395, 0.8305168152, 0.9101333618, 0.5969888568, -0.2304041535, + 1.8251065016, -1.1460005045, -0.2217972875, -0.5881155133, -0.4704960585, 0.4888032973, 1.3412656784, -1.0570495129, + 0.4420121312, 1.2955129147, 0.8408915997, 0.7732490897, -0.6764742732, -0.0356562771, -0.6429589391, 1.8658261299, + 0.503526926, 1.2822653055, 0.9182057381, 0.4520080388, -0.5673279762, -0.4225480556, -1.2345860004, 0.9104699492, + -0.610440135, 0.5325096846, 0.259426415, 2.1227545738, 0.6246936321, 0.343685925, 0.4797151685, 0.5576152802, + 0.4796886742, 0.6413477659, 0.1015166044, -0.5291261673, 0.0093640964, 1.192758441, 1.5470068455, 0.9478160739, + -0.8584091067, 1.4589502811, 1.0034278631, -2.0495164394, 1.0458933115, -0.6270156503, -1.697175622, -0.4960333407, + 1.4561544657, 1.0882210732, -0.097612299, -0.7173095345, 0.1641712338, -0.6962606907, -1.3123685122, 0.7208009362, + 1.4251564741, -0.9525543451, -1.6627132893, -1.3450037241, 0.9273759127, 0.3668547571, 0.084720239, -0.8547070026, + -0.1450030655, -1.0790885687, 0.6394917965, -0.7484422326, -0.0812485516, -2.3238573074, -0.8937191367, -0.2410787642, + 0.765801549, -0.1973870993, 0.193147853, -0.5485792756, -0.3950333297, 0.3372679055, 0.7965800166, -0.1148310974, + 1.0055104494, -1.7035870552, -1.2542206049, -0.0020835998, -1.0969371796, -0.6635608077, -0.6708840728, -0.1306800544, + 2.0890042782, 0.2768505216, 2.323486805, -0.1149376929, 1.7064332962, -0.0357143879, 0.0917023197, 0.2306758016, + -0.8789747953, 0.6359471083, 1.0145800114, -1.207918644, 0.7884379625, 0.5274050832, 0.1402386427, 0.3174589276, + -0.5563088655, -1.8163865805, 1.6633933783, -0.1732443124, 0.1822638363, -0.8089761734, 0.6185746193, 1.4769704342, + -0.8918659687, 1.0805387497, -2.2777967453, 0.0982830897, -0.9784666896, 0.1409724802, -0.6910139918, -0.2581627965, + -0.3227139115, 1.2393940687, 1.4970542192, 0.3486480415, 0.6801899076, -1.2906173468, -0.869425416, 0.6916615367, + -0.3949315548, 0.4967114031, -0.9639406204, 1.0947629213, -0.5677868724, 0.1172745824, 0.1036742851, 0.8766137958, + -0.5469971895, 0.0912009105, -0.8483621478, -0.1651878506, -0.8982597589, 1.8080214262, -0.1094860435, -0.6009634733, + -0.3665615022, -1.1674404144, -0.3560737967, 0.4168348908, 1.2016643286, -0.5615233183, 0.6447062492, -0.2535068691, + -1.1192104816, 1.1256830692, -1.6240452528, 0.9639360905, 0.4438114166, 1.8228126764, 1.9016685486, 1.334077239, + -0.9280285835, 1.7382543087, 0.5836077929, 2.3370118141, 0.5108041763, 1.446965456, 0.4597733915, 1.0623366833, + 0.0035629983, 0.0866807178, -1.346378088, 1.1956572533, 0.3716119528, 0.0912752375, 0.5642582178, 0.768727839, + -0.0072249584, -0.4405217469, 1.210465312, 0.0289006699, -0.6262733936, 0.2481508404, 1.7004103661, -1.0955580473, + -0.972604394, -0.9737624526, 0.2870694399, 0.5214788914, 1.4835518599, -0.2087257504, 0.0239505731, 0.2233554721, + 0.2403004915, -0.8426833749, -1.2004982233, 0.7131180763, -0.6364238858, 2.0007157326, -0.3677787781, 0.5677682161, + -0.5169160366, 0.784917891, -0.1691215634, 0.3505437374, 1.2626199722, -0.3145025969, 0.0967818573, -1.1018123627, + 2.0346674919, -0.5044198632, 2.0918335915, 0.5418912172, 0.1253499985, -0.4790270329, 0.988515377, -0.224477455, + -0.7532069683, -0.2590924203, -0.3724360764, -0.5268012881, 0.0099415304, 0.985239923, -0.9677956104, 0.9610522985, + -0.4307636321, 0.9771789312, 0.4913146794, -0.1979523748, -1.2591580153, 0.1725802869, 0.3992780149, 0.2902160883, + 0.6774837375, 0.1915705055, -0.5545125008, -1.6164081097, -0.4995488822, 0.1495799124, 0.7770783901, -0.6658815742, + -1.3216475248, 0.7363036275, 0.4968822896, 0.5971414447, -0.6678465605, 0.1934313029, 0.4205310643, 0.5923535228, + 0.0337040164, 0.483132869, -0.3680884242, 0.3568235636, -0.3181792498, -0.8712489605, -0.8680101037, -0.5461862683, + 0.6563332677, -0.3947722018, -0.2092790902, 0.0315701514, -0.4167560935, 0.057035502, 1.4990587234, -0.8132793903, + -0.4818907976, 0.4890195429, 0.6042798758, 1.5244840384, 0.4387151301, 0.3640931845, 1.5731611252, 0.5005360842, + 1.0017102957, -0.4325468838, -0.7100720406, -1.3056461811, 0.3504725397, 0.2902453542, 0.3730077446, -1.8038679361, + 0.3144704103, 1.1459712982, -0.965585351, 0.4122045934, 1.5242187977, -0.2994287908, 0.0495324992, -0.884137094, + -0.9477353096, -0.5417408943, -0.0676480904, -0.4663005173, 0.9185313582, 0.0686773732, -0.6691791415, 0.3122829497, + -1.1253046989, -0.155660063, 0.5729102492, -1.083771348, 0.0669136345, 0.4971903265, 0.0897533596, -0.1047038808, + -0.6622824669, -0.7894172668, 0.8324003816, 0.7106827497, 0.348326087, -0.7259815335, 0.6386246681, -0.5196985602, + 0.5204224586, 0.0865338221, -0.781047523, -1.2443351746, 0.3589504063, 0.4397775829, -1.1927919388, 0.917208612, + -1.2508444786, 1.7453820705, -0.3246877491, -0.4532547295, -0.0731760189, -1.3975434303, -0.7634076476, 1.5434905291, + -0.4080433547, 0.4650013745, -1.4238005877, 0.2563230693, 1.7736479044, -0.7137615681, 2.2522010803, -1.3089007139, + 1.152510643, -0.1405597478, 0.5320132971, -0.681065321, -0.4485176206, -0.3747822344, 0.4281465709, 0.800771594, + 0.0123932073, 0.1402721852, 1.9548217058, 0.330994457, 0.3134448826, -0.8624955416, 0.1731562018, -1.1307023764, + -1.2180870771, 0.3798313737, 0.1041512787, -1.0410223007, -0.2304405719, 0.091612272, -1.1846817732, -1.1531682014, + -0.4354380965, 0.4104143679, -0.4816984534, 0.4900153279, 0.7041178942, -0.7546210289, 0.5832744837, 1.2078104019, + 0.4386845529, -1.5632371902, -0.8126469851, 0.1477559507, -0.0461850464, -0.367308259, -0.4501196742, -0.1551027894, + -0.7583582997, -0.0730031282, -1.9887934923, -0.8846876621, 0.673275888, -0.081119366, 1.0592772961, -0.5077518821, + -0.3238532543, 1.3735461235, -1.4465440512, 0.182135582, 0.0676640049, -0.4560262859, -0.3496088684, -0.6075907946, + 0.6537126303, -1.7022186518, 0.0755707473, -0.1904866546, -2.1203536987, 1.7095605135, 0.7199447155, 1.7510561943, + 0.816927433, 0.8673193455, -1.2237163782, 2.6919562817, 0.303311348, 0.235571906, 0.4901683927, -0.7814581394, + 0.8745526671, 0.2152803242, 1.0555243492, 0.3528210223, 0.3482930064, -0.0836526528, -0.8183871508, -1.3136165142, + 0.5067337751, 0.9809406996, -0.372793138, 0.1372788996, 1.2173398733, 1.0570574999, -0.1092743352, 0.4346898496, + -0.7528158426, 0.848870337, -0.8521622419, -0.812435329, -2.1803562641, -0.7766513228, 1.1283991337, 0.3751853406, + -1.3530814648, 1.3838658333, 0.4173292816, 0.7445374727, -0.0002430229, -0.9045234919, -2.6463234425, -0.3570845723, + 0.2908712029, 0.3473463953, 0.5702397823, 0.7549381852, 1.4791334867, 0.9874882102, -0.6921150684, 2.3449747562, + 0.6544520259, 0.3682841957, 1.904048562, 0.4765006304, 1.1654456854, 0.730753839, -0.4611986578, 0.639059782, + 0.374117434, -0.5228999257, 1.619404912, -1.0346127748, -0.5952832699, -0.8493008614, 0.8470287919, -0.5518957973, + 0.2897983789, -0.0187721644, -0.3662812412, -0.3504948616, -0.3711920381, 1.7615973949, -0.4802156985, -1.8253751993, + -0.1795722097, -0.3333802223, 0.4528505504, 0.725084424, -0.1168686971, -0.2354764342, -1.0015610456, 0.5932791233, + -0.7151992321, 1.1872414351, -0.6099489331, -0.8342801929, 1.0395519733, 0.46417889, -0.1812096685, -0.2494318336, + 0.1936044991, -0.3829216361, -1.2802710533, -0.0509898625, -1.153518796, 2.3395931721, 0.9372795224, -1.0627675056, + -2.2381188869, -0.0003268473, 0.1890586317, 1.9689356089, 0.4381758869, 0.6209080815, -0.0069314591, 0.6565827131, + 0.9101958871, -0.8087453246, -1.0782167912, -0.413887769, -1.1793274879, 0.3645130098, 2.4339489937, 1.2218075991, + -0.5169935226, 0.3686336875, 0.3838019669, 1.0012456179, 0.0827877894, 0.6399840117, -1.1393259764, 1.150049448, + 0.1755813956, -0.4248540998, -0.9612060785, 1.2496811152, 0.6430417895, -0.8739003539, -0.6526424289, 1.1801552773, + -1.3901848793, 0.6684985757, 0.7047442794, -0.0454604439, 0.9043201208, -0.0832923055, -0.0246616453, -0.7082564831, + -0.6657384038, 1.162517786, 0.7331817746, -0.806553185, 3.054984808, -0.6254408956, -0.9780409336, 0.3719343543, + -0.7863800526, 0.2642794549, 2.1103971004, -0.2257129401, -1.3434938192, -0.6517789364, 0.9215201735, -0.5927384496, + 0.9416487217, 0.0437185653, -0.3107615113, -1.8002775908, -1.5352293253, -1.2877420187, 0.249764055, 0.088930659, + -0.350710541, -0.5227136612, -0.5778329372, -0.7980781794, 0.211048156, -1.3815633059, -0.6894747019, -0.2972003222, + 0.8221981525, -0.2503884733, 0.7942054272, 0.9488335848, -0.188492164, 1.0855621099, -0.6987811923, -0.2730012834, + 1.4528568983, -0.6969278455, 0.5462369323, 0.4251119494, 1.1552058458, 0.3428002, 0.8982730508, -1.4678502083, + -0.543415606, -0.0516024604, 1.3498048782, 1.7462068796, 1.0836268663, 0.8198674917, -0.4759975374, -1.0495749712, + -0.99966079, 0.3143595755, -0.8451169133, 0.9353263378, 0.9249797463, 0.2017759383, -1.9286822081, -1.1570881605, + 0.5033632517, 1.1476683617, 0.2429254949, -0.6879550219, 0.994307816, -0.2067762166, 0.6849880219, 1.404476881, + -1.4275686741, -0.8624293804, 0.7384086847, -0.5561550856, -0.8264702559, 0.7136894464, -0.3004029989, 0.8249571323, + 1.3415811062, -0.1680783927, 1.0953153372, -0.8835517168, -1.0230761766, -0.2327672988, 1.2700972557, -1.1392649412, + -0.4342262745, -0.722363472, 0.5530021787, 0.5501202941, 0.3454295397, -1.0601592064, 0.3098625839, 0.3677841425, + 0.9607761502, 0.6529376507, 1.4435209036, 1.0172544718, 1.3574310541, -0.0099963387, 0.0024282169, -0.4879335463, + -0.432488054, 1.4777532816, 0.2670559883, -0.4485886097, 0.6798025966, 0.680736661, -1.4864747524, 0.2098133266, + 0.4501485527, 1.2317266464, -0.2362726778, -0.4584268034, 2.8149886131, 0.1683895439, 0.2099463046, 1.2645759583, + 1.2813298702, -1.3021427393, -0.0147156315, -0.4178023934, 1.9107762575, -0.6563686728, -1.0691428185, -0.4230622947, + -0.013246214, 1.8421353102, 1.7196012735, 0.5972613692, 0.3515547812, -0.5387497544, -0.0692220926, -0.3597345054, + -1.0044300556, 0.5427931547, -0.8332656026, -0.5242043734, 0.8488559127, 0.1747637987, -0.3172430992, -1.2048152685, + 0.6520953178, 0.4357360303, -0.5587982535, -0.4179782867, 0.4264180362, -0.0548314825, -1.1908137798, 0.4734176993, + -0.6122033, 0.4030275941, -0.2191144228, -0.323892951, 0.6194945574, -1.255004406, 1.5398229361, -0.4604188502, + 0.7527544498, -0.3760625124, -0.6907941699, 0.6619018316, 0.3901435733, -0.9779542089, 0.281270504, 1.3486820459, + 0.8936386704, -1.0297094584, -0.776607573, 0.5017185807, -0.9354196787, -0.4815663397, -0.0947765708, -1.3963850737, + 0.25904724, 2.3648326397, -1.925522089, 1.373601079, -0.2367615402, 1.2566763163, 1.9916495085, -0.5050504208, + -0.6587370634, 0.1339435875, -1.5667083263, 0.4359713495, 0.0420700498, 0.0357943885, -0.0433804691, 2.2872498035, + 1.2421827316, -1.6219403744, 0.2979706526, 0.5869822502, -0.6416541934, 0.3410756886, -2.2526934147, -0.8089647293, + 0.2043059468, -0.1011173427, -0.4876793921, -1.3751064539, -0.2896009982, -0.361410141, -0.4906738997, 2.8373856544, + 0.2476367205, 0.0999422297, -0.9083200097, 1.2840486765, -0.9753172398, 0.0642992556, -0.8871639371, 0.3426522911, + -2.119007349, -0.773508966, -1.3035955429, -1.9201433659, 1.1583014727, -1.3426201344, 1.3124009371, 0.4313886762, + 0.0344963595, -1.2075973749, 1.2700092793, 0.6499128342, 3.3665959835, -1.6459656954, -1.3581641912, -1.821644783, + 1.4461368322, -0.1574293673, 0.1464605033, -0.7976961136, 0.1109806001, 0.158321768, 1.0877591372, -0.0723408088, + -1.0505943298, 0.2393178642, -1.436377883, 0.3752524555, 1.2342381477, -0.8808445334, -0.2301429659, 0.3931305408, + -0.4250062704, -0.5529979467, 0.686219573, 2.4019544125, -1.3151100874, -0.230142355, 0.4676499367, 0.5954039693, + 0.4348103404, -0.0355928615, 1.382874608, -0.2989363372, -0.891956687, -1.3971213102, 1.7783776522, -0.2302737534, + -1.762416482, -0.6463377476, 1.1267231703, 0.4442473948, 0.4791038632, -1.4811384678, -2.1068751812, 0.5931427479, + -0.1246527433, 2.1817100048, 1.6543698311, -0.1731125265, -0.1042543724, -0.0780078098, -0.7192997336, -0.4809856117, + -0.1577761769, 0.4041523635, -0.0076569053, 1.1993273497, -0.3402960598, 0.7366626859, 1.3511939049, 0.4218282104, + 0.1720520854, 1.8980066776, 0.2961442173, 1.1082334518, -0.7020488977, 1.1318085194, -0.6802171469, -0.6433147788, + -1.0897530317, -0.1884802282, -0.8276434541, -0.7988906503, 0.3866085112, -0.0302876048, 1.0736109018, 0.0648761988, + 0.8674221635, 0.4764135778, -1.1911543608, 0.7603228092, 1.4816516638, -0.8416389227, 0.1508948207, -0.4492126107, + -0.5611734986, 1.6207737923, 0.8324872255, -0.5176488757, 0.5176472068, 3.0010211468, -0.5873510242, -0.7627546191, + 0.7660671473, 0.6905959249, -0.2636062503, -0.4258366227, -1.2875888348, 1.4470908642, 0.0458003469, -0.5081302524, + 1.5856559277, -0.5258768201, 0.1839931756, -0.4267107844, -0.7687863708, -1.97488451, -0.7904258966, -0.3710695207, + 0.2210629135, 0.1301920861, -0.897957325, 0.2273373753, 0.7875413895, 0.7730968595, 1.2694029808, 0.2548620105, + -0.8165200353, 2.0619447231, 0.0528843738, -1.485612154, 0.5538668633, 0.4425628781, -0.2612531483, 0.2037329376, + 1.2159631252, -0.1642043442, 0.4371479452, -0.2363016307, -1.6688332558, -0.8167054057, 0.2186635584, -0.2214595377, + -0.2448555678, -0.3115261793, 0.9378111362, 0.1662903726, -0.6850562692, -0.8621481061, -0.8770141602, 0.2879326642, + -0.7475222945, -0.7961471677, 1.0106245279, -0.2903393209, 0.1513967961, -1.1147676706, -1.2387049198, 2.6652097702, + -0.1084619164, 1.3810008764, 0.6159277558, -0.5572487116, -0.465816915, -0.2820259333, -1.1114195585, -0.3663528562, + -0.4245306551, -0.1668689102, 1.3447589874, 0.0826546401, 0.593144536, -2.0726764202, -0.6349374056, 0.1409984976, + -0.8965637088, -0.2465610951, -0.7543249726, 1.3068647385, 0.5193663836, 1.2673950195, 0.0530828945, -1.3074204922, + -0.9408559203, -0.3132842779, -0.3520522416, 0.2639456987, -1.6094528437, 0.2965346277, 1.1979731321, -0.6135300398, + -1.2268162966, 0.1642137766, 0.9970766306, -1.3188539743, 1.0603978634, -1.1148290634, -0.0663175508, -0.7761843204, + -0.836971283, 1.0939637423, -0.1550624073, -1.6109610796, -0.0460047275, 0.6645396352, -0.2567320764, 0.0598233193, + 0.7579881549, 1.9713249207, 0.3284783065, -0.5257778764, 0.9011698961, 1.1173251867, -1.0251053572, -0.0538991652, + 0.2657756507, 0.6858976483, -0.0486010723, 0.1332474202, -0.5991258025, -1.612467289, 0.024162814, 0.0723342896, + 0.6667144895, 0.3458332419, -1.0246504545, 0.0992837548, -0.896479249, 0.072352156, 0.2398944497, -0.7628162503, + 0.4543907344, 2.37499547, -0.1462941468, 0.0003235369, 1.0902603865, 0.5219897628, 0.3533296883, -0.7274948955, + 0.3543509543, 0.3556120694, 0.8606618643, -0.6099217534, 0.6097067595, -1.0419270992, 0.1097846627, -0.1417976171, + -1.1922610998, 0.0365081467, 1.3653956652, -0.5518307686, 0.31836918, 0.117094554, -0.1883369386, 0.9821451306, + -0.0275580082, 0.6468264461, -1.5413923264, 1.6071134806, -0.9581078291, 0.7696560621, -0.1862657368, 0.4136942625, + -2.6068975925, 0.8061500788, -0.7720109224, 0.1059482396, -3.1292214394, 0.0776122808, -1.3263397217, 0.3734543025, + 0.9427181482, 0.11157763, 1.9515994787, 0.7113924623, -0.2507297397, 1.5339950323, -1.1204895973, 0.3802853823, + 0.5562388301, 0.4393317401, 0.3805435896, -0.1796236187, -0.0068756798, 0.3063318431, -0.8758431673, 0.0523967259, + -0.9203234911, 0.4118686318, -1.116797924, -0.8827121854, 1.2052417994, -2.1289260387, 0.5620676279, 0.9299391508, + 1.7372515202, 0.9391069412, 0.1322578937, 1.6648646593, 0.6191270351, -0.4869742095, 0.020215515, -0.0032952912, + -0.7536495328, -0.0577502102, 1.4988473654, 1.1853531599, -1.1569428444, 0.4523760378, -0.4761290252, 0.4584850967, + -0.0814426169, 1.1522524357, 0.5754417777, 0.9752656817, -0.6391966939, 0.8959468603, -0.5191081166, 0.4095037282, + 1.2617907524, 1.377889514, 0.9799590111, 1.6725335121, -3.0943217278, 0.949886024, 0.8754180074, -0.3936840296, + -0.4376997054, -0.213549152, -1.3722800016, 0.3389026225, 0.1849378496, 0.1413071156, 0.1889852732, -0.9622039795, + -0.6044231057, 0.8672102094, 0.0209429972, 0.6589286327, -0.1708002537, 0.1002857089, -0.8388501406, -0.1158685908, + -1.9335631132, -0.2489332408, -1.6315416098, 0.5039172173, 1.101513505, 0.5260147452, 0.357291609, -1.0680633783, + -0.7171474695, -1.0039732456, -0.6688591242, -1.7563149929, 0.3410589695, -0.083037518, -1.8177490234, -0.1606295109, + 1.2918634415, -0.8302479982, -0.181780234, -0.253295958, 1.9223433733, -2.0590584278, -0.7776770592, 1.490190506, + 1.2545901537, 0.8289508224, 0.1364070326, 0.0048171692, 0.4144740701, 0.1384837925, -1.2213534117, 0.420573771, + -0.156627357, -1.3302257061, -1.0808893442, -0.3223316371, 2.3164737225, -0.6410893798, 0.7436528206, -1.2338428497, + -1.8407684565, -0.9513223767, -0.5103200674, -0.5803955793, -0.306178093, 0.4369329214, -0.9844542146, -0.332223922, + -0.5980868936, 2.0401651859, 0.7489195466, 1.0855104923, -1.0209662914, 0.943803966, 1.3219096661, -0.7857168913, + -0.7631080747, 0.3792274594, 1.9473079443, -0.4503182769, 0.3687690496, 0.5508050919, -0.0530326739, 0.3569258451, + -0.2823581696, 0.1155722141, 0.0433711931, 0.0135188764, -1.3273210526, 0.216589123, -0.699796319, -0.0507710278, + -1.7662363052, 1.1606320143, -0.0638204664, -0.1239236444, -1.5254353285, 0.888463974, -0.0218050219, -0.4060950279, + 1.0596505404, 1.6093878746, 0.6677417755, -0.8113313913, 0.2368712276, -0.7918953896, 1.3205071688, -1.1475688219, + -1.0701115131, 1.3642249107, -1.0599621534, 0.0186037924, 0.5424012542, -0.7976353168, 0.5737085938, -1.7811143398, + -0.8941566944, 0.6157245636, -1.4740045071, -0.0339163728, -0.2008125037, 0.4697420597, 0.7060800195, 0.3085568547, + 1.4709632397, -1.4332449436, -1.3343772888, -1.9902968407, -0.3875651062, 1.72113204, 1.4731040001, -1.1057852507, + 0.8125382066, 1.5489228964, 0.2021583468, 2.3115398884, -0.4626514018, -0.0988822505, -0.3713912368, -0.1346644759, + -1.1158742905, -0.1639193296, 0.0890217721, -0.449988246, -1.1167421341, 0.4916646779, 0.2613768578, 0.2538814545, + 0.2545026839, 1.0541639328, 3.0064599514, -0.7094870806, 0.7198755145, 0.1062187478, -0.7458360791, 1.3711556196, + 0.9849750996, 1.1028059721, 0.2148303241, 0.2942796648, 0.3881600797, -2.2538924217, -0.0313082747, 0.0384150855, + 1.4320955276, -0.9805296063, -0.8168244958, -1.0708725452, -1.3232696056, -0.0492793471, 1.1589303017, 0.998595953, + 0.1406734884, -0.2315083295, -1.3020762205, 1.6821084023, 0.0845298097, -0.0012636767, 1.3425643444, -1.1528156996, + -0.4846612811, -1.1822725534, -0.6761192083, -0.0896490365, 0.094338581, 0.3186304867, 0.7720057964, -0.2023819238, + 0.2094048411, -1.241980195, -0.3391025066, 3.1322660446, 0.1629785895, 1.3776082993, -0.4834138453, -1.440314889, + -0.9649205208, 0.6832093, 0.3958668113, 0.5880941153, 0.0307263527, -0.8174967766, -0.0751677454, 0.4808998108, + 0.1181297526, 0.279282093, -2.1766908169, 0.3593552709, 1.2126170397, -0.7078419924, -0.1993245333, 1.2566301823, + 0.300334692, -0.4112148881, 0.4869786203, -0.0476831608, 0.6511651874, -1.5540522337, -0.4369316995, 1.0390468836, + 0.9457051158, 0.2111051232, -0.3961375952, 0.9423094988, -1.1002054214, -0.7350199819, 0.0146141937, 0.574573338, + -2.6855244637, 0.5434151292, -0.1790276021, 0.7951074839, -1.7326436043, 0.0923662931, -0.5095089674, 0.5917858481, + 0.8422880769, -0.1820607781, -1.6822385788, 0.9818657041, 0.5777400136, -0.7624858618, -1.0306129456, -0.213079527, + 0.98319906, 0.8381908536, 0.4186193347, 0.2878623307, 3.3586564064, 0.676828146, 0.7891095877, -1.5845159292, + 0.6934824586, 0.1463712752, 0.1077918932, -0.0776537731, -0.9601588845, 1.5597449541, 0.2852105498, 1.1821978092, + 1.460005641, -1.0947434902, -0.5802459717, -0.3190021217, 0.2932513952, -1.2169111967, -0.1552423239, 0.2548938096, + -0.6420126557, 0.9541916847, -0.4548354447, 0.2853848338, 1.049013257, -0.1054982617, -0.8711935282, 0.0640761554, + 2.0955986977, 2.2802312374, -0.7062234282, -0.9325771928, -2.7064745426, 0.5550458431, -0.8726333976, 0.8819828033, + 0.4131059051, -0.4404965639, 0.5863825679, 0.9154740572, 0.2949877381, -2.6654002666, 1.2274175882, 0.1260483563, + 1.0107161999, 0.4425277412, 1.2145001888, 2.3537797928, 0.3502727151, 0.4897087514, -1.473148942, -0.6829451919, + 0.7784183621, 0.0769444928, 0.8899565339, 0.6568589211, -1.4877281189, 0.8486710787, 0.2527044415, -1.2365397215, + 1.8013707399, 2.1016540527, -0.0500311032, -1.302251935, -1.9501366615, -0.5360963345, 0.3994601369, 0.5160616636, + -0.823528409, -1.7060825825, -0.7978700995, 1.750362277, -0.1441345215, -0.9500775933, 0.5486234426, 0.1444375366, + -0.7123869658, -0.1756013632, 0.1871870011, 1.1465924978, -0.3897903562, 1.8086135387, 1.1280059814, -0.0083743073, + -0.3285886049, 0.2197051197, 0.7689400911, 1.0436525345, 0.2513706982, 2.6073219776, -0.3112938404, 0.2724854648, + -2.2912137508, 0.2034903765, 1.132851243, -0.0851072371, -0.1136390269, -0.2366341352, 1.2237306833, -0.2443148643, + -0.114937298, 0.8067960143, 0.7126696706, -0.3885196447, 0.8958705068, 0.6093592644, 0.7420414686, -1.1293281317, + 0.0535399579, 0.1800847501, 0.9242040515, 1.0947157145, -0.4837334454, -0.8320499063, -0.0283501279, -0.7321954966, + -0.464815408, 0.5936284661, -0.1790808439, 0.6123202443, -0.3115934134, -0.622081995, 0.3708849251, 1.4454218149, + -0.1824720055, -1.4103887081, 0.2352046967, 1.5774737597, 0.8297368884, 1.1899679899, 1.4147301912, -0.158270061, + -1.1319595575, -0.5135700703, 0.7510833144, -1.5830452442, -0.6762850881, -0.6799480915, 0.4081239104, 0.8614497185, + -1.4354953766, -1.4303246737, -0.3100005388, 0.6109189987, 0.3791231215, -0.7022027969, 1.0591596365, -1.4798945189, + -1.0763273239, -0.6885050535, -0.556545794, -1.9920260906, -0.5430017114, -0.2988832593, -0.4576859176, 0.6534484625, + 0.0158297122, 0.0252145696, -0.5811895132, 1.6511220932, 0.029305296, 0.8481232524, 1.3957945108, 0.9147311449, + 1.9018837214, 0.0225104298, -1.0985888243, -1.5755480528, -1.9768010378, -0.4817121029, -1.4537837505, 0.7854406238, + -0.3301056623, 1.2437915802, -0.0110594444, 1.3535820246, -1.1919013262, 0.6878582835, 0.4309915602, 0.034405116, + -0.4072600603, 0.118393153, -1.1715111732, 1.1703085899, 1.4365798235, -1.1344217062, -0.5182979107, 0.8712841272, + 0.8400304317, 1.4912987947, 0.3017890751, 0.2879858613, 1.5178281069, -0.3468378782, -0.1891960204, 0.3158127964, + 0.2165258229, -0.2097465992, 0.6558660865, -1.6493350267, 0.0418719389, 0.2596367896, -1.1072080135, 0.1650775224, + -0.6635113955, -0.7450125813, 2.1797268391, 0.7675815821, 1.6386095285, -0.7342829704, -0.882660985, 0.8525941968, + 0.077968061, -0.2251982987, 0.5225286484, 1.7051614523, -1.0837510824, -1.2669957876, 0.1919908673, 0.8322687149, + -0.7541927695, 0.6820940971, -0.0351917483, -1.4053186178, 0.2227966338, 1.3239190578, 1.3002049923, 1.4524662495, + 0.3714876473, 0.2805170417, -0.0919749141, -0.5110696554, 1.1964526176, -0.0531565435, -1.1680847406, -0.6295111775, + 1.6872906685, -2.5313727856, 0.2121602297, -0.8588676453, 0.5005645156, -1.4779620171, -0.4762757719, -0.2537456751, + 0.5073809624, 0.6816993356, 0.5533781648, 0.9636012316, 1.4837093353, 1.5566785336, 1.2752995491, -1.181194067, + 1.4324865341, 0.2819110155, -0.4524187148, 0.7230597734, -2.5340185165, 0.0218055099, -1.2718653679, -2.7177481651, + 0.5364590287, -0.0088465754, -1.0927875042, -0.2092958838, 0.3976587653, 0.1919134855, -0.5732107162, -0.0421538688, + -1.594214201, -0.304315269, -1.354521513, -1.0652045012, 2.5165457726, 0.8235344291, -0.8325254917, 0.7410484552, + -0.8188034892, -0.3710550368, -0.1469221711, 1.4208518267, -0.6055439115, -2.3149800301, 0.053371232, 0.9889836907, + 0.5201842785, 1.0583690405, 0.0227681696, 1.2871819735, 0.8295145035, 0.1761369258, -1.2930803299, 0.5198744535, + 0.3537299931, 0.906423986, 0.3577017486, -1.2018020153, 1.539326787, 1.1606206894, 0.3462671638, 1.0494418144, + 2.0337548256, -0.6492514014, -0.253616184, 1.1055673361, 0.7026463747, 0.8310782909, 1.0652977228, -0.2652146518, + 0.697658062, -0.1085451543, -1.5246456861, 0.3379697502, 0.6745842099, 0.6699867249, 0.7807105184, 0.3559247553, + -1.4706202745, 0.2427008599, 0.1194189042, -0.9471550584, 0.5363782048, 0.7715194225, -0.7956759334, 1.3846803904, + -0.0059837541, 1.6803729534, 0.4307575822, 1.3302416801, -1.9971408844, 0.9966135025, 0.6510790586, 0.3689449728, + 0.3054286242, -0.086813651, -0.4496328235, -0.4203562438, 0.0446175151, 0.0464101844, -0.6030803919, 0.9469773769, + 0.883023262, -0.6825973988, 0.0063548535, 0.9545045495, 1.7176597118, -0.4867136478, 0.5350939631, 0.2192623615, + 1.4326761961, -1.8599370718, -1.3125212193, 0.1645046771, -1.1676248312, 1.4429554939, -0.5579243302, 0.4837940633, + 0.9947431087, -1.2013341188, -0.4283203483, -1.7186342478, 0.0546005592, 1.0362206697, -0.9954963326, 0.0477595143, + -0.026892107, 0.6498132348, 0.1365755051, 0.1145898923, 1.2277548313, -0.7165322304, -0.3180812597, -0.9940687418, + -1.9625616074, 0.7006590962, -0.0359061249, -0.3734052181, -0.2956706583, 1.2970714569, -2.0354444981, 1.5242056847, + 1.4134936333, 0.6256355047, 0.6216192245, 0.5148414969, 1.6640155315, 0.0376209542, -0.2404932976, -1.3875989914, + 1.0557792187, 0.9804635644, 0.2911759019, 1.6869058609, 2.4566636086, 1.6708139181, -0.6846850514, -0.0785990059, + -1.9915647507, -2.2253570557, 1.7390940189, -0.0221805908, -0.5199558735, -0.4286879599, -0.8465876579, 0.1239822507, + -0.3726306856, -0.8203553557, -0.0182525702, 0.5630733371, -1.8752394915, 0.415504247, 0.5997116566, -1.9111266136, + -0.1225134805, -0.9004780054, 0.5674170256, 0.9721233249, -0.5763071179, 1.2280766964, 0.0869190246, 1.5497611761, + 0.06901256, -0.3725866973, 1.1458171606, 0.7421871424, -0.2898759842, 0.4488764405, -1.1340010166, -0.625756979, + 0.809925735, -0.5755894184, -0.3711819947, -1.2420692444, 0.5750556588, 1.2347095013, -1.3155068159, 0.5820550323, + -0.1800024062, -0.7291352749, 0.9901236296, 1.6943480968, 0.3219739199, 0.4525323808, -0.8705807328, 1.2545053959, + 0.0177927706, -0.9325863123, 0.5151397586, -0.0098660281, 0.4695507288, -1.9551370144, 0.1708181202, -1.2006139755, + -0.6353746653, -0.341444999, 0.6378657818, 1.6013050079, 1.3553612232, 0.3463516533, 0.4996110201, 0.5760862827, + -0.3864963055, 0.6062389612, -0.9762124419, 3.0961830616, -0.3332355917, -0.6250987053, -0.3858212531, -0.0016092911, + 0.1147701219, 0.1219455898, 3.0642769337, 0.9969142675, -0.3090046346, -0.6291542649, 1.7868961096, 0.3111509979, + 2.1643211842, 0.298963666, -1.6422638893, 0.0548259765, 0.0236156844, 0.6794649363, 0.6361483335, -0.2971331179, + 0.1430229992, 0.3408798873, 0.1371335685, -1.1627069712, -1.6395305395, -0.7312899828, 0.8405165672, -1.4277316332, + -0.6171786189, 0.9497544765, 0.158977598, 1.0119231939, 1.3794178963, -0.4360499978, -0.0422094576, 1.5773836374, + 2.0762181282, 0.7507163882, -0.3115755916, 0.7139906287, -1.198494792, 1.625947237, -1.8023258448, -0.2536619902, + -0.3082579374, 0.0895618051, -0.282651335, -0.775591433, 0.1211613193, -0.5160586238, 0.3996881247, 2.6127579212, + 0.7454584837, -0.5768119097, -1.1571289301, 0.2560498416, -0.825420022, -2.607578516, 0.8396331072, 1.7745233774, + -1.1578730345, -0.228680104, 0.1026872993, -0.4894656837, -1.0386230946, 0.6681470871, 1.1531586647, -0.2183658928, + 0.3109624088, -0.6623362303, -1.805311203, 0.3087073267, 1.0570780039, 1.07464993, 0.5073927045, -0.8723320365, + 0.6104628444, 0.4474971294, -0.7325591445, 0.255227536, 0.4838557839, -1.0039037466, -0.196380347, -0.6780635118, + -0.4196233749, 1.5498566628, -1.6033440828, 0.3494834006, 1.0629042387, 1.0952367783, -0.9827461243, 1.2384337187, + -0.7188549638, 0.0698258132, -0.5090520978, -1.3466193676, 0.2113907784, -1.9054464102, 0.7425320148, 0.0713237897, + -0.3361792564, -0.1544833332, 1.2751290798, 0.9343932867, -1.1927865744, 0.1609488577, -0.0817530602, -1.6265294552, + 0.0792161152, 1.0164269209, 0.0274453927, 0.5830265284, 0.4806797206, 1.7057460546, 0.344622612, 0.1727063209, + -0.5576907992, 0.5787950158, 0.2685793638, -1.1247400045, -1.1956520081, 0.7687556148, -0.8483432531, -0.1325481385, + 0.6503481269, 1.2317855358, 2.5165569782, 0.9462372661, 0.7442957163, -0.1037486866, 0.8058280349, 1.2004961967, + -0.2012088895, 1.2878060341, -1.6287704706, 1.1572757959, 0.2970125377, -0.843301177, 0.694114089, -0.3813734949, + -0.7616585493, 0.2744237781, -0.0081879422, -2.0205621719, -0.4257437587, 0.0422513634, -0.0920020416, -1.5582008362, + -0.0928666592, -1.2283902168, -0.1833214313, -0.319095552, -0.0863488317, 0.9307079315, -1.9677612782, -1.5400369167, + 1.0738964081, -1.0055810213, 1.1223951578, 0.5734156966, 0.4714262486, -0.0594240949, -0.8080806136, 0.227867797, + 1.036233902, -0.249535948, -0.7958166599, -1.1433826685, -1.1669473648, 0.2910191119, -0.2219422013, 0.1698516011, + -0.5612007976, 1.1821777821, -0.9412812591, 0.3577224612, -1.4375506639, 0.6173115969, -0.075397186, 0.4404014051, + 0.3479704261, 1.7728350163, -2.4903116226, 1.9318493605, -0.1871684641, -0.0486194454, 0.566999197, -0.1999413967, + 0.3919151723, -1.013764143, 0.4496327043, 1.2215998173, -1.367407918, -0.3145882785, -0.6682460308, 1.7609888315, + 0.4312697351, 0.411765486, -0.8673826456, -2.2342579365, 0.8778496981, 1.762727499, 0.180137679, -0.9213985801, + -0.7761957645, 1.5885344744, 0.3222749829, -0.7482187152, -0.0693738833, -2.54850173, -0.0396765657, 0.9220715165, + -1.18762815, -0.2048502117, -0.8791155815, -0.2799369693, -0.7904237509, 0.7771903872, 0.0180385746, 0.2614985704, + 0.1531894207, 0.4526953697, -0.7578824162, -1.0335227251, 1.0775671005, 0.2108330131, 0.2002221793, 0.4302573204, + -0.9542171359, -0.120671995, -2.2216730118, -1.1611789465, -0.8942284584, 0.3513225317, -0.4492657483, 1.7326287031, + 0.8167504072, -1.3099080324, 1.0597997904, -0.0260978416, -0.0922782496, -0.2445535958, -0.8588480353, 0.0233809687, + 0.8380134702, -0.8886740804, 0.0055783619, 0.8041345477, 0.5155995488, 1.3099330664, 0.0607562996, -0.4853078723, + -1.2040776014, -1.8143754005, -0.9156990051, 1.190397501, 0.3376074731, 0.4168293178, 0.2208614945, 0.0823195726, + 0.3248101473, 1.0169280767, 0.366075933, 0.7446341515, -0.6754641533, -0.9308695197, -0.9214447737, -0.9902174473, + 0.0467686094, -0.4429434836, -0.2878521383, 0.4659559727, -1.5754804611, 0.7648607492, 0.6077049971, -0.2009276748, + 0.1410205662, -0.7378753424, 1.5970349312, 2.4544296265, -1.7936341763, -0.6051549911, 1.5142178535, -1.1078259945, + 0.3795293868, 1.7709084749, 0.4984016716, -0.2436304092, -2.2577059269, -1.245885849, -0.7088252306, 1.5962058306, + -1.9355672598, 0.6987320781, 0.3166677952, -0.861558497, -0.1896579862, -0.6173701882, -1.0844488144, 0.5718342662, + -0.5237622857, -0.4043986797, 1.4371533394, -0.5186876655, -0.8964678645, 0.9899360538, -1.3119916916, -0.7182676196, + 1.0389785767, -1.1774294376, 0.6187053919, -0.4993627965, -1.1766394377, 0.0940822363, -1.0231488943, -0.4538815022, + -0.6294190288, 0.5030683875, -0.2208803594, 0.9774012566, -1.0498013496, 1.1215320826, -0.2495442778, 0.3619700968, + -1.0616446733, 1.0567066669, 1.3423643112, 0.7119333148, 2.0674512386, -1.6267881393, 0.6471201181, 0.2160703689, + 1.3485805988, -0.1709989458, -1.2881512642, -0.3260785937, -1.8688436747, -0.1713963598, -0.2822999358, -0.7701655626, + 0.1642793864, -0.4175589979, -0.6222335696, 0.2136606127, 0.4244953096, 1.04510355, -1.6823191643, 0.0403030105, + -0.4710847735, -0.2437952608, 1.3693777323, -1.1758570671, -0.0542855076, -0.9699545503, -0.5364821553, -1.7010054588, + 0.2163471431, -0.2669135332, -0.3398927152, -0.0248095077, -0.4684832692, -2.017809391, 0.400156796, -0.6108651161, + 0.5783423781, 0.164952606, 0.8978267312, 0.7421654463, 0.4261821806, -1.0519768, -1.4087666273, -0.8967926502, + -0.6909884214, -1.0733422041, 1.3887276649, -1.5292494297, 0.6003373861, -0.3892106116, -0.0517769493, 0.0179459751, + 0.157114625, -0.5726046562, 0.0190555137, 0.5697455406, -0.8141471148, -0.3097047508, 0.4373070598, -0.3019420505, + 0.1362971067, -1.0670320988, -0.000081754, 0.8114110827, 0.40831846, 1.828209877, 0.1381276697, -1.9155849218, + 0.0719738081, 0.220882073, 1.2493988276, 0.3405856788, 2.0780653954, -1.255166173, 1.0017586946, -0.5354287028, + 0.8841439486, -0.5767771602, 1.1559445858, 0.3145794272, 0.1051806211, 0.6909182072, 0.7290110588, 0.1197143495, + -0.6287478209, -0.6085677147, -0.8197476268, -1.5091049671, 1.0208386183, -0.0439724736, 1.7148467302, -0.0321364142, + 1.3864095211, -1.0215556622, -3.0513429642, -1.1673578024, 2.185600996, 0.2588728666, 0.3434796929, -0.8460996151, + -1.9793503284, -1.1928198338, 0.9098986983, 0.4554537833, -1.0023721457, -1.8009947538, -0.6367038488, 0.9891266227, + 0.020365987, 0.3414032459, -0.4097161591, 0.2278744727, 1.220962882, 1.1159952879, -0.9623272419, -0.4903887212, + 0.4621538222, 0.2723306119, -0.9540486336, -0.2404303402, 0.3517660499, -1.4416646957, 0.4990543127, -0.7126743197, + 0.3536555171, -0.9577149749, -0.3402226269, -0.8734661937, 1.0238445997, -1.268478632, 0.2645486295, 0.2472764254, + 1.1231633425, 0.8844839931, -0.5912511945, -0.3987582028, -0.6692000628, -1.7035512924, 1.1779968739, 1.1480795145, + -1.961986661, -0.6322578192, 0.4063148499, 0.868581593, 0.1516608745, -1.1480426788, 0.03436362, -0.2617740929, + 0.834068954, 0.8000271916, -0.4284797311, -0.0311497673, -1.1331477165, 0.1529792249, 0.7315949202, -0.4204881787, + -1.7638682127, 0.6233843565, 0.14150922, 0.2131320089, 1.0914654732, -1.6148589849, 0.4392548501, 0.3568493426, + -1.3790297508, -0.1812242717, -0.4438568354, -0.5541661978, -0.4909126163, -0.9593079686, 1.086622715, 0.0711556524, + -0.6503744125, 0.3807986677, -0.0300570186, -1.6283313036, 0.6702497005, 0.2368342578, 0.606620729, -0.6736672521, + -1.0897010565, -1.1997205019, 0.291911006, 0.5207223892, 0.6099629998, 0.6813975573, 0.4636356533, 0.068745181, + -0.4502599537, 0.1851959527, -1.433814764, -0.4437556267, 1.4200047255, -0.6315543652, -0.774446249, 0.6045300961, + -1.2394708395, -0.2095934153, -0.3702944219, -0.6200354695, -1.3909845352, -0.3433581889, -0.9693596363, + -0.3587476015, 0.3847161233, -0.2518064678, 0.4357206225, -0.9091473222, 0.6839234829, -0.029562572, 1.4972803593, + -0.1460575759, -0.0939826742, -0.2217037976, 0.0946994647, -0.2410782129, 0.9098507762, -1.3256295919, -0.0817464665, + 1.3583462238, 0.7781915665, 0.0069436296, 0.5164428353, -0.0651496351, 0.7075184584, -1.4202232361, 0.2231310159, + -0.3650387228, 0.1650255471, -1.3219217062, 1.0231046677, 0.7444481254, 0.5359328985, 0.566653192, 0.3261220157, + -1.3667412996, 0.160564363, 0.2437143475, 0.4470121264, 0.3345755637, 1.5117784739, -1.4013890028, -0.358553499, + -0.2405987382, -1.2795827389, 0.3206909299, -0.4760054648, 1.4264730215, 0.279827565, -0.0359120257, 0.468708396, + -0.4645172954, -0.1489082575, 1.6419786215, 0.8950193524, -0.2498975992, 0.0254452918, 0.767909348, 0.397723794, + -1.2860594988, -0.343510896, 1.3776507378, -0.2499962747, 0.5837259293, -0.3566249013, -1.5012432337, -0.0366155952, + 0.6415373683, 1.7652125359, -1.3682287931, -0.0861081928, 0.0383691862, 1.2417683601, -0.1283382177, -0.1103384346, + -0.7885918617, 0.0254839975, -0.7123177052, -1.1390565634, -0.0729266852, 0.2223683745, -2.5684566498, 0.4270484746, + -0.0046181614, 0.0415315256, 0.6546118855, -0.9823287725, -1.3519179821, 1.2908511162, -0.5305488706, 1.7785286903, + 0.8555805683, 1.3566535711, -0.4564712942, -1.4938685894, -0.9814547896, -1.3854124546, -1.5733133554, -0.812942028, + 0.3343071938, -0.2484793961, 0.7299104333, 0.6596966982, -0.7074251175, 1.639279604, -0.7114089131, 0.3561543822, + 0.1788314283, -0.01024222, -1.5114012957, -0.0173943099, -1.072024107, -2.3937253952, -1.3889380693, 0.0471616276, + -0.4784292877, -0.8774627447, -0.7773531675, 0.5064339042, 1.4271920919, 0.6994634271, 0.3179759979, 2.0188155174, + -0.62578547, 0.4875732064, 0.974270165, -0.6120517254, -1.6027874947, -0.5442904234, -0.2421242595, 0.5398359299, + 1.3619903326, 0.7030728459, -0.4203302264, -0.0356382467, 0.4759574831, -0.3176399469, 0.9230871201, -0.7705651522, + -0.8988927603, 1.851706028, 0.6137269139, -0.1375556439, 0.7560847998, -0.7871061563, -0.8101333976, 0.9718251228, + -0.2960273027, -0.8531348705, -0.7449046373, -2.3861715794, 0.5155227184, -1.4067013264, 0.3101865947, -2.1656732559, + -0.4105100334, 0.4387335181, 0.6727346778, 0.2653877437, 0.9309439659, -1.1482447386, 1.7589145899, 0.429344058, + 0.6618949175, 0.6083560586, -0.7772499323, -0.2988936305, 1.9642839432, -1.344645977, 0.3042408824, -1.803396821, + 1.1037830114, -1.7535353899, -0.5489560366, 0.9455407262, -0.843342483, -0.1801532805, -0.4749929905, 0.2693964243, + 0.4919607341, 1.2626482248, -1.0708043575, 0.1030553579, 0.1843638122, -0.7110225558, -0.0900483355, 2.1595232487, + 0.1592033505, -0.9272395968, 0.9635785222, -3.7438845634, -0.7730277777, -0.9164265394, -0.2171987295, 0.0299481545, + 0.4585601985, -2.6037380695, 0.2609812319, 1.304089427, 0.9559362531, -0.041381672, -0.6852220297, 0.4935119152, + 0.7921469212, 0.1276420653, -0.1001019925, -0.0484789126, -0.5497506261, -1.6832387447, -1.543117404, -1.1059116125, + -0.1819771081, 0.1616688073, -0.5764904022, -0.988022089, 0.0783481523, 1.4437611103, 1.9365442991, -0.3549702466, + -2.2470059395, -0.4686661363, -0.998326242, 1.7535051107, 0.6303505898, -0.7734314799, 2.6364636421, 0.0392718092, + 1.5254333019, -0.6479625106, 1.609962821, 0.3199017942, 0.3757773638, -0.4623837471, -0.1848932803, 0.3996022344, + -0.0442292541, 1.3251973391, -0.442417264, 0.0063154404, -1.4659434557, 0.5882980824, 0.6704141498, 0.9195390344, + 0.5987154841, -0.6095600128, 2.0387501717, 1.5419700146, -1.3648542166, -0.9416725636, -0.5326945186, -0.6290355921, + 0.2064234316, -1.164329648, 1.3079528809, 0.478761375, -1.1614365578, -1.2261186838, 0.6149030924, 1.1901096106, + -1.7869648933, -1.7015125751, -0.0369055569, -0.1572385281, -1.8780126572, -0.1200147271, -0.4242606461, + -0.3192552626, 0.0104762856, -0.6464591026, 0.8706829548, 0.5600137115, 2.6534612179, 1.3147951365, -2.0153663158, + -1.6875379086, -0.645911634, -0.4426926076, 0.1987432837, 0.4108413756, -0.4009189308, 0.9362496138, -0.7191836238, + 0.6938658953, -1.7758921385, -0.1403557509, -0.022806596, 1.0006980896, 0.8325053453, 0.6643543839, 1.0108941793, + -2.3972070217, -1.1385048628, 0.4741702378, -0.6687298417, 0.4963333309, -0.7473987341, -0.386541158, 0.2450307906, + -0.8685840368, -1.5923013687, 0.0233582482, 0.8655768037, 0.943656683, -0.7575323582, 1.0158644915, 0.6127064824, + -1.7185145617, -0.4814927578, 0.0290120076, -1.8096933365, -0.8135496378, 0.5268061161, -1.374557972, 0.844942987, + 0.7756015658, 0.2198592126, 0.1512816399, 0.7091155648, 1.174185276, -0.5143500566, -1.6707895994, 1.2580791712, + 1.5318725109, -0.5002031326, -0.2448760867, -0.2390441149, -1.490323782, 0.6865671277, -0.3201767504, -0.0794070512, + 1.9951273203, -1.4163293839, 0.9918632507, 1.7666332722, 0.1555749178, -0.3725374937, -2.1025719643, -1.2156616449, + -0.883698523, -0.3397898972, 0.4215038717, 0.4887259007, -0.4905745983, -1.3774695396, -0.6583486795, 0.0738252997, + 0.7343323231, 0.4211414754, 0.1247600242, 1.7488490343, 0.2251959741, -1.0532218218, 0.4716623127, 0.5744453073, + -0.0024379981, 1.1637272835, -1.94810009, 1.4603103399, 1.5550012589, -1.2255028486, 0.6156579256, 0.6069850922, + 0.8603722453, -0.5207680464, 0.8478476405, -0.3461050093, -0.6320928931, -0.7256397605, -0.9042200446, 0.7228765488, + -0.0928905234, -0.7883547544, 1.6062039137, 0.0710300654, 0.5437248349, -0.4915961325, -0.1041649207, -0.3031794131, + -0.4425407946, 1.1392168999, -2.0505964756, 0.4079806805, -0.0800484493, -1.3515720367, -0.9124820828, -0.8583441377, + 1.2894556522, 0.5908492804, -0.5798185468, 0.0520669743, -0.1212026998, 0.4420488775, 0.6347669959, 2.2531759739, + 0.4614149332, 2.1107082367, -0.6364678741, 0.6796067357, -1.2275124788, -2.113713026, -1.4560955763, -0.1521469504, + -1.1474013329, -0.0936479792, -0.4342494607, -0.3847503066, 0.9745326042, -0.8003863692, -0.1759050786, 0.4681669176, + -0.2825888991, 0.570293963, -2.0764098167, 0.0134140672, -0.799105823, 1.5231801271, 0.3928492367, 0.808791399, + 0.1406501085, 0.2782938778, -1.205897212, 0.7704486251, -0.6398083568, 1.8859362602, 0.8982129097, 1.1188243628, + 0.034244068, 0.1872243583, 1.8391888142, 1.3006812334, 0.3444184959, 0.1678676009, -0.2385491282, 0.1145463064, + -1.568549633, -0.4964090586, -0.3101575971, 0.3440920413, 0.1293883473, 0.5067656636, 0.3827549219, -1.0888370275, + -1.4858487844, -0.9661257863, -0.7745360136, -1.4245500565, 0.139393881, -1.4260451794, -0.5082685947, 0.8763096929, + -0.6662014127, -1.2093539238, 0.7315164804, -1.1380810738, 0.0281808823, -0.9322289228, 1.2290621996, 0.730882287, + 0.1425308883, 1.4224876165, 0.7261432409, 1.126049161, -0.8474053741, -1.1105213165, -0.8556407094, -0.7260117531, + 1.1177033186, 1.1724927425, -0.179557398, 1.0290118456, -1.1191790104, 0.0396585315, -0.0047235782, 0.2664375901, + -0.5832667947, -0.8921521902, -0.8755141497, -0.9598096013, 0.4069607854, 2.1447017193, 0.3723194003, 0.3736964762, + -0.6830319166, 1.3127006292, -0.6640972495, 0.7430377603, 1.0540186167, 2.0303764343, 0.8735508919, -0.6355731487, + 0.5069352984, -0.95575279, 0.9533885121, -0.4849050343, -0.1885131001, -0.6945106983, -0.6633606553, 0.257712245, + 0.6968512535, 0.0700863674, -0.8694693446, -0.9572583437, -0.1153896451, 0.2002226561, -0.3849981725, 0.2202363312, + 2.0618686676, 0.3926514387, -1.5631883144, -1.2940770388, -0.5507266521, 0.731365025, -1.7164524794, -0.7593462467, + 0.3257178962, 1.1041924953, -0.6681020856, -1.2724117041, -2.1357870102, 0.356523782, -0.0748446658, 2.0107169151, + -0.8546269536, -1.1847459078, 1.8804349899, -0.1341653168, -0.5399327278, 0.6568149924, -0.6100254059, -0.0584002621, + -0.3279354274, 0.0255116895, -0.476526767, -1.3591419458, -0.1435545087, 0.5789028406, -1.7496489286, 1.4535236359, + -0.6286903024, 0.2937216759, 0.1816752106, 0.3662569225, -0.8155812621, -0.717700839, -0.635145247, -0.598746419, + -0.7643153667, -0.092450656, 0.0002173648, 0.4418594539, 0.284568131, 0.1451430768, -0.9784609079, -1.6784154177, + -1.2964258194, 1.5535236597, -0.793620944, -0.5138964057, -0.9194343686, -1.3460687399, 2.6226949692, 0.829631269, + 0.6559735537, 0.5372175574, -1.2835997343, -1.234891057, -0.9327340722, 1.3215962648, 0.4506095648, -0.1519411802, + -0.1253918707, 0.1870906502, 1.6497941017, 0.0869149938, -1.0887746811, 0.7199364305, 0.4501723051, 0.2700583041, + -0.4041815102, 1.0006670952, 1.3125792742, 0.6810870171, -0.1800761074, 2.4339106083, 0.1763603538, 0.8710671067, + -0.3742243946, 0.4617210627, 0.3632403314, -1.1402145624, 0.8772246838, -0.2340421081, -0.8595511913, 0.0905576646, + -1.4307808876, 0.5439644456, -0.0927907899, -0.6408239603, 0.613607049, 0.5124572515, -0.6934475303, -0.689656496, + 0.5295175314, -0.1667579859, 0.2426082194, 0.018985983, 2.2494912148, -0.2460813224, -0.2038732916, -0.6019621491, + -0.0026605215, 0.196095258, -1.1902012825, 0.4211482704, -0.4473219514, 0.4534853399, -0.3401862979, 0.151392445, + 0.3664656281, 0.2547777295, -1.0560954809, -1.913236618, 1.4109679461, 0.6244448423, 0.4116883576, 0.4919942617, + -0.639054656, -0.0430185869, 1.6317751408, 0.2780894935, 1.6450288296, -0.3439806104, -1.5669082403, -0.0530644134, + 1.5441375971, -0.4733426571, 0.67461133, 1.0411593914, 0.985576272, -1.7978531122, -0.9804763794, 0.605910182, + 1.1089842319, -0.8183146119, -0.9320350289, -1.1980115175, 0.1660242826, -0.752530396, 1.5922327042, -0.8294901252, + 0.9423011541, -1.8002551794, 0.0447457209, 1.4288845062, 0.5406267047, -0.115199551, 0.8838722706, -1.7344129086, + 0.5595968366, 0.4175852537, 0.6582928896, 0.7738341093, 0.7438519001, 1.0156049728, -1.3063168526, -0.9007453322, + -0.5195229053, -0.066014275, 1.7721335888, -0.5381574631, 0.0451898575, -0.8444939852, -0.0029482909, 0.9423898458, + -0.8007932305, 2.1239731312, -0.2745014429, -1.9707047939, -1.2178057432, 0.7433405519, 0.2328127027, 1.4669008255, + 0.198547855, 0.883330524, 0.4210582674, -0.6766483188, 0.7286726236, -1.7391421795, 0.4351043105, 0.6838805676, + 0.199822247, 1.5584337711, -0.7463527322, 1.087860465, -0.5838196278, 0.3922228813, -1.2806158066, 0.0529088899, + 0.3663826287, -0.1530306935, 0.0078097042, 0.3014991581, -1.7583640814, 0.5166698098, -1.0459570885, 0.3360862434, + -0.302154094, 1.6351559162, 0.2339851409, 1.3475879431, -0.281058073, 1.2364726067, 0.8393220305, -1.1669842005, + -0.9311234355, 0.307246536, -0.7316344976, 0.620942533, -0.4304316342, 1.0347040892, 0.3869737089, -0.8412460685, + 0.9965993166, 0.293193996, -1.5351545811, -0.2541728318, -0.5098071098, -1.9362185001, -1.0679433346, 1.2295447588, + -0.6092607379, -0.2998788953, -0.2101449221, 1.5696338415, -0.9006688595, 1.9490916729, -1.1761932373, 1.4566138983, + 0.7829972506, -0.9729502797, -0.6038942933, -0.3258980215, 0.364859134, 0.6088670492, 0.5756407976, 0.1295090169, + -2.058416605, 0.7405277491, -0.0565741882, 1.6712781191, -0.0073989523, -0.7615351081, -1.762571454, -1.6687066555, + 0.2233912647, 1.7904453278, -0.2203775346, 0.3719655573, -1.259683609, -0.1352416873, 1.6784518957, 0.9244667888, + 0.6470136046, 0.1950820833, 0.268650353, -0.316455245, -1.4811400175, -0.4500595033, 0.9400957823, -0.8417010903, + 1.203125, 0.1384577602, 0.714723289, 0.8561578989, 0.8689596653, -0.7192590237, -0.4665651917, -0.1493928432, + -1.8951672316, 0.9723851681, -1.4815393686, -0.3151030242, -2.1755998135, 0.3345840275, 0.4477573931, -0.8480839133, + 1.4286578894, -0.5938410759, -0.3036641181, -0.1643898785, 1.4175655842, -1.2077329159, 0.5321143866, -0.394600153, + 1.0930041075, 0.8004240394, 0.0015130466, -1.2983140945, -0.200617671, -1.0674712658, 0.6152316332, 1.3683578968, + 0.5303028822, -0.3842371404, -1.3599123955, 1.2266104221, 0.7833281159, 1.6608939171, -1.1905647516, -0.5298700333, + 0.9390087724, -0.727386415, -3.0896890163, -0.9112982154, -0.2719693184, 0.4283858538, 2.2000403404, 1.2904229164, + -2.8206224442, 1.5973047018, -0.3084849417, -1.2416521311, 0.3893934488, 0.9960338473, -1.6180120707, -0.7857273817, + -1.6723463535, -0.1164723262, -1.4589574337, -0.201991111, 0.2670248449, 0.934135139, -0.5450060368, -0.9017308354, + -1.1602119207, -0.9146684408, -0.4528957009, -0.7189208269, -0.8239266276, -1.4149652719, 1.007165432, -0.7333939075, + -1.248292923, 0.3368687928, 1.5294657946, 2.1932830811, -0.0322217532, 1.3643707037, -0.7223550677, -1.0060669184, + 0.4713765979, 0.037475802, -0.2954056263, -0.5196225643, -0.3418472409, 0.8694543839, -0.0366826206, -0.3693021238, + -0.0720364004, -0.3977731168, -0.2981844246, 0.3481273651, -2.2333576679, 0.1124164909, -0.5860416293, 1.2649736404, + 0.4698347449, -1.6995165348, -0.6768918633, 0.5547665358, 0.1519433111, 0.4794569612, -2.0995452404, 0.1126223803, + -0.5789268613, 0.7632908821, 0.6681728959, -0.1237390935, -0.2411789, -0.8700891137, -0.0535563789, 0.1604736447, + -0.2040840238, -0.3879729211, 0.3112916052, 0.7895922065, -0.0806431398, -1.9122922421, -1.2963095903, 0.9608740211, + -0.5996281505, -0.2180650234, -0.1556250751, 0.5601133108, 0.5118433237, -0.6297109723, -0.247744903, 0.4377675653, + 0.1655773968, -2.1302938461, -1.1546865702, 1.3413959742, -0.7347362041, 0.8989260197, 0.4398216605, -0.8333153129, + -0.5954267979, -0.4634758532, -0.0472172499, -0.1780685633, -0.6798447371, -1.1439967155, -0.0540322363, + -0.7338622808, -0.3657207787, -1.3311915398, -0.0009648965, 0.8482714295, -0.3821905851, 0.5203379989, -0.497880578, + -0.6867644191, -0.3023690581, -1.7219276428, -0.0706413612, -0.9097322226, -0.6544209719, -0.6343010068, 0.1573838145, + 0.8664366603, 0.7233697176, -2.0078625679, 0.2135981321, 0.4005902708, 0.3631705046, -1.0551964045, 0.1154454425, + -0.6361332536, -0.793640554, -0.8201953769, 1.526741147, -0.3820387125, 0.8344710469, -0.4640203118, -0.1984673291, + 1.1495521069, -0.2665902674, -0.3317551613, -2.1129162312, -0.9538705945, 0.7641342282, -1.5903077126, 0.8508225679, + 1.7642945051, -1.1222983599, 0.5385093093, 0.4542241693, -1.7904034853, -1.0321934223, 3.2340333462, 0.3957667649, + 1.8712517023, 0.1348981857, 0.3125168383, 0.2443830669, 0.4996775389, 0.2636229098, 1.9391344786, -0.4150807559, + -0.5804721117, -1.0143501759, 0.1284436435, 1.1321600676, 0.3555642068, -0.1672841161, 0.6568336487, 1.0217926502, + 1.132204175, -0.7075734138, -1.3878320456, 0.4098901749, 0.2341521829, -0.1374025643, -0.0444334671, 0.4156866968, + 0.9274237156, -0.554607451, 0.6505785584, -0.1995093673, -0.0293728597, -0.3378144503, 0.5294931531, -0.8031910062, + 2.080940485, -1.1738935709, 0.7713395357, -0.7774733901, -0.5353500247, 0.3451361656, -1.3199455738, -0.3418870568, + -1.0163743496, -1.1710753441, -0.2852978408, 1.0949852467, 1.3117394447, -0.8261899948, -0.61632514, 0.0279291794, + -0.4021877348, 0.5516725779, 0.5848386884, 1.0316517353, 0.3473063111, 0.6851702929, 0.8027648926, 0.5897445679, + -1.0397065878, 0.8500480652, -1.5022568703, 0.520131588, 1.5309634209, -0.0968860835, 1.6017364264, 0.3336514235, + -0.0345757678, 1.5534172058, 1.7362976074, 0.6443283558, 0.8172535896, -2.295019865, -1.5091173649, -0.199706912, + 1.0716969967, -0.1073218584, -0.7956750989, -0.6962655783, 0.4508700073, -0.3004487455, -1.1373023987, 1.7564595938, + -0.1807855815, -0.376059413, -1.2967089415, -0.6098486781, 0.4165080786, -0.8964832425, 1.774846077, -0.7647678256, + -1.5128406286, -0.3202617466, -0.2043563724, 1.0446738005, -0.7297920585, -0.0262035001, -0.1444185227, 0.384003967, + 0.2060625702, -0.2181037962, -1.129496932, -1.0868163109, 0.3352339864, 1.9930715561, 0.5076326132, 1.3730456829, + -0.002353942, -1.5736697912, -0.3311335146, 0.9903514385, 0.0521080866, -2.4414179325, -2.5822451115, 0.1565915942, + 1.4188001156, 0.7368789911, 0.2345260978, 1.0152734518, 2.2886154652, -1.0148390532, -0.3122152388, -0.2702304125, + -0.5222117305, 1.4889755249, 0.5128302574, -1.7104084492, 0.1142061651, -0.2926707566, -0.8836719394, 1.8603035212, + 0.1356332749, 0.8755128384, -0.9803749323, -0.229341656, 0.2006159127, 1.7615724802, 0.3264065087, 0.6724275351, + -0.0469790995, 3.1880333424, 0.4425591826, -2.3789470196, -2.432087183, -1.5881433487, -0.4209427834, 0.4819173217, + -0.5247082114, -1.5172423124, 0.8938916922, -1.6846462488, 0.244619146, -1.0680624247, -0.3203495741, 0.0754074827, + 0.9786596894, -1.003115654, -1.455915451, 0.3935267925, -0.384223491, 0.4690336883, -1.0834065676, 1.4030132294, + -1.4369273186, 1.1485811472, 1.448828578, -0.9468003511, -0.5519796014, -0.4509304166, -0.4519639015, 0.0976786837, + -1.9000874758, 0.795800209, 0.1177812293, -0.3470512629, 0.017277658, 0.8916116953, 0.1383883506, 0.1076137498, + -0.1316533536, -1.9620102644, -2.0274169445, 1.532495141, 0.7383908629, -1.1564779282, 1.5768051147, -1.4502425194, + 0.9668387771, 0.3540835083, 3.4085419178, 1.9100345373, -0.8650856614, 1.4155201912, 0.5690464377, 0.5973732471, + -0.8678830266, 0.8286939859, -0.235162735, 0.9233389497, -0.5177605748, 0.4496781528, 0.080087252, 0.2445594221, + -0.2652956247, 2.1359424591, 0.1638048589, -0.7652742267, -0.8763234019, 0.3231536448, -0.6016790271, 0.280115366, + 0.8367733955, 0.5688657761, 0.6027054191, 1.1826387644, 0.0957681388, 0.1674305946, -0.1956560016, 0.5108280778, + 1.0816714764, 0.6208047867, -0.1561427861, 0.8358264565, 0.9209582806, -0.8191552162, -0.1509196013, 0.8101909161, + 1.2557537556, 0.2925243676, -0.0419176333, 1.1210883856, -1.0228914022, -0.1098661944, -0.8591143489, 0.2410670966, + 0.9973797798, -1.4664530754, -0.0980027616, 1.8604106903, -0.6354730725, 0.2107730508, 0.5374374986, -1.1003706455, + 0.8711256385, -0.6260376573, 0.2263965756, -0.0102861263, -0.1871914864, 0.8020673394, 0.5475625992, 0.2951956689, + 1.2020192146, -0.4511943161, 0.6142093539, 0.0216287971, 1.3507753611, -0.3723137379, -0.1512116939, -1.7927660942, + -0.4930469692, 0.6896463633, -1.8515053988, -1.6282465458, -1.2689808607, 0.3326217532, 2.13128829, 1.7744779587, + -0.8050757051, -1.5977858305, -0.3082677424, 0.1215020418, 1.4367951155, 1.2268460989, -0.0081329355, -0.5573827624, + 0.1035985723, -1.2760721445, -1.1780765057, -1.2280064821, 1.1160129309, 1.7673761845, 1.733494997, -1.7602155209, + 0.5039381385, -0.3720277846, 0.3963406086, 1.0447177887, -0.8420517445, -0.0861799866, -0.1530893594, 0.2599826753, + 1.1811122894, 0.553283155, -1.3378735781, -0.8013755083, -0.8412433267, 1.0781079531, -0.00289982, -0.6660804749, + -0.7412942052, 2.3283331394, -0.4305628836, 2.7005894184, -0.6134419441, -1.0312664509, 1.0619452, -1.1738936901, + 1.284637332, 1.7262413502, 1.3725773096, -0.7013794184, -1.3772867918, 0.4172764719, 0.4020915329, -1.1206417084, + -1.2978309393, -0.0802910849, 0.9490975738, 0.0574220717, 0.161134243, 0.6615610719, -1.6403830051, 0.22588256, + -0.2138030678, -1.7920988798, -1.5084474087, 1.6496242285, -1.0713797808, -1.890737772, 0.0772534534, -0.233731091, + 0.0140136406, 0.5051288605, 0.466483295, 0.8642095923, -1.8167469501, 1.0395417213, -1.1637365818, 1.1356519461, + -1.7042986155, -0.0973814875, 1.1059724092, 0.6865385175, -0.0097261248, -0.0064713955, 0.2397290915, 0.4610339105, + 2.3903193474, 0.5248602629, -0.8353090286, 1.6538916826, -0.5744239688, 0.4300434589, -1.45135355, -1.2397629023, + -0.9852696657, 0.1993034035, 0.0661344454, -0.5709816217, -0.0929837227, 0.2432375997, -0.0583449788, 0.0009275326, + 0.8209046721, 0.05188822, 0.8052539229, -1.6794208288, 0.217873469, 0.7934340835, -0.891541779, -0.9696401358, + 0.0556026287, 0.7279754281, 0.4486949742, 1.3063867092, 0.0655736998, -0.5748510361, 0.0804484934, -1.2538518906, + 1.0344552994, 0.0385405272, 0.1673927009, -0.451433897, -1.3391981125, -0.3614654243, 0.9321334958, 0.4562244713, + 0.2335039377, 0.1003533304, -1.6953806877, 0.1109338477, 0.438850224, -0.1420196295, -0.5670718551, -0.4239734113, + 0.6679923534, 0.1954314113, -0.7743871212, 0.789758563, 0.2001348287, -1.4090903997, -0.6529703736, -0.5033426285, + 0.8819975853, -0.8331340551, 0.4697431326, 0.1163358986, 0.7791193128, -0.4779369533, 0.3048064709, -0.594065547, + -0.4552982152, -0.4650419652, 0.0361061431, 1.5899168253, 0.0063533471, 1.6877865791, 0.051595144, -0.9018155932, + 1.231910944, -0.6424393058, -0.256829381, 0.692933619, -0.3502320945, 1.4825685024, 1.3803684711, 1.1104739904, + 0.6726384163, 1.6660864353, -1.1913731098, 0.4051263034, -0.3095752001, -1.2381680012, -1.6911195517, 1.1668710709, + -0.6490058303, 0.458401531, -0.9608908892, 0.0266461428, -1.2123868465, -1.4942896366, 0.1524978429, -0.63950634, + -0.3380450904, -0.9216715693, -0.0510670282, 1.1863936186, -0.624769032, 0.3869996667, -0.5245535374, 0.3170322776, + -1.0178136826, -0.174255982, -0.1370685846, 0.8142974377, 0.7342265844, -1.9699764252, 2.2751204967, -0.3226063848, + -0.5424374342, 0.6009609699, -1.75877285, -1.5937917233, 0.9980217814, 0.480889529, 0.5623027086, 0.3096584976, + -1.2413680553, 0.0726389959, -0.2213159949, 2.1800575256, -1.4602934122, 0.0018683164, -0.1173354015, -1.0309307575, + -1.3381360769, -0.7076413631, -2.1738369465, 0.683737874, -0.7091113329, -2.7662103176, 0.760804832, 1.0504329205, + -1.4428687096, -0.7895605564, 0.7236565351, -1.1905863285, -0.6919526458, 0.8573622108, 1.5371603966, -0.9198681116, + 0.7844922543, 0.6338860393, -0.4500072896, -2.0559315681, -2.0172803402, -1.2834616899, -0.3556898534, 0.6204849482, + 2.3478055, -1.3467277288, 0.1222354546, -0.2214947045, -0.2462989539, -0.0867773294, 0.6118643284, 0.6414287686, + 0.4616425931, -0.1879353225, -0.3813198209, 1.3266900778, 0.4950915277, -0.8527886271, -1.9915175438, -0.02681618, + 0.2655802965, 0.3149074912, 1.0536828041, 0.8504412174, -0.7472555041, -1.5911126137, 1.3834769726, -1.4433643818, + 0.6882103086, -1.4758917093, 0.8962612748, -0.6082796454, -0.8149115443, 1.3695408106, -1.9525241852, -0.5935515165, + 2.1671218872, -0.9892462492, -0.2221836448, -0.2219780684, 0.9403944612, 0.1978086531, -0.7817671895, -0.4124997258, + 0.3687230051, 1.0968439579, -1.8594348431, 0.0029549592, 0.1101333052, 1.5394915342, -0.0038964562, 1.0981504917, + -0.0400299132, 0.2016086131, -1.3140232563, 0.2941615582, -0.7528982162, -0.0452784672, 0.7580948472, -1.3945977688, + 1.3409752846, -0.3101814091, -1.2464029789, -1.1343907118, 1.7912290096, 0.7197954059, -0.501552701, -0.1126659065, + 1.1124942303, 1.3593585491, -1.0211582184, -0.766172111, -0.6488007903, -0.9884676933, 0.7920768261, 0.5087880492, + 1.3648190498, 0.6742984653, -1.6158971786, -0.802767396, 0.2757093608, 0.2329666018, -0.625159204, 0.0634803176, + -0.1018172055, 1.5068968534, 0.6900904775, -1.7025721073, 0.3553458452, 0.3871901035, 0.9579328299, 0.7569516301, + 0.7862011194, 1.3912926912, -0.1798933148, -0.3273005486, -0.3807692528, -0.6068280339, -1.0164443254, 0.7183098793, + -0.3550116718, -0.0208350029, -1.5521923304, -1.1644581556, 1.0302523375, 1.1733825207, 0.2134277225, 0.0292529687, + -0.5484084487, -0.3583379388, -0.8931321502, -0.1975669116, 0.2763205469, 1.1366759539, -2.0308594704, 0.3366666138, + 0.3184001446, 0.4373573661, -0.8740926385, 1.0525960922, -1.2406895161, -0.567971766, -0.58529073, 1.1207735538, + 0.4359603524, -0.8621008396, 0.2411166579, -0.1937544495, 0.6315796971, -0.4637977481, -0.8728907704, -0.3243234754, + 0.3536755145, -0.243192479, -1.2344973087, -1.1073101759, 1.7516149282, -0.42013219, -0.6599223614, -0.6240724325, + 0.0641648844, 0.8778529763, -0.7815441489, 0.850804925, -0.869068265, 0.9813565016, -2.0868430138, -1.1037631035, + -0.1131165251, 0.0414229818, -0.8837306499, -1.4935542345, 1.1044009924, -3.1893181801, 0.5092691183, 0.4799568355, + 1.3159337044, -0.0970403627, -0.2791163325, 1.7901148796, 1.5886393785, -0.3469516039, -0.9854775667, 1.3777000904, + -0.4683577418, 1.6312767267, -0.5955067277, 0.6797708273, 0.6795912981, 0.5310679078, -0.8304234743, 0.7193893194, + -0.0236661416, 2.5271956921, -0.7473905683, -1.0720716715, -0.1273948997, -1.3011174202, -1.6902400255, -0.417000711, + 1.1451983452, 0.887558639, -1.9904561043, -0.6132237911, 0.0021884013, -1.0157800913, -1.2629107237, -1.6704556942, + -0.9015039206, -0.748760581, -0.0734295398, -1.4195762873, 0.9139781594, 1.6136165857, -0.3155820668, -0.5592501163, + 1.72057724, 0.1843333095, -0.2459741086, 0.7138553858, 0.9178287387, -0.3423841894, 0.6098057628, 1.5959429741, + 0.6128612757, -0.6838819981, 0.6335126162, -1.2277721167, 0.0185308941, -0.86067909, 0.1154111698, 1.496524334, + -1.1527279615, -0.6795991063, -0.9856798053, -1.2678070068, -0.4434808195, 0.0805942714, 0.2353551388, 0.0121626621, + 0.556168735, -0.0758090466, 0.144815132, 0.2649245858, 0.7526773214, -0.2883499265, 3.2922325134, 1.245164752, + -0.6571530104, 0.7045717239, 1.0751260519, 0.289665848, -0.068431206, -0.7031256557, -0.7291713953, -0.4636211991, + 0.5477852225, 0.4574085772, -2.863710165, -0.3515471518, -0.6543455124, 1.0587671995, -1.0377566814, -0.1081912965, + -0.7057687044, -1.2898498774, -1.64016366, -0.0102215903, -1.6310093403, -0.6036027074, -0.3954981267, -1.00301826, + -0.6082266569, 2.5081093311, 1.6789019108, 0.2176964432, 1.2520422935, -0.4151733816, -1.2843372822, -1.0400305986, + 0.3440242708, -0.4483019412, 0.6690663099, -0.7175396681, -0.145840764, 2.2244884968, 0.1947859079, 0.1055293828, + -0.6040461063, 0.8576923013, -1.5997809172, 1.8376449347, 2.8909277916, -0.5177230239, 0.2298939377, 1.8100821972, + -0.5709523559, -0.5115388036, 1.2967069149, -0.5621591806, -1.1462398767, -0.9591106772, -1.688269496, -0.7014160156, + 0.6921666265, -1.1444196701, -0.1640264839, 0.4573389292, 0.5338413119, 0.8252105117, 0.1567942351, 1.4680320024, + -0.2286765873, -2.0002055168, -0.6564577818, 1.9003719091, 0.4424801469, 0.4283055365, 0.6784015894, -0.9360645413, + 0.5108249784, -0.0562780872, 0.0913101286, -0.8051065207, -1.8382200003, 1.4490640163, 0.5964669585, 1.4912917614, + -0.3538664877, 1.151913166, -1.2095607519, 0.6885273457, -0.0599056147, 0.8238558769, -0.0441347621, -0.9308155775, + -0.712208569, -2.2147786617, 1.1632386446, 0.6279171109, -1.3401852846, -0.9253047109, 1.6279819012, 0.5150529146, + -0.6503204703, 0.1271840185, -0.1690019965, -0.5984864831, 0.5934988856, 1.3468483686, -2.3228442669, 0.3811374903, + 0.0807556435, 0.4608016312, 1.1064083576, -0.9534149766, -0.5410642624, 1.6721212864, 0.3387215137, -0.5848330259, + 0.1684350818, 1.1708821058, -0.0112401946, -0.0421408676, -0.0110325404, -0.0399069786, 1.8626705408, -0.3295717239, + 0.2178692967, 0.3128709197, -0.6914327145, -0.0489474349, -0.4623219073, 0.6858608127, 0.4037072062, -0.4837623537, + -1.6117572784, 0.0941191539, -0.6782262921, 1.2615525723, -0.2805505693, 2.6711010933, 1.3798089027, -1.1973799467, + -0.4020443559, -0.5639002919, 1.5455411673, 0.6903855801, 0.9709954858, 0.0853693932, 1.207965374, -0.1136911586, + 1.19851017, -0.8023996949, 0.8236210346, -0.7027028799, -0.5922062993, -2.278396368, -0.3009352088, -0.7893054485, + -0.2613692284, 1.8687489033, 0.1451711506, 1.1809588671, 1.4143635035, 0.2772610784, -0.374976933, 0.6385892034, + 0.7431727648, -1.3622537851, 1.3739572763, -0.9690158963, 1.0907326937, -1.2023899555, 1.2161438465, 1.5248703957, + -0.1389713138, -0.3804358244, -0.109330222, 0.5503053069, -1.3575862646, 0.4582281709, -1.1639021635, -0.3647545874, + -0.7115260959, 1.4336994886, 0.2221960723, 2.0658452511, -0.2943881452, -0.7061772346, 0.6280207634, 0.5662272573, + 0.3857337832, -0.4284617901, -1.3776395321, -0.6398698092, 0.4830209613, 0.9864068627, -0.7793473601, -0.4055784643, + -0.5901540518, -1.5036782026, 2.4848642349, -0.3595902622, 0.4562184513, -1.2775880098, -0.4926495552, -1.4293605089, + -1.3942863941, 0.7871758938, -1.9546544552, -0.9582464099, -0.8009232283, -0.3317953348, 0.5323982239, 0.4935196638, + 0.8553711176, 0.1533751488, 0.9288468957, 0.182693854, 0.8980613947, 0.4672872722, -0.0300932415, 0.3488621712, + 2.1993985176, -0.3082002103, 0.6237960458, -0.5904917717, -0.5733503699, -1.4770421982, -0.3424594402, 1.8895410299, + -1.0194392204, -0.7236206532, -1.3778822422, 1.0129799843, 1.1487203836, -1.0671883821, 0.8054333925, -1.6088992357, + -0.9679784179, 0.4632321298, 1.293644309, 0.6811715961, 0.0065504359, -1.3251696825, -0.5823521614, 0.3334719539, + -1.1553093195, 0.6754829288, -0.6283892393, 0.0070697991, -0.1301544905, 0.000015907, 1.6803572178, 1.0456736088, + -1.2322541475, -1.7359474897, 0.8063043952, -0.3912761509, 1.4771649837, -0.3736453354, 1.5715459585, 1.1237367392, + -1.5193575621, 0.5520567894, 0.5154913664, -0.0857104436, -0.9226989746, -0.1511355489, -0.1532225013, -0.4101878107, + 2.1041259766, -1.2773672342, -0.4122236669, -1.2621785402, -0.644549489, 0.2983115911, -0.4472069144, 0.0983226672, + 0.228484869, 0.4287489355, -0.297319144, -0.8167265654, 1.2091214657, -0.4534170032, 0.9312779903, -0.3093512654, + -0.3528625667, -0.0741263479, 1.0887343884, -1.2669620514, 0.3354581296, 0.004424131, 0.3022244275, 1.1900383234, + 0.2975670993, 1.4324852228, 0.6217397451, -0.5294061899, 0.4970742464, -0.5087625384, 0.1304465979, -0.1666449457, + 0.5193110704, 0.8491689563, 0.5580003262, -0.5960376263, 2.3947246075, -0.5828321576, -1.249351263, 0.7954925895, + -0.5065029263, -0.5937213898, 0.9579040408, -0.0251192842, -0.5465407968, 1.1391458511, -0.4674501121, -0.1967873126, + 0.2859996259, 0.983766973, -0.966819942, -0.113345392, -0.2571675479, 2.5318741798, -0.5155376792, 0.8728454709, + 0.0778044462, -3.1305611134, -0.4914603829, 1.1896528006, -1.4559942484, 0.3755713403, -0.5113667846, -0.4030328989, + -0.8139418364, 1.3834196329, -0.1454866529, 0.284616977, 1.1209895611, 0.8712860346, -0.0718860626, -0.6956607103, + -0.445933044, -0.4794711769, 1.5473222733, 0.0038444141, -0.9808133841, 0.2412267625, 0.9256925583, -0.5301594734, + -0.4780997336, -0.681268394, 0.5242022872, 0.1786995083, 0.8638377786, -0.3517528772, 0.5365935564, 0.5407190323, + 1.1510950327, -1.0237739086, 0.6385636926, 2.2565796375, 0.7124504447, -1.9051090479, 0.5709059238, 1.9324462414, + -0.8584792018, 0.8580051064, 0.2227552831, -2.1613814831, -0.2940069735, -0.1814101785, 0.7617862225, 0.6633594036, + 0.1448772103, 0.4526188672, 1.650875926, -1.7932395935, -1.7927554846, -1.298722744, -3.7009484768, 1.4530611038, + 0.2657386363, -1.1115087271, 0.3476705849, 0.9187952876, -1.2118660212, 0.9229725599, 1.2597514391, -1.9153442383, + 0.4390523732, -1.1919585466, 0.2263162732, 0.8045522571, -0.8975812793, 0.1102162153, -1.7435343266, -1.5475306511, + 0.1274931878, 2.3257565498, 0.2937721014, -1.1089141369, 0.5591292381, -0.3039319515, 0.7630262375, 0.2723177671, + -1.6435691118, -1.1236854792, 0.1609627306, 0.6847237945, -2.4690279961, 0.0209366865, -0.53102386, 0.4430907667, + -0.3956150711, 2.5748353004, 0.9656668305, 0.5004914999, 0.4974248707, 0.1869066209, -0.3793111145, -0.5843949914, + 1.0160140991, 1.0422772169, 0.0353021547, -0.2838065624, 2.4264302254, 0.1781947762, -1.4493917227, -1.2831250429, + -1.2559127808, 0.8513959646, -0.47084409, -0.9816243052, -1.4453076124, 1.064050436, -2.4597752094, 2.495146513, + -1.321087718, -0.3973611891, 0.6279271245, 1.2438503504, -0.8696066141, -1.6361762285, -0.0915040895, 0.5303424001, + 0.1272949874, 0.6879992485, 0.650703907, 1.67504251, -1.7682852745, 0.4391796291, 0.0041834023, -0.2630576193, + -1.8533036709, -0.8588609695, 0.1978735924, -0.7241343856, -0.4095613658, -0.6204192638, 0.280904144, 0.0266254898, + 0.5631239414, -0.0666484684, -1.3585243225, 0.1720818728, -0.9857338667, 0.6432245374, 0.4694710672, 0.3492645621, + -0.5567824244, -0.4697691798, -0.4117129147, 2.1153721809, 0.5442541838, -1.6541137695, 2.1774716377, -0.1963181496, + -0.8331007361, 0.7331581712, -0.0479035601, -0.4869109094, 0.6976183653, -0.1689549834, 0.6171053648, 1.2108881474, + 0.5635103583, -0.8354082704, 1.2755782604, 0.9359452128, 1.2179498672, 0.2265103161, 1.6606619358, 0.5011734366, + 0.1251170188, 0.2605842352, -1.5394775867, 0.4511664212, -0.2313937992, 1.1197661161, -0.1140006483, 0.3820356131, + 1.3873690367, 0.6571901441, 0.5457989573, -0.6308066845, -1.1354978085, -2.4026119709, -0.3027979434, -0.5020709634, + -0.2321306318, -0.020123871, 0.9409797788, 0.7256790996, 1.3103921413, -1.0225174427, 0.8154883385, -1.143021822, + 0.5008414984, 0.3574302495, 0.0495680012, 1.5883718729, -0.1069783717, 0.1745323092, -0.0496963039, 1.0220882893, + 0.4006874859, -1.0913971663, -2.329105854, -0.690020442, -0.9169560671, -1.1179387569, -1.0036914349, 0.2173535079, + 1.079076767, 0.0816364065, 0.2541635036, -0.8011046052, 0.4594263136, -0.6509816051, 1.1677899361, -0.347751379, + 0.5618755221, 1.1921788454, 1.5922267437, -0.2455349416, -1.0317528248, 0.2817627192, -0.835185349, 2.2162134647, + 0.373724103, -0.9866889119, -1.3697648048, -0.1978318542, -1.427968502, 0.1537464261, 1.1027641296, -0.4549758434, + 1.304069519, 0.951725781, 1.3341605663, -0.5766361356, 0.454246521, 0.6612707376, -1.21492064, 0.7250176668, + 1.0353204012, -0.3413012028, -1.3613491058, 0.4005934596, -0.1110523567, -0.0788928047, 1.1674675941, -0.3902478814, + 0.8044789433, 0.7681032419, 0.0321332254, -0.2218496799, -0.8551516533, -0.4030755162, -0.0721132234, -1.2544465065, + 1.4844565392, -0.5042630434, 1.1852766275, -1.2150322199, 2.2204818726, -1.1828657389, 0.7846149802, -1.9904559851, + 0.1393995136, 0.6561467052, 0.6043061018, -1.0907354355, -0.7484697104, -0.7126812339, 0.8230614066, -1.3216540813, + 0.132691592, 1.2171856165, -0.4447000027, 0.8073532581, 0.6256611347, -0.060797669, 0.7808696032, 0.3649677634, + 0.5778753161, 0.4065142274, -0.5495318174, 0.4771209359, 2.5231893063, 0.6165393591, -0.5275948644, 0.5816348195, + 0.512090683, -0.7348868251, -0.4592056274, 0.4749583006, 1.1358423233, 0.6339197755, 1.2536251545, 0.0191743113, + 1.3371372223, 0.69080621, -1.5238791704, 0.7582221627, -2.0854206085, 1.0246943235, 0.3916818202, -0.3441234529, + -0.3393303752, 0.5980219245, 1.7809047699, -0.0322760791, -0.5638660192, 0.7236633301, 0.1639522463, 1.5012469292, + -0.3719091415, 1.1622062922, 2.8788545132, 0.0829108357, -0.000399607, 1.1071796417, -0.9313130379, 0.1179228798, + -0.6248297095, -0.6864803433, 0.3658074439, -0.1976805627, -0.7697430253, 1.1433596611, 0.4378886223, 1.0920422077, + -0.1473139822, -0.4550720155, 0.8509523273, -0.4368683994, 0.1370265186, 0.9994106889, 0.0470677242, -1.2024868727, + 0.7732259631, 0.7193604708, -0.4950317442, -0.6972939372, -1.1340928078, 1.4360136986, -1.0777835846, 0.6327699423, + -0.7165985703, -1.7260651588, 0.7511957884, -0.8365247846, 1.4378730059, -0.2593916655, -0.7531266212, -0.0018816765, + 0.2780501246, 0.3728078902, 0.5840899348, 1.1903779507, -0.7974692583, 0.6395269036, -0.1412059069, 0.5012361407, + -0.1481624842, -0.0530277118, 0.2532734871, 0.7361589074, -0.550516963, 1.3500739336, -0.7229986191, 0.5972332358, + 1.5588985682, -0.9929527044, 0.6563365459, 2.0401813984, 0.2912432551, -1.0593951941, -0.7136363983, -0.4101233482, + -0.8217135072, -0.9647257328, 1.5899295807, 1.4830676317, -2.0082218647, 0.6201471686, 0.0921110585, 1.0209305286, + -2.2872138023, 0.2827239335, -2.0732119083, 1.1393668652, -0.8216959834, 0.2826004326, 0.0577638298, 1.0376316309, + -1.2894252539, -0.5568271875, 0.3712979555, 1.0854558945, 1.6734513044, -0.2837608159, 0.780890286, 1.2088090181, + -0.3496015966, -1.8581924438, -0.3988831639, -0.4860283136, 0.5964819193, -0.1913231909, -1.8144276142, -0.9861682057, + -0.9875866175, -0.3508193493, -1.0703758001, 0.9739978313, 1.7451748848, 1.1622909307, 1.2399636507, 0.18382065, + -2.1057317257, -0.386880964, -1.4580152035, -1.958309412, -0.521422863, -0.8149047494, -0.2598052323, -0.0679654256, + 1.523608923, -1.8181490898, 0.7602464557, 0.2036284059, -0.6710840464, -0.4183948934, 1.6409194469, 0.0934851244, + -0.9035621285, -0.1599463671, -0.2006375492, -0.1909182221, -0.9695960283, 0.5366060734, 0.0499979891, -0.5023054481, + 1.6040503979, -1.2374203205, -0.2361531258, -1.3638973236, 1.9122620821, -0.8687421679, 0.5375559926, 0.4242394269, + -0.5340645313, 0.702186048, 0.2912759781, -0.4078489244, -0.0786173418, -1.5945433378, -0.3502337337, 2.0544710159, + -0.19283849, 0.9104574323, -0.0862179101, 0.6111246347, -0.35344401, 0.5634724498, 0.4857985377, 0.2631002367, + 1.4814050198, 1.1656149626, 1.1763496399, -1.2619029284, 1.0174994469, 0.8297733068, -0.5920416117, 1.5649130344, + -0.7932690978, -1.9636081457, 0.0073007345, 1.7777563334, 0.4939030111, -0.8862183094, 0.5388250947, 2.3175821304, + -0.6583781838, 0.0406383574, -0.677446723, -0.0744541883, -0.6628022194, -0.7723457813, 0.8113358021, -0.0109207612, + -1.4630174637, 0.8977974653, 0.0017468558, 0.8730773926, 1.8256112337, 0.9446329474, 1.9473477602, 0.5063759089, + -0.2418232411, 1.68757236, 0.5409396887, -1.7663731575, 0.7723557353, 0.790448308, -1.1151059866, 0.6893996, + 0.0964727402, 0.3555314541, 2.890386343, -0.2023495734, 1.1651166677, -0.1074468717, -0.4425264895, 0.3537662923, + -0.5301949382, -0.1266164333, 0.1925617903, 1.4034749269, -0.4170812666, 0.2439171225, 0.6235732436, 0.0569755919, + 0.4600847065, 1.2430694103, -0.215076685, 0.5950499773, 0.1923431158, -0.1020159572, -0.91606462, 0.8229887486, + 1.0482641459, 0.5558660626, -0.7286831141, 1.710979104, -1.3896939754, 0.7022241354, 0.7677382231, 0.8328258991, + -0.7697517872, 0.6147429943, 2.0839247704, 0.7161874175, -0.3919250667, 0.905344367, 0.0932821408, -0.7115653157, + -0.2126543075, -0.8772642612, -0.1721208841, 1.3694014549, 0.251131773, 0.1415636986, 0.0112932771, -0.6726903915, + -1.6037570238, -0.5378059745, 0.0845245272, 0.7646923065, -0.2101514488, 0.9166517854, 0.4953337014, -1.5049014091, + 1.1143501997, 1.6012240648, 0.6021217704, -0.9676260948, 0.567297399, -0.0398906879, -0.2725612223, 0.6513987184, + 0.5207162499, -1.9729640484, 0.8367348313, 1.0528236628, -0.4983050823, 0.5411375165, -0.6223208308, -0.5388869643, + 0.9614911675, -2.0136291981, 2.0114109516, 0.223733142, 0.7709437013, 0.1642037779, 0.977611661, -0.2966648638, + -1.1799397469, 0.7032052279, 0.0894018561, 0.7504652143, 0.3706242144, 0.504791677, 0.6028758287, 0.4940436482, + 0.8593719602, 0.5868232846, 0.1310377866, -0.3590817153, -0.8620396852, 0.6448566914, 0.6952871084, 0.9641913176, + 0.1289675683, 0.9945142865, -0.3077834547, -2.1486518383, 1.8851884604, 2.6745195389, -0.3878851533, 0.3051368296, + -1.3988252878, -0.6323857307, -0.8161635399, -1.3922702074, -0.6827468276, -0.2562257946, 0.5322270989, -0.7437602878, + -0.2868638039, 0.7098515034, -1.4383655787, -0.6667670012, -1.3716266155, -0.1098348424, 0.7378181219, -0.0879292637, + 1.1370954514, 1.7925657034, -0.2012682259, -0.269438833, -0.4670928419, -0.5821979642, -0.7644075751, 0.6695444584, + 0.0306869764, -1.6800422668, -1.6340225935, -0.4223179817, 0.7865099311, 0.1305941641, -0.7552067041, -0.0254859049, + 1.9027297497, -1.3717647791, 0.7811303735, -0.2215402573, 2.1291007996, 1.1312514544, -0.2409127802, 0.5062365532, + -0.5534172058, -0.3004655242, -0.5346511602, -0.8108330965, 0.3282672167, -1.0185667276, -0.3533863127, -0.8215651512, + 0.2005594671, 1.8420407772, 0.3635246158, 0.786136508, -1.059717536, -0.1873623729, 0.7724383473, 1.2314850092, + -0.7266256213, -0.256904155, 2.0182263851, 0.4881033897, 0.3779078424, -1.1142752171, -0.5767669082, 0.1944286525, + 2.3854238987, 0.786962688, 0.8664147854, -1.8784008026, -0.59552145, 0.6883810163, -0.6199914813, -1.1991696358, + 1.2152301073, -2.407053709, -1.0307068825, -0.664309144, -0.5183378458, -0.4899657965, -1.8663284779, 1.7655661106, + -0.754704535, -1.4823474884, 0.0760180503, -0.1749891788, -0.379602313, 0.0475712158, 1.738478303, -0.2914048135, + -0.1437018216, 0.1325060278, -2.3676879406, -0.2258290648, 1.6418195963, -0.7734972239, 0.7461740971, 0.6074157953, + 0.411765337, -0.6067041159, -1.6472831964, 1.7200328112, 0.0232646484, 0.4374954998, 1.2455363274, 0.58944875, + -1.7584183216, 1.0120782852, 1.0967348814, 0.0198814012, 0.3985802829, 0.6743020415, -0.8145176768, -0.7799610496, + 0.377789259, 1.0087720156, 2.0344851017, 0.0204913002, -0.0241909269, -1.8100771904, 0.779527545, 0.2824576795, + -0.673760891, 1.0618784428, -0.373511523, -0.1141227409, 0.050863523, 0.1573044062, -0.7637298703, 0.1603048593, + 0.1740360856, -0.072232306, 1.0070261955, 1.3884991407, 0.5985660553, -0.5918496847, -2.4490859509, 0.3502865136, + -0.7734159231, -0.7966606617, 1.0198645592, -3.6166062355, 1.3282010555, -0.9895777106, -0.0881013423, -0.5323204994, + -1.1653339863, -0.9234332442, 0.1528675258, 0.6556922197, 0.268760711, 0.277961731, -0.4949930906, -1.0904607773, + 0.9958393574, 0.6449023485, -0.0139402952, -0.6758316755, 0.0389272645, 0.2130638659, -1.5142279863, 0.5219237804, + 0.6738876104, 0.0340359621, 1.2885986567, 0.3472016752, -1.3768179417, -1.1709387302, -0.1141757742, 0.3047106266, + 0.3039871454, -0.5379764438, -0.0836184621, -0.8551713824, -1.530089736, -0.6361967325, -1.9284130335, 1.1020956039, + -0.2246899605, 0.5269551873, -0.9494376183, -0.9701120257, 0.7764113545, -0.2850833535, 0.5099344254, -0.13756378, + 1.1417900324, -0.2920076251, -2.0219731331, -0.7772913575, 0.0708815753, -0.3063801825, -0.4740124345, -0.2298611403, + 0.7288610935, 0.2877394259, 0.1773329675, 0.4523156583, 0.6529164314, -0.7750585675, 1.6021527052, 0.8939141631, + -0.0089290179, 0.2659767866, 0.1753713489, -0.5379931331, 0.287309587, 2.2902197838, 0.9296517968, 0.3582972586, + -1.617380619, 1.1959173679, 0.3798225224, 0.3370334506, -0.6950842142, -0.1877526492, -1.0495693684, -1.9517418146, + 0.9486764669, 1.3959928751, -0.156512484, -0.8272699118, -0.6829131842, -2.2610342503, 0.2792412639, -0.8317098618, + -0.0329254083, -0.0633183643, 0.0907527655, 1.6180012226, 0.1789626926, -0.5308724046, -0.1154055297, 2.2669715881, + 1.0755400658, -1.2605806589, -1.3714374304, 0.6071957946, 0.6227938533, -0.2147837281, -0.3323607743, 1.2683321238, + 0.0792714432, -0.7269679904, -1.4837813377, 0.1482709199, -0.8914306164, -0.313654542, 0.8342787623, 0.512450695, + 0.386811316, 0.6767075062, -1.5070546865, -1.1736109257, -0.4428335726, -1.2228515148, 1.6584920883, 0.8860940933, + -0.3657595515, 0.2537226081, -1.5250725746, 0.7131353021, 1.0954420567, -0.4071093798, 0.6125251055, 0.27613765, + -0.2350142002, 1.3670639992, -0.3232049346, -0.7421479821, 1.3723272085, 0.1204612628, -1.4851864576, 0.322743386, + -0.8716908097, 1.0561125278, 1.1365944147, 0.4882908463, -2.3186235428, 1.2475165129, -1.0494215488, -1.1936898232, + -0.8012831211, -0.1370985806, 0.7666711211, 0.1403384358, 0.3451739848, 0.792139709, -0.0043549207, 0.4684241712, + 1.0302612782, -0.1617009193, 0.5881261826, -2.0054824352, 0.3759513497, 1.6423543692, 0.8723756671, 1.5837312937, + 1.2748030424, -1.9394344091, -1.3062525988, 0.802103579, 1.2067923546, -0.6591643095, 1.4958468676, 1.427870512, + 0.287011832, 0.2882831693, -0.9594781399, 0.1612415165, 1.7277601957, 0.8202464581, 1.2654410601, 1.6296563148, + -0.4528054595, 1.2124234438, -0.9555593729, 0.7217754126, 1.3135437965, -0.9282189608, 1.1860563755, 1.3845413923, + -0.0372342989, -1.0035890341, 0.7181358337, 2.2787775993, -1.8576666117, 0.1417283565, 1.198903203, -1.0669670105, + -0.5698820949, -1.3290554285, 0.0011848081, -0.6872947216, -0.0984507203, 0.0053924564, 1.8844401836, 0.6896256804, + -1.1454101801, 0.2944171727, 0.5787634254, -1.6376229525, 1.6078158617, -0.6052874327, 1.084240675, -0.6343843341, + 1.123426795, 0.6614363194, -0.5274475217, -1.6983145475, 0.1424814761, 1.5018779039, 1.6019635201, 0.2406056076, + -1.337833643, 0.3889307678, 0.7279734015, -1.4437752962, 0.2451101989, 1.3260084391, 0.4043070674, -0.6334703565, + -0.0905047655, 2.2889361382, -1.6737362146, 0.4014829993, 0.9645870328, -0.3940742314, 2.2201044559, -1.1043834686, + 1.0660539865, 0.6407681108, -2.9392998219, -0.1941942126, 0.0725432858, -1.6567014456, -0.9918910265, 0.0521232933, + 0.2113792449, 1.2878824472, 1.0472283363, -0.0297677517, 0.6040073633, 0.8790017366, 0.5193853974, 1.0043952465, + 0.1468016207, 0.2064592689, -0.1191236898, -0.7948093414, -2.2682187557, 0.3695141971, 0.0789367929, -0.2442376614, + 2.2216601372, 2.7800517082, -0.0808964223, -0.9864557981, 0.1934024394, -0.144389838, -0.5223660469, 2.2616927624, + -0.0752847716, 0.6587827206, 0.4554153383, 0.4489373267, -0.7989477515, -1.1259423494, -0.9596457481, 1.1747367382, + 0.0612658411, -0.9934889078, -1.4369478226, 0.4548711479, 1.2188794613, -0.863884449, -1.6974016428, 0.3228982687, + 0.4121471941, -1.005636692, -0.4581864774, -1.6678930521, -1.3405390978, 0.4931705296, -0.0594159402, -0.9209959507, + -0.5359746814, -1.2050573826, -0.241651386, 0.0205140915, 0.8051583171, -0.3039194643, 0.4501983523, 1.6569852829, + 0.8124082088, -0.2882144153, -0.0287091434, -0.8580284119, -0.5605448484, 1.5844684839, 1.6319321394, 0.2433615923, + 1.8722686768, 1.3541325331, 0.2546465099, 0.7951636314, 0.4162734747, 0.715367198, -0.5670320988, -0.4803200364, + -0.4373582602, -0.8799190521, 0.5002053976, -0.4195810854, 1.4329137802, 0.745128274, -0.2605960965, -0.1553190053, + -0.1571091563, 0.547662437, -0.534314394, 0.3311653733, 0.8613076806, 0.4169470966, 0.1481061727, -0.956676662, + 0.3370350003, -1.6706675291, 0.6576215029, 1.1566696167, -0.2248429358, -1.4964891672, -1.4325475693, -0.4104234874, + -0.005122548, 0.2184714079, 0.8567622304, 0.0752849728, -0.5590589046, 0.0686668381, 1.1503990889, 1.2555845976, + 0.8356750011, -1.2136638165, -0.6048707366, -0.0624855757, 0.0132966116, -0.0085763428, -0.8367882371, -1.0246938467, + 2.9996769428, -0.2250829041, -1.3752338886, 0.4163417816, 1.5430538654, 0.8278558254, 1.0882321596, 0.6639254093, + 0.029186096, -0.6185283661, -1.1871991158, 0.503025949, 0.8486614823, -0.4215537012, 0.5474107265, -0.1873566657, + -0.5774893165, 0.9267744422, -0.6131139994, 0.6064761877, 2.2037541866, 1.848480463, 0.2465688884, 0.4237998426, + 2.8766086102, -0.6650875807, -0.2597856522, 0.4639374614, 1.1446344852, -0.6116654873, -0.0218625776, -0.4358089566, + -0.5646321774, 0.5649581552, 0.7810892463, 0.7661207318, -0.0211674664, 1.7043101788, 2.2350108624, -0.1355992109, + -0.4077370465, 1.7714235783, -0.8152344227, -0.3246816397, 0.2365811616, -0.8649201989, -0.8507444263, -1.2081509829, + 0.7433677316, -1.2326159477, 0.6326366663, -0.610639751, 0.0574978702, -0.7415626049, 0.9871259332, 2.2205648422, + 0.6921710372, -0.8000081778, 0.9471917748, -2.2180683613, -1.0951820612, -0.4547932744, 0.7424654365, 1.8997622728, + -0.5095831156, 1.2237663269, 1.2456455231, -1.2396967411, -0.3688427806, 1.2640622854, -1.0342392921, -1.4049681425, + -1.5210585594, -1.0076230764, 1.3294607401, 0.6158753037, 0.7308965325, 0.0848912075, -0.196957469, -0.0819591358, + -0.3404512405, -0.6221250296, -0.7510188818, -0.4768586755, 1.2083463669, 0.4217658043, 1.4242808819, 0.0852572173, + -0.3053416908, 0.9350500703, -0.4598187804, 1.8786497116, 1.3874312639, 0.5443605185, -1.4051083326, 0.1745427251, + 1.4360253811, -0.904571116, 0.0467361361, 0.5182443857, 1.4112025499, 1.2951264381, -0.7757521868, -0.2411681116, + -0.4241921604, -0.5597399473, -0.6066641808, -1.1611486673, 0.2278152853, -0.041308485, 1.1212860346, 0.6273789406, + -1.0726985931, 0.7191551328, 1.1449415684, -0.5668084621, -0.8096838593, 0.2828166783, -0.6697654724, 0.0814880952, + 0.438308388, -0.399852097, 0.6673691273, -2.2718055248, 0.4157564938, -1.9803010225, -0.4021820128, -0.9504793286, + 0.5314682722, 1.3823496103, -0.1732390821, -0.3971373439, 1.3028131723, -0.8584709167, 0.7786294222, 1.414296031, + -1.2077190876, 0.3213968873, 1.8558900356, 0.2112760097, -0.3709301651, 1.1207209826, 1.1596553326, -0.5884460211, + -1.1001182795, 0.3257922828, -1.1892958879, -0.7330425382, -1.5030636787, 0.2551620305, 0.2792249322, -0.3615036905, + -0.6149381399, -0.5369812846, -1.1995630264, 0.5322521925, -1.3133509159, -0.6877193451, -0.07935635, 0.7657913566, + 1.0005102158, -0.1015864313, -0.622178793, -0.6660726666, -1.0681372881, 1.1551531553, -0.1612300426, 0.4519759119, + -0.8223438859, 0.736492157, 2.1589651108, -0.6829474568, -1.0340731144, -1.4623531103, -0.8314996362, 0.9340252876, + -0.194485575, 0.0987237468, 0.0290169753, -1.8448588848, -0.7846073508, -0.0732088313, -1.7333260775, -4.0291380882, + -0.5306329727, 0.7409014106, 0.283256799, -0.9075359702, 0.1050713211, -1.2936125994, 0.966311574, -0.5140835047, + -0.5231055021, 0.4298277795, 0.8415327668, 0.3716501296, -0.0323132835, -0.634794116, 1.3319286108, -0.8133419156, + -0.9136698842, 1.3833984137, 0.8047218323, -0.8619208336, -0.9462947249, 0.179730013, 2.6600546837, -1.1597884893, + 0.4171127379, -1.4330574274, -0.2685092986, -0.556317687, -0.1373858452, 0.2979919016, -1.6659470797, 0.9449476004, + -1.2770717144, -0.1901160926, -1.1533769369, -1.0791780949, 0.9957335591, 1.486164093, 1.0744752884, 1.2719250917, + -0.4285410643, -0.7043931484, 1.0934284925, 0.3522428274, 0.3764531016, -0.3339338601, -1.4555534124, -0.4577522576, + 0.217902422, 1.1649961472, 0.9591401219, 0.665577352, 0.3939776421, 0.5124578476, 0.2843569219, 1.3237973452, + -2.1637573242, 1.0497915745, -0.0111749861, 0.5166006684, -1.2268714905, -0.1555034965, -0.0298048109, -0.8875045776, + 0.1314747632, -0.3267731369, -0.5512117743, 0.6083897948, 0.6339176297, -0.8001993895, -1.3872141838, 0.4129168987, + 0.6903015971, -0.8204827309, -1.4886994362, -0.3166840076, -0.098936826, -0.5029759407, -0.2094892561, -0.2207775265, + 0.62603724, 2.3226847649, -0.8254155517, -1.2173273563, 0.4000590742, -0.1477404535, -0.2987808287, 0.7859148383, + 0.5849666595, -0.2389931232, -0.334538728, -0.4545707107, 0.0136067895, 2.3920662403, -1.5474188328, -0.0663272217, + -1.2421488762, 0.7367187738, -1.2968086004, 0.4109822512, 1.885432601, -0.3313354552, -0.7640479803, -0.186897859, + -0.2272865027, 0.1732350737, 0.0523185283, 0.116978094, -0.2806419432, 2.2475368977, 0.251134038, -0.5130397081, + -0.507416904, 1.0990157127, 1.2466640472, 0.3869113028, 0.380975008, 1.1946322918, -0.3047500253, -0.5252722502, + 0.0020444905, -2.1285502911, 0.2623390555, 0.5451027155, 1.8167289495, -1.1404950619, 0.5926309824, 0.5969594121, + -0.0148727661, 0.0002652447, 0.4641184211, -0.4436666667, -0.6841523051, 0.5644008517, 0.1762598157, -0.3095212281, + 0.9205504656, -0.004645023, -0.4804340601, 0.5649686456, -0.362947315, 0.1853141338, 0.6242626309, -0.6242429614, + 0.3195052743, -0.2832978666, -0.7747485638, 0.6012946367, -0.1605652124, -0.4696919918, 0.7488157749, 1.0230870247, + 0.5574153662, -0.629734695, -1.2690787315, -0.6727031469, -1.1326258183, -0.9907282591, -0.4507670999, 0.4559905231, + 0.917884171, -0.6517288089, -0.4528707564, 2.0510644913, -0.4466638565, 0.3832630217, -2.3713276386, -0.7958715558, + 1.5951139927, -0.6162417531, -0.7024154663, -0.7358942628, -0.0514691435, -0.261804074, 0.3440458477, -0.2452831417, + -1.1451121569, -0.2014667243, 0.4369078875, 0.3151161969, 0.4121712446, 0.2650465369, 0.9768393636, 0.965126276, + -0.1851613075, 0.7949992418, 1.2735664845, 0.9264928102, -0.3236273825, 0.4478474557, -0.3741316497, -0.1214300245, + 0.0958605856, -0.4238029718, -0.4743156135, -0.8259438872, 0.7757176757, 0.3365464211, -1.4995009899, 0.7254462242, + 0.8834500313, -0.624453485, -1.6591092348, -1.0582569838, -0.4764253795, -1.7733248472, 0.9393494129, 0.1969945282, + 0.1639864594, 0.1929222494, 1.417452693, -1.1465125084, 0.8462514281, 0.5178537369, -1.0700050592, 1.4103268385, + 0.2136932462, 1.4934782982, 1.8879579306, -0.7683445811, -0.8442191482, 1.9063091278, -0.6955130696, 1.6429194212, + -1.1053818464, 0.1641834229, 0.1306985021, -0.1009309143, -0.1554664522, 0.6429009438, -0.354731679, -0.3141651452, + -0.7517613769, -1.265111208, 0.4944086671, -1.7528989315, -0.0695738867, 0.3000741899, -1.3996940851, -1.2547707558, + -1.1402056217, -0.5491457582, -0.127879262, 0.6167907715, 0.4023316503, -0.2770686746, 0.8350918889, -1.2336196899, + -0.8996614218, 0.8900222778, -0.1889329702, 1.2801160812, 0.6478344202, -0.6443380117, 0.3230400383, 0.5593442917, + 1.1015638113, -2.28272295, -0.5276812911, -0.3871492147, 0.8352118134, -0.247756198, -1.7110137939, 2.6469244957, + 0.3301985562, -1.3280184269, -0.8027424216, -0.7288699746, -0.8320157528, 0.140643388, 0.0071848044, 0.6772457361, + 0.7906083465, 1.5656526089, 1.8632999659, 1.4107118845, -0.1728944927, 1.5014334917, 0.5151723027, -0.5827595592, + -0.6851282716, -1.1576546431, -0.7370390296, 1.1400220394, 0.1113723516, 0.890642643, -0.1768481135, 1.7654592991, + -0.0840447322, 0.6247481108, -0.9882045984, 1.0037338734, 0.0724427253, 0.1596299112, -0.5648909807, -1.0839179754, + -0.5491756201, 0.8615249991, -2.6529829502, -0.5975295305, -0.2969869673, 0.8291987777, 0.9888102412, -0.0241858158, + 0.0042725853, -0.6767337322, 0.4008062184, -0.115072988, 0.6527836919, -1.3201049566, 0.5537902713, -1.0040954351, + -0.8293229342, 0.4181952775, 0.2711547315, 0.708134234, -2.2100968361, 0.4100460112, -1.2368681431, 0.0858222991, + -0.6589938402, -0.0142544145, 1.3100295067, 0.4607637525, -0.3612421453, 2.7282576561, -0.4968651235, -0.4072162211, + 0.4305685759, -0.9169256687, 1.4734205008, -0.668515265, -0.8737441897, -0.5534303188, 0.520039916, -1.1848164797, + 0.3177312613, 0.0415630788, 0.5504212379, 1.3617442846, 0.5164669752, -0.0615786836, -0.6427606344, 0.1296616346, + 0.3920331001, 0.2797629535, -0.7505016327, 0.0564294457, -0.1437963694, 0.2603136599, -0.9009698629, -0.227760151, + -0.7939273715, 0.3479827642, 1.3618816137, -0.5092176795, 0.3851687908, -1.3853656054, 0.7346545458, 0.5953921676, + 0.6145576239, 0.5108073354, -0.7996370196, 0.2773365974, 0.2169533074, 1.1366590261, -1.0889068842, -1.0152673721, + 0.7809972167, 0.7224917412, -1.3904248476, 0.2733822465, 0.67476964, -0.0467090495, -1.1458916664, 0.734431088, + 1.2709969282, 1.0786265135, 1.3192250729, -1.7286123037, 1.0670614243, -0.0010136778, -0.5207394958, -0.3519857526, + -0.0657513589, 1.2044017315, -0.409334451, -1.0834403038, 0.0430439971, -0.1649459302, -1.7983412743, 0.6118800044, + -0.7838023305, 1.0087105036, -1.5372934341, -1.0053912401, 0.7615340948, 1.9778778553, 0.9270530343, 1.1736884117, + 0.0775798485, -0.4577569664, -1.3965622187, 1.818915844, -1.9773858786, -0.7674823403, 1.9165551662, 1.1599441767, + 1.7834349871, -0.1174152419, 0.9704736471, -1.1975587606, -1.5968848467, -1.7459049225, 0.590697825, 1.123521328, + 2.0732831955, -1.0014953613, 1.6119662523, -0.4356044829, -0.1917356253, 0.741194427, 0.5390760899, 0.4717051387, + -0.6492152214, 0.815736115, -1.8203171492, 0.239495635, -1.0516985655, -0.1302240044, 0.446454972, -0.8567866087, + -1.8950551748, 0.0301094223, -2.3413836956, -0.9489056468, -0.9709588885, 0.1027731523, 0.6144888401, 1.4732381105, + 1.7237547636, -1.213365674, 0.1944560856, -0.0028214678, 0.4646196365, -0.4514550865, -1.0959115028, 1.0776283741, + 2.025510788, 1.2845118046, -0.0877527371, -0.5224267244, 1.7399580479, 0.7644951344, -0.8440381885, 0.5369064808, + -0.7958087921, -0.0592793599, -0.6017829776, 1.6896573305, -0.6590547562, -1.0762586594, 0.4362809658, 0.0668928027, + 2.0457201004, 0.5018579364, 0.5019522309, -1.1521987915, -0.281617403, -1.7676477432, 0.0686004385, 0.5971288681, + 1.5740783215, -1.500530839, 0.2959667742, 0.0992885381, -0.4789198041, -0.4450925291, 1.6048885584, 1.9666018486, + -1.5215646029, 0.6102808118, -1.0968976021, 1.1952879429, 1.0654774904, 0.0481246337, 1.0292104483, 0.6108282804, + -1.9799226522, -0.1822997779, -1.0944604874, 0.3795200884, 0.6275728941, -1.081197381, 0.5579342842, 1.4074038267, + 0.2341215163, -1.939812541, 0.1486764103, -1.7583855391, -0.8627243042, 0.8016073704, 0.2244357616, -2.3210380077, + -0.1822131872, 0.2372455597, -0.0160580892, -0.6138968468, 0.2037782669, -1.0922092199, 1.6620970964, -0.1207506806, + 1.4912840128, 1.9458825588, -1.0110816956, -0.3563345075, -0.7647183537, 0.3050349653, -0.0155192744, 0.8703370094, + -0.200746879, -0.0845041946, -0.2028828859, -0.7978484631, 0.1054977104, 0.3118167818, -1.6269580126, 1.1409548521, + 0.9135065079, 0.1632136852, -1.0845395327, -0.8973467946, -0.1036828682, -0.332406491, 1.1789542437, -0.3770294487, + 1.5620265007, -1.3538585901, 0.1679062247, 0.1029169038, -0.4538665116, 0.038523037, 0.713278532, 1.3319801092, + 0.2151621729, -0.6791537404, 0.0503540374, -1.7433155775, -0.2129102945, 2.3486294746, 0.6435081959, 0.0417948477, + 0.4045048654, 0.5760819316, 0.2136069536, 1.5347999334, -1.6873236895, 0.611557126, -0.0327798501, -0.5411595106, + -0.445376873, -2.0417563915, 1.9538553953, 1.5702822208, 0.9667896032, 0.0068834368, -1.4329059124, 1.7121027708, + -1.210772872, 0.8673722148, -0.0087148799, -0.2151390463, 0.1782071441, -1.790554285, 1.1115261316, 1.043643713, + -0.8217792511, -0.8795315027, -1.5809032917, 0.361969769, 1.7345861197, 0.5589722395, 1.2194062471, 1.2847113609, + 0.7623335123, -0.4450575113, -0.5541297793, 2.3819768429, 1.0045148134, -0.2210227102, 0.0310857967, -0.3054305315, + -0.2346151024, -0.2350860834, -1.0135045052, -0.4001455605, -0.4735128582, -2.399721384, -1.6969120502, 0.6540305614, + 0.7910987139, 2.6275141239, -0.5053266883, -0.6437256932, 0.4331637621, -0.1179857254, 1.3676888943, -0.3311014175, + 0.0152680846, -0.0236807577, 0.9302479625, 0.660063982, -2.4037752151, -0.9464588761, 0.0438113771, -0.0725328401, + 1.0720617771, 1.0761135817, -0.2737096846, -0.558889389, 0.2598156333, 0.9769091606, -0.6441979408, 0.7905815244, + 0.8603966832, 0.2026889175, 1.36736691, -1.38582623, 0.2233661562, -0.1094158739, 1.445379734, 0.0151959099, + -1.6613028049, 0.7575907707, -0.1962304562, -0.1996283978, -0.7416828871, -0.7916600108, 1.4287346601, -0.4484005272, + 0.6876532435, -0.6248690486, 0.329863131, 0.912732482, -0.9684745073, 1.3250454664, 2.2452054024, -0.9814113975, + 0.0123218549, -0.0707478821, -0.0363855138, 1.0943500996, -2.1510896683, 0.5944954753, -1.027586937, -0.7499034405, + -0.9592984319, 0.5362375975, -2.1820952892, 0.6188629866, 0.7973918915, -1.7052952051, -0.7358623147, 1.4108181, + 0.321433574, 1.3040961027, 0.6007806063, 0.6384257674, 0.5477932692, -0.0138832955, -0.8589347005, 0.8096865416, + 0.3102856278, -0.2026515752, 0.9718768001, 0.6564921737, 0.160317257, 1.0024086237, -0.9002149105, -0.8006245494, + -0.9411728382, -0.1576966792, 1.1415449381, -0.0577506274, 1.1866910458, 0.3541076481, 0.6679896116, 1.3162442446, + -0.2557232678, -0.3763893545, 0.2416353524, 0.7076978683, -1.8903992176, 1.1509604454, -0.5034546256, 0.2765678763, + -1.8116631508, 0.0736504048, -0.5345338583, -0.2187395692, 0.8730805516, 0.2851711512, 0.4014697671, 0.5744179487, + -0.9496762156, -0.9646509886, -0.2687695622, 1.8421496153, 0.833501637, -0.6742351651, -0.3898480535, -1.3010454178, + 1.2313911915, 2.5872275829, 1.0136504173, -0.1823874265, -1.9427940845, 0.0121092172, 1.0977327824, -0.9339600801, + 0.0772805214, -0.7465289831, -3.4953188896, -1.5749645233, 0.0567488112, 0.4932927489, 0.4036336541, 1.510202527, + -0.3151389062, 0.4847653508, 2.2489926815, 1.2595604658, 0.4640718997, -0.2695495784, -0.7470452785, 0.7966135144, + -1.2423455715, 1.0008935928, 0.1510142535, -1.3154373169, -0.5294527411, -1.4460440874, 0.0734137148, -0.9246321321, + 0.0041351891, 0.3118188381, -0.4110965133, -0.4202423096, 0.1939986348, -1.1355917454, 1.0640664101, 0.1575757712, + 0.2295729369, -0.5353895426, 0.2008222491, -0.0894518197, -1.2742060423, -1.2324142456, -0.0447078608, -0.1281779855, + -1.292544961, -2.0690896511, 1.6433898211, -0.6176621914, -1.8369152546, 0.8185908198, 0.3368025124, 0.2383316606, + -0.3955019116, 1.0942413807, 1.0905435085, -0.6878349185, -0.8977550864, 0.5481200814, -0.8589039445, 0.2464670092, + 2.2294669151, 0.3704622686, -1.6462700367, -1.009662509, -0.7288820148, 0.072027348, -1.4444570541, -1.4314428568, + -1.0962486267, -0.6008301377, 0.662630558, 0.3884952664, 0.1886538416, -0.0186148025, 0.9334484339, 0.5448017716, + 0.1605713814, -0.5728644133, 2.3174045086, -1.1572582722, 0.3675760925, 1.2822412252, 0.6096727848, 1.083348155, + -1.4809343815, 0.6521091461, 0.4051893651, -0.0447794273, -0.4249199927, 0.9600380063, -0.1428283155, 0.1274694651, + 1.0010346174, 0.966557622, 0.7157662511, 0.1009588018, 0.9976038933, -0.3180441856, -0.7530906796, 0.5247619748, + -0.152707085, 1.2734057903, 0.4071713686, 0.9690848589, -0.7642352581, 1.0456936359, 0.6039264202, -0.6427201629, + 0.2151586413, -0.3214791715, -0.4597530067, 0.527127564, -0.603156209, -0.3741852939, 1.962474227, 1.3004586697, + -0.9262704253, -0.5459587574, 1.9289519787, -0.1279011965, -0.8018730879, -0.3704701662, 0.1392263919, 2.2456700802, + -0.213186577, 0.2803228796, -0.2014343739, 0.4005430639, -0.730394125, -0.6890636683, -0.1513775736, 0.8517774343, + -1.3185310364, -0.8762566447, -0.130394727, 0.9660004377, -0.4019751847, 0.4808919728, -1.37819314, 1.8092302084, + 1.2631082535, 1.0598397255, 1.1649284363, -0.5299757719, -0.230215326, 0.4181659818, 1.011333704, -0.0762433708, + -0.1666911095, -0.0848165229, -2.1126856804, -1.9476577044, -0.3496899605, -0.496701926, 0.5956168175, -1.2740421295, + 1.6090040207, 1.1050789356, -0.3681654334, -0.4480681121, -0.2363000661, -0.2702892125, 0.8397852182, 0.4432892799, + -0.6930931807, 0.8435317278, 1.0990096331, -1.4728732109, 0.3252948225, 0.1570708901, -0.2961833179, -0.0988946781, + -0.6090566516, 1.7864310741, 0.3255374432, -0.7772111297, 0.8540177941, -0.3736964464, -0.1458571851, -0.4800638556, + 0.6023507118, 1.3466943502, -1.305772543, -0.6299296618, -0.1963314563, -0.6180570722, -0.6634348035, -0.9157820344, + -2.1389577389, -0.5336833596, 1.3248667717, -0.6429237723, -1.1559734344, 0.6903609633, 1.2517040968, 0.9739649892, + 1.2991584539, 0.2655103207, 0.3484174013, -1.2541536093, 0.189482972, 0.8233504891, -0.0764275566, -1.2177714109, + -0.8417980671, 0.8581524491, 0.0035927813, 0.6365355849, -0.804219842, -0.1388953626, -1.632650733, -0.6042947769, + -0.966971755, 0.293833375, 0.9714415073, -0.1223727614, -0.8723503947, -1.1460812092, -0.2133648992, -1.1128445864, + 0.9363123178, 0.1991896331, -0.8822627068, 0.1223424897, 1.3291049004, 0.0668822005, 0.1119093895, 1.6684954166, + -0.9703634977, 0.8244425654, -0.3810819983, 0.6499918699, -0.4449295998, 0.5241637826, 1.8430259228, -0.1138890088, + -0.7317150235, 1.5404244661, -0.6431032419, 1.0746787786, 0.9530599117, 0.203567639, 1.7534618378, 0.4639586806, + 0.0214881431, 0.3588767946, -0.4447282851, 1.6261456013, 1.7030267715, -1.462448597, 0.6691627502, -0.41205284, + -1.2016181946, -1.0315819979, -1.8414787054, 0.7353565097, 0.0985109657, -0.5989940166, 0.628937006, -0.7668067217, + -1.0768667459, 1.1415388584, 0.2427966297, -1.5039368868, 0.2121663541, 1.8831692934, 1.7689586878, -0.0031755727, + 0.1881536543, 0.0798226669, 0.4581492841, 0.2642267048, 0.9306536317, -0.4983684719, -0.1663818955, -0.91448915, + 0.9846673012, 0.2117036432, -0.6294923425, 2.242112875, -0.1303592473, 0.4997661114, 0.9499601126, 0.7253001332, + 0.2831318378, -0.4090300798, 1.1107546091, 2.2380344868, 1.3806735277, -0.3407057524, 0.4970670044, 1.342285037, + 0.1040709913, -0.1962797344, -0.6731407642, 0.3965022266, 1.6650975943, -0.6868150234, -0.9100295305, 1.5729589462, + -0.10790281, -0.8686639071, 0.213799119, -0.8141530752, -1.2586628199, -1.0130791664, -0.1064461023, 1.3744591475, + -0.5557163358, -1.4183386564, 0.4970445335, -0.1264280081, -0.6952810287, 0.7875682116, 0.9634685516, -0.0873802453, + 0.4830078781, -2.0697469711, -0.2951569259, 1.9275074005, -0.2655444741, -0.5246491432, 0.6961337328, -1.1402201653, + -0.8014924526, 0.4705885053, 1.3276981115, 0.948762238, -0.1226340607, 2.2388117313, 0.9282962084, 0.8358730078, + 0.5729625225, 1.3172289133, -0.7303490639, 0.1824570298, -0.6966341138, -0.8805764914, 0.7411084175, 0.2305240929, + 0.0980034173, 0.8006091118, 0.2612165213, 1.0207033157, -0.0486149713, -0.1296018958, -0.2046490759, 0.3058603108, + 0.1007243693, -1.8249213696, 0.5788246989, 0.5505513549, 0.8283489943, 2.3347523212, -0.3820807934, -0.666565299, + -0.6986245513, 0.5523877144, 0.5897316337, -1.7852385044, 1.5092515945, 0.5711547732, 0.3464311659, 0.2958600223, + 2.0925042629, -0.2321517169, -0.1434054524, 0.5728091598, -0.2187698931, -0.4759446084, 0.1177005395, 0.2013361752, + 0.5981849432, -1.9799973965, 0.2529041767, -0.5476834178, -0.173059389, -1.7854814529, -1.1705741882, -0.358163476, + 0.3817416131, 0.7512064576, -0.102755174, 0.6353870034, 1.3960314989, -1.2177100182, -1.2762954235, 0.2829504609, + -0.3222350478, -1.9788143635, 1.185239315, -0.8120482564, 0.2017181963, -0.7778249979, 0.132488817, -1.7530630827, + -0.3840102851, 0.5514950156, -0.9082639813, 0.2709457278, -0.2724392414, 1.7407710552, 1.0251507759, 0.5038827658, + 0.0599922501, 0.2778967619, 1.1140643358, 0.5126416087, 0.9094967842, -0.2608771026, 1.0770685673, 0.3795000911, + -0.1550950557, 0.4098328948, 0.0182807632, 1.7432143688, 0.0442269817, -0.0733183324, -1.7420239449, -1.0372033119, + -1.4505765438, -1.0695979595, 0.3520697057, -0.1199650243, 0.1623314768, -0.4059309363, 0.2590332925, 0.3168719411, + -0.298520416, -1.1141160727, 0.4796123803, 0.5619376302, -0.0879992098, -0.2896755636, 0.0345673114, -0.6017387509, + 2.2942187786, -0.4575514793, 0.4433886707, -0.639359951, -0.7018532753, -2.0840408802, 0.2744977772, -1.7085973024, + 2.0885903835, -1.0704900026, 0.6227512956, -2.3643672466, 0.473782897, 1.8228685856, 1.2083232403, 0.5655582547, + 1.1943204403, -1.6110794544, -0.8104713559, 0.6233947873, 1.4821898937, -0.3512924016, -0.9832256436, -0.310965836, + 0.2102089971, 0.0661011934, -0.7598971128, 0.2737687528, -0.3565664291, 0.0649320632, -0.8309890628, 0.8115738034, + 0.5818820596, -1.247025013, 1.5066984892, 0.0355780944, 0.5166119933, 2.25268507, -0.8431701064, -0.0671550483, + -1.17545259, 0.5172681212, -1.4026856422, 1.2922587395, 1.1752586365, 0.430885911, -0.1489560753, 1.2196234465, + 0.2266667634, 0.6856338382, -0.0718977973, -0.7315303683, -0.7587987781, -0.6444988251, 1.0108252764, 1.7422361374, + -1.056612134, -0.1381981969, -2.4956552982, -0.613925755, -1.2556135654, 3.1750850677, 0.2591003776, 0.2450738251, + 0.3005379438, -0.9752496481, 1.7764663696, -0.1214622557, 0.5261299014, 0.2342363894, -0.0667102411, -0.9946687222, + -0.7998950481, -0.1393250823, 0.5439608097, -0.3280489445, -1.6486464739, 0.0773164555, -0.6094115973, 0.7776465416, + -0.769831717, -0.2485616952, 0.7960718274, 0.2313920408, 0.0460020714, -1.7142246962, 0.6232043505, 0.2541713715, + -0.453440547, 1.7899509668, 0.1362471282, -1.9164524078, 1.3635959625, -0.8852525353, -0.3090792894, 0.3931639791, + -0.9311147928, -0.3980593979, 1.916015625, -2.4146127701, 0.9591246843, 0.0804828331, -1.1393139362, 0.5533338785, + -0.0600930825, 0.2490953207, 0.3519489169, 0.7660022974, -1.6150187254, 0.6105470061, -1.2359455824, -0.8698206544, + 0.3892658055, -0.7539950013, 0.6950904131, -0.9604725242, 0.4308103025, -2.3256311417, -0.7111156583, -0.4337917566, + 0.8061956763, -1.3608552217, 0.4315817952, -1.3107632399, 0.557438612, -2.2791669369, -0.9615024328, -0.0104346648, + 1.8257387877, 1.4231183529, 0.2945812345, -0.1324300915, 0.2946366966, 1.6782826185, 0.6541477442, 0.4029373229, + 0.4747828245, 1.1353145838, 0.3953845799, 0.1936890781, 0.406262368, 0.417966336, -0.1990364641, 0.2323853821, + -0.162743479, 1.2631576061, 1.0686953068, -0.2658118308, 0.6809504032, 1.540771246, -0.6695981622, 1.8600367308, + 0.4357393682, -2.5560443401, -0.5719974041, -0.8085638285, -0.2786338627, -0.7596287727, -0.7966396809, -0.6347700357, + 0.6346846819, -0.1229087114, -0.4061551392, 0.4961775839, -0.929802835, 1.7950794697, -0.4195333719, -0.6384252906, + 0.4334599376, 1.2472872734, -0.2829909325, 0.1914219707, -2.3444113731, 0.1594360918, 1.2696460485, 0.4959804118, + 0.2380602211, -0.1448186785, -2.1736934185, 0.0322666392, -1.1135591269, 0.1910399944, 0.5964226723, 0.6934137344, + -0.3309519887, 0.5232272744, 0.6514256001, 0.5427439809, -1.2049249411, 1.2035021782, -2.1379439831, -0.0123552503, + 1.6907293797, 1.3622356653, 0.0854423568, -0.1239003465, -1.1248239279, 0.3118157685, 1.4227129221, 1.3931421041, + -0.5201041102, -0.6520749331, -0.1951945126, -0.0238409471, -1.0981628895, 0.1196731627, -1.0028203726, -0.0433323942, + 0.1475336701, -0.2034588307, 0.0879188478, -0.1838414073, 0.8159422278, -0.6409673691, 0.0307073314, -0.822542429, + 0.186487779, -1.2164173126, -1.0154621601, -1.4576314688, -0.7777158022, -1.0057930946, 1.5576810837, 1.0352222919, + 1.8638725281, -0.0097064106, 0.805419147, 0.1223727986, -0.0801445544, -1.4936922789, -0.4619750381, 0.0596807078, + 0.3278731108, -1.0393821001, -0.4951561689, -0.3413927257, 0.19047001, -0.1210603565, -0.159424156, -0.5338973403, + -2.1179163456, 0.9923138022, 1.67565763, -0.5539448261, -0.4309539795, 1.2551391125, -0.9311563969, 0.6251273155, + -0.0564246289, 0.8008189201, -1.9777007103, -0.309818089, 0.7816771269, 0.6166989803, -0.6998443007, 0.4654302001, + 0.0343916118, 2.4334328175, 0.5027511716, -0.5978142023, -1.1934173107, 1.1687659025, -1.3383669853, 1.0300269127, + -0.0677551478, 0.390041858, -0.4028481245, 1.5647825003, 0.4914836287, -1.01390481, 0.7788290381, -0.9364992976, + -0.4769464433, -2.2719848156, -1.2316024303, 1.4936300516, 1.1475230455, -1.6251858473, -0.1341409087, -0.6324136257, + 0.9583027363, -1.8046439886, -0.665735662, -0.2849379182, 1.1019287109, 0.3203172982, 0.8305735588, 0.8801663518, + 0.2541929483, -0.7876218557, -0.4848353863, -0.603825748, -0.3463531435, -0.4620301723, 0.3399290442, 0.4784194231, + -1.4630919695, 0.5666418672, 0.6698990464, -0.1886400282, -0.0589710884, -0.8409474492, -0.5538551211, 1.1771206856, + 0.0073921932, -0.0275823288, 0.4827136993, 2.1394298077, 1.0037149191, 1.3728575706, 0.5932582617, 0.6228179932, + 2.2393188477, 0.6417520642, -0.6442270875, 0.3314913809, 0.4365530312, 0.9575701952, 0.125328213, -2.6363835335, + -1.1195566654, 0.1741666943, -1.3815630674, -1.3405553102, -0.9259150624, 0.7431330681, -0.5993356109, -0.9352449775, + -0.2250264287, -0.3261758387, -0.9840246439, 0.8795168996, -0.0585330613, 0.4813308418, 0.693235755, -0.6614339352, + -0.6948084831, -0.5029956698, 1.063401103, 1.9179027081, -0.156888783, 1.2873591185, 0.7845811844, -0.9608737826, + -1.5719852448, -0.3008854091, -1.5339412689, -0.2134107649, 0.4248637855, -0.3359931409, -0.1320641041, 0.8435388803, + -2.7100458145, -1.7172553539, 0.8296487927, -0.9835475087, 1.591786027, 0.1721152812, 0.4304965138, 0.7664323449, + -1.2311582565, -2.3880450726, -0.4940323532, -1.0391459465, -0.7237001657, 1.2727987766, 1.6193475723, -1.0287649632, + 0.7299798131, -0.634901166, -0.0274767578, -1.590005517, -0.4706409872, 0.7383552194, -1.4446251392, 2.9851384163, + -0.5311147571, 0.0925131291, 1.0023488998, 0.9239675403, -0.3110629916, -0.3885660768, -0.5063413978, 0.2894129455, + 0.8276406527, -0.4842105806, -1.5078349113, 1.2256025076, 0.8286691904, -0.3395346701, -0.0520976894, -0.6069356203, + 1.4886635542, 0.8925319314, 0.5489603281, 0.4804161787, 1.3660881519, -0.4378204644, -0.7837976217, 0.327993989, + -0.4669124186, 0.5884266496, -0.1041898355, -0.7743563056, 1.9065687656, -0.140136525, 0.0404757708, -0.4654856622, + 0.1470849812, -1.2212413549, -0.2502074838, -0.5511439443, 0.1273302287, -0.8361667991, 0.5060011148, 0.4187401831, + -1.0274453163, 0.1833582371, 0.1491656005, 0.852036953, -1.0309195518, -0.2227566093, 0.0463354513, -1.7734726667, + 0.2360962629, 1.2328624725, 1.3344942331, -0.6834138036, -0.9213144183, -0.2375682145, -1.0676547289, -0.7755971551, + -0.1519525945, -1.1810057163, 0.6070850492, -1.2324193716, 0.7946123481, 0.4432314336, -1.2385253906, 0.786057651, + -1.2088580132, -0.6392730474, -0.8253847957, 2.063644886, -0.3773825765, 0.2946148515, 1.292707324, 0.3535074592, + -0.4379634857, -0.0179980081, -0.0072805942, 2.2701530457, -2.1468765736, -0.3751948774, -1.4295772314, 2.2897188663, + 0.7464865446, 0.2147173584, -1.1608482599, 1.5358866453, 0.5187512636, 1.8804030418, 1.5796387196, 1.048718214, + -0.867683053, -0.0556595251, 1.3028850555, -0.5795240998, -0.5162953138, -0.065546684, 0.9422415495, 0.7499783039, + -0.9180640578, 0.4498133957, 1.159091115, 0.4048582017, -1.7504346371, 2.2532100677, 0.0281716362, -0.6220969558, + -1.5183184147, 0.9161355495, -0.8907647133, -1.3098375797, -0.3318792582, 0.2209775299, -1.2912184, -1.5370779037, + 0.2036247104, 2.0972721577, -1.061144352, 0.9589093328, 1.15919137, 1.0168168545, 1.2855957747, -0.0241216458, + -0.8847688437, -0.2365839183, 0.0415988378, -0.1515546739, -1.007044673, -1.1214296818, -0.341704458, -1.3171265125, + -1.5975716114, 0.8810922503, 0.4943160117, 0.0729970559, -0.0358922035, 1.4424666166, -1.5872232914, -1.3994543552, + -0.4739158154, -0.4085120559, 1.6491034031, 0.3564356565, -0.5753759146, 2.0592122078, -1.0333622694, 2.1544709206, + 1.3682296276, -0.7064908743, 1.7868995667, -0.9723177552, -0.7266247869, 0.9715178609, 0.4088996947, -1.7122020721, + -0.4308840632, 0.3252696097, 0.2743642926, -0.8869826794, -1.0270365477, -0.5657429695, 0.0832255706, 0.0655450523, + 0.4747250974, -1.372638464, 0.4130788743, 0.6846900582, -0.5520215034, -2.0530512333, -2.1558058262, 0.1264140904, + 0.37466079, 1.8946000338, 0.1379344761, -1.2841641903, -0.3011165857, -1.3064757586, 0.6817041039, 0.9905909896, + -0.3322680295, -1.0966534615, -0.5721865296, 1.161303401, 0.4173618853, 0.2521701753, 0.0170840435, -1.121846199, + 1.3891819715, 2.0246393681, -0.3689926863, 1.2998167276, -0.0202535987, 0.4367121756, 1.0193365812, 0.904296875, + 0.6680484414, -0.6065965295, -0.5022114515, 0.5810588598, -0.3901543915, -1.1834454536, 0.8150207996, -1.1420608759, + -0.35981071, -1.6044889688, -2.438410759, 0.0117071439, 1.9975863695, -1.3817124367, -0.3072476387, 0.0048268959, + -1.7112979889, 0.9031231999, -0.2966916263, -1.0396625996, -0.1289494932, -0.7083650827, -1.4692304134, -0.5094682574, + 1.939237237, -1.613928318, -1.1871839762, -1.1809390783, -1.9714508057, -0.9087123275, -0.2333478034, -0.7533107996, + -0.9897646308, 1.4758378267, 0.1605499536, -0.0507054329, -0.2238054425, 0.8934520483, -0.0074833194, -0.3475907147, + 0.4808534384, -1.3428298235, 0.0425792374, -1.4493671656, -1.1105960608, -0.3286893964, -1.1615190506, 0.7743390799, + 0.5156641006, 1.4899449348, 0.7932764888, -0.3827163875, 0.9504209161, -0.1228832677, -0.5156506896, -0.2268660665, + -0.6296691298, 1.0760799646, -0.4033052623, -0.7914856672, -0.2877828479, 1.5812536478, -1.1596530676, 0.0779661462, + 0.6545679569, -0.2202242166, -0.7564415932, -0.041714374, -0.3171341121, -0.4582436979, -0.9056224823, -0.9524829984, + 1.6070226431, -1.2132416964, 2.2914252281, -1.1252080202, -0.6691984534, -0.2136556059, 1.5424201488, 0.3239894807, + -0.1936365366, -0.3805269301, 0.3153375685, -0.0132743232, -0.717476368, -0.6745864749, 0.5147384405, 0.2804582715, + 0.8614385724, 1.0986897945, 1.7333666086, -0.7799022198, -0.9911209941, 0.9604320526, -0.8721246123, -1.6883252859, + -0.8845354915, 0.7923492789, -0.5049350262, 2.007610321, -0.0851265863, 0.7332333326, -0.1772662252, 1.5707787275, + -1.1044410467, -0.1525815576, -0.9408708811, 0.4330949187, -1.2818670273, -0.3055057526, -0.1675800681, 0.0284603387, + -0.8147291541, -0.4210108519, 0.7458789945, -1.1510759592, -0.5196728706, 1.2945172787, 0.3134264946, -0.5981710553, + -1.7199571133, -0.9573861957, 0.3585983515, 0.1577864438, 0.0976585224, 0.9235061407, -0.4882372022, -1.2233790159, + -0.3873362243, 0.1936537027, 0.845980823, -2.3967981339, -1.7979650497, -1.3401989937, -0.6894354224, 0.0410711132, + -0.7186352611, 0.0600788631, 1.3476153612, 0.3278820813, -1.3045172691, -1.3771083355, -1.7876477242, 0.2890119255, + 1.3028764725, -0.3252322376, -1.6646826267, 1.0996216536, 0.8495755792, 1.1889733076, -0.6801342368, -0.9674876332, + -0.555995822, -0.8111504912, 1.2361888885, 0.2234009504, 1.1607664824, -0.7407107949, -0.2627224922, -0.6727229357, + 0.65917027, -0.1328006536, 1.9366884232, -0.0906984061, 0.7591729164, 0.1739566326, 0.7143741846, 0.5020965338, + 1.7826042175, 0.6204472184, -0.5581421852, 0.2132278383, 0.3122832775, -0.9909564257, 1.259960413, -0.1934482753, + -0.9713167548, 1.1571723223, 1.5756896734, -0.5407086611, -0.6157051921, -1.6384927034, 0.9595841765, 1.1959745884, + -0.2396019995, 0.5296090841, 0.0760802999, -1.4119911194, 0.263340354, 0.8130000234, -0.0615768097, -2.6958682537, + -0.077426739, 0.2242079079, -1.1902222633, -2.2081933022, 1.3072851896, -0.6697205305, 0.3599147201, -0.5324732065, + 1.864731431, -0.6539912224, -0.0811203197, -1.6695041656, -0.1677595228, 0.1529489309, 0.032698296, 0.3603679836, + 0.2729178965, 2.6728754044, 0.0517382957, -1.1903650761, 1.9886676073, 0.3085786998, 1.2711433172, 0.3996826708, + -0.9335381389, -0.3373581767, 0.5985429883, -0.718891263, -0.5423603654, 0.810932219, 2.118268013, -0.2123235017, + -0.2050291598, -0.3468085825, -0.0957891718, -0.2557451129, 0.1651563942, -0.9804444909, 1.7935678959, -0.542006433, + -1.2521762848, -0.4070931375, -2.2685718536, 0.2797066867, -0.167173177, 0.7808704972, -0.258479774, -1.3019461632, + -0.8495772481, 1.1621996164, 0.7994099259, 1.4648393393, 0.0249336269, -0.5417373776, -0.1430224478, 0.3782896399, + 0.4983956516, -0.3447601497, -0.0361413844, -1.3818486929, -0.190946281, -0.6342868805, -1.5501580238, 0.4438783824, + 1.4791367054, -0.2694898248, -0.5962350965, -0.4852928221, -0.9123769999, 1.4600878954, 0.0140110198, -0.0810736865, + 0.4739871919, -1.6347879171, 0.656116128, 0.7903645635, -0.0381236821, 0.7106814384, -0.4605905414, 0.0920624137, + -0.7547672391, 0.097922951, 0.3171488345, 1.1117020845, 1.4691916704, 2.1095216274, 0.0467688963, -0.2855694592, + -0.962726593, -1.6467630863, 0.4463484585, 0.1725912839, -0.4279518425, -0.1798031181, 0.3101399839, 0.0048362794, + 1.4784452915, 1.5026966333, 1.0328475237, -0.4919162393, -0.1434764564, 0.4667615294, 0.9142318368, -0.9285969734, + -0.2069311589, 1.4059398174, -0.5289928913, -0.4967575073, -1.3956668377, 1.4277200699, 0.8334128261, -0.0185762569, + -0.1923116297, 0.0418641306, -0.4321692884, 0.8290914893, 0.8341650367, -0.233321771, 0.7934345007, 0.3587965965, + 0.5614849925, -2.0616495609, -0.1924656183, -0.0459085889, 0.2538861036, -0.405780226, -0.0318090059, 1.3345776796, + 1.9516458511, -0.4307067394, 0.8678566217, -0.1097779796, -1.6316813231, 0.1627230048, 0.6683475971, -1.0535581112, + 0.3491037786, 0.4147782922, -1.2055585384, 0.488607794, -0.1130808294, 0.7219112515, 0.0661294386, -0.140084058, + -0.0657013953, -0.6607044935, -0.6015189886, 0.7106990814, 1.7140800953, 0.9367416501, -1.2773195505, -0.6420869827, + -0.6175547242, -1.8307830095, -0.4264650047, 0.5967303514, 1.380461812, 0.8144572973, 1.5835609436, -0.3536988199, + 0.7703401446, 1.4535437822, 0.7620157599, -0.2588397861, 1.8452669382, 0.282956481, -0.8681214452, -1.8005297184, + 0.4997319281, -0.4752902091, 0.8748758435, -1.3430117369, 0.5314849615, -0.5759868622, 1.2641209364, 0.855440259, + 1.5168594122, 0.2480181605, -0.2194981575, 0.5211862922, -0.6440048814, 0.7792780399, 1.4497418404, 0.7278845906, + -0.5463015437, -0.0357734151, 2.2245075703, 1.7500543594, -0.1910633743, 0.6573238969, -1.3362874985, -0.7534814477, + 1.2886375189, 0.8610209227, -1.012185812, 0.9795084, -0.1356090903, 0.5075626969, -0.8574798107, 0.5879177451, + -1.7946065664, -0.0130303819, 2.6269860268, -0.2716670632, -0.0657275766, 0.1854525954, 0.6998822093, 0.2578449249, + -1.4977544546, -0.6380822659, 0.3094310462, 0.9322613478, 1.0821434259, 0.0982655212, 1.265530467, 0.8077735901, + 0.7658033371, 0.0170805342, -0.6523284912, 0.496796906, 0.2543117404, -0.147229746, -1.0754979849, -0.3788460195, + -0.6500695348, -1.2020435333, -0.706248045, -0.1719639748, 0.1413584501, 1.7674720287, 1.424582243, -0.6928767562, + 0.407050848, -0.8351898193, 0.61244452, -1.4726996422, 1.2751882076, -0.0078987619, 0.725051105, 0.4638235867, + 0.2765693367, 1.0345190763, 0.6211076975, -0.2134134769, 1.0013273954, -0.3205123544, -1.958065033, -0.1975866854, + 0.5886839032, 0.2872526348, 1.8216292858, -0.8485202789, -1.1175162792, 0.09096203, -0.1545620412, 0.6551841497, + 0.7736989856, -1.3568792343, 0.7647265792, -0.2998824716, -1.3783611059, -2.0769608021, -2.3308551311, -0.1665841937, + 1.6644699574, -1.1846499443, 1.8231101036, 0.4575906098, -0.5072680116, -0.3290798664, -1.7656143904, -1.0600577593, + -0.2223261595, 0.4002893269, 0.7339606881, -1.7777433395, 0.1461729258, 0.7029541135, 0.7349690199, -0.4175417423, + -0.6678780913, -1.4948253632, -1.2591323853, 0.700217247, 0.4057020247, -1.884611845, -0.4096996486, 0.3572451174, + -0.5729187727, 0.3632394969, 0.8388002515, 0.788812995, 2.074542284, 0.1977431327, 0.1684732288, -0.5357504487, + -0.7693734169, 0.4129380882, -0.3638237119, 0.6388210654, 0.0842956081, -0.1233994961, 0.0458561741, 0.0440238081, + -0.8346993327, 1.1818025112, 0.3015581667, 0.2385077327, -1.22800529, -0.0870673805, 0.3921283185, 0.4252742529, + -0.0002660285, 0.498814404, -0.3004822135, -0.2015036196, -0.5291435719, 1.3097598553, 1.4225721359, 0.6904790998, + -0.7867959142, 1.5844599009, -0.2980011702, 1.2988511324, 0.2470097095, -0.4910517037, -0.4043954611, 1.0191758871, + 0.1660731584, 1.622141242, 0.0662123859, 0.1093840599, 0.3859095871, -0.1514603198, 0.7722839713, -1.8401905298, + -0.4582791924, -1.5480029583, 0.8383934498, 1.5307412148, -1.084883213, -1.4832700491, 1.3966538906, 0.7267266512, + 0.5375882387, -0.7886016369, 1.0743261576, -1.1768319607, 0.1318906993, -0.3701928556, 0.560105145, 0.3761105239, + -0.0058422196, 0.8287389874, -2.538957119, 2.1728942394, 0.3999422789, -0.0519637764, -0.0581969433, 0.1575311124, + -0.7968834043, 1.0298998356, 0.3352723718, 1.8463332653, -1.3961603642, -0.1399134099, 0.8294527531, 0.8428064585, + 0.1062459201, -1.6589927673, -0.5416683555, -0.3484183848, -1.3727669716, -2.1644611359, -1.1050168276, -0.6006038189, + -0.6543050408, 0.4155762792, -0.4915748537, -2.1399559975, 1.0393067598, -0.1879214644, 0.8151748776, -0.5987551212, + -1.0111064911, -0.1526869535, -1.9934095144, 0.0915879831, 0.0305229817, 0.0214052256, 1.4779964685, 0.4579023123, + -0.1609235853, 0.8058716059, -0.1193252355, -1.42098248, -1.44328022, 0.3448107541, 0.8484117389, 0.3917312622, + -1.3221226931, 0.2110161185, -0.132226631, 1.2812737226, 0.2105053812, 0.5784762502, 1.2395321131, -0.1125992611, + 0.6148221493, 0.1073464751, 3.1926834583, -1.7169188261, -0.426481843, 0.5589302778, 0.0098558068, 0.0445020609, + -1.0925434828, 0.5685714483, 1.8520839214, 0.2249426991, -0.1640461534, 0.4741087854, -1.802880764, 2.5509712696, + -0.3230691254, 0.1120029092, 1.4169816971, -1.102170825, -1.3753912449, -0.6458590627, 0.1685565859, -0.2544992864, + 1.297736764, -0.643476367, -0.4687041342, -1.5133686066, 0.5543805361, -1.6351692677, -0.5480977893, -1.8672090769, + 1.866974473, 0.1007032543, -0.7519266605, 0.928889513, 1.0849411488, 0.8286650181, 0.2248411477, -1.4469972849, + -0.8432237506, 0.4922606349, 1.0674357414, 1.0139129162, 1.8805615902, -1.019846797, -1.4214346409, 0.0867412463, + 0.7238012552, 1.2070678473, -0.2821899652, -2.5294377804, -0.1533146352, 1.5075769424, 0.1515903473, -0.7290561795, + -0.3938293755, -0.3148902059, -0.0655002147, 1.032802701, 0.9855728745, 0.0142235737, 0.1424133629, 2.3653128147, + -0.0937726349, 0.672095716, 0.3193032146, -0.0347761326, 0.880890429, 0.6379359365, 0.5533177257, 1.124715209, + -0.0711953193, 0.0823010355, 1.5953356028, -1.1492849588, -0.2697221935, 2.5629601479, -0.4678767622, 0.3748208582, + -0.3017410338, -1.1595700979, 0.984841466, -1.5886949301, 2.1473009586, -0.432054162, 0.335120976, 1.1572041512, + -1.6510055065, 1.476315856, -0.8780969977, 0.7521370649, 0.7664933801, 0.6427647471, 0.6748605967, -2.1987223625, + -0.7755331993, -0.6144747734, 0.1226312146, -0.0433201976, -0.9534757137, -0.7053830028, -0.2736400366, -1.21372962, + 0.6272516251, -0.197333917, 0.1871281117, -2.7975583076, -0.1932645291, -2.1384193897, 0.0670402572, -1.4602125883, + -0.1883114576, -1.9900075197, -0.1766163856, 1.3107856512, 0.8267203569, 1.0474450588, -0.4156937301, 1.4552435875, + -0.9403783679, 0.6154562235, 0.9041082263, -1.4211113453, 0.154235974, 0.2054781765, 1.2778793573, -0.1201702952, + -1.3128867149, 0.3029603362, -0.7522927523, -0.9131040573, 0.928286314, 0.5733796358, -0.9316766858, 0.2135121375, + -0.7382605076, -0.5023554564, -0.9460375905, -0.3469051719, 0.3816500604, -1.3926203251, -0.7923706174, -0.8669332266, + -0.5555337071, 0.2142671943, 0.5651071072, -0.6646097302, -1.0670479536, 0.04960832, -2.2859947681, -0.5420932174, + -0.8602784276, 1.1403759718, 0.536891818, 0.4115375876, 1.4746530056, -0.2967051268, -0.4382048249, -0.7692515254, + -2.1632175446, 0.2171597481, -0.4031183124, 0.8962494135, 0.9963235855, -0.8190985322, -0.327156961, -1.8990769386, + 0.3499003649, -2.3797082901, 0.6820656061, -1.0557612181, -0.1580118388, 1.3777353764, -0.9384363294, 0.2778090537, + -0.7599855661, 0.0350417122, 0.339105159, 1.069309473, -0.461057961, -0.7098724842, 0.2182071954, 0.8414065838, + 0.8761809468, -1.2011101246, -0.0909584537, 1.6314455271, -0.3418768048, -0.6599820852, 0.062771976, 1.9397410154, + -2.6317727566, -0.9709402919, 0.2281691581, -0.1328415275, 0.3824462593, 0.9747131467, 2.1028826237, -1.8011776209, + -0.7046427727, 0.1276893169, 1.2597452402, -0.2805773318, 1.7098058462, -0.508759737, 1.8857795, -1.8405008316, + 0.1865903288, -0.4646588862, -0.8164331317, -0.6990193129, -1.1148481369, -1.410484314, -0.5799752474, -0.4449983835, + -2.0007512569, -1.572196722, -1.9587359428, -0.6990004778, 0.0577918403, -1.6206052303, -0.1327113062, -2.6066644192, + 0.3853771985, 0.7883592248, -0.4743609726, 0.3637579083, 1.8269271851, -0.3550509512, -0.3871345222, 1.4265280962, + 1.3550875187, -0.01440736, 0.0320234708, 0.2594887316, -1.8753159046, 1.299087286, 1.1652233601, -0.4094679356, + 0.6926257014, 0.4886541367, -0.3665470183, 0.9978932142, -0.4778836966, -2.4469411373, 0.8460370302, 0.2013505697, + -1.1429011822, 2.0269160271, -0.3998430967, 0.2654949725, -1.095746994, -0.7791578174, 0.7616731524, 1.3665670156, + -0.8782943487, -0.8286035061, -1.1778832674, -0.8636802435, -0.0061646109, 2.2168614864, 1.0119706392, -0.2279826999, + -0.6041381359, -0.608514905, -1.2976219654, -0.2709690034, -0.0114500197, -0.4823000729, 1.2648714781, -1.3784844875, + 0.6856546402, 0.9222300053, 0.6966942549, -1.8633707762, -0.1454697251, -1.3210371733, -0.1145494431, 1.1239894629, + 1.9604538679, -0.4812983572, -0.5667022467, -1.0941706896, -0.7513188124, -0.4788049757, -0.9990747571, -0.7967398167, + -0.9379817247, -0.9230493903, 1.3206555843, -2.1616094112, 0.9471166134, 1.4199587107, 0.6445659995, 0.4961482286, + 0.4532108903, -1.3316901922, 0.6221421361, 1.1318142414, 0.5100553036, -0.1593082994, -0.7789161801, -2.7416522503, + 1.1332864761, -1.0270265341, -0.2043064237, -0.8484025598, -0.126359731, -0.1946774721, 0.6200547814, -0.6168873906, + -1.3963674307, -0.6660103798, 0.0967090577, -1.6318593025, 0.2810838521, 0.6856861115, -1.1412400007, 0.3920578957, + 0.3876029253, -2.0110924244, -0.6093295813, 0.8308763504, -0.6013477445, 1.475643754, 0.3031979799, -0.5353441238, + -0.5915081501, 0.9075561166, 1.1504007578, 0.6115757227, -2.3925230503, -1.2824686766, -1.335162878, 1.1867614985, + 0.2219233513, -0.80807513, 0.5201536417, -0.1467103064, 1.5671451092, 1.9779373407, -0.2780325115, 0.3241499662, + 1.5429707766, 0.3520541489, -0.0514822975, -0.1410155594, -1.3119984865, -0.3331850767, -1.3207861185, -0.0688070208, + -0.1959996521, -1.2634282112, 0.4501601756, -0.6468436122, 0.6385756135, 0.4816366732, 0.8377054334, -1.1855635643, + 0.5892620087, -0.6773741245, -1.5393686295, 1.6592665911, 1.1991732121, -0.8384900093, -0.0617964156, -0.3647063375, + 0.0483825915, 0.697745204, 0.8587312102, -0.5782601237, 0.6752809882, 1.8073829412, -0.4694879651, 2.685434103, + -0.7661315799, -0.1617361754, -1.6490541697, -0.3861537874, 1.194372654, 0.4325670004, 0.9196245074, 1.1767194271, + -1.1586842537, 2.2081480026, -0.8941178322, -0.145777449, -1.3551640511, -2.0796351433, -1.5357860327, 1.3167635202, + -0.4685901403, -1.3264200687, -1.1433360577, 0.5723722577, -1.3153508902, -0.0003914612, 0.4272823632, -0.6007682085, + -0.9464733005, 0.9466275573, -0.3957338631, 0.3242906034, 0.3518322706, -0.9805750847, -1.4119974375, 0.9316169024, + -0.0752965063, -0.3946371078, 1.03444314, 0.599147141, 0.7365334034, -0.837454319, -0.017191695, 0.5245986581, + -0.2836663425, -0.7435886264, -0.5999352336, 0.5393315554, -0.9004894495, 0.9330707788, -1.038808465, 0.5326125026, + -0.2157468051, 0.3797125518, -1.6414234638, -1.5240204334, -0.1943216473, 2.4012343884, -0.1102185398, 1.0404075384, + -0.5839586258, -0.6843239665, -1.0446710587, 1.3564828634, -1.1882144213, 0.4350872934, 0.2158848494, -0.399723202, + 1.3127151728, 0.7766410112, 0.0745480806, 0.870105505, 0.5700027943, -1.992995739, 1.7805351019, 0.0368345529, + -0.2137983143, 0.9791098237, 0.3465301096, -0.1790597886, 0.7861873507, 0.2161410749, 1.910949111, 0.0643576086, + 1.4099440575, 0.51432693, -1.2256814241, 0.3933446407, 0.966717422, -0.0542557761, -0.6940347552, -0.1299740523, + -0.6604279876, 0.0753633454, -0.4645026326, -0.9675666094, 0.64194417, 1.0465860367, 0.4986249506, -0.3357897699, + -1.8439725637, -1.3316335678, -0.4952035844, 1.555793047, 0.6939328909, -0.9675522447, 0.1987546235, 0.0348333046, + -1.2145023346, -1.0559561253, -1.6981366873, -0.6445525289, -0.433930546, 1.0280379057, 1.7661401033, -1.4261125326, + -1.328785181, -0.8939813375, 1.1151138544, 0.4468123913, 0.5887181163, -0.0540989488, 0.8927987218, 2.1387660503, + 1.7823724747, 1.7096697092, 1.8147362471, -0.1693580598, -1.075381875, 1.2679872513, -2.0095827579, 0.6978594661, + -1.2827425003, 0.334469974, -0.040559724, 0.178597182, -1.7131185532, 0.801559031, -0.7889513373, 0.4382426143, + -0.2685180604, -0.4353355765, 0.8980778456, 1.4425247908, -0.6797144413, -0.5390772223, -1.233269453, -0.8271765709, + 1.2962095737, -0.685787499, 0.4101184309, -1.0391228199, 0.4739780426, 0.203710109, 1.2740825415, -1.7347189188, + 1.1883305311, -0.2816534936, -0.0767895505, -0.139481172, -0.5756545663, -0.4448460937, -0.9648231268, 2.6027748585, + -1.0214937925, -0.8026785254, 0.1019904837, 0.0143244155, -0.4809729457, -1.2737265825, -0.5467684269, 1.2570265532, + 0.7116396427, 1.6483726501, 0.4744225144, -1.3267292976, -0.0733655021, -1.5249861479, -0.0464469939, 2.2251887321, + 0.2355747223, 1.229254961, -0.825357914, -0.1976063699, -2.2327098846, -0.2294290513, -0.878723979, -0.4248799682, + -0.9848347306, 1.1690719128, -1.8133636713, -1.8084857464, 0.0479786545, 2.0665719509, -2.6742475033, 0.5344931483, + 0.0683459938, -0.4919559062, -0.9514514208, -1.2987574339, -2.8886623383, -0.0731047243, -1.9328001738, 0.9243254066, + 0.4220359325, -0.7849935889, -1.3458760977, 0.3226920068, -0.6062769294, -1.6259837151, 0.6885620952, 1.7813590765, + 0.0121325897, 1.6976926327, -0.3455361128, 1.0504717827, 0.1753101647, -0.0284505151, -0.2338887602, 0.7708004713, + 0.4418765306, 1.2308294773, -0.5319422483, -0.461245656, 0.3082421124, -0.5902484655, -0.2054267824, 1.5642417669, + 0.1995749623, -1.3234007359, -0.6998391747, -0.6464892626, -0.392688185, 0.1428338438, 0.2082134038, -0.3770585358, + 0.2527660429, 2.2772750854, 0.6177937388, -1.6407494545, 0.0468776226, -0.986561954, -0.4993889332, 0.869169116, + -0.271432519, 0.9959207177, -0.4606694579, -1.1768029928, 1.0289868116, 0.7226113081, -0.7540940642, -0.7165128589, + -0.5451242924, -0.4123264253, -0.8378821611, 1.1969192028, 0.2376316488, 0.662037909, -1.2662197351, -0.2605038881, + -0.4416389763, 1.629938364, 0.0120546557, 0.1751725078, 2.0253489017, -2.0747103691, 0.7142991424, -0.8726304173, + 0.1750395596, 0.4198315442, 0.8568505049, -0.7676183581, 1.2397425175, 0.6619054079, -0.8535833955, 0.9861800671, + -1.0405623913, -0.2410328388, 1.1349664927, 0.2311729193, 0.1398157328, 0.7055028081, -1.5441834927, -0.2105818391, + 0.865852952, -1.5761580467, -1.0042510033, -0.6100757122, -0.1319507957, 1.9316471815, -0.3888913393, 1.4629999399, + 0.3790009618, -0.7812678814, 0.2428106815, 1.7966394424, 0.2591165304, -1.0846961737, 0.4639006257, -0.3702415228, + -1.3542098999, -2.5225086212, 2.1170349121, 0.2919540107, 1.5617704391, -0.5720227361, 0.1448655128, 0.8777965903, + -0.7311284542, 0.6961936951, -0.2438761741, 0.2898792624, -1.0157407522, 0.1055957079, 1.5368494987, -0.2627255023, + 0.5305185318, -0.9444933534, 0.9583199024, -0.4513328671, -1.7957193851, -1.9104524851, 1.5604406595, 1.05876863, + -0.2916118801, -0.8341334462, 0.6081914306, 0.5385888815, 0.2649672329, 1.9931534529, 1.7101278305, -0.3339462578, + -1.6201473475, 0.4781301022, 1.6592991352, 1.8929585218, -0.5796220303, 0.1620042324, -0.919179678, 0.2226093709, + -0.3510306776, 2.5146825314, 1.3014285564, -0.5516109467, -1.7102047205, -0.8960490823, -0.9496671557, -0.4185546935, + -0.6126506329, 2.3513891697, -0.5045138597, 0.2073156387, -0.0403192304, 0.2158572525, 1.6789017916, -0.0491207652, + -0.0926134512, -0.9717449546, 0.3141212761, -0.1822118014, 1.559894681, 0.1269149184, -1.7584841251, -0.2879258394, + -0.5144426823, 0.8904726505, 0.0560838953, 1.0901510715, -0.3769854307, -0.6356492043, -0.2561465204, -0.2323470414, + 0.8959264159, 1.5302934647, 0.9458421469, -0.75895679, 1.3199381828, 0.2553999126, 0.0001370502, -0.9755280614, + 0.1034968719, -0.5387631655, 1.16416502, 1.5335197449, -0.0891886353, 1.0386070013, 0.3652443886, 0.4225503206, + -0.9608186483, 0.2354464382, 0.8191389441, -0.0019620592, -2.2598648071, 0.2033568025, 0.9071549177, 1.6220998764, + 0.0620047227, 1.1191365719, -0.6640503407, -0.2967987657, -0.1196853444, 0.4721096754, -1.5424871445, 2.5747241974, + -0.9410291314, 0.2411335409, -0.5882598758, 0.5838999152, 1.2239956856, 0.0473095626, 0.0269213933, -1.7474669218, + -0.1254788041, 0.639051795, -0.1682768017, 0.1148226485, -0.8987408876, -1.1397955418, 1.4998438358, 1.4500621557, + 0.1748585701, -0.1256774962, 0.6514495611, -1.3195337057, -1.3019288778, 0.1573456079, 1.197625041, -0.643481195, + -0.071953319, -0.0295303278, -0.9087253809, 0.6040388942, -0.3942040503, 0.8656547666, 1.3265830278, 0.1610490084, + -0.5010558963, -1.4810063839, -0.2897340357, -0.6645922661, 0.2873976231, 0.0032383415, -2.2635951042, 0.7036095262, + 0.2958571017, 1.3461945057, 0.4321117997, -1.031516552, 0.90343678, -1.0506396294, 0.363396138, 1.2920157909, + -0.1767129153, 0.958302021, 1.9570393562, -0.0153314872, 0.2814647257, -0.3974483609, -0.2976866663, -1.3961068392, + -1.6619836092, -1.175011158, -0.342702806, 0.8588997126, -1.0289971828, -0.1670207977, -0.222649157, 0.5565141439, + 0.3041157424, 0.1601631343, -0.6869891882, 0.0558025204, -0.15178065, 0.2210749239, -1.2610491514, 0.496558547, + -0.8622374535, -0.2092900723, 1.9283560514, 2.0117387772, 1.236412406, -1.2820222378, -0.5927175283, -1.2122610807, + -0.2559721172, 0.3717762232, -0.4502603412, 1.7123154402, 0.3875474632, 0.6138361096, 0.4190999269, 0.7165051699, + -0.9974407554, 0.619525969, -1.8539083004, -0.8086301088, -1.7899594307, 0.5038084984, -0.9629930854, 1.073776722, + -0.0268682484, -1.5845243931, 1.5086864233, 0.6216324568, 1.9804166555, -1.008636713, 2.2385258675, -0.5203742385, + -0.8196234703, 1.116543293, -1.280862093, 1.2763589621, -0.9164367914, 0.126875326, 2.0863809586, -0.7245088816, + -1.2106389999, 1.2202898264, -0.8158519864, 0.8383903503, 1.5530946255, -0.1538568288, 0.2419621795, -1.1090013981, + 2.5024588108, 0.1697666496, 1.0527145863, 0.6301341653, -1.3145409822, -0.583060503, -0.2038480788, -0.1603022367, + -0.6039440632, 0.6921498179, 0.5524765253, 0.8396931291, 0.4275787771, 0.5381883383, -0.031862624, 2.2095665932, + 1.4112273455, 0.0706845075, 0.3475209475, 0.3752060533, -0.5024744272, 0.447191298, 0.3937501609, -0.4151968062, + 1.5611482859, 1.7722326517, -0.4225720763 +] diff --git a/js/node/test/testdata/squeezenet.output0.json b/js/node/test/testdata/squeezenet.output0.json index 94045ff7fee50..42e6527ba5d55 100644 --- a/js/node/test/testdata/squeezenet.output0.json +++ b/js/node/test/testdata/squeezenet.output0.json @@ -1 +1,109 @@ -[3.30038e-05,0.00240706,6.37481e-05,0.000747601,0.00150019,0.00483676,0.0225981,1.00831e-06,1.09255e-05,4.99784e-07,3.56863e-06,2.39458e-07,4.05555e-06,4.125e-05,2.7419e-05,7.0522e-06,3.13915e-06,1.43166e-06,3.89503e-05,9.59126e-07,4.04121e-05,1.44285e-05,3.57193e-06,1.79007e-06,9.95244e-07,8.06105e-06,0.000350968,1.53663e-05,6.4513e-06,0.0012472,5.49246e-06,1.79511e-05,3.62395e-05,0.0108226,0.00336278,0.000252014,0.011735,0.00017365,0.00218219,6.12092e-07,2.211e-05,3.50974e-05,8.72451e-06,1.4989e-05,0.000234527,0.0068162,2.21972e-05,0.00151148,0.000432405,0.00197073,0.00484609,2.82015e-07,0.000228804,3.39269e-05,0.000382118,4.70206e-06,1.1913e-05,2.23097e-06,0.00685201,3.31187e-05,0.000336639,2.79269e-05,0.000199309,0.00317999,0.000113043,0.00128387,0.00155218,0.000923709,0.000240535,0.00253241,2.83529e-05,0.00133016,2.0673e-06,0.000300064,2.02181e-05,0.00039521,0.00180333,0.00526178,0.00672168,0.00165962,1.2716e-06,2.40267e-05,7.0667e-05,8.33176e-06,5.46878e-06,0.000184338,0.000245671,9.80053e-07,2.81819e-07,4.73917e-06,2.19647e-07,2.98639e-06,7.11458e-07,8.84598e-07,1.8719e-05,2.70032e-07,1.23598e-05,3.72205e-07,1.26912e-05,2.47628e-05,1.79942e-06,0.000126682,4.94588e-05,0.0102678,1.58766e-06,2.19647e-07,7.29778e-05,0.00677497,3.8126e-05,0.000435307,2.3404e-06,0.132055,6.02585e-05,5.89881e-05,3.03346e-05,1.3844e-06,5.24638e-05,0.000825554,0.00500985,0.000136619,1.46635e-05,7.55287e-05,3.5211e-06,1.12535e-06,8.07075e-05,0.000272862,0.00321429,1.22513e-05,2.93262e-05,1.48032e-05,5.36753e-06,7.58634e-05,0.000112646,5.02625e-05,3.24783e-05,1.71106e-05,4.81191e-06,0.000141718,7.72931e-05,2.35613e-06,0.00012713,8.392e-05,2.60958e-05,3.85835e-06,1.14518e-05,6.8281e-06,1.35586e-06,6.49379e-05,1.18678e-05,0.00341779,2.61765e-05,2.91871e-05,2.34715e-06,0.000145097,4.2643e-05,0.000197889,7.91037e-05,9.83346e-06,3.39639e-07,3.03579e-06,1.17122e-05,2.06673e-05,0.000150339,0.00020328,1.04667e-05,6.91003e-07,4.05582e-06,5.44345e-07,4.66852e-05,1.18521e-05,3.95729e-07,5.05007e-05,7.4885e-05,6.45486e-06,1.28401e-06,2.01996e-06,5.05181e-06,4.2517e-06,3.03471e-05,2.77055e-05,2.64213e-05,1.88586e-05,1.32463e-05,6.96098e-06,2.90003e-06,3.06301e-06,1.12795e-06,9.59877e-07,2.86446e-06,1.51577e-06,2.72648e-06,6.72556e-06,6.54428e-05,4.4694e-07,1.67012e-06,1.66503e-06,1.55137e-06,1.84327e-06,2.53061e-07,1.05396e-05,1.86334e-05,7.70901e-07,1.40602e-05,0.000601871,0.000196814,8.07645e-07,6.08658e-06,3.00776e-06,2.60375e-06,2.38763e-05,5.27953e-06,1.07436e-05,2.97076e-05,2.28515e-05,7.25094e-06,0.000152125,1.37768e-06,1.51765e-05,2.42037e-06,6.10985e-07,1.8458e-06,7.37962e-06,1.46182e-05,2.51198e-05,3.27596e-07,1.4108e-06,6.25375e-06,2.68018e-06,2.69143e-05,6.06063e-06,0.000106133,1.46003e-05,4.83793e-07,1.34876e-05,2.31457e-06,6.68377e-06,4.43177e-06,7.89233e-05,6.51787e-06,3.42215e-06,2.56579e-06,2.39804e-05,2.38996e-05,7.296e-06,2.30304e-07,6.76266e-05,1.74024e-06,1.99373e-05,6.47423e-07,3.43456e-06,1.10051e-05,1.23886e-06,2.60883e-05,3.96144e-06,4.10274e-05,9.1267e-07,5.01223e-06,0.000132038,6.39193e-05,0.000112808,1.90401e-05,8.00349e-06,7.82643e-06,2.27094e-05,1.38722e-05,4.99394e-06,2.65734e-06,7.1897e-07,3.4084e-07,2.5075e-06,9.08597e-06,1.05238e-06,2.37228e-05,8.48681e-05,0.00015608,4.96326e-06,9.76552e-05,0.00012748,1.16663e-05,0.000474339,0.000125924,9.32651e-07,6.14761e-06,1.84157e-05,2.0661e-05,2.15305e-06,1.90258e-06,6.07655e-06,2.72655e-06,5.12465e-07,3.07574e-06,5.70555e-06,3.70938e-05,3.89949e-06,5.05176e-06,1.89544e-06,3.55921e-05,0.000115676,8.98462e-05,5.97214e-05,2.12628e-06,6.78752e-05,4.29522e-05,1.56884e-06,1.50015e-05,0.000283533,6.39846e-07,9.70085e-05,1.88628e-05,6.64936e-07,0.000356803,8.39299e-06,5.74065e-05,7.27516e-05,0.00261427,6.00777e-05,7.12263e-05,1.26491e-06,0.000868939,0.000397627,2.35373e-05,2.28251e-07,3.06452e-07,2.19647e-07,8.73208e-07,9.02118e-07,1.382e-06,0.000156077,0.000121389,8.77277e-05,0.00316587,0.000807538,0.00204002,0.00032277,0.000302543,4.31282e-06,2.19416e-05,0.00177341,1.06765e-05,1.11829e-06,2.17968e-06,1.53142e-05,6.17556e-06,1.55956e-05,0.00168962,5.31761e-07,7.22402e-05,6.69545e-06,3.47428e-07,9.00044e-07,0.000113894,2.07959e-05,7.21104e-06,6.67658e-05,1.03238e-05,3.54474e-06,0.000450102,0.000364276,0.000164161,0.000321661,7.09733e-05,0.000874399,0.000532035,0.000946064,1.63541e-06,6.66925e-07,1.00801e-05,9.33275e-07,2.26388e-07,2.65757e-07,3.81374e-07,3.49317e-06,5.70276e-07,1.79782e-06,3.96168e-06,3.79932e-07,9.98164e-07,2.68421e-05,7.04427e-06,2.14382e-06,5.87577e-05,8.82346e-07,1.65695e-06,4.0358e-06,3.4606e-07,4.24055e-05,6.4875e-06,7.15376e-07,2.83752e-07,0.000187299,5.81318e-05,0.000161363,1.87876e-05,1.81743e-06,0.00169564,0.00922038,2.4518e-06,2.37628e-05,1.56076e-06,4.16376e-05,2.22112e-07,2.74136e-07,8.87607e-07,2.37552e-05,5.59479e-05,0.000238186,4.14247e-06,2.62818e-07,5.15268e-06,2.44908e-05,5.29226e-06,0.000488674,0.000196068,4.08526e-07,1.51241e-06,4.3665e-06,1.00193e-05,0.00267409,0.000107653,0.00136346,2.21079e-06,1.27526e-05,2.54319e-06,1.4435e-06,2.92003e-07,1.88393e-05,2.84691e-05,2.419e-06,2.81245e-06,4.00504e-06,1.22796e-05,0.000329972,7.76645e-07,8.17329e-05,0.0075691,0.000272345,3.47348e-07,1.72498e-05,0.00059095,2.19856e-07,2.97259e-05,5.70946e-05,3.50248e-06,0.000505348,2.6645e-07,1.84202e-05,0.0419757,1.19775e-06,0.000125246,3.40366e-06,1.28719e-06,7.57776e-07,0.000119444,4.55271e-06,5.57566e-06,1.85926e-05,4.23977e-07,4.13716e-07,0.000238636,0.00234118,2.00847e-05,8.80801e-07,6.20842e-05,0.000201885,4.35091e-07,0.000212658,7.93442e-07,2.56245e-07,2.86597e-07,4.9724e-05,0.000595791,3.17517e-07,8.28939e-07,2.65091e-05,0.000116553,1.81658e-06,2.7075e-07,1.80121e-06,0.00671099,2.88147e-07,3.31486e-05,0.000103751,7.2855e-07,2.59299e-06,8.29641e-06,2.8954e-05,3.82065e-07,1.58906e-05,7.5345e-06,1.88725e-06,2.20567e-07,2.64769e-07,0.000704843,7.48047e-06,7.07716e-06,3.24475e-06,0.000229562,1.04762e-05,2.75673e-07,5.60927e-05,0.000670869,5.25422e-06,7.67442e-06,3.99764e-05,2.02051e-05,4.53167e-06,4.54816e-06,8.61861e-06,1.01519e-06,3.966e-07,4.79176e-05,2.37593e-07,4.46226e-07,2.95312e-07,3.49675e-07,5.54914e-06,0.000167629,2.35371e-05,9.46391e-07,0.000218146,0.000695242,0.000177932,2.13105e-05,1.37545e-05,4.23788e-07,0.00279564,1.56444e-06,2.2925e-07,1.14547e-05,0.000838637,1.94783e-05,2.22737e-06,0.00269667,0.000587703,0.000242132,2.39822e-07,7.88235e-07,2.19647e-07,3.96023e-05,0.000942217,0.000199963,2.98115e-07,0.000114011,2.78705e-06,1.49864e-06,5.44075e-05,6.16242e-06,2.25314e-07,2.90298e-07,0.0563553,2.19647e-07,0.00041908,2.45128e-06,0.000216731,0.000220765,7.10003e-06,0.00314294,4.27621e-06,1.21116e-06,3.57691e-06,2.19866e-07,2.77421e-05,1.33204e-06,3.23081e-06,4.16899e-07,3.00326e-05,2.23953e-07,5.92595e-06,2.59079e-07,3.95766e-07,6.23917e-05,2.3895e-07,2.59321e-05,8.72774e-07,1.46551e-05,2.37166e-07,4.85887e-07,5.91673e-06,1.5925e-05,5.48621e-07,1.29689e-06,2.42972e-07,2.58339e-07,7.07611e-06,9.51068e-06,9.89523e-05,4.30986e-05,6.61681e-05,0.000377943,3.49729e-06,5.08567e-06,0.100853,1.0899e-05,1.52226e-06,4.74296e-07,2.98692e-07,1.48701e-05,2.72196e-07,8.15167e-07,0.000854144,4.81532e-05,7.4703e-05,2.33504e-07,4.01518e-07,4.65201e-05,0.000614875,2.85956e-05,7.15136e-07,7.42455e-06,6.68006e-05,0.00338469,0.000373694,3.92498e-07,8.70474e-07,1.46042e-06,2.39024e-05,4.56457e-06,7.64493e-05,2.58002e-05,0.000290927,5.9998e-05,1.0992e-06,7.49084e-06,0.000270476,1.07873e-05,8.33809e-07,0.000378689,2.31458e-07,6.9372e-06,3.28015e-05,1.66907e-05,0.000668885,3.65539e-05,4.492e-06,6.63593e-07,1.4175e-05,5.3893e-06,1.25146e-06,8.96112e-06,1.56599e-05,0.000639026,5.25124e-07,4.33042e-07,9.55997e-07,7.20381e-05,1.8769e-06,0.00591436,0.0142333,5.78227e-05,5.58047e-06,1.15346e-05,0.000191445,2.50651e-06,5.37143e-05,1.61384e-06,2.10579e-05,2.82325e-07,0.000562215,7.31107e-05,0.000185458,9.19092e-06,2.24806e-07,0.00122146,3.34874e-06,3.1904e-05,2.49545e-07,0.000527636,5.26276e-07,4.21786e-06,0.0981208,2.38566e-07,8.18549e-06,7.68801e-06,1.79197e-05,0.000124411,2.81175e-07,2.37748e-07,0.000151226,1.34168e-05,1.33137e-06,0.00140345,4.45635e-05,0.000123665,4.43648e-07,3.71324e-07,2.56964e-06,6.44212e-05,3.52327e-06,0.000145309,2.28818e-05,8.69461e-07,7.64946e-06,0.00124899,1.95925e-06,1.82611e-05,0.000128566,6.53273e-05,6.7991e-05,6.96028e-07,6.85518e-07,0.0999919,0.000171717,2.45555e-07,2.20557e-07,6.95378e-05,2.36021e-07,6.83477e-05,2.71391e-06,0.000297223,6.14753e-05,3.98032e-05,0.000202539,0.0211731,0.000109838,0.000204545,9.54438e-07,0.000132366,3.13755e-07,1.7683e-05,3.05367e-06,8.13365e-05,8.62639e-05,5.79236e-05,1.72338e-05,5.51936e-06,2.37853e-05,2.38583e-06,7.3413e-05,0.0365768,0.000350949,3.97942e-07,0.000166126,2.62828e-07,0.000119214,2.59006e-07,0.000244027,2.20833e-07,2.69368e-05,2.08583e-06,6.67744e-05,1.15667e-06,0.00231503,2.33152e-05,2.7366e-06,3.53167e-05,2.03656e-05,6.22545e-05,1.2622e-06,1.95008e-05,0.000707449,0.0022835,2.14179e-05,6.99508e-06,7.92588e-05,6.41414e-07,0.00251094,2.4398e-05,6.75114e-07,8.26408e-07,4.115e-07,3.32577e-05,3.77059e-05,2.97349e-07,1.01808e-06,1.14929e-06,2.92594e-07,3.70965e-07,0.000210903,7.57253e-06,0.000671497,2.57833e-05,4.24406e-05,0.000115908,1.37939e-05,1.4135e-05,8.69344e-05,1.36076e-06,5.66509e-06,9.69823e-06,2.20374e-07,3.79278e-06,3.20583e-07,3.48438e-05,2.23965e-05,3.01125e-05,3.28908e-07,1.8647e-06,3.01314e-06,3.23302e-07,0.000202211,1.46115e-06,0.000135461,1.81886e-06,0.00220625,0.0100632,4.68942e-06,5.13535e-06,0.000709504,6.95215e-05,1.05843e-05,2.19647e-07,5.92654e-05,7.72615e-06,1.30853e-05,0.00035334,2.60654e-05,1.70955e-06,2.0768e-05,1.40579e-06,5.68283e-05,2.28711e-07,3.1642e-05,0.000870124,0.000250426,8.21169e-06,0.00041412,5.17313e-05,2.19648e-07,2.58391e-05,4.21913e-07,2.75305e-07,2.02621e-06,5.78907e-06,2.06269e-06,1.4204e-05,2.70143e-06,1.57078e-06,6.74661e-07,3.99983e-05,5.39646e-06,2.84113e-05,1.13468e-05,2.61936e-05,0.000348203,1.3984e-05,5.74484e-06,4.46801e-06,3.07966e-07,0.000679563,4.93455e-07,0.000668054,0.000694075,0.000109974,2.86653e-07,0.000163258,0.00102639,2.56474e-05,5.7945e-06,3.08543e-06,2.04542e-05,6.7593e-06,1.35856e-05,1.80622e-05,1.42013e-06,2.31614e-05,9.83816e-06,2.23705e-07,8.88647e-06,2.99608e-07,2.06588e-06,4.90268e-07,0.00990751,5.02635e-05,2.991e-05,6.99187e-06,2.19762e-07,4.38414e-06,1.94361e-05,0.0118964,4.71439e-07,3.48044e-06,3.06884e-06,8.46049e-07,2.84214e-06,2.61806e-07,8.08323e-07,0.000378208,1.44979e-06,2.48622e-07,2.63819e-05,2.31254e-06,3.73906e-07,7.06266e-07,8.55171e-05,0.000463059,0.00519056,2.3448e-07,7.43225e-05,1.92467e-05,3.02221e-07,3.01564e-06,1.00334e-05,0.00138754,5.73591e-05,4.46816e-06,0.0001871,0.000772637,5.25714e-05,0.000222698,0.00011766,6.29192e-05,0.00104611,0.000150696,2.85862e-06,0.0213807,7.83114e-05,1.22906e-05,2.89221e-05,0.00558292,1.80053e-05,6.28303e-05,0.000187814,2.22076e-05,0.019121,1.44428e-05,3.48743e-05,4.95461e-06,2.01822e-06,0.000154636,3.96885e-06,1.15581e-05,0.0217395,0.00106286,1.47636e-05,7.78406e-07,0.000182114,3.64317e-05,2.45914e-05,0.000218702,1.77705e-05,3.88213e-05,6.38537e-06,6.49358e-06,6.16064e-07,9.00705e-06,6.60956e-06,3.62144e-05,3.51255e-06,3.13264e-05,6.02226e-07,9.67834e-06,1.9771e-06,8.10685e-06,4.62282e-06,1.3246e-06,7.31311e-07,7.34991e-06,2.95626e-05,3.87789e-05,1.1141e-05,2.79194e-06,3.32728e-05,8.18433e-06,2.76908e-07,2.60412e-07,4.92324e-06,2.33574e-07,3.27539e-06,1.97259e-05,2.95824e-06,2.76007e-06,0.00158116,5.84331e-07,1.81017e-06,1.5555e-05,7.36356e-07,0.000136843,1.42929e-05,0.000111963,0.000735147,0.000271685,0.00143252,6.72216e-05,0.000145032,0.000286367,0.000266569,0.000258938,0.00629227,0.000196766,0.00144487,0.000658506,6.19422e-06,7.89064e-06,0.000167934,3.46261e-05,2.56693e-05,1.69383e-06,1.93635e-05,1.4758e-05,1.72688e-06,2.75854e-07,7.37269e-07,6.86722e-07,2.20309e-07,3.00458e-07,8.82893e-06,5.07031e-06,3.30098e-05,5.39999e-06,0.0041139] +[ + 3.30038e-5, 0.00240706, 6.37481e-5, 0.000747601, 0.00150019, 0.00483676, 0.0225981, 1.00831e-6, 1.09255e-5, + 4.99784e-7, 3.56863e-6, 2.39458e-7, 4.05555e-6, 4.125e-5, 2.7419e-5, 7.0522e-6, 3.13915e-6, 1.43166e-6, 3.89503e-5, + 9.59126e-7, 4.04121e-5, 1.44285e-5, 3.57193e-6, 1.79007e-6, 9.95244e-7, 8.06105e-6, 0.000350968, 1.53663e-5, + 6.4513e-6, 0.0012472, 5.49246e-6, 1.79511e-5, 3.62395e-5, 0.0108226, 0.00336278, 0.000252014, 0.011735, 0.00017365, + 0.00218219, 6.12092e-7, 2.211e-5, 3.50974e-5, 8.72451e-6, 1.4989e-5, 0.000234527, 0.0068162, 2.21972e-5, 0.00151148, + 0.000432405, 0.00197073, 0.00484609, 2.82015e-7, 0.000228804, 3.39269e-5, 0.000382118, 4.70206e-6, 1.1913e-5, + 2.23097e-6, 0.00685201, 3.31187e-5, 0.000336639, 2.79269e-5, 0.000199309, 0.00317999, 0.000113043, 0.00128387, + 0.00155218, 0.000923709, 0.000240535, 0.00253241, 2.83529e-5, 0.00133016, 2.0673e-6, 0.000300064, 2.02181e-5, + 0.00039521, 0.00180333, 0.00526178, 0.00672168, 0.00165962, 1.2716e-6, 2.40267e-5, 7.0667e-5, 8.33176e-6, 5.46878e-6, + 0.000184338, 0.000245671, 9.80053e-7, 2.81819e-7, 4.73917e-6, 2.19647e-7, 2.98639e-6, 7.11458e-7, 8.84598e-7, + 1.8719e-5, 2.70032e-7, 1.23598e-5, 3.72205e-7, 1.26912e-5, 2.47628e-5, 1.79942e-6, 0.000126682, 4.94588e-5, 0.0102678, + 1.58766e-6, 2.19647e-7, 7.29778e-5, 0.00677497, 3.8126e-5, 0.000435307, 2.3404e-6, 0.132055, 6.02585e-5, 5.89881e-5, + 3.03346e-5, 1.3844e-6, 5.24638e-5, 0.000825554, 0.00500985, 0.000136619, 1.46635e-5, 7.55287e-5, 3.5211e-6, + 1.12535e-6, 8.07075e-5, 0.000272862, 0.00321429, 1.22513e-5, 2.93262e-5, 1.48032e-5, 5.36753e-6, 7.58634e-5, + 0.000112646, 5.02625e-5, 3.24783e-5, 1.71106e-5, 4.81191e-6, 0.000141718, 7.72931e-5, 2.35613e-6, 0.00012713, + 8.392e-5, 2.60958e-5, 3.85835e-6, 1.14518e-5, 6.8281e-6, 1.35586e-6, 6.49379e-5, 1.18678e-5, 0.00341779, 2.61765e-5, + 2.91871e-5, 2.34715e-6, 0.000145097, 4.2643e-5, 0.000197889, 7.91037e-5, 9.83346e-6, 3.39639e-7, 3.03579e-6, + 1.17122e-5, 2.06673e-5, 0.000150339, 0.00020328, 1.04667e-5, 6.91003e-7, 4.05582e-6, 5.44345e-7, 4.66852e-5, + 1.18521e-5, 3.95729e-7, 5.05007e-5, 7.4885e-5, 6.45486e-6, 1.28401e-6, 2.01996e-6, 5.05181e-6, 4.2517e-6, 3.03471e-5, + 2.77055e-5, 2.64213e-5, 1.88586e-5, 1.32463e-5, 6.96098e-6, 2.90003e-6, 3.06301e-6, 1.12795e-6, 9.59877e-7, + 2.86446e-6, 1.51577e-6, 2.72648e-6, 6.72556e-6, 6.54428e-5, 4.4694e-7, 1.67012e-6, 1.66503e-6, 1.55137e-6, 1.84327e-6, + 2.53061e-7, 1.05396e-5, 1.86334e-5, 7.70901e-7, 1.40602e-5, 0.000601871, 0.000196814, 8.07645e-7, 6.08658e-6, + 3.00776e-6, 2.60375e-6, 2.38763e-5, 5.27953e-6, 1.07436e-5, 2.97076e-5, 2.28515e-5, 7.25094e-6, 0.000152125, + 1.37768e-6, 1.51765e-5, 2.42037e-6, 6.10985e-7, 1.8458e-6, 7.37962e-6, 1.46182e-5, 2.51198e-5, 3.27596e-7, 1.4108e-6, + 6.25375e-6, 2.68018e-6, 2.69143e-5, 6.06063e-6, 0.000106133, 1.46003e-5, 4.83793e-7, 1.34876e-5, 2.31457e-6, + 6.68377e-6, 4.43177e-6, 7.89233e-5, 6.51787e-6, 3.42215e-6, 2.56579e-6, 2.39804e-5, 2.38996e-5, 7.296e-6, 2.30304e-7, + 6.76266e-5, 1.74024e-6, 1.99373e-5, 6.47423e-7, 3.43456e-6, 1.10051e-5, 1.23886e-6, 2.60883e-5, 3.96144e-6, + 4.10274e-5, 9.1267e-7, 5.01223e-6, 0.000132038, 6.39193e-5, 0.000112808, 1.90401e-5, 8.00349e-6, 7.82643e-6, + 2.27094e-5, 1.38722e-5, 4.99394e-6, 2.65734e-6, 7.1897e-7, 3.4084e-7, 2.5075e-6, 9.08597e-6, 1.05238e-6, 2.37228e-5, + 8.48681e-5, 0.00015608, 4.96326e-6, 9.76552e-5, 0.00012748, 1.16663e-5, 0.000474339, 0.000125924, 9.32651e-7, + 6.14761e-6, 1.84157e-5, 2.0661e-5, 2.15305e-6, 1.90258e-6, 6.07655e-6, 2.72655e-6, 5.12465e-7, 3.07574e-6, 5.70555e-6, + 3.70938e-5, 3.89949e-6, 5.05176e-6, 1.89544e-6, 3.55921e-5, 0.000115676, 8.98462e-5, 5.97214e-5, 2.12628e-6, + 6.78752e-5, 4.29522e-5, 1.56884e-6, 1.50015e-5, 0.000283533, 6.39846e-7, 9.70085e-5, 1.88628e-5, 6.64936e-7, + 0.000356803, 8.39299e-6, 5.74065e-5, 7.27516e-5, 0.00261427, 6.00777e-5, 7.12263e-5, 1.26491e-6, 0.000868939, + 0.000397627, 2.35373e-5, 2.28251e-7, 3.06452e-7, 2.19647e-7, 8.73208e-7, 9.02118e-7, 1.382e-6, 0.000156077, + 0.000121389, 8.77277e-5, 0.00316587, 0.000807538, 0.00204002, 0.00032277, 0.000302543, 4.31282e-6, 2.19416e-5, + 0.00177341, 1.06765e-5, 1.11829e-6, 2.17968e-6, 1.53142e-5, 6.17556e-6, 1.55956e-5, 0.00168962, 5.31761e-7, + 7.22402e-5, 6.69545e-6, 3.47428e-7, 9.00044e-7, 0.000113894, 2.07959e-5, 7.21104e-6, 6.67658e-5, 1.03238e-5, + 3.54474e-6, 0.000450102, 0.000364276, 0.000164161, 0.000321661, 7.09733e-5, 0.000874399, 0.000532035, 0.000946064, + 1.63541e-6, 6.66925e-7, 1.00801e-5, 9.33275e-7, 2.26388e-7, 2.65757e-7, 3.81374e-7, 3.49317e-6, 5.70276e-7, + 1.79782e-6, 3.96168e-6, 3.79932e-7, 9.98164e-7, 2.68421e-5, 7.04427e-6, 2.14382e-6, 5.87577e-5, 8.82346e-7, + 1.65695e-6, 4.0358e-6, 3.4606e-7, 4.24055e-5, 6.4875e-6, 7.15376e-7, 2.83752e-7, 0.000187299, 5.81318e-5, 0.000161363, + 1.87876e-5, 1.81743e-6, 0.00169564, 0.00922038, 2.4518e-6, 2.37628e-5, 1.56076e-6, 4.16376e-5, 2.22112e-7, 2.74136e-7, + 8.87607e-7, 2.37552e-5, 5.59479e-5, 0.000238186, 4.14247e-6, 2.62818e-7, 5.15268e-6, 2.44908e-5, 5.29226e-6, + 0.000488674, 0.000196068, 4.08526e-7, 1.51241e-6, 4.3665e-6, 1.00193e-5, 0.00267409, 0.000107653, 0.00136346, + 2.21079e-6, 1.27526e-5, 2.54319e-6, 1.4435e-6, 2.92003e-7, 1.88393e-5, 2.84691e-5, 2.419e-6, 2.81245e-6, 4.00504e-6, + 1.22796e-5, 0.000329972, 7.76645e-7, 8.17329e-5, 0.0075691, 0.000272345, 3.47348e-7, 1.72498e-5, 0.00059095, + 2.19856e-7, 2.97259e-5, 5.70946e-5, 3.50248e-6, 0.000505348, 2.6645e-7, 1.84202e-5, 0.0419757, 1.19775e-6, + 0.000125246, 3.40366e-6, 1.28719e-6, 7.57776e-7, 0.000119444, 4.55271e-6, 5.57566e-6, 1.85926e-5, 4.23977e-7, + 4.13716e-7, 0.000238636, 0.00234118, 2.00847e-5, 8.80801e-7, 6.20842e-5, 0.000201885, 4.35091e-7, 0.000212658, + 7.93442e-7, 2.56245e-7, 2.86597e-7, 4.9724e-5, 0.000595791, 3.17517e-7, 8.28939e-7, 2.65091e-5, 0.000116553, + 1.81658e-6, 2.7075e-7, 1.80121e-6, 0.00671099, 2.88147e-7, 3.31486e-5, 0.000103751, 7.2855e-7, 2.59299e-6, 8.29641e-6, + 2.8954e-5, 3.82065e-7, 1.58906e-5, 7.5345e-6, 1.88725e-6, 2.20567e-7, 2.64769e-7, 0.000704843, 7.48047e-6, 7.07716e-6, + 3.24475e-6, 0.000229562, 1.04762e-5, 2.75673e-7, 5.60927e-5, 0.000670869, 5.25422e-6, 7.67442e-6, 3.99764e-5, + 2.02051e-5, 4.53167e-6, 4.54816e-6, 8.61861e-6, 1.01519e-6, 3.966e-7, 4.79176e-5, 2.37593e-7, 4.46226e-7, 2.95312e-7, + 3.49675e-7, 5.54914e-6, 0.000167629, 2.35371e-5, 9.46391e-7, 0.000218146, 0.000695242, 0.000177932, 2.13105e-5, + 1.37545e-5, 4.23788e-7, 0.00279564, 1.56444e-6, 2.2925e-7, 1.14547e-5, 0.000838637, 1.94783e-5, 2.22737e-6, + 0.00269667, 0.000587703, 0.000242132, 2.39822e-7, 7.88235e-7, 2.19647e-7, 3.96023e-5, 0.000942217, 0.000199963, + 2.98115e-7, 0.000114011, 2.78705e-6, 1.49864e-6, 5.44075e-5, 6.16242e-6, 2.25314e-7, 2.90298e-7, 0.0563553, + 2.19647e-7, 0.00041908, 2.45128e-6, 0.000216731, 0.000220765, 7.10003e-6, 0.00314294, 4.27621e-6, 1.21116e-6, + 3.57691e-6, 2.19866e-7, 2.77421e-5, 1.33204e-6, 3.23081e-6, 4.16899e-7, 3.00326e-5, 2.23953e-7, 5.92595e-6, + 2.59079e-7, 3.95766e-7, 6.23917e-5, 2.3895e-7, 2.59321e-5, 8.72774e-7, 1.46551e-5, 2.37166e-7, 4.85887e-7, 5.91673e-6, + 1.5925e-5, 5.48621e-7, 1.29689e-6, 2.42972e-7, 2.58339e-7, 7.07611e-6, 9.51068e-6, 9.89523e-5, 4.30986e-5, 6.61681e-5, + 0.000377943, 3.49729e-6, 5.08567e-6, 0.100853, 1.0899e-5, 1.52226e-6, 4.74296e-7, 2.98692e-7, 1.48701e-5, 2.72196e-7, + 8.15167e-7, 0.000854144, 4.81532e-5, 7.4703e-5, 2.33504e-7, 4.01518e-7, 4.65201e-5, 0.000614875, 2.85956e-5, + 7.15136e-7, 7.42455e-6, 6.68006e-5, 0.00338469, 0.000373694, 3.92498e-7, 8.70474e-7, 1.46042e-6, 2.39024e-5, + 4.56457e-6, 7.64493e-5, 2.58002e-5, 0.000290927, 5.9998e-5, 1.0992e-6, 7.49084e-6, 0.000270476, 1.07873e-5, + 8.33809e-7, 0.000378689, 2.31458e-7, 6.9372e-6, 3.28015e-5, 1.66907e-5, 0.000668885, 3.65539e-5, 4.492e-6, 6.63593e-7, + 1.4175e-5, 5.3893e-6, 1.25146e-6, 8.96112e-6, 1.56599e-5, 0.000639026, 5.25124e-7, 4.33042e-7, 9.55997e-7, 7.20381e-5, + 1.8769e-6, 0.00591436, 0.0142333, 5.78227e-5, 5.58047e-6, 1.15346e-5, 0.000191445, 2.50651e-6, 5.37143e-5, 1.61384e-6, + 2.10579e-5, 2.82325e-7, 0.000562215, 7.31107e-5, 0.000185458, 9.19092e-6, 2.24806e-7, 0.00122146, 3.34874e-6, + 3.1904e-5, 2.49545e-7, 0.000527636, 5.26276e-7, 4.21786e-6, 0.0981208, 2.38566e-7, 8.18549e-6, 7.68801e-6, 1.79197e-5, + 0.000124411, 2.81175e-7, 2.37748e-7, 0.000151226, 1.34168e-5, 1.33137e-6, 0.00140345, 4.45635e-5, 0.000123665, + 4.43648e-7, 3.71324e-7, 2.56964e-6, 6.44212e-5, 3.52327e-6, 0.000145309, 2.28818e-5, 8.69461e-7, 7.64946e-6, + 0.00124899, 1.95925e-6, 1.82611e-5, 0.000128566, 6.53273e-5, 6.7991e-5, 6.96028e-7, 6.85518e-7, 0.0999919, + 0.000171717, 2.45555e-7, 2.20557e-7, 6.95378e-5, 2.36021e-7, 6.83477e-5, 2.71391e-6, 0.000297223, 6.14753e-5, + 3.98032e-5, 0.000202539, 0.0211731, 0.000109838, 0.000204545, 9.54438e-7, 0.000132366, 3.13755e-7, 1.7683e-5, + 3.05367e-6, 8.13365e-5, 8.62639e-5, 5.79236e-5, 1.72338e-5, 5.51936e-6, 2.37853e-5, 2.38583e-6, 7.3413e-5, 0.0365768, + 0.000350949, 3.97942e-7, 0.000166126, 2.62828e-7, 0.000119214, 2.59006e-7, 0.000244027, 2.20833e-7, 2.69368e-5, + 2.08583e-6, 6.67744e-5, 1.15667e-6, 0.00231503, 2.33152e-5, 2.7366e-6, 3.53167e-5, 2.03656e-5, 6.22545e-5, 1.2622e-6, + 1.95008e-5, 0.000707449, 0.0022835, 2.14179e-5, 6.99508e-6, 7.92588e-5, 6.41414e-7, 0.00251094, 2.4398e-5, 6.75114e-7, + 8.26408e-7, 4.115e-7, 3.32577e-5, 3.77059e-5, 2.97349e-7, 1.01808e-6, 1.14929e-6, 2.92594e-7, 3.70965e-7, 0.000210903, + 7.57253e-6, 0.000671497, 2.57833e-5, 4.24406e-5, 0.000115908, 1.37939e-5, 1.4135e-5, 8.69344e-5, 1.36076e-6, + 5.66509e-6, 9.69823e-6, 2.20374e-7, 3.79278e-6, 3.20583e-7, 3.48438e-5, 2.23965e-5, 3.01125e-5, 3.28908e-7, 1.8647e-6, + 3.01314e-6, 3.23302e-7, 0.000202211, 1.46115e-6, 0.000135461, 1.81886e-6, 0.00220625, 0.0100632, 4.68942e-6, + 5.13535e-6, 0.000709504, 6.95215e-5, 1.05843e-5, 2.19647e-7, 5.92654e-5, 7.72615e-6, 1.30853e-5, 0.00035334, + 2.60654e-5, 1.70955e-6, 2.0768e-5, 1.40579e-6, 5.68283e-5, 2.28711e-7, 3.1642e-5, 0.000870124, 0.000250426, + 8.21169e-6, 0.00041412, 5.17313e-5, 2.19648e-7, 2.58391e-5, 4.21913e-7, 2.75305e-7, 2.02621e-6, 5.78907e-6, + 2.06269e-6, 1.4204e-5, 2.70143e-6, 1.57078e-6, 6.74661e-7, 3.99983e-5, 5.39646e-6, 2.84113e-5, 1.13468e-5, 2.61936e-5, + 0.000348203, 1.3984e-5, 5.74484e-6, 4.46801e-6, 3.07966e-7, 0.000679563, 4.93455e-7, 0.000668054, 0.000694075, + 0.000109974, 2.86653e-7, 0.000163258, 0.00102639, 2.56474e-5, 5.7945e-6, 3.08543e-6, 2.04542e-5, 6.7593e-6, + 1.35856e-5, 1.80622e-5, 1.42013e-6, 2.31614e-5, 9.83816e-6, 2.23705e-7, 8.88647e-6, 2.99608e-7, 2.06588e-6, + 4.90268e-7, 0.00990751, 5.02635e-5, 2.991e-5, 6.99187e-6, 2.19762e-7, 4.38414e-6, 1.94361e-5, 0.0118964, 4.71439e-7, + 3.48044e-6, 3.06884e-6, 8.46049e-7, 2.84214e-6, 2.61806e-7, 8.08323e-7, 0.000378208, 1.44979e-6, 2.48622e-7, + 2.63819e-5, 2.31254e-6, 3.73906e-7, 7.06266e-7, 8.55171e-5, 0.000463059, 0.00519056, 2.3448e-7, 7.43225e-5, + 1.92467e-5, 3.02221e-7, 3.01564e-6, 1.00334e-5, 0.00138754, 5.73591e-5, 4.46816e-6, 0.0001871, 0.000772637, + 5.25714e-5, 0.000222698, 0.00011766, 6.29192e-5, 0.00104611, 0.000150696, 2.85862e-6, 0.0213807, 7.83114e-5, + 1.22906e-5, 2.89221e-5, 0.00558292, 1.80053e-5, 6.28303e-5, 0.000187814, 2.22076e-5, 0.019121, 1.44428e-5, 3.48743e-5, + 4.95461e-6, 2.01822e-6, 0.000154636, 3.96885e-6, 1.15581e-5, 0.0217395, 0.00106286, 1.47636e-5, 7.78406e-7, + 0.000182114, 3.64317e-5, 2.45914e-5, 0.000218702, 1.77705e-5, 3.88213e-5, 6.38537e-6, 6.49358e-6, 6.16064e-7, + 9.00705e-6, 6.60956e-6, 3.62144e-5, 3.51255e-6, 3.13264e-5, 6.02226e-7, 9.67834e-6, 1.9771e-6, 8.10685e-6, 4.62282e-6, + 1.3246e-6, 7.31311e-7, 7.34991e-6, 2.95626e-5, 3.87789e-5, 1.1141e-5, 2.79194e-6, 3.32728e-5, 8.18433e-6, 2.76908e-7, + 2.60412e-7, 4.92324e-6, 2.33574e-7, 3.27539e-6, 1.97259e-5, 2.95824e-6, 2.76007e-6, 0.00158116, 5.84331e-7, + 1.81017e-6, 1.5555e-5, 7.36356e-7, 0.000136843, 1.42929e-5, 0.000111963, 0.000735147, 0.000271685, 0.00143252, + 6.72216e-5, 0.000145032, 0.000286367, 0.000266569, 0.000258938, 0.00629227, 0.000196766, 0.00144487, 0.000658506, + 6.19422e-6, 7.89064e-6, 0.000167934, 3.46261e-5, 2.56693e-5, 1.69383e-6, 1.93635e-5, 1.4758e-5, 1.72688e-6, + 2.75854e-7, 7.37269e-7, 6.86722e-7, 2.20309e-7, 3.00458e-7, 8.82893e-6, 5.07031e-6, 3.30098e-5, 5.39999e-6, 0.0041139 +] diff --git a/js/package-lock.json b/js/package-lock.json index deb97d1a076c7..be7b3c9cd7d30 100644 --- a/js/package-lock.json +++ b/js/package-lock.json @@ -7,6 +7,7 @@ "license": "MIT", "devDependencies": { "@types/fs-extra": "^11.0.1", + "@types/mocha": "^10.0.1", "@types/node": "^18.14.6", "@types/npmlog": "^4.1.4", "@typescript-eslint/eslint-plugin": "^5.54.1", @@ -21,8 +22,10 @@ "eslint-plugin-unicorn": "^46.0.0", "fs-extra": "^11.1.0", "jszip": "^3.10.1", + "mocha": "^10.2.0", "node-polyfill-webpack-plugin": "^2.0.1", "npmlog": "^7.0.1", + "prettier": "^3.0.0", "terser": "^5.16.5", "ts-loader": "^9.4.2", "typescript": "^4.9.5", @@ -397,6 +400,12 @@ "@types/node": "*" } }, + "node_modules/@types/mocha": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz", + "integrity": "sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==", + "dev": true + }, "node_modules/@types/node": { "version": "18.14.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz", @@ -887,6 +896,15 @@ "ajv": "^6.9.1" } }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -911,6 +929,19 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", @@ -1098,6 +1129,15 @@ "node": "*" } }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/bn.js": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", @@ -1132,6 +1172,12 @@ "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", "dev": true }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, "node_modules/browserify-aes": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", @@ -1343,6 +1389,18 @@ "node": ">=6" } }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001460", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001460.tgz", @@ -1375,6 +1433,45 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/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, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/chrome-trace-event": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", @@ -1446,6 +1543,17 @@ "node": ">=0.8.0" } }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, "node_modules/clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", @@ -1634,6 +1742,18 @@ } } }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -1672,6 +1792,15 @@ "minimalistic-assert": "^1.0.0" } }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/diffie-hellman": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", @@ -2460,6 +2589,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, "node_modules/flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -2508,6 +2646,20 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -2560,6 +2712,15 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-intrinsic": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", @@ -2862,6 +3023,15 @@ "minimalistic-assert": "^1.0.1" } }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, "node_modules/hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -3060,6 +3230,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-boolean-object": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", @@ -3236,6 +3418,15 @@ "node": ">=8" } }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "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", @@ -3325,6 +3516,18 @@ "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==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", @@ -3589,6 +3792,22 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "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, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -3722,6 +3941,129 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "dev": true, + "dependencies": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "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" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/minimatch/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, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/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 + }, + "node_modules/mocha/node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/mocha/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, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/mrmime": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", @@ -3737,6 +4079,18 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -3877,6 +4231,15 @@ "semver": "bin/semver" } }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/npmlog": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-7.0.1.tgz", @@ -4254,6 +4617,21 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.0.tgz", + "integrity": "sha512-zBf5eHpwHOGPC47h0zrPyNn+eAEIdEzfywMoYn2XPi0P44Zp0tSq64rq0xAREh4auw2cJZHo9QUob+NqCQky4g==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -4473,6 +4851,18 @@ "util-deprecate": "~1.0.1" } }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/rechoir": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", @@ -4544,6 +4934,15 @@ "jsesc": "bin/jsesc" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", @@ -5603,9 +6002,9 @@ "dev": true }, "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", + "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -5631,6 +6030,29 @@ "webpack": "^4.0.0 || ^5.0.0" } }, + "node_modules/workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "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, + "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", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -5667,12 +6089,63 @@ "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, + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -5981,6 +6454,12 @@ "@types/node": "*" } }, + "@types/mocha": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz", + "integrity": "sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==", + "dev": true + }, "@types/node": { "version": "18.14.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz", @@ -6337,6 +6816,12 @@ "dev": true, "requires": {} }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -6352,6 +6837,16 @@ "color-convert": "^2.0.1" } }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, "aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", @@ -6493,6 +6988,12 @@ "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", "dev": true }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, "bn.js": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", @@ -6524,6 +7025,12 @@ "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", "dev": true }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, "browserify-aes": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", @@ -6678,6 +7185,12 @@ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, "caniuse-lite": { "version": "1.0.30001460", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001460.tgz", @@ -6694,6 +7207,33 @@ "supports-color": "^7.1.0" } }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "dependencies": { + "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, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, "chrome-trace-event": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", @@ -6744,6 +7284,17 @@ } } }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, "clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", @@ -6908,6 +7459,12 @@ "ms": "2.1.2" } }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + }, "deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -6940,6 +7497,12 @@ "minimalistic-assert": "^1.0.0" } }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true + }, "diffie-hellman": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", @@ -7574,6 +8137,12 @@ "path-exists": "^4.0.0" } }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, "flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -7616,6 +8185,13 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -7656,6 +8232,12 @@ "wide-align": "^1.1.5" } }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, "get-intrinsic": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", @@ -7865,6 +8447,12 @@ "minimalistic-assert": "^1.0.1" } }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -8007,6 +8595,15 @@ "has-bigints": "^1.0.1" } }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, "is-boolean-object": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", @@ -8117,6 +8714,12 @@ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + }, "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -8176,6 +8779,12 @@ "has-tostringtag": "^1.0.0" } }, + "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 + }, "is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", @@ -8384,6 +8993,16 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "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, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + } + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -8492,6 +9111,106 @@ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true }, + "mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "dev": true, + "requires": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "dependencies": { + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "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" + }, + "dependencies": { + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + }, + "dependencies": { + "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, + "requires": { + "balanced-match": "^1.0.0" + } + } + } + }, + "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 + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "mrmime": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", @@ -8504,6 +9223,12 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -8616,6 +9341,12 @@ } } }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, "npmlog": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-7.0.1.tgz", @@ -8893,6 +9624,12 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, + "prettier": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.0.tgz", + "integrity": "sha512-zBf5eHpwHOGPC47h0zrPyNn+eAEIdEzfywMoYn2XPi0P44Zp0tSq64rq0xAREh4auw2cJZHo9QUob+NqCQky4g==", + "dev": true + }, "process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -9061,6 +9798,15 @@ "util-deprecate": "~1.0.1" } }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, "rechoir": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", @@ -9110,6 +9856,12 @@ } } }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, "resolve": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", @@ -9895,9 +10647,9 @@ "dev": true }, "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", + "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", "dev": true }, "worker-loader": { @@ -9910,6 +10662,23 @@ "schema-utils": "^3.0.0" } }, + "workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "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, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -9929,12 +10698,51 @@ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "dev": true }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + } + }, "yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/js/package.json b/js/package.json index 0d57a1d86bf1f..82d644ae6570f 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,7 @@ { "devDependencies": { "@types/fs-extra": "^11.0.1", + "@types/mocha": "^10.0.1", "@types/node": "^18.14.6", "@types/npmlog": "^4.1.4", "@typescript-eslint/eslint-plugin": "^5.54.1", @@ -15,8 +16,10 @@ "eslint-plugin-unicorn": "^46.0.0", "fs-extra": "^11.1.0", "jszip": "^3.10.1", + "mocha": "^10.2.0", "node-polyfill-webpack-plugin": "^2.0.1", "npmlog": "^7.0.1", + "prettier": "^3.0.0", "terser": "^5.16.5", "ts-loader": "^9.4.2", "typescript": "^4.9.5", @@ -26,9 +29,16 @@ "worker-loader": "^3.0.8" }, "scripts": { + "prepare": "tsc --build scripts", "lint": "eslint . --ext .ts --ext .tsx", - "format": "clang-format --glob=\"{scripts/**/*.ts,common/lib/**/*.ts,node/{lib,script,test}/**/*.ts,node/src/**/*.{cc,h},web/{lib,script,test}/**/*.ts,react_native/{android,example,ios,lib}/**/*.{ts,mm,java}}\" --style=file -i", - "prepare-node-tests": "tsc --build scripts && node ./scripts/prepare-onnx-node-tests" + "format:ts": "clang-format --glob=\"{scripts/**/*.ts,common/{lib,test}/**/*.ts,node/{lib,script,test}/**/*.ts,web/{lib,script,test}/**/*.ts,react_native/{android,example,ios,lib}/**/*.{ts,tsx}}\" --style=file -i", + "format:js": "clang-format --glob=\"{{,common,node,web,react_native}/{*,.*}.{,m,c}js,web/test/e2e/**/*.{,m,c}js}\" --style=file -i", + "format:cf": "clang-format --glob=\"{node/src/**/*.{cc,h},react_native/{android,example,ios,lib}/**/*.{mm,java}}\" --style=file -i", + "format:json": "prettier \"**/*.{json,jsonc}\" --write", + "format:md": "prettier \"**/*.md\" --write", + "format": "npm run format:ts && npm run format:js && npm run format:cf && npm run format:json && npm run format:md", + "prepare-node-tests": "node ./scripts/prepare-onnx-node-tests", + "update-version": "node ./scripts/update-version" }, "license": "MIT" } diff --git a/js/react_native/README.md b/js/react_native/README.md index 2f08356a84dee..b45182d16a3fc 100644 --- a/js/react_native/README.md +++ b/js/react_native/README.md @@ -28,6 +28,7 @@ const result = session.run(input, ['num_detection:0', 'detection_classes:0']) ``` Refer to [ONNX Runtime JavaScript examples](https://github.com/microsoft/onnxruntime-inference-examples/tree/main/js) for samples and tutorials. The ONNX Runtime React Native library does not currently support the following features: + - Tensors with unsigned data types, with the exception of uint8 on Android devices - Model loading using ArrayBuffer diff --git a/js/react_native/android/CMakeLists.txt b/js/react_native/android/CMakeLists.txt new file mode 100644 index 0000000000000..98f30daac6372 --- /dev/null +++ b/js/react_native/android/CMakeLists.txt @@ -0,0 +1,37 @@ +project(OnnxruntimeJSIHelper) +cmake_minimum_required(VERSION 3.9.0) + +set (PACKAGE_NAME "onnxruntime-react-native") +set (BUILD_DIR ${CMAKE_SOURCE_DIR}/build) +set(CMAKE_VERBOSE_MAKEFILE ON) +set(CMAKE_CXX_STANDARD 17) + +file(TO_CMAKE_PATH "${NODE_MODULES_DIR}/react-native/ReactCommon/jsi/jsi/jsi.cpp" libPath) + +include_directories( + "${NODE_MODULES_DIR}/react-native/React" + "${NODE_MODULES_DIR}/react-native/React/Base" + "${NODE_MODULES_DIR}/react-native/ReactCommon/jsi" +) + +add_library(onnxruntimejsihelper + SHARED + ${libPath} + src/main/cpp/cpp-adapter.cpp +) + +# Configure C++ 17 +set_target_properties( + onnxruntimejsihelper PROPERTIES + CXX_STANDARD 17 + CXX_EXTENSIONS OFF + POSITION_INDEPENDENT_CODE ON +) + +find_library(log-lib log) + +target_link_libraries( + onnxruntimejsihelper + ${log-lib} # <-- Logcat logger + android # <-- Android JNI core +) diff --git a/js/react_native/android/build.gradle b/js/react_native/android/build.gradle index 4c8a318234772..7a99a0a2671d5 100644 --- a/js/react_native/android/build.gradle +++ b/js/react_native/android/build.gradle @@ -1,3 +1,5 @@ +import java.nio.file.Paths + buildscript { repositories { google() @@ -20,6 +22,53 @@ def getExtOrIntegerDefault(name) { return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties['OnnxruntimeModule_' + name]).toInteger() } +def reactNativeArchitectures() { + def value = project.getProperties().get("reactNativeArchitectures") + return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] +} + +def resolveBuildType() { + Gradle gradle = getGradle() + String tskReqStr = gradle.getStartParameter().getTaskRequests()['args'].toString() + return tskReqStr.contains('Release') ? 'release' : 'debug' +} + +static def findNodeModules(baseDir) { + def basePath = baseDir.toPath().normalize() + while (basePath) { + def nodeModulesPath = Paths.get(basePath.toString(), "node_modules") + def reactNativePath = Paths.get(nodeModulesPath.toString(), "react-native") + if (nodeModulesPath.toFile().exists() && reactNativePath.toFile().exists()) { + return nodeModulesPath.toString() + } + basePath = basePath.getParent() + } + throw new GradleException("onnxruntime-react-native: Failed to find node_modules/ path!") +} + +def nodeModules = findNodeModules(projectDir); + +def checkIfOrtExtensionsEnabled() { + // locate user's project dir + def reactnativeRootDir = project.rootDir.parentFile + // get package.json file in root directory + def packageJsonFile = new File(reactnativeRootDir, 'package.json') + // read field 'onnxruntimeExtensionsEnabled' + if (packageJsonFile.exists()) { + def packageJsonContents = packageJsonFile.getText() + def packageJson = new groovy.json.JsonSlurper().parseText(packageJsonContents) + return packageJson.onnxruntimeExtensionsEnabled == "true" + } else { + logger.warn("Could not find package.json file in the expected directory: ${reactnativeRootDir}. ONNX Runtime Extensions will not be enabled.") + } + return false +} + +boolean ortExtensionsEnabled = checkIfOrtExtensionsEnabled() + +def REACT_NATIVE_VERSION = ['node', '--print', "JSON.parse(require('fs').readFileSync(require.resolve('react-native/package.json'), 'utf-8')).version"].execute(null, rootDir).text.trim() +def REACT_NATIVE_MINOR_VERSION = REACT_NATIVE_VERSION.split("\\.")[1].toInteger() + android { compileSdkVersion getExtOrIntegerDefault('compileSdkVersion') buildToolsVersion getExtOrDefault('buildToolsVersion') @@ -29,6 +78,44 @@ android { versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + externalNativeBuild { + cmake { + cppFlags "-O2 -frtti -fexceptions -Wall -Wno-unused-variable -fstack-protector-all" + if (REACT_NATIVE_MINOR_VERSION >= 71) { + // fabricjni required c++_shared + arguments "-DANDROID_STL=c++_shared", "-DNODE_MODULES_DIR=${nodeModules}", "-DORT_EXTENSIONS_ENABLED=${ortExtensionsEnabled}" + } else { + arguments "-DNODE_MODULES_DIR=${nodeModules}", "-DORT_EXTENSIONS_ENABLED=${ortExtensionsEnabled}" + } + abiFilters (*reactNativeArchitectures()) + } + } + } + + if (rootProject.hasProperty("ndkPath")) { + ndkPath rootProject.ext.ndkPath + } + if (rootProject.hasProperty("ndkVersion")) { + ndkVersion rootProject.ext.ndkVersion + } + + buildFeatures { + prefab true + } + + externalNativeBuild { + cmake { + path "CMakeLists.txt" + } + } + + packagingOptions { + doNotStrip resolveBuildType() == 'debug' ? "**/**/*.so" : '' + excludes = [ + "META-INF", + "META-INF/**", + "**/libjsi.so", + ] } buildTypes { @@ -43,6 +130,17 @@ android { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } + + sourceSets { + main { + java.srcDirs = ['src/main/java/'] + if (ortExtensionsEnabled) { + java.exclude '**/OnnxruntimeExtensionsDisabled.java' + } else { + java.exclude '**/OnnxruntimeExtensionsEnabled.java' + } + } + } } repositories { @@ -120,8 +218,6 @@ repositories { } } -def REACT_NATIVE_VERSION = new File(['node', '--print', "JSON.parse(require('fs').readFileSync(require.resolve('react-native/package.json'), 'utf-8')).version"].execute(null, rootDir).text.trim()) - dependencies { api "com.facebook.react:react-native:" + REACT_NATIVE_VERSION api "org.mockito:mockito-core:2.28.2" @@ -136,4 +232,9 @@ dependencies { // Mobile build: // implementation "com.microsoft.onnxruntime:onnxruntime-mobile:latest.integration@aar" implementation "com.microsoft.onnxruntime:onnxruntime-android:latest.integration@aar" + + // By default it will just include onnxruntime full aar package + if (ortExtensionsEnabled) { + implementation "com.microsoft.onnxruntime:onnxruntime-extensions-android:latest.integration@aar" + } } diff --git a/js/react_native/android/src/androidTest/java/ai/onnxruntime/reactnative/FakeBlobModule.java b/js/react_native/android/src/androidTest/java/ai/onnxruntime/reactnative/FakeBlobModule.java new file mode 100644 index 0000000000000..82d063ad51e3f --- /dev/null +++ b/js/react_native/android/src/androidTest/java/ai/onnxruntime/reactnative/FakeBlobModule.java @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package ai.onnxruntime.reactnative; + +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.JavaOnlyMap; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.modules.blob.BlobModule; + +public class FakeBlobModule extends BlobModule { + + public FakeBlobModule(ReactApplicationContext context) { super(null); } + + @Override + public String getName() { + return "BlobModule"; + } + + public JavaOnlyMap testCreateData(byte[] bytes) { + String blobId = store(bytes); + JavaOnlyMap data = new JavaOnlyMap(); + data.putString("blobId", blobId); + data.putInt("offset", 0); + data.putInt("size", bytes.length); + return data; + } + + public byte[] testGetData(ReadableMap data) { + String blobId = data.getString("blobId"); + int offset = data.getInt("offset"); + int size = data.getInt("size"); + return resolve(blobId, offset, size); + } +} diff --git a/js/react_native/android/src/androidTest/java/ai/onnxruntime/reactnative/OnnxruntimeModuleTest.java b/js/react_native/android/src/androidTest/java/ai/onnxruntime/reactnative/OnnxruntimeModuleTest.java index 448ece3963acf..b15b1a468ae29 100644 --- a/js/react_native/android/src/androidTest/java/ai/onnxruntime/reactnative/OnnxruntimeModuleTest.java +++ b/js/react_native/android/src/androidTest/java/ai/onnxruntime/reactnative/OnnxruntimeModuleTest.java @@ -10,11 +10,15 @@ import android.util.Base64; import androidx.test.platform.app.InstrumentationRegistry; import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.CatalystInstance; import com.facebook.react.bridge.JavaOnlyArray; import com.facebook.react.bridge.JavaOnlyMap; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.WritableMap; +import com.facebook.react.modules.blob.BlobModule; +import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -28,12 +32,33 @@ public class OnnxruntimeModuleTest { private ReactApplicationContext reactContext = new ReactApplicationContext(InstrumentationRegistry.getInstrumentation().getContext()); + private FakeBlobModule blobModule; + + private static byte[] getInputModelBuffer(InputStream modelStream) throws Exception { + ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream(); + + int bufferSize = 1024; + byte[] buffer = new byte[bufferSize]; + + int len; + while ((len = modelStream.read(buffer)) != -1) { + byteBuffer.write(buffer, 0, len); + } + + byte[] modelBuffer = byteBuffer.toByteArray(); + + return modelBuffer; + } + @Before - public void setUp() {} + public void setUp() { + blobModule = new FakeBlobModule(reactContext); + } @Test public void getName() throws Exception { OnnxruntimeModule ortModule = new OnnxruntimeModule(reactContext); + ortModule.blobModule = blobModule; String name = "Onnxruntime"; Assert.assertEquals(ortModule.getName(), name); } @@ -46,24 +71,29 @@ public void onnxruntime_module() throws Exception { when(Arguments.createArray()).thenAnswer(i -> new JavaOnlyArray()); OnnxruntimeModule ortModule = new OnnxruntimeModule(reactContext); + ortModule.blobModule = blobModule; + String sessionKey = ""; // test loadModel() { - InputStream modelStream = - reactContext.getResources().openRawResource(ai.onnxruntime.reactnative.test.R.raw.test_types_float); - JavaOnlyMap options = new JavaOnlyMap(); - try { - ReadableMap resultMap = ortModule.loadModel("test", modelStream, options); - ReadableArray inputNames = resultMap.getArray("inputNames"); - ReadableArray outputNames = resultMap.getArray("outputNames"); - - Assert.assertEquals(resultMap.getString("key"), "test"); - Assert.assertEquals(inputNames.size(), 1); - Assert.assertEquals(inputNames.getString(0), "input"); - Assert.assertEquals(outputNames.size(), 1); - Assert.assertEquals(outputNames.getString(0), "output"); - } catch (Exception e) { - Assert.fail(e.getMessage()); + try (InputStream modelStream = + reactContext.getResources().openRawResource(ai.onnxruntime.reactnative.test.R.raw.test_types_float);) { + byte[] modelBuffer = getInputModelBuffer(modelStream); + + JavaOnlyMap options = new JavaOnlyMap(); + try { + ReadableMap resultMap = ortModule.loadModel(modelBuffer, options); + sessionKey = resultMap.getString("key"); + ReadableArray inputNames = resultMap.getArray("inputNames"); + ReadableArray outputNames = resultMap.getArray("outputNames"); + + Assert.assertEquals(inputNames.size(), 1); + Assert.assertEquals(inputNames.getString(0), "input"); + Assert.assertEquals(outputNames.size(), 1); + Assert.assertEquals(outputNames.getString(0), "output"); + } catch (Exception e) { + Assert.fail(e.getMessage()); + } } } @@ -90,8 +120,7 @@ public void onnxruntime_module() throws Exception { floatBuffer.put(value); } floatBuffer.rewind(); - String dataEncoded = Base64.encodeToString(buffer.array(), Base64.DEFAULT); - inputTensorMap.putString("data", dataEncoded); + inputTensorMap.putMap("data", blobModule.testCreateData(buffer.array())); inputDataMap.putMap("input", inputTensorMap); } @@ -103,17 +132,16 @@ public void onnxruntime_module() throws Exception { options.putBoolean("encodeTensorData", true); try { - ReadableMap resultMap = ortModule.run("test", inputDataMap, outputNames, options); + ReadableMap resultMap = ortModule.run(sessionKey, inputDataMap, outputNames, options); ReadableMap outputMap = resultMap.getMap("output"); for (int i = 0; i < 2; ++i) { Assert.assertEquals(outputMap.getArray("dims").getInt(i), dims[i]); } Assert.assertEquals(outputMap.getString("type"), TensorHelper.JsTensorTypeFloat); - String dataEncoded = outputMap.getString("data"); - FloatBuffer buffer = ByteBuffer.wrap(Base64.decode(dataEncoded, Base64.DEFAULT)) - .order(ByteOrder.nativeOrder()) - .asFloatBuffer(); + ReadableMap data = outputMap.getMap("data"); + FloatBuffer buffer = + ByteBuffer.wrap(blobModule.testGetData(data)).order(ByteOrder.nativeOrder()).asFloatBuffer(); for (int i = 0; i < 5; ++i) { Assert.assertEquals(buffer.get(i), inputData[i], 1e-6f); } @@ -121,6 +149,53 @@ public void onnxruntime_module() throws Exception { Assert.fail(e.getMessage()); } } + + // test dispose + ortModule.dispose(sessionKey); + } finally { + mockSession.finishMocking(); + } + } + + @Test + public void onnxruntime_module_append_nnapi() throws Exception { + MockitoSession mockSession = mockitoSession().mockStatic(Arguments.class).startMocking(); + try { + when(Arguments.createMap()).thenAnswer(i -> new JavaOnlyMap()); + when(Arguments.createArray()).thenAnswer(i -> new JavaOnlyArray()); + + OnnxruntimeModule ortModule = new OnnxruntimeModule(reactContext); + ortModule.blobModule = blobModule; + String sessionKey = ""; + + // test loadModel() with nnapi ep options + + try (InputStream modelStream = + reactContext.getResources().openRawResource(ai.onnxruntime.reactnative.test.R.raw.test_types_float);) { + + byte[] modelBuffer = getInputModelBuffer(modelStream); + + // register with nnapi ep options + JavaOnlyMap options = new JavaOnlyMap(); + JavaOnlyArray epArray = new JavaOnlyArray(); + epArray.pushString("nnapi"); + options.putArray("executionProviders", epArray); + + try { + ReadableMap resultMap = ortModule.loadModel(modelBuffer, options); + sessionKey = resultMap.getString("key"); + ReadableArray inputNames = resultMap.getArray("inputNames"); + ReadableArray outputNames = resultMap.getArray("outputNames"); + + Assert.assertEquals(inputNames.size(), 1); + Assert.assertEquals(inputNames.getString(0), "input"); + Assert.assertEquals(outputNames.size(), 1); + Assert.assertEquals(outputNames.getString(0), "output"); + } catch (Exception e) { + Assert.fail(e.getMessage()); + } + } + ortModule.dispose(sessionKey); } finally { mockSession.finishMocking(); } diff --git a/js/react_native/android/src/androidTest/java/ai/onnxruntime/reactnative/TensorHelperTest.java b/js/react_native/android/src/androidTest/java/ai/onnxruntime/reactnative/TensorHelperTest.java index f8caae96bbf86..72518488e6682 100644 --- a/js/react_native/android/src/androidTest/java/ai/onnxruntime/reactnative/TensorHelperTest.java +++ b/js/react_native/android/src/androidTest/java/ai/onnxruntime/reactnative/TensorHelperTest.java @@ -20,7 +20,9 @@ import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.JavaOnlyArray; import com.facebook.react.bridge.JavaOnlyMap; +import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.modules.blob.BlobModule; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.nio.ByteBuffer; @@ -39,11 +41,17 @@ @SmallTest public class TensorHelperTest { + private ReactApplicationContext reactContext = + new ReactApplicationContext(InstrumentationRegistry.getInstrumentation().getContext()); + private OrtEnvironment ortEnvironment; + private FakeBlobModule blobModule; + @Before public void setUp() { ortEnvironment = OrtEnvironment.getEnvironment("TensorHelperTest"); + blobModule = new FakeBlobModule(reactContext); } @Test @@ -64,10 +72,9 @@ public void createInputTensor_float32() throws Exception { dataFloatBuffer.put(Float.MIN_VALUE); dataFloatBuffer.put(2.0f); dataFloatBuffer.put(Float.MAX_VALUE); - String dataEncoded = Base64.encodeToString(dataByteBuffer.array(), Base64.DEFAULT); - inputTensorMap.putString("data", dataEncoded); + inputTensorMap.putMap("data", blobModule.testCreateData(dataByteBuffer.array())); - OnnxTensor inputTensor = TensorHelper.createInputTensor(inputTensorMap, ortEnvironment); + OnnxTensor inputTensor = TensorHelper.createInputTensor(blobModule, inputTensorMap, ortEnvironment); Assert.assertEquals(inputTensor.getInfo().onnxType, TensorInfo.OnnxTensorType.ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT); Assert.assertEquals(outputTensor.getInfo().onnxType, TensorInfo.OnnxTensorType.ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT); @@ -94,10 +101,9 @@ public void createInputTensor_int8() throws Exception { dataByteBuffer.put(Byte.MIN_VALUE); dataByteBuffer.put((byte)2); dataByteBuffer.put(Byte.MAX_VALUE); - String dataEncoded = Base64.encodeToString(dataByteBuffer.array(), Base64.DEFAULT); - inputTensorMap.putString("data", dataEncoded); + inputTensorMap.putMap("data", blobModule.testCreateData(dataByteBuffer.array())); - OnnxTensor inputTensor = TensorHelper.createInputTensor(inputTensorMap, ortEnvironment); + OnnxTensor inputTensor = TensorHelper.createInputTensor(blobModule, inputTensorMap, ortEnvironment); Assert.assertEquals(inputTensor.getInfo().onnxType, TensorInfo.OnnxTensorType.ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8); Assert.assertEquals(outputTensor.getInfo().onnxType, TensorInfo.OnnxTensorType.ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8); @@ -125,10 +131,9 @@ public void createInputTensor_uint8() throws Exception { dataByteBuffer.put((byte)0); dataByteBuffer.put((byte)2); dataByteBuffer.put((byte)255); - String dataEncoded = Base64.encodeToString(dataByteBuffer.array(), Base64.DEFAULT); - inputTensorMap.putString("data", dataEncoded); + inputTensorMap.putMap("data", blobModule.testCreateData(dataByteBuffer.array())); - OnnxTensor inputTensor = TensorHelper.createInputTensor(inputTensorMap, ortEnvironment); + OnnxTensor inputTensor = TensorHelper.createInputTensor(blobModule, inputTensorMap, ortEnvironment); Assert.assertEquals(inputTensor.getInfo().onnxType, TensorInfo.OnnxTensorType.ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8); Assert.assertEquals(outputTensor.getInfo().onnxType, TensorInfo.OnnxTensorType.ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8); @@ -157,10 +162,9 @@ public void createInputTensor_int32() throws Exception { dataIntBuffer.put(Integer.MIN_VALUE); dataIntBuffer.put(2); dataIntBuffer.put(Integer.MAX_VALUE); - String dataEncoded = Base64.encodeToString(dataByteBuffer.array(), Base64.DEFAULT); - inputTensorMap.putString("data", dataEncoded); + inputTensorMap.putMap("data", blobModule.testCreateData(dataByteBuffer.array())); - OnnxTensor inputTensor = TensorHelper.createInputTensor(inputTensorMap, ortEnvironment); + OnnxTensor inputTensor = TensorHelper.createInputTensor(blobModule, inputTensorMap, ortEnvironment); Assert.assertEquals(inputTensor.getInfo().onnxType, TensorInfo.OnnxTensorType.ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32); Assert.assertEquals(outputTensor.getInfo().onnxType, TensorInfo.OnnxTensorType.ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32); @@ -189,10 +193,9 @@ public void createInputTensor_int64() throws Exception { dataLongBuffer.put(Long.MIN_VALUE); dataLongBuffer.put(15000000001L); dataLongBuffer.put(Long.MAX_VALUE); - String dataEncoded = Base64.encodeToString(dataByteBuffer.array(), Base64.DEFAULT); - inputTensorMap.putString("data", dataEncoded); + inputTensorMap.putMap("data", blobModule.testCreateData(dataByteBuffer.array())); - OnnxTensor inputTensor = TensorHelper.createInputTensor(inputTensorMap, ortEnvironment); + OnnxTensor inputTensor = TensorHelper.createInputTensor(blobModule, inputTensorMap, ortEnvironment); Assert.assertEquals(inputTensor.getInfo().onnxType, TensorInfo.OnnxTensorType.ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64); Assert.assertEquals(outputTensor.getInfo().onnxType, TensorInfo.OnnxTensorType.ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64); @@ -221,10 +224,9 @@ public void createInputTensor_double() throws Exception { dataDoubleBuffer.put(Double.MIN_VALUE); dataDoubleBuffer.put(1.8e+30); dataDoubleBuffer.put(Double.MAX_VALUE); - String dataEncoded = Base64.encodeToString(dataByteBuffer.array(), Base64.DEFAULT); - inputTensorMap.putString("data", dataEncoded); + inputTensorMap.putMap("data", blobModule.testCreateData(dataByteBuffer.array())); - OnnxTensor inputTensor = TensorHelper.createInputTensor(inputTensorMap, ortEnvironment); + OnnxTensor inputTensor = TensorHelper.createInputTensor(blobModule, inputTensorMap, ortEnvironment); Assert.assertEquals(inputTensor.getInfo().onnxType, TensorInfo.OnnxTensorType.ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE); Assert.assertEquals(outputTensor.getInfo().onnxType, @@ -236,6 +238,34 @@ public void createInputTensor_double() throws Exception { outputTensor.close(); } + @Test + public void createInputTensor_bool() throws Exception { + OnnxTensor outputTensor = OnnxTensor.createTensor(ortEnvironment, new boolean[] {false, true}); + + JavaOnlyMap inputTensorMap = new JavaOnlyMap(); + + JavaOnlyArray dims = new JavaOnlyArray(); + dims.pushInt(2); + inputTensorMap.putArray("dims", dims); + + inputTensorMap.putString("type", TensorHelper.JsTensorTypeBool); + + ByteBuffer dataByteBuffer = ByteBuffer.allocate(2); + dataByteBuffer.put((byte)0); + dataByteBuffer.put((byte)1); + inputTensorMap.putMap("data", blobModule.testCreateData(dataByteBuffer.array())); + + OnnxTensor inputTensor = TensorHelper.createInputTensor(blobModule, inputTensorMap, ortEnvironment); + + Assert.assertEquals(inputTensor.getInfo().onnxType, TensorInfo.OnnxTensorType.ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL); + Assert.assertEquals(outputTensor.getInfo().onnxType, TensorInfo.OnnxTensorType.ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL); + Assert.assertEquals(inputTensor.toString(), outputTensor.toString()); + Assert.assertArrayEquals(inputTensor.getByteBuffer().array(), outputTensor.getByteBuffer().array()); + + inputTensor.close(); + outputTensor.close(); + } + @Test public void createOutputTensor_bool() throws Exception { MockitoSession mockSession = mockitoSession().mockStatic(Arguments.class).startMocking(); @@ -258,14 +288,14 @@ public void createOutputTensor_bool() throws Exception { OrtSession.Result result = session.run(container); - ReadableMap resultMap = TensorHelper.createOutputTensor(result); + ReadableMap resultMap = TensorHelper.createOutputTensor(blobModule, result); ReadableMap outputMap = resultMap.getMap("output"); for (int i = 0; i < 2; ++i) { Assert.assertEquals(outputMap.getArray("dims").getInt(i), dims[i]); } Assert.assertEquals(outputMap.getString("type"), TensorHelper.JsTensorTypeBool); - String dataEncoded = outputMap.getString("data"); - ByteBuffer buffer = ByteBuffer.wrap(Base64.decode(dataEncoded, Base64.DEFAULT)); + ReadableMap data = outputMap.getMap("data"); + ByteBuffer buffer = ByteBuffer.wrap(blobModule.testGetData(data)); for (int i = 0; i < 5; ++i) { Assert.assertEquals(buffer.get(i) == 1, inputData[i]); } @@ -298,15 +328,15 @@ public void createOutputTensor_double() throws Exception { OrtSession.Result result = session.run(container); - ReadableMap resultMap = TensorHelper.createOutputTensor(result); + ReadableMap resultMap = TensorHelper.createOutputTensor(blobModule, result); ReadableMap outputMap = resultMap.getMap("output"); for (int i = 0; i < 2; ++i) { Assert.assertEquals(outputMap.getArray("dims").getInt(i), dims[i]); } Assert.assertEquals(outputMap.getString("type"), TensorHelper.JsTensorTypeDouble); - String dataEncoded = outputMap.getString("data"); + ReadableMap data = outputMap.getMap("data"); DoubleBuffer buffer = - ByteBuffer.wrap(Base64.decode(dataEncoded, Base64.DEFAULT)).order(ByteOrder.nativeOrder()).asDoubleBuffer(); + ByteBuffer.wrap(blobModule.testGetData(data)).order(ByteOrder.nativeOrder()).asDoubleBuffer(); for (int i = 0; i < 5; ++i) { Assert.assertEquals(buffer.get(i), inputData[i], 1e-6f); } @@ -339,15 +369,14 @@ public void createOutputTensor_float() throws Exception { OrtSession.Result result = session.run(container); - ReadableMap resultMap = TensorHelper.createOutputTensor(result); + ReadableMap resultMap = TensorHelper.createOutputTensor(blobModule, result); ReadableMap outputMap = resultMap.getMap("output"); for (int i = 0; i < 2; ++i) { Assert.assertEquals(outputMap.getArray("dims").getInt(i), dims[i]); } Assert.assertEquals(outputMap.getString("type"), TensorHelper.JsTensorTypeFloat); - String dataEncoded = outputMap.getString("data"); - FloatBuffer buffer = - ByteBuffer.wrap(Base64.decode(dataEncoded, Base64.DEFAULT)).order(ByteOrder.nativeOrder()).asFloatBuffer(); + ReadableMap data = outputMap.getMap("data"); + FloatBuffer buffer = ByteBuffer.wrap(blobModule.testGetData(data)).order(ByteOrder.nativeOrder()).asFloatBuffer(); for (int i = 0; i < 5; ++i) { Assert.assertEquals(buffer.get(i), inputData[i], 1e-6f); } @@ -380,14 +409,14 @@ public void createOutputTensor_int8() throws Exception { OrtSession.Result result = session.run(container); - ReadableMap resultMap = TensorHelper.createOutputTensor(result); + ReadableMap resultMap = TensorHelper.createOutputTensor(blobModule, result); ReadableMap outputMap = resultMap.getMap("output"); for (int i = 0; i < 2; ++i) { Assert.assertEquals(outputMap.getArray("dims").getInt(i), dims[i]); } Assert.assertEquals(outputMap.getString("type"), TensorHelper.JsTensorTypeByte); - String dataEncoded = outputMap.getString("data"); - ByteBuffer buffer = ByteBuffer.wrap(Base64.decode(dataEncoded, Base64.DEFAULT)); + ReadableMap data = outputMap.getMap("data"); + ByteBuffer buffer = ByteBuffer.wrap(blobModule.testGetData(data)); for (int i = 0; i < 5; ++i) { Assert.assertEquals(buffer.get(i), inputData[i]); } @@ -420,15 +449,14 @@ public void createOutputTensor_int32() throws Exception { OrtSession.Result result = session.run(container); - ReadableMap resultMap = TensorHelper.createOutputTensor(result); + ReadableMap resultMap = TensorHelper.createOutputTensor(blobModule, result); ReadableMap outputMap = resultMap.getMap("output"); for (int i = 0; i < 2; ++i) { Assert.assertEquals(outputMap.getArray("dims").getInt(i), dims[i]); } Assert.assertEquals(outputMap.getString("type"), TensorHelper.JsTensorTypeInt); - String dataEncoded = outputMap.getString("data"); - IntBuffer buffer = - ByteBuffer.wrap(Base64.decode(dataEncoded, Base64.DEFAULT)).order(ByteOrder.nativeOrder()).asIntBuffer(); + ReadableMap data = outputMap.getMap("data"); + IntBuffer buffer = ByteBuffer.wrap(blobModule.testGetData(data)).order(ByteOrder.nativeOrder()).asIntBuffer(); for (int i = 0; i < 5; ++i) { Assert.assertEquals(buffer.get(i), inputData[i]); } @@ -461,15 +489,14 @@ public void createOutputTensor_int64() throws Exception { OrtSession.Result result = session.run(container); - ReadableMap resultMap = TensorHelper.createOutputTensor(result); + ReadableMap resultMap = TensorHelper.createOutputTensor(blobModule, result); ReadableMap outputMap = resultMap.getMap("output"); for (int i = 0; i < 2; ++i) { Assert.assertEquals(outputMap.getArray("dims").getInt(i), dims[i]); } Assert.assertEquals(outputMap.getString("type"), TensorHelper.JsTensorTypeLong); - String dataEncoded = outputMap.getString("data"); - LongBuffer buffer = - ByteBuffer.wrap(Base64.decode(dataEncoded, Base64.DEFAULT)).order(ByteOrder.nativeOrder()).asLongBuffer(); + ReadableMap data = outputMap.getMap("data"); + LongBuffer buffer = ByteBuffer.wrap(blobModule.testGetData(data)).order(ByteOrder.nativeOrder()).asLongBuffer(); for (int i = 0; i < 5; ++i) { Assert.assertEquals(buffer.get(i), inputData[i]); } @@ -502,14 +529,14 @@ public void createOutputTensor_uint8() throws Exception { OrtSession.Result result = session.run(container); - ReadableMap resultMap = TensorHelper.createOutputTensor(result); + ReadableMap resultMap = TensorHelper.createOutputTensor(blobModule, result); ReadableMap outputMap = resultMap.getMap("output"); for (int i = 0; i < 2; ++i) { Assert.assertEquals(outputMap.getArray("dims").getInt(i), dims[i]); } Assert.assertEquals(outputMap.getString("type"), TensorHelper.JsTensorTypeUnsignedByte); - String dataEncoded = outputMap.getString("data"); - ByteBuffer buffer = ByteBuffer.wrap(Base64.decode(dataEncoded, Base64.DEFAULT)); + ReadableMap data = outputMap.getMap("data"); + ByteBuffer buffer = ByteBuffer.wrap(blobModule.testGetData(data)); for (int i = 0; i < 5; ++i) { Assert.assertEquals(buffer.get(i), inputData[i]); } diff --git a/js/react_native/android/src/main/cpp/cpp-adapter.cpp b/js/react_native/android/src/main/cpp/cpp-adapter.cpp new file mode 100644 index 0000000000000..be1228bbfe959 --- /dev/null +++ b/js/react_native/android/src/main/cpp/cpp-adapter.cpp @@ -0,0 +1,127 @@ +#include +#include +#include + +using namespace facebook; + +typedef u_int8_t byte; + +std::string jstring2string(JNIEnv *env, jstring jStr) { + if (!jStr) return ""; + + jclass stringClass = env->GetObjectClass(jStr); + jmethodID getBytes = env->GetMethodID(stringClass, "getBytes", "(Ljava/lang/String;)[B"); + const auto stringJbytes = (jbyteArray) env->CallObjectMethod(jStr, getBytes, env->NewStringUTF("UTF-8")); + + auto length = (size_t) env->GetArrayLength(stringJbytes); + jbyte* pBytes = env->GetByteArrayElements(stringJbytes, nullptr); + + std::string ret = std::string((char *)pBytes, length); + env->ReleaseByteArrayElements(stringJbytes, pBytes, JNI_ABORT); + + env->DeleteLocalRef(stringJbytes); + env->DeleteLocalRef(stringClass); + return ret; +} + +byte* getBytesFromBlob(JNIEnv *env, jobject instanceGlobal, const std::string& blobId, int offset, int size) { + if (!env) throw std::runtime_error("JNI Environment is gone!"); + + // get java class + jclass clazz = env->GetObjectClass(instanceGlobal); + // get method in java class + jmethodID getBufferJava = env->GetMethodID(clazz, "getBlobBuffer", "(Ljava/lang/String;II)[B"); + // call method + auto jstring = env->NewStringUTF(blobId.c_str()); + auto boxedBytes = (jbyteArray) env->CallObjectMethod(instanceGlobal, + getBufferJava, + // arguments + jstring, + offset, + size); + env->DeleteLocalRef(jstring); + + jboolean isCopy = true; + jbyte* bytes = env->GetByteArrayElements(boxedBytes, &isCopy); + env->DeleteLocalRef(boxedBytes); + return reinterpret_cast(bytes); +}; + +std::string createBlob(JNIEnv *env, jobject instanceGlobal, byte* bytes, size_t size) { + if (!env) throw std::runtime_error("JNI Environment is gone!"); + + // get java class + jclass clazz = env->GetObjectClass(instanceGlobal); + // get method in java class + jmethodID getBufferJava = env->GetMethodID(clazz, "createBlob", "([B)Ljava/lang/String;"); + // call method + auto byteArray = env->NewByteArray(size); + env->SetByteArrayRegion(byteArray, 0, size, reinterpret_cast(bytes)); + auto blobId = (jstring) env->CallObjectMethod(instanceGlobal, getBufferJava, byteArray); + env->DeleteLocalRef(byteArray); + + return jstring2string(env, blobId); +}; + +extern "C" +JNIEXPORT void JNICALL +Java_ai_onnxruntime_reactnative_OnnxruntimeJSIHelper_nativeInstall(JNIEnv *env, jclass _, jlong jsiPtr, jobject instance) { + auto jsiRuntime = reinterpret_cast(jsiPtr); + + auto& runtime = *jsiRuntime; + + auto instanceGlobal = env->NewGlobalRef(instance); + + auto resolveArrayBuffer = jsi::Function::createFromHostFunction(runtime, + jsi::PropNameID::forAscii(runtime, "jsiOnnxruntimeResolveArrayBuffer"), + 1, + [=](jsi::Runtime& runtime, + const jsi::Value& thisValue, + const jsi::Value* arguments, + size_t count) -> jsi::Value { + if (count != 1) { + throw jsi::JSError(runtime, "jsiOnnxruntimeResolveArrayBuffer(..) expects one argument (object)!"); + } + + jsi::Object data = arguments[0].asObject(runtime); + auto blobId = data.getProperty(runtime, "blobId").asString(runtime); + auto offset = data.getProperty(runtime, "offset").asNumber(); + auto size = data.getProperty(runtime, "size").asNumber(); + + auto bytes = getBytesFromBlob(env, instanceGlobal, blobId.utf8(runtime), offset, size); + + size_t totalSize = size - offset; + jsi::Function arrayBufferCtor = runtime.global().getPropertyAsFunction(runtime, "ArrayBuffer"); + jsi::Object o = arrayBufferCtor.callAsConstructor(runtime, (int) totalSize).getObject(runtime); + jsi::ArrayBuffer buf = o.getArrayBuffer(runtime); + memcpy(buf.data(runtime), reinterpret_cast(bytes), totalSize); + + return buf; + }); + runtime.global().setProperty(runtime, "jsiOnnxruntimeResolveArrayBuffer", std::move(resolveArrayBuffer)); + + auto storeArrayBuffer = jsi::Function::createFromHostFunction(runtime, + jsi::PropNameID::forAscii(runtime, "jsiOnnxruntimeStoreArrayBuffer"), + 1, + [=](jsi::Runtime& runtime, + const jsi::Value& thisValue, + const jsi::Value* arguments, + size_t count) -> jsi::Value { + if (count != 1) { + throw jsi::JSError(runtime, "jsiOnnxruntimeStoreArrayBuffer(..) expects one argument (object)!"); + } + + auto arrayBuffer = arguments[0].asObject(runtime).getArrayBuffer(runtime); + auto size = arrayBuffer.size(runtime); + + std::string blobId = createBlob(env, instanceGlobal, arrayBuffer.data(runtime), size); + + jsi::Object result(runtime); + auto blobIdString = jsi::String::createFromUtf8(runtime, blobId); + result.setProperty(runtime, "blobId", blobIdString); + result.setProperty(runtime, "offset", jsi::Value(0)); + result.setProperty(runtime, "size", jsi::Value(static_cast(size))); + return result; + }); + runtime.global().setProperty(runtime, "jsiOnnxruntimeStoreArrayBuffer", std::move(storeArrayBuffer)); +} diff --git a/js/react_native/android/src/main/java/ai/onnxruntime/reactnative/OnnxruntimeExtensionsDisabled.java b/js/react_native/android/src/main/java/ai/onnxruntime/reactnative/OnnxruntimeExtensionsDisabled.java new file mode 100644 index 0000000000000..de4c880981881 --- /dev/null +++ b/js/react_native/android/src/main/java/ai/onnxruntime/reactnative/OnnxruntimeExtensionsDisabled.java @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package ai.onnxruntime.reactnative; + +import ai.onnxruntime.OrtSession.SessionOptions; +import android.util.Log; + +class OnnxruntimeExtensions { + public void registerOrtExtensionsIfEnabled(SessionOptions sessionOptions) { + Log.i("OnnxruntimeExtensions", + "ORT Extensions is not enabled in the current configuration. If you want to enable this support, " + + "please add \"onnxruntimeEnableExtensions\": \"true\" in your project root directory package.json."); + return; + } +} diff --git a/js/react_native/android/src/main/java/ai/onnxruntime/reactnative/OnnxruntimeExtensionsEnabled.java b/js/react_native/android/src/main/java/ai/onnxruntime/reactnative/OnnxruntimeExtensionsEnabled.java new file mode 100644 index 0000000000000..9bbf41c8f1671 --- /dev/null +++ b/js/react_native/android/src/main/java/ai/onnxruntime/reactnative/OnnxruntimeExtensionsEnabled.java @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package ai.onnxruntime.reactnative; + +import ai.onnxruntime.OrtException; +import ai.onnxruntime.OrtSession.SessionOptions; +import ai.onnxruntime.extensions.OrtxPackage; + +class OnnxruntimeExtensions { + public void registerOrtExtensionsIfEnabled(SessionOptions sessionOptions) throws OrtException { + sessionOptions.registerCustomOpLibrary(OrtxPackage.getLibraryPath()); + } +} diff --git a/js/react_native/android/src/main/java/ai/onnxruntime/reactnative/OnnxruntimeJSIHelper.java b/js/react_native/android/src/main/java/ai/onnxruntime/reactnative/OnnxruntimeJSIHelper.java new file mode 100644 index 0000000000000..93b37df0768b4 --- /dev/null +++ b/js/react_native/android/src/main/java/ai/onnxruntime/reactnative/OnnxruntimeJSIHelper.java @@ -0,0 +1,70 @@ +package ai.onnxruntime.reactnative; + +import androidx.annotation.NonNull; +import com.facebook.react.bridge.JavaScriptContextHolder; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.module.annotations.ReactModule; +import com.facebook.react.modules.blob.BlobModule; + +@ReactModule(name = OnnxruntimeJSIHelper.NAME) +public class OnnxruntimeJSIHelper extends ReactContextBaseJavaModule { + public static final String NAME = "OnnxruntimeJSIHelper"; + + private static ReactApplicationContext reactContext; + protected BlobModule blobModule; + + public OnnxruntimeJSIHelper(ReactApplicationContext context) { + super(context); + reactContext = context; + } + + @Override + @NonNull + public String getName() { + return NAME; + } + + public void checkBlobModule() { + if (blobModule == null) { + blobModule = getReactApplicationContext().getNativeModule(BlobModule.class); + if (blobModule == null) { + throw new RuntimeException("BlobModule is not initialized"); + } + } + } + + @ReactMethod(isBlockingSynchronousMethod = true) + public boolean install() { + try { + System.loadLibrary("onnxruntimejsihelper"); + JavaScriptContextHolder jsContext = getReactApplicationContext().getJavaScriptContextHolder(); + nativeInstall(jsContext.get(), this); + return true; + } catch (Exception exception) { + return false; + } + } + + public byte[] getBlobBuffer(String blobId, int offset, int size) { + checkBlobModule(); + byte[] bytes = blobModule.resolve(blobId, offset, size); + blobModule.remove(blobId); + if (bytes == null) { + throw new RuntimeException("Failed to resolve Blob #" + blobId + "! Not found."); + } + return bytes; + } + + public String createBlob(byte[] buffer) { + checkBlobModule(); + String blobId = blobModule.store(buffer); + if (blobId == null) { + throw new RuntimeException("Failed to create Blob!"); + } + return blobId; + } + + public static native void nativeInstall(long jsiPointer, OnnxruntimeJSIHelper instance); +} diff --git a/js/react_native/android/src/main/java/ai/onnxruntime/reactnative/OnnxruntimeModule.java b/js/react_native/android/src/main/java/ai/onnxruntime/reactnative/OnnxruntimeModule.java index fe59cefbee9cd..fd085f9533801 100644 --- a/js/react_native/android/src/main/java/ai/onnxruntime/reactnative/OnnxruntimeModule.java +++ b/js/react_native/android/src/main/java/ai/onnxruntime/reactnative/OnnxruntimeModule.java @@ -11,12 +11,14 @@ import ai.onnxruntime.OrtSession.Result; import ai.onnxruntime.OrtSession.RunOptions; import ai.onnxruntime.OrtSession.SessionOptions; +import ai.onnxruntime.providers.NNAPIFlags; import android.net.Uri; import android.os.Build; import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.LifecycleEventListener; import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; @@ -26,11 +28,15 @@ import com.facebook.react.bridge.ReadableType; import com.facebook.react.bridge.WritableArray; import com.facebook.react.bridge.WritableMap; +import com.facebook.react.modules.blob.BlobModule; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; +import java.math.BigInteger; +import java.util.Collections; +import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -40,12 +46,21 @@ import java.util.stream.Stream; @RequiresApi(api = Build.VERSION_CODES.N) -public class OnnxruntimeModule extends ReactContextBaseJavaModule { +public class OnnxruntimeModule extends ReactContextBaseJavaModule implements LifecycleEventListener { private static ReactApplicationContext reactContext; private static OrtEnvironment ortEnvironment = OrtEnvironment.getEnvironment(); private static Map sessionMap = new HashMap<>(); + private static BigInteger nextSessionId = new BigInteger("0"); + private static String getNextSessionKey() { + String key = nextSessionId.toString(); + nextSessionId = nextSessionId.add(BigInteger.valueOf(1)); + return key; + } + + protected BlobModule blobModule; + public OnnxruntimeModule(ReactApplicationContext context) { super(context); reactContext = context; @@ -57,14 +72,23 @@ public String getName() { return "Onnxruntime"; } + public void checkBlobModule() { + if (blobModule == null) { + blobModule = getReactApplicationContext().getNativeModule(BlobModule.class); + if (blobModule == null) { + throw new RuntimeException("BlobModule is not initialized"); + } + } + } + /** * React native binding API to load a model using given uri. * - * @param uri a model file location. it's used as a key when multiple sessions are created, i.e. multiple models are - * loaded. + * @param uri a model file location * @param options onnxruntime session options * @param promise output returning back to react native js - * @note when run() is called, the same uri must be passed into the first parameter. + * @note the value provided to `promise` includes a key representing the session. + * when run() is called, the key must be passed into the first parameter. */ @ReactMethod public void loadModel(String uri, ReadableMap options, Promise promise) { @@ -72,14 +96,53 @@ public void loadModel(String uri, ReadableMap options, Promise promise) { WritableMap resultMap = loadModel(uri, options); promise.resolve(resultMap); } catch (Exception e) { - promise.reject("Can't load model \"" + uri + "\": " + e.getMessage(), e); + promise.reject("Failed to load model \"" + uri + "\": " + e.getMessage(), e); + } + } + + /** + * React native binding API to load a model using blob object that data stored in BlobModule. + * + * @param data the blob object + * @param options onnxruntime session options + * @param promise output returning back to react native js + * @note the value provided to `promise` includes a key representing the session. + * when run() is called, the key must be passed into the first parameter. + */ + @ReactMethod + public void loadModelFromBlob(ReadableMap data, ReadableMap options, Promise promise) { + try { + checkBlobModule(); + String blobId = data.getString("blobId"); + byte[] bytes = blobModule.resolve(blobId, data.getInt("offset"), data.getInt("size")); + blobModule.remove(blobId); + WritableMap resultMap = loadModel(bytes, options); + promise.resolve(resultMap); + } catch (Exception e) { + promise.reject("Failed to load model from buffer: " + e.getMessage(), e); + } + } + + /** + * React native binding API to dispose a session. + * + * @param key session key representing a session given at loadModel() + * @param promise output returning back to react native js + */ + @ReactMethod + public void dispose(String key, Promise promise) { + try { + dispose(key); + promise.resolve(null); + } catch (OrtException e) { + promise.reject("Failed to dispose session: " + e.getMessage(), e); } } /** * React native binding API to run a model using given uri. * - * @param key a model file location given at loadModel() + * @param key session key representing a session given at loadModel() * @param input an input tensor * @param output an output names to be returned * @param options onnxruntime run options @@ -103,39 +166,55 @@ public void run(String key, ReadableMap input, ReadableArray output, ReadableMap * @return model loading information, such as key, input names, and output names */ public WritableMap loadModel(String uri, ReadableMap options) throws Exception { - InputStream modelStream = reactContext.getApplicationContext().getContentResolver().openInputStream(Uri.parse(uri)); - WritableMap resultMap = loadModel(uri, modelStream, options); - modelStream.close(); - return resultMap; + return loadModelImpl(uri, null, options); } /** - * Load a model from raw resource directory. + * Load a model from buffer. * - * @param uri uri parameter from react native loadModel() or dummy string for unit testing purpose - * @param modelStream a input stream to read a model + * @param modelData the model data buffer * @param options onnxruntime session options * @return model loading information, such as key, input names, and output names */ - public WritableMap loadModel(String uri, InputStream modelStream, ReadableMap options) throws Exception { - OrtSession ortSession = null; + public WritableMap loadModel(byte[] modelData, ReadableMap options) throws Exception { + return loadModelImpl("", modelData, options); + } + + /** + * Load model implementation method for either from model path or model data buffer. + * + * @param uri uri parameter from react native loadModel() + * @param modelData model data buffer + * @param options onnxruntime session options + * @return model loading information map, such as key, input names, and output names + */ + private WritableMap loadModelImpl(String uri, byte[] modelData, ReadableMap options) throws Exception { + OrtSession ortSession; + SessionOptions sessionOptions = parseSessionOptions(options); - if (!sessionMap.containsKey(uri)) { - byte[] modelArray = null; + // optional call for registering custom ops when ort extensions enabled + OnnxruntimeExtensions ortExt = new OnnxruntimeExtensions(); + ortExt.registerOrtExtensionsIfEnabled(sessionOptions); + if (modelData != null && modelData.length > 0) { + // load model via model data array + ortSession = ortEnvironment.createSession(modelData, sessionOptions); + } else { + // load model via model path string uri + InputStream modelStream = + reactContext.getApplicationContext().getContentResolver().openInputStream(Uri.parse(uri)); Reader reader = new BufferedReader(new InputStreamReader(modelStream)); - modelArray = new byte[modelStream.available()]; + byte[] modelArray = new byte[modelStream.available()]; modelStream.read(modelArray); - - SessionOptions sessionOptions = parseSessionOptions(options); + modelStream.close(); ortSession = ortEnvironment.createSession(modelArray, sessionOptions); - sessionMap.put(uri, ortSession); - } else { - ortSession = sessionMap.get(uri); } + String key = getNextSessionKey(); + sessionMap.put(key, ortSession); + WritableMap resultMap = Arguments.createMap(); - resultMap.putString("key", uri); + resultMap.putString("key", key); WritableArray inputNames = Arguments.createArray(); for (String inputName : ortSession.getInputNames()) { inputNames.pushString(inputName); @@ -150,10 +229,23 @@ public WritableMap loadModel(String uri, InputStream modelStream, ReadableMap op return resultMap; } + /** + * Dispose a model using given key. + * + * @param key a session key representing the session given at loadModel() + */ + public void dispose(String key) throws OrtException { + OrtSession ortSession = sessionMap.get(key); + if (ortSession != null) { + ortSession.close(); + sessionMap.remove(key); + } + } + /** * Run a model using given uri. * - * @param key a model file location given at loadModel() + * @param key a session key representing the session given at loadModel() * @param input an input tensor * @param output an output names to be returned * @param options onnxruntime run options @@ -162,14 +254,17 @@ public WritableMap loadModel(String uri, InputStream modelStream, ReadableMap op public WritableMap run(String key, ReadableMap input, ReadableArray output, ReadableMap options) throws Exception { OrtSession ortSession = sessionMap.get(key); if (ortSession == null) { - throw new Exception("Model is not loaded: " + key); + throw new Exception("Model is not loaded."); } RunOptions runOptions = parseRunOptions(options); + checkBlobModule(); + long startTime = System.currentTimeMillis(); Map feed = new HashMap<>(); Iterator iterator = ortSession.getInputNames().iterator(); + Result result = null; try { while (iterator.hasNext()) { String inputName = iterator.next(); @@ -179,19 +274,7 @@ public WritableMap run(String key, ReadableMap input, ReadableArray output, Read throw new Exception("Can't find input: " + inputName); } - if (inputMap.getType("data") != ReadableType.String) { - // NOTE: - // - // tensor data should always be a BASE64 encoded string. - // This is because the current React Native bridge supports limited data type as arguments. - // In order to pass data from JS to Java, we have to encode them into string. - // - // see also: - // https://reactnative.dev/docs/native-modules-android#argument-types - throw new Exception("Non string type of a tensor data is not allowed"); - } - - OnnxTensor onnxTensor = TensorHelper.createInputTensor(inputMap, ortEnvironment); + OnnxTensor onnxTensor = TensorHelper.createInputTensor(blobModule, inputMap, ortEnvironment); feed.put(inputName, onnxTensor); } @@ -207,7 +290,6 @@ public WritableMap run(String key, ReadableMap input, ReadableArray output, Read Log.d("Duration", "createInputTensor: " + duration); startTime = System.currentTimeMillis(); - Result result = null; if (requestedOutputs != null) { result = ortSession.run(feed, requestedOutputs, runOptions); } else { @@ -217,7 +299,7 @@ public WritableMap run(String key, ReadableMap input, ReadableArray output, Read Log.d("Duration", "inference: " + duration); startTime = System.currentTimeMillis(); - WritableMap resultMap = TensorHelper.createOutputTensor(result); + WritableMap resultMap = TensorHelper.createOutputTensor(blobModule, result); duration = System.currentTimeMillis() - startTime; Log.d("Duration", "createOutputTensor: " + duration); @@ -225,6 +307,9 @@ public WritableMap run(String key, ReadableMap input, ReadableArray output, Read } finally { OnnxValue.close(feed); + if (result != null) { + result.close(); + } } } @@ -285,6 +370,44 @@ private SessionOptions parseSessionOptions(ReadableMap options) throws OrtExcept } } + if (options.hasKey("executionProviders")) { + ReadableArray executionProviders = options.getArray("executionProviders"); + for (int i = 0; i < executionProviders.size(); ++i) { + String epName = null; + ReadableMap epOptions = null; + if (executionProviders.getType(i) == ReadableType.String) { + epName = executionProviders.getString(i); + } else { + epOptions = executionProviders.getMap(i); + epName = epOptions.getString("name"); + } + if (epName.equals("nnapi")) { + EnumSet flags = EnumSet.noneOf(NNAPIFlags.class); + if (epOptions != null) { + if (epOptions.hasKey("useFP16") && epOptions.getBoolean("useFP16")) { + flags.add(NNAPIFlags.USE_FP16); + } + if (epOptions.hasKey("useNCHW") && epOptions.getBoolean("useNCHW")) { + flags.add(NNAPIFlags.USE_NCHW); + } + if (epOptions.hasKey("cpuDisabled") && epOptions.getBoolean("cpuDisabled")) { + flags.add(NNAPIFlags.CPU_DISABLED); + } + if (epOptions.hasKey("cpuOnly") && epOptions.getBoolean("cpuOnly")) { + flags.add(NNAPIFlags.CPU_ONLY); + } + } + sessionOptions.addNnapi(flags); + } else if (epName.equals("xnnpack")) { + sessionOptions.addXnnpack(Collections.emptyMap()); + } else if (epName.equals("cpu")) { + continue; + } else { + throw new OrtException("Unsupported execution provider: " + epName); + } + } + } + if (options.hasKey("logId")) { String logId = options.getString("logId"); sessionOptions.setLoggerId(logId); @@ -313,4 +436,22 @@ private RunOptions parseRunOptions(ReadableMap options) throws OrtException { return runOptions; } + + @Override + public void onHostResume() {} + + @Override + public void onHostPause() {} + + @Override + public void onHostDestroy() { + for (String key : sessionMap.keySet()) { + try { + dispose(key); + } catch (Exception e) { + Log.e("onHostDestroy", "Failed to dispose session: " + key, e); + } + } + sessionMap.clear(); + } } diff --git a/js/react_native/android/src/main/java/ai/onnxruntime/reactnative/OnnxruntimePackage.java b/js/react_native/android/src/main/java/ai/onnxruntime/reactnative/OnnxruntimePackage.java index b2ccbf10c7f9a..bb4386a0953f3 100644 --- a/js/react_native/android/src/main/java/ai/onnxruntime/reactnative/OnnxruntimePackage.java +++ b/js/react_native/android/src/main/java/ai/onnxruntime/reactnative/OnnxruntimePackage.java @@ -9,6 +9,7 @@ import com.facebook.react.ReactPackage; import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.modules.blob.BlobModule; import com.facebook.react.uimanager.ViewManager; import java.util.ArrayList; import java.util.Collections; @@ -21,6 +22,7 @@ public class OnnxruntimePackage implements ReactPackage { public List createNativeModules(@NonNull ReactApplicationContext reactContext) { List modules = new ArrayList<>(); modules.add(new OnnxruntimeModule(reactContext)); + modules.add(new OnnxruntimeJSIHelper(reactContext)); return modules; } diff --git a/js/react_native/android/src/main/java/ai/onnxruntime/reactnative/TensorHelper.java b/js/react_native/android/src/main/java/ai/onnxruntime/reactnative/TensorHelper.java index 500141ab51c49..63cddace36640 100644 --- a/js/react_native/android/src/main/java/ai/onnxruntime/reactnative/TensorHelper.java +++ b/js/react_native/android/src/main/java/ai/onnxruntime/reactnative/TensorHelper.java @@ -16,6 +16,7 @@ import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.WritableArray; import com.facebook.react.bridge.WritableMap; +import com.facebook.react.modules.blob.BlobModule; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.DoubleBuffer; @@ -45,9 +46,10 @@ public class TensorHelper { /** * It creates an input tensor from a map passed by react native js. - * 'data' must be a string type as data is encoded as base64. It first decodes it and creates a tensor. + * 'data' is blob object and the buffer is stored in BlobModule. It first resolve it and creates a tensor. */ - public static OnnxTensor createInputTensor(ReadableMap inputTensor, OrtEnvironment ortEnvironment) throws Exception { + public static OnnxTensor createInputTensor(BlobModule blobModule, ReadableMap inputTensor, + OrtEnvironment ortEnvironment) throws Exception { // shape ReadableArray dimsArray = inputTensor.getArray("dims"); long[] dims = new long[dimsArray.size()]; @@ -68,8 +70,11 @@ public static OnnxTensor createInputTensor(ReadableMap inputTensor, OrtEnvironme } onnxTensor = OnnxTensor.createTensor(ortEnvironment, buffer, dims); } else { - String data = inputTensor.getString("data"); - ByteBuffer values = ByteBuffer.wrap(Base64.decode(data, Base64.DEFAULT)).order(ByteOrder.nativeOrder()); + ReadableMap data = inputTensor.getMap("data"); + String blobId = data.getString("blobId"); + byte[] bytes = blobModule.resolve(blobId, data.getInt("offset"), data.getInt("size")); + blobModule.remove(blobId); + ByteBuffer values = ByteBuffer.wrap(bytes).order(ByteOrder.nativeOrder()); onnxTensor = createInputTensor(tensorType, dims, values, ortEnvironment); } @@ -78,9 +83,9 @@ public static OnnxTensor createInputTensor(ReadableMap inputTensor, OrtEnvironme /** * It creates an output map from an output tensor. - * a data array is encoded as base64 string. + * a data array is store in BlobModule. */ - public static WritableMap createOutputTensor(OrtSession.Result result) throws Exception { + public static WritableMap createOutputTensor(BlobModule blobModule, OrtSession.Result result) throws Exception { WritableMap outputTensorMap = Arguments.createMap(); Iterator> iterator = result.iterator(); @@ -115,8 +120,13 @@ public static WritableMap createOutputTensor(OrtSession.Result result) throws Ex } outputTensor.putArray("data", dataArray); } else { - String data = createOutputTensor(onnxTensor); - outputTensor.putString("data", data); + // Store in BlobModule then create a blob object as data + byte[] bufferArray = createOutputTensor(onnxTensor); + WritableMap data = Arguments.createMap(); + data.putString("blobId", blobModule.store(bufferArray)); + data.putInt("offset", 0); + data.putInt("size", bufferArray.length); + outputTensor.putMap("data", data); } outputTensorMap.putMap(outputName, outputTensor); @@ -164,7 +174,11 @@ private static OnnxTensor createInputTensor(TensorInfo.OnnxTensorType tensorType tensor = OnnxTensor.createTensor(ortEnvironment, buffer, dims, OnnxJavaType.UINT8); break; } - case ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL: + case ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL: { + ByteBuffer buffer = values; + tensor = OnnxTensor.createTensor(ortEnvironment, buffer, dims, OnnxJavaType.BOOL); + break; + } case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16: case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT16: case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT32: @@ -177,7 +191,7 @@ private static OnnxTensor createInputTensor(TensorInfo.OnnxTensorType tensorType return tensor; } - private static String createOutputTensor(OnnxTensor onnxTensor) throws Exception { + private static byte[] createOutputTensor(OnnxTensor onnxTensor) throws Exception { TensorInfo tensorInfo = onnxTensor.getInfo(); ByteBuffer buffer = null; @@ -224,8 +238,7 @@ private static String createOutputTensor(OnnxTensor onnxTensor) throws Exception throw new IllegalStateException("Unexpected type: " + tensorInfo.onnxType.toString()); } - String data = Base64.encodeToString(buffer.array(), Base64.DEFAULT); - return data; + return buffer.array(); } private static final Map JsTensorTypeToOnnxTensorTypeMap = diff --git a/js/react_native/babel.config.js b/js/react_native/babel.config.js index e2240f1f51f8b..b667f9a55a389 100644 --- a/js/react_native/babel.config.js +++ b/js/react_native/babel.config.js @@ -1,5 +1,5 @@ 'use strict'; module.exports = { - presets: ['module:metro-react-native-babel-preset'], + presets : ['module:metro-react-native-babel-preset'], }; diff --git a/js/react_native/e2e/.detoxrc.js b/js/react_native/e2e/.detoxrc.js index b6230d02c9c01..94ff7272972c4 100644 --- a/js/react_native/e2e/.detoxrc.js +++ b/js/react_native/e2e/.detoxrc.js @@ -13,12 +13,12 @@ module.exports = { 'ios.debug': { type: 'ios.app', binaryPath: 'ios/build/Build/Products/Debug-iphonesimulator/OnnxruntimeModuleExample.app', - build: 'xcodebuild -workspace ios/OnnxruntimeModuleExample.xcworkspace -scheme OnnxruntimeModuleExample -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build' + build: 'xcodebuild ARCHS=x86_64 ONLY_ACTIVE_ARCH=NO -workspace ios/OnnxruntimeModuleExample.xcworkspace -scheme OnnxruntimeModuleExample -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build' }, 'ios.release': { type: 'ios.app', binaryPath: 'ios/build/Build/Products/Release-iphonesimulator/OnnxruntimeModuleExample.app', - build: 'xcodebuild -workspace ios/OnnxruntimeModuleExample.xcworkspace -scheme OnnxruntimeModuleExample -configuration Release -sdk iphonesimulator -derivedDataPath ios/build' + build: 'xcodebuild ARCHS=x86_64 ONLY_ACTIVE_ARCH=NO -workspace ios/OnnxruntimeModuleExample.xcworkspace -scheme OnnxruntimeModuleExample -configuration Release -sdk iphonesimulator -derivedDataPath ios/build' }, 'android.debug': { type: 'android.apk', diff --git a/js/react_native/e2e/android/app/build.gradle b/js/react_native/e2e/android/app/build.gradle index 8ff9b102ed57d..811b697126972 100644 --- a/js/react_native/e2e/android/app/build.gradle +++ b/js/react_native/e2e/android/app/build.gradle @@ -227,7 +227,7 @@ dependencies { // Run this once to be able to run the application with BUCK // puts all compile dependencies into folder libs for BUCK to use task copyDownloadableDepsToLibs(type: Copy) { - from configurations.compile + from configurations.implementation into 'libs' } 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 e1a1be51c142b..24e685b6caf0b 100644 --- a/js/react_native/e2e/android/app/src/main/AndroidManifest.xml +++ b/js/react_native/e2e/android/app/src/main/AndroidManifest.xml @@ -18,7 +18,8 @@ android:label="@string/app_name" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode" android:launchMode="singleTask" - android:windowSoftInputMode="adjustResize"> + android:windowSoftInputMode="adjustResize" + android:exported="true"> diff --git a/js/react_native/e2e/android/app/src/main/assets/index.android.bundle b/js/react_native/e2e/android/app/src/main/assets/index.android.bundle deleted file mode 100644 index 00d9a7249c151..0000000000000 --- a/js/react_native/e2e/android/app/src/main/assets/index.android.bundle +++ /dev/null @@ -1,811 +0,0 @@ -var __BUNDLE_START_TIME__=this.nativePerformanceNow?nativePerformanceNow():Date.now(),__DEV__=false,process=this.process||{},__METRO_GLOBAL_PREFIX__='';process.env=process.env||{};process.env.NODE_ENV=process.env.NODE_ENV||"production"; -!(function(r){"use strict";r.__r=o,r[__METRO_GLOBAL_PREFIX__+"__d"]=function(r,i,n){if(null!=e[i])return;var o={dependencyMap:n,factory:r,hasError:!1,importedAll:t,importedDefault:t,isInitialized:!1,publicModule:{exports:{}}};e[i]=o},r.__c=n,r.__registerSegment=function(r,t,i){s[r]=t,i&&i.forEach(function(t){e[t]||v.has(t)||v.set(t,r)})};var e=n(),t={},i={}.hasOwnProperty;function n(){return e=Object.create(null)}function o(r){var t=r,i=e[t];return i&&i.isInitialized?i.publicModule.exports:d(t,i)}function l(r){var i=r;if(e[i]&&e[i].importedDefault!==t)return e[i].importedDefault;var n=o(i),l=n&&n.__esModule?n.default:n;return e[i].importedDefault=l}function u(r){var n=r;if(e[n]&&e[n].importedAll!==t)return e[n].importedAll;var l,u=o(n);if(u&&u.__esModule)l=u;else{if(l={},u)for(var a in u)i.call(u,a)&&(l[a]=u[a]);l.default=u}return e[n].importedAll=l}o.importDefault=l,o.importAll=u;var a=!1;function d(e,t){if(!a&&r.ErrorUtils){var i;a=!0;try{i=h(e,t)}catch(e){r.ErrorUtils.reportFatalError(e)}return a=!1,i}return h(e,t)}var f=16,c=65535;function p(r){return{segmentId:r>>>f,localId:r&c}}o.unpackModuleId=p,o.packModuleId=function(r){return(r.segmentId<0){var n,a=null!==(n=v.get(t))&&void 0!==n?n:0,d=s[a];null!=d&&(d(t),i=e[t],v.delete(t))}var f=r.nativeRequire;if(!i&&f){var c=p(t),h=c.segmentId;f(c.localId,h),i=e[t]}if(!i)throw Error('Requiring unknown module "'+t+'".');if(i.hasError)throw _(t,i.error);i.isInitialized=!0;var m=i,g=m.factory,I=m.dependencyMap;try{var M=i.publicModule;return M.id=t,g(r,o,l,u,M,M.exports,I),i.factory=void 0,i.dependencyMap=void 0,M.exports}catch(r){throw i.hasError=!0,i.error=r,i.isInitialized=!1,i.publicModule.exports=void 0,r}}function _(r,e){return Error('Requiring module "'+r+'", which threw an exception: '+e)}})('undefined'!=typeof globalThis?globalThis:'undefined'!=typeof global?global:'undefined'!=typeof window?window:this); -!(function(n){var e=(function(){function n(n,e){return n}function e(n){var e={};return n.forEach(function(n,r){e[n]=!0}),e}function r(n,r,u){if(n.formatValueCalls++,n.formatValueCalls>200)return"[TOO BIG formatValueCalls "+n.formatValueCalls+" exceeded limit of 200]";var f=t(n,r);if(f)return f;var c=Object.keys(r),s=e(c);if(d(r)&&(c.indexOf('message')>=0||c.indexOf('description')>=0))return o(r);if(0===c.length){if(v(r)){var g=r.name?': '+r.name:'';return n.stylize('[Function'+g+']','special')}if(p(r))return n.stylize(RegExp.prototype.toString.call(r),'regexp');if(y(r))return n.stylize(Date.prototype.toString.call(r),'date');if(d(r))return o(r)}var h,b,m='',j=!1,O=['{','}'];(h=r,Array.isArray(h)&&(j=!0,O=['[',']']),v(r))&&(m=' [Function'+(r.name?': '+r.name:'')+']');return p(r)&&(m=' '+RegExp.prototype.toString.call(r)),y(r)&&(m=' '+Date.prototype.toUTCString.call(r)),d(r)&&(m=' '+o(r)),0!==c.length||j&&0!=r.length?u<0?p(r)?n.stylize(RegExp.prototype.toString.call(r),'regexp'):n.stylize('[Object]','special'):(n.seen.push(r),b=j?i(n,r,u,s,c):c.map(function(e){return l(n,r,u,s,e,j)}),n.seen.pop(),a(b,m,O)):O[0]+m+O[1]}function t(n,e){if(s(e))return n.stylize('undefined','undefined');if('string'==typeof e){var r="'"+JSON.stringify(e).replace(/^"|"$/g,'').replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return n.stylize(r,'string')}return c(e)?n.stylize(''+e,'number'):u(e)?n.stylize(''+e,'boolean'):f(e)?n.stylize('null','null'):void 0}function o(n){return'['+Error.prototype.toString.call(n)+']'}function i(n,e,r,t,o){for(var i=[],a=0,u=e.length;a-1&&(u=l?u.split('\n').map(function(n){return' '+n}).join('\n').substr(2):'\n'+u.split('\n').map(function(n){return' '+n}).join('\n')):u=n.stylize('[Circular]','special')),s(a)){if(l&&i.match(/^\d+$/))return u;(a=JSON.stringify(''+i)).match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(a=a.substr(1,a.length-2),a=n.stylize(a,'name')):(a=a.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),a=n.stylize(a,'string'))}return a+': '+u}function a(n,e,r){return n.reduce(function(n,e){return 0,e.indexOf('\n')>=0&&0,n+e.replace(/\u001b\[\d\d?m/g,'').length+1},0)>60?r[0]+(''===e?'':e+'\n ')+' '+n.join(',\n ')+' '+r[1]:r[0]+e+' '+n.join(', ')+' '+r[1]}function u(n){return'boolean'==typeof n}function f(n){return null===n}function c(n){return'number'==typeof n}function s(n){return void 0===n}function p(n){return g(n)&&'[object RegExp]'===h(n)}function g(n){return'object'==typeof n&&null!==n}function y(n){return g(n)&&'[object Date]'===h(n)}function d(n){return g(n)&&('[object Error]'===h(n)||n instanceof Error)}function v(n){return'function'==typeof n}function h(n){return Object.prototype.toString.call(n)}function b(n,e){return Object.prototype.hasOwnProperty.call(n,e)}return function(e,t){return r({seen:[],formatValueCalls:0,stylize:n},e,t.depth)}})(),r='(index)',t={trace:0,info:1,warn:2,error:3},o=[];o[t.trace]='debug',o[t.info]='log',o[t.warn]='warning',o[t.error]='error';var i=1;function l(r){return function(){var l;l=1===arguments.length&&'string'==typeof arguments[0]?arguments[0]:Array.prototype.map.call(arguments,function(n){return e(n,{depth:10})}).join(', ');var a=arguments[0],u=r;'string'==typeof a&&'Warning: '===a.slice(0,9)&&u>=t.error&&(u=t.warn),n.__inspectorLog&&n.__inspectorLog(o[u],l,[].slice.call(arguments),i),s.length&&(l=p('',l)),n.nativeLoggingHook(l,u)}}function a(n,e){return Array.apply(null,Array(e)).map(function(){return n})}var u="\u2502",f="\u2510",c="\u2518",s=[];function p(n,e){return s.join('')+n+' '+(e||'')}if(n.nativeLoggingHook){n.console;n.console={error:l(t.error),info:l(t.info),log:l(t.info),warn:l(t.warn),trace:l(t.trace),debug:l(t.trace),table:function(e){if(!Array.isArray(e)){var o=e;for(var i in e=[],o)if(o.hasOwnProperty(i)){var l=o[i];l[r]=i,e.push(l)}}if(0!==e.length){var u=Object.keys(e[0]).sort(),f=[],c=[];u.forEach(function(n,r){c[r]=n.length;for(var t=0;t';return function(){for(var r=arguments.length,u=new Array(r),e=0;e1?n-1:0),o=1;o0?l[l.length-1]:null,c=l.length>1?l[l.length-2]:null,v='function'==typeof s,h='function'==typeof c;h&&r(d[1])(v,'Cannot have a non-function arg after a function arg.');var y=v?s:null,C=h?c:null,M=v+h,b=l.slice(0,l.length-M);if('sync'===o)return r(d[3]).callNativeSyncHook(n,t,b,C,y);r(d[3]).enqueueNativeCall(n,t,b,C,y)}).type=o,u}function u(n,t){return-1!==n.indexOf(t)}function l(n,t){return r(d[2])(t,n||{})}g.__fbGenNativeModule=n;var f={};if(g.nativeModuleProxy)f=g.nativeModuleProxy;else if(!g.nativeExtensions){var s=g.__fbBatchedBridgeConfig;r(d[1])(s,'__fbBatchedBridgeConfig is not set, cannot invoke native modules');var c=r(d[4]);(s.remoteModuleConfig||[]).forEach(function(o,u){var l=n(o,u);l&&(l.module?f[l.name]=l.module:c(f,l.name,{get:function(){return t(l.name,u)}}))})}m.exports=f},22,[23,18,29,30,39]); -__d(function(g,r,_i,a,m,e,d){m.exports=function(t,o){return r(d[0])(t)||r(d[1])(t,o)||r(d[2])(t,o)||r(d[3])()},m.exports.__esModule=!0,m.exports.default=m.exports},23,[24,25,26,28]); -__d(function(g,r,i,a,m,e,d){m.exports=function(t){if(Array.isArray(t))return t},m.exports.__esModule=!0,m.exports.default=m.exports},24,[]); -__d(function(g,r,_i2,a,m,e,d){m.exports=function(t,l){var n=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=n){var o,u,f=[],i=!0,y=!1;try{for(n=n.call(t);!(i=(o=n.next()).done)&&(f.push(o.value),!l||f.length!==l);i=!0);}catch(t){y=!0,u=t}finally{try{i||null==n.return||n.return()}finally{if(y)throw u}}return f}},m.exports.__esModule=!0,m.exports.default=m.exports},25,[]); -__d(function(g,r,i,a,m,e,d){m.exports=function(t,o){if(t){if("string"==typeof t)return r(d[0])(t,o);var n=Object.prototype.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?r(d[0])(t,o):void 0}},m.exports.__esModule=!0,m.exports.default=m.exports},26,[27]); -__d(function(g,r,_i,a,m,e,d){m.exports=function(t,n){(null==n||n>t.length)&&(n=t.length);for(var o=0,l=new Array(n);o=5){var h=this._queue;this._queue=[[],[],[],this._callID],this._lastFlush=o,g.nativeFlushQueueImmediate(h)}r(d[2]).counterEvent('pending_js_to_native_queue',this._queue[0].length),this.__spy&&this.__spy({type:1,module:t+'',method:l,args:s})}},{key:"createDebugLookup",value:function(t,l,s){}},{key:"setReactNativeMicrotasksCallback",value:function(t){this._reactNativeMicrotasksCallback=t}},{key:"__guard",value:function(t){if(this.__shouldPauseOnThrow())t();else try{t()}catch(t){r(d[3]).reportFatalError(t)}}},{key:"__shouldPauseOnThrow",value:function(){return'undefined'!=typeof DebuggerInternal&&!0===DebuggerInternal.shouldPauseOnThrow}},{key:"__callReactNativeMicrotasks",value:function(){r(d[2]).beginEvent('JSTimers.callReactNativeMicrotasks()'),null!=this._reactNativeMicrotasksCallback&&this._reactNativeMicrotasksCallback(),r(d[2]).endEvent()}},{key:"__callFunction",value:function(t,l,s){this._lastFlush=Date.now(),this._eventLoopStartTime=this._lastFlush,this.__spy?r(d[2]).beginEvent(t+"."+l+"("+r(d[4]).default(s)+")"):r(d[2]).beginEvent(t+"."+l+"(...)"),this.__spy&&this.__spy({type:0,module:t,method:l,args:s});var u=this.getCallableModule(t);r(d[5])(!!u,"Module "+t+" is not a registered callable module (calling "+l+"). A frequent cause of the error is that the application entry file path is incorrect.\n This can also happen when the JS bundle is corrupt or there is an early initialization error when loading React Native."),r(d[5])(!!u[l],"Method "+l+" does not exist on module "+t),u[l].apply(u,s),r(d[2]).endEvent()}},{key:"__invokeCallback",value:function(t,l){this._lastFlush=Date.now(),this._eventLoopStartTime=this._lastFlush;var s=t>>>1,u=1&t?this._successCallbacks.get(s):this._failureCallbacks.get(s);u&&(this._successCallbacks.delete(s),this._failureCallbacks.delete(s),u.apply(void 0,r(d[6])(l)))}}],[{key:"spy",value:function(l){t.prototype.__spy=!0===l?function(t){console.log((0===t.type?'N->JS':'JS->N')+" : "+(null!=t.module?t.module+'.':'')+t.method+"("+JSON.stringify(t.args)+")")}:!1===l?null:l}}]),t})();m.exports=t},31,[7,8,32,33,34,18,35]); -__d(function(g,r,i,a,m,e,d){'use strict';var n=!1,t=0,c={installReactHook:function(){!0},setEnabled:function(t){n!==t&&(n=t)},isEnabled:function(){return n},beginEvent:function(t,c){if(n){var o='function'==typeof t?t():t;g.nativeTraceBeginSection(131072,o,c)}},endEvent:function(){n&&g.nativeTraceEndSection(131072)},beginAsyncEvent:function(c){var o=t;if(n){t++;var f='function'==typeof c?c():c;g.nativeTraceBeginAsyncSection(131072,f,o)}return o},endAsyncEvent:function(t,c){if(n){var o='function'==typeof t?t():t;g.nativeTraceEndAsyncSection(131072,o,c)}},counterEvent:function(t,c){if(n){var o='function'==typeof t?t():t;g.nativeTraceCounter&&g.nativeTraceCounter(131072,o,c)}}};m.exports=c},32,[]); -__d(function(g,r,i,a,m,e,d){m.exports=g.ErrorUtils},33,[]); -__d(function(g,r,_i,a,m,_e,d){Object.defineProperty(_e,"__esModule",{value:!0}),_e.createStringifySafeWithLimits=o,_e.default=void 0;var t=r(d[0])(r(d[1]));function e(t,e){var i="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(i)return(i=i.call(t)).next.bind(i);if(Array.isArray(t)||(i=n(t))||e&&t&&"number"==typeof t.length){i&&(t=i);var o=0;return function(){return o>=t.length?{done:!0}:{done:!1,value:t[o++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function n(t,e){if(t){if("string"==typeof t)return i(t,e);var n=Object.prototype.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?i(t,e):void 0}}function i(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,i=new Array(e);nf+"...(truncated)...".length?i.substring(0,f)+"...(truncated)...":i}if('object'!=typeof i||null===i)return i;var u=i;if(Array.isArray(i))h.length>=o?u="[ ... array with "+i.length+" values ... ]":i.length>c&&(u=i.slice(0,c).concat(["... extra "+(i.length-c)+" values truncated ..."]));else{(0,t.default)('object'==typeof i,'This was already found earlier');var l=Object.keys(i);if(h.length>=o)u="{ ... object with "+l.length+" keys ... }";else if(l.length>s){u={};for(var y,v=e(l.slice(0,s));!(y=v()).done;){var b=y.value;u[b]=i[b]}u['...(truncated keys)...']=l.length-s}}return h.unshift(u),u}return function(t){if(void 0===t)return'undefined';if(null===t)return'null';if('function'==typeof t)try{return t.toString()}catch(t){return'[function unknown]'}else{if(t instanceof Error)return t.name+': '+t.message;try{var e=JSON.stringify(t,v);return void 0===e?'["'+typeof t+'" failed to stringify]':e}catch(e){if('function'==typeof t.toString)try{return t.toString()}catch(t){}}}return'["'+typeof t+'" failed to stringify]'}}var u=o({maxDepth:10,maxStringLimit:100,maxArrayLimit:50,maxObjectKeysLimit:50});_e.default=u},34,[3,18]); -__d(function(g,r,i,a,m,e,d){m.exports=function(t){return r(d[0])(t)||r(d[1])(t)||r(d[2])(t)||r(d[3])()},m.exports.__esModule=!0,m.exports.default=m.exports},35,[36,37,26,38]); -__d(function(g,r,i,a,m,e,d){m.exports=function(t){if(Array.isArray(t))return r(d[0])(t)},m.exports.__esModule=!0,m.exports.default=m.exports},36,[27]); -__d(function(g,r,i,a,m,e,d){m.exports=function(o){if("undefined"!=typeof Symbol&&null!=o[Symbol.iterator]||null!=o["@@iterator"])return Array.from(o)},m.exports.__esModule=!0,m.exports.default=m.exports},37,[]); -__d(function(g,r,i,a,m,e,d){m.exports=function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")},m.exports.__esModule=!0,m.exports.default=m.exports},38,[]); -__d(function(g,r,i,a,m,e,d){'use strict';m.exports=function(t,n,u){var b,c=u.get,o=!1!==u.enumerable,f=!1!==u.writable,l=!1;function s(u){b=u,l=!0,Object.defineProperty(t,n,{value:u,configurable:!0,enumerable:o,writable:f})}Object.defineProperty(t,n,{get:function(){return l||(l=!0,s(c())),b},set:s,configurable:!0,enumerable:o})}},39,[]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,f=new WeakMap;return(t=function(t){return t?f:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var f=t(o);if(f&&f.has(n))return f.get(n);var u={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in n)if("default"!==l&&Object.prototype.hasOwnProperty.call(n,l)){var p=c?Object.getOwnPropertyDescriptor(n,l):null;p&&(p.get||p.set)?Object.defineProperty(u,l,p):u[l]=n[l]}u.default=n,f&&f.set(n,u);return u})(r(d[0])).get('AccessibilityInfo');e.default=n},40,[21]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in n)if("default"!==l&&Object.prototype.hasOwnProperty.call(n,l)){var p=c?Object.getOwnPropertyDescriptor(n,l):null;p&&(p.get||p.set)?Object.defineProperty(f,l,p):f[l]=n[l]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).get('AccessibilityManager');e.default=n},41,[21]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1]));m.exports=function(s,c){'focus'===c&&t.default.sendAccessibilityEvent(s,t.default.getConstants().AccessibilityEventTypes.typeViewFocused),'click'===c&&t.default.sendAccessibilityEvent(s,t.default.getConstants().AccessibilityEventTypes.typeViewClicked)}},42,[3,43]); -__d(function(g,r,i,a,m,e,d){var l=r(d[0])(r(d[1])),n=!0===g.RN$Bridgeless?r(d[2]):null==l.default.unstable_UIManager?r(d[3]):l.default.unstable_UIManager;m.exports=n},43,[3,44,45,46]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;e.default={unstable_UIManager:null}},44,[]); -__d(function(g,r,i,a,m,e,d){'use strict';m.exports={getViewManagerConfig:function(n){return console.warn('Attempting to get config for view manager: '+n),'RCTVirtualText'===n?{}:null},hasViewManagerConfig:function(n){return'RCTVirtualText'===n||'RCTShimmeringView'===n},getConstants:function(){return{}},getConstantsForViewManager:function(n){},getDefaultEventTypes:function(){return[]},lazilyLoadView:function(n){},createView:function(n,t,o,u){},updateView:function(n,t,o){},focus:function(n){},blur:function(n){},findSubviewIn:function(n,t,o){},dispatchViewManagerCommand:function(n,t,o){},measure:function(n,t){},measureInWindow:function(n,t){},viewIsDescendantOf:function(n,t,o){},measureLayout:function(n,t,o,u){},measureLayoutRelativeToParent:function(n,t,o){},setJSResponder:function(n,t){},clearJSResponder:function(){},configureNextLayoutAnimation:function(n,t,o){},removeSubviewsFromContainerWithID:function(n){},replaceExistingNonRootView:function(n,t){},setChildren:function(n,t){},manageChildren:function(n,t,o,u,c,f){},setLayoutAnimationEnabledExperimental:function(n){},sendAccessibilityEvent:function(n,t){},showPopupMenu:function(n,t,o,u){},dismissPopupMenu:function(){}}},45,[]); -__d(function(g,r,i,a,m,_e,d){var n=r(d[0])(r(d[1])),e=r(d[0])(r(d[2])),t={},o=new Set,f={},u=!1;function c(){return u||(f=e.default.getConstants(),u=!0),f}function l(n){if(void 0===t[n]&&g.nativeCallSyncHook&&e.default.getConstantsForViewManager)try{t[n]=e.default.getConstantsForViewManager(n)}catch(e){console.error("NativeUIManager.getConstantsForViewManager('"+n+"') threw an exception.",e),t[n]=null}var f=t[n];if(f)return f;if(!g.nativeCallSyncHook)return f;if(e.default.lazilyLoadView&&!o.has(n)){var u=e.default.lazilyLoadView(n);o.add(n),null!=u&&null!=u.viewConfig&&(c()[n]=u.viewConfig,w(n))}return t[n]}var s=(0,n.default)({},e.default,{createView:function(n,t,o,f){e.default.createView(n,t,o,f)},getConstants:function(){return c()},getViewManagerConfig:function(n){return l(n)},hasViewManagerConfig:function(n){return null!=l(n)}});function w(n){var e=c()[n];t[n]=e,e.Manager&&(r(d[3])(e,'Constants',{get:function(){var n=r(d[4])[e.Manager],t={};return n&&Object.keys(n).forEach(function(e){var o=n[e];'function'!=typeof o&&(t[e]=o)}),t}}),r(d[3])(e,'Commands',{get:function(){var n=r(d[4])[e.Manager],t={},o=0;return n&&Object.keys(n).forEach(function(e){'function'==typeof n[e]&&(t[e]=o++)}),t}}))}e.default.getViewManagerConfig=s.getViewManagerConfig,c().ViewManagerNames&&e.default.getConstants().ViewManagerNames.forEach(function(n){r(d[3])(e.default,n,{get:function(){return e.default.getConstantsForViewManager(n)}})}),g.nativeCallSyncHook||Object.keys(c()).forEach(function(n){r(d[5]).includes(n)||(t[n]||(t[n]=c()[n]),r(d[3])(e.default,n,{get:function(){return console.warn("Accessing view manager configs directly off UIManager via UIManager['"+n+"'] is no longer supported. Use UIManager.getViewManagerConfig('"+n+"') instead."),s.getViewManagerConfig(n)}}))}),m.exports=s},46,[3,29,47,39,22,48]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,f=new WeakMap;return(t=function(t){return t?f:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var f=t(o);if(f&&f.has(n))return f.get(n);var u={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in n)if("default"!==l&&Object.prototype.hasOwnProperty.call(n,l)){var p=c?Object.getOwnPropertyDescriptor(n,l):null;p&&(p.get||p.set)?Object.defineProperty(u,l,p):u[l]=n[l]}u.default=n,f&&f.set(n,u);return u})(r(d[0])).getEnforcing('UIManager');e.default=n},47,[21]); -__d(function(g,r,i,a,m,e,d){'use strict';m.exports=['clearJSResponder','configureNextLayoutAnimation','createView','dismissPopupMenu','dispatchViewManagerCommand','findSubviewIn','getConstantsForViewManager','getDefaultEventTypes','manageChildren','measure','measureInWindow','measureLayout','measureLayoutRelativeToParent','removeRootView','removeSubviewsFromContainerWithID','replaceExistingNonRootView','sendAccessibilityEvent','setChildren','setJSResponder','setLayoutAnimationEnabledExperimental','showPopupMenu','updateView','viewIsDescendantOf','PopupMenu','LazyViewManagersEnabled','ViewManagerNames','StyleConstants','AccessibilityEventTypes','UIView','getViewManagerConfig','hasViewManagerConfig','blur','focus','genericBubblingEventTypes','genericDirectEventTypes','lazilyLoadView']},48,[]); -__d(function(g,r,i,a,m,e,d){'use strict';var t;t=r(d[0]),m.exports=t},49,[50]); -__d(function(e,n,t,r,l,a,i){"use strict";n(i[0]);var u=n(i[1]);function o(e,n,t,r,l,a,i,u,o){var s=Array.prototype.slice.call(arguments,3);try{n.apply(t,s)}catch(e){this.onError(e)}}var s=!1,c=null,d=!1,f=null,p={onError:function(e){s=!0,c=e}};function h(e,n,t,r,l,a,i,u,d){s=!1,c=null,o.apply(p,arguments)}function g(e,n,t,r,l,a,i,u,o){if(h.apply(this,arguments),s){if(!s)throw Error("clearCaughtError was called but no error was captured. This error is likely caused by a bug in React. Please file an issue.");var p=c;s=!1,c=null,d||(d=!0,f=p)}}var m=Array.isArray,v=null,b=null,y=null;function S(e,n,t){var r=e.type||"unknown-event";e.currentTarget=y(t),g(r,n,void 0,e),e.currentTarget=null}function k(e){var n=e._dispatchListeners,t=e._dispatchInstances;if(m(n))throw Error("executeDirectDispatch(...): Invalid `event`.");return e.currentTarget=n?y(t):null,n=n?n(e):null,e.currentTarget=null,e._dispatchListeners=null,e._dispatchInstances=null,n}function w(){return!0}function _(){return!1}function T(e,n,t,r){for(var l in this.dispatchConfig=e,this._targetInst=n,this.nativeEvent=t,this._dispatchInstances=this._dispatchListeners=null,e=this.constructor.Interface)e.hasOwnProperty(l)&&((n=e[l])?this[l]=n(t):"target"===l?this.target=r:this[l]=t[l]);return this.isDefaultPrevented=(null!=t.defaultPrevented?t.defaultPrevented:!1===t.returnValue)?w:_,this.isPropagationStopped=_,this}function x(e,n,t,r){if(this.eventPool.length){var l=this.eventPool.pop();return this.call(l,e,n,t,r),l}return new this(e,n,t,r)}function P(e){if(!(e instanceof this))throw Error("Trying to release an event instance into a pool of a different type.");e.destructor(),10>this.eventPool.length&&this.eventPool.push(e)}function R(e){e.getPooled=x,e.eventPool=[],e.release=P}n(i[2])(T.prototype,{preventDefault:function(){this.defaultPrevented=!0;var e=this.nativeEvent;e&&(e.preventDefault?e.preventDefault():"unknown"!=typeof e.returnValue&&(e.returnValue=!1),this.isDefaultPrevented=w)},stopPropagation:function(){var e=this.nativeEvent;e&&(e.stopPropagation?e.stopPropagation():"unknown"!=typeof e.cancelBubble&&(e.cancelBubble=!0),this.isPropagationStopped=w)},persist:function(){this.isPersistent=w},isPersistent:_,destructor:function(){var e,n=this.constructor.Interface;for(e in n)this[e]=null;this.nativeEvent=this._targetInst=this.dispatchConfig=null,this.isPropagationStopped=this.isDefaultPrevented=_,this._dispatchInstances=this._dispatchListeners=null}}),T.Interface={type:null,target:null,currentTarget:function(){return null},eventPhase:null,bubbles:null,cancelable:null,timeStamp:function(e){return e.timeStamp||Date.now()},defaultPrevented:null,isTrusted:null},T.extend=function(e){function t(){}function r(){return l.apply(this,arguments)}var l=this;t.prototype=l.prototype;var a=new t;return n(i[2])(a,r.prototype),r.prototype=a,r.prototype.constructor=r,r.Interface=n(i[2])({},l.Interface,e),r.extend=l.extend,R(r),r},R(T);var E=T.extend({touchHistory:function(){return null}});function C(e){return"topTouchStart"===e}function N(e){return"topTouchMove"===e}var z=["topTouchStart"],I=["topTouchMove"],L=["topTouchCancel","topTouchEnd"],U=[],M={touchBank:U,numberActiveTouches:0,indexOfSingleActiveTouch:-1,mostRecentTimeStamp:0};function F(e){return e.timeStamp||e.timestamp}function D(e){if(null==(e=e.identifier))throw Error("Touch object is missing identifier.");return e}function A(e){var n=D(e),t=U[n];t?(t.touchActive=!0,t.startPageX=e.pageX,t.startPageY=e.pageY,t.startTimeStamp=F(e),t.currentPageX=e.pageX,t.currentPageY=e.pageY,t.currentTimeStamp=F(e),t.previousPageX=e.pageX,t.previousPageY=e.pageY,t.previousTimeStamp=F(e)):(t={touchActive:!0,startPageX:e.pageX,startPageY:e.pageY,startTimeStamp:F(e),currentPageX:e.pageX,currentPageY:e.pageY,currentTimeStamp:F(e),previousPageX:e.pageX,previousPageY:e.pageY,previousTimeStamp:F(e)},U[n]=t),M.mostRecentTimeStamp=F(e)}function Q(e){var n=U[D(e)];n&&(n.touchActive=!0,n.previousPageX=n.currentPageX,n.previousPageY=n.currentPageY,n.previousTimeStamp=n.currentTimeStamp,n.currentPageX=e.pageX,n.currentPageY=e.pageY,n.currentTimeStamp=F(e),M.mostRecentTimeStamp=F(e))}function H(e){var n=U[D(e)];n&&(n.touchActive=!1,n.previousPageX=n.currentPageX,n.previousPageY=n.currentPageY,n.previousTimeStamp=n.currentTimeStamp,n.currentPageX=e.pageX,n.currentPageY=e.pageY,n.currentTimeStamp=F(e),M.mostRecentTimeStamp=F(e))}var O,j={instrument:function(e){O=e},recordTouchTrack:function(e,n){if(null!=O&&O(e,n),N(e))n.changedTouches.forEach(Q);else if(C(e))n.changedTouches.forEach(A),M.numberActiveTouches=n.touches.length,1===M.numberActiveTouches&&(M.indexOfSingleActiveTouch=n.touches[0].identifier);else if(("topTouchEnd"===e||"topTouchCancel"===e)&&(n.changedTouches.forEach(H),M.numberActiveTouches=n.touches.length,1===M.numberActiveTouches))for(e=0;ei||(a=i),Ne(a,e,l)}}}),v=function(e){return we.get(e._nativeTag)||null},b=_e,y=function(e){var n=(e=e.stateNode)._nativeTag;if(void 0===n&&(n=(e=e.canonical)._nativeTag),!n)throw Error("All native instances should have a tag.");return e},re.injection.injectGlobalResponderHandler({onChange:function(e,t,r){null!==t?n(i[3]).UIManager.setJSResponder(t.stateNode._nativeTag,r):n(i[3]).UIManager.clearJSResponder()}});var ze=u.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,Ie=60103,Le=60106,Ue=60107,Me=60108,Fe=60114,De=60109,Ae=60110,Qe=60112,He=60113,Oe=60120,je=60115,Be=60116,Ve=60129,We=60130,Ye=60131,qe=60132;if("function"==typeof Symbol&&Symbol.for){var Xe=Symbol.for;Ie=Xe("react.element"),Le=Xe("react.portal"),Ue=Xe("react.fragment"),Me=Xe("react.strict_mode"),Fe=Xe("react.profiler"),De=Xe("react.provider"),Ae=Xe("react.context"),Qe=Xe("react.forward_ref"),He=Xe("react.suspense"),Oe=Xe("react.suspense_list"),je=Xe("react.memo"),Be=Xe("react.lazy"),Xe("react.scope"),Ve=Xe("react.debug_trace_mode"),We=Xe("react.offscreen"),Ye=Xe("react.legacy_hidden"),qe=Xe("react.cache")}var $e="function"==typeof Symbol&&Symbol.iterator;function Ge(e){return null===e||"object"!=typeof e?null:"function"==typeof(e=$e&&e[$e]||e["@@iterator"])?e:null}function Ke(e){if(null==e)return null;if("function"==typeof e)return e.displayName||e.name||null;if("string"==typeof e)return e;switch(e){case Ue:return"Fragment";case Le:return"Portal";case Fe:return"Profiler";case Me:return"StrictMode";case He:return"Suspense";case Oe:return"SuspenseList";case qe:return"Cache"}if("object"==typeof e)switch(e.$$typeof){case Ae:return(e.displayName||"Context")+".Consumer";case De:return(e._context.displayName||"Context")+".Provider";case Qe:var n=e.render;return(e=e.displayName)||(e=""!==(e=n.displayName||n.name||"")?"ForwardRef("+e+")":"ForwardRef"),e;case je:return null!==(n=e.displayName||null)?n:Ke(e.type)||"Memo";case Be:n=e._payload,e=e._init;try{return Ke(e(n))}catch(e){}}return null}function Je(e){var n=e.type;switch(e.tag){case 24:return"Cache";case 9:return(n.displayName||"Context")+".Consumer";case 10:return(n._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=(e=n.render).displayName||e.name||"",n.displayName||(""!==e?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return n;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return Ke(n);case 23:return"LegacyHidden";case 8:return n===Me?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 1:case 0:case 17:case 2:case 14:case 15:if("function"==typeof n)return n.displayName||n.name||null;if("string"==typeof n)return n}return null}function Ze(e){var n=e,t=e;if(e.alternate)for(;n.return;)n=n.return;else{e=n;do{0!=(2050&(n=e).flags)&&(t=n.return),e=n.return}while(e)}return 3===n.tag?t:null}function en(e){if(Ze(e)!==e)throw Error("Unable to find node on an unmounted component.")}function nn(e){var n=e.alternate;if(!n){if(null===(n=Ze(e)))throw Error("Unable to find node on an unmounted component.");return n!==e?null:e}for(var t=e,r=n;;){var l=t.return;if(null===l)break;var a=l.alternate;if(null===a){if(null!==(r=l.return)){t=r;continue}break}if(l.child===a.child){for(a=l.child;a;){if(a===t)return en(l),e;if(a===r)return en(l),n;a=a.sibling}throw Error("Unable to find node on an unmounted component.")}if(t.return!==r.return)t=l,r=a;else{for(var i=!1,u=l.child;u;){if(u===t){i=!0,t=l,r=a;break}if(u===r){i=!0,r=l,t=a;break}u=u.sibling}if(!i){for(u=a.child;u;){if(u===t){i=!0,t=a,r=l;break}if(u===r){i=!0,r=a,t=l;break}u=u.sibling}if(!i)throw Error("Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue.")}}if(t.alternate!==r)throw Error("Return fibers should always be each others' alternates. This error is likely caused by a bug in React. Please file an issue.")}if(3!==t.tag)throw Error("Unable to find node on an unmounted component.");return t.stateNode.current===t?e:n}function tn(e){return null!==(e=nn(e))?rn(e):null}function rn(e){if(5===e.tag||6===e.tag)return e;for(e=e.child;null!==e;){var n=rn(e);if(null!==n)return n;e=e.sibling}return null}var ln={},an=null,un=0,on={unsafelyIgnoreFunctions:!0};function sn(e,t){return"object"!=typeof t||null===t||n(i[3]).deepDiffer(e,t,on)}function cn(e,n,t){if(m(n))for(var r=n.length;r--&&0=(a=n&-n)||16===l&&0!=(4194240&a)))return n;if(0!=(4&r)&&(r|=16&t),0!==(n=e.entangledLanes))for(e=e.entanglements,n&=r;0t;t++)n.push(e);return n}function Rn(e,n,t){e.pendingLanes|=n,536870912!==n&&(e.suspendedLanes=0,e.pingedLanes=0),(e=e.eventTimes)[n=31-Nn(n)]=t}function En(e,n){var t=e.pendingLanes&~n;e.pendingLanes=n,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=n,e.mutableReadLanes&=n,e.entangledLanes&=n,n=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0Xn||(e.current=qn[Xn],qn[Xn]=null,Xn--)}function Kn(e,n){qn[++Xn]=e.current,e.current=n}var Jn={},Zn=$n(Jn),et=$n(!1),nt=Jn;function tt(e,n){var t=e.type.contextTypes;if(!t)return Jn;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===n)return r.__reactInternalMemoizedMaskedChildContext;var l,a={};for(l in t)a[l]=n[l];return r&&((e=e.stateNode).__reactInternalMemoizedUnmaskedChildContext=n,e.__reactInternalMemoizedMaskedChildContext=a),a}function rt(e){return null!==(e=e.childContextTypes)&&void 0!==e}function lt(){Gn(et),Gn(Zn)}function at(e,n,t){if(Zn.current!==Jn)throw Error("Unexpected context found on stack. This error is likely caused by a bug in React. Please file an issue.");Kn(Zn,n),Kn(et,t)}function it(e,t,r){var l=e.stateNode;if(t=t.childContextTypes,"function"!=typeof l.getChildContext)return r;for(var a in l=l.getChildContext())if(!(a in t))throw Error((Je(e)||"Unknown")+'.getChildContext(): key "'+a+'" is not defined in childContextTypes.');return n(i[2])({},r,l)}function ut(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||Jn,nt=Zn.current,Kn(Zn,e),Kn(et,et.current),!0}function ot(e,n,t){var r=e.stateNode;if(!r)throw Error("Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue.");t?(e=it(e,n,nt),r.__reactInternalMemoizedMergedChildContext=e,Gn(et),Gn(Zn),Kn(Zn,e)):Gn(et),Kn(et,t)}var st=null,ct=!1,dt=!1;function ft(){if(!dt&&null!==st){dt=!0;var e=0,t=Ln;try{var r=st;for(Ln=1;eg?(m=h,h=null):m=h.sibling;var v=f(l,h,u[g],o);if(null===v){null===h&&(h=m);break}e&&h&&null===v.alternate&&n(l,h),i=a(v,i,g),null===c?s=v:c.sibling=v,c=v,h=m}if(g===u.length)return t(l,h),s;if(null===h){for(;gg?(m=h,h=null):m=h.sibling;var b=f(l,h,v.value,o);if(null===b){null===h&&(h=m);break}e&&h&&null===b.alternate&&n(l,h),i=a(b,i,g),null===c?s=b:c.sibling=b,c=b,h=m}if(v.done)return t(l,h),s;if(null===h){for(;!v.done;g++,v=u.next())null!==(v=d(l,v.value,o))&&(i=a(v,i,g),null===c?s=v:c.sibling=v,c=v);return s}for(h=r(l,h);!v.done;g++,v=u.next())null!==(v=p(h,l,g,v.value,o))&&(e&&null!==v.alternate&&h.delete(null===v.key?g:v.key),i=a(v,i,g),null===c?s=v:c.sibling=v,c=v);return e&&h.forEach(function(e){return n(l,e)}),s}return function(e,r,a,u){var o="object"==typeof a&&null!==a&&a.type===Ue&&null===a.key;if(o&&(a=a.props.children),"object"==typeof a&&null!==a){switch(a.$$typeof){case Ie:e:{var s=a.key;for(o=r;null!==o;){if(o.key===s){if((s=a.type)===Ue){if(7===o.tag){t(e,o.sibling),(r=l(o,a.props.children)).return=e,e=r;break e}}else if(o.elementType===s){t(e,o.sibling),(r=l(o,a.props)).ref=Wt(e,o,a),r.return=e,e=r;break e}t(e,o);break}n(e,o),o=o.sibling}a.type===Ue?((r=Ka(a.props.children,e.mode,u,a.key)).return=e,e=r):((u=Ga(a.type,a.key,a.props,null,e.mode,u)).ref=Wt(e,r,a),u.return=e,e=u)}return i(e);case Le:e:{for(o=a.key;null!==r;){if(r.key===o){if(4===r.tag&&r.stateNode.containerInfo===a.containerInfo&&r.stateNode.implementation===a.implementation){t(e,r.sibling),(r=l(r,a.children||[])).return=e,e=r;break e}t(e,r);break}n(e,r),r=r.sibling}(r=ei(a,e.mode,u)).return=e,e=r}return i(e)}if(m(a))return h(e,r,a,u);if(Ge(a))return g(e,r,a,u);Yt(e,a)}if("string"==typeof a||"number"==typeof a)return a=""+a,null!==r&&6===r.tag?(t(e,r.sibling),(r=l(r,a)).return=e,e=r):(t(e,r),(r=Za(a,e.mode,u)).return=e,e=r),i(e);if(void 0===a&&!o)switch(e.tag){case 1:case 0:case 11:case 15:throw Error((Je(e)||"Component")+"(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.")}return t(e,r)}}var Xt=qt(!0),$t=qt(!1),Gt={},Kt=$n(Gt),Jt=$n(Gt),Zt=$n(Gt);function er(e){if(e===Gt)throw Error("Expected host context to exist. This error is likely caused by a bug in React. Please file an issue.");return e}function nr(e,n){Kn(Zt,n),Kn(Jt,e),Kn(Kt,Gt),Gn(Kt),Kn(Kt,{isInAParentText:!1})}function tr(){Gn(Kt),Gn(Jt),Gn(Zt)}function rr(e){er(Zt.current);var n=er(Kt.current),t=e.type;t="AndroidTextInput"===t||"RCTMultilineTextInputView"===t||"RCTSinglelineTextInputView"===t||"RCTText"===t||"RCTVirtualText"===t,n!==(t=n.isInAParentText!==t?{isInAParentText:t}:n)&&(Kn(Jt,e),Kn(Kt,t))}function lr(e){Jt.current===e&&(Gn(Kt),Gn(Jt))}var ar=$n(0);function ir(e){for(var n=e;null!==n;){if(13===n.tag){var t=n.memoizedState;if(null!==t&&(null===t.dehydrated||Mn()||Mn()))return n}else if(19===n.tag&&void 0!==n.memoizedProps.revealOrder){if(0!=(128&n.flags))return n}else if(null!==n.child){n.child.return=n,n=n.child;continue}if(n===e)break;for(;null===n.sibling;){if(null===n.return||n.return===e)return null;n=n.return}n.sibling.return=n.return,n=n.sibling}return null}var ur=[];function or(){for(var e=0;ea))throw Error("Too many re-renders. React limits the number of renders to prevent an infinite loop.");a+=1,hr=pr=null,n.updateQueue=null,sr.current=Yr,e=t(r,l)}while(mr)}if(sr.current=Br,n=null!==pr&&null!==pr.next,dr=0,hr=pr=fr=null,gr=!1,n)throw Error("Rendered fewer hooks than expected. This may be caused by an accidental early return statement.");return e}function Sr(){var e={memoizedState:null,baseState:null,baseQueue:null,queue:null,next:null};return null===hr?fr.memoizedState=hr=e:hr=hr.next=e,hr}function kr(){if(null===pr){var e=fr.alternate;e=null!==e?e.memoizedState:null}else e=pr.next;var n=null===hr?fr.memoizedState:hr.next;if(null!==n)hr=n,pr=e;else{if(null===e)throw Error("Rendered more hooks than during the previous render.");e={memoizedState:(pr=e).memoizedState,baseState:pr.baseState,baseQueue:pr.baseQueue,queue:pr.queue,next:null},null===hr?fr.memoizedState=hr=e:hr=hr.next=e}return hr}function wr(e,n){return"function"==typeof n?n(e):n}function _r(e){var n=kr(),t=n.queue;if(null===t)throw Error("Should have a queue. This is likely a bug in React. Please file an issue.");t.lastRenderedReducer=e;var r=pr,l=r.baseQueue,a=t.pending;if(null!==a){if(null!==l){var i=l.next;l.next=a.next,a.next=i}r.baseQueue=l=a,t.pending=null}if(null!==l){a=l.next,r=r.baseState;var u=i=null,o=null,s=a;do{var c=s.lane;if((dr&c)===c)null!==o&&(o=o.next={lane:0,action:s.action,eagerReducer:s.eagerReducer,eagerState:s.eagerState,next:null}),r=s.eagerReducer===e?s.eagerState:e(r,s.action);else{var d={lane:c,action:s.action,eagerReducer:s.eagerReducer,eagerState:s.eagerState,next:null};null===o?(u=o=d,i=r):o=o.next=d,fr.lanes|=c,ia|=c}s=s.next}while(null!==s&&s!==a);null===o?i=r:o.next=u,ht(r,n.memoizedState)||(Zr=!0),n.memoizedState=r,n.baseState=i,n.baseQueue=o,t.lastRenderedState=r}if(null!==(e=t.interleaved)){l=e;do{a=l.lane,fr.lanes|=a,ia|=a,l=l.next}while(l!==e)}else null===l&&(t.lanes=0);return[n.memoizedState,t.dispatch]}function Tr(e){var n=kr(),t=n.queue;if(null===t)throw Error("Should have a queue. This is likely a bug in React. Please file an issue.");t.lastRenderedReducer=e;var r=t.dispatch,l=t.pending,a=n.memoizedState;if(null!==l){t.pending=null;var i=l=l.next;do{a=e(a,i.action),i=i.next}while(i!==l);ht(a,n.memoizedState)||(Zr=!0),n.memoizedState=a,null===n.baseQueue&&(n.baseState=a),t.lastRenderedState=a}return[a,r]}function xr(e,n,t){var r=n._getVersion;r=r(n._source);var l=n._workInProgressVersionPrimary;if(null!==l?e=l===r:(e=e.mutableReadLanes,(e=(dr&e)===e)&&(n._workInProgressVersionPrimary=r,ur.push(n))),e)return t(n._source);throw ur.push(n),Error("Cannot read from mutable source during the current render without tearing. This may be a bug in React. Please file an issue.")}function Pr(e,n,t,r){var l=Zl;if(null===l)throw Error("Expected a work-in-progress root. This is a bug in React. Please file an issue.");var a=n._getVersion,i=a(n._source),u=sr.current,o=u.useState(function(){return xr(l,n,t)}),s=o[1],c=o[0];o=hr;var d=e.memoizedState,f=d.refs,p=f.getSnapshot,h=d.source;d=d.subscribe;var g=fr;return e.memoizedState={refs:f,source:n,subscribe:r},u.useEffect(function(){f.getSnapshot=t,f.setSnapshot=s;var e=a(n._source);ht(i,e)||(e=t(n._source),ht(c,e)||(s(e),e=wa(g),l.mutableReadLanes|=e&l.pendingLanes),Cn(l,l.mutableReadLanes))},[t,n,r]),u.useEffect(function(){return r(n._source,function(){var e=f.getSnapshot,t=f.setSnapshot;try{t(e(n._source));var r=wa(g);l.mutableReadLanes|=r&l.pendingLanes}catch(e){t(function(){throw e})}})},[n,r]),ht(p,t)&&ht(h,n)&&ht(d,r)||((e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:wr,lastRenderedState:c}).dispatch=s=jr.bind(null,fr,e),o.queue=e,o.baseQueue=null,c=xr(l,n,t),o.memoizedState=o.baseState=c),c}function Rr(e,n,t){return Pr(kr(),e,n,t)}function Er(e){var n=Sr();return"function"==typeof e&&(e=e()),n.memoizedState=n.baseState=e,e=(e=n.queue={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:wr,lastRenderedState:e}).dispatch=jr.bind(null,fr,e),[n.memoizedState,e]}function Cr(e,n,t,r){return e={tag:e,create:n,destroy:t,deps:r,next:null},null===(n=fr.updateQueue)?(n={lastEffect:null},fr.updateQueue=n,n.lastEffect=e.next=e):null===(t=n.lastEffect)?n.lastEffect=e.next=e:(r=t.next,t.next=e,e.next=r,n.lastEffect=e),e}function Nr(){return kr().memoizedState}function zr(e,n,t,r){var l=Sr();fr.flags|=e,l.memoizedState=Cr(1|n,t,void 0,void 0===r?null:r)}function Ir(e,n,t,r){var l=kr();r=void 0===r?null:r;var a=void 0;if(null!==pr){var i=pr.memoizedState;if(a=i.destroy,null!==r&&br(r,i.deps))return void(l.memoizedState=Cr(n,t,a,r))}fr.flags|=e,l.memoizedState=Cr(1|n,t,a,r)}function Lr(e,n){return zr(1049600,4,e,n)}function Ur(e,n){return Ir(1024,4,e,n)}function Mr(e,n){return Ir(4,2,e,n)}function Fr(e,n){return"function"==typeof n?(e=e(),n(e),function(){n(null)}):null!==n&&void 0!==n?(e=e(),n.current=e,function(){n.current=null}):void 0}function Dr(e,n,t){return t=null!==t&&void 0!==t?t.concat([e]):null,Ir(4,2,Fr.bind(null,n,e),t)}function Ar(){}function Qr(e,n){var t=kr();n=void 0===n?null:n;var r=t.memoizedState;return null!==r&&null!==n&&br(n,r[1])?r[0]:(t.memoizedState=[e,n],e)}function Hr(e,n){var t=kr();n=void 0===n?null:n;var r=t.memoizedState;return null!==r&&null!==n&&br(n,r[1])?r[0]:(e=e(),t.memoizedState=[e,n],e)}function Or(e,n){var t=Ln;Ln=0!==t&&4>t?t:4,e(!0);var r=cr.transition;cr.transition=1;try{e(!1),n()}finally{Ln=t,cr.transition=r}}function jr(e,n,t){var r=ka(),l=wa(e),a={lane:l,action:t,eagerReducer:null,eagerState:null,next:null},i=e.alternate;if(e===fr||null!==i&&i===fr)mr=gr=!0,null===(l=n.pending)?a.next=a:(a.next=l.next,l.next=a),n.pending=a;else{if(null!==Zl&&0!=(1&e.mode)&&0==(8&Jl)){var u=n.interleaved;null===u?(a.next=a,null===Et?Et=[n]:Et.push(n)):(a.next=u.next,u.next=a),n.interleaved=a}else null===(u=n.pending)?a.next=a:(a.next=u.next,u.next=a),n.pending=a;if(0===e.lanes&&(null===i||0===i.lanes)&&null!==(i=n.lastRenderedReducer))try{var o=n.lastRenderedState,s=i(o,t);if(a.eagerReducer=i,a.eagerState=s,ht(s,o))return}catch(e){}a=_a(e,l,r),0!=(4194240&l)&&null!==a&&(e=n.lanes,l|=e&=a.pendingLanes,n.lanes=l,Cn(a,l))}}var Br={readContext:Rt,useCallback:vr,useContext:vr,useEffect:vr,useImperativeHandle:vr,useLayoutEffect:vr,useMemo:vr,useReducer:vr,useRef:vr,useState:vr,useDebugValue:vr,useDeferredValue:vr,useTransition:vr,useMutableSource:vr,useOpaqueIdentifier:vr,unstable_isNewReconciler:!1},Vr={readContext:Rt,useCallback:function(e,n){return Sr().memoizedState=[e,void 0===n?null:n],e},useContext:Rt,useEffect:Lr,useImperativeHandle:function(e,n,t){return t=null!==t&&void 0!==t?t.concat([e]):null,zr(4,2,Fr.bind(null,n,e),t)},useLayoutEffect:function(e,n){return zr(4,2,e,n)},useMemo:function(e,n){var t=Sr();return n=void 0===n?null:n,e=e(),t.memoizedState=[e,n],e},useReducer:function(e,n,t){var r=Sr();return n=void 0!==t?t(n):n,r.memoizedState=r.baseState=n,e=(e=r.queue={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:n}).dispatch=jr.bind(null,fr,e),[r.memoizedState,e]},useRef:function(e){return e={current:e},Sr().memoizedState=e},useState:Er,useDebugValue:Ar,useDeferredValue:function(e){var n=Er(e),t=n[0],r=n[1];return Lr(function(){var n=cr.transition;cr.transition=1;try{r(e)}finally{cr.transition=n}},[e]),t},useTransition:function(){var e=Er(!1),n=e[0];return e=Or.bind(null,e[1]),Sr().memoizedState=e,[n,e]},useMutableSource:function(e,n,t){var r=Sr();return r.memoizedState={refs:{getSnapshot:n,setSnapshot:null},source:e,subscribe:t},Pr(r,e,n,t)},useOpaqueIdentifier:function(){throw Error("Not yet implemented")},unstable_isNewReconciler:!1},Wr={readContext:Rt,useCallback:Qr,useContext:Rt,useEffect:Ur,useImperativeHandle:Dr,useLayoutEffect:Mr,useMemo:Hr,useReducer:_r,useRef:Nr,useState:function(){return _r(wr)},useDebugValue:Ar,useDeferredValue:function(e){var n=_r(wr),t=n[0],r=n[1];return Ur(function(){var n=cr.transition;cr.transition=1;try{r(e)}finally{cr.transition=n}},[e]),t},useTransition:function(){return[_r(wr)[0],kr().memoizedState]},useMutableSource:Rr,useOpaqueIdentifier:function(){return _r(wr)[0]},unstable_isNewReconciler:!1},Yr={readContext:Rt,useCallback:Qr,useContext:Rt,useEffect:Ur,useImperativeHandle:Dr,useLayoutEffect:Mr,useMemo:Hr,useReducer:Tr,useRef:Nr,useState:function(){return Tr(wr)},useDebugValue:Ar,useDeferredValue:function(e){var n=Tr(wr),t=n[0],r=n[1];return Ur(function(){var n=cr.transition;cr.transition=1;try{r(e)}finally{cr.transition=n}},[e]),t},useTransition:function(){return[Tr(wr)[0],kr().memoizedState]},useMutableSource:Rr,useOpaqueIdentifier:function(){return Tr(wr)[0]},unstable_isNewReconciler:!1};function qr(e,n){return{value:e,source:n,stack:vt(n)}}if("function"!=typeof n(i[3]).ReactFiberErrorDialog.showErrorDialog)throw Error("Expected ReactFiberErrorDialog.showErrorDialog to be a function.");function Xr(e,t){try{!1!==n(i[3]).ReactFiberErrorDialog.showErrorDialog({componentStack:null!==t.stack?t.stack:"",error:t.value,errorBoundary:null!==e&&1===e.tag?e.stateNode:null})&&console.error(t.value)}catch(e){setTimeout(function(){throw e})}}var $r="function"==typeof WeakMap?WeakMap:Map;function Gr(e,n,t){(t=It(-1,t)).tag=3,t.payload={element:null};var r=n.value;return t.callback=function(){da||(da=!0,fa=r),Xr(e,n)},t}function Kr(e,n,t){(t=It(-1,t)).tag=3;var r=e.type.getDerivedStateFromError;if("function"==typeof r){var l=n.value;t.payload=function(){return Xr(e,n),r(l)}}var a=e.stateNode;return null!==a&&"function"==typeof a.componentDidCatch&&(t.callback=function(){"function"!=typeof r&&(null===pa?pa=new Set([this]):pa.add(this),Xr(e,n));var t=n.stack;this.componentDidCatch(n.value,{componentStack:null!==t?t:""})}),t}var Jr=ze.ReactCurrentOwner,Zr=!1;function el(e,n,t,r){n.child=null===e?$t(n,null,t,r):Xt(n,e.child,t,r)}function nl(e,n,t,r,l){t=t.render;var a=n.ref;return Pt(n,l),r=yr(e,n,t,r,a,l),null===e||Zr?(n.flags|=1,el(e,n,r,l),n.child):(n.updateQueue=e.updateQueue,n.flags&=-1029,e.lanes&=~l,_l(e,n,l))}function tl(e,n,t,r,l,a){if(null===e){var i=t.type;return"function"!=typeof i||qa(i)||void 0!==i.defaultProps||null!==t.compare||void 0!==t.defaultProps?((e=Ga(t.type,null,r,n,n.mode,a)).ref=n.ref,e.return=n,n.child=e):(n.tag=15,n.type=i,rl(e,n,i,r,l,a))}return i=e.child,0==(l&a)&&(l=i.memoizedProps,(t=null!==(t=t.compare)?t:gt)(l,r)&&e.ref===n.ref)?_l(e,n,a):(n.flags|=1,(e=$a(i,r)).ref=n.ref,e.return=n,n.child=e)}function rl(e,n,t,r,l,a){if(null!==e&>(e.memoizedProps,r)&&e.ref===n.ref){if(Zr=!1,0==(a&l))return n.lanes=e.lanes,_l(e,n,a);0!=(32768&e.flags)&&(Zr=!0)}return il(e,n,t,r,a)}function ll(e,n,t){var r=n.pendingProps,l=r.children,a=null!==e?e.memoizedState:null;if("hidden"===r.mode||"unstable-defer-without-hiding"===r.mode)if(0==(1&n.mode))n.memoizedState={baseLanes:0,cachePool:null},Kn(ra,ta),ta|=t;else{if(0==(1073741824&t))return e=null!==a?a.baseLanes|t:t,n.lanes=n.childLanes=1073741824,n.memoizedState={baseLanes:e,cachePool:null},n.updateQueue=null,Kn(ra,ta),ta|=e,null;n.memoizedState={baseLanes:0,cachePool:null},r=null!==a?a.baseLanes:t,Kn(ra,ta),ta|=r}else null!==a?(r=a.baseLanes|t,n.memoizedState=null):r=t,Kn(ra,ta),ta|=r;return el(e,n,l,t),n.child}function al(e,n){var t=n.ref;(null===e&&null!==t||null!==e&&e.ref!==t)&&(n.flags|=256)}function il(e,n,t,r,l){var a=rt(t)?nt:Zn.current;return a=tt(n,a),Pt(n,l),t=yr(e,n,t,r,a,l),null===e||Zr?(n.flags|=1,el(e,n,t,l),n.child):(n.updateQueue=e.updateQueue,n.flags&=-1029,e.lanes&=~l,_l(e,n,l))}function ul(e,n,t,r,l){if(rt(t)){var a=!0;ut(n)}else a=!1;if(Pt(n,l),null===n.stateNode)null!==e&&(e.alternate=null,n.alternate=null,n.flags|=2),jt(n,t,r),Vt(n,t,r,l),r=!0;else if(null===e){var i=n.stateNode,u=n.memoizedProps;i.props=u;var o=i.context,s=t.contextType;"object"==typeof s&&null!==s?s=Rt(s):s=tt(n,s=rt(t)?nt:Zn.current);var c=t.getDerivedStateFromProps,d="function"==typeof c||"function"==typeof i.getSnapshotBeforeUpdate;d||"function"!=typeof i.UNSAFE_componentWillReceiveProps&&"function"!=typeof i.componentWillReceiveProps||(u!==r||o!==s)&&Bt(n,i,r,s),Ct=!1;var f=n.memoizedState;i.state=f,Ft(n,r,i,l),o=n.memoizedState,u!==r||f!==o||et.current||Ct?("function"==typeof c&&(Qt(n,t,c,r),o=n.memoizedState),(u=Ct||Ot(n,t,u,r,f,o,s))?(d||"function"!=typeof i.UNSAFE_componentWillMount&&"function"!=typeof i.componentWillMount||("function"==typeof i.componentWillMount&&i.componentWillMount(),"function"==typeof i.UNSAFE_componentWillMount&&i.UNSAFE_componentWillMount()),"function"==typeof i.componentDidMount&&(n.flags|=4)):("function"==typeof i.componentDidMount&&(n.flags|=4),n.memoizedProps=r,n.memoizedState=o),i.props=r,i.state=o,i.context=s,r=u):("function"==typeof i.componentDidMount&&(n.flags|=4),r=!1)}else{i=n.stateNode,zt(e,n),u=n.memoizedProps,s=n.type===n.elementType?u:bt(n.type,u),i.props=s,d=n.pendingProps,f=i.context,"object"==typeof(o=t.contextType)&&null!==o?o=Rt(o):o=tt(n,o=rt(t)?nt:Zn.current);var p=t.getDerivedStateFromProps;(c="function"==typeof p||"function"==typeof i.getSnapshotBeforeUpdate)||"function"!=typeof i.UNSAFE_componentWillReceiveProps&&"function"!=typeof i.componentWillReceiveProps||(u!==d||f!==o)&&Bt(n,i,r,o),Ct=!1,f=n.memoizedState,i.state=f,Ft(n,r,i,l);var h=n.memoizedState;u!==d||f!==h||et.current||Ct?("function"==typeof p&&(Qt(n,t,p,r),h=n.memoizedState),(s=Ct||Ot(n,t,s,r,f,h,o)||!1)?(c||"function"!=typeof i.UNSAFE_componentWillUpdate&&"function"!=typeof i.componentWillUpdate||("function"==typeof i.componentWillUpdate&&i.componentWillUpdate(r,h,o),"function"==typeof i.UNSAFE_componentWillUpdate&&i.UNSAFE_componentWillUpdate(r,h,o)),"function"==typeof i.componentDidUpdate&&(n.flags|=4),"function"==typeof i.getSnapshotBeforeUpdate&&(n.flags|=512)):("function"!=typeof i.componentDidUpdate||u===e.memoizedProps&&f===e.memoizedState||(n.flags|=4),"function"!=typeof i.getSnapshotBeforeUpdate||u===e.memoizedProps&&f===e.memoizedState||(n.flags|=512),n.memoizedProps=r,n.memoizedState=h),i.props=r,i.state=h,i.context=o,r=s):("function"!=typeof i.componentDidUpdate||u===e.memoizedProps&&f===e.memoizedState||(n.flags|=4),"function"!=typeof i.getSnapshotBeforeUpdate||u===e.memoizedProps&&f===e.memoizedState||(n.flags|=512),r=!1)}return ol(e,n,t,r,a,l)}function ol(e,n,t,r,l,a){al(e,n);var i=0!=(128&n.flags);if(!r&&!i)return l&&ot(n,t,!1),_l(e,n,a);r=n.stateNode,Jr.current=n;var u=i&&"function"!=typeof t.getDerivedStateFromError?null:r.render();return n.flags|=1,null!==e&&i?(n.child=Xt(n,e.child,null,a),n.child=Xt(n,null,u,a)):el(e,n,u,a),n.memoizedState=r.state,l&&ot(n,t,!0),n.child}function sl(e){var n=e.stateNode;n.pendingContext?at(0,n.pendingContext,n.pendingContext!==n.context):n.context&&at(0,n.context,!1),nr(e,n.containerInfo)}var cl,dl,fl,pl,hl={dehydrated:null,retryLane:0};function gl(e){return{baseLanes:e,cachePool:null}}function ml(e,n,t){var r,l=n.pendingProps,a=ar.current,i=!1;return(r=0!=(128&n.flags))||(r=(null===e||null!==e.memoizedState)&&0!=(2&a)),r?(i=!0,n.flags&=-129):null!==e&&null===e.memoizedState||void 0===l.fallback||!0===l.unstable_avoidThisFallback||(a|=1),Kn(ar,1&a),null===e?(e=l.children,a=l.fallback,i?(e=vl(n,e,a,t),n.child.memoizedState=gl(t),n.memoizedState=hl,e):"number"==typeof l.unstable_expectedLoadTime?(e=vl(n,e,a,t),n.child.memoizedState=gl(t),n.memoizedState=hl,n.lanes=4194304,e):((t=Ja({mode:"visible",children:e},n.mode,t,null)).return=n,n.child=t)):(e.memoizedState,i?(l=yl(e,n,l.children,l.fallback,t),i=n.child,a=e.child.memoizedState,i.memoizedState=null===a?gl(t):{baseLanes:a.baseLanes|t,cachePool:null},i.childLanes=e.childLanes&~t,n.memoizedState=hl,l):(t=bl(e,n,l.children,t),n.memoizedState=null,t))}function vl(e,n,t,r){var l=e.mode,a=e.child;return n={mode:"hidden",children:n},0==(1&l)&&null!==a?(a.childLanes=0,a.pendingProps=n):a=Ja(n,l,0,null),t=Ka(t,l,r,null),a.return=e,t.return=e,a.sibling=t,e.child=a,t}function bl(e,n,t,r){var l=e.child;return e=l.sibling,t=$a(l,{mode:"visible",children:t}),0==(1&n.mode)&&(t.lanes=r),t.return=n,t.sibling=null,null!==e&&(null===(r=n.deletions)?(n.deletions=[e],n.flags|=16):r.push(e)),n.child=t}function yl(e,n,t,r,l){var a=n.mode,i=(e=e.child).sibling,u={mode:"hidden",children:t};return 0==(1&a)&&n.child!==e?((t=n.child).childLanes=0,t.pendingProps=u,n.deletions=null):(t=$a(e,u)).subtreeFlags=1835008&e.subtreeFlags,null!==i?r=$a(i,r):(r=Ka(r,a,l,null)).flags|=2,r.return=n,t.return=n,t.sibling=r,n.child=t,r}function Sl(e,n){e.lanes|=n;var t=e.alternate;null!==t&&(t.lanes|=n),xt(e.return,n)}function kl(e,n,t,r,l){var a=e.memoizedState;null===a?e.memoizedState={isBackwards:n,rendering:null,renderingStartTime:0,last:r,tail:t,tailMode:l}:(a.isBackwards=n,a.rendering=null,a.renderingStartTime=0,a.last=r,a.tail=t,a.tailMode=l)}function wl(e,n,t){var r=n.pendingProps,l=r.revealOrder,a=r.tail;if(el(e,n,r.children,t),0!=(2&(r=ar.current)))r=1&r|2,n.flags|=128;else{if(null!==e&&0!=(128&e.flags))e:for(e=n.child;null!==e;){if(13===e.tag)null!==e.memoizedState&&Sl(e,t);else if(19===e.tag)Sl(e,t);else if(null!==e.child){e.child.return=e,e=e.child;continue}if(e===n)break e;for(;null===e.sibling;){if(null===e.return||e.return===n)break e;e=e.return}e.sibling.return=e.return,e=e.sibling}r&=1}if(Kn(ar,r),0==(1&n.mode))n.memoizedState=null;else switch(l){case"forwards":for(t=n.child,l=null;null!==t;)null!==(e=t.alternate)&&null===ir(e)&&(l=t),t=t.sibling;null===(t=l)?(l=n.child,n.child=null):(l=t.sibling,t.sibling=null),kl(n,!1,l,t,a);break;case"backwards":for(t=null,l=n.child,n.child=null;null!==l;){if(null!==(e=l.alternate)&&null===ir(e)){n.child=l;break}e=l.sibling,l.sibling=t,t=l,l=e}kl(n,!0,t,null,a);break;case"together":kl(n,!1,null,null,void 0);break;default:n.memoizedState=null}return n.child}function _l(e,n,t){if(null!==e&&(n.dependencies=e.dependencies),ia|=n.lanes,0==(t&n.childLanes))return null;if(null!==e&&n.child!==e.child)throw Error("Resuming work not yet implemented.");if(null!==n.child){for(t=$a(e=n.child,e.pendingProps),n.child=t,t.return=n;null!==e.sibling;)e=e.sibling,(t=t.sibling=$a(e,e.pendingProps)).return=n;t.sibling=null}return n.child}function Tl(e,n){switch(e.tailMode){case"hidden":n=e.tail;for(var t=null;null!==n;)null!==n.alternate&&(t=n),n=n.sibling;null===t?e.tail=null:t.sibling=null;break;case"collapsed":t=e.tail;for(var r=null;null!==t;)null!==t.alternate&&(r=t),t=t.sibling;null===r?n||null===e.tail?e.tail=null:e.tail.sibling=null:r.sibling=null}}function xl(e){var n=null!==e.alternate&&e.alternate.child===e.child,t=0,r=0;if(n)for(var l=e.child;null!==l;)t|=l.lanes|l.childLanes,r|=1835008&l.subtreeFlags,r|=1835008&l.flags,l.return=e,l=l.sibling;else for(l=e.child;null!==l;)t|=l.lanes|l.childLanes,r|=l.subtreeFlags,r|=l.flags,l.return=e,l=l.sibling;return e.subtreeFlags|=r,e.childLanes=t,n}function Pl(e,t,r){var l=t.pendingProps;switch(t.tag){case 2:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return xl(t),null;case 1:return rt(t.type)&<(),xl(t),null;case 3:return l=t.stateNode,tr(),Gn(et),Gn(Zn),or(),l.pendingContext&&(l.context=l.pendingContext,l.pendingContext=null),null!==e&&null!==e.child||l.hydrate||(t.flags|=512),dl(e,t),xl(t),null;case 5:lr(t),r=er(Zt.current);var a=t.type;if(null!==e&&null!=t.stateNode)fl(e,t,a,l,r),e.ref!==t.ref&&(t.flags|=256);else{if(!l){if(null===t.stateNode)throw Error("We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue.");return xl(t),null}er(Kt.current),e=Qn(),a=Fn(a);var u=hn(null,ln,l,a.validAttributes);n(i[3]).UIManager.createView(e,a.uiViewClassName,r,u),r=new mn(e,a,t),ke.set(e,t),we.set(e,l),cl(r,t,!1,!1),t.stateNode=r,On(r)&&(t.flags|=4),null!==t.ref&&(t.flags|=256)}return xl(t),null;case 6:if(e&&null!=t.stateNode)pl(e,t,e.memoizedProps,l);else{if("string"!=typeof l&&null===t.stateNode)throw Error("We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue.");if(e=er(Zt.current),!er(Kt.current).isInAParentText)throw Error("Text strings must be rendered within a component.");r=Qn(),n(i[3]).UIManager.createView(r,"RCTRawText",e,{text:l}),ke.set(r,t),t.stateNode=r}return xl(t),null;case 13:return Gn(ar),l=t.memoizedState,0!=(128&t.flags)?(t.lanes=r,t):(l=null!==l,r=!1,null!==e&&(r=null!==e.memoizedState),l&&!r&&0!=(1&t.mode)&&(null===e&&!0!==t.memoizedProps.unstable_avoidThisFallback||0!=(1&ar.current)?0===la&&(la=3):(0!==la&&3!==la||(la=4),null===Zl||0==(268435455&ia)&&0==(268435455&ua)||Ra(Zl,na))),(l||r)&&(t.flags|=4),xl(t),null);case 4:return tr(),dl(e,t),xl(t),null;case 10:return Tt(t.type._context),xl(t),null;case 17:return rt(t.type)&<(),xl(t),null;case 19:if(Gn(ar),null===(a=t.memoizedState))return xl(t),null;if(l=0!=(128&t.flags),null===(u=a.rendering))if(l)Tl(a,!1);else{if(0!==la||null!==e&&0!=(128&e.flags))for(e=t.child;null!==e;){if(null!==(u=ir(e))){for(t.flags|=128,Tl(a,!1),null!==(e=u.updateQueue)&&(t.updateQueue=e,t.flags|=4),t.subtreeFlags=0,e=r,l=t.child;null!==l;)a=e,(r=l).flags&=1835010,null===(u=r.alternate)?(r.childLanes=0,r.lanes=a,r.child=null,r.subtreeFlags=0,r.memoizedProps=null,r.memoizedState=null,r.updateQueue=null,r.dependencies=null,r.stateNode=null):(r.childLanes=u.childLanes,r.lanes=u.lanes,r.child=u.child,r.subtreeFlags=0,r.deletions=null,r.memoizedProps=u.memoizedProps,r.memoizedState=u.memoizedState,r.updateQueue=u.updateQueue,r.type=u.type,a=u.dependencies,r.dependencies=null===a?null:{lanes:a.lanes,firstContext:a.firstContext}),l=l.sibling;return Kn(ar,1&ar.current|2),t.child}e=e.sibling}null!==a.tail&&n(i[4]).unstable_now()>ca&&(t.flags|=128,l=!0,Tl(a,!1),t.lanes=4194304)}else{if(!l)if(null!==(e=ir(u))){if(t.flags|=128,l=!0,null!==(e=e.updateQueue)&&(t.updateQueue=e,t.flags|=4),Tl(a,!0),null===a.tail&&"hidden"===a.tailMode&&!u.alternate)return xl(t),null}else 2*n(i[4]).unstable_now()-a.renderingStartTime>ca&&1073741824!==r&&(t.flags|=128,l=!0,Tl(a,!1),t.lanes=4194304);a.isBackwards?(u.sibling=t.child,t.child=u):(null!==(e=a.last)?e.sibling=u:t.child=u,a.last=u)}return null!==a.tail?(t=a.tail,a.rendering=t,a.tail=t.sibling,a.renderingStartTime=n(i[4]).unstable_now(),t.sibling=null,e=ar.current,Kn(ar,l?1&e|2:1&e),t):(xl(t),null);case 22:case 23:return Ca(),r=null!==t.memoizedState,null!==e&&null!==e.memoizedState!==r&&"unstable-defer-without-hiding"!==l.mode&&(t.flags|=4),r&&0==(1073741824&ta)&&0!=(1&t.mode)||xl(t),null}throw Error("Unknown unit of work tag ("+t.tag+"). This error is likely caused by a bug in React. Please file an issue.")}function Rl(e){switch(e.tag){case 1:rt(e.type)&<();var n=e.flags;return 16384&n?(e.flags=-16385&n|128,e):null;case 3:if(tr(),Gn(et),Gn(Zn),or(),0!=(128&(n=e.flags)))throw Error("The root failed to unmount after an error. This is likely a bug in React. Please file an issue.");return e.flags=-16385&n|128,e;case 5:return lr(e),null;case 13:return Gn(ar),16384&(n=e.flags)?(e.flags=-16385&n|128,e):null;case 19:return Gn(ar),null;case 4:return tr(),null;case 10:return Tt(e.type._context),null;case 22:case 23:return Ca(),null;case 24:default:return null}}cl=function(e,n){for(var t=n.child;null!==t;){if(5===t.tag||6===t.tag)e._children.push(t.stateNode);else if(4!==t.tag&&null!==t.child){t.child.return=t,t=t.child;continue}if(t===n)break;for(;null===t.sibling;){if(null===t.return||t.return===n)return;t=t.return}t.sibling.return=t.return,t=t.sibling}},dl=function(){},fl=function(e,n,t,r){e.memoizedProps!==r&&(er(Kt.current),n.updateQueue=Dn)&&(n.flags|=4)},pl=function(e,n,t,r){t!==r&&(n.flags|=4)};var El="function"==typeof WeakSet?WeakSet:Set,Cl=null;function Nl(e,n){var t=e.ref;if(null!==t)if("function"==typeof t)try{t(null)}catch(t){ja(e,n,t)}else t.current=null}var zl=!1;function Il(e,n){for(Cl=n;null!==Cl;)if(n=(e=Cl).child,0!=(516&e.subtreeFlags)&&null!==n)n.return=e,Cl=n;else for(;null!==Cl;){e=Cl;try{var t=e.alternate;if(0!=(512&e.flags))switch(e.tag){case 0:case 11:case 15:break;case 1:if(null!==t){var r=t.memoizedProps,l=t.memoizedState,a=e.stateNode,i=a.getSnapshotBeforeUpdate(e.elementType===e.type?r:bt(e.type,r),l);a.__reactInternalSnapshotBeforeUpdate=i}break;case 3:break;case 5:case 6:case 4:case 17:break;default:throw Error("This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue.")}}catch(n){ja(e,e.return,n)}if(null!==(n=e.sibling)){n.return=e.return,Cl=n;break}Cl=e.return}return t=zl,zl=!1,t}function Ll(e,n,t){var r=n.updateQueue;if(null!==(r=null!==r?r.lastEffect:null)){var l=r=r.next;do{if((l.tag&e)===e){var a=l.destroy;if(l.destroy=void 0,void 0!==a){var i=n,u=t;try{a()}catch(e){ja(i,u,e)}}}l=l.next}while(l!==r)}}function Ul(e,n){if(null!==(n=null!==(n=n.updateQueue)?n.lastEffect:null)){var t=n=n.next;do{if((t.tag&e)===e){var r=t.create;t.destroy=r()}t=t.next}while(t!==n)}}function Ml(e,t){for(var r=null,l=e;;){if(5===l.tag){if(null===r){r=l;var a=l.stateNode;if(t){var u=a.viewConfig,o=hn(null,ln,{style:{display:"none"}},u.validAttributes);n(i[3]).UIManager.updateView(a._nativeTag,u.uiViewClassName,o)}else{a=l.stateNode,o=l.memoizedProps,u=a.viewConfig,o=hn(null,n(i[2])({},o,{style:[o.style,{display:"none"}]}),o,u.validAttributes),n(i[3]).UIManager.updateView(a._nativeTag,u.uiViewClassName,o)}}}else if(6===l.tag){if(null===r)throw Error("Not yet implemented.")}else if((22!==l.tag&&23!==l.tag||null===l.memoizedState||l===e)&&null!==l.child){l.child.return=l,l=l.child;continue}if(l===e)break;for(;null===l.sibling;){if(null===l.return||l.return===e)return;r===l&&(r=null),l=l.return}r===l&&(r=null),l.sibling.return=l.return,l=l.sibling}}function Fl(e,n,t){if(bn&&"function"==typeof bn.onCommitFiberUnmount)try{bn.onCommitFiberUnmount(vn,n)}catch(e){}switch(n.tag){case 0:case 11:case 14:case 15:if(null!==(e=n.updateQueue)&&null!==(e=e.lastEffect)){var r=e=e.next;do{var l=r,a=l.destroy;if(l=l.tag,void 0!==a&&0!=(2&l)){l=n;var i=t;try{a()}catch(e){ja(l,i,e)}}r=r.next}while(r!==e)}break;case 1:if(Nl(n,t),"function"==typeof(e=n.stateNode).componentWillUnmount)try{e.props=n.memoizedProps,e.state=n.memoizedState,e.componentWillUnmount()}catch(e){ja(n,t,e)}break;case 5:Nl(n,t);break;case 4:jl(e,n,t)}}function Dl(e){var n=e.alternate;null!==n&&(e.alternate=null,Dl(n)),e.child=null,e.deletions=null,e.sibling=null,e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function Al(e){return 5===e.tag||3===e.tag||4===e.tag}function Ql(e){e:{for(var n=e.return;null!==n;){if(Al(n))break e;n=n.return}throw Error("Expected to find a host parent. This error is likely caused by a bug in React. Please file an issue.")}var t=n;switch(n=t.stateNode,t.tag){case 5:var r=!1;break;case 3:case 4:n=n.containerInfo,r=!0;break;default:throw Error("Invalid host parent fiber. This error is likely caused by a bug in React. Please file an issue.")}32&t.flags&&(t.flags&=-33);e:n:for(t=e;;){for(;null===t.sibling;){if(null===t.return||Al(t.return)){t=null;break e}t=t.return}for(t.sibling.return=t.return,t=t.sibling;5!==t.tag&&6!==t.tag&&18!==t.tag;){if(2&t.flags)continue n;if(null===t.child||4===t.tag)continue n;t.child.return=t,t=t.child}if(!(2&t.flags)){t=t.stateNode;break e}}r?Hl(e,t,n):Ol(e,t,n)}function Hl(e,t,r){var l=e.tag;if(5===l||6===l)if(e=e.stateNode,t){if("number"==typeof r)throw Error("Container does not support insertBefore operation")}else n(i[3]).UIManager.setChildren(r,["number"==typeof e?e:e._nativeTag]);else if(4!==l&&null!==(e=e.child))for(Hl(e,t,r),e=e.sibling;null!==e;)Hl(e,t,r),e=e.sibling}function Ol(e,t,r){var l=e.tag;if(5===l||6===l)if(e=e.stateNode,t){var a=(l=r._children).indexOf(e);0<=a?(l.splice(a,1),t=l.indexOf(t),l.splice(t,0,e),n(i[3]).UIManager.manageChildren(r._nativeTag,[a],[t],[],[],[])):(t=l.indexOf(t),l.splice(t,0,e),n(i[3]).UIManager.manageChildren(r._nativeTag,[],[],["number"==typeof e?e:e._nativeTag],[t],[]))}else t="number"==typeof e?e:e._nativeTag,0<=(a=(l=r._children).indexOf(e))?(l.splice(a,1),l.push(e),n(i[3]).UIManager.manageChildren(r._nativeTag,[a],[l.length-1],[],[],[])):(l.push(e),n(i[3]).UIManager.manageChildren(r._nativeTag,[],[],[t],[l.length-1],[]));else if(4!==l&&null!==(e=e.child))for(Ol(e,t,r),e=e.sibling;null!==e;)Ol(e,t,r),e=e.sibling}function jl(e,t,r){for(var l,a,u=t,o=!1;;){if(!o){o=u.return;e:for(;;){if(null===o)throw Error("Expected to find a host parent. This error is likely caused by a bug in React. Please file an issue.");switch(l=o.stateNode,o.tag){case 5:a=!1;break e;case 3:case 4:l=l.containerInfo,a=!0;break e}o=o.return}o=!0}if(5===u.tag||6===u.tag){e:for(var s=e,c=u,d=r,f=c;;)if(Fl(s,f,d),null!==f.child&&4!==f.tag)f.child.return=f,f=f.child;else{if(f===c)break e;for(;null===f.sibling;){if(null===f.return||f.return===c)break e;f=f.return}f.sibling.return=f.return,f=f.sibling}a?(s=l,Hn(u.stateNode),n(i[3]).UIManager.manageChildren(s,[],[],[],[],[0])):(s=l,Hn(d=u.stateNode),d=(c=s._children).indexOf(d),c.splice(d,1),n(i[3]).UIManager.manageChildren(s._nativeTag,[],[],[],[],[d]))}else if(4===u.tag){if(null!==u.child){l=u.stateNode.containerInfo,a=!0,u.child.return=u,u=u.child;continue}}else if(Fl(e,u,r),null!==u.child){u.child.return=u,u=u.child;continue}if(u===t)break;for(;null===u.sibling;){if(null===u.return||u.return===t)return;4===(u=u.return).tag&&(o=!1)}u.sibling.return=u.return,u=u.sibling}}function Bl(e,t){switch(t.tag){case 0:case 11:case 14:case 15:return void Ll(3,t,t.return);case 1:return;case 5:var r=t.stateNode;if(null!=r){var l=t.memoizedProps;e=null!==e?e.memoizedProps:l;var a=t.updateQueue;t.updateQueue=null,null!==a&&(t=r.viewConfig,we.set(r._nativeTag,l),null!=(l=hn(null,e,l,t.validAttributes))&&n(i[3]).UIManager.updateView(r._nativeTag,t.uiViewClassName,l))}return;case 6:if(null===t.stateNode)throw Error("This should have a text node initialized. This error is likely caused by a bug in React. Please file an issue.");return void n(i[3]).UIManager.updateView(t.stateNode,"RCTRawText",{text:t.memoizedProps});case 3:case 12:return;case 13:return null!==t.memoizedState&&(sa=n(i[4]).unstable_now(),Ml(t.child,!0)),void Vl(t);case 19:return void Vl(t);case 17:return;case 22:case 23:return void Ml(t,null!==t.memoizedState)}throw Error("This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue.")}function Vl(e){var n=e.updateQueue;if(null!==n){e.updateQueue=null;var t=e.stateNode;null===t&&(t=e.stateNode=new El),n.forEach(function(n){var r=Va.bind(null,e,n);t.has(n)||(t.add(n),n.then(r,r))})}}function Wl(e,n){for(Cl=n;null!==Cl;){var t=(n=Cl).deletions;if(null!==t)for(var r=0;ra&&(a=o),l&=~u}if(l=a,10<(l=(120>(l=n(i[4]).unstable_now()-l)?120:480>l?480:1080>l?1080:1920>l?1920:3e3>l?3e3:4320>l?4320:1960*Xl(l/1960))-l)){e.timeoutHandle=jn(Aa.bind(null,e),l);break}Aa(e);break;case 5:Aa(e);break;default:throw Error("Unknown root exit status.")}}return xa(e,n(i[4]).unstable_now()),e.callbackNode===r?Pa.bind(null,e):null}function Ra(e,n){for(n&=~oa,n&=~ua,e.suspendedLanes|=n,e.pingedLanes&=~n,e=e.expirationTimes;0 component higher in the tree to provide a loading indicator or placeholder to display.")}5!==la&&(la=2),o=qr(o,u),p=i;do{switch(p.tag){case 3:a=o,p.flags|=16384,n&=-n,p.lanes|=n,Mt(p,Gr(p,a,n));break e;case 1:a=o;var w=p.type,_=p.stateNode;if(0==(128&p.flags)&&("function"==typeof w.getDerivedStateFromError||null!==_&&"function"==typeof _.componentDidCatch&&(null===pa||!pa.has(_)))){p.flags|=16384,n&=-n,p.lanes|=n,Mt(p,Kr(p,a,n));break e}}p=p.return}while(null!==p)}Da(t)}catch(e){n=e,ea===t&&null!==t&&(ea=t=t.return);continue}break}}function Ia(){var e=$l.current;return $l.current=Br,null===e?Br:e}function La(e,n){var t=Jl;Jl|=8;var r=Ia();for(Zl===e&&na===n||Na(e,n);;)try{Ua();break}catch(n){za(e,n)}if(_t(),Jl=t,$l.current=r,null!==ea)throw Error("Cannot commit an incomplete root. This error is likely caused by a bug in React. Please file an issue.");return Zl=null,na=0,la}function Ua(){for(;null!==ea;)Fa(ea)}function Ma(){for(;null!==ea&&!n(i[4]).unstable_shouldYield();)Fa(ea)}function Fa(e){var n=ql(e.alternate,e,ta);e.memoizedProps=e.pendingProps,null===n?Da(e):ea=n,Gl.current=null}function Da(e){var n=e;do{var t=n.alternate;if(e=n.return,0==(8192&n.flags)){if(null!==(t=Pl(t,n,ta)))return void(ea=t)}else{if(null!==(t=Rl(n)))return t.flags&=8191,void(ea=t);null!==e&&(e.flags|=8192,e.subtreeFlags=0,e.deletions=null)}if(null!==(n=n.sibling))return void(ea=n);ea=n=e}while(null!==n);0===la&&(la=5)}function Aa(e){var n=Ln,t=Kl.transition;try{Kl.transition=0,Ln=1,Qa(e,n)}finally{Kl.transition=t,Ln=n}return null}function Qa(e,t){do{Ha()}while(null!==ga);if(0!=(24&Jl))throw Error("Should not already be working.");var r=e.finishedWork,l=e.finishedLanes;if(null===r)return null;if(e.finishedWork=null,e.finishedLanes=0,r===e.current)throw Error("Cannot commit the same tree as before. This error is likely caused by a bug in React. Please file an issue.");e.callbackNode=null,e.callbackPriority=0;var a=r.lanes|r.childLanes;if(En(e,a),e===Zl&&(ea=Zl=null,na=0),0==(1040&r.subtreeFlags)&&0==(1040&r.flags)||ha||(ha=!0,n(i[4]).unstable_scheduleCallback(n(i[4]).unstable_NormalPriority,function(){return Ha(),null})),a=0!=(8054&r.flags),0!=(8054&r.subtreeFlags)||a){a=Kl.transition,Kl.transition=0;var u=Ln;Ln=1;var o=Jl;Jl|=16,Gl.current=null,Il(e,r),Wl(e,r),e.current=r,Yl(r),n(i[4]).unstable_requestPaint(),Jl=o,Ln=u,Kl.transition=a}else e.current=r;if(ha&&(ha=!1,ga=e,ma=l),0===(a=e.pendingLanes)&&(pa=null),0!=(1&a)?e===ba?va++:(va=0,ba=e):va=0,yn(r.stateNode),xa(e,n(i[4]).unstable_now()),da)throw da=!1,e=fa,fa=null,e;return 0!=(4&Jl)?null:(0!=(1&ma)&&0!==e.tag&&Ha(),ft(),null)}function Ha(){if(null!==ga){var e=Un(ma),n=Kl.transition,t=Ln;try{if(Kl.transition=0,Ln=16>e?16:e,null===ga)var r=!1;else{if(e=ga,ga=null,ma=0,0!=(24&Jl))throw Error("Cannot flush passive effects while already rendering.");var l=Jl;for(Jl|=16,Cl=e.current;null!==Cl;){var a=Cl,i=a.child;if(0!=(16&Cl.flags)){var u=a.deletions;if(null!==u){for(var o=0;on(i[4]).unstable_now()-sa?Na(e,0):oa|=r),xa(e,t)}function Va(e,n){var t=e.stateNode;null!==t&&t.delete(n),0===(n=0)&&(0==(1&e.mode)?n=1:(n=kn,0==(130023424&(kn<<=1))&&(kn=4194304))),t=ka(),null!==(e=Ta(e,n))&&(Rn(e,n,t),xa(e,t))}function Wa(e,n,t,r){this.tag=e,this.key=t,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=n,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function Ya(e,n,t,r){return new Wa(e,n,t,r)}function qa(e){return!(!(e=e.prototype)||!e.isReactComponent)}function Xa(e){if("function"==typeof e)return qa(e)?1:0;if(void 0!==e&&null!==e){if((e=e.$$typeof)===Qe)return 11;if(e===je)return 14}return 2}function $a(e,n){var t=e.alternate;return null===t?((t=Ya(e.tag,n,e.key,e.mode)).elementType=e.elementType,t.type=e.type,t.stateNode=e.stateNode,t.alternate=e,e.alternate=t):(t.pendingProps=n,t.type=e.type,t.flags=0,t.subtreeFlags=0,t.deletions=null),t.flags=1835008&e.flags,t.childLanes=e.childLanes,t.lanes=e.lanes,t.child=e.child,t.memoizedProps=e.memoizedProps,t.memoizedState=e.memoizedState,t.updateQueue=e.updateQueue,n=e.dependencies,t.dependencies=null===n?null:{lanes:n.lanes,firstContext:n.firstContext},t.sibling=e.sibling,t.index=e.index,t.ref=e.ref,t}function Ga(e,n,t,r,l,a){var i=2;if(r=e,"function"==typeof e)qa(e)&&(i=1);else if("string"==typeof e)i=5;else e:switch(e){case Ue:return Ka(t.children,l,a,n);case Ve:i=8,l|=4;break;case Me:i=8,l|=8;break;case Fe:return(e=Ya(12,t,n,2|l)).elementType=Fe,e.lanes=a,e;case He:return(e=Ya(13,t,n,l)).elementType=He,e.lanes=a,e;case Oe:return(e=Ya(19,t,n,l)).elementType=Oe,e.lanes=a,e;case We:return Ja(t,l,a,n);case Ye:return(e=Ya(23,t,n,l)).elementType=Ye,e.lanes=a,e;default:if("object"==typeof e&&null!==e)switch(e.$$typeof){case De:i=10;break e;case Ae:i=9;break e;case Qe:i=11;break e;case je:i=14;break e;case Be:i=16,r=null;break e}throw Error("Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: "+(null==e?e:typeof e)+".")}return(n=Ya(i,t,n,l)).elementType=e,n.type=r,n.lanes=a,n}function Ka(e,n,t,r){return(e=Ya(7,e,r,n)).lanes=t,e}function Ja(e,n,t,r){return(e=Ya(22,e,r,n)).elementType=We,e.lanes=t,e}function Za(e,n,t){return(e=Ya(6,e,null,n)).lanes=t,e}function ei(e,n,t){return(n=Ya(4,null!==e.children?e.children:[],e.key,n)).lanes=t,n.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},n}function ni(e,n,t){this.tag=n,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.pendingContext=this.context=null,this.hydrate=t,this.callbackNode=null,this.callbackPriority=0,this.eventTimes=Pn(0),this.expirationTimes=Pn(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=Pn(0)}function ti(e,n,t){var r=3=t.length?{done:!0}:{done:!1,value:t[i++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function n(t,n){if(t){if("string"==typeof t)return o(t,n);var u=Object.prototype.toString.call(t).slice(8,-1);return"Object"===u&&t.constructor&&(u=t.constructor.name),"Map"===u||"Set"===u?Array.from(t):"Arguments"===u||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(u)?o(t,n):void 0}}function o(t,n){(null==n||n>t.length)&&(n=t.length);for(var o=0,u=new Array(n);o|\/|[a-z]:\\|\\\\).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i,u=/\((\S*)(?::(\d+))(?::(\d+))\)/;function t(t){var o=l.exec(t);if(!o)return null;var c=o[2]&&0===o[2].indexOf('native'),s=o[2]&&0===o[2].indexOf('eval'),v=u.exec(o[2]);return s&&null!=v&&(o[2]=v[1],o[3]=v[2],o[4]=v[3]),{file:c?null:o[2],methodName:o[1]||n,arguments:c?[o[2]]:[],lineNumber:o[3]?+o[3]:null,column:o[4]?+o[4]:null}}var o=/^\s*at (?:((?:\[object object\])?.+) )?\(?((?:file|ms-appx|https?|webpack|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i;function c(l){var u=o.exec(l);return u?{file:u[2],methodName:u[1]||n,arguments:[],lineNumber:+u[3],column:u[4]?+u[4]:null}:null}var s=/^\s*(.*?)(?:\((.*?)\))?(?:^|@)((?:file|https?|blob|chrome|webpack|resource|\[native).*?|[^@]*bundle)(?::(\d+))?(?::(\d+))?\s*$/i,v=/(\S+) line (\d+)(?: > eval line \d+)* > eval/i;function f(l){var u=s.exec(l);if(!u)return null;var t=u[3]&&u[3].indexOf(' > eval')>-1,o=v.exec(u[3]);return t&&null!=o&&(u[3]=o[1],u[4]=o[2],u[5]=null),{file:u[3],methodName:u[1]||n,arguments:u[2]?u[2].split(','):[],lineNumber:u[4]?+u[4]:null,column:u[5]?+u[5]:null}}var b=/^\s*(?:([^@]*)(?:\((.*?)\))?@)?(\S.*?):(\d+)(?::(\d+))?\s*$/i;function p(l){var u=b.exec(l);return u?{file:u[3],methodName:u[1]||n,arguments:[],lineNumber:+u[4],column:u[5]?+u[5]:null}:null}var x=/^\s*at (?:((?:\[object object\])?[^\\/]+(?: \[as \S+\])?) )?\(?(.*?):(\d+)(?::(\d+))?\)?\s*$/i;function h(l){var u=x.exec(l);return u?{file:u[2],methodName:u[1]||n,arguments:[],lineNumber:+u[3],column:u[4]?+u[4]:null}:null}e.parse=function(n){return n.split('\n').reduce(function(n,l){var u=t(l)||c(l)||f(l)||h(l)||p(l);return u&&n.push(u),n},[])}},64,[]); -__d(function(g,r,_i,a,m,e,d){'use strict';var t=/^ {4}at (.+?)(?: \((native)\)?| \((address at )?(.*?):(\d+):(\d+)\))$/,n=/^ {4}... skipping (\d+) frames$/;function s(s){var i=s.match(t);if(i)return{type:'FRAME',functionName:i[1],location:'native'===i[2]?{type:'NATIVE'}:'address at '===i[3]?{type:'BYTECODE',sourceUrl:i[4],line1Based:Number.parseInt(i[5],10),virtualOffset0Based:Number.parseInt(i[6],10)}:{type:'SOURCE',sourceUrl:i[4],line1Based:Number.parseInt(i[5],10),column1Based:Number.parseInt(i[6],10)}};var u=s.match(n);return u?{type:'SKIPPED',count:Number.parseInt(u[1],10)}:void 0}m.exports=function(t){for(var n=t.split(/\n/),i=[],u=-1,p=0;p-1}m.exports={isNativeFunction:t,hasNativeConstructor:function(n,o){var c=Object.getPrototypeOf(n).constructor;return c.name===o&&t(c)}}},74,[]); -__d(function(g,r,i,a,m,e,d){m.exports=r(d[0])},75,[76]); -__d(function(g,r,_i,a,m,e,d){var t=(function(t){"use strict";var n,o=Object.prototype,i=o.hasOwnProperty,c="function"==typeof Symbol?Symbol:{},u=c.iterator||"@@iterator",h=c.asyncIterator||"@@asyncIterator",f=c.toStringTag||"@@toStringTag";function l(t,n,o){return Object.defineProperty(t,n,{value:o,enumerable:!0,configurable:!0,writable:!0}),t[n]}try{l({},"")}catch(t){l=function(t,n,o){return t[n]=o}}function s(t,n,o,i){var c=n&&n.prototype instanceof b?n:b,u=Object.create(c.prototype),h=new R(i||[]);return u._invoke=F(t,o,h),u}function p(t,n,o){try{return{type:"normal",arg:t.call(n,o)}}catch(t){return{type:"throw",arg:t}}}t.wrap=s;var y="suspendedStart",v="suspendedYield",w="executing",L="completed",x={};function b(){}function E(){}function _(){}var j={};l(j,u,function(){return this});var O=Object.getPrototypeOf,k=O&&O(O(A([])));k&&k!==o&&i.call(k,u)&&(j=k);var G=_.prototype=b.prototype=Object.create(j);function N(t){["next","throw","return"].forEach(function(n){l(t,n,function(t){return this._invoke(n,t)})})}function T(t,n){function o(c,u,h,f){var l=p(t[c],t,u);if("throw"!==l.type){var s=l.arg,y=s.value;return y&&"object"==typeof y&&i.call(y,"__await")?n.resolve(y.__await).then(function(t){o("next",t,h,f)},function(t){o("throw",t,h,f)}):n.resolve(y).then(function(t){s.value=t,h(s)},function(t){return o("throw",t,h,f)})}f(l.arg)}var c;this._invoke=function(t,i){function u(){return new n(function(n,c){o(t,i,n,c)})}return c=c?c.then(u,u):u()}}function F(t,n,o){var i=y;return function(c,u){if(i===w)throw new Error("Generator is already running");if(i===L){if("throw"===c)throw u;return Y()}for(o.method=c,o.arg=u;;){var h=o.delegate;if(h){var f=P(h,o);if(f){if(f===x)continue;return f}}if("next"===o.method)o.sent=o._sent=o.arg;else if("throw"===o.method){if(i===y)throw i=L,o.arg;o.dispatchException(o.arg)}else"return"===o.method&&o.abrupt("return",o.arg);i=w;var l=p(t,n,o);if("normal"===l.type){if(i=o.done?L:v,l.arg===x)continue;return{value:l.arg,done:o.done}}"throw"===l.type&&(i=L,o.method="throw",o.arg=l.arg)}}}function P(t,o){var i=t.iterator[o.method];if(i===n){if(o.delegate=null,"throw"===o.method){if(t.iterator.return&&(o.method="return",o.arg=n,P(t,o),"throw"===o.method))return x;o.method="throw",o.arg=new TypeError("The iterator does not provide a 'throw' method")}return x}var c=p(i,t.iterator,o.arg);if("throw"===c.type)return o.method="throw",o.arg=c.arg,o.delegate=null,x;var u=c.arg;return u?u.done?(o[t.resultName]=u.value,o.next=t.nextLoc,"return"!==o.method&&(o.method="next",o.arg=n),o.delegate=null,x):u:(o.method="throw",o.arg=new TypeError("iterator result is not an object"),o.delegate=null,x)}function S(t){var n={tryLoc:t[0]};1 in t&&(n.catchLoc=t[1]),2 in t&&(n.finallyLoc=t[2],n.afterLoc=t[3]),this.tryEntries.push(n)}function I(t){var n=t.completion||{};n.type="normal",delete n.arg,t.completion=n}function R(t){this.tryEntries=[{tryLoc:"root"}],t.forEach(S,this),this.reset(!0)}function A(t){if(t){var o=t[u];if(o)return o.call(t);if("function"==typeof t.next)return t;if(!isNaN(t.length)){var c=-1,h=function o(){for(;++c=0;--u){var h=this.tryEntries[u],f=h.completion;if("root"===h.tryLoc)return c("end");if(h.tryLoc<=this.prev){var l=i.call(h,"catchLoc"),s=i.call(h,"finallyLoc");if(l&&s){if(this.prev=0;--o){var c=this.tryEntries[o];if(c.tryLoc<=this.prev&&i.call(c,"finallyLoc")&&this.prev=0;--n){var o=this.tryEntries[n];if(o.finallyLoc===t)return this.complete(o.completion,o.afterLoc),I(o),x}},catch:function(t){for(var n=this.tryEntries.length-1;n>=0;--n){var o=this.tryEntries[n];if(o.tryLoc===t){var i=o.completion;if("throw"===i.type){var c=i.arg;I(o)}return c}}throw new Error("illegal catch attempt")},delegateYield:function(t,o,i){return this.delegate={iterator:A(t),resultName:o,nextLoc:i},"next"===this.method&&(this.arg=n),x}},t})("object"==typeof m?m.exports:{});try{regeneratorRuntime=t}catch(n){"object"==typeof globalThis?globalThis.regeneratorRuntime=t:Function("r","regeneratorRuntime = r")(t)}},76,[]); -__d(function(g,r,i,a,m,e,d){'use strict';var l,n,t=!0===(null==(l=g.HermesInternal)?void 0:null==l.hasPromise?void 0:l.hasPromise())&&!0===(null==(n=g.HermesInternal)?void 0:null==n.useEngineQueue?void 0:n.useEngineQueue()),u=r(d[0]).isNativeFunction(Promise)||t;if(!g.RN$Bridgeless){var o=function(l){r(d[1]).polyfillGlobal(l,function(){return r(d[2])[l]})};o('setTimeout'),o('clearTimeout'),o('setInterval'),o('clearInterval'),o('requestAnimationFrame'),o('cancelAnimationFrame'),o('requestIdleCallback'),o('cancelIdleCallback')}u?(r(d[1]).polyfillGlobal('setImmediate',function(){return r(d[3]).setImmediate}),r(d[1]).polyfillGlobal('clearImmediate',function(){return r(d[3]).clearImmediate})):g.RN$Bridgeless||(r(d[1]).polyfillGlobal('setImmediate',function(){return r(d[2]).queueReactNativeMicrotask}),r(d[1]).polyfillGlobal('clearImmediate',function(){return r(d[2]).clearReactNativeMicrotask})),t?r(d[1]).polyfillGlobal('queueMicrotask',function(){var l;return null==(l=g.HermesInternal)?void 0:l.enqueueJob}):r(d[1]).polyfillGlobal('queueMicrotask',function(){return r(d[4]).default})},77,[74,67,78,80,81]); -__d(function(g,r,_i,a,m,_e,d){var e=r(d[0])(r(d[1])),t=16.666666666666668,n=[],i=[],l=[],o=[],c=[],u={},f=1,s=null,v=!1;function h(){var e=l.indexOf(null);return-1===e&&(e=l.length),e}function T(e,t){var o=f++,c=h();return l[c]=o,n[c]=e,i[c]=t,o}function k(e,o,c){e>f&&console.warn('Tried to call timer with ID %s but no such timer exists.',e);var u=l.indexOf(e);if(-1!==u){var v=i[u],h=n[u];if(h&&v){'setInterval'!==v&&p(u);try{'setTimeout'===v||'setInterval'===v||'queueReactNativeMicrotask'===v?h():'requestAnimationFrame'===v?h(g.performance.now()):'requestIdleCallback'===v?h({timeRemaining:function(){return Math.max(0,t-(g.performance.now()-o))},didTimeout:!!c}):console.error('Tried to call a callback with invalid type: '+v)}catch(e){s?s.push(e):s=[e]}}else console.error('No callback found for timerID '+e)}}function w(){if(0===o.length)return!1;var e=o;o=[];for(var t=0;t0}function p(e){l[e]=null,n[e]=null,i[e]=null}function N(e){if(null!=e){var t=l.indexOf(e);if(-1!==t){var n=i[t];p(t),'queueReactNativeMicrotask'!==n&&'requestIdleCallback'!==n&&M(e)}}}var b,I={setTimeout:function(e,t){for(var n=arguments.length,i=new Array(n>2?n-2:0),l=2;l2?n-2:0),l=2;l1?t-1:0),i=1;i-1&&(c.splice(e,1),k(i,g.performance.now(),!0)),delete u[i],0===c.length&&R(!1)},n);u[i]=l}return i},cancelIdleCallback:function(e){N(e);var t=c.indexOf(e);-1!==t&&c.splice(t,1);var n=u[e];n&&(I.clearTimeout(n),delete u[e]),0===c.length&&R(!1)},clearTimeout:function(e){N(e)},clearInterval:function(e){N(e)},clearReactNativeMicrotask:function(e){N(e);var t=o.indexOf(e);-1!==t&&o.splice(t,1)},cancelAnimationFrame:function(e){N(e)},callTimers:function(e){r(d[2])(0!==e.length,'Cannot call `callTimers` with an empty list of IDs.'),s=null;for(var t=0;t1)for(var i=1;i0){var n=c;c=[];for(var i=0;i1?u-1:0),c=1;c=0,loaded:t,total:s})}},{key:"__didCompleteResponse",value:function(e,t,s){e===this._requestId&&(t&&(''!==this._responseType&&'text'!==this._responseType||(this._response=t),this._hasError=!0,s&&(this._timedOut=!0)),this._clearSubscriptions(),this._requestId=null,this.setReadyState(this.DONE),t?E._interceptor&&E._interceptor.loadingFailed(e,t):E._interceptor&&E._interceptor.loadingFinished(e,this._response.length))}},{key:"_clearSubscriptions",value:function(){(this._subscriptions||[]).forEach(function(e){e&&e.remove()}),this._subscriptions=[]}},{key:"getAllResponseHeaders",value:function(){if(!this.responseHeaders)return null;var e=this.responseHeaders||{};return Object.keys(e).map(function(t){return t+': '+e[t]}).join('\r\n')}},{key:"getResponseHeader",value:function(e){var t=this._lowerCaseResponseHeaders[e.toLowerCase()];return void 0!==t?t:null}},{key:"setRequestHeader",value:function(e,t){if(this.readyState!==this.OPENED)throw new Error('Request has not been opened');this._headers[e.toLowerCase()]=String(t)}},{key:"setTrackingName",value:function(e){return this._trackingName=e,this}},{key:"setPerformanceLogger",value:function(e){return this._performanceLogger=e,this}},{key:"open",value:function(e,t,s){if(this.readyState!==this.UNSENT)throw new Error('Cannot open, already sending');if(void 0!==s&&!s)throw new Error('Synchronous http requests are not supported');if(!t)throw new Error('Cannot load an empty url');this._method=e.toUpperCase(),this._url=t,this._aborted=!1,this.setReadyState(this.OPENED)}},{key:"send",value:function(t){var s=this;if(this.readyState!==this.OPENED)throw new Error('Request has not been opened');if(this._sent)throw new Error('Request has already been sent');this._sent=!0;var n=this._incrementalEvents||!!this.onreadystatechange||!!this.onprogress;this._subscriptions.push(r(d[13]).addListener('didSendNetworkData',function(t){return s.__didUploadProgress.apply(s,(0,e.default)(t))})),this._subscriptions.push(r(d[13]).addListener('didReceiveNetworkResponse',function(t){return s.__didReceiveResponse.apply(s,(0,e.default)(t))})),this._subscriptions.push(r(d[13]).addListener('didReceiveNetworkData',function(t){return s.__didReceiveData.apply(s,(0,e.default)(t))})),this._subscriptions.push(r(d[13]).addListener('didReceiveNetworkIncrementalData',function(t){return s.__didReceiveIncrementalData.apply(s,(0,e.default)(t))})),this._subscriptions.push(r(d[13]).addListener('didReceiveNetworkDataProgress',function(t){return s.__didReceiveDataProgress.apply(s,(0,e.default)(t))})),this._subscriptions.push(r(d[13]).addListener('didCompleteNetworkResponse',function(t){return s.__didCompleteResponse.apply(s,(0,e.default)(t))}));var o='text';'arraybuffer'===this._responseType&&(o='base64'),'blob'===this._responseType&&(o='blob');var h;h='unknown'!==s._trackingName?s._trackingName:s._url,s._perfKey='network_XMLHttpRequest_'+String(h),s._performanceLogger.startTimespan(s._perfKey),r(d[11])(s._method,'XMLHttpRequest method needs to be defined (%s).',h),r(d[11])(s._url,'XMLHttpRequest URL needs to be defined (%s).',h),r(d[13]).sendRequest(s._method,s._trackingName,s._url,s._headers,t,o,n,s.timeout,s.__didCreateRequest.bind(s),s.withCredentials)}},{key:"abort",value:function(){this._aborted=!0,this._requestId&&r(d[13]).abortRequest(this._requestId),this.readyState===this.UNSENT||this.readyState===this.OPENED&&!this._sent||this.readyState===this.DONE||(this._reset(),this.setReadyState(this.DONE)),this._reset()}},{key:"setResponseHeaders",value:function(e){this.responseHeaders=e||null;var t=e||{};this._lowerCaseResponseHeaders=Object.keys(t).reduce(function(e,s){return e[s.toLowerCase()]=t[s],e},{})}},{key:"setReadyState",value:function(e){this.readyState=e,this.dispatchEvent({type:'readystatechange'}),e===this.DONE&&(this._aborted?this.dispatchEvent({type:'abort'}):this._hasError?this._timedOut?this.dispatchEvent({type:'timeout'}):this.dispatchEvent({type:'error'}):this.dispatchEvent({type:'load'}),this.dispatchEvent({type:'loadend'}))}},{key:"addEventListener",value:function(e,s){'readystatechange'!==e&&'progress'!==e||(this._incrementalEvents=!0),(0,t.default)((0,u.default)(E.prototype),"addEventListener",this).call(this,e,s)}}],[{key:"setInterceptor",value:function(e){E._interceptor=e}}]),E})(r(d[9]).apply(void 0,(0,e.default)(b)));N.UNSENT=l,N.OPENED=_,N.HEADERS_RECEIVED=f,N.LOADING=y,N.DONE=v,N._interceptor=null,m.exports=N},83,[3,35,84,8,7,10,12,15,86,90,91,18,93,94]); -__d(function(g,r,i,a,m,e,d){function t(){return"undefined"!=typeof Reflect&&Reflect.get?(m.exports=t=Reflect.get,m.exports.__esModule=!0,m.exports.default=m.exports):(m.exports=t=function(t,o,p){var s=r(d[0])(t,o);if(s){var l=Object.getOwnPropertyDescriptor(s,o);return l.get?l.get.call(arguments.length<3?t:p):l.value}},m.exports.__esModule=!0,m.exports.default=m.exports),t.apply(this,arguments)}m.exports=t,m.exports.__esModule=!0,m.exports.default=m.exports},84,[85]); -__d(function(g,r,i,a,m,e,d){m.exports=function(t,o){for(;!Object.prototype.hasOwnProperty.call(t,o)&&null!==(t=r(d[0])(t)););return t},m.exports.__esModule=!0,m.exports.default=m.exports},85,[15]); -__d(function(g,_r,i,a,m,e,d){var t=_r(d[0])(_r(d[1])),l=_r(d[0])(_r(d[2])),r=_r(d[0])(_r(d[3])),o=_r(d[0])(_r(d[4])),n=_r(d[0])(_r(d[5]));var u=(function(){function u(){(0,l.default)(this,u)}return(0,r.default)(u,null,[{key:"createFromParts",value:function(t,l){(0,n.default)(o.default,'NativeBlobModule is available.');var r='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g,function(t){var l=16*Math.random()|0;return('x'==t?l:3&l|8).toString(16)}),f=t.map(function(t){if(t instanceof ArrayBuffer||g.ArrayBufferView&&t instanceof g.ArrayBufferView)throw new Error("Creating blobs from 'ArrayBuffer' and 'ArrayBufferView' are not supported");return t instanceof _r(d[6])?{data:t.data,type:'blob'}:{data:String(t),type:'string'}}),c=f.reduce(function(t,l){return'string'===l.type?t+g.unescape(encodeURI(l.data)).length:t+l.data.size},0);return o.default.createFromParts(f,r),u.createFromOptions({blobId:r,offset:0,size:c,type:l?l.type:'',lastModified:l?l.lastModified:Date.now()})}},{key:"createFromOptions",value:function(l){return _r(d[7]).register(l.blobId),(0,t.default)(Object.create(_r(d[6]).prototype),{data:null==l.__collector?(0,t.default)({},l,{__collector:(r=l.blobId,null==g.__blobCollectorProvider?null:g.__blobCollectorProvider(r))}):l});var r}},{key:"release",value:function(t){(0,n.default)(o.default,'NativeBlobModule is available.'),_r(d[7]).unregister(t),_r(d[7]).has(t)||o.default.release(t)}},{key:"addNetworkingHandler",value:function(){(0,n.default)(o.default,'NativeBlobModule is available.'),o.default.addNetworkingHandler()}},{key:"addWebSocketHandler",value:function(t){(0,n.default)(o.default,'NativeBlobModule is available.'),o.default.addWebSocketHandler(t)}},{key:"removeWebSocketHandler",value:function(t){(0,n.default)(o.default,'NativeBlobModule is available.'),o.default.removeWebSocketHandler(t)}},{key:"sendOverSocket",value:function(t,l){(0,n.default)(o.default,'NativeBlobModule is available.'),o.default.sendOverSocket(t.data,l)}}]),u})();u.isAvailable=!!o.default,m.exports=u},86,[3,29,7,8,87,18,88,89]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var l={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var f in n)if("default"!==f&&Object.prototype.hasOwnProperty.call(n,f)){var s=c?Object.getOwnPropertyDescriptor(n,f):null;s&&(s.get||s.set)?Object.defineProperty(l,f,s):l[f]=n[f]}l.default=n,u&&u.set(n,l);return l})(r(d[0])).get('BlobModule'),o=null,u=null;null!=n&&(u={getConstants:function(){return null==o&&(o=n.getConstants()),o},addNetworkingHandler:function(){n.addNetworkingHandler()},addWebSocketHandler:function(t){n.addWebSocketHandler(t)},removeWebSocketHandler:function(t){n.removeWebSocketHandler(t)},sendOverSocket:function(t,o){n.sendOverSocket(t,o)},createFromParts:function(t,o){n.createFromParts(t,o)},release:function(t){n.release(t)}});var l=u;e.default=l},87,[21]); -__d(function(g,r,i,a,m,e,d){'use strict';var t=(function(){function t(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],s=arguments.length>1?arguments[1]:void 0;r(d[0])(this,t);var o=r(d[1]);this.data=o.createFromParts(n,s).data}return r(d[2])(t,[{key:"data",get:function(){if(!this._data)throw new Error('Blob has been closed and is no longer available');return this._data},set:function(t){this._data=t}},{key:"slice",value:function(t,n){var s=r(d[1]),o=this.data,u=o.offset,l=o.size;return'number'==typeof t&&(t>l&&(t=l),u+=t,l-=t,'number'==typeof n&&(n<0&&(n=this.size+n),l=n-t)),s.createFromOptions({blobId:this.data.blobId,offset:u,size:l})}},{key:"close",value:function(){r(d[1]).release(this.data.blobId),this.data=null}},{key:"size",get:function(){return this.data.size}},{key:"type",get:function(){return this.data.type||''}}]),t})();m.exports=t},88,[7,86,8]); -__d(function(g,r,i,a,m,e,d){var n={};m.exports={register:function(t){n[t]?n[t]++:n[t]=1},unregister:function(t){n[t]&&(n[t]--,n[t]<=0&&delete n[t])},has:function(t){return n[t]&&n[t]>0}}},89,[]); -__d(function(g,r,_i,a,m,e,d){'use strict';Object.defineProperty(e,'__esModule',{value:!0});var t=new WeakMap,n=new WeakMap;function o(n){var o=t.get(n);return console.assert(null!=o,"'this' is expected an Event object, but got",n),o}function i(t){null==t.passiveListener?t.event.cancelable&&(t.canceled=!0,"function"==typeof t.event.preventDefault&&t.event.preventDefault()):"undefined"!=typeof console&&"function"==typeof console.error&&console.error("Unable to preventDefault inside passive event listener invocation.",t.passiveListener)}function l(n,o){t.set(this,{eventTarget:n,event:o,eventPhase:2,currentTarget:n,canceled:!1,stopped:!1,immediateStopped:!1,passiveListener:null,timeStamp:o.timeStamp||Date.now()}),Object.defineProperty(this,"isTrusted",{value:!1,enumerable:!0});for(var i=Object.keys(o),l=0;l0){for(var t=new Array(arguments.length),n=0;n1&&void 0!==arguments[1]?arguments[1]:l(),n=arguments.length>2?arguments[2]:void 0;this._closed||null==this._points[t]&&(this._points[t]=s,n&&(this._pointExtras[t]=n))}},{key:"removeExtra",value:function(t){var s=this._extras[t];return delete this._extras[t],s}},{key:"setExtra",value:function(t,s){this._closed||this._extras.hasOwnProperty(t)||(this._extras[t]=s)}},{key:"startTimespan",value:function(t){var s=arguments.length>1&&void 0!==arguments[1]?arguments[1]:l(),n=arguments.length>2?arguments[2]:void 0;this._closed||this._timespans[t]||(this._timespans[t]={startTime:s,startExtras:n},u[t]=r(d[4]).beginAsyncEvent(t))}},{key:"stopTimespan",value:function(t){var s=arguments.length>1&&void 0!==arguments[1]?arguments[1]:l(),n=arguments.length>2?arguments[2]:void 0;if(!this._closed){var o=this._timespans[t];o&&null!=o.startTime&&null==o.endTime&&(o.endExtras=n,o.endTime=s,o.totalTime=o.endTime-(o.startTime||0),null!=u[t]&&(r(d[4]).endAsyncEvent(t,u[t]),delete u[t]))}}}]),t})()},92,[3,29,7,8,32]); -__d(function(g,r,_i,a,m,e,d){'use strict';e.byteLength=function(t){var n=i(t),o=n[0],h=n[1];return 3*(o+h)/4-h},e.toByteArray=function(t){var h,u,c=i(t),A=c[0],C=c[1],y=new o(f(t,A,C)),s=0,v=C>0?A-4:A;for(u=0;u>16&255,y[s++]=h>>8&255,y[s++]=255&h;2===C&&(h=n[t.charCodeAt(u)]<<2|n[t.charCodeAt(u+1)]>>4,y[s++]=255&h);1===C&&(h=n[t.charCodeAt(u)]<<10|n[t.charCodeAt(u+1)]<<4|n[t.charCodeAt(u+2)]>>2,y[s++]=h>>8&255,y[s++]=255&h);return y},e.fromByteArray=function(n){for(var o,h=n.length,u=h%3,c=[],i=0,f=h-u;if?f:i+16383));1===u?(o=n[h-1],c.push(t[o>>2]+t[o<<4&63]+'==')):2===u&&(o=(n[h-2]<<8)+n[h-1],c.push(t[o>>10]+t[o>>4&63]+t[o<<2&63]+'='));return c.join('')};for(var t=[],n=[],o='undefined'!=typeof Uint8Array?Uint8Array:Array,h='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',u=0,c=h.length;u0)throw new Error('Invalid string. Length must be a multiple of 4');var o=t.indexOf('=');return-1===o&&(o=n),[o,o===n?0:4-o%4]}function f(t,n,o){return 3*(n+o)/4-o}function A(n,o,h){for(var u,c,i=[],f=o;f>18&63]+t[c>>12&63]+t[c>>6&63]+t[63&c]);return i.join('')}n['-'.charCodeAt(0)]=62,n['_'.charCodeAt(0)]=63},93,[]); -__d(function(g,r,i,a,m,_e,d){var t=r(d[0])(r(d[1])),e=r(d[0])(r(d[2])),u=r(d[0])(r(d[3])),n=r(d[0])(r(d[4])),f=r(d[0])(r(d[5])),o=r(d[0])(r(d[6])),l=r(d[0])(r(d[7])),c=r(d[0])(r(d[8])),s=r(d[0])(r(d[9])),v=r(d[0])(r(d[10]));function h(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}function p(t){var e=[];for(var u in t)e.push([u,t[u]]);return e}var y=1;var R=(function(l){(0,n.default)(D,l);var R,k,q=(R=D,k=h(),function(){var t,e=(0,o.default)(R);if(k){var u=(0,o.default)(this).constructor;t=Reflect.construct(e,arguments,u)}else t=e.apply(this,arguments);return(0,f.default)(this,t)});function D(){return(0,e.default)(this,D),q.call(this,'ios'!==v.default.OS?null:c.default)}return(0,u.default)(D,[{key:"sendRequest",value:function(e,u,n,f,o,l,v,h,R,k){var q=(0,s.default)(o);q&&q.formData&&(q.formData=q.formData.map(function(e){return(0,t.default)({},e,{headers:p(e.headers)})}));var D=y++;c.default.sendRequest(e,n,D,p(f),(0,t.default)({},q,{trackingName:u}),l,v,h,k),R(D)}},{key:"abortRequest",value:function(t){c.default.abortRequest(t)}},{key:"clearCookies",value:function(t){c.default.clearCookies(t)}}]),D})(l.default);m.exports=new R},94,[3,29,7,8,10,12,15,95,96,97,19]); -__d(function(g,r,i,a,m,e,d){'use strict';Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),l=r(d[0])(r(d[3])),u=r(d[0])(r(d[4])),o=r(d[0])(r(d[5])),s=(function(){function s(n){(0,t.default)(this,s),'ios'===l.default.OS&&(0,o.default)(null!=n,'`new NativeEventEmitter()` requires a non-null argument.');var u=!!n&&'function'==typeof n.addListener,v=!!n&&'function'==typeof n.removeListeners;n&&u&&v?this._nativeModule=n:null!=n&&(u||console.warn('`new NativeEventEmitter()` was called with a non-null argument without the required `addListener` method.'),v||console.warn('`new NativeEventEmitter()` was called with a non-null argument without the required `removeListeners` method.'))}return(0,n.default)(s,[{key:"addListener",value:function(t,n,l){var o,s=this;null==(o=this._nativeModule)||o.addListener(t);var v=u.default.addListener(t,n,l);return{remove:function(){var t;null!=v&&(null==(t=s._nativeModule)||t.removeListeners(1),v.remove(),v=null)}}}},{key:"removeListener",value:function(t,n){var l;null==(l=this._nativeModule)||l.removeListeners(1),u.default.removeListener(t,n)}},{key:"emit",value:function(t){for(var n=arguments.length,l=new Array(n>1?n-1:0),o=1;o-1};function s(t){if('string'!=typeof t&&(t=String(t)),/[^a-z0-9\-#$%&'*+.^_`|~!]/i.test(t)||''===t)throw new TypeError('Invalid character in header field name: "'+t+'"');return t.toLowerCase()}function h(t){return'string'!=typeof t&&(t=String(t)),t}function f(t){var e={next:function(){var e=t.shift();return{done:void 0===e,value:e}}};return o.iterable&&(e[Symbol.iterator]=function(){return e}),e}function u(t){this.map={},t instanceof u?t.forEach(function(t,e){this.append(e,t)},this):Array.isArray(t)?t.forEach(function(t){this.append(t[0],t[1])},this):t&&Object.getOwnPropertyNames(t).forEach(function(e){this.append(e,t[e])},this)}function c(t){if(t.bodyUsed)return Promise.reject(new TypeError('Already read'));t.bodyUsed=!0}function y(t){return new Promise(function(e,o){t.onload=function(){e(t.result)},t.onerror=function(){o(t.error)}})}function l(t){var e=new FileReader,o=y(e);return e.readAsArrayBuffer(t),o}function p(t){for(var e=new Uint8Array(t),o=new Array(e.length),n=0;n-1?n:o),this.mode=e.mode||this.mode||null,this.signal=e.signal||this.signal,this.referrer=null,('GET'===this.method||'HEAD'===this.method)&&i)throw new TypeError('Body not allowed for GET or HEAD requests');if(this._initBody(i),!('GET'!==this.method&&'HEAD'!==this.method||'no-store'!==e.cache&&'no-cache'!==e.cache)){var s=/([?&])_=[^&]*/;if(s.test(this.url))this.url=this.url.replace(s,'$1_='+(new Date).getTime());else{this.url+=(/\?/.test(this.url)?'&':'?')+'_='+(new Date).getTime()}}}function E(t){var e=new FormData;return t.trim().split('&').forEach(function(t){if(t){var o=t.split('='),n=o.shift().replace(/\+/g,' '),i=o.join('=').replace(/\+/g,' ');e.append(decodeURIComponent(n),decodeURIComponent(i))}}),e}function T(t,e){if(!(this instanceof T))throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');e||(e={}),this.type='default',this.status=void 0===e.status?200:e.status,this.ok=this.status>=200&&this.status<300,this.statusText=void 0===e.statusText?'':''+e.statusText,this.headers=new u(e.headers),this.url=e.url||'',this._initBody(t)}_.prototype.clone=function(){return new _(this,{body:this._bodyInit})},w.call(_.prototype),w.call(T.prototype),T.prototype.clone=function(){return new T(this._bodyInit,{status:this.status,statusText:this.statusText,headers:new u(this.headers),url:this.url})},T.error=function(){var t=new T(null,{status:0,statusText:''});return t.type='error',t};var A=[301,302,303,307,308];T.redirect=function(t,e){if(-1===A.indexOf(e))throw new RangeError('Invalid status code');return new T(null,{status:e,headers:{location:t}})},t.DOMException=e.DOMException;try{new t.DOMException}catch(e){t.DOMException=function(t,e){this.message=t,this.name=e;var o=Error(t);this.stack=o.stack},t.DOMException.prototype=Object.create(Error.prototype),t.DOMException.prototype.constructor=t.DOMException}function B(n,i){return new Promise(function(s,f){var c=new _(n,i);if(c.signal&&c.signal.aborted)return f(new t.DOMException('Aborted','AbortError'));var y=new XMLHttpRequest;function l(){y.abort()}y.onload=function(){var t,e,o={status:y.status,statusText:y.statusText,headers:(t=y.getAllResponseHeaders()||'',e=new u,t.replace(/\r?\n[\t ]+/g,' ').split('\r').map(function(t){return 0===t.indexOf('\n')?t.substr(1,t.length):t}).forEach(function(t){var o=t.split(':'),n=o.shift().trim();if(n){var i=o.join(':').trim();e.append(n,i)}}),e)};o.url='responseURL'in y?y.responseURL:o.headers.get('X-Request-URL');var n='response'in y?y.response:y.responseText;setTimeout(function(){s(new T(n,o))},0)},y.onerror=function(){setTimeout(function(){f(new TypeError('Network request failed'))},0)},y.ontimeout=function(){setTimeout(function(){f(new TypeError('Network request failed'))},0)},y.onabort=function(){setTimeout(function(){f(new t.DOMException('Aborted','AbortError'))},0)},y.open(c.method,(function(t){try{return''===t&&e.location.href?e.location.href:t}catch(e){return t}})(c.url),!0),'include'===c.credentials?y.withCredentials=!0:'omit'===c.credentials&&(y.withCredentials=!1),'responseType'in y&&(o.blob?y.responseType='blob':o.arrayBuffer&&c.headers.get('Content-Type')&&-1!==c.headers.get('Content-Type').indexOf('application/octet-stream')&&(y.responseType='arraybuffer')),!i||'object'!=typeof i.headers||i.headers instanceof u?c.headers.forEach(function(t,e){y.setRequestHeader(e,t)}):Object.getOwnPropertyNames(i.headers).forEach(function(t){y.setRequestHeader(t,h(i.headers[t]))}),c.signal&&(c.signal.addEventListener('abort',l),y.onreadystatechange=function(){4===y.readyState&&c.signal.removeEventListener('abort',l)}),y.send(void 0===c._bodyInit?null:c._bodyInit)})}B.polyfill=!0,e.fetch||(e.fetch=B,e.Headers=u,e.Request=_,e.Response=T),t.Headers=u,t.Request=_,t.Response=T,t.fetch=B,Object.defineProperty(t,'__esModule',{value:!0})},'object'==typeof _e&&void 0!==m?e(_e):'function'==typeof define&&define.amd?define(['exports'],e):e(t.WHATWGFetch={})},101,[]); -__d(function(g,r,i,a,m,_e,d){var e=r(d[0])(r(d[1])),t=r(d[0])(r(d[2])),n=r(d[0])(r(d[3])),s=r(d[0])(r(d[4])),o=r(d[0])(r(d[5])),u=r(d[0])(r(d[6])),c=r(d[0])(r(d[7])),l=r(d[0])(r(d[8])),f=r(d[0])(r(d[9])),h=r(d[0])(r(d[10])),y=r(d[0])(r(d[11])),b=r(d[0])(r(d[12])),p=r(d[0])(r(d[13])),v=r(d[0])(r(d[14])),_=r(d[0])(r(d[15])),E=r(d[0])(r(d[16])),k=["headers"];function S(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}var I=0,N=1,O=2,w=3,C=0,L=(function(_){(0,s.default)(R,_);var L,T,A=(L=R,T=S(),function(){var e,t=(0,u.default)(L);if(T){var n=(0,u.default)(this).constructor;e=Reflect.construct(t,arguments,n)}else e=t.apply(this,arguments);return(0,o.default)(this,e)});function R(n,s,o){var u;(0,t.default)(this,R),(u=A.call(this)).CONNECTING=I,u.OPEN=N,u.CLOSING=O,u.CLOSED=w,u.readyState=I,u.url=n,'string'==typeof s&&(s=[s]);var c=o||{},l=c.headers,h=void 0===l?{}:l,p=(0,e.default)(c,k);return p&&'string'==typeof p.origin&&(console.warn('Specifying `origin` as a WebSocket connection option is deprecated. Include it under `headers` instead.'),h.origin=p.origin,delete p.origin),Object.keys(p).length>0&&console.warn('Unrecognized WebSocket connection option(s) `'+Object.keys(p).join('`, `')+"`. Did you mean to put these under `headers`?"),Array.isArray(s)||(s=null),u._eventEmitter=new f.default('ios'!==y.default.OS?null:b.default),u._socketId=C++,u._registerEvents(),b.default.connect(n,s,{headers:h},u._socketId),u}return(0,n.default)(R,[{key:"binaryType",get:function(){return this._binaryType},set:function(e){if('blob'!==e&&'arraybuffer'!==e)throw new Error("binaryType must be either 'blob' or 'arraybuffer'");'blob'!==this._binaryType&&'blob'!==e||((0,E.default)(l.default.isAvailable,'Native module BlobModule is required for blob support'),'blob'===e?l.default.addWebSocketHandler(this._socketId):l.default.removeWebSocketHandler(this._socketId)),this._binaryType=e}},{key:"close",value:function(e,t){this.readyState!==this.CLOSING&&this.readyState!==this.CLOSED&&(this.readyState=this.CLOSING,this._close(e,t))}},{key:"send",value:function(e){if(this.readyState===this.CONNECTING)throw new Error('INVALID_STATE_ERR');if(e instanceof c.default)return(0,E.default)(l.default.isAvailable,'Native module BlobModule is required for blob support'),void l.default.sendOverSocket(e,this._socketId);if('string'!=typeof e){if(!(e instanceof ArrayBuffer||ArrayBuffer.isView(e)))throw new Error('Unsupported data type');b.default.sendBinary((0,h.default)(e),this._socketId)}else b.default.send(e,this._socketId)}},{key:"ping",value:function(){if(this.readyState===this.CONNECTING)throw new Error('INVALID_STATE_ERR');b.default.ping(this._socketId)}},{key:"_close",value:function(e,t){var n='number'==typeof e?e:1e3,s='string'==typeof t?t:'';b.default.close(n,s,this._socketId),l.default.isAvailable&&'blob'===this._binaryType&&l.default.removeWebSocketHandler(this._socketId)}},{key:"_unregisterEvents",value:function(){this._subscriptions.forEach(function(e){return e.remove()}),this._subscriptions=[]}},{key:"_registerEvents",value:function(){var e=this;this._subscriptions=[this._eventEmitter.addListener('websocketMessage',function(t){if(t.id===e._socketId){var n=t.data;switch(t.type){case'binary':n=v.default.toByteArray(t.data).buffer;break;case'blob':n=l.default.createFromOptions(t.data)}e.dispatchEvent(new p.default('message',{data:n}))}}),this._eventEmitter.addListener('websocketOpen',function(t){t.id===e._socketId&&(e.readyState=e.OPEN,e.protocol=t.protocol,e.dispatchEvent(new p.default('open')))}),this._eventEmitter.addListener('websocketClosed',function(t){t.id===e._socketId&&(e.readyState=e.CLOSED,e.dispatchEvent(new p.default('close',{code:t.code,reason:t.reason})),e._unregisterEvents(),e.close())}),this._eventEmitter.addListener('websocketFailed',function(t){t.id===e._socketId&&(e.readyState=e.CLOSED,e.dispatchEvent(new p.default('error',{message:t.message})),e.dispatchEvent(new p.default('close',{message:t.message})),e._unregisterEvents(),e.close())})]}}]),R})(_.default.apply(void 0,['close','error','message','open']));L.CONNECTING=I,L.OPEN=N,L.CLOSING=O,L.CLOSED=w,m.exports=L},102,[3,103,7,8,10,12,15,88,86,95,99,19,105,106,93,90,18]); -__d(function(g,r,_i,a,m,e,d){m.exports=function(t,o){if(null==t)return{};var n,l,p=r(d[0])(t,o);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(t);for(l=0;l=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(p[n]=t[n])}return p},m.exports.__esModule=!0,m.exports.default=m.exports},103,[104]); -__d(function(g,r,_i,a,m,e,d){m.exports=function(t,n){if(null==t)return{};var o,u,f={},s=Object.keys(t);for(u=0;u=0||(f[o]=t[o]);return f},m.exports.__esModule=!0,m.exports.default=m.exports},104,[]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in n)if("default"!==l&&Object.prototype.hasOwnProperty.call(n,l)){var p=c?Object.getOwnPropertyDescriptor(n,l):null;p&&(p.get||p.set)?Object.defineProperty(f,l,p):f[l]=n[l]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).getEnforcing('WebSocketModule');e.default=n},105,[21]); -__d(function(g,r,i,a,m,e,d){'use strict';var t=r(d[0])(function t(s,n){r(d[1])(this,t),this.type=s.toString(),r(d[2])(this,n)});m.exports=t},106,[8,7,29]); -__d(function(g,r,i,a,m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var e=(function(e){r(d[2])(o,e);var n,u,c=(n=o,u=t(),function(){var t,e=r(d[0])(n);if(u){var c=r(d[0])(this).constructor;t=Reflect.construct(e,arguments,c)}else t=e.apply(this,arguments);return r(d[1])(this,t)});function o(t,e,n){var u;return r(d[3])(this,o),r(d[4])(null!=t&&null!=e,'Failed to construct `File`: Must pass both `parts` and `name` arguments.'),(u=c.call(this,t,n)).data.name=e,u}return r(d[5])(o,[{key:"name",get:function(){return r(d[4])(null!=this.data.name,'Files must have a name set.'),this.data.name}},{key:"lastModified",get:function(){return this.data.lastModified||0}}]),o})(r(d[6]));m.exports=e},107,[15,12,10,7,18,8,88]); -__d(function(g,r,i,a,m,_e,d){var t=r(d[0])(r(d[1])),e=r(d[0])(r(d[2])),n=r(d[0])(r(d[3])),o=r(d[0])(r(d[4])),s=r(d[0])(r(d[5])),u=r(d[0])(r(d[6]));function l(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var c=0,f=1,h=2,y=(function(y){(0,n.default)(b,y);var _,p,v=(_=b,p=l(),function(){var t,e=(0,s.default)(_);if(p){var n=(0,s.default)(this).constructor;t=Reflect.construct(e,arguments,n)}else t=e.apply(this,arguments);return(0,o.default)(this,t)});function b(){var e;return(0,t.default)(this,b),(e=v.call(this)).EMPTY=c,e.LOADING=f,e.DONE=h,e._aborted=!1,e._subscriptions=[],e._reset(),e}return(0,e.default)(b,[{key:"_reset",value:function(){this._readyState=c,this._error=null,this._result=null}},{key:"_clearSubscriptions",value:function(){this._subscriptions.forEach(function(t){return t.remove()}),this._subscriptions=[]}},{key:"_setReadyState",value:function(t){this._readyState=t,this.dispatchEvent({type:'readystatechange'}),t===h&&(this._aborted?this.dispatchEvent({type:'abort'}):this._error?this.dispatchEvent({type:'error'}):this.dispatchEvent({type:'load'}),this.dispatchEvent({type:'loadend'}))}},{key:"readAsArrayBuffer",value:function(){throw new Error('FileReader.readAsArrayBuffer is not implemented')}},{key:"readAsDataURL",value:function(t){var e=this;if(this._aborted=!1,null==t)throw new TypeError("Failed to execute 'readAsDataURL' on 'FileReader': parameter 1 is not of type 'Blob'");u.default.readAsDataURL(t.data).then(function(t){e._aborted||(e._result=t,e._setReadyState(h))},function(t){e._aborted||(e._error=t,e._setReadyState(h))})}},{key:"readAsText",value:function(t){var e=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:'UTF-8';if(this._aborted=!1,null==t)throw new TypeError("Failed to execute 'readAsText' on 'FileReader': parameter 1 is not of type 'Blob'");u.default.readAsText(t.data,n).then(function(t){e._aborted||(e._result=t,e._setReadyState(h))},function(t){e._aborted||(e._error=t,e._setReadyState(h))})}},{key:"abort",value:function(){this._aborted=!0,this._readyState!==c&&this._readyState!==h&&(this._reset(),this._setReadyState(h)),this._reset()}},{key:"readyState",get:function(){return this._readyState}},{key:"error",get:function(){return this._error}},{key:"result",get:function(){return this._result}}]),b})(r(d[7]).apply(void 0,['abort','error','load','loadstart','loadend','progress']));y.EMPTY=c,y.LOADING=f,y.DONE=h,m.exports=y},108,[3,7,8,10,12,15,109,90]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in n)if("default"!==c&&Object.prototype.hasOwnProperty.call(n,c)){var p=l?Object.getOwnPropertyDescriptor(n,c):null;p&&(p.get||p.set)?Object.defineProperty(f,c,p):f[c]=n[c]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).getEnforcing('FileReaderModule');e.default=n},109,[21]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.URLSearchParams=e.URL=void 0;var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),o=r(d[0])(r(d[3])),s=null;if(o.default&&'string'==typeof o.default.getConstants().BLOB_URI_SCHEME){var u=o.default.getConstants();s=u.BLOB_URI_SCHEME+':','string'==typeof u.BLOB_URI_HOST&&(s+="//"+u.BLOB_URI_HOST+"/")}var h=(function(o){function s(n){var o=this;(0,t.default)(this,s),this._searchParams=[],'object'==typeof n&&Object.keys(n).forEach(function(t){return o.append(t,n[t])})}return(0,n.default)(s,[{key:"append",value:function(t,n){this._searchParams.push([t,n])}},{key:"delete",value:function(t){throw new Error('URLSearchParams.delete is not implemented')}},{key:"get",value:function(t){throw new Error('URLSearchParams.get is not implemented')}},{key:"getAll",value:function(t){throw new Error('URLSearchParams.getAll is not implemented')}},{key:"has",value:function(t){throw new Error('URLSearchParams.has is not implemented')}},{key:"set",value:function(t,n){throw new Error('URLSearchParams.set is not implemented')}},{key:"sort",value:function(){throw new Error('URLSearchParams.sort is not implemented')}},{key:o,value:function(){return this._searchParams[Symbol.iterator]()}},{key:"toString",value:function(){if(0===this._searchParams.length)return'';var t=this._searchParams.length-1;return this._searchParams.reduce(function(n,o,s){return n+o.join('=')+(s===t?'':'&')},'')}}]),s})(Symbol.iterator);function f(t){return/^(?:(?:(?:https?|ftp):)?\/\/)(?:(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z0-9\u00a1-\uffff][a-z0-9\u00a1-\uffff_-]{0,62})?[a-z0-9\u00a1-\uffff]\.)*(?:[a-z\u00a1-\uffff]{2,}\.?))(?::\d{2,5})?(?:[/?#]\S*)?$/.test(t)}e.URLSearchParams=h;var l=(function(){function o(n,s){(0,t.default)(this,o),this._searchParamsInstance=null;var u=null;if(!s||f(n))this._url=n,this._url.endsWith('/')||(this._url+='/');else{if('string'==typeof s){if(!f(u=s))throw new TypeError("Invalid base URL: "+u)}else'object'==typeof s&&(u=s.toString());u.endsWith('/')&&(u=u.slice(0,u.length-1)),n.startsWith('/')||(n="/"+n),u.endsWith(n)&&(n=''),this._url=""+u+n}}return(0,n.default)(o,[{key:"hash",get:function(){throw new Error('URL.hash is not implemented')}},{key:"host",get:function(){throw new Error('URL.host is not implemented')}},{key:"hostname",get:function(){throw new Error('URL.hostname is not implemented')}},{key:"href",get:function(){return this.toString()}},{key:"origin",get:function(){throw new Error('URL.origin is not implemented')}},{key:"password",get:function(){throw new Error('URL.password is not implemented')}},{key:"pathname",get:function(){throw new Error('URL.pathname not implemented')}},{key:"port",get:function(){throw new Error('URL.port is not implemented')}},{key:"protocol",get:function(){throw new Error('URL.protocol is not implemented')}},{key:"search",get:function(){throw new Error('URL.search is not implemented')}},{key:"searchParams",get:function(){return null==this._searchParamsInstance&&(this._searchParamsInstance=new h),this._searchParamsInstance}},{key:"toJSON",value:function(){return this.toString()}},{key:"toString",value:function(){if(null===this._searchParamsInstance)return this._url;var t=this._url.indexOf('?')>-1?'&':'?';return this._url+t+this._searchParamsInstance.toString()}},{key:"username",get:function(){throw new Error('URL.username is not implemented')}}],[{key:"createObjectURL",value:function(t){if(null===s)throw new Error('Cannot create URL for blob!');return""+s+t.data.blobId+"?offset="+t.data.offset+"&size="+t.size}},{key:"revokeObjectURL",value:function(t){}}]),o})();e.URL=l},110,[3,7,8,87]); -__d(function(g,r,i,a,m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}Object.defineProperty(_e,'__esModule',{value:!0});var e=(function(e){r(d[2])(c,e);var n,l,u=(n=c,l=t(),function(){var t,e=r(d[0])(n);if(l){var o=r(d[0])(this).constructor;t=Reflect.construct(e,arguments,o)}else t=e.apply(this,arguments);return r(d[1])(this,t)});function c(){throw r(d[3])(this,c),u.call(this),new TypeError("AbortSignal cannot be constructed directly")}return r(d[4])(c,[{key:"aborted",get:function(){var t=o.get(this);if("boolean"!=typeof t)throw new TypeError("Expected 'this' to be an 'AbortSignal' object, but got "+(null===this?"null":typeof this));return t}}]),c})(r(d[5]).EventTarget);r(d[5]).defineEventAttribute(e.prototype,"abort");var o=new WeakMap;Object.defineProperties(e.prototype,{aborted:{enumerable:!0}}),"function"==typeof Symbol&&"symbol"==typeof Symbol.toStringTag&&Object.defineProperty(e.prototype,Symbol.toStringTag,{configurable:!0,value:"AbortSignal"});var n=(function(){function t(){var n;r(d[3])(this,t),l.set(this,(n=Object.create(e.prototype),r(d[5]).EventTarget.call(n),o.set(n,!1),n))}return r(d[4])(t,[{key:"signal",get:function(){return u(this)}},{key:"abort",value:function(){var t;t=u(this),!1===o.get(t)&&(o.set(t,!0),t.dispatchEvent({type:"abort"}))}}]),t})(),l=new WeakMap;function u(t){var e=l.get(t);if(null==e)throw new TypeError("Expected 'this' to be an 'AbortController' object, but got "+(null===t?"null":typeof t));return e}Object.defineProperties(n.prototype,{signal:{enumerable:!0},abort:{enumerable:!0}}),"function"==typeof Symbol&&"symbol"==typeof Symbol.toStringTag&&Object.defineProperty(n.prototype,Symbol.toStringTag,{configurable:!0,value:"AbortController"}),_e.AbortController=n,_e.AbortSignal=e,_e.default=n,m.exports=n,m.exports.AbortController=m.exports.default=n,m.exports.AbortSignal=e},111,[15,12,10,7,8,90]); -__d(function(g,r,i,a,m,e,d){'use strict';g.alert||(g.alert=function(t){r(d[0]).alert('Alert',''+t)})},112,[113]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),o=r(d[0])(r(d[3])),s=r(d[0])(r(d[4])),l=(function(){function l(){(0,t.default)(this,l)}return(0,n.default)(l,null,[{key:"alert",value:function(t,n,s,u){if('ios'===o.default.OS)l.prompt(t,n,s,'default');else if('android'===o.default.OS){var c=r(d[5]).default;if(!c)return;var f=c.getConstants(),v={title:t||'',message:n||'',cancelable:!1};u&&u.cancelable&&(v.cancelable=u.cancelable);var p=s?s.slice(0,3):[{text:"OK"}],b=p.pop(),y=p.pop(),h=p.pop();h&&(v.buttonNeutral=h.text||''),y&&(v.buttonNegative=y.text||''),b&&(v.buttonPositive=b.text||"OK");c.showAlert(v,function(t){return console.warn(t)},function(t,n){t===f.buttonClicked?n===f.buttonNeutral?h.onPress&&h.onPress():n===f.buttonNegative?y.onPress&&y.onPress():n===f.buttonPositive&&b.onPress&&b.onPress():t===f.dismissed&&u&&u.onDismiss&&u.onDismiss()})}}},{key:"prompt",value:function(t,n,l){var u=arguments.length>3&&void 0!==arguments[3]?arguments[3]:'plain-text',c=arguments.length>4?arguments[4]:void 0,f=arguments.length>5?arguments[5]:void 0;if('ios'===o.default.OS){var v,p,b=[],y=[];'function'==typeof l?b=[l]:Array.isArray(l)&&l.forEach(function(t,n){if(b[n]=t.onPress,'cancel'===t.style?v=String(n):'destructive'===t.style&&(p=String(n)),t.text||n<(l||[]).length-1){var o={};o[n]=t.text||'',y.push(o)}}),s.default.alertWithArgs({title:t||'',message:n||void 0,buttons:y,type:u||void 0,defaultValue:c,cancelButtonKey:v,destructiveButtonKey:p,keyboardType:f},function(t,n){var o=b[t];o&&o(n)})}}}]),l})();m.exports=l},113,[3,7,8,19,114,115]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1]));function n(){}m.exports={alertWithArgs:function(f,o){t.default&&t.default.showAlert(f,n,o||n)}}},114,[3,115]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in n)if("default"!==c&&Object.prototype.hasOwnProperty.call(n,c)){var p=l?Object.getOwnPropertyDescriptor(n,c):null;p&&(p.get||p.set)?Object.defineProperty(f,c,p):f[c]=n[c]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).get('DialogManagerAndroid');e.default=n},115,[21]); -__d(function(g,r,i,a,m,e,d){'use strict';var t=g.navigator;void 0===t&&(g.navigator=t={}),r(d[0]).polyfillObjectProperty(t,'product',function(){return'ReactNative'})},116,[67]); -__d(function(g,r,i,a,m,e,d){'use strict';var n;if(g.RN$Bridgeless&&g.RN$registerCallableModule)n=g.RN$registerCallableModule;else{var t=r(d[0]);n=function(n,u){return t.registerLazyCallableModule(n,u)}}n('Systrace',function(){return r(d[1])}),n('JSTimers',function(){return r(d[2])}),n('HeapCapture',function(){return r(d[3])}),n('SamplingProfiler',function(){return r(d[4])}),n('RCTLog',function(){return r(d[5])}),n('RCTDeviceEventEmitter',function(){return r(d[6]).default}),n('RCTNativeAppEventEmitter',function(){return r(d[7])}),n('GlobalPerformanceLogger',function(){return r(d[8])}),n('JSDevSupportModule',function(){return r(d[9])}),n('HMRClient',function(){return r(d[10])})},117,[30,32,78,118,120,122,4,123,91,124,126]); -__d(function(g,r,i,a,m,_e,d){var e=r(d[0])(r(d[1])),t={captureHeap:function(t){var p=null;try{g.nativeCaptureHeap(t),console.log('HeapCapture.captureHeap succeeded: '+t)}catch(e){console.log('HeapCapture.captureHeap error: '+e.toString()),p=e.toString()}e.default&&e.default.captureComplete(t,p)}};m.exports=t},118,[3,119]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var u=new WeakMap,o=new WeakMap;return(t=function(t){return t?o:u})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,u){if(!u&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var o=t(u);if(o&&o.has(n))return o.get(n);var f={},p=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in n)if("default"!==c&&Object.prototype.hasOwnProperty.call(n,c)){var l=p?Object.getOwnPropertyDescriptor(n,c):null;l&&(l.get||l.set)?Object.defineProperty(f,c,l):f[c]=n[c]}f.default=n,o&&o.set(n,f);return f})(r(d[0])).get('JSCHeapCapture');e.default=n},119,[21]); -__d(function(g,r,i,a,m,_e,d){'use strict';var o={poke:function(o){var e=null,l=null;try{null===(l=g.pokeSamplingProfiler())?console.log('The JSC Sampling Profiler has started'):console.log('The JSC Sampling Profiler has stopped')}catch(o){console.log('Error occurred when restarting Sampling Profiler: '+o.toString()),e=o.toString()}var n=r(d[0]).default;n&&n.operationComplete(o,l,e)}};m.exports=o},120,[121]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,f=new WeakMap;return(t=function(t){return t?f:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var f=t(o);if(f&&f.has(n))return f.get(n);var u={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var p in n)if("default"!==p&&Object.prototype.hasOwnProperty.call(n,p)){var c=l?Object.getOwnPropertyDescriptor(n,p):null;c&&(c.get||c.set)?Object.defineProperty(u,p,c):u[p]=n[p]}u.default=n,f&&f.set(n,u);return u})(r(d[0])).get('JSCSamplingProfiler');e.default=n},121,[21]); -__d(function(g,r,i,a,m,e,d){'use strict';var o={log:'log',info:'info',warn:'warn',error:'error',fatal:'error'},n=null,l={logIfNoNativeHook:function(o){for(var t=arguments.length,f=new Array(t>1?t-1:0),c=1;c1?f-1:0),v=1;v1?t-1:0),f=1;f>>8)>>>0,t|=0)}}},141,[142,144]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1]));m.exports=function(n){if('object'==typeof n&&null!=n&&null!=(0,r(d[2]).normalizeColorObject)(n))return n;if('string'==typeof n||'number'==typeof n)return(0,t.default)(n)}},142,[3,143,144]); -__d(function(_g,_r,i,a,m,e,d){'use strict';function r(r,l,n){return n<0&&(n+=1),n>1&&(n-=1),n<.16666666666666666?r+6*(l-r)*n:n<.5?l:n<.6666666666666666?r+(l-r)*(.6666666666666666-n)*6:r}function l(l,n,t){var o=t<.5?t*(1+n):t+n-t*n,u=2*t-o,g=r(u,o,l+.3333333333333333),s=r(u,o,l),h=r(u,o,l-.3333333333333333);return Math.round(255*g)<<24|Math.round(255*s)<<16|Math.round(255*h)<<8}var n,t='[-+]?\\d*\\.?\\d+',o="[-+]?\\d*\\.?\\d+%";function u(){for(var r=arguments.length,l=new Array(r),n=0;n255?255:l}function s(r){return(parseFloat(r)%360+360)%360/360}function h(r){var l=parseFloat(r);return l<0?0:l>1?255:Math.round(255*l)}function c(r){var l=parseFloat(r);return l<0?0:l>100?1:l/100}var p={transparent:0,aliceblue:4042850303,antiquewhite:4209760255,aqua:16777215,aquamarine:2147472639,azure:4043309055,beige:4126530815,bisque:4293182719,black:255,blanchedalmond:4293643775,blue:65535,blueviolet:2318131967,brown:2771004159,burlywood:3736635391,burntsienna:3934150143,cadetblue:1604231423,chartreuse:2147418367,chocolate:3530104575,coral:4286533887,cornflowerblue:1687547391,cornsilk:4294499583,crimson:3692313855,cyan:16777215,darkblue:35839,darkcyan:9145343,darkgoldenrod:3095792639,darkgray:2846468607,darkgreen:6553855,darkgrey:2846468607,darkkhaki:3182914559,darkmagenta:2332068863,darkolivegreen:1433087999,darkorange:4287365375,darkorchid:2570243327,darkred:2332033279,darksalmon:3918953215,darkseagreen:2411499519,darkslateblue:1211993087,darkslategray:793726975,darkslategrey:793726975,darkturquoise:13554175,darkviolet:2483082239,deeppink:4279538687,deepskyblue:12582911,dimgray:1768516095,dimgrey:1768516095,dodgerblue:512819199,firebrick:2988581631,floralwhite:4294635775,forestgreen:579543807,fuchsia:4278255615,gainsboro:3705462015,ghostwhite:4177068031,gold:4292280575,goldenrod:3668254975,gray:2155905279,green:8388863,greenyellow:2919182335,grey:2155905279,honeydew:4043305215,hotpink:4285117695,indianred:3445382399,indigo:1258324735,ivory:4294963455,khaki:4041641215,lavender:3873897215,lavenderblush:4293981695,lawngreen:2096890111,lemonchiffon:4294626815,lightblue:2916673279,lightcoral:4034953471,lightcyan:3774873599,lightgoldenrodyellow:4210742015,lightgray:3553874943,lightgreen:2431553791,lightgrey:3553874943,lightpink:4290167295,lightsalmon:4288707327,lightseagreen:548580095,lightskyblue:2278488831,lightslategray:2005441023,lightslategrey:2005441023,lightsteelblue:2965692159,lightyellow:4294959359,lime:16711935,limegreen:852308735,linen:4210091775,magenta:4278255615,maroon:2147483903,mediumaquamarine:1724754687,mediumblue:52735,mediumorchid:3126187007,mediumpurple:2473647103,mediumseagreen:1018393087,mediumslateblue:2070474495,mediumspringgreen:16423679,mediumturquoise:1221709055,mediumvioletred:3340076543,midnightblue:421097727,mintcream:4127193855,mistyrose:4293190143,moccasin:4293178879,navajowhite:4292783615,navy:33023,oldlace:4260751103,olive:2155872511,olivedrab:1804477439,orange:4289003775,orangered:4282712319,orchid:3664828159,palegoldenrod:4008225535,palegreen:2566625535,paleturquoise:2951671551,palevioletred:3681588223,papayawhip:4293907967,peachpuff:4292524543,peru:3448061951,pink:4290825215,plum:3718307327,powderblue:2967529215,purple:2147516671,rebeccapurple:1714657791,red:4278190335,rosybrown:3163525119,royalblue:1097458175,saddlebrown:2336560127,salmon:4202722047,sandybrown:4104413439,seagreen:780883967,seashell:4294307583,sienna:2689740287,silver:3233857791,skyblue:2278484991,slateblue:1784335871,slategray:1887473919,slategrey:1887473919,snow:4294638335,springgreen:16744447,steelblue:1182971135,tan:3535047935,teal:8421631,thistle:3636451583,tomato:4284696575,turquoise:1088475391,violet:4001558271,wheat:4125012991,white:4294967295,whitesmoke:4126537215,yellow:4294902015,yellowgreen:2597139199};m.exports=function(r){var b,y=(void 0===n&&(n={rgb:new RegExp('rgb'+u(t,t,t)),rgba:new RegExp('rgba'+u(t,t,t,t)),hsl:new RegExp('hsl'+u(t,o,o)),hsla:new RegExp('hsla'+u(t,o,o,t)),hex3:/^#([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,hex4:/^#([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,hex6:/^#([0-9a-fA-F]{6})$/,hex8:/^#([0-9a-fA-F]{8})$/}),n);return'number'==typeof r?r>>>0===r&&r>=0&&r<=4294967295?r:null:'string'!=typeof r?null:(b=y.hex6.exec(r))?parseInt(b[1]+'ff',16)>>>0:p.hasOwnProperty(r)?p[r]:(b=y.rgb.exec(r))?(g(b[1])<<24|g(b[2])<<16|g(b[3])<<8|255)>>>0:(b=y.rgba.exec(r))?(g(b[1])<<24|g(b[2])<<16|g(b[3])<<8|h(b[4]))>>>0:(b=y.hex3.exec(r))?parseInt(b[1]+b[1]+b[2]+b[2]+b[3]+b[3]+'ff',16)>>>0:(b=y.hex8.exec(r))?parseInt(b[1],16)>>>0:(b=y.hex4.exec(r))?parseInt(b[1]+b[1]+b[2]+b[2]+b[3]+b[3]+b[4]+b[4],16)>>>0:(b=y.hsl.exec(r))?(255|l(s(b[1]),c(b[2]),c(b[3])))>>>0:(b=y.hsla.exec(r))?(l(s(b[1]),c(b[2]),c(b[3]))|h(b[4]))>>>0:null}},143,[]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.processColorObject=e.normalizeColorObject=e.PlatformColor=void 0;e.PlatformColor=function(){for(var o=arguments.length,n=new Array(o),t=0;t.49999*l?[0,2*Math.atan2(u,m)*C,90]:M<-.49999*l?[0,-2*Math.atan2(u,m)*C,-90]:[t.roundTo3Places(Math.atan2(2*u*m-2*s*c,1-2*v-2*h)*C),t.roundTo3Places(Math.atan2(2*s*m-2*u*c,1-2*f-2*h)*C),t.roundTo3Places(Math.asin(2*u*s+2*c*m)*C)]},roundTo3Places:function(t){var n=t.toString().split('e');return.001*Math.round(n[0]+'e'+(n[1]?+n[1]-3:3))},decomposeMatrix:function(n){r(d[1])(16===n.length,'Matrix decomposition needs a list of 3d matrix values, received %s',n);var a=[],o=[],i=[],u=[],s=[];if(n[15]){for(var c=[],m=[],v=0;v<4;v++){c.push([]);for(var f=0;f<4;f++){var h=n[4*v+f]/n[15];c[v].push(h),m.push(3===f?0:h)}}if(m[15]=1,t.determinant(m)){if(0!==c[0][3]||0!==c[1][3]||0!==c[2][3]){var M=[c[0][3],c[1][3],c[2][3],c[3][3]],l=t.inverse(m),C=t.transpose(l);a=t.multiplyVectorByMatrix(M,C)}else a[0]=a[1]=a[2]=0,a[3]=1;for(var p=0;p<3;p++)s[p]=c[3][p];for(var x=[],T=0;T<3;T++)x[T]=[c[T][0],c[T][1],c[T][2]];i[0]=t.v3Length(x[0]),x[0]=t.v3Normalize(x[0],i[0]),u[0]=t.v3Dot(x[0],x[1]),x[1]=t.v3Combine(x[1],x[0],1,-u[0]),i[1]=t.v3Length(x[1]),x[1]=t.v3Normalize(x[1],i[1]),u[0]/=i[1],u[1]=t.v3Dot(x[0],x[2]),x[2]=t.v3Combine(x[2],x[0],1,-u[1]),u[2]=t.v3Dot(x[1],x[2]),x[2]=t.v3Combine(x[2],x[1],1,-u[2]),i[2]=t.v3Length(x[2]),x[2]=t.v3Normalize(x[2],i[2]),u[1]/=i[2],u[2]/=i[2];var y,S=t.v3Cross(x[1],x[2]);if(t.v3Dot(x[0],S)<0)for(var P=0;P<3;P++)i[P]*=-1,x[P][0]*=-1,x[P][1]*=-1,x[P][2]*=-1;return o[0]=.5*Math.sqrt(Math.max(1+x[0][0]-x[1][1]-x[2][2],0)),o[1]=.5*Math.sqrt(Math.max(1-x[0][0]+x[1][1]-x[2][2],0)),o[2]=.5*Math.sqrt(Math.max(1-x[0][0]-x[1][1]+x[2][2],0)),o[3]=.5*Math.sqrt(Math.max(1+x[0][0]+x[1][1]+x[2][2],0)),x[2][1]>x[1][2]&&(o[0]=-o[0]),x[0][2]>x[2][0]&&(o[1]=-o[1]),x[1][0]>x[0][1]&&(o[2]=-o[2]),{rotationDegrees:y=o[0]<.001&&o[0]>=0&&o[1]<.001&&o[1]>=0?[0,0,t.roundTo3Places(180*Math.atan2(x[0][1],x[0][0])/Math.PI)]:t.quaternionToDegreesXYZ(o,c,x),perspective:a,quaternion:o,scale:i,skew:u,translation:s,rotate:y[2],rotateX:y[0],rotateY:y[1],scaleX:i[0],scaleY:i[1],translateX:s[0],translateY:s[1]}}}}};_m.exports=t},149,[23,18]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.get=p,e.getWithFallback_DEPRECATED=function(n,o){if(null==t){if(v(n))return p(n,o)}else if(null!=t(n))return p(n,o);var u=function(t){return null};return u.displayName="Fallback("+n+")",u},e.setRuntimeConfigProvider=function(n){(0,f.default)(null==t,'NativeComponentRegistry.setRuntimeConfigProvider() called more than once.'),t=n},e.unstable_hasComponent=function(t){var n=s.get(t);if(null==n){if(!g.__nativeComponentRegistry__hasComponent)throw"unstable_hasComponent('"+t+"'): Global function is not registered";n=g.__nativeComponentRegistry__hasComponent(t),s.set(t,n)}return n},e.unstable_hasStaticViewConfig=function(n){var o;return!(null!=(o=null==t?void 0:t(n))?o:{native:!0}).native};var t,n=r(d[0])(r(d[1])),o=r(d[0])(r(d[2])),u=r(d[0])(r(d[3])),l=r(d[0])(r(d[4])),f=r(d[0])(r(d[5]));!(function(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var o=c(n);if(o&&o.has(t))return o.get(t);var u={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var f in t)if("default"!==f&&Object.prototype.hasOwnProperty.call(t,f)){var s=l?Object.getOwnPropertyDescriptor(t,f):null;s&&(s.get||s.set)?Object.defineProperty(u,f,s):u[f]=t[f]}u.default=t,o&&o.set(t,u)})(r(d[6]));function c(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,o=new WeakMap;return(c=function(t){return t?o:n})(t)}var s=new Map;function p(n,f){return o.default.register(n,function(){var o,c=null!=(o=null==t?void 0:t(n))?o:{native:!0,verify:!1},s=c.native,p=c.verify,v=s?(0,u.default)(n):(0,r(d[7]).createViewConfig)(f());return p&&(s?(0,l.default)(v,(0,r(d[7]).createViewConfig)(f())):(0,l.default)((0,u.default)(n),v)),v}),n}function v(o){return(0,f.default)(null==t,'Unexpected invocation!'),null!=n.default.getViewManagerConfig(o)}},150,[3,43,134,151,164,18,129,165]); -__d(function(g,r,i,a,m,e,d){'use strict';var n=!1;function t(n){var t=r(d[0]).getConstants();t.ViewManagerNames||t.LazyViewManagersEnabled?n=s(n,r(d[0]).getDefaultEventTypes()):(n.bubblingEventTypes=s(n.bubblingEventTypes,t.genericBubblingEventTypes),n.directEventTypes=s(n.directEventTypes,t.genericDirectEventTypes))}function s(n,t){if(!t)return n;if(!n)return t;for(var o in t)if(t.hasOwnProperty(o)){var u=t[o];if(n.hasOwnProperty(o)){var c=n[o];'object'==typeof u&&'object'==typeof c&&(u=s(c,u))}n[o]=u}return n}function o(n){switch(n){case'CATransform3D':return r(d[4]);case'CGPoint':return r(d[5]);case'CGSize':return r(d[6]);case'UIEdgeInsets':return r(d[7]);case'Point':return r(d[5])}return null}function u(n){switch(n){case'CGColor':case'UIColor':return r(d[8]);case'CGColorArray':case'UIColorArray':return r(d[9]);case'CGImage':case'UIImage':case'RCTImageSource':return r(d[10]);case'Color':return r(d[8]);case'ColorArray':return r(d[9])}return null}m.exports=function(s){var c=r(d[0]).getViewManagerConfig(s);r(d[1])(null!=c&&null!=c.NativeProps,'requireNativeComponent: "%s" was not found in the UIManager.',s);for(var l=c.baseModuleName,v=c.bubblingEventTypes,b=c.directEventTypes,p=c.NativeProps;l;){var f=r(d[0]).getViewManagerConfig(l);f?(v=r(d[2])({},f.bubblingEventTypes,v),b=r(d[2])({},f.directEventTypes,b),p=r(d[2])({},f.NativeProps,p),l=f.baseModuleName):l=null}var y={};for(var C in p){var E=p[C],T=o(E),w=u(E);y[C]=null==T&&null==w||{diff:T,process:w}}return y.style=r(d[3]),r(d[2])(c,{uiViewClassName:s,validAttributes:y,bubblingEventTypes:v,directEventTypes:b}),n||(t(c),n=!0),c}},151,[43,18,29,152,147,153,146,145,141,154,155]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),o=r(d[0])(r(d[2])),n=r(d[0])(r(d[3])),l={process:t.default},s={alignContent:!0,alignItems:!0,alignSelf:!0,aspectRatio:!0,borderBottomWidth:!0,borderEndWidth:!0,borderLeftWidth:!0,borderRightWidth:!0,borderStartWidth:!0,borderTopWidth:!0,borderWidth:!0,bottom:!0,direction:!0,display:!0,end:!0,flex:!0,flexBasis:!0,flexDirection:!0,flexGrow:!0,flexShrink:!0,flexWrap:!0,height:!0,justifyContent:!0,left:!0,margin:!0,marginBottom:!0,marginEnd:!0,marginHorizontal:!0,marginLeft:!0,marginRight:!0,marginStart:!0,marginTop:!0,marginVertical:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,overflow:!0,padding:!0,paddingBottom:!0,paddingEnd:!0,paddingHorizontal:!0,paddingLeft:!0,paddingRight:!0,paddingStart:!0,paddingTop:!0,paddingVertical:!0,position:!0,right:!0,start:!0,top:!0,width:!0,zIndex:!0,elevation:!0,shadowColor:l,shadowOffset:{diff:n.default},shadowOpacity:!0,shadowRadius:!0,decomposedMatrix:!0,rotation:!0,scaleX:!0,scaleY:!0,transform:{process:o.default},transformMatrix:!0,translateX:!0,translateY:!0,backfaceVisibility:!0,backgroundColor:l,borderBottomColor:l,borderBottomEndRadius:!0,borderBottomLeftRadius:!0,borderBottomRightRadius:!0,borderBottomStartRadius:!0,borderColor:l,borderEndColor:l,borderLeftColor:l,borderRadius:!0,borderRightColor:l,borderStartColor:l,borderStyle:!0,borderTopColor:l,borderTopEndRadius:!0,borderTopLeftRadius:!0,borderTopRightRadius:!0,borderTopStartRadius:!0,opacity:!0,color:l,fontFamily:!0,fontSize:!0,fontStyle:!0,fontVariant:!0,fontWeight:!0,includeFontPadding:!0,letterSpacing:!0,lineHeight:!0,textAlign:!0,textAlignVertical:!0,textDecorationColor:l,textDecorationLine:!0,textDecorationStyle:!0,textShadowColor:l,textShadowOffset:!0,textShadowRadius:!0,textTransform:!0,writingDirection:!0,overlayColor:l,resizeMode:!0,tintColor:l};m.exports=s},152,[3,141,148,146]); -__d(function(g,r,i,a,m,e,d){'use strict';var t={x:void 0,y:void 0};m.exports=function(n,o){return(n=n||t)!==(o=o||t)&&(n.x!==o.x||n.y!==o.y)}},153,[]); -__d(function(g,r,i,a,m,e,d){'use strict';var n=r(d[0])(r(d[1])),l=0;function u(u){var o=(0,n.default)(u);return null==o?(console.error('Invalid value in color array:',u),l):o}m.exports=function(n){return null==n?null:n.map(u)}},154,[3,141]); -__d(function(g,r,i,a,m,e,d){'use strict';var t,n,s,u;function o(){if(u)return u;var t=g.nativeExtensions&&g.nativeExtensions.SourceCode;return t||(t=r(d[0]).default),u=t.getConstants().scriptURL}function f(){if(void 0===n){var t=o(),s=t&&t.match(/^https?:\/\/.*?\//);n=s?s[0]:null}return n}function c(t){if(t){if(t.startsWith('assets://'))return null;(t=t.substring(0,t.lastIndexOf('/')+1)).includes('://')||(t='file://'+t)}return t}m.exports=function(n){if('object'==typeof n)return n;var u=r(d[1]).getAssetByID(n);if(!u)return null;var l=new(r(d[2]))(f(),(void 0===s&&(s=c(o())),s),u);return t?t(l):l.defaultAsset()},m.exports.pickScale=r(d[3]).pickScale,m.exports.setCustomSourceTransformer=function(n){t=n}},155,[156,157,158,159]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in n)if("default"!==c&&Object.prototype.hasOwnProperty.call(n,c)){var p=l?Object.getOwnPropertyDescriptor(n,c):null;p&&(p.get||p.set)?Object.defineProperty(f,c,p):f[c]=n[c]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).getEnforcing('SourceCode'),o=null,u={getConstants:function(){return null==o&&(o=n.getConstants()),o}};e.default=u},156,[21]); -__d(function(g,r,i,a,m,e,d){'use strict';var t=[];m.exports={registerAsset:function(s){return t.push(s)},getAssetByID:function(s){return t[s-1]}}},157,[]); -__d(function(g,r,i,a,m,e,d){'use strict';function t(t){var s=r(d[0]).pickScale(t.scales,r(d[1]).get()),n=1===s?'':'@'+s+'x';return r(d[2]).getBasePath(t)+'/'+t.name+n+'.'+t.type}var s=(function(){function s(t,n,u){r(d[3])(this,s),this.serverUrl=t,this.jsbundleUrl=n,this.asset=u}return r(d[4])(s,[{key:"isLoadedFromServer",value:function(){return!!this.serverUrl}},{key:"isLoadedFromFileSystem",value:function(){return!(!this.jsbundleUrl||!this.jsbundleUrl.startsWith('file://'))}},{key:"defaultAsset",value:function(){return this.isLoadedFromServer()?this.assetServerURL():this.isLoadedFromFileSystem()?this.drawableFolderInBundle():this.resourceIdentifierWithoutScale()}},{key:"assetServerURL",value:function(){return r(d[5])(!!this.serverUrl,'need server to load from'),this.fromSource(this.serverUrl+t(this.asset)+"?platform=android&hash="+this.asset.hash)}},{key:"scaledAssetPath",value:function(){return this.fromSource(t(this.asset))}},{key:"scaledAssetURLNearBundle",value:function(){var s=this.jsbundleUrl||'file://';return this.fromSource(s+t(this.asset).replace(/\.\.\//g,'_'))}},{key:"resourceIdentifierWithoutScale",value:function(){return r(d[5])(!0,'resource identifiers work on Android'),this.fromSource(r(d[2]).getAndroidResourceIdentifier(this.asset))}},{key:"drawableFolderInBundle",value:function(){var t,s,n=this.jsbundleUrl||'file://';return this.fromSource(n+(t=this.asset,s=r(d[0]).pickScale(t.scales,r(d[1]).get()),r(d[2]).getAndroidResourceFolderName(t,s)+'/'+r(d[2]).getAndroidResourceIdentifier(t)+'.'+t.type))}},{key:"fromSource",value:function(t){return{__packager_asset:!0,width:this.asset.width,height:this.asset.height,uri:t,scale:r(d[0]).pickScale(this.asset.scales,r(d[1]).get())}}}]),s})();s.pickScale=r(d[0]).pickScale,m.exports=s},158,[159,160,163,7,8,18]); -__d(function(g,r,_i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.getUrlCacheBreaker=function(){if(null==n)return'';return n},e.pickScale=function(n,u){null==u&&(u=t.default.get());for(var l=0;l=u)return n[l];return n[n.length-1]||1},e.setUrlCacheBreaker=function(t){n=t};var n,t=r(d[0])(r(d[1]))},159,[3,160]); -__d(function(g,r,i,a,m,e,d){'use strict';var t=(function(){function t(){r(d[0])(this,t)}return r(d[1])(t,null,[{key:"get",value:function(){return r(d[2]).get('window').scale}},{key:"getFontScale",value:function(){return r(d[2]).get('window').fontScale||t.get()}},{key:"getPixelSizeForLayoutSize",value:function(n){return Math.round(n*t.get())}},{key:"roundToNearestPixel",value:function(n){var u=t.get();return Math.round(n*u)/u}},{key:"startDetecting",value:function(){}}]),t})();m.exports=t},160,[7,8,161]); -__d(function(g,r,i,a,m,e,d){var n,t=r(d[0])(r(d[1])),s=r(d[0])(r(d[2])),o=r(d[0])(r(d[3])),l=r(d[0])(r(d[4])),c=r(d[0])(r(d[5])),u=r(d[0])(r(d[6])),f=new o.default,v=!1,h=(function(){function o(){(0,t.default)(this,o)}return(0,s.default)(o,null,[{key:"get",value:function(t){return(0,u.default)(n[t],'No dimension set for key '+t),n[t]}},{key:"set",value:function(t){var s=t.screen,o=t.window,l=t.windowPhysicalPixels;l&&(o={width:l.width/l.scale,height:l.height/l.scale,scale:l.scale,fontScale:l.fontScale});var c=t.screenPhysicalPixels;c?s={width:c.width/c.scale,height:c.height/c.scale,scale:c.scale,fontScale:c.fontScale}:null==s&&(s=o),n={window:o,screen:s},v?f.emit('change',n):v=!0}},{key:"addEventListener",value:function(n,t){return(0,u.default)('change'===n,'Trying to subscribe to unknown event: "%s"',n),f.addListener(n,t)}},{key:"removeEventListener",value:function(n,t){(0,u.default)('change'===n,'Trying to remove listener for unknown event: "%s"',n),f.removeListener(n,t)}}]),o})(),w=g.nativeExtensions&&g.nativeExtensions.DeviceInfo&&g.nativeExtensions.DeviceInfo.Dimensions;w||(l.default.addListener('didUpdateDimensions',function(n){h.set(n)}),w=c.default.getConstants().Dimensions),h.set(w),m.exports=h},161,[3,7,8,5,4,162,18]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in n)if("default"!==c&&Object.prototype.hasOwnProperty.call(n,c)){var p=l?Object.getOwnPropertyDescriptor(n,c):null;p&&(p.get||p.set)?Object.defineProperty(f,c,p):f[c]=n[c]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).getEnforcing('DeviceInfo'),o=null,u={getConstants:function(){return null==o&&(o=n.getConstants()),o}};e.default=u},162,[21]); -__d(function(g,r,i,a,m,e,d){'use strict';var t={.75:'ldpi',1:'mdpi',1.5:'hdpi',2:'xhdpi',3:'xxhdpi',4:'xxxhdpi'};function n(n){if(n.toString()in t)return t[n.toString()];throw new Error('no such scale '+n.toString())}var o=new Set(['gif','jpeg','jpg','png','svg','webp','xml']);function s(t){var n=t.httpServerLocation;return n.startsWith('/')?n.substr(1):n}m.exports={getAndroidResourceFolderName:function(s,u){if(!o.has(s.type))return'raw';var c=n(u);if(!c)throw new Error("Don't know which android drawable suffix to use for scale: "+u+'\nAsset: '+JSON.stringify(s,null,'\t')+'\nPossible scales are:'+JSON.stringify(t,null,'\t'));return'drawable-'+c},getAndroidResourceIdentifier:function(t){return(s(t)+'/'+t.name).toLowerCase().replace(/\//g,'_').replace(/([^a-z0-9_])/g,'').replace(/^assets_/,'')},getBasePath:s}},163,[]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=function(t,n){for(var o=0,u=['validAttributes','bubblingEventTypes','directEventTypes'];o0){var l,v=null!=(l=n.uiViewClassName)?l:t.uiViewClassName;console.error("'"+v+"' has a view config that does not match native. '"+s+"' is missing: "+c.join(', '))}}},e.getConfigWithoutViewProps=function(n,f){if(!n[f])return{};return Object.keys(n[f]).filter(function(n){return!t.default[f][n]}).reduce(function(t,o){return t[o]=n[f][o],t},{})},e.lefthandObjectDiff=f,e.stringifyViewConfig=function(t){return JSON.stringify(t,function(t,n){return'function'==typeof n?"\u0192 "+n.name:n},2)};var t=r(d[0])(r(d[1])),n=['transform','hitSlop'];function f(t,o){var u={};function s(t,n,o){if(typeof t==typeof n||null==t)if('object'!=typeof t)t===n||(u[o]=n);else{var s=f(t,n);Object.keys(s).length>1&&(u[o]=s)}else u[o]=n}for(var c in t)n.includes(c)||(o?t.hasOwnProperty(c)&&s(t[c],o[c],c):u[c]={});return u}},164,[3,139]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.createViewConfig=function(t){return{uiViewClassName:t.uiViewClassName,Commands:{},bubblingEventTypes:u(n.default.bubblingEventTypes,t.bubblingEventTypes),directEventTypes:u(n.default.directEventTypes,t.directEventTypes),validAttributes:u(n.default.validAttributes,t.validAttributes)}};var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2]));function u(n,u){var l;return null==n||null==u?null!=(l=null!=n?n:u)?l:{}:(0,t.default)({},n,u)}},165,[3,29,139]); -__d(function(g,r,i,a,m,e,d){'use strict';var n;m.exports=function t(o,u){var f=arguments.length>2&&void 0!==arguments[2]?arguments[2]:-1,s=arguments.length>3?arguments[3]:void 0,c='number'==typeof f?s:f,l='number'==typeof f?f:-1;if(0===l)return!0;if(o===u)return!1;if('function'==typeof o&&'function'==typeof u){var v=null==c?void 0:c.unsafelyIgnoreFunctions;return null==v&&(!n||!n.onDifferentFunctionsIgnored||c&&'unsafelyIgnoreFunctions'in c||n.onDifferentFunctionsIgnored(o.name,u.name),v=!0),!v}if('object'!=typeof o||null===o)return o!==u;if('object'!=typeof u||null===u)return!0;if(o.constructor!==u.constructor)return!0;if(Array.isArray(o)){var y=o.length;if(u.length!==y)return!0;for(var p=0;p=w},r=function(){},_e.unstable_forceFrameRate=function(e){0>e||125>>1,a=e[r];if(!(void 0!==a&&0x(l,t))void 0!==s&&0>x(s,l)?(e[r]=s,e[u]=t,r=u):(e[r]=l,e[o]=t,r=o);else{if(!(void 0!==s&&0>x(s,t)))break e;e[r]=s,e[u]=t,r=u}}}return n}return null}function x(e,n){var t=e.sortIndex-n.sortIndex;return 0!==t?t:e.id-n.id}var P=[],F=[],I=1,M=null,C=3,j=!1,A=!1,L=!1;function q(e){for(var n=T(F);null!==n;){if(null===n.callback)g(F);else{if(!(n.startTime<=e))break;g(F),n.sortIndex=n.expirationTime,k(P,n)}n=T(F)}}function R(t){if(L=!1,q(t),!A)if(null!==T(P))A=!0,e(Y);else{var r=T(F);null!==r&&n(R,r.startTime-t)}}function Y(e,r){A=!1,L&&(L=!1,t()),j=!0;var a=C;try{for(q(r),M=T(P);null!==M&&(!(M.expirationTime>r)||e&&!_e.unstable_shouldYield());){var o=M.callback;if("function"==typeof o){M.callback=null,C=M.priorityLevel;var l=o(M.expirationTime<=r);r=_e.unstable_now(),"function"==typeof l?M.callback=l:M===T(P)&&g(P),q(r)}else g(P);M=T(P)}if(null!==M)var u=!0;else{var s=T(F);null!==s&&n(R,s.startTime-r),u=!1}return u}finally{M=null,C=a,j=!1}}var E=r;_e.unstable_IdlePriority=5,_e.unstable_ImmediatePriority=1,_e.unstable_LowPriority=4,_e.unstable_NormalPriority=3,_e.unstable_Profiling=null,_e.unstable_UserBlockingPriority=2,_e.unstable_cancelCallback=function(e){e.callback=null},_e.unstable_continueExecution=function(){A||j||(A=!0,e(Y))},_e.unstable_getCurrentPriorityLevel=function(){return C},_e.unstable_getFirstCallbackNode=function(){return T(P)},_e.unstable_next=function(e){switch(C){case 1:case 2:case 3:var n=3;break;default:n=C}var t=C;C=n;try{return e()}finally{C=t}},_e.unstable_pauseExecution=function(){},_e.unstable_requestPaint=E,_e.unstable_runWithPriority=function(e,n){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var t=C;C=e;try{return n()}finally{C=t}},_e.unstable_scheduleCallback=function(r,a,o){var l=_e.unstable_now();switch("object"==typeof o&&null!==o?o="number"==typeof(o=o.delay)&&0l?(r.sortIndex=o,k(F,r),null===T(P)&&r===T(F)&&(L?t():L=!0,n(R,o-l))):(r.sortIndex=u,k(P,r),A||j||(A=!0,e(Y))),r},_e.unstable_wrapCallback=function(e){var n=C;return function(){var t=C;C=n;try{return e.apply(this,arguments)}finally{C=t}}}},171,[]); -__d(function(g,r,i,a,m,e,d){'use strict';var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),o=(function(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var o=c(n);if(o&&o.has(t))return o.get(t);var l={},u=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var f in t)if("default"!==f&&Object.prototype.hasOwnProperty.call(t,f)){var s=u?Object.getOwnPropertyDescriptor(t,f):null;s&&(s.get||s.set)?Object.defineProperty(l,f,s):l[f]=t[f]}l.default=t,o&&o.set(t,l);return l})(r(d[3])),l=r(d[0])(r(d[4])),u=r(d[0])(r(d[5])),f=r(d[0])(r(d[6])),s=["animating","color","hidesWhenStopped","onLayout","size","style"];function c(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,o=new WeakMap;return(c=function(t){return t?o:n})(t)}var p='android'===l.default.OS?r(d[7]):r(d[8]).default,y=o.forwardRef(function(c,y){var v,O,w=c.animating,b=void 0===w||w,S=c.color,j=void 0===S?'ios'===l.default.OS?"#999999":null:S,z=c.hidesWhenStopped,W=void 0===z||z,k=c.onLayout,L=c.size,P=void 0===L?'small':L,M=c.style,_=(0,n.default)(c,s);switch(P){case'small':v=h.sizeSmall,O='small';break;case'large':v=h.sizeLarge,O='large';break;default:v={height:P,width:P}}var E=(0,t.default)({animating:b,color:j,hidesWhenStopped:W},_,{ref:y,style:v,size:O});return o.createElement(f.default,{onLayout:k,style:u.default.compose(h.container,M)},'android'===l.default.OS?o.createElement(p,(0,t.default)({},E,{styleAttr:'Normal',indeterminate:!0})):o.createElement(p,E))});y.displayName='ActivityIndicator';var h=u.default.create({container:{alignItems:'center',justifyContent:'center'},sizeSmall:{width:20,height:20},sizeLarge:{width:36,height:36}});m.exports=y},172,[3,29,103,129,19,173,174,177,182]); -__d(function(g,r,i,a,m,e,d){'use strict';var t=r(d[0]).roundToNearestPixel(.4);0===t&&(t=1/r(d[0]).get());var o={position:'absolute',left:0,right:0,top:0,bottom:0};m.exports={hairlineWidth:t,absoluteFill:o,absoluteFillObject:o,compose:function(t,o){return null!=t&&null!=o?[t,o]:null!=t?t:o},flatten:r(d[1]),setStyleAttributePreprocessor:function(t,o){var l;if(!0===r(d[2])[t])l={process:o};else{if('object'!=typeof r(d[2])[t])return void console.error(t+" is not a valid style attribute");l=r(d[3])({},r(d[2])[t],{process:o})}r(d[2])[t]=l},create:function(t){return t}}},173,[160,168,152,29]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),f=r(d[0])(r(d[3])),u=(function(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var f=o(n);if(f&&f.has(t))return f.get(t);var u={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in t)if("default"!==c&&Object.prototype.hasOwnProperty.call(t,c)){var p=l?Object.getOwnPropertyDescriptor(t,c):null;p&&(p.get||p.set)?Object.defineProperty(u,c,p):u[c]=t[c]}u.default=t,f&&f.set(t,u);return u})(r(d[4]));function o(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,f=new WeakMap;return(o=function(t){return t?f:n})(t)}var l=u.forwardRef(function(o,l){return u.createElement(f.default.Provider,{value:!1},u.createElement(n.default,(0,t.default)({},o,{ref:l})))});l.displayName='View',m.exports=l},174,[3,29,175,176,129]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=e.Commands=void 0;var t=l(r(d[0])),n=r(d[1])(r(d[2])),o=r(d[1])(r(d[3])),u=r(d[1])(r(d[4]));l(r(d[5]));function f(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,o=new WeakMap;return(f=function(t){return t?o:n})(t)}function l(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var o=f(n);if(o&&o.has(t))return o.get(t);var u={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var p in t)if("default"!==p&&Object.prototype.hasOwnProperty.call(t,p)){var s=l?Object.getOwnPropertyDescriptor(t,p):null;s&&(s.get||s.set)?Object.defineProperty(u,p,s):u[p]=t[p]}return u.default=t,o&&o.set(t,u),u}var p=t.get('RCTView',function(){return'android'===n.default.OS?u.default:{uiViewClassName:'RCTView'}}),s=(0,o.default)({supportedCommands:['hotspotUpdate','setPressed']});e.Commands=s;var c=p;e.default=c},175,[150,3,19,137,140,129]); -__d(function(g,r,i,a,m,e,d){'use strict';var t=r(d[0]).createContext(!1);m.exports=t},176,[129]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),f=r(d[0])(r(d[3])),l=["styleAttr","indeterminate","animating"],o=r(d[4]),u=o.forwardRef(function(u,v){var s=u.styleAttr,c=void 0===s?'Normal':s,y=u.indeterminate,A=void 0===y||y,_=u.animating,p=void 0===_||_,w=(0,n.default)(u,l);return o.createElement(f.default,(0,t.default)({styleAttr:c,indeterminate:A,animating:p},w,{ref:v}))});m.exports=u},177,[3,29,103,178,129]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var t=(0,r(d[0])(r(d[1])).default)('AndroidProgressBar',{interfaceOnly:!0});e.default=t},178,[3,179]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=r(d[0])(r(d[1])),o=r(d[0])(r(d[2]));var t=function(t,p){var l=p&&null!=p.paperComponentName?p.paperComponentName:t;if(null!=p&&null!=p.paperComponentNameDeprecated)if(o.default.getViewManagerConfig(t))l=t;else{var u;if(null==p.paperComponentNameDeprecated||!o.default.getViewManagerConfig(p.paperComponentNameDeprecated))throw new Error("Failed to find native component for either "+t+" or "+(null!=(u=p.paperComponentNameDeprecated)?u:'(unknown)'));l=p.paperComponentNameDeprecated}return(0,n.default)(l)};e.default=t},179,[3,180,43]); -__d(function(g,r,i,a,m,e,d){'use strict';m.exports=function(n){return r(d[0])(n,function(){return r(d[1])(n)})}},180,[181,151]); -__d(function(g,r,i,a,m,e,d){'use strict';var t=r(d[0]).ReactNativeViewConfigRegistry.register;m.exports=function(n,s){return t(n,s)}},181,[132]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var t=(0,r(d[0])(r(d[1])).default)('ActivityIndicatorView',{paperComponentName:'RCTActivityIndicatorView'});e.default=t},182,[3,179]); -__d(function(g,r,i,a,m,_e,d){'use strict';var t=r(d[0])(r(d[1])),e=r(d[0])(r(d[2])),o=r(d[0])(r(d[3])),s=r(d[0])(r(d[4])),n=r(d[0])(r(d[5])),c=r(d[0])(r(d[6])),l=(function(t,e){if(!e&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var o=x(e);if(o&&o.has(t))return o.get(t);var s={},n=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in t)if("default"!==c&&Object.prototype.hasOwnProperty.call(t,c)){var l=n?Object.getOwnPropertyDescriptor(t,c):null;l&&(l.get||l.set)?Object.defineProperty(s,c,l):s[c]=t[c]}s.default=t,o&&o.set(t,s);return s})(r(d[7])),u=r(d[0])(r(d[8])),f=r(d[0])(r(d[9])),p=r(d[0])(r(d[10])),b=r(d[0])(r(d[11])),y=r(d[0])(r(d[12])),h=r(d[0])(r(d[13])),v=r(d[0])(r(d[14]));function x(t){if("function"!=typeof WeakMap)return null;var e=new WeakMap,o=new WeakMap;return(x=function(t){return t?o:e})(t)}function F(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var D=(function(f){(0,s.default)(w,f);var x,D,S=(x=w,D=F(),function(){var t,e=(0,c.default)(x);if(D){var o=(0,c.default)(this).constructor;t=Reflect.construct(e,arguments,o)}else t=e.apply(this,arguments);return(0,n.default)(this,t)});function w(){return(0,e.default)(this,w),S.apply(this,arguments)}return(0,o.default)(w,[{key:"render",value:function(){var e,o,s=this.props,n=s.accessibilityLabel,c=s.color,f=s.onPress,x=s.touchSoundDisabled,F=s.title,D=s.hasTVPreferredFocus,S=s.nextFocusDown,w=s.nextFocusForward,P=s.nextFocusLeft,R=s.nextFocusRight,A=s.nextFocusUp,k=s.testID,j=s.accessible,C=s.accessibilityActions,L=s.onAccessibilityAction,M=[O.button],W=[O.text];c&&('ios'===u.default.OS?W.push({color:c}):M.push({backgroundColor:c}));var _=null!=this.props.disabled?this.props.disabled:null==(e=this.props.accessibilityState)?void 0:e.disabled,B=_!==(null==(o=this.props.accessibilityState)?void 0:o.disabled)?(0,t.default)({},this.props.accessibilityState,{disabled:_}):this.props.accessibilityState;_&&(M.push(O.buttonDisabled),W.push(O.textDisabled)),(0,v.default)('string'==typeof F,'The title prop of a Button must be a string');var E='android'===u.default.OS?F.toUpperCase():F,T='android'===u.default.OS?b.default:y.default;return l.createElement(T,{accessible:j,accessibilityActions:C,onAccessibilityAction:L,accessibilityLabel:n,accessibilityRole:"button",accessibilityState:B,hasTVPreferredFocus:D,nextFocusDown:S,nextFocusForward:w,nextFocusLeft:P,nextFocusRight:R,nextFocusUp:A,testID:k,disabled:_,onPress:f,touchSoundDisabled:x},l.createElement(h.default,{style:M},l.createElement(p.default,{style:W,disabled:_},E)))}}]),w})(l.Component),O=f.default.create({button:u.default.select({ios:{},android:{elevation:4,backgroundColor:'#2196F3',borderRadius:2}}),text:(0,t.default)({textAlign:'center',margin:8},u.default.select({ios:{color:'#007AFF',fontSize:18},android:{color:'white',fontWeight:'500'}})),buttonDisabled:u.default.select({ios:{},android:{elevation:0,backgroundColor:'#dfdfdf'}}),textDisabled:u.default.select({ios:{color:'#cdcdcd'},android:{color:'#a1a1a1'}})});m.exports=D},183,[3,29,7,8,10,12,15,129,19,173,184,209,210,174,18]); -__d(function(g,r,i,a,m,e,d){var n=r(d[0])(r(d[1])),o=r(d[0])(r(d[2])),t=r(d[0])(r(d[3])),s=r(d[0])(r(d[4])),l=(v(r(d[5])),r(d[0])(r(d[6]))),u=(r(d[0])(r(d[7])),r(d[0])(r(d[8]))),p=r(d[0])(r(d[9])),f=v(r(d[10])),c=(r(d[0])(r(d[11])),["accessible","allowFontScaling","ellipsizeMode","onLongPress","onPress","onPressIn","onPressOut","onResponderGrant","onResponderMove","onResponderRelease","onResponderTerminate","onResponderTerminationRequest","onStartShouldSetResponder","pressRetentionOffset","suppressHighlighting"]);function R(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,t=new WeakMap;return(R=function(n){return n?t:o})(n)}function v(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var t=R(o);if(t&&t.has(n))return t.get(n);var s={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var u in n)if("default"!==u&&Object.prototype.hasOwnProperty.call(n,u)){var p=l?Object.getOwnPropertyDescriptor(n,u):null;p&&(p.get||p.set)?Object.defineProperty(s,u,p):s[u]=n[u]}return s.default=n,t&&t.set(n,s),s}var P=f.forwardRef(function(s,R){var v=s.accessible,P=s.allowFontScaling,b=s.ellipsizeMode,O=s.onLongPress,T=s.onPress,h=s.onPressIn,y=s.onPressOut,M=s.onResponderGrant,w=s.onResponderMove,E=s.onResponderRelease,C=s.onResponderTerminate,L=s.onResponderTerminationRequest,j=s.onStartShouldSetResponder,x=s.pressRetentionOffset,D=s.suppressHighlighting,_=(0,t.default)(s,c),q=(0,f.useState)(!1),G=(0,o.default)(q,2),H=G[0],k=G[1],z=(null!=T||null!=O||null!=j)&&!0!==_.disabled,F=S(z),I=(0,f.useMemo)(function(){return F?{disabled:!z,pressRectOffset:x,onLongPress:O,onPress:T,onPressIn:function(n){k(!D),null==h||h(n)},onPressOut:function(n){k(!1),null==y||y(n)},onResponderTerminationRequest_DEPRECATED:L,onStartShouldSetResponder_DEPRECATED:j}:null},[F,z,x,O,T,h,y,L,j,D]),N=(0,l.default)(I),W=(0,f.useMemo)(function(){return null==N?null:{onResponderGrant:function(n){N.onResponderGrant(n),null!=M&&M(n)},onResponderMove:function(n){N.onResponderMove(n),null!=w&&w(n)},onResponderRelease:function(n){N.onResponderRelease(n),null!=E&&E(n)},onResponderTerminate:function(n){N.onResponderTerminate(n),null!=C&&C(n)},onResponderTerminationRequest:N.onResponderTerminationRequest,onStartShouldSetResponder:N.onStartShouldSetResponder}},[N,M,w,E,C]),A=null==_.selectionColor?null:(0,u.default)(_.selectionColor),V=_.style,B=_.numberOfLines;return null==B||B>=0||(console.error("'numberOfLines' in must be a non-negative number, received: "+B+". The value will be set to 0."),B=0),(0,f.useContext)(p.default)?f.createElement(r(d[12]).NativeVirtualText,(0,n.default)({},_,W,{isHighlighted:H,numberOfLines:B,selectionColor:A,style:V,ref:R})):f.createElement(p.default.Provider,{value:!0},f.createElement(r(d[12]).NativeText,(0,n.default)({},_,W,{accessible:!1!==v,allowFontScaling:!1!==P,ellipsizeMode:null!=b?b:'tail',isHighlighted:H,numberOfLines:B,selectionColor:A,style:V,ref:R})))});function S(n){var t=(0,f.useState)(n),s=(0,o.default)(t,2),l=s[0],u=s[1];return!l&&n&&u(n),l}P.displayName='Text',P.propTypes=s.default,m.exports=P},184,[3,29,23,103,185,199,200,173,141,176,129,18,207]); -__d(function(g,r,i,a,m,e,d){'use strict';var o=r(d[0])(r(d[1]));m.exports={ellipsizeMode:r(d[2]).oneOf(['head','middle','tail','clip']),numberOfLines:r(d[2]).number,textBreakStrategy:r(d[2]).oneOf(['simple','highQuality','balanced']),onLayout:r(d[2]).func,onPress:r(d[2]).func,onLongPress:r(d[2]).func,pressRetentionOffset:r(d[3]),selectable:r(d[2]).bool,selectionColor:r(d[4]),suppressHighlighting:r(d[2]).bool,style:o,testID:r(d[2]).string,nativeID:r(d[2]).string,allowFontScaling:r(d[2]).bool,maxFontSizeMultiplier:r(d[2]).number,accessible:r(d[2]).bool,adjustsFontSizeToFit:r(d[2]).bool,minimumFontScale:r(d[2]).number,disabled:r(d[2]).bool,dataDetectorType:r(d[2]).oneOf(['phoneNumber','link','email','none','all'])}},185,[186,188,191,198,195]); -__d(function(g,r,i,a,m,e,d){'use strict';m.exports=function(n){var t=r(d[0])(n);return function(n,o,c,u){var f=n;n[o]&&((f={})[o]=r(d[1])(n[o]));for(var v=arguments.length,p=new Array(v>4?v-4:0),s=4;s5?v-5:0),j=5;j4?s-4:0),p=4;p3?f-3:0),p=3;p0?t._pressDelayTimeout=setTimeout(function(){t._receiveSignal('DELAY',E)},n):t._receiveSignal('DELAY',E);var R=I(t._config.delayLongPress,10,500-n);t._longPressDelayTimeout=setTimeout(function(){t._handleLongPress(E)},R+n)},onResponderMove:function(E){var n=t._config.onPressMove;null!=n&&n(E);var R=t._responderRegion;if(null!=R){var _=A(E);if(null==_)return t._cancelLongPressDelayTimeout(),void t._receiveSignal('LEAVE_PRESS_RECT',E);if(null!=t._touchActivatePosition){var o=t._touchActivatePosition.pageX-_.pageX,l=t._touchActivatePosition.pageY-_.pageY;Math.hypot(o,l)>10&&t._cancelLongPressDelayTimeout()}t._isTouchWithinResponderRegion(_,R)?t._receiveSignal('ENTER_PRESS_RECT',E):(t._cancelLongPressDelayTimeout(),t._receiveSignal('LEAVE_PRESS_RECT',E))}},onResponderRelease:function(E){t._receiveSignal('RESPONDER_RELEASE',E)},onResponderTerminate:function(E){t._receiveSignal('RESPONDER_TERMINATED',E)},onResponderTerminationRequest:function(){var E=t._config.cancelable;if(null==E){var n=t._config.onResponderTerminationRequest_DEPRECATED;return null==n||n()}return E},onClick:function(E){var n=t._config,R=n.onPress,_=n.disabled;null!=R&&!0!==_&&R(E)}},_='ios'===l.default.OS||'android'===l.default.OS?null:{onMouseEnter:function(E){if((0,r(d[10]).isHoverEnabled)()){t._isHovered=!0,t._cancelHoverOutDelayTimeout();var n=t._config.onHoverIn;if(null!=n){var R=I(t._config.delayHoverIn);R>0?(E.persist(),t._hoverInDelayTimeout=setTimeout(function(){n(E)},R)):n(E)}}},onMouseLeave:function(E){if(t._isHovered){t._isHovered=!1,t._cancelHoverInDelayTimeout();var n=t._config.onHoverOut;if(null!=n){var R=I(t._config.delayHoverOut);R>0?(E.persist(),t._hoverInDelayTimeout=setTimeout(function(){n(E)},R)):n(E)}}}};return(0,E.default)({},n,R,_)}},{key:"_receiveSignal",value:function(E,t){var n,_=this._touchState,l=null==(n=S[_])?void 0:n[E];null==this._responderID&&'RESPONDER_RELEASE'===E||((0,R.default)(null!=l&&'ERROR'!==l,'Pressability: Invalid signal `%s` for state `%s` on responder: %s',E,_,'number'==typeof this._responderID?this._responderID:'<>'),_!==l&&(null!=t.nativeEvent.timestamp&&o.default.emitEvent(function(){return{signal:E,touchDelayMs:Date.now()-t.nativeEvent.timestamp}}),this._performTransitionSideEffects(_,l,E,t),this._touchState=l))}},{key:"_performTransitionSideEffects",value:function(E,t,n,R){c(n)&&(this._touchActivatePosition=null,this._cancelLongPressDelayTimeout());var o='NOT_RESPONDER'===E&&'RESPONDER_INACTIVE_PRESS_IN'===t,u=!P(E)&&P(t);if((o||u)&&this._measureResponderRegion(),O(E)&&'LONG_PRESS_DETECTED'===n){var s=this._config.onLongPress;null!=s&&s(R)}var S=T(E),D=T(t);if(!S&&D?this._activate(R):S&&!D&&this._deactivate(R),O(E)&&'RESPONDER_RELEASE'===n){D||S||(this._activate(R),this._deactivate(R));var N=this._config,h=N.onLongPress,f=N.onPress,v=N.android_disableSound;if(null!=f)null!=h&&'RESPONDER_ACTIVE_LONG_PRESS_IN'===E&&this._shouldLongPressCancelPress()||('android'===l.default.OS&&!0!==v&&_.default.playTouchSound(),f(R))}this._cancelPressDelayTimeout()}},{key:"_activate",value:function(E){var t=this._config.onPressIn,n=A(E),R=n.pageX,_=n.pageY;this._touchActivatePosition={pageX:R,pageY:_},this._touchActivateTime=Date.now(),null!=t&&t(E)}},{key:"_deactivate",value:function(E){var t=this._config.onPressOut;if(null!=t){var n,R=I(this._config.minPressDuration,0,130),_=Date.now()-(null!=(n=this._touchActivateTime)?n:0),o=Math.max(R-_,I(this._config.delayPressOut));o>0?(E.persist(),this._pressOutDelayTimeout=setTimeout(function(){t(E)},o)):t(E)}this._touchActivateTime=null}},{key:"_measureResponderRegion",value:function(){null!=this._responderID&&('number'==typeof this._responderID?u.default.measure(this._responderID,this._measureCallback):this._responderID.measure(this._measureCallback))}},{key:"_isTouchWithinResponderRegion",value:function(E,t){var n,R,_,o,l=(0,r(d[11]).normalizeRect)(this._config.hitSlop),u=(0,r(d[11]).normalizeRect)(this._config.pressRectOffset),s=t.bottom,S=t.left,T=t.right,P=t.top;return null!=l&&(null!=l.bottom&&(s+=l.bottom),null!=l.left&&(S-=l.left),null!=l.right&&(T+=l.right),null!=l.top&&(P-=l.top)),s+=null!=(n=null==u?void 0:u.bottom)?n:D,S-=null!=(R=null==u?void 0:u.left)?R:N,T+=null!=(_=null==u?void 0:u.right)?_:h,P-=null!=(o=null==u?void 0:u.top)?o:f,E.pageX>S&&E.pageXP&&E.pageY1&&void 0!==arguments[1]?arguments[1]:0,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0;return Math.max(t,null!=E?E:n)}e.default=v;var A=function(E){var t=E.nativeEvent,n=t.changedTouches,R=t.touches;return null!=R&&R.length>0?R[0]:null!=n&&n.length>0?n[0]:E.nativeEvent}},201,[3,29,7,8,18,202,204,19,43,129,205,206]); -__d(function(g,r,i,a,m,e,d){var u=r(d[0])(r(d[1])),o={playTouchSound:function(){u.default&&u.default.playTouchSound()}};m.exports=o},202,[3,203]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in n)if("default"!==l&&Object.prototype.hasOwnProperty.call(n,l)){var p=c?Object.getOwnPropertyDescriptor(n,l):null;p&&(p.get||p.set)?Object.defineProperty(f,l,p):f[l]=n[l]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).get('SoundManager');e.default=n},203,[21]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),s=new((function(){function s(){(0,t.default)(this,s),this._listeners=[]}return(0,n.default)(s,[{key:"addListener",value:function(t){this._listeners.push(t)}},{key:"removeListener",value:function(t){var n=this._listeners.indexOf(t);n>-1&&this._listeners.splice(n,1)}},{key:"emitEvent",value:function(t){if(0!==this._listeners.length){var n=t();this._listeners.forEach(function(t){return t(n)})}}}]),s})());e.default=s},204,[3,7,8]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.isHoverEnabled=function(){return n};var n=!1;if('web'===r(d[0])(r(d[1])).default.OS&&Boolean('undefined'!=typeof window&&window.document&&window.document.createElement)){var t=0,o=function(){t=Date.now(),n&&(n=!1)};document.addEventListener('touchstart',o,!0),document.addEventListener('touchmove',o,!0),document.addEventListener('mousemove',function(){n||Date.now()-t<1e3||(n=!0)},!0)}},205,[3,19]); -__d(function(g,r,i,a,m,e,d){function t(t){return{bottom:t,left:t,right:t,top:t}}Object.defineProperty(e,"__esModule",{value:!0}),e.createSquare=t,e.normalizeRect=function(n){return'number'==typeof n?t(n):n}},206,[]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.NativeVirtualText=e.NativeText=void 0;var t=r(d[0])(r(d[1])),l=r(d[0])(r(d[2])),n=r(d[0])(r(d[3])),o=r(d[0])(r(d[4])),u=(0,o.default)('RCTText',function(){return{validAttributes:(0,t.default)({},l.default.UIView,{isHighlighted:!0,numberOfLines:!0,ellipsizeMode:!0,allowFontScaling:!0,maxFontSizeMultiplier:!0,disabled:!0,selectable:!0,selectionColor:!0,adjustsFontSizeToFit:!0,minimumFontScale:!0,textBreakStrategy:!0,onTextLayout:!0,onInlineViewLayout:!0,dataDetectorType:!0,android_hyphenationFrequency:!0}),directEventTypes:{topTextLayout:{registrationName:'onTextLayout'},topInlineViewLayout:{registrationName:'onInlineViewLayout'}},uiViewClassName:'RCTText'}});e.NativeText=u;var s=g.RN$Bridgeless||n.default.hasViewManagerConfig('RCTVirtualText')?(0,o.default)('RCTVirtualText',function(){return{validAttributes:(0,t.default)({},l.default.UIView,{isHighlighted:!0,maxFontSizeMultiplier:!0}),uiViewClassName:'RCTVirtualText'}}):u;e.NativeVirtualText=s},207,[3,29,208,43,181]); -__d(function(g,r,i,a,m,e,d){'use strict';var s=r(d[0])(r(d[1])),t={pointerEvents:!0,accessible:!0,accessibilityActions:!0,accessibilityLabel:!0,accessibilityLiveRegion:!0,accessibilityRole:!0,accessibilityState:!0,accessibilityValue:!0,accessibilityHint:!0,importantForAccessibility:!0,nativeID:!0,testID:!0,renderToHardwareTextureAndroid:!0,shouldRasterizeIOS:!0,onLayout:!0,onAccessibilityAction:!0,onAccessibilityTap:!0,onMagicTap:!0,onAccessibilityEscape:!0,collapsable:!0,needsOffscreenAlphaCompositing:!0,style:r(d[0])(r(d[2])).default},c={UIView:t,RCTView:(0,s.default)({},t,{removeClippedSubviews:!0})};m.exports=c},208,[3,29,152]); -__d(function(g,r,i,a,m,_e,d){var e=r(d[0])(r(d[1])),t=r(d[0])(r(d[2])),s=r(d[0])(r(d[3])),o=r(d[0])(r(d[4])),n=r(d[0])(r(d[5])),l=r(d[0])(r(d[6])),c=r(d[0])(r(d[7])),p=r(d[0])(r(d[8])),u=r(d[0])(r(d[9])),f=r(d[0])(r(d[10])),h=(r(d[0])(r(d[11])),r(d[0])(r(d[12]))),b=(function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var s=P(t);if(s&&s.has(e))return s.get(e);var o={},n=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in e)if("default"!==l&&Object.prototype.hasOwnProperty.call(e,l)){var c=n?Object.getOwnPropertyDescriptor(e,l):null;c&&(c.get||c.set)?Object.defineProperty(o,l,c):o[l]=e[l]}o.default=e,s&&s.set(e,o);return o})(r(d[13])),y=r(d[0])(r(d[14])),v=["onBlur","onFocus"];function P(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,s=new WeakMap;return(P=function(e){return e?s:t})(e)}function F(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}var O=(function(h){(0,n.default)(R,h);var y,P,O=(y=R,P=F(),function(){var e,t=(0,c.default)(y);if(P){var s=(0,c.default)(this).constructor;e=Reflect.construct(t,arguments,s)}else e=t.apply(this,arguments);return(0,l.default)(this,e)});function R(){var e;(0,s.default)(this,R);for(var t=arguments.length,o=new Array(t),n=0;n=23};var S='android'===f.default.OS?function(e,t){return t&&O.canUseNativeForeground()?{nativeForegroundAndroid:e}:{nativeBackgroundAndroid:e}}:function(e,t){return null};O.displayName='TouchableNativeFeedback',m.exports=O},209,[3,29,103,7,8,10,12,15,201,49,19,174,141,129,18,175]); -__d(function(g,r,i,a,m,_e,d){var t=r(d[0])(r(d[1])),e=r(d[0])(r(d[2])),s=r(d[0])(r(d[3])),o=r(d[0])(r(d[4])),n=r(d[0])(r(d[5])),c=r(d[0])(r(d[6])),l=r(d[0])(r(d[7])),p=r(d[0])(r(d[8])),u=r(d[0])(r(d[9])),f=r(d[0])(r(d[10])),y=r(d[0])(r(d[11])),h=r(d[0])(r(d[12])),b=(function(t,e){if(!e&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var s=P(e);if(s&&s.has(t))return s.get(t);var o={},n=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in t)if("default"!==c&&Object.prototype.hasOwnProperty.call(t,c)){var l=n?Object.getOwnPropertyDescriptor(t,c):null;l&&(l.get||l.set)?Object.defineProperty(o,c,l):o[c]=t[c]}o.default=t,s&&s.set(t,o);return o})(r(d[13])),v=["onBlur","onFocus"];function P(t){if("function"!=typeof WeakMap)return null;var e=new WeakMap,s=new WeakMap;return(P=function(t){return t?s:e})(t)}function O(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var F=(function(P){(0,n.default)(w,P);var F,_,R=(F=w,_=O(),function(){var t,e=(0,l.default)(F);if(_){var s=(0,l.default)(this).constructor;t=Reflect.construct(e,arguments,s)}else t=e.apply(this,arguments);return(0,c.default)(this,t)});function w(){var t;(0,s.default)(this,w);for(var e=arguments.length,o=new Array(e),n=0;n1&&void 0!==arguments[1]?arguments[1]:{}).iterations;return t},event:r(d[5]).event,createAnimatedComponent:r(d[6]),attachNativeEvent:r(d[7]).attachNativeEvent,forkEvent:r(d[5]).forkEvent,unforkEvent:r(d[5]).unforkEvent,Event:r(d[7]).AnimatedEvent}},212,[29,213,222,217,219,223,239,238]); -__d(function(g,r,i,a,m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}function e(t){var e=new Set;!(function t(n){'function'==typeof n.update?e.add(n):n.__getChildren().forEach(t)})(t),e.forEach(function(t){return t.update()})}var n=(function(n){r(d[3])(_,n);var s,u,o=(s=_,u=t(),function(){var t,e=r(d[0])(s);if(u){var n=r(d[0])(this).constructor;t=Reflect.construct(e,arguments,n)}else t=e.apply(this,arguments);return r(d[1])(this,t)});function _(t){var e;if(r(d[4])(this,_),e=o.call(this),'number'!=typeof t)throw new Error('AnimatedValue: Attempting to set value to undefined');return e._startingValue=e._value=t,e._offset=0,e._animation=null,e}return r(d[5])(_,[{key:"__detach",value:function(){var t=this;this.__isNative&&r(d[2]).API.getValue(this.__getNativeTag(),function(e){t._value=e}),this.stopAnimation(),r(d[6])(r(d[0])(_.prototype),"__detach",this).call(this)}},{key:"__getValue",value:function(){return this._value+this._offset}},{key:"setValue",value:function(t){var e,n,s=this;this._animation&&(this._animation.stop(),this._animation=null),this._updateValue(t,!this.__isNative),this.__isNative&&(e=this.__getNativeTag().toString(),n=function(){r(d[2]).API.setAnimatedNodeValue(s.__getNativeTag(),t)},r(d[2]).API.setWaitingForIdentifier(e),n(),r(d[2]).API.unsetWaitingForIdentifier(e))}},{key:"setOffset",value:function(t){this._offset=t,this.__isNative&&r(d[2]).API.setAnimatedNodeOffset(this.__getNativeTag(),t)}},{key:"flattenOffset",value:function(){this._value+=this._offset,this._offset=0,this.__isNative&&r(d[2]).API.flattenAnimatedNodeOffset(this.__getNativeTag())}},{key:"extractOffset",value:function(){this._offset+=this._value,this._value=0,this.__isNative&&r(d[2]).API.extractAnimatedNodeOffset(this.__getNativeTag())}},{key:"stopAnimation",value:function(t){this.stopTracking(),this._animation&&this._animation.stop(),this._animation=null,t&&t(this.__getValue())}},{key:"resetAnimation",value:function(t){this.stopAnimation(t),this._value=this._startingValue,this.__isNative&&r(d[2]).API.setAnimatedNodeValue(this.__getNativeTag(),this._startingValue)}},{key:"_onAnimatedValueUpdateReceived",value:function(t){this._updateValue(t,!1)}},{key:"interpolate",value:function(t){return new(r(d[7]))(this,t)}},{key:"animate",value:function(t,e){var n=this,s=null;t.__isInteraction&&(s=r(d[8]).createInteractionHandle());var u=this._animation;this._animation&&this._animation.stop(),this._animation=t,t.start(this._value,function(t){n._updateValue(t,!0)},function(t){n._animation=null,null!==s&&r(d[8]).clearInteractionHandle(s),e&&e(t)},u,this)}},{key:"stopTracking",value:function(){this._tracking&&this._tracking.__detach(),this._tracking=null}},{key:"track",value:function(t){this.stopTracking(),this._tracking=t}},{key:"_updateValue",value:function(t,n){if(void 0===t)throw new Error('AnimatedValue: Attempting to set value to undefined');this._value=t,n&&e(this),r(d[6])(r(d[0])(_.prototype),"__callListeners",this).call(this,this.__getValue())}},{key:"__getNativeConfig",value:function(){return{type:'value',value:this._value,offset:this._offset}}}]),_})(r(d[9]));m.exports=n},213,[15,12,214,10,7,8,84,217,220,218]); -__d(function(g,r,i,a,m,e,d){var t,n=r(d[0])(r(d[1])),o=r(d[0])(r(d[2])),u=r(d[0])(r(d[3])),l=r(d[0])(r(d[4])),s=r(d[0])(r(d[5])),f='ios'===l.default.OS&&g.RN$Bridgeless?o.default:n.default,c=1,v=1,p=new Set,N=!1,b=[],A={getValue:function(t,n){(0,s.default)(f,'Native animated module is not available'),A.queueOperation(function(){f.getValue(t,n)})},setWaitingForIdentifier:function(t){p.add(t),N=!0},unsetWaitingForIdentifier:function(t){p.delete(t),0===p.size&&(N=!1,A.disableQueue())},disableQueue:function(){(0,s.default)(f,'Native animated module is not available'),'android'===l.default.OS&&f.startOperationBatch();for(var t=0,n=b.length;tn){if('identity'===u)return c;'clamp'===u&&(c=n)}return a===r?a:e===n?t<=e?a:r:(e===-1/0?c=-c:n===1/0?c-=e:c=(c-e)/(n-e),c=i(c),a===-1/0?c=-c:r===1/0?c+=a:c=c*(r-a)+a,c)}function r(t){var e=_r(d[3])(t);return null===e||'number'!=typeof e?t:"rgba("+((4278190080&(e=e||0))>>>24)+", "+((16711680&e)>>>16)+", "+((65280&e)>>>8)+", "+(255&e)/255+")"}var i=/[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?/g;function o(t){var e=t.outputRange;_r(d[2])(e.length>=2,'Bad output range'),u(e=e.map(r));var a=e[0].match(i).map(function(){return[]});e.forEach(function(t){t.match(i).forEach(function(t,e){a[e].push(+t)})});var o,c=e[0].match(i).map(function(e,r){return n(_r(d[4])({},t,{outputRange:a[r]}))}),l='string'==typeof(o=e[0])&&o.startsWith('rgb');return function(t){var n=0;return e[0].replace(i,function(){var e=+c[n++](t);return l&&(e=n<4?Math.round(e):Math.round(1e3*e)/1e3),String(e)})}}function u(t){for(var e=t[0].replace(i,''),n=1;n=t);++n);return n-1}function l(t){_r(d[2])(t.length>=2,'inputRange must have at least 2 elements');for(var e=1;e=t[e-1],'inputRange must be monotonically non-decreasing '+t)}function p(t,e){_r(d[2])(e.length>=2,t+' must have at least 2 elements'),_r(d[2])(2!==e.length||e[0]!==-1/0||e[1]!==1/0,t+'cannot be ]-infinity;+infinity[ '+e)}var f=(function(e){_r(d[5])(o,e);var a,r,i=(a=o,r=t(),function(){var t,e=_r(d[0])(a);if(r){var n=_r(d[0])(this).constructor;t=Reflect.construct(e,arguments,n)}else t=e.apply(this,arguments);return _r(d[1])(this,t)});function o(t,e){var a;return _r(d[6])(this,o),(a=i.call(this))._parent=t,a._config=e,a._interpolation=n(e),a}return _r(d[7])(o,[{key:"__makeNative",value:function(){this._parent.__makeNative(),_r(d[8])(_r(d[0])(o.prototype),"__makeNative",this).call(this)}},{key:"__getValue",value:function(){var t=this._parent.__getValue();return _r(d[2])('number'==typeof t,'Cannot interpolate an input which is not a number.'),this._interpolation(t)}},{key:"interpolate",value:function(t){return new o(this,t)}},{key:"__attach",value:function(){this._parent.__addChild(this)}},{key:"__detach",value:function(){this._parent.__removeChild(this),_r(d[8])(_r(d[0])(o.prototype),"__detach",this).call(this)}},{key:"__transformDataType",value:function(t){return t.map(_r(d[9]).transformDataType)}},{key:"__getNativeConfig",value:function(){return{inputRange:this._config.inputRange,outputRange:this.__transformDataType(this._config.outputRange),extrapolateLeft:this._config.extrapolateLeft||this._config.extrapolate||'extend',extrapolateRight:this._config.extrapolateRight||this._config.extrapolate||'extend',type:'interpolation'}}}]),o})(_r(d[10]));f.__createInterpolation=n,m.exports=f},217,[15,12,18,142,29,10,7,8,84,214,218]); -__d(function(g,r,_i,a,m,_e,d){'use strict';function t(t,i){var n="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(n)return(n=n.call(t)).next.bind(n);if(Array.isArray(t)||(n=e(t))||i&&t&&"number"==typeof t.length){n&&(t=n);var o=0;return function(){return o>=t.length?{done:!0}:{done:!1,value:t[o++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function e(t,e){if(t){if("string"==typeof t)return i(t,e);var n=Object.prototype.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?i(t,e):void 0}}function i(t,e){(null==e||e>t.length)&&(e=t.length);for(var i=0,n=new Array(e);i0?setTimeout(h,0):setImmediate(h))}function h(){l=0;var f=o.size;c.forEach(function(n){return o.add(n)}),s.forEach(function(n){return o.delete(n)});var h=o.size;if(0!==f&&0===h?n.emit(t.Events.interactionComplete):0===f&&0!==h&&n.emit(t.Events.interactionStart),0===h)for(;u.hasTasksToProcess();)if(u.processNext(),p>0&&r(d[4]).getEventLoopRunningTime()>=p){v();break}c.clear(),s.clear()}m.exports=t},220,[3,5,18,221,30]); -__d(function(g,r,i,a,m,_e,d){'use strict';var e=(function(){function e(t){var u=t.onMoreTasks;r(d[0])(this,e),this._onMoreTasks=u,this._queueStack=[{tasks:[],popable:!1}]}return r(d[1])(e,[{key:"enqueue",value:function(e){this._getCurrentQueue().push(e)}},{key:"enqueueTasks",value:function(e){var t=this;e.forEach(function(e){return t.enqueue(e)})}},{key:"cancelTasks",value:function(e){this._queueStack=this._queueStack.map(function(t){return r(d[2])({},t,{tasks:t.tasks.filter(function(t){return-1===e.indexOf(t)})})}).filter(function(e,t){return e.tasks.length>0||0===t})}},{key:"hasTasksToProcess",value:function(){return this._getCurrentQueue().length>0}},{key:"processNext",value:function(){var e=this._getCurrentQueue();if(e.length){var t=e.shift();try{'object'==typeof t&&t.gen?this._genPromise(t):'object'==typeof t&&t.run?t.run():(r(d[3])('function'==typeof t,'Expected Function, SimpleTask, or PromiseTask, but got:\n'+JSON.stringify(t,null,2)),t())}catch(e){throw e.message='TaskQueue: Error with task '+(t.name||'')+': '+e.message,e}}}},{key:"_getCurrentQueue",value:function(){var e=this._queueStack.length-1,t=this._queueStack[e];return t.popable&&0===t.tasks.length&&this._queueStack.length>1?(this._queueStack.pop(),this._getCurrentQueue()):t.tasks}},{key:"_genPromise",value:function(e){var t=this;this._queueStack.push({tasks:[],popable:!1});var u=this._queueStack.length-1,s=this._queueStack[u];e.gen().then(function(){s.popable=!0,t.hasTasksToProcess()&&t._onMoreTasks()}).catch(function(t){throw t.message="TaskQueue: Error resolving Promise in task "+e.name+": "+t.message,t}).done()}}]),e})();m.exports=e},221,[7,8,29,18]); -__d(function(g,r,i,a,m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var e=1,n=(function(n){r(d[2])(o,n);var s,u,f=(s=o,u=t(),function(){var t,e=r(d[0])(s);if(u){var n=r(d[0])(this).constructor;t=Reflect.construct(e,arguments,n)}else t=e.apply(this,arguments);return r(d[1])(this,t)});function o(t){var e;r(d[3])(this,o),e=f.call(this);var n=t||{x:0,y:0};return'number'==typeof n.x&&'number'==typeof n.y?(e.x=new(r(d[4]))(n.x),e.y=new(r(d[4]))(n.y)):(r(d[5])(n.x instanceof r(d[4])&&n.y instanceof r(d[4]),"AnimatedValueXY must be initialized with an object of numbers or AnimatedValues."),e.x=n.x,e.y=n.y),e._listeners={},e}return r(d[6])(o,[{key:"setValue",value:function(t){this.x.setValue(t.x),this.y.setValue(t.y)}},{key:"setOffset",value:function(t){this.x.setOffset(t.x),this.y.setOffset(t.y)}},{key:"flattenOffset",value:function(){this.x.flattenOffset(),this.y.flattenOffset()}},{key:"extractOffset",value:function(){this.x.extractOffset(),this.y.extractOffset()}},{key:"__getValue",value:function(){return{x:this.x.__getValue(),y:this.y.__getValue()}}},{key:"resetAnimation",value:function(t){this.x.resetAnimation(),this.y.resetAnimation(),t&&t(this.__getValue())}},{key:"stopAnimation",value:function(t){this.x.stopAnimation(),this.y.stopAnimation(),t&&t(this.__getValue())}},{key:"addListener",value:function(t){var n=this,s=String(e++),u=function(e){e.value;t(n.__getValue())};return this._listeners[s]={x:this.x.addListener(u),y:this.y.addListener(u)},s}},{key:"removeListener",value:function(t){this.x.removeListener(this._listeners[t].x),this.y.removeListener(this._listeners[t].y),delete this._listeners[t]}},{key:"removeAllListeners",value:function(){this.x.removeAllListeners(),this.y.removeAllListeners(),this._listeners={}}},{key:"getLayout",value:function(){return{left:this.x,top:this.y}}},{key:"getTranslateTransform",value:function(){return[{translateX:this.x},{translateY:this.y}]}}]),o})(r(d[7]));m.exports=n},222,[15,12,10,7,213,18,8,218]); -__d(function(g,r,_i,_a,m,e,d){'use strict';var n=function(n,t){return n&&t.onComplete?function(){t.onComplete&&t.onComplete.apply(t,arguments),n&&n.apply(void 0,arguments)}:n||t.onComplete},t=function(n,t,i){if(n instanceof r(d[6])){var o=r(d[7])({},t),u=r(d[7])({},t);for(var s in t){var c=t[s],f=c.x,v=c.y;void 0!==f&&void 0!==v&&(o[s]=f,u[s]=v)}var p=i(n.x,o),l=i(n.y,u);return a([p,l],{stopTogether:!1})}return null},i=function i(o,a){var u=function(t,i,o){o=n(o,i);var a=t,u=i;a.stopTracking(),i.toValue instanceof r(d[8])?a.track(new(r(d[9]))(a,i.toValue,r(d[11]),u,o)):a.animate(new(r(d[11]))(u),o)};return t(o,a,i)||{start:function(n){u(o,a,n)},stop:function(){o.stopAnimation()},reset:function(){o.resetAnimation()},_startNativeLoop:function(n){var t=r(d[7])({},a,{iterations:n});u(o,t)},_isUsingNativeDriver:function(){return a.useNativeDriver||!1}}},o=function(n){var t=0;return{start:function(i){0===n.length?i&&i({finished:!0}):n[t].start(function o(a){a.finished&&++t!==n.length?n[t].start(o):i&&i(a)})},stop:function(){t1&&void 0!==arguments[1]?arguments[1]:{},i=t.iterations,o=void 0===i?-1:i,a=t.resetBeforeIteration,u=void 0===a||a,s=!1,c=0;return{start:function(t){n&&0!==o?n._isUsingNativeDriver()?n._startNativeLoop(o):(function i(){var a=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{finished:!0};s||c===o||!1===a.finished?t&&t(a):(c++,u&&n.reset(),n.start(i))})():t&&t({finished:!0})},stop:function(){s=!0,n.stop()},reset:function(){c=0,s=!1,n.reset()},_startNativeLoop:function(){throw new Error('Loops run using the native driver cannot contain Animated.loop animations')},_isUsingNativeDriver:function(){return n._isUsingNativeDriver()}}},event:function(n,t){var i=new(r(d[14]).AnimatedEvent)(n,t);return i.__isNative?i:i.__getHandler()},createAnimatedComponent:r(d[16]),attachNativeEvent:r(d[14]).attachNativeEvent,forkEvent:function(n,t){return n?n instanceof r(d[14]).AnimatedEvent?(n.__addListener(t),n):function(){'function'==typeof n&&n.apply(void 0,arguments),t.apply(void 0,arguments)}:t},unforkEvent:function(n,t){n&&n instanceof r(d[14]).AnimatedEvent&&n.__removeListener(t)},Event:r(d[14]).AnimatedEvent}},223,[224,225,226,227,228,229,222,29,219,230,231,234,237,213,238,217,239]); -__d(function(g,r,i,_a,m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var e=(function(e){r(d[2])(u,e);var n,a,_=(n=u,a=t(),function(){var t,e=r(d[0])(n);if(a){var _=r(d[0])(this).constructor;t=Reflect.construct(e,arguments,_)}else t=e.apply(this,arguments);return r(d[1])(this,t)});function u(t,e){var n;return r(d[3])(this,u),(n=_.call(this))._a='number'==typeof t?new(r(d[4]))(t):t,n._b='number'==typeof e?new(r(d[4]))(e):e,n}return r(d[5])(u,[{key:"__makeNative",value:function(){this._a.__makeNative(),this._b.__makeNative(),r(d[6])(r(d[0])(u.prototype),"__makeNative",this).call(this)}},{key:"__getValue",value:function(){return this._a.__getValue()+this._b.__getValue()}},{key:"interpolate",value:function(t){return new(r(d[7]))(this,t)}},{key:"__attach",value:function(){this._a.__addChild(this),this._b.__addChild(this)}},{key:"__detach",value:function(){this._a.__removeChild(this),this._b.__removeChild(this),r(d[6])(r(d[0])(u.prototype),"__detach",this).call(this)}},{key:"__getNativeConfig",value:function(){return{type:'addition',input:[this._a.__getNativeTag(),this._b.__getNativeTag()]}}}]),u})(r(d[8]));m.exports=e},224,[15,12,10,7,213,8,84,217,218]); -__d(function(g,r,i,_a,m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var e=(function(e){r(d[2])(u,e);var n,a,_=(n=u,a=t(),function(){var t,e=r(d[0])(n);if(a){var _=r(d[0])(this).constructor;t=Reflect.construct(e,arguments,_)}else t=e.apply(this,arguments);return r(d[1])(this,t)});function u(t,e){var n;return r(d[3])(this,u),(n=_.call(this))._a='number'==typeof t?new(r(d[4]))(t):t,n._b='number'==typeof e?new(r(d[4]))(e):e,n}return r(d[5])(u,[{key:"__makeNative",value:function(){this._a.__makeNative(),this._b.__makeNative(),r(d[6])(r(d[0])(u.prototype),"__makeNative",this).call(this)}},{key:"__getValue",value:function(){return this._a.__getValue()-this._b.__getValue()}},{key:"interpolate",value:function(t){return new(r(d[7]))(this,t)}},{key:"__attach",value:function(){this._a.__addChild(this),this._b.__addChild(this)}},{key:"__detach",value:function(){this._a.__removeChild(this),this._b.__removeChild(this),r(d[6])(r(d[0])(u.prototype),"__detach",this).call(this)}},{key:"__getNativeConfig",value:function(){return{type:'subtraction',input:[this._a.__getNativeTag(),this._b.__getNativeTag()]}}}]),u})(r(d[8]));m.exports=e},225,[15,12,10,7,213,8,84,217,218]); -__d(function(g,r,i,_a,m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var e=(function(e){r(d[2])(_,e);var n,o,a=(n=_,o=t(),function(){var t,e=r(d[0])(n);if(o){var a=r(d[0])(this).constructor;t=Reflect.construct(e,arguments,a)}else t=e.apply(this,arguments);return r(d[1])(this,t)});function _(t,e){var n;return r(d[3])(this,_),(n=a.call(this))._warnedAboutDivideByZero=!1,(0===e||e instanceof r(d[4])&&0===e.__getValue())&&console.error('Detected potential division by zero in AnimatedDivision'),n._a='number'==typeof t?new(r(d[5]))(t):t,n._b='number'==typeof e?new(r(d[5]))(e):e,n}return r(d[6])(_,[{key:"__makeNative",value:function(){this._a.__makeNative(),this._b.__makeNative(),r(d[7])(r(d[0])(_.prototype),"__makeNative",this).call(this)}},{key:"__getValue",value:function(){var t=this._a.__getValue(),e=this._b.__getValue();return 0===e?(this._warnedAboutDivideByZero||(console.error('Detected division by zero in AnimatedDivision'),this._warnedAboutDivideByZero=!0),0):(this._warnedAboutDivideByZero=!1,t/e)}},{key:"interpolate",value:function(t){return new(r(d[8]))(this,t)}},{key:"__attach",value:function(){this._a.__addChild(this),this._b.__addChild(this)}},{key:"__detach",value:function(){this._a.__removeChild(this),this._b.__removeChild(this),r(d[7])(r(d[0])(_.prototype),"__detach",this).call(this)}},{key:"__getNativeConfig",value:function(){return{type:'division',input:[this._a.__getNativeTag(),this._b.__getNativeTag()]}}}]),_})(r(d[9]));m.exports=e},226,[15,12,10,7,219,213,8,84,217,218]); -__d(function(g,r,i,_a,m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var e=(function(e){r(d[2])(u,e);var n,a,_=(n=u,a=t(),function(){var t,e=r(d[0])(n);if(a){var _=r(d[0])(this).constructor;t=Reflect.construct(e,arguments,_)}else t=e.apply(this,arguments);return r(d[1])(this,t)});function u(t,e){var n;return r(d[3])(this,u),(n=_.call(this))._a='number'==typeof t?new(r(d[4]))(t):t,n._b='number'==typeof e?new(r(d[4]))(e):e,n}return r(d[5])(u,[{key:"__makeNative",value:function(){this._a.__makeNative(),this._b.__makeNative(),r(d[6])(r(d[0])(u.prototype),"__makeNative",this).call(this)}},{key:"__getValue",value:function(){return this._a.__getValue()*this._b.__getValue()}},{key:"interpolate",value:function(t){return new(r(d[7]))(this,t)}},{key:"__attach",value:function(){this._a.__addChild(this),this._b.__addChild(this)}},{key:"__detach",value:function(){this._a.__removeChild(this),this._b.__removeChild(this),r(d[6])(r(d[0])(u.prototype),"__detach",this).call(this)}},{key:"__getNativeConfig",value:function(){return{type:'multiplication',input:[this._a.__getNativeTag(),this._b.__getNativeTag()]}}}]),u})(r(d[8]));m.exports=e},227,[15,12,10,7,213,8,84,217,218]); -__d(function(g,r,i,_a,m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var e=(function(e){r(d[2])(o,e);var u,n,a=(u=o,n=t(),function(){var t,e=r(d[0])(u);if(n){var a=r(d[0])(this).constructor;t=Reflect.construct(e,arguments,a)}else t=e.apply(this,arguments);return r(d[1])(this,t)});function o(t,e){var u;return r(d[3])(this,o),(u=a.call(this))._a=t,u._modulus=e,u}return r(d[4])(o,[{key:"__makeNative",value:function(){this._a.__makeNative(),r(d[5])(r(d[0])(o.prototype),"__makeNative",this).call(this)}},{key:"__getValue",value:function(){return(this._a.__getValue()%this._modulus+this._modulus)%this._modulus}},{key:"interpolate",value:function(t){return new(r(d[6]))(this,t)}},{key:"__attach",value:function(){this._a.__addChild(this)}},{key:"__detach",value:function(){this._a.__removeChild(this),r(d[5])(r(d[0])(o.prototype),"__detach",this).call(this)}},{key:"__getNativeConfig",value:function(){return{type:'modulus',input:this._a.__getNativeTag(),modulus:this._modulus}}}]),o})(r(d[7]));m.exports=e},228,[15,12,10,7,8,84,217,218]); -__d(function(g,r,i,_a,m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var e=(function(e){r(d[2])(_,e);var a,n,u=(a=_,n=t(),function(){var t,e=r(d[0])(a);if(n){var u=r(d[0])(this).constructor;t=Reflect.construct(e,arguments,u)}else t=e.apply(this,arguments);return r(d[1])(this,t)});function _(t,e,a){var n;return r(d[3])(this,_),(n=u.call(this))._a=t,n._min=e,n._max=a,n._value=n._lastValue=n._a.__getValue(),n}return r(d[4])(_,[{key:"__makeNative",value:function(){this._a.__makeNative(),r(d[5])(r(d[0])(_.prototype),"__makeNative",this).call(this)}},{key:"interpolate",value:function(t){return new(r(d[6]))(this,t)}},{key:"__getValue",value:function(){var t=this._a.__getValue(),e=t-this._lastValue;return this._lastValue=t,this._value=Math.min(Math.max(this._value+e,this._min),this._max),this._value}},{key:"__attach",value:function(){this._a.__addChild(this)}},{key:"__detach",value:function(){this._a.__removeChild(this),r(d[5])(r(d[0])(_.prototype),"__detach",this).call(this)}},{key:"__getNativeConfig",value:function(){return{type:'diffclamp',input:this._a.__getNativeTag(),min:this._min,max:this._max}}}]),_})(r(d[7]));m.exports=e},229,[15,12,10,7,8,84,217,218]); -__d(function(g,r,i,a,m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var e=(function(e){r(d[2])(u,e);var n,_,o=(n=u,_=t(),function(){var t,e=r(d[0])(n);if(_){var o=r(d[0])(this).constructor;t=Reflect.construct(e,arguments,o)}else t=e.apply(this,arguments);return r(d[1])(this,t)});function u(t,e,n,_,s){var l;return r(d[3])(this,u),(l=o.call(this))._value=t,l._parent=e,l._animationClass=n,l._animationConfig=_,l._useNativeDriver=r(d[4]).shouldUseNativeDriver(_),l._callback=s,l.__attach(),l}return r(d[5])(u,[{key:"__makeNative",value:function(){this.__isNative=!0,this._parent.__makeNative(),r(d[6])(r(d[0])(u.prototype),"__makeNative",this).call(this),this._value.__makeNative()}},{key:"__getValue",value:function(){return this._parent.__getValue()}},{key:"__attach",value:function(){this._parent.__addChild(this),this._useNativeDriver&&this.__makeNative()}},{key:"__detach",value:function(){this._parent.__removeChild(this),r(d[6])(r(d[0])(u.prototype),"__detach",this).call(this)}},{key:"update",value:function(){this._value.animate(new this._animationClass(r(d[7])({},this._animationConfig,{toValue:this._animationConfig.toValue.__getValue()})),this._callback)}},{key:"__getNativeConfig",value:function(){var t=new this._animationClass(r(d[7])({},this._animationConfig,{toValue:void 0})).__getNativeAnimationConfig();return{type:'tracking',animationId:r(d[4]).generateNewAnimationId(),animationConfig:t,toValue:this._parent.__getNativeTag(),value:this._value.__getNativeTag()}}}]),u})(r(d[8]));m.exports=e},230,[15,12,10,7,214,8,84,29,219]); -__d(function(g,r,i,a,_m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var s=(function(s){r(d[2])(l,s);var e,n,o=(e=l,n=t(),function(){var t,s=r(d[0])(e);if(n){var o=r(d[0])(this).constructor;t=Reflect.construct(s,arguments,o)}else t=s.apply(this,arguments);return r(d[1])(this,t)});function l(t){var s,e,n,h,_,u,f,c,m,v,p,y;if(r(d[3])(this,l),(m=o.call(this))._overshootClamping=null!=(s=t.overshootClamping)&&s,m._restDisplacementThreshold=null!=(e=t.restDisplacementThreshold)?e:.001,m._restSpeedThreshold=null!=(n=t.restSpeedThreshold)?n:.001,m._initialVelocity=null!=(h=t.velocity)?h:0,m._lastVelocity=null!=(_=t.velocity)?_:0,m._toValue=t.toValue,m._delay=null!=(u=t.delay)?u:0,m._useNativeDriver=r(d[4]).shouldUseNativeDriver(t),m.__isInteraction=null!=(f=t.isInteraction)?f:!m._useNativeDriver,m.__iterations=null!=(c=t.iterations)?c:1,void 0!==t.stiffness||void 0!==t.damping||void 0!==t.mass)r(d[5])(void 0===t.bounciness&&void 0===t.speed&&void 0===t.tension&&void 0===t.friction,'You can define one of bounciness/speed, tension/friction, or stiffness/damping/mass, but not more than one'),m._stiffness=null!=(v=t.stiffness)?v:100,m._damping=null!=(p=t.damping)?p:10,m._mass=null!=(y=t.mass)?y:1;else if(void 0!==t.bounciness||void 0!==t.speed){var V,T;r(d[5])(void 0===t.tension&&void 0===t.friction&&void 0===t.stiffness&&void 0===t.damping&&void 0===t.mass,'You can define one of bounciness/speed, tension/friction, or stiffness/damping/mass, but not more than one');var b=r(d[6]).fromBouncinessAndSpeed(null!=(V=t.bounciness)?V:8,null!=(T=t.speed)?T:12);m._stiffness=b.stiffness,m._damping=b.damping,m._mass=1}else{var M,D,P=r(d[6]).fromOrigamiTensionAndFriction(null!=(M=t.tension)?M:40,null!=(D=t.friction)?D:7);m._stiffness=P.stiffness,m._damping=P.damping,m._mass=1}return r(d[5])(m._stiffness>0,'Stiffness value must be greater than 0'),r(d[5])(m._damping>0,'Damping value must be greater than 0'),r(d[5])(m._mass>0,'Mass value must be greater than 0'),m}return r(d[7])(l,[{key:"__getNativeAnimationConfig",value:function(){var t;return{type:'spring',overshootClamping:this._overshootClamping,restDisplacementThreshold:this._restDisplacementThreshold,restSpeedThreshold:this._restSpeedThreshold,stiffness:this._stiffness,damping:this._damping,mass:this._mass,initialVelocity:null!=(t=this._initialVelocity)?t:this._lastVelocity,toValue:this._toValue,iterations:this.__iterations}}},{key:"start",value:function(t,s,e,n,o){var h=this;if(this.__active=!0,this._startPosition=t,this._lastPosition=this._startPosition,this._onUpdate=s,this.__onEnd=e,this._lastTime=Date.now(),this._frameTime=0,n instanceof l){var _=n.getInternalState();this._lastPosition=_.lastPosition,this._lastVelocity=_.lastVelocity,this._initialVelocity=this._lastVelocity,this._lastTime=_.lastTime}var u=function(){h._useNativeDriver?h.__startNativeAnimation(o):h.onUpdate()};this._delay?this._timeout=setTimeout(u,this._delay):u()}},{key:"getInternalState",value:function(){return{lastPosition:this._lastPosition,lastVelocity:this._lastVelocity,lastTime:this._lastTime}}},{key:"onUpdate",value:function(){var t=Date.now();t>this._lastTime+64&&(t=this._lastTime+64);var s=(t-this._lastTime)/1e3;this._frameTime+=s;var e=this._damping,n=this._mass,o=this._stiffness,l=-this._initialVelocity,h=e/(2*Math.sqrt(o*n)),_=Math.sqrt(o/n),u=_*Math.sqrt(1-h*h),f=this._toValue-this._startPosition,c=0,m=0,v=this._frameTime;if(h<1){var p=Math.exp(-h*_*v);c=this._toValue-p*((l+h*_*f)/u*Math.sin(u*v)+f*Math.cos(u*v)),m=h*_*p*(Math.sin(u*v)*(l+h*_*f)/u+f*Math.cos(u*v))-p*(Math.cos(u*v)*(l+h*_*f)-u*f*Math.sin(u*v))}else{var y=Math.exp(-_*v);c=this._toValue-y*(f+(l+_*f)*v),m=y*(l*(v*_-1)+v*f*(_*_))}if(this._lastTime=t,this._lastPosition=c,this._lastVelocity=m,this._onUpdate(c),this.__active){var V=!1;this._overshootClamping&&0!==this._stiffness&&(V=this._startPositionthis._toValue:c18&&A<=44?p(A):h(A),s(2*M-M*M,v,.01));return{stiffness:n(x),damping:t(B)}}}},232,[]); -__d(function(g,r,i,a,m,_e,d){'use strict';var t=1,n=(function(){function n(){r(d[0])(this,n)}return r(d[1])(n,[{key:"start",value:function(t,n,e,o,_){}},{key:"stop",value:function(){this.__nativeId&&r(d[2]).API.stopAnimation(this.__nativeId)}},{key:"__getNativeAnimationConfig",value:function(){throw new Error('This animation type cannot be offloaded to native')}},{key:"__debouncedOnEnd",value:function(t){var n=this.__onEnd;this.__onEnd=null,n&&n(t)}},{key:"__startNativeAnimation",value:function(n){var e=t+":startAnimation";t+=1,r(d[2]).API.setWaitingForIdentifier(e);try{n.__makeNative(),this.__nativeId=r(d[2]).generateNewAnimationId(),r(d[2]).API.startAnimatingNode(this.__nativeId,n.__getNativeTag(),this.__getNativeAnimationConfig(),this.__debouncedOnEnd.bind(this))}catch(t){throw t}finally{r(d[2]).API.unsetWaitingForIdentifier(e)}}}]),n})();m.exports=n},233,[7,8,214]); -__d(function(g,r,i,a,m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var e;function n(){if(!e){var t=r(d[2]);e=t.inOut(t.ease)}return e}var s=(function(e){r(d[3])(_,e);var s,o,u=(s=_,o=t(),function(){var t,e=r(d[0])(s);if(o){var n=r(d[0])(this).constructor;t=Reflect.construct(e,arguments,n)}else t=e.apply(this,arguments);return r(d[1])(this,t)});function _(t){var e,s,o,h,l,c;return r(d[4])(this,_),(c=u.call(this))._toValue=t.toValue,c._easing=null!=(e=t.easing)?e:n(),c._duration=null!=(s=t.duration)?s:500,c._delay=null!=(o=t.delay)?o:0,c.__iterations=null!=(h=t.iterations)?h:1,c._useNativeDriver=r(d[5]).shouldUseNativeDriver(t),c.__isInteraction=null!=(l=t.isInteraction)?l:!c._useNativeDriver,c}return r(d[6])(_,[{key:"__getNativeAnimationConfig",value:function(){for(var t=[],e=Math.round(this._duration/16.666666666666668),n=0;n=this._startTime+this._duration)return 0===this._duration?this._onUpdate(this._toValue):this._onUpdate(this._fromValue+this._easing(1)*(this._toValue-this._fromValue)),void this.__debouncedOnEnd({finished:!0});this._onUpdate(this._fromValue+this._easing((t-this._startTime)/this._duration)*(this._toValue-this._fromValue)),this.__active&&(this._animationFrame=requestAnimationFrame(this.onUpdate.bind(this)))}},{key:"stop",value:function(){r(d[7])(r(d[0])(_.prototype),"stop",this).call(this),this.__active=!1,clearTimeout(this._timeout),g.cancelAnimationFrame(this._animationFrame),this.__debouncedOnEnd({finished:!1})}}]),_})(r(d[8]));m.exports=s},234,[15,12,235,10,7,214,8,84,233]); -__d(function(g,r,i,a,m,e,d){'use strict';var n,u=(function(){function u(){r(d[0])(this,u)}return r(d[1])(u,null,[{key:"step0",value:function(n){return n>0?1:0}},{key:"step1",value:function(n){return n>=1?1:0}},{key:"linear",value:function(n){return n}},{key:"ease",value:function(t){return n||(n=u.bezier(.42,0,1,1)),n(t)}},{key:"quad",value:function(n){return n*n}},{key:"cubic",value:function(n){return n*n*n}},{key:"poly",value:function(n){return function(u){return Math.pow(u,n)}}},{key:"sin",value:function(n){return 1-Math.cos(n*Math.PI/2)}},{key:"circle",value:function(n){return 1-Math.sqrt(1-n*n)}},{key:"exp",value:function(n){return Math.pow(2,10*(n-1))}},{key:"elastic",value:function(){var n=(arguments.length>0&&void 0!==arguments[0]?arguments[0]:1)*Math.PI;return function(u){return 1-Math.pow(Math.cos(u*Math.PI/2),3)*Math.cos(u*n)}}},{key:"back",value:function(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1.70158;return function(u){return u*u*((n+1)*u-n)}}},{key:"bounce",value:function(n){if(n<.36363636363636365)return 7.5625*n*n;if(n<.7272727272727273){var u=n-.5454545454545454;return 7.5625*u*u+.75}if(n<.9090909090909091){var t=n-.8181818181818182;return 7.5625*t*t+.9375}var o=n-.9545454545454546;return 7.5625*o*o+.984375}},{key:"bezier",value:function(n,u,t,o){return r(d[2])(n,u,t,o)}},{key:"in",value:function(n){return n}},{key:"out",value:function(n){return function(u){return 1-n(1-u)}}},{key:"inOut",value:function(n){return function(u){return u<.5?n(2*u)/2:1-n(2*(1-u))/2}}}]),u})();m.exports=u},235,[7,8,236]); -__d(function(g,r,_i,a,m,e,d){'use strict';var n=4,t=.001,u=1e-7,o=10,f=.1,i='function'==typeof Float32Array;function c(n,t){return 1-3*t+3*n}function v(n,t){return 3*t-6*n}function s(n){return 3*n}function w(n,t,u){return((c(t,u)*n+v(t,u))*n+s(t))*n}function l(n,t,u){return 3*c(t,u)*n*n+2*v(t,u)*n+s(t)}function y(n,t,f,i,c){var v,s,l=0,y=t,b=f;do{(v=w(s=y+(b-y)/2,i,c)-n)>0?b=s:y=s}while(Math.abs(v)>u&&++l=0&&n<=1&&o>=0&&o<=1))throw new Error('bezier x values must be in [0, 1] range');var v=i?new Float32Array(11):new Array(11);if(n!==u||o!==c)for(var s=0;s<11;++s)v[s]=w(s*f,n,o);function h(u){for(var i=0,c=1;10!==c&&v[c]<=u;++c)i+=f;var s=i+(u-v[--c])/(v[c+1]-v[c])*f,w=l(s,n,o);return w>=t?b(u,s,n,o):0===w?s:y(u,i,i+f,n,o)}return function(t){return n===u&&o===c?t:0===t?0:1===t?1:w(h(t),u,c)}}},236,[]); -__d(function(g,r,i,a,m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var e=(function(e){r(d[2])(c,e);var n,s,o=(n=c,s=t(),function(){var t,e=r(d[0])(n);if(s){var o=r(d[0])(this).constructor;t=Reflect.construct(e,arguments,o)}else t=e.apply(this,arguments);return r(d[1])(this,t)});function c(t){var e,n,s,u;return r(d[3])(this,c),(u=o.call(this))._deceleration=null!=(e=t.deceleration)?e:.998,u._velocity=t.velocity,u._useNativeDriver=r(d[4]).shouldUseNativeDriver(t),u.__isInteraction=null!=(n=t.isInteraction)?n:!u._useNativeDriver,u.__iterations=null!=(s=t.iterations)?s:1,u}return r(d[5])(c,[{key:"__getNativeAnimationConfig",value:function(){return{type:'decay',deceleration:this._deceleration,velocity:this._velocity,iterations:this.__iterations}}},{key:"start",value:function(t,e,n,s,o){this.__active=!0,this._lastValue=t,this._fromValue=t,this._onUpdate=e,this.__onEnd=n,this._startTime=Date.now(),this._useNativeDriver?this.__startNativeAnimation(o):this._animationFrame=requestAnimationFrame(this.onUpdate.bind(this))}},{key:"onUpdate",value:function(){var t=Date.now(),e=this._fromValue+this._velocity/(1-this._deceleration)*(1-Math.exp(-(1-this._deceleration)*(t-this._startTime)));this._onUpdate(e),Math.abs(this._lastValue-e)<.1?this.__debouncedOnEnd({finished:!0}):(this._lastValue=e,this.__active&&(this._animationFrame=requestAnimationFrame(this.onUpdate.bind(this))))}},{key:"stop",value:function(){r(d[6])(r(d[0])(c.prototype),"stop",this).call(this),this.__active=!1,g.cancelAnimationFrame(this._animationFrame),this.__debouncedOnEnd({finished:!1})}}]),c})(r(d[7]));m.exports=e},237,[15,12,10,7,214,8,84,233]); -__d(function(g,r,i,a,m,e,d){'use strict';function t(t,n,s){var v=[];r(d[1])(s[0]&&s[0].nativeEvent,'Native driven events only support animated values contained inside `nativeEvent`.'),(function t(n,s){if(n instanceof r(d[0]))n.__makeNative(),v.push({nativeEventPath:s,animatedValueTag:n.__getNativeTag()});else if('object'==typeof n)for(var o in n)t(n[o],s.concat(o))})(s[0].nativeEvent,[]);var o=r(d[2]).findNodeHandle(t);return null!=o&&v.forEach(function(t){r(d[3]).API.addAnimatedEventToView(o,n,t)}),{detach:function(){null!=o&&v.forEach(function(t){r(d[3]).API.removeAnimatedEventFromView(o,n,t.animatedValueTag)})}}}var n=(function(){function n(t,s){r(d[4])(this,n),this._listeners=[],this._argMapping=t,null==s&&(console.warn('Animated.event now requires a second argument for options'),s={useNativeDriver:!1}),s.listener&&this.__addListener(s.listener),this._callListeners=this._callListeners.bind(this),this._attachedEvent=null,this.__isNative=r(d[3]).shouldUseNativeDriver(s)}return r(d[5])(n,[{key:"__addListener",value:function(t){this._listeners.push(t)}},{key:"__removeListener",value:function(t){this._listeners=this._listeners.filter(function(n){return n!==t})}},{key:"__attach",value:function(n,s){r(d[1])(this.__isNative,'Only native driven events need to be attached.'),this._attachedEvent=t(n,s,this._argMapping)}},{key:"__detach",value:function(t,n){r(d[1])(this.__isNative,'Only native driven events need to be detached.'),this._attachedEvent&&this._attachedEvent.detach()}},{key:"__getHandler",value:function(){var t=this;if(this.__isNative)return this._callListeners;return function(){for(var n=arguments.length,s=new Array(n),v=0;v1){for(var l=[],s=0;s1?Math.ceil(e.length/n):e.length}return 0},t._keyExtractor=function(e,n){var o,l=v(t.props.numColumns),s=null!=(o=t.props.keyExtractor)?o:r(d[10]).keyExtractor;return l>1?Array.isArray(e)?e.map(function(e,t){return s(e,n*l+t)}).join(':'):void r(d[11])(Array.isArray(e),"FlatList: Encountered internal consistency error, expected each item to consist of an array with 1-%s columns; instead, received a single item.",l):s(e,n)},t._renderer=function(){var e=t.props,o=e.ListItemComponent,l=e.renderItem,s=e.columnWrapperStyle,u=v(t.props.numColumns),c=o?'ListItemComponent':'renderItem',f=function(e){return o?h.createElement(o,e):l?l(e):null};return(0,n.default)({},c,function(e){if(u>1){var t=e.item,n=e.index;return r(d[11])(Array.isArray(t),'Expected array of items with numColumns > 1'),h.createElement(r(d[12]),{style:r(d[13]).compose(y.row,s)},t.map(function(t,o){var l=f({item:t,index:n*u+o,separators:e.separators});return null!=l?h.createElement(h.Fragment,{key:o},l):null}))}return f(e)})},t._checkProps(t.props),t.props.viewabilityConfigCallbackPairs?t._virtualizedListPairs=t.props.viewabilityConfigCallbackPairs.map(function(e){return{viewabilityConfig:e.viewabilityConfig,onViewableItemsChanged:t._createOnViewableItemsChanged(e.onViewableItemsChanged)}}):t.props.onViewableItemsChanged&&t._virtualizedListPairs.push({viewabilityConfig:t.props.viewabilityConfig,onViewableItemsChanged:t._createOnViewableItemsChanged(t.props.onViewableItemsChanged)}),t}return(0,l.default)(k,[{key:"scrollToEnd",value:function(e){this._listRef&&this._listRef.scrollToEnd(e)}},{key:"scrollToIndex",value:function(e){this._listRef&&this._listRef.scrollToIndex(e)}},{key:"scrollToItem",value:function(e){this._listRef&&this._listRef.scrollToItem(e)}},{key:"scrollToOffset",value:function(e){this._listRef&&this._listRef.scrollToOffset(e)}},{key:"recordInteraction",value:function(){this._listRef&&this._listRef.recordInteraction()}},{key:"flashScrollIndicators",value:function(){this._listRef&&this._listRef.flashScrollIndicators()}},{key:"getScrollResponder",value:function(){if(this._listRef)return this._listRef.getScrollResponder()}},{key:"getNativeScrollRef",value:function(){if(this._listRef)return this._listRef.getScrollRef()}},{key:"getScrollableNode",value:function(){if(this._listRef)return this._listRef.getScrollableNode()}},{key:"setNativeProps",value:function(e){this._listRef&&this._listRef.setNativeProps(e)}},{key:"componentDidUpdate",value:function(e){r(d[11])(e.numColumns===this.props.numColumns,"Changing numColumns on the fly is not supported. Change the key prop on FlatList when changing the number of columns to force a fresh render of the component."),r(d[11])(e.onViewableItemsChanged===this.props.onViewableItemsChanged,'Changing onViewableItemsChanged on the fly is not supported'),r(d[11])(!r(d[14])(e.viewabilityConfig,this.props.viewabilityConfig),'Changing viewabilityConfig on the fly is not supported'),r(d[11])(e.viewabilityConfigCallbackPairs===this.props.viewabilityConfigCallbackPairs,'Changing viewabilityConfigCallbackPairs on the fly is not supported'),this._checkProps(this.props)}},{key:"_checkProps",value:function(e){var t=e.getItem,n=e.getItemCount,o=e.horizontal,l=e.columnWrapperStyle,s=e.onViewableItemsChanged,u=e.viewabilityConfigCallbackPairs,c=v(this.props.numColumns);r(d[11])(!t&&!n,'FlatList does not support custom data formats.'),c>1?r(d[11])(!o,'numColumns does not support horizontal.'):r(d[11])(!l,'columnWrapperStyle not supported for single column lists'),r(d[11])(!(s&&u),"FlatList does not support setting both onViewableItemsChanged and viewabilityConfigCallbackPairs.")}},{key:"_pushMultiColumnViewable",value:function(e,n){var o,l=v(this.props.numColumns),s=null!=(o=this.props.keyExtractor)?o:r(d[10]).keyExtractor;n.item.forEach(function(o,u){r(d[11])(null!=n.index,'Missing index!');var c=n.index*l+u;e.push((0,t.default)({},n,{item:o,key:s(o,c),index:c}))})}},{key:"_createOnViewableItemsChanged",value:function(e){var t=this;return function(n){var o=v(t.props.numColumns);if(e)if(o>1){var l=[],s=[];n.viewableItems.forEach(function(e){return t._pushMultiColumnViewable(s,e)}),n.changed.forEach(function(e){return t._pushMultiColumnViewable(l,e)}),e({viewableItems:s,changed:l})}else e(n)}}},{key:"render",value:function(){var n,o=this.props,l=(o.numColumns,o.columnWrapperStyle,o.removeClippedSubviews),s=(0,e.default)(o,f);return h.createElement(r(d[15]),(0,t.default)({},s,{getItem:this._getItem,getItemCount:this._getItemCount,keyExtractor:this._keyExtractor,ref:this._captureRef,viewabilityConfigCallbackPairs:this._virtualizedListPairs,removeClippedSubviews:(n=l,null==n||n)},this._renderer()))}}]),k})(h.PureComponent),y=r(d[13]).create({row:{flexDirection:'row'}});m.exports=C},246,[3,103,29,247,7,8,10,12,15,129,248,18,174,173,166,249]); -__d(function(g,r,i,a,m,e,d){m.exports=function(t,n,o){return n in t?Object.defineProperty(t,n,{value:o,enumerable:!0,configurable:!0,writable:!0}):t[n]=o,t},m.exports.__esModule=!0,m.exports.default=m.exports},247,[]); -__d(function(g,r,i,a,m,e,d){'use strict';Object.defineProperty(e,"__esModule",{value:!0}),e.computeWindowedRenderLimits=function(n,s,o,u,c,h,v){var b=s(n);if(0===b)return c;var M=v.offset,y=v.velocity,x=v.visibleLength,p=Math.max(0,M),w=p+x,O=(u-1)*x,k=y>1?'after':y<-1?'before':'none',_=Math.max(0,p-.5*O),j=Math.max(0,w+.5*O);if(h(b-1).offset<_)return{first:Math.max(0,b-1-o),last:b-1};var L=f([_,p,w,j],b,h),S=(0,t.default)(L,4),C=S[0],E=S[1],J=S[2],N=S[3];C=null==C?0:C,E=null==E?Math.max(0,C):E,N=null==N?b-1:N,J=null==J?Math.min(N,E+o-1):J;var R={first:E,last:J},B=l(c,R);for(;!(E<=C&&J>=N);){var F=B>=o,P=E<=c.first||E>c.last,T=E>C&&(!F||!P),W=J>=c.last||J=E&&E>=0&&J=C&&J<=N&&E<=R.first&&J>=R.last))throw new Error('Bad window calculation '+JSON.stringify({first:E,last:J,itemCount:b,overscanFirst:C,overscanLast:N,visible:R}));return{first:E,last:J}},e.elementsThatOverlapOffsets=f,e.keyExtractor=function(t,n){if('object'==typeof t&&null!=(null==t?void 0:t.key))return t.key;if('object'==typeof t&&null!=(null==t?void 0:t.id))return t.id;return String(n)},e.newRangeCount=l;var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2]));function f(t,f,l){for(var s=[],o=0,u=0;u=t[v]&&(s[v]=u,o++,v===t.length-1))return(0,n.default)(o===t.length,'bad offsets input, should be in increasing order: %s',JSON.stringify(t)),s;return s}function l(t,n){return n.last-n.first+1-Math.max(0,1+Math.min(n.last,t.last)-Math.max(n.first,t.first))}},248,[3,23,18]); -__d(function(g,r,_i,a,m,_e,d){var e=r(d[0])(r(d[1])),t=r(d[0])(r(d[2])),o=r(d[0])(r(d[3])),n=r(d[0])(r(d[4])),s=r(d[0])(r(d[5])),i=r(d[0])(r(d[6])),l=r(d[0])(r(d[7])),c=r(d[0])(r(d[8])),h=(function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var o=u(t);if(o&&o.has(e))return o.get(e);var n={},s=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var i in e)if("default"!==i&&Object.prototype.hasOwnProperty.call(e,i)){var l=s?Object.getOwnPropertyDescriptor(e,i):null;l&&(l.get||l.set)?Object.defineProperty(n,i,l):n[i]=e[i]}n.default=e,o&&o.set(e,n);return n})(r(d[9]));function u(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,o=new WeakMap;return(u=function(e){return e?o:t})(e)}function p(e,t){var o="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(o)return(o=o.call(e)).next.bind(o);if(Array.isArray(e)||(o=f(e))||t&&e&&"number"==typeof e.length){o&&(e=o);var n=0;return function(){return n>=e.length?{done:!0}:{done:!1,value:e[n++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function f(e,t){if(e){if("string"==typeof e)return _(e,t);var o=Object.prototype.toString.call(e).slice(8,-1);return"Object"===o&&e.constructor&&(o=e.constructor.name),"Map"===o||"Set"===o?Array.from(e):"Arguments"===o||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(o)?_(e,t):void 0}}function _(e,t){(null==t||t>e.length)&&(t=e.length);for(var o=0,n=new Array(t);o0&&t>0&&null!=i.props.initialScrollIndex&&i.props.initialScrollIndex>0&&!i._hasDoneInitialScroll&&(null==i.props.contentOffset&&i.scrollToIndex({animated:!1,index:i.props.initialScrollIndex}),i._hasDoneInitialScroll=!0),i.props.onContentSizeChange&&i.props.onContentSizeChange(e,t),i._scrollMetrics.contentLength=i._selectLength({height:t,width:e}),i._scheduleCellsToRenderUpdate(),i._maybeCallOnEndReached()},i._convertParentScrollMetrics=function(e){var t=e.offset-i._offsetFromParentVirtualizedList,o=e.visibleLength,n=t-i._scrollMetrics.offset;return{visibleLength:o,contentLength:i._scrollMetrics.contentLength,offset:t,dOffset:n}},i._onScroll=function(e){i._nestedChildLists.forEach(function(t){t.ref&&t.ref._onScroll(e)}),i.props.onScroll&&i.props.onScroll(e);var t=e.timeStamp,o=i._selectLength(e.nativeEvent.layoutMeasurement),n=i._selectLength(e.nativeEvent.contentSize),s=i._selectOffset(e.nativeEvent.contentOffset),l=s-i._scrollMetrics.offset;if(i._isNestedWithSameOrientation()){if(0===i._scrollMetrics.contentLength)return;var c=i._convertParentScrollMetrics({visibleLength:o,offset:s});o=c.visibleLength,n=c.contentLength,s=c.offset,l=c.dOffset}var h=i._scrollMetrics.timestamp?Math.max(1,t-i._scrollMetrics.timestamp):1,u=l/h;h>500&&i._scrollMetrics.dt>500&&n>5*o&&!i._hasWarned.perf&&(r(d[14])("VirtualizedList: You have a large list that is slow to update - make sure your renderItem function renders components that follow React performance best practices like PureComponent, shouldComponentUpdate, etc.",{dt:h,prevDt:i._scrollMetrics.dt,contentLength:n}),i._hasWarned.perf=!0),i._scrollMetrics={contentLength:n,dt:h,dOffset:l,offset:s,timestamp:t,velocity:u,visibleLength:o},i._updateViewableItems(i.props.data),i.props&&(i._maybeCallOnEndReached(),0!==u&&i._fillRateHelper.activate(),i._computeBlankness(),i._scheduleCellsToRenderUpdate())},i._onScrollBeginDrag=function(e){i._nestedChildLists.forEach(function(t){t.ref&&t.ref._onScrollBeginDrag(e)}),i._viewabilityTuples.forEach(function(e){e.viewabilityHelper.recordInteraction()}),i._hasInteracted=!0,i.props.onScrollBeginDrag&&i.props.onScrollBeginDrag(e)},i._onScrollEndDrag=function(e){i._nestedChildLists.forEach(function(t){t.ref&&t.ref._onScrollEndDrag(e)});var t=e.nativeEvent.velocity;t&&(i._scrollMetrics.velocity=i._selectOffset(t)),i._computeBlankness(),i.props.onScrollEndDrag&&i.props.onScrollEndDrag(e)},i._onMomentumScrollBegin=function(e){i._nestedChildLists.forEach(function(t){t.ref&&t.ref._onMomentumScrollBegin(e)}),i.props.onMomentumScrollBegin&&i.props.onMomentumScrollBegin(e)},i._onMomentumScrollEnd=function(e){i._nestedChildLists.forEach(function(t){t.ref&&t.ref._onMomentumScrollEnd(e)}),i._scrollMetrics.velocity=0,i._computeBlankness(),i.props.onMomentumScrollEnd&&i.props.onMomentumScrollEnd(e)},i._updateCellsToRender=function(){var e=i.props,t=e.data,o=e.getItemCount,n=M(e.onEndReachedThreshold),s=i._isVirtualizationDisabled();i._updateViewableItems(t),t&&i.setState(function(e){var l,c=i._scrollMetrics,h=c.contentLength,u=c.offset,f=c.visibleLength;if(s){var _=h-f-u0&&h>0&&(i.props.initialScrollIndex&&!i._scrollMetrics.offset||(l=(0,r(d[15]).computeWindowedRenderLimits)(i.props.data,i.props.getItemCount,I(i.props.maxToRenderPerBatch),R(i.props.windowSize),e,i._getFrameMetricsApprox,i._scrollMetrics)));if(l&&i._nestedChildLists.size>0)for(var y=l.first,v=l.last,C=y;C<=v;C++){var L=i._indicesToKeys.get(C),b=L&&i._cellKeysToChildListKeys.get(L);if(b){for(var S,M=!1,x=p(b);!(S=x()).done;){var w=S.value,k=i._nestedChildLists.get(w);if(k&&k.ref&&k.ref.hasMore()){M=!0;break}}if(M){l.last=C;break}}}return null!=l&&l.first===e.first&&l.last===e.last&&(l=null),l})},i._createViewToken=function(e,t){var o=i.props,n=o.data,s=(0,o.getItem)(n,e);return{index:e,item:s,key:i._keyExtractor(s,e),isViewable:t}},i._getFrameMetricsApprox=function(e){var t=i._getFrameMetrics(e);if(t&&t.index===e)return t;var o=i.props.getItemLayout;return r(d[11])(!o,'Should not have to estimate frames when a measurement metrics function is provided'),{length:i._averageCellLength,offset:i._averageCellLength*e}},i._getFrameMetrics=function(e){var t=i.props,o=t.data,n=t.getItem,s=t.getItemCount,l=t.getItemLayout;r(d[11])(s(o)>e,'Tried to get frame for out of range index '+e);var c=n(o,e),h=c&&i._frames[i._keyExtractor(c,e)];return h&&h.index===e||l&&(h=l(o,e)),h},r(d[11])(!e.onScroll||!e.onScroll.__isNative,"Components based on VirtualizedList must be wrapped with Animated.createAnimatedComponent to support native onScroll events with useNativeDriver"),r(d[11])(R(e.windowSize)>0,'VirtualizedList: The windowSize prop must be present and set to a value greater than 0.'),i._fillRateHelper=new(r(d[16]))(i._getFrameMetrics),i._updateCellsToRenderBatcher=new(r(d[17]))(i._updateCellsToRender,null!=(n=i.props.updateCellsBatchingPeriod)?n:50),i.props.viewabilityConfigCallbackPairs?i._viewabilityTuples=i.props.viewabilityConfigCallbackPairs.map(function(e){return{viewabilityHelper:new(r(d[18]))(e.viewabilityConfig),onViewableItemsChanged:e.onViewableItemsChanged}}):i.props.onViewableItemsChanged&&i._viewabilityTuples.push({viewabilityHelper:new(r(d[18]))(i.props.viewabilityConfig),onViewableItemsChanged:i.props.onViewableItemsChanged});var l={first:i.props.initialScrollIndex||0,last:Math.min(i.props.getItemCount(i.props.data),(i.props.initialScrollIndex||0)+S(i.props.initialNumToRender))-1};if(i._isNestedWithSameOrientation()){var f=i.context.getNestedChildState(i._getListKey());f&&(l=f,i.state=f,i._frames=f.frames)}return i.state=l,i}return(0,n.default)(u,[{key:"scrollToEnd",value:function(e){var t=!e||e.animated,o=this.props.getItemCount(this.props.data)-1,n=this._getFrameMetricsApprox(o),s=Math.max(0,n.offset+n.length+this._footerLength-this._scrollMetrics.visibleLength);null!=this._scrollRef&&(null!=this._scrollRef.scrollTo?this._scrollRef.scrollTo(b(this.props.horizontal)?{x:s,animated:t}:{y:s,animated:t}):console.warn("No scrollTo method provided. This may be because you have two nested VirtualizedLists with the same orientation, or because you are using a custom component that does not implement scrollTo."))}},{key:"scrollToIndex",value:function(e){var t=this.props,o=t.data,n=t.horizontal,s=t.getItemCount,i=t.getItemLayout,l=t.onScrollToIndexFailed,c=e.animated,h=e.index,u=e.viewOffset,p=e.viewPosition;if(r(d[11])(h>=0,"scrollToIndex out of range: requested index "+h+" but minimum is 0"),r(d[11])(s(o)>=1,"scrollToIndex out of range: item length "+s(o)+" but minimum is 1"),r(d[11])(hthis._highestMeasuredFrameIndex)return r(d[11])(!!l,"scrollToIndex should be used in conjunction with getItemLayout or onScrollToIndexFailed, otherwise there is no way to know the location of offscreen indices or handle failures."),void l({averageItemLength:this._averageCellLength,highestMeasuredFrameIndex:this._highestMeasuredFrameIndex,index:h});var f=this._getFrameMetricsApprox(h),_=Math.max(0,f.offset-(p||0)*(this._scrollMetrics.visibleLength-f.length))-(u||0);null!=this._scrollRef&&(null!=this._scrollRef.scrollTo?this._scrollRef.scrollTo(n?{x:_,animated:c}:{y:_,animated:c}):console.warn("No scrollTo method provided. This may be because you have two nested VirtualizedLists with the same orientation, or because you are using a custom component that does not implement scrollTo."))}},{key:"scrollToItem",value:function(e){for(var o=e.item,n=this.props,s=n.data,i=n.getItem,l=(0,n.getItemCount)(s),c=0;c0){C=!1,L='';var x=this._getSpacerKey(!p),w=this.props.initialScrollIndex?-1:S(this.props.initialNumToRender)-1,k=this.state,T=k.first,z=k.last;this._pushCells(y,I,v,0,w,_);var K=Math.max(w+1,T);if(!f&&T>w+1){var O=!1;if(v.size>0)for(var P=l?1:0,F=K-1;F>w;F--)if(v.has(F+P)){var V=this._getFrameMetricsApprox(w),D=this._getFrameMetricsApprox(F),N=D.offset-V.offset-(this.props.initialScrollIndex?0:V.length);y.push(h.createElement(r(d[10]),{key:"$sticky_lead",style:(0,e.default)({},x,N)})),this._pushCells(y,I,v,F,F,_);var A=this._getFrameMetricsApprox(T).offset-(D.offset+D.length);y.push(h.createElement(r(d[10]),{key:"$sticky_trail",style:(0,e.default)({},x,A)})),O=!0;break}if(!O){var B=this._getFrameMetricsApprox(w),H=this._getFrameMetricsApprox(T).offset-(B.offset+B.length);y.push(h.createElement(r(d[10]),{key:"$lead_spacer",style:(0,e.default)({},x,H)}))}}if(this._pushCells(y,I,v,K,z,_),!this._hasWarned.keys&&C&&(console.warn("VirtualizedList: missing keys for items, make sure to specify a key or id property on each item or provide a custom keyExtractor.",L),this._hasWarned.keys=!0),!f&&zu&&(this._sentEndForContentLength=0)}},{key:"_scheduleCellsToRenderUpdate",value:function(){var e=this.state,t=e.first,o=e.last,n=this._scrollMetrics,s=n.offset,i=n.visibleLength,l=n.velocity,c=this.props.getItemCount(this.props.data),h=!1,u=M(this.props.onEndReachedThreshold)*i/2;if(t>0){var p=s-this._getFrameMetricsApprox(t).offset;h=h||p<0||l<-2&&p2&&f0&&(this._scrollAnimatedValueAttachment=p.default.attachNativeEvent(this._scrollViewRef,'onScroll',[{nativeEvent:{contentOffset:{y:this._scrollAnimatedValue}}}]))}},{key:"_setStickyHeaderRef",value:function(e,o){o?this._stickyHeaderRefs.set(e,o):this._stickyHeaderRefs.delete(e)}},{key:"_onStickyHeaderLayout",value:function(e,o,t){var n=this.props.stickyHeaderIndices;if(n){var l=y.Children.toArray(this.props.children);if(t===this._getKeyForIndex(e,l)){var s=o.nativeEvent.layout.y;this._headerLayoutYs.set(t,s);var u=n[n.indexOf(e)-1];if(null!=u){var c=this._stickyHeaderRefs.get(this._getKeyForIndex(u,l));c&&c.setNextHeaderY&&c.setNextHeaderY(s)}}}}},{key:"render",value:function(){var t=this,n=!0===this.props.horizontal?P:F,l=(0,o.default)(n,2),s=l[0],u=l[1],c=[!0===this.props.horizontal&&Y.contentContainerHorizontal,this.props.contentContainerStyle],p=null==this.props.onContentSizeChange?null:{onLayout:this._handleContentOnLayout},f=this.props.stickyHeaderIndices,S=this.props.children;if(null!=f&&f.length>0){var b=y.Children.toArray(this.props.children);S=b.map(function(e,o){var n=e?f.indexOf(o):-1;if(n>-1){var l=e.key,s=f[n+1],u=t.props.StickyHeaderComponent||_.default;return y.createElement(u,{key:l,nativeID:'StickyHeader-'+l,ref:function(e){return t._setStickyHeaderRef(l,e)},nextHeaderLayoutY:t._headerLayoutYs.get(t._getKeyForIndex(s,b)),onLayout:function(e){return t._onStickyHeaderLayout(o,e,l)},scrollAnimatedValue:t._scrollAnimatedValue,inverted:t.props.invertStickyHeaders,hiddenOnScroll:t.props.stickyHeaderHiddenOnScroll,scrollViewHeight:t.state.layoutHeight},e)}return e})}S=y.createElement(D.default.Provider,{value:!0===this.props.horizontal?D.HORIZONTAL:D.VERTICAL},S);var R=Array.isArray(f)&&f.length>0,T=y.createElement(u,(0,e.default)({},p,{ref:this._setInnerViewRef,style:c,removeClippedSubviews:('android'!==h.default.OS||!R)&&this.props.removeClippedSubviews,collapsable:!1}),S),w=void 0!==this.props.alwaysBounceHorizontal?this.props.alwaysBounceHorizontal:this.props.horizontal,V=void 0!==this.props.alwaysBounceVertical?this.props.alwaysBounceVertical:!this.props.horizontal,k=!0===this.props.horizontal?Y.baseHorizontal:Y.baseVertical,E=(0,e.default)({},this.props,{alwaysBounceHorizontal:w,alwaysBounceVertical:V,style:v.default.compose(k,this.props.style),onContentSizeChange:null,onLayout:this._handleLayout,onMomentumScrollBegin:this._handleMomentumScrollBegin,onMomentumScrollEnd:this._handleMomentumScrollEnd,onResponderGrant:this._handleResponderGrant,onResponderReject:this._handleResponderReject,onResponderRelease:this._handleResponderRelease,onResponderTerminationRequest:this._handleResponderTerminationRequest,onScrollBeginDrag:this._handleScrollBeginDrag,onScrollEndDrag:this._handleScrollEndDrag,onScrollShouldSetResponder:this._handleScrollShouldSetResponder,onStartShouldSetResponder:this._handleStartShouldSetResponder,onStartShouldSetResponderCapture:this._handleStartShouldSetResponderCapture,onTouchEnd:this._handleTouchEnd,onTouchMove:this._handleTouchMove,onTouchStart:this._handleTouchStart,onTouchCancel:this._handleTouchCancel,onScroll:this._handleScroll,scrollEventThrottle:R?1:this.props.scrollEventThrottle,sendMomentumEvents:!(!this.props.onMomentumScrollBegin&&!this.props.onMomentumScrollEnd),snapToStart:!1!==this.props.snapToStart,snapToEnd:!1!==this.props.snapToEnd,pagingEnabled:h.default.select({ios:!0===this.props.pagingEnabled&&null==this.props.snapToInterval&&null==this.props.snapToOffsets,android:!0===this.props.pagingEnabled||null!=this.props.snapToInterval||null!=this.props.snapToOffsets})}),K=this.props.decelerationRate;null!=K&&(E.decelerationRate=(0,O.default)(K));var A=this.props.refreshControl;if(A){if('ios'===h.default.OS)return y.createElement(s,(0,e.default)({},E,{ref:this._setNativeRef}),A,T);if('android'===h.default.OS){var N=(0,I.default)((0,H.default)(E.style)),M=N.outer,W=N.inner;return y.cloneElement(A,{style:v.default.compose(k,M)},y.createElement(s,(0,e.default)({},E,{style:v.default.compose(k,W),ref:this._setNativeRef}),T))}}return y.createElement(s,(0,e.default)({},E,{ref:this._setNativeRef}),T)}}]),x})(y.Component);G.Context=D.default;var Y=v.default.create({baseVertical:{flexGrow:1,flexShrink:1,flexDirection:'column',overflow:'scroll'},baseHorizontal:{flexGrow:1,flexShrink:1,flexDirection:'row',overflow:'scroll'},contentContainerHorizontal:{flexDirection:'row'}});function U(o,t){return y.createElement(G,(0,e.default)({},o,{scrollViewRef:t}))}U.displayName='ScrollView';var Z=y.forwardRef(U);Z.Context=D.default,Z.displayName='ScrollView',m.exports=Z},250,[3,29,23,7,8,14,10,12,15,223,161,19,129,49,251,173,174,43,252,256,135,254,168,18,258,259,241,260,261,262,263,264,265]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),u=r(d[0])(r(d[3])),l=r(d[0])(r(d[4])),o=r(d[0])(r(d[5])),f=(function(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var u=s(n);if(u&&u.has(t))return u.get(t);var l={},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var f in t)if("default"!==f&&Object.prototype.hasOwnProperty.call(t,f)){var c=o?Object.getOwnPropertyDescriptor(t,f):null;c&&(c.get||c.set)?Object.defineProperty(l,f,c):l[f]=t[f]}l.default=t,u&&u.set(t,l);return l})(r(d[6]));function s(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,u=new WeakMap;return(s=function(t){return t?u:n})(t)}var c=o.default.View,p=f.forwardRef(function(l,s){var p=l.inverted,h=l.scrollViewHeight,y=l.hiddenOnScroll,R=l.scrollAnimatedValue,O=l.nextHeaderLayoutY,L=f.useState(!1),b=(0,t.default)(L,2),w=b[0],S=b[1],j=f.useState(0),E=(0,t.default)(j,2),P=E[0],_=E[1],x=f.useState(0),M=(0,t.default)(x,2),k=M[0],C=M[1],D=f.useState(null),H=(0,t.default)(D,2),I=H[0],V=H[1],Y=f.useState(O),T=(0,t.default)(Y,2),W=T[0],A=T[1],N=f.useState(!1),z=(0,t.default)(N,2),F=z[0],q=z[1],B=f.useRef(),G=(0,n.default)({getForwardedRef:function(){return s},setLocalRef:function(t){var n,u;(B.current=t,t)&&(t.setNextHeaderY=function(t){A(t)},q(!(null==(n=t._internalInstanceHandle)||null==(u=n.stateNode)||!u.canonical)))}}),J=(0,f.useMemo)(function(){return!0===y?o.default.diffClamp(R.interpolate({extrapolateLeft:'clamp',inputRange:[P,P+1],outputRange:[0,1]}).interpolate({inputRange:[0,1],outputRange:[0,-1]}),-k,0):null},[R,k,P,y]),K=f.useState(function(){var t=R.interpolate({inputRange:[-1,0],outputRange:[0,0]});return null!=J?o.default.add(t,J):t}),Q=(0,t.default)(K,2),U=Q[0],X=Q[1],Z=(0,f.useRef)(!0),$=(0,f.useRef)(null);(0,f.useEffect)(function(){0!==I&&null!=I&&(Z.current=!1)},[I]);var ee=(0,f.useCallback)(function(t){var n=t.value,l='android'===u.default.OS?15:64;0!==n||Z.current?(null!=$.current&&clearTimeout($.current),$.current=setTimeout(function(){n!==I&&V(n)},l)):Z.current=!0},[I]);(0,f.useEffect)(function(){var t=[-1,0],n=[0,0];if(w)if(!0===p){if(null!=h){var u=P+k-h;if(u>0){t.push(u),n.push(0),t.push(u+1),n.push(1);var l=(W||0)-k-h;l>u&&(t.push(l,l+1),n.push(l-u,l-u))}}}else{t.push(P),n.push(0);var f=(W||0)-k;f>=P?(t.push(f,f+1),n.push(f-P,f-P)):(t.push(P+1),n.push(1))}var s,c=R.interpolate({inputRange:t,outputRange:n});return null!=J&&(c=o.default.add(c,J)),F&&(s=c.addListener(ee)),X(c),function(){s&&c.removeListener(s),null!=$.current&&clearTimeout($.current)}},[W,w,k,P,h,R,p,J,ee,F]);var te=f.Children.only(l.children),ne=F&&null!=I?{style:{transform:[{translateY:I}]}}:null;return f.createElement(c,{collapsable:!1,nativeID:l.nativeID,onLayout:function(t){_(t.nativeEvent.layout.y),C(t.nativeEvent.layout.height),S(!0),l.onLayout(t);var n=f.Children.only(l.children);n.props.onLayout&&n.props.onLayout(t)},ref:G,style:[te.props.style,v.header,{transform:[{translateY:U}]}],passthroughAnimatedPropExplicitValues:ne},f.cloneElement(te,{style:v.fill,onLayout:void 0}))}),v=l.default.create({header:{zIndex:10,position:'relative'},fill:{flex:1}}),h=p;e.default=h},251,[3,23,241,19,173,211,129]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),u=r(d[0])(r(d[3])),l=r(d[0])(r(d[4])),o=r(d[0])(r(d[5])),s=r(d[0])(r(d[6])),f=r(d[0])(r(d[7])),v=(function(){function v(){(0,t.default)(this,v),this._emitter=new u.default('ios'!==s.default.OS?null:f.default)}return(0,n.default)(v,[{key:"addListener",value:function(t,n,u){return this._emitter.addListener(t,n)}},{key:"removeListener",value:function(t,n){this._emitter.removeListener(t,n)}},{key:"removeAllListeners",value:function(t){this._emitter.removeAllListeners(t)}},{key:"dismiss",value:function(){(0,o.default)()}},{key:"scheduleLayoutAnimation",value:function(t){var n=t.duration,u=t.easing;null!=n&&0!==n&&l.default.configureNext({duration:n,update:{duration:n,type:null!=u&&l.default.Types[u]||'keyboard'}})}}]),v})();m.exports=new v},252,[3,7,8,95,253,254,19,255]); -__d(function(g,r,i,a,m,e,d){'use strict';var n=r(d[0])(r(d[1]));function t(t,u,o){var l,s;if(!n.default.isTesting){var c,p,y=!1,f=function(){y||(y=!0,clearTimeout(b),null==u||u())},b=setTimeout(f,(null!=(l=t.duration)?l:0)+17),I=null==(s=g)?void 0:s.nativeFabricUIManager;if(null!=I&&I.configureNextLayoutAnimation)null==(c=g)||null==(p=c.nativeFabricUIManager)||p.configureNextLayoutAnimation(t,f,null!=o?o:function(){});else null!=r(d[2])&&r(d[2]).configureNextLayoutAnimation&&r(d[2]).configureNextLayoutAnimation(t,null!=f?f:function(){},null!=o?o:function(){})}}function u(n,t,u){return{duration:n,create:{type:t,property:u},update:{type:t},delete:{type:t,property:u}}}var o={easeInEaseOut:u(300,'easeInEaseOut','opacity'),linear:u(500,'linear','opacity'),spring:{duration:700,create:{type:'linear',property:'opacity'},update:{type:'spring',springDamping:.4},delete:{type:'linear',property:'opacity'}}},l={configureNext:t,create:u,Types:Object.freeze({spring:'spring',linear:'linear',easeInEaseOut:'easeInEaseOut',easeIn:'easeIn',easeOut:'easeOut',keyboard:'keyboard'}),Properties:Object.freeze({opacity:'opacity',scaleX:'scaleX',scaleY:'scaleY',scaleXY:'scaleXY'}),checkConfig:function(){console.error('LayoutAnimation.checkConfig(...) has been disabled.')},Presets:o,easeInEaseOut:t.bind(null,o.easeInEaseOut),linear:t.bind(null,o.linear),spring:t.bind(null,o.spring)};m.exports=l},253,[3,19,43]); -__d(function(g,r,i,a,m,e,d){'use strict';m.exports=function(){r(d[0]).blurTextInput(r(d[0]).currentlyFocusedInput())}},254,[135]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in n)if("default"!==l&&Object.prototype.hasOwnProperty.call(n,l)){var p=c?Object.getOwnPropertyDescriptor(n,l):null;p&&(p.get||p.set)?Object.defineProperty(f,l,p):f[l]=n[l]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).get('KeyboardObserver');e.default=n},255,[21]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),o={setGlobalOptions:function(o){if(void 0!==o.debug&&r(d[2])(t.default,'Trying to debug FrameRateLogger without the native module!'),t.default){var l={debug:!!o.debug,reportStackTraces:!!o.reportStackTraces};t.default.setGlobalOptions(l)}},setContext:function(o){t.default&&t.default.setContext(o)},beginScroll:function(){t.default&&t.default.beginScroll()},endScroll:function(){t.default&&t.default.endScroll()}};m.exports=o},256,[3,257,18]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in n)if("default"!==l&&Object.prototype.hasOwnProperty.call(n,l)){var p=c?Object.getOwnPropertyDescriptor(n,l):null;p&&(p.get||p.set)?Object.defineProperty(f,l,p):f[l]=n[l]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).get('FrameRateLogger');e.default=n},257,[21]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1]));m.exports=function(n){return'normal'===n?t.default.select({ios:.998,android:.985}):'fast'===n?t.default.select({ios:.99,android:.9}):n}},258,[3,19]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=function(s){var c=null,t=null;if(null!=s){c={},t={};for(var n=0,l=Object.keys(s);nMath.random(),this._resetData()}return r(d[0])(_,[{key:"activate",value:function(){this._enabled&&null==this._samplesStartTime&&(this._samplesStartTime=g.performance.now())}},{key:"deactivateAndFlush",value:function(){if(this._enabled){var t=this._samplesStartTime;if(null!=t)if(this._info.sample_count0&&(c=Math.min(h,Math.max(0,y.offset-_)));for(var p=0,b=n.last,v=this._getFrameMetrics(b);b>=n.first&&(!v||!v.inLayout);)v=this._getFrameMetrics(b),b--;if(v&&b0?(this._anyBlankStartTime=f,this._info.any_blank_speed_sum+=u,this._info.any_blank_count++,this._info.pixels_blank+=M,T>.5&&(this._mostlyBlankStartTime=f,this._info.mostly_blank_count++)):(u<.01||Math.abs(l)<1)&&this.deactivateAndFlush(),T}},{key:"enabled",value:function(){return this._enabled}},{key:"_resetData",value:function(){this._anyBlankStartTime=null,this._info=new t,this._mostlyBlankStartTime=null,this._samplesStartTime=null}}],[{key:"addListener",value:function(t){return null===l&&console.warn('Call `FillRateHelper.setSampleRate` before `addListener`.'),n.push(t),{remove:function(){n=n.filter(function(n){return t!==n})}}}},{key:"setSampleRate",value:function(t){l=t}},{key:"setMinSampleCount",value:function(t){s=t}}]),_})();m.exports=_},270,[8,7,29]); -__d(function(g,r,i,a,m,e,d){'use strict';var t=(function(){function t(n,l){r(d[0])(this,t),this._delay=l,this._callback=n}return r(d[1])(t,[{key:"dispose",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{abort:!1};this._taskHandle&&(this._taskHandle.cancel(),t.abort||this._callback(),this._taskHandle=null)}},{key:"schedule",value:function(){var t=this;if(!this._taskHandle){var n=setTimeout(function(){t._taskHandle=r(d[2]).runAfterInteractions(function(){t._taskHandle=null,t._callback()})},this._delay);this._taskHandle={cancel:function(){return clearTimeout(n)}}}}}]),t})();m.exports=t},271,[7,8,220]); -__d(function(g,r,_i,a,m,e,d){'use strict';function t(t,i){var o="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(o)return(o=o.call(t)).next.bind(o);if(Array.isArray(t)||(o=n(t))||i&&t&&"number"==typeof t.length){o&&(t=o);var s=0;return function(){return s>=t.length?{done:!0}:{done:!1,value:t[s++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function n(t,n){if(t){if("string"==typeof t)return i(t,n);var o=Object.prototype.toString.call(t).slice(8,-1);return"Object"===o&&t.constructor&&(o=t.constructor.name),"Map"===o||"Set"===o?Array.from(t):"Arguments"===o||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(o)?i(t,n):void 0}}function i(t,n){(null==n||n>t.length)&&(n=t.length);for(var i=0,o=new Array(n);i0&&void 0!==arguments[0]?arguments[0]:{viewAreaCoveragePercentThreshold:0};r(d[0])(this,n),this._hasInteracted=!1,this._timers=new Set,this._viewableIndices=[],this._viewableItems=new Map,this._config=t}return r(d[1])(n,[{key:"dispose",value:function(){this._timers.forEach(clearTimeout)}},{key:"computeViewableItems",value:function(t,n,i,o,l){var u=this._config,c=u.itemVisiblePercentThreshold,h=u.viewAreaCoveragePercentThreshold,f=null!=h,v=f?h:c;r(d[2])(null!=v&&null!=c!=(null!=h),'Must set exactly one of itemVisiblePercentThreshold or viewAreaCoveragePercentThreshold');var b=[];if(0===t)return b;var y=-1,w=l||{first:0,last:t-1},_=w.first,p=w.last;if(p>=t)return console.warn('Invalid render range computing viewability '+JSON.stringify({renderRange:l,itemCount:t})),[];for(var I=_;I<=p;I++){var A=o(I);if(A){var S=A.offset-n,T=S+A.length;if(S0)y=I,s(f,v,S,T,i,A.length)&&b.push(I);else if(y>=0)break}}return b}},{key:"onUpdate",value:function(t,n,i,o,s,l,u){var c=this;if((!this._config.waitForInteraction||this._hasInteracted)&&0!==t&&o(0)){var h=[];if(t&&(h=this.computeViewableItems(t,n,i,o,u)),this._viewableIndices.length!==h.length||!this._viewableIndices.every(function(t,n){return t===h[n]}))if(this._viewableIndices=h,this._config.minimumViewTime){var f=setTimeout(function(){c._timers.delete(f),c._onUpdateSync(h,l,s)},this._config.minimumViewTime);this._timers.add(f)}else this._onUpdateSync(h,l,s)}}},{key:"resetViewableIndices",value:function(){this._viewableIndices=[]}},{key:"recordInteraction",value:function(){this._hasInteracted=!0}},{key:"_onUpdateSync",value:function(n,i,o){var s=this;n=n.filter(function(t){return s._viewableIndices.includes(t)});for(var l,u=this._viewableItems,c=new Map(n.map(function(t){var n=o(t,!0);return[n.key,n]})),h=[],f=t(c);!(l=f()).done;){var v=l.value,b=r(d[3])(v,2),y=b[0],w=b[1];u.has(y)||h.push(w)}for(var _,p=t(u);!(_=p()).done;){var I=_.value,A=r(d[3])(I,2),S=A[0],T=A[1];c.has(S)||h.push(r(d[4])({},T,{isViewable:!1}))}h.length>0&&(this._viewableItems=c,i({viewableItems:Array.from(c.values()),changed:h,viewabilityConfig:this._config}))}}]),n})();function s(t,n,i,o,s,c){if(u(i,o,s))return!0;var h=l(i,o,s);return 100*(t?h/s:h/c)>=n}function l(t,n,i){var o=Math.min(n,i)-Math.max(t,0);return Math.max(0,o)}function u(t,n,i){return t>=0&&n<=i&&n>t}m.exports=o},272,[7,8,18,23,29]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.VirtualizedListCellContextProvider=function(l){var u=l.cellKey,s=l.children,c=(0,n.useContext)(o);return n.createElement(o.Provider,{value:null==c?null:(0,t.default)({},c,{cellKey:u})},s)},e.VirtualizedListContext=void 0,e.VirtualizedListContextProvider=function(t){var l=t.children,u=t.value,s=(0,n.useMemo)(function(){return{cellKey:null,getScrollMetrics:u.getScrollMetrics,horizontal:u.horizontal,getOutermostParentListRef:u.getOutermostParentListRef,getNestedChildState:u.getNestedChildState,registerAsNestedChild:u.registerAsNestedChild,unregisterAsNestedChild:u.unregisterAsNestedChild,debugInfo:{cellKey:u.debugInfo.cellKey,horizontal:u.debugInfo.horizontal,listKey:u.debugInfo.listKey,parent:u.debugInfo.parent}}},[u.getScrollMetrics,u.horizontal,u.getOutermostParentListRef,u.getNestedChildState,u.registerAsNestedChild,u.unregisterAsNestedChild,u.debugInfo.cellKey,u.debugInfo.horizontal,u.debugInfo.listKey,u.debugInfo.parent]);return n.createElement(o.Provider,{value:s},l)},e.VirtualizedListContextResetter=function(t){var l=t.children;return n.createElement(o.Provider,{value:null},l)};var t=r(d[0])(r(d[1])),n=(function(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var o=l(n);if(o&&o.has(t))return o.get(t);var u={},s=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in t)if("default"!==c&&Object.prototype.hasOwnProperty.call(t,c)){var f=s?Object.getOwnPropertyDescriptor(t,c):null;f&&(f.get||f.set)?Object.defineProperty(u,c,f):u[c]=t[c]}u.default=t,o&&o.set(t,u);return u})(r(d[2]));function l(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,o=new WeakMap;return(l=function(t){return t?o:n})(t)}var o=n.createContext(null);e.VirtualizedListContext=o},273,[3,29,129]); -__d(function(g,r,i,a,m,e,d){!(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var f=t(o);if(f&&f.has(n))return f.get(n);var u={},p=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in n)if("default"!==c&&Object.prototype.hasOwnProperty.call(n,c)){var l=p?Object.getOwnPropertyDescriptor(n,c):null;l&&(l.get||l.set)?Object.defineProperty(u,c,l):u[c]=n[c]}u.default=n,f&&f.set(n,u)})(r(d[0]));function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,f=new WeakMap;return(t=function(t){return t?f:o})(n)}m.exports=r(d[1])(r(d[2]),{collapsable:!1})},274,[129,239,275]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),o=r(d[0])(r(d[3])),u=r(d[0])(r(d[4])),l=(function(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var o=b(n);if(o&&o.has(t))return o.get(t);var u={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in t)if("default"!==c&&Object.prototype.hasOwnProperty.call(t,c)){var f=l?Object.getOwnPropertyDescriptor(t,c):null;f&&(f.get||f.set)?Object.defineProperty(u,c,f):u[c]=t[c]}u.default=t,o&&o.set(t,u);return u})(r(d[5])),c=r(d[0])(r(d[6])),f=r(d[0])(r(d[7])),s=r(d[0])(r(d[8])),h=r(d[0])(r(d[9])),p=r(d[0])(r(d[10])),y=r(d[0])(r(d[11])),w=r(d[0])(r(d[12])),v=r(d[0])(r(d[13]));function b(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,o=new WeakMap;return(b=function(t){return t?o:n})(t)}var S=1;function I(t,n){var o=S++;return n&&n(o),w.default.prefetchImage(t,o)}var E=function(n,o){var c,s,w,b,S=(0,y.default)(n.source),I=(0,y.default)(n.defaultSource),E=(0,y.default)(n.loadingIndicatorSource);S&&(''===S.uri&&console.warn('source.uri should not be an empty string'));if(n.src&&console.warn('The component requires a `source` property rather than `src`.'),n.children)throw new Error('The component cannot contain children. If you want to render content on top of the image, consider using the component or absolute positioning.');if(n.defaultSource&&n.loadingIndicatorSource)throw new Error('The component cannot have defaultSource and loadingIndicatorSource at the same time. Please use either defaultSource or loadingIndicatorSource.');if(!S||S.uri||Array.isArray(S)||(S=null),null!=(null==(c=S)?void 0:c.uri)){var P=S,_=P.width,j=P.height;w=(0,p.default)([{width:_,height:j},O.base,n.style]),b=[{uri:S.uri}]}else w=(0,p.default)([O.base,n.style]),b=S;var z=n.onLoadStart,C=n.onLoad,W=n.onLoadEnd,M=n.onError,T=(0,t.default)({},n,{style:w,shouldNotifyLoadEvents:!!(z||C||W||M),src:b,headers:null==(s=S)?void 0:s.headers,defaultSrc:I?I.uri:null,loadingIndicatorSrc:E?E.uri:null,ref:o});return l.createElement(h.default.Consumer,null,function(n){var o=null!==n?(0,t.default)({},T,{internal_analyticTag:n}):T;return l.createElement(f.default.Consumer,null,function(t){return t?l.createElement(v.default,o):l.createElement(u.default,o)})})};E=l.forwardRef(E),null!=s.default.unstable_createImageComponent&&(E=s.default.unstable_createImageComponent(E)),E.displayName='Image',E.getSize=function(t,n,o){return w.default.getSize(t).then(function(t){n(t.width,t.height)}).catch(o||function(){console.warn('Failed to get size for image: '+t)})},E.getSizeWithHeaders=function(t,n,o,u){return w.default.getSizeWithHeaders(t,n).then(function(t){o(t.width,t.height)}).catch(u||function(){console.warn('Failed to get size for image: '+t)})},E.prefetch=I,E.prefetchWithMetadata=function(t,n,o,u){I(t,u)},E.abortPrefetch=function(t){w.default.abortRequest(t)},E.queryCache=function(t){return n.default.async(function(o){for(;;)switch(o.prev=o.next){case 0:return o.next=2,n.default.awrap(w.default.queryCache(t));case 2:return o.abrupt("return",o.sent);case 3:case"end":return o.stop()}},null,null,null,Promise)},E.resolveAssetSource=y.default,E.propTypes=o.default;var O=c.default.create({base:{overflow:'hidden'}});m.exports=E},275,[3,29,75,276,280,129,173,176,281,283,168,155,284,282]); -__d(function(g,r,i,a,m,e,d){'use strict';var n=r(d[0])({},r(d[1]),{style:r(d[2])(r(d[3])),source:r(d[4]).oneOfType([r(d[4]).shape({uri:r(d[4]).string,headers:r(d[4]).objectOf(r(d[4]).string)}),r(d[4]).number,r(d[4]).arrayOf(r(d[4]).shape({uri:r(d[4]).string,width:r(d[4]).number,height:r(d[4]).number,headers:r(d[4]).objectOf(r(d[4]).string)}))]),blurRadius:r(d[4]).number,defaultSource:r(d[4]).number,loadingIndicatorSource:r(d[4]).oneOfType([r(d[4]).shape({uri:r(d[4]).string}),r(d[4]).number]),progressiveRenderingEnabled:r(d[4]).bool,fadeDuration:r(d[4]).number,internal_analyticTag:r(d[4]).string,onLoadStart:r(d[4]).func,onError:r(d[4]).func,onLoad:r(d[4]).func,onLoadEnd:r(d[4]).func,testID:r(d[4]).string,resizeMethod:r(d[4]).oneOf(['auto','resize','scale']),resizeMode:r(d[4]).oneOf(['cover','contain','stretch','repeat','center'])});m.exports=n},276,[29,277,186,279,191]); -__d(function(g,r,i,a,m,e,d){'use strict';var o=r(d[0])(r(d[1]));m.exports={accessible:r(d[2]).bool,accessibilityLabel:r(d[2]).node,accessibilityHint:r(d[2]).string,accessibilityActions:r(d[2]).arrayOf(r(d[2]).string),accessibilityIgnoresInvertColors:r(d[2]).bool,accessibilityRole:r(d[2]).oneOf(r(d[3]).DeprecatedAccessibilityRoles),accessibilityState:r(d[2]).object,accessibilityValue:r(d[2]).object,accessibilityLiveRegion:r(d[2]).oneOf(['none','polite','assertive']),importantForAccessibility:r(d[2]).oneOf(['auto','yes','no','no-hide-descendants']),accessibilityViewIsModal:r(d[2]).bool,accessibilityElementsHidden:r(d[2]).bool,onAccessibilityAction:r(d[2]).func,onAccessibilityTap:r(d[2]).func,onMagicTap:r(d[2]).func,testID:r(d[2]).string,nativeID:r(d[2]).string,onResponderGrant:r(d[2]).func,onResponderMove:r(d[2]).func,onResponderReject:r(d[2]).func,onResponderRelease:r(d[2]).func,onResponderTerminate:r(d[2]).func,onResponderTerminationRequest:r(d[2]).func,onStartShouldSetResponder:r(d[2]).func,onStartShouldSetResponderCapture:r(d[2]).func,onMoveShouldSetResponder:r(d[2]).func,onMoveShouldSetResponderCapture:r(d[2]).func,hitSlop:r(d[4]),onLayout:r(d[2]).func,pointerEvents:r(d[2]).oneOf(['box-none','none','box-only','auto']),style:o,removeClippedSubviews:r(d[2]).bool,renderToHardwareTextureAndroid:r(d[2]).bool,shouldRasterizeIOS:r(d[2]).bool,collapsable:r(d[2]).bool,needsOffscreenAlphaCompositing:r(d[2]).bool}},277,[186,189,191,278,198]); -__d(function(g,r,i,a,m,e,d){'use strict';m.exports={DeprecatedAccessibilityRoles:['none','button','togglebutton','link','search','image','keyboardkey','text','adjustable','imagebutton','header','summary','alert','checkbox','combobox','menu','menubar','menuitem','progressbar','radio','radiogroup','scrollbar','spinbutton','switch','tab','tablist','timer','list','toolbar']}},278,[]); -__d(function(g,r,i,a,m,e,d){'use strict';var o=r(d[0])({},r(d[1]),r(d[2]),r(d[3]),{resizeMode:r(d[4]).oneOf(['center','contain','cover','repeat','stretch']),backfaceVisibility:r(d[4]).oneOf(['visible','hidden']),backgroundColor:r(d[5]),borderColor:r(d[5]),borderWidth:r(d[4]).number,borderRadius:r(d[4]).number,overflow:r(d[4]).oneOf(['visible','hidden']),tintColor:r(d[5]),opacity:r(d[4]).number,overlayColor:r(d[4]).string,borderTopLeftRadius:r(d[4]).number,borderTopRightRadius:r(d[4]).number,borderBottomLeftRadius:r(d[4]).number,borderBottomRightRadius:r(d[4]).number});m.exports=o},279,[29,190,194,196,191,195]); -__d(function(g,r,i,a,m,e,d){function t(o){if("function"!=typeof WeakMap)return null;var n=new WeakMap,s=new WeakMap;return(t=function(t){return t?s:n})(o)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var o=(function(o,n){if(!n&&o&&o.__esModule)return o;if(null===o||"object"!=typeof o&&"function"!=typeof o)return{default:o};var s=t(n);if(s&&s.has(o))return s.get(o);var u={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var f in o)if("default"!==f&&Object.prototype.hasOwnProperty.call(o,f)){var c=l?Object.getOwnPropertyDescriptor(o,f):null;c&&(c.get||c.set)?Object.defineProperty(u,f,c):u[f]=o[f]}u.default=o,s&&s.set(o,u);return u})(r(d[0])).get('RCTImageView',function(){return{uiViewClassName:'RCTImageView',bubblingEventTypes:{},directEventTypes:{topLoadStart:{registrationName:'onLoadStart'},topProgress:{registrationName:'onProgress'},topError:{registrationName:'onError'},topPartialLoad:{registrationName:'onPartialLoad'},topLoad:{registrationName:'onLoad'},topLoadEnd:{registrationName:'onLoadEnd'}},validAttributes:{blurRadius:!0,capInsets:{diff:r(d[1])},defaultSource:{process:r(d[2])},defaultSrc:!0,fadeDuration:!0,headers:!0,internal_analyticTag:!0,loadingIndicatorSrc:!0,onError:!0,onLoad:!0,onLoadEnd:!0,onLoadStart:!0,onPartialLoad:!0,onProgress:!0,overlayColor:{process:r(d[3])},progressiveRenderingEnabled:!0,resizeMethod:!0,resizeMode:!0,shouldNotifyLoadEvents:!0,source:!0,src:!0,tintColor:{process:r(d[3])}}}});e.default=o},280,[150,145,155,141]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in n)if("default"!==c&&Object.prototype.hasOwnProperty.call(n,c)){var p=l?Object.getOwnPropertyDescriptor(n,c):null;p&&(p.get||p.set)?Object.defineProperty(f,c,p):f[c]=n[c]}f.default=n,u&&u.set(n,f)})(r(d[0])),r(d[1])(r(d[2])),r(d[1])(r(d[3]));function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}e.default={unstable_createImageComponent:null}},281,[129,3,280,282]); -__d(function(g,r,i,a,m,e,d){'use strict';function t(o){if("function"!=typeof WeakMap)return null;var n=new WeakMap,s=new WeakMap;return(t=function(t){return t?s:n})(o)}var o=(function(o,n){if(!n&&o&&o.__esModule)return o;if(null===o||"object"!=typeof o&&"function"!=typeof o)return{default:o};var s=t(n);if(s&&s.has(o))return s.get(o);var u={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in o)if("default"!==c&&Object.prototype.hasOwnProperty.call(o,c)){var p=l?Object.getOwnPropertyDescriptor(o,c):null;p&&(p.get||p.set)?Object.defineProperty(u,c,p):u[c]=o[c]}u.default=o,s&&s.set(o,u);return u})(r(d[0])).get('RCTTextInlineImage',function(){return{uiViewClassName:'RCTImageView',bubblingEventTypes:{},directEventTypes:{topLoadStart:{registrationName:'onLoadStart'},topProgress:{registrationName:'onProgress'},topError:{registrationName:'onError'},topPartialLoad:{registrationName:'onPartialLoad'},topLoad:{registrationName:'onLoad'},topLoadEnd:{registrationName:'onLoadEnd'}},validAttributes:{blurRadius:!0,capInsets:{diff:r(d[1])},defaultSource:{process:r(d[2])},defaultSrc:!0,fadeDuration:!0,headers:!0,internal_analyticTag:!0,loadingIndicatorSrc:!0,onError:!0,onLoad:!0,onLoadEnd:!0,onLoadStart:!0,onPartialLoad:!0,onProgress:!0,overlayColor:{process:r(d[3])},progressiveRenderingEnabled:!0,resizeMethod:!0,resizeMode:!0,shouldNotifyLoadEvents:!0,source:!0,src:!0,tintColor:{process:r(d[3])}}}});m.exports=o},282,[150,145,155,141]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in n)if("default"!==c&&Object.prototype.hasOwnProperty.call(n,c)){var p=l?Object.getOwnPropertyDescriptor(n,c):null;p&&(p.get||p.set)?Object.defineProperty(f,c,p):f[c]=n[c]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).createContext(null);e.default=n},283,[129]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,f=new WeakMap;return(t=function(t){return t?f:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var f=t(o);if(f&&f.has(n))return f.get(n);var u={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in n)if("default"!==l&&Object.prototype.hasOwnProperty.call(n,l)){var p=c?Object.getOwnPropertyDescriptor(n,l):null;p&&(p.get||p.set)?Object.defineProperty(u,l,p):u[l]=n[l]}u.default=n,f&&f.set(n,u);return u})(r(d[0])).getEnforcing('ImageLoader');e.default=n},284,[21]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),n=(function(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var f=o(n);if(f&&f.has(t))return f.get(t);var u={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in t)if("default"!==c&&Object.prototype.hasOwnProperty.call(t,c)){var p=l?Object.getOwnPropertyDescriptor(t,c):null;p&&(p.get||p.set)?Object.defineProperty(u,c,p):u[c]=t[c]}u.default=t,f&&f.set(t,u);return u})(r(d[2]));function o(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,f=new WeakMap;return(o=function(t){return t?f:n})(t)}var f=n.forwardRef(function(o,f){return n.createElement(r(d[3]),(0,t.default)({scrollEventThrottle:1e-4},o,{ref:f}))});m.exports=r(d[4])(f,{collapsable:!1})},285,[3,29,129,250,239]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),n=(function(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var f=o(n);if(f&&f.has(t))return f.get(t);var u={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in t)if("default"!==l&&Object.prototype.hasOwnProperty.call(t,l)){var p=c?Object.getOwnPropertyDescriptor(t,l):null;p&&(p.get||p.set)?Object.defineProperty(u,l,p):u[l]=t[l]}u.default=t,f&&f.set(t,u);return u})(r(d[2])),f=r(d[0])(r(d[3]));function o(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,f=new WeakMap;return(o=function(t){return t?f:n})(t)}var u=n.forwardRef(function(o,u){return n.createElement(f.default,(0,t.default)({scrollEventThrottle:1e-4},o,{ref:u}))});m.exports=r(d[4])(u)},286,[3,29,129,287,239]); -__d(function(g,r,i,a,m,_e,d){'use strict';Object.defineProperty(_e,"__esModule",{value:!0}),_e.default=void 0;var e=r(d[0])(r(d[1])),t=r(d[0])(r(d[2])),n=r(d[0])(r(d[3])),o=r(d[0])(r(d[4])),f=r(d[0])(r(d[5])),u=r(d[0])(r(d[6])),c=r(d[0])(r(d[7])),l=r(d[0])(r(d[8])),s=(function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=y(t);if(n&&n.has(e))return n.get(e);var o={},f=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var u in e)if("default"!==u&&Object.prototype.hasOwnProperty.call(e,u)){var c=f?Object.getOwnPropertyDescriptor(e,u):null;c&&(c.get||c.set)?Object.defineProperty(o,u,c):o[u]=e[u]}o.default=e,n&&n.set(e,o);return o})(r(d[9])),p=r(d[0])(r(d[10])),v=["stickySectionHeadersEnabled"];function y(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(y=function(e){return e?n:t})(e)}function h(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}var R=(function(y){(0,f.default)(w,y);var R,_,L=(R=w,_=h(),function(){var e,t=(0,c.default)(R);if(_){var n=(0,c.default)(this).constructor;e=Reflect.construct(t,arguments,n)}else e=t.apply(this,arguments);return(0,u.default)(this,e)});function w(){var e;(0,n.default)(this,w);for(var t=arguments.length,o=new Array(t),f=0;f=e.length?{done:!0}:{done:!1,value:e[i++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function I(e,t){if(e){if("string"==typeof e)return _(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?_(e,t):void 0}}function _(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,i=new Array(t);n0&&this.props.stickySectionHeadersEnabled)o+=this._listRef._getFrameMetricsApprox(t-e.itemIndex).length;var l=(0,n.default)({},e,{viewOffset:o,index:t});this._listRef.scrollToIndex(l)}}},{key:"getListRef",value:function(){return this._listRef}},{key:"render",value:function(){for(var e,i=this,o=this.props,l=(o.ItemSeparatorComponent,o.SectionSeparatorComponent,o.renderItem,o.renderSectionFooter,o.renderSectionHeader,o.sections,o.stickySectionHeadersEnabled,(0,t.default)(o,v)),u=this.props.ListHeaderComponent?1:0,c=this.props.stickySectionHeadersEnabled?[]:void 0,s=0,p=S(this.props.sections);!(e=p()).done;){var y=e.value;null!=c&&c.push(s+u),s+=2,s+=this.props.getItemCount(y.data)}var I=this._renderItem(s);return h.createElement(f.VirtualizedList,(0,n.default)({},l,{keyExtractor:this._keyExtractor,stickyHeaderIndices:c,renderItem:I,data:this.props.sections,getItem:function(e,t){return i._getItem(i.props,e,t)},getItemCount:function(){return s},onViewableItemsChanged:this.props.onViewableItemsChanged?this._onViewableItemsChanged:void 0,ref:this._captureRef}))}},{key:"_getItem",value:function(e,t,n){if(!t)return null;for(var i=n-1,o=0;o=o(p)+1)t-=o(p)+1;else return-1===t?{section:s,key:f+':header',index:null,header:!0,trailingSection:u[c+1]}:t===o(p)?{section:s,key:f+':footer',index:null,header:!1,trailingSection:u[c+1]}:{section:s,key:f+':'+(s.keyExtractor||l||r(d[13]).keyExtractor)(i(p,t),t),index:t,leadingItem:i(p,t-1),leadingSection:u[c-1],trailingItem:i(p,t+1),trailingSection:u[c+1]}}}},{key:"_getSeparatorComponent",value:function(e,t,n){if(!(t=t||this._subExtractor(e)))return null;var i=t.section.ItemSeparatorComponent||this.props.ItemSeparatorComponent,o=this.props.SectionSeparatorComponent,l=e===n-1,u=t.index===this.props.getItemCount(t.section.data)-1;return o&&u?o:!i||u||l?null:i}}]),x})(h.PureComponent);function k(t){var i=t.LeadingSeparatorComponent,o=t.SeparatorComponent,l=t.cellKey,u=t.prevCellKey,c=t.setSelfHighlightCallback,s=t.updateHighlightFor,p=t.setSelfUpdatePropsCallback,v=t.updatePropsFor,y=t.item,S=t.index,I=t.section,_=t.inverted,b=h.useState(!1),x=(0,e.default)(b,2),k=x[0],C=x[1],E=h.useState(!1),w=(0,e.default)(E,2),H=w[0],P=w[1],F=h.useState({leadingItem:t.leadingItem,leadingSection:t.leadingSection,section:t.section,trailingItem:t.item,trailingSection:t.trailingSection}),R=(0,e.default)(F,2),M=R[0],O=R[1],V=h.useState({leadingItem:t.item,leadingSection:t.leadingSection,section:t.section,trailingItem:t.trailingItem,trailingSection:t.trailingSection}),j=(0,e.default)(V,2),A=j[0],U=j[1];h.useEffect(function(){return c(l,P),p(l,U),function(){p(l,null),c(l,null)}},[l,c,U,p]);var L={highlight:function(){C(!0),P(!0),null!=u&&s(u,!0)},unhighlight:function(){C(!1),P(!1),null!=u&&s(u,!1)},updateProps:function(e,t){'leading'===e?null!=i?O((0,n.default)({},M,t)):null!=u&&v(u,(0,n.default)({},M,t)):'trailing'===e&&null!=o&&U((0,n.default)({},A,t))}},B=t.renderItem({item:y,index:S,section:I,separators:L}),K=null!=i&&h.createElement(i,(0,n.default)({highlighted:k},M)),T=null!=o&&h.createElement(o,(0,n.default)({highlighted:H},A));return K||T?h.createElement(f.View,null,!1===_?K:T,B,!1===_?T:K):B}m.exports=x},288,[3,23,103,29,7,8,14,10,12,15,18,1,129,248]); -__d(function(g,r,i,a,m,e,d){!(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var f=t(o);if(f&&f.has(n))return f.get(n);var u={},p=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in n)if("default"!==c&&Object.prototype.hasOwnProperty.call(n,c)){var l=p?Object.getOwnPropertyDescriptor(n,c):null;l&&(l.get||l.set)?Object.defineProperty(u,c,l):u[c]=n[c]}u.default=n,f&&f.set(n,u)})(r(d[0]));function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,f=new WeakMap;return(t=function(t){return t?f:o})(n)}m.exports=r(d[1])(r(d[2]),{collapsable:!1})},289,[129,239,184]); -__d(function(g,r,i,a,m,e,d){!(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var f=t(o);if(f&&f.has(n))return f.get(n);var u={},p=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in n)if("default"!==c&&Object.prototype.hasOwnProperty.call(n,c)){var l=p?Object.getOwnPropertyDescriptor(n,c):null;l&&(l.get||l.set)?Object.defineProperty(u,c,l):u[c]=n[c]}u.default=n,f&&f.set(n,u)})(r(d[0]));function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,f=new WeakMap;return(t=function(t){return t?f:o})(n)}m.exports=r(d[1])(r(d[2]),{collapsable:!0})},290,[129,239,174]); -__d(function(g,r,i,a,m,e,d){'use strict';var n={};m.exports=function(o,t){n[o]||(console.warn(t),n[o]=!0)}},291,[]); -__d(function(g,r,i,a,m,_e,d){'use strict';var e=r(d[0])(r(d[1])),t=r(d[0])(r(d[2])),n=r(d[0])(r(d[3])),o=r(d[0])(r(d[4])),u=r(d[0])(r(d[5])),c=(function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=p(t);if(n&&n.has(e))return n.get(e);var o={},u=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in e)if("default"!==c&&Object.prototype.hasOwnProperty.call(e,c)){var f=u?Object.getOwnPropertyDescriptor(e,c):null;f&&(f.get||f.set)?Object.defineProperty(o,c,f):o[c]=e[c]}o.default=e,n&&n.set(e,o);return o})(r(d[6])),f=r(d[0])(r(d[7])),l=r(d[0])(r(d[8])),s=r(d[0])(r(d[9]));function p(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(p=function(e){return e?n:t})(e)}function y(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}var h=(function(f){(0,n.default)(b,f);var p,h,O=(p=b,h=y(),function(){var e,t=(0,u.default)(p);if(h){var n=(0,u.default)(this).constructor;e=Reflect.construct(t,arguments,n)}else e=t.apply(this,arguments);return(0,o.default)(this,e)});function b(){return(0,e.default)(this,b),O.apply(this,arguments)}return(0,t.default)(b,[{key:"render",value:function(){return c.createElement(s.default,{style:[v.dummyDatePickerIOS,this.props.style]},c.createElement(l.default,{style:v.datePickerText},"DatePickerIOS is not supported on this platform!"))}}]),b})(c.Component),v=f.default.create({dummyDatePickerIOS:{height:100,width:300,backgroundColor:'#ffbcbc',borderWidth:1,borderColor:'red',alignItems:'center',justifyContent:'center',margin:10},datePickerText:{color:'#333333',margin:20}});m.exports=h},292,[3,7,8,10,12,15,129,173,184,174]); -__d(function(g,r,i,a,m,_e,d){var e=r(d[0])(r(d[1])),t=r(d[0])(r(d[2])),n=r(d[0])(r(d[3])),o=r(d[0])(r(d[4])),u=r(d[0])(r(d[5])),s=r(d[0])(r(d[6])),l=r(d[0])(r(d[7])),f=r(d[0])(r(d[8])),c=k(r(d[9])),p=r(d[0])(r(d[10])),w=r(d[0])(r(d[11])),h=r(d[0])(r(d[12])),v=r(d[0])(r(d[13])),y=r(d[0])(r(d[14])),D=k(r(d[15])),b=["onDrawerStateChanged","renderNavigationView","onDrawerOpen","onDrawerClose"];function C(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(C=function(e){return e?n:t})(e)}function k(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=C(t);if(n&&n.has(e))return n.get(e);var o={},u=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var s in e)if("default"!==s&&Object.prototype.hasOwnProperty.call(e,s)){var l=u?Object.getOwnPropertyDescriptor(e,s):null;l&&(l.get||l.set)?Object.defineProperty(o,s,l):o[s]=e[s]}return o.default=e,n&&n.set(e,o),o}function _(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}var S=['Idle','Dragging','Settling'],R=(function(w){(0,u.default)(O,w);var C,k,R=(C=O,k=_(),function(){var e,t=(0,l.default)(C);if(k){var n=(0,l.default)(this).constructor;e=Reflect.construct(t,arguments,n)}else e=t.apply(this,arguments);return(0,s.default)(this,e)});function O(){var e;(0,n.default)(this,O);for(var t=arguments.length,o=new Array(t),u=0;u=21&&null!=this.props.statusBarBackgroundColor,l=c.createElement(h.default,{style:[B.drawerSubview,{width:this.props.drawerWidth,backgroundColor:this.props.drawerBackgroundColor}],collapsable:!1},o(),s&&c.createElement(h.default,{style:B.drawerStatusBar})),w=c.createElement(h.default,{style:B.mainSubview,collapsable:!1},s&&c.createElement(p.default,{translucent:!0,backgroundColor:this.props.statusBarBackgroundColor}),s&&c.createElement(h.default,{style:[B.statusBar,{backgroundColor:this.props.statusBarBackgroundColor}]}),this.props.children);return c.createElement(D.default,(0,e.default)({},u,{ref:this._nativeRef,drawerWidth:this.props.drawerWidth,drawerPosition:this.props.drawerPosition,drawerLockMode:this.props.drawerLockMode,style:[B.base,this.props.style],onDrawerSlide:this._onDrawerSlide,onDrawerOpen:this._onDrawerOpen,onDrawerClose:this._onDrawerClose,onDrawerStateChanged:this._onDrawerStateChanged}),w,l)}},{key:"openDrawer",value:function(){D.Commands.openDrawer((0,y.default)(this._nativeRef.current))}},{key:"closeDrawer",value:function(){D.Commands.closeDrawer((0,y.default)(this._nativeRef.current))}},{key:"blur",value:function(){(0,y.default)(this._nativeRef.current).blur()}},{key:"focus",value:function(){(0,y.default)(this._nativeRef.current).focus()}},{key:"measure",value:function(e){(0,y.default)(this._nativeRef.current).measure(e)}},{key:"measureInWindow",value:function(e){(0,y.default)(this._nativeRef.current).measureInWindow(e)}},{key:"measureLayout",value:function(e,t,n){(0,y.default)(this._nativeRef.current).measureLayout(e,t,n)}},{key:"setNativeProps",value:function(e){(0,y.default)(this._nativeRef.current).setNativeProps(e)}}],[{key:"positions",get:function(){return console.warn('Setting DrawerLayoutAndroid drawerPosition using `DrawerLayoutAndroid.positions` is deprecated. Instead pass the string value "left" or "right"'),{Left:'left',Right:'right'}}}]),O})(c.Component);R.defaultProps={drawerBackgroundColor:'white'};var B=w.default.create({base:{flex:1,elevation:16},mainSubview:{position:'absolute',top:0,left:0,right:0,bottom:0},drawerSubview:{position:'absolute',top:0,bottom:0},statusBar:{height:p.default.currentHeight},drawerStatusBar:{position:'absolute',top:0,left:0,right:0,height:p.default.currentHeight,backgroundColor:'rgba(0, 0, 0, 0.251)'}});m.exports=R},293,[3,29,103,7,8,10,12,15,19,129,294,173,174,254,297,298]); -__d(function(g,r,i,a,m,_e,d){var t,e=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),l=r(d[0])(r(d[3])),o=r(d[0])(r(d[4])),u=r(d[0])(r(d[5])),c=r(d[0])(r(d[6])),s=(function(t,e){if(!e&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var n=S(e);if(n&&n.has(t))return n.get(t);var l={},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var u in t)if("default"!==u&&Object.prototype.hasOwnProperty.call(t,u)){var c=o?Object.getOwnPropertyDescriptor(t,u):null;c&&(c.get||c.set)?Object.defineProperty(l,u,c):l[u]=t[u]}l.default=t,n&&n.set(t,l);return l})(r(d[7])),f=r(d[0])(r(d[8])),p=r(d[0])(r(d[9])),y=r(d[0])(r(d[10])),v=r(d[0])(r(d[11])),k=r(d[0])(r(d[12]));function S(t){if("function"!=typeof WeakMap)return null;var e=new WeakMap,n=new WeakMap;return(S=function(t){return t?n:e})(t)}function b(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}function _(t){var e,n,l=null!=(e=t.animated)&&e,o=null!=(n=t.showHideTransition)?n:'fade';return{backgroundColor:null!=t.backgroundColor?{value:t.backgroundColor,animated:l}:null,barStyle:null!=t.barStyle?{value:t.barStyle,animated:l}:null,translucent:t.translucent,hidden:null!=t.hidden?{value:t.hidden,animated:l,transition:o}:null,networkActivityIndicatorVisible:t.networkActivityIndicatorVisible}}var h=(function(t){(0,l.default)(h,t);var c,s,S=(c=h,s=b(),function(){var t,e=(0,u.default)(c);if(s){var n=(0,u.default)(this).constructor;t=Reflect.construct(e,arguments,n)}else t=e.apply(this,arguments);return(0,o.default)(this,t)});function h(){var t;(0,e.default)(this,h);for(var n=arguments.length,l=new Array(n),o=0;o is only supported on iOS.'),0===c.Children.count(this.props.children)?null:c.createElement(s.default,{style:[this.props.style,v.container],nativeID:this.props.nativeID,backgroundColor:this.props.backgroundColor},this.props.children)}}]),b})(c.Component),v=l.default.create({container:{position:'absolute'}});m.exports=h},300,[3,7,8,10,12,15,129,19,173,301]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var t=(0,r(d[0])(r(d[1])).default)('InputAccessory',{interfaceOnly:!0,paperComponentName:'RCTInputAccessoryView',excludedPlatforms:['android']});e.default=t},301,[3,179]); -__d(function(g,r,i,a,m,_e,d){Object.defineProperty(_e,"__esModule",{value:!0}),_e.default=void 0;var e=r(d[0])(r(d[1])),t=r(d[0])(r(d[2])),n=r(d[0])(r(d[3])),o=r(d[0])(r(d[4])),u=r(d[0])(r(d[5])),f=r(d[0])(r(d[6])),l=r(d[0])(r(d[7])),s=r(d[0])(r(d[8])),c=r(d[0])(r(d[9])),y=r(d[0])(r(d[10])),h=(function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=_(t);if(n&&n.has(e))return n.get(e);var o={},u=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var f in e)if("default"!==f&&Object.prototype.hasOwnProperty.call(e,f)){var l=u?Object.getOwnPropertyDescriptor(e,f):null;l&&(l.get||l.set)?Object.defineProperty(o,f,l):o[f]=e[f]}o.default=e,n&&n.set(e,o);return o})(r(d[11])),p=r(d[0])(r(d[12])),v=r(d[0])(r(d[13])),b=["behavior","children","contentContainerStyle","enabled","keyboardVerticalOffset","style"];function _(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(_=function(e){return e?n:t})(e)}function k(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}var O=(function(_){(0,u.default)(E,_);var O,w,L=(O=E,w=k(),function(){var e,t=(0,l.default)(O);if(w){var n=(0,l.default)(this).constructor;e=Reflect.construct(t,arguments,n)}else e=t.apply(this,arguments);return(0,f.default)(this,e)});function E(e){var t;return(0,n.default)(this,E),(t=L.call(this,e))._frame=null,t._keyboardEvent=null,t._subscriptions=[],t._initialFrameHeight=0,t._onKeyboardChange=function(e){t._keyboardEvent=e,t._updateBottomIfNecesarry()},t._onLayout=function(e){var n=null==t._frame;t._frame=e.nativeEvent.layout,t._initialFrameHeight||(t._initialFrameHeight=t._frame.height),n&&t._updateBottomIfNecesarry()},t._updateBottomIfNecesarry=function(){if(null!=t._keyboardEvent){var e=t._keyboardEvent,n=e.duration,o=e.easing,u=e.endCoordinates,f=t._relativeKeyboardHeight(u);t.state.bottom!==f&&(n&&o&&c.default.configureNext({duration:n>10?n:10,update:{duration:n>10?n:10,type:c.default.Types[o]||'keyboard'}}),t.setState({bottom:f}))}else t.setState({bottom:0})},t.state={bottom:0},t.viewRef=h.createRef(),t}return(0,o.default)(E,[{key:"_relativeKeyboardHeight",value:function(e){var t,n=this._frame;if(!n||!e)return 0;var o=e.screenY-(null!=(t=this.props.keyboardVerticalOffset)?t:0);return Math.max(n.y+n.height-o,0)}},{key:"componentDidMount",value:function(){'ios'===y.default.OS?this._subscriptions=[s.default.addListener('keyboardWillChangeFrame',this._onKeyboardChange)]:this._subscriptions=[s.default.addListener('keyboardDidHide',this._onKeyboardChange),s.default.addListener('keyboardDidShow',this._onKeyboardChange)]}},{key:"componentWillUnmount",value:function(){this._subscriptions.forEach(function(e){e.remove()})}},{key:"render",value:function(){var n=this.props,o=n.behavior,u=n.children,f=n.contentContainerStyle,l=n.enabled,s=void 0===l||l,c=(n.keyboardVerticalOffset,n.style),y=(0,t.default)(n,b),_=!0===s?this.state.bottom:0;switch(o){case'height':var k;return null!=this._frame&&this.state.bottom>0&&(k={height:this._initialFrameHeight-_,flex:0}),h.createElement(v.default,(0,e.default)({ref:this.viewRef,style:p.default.compose(c,k),onLayout:this._onLayout},y),u);case'position':return h.createElement(v.default,(0,e.default)({ref:this.viewRef,style:c,onLayout:this._onLayout},y),h.createElement(v.default,{style:p.default.compose(f,{bottom:_})},u));case'padding':return h.createElement(v.default,(0,e.default)({ref:this.viewRef,style:p.default.compose(c,{paddingBottom:_}),onLayout:this._onLayout},y),u);default:return h.createElement(v.default,(0,e.default)({ref:this.viewRef,onLayout:this._onLayout,style:c},y),u)}}}]),E})(h.Component);_e.default=O},302,[3,29,103,7,8,10,12,15,252,253,19,129,173,174]); -__d(function(g,r,i,a,m,e,d){'use strict';m.exports=r(d[0])},303,[304]); -__d(function(g,r,i,a,m,_e,d){'use strict';var e=r(d[0])(r(d[1])),t=r(d[0])(r(d[2])),n=r(d[0])(r(d[3])),u=r(d[0])(r(d[4])),o=r(d[0])(r(d[5])),f=(function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=l(t);if(n&&n.has(e))return n.get(e);var u={},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var f in e)if("default"!==f&&Object.prototype.hasOwnProperty.call(e,f)){var c=o?Object.getOwnPropertyDescriptor(e,f):null;c&&(c.get||c.set)?Object.defineProperty(u,f,c):u[f]=e[f]}u.default=e,n&&n.set(e,u);return u})(r(d[6])),c=r(d[0])(r(d[7]));function l(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(l=function(e){return e?n:t})(e)}function p(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}var s=(function(c){(0,n.default)(h,c);var l,s,v=(l=h,s=p(),function(){var e,t=(0,o.default)(l);if(s){var n=(0,o.default)(this).constructor;e=Reflect.construct(t,arguments,n)}else e=t.apply(this,arguments);return(0,u.default)(this,e)});function h(){return(0,e.default)(this,h),v.apply(this,arguments)}return(0,t.default)(h,[{key:"render",value:function(){var e=r(d[8]);return f.createElement(e,{style:[y.unimplementedView,this.props.style]},this.props.children)}}]),h})(f.Component),y=c.default.create({unimplementedView:{}});m.exports=s},304,[3,7,8,10,12,15,129,173,174]); -__d(function(g,r,i,a,m,_e,d){var t,e,n=r(d[0])(r(d[1])),o=r(d[0])(r(d[2])),s=r(d[0])(r(d[3])),l=r(d[0])(r(d[4])),u=r(d[0])(r(d[5])),p=r(d[0])(r(d[6])),c=r(d[0])(r(d[7])),f=(r(d[0])(r(d[8])),r(d[0])(r(d[9])),r(d[0])(r(d[10])));function h(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var v=r(d[11]),y=0,R=(function(t){(0,l.default)(R,t);var e,n,c=(e=R,n=h(),function(){var t,o=(0,p.default)(e);if(n){var s=(0,p.default)(this).constructor;t=Reflect.construct(o,arguments,s)}else t=o.apply(this,arguments);return(0,u.default)(this,t)});function R(t){var e;return(0,o.default)(this,R),(e=c.call(this,t))._identifier=y++,e}return(0,s.default)(R,[{key:"componentDidMount",value:function(){}},{key:"componentWillUnmount",value:function(){this._eventSubscription&&this._eventSubscription.remove()}},{key:"componentDidUpdate",value:function(){}},{key:"render",value:function(){var t=this;if(!0!==this.props.visible)return null;var e={backgroundColor:!0===this.props.transparent?'transparent':'white'},n=this.props.animationType||'none',o=this.props.presentationStyle;o||(o='fullScreen',!0===this.props.transparent&&(o='overFullScreen'));var s=this.props.children;return v.createElement(f.default,{animationType:n,presentationStyle:o,transparent:this.props.transparent,hardwareAccelerated:this.props.hardwareAccelerated,onRequestClose:this.props.onRequestClose,onShow:this.props.onShow,onDismiss:function(){t.props.onDismiss&&t.props.onDismiss()},visible:this.props.visible,statusBarTranslucent:this.props.statusBarTranslucent,identifier:this._identifier,style:b.modal,onStartShouldSetResponder:this._shouldSetResponder,supportedOrientations:this.props.supportedOrientations,onOrientationChange:this.props.onOrientationChange},v.createElement(r(d[12]).VirtualizedListContextResetter,null,v.createElement(r(d[13]).Context.Provider,{value:null},v.createElement(r(d[14]),{style:[b.container,e],collapsable:!1},s))))}},{key:"_shouldSetResponder",value:function(){return!0}}]),R})(v.Component);R.defaultProps={visible:!0,hardwareAccelerated:!1},R.contextType=r(d[15]).RootTagContext;var S=r(d[16]).getConstants().isRTL?'right':'left',b=r(d[17]).create({modal:{position:'absolute'},container:(t={},(0,n.default)(t,S,0),(0,n.default)(t,"top",0),(0,n.default)(t,"flex",1),t)}),C=null!=(e=c.default.unstable_Modal)?e:R;m.exports=C},305,[3,247,7,8,10,12,15,306,95,307,308,129,273,250,174,309,310,173]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;e.default={unstable_Modal:null}},306,[]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in n)if("default"!==c&&Object.prototype.hasOwnProperty.call(n,c)){var p=l?Object.getOwnPropertyDescriptor(n,c):null;p&&(p.get||p.set)?Object.defineProperty(f,c,p):f[c]=n[c]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).get('ModalManager');e.default=n},307,[21]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var o=(0,r(d[0])(r(d[1])).default)('ModalHostView',{interfaceOnly:!0,paperComponentName:'RCTModalHostView'});e.default=o},308,[3,179]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.RootTagContext=void 0,e.createRootTag=function(t){return t};var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var p in n)if("default"!==p&&Object.prototype.hasOwnProperty.call(n,p)){var l=c?Object.getOwnPropertyDescriptor(n,p):null;l&&(l.get||l.set)?Object.defineProperty(f,p,l):f[p]=n[p]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).createContext(0);e.RootTagContext=n},309,[129]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),n=(function(){if(t.default){var n=t.default.getConstants(),f=n.isRTL,L=n.doLeftAndRightSwapInRTL,R=n.localeIdentifier;return{isRTL:f,doLeftAndRightSwapInRTL:L,localeIdentifier:R}}return{isRTL:!1,doLeftAndRightSwapInRTL:!0}})();m.exports={getConstants:function(){return n},allowRTL:function(n){t.default&&t.default.allowRTL(n)},forceRTL:function(n){t.default&&t.default.forceRTL(n)},swapLeftAndRightInRTL:function(n){t.default&&t.default.swapLeftAndRightInRTL(n)},isRTL:n.isRTL,doLeftAndRightSwapInRTL:n.doLeftAndRightSwapInRTL}},310,[3,311]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in n)if("default"!==l&&Object.prototype.hasOwnProperty.call(n,l)){var p=c?Object.getOwnPropertyDescriptor(n,l):null;p&&(p.get||p.set)?Object.defineProperty(f,l,p):f[l]=n[l]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).get('I18nManager');e.default=n},311,[21]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=r(d[0])(r(d[1])),s=r(d[0])(r(d[2])),t=r(d[0])(r(d[3])),l=(function(n,s){if(!s&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var t=p(s);if(t&&t.has(n))return t.get(n);var l={},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var u in n)if("default"!==u&&Object.prototype.hasOwnProperty.call(n,u)){var f=o?Object.getOwnPropertyDescriptor(n,u):null;f&&(f.get||f.set)?Object.defineProperty(l,u,f):l[u]=n[u]}l.default=n,t&&t.set(n,l);return l})(r(d[4])),o=r(d[0])(r(d[5])),u=r(d[0])(r(d[6])),f=r(d[0])(r(d[7])),c=["accessible","android_disableSound","android_ripple","cancelable","children","delayLongPress","disabled","focusable","onLongPress","onPress","onPressIn","onPressOut","pressRetentionOffset","style","testOnly_pressed","unstable_pressDelay"];function p(n){if("function"!=typeof WeakMap)return null;var s=new WeakMap,t=new WeakMap;return(p=function(n){return n?t:s})(n)}function b(n){var t=(0,l.useState)(!1),o=(0,s.default)(t,2),u=o[0],f=o[1];return[u||n,f]}var P=l.memo(l.forwardRef(function(p,P){var y=p.accessible,v=p.android_disableSound,O=p.android_ripple,_=p.cancelable,S=p.children,M=p.delayLongPress,h=p.disabled,j=p.focusable,w=p.onLongPress,I=p.onPress,L=p.onPressIn,R=p.onPressOut,D=p.pressRetentionOffset,k=p.style,W=p.testOnly_pressed,z=p.unstable_pressDelay,E=(0,t.default)(p,c),H=(0,l.useRef)(null);(0,l.useImperativeHandle)(P,function(){return H.current});var N=(0,o.default)(O,H),q=b(!0===W),x=(0,s.default)(q,2),A=x[0],B=x[1],C=(0,r(d[8]).normalizeRect)(p.hitSlop),F=null!=h?(0,n.default)({},p.accessibilityState,{disabled:h}):p.accessibilityState,G=(0,n.default)({},E,null==N?void 0:N.viewProps,{accessible:!1!==y,accessibilityState:F,focusable:!1!==j,hitSlop:C}),J=(0,l.useMemo)(function(){return{cancelable:_,disabled:h,hitSlop:C,pressRectOffset:D,android_disableSound:v,delayLongPress:M,delayPressIn:z,onLongPress:w,onPress:I,onPressIn:function(n){null!=N&&N.onPressIn(n),B(!0),null!=L&&L(n)},onPressMove:null==N?void 0:N.onPressMove,onPressOut:function(n){null!=N&&N.onPressOut(n),B(!1),null!=R&&R(n)}}},[v,N,_,M,h,C,w,I,L,R,D,B,z]),K=(0,u.default)(J);return l.createElement(f.default,(0,n.default)({},G,K,{ref:H,style:'function'==typeof k?k({pressed:A}):k,collapsable:!1}),'function'==typeof S?S({pressed:A}):S,null)}));P.displayName='Pressable';var y=P;e.default=y},312,[3,29,23,103,129,313,200,174,206]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=function(l,u){var s=null!=l?l:{},c=s.color,f=s.borderless,p=s.radius,v=s.foreground;return(0,o.useMemo)(function(){if('android'===t.Platform.OS&&t.Platform.Version>=21&&(null!=c||null!=f||null!=p)){var o=(0,t.processColor)(c);(0,n.default)(null==o||'number'==typeof o,'Unexpected color given for Ripple color');var l={type:'RippleAndroid',color:o,borderless:!0===f,rippleRadius:p};return{viewProps:!0===v?{nativeForegroundAndroid:l}:{nativeBackgroundAndroid:l},onPressIn:function(n){var t,o,l=u.current;null!=l&&(r(d[4]).Commands.hotspotUpdate(l,null!=(t=n.nativeEvent.locationX)?t:0,null!=(o=n.nativeEvent.locationY)?o:0),r(d[4]).Commands.setPressed(l,!0))},onPressMove:function(n){var t,o,l=u.current;null!=l&&r(d[4]).Commands.hotspotUpdate(l,null!=(t=n.nativeEvent.locationX)?t:0,null!=(o=n.nativeEvent.locationY)?o:0)},onPressOut:function(n){var t=u.current;null!=t&&r(d[4]).Commands.setPressed(t,!1)}}}return null},[f,c,v,p,u])};var n=r(d[0])(r(d[1])),t=r(d[2]),o=(function(n,t){if(!t&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var o=l(t);if(o&&o.has(n))return o.get(n);var u={},s=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in n)if("default"!==c&&Object.prototype.hasOwnProperty.call(n,c)){var f=s?Object.getOwnPropertyDescriptor(n,c):null;f&&(f.get||f.set)?Object.defineProperty(u,c,f):u[c]=n[c]}u.default=n,o&&o.set(n,u);return u})(r(d[3]));function l(n){if("function"!=typeof WeakMap)return null;var t=new WeakMap,o=new WeakMap;return(l=function(n){return n?o:t})(n)}},313,[3,18,1,129,175]); -__d(function(g,r,i,a,m,_e,d){'use strict';var t=r(d[0])(r(d[1])),e=r(d[0])(r(d[2])),n=r(d[0])(r(d[3])),o=r(d[0])(r(d[4])),u=r(d[0])(r(d[5])),f=(function(t,e){if(!e&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var n=p(e);if(n&&n.has(t))return n.get(t);var o={},u=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var f in t)if("default"!==f&&Object.prototype.hasOwnProperty.call(t,f)){var c=u?Object.getOwnPropertyDescriptor(t,f):null;c&&(c.get||c.set)?Object.defineProperty(o,f,c):o[f]=t[f]}o.default=t,n&&n.set(t,o);return o})(r(d[6])),c=r(d[0])(r(d[7])),l=r(d[0])(r(d[8])),s=r(d[0])(r(d[9]));function p(t){if("function"!=typeof WeakMap)return null;var e=new WeakMap,n=new WeakMap;return(p=function(t){return t?n:e})(t)}function y(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var h=(function(c){(0,n.default)(O,c);var p,h,b=(p=O,h=y(),function(){var t,e=(0,u.default)(p);if(h){var n=(0,u.default)(this).constructor;t=Reflect.construct(e,arguments,n)}else t=e.apply(this,arguments);return(0,o.default)(this,t)});function O(){return(0,t.default)(this,O),b.apply(this,arguments)}return(0,e.default)(O,[{key:"render",value:function(){return f.createElement(s.default,{style:[v.dummy,this.props.style]},f.createElement(l.default,{style:v.text},"ProgressViewIOS is not supported on this platform!"))}}]),O})(f.Component),v=c.default.create({dummy:{width:120,height:20,backgroundColor:'#ffbcbc',borderWidth:1,borderColor:'red',alignItems:'center',justifyContent:'center'},text:{color:'#333333',margin:5,fontSize:10}});m.exports=h},314,[3,7,8,10,12,15,129,173,184,174]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var t,n=r(d[0])(r(d[1])),u=r(d[0])(r(d[2])),f=r(d[0])(r(d[3])),o=(function(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var u=c(n);if(u&&u.has(t))return u.get(t);var f={},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in t)if("default"!==l&&Object.prototype.hasOwnProperty.call(t,l)){var p=o?Object.getOwnPropertyDescriptor(t,l):null;p&&(p.get||p.set)?Object.defineProperty(f,l,p):f[l]=t[l]}f.default=t,u&&u.set(t,f);return f})(r(d[4])),l=r(d[0])(r(d[5])),p=["emulateUnlessSupported"];function c(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,u=new WeakMap;return(c=function(t){return t?u:n})(t)}if('android'===f.default.OS)t=o.forwardRef(function(t,f){t.emulateUnlessSupported;var c=(0,u.default)(t,p);return o.createElement(l.default,(0,n.default)({},c,{ref:f}))});else{var s=r(d[6]).default;t=o.forwardRef(function(t,u){return o.createElement(s,(0,n.default)({emulateUnlessSupported:!0},t,{ref:u}))})}var v=t;e.default=v},315,[3,29,103,19,129,174,316]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var f=(0,r(d[0])(r(d[1])).default)('SafeAreaView',{paperComponentName:'RCTSafeAreaView',interfaceOnly:!0});e.default=f},316,[3,179]); -__d(function(g,r,i,a,m,_e,d){'use strict';var t=r(d[0])(r(d[1])),e=r(d[0])(r(d[2])),n=r(d[0])(r(d[3])),o=r(d[0])(r(d[4])),u=r(d[0])(r(d[5])),f=(function(t,e){if(!e&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var n=p(e);if(n&&n.has(t))return n.get(t);var o={},u=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var f in t)if("default"!==f&&Object.prototype.hasOwnProperty.call(t,f)){var c=u?Object.getOwnPropertyDescriptor(t,f):null;c&&(c.get||c.set)?Object.defineProperty(o,f,c):o[f]=t[f]}o.default=t,n&&n.set(t,o);return o})(r(d[6])),c=r(d[0])(r(d[7])),l=r(d[0])(r(d[8])),s=r(d[0])(r(d[9]));function p(t){if("function"!=typeof WeakMap)return null;var e=new WeakMap,n=new WeakMap;return(p=function(t){return t?n:e})(t)}function y(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var h=(function(c){(0,n.default)(O,c);var p,h,b=(p=O,h=y(),function(){var t,e=(0,u.default)(p);if(h){var n=(0,u.default)(this).constructor;t=Reflect.construct(e,arguments,n)}else t=e.apply(this,arguments);return(0,o.default)(this,t)});function O(){return(0,t.default)(this,O),b.apply(this,arguments)}return(0,e.default)(O,[{key:"render",value:function(){return f.createElement(s.default,{style:[v.dummy,this.props.style]},f.createElement(l.default,{style:v.text},"SegmentedControlIOS is not supported on this platform!"))}}]),O})(f.Component),v=c.default.create({dummy:{width:120,height:50,backgroundColor:'#ffbcbc',borderWidth:1,borderColor:'red',alignItems:'center',justifyContent:'center'},text:{color:'#333333',margin:5,fontSize:10}});m.exports=h},317,[3,7,8,10,12,15,129,173,184,174]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),l=(function(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var l=c(n);if(l&&l.has(t))return l.get(t);var u={},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var f in t)if("default"!==f&&Object.prototype.hasOwnProperty.call(t,f)){var s=o?Object.getOwnPropertyDescriptor(t,f):null;s&&(s.get||s.set)?Object.defineProperty(u,f,s):u[f]=t[f]}u.default=t,l&&l.set(t,u);return u})(r(d[3])),u=r(d[0])(r(d[4])),o=r(d[0])(r(d[5])),f=r(d[0])(r(d[6])),s=["value","minimumValue","maximumValue","step","onValueChange","onSlidingComplete"];function c(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,l=new WeakMap;return(c=function(t){return t?l:n})(t)}var v,p=l.forwardRef(function(c,p){var b,y=f.default.compose(v.slider,c.style),S=c.value,O=void 0===S?.5:S,h=c.minimumValue,V=void 0===h?0:h,C=c.maximumValue,j=void 0===C?1:C,w=c.step,E=void 0===w?0:w,P=c.onValueChange,x=c.onSlidingComplete,M=(0,n.default)(c,s),R=P?function(t){var n=!0;'android'===u.default.OS&&(n=null!=t.nativeEvent.fromUser&&t.nativeEvent.fromUser),n&&P(t.nativeEvent.value)}:null,_=R,k=x?function(t){x(t.nativeEvent.value)}:null,W=!0===c.disabled||!0===(null==(b=c.accessibilityState)?void 0:b.disabled),D=W?(0,t.default)({},c.accessibilityState,{disabled:!0}):c.accessibilityState;return l.createElement(o.default,(0,t.default)({},M,{accessibilityState:D,enabled:!W,disabled:W,maximumValue:j,minimumValue:V,onChange:_,onResponderTerminationRequest:function(){return!1},onSlidingComplete:k,onStartShouldSetResponder:function(){return!0},onValueChange:R,ref:p,step:E,style:y,value:O}))});v='ios'===u.default.OS?f.default.create({slider:{height:40}}):f.default.create({slider:{}}),m.exports=p},318,[3,29,103,129,19,319,173]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var l=(0,r(d[0])(r(d[1])).default)('Slider',{interfaceOnly:!0,paperComponentName:'RCTSlider'});e.default=l},319,[3,179]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),o=r(d[0])(r(d[3])),l=r(d[0])(r(d[4])),u=C(r(d[5])),f=r(d[0])(r(d[6])),c=r(d[0])(r(d[7])),s=C(r(d[8])),v=C(r(d[9])),b=["disabled","ios_backgroundColor","onChange","onValueChange","style","thumbColor","trackColor","value"];function p(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,o=new WeakMap;return(p=function(t){return t?o:n})(t)}function C(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var o=p(n);if(o&&o.has(t))return o.get(t);var l={},u=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var f in t)if("default"!==f&&Object.prototype.hasOwnProperty.call(t,f)){var c=u?Object.getOwnPropertyDescriptor(t,f):null;c&&(c.get||c.set)?Object.defineProperty(l,f,c):l[f]=t[f]}return l.default=t,o&&o.set(t,l),l}var h=function(){return!1},y=function(){return!0},R=u.forwardRef(function(p,C){var R=p.disabled,k=p.ios_backgroundColor,O=p.onChange,w=p.onValueChange,S=p.style,_=p.thumbColor,j=p.trackColor,P=p.value,T=(0,o.default)(p,b),E=null==j?void 0:j.false,M=null==j?void 0:j.true,V=u.useRef(null),F=(0,c.default)(V,C),W=u.useState({value:null}),q=(0,n.default)(W,2),D=q[0],N=q[1],L=function(t){null==O||O(t),null==w||w(t.nativeEvent.value),N({value:t.nativeEvent.value})};if(u.useLayoutEffect(function(){var t,n=!0===P;D.value!==n&&null!=(null==(t=V.current)?void 0:t.setNativeProps)&&('android'===l.default.OS?s.Commands.setNativeValue(V.current,n):v.Commands.setValue(V.current,n))},[P,D]),'android'===l.default.OS){var x,z={enabled:!0!==R,on:!0===P,style:S,thumbTintColor:_,trackColorForFalse:E,trackColorForTrue:M,trackTintColor:!0===P?M:E};return u.createElement(s.default,(0,t.default)({},T,z,{accessibilityRole:null!=(x=p.accessibilityRole)?x:'switch',onChange:L,onResponderTerminationRequest:h,onStartShouldSetResponder:y,ref:F}))}var A,B={disabled:R,onTintColor:M,style:f.default.compose({height:31,width:51},f.default.compose(S,null==k?null:{backgroundColor:k,borderRadius:16})),thumbTintColor:_,tintColor:E,value:!0===P};return u.createElement(v.default,(0,t.default)({},T,B,{accessibilityRole:null!=(A=p.accessibilityRole)?A:'switch',onChange:L,onResponderTerminationRequest:h,onStartShouldSetResponder:y,ref:F}))});e.default=R},320,[3,29,23,103,19,129,173,321,322,323]); -__d(function(g,r,_i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=function(){for(var o=arguments.length,u=new Array(o),i=0;i=t.length?{done:!0}:{done:!1,value:t[i++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function o(t,n){if(t){if("string"==typeof t)return u(t,n);var o=Object.prototype.toString.call(t).slice(8,-1);return"Object"===o&&t.constructor&&(o=t.constructor.name),"Map"===o||"Set"===o?Array.from(t):"Arguments"===o||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(o)?u(t,n):void 0}}function u(t,n){(null==n||n>t.length)&&(n=t.length);for(var o=0,u=new Array(n);o1&&(be=u.createElement(f.default,null,be)),oe=u.createElement(I,(0,t.default)({ref:ee},o,pe,{accessible:ce,autoCapitalize:ye,blurOnSubmit:ae,caretHidden:se,children:be,disableFullscreenUI:o.disableFullscreenUI,focusable:ie,mostRecentEventCount:H,onBlur:ue,onChange:te,onFocus:le,onScroll:re,onSelectionChange:ne,placeholder:Se,selection:M,style:Ce,text:X,textBreakStrategy:o.textBreakStrategy}))}return u.createElement(p.default.Provider,{value:!0},oe)}var M=u.forwardRef(function(l,o){var c=l.allowFontScaling,s=void 0===c||c,f=l.rejectResponderTermination,p=void 0===f||f,v=l.underlineColorAndroid,C=void 0===v?'transparent':v,y=(0,n.default)(l,F);return u.createElement(A,(0,t.default)({allowFontScaling:s,rejectResponderTermination:p,underlineColorAndroid:C},y,{forwardedRef:o}))});M.propTypes=o.default,M.State={currentlyFocusedInput:v.default.currentlyFocusedInput,currentlyFocusedField:v.default.currentlyFocusedField,focusTextInput:v.default.focusTextInput,blurTextInput:v.default.blurTextInput};var z=s.default.create({multilineInput:{paddingTop:5}});m.exports=M},324,[3,29,103,23,129,325,19,173,184,176,135,18,297,241,200,136,326,328]); -__d(function(g,r,i,a,m,e,d){'use strict';var n=['phoneNumber','link','address','calendarEvent','none','all'];m.exports=r(d[0])({},r(d[1]),{autoCapitalize:r(d[2]).oneOf(['none','sentences','words','characters']),autoComplete:r(d[2]).oneOf(['cc-csc','cc-exp','cc-exp-month','cc-exp-year','cc-number','email','name','password','postal-code','street-address','tel','username','off']),autoCorrect:r(d[2]).bool,spellCheck:r(d[2]).bool,autoFocus:r(d[2]).bool,allowFontScaling:r(d[2]).bool,maxFontSizeMultiplier:r(d[2]).number,editable:r(d[2]).bool,keyboardType:r(d[2]).oneOf(['default','email-address','numeric','phone-pad','number-pad','url','ascii-capable','numbers-and-punctuation','name-phone-pad','decimal-pad','twitter','web-search','ascii-capable-number-pad','visible-password']),keyboardAppearance:r(d[2]).oneOf(['default','light','dark']),returnKeyType:r(d[2]).oneOf(['done','go','next','search','send','none','previous','default','emergency-call','google','join','route','yahoo']),returnKeyLabel:r(d[2]).string,maxLength:r(d[2]).number,numberOfLines:r(d[2]).number,disableFullscreenUI:r(d[2]).bool,enablesReturnKeyAutomatically:r(d[2]).bool,multiline:r(d[2]).bool,textBreakStrategy:r(d[2]).oneOf(['simple','highQuality','balanced']),onBlur:r(d[2]).func,onFocus:r(d[2]).func,onChange:r(d[2]).func,onChangeText:r(d[2]).func,onContentSizeChange:r(d[2]).func,onTextInput:r(d[2]).func,onEndEditing:r(d[2]).func,onSelectionChange:r(d[2]).func,onSubmitEditing:r(d[2]).func,onKeyPress:r(d[2]).func,onLayout:r(d[2]).func,onScroll:r(d[2]).func,placeholder:r(d[2]).string,placeholderTextColor:r(d[3]),scrollEnabled:r(d[2]).bool,secureTextEntry:r(d[2]).bool,selectionColor:r(d[3]),selection:r(d[2]).shape({start:r(d[2]).number.isRequired,end:r(d[2]).number}),value:r(d[2]).string,defaultValue:r(d[2]).string,clearButtonMode:r(d[2]).oneOf(['never','while-editing','unless-editing','always']),clearTextOnFocus:r(d[2]).bool,selectTextOnFocus:r(d[2]).bool,blurOnSubmit:r(d[2]).bool,style:r(d[4]).style,underlineColorAndroid:r(d[3]),inlineImageLeft:r(d[2]).string,inlineImagePadding:r(d[2]).number,rejectResponderTermination:r(d[2]).bool,dataDetectorTypes:r(d[2]).oneOfType([r(d[2]).oneOf(n),r(d[2]).arrayOf(r(d[2]).oneOf(n))]),caretHidden:r(d[2]).bool,contextMenuHidden:r(d[2]).bool,inputAccessoryViewID:r(d[2]).string,textContentType:r(d[2]).oneOf(['none','URL','addressCity','addressCityAndState','addressState','countryName','creditCardNumber','emailAddress','familyName','fullStreetAddress','givenName','jobTitle','location','middleName','name','namePrefix','nameSuffix','nickname','organizationName','postalCode','streetAddressLine1','streetAddressLine2','sublocality','telephoneNumber','username','password','newPassword','oneTimeCode']),showSoftInputOnFocus:r(d[2]).bool})},325,[29,277,191,195,185]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=e.Commands=void 0;var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),u=(function(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var u=o(n);if(u&&u.has(t))return u.get(t);var f={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in t)if("default"!==c&&Object.prototype.hasOwnProperty.call(t,c)){var p=l?Object.getOwnPropertyDescriptor(t,c):null;p&&(p.get||p.set)?Object.defineProperty(f,c,p):f[c]=t[c]}f.default=t,u&&u.set(t,f);return f})(r(d[3]));function o(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,u=new WeakMap;return(o=function(t){return t?u:n})(t)}var f=(0,t.default)({supportedCommands:['focus','blur','setTextAndSelection']});e.Commands=f;var l=u.get('RCTSinglelineTextInputView',function(){return n.default});e.default=l},326,[3,137,327,150]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),o=r(d[0])(r(d[2])),n={uiViewClassName:'RCTSinglelineTextInputView',bubblingEventTypes:{topBlur:{phasedRegistrationNames:{bubbled:'onBlur',captured:'onBlurCapture'}},topChange:{phasedRegistrationNames:{bubbled:'onChange',captured:'onChangeCapture'}},topEndEditing:{phasedRegistrationNames:{bubbled:'onEndEditing',captured:'onEndEditingCapture'}},topFocus:{phasedRegistrationNames:{bubbled:'onFocus',captured:'onFocusCapture'}},topKeyPress:{phasedRegistrationNames:{bubbled:'onKeyPress',captured:'onKeyPressCapture'}},topSubmitEditing:{phasedRegistrationNames:{bubbled:'onSubmitEditing',captured:'onSubmitEditingCapture'}},topTouchCancel:{phasedRegistrationNames:{bubbled:'onTouchCancel',captured:'onTouchCancelCapture'}},topTouchEnd:{phasedRegistrationNames:{bubbled:'onTouchEnd',captured:'onTouchEndCapture'}},topTouchMove:{phasedRegistrationNames:{bubbled:'onTouchMove',captured:'onTouchMoveCapture'}}},directEventTypes:{},validAttributes:(0,t.default)({},o.default.validAttributes,{fontSize:!0,fontWeight:!0,fontVariant:!0,textShadowOffset:{diff:r(d[3])},allowFontScaling:!0,fontStyle:!0,textTransform:!0,textAlign:!0,fontFamily:!0,lineHeight:!0,isHighlighted:!0,writingDirection:!0,textDecorationLine:!0,textShadowRadius:!0,letterSpacing:!0,textDecorationStyle:!0,textDecorationColor:{process:r(d[4])},color:{process:r(d[4])},maxFontSizeMultiplier:!0,textShadowColor:{process:r(d[4])},editable:!0,inputAccessoryViewID:!0,caretHidden:!0,enablesReturnKeyAutomatically:!0,placeholderTextColor:{process:r(d[4])},onSelectionChange:!0,clearButtonMode:!0,onContentSizeChange:!0,keyboardType:!0,selection:!0,returnKeyType:!0,blurOnSubmit:!0,mostRecentEventCount:!0,onChange:!0,scrollEnabled:!0,selectionColor:{process:r(d[4])},contextMenuHidden:!0,secureTextEntry:!0,onTextInput:!0,placeholder:!0,autoCorrect:!0,onScroll:!0,multiline:!0,textContentType:!0,maxLength:!0,autoCapitalize:!0,keyboardAppearance:!0,passwordRules:!0,spellCheck:!0,selectTextOnFocus:!0,text:!0,clearTextOnFocus:!0})};m.exports=n},327,[3,29,139,146,141]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=e.Commands=void 0;var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),u=(function(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var u=o(n);if(u&&u.has(t))return u.get(t);var f={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in t)if("default"!==c&&Object.prototype.hasOwnProperty.call(t,c)){var p=l?Object.getOwnPropertyDescriptor(t,c):null;p&&(p.get||p.set)?Object.defineProperty(f,c,p):f[c]=t[c]}f.default=t,u&&u.set(t,f);return f})(r(d[3]));function o(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,u=new WeakMap;return(o=function(t){return t?u:n})(t)}var f=(0,t.default)({supportedCommands:['focus','blur','setTextAndSelection']});e.Commands=f;var l=u.get('RCTMultilineTextInputView',function(){return n.default});e.default=l},328,[3,137,327,150]); -__d(function(g,r,i,a,m,_e,d){var t=r(d[0])(r(d[1])),e=r(d[0])(r(d[2])),o=((function(t,e){if(!e&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var o=u(e);if(o&&o.has(t))return o.get(t);var E={},s=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var n in t)if("default"!==n&&Object.prototype.hasOwnProperty.call(t,n)){var l=s?Object.getOwnPropertyDescriptor(t,n):null;l&&(l.get||l.set)?Object.defineProperty(E,n,l):E[n]=t[n]}E.default=t,o&&o.set(t,E)})(r(d[3])),r(d[0])(r(d[4]))),E=r(d[0])(r(d[5])),s=r(d[0])(r(d[6])),n=r(d[0])(r(d[7])),l=r(d[0])(r(d[8]));function u(t){if("function"!=typeof WeakMap)return null;var e=new WeakMap,o=new WeakMap;return(u=function(t){return t?o:e})(t)}var h=function(t){var e=t.touches,o=t.changedTouches,E=e&&e.length>0,s=o&&o.length>0;return!E&&s?o[0]:E?e[0]:t},R='NOT_RESPONDER',_='RESPONDER_INACTIVE_PRESS_IN',c='RESPONDER_INACTIVE_PRESS_OUT',S='RESPONDER_ACTIVE_PRESS_IN',T='RESPONDER_ACTIVE_PRESS_OUT',P='RESPONDER_ACTIVE_LONG_PRESS_IN',D='RESPONDER_ACTIVE_LONG_PRESS_OUT',N='ERROR',O={NOT_RESPONDER:!1,RESPONDER_INACTIVE_PRESS_IN:!1,RESPONDER_INACTIVE_PRESS_OUT:!1,RESPONDER_ACTIVE_PRESS_IN:!1,RESPONDER_ACTIVE_PRESS_OUT:!1,RESPONDER_ACTIVE_LONG_PRESS_IN:!1,RESPONDER_ACTIVE_LONG_PRESS_OUT:!1,ERROR:!1},p=(0,e.default)({},O,{RESPONDER_ACTIVE_PRESS_OUT:!0,RESPONDER_ACTIVE_PRESS_IN:!0}),f=(0,e.default)({},O,{RESPONDER_INACTIVE_PRESS_IN:!0,RESPONDER_ACTIVE_PRESS_IN:!0,RESPONDER_ACTIVE_LONG_PRESS_IN:!0}),A=(0,e.default)({},O,{RESPONDER_ACTIVE_LONG_PRESS_IN:!0}),b='DELAY',I='RESPONDER_GRANT',L='RESPONDER_RELEASE',v='RESPONDER_TERMINATED',y='ENTER_PRESS_RECT',C='LEAVE_PRESS_RECT',G='LONG_PRESS_DETECTED',V={NOT_RESPONDER:{DELAY:N,RESPONDER_GRANT:_,RESPONDER_RELEASE:N,RESPONDER_TERMINATED:N,ENTER_PRESS_RECT:N,LEAVE_PRESS_RECT:N,LONG_PRESS_DETECTED:N},RESPONDER_INACTIVE_PRESS_IN:{DELAY:S,RESPONDER_GRANT:N,RESPONDER_RELEASE:R,RESPONDER_TERMINATED:R,ENTER_PRESS_RECT:_,LEAVE_PRESS_RECT:c,LONG_PRESS_DETECTED:N},RESPONDER_INACTIVE_PRESS_OUT:{DELAY:T,RESPONDER_GRANT:N,RESPONDER_RELEASE:R,RESPONDER_TERMINATED:R,ENTER_PRESS_RECT:_,LEAVE_PRESS_RECT:c,LONG_PRESS_DETECTED:N},RESPONDER_ACTIVE_PRESS_IN:{DELAY:N,RESPONDER_GRANT:N,RESPONDER_RELEASE:R,RESPONDER_TERMINATED:R,ENTER_PRESS_RECT:S,LEAVE_PRESS_RECT:T,LONG_PRESS_DETECTED:P},RESPONDER_ACTIVE_PRESS_OUT:{DELAY:N,RESPONDER_GRANT:N,RESPONDER_RELEASE:R,RESPONDER_TERMINATED:R,ENTER_PRESS_RECT:S,LEAVE_PRESS_RECT:T,LONG_PRESS_DETECTED:N},RESPONDER_ACTIVE_LONG_PRESS_IN:{DELAY:N,RESPONDER_GRANT:N,RESPONDER_RELEASE:R,RESPONDER_TERMINATED:R,ENTER_PRESS_RECT:P,LEAVE_PRESS_RECT:D,LONG_PRESS_DETECTED:P},RESPONDER_ACTIVE_LONG_PRESS_OUT:{DELAY:N,RESPONDER_GRANT:N,RESPONDER_RELEASE:R,RESPONDER_TERMINATED:R,ENTER_PRESS_RECT:P,LEAVE_PRESS_RECT:D,LONG_PRESS_DETECTED:N},error:{DELAY:R,RESPONDER_GRANT:_,RESPONDER_RELEASE:R,RESPONDER_TERMINATED:R,ENTER_PRESS_RECT:R,LEAVE_PRESS_RECT:R,LONG_PRESS_DETECTED:R}},H={componentDidMount:function(){E.default.isTV},componentWillUnmount:function(){this.touchableDelayTimeout&&clearTimeout(this.touchableDelayTimeout),this.longPressDelayTimeout&&clearTimeout(this.longPressDelayTimeout),this.pressOutDelayTimeout&&clearTimeout(this.pressOutDelayTimeout)},touchableGetInitialState:function(){return{touchable:{touchState:void 0,responderID:null}}},touchableHandleResponderTerminationRequest:function(){return!this.props.rejectResponderTermination},touchableHandleStartShouldSetResponder:function(){return!this.props.disabled},touchableLongPressCancelsPress:function(){return!0},touchableHandleResponderGrant:function(t){var e=t.currentTarget;t.persist(),this.pressOutDelayTimeout&&clearTimeout(this.pressOutDelayTimeout),this.pressOutDelayTimeout=null,this.state.touchable.touchState=R,this.state.touchable.responderID=e,this._receiveSignal(I,t);var o=void 0!==this.touchableGetHighlightDelayMS?Math.max(this.touchableGetHighlightDelayMS(),0):130;0!==(o=isNaN(o)?130:o)?this.touchableDelayTimeout=setTimeout(this._handleDelay.bind(this,t),o):this._handleDelay(t);var E=void 0!==this.touchableGetLongPressDelayMS?Math.max(this.touchableGetLongPressDelayMS(),10):370;E=isNaN(E)?370:E,this.longPressDelayTimeout=setTimeout(this._handleLongDelay.bind(this,t),E+o)},touchableHandleResponderRelease:function(t){this.pressInLocation=null,this._receiveSignal(L,t)},touchableHandleResponderTerminate:function(t){this.pressInLocation=null,this._receiveSignal(v,t)},touchableHandleResponderMove:function(t){if(this.state.touchable.positionOnActivate){var e=this.state.touchable.positionOnActivate,o=this.state.touchable.dimensionsOnActivate,E=this.touchableGetPressRectOffset?this.touchableGetPressRectOffset():{left:20,right:20,top:20,bottom:20},s=E.left,n=E.top,l=E.right,u=E.bottom,R=this.touchableGetHitSlop?this.touchableGetHitSlop():null;R&&(s+=R.left||0,n+=R.top||0,l+=R.right||0,u+=R.bottom||0);var c=h(t.nativeEvent),S=c&&c.pageX,T=c&&c.pageY;if(this.pressInLocation)this._getDistanceBetweenPoints(S,T,this.pressInLocation.pageX,this.pressInLocation.pageY)>10&&this._cancelLongPressDelayTimeout();if(S>e.left-s&&T>e.top-n&&S>`");E!==s&&(this._performSideEffectsForTransition(E,s,t,e),this.state.touchable.touchState=s)}},_cancelLongPressDelayTimeout:function(){this.longPressDelayTimeout&&clearTimeout(this.longPressDelayTimeout),this.longPressDelayTimeout=null},_isHighlight:function(t){return t===S||t===P},_savePressInLocation:function(t){var e=h(t.nativeEvent),o=e&&e.pageX,E=e&&e.pageY,s=e&&e.locationX,n=e&&e.locationY;this.pressInLocation={pageX:o,pageY:E,locationX:s,locationY:n}},_getDistanceBetweenPoints:function(t,e,o,E){var s=t-o,n=e-E;return Math.sqrt(s*s+n*n)},_performSideEffectsForTransition:function(t,e,o,s){var n=this._isHighlight(t),u=this._isHighlight(e);(o===v||o===L)&&this._cancelLongPressDelayTimeout();var h=t===R&&e===_,c=!p[t]&&p[e];if((h||c)&&this._remeasureMetricsOnActivation(),f[t]&&o===G&&this.touchableHandleLongPress&&this.touchableHandleLongPress(s),u&&!n?this._startHighlight(s):!u&&n&&this._endHighlight(s),f[t]&&o===L){var S=!!this.props.onLongPress,T=A[t]&&(!S||!this.touchableLongPressCancelsPress());(!A[t]||T)&&this.touchableHandlePress&&(u||n||(this._startHighlight(s),this._endHighlight(s)),'android'!==E.default.OS||this.props.touchSoundDisabled||l.default.playTouchSound(),this.touchableHandlePress(s))}this.touchableDelayTimeout&&clearTimeout(this.touchableDelayTimeout),this.touchableDelayTimeout=null},_startHighlight:function(t){this._savePressInLocation(t),this.touchableHandleActivePressIn&&this.touchableHandleActivePressIn(t)},_endHighlight:function(t){var e=this;this.touchableHandleActivePressOut&&(this.touchableGetPressOutDelayMS&&this.touchableGetPressOutDelayMS()?this.pressOutDelayTimeout=setTimeout(function(){e.touchableHandleActivePressOut(t)},this.touchableGetPressOutDelayMS()):this.touchableHandleActivePressOut(t))},withoutDefaultFocusAndBlur:{}},M=(H.touchableHandleFocus,H.touchableHandleBlur,(0,t.default)(H,["touchableHandleFocus","touchableHandleBlur"]));H.withoutDefaultFocusAndBlur=M;var w={Mixin:H,renderDebugView:function(t){t.color,t.hitSlop;return null}};m.exports=w},329,[3,103,29,129,330,19,332,43,202]); -__d(function(g,r,i,a,m,e,d){'use strict';var t=r(d[0])(r(d[1])),o=t.default.twoArgumentPooler;function n(t,o){this.width=t,this.height=o}n.prototype.destructor=function(){this.width=null,this.height=null},n.getPooledFromElement=function(t){return n.getPooled(t.offsetWidth,t.offsetHeight)},t.default.addPoolingTo(n,o),m.exports=n},330,[3,331]); -__d(function(g,r,i,a,m,e,d){'use strict';var t=r(d[0])(r(d[1])),n=function(t){if(this.instancePool.length){var n=this.instancePool.pop();return this.call(n,t),n}return new this(t)},o=function(n){(0,t.default)(n instanceof this,'Trying to release an instance into a pool of a different type.'),n.destructor(),this.instancePool.length=e.length?{done:!0}:{done:!1,value:e[o++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function b(e,t){if(e){if("string"==typeof e)return h(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?h(e,t):void 0}}function h(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,o=new Array(t);n=0;n--)if(t[n]())return;i.exitApp()});var i={exitApp:function(){n.default&&n.default.invokeDefaultBackPressHandler()},addEventListener:function(n,f){return-1===t.indexOf(f)&&t.push(f),{remove:function(){return i.removeEventListener(n,f)}}},removeEventListener:function(n,i){-1!==t.indexOf(i)&&t.splice(t.indexOf(i),1)}};m.exports=i},345,[3,346,4]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in n)if("default"!==l&&Object.prototype.hasOwnProperty.call(n,l)){var p=c?Object.getOwnPropertyDescriptor(n,l):null;p&&(p.get||p.set)?Object.defineProperty(f,l,p):f[l]=n[l]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).get('DeviceEventManager');e.default=n},346,[21]); -__d(function(g,r,i,a,m,_e,d){var t=r(d[0])(r(d[1])),e=r(d[0])(r(d[2])),n=r(d[0])(r(d[3])),o=r(d[0])(r(d[4])),u=r(d[0])(r(d[5])),c=r(d[0])(r(d[6])),l=(r(d[0])(r(d[7])),r(d[0])(r(d[8]))),s=(function(t,e){if(!e&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var n=p(e);if(n&&n.has(t))return n.get(t);var o={},u=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in t)if("default"!==c&&Object.prototype.hasOwnProperty.call(t,c)){var l=u?Object.getOwnPropertyDescriptor(t,c):null;l&&(l.get||l.set)?Object.defineProperty(o,c,l):o[c]=t[c]}o.default=t,n&&n.set(t,o);return o})(r(d[9]));function p(t){if("function"!=typeof WeakMap)return null;var e=new WeakMap,n=new WeakMap;return(p=function(t){return t?n:e})(t)}function f(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var h=(function(l){(0,n.default)(b,l);var p,h,y=(p=b,h=f(),function(){var t,e=(0,u.default)(p);if(h){var n=(0,u.default)(this).constructor;t=Reflect.construct(e,arguments,n)}else t=e.apply(this,arguments);return(0,o.default)(this,t)});function b(){var e;(0,t.default)(this,b);for(var n=arguments.length,o=new Array(n),u=0;uthis.eventPool.length&&this.eventPool.push(e)}function T(e){e.getPooled=_,e.eventPool=[],e.release=R}n(i[2])(P.prototype,{preventDefault:function(){this.defaultPrevented=!0;var e=this.nativeEvent;e&&(e.preventDefault?e.preventDefault():"unknown"!=typeof e.returnValue&&(e.returnValue=!1),this.isDefaultPrevented=w)},stopPropagation:function(){var e=this.nativeEvent;e&&(e.stopPropagation?e.stopPropagation():"unknown"!=typeof e.cancelBubble&&(e.cancelBubble=!0),this.isPropagationStopped=w)},persist:function(){this.isPersistent=w},isPersistent:x,destructor:function(){var e,n=this.constructor.Interface;for(e in n)this[e]=null;this.nativeEvent=this._targetInst=this.dispatchConfig=null,this.isPropagationStopped=this.isDefaultPrevented=x,this._dispatchInstances=this._dispatchListeners=null}}),P.Interface={type:null,target:null,currentTarget:function(){return null},eventPhase:null,bubbles:null,cancelable:null,timeStamp:function(e){return e.timeStamp||Date.now()},defaultPrevented:null,isTrusted:null},P.extend=function(e){function t(){}function r(){return l.apply(this,arguments)}var l=this;t.prototype=l.prototype;var a=new t;return n(i[2])(a,r.prototype),r.prototype=a,r.prototype.constructor=r,r.Interface=n(i[2])({},l.Interface,e),r.extend=l.extend,T(r),r},T(P);var E=P.extend({touchHistory:function(){return null}});function N(e){return"topTouchStart"===e}function C(e){return"topTouchMove"===e}var z=["topTouchStart"],I=["topTouchMove"],L=["topTouchCancel","topTouchEnd"],U=[],M={touchBank:U,numberActiveTouches:0,indexOfSingleActiveTouch:-1,mostRecentTimeStamp:0};function F(e){return e.timeStamp||e.timestamp}function D(e){if(null==(e=e.identifier))throw Error("Touch object is missing identifier.");return e}function A(e){var n=D(e),t=U[n];t?(t.touchActive=!0,t.startPageX=e.pageX,t.startPageY=e.pageY,t.startTimeStamp=F(e),t.currentPageX=e.pageX,t.currentPageY=e.pageY,t.currentTimeStamp=F(e),t.previousPageX=e.pageX,t.previousPageY=e.pageY,t.previousTimeStamp=F(e)):(t={touchActive:!0,startPageX:e.pageX,startPageY:e.pageY,startTimeStamp:F(e),currentPageX:e.pageX,currentPageY:e.pageY,currentTimeStamp:F(e),previousPageX:e.pageX,previousPageY:e.pageY,previousTimeStamp:F(e)},U[n]=t),M.mostRecentTimeStamp=F(e)}function H(e){var n=U[D(e)];n&&(n.touchActive=!0,n.previousPageX=n.currentPageX,n.previousPageY=n.currentPageY,n.previousTimeStamp=n.currentTimeStamp,n.currentPageX=e.pageX,n.currentPageY=e.pageY,n.currentTimeStamp=F(e),M.mostRecentTimeStamp=F(e))}function Q(e){var n=U[D(e)];n&&(n.touchActive=!1,n.previousPageX=n.currentPageX,n.previousPageY=n.currentPageY,n.previousTimeStamp=n.currentTimeStamp,n.currentPageX=e.pageX,n.currentPageY=e.pageY,n.currentTimeStamp=F(e),M.mostRecentTimeStamp=F(e))}var j,B={instrument:function(e){j=e},recordTouchTrack:function(e,n){if(null!=j&&j(e,n),C(e))n.changedTouches.forEach(H);else if(N(e))n.changedTouches.forEach(A),M.numberActiveTouches=n.touches.length,1===M.numberActiveTouches&&(M.indexOfSingleActiveTouch=n.touches[0].identifier);else if(("topTouchEnd"===e||"topTouchCancel"===e)&&(n.changedTouches.forEach(Q),M.numberActiveTouches=n.touches.length,1===M.numberActiveTouches))for(e=0;e=(a=n&-n)||16===l&&0!=(4194240&a)))return n;if(0!=(4&r)&&(r|=16&t),0!==(n=e.entangledLanes))for(e=e.entanglements,n&=r;0t;t++)n.push(e);return n}function wn(e,n,t){e.pendingLanes|=n,536870912!==n&&(e.suspendedLanes=0,e.pingedLanes=0),(e=e.eventTimes)[n=31-_n(n)]=t}function xn(e,n){var t=e.pendingLanes&~n;e.pendingLanes=n,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=n,e.mutableReadLanes&=n,e.entangledLanes&=n,n=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0 component.");return t=$n,$n+=2,{node:Ln(t,"RCTRawText",n,{text:e},r)}}var Kn=setTimeout,Zn=clearTimeout;function et(e){var n=e.node,t=an(null,Ge,{style:{display:"none"}},e.canonical.viewConfig.validAttributes);return{node:Dn(n,t),canonical:e.canonical}}function nt(e,n,t){return n="",t&&(n=" (created by "+t+")"),"\n in "+(e||"Unknown")+n}function tt(e,n){return e?nt(e.displayName||e.name||null,n,null):""}var rt=Object.prototype.hasOwnProperty,lt=[],at=-1;function it(e){return{current:e}}function ut(e){0>at||(e.current=lt[at],lt[at]=null,at--)}function ot(e,n){lt[++at]=e.current,e.current=n}var st={},ct=it(st),dt=it(!1),ft=st;function pt(e,n){var t=e.type.contextTypes;if(!t)return st;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===n)return r.__reactInternalMemoizedMaskedChildContext;var l,a={};for(l in t)a[l]=n[l];return r&&((e=e.stateNode).__reactInternalMemoizedUnmaskedChildContext=n,e.__reactInternalMemoizedMaskedChildContext=a),a}function ht(e){return null!==(e=e.childContextTypes)&&void 0!==e}function gt(){ut(dt),ut(ct)}function mt(e,n,t){if(ct.current!==st)throw Error("Unexpected context found on stack. This error is likely caused by a bug in React. Please file an issue.");ot(ct,n),ot(dt,t)}function vt(e,t,r){var l=e.stateNode;if(t=t.childContextTypes,"function"!=typeof l.getChildContext)return r;for(var a in l=l.getChildContext())if(!(a in t))throw Error((We(e)||"Unknown")+'.getChildContext(): key "'+a+'" is not defined in childContextTypes.');return n(i[2])({},r,l)}function bt(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||st,ft=ct.current,ot(ct,e),ot(dt,dt.current),!0}function yt(e,n,t){var r=e.stateNode;if(!r)throw Error("Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue.");t?(e=vt(e,n,ft),r.__reactInternalMemoizedMergedChildContext=e,ut(dt),ut(ct),ot(ct,e)):ut(dt),ot(dt,t)}var St=null,kt=!1,wt=!1;function xt(){if(!wt&&null!==St){wt=!0;var e=0,t=En;try{var r=St;for(En=1;eg?(m=h,h=null):m=h.sibling;var v=f(l,h,u[g],o);if(null===v){null===h&&(h=m);break}e&&h&&null===v.alternate&&n(l,h),i=a(v,i,g),null===c?s=v:c.sibling=v,c=v,h=m}if(g===u.length)return t(l,h),s;if(null===h){for(;gg?(m=h,h=null):m=h.sibling;var b=f(l,h,v.value,o);if(null===b){null===h&&(h=m);break}e&&h&&null===b.alternate&&n(l,h),i=a(b,i,g),null===c?s=b:c.sibling=b,c=b,h=m}if(v.done)return t(l,h),s;if(null===h){for(;!v.done;g++,v=u.next())null!==(v=d(l,v.value,o))&&(i=a(v,i,g),null===c?s=v:c.sibling=v,c=v);return s}for(h=r(l,h);!v.done;g++,v=u.next())null!==(v=p(h,l,g,v.value,o))&&(e&&null!==v.alternate&&h.delete(null===v.key?g:v.key),i=a(v,i,g),null===c?s=v:c.sibling=v,c=v);return e&&h.forEach(function(e){return n(l,e)}),s}return function(e,r,a,u){var o="object"==typeof a&&null!==a&&a.type===_e&&null===a.key;if(o&&(a=a.props.children),"object"==typeof a&&null!==a){switch(a.$$typeof){case xe:e:{var s=a.key;for(o=r;null!==o;){if(o.key===s){if((s=a.type)===_e){if(7===o.tag){t(e,o.sibling),(r=l(o,a.props.children)).return=e,e=r;break e}}else if(o.elementType===s){t(e,o.sibling),(r=l(o,a.props)).ref=nr(e,o,a),r.return=e,e=r;break e}t(e,o);break}n(e,o),o=o.sibling}a.type===_e?((r=ti(a.props.children,e.mode,u,a.key)).return=e,e=r):((u=ni(a.type,a.key,a.props,null,e.mode,u)).ref=nr(e,r,a),u.return=e,e=u)}return i(e);case Pe:e:{for(o=a.key;null!==r;){if(r.key===o){if(4===r.tag&&r.stateNode.containerInfo===a.containerInfo&&r.stateNode.implementation===a.implementation){t(e,r.sibling),(r=l(r,a.children||[])).return=e,e=r;break e}t(e,r);break}n(e,r),r=r.sibling}(r=ai(a,e.mode,u)).return=e,e=r}return i(e)}if(m(a))return h(e,r,a,u);if(je(a))return g(e,r,a,u);tr(e,a)}if("string"==typeof a||"number"==typeof a)return a=""+a,null!==r&&6===r.tag?(t(e,r.sibling),(r=l(r,a)).return=e,e=r):(t(e,r),(r=li(a,e.mode,u)).return=e,e=r),i(e);if(void 0===a&&!o)switch(e.tag){case 1:case 0:case 11:case 15:throw Error((We(e)||"Component")+"(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.")}return t(e,r)}}var lr=rr(!0),ar=rr(!1),ir={},ur=it(ir),or=it(ir),sr=it(ir);function cr(e){if(e===ir)throw Error("Expected host context to exist. This error is likely caused by a bug in React. Please file an issue.");return e}function dr(e,n){ot(sr,n),ot(or,e),ot(ur,ir),ut(ur),ot(ur,{isInAParentText:!1})}function fr(){ut(ur),ut(or),ut(sr)}function pr(e){cr(sr.current);var n=cr(ur.current),t=e.type;t="AndroidTextInput"===t||"RCTMultilineTextInputView"===t||"RCTSinglelineTextInputView"===t||"RCTText"===t||"RCTVirtualText"===t,n!==(t=n.isInAParentText!==t?{isInAParentText:t}:n)&&(ot(or,e),ot(ur,t))}function hr(e){or.current===e&&(ut(ur),ut(or))}var gr=it(0);function mr(e){for(var n=e;null!==n;){if(13===n.tag){var t=n.memoizedState;if(null!==t&&(null===t.dehydrated||zn()||zn()))return n}else if(19===n.tag&&void 0!==n.memoizedProps.revealOrder){if(0!=(128&n.flags))return n}else if(null!==n.child){n.child.return=n,n=n.child;continue}if(n===e)break;for(;null===n.sibling;){if(null===n.return||n.return===e)return null;n=n.return}n.sibling.return=n.return,n=n.sibling}return null}var vr=[];function br(){for(var e=0;ea))throw Error("Too many re-renders. React limits the number of renders to prevent an infinite loop.");a+=1,Pr=xr=null,n.updateQueue=null,yr.current=tl,e=t(r,l)}while(Rr)}if(yr.current=Zr,n=null!==xr&&null!==xr.next,kr=0,Pr=xr=wr=null,_r=!1,n)throw Error("Rendered fewer hooks than expected. This may be caused by an accidental early return statement.");return e}function Cr(){var e={memoizedState:null,baseState:null,baseQueue:null,queue:null,next:null};return null===Pr?wr.memoizedState=Pr=e:Pr=Pr.next=e,Pr}function zr(){if(null===xr){var e=wr.alternate;e=null!==e?e.memoizedState:null}else e=xr.next;var n=null===Pr?wr.memoizedState:Pr.next;if(null!==n)Pr=n,xr=e;else{if(null===e)throw Error("Rendered more hooks than during the previous render.");e={memoizedState:(xr=e).memoizedState,baseState:xr.baseState,baseQueue:xr.baseQueue,queue:xr.queue,next:null},null===Pr?wr.memoizedState=Pr=e:Pr=Pr.next=e}return Pr}function Ir(e,n){return"function"==typeof n?n(e):n}function Lr(e){var n=zr(),t=n.queue;if(null===t)throw Error("Should have a queue. This is likely a bug in React. Please file an issue.");t.lastRenderedReducer=e;var r=xr,l=r.baseQueue,a=t.pending;if(null!==a){if(null!==l){var i=l.next;l.next=a.next,a.next=i}r.baseQueue=l=a,t.pending=null}if(null!==l){a=l.next,r=r.baseState;var u=i=null,o=null,s=a;do{var c=s.lane;if((kr&c)===c)null!==o&&(o=o.next={lane:0,action:s.action,eagerReducer:s.eagerReducer,eagerState:s.eagerState,next:null}),r=s.eagerReducer===e?s.eagerState:e(r,s.action);else{var d={lane:c,action:s.action,eagerReducer:s.eagerReducer,eagerState:s.eagerState,next:null};null===o?(u=o=d,i=r):o=o.next=d,wr.lanes|=c,da|=c}s=s.next}while(null!==s&&s!==a);null===o?i=r:o.next=u,_t(r,n.memoizedState)||(sl=!0),n.memoizedState=r,n.baseState=i,n.baseQueue=o,t.lastRenderedState=r}if(null!==(e=t.interleaved)){l=e;do{a=l.lane,wr.lanes|=a,da|=a,l=l.next}while(l!==e)}else null===l&&(t.lanes=0);return[n.memoizedState,t.dispatch]}function Ur(e){var n=zr(),t=n.queue;if(null===t)throw Error("Should have a queue. This is likely a bug in React. Please file an issue.");t.lastRenderedReducer=e;var r=t.dispatch,l=t.pending,a=n.memoizedState;if(null!==l){t.pending=null;var i=l=l.next;do{a=e(a,i.action),i=i.next}while(i!==l);_t(a,n.memoizedState)||(sl=!0),n.memoizedState=a,null===n.baseQueue&&(n.baseState=a),t.lastRenderedState=a}return[a,r]}function Mr(e,n,t){var r=n._getVersion;r=r(n._source);var l=n._workInProgressVersionSecondary;if(null!==l?e=l===r:(e=e.mutableReadLanes,(e=(kr&e)===e)&&(n._workInProgressVersionSecondary=r,vr.push(n))),e)return t(n._source);throw vr.push(n),Error("Cannot read from mutable source during the current render without tearing. This may be a bug in React. Please file an issue.")}function Fr(e,n,t,r){var l=la;if(null===l)throw Error("Expected a work-in-progress root. This is a bug in React. Please file an issue.");var a=n._getVersion,i=a(n._source),u=yr.current,o=u.useState(function(){return Mr(l,n,t)}),s=o[1],c=o[0];o=Pr;var d=e.memoizedState,f=d.refs,p=f.getSnapshot,h=d.source;d=d.subscribe;var g=wr;return e.memoizedState={refs:f,source:n,subscribe:r},u.useEffect(function(){f.getSnapshot=t,f.setSnapshot=s;var e=a(n._source);_t(i,e)||(e=t(n._source),_t(c,e)||(s(e),e=Ta(g),l.mutableReadLanes|=e&l.pendingLanes),Pn(l,l.mutableReadLanes))},[t,n,r]),u.useEffect(function(){return r(n._source,function(){var e=f.getSnapshot,t=f.setSnapshot;try{t(e(n._source));var r=Ta(g);l.mutableReadLanes|=r&l.pendingLanes}catch(e){t(function(){throw e})}})},[n,r]),_t(p,t)&&_t(h,n)&&_t(d,r)||((e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:Ir,lastRenderedState:c}).dispatch=s=Kr.bind(null,wr,e),o.queue=e,o.baseQueue=null,c=Mr(l,n,t),o.memoizedState=o.baseState=c),c}function Dr(e,n,t){return Fr(zr(),e,n,t)}function Ar(e){var n=Cr();return"function"==typeof e&&(e=e()),n.memoizedState=n.baseState=e,e=(e=n.queue={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:Ir,lastRenderedState:e}).dispatch=Kr.bind(null,wr,e),[n.memoizedState,e]}function Hr(e,n,t,r){return e={tag:e,create:n,destroy:t,deps:r,next:null},null===(n=wr.updateQueue)?(n={lastEffect:null},wr.updateQueue=n,n.lastEffect=e.next=e):null===(t=n.lastEffect)?n.lastEffect=e.next=e:(r=t.next,t.next=e,e.next=r,n.lastEffect=e),e}function Qr(){return zr().memoizedState}function jr(e,n,t,r){var l=Cr();wr.flags|=e,l.memoizedState=Hr(1|n,t,void 0,void 0===r?null:r)}function Br(e,n,t,r){var l=zr();r=void 0===r?null:r;var a=void 0;if(null!==xr){var i=xr.memoizedState;if(a=i.destroy,null!==r&&Er(r,i.deps))return void(l.memoizedState=Hr(n,t,a,r))}wr.flags|=e,l.memoizedState=Hr(1|n,t,a,r)}function Wr(e,n){return jr(1049600,4,e,n)}function Or(e,n){return Br(1024,4,e,n)}function Vr(e,n){return Br(4,2,e,n)}function Yr(e,n){return"function"==typeof n?(e=e(),n(e),function(){n(null)}):null!==n&&void 0!==n?(e=e(),n.current=e,function(){n.current=null}):void 0}function qr(e,n,t){return t=null!==t&&void 0!==t?t.concat([e]):null,Br(4,2,Yr.bind(null,n,e),t)}function Xr(){}function $r(e,n){var t=zr();n=void 0===n?null:n;var r=t.memoizedState;return null!==r&&null!==n&&Er(n,r[1])?r[0]:(t.memoizedState=[e,n],e)}function Gr(e,n){var t=zr();n=void 0===n?null:n;var r=t.memoizedState;return null!==r&&null!==n&&Er(n,r[1])?r[0]:(e=e(),t.memoizedState=[e,n],e)}function Jr(e,n){var t=En;En=0!==t&&4>t?t:4,e(!0);var r=Sr.transition;Sr.transition=1;try{e(!1),n()}finally{En=t,Sr.transition=r}}function Kr(e,n,t){var r=Ra(),l=Ta(e),a={lane:l,action:t,eagerReducer:null,eagerState:null,next:null},i=e.alternate;if(e===wr||null!==i&&i===wr)Rr=_r=!0,null===(l=n.pending)?a.next=a:(a.next=l.next,l.next=a),n.pending=a;else{if(null!==la&&0!=(1&e.mode)&&0==(8&ra)){var u=n.interleaved;null===u?(a.next=a,null===At?At=[n]:At.push(n)):(a.next=u.next,u.next=a),n.interleaved=a}else null===(u=n.pending)?a.next=a:(a.next=u.next,u.next=a),n.pending=a;if(0===e.lanes&&(null===i||0===i.lanes)&&null!==(i=n.lastRenderedReducer))try{var o=n.lastRenderedState,s=i(o,t);if(a.eagerReducer=i,a.eagerState=s,_t(s,o))return}catch(e){}a=Ea(e,l,r),0!=(4194240&l)&&null!==a&&(e=n.lanes,l|=e&=a.pendingLanes,n.lanes=l,Pn(a,l))}}var Zr={readContext:Dt,useCallback:Tr,useContext:Tr,useEffect:Tr,useImperativeHandle:Tr,useLayoutEffect:Tr,useMemo:Tr,useReducer:Tr,useRef:Tr,useState:Tr,useDebugValue:Tr,useDeferredValue:Tr,useTransition:Tr,useMutableSource:Tr,useOpaqueIdentifier:Tr,unstable_isNewReconciler:!1},el={readContext:Dt,useCallback:function(e,n){return Cr().memoizedState=[e,void 0===n?null:n],e},useContext:Dt,useEffect:Wr,useImperativeHandle:function(e,n,t){return t=null!==t&&void 0!==t?t.concat([e]):null,jr(4,2,Yr.bind(null,n,e),t)},useLayoutEffect:function(e,n){return jr(4,2,e,n)},useMemo:function(e,n){var t=Cr();return n=void 0===n?null:n,e=e(),t.memoizedState=[e,n],e},useReducer:function(e,n,t){var r=Cr();return n=void 0!==t?t(n):n,r.memoizedState=r.baseState=n,e=(e=r.queue={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:n}).dispatch=Kr.bind(null,wr,e),[r.memoizedState,e]},useRef:function(e){return e={current:e},Cr().memoizedState=e},useState:Ar,useDebugValue:Xr,useDeferredValue:function(e){var n=Ar(e),t=n[0],r=n[1];return Wr(function(){var n=Sr.transition;Sr.transition=1;try{r(e)}finally{Sr.transition=n}},[e]),t},useTransition:function(){var e=Ar(!1),n=e[0];return e=Jr.bind(null,e[1]),Cr().memoizedState=e,[n,e]},useMutableSource:function(e,n,t){var r=Cr();return r.memoizedState={refs:{getSnapshot:n,setSnapshot:null},source:e,subscribe:t},Fr(r,e,n,t)},useOpaqueIdentifier:function(){throw Error("Not yet implemented")},unstable_isNewReconciler:!1},nl={readContext:Dt,useCallback:$r,useContext:Dt,useEffect:Or,useImperativeHandle:qr,useLayoutEffect:Vr,useMemo:Gr,useReducer:Lr,useRef:Qr,useState:function(){return Lr(Ir)},useDebugValue:Xr,useDeferredValue:function(e){var n=Lr(Ir),t=n[0],r=n[1];return Or(function(){var n=Sr.transition;Sr.transition=1;try{r(e)}finally{Sr.transition=n}},[e]),t},useTransition:function(){return[Lr(Ir)[0],zr().memoizedState]},useMutableSource:Dr,useOpaqueIdentifier:function(){return Lr(Ir)[0]},unstable_isNewReconciler:!1},tl={readContext:Dt,useCallback:$r,useContext:Dt,useEffect:Or,useImperativeHandle:qr,useLayoutEffect:Vr,useMemo:Gr,useReducer:Ur,useRef:Qr,useState:function(){return Ur(Ir)},useDebugValue:Xr,useDeferredValue:function(e){var n=Ur(Ir),t=n[0],r=n[1];return Or(function(){var n=Sr.transition;Sr.transition=1;try{r(e)}finally{Sr.transition=n}},[e]),t},useTransition:function(){return[Ur(Ir)[0],zr().memoizedState]},useMutableSource:Dr,useOpaqueIdentifier:function(){return Ur(Ir)[0]},unstable_isNewReconciler:!1};function rl(e,n){try{var t="",r=n;do{t+=Tt(r),r=r.return}while(r);var l=t}catch(e){l="\nError generating stack: "+e.message+"\n"+e.stack}return{value:e,source:n,stack:l}}if("function"!=typeof n(i[3]).ReactFiberErrorDialog.showErrorDialog)throw Error("Expected ReactFiberErrorDialog.showErrorDialog to be a function.");function ll(e,t){try{!1!==n(i[3]).ReactFiberErrorDialog.showErrorDialog({componentStack:null!==t.stack?t.stack:"",error:t.value,errorBoundary:null!==e&&1===e.tag?e.stateNode:null})&&console.error(t.value)}catch(e){setTimeout(function(){throw e})}}var al="function"==typeof WeakMap?WeakMap:Map;function il(e,n,t){(t=Bt(-1,t)).tag=3,t.payload={element:null};var r=n.value;return t.callback=function(){ma||(ma=!0,va=r),ll(e,n)},t}function ul(e,n,t){(t=Bt(-1,t)).tag=3;var r=e.type.getDerivedStateFromError;if("function"==typeof r){var l=n.value;t.payload=function(){return ll(e,n),r(l)}}var a=e.stateNode;return null!==a&&"function"==typeof a.componentDidCatch&&(t.callback=function(){"function"!=typeof r&&(null===ba?ba=new Set([this]):ba.add(this),ll(e,n));var t=n.stack;this.componentDidCatch(n.value,{componentStack:null!==t?t:""})}),t}var ol=we.ReactCurrentOwner,sl=!1;function cl(e,n,t,r){n.child=null===e?ar(n,null,t,r):lr(n,e.child,t,r)}function dl(e,n,t,r,l){t=t.render;var a=n.ref;return Ft(n,l),r=Nr(e,n,t,r,a,l),null===e||sl?(n.flags|=1,cl(e,n,r,l),n.child):(n.updateQueue=e.updateQueue,n.flags&=-1029,e.lanes&=~l,Ll(e,n,l))}function fl(e,n,t,r,l,a){if(null===e){var i=t.type;return"function"!=typeof i||Ka(i)||void 0!==i.defaultProps||null!==t.compare||void 0!==t.defaultProps?((e=ni(t.type,null,r,n,n.mode,a)).ref=n.ref,e.return=n,n.child=e):(n.tag=15,n.type=i,pl(e,n,i,r,l,a))}return i=e.child,0==(l&a)&&(l=i.memoizedProps,(t=null!==(t=t.compare)?t:Rt)(l,r)&&e.ref===n.ref)?Ll(e,n,a):(n.flags|=1,(e=ei(i,r)).ref=n.ref,e.return=n,n.child=e)}function pl(e,n,t,r,l,a){if(null!==e&&Rt(e.memoizedProps,r)&&e.ref===n.ref){if(sl=!1,0==(a&l))return n.lanes=e.lanes,Ll(e,n,a);0!=(32768&e.flags)&&(sl=!0)}return ml(e,n,t,r,a)}function hl(e,n,t){var r=n.pendingProps,l=r.children,a=null!==e?e.memoizedState:null;if("hidden"===r.mode||"unstable-defer-without-hiding"===r.mode)if(0==(1&n.mode))n.memoizedState={baseLanes:0,cachePool:null},ot(oa,ua),ua|=t;else{if(0==(1073741824&t))return e=null!==a?a.baseLanes|t:t,n.lanes=n.childLanes=1073741824,n.memoizedState={baseLanes:e,cachePool:null},n.updateQueue=null,ot(oa,ua),ua|=e,null;n.memoizedState={baseLanes:0,cachePool:null},r=null!==a?a.baseLanes:t,ot(oa,ua),ua|=r}else null!==a?(r=a.baseLanes|t,n.memoizedState=null):r=t,ot(oa,ua),ua|=r;return cl(e,n,l,t),n.child}function gl(e,n){var t=n.ref;(null===e&&null!==t||null!==e&&e.ref!==t)&&(n.flags|=256)}function ml(e,n,t,r,l){var a=ht(t)?ft:ct.current;return a=pt(n,a),Ft(n,l),t=Nr(e,n,t,r,a,l),null===e||sl?(n.flags|=1,cl(e,n,t,l),n.child):(n.updateQueue=e.updateQueue,n.flags&=-1029,e.lanes&=~l,Ll(e,n,l))}function vl(e,n,t,r,l){if(ht(t)){var a=!0;bt(n)}else a=!1;if(Ft(n,l),null===n.stateNode)null!==e&&(e.alternate=null,n.alternate=null,n.flags|=2),Kt(n,t,r),er(n,t,r,l),r=!0;else if(null===e){var i=n.stateNode,u=n.memoizedProps;i.props=u;var o=i.context,s=t.contextType;"object"==typeof s&&null!==s?s=Dt(s):s=pt(n,s=ht(t)?ft:ct.current);var c=t.getDerivedStateFromProps,d="function"==typeof c||"function"==typeof i.getSnapshotBeforeUpdate;d||"function"!=typeof i.UNSAFE_componentWillReceiveProps&&"function"!=typeof i.componentWillReceiveProps||(u!==r||o!==s)&&Zt(n,i,r,s),Ht=!1;var f=n.memoizedState;i.state=f,Yt(n,r,i,l),o=n.memoizedState,u!==r||f!==o||dt.current||Ht?("function"==typeof c&&($t(n,t,c,r),o=n.memoizedState),(u=Ht||Jt(n,t,u,r,f,o,s))?(d||"function"!=typeof i.UNSAFE_componentWillMount&&"function"!=typeof i.componentWillMount||("function"==typeof i.componentWillMount&&i.componentWillMount(),"function"==typeof i.UNSAFE_componentWillMount&&i.UNSAFE_componentWillMount()),"function"==typeof i.componentDidMount&&(n.flags|=4)):("function"==typeof i.componentDidMount&&(n.flags|=4),n.memoizedProps=r,n.memoizedState=o),i.props=r,i.state=o,i.context=s,r=u):("function"==typeof i.componentDidMount&&(n.flags|=4),r=!1)}else{i=n.stateNode,jt(e,n),u=n.memoizedProps,s=n.type===n.elementType?u:Et(n.type,u),i.props=s,d=n.pendingProps,f=i.context,"object"==typeof(o=t.contextType)&&null!==o?o=Dt(o):o=pt(n,o=ht(t)?ft:ct.current);var p=t.getDerivedStateFromProps;(c="function"==typeof p||"function"==typeof i.getSnapshotBeforeUpdate)||"function"!=typeof i.UNSAFE_componentWillReceiveProps&&"function"!=typeof i.componentWillReceiveProps||(u!==d||f!==o)&&Zt(n,i,r,o),Ht=!1,f=n.memoizedState,i.state=f,Yt(n,r,i,l);var h=n.memoizedState;u!==d||f!==h||dt.current||Ht?("function"==typeof p&&($t(n,t,p,r),h=n.memoizedState),(s=Ht||Jt(n,t,s,r,f,h,o)||!1)?(c||"function"!=typeof i.UNSAFE_componentWillUpdate&&"function"!=typeof i.componentWillUpdate||("function"==typeof i.componentWillUpdate&&i.componentWillUpdate(r,h,o),"function"==typeof i.UNSAFE_componentWillUpdate&&i.UNSAFE_componentWillUpdate(r,h,o)),"function"==typeof i.componentDidUpdate&&(n.flags|=4),"function"==typeof i.getSnapshotBeforeUpdate&&(n.flags|=512)):("function"!=typeof i.componentDidUpdate||u===e.memoizedProps&&f===e.memoizedState||(n.flags|=4),"function"!=typeof i.getSnapshotBeforeUpdate||u===e.memoizedProps&&f===e.memoizedState||(n.flags|=512),n.memoizedProps=r,n.memoizedState=h),i.props=r,i.state=h,i.context=o,r=s):("function"!=typeof i.componentDidUpdate||u===e.memoizedProps&&f===e.memoizedState||(n.flags|=4),"function"!=typeof i.getSnapshotBeforeUpdate||u===e.memoizedProps&&f===e.memoizedState||(n.flags|=512),r=!1)}return bl(e,n,t,r,a,l)}function bl(e,n,t,r,l,a){gl(e,n);var i=0!=(128&n.flags);if(!r&&!i)return l&&yt(n,t,!1),Ll(e,n,a);r=n.stateNode,ol.current=n;var u=i&&"function"!=typeof t.getDerivedStateFromError?null:r.render();return n.flags|=1,null!==e&&i?(n.child=lr(n,e.child,null,a),n.child=lr(n,null,u,a)):cl(e,n,u,a),n.memoizedState=r.state,l&&yt(n,t,!0),n.child}function yl(e){var n=e.stateNode;n.pendingContext?mt(0,n.pendingContext,n.pendingContext!==n.context):n.context&&mt(0,n.context,!1),dr(e,n.containerInfo)}var Sl,kl,wl,xl,Pl={dehydrated:null,retryLane:0};function _l(e){return{baseLanes:e,cachePool:null}}function Rl(e,n,t){var r,l=n.pendingProps,a=gr.current,i=!1;return(r=0!=(128&n.flags))||(r=(null===e||null!==e.memoizedState)&&0!=(2&a)),r?(i=!0,n.flags&=-129):null!==e&&null===e.memoizedState||void 0===l.fallback||!0===l.unstable_avoidThisFallback||(a|=1),ot(gr,1&a),null===e?(e=l.children,a=l.fallback,i?(e=Tl(n,e,a,t),n.child.memoizedState=_l(t),n.memoizedState=Pl,e):"number"==typeof l.unstable_expectedLoadTime?(e=Tl(n,e,a,t),n.child.memoizedState=_l(t),n.memoizedState=Pl,n.lanes=4194304,e):((t=ri({mode:"visible",children:e},n.mode,t,null)).return=n,n.child=t)):(e.memoizedState,i?(l=Nl(e,n,l.children,l.fallback,t),i=n.child,a=e.child.memoizedState,i.memoizedState=null===a?_l(t):{baseLanes:a.baseLanes|t,cachePool:null},i.childLanes=e.childLanes&~t,n.memoizedState=Pl,l):(t=El(e,n,l.children,t),n.memoizedState=null,t))}function Tl(e,n,t,r){var l=e.mode,a=e.child;return n={mode:"hidden",children:n},0==(1&l)&&null!==a?(a.childLanes=0,a.pendingProps=n):a=ri(n,l,0,null),t=ti(t,l,r,null),a.return=e,t.return=e,a.sibling=t,e.child=a,t}function El(e,n,t,r){var l=e.child;return e=l.sibling,t=ei(l,{mode:"visible",children:t}),0==(1&n.mode)&&(t.lanes=r),t.return=n,t.sibling=null,null!==e&&(null===(r=n.deletions)?(n.deletions=[e],n.flags|=16):r.push(e)),n.child=t}function Nl(e,n,t,r,l){var a=n.mode,i=(e=e.child).sibling,u={mode:"hidden",children:t};return 0==(1&a)&&n.child!==e?((t=n.child).childLanes=0,t.pendingProps=u,n.deletions=null):(t=ei(e,u)).subtreeFlags=1835008&e.subtreeFlags,null!==i?r=ei(i,r):(r=ti(r,a,l,null)).flags|=2,r.return=n,t.return=n,t.sibling=r,n.child=t,r}function Cl(e,n){e.lanes|=n;var t=e.alternate;null!==t&&(t.lanes|=n),Mt(e.return,n)}function zl(e,n,t,r,l){var a=e.memoizedState;null===a?e.memoizedState={isBackwards:n,rendering:null,renderingStartTime:0,last:r,tail:t,tailMode:l}:(a.isBackwards=n,a.rendering=null,a.renderingStartTime=0,a.last=r,a.tail=t,a.tailMode=l)}function Il(e,n,t){var r=n.pendingProps,l=r.revealOrder,a=r.tail;if(cl(e,n,r.children,t),0!=(2&(r=gr.current)))r=1&r|2,n.flags|=128;else{if(null!==e&&0!=(128&e.flags))e:for(e=n.child;null!==e;){if(13===e.tag)null!==e.memoizedState&&Cl(e,t);else if(19===e.tag)Cl(e,t);else if(null!==e.child){e.child.return=e,e=e.child;continue}if(e===n)break e;for(;null===e.sibling;){if(null===e.return||e.return===n)break e;e=e.return}e.sibling.return=e.return,e=e.sibling}r&=1}if(ot(gr,r),0==(1&n.mode))n.memoizedState=null;else switch(l){case"forwards":for(t=n.child,l=null;null!==t;)null!==(e=t.alternate)&&null===mr(e)&&(l=t),t=t.sibling;null===(t=l)?(l=n.child,n.child=null):(l=t.sibling,t.sibling=null),zl(n,!1,l,t,a);break;case"backwards":for(t=null,l=n.child,n.child=null;null!==l;){if(null!==(e=l.alternate)&&null===mr(e)){n.child=l;break}e=l.sibling,l.sibling=t,t=l,l=e}zl(n,!0,t,null,a);break;case"together":zl(n,!1,null,null,void 0);break;default:n.memoizedState=null}return n.child}function Ll(e,n,t){if(null!==e&&(n.dependencies=e.dependencies),da|=n.lanes,0==(t&n.childLanes))return null;if(null!==e&&n.child!==e.child)throw Error("Resuming work not yet implemented.");if(null!==n.child){for(t=ei(e=n.child,e.pendingProps),n.child=t,t.return=n;null!==e.sibling;)e=e.sibling,(t=t.sibling=ei(e,e.pendingProps)).return=n;t.sibling=null}return n.child}function Ul(e,n){if(null!==e&&e.child===n.child)return!0;if(0!=(16&n.flags))return!1;for(e=n.child;null!==e;){if(0!=(6454&e.flags)||0!=(6454&e.subtreeFlags))return!1;e=e.sibling}return!0}function Ml(e,n,t,r){for(var l=n.child;null!==l;){if(5===l.tag){var a=l.stateNode;t&&r&&(a=et(a)),Qn(e,a.node)}else if(6===l.tag){if(a=l.stateNode,t&&r)throw Error("Not yet implemented.");Qn(e,a.node)}else if(4!==l.tag){if(13===l.tag&&0!=(4&l.flags)&&(a=null!==l.memoizedState)){var i=l.child;if(null!==i&&(null!==i.child&&(i.child.return=i,Ml(e,i,!0,a)),null!==(a=i.sibling))){a.return=l,l=a;continue}}if(null!==l.child){l.child.return=l,l=l.child;continue}}if(l===n)break;for(;null===l.sibling;){if(null===l.return||l.return===n)return;l=l.return}l.sibling.return=l.return,l=l.sibling}}function Fl(e,n){switch(e.tailMode){case"hidden":n=e.tail;for(var t=null;null!==n;)null!==n.alternate&&(t=n),n=n.sibling;null===t?e.tail=null:t.sibling=null;break;case"collapsed":t=e.tail;for(var r=null;null!==t;)null!==t.alternate&&(r=t),t=t.sibling;null===r?n||null===e.tail?e.tail=null:e.tail.sibling=null:r.sibling=null}}function Dl(e){var n=null!==e.alternate&&e.alternate.child===e.child,t=0,r=0;if(n)for(var l=e.child;null!==l;)t|=l.lanes|l.childLanes,r|=1835008&l.subtreeFlags,r|=1835008&l.flags,l.return=e,l=l.sibling;else for(l=e.child;null!==l;)t|=l.lanes|l.childLanes,r|=l.subtreeFlags,r|=l.flags,l.return=e,l=l.sibling;return e.subtreeFlags|=r,e.childLanes=t,n}function Al(e,t,r){var l=t.pendingProps;switch(t.tag){case 2:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return Dl(t),null;case 1:return ht(t.type)&>(),Dl(t),null;case 3:return l=t.stateNode,fr(),ut(dt),ut(ct),br(),l.pendingContext&&(l.context=l.pendingContext,l.pendingContext=null),null!==e&&null!==e.child||l.hydrate||(t.flags|=512),kl(e,t),Dl(t),null;case 5:hr(t),r=cr(sr.current);var a=t.type;if(null!==e&&null!=t.stateNode)wl(e,t,a,l,r),e.ref!==t.ref&&(t.flags|=256);else{if(!l){if(null===t.stateNode)throw Error("We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue.");return Dl(t),null}cr(ur.current),e=$n,$n+=2,a=Xn(a);var u=an(null,Ge,l,a.validAttributes);r=Ln(e,a.uiViewClassName,r,u,t),e=new Gn(e,a,l,t),Sl(e={node:r,canonical:e},t,!1,!1),t.stateNode=e,null!==t.ref&&(t.flags|=256)}return Dl(t),null;case 6:if(e&&null!=t.stateNode)xl(e,t,e.memoizedProps,l);else{if("string"!=typeof l&&null===t.stateNode)throw Error("We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue.");e=cr(sr.current),r=cr(ur.current),t.stateNode=Jn(l,e,r,t)}return Dl(t),null;case 13:return ut(gr),l=t.memoizedState,0!=(128&t.flags)?(t.lanes=r,t):(l=null!==l,r=!1,null!==e&&(r=null!==e.memoizedState),l&&!r&&0!=(1&t.mode)&&(null===e&&!0!==t.memoizedProps.unstable_avoidThisFallback||0!=(1&gr.current)?0===sa&&(sa=3):(0!==sa&&3!==sa||(sa=4),null===la||0==(268435455&da)&&0==(268435455&fa)||Ia(la,ia))),l&&(t.flags|=4),Dl(t),null);case 4:return fr(),kl(e,t),Dl(t),null;case 10:return Ut(t.type._context),Dl(t),null;case 17:return ht(t.type)&>(),Dl(t),null;case 19:if(ut(gr),null===(a=t.memoizedState))return Dl(t),null;if(l=0!=(128&t.flags),null===(u=a.rendering))if(l)Fl(a,!1);else{if(0!==sa||null!==e&&0!=(128&e.flags))for(e=t.child;null!==e;){if(null!==(u=mr(e))){for(t.flags|=128,Fl(a,!1),null!==(e=u.updateQueue)&&(t.updateQueue=e,t.flags|=4),t.subtreeFlags=0,e=r,l=t.child;null!==l;)a=e,(r=l).flags&=1835010,null===(u=r.alternate)?(r.childLanes=0,r.lanes=a,r.child=null,r.subtreeFlags=0,r.memoizedProps=null,r.memoizedState=null,r.updateQueue=null,r.dependencies=null,r.stateNode=null):(r.childLanes=u.childLanes,r.lanes=u.lanes,r.child=u.child,r.subtreeFlags=0,r.deletions=null,r.memoizedProps=u.memoizedProps,r.memoizedState=u.memoizedState,r.updateQueue=u.updateQueue,r.type=u.type,a=u.dependencies,r.dependencies=null===a?null:{lanes:a.lanes,firstContext:a.firstContext}),l=l.sibling;return ot(gr,1&gr.current|2),t.child}e=e.sibling}null!==a.tail&&n(i[4]).unstable_now()>ga&&(t.flags|=128,l=!0,Fl(a,!1),t.lanes=4194304)}else{if(!l)if(null!==(e=mr(u))){if(t.flags|=128,l=!0,null!==(e=e.updateQueue)&&(t.updateQueue=e,t.flags|=4),Fl(a,!0),null===a.tail&&"hidden"===a.tailMode&&!u.alternate)return Dl(t),null}else 2*n(i[4]).unstable_now()-a.renderingStartTime>ga&&1073741824!==r&&(t.flags|=128,l=!0,Fl(a,!1),t.lanes=4194304);a.isBackwards?(u.sibling=t.child,t.child=u):(null!==(e=a.last)?e.sibling=u:t.child=u,a.last=u)}return null!==a.tail?(t=a.tail,a.rendering=t,a.tail=t.sibling,a.renderingStartTime=n(i[4]).unstable_now(),t.sibling=null,e=gr.current,ot(gr,l?1&e|2:1&e),t):(Dl(t),null);case 22:case 23:return Ua(),r=null!==t.memoizedState,null!==e&&null!==e.memoizedState!==r&&"unstable-defer-without-hiding"!==l.mode&&(t.flags|=4),r&&0==(1073741824&ua)&&0!=(1&t.mode)||Dl(t),null}throw Error("Unknown unit of work tag ("+t.tag+"). This error is likely caused by a bug in React. Please file an issue.")}function Hl(e){switch(e.tag){case 1:ht(e.type)&>();var n=e.flags;return 16384&n?(e.flags=-16385&n|128,e):null;case 3:if(fr(),ut(dt),ut(ct),br(),0!=(128&(n=e.flags)))throw Error("The root failed to unmount after an error. This is likely a bug in React. Please file an issue.");return e.flags=-16385&n|128,e;case 5:return hr(e),null;case 13:return ut(gr),16384&(n=e.flags)?(e.flags=-16385&n|128,e):null;case 19:return ut(gr),null;case 4:return fr(),null;case 10:return Ut(e.type._context),null;case 22:case 23:return Ua(),null;case 24:default:return null}}Sl=function(e,n,t,r){for(var l=n.child;null!==l;){if(5===l.tag){var a=l.stateNode;t&&r&&(a=et(a)),Hn(e.node,a.node)}else if(6===l.tag){if(a=l.stateNode,t&&r)throw Error("Not yet implemented.");Hn(e.node,a.node)}else if(4!==l.tag){if(13===l.tag&&0!=(4&l.flags)&&(a=null!==l.memoizedState)){var i=l.child;if(null!==i&&(null!==i.child&&(i.child.return=i,Sl(e,i,!0,a)),null!==(a=i.sibling))){a.return=l,l=a;continue}}if(null!==l.child){l.child.return=l,l=l.child;continue}}if(l===n)break;for(;null===l.sibling;){if(null===l.return||l.return===n)return;l=l.return}l.sibling.return=l.return,l=l.sibling}},kl=function(e,n){var t=n.stateNode;if(!Ul(e,n)){e=t.containerInfo;var r=An(e);Ml(r,n,!1,!1),t.pendingChildren=r,n.flags|=4,jn(e,r)}},wl=function(e,n,t,r){t=e.stateNode;var l=e.memoizedProps;if((e=Ul(e,n))&&l===r)n.stateNode=t;else{var a=n.stateNode;cr(ur.current);var i=null;l!==r&&(l=an(null,l,r,a.canonical.viewConfig.validAttributes),a.canonical.currentProps=r,i=l),e&&null===i?n.stateNode=t:(r=i,l=t.node,t={node:e?null!==r?Dn(l,r):Un(l):null!==r?Fn(l,r):Mn(l),canonical:t.canonical},n.stateNode=t,e?n.flags|=4:Sl(t,n,!1,!1))}},xl=function(e,n,t,r){t!==r?(e=cr(sr.current),t=cr(ur.current),n.stateNode=Jn(r,e,t,n),n.flags|=4):n.stateNode=e.stateNode};var Ql="function"==typeof WeakSet?WeakSet:Set,jl=null;function Bl(e,n){var t=e.ref;if(null!==t)if("function"==typeof t)try{t(null)}catch(t){qa(e,n,t)}else t.current=null}var Wl=!1;function Ol(e,n){for(jl=n;null!==jl;)if(n=(e=jl).child,0!=(516&e.subtreeFlags)&&null!==n)n.return=e,jl=n;else for(;null!==jl;){e=jl;try{var t=e.alternate;if(0!=(512&e.flags))switch(e.tag){case 0:case 11:case 15:break;case 1:if(null!==t){var r=t.memoizedProps,l=t.memoizedState,a=e.stateNode,i=a.getSnapshotBeforeUpdate(e.elementType===e.type?r:Et(e.type,r),l);a.__reactInternalSnapshotBeforeUpdate=i}break;case 3:break;case 5:case 6:case 4:case 17:break;default:throw Error("This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue.")}}catch(n){qa(e,e.return,n)}if(null!==(n=e.sibling)){n.return=e.return,jl=n;break}jl=e.return}return t=Wl,Wl=!1,t}function Vl(e,n,t){var r=n.updateQueue;if(null!==(r=null!==r?r.lastEffect:null)){var l=r=r.next;do{if((l.tag&e)===e){var a=l.destroy;if(l.destroy=void 0,void 0!==a){var i=n,u=t;try{a()}catch(e){qa(i,u,e)}}}l=l.next}while(l!==r)}}function Yl(e,n){if(null!==(n=null!==(n=n.updateQueue)?n.lastEffect:null)){var t=n=n.next;do{if((t.tag&e)===e){var r=t.create;t.destroy=r()}t=t.next}while(t!==n)}}function ql(e){var n=e.alternate;null!==n&&(e.alternate=null,ql(n)),e.child=null,e.deletions=null,e.sibling=null,e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function Xl(e,t){switch(t.tag){case 0:case 11:case 14:case 15:return void Vl(3,t,t.return);case 12:return;case 13:return null!==t.memoizedState&&(ha=n(i[4]).unstable_now()),void $l(t);case 19:return void $l(t);case 22:case 23:return}e:{switch(t.tag){case 1:case 5:case 6:break e;case 3:case 4:break e}throw Error("This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue.")}}function $l(e){var n=e.updateQueue;if(null!==n){e.updateQueue=null;var t=e.stateNode;null===t&&(t=e.stateNode=new Ql),n.forEach(function(n){var r=$a.bind(null,e,n);t.has(n)||(t.add(n),n.then(r,r))})}}function Gl(e,n){for(jl=n;null!==jl;){if(null!==(n=(e=jl).deletions))for(var t=0;ta&&(a=o),l&=~u}if(l=a,10<(l=(120>(l=n(i[4]).unstable_now()-l)?120:480>l?480:1080>l?1080:1920>l?1920:3e3>l?3e3:4320>l?4320:1960*Zl(l/1960))-l)){e.timeoutHandle=Kn(Wa.bind(null,e),l);break}Wa(e);break;case 5:Wa(e);break;default:throw Error("Unknown root exit status.")}}return Ca(e,n(i[4]).unstable_now()),e.callbackNode===r?za.bind(null,e):null}function Ia(e,n){for(n&=~pa,n&=~fa,e.suspendedLanes|=n,e.pingedLanes&=~n,e=e.expirationTimes;0 component higher in the tree to provide a loading indicator or placeholder to display.")}5!==sa&&(sa=2),o=rl(o,u),p=i;do{switch(p.tag){case 3:a=o,p.flags|=16384,n&=-n,p.lanes|=n,Vt(p,il(p,a,n));break e;case 1:a=o;var w=p.type,x=p.stateNode;if(0==(128&p.flags)&&("function"==typeof w.getDerivedStateFromError||null!==x&&"function"==typeof x.componentDidCatch&&(null===ba||!ba.has(x)))){p.flags|=16384,n&=-n,p.lanes|=n,Vt(p,ul(p,a,n));break e}}p=p.return}while(null!==p)}Ba(t)}catch(e){n=e,aa===t&&null!==t&&(aa=t=t.return);continue}break}}function Da(){var e=ea.current;return ea.current=Zr,null===e?Zr:e}function Aa(e,n){var t=ra;ra|=8;var r=Da();for(la===e&&ia===n||Ma(e,n);;)try{Ha();break}catch(n){Fa(e,n)}if(Lt(),ra=t,ea.current=r,null!==aa)throw Error("Cannot commit an incomplete root. This error is likely caused by a bug in React. Please file an issue.");return la=null,ia=0,sa}function Ha(){for(;null!==aa;)ja(aa)}function Qa(){for(;null!==aa&&!n(i[4]).unstable_shouldYield();)ja(aa)}function ja(e){var n=Kl(e.alternate,e,ua);e.memoizedProps=e.pendingProps,null===n?Ba(e):aa=n,na.current=null}function Ba(e){var n=e;do{var t=n.alternate;if(e=n.return,0==(8192&n.flags)){if(null!==(t=Al(t,n,ua)))return void(aa=t)}else{if(null!==(t=Hl(n)))return t.flags&=8191,void(aa=t);null!==e&&(e.flags|=8192,e.subtreeFlags=0,e.deletions=null)}if(null!==(n=n.sibling))return void(aa=n);aa=n=e}while(null!==n);0===sa&&(sa=5)}function Wa(e){var n=En,t=ta.transition;try{ta.transition=0,En=1,Oa(e,n)}finally{ta.transition=t,En=n}return null}function Oa(e,t){do{Va()}while(null!==Sa);if(0!=(24&ra))throw Error("Should not already be working.");var r=e.finishedWork,l=e.finishedLanes;if(null===r)return null;if(e.finishedWork=null,e.finishedLanes=0,r===e.current)throw Error("Cannot commit the same tree as before. This error is likely caused by a bug in React. Please file an issue.");e.callbackNode=null,e.callbackPriority=0;var a=r.lanes|r.childLanes;if(xn(e,a),e===la&&(aa=la=null,ia=0),0==(1040&r.subtreeFlags)&&0==(1040&r.flags)||ya||(ya=!0,n(i[4]).unstable_scheduleCallback(n(i[4]).unstable_NormalPriority,function(){return Va(),null})),a=0!=(8054&r.flags),0!=(8054&r.subtreeFlags)||a){a=ta.transition,ta.transition=0;var u=En;En=1;var o=ra;ra|=16,na.current=null,Ol(e,r),Gl(e,r),e.current=r,Jl(r),n(i[4]).unstable_requestPaint(),ra=o,En=u,ta.transition=a}else e.current=r;if(ya&&(ya=!1,Sa=e,ka=l),0===(a=e.pendingLanes)&&(ba=null),0!=(1&a)?e===xa?wa++:(wa=0,xa=e):wa=0,hn(r.stateNode),Ca(e,n(i[4]).unstable_now()),ma)throw ma=!1,e=va,va=null,e;return 0!=(4&ra)?null:(0!=(1&ka)&&0!==e.tag&&Va(),xt(),null)}function Va(){if(null!==Sa){var e=Nn(ka),n=ta.transition,t=En;try{if(ta.transition=0,En=16>e?16:e,null===Sa)var r=!1;else{if(e=Sa,Sa=null,ka=0,0!=(24&ra))throw Error("Cannot flush passive effects while already rendering.");var l=ra;for(ra|=16,jl=e.current;null!==jl;){var a=jl,i=a.child;if(0!=(16&jl.flags)){var u=a.deletions;if(null!==u){for(var o=0;on(i[4]).unstable_now()-ha?Ma(e,0):pa|=r),Ca(e,t)}function $a(e,n){var t=e.stateNode;null!==t&&t.delete(n),0===(n=0)&&(0==(1&e.mode)?n=1:(n=mn,0==(130023424&(mn<<=1))&&(mn=4194304))),t=Ra(),null!==(e=Na(e,n))&&(wn(e,n,t),Ca(e,t))}function Ga(e,n,t,r){this.tag=e,this.key=t,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=n,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function Ja(e,n,t,r){return new Ga(e,n,t,r)}function Ka(e){return!(!(e=e.prototype)||!e.isReactComponent)}function Za(e){if("function"==typeof e)return Ka(e)?1:0;if(void 0!==e&&null!==e){if((e=e.$$typeof)===Ce)return 11;if(e===Le)return 14}return 2}function ei(e,n){var t=e.alternate;return null===t?((t=Ja(e.tag,n,e.key,e.mode)).elementType=e.elementType,t.type=e.type,t.stateNode=e.stateNode,t.alternate=e,e.alternate=t):(t.pendingProps=n,t.type=e.type,t.flags=0,t.subtreeFlags=0,t.deletions=null),t.flags=1835008&e.flags,t.childLanes=e.childLanes,t.lanes=e.lanes,t.child=e.child,t.memoizedProps=e.memoizedProps,t.memoizedState=e.memoizedState,t.updateQueue=e.updateQueue,n=e.dependencies,t.dependencies=null===n?null:{lanes:n.lanes,firstContext:n.firstContext},t.sibling=e.sibling,t.index=e.index,t.ref=e.ref,t}function ni(e,n,t,r,l,a){var i=2;if(r=e,"function"==typeof e)Ka(e)&&(i=1);else if("string"==typeof e)i=5;else e:switch(e){case _e:return ti(t.children,l,a,n);case Me:i=8,l|=4;break;case Re:i=8,l|=8;break;case Te:return(e=Ja(12,t,n,2|l)).elementType=Te,e.lanes=a,e;case ze:return(e=Ja(13,t,n,l)).elementType=ze,e.lanes=a,e;case Ie:return(e=Ja(19,t,n,l)).elementType=Ie,e.lanes=a,e;case Fe:return ri(t,l,a,n);case De:return(e=Ja(23,t,n,l)).elementType=De,e.lanes=a,e;default:if("object"==typeof e&&null!==e)switch(e.$$typeof){case Ee:i=10;break e;case Ne:i=9;break e;case Ce:i=11;break e;case Le:i=14;break e;case Ue:i=16,r=null;break e}throw Error("Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: "+(null==e?e:typeof e)+".")}return(n=Ja(i,t,n,l)).elementType=e,n.type=r,n.lanes=a,n}function ti(e,n,t,r){return(e=Ja(7,e,r,n)).lanes=t,e}function ri(e,n,t,r){return(e=Ja(22,e,r,n)).elementType=Fe,e.lanes=t,e}function li(e,n,t){return(e=Ja(6,e,null,n)).lanes=t,e}function ai(e,n,t){return(n=Ja(4,null!==e.children?e.children:[],e.key,n)).lanes=t,n.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},n}function ii(e,n,t){this.tag=n,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.pendingContext=this.context=null,this.hydrate=t,this.callbackNode=null,this.callbackPriority=0,this.eventTimes=kn(0),this.expirationTimes=kn(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=kn(0)}function ui(e,n,t){var r=3=t.length?{done:!0}:{done:!1,value:t[o++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function f(t,n){if(t){if("string"==typeof t)return s(t,n);var u=Object.prototype.toString.call(t).slice(8,-1);return"Object"===u&&t.constructor&&(u=t.constructor.name),"Map"===u||"Set"===u?Array.from(t):"Arguments"===u||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(u)?s(t,n):void 0}}function s(t,n){(null==n||n>t.length)&&(n=t.length);for(var u=0,o=new Array(n);ui&&(f+=u&&o?h.currentPageX:u&&!o?h.currentPageY:!u&&o?h.previousPageX:h.previousPageY,s=1);else for(var v=0;v=i){f+=u&&o?C.currentPageX:u&&!o?C.currentPageY:!u&&o?C.previousPageX:C.previousPageY,s++}}return s>0?f/s:n.noCentroid},currentCentroidXOfTouchesChangedAfter:function(t,i){return n.centroidDimension(t,i,!0,!0)},currentCentroidYOfTouchesChangedAfter:function(t,i){return n.centroidDimension(t,i,!1,!0)},previousCentroidXOfTouchesChangedAfter:function(t,i){return n.centroidDimension(t,i,!0,!1)},previousCentroidYOfTouchesChangedAfter:function(t,i){return n.centroidDimension(t,i,!1,!1)},currentCentroidX:function(t){return n.centroidDimension(t,0,!0,!0)},currentCentroidY:function(t){return n.centroidDimension(t,0,!1,!0)},noCentroid:-1};m.exports=n},376,[]); -__d(function(g,r,i,a,m,e,d){var n=r(d[0])(r(d[1])),s=r(d[0])(r(d[2])),o=r(d[0])(r(d[3])),t=r(d[0])(r(d[4])),E=r(d[0])(r(d[5])),A=r(d[0])(r(d[6])),_=r(d[0])(r(d[7])),u=Object.freeze({GRANTED:'granted',DENIED:'denied',NEVER_ASK_AGAIN:'never_ask_again'}),S=Object.freeze({READ_CALENDAR:'android.permission.READ_CALENDAR',WRITE_CALENDAR:'android.permission.WRITE_CALENDAR',CAMERA:'android.permission.CAMERA',READ_CONTACTS:'android.permission.READ_CONTACTS',WRITE_CONTACTS:'android.permission.WRITE_CONTACTS',GET_ACCOUNTS:'android.permission.GET_ACCOUNTS',ACCESS_FINE_LOCATION:'android.permission.ACCESS_FINE_LOCATION',ACCESS_COARSE_LOCATION:'android.permission.ACCESS_COARSE_LOCATION',ACCESS_BACKGROUND_LOCATION:'android.permission.ACCESS_BACKGROUND_LOCATION',RECORD_AUDIO:'android.permission.RECORD_AUDIO',READ_PHONE_STATE:'android.permission.READ_PHONE_STATE',CALL_PHONE:'android.permission.CALL_PHONE',READ_CALL_LOG:'android.permission.READ_CALL_LOG',WRITE_CALL_LOG:'android.permission.WRITE_CALL_LOG',ADD_VOICEMAIL:'com.android.voicemail.permission.ADD_VOICEMAIL',USE_SIP:'android.permission.USE_SIP',PROCESS_OUTGOING_CALLS:'android.permission.PROCESS_OUTGOING_CALLS',BODY_SENSORS:'android.permission.BODY_SENSORS',SEND_SMS:'android.permission.SEND_SMS',RECEIVE_SMS:'android.permission.RECEIVE_SMS',READ_SMS:'android.permission.READ_SMS',RECEIVE_WAP_PUSH:'android.permission.RECEIVE_WAP_PUSH',RECEIVE_MMS:'android.permission.RECEIVE_MMS',READ_EXTERNAL_STORAGE:'android.permission.READ_EXTERNAL_STORAGE',WRITE_EXTERNAL_STORAGE:'android.permission.WRITE_EXTERNAL_STORAGE',BLUETOOTH_CONNECT:'android.permission.BLUETOOTH_CONNECT',BLUETOOTH_SCAN:'android.permission.BLUETOOTH_SCAN',BLUETOOTH_ADVERTISE:'android.permission.BLUETOOTH_ADVERTISE'}),O=new((function(){function O(){(0,o.default)(this,O),this.PERMISSIONS=S,this.RESULTS=u}return(0,t.default)(O,[{key:"checkPermission",value:function(n){return console.warn('"PermissionsAndroid.checkPermission" is deprecated. Use "PermissionsAndroid.check" instead'),(0,_.default)(A.default,'PermissionsAndroid is not installed correctly.'),A.default.checkPermission(n)}},{key:"check",value:function(n){return(0,_.default)(A.default,'PermissionsAndroid is not installed correctly.'),A.default.checkPermission(n)}},{key:"requestPermission",value:function(s,o){var t;return n.default.async(function(E){for(;;)switch(E.prev=E.next){case 0:console.warn('"PermissionsAndroid.requestPermission" is deprecated. Use "PermissionsAndroid.request" instead'),E.next=4;break;case 4:return E.next=6,n.default.awrap(this.request(s,o));case 6:return t=E.sent,E.abrupt("return",t===this.RESULTS.GRANTED);case 8:case"end":return E.stop()}},null,this,null,Promise)}},{key:"request",value:function(o,t){return n.default.async(function(u){for(;;)switch(u.prev=u.next){case 0:u.next=3;break;case 3:if((0,_.default)(A.default,'PermissionsAndroid is not installed correctly.'),!t){u.next=10;break}return u.next=7,n.default.awrap(A.default.shouldShowRequestPermissionRationale(o));case 7:if(!u.sent||!E.default){u.next=10;break}return u.abrupt("return",new Promise(function(n,_){var u=(0,s.default)({},t);E.default.showAlert(u,function(){return _(new Error('Error showing rationale'))},function(){return n(A.default.requestPermission(o))})}));case 10:return u.abrupt("return",A.default.requestPermission(o));case 11:case"end":return u.stop()}},null,this,null,Promise)}},{key:"requestMultiple",value:function(n){return(0,_.default)(A.default,'PermissionsAndroid is not installed correctly.'),A.default.requestMultiplePermissions(n)}}]),O})());m.exports=O},377,[3,75,29,7,8,115,378,18]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in n)if("default"!==l&&Object.prototype.hasOwnProperty.call(n,l)){var p=c?Object.getOwnPropertyDescriptor(n,l):null;p&&(p.get||p.set)?Object.defineProperty(f,l,p):f[l]=n[l]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).get('PermissionsAndroid');e.default=n},378,[21]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),o=r(d[0])(r(d[2])),n=r(d[0])(r(d[3])),l=r(d[0])(r(d[4])),u=r(d[0])(r(d[5])),c=r(d[0])(r(d[6])),f=new n.default('ios'!==c.default.OS?null:l.default),s=new Map,v=(function(){function n(o){var l=this;(0,t.default)(this,n),this._data={},this._remoteNotificationCompleteCallbackCalled=!1,this._isRemote=o.remote,this._isRemote&&(this._notificationId=o.notificationId),o.remote?Object.keys(o).forEach(function(t){var n=o[t];'aps'===t?(l._alert=n.alert,l._sound=n.sound,l._badgeCount=n.badge,l._category=n.category,l._contentAvailable=n['content-available'],l._threadID=n['thread-id']):l._data[t]=n}):(this._badgeCount=o.applicationIconBadgeNumber,this._sound=o.soundName,this._alert=o.alertBody,this._data=o.userInfo,this._category=o.category)}return(0,o.default)(n,[{key:"finish",value:function(t){this._isRemote&&this._notificationId&&!this._remoteNotificationCompleteCallbackCalled&&(this._remoteNotificationCompleteCallbackCalled=!0,(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.onFinishRemoteNotification(this._notificationId,t))}},{key:"getMessage",value:function(){return this._alert}},{key:"getSound",value:function(){return this._sound}},{key:"getCategory",value:function(){return this._category}},{key:"getAlert",value:function(){return this._alert}},{key:"getContentAvailable",value:function(){return this._contentAvailable}},{key:"getBadgeCount",value:function(){return this._badgeCount}},{key:"getData",value:function(){return this._data}},{key:"getThreadID",value:function(){return this._threadID}}],[{key:"presentLocalNotification",value:function(t){(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.presentLocalNotification(t)}},{key:"scheduleLocalNotification",value:function(t){(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.scheduleLocalNotification(t)}},{key:"cancelAllLocalNotifications",value:function(){(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.cancelAllLocalNotifications()}},{key:"removeAllDeliveredNotifications",value:function(){(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.removeAllDeliveredNotifications()}},{key:"getDeliveredNotifications",value:function(t){(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.getDeliveredNotifications(t)}},{key:"removeDeliveredNotifications",value:function(t){(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.removeDeliveredNotifications(t)}},{key:"setApplicationIconBadgeNumber",value:function(t){(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.setApplicationIconBadgeNumber(t)}},{key:"getApplicationIconBadgeNumber",value:function(t){(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.getApplicationIconBadgeNumber(t)}},{key:"cancelLocalNotifications",value:function(t){(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.cancelLocalNotifications(t)}},{key:"getScheduledLocalNotifications",value:function(t){(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.getScheduledLocalNotifications(t)}},{key:"addEventListener",value:function(t,o){var l;(0,u.default)('notification'===t||'register'===t||'registrationError'===t||'localNotification'===t,'PushNotificationIOS only supports `notification`, `register`, `registrationError`, and `localNotification` events'),'notification'===t?l=f.addListener("remoteNotificationReceived",function(t){o(new n(t))}):'localNotification'===t?l=f.addListener("localNotificationReceived",function(t){o(new n(t))}):'register'===t?l=f.addListener("remoteNotificationsRegistered",function(t){o(t.deviceToken)}):'registrationError'===t&&(l=f.addListener("remoteNotificationRegistrationError",function(t){o(t)})),s.set(t,l)}},{key:"removeEventListener",value:function(t,o){(0,u.default)('notification'===t||'register'===t||'registrationError'===t||'localNotification'===t,'PushNotificationIOS only supports `notification`, `register`, `registrationError`, and `localNotification` events');var n=s.get(t);n&&(n.remove(),s.delete(t))}},{key:"requestPermissions",value:function(t){var o={alert:!0,badge:!0,sound:!0};return t&&(o={alert:!!t.alert,badge:!!t.badge,sound:!!t.sound}),(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.requestPermissions(o)}},{key:"abandonPermissions",value:function(){(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.abandonPermissions()}},{key:"checkPermissions",value:function(t){(0,u.default)('function'==typeof t,'Must provide a valid callback'),(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.checkPermissions(t)}},{key:"getInitialNotification",value:function(){return(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.getInitialNotification().then(function(t){return t&&new n(t)})}},{key:"getAuthorizationStatus",value:function(t){(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.getAuthorizationStatus(t)}}]),n})();v.FetchResult={NewData:'UIBackgroundFetchResultNewData',NoData:'UIBackgroundFetchResultNoData',ResultFailed:'UIBackgroundFetchResultFailed'},m.exports=v},379,[3,7,8,95,380,18,19]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in n)if("default"!==l&&Object.prototype.hasOwnProperty.call(n,l)){var p=c?Object.getOwnPropertyDescriptor(n,l):null;p&&(p.get||p.set)?Object.defineProperty(f,l,p):f[l]=n[l]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).get('PushNotificationManager');e.default=n},380,[21]); -__d(function(g,r,i,a,m,e,d){'use strict';var n={get:function(n){return console.warn('Settings is not yet supported on Android'),null},set:function(n){console.warn('Settings is not yet supported on Android')},watchKeys:function(n,t){return console.warn('Settings is not yet supported on Android'),-1},clearWatch:function(n){console.warn('Settings is not yet supported on Android')}};m.exports=n},381,[]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),s=r(d[0])(r(d[3])),l=(r(d[0])(r(d[4])),r(d[0])(r(d[5]))),o=(function(){function o(){(0,n.default)(this,o)}return(0,s.default)(o,null,[{key:"share",value:function(n){var s=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};r(d[6])('object'==typeof n&&null!==n,'Content to share must be a valid object'),r(d[6])('string'==typeof n.url||'string'==typeof n.message,'At least one of URL and message is required'),r(d[6])('object'==typeof s&&null!==s,'Options must be a valid object'),r(d[6])(l.default,'ShareModule should be registered on Android.'),r(d[6])(null==n.title||'string'==typeof n.title,'Invalid title: title should be a string.');var o={title:n.title,message:'string'==typeof n.message?n.message:void 0};return l.default.share(o,s.dialogTitle).then(function(n){return(0,t.default)({activityType:null},n)})}}]),o})();o.sharedAction='sharedAction',o.dismissedAction='dismissedAction',m.exports=o},382,[3,29,7,8,336,383,18]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in n)if("default"!==c&&Object.prototype.hasOwnProperty.call(n,c)){var p=l?Object.getOwnPropertyDescriptor(n,c):null;p&&(p.get||p.set)?Object.defineProperty(f,c,p):f[c]=n[c]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).get('ShareModule');e.default=n},383,[21]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),f=t.default.getConstants(),n={SHORT:f.SHORT,LONG:f.LONG,TOP:f.TOP,BOTTOM:f.BOTTOM,CENTER:f.CENTER,show:function(f,n){t.default.show(f,n)},showWithGravity:function(f,n,o){t.default.showWithGravity(f,n,o)},showWithGravityAndOffset:function(f,n,o,O,s){t.default.showWithGravityAndOffset(f,n,o,O,s)}};m.exports=n},384,[3,385]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,f=new WeakMap;return(t=function(t){return t?f:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var f=t(o);if(f&&f.has(n))return f.get(n);var u={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in n)if("default"!==l&&Object.prototype.hasOwnProperty.call(n,l)){var p=c?Object.getOwnPropertyDescriptor(n,l):null;p&&(p.get||p.set)?Object.defineProperty(u,l,p):u[l]=n[l]}u.default=n,f&&f.set(n,u);return u})(r(d[0])).getEnforcing('ToastAndroid');e.default=n},385,[21]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=function(){var t=(0,n.useMemo)(function(){return{getCurrentValue:function(){return u.default.getColorScheme()},subscribe:function(n){var t=u.default.addChangeListener(n);return function(){t.remove()}}}},[]);return(0,r(d[3]).useSubscription)(t)};var n=r(d[0]),u=r(d[1])(r(d[2]))},386,[129,3,337,387]); -__d(function(g,r,i,a,m,e,d){'use strict';m.exports=r(d[0])},387,[388]); -__d(function(_g,r,i,_a,m,e,_d){'use strict';var u=r(_d[0]);e.useSubscription=function(t){var n=t.getCurrentValue,a=t.subscribe,s=u.useState(function(){return{getCurrentValue:n,subscribe:a,value:n()}});t=s[0];var c=s[1];return s=t.value,t.getCurrentValue===n&&t.subscribe===a||(s=n(),c({getCurrentValue:n,subscribe:a,value:s})),u.useDebugValue(s),u.useEffect(function(){function u(){if(!t){var u=n();c(function(t){return t.getCurrentValue!==n||t.subscribe!==a||t.value===u?t:r(_d[1])({},t,{value:u})})}}var t=!1,s=a(u);return u(),function(){t=!0,s()}},[n,a]),s}},388,[129,131]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=function(){var f=(0,u.useState)(function(){return n.default.get('window')}),o=(0,t.default)(f,2),c=o[0],l=o[1];return(0,u.useEffect)(function(){function t(t){var n=t.window;c.width===n.width&&c.height===n.height&&c.scale===n.scale&&c.fontScale===n.fontScale||l(n)}var u=n.default.addEventListener('change',t);return t({window:n.default.get('window')}),function(){u.remove()}},[c]),c};var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),u=r(d[3])},389,[3,23,161,129]); -__d(function(g,r,i,a,m,e,d){'use strict';var A=r(d[0])({BOM:"\ufeff",BULLET:"\u2022",BULLET_SP:"\xa0\u2022\xa0",MIDDOT:"\xb7",MIDDOT_SP:"\xa0\xb7\xa0",MIDDOT_KATAKANA:"\u30fb",MDASH:"\u2014",MDASH_SP:"\xa0\u2014\xa0",NDASH:"\u2013",NDASH_SP:"\xa0\u2013\xa0",NBSP:"\xa0",PIZZA:"\ud83c\udf55",TRIANGLE_LEFT:"\u25c0",TRIANGLE_RIGHT:"\u25b6"});m.exports=A},390,[167]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),n=400;var o={vibrate:function(){var o=arguments.length>0&&void 0!==arguments[0]?arguments[0]:n,f=arguments.length>1&&void 0!==arguments[1]&&arguments[1];if('number'==typeof o)t.default.vibrate(o);else{if(!Array.isArray(o))throw new Error('Vibration pattern should be a number or array');t.default.vibrateByPattern(o,f?0:-1)}},cancel:function(){t.default.cancel()}};m.exports=o},391,[3,392]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,f=new WeakMap;return(t=function(t){return t?f:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var f=t(o);if(f&&f.has(n))return f.get(n);var u={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in n)if("default"!==l&&Object.prototype.hasOwnProperty.call(n,l)){var p=c?Object.getOwnPropertyDescriptor(n,l):null;p&&(p.get||p.set)?Object.defineProperty(u,l,p):u[l]=n[l]}u.default=n,f&&f.set(n,u);return u})(r(d[0])).getEnforcing('Vibration');e.default=n},392,[21]); -__d(function(g,r,i,a,m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var n;n=(function(n){r(d[3])(o,n);var e,u,c=(e=o,u=t(),function(){var t,n=r(d[0])(e);if(u){var c=r(d[0])(this).constructor;t=Reflect.construct(n,arguments,c)}else t=n.apply(this,arguments);return r(d[1])(this,t)});function o(){return r(d[4])(this,o),c.apply(this,arguments)}return r(d[5])(o,[{key:"render",value:function(){return null}}],[{key:"ignoreWarnings",value:function(t){}},{key:"install",value:function(){}},{key:"uninstall",value:function(){}}]),o})(r(d[2]).Component),m.exports=n},393,[15,12,129,10,7,8]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.DynamicColorIOS=void 0;e.DynamicColorIOS=function(o){throw new Error('DynamicColorIOS is not available on this platform.')}},394,[]); -__d(function(g,r,i,a,m,e,d){'use strict';var n=r(d[0]).shape({x:r(d[0]).number,y:r(d[0]).number});m.exports=n},395,[191]); -__d(function(g,r,i,a,m,_e,d){Object.defineProperty(_e,"__esModule",{value:!0}),_e.default=void 0;var e=r(d[0])(r(d[1])),t=r(d[0])(r(d[2])),n=r(d[0])(r(d[3])),u=r(d[0])(r(d[4])),s=r(d[0])(r(d[5])),o=r(d[0])(r(d[6])),c=(function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=p(t);if(n&&n.has(e))return n.get(e);var u={},s=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var o in e)if("default"!==o&&Object.prototype.hasOwnProperty.call(e,o)){var c=s?Object.getOwnPropertyDescriptor(e,o):null;c&&(c.get||c.set)?Object.defineProperty(u,o,c):u[o]=e[o]}u.default=e,n&&n.set(e,u);return u})(r(d[7])),l=r(d[8]),f=r(d[0])(r(d[9]));function p(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(p=function(e){return e?n:t})(e)}function h(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}var y=(function(p){(0,u.default)(w,p);var y,v,b=(y=w,v=h(),function(){var e,t=(0,o.default)(y);if(v){var n=(0,o.default)(this).constructor;e=Reflect.construct(t,arguments,n)}else e=t.apply(this,arguments);return(0,s.default)(this,e)});function w(n){var u;return(0,t.default)(this,w),(u=b.call(this,n)).infer=function(){var t,n,s,o,c,l,p,h,y,v,b,w;return e.default.async(function(P){for(;;)switch(P.prev=P.next){case 0:return P.prev=0,t={},P.next=4,e.default.awrap(f.default.preprocess(u.state.imagePath));case 4:for(o in n=P.sent,s={},n)Object.hasOwnProperty.call(n,o)&&(c=r(d[10]).Buffer.from(n[o].data,'base64'),l=new Float32Array(c.buffer,c.byteOffset,c.length/Float32Array.BYTES_PER_ELEMENT),s[o]=new(r(d[11]).Tensor)(n[o].type,l,n[o].dims));return P.next=9,e.default.awrap(u.state.session.run(s,u.state.session.outputNames,t));case 9:for(y in p=P.sent,h={},p)Object.hasOwnProperty.call(p,y)&&(v=p[y].data.buffer,b={data:r(d[10]).Buffer.from(v,0,v.byteLength).toString('base64')},h[y]=b);return P.next=14,e.default.awrap(f.default.postprocess(h));case 14:w=P.sent,u.setState({output:w.result}),P.next=21;break;case 18:P.prev=18,P.t0=P.catch(0),console.log(P.t0.message);case 21:case"end":return P.stop()}},null,null,[[0,18]],Promise)},u.state={session:null,output:null,imagePath:null},u}return(0,n.default)(w,[{key:"componentDidMount",value:function(){var t,n,u;return e.default.async(function(s){for(;;)switch(s.prev=s.next){case 0:if(this.state.session){s.next=19;break}return s.prev=1,s.next=4,e.default.awrap(f.default.getImagePath());case 4:return t=s.sent,this.setState({imagePath:t}),s.next=8,e.default.awrap(f.default.getLocalModelPath());case 8:return n=s.sent,s.next=11,e.default.awrap(r(d[11]).InferenceSession.create(n));case 11:u=s.sent,this.setState({session:u}),this.infer(),s.next=19;break;case 16:s.prev=16,s.t0=s.catch(1),console.log(s.t0.message);case 19:case"end":return s.stop()}},null,this,[[1,16]],Promise)}},{key:"render",value:function(){var e=this.state,t=e.output,n=e.imagePath;return c.createElement(l.View,null,c.createElement(l.Text,null,'\n'),n&&c.createElement(l.Image,{source:{uri:n},style:{height:200,width:200,resizeMode:'stretch'}}),t&&c.createElement(l.TextInput,{accessibilityLabel:"output"},"Result: ",t))}}]),w})(c.PureComponent);_e.default=y},396,[3,75,7,8,10,12,15,129,1,397,398,400]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var t=r(d[0]).NativeModules.MNISTDataHandler;e.default=t},397,[1]); -__d(function(g,r,_i,_a,_m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var e='function'==typeof Symbol&&'function'==typeof Symbol.for?Symbol.for('nodejs.util.inspect.custom'):null;_e.Buffer=o,_e.SlowBuffer=function(t){+t!=t&&(t=0);return o.alloc(+t)},_e.INSPECT_MAX_BYTES=50;var n=2147483647;function i(t){if(t>n)throw new RangeError('The value "'+t+'" is invalid for option "size"');var e=new Uint8Array(t);return Object.setPrototypeOf(e,o.prototype),e}function o(t,e,n){if('number'==typeof t){if('string'==typeof e)throw new TypeError('The "string" argument must be of type string. Received type number');return h(t)}return f(t,e,n)}function f(t,e,n){if('string'==typeof t)return a(t,e);if(ArrayBuffer.isView(t))return c(t);if(null==t)throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof t);if(nt(t,ArrayBuffer)||t&&nt(t.buffer,ArrayBuffer))return l(t,e,n);if('undefined'!=typeof SharedArrayBuffer&&(nt(t,SharedArrayBuffer)||t&&nt(t.buffer,SharedArrayBuffer)))return l(t,e,n);if('number'==typeof t)throw new TypeError('The "value" argument must not be of type number. Received type number');var i=t.valueOf&&t.valueOf();if(null!=i&&i!==t)return o.from(i,e,n);var f=y(t);if(f)return f;if('undefined'!=typeof Symbol&&null!=Symbol.toPrimitive&&'function'==typeof t[Symbol.toPrimitive])return o.from(t[Symbol.toPrimitive]('string'),e,n);throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof t)}function u(t){if('number'!=typeof t)throw new TypeError('"size" argument must be of type number');if(t<0)throw new RangeError('The value "'+t+'" is invalid for option "size"')}function s(t,e,n){return u(t),t<=0?i(t):void 0!==e?'string'==typeof n?i(t).fill(e,n):i(t).fill(e):i(t)}function h(t){return u(t),i(t<0?0:0|w(t))}function a(t,e){if('string'==typeof e&&''!==e||(e='utf8'),!o.isEncoding(e))throw new TypeError('Unknown encoding: '+e);var n=0|v(t,e),f=i(n),u=f.write(t,e);return u!==n&&(f=f.slice(0,u)),f}function p(t){for(var e=t.length<0?0:0|w(t.length),n=i(e),o=0;o=n)throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+n.toString(16)+' bytes');return 0|t}function v(t,e){if(o.isBuffer(t))return t.length;if(ArrayBuffer.isView(t)||nt(t,ArrayBuffer))return t.byteLength;if('string'!=typeof t)throw new TypeError("The \"string\" argument must be one of type string, Buffer, or ArrayBuffer. Received type "+typeof t);var n=t.length,i=arguments.length>2&&!0===arguments[2];if(!i&&0===n)return 0;for(var f=!1;;)switch(e){case'ascii':case'latin1':case'binary':return n;case'utf8':case'utf-8':return K(t).length;case'ucs2':case'ucs-2':case'utf16le':case'utf-16le':return 2*n;case'hex':return n>>>1;case'base64':return rt(t).length;default:if(f)return i?-1:K(t).length;e=(''+e).toLowerCase(),f=!0}}function b(t,e,n){var i=!1;if((void 0===e||e<0)&&(e=0),e>this.length)return'';if((void 0===n||n>this.length)&&(n=this.length),n<=0)return'';if((n>>>=0)<=(e>>>=0))return'';for(t||(t='utf8');;)switch(t){case'hex':return P(this,e,n);case'utf8':case'utf-8':return L(this,e,n);case'ascii':return S(this,e,n);case'latin1':case'binary':return x(this,e,n);case'base64':return O(this,e,n);case'ucs2':case'ucs-2':case'utf16le':case'utf-16le':return k(this,e,n);default:if(i)throw new TypeError('Unknown encoding: '+t);t=(t+'').toLowerCase(),i=!0}}function B(t,e,n){var i=t[e];t[e]=t[n],t[n]=i}function E(t,e,n,i,f){if(0===t.length)return-1;if('string'==typeof n?(i=n,n=0):n>2147483647?n=2147483647:n<-2147483648&&(n=-2147483648),it(n=+n)&&(n=f?0:t.length-1),n<0&&(n=t.length+n),n>=t.length){if(f)return-1;n=t.length-1}else if(n<0){if(!f)return-1;n=0}if('string'==typeof e&&(e=o.from(e,i)),o.isBuffer(e))return 0===e.length?-1:m(t,e,n,i,f);if('number'==typeof e)return e&=255,'function'==typeof Uint8Array.prototype.indexOf?f?Uint8Array.prototype.indexOf.call(t,e,n):Uint8Array.prototype.lastIndexOf.call(t,e,n):m(t,[e],n,i,f);throw new TypeError('val must be string, number or Buffer')}function m(t,e,n,i,o){var f,u=1,s=t.length,h=e.length;if(void 0!==i&&('ucs2'===(i=String(i).toLowerCase())||'ucs-2'===i||'utf16le'===i||'utf-16le'===i)){if(t.length<2||e.length<2)return-1;u=2,s/=2,h/=2,n/=2}function a(t,e){return 1===u?t[e]:t.readUInt16BE(e*u)}if(o){var p=-1;for(f=n;fs&&(n=s-h),f=n;f>=0;f--){for(var c=!0,l=0;lo&&(i=o):i=o;var f,u=e.length;for(i>u/2&&(i=u/2),f=0;f239?4:f>223?3:f>191?2:1;if(o+s<=n){var h=void 0,a=void 0,p=void 0,c=void 0;switch(s){case 1:f<128&&(u=f);break;case 2:128==(192&(h=t[o+1]))&&(c=(31&f)<<6|63&h)>127&&(u=c);break;case 3:h=t[o+1],a=t[o+2],128==(192&h)&&128==(192&a)&&(c=(15&f)<<12|(63&h)<<6|63&a)>2047&&(c<55296||c>57343)&&(u=c);break;case 4:h=t[o+1],a=t[o+2],p=t[o+3],128==(192&h)&&128==(192&a)&&128==(192&p)&&(c=(15&f)<<18|(63&h)<<12|(63&a)<<6|63&p)>65535&&c<1114112&&(u=c)}}null===u?(u=65533,s=1):u>65535&&(u-=65536,i.push(u>>>10&1023|55296),u=56320|1023&u),i.push(u),o+=s}return _(i)}_e.kMaxLength=n,o.TYPED_ARRAY_SUPPORT=(function(){try{var t=new Uint8Array(1),e={foo:function(){return 42}};return Object.setPrototypeOf(e,Uint8Array.prototype),Object.setPrototypeOf(t,e),42===t.foo()}catch(t){return!1}})(),o.TYPED_ARRAY_SUPPORT||'undefined'==typeof console||'function'!=typeof console.error||console.error("This browser lacks typed array (Uint8Array) support which is required by `buffer` v5.x. Use `buffer` v4.x if you require old browser support."),Object.defineProperty(o.prototype,'parent',{enumerable:!0,get:function(){if(o.isBuffer(this))return this.buffer}}),Object.defineProperty(o.prototype,'offset',{enumerable:!0,get:function(){if(o.isBuffer(this))return this.byteOffset}}),o.poolSize=8192,o.from=function(t,e,n){return f(t,e,n)},Object.setPrototypeOf(o.prototype,Uint8Array.prototype),Object.setPrototypeOf(o,Uint8Array),o.alloc=function(t,e,n){return s(t,e,n)},o.allocUnsafe=function(t){return h(t)},o.allocUnsafeSlow=function(t){return h(t)},o.isBuffer=function(t){return null!=t&&!0===t._isBuffer&&t!==o.prototype},o.compare=function(t,e){if(nt(t,Uint8Array)&&(t=o.from(t,t.offset,t.byteLength)),nt(e,Uint8Array)&&(e=o.from(e,e.offset,e.byteLength)),!o.isBuffer(t)||!o.isBuffer(e))throw new TypeError('The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array');if(t===e)return 0;for(var n=t.length,i=e.length,f=0,u=Math.min(n,i);fi.length?(o.isBuffer(u)||(u=o.from(u)),u.copy(i,f)):Uint8Array.prototype.set.call(i,u,f);else{if(!o.isBuffer(u))throw new TypeError('"list" argument must be an Array of Buffers');u.copy(i,f)}f+=u.length}return i},o.byteLength=v,o.prototype._isBuffer=!0,o.prototype.swap16=function(){var t=this.length;if(t%2!=0)throw new RangeError('Buffer size must be a multiple of 16-bits');for(var e=0;ee&&(t+=' ... '),''},e&&(o.prototype[e]=o.prototype.inspect),o.prototype.compare=function(t,e,n,i,f){if(nt(t,Uint8Array)&&(t=o.from(t,t.offset,t.byteLength)),!o.isBuffer(t))throw new TypeError("The \"target\" argument must be one of type Buffer or Uint8Array. Received type "+typeof t);if(void 0===e&&(e=0),void 0===n&&(n=t?t.length:0),void 0===i&&(i=0),void 0===f&&(f=this.length),e<0||n>t.length||i<0||f>this.length)throw new RangeError('out of range index');if(i>=f&&e>=n)return 0;if(i>=f)return-1;if(e>=n)return 1;if(e>>>=0,n>>>=0,i>>>=0,f>>>=0,this===t)return 0;for(var u=f-i,s=n-e,h=Math.min(u,s),a=this.slice(i,f),p=t.slice(e,n),c=0;c>>=0,isFinite(n)?(n>>>=0,void 0===i&&(i='utf8')):(i=n,n=void 0)}var o=this.length-e;if((void 0===n||n>o)&&(n=o),t.length>0&&(n<0||e<0)||e>this.length)throw new RangeError('Attempt to write outside buffer bounds');i||(i='utf8');for(var f=!1;;)switch(i){case'hex':return I(this,t,e,n);case'utf8':case'utf-8':return U(this,t,e,n);case'ascii':case'latin1':case'binary':return A(this,t,e,n);case'base64':return R(this,t,e,n);case'ucs2':case'ucs-2':case'utf16le':case'utf-16le':return T(this,t,e,n);default:if(f)throw new TypeError('Unknown encoding: '+i);i=(''+i).toLowerCase(),f=!0}},o.prototype.toJSON=function(){return{type:'Buffer',data:Array.prototype.slice.call(this._arr||this,0)}};var M=4096;function _(t){var e=t.length;if(e<=M)return String.fromCharCode.apply(String,t);for(var n='',i=0;ii)&&(n=i);for(var o='',f=e;fn)throw new RangeError('Trying to access beyond buffer length')}function N(t,e,n,i,f,u){if(!o.isBuffer(t))throw new TypeError('"buffer" argument must be a Buffer instance');if(e>f||et.length)throw new RangeError('Index out of range')}function F(t,e,n,i,o){X(e,i,o,t,n,7);var f=Number(e&BigInt(4294967295));t[n++]=f,f>>=8,t[n++]=f,f>>=8,t[n++]=f,f>>=8,t[n++]=f;var u=Number(e>>BigInt(32)&BigInt(4294967295));return t[n++]=u,u>>=8,t[n++]=u,u>>=8,t[n++]=u,u>>=8,t[n++]=u,n}function j(t,e,n,i,o){X(e,i,o,t,n,7);var f=Number(e&BigInt(4294967295));t[n+7]=f,f>>=8,t[n+6]=f,f>>=8,t[n+5]=f,f>>=8,t[n+4]=f;var u=Number(e>>BigInt(32)&BigInt(4294967295));return t[n+3]=u,u>>=8,t[n+2]=u,u>>=8,t[n+1]=u,u>>=8,t[n]=u,n+8}function D(t,e,n,i,o,f){if(n+i>t.length)throw new RangeError('Index out of range');if(n<0)throw new RangeError('Index out of range')}function z(t,e,n,i,o){return e=+e,n>>>=0,o||D(t,0,n,4),r(d[3]).write(t,e,n,i,23,4),n+4}function Y(t,e,n,i,o){return e=+e,n>>>=0,o||D(t,0,n,8),r(d[3]).write(t,e,n,i,52,8),n+8}o.prototype.slice=function(t,e){var n=this.length;t=~~t,e=void 0===e?n:~~e,t<0?(t+=n)<0&&(t=0):t>n&&(t=n),e<0?(e+=n)<0&&(e=0):e>n&&(e=n),e>>=0,e>>>=0,n||C(t,e,this.length);for(var i=this[t],o=1,f=0;++f>>=0,e>>>=0,n||C(t,e,this.length);for(var i=this[t+--e],o=1;e>0&&(o*=256);)i+=this[t+--e]*o;return i},o.prototype.readUint8=o.prototype.readUInt8=function(t,e){return t>>>=0,e||C(t,1,this.length),this[t]},o.prototype.readUint16LE=o.prototype.readUInt16LE=function(t,e){return t>>>=0,e||C(t,2,this.length),this[t]|this[t+1]<<8},o.prototype.readUint16BE=o.prototype.readUInt16BE=function(t,e){return t>>>=0,e||C(t,2,this.length),this[t]<<8|this[t+1]},o.prototype.readUint32LE=o.prototype.readUInt32LE=function(t,e){return t>>>=0,e||C(t,4,this.length),(this[t]|this[t+1]<<8|this[t+2]<<16)+16777216*this[t+3]},o.prototype.readUint32BE=o.prototype.readUInt32BE=function(t,e){return t>>>=0,e||C(t,4,this.length),16777216*this[t]+(this[t+1]<<16|this[t+2]<<8|this[t+3])},o.prototype.readBigUInt64LE=ft(function(t){J(t>>>=0,'offset');var e=this[t],n=this[t+7];void 0!==e&&void 0!==n||Z(t,this.length-8);var i=e+this[++t]*Math.pow(2,8)+this[++t]*Math.pow(2,16)+this[++t]*Math.pow(2,24),o=this[++t]+this[++t]*Math.pow(2,8)+this[++t]*Math.pow(2,16)+n*Math.pow(2,24);return BigInt(i)+(BigInt(o)<>>=0,'offset');var e=this[t],n=this[t+7];void 0!==e&&void 0!==n||Z(t,this.length-8);var i=e*Math.pow(2,24)+this[++t]*Math.pow(2,16)+this[++t]*Math.pow(2,8)+this[++t],o=this[++t]*Math.pow(2,24)+this[++t]*Math.pow(2,16)+this[++t]*Math.pow(2,8)+n;return(BigInt(i)<>>=0,e>>>=0,n||C(t,e,this.length);for(var i=this[t],o=1,f=0;++f=(o*=128)&&(i-=Math.pow(2,8*e)),i},o.prototype.readIntBE=function(t,e,n){t>>>=0,e>>>=0,n||C(t,e,this.length);for(var i=e,o=1,f=this[t+--i];i>0&&(o*=256);)f+=this[t+--i]*o;return f>=(o*=128)&&(f-=Math.pow(2,8*e)),f},o.prototype.readInt8=function(t,e){return t>>>=0,e||C(t,1,this.length),128&this[t]?-1*(255-this[t]+1):this[t]},o.prototype.readInt16LE=function(t,e){t>>>=0,e||C(t,2,this.length);var n=this[t]|this[t+1]<<8;return 32768&n?4294901760|n:n},o.prototype.readInt16BE=function(t,e){t>>>=0,e||C(t,2,this.length);var n=this[t+1]|this[t]<<8;return 32768&n?4294901760|n:n},o.prototype.readInt32LE=function(t,e){return t>>>=0,e||C(t,4,this.length),this[t]|this[t+1]<<8|this[t+2]<<16|this[t+3]<<24},o.prototype.readInt32BE=function(t,e){return t>>>=0,e||C(t,4,this.length),this[t]<<24|this[t+1]<<16|this[t+2]<<8|this[t+3]},o.prototype.readBigInt64LE=ft(function(t){J(t>>>=0,'offset');var e=this[t],n=this[t+7];void 0!==e&&void 0!==n||Z(t,this.length-8);var i=this[t+4]+this[t+5]*Math.pow(2,8)+this[t+6]*Math.pow(2,16)+(n<<24);return(BigInt(i)<>>=0,'offset');var e=this[t],n=this[t+7];void 0!==e&&void 0!==n||Z(t,this.length-8);var i=(e<<24)+this[++t]*Math.pow(2,16)+this[++t]*Math.pow(2,8)+this[++t];return(BigInt(i)<>>=0,e||C(t,4,this.length),r(d[3]).read(this,t,!0,23,4)},o.prototype.readFloatBE=function(t,e){return t>>>=0,e||C(t,4,this.length),r(d[3]).read(this,t,!1,23,4)},o.prototype.readDoubleLE=function(t,e){return t>>>=0,e||C(t,8,this.length),r(d[3]).read(this,t,!0,52,8)},o.prototype.readDoubleBE=function(t,e){return t>>>=0,e||C(t,8,this.length),r(d[3]).read(this,t,!1,52,8)},o.prototype.writeUintLE=o.prototype.writeUIntLE=function(t,e,n,i){(t=+t,e>>>=0,n>>>=0,i)||N(this,t,e,n,Math.pow(2,8*n)-1,0);var o=1,f=0;for(this[e]=255&t;++f>>=0,n>>>=0,i)||N(this,t,e,n,Math.pow(2,8*n)-1,0);var o=n-1,f=1;for(this[e+o]=255&t;--o>=0&&(f*=256);)this[e+o]=t/f&255;return e+n},o.prototype.writeUint8=o.prototype.writeUInt8=function(t,e,n){return t=+t,e>>>=0,n||N(this,t,e,1,255,0),this[e]=255&t,e+1},o.prototype.writeUint16LE=o.prototype.writeUInt16LE=function(t,e,n){return t=+t,e>>>=0,n||N(this,t,e,2,65535,0),this[e]=255&t,this[e+1]=t>>>8,e+2},o.prototype.writeUint16BE=o.prototype.writeUInt16BE=function(t,e,n){return t=+t,e>>>=0,n||N(this,t,e,2,65535,0),this[e]=t>>>8,this[e+1]=255&t,e+2},o.prototype.writeUint32LE=o.prototype.writeUInt32LE=function(t,e,n){return t=+t,e>>>=0,n||N(this,t,e,4,4294967295,0),this[e+3]=t>>>24,this[e+2]=t>>>16,this[e+1]=t>>>8,this[e]=255&t,e+4},o.prototype.writeUint32BE=o.prototype.writeUInt32BE=function(t,e,n){return t=+t,e>>>=0,n||N(this,t,e,4,4294967295,0),this[e]=t>>>24,this[e+1]=t>>>16,this[e+2]=t>>>8,this[e+3]=255&t,e+4},o.prototype.writeBigUInt64LE=ft(function(t){return F(this,t,arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,BigInt(0),BigInt('0xffffffffffffffff'))}),o.prototype.writeBigUInt64BE=ft(function(t){return j(this,t,arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,BigInt(0),BigInt('0xffffffffffffffff'))}),o.prototype.writeIntLE=function(t,e,n,i){if(t=+t,e>>>=0,!i){var o=Math.pow(2,8*n-1);N(this,t,e,n,o-1,-o)}var f=0,u=1,s=0;for(this[e]=255&t;++f>0)-s&255;return e+n},o.prototype.writeIntBE=function(t,e,n,i){if(t=+t,e>>>=0,!i){var o=Math.pow(2,8*n-1);N(this,t,e,n,o-1,-o)}var f=n-1,u=1,s=0;for(this[e+f]=255&t;--f>=0&&(u*=256);)t<0&&0===s&&0!==this[e+f+1]&&(s=1),this[e+f]=(t/u>>0)-s&255;return e+n},o.prototype.writeInt8=function(t,e,n){return t=+t,e>>>=0,n||N(this,t,e,1,127,-128),t<0&&(t=255+t+1),this[e]=255&t,e+1},o.prototype.writeInt16LE=function(t,e,n){return t=+t,e>>>=0,n||N(this,t,e,2,32767,-32768),this[e]=255&t,this[e+1]=t>>>8,e+2},o.prototype.writeInt16BE=function(t,e,n){return t=+t,e>>>=0,n||N(this,t,e,2,32767,-32768),this[e]=t>>>8,this[e+1]=255&t,e+2},o.prototype.writeInt32LE=function(t,e,n){return t=+t,e>>>=0,n||N(this,t,e,4,2147483647,-2147483648),this[e]=255&t,this[e+1]=t>>>8,this[e+2]=t>>>16,this[e+3]=t>>>24,e+4},o.prototype.writeInt32BE=function(t,e,n){return t=+t,e>>>=0,n||N(this,t,e,4,2147483647,-2147483648),t<0&&(t=4294967295+t+1),this[e]=t>>>24,this[e+1]=t>>>16,this[e+2]=t>>>8,this[e+3]=255&t,e+4},o.prototype.writeBigInt64LE=ft(function(t){return F(this,t,arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,-BigInt('0x8000000000000000'),BigInt('0x7fffffffffffffff'))}),o.prototype.writeBigInt64BE=ft(function(t){return j(this,t,arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,-BigInt('0x8000000000000000'),BigInt('0x7fffffffffffffff'))}),o.prototype.writeFloatLE=function(t,e,n){return z(this,t,e,!0,n)},o.prototype.writeFloatBE=function(t,e,n){return z(this,t,e,!1,n)},o.prototype.writeDoubleLE=function(t,e,n){return Y(this,t,e,!0,n)},o.prototype.writeDoubleBE=function(t,e,n){return Y(this,t,e,!1,n)},o.prototype.copy=function(t,e,n,i){if(!o.isBuffer(t))throw new TypeError('argument should be a Buffer');if(n||(n=0),i||0===i||(i=this.length),e>=t.length&&(e=t.length),e||(e=0),i>0&&i=this.length)throw new RangeError('Index out of range');if(i<0)throw new RangeError('sourceEnd out of bounds');i>this.length&&(i=this.length),t.length-e>>=0,n=void 0===n?this.length:n>>>0,t||(t=0),'number'==typeof t)for(u=e;u=i+4;n-=3)e="_"+t.slice(n-3,n)+e;return""+t.slice(0,n)+e}function W(t,e,n){J(e,'offset'),void 0!==t[e]&&void 0!==t[e+n]||Z(e,t.length-(n+1))}function X(t,e,n,i,o,f){if(t>n||t3?0===e||e===BigInt(0)?">= 0"+s+" and < 2"+s+" ** "+8*(f+1)+s:">= -(2"+s+" ** "+(8*(f+1)-1)+s+") and < 2 ** "+(8*(f+1)-1)+s:">= "+e+s+" and <= "+n+s,new G.ERR_OUT_OF_RANGE('value',u,t)}W(i,o,f)}function J(t,e){if('number'!=typeof t)throw new G.ERR_INVALID_ARG_TYPE(e,'number',t)}function Z(t,e,n){if(Math.floor(t)!==t)throw J(t,n),new G.ERR_OUT_OF_RANGE(n||'offset','an integer',t);if(e<0)throw new G.ERR_BUFFER_OUT_OF_BOUNDS;throw new G.ERR_OUT_OF_RANGE(n||'offset',">= "+(n?1:0)+" and <= "+e,t)}V('ERR_BUFFER_OUT_OF_BOUNDS',function(t){return t?t+" is outside of buffer bounds":'Attempt to access memory outside buffer bounds'},RangeError),V('ERR_INVALID_ARG_TYPE',function(t,e){return"The \""+t+"\" argument must be of type number. Received type "+typeof e},TypeError),V('ERR_OUT_OF_RANGE',function(t,e,n){var i="The value of \""+t+"\" is out of range.",o=n;return Number.isInteger(n)&&Math.abs(n)>Math.pow(2,32)?o=q(String(n)):'bigint'==typeof n&&(o=String(n),(n>Math.pow(BigInt(2),BigInt(32))||n<-Math.pow(BigInt(2),BigInt(32)))&&(o=q(o)),o+='n'),i+=" It must be "+e+". Received "+o},RangeError);var $=/[^+/0-9A-Za-z-_]/g;function H(t){if((t=(t=t.split('=')[0]).trim().replace($,'')).length<2)return'';for(;t.length%4!=0;)t+='=';return t}function K(t,e){var n;e=e||1/0;for(var i=t.length,o=null,f=[],u=0;u55295&&n<57344){if(!o){if(n>56319){(e-=3)>-1&&f.push(239,191,189);continue}if(u+1===i){(e-=3)>-1&&f.push(239,191,189);continue}o=n;continue}if(n<56320){(e-=3)>-1&&f.push(239,191,189),o=n;continue}n=65536+(o-55296<<10|n-56320)}else o&&(e-=3)>-1&&f.push(239,191,189);if(o=null,n<128){if((e-=1)<0)break;f.push(n)}else if(n<2048){if((e-=2)<0)break;f.push(n>>6|192,63&n|128)}else if(n<65536){if((e-=3)<0)break;f.push(n>>12|224,n>>6&63|128,63&n|128)}else{if(!(n<1114112))throw new Error('Invalid code point');if((e-=4)<0)break;f.push(n>>18|240,n>>12&63|128,n>>6&63|128,63&n|128)}}return f}function Q(t){for(var e=[],n=0;n>8,o=n%256,f.push(o),f.push(i);return f}function rt(t){return r(d[2]).toByteArray(H(t))}function et(t,e,n,i){var o;for(o=0;o=e.length||o>=t.length);++o)e[o+n]=t[o];return o}function nt(t,e){return t instanceof e||null!=t&&null!=t.constructor&&null!=t.constructor.name&&t.constructor.name===e.name}function it(t){return t!=t}var ot=(function(){for(var t=new Array(256),e=0;e<16;++e)for(var n=16*e,i=0;i<16;++i)t[n+i]="0123456789abcdef"[e]+"0123456789abcdef"[i];return t})();function ft(t){return'undefined'==typeof BigInt?ut:t}function ut(){throw new Error('BigInt not supported')}},398,[15,12,93,399,10,7,14,8]); -__d(function(g,r,_i,a,_m,_e,_d){_e.read=function(o,t,h,M,f){var w,p,i=8*f-M-1,n=(1<>1,e=-7,u=h?f-1:0,s=h?-1:1,c=o[t+u];for(u+=s,w=c&(1<<-e)-1,c>>=-e,e+=i;e>0;w=256*w+o[t+u],u+=s,e-=8);for(p=w&(1<<-e)-1,w>>=-e,e+=M;e>0;p=256*p+o[t+u],u+=s,e-=8);if(0===w)w=1-N;else{if(w===n)return p?NaN:1/0*(c?-1:1);p+=Math.pow(2,M),w-=N}return(c?-1:1)*p*Math.pow(2,w-M)},_e.write=function(o,t,h,M,f,w){var p,i,n,N=8*w-f-1,e=(1<>1,s=23===f?Math.pow(2,-24)-Math.pow(2,-77):0,c=M?0:w-1,l=M?1:-1,d=t<0||0===t&&1/t<0?1:0;for(t=Math.abs(t),isNaN(t)||t===1/0?(i=isNaN(t)?1:0,p=e):(p=Math.floor(Math.log(t)/Math.LN2),t*(n=Math.pow(2,-p))<1&&(p--,n*=2),(t+=p+u>=1?s/n:s*Math.pow(2,1-u))*n>=2&&(p++,n/=2),p+u>=e?(i=0,p=e):p+u>=1?(i=(t*n-1)*Math.pow(2,f),p+=u):(i=t*Math.pow(2,u-1)*Math.pow(2,f),p=0));f>=8;o[h+c]=255&i,c+=l,i/=256,f-=8);for(p=p<0;o[h+c]=255&p,c+=l,p/=256,N-=8);o[h+c-l]|=128*d}},399,[]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),Object.keys(r(d[0])).forEach(function(n){"default"!==n&&"__esModule"!==n&&(n in e&&e[n]===r(d[0])[n]||Object.defineProperty(e,n,{enumerable:!0,get:function(){return r(d[0])[n]}}))}),(0,r(d[0]).registerBackend)('cpu',r(d[1]).onnxruntimeBackend,1)},400,[401,406]); -__d(function(g,_r5,_i2,_a2,m,_e6,_d){function e(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(n)return(n=n.call(e)).next.bind(n);if(Array.isArray(e)||(n=r(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var a=0;return function(){return a>=e.length?{done:!0}:{done:!1,value:e[a++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function r(e,r){if(e){if("string"==typeof e)return t(e,r);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?t(e,r):void 0}}function t(e,r){(null==r||r>e.length)&&(r=e.length);for(var t=0,n=new Array(r);t=0){for(var o=0;o=c.byteLength)){h.next=32;break}throw new RangeError("'byteOffset' is out of range [0, "+c.byteLength+").");case 32:if(y=t.byteLength-b,"number"!=typeof o){h.next=45;break}if(y=o,Number.isSafeInteger(y)){h.next=35;break}throw new RangeError("'byteLength' must be an integer.");case 35:if(!(y<=0||b+y>c.byteLength)){h.next=37;break}throw new RangeError("'byteLength' is out of range (0, "+(c.byteLength-b)+"].");case 37:if("object"!=typeof s||null===s){h.next=41;break}f=s,h.next=43;break;case 41:if(void 0===s){h.next=43;break}throw new TypeError("'options' must be an object.");case 43:h.next=47;break;case 45:if(void 0===o){h.next=47;break}throw new TypeError("'byteLength' must be a number.");case 47:h.next=51;break;case 49:if(void 0===i){h.next=51;break}throw new TypeError("'options' must be an object.");case 51:u=new Uint8Array(c,b,y);case 52:return l=(f.executionProviders||[]).map(function(e){return"string"==typeof e?e:e.name}),h.next=55,_r5(_d[2]).awrap((function(r){var t,i,o,s,u,f;return _r5(_d[2]).async(function(c){for(;;)switch(c.prev=c.next){case 0:t=0===r.length?a:r,i=[],o=e(t);case 2:if((s=o()).done){c.next=28;break}if(u=s.value,!(f=n[u])){c.next=26;break}if(!f.initialized){c.next=8;break}return c.abrupt("return",f.backend);case 8:if(!f.initializing){c.next=10;break}throw new Error("backend \""+u+"\" is being initialized; cannot initialize multiple times.");case 10:if(!f.aborted){c.next=12;break}return c.abrupt("continue",26);case 12:return c.prev=12,f.initializing=!0,c.next=16,_r5(_d[2]).awrap(f.backend.init());case 16:return f.initialized=!0,c.abrupt("return",f.backend);case 20:c.prev=20,c.t0=c.catch(12),i.push({name:u,err:c.t0}),f.aborted=!0;case 23:return c.prev=23,f.initializing=!1,c.finish(23);case 26:c.next=2;break;case 28:throw new Error("no available backend found. ERR: "+i.map(function(e){return"["+e.name+"] "+e.err}).join(", "));case 29:case"end":return c.stop()}},null,null,[[12,20,23,26]],Promise)})(l));case 55:return p=h.sent,h.next=58,_r5(_d[2]).awrap(p.createSessionHandler(u,f));case 58:return d=h.sent,h.abrupt("return",new r(d));case 60:case"end":return h.stop()}},null,null,null,Promise)}}]),r})(),l=_e6;for(var p in t)l[p]=t[p];t.__esModule&&Object.defineProperty(l,"__esModule",{value:!0})})()},401,[402,403,404]); -__d(function(g,r,i,a,m,e,d){m.exports=function(o,n){if(!(o instanceof n))throw new TypeError("Cannot call a class as a function")},m.exports.__esModule=!0,m.exports.default=m.exports},402,[]); -__d(function(g,r,_i,a,m,e,d){function t(t,o){for(var n=0;n=0;--u){var h=this.tryEntries[u],f=h.completion;if("root"===h.tryLoc)return c("end");if(h.tryLoc<=this.prev){var l=i.call(h,"catchLoc"),s=i.call(h,"finallyLoc");if(l&&s){if(this.prev=0;--o){var c=this.tryEntries[o];if(c.tryLoc<=this.prev&&i.call(c,"finallyLoc")&&this.prev=0;--n){var o=this.tryEntries[n];if(o.finallyLoc===t)return this.complete(o.completion,o.afterLoc),I(o),x}},catch:function(t){for(var n=this.tryEntries.length-1;n>=0;--n){var o=this.tryEntries[n];if(o.tryLoc===t){var i=o.completion;if("throw"===i.type){var c=i.arg;I(o)}return c}}throw new Error("illegal catch attempt")},delegateYield:function(t,o,i){return this.delegate={iterator:A(t),resultName:o,nextLoc:i},"next"===this.method&&(this.arg=n),x}},t})("object"==typeof m?m.exports:{});try{regeneratorRuntime=t}catch(n){"object"==typeof globalThis?globalThis.regeneratorRuntime=t:Function("r","regeneratorRuntime = r")(t)}},405,[]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.onnxruntimeBackend=void 0;var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),u=r(d[0])(r(d[3])),s=r(d[0])(r(d[4])),o=r(d[0])(r(d[5])),l=function(t){switch(t){case'float32':return Float32Array;case'int8':return Int8Array;case'int16':return Int16Array;case'int32':return Int32Array;case'bool':return Int8Array;case'float64':return Float64Array;case'int64':return BigInt64Array;default:throw new Error("unsupported type: "+t)}},c=(0,o.default)("inferenceSession"),f=(0,o.default)("key"),p=(function(){function o(t){(0,n.default)(this,o),Object.defineProperty(this,c,{writable:!0,value:void 0}),Object.defineProperty(this,f,{writable:!0,value:void 0}),(0,s.default)(this,c)[c]=r(d[6]).binding,(0,s.default)(this,f)[f]=t,this.inputNames=[],this.outputNames=[]}return(0,u.default)(o,[{key:"loadModel",value:function(n){var u;return t.default.async(function(o){for(;;)switch(o.prev=o.next){case 0:return o.prev=0,o.next=3,t.default.awrap((0,s.default)(this,c)[c].loadModel((0,s.default)(this,f)[f],n));case 3:if((u=o.sent).key===(0,s.default)(this,f)[f]){o.next=6;break}throw new Error('Session key is invalid');case 6:this.inputNames=u.inputNames,this.outputNames=u.outputNames,o.next=13;break;case 10:throw o.prev=10,o.t0=o.catch(0),new Error("Can't load a model: "+o.t0.message);case 13:case"end":return o.stop()}},null,this,[[0,10]],Promise)}},{key:"dispose",value:function(){return t.default.async(function(t){for(;;)switch(t.prev=t.next){case 0:return t.abrupt("return",Promise.resolve());case 1:case"end":return t.stop()}},null,null,null,Promise)}},{key:"startProfiling",value:function(){}},{key:"endProfiling",value:function(){}},{key:"run",value:function(n,u,o){var l,p,y,v,h;return t.default.async(function(w){for(;;)switch(w.prev=w.next){case 0:l=[],w.t0=t.default.keys(u);case 2:if((w.t1=w.t0()).done){w.next=10;break}if(p=w.t1.value,!Object.prototype.hasOwnProperty.call(u,p)){w.next=8;break}if(!u[p]){w.next=7;break}throw new Error('Preallocated output is not supported and only names as string array is allowed as parameter');case 7:l.push(p);case 8:w.next=2;break;case 10:return y=this.encodeFeedsType(n),w.next=13,t.default.awrap((0,s.default)(this,c)[c].run((0,s.default)(this,f)[f],y,l,o));case 13:return v=w.sent,h=this.decodeReturnType(v),w.abrupt("return",h);case 16:case"end":return w.stop()}},null,this,null,Promise)}},{key:"encodeFeedsType",value:function(t){var n={};for(var u in t)if(Object.hasOwnProperty.call(t,u)){var s=void 0;if(Array.isArray(t[u].data))s=t[u].data;else{var o=t[u].data.buffer;s=r(d[7]).Buffer.from(o,0,o.byteLength).toString('base64')}n[u]={dims:t[u].dims,type:t[u].type,data:s}}return n}},{key:"decodeReturnType",value:function(t){var n={};for(var u in t)if(Object.hasOwnProperty.call(t,u)){var s=void 0;if(Array.isArray(t[u].data))s=t[u].data;else{var o=r(d[7]).Buffer.from(t[u].data,'base64'),c=l(t[u].type);s=new c(o.buffer,o.byteOffset,o.length/c.BYTES_PER_ELEMENT)}n[u]=new(r(d[8]).Tensor)(t[u].type,s,t[u].dims)}return n}}]),o})(),y=new((function(){function s(){(0,n.default)(this,s)}return(0,u.default)(s,[{key:"init",value:function(){return t.default.async(function(t){for(;;)switch(t.prev=t.next){case 0:return t.abrupt("return",Promise.resolve());case 1:case"end":return t.stop()}},null,null,null,Promise)}},{key:"createSessionHandler",value:function(n,u){var s;return t.default.async(function(o){for(;;)switch(o.prev=o.next){case 0:if('string'==typeof n){o.next=2;break}throw new Error('Uint8Array is not supported');case 2:return s=new p(n),o.next=5,t.default.awrap(s.loadModel(u||{}));case 5:return o.abrupt("return",s);case 6:case"end":return o.stop()}},null,null,null,Promise)}}]),s})());e.onnxruntimeBackend=y},406,[407,404,402,403,408,409,410,801,401]); -__d(function(g,r,i,a,m,e,d){m.exports=function(t){return t&&t.__esModule?t:{default:t}},m.exports.__esModule=!0,m.exports.default=m.exports},407,[]); -__d(function(g,r,i,a,m,e,d){m.exports=function(t,o){if(!Object.prototype.hasOwnProperty.call(t,o))throw new TypeError("attempted to use private field on non-instance");return t},m.exports.__esModule=!0,m.exports.default=m.exports},408,[]); -__d(function(g,r,i,a,m,e,d){var t=0;m.exports=function(_){return"__private_"+t+++"_"+_},m.exports.__esModule=!0,m.exports.default=m.exports},409,[]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.binding=void 0;var n=r(d[0]).NativeModules.Onnxruntime;e.binding=n},410,[411]); -__d(function(g,r,i,a,m,e,d){'use strict';m.exports={get AccessibilityInfo(){return r(d[0]).default},get ActivityIndicator(){return r(d[1])},get Button(){return r(d[2])},get DatePickerIOS(){return r(d[3])('DatePickerIOS-merged',"DatePickerIOS has been merged with DatePickerAndroid and will be removed in a future release. It can now be installed and imported from '@react-native-community/datetimepicker' instead of 'react-native'. See https://github.com/react-native-datetimepicker/datetimepicker"),r(d[4])},get DrawerLayoutAndroid(){return r(d[5])},get FlatList(){return r(d[6])},get Image(){return r(d[7])},get ImageBackground(){return r(d[8])},get InputAccessoryView(){return r(d[9])},get KeyboardAvoidingView(){return r(d[10]).default},get MaskedViewIOS(){return r(d[3])('maskedviewios-moved',"MaskedViewIOS has been extracted from react-native core and will be removed in a future release. It can now be installed and imported from '@react-native-masked-view/masked-view' instead of 'react-native'. See https://github.com/react-native-masked-view/masked-view"),r(d[11])},get Modal(){return r(d[12])},get Pressable(){return r(d[13]).default},get ProgressBarAndroid(){return r(d[3])('progress-bar-android-moved',"ProgressBarAndroid has been extracted from react-native core and will be removed in a future release. It can now be installed and imported from '@react-native-community/progress-bar-android' instead of 'react-native'. See https://github.com/react-native-progress-view/progress-bar-android"),r(d[14])},get ProgressViewIOS(){return r(d[3])('progress-view-ios-moved',"ProgressViewIOS has been extracted from react-native core and will be removed in a future release. It can now be installed and imported from '@react-native-community/progress-view' instead of 'react-native'. See https://github.com/react-native-progress-view/progress-view"),r(d[15])},get RefreshControl(){return r(d[16])},get SafeAreaView(){return r(d[17]).default},get ScrollView(){return r(d[18])},get SectionList(){return r(d[19]).default},get SegmentedControlIOS(){return r(d[3])('segmented-control-ios-moved',"SegmentedControlIOS has been extracted from react-native core and will be removed in a future release. It can now be installed and imported from '@react-native-segmented-control/segmented-control' instead of 'react-native'. See https://github.com/react-native-segmented-control/segmented-control"),r(d[20])},get Slider(){return r(d[3])('slider-moved',"Slider has been extracted from react-native core and will be removed in a future release. It can now be installed and imported from '@react-native-community/slider' instead of 'react-native'. See https://github.com/callstack/react-native-slider"),r(d[21])},get StatusBar(){return r(d[22])},get Switch(){return r(d[23]).default},get Text(){return r(d[24])},get TextInput(){return r(d[25])},get Touchable(){return r(d[26])},get TouchableHighlight(){return r(d[27])},get TouchableNativeFeedback(){return r(d[28])},get TouchableOpacity(){return r(d[29])},get TouchableWithoutFeedback(){return r(d[30])},get View(){return r(d[31])},get VirtualizedList(){return r(d[32])},get VirtualizedSectionList(){return r(d[33])},get ActionSheetIOS(){return r(d[34])},get Alert(){return r(d[35])},get Animated(){return r(d[36])},get Appearance(){return r(d[37])},get AppRegistry(){return r(d[38])},get AppState(){return r(d[39])},get AsyncStorage(){return r(d[3])('async-storage-moved',"AsyncStorage has been extracted from react-native core and will be removed in a future release. It can now be installed and imported from '@react-native-async-storage/async-storage' instead of 'react-native'. See https://github.com/react-native-async-storage/async-storage"),r(d[40])},get BackHandler(){return r(d[41])},get Clipboard(){return r(d[3])('clipboard-moved',"Clipboard has been extracted from react-native core and will be removed in a future release. It can now be installed and imported from '@react-native-clipboard/clipboard' instead of 'react-native'. See https://github.com/react-native-clipboard/clipboard"),r(d[42])},get DatePickerAndroid(){return r(d[3])('DatePickerAndroid-merged',"DatePickerAndroid has been merged with DatePickerIOS and will be removed in a future release. It can now be installed and imported from '@react-native-community/datetimepicker' instead of 'react-native'. See https://github.com/react-native-datetimepicker/datetimepicker"),r(d[43])},get DeviceInfo(){return r(d[44])},get DevSettings(){return r(d[45])},get Dimensions(){return r(d[46])},get Easing(){return r(d[47])},get findNodeHandle(){return r(d[48]).findNodeHandle},get I18nManager(){return r(d[49])},get ImagePickerIOS(){return r(d[3])('imagePickerIOS-moved',"ImagePickerIOS has been extracted from react-native core and will be removed in a future release. Please upgrade to use either '@react-native-community/react-native-image-picker' or 'expo-image-picker'. If you cannot upgrade to a different library, please install the deprecated '@react-native-community/image-picker-ios' package. See https://github.com/rnc-archive/react-native-image-picker-ios"),r(d[50])},get InteractionManager(){return r(d[51])},get Keyboard(){return r(d[52])},get LayoutAnimation(){return r(d[53])},get Linking(){return r(d[54])},get LogBox(){return r(d[55])},get NativeDialogManagerAndroid(){return r(d[56]).default},get NativeEventEmitter(){return r(d[57]).default},get Networking(){return r(d[58])},get PanResponder(){return r(d[59])},get PermissionsAndroid(){return r(d[60])},get PixelRatio(){return r(d[61])},get PushNotificationIOS(){return r(d[3])('pushNotificationIOS-moved',"PushNotificationIOS has been extracted from react-native core and will be removed in a future release. It can now be installed and imported from '@react-native-community/push-notification-ios' instead of 'react-native'. See https://github.com/react-native-push-notification-ios/push-notification-ios"),r(d[62])},get Settings(){return r(d[63])},get Share(){return r(d[64])},get StyleSheet(){return r(d[65])},get Systrace(){return r(d[66])},get ToastAndroid(){return r(d[67])},get TurboModuleRegistry(){return r(d[68])},get UIManager(){return r(d[69])},get unstable_batchedUpdates(){return r(d[48]).unstable_batchedUpdates},get useColorScheme(){return r(d[70]).default},get useWindowDimensions(){return r(d[71]).default},get UTFSequence(){return r(d[72])},get Vibration(){return r(d[73])},get YellowBox(){return r(d[74])},get DeviceEventEmitter(){return r(d[75]).default},get DynamicColorIOS(){return r(d[76]).DynamicColorIOS},get NativeAppEventEmitter(){return r(d[77])},get NativeModules(){return r(d[78])},get Platform(){return r(d[79])},get PlatformColor(){return r(d[80]).PlatformColor},get processColor(){return r(d[81])},get requireNativeComponent(){return r(d[82])},get RootTagContext(){return r(d[83]).RootTagContext},get unstable_enableLogBox(){return function(){return console.warn('LogBox is enabled by default so there is no need to call unstable_enableLogBox() anymore. This is a no op and will be removed in the next version.')}},get ColorPropType(){return r(d[84])},get EdgeInsetsPropType(){return r(d[85])},get PointPropType(){return r(d[86])},get ViewPropTypes(){return r(d[87])}}},411,[412,577,588,696,697,698,651,680,704,705,707,708,710,717,582,719,671,720,655,692,722,723,699,725,589,729,734,738,614,615,739,579,654,693,740,518,616,742,744,761,764,750,767,769,771,772,566,640,456,715,774,625,657,658,776,779,520,500,499,780,782,565,784,786,787,578,439,789,428,450,791,794,795,796,798,413,799,528,429,426,549,546,585,714,600,603,800,682]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=r(d[0])(r(d[1])),t=r(d[0])(r(d[2])),l=r(d[0])(r(d[3])),u=r(d[0])(r(d[4])),o=r(d[0])(r(d[5])),c='android'===t.default.OS?new Map([['change','touchExplorationDidChange'],['reduceMotionChanged','reduceMotionDidChange'],['screenReaderChanged','touchExplorationDidChange']]):new Map([['announcementFinished','announcementFinished'],['boldTextChanged','boldTextChanged'],['change','screenReaderChanged'],['grayscaleChanged','grayscaleChanged'],['invertColorsChanged','invertColorsChanged'],['reduceMotionChanged','reduceMotionChanged'],['reduceTransparencyChanged','reduceTransparencyChanged'],['screenReaderChanged','screenReaderChanged']]),s={isBoldTextEnabled:function(){return'android'===t.default.OS?Promise.resolve(!1):new Promise(function(n,t){null!=u.default?u.default.getCurrentBoldTextState(n,t):t(null)})},isGrayscaleEnabled:function(){return'android'===t.default.OS?Promise.resolve(!1):new Promise(function(n,t){null!=u.default?u.default.getCurrentGrayscaleState(n,t):t(null)})},isInvertColorsEnabled:function(){return'android'===t.default.OS?Promise.resolve(!1):new Promise(function(n,t){null!=u.default?u.default.getCurrentInvertColorsState(n,t):t(null)})},isReduceMotionEnabled:function(){return new Promise(function(n,o){'android'===t.default.OS?null!=l.default?l.default.isReduceMotionEnabled(n):o(null):null!=u.default?u.default.getCurrentReduceMotionState(n,o):o(null)})},isReduceTransparencyEnabled:function(){return'android'===t.default.OS?Promise.resolve(!1):new Promise(function(n,t){null!=u.default?u.default.getCurrentReduceTransparencyState(n,t):t(null)})},isScreenReaderEnabled:function(){return new Promise(function(n,o){'android'===t.default.OS?null!=l.default?l.default.isTouchExplorationEnabled(n):o(null):null!=u.default?u.default.getCurrentVoiceOverState(n,o):o(null)})},addEventListener:function(t,l){var u=c.get(t);return null==u?{remove:function(){}}:n.default.addListener(u,l)},setAccessibilityFocus:function(n){(0,o.default)(n,'focus')},sendAccessibilityEvent_unstable:function(n,l){'ios'===t.default.OS&&'click'===l||(0,r(d[6]).sendAccessibilityEvent)(n,l)},announceForAccessibility:function(n){'android'===t.default.OS?null==l.default||l.default.announceForAccessibility(n):null==u.default||u.default.announceForAccessibility(n)},removeEventListener:function(t,l){null!=c.get(t)&&n.default.removeListener('deviceEventName',l)},getRecommendedTimeoutMillis:function(n){return'android'===t.default.OS?new Promise(function(t,u){null!=l.default&&l.default.getRecommendedTimeoutMillis?l.default.getRecommendedTimeoutMillis(n,t):t(n)}):Promise.resolve(n)}};e.default=s},412,[407,413,426,447,448,449,456]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var t=new(r(d[0])(r(d[1])).default);e.default=t},413,[407,414]); -__d(function(g,r,i,a,m,e,d){'use strict';Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0,e.default=r(d[0])},414,[415]); -__d(function(g,r,_i,a,m,e,d){var t=r(d[0])(r(d[1])),i=r(d[0])(r(d[2])),n=r(d[0])(r(d[3])),s=r(d[0])(r(d[4])),o=function(){return!0},u=(function(){function u(i){(0,t.default)(this,u),this._subscriber=new s.default,null!=i&&(console.warn('EventEmitter(...): Constructor argument is deprecated.'),this._subscriber=i)}return(0,i.default)(u,[{key:"addListener",value:function(t,i,s){return this._subscriber.addSubscription(t,new n.default(this,this._subscriber,i,s))}},{key:"removeAllListeners",value:function(t){this._subscriber.removeAllSubscriptions(t)}},{key:"removeSubscription",value:function(t){console.warn("EventEmitter.removeSubscription(...): Method has been deprecated. Please instead use `remove()` on the subscription itself."),this.__removeSubscription(t)}},{key:"__removeSubscription",value:function(t){r(d[5])(t.emitter===this,'Subscription does not belong to this emitter.'),this._subscriber.removeSubscription(t)}},{key:"listenerCount",value:function(t){var i=this._subscriber.getSubscriptionsForType(t);return i?i.filter(o).length:0}},{key:"emit",value:function(t){var i=this._subscriber.getSubscriptionsForType(t);if(i){for(var n=arguments.length,s=new Array(n>1?n-1:0),o=1;o0?l[l.length-1]:null,c=l.length>1?l[l.length-2]:null,v='function'==typeof s,h='function'==typeof c;h&&r(d[1])(v,'Cannot have a non-function arg after a function arg.');var y=v?s:null,C=h?c:null,M=v+h,b=l.slice(0,l.length-M);if('sync'===o)return r(d[3]).callNativeSyncHook(n,t,b,C,y);r(d[3]).enqueueNativeCall(n,t,b,C,y)}).type=o,u}function u(n,t){return-1!==n.indexOf(t)}function l(n,t){return r(d[2])(t,n||{})}g.__fbGenNativeModule=n;var f={};if(g.nativeModuleProxy)f=g.nativeModuleProxy;else if(!g.nativeExtensions){var s=g.__fbBatchedBridgeConfig;r(d[1])(s,'__fbBatchedBridgeConfig is not set, cannot invoke native modules');var c=r(d[4]);(s.remoteModuleConfig||[]).forEach(function(o,u){var l=n(o,u);l&&(l.module?f[l.name]=l.module:c(f,l.name,{get:function(){return t(l.name,u)}}))})}m.exports=f},429,[430,425,436,437,446]); -__d(function(g,r,_i,a,m,e,d){m.exports=function(t,o){return r(d[0])(t)||r(d[1])(t,o)||r(d[2])(t,o)||r(d[3])()},m.exports.__esModule=!0,m.exports.default=m.exports},430,[431,432,433,435]); -__d(function(g,r,i,a,m,e,d){m.exports=function(t){if(Array.isArray(t))return t},m.exports.__esModule=!0,m.exports.default=m.exports},431,[]); -__d(function(g,r,_i2,a,m,e,d){m.exports=function(t,l){var n=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=n){var o,u,f=[],i=!0,y=!1;try{for(n=n.call(t);!(i=(o=n.next()).done)&&(f.push(o.value),!l||f.length!==l);i=!0);}catch(t){y=!0,u=t}finally{try{i||null==n.return||n.return()}finally{if(y)throw u}}return f}},m.exports.__esModule=!0,m.exports.default=m.exports},432,[]); -__d(function(g,r,i,a,m,e,d){m.exports=function(t,o){if(t){if("string"==typeof t)return r(d[0])(t,o);var n=Object.prototype.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?r(d[0])(t,o):void 0}},m.exports.__esModule=!0,m.exports.default=m.exports},433,[434]); -__d(function(g,r,_i,a,m,e,d){m.exports=function(t,n){(null==n||n>t.length)&&(n=t.length);for(var o=0,l=new Array(n);o=5){var h=this._queue;this._queue=[[],[],[],this._callID],this._lastFlush=o,g.nativeFlushQueueImmediate(h)}r(d[2]).counterEvent('pending_js_to_native_queue',this._queue[0].length),this.__spy&&this.__spy({type:1,module:t+'',method:l,args:s})}},{key:"createDebugLookup",value:function(t,l,s){}},{key:"setReactNativeMicrotasksCallback",value:function(t){this._reactNativeMicrotasksCallback=t}},{key:"__guard",value:function(t){if(this.__shouldPauseOnThrow())t();else try{t()}catch(t){r(d[3]).reportFatalError(t)}}},{key:"__shouldPauseOnThrow",value:function(){return'undefined'!=typeof DebuggerInternal&&!0===DebuggerInternal.shouldPauseOnThrow}},{key:"__callReactNativeMicrotasks",value:function(){r(d[2]).beginEvent('JSTimers.callReactNativeMicrotasks()'),null!=this._reactNativeMicrotasksCallback&&this._reactNativeMicrotasksCallback(),r(d[2]).endEvent()}},{key:"__callFunction",value:function(t,l,s){this._lastFlush=Date.now(),this._eventLoopStartTime=this._lastFlush,this.__spy?r(d[2]).beginEvent(t+"."+l+"("+r(d[4]).default(s)+")"):r(d[2]).beginEvent(t+"."+l+"(...)"),this.__spy&&this.__spy({type:0,module:t,method:l,args:s});var u=this.getCallableModule(t);r(d[5])(!!u,"Module "+t+" is not a registered callable module (calling "+l+"). A frequent cause of the error is that the application entry file path is incorrect.\n This can also happen when the JS bundle is corrupt or there is an early initialization error when loading React Native."),r(d[5])(!!u[l],"Method "+l+" does not exist on module "+t),u[l].apply(u,s),r(d[2]).endEvent()}},{key:"__invokeCallback",value:function(t,l){this._lastFlush=Date.now(),this._eventLoopStartTime=this._lastFlush;var s=t>>>1,u=1&t?this._successCallbacks.get(s):this._failureCallbacks.get(s);u&&(this._successCallbacks.delete(s),this._failureCallbacks.delete(s),u.apply(void 0,r(d[6])(l)))}}],[{key:"spy",value:function(l){t.prototype.__spy=!0===l?function(t){console.log((0===t.type?'N->JS':'JS->N')+" : "+(null!=t.module?t.module+'.':'')+t.method+"("+JSON.stringify(t.args)+")")}:!1===l?null:l}}]),t})();m.exports=t},438,[402,403,439,440,441,425,442]); -__d(function(g,r,i,a,m,e,d){'use strict';var n=!1,t=0,c={installReactHook:function(){!0},setEnabled:function(t){n!==t&&(n=t)},isEnabled:function(){return n},beginEvent:function(t,c){if(n){var o='function'==typeof t?t():t;g.nativeTraceBeginSection(131072,o,c)}},endEvent:function(){n&&g.nativeTraceEndSection(131072)},beginAsyncEvent:function(c){var o=t;if(n){t++;var f='function'==typeof c?c():c;g.nativeTraceBeginAsyncSection(131072,f,o)}return o},endAsyncEvent:function(t,c){if(n){var o='function'==typeof t?t():t;g.nativeTraceEndAsyncSection(131072,o,c)}},counterEvent:function(t,c){if(n){var o='function'==typeof t?t():t;g.nativeTraceCounter&&g.nativeTraceCounter(131072,o,c)}}};m.exports=c},439,[]); -__d(function(g,r,i,a,m,e,d){m.exports=g.ErrorUtils},440,[]); -__d(function(g,r,_i,a,m,_e,d){Object.defineProperty(_e,"__esModule",{value:!0}),_e.createStringifySafeWithLimits=o,_e.default=void 0;var t=r(d[0])(r(d[1]));function e(t,e){var i="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(i)return(i=i.call(t)).next.bind(i);if(Array.isArray(t)||(i=n(t))||e&&t&&"number"==typeof t.length){i&&(t=i);var o=0;return function(){return o>=t.length?{done:!0}:{done:!1,value:t[o++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function n(t,e){if(t){if("string"==typeof t)return i(t,e);var n=Object.prototype.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?i(t,e):void 0}}function i(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,i=new Array(e);nf+"...(truncated)...".length?i.substring(0,f)+"...(truncated)...":i}if('object'!=typeof i||null===i)return i;var u=i;if(Array.isArray(i))h.length>=o?u="[ ... array with "+i.length+" values ... ]":i.length>c&&(u=i.slice(0,c).concat(["... extra "+(i.length-c)+" values truncated ..."]));else{(0,t.default)('object'==typeof i,'This was already found earlier');var l=Object.keys(i);if(h.length>=o)u="{ ... object with "+l.length+" keys ... }";else if(l.length>s){u={};for(var y,v=e(l.slice(0,s));!(y=v()).done;){var b=y.value;u[b]=i[b]}u['...(truncated keys)...']=l.length-s}}return h.unshift(u),u}return function(t){if(void 0===t)return'undefined';if(null===t)return'null';if('function'==typeof t)try{return t.toString()}catch(t){return'[function unknown]'}else{if(t instanceof Error)return t.name+': '+t.message;try{var e=JSON.stringify(t,v);return void 0===e?'["'+typeof t+'" failed to stringify]':e}catch(e){if('function'==typeof t.toString)try{return t.toString()}catch(t){}}}return'["'+typeof t+'" failed to stringify]'}}var u=o({maxDepth:10,maxStringLimit:100,maxArrayLimit:50,maxObjectKeysLimit:50});_e.default=u},441,[407,425]); -__d(function(g,r,i,a,m,e,d){m.exports=function(t){return r(d[0])(t)||r(d[1])(t)||r(d[2])(t)||r(d[3])()},m.exports.__esModule=!0,m.exports.default=m.exports},442,[443,444,433,445]); -__d(function(g,r,i,a,m,e,d){m.exports=function(t){if(Array.isArray(t))return r(d[0])(t)},m.exports.__esModule=!0,m.exports.default=m.exports},443,[434]); -__d(function(g,r,i,a,m,e,d){m.exports=function(o){if("undefined"!=typeof Symbol&&null!=o[Symbol.iterator]||null!=o["@@iterator"])return Array.from(o)},m.exports.__esModule=!0,m.exports.default=m.exports},444,[]); -__d(function(g,r,i,a,m,e,d){m.exports=function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")},m.exports.__esModule=!0,m.exports.default=m.exports},445,[]); -__d(function(g,r,i,a,m,e,d){'use strict';m.exports=function(t,n,u){var b,c=u.get,o=!1!==u.enumerable,f=!1!==u.writable,l=!1;function s(u){b=u,l=!0,Object.defineProperty(t,n,{value:u,configurable:!0,enumerable:o,writable:f})}Object.defineProperty(t,n,{get:function(){return l||(l=!0,s(c())),b},set:s,configurable:!0,enumerable:o})}},446,[]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,f=new WeakMap;return(t=function(t){return t?f:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var f=t(o);if(f&&f.has(n))return f.get(n);var u={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in n)if("default"!==l&&Object.prototype.hasOwnProperty.call(n,l)){var p=c?Object.getOwnPropertyDescriptor(n,l):null;p&&(p.get||p.set)?Object.defineProperty(u,l,p):u[l]=n[l]}u.default=n,f&&f.set(n,u);return u})(r(d[0])).get('AccessibilityInfo');e.default=n},447,[428]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in n)if("default"!==l&&Object.prototype.hasOwnProperty.call(n,l)){var p=c?Object.getOwnPropertyDescriptor(n,l):null;p&&(p.get||p.set)?Object.defineProperty(f,l,p):f[l]=n[l]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).get('AccessibilityManager');e.default=n},448,[428]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1]));m.exports=function(s,c){'focus'===c&&t.default.sendAccessibilityEvent(s,t.default.getConstants().AccessibilityEventTypes.typeViewFocused),'click'===c&&t.default.sendAccessibilityEvent(s,t.default.getConstants().AccessibilityEventTypes.typeViewClicked)}},449,[407,450]); -__d(function(g,r,i,a,m,e,d){var l=r(d[0])(r(d[1])),n=!0===g.RN$Bridgeless?r(d[2]):null==l.default.unstable_UIManager?r(d[3]):l.default.unstable_UIManager;m.exports=n},450,[407,451,452,453]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;e.default={unstable_UIManager:null}},451,[]); -__d(function(g,r,i,a,m,e,d){'use strict';m.exports={getViewManagerConfig:function(n){return console.warn('Attempting to get config for view manager: '+n),'RCTVirtualText'===n?{}:null},hasViewManagerConfig:function(n){return'RCTVirtualText'===n||'RCTShimmeringView'===n},getConstants:function(){return{}},getConstantsForViewManager:function(n){},getDefaultEventTypes:function(){return[]},lazilyLoadView:function(n){},createView:function(n,t,o,u){},updateView:function(n,t,o){},focus:function(n){},blur:function(n){},findSubviewIn:function(n,t,o){},dispatchViewManagerCommand:function(n,t,o){},measure:function(n,t){},measureInWindow:function(n,t){},viewIsDescendantOf:function(n,t,o){},measureLayout:function(n,t,o,u){},measureLayoutRelativeToParent:function(n,t,o){},setJSResponder:function(n,t){},clearJSResponder:function(){},configureNextLayoutAnimation:function(n,t,o){},removeSubviewsFromContainerWithID:function(n){},replaceExistingNonRootView:function(n,t){},setChildren:function(n,t){},manageChildren:function(n,t,o,u,c,f){},setLayoutAnimationEnabledExperimental:function(n){},sendAccessibilityEvent:function(n,t){},showPopupMenu:function(n,t,o,u){},dismissPopupMenu:function(){}}},452,[]); -__d(function(g,r,i,a,m,_e,d){var n=r(d[0])(r(d[1])),e=r(d[0])(r(d[2])),t={},o=new Set,f={},u=!1;function c(){return u||(f=e.default.getConstants(),u=!0),f}function l(n){if(void 0===t[n]&&g.nativeCallSyncHook&&e.default.getConstantsForViewManager)try{t[n]=e.default.getConstantsForViewManager(n)}catch(e){console.error("NativeUIManager.getConstantsForViewManager('"+n+"') threw an exception.",e),t[n]=null}var f=t[n];if(f)return f;if(!g.nativeCallSyncHook)return f;if(e.default.lazilyLoadView&&!o.has(n)){var u=e.default.lazilyLoadView(n);o.add(n),null!=u&&null!=u.viewConfig&&(c()[n]=u.viewConfig,w(n))}return t[n]}var s=(0,n.default)({},e.default,{createView:function(n,t,o,f){e.default.createView(n,t,o,f)},getConstants:function(){return c()},getViewManagerConfig:function(n){return l(n)},hasViewManagerConfig:function(n){return null!=l(n)}});function w(n){var e=c()[n];t[n]=e,e.Manager&&(r(d[3])(e,'Constants',{get:function(){var n=r(d[4])[e.Manager],t={};return n&&Object.keys(n).forEach(function(e){var o=n[e];'function'!=typeof o&&(t[e]=o)}),t}}),r(d[3])(e,'Commands',{get:function(){var n=r(d[4])[e.Manager],t={},o=0;return n&&Object.keys(n).forEach(function(e){'function'==typeof n[e]&&(t[e]=o++)}),t}}))}e.default.getViewManagerConfig=s.getViewManagerConfig,c().ViewManagerNames&&e.default.getConstants().ViewManagerNames.forEach(function(n){r(d[3])(e.default,n,{get:function(){return e.default.getConstantsForViewManager(n)}})}),g.nativeCallSyncHook||Object.keys(c()).forEach(function(n){r(d[5]).includes(n)||(t[n]||(t[n]=c()[n]),r(d[3])(e.default,n,{get:function(){return console.warn("Accessing view manager configs directly off UIManager via UIManager['"+n+"'] is no longer supported. Use UIManager.getViewManagerConfig('"+n+"') instead."),s.getViewManagerConfig(n)}}))}),m.exports=s},453,[407,436,454,446,429,455]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,f=new WeakMap;return(t=function(t){return t?f:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var f=t(o);if(f&&f.has(n))return f.get(n);var u={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in n)if("default"!==l&&Object.prototype.hasOwnProperty.call(n,l)){var p=c?Object.getOwnPropertyDescriptor(n,l):null;p&&(p.get||p.set)?Object.defineProperty(u,l,p):u[l]=n[l]}u.default=n,f&&f.set(n,u);return u})(r(d[0])).getEnforcing('UIManager');e.default=n},454,[428]); -__d(function(g,r,i,a,m,e,d){'use strict';m.exports=['clearJSResponder','configureNextLayoutAnimation','createView','dismissPopupMenu','dispatchViewManagerCommand','findSubviewIn','getConstantsForViewManager','getDefaultEventTypes','manageChildren','measure','measureInWindow','measureLayout','measureLayoutRelativeToParent','removeRootView','removeSubviewsFromContainerWithID','replaceExistingNonRootView','sendAccessibilityEvent','setChildren','setJSResponder','setLayoutAnimationEnabledExperimental','showPopupMenu','updateView','viewIsDescendantOf','PopupMenu','LazyViewManagersEnabled','ViewManagerNames','StyleConstants','AccessibilityEventTypes','UIView','getViewManagerConfig','hasViewManagerConfig','blur','focus','genericBubblingEventTypes','genericDirectEventTypes','lazilyLoadView']},455,[]); -__d(function(g,r,i,a,m,e,d){'use strict';var t;t=r(d[0]),m.exports=t},456,[457]); -__d(function(e,n,t,r,l,a,i){"use strict";n(i[0]);var u=n(i[1]);function o(e,n,t,r,l,a,i,u,o){var s=Array.prototype.slice.call(arguments,3);try{n.apply(t,s)}catch(e){this.onError(e)}}var s=!1,c=null,d=!1,f=null,p={onError:function(e){s=!0,c=e}};function h(e,n,t,r,l,a,i,u,d){s=!1,c=null,o.apply(p,arguments)}function g(e,n,t,r,l,a,i,u,o){if(h.apply(this,arguments),s){if(!s)throw Error("clearCaughtError was called but no error was captured. This error is likely caused by a bug in React. Please file an issue.");var p=c;s=!1,c=null,d||(d=!0,f=p)}}var m=Array.isArray,v=null,b=null,y=null;function S(e,n,t){var r=e.type||"unknown-event";e.currentTarget=y(t),g(r,n,void 0,e),e.currentTarget=null}function k(e){var n=e._dispatchListeners,t=e._dispatchInstances;if(m(n))throw Error("executeDirectDispatch(...): Invalid `event`.");return e.currentTarget=n?y(t):null,n=n?n(e):null,e.currentTarget=null,e._dispatchListeners=null,e._dispatchInstances=null,n}function w(){return!0}function _(){return!1}function T(e,n,t,r){for(var l in this.dispatchConfig=e,this._targetInst=n,this.nativeEvent=t,this._dispatchInstances=this._dispatchListeners=null,e=this.constructor.Interface)e.hasOwnProperty(l)&&((n=e[l])?this[l]=n(t):"target"===l?this.target=r:this[l]=t[l]);return this.isDefaultPrevented=(null!=t.defaultPrevented?t.defaultPrevented:!1===t.returnValue)?w:_,this.isPropagationStopped=_,this}function x(e,n,t,r){if(this.eventPool.length){var l=this.eventPool.pop();return this.call(l,e,n,t,r),l}return new this(e,n,t,r)}function P(e){if(!(e instanceof this))throw Error("Trying to release an event instance into a pool of a different type.");e.destructor(),10>this.eventPool.length&&this.eventPool.push(e)}function R(e){e.getPooled=x,e.eventPool=[],e.release=P}n(i[2])(T.prototype,{preventDefault:function(){this.defaultPrevented=!0;var e=this.nativeEvent;e&&(e.preventDefault?e.preventDefault():"unknown"!=typeof e.returnValue&&(e.returnValue=!1),this.isDefaultPrevented=w)},stopPropagation:function(){var e=this.nativeEvent;e&&(e.stopPropagation?e.stopPropagation():"unknown"!=typeof e.cancelBubble&&(e.cancelBubble=!0),this.isPropagationStopped=w)},persist:function(){this.isPersistent=w},isPersistent:_,destructor:function(){var e,n=this.constructor.Interface;for(e in n)this[e]=null;this.nativeEvent=this._targetInst=this.dispatchConfig=null,this.isPropagationStopped=this.isDefaultPrevented=_,this._dispatchInstances=this._dispatchListeners=null}}),T.Interface={type:null,target:null,currentTarget:function(){return null},eventPhase:null,bubbles:null,cancelable:null,timeStamp:function(e){return e.timeStamp||Date.now()},defaultPrevented:null,isTrusted:null},T.extend=function(e){function t(){}function r(){return l.apply(this,arguments)}var l=this;t.prototype=l.prototype;var a=new t;return n(i[2])(a,r.prototype),r.prototype=a,r.prototype.constructor=r,r.Interface=n(i[2])({},l.Interface,e),r.extend=l.extend,R(r),r},R(T);var E=T.extend({touchHistory:function(){return null}});function C(e){return"topTouchStart"===e}function N(e){return"topTouchMove"===e}var z=["topTouchStart"],I=["topTouchMove"],L=["topTouchCancel","topTouchEnd"],U=[],M={touchBank:U,numberActiveTouches:0,indexOfSingleActiveTouch:-1,mostRecentTimeStamp:0};function F(e){return e.timeStamp||e.timestamp}function D(e){if(null==(e=e.identifier))throw Error("Touch object is missing identifier.");return e}function A(e){var n=D(e),t=U[n];t?(t.touchActive=!0,t.startPageX=e.pageX,t.startPageY=e.pageY,t.startTimeStamp=F(e),t.currentPageX=e.pageX,t.currentPageY=e.pageY,t.currentTimeStamp=F(e),t.previousPageX=e.pageX,t.previousPageY=e.pageY,t.previousTimeStamp=F(e)):(t={touchActive:!0,startPageX:e.pageX,startPageY:e.pageY,startTimeStamp:F(e),currentPageX:e.pageX,currentPageY:e.pageY,currentTimeStamp:F(e),previousPageX:e.pageX,previousPageY:e.pageY,previousTimeStamp:F(e)},U[n]=t),M.mostRecentTimeStamp=F(e)}function Q(e){var n=U[D(e)];n&&(n.touchActive=!0,n.previousPageX=n.currentPageX,n.previousPageY=n.currentPageY,n.previousTimeStamp=n.currentTimeStamp,n.currentPageX=e.pageX,n.currentPageY=e.pageY,n.currentTimeStamp=F(e),M.mostRecentTimeStamp=F(e))}function H(e){var n=U[D(e)];n&&(n.touchActive=!1,n.previousPageX=n.currentPageX,n.previousPageY=n.currentPageY,n.previousTimeStamp=n.currentTimeStamp,n.currentPageX=e.pageX,n.currentPageY=e.pageY,n.currentTimeStamp=F(e),M.mostRecentTimeStamp=F(e))}var O,j={instrument:function(e){O=e},recordTouchTrack:function(e,n){if(null!=O&&O(e,n),N(e))n.changedTouches.forEach(Q);else if(C(e))n.changedTouches.forEach(A),M.numberActiveTouches=n.touches.length,1===M.numberActiveTouches&&(M.indexOfSingleActiveTouch=n.touches[0].identifier);else if(("topTouchEnd"===e||"topTouchCancel"===e)&&(n.changedTouches.forEach(H),M.numberActiveTouches=n.touches.length,1===M.numberActiveTouches))for(e=0;ei||(a=i),Ne(a,e,l)}}}),v=function(e){return we.get(e._nativeTag)||null},b=_e,y=function(e){var n=(e=e.stateNode)._nativeTag;if(void 0===n&&(n=(e=e.canonical)._nativeTag),!n)throw Error("All native instances should have a tag.");return e},re.injection.injectGlobalResponderHandler({onChange:function(e,t,r){null!==t?n(i[3]).UIManager.setJSResponder(t.stateNode._nativeTag,r):n(i[3]).UIManager.clearJSResponder()}});var ze=u.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,Ie=60103,Le=60106,Ue=60107,Me=60108,Fe=60114,De=60109,Ae=60110,Qe=60112,He=60113,Oe=60120,je=60115,Be=60116,Ve=60129,We=60130,Ye=60131,qe=60132;if("function"==typeof Symbol&&Symbol.for){var Xe=Symbol.for;Ie=Xe("react.element"),Le=Xe("react.portal"),Ue=Xe("react.fragment"),Me=Xe("react.strict_mode"),Fe=Xe("react.profiler"),De=Xe("react.provider"),Ae=Xe("react.context"),Qe=Xe("react.forward_ref"),He=Xe("react.suspense"),Oe=Xe("react.suspense_list"),je=Xe("react.memo"),Be=Xe("react.lazy"),Xe("react.scope"),Ve=Xe("react.debug_trace_mode"),We=Xe("react.offscreen"),Ye=Xe("react.legacy_hidden"),qe=Xe("react.cache")}var $e="function"==typeof Symbol&&Symbol.iterator;function Ge(e){return null===e||"object"!=typeof e?null:"function"==typeof(e=$e&&e[$e]||e["@@iterator"])?e:null}function Ke(e){if(null==e)return null;if("function"==typeof e)return e.displayName||e.name||null;if("string"==typeof e)return e;switch(e){case Ue:return"Fragment";case Le:return"Portal";case Fe:return"Profiler";case Me:return"StrictMode";case He:return"Suspense";case Oe:return"SuspenseList";case qe:return"Cache"}if("object"==typeof e)switch(e.$$typeof){case Ae:return(e.displayName||"Context")+".Consumer";case De:return(e._context.displayName||"Context")+".Provider";case Qe:var n=e.render;return(e=e.displayName)||(e=""!==(e=n.displayName||n.name||"")?"ForwardRef("+e+")":"ForwardRef"),e;case je:return null!==(n=e.displayName||null)?n:Ke(e.type)||"Memo";case Be:n=e._payload,e=e._init;try{return Ke(e(n))}catch(e){}}return null}function Je(e){var n=e.type;switch(e.tag){case 24:return"Cache";case 9:return(n.displayName||"Context")+".Consumer";case 10:return(n._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=(e=n.render).displayName||e.name||"",n.displayName||(""!==e?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return n;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return Ke(n);case 23:return"LegacyHidden";case 8:return n===Me?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 1:case 0:case 17:case 2:case 14:case 15:if("function"==typeof n)return n.displayName||n.name||null;if("string"==typeof n)return n}return null}function Ze(e){var n=e,t=e;if(e.alternate)for(;n.return;)n=n.return;else{e=n;do{0!=(2050&(n=e).flags)&&(t=n.return),e=n.return}while(e)}return 3===n.tag?t:null}function en(e){if(Ze(e)!==e)throw Error("Unable to find node on an unmounted component.")}function nn(e){var n=e.alternate;if(!n){if(null===(n=Ze(e)))throw Error("Unable to find node on an unmounted component.");return n!==e?null:e}for(var t=e,r=n;;){var l=t.return;if(null===l)break;var a=l.alternate;if(null===a){if(null!==(r=l.return)){t=r;continue}break}if(l.child===a.child){for(a=l.child;a;){if(a===t)return en(l),e;if(a===r)return en(l),n;a=a.sibling}throw Error("Unable to find node on an unmounted component.")}if(t.return!==r.return)t=l,r=a;else{for(var i=!1,u=l.child;u;){if(u===t){i=!0,t=l,r=a;break}if(u===r){i=!0,r=l,t=a;break}u=u.sibling}if(!i){for(u=a.child;u;){if(u===t){i=!0,t=a,r=l;break}if(u===r){i=!0,r=a,t=l;break}u=u.sibling}if(!i)throw Error("Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue.")}}if(t.alternate!==r)throw Error("Return fibers should always be each others' alternates. This error is likely caused by a bug in React. Please file an issue.")}if(3!==t.tag)throw Error("Unable to find node on an unmounted component.");return t.stateNode.current===t?e:n}function tn(e){return null!==(e=nn(e))?rn(e):null}function rn(e){if(5===e.tag||6===e.tag)return e;for(e=e.child;null!==e;){var n=rn(e);if(null!==n)return n;e=e.sibling}return null}var ln={},an=null,un=0,on={unsafelyIgnoreFunctions:!0};function sn(e,t){return"object"!=typeof t||null===t||n(i[3]).deepDiffer(e,t,on)}function cn(e,n,t){if(m(n))for(var r=n.length;r--&&0=(a=n&-n)||16===l&&0!=(4194240&a)))return n;if(0!=(4&r)&&(r|=16&t),0!==(n=e.entangledLanes))for(e=e.entanglements,n&=r;0t;t++)n.push(e);return n}function Rn(e,n,t){e.pendingLanes|=n,536870912!==n&&(e.suspendedLanes=0,e.pingedLanes=0),(e=e.eventTimes)[n=31-Nn(n)]=t}function En(e,n){var t=e.pendingLanes&~n;e.pendingLanes=n,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=n,e.mutableReadLanes&=n,e.entangledLanes&=n,n=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0Xn||(e.current=qn[Xn],qn[Xn]=null,Xn--)}function Kn(e,n){qn[++Xn]=e.current,e.current=n}var Jn={},Zn=$n(Jn),et=$n(!1),nt=Jn;function tt(e,n){var t=e.type.contextTypes;if(!t)return Jn;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===n)return r.__reactInternalMemoizedMaskedChildContext;var l,a={};for(l in t)a[l]=n[l];return r&&((e=e.stateNode).__reactInternalMemoizedUnmaskedChildContext=n,e.__reactInternalMemoizedMaskedChildContext=a),a}function rt(e){return null!==(e=e.childContextTypes)&&void 0!==e}function lt(){Gn(et),Gn(Zn)}function at(e,n,t){if(Zn.current!==Jn)throw Error("Unexpected context found on stack. This error is likely caused by a bug in React. Please file an issue.");Kn(Zn,n),Kn(et,t)}function it(e,t,r){var l=e.stateNode;if(t=t.childContextTypes,"function"!=typeof l.getChildContext)return r;for(var a in l=l.getChildContext())if(!(a in t))throw Error((Je(e)||"Unknown")+'.getChildContext(): key "'+a+'" is not defined in childContextTypes.');return n(i[2])({},r,l)}function ut(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||Jn,nt=Zn.current,Kn(Zn,e),Kn(et,et.current),!0}function ot(e,n,t){var r=e.stateNode;if(!r)throw Error("Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue.");t?(e=it(e,n,nt),r.__reactInternalMemoizedMergedChildContext=e,Gn(et),Gn(Zn),Kn(Zn,e)):Gn(et),Kn(et,t)}var st=null,ct=!1,dt=!1;function ft(){if(!dt&&null!==st){dt=!0;var e=0,t=Ln;try{var r=st;for(Ln=1;eg?(m=h,h=null):m=h.sibling;var v=f(l,h,u[g],o);if(null===v){null===h&&(h=m);break}e&&h&&null===v.alternate&&n(l,h),i=a(v,i,g),null===c?s=v:c.sibling=v,c=v,h=m}if(g===u.length)return t(l,h),s;if(null===h){for(;gg?(m=h,h=null):m=h.sibling;var b=f(l,h,v.value,o);if(null===b){null===h&&(h=m);break}e&&h&&null===b.alternate&&n(l,h),i=a(b,i,g),null===c?s=b:c.sibling=b,c=b,h=m}if(v.done)return t(l,h),s;if(null===h){for(;!v.done;g++,v=u.next())null!==(v=d(l,v.value,o))&&(i=a(v,i,g),null===c?s=v:c.sibling=v,c=v);return s}for(h=r(l,h);!v.done;g++,v=u.next())null!==(v=p(h,l,g,v.value,o))&&(e&&null!==v.alternate&&h.delete(null===v.key?g:v.key),i=a(v,i,g),null===c?s=v:c.sibling=v,c=v);return e&&h.forEach(function(e){return n(l,e)}),s}return function(e,r,a,u){var o="object"==typeof a&&null!==a&&a.type===Ue&&null===a.key;if(o&&(a=a.props.children),"object"==typeof a&&null!==a){switch(a.$$typeof){case Ie:e:{var s=a.key;for(o=r;null!==o;){if(o.key===s){if((s=a.type)===Ue){if(7===o.tag){t(e,o.sibling),(r=l(o,a.props.children)).return=e,e=r;break e}}else if(o.elementType===s){t(e,o.sibling),(r=l(o,a.props)).ref=Wt(e,o,a),r.return=e,e=r;break e}t(e,o);break}n(e,o),o=o.sibling}a.type===Ue?((r=Ka(a.props.children,e.mode,u,a.key)).return=e,e=r):((u=Ga(a.type,a.key,a.props,null,e.mode,u)).ref=Wt(e,r,a),u.return=e,e=u)}return i(e);case Le:e:{for(o=a.key;null!==r;){if(r.key===o){if(4===r.tag&&r.stateNode.containerInfo===a.containerInfo&&r.stateNode.implementation===a.implementation){t(e,r.sibling),(r=l(r,a.children||[])).return=e,e=r;break e}t(e,r);break}n(e,r),r=r.sibling}(r=ei(a,e.mode,u)).return=e,e=r}return i(e)}if(m(a))return h(e,r,a,u);if(Ge(a))return g(e,r,a,u);Yt(e,a)}if("string"==typeof a||"number"==typeof a)return a=""+a,null!==r&&6===r.tag?(t(e,r.sibling),(r=l(r,a)).return=e,e=r):(t(e,r),(r=Za(a,e.mode,u)).return=e,e=r),i(e);if(void 0===a&&!o)switch(e.tag){case 1:case 0:case 11:case 15:throw Error((Je(e)||"Component")+"(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.")}return t(e,r)}}var Xt=qt(!0),$t=qt(!1),Gt={},Kt=$n(Gt),Jt=$n(Gt),Zt=$n(Gt);function er(e){if(e===Gt)throw Error("Expected host context to exist. This error is likely caused by a bug in React. Please file an issue.");return e}function nr(e,n){Kn(Zt,n),Kn(Jt,e),Kn(Kt,Gt),Gn(Kt),Kn(Kt,{isInAParentText:!1})}function tr(){Gn(Kt),Gn(Jt),Gn(Zt)}function rr(e){er(Zt.current);var n=er(Kt.current),t=e.type;t="AndroidTextInput"===t||"RCTMultilineTextInputView"===t||"RCTSinglelineTextInputView"===t||"RCTText"===t||"RCTVirtualText"===t,n!==(t=n.isInAParentText!==t?{isInAParentText:t}:n)&&(Kn(Jt,e),Kn(Kt,t))}function lr(e){Jt.current===e&&(Gn(Kt),Gn(Jt))}var ar=$n(0);function ir(e){for(var n=e;null!==n;){if(13===n.tag){var t=n.memoizedState;if(null!==t&&(null===t.dehydrated||Mn()||Mn()))return n}else if(19===n.tag&&void 0!==n.memoizedProps.revealOrder){if(0!=(128&n.flags))return n}else if(null!==n.child){n.child.return=n,n=n.child;continue}if(n===e)break;for(;null===n.sibling;){if(null===n.return||n.return===e)return null;n=n.return}n.sibling.return=n.return,n=n.sibling}return null}var ur=[];function or(){for(var e=0;ea))throw Error("Too many re-renders. React limits the number of renders to prevent an infinite loop.");a+=1,hr=pr=null,n.updateQueue=null,sr.current=Yr,e=t(r,l)}while(mr)}if(sr.current=Br,n=null!==pr&&null!==pr.next,dr=0,hr=pr=fr=null,gr=!1,n)throw Error("Rendered fewer hooks than expected. This may be caused by an accidental early return statement.");return e}function Sr(){var e={memoizedState:null,baseState:null,baseQueue:null,queue:null,next:null};return null===hr?fr.memoizedState=hr=e:hr=hr.next=e,hr}function kr(){if(null===pr){var e=fr.alternate;e=null!==e?e.memoizedState:null}else e=pr.next;var n=null===hr?fr.memoizedState:hr.next;if(null!==n)hr=n,pr=e;else{if(null===e)throw Error("Rendered more hooks than during the previous render.");e={memoizedState:(pr=e).memoizedState,baseState:pr.baseState,baseQueue:pr.baseQueue,queue:pr.queue,next:null},null===hr?fr.memoizedState=hr=e:hr=hr.next=e}return hr}function wr(e,n){return"function"==typeof n?n(e):n}function _r(e){var n=kr(),t=n.queue;if(null===t)throw Error("Should have a queue. This is likely a bug in React. Please file an issue.");t.lastRenderedReducer=e;var r=pr,l=r.baseQueue,a=t.pending;if(null!==a){if(null!==l){var i=l.next;l.next=a.next,a.next=i}r.baseQueue=l=a,t.pending=null}if(null!==l){a=l.next,r=r.baseState;var u=i=null,o=null,s=a;do{var c=s.lane;if((dr&c)===c)null!==o&&(o=o.next={lane:0,action:s.action,eagerReducer:s.eagerReducer,eagerState:s.eagerState,next:null}),r=s.eagerReducer===e?s.eagerState:e(r,s.action);else{var d={lane:c,action:s.action,eagerReducer:s.eagerReducer,eagerState:s.eagerState,next:null};null===o?(u=o=d,i=r):o=o.next=d,fr.lanes|=c,ia|=c}s=s.next}while(null!==s&&s!==a);null===o?i=r:o.next=u,ht(r,n.memoizedState)||(Zr=!0),n.memoizedState=r,n.baseState=i,n.baseQueue=o,t.lastRenderedState=r}if(null!==(e=t.interleaved)){l=e;do{a=l.lane,fr.lanes|=a,ia|=a,l=l.next}while(l!==e)}else null===l&&(t.lanes=0);return[n.memoizedState,t.dispatch]}function Tr(e){var n=kr(),t=n.queue;if(null===t)throw Error("Should have a queue. This is likely a bug in React. Please file an issue.");t.lastRenderedReducer=e;var r=t.dispatch,l=t.pending,a=n.memoizedState;if(null!==l){t.pending=null;var i=l=l.next;do{a=e(a,i.action),i=i.next}while(i!==l);ht(a,n.memoizedState)||(Zr=!0),n.memoizedState=a,null===n.baseQueue&&(n.baseState=a),t.lastRenderedState=a}return[a,r]}function xr(e,n,t){var r=n._getVersion;r=r(n._source);var l=n._workInProgressVersionPrimary;if(null!==l?e=l===r:(e=e.mutableReadLanes,(e=(dr&e)===e)&&(n._workInProgressVersionPrimary=r,ur.push(n))),e)return t(n._source);throw ur.push(n),Error("Cannot read from mutable source during the current render without tearing. This may be a bug in React. Please file an issue.")}function Pr(e,n,t,r){var l=Zl;if(null===l)throw Error("Expected a work-in-progress root. This is a bug in React. Please file an issue.");var a=n._getVersion,i=a(n._source),u=sr.current,o=u.useState(function(){return xr(l,n,t)}),s=o[1],c=o[0];o=hr;var d=e.memoizedState,f=d.refs,p=f.getSnapshot,h=d.source;d=d.subscribe;var g=fr;return e.memoizedState={refs:f,source:n,subscribe:r},u.useEffect(function(){f.getSnapshot=t,f.setSnapshot=s;var e=a(n._source);ht(i,e)||(e=t(n._source),ht(c,e)||(s(e),e=wa(g),l.mutableReadLanes|=e&l.pendingLanes),Cn(l,l.mutableReadLanes))},[t,n,r]),u.useEffect(function(){return r(n._source,function(){var e=f.getSnapshot,t=f.setSnapshot;try{t(e(n._source));var r=wa(g);l.mutableReadLanes|=r&l.pendingLanes}catch(e){t(function(){throw e})}})},[n,r]),ht(p,t)&&ht(h,n)&&ht(d,r)||((e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:wr,lastRenderedState:c}).dispatch=s=jr.bind(null,fr,e),o.queue=e,o.baseQueue=null,c=xr(l,n,t),o.memoizedState=o.baseState=c),c}function Rr(e,n,t){return Pr(kr(),e,n,t)}function Er(e){var n=Sr();return"function"==typeof e&&(e=e()),n.memoizedState=n.baseState=e,e=(e=n.queue={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:wr,lastRenderedState:e}).dispatch=jr.bind(null,fr,e),[n.memoizedState,e]}function Cr(e,n,t,r){return e={tag:e,create:n,destroy:t,deps:r,next:null},null===(n=fr.updateQueue)?(n={lastEffect:null},fr.updateQueue=n,n.lastEffect=e.next=e):null===(t=n.lastEffect)?n.lastEffect=e.next=e:(r=t.next,t.next=e,e.next=r,n.lastEffect=e),e}function Nr(){return kr().memoizedState}function zr(e,n,t,r){var l=Sr();fr.flags|=e,l.memoizedState=Cr(1|n,t,void 0,void 0===r?null:r)}function Ir(e,n,t,r){var l=kr();r=void 0===r?null:r;var a=void 0;if(null!==pr){var i=pr.memoizedState;if(a=i.destroy,null!==r&&br(r,i.deps))return void(l.memoizedState=Cr(n,t,a,r))}fr.flags|=e,l.memoizedState=Cr(1|n,t,a,r)}function Lr(e,n){return zr(1049600,4,e,n)}function Ur(e,n){return Ir(1024,4,e,n)}function Mr(e,n){return Ir(4,2,e,n)}function Fr(e,n){return"function"==typeof n?(e=e(),n(e),function(){n(null)}):null!==n&&void 0!==n?(e=e(),n.current=e,function(){n.current=null}):void 0}function Dr(e,n,t){return t=null!==t&&void 0!==t?t.concat([e]):null,Ir(4,2,Fr.bind(null,n,e),t)}function Ar(){}function Qr(e,n){var t=kr();n=void 0===n?null:n;var r=t.memoizedState;return null!==r&&null!==n&&br(n,r[1])?r[0]:(t.memoizedState=[e,n],e)}function Hr(e,n){var t=kr();n=void 0===n?null:n;var r=t.memoizedState;return null!==r&&null!==n&&br(n,r[1])?r[0]:(e=e(),t.memoizedState=[e,n],e)}function Or(e,n){var t=Ln;Ln=0!==t&&4>t?t:4,e(!0);var r=cr.transition;cr.transition=1;try{e(!1),n()}finally{Ln=t,cr.transition=r}}function jr(e,n,t){var r=ka(),l=wa(e),a={lane:l,action:t,eagerReducer:null,eagerState:null,next:null},i=e.alternate;if(e===fr||null!==i&&i===fr)mr=gr=!0,null===(l=n.pending)?a.next=a:(a.next=l.next,l.next=a),n.pending=a;else{if(null!==Zl&&0!=(1&e.mode)&&0==(8&Jl)){var u=n.interleaved;null===u?(a.next=a,null===Et?Et=[n]:Et.push(n)):(a.next=u.next,u.next=a),n.interleaved=a}else null===(u=n.pending)?a.next=a:(a.next=u.next,u.next=a),n.pending=a;if(0===e.lanes&&(null===i||0===i.lanes)&&null!==(i=n.lastRenderedReducer))try{var o=n.lastRenderedState,s=i(o,t);if(a.eagerReducer=i,a.eagerState=s,ht(s,o))return}catch(e){}a=_a(e,l,r),0!=(4194240&l)&&null!==a&&(e=n.lanes,l|=e&=a.pendingLanes,n.lanes=l,Cn(a,l))}}var Br={readContext:Rt,useCallback:vr,useContext:vr,useEffect:vr,useImperativeHandle:vr,useLayoutEffect:vr,useMemo:vr,useReducer:vr,useRef:vr,useState:vr,useDebugValue:vr,useDeferredValue:vr,useTransition:vr,useMutableSource:vr,useOpaqueIdentifier:vr,unstable_isNewReconciler:!1},Vr={readContext:Rt,useCallback:function(e,n){return Sr().memoizedState=[e,void 0===n?null:n],e},useContext:Rt,useEffect:Lr,useImperativeHandle:function(e,n,t){return t=null!==t&&void 0!==t?t.concat([e]):null,zr(4,2,Fr.bind(null,n,e),t)},useLayoutEffect:function(e,n){return zr(4,2,e,n)},useMemo:function(e,n){var t=Sr();return n=void 0===n?null:n,e=e(),t.memoizedState=[e,n],e},useReducer:function(e,n,t){var r=Sr();return n=void 0!==t?t(n):n,r.memoizedState=r.baseState=n,e=(e=r.queue={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:n}).dispatch=jr.bind(null,fr,e),[r.memoizedState,e]},useRef:function(e){return e={current:e},Sr().memoizedState=e},useState:Er,useDebugValue:Ar,useDeferredValue:function(e){var n=Er(e),t=n[0],r=n[1];return Lr(function(){var n=cr.transition;cr.transition=1;try{r(e)}finally{cr.transition=n}},[e]),t},useTransition:function(){var e=Er(!1),n=e[0];return e=Or.bind(null,e[1]),Sr().memoizedState=e,[n,e]},useMutableSource:function(e,n,t){var r=Sr();return r.memoizedState={refs:{getSnapshot:n,setSnapshot:null},source:e,subscribe:t},Pr(r,e,n,t)},useOpaqueIdentifier:function(){throw Error("Not yet implemented")},unstable_isNewReconciler:!1},Wr={readContext:Rt,useCallback:Qr,useContext:Rt,useEffect:Ur,useImperativeHandle:Dr,useLayoutEffect:Mr,useMemo:Hr,useReducer:_r,useRef:Nr,useState:function(){return _r(wr)},useDebugValue:Ar,useDeferredValue:function(e){var n=_r(wr),t=n[0],r=n[1];return Ur(function(){var n=cr.transition;cr.transition=1;try{r(e)}finally{cr.transition=n}},[e]),t},useTransition:function(){return[_r(wr)[0],kr().memoizedState]},useMutableSource:Rr,useOpaqueIdentifier:function(){return _r(wr)[0]},unstable_isNewReconciler:!1},Yr={readContext:Rt,useCallback:Qr,useContext:Rt,useEffect:Ur,useImperativeHandle:Dr,useLayoutEffect:Mr,useMemo:Hr,useReducer:Tr,useRef:Nr,useState:function(){return Tr(wr)},useDebugValue:Ar,useDeferredValue:function(e){var n=Tr(wr),t=n[0],r=n[1];return Ur(function(){var n=cr.transition;cr.transition=1;try{r(e)}finally{cr.transition=n}},[e]),t},useTransition:function(){return[Tr(wr)[0],kr().memoizedState]},useMutableSource:Rr,useOpaqueIdentifier:function(){return Tr(wr)[0]},unstable_isNewReconciler:!1};function qr(e,n){return{value:e,source:n,stack:vt(n)}}if("function"!=typeof n(i[3]).ReactFiberErrorDialog.showErrorDialog)throw Error("Expected ReactFiberErrorDialog.showErrorDialog to be a function.");function Xr(e,t){try{!1!==n(i[3]).ReactFiberErrorDialog.showErrorDialog({componentStack:null!==t.stack?t.stack:"",error:t.value,errorBoundary:null!==e&&1===e.tag?e.stateNode:null})&&console.error(t.value)}catch(e){setTimeout(function(){throw e})}}var $r="function"==typeof WeakMap?WeakMap:Map;function Gr(e,n,t){(t=It(-1,t)).tag=3,t.payload={element:null};var r=n.value;return t.callback=function(){da||(da=!0,fa=r),Xr(e,n)},t}function Kr(e,n,t){(t=It(-1,t)).tag=3;var r=e.type.getDerivedStateFromError;if("function"==typeof r){var l=n.value;t.payload=function(){return Xr(e,n),r(l)}}var a=e.stateNode;return null!==a&&"function"==typeof a.componentDidCatch&&(t.callback=function(){"function"!=typeof r&&(null===pa?pa=new Set([this]):pa.add(this),Xr(e,n));var t=n.stack;this.componentDidCatch(n.value,{componentStack:null!==t?t:""})}),t}var Jr=ze.ReactCurrentOwner,Zr=!1;function el(e,n,t,r){n.child=null===e?$t(n,null,t,r):Xt(n,e.child,t,r)}function nl(e,n,t,r,l){t=t.render;var a=n.ref;return Pt(n,l),r=yr(e,n,t,r,a,l),null===e||Zr?(n.flags|=1,el(e,n,r,l),n.child):(n.updateQueue=e.updateQueue,n.flags&=-1029,e.lanes&=~l,_l(e,n,l))}function tl(e,n,t,r,l,a){if(null===e){var i=t.type;return"function"!=typeof i||qa(i)||void 0!==i.defaultProps||null!==t.compare||void 0!==t.defaultProps?((e=Ga(t.type,null,r,n,n.mode,a)).ref=n.ref,e.return=n,n.child=e):(n.tag=15,n.type=i,rl(e,n,i,r,l,a))}return i=e.child,0==(l&a)&&(l=i.memoizedProps,(t=null!==(t=t.compare)?t:gt)(l,r)&&e.ref===n.ref)?_l(e,n,a):(n.flags|=1,(e=$a(i,r)).ref=n.ref,e.return=n,n.child=e)}function rl(e,n,t,r,l,a){if(null!==e&>(e.memoizedProps,r)&&e.ref===n.ref){if(Zr=!1,0==(a&l))return n.lanes=e.lanes,_l(e,n,a);0!=(32768&e.flags)&&(Zr=!0)}return il(e,n,t,r,a)}function ll(e,n,t){var r=n.pendingProps,l=r.children,a=null!==e?e.memoizedState:null;if("hidden"===r.mode||"unstable-defer-without-hiding"===r.mode)if(0==(1&n.mode))n.memoizedState={baseLanes:0,cachePool:null},Kn(ra,ta),ta|=t;else{if(0==(1073741824&t))return e=null!==a?a.baseLanes|t:t,n.lanes=n.childLanes=1073741824,n.memoizedState={baseLanes:e,cachePool:null},n.updateQueue=null,Kn(ra,ta),ta|=e,null;n.memoizedState={baseLanes:0,cachePool:null},r=null!==a?a.baseLanes:t,Kn(ra,ta),ta|=r}else null!==a?(r=a.baseLanes|t,n.memoizedState=null):r=t,Kn(ra,ta),ta|=r;return el(e,n,l,t),n.child}function al(e,n){var t=n.ref;(null===e&&null!==t||null!==e&&e.ref!==t)&&(n.flags|=256)}function il(e,n,t,r,l){var a=rt(t)?nt:Zn.current;return a=tt(n,a),Pt(n,l),t=yr(e,n,t,r,a,l),null===e||Zr?(n.flags|=1,el(e,n,t,l),n.child):(n.updateQueue=e.updateQueue,n.flags&=-1029,e.lanes&=~l,_l(e,n,l))}function ul(e,n,t,r,l){if(rt(t)){var a=!0;ut(n)}else a=!1;if(Pt(n,l),null===n.stateNode)null!==e&&(e.alternate=null,n.alternate=null,n.flags|=2),jt(n,t,r),Vt(n,t,r,l),r=!0;else if(null===e){var i=n.stateNode,u=n.memoizedProps;i.props=u;var o=i.context,s=t.contextType;"object"==typeof s&&null!==s?s=Rt(s):s=tt(n,s=rt(t)?nt:Zn.current);var c=t.getDerivedStateFromProps,d="function"==typeof c||"function"==typeof i.getSnapshotBeforeUpdate;d||"function"!=typeof i.UNSAFE_componentWillReceiveProps&&"function"!=typeof i.componentWillReceiveProps||(u!==r||o!==s)&&Bt(n,i,r,s),Ct=!1;var f=n.memoizedState;i.state=f,Ft(n,r,i,l),o=n.memoizedState,u!==r||f!==o||et.current||Ct?("function"==typeof c&&(Qt(n,t,c,r),o=n.memoizedState),(u=Ct||Ot(n,t,u,r,f,o,s))?(d||"function"!=typeof i.UNSAFE_componentWillMount&&"function"!=typeof i.componentWillMount||("function"==typeof i.componentWillMount&&i.componentWillMount(),"function"==typeof i.UNSAFE_componentWillMount&&i.UNSAFE_componentWillMount()),"function"==typeof i.componentDidMount&&(n.flags|=4)):("function"==typeof i.componentDidMount&&(n.flags|=4),n.memoizedProps=r,n.memoizedState=o),i.props=r,i.state=o,i.context=s,r=u):("function"==typeof i.componentDidMount&&(n.flags|=4),r=!1)}else{i=n.stateNode,zt(e,n),u=n.memoizedProps,s=n.type===n.elementType?u:bt(n.type,u),i.props=s,d=n.pendingProps,f=i.context,"object"==typeof(o=t.contextType)&&null!==o?o=Rt(o):o=tt(n,o=rt(t)?nt:Zn.current);var p=t.getDerivedStateFromProps;(c="function"==typeof p||"function"==typeof i.getSnapshotBeforeUpdate)||"function"!=typeof i.UNSAFE_componentWillReceiveProps&&"function"!=typeof i.componentWillReceiveProps||(u!==d||f!==o)&&Bt(n,i,r,o),Ct=!1,f=n.memoizedState,i.state=f,Ft(n,r,i,l);var h=n.memoizedState;u!==d||f!==h||et.current||Ct?("function"==typeof p&&(Qt(n,t,p,r),h=n.memoizedState),(s=Ct||Ot(n,t,s,r,f,h,o)||!1)?(c||"function"!=typeof i.UNSAFE_componentWillUpdate&&"function"!=typeof i.componentWillUpdate||("function"==typeof i.componentWillUpdate&&i.componentWillUpdate(r,h,o),"function"==typeof i.UNSAFE_componentWillUpdate&&i.UNSAFE_componentWillUpdate(r,h,o)),"function"==typeof i.componentDidUpdate&&(n.flags|=4),"function"==typeof i.getSnapshotBeforeUpdate&&(n.flags|=512)):("function"!=typeof i.componentDidUpdate||u===e.memoizedProps&&f===e.memoizedState||(n.flags|=4),"function"!=typeof i.getSnapshotBeforeUpdate||u===e.memoizedProps&&f===e.memoizedState||(n.flags|=512),n.memoizedProps=r,n.memoizedState=h),i.props=r,i.state=h,i.context=o,r=s):("function"!=typeof i.componentDidUpdate||u===e.memoizedProps&&f===e.memoizedState||(n.flags|=4),"function"!=typeof i.getSnapshotBeforeUpdate||u===e.memoizedProps&&f===e.memoizedState||(n.flags|=512),r=!1)}return ol(e,n,t,r,a,l)}function ol(e,n,t,r,l,a){al(e,n);var i=0!=(128&n.flags);if(!r&&!i)return l&&ot(n,t,!1),_l(e,n,a);r=n.stateNode,Jr.current=n;var u=i&&"function"!=typeof t.getDerivedStateFromError?null:r.render();return n.flags|=1,null!==e&&i?(n.child=Xt(n,e.child,null,a),n.child=Xt(n,null,u,a)):el(e,n,u,a),n.memoizedState=r.state,l&&ot(n,t,!0),n.child}function sl(e){var n=e.stateNode;n.pendingContext?at(0,n.pendingContext,n.pendingContext!==n.context):n.context&&at(0,n.context,!1),nr(e,n.containerInfo)}var cl,dl,fl,pl,hl={dehydrated:null,retryLane:0};function gl(e){return{baseLanes:e,cachePool:null}}function ml(e,n,t){var r,l=n.pendingProps,a=ar.current,i=!1;return(r=0!=(128&n.flags))||(r=(null===e||null!==e.memoizedState)&&0!=(2&a)),r?(i=!0,n.flags&=-129):null!==e&&null===e.memoizedState||void 0===l.fallback||!0===l.unstable_avoidThisFallback||(a|=1),Kn(ar,1&a),null===e?(e=l.children,a=l.fallback,i?(e=vl(n,e,a,t),n.child.memoizedState=gl(t),n.memoizedState=hl,e):"number"==typeof l.unstable_expectedLoadTime?(e=vl(n,e,a,t),n.child.memoizedState=gl(t),n.memoizedState=hl,n.lanes=4194304,e):((t=Ja({mode:"visible",children:e},n.mode,t,null)).return=n,n.child=t)):(e.memoizedState,i?(l=yl(e,n,l.children,l.fallback,t),i=n.child,a=e.child.memoizedState,i.memoizedState=null===a?gl(t):{baseLanes:a.baseLanes|t,cachePool:null},i.childLanes=e.childLanes&~t,n.memoizedState=hl,l):(t=bl(e,n,l.children,t),n.memoizedState=null,t))}function vl(e,n,t,r){var l=e.mode,a=e.child;return n={mode:"hidden",children:n},0==(1&l)&&null!==a?(a.childLanes=0,a.pendingProps=n):a=Ja(n,l,0,null),t=Ka(t,l,r,null),a.return=e,t.return=e,a.sibling=t,e.child=a,t}function bl(e,n,t,r){var l=e.child;return e=l.sibling,t=$a(l,{mode:"visible",children:t}),0==(1&n.mode)&&(t.lanes=r),t.return=n,t.sibling=null,null!==e&&(null===(r=n.deletions)?(n.deletions=[e],n.flags|=16):r.push(e)),n.child=t}function yl(e,n,t,r,l){var a=n.mode,i=(e=e.child).sibling,u={mode:"hidden",children:t};return 0==(1&a)&&n.child!==e?((t=n.child).childLanes=0,t.pendingProps=u,n.deletions=null):(t=$a(e,u)).subtreeFlags=1835008&e.subtreeFlags,null!==i?r=$a(i,r):(r=Ka(r,a,l,null)).flags|=2,r.return=n,t.return=n,t.sibling=r,n.child=t,r}function Sl(e,n){e.lanes|=n;var t=e.alternate;null!==t&&(t.lanes|=n),xt(e.return,n)}function kl(e,n,t,r,l){var a=e.memoizedState;null===a?e.memoizedState={isBackwards:n,rendering:null,renderingStartTime:0,last:r,tail:t,tailMode:l}:(a.isBackwards=n,a.rendering=null,a.renderingStartTime=0,a.last=r,a.tail=t,a.tailMode=l)}function wl(e,n,t){var r=n.pendingProps,l=r.revealOrder,a=r.tail;if(el(e,n,r.children,t),0!=(2&(r=ar.current)))r=1&r|2,n.flags|=128;else{if(null!==e&&0!=(128&e.flags))e:for(e=n.child;null!==e;){if(13===e.tag)null!==e.memoizedState&&Sl(e,t);else if(19===e.tag)Sl(e,t);else if(null!==e.child){e.child.return=e,e=e.child;continue}if(e===n)break e;for(;null===e.sibling;){if(null===e.return||e.return===n)break e;e=e.return}e.sibling.return=e.return,e=e.sibling}r&=1}if(Kn(ar,r),0==(1&n.mode))n.memoizedState=null;else switch(l){case"forwards":for(t=n.child,l=null;null!==t;)null!==(e=t.alternate)&&null===ir(e)&&(l=t),t=t.sibling;null===(t=l)?(l=n.child,n.child=null):(l=t.sibling,t.sibling=null),kl(n,!1,l,t,a);break;case"backwards":for(t=null,l=n.child,n.child=null;null!==l;){if(null!==(e=l.alternate)&&null===ir(e)){n.child=l;break}e=l.sibling,l.sibling=t,t=l,l=e}kl(n,!0,t,null,a);break;case"together":kl(n,!1,null,null,void 0);break;default:n.memoizedState=null}return n.child}function _l(e,n,t){if(null!==e&&(n.dependencies=e.dependencies),ia|=n.lanes,0==(t&n.childLanes))return null;if(null!==e&&n.child!==e.child)throw Error("Resuming work not yet implemented.");if(null!==n.child){for(t=$a(e=n.child,e.pendingProps),n.child=t,t.return=n;null!==e.sibling;)e=e.sibling,(t=t.sibling=$a(e,e.pendingProps)).return=n;t.sibling=null}return n.child}function Tl(e,n){switch(e.tailMode){case"hidden":n=e.tail;for(var t=null;null!==n;)null!==n.alternate&&(t=n),n=n.sibling;null===t?e.tail=null:t.sibling=null;break;case"collapsed":t=e.tail;for(var r=null;null!==t;)null!==t.alternate&&(r=t),t=t.sibling;null===r?n||null===e.tail?e.tail=null:e.tail.sibling=null:r.sibling=null}}function xl(e){var n=null!==e.alternate&&e.alternate.child===e.child,t=0,r=0;if(n)for(var l=e.child;null!==l;)t|=l.lanes|l.childLanes,r|=1835008&l.subtreeFlags,r|=1835008&l.flags,l.return=e,l=l.sibling;else for(l=e.child;null!==l;)t|=l.lanes|l.childLanes,r|=l.subtreeFlags,r|=l.flags,l.return=e,l=l.sibling;return e.subtreeFlags|=r,e.childLanes=t,n}function Pl(e,t,r){var l=t.pendingProps;switch(t.tag){case 2:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return xl(t),null;case 1:return rt(t.type)&<(),xl(t),null;case 3:return l=t.stateNode,tr(),Gn(et),Gn(Zn),or(),l.pendingContext&&(l.context=l.pendingContext,l.pendingContext=null),null!==e&&null!==e.child||l.hydrate||(t.flags|=512),dl(e,t),xl(t),null;case 5:lr(t),r=er(Zt.current);var a=t.type;if(null!==e&&null!=t.stateNode)fl(e,t,a,l,r),e.ref!==t.ref&&(t.flags|=256);else{if(!l){if(null===t.stateNode)throw Error("We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue.");return xl(t),null}er(Kt.current),e=Qn(),a=Fn(a);var u=hn(null,ln,l,a.validAttributes);n(i[3]).UIManager.createView(e,a.uiViewClassName,r,u),r=new mn(e,a,t),ke.set(e,t),we.set(e,l),cl(r,t,!1,!1),t.stateNode=r,On(r)&&(t.flags|=4),null!==t.ref&&(t.flags|=256)}return xl(t),null;case 6:if(e&&null!=t.stateNode)pl(e,t,e.memoizedProps,l);else{if("string"!=typeof l&&null===t.stateNode)throw Error("We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue.");if(e=er(Zt.current),!er(Kt.current).isInAParentText)throw Error("Text strings must be rendered within a component.");r=Qn(),n(i[3]).UIManager.createView(r,"RCTRawText",e,{text:l}),ke.set(r,t),t.stateNode=r}return xl(t),null;case 13:return Gn(ar),l=t.memoizedState,0!=(128&t.flags)?(t.lanes=r,t):(l=null!==l,r=!1,null!==e&&(r=null!==e.memoizedState),l&&!r&&0!=(1&t.mode)&&(null===e&&!0!==t.memoizedProps.unstable_avoidThisFallback||0!=(1&ar.current)?0===la&&(la=3):(0!==la&&3!==la||(la=4),null===Zl||0==(268435455&ia)&&0==(268435455&ua)||Ra(Zl,na))),(l||r)&&(t.flags|=4),xl(t),null);case 4:return tr(),dl(e,t),xl(t),null;case 10:return Tt(t.type._context),xl(t),null;case 17:return rt(t.type)&<(),xl(t),null;case 19:if(Gn(ar),null===(a=t.memoizedState))return xl(t),null;if(l=0!=(128&t.flags),null===(u=a.rendering))if(l)Tl(a,!1);else{if(0!==la||null!==e&&0!=(128&e.flags))for(e=t.child;null!==e;){if(null!==(u=ir(e))){for(t.flags|=128,Tl(a,!1),null!==(e=u.updateQueue)&&(t.updateQueue=e,t.flags|=4),t.subtreeFlags=0,e=r,l=t.child;null!==l;)a=e,(r=l).flags&=1835010,null===(u=r.alternate)?(r.childLanes=0,r.lanes=a,r.child=null,r.subtreeFlags=0,r.memoizedProps=null,r.memoizedState=null,r.updateQueue=null,r.dependencies=null,r.stateNode=null):(r.childLanes=u.childLanes,r.lanes=u.lanes,r.child=u.child,r.subtreeFlags=0,r.deletions=null,r.memoizedProps=u.memoizedProps,r.memoizedState=u.memoizedState,r.updateQueue=u.updateQueue,r.type=u.type,a=u.dependencies,r.dependencies=null===a?null:{lanes:a.lanes,firstContext:a.firstContext}),l=l.sibling;return Kn(ar,1&ar.current|2),t.child}e=e.sibling}null!==a.tail&&n(i[4]).unstable_now()>ca&&(t.flags|=128,l=!0,Tl(a,!1),t.lanes=4194304)}else{if(!l)if(null!==(e=ir(u))){if(t.flags|=128,l=!0,null!==(e=e.updateQueue)&&(t.updateQueue=e,t.flags|=4),Tl(a,!0),null===a.tail&&"hidden"===a.tailMode&&!u.alternate)return xl(t),null}else 2*n(i[4]).unstable_now()-a.renderingStartTime>ca&&1073741824!==r&&(t.flags|=128,l=!0,Tl(a,!1),t.lanes=4194304);a.isBackwards?(u.sibling=t.child,t.child=u):(null!==(e=a.last)?e.sibling=u:t.child=u,a.last=u)}return null!==a.tail?(t=a.tail,a.rendering=t,a.tail=t.sibling,a.renderingStartTime=n(i[4]).unstable_now(),t.sibling=null,e=ar.current,Kn(ar,l?1&e|2:1&e),t):(xl(t),null);case 22:case 23:return Ca(),r=null!==t.memoizedState,null!==e&&null!==e.memoizedState!==r&&"unstable-defer-without-hiding"!==l.mode&&(t.flags|=4),r&&0==(1073741824&ta)&&0!=(1&t.mode)||xl(t),null}throw Error("Unknown unit of work tag ("+t.tag+"). This error is likely caused by a bug in React. Please file an issue.")}function Rl(e){switch(e.tag){case 1:rt(e.type)&<();var n=e.flags;return 16384&n?(e.flags=-16385&n|128,e):null;case 3:if(tr(),Gn(et),Gn(Zn),or(),0!=(128&(n=e.flags)))throw Error("The root failed to unmount after an error. This is likely a bug in React. Please file an issue.");return e.flags=-16385&n|128,e;case 5:return lr(e),null;case 13:return Gn(ar),16384&(n=e.flags)?(e.flags=-16385&n|128,e):null;case 19:return Gn(ar),null;case 4:return tr(),null;case 10:return Tt(e.type._context),null;case 22:case 23:return Ca(),null;case 24:default:return null}}cl=function(e,n){for(var t=n.child;null!==t;){if(5===t.tag||6===t.tag)e._children.push(t.stateNode);else if(4!==t.tag&&null!==t.child){t.child.return=t,t=t.child;continue}if(t===n)break;for(;null===t.sibling;){if(null===t.return||t.return===n)return;t=t.return}t.sibling.return=t.return,t=t.sibling}},dl=function(){},fl=function(e,n,t,r){e.memoizedProps!==r&&(er(Kt.current),n.updateQueue=Dn)&&(n.flags|=4)},pl=function(e,n,t,r){t!==r&&(n.flags|=4)};var El="function"==typeof WeakSet?WeakSet:Set,Cl=null;function Nl(e,n){var t=e.ref;if(null!==t)if("function"==typeof t)try{t(null)}catch(t){ja(e,n,t)}else t.current=null}var zl=!1;function Il(e,n){for(Cl=n;null!==Cl;)if(n=(e=Cl).child,0!=(516&e.subtreeFlags)&&null!==n)n.return=e,Cl=n;else for(;null!==Cl;){e=Cl;try{var t=e.alternate;if(0!=(512&e.flags))switch(e.tag){case 0:case 11:case 15:break;case 1:if(null!==t){var r=t.memoizedProps,l=t.memoizedState,a=e.stateNode,i=a.getSnapshotBeforeUpdate(e.elementType===e.type?r:bt(e.type,r),l);a.__reactInternalSnapshotBeforeUpdate=i}break;case 3:break;case 5:case 6:case 4:case 17:break;default:throw Error("This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue.")}}catch(n){ja(e,e.return,n)}if(null!==(n=e.sibling)){n.return=e.return,Cl=n;break}Cl=e.return}return t=zl,zl=!1,t}function Ll(e,n,t){var r=n.updateQueue;if(null!==(r=null!==r?r.lastEffect:null)){var l=r=r.next;do{if((l.tag&e)===e){var a=l.destroy;if(l.destroy=void 0,void 0!==a){var i=n,u=t;try{a()}catch(e){ja(i,u,e)}}}l=l.next}while(l!==r)}}function Ul(e,n){if(null!==(n=null!==(n=n.updateQueue)?n.lastEffect:null)){var t=n=n.next;do{if((t.tag&e)===e){var r=t.create;t.destroy=r()}t=t.next}while(t!==n)}}function Ml(e,t){for(var r=null,l=e;;){if(5===l.tag){if(null===r){r=l;var a=l.stateNode;if(t){var u=a.viewConfig,o=hn(null,ln,{style:{display:"none"}},u.validAttributes);n(i[3]).UIManager.updateView(a._nativeTag,u.uiViewClassName,o)}else{a=l.stateNode,o=l.memoizedProps,u=a.viewConfig,o=hn(null,n(i[2])({},o,{style:[o.style,{display:"none"}]}),o,u.validAttributes),n(i[3]).UIManager.updateView(a._nativeTag,u.uiViewClassName,o)}}}else if(6===l.tag){if(null===r)throw Error("Not yet implemented.")}else if((22!==l.tag&&23!==l.tag||null===l.memoizedState||l===e)&&null!==l.child){l.child.return=l,l=l.child;continue}if(l===e)break;for(;null===l.sibling;){if(null===l.return||l.return===e)return;r===l&&(r=null),l=l.return}r===l&&(r=null),l.sibling.return=l.return,l=l.sibling}}function Fl(e,n,t){if(bn&&"function"==typeof bn.onCommitFiberUnmount)try{bn.onCommitFiberUnmount(vn,n)}catch(e){}switch(n.tag){case 0:case 11:case 14:case 15:if(null!==(e=n.updateQueue)&&null!==(e=e.lastEffect)){var r=e=e.next;do{var l=r,a=l.destroy;if(l=l.tag,void 0!==a&&0!=(2&l)){l=n;var i=t;try{a()}catch(e){ja(l,i,e)}}r=r.next}while(r!==e)}break;case 1:if(Nl(n,t),"function"==typeof(e=n.stateNode).componentWillUnmount)try{e.props=n.memoizedProps,e.state=n.memoizedState,e.componentWillUnmount()}catch(e){ja(n,t,e)}break;case 5:Nl(n,t);break;case 4:jl(e,n,t)}}function Dl(e){var n=e.alternate;null!==n&&(e.alternate=null,Dl(n)),e.child=null,e.deletions=null,e.sibling=null,e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function Al(e){return 5===e.tag||3===e.tag||4===e.tag}function Ql(e){e:{for(var n=e.return;null!==n;){if(Al(n))break e;n=n.return}throw Error("Expected to find a host parent. This error is likely caused by a bug in React. Please file an issue.")}var t=n;switch(n=t.stateNode,t.tag){case 5:var r=!1;break;case 3:case 4:n=n.containerInfo,r=!0;break;default:throw Error("Invalid host parent fiber. This error is likely caused by a bug in React. Please file an issue.")}32&t.flags&&(t.flags&=-33);e:n:for(t=e;;){for(;null===t.sibling;){if(null===t.return||Al(t.return)){t=null;break e}t=t.return}for(t.sibling.return=t.return,t=t.sibling;5!==t.tag&&6!==t.tag&&18!==t.tag;){if(2&t.flags)continue n;if(null===t.child||4===t.tag)continue n;t.child.return=t,t=t.child}if(!(2&t.flags)){t=t.stateNode;break e}}r?Hl(e,t,n):Ol(e,t,n)}function Hl(e,t,r){var l=e.tag;if(5===l||6===l)if(e=e.stateNode,t){if("number"==typeof r)throw Error("Container does not support insertBefore operation")}else n(i[3]).UIManager.setChildren(r,["number"==typeof e?e:e._nativeTag]);else if(4!==l&&null!==(e=e.child))for(Hl(e,t,r),e=e.sibling;null!==e;)Hl(e,t,r),e=e.sibling}function Ol(e,t,r){var l=e.tag;if(5===l||6===l)if(e=e.stateNode,t){var a=(l=r._children).indexOf(e);0<=a?(l.splice(a,1),t=l.indexOf(t),l.splice(t,0,e),n(i[3]).UIManager.manageChildren(r._nativeTag,[a],[t],[],[],[])):(t=l.indexOf(t),l.splice(t,0,e),n(i[3]).UIManager.manageChildren(r._nativeTag,[],[],["number"==typeof e?e:e._nativeTag],[t],[]))}else t="number"==typeof e?e:e._nativeTag,0<=(a=(l=r._children).indexOf(e))?(l.splice(a,1),l.push(e),n(i[3]).UIManager.manageChildren(r._nativeTag,[a],[l.length-1],[],[],[])):(l.push(e),n(i[3]).UIManager.manageChildren(r._nativeTag,[],[],[t],[l.length-1],[]));else if(4!==l&&null!==(e=e.child))for(Ol(e,t,r),e=e.sibling;null!==e;)Ol(e,t,r),e=e.sibling}function jl(e,t,r){for(var l,a,u=t,o=!1;;){if(!o){o=u.return;e:for(;;){if(null===o)throw Error("Expected to find a host parent. This error is likely caused by a bug in React. Please file an issue.");switch(l=o.stateNode,o.tag){case 5:a=!1;break e;case 3:case 4:l=l.containerInfo,a=!0;break e}o=o.return}o=!0}if(5===u.tag||6===u.tag){e:for(var s=e,c=u,d=r,f=c;;)if(Fl(s,f,d),null!==f.child&&4!==f.tag)f.child.return=f,f=f.child;else{if(f===c)break e;for(;null===f.sibling;){if(null===f.return||f.return===c)break e;f=f.return}f.sibling.return=f.return,f=f.sibling}a?(s=l,Hn(u.stateNode),n(i[3]).UIManager.manageChildren(s,[],[],[],[],[0])):(s=l,Hn(d=u.stateNode),d=(c=s._children).indexOf(d),c.splice(d,1),n(i[3]).UIManager.manageChildren(s._nativeTag,[],[],[],[],[d]))}else if(4===u.tag){if(null!==u.child){l=u.stateNode.containerInfo,a=!0,u.child.return=u,u=u.child;continue}}else if(Fl(e,u,r),null!==u.child){u.child.return=u,u=u.child;continue}if(u===t)break;for(;null===u.sibling;){if(null===u.return||u.return===t)return;4===(u=u.return).tag&&(o=!1)}u.sibling.return=u.return,u=u.sibling}}function Bl(e,t){switch(t.tag){case 0:case 11:case 14:case 15:return void Ll(3,t,t.return);case 1:return;case 5:var r=t.stateNode;if(null!=r){var l=t.memoizedProps;e=null!==e?e.memoizedProps:l;var a=t.updateQueue;t.updateQueue=null,null!==a&&(t=r.viewConfig,we.set(r._nativeTag,l),null!=(l=hn(null,e,l,t.validAttributes))&&n(i[3]).UIManager.updateView(r._nativeTag,t.uiViewClassName,l))}return;case 6:if(null===t.stateNode)throw Error("This should have a text node initialized. This error is likely caused by a bug in React. Please file an issue.");return void n(i[3]).UIManager.updateView(t.stateNode,"RCTRawText",{text:t.memoizedProps});case 3:case 12:return;case 13:return null!==t.memoizedState&&(sa=n(i[4]).unstable_now(),Ml(t.child,!0)),void Vl(t);case 19:return void Vl(t);case 17:return;case 22:case 23:return void Ml(t,null!==t.memoizedState)}throw Error("This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue.")}function Vl(e){var n=e.updateQueue;if(null!==n){e.updateQueue=null;var t=e.stateNode;null===t&&(t=e.stateNode=new El),n.forEach(function(n){var r=Va.bind(null,e,n);t.has(n)||(t.add(n),n.then(r,r))})}}function Wl(e,n){for(Cl=n;null!==Cl;){var t=(n=Cl).deletions;if(null!==t)for(var r=0;ra&&(a=o),l&=~u}if(l=a,10<(l=(120>(l=n(i[4]).unstable_now()-l)?120:480>l?480:1080>l?1080:1920>l?1920:3e3>l?3e3:4320>l?4320:1960*Xl(l/1960))-l)){e.timeoutHandle=jn(Aa.bind(null,e),l);break}Aa(e);break;case 5:Aa(e);break;default:throw Error("Unknown root exit status.")}}return xa(e,n(i[4]).unstable_now()),e.callbackNode===r?Pa.bind(null,e):null}function Ra(e,n){for(n&=~oa,n&=~ua,e.suspendedLanes|=n,e.pingedLanes&=~n,e=e.expirationTimes;0 component higher in the tree to provide a loading indicator or placeholder to display.")}5!==la&&(la=2),o=qr(o,u),p=i;do{switch(p.tag){case 3:a=o,p.flags|=16384,n&=-n,p.lanes|=n,Mt(p,Gr(p,a,n));break e;case 1:a=o;var w=p.type,_=p.stateNode;if(0==(128&p.flags)&&("function"==typeof w.getDerivedStateFromError||null!==_&&"function"==typeof _.componentDidCatch&&(null===pa||!pa.has(_)))){p.flags|=16384,n&=-n,p.lanes|=n,Mt(p,Kr(p,a,n));break e}}p=p.return}while(null!==p)}Da(t)}catch(e){n=e,ea===t&&null!==t&&(ea=t=t.return);continue}break}}function Ia(){var e=$l.current;return $l.current=Br,null===e?Br:e}function La(e,n){var t=Jl;Jl|=8;var r=Ia();for(Zl===e&&na===n||Na(e,n);;)try{Ua();break}catch(n){za(e,n)}if(_t(),Jl=t,$l.current=r,null!==ea)throw Error("Cannot commit an incomplete root. This error is likely caused by a bug in React. Please file an issue.");return Zl=null,na=0,la}function Ua(){for(;null!==ea;)Fa(ea)}function Ma(){for(;null!==ea&&!n(i[4]).unstable_shouldYield();)Fa(ea)}function Fa(e){var n=ql(e.alternate,e,ta);e.memoizedProps=e.pendingProps,null===n?Da(e):ea=n,Gl.current=null}function Da(e){var n=e;do{var t=n.alternate;if(e=n.return,0==(8192&n.flags)){if(null!==(t=Pl(t,n,ta)))return void(ea=t)}else{if(null!==(t=Rl(n)))return t.flags&=8191,void(ea=t);null!==e&&(e.flags|=8192,e.subtreeFlags=0,e.deletions=null)}if(null!==(n=n.sibling))return void(ea=n);ea=n=e}while(null!==n);0===la&&(la=5)}function Aa(e){var n=Ln,t=Kl.transition;try{Kl.transition=0,Ln=1,Qa(e,n)}finally{Kl.transition=t,Ln=n}return null}function Qa(e,t){do{Ha()}while(null!==ga);if(0!=(24&Jl))throw Error("Should not already be working.");var r=e.finishedWork,l=e.finishedLanes;if(null===r)return null;if(e.finishedWork=null,e.finishedLanes=0,r===e.current)throw Error("Cannot commit the same tree as before. This error is likely caused by a bug in React. Please file an issue.");e.callbackNode=null,e.callbackPriority=0;var a=r.lanes|r.childLanes;if(En(e,a),e===Zl&&(ea=Zl=null,na=0),0==(1040&r.subtreeFlags)&&0==(1040&r.flags)||ha||(ha=!0,n(i[4]).unstable_scheduleCallback(n(i[4]).unstable_NormalPriority,function(){return Ha(),null})),a=0!=(8054&r.flags),0!=(8054&r.subtreeFlags)||a){a=Kl.transition,Kl.transition=0;var u=Ln;Ln=1;var o=Jl;Jl|=16,Gl.current=null,Il(e,r),Wl(e,r),e.current=r,Yl(r),n(i[4]).unstable_requestPaint(),Jl=o,Ln=u,Kl.transition=a}else e.current=r;if(ha&&(ha=!1,ga=e,ma=l),0===(a=e.pendingLanes)&&(pa=null),0!=(1&a)?e===ba?va++:(va=0,ba=e):va=0,yn(r.stateNode),xa(e,n(i[4]).unstable_now()),da)throw da=!1,e=fa,fa=null,e;return 0!=(4&Jl)?null:(0!=(1&ma)&&0!==e.tag&&Ha(),ft(),null)}function Ha(){if(null!==ga){var e=Un(ma),n=Kl.transition,t=Ln;try{if(Kl.transition=0,Ln=16>e?16:e,null===ga)var r=!1;else{if(e=ga,ga=null,ma=0,0!=(24&Jl))throw Error("Cannot flush passive effects while already rendering.");var l=Jl;for(Jl|=16,Cl=e.current;null!==Cl;){var a=Cl,i=a.child;if(0!=(16&Cl.flags)){var u=a.deletions;if(null!==u){for(var o=0;on(i[4]).unstable_now()-sa?Na(e,0):oa|=r),xa(e,t)}function Va(e,n){var t=e.stateNode;null!==t&&t.delete(n),0===(n=0)&&(0==(1&e.mode)?n=1:(n=kn,0==(130023424&(kn<<=1))&&(kn=4194304))),t=ka(),null!==(e=Ta(e,n))&&(Rn(e,n,t),xa(e,t))}function Wa(e,n,t,r){this.tag=e,this.key=t,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=n,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function Ya(e,n,t,r){return new Wa(e,n,t,r)}function qa(e){return!(!(e=e.prototype)||!e.isReactComponent)}function Xa(e){if("function"==typeof e)return qa(e)?1:0;if(void 0!==e&&null!==e){if((e=e.$$typeof)===Qe)return 11;if(e===je)return 14}return 2}function $a(e,n){var t=e.alternate;return null===t?((t=Ya(e.tag,n,e.key,e.mode)).elementType=e.elementType,t.type=e.type,t.stateNode=e.stateNode,t.alternate=e,e.alternate=t):(t.pendingProps=n,t.type=e.type,t.flags=0,t.subtreeFlags=0,t.deletions=null),t.flags=1835008&e.flags,t.childLanes=e.childLanes,t.lanes=e.lanes,t.child=e.child,t.memoizedProps=e.memoizedProps,t.memoizedState=e.memoizedState,t.updateQueue=e.updateQueue,n=e.dependencies,t.dependencies=null===n?null:{lanes:n.lanes,firstContext:n.firstContext},t.sibling=e.sibling,t.index=e.index,t.ref=e.ref,t}function Ga(e,n,t,r,l,a){var i=2;if(r=e,"function"==typeof e)qa(e)&&(i=1);else if("string"==typeof e)i=5;else e:switch(e){case Ue:return Ka(t.children,l,a,n);case Ve:i=8,l|=4;break;case Me:i=8,l|=8;break;case Fe:return(e=Ya(12,t,n,2|l)).elementType=Fe,e.lanes=a,e;case He:return(e=Ya(13,t,n,l)).elementType=He,e.lanes=a,e;case Oe:return(e=Ya(19,t,n,l)).elementType=Oe,e.lanes=a,e;case We:return Ja(t,l,a,n);case Ye:return(e=Ya(23,t,n,l)).elementType=Ye,e.lanes=a,e;default:if("object"==typeof e&&null!==e)switch(e.$$typeof){case De:i=10;break e;case Ae:i=9;break e;case Qe:i=11;break e;case je:i=14;break e;case Be:i=16,r=null;break e}throw Error("Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: "+(null==e?e:typeof e)+".")}return(n=Ya(i,t,n,l)).elementType=e,n.type=r,n.lanes=a,n}function Ka(e,n,t,r){return(e=Ya(7,e,r,n)).lanes=t,e}function Ja(e,n,t,r){return(e=Ya(22,e,r,n)).elementType=We,e.lanes=t,e}function Za(e,n,t){return(e=Ya(6,e,null,n)).lanes=t,e}function ei(e,n,t){return(n=Ya(4,null!==e.children?e.children:[],e.key,n)).lanes=t,n.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},n}function ni(e,n,t){this.tag=n,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.pendingContext=this.context=null,this.hydrate=t,this.callbackNode=null,this.callbackPriority=0,this.eventTimes=Pn(0),this.expirationTimes=Pn(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=Pn(0)}function ti(e,n,t){var r=3=t.length?{done:!0}:{done:!1,value:t[i++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function n(t,n){if(t){if("string"==typeof t)return o(t,n);var u=Object.prototype.toString.call(t).slice(8,-1);return"Object"===u&&t.constructor&&(u=t.constructor.name),"Map"===u||"Set"===u?Array.from(t):"Arguments"===u||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(u)?o(t,n):void 0}}function o(t,n){(null==n||n>t.length)&&(n=t.length);for(var o=0,u=new Array(n);o|\/|[a-z]:\\|\\\\).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i,u=/\((\S*)(?::(\d+))(?::(\d+))\)/;function t(t){var o=l.exec(t);if(!o)return null;var c=o[2]&&0===o[2].indexOf('native'),s=o[2]&&0===o[2].indexOf('eval'),v=u.exec(o[2]);return s&&null!=v&&(o[2]=v[1],o[3]=v[2],o[4]=v[3]),{file:c?null:o[2],methodName:o[1]||n,arguments:c?[o[2]]:[],lineNumber:o[3]?+o[3]:null,column:o[4]?+o[4]:null}}var o=/^\s*at (?:((?:\[object object\])?.+) )?\(?((?:file|ms-appx|https?|webpack|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i;function c(l){var u=o.exec(l);return u?{file:u[2],methodName:u[1]||n,arguments:[],lineNumber:+u[3],column:u[4]?+u[4]:null}:null}var s=/^\s*(.*?)(?:\((.*?)\))?(?:^|@)((?:file|https?|blob|chrome|webpack|resource|\[native).*?|[^@]*bundle)(?::(\d+))?(?::(\d+))?\s*$/i,v=/(\S+) line (\d+)(?: > eval line \d+)* > eval/i;function f(l){var u=s.exec(l);if(!u)return null;var t=u[3]&&u[3].indexOf(' > eval')>-1,o=v.exec(u[3]);return t&&null!=o&&(u[3]=o[1],u[4]=o[2],u[5]=null),{file:u[3],methodName:u[1]||n,arguments:u[2]?u[2].split(','):[],lineNumber:u[4]?+u[4]:null,column:u[5]?+u[5]:null}}var b=/^\s*(?:([^@]*)(?:\((.*?)\))?@)?(\S.*?):(\d+)(?::(\d+))?\s*$/i;function p(l){var u=b.exec(l);return u?{file:u[3],methodName:u[1]||n,arguments:[],lineNumber:+u[4],column:u[5]?+u[5]:null}:null}var x=/^\s*at (?:((?:\[object object\])?[^\\/]+(?: \[as \S+\])?) )?\(?(.*?):(\d+)(?::(\d+))?\)?\s*$/i;function h(l){var u=x.exec(l);return u?{file:u[2],methodName:u[1]||n,arguments:[],lineNumber:+u[3],column:u[4]?+u[4]:null}:null}e.parse=function(n){return n.split('\n').reduce(function(n,l){var u=t(l)||c(l)||f(l)||h(l)||p(l);return u&&n.push(u),n},[])}},471,[]); -__d(function(g,r,_i,a,m,e,d){'use strict';var t=/^ {4}at (.+?)(?: \((native)\)?| \((address at )?(.*?):(\d+):(\d+)\))$/,n=/^ {4}... skipping (\d+) frames$/;function s(s){var i=s.match(t);if(i)return{type:'FRAME',functionName:i[1],location:'native'===i[2]?{type:'NATIVE'}:'address at '===i[3]?{type:'BYTECODE',sourceUrl:i[4],line1Based:Number.parseInt(i[5],10),virtualOffset0Based:Number.parseInt(i[6],10)}:{type:'SOURCE',sourceUrl:i[4],line1Based:Number.parseInt(i[5],10),column1Based:Number.parseInt(i[6],10)}};var u=s.match(n);return u?{type:'SKIPPED',count:Number.parseInt(u[1],10)}:void 0}m.exports=function(t){for(var n=t.split(/\n/),i=[],u=-1,p=0;p-1}m.exports={isNativeFunction:t,hasNativeConstructor:function(n,o){var c=Object.getPrototypeOf(n).constructor;return c.name===o&&t(c)}}},481,[]); -__d(function(g,r,i,a,m,e,d){'use strict';var l,n,t=!0===(null==(l=g.HermesInternal)?void 0:null==l.hasPromise?void 0:l.hasPromise())&&!0===(null==(n=g.HermesInternal)?void 0:null==n.useEngineQueue?void 0:n.useEngineQueue()),u=r(d[0]).isNativeFunction(Promise)||t;if(!g.RN$Bridgeless){var o=function(l){r(d[1]).polyfillGlobal(l,function(){return r(d[2])[l]})};o('setTimeout'),o('clearTimeout'),o('setInterval'),o('clearInterval'),o('requestAnimationFrame'),o('cancelAnimationFrame'),o('requestIdleCallback'),o('cancelIdleCallback')}u?(r(d[1]).polyfillGlobal('setImmediate',function(){return r(d[3]).setImmediate}),r(d[1]).polyfillGlobal('clearImmediate',function(){return r(d[3]).clearImmediate})):g.RN$Bridgeless||(r(d[1]).polyfillGlobal('setImmediate',function(){return r(d[2]).queueReactNativeMicrotask}),r(d[1]).polyfillGlobal('clearImmediate',function(){return r(d[2]).clearReactNativeMicrotask})),t?r(d[1]).polyfillGlobal('queueMicrotask',function(){var l;return null==(l=g.HermesInternal)?void 0:l.enqueueJob}):r(d[1]).polyfillGlobal('queueMicrotask',function(){return r(d[4]).default})},482,[481,474,483,485,486]); -__d(function(g,r,_i,a,m,_e,d){var e=r(d[0])(r(d[1])),t=16.666666666666668,n=[],i=[],l=[],o=[],c=[],u={},f=1,s=null,v=!1;function h(){var e=l.indexOf(null);return-1===e&&(e=l.length),e}function T(e,t){var o=f++,c=h();return l[c]=o,n[c]=e,i[c]=t,o}function k(e,o,c){e>f&&console.warn('Tried to call timer with ID %s but no such timer exists.',e);var u=l.indexOf(e);if(-1!==u){var v=i[u],h=n[u];if(h&&v){'setInterval'!==v&&p(u);try{'setTimeout'===v||'setInterval'===v||'queueReactNativeMicrotask'===v?h():'requestAnimationFrame'===v?h(g.performance.now()):'requestIdleCallback'===v?h({timeRemaining:function(){return Math.max(0,t-(g.performance.now()-o))},didTimeout:!!c}):console.error('Tried to call a callback with invalid type: '+v)}catch(e){s?s.push(e):s=[e]}}else console.error('No callback found for timerID '+e)}}function w(){if(0===o.length)return!1;var e=o;o=[];for(var t=0;t0}function p(e){l[e]=null,n[e]=null,i[e]=null}function N(e){if(null!=e){var t=l.indexOf(e);if(-1!==t){var n=i[t];p(t),'queueReactNativeMicrotask'!==n&&'requestIdleCallback'!==n&&M(e)}}}var b,I={setTimeout:function(e,t){for(var n=arguments.length,i=new Array(n>2?n-2:0),l=2;l2?n-2:0),l=2;l1?t-1:0),i=1;i-1&&(c.splice(e,1),k(i,g.performance.now(),!0)),delete u[i],0===c.length&&R(!1)},n);u[i]=l}return i},cancelIdleCallback:function(e){N(e);var t=c.indexOf(e);-1!==t&&c.splice(t,1);var n=u[e];n&&(I.clearTimeout(n),delete u[e]),0===c.length&&R(!1)},clearTimeout:function(e){N(e)},clearInterval:function(e){N(e)},clearReactNativeMicrotask:function(e){N(e);var t=o.indexOf(e);-1!==t&&o.splice(t,1)},cancelAnimationFrame:function(e){N(e)},callTimers:function(e){r(d[2])(0!==e.length,'Cannot call `callTimers` with an empty list of IDs.'),s=null;for(var t=0;t1)for(var i=1;i0){var n=c;c=[];for(var i=0;i1?u-1:0),c=1;c=0,loaded:t,total:s})}},{key:"__didCompleteResponse",value:function(e,t,s){e===this._requestId&&(t&&(''!==this._responseType&&'text'!==this._responseType||(this._response=t),this._hasError=!0,s&&(this._timedOut=!0)),this._clearSubscriptions(),this._requestId=null,this.setReadyState(this.DONE),t?E._interceptor&&E._interceptor.loadingFailed(e,t):E._interceptor&&E._interceptor.loadingFinished(e,this._response.length))}},{key:"_clearSubscriptions",value:function(){(this._subscriptions||[]).forEach(function(e){e&&e.remove()}),this._subscriptions=[]}},{key:"getAllResponseHeaders",value:function(){if(!this.responseHeaders)return null;var e=this.responseHeaders||{};return Object.keys(e).map(function(t){return t+': '+e[t]}).join('\r\n')}},{key:"getResponseHeader",value:function(e){var t=this._lowerCaseResponseHeaders[e.toLowerCase()];return void 0!==t?t:null}},{key:"setRequestHeader",value:function(e,t){if(this.readyState!==this.OPENED)throw new Error('Request has not been opened');this._headers[e.toLowerCase()]=String(t)}},{key:"setTrackingName",value:function(e){return this._trackingName=e,this}},{key:"setPerformanceLogger",value:function(e){return this._performanceLogger=e,this}},{key:"open",value:function(e,t,s){if(this.readyState!==this.UNSENT)throw new Error('Cannot open, already sending');if(void 0!==s&&!s)throw new Error('Synchronous http requests are not supported');if(!t)throw new Error('Cannot load an empty url');this._method=e.toUpperCase(),this._url=t,this._aborted=!1,this.setReadyState(this.OPENED)}},{key:"send",value:function(t){var s=this;if(this.readyState!==this.OPENED)throw new Error('Request has not been opened');if(this._sent)throw new Error('Request has already been sent');this._sent=!0;var n=this._incrementalEvents||!!this.onreadystatechange||!!this.onprogress;this._subscriptions.push(r(d[13]).addListener('didSendNetworkData',function(t){return s.__didUploadProgress.apply(s,(0,e.default)(t))})),this._subscriptions.push(r(d[13]).addListener('didReceiveNetworkResponse',function(t){return s.__didReceiveResponse.apply(s,(0,e.default)(t))})),this._subscriptions.push(r(d[13]).addListener('didReceiveNetworkData',function(t){return s.__didReceiveData.apply(s,(0,e.default)(t))})),this._subscriptions.push(r(d[13]).addListener('didReceiveNetworkIncrementalData',function(t){return s.__didReceiveIncrementalData.apply(s,(0,e.default)(t))})),this._subscriptions.push(r(d[13]).addListener('didReceiveNetworkDataProgress',function(t){return s.__didReceiveDataProgress.apply(s,(0,e.default)(t))})),this._subscriptions.push(r(d[13]).addListener('didCompleteNetworkResponse',function(t){return s.__didCompleteResponse.apply(s,(0,e.default)(t))}));var o='text';'arraybuffer'===this._responseType&&(o='base64'),'blob'===this._responseType&&(o='blob');var h;h='unknown'!==s._trackingName?s._trackingName:s._url,s._perfKey='network_XMLHttpRequest_'+String(h),s._performanceLogger.startTimespan(s._perfKey),r(d[11])(s._method,'XMLHttpRequest method needs to be defined (%s).',h),r(d[11])(s._url,'XMLHttpRequest URL needs to be defined (%s).',h),r(d[13]).sendRequest(s._method,s._trackingName,s._url,s._headers,t,o,n,s.timeout,s.__didCreateRequest.bind(s),s.withCredentials)}},{key:"abort",value:function(){this._aborted=!0,this._requestId&&r(d[13]).abortRequest(this._requestId),this.readyState===this.UNSENT||this.readyState===this.OPENED&&!this._sent||this.readyState===this.DONE||(this._reset(),this.setReadyState(this.DONE)),this._reset()}},{key:"setResponseHeaders",value:function(e){this.responseHeaders=e||null;var t=e||{};this._lowerCaseResponseHeaders=Object.keys(t).reduce(function(e,s){return e[s.toLowerCase()]=t[s],e},{})}},{key:"setReadyState",value:function(e){this.readyState=e,this.dispatchEvent({type:'readystatechange'}),e===this.DONE&&(this._aborted?this.dispatchEvent({type:'abort'}):this._hasError?this._timedOut?this.dispatchEvent({type:'timeout'}):this.dispatchEvent({type:'error'}):this.dispatchEvent({type:'load'}),this.dispatchEvent({type:'loadend'}))}},{key:"addEventListener",value:function(e,s){'readystatechange'!==e&&'progress'!==e||(this._incrementalEvents=!0),(0,t.default)((0,u.default)(E.prototype),"addEventListener",this).call(this,e,s)}}],[{key:"setInterceptor",value:function(e){E._interceptor=e}}]),E})(r(d[9]).apply(void 0,(0,e.default)(b)));N.UNSENT=l,N.OPENED=_,N.HEADERS_RECEIVED=f,N.LOADING=y,N.DONE=v,N._interceptor=null,m.exports=N},488,[407,442,489,403,402,417,419,422,491,495,496,425,498,499]); -__d(function(g,r,i,a,m,e,d){function t(){return"undefined"!=typeof Reflect&&Reflect.get?(m.exports=t=Reflect.get,m.exports.__esModule=!0,m.exports.default=m.exports):(m.exports=t=function(t,o,p){var s=r(d[0])(t,o);if(s){var l=Object.getOwnPropertyDescriptor(s,o);return l.get?l.get.call(arguments.length<3?t:p):l.value}},m.exports.__esModule=!0,m.exports.default=m.exports),t.apply(this,arguments)}m.exports=t,m.exports.__esModule=!0,m.exports.default=m.exports},489,[490]); -__d(function(g,r,i,a,m,e,d){m.exports=function(t,o){for(;!Object.prototype.hasOwnProperty.call(t,o)&&null!==(t=r(d[0])(t)););return t},m.exports.__esModule=!0,m.exports.default=m.exports},490,[422]); -__d(function(g,_r,i,a,m,e,d){var t=_r(d[0])(_r(d[1])),l=_r(d[0])(_r(d[2])),r=_r(d[0])(_r(d[3])),o=_r(d[0])(_r(d[4])),n=_r(d[0])(_r(d[5]));var u=(function(){function u(){(0,l.default)(this,u)}return(0,r.default)(u,null,[{key:"createFromParts",value:function(t,l){(0,n.default)(o.default,'NativeBlobModule is available.');var r='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g,function(t){var l=16*Math.random()|0;return('x'==t?l:3&l|8).toString(16)}),f=t.map(function(t){if(t instanceof ArrayBuffer||g.ArrayBufferView&&t instanceof g.ArrayBufferView)throw new Error("Creating blobs from 'ArrayBuffer' and 'ArrayBufferView' are not supported");return t instanceof _r(d[6])?{data:t.data,type:'blob'}:{data:String(t),type:'string'}}),c=f.reduce(function(t,l){return'string'===l.type?t+g.unescape(encodeURI(l.data)).length:t+l.data.size},0);return o.default.createFromParts(f,r),u.createFromOptions({blobId:r,offset:0,size:c,type:l?l.type:'',lastModified:l?l.lastModified:Date.now()})}},{key:"createFromOptions",value:function(l){return _r(d[7]).register(l.blobId),(0,t.default)(Object.create(_r(d[6]).prototype),{data:null==l.__collector?(0,t.default)({},l,{__collector:(r=l.blobId,null==g.__blobCollectorProvider?null:g.__blobCollectorProvider(r))}):l});var r}},{key:"release",value:function(t){(0,n.default)(o.default,'NativeBlobModule is available.'),_r(d[7]).unregister(t),_r(d[7]).has(t)||o.default.release(t)}},{key:"addNetworkingHandler",value:function(){(0,n.default)(o.default,'NativeBlobModule is available.'),o.default.addNetworkingHandler()}},{key:"addWebSocketHandler",value:function(t){(0,n.default)(o.default,'NativeBlobModule is available.'),o.default.addWebSocketHandler(t)}},{key:"removeWebSocketHandler",value:function(t){(0,n.default)(o.default,'NativeBlobModule is available.'),o.default.removeWebSocketHandler(t)}},{key:"sendOverSocket",value:function(t,l){(0,n.default)(o.default,'NativeBlobModule is available.'),o.default.sendOverSocket(t.data,l)}}]),u})();u.isAvailable=!!o.default,m.exports=u},491,[407,436,402,403,492,425,493,494]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var l={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var f in n)if("default"!==f&&Object.prototype.hasOwnProperty.call(n,f)){var s=c?Object.getOwnPropertyDescriptor(n,f):null;s&&(s.get||s.set)?Object.defineProperty(l,f,s):l[f]=n[f]}l.default=n,u&&u.set(n,l);return l})(r(d[0])).get('BlobModule'),o=null,u=null;null!=n&&(u={getConstants:function(){return null==o&&(o=n.getConstants()),o},addNetworkingHandler:function(){n.addNetworkingHandler()},addWebSocketHandler:function(t){n.addWebSocketHandler(t)},removeWebSocketHandler:function(t){n.removeWebSocketHandler(t)},sendOverSocket:function(t,o){n.sendOverSocket(t,o)},createFromParts:function(t,o){n.createFromParts(t,o)},release:function(t){n.release(t)}});var l=u;e.default=l},492,[428]); -__d(function(g,r,i,a,m,e,d){'use strict';var t=(function(){function t(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],s=arguments.length>1?arguments[1]:void 0;r(d[0])(this,t);var o=r(d[1]);this.data=o.createFromParts(n,s).data}return r(d[2])(t,[{key:"data",get:function(){if(!this._data)throw new Error('Blob has been closed and is no longer available');return this._data},set:function(t){this._data=t}},{key:"slice",value:function(t,n){var s=r(d[1]),o=this.data,u=o.offset,l=o.size;return'number'==typeof t&&(t>l&&(t=l),u+=t,l-=t,'number'==typeof n&&(n<0&&(n=this.size+n),l=n-t)),s.createFromOptions({blobId:this.data.blobId,offset:u,size:l})}},{key:"close",value:function(){r(d[1]).release(this.data.blobId),this.data=null}},{key:"size",get:function(){return this.data.size}},{key:"type",get:function(){return this.data.type||''}}]),t})();m.exports=t},493,[402,491,403]); -__d(function(g,r,i,a,m,e,d){var n={};m.exports={register:function(t){n[t]?n[t]++:n[t]=1},unregister:function(t){n[t]&&(n[t]--,n[t]<=0&&delete n[t])},has:function(t){return n[t]&&n[t]>0}}},494,[]); -__d(function(g,r,_i,a,m,e,d){'use strict';Object.defineProperty(e,'__esModule',{value:!0});var t=new WeakMap,n=new WeakMap;function o(n){var o=t.get(n);return console.assert(null!=o,"'this' is expected an Event object, but got",n),o}function i(t){null==t.passiveListener?t.event.cancelable&&(t.canceled=!0,"function"==typeof t.event.preventDefault&&t.event.preventDefault()):"undefined"!=typeof console&&"function"==typeof console.error&&console.error("Unable to preventDefault inside passive event listener invocation.",t.passiveListener)}function l(n,o){t.set(this,{eventTarget:n,event:o,eventPhase:2,currentTarget:n,canceled:!1,stopped:!1,immediateStopped:!1,passiveListener:null,timeStamp:o.timeStamp||Date.now()}),Object.defineProperty(this,"isTrusted",{value:!1,enumerable:!0});for(var i=Object.keys(o),l=0;l0){for(var t=new Array(arguments.length),n=0;n1&&void 0!==arguments[1]?arguments[1]:l(),n=arguments.length>2?arguments[2]:void 0;this._closed||null==this._points[t]&&(this._points[t]=s,n&&(this._pointExtras[t]=n))}},{key:"removeExtra",value:function(t){var s=this._extras[t];return delete this._extras[t],s}},{key:"setExtra",value:function(t,s){this._closed||this._extras.hasOwnProperty(t)||(this._extras[t]=s)}},{key:"startTimespan",value:function(t){var s=arguments.length>1&&void 0!==arguments[1]?arguments[1]:l(),n=arguments.length>2?arguments[2]:void 0;this._closed||this._timespans[t]||(this._timespans[t]={startTime:s,startExtras:n},u[t]=r(d[4]).beginAsyncEvent(t))}},{key:"stopTimespan",value:function(t){var s=arguments.length>1&&void 0!==arguments[1]?arguments[1]:l(),n=arguments.length>2?arguments[2]:void 0;if(!this._closed){var o=this._timespans[t];o&&null!=o.startTime&&null==o.endTime&&(o.endExtras=n,o.endTime=s,o.totalTime=o.endTime-(o.startTime||0),null!=u[t]&&(r(d[4]).endAsyncEvent(t,u[t]),delete u[t]))}}}]),t})()},497,[407,436,402,403,439]); -__d(function(g,r,_i,a,m,e,d){'use strict';e.byteLength=function(t){var n=i(t),o=n[0],h=n[1];return 3*(o+h)/4-h},e.toByteArray=function(t){var h,u,c=i(t),A=c[0],C=c[1],y=new o(f(t,A,C)),s=0,v=C>0?A-4:A;for(u=0;u>16&255,y[s++]=h>>8&255,y[s++]=255&h;2===C&&(h=n[t.charCodeAt(u)]<<2|n[t.charCodeAt(u+1)]>>4,y[s++]=255&h);1===C&&(h=n[t.charCodeAt(u)]<<10|n[t.charCodeAt(u+1)]<<4|n[t.charCodeAt(u+2)]>>2,y[s++]=h>>8&255,y[s++]=255&h);return y},e.fromByteArray=function(n){for(var o,h=n.length,u=h%3,c=[],i=0,f=h-u;if?f:i+16383));1===u?(o=n[h-1],c.push(t[o>>2]+t[o<<4&63]+'==')):2===u&&(o=(n[h-2]<<8)+n[h-1],c.push(t[o>>10]+t[o>>4&63]+t[o<<2&63]+'='));return c.join('')};for(var t=[],n=[],o='undefined'!=typeof Uint8Array?Uint8Array:Array,h='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',u=0,c=h.length;u0)throw new Error('Invalid string. Length must be a multiple of 4');var o=t.indexOf('=');return-1===o&&(o=n),[o,o===n?0:4-o%4]}function f(t,n,o){return 3*(n+o)/4-o}function A(n,o,h){for(var u,c,i=[],f=o;f>18&63]+t[c>>12&63]+t[c>>6&63]+t[63&c]);return i.join('')}n['-'.charCodeAt(0)]=62,n['_'.charCodeAt(0)]=63},498,[]); -__d(function(g,r,i,a,m,_e,d){var t=r(d[0])(r(d[1])),e=r(d[0])(r(d[2])),u=r(d[0])(r(d[3])),n=r(d[0])(r(d[4])),f=r(d[0])(r(d[5])),o=r(d[0])(r(d[6])),l=r(d[0])(r(d[7])),c=r(d[0])(r(d[8])),s=r(d[0])(r(d[9])),v=r(d[0])(r(d[10]));function h(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}function p(t){var e=[];for(var u in t)e.push([u,t[u]]);return e}var y=1;var R=(function(l){(0,n.default)(D,l);var R,k,q=(R=D,k=h(),function(){var t,e=(0,o.default)(R);if(k){var u=(0,o.default)(this).constructor;t=Reflect.construct(e,arguments,u)}else t=e.apply(this,arguments);return(0,f.default)(this,t)});function D(){return(0,e.default)(this,D),q.call(this,'ios'!==v.default.OS?null:c.default)}return(0,u.default)(D,[{key:"sendRequest",value:function(e,u,n,f,o,l,v,h,R,k){var q=(0,s.default)(o);q&&q.formData&&(q.formData=q.formData.map(function(e){return(0,t.default)({},e,{headers:p(e.headers)})}));var D=y++;c.default.sendRequest(e,n,D,p(f),(0,t.default)({},q,{trackingName:u}),l,v,h,k),R(D)}},{key:"abortRequest",value:function(t){c.default.abortRequest(t)}},{key:"clearCookies",value:function(t){c.default.clearCookies(t)}}]),D})(l.default);m.exports=new R},499,[407,436,402,403,417,419,422,500,501,502,426]); -__d(function(g,r,i,a,m,e,d){'use strict';Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),l=r(d[0])(r(d[3])),u=r(d[0])(r(d[4])),o=r(d[0])(r(d[5])),s=(function(){function s(n){(0,t.default)(this,s),'ios'===l.default.OS&&(0,o.default)(null!=n,'`new NativeEventEmitter()` requires a non-null argument.');var u=!!n&&'function'==typeof n.addListener,v=!!n&&'function'==typeof n.removeListeners;n&&u&&v?this._nativeModule=n:null!=n&&(u||console.warn('`new NativeEventEmitter()` was called with a non-null argument without the required `addListener` method.'),v||console.warn('`new NativeEventEmitter()` was called with a non-null argument without the required `removeListeners` method.'))}return(0,n.default)(s,[{key:"addListener",value:function(t,n,l){var o,s=this;null==(o=this._nativeModule)||o.addListener(t);var v=u.default.addListener(t,n,l);return{remove:function(){var t;null!=v&&(null==(t=s._nativeModule)||t.removeListeners(1),v.remove(),v=null)}}}},{key:"removeListener",value:function(t,n){var l;null==(l=this._nativeModule)||l.removeListeners(1),u.default.removeListener(t,n)}},{key:"emit",value:function(t){for(var n=arguments.length,l=new Array(n>1?n-1:0),o=1;o-1};function s(t){if('string'!=typeof t&&(t=String(t)),/[^a-z0-9\-#$%&'*+.^_`|~!]/i.test(t)||''===t)throw new TypeError('Invalid character in header field name: "'+t+'"');return t.toLowerCase()}function h(t){return'string'!=typeof t&&(t=String(t)),t}function f(t){var e={next:function(){var e=t.shift();return{done:void 0===e,value:e}}};return o.iterable&&(e[Symbol.iterator]=function(){return e}),e}function u(t){this.map={},t instanceof u?t.forEach(function(t,e){this.append(e,t)},this):Array.isArray(t)?t.forEach(function(t){this.append(t[0],t[1])},this):t&&Object.getOwnPropertyNames(t).forEach(function(e){this.append(e,t[e])},this)}function c(t){if(t.bodyUsed)return Promise.reject(new TypeError('Already read'));t.bodyUsed=!0}function y(t){return new Promise(function(e,o){t.onload=function(){e(t.result)},t.onerror=function(){o(t.error)}})}function l(t){var e=new FileReader,o=y(e);return e.readAsArrayBuffer(t),o}function p(t){for(var e=new Uint8Array(t),o=new Array(e.length),n=0;n-1?n:o),this.mode=e.mode||this.mode||null,this.signal=e.signal||this.signal,this.referrer=null,('GET'===this.method||'HEAD'===this.method)&&i)throw new TypeError('Body not allowed for GET or HEAD requests');if(this._initBody(i),!('GET'!==this.method&&'HEAD'!==this.method||'no-store'!==e.cache&&'no-cache'!==e.cache)){var s=/([?&])_=[^&]*/;if(s.test(this.url))this.url=this.url.replace(s,'$1_='+(new Date).getTime());else{this.url+=(/\?/.test(this.url)?'&':'?')+'_='+(new Date).getTime()}}}function E(t){var e=new FormData;return t.trim().split('&').forEach(function(t){if(t){var o=t.split('='),n=o.shift().replace(/\+/g,' '),i=o.join('=').replace(/\+/g,' ');e.append(decodeURIComponent(n),decodeURIComponent(i))}}),e}function T(t,e){if(!(this instanceof T))throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');e||(e={}),this.type='default',this.status=void 0===e.status?200:e.status,this.ok=this.status>=200&&this.status<300,this.statusText=void 0===e.statusText?'':''+e.statusText,this.headers=new u(e.headers),this.url=e.url||'',this._initBody(t)}_.prototype.clone=function(){return new _(this,{body:this._bodyInit})},w.call(_.prototype),w.call(T.prototype),T.prototype.clone=function(){return new T(this._bodyInit,{status:this.status,statusText:this.statusText,headers:new u(this.headers),url:this.url})},T.error=function(){var t=new T(null,{status:0,statusText:''});return t.type='error',t};var A=[301,302,303,307,308];T.redirect=function(t,e){if(-1===A.indexOf(e))throw new RangeError('Invalid status code');return new T(null,{status:e,headers:{location:t}})},t.DOMException=e.DOMException;try{new t.DOMException}catch(e){t.DOMException=function(t,e){this.message=t,this.name=e;var o=Error(t);this.stack=o.stack},t.DOMException.prototype=Object.create(Error.prototype),t.DOMException.prototype.constructor=t.DOMException}function B(n,i){return new Promise(function(s,f){var c=new _(n,i);if(c.signal&&c.signal.aborted)return f(new t.DOMException('Aborted','AbortError'));var y=new XMLHttpRequest;function l(){y.abort()}y.onload=function(){var t,e,o={status:y.status,statusText:y.statusText,headers:(t=y.getAllResponseHeaders()||'',e=new u,t.replace(/\r?\n[\t ]+/g,' ').split('\r').map(function(t){return 0===t.indexOf('\n')?t.substr(1,t.length):t}).forEach(function(t){var o=t.split(':'),n=o.shift().trim();if(n){var i=o.join(':').trim();e.append(n,i)}}),e)};o.url='responseURL'in y?y.responseURL:o.headers.get('X-Request-URL');var n='response'in y?y.response:y.responseText;setTimeout(function(){s(new T(n,o))},0)},y.onerror=function(){setTimeout(function(){f(new TypeError('Network request failed'))},0)},y.ontimeout=function(){setTimeout(function(){f(new TypeError('Network request failed'))},0)},y.onabort=function(){setTimeout(function(){f(new t.DOMException('Aborted','AbortError'))},0)},y.open(c.method,(function(t){try{return''===t&&e.location.href?e.location.href:t}catch(e){return t}})(c.url),!0),'include'===c.credentials?y.withCredentials=!0:'omit'===c.credentials&&(y.withCredentials=!1),'responseType'in y&&(o.blob?y.responseType='blob':o.arrayBuffer&&c.headers.get('Content-Type')&&-1!==c.headers.get('Content-Type').indexOf('application/octet-stream')&&(y.responseType='arraybuffer')),!i||'object'!=typeof i.headers||i.headers instanceof u?c.headers.forEach(function(t,e){y.setRequestHeader(e,t)}):Object.getOwnPropertyNames(i.headers).forEach(function(t){y.setRequestHeader(t,h(i.headers[t]))}),c.signal&&(c.signal.addEventListener('abort',l),y.onreadystatechange=function(){4===y.readyState&&c.signal.removeEventListener('abort',l)}),y.send(void 0===c._bodyInit?null:c._bodyInit)})}B.polyfill=!0,e.fetch||(e.fetch=B,e.Headers=u,e.Request=_,e.Response=T),t.Headers=u,t.Request=_,t.Response=T,t.fetch=B,Object.defineProperty(t,'__esModule',{value:!0})},'object'==typeof _e&&void 0!==m?e(_e):'function'==typeof define&&define.amd?define(['exports'],e):e(t.WHATWGFetch={})},506,[]); -__d(function(g,r,i,a,m,_e,d){var e=r(d[0])(r(d[1])),t=r(d[0])(r(d[2])),n=r(d[0])(r(d[3])),s=r(d[0])(r(d[4])),o=r(d[0])(r(d[5])),u=r(d[0])(r(d[6])),c=r(d[0])(r(d[7])),l=r(d[0])(r(d[8])),f=r(d[0])(r(d[9])),h=r(d[0])(r(d[10])),y=r(d[0])(r(d[11])),b=r(d[0])(r(d[12])),p=r(d[0])(r(d[13])),v=r(d[0])(r(d[14])),_=r(d[0])(r(d[15])),E=r(d[0])(r(d[16])),k=["headers"];function S(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}var I=0,N=1,O=2,w=3,C=0,L=(function(_){(0,s.default)(R,_);var L,T,A=(L=R,T=S(),function(){var e,t=(0,u.default)(L);if(T){var n=(0,u.default)(this).constructor;e=Reflect.construct(t,arguments,n)}else e=t.apply(this,arguments);return(0,o.default)(this,e)});function R(n,s,o){var u;(0,t.default)(this,R),(u=A.call(this)).CONNECTING=I,u.OPEN=N,u.CLOSING=O,u.CLOSED=w,u.readyState=I,u.url=n,'string'==typeof s&&(s=[s]);var c=o||{},l=c.headers,h=void 0===l?{}:l,p=(0,e.default)(c,k);return p&&'string'==typeof p.origin&&(console.warn('Specifying `origin` as a WebSocket connection option is deprecated. Include it under `headers` instead.'),h.origin=p.origin,delete p.origin),Object.keys(p).length>0&&console.warn('Unrecognized WebSocket connection option(s) `'+Object.keys(p).join('`, `')+"`. Did you mean to put these under `headers`?"),Array.isArray(s)||(s=null),u._eventEmitter=new f.default('ios'!==y.default.OS?null:b.default),u._socketId=C++,u._registerEvents(),b.default.connect(n,s,{headers:h},u._socketId),u}return(0,n.default)(R,[{key:"binaryType",get:function(){return this._binaryType},set:function(e){if('blob'!==e&&'arraybuffer'!==e)throw new Error("binaryType must be either 'blob' or 'arraybuffer'");'blob'!==this._binaryType&&'blob'!==e||((0,E.default)(l.default.isAvailable,'Native module BlobModule is required for blob support'),'blob'===e?l.default.addWebSocketHandler(this._socketId):l.default.removeWebSocketHandler(this._socketId)),this._binaryType=e}},{key:"close",value:function(e,t){this.readyState!==this.CLOSING&&this.readyState!==this.CLOSED&&(this.readyState=this.CLOSING,this._close(e,t))}},{key:"send",value:function(e){if(this.readyState===this.CONNECTING)throw new Error('INVALID_STATE_ERR');if(e instanceof c.default)return(0,E.default)(l.default.isAvailable,'Native module BlobModule is required for blob support'),void l.default.sendOverSocket(e,this._socketId);if('string'!=typeof e){if(!(e instanceof ArrayBuffer||ArrayBuffer.isView(e)))throw new Error('Unsupported data type');b.default.sendBinary((0,h.default)(e),this._socketId)}else b.default.send(e,this._socketId)}},{key:"ping",value:function(){if(this.readyState===this.CONNECTING)throw new Error('INVALID_STATE_ERR');b.default.ping(this._socketId)}},{key:"_close",value:function(e,t){var n='number'==typeof e?e:1e3,s='string'==typeof t?t:'';b.default.close(n,s,this._socketId),l.default.isAvailable&&'blob'===this._binaryType&&l.default.removeWebSocketHandler(this._socketId)}},{key:"_unregisterEvents",value:function(){this._subscriptions.forEach(function(e){return e.remove()}),this._subscriptions=[]}},{key:"_registerEvents",value:function(){var e=this;this._subscriptions=[this._eventEmitter.addListener('websocketMessage',function(t){if(t.id===e._socketId){var n=t.data;switch(t.type){case'binary':n=v.default.toByteArray(t.data).buffer;break;case'blob':n=l.default.createFromOptions(t.data)}e.dispatchEvent(new p.default('message',{data:n}))}}),this._eventEmitter.addListener('websocketOpen',function(t){t.id===e._socketId&&(e.readyState=e.OPEN,e.protocol=t.protocol,e.dispatchEvent(new p.default('open')))}),this._eventEmitter.addListener('websocketClosed',function(t){t.id===e._socketId&&(e.readyState=e.CLOSED,e.dispatchEvent(new p.default('close',{code:t.code,reason:t.reason})),e._unregisterEvents(),e.close())}),this._eventEmitter.addListener('websocketFailed',function(t){t.id===e._socketId&&(e.readyState=e.CLOSED,e.dispatchEvent(new p.default('error',{message:t.message})),e.dispatchEvent(new p.default('close',{message:t.message})),e._unregisterEvents(),e.close())})]}}]),R})(_.default.apply(void 0,['close','error','message','open']));L.CONNECTING=I,L.OPEN=N,L.CLOSING=O,L.CLOSED=w,m.exports=L},507,[407,508,402,403,417,419,422,493,491,500,504,426,510,511,498,495,425]); -__d(function(g,r,_i,a,m,e,d){m.exports=function(t,o){if(null==t)return{};var n,l,p=r(d[0])(t,o);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(t);for(l=0;l=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(p[n]=t[n])}return p},m.exports.__esModule=!0,m.exports.default=m.exports},508,[509]); -__d(function(g,r,_i,a,m,e,d){m.exports=function(t,n){if(null==t)return{};var o,u,f={},s=Object.keys(t);for(u=0;u=0||(f[o]=t[o]);return f},m.exports.__esModule=!0,m.exports.default=m.exports},509,[]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in n)if("default"!==l&&Object.prototype.hasOwnProperty.call(n,l)){var p=c?Object.getOwnPropertyDescriptor(n,l):null;p&&(p.get||p.set)?Object.defineProperty(f,l,p):f[l]=n[l]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).getEnforcing('WebSocketModule');e.default=n},510,[428]); -__d(function(g,r,i,a,m,e,d){'use strict';var t=r(d[0])(function t(s,n){r(d[1])(this,t),this.type=s.toString(),r(d[2])(this,n)});m.exports=t},511,[403,402,436]); -__d(function(g,r,i,a,m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var e=(function(e){r(d[2])(o,e);var n,u,c=(n=o,u=t(),function(){var t,e=r(d[0])(n);if(u){var c=r(d[0])(this).constructor;t=Reflect.construct(e,arguments,c)}else t=e.apply(this,arguments);return r(d[1])(this,t)});function o(t,e,n){var u;return r(d[3])(this,o),r(d[4])(null!=t&&null!=e,'Failed to construct `File`: Must pass both `parts` and `name` arguments.'),(u=c.call(this,t,n)).data.name=e,u}return r(d[5])(o,[{key:"name",get:function(){return r(d[4])(null!=this.data.name,'Files must have a name set.'),this.data.name}},{key:"lastModified",get:function(){return this.data.lastModified||0}}]),o})(r(d[6]));m.exports=e},512,[422,419,417,402,425,403,493]); -__d(function(g,r,i,a,m,_e,d){var t=r(d[0])(r(d[1])),e=r(d[0])(r(d[2])),n=r(d[0])(r(d[3])),o=r(d[0])(r(d[4])),s=r(d[0])(r(d[5])),u=r(d[0])(r(d[6]));function l(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var c=0,f=1,h=2,y=(function(y){(0,n.default)(b,y);var _,p,v=(_=b,p=l(),function(){var t,e=(0,s.default)(_);if(p){var n=(0,s.default)(this).constructor;t=Reflect.construct(e,arguments,n)}else t=e.apply(this,arguments);return(0,o.default)(this,t)});function b(){var e;return(0,t.default)(this,b),(e=v.call(this)).EMPTY=c,e.LOADING=f,e.DONE=h,e._aborted=!1,e._subscriptions=[],e._reset(),e}return(0,e.default)(b,[{key:"_reset",value:function(){this._readyState=c,this._error=null,this._result=null}},{key:"_clearSubscriptions",value:function(){this._subscriptions.forEach(function(t){return t.remove()}),this._subscriptions=[]}},{key:"_setReadyState",value:function(t){this._readyState=t,this.dispatchEvent({type:'readystatechange'}),t===h&&(this._aborted?this.dispatchEvent({type:'abort'}):this._error?this.dispatchEvent({type:'error'}):this.dispatchEvent({type:'load'}),this.dispatchEvent({type:'loadend'}))}},{key:"readAsArrayBuffer",value:function(){throw new Error('FileReader.readAsArrayBuffer is not implemented')}},{key:"readAsDataURL",value:function(t){var e=this;if(this._aborted=!1,null==t)throw new TypeError("Failed to execute 'readAsDataURL' on 'FileReader': parameter 1 is not of type 'Blob'");u.default.readAsDataURL(t.data).then(function(t){e._aborted||(e._result=t,e._setReadyState(h))},function(t){e._aborted||(e._error=t,e._setReadyState(h))})}},{key:"readAsText",value:function(t){var e=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:'UTF-8';if(this._aborted=!1,null==t)throw new TypeError("Failed to execute 'readAsText' on 'FileReader': parameter 1 is not of type 'Blob'");u.default.readAsText(t.data,n).then(function(t){e._aborted||(e._result=t,e._setReadyState(h))},function(t){e._aborted||(e._error=t,e._setReadyState(h))})}},{key:"abort",value:function(){this._aborted=!0,this._readyState!==c&&this._readyState!==h&&(this._reset(),this._setReadyState(h)),this._reset()}},{key:"readyState",get:function(){return this._readyState}},{key:"error",get:function(){return this._error}},{key:"result",get:function(){return this._result}}]),b})(r(d[7]).apply(void 0,['abort','error','load','loadstart','loadend','progress']));y.EMPTY=c,y.LOADING=f,y.DONE=h,m.exports=y},513,[407,402,403,417,419,422,514,495]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in n)if("default"!==c&&Object.prototype.hasOwnProperty.call(n,c)){var p=l?Object.getOwnPropertyDescriptor(n,c):null;p&&(p.get||p.set)?Object.defineProperty(f,c,p):f[c]=n[c]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).getEnforcing('FileReaderModule');e.default=n},514,[428]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.URLSearchParams=e.URL=void 0;var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),o=r(d[0])(r(d[3])),s=null;if(o.default&&'string'==typeof o.default.getConstants().BLOB_URI_SCHEME){var u=o.default.getConstants();s=u.BLOB_URI_SCHEME+':','string'==typeof u.BLOB_URI_HOST&&(s+="//"+u.BLOB_URI_HOST+"/")}var h=(function(o){function s(n){var o=this;(0,t.default)(this,s),this._searchParams=[],'object'==typeof n&&Object.keys(n).forEach(function(t){return o.append(t,n[t])})}return(0,n.default)(s,[{key:"append",value:function(t,n){this._searchParams.push([t,n])}},{key:"delete",value:function(t){throw new Error('URLSearchParams.delete is not implemented')}},{key:"get",value:function(t){throw new Error('URLSearchParams.get is not implemented')}},{key:"getAll",value:function(t){throw new Error('URLSearchParams.getAll is not implemented')}},{key:"has",value:function(t){throw new Error('URLSearchParams.has is not implemented')}},{key:"set",value:function(t,n){throw new Error('URLSearchParams.set is not implemented')}},{key:"sort",value:function(){throw new Error('URLSearchParams.sort is not implemented')}},{key:o,value:function(){return this._searchParams[Symbol.iterator]()}},{key:"toString",value:function(){if(0===this._searchParams.length)return'';var t=this._searchParams.length-1;return this._searchParams.reduce(function(n,o,s){return n+o.join('=')+(s===t?'':'&')},'')}}]),s})(Symbol.iterator);function f(t){return/^(?:(?:(?:https?|ftp):)?\/\/)(?:(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z0-9\u00a1-\uffff][a-z0-9\u00a1-\uffff_-]{0,62})?[a-z0-9\u00a1-\uffff]\.)*(?:[a-z\u00a1-\uffff]{2,}\.?))(?::\d{2,5})?(?:[/?#]\S*)?$/.test(t)}e.URLSearchParams=h;var l=(function(){function o(n,s){(0,t.default)(this,o),this._searchParamsInstance=null;var u=null;if(!s||f(n))this._url=n,this._url.endsWith('/')||(this._url+='/');else{if('string'==typeof s){if(!f(u=s))throw new TypeError("Invalid base URL: "+u)}else'object'==typeof s&&(u=s.toString());u.endsWith('/')&&(u=u.slice(0,u.length-1)),n.startsWith('/')||(n="/"+n),u.endsWith(n)&&(n=''),this._url=""+u+n}}return(0,n.default)(o,[{key:"hash",get:function(){throw new Error('URL.hash is not implemented')}},{key:"host",get:function(){throw new Error('URL.host is not implemented')}},{key:"hostname",get:function(){throw new Error('URL.hostname is not implemented')}},{key:"href",get:function(){return this.toString()}},{key:"origin",get:function(){throw new Error('URL.origin is not implemented')}},{key:"password",get:function(){throw new Error('URL.password is not implemented')}},{key:"pathname",get:function(){throw new Error('URL.pathname not implemented')}},{key:"port",get:function(){throw new Error('URL.port is not implemented')}},{key:"protocol",get:function(){throw new Error('URL.protocol is not implemented')}},{key:"search",get:function(){throw new Error('URL.search is not implemented')}},{key:"searchParams",get:function(){return null==this._searchParamsInstance&&(this._searchParamsInstance=new h),this._searchParamsInstance}},{key:"toJSON",value:function(){return this.toString()}},{key:"toString",value:function(){if(null===this._searchParamsInstance)return this._url;var t=this._url.indexOf('?')>-1?'&':'?';return this._url+t+this._searchParamsInstance.toString()}},{key:"username",get:function(){throw new Error('URL.username is not implemented')}}],[{key:"createObjectURL",value:function(t){if(null===s)throw new Error('Cannot create URL for blob!');return""+s+t.data.blobId+"?offset="+t.data.offset+"&size="+t.size}},{key:"revokeObjectURL",value:function(t){}}]),o})();e.URL=l},515,[407,402,403,492]); -__d(function(g,r,i,a,m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}Object.defineProperty(_e,'__esModule',{value:!0});var e=(function(e){r(d[2])(c,e);var n,l,u=(n=c,l=t(),function(){var t,e=r(d[0])(n);if(l){var o=r(d[0])(this).constructor;t=Reflect.construct(e,arguments,o)}else t=e.apply(this,arguments);return r(d[1])(this,t)});function c(){throw r(d[3])(this,c),u.call(this),new TypeError("AbortSignal cannot be constructed directly")}return r(d[4])(c,[{key:"aborted",get:function(){var t=o.get(this);if("boolean"!=typeof t)throw new TypeError("Expected 'this' to be an 'AbortSignal' object, but got "+(null===this?"null":typeof this));return t}}]),c})(r(d[5]).EventTarget);r(d[5]).defineEventAttribute(e.prototype,"abort");var o=new WeakMap;Object.defineProperties(e.prototype,{aborted:{enumerable:!0}}),"function"==typeof Symbol&&"symbol"==typeof Symbol.toStringTag&&Object.defineProperty(e.prototype,Symbol.toStringTag,{configurable:!0,value:"AbortSignal"});var n=(function(){function t(){var n;r(d[3])(this,t),l.set(this,(n=Object.create(e.prototype),r(d[5]).EventTarget.call(n),o.set(n,!1),n))}return r(d[4])(t,[{key:"signal",get:function(){return u(this)}},{key:"abort",value:function(){var t;t=u(this),!1===o.get(t)&&(o.set(t,!0),t.dispatchEvent({type:"abort"}))}}]),t})(),l=new WeakMap;function u(t){var e=l.get(t);if(null==e)throw new TypeError("Expected 'this' to be an 'AbortController' object, but got "+(null===t?"null":typeof t));return e}Object.defineProperties(n.prototype,{signal:{enumerable:!0},abort:{enumerable:!0}}),"function"==typeof Symbol&&"symbol"==typeof Symbol.toStringTag&&Object.defineProperty(n.prototype,Symbol.toStringTag,{configurable:!0,value:"AbortController"}),_e.AbortController=n,_e.AbortSignal=e,_e.default=n,m.exports=n,m.exports.AbortController=m.exports.default=n,m.exports.AbortSignal=e},516,[422,419,417,402,403,495]); -__d(function(g,r,i,a,m,e,d){'use strict';g.alert||(g.alert=function(t){r(d[0]).alert('Alert',''+t)})},517,[518]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),o=r(d[0])(r(d[3])),s=r(d[0])(r(d[4])),l=(function(){function l(){(0,t.default)(this,l)}return(0,n.default)(l,null,[{key:"alert",value:function(t,n,s,u){if('ios'===o.default.OS)l.prompt(t,n,s,'default');else if('android'===o.default.OS){var c=r(d[5]).default;if(!c)return;var f=c.getConstants(),v={title:t||'',message:n||'',cancelable:!1};u&&u.cancelable&&(v.cancelable=u.cancelable);var p=s?s.slice(0,3):[{text:"OK"}],b=p.pop(),y=p.pop(),h=p.pop();h&&(v.buttonNeutral=h.text||''),y&&(v.buttonNegative=y.text||''),b&&(v.buttonPositive=b.text||"OK");c.showAlert(v,function(t){return console.warn(t)},function(t,n){t===f.buttonClicked?n===f.buttonNeutral?h.onPress&&h.onPress():n===f.buttonNegative?y.onPress&&y.onPress():n===f.buttonPositive&&b.onPress&&b.onPress():t===f.dismissed&&u&&u.onDismiss&&u.onDismiss()})}}},{key:"prompt",value:function(t,n,l){var u=arguments.length>3&&void 0!==arguments[3]?arguments[3]:'plain-text',c=arguments.length>4?arguments[4]:void 0,f=arguments.length>5?arguments[5]:void 0;if('ios'===o.default.OS){var v,p,b=[],y=[];'function'==typeof l?b=[l]:Array.isArray(l)&&l.forEach(function(t,n){if(b[n]=t.onPress,'cancel'===t.style?v=String(n):'destructive'===t.style&&(p=String(n)),t.text||n<(l||[]).length-1){var o={};o[n]=t.text||'',y.push(o)}}),s.default.alertWithArgs({title:t||'',message:n||void 0,buttons:y,type:u||void 0,defaultValue:c,cancelButtonKey:v,destructiveButtonKey:p,keyboardType:f},function(t,n){var o=b[t];o&&o(n)})}}}]),l})();m.exports=l},518,[407,402,403,426,519,520]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1]));function n(){}m.exports={alertWithArgs:function(f,o){t.default&&t.default.showAlert(f,n,o||n)}}},519,[407,520]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in n)if("default"!==c&&Object.prototype.hasOwnProperty.call(n,c)){var p=l?Object.getOwnPropertyDescriptor(n,c):null;p&&(p.get||p.set)?Object.defineProperty(f,c,p):f[c]=n[c]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).get('DialogManagerAndroid');e.default=n},520,[428]); -__d(function(g,r,i,a,m,e,d){'use strict';var t=g.navigator;void 0===t&&(g.navigator=t={}),r(d[0]).polyfillObjectProperty(t,'product',function(){return'ReactNative'})},521,[474]); -__d(function(g,r,i,a,m,e,d){'use strict';var n;if(g.RN$Bridgeless&&g.RN$registerCallableModule)n=g.RN$registerCallableModule;else{var t=r(d[0]);n=function(n,u){return t.registerLazyCallableModule(n,u)}}n('Systrace',function(){return r(d[1])}),n('JSTimers',function(){return r(d[2])}),n('HeapCapture',function(){return r(d[3])}),n('SamplingProfiler',function(){return r(d[4])}),n('RCTLog',function(){return r(d[5])}),n('RCTDeviceEventEmitter',function(){return r(d[6]).default}),n('RCTNativeAppEventEmitter',function(){return r(d[7])}),n('GlobalPerformanceLogger',function(){return r(d[8])}),n('JSDevSupportModule',function(){return r(d[9])}),n('HMRClient',function(){return r(d[10])})},522,[437,439,483,523,525,527,413,528,496,529,531]); -__d(function(g,r,i,a,m,_e,d){var e=r(d[0])(r(d[1])),t={captureHeap:function(t){var p=null;try{g.nativeCaptureHeap(t),console.log('HeapCapture.captureHeap succeeded: '+t)}catch(e){console.log('HeapCapture.captureHeap error: '+e.toString()),p=e.toString()}e.default&&e.default.captureComplete(t,p)}};m.exports=t},523,[407,524]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var u=new WeakMap,o=new WeakMap;return(t=function(t){return t?o:u})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,u){if(!u&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var o=t(u);if(o&&o.has(n))return o.get(n);var f={},p=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in n)if("default"!==c&&Object.prototype.hasOwnProperty.call(n,c)){var l=p?Object.getOwnPropertyDescriptor(n,c):null;l&&(l.get||l.set)?Object.defineProperty(f,c,l):f[c]=n[c]}f.default=n,o&&o.set(n,f);return f})(r(d[0])).get('JSCHeapCapture');e.default=n},524,[428]); -__d(function(g,r,i,a,m,_e,d){'use strict';var o={poke:function(o){var e=null,l=null;try{null===(l=g.pokeSamplingProfiler())?console.log('The JSC Sampling Profiler has started'):console.log('The JSC Sampling Profiler has stopped')}catch(o){console.log('Error occurred when restarting Sampling Profiler: '+o.toString()),e=o.toString()}var n=r(d[0]).default;n&&n.operationComplete(o,l,e)}};m.exports=o},525,[526]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,f=new WeakMap;return(t=function(t){return t?f:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var f=t(o);if(f&&f.has(n))return f.get(n);var u={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var p in n)if("default"!==p&&Object.prototype.hasOwnProperty.call(n,p)){var c=l?Object.getOwnPropertyDescriptor(n,p):null;c&&(c.get||c.set)?Object.defineProperty(u,p,c):u[p]=n[p]}u.default=n,f&&f.set(n,u);return u})(r(d[0])).get('JSCSamplingProfiler');e.default=n},526,[428]); -__d(function(g,r,i,a,m,e,d){'use strict';var o={log:'log',info:'info',warn:'warn',error:'error',fatal:'error'},n=null,l={logIfNoNativeHook:function(o){for(var t=arguments.length,f=new Array(t>1?t-1:0),c=1;c1?f-1:0),v=1;v1?t-1:0),f=1;f>>8)>>>0,t|=0)}}},546,[547,549]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1]));m.exports=function(n){if('object'==typeof n&&null!=n&&null!=(0,r(d[2]).normalizeColorObject)(n))return n;if('string'==typeof n||'number'==typeof n)return(0,t.default)(n)}},547,[407,548,549]); -__d(function(_g,_r,i,a,m,e,d){'use strict';function r(r,l,n){return n<0&&(n+=1),n>1&&(n-=1),n<.16666666666666666?r+6*(l-r)*n:n<.5?l:n<.6666666666666666?r+(l-r)*(.6666666666666666-n)*6:r}function l(l,n,t){var o=t<.5?t*(1+n):t+n-t*n,u=2*t-o,g=r(u,o,l+.3333333333333333),s=r(u,o,l),h=r(u,o,l-.3333333333333333);return Math.round(255*g)<<24|Math.round(255*s)<<16|Math.round(255*h)<<8}var n,t='[-+]?\\d*\\.?\\d+',o="[-+]?\\d*\\.?\\d+%";function u(){for(var r=arguments.length,l=new Array(r),n=0;n255?255:l}function s(r){return(parseFloat(r)%360+360)%360/360}function h(r){var l=parseFloat(r);return l<0?0:l>1?255:Math.round(255*l)}function c(r){var l=parseFloat(r);return l<0?0:l>100?1:l/100}var p={transparent:0,aliceblue:4042850303,antiquewhite:4209760255,aqua:16777215,aquamarine:2147472639,azure:4043309055,beige:4126530815,bisque:4293182719,black:255,blanchedalmond:4293643775,blue:65535,blueviolet:2318131967,brown:2771004159,burlywood:3736635391,burntsienna:3934150143,cadetblue:1604231423,chartreuse:2147418367,chocolate:3530104575,coral:4286533887,cornflowerblue:1687547391,cornsilk:4294499583,crimson:3692313855,cyan:16777215,darkblue:35839,darkcyan:9145343,darkgoldenrod:3095792639,darkgray:2846468607,darkgreen:6553855,darkgrey:2846468607,darkkhaki:3182914559,darkmagenta:2332068863,darkolivegreen:1433087999,darkorange:4287365375,darkorchid:2570243327,darkred:2332033279,darksalmon:3918953215,darkseagreen:2411499519,darkslateblue:1211993087,darkslategray:793726975,darkslategrey:793726975,darkturquoise:13554175,darkviolet:2483082239,deeppink:4279538687,deepskyblue:12582911,dimgray:1768516095,dimgrey:1768516095,dodgerblue:512819199,firebrick:2988581631,floralwhite:4294635775,forestgreen:579543807,fuchsia:4278255615,gainsboro:3705462015,ghostwhite:4177068031,gold:4292280575,goldenrod:3668254975,gray:2155905279,green:8388863,greenyellow:2919182335,grey:2155905279,honeydew:4043305215,hotpink:4285117695,indianred:3445382399,indigo:1258324735,ivory:4294963455,khaki:4041641215,lavender:3873897215,lavenderblush:4293981695,lawngreen:2096890111,lemonchiffon:4294626815,lightblue:2916673279,lightcoral:4034953471,lightcyan:3774873599,lightgoldenrodyellow:4210742015,lightgray:3553874943,lightgreen:2431553791,lightgrey:3553874943,lightpink:4290167295,lightsalmon:4288707327,lightseagreen:548580095,lightskyblue:2278488831,lightslategray:2005441023,lightslategrey:2005441023,lightsteelblue:2965692159,lightyellow:4294959359,lime:16711935,limegreen:852308735,linen:4210091775,magenta:4278255615,maroon:2147483903,mediumaquamarine:1724754687,mediumblue:52735,mediumorchid:3126187007,mediumpurple:2473647103,mediumseagreen:1018393087,mediumslateblue:2070474495,mediumspringgreen:16423679,mediumturquoise:1221709055,mediumvioletred:3340076543,midnightblue:421097727,mintcream:4127193855,mistyrose:4293190143,moccasin:4293178879,navajowhite:4292783615,navy:33023,oldlace:4260751103,olive:2155872511,olivedrab:1804477439,orange:4289003775,orangered:4282712319,orchid:3664828159,palegoldenrod:4008225535,palegreen:2566625535,paleturquoise:2951671551,palevioletred:3681588223,papayawhip:4293907967,peachpuff:4292524543,peru:3448061951,pink:4290825215,plum:3718307327,powderblue:2967529215,purple:2147516671,rebeccapurple:1714657791,red:4278190335,rosybrown:3163525119,royalblue:1097458175,saddlebrown:2336560127,salmon:4202722047,sandybrown:4104413439,seagreen:780883967,seashell:4294307583,sienna:2689740287,silver:3233857791,skyblue:2278484991,slateblue:1784335871,slategray:1887473919,slategrey:1887473919,snow:4294638335,springgreen:16744447,steelblue:1182971135,tan:3535047935,teal:8421631,thistle:3636451583,tomato:4284696575,turquoise:1088475391,violet:4001558271,wheat:4125012991,white:4294967295,whitesmoke:4126537215,yellow:4294902015,yellowgreen:2597139199};m.exports=function(r){var b,y=(void 0===n&&(n={rgb:new RegExp('rgb'+u(t,t,t)),rgba:new RegExp('rgba'+u(t,t,t,t)),hsl:new RegExp('hsl'+u(t,o,o)),hsla:new RegExp('hsla'+u(t,o,o,t)),hex3:/^#([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,hex4:/^#([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,hex6:/^#([0-9a-fA-F]{6})$/,hex8:/^#([0-9a-fA-F]{8})$/}),n);return'number'==typeof r?r>>>0===r&&r>=0&&r<=4294967295?r:null:'string'!=typeof r?null:(b=y.hex6.exec(r))?parseInt(b[1]+'ff',16)>>>0:p.hasOwnProperty(r)?p[r]:(b=y.rgb.exec(r))?(g(b[1])<<24|g(b[2])<<16|g(b[3])<<8|255)>>>0:(b=y.rgba.exec(r))?(g(b[1])<<24|g(b[2])<<16|g(b[3])<<8|h(b[4]))>>>0:(b=y.hex3.exec(r))?parseInt(b[1]+b[1]+b[2]+b[2]+b[3]+b[3]+'ff',16)>>>0:(b=y.hex8.exec(r))?parseInt(b[1],16)>>>0:(b=y.hex4.exec(r))?parseInt(b[1]+b[1]+b[2]+b[2]+b[3]+b[3]+b[4]+b[4],16)>>>0:(b=y.hsl.exec(r))?(255|l(s(b[1]),c(b[2]),c(b[3])))>>>0:(b=y.hsla.exec(r))?(l(s(b[1]),c(b[2]),c(b[3]))|h(b[4]))>>>0:null}},548,[]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.processColorObject=e.normalizeColorObject=e.PlatformColor=void 0;e.PlatformColor=function(){for(var o=arguments.length,n=new Array(o),t=0;t.49999*l?[0,2*Math.atan2(u,m)*C,90]:M<-.49999*l?[0,-2*Math.atan2(u,m)*C,-90]:[t.roundTo3Places(Math.atan2(2*u*m-2*s*c,1-2*v-2*h)*C),t.roundTo3Places(Math.atan2(2*s*m-2*u*c,1-2*f-2*h)*C),t.roundTo3Places(Math.asin(2*u*s+2*c*m)*C)]},roundTo3Places:function(t){var n=t.toString().split('e');return.001*Math.round(n[0]+'e'+(n[1]?+n[1]-3:3))},decomposeMatrix:function(n){r(d[1])(16===n.length,'Matrix decomposition needs a list of 3d matrix values, received %s',n);var a=[],o=[],i=[],u=[],s=[];if(n[15]){for(var c=[],m=[],v=0;v<4;v++){c.push([]);for(var f=0;f<4;f++){var h=n[4*v+f]/n[15];c[v].push(h),m.push(3===f?0:h)}}if(m[15]=1,t.determinant(m)){if(0!==c[0][3]||0!==c[1][3]||0!==c[2][3]){var M=[c[0][3],c[1][3],c[2][3],c[3][3]],l=t.inverse(m),C=t.transpose(l);a=t.multiplyVectorByMatrix(M,C)}else a[0]=a[1]=a[2]=0,a[3]=1;for(var p=0;p<3;p++)s[p]=c[3][p];for(var x=[],T=0;T<3;T++)x[T]=[c[T][0],c[T][1],c[T][2]];i[0]=t.v3Length(x[0]),x[0]=t.v3Normalize(x[0],i[0]),u[0]=t.v3Dot(x[0],x[1]),x[1]=t.v3Combine(x[1],x[0],1,-u[0]),i[1]=t.v3Length(x[1]),x[1]=t.v3Normalize(x[1],i[1]),u[0]/=i[1],u[1]=t.v3Dot(x[0],x[2]),x[2]=t.v3Combine(x[2],x[0],1,-u[1]),u[2]=t.v3Dot(x[1],x[2]),x[2]=t.v3Combine(x[2],x[1],1,-u[2]),i[2]=t.v3Length(x[2]),x[2]=t.v3Normalize(x[2],i[2]),u[1]/=i[2],u[2]/=i[2];var y,S=t.v3Cross(x[1],x[2]);if(t.v3Dot(x[0],S)<0)for(var P=0;P<3;P++)i[P]*=-1,x[P][0]*=-1,x[P][1]*=-1,x[P][2]*=-1;return o[0]=.5*Math.sqrt(Math.max(1+x[0][0]-x[1][1]-x[2][2],0)),o[1]=.5*Math.sqrt(Math.max(1-x[0][0]+x[1][1]-x[2][2],0)),o[2]=.5*Math.sqrt(Math.max(1-x[0][0]-x[1][1]+x[2][2],0)),o[3]=.5*Math.sqrt(Math.max(1+x[0][0]+x[1][1]+x[2][2],0)),x[2][1]>x[1][2]&&(o[0]=-o[0]),x[0][2]>x[2][0]&&(o[1]=-o[1]),x[1][0]>x[0][1]&&(o[2]=-o[2]),{rotationDegrees:y=o[0]<.001&&o[0]>=0&&o[1]<.001&&o[1]>=0?[0,0,t.roundTo3Places(180*Math.atan2(x[0][1],x[0][0])/Math.PI)]:t.quaternionToDegreesXYZ(o,c,x),perspective:a,quaternion:o,scale:i,skew:u,translation:s,rotate:y[2],rotateX:y[0],rotateY:y[1],scaleX:i[0],scaleY:i[1],translateX:s[0],translateY:s[1]}}}}};_m.exports=t},554,[430,425]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.get=p,e.getWithFallback_DEPRECATED=function(n,o){if(null==t){if(v(n))return p(n,o)}else if(null!=t(n))return p(n,o);var u=function(t){return null};return u.displayName="Fallback("+n+")",u},e.setRuntimeConfigProvider=function(n){(0,f.default)(null==t,'NativeComponentRegistry.setRuntimeConfigProvider() called more than once.'),t=n},e.unstable_hasComponent=function(t){var n=s.get(t);if(null==n){if(!g.__nativeComponentRegistry__hasComponent)throw"unstable_hasComponent('"+t+"'): Global function is not registered";n=g.__nativeComponentRegistry__hasComponent(t),s.set(t,n)}return n},e.unstable_hasStaticViewConfig=function(n){var o;return!(null!=(o=null==t?void 0:t(n))?o:{native:!0}).native};var t,n=r(d[0])(r(d[1])),o=r(d[0])(r(d[2])),u=r(d[0])(r(d[3])),l=r(d[0])(r(d[4])),f=r(d[0])(r(d[5]));!(function(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var o=c(n);if(o&&o.has(t))return o.get(t);var u={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var f in t)if("default"!==f&&Object.prototype.hasOwnProperty.call(t,f)){var s=l?Object.getOwnPropertyDescriptor(t,f):null;s&&(s.get||s.set)?Object.defineProperty(u,f,s):u[f]=t[f]}u.default=t,o&&o.set(t,u)})(r(d[6]));function c(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,o=new WeakMap;return(c=function(t){return t?o:n})(t)}var s=new Map;function p(n,f){return o.default.register(n,function(){var o,c=null!=(o=null==t?void 0:t(n))?o:{native:!0,verify:!1},s=c.native,p=c.verify,v=s?(0,u.default)(n):(0,r(d[7]).createViewConfig)(f());return p&&(s?(0,l.default)(v,(0,r(d[7]).createViewConfig)(f())):(0,l.default)((0,u.default)(n),v)),v}),n}function v(o){return(0,f.default)(null==t,'Unexpected invocation!'),null!=n.default.getViewManagerConfig(o)}},555,[407,450,539,556,569,425,534,570]); -__d(function(g,r,i,a,m,e,d){'use strict';var n=!1;function t(n){var t=r(d[0]).getConstants();t.ViewManagerNames||t.LazyViewManagersEnabled?n=s(n,r(d[0]).getDefaultEventTypes()):(n.bubblingEventTypes=s(n.bubblingEventTypes,t.genericBubblingEventTypes),n.directEventTypes=s(n.directEventTypes,t.genericDirectEventTypes))}function s(n,t){if(!t)return n;if(!n)return t;for(var o in t)if(t.hasOwnProperty(o)){var u=t[o];if(n.hasOwnProperty(o)){var c=n[o];'object'==typeof u&&'object'==typeof c&&(u=s(c,u))}n[o]=u}return n}function o(n){switch(n){case'CATransform3D':return r(d[4]);case'CGPoint':return r(d[5]);case'CGSize':return r(d[6]);case'UIEdgeInsets':return r(d[7]);case'Point':return r(d[5])}return null}function u(n){switch(n){case'CGColor':case'UIColor':return r(d[8]);case'CGColorArray':case'UIColorArray':return r(d[9]);case'CGImage':case'UIImage':case'RCTImageSource':return r(d[10]);case'Color':return r(d[8]);case'ColorArray':return r(d[9])}return null}m.exports=function(s){var c=r(d[0]).getViewManagerConfig(s);r(d[1])(null!=c&&null!=c.NativeProps,'requireNativeComponent: "%s" was not found in the UIManager.',s);for(var l=c.baseModuleName,v=c.bubblingEventTypes,b=c.directEventTypes,p=c.NativeProps;l;){var f=r(d[0]).getViewManagerConfig(l);f?(v=r(d[2])({},f.bubblingEventTypes,v),b=r(d[2])({},f.directEventTypes,b),p=r(d[2])({},f.NativeProps,p),l=f.baseModuleName):l=null}var y={};for(var C in p){var E=p[C],T=o(E),w=u(E);y[C]=null==T&&null==w||{diff:T,process:w}}return y.style=r(d[3]),r(d[2])(c,{uiViewClassName:s,validAttributes:y,bubblingEventTypes:v,directEventTypes:b}),n||(t(c),n=!0),c}},556,[450,425,436,557,552,558,551,550,546,559,560]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),o=r(d[0])(r(d[2])),n=r(d[0])(r(d[3])),l={process:t.default},s={alignContent:!0,alignItems:!0,alignSelf:!0,aspectRatio:!0,borderBottomWidth:!0,borderEndWidth:!0,borderLeftWidth:!0,borderRightWidth:!0,borderStartWidth:!0,borderTopWidth:!0,borderWidth:!0,bottom:!0,direction:!0,display:!0,end:!0,flex:!0,flexBasis:!0,flexDirection:!0,flexGrow:!0,flexShrink:!0,flexWrap:!0,height:!0,justifyContent:!0,left:!0,margin:!0,marginBottom:!0,marginEnd:!0,marginHorizontal:!0,marginLeft:!0,marginRight:!0,marginStart:!0,marginTop:!0,marginVertical:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,overflow:!0,padding:!0,paddingBottom:!0,paddingEnd:!0,paddingHorizontal:!0,paddingLeft:!0,paddingRight:!0,paddingStart:!0,paddingTop:!0,paddingVertical:!0,position:!0,right:!0,start:!0,top:!0,width:!0,zIndex:!0,elevation:!0,shadowColor:l,shadowOffset:{diff:n.default},shadowOpacity:!0,shadowRadius:!0,decomposedMatrix:!0,rotation:!0,scaleX:!0,scaleY:!0,transform:{process:o.default},transformMatrix:!0,translateX:!0,translateY:!0,backfaceVisibility:!0,backgroundColor:l,borderBottomColor:l,borderBottomEndRadius:!0,borderBottomLeftRadius:!0,borderBottomRightRadius:!0,borderBottomStartRadius:!0,borderColor:l,borderEndColor:l,borderLeftColor:l,borderRadius:!0,borderRightColor:l,borderStartColor:l,borderStyle:!0,borderTopColor:l,borderTopEndRadius:!0,borderTopLeftRadius:!0,borderTopRightRadius:!0,borderTopStartRadius:!0,opacity:!0,color:l,fontFamily:!0,fontSize:!0,fontStyle:!0,fontVariant:!0,fontWeight:!0,includeFontPadding:!0,letterSpacing:!0,lineHeight:!0,textAlign:!0,textAlignVertical:!0,textDecorationColor:l,textDecorationLine:!0,textDecorationStyle:!0,textShadowColor:l,textShadowOffset:!0,textShadowRadius:!0,textTransform:!0,writingDirection:!0,overlayColor:l,resizeMode:!0,tintColor:l};m.exports=s},557,[407,546,553,551]); -__d(function(g,r,i,a,m,e,d){'use strict';var t={x:void 0,y:void 0};m.exports=function(n,o){return(n=n||t)!==(o=o||t)&&(n.x!==o.x||n.y!==o.y)}},558,[]); -__d(function(g,r,i,a,m,e,d){'use strict';var n=r(d[0])(r(d[1])),l=0;function u(u){var o=(0,n.default)(u);return null==o?(console.error('Invalid value in color array:',u),l):o}m.exports=function(n){return null==n?null:n.map(u)}},559,[407,546]); -__d(function(g,r,i,a,m,e,d){'use strict';var t,n,s,u;function o(){if(u)return u;var t=g.nativeExtensions&&g.nativeExtensions.SourceCode;return t||(t=r(d[0]).default),u=t.getConstants().scriptURL}function f(){if(void 0===n){var t=o(),s=t&&t.match(/^https?:\/\/.*?\//);n=s?s[0]:null}return n}function c(t){if(t){if(t.startsWith('assets://'))return null;(t=t.substring(0,t.lastIndexOf('/')+1)).includes('://')||(t='file://'+t)}return t}m.exports=function(n){if('object'==typeof n)return n;var u=r(d[1]).getAssetByID(n);if(!u)return null;var l=new(r(d[2]))(f(),(void 0===s&&(s=c(o())),s),u);return t?t(l):l.defaultAsset()},m.exports.pickScale=r(d[3]).pickScale,m.exports.setCustomSourceTransformer=function(n){t=n}},560,[561,562,563,564]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in n)if("default"!==c&&Object.prototype.hasOwnProperty.call(n,c)){var p=l?Object.getOwnPropertyDescriptor(n,c):null;p&&(p.get||p.set)?Object.defineProperty(f,c,p):f[c]=n[c]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).getEnforcing('SourceCode'),o=null,u={getConstants:function(){return null==o&&(o=n.getConstants()),o}};e.default=u},561,[428]); -__d(function(g,r,i,a,m,e,d){'use strict';var t=[];m.exports={registerAsset:function(s){return t.push(s)},getAssetByID:function(s){return t[s-1]}}},562,[]); -__d(function(g,r,i,a,m,e,d){'use strict';function t(t){var s=r(d[0]).pickScale(t.scales,r(d[1]).get()),n=1===s?'':'@'+s+'x';return r(d[2]).getBasePath(t)+'/'+t.name+n+'.'+t.type}var s=(function(){function s(t,n,u){r(d[3])(this,s),this.serverUrl=t,this.jsbundleUrl=n,this.asset=u}return r(d[4])(s,[{key:"isLoadedFromServer",value:function(){return!!this.serverUrl}},{key:"isLoadedFromFileSystem",value:function(){return!(!this.jsbundleUrl||!this.jsbundleUrl.startsWith('file://'))}},{key:"defaultAsset",value:function(){return this.isLoadedFromServer()?this.assetServerURL():this.isLoadedFromFileSystem()?this.drawableFolderInBundle():this.resourceIdentifierWithoutScale()}},{key:"assetServerURL",value:function(){return r(d[5])(!!this.serverUrl,'need server to load from'),this.fromSource(this.serverUrl+t(this.asset)+"?platform=android&hash="+this.asset.hash)}},{key:"scaledAssetPath",value:function(){return this.fromSource(t(this.asset))}},{key:"scaledAssetURLNearBundle",value:function(){var s=this.jsbundleUrl||'file://';return this.fromSource(s+t(this.asset).replace(/\.\.\//g,'_'))}},{key:"resourceIdentifierWithoutScale",value:function(){return r(d[5])(!0,'resource identifiers work on Android'),this.fromSource(r(d[2]).getAndroidResourceIdentifier(this.asset))}},{key:"drawableFolderInBundle",value:function(){var t,s,n=this.jsbundleUrl||'file://';return this.fromSource(n+(t=this.asset,s=r(d[0]).pickScale(t.scales,r(d[1]).get()),r(d[2]).getAndroidResourceFolderName(t,s)+'/'+r(d[2]).getAndroidResourceIdentifier(t)+'.'+t.type))}},{key:"fromSource",value:function(t){return{__packager_asset:!0,width:this.asset.width,height:this.asset.height,uri:t,scale:r(d[0]).pickScale(this.asset.scales,r(d[1]).get())}}}]),s})();s.pickScale=r(d[0]).pickScale,m.exports=s},563,[564,565,568,402,403,425]); -__d(function(g,r,_i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.getUrlCacheBreaker=function(){if(null==n)return'';return n},e.pickScale=function(n,u){null==u&&(u=t.default.get());for(var l=0;l=u)return n[l];return n[n.length-1]||1},e.setUrlCacheBreaker=function(t){n=t};var n,t=r(d[0])(r(d[1]))},564,[407,565]); -__d(function(g,r,i,a,m,e,d){'use strict';var t=(function(){function t(){r(d[0])(this,t)}return r(d[1])(t,null,[{key:"get",value:function(){return r(d[2]).get('window').scale}},{key:"getFontScale",value:function(){return r(d[2]).get('window').fontScale||t.get()}},{key:"getPixelSizeForLayoutSize",value:function(n){return Math.round(n*t.get())}},{key:"roundToNearestPixel",value:function(n){var u=t.get();return Math.round(n*u)/u}},{key:"startDetecting",value:function(){}}]),t})();m.exports=t},565,[402,403,566]); -__d(function(g,r,i,a,m,e,d){var n,t=r(d[0])(r(d[1])),s=r(d[0])(r(d[2])),o=r(d[0])(r(d[3])),l=r(d[0])(r(d[4])),c=r(d[0])(r(d[5])),u=r(d[0])(r(d[6])),f=new o.default,v=!1,h=(function(){function o(){(0,t.default)(this,o)}return(0,s.default)(o,null,[{key:"get",value:function(t){return(0,u.default)(n[t],'No dimension set for key '+t),n[t]}},{key:"set",value:function(t){var s=t.screen,o=t.window,l=t.windowPhysicalPixels;l&&(o={width:l.width/l.scale,height:l.height/l.scale,scale:l.scale,fontScale:l.fontScale});var c=t.screenPhysicalPixels;c?s={width:c.width/c.scale,height:c.height/c.scale,scale:c.scale,fontScale:c.fontScale}:null==s&&(s=o),n={window:o,screen:s},v?f.emit('change',n):v=!0}},{key:"addEventListener",value:function(n,t){return(0,u.default)('change'===n,'Trying to subscribe to unknown event: "%s"',n),f.addListener(n,t)}},{key:"removeEventListener",value:function(n,t){(0,u.default)('change'===n,'Trying to remove listener for unknown event: "%s"',n),f.removeListener(n,t)}}]),o})(),w=g.nativeExtensions&&g.nativeExtensions.DeviceInfo&&g.nativeExtensions.DeviceInfo.Dimensions;w||(l.default.addListener('didUpdateDimensions',function(n){h.set(n)}),w=c.default.getConstants().Dimensions),h.set(w),m.exports=h},566,[407,402,403,414,413,567,425]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in n)if("default"!==c&&Object.prototype.hasOwnProperty.call(n,c)){var p=l?Object.getOwnPropertyDescriptor(n,c):null;p&&(p.get||p.set)?Object.defineProperty(f,c,p):f[c]=n[c]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).getEnforcing('DeviceInfo'),o=null,u={getConstants:function(){return null==o&&(o=n.getConstants()),o}};e.default=u},567,[428]); -__d(function(g,r,i,a,m,e,d){'use strict';var t={.75:'ldpi',1:'mdpi',1.5:'hdpi',2:'xhdpi',3:'xxhdpi',4:'xxxhdpi'};function n(n){if(n.toString()in t)return t[n.toString()];throw new Error('no such scale '+n.toString())}var o=new Set(['gif','jpeg','jpg','png','svg','webp','xml']);function s(t){var n=t.httpServerLocation;return n.startsWith('/')?n.substr(1):n}m.exports={getAndroidResourceFolderName:function(s,u){if(!o.has(s.type))return'raw';var c=n(u);if(!c)throw new Error("Don't know which android drawable suffix to use for scale: "+u+'\nAsset: '+JSON.stringify(s,null,'\t')+'\nPossible scales are:'+JSON.stringify(t,null,'\t'));return'drawable-'+c},getAndroidResourceIdentifier:function(t){return(s(t)+'/'+t.name).toLowerCase().replace(/\//g,'_').replace(/([^a-z0-9_])/g,'').replace(/^assets_/,'')},getBasePath:s}},568,[]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=function(t,n){for(var o=0,u=['validAttributes','bubblingEventTypes','directEventTypes'];o0){var l,v=null!=(l=n.uiViewClassName)?l:t.uiViewClassName;console.error("'"+v+"' has a view config that does not match native. '"+s+"' is missing: "+c.join(', '))}}},e.getConfigWithoutViewProps=function(n,f){if(!n[f])return{};return Object.keys(n[f]).filter(function(n){return!t.default[f][n]}).reduce(function(t,o){return t[o]=n[f][o],t},{})},e.lefthandObjectDiff=f,e.stringifyViewConfig=function(t){return JSON.stringify(t,function(t,n){return'function'==typeof n?"\u0192 "+n.name:n},2)};var t=r(d[0])(r(d[1])),n=['transform','hitSlop'];function f(t,o){var u={};function s(t,n,o){if(typeof t==typeof n||null==t)if('object'!=typeof t)t===n||(u[o]=n);else{var s=f(t,n);Object.keys(s).length>1&&(u[o]=s)}else u[o]=n}for(var c in t)n.includes(c)||(o?t.hasOwnProperty(c)&&s(t[c],o[c],c):u[c]={});return u}},569,[407,544]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.createViewConfig=function(t){return{uiViewClassName:t.uiViewClassName,Commands:{},bubblingEventTypes:u(n.default.bubblingEventTypes,t.bubblingEventTypes),directEventTypes:u(n.default.directEventTypes,t.directEventTypes),validAttributes:u(n.default.validAttributes,t.validAttributes)}};var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2]));function u(n,u){var l;return null==n||null==u?null!=(l=null!=n?n:u)?l:{}:(0,t.default)({},n,u)}},570,[407,436,544]); -__d(function(g,r,i,a,m,e,d){'use strict';var n;m.exports=function t(o,u){var f=arguments.length>2&&void 0!==arguments[2]?arguments[2]:-1,s=arguments.length>3?arguments[3]:void 0,c='number'==typeof f?s:f,l='number'==typeof f?f:-1;if(0===l)return!0;if(o===u)return!1;if('function'==typeof o&&'function'==typeof u){var v=null==c?void 0:c.unsafelyIgnoreFunctions;return null==v&&(!n||!n.onDifferentFunctionsIgnored||c&&'unsafelyIgnoreFunctions'in c||n.onDifferentFunctionsIgnored(o.name,u.name),v=!0),!v}if('object'!=typeof o||null===o)return o!==u;if('object'!=typeof u||null===u)return!0;if(o.constructor!==u.constructor)return!0;if(Array.isArray(o)){var y=o.length;if(u.length!==y)return!0;for(var p=0;p=w},r=function(){},_e.unstable_forceFrameRate=function(e){0>e||125>>1,a=e[r];if(!(void 0!==a&&0x(l,t))void 0!==s&&0>x(s,l)?(e[r]=s,e[u]=t,r=u):(e[r]=l,e[o]=t,r=o);else{if(!(void 0!==s&&0>x(s,t)))break e;e[r]=s,e[u]=t,r=u}}}return n}return null}function x(e,n){var t=e.sortIndex-n.sortIndex;return 0!==t?t:e.id-n.id}var P=[],F=[],I=1,M=null,C=3,j=!1,A=!1,L=!1;function q(e){for(var n=T(F);null!==n;){if(null===n.callback)g(F);else{if(!(n.startTime<=e))break;g(F),n.sortIndex=n.expirationTime,k(P,n)}n=T(F)}}function R(t){if(L=!1,q(t),!A)if(null!==T(P))A=!0,e(Y);else{var r=T(F);null!==r&&n(R,r.startTime-t)}}function Y(e,r){A=!1,L&&(L=!1,t()),j=!0;var a=C;try{for(q(r),M=T(P);null!==M&&(!(M.expirationTime>r)||e&&!_e.unstable_shouldYield());){var o=M.callback;if("function"==typeof o){M.callback=null,C=M.priorityLevel;var l=o(M.expirationTime<=r);r=_e.unstable_now(),"function"==typeof l?M.callback=l:M===T(P)&&g(P),q(r)}else g(P);M=T(P)}if(null!==M)var u=!0;else{var s=T(F);null!==s&&n(R,s.startTime-r),u=!1}return u}finally{M=null,C=a,j=!1}}var E=r;_e.unstable_IdlePriority=5,_e.unstable_ImmediatePriority=1,_e.unstable_LowPriority=4,_e.unstable_NormalPriority=3,_e.unstable_Profiling=null,_e.unstable_UserBlockingPriority=2,_e.unstable_cancelCallback=function(e){e.callback=null},_e.unstable_continueExecution=function(){A||j||(A=!0,e(Y))},_e.unstable_getCurrentPriorityLevel=function(){return C},_e.unstable_getFirstCallbackNode=function(){return T(P)},_e.unstable_next=function(e){switch(C){case 1:case 2:case 3:var n=3;break;default:n=C}var t=C;C=n;try{return e()}finally{C=t}},_e.unstable_pauseExecution=function(){},_e.unstable_requestPaint=E,_e.unstable_runWithPriority=function(e,n){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var t=C;C=e;try{return n()}finally{C=t}},_e.unstable_scheduleCallback=function(r,a,o){var l=_e.unstable_now();switch("object"==typeof o&&null!==o?o="number"==typeof(o=o.delay)&&0l?(r.sortIndex=o,k(F,r),null===T(P)&&r===T(F)&&(L?t():L=!0,n(R,o-l))):(r.sortIndex=u,k(P,r),A||j||(A=!0,e(Y))),r},_e.unstable_wrapCallback=function(e){var n=C;return function(){var t=C;C=n;try{return e.apply(this,arguments)}finally{C=t}}}},576,[]); -__d(function(g,r,i,a,m,e,d){'use strict';var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),o=(function(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var o=c(n);if(o&&o.has(t))return o.get(t);var l={},u=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var f in t)if("default"!==f&&Object.prototype.hasOwnProperty.call(t,f)){var s=u?Object.getOwnPropertyDescriptor(t,f):null;s&&(s.get||s.set)?Object.defineProperty(l,f,s):l[f]=t[f]}l.default=t,o&&o.set(t,l);return l})(r(d[3])),l=r(d[0])(r(d[4])),u=r(d[0])(r(d[5])),f=r(d[0])(r(d[6])),s=["animating","color","hidesWhenStopped","onLayout","size","style"];function c(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,o=new WeakMap;return(c=function(t){return t?o:n})(t)}var p='android'===l.default.OS?r(d[7]):r(d[8]).default,y=o.forwardRef(function(c,y){var v,O,w=c.animating,b=void 0===w||w,S=c.color,j=void 0===S?'ios'===l.default.OS?"#999999":null:S,z=c.hidesWhenStopped,W=void 0===z||z,k=c.onLayout,L=c.size,P=void 0===L?'small':L,M=c.style,_=(0,n.default)(c,s);switch(P){case'small':v=h.sizeSmall,O='small';break;case'large':v=h.sizeLarge,O='large';break;default:v={height:P,width:P}}var E=(0,t.default)({animating:b,color:j,hidesWhenStopped:W},_,{ref:y,style:v,size:O});return o.createElement(f.default,{onLayout:k,style:u.default.compose(h.container,M)},'android'===l.default.OS?o.createElement(p,(0,t.default)({},E,{styleAttr:'Normal',indeterminate:!0})):o.createElement(p,E))});y.displayName='ActivityIndicator';var h=u.default.create({container:{alignItems:'center',justifyContent:'center'},sizeSmall:{width:20,height:20},sizeLarge:{width:36,height:36}});m.exports=y},577,[407,436,508,534,426,578,579,582,587]); -__d(function(g,r,i,a,m,e,d){'use strict';var t=r(d[0]).roundToNearestPixel(.4);0===t&&(t=1/r(d[0]).get());var o={position:'absolute',left:0,right:0,top:0,bottom:0};m.exports={hairlineWidth:t,absoluteFill:o,absoluteFillObject:o,compose:function(t,o){return null!=t&&null!=o?[t,o]:null!=t?t:o},flatten:r(d[1]),setStyleAttributePreprocessor:function(t,o){var l;if(!0===r(d[2])[t])l={process:o};else{if('object'!=typeof r(d[2])[t])return void console.error(t+" is not a valid style attribute");l=r(d[3])({},r(d[2])[t],{process:o})}r(d[2])[t]=l},create:function(t){return t}}},578,[565,573,557,436]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),f=r(d[0])(r(d[3])),u=(function(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var f=o(n);if(f&&f.has(t))return f.get(t);var u={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in t)if("default"!==c&&Object.prototype.hasOwnProperty.call(t,c)){var p=l?Object.getOwnPropertyDescriptor(t,c):null;p&&(p.get||p.set)?Object.defineProperty(u,c,p):u[c]=t[c]}u.default=t,f&&f.set(t,u);return u})(r(d[4]));function o(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,f=new WeakMap;return(o=function(t){return t?f:n})(t)}var l=u.forwardRef(function(o,l){return u.createElement(f.default.Provider,{value:!1},u.createElement(n.default,(0,t.default)({},o,{ref:l})))});l.displayName='View',m.exports=l},579,[407,436,580,581,534]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=e.Commands=void 0;var t=l(r(d[0])),n=r(d[1])(r(d[2])),o=r(d[1])(r(d[3])),u=r(d[1])(r(d[4]));l(r(d[5]));function f(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,o=new WeakMap;return(f=function(t){return t?o:n})(t)}function l(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var o=f(n);if(o&&o.has(t))return o.get(t);var u={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var p in t)if("default"!==p&&Object.prototype.hasOwnProperty.call(t,p)){var s=l?Object.getOwnPropertyDescriptor(t,p):null;s&&(s.get||s.set)?Object.defineProperty(u,p,s):u[p]=t[p]}return u.default=t,o&&o.set(t,u),u}var p=t.get('RCTView',function(){return'android'===n.default.OS?u.default:{uiViewClassName:'RCTView'}}),s=(0,o.default)({supportedCommands:['hotspotUpdate','setPressed']});e.Commands=s;var c=p;e.default=c},580,[555,407,426,542,545,534]); -__d(function(g,r,i,a,m,e,d){'use strict';var t=r(d[0]).createContext(!1);m.exports=t},581,[534]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),f=r(d[0])(r(d[3])),l=["styleAttr","indeterminate","animating"],o=r(d[4]),u=o.forwardRef(function(u,v){var s=u.styleAttr,c=void 0===s?'Normal':s,y=u.indeterminate,A=void 0===y||y,_=u.animating,p=void 0===_||_,w=(0,n.default)(u,l);return o.createElement(f.default,(0,t.default)({styleAttr:c,indeterminate:A,animating:p},w,{ref:v}))});m.exports=u},582,[407,436,508,583,534]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var t=(0,r(d[0])(r(d[1])).default)('AndroidProgressBar',{interfaceOnly:!0});e.default=t},583,[407,584]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=r(d[0])(r(d[1])),o=r(d[0])(r(d[2]));var t=function(t,p){var l=p&&null!=p.paperComponentName?p.paperComponentName:t;if(null!=p&&null!=p.paperComponentNameDeprecated)if(o.default.getViewManagerConfig(t))l=t;else{var u;if(null==p.paperComponentNameDeprecated||!o.default.getViewManagerConfig(p.paperComponentNameDeprecated))throw new Error("Failed to find native component for either "+t+" or "+(null!=(u=p.paperComponentNameDeprecated)?u:'(unknown)'));l=p.paperComponentNameDeprecated}return(0,n.default)(l)};e.default=t},584,[407,585,450]); -__d(function(g,r,i,a,m,e,d){'use strict';m.exports=function(n){return r(d[0])(n,function(){return r(d[1])(n)})}},585,[586,556]); -__d(function(g,r,i,a,m,e,d){'use strict';var t=r(d[0]).ReactNativeViewConfigRegistry.register;m.exports=function(n,s){return t(n,s)}},586,[537]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var t=(0,r(d[0])(r(d[1])).default)('ActivityIndicatorView',{paperComponentName:'RCTActivityIndicatorView'});e.default=t},587,[407,584]); -__d(function(g,r,i,a,m,_e,d){'use strict';var t=r(d[0])(r(d[1])),e=r(d[0])(r(d[2])),o=r(d[0])(r(d[3])),s=r(d[0])(r(d[4])),n=r(d[0])(r(d[5])),c=r(d[0])(r(d[6])),l=(function(t,e){if(!e&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var o=x(e);if(o&&o.has(t))return o.get(t);var s={},n=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in t)if("default"!==c&&Object.prototype.hasOwnProperty.call(t,c)){var l=n?Object.getOwnPropertyDescriptor(t,c):null;l&&(l.get||l.set)?Object.defineProperty(s,c,l):s[c]=t[c]}s.default=t,o&&o.set(t,s);return s})(r(d[7])),u=r(d[0])(r(d[8])),f=r(d[0])(r(d[9])),p=r(d[0])(r(d[10])),b=r(d[0])(r(d[11])),y=r(d[0])(r(d[12])),h=r(d[0])(r(d[13])),v=r(d[0])(r(d[14]));function x(t){if("function"!=typeof WeakMap)return null;var e=new WeakMap,o=new WeakMap;return(x=function(t){return t?o:e})(t)}function F(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var D=(function(f){(0,s.default)(w,f);var x,D,S=(x=w,D=F(),function(){var t,e=(0,c.default)(x);if(D){var o=(0,c.default)(this).constructor;t=Reflect.construct(e,arguments,o)}else t=e.apply(this,arguments);return(0,n.default)(this,t)});function w(){return(0,e.default)(this,w),S.apply(this,arguments)}return(0,o.default)(w,[{key:"render",value:function(){var e,o,s=this.props,n=s.accessibilityLabel,c=s.color,f=s.onPress,x=s.touchSoundDisabled,F=s.title,D=s.hasTVPreferredFocus,S=s.nextFocusDown,w=s.nextFocusForward,P=s.nextFocusLeft,R=s.nextFocusRight,A=s.nextFocusUp,k=s.testID,j=s.accessible,C=s.accessibilityActions,L=s.onAccessibilityAction,M=[O.button],W=[O.text];c&&('ios'===u.default.OS?W.push({color:c}):M.push({backgroundColor:c}));var _=null!=this.props.disabled?this.props.disabled:null==(e=this.props.accessibilityState)?void 0:e.disabled,B=_!==(null==(o=this.props.accessibilityState)?void 0:o.disabled)?(0,t.default)({},this.props.accessibilityState,{disabled:_}):this.props.accessibilityState;_&&(M.push(O.buttonDisabled),W.push(O.textDisabled)),(0,v.default)('string'==typeof F,'The title prop of a Button must be a string');var E='android'===u.default.OS?F.toUpperCase():F,T='android'===u.default.OS?b.default:y.default;return l.createElement(T,{accessible:j,accessibilityActions:C,onAccessibilityAction:L,accessibilityLabel:n,accessibilityRole:"button",accessibilityState:B,hasTVPreferredFocus:D,nextFocusDown:S,nextFocusForward:w,nextFocusLeft:P,nextFocusRight:R,nextFocusUp:A,testID:k,disabled:_,onPress:f,touchSoundDisabled:x},l.createElement(h.default,{style:M},l.createElement(p.default,{style:W,disabled:_},E)))}}]),w})(l.Component),O=f.default.create({button:u.default.select({ios:{},android:{elevation:4,backgroundColor:'#2196F3',borderRadius:2}}),text:(0,t.default)({textAlign:'center',margin:8},u.default.select({ios:{color:'#007AFF',fontSize:18},android:{color:'white',fontWeight:'500'}})),buttonDisabled:u.default.select({ios:{},android:{elevation:0,backgroundColor:'#dfdfdf'}}),textDisabled:u.default.select({ios:{color:'#cdcdcd'},android:{color:'#a1a1a1'}})});m.exports=D},588,[407,436,402,403,417,419,422,534,426,578,589,614,615,579,425]); -__d(function(g,r,i,a,m,e,d){var n=r(d[0])(r(d[1])),o=r(d[0])(r(d[2])),t=r(d[0])(r(d[3])),s=r(d[0])(r(d[4])),l=(v(r(d[5])),r(d[0])(r(d[6]))),u=(r(d[0])(r(d[7])),r(d[0])(r(d[8]))),p=r(d[0])(r(d[9])),f=v(r(d[10])),c=(r(d[0])(r(d[11])),["accessible","allowFontScaling","ellipsizeMode","onLongPress","onPress","onPressIn","onPressOut","onResponderGrant","onResponderMove","onResponderRelease","onResponderTerminate","onResponderTerminationRequest","onStartShouldSetResponder","pressRetentionOffset","suppressHighlighting"]);function R(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,t=new WeakMap;return(R=function(n){return n?t:o})(n)}function v(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var t=R(o);if(t&&t.has(n))return t.get(n);var s={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var u in n)if("default"!==u&&Object.prototype.hasOwnProperty.call(n,u)){var p=l?Object.getOwnPropertyDescriptor(n,u):null;p&&(p.get||p.set)?Object.defineProperty(s,u,p):s[u]=n[u]}return s.default=n,t&&t.set(n,s),s}var P=f.forwardRef(function(s,R){var v=s.accessible,P=s.allowFontScaling,b=s.ellipsizeMode,O=s.onLongPress,T=s.onPress,h=s.onPressIn,y=s.onPressOut,M=s.onResponderGrant,w=s.onResponderMove,E=s.onResponderRelease,C=s.onResponderTerminate,L=s.onResponderTerminationRequest,j=s.onStartShouldSetResponder,x=s.pressRetentionOffset,D=s.suppressHighlighting,_=(0,t.default)(s,c),q=(0,f.useState)(!1),G=(0,o.default)(q,2),H=G[0],k=G[1],z=(null!=T||null!=O||null!=j)&&!0!==_.disabled,F=S(z),I=(0,f.useMemo)(function(){return F?{disabled:!z,pressRectOffset:x,onLongPress:O,onPress:T,onPressIn:function(n){k(!D),null==h||h(n)},onPressOut:function(n){k(!1),null==y||y(n)},onResponderTerminationRequest_DEPRECATED:L,onStartShouldSetResponder_DEPRECATED:j}:null},[F,z,x,O,T,h,y,L,j,D]),N=(0,l.default)(I),W=(0,f.useMemo)(function(){return null==N?null:{onResponderGrant:function(n){N.onResponderGrant(n),null!=M&&M(n)},onResponderMove:function(n){N.onResponderMove(n),null!=w&&w(n)},onResponderRelease:function(n){N.onResponderRelease(n),null!=E&&E(n)},onResponderTerminate:function(n){N.onResponderTerminate(n),null!=C&&C(n)},onResponderTerminationRequest:N.onResponderTerminationRequest,onStartShouldSetResponder:N.onStartShouldSetResponder}},[N,M,w,E,C]),A=null==_.selectionColor?null:(0,u.default)(_.selectionColor),V=_.style,B=_.numberOfLines;return null==B||B>=0||(console.error("'numberOfLines' in must be a non-negative number, received: "+B+". The value will be set to 0."),B=0),(0,f.useContext)(p.default)?f.createElement(r(d[12]).NativeVirtualText,(0,n.default)({},_,W,{isHighlighted:H,numberOfLines:B,selectionColor:A,style:V,ref:R})):f.createElement(p.default.Provider,{value:!0},f.createElement(r(d[12]).NativeText,(0,n.default)({},_,W,{accessible:!1!==v,allowFontScaling:!1!==P,ellipsizeMode:null!=b?b:'tail',isHighlighted:H,numberOfLines:B,selectionColor:A,style:V,ref:R})))});function S(n){var t=(0,f.useState)(n),s=(0,o.default)(t,2),l=s[0],u=s[1];return!l&&n&&u(n),l}P.displayName='Text',P.propTypes=s.default,m.exports=P},589,[407,436,430,508,590,604,605,578,546,581,534,425,612]); -__d(function(g,r,i,a,m,e,d){'use strict';var o=r(d[0])(r(d[1]));m.exports={ellipsizeMode:r(d[2]).oneOf(['head','middle','tail','clip']),numberOfLines:r(d[2]).number,textBreakStrategy:r(d[2]).oneOf(['simple','highQuality','balanced']),onLayout:r(d[2]).func,onPress:r(d[2]).func,onLongPress:r(d[2]).func,pressRetentionOffset:r(d[3]),selectable:r(d[2]).bool,selectionColor:r(d[4]),suppressHighlighting:r(d[2]).bool,style:o,testID:r(d[2]).string,nativeID:r(d[2]).string,allowFontScaling:r(d[2]).bool,maxFontSizeMultiplier:r(d[2]).number,accessible:r(d[2]).bool,adjustsFontSizeToFit:r(d[2]).bool,minimumFontScale:r(d[2]).number,disabled:r(d[2]).bool,dataDetectorType:r(d[2]).oneOf(['phoneNumber','link','email','none','all'])}},590,[591,593,596,603,600]); -__d(function(g,r,i,a,m,e,d){'use strict';m.exports=function(n){var t=r(d[0])(n);return function(n,o,c,u){var f=n;n[o]&&((f={})[o]=r(d[1])(n[o]));for(var v=arguments.length,p=new Array(v>4?v-4:0),s=4;s5?v-5:0),j=5;j4?s-4:0),p=4;p3?f-3:0),p=3;p0?t._pressDelayTimeout=setTimeout(function(){t._receiveSignal('DELAY',E)},n):t._receiveSignal('DELAY',E);var R=I(t._config.delayLongPress,10,500-n);t._longPressDelayTimeout=setTimeout(function(){t._handleLongPress(E)},R+n)},onResponderMove:function(E){var n=t._config.onPressMove;null!=n&&n(E);var R=t._responderRegion;if(null!=R){var _=A(E);if(null==_)return t._cancelLongPressDelayTimeout(),void t._receiveSignal('LEAVE_PRESS_RECT',E);if(null!=t._touchActivatePosition){var o=t._touchActivatePosition.pageX-_.pageX,l=t._touchActivatePosition.pageY-_.pageY;Math.hypot(o,l)>10&&t._cancelLongPressDelayTimeout()}t._isTouchWithinResponderRegion(_,R)?t._receiveSignal('ENTER_PRESS_RECT',E):(t._cancelLongPressDelayTimeout(),t._receiveSignal('LEAVE_PRESS_RECT',E))}},onResponderRelease:function(E){t._receiveSignal('RESPONDER_RELEASE',E)},onResponderTerminate:function(E){t._receiveSignal('RESPONDER_TERMINATED',E)},onResponderTerminationRequest:function(){var E=t._config.cancelable;if(null==E){var n=t._config.onResponderTerminationRequest_DEPRECATED;return null==n||n()}return E},onClick:function(E){var n=t._config,R=n.onPress,_=n.disabled;null!=R&&!0!==_&&R(E)}},_='ios'===l.default.OS||'android'===l.default.OS?null:{onMouseEnter:function(E){if((0,r(d[10]).isHoverEnabled)()){t._isHovered=!0,t._cancelHoverOutDelayTimeout();var n=t._config.onHoverIn;if(null!=n){var R=I(t._config.delayHoverIn);R>0?(E.persist(),t._hoverInDelayTimeout=setTimeout(function(){n(E)},R)):n(E)}}},onMouseLeave:function(E){if(t._isHovered){t._isHovered=!1,t._cancelHoverInDelayTimeout();var n=t._config.onHoverOut;if(null!=n){var R=I(t._config.delayHoverOut);R>0?(E.persist(),t._hoverInDelayTimeout=setTimeout(function(){n(E)},R)):n(E)}}}};return(0,E.default)({},n,R,_)}},{key:"_receiveSignal",value:function(E,t){var n,_=this._touchState,l=null==(n=S[_])?void 0:n[E];null==this._responderID&&'RESPONDER_RELEASE'===E||((0,R.default)(null!=l&&'ERROR'!==l,'Pressability: Invalid signal `%s` for state `%s` on responder: %s',E,_,'number'==typeof this._responderID?this._responderID:'<>'),_!==l&&(null!=t.nativeEvent.timestamp&&o.default.emitEvent(function(){return{signal:E,touchDelayMs:Date.now()-t.nativeEvent.timestamp}}),this._performTransitionSideEffects(_,l,E,t),this._touchState=l))}},{key:"_performTransitionSideEffects",value:function(E,t,n,R){c(n)&&(this._touchActivatePosition=null,this._cancelLongPressDelayTimeout());var o='NOT_RESPONDER'===E&&'RESPONDER_INACTIVE_PRESS_IN'===t,u=!P(E)&&P(t);if((o||u)&&this._measureResponderRegion(),O(E)&&'LONG_PRESS_DETECTED'===n){var s=this._config.onLongPress;null!=s&&s(R)}var S=T(E),D=T(t);if(!S&&D?this._activate(R):S&&!D&&this._deactivate(R),O(E)&&'RESPONDER_RELEASE'===n){D||S||(this._activate(R),this._deactivate(R));var N=this._config,h=N.onLongPress,f=N.onPress,v=N.android_disableSound;if(null!=f)null!=h&&'RESPONDER_ACTIVE_LONG_PRESS_IN'===E&&this._shouldLongPressCancelPress()||('android'===l.default.OS&&!0!==v&&_.default.playTouchSound(),f(R))}this._cancelPressDelayTimeout()}},{key:"_activate",value:function(E){var t=this._config.onPressIn,n=A(E),R=n.pageX,_=n.pageY;this._touchActivatePosition={pageX:R,pageY:_},this._touchActivateTime=Date.now(),null!=t&&t(E)}},{key:"_deactivate",value:function(E){var t=this._config.onPressOut;if(null!=t){var n,R=I(this._config.minPressDuration,0,130),_=Date.now()-(null!=(n=this._touchActivateTime)?n:0),o=Math.max(R-_,I(this._config.delayPressOut));o>0?(E.persist(),this._pressOutDelayTimeout=setTimeout(function(){t(E)},o)):t(E)}this._touchActivateTime=null}},{key:"_measureResponderRegion",value:function(){null!=this._responderID&&('number'==typeof this._responderID?u.default.measure(this._responderID,this._measureCallback):this._responderID.measure(this._measureCallback))}},{key:"_isTouchWithinResponderRegion",value:function(E,t){var n,R,_,o,l=(0,r(d[11]).normalizeRect)(this._config.hitSlop),u=(0,r(d[11]).normalizeRect)(this._config.pressRectOffset),s=t.bottom,S=t.left,T=t.right,P=t.top;return null!=l&&(null!=l.bottom&&(s+=l.bottom),null!=l.left&&(S-=l.left),null!=l.right&&(T+=l.right),null!=l.top&&(P-=l.top)),s+=null!=(n=null==u?void 0:u.bottom)?n:D,S-=null!=(R=null==u?void 0:u.left)?R:N,T+=null!=(_=null==u?void 0:u.right)?_:h,P-=null!=(o=null==u?void 0:u.top)?o:f,E.pageX>S&&E.pageXP&&E.pageY1&&void 0!==arguments[1]?arguments[1]:0,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0;return Math.max(t,null!=E?E:n)}e.default=v;var A=function(E){var t=E.nativeEvent,n=t.changedTouches,R=t.touches;return null!=R&&R.length>0?R[0]:null!=n&&n.length>0?n[0]:E.nativeEvent}},606,[407,436,402,403,425,607,609,426,450,534,610,611]); -__d(function(g,r,i,a,m,e,d){var u=r(d[0])(r(d[1])),o={playTouchSound:function(){u.default&&u.default.playTouchSound()}};m.exports=o},607,[407,608]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in n)if("default"!==l&&Object.prototype.hasOwnProperty.call(n,l)){var p=c?Object.getOwnPropertyDescriptor(n,l):null;p&&(p.get||p.set)?Object.defineProperty(f,l,p):f[l]=n[l]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).get('SoundManager');e.default=n},608,[428]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),s=new((function(){function s(){(0,t.default)(this,s),this._listeners=[]}return(0,n.default)(s,[{key:"addListener",value:function(t){this._listeners.push(t)}},{key:"removeListener",value:function(t){var n=this._listeners.indexOf(t);n>-1&&this._listeners.splice(n,1)}},{key:"emitEvent",value:function(t){if(0!==this._listeners.length){var n=t();this._listeners.forEach(function(t){return t(n)})}}}]),s})());e.default=s},609,[407,402,403]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.isHoverEnabled=function(){return n};var n=!1;if('web'===r(d[0])(r(d[1])).default.OS&&Boolean('undefined'!=typeof window&&window.document&&window.document.createElement)){var t=0,o=function(){t=Date.now(),n&&(n=!1)};document.addEventListener('touchstart',o,!0),document.addEventListener('touchmove',o,!0),document.addEventListener('mousemove',function(){n||Date.now()-t<1e3||(n=!0)},!0)}},610,[407,426]); -__d(function(g,r,i,a,m,e,d){function t(t){return{bottom:t,left:t,right:t,top:t}}Object.defineProperty(e,"__esModule",{value:!0}),e.createSquare=t,e.normalizeRect=function(n){return'number'==typeof n?t(n):n}},611,[]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.NativeVirtualText=e.NativeText=void 0;var t=r(d[0])(r(d[1])),l=r(d[0])(r(d[2])),n=r(d[0])(r(d[3])),o=r(d[0])(r(d[4])),u=(0,o.default)('RCTText',function(){return{validAttributes:(0,t.default)({},l.default.UIView,{isHighlighted:!0,numberOfLines:!0,ellipsizeMode:!0,allowFontScaling:!0,maxFontSizeMultiplier:!0,disabled:!0,selectable:!0,selectionColor:!0,adjustsFontSizeToFit:!0,minimumFontScale:!0,textBreakStrategy:!0,onTextLayout:!0,onInlineViewLayout:!0,dataDetectorType:!0,android_hyphenationFrequency:!0}),directEventTypes:{topTextLayout:{registrationName:'onTextLayout'},topInlineViewLayout:{registrationName:'onInlineViewLayout'}},uiViewClassName:'RCTText'}});e.NativeText=u;var s=g.RN$Bridgeless||n.default.hasViewManagerConfig('RCTVirtualText')?(0,o.default)('RCTVirtualText',function(){return{validAttributes:(0,t.default)({},l.default.UIView,{isHighlighted:!0,maxFontSizeMultiplier:!0}),uiViewClassName:'RCTVirtualText'}}):u;e.NativeVirtualText=s},612,[407,436,613,450,586]); -__d(function(g,r,i,a,m,e,d){'use strict';var s=r(d[0])(r(d[1])),t={pointerEvents:!0,accessible:!0,accessibilityActions:!0,accessibilityLabel:!0,accessibilityLiveRegion:!0,accessibilityRole:!0,accessibilityState:!0,accessibilityValue:!0,accessibilityHint:!0,importantForAccessibility:!0,nativeID:!0,testID:!0,renderToHardwareTextureAndroid:!0,shouldRasterizeIOS:!0,onLayout:!0,onAccessibilityAction:!0,onAccessibilityTap:!0,onMagicTap:!0,onAccessibilityEscape:!0,collapsable:!0,needsOffscreenAlphaCompositing:!0,style:r(d[0])(r(d[2])).default},c={UIView:t,RCTView:(0,s.default)({},t,{removeClippedSubviews:!0})};m.exports=c},613,[407,436,557]); -__d(function(g,r,i,a,m,_e,d){var e=r(d[0])(r(d[1])),t=r(d[0])(r(d[2])),s=r(d[0])(r(d[3])),o=r(d[0])(r(d[4])),n=r(d[0])(r(d[5])),l=r(d[0])(r(d[6])),c=r(d[0])(r(d[7])),p=r(d[0])(r(d[8])),u=r(d[0])(r(d[9])),f=r(d[0])(r(d[10])),h=(r(d[0])(r(d[11])),r(d[0])(r(d[12]))),b=(function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var s=P(t);if(s&&s.has(e))return s.get(e);var o={},n=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in e)if("default"!==l&&Object.prototype.hasOwnProperty.call(e,l)){var c=n?Object.getOwnPropertyDescriptor(e,l):null;c&&(c.get||c.set)?Object.defineProperty(o,l,c):o[l]=e[l]}o.default=e,s&&s.set(e,o);return o})(r(d[13])),y=r(d[0])(r(d[14])),v=["onBlur","onFocus"];function P(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,s=new WeakMap;return(P=function(e){return e?s:t})(e)}function F(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}var O=(function(h){(0,n.default)(R,h);var y,P,O=(y=R,P=F(),function(){var e,t=(0,c.default)(y);if(P){var s=(0,c.default)(this).constructor;e=Reflect.construct(t,arguments,s)}else e=t.apply(this,arguments);return(0,l.default)(this,e)});function R(){var e;(0,s.default)(this,R);for(var t=arguments.length,o=new Array(t),n=0;n=23};var S='android'===f.default.OS?function(e,t){return t&&O.canUseNativeForeground()?{nativeForegroundAndroid:e}:{nativeBackgroundAndroid:e}}:function(e,t){return null};O.displayName='TouchableNativeFeedback',m.exports=O},614,[407,436,508,402,403,417,419,422,606,456,426,579,546,534,425,580]); -__d(function(g,r,i,a,m,_e,d){var t=r(d[0])(r(d[1])),e=r(d[0])(r(d[2])),s=r(d[0])(r(d[3])),o=r(d[0])(r(d[4])),n=r(d[0])(r(d[5])),c=r(d[0])(r(d[6])),l=r(d[0])(r(d[7])),p=r(d[0])(r(d[8])),u=r(d[0])(r(d[9])),f=r(d[0])(r(d[10])),y=r(d[0])(r(d[11])),h=r(d[0])(r(d[12])),b=(function(t,e){if(!e&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var s=P(e);if(s&&s.has(t))return s.get(t);var o={},n=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in t)if("default"!==c&&Object.prototype.hasOwnProperty.call(t,c)){var l=n?Object.getOwnPropertyDescriptor(t,c):null;l&&(l.get||l.set)?Object.defineProperty(o,c,l):o[c]=t[c]}o.default=t,s&&s.set(t,o);return o})(r(d[13])),v=["onBlur","onFocus"];function P(t){if("function"!=typeof WeakMap)return null;var e=new WeakMap,s=new WeakMap;return(P=function(t){return t?s:e})(t)}function O(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var F=(function(P){(0,n.default)(w,P);var F,_,R=(F=w,_=O(),function(){var t,e=(0,l.default)(F);if(_){var s=(0,l.default)(this).constructor;t=Reflect.construct(e,arguments,s)}else t=e.apply(this,arguments);return(0,c.default)(this,t)});function w(){var t;(0,s.default)(this,w);for(var e=arguments.length,o=new Array(e),n=0;n1&&void 0!==arguments[1]?arguments[1]:{}).iterations;return t},event:r(d[5]).event,createAnimatedComponent:r(d[6]),attachNativeEvent:r(d[7]).attachNativeEvent,forkEvent:r(d[5]).forkEvent,unforkEvent:r(d[5]).unforkEvent,Event:r(d[7]).AnimatedEvent}},617,[436,618,627,622,624,628,644,643]); -__d(function(g,r,i,a,m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}function e(t){var e=new Set;!(function t(n){'function'==typeof n.update?e.add(n):n.__getChildren().forEach(t)})(t),e.forEach(function(t){return t.update()})}var n=(function(n){r(d[3])(_,n);var s,u,o=(s=_,u=t(),function(){var t,e=r(d[0])(s);if(u){var n=r(d[0])(this).constructor;t=Reflect.construct(e,arguments,n)}else t=e.apply(this,arguments);return r(d[1])(this,t)});function _(t){var e;if(r(d[4])(this,_),e=o.call(this),'number'!=typeof t)throw new Error('AnimatedValue: Attempting to set value to undefined');return e._startingValue=e._value=t,e._offset=0,e._animation=null,e}return r(d[5])(_,[{key:"__detach",value:function(){var t=this;this.__isNative&&r(d[2]).API.getValue(this.__getNativeTag(),function(e){t._value=e}),this.stopAnimation(),r(d[6])(r(d[0])(_.prototype),"__detach",this).call(this)}},{key:"__getValue",value:function(){return this._value+this._offset}},{key:"setValue",value:function(t){var e,n,s=this;this._animation&&(this._animation.stop(),this._animation=null),this._updateValue(t,!this.__isNative),this.__isNative&&(e=this.__getNativeTag().toString(),n=function(){r(d[2]).API.setAnimatedNodeValue(s.__getNativeTag(),t)},r(d[2]).API.setWaitingForIdentifier(e),n(),r(d[2]).API.unsetWaitingForIdentifier(e))}},{key:"setOffset",value:function(t){this._offset=t,this.__isNative&&r(d[2]).API.setAnimatedNodeOffset(this.__getNativeTag(),t)}},{key:"flattenOffset",value:function(){this._value+=this._offset,this._offset=0,this.__isNative&&r(d[2]).API.flattenAnimatedNodeOffset(this.__getNativeTag())}},{key:"extractOffset",value:function(){this._offset+=this._value,this._value=0,this.__isNative&&r(d[2]).API.extractAnimatedNodeOffset(this.__getNativeTag())}},{key:"stopAnimation",value:function(t){this.stopTracking(),this._animation&&this._animation.stop(),this._animation=null,t&&t(this.__getValue())}},{key:"resetAnimation",value:function(t){this.stopAnimation(t),this._value=this._startingValue,this.__isNative&&r(d[2]).API.setAnimatedNodeValue(this.__getNativeTag(),this._startingValue)}},{key:"_onAnimatedValueUpdateReceived",value:function(t){this._updateValue(t,!1)}},{key:"interpolate",value:function(t){return new(r(d[7]))(this,t)}},{key:"animate",value:function(t,e){var n=this,s=null;t.__isInteraction&&(s=r(d[8]).createInteractionHandle());var u=this._animation;this._animation&&this._animation.stop(),this._animation=t,t.start(this._value,function(t){n._updateValue(t,!0)},function(t){n._animation=null,null!==s&&r(d[8]).clearInteractionHandle(s),e&&e(t)},u,this)}},{key:"stopTracking",value:function(){this._tracking&&this._tracking.__detach(),this._tracking=null}},{key:"track",value:function(t){this.stopTracking(),this._tracking=t}},{key:"_updateValue",value:function(t,n){if(void 0===t)throw new Error('AnimatedValue: Attempting to set value to undefined');this._value=t,n&&e(this),r(d[6])(r(d[0])(_.prototype),"__callListeners",this).call(this,this.__getValue())}},{key:"__getNativeConfig",value:function(){return{type:'value',value:this._value,offset:this._offset}}}]),_})(r(d[9]));m.exports=n},618,[422,419,619,417,402,403,489,622,625,623]); -__d(function(g,r,i,a,m,e,d){var t,n=r(d[0])(r(d[1])),o=r(d[0])(r(d[2])),u=r(d[0])(r(d[3])),l=r(d[0])(r(d[4])),s=r(d[0])(r(d[5])),f='ios'===l.default.OS&&g.RN$Bridgeless?o.default:n.default,c=1,v=1,p=new Set,N=!1,b=[],A={getValue:function(t,n){(0,s.default)(f,'Native animated module is not available'),A.queueOperation(function(){f.getValue(t,n)})},setWaitingForIdentifier:function(t){p.add(t),N=!0},unsetWaitingForIdentifier:function(t){p.delete(t),0===p.size&&(N=!1,A.disableQueue())},disableQueue:function(){(0,s.default)(f,'Native animated module is not available'),'android'===l.default.OS&&f.startOperationBatch();for(var t=0,n=b.length;tn){if('identity'===u)return c;'clamp'===u&&(c=n)}return a===r?a:e===n?t<=e?a:r:(e===-1/0?c=-c:n===1/0?c-=e:c=(c-e)/(n-e),c=i(c),a===-1/0?c=-c:r===1/0?c+=a:c=c*(r-a)+a,c)}function r(t){var e=_r(d[3])(t);return null===e||'number'!=typeof e?t:"rgba("+((4278190080&(e=e||0))>>>24)+", "+((16711680&e)>>>16)+", "+((65280&e)>>>8)+", "+(255&e)/255+")"}var i=/[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?/g;function o(t){var e=t.outputRange;_r(d[2])(e.length>=2,'Bad output range'),u(e=e.map(r));var a=e[0].match(i).map(function(){return[]});e.forEach(function(t){t.match(i).forEach(function(t,e){a[e].push(+t)})});var o,c=e[0].match(i).map(function(e,r){return n(_r(d[4])({},t,{outputRange:a[r]}))}),l='string'==typeof(o=e[0])&&o.startsWith('rgb');return function(t){var n=0;return e[0].replace(i,function(){var e=+c[n++](t);return l&&(e=n<4?Math.round(e):Math.round(1e3*e)/1e3),String(e)})}}function u(t){for(var e=t[0].replace(i,''),n=1;n=t);++n);return n-1}function l(t){_r(d[2])(t.length>=2,'inputRange must have at least 2 elements');for(var e=1;e=t[e-1],'inputRange must be monotonically non-decreasing '+t)}function p(t,e){_r(d[2])(e.length>=2,t+' must have at least 2 elements'),_r(d[2])(2!==e.length||e[0]!==-1/0||e[1]!==1/0,t+'cannot be ]-infinity;+infinity[ '+e)}var f=(function(e){_r(d[5])(o,e);var a,r,i=(a=o,r=t(),function(){var t,e=_r(d[0])(a);if(r){var n=_r(d[0])(this).constructor;t=Reflect.construct(e,arguments,n)}else t=e.apply(this,arguments);return _r(d[1])(this,t)});function o(t,e){var a;return _r(d[6])(this,o),(a=i.call(this))._parent=t,a._config=e,a._interpolation=n(e),a}return _r(d[7])(o,[{key:"__makeNative",value:function(){this._parent.__makeNative(),_r(d[8])(_r(d[0])(o.prototype),"__makeNative",this).call(this)}},{key:"__getValue",value:function(){var t=this._parent.__getValue();return _r(d[2])('number'==typeof t,'Cannot interpolate an input which is not a number.'),this._interpolation(t)}},{key:"interpolate",value:function(t){return new o(this,t)}},{key:"__attach",value:function(){this._parent.__addChild(this)}},{key:"__detach",value:function(){this._parent.__removeChild(this),_r(d[8])(_r(d[0])(o.prototype),"__detach",this).call(this)}},{key:"__transformDataType",value:function(t){return t.map(_r(d[9]).transformDataType)}},{key:"__getNativeConfig",value:function(){return{inputRange:this._config.inputRange,outputRange:this.__transformDataType(this._config.outputRange),extrapolateLeft:this._config.extrapolateLeft||this._config.extrapolate||'extend',extrapolateRight:this._config.extrapolateRight||this._config.extrapolate||'extend',type:'interpolation'}}}]),o})(_r(d[10]));f.__createInterpolation=n,m.exports=f},622,[422,419,425,547,436,417,402,403,489,619,623]); -__d(function(g,r,_i,a,m,_e,d){'use strict';function t(t,i){var n="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(n)return(n=n.call(t)).next.bind(n);if(Array.isArray(t)||(n=e(t))||i&&t&&"number"==typeof t.length){n&&(t=n);var o=0;return function(){return o>=t.length?{done:!0}:{done:!1,value:t[o++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function e(t,e){if(t){if("string"==typeof t)return i(t,e);var n=Object.prototype.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?i(t,e):void 0}}function i(t,e){(null==e||e>t.length)&&(e=t.length);for(var i=0,n=new Array(e);i0?setTimeout(h,0):setImmediate(h))}function h(){l=0;var f=o.size;c.forEach(function(n){return o.add(n)}),s.forEach(function(n){return o.delete(n)});var h=o.size;if(0!==f&&0===h?n.emit(t.Events.interactionComplete):0===f&&0!==h&&n.emit(t.Events.interactionStart),0===h)for(;u.hasTasksToProcess();)if(u.processNext(),p>0&&r(d[4]).getEventLoopRunningTime()>=p){v();break}c.clear(),s.clear()}m.exports=t},625,[407,414,425,626,437]); -__d(function(g,r,i,a,m,_e,d){'use strict';var e=(function(){function e(t){var u=t.onMoreTasks;r(d[0])(this,e),this._onMoreTasks=u,this._queueStack=[{tasks:[],popable:!1}]}return r(d[1])(e,[{key:"enqueue",value:function(e){this._getCurrentQueue().push(e)}},{key:"enqueueTasks",value:function(e){var t=this;e.forEach(function(e){return t.enqueue(e)})}},{key:"cancelTasks",value:function(e){this._queueStack=this._queueStack.map(function(t){return r(d[2])({},t,{tasks:t.tasks.filter(function(t){return-1===e.indexOf(t)})})}).filter(function(e,t){return e.tasks.length>0||0===t})}},{key:"hasTasksToProcess",value:function(){return this._getCurrentQueue().length>0}},{key:"processNext",value:function(){var e=this._getCurrentQueue();if(e.length){var t=e.shift();try{'object'==typeof t&&t.gen?this._genPromise(t):'object'==typeof t&&t.run?t.run():(r(d[3])('function'==typeof t,'Expected Function, SimpleTask, or PromiseTask, but got:\n'+JSON.stringify(t,null,2)),t())}catch(e){throw e.message='TaskQueue: Error with task '+(t.name||'')+': '+e.message,e}}}},{key:"_getCurrentQueue",value:function(){var e=this._queueStack.length-1,t=this._queueStack[e];return t.popable&&0===t.tasks.length&&this._queueStack.length>1?(this._queueStack.pop(),this._getCurrentQueue()):t.tasks}},{key:"_genPromise",value:function(e){var t=this;this._queueStack.push({tasks:[],popable:!1});var u=this._queueStack.length-1,s=this._queueStack[u];e.gen().then(function(){s.popable=!0,t.hasTasksToProcess()&&t._onMoreTasks()}).catch(function(t){throw t.message="TaskQueue: Error resolving Promise in task "+e.name+": "+t.message,t}).done()}}]),e})();m.exports=e},626,[402,403,436,425]); -__d(function(g,r,i,a,m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var e=1,n=(function(n){r(d[2])(o,n);var s,u,f=(s=o,u=t(),function(){var t,e=r(d[0])(s);if(u){var n=r(d[0])(this).constructor;t=Reflect.construct(e,arguments,n)}else t=e.apply(this,arguments);return r(d[1])(this,t)});function o(t){var e;r(d[3])(this,o),e=f.call(this);var n=t||{x:0,y:0};return'number'==typeof n.x&&'number'==typeof n.y?(e.x=new(r(d[4]))(n.x),e.y=new(r(d[4]))(n.y)):(r(d[5])(n.x instanceof r(d[4])&&n.y instanceof r(d[4]),"AnimatedValueXY must be initialized with an object of numbers or AnimatedValues."),e.x=n.x,e.y=n.y),e._listeners={},e}return r(d[6])(o,[{key:"setValue",value:function(t){this.x.setValue(t.x),this.y.setValue(t.y)}},{key:"setOffset",value:function(t){this.x.setOffset(t.x),this.y.setOffset(t.y)}},{key:"flattenOffset",value:function(){this.x.flattenOffset(),this.y.flattenOffset()}},{key:"extractOffset",value:function(){this.x.extractOffset(),this.y.extractOffset()}},{key:"__getValue",value:function(){return{x:this.x.__getValue(),y:this.y.__getValue()}}},{key:"resetAnimation",value:function(t){this.x.resetAnimation(),this.y.resetAnimation(),t&&t(this.__getValue())}},{key:"stopAnimation",value:function(t){this.x.stopAnimation(),this.y.stopAnimation(),t&&t(this.__getValue())}},{key:"addListener",value:function(t){var n=this,s=String(e++),u=function(e){e.value;t(n.__getValue())};return this._listeners[s]={x:this.x.addListener(u),y:this.y.addListener(u)},s}},{key:"removeListener",value:function(t){this.x.removeListener(this._listeners[t].x),this.y.removeListener(this._listeners[t].y),delete this._listeners[t]}},{key:"removeAllListeners",value:function(){this.x.removeAllListeners(),this.y.removeAllListeners(),this._listeners={}}},{key:"getLayout",value:function(){return{left:this.x,top:this.y}}},{key:"getTranslateTransform",value:function(){return[{translateX:this.x},{translateY:this.y}]}}]),o})(r(d[7]));m.exports=n},627,[422,419,417,402,618,425,403,623]); -__d(function(g,r,_i,_a,m,e,d){'use strict';var n=function(n,t){return n&&t.onComplete?function(){t.onComplete&&t.onComplete.apply(t,arguments),n&&n.apply(void 0,arguments)}:n||t.onComplete},t=function(n,t,i){if(n instanceof r(d[6])){var o=r(d[7])({},t),u=r(d[7])({},t);for(var s in t){var c=t[s],f=c.x,v=c.y;void 0!==f&&void 0!==v&&(o[s]=f,u[s]=v)}var p=i(n.x,o),l=i(n.y,u);return a([p,l],{stopTogether:!1})}return null},i=function i(o,a){var u=function(t,i,o){o=n(o,i);var a=t,u=i;a.stopTracking(),i.toValue instanceof r(d[8])?a.track(new(r(d[9]))(a,i.toValue,r(d[11]),u,o)):a.animate(new(r(d[11]))(u),o)};return t(o,a,i)||{start:function(n){u(o,a,n)},stop:function(){o.stopAnimation()},reset:function(){o.resetAnimation()},_startNativeLoop:function(n){var t=r(d[7])({},a,{iterations:n});u(o,t)},_isUsingNativeDriver:function(){return a.useNativeDriver||!1}}},o=function(n){var t=0;return{start:function(i){0===n.length?i&&i({finished:!0}):n[t].start(function o(a){a.finished&&++t!==n.length?n[t].start(o):i&&i(a)})},stop:function(){t1&&void 0!==arguments[1]?arguments[1]:{},i=t.iterations,o=void 0===i?-1:i,a=t.resetBeforeIteration,u=void 0===a||a,s=!1,c=0;return{start:function(t){n&&0!==o?n._isUsingNativeDriver()?n._startNativeLoop(o):(function i(){var a=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{finished:!0};s||c===o||!1===a.finished?t&&t(a):(c++,u&&n.reset(),n.start(i))})():t&&t({finished:!0})},stop:function(){s=!0,n.stop()},reset:function(){c=0,s=!1,n.reset()},_startNativeLoop:function(){throw new Error('Loops run using the native driver cannot contain Animated.loop animations')},_isUsingNativeDriver:function(){return n._isUsingNativeDriver()}}},event:function(n,t){var i=new(r(d[14]).AnimatedEvent)(n,t);return i.__isNative?i:i.__getHandler()},createAnimatedComponent:r(d[16]),attachNativeEvent:r(d[14]).attachNativeEvent,forkEvent:function(n,t){return n?n instanceof r(d[14]).AnimatedEvent?(n.__addListener(t),n):function(){'function'==typeof n&&n.apply(void 0,arguments),t.apply(void 0,arguments)}:t},unforkEvent:function(n,t){n&&n instanceof r(d[14]).AnimatedEvent&&n.__removeListener(t)},Event:r(d[14]).AnimatedEvent}},628,[629,630,631,632,633,634,627,436,624,635,636,639,642,618,643,622,644]); -__d(function(g,r,i,_a,m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var e=(function(e){r(d[2])(u,e);var n,a,_=(n=u,a=t(),function(){var t,e=r(d[0])(n);if(a){var _=r(d[0])(this).constructor;t=Reflect.construct(e,arguments,_)}else t=e.apply(this,arguments);return r(d[1])(this,t)});function u(t,e){var n;return r(d[3])(this,u),(n=_.call(this))._a='number'==typeof t?new(r(d[4]))(t):t,n._b='number'==typeof e?new(r(d[4]))(e):e,n}return r(d[5])(u,[{key:"__makeNative",value:function(){this._a.__makeNative(),this._b.__makeNative(),r(d[6])(r(d[0])(u.prototype),"__makeNative",this).call(this)}},{key:"__getValue",value:function(){return this._a.__getValue()+this._b.__getValue()}},{key:"interpolate",value:function(t){return new(r(d[7]))(this,t)}},{key:"__attach",value:function(){this._a.__addChild(this),this._b.__addChild(this)}},{key:"__detach",value:function(){this._a.__removeChild(this),this._b.__removeChild(this),r(d[6])(r(d[0])(u.prototype),"__detach",this).call(this)}},{key:"__getNativeConfig",value:function(){return{type:'addition',input:[this._a.__getNativeTag(),this._b.__getNativeTag()]}}}]),u})(r(d[8]));m.exports=e},629,[422,419,417,402,618,403,489,622,623]); -__d(function(g,r,i,_a,m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var e=(function(e){r(d[2])(u,e);var n,a,_=(n=u,a=t(),function(){var t,e=r(d[0])(n);if(a){var _=r(d[0])(this).constructor;t=Reflect.construct(e,arguments,_)}else t=e.apply(this,arguments);return r(d[1])(this,t)});function u(t,e){var n;return r(d[3])(this,u),(n=_.call(this))._a='number'==typeof t?new(r(d[4]))(t):t,n._b='number'==typeof e?new(r(d[4]))(e):e,n}return r(d[5])(u,[{key:"__makeNative",value:function(){this._a.__makeNative(),this._b.__makeNative(),r(d[6])(r(d[0])(u.prototype),"__makeNative",this).call(this)}},{key:"__getValue",value:function(){return this._a.__getValue()-this._b.__getValue()}},{key:"interpolate",value:function(t){return new(r(d[7]))(this,t)}},{key:"__attach",value:function(){this._a.__addChild(this),this._b.__addChild(this)}},{key:"__detach",value:function(){this._a.__removeChild(this),this._b.__removeChild(this),r(d[6])(r(d[0])(u.prototype),"__detach",this).call(this)}},{key:"__getNativeConfig",value:function(){return{type:'subtraction',input:[this._a.__getNativeTag(),this._b.__getNativeTag()]}}}]),u})(r(d[8]));m.exports=e},630,[422,419,417,402,618,403,489,622,623]); -__d(function(g,r,i,_a,m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var e=(function(e){r(d[2])(_,e);var n,o,a=(n=_,o=t(),function(){var t,e=r(d[0])(n);if(o){var a=r(d[0])(this).constructor;t=Reflect.construct(e,arguments,a)}else t=e.apply(this,arguments);return r(d[1])(this,t)});function _(t,e){var n;return r(d[3])(this,_),(n=a.call(this))._warnedAboutDivideByZero=!1,(0===e||e instanceof r(d[4])&&0===e.__getValue())&&console.error('Detected potential division by zero in AnimatedDivision'),n._a='number'==typeof t?new(r(d[5]))(t):t,n._b='number'==typeof e?new(r(d[5]))(e):e,n}return r(d[6])(_,[{key:"__makeNative",value:function(){this._a.__makeNative(),this._b.__makeNative(),r(d[7])(r(d[0])(_.prototype),"__makeNative",this).call(this)}},{key:"__getValue",value:function(){var t=this._a.__getValue(),e=this._b.__getValue();return 0===e?(this._warnedAboutDivideByZero||(console.error('Detected division by zero in AnimatedDivision'),this._warnedAboutDivideByZero=!0),0):(this._warnedAboutDivideByZero=!1,t/e)}},{key:"interpolate",value:function(t){return new(r(d[8]))(this,t)}},{key:"__attach",value:function(){this._a.__addChild(this),this._b.__addChild(this)}},{key:"__detach",value:function(){this._a.__removeChild(this),this._b.__removeChild(this),r(d[7])(r(d[0])(_.prototype),"__detach",this).call(this)}},{key:"__getNativeConfig",value:function(){return{type:'division',input:[this._a.__getNativeTag(),this._b.__getNativeTag()]}}}]),_})(r(d[9]));m.exports=e},631,[422,419,417,402,624,618,403,489,622,623]); -__d(function(g,r,i,_a,m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var e=(function(e){r(d[2])(u,e);var n,a,_=(n=u,a=t(),function(){var t,e=r(d[0])(n);if(a){var _=r(d[0])(this).constructor;t=Reflect.construct(e,arguments,_)}else t=e.apply(this,arguments);return r(d[1])(this,t)});function u(t,e){var n;return r(d[3])(this,u),(n=_.call(this))._a='number'==typeof t?new(r(d[4]))(t):t,n._b='number'==typeof e?new(r(d[4]))(e):e,n}return r(d[5])(u,[{key:"__makeNative",value:function(){this._a.__makeNative(),this._b.__makeNative(),r(d[6])(r(d[0])(u.prototype),"__makeNative",this).call(this)}},{key:"__getValue",value:function(){return this._a.__getValue()*this._b.__getValue()}},{key:"interpolate",value:function(t){return new(r(d[7]))(this,t)}},{key:"__attach",value:function(){this._a.__addChild(this),this._b.__addChild(this)}},{key:"__detach",value:function(){this._a.__removeChild(this),this._b.__removeChild(this),r(d[6])(r(d[0])(u.prototype),"__detach",this).call(this)}},{key:"__getNativeConfig",value:function(){return{type:'multiplication',input:[this._a.__getNativeTag(),this._b.__getNativeTag()]}}}]),u})(r(d[8]));m.exports=e},632,[422,419,417,402,618,403,489,622,623]); -__d(function(g,r,i,_a,m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var e=(function(e){r(d[2])(o,e);var u,n,a=(u=o,n=t(),function(){var t,e=r(d[0])(u);if(n){var a=r(d[0])(this).constructor;t=Reflect.construct(e,arguments,a)}else t=e.apply(this,arguments);return r(d[1])(this,t)});function o(t,e){var u;return r(d[3])(this,o),(u=a.call(this))._a=t,u._modulus=e,u}return r(d[4])(o,[{key:"__makeNative",value:function(){this._a.__makeNative(),r(d[5])(r(d[0])(o.prototype),"__makeNative",this).call(this)}},{key:"__getValue",value:function(){return(this._a.__getValue()%this._modulus+this._modulus)%this._modulus}},{key:"interpolate",value:function(t){return new(r(d[6]))(this,t)}},{key:"__attach",value:function(){this._a.__addChild(this)}},{key:"__detach",value:function(){this._a.__removeChild(this),r(d[5])(r(d[0])(o.prototype),"__detach",this).call(this)}},{key:"__getNativeConfig",value:function(){return{type:'modulus',input:this._a.__getNativeTag(),modulus:this._modulus}}}]),o})(r(d[7]));m.exports=e},633,[422,419,417,402,403,489,622,623]); -__d(function(g,r,i,_a,m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var e=(function(e){r(d[2])(_,e);var a,n,u=(a=_,n=t(),function(){var t,e=r(d[0])(a);if(n){var u=r(d[0])(this).constructor;t=Reflect.construct(e,arguments,u)}else t=e.apply(this,arguments);return r(d[1])(this,t)});function _(t,e,a){var n;return r(d[3])(this,_),(n=u.call(this))._a=t,n._min=e,n._max=a,n._value=n._lastValue=n._a.__getValue(),n}return r(d[4])(_,[{key:"__makeNative",value:function(){this._a.__makeNative(),r(d[5])(r(d[0])(_.prototype),"__makeNative",this).call(this)}},{key:"interpolate",value:function(t){return new(r(d[6]))(this,t)}},{key:"__getValue",value:function(){var t=this._a.__getValue(),e=t-this._lastValue;return this._lastValue=t,this._value=Math.min(Math.max(this._value+e,this._min),this._max),this._value}},{key:"__attach",value:function(){this._a.__addChild(this)}},{key:"__detach",value:function(){this._a.__removeChild(this),r(d[5])(r(d[0])(_.prototype),"__detach",this).call(this)}},{key:"__getNativeConfig",value:function(){return{type:'diffclamp',input:this._a.__getNativeTag(),min:this._min,max:this._max}}}]),_})(r(d[7]));m.exports=e},634,[422,419,417,402,403,489,622,623]); -__d(function(g,r,i,a,m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var e=(function(e){r(d[2])(u,e);var n,_,o=(n=u,_=t(),function(){var t,e=r(d[0])(n);if(_){var o=r(d[0])(this).constructor;t=Reflect.construct(e,arguments,o)}else t=e.apply(this,arguments);return r(d[1])(this,t)});function u(t,e,n,_,s){var l;return r(d[3])(this,u),(l=o.call(this))._value=t,l._parent=e,l._animationClass=n,l._animationConfig=_,l._useNativeDriver=r(d[4]).shouldUseNativeDriver(_),l._callback=s,l.__attach(),l}return r(d[5])(u,[{key:"__makeNative",value:function(){this.__isNative=!0,this._parent.__makeNative(),r(d[6])(r(d[0])(u.prototype),"__makeNative",this).call(this),this._value.__makeNative()}},{key:"__getValue",value:function(){return this._parent.__getValue()}},{key:"__attach",value:function(){this._parent.__addChild(this),this._useNativeDriver&&this.__makeNative()}},{key:"__detach",value:function(){this._parent.__removeChild(this),r(d[6])(r(d[0])(u.prototype),"__detach",this).call(this)}},{key:"update",value:function(){this._value.animate(new this._animationClass(r(d[7])({},this._animationConfig,{toValue:this._animationConfig.toValue.__getValue()})),this._callback)}},{key:"__getNativeConfig",value:function(){var t=new this._animationClass(r(d[7])({},this._animationConfig,{toValue:void 0})).__getNativeAnimationConfig();return{type:'tracking',animationId:r(d[4]).generateNewAnimationId(),animationConfig:t,toValue:this._parent.__getNativeTag(),value:this._value.__getNativeTag()}}}]),u})(r(d[8]));m.exports=e},635,[422,419,417,402,619,403,489,436,624]); -__d(function(g,r,i,a,_m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var s=(function(s){r(d[2])(l,s);var e,n,o=(e=l,n=t(),function(){var t,s=r(d[0])(e);if(n){var o=r(d[0])(this).constructor;t=Reflect.construct(s,arguments,o)}else t=s.apply(this,arguments);return r(d[1])(this,t)});function l(t){var s,e,n,h,_,u,f,c,m,v,p,y;if(r(d[3])(this,l),(m=o.call(this))._overshootClamping=null!=(s=t.overshootClamping)&&s,m._restDisplacementThreshold=null!=(e=t.restDisplacementThreshold)?e:.001,m._restSpeedThreshold=null!=(n=t.restSpeedThreshold)?n:.001,m._initialVelocity=null!=(h=t.velocity)?h:0,m._lastVelocity=null!=(_=t.velocity)?_:0,m._toValue=t.toValue,m._delay=null!=(u=t.delay)?u:0,m._useNativeDriver=r(d[4]).shouldUseNativeDriver(t),m.__isInteraction=null!=(f=t.isInteraction)?f:!m._useNativeDriver,m.__iterations=null!=(c=t.iterations)?c:1,void 0!==t.stiffness||void 0!==t.damping||void 0!==t.mass)r(d[5])(void 0===t.bounciness&&void 0===t.speed&&void 0===t.tension&&void 0===t.friction,'You can define one of bounciness/speed, tension/friction, or stiffness/damping/mass, but not more than one'),m._stiffness=null!=(v=t.stiffness)?v:100,m._damping=null!=(p=t.damping)?p:10,m._mass=null!=(y=t.mass)?y:1;else if(void 0!==t.bounciness||void 0!==t.speed){var V,T;r(d[5])(void 0===t.tension&&void 0===t.friction&&void 0===t.stiffness&&void 0===t.damping&&void 0===t.mass,'You can define one of bounciness/speed, tension/friction, or stiffness/damping/mass, but not more than one');var b=r(d[6]).fromBouncinessAndSpeed(null!=(V=t.bounciness)?V:8,null!=(T=t.speed)?T:12);m._stiffness=b.stiffness,m._damping=b.damping,m._mass=1}else{var M,D,P=r(d[6]).fromOrigamiTensionAndFriction(null!=(M=t.tension)?M:40,null!=(D=t.friction)?D:7);m._stiffness=P.stiffness,m._damping=P.damping,m._mass=1}return r(d[5])(m._stiffness>0,'Stiffness value must be greater than 0'),r(d[5])(m._damping>0,'Damping value must be greater than 0'),r(d[5])(m._mass>0,'Mass value must be greater than 0'),m}return r(d[7])(l,[{key:"__getNativeAnimationConfig",value:function(){var t;return{type:'spring',overshootClamping:this._overshootClamping,restDisplacementThreshold:this._restDisplacementThreshold,restSpeedThreshold:this._restSpeedThreshold,stiffness:this._stiffness,damping:this._damping,mass:this._mass,initialVelocity:null!=(t=this._initialVelocity)?t:this._lastVelocity,toValue:this._toValue,iterations:this.__iterations}}},{key:"start",value:function(t,s,e,n,o){var h=this;if(this.__active=!0,this._startPosition=t,this._lastPosition=this._startPosition,this._onUpdate=s,this.__onEnd=e,this._lastTime=Date.now(),this._frameTime=0,n instanceof l){var _=n.getInternalState();this._lastPosition=_.lastPosition,this._lastVelocity=_.lastVelocity,this._initialVelocity=this._lastVelocity,this._lastTime=_.lastTime}var u=function(){h._useNativeDriver?h.__startNativeAnimation(o):h.onUpdate()};this._delay?this._timeout=setTimeout(u,this._delay):u()}},{key:"getInternalState",value:function(){return{lastPosition:this._lastPosition,lastVelocity:this._lastVelocity,lastTime:this._lastTime}}},{key:"onUpdate",value:function(){var t=Date.now();t>this._lastTime+64&&(t=this._lastTime+64);var s=(t-this._lastTime)/1e3;this._frameTime+=s;var e=this._damping,n=this._mass,o=this._stiffness,l=-this._initialVelocity,h=e/(2*Math.sqrt(o*n)),_=Math.sqrt(o/n),u=_*Math.sqrt(1-h*h),f=this._toValue-this._startPosition,c=0,m=0,v=this._frameTime;if(h<1){var p=Math.exp(-h*_*v);c=this._toValue-p*((l+h*_*f)/u*Math.sin(u*v)+f*Math.cos(u*v)),m=h*_*p*(Math.sin(u*v)*(l+h*_*f)/u+f*Math.cos(u*v))-p*(Math.cos(u*v)*(l+h*_*f)-u*f*Math.sin(u*v))}else{var y=Math.exp(-_*v);c=this._toValue-y*(f+(l+_*f)*v),m=y*(l*(v*_-1)+v*f*(_*_))}if(this._lastTime=t,this._lastPosition=c,this._lastVelocity=m,this._onUpdate(c),this.__active){var V=!1;this._overshootClamping&&0!==this._stiffness&&(V=this._startPositionthis._toValue:c18&&A<=44?p(A):h(A),s(2*M-M*M,v,.01));return{stiffness:n(x),damping:t(B)}}}},637,[]); -__d(function(g,r,i,a,m,_e,d){'use strict';var t=1,n=(function(){function n(){r(d[0])(this,n)}return r(d[1])(n,[{key:"start",value:function(t,n,e,o,_){}},{key:"stop",value:function(){this.__nativeId&&r(d[2]).API.stopAnimation(this.__nativeId)}},{key:"__getNativeAnimationConfig",value:function(){throw new Error('This animation type cannot be offloaded to native')}},{key:"__debouncedOnEnd",value:function(t){var n=this.__onEnd;this.__onEnd=null,n&&n(t)}},{key:"__startNativeAnimation",value:function(n){var e=t+":startAnimation";t+=1,r(d[2]).API.setWaitingForIdentifier(e);try{n.__makeNative(),this.__nativeId=r(d[2]).generateNewAnimationId(),r(d[2]).API.startAnimatingNode(this.__nativeId,n.__getNativeTag(),this.__getNativeAnimationConfig(),this.__debouncedOnEnd.bind(this))}catch(t){throw t}finally{r(d[2]).API.unsetWaitingForIdentifier(e)}}}]),n})();m.exports=n},638,[402,403,619]); -__d(function(g,r,i,a,m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var e;function n(){if(!e){var t=r(d[2]);e=t.inOut(t.ease)}return e}var s=(function(e){r(d[3])(_,e);var s,o,u=(s=_,o=t(),function(){var t,e=r(d[0])(s);if(o){var n=r(d[0])(this).constructor;t=Reflect.construct(e,arguments,n)}else t=e.apply(this,arguments);return r(d[1])(this,t)});function _(t){var e,s,o,h,l,c;return r(d[4])(this,_),(c=u.call(this))._toValue=t.toValue,c._easing=null!=(e=t.easing)?e:n(),c._duration=null!=(s=t.duration)?s:500,c._delay=null!=(o=t.delay)?o:0,c.__iterations=null!=(h=t.iterations)?h:1,c._useNativeDriver=r(d[5]).shouldUseNativeDriver(t),c.__isInteraction=null!=(l=t.isInteraction)?l:!c._useNativeDriver,c}return r(d[6])(_,[{key:"__getNativeAnimationConfig",value:function(){for(var t=[],e=Math.round(this._duration/16.666666666666668),n=0;n=this._startTime+this._duration)return 0===this._duration?this._onUpdate(this._toValue):this._onUpdate(this._fromValue+this._easing(1)*(this._toValue-this._fromValue)),void this.__debouncedOnEnd({finished:!0});this._onUpdate(this._fromValue+this._easing((t-this._startTime)/this._duration)*(this._toValue-this._fromValue)),this.__active&&(this._animationFrame=requestAnimationFrame(this.onUpdate.bind(this)))}},{key:"stop",value:function(){r(d[7])(r(d[0])(_.prototype),"stop",this).call(this),this.__active=!1,clearTimeout(this._timeout),g.cancelAnimationFrame(this._animationFrame),this.__debouncedOnEnd({finished:!1})}}]),_})(r(d[8]));m.exports=s},639,[422,419,640,417,402,619,403,489,638]); -__d(function(g,r,i,a,m,e,d){'use strict';var n,u=(function(){function u(){r(d[0])(this,u)}return r(d[1])(u,null,[{key:"step0",value:function(n){return n>0?1:0}},{key:"step1",value:function(n){return n>=1?1:0}},{key:"linear",value:function(n){return n}},{key:"ease",value:function(t){return n||(n=u.bezier(.42,0,1,1)),n(t)}},{key:"quad",value:function(n){return n*n}},{key:"cubic",value:function(n){return n*n*n}},{key:"poly",value:function(n){return function(u){return Math.pow(u,n)}}},{key:"sin",value:function(n){return 1-Math.cos(n*Math.PI/2)}},{key:"circle",value:function(n){return 1-Math.sqrt(1-n*n)}},{key:"exp",value:function(n){return Math.pow(2,10*(n-1))}},{key:"elastic",value:function(){var n=(arguments.length>0&&void 0!==arguments[0]?arguments[0]:1)*Math.PI;return function(u){return 1-Math.pow(Math.cos(u*Math.PI/2),3)*Math.cos(u*n)}}},{key:"back",value:function(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1.70158;return function(u){return u*u*((n+1)*u-n)}}},{key:"bounce",value:function(n){if(n<.36363636363636365)return 7.5625*n*n;if(n<.7272727272727273){var u=n-.5454545454545454;return 7.5625*u*u+.75}if(n<.9090909090909091){var t=n-.8181818181818182;return 7.5625*t*t+.9375}var o=n-.9545454545454546;return 7.5625*o*o+.984375}},{key:"bezier",value:function(n,u,t,o){return r(d[2])(n,u,t,o)}},{key:"in",value:function(n){return n}},{key:"out",value:function(n){return function(u){return 1-n(1-u)}}},{key:"inOut",value:function(n){return function(u){return u<.5?n(2*u)/2:1-n(2*(1-u))/2}}}]),u})();m.exports=u},640,[402,403,641]); -__d(function(g,r,_i,a,m,e,d){'use strict';var n=4,t=.001,u=1e-7,o=10,f=.1,i='function'==typeof Float32Array;function c(n,t){return 1-3*t+3*n}function v(n,t){return 3*t-6*n}function s(n){return 3*n}function w(n,t,u){return((c(t,u)*n+v(t,u))*n+s(t))*n}function l(n,t,u){return 3*c(t,u)*n*n+2*v(t,u)*n+s(t)}function y(n,t,f,i,c){var v,s,l=0,y=t,b=f;do{(v=w(s=y+(b-y)/2,i,c)-n)>0?b=s:y=s}while(Math.abs(v)>u&&++l=0&&n<=1&&o>=0&&o<=1))throw new Error('bezier x values must be in [0, 1] range');var v=i?new Float32Array(11):new Array(11);if(n!==u||o!==c)for(var s=0;s<11;++s)v[s]=w(s*f,n,o);function h(u){for(var i=0,c=1;10!==c&&v[c]<=u;++c)i+=f;var s=i+(u-v[--c])/(v[c+1]-v[c])*f,w=l(s,n,o);return w>=t?b(u,s,n,o):0===w?s:y(u,i,i+f,n,o)}return function(t){return n===u&&o===c?t:0===t?0:1===t?1:w(h(t),u,c)}}},641,[]); -__d(function(g,r,i,a,m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var e=(function(e){r(d[2])(c,e);var n,s,o=(n=c,s=t(),function(){var t,e=r(d[0])(n);if(s){var o=r(d[0])(this).constructor;t=Reflect.construct(e,arguments,o)}else t=e.apply(this,arguments);return r(d[1])(this,t)});function c(t){var e,n,s,u;return r(d[3])(this,c),(u=o.call(this))._deceleration=null!=(e=t.deceleration)?e:.998,u._velocity=t.velocity,u._useNativeDriver=r(d[4]).shouldUseNativeDriver(t),u.__isInteraction=null!=(n=t.isInteraction)?n:!u._useNativeDriver,u.__iterations=null!=(s=t.iterations)?s:1,u}return r(d[5])(c,[{key:"__getNativeAnimationConfig",value:function(){return{type:'decay',deceleration:this._deceleration,velocity:this._velocity,iterations:this.__iterations}}},{key:"start",value:function(t,e,n,s,o){this.__active=!0,this._lastValue=t,this._fromValue=t,this._onUpdate=e,this.__onEnd=n,this._startTime=Date.now(),this._useNativeDriver?this.__startNativeAnimation(o):this._animationFrame=requestAnimationFrame(this.onUpdate.bind(this))}},{key:"onUpdate",value:function(){var t=Date.now(),e=this._fromValue+this._velocity/(1-this._deceleration)*(1-Math.exp(-(1-this._deceleration)*(t-this._startTime)));this._onUpdate(e),Math.abs(this._lastValue-e)<.1?this.__debouncedOnEnd({finished:!0}):(this._lastValue=e,this.__active&&(this._animationFrame=requestAnimationFrame(this.onUpdate.bind(this))))}},{key:"stop",value:function(){r(d[6])(r(d[0])(c.prototype),"stop",this).call(this),this.__active=!1,g.cancelAnimationFrame(this._animationFrame),this.__debouncedOnEnd({finished:!1})}}]),c})(r(d[7]));m.exports=e},642,[422,419,417,402,619,403,489,638]); -__d(function(g,r,i,a,m,e,d){'use strict';function t(t,n,s){var v=[];r(d[1])(s[0]&&s[0].nativeEvent,'Native driven events only support animated values contained inside `nativeEvent`.'),(function t(n,s){if(n instanceof r(d[0]))n.__makeNative(),v.push({nativeEventPath:s,animatedValueTag:n.__getNativeTag()});else if('object'==typeof n)for(var o in n)t(n[o],s.concat(o))})(s[0].nativeEvent,[]);var o=r(d[2]).findNodeHandle(t);return null!=o&&v.forEach(function(t){r(d[3]).API.addAnimatedEventToView(o,n,t)}),{detach:function(){null!=o&&v.forEach(function(t){r(d[3]).API.removeAnimatedEventFromView(o,n,t.animatedValueTag)})}}}var n=(function(){function n(t,s){r(d[4])(this,n),this._listeners=[],this._argMapping=t,null==s&&(console.warn('Animated.event now requires a second argument for options'),s={useNativeDriver:!1}),s.listener&&this.__addListener(s.listener),this._callListeners=this._callListeners.bind(this),this._attachedEvent=null,this.__isNative=r(d[3]).shouldUseNativeDriver(s)}return r(d[5])(n,[{key:"__addListener",value:function(t){this._listeners.push(t)}},{key:"__removeListener",value:function(t){this._listeners=this._listeners.filter(function(n){return n!==t})}},{key:"__attach",value:function(n,s){r(d[1])(this.__isNative,'Only native driven events need to be attached.'),this._attachedEvent=t(n,s,this._argMapping)}},{key:"__detach",value:function(t,n){r(d[1])(this.__isNative,'Only native driven events need to be detached.'),this._attachedEvent&&this._attachedEvent.detach()}},{key:"__getHandler",value:function(){var t=this;if(this.__isNative)return this._callListeners;return function(){for(var n=arguments.length,s=new Array(n),v=0;v1){for(var l=[],s=0;s1?Math.ceil(e.length/n):e.length}return 0},t._keyExtractor=function(e,n){var o,l=v(t.props.numColumns),s=null!=(o=t.props.keyExtractor)?o:r(d[10]).keyExtractor;return l>1?Array.isArray(e)?e.map(function(e,t){return s(e,n*l+t)}).join(':'):void r(d[11])(Array.isArray(e),"FlatList: Encountered internal consistency error, expected each item to consist of an array with 1-%s columns; instead, received a single item.",l):s(e,n)},t._renderer=function(){var e=t.props,o=e.ListItemComponent,l=e.renderItem,s=e.columnWrapperStyle,u=v(t.props.numColumns),c=o?'ListItemComponent':'renderItem',f=function(e){return o?h.createElement(o,e):l?l(e):null};return(0,n.default)({},c,function(e){if(u>1){var t=e.item,n=e.index;return r(d[11])(Array.isArray(t),'Expected array of items with numColumns > 1'),h.createElement(r(d[12]),{style:r(d[13]).compose(y.row,s)},t.map(function(t,o){var l=f({item:t,index:n*u+o,separators:e.separators});return null!=l?h.createElement(h.Fragment,{key:o},l):null}))}return f(e)})},t._checkProps(t.props),t.props.viewabilityConfigCallbackPairs?t._virtualizedListPairs=t.props.viewabilityConfigCallbackPairs.map(function(e){return{viewabilityConfig:e.viewabilityConfig,onViewableItemsChanged:t._createOnViewableItemsChanged(e.onViewableItemsChanged)}}):t.props.onViewableItemsChanged&&t._virtualizedListPairs.push({viewabilityConfig:t.props.viewabilityConfig,onViewableItemsChanged:t._createOnViewableItemsChanged(t.props.onViewableItemsChanged)}),t}return(0,l.default)(k,[{key:"scrollToEnd",value:function(e){this._listRef&&this._listRef.scrollToEnd(e)}},{key:"scrollToIndex",value:function(e){this._listRef&&this._listRef.scrollToIndex(e)}},{key:"scrollToItem",value:function(e){this._listRef&&this._listRef.scrollToItem(e)}},{key:"scrollToOffset",value:function(e){this._listRef&&this._listRef.scrollToOffset(e)}},{key:"recordInteraction",value:function(){this._listRef&&this._listRef.recordInteraction()}},{key:"flashScrollIndicators",value:function(){this._listRef&&this._listRef.flashScrollIndicators()}},{key:"getScrollResponder",value:function(){if(this._listRef)return this._listRef.getScrollResponder()}},{key:"getNativeScrollRef",value:function(){if(this._listRef)return this._listRef.getScrollRef()}},{key:"getScrollableNode",value:function(){if(this._listRef)return this._listRef.getScrollableNode()}},{key:"setNativeProps",value:function(e){this._listRef&&this._listRef.setNativeProps(e)}},{key:"componentDidUpdate",value:function(e){r(d[11])(e.numColumns===this.props.numColumns,"Changing numColumns on the fly is not supported. Change the key prop on FlatList when changing the number of columns to force a fresh render of the component."),r(d[11])(e.onViewableItemsChanged===this.props.onViewableItemsChanged,'Changing onViewableItemsChanged on the fly is not supported'),r(d[11])(!r(d[14])(e.viewabilityConfig,this.props.viewabilityConfig),'Changing viewabilityConfig on the fly is not supported'),r(d[11])(e.viewabilityConfigCallbackPairs===this.props.viewabilityConfigCallbackPairs,'Changing viewabilityConfigCallbackPairs on the fly is not supported'),this._checkProps(this.props)}},{key:"_checkProps",value:function(e){var t=e.getItem,n=e.getItemCount,o=e.horizontal,l=e.columnWrapperStyle,s=e.onViewableItemsChanged,u=e.viewabilityConfigCallbackPairs,c=v(this.props.numColumns);r(d[11])(!t&&!n,'FlatList does not support custom data formats.'),c>1?r(d[11])(!o,'numColumns does not support horizontal.'):r(d[11])(!l,'columnWrapperStyle not supported for single column lists'),r(d[11])(!(s&&u),"FlatList does not support setting both onViewableItemsChanged and viewabilityConfigCallbackPairs.")}},{key:"_pushMultiColumnViewable",value:function(e,n){var o,l=v(this.props.numColumns),s=null!=(o=this.props.keyExtractor)?o:r(d[10]).keyExtractor;n.item.forEach(function(o,u){r(d[11])(null!=n.index,'Missing index!');var c=n.index*l+u;e.push((0,t.default)({},n,{item:o,key:s(o,c),index:c}))})}},{key:"_createOnViewableItemsChanged",value:function(e){var t=this;return function(n){var o=v(t.props.numColumns);if(e)if(o>1){var l=[],s=[];n.viewableItems.forEach(function(e){return t._pushMultiColumnViewable(s,e)}),n.changed.forEach(function(e){return t._pushMultiColumnViewable(l,e)}),e({viewableItems:s,changed:l})}else e(n)}}},{key:"render",value:function(){var n,o=this.props,l=(o.numColumns,o.columnWrapperStyle,o.removeClippedSubviews),s=(0,e.default)(o,f);return h.createElement(r(d[15]),(0,t.default)({},s,{getItem:this._getItem,getItemCount:this._getItemCount,keyExtractor:this._keyExtractor,ref:this._captureRef,viewabilityConfigCallbackPairs:this._virtualizedListPairs,removeClippedSubviews:(n=l,null==n||n)},this._renderer()))}}]),k})(h.PureComponent),y=r(d[13]).create({row:{flexDirection:'row'}});m.exports=C},651,[407,508,436,652,402,403,417,419,422,534,653,425,579,578,571,654]); -__d(function(g,r,i,a,m,e,d){m.exports=function(t,n,o){return n in t?Object.defineProperty(t,n,{value:o,enumerable:!0,configurable:!0,writable:!0}):t[n]=o,t},m.exports.__esModule=!0,m.exports.default=m.exports},652,[]); -__d(function(g,r,i,a,m,e,d){'use strict';Object.defineProperty(e,"__esModule",{value:!0}),e.computeWindowedRenderLimits=function(n,s,o,u,c,h,v){var b=s(n);if(0===b)return c;var M=v.offset,y=v.velocity,x=v.visibleLength,p=Math.max(0,M),w=p+x,O=(u-1)*x,k=y>1?'after':y<-1?'before':'none',_=Math.max(0,p-.5*O),j=Math.max(0,w+.5*O);if(h(b-1).offset<_)return{first:Math.max(0,b-1-o),last:b-1};var L=f([_,p,w,j],b,h),S=(0,t.default)(L,4),C=S[0],E=S[1],J=S[2],N=S[3];C=null==C?0:C,E=null==E?Math.max(0,C):E,N=null==N?b-1:N,J=null==J?Math.min(N,E+o-1):J;var R={first:E,last:J},B=l(c,R);for(;!(E<=C&&J>=N);){var F=B>=o,P=E<=c.first||E>c.last,T=E>C&&(!F||!P),W=J>=c.last||J=E&&E>=0&&J=C&&J<=N&&E<=R.first&&J>=R.last))throw new Error('Bad window calculation '+JSON.stringify({first:E,last:J,itemCount:b,overscanFirst:C,overscanLast:N,visible:R}));return{first:E,last:J}},e.elementsThatOverlapOffsets=f,e.keyExtractor=function(t,n){if('object'==typeof t&&null!=(null==t?void 0:t.key))return t.key;if('object'==typeof t&&null!=(null==t?void 0:t.id))return t.id;return String(n)},e.newRangeCount=l;var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2]));function f(t,f,l){for(var s=[],o=0,u=0;u=t[v]&&(s[v]=u,o++,v===t.length-1))return(0,n.default)(o===t.length,'bad offsets input, should be in increasing order: %s',JSON.stringify(t)),s;return s}function l(t,n){return n.last-n.first+1-Math.max(0,1+Math.min(n.last,t.last)-Math.max(n.first,t.first))}},653,[407,430,425]); -__d(function(g,r,_i,a,m,_e,d){var e=r(d[0])(r(d[1])),t=r(d[0])(r(d[2])),o=r(d[0])(r(d[3])),n=r(d[0])(r(d[4])),s=r(d[0])(r(d[5])),i=r(d[0])(r(d[6])),l=r(d[0])(r(d[7])),c=r(d[0])(r(d[8])),h=(function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var o=u(t);if(o&&o.has(e))return o.get(e);var n={},s=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var i in e)if("default"!==i&&Object.prototype.hasOwnProperty.call(e,i)){var l=s?Object.getOwnPropertyDescriptor(e,i):null;l&&(l.get||l.set)?Object.defineProperty(n,i,l):n[i]=e[i]}n.default=e,o&&o.set(e,n);return n})(r(d[9]));function u(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,o=new WeakMap;return(u=function(e){return e?o:t})(e)}function p(e,t){var o="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(o)return(o=o.call(e)).next.bind(o);if(Array.isArray(e)||(o=f(e))||t&&e&&"number"==typeof e.length){o&&(e=o);var n=0;return function(){return n>=e.length?{done:!0}:{done:!1,value:e[n++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function f(e,t){if(e){if("string"==typeof e)return _(e,t);var o=Object.prototype.toString.call(e).slice(8,-1);return"Object"===o&&e.constructor&&(o=e.constructor.name),"Map"===o||"Set"===o?Array.from(e):"Arguments"===o||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(o)?_(e,t):void 0}}function _(e,t){(null==t||t>e.length)&&(t=e.length);for(var o=0,n=new Array(t);o0&&t>0&&null!=i.props.initialScrollIndex&&i.props.initialScrollIndex>0&&!i._hasDoneInitialScroll&&(null==i.props.contentOffset&&i.scrollToIndex({animated:!1,index:i.props.initialScrollIndex}),i._hasDoneInitialScroll=!0),i.props.onContentSizeChange&&i.props.onContentSizeChange(e,t),i._scrollMetrics.contentLength=i._selectLength({height:t,width:e}),i._scheduleCellsToRenderUpdate(),i._maybeCallOnEndReached()},i._convertParentScrollMetrics=function(e){var t=e.offset-i._offsetFromParentVirtualizedList,o=e.visibleLength,n=t-i._scrollMetrics.offset;return{visibleLength:o,contentLength:i._scrollMetrics.contentLength,offset:t,dOffset:n}},i._onScroll=function(e){i._nestedChildLists.forEach(function(t){t.ref&&t.ref._onScroll(e)}),i.props.onScroll&&i.props.onScroll(e);var t=e.timeStamp,o=i._selectLength(e.nativeEvent.layoutMeasurement),n=i._selectLength(e.nativeEvent.contentSize),s=i._selectOffset(e.nativeEvent.contentOffset),l=s-i._scrollMetrics.offset;if(i._isNestedWithSameOrientation()){if(0===i._scrollMetrics.contentLength)return;var c=i._convertParentScrollMetrics({visibleLength:o,offset:s});o=c.visibleLength,n=c.contentLength,s=c.offset,l=c.dOffset}var h=i._scrollMetrics.timestamp?Math.max(1,t-i._scrollMetrics.timestamp):1,u=l/h;h>500&&i._scrollMetrics.dt>500&&n>5*o&&!i._hasWarned.perf&&(r(d[14])("VirtualizedList: You have a large list that is slow to update - make sure your renderItem function renders components that follow React performance best practices like PureComponent, shouldComponentUpdate, etc.",{dt:h,prevDt:i._scrollMetrics.dt,contentLength:n}),i._hasWarned.perf=!0),i._scrollMetrics={contentLength:n,dt:h,dOffset:l,offset:s,timestamp:t,velocity:u,visibleLength:o},i._updateViewableItems(i.props.data),i.props&&(i._maybeCallOnEndReached(),0!==u&&i._fillRateHelper.activate(),i._computeBlankness(),i._scheduleCellsToRenderUpdate())},i._onScrollBeginDrag=function(e){i._nestedChildLists.forEach(function(t){t.ref&&t.ref._onScrollBeginDrag(e)}),i._viewabilityTuples.forEach(function(e){e.viewabilityHelper.recordInteraction()}),i._hasInteracted=!0,i.props.onScrollBeginDrag&&i.props.onScrollBeginDrag(e)},i._onScrollEndDrag=function(e){i._nestedChildLists.forEach(function(t){t.ref&&t.ref._onScrollEndDrag(e)});var t=e.nativeEvent.velocity;t&&(i._scrollMetrics.velocity=i._selectOffset(t)),i._computeBlankness(),i.props.onScrollEndDrag&&i.props.onScrollEndDrag(e)},i._onMomentumScrollBegin=function(e){i._nestedChildLists.forEach(function(t){t.ref&&t.ref._onMomentumScrollBegin(e)}),i.props.onMomentumScrollBegin&&i.props.onMomentumScrollBegin(e)},i._onMomentumScrollEnd=function(e){i._nestedChildLists.forEach(function(t){t.ref&&t.ref._onMomentumScrollEnd(e)}),i._scrollMetrics.velocity=0,i._computeBlankness(),i.props.onMomentumScrollEnd&&i.props.onMomentumScrollEnd(e)},i._updateCellsToRender=function(){var e=i.props,t=e.data,o=e.getItemCount,n=M(e.onEndReachedThreshold),s=i._isVirtualizationDisabled();i._updateViewableItems(t),t&&i.setState(function(e){var l,c=i._scrollMetrics,h=c.contentLength,u=c.offset,f=c.visibleLength;if(s){var _=h-f-u0&&h>0&&(i.props.initialScrollIndex&&!i._scrollMetrics.offset||(l=(0,r(d[15]).computeWindowedRenderLimits)(i.props.data,i.props.getItemCount,I(i.props.maxToRenderPerBatch),R(i.props.windowSize),e,i._getFrameMetricsApprox,i._scrollMetrics)));if(l&&i._nestedChildLists.size>0)for(var y=l.first,v=l.last,C=y;C<=v;C++){var L=i._indicesToKeys.get(C),b=L&&i._cellKeysToChildListKeys.get(L);if(b){for(var S,M=!1,x=p(b);!(S=x()).done;){var w=S.value,k=i._nestedChildLists.get(w);if(k&&k.ref&&k.ref.hasMore()){M=!0;break}}if(M){l.last=C;break}}}return null!=l&&l.first===e.first&&l.last===e.last&&(l=null),l})},i._createViewToken=function(e,t){var o=i.props,n=o.data,s=(0,o.getItem)(n,e);return{index:e,item:s,key:i._keyExtractor(s,e),isViewable:t}},i._getFrameMetricsApprox=function(e){var t=i._getFrameMetrics(e);if(t&&t.index===e)return t;var o=i.props.getItemLayout;return r(d[11])(!o,'Should not have to estimate frames when a measurement metrics function is provided'),{length:i._averageCellLength,offset:i._averageCellLength*e}},i._getFrameMetrics=function(e){var t=i.props,o=t.data,n=t.getItem,s=t.getItemCount,l=t.getItemLayout;r(d[11])(s(o)>e,'Tried to get frame for out of range index '+e);var c=n(o,e),h=c&&i._frames[i._keyExtractor(c,e)];return h&&h.index===e||l&&(h=l(o,e)),h},r(d[11])(!e.onScroll||!e.onScroll.__isNative,"Components based on VirtualizedList must be wrapped with Animated.createAnimatedComponent to support native onScroll events with useNativeDriver"),r(d[11])(R(e.windowSize)>0,'VirtualizedList: The windowSize prop must be present and set to a value greater than 0.'),i._fillRateHelper=new(r(d[16]))(i._getFrameMetrics),i._updateCellsToRenderBatcher=new(r(d[17]))(i._updateCellsToRender,null!=(n=i.props.updateCellsBatchingPeriod)?n:50),i.props.viewabilityConfigCallbackPairs?i._viewabilityTuples=i.props.viewabilityConfigCallbackPairs.map(function(e){return{viewabilityHelper:new(r(d[18]))(e.viewabilityConfig),onViewableItemsChanged:e.onViewableItemsChanged}}):i.props.onViewableItemsChanged&&i._viewabilityTuples.push({viewabilityHelper:new(r(d[18]))(i.props.viewabilityConfig),onViewableItemsChanged:i.props.onViewableItemsChanged});var l={first:i.props.initialScrollIndex||0,last:Math.min(i.props.getItemCount(i.props.data),(i.props.initialScrollIndex||0)+S(i.props.initialNumToRender))-1};if(i._isNestedWithSameOrientation()){var f=i.context.getNestedChildState(i._getListKey());f&&(l=f,i.state=f,i._frames=f.frames)}return i.state=l,i}return(0,n.default)(u,[{key:"scrollToEnd",value:function(e){var t=!e||e.animated,o=this.props.getItemCount(this.props.data)-1,n=this._getFrameMetricsApprox(o),s=Math.max(0,n.offset+n.length+this._footerLength-this._scrollMetrics.visibleLength);null!=this._scrollRef&&(null!=this._scrollRef.scrollTo?this._scrollRef.scrollTo(b(this.props.horizontal)?{x:s,animated:t}:{y:s,animated:t}):console.warn("No scrollTo method provided. This may be because you have two nested VirtualizedLists with the same orientation, or because you are using a custom component that does not implement scrollTo."))}},{key:"scrollToIndex",value:function(e){var t=this.props,o=t.data,n=t.horizontal,s=t.getItemCount,i=t.getItemLayout,l=t.onScrollToIndexFailed,c=e.animated,h=e.index,u=e.viewOffset,p=e.viewPosition;if(r(d[11])(h>=0,"scrollToIndex out of range: requested index "+h+" but minimum is 0"),r(d[11])(s(o)>=1,"scrollToIndex out of range: item length "+s(o)+" but minimum is 1"),r(d[11])(hthis._highestMeasuredFrameIndex)return r(d[11])(!!l,"scrollToIndex should be used in conjunction with getItemLayout or onScrollToIndexFailed, otherwise there is no way to know the location of offscreen indices or handle failures."),void l({averageItemLength:this._averageCellLength,highestMeasuredFrameIndex:this._highestMeasuredFrameIndex,index:h});var f=this._getFrameMetricsApprox(h),_=Math.max(0,f.offset-(p||0)*(this._scrollMetrics.visibleLength-f.length))-(u||0);null!=this._scrollRef&&(null!=this._scrollRef.scrollTo?this._scrollRef.scrollTo(n?{x:_,animated:c}:{y:_,animated:c}):console.warn("No scrollTo method provided. This may be because you have two nested VirtualizedLists with the same orientation, or because you are using a custom component that does not implement scrollTo."))}},{key:"scrollToItem",value:function(e){for(var o=e.item,n=this.props,s=n.data,i=n.getItem,l=(0,n.getItemCount)(s),c=0;c0){C=!1,L='';var x=this._getSpacerKey(!p),w=this.props.initialScrollIndex?-1:S(this.props.initialNumToRender)-1,k=this.state,T=k.first,z=k.last;this._pushCells(y,I,v,0,w,_);var K=Math.max(w+1,T);if(!f&&T>w+1){var O=!1;if(v.size>0)for(var P=l?1:0,F=K-1;F>w;F--)if(v.has(F+P)){var V=this._getFrameMetricsApprox(w),D=this._getFrameMetricsApprox(F),N=D.offset-V.offset-(this.props.initialScrollIndex?0:V.length);y.push(h.createElement(r(d[10]),{key:"$sticky_lead",style:(0,e.default)({},x,N)})),this._pushCells(y,I,v,F,F,_);var A=this._getFrameMetricsApprox(T).offset-(D.offset+D.length);y.push(h.createElement(r(d[10]),{key:"$sticky_trail",style:(0,e.default)({},x,A)})),O=!0;break}if(!O){var B=this._getFrameMetricsApprox(w),H=this._getFrameMetricsApprox(T).offset-(B.offset+B.length);y.push(h.createElement(r(d[10]),{key:"$lead_spacer",style:(0,e.default)({},x,H)}))}}if(this._pushCells(y,I,v,K,z,_),!this._hasWarned.keys&&C&&(console.warn("VirtualizedList: missing keys for items, make sure to specify a key or id property on each item or provide a custom keyExtractor.",L),this._hasWarned.keys=!0),!f&&zu&&(this._sentEndForContentLength=0)}},{key:"_scheduleCellsToRenderUpdate",value:function(){var e=this.state,t=e.first,o=e.last,n=this._scrollMetrics,s=n.offset,i=n.visibleLength,l=n.velocity,c=this.props.getItemCount(this.props.data),h=!1,u=M(this.props.onEndReachedThreshold)*i/2;if(t>0){var p=s-this._getFrameMetricsApprox(t).offset;h=h||p<0||l<-2&&p2&&f0&&(this._scrollAnimatedValueAttachment=p.default.attachNativeEvent(this._scrollViewRef,'onScroll',[{nativeEvent:{contentOffset:{y:this._scrollAnimatedValue}}}]))}},{key:"_setStickyHeaderRef",value:function(e,o){o?this._stickyHeaderRefs.set(e,o):this._stickyHeaderRefs.delete(e)}},{key:"_onStickyHeaderLayout",value:function(e,o,t){var n=this.props.stickyHeaderIndices;if(n){var l=y.Children.toArray(this.props.children);if(t===this._getKeyForIndex(e,l)){var s=o.nativeEvent.layout.y;this._headerLayoutYs.set(t,s);var u=n[n.indexOf(e)-1];if(null!=u){var c=this._stickyHeaderRefs.get(this._getKeyForIndex(u,l));c&&c.setNextHeaderY&&c.setNextHeaderY(s)}}}}},{key:"render",value:function(){var t=this,n=!0===this.props.horizontal?P:F,l=(0,o.default)(n,2),s=l[0],u=l[1],c=[!0===this.props.horizontal&&Y.contentContainerHorizontal,this.props.contentContainerStyle],p=null==this.props.onContentSizeChange?null:{onLayout:this._handleContentOnLayout},f=this.props.stickyHeaderIndices,S=this.props.children;if(null!=f&&f.length>0){var b=y.Children.toArray(this.props.children);S=b.map(function(e,o){var n=e?f.indexOf(o):-1;if(n>-1){var l=e.key,s=f[n+1],u=t.props.StickyHeaderComponent||_.default;return y.createElement(u,{key:l,nativeID:'StickyHeader-'+l,ref:function(e){return t._setStickyHeaderRef(l,e)},nextHeaderLayoutY:t._headerLayoutYs.get(t._getKeyForIndex(s,b)),onLayout:function(e){return t._onStickyHeaderLayout(o,e,l)},scrollAnimatedValue:t._scrollAnimatedValue,inverted:t.props.invertStickyHeaders,hiddenOnScroll:t.props.stickyHeaderHiddenOnScroll,scrollViewHeight:t.state.layoutHeight},e)}return e})}S=y.createElement(D.default.Provider,{value:!0===this.props.horizontal?D.HORIZONTAL:D.VERTICAL},S);var R=Array.isArray(f)&&f.length>0,T=y.createElement(u,(0,e.default)({},p,{ref:this._setInnerViewRef,style:c,removeClippedSubviews:('android'!==h.default.OS||!R)&&this.props.removeClippedSubviews,collapsable:!1}),S),w=void 0!==this.props.alwaysBounceHorizontal?this.props.alwaysBounceHorizontal:this.props.horizontal,V=void 0!==this.props.alwaysBounceVertical?this.props.alwaysBounceVertical:!this.props.horizontal,k=!0===this.props.horizontal?Y.baseHorizontal:Y.baseVertical,E=(0,e.default)({},this.props,{alwaysBounceHorizontal:w,alwaysBounceVertical:V,style:v.default.compose(k,this.props.style),onContentSizeChange:null,onLayout:this._handleLayout,onMomentumScrollBegin:this._handleMomentumScrollBegin,onMomentumScrollEnd:this._handleMomentumScrollEnd,onResponderGrant:this._handleResponderGrant,onResponderReject:this._handleResponderReject,onResponderRelease:this._handleResponderRelease,onResponderTerminationRequest:this._handleResponderTerminationRequest,onScrollBeginDrag:this._handleScrollBeginDrag,onScrollEndDrag:this._handleScrollEndDrag,onScrollShouldSetResponder:this._handleScrollShouldSetResponder,onStartShouldSetResponder:this._handleStartShouldSetResponder,onStartShouldSetResponderCapture:this._handleStartShouldSetResponderCapture,onTouchEnd:this._handleTouchEnd,onTouchMove:this._handleTouchMove,onTouchStart:this._handleTouchStart,onTouchCancel:this._handleTouchCancel,onScroll:this._handleScroll,scrollEventThrottle:R?1:this.props.scrollEventThrottle,sendMomentumEvents:!(!this.props.onMomentumScrollBegin&&!this.props.onMomentumScrollEnd),snapToStart:!1!==this.props.snapToStart,snapToEnd:!1!==this.props.snapToEnd,pagingEnabled:h.default.select({ios:!0===this.props.pagingEnabled&&null==this.props.snapToInterval&&null==this.props.snapToOffsets,android:!0===this.props.pagingEnabled||null!=this.props.snapToInterval||null!=this.props.snapToOffsets})}),K=this.props.decelerationRate;null!=K&&(E.decelerationRate=(0,O.default)(K));var A=this.props.refreshControl;if(A){if('ios'===h.default.OS)return y.createElement(s,(0,e.default)({},E,{ref:this._setNativeRef}),A,T);if('android'===h.default.OS){var N=(0,I.default)((0,H.default)(E.style)),M=N.outer,W=N.inner;return y.cloneElement(A,{style:v.default.compose(k,M)},y.createElement(s,(0,e.default)({},E,{style:v.default.compose(k,W),ref:this._setNativeRef}),T))}}return y.createElement(s,(0,e.default)({},E,{ref:this._setNativeRef}),T)}}]),x})(y.Component);G.Context=D.default;var Y=v.default.create({baseVertical:{flexGrow:1,flexShrink:1,flexDirection:'column',overflow:'scroll'},baseHorizontal:{flexGrow:1,flexShrink:1,flexDirection:'row',overflow:'scroll'},contentContainerHorizontal:{flexDirection:'row'}});function U(o,t){return y.createElement(G,(0,e.default)({},o,{scrollViewRef:t}))}U.displayName='ScrollView';var Z=y.forwardRef(U);Z.Context=D.default,Z.displayName='ScrollView',m.exports=Z},655,[407,436,430,402,403,421,417,419,422,628,566,426,534,456,656,578,579,450,657,661,540,659,573,425,663,664,646,665,666,667,668,669,670]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),u=r(d[0])(r(d[3])),l=r(d[0])(r(d[4])),o=r(d[0])(r(d[5])),f=(function(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var u=s(n);if(u&&u.has(t))return u.get(t);var l={},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var f in t)if("default"!==f&&Object.prototype.hasOwnProperty.call(t,f)){var c=o?Object.getOwnPropertyDescriptor(t,f):null;c&&(c.get||c.set)?Object.defineProperty(l,f,c):l[f]=t[f]}l.default=t,u&&u.set(t,l);return l})(r(d[6]));function s(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,u=new WeakMap;return(s=function(t){return t?u:n})(t)}var c=o.default.View,p=f.forwardRef(function(l,s){var p=l.inverted,h=l.scrollViewHeight,y=l.hiddenOnScroll,R=l.scrollAnimatedValue,O=l.nextHeaderLayoutY,L=f.useState(!1),b=(0,t.default)(L,2),w=b[0],S=b[1],j=f.useState(0),E=(0,t.default)(j,2),P=E[0],_=E[1],x=f.useState(0),M=(0,t.default)(x,2),k=M[0],C=M[1],D=f.useState(null),H=(0,t.default)(D,2),I=H[0],V=H[1],Y=f.useState(O),T=(0,t.default)(Y,2),W=T[0],A=T[1],N=f.useState(!1),z=(0,t.default)(N,2),F=z[0],q=z[1],B=f.useRef(),G=(0,n.default)({getForwardedRef:function(){return s},setLocalRef:function(t){var n,u;(B.current=t,t)&&(t.setNextHeaderY=function(t){A(t)},q(!(null==(n=t._internalInstanceHandle)||null==(u=n.stateNode)||!u.canonical)))}}),J=(0,f.useMemo)(function(){return!0===y?o.default.diffClamp(R.interpolate({extrapolateLeft:'clamp',inputRange:[P,P+1],outputRange:[0,1]}).interpolate({inputRange:[0,1],outputRange:[0,-1]}),-k,0):null},[R,k,P,y]),K=f.useState(function(){var t=R.interpolate({inputRange:[-1,0],outputRange:[0,0]});return null!=J?o.default.add(t,J):t}),Q=(0,t.default)(K,2),U=Q[0],X=Q[1],Z=(0,f.useRef)(!0),$=(0,f.useRef)(null);(0,f.useEffect)(function(){0!==I&&null!=I&&(Z.current=!1)},[I]);var ee=(0,f.useCallback)(function(t){var n=t.value,l='android'===u.default.OS?15:64;0!==n||Z.current?(null!=$.current&&clearTimeout($.current),$.current=setTimeout(function(){n!==I&&V(n)},l)):Z.current=!0},[I]);(0,f.useEffect)(function(){var t=[-1,0],n=[0,0];if(w)if(!0===p){if(null!=h){var u=P+k-h;if(u>0){t.push(u),n.push(0),t.push(u+1),n.push(1);var l=(W||0)-k-h;l>u&&(t.push(l,l+1),n.push(l-u,l-u))}}}else{t.push(P),n.push(0);var f=(W||0)-k;f>=P?(t.push(f,f+1),n.push(f-P,f-P)):(t.push(P+1),n.push(1))}var s,c=R.interpolate({inputRange:t,outputRange:n});return null!=J&&(c=o.default.add(c,J)),F&&(s=c.addListener(ee)),X(c),function(){s&&c.removeListener(s),null!=$.current&&clearTimeout($.current)}},[W,w,k,P,h,R,p,J,ee,F]);var te=f.Children.only(l.children),ne=F&&null!=I?{style:{transform:[{translateY:I}]}}:null;return f.createElement(c,{collapsable:!1,nativeID:l.nativeID,onLayout:function(t){_(t.nativeEvent.layout.y),C(t.nativeEvent.layout.height),S(!0),l.onLayout(t);var n=f.Children.only(l.children);n.props.onLayout&&n.props.onLayout(t)},ref:G,style:[te.props.style,v.header,{transform:[{translateY:U}]}],passthroughAnimatedPropExplicitValues:ne},f.cloneElement(te,{style:v.fill,onLayout:void 0}))}),v=l.default.create({header:{zIndex:10,position:'relative'},fill:{flex:1}}),h=p;e.default=h},656,[407,430,646,426,578,616,534]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),u=r(d[0])(r(d[3])),l=r(d[0])(r(d[4])),o=r(d[0])(r(d[5])),s=r(d[0])(r(d[6])),f=r(d[0])(r(d[7])),v=(function(){function v(){(0,t.default)(this,v),this._emitter=new u.default('ios'!==s.default.OS?null:f.default)}return(0,n.default)(v,[{key:"addListener",value:function(t,n,u){return this._emitter.addListener(t,n)}},{key:"removeListener",value:function(t,n){this._emitter.removeListener(t,n)}},{key:"removeAllListeners",value:function(t){this._emitter.removeAllListeners(t)}},{key:"dismiss",value:function(){(0,o.default)()}},{key:"scheduleLayoutAnimation",value:function(t){var n=t.duration,u=t.easing;null!=n&&0!==n&&l.default.configureNext({duration:n,update:{duration:n,type:null!=u&&l.default.Types[u]||'keyboard'}})}}]),v})();m.exports=new v},657,[407,402,403,500,658,659,426,660]); -__d(function(g,r,i,a,m,e,d){'use strict';var n=r(d[0])(r(d[1]));function t(t,u,o){var l,s;if(!n.default.isTesting){var c,p,y=!1,f=function(){y||(y=!0,clearTimeout(b),null==u||u())},b=setTimeout(f,(null!=(l=t.duration)?l:0)+17),I=null==(s=g)?void 0:s.nativeFabricUIManager;if(null!=I&&I.configureNextLayoutAnimation)null==(c=g)||null==(p=c.nativeFabricUIManager)||p.configureNextLayoutAnimation(t,f,null!=o?o:function(){});else null!=r(d[2])&&r(d[2]).configureNextLayoutAnimation&&r(d[2]).configureNextLayoutAnimation(t,null!=f?f:function(){},null!=o?o:function(){})}}function u(n,t,u){return{duration:n,create:{type:t,property:u},update:{type:t},delete:{type:t,property:u}}}var o={easeInEaseOut:u(300,'easeInEaseOut','opacity'),linear:u(500,'linear','opacity'),spring:{duration:700,create:{type:'linear',property:'opacity'},update:{type:'spring',springDamping:.4},delete:{type:'linear',property:'opacity'}}},l={configureNext:t,create:u,Types:Object.freeze({spring:'spring',linear:'linear',easeInEaseOut:'easeInEaseOut',easeIn:'easeIn',easeOut:'easeOut',keyboard:'keyboard'}),Properties:Object.freeze({opacity:'opacity',scaleX:'scaleX',scaleY:'scaleY',scaleXY:'scaleXY'}),checkConfig:function(){console.error('LayoutAnimation.checkConfig(...) has been disabled.')},Presets:o,easeInEaseOut:t.bind(null,o.easeInEaseOut),linear:t.bind(null,o.linear),spring:t.bind(null,o.spring)};m.exports=l},658,[407,426,450]); -__d(function(g,r,i,a,m,e,d){'use strict';m.exports=function(){r(d[0]).blurTextInput(r(d[0]).currentlyFocusedInput())}},659,[540]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in n)if("default"!==l&&Object.prototype.hasOwnProperty.call(n,l)){var p=c?Object.getOwnPropertyDescriptor(n,l):null;p&&(p.get||p.set)?Object.defineProperty(f,l,p):f[l]=n[l]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).get('KeyboardObserver');e.default=n},660,[428]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),o={setGlobalOptions:function(o){if(void 0!==o.debug&&r(d[2])(t.default,'Trying to debug FrameRateLogger without the native module!'),t.default){var l={debug:!!o.debug,reportStackTraces:!!o.reportStackTraces};t.default.setGlobalOptions(l)}},setContext:function(o){t.default&&t.default.setContext(o)},beginScroll:function(){t.default&&t.default.beginScroll()},endScroll:function(){t.default&&t.default.endScroll()}};m.exports=o},661,[407,662,425]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in n)if("default"!==l&&Object.prototype.hasOwnProperty.call(n,l)){var p=c?Object.getOwnPropertyDescriptor(n,l):null;p&&(p.get||p.set)?Object.defineProperty(f,l,p):f[l]=n[l]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).get('FrameRateLogger');e.default=n},662,[428]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1]));m.exports=function(n){return'normal'===n?t.default.select({ios:.998,android:.985}):'fast'===n?t.default.select({ios:.99,android:.9}):n}},663,[407,426]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=function(s){var c=null,t=null;if(null!=s){c={},t={};for(var n=0,l=Object.keys(s);nMath.random(),this._resetData()}return r(d[0])(_,[{key:"activate",value:function(){this._enabled&&null==this._samplesStartTime&&(this._samplesStartTime=g.performance.now())}},{key:"deactivateAndFlush",value:function(){if(this._enabled){var t=this._samplesStartTime;if(null!=t)if(this._info.sample_count0&&(c=Math.min(h,Math.max(0,y.offset-_)));for(var p=0,b=n.last,v=this._getFrameMetrics(b);b>=n.first&&(!v||!v.inLayout);)v=this._getFrameMetrics(b),b--;if(v&&b0?(this._anyBlankStartTime=f,this._info.any_blank_speed_sum+=u,this._info.any_blank_count++,this._info.pixels_blank+=M,T>.5&&(this._mostlyBlankStartTime=f,this._info.mostly_blank_count++)):(u<.01||Math.abs(l)<1)&&this.deactivateAndFlush(),T}},{key:"enabled",value:function(){return this._enabled}},{key:"_resetData",value:function(){this._anyBlankStartTime=null,this._info=new t,this._mostlyBlankStartTime=null,this._samplesStartTime=null}}],[{key:"addListener",value:function(t){return null===l&&console.warn('Call `FillRateHelper.setSampleRate` before `addListener`.'),n.push(t),{remove:function(){n=n.filter(function(n){return t!==n})}}}},{key:"setSampleRate",value:function(t){l=t}},{key:"setMinSampleCount",value:function(t){s=t}}]),_})();m.exports=_},675,[403,402,436]); -__d(function(g,r,i,a,m,e,d){'use strict';var t=(function(){function t(n,l){r(d[0])(this,t),this._delay=l,this._callback=n}return r(d[1])(t,[{key:"dispose",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{abort:!1};this._taskHandle&&(this._taskHandle.cancel(),t.abort||this._callback(),this._taskHandle=null)}},{key:"schedule",value:function(){var t=this;if(!this._taskHandle){var n=setTimeout(function(){t._taskHandle=r(d[2]).runAfterInteractions(function(){t._taskHandle=null,t._callback()})},this._delay);this._taskHandle={cancel:function(){return clearTimeout(n)}}}}}]),t})();m.exports=t},676,[402,403,625]); -__d(function(g,r,_i,a,m,e,d){'use strict';function t(t,i){var o="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(o)return(o=o.call(t)).next.bind(o);if(Array.isArray(t)||(o=n(t))||i&&t&&"number"==typeof t.length){o&&(t=o);var s=0;return function(){return s>=t.length?{done:!0}:{done:!1,value:t[s++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function n(t,n){if(t){if("string"==typeof t)return i(t,n);var o=Object.prototype.toString.call(t).slice(8,-1);return"Object"===o&&t.constructor&&(o=t.constructor.name),"Map"===o||"Set"===o?Array.from(t):"Arguments"===o||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(o)?i(t,n):void 0}}function i(t,n){(null==n||n>t.length)&&(n=t.length);for(var i=0,o=new Array(n);i0&&void 0!==arguments[0]?arguments[0]:{viewAreaCoveragePercentThreshold:0};r(d[0])(this,n),this._hasInteracted=!1,this._timers=new Set,this._viewableIndices=[],this._viewableItems=new Map,this._config=t}return r(d[1])(n,[{key:"dispose",value:function(){this._timers.forEach(clearTimeout)}},{key:"computeViewableItems",value:function(t,n,i,o,l){var u=this._config,c=u.itemVisiblePercentThreshold,h=u.viewAreaCoveragePercentThreshold,f=null!=h,v=f?h:c;r(d[2])(null!=v&&null!=c!=(null!=h),'Must set exactly one of itemVisiblePercentThreshold or viewAreaCoveragePercentThreshold');var b=[];if(0===t)return b;var y=-1,w=l||{first:0,last:t-1},_=w.first,p=w.last;if(p>=t)return console.warn('Invalid render range computing viewability '+JSON.stringify({renderRange:l,itemCount:t})),[];for(var I=_;I<=p;I++){var A=o(I);if(A){var S=A.offset-n,T=S+A.length;if(S0)y=I,s(f,v,S,T,i,A.length)&&b.push(I);else if(y>=0)break}}return b}},{key:"onUpdate",value:function(t,n,i,o,s,l,u){var c=this;if((!this._config.waitForInteraction||this._hasInteracted)&&0!==t&&o(0)){var h=[];if(t&&(h=this.computeViewableItems(t,n,i,o,u)),this._viewableIndices.length!==h.length||!this._viewableIndices.every(function(t,n){return t===h[n]}))if(this._viewableIndices=h,this._config.minimumViewTime){var f=setTimeout(function(){c._timers.delete(f),c._onUpdateSync(h,l,s)},this._config.minimumViewTime);this._timers.add(f)}else this._onUpdateSync(h,l,s)}}},{key:"resetViewableIndices",value:function(){this._viewableIndices=[]}},{key:"recordInteraction",value:function(){this._hasInteracted=!0}},{key:"_onUpdateSync",value:function(n,i,o){var s=this;n=n.filter(function(t){return s._viewableIndices.includes(t)});for(var l,u=this._viewableItems,c=new Map(n.map(function(t){var n=o(t,!0);return[n.key,n]})),h=[],f=t(c);!(l=f()).done;){var v=l.value,b=r(d[3])(v,2),y=b[0],w=b[1];u.has(y)||h.push(w)}for(var _,p=t(u);!(_=p()).done;){var I=_.value,A=r(d[3])(I,2),S=A[0],T=A[1];c.has(S)||h.push(r(d[4])({},T,{isViewable:!1}))}h.length>0&&(this._viewableItems=c,i({viewableItems:Array.from(c.values()),changed:h,viewabilityConfig:this._config}))}}]),n})();function s(t,n,i,o,s,c){if(u(i,o,s))return!0;var h=l(i,o,s);return 100*(t?h/s:h/c)>=n}function l(t,n,i){var o=Math.min(n,i)-Math.max(t,0);return Math.max(0,o)}function u(t,n,i){return t>=0&&n<=i&&n>t}m.exports=o},677,[402,403,425,430,436]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.VirtualizedListCellContextProvider=function(l){var u=l.cellKey,s=l.children,c=(0,n.useContext)(o);return n.createElement(o.Provider,{value:null==c?null:(0,t.default)({},c,{cellKey:u})},s)},e.VirtualizedListContext=void 0,e.VirtualizedListContextProvider=function(t){var l=t.children,u=t.value,s=(0,n.useMemo)(function(){return{cellKey:null,getScrollMetrics:u.getScrollMetrics,horizontal:u.horizontal,getOutermostParentListRef:u.getOutermostParentListRef,getNestedChildState:u.getNestedChildState,registerAsNestedChild:u.registerAsNestedChild,unregisterAsNestedChild:u.unregisterAsNestedChild,debugInfo:{cellKey:u.debugInfo.cellKey,horizontal:u.debugInfo.horizontal,listKey:u.debugInfo.listKey,parent:u.debugInfo.parent}}},[u.getScrollMetrics,u.horizontal,u.getOutermostParentListRef,u.getNestedChildState,u.registerAsNestedChild,u.unregisterAsNestedChild,u.debugInfo.cellKey,u.debugInfo.horizontal,u.debugInfo.listKey,u.debugInfo.parent]);return n.createElement(o.Provider,{value:s},l)},e.VirtualizedListContextResetter=function(t){var l=t.children;return n.createElement(o.Provider,{value:null},l)};var t=r(d[0])(r(d[1])),n=(function(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var o=l(n);if(o&&o.has(t))return o.get(t);var u={},s=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in t)if("default"!==c&&Object.prototype.hasOwnProperty.call(t,c)){var f=s?Object.getOwnPropertyDescriptor(t,c):null;f&&(f.get||f.set)?Object.defineProperty(u,c,f):u[c]=t[c]}u.default=t,o&&o.set(t,u);return u})(r(d[2]));function l(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,o=new WeakMap;return(l=function(t){return t?o:n})(t)}var o=n.createContext(null);e.VirtualizedListContext=o},678,[407,436,534]); -__d(function(g,r,i,a,m,e,d){!(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var f=t(o);if(f&&f.has(n))return f.get(n);var u={},p=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in n)if("default"!==c&&Object.prototype.hasOwnProperty.call(n,c)){var l=p?Object.getOwnPropertyDescriptor(n,c):null;l&&(l.get||l.set)?Object.defineProperty(u,c,l):u[c]=n[c]}u.default=n,f&&f.set(n,u)})(r(d[0]));function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,f=new WeakMap;return(t=function(t){return t?f:o})(n)}m.exports=r(d[1])(r(d[2]),{collapsable:!1})},679,[534,644,680]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),o=r(d[0])(r(d[3])),u=r(d[0])(r(d[4])),l=(function(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var o=b(n);if(o&&o.has(t))return o.get(t);var u={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in t)if("default"!==c&&Object.prototype.hasOwnProperty.call(t,c)){var f=l?Object.getOwnPropertyDescriptor(t,c):null;f&&(f.get||f.set)?Object.defineProperty(u,c,f):u[c]=t[c]}u.default=t,o&&o.set(t,u);return u})(r(d[5])),c=r(d[0])(r(d[6])),f=r(d[0])(r(d[7])),s=r(d[0])(r(d[8])),h=r(d[0])(r(d[9])),p=r(d[0])(r(d[10])),y=r(d[0])(r(d[11])),w=r(d[0])(r(d[12])),v=r(d[0])(r(d[13]));function b(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,o=new WeakMap;return(b=function(t){return t?o:n})(t)}var S=1;function I(t,n){var o=S++;return n&&n(o),w.default.prefetchImage(t,o)}var E=function(n,o){var c,s,w,b,S=(0,y.default)(n.source),I=(0,y.default)(n.defaultSource),E=(0,y.default)(n.loadingIndicatorSource);S&&(''===S.uri&&console.warn('source.uri should not be an empty string'));if(n.src&&console.warn('The component requires a `source` property rather than `src`.'),n.children)throw new Error('The component cannot contain children. If you want to render content on top of the image, consider using the component or absolute positioning.');if(n.defaultSource&&n.loadingIndicatorSource)throw new Error('The component cannot have defaultSource and loadingIndicatorSource at the same time. Please use either defaultSource or loadingIndicatorSource.');if(!S||S.uri||Array.isArray(S)||(S=null),null!=(null==(c=S)?void 0:c.uri)){var P=S,_=P.width,j=P.height;w=(0,p.default)([{width:_,height:j},O.base,n.style]),b=[{uri:S.uri}]}else w=(0,p.default)([O.base,n.style]),b=S;var z=n.onLoadStart,C=n.onLoad,W=n.onLoadEnd,M=n.onError,T=(0,t.default)({},n,{style:w,shouldNotifyLoadEvents:!!(z||C||W||M),src:b,headers:null==(s=S)?void 0:s.headers,defaultSrc:I?I.uri:null,loadingIndicatorSrc:E?E.uri:null,ref:o});return l.createElement(h.default.Consumer,null,function(n){var o=null!==n?(0,t.default)({},T,{internal_analyticTag:n}):T;return l.createElement(f.default.Consumer,null,function(t){return t?l.createElement(v.default,o):l.createElement(u.default,o)})})};E=l.forwardRef(E),null!=s.default.unstable_createImageComponent&&(E=s.default.unstable_createImageComponent(E)),E.displayName='Image',E.getSize=function(t,n,o){return w.default.getSize(t).then(function(t){n(t.width,t.height)}).catch(o||function(){console.warn('Failed to get size for image: '+t)})},E.getSizeWithHeaders=function(t,n,o,u){return w.default.getSizeWithHeaders(t,n).then(function(t){o(t.width,t.height)}).catch(u||function(){console.warn('Failed to get size for image: '+t)})},E.prefetch=I,E.prefetchWithMetadata=function(t,n,o,u){I(t,u)},E.abortPrefetch=function(t){w.default.abortRequest(t)},E.queryCache=function(t){return n.default.async(function(o){for(;;)switch(o.prev=o.next){case 0:return o.next=2,n.default.awrap(w.default.queryCache(t));case 2:return o.abrupt("return",o.sent);case 3:case"end":return o.stop()}},null,null,null,Promise)},E.resolveAssetSource=y.default,E.propTypes=o.default;var O=c.default.create({base:{overflow:'hidden'}});m.exports=E},680,[407,436,404,681,685,534,578,581,686,688,573,560,689,687]); -__d(function(g,r,i,a,m,e,d){'use strict';var n=r(d[0])({},r(d[1]),{style:r(d[2])(r(d[3])),source:r(d[4]).oneOfType([r(d[4]).shape({uri:r(d[4]).string,headers:r(d[4]).objectOf(r(d[4]).string)}),r(d[4]).number,r(d[4]).arrayOf(r(d[4]).shape({uri:r(d[4]).string,width:r(d[4]).number,height:r(d[4]).number,headers:r(d[4]).objectOf(r(d[4]).string)}))]),blurRadius:r(d[4]).number,defaultSource:r(d[4]).number,loadingIndicatorSource:r(d[4]).oneOfType([r(d[4]).shape({uri:r(d[4]).string}),r(d[4]).number]),progressiveRenderingEnabled:r(d[4]).bool,fadeDuration:r(d[4]).number,internal_analyticTag:r(d[4]).string,onLoadStart:r(d[4]).func,onError:r(d[4]).func,onLoad:r(d[4]).func,onLoadEnd:r(d[4]).func,testID:r(d[4]).string,resizeMethod:r(d[4]).oneOf(['auto','resize','scale']),resizeMode:r(d[4]).oneOf(['cover','contain','stretch','repeat','center'])});m.exports=n},681,[436,682,591,684,596]); -__d(function(g,r,i,a,m,e,d){'use strict';var o=r(d[0])(r(d[1]));m.exports={accessible:r(d[2]).bool,accessibilityLabel:r(d[2]).node,accessibilityHint:r(d[2]).string,accessibilityActions:r(d[2]).arrayOf(r(d[2]).string),accessibilityIgnoresInvertColors:r(d[2]).bool,accessibilityRole:r(d[2]).oneOf(r(d[3]).DeprecatedAccessibilityRoles),accessibilityState:r(d[2]).object,accessibilityValue:r(d[2]).object,accessibilityLiveRegion:r(d[2]).oneOf(['none','polite','assertive']),importantForAccessibility:r(d[2]).oneOf(['auto','yes','no','no-hide-descendants']),accessibilityViewIsModal:r(d[2]).bool,accessibilityElementsHidden:r(d[2]).bool,onAccessibilityAction:r(d[2]).func,onAccessibilityTap:r(d[2]).func,onMagicTap:r(d[2]).func,testID:r(d[2]).string,nativeID:r(d[2]).string,onResponderGrant:r(d[2]).func,onResponderMove:r(d[2]).func,onResponderReject:r(d[2]).func,onResponderRelease:r(d[2]).func,onResponderTerminate:r(d[2]).func,onResponderTerminationRequest:r(d[2]).func,onStartShouldSetResponder:r(d[2]).func,onStartShouldSetResponderCapture:r(d[2]).func,onMoveShouldSetResponder:r(d[2]).func,onMoveShouldSetResponderCapture:r(d[2]).func,hitSlop:r(d[4]),onLayout:r(d[2]).func,pointerEvents:r(d[2]).oneOf(['box-none','none','box-only','auto']),style:o,removeClippedSubviews:r(d[2]).bool,renderToHardwareTextureAndroid:r(d[2]).bool,shouldRasterizeIOS:r(d[2]).bool,collapsable:r(d[2]).bool,needsOffscreenAlphaCompositing:r(d[2]).bool}},682,[591,594,596,683,603]); -__d(function(g,r,i,a,m,e,d){'use strict';m.exports={DeprecatedAccessibilityRoles:['none','button','togglebutton','link','search','image','keyboardkey','text','adjustable','imagebutton','header','summary','alert','checkbox','combobox','menu','menubar','menuitem','progressbar','radio','radiogroup','scrollbar','spinbutton','switch','tab','tablist','timer','list','toolbar']}},683,[]); -__d(function(g,r,i,a,m,e,d){'use strict';var o=r(d[0])({},r(d[1]),r(d[2]),r(d[3]),{resizeMode:r(d[4]).oneOf(['center','contain','cover','repeat','stretch']),backfaceVisibility:r(d[4]).oneOf(['visible','hidden']),backgroundColor:r(d[5]),borderColor:r(d[5]),borderWidth:r(d[4]).number,borderRadius:r(d[4]).number,overflow:r(d[4]).oneOf(['visible','hidden']),tintColor:r(d[5]),opacity:r(d[4]).number,overlayColor:r(d[4]).string,borderTopLeftRadius:r(d[4]).number,borderTopRightRadius:r(d[4]).number,borderBottomLeftRadius:r(d[4]).number,borderBottomRightRadius:r(d[4]).number});m.exports=o},684,[436,595,599,601,596,600]); -__d(function(g,r,i,a,m,e,d){function t(o){if("function"!=typeof WeakMap)return null;var n=new WeakMap,s=new WeakMap;return(t=function(t){return t?s:n})(o)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var o=(function(o,n){if(!n&&o&&o.__esModule)return o;if(null===o||"object"!=typeof o&&"function"!=typeof o)return{default:o};var s=t(n);if(s&&s.has(o))return s.get(o);var u={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var f in o)if("default"!==f&&Object.prototype.hasOwnProperty.call(o,f)){var c=l?Object.getOwnPropertyDescriptor(o,f):null;c&&(c.get||c.set)?Object.defineProperty(u,f,c):u[f]=o[f]}u.default=o,s&&s.set(o,u);return u})(r(d[0])).get('RCTImageView',function(){return{uiViewClassName:'RCTImageView',bubblingEventTypes:{},directEventTypes:{topLoadStart:{registrationName:'onLoadStart'},topProgress:{registrationName:'onProgress'},topError:{registrationName:'onError'},topPartialLoad:{registrationName:'onPartialLoad'},topLoad:{registrationName:'onLoad'},topLoadEnd:{registrationName:'onLoadEnd'}},validAttributes:{blurRadius:!0,capInsets:{diff:r(d[1])},defaultSource:{process:r(d[2])},defaultSrc:!0,fadeDuration:!0,headers:!0,internal_analyticTag:!0,loadingIndicatorSrc:!0,onError:!0,onLoad:!0,onLoadEnd:!0,onLoadStart:!0,onPartialLoad:!0,onProgress:!0,overlayColor:{process:r(d[3])},progressiveRenderingEnabled:!0,resizeMethod:!0,resizeMode:!0,shouldNotifyLoadEvents:!0,source:!0,src:!0,tintColor:{process:r(d[3])}}}});e.default=o},685,[555,550,560,546]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in n)if("default"!==c&&Object.prototype.hasOwnProperty.call(n,c)){var p=l?Object.getOwnPropertyDescriptor(n,c):null;p&&(p.get||p.set)?Object.defineProperty(f,c,p):f[c]=n[c]}f.default=n,u&&u.set(n,f)})(r(d[0])),r(d[1])(r(d[2])),r(d[1])(r(d[3]));function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}e.default={unstable_createImageComponent:null}},686,[534,407,685,687]); -__d(function(g,r,i,a,m,e,d){'use strict';function t(o){if("function"!=typeof WeakMap)return null;var n=new WeakMap,s=new WeakMap;return(t=function(t){return t?s:n})(o)}var o=(function(o,n){if(!n&&o&&o.__esModule)return o;if(null===o||"object"!=typeof o&&"function"!=typeof o)return{default:o};var s=t(n);if(s&&s.has(o))return s.get(o);var u={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in o)if("default"!==c&&Object.prototype.hasOwnProperty.call(o,c)){var p=l?Object.getOwnPropertyDescriptor(o,c):null;p&&(p.get||p.set)?Object.defineProperty(u,c,p):u[c]=o[c]}u.default=o,s&&s.set(o,u);return u})(r(d[0])).get('RCTTextInlineImage',function(){return{uiViewClassName:'RCTImageView',bubblingEventTypes:{},directEventTypes:{topLoadStart:{registrationName:'onLoadStart'},topProgress:{registrationName:'onProgress'},topError:{registrationName:'onError'},topPartialLoad:{registrationName:'onPartialLoad'},topLoad:{registrationName:'onLoad'},topLoadEnd:{registrationName:'onLoadEnd'}},validAttributes:{blurRadius:!0,capInsets:{diff:r(d[1])},defaultSource:{process:r(d[2])},defaultSrc:!0,fadeDuration:!0,headers:!0,internal_analyticTag:!0,loadingIndicatorSrc:!0,onError:!0,onLoad:!0,onLoadEnd:!0,onLoadStart:!0,onPartialLoad:!0,onProgress:!0,overlayColor:{process:r(d[3])},progressiveRenderingEnabled:!0,resizeMethod:!0,resizeMode:!0,shouldNotifyLoadEvents:!0,source:!0,src:!0,tintColor:{process:r(d[3])}}}});m.exports=o},687,[555,550,560,546]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in n)if("default"!==c&&Object.prototype.hasOwnProperty.call(n,c)){var p=l?Object.getOwnPropertyDescriptor(n,c):null;p&&(p.get||p.set)?Object.defineProperty(f,c,p):f[c]=n[c]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).createContext(null);e.default=n},688,[534]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,f=new WeakMap;return(t=function(t){return t?f:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var f=t(o);if(f&&f.has(n))return f.get(n);var u={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in n)if("default"!==l&&Object.prototype.hasOwnProperty.call(n,l)){var p=c?Object.getOwnPropertyDescriptor(n,l):null;p&&(p.get||p.set)?Object.defineProperty(u,l,p):u[l]=n[l]}u.default=n,f&&f.set(n,u);return u})(r(d[0])).getEnforcing('ImageLoader');e.default=n},689,[428]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),n=(function(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var f=o(n);if(f&&f.has(t))return f.get(t);var u={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in t)if("default"!==c&&Object.prototype.hasOwnProperty.call(t,c)){var p=l?Object.getOwnPropertyDescriptor(t,c):null;p&&(p.get||p.set)?Object.defineProperty(u,c,p):u[c]=t[c]}u.default=t,f&&f.set(t,u);return u})(r(d[2]));function o(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,f=new WeakMap;return(o=function(t){return t?f:n})(t)}var f=n.forwardRef(function(o,f){return n.createElement(r(d[3]),(0,t.default)({scrollEventThrottle:1e-4},o,{ref:f}))});m.exports=r(d[4])(f,{collapsable:!1})},690,[407,436,534,655,644]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),n=(function(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var f=o(n);if(f&&f.has(t))return f.get(t);var u={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in t)if("default"!==l&&Object.prototype.hasOwnProperty.call(t,l)){var p=c?Object.getOwnPropertyDescriptor(t,l):null;p&&(p.get||p.set)?Object.defineProperty(u,l,p):u[l]=t[l]}u.default=t,f&&f.set(t,u);return u})(r(d[2])),f=r(d[0])(r(d[3]));function o(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,f=new WeakMap;return(o=function(t){return t?f:n})(t)}var u=n.forwardRef(function(o,u){return n.createElement(f.default,(0,t.default)({scrollEventThrottle:1e-4},o,{ref:u}))});m.exports=r(d[4])(u)},691,[407,436,534,692,644]); -__d(function(g,r,i,a,m,_e,d){'use strict';Object.defineProperty(_e,"__esModule",{value:!0}),_e.default=void 0;var e=r(d[0])(r(d[1])),t=r(d[0])(r(d[2])),n=r(d[0])(r(d[3])),o=r(d[0])(r(d[4])),f=r(d[0])(r(d[5])),u=r(d[0])(r(d[6])),c=r(d[0])(r(d[7])),l=r(d[0])(r(d[8])),s=(function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=y(t);if(n&&n.has(e))return n.get(e);var o={},f=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var u in e)if("default"!==u&&Object.prototype.hasOwnProperty.call(e,u)){var c=f?Object.getOwnPropertyDescriptor(e,u):null;c&&(c.get||c.set)?Object.defineProperty(o,u,c):o[u]=e[u]}o.default=e,n&&n.set(e,o);return o})(r(d[9])),p=r(d[0])(r(d[10])),v=["stickySectionHeadersEnabled"];function y(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(y=function(e){return e?n:t})(e)}function h(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}var R=(function(y){(0,f.default)(w,y);var R,_,L=(R=w,_=h(),function(){var e,t=(0,c.default)(R);if(_){var n=(0,c.default)(this).constructor;e=Reflect.construct(t,arguments,n)}else e=t.apply(this,arguments);return(0,u.default)(this,e)});function w(){var e;(0,n.default)(this,w);for(var t=arguments.length,o=new Array(t),f=0;f=e.length?{done:!0}:{done:!1,value:e[i++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function I(e,t){if(e){if("string"==typeof e)return _(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?_(e,t):void 0}}function _(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,i=new Array(t);n0&&this.props.stickySectionHeadersEnabled)o+=this._listRef._getFrameMetricsApprox(t-e.itemIndex).length;var l=(0,n.default)({},e,{viewOffset:o,index:t});this._listRef.scrollToIndex(l)}}},{key:"getListRef",value:function(){return this._listRef}},{key:"render",value:function(){for(var e,i=this,o=this.props,l=(o.ItemSeparatorComponent,o.SectionSeparatorComponent,o.renderItem,o.renderSectionFooter,o.renderSectionHeader,o.sections,o.stickySectionHeadersEnabled,(0,t.default)(o,v)),u=this.props.ListHeaderComponent?1:0,c=this.props.stickySectionHeadersEnabled?[]:void 0,s=0,p=S(this.props.sections);!(e=p()).done;){var y=e.value;null!=c&&c.push(s+u),s+=2,s+=this.props.getItemCount(y.data)}var I=this._renderItem(s);return h.createElement(f.VirtualizedList,(0,n.default)({},l,{keyExtractor:this._keyExtractor,stickyHeaderIndices:c,renderItem:I,data:this.props.sections,getItem:function(e,t){return i._getItem(i.props,e,t)},getItemCount:function(){return s},onViewableItemsChanged:this.props.onViewableItemsChanged?this._onViewableItemsChanged:void 0,ref:this._captureRef}))}},{key:"_getItem",value:function(e,t,n){if(!t)return null;for(var i=n-1,o=0;o=o(p)+1)t-=o(p)+1;else return-1===t?{section:s,key:f+':header',index:null,header:!0,trailingSection:u[c+1]}:t===o(p)?{section:s,key:f+':footer',index:null,header:!1,trailingSection:u[c+1]}:{section:s,key:f+':'+(s.keyExtractor||l||r(d[13]).keyExtractor)(i(p,t),t),index:t,leadingItem:i(p,t-1),leadingSection:u[c-1],trailingItem:i(p,t+1),trailingSection:u[c+1]}}}},{key:"_getSeparatorComponent",value:function(e,t,n){if(!(t=t||this._subExtractor(e)))return null;var i=t.section.ItemSeparatorComponent||this.props.ItemSeparatorComponent,o=this.props.SectionSeparatorComponent,l=e===n-1,u=t.index===this.props.getItemCount(t.section.data)-1;return o&&u?o:!i||u||l?null:i}}]),x})(h.PureComponent);function k(t){var i=t.LeadingSeparatorComponent,o=t.SeparatorComponent,l=t.cellKey,u=t.prevCellKey,c=t.setSelfHighlightCallback,s=t.updateHighlightFor,p=t.setSelfUpdatePropsCallback,v=t.updatePropsFor,y=t.item,S=t.index,I=t.section,_=t.inverted,b=h.useState(!1),x=(0,e.default)(b,2),k=x[0],C=x[1],E=h.useState(!1),w=(0,e.default)(E,2),H=w[0],P=w[1],F=h.useState({leadingItem:t.leadingItem,leadingSection:t.leadingSection,section:t.section,trailingItem:t.item,trailingSection:t.trailingSection}),R=(0,e.default)(F,2),M=R[0],O=R[1],V=h.useState({leadingItem:t.item,leadingSection:t.leadingSection,section:t.section,trailingItem:t.trailingItem,trailingSection:t.trailingSection}),j=(0,e.default)(V,2),A=j[0],U=j[1];h.useEffect(function(){return c(l,P),p(l,U),function(){p(l,null),c(l,null)}},[l,c,U,p]);var L={highlight:function(){C(!0),P(!0),null!=u&&s(u,!0)},unhighlight:function(){C(!1),P(!1),null!=u&&s(u,!1)},updateProps:function(e,t){'leading'===e?null!=i?O((0,n.default)({},M,t)):null!=u&&v(u,(0,n.default)({},M,t)):'trailing'===e&&null!=o&&U((0,n.default)({},A,t))}},B=t.renderItem({item:y,index:S,section:I,separators:L}),K=null!=i&&h.createElement(i,(0,n.default)({highlighted:k},M)),T=null!=o&&h.createElement(o,(0,n.default)({highlighted:H},A));return K||T?h.createElement(f.View,null,!1===_?K:T,B,!1===_?T:K):B}m.exports=x},693,[407,430,508,436,402,403,421,417,419,422,425,411,534,653]); -__d(function(g,r,i,a,m,e,d){!(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var f=t(o);if(f&&f.has(n))return f.get(n);var u={},p=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in n)if("default"!==c&&Object.prototype.hasOwnProperty.call(n,c)){var l=p?Object.getOwnPropertyDescriptor(n,c):null;l&&(l.get||l.set)?Object.defineProperty(u,c,l):u[c]=n[c]}u.default=n,f&&f.set(n,u)})(r(d[0]));function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,f=new WeakMap;return(t=function(t){return t?f:o})(n)}m.exports=r(d[1])(r(d[2]),{collapsable:!1})},694,[534,644,589]); -__d(function(g,r,i,a,m,e,d){!(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var f=t(o);if(f&&f.has(n))return f.get(n);var u={},p=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in n)if("default"!==c&&Object.prototype.hasOwnProperty.call(n,c)){var l=p?Object.getOwnPropertyDescriptor(n,c):null;l&&(l.get||l.set)?Object.defineProperty(u,c,l):u[c]=n[c]}u.default=n,f&&f.set(n,u)})(r(d[0]));function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,f=new WeakMap;return(t=function(t){return t?f:o})(n)}m.exports=r(d[1])(r(d[2]),{collapsable:!0})},695,[534,644,579]); -__d(function(g,r,i,a,m,e,d){'use strict';var n={};m.exports=function(o,t){n[o]||(console.warn(t),n[o]=!0)}},696,[]); -__d(function(g,r,i,a,m,_e,d){'use strict';var e=r(d[0])(r(d[1])),t=r(d[0])(r(d[2])),n=r(d[0])(r(d[3])),o=r(d[0])(r(d[4])),u=r(d[0])(r(d[5])),c=(function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=p(t);if(n&&n.has(e))return n.get(e);var o={},u=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in e)if("default"!==c&&Object.prototype.hasOwnProperty.call(e,c)){var f=u?Object.getOwnPropertyDescriptor(e,c):null;f&&(f.get||f.set)?Object.defineProperty(o,c,f):o[c]=e[c]}o.default=e,n&&n.set(e,o);return o})(r(d[6])),f=r(d[0])(r(d[7])),l=r(d[0])(r(d[8])),s=r(d[0])(r(d[9]));function p(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(p=function(e){return e?n:t})(e)}function y(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}var h=(function(f){(0,n.default)(b,f);var p,h,O=(p=b,h=y(),function(){var e,t=(0,u.default)(p);if(h){var n=(0,u.default)(this).constructor;e=Reflect.construct(t,arguments,n)}else e=t.apply(this,arguments);return(0,o.default)(this,e)});function b(){return(0,e.default)(this,b),O.apply(this,arguments)}return(0,t.default)(b,[{key:"render",value:function(){return c.createElement(s.default,{style:[v.dummyDatePickerIOS,this.props.style]},c.createElement(l.default,{style:v.datePickerText},"DatePickerIOS is not supported on this platform!"))}}]),b})(c.Component),v=f.default.create({dummyDatePickerIOS:{height:100,width:300,backgroundColor:'#ffbcbc',borderWidth:1,borderColor:'red',alignItems:'center',justifyContent:'center',margin:10},datePickerText:{color:'#333333',margin:20}});m.exports=h},697,[407,402,403,417,419,422,534,578,589,579]); -__d(function(g,r,i,a,m,_e,d){var e=r(d[0])(r(d[1])),t=r(d[0])(r(d[2])),n=r(d[0])(r(d[3])),o=r(d[0])(r(d[4])),u=r(d[0])(r(d[5])),s=r(d[0])(r(d[6])),l=r(d[0])(r(d[7])),f=r(d[0])(r(d[8])),c=k(r(d[9])),p=r(d[0])(r(d[10])),w=r(d[0])(r(d[11])),h=r(d[0])(r(d[12])),v=r(d[0])(r(d[13])),y=r(d[0])(r(d[14])),D=k(r(d[15])),b=["onDrawerStateChanged","renderNavigationView","onDrawerOpen","onDrawerClose"];function C(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(C=function(e){return e?n:t})(e)}function k(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=C(t);if(n&&n.has(e))return n.get(e);var o={},u=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var s in e)if("default"!==s&&Object.prototype.hasOwnProperty.call(e,s)){var l=u?Object.getOwnPropertyDescriptor(e,s):null;l&&(l.get||l.set)?Object.defineProperty(o,s,l):o[s]=e[s]}return o.default=e,n&&n.set(e,o),o}function _(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}var S=['Idle','Dragging','Settling'],R=(function(w){(0,u.default)(O,w);var C,k,R=(C=O,k=_(),function(){var e,t=(0,l.default)(C);if(k){var n=(0,l.default)(this).constructor;e=Reflect.construct(t,arguments,n)}else e=t.apply(this,arguments);return(0,s.default)(this,e)});function O(){var e;(0,n.default)(this,O);for(var t=arguments.length,o=new Array(t),u=0;u=21&&null!=this.props.statusBarBackgroundColor,l=c.createElement(h.default,{style:[B.drawerSubview,{width:this.props.drawerWidth,backgroundColor:this.props.drawerBackgroundColor}],collapsable:!1},o(),s&&c.createElement(h.default,{style:B.drawerStatusBar})),w=c.createElement(h.default,{style:B.mainSubview,collapsable:!1},s&&c.createElement(p.default,{translucent:!0,backgroundColor:this.props.statusBarBackgroundColor}),s&&c.createElement(h.default,{style:[B.statusBar,{backgroundColor:this.props.statusBarBackgroundColor}]}),this.props.children);return c.createElement(D.default,(0,e.default)({},u,{ref:this._nativeRef,drawerWidth:this.props.drawerWidth,drawerPosition:this.props.drawerPosition,drawerLockMode:this.props.drawerLockMode,style:[B.base,this.props.style],onDrawerSlide:this._onDrawerSlide,onDrawerOpen:this._onDrawerOpen,onDrawerClose:this._onDrawerClose,onDrawerStateChanged:this._onDrawerStateChanged}),w,l)}},{key:"openDrawer",value:function(){D.Commands.openDrawer((0,y.default)(this._nativeRef.current))}},{key:"closeDrawer",value:function(){D.Commands.closeDrawer((0,y.default)(this._nativeRef.current))}},{key:"blur",value:function(){(0,y.default)(this._nativeRef.current).blur()}},{key:"focus",value:function(){(0,y.default)(this._nativeRef.current).focus()}},{key:"measure",value:function(e){(0,y.default)(this._nativeRef.current).measure(e)}},{key:"measureInWindow",value:function(e){(0,y.default)(this._nativeRef.current).measureInWindow(e)}},{key:"measureLayout",value:function(e,t,n){(0,y.default)(this._nativeRef.current).measureLayout(e,t,n)}},{key:"setNativeProps",value:function(e){(0,y.default)(this._nativeRef.current).setNativeProps(e)}}],[{key:"positions",get:function(){return console.warn('Setting DrawerLayoutAndroid drawerPosition using `DrawerLayoutAndroid.positions` is deprecated. Instead pass the string value "left" or "right"'),{Left:'left',Right:'right'}}}]),O})(c.Component);R.defaultProps={drawerBackgroundColor:'white'};var B=w.default.create({base:{flex:1,elevation:16},mainSubview:{position:'absolute',top:0,left:0,right:0,bottom:0},drawerSubview:{position:'absolute',top:0,bottom:0},statusBar:{height:p.default.currentHeight},drawerStatusBar:{position:'absolute',top:0,left:0,right:0,height:p.default.currentHeight,backgroundColor:'rgba(0, 0, 0, 0.251)'}});m.exports=R},698,[407,436,508,402,403,417,419,422,426,534,699,578,579,659,702,703]); -__d(function(g,r,i,a,m,_e,d){var t,e=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),l=r(d[0])(r(d[3])),o=r(d[0])(r(d[4])),u=r(d[0])(r(d[5])),c=r(d[0])(r(d[6])),s=(function(t,e){if(!e&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var n=S(e);if(n&&n.has(t))return n.get(t);var l={},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var u in t)if("default"!==u&&Object.prototype.hasOwnProperty.call(t,u)){var c=o?Object.getOwnPropertyDescriptor(t,u):null;c&&(c.get||c.set)?Object.defineProperty(l,u,c):l[u]=t[u]}l.default=t,n&&n.set(t,l);return l})(r(d[7])),f=r(d[0])(r(d[8])),p=r(d[0])(r(d[9])),y=r(d[0])(r(d[10])),v=r(d[0])(r(d[11])),k=r(d[0])(r(d[12]));function S(t){if("function"!=typeof WeakMap)return null;var e=new WeakMap,n=new WeakMap;return(S=function(t){return t?n:e})(t)}function b(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}function _(t){var e,n,l=null!=(e=t.animated)&&e,o=null!=(n=t.showHideTransition)?n:'fade';return{backgroundColor:null!=t.backgroundColor?{value:t.backgroundColor,animated:l}:null,barStyle:null!=t.barStyle?{value:t.barStyle,animated:l}:null,translucent:t.translucent,hidden:null!=t.hidden?{value:t.hidden,animated:l,transition:o}:null,networkActivityIndicatorVisible:t.networkActivityIndicatorVisible}}var h=(function(t){(0,l.default)(h,t);var c,s,S=(c=h,s=b(),function(){var t,e=(0,u.default)(c);if(s){var n=(0,u.default)(this).constructor;t=Reflect.construct(e,arguments,n)}else t=e.apply(this,arguments);return(0,o.default)(this,t)});function h(){var t;(0,e.default)(this,h);for(var n=arguments.length,l=new Array(n),o=0;o is only supported on iOS.'),0===c.Children.count(this.props.children)?null:c.createElement(s.default,{style:[this.props.style,v.container],nativeID:this.props.nativeID,backgroundColor:this.props.backgroundColor},this.props.children)}}]),b})(c.Component),v=l.default.create({container:{position:'absolute'}});m.exports=h},705,[407,402,403,417,419,422,534,426,578,706]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var t=(0,r(d[0])(r(d[1])).default)('InputAccessory',{interfaceOnly:!0,paperComponentName:'RCTInputAccessoryView',excludedPlatforms:['android']});e.default=t},706,[407,584]); -__d(function(g,r,i,a,m,_e,d){Object.defineProperty(_e,"__esModule",{value:!0}),_e.default=void 0;var e=r(d[0])(r(d[1])),t=r(d[0])(r(d[2])),n=r(d[0])(r(d[3])),o=r(d[0])(r(d[4])),u=r(d[0])(r(d[5])),f=r(d[0])(r(d[6])),l=r(d[0])(r(d[7])),s=r(d[0])(r(d[8])),c=r(d[0])(r(d[9])),y=r(d[0])(r(d[10])),h=(function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=_(t);if(n&&n.has(e))return n.get(e);var o={},u=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var f in e)if("default"!==f&&Object.prototype.hasOwnProperty.call(e,f)){var l=u?Object.getOwnPropertyDescriptor(e,f):null;l&&(l.get||l.set)?Object.defineProperty(o,f,l):o[f]=e[f]}o.default=e,n&&n.set(e,o);return o})(r(d[11])),p=r(d[0])(r(d[12])),v=r(d[0])(r(d[13])),b=["behavior","children","contentContainerStyle","enabled","keyboardVerticalOffset","style"];function _(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(_=function(e){return e?n:t})(e)}function k(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}var O=(function(_){(0,u.default)(E,_);var O,w,L=(O=E,w=k(),function(){var e,t=(0,l.default)(O);if(w){var n=(0,l.default)(this).constructor;e=Reflect.construct(t,arguments,n)}else e=t.apply(this,arguments);return(0,f.default)(this,e)});function E(e){var t;return(0,n.default)(this,E),(t=L.call(this,e))._frame=null,t._keyboardEvent=null,t._subscriptions=[],t._initialFrameHeight=0,t._onKeyboardChange=function(e){t._keyboardEvent=e,t._updateBottomIfNecesarry()},t._onLayout=function(e){var n=null==t._frame;t._frame=e.nativeEvent.layout,t._initialFrameHeight||(t._initialFrameHeight=t._frame.height),n&&t._updateBottomIfNecesarry()},t._updateBottomIfNecesarry=function(){if(null!=t._keyboardEvent){var e=t._keyboardEvent,n=e.duration,o=e.easing,u=e.endCoordinates,f=t._relativeKeyboardHeight(u);t.state.bottom!==f&&(n&&o&&c.default.configureNext({duration:n>10?n:10,update:{duration:n>10?n:10,type:c.default.Types[o]||'keyboard'}}),t.setState({bottom:f}))}else t.setState({bottom:0})},t.state={bottom:0},t.viewRef=h.createRef(),t}return(0,o.default)(E,[{key:"_relativeKeyboardHeight",value:function(e){var t,n=this._frame;if(!n||!e)return 0;var o=e.screenY-(null!=(t=this.props.keyboardVerticalOffset)?t:0);return Math.max(n.y+n.height-o,0)}},{key:"componentDidMount",value:function(){'ios'===y.default.OS?this._subscriptions=[s.default.addListener('keyboardWillChangeFrame',this._onKeyboardChange)]:this._subscriptions=[s.default.addListener('keyboardDidHide',this._onKeyboardChange),s.default.addListener('keyboardDidShow',this._onKeyboardChange)]}},{key:"componentWillUnmount",value:function(){this._subscriptions.forEach(function(e){e.remove()})}},{key:"render",value:function(){var n=this.props,o=n.behavior,u=n.children,f=n.contentContainerStyle,l=n.enabled,s=void 0===l||l,c=(n.keyboardVerticalOffset,n.style),y=(0,t.default)(n,b),_=!0===s?this.state.bottom:0;switch(o){case'height':var k;return null!=this._frame&&this.state.bottom>0&&(k={height:this._initialFrameHeight-_,flex:0}),h.createElement(v.default,(0,e.default)({ref:this.viewRef,style:p.default.compose(c,k),onLayout:this._onLayout},y),u);case'position':return h.createElement(v.default,(0,e.default)({ref:this.viewRef,style:c,onLayout:this._onLayout},y),h.createElement(v.default,{style:p.default.compose(f,{bottom:_})},u));case'padding':return h.createElement(v.default,(0,e.default)({ref:this.viewRef,style:p.default.compose(c,{paddingBottom:_}),onLayout:this._onLayout},y),u);default:return h.createElement(v.default,(0,e.default)({ref:this.viewRef,onLayout:this._onLayout,style:c},y),u)}}}]),E})(h.Component);_e.default=O},707,[407,436,508,402,403,417,419,422,657,658,426,534,578,579]); -__d(function(g,r,i,a,m,e,d){'use strict';m.exports=r(d[0])},708,[709]); -__d(function(g,r,i,a,m,_e,d){'use strict';var e=r(d[0])(r(d[1])),t=r(d[0])(r(d[2])),n=r(d[0])(r(d[3])),u=r(d[0])(r(d[4])),o=r(d[0])(r(d[5])),f=(function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=l(t);if(n&&n.has(e))return n.get(e);var u={},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var f in e)if("default"!==f&&Object.prototype.hasOwnProperty.call(e,f)){var c=o?Object.getOwnPropertyDescriptor(e,f):null;c&&(c.get||c.set)?Object.defineProperty(u,f,c):u[f]=e[f]}u.default=e,n&&n.set(e,u);return u})(r(d[6])),c=r(d[0])(r(d[7]));function l(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(l=function(e){return e?n:t})(e)}function p(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}var s=(function(c){(0,n.default)(h,c);var l,s,v=(l=h,s=p(),function(){var e,t=(0,o.default)(l);if(s){var n=(0,o.default)(this).constructor;e=Reflect.construct(t,arguments,n)}else e=t.apply(this,arguments);return(0,u.default)(this,e)});function h(){return(0,e.default)(this,h),v.apply(this,arguments)}return(0,t.default)(h,[{key:"render",value:function(){var e=r(d[8]);return f.createElement(e,{style:[y.unimplementedView,this.props.style]},this.props.children)}}]),h})(f.Component),y=c.default.create({unimplementedView:{}});m.exports=s},709,[407,402,403,417,419,422,534,578,579]); -__d(function(g,r,i,a,m,_e,d){var t,e,n=r(d[0])(r(d[1])),o=r(d[0])(r(d[2])),s=r(d[0])(r(d[3])),l=r(d[0])(r(d[4])),u=r(d[0])(r(d[5])),p=r(d[0])(r(d[6])),c=r(d[0])(r(d[7])),f=(r(d[0])(r(d[8])),r(d[0])(r(d[9])),r(d[0])(r(d[10])));function h(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var v=r(d[11]),y=0,R=(function(t){(0,l.default)(R,t);var e,n,c=(e=R,n=h(),function(){var t,o=(0,p.default)(e);if(n){var s=(0,p.default)(this).constructor;t=Reflect.construct(o,arguments,s)}else t=o.apply(this,arguments);return(0,u.default)(this,t)});function R(t){var e;return(0,o.default)(this,R),(e=c.call(this,t))._identifier=y++,e}return(0,s.default)(R,[{key:"componentDidMount",value:function(){}},{key:"componentWillUnmount",value:function(){this._eventSubscription&&this._eventSubscription.remove()}},{key:"componentDidUpdate",value:function(){}},{key:"render",value:function(){var t=this;if(!0!==this.props.visible)return null;var e={backgroundColor:!0===this.props.transparent?'transparent':'white'},n=this.props.animationType||'none',o=this.props.presentationStyle;o||(o='fullScreen',!0===this.props.transparent&&(o='overFullScreen'));var s=this.props.children;return v.createElement(f.default,{animationType:n,presentationStyle:o,transparent:this.props.transparent,hardwareAccelerated:this.props.hardwareAccelerated,onRequestClose:this.props.onRequestClose,onShow:this.props.onShow,onDismiss:function(){t.props.onDismiss&&t.props.onDismiss()},visible:this.props.visible,statusBarTranslucent:this.props.statusBarTranslucent,identifier:this._identifier,style:b.modal,onStartShouldSetResponder:this._shouldSetResponder,supportedOrientations:this.props.supportedOrientations,onOrientationChange:this.props.onOrientationChange},v.createElement(r(d[12]).VirtualizedListContextResetter,null,v.createElement(r(d[13]).Context.Provider,{value:null},v.createElement(r(d[14]),{style:[b.container,e],collapsable:!1},s))))}},{key:"_shouldSetResponder",value:function(){return!0}}]),R})(v.Component);R.defaultProps={visible:!0,hardwareAccelerated:!1},R.contextType=r(d[15]).RootTagContext;var S=r(d[16]).getConstants().isRTL?'right':'left',b=r(d[17]).create({modal:{position:'absolute'},container:(t={},(0,n.default)(t,S,0),(0,n.default)(t,"top",0),(0,n.default)(t,"flex",1),t)}),C=null!=(e=c.default.unstable_Modal)?e:R;m.exports=C},710,[407,652,402,403,417,419,422,711,500,712,713,534,678,655,579,714,715,578]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;e.default={unstable_Modal:null}},711,[]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in n)if("default"!==c&&Object.prototype.hasOwnProperty.call(n,c)){var p=l?Object.getOwnPropertyDescriptor(n,c):null;p&&(p.get||p.set)?Object.defineProperty(f,c,p):f[c]=n[c]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).get('ModalManager');e.default=n},712,[428]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var o=(0,r(d[0])(r(d[1])).default)('ModalHostView',{interfaceOnly:!0,paperComponentName:'RCTModalHostView'});e.default=o},713,[407,584]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.RootTagContext=void 0,e.createRootTag=function(t){return t};var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var p in n)if("default"!==p&&Object.prototype.hasOwnProperty.call(n,p)){var l=c?Object.getOwnPropertyDescriptor(n,p):null;l&&(l.get||l.set)?Object.defineProperty(f,p,l):f[p]=n[p]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).createContext(0);e.RootTagContext=n},714,[534]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),n=(function(){if(t.default){var n=t.default.getConstants(),f=n.isRTL,L=n.doLeftAndRightSwapInRTL,R=n.localeIdentifier;return{isRTL:f,doLeftAndRightSwapInRTL:L,localeIdentifier:R}}return{isRTL:!1,doLeftAndRightSwapInRTL:!0}})();m.exports={getConstants:function(){return n},allowRTL:function(n){t.default&&t.default.allowRTL(n)},forceRTL:function(n){t.default&&t.default.forceRTL(n)},swapLeftAndRightInRTL:function(n){t.default&&t.default.swapLeftAndRightInRTL(n)},isRTL:n.isRTL,doLeftAndRightSwapInRTL:n.doLeftAndRightSwapInRTL}},715,[407,716]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in n)if("default"!==l&&Object.prototype.hasOwnProperty.call(n,l)){var p=c?Object.getOwnPropertyDescriptor(n,l):null;p&&(p.get||p.set)?Object.defineProperty(f,l,p):f[l]=n[l]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).get('I18nManager');e.default=n},716,[428]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=r(d[0])(r(d[1])),s=r(d[0])(r(d[2])),t=r(d[0])(r(d[3])),l=(function(n,s){if(!s&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var t=p(s);if(t&&t.has(n))return t.get(n);var l={},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var u in n)if("default"!==u&&Object.prototype.hasOwnProperty.call(n,u)){var f=o?Object.getOwnPropertyDescriptor(n,u):null;f&&(f.get||f.set)?Object.defineProperty(l,u,f):l[u]=n[u]}l.default=n,t&&t.set(n,l);return l})(r(d[4])),o=r(d[0])(r(d[5])),u=r(d[0])(r(d[6])),f=r(d[0])(r(d[7])),c=["accessible","android_disableSound","android_ripple","cancelable","children","delayLongPress","disabled","focusable","onLongPress","onPress","onPressIn","onPressOut","pressRetentionOffset","style","testOnly_pressed","unstable_pressDelay"];function p(n){if("function"!=typeof WeakMap)return null;var s=new WeakMap,t=new WeakMap;return(p=function(n){return n?t:s})(n)}function b(n){var t=(0,l.useState)(!1),o=(0,s.default)(t,2),u=o[0],f=o[1];return[u||n,f]}var P=l.memo(l.forwardRef(function(p,P){var y=p.accessible,v=p.android_disableSound,O=p.android_ripple,_=p.cancelable,S=p.children,M=p.delayLongPress,h=p.disabled,j=p.focusable,w=p.onLongPress,I=p.onPress,L=p.onPressIn,R=p.onPressOut,D=p.pressRetentionOffset,k=p.style,W=p.testOnly_pressed,z=p.unstable_pressDelay,E=(0,t.default)(p,c),H=(0,l.useRef)(null);(0,l.useImperativeHandle)(P,function(){return H.current});var N=(0,o.default)(O,H),q=b(!0===W),x=(0,s.default)(q,2),A=x[0],B=x[1],C=(0,r(d[8]).normalizeRect)(p.hitSlop),F=null!=h?(0,n.default)({},p.accessibilityState,{disabled:h}):p.accessibilityState,G=(0,n.default)({},E,null==N?void 0:N.viewProps,{accessible:!1!==y,accessibilityState:F,focusable:!1!==j,hitSlop:C}),J=(0,l.useMemo)(function(){return{cancelable:_,disabled:h,hitSlop:C,pressRectOffset:D,android_disableSound:v,delayLongPress:M,delayPressIn:z,onLongPress:w,onPress:I,onPressIn:function(n){null!=N&&N.onPressIn(n),B(!0),null!=L&&L(n)},onPressMove:null==N?void 0:N.onPressMove,onPressOut:function(n){null!=N&&N.onPressOut(n),B(!1),null!=R&&R(n)}}},[v,N,_,M,h,C,w,I,L,R,D,B,z]),K=(0,u.default)(J);return l.createElement(f.default,(0,n.default)({},G,K,{ref:H,style:'function'==typeof k?k({pressed:A}):k,collapsable:!1}),'function'==typeof S?S({pressed:A}):S,null)}));P.displayName='Pressable';var y=P;e.default=y},717,[407,436,430,508,534,718,605,579,611]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=function(l,u){var s=null!=l?l:{},c=s.color,f=s.borderless,p=s.radius,v=s.foreground;return(0,o.useMemo)(function(){if('android'===t.Platform.OS&&t.Platform.Version>=21&&(null!=c||null!=f||null!=p)){var o=(0,t.processColor)(c);(0,n.default)(null==o||'number'==typeof o,'Unexpected color given for Ripple color');var l={type:'RippleAndroid',color:o,borderless:!0===f,rippleRadius:p};return{viewProps:!0===v?{nativeForegroundAndroid:l}:{nativeBackgroundAndroid:l},onPressIn:function(n){var t,o,l=u.current;null!=l&&(r(d[4]).Commands.hotspotUpdate(l,null!=(t=n.nativeEvent.locationX)?t:0,null!=(o=n.nativeEvent.locationY)?o:0),r(d[4]).Commands.setPressed(l,!0))},onPressMove:function(n){var t,o,l=u.current;null!=l&&r(d[4]).Commands.hotspotUpdate(l,null!=(t=n.nativeEvent.locationX)?t:0,null!=(o=n.nativeEvent.locationY)?o:0)},onPressOut:function(n){var t=u.current;null!=t&&r(d[4]).Commands.setPressed(t,!1)}}}return null},[f,c,v,p,u])};var n=r(d[0])(r(d[1])),t=r(d[2]),o=(function(n,t){if(!t&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var o=l(t);if(o&&o.has(n))return o.get(n);var u={},s=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in n)if("default"!==c&&Object.prototype.hasOwnProperty.call(n,c)){var f=s?Object.getOwnPropertyDescriptor(n,c):null;f&&(f.get||f.set)?Object.defineProperty(u,c,f):u[c]=n[c]}u.default=n,o&&o.set(n,u);return u})(r(d[3]));function l(n){if("function"!=typeof WeakMap)return null;var t=new WeakMap,o=new WeakMap;return(l=function(n){return n?o:t})(n)}},718,[407,425,411,534,580]); -__d(function(g,r,i,a,m,_e,d){'use strict';var t=r(d[0])(r(d[1])),e=r(d[0])(r(d[2])),n=r(d[0])(r(d[3])),o=r(d[0])(r(d[4])),u=r(d[0])(r(d[5])),f=(function(t,e){if(!e&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var n=p(e);if(n&&n.has(t))return n.get(t);var o={},u=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var f in t)if("default"!==f&&Object.prototype.hasOwnProperty.call(t,f)){var c=u?Object.getOwnPropertyDescriptor(t,f):null;c&&(c.get||c.set)?Object.defineProperty(o,f,c):o[f]=t[f]}o.default=t,n&&n.set(t,o);return o})(r(d[6])),c=r(d[0])(r(d[7])),l=r(d[0])(r(d[8])),s=r(d[0])(r(d[9]));function p(t){if("function"!=typeof WeakMap)return null;var e=new WeakMap,n=new WeakMap;return(p=function(t){return t?n:e})(t)}function y(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var h=(function(c){(0,n.default)(O,c);var p,h,b=(p=O,h=y(),function(){var t,e=(0,u.default)(p);if(h){var n=(0,u.default)(this).constructor;t=Reflect.construct(e,arguments,n)}else t=e.apply(this,arguments);return(0,o.default)(this,t)});function O(){return(0,t.default)(this,O),b.apply(this,arguments)}return(0,e.default)(O,[{key:"render",value:function(){return f.createElement(s.default,{style:[v.dummy,this.props.style]},f.createElement(l.default,{style:v.text},"ProgressViewIOS is not supported on this platform!"))}}]),O})(f.Component),v=c.default.create({dummy:{width:120,height:20,backgroundColor:'#ffbcbc',borderWidth:1,borderColor:'red',alignItems:'center',justifyContent:'center'},text:{color:'#333333',margin:5,fontSize:10}});m.exports=h},719,[407,402,403,417,419,422,534,578,589,579]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var t,n=r(d[0])(r(d[1])),u=r(d[0])(r(d[2])),f=r(d[0])(r(d[3])),o=(function(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var u=c(n);if(u&&u.has(t))return u.get(t);var f={},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in t)if("default"!==l&&Object.prototype.hasOwnProperty.call(t,l)){var p=o?Object.getOwnPropertyDescriptor(t,l):null;p&&(p.get||p.set)?Object.defineProperty(f,l,p):f[l]=t[l]}f.default=t,u&&u.set(t,f);return f})(r(d[4])),l=r(d[0])(r(d[5])),p=["emulateUnlessSupported"];function c(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,u=new WeakMap;return(c=function(t){return t?u:n})(t)}if('android'===f.default.OS)t=o.forwardRef(function(t,f){t.emulateUnlessSupported;var c=(0,u.default)(t,p);return o.createElement(l.default,(0,n.default)({},c,{ref:f}))});else{var s=r(d[6]).default;t=o.forwardRef(function(t,u){return o.createElement(s,(0,n.default)({emulateUnlessSupported:!0},t,{ref:u}))})}var v=t;e.default=v},720,[407,436,508,426,534,579,721]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var f=(0,r(d[0])(r(d[1])).default)('SafeAreaView',{paperComponentName:'RCTSafeAreaView',interfaceOnly:!0});e.default=f},721,[407,584]); -__d(function(g,r,i,a,m,_e,d){'use strict';var t=r(d[0])(r(d[1])),e=r(d[0])(r(d[2])),n=r(d[0])(r(d[3])),o=r(d[0])(r(d[4])),u=r(d[0])(r(d[5])),f=(function(t,e){if(!e&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var n=p(e);if(n&&n.has(t))return n.get(t);var o={},u=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var f in t)if("default"!==f&&Object.prototype.hasOwnProperty.call(t,f)){var c=u?Object.getOwnPropertyDescriptor(t,f):null;c&&(c.get||c.set)?Object.defineProperty(o,f,c):o[f]=t[f]}o.default=t,n&&n.set(t,o);return o})(r(d[6])),c=r(d[0])(r(d[7])),l=r(d[0])(r(d[8])),s=r(d[0])(r(d[9]));function p(t){if("function"!=typeof WeakMap)return null;var e=new WeakMap,n=new WeakMap;return(p=function(t){return t?n:e})(t)}function y(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var h=(function(c){(0,n.default)(O,c);var p,h,b=(p=O,h=y(),function(){var t,e=(0,u.default)(p);if(h){var n=(0,u.default)(this).constructor;t=Reflect.construct(e,arguments,n)}else t=e.apply(this,arguments);return(0,o.default)(this,t)});function O(){return(0,t.default)(this,O),b.apply(this,arguments)}return(0,e.default)(O,[{key:"render",value:function(){return f.createElement(s.default,{style:[v.dummy,this.props.style]},f.createElement(l.default,{style:v.text},"SegmentedControlIOS is not supported on this platform!"))}}]),O})(f.Component),v=c.default.create({dummy:{width:120,height:50,backgroundColor:'#ffbcbc',borderWidth:1,borderColor:'red',alignItems:'center',justifyContent:'center'},text:{color:'#333333',margin:5,fontSize:10}});m.exports=h},722,[407,402,403,417,419,422,534,578,589,579]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),l=(function(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var l=c(n);if(l&&l.has(t))return l.get(t);var u={},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var f in t)if("default"!==f&&Object.prototype.hasOwnProperty.call(t,f)){var s=o?Object.getOwnPropertyDescriptor(t,f):null;s&&(s.get||s.set)?Object.defineProperty(u,f,s):u[f]=t[f]}u.default=t,l&&l.set(t,u);return u})(r(d[3])),u=r(d[0])(r(d[4])),o=r(d[0])(r(d[5])),f=r(d[0])(r(d[6])),s=["value","minimumValue","maximumValue","step","onValueChange","onSlidingComplete"];function c(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,l=new WeakMap;return(c=function(t){return t?l:n})(t)}var v,p=l.forwardRef(function(c,p){var b,y=f.default.compose(v.slider,c.style),S=c.value,O=void 0===S?.5:S,h=c.minimumValue,V=void 0===h?0:h,C=c.maximumValue,j=void 0===C?1:C,w=c.step,E=void 0===w?0:w,P=c.onValueChange,x=c.onSlidingComplete,M=(0,n.default)(c,s),R=P?function(t){var n=!0;'android'===u.default.OS&&(n=null!=t.nativeEvent.fromUser&&t.nativeEvent.fromUser),n&&P(t.nativeEvent.value)}:null,_=R,k=x?function(t){x(t.nativeEvent.value)}:null,W=!0===c.disabled||!0===(null==(b=c.accessibilityState)?void 0:b.disabled),D=W?(0,t.default)({},c.accessibilityState,{disabled:!0}):c.accessibilityState;return l.createElement(o.default,(0,t.default)({},M,{accessibilityState:D,enabled:!W,disabled:W,maximumValue:j,minimumValue:V,onChange:_,onResponderTerminationRequest:function(){return!1},onSlidingComplete:k,onStartShouldSetResponder:function(){return!0},onValueChange:R,ref:p,step:E,style:y,value:O}))});v='ios'===u.default.OS?f.default.create({slider:{height:40}}):f.default.create({slider:{}}),m.exports=p},723,[407,436,508,534,426,724,578]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var l=(0,r(d[0])(r(d[1])).default)('Slider',{interfaceOnly:!0,paperComponentName:'RCTSlider'});e.default=l},724,[407,584]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),o=r(d[0])(r(d[3])),l=r(d[0])(r(d[4])),u=C(r(d[5])),f=r(d[0])(r(d[6])),c=r(d[0])(r(d[7])),s=C(r(d[8])),v=C(r(d[9])),b=["disabled","ios_backgroundColor","onChange","onValueChange","style","thumbColor","trackColor","value"];function p(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,o=new WeakMap;return(p=function(t){return t?o:n})(t)}function C(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var o=p(n);if(o&&o.has(t))return o.get(t);var l={},u=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var f in t)if("default"!==f&&Object.prototype.hasOwnProperty.call(t,f)){var c=u?Object.getOwnPropertyDescriptor(t,f):null;c&&(c.get||c.set)?Object.defineProperty(l,f,c):l[f]=t[f]}return l.default=t,o&&o.set(t,l),l}var h=function(){return!1},y=function(){return!0},R=u.forwardRef(function(p,C){var R=p.disabled,k=p.ios_backgroundColor,O=p.onChange,w=p.onValueChange,S=p.style,_=p.thumbColor,j=p.trackColor,P=p.value,T=(0,o.default)(p,b),E=null==j?void 0:j.false,M=null==j?void 0:j.true,V=u.useRef(null),F=(0,c.default)(V,C),W=u.useState({value:null}),q=(0,n.default)(W,2),D=q[0],N=q[1],L=function(t){null==O||O(t),null==w||w(t.nativeEvent.value),N({value:t.nativeEvent.value})};if(u.useLayoutEffect(function(){var t,n=!0===P;D.value!==n&&null!=(null==(t=V.current)?void 0:t.setNativeProps)&&('android'===l.default.OS?s.Commands.setNativeValue(V.current,n):v.Commands.setValue(V.current,n))},[P,D]),'android'===l.default.OS){var x,z={enabled:!0!==R,on:!0===P,style:S,thumbTintColor:_,trackColorForFalse:E,trackColorForTrue:M,trackTintColor:!0===P?M:E};return u.createElement(s.default,(0,t.default)({},T,z,{accessibilityRole:null!=(x=p.accessibilityRole)?x:'switch',onChange:L,onResponderTerminationRequest:h,onStartShouldSetResponder:y,ref:F}))}var A,B={disabled:R,onTintColor:M,style:f.default.compose({height:31,width:51},f.default.compose(S,null==k?null:{backgroundColor:k,borderRadius:16})),thumbTintColor:_,tintColor:E,value:!0===P};return u.createElement(v.default,(0,t.default)({},T,B,{accessibilityRole:null!=(A=p.accessibilityRole)?A:'switch',onChange:L,onResponderTerminationRequest:h,onStartShouldSetResponder:y,ref:F}))});e.default=R},725,[407,436,430,508,426,534,578,726,727,728]); -__d(function(g,r,_i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=function(){for(var o=arguments.length,u=new Array(o),i=0;i=t.length?{done:!0}:{done:!1,value:t[i++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function o(t,n){if(t){if("string"==typeof t)return u(t,n);var o=Object.prototype.toString.call(t).slice(8,-1);return"Object"===o&&t.constructor&&(o=t.constructor.name),"Map"===o||"Set"===o?Array.from(t):"Arguments"===o||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(o)?u(t,n):void 0}}function u(t,n){(null==n||n>t.length)&&(n=t.length);for(var o=0,u=new Array(n);o1&&(be=u.createElement(f.default,null,be)),oe=u.createElement(I,(0,t.default)({ref:ee},o,pe,{accessible:ce,autoCapitalize:ye,blurOnSubmit:ae,caretHidden:se,children:be,disableFullscreenUI:o.disableFullscreenUI,focusable:ie,mostRecentEventCount:H,onBlur:ue,onChange:te,onFocus:le,onScroll:re,onSelectionChange:ne,placeholder:Se,selection:M,style:Ce,text:X,textBreakStrategy:o.textBreakStrategy}))}return u.createElement(p.default.Provider,{value:!0},oe)}var M=u.forwardRef(function(l,o){var c=l.allowFontScaling,s=void 0===c||c,f=l.rejectResponderTermination,p=void 0===f||f,v=l.underlineColorAndroid,C=void 0===v?'transparent':v,y=(0,n.default)(l,F);return u.createElement(A,(0,t.default)({allowFontScaling:s,rejectResponderTermination:p,underlineColorAndroid:C},y,{forwardedRef:o}))});M.propTypes=o.default,M.State={currentlyFocusedInput:v.default.currentlyFocusedInput,currentlyFocusedField:v.default.currentlyFocusedField,focusTextInput:v.default.focusTextInput,blurTextInput:v.default.blurTextInput};var z=s.default.create({multilineInput:{paddingTop:5}});m.exports=M},729,[407,436,508,430,534,730,426,578,589,581,540,425,702,646,605,541,731,733]); -__d(function(g,r,i,a,m,e,d){'use strict';var n=['phoneNumber','link','address','calendarEvent','none','all'];m.exports=r(d[0])({},r(d[1]),{autoCapitalize:r(d[2]).oneOf(['none','sentences','words','characters']),autoComplete:r(d[2]).oneOf(['cc-csc','cc-exp','cc-exp-month','cc-exp-year','cc-number','email','name','password','postal-code','street-address','tel','username','off']),autoCorrect:r(d[2]).bool,spellCheck:r(d[2]).bool,autoFocus:r(d[2]).bool,allowFontScaling:r(d[2]).bool,maxFontSizeMultiplier:r(d[2]).number,editable:r(d[2]).bool,keyboardType:r(d[2]).oneOf(['default','email-address','numeric','phone-pad','number-pad','url','ascii-capable','numbers-and-punctuation','name-phone-pad','decimal-pad','twitter','web-search','ascii-capable-number-pad','visible-password']),keyboardAppearance:r(d[2]).oneOf(['default','light','dark']),returnKeyType:r(d[2]).oneOf(['done','go','next','search','send','none','previous','default','emergency-call','google','join','route','yahoo']),returnKeyLabel:r(d[2]).string,maxLength:r(d[2]).number,numberOfLines:r(d[2]).number,disableFullscreenUI:r(d[2]).bool,enablesReturnKeyAutomatically:r(d[2]).bool,multiline:r(d[2]).bool,textBreakStrategy:r(d[2]).oneOf(['simple','highQuality','balanced']),onBlur:r(d[2]).func,onFocus:r(d[2]).func,onChange:r(d[2]).func,onChangeText:r(d[2]).func,onContentSizeChange:r(d[2]).func,onTextInput:r(d[2]).func,onEndEditing:r(d[2]).func,onSelectionChange:r(d[2]).func,onSubmitEditing:r(d[2]).func,onKeyPress:r(d[2]).func,onLayout:r(d[2]).func,onScroll:r(d[2]).func,placeholder:r(d[2]).string,placeholderTextColor:r(d[3]),scrollEnabled:r(d[2]).bool,secureTextEntry:r(d[2]).bool,selectionColor:r(d[3]),selection:r(d[2]).shape({start:r(d[2]).number.isRequired,end:r(d[2]).number}),value:r(d[2]).string,defaultValue:r(d[2]).string,clearButtonMode:r(d[2]).oneOf(['never','while-editing','unless-editing','always']),clearTextOnFocus:r(d[2]).bool,selectTextOnFocus:r(d[2]).bool,blurOnSubmit:r(d[2]).bool,style:r(d[4]).style,underlineColorAndroid:r(d[3]),inlineImageLeft:r(d[2]).string,inlineImagePadding:r(d[2]).number,rejectResponderTermination:r(d[2]).bool,dataDetectorTypes:r(d[2]).oneOfType([r(d[2]).oneOf(n),r(d[2]).arrayOf(r(d[2]).oneOf(n))]),caretHidden:r(d[2]).bool,contextMenuHidden:r(d[2]).bool,inputAccessoryViewID:r(d[2]).string,textContentType:r(d[2]).oneOf(['none','URL','addressCity','addressCityAndState','addressState','countryName','creditCardNumber','emailAddress','familyName','fullStreetAddress','givenName','jobTitle','location','middleName','name','namePrefix','nameSuffix','nickname','organizationName','postalCode','streetAddressLine1','streetAddressLine2','sublocality','telephoneNumber','username','password','newPassword','oneTimeCode']),showSoftInputOnFocus:r(d[2]).bool})},730,[436,682,596,600,590]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=e.Commands=void 0;var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),u=(function(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var u=o(n);if(u&&u.has(t))return u.get(t);var f={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in t)if("default"!==c&&Object.prototype.hasOwnProperty.call(t,c)){var p=l?Object.getOwnPropertyDescriptor(t,c):null;p&&(p.get||p.set)?Object.defineProperty(f,c,p):f[c]=t[c]}f.default=t,u&&u.set(t,f);return f})(r(d[3]));function o(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,u=new WeakMap;return(o=function(t){return t?u:n})(t)}var f=(0,t.default)({supportedCommands:['focus','blur','setTextAndSelection']});e.Commands=f;var l=u.get('RCTSinglelineTextInputView',function(){return n.default});e.default=l},731,[407,542,732,555]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),o=r(d[0])(r(d[2])),n={uiViewClassName:'RCTSinglelineTextInputView',bubblingEventTypes:{topBlur:{phasedRegistrationNames:{bubbled:'onBlur',captured:'onBlurCapture'}},topChange:{phasedRegistrationNames:{bubbled:'onChange',captured:'onChangeCapture'}},topEndEditing:{phasedRegistrationNames:{bubbled:'onEndEditing',captured:'onEndEditingCapture'}},topFocus:{phasedRegistrationNames:{bubbled:'onFocus',captured:'onFocusCapture'}},topKeyPress:{phasedRegistrationNames:{bubbled:'onKeyPress',captured:'onKeyPressCapture'}},topSubmitEditing:{phasedRegistrationNames:{bubbled:'onSubmitEditing',captured:'onSubmitEditingCapture'}},topTouchCancel:{phasedRegistrationNames:{bubbled:'onTouchCancel',captured:'onTouchCancelCapture'}},topTouchEnd:{phasedRegistrationNames:{bubbled:'onTouchEnd',captured:'onTouchEndCapture'}},topTouchMove:{phasedRegistrationNames:{bubbled:'onTouchMove',captured:'onTouchMoveCapture'}}},directEventTypes:{},validAttributes:(0,t.default)({},o.default.validAttributes,{fontSize:!0,fontWeight:!0,fontVariant:!0,textShadowOffset:{diff:r(d[3])},allowFontScaling:!0,fontStyle:!0,textTransform:!0,textAlign:!0,fontFamily:!0,lineHeight:!0,isHighlighted:!0,writingDirection:!0,textDecorationLine:!0,textShadowRadius:!0,letterSpacing:!0,textDecorationStyle:!0,textDecorationColor:{process:r(d[4])},color:{process:r(d[4])},maxFontSizeMultiplier:!0,textShadowColor:{process:r(d[4])},editable:!0,inputAccessoryViewID:!0,caretHidden:!0,enablesReturnKeyAutomatically:!0,placeholderTextColor:{process:r(d[4])},onSelectionChange:!0,clearButtonMode:!0,onContentSizeChange:!0,keyboardType:!0,selection:!0,returnKeyType:!0,blurOnSubmit:!0,mostRecentEventCount:!0,onChange:!0,scrollEnabled:!0,selectionColor:{process:r(d[4])},contextMenuHidden:!0,secureTextEntry:!0,onTextInput:!0,placeholder:!0,autoCorrect:!0,onScroll:!0,multiline:!0,textContentType:!0,maxLength:!0,autoCapitalize:!0,keyboardAppearance:!0,passwordRules:!0,spellCheck:!0,selectTextOnFocus:!0,text:!0,clearTextOnFocus:!0})};m.exports=n},732,[407,436,544,551,546]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=e.Commands=void 0;var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),u=(function(t,n){if(!n&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var u=o(n);if(u&&u.has(t))return u.get(t);var f={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in t)if("default"!==c&&Object.prototype.hasOwnProperty.call(t,c)){var p=l?Object.getOwnPropertyDescriptor(t,c):null;p&&(p.get||p.set)?Object.defineProperty(f,c,p):f[c]=t[c]}f.default=t,u&&u.set(t,f);return f})(r(d[3]));function o(t){if("function"!=typeof WeakMap)return null;var n=new WeakMap,u=new WeakMap;return(o=function(t){return t?u:n})(t)}var f=(0,t.default)({supportedCommands:['focus','blur','setTextAndSelection']});e.Commands=f;var l=u.get('RCTMultilineTextInputView',function(){return n.default});e.default=l},733,[407,542,732,555]); -__d(function(g,r,i,a,m,_e,d){var t=r(d[0])(r(d[1])),e=r(d[0])(r(d[2])),o=((function(t,e){if(!e&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var o=u(e);if(o&&o.has(t))return o.get(t);var E={},s=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var n in t)if("default"!==n&&Object.prototype.hasOwnProperty.call(t,n)){var l=s?Object.getOwnPropertyDescriptor(t,n):null;l&&(l.get||l.set)?Object.defineProperty(E,n,l):E[n]=t[n]}E.default=t,o&&o.set(t,E)})(r(d[3])),r(d[0])(r(d[4]))),E=r(d[0])(r(d[5])),s=r(d[0])(r(d[6])),n=r(d[0])(r(d[7])),l=r(d[0])(r(d[8]));function u(t){if("function"!=typeof WeakMap)return null;var e=new WeakMap,o=new WeakMap;return(u=function(t){return t?o:e})(t)}var h=function(t){var e=t.touches,o=t.changedTouches,E=e&&e.length>0,s=o&&o.length>0;return!E&&s?o[0]:E?e[0]:t},R='NOT_RESPONDER',_='RESPONDER_INACTIVE_PRESS_IN',c='RESPONDER_INACTIVE_PRESS_OUT',S='RESPONDER_ACTIVE_PRESS_IN',T='RESPONDER_ACTIVE_PRESS_OUT',P='RESPONDER_ACTIVE_LONG_PRESS_IN',D='RESPONDER_ACTIVE_LONG_PRESS_OUT',N='ERROR',O={NOT_RESPONDER:!1,RESPONDER_INACTIVE_PRESS_IN:!1,RESPONDER_INACTIVE_PRESS_OUT:!1,RESPONDER_ACTIVE_PRESS_IN:!1,RESPONDER_ACTIVE_PRESS_OUT:!1,RESPONDER_ACTIVE_LONG_PRESS_IN:!1,RESPONDER_ACTIVE_LONG_PRESS_OUT:!1,ERROR:!1},p=(0,e.default)({},O,{RESPONDER_ACTIVE_PRESS_OUT:!0,RESPONDER_ACTIVE_PRESS_IN:!0}),f=(0,e.default)({},O,{RESPONDER_INACTIVE_PRESS_IN:!0,RESPONDER_ACTIVE_PRESS_IN:!0,RESPONDER_ACTIVE_LONG_PRESS_IN:!0}),A=(0,e.default)({},O,{RESPONDER_ACTIVE_LONG_PRESS_IN:!0}),b='DELAY',I='RESPONDER_GRANT',L='RESPONDER_RELEASE',v='RESPONDER_TERMINATED',y='ENTER_PRESS_RECT',C='LEAVE_PRESS_RECT',G='LONG_PRESS_DETECTED',V={NOT_RESPONDER:{DELAY:N,RESPONDER_GRANT:_,RESPONDER_RELEASE:N,RESPONDER_TERMINATED:N,ENTER_PRESS_RECT:N,LEAVE_PRESS_RECT:N,LONG_PRESS_DETECTED:N},RESPONDER_INACTIVE_PRESS_IN:{DELAY:S,RESPONDER_GRANT:N,RESPONDER_RELEASE:R,RESPONDER_TERMINATED:R,ENTER_PRESS_RECT:_,LEAVE_PRESS_RECT:c,LONG_PRESS_DETECTED:N},RESPONDER_INACTIVE_PRESS_OUT:{DELAY:T,RESPONDER_GRANT:N,RESPONDER_RELEASE:R,RESPONDER_TERMINATED:R,ENTER_PRESS_RECT:_,LEAVE_PRESS_RECT:c,LONG_PRESS_DETECTED:N},RESPONDER_ACTIVE_PRESS_IN:{DELAY:N,RESPONDER_GRANT:N,RESPONDER_RELEASE:R,RESPONDER_TERMINATED:R,ENTER_PRESS_RECT:S,LEAVE_PRESS_RECT:T,LONG_PRESS_DETECTED:P},RESPONDER_ACTIVE_PRESS_OUT:{DELAY:N,RESPONDER_GRANT:N,RESPONDER_RELEASE:R,RESPONDER_TERMINATED:R,ENTER_PRESS_RECT:S,LEAVE_PRESS_RECT:T,LONG_PRESS_DETECTED:N},RESPONDER_ACTIVE_LONG_PRESS_IN:{DELAY:N,RESPONDER_GRANT:N,RESPONDER_RELEASE:R,RESPONDER_TERMINATED:R,ENTER_PRESS_RECT:P,LEAVE_PRESS_RECT:D,LONG_PRESS_DETECTED:P},RESPONDER_ACTIVE_LONG_PRESS_OUT:{DELAY:N,RESPONDER_GRANT:N,RESPONDER_RELEASE:R,RESPONDER_TERMINATED:R,ENTER_PRESS_RECT:P,LEAVE_PRESS_RECT:D,LONG_PRESS_DETECTED:N},error:{DELAY:R,RESPONDER_GRANT:_,RESPONDER_RELEASE:R,RESPONDER_TERMINATED:R,ENTER_PRESS_RECT:R,LEAVE_PRESS_RECT:R,LONG_PRESS_DETECTED:R}},H={componentDidMount:function(){E.default.isTV},componentWillUnmount:function(){this.touchableDelayTimeout&&clearTimeout(this.touchableDelayTimeout),this.longPressDelayTimeout&&clearTimeout(this.longPressDelayTimeout),this.pressOutDelayTimeout&&clearTimeout(this.pressOutDelayTimeout)},touchableGetInitialState:function(){return{touchable:{touchState:void 0,responderID:null}}},touchableHandleResponderTerminationRequest:function(){return!this.props.rejectResponderTermination},touchableHandleStartShouldSetResponder:function(){return!this.props.disabled},touchableLongPressCancelsPress:function(){return!0},touchableHandleResponderGrant:function(t){var e=t.currentTarget;t.persist(),this.pressOutDelayTimeout&&clearTimeout(this.pressOutDelayTimeout),this.pressOutDelayTimeout=null,this.state.touchable.touchState=R,this.state.touchable.responderID=e,this._receiveSignal(I,t);var o=void 0!==this.touchableGetHighlightDelayMS?Math.max(this.touchableGetHighlightDelayMS(),0):130;0!==(o=isNaN(o)?130:o)?this.touchableDelayTimeout=setTimeout(this._handleDelay.bind(this,t),o):this._handleDelay(t);var E=void 0!==this.touchableGetLongPressDelayMS?Math.max(this.touchableGetLongPressDelayMS(),10):370;E=isNaN(E)?370:E,this.longPressDelayTimeout=setTimeout(this._handleLongDelay.bind(this,t),E+o)},touchableHandleResponderRelease:function(t){this.pressInLocation=null,this._receiveSignal(L,t)},touchableHandleResponderTerminate:function(t){this.pressInLocation=null,this._receiveSignal(v,t)},touchableHandleResponderMove:function(t){if(this.state.touchable.positionOnActivate){var e=this.state.touchable.positionOnActivate,o=this.state.touchable.dimensionsOnActivate,E=this.touchableGetPressRectOffset?this.touchableGetPressRectOffset():{left:20,right:20,top:20,bottom:20},s=E.left,n=E.top,l=E.right,u=E.bottom,R=this.touchableGetHitSlop?this.touchableGetHitSlop():null;R&&(s+=R.left||0,n+=R.top||0,l+=R.right||0,u+=R.bottom||0);var c=h(t.nativeEvent),S=c&&c.pageX,T=c&&c.pageY;if(this.pressInLocation)this._getDistanceBetweenPoints(S,T,this.pressInLocation.pageX,this.pressInLocation.pageY)>10&&this._cancelLongPressDelayTimeout();if(S>e.left-s&&T>e.top-n&&S>`");E!==s&&(this._performSideEffectsForTransition(E,s,t,e),this.state.touchable.touchState=s)}},_cancelLongPressDelayTimeout:function(){this.longPressDelayTimeout&&clearTimeout(this.longPressDelayTimeout),this.longPressDelayTimeout=null},_isHighlight:function(t){return t===S||t===P},_savePressInLocation:function(t){var e=h(t.nativeEvent),o=e&&e.pageX,E=e&&e.pageY,s=e&&e.locationX,n=e&&e.locationY;this.pressInLocation={pageX:o,pageY:E,locationX:s,locationY:n}},_getDistanceBetweenPoints:function(t,e,o,E){var s=t-o,n=e-E;return Math.sqrt(s*s+n*n)},_performSideEffectsForTransition:function(t,e,o,s){var n=this._isHighlight(t),u=this._isHighlight(e);(o===v||o===L)&&this._cancelLongPressDelayTimeout();var h=t===R&&e===_,c=!p[t]&&p[e];if((h||c)&&this._remeasureMetricsOnActivation(),f[t]&&o===G&&this.touchableHandleLongPress&&this.touchableHandleLongPress(s),u&&!n?this._startHighlight(s):!u&&n&&this._endHighlight(s),f[t]&&o===L){var S=!!this.props.onLongPress,T=A[t]&&(!S||!this.touchableLongPressCancelsPress());(!A[t]||T)&&this.touchableHandlePress&&(u||n||(this._startHighlight(s),this._endHighlight(s)),'android'!==E.default.OS||this.props.touchSoundDisabled||l.default.playTouchSound(),this.touchableHandlePress(s))}this.touchableDelayTimeout&&clearTimeout(this.touchableDelayTimeout),this.touchableDelayTimeout=null},_startHighlight:function(t){this._savePressInLocation(t),this.touchableHandleActivePressIn&&this.touchableHandleActivePressIn(t)},_endHighlight:function(t){var e=this;this.touchableHandleActivePressOut&&(this.touchableGetPressOutDelayMS&&this.touchableGetPressOutDelayMS()?this.pressOutDelayTimeout=setTimeout(function(){e.touchableHandleActivePressOut(t)},this.touchableGetPressOutDelayMS()):this.touchableHandleActivePressOut(t))},withoutDefaultFocusAndBlur:{}},M=(H.touchableHandleFocus,H.touchableHandleBlur,(0,t.default)(H,["touchableHandleFocus","touchableHandleBlur"]));H.withoutDefaultFocusAndBlur=M;var w={Mixin:H,renderDebugView:function(t){t.color,t.hitSlop;return null}};m.exports=w},734,[407,508,436,534,735,426,737,450,607]); -__d(function(g,r,i,a,m,e,d){'use strict';var t=r(d[0])(r(d[1])),o=t.default.twoArgumentPooler;function n(t,o){this.width=t,this.height=o}n.prototype.destructor=function(){this.width=null,this.height=null},n.getPooledFromElement=function(t){return n.getPooled(t.offsetWidth,t.offsetHeight)},t.default.addPoolingTo(n,o),m.exports=n},735,[407,736]); -__d(function(g,r,i,a,m,e,d){'use strict';var t=r(d[0])(r(d[1])),n=function(t){if(this.instancePool.length){var n=this.instancePool.pop();return this.call(n,t),n}return new this(t)},o=function(n){(0,t.default)(n instanceof this,'Trying to release an instance into a pool of a different type.'),n.destructor(),this.instancePool.length=e.length?{done:!0}:{done:!1,value:e[o++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function b(e,t){if(e){if("string"==typeof e)return h(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?h(e,t):void 0}}function h(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,o=new Array(t);n=0;n--)if(t[n]())return;i.exitApp()});var i={exitApp:function(){n.default&&n.default.invokeDefaultBackPressHandler()},addEventListener:function(n,f){return-1===t.indexOf(f)&&t.push(f),{remove:function(){return i.removeEventListener(n,f)}}},removeEventListener:function(n,i){-1!==t.indexOf(i)&&t.splice(t.indexOf(i),1)}};m.exports=i},750,[407,751,413]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in n)if("default"!==l&&Object.prototype.hasOwnProperty.call(n,l)){var p=c?Object.getOwnPropertyDescriptor(n,l):null;p&&(p.get||p.set)?Object.defineProperty(f,l,p):f[l]=n[l]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).get('DeviceEventManager');e.default=n},751,[428]); -__d(function(g,r,i,a,m,_e,d){var t=r(d[0])(r(d[1])),e=r(d[0])(r(d[2])),n=r(d[0])(r(d[3])),o=r(d[0])(r(d[4])),u=r(d[0])(r(d[5])),c=r(d[0])(r(d[6])),l=(r(d[0])(r(d[7])),r(d[0])(r(d[8]))),s=(function(t,e){if(!e&&t&&t.__esModule)return t;if(null===t||"object"!=typeof t&&"function"!=typeof t)return{default:t};var n=p(e);if(n&&n.has(t))return n.get(t);var o={},u=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in t)if("default"!==c&&Object.prototype.hasOwnProperty.call(t,c)){var l=u?Object.getOwnPropertyDescriptor(t,c):null;l&&(l.get||l.set)?Object.defineProperty(o,c,l):o[c]=t[c]}o.default=t,n&&n.set(t,o);return o})(r(d[9]));function p(t){if("function"!=typeof WeakMap)return null;var e=new WeakMap,n=new WeakMap;return(p=function(t){return t?n:e})(t)}function f(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var h=(function(l){(0,n.default)(b,l);var p,h,y=(p=b,h=f(),function(){var t,e=(0,u.default)(p);if(h){var n=(0,u.default)(this).constructor;t=Reflect.construct(e,arguments,n)}else t=e.apply(this,arguments);return(0,o.default)(this,t)});function b(){var e;(0,t.default)(this,b);for(var n=arguments.length,o=new Array(n),u=0;uthis.eventPool.length&&this.eventPool.push(e)}function T(e){e.getPooled=_,e.eventPool=[],e.release=R}n(i[2])(P.prototype,{preventDefault:function(){this.defaultPrevented=!0;var e=this.nativeEvent;e&&(e.preventDefault?e.preventDefault():"unknown"!=typeof e.returnValue&&(e.returnValue=!1),this.isDefaultPrevented=w)},stopPropagation:function(){var e=this.nativeEvent;e&&(e.stopPropagation?e.stopPropagation():"unknown"!=typeof e.cancelBubble&&(e.cancelBubble=!0),this.isPropagationStopped=w)},persist:function(){this.isPersistent=w},isPersistent:x,destructor:function(){var e,n=this.constructor.Interface;for(e in n)this[e]=null;this.nativeEvent=this._targetInst=this.dispatchConfig=null,this.isPropagationStopped=this.isDefaultPrevented=x,this._dispatchInstances=this._dispatchListeners=null}}),P.Interface={type:null,target:null,currentTarget:function(){return null},eventPhase:null,bubbles:null,cancelable:null,timeStamp:function(e){return e.timeStamp||Date.now()},defaultPrevented:null,isTrusted:null},P.extend=function(e){function t(){}function r(){return l.apply(this,arguments)}var l=this;t.prototype=l.prototype;var a=new t;return n(i[2])(a,r.prototype),r.prototype=a,r.prototype.constructor=r,r.Interface=n(i[2])({},l.Interface,e),r.extend=l.extend,T(r),r},T(P);var E=P.extend({touchHistory:function(){return null}});function N(e){return"topTouchStart"===e}function C(e){return"topTouchMove"===e}var z=["topTouchStart"],I=["topTouchMove"],L=["topTouchCancel","topTouchEnd"],U=[],M={touchBank:U,numberActiveTouches:0,indexOfSingleActiveTouch:-1,mostRecentTimeStamp:0};function F(e){return e.timeStamp||e.timestamp}function D(e){if(null==(e=e.identifier))throw Error("Touch object is missing identifier.");return e}function A(e){var n=D(e),t=U[n];t?(t.touchActive=!0,t.startPageX=e.pageX,t.startPageY=e.pageY,t.startTimeStamp=F(e),t.currentPageX=e.pageX,t.currentPageY=e.pageY,t.currentTimeStamp=F(e),t.previousPageX=e.pageX,t.previousPageY=e.pageY,t.previousTimeStamp=F(e)):(t={touchActive:!0,startPageX:e.pageX,startPageY:e.pageY,startTimeStamp:F(e),currentPageX:e.pageX,currentPageY:e.pageY,currentTimeStamp:F(e),previousPageX:e.pageX,previousPageY:e.pageY,previousTimeStamp:F(e)},U[n]=t),M.mostRecentTimeStamp=F(e)}function H(e){var n=U[D(e)];n&&(n.touchActive=!0,n.previousPageX=n.currentPageX,n.previousPageY=n.currentPageY,n.previousTimeStamp=n.currentTimeStamp,n.currentPageX=e.pageX,n.currentPageY=e.pageY,n.currentTimeStamp=F(e),M.mostRecentTimeStamp=F(e))}function Q(e){var n=U[D(e)];n&&(n.touchActive=!1,n.previousPageX=n.currentPageX,n.previousPageY=n.currentPageY,n.previousTimeStamp=n.currentTimeStamp,n.currentPageX=e.pageX,n.currentPageY=e.pageY,n.currentTimeStamp=F(e),M.mostRecentTimeStamp=F(e))}var j,B={instrument:function(e){j=e},recordTouchTrack:function(e,n){if(null!=j&&j(e,n),C(e))n.changedTouches.forEach(H);else if(N(e))n.changedTouches.forEach(A),M.numberActiveTouches=n.touches.length,1===M.numberActiveTouches&&(M.indexOfSingleActiveTouch=n.touches[0].identifier);else if(("topTouchEnd"===e||"topTouchCancel"===e)&&(n.changedTouches.forEach(Q),M.numberActiveTouches=n.touches.length,1===M.numberActiveTouches))for(e=0;e=(a=n&-n)||16===l&&0!=(4194240&a)))return n;if(0!=(4&r)&&(r|=16&t),0!==(n=e.entangledLanes))for(e=e.entanglements,n&=r;0t;t++)n.push(e);return n}function wn(e,n,t){e.pendingLanes|=n,536870912!==n&&(e.suspendedLanes=0,e.pingedLanes=0),(e=e.eventTimes)[n=31-_n(n)]=t}function xn(e,n){var t=e.pendingLanes&~n;e.pendingLanes=n,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=n,e.mutableReadLanes&=n,e.entangledLanes&=n,n=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0 component.");return t=$n,$n+=2,{node:Ln(t,"RCTRawText",n,{text:e},r)}}var Kn=setTimeout,Zn=clearTimeout;function et(e){var n=e.node,t=an(null,Ge,{style:{display:"none"}},e.canonical.viewConfig.validAttributes);return{node:Dn(n,t),canonical:e.canonical}}function nt(e,n,t){return n="",t&&(n=" (created by "+t+")"),"\n in "+(e||"Unknown")+n}function tt(e,n){return e?nt(e.displayName||e.name||null,n,null):""}var rt=Object.prototype.hasOwnProperty,lt=[],at=-1;function it(e){return{current:e}}function ut(e){0>at||(e.current=lt[at],lt[at]=null,at--)}function ot(e,n){lt[++at]=e.current,e.current=n}var st={},ct=it(st),dt=it(!1),ft=st;function pt(e,n){var t=e.type.contextTypes;if(!t)return st;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===n)return r.__reactInternalMemoizedMaskedChildContext;var l,a={};for(l in t)a[l]=n[l];return r&&((e=e.stateNode).__reactInternalMemoizedUnmaskedChildContext=n,e.__reactInternalMemoizedMaskedChildContext=a),a}function ht(e){return null!==(e=e.childContextTypes)&&void 0!==e}function gt(){ut(dt),ut(ct)}function mt(e,n,t){if(ct.current!==st)throw Error("Unexpected context found on stack. This error is likely caused by a bug in React. Please file an issue.");ot(ct,n),ot(dt,t)}function vt(e,t,r){var l=e.stateNode;if(t=t.childContextTypes,"function"!=typeof l.getChildContext)return r;for(var a in l=l.getChildContext())if(!(a in t))throw Error((We(e)||"Unknown")+'.getChildContext(): key "'+a+'" is not defined in childContextTypes.');return n(i[2])({},r,l)}function bt(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||st,ft=ct.current,ot(ct,e),ot(dt,dt.current),!0}function yt(e,n,t){var r=e.stateNode;if(!r)throw Error("Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue.");t?(e=vt(e,n,ft),r.__reactInternalMemoizedMergedChildContext=e,ut(dt),ut(ct),ot(ct,e)):ut(dt),ot(dt,t)}var St=null,kt=!1,wt=!1;function xt(){if(!wt&&null!==St){wt=!0;var e=0,t=En;try{var r=St;for(En=1;eg?(m=h,h=null):m=h.sibling;var v=f(l,h,u[g],o);if(null===v){null===h&&(h=m);break}e&&h&&null===v.alternate&&n(l,h),i=a(v,i,g),null===c?s=v:c.sibling=v,c=v,h=m}if(g===u.length)return t(l,h),s;if(null===h){for(;gg?(m=h,h=null):m=h.sibling;var b=f(l,h,v.value,o);if(null===b){null===h&&(h=m);break}e&&h&&null===b.alternate&&n(l,h),i=a(b,i,g),null===c?s=b:c.sibling=b,c=b,h=m}if(v.done)return t(l,h),s;if(null===h){for(;!v.done;g++,v=u.next())null!==(v=d(l,v.value,o))&&(i=a(v,i,g),null===c?s=v:c.sibling=v,c=v);return s}for(h=r(l,h);!v.done;g++,v=u.next())null!==(v=p(h,l,g,v.value,o))&&(e&&null!==v.alternate&&h.delete(null===v.key?g:v.key),i=a(v,i,g),null===c?s=v:c.sibling=v,c=v);return e&&h.forEach(function(e){return n(l,e)}),s}return function(e,r,a,u){var o="object"==typeof a&&null!==a&&a.type===_e&&null===a.key;if(o&&(a=a.props.children),"object"==typeof a&&null!==a){switch(a.$$typeof){case xe:e:{var s=a.key;for(o=r;null!==o;){if(o.key===s){if((s=a.type)===_e){if(7===o.tag){t(e,o.sibling),(r=l(o,a.props.children)).return=e,e=r;break e}}else if(o.elementType===s){t(e,o.sibling),(r=l(o,a.props)).ref=nr(e,o,a),r.return=e,e=r;break e}t(e,o);break}n(e,o),o=o.sibling}a.type===_e?((r=ti(a.props.children,e.mode,u,a.key)).return=e,e=r):((u=ni(a.type,a.key,a.props,null,e.mode,u)).ref=nr(e,r,a),u.return=e,e=u)}return i(e);case Pe:e:{for(o=a.key;null!==r;){if(r.key===o){if(4===r.tag&&r.stateNode.containerInfo===a.containerInfo&&r.stateNode.implementation===a.implementation){t(e,r.sibling),(r=l(r,a.children||[])).return=e,e=r;break e}t(e,r);break}n(e,r),r=r.sibling}(r=ai(a,e.mode,u)).return=e,e=r}return i(e)}if(m(a))return h(e,r,a,u);if(je(a))return g(e,r,a,u);tr(e,a)}if("string"==typeof a||"number"==typeof a)return a=""+a,null!==r&&6===r.tag?(t(e,r.sibling),(r=l(r,a)).return=e,e=r):(t(e,r),(r=li(a,e.mode,u)).return=e,e=r),i(e);if(void 0===a&&!o)switch(e.tag){case 1:case 0:case 11:case 15:throw Error((We(e)||"Component")+"(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.")}return t(e,r)}}var lr=rr(!0),ar=rr(!1),ir={},ur=it(ir),or=it(ir),sr=it(ir);function cr(e){if(e===ir)throw Error("Expected host context to exist. This error is likely caused by a bug in React. Please file an issue.");return e}function dr(e,n){ot(sr,n),ot(or,e),ot(ur,ir),ut(ur),ot(ur,{isInAParentText:!1})}function fr(){ut(ur),ut(or),ut(sr)}function pr(e){cr(sr.current);var n=cr(ur.current),t=e.type;t="AndroidTextInput"===t||"RCTMultilineTextInputView"===t||"RCTSinglelineTextInputView"===t||"RCTText"===t||"RCTVirtualText"===t,n!==(t=n.isInAParentText!==t?{isInAParentText:t}:n)&&(ot(or,e),ot(ur,t))}function hr(e){or.current===e&&(ut(ur),ut(or))}var gr=it(0);function mr(e){for(var n=e;null!==n;){if(13===n.tag){var t=n.memoizedState;if(null!==t&&(null===t.dehydrated||zn()||zn()))return n}else if(19===n.tag&&void 0!==n.memoizedProps.revealOrder){if(0!=(128&n.flags))return n}else if(null!==n.child){n.child.return=n,n=n.child;continue}if(n===e)break;for(;null===n.sibling;){if(null===n.return||n.return===e)return null;n=n.return}n.sibling.return=n.return,n=n.sibling}return null}var vr=[];function br(){for(var e=0;ea))throw Error("Too many re-renders. React limits the number of renders to prevent an infinite loop.");a+=1,Pr=xr=null,n.updateQueue=null,yr.current=tl,e=t(r,l)}while(Rr)}if(yr.current=Zr,n=null!==xr&&null!==xr.next,kr=0,Pr=xr=wr=null,_r=!1,n)throw Error("Rendered fewer hooks than expected. This may be caused by an accidental early return statement.");return e}function Cr(){var e={memoizedState:null,baseState:null,baseQueue:null,queue:null,next:null};return null===Pr?wr.memoizedState=Pr=e:Pr=Pr.next=e,Pr}function zr(){if(null===xr){var e=wr.alternate;e=null!==e?e.memoizedState:null}else e=xr.next;var n=null===Pr?wr.memoizedState:Pr.next;if(null!==n)Pr=n,xr=e;else{if(null===e)throw Error("Rendered more hooks than during the previous render.");e={memoizedState:(xr=e).memoizedState,baseState:xr.baseState,baseQueue:xr.baseQueue,queue:xr.queue,next:null},null===Pr?wr.memoizedState=Pr=e:Pr=Pr.next=e}return Pr}function Ir(e,n){return"function"==typeof n?n(e):n}function Lr(e){var n=zr(),t=n.queue;if(null===t)throw Error("Should have a queue. This is likely a bug in React. Please file an issue.");t.lastRenderedReducer=e;var r=xr,l=r.baseQueue,a=t.pending;if(null!==a){if(null!==l){var i=l.next;l.next=a.next,a.next=i}r.baseQueue=l=a,t.pending=null}if(null!==l){a=l.next,r=r.baseState;var u=i=null,o=null,s=a;do{var c=s.lane;if((kr&c)===c)null!==o&&(o=o.next={lane:0,action:s.action,eagerReducer:s.eagerReducer,eagerState:s.eagerState,next:null}),r=s.eagerReducer===e?s.eagerState:e(r,s.action);else{var d={lane:c,action:s.action,eagerReducer:s.eagerReducer,eagerState:s.eagerState,next:null};null===o?(u=o=d,i=r):o=o.next=d,wr.lanes|=c,da|=c}s=s.next}while(null!==s&&s!==a);null===o?i=r:o.next=u,_t(r,n.memoizedState)||(sl=!0),n.memoizedState=r,n.baseState=i,n.baseQueue=o,t.lastRenderedState=r}if(null!==(e=t.interleaved)){l=e;do{a=l.lane,wr.lanes|=a,da|=a,l=l.next}while(l!==e)}else null===l&&(t.lanes=0);return[n.memoizedState,t.dispatch]}function Ur(e){var n=zr(),t=n.queue;if(null===t)throw Error("Should have a queue. This is likely a bug in React. Please file an issue.");t.lastRenderedReducer=e;var r=t.dispatch,l=t.pending,a=n.memoizedState;if(null!==l){t.pending=null;var i=l=l.next;do{a=e(a,i.action),i=i.next}while(i!==l);_t(a,n.memoizedState)||(sl=!0),n.memoizedState=a,null===n.baseQueue&&(n.baseState=a),t.lastRenderedState=a}return[a,r]}function Mr(e,n,t){var r=n._getVersion;r=r(n._source);var l=n._workInProgressVersionSecondary;if(null!==l?e=l===r:(e=e.mutableReadLanes,(e=(kr&e)===e)&&(n._workInProgressVersionSecondary=r,vr.push(n))),e)return t(n._source);throw vr.push(n),Error("Cannot read from mutable source during the current render without tearing. This may be a bug in React. Please file an issue.")}function Fr(e,n,t,r){var l=la;if(null===l)throw Error("Expected a work-in-progress root. This is a bug in React. Please file an issue.");var a=n._getVersion,i=a(n._source),u=yr.current,o=u.useState(function(){return Mr(l,n,t)}),s=o[1],c=o[0];o=Pr;var d=e.memoizedState,f=d.refs,p=f.getSnapshot,h=d.source;d=d.subscribe;var g=wr;return e.memoizedState={refs:f,source:n,subscribe:r},u.useEffect(function(){f.getSnapshot=t,f.setSnapshot=s;var e=a(n._source);_t(i,e)||(e=t(n._source),_t(c,e)||(s(e),e=Ta(g),l.mutableReadLanes|=e&l.pendingLanes),Pn(l,l.mutableReadLanes))},[t,n,r]),u.useEffect(function(){return r(n._source,function(){var e=f.getSnapshot,t=f.setSnapshot;try{t(e(n._source));var r=Ta(g);l.mutableReadLanes|=r&l.pendingLanes}catch(e){t(function(){throw e})}})},[n,r]),_t(p,t)&&_t(h,n)&&_t(d,r)||((e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:Ir,lastRenderedState:c}).dispatch=s=Kr.bind(null,wr,e),o.queue=e,o.baseQueue=null,c=Mr(l,n,t),o.memoizedState=o.baseState=c),c}function Dr(e,n,t){return Fr(zr(),e,n,t)}function Ar(e){var n=Cr();return"function"==typeof e&&(e=e()),n.memoizedState=n.baseState=e,e=(e=n.queue={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:Ir,lastRenderedState:e}).dispatch=Kr.bind(null,wr,e),[n.memoizedState,e]}function Hr(e,n,t,r){return e={tag:e,create:n,destroy:t,deps:r,next:null},null===(n=wr.updateQueue)?(n={lastEffect:null},wr.updateQueue=n,n.lastEffect=e.next=e):null===(t=n.lastEffect)?n.lastEffect=e.next=e:(r=t.next,t.next=e,e.next=r,n.lastEffect=e),e}function Qr(){return zr().memoizedState}function jr(e,n,t,r){var l=Cr();wr.flags|=e,l.memoizedState=Hr(1|n,t,void 0,void 0===r?null:r)}function Br(e,n,t,r){var l=zr();r=void 0===r?null:r;var a=void 0;if(null!==xr){var i=xr.memoizedState;if(a=i.destroy,null!==r&&Er(r,i.deps))return void(l.memoizedState=Hr(n,t,a,r))}wr.flags|=e,l.memoizedState=Hr(1|n,t,a,r)}function Wr(e,n){return jr(1049600,4,e,n)}function Or(e,n){return Br(1024,4,e,n)}function Vr(e,n){return Br(4,2,e,n)}function Yr(e,n){return"function"==typeof n?(e=e(),n(e),function(){n(null)}):null!==n&&void 0!==n?(e=e(),n.current=e,function(){n.current=null}):void 0}function qr(e,n,t){return t=null!==t&&void 0!==t?t.concat([e]):null,Br(4,2,Yr.bind(null,n,e),t)}function Xr(){}function $r(e,n){var t=zr();n=void 0===n?null:n;var r=t.memoizedState;return null!==r&&null!==n&&Er(n,r[1])?r[0]:(t.memoizedState=[e,n],e)}function Gr(e,n){var t=zr();n=void 0===n?null:n;var r=t.memoizedState;return null!==r&&null!==n&&Er(n,r[1])?r[0]:(e=e(),t.memoizedState=[e,n],e)}function Jr(e,n){var t=En;En=0!==t&&4>t?t:4,e(!0);var r=Sr.transition;Sr.transition=1;try{e(!1),n()}finally{En=t,Sr.transition=r}}function Kr(e,n,t){var r=Ra(),l=Ta(e),a={lane:l,action:t,eagerReducer:null,eagerState:null,next:null},i=e.alternate;if(e===wr||null!==i&&i===wr)Rr=_r=!0,null===(l=n.pending)?a.next=a:(a.next=l.next,l.next=a),n.pending=a;else{if(null!==la&&0!=(1&e.mode)&&0==(8&ra)){var u=n.interleaved;null===u?(a.next=a,null===At?At=[n]:At.push(n)):(a.next=u.next,u.next=a),n.interleaved=a}else null===(u=n.pending)?a.next=a:(a.next=u.next,u.next=a),n.pending=a;if(0===e.lanes&&(null===i||0===i.lanes)&&null!==(i=n.lastRenderedReducer))try{var o=n.lastRenderedState,s=i(o,t);if(a.eagerReducer=i,a.eagerState=s,_t(s,o))return}catch(e){}a=Ea(e,l,r),0!=(4194240&l)&&null!==a&&(e=n.lanes,l|=e&=a.pendingLanes,n.lanes=l,Pn(a,l))}}var Zr={readContext:Dt,useCallback:Tr,useContext:Tr,useEffect:Tr,useImperativeHandle:Tr,useLayoutEffect:Tr,useMemo:Tr,useReducer:Tr,useRef:Tr,useState:Tr,useDebugValue:Tr,useDeferredValue:Tr,useTransition:Tr,useMutableSource:Tr,useOpaqueIdentifier:Tr,unstable_isNewReconciler:!1},el={readContext:Dt,useCallback:function(e,n){return Cr().memoizedState=[e,void 0===n?null:n],e},useContext:Dt,useEffect:Wr,useImperativeHandle:function(e,n,t){return t=null!==t&&void 0!==t?t.concat([e]):null,jr(4,2,Yr.bind(null,n,e),t)},useLayoutEffect:function(e,n){return jr(4,2,e,n)},useMemo:function(e,n){var t=Cr();return n=void 0===n?null:n,e=e(),t.memoizedState=[e,n],e},useReducer:function(e,n,t){var r=Cr();return n=void 0!==t?t(n):n,r.memoizedState=r.baseState=n,e=(e=r.queue={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:n}).dispatch=Kr.bind(null,wr,e),[r.memoizedState,e]},useRef:function(e){return e={current:e},Cr().memoizedState=e},useState:Ar,useDebugValue:Xr,useDeferredValue:function(e){var n=Ar(e),t=n[0],r=n[1];return Wr(function(){var n=Sr.transition;Sr.transition=1;try{r(e)}finally{Sr.transition=n}},[e]),t},useTransition:function(){var e=Ar(!1),n=e[0];return e=Jr.bind(null,e[1]),Cr().memoizedState=e,[n,e]},useMutableSource:function(e,n,t){var r=Cr();return r.memoizedState={refs:{getSnapshot:n,setSnapshot:null},source:e,subscribe:t},Fr(r,e,n,t)},useOpaqueIdentifier:function(){throw Error("Not yet implemented")},unstable_isNewReconciler:!1},nl={readContext:Dt,useCallback:$r,useContext:Dt,useEffect:Or,useImperativeHandle:qr,useLayoutEffect:Vr,useMemo:Gr,useReducer:Lr,useRef:Qr,useState:function(){return Lr(Ir)},useDebugValue:Xr,useDeferredValue:function(e){var n=Lr(Ir),t=n[0],r=n[1];return Or(function(){var n=Sr.transition;Sr.transition=1;try{r(e)}finally{Sr.transition=n}},[e]),t},useTransition:function(){return[Lr(Ir)[0],zr().memoizedState]},useMutableSource:Dr,useOpaqueIdentifier:function(){return Lr(Ir)[0]},unstable_isNewReconciler:!1},tl={readContext:Dt,useCallback:$r,useContext:Dt,useEffect:Or,useImperativeHandle:qr,useLayoutEffect:Vr,useMemo:Gr,useReducer:Ur,useRef:Qr,useState:function(){return Ur(Ir)},useDebugValue:Xr,useDeferredValue:function(e){var n=Ur(Ir),t=n[0],r=n[1];return Or(function(){var n=Sr.transition;Sr.transition=1;try{r(e)}finally{Sr.transition=n}},[e]),t},useTransition:function(){return[Ur(Ir)[0],zr().memoizedState]},useMutableSource:Dr,useOpaqueIdentifier:function(){return Ur(Ir)[0]},unstable_isNewReconciler:!1};function rl(e,n){try{var t="",r=n;do{t+=Tt(r),r=r.return}while(r);var l=t}catch(e){l="\nError generating stack: "+e.message+"\n"+e.stack}return{value:e,source:n,stack:l}}if("function"!=typeof n(i[3]).ReactFiberErrorDialog.showErrorDialog)throw Error("Expected ReactFiberErrorDialog.showErrorDialog to be a function.");function ll(e,t){try{!1!==n(i[3]).ReactFiberErrorDialog.showErrorDialog({componentStack:null!==t.stack?t.stack:"",error:t.value,errorBoundary:null!==e&&1===e.tag?e.stateNode:null})&&console.error(t.value)}catch(e){setTimeout(function(){throw e})}}var al="function"==typeof WeakMap?WeakMap:Map;function il(e,n,t){(t=Bt(-1,t)).tag=3,t.payload={element:null};var r=n.value;return t.callback=function(){ma||(ma=!0,va=r),ll(e,n)},t}function ul(e,n,t){(t=Bt(-1,t)).tag=3;var r=e.type.getDerivedStateFromError;if("function"==typeof r){var l=n.value;t.payload=function(){return ll(e,n),r(l)}}var a=e.stateNode;return null!==a&&"function"==typeof a.componentDidCatch&&(t.callback=function(){"function"!=typeof r&&(null===ba?ba=new Set([this]):ba.add(this),ll(e,n));var t=n.stack;this.componentDidCatch(n.value,{componentStack:null!==t?t:""})}),t}var ol=we.ReactCurrentOwner,sl=!1;function cl(e,n,t,r){n.child=null===e?ar(n,null,t,r):lr(n,e.child,t,r)}function dl(e,n,t,r,l){t=t.render;var a=n.ref;return Ft(n,l),r=Nr(e,n,t,r,a,l),null===e||sl?(n.flags|=1,cl(e,n,r,l),n.child):(n.updateQueue=e.updateQueue,n.flags&=-1029,e.lanes&=~l,Ll(e,n,l))}function fl(e,n,t,r,l,a){if(null===e){var i=t.type;return"function"!=typeof i||Ka(i)||void 0!==i.defaultProps||null!==t.compare||void 0!==t.defaultProps?((e=ni(t.type,null,r,n,n.mode,a)).ref=n.ref,e.return=n,n.child=e):(n.tag=15,n.type=i,pl(e,n,i,r,l,a))}return i=e.child,0==(l&a)&&(l=i.memoizedProps,(t=null!==(t=t.compare)?t:Rt)(l,r)&&e.ref===n.ref)?Ll(e,n,a):(n.flags|=1,(e=ei(i,r)).ref=n.ref,e.return=n,n.child=e)}function pl(e,n,t,r,l,a){if(null!==e&&Rt(e.memoizedProps,r)&&e.ref===n.ref){if(sl=!1,0==(a&l))return n.lanes=e.lanes,Ll(e,n,a);0!=(32768&e.flags)&&(sl=!0)}return ml(e,n,t,r,a)}function hl(e,n,t){var r=n.pendingProps,l=r.children,a=null!==e?e.memoizedState:null;if("hidden"===r.mode||"unstable-defer-without-hiding"===r.mode)if(0==(1&n.mode))n.memoizedState={baseLanes:0,cachePool:null},ot(oa,ua),ua|=t;else{if(0==(1073741824&t))return e=null!==a?a.baseLanes|t:t,n.lanes=n.childLanes=1073741824,n.memoizedState={baseLanes:e,cachePool:null},n.updateQueue=null,ot(oa,ua),ua|=e,null;n.memoizedState={baseLanes:0,cachePool:null},r=null!==a?a.baseLanes:t,ot(oa,ua),ua|=r}else null!==a?(r=a.baseLanes|t,n.memoizedState=null):r=t,ot(oa,ua),ua|=r;return cl(e,n,l,t),n.child}function gl(e,n){var t=n.ref;(null===e&&null!==t||null!==e&&e.ref!==t)&&(n.flags|=256)}function ml(e,n,t,r,l){var a=ht(t)?ft:ct.current;return a=pt(n,a),Ft(n,l),t=Nr(e,n,t,r,a,l),null===e||sl?(n.flags|=1,cl(e,n,t,l),n.child):(n.updateQueue=e.updateQueue,n.flags&=-1029,e.lanes&=~l,Ll(e,n,l))}function vl(e,n,t,r,l){if(ht(t)){var a=!0;bt(n)}else a=!1;if(Ft(n,l),null===n.stateNode)null!==e&&(e.alternate=null,n.alternate=null,n.flags|=2),Kt(n,t,r),er(n,t,r,l),r=!0;else if(null===e){var i=n.stateNode,u=n.memoizedProps;i.props=u;var o=i.context,s=t.contextType;"object"==typeof s&&null!==s?s=Dt(s):s=pt(n,s=ht(t)?ft:ct.current);var c=t.getDerivedStateFromProps,d="function"==typeof c||"function"==typeof i.getSnapshotBeforeUpdate;d||"function"!=typeof i.UNSAFE_componentWillReceiveProps&&"function"!=typeof i.componentWillReceiveProps||(u!==r||o!==s)&&Zt(n,i,r,s),Ht=!1;var f=n.memoizedState;i.state=f,Yt(n,r,i,l),o=n.memoizedState,u!==r||f!==o||dt.current||Ht?("function"==typeof c&&($t(n,t,c,r),o=n.memoizedState),(u=Ht||Jt(n,t,u,r,f,o,s))?(d||"function"!=typeof i.UNSAFE_componentWillMount&&"function"!=typeof i.componentWillMount||("function"==typeof i.componentWillMount&&i.componentWillMount(),"function"==typeof i.UNSAFE_componentWillMount&&i.UNSAFE_componentWillMount()),"function"==typeof i.componentDidMount&&(n.flags|=4)):("function"==typeof i.componentDidMount&&(n.flags|=4),n.memoizedProps=r,n.memoizedState=o),i.props=r,i.state=o,i.context=s,r=u):("function"==typeof i.componentDidMount&&(n.flags|=4),r=!1)}else{i=n.stateNode,jt(e,n),u=n.memoizedProps,s=n.type===n.elementType?u:Et(n.type,u),i.props=s,d=n.pendingProps,f=i.context,"object"==typeof(o=t.contextType)&&null!==o?o=Dt(o):o=pt(n,o=ht(t)?ft:ct.current);var p=t.getDerivedStateFromProps;(c="function"==typeof p||"function"==typeof i.getSnapshotBeforeUpdate)||"function"!=typeof i.UNSAFE_componentWillReceiveProps&&"function"!=typeof i.componentWillReceiveProps||(u!==d||f!==o)&&Zt(n,i,r,o),Ht=!1,f=n.memoizedState,i.state=f,Yt(n,r,i,l);var h=n.memoizedState;u!==d||f!==h||dt.current||Ht?("function"==typeof p&&($t(n,t,p,r),h=n.memoizedState),(s=Ht||Jt(n,t,s,r,f,h,o)||!1)?(c||"function"!=typeof i.UNSAFE_componentWillUpdate&&"function"!=typeof i.componentWillUpdate||("function"==typeof i.componentWillUpdate&&i.componentWillUpdate(r,h,o),"function"==typeof i.UNSAFE_componentWillUpdate&&i.UNSAFE_componentWillUpdate(r,h,o)),"function"==typeof i.componentDidUpdate&&(n.flags|=4),"function"==typeof i.getSnapshotBeforeUpdate&&(n.flags|=512)):("function"!=typeof i.componentDidUpdate||u===e.memoizedProps&&f===e.memoizedState||(n.flags|=4),"function"!=typeof i.getSnapshotBeforeUpdate||u===e.memoizedProps&&f===e.memoizedState||(n.flags|=512),n.memoizedProps=r,n.memoizedState=h),i.props=r,i.state=h,i.context=o,r=s):("function"!=typeof i.componentDidUpdate||u===e.memoizedProps&&f===e.memoizedState||(n.flags|=4),"function"!=typeof i.getSnapshotBeforeUpdate||u===e.memoizedProps&&f===e.memoizedState||(n.flags|=512),r=!1)}return bl(e,n,t,r,a,l)}function bl(e,n,t,r,l,a){gl(e,n);var i=0!=(128&n.flags);if(!r&&!i)return l&&yt(n,t,!1),Ll(e,n,a);r=n.stateNode,ol.current=n;var u=i&&"function"!=typeof t.getDerivedStateFromError?null:r.render();return n.flags|=1,null!==e&&i?(n.child=lr(n,e.child,null,a),n.child=lr(n,null,u,a)):cl(e,n,u,a),n.memoizedState=r.state,l&&yt(n,t,!0),n.child}function yl(e){var n=e.stateNode;n.pendingContext?mt(0,n.pendingContext,n.pendingContext!==n.context):n.context&&mt(0,n.context,!1),dr(e,n.containerInfo)}var Sl,kl,wl,xl,Pl={dehydrated:null,retryLane:0};function _l(e){return{baseLanes:e,cachePool:null}}function Rl(e,n,t){var r,l=n.pendingProps,a=gr.current,i=!1;return(r=0!=(128&n.flags))||(r=(null===e||null!==e.memoizedState)&&0!=(2&a)),r?(i=!0,n.flags&=-129):null!==e&&null===e.memoizedState||void 0===l.fallback||!0===l.unstable_avoidThisFallback||(a|=1),ot(gr,1&a),null===e?(e=l.children,a=l.fallback,i?(e=Tl(n,e,a,t),n.child.memoizedState=_l(t),n.memoizedState=Pl,e):"number"==typeof l.unstable_expectedLoadTime?(e=Tl(n,e,a,t),n.child.memoizedState=_l(t),n.memoizedState=Pl,n.lanes=4194304,e):((t=ri({mode:"visible",children:e},n.mode,t,null)).return=n,n.child=t)):(e.memoizedState,i?(l=Nl(e,n,l.children,l.fallback,t),i=n.child,a=e.child.memoizedState,i.memoizedState=null===a?_l(t):{baseLanes:a.baseLanes|t,cachePool:null},i.childLanes=e.childLanes&~t,n.memoizedState=Pl,l):(t=El(e,n,l.children,t),n.memoizedState=null,t))}function Tl(e,n,t,r){var l=e.mode,a=e.child;return n={mode:"hidden",children:n},0==(1&l)&&null!==a?(a.childLanes=0,a.pendingProps=n):a=ri(n,l,0,null),t=ti(t,l,r,null),a.return=e,t.return=e,a.sibling=t,e.child=a,t}function El(e,n,t,r){var l=e.child;return e=l.sibling,t=ei(l,{mode:"visible",children:t}),0==(1&n.mode)&&(t.lanes=r),t.return=n,t.sibling=null,null!==e&&(null===(r=n.deletions)?(n.deletions=[e],n.flags|=16):r.push(e)),n.child=t}function Nl(e,n,t,r,l){var a=n.mode,i=(e=e.child).sibling,u={mode:"hidden",children:t};return 0==(1&a)&&n.child!==e?((t=n.child).childLanes=0,t.pendingProps=u,n.deletions=null):(t=ei(e,u)).subtreeFlags=1835008&e.subtreeFlags,null!==i?r=ei(i,r):(r=ti(r,a,l,null)).flags|=2,r.return=n,t.return=n,t.sibling=r,n.child=t,r}function Cl(e,n){e.lanes|=n;var t=e.alternate;null!==t&&(t.lanes|=n),Mt(e.return,n)}function zl(e,n,t,r,l){var a=e.memoizedState;null===a?e.memoizedState={isBackwards:n,rendering:null,renderingStartTime:0,last:r,tail:t,tailMode:l}:(a.isBackwards=n,a.rendering=null,a.renderingStartTime=0,a.last=r,a.tail=t,a.tailMode=l)}function Il(e,n,t){var r=n.pendingProps,l=r.revealOrder,a=r.tail;if(cl(e,n,r.children,t),0!=(2&(r=gr.current)))r=1&r|2,n.flags|=128;else{if(null!==e&&0!=(128&e.flags))e:for(e=n.child;null!==e;){if(13===e.tag)null!==e.memoizedState&&Cl(e,t);else if(19===e.tag)Cl(e,t);else if(null!==e.child){e.child.return=e,e=e.child;continue}if(e===n)break e;for(;null===e.sibling;){if(null===e.return||e.return===n)break e;e=e.return}e.sibling.return=e.return,e=e.sibling}r&=1}if(ot(gr,r),0==(1&n.mode))n.memoizedState=null;else switch(l){case"forwards":for(t=n.child,l=null;null!==t;)null!==(e=t.alternate)&&null===mr(e)&&(l=t),t=t.sibling;null===(t=l)?(l=n.child,n.child=null):(l=t.sibling,t.sibling=null),zl(n,!1,l,t,a);break;case"backwards":for(t=null,l=n.child,n.child=null;null!==l;){if(null!==(e=l.alternate)&&null===mr(e)){n.child=l;break}e=l.sibling,l.sibling=t,t=l,l=e}zl(n,!0,t,null,a);break;case"together":zl(n,!1,null,null,void 0);break;default:n.memoizedState=null}return n.child}function Ll(e,n,t){if(null!==e&&(n.dependencies=e.dependencies),da|=n.lanes,0==(t&n.childLanes))return null;if(null!==e&&n.child!==e.child)throw Error("Resuming work not yet implemented.");if(null!==n.child){for(t=ei(e=n.child,e.pendingProps),n.child=t,t.return=n;null!==e.sibling;)e=e.sibling,(t=t.sibling=ei(e,e.pendingProps)).return=n;t.sibling=null}return n.child}function Ul(e,n){if(null!==e&&e.child===n.child)return!0;if(0!=(16&n.flags))return!1;for(e=n.child;null!==e;){if(0!=(6454&e.flags)||0!=(6454&e.subtreeFlags))return!1;e=e.sibling}return!0}function Ml(e,n,t,r){for(var l=n.child;null!==l;){if(5===l.tag){var a=l.stateNode;t&&r&&(a=et(a)),Qn(e,a.node)}else if(6===l.tag){if(a=l.stateNode,t&&r)throw Error("Not yet implemented.");Qn(e,a.node)}else if(4!==l.tag){if(13===l.tag&&0!=(4&l.flags)&&(a=null!==l.memoizedState)){var i=l.child;if(null!==i&&(null!==i.child&&(i.child.return=i,Ml(e,i,!0,a)),null!==(a=i.sibling))){a.return=l,l=a;continue}}if(null!==l.child){l.child.return=l,l=l.child;continue}}if(l===n)break;for(;null===l.sibling;){if(null===l.return||l.return===n)return;l=l.return}l.sibling.return=l.return,l=l.sibling}}function Fl(e,n){switch(e.tailMode){case"hidden":n=e.tail;for(var t=null;null!==n;)null!==n.alternate&&(t=n),n=n.sibling;null===t?e.tail=null:t.sibling=null;break;case"collapsed":t=e.tail;for(var r=null;null!==t;)null!==t.alternate&&(r=t),t=t.sibling;null===r?n||null===e.tail?e.tail=null:e.tail.sibling=null:r.sibling=null}}function Dl(e){var n=null!==e.alternate&&e.alternate.child===e.child,t=0,r=0;if(n)for(var l=e.child;null!==l;)t|=l.lanes|l.childLanes,r|=1835008&l.subtreeFlags,r|=1835008&l.flags,l.return=e,l=l.sibling;else for(l=e.child;null!==l;)t|=l.lanes|l.childLanes,r|=l.subtreeFlags,r|=l.flags,l.return=e,l=l.sibling;return e.subtreeFlags|=r,e.childLanes=t,n}function Al(e,t,r){var l=t.pendingProps;switch(t.tag){case 2:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return Dl(t),null;case 1:return ht(t.type)&>(),Dl(t),null;case 3:return l=t.stateNode,fr(),ut(dt),ut(ct),br(),l.pendingContext&&(l.context=l.pendingContext,l.pendingContext=null),null!==e&&null!==e.child||l.hydrate||(t.flags|=512),kl(e,t),Dl(t),null;case 5:hr(t),r=cr(sr.current);var a=t.type;if(null!==e&&null!=t.stateNode)wl(e,t,a,l,r),e.ref!==t.ref&&(t.flags|=256);else{if(!l){if(null===t.stateNode)throw Error("We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue.");return Dl(t),null}cr(ur.current),e=$n,$n+=2,a=Xn(a);var u=an(null,Ge,l,a.validAttributes);r=Ln(e,a.uiViewClassName,r,u,t),e=new Gn(e,a,l,t),Sl(e={node:r,canonical:e},t,!1,!1),t.stateNode=e,null!==t.ref&&(t.flags|=256)}return Dl(t),null;case 6:if(e&&null!=t.stateNode)xl(e,t,e.memoizedProps,l);else{if("string"!=typeof l&&null===t.stateNode)throw Error("We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue.");e=cr(sr.current),r=cr(ur.current),t.stateNode=Jn(l,e,r,t)}return Dl(t),null;case 13:return ut(gr),l=t.memoizedState,0!=(128&t.flags)?(t.lanes=r,t):(l=null!==l,r=!1,null!==e&&(r=null!==e.memoizedState),l&&!r&&0!=(1&t.mode)&&(null===e&&!0!==t.memoizedProps.unstable_avoidThisFallback||0!=(1&gr.current)?0===sa&&(sa=3):(0!==sa&&3!==sa||(sa=4),null===la||0==(268435455&da)&&0==(268435455&fa)||Ia(la,ia))),l&&(t.flags|=4),Dl(t),null);case 4:return fr(),kl(e,t),Dl(t),null;case 10:return Ut(t.type._context),Dl(t),null;case 17:return ht(t.type)&>(),Dl(t),null;case 19:if(ut(gr),null===(a=t.memoizedState))return Dl(t),null;if(l=0!=(128&t.flags),null===(u=a.rendering))if(l)Fl(a,!1);else{if(0!==sa||null!==e&&0!=(128&e.flags))for(e=t.child;null!==e;){if(null!==(u=mr(e))){for(t.flags|=128,Fl(a,!1),null!==(e=u.updateQueue)&&(t.updateQueue=e,t.flags|=4),t.subtreeFlags=0,e=r,l=t.child;null!==l;)a=e,(r=l).flags&=1835010,null===(u=r.alternate)?(r.childLanes=0,r.lanes=a,r.child=null,r.subtreeFlags=0,r.memoizedProps=null,r.memoizedState=null,r.updateQueue=null,r.dependencies=null,r.stateNode=null):(r.childLanes=u.childLanes,r.lanes=u.lanes,r.child=u.child,r.subtreeFlags=0,r.deletions=null,r.memoizedProps=u.memoizedProps,r.memoizedState=u.memoizedState,r.updateQueue=u.updateQueue,r.type=u.type,a=u.dependencies,r.dependencies=null===a?null:{lanes:a.lanes,firstContext:a.firstContext}),l=l.sibling;return ot(gr,1&gr.current|2),t.child}e=e.sibling}null!==a.tail&&n(i[4]).unstable_now()>ga&&(t.flags|=128,l=!0,Fl(a,!1),t.lanes=4194304)}else{if(!l)if(null!==(e=mr(u))){if(t.flags|=128,l=!0,null!==(e=e.updateQueue)&&(t.updateQueue=e,t.flags|=4),Fl(a,!0),null===a.tail&&"hidden"===a.tailMode&&!u.alternate)return Dl(t),null}else 2*n(i[4]).unstable_now()-a.renderingStartTime>ga&&1073741824!==r&&(t.flags|=128,l=!0,Fl(a,!1),t.lanes=4194304);a.isBackwards?(u.sibling=t.child,t.child=u):(null!==(e=a.last)?e.sibling=u:t.child=u,a.last=u)}return null!==a.tail?(t=a.tail,a.rendering=t,a.tail=t.sibling,a.renderingStartTime=n(i[4]).unstable_now(),t.sibling=null,e=gr.current,ot(gr,l?1&e|2:1&e),t):(Dl(t),null);case 22:case 23:return Ua(),r=null!==t.memoizedState,null!==e&&null!==e.memoizedState!==r&&"unstable-defer-without-hiding"!==l.mode&&(t.flags|=4),r&&0==(1073741824&ua)&&0!=(1&t.mode)||Dl(t),null}throw Error("Unknown unit of work tag ("+t.tag+"). This error is likely caused by a bug in React. Please file an issue.")}function Hl(e){switch(e.tag){case 1:ht(e.type)&>();var n=e.flags;return 16384&n?(e.flags=-16385&n|128,e):null;case 3:if(fr(),ut(dt),ut(ct),br(),0!=(128&(n=e.flags)))throw Error("The root failed to unmount after an error. This is likely a bug in React. Please file an issue.");return e.flags=-16385&n|128,e;case 5:return hr(e),null;case 13:return ut(gr),16384&(n=e.flags)?(e.flags=-16385&n|128,e):null;case 19:return ut(gr),null;case 4:return fr(),null;case 10:return Ut(e.type._context),null;case 22:case 23:return Ua(),null;case 24:default:return null}}Sl=function(e,n,t,r){for(var l=n.child;null!==l;){if(5===l.tag){var a=l.stateNode;t&&r&&(a=et(a)),Hn(e.node,a.node)}else if(6===l.tag){if(a=l.stateNode,t&&r)throw Error("Not yet implemented.");Hn(e.node,a.node)}else if(4!==l.tag){if(13===l.tag&&0!=(4&l.flags)&&(a=null!==l.memoizedState)){var i=l.child;if(null!==i&&(null!==i.child&&(i.child.return=i,Sl(e,i,!0,a)),null!==(a=i.sibling))){a.return=l,l=a;continue}}if(null!==l.child){l.child.return=l,l=l.child;continue}}if(l===n)break;for(;null===l.sibling;){if(null===l.return||l.return===n)return;l=l.return}l.sibling.return=l.return,l=l.sibling}},kl=function(e,n){var t=n.stateNode;if(!Ul(e,n)){e=t.containerInfo;var r=An(e);Ml(r,n,!1,!1),t.pendingChildren=r,n.flags|=4,jn(e,r)}},wl=function(e,n,t,r){t=e.stateNode;var l=e.memoizedProps;if((e=Ul(e,n))&&l===r)n.stateNode=t;else{var a=n.stateNode;cr(ur.current);var i=null;l!==r&&(l=an(null,l,r,a.canonical.viewConfig.validAttributes),a.canonical.currentProps=r,i=l),e&&null===i?n.stateNode=t:(r=i,l=t.node,t={node:e?null!==r?Dn(l,r):Un(l):null!==r?Fn(l,r):Mn(l),canonical:t.canonical},n.stateNode=t,e?n.flags|=4:Sl(t,n,!1,!1))}},xl=function(e,n,t,r){t!==r?(e=cr(sr.current),t=cr(ur.current),n.stateNode=Jn(r,e,t,n),n.flags|=4):n.stateNode=e.stateNode};var Ql="function"==typeof WeakSet?WeakSet:Set,jl=null;function Bl(e,n){var t=e.ref;if(null!==t)if("function"==typeof t)try{t(null)}catch(t){qa(e,n,t)}else t.current=null}var Wl=!1;function Ol(e,n){for(jl=n;null!==jl;)if(n=(e=jl).child,0!=(516&e.subtreeFlags)&&null!==n)n.return=e,jl=n;else for(;null!==jl;){e=jl;try{var t=e.alternate;if(0!=(512&e.flags))switch(e.tag){case 0:case 11:case 15:break;case 1:if(null!==t){var r=t.memoizedProps,l=t.memoizedState,a=e.stateNode,i=a.getSnapshotBeforeUpdate(e.elementType===e.type?r:Et(e.type,r),l);a.__reactInternalSnapshotBeforeUpdate=i}break;case 3:break;case 5:case 6:case 4:case 17:break;default:throw Error("This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue.")}}catch(n){qa(e,e.return,n)}if(null!==(n=e.sibling)){n.return=e.return,jl=n;break}jl=e.return}return t=Wl,Wl=!1,t}function Vl(e,n,t){var r=n.updateQueue;if(null!==(r=null!==r?r.lastEffect:null)){var l=r=r.next;do{if((l.tag&e)===e){var a=l.destroy;if(l.destroy=void 0,void 0!==a){var i=n,u=t;try{a()}catch(e){qa(i,u,e)}}}l=l.next}while(l!==r)}}function Yl(e,n){if(null!==(n=null!==(n=n.updateQueue)?n.lastEffect:null)){var t=n=n.next;do{if((t.tag&e)===e){var r=t.create;t.destroy=r()}t=t.next}while(t!==n)}}function ql(e){var n=e.alternate;null!==n&&(e.alternate=null,ql(n)),e.child=null,e.deletions=null,e.sibling=null,e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function Xl(e,t){switch(t.tag){case 0:case 11:case 14:case 15:return void Vl(3,t,t.return);case 12:return;case 13:return null!==t.memoizedState&&(ha=n(i[4]).unstable_now()),void $l(t);case 19:return void $l(t);case 22:case 23:return}e:{switch(t.tag){case 1:case 5:case 6:break e;case 3:case 4:break e}throw Error("This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue.")}}function $l(e){var n=e.updateQueue;if(null!==n){e.updateQueue=null;var t=e.stateNode;null===t&&(t=e.stateNode=new Ql),n.forEach(function(n){var r=$a.bind(null,e,n);t.has(n)||(t.add(n),n.then(r,r))})}}function Gl(e,n){for(jl=n;null!==jl;){if(null!==(n=(e=jl).deletions))for(var t=0;ta&&(a=o),l&=~u}if(l=a,10<(l=(120>(l=n(i[4]).unstable_now()-l)?120:480>l?480:1080>l?1080:1920>l?1920:3e3>l?3e3:4320>l?4320:1960*Zl(l/1960))-l)){e.timeoutHandle=Kn(Wa.bind(null,e),l);break}Wa(e);break;case 5:Wa(e);break;default:throw Error("Unknown root exit status.")}}return Ca(e,n(i[4]).unstable_now()),e.callbackNode===r?za.bind(null,e):null}function Ia(e,n){for(n&=~pa,n&=~fa,e.suspendedLanes|=n,e.pingedLanes&=~n,e=e.expirationTimes;0 component higher in the tree to provide a loading indicator or placeholder to display.")}5!==sa&&(sa=2),o=rl(o,u),p=i;do{switch(p.tag){case 3:a=o,p.flags|=16384,n&=-n,p.lanes|=n,Vt(p,il(p,a,n));break e;case 1:a=o;var w=p.type,x=p.stateNode;if(0==(128&p.flags)&&("function"==typeof w.getDerivedStateFromError||null!==x&&"function"==typeof x.componentDidCatch&&(null===ba||!ba.has(x)))){p.flags|=16384,n&=-n,p.lanes|=n,Vt(p,ul(p,a,n));break e}}p=p.return}while(null!==p)}Ba(t)}catch(e){n=e,aa===t&&null!==t&&(aa=t=t.return);continue}break}}function Da(){var e=ea.current;return ea.current=Zr,null===e?Zr:e}function Aa(e,n){var t=ra;ra|=8;var r=Da();for(la===e&&ia===n||Ma(e,n);;)try{Ha();break}catch(n){Fa(e,n)}if(Lt(),ra=t,ea.current=r,null!==aa)throw Error("Cannot commit an incomplete root. This error is likely caused by a bug in React. Please file an issue.");return la=null,ia=0,sa}function Ha(){for(;null!==aa;)ja(aa)}function Qa(){for(;null!==aa&&!n(i[4]).unstable_shouldYield();)ja(aa)}function ja(e){var n=Kl(e.alternate,e,ua);e.memoizedProps=e.pendingProps,null===n?Ba(e):aa=n,na.current=null}function Ba(e){var n=e;do{var t=n.alternate;if(e=n.return,0==(8192&n.flags)){if(null!==(t=Al(t,n,ua)))return void(aa=t)}else{if(null!==(t=Hl(n)))return t.flags&=8191,void(aa=t);null!==e&&(e.flags|=8192,e.subtreeFlags=0,e.deletions=null)}if(null!==(n=n.sibling))return void(aa=n);aa=n=e}while(null!==n);0===sa&&(sa=5)}function Wa(e){var n=En,t=ta.transition;try{ta.transition=0,En=1,Oa(e,n)}finally{ta.transition=t,En=n}return null}function Oa(e,t){do{Va()}while(null!==Sa);if(0!=(24&ra))throw Error("Should not already be working.");var r=e.finishedWork,l=e.finishedLanes;if(null===r)return null;if(e.finishedWork=null,e.finishedLanes=0,r===e.current)throw Error("Cannot commit the same tree as before. This error is likely caused by a bug in React. Please file an issue.");e.callbackNode=null,e.callbackPriority=0;var a=r.lanes|r.childLanes;if(xn(e,a),e===la&&(aa=la=null,ia=0),0==(1040&r.subtreeFlags)&&0==(1040&r.flags)||ya||(ya=!0,n(i[4]).unstable_scheduleCallback(n(i[4]).unstable_NormalPriority,function(){return Va(),null})),a=0!=(8054&r.flags),0!=(8054&r.subtreeFlags)||a){a=ta.transition,ta.transition=0;var u=En;En=1;var o=ra;ra|=16,na.current=null,Ol(e,r),Gl(e,r),e.current=r,Jl(r),n(i[4]).unstable_requestPaint(),ra=o,En=u,ta.transition=a}else e.current=r;if(ya&&(ya=!1,Sa=e,ka=l),0===(a=e.pendingLanes)&&(ba=null),0!=(1&a)?e===xa?wa++:(wa=0,xa=e):wa=0,hn(r.stateNode),Ca(e,n(i[4]).unstable_now()),ma)throw ma=!1,e=va,va=null,e;return 0!=(4&ra)?null:(0!=(1&ka)&&0!==e.tag&&Va(),xt(),null)}function Va(){if(null!==Sa){var e=Nn(ka),n=ta.transition,t=En;try{if(ta.transition=0,En=16>e?16:e,null===Sa)var r=!1;else{if(e=Sa,Sa=null,ka=0,0!=(24&ra))throw Error("Cannot flush passive effects while already rendering.");var l=ra;for(ra|=16,jl=e.current;null!==jl;){var a=jl,i=a.child;if(0!=(16&jl.flags)){var u=a.deletions;if(null!==u){for(var o=0;on(i[4]).unstable_now()-ha?Ma(e,0):pa|=r),Ca(e,t)}function $a(e,n){var t=e.stateNode;null!==t&&t.delete(n),0===(n=0)&&(0==(1&e.mode)?n=1:(n=mn,0==(130023424&(mn<<=1))&&(mn=4194304))),t=Ra(),null!==(e=Na(e,n))&&(wn(e,n,t),Ca(e,t))}function Ga(e,n,t,r){this.tag=e,this.key=t,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=n,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function Ja(e,n,t,r){return new Ga(e,n,t,r)}function Ka(e){return!(!(e=e.prototype)||!e.isReactComponent)}function Za(e){if("function"==typeof e)return Ka(e)?1:0;if(void 0!==e&&null!==e){if((e=e.$$typeof)===Ce)return 11;if(e===Le)return 14}return 2}function ei(e,n){var t=e.alternate;return null===t?((t=Ja(e.tag,n,e.key,e.mode)).elementType=e.elementType,t.type=e.type,t.stateNode=e.stateNode,t.alternate=e,e.alternate=t):(t.pendingProps=n,t.type=e.type,t.flags=0,t.subtreeFlags=0,t.deletions=null),t.flags=1835008&e.flags,t.childLanes=e.childLanes,t.lanes=e.lanes,t.child=e.child,t.memoizedProps=e.memoizedProps,t.memoizedState=e.memoizedState,t.updateQueue=e.updateQueue,n=e.dependencies,t.dependencies=null===n?null:{lanes:n.lanes,firstContext:n.firstContext},t.sibling=e.sibling,t.index=e.index,t.ref=e.ref,t}function ni(e,n,t,r,l,a){var i=2;if(r=e,"function"==typeof e)Ka(e)&&(i=1);else if("string"==typeof e)i=5;else e:switch(e){case _e:return ti(t.children,l,a,n);case Me:i=8,l|=4;break;case Re:i=8,l|=8;break;case Te:return(e=Ja(12,t,n,2|l)).elementType=Te,e.lanes=a,e;case ze:return(e=Ja(13,t,n,l)).elementType=ze,e.lanes=a,e;case Ie:return(e=Ja(19,t,n,l)).elementType=Ie,e.lanes=a,e;case Fe:return ri(t,l,a,n);case De:return(e=Ja(23,t,n,l)).elementType=De,e.lanes=a,e;default:if("object"==typeof e&&null!==e)switch(e.$$typeof){case Ee:i=10;break e;case Ne:i=9;break e;case Ce:i=11;break e;case Le:i=14;break e;case Ue:i=16,r=null;break e}throw Error("Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: "+(null==e?e:typeof e)+".")}return(n=Ja(i,t,n,l)).elementType=e,n.type=r,n.lanes=a,n}function ti(e,n,t,r){return(e=Ja(7,e,r,n)).lanes=t,e}function ri(e,n,t,r){return(e=Ja(22,e,r,n)).elementType=Fe,e.lanes=t,e}function li(e,n,t){return(e=Ja(6,e,null,n)).lanes=t,e}function ai(e,n,t){return(n=Ja(4,null!==e.children?e.children:[],e.key,n)).lanes=t,n.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},n}function ii(e,n,t){this.tag=n,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.pendingContext=this.context=null,this.hydrate=t,this.callbackNode=null,this.callbackPriority=0,this.eventTimes=kn(0),this.expirationTimes=kn(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=kn(0)}function ui(e,n,t){var r=3=t.length?{done:!0}:{done:!1,value:t[o++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function f(t,n){if(t){if("string"==typeof t)return s(t,n);var u=Object.prototype.toString.call(t).slice(8,-1);return"Object"===u&&t.constructor&&(u=t.constructor.name),"Map"===u||"Set"===u?Array.from(t):"Arguments"===u||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(u)?s(t,n):void 0}}function s(t,n){(null==n||n>t.length)&&(n=t.length);for(var u=0,o=new Array(n);ui&&(f+=u&&o?h.currentPageX:u&&!o?h.currentPageY:!u&&o?h.previousPageX:h.previousPageY,s=1);else for(var v=0;v=i){f+=u&&o?C.currentPageX:u&&!o?C.currentPageY:!u&&o?C.previousPageX:C.previousPageY,s++}}return s>0?f/s:n.noCentroid},currentCentroidXOfTouchesChangedAfter:function(t,i){return n.centroidDimension(t,i,!0,!0)},currentCentroidYOfTouchesChangedAfter:function(t,i){return n.centroidDimension(t,i,!1,!0)},previousCentroidXOfTouchesChangedAfter:function(t,i){return n.centroidDimension(t,i,!0,!1)},previousCentroidYOfTouchesChangedAfter:function(t,i){return n.centroidDimension(t,i,!1,!1)},currentCentroidX:function(t){return n.centroidDimension(t,0,!0,!0)},currentCentroidY:function(t){return n.centroidDimension(t,0,!1,!0)},noCentroid:-1};m.exports=n},781,[]); -__d(function(g,r,i,a,m,e,d){var n=r(d[0])(r(d[1])),s=r(d[0])(r(d[2])),o=r(d[0])(r(d[3])),t=r(d[0])(r(d[4])),E=r(d[0])(r(d[5])),A=r(d[0])(r(d[6])),_=r(d[0])(r(d[7])),u=Object.freeze({GRANTED:'granted',DENIED:'denied',NEVER_ASK_AGAIN:'never_ask_again'}),S=Object.freeze({READ_CALENDAR:'android.permission.READ_CALENDAR',WRITE_CALENDAR:'android.permission.WRITE_CALENDAR',CAMERA:'android.permission.CAMERA',READ_CONTACTS:'android.permission.READ_CONTACTS',WRITE_CONTACTS:'android.permission.WRITE_CONTACTS',GET_ACCOUNTS:'android.permission.GET_ACCOUNTS',ACCESS_FINE_LOCATION:'android.permission.ACCESS_FINE_LOCATION',ACCESS_COARSE_LOCATION:'android.permission.ACCESS_COARSE_LOCATION',ACCESS_BACKGROUND_LOCATION:'android.permission.ACCESS_BACKGROUND_LOCATION',RECORD_AUDIO:'android.permission.RECORD_AUDIO',READ_PHONE_STATE:'android.permission.READ_PHONE_STATE',CALL_PHONE:'android.permission.CALL_PHONE',READ_CALL_LOG:'android.permission.READ_CALL_LOG',WRITE_CALL_LOG:'android.permission.WRITE_CALL_LOG',ADD_VOICEMAIL:'com.android.voicemail.permission.ADD_VOICEMAIL',USE_SIP:'android.permission.USE_SIP',PROCESS_OUTGOING_CALLS:'android.permission.PROCESS_OUTGOING_CALLS',BODY_SENSORS:'android.permission.BODY_SENSORS',SEND_SMS:'android.permission.SEND_SMS',RECEIVE_SMS:'android.permission.RECEIVE_SMS',READ_SMS:'android.permission.READ_SMS',RECEIVE_WAP_PUSH:'android.permission.RECEIVE_WAP_PUSH',RECEIVE_MMS:'android.permission.RECEIVE_MMS',READ_EXTERNAL_STORAGE:'android.permission.READ_EXTERNAL_STORAGE',WRITE_EXTERNAL_STORAGE:'android.permission.WRITE_EXTERNAL_STORAGE',BLUETOOTH_CONNECT:'android.permission.BLUETOOTH_CONNECT',BLUETOOTH_SCAN:'android.permission.BLUETOOTH_SCAN',BLUETOOTH_ADVERTISE:'android.permission.BLUETOOTH_ADVERTISE'}),O=new((function(){function O(){(0,o.default)(this,O),this.PERMISSIONS=S,this.RESULTS=u}return(0,t.default)(O,[{key:"checkPermission",value:function(n){return console.warn('"PermissionsAndroid.checkPermission" is deprecated. Use "PermissionsAndroid.check" instead'),(0,_.default)(A.default,'PermissionsAndroid is not installed correctly.'),A.default.checkPermission(n)}},{key:"check",value:function(n){return(0,_.default)(A.default,'PermissionsAndroid is not installed correctly.'),A.default.checkPermission(n)}},{key:"requestPermission",value:function(s,o){var t;return n.default.async(function(E){for(;;)switch(E.prev=E.next){case 0:console.warn('"PermissionsAndroid.requestPermission" is deprecated. Use "PermissionsAndroid.request" instead'),E.next=4;break;case 4:return E.next=6,n.default.awrap(this.request(s,o));case 6:return t=E.sent,E.abrupt("return",t===this.RESULTS.GRANTED);case 8:case"end":return E.stop()}},null,this,null,Promise)}},{key:"request",value:function(o,t){return n.default.async(function(u){for(;;)switch(u.prev=u.next){case 0:u.next=3;break;case 3:if((0,_.default)(A.default,'PermissionsAndroid is not installed correctly.'),!t){u.next=10;break}return u.next=7,n.default.awrap(A.default.shouldShowRequestPermissionRationale(o));case 7:if(!u.sent||!E.default){u.next=10;break}return u.abrupt("return",new Promise(function(n,_){var u=(0,s.default)({},t);E.default.showAlert(u,function(){return _(new Error('Error showing rationale'))},function(){return n(A.default.requestPermission(o))})}));case 10:return u.abrupt("return",A.default.requestPermission(o));case 11:case"end":return u.stop()}},null,this,null,Promise)}},{key:"requestMultiple",value:function(n){return(0,_.default)(A.default,'PermissionsAndroid is not installed correctly.'),A.default.requestMultiplePermissions(n)}}]),O})());m.exports=O},782,[407,404,436,402,403,520,783,425]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in n)if("default"!==l&&Object.prototype.hasOwnProperty.call(n,l)){var p=c?Object.getOwnPropertyDescriptor(n,l):null;p&&(p.get||p.set)?Object.defineProperty(f,l,p):f[l]=n[l]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).get('PermissionsAndroid');e.default=n},783,[428]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),o=r(d[0])(r(d[2])),n=r(d[0])(r(d[3])),l=r(d[0])(r(d[4])),u=r(d[0])(r(d[5])),c=r(d[0])(r(d[6])),f=new n.default('ios'!==c.default.OS?null:l.default),s=new Map,v=(function(){function n(o){var l=this;(0,t.default)(this,n),this._data={},this._remoteNotificationCompleteCallbackCalled=!1,this._isRemote=o.remote,this._isRemote&&(this._notificationId=o.notificationId),o.remote?Object.keys(o).forEach(function(t){var n=o[t];'aps'===t?(l._alert=n.alert,l._sound=n.sound,l._badgeCount=n.badge,l._category=n.category,l._contentAvailable=n['content-available'],l._threadID=n['thread-id']):l._data[t]=n}):(this._badgeCount=o.applicationIconBadgeNumber,this._sound=o.soundName,this._alert=o.alertBody,this._data=o.userInfo,this._category=o.category)}return(0,o.default)(n,[{key:"finish",value:function(t){this._isRemote&&this._notificationId&&!this._remoteNotificationCompleteCallbackCalled&&(this._remoteNotificationCompleteCallbackCalled=!0,(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.onFinishRemoteNotification(this._notificationId,t))}},{key:"getMessage",value:function(){return this._alert}},{key:"getSound",value:function(){return this._sound}},{key:"getCategory",value:function(){return this._category}},{key:"getAlert",value:function(){return this._alert}},{key:"getContentAvailable",value:function(){return this._contentAvailable}},{key:"getBadgeCount",value:function(){return this._badgeCount}},{key:"getData",value:function(){return this._data}},{key:"getThreadID",value:function(){return this._threadID}}],[{key:"presentLocalNotification",value:function(t){(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.presentLocalNotification(t)}},{key:"scheduleLocalNotification",value:function(t){(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.scheduleLocalNotification(t)}},{key:"cancelAllLocalNotifications",value:function(){(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.cancelAllLocalNotifications()}},{key:"removeAllDeliveredNotifications",value:function(){(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.removeAllDeliveredNotifications()}},{key:"getDeliveredNotifications",value:function(t){(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.getDeliveredNotifications(t)}},{key:"removeDeliveredNotifications",value:function(t){(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.removeDeliveredNotifications(t)}},{key:"setApplicationIconBadgeNumber",value:function(t){(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.setApplicationIconBadgeNumber(t)}},{key:"getApplicationIconBadgeNumber",value:function(t){(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.getApplicationIconBadgeNumber(t)}},{key:"cancelLocalNotifications",value:function(t){(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.cancelLocalNotifications(t)}},{key:"getScheduledLocalNotifications",value:function(t){(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.getScheduledLocalNotifications(t)}},{key:"addEventListener",value:function(t,o){var l;(0,u.default)('notification'===t||'register'===t||'registrationError'===t||'localNotification'===t,'PushNotificationIOS only supports `notification`, `register`, `registrationError`, and `localNotification` events'),'notification'===t?l=f.addListener("remoteNotificationReceived",function(t){o(new n(t))}):'localNotification'===t?l=f.addListener("localNotificationReceived",function(t){o(new n(t))}):'register'===t?l=f.addListener("remoteNotificationsRegistered",function(t){o(t.deviceToken)}):'registrationError'===t&&(l=f.addListener("remoteNotificationRegistrationError",function(t){o(t)})),s.set(t,l)}},{key:"removeEventListener",value:function(t,o){(0,u.default)('notification'===t||'register'===t||'registrationError'===t||'localNotification'===t,'PushNotificationIOS only supports `notification`, `register`, `registrationError`, and `localNotification` events');var n=s.get(t);n&&(n.remove(),s.delete(t))}},{key:"requestPermissions",value:function(t){var o={alert:!0,badge:!0,sound:!0};return t&&(o={alert:!!t.alert,badge:!!t.badge,sound:!!t.sound}),(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.requestPermissions(o)}},{key:"abandonPermissions",value:function(){(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.abandonPermissions()}},{key:"checkPermissions",value:function(t){(0,u.default)('function'==typeof t,'Must provide a valid callback'),(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.checkPermissions(t)}},{key:"getInitialNotification",value:function(){return(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.getInitialNotification().then(function(t){return t&&new n(t)})}},{key:"getAuthorizationStatus",value:function(t){(0,u.default)(l.default,'PushNotificationManager is not available.'),l.default.getAuthorizationStatus(t)}}]),n})();v.FetchResult={NewData:'UIBackgroundFetchResultNewData',NoData:'UIBackgroundFetchResultNoData',ResultFailed:'UIBackgroundFetchResultFailed'},m.exports=v},784,[407,402,403,500,785,425,426]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in n)if("default"!==l&&Object.prototype.hasOwnProperty.call(n,l)){var p=c?Object.getOwnPropertyDescriptor(n,l):null;p&&(p.get||p.set)?Object.defineProperty(f,l,p):f[l]=n[l]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).get('PushNotificationManager');e.default=n},785,[428]); -__d(function(g,r,i,a,m,e,d){'use strict';var n={get:function(n){return console.warn('Settings is not yet supported on Android'),null},set:function(n){console.warn('Settings is not yet supported on Android')},watchKeys:function(n,t){return console.warn('Settings is not yet supported on Android'),-1},clearWatch:function(n){console.warn('Settings is not yet supported on Android')}};m.exports=n},786,[]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),s=r(d[0])(r(d[3])),l=(r(d[0])(r(d[4])),r(d[0])(r(d[5]))),o=(function(){function o(){(0,n.default)(this,o)}return(0,s.default)(o,null,[{key:"share",value:function(n){var s=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};r(d[6])('object'==typeof n&&null!==n,'Content to share must be a valid object'),r(d[6])('string'==typeof n.url||'string'==typeof n.message,'At least one of URL and message is required'),r(d[6])('object'==typeof s&&null!==s,'Options must be a valid object'),r(d[6])(l.default,'ShareModule should be registered on Android.'),r(d[6])(null==n.title||'string'==typeof n.title,'Invalid title: title should be a string.');var o={title:n.title,message:'string'==typeof n.message?n.message:void 0};return l.default.share(o,s.dialogTitle).then(function(n){return(0,t.default)({activityType:null},n)})}}]),o})();o.sharedAction='sharedAction',o.dismissedAction='dismissedAction',m.exports=o},787,[407,436,402,403,741,788,425]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,u=new WeakMap;return(t=function(t){return t?u:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var u=t(o);if(u&&u.has(n))return u.get(n);var f={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var c in n)if("default"!==c&&Object.prototype.hasOwnProperty.call(n,c)){var p=l?Object.getOwnPropertyDescriptor(n,c):null;p&&(p.get||p.set)?Object.defineProperty(f,c,p):f[c]=n[c]}f.default=n,u&&u.set(n,f);return f})(r(d[0])).get('ShareModule');e.default=n},788,[428]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),f=t.default.getConstants(),n={SHORT:f.SHORT,LONG:f.LONG,TOP:f.TOP,BOTTOM:f.BOTTOM,CENTER:f.CENTER,show:function(f,n){t.default.show(f,n)},showWithGravity:function(f,n,o){t.default.showWithGravity(f,n,o)},showWithGravityAndOffset:function(f,n,o,O,s){t.default.showWithGravityAndOffset(f,n,o,O,s)}};m.exports=n},789,[407,790]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,f=new WeakMap;return(t=function(t){return t?f:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var f=t(o);if(f&&f.has(n))return f.get(n);var u={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in n)if("default"!==l&&Object.prototype.hasOwnProperty.call(n,l)){var p=c?Object.getOwnPropertyDescriptor(n,l):null;p&&(p.get||p.set)?Object.defineProperty(u,l,p):u[l]=n[l]}u.default=n,f&&f.set(n,u);return u})(r(d[0])).getEnforcing('ToastAndroid');e.default=n},790,[428]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=function(){var t=(0,n.useMemo)(function(){return{getCurrentValue:function(){return u.default.getColorScheme()},subscribe:function(n){var t=u.default.addChangeListener(n);return function(){t.remove()}}}},[]);return(0,r(d[3]).useSubscription)(t)};var n=r(d[0]),u=r(d[1])(r(d[2]))},791,[534,407,742,792]); -__d(function(g,r,i,a,m,e,d){'use strict';m.exports=r(d[0])},792,[793]); -__d(function(_g,r,i,_a,m,e,_d){'use strict';var u=r(_d[0]);e.useSubscription=function(t){var n=t.getCurrentValue,a=t.subscribe,s=u.useState(function(){return{getCurrentValue:n,subscribe:a,value:n()}});t=s[0];var c=s[1];return s=t.value,t.getCurrentValue===n&&t.subscribe===a||(s=n(),c({getCurrentValue:n,subscribe:a,value:s})),u.useDebugValue(s),u.useEffect(function(){function u(){if(!t){var u=n();c(function(t){return t.getCurrentValue!==n||t.subscribe!==a||t.value===u?t:r(_d[1])({},t,{value:u})})}}var t=!1,s=a(u);return u(),function(){t=!0,s()}},[n,a]),s}},793,[534,536]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.default=function(){var f=(0,u.useState)(function(){return n.default.get('window')}),o=(0,t.default)(f,2),c=o[0],l=o[1];return(0,u.useEffect)(function(){function t(t){var n=t.window;c.width===n.width&&c.height===n.height&&c.scale===n.scale&&c.fontScale===n.fontScale||l(n)}var u=n.default.addEventListener('change',t);return t({window:n.default.get('window')}),function(){u.remove()}},[c]),c};var t=r(d[0])(r(d[1])),n=r(d[0])(r(d[2])),u=r(d[3])},794,[407,430,566,534]); -__d(function(g,r,i,a,m,e,d){'use strict';var A=r(d[0])({BOM:"\ufeff",BULLET:"\u2022",BULLET_SP:"\xa0\u2022\xa0",MIDDOT:"\xb7",MIDDOT_SP:"\xa0\xb7\xa0",MIDDOT_KATAKANA:"\u30fb",MDASH:"\u2014",MDASH_SP:"\xa0\u2014\xa0",NDASH:"\u2013",NDASH_SP:"\xa0\u2013\xa0",NBSP:"\xa0",PIZZA:"\ud83c\udf55",TRIANGLE_LEFT:"\u25c0",TRIANGLE_RIGHT:"\u25b6"});m.exports=A},795,[572]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0])(r(d[1])),n=400;var o={vibrate:function(){var o=arguments.length>0&&void 0!==arguments[0]?arguments[0]:n,f=arguments.length>1&&void 0!==arguments[1]&&arguments[1];if('number'==typeof o)t.default.vibrate(o);else{if(!Array.isArray(o))throw new Error('Vibration pattern should be a number or array');t.default.vibrateByPattern(o,f?0:-1)}},cancel:function(){t.default.cancel()}};m.exports=o},796,[407,797]); -__d(function(g,r,i,a,m,e,d){function t(n){if("function"!=typeof WeakMap)return null;var o=new WeakMap,f=new WeakMap;return(t=function(t){return t?f:o})(n)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n=(function(n,o){if(!o&&n&&n.__esModule)return n;if(null===n||"object"!=typeof n&&"function"!=typeof n)return{default:n};var f=t(o);if(f&&f.has(n))return f.get(n);var u={},c=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in n)if("default"!==l&&Object.prototype.hasOwnProperty.call(n,l)){var p=c?Object.getOwnPropertyDescriptor(n,l):null;p&&(p.get||p.set)?Object.defineProperty(u,l,p):u[l]=n[l]}u.default=n,f&&f.set(n,u);return u})(r(d[0])).getEnforcing('Vibration');e.default=n},797,[428]); -__d(function(g,r,i,a,m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var n;n=(function(n){r(d[3])(o,n);var e,u,c=(e=o,u=t(),function(){var t,n=r(d[0])(e);if(u){var c=r(d[0])(this).constructor;t=Reflect.construct(n,arguments,c)}else t=n.apply(this,arguments);return r(d[1])(this,t)});function o(){return r(d[4])(this,o),c.apply(this,arguments)}return r(d[5])(o,[{key:"render",value:function(){return null}}],[{key:"ignoreWarnings",value:function(t){}},{key:"install",value:function(){}},{key:"uninstall",value:function(){}}]),o})(r(d[2]).Component),m.exports=n},798,[422,419,534,417,402,403]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.DynamicColorIOS=void 0;e.DynamicColorIOS=function(o){throw new Error('DynamicColorIOS is not available on this platform.')}},799,[]); -__d(function(g,r,i,a,m,e,d){'use strict';var n=r(d[0]).shape({x:r(d[0]).number,y:r(d[0]).number});m.exports=n},800,[596]); -__d(function(g,r,_i,_a,_m,_e,d){'use strict';function t(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}var e='function'==typeof Symbol&&'function'==typeof Symbol.for?Symbol.for('nodejs.util.inspect.custom'):null;_e.Buffer=o,_e.SlowBuffer=function(t){+t!=t&&(t=0);return o.alloc(+t)},_e.INSPECT_MAX_BYTES=50;var n=2147483647;function i(t){if(t>n)throw new RangeError('The value "'+t+'" is invalid for option "size"');var e=new Uint8Array(t);return Object.setPrototypeOf(e,o.prototype),e}function o(t,e,n){if('number'==typeof t){if('string'==typeof e)throw new TypeError('The "string" argument must be of type string. Received type number');return h(t)}return f(t,e,n)}function f(t,e,n){if('string'==typeof t)return a(t,e);if(ArrayBuffer.isView(t))return c(t);if(null==t)throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof t);if(nt(t,ArrayBuffer)||t&&nt(t.buffer,ArrayBuffer))return l(t,e,n);if('undefined'!=typeof SharedArrayBuffer&&(nt(t,SharedArrayBuffer)||t&&nt(t.buffer,SharedArrayBuffer)))return l(t,e,n);if('number'==typeof t)throw new TypeError('The "value" argument must not be of type number. Received type number');var i=t.valueOf&&t.valueOf();if(null!=i&&i!==t)return o.from(i,e,n);var f=y(t);if(f)return f;if('undefined'!=typeof Symbol&&null!=Symbol.toPrimitive&&'function'==typeof t[Symbol.toPrimitive])return o.from(t[Symbol.toPrimitive]('string'),e,n);throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof t)}function u(t){if('number'!=typeof t)throw new TypeError('"size" argument must be of type number');if(t<0)throw new RangeError('The value "'+t+'" is invalid for option "size"')}function s(t,e,n){return u(t),t<=0?i(t):void 0!==e?'string'==typeof n?i(t).fill(e,n):i(t).fill(e):i(t)}function h(t){return u(t),i(t<0?0:0|w(t))}function a(t,e){if('string'==typeof e&&''!==e||(e='utf8'),!o.isEncoding(e))throw new TypeError('Unknown encoding: '+e);var n=0|v(t,e),f=i(n),u=f.write(t,e);return u!==n&&(f=f.slice(0,u)),f}function p(t){for(var e=t.length<0?0:0|w(t.length),n=i(e),o=0;o=n)throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+n.toString(16)+' bytes');return 0|t}function v(t,e){if(o.isBuffer(t))return t.length;if(ArrayBuffer.isView(t)||nt(t,ArrayBuffer))return t.byteLength;if('string'!=typeof t)throw new TypeError("The \"string\" argument must be one of type string, Buffer, or ArrayBuffer. Received type "+typeof t);var n=t.length,i=arguments.length>2&&!0===arguments[2];if(!i&&0===n)return 0;for(var f=!1;;)switch(e){case'ascii':case'latin1':case'binary':return n;case'utf8':case'utf-8':return K(t).length;case'ucs2':case'ucs-2':case'utf16le':case'utf-16le':return 2*n;case'hex':return n>>>1;case'base64':return rt(t).length;default:if(f)return i?-1:K(t).length;e=(''+e).toLowerCase(),f=!0}}function b(t,e,n){var i=!1;if((void 0===e||e<0)&&(e=0),e>this.length)return'';if((void 0===n||n>this.length)&&(n=this.length),n<=0)return'';if((n>>>=0)<=(e>>>=0))return'';for(t||(t='utf8');;)switch(t){case'hex':return P(this,e,n);case'utf8':case'utf-8':return L(this,e,n);case'ascii':return S(this,e,n);case'latin1':case'binary':return x(this,e,n);case'base64':return O(this,e,n);case'ucs2':case'ucs-2':case'utf16le':case'utf-16le':return k(this,e,n);default:if(i)throw new TypeError('Unknown encoding: '+t);t=(t+'').toLowerCase(),i=!0}}function B(t,e,n){var i=t[e];t[e]=t[n],t[n]=i}function E(t,e,n,i,f){if(0===t.length)return-1;if('string'==typeof n?(i=n,n=0):n>2147483647?n=2147483647:n<-2147483648&&(n=-2147483648),it(n=+n)&&(n=f?0:t.length-1),n<0&&(n=t.length+n),n>=t.length){if(f)return-1;n=t.length-1}else if(n<0){if(!f)return-1;n=0}if('string'==typeof e&&(e=o.from(e,i)),o.isBuffer(e))return 0===e.length?-1:m(t,e,n,i,f);if('number'==typeof e)return e&=255,'function'==typeof Uint8Array.prototype.indexOf?f?Uint8Array.prototype.indexOf.call(t,e,n):Uint8Array.prototype.lastIndexOf.call(t,e,n):m(t,[e],n,i,f);throw new TypeError('val must be string, number or Buffer')}function m(t,e,n,i,o){var f,u=1,s=t.length,h=e.length;if(void 0!==i&&('ucs2'===(i=String(i).toLowerCase())||'ucs-2'===i||'utf16le'===i||'utf-16le'===i)){if(t.length<2||e.length<2)return-1;u=2,s/=2,h/=2,n/=2}function a(t,e){return 1===u?t[e]:t.readUInt16BE(e*u)}if(o){var p=-1;for(f=n;fs&&(n=s-h),f=n;f>=0;f--){for(var c=!0,l=0;lo&&(i=o):i=o;var f,u=e.length;for(i>u/2&&(i=u/2),f=0;f239?4:f>223?3:f>191?2:1;if(o+s<=n){var h=void 0,a=void 0,p=void 0,c=void 0;switch(s){case 1:f<128&&(u=f);break;case 2:128==(192&(h=t[o+1]))&&(c=(31&f)<<6|63&h)>127&&(u=c);break;case 3:h=t[o+1],a=t[o+2],128==(192&h)&&128==(192&a)&&(c=(15&f)<<12|(63&h)<<6|63&a)>2047&&(c<55296||c>57343)&&(u=c);break;case 4:h=t[o+1],a=t[o+2],p=t[o+3],128==(192&h)&&128==(192&a)&&128==(192&p)&&(c=(15&f)<<18|(63&h)<<12|(63&a)<<6|63&p)>65535&&c<1114112&&(u=c)}}null===u?(u=65533,s=1):u>65535&&(u-=65536,i.push(u>>>10&1023|55296),u=56320|1023&u),i.push(u),o+=s}return _(i)}_e.kMaxLength=n,o.TYPED_ARRAY_SUPPORT=(function(){try{var t=new Uint8Array(1),e={foo:function(){return 42}};return Object.setPrototypeOf(e,Uint8Array.prototype),Object.setPrototypeOf(t,e),42===t.foo()}catch(t){return!1}})(),o.TYPED_ARRAY_SUPPORT||'undefined'==typeof console||'function'!=typeof console.error||console.error("This browser lacks typed array (Uint8Array) support which is required by `buffer` v5.x. Use `buffer` v4.x if you require old browser support."),Object.defineProperty(o.prototype,'parent',{enumerable:!0,get:function(){if(o.isBuffer(this))return this.buffer}}),Object.defineProperty(o.prototype,'offset',{enumerable:!0,get:function(){if(o.isBuffer(this))return this.byteOffset}}),o.poolSize=8192,o.from=function(t,e,n){return f(t,e,n)},Object.setPrototypeOf(o.prototype,Uint8Array.prototype),Object.setPrototypeOf(o,Uint8Array),o.alloc=function(t,e,n){return s(t,e,n)},o.allocUnsafe=function(t){return h(t)},o.allocUnsafeSlow=function(t){return h(t)},o.isBuffer=function(t){return null!=t&&!0===t._isBuffer&&t!==o.prototype},o.compare=function(t,e){if(nt(t,Uint8Array)&&(t=o.from(t,t.offset,t.byteLength)),nt(e,Uint8Array)&&(e=o.from(e,e.offset,e.byteLength)),!o.isBuffer(t)||!o.isBuffer(e))throw new TypeError('The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array');if(t===e)return 0;for(var n=t.length,i=e.length,f=0,u=Math.min(n,i);fi.length?(o.isBuffer(u)||(u=o.from(u)),u.copy(i,f)):Uint8Array.prototype.set.call(i,u,f);else{if(!o.isBuffer(u))throw new TypeError('"list" argument must be an Array of Buffers');u.copy(i,f)}f+=u.length}return i},o.byteLength=v,o.prototype._isBuffer=!0,o.prototype.swap16=function(){var t=this.length;if(t%2!=0)throw new RangeError('Buffer size must be a multiple of 16-bits');for(var e=0;ee&&(t+=' ... '),''},e&&(o.prototype[e]=o.prototype.inspect),o.prototype.compare=function(t,e,n,i,f){if(nt(t,Uint8Array)&&(t=o.from(t,t.offset,t.byteLength)),!o.isBuffer(t))throw new TypeError("The \"target\" argument must be one of type Buffer or Uint8Array. Received type "+typeof t);if(void 0===e&&(e=0),void 0===n&&(n=t?t.length:0),void 0===i&&(i=0),void 0===f&&(f=this.length),e<0||n>t.length||i<0||f>this.length)throw new RangeError('out of range index');if(i>=f&&e>=n)return 0;if(i>=f)return-1;if(e>=n)return 1;if(e>>>=0,n>>>=0,i>>>=0,f>>>=0,this===t)return 0;for(var u=f-i,s=n-e,h=Math.min(u,s),a=this.slice(i,f),p=t.slice(e,n),c=0;c>>=0,isFinite(n)?(n>>>=0,void 0===i&&(i='utf8')):(i=n,n=void 0)}var o=this.length-e;if((void 0===n||n>o)&&(n=o),t.length>0&&(n<0||e<0)||e>this.length)throw new RangeError('Attempt to write outside buffer bounds');i||(i='utf8');for(var f=!1;;)switch(i){case'hex':return I(this,t,e,n);case'utf8':case'utf-8':return U(this,t,e,n);case'ascii':case'latin1':case'binary':return A(this,t,e,n);case'base64':return R(this,t,e,n);case'ucs2':case'ucs-2':case'utf16le':case'utf-16le':return T(this,t,e,n);default:if(f)throw new TypeError('Unknown encoding: '+i);i=(''+i).toLowerCase(),f=!0}},o.prototype.toJSON=function(){return{type:'Buffer',data:Array.prototype.slice.call(this._arr||this,0)}};var M=4096;function _(t){var e=t.length;if(e<=M)return String.fromCharCode.apply(String,t);for(var n='',i=0;ii)&&(n=i);for(var o='',f=e;fn)throw new RangeError('Trying to access beyond buffer length')}function N(t,e,n,i,f,u){if(!o.isBuffer(t))throw new TypeError('"buffer" argument must be a Buffer instance');if(e>f||et.length)throw new RangeError('Index out of range')}function F(t,e,n,i,o){X(e,i,o,t,n,7);var f=Number(e&BigInt(4294967295));t[n++]=f,f>>=8,t[n++]=f,f>>=8,t[n++]=f,f>>=8,t[n++]=f;var u=Number(e>>BigInt(32)&BigInt(4294967295));return t[n++]=u,u>>=8,t[n++]=u,u>>=8,t[n++]=u,u>>=8,t[n++]=u,n}function j(t,e,n,i,o){X(e,i,o,t,n,7);var f=Number(e&BigInt(4294967295));t[n+7]=f,f>>=8,t[n+6]=f,f>>=8,t[n+5]=f,f>>=8,t[n+4]=f;var u=Number(e>>BigInt(32)&BigInt(4294967295));return t[n+3]=u,u>>=8,t[n+2]=u,u>>=8,t[n+1]=u,u>>=8,t[n]=u,n+8}function D(t,e,n,i,o,f){if(n+i>t.length)throw new RangeError('Index out of range');if(n<0)throw new RangeError('Index out of range')}function z(t,e,n,i,o){return e=+e,n>>>=0,o||D(t,0,n,4),r(d[3]).write(t,e,n,i,23,4),n+4}function Y(t,e,n,i,o){return e=+e,n>>>=0,o||D(t,0,n,8),r(d[3]).write(t,e,n,i,52,8),n+8}o.prototype.slice=function(t,e){var n=this.length;t=~~t,e=void 0===e?n:~~e,t<0?(t+=n)<0&&(t=0):t>n&&(t=n),e<0?(e+=n)<0&&(e=0):e>n&&(e=n),e>>=0,e>>>=0,n||C(t,e,this.length);for(var i=this[t],o=1,f=0;++f>>=0,e>>>=0,n||C(t,e,this.length);for(var i=this[t+--e],o=1;e>0&&(o*=256);)i+=this[t+--e]*o;return i},o.prototype.readUint8=o.prototype.readUInt8=function(t,e){return t>>>=0,e||C(t,1,this.length),this[t]},o.prototype.readUint16LE=o.prototype.readUInt16LE=function(t,e){return t>>>=0,e||C(t,2,this.length),this[t]|this[t+1]<<8},o.prototype.readUint16BE=o.prototype.readUInt16BE=function(t,e){return t>>>=0,e||C(t,2,this.length),this[t]<<8|this[t+1]},o.prototype.readUint32LE=o.prototype.readUInt32LE=function(t,e){return t>>>=0,e||C(t,4,this.length),(this[t]|this[t+1]<<8|this[t+2]<<16)+16777216*this[t+3]},o.prototype.readUint32BE=o.prototype.readUInt32BE=function(t,e){return t>>>=0,e||C(t,4,this.length),16777216*this[t]+(this[t+1]<<16|this[t+2]<<8|this[t+3])},o.prototype.readBigUInt64LE=ft(function(t){J(t>>>=0,'offset');var e=this[t],n=this[t+7];void 0!==e&&void 0!==n||Z(t,this.length-8);var i=e+this[++t]*Math.pow(2,8)+this[++t]*Math.pow(2,16)+this[++t]*Math.pow(2,24),o=this[++t]+this[++t]*Math.pow(2,8)+this[++t]*Math.pow(2,16)+n*Math.pow(2,24);return BigInt(i)+(BigInt(o)<>>=0,'offset');var e=this[t],n=this[t+7];void 0!==e&&void 0!==n||Z(t,this.length-8);var i=e*Math.pow(2,24)+this[++t]*Math.pow(2,16)+this[++t]*Math.pow(2,8)+this[++t],o=this[++t]*Math.pow(2,24)+this[++t]*Math.pow(2,16)+this[++t]*Math.pow(2,8)+n;return(BigInt(i)<>>=0,e>>>=0,n||C(t,e,this.length);for(var i=this[t],o=1,f=0;++f=(o*=128)&&(i-=Math.pow(2,8*e)),i},o.prototype.readIntBE=function(t,e,n){t>>>=0,e>>>=0,n||C(t,e,this.length);for(var i=e,o=1,f=this[t+--i];i>0&&(o*=256);)f+=this[t+--i]*o;return f>=(o*=128)&&(f-=Math.pow(2,8*e)),f},o.prototype.readInt8=function(t,e){return t>>>=0,e||C(t,1,this.length),128&this[t]?-1*(255-this[t]+1):this[t]},o.prototype.readInt16LE=function(t,e){t>>>=0,e||C(t,2,this.length);var n=this[t]|this[t+1]<<8;return 32768&n?4294901760|n:n},o.prototype.readInt16BE=function(t,e){t>>>=0,e||C(t,2,this.length);var n=this[t+1]|this[t]<<8;return 32768&n?4294901760|n:n},o.prototype.readInt32LE=function(t,e){return t>>>=0,e||C(t,4,this.length),this[t]|this[t+1]<<8|this[t+2]<<16|this[t+3]<<24},o.prototype.readInt32BE=function(t,e){return t>>>=0,e||C(t,4,this.length),this[t]<<24|this[t+1]<<16|this[t+2]<<8|this[t+3]},o.prototype.readBigInt64LE=ft(function(t){J(t>>>=0,'offset');var e=this[t],n=this[t+7];void 0!==e&&void 0!==n||Z(t,this.length-8);var i=this[t+4]+this[t+5]*Math.pow(2,8)+this[t+6]*Math.pow(2,16)+(n<<24);return(BigInt(i)<>>=0,'offset');var e=this[t],n=this[t+7];void 0!==e&&void 0!==n||Z(t,this.length-8);var i=(e<<24)+this[++t]*Math.pow(2,16)+this[++t]*Math.pow(2,8)+this[++t];return(BigInt(i)<>>=0,e||C(t,4,this.length),r(d[3]).read(this,t,!0,23,4)},o.prototype.readFloatBE=function(t,e){return t>>>=0,e||C(t,4,this.length),r(d[3]).read(this,t,!1,23,4)},o.prototype.readDoubleLE=function(t,e){return t>>>=0,e||C(t,8,this.length),r(d[3]).read(this,t,!0,52,8)},o.prototype.readDoubleBE=function(t,e){return t>>>=0,e||C(t,8,this.length),r(d[3]).read(this,t,!1,52,8)},o.prototype.writeUintLE=o.prototype.writeUIntLE=function(t,e,n,i){(t=+t,e>>>=0,n>>>=0,i)||N(this,t,e,n,Math.pow(2,8*n)-1,0);var o=1,f=0;for(this[e]=255&t;++f>>=0,n>>>=0,i)||N(this,t,e,n,Math.pow(2,8*n)-1,0);var o=n-1,f=1;for(this[e+o]=255&t;--o>=0&&(f*=256);)this[e+o]=t/f&255;return e+n},o.prototype.writeUint8=o.prototype.writeUInt8=function(t,e,n){return t=+t,e>>>=0,n||N(this,t,e,1,255,0),this[e]=255&t,e+1},o.prototype.writeUint16LE=o.prototype.writeUInt16LE=function(t,e,n){return t=+t,e>>>=0,n||N(this,t,e,2,65535,0),this[e]=255&t,this[e+1]=t>>>8,e+2},o.prototype.writeUint16BE=o.prototype.writeUInt16BE=function(t,e,n){return t=+t,e>>>=0,n||N(this,t,e,2,65535,0),this[e]=t>>>8,this[e+1]=255&t,e+2},o.prototype.writeUint32LE=o.prototype.writeUInt32LE=function(t,e,n){return t=+t,e>>>=0,n||N(this,t,e,4,4294967295,0),this[e+3]=t>>>24,this[e+2]=t>>>16,this[e+1]=t>>>8,this[e]=255&t,e+4},o.prototype.writeUint32BE=o.prototype.writeUInt32BE=function(t,e,n){return t=+t,e>>>=0,n||N(this,t,e,4,4294967295,0),this[e]=t>>>24,this[e+1]=t>>>16,this[e+2]=t>>>8,this[e+3]=255&t,e+4},o.prototype.writeBigUInt64LE=ft(function(t){return F(this,t,arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,BigInt(0),BigInt('0xffffffffffffffff'))}),o.prototype.writeBigUInt64BE=ft(function(t){return j(this,t,arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,BigInt(0),BigInt('0xffffffffffffffff'))}),o.prototype.writeIntLE=function(t,e,n,i){if(t=+t,e>>>=0,!i){var o=Math.pow(2,8*n-1);N(this,t,e,n,o-1,-o)}var f=0,u=1,s=0;for(this[e]=255&t;++f>0)-s&255;return e+n},o.prototype.writeIntBE=function(t,e,n,i){if(t=+t,e>>>=0,!i){var o=Math.pow(2,8*n-1);N(this,t,e,n,o-1,-o)}var f=n-1,u=1,s=0;for(this[e+f]=255&t;--f>=0&&(u*=256);)t<0&&0===s&&0!==this[e+f+1]&&(s=1),this[e+f]=(t/u>>0)-s&255;return e+n},o.prototype.writeInt8=function(t,e,n){return t=+t,e>>>=0,n||N(this,t,e,1,127,-128),t<0&&(t=255+t+1),this[e]=255&t,e+1},o.prototype.writeInt16LE=function(t,e,n){return t=+t,e>>>=0,n||N(this,t,e,2,32767,-32768),this[e]=255&t,this[e+1]=t>>>8,e+2},o.prototype.writeInt16BE=function(t,e,n){return t=+t,e>>>=0,n||N(this,t,e,2,32767,-32768),this[e]=t>>>8,this[e+1]=255&t,e+2},o.prototype.writeInt32LE=function(t,e,n){return t=+t,e>>>=0,n||N(this,t,e,4,2147483647,-2147483648),this[e]=255&t,this[e+1]=t>>>8,this[e+2]=t>>>16,this[e+3]=t>>>24,e+4},o.prototype.writeInt32BE=function(t,e,n){return t=+t,e>>>=0,n||N(this,t,e,4,2147483647,-2147483648),t<0&&(t=4294967295+t+1),this[e]=t>>>24,this[e+1]=t>>>16,this[e+2]=t>>>8,this[e+3]=255&t,e+4},o.prototype.writeBigInt64LE=ft(function(t){return F(this,t,arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,-BigInt('0x8000000000000000'),BigInt('0x7fffffffffffffff'))}),o.prototype.writeBigInt64BE=ft(function(t){return j(this,t,arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,-BigInt('0x8000000000000000'),BigInt('0x7fffffffffffffff'))}),o.prototype.writeFloatLE=function(t,e,n){return z(this,t,e,!0,n)},o.prototype.writeFloatBE=function(t,e,n){return z(this,t,e,!1,n)},o.prototype.writeDoubleLE=function(t,e,n){return Y(this,t,e,!0,n)},o.prototype.writeDoubleBE=function(t,e,n){return Y(this,t,e,!1,n)},o.prototype.copy=function(t,e,n,i){if(!o.isBuffer(t))throw new TypeError('argument should be a Buffer');if(n||(n=0),i||0===i||(i=this.length),e>=t.length&&(e=t.length),e||(e=0),i>0&&i=this.length)throw new RangeError('Index out of range');if(i<0)throw new RangeError('sourceEnd out of bounds');i>this.length&&(i=this.length),t.length-e>>=0,n=void 0===n?this.length:n>>>0,t||(t=0),'number'==typeof t)for(u=e;u=i+4;n-=3)e="_"+t.slice(n-3,n)+e;return""+t.slice(0,n)+e}function W(t,e,n){J(e,'offset'),void 0!==t[e]&&void 0!==t[e+n]||Z(e,t.length-(n+1))}function X(t,e,n,i,o,f){if(t>n||t3?0===e||e===BigInt(0)?">= 0"+s+" and < 2"+s+" ** "+8*(f+1)+s:">= -(2"+s+" ** "+(8*(f+1)-1)+s+") and < 2 ** "+(8*(f+1)-1)+s:">= "+e+s+" and <= "+n+s,new G.ERR_OUT_OF_RANGE('value',u,t)}W(i,o,f)}function J(t,e){if('number'!=typeof t)throw new G.ERR_INVALID_ARG_TYPE(e,'number',t)}function Z(t,e,n){if(Math.floor(t)!==t)throw J(t,n),new G.ERR_OUT_OF_RANGE(n||'offset','an integer',t);if(e<0)throw new G.ERR_BUFFER_OUT_OF_BOUNDS;throw new G.ERR_OUT_OF_RANGE(n||'offset',">= "+(n?1:0)+" and <= "+e,t)}V('ERR_BUFFER_OUT_OF_BOUNDS',function(t){return t?t+" is outside of buffer bounds":'Attempt to access memory outside buffer bounds'},RangeError),V('ERR_INVALID_ARG_TYPE',function(t,e){return"The \""+t+"\" argument must be of type number. Received type "+typeof e},TypeError),V('ERR_OUT_OF_RANGE',function(t,e,n){var i="The value of \""+t+"\" is out of range.",o=n;return Number.isInteger(n)&&Math.abs(n)>Math.pow(2,32)?o=q(String(n)):'bigint'==typeof n&&(o=String(n),(n>Math.pow(BigInt(2),BigInt(32))||n<-Math.pow(BigInt(2),BigInt(32)))&&(o=q(o)),o+='n'),i+=" It must be "+e+". Received "+o},RangeError);var $=/[^+/0-9A-Za-z-_]/g;function H(t){if((t=(t=t.split('=')[0]).trim().replace($,'')).length<2)return'';for(;t.length%4!=0;)t+='=';return t}function K(t,e){var n;e=e||1/0;for(var i=t.length,o=null,f=[],u=0;u55295&&n<57344){if(!o){if(n>56319){(e-=3)>-1&&f.push(239,191,189);continue}if(u+1===i){(e-=3)>-1&&f.push(239,191,189);continue}o=n;continue}if(n<56320){(e-=3)>-1&&f.push(239,191,189),o=n;continue}n=65536+(o-55296<<10|n-56320)}else o&&(e-=3)>-1&&f.push(239,191,189);if(o=null,n<128){if((e-=1)<0)break;f.push(n)}else if(n<2048){if((e-=2)<0)break;f.push(n>>6|192,63&n|128)}else if(n<65536){if((e-=3)<0)break;f.push(n>>12|224,n>>6&63|128,63&n|128)}else{if(!(n<1114112))throw new Error('Invalid code point');if((e-=4)<0)break;f.push(n>>18|240,n>>12&63|128,n>>6&63|128,63&n|128)}}return f}function Q(t){for(var e=[],n=0;n>8,o=n%256,f.push(o),f.push(i);return f}function rt(t){return r(d[2]).toByteArray(H(t))}function et(t,e,n,i){var o;for(o=0;o=e.length||o>=t.length);++o)e[o+n]=t[o];return o}function nt(t,e){return t instanceof e||null!=t&&null!=t.constructor&&null!=t.constructor.name&&t.constructor.name===e.name}function it(t){return t!=t}var ot=(function(){for(var t=new Array(256),e=0;e<16;++e)for(var n=16*e,i=0;i<16;++i)t[n+i]="0123456789abcdef"[e]+"0123456789abcdef"[i];return t})();function ft(t){return'undefined'==typeof BigInt?ut:t}function ut(){throw new Error('BigInt not supported')}},801,[422,419,498,802,417,402,421,403]); -__d(function(g,r,_i,a,_m,_e,_d){_e.read=function(o,t,h,M,f){var w,p,i=8*f-M-1,n=(1<>1,e=-7,u=h?f-1:0,s=h?-1:1,c=o[t+u];for(u+=s,w=c&(1<<-e)-1,c>>=-e,e+=i;e>0;w=256*w+o[t+u],u+=s,e-=8);for(p=w&(1<<-e)-1,w>>=-e,e+=M;e>0;p=256*p+o[t+u],u+=s,e-=8);if(0===w)w=1-N;else{if(w===n)return p?NaN:1/0*(c?-1:1);p+=Math.pow(2,M),w-=N}return(c?-1:1)*p*Math.pow(2,w-M)},_e.write=function(o,t,h,M,f,w){var p,i,n,N=8*w-f-1,e=(1<>1,s=23===f?Math.pow(2,-24)-Math.pow(2,-77):0,c=M?0:w-1,l=M?1:-1,d=t<0||0===t&&1/t<0?1:0;for(t=Math.abs(t),isNaN(t)||t===1/0?(i=isNaN(t)?1:0,p=e):(p=Math.floor(Math.log(t)/Math.LN2),t*(n=Math.pow(2,-p))<1&&(p--,n*=2),(t+=p+u>=1?s/n:s*Math.pow(2,1-u))*n>=2&&(p++,n/=2),p+u>=e?(i=0,p=e):p+u>=1?(i=(t*n-1)*Math.pow(2,f),p+=u):(i=t*Math.pow(2,u-1)*Math.pow(2,f),p=0));f>=8;o[h+c]=255&i,c+=l,i/=256,f-=8);for(p=p<0;o[h+c]=255&p,c+=l,p/=256,N-=8);o[h+c-l]|=128*d}},802,[]); -__d(function(e,n,m,a,l,u,x){l.exports={name:"OnnxruntimeModuleExample",displayName:"OnnxruntimeModule Example"}},803,[]); -__r(52); -__r(0); \ 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 87845b877c125..08e1f9c017584 100644 --- a/js/react_native/e2e/android/build.gradle +++ b/js/react_native/e2e/android/build.gradle @@ -13,7 +13,7 @@ buildscript { jcenter() } dependencies { - classpath('com.android.tools.build:gradle:4.1.2') + classpath('com.android.tools.build:gradle:7.1.1') classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files 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 51d930a381f3a..59250647c4090 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 -distributionSha256Sum=7faa7198769f872826c8ef4f1450f839ec27f0b4d5d1e51bade63667cbccd205 -distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip +distributionSha256Sum=b586e04868a22fd817c8971330fec37e298f3242eb85c374181b12d637f80302 +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/js/react_native/e2e/ios/OnnxruntimeModuleExample/Images.xcassets/AppIcon.appiconset/Contents.json b/js/react_native/e2e/ios/OnnxruntimeModuleExample/Images.xcassets/AppIcon.appiconset/Contents.json index 118c98f7461bf..48e64ae8a3efa 100644 --- a/js/react_native/e2e/ios/OnnxruntimeModuleExample/Images.xcassets/AppIcon.appiconset/Contents.json +++ b/js/react_native/e2e/ios/OnnxruntimeModuleExample/Images.xcassets/AppIcon.appiconset/Contents.json @@ -1,38 +1,38 @@ { - "images" : [ + "images": [ { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "2x" + "idiom": "iphone", + "size": "29x29", + "scale": "2x" }, { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "3x" + "idiom": "iphone", + "size": "29x29", + "scale": "3x" }, { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "2x" + "idiom": "iphone", + "size": "40x40", + "scale": "2x" }, { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "3x" + "idiom": "iphone", + "size": "40x40", + "scale": "3x" }, { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "2x" + "idiom": "iphone", + "size": "60x60", + "scale": "2x" }, { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "3x" + "idiom": "iphone", + "size": "60x60", + "scale": "3x" } ], - "info" : { - "version" : 1, - "author" : "xcode" + "info": { + "version": 1, + "author": "xcode" } -} \ No newline at end of file +} diff --git a/js/react_native/e2e/ios/OnnxruntimeModuleExample/Images.xcassets/Contents.json b/js/react_native/e2e/ios/OnnxruntimeModuleExample/Images.xcassets/Contents.json index 2d92bd53fdb22..97a8662ebdb43 100644 --- a/js/react_native/e2e/ios/OnnxruntimeModuleExample/Images.xcassets/Contents.json +++ b/js/react_native/e2e/ios/OnnxruntimeModuleExample/Images.xcassets/Contents.json @@ -1,6 +1,6 @@ { - "info" : { - "version" : 1, - "author" : "xcode" + "info": { + "version": 1, + "author": "xcode" } } diff --git a/js/react_native/e2e/yarn.lock b/js/react_native/e2e/yarn.lock index 57f162ebd2650..aaa35ae7895b9 100644 --- a/js/react_native/e2e/yarn.lock +++ b/js/react_native/e2e/yarn.lock @@ -2579,9 +2579,9 @@ decamelize@^4.0.0: integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== decode-uri-component@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og== + version "0.2.2" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" + integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== dedent@^0.7.0: version "0.7.0" @@ -5548,19 +5548,19 @@ semver@7.0.0: integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== semver@^5.5.0, semver@^5.6.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + 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: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + 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.5: - version "7.4.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.4.0.tgz#8481c92feffc531ab1e012a8ffc15bdd3a0f4318" - integrity sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw== + 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" diff --git a/js/react_native/ios/OnnxruntimeJSIHelper.h b/js/react_native/ios/OnnxruntimeJSIHelper.h new file mode 100644 index 0000000000000..990a4d1879ece --- /dev/null +++ b/js/react_native/ios/OnnxruntimeJSIHelper.h @@ -0,0 +1,5 @@ +#import + +@interface OnnxruntimeJSIHelper : NSObject + +@end diff --git a/js/react_native/ios/OnnxruntimeJSIHelper.mm b/js/react_native/ios/OnnxruntimeJSIHelper.mm new file mode 100644 index 0000000000000..6fac00cefaedb --- /dev/null +++ b/js/react_native/ios/OnnxruntimeJSIHelper.mm @@ -0,0 +1,85 @@ +#import "OnnxruntimeJSIHelper.h" +#import +#import +#import + +@implementation OnnxruntimeJSIHelper + +RCT_EXPORT_MODULE() + +RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(install) { + RCTBridge *bridge = [RCTBridge currentBridge]; + RCTCxxBridge *cxxBridge = (RCTCxxBridge *)bridge; + if (cxxBridge == nil) { + return @false; + } + + using namespace facebook; + + auto jsiRuntime = (jsi::Runtime *)cxxBridge.runtime; + if (jsiRuntime == nil) { + return @false; + } + auto &runtime = *jsiRuntime; + + auto resolveArrayBuffer = jsi::Function::createFromHostFunction( + runtime, jsi::PropNameID::forUtf8(runtime, "jsiOnnxruntimeResolveArrayBuffer"), 1, + [](jsi::Runtime &runtime, const jsi::Value &thisArg, const jsi::Value *args, size_t count) -> jsi::Value { + if (count != 1) { + throw jsi::JSError(runtime, "jsiOnnxruntimeResolveArrayBuffer(..) expects one argument (object)!"); + } + + auto data = args[0].asObject(runtime); + auto blobId = data.getProperty(runtime, "blobId").asString(runtime).utf8(runtime); + auto size = data.getProperty(runtime, "size").asNumber(); + auto offset = data.getProperty(runtime, "offset").asNumber(); + + RCTBlobManager *blobManager = [[RCTBridge currentBridge] moduleForClass:RCTBlobManager.class]; + if (blobManager == nil) { + throw jsi::JSError(runtime, "RCTBlobManager is not initialized"); + } + + NSString *blobIdStr = [NSString stringWithUTF8String:blobId.c_str()]; + auto blob = [blobManager resolve:blobIdStr offset:(long)offset size:(long)size]; + + jsi::Function arrayBufferCtor = runtime.global().getPropertyAsFunction(runtime, "ArrayBuffer"); + jsi::Object o = arrayBufferCtor.callAsConstructor(runtime, (int)blob.length).getObject(runtime); + jsi::ArrayBuffer buf = o.getArrayBuffer(runtime); + memcpy(buf.data(runtime), blob.bytes, blob.length); + [blobManager remove:blobIdStr]; + return buf; + }); + runtime.global().setProperty(runtime, "jsiOnnxruntimeResolveArrayBuffer", resolveArrayBuffer); + + auto storeArrayBuffer = jsi::Function::createFromHostFunction( + runtime, jsi::PropNameID::forUtf8(runtime, "jsiOnnxruntimeStoreArrayBuffer"), 1, + [](jsi::Runtime &runtime, const jsi::Value &thisArg, const jsi::Value *args, size_t count) -> jsi::Value { + if (count != 1) { + throw jsi::JSError(runtime, "jsiOnnxruntimeStoreArrayBuffer(..) expects one argument (object)!"); + } + + auto arrayBuffer = args[0].asObject(runtime).getArrayBuffer(runtime); + auto size = arrayBuffer.length(runtime); + NSData *data = [NSData dataWithBytesNoCopy:arrayBuffer.data(runtime) length:size freeWhenDone:NO]; + + RCTBlobManager *blobManager = [[RCTBridge currentBridge] moduleForClass:RCTBlobManager.class]; + if (blobManager == nil) { + throw jsi::JSError(runtime, "RCTBlobManager is not initialized"); + } + + NSString *blobId = [blobManager store:data]; + + jsi::Object result(runtime); + auto blobIdString = jsi::String::createFromUtf8(runtime, [blobId cStringUsingEncoding:NSUTF8StringEncoding]); + result.setProperty(runtime, "blobId", blobIdString); + result.setProperty(runtime, "offset", jsi::Value(0)); + result.setProperty(runtime, "size", jsi::Value(static_cast(size))); + return result; + }); + + runtime.global().setProperty(runtime, "jsiOnnxruntimeStoreArrayBuffer", storeArrayBuffer); + + return @true; +} + +@end diff --git a/js/react_native/ios/OnnxruntimeModule.h b/js/react_native/ios/OnnxruntimeModule.h index 23f250a15560a..24603cc648525 100644 --- a/js/react_native/ios/OnnxruntimeModule.h +++ b/js/react_native/ios/OnnxruntimeModule.h @@ -5,12 +5,20 @@ #define OnnxruntimeModule_h #import +#import @interface OnnxruntimeModule : NSObject +- (void)setBlobManager:(RCTBlobManager *)manager; + -(NSDictionary*)loadModel:(NSString*)modelPath options:(NSDictionary*)options; +-(NSDictionary*)loadModelFromBuffer:(NSData*)modelData + options:(NSDictionary*)options; + +-(void)dispose:(NSString*)key; + -(NSDictionary*)run:(NSString*)url input:(NSDictionary*)input output:(NSArray*)output diff --git a/js/react_native/ios/OnnxruntimeModule.mm b/js/react_native/ios/OnnxruntimeModule.mm index fe7bf48c74d9c..040e1dc29ef24 100644 --- a/js/react_native/ios/OnnxruntimeModule.mm +++ b/js/react_native/ios/OnnxruntimeModule.mm @@ -5,8 +5,25 @@ #import "TensorHelper.h" #import +#import +#import #import -#import + +// Note: Using below syntax for including ort c api and ort extensions headers to resolve a compiling error happened +// in an expo react native ios app when ort extensions enabled (a redefinition error of multiple object types defined +// within ORT C API header). It's an edge case that compiler allows both ort c api headers to be included when #include +// syntax doesn't match. For the case when extensions not enabled, it still requires a onnxruntime prefix directory for +// searching paths. Also in general, it's a convention to use #include for C/C++ headers rather then #import. See: +// https://google.github.io/styleguide/objcguide.html#import-and-include +// https://microsoft.github.io/objc-guide/Headers/ImportAndInclude.html +#ifdef ORT_ENABLE_EXTENSIONS +#include "coreml_provider_factory.h" +#include "onnxruntime_cxx_api.h" +#include "onnxruntime_extensions.h" +#else +#include "onnxruntime/coreml_provider_factory.h" +#include +#endif @implementation OnnxruntimeModule @@ -22,8 +39,30 @@ @implementation OnnxruntimeModule static NSMutableDictionary *sessionMap = [NSMutableDictionary dictionary]; static Ort::AllocatorWithDefaultOptions ortAllocator; +static int nextSessionId = 0; +- (NSString *)getNextSessionKey { + NSString *key = @(nextSessionId).stringValue; + nextSessionId++; + return key; +} + RCT_EXPORT_MODULE(Onnxruntime) +RCTBlobManager *blobManager = nil; + +- (void)checkBlobManager { + if (blobManager == nil) { + blobManager = [[RCTBridge currentBridge] moduleForClass:RCTBlobManager.class]; + if (blobManager == nil) { + @throw @"RCTBlobManager is not initialized"; + } + } +} + +- (void)setBlobManager:(RCTBlobManager *)manager { + blobManager = manager; +} + /** * React native binding API to load a model using given uri. * @@ -43,7 +82,54 @@ @implementation OnnxruntimeModule NSDictionary *resultMap = [self loadModel:modelPath options:options]; resolve(resultMap); } @catch (...) { - reject(@"onnxruntime", @"can't load model", nil); + reject(@"onnxruntime", @"failed to load model", nil); + } +} + +/** + * React native binding API to load a model using blob object that data stored in RCTBlobManager. + * + * @param modelDataBlob a model data blob object + * @param options onnxruntime session options + * @param resolve callback for returning output back to react native js + * @param reject callback for returning an error back to react native js + * @note when run() is called, the same modelPath must be passed into the first parameter. + */ +RCT_EXPORT_METHOD(loadModelFromBlob + : (NSDictionary *)modelDataBlob options + : (NSDictionary *)options resolver + : (RCTPromiseResolveBlock)resolve rejecter + : (RCTPromiseRejectBlock)reject) { + @try { + [self checkBlobManager]; + NSString *blobId = [modelDataBlob objectForKey:@"blobId"]; + long size = [[modelDataBlob objectForKey:@"size"] longValue]; + long offset = [[modelDataBlob objectForKey:@"offset"] longValue]; + auto modelData = [blobManager resolve:blobId offset:offset size:size]; + NSDictionary *resultMap = [self loadModelFromBuffer:modelData options:options]; + [blobManager remove:blobId]; + resolve(resultMap); + } @catch (...) { + reject(@"onnxruntime", @"failed to load model from buffer", nil); + } +} + +/** + * React native binding API to dispose a session using given key from loadModel() + * + * @param key a model path location given at loadModel() + * @param resolve callback for returning output back to react native js + * @param reject callback for returning an error back to react native js + */ +RCT_EXPORT_METHOD(dispose + : (NSString *)key resolver + : (RCTPromiseResolveBlock)resolve rejecter + : (RCTPromiseRejectBlock)reject) { + @try { + [self dispose:key]; + resolve(nil); + } @catch (...) { + reject(@"onnxruntime", @"failed to dispose session", nil); } } @@ -68,49 +154,75 @@ @implementation OnnxruntimeModule NSDictionary *resultMap = [self run:url input:input output:output options:options]; resolve(resultMap); } @catch (...) { - reject(@"onnxruntime", @"can't run model", nil); + reject(@"onnxruntime", @"failed to run model", nil); } } /** * Load a model using given model path. * - * @param modelPath a model file location. it's used as a key when multiple sessions are created, i.e. multiple models - * are loaded. - * @param options onnxruntime session options + * @param modelPath a model file location. + * @param options onnxruntime session options. * @note when run() is called, the same modelPath must be passed into the first parameter. */ - (NSDictionary *)loadModel:(NSString *)modelPath options:(NSDictionary *)options { - NSValue *value = [sessionMap objectForKey:modelPath]; - SessionInfo *sessionInfo = nullptr; - if (value == nil) { - sessionInfo = new SessionInfo(); + return [self loadModelImpl:modelPath modelData:nil options:options]; +} - Ort::SessionOptions sessionOptions = [self parseSessionOptions:options]; - sessionInfo->session.reset(new Ort::Session(*ortEnv, [modelPath UTF8String], sessionOptions)); +/** + * Load a model using given model data array + * + * @param modelData the model data buffer. + * @param options onnxruntime session options + */ +- (NSDictionary *)loadModelFromBuffer:(NSData *)modelData options:(NSDictionary *)options { + return [self loadModelImpl:@"" modelData:modelData options:options]; +} - sessionInfo->inputNames.reserve(sessionInfo->session->GetInputCount()); - for (size_t i = 0; i < sessionInfo->session->GetInputCount(); ++i) { - auto inputName = sessionInfo->session->GetInputNameAllocated(i, ortAllocator); - sessionInfo->inputNames.emplace_back(inputName.get()); - sessionInfo->inputNames_ptrs.emplace_back(std::move(inputName)); - } +/** + * Load model implementation method given either model data array or model path + * + * @param modelPath the model file location. + * @param modelData the model data buffer. + * @param options onnxruntime session options. + */ +- (NSDictionary *)loadModelImpl:(NSString *)modelPath modelData:(NSData *)modelData options:(NSDictionary *)options { + SessionInfo *sessionInfo = nullptr; + sessionInfo = new SessionInfo(); + Ort::SessionOptions sessionOptions = [self parseSessionOptions:options]; - sessionInfo->outputNames.reserve(sessionInfo->session->GetOutputCount()); - for (size_t i = 0; i < sessionInfo->session->GetOutputCount(); ++i) { - auto outputName = sessionInfo->session->GetOutputNameAllocated(i, ortAllocator); - sessionInfo->outputNames.emplace_back(outputName.get()); - sessionInfo->outputNames_ptrs.emplace_back(std::move(outputName)); - } +#ifdef ORT_ENABLE_EXTENSIONS + Ort::ThrowOnError(RegisterCustomOps(sessionOptions, OrtGetApiBase())); +#endif - value = [NSValue valueWithPointer:(void *)sessionInfo]; - sessionMap[modelPath] = value; + if (modelData == nil) { + sessionInfo->session.reset(new Ort::Session(*ortEnv, [modelPath UTF8String], sessionOptions)); } else { - sessionInfo = (SessionInfo *)[value pointerValue]; + NSUInteger dataLength = [modelData length]; + Byte *modelBytes = (Byte *)[modelData bytes]; + sessionInfo->session.reset(new Ort::Session(*ortEnv, modelBytes, (size_t)dataLength, sessionOptions)); + } + + sessionInfo->inputNames.reserve(sessionInfo->session->GetInputCount()); + for (size_t i = 0; i < sessionInfo->session->GetInputCount(); ++i) { + auto inputName = sessionInfo->session->GetInputNameAllocated(i, ortAllocator); + sessionInfo->inputNames.emplace_back(inputName.get()); + sessionInfo->inputNames_ptrs.emplace_back(std::move(inputName)); } + sessionInfo->outputNames.reserve(sessionInfo->session->GetOutputCount()); + for (size_t i = 0; i < sessionInfo->session->GetOutputCount(); ++i) { + auto outputName = sessionInfo->session->GetOutputNameAllocated(i, ortAllocator); + sessionInfo->outputNames.emplace_back(outputName.get()); + sessionInfo->outputNames_ptrs.emplace_back(std::move(outputName)); + } + + NSString *key = [self getNextSessionKey]; + NSValue *value = [NSValue valueWithPointer:(void *)sessionInfo]; + sessionMap[key] = value; + NSMutableDictionary *resultMap = [NSMutableDictionary dictionary]; - resultMap[@"key"] = modelPath; + resultMap[@"key"] = key; NSMutableArray *inputNames = [NSMutableArray array]; for (auto inputName : sessionInfo->inputNames) { @@ -127,6 +239,25 @@ - (NSDictionary *)loadModel:(NSString *)modelPath options:(NSDictionary *)option return resultMap; } +/** + * Dispose a session given a key. + * + * @param key a session key returned from loadModel() + */ +- (void)dispose:(NSString *)key { + NSValue *value = [sessionMap objectForKey:key]; + if (value == nil) { + NSException *exception = [NSException exceptionWithName:@"onnxruntime" + reason:@"can't find onnxruntime session" + userInfo:nil]; + @throw exception; + } + [sessionMap removeObjectForKey:key]; + SessionInfo *sessionInfo = (SessionInfo *)[value pointerValue]; + delete sessionInfo; + sessionInfo = nullptr; +} + /** * Run a model using given uri. * @@ -148,6 +279,8 @@ - (NSDictionary *)run:(NSString *)url } SessionInfo *sessionInfo = (SessionInfo *)[value pointerValue]; + [self checkBlobManager]; + std::vector feeds; std::vector allocations; feeds.reserve(sessionInfo->inputNames.size()); @@ -158,7 +291,10 @@ - (NSDictionary *)run:(NSString *)url @throw exception; } - Ort::Value value = [TensorHelper createInputTensor:inputTensor ortAllocator:ortAllocator allocations:allocations]; + Ort::Value value = [TensorHelper createInputTensor:blobManager + input:inputTensor + ortAllocator:ortAllocator + allocations:allocations]; feeds.emplace_back(std::move(value)); } @@ -173,7 +309,7 @@ - (NSDictionary *)run:(NSString *)url sessionInfo->session->Run(runOptions, sessionInfo->inputNames.data(), feeds.data(), sessionInfo->inputNames.size(), requestedOutputs.data(), requestedOutputs.size()); - NSDictionary *resultMap = [TensorHelper createOutputTensor:requestedOutputs values:result]; + NSDictionary *resultMap = [TensorHelper createOutputTensor:blobManager outputNames:requestedOutputs values:result]; return resultMap; } @@ -237,6 +373,44 @@ - (NSDictionary *)run:(NSString *)url } } + if ([options objectForKey:@"executionProviders"]) { + NSArray *executionProviders = [options objectForKey:@"executionProviders"]; + for (auto *executionProvider in executionProviders) { + NSString *epName = nil; + bool useOptions = false; + if ([executionProvider isKindOfClass:[NSString class]]) { + epName = (NSString *)executionProvider; + } else { + epName = [executionProvider objectForKey:@"name"]; + useOptions = true; + } + if ([epName isEqualToString:@"coreml"]) { + uint32_t coreml_flags = 0; + if (useOptions) { + if ([[executionProvider objectForKey:@"useCPUOnly"] boolValue]) { + coreml_flags |= COREML_FLAG_USE_CPU_ONLY; + } + if ([[executionProvider objectForKey:@"enableOnSubgraph"] boolValue]) { + coreml_flags |= COREML_FLAG_ENABLE_ON_SUBGRAPH; + } + if ([[executionProvider objectForKey:@"onlyEnableDeviceWithANE"] boolValue]) { + coreml_flags |= COREML_FLAG_ONLY_ENABLE_DEVICE_WITH_ANE; + } + } + Ort::ThrowOnError(OrtSessionOptionsAppendExecutionProvider_CoreML(sessionOptions, coreml_flags)); + } else if ([epName isEqualToString:@"xnnpack"]) { + sessionOptions.AppendExecutionProvider("XNNPACK", {}); + } else if ([epName isEqualToString:@"cpu"]) { + continue; + } else { + NSException *exception = [NSException exceptionWithName:@"onnxruntime" + reason:@"unsupported execution provider" + userInfo:nil]; + @throw exception; + } + } + } + if ([options objectForKey:@"logId"]) { NSString *logId = [[options objectForKey:@"logId"] stringValue]; sessionOptions.SetLogId([logId UTF8String]); @@ -269,11 +443,9 @@ - (NSDictionary *)run:(NSString *)url - (void)dealloc { NSEnumerator *iterator = [sessionMap keyEnumerator]; while (NSString *key = [iterator nextObject]) { - NSValue *value = [sessionMap objectForKey:key]; - SessionInfo *sessionInfo = (SessionInfo *)[value pointerValue]; - delete sessionInfo; - sessionInfo = nullptr; + [self dispose:key]; } + blobManager = nullptr; } @end diff --git a/js/react_native/ios/OnnxruntimeModuleTest/FakeRCTBlobManager.h b/js/react_native/ios/OnnxruntimeModuleTest/FakeRCTBlobManager.h new file mode 100644 index 0000000000000..c6069b1a1d26d --- /dev/null +++ b/js/react_native/ios/OnnxruntimeModuleTest/FakeRCTBlobManager.h @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef FakeRCTBlobManager_h +#define FakeRCTBlobManager_h + +#import + +@interface FakeRCTBlobManager : RCTBlobManager + +@property (nonatomic, strong) NSMutableDictionary *blobs; + +- (NSString *)store:(NSData *)data; + +- (NSData *)resolve:(NSString *)blobId offset:(long)offset size:(long)size; + +- (NSDictionary *)testCreateData:(NSData *)buffer; + +- (NSString *)testGetData:(NSDictionary *)data; + +@end + +#endif /* FakeRCTBlobManager_h */ diff --git a/js/react_native/ios/OnnxruntimeModuleTest/FakeRCTBlobManager.m b/js/react_native/ios/OnnxruntimeModuleTest/FakeRCTBlobManager.m new file mode 100644 index 0000000000000..5df902df03534 --- /dev/null +++ b/js/react_native/ios/OnnxruntimeModuleTest/FakeRCTBlobManager.m @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import +#import "FakeRCTBlobManager.h" + +@implementation FakeRCTBlobManager + +- (instancetype)init { + if (self = [super init]) { + _blobs = [NSMutableDictionary new]; + } + return self; +} + +- (NSString *)store:(NSData *)data { + NSString *blobId = [[NSUUID UUID] UUIDString]; + _blobs[blobId] = data; + return blobId; +} + +- (NSData *)resolve:(NSString *)blobId offset:(long)offset size:(long)size { + NSData *data = _blobs[blobId]; + if (data == nil) { + return nil; + } + return [data subdataWithRange:NSMakeRange(offset, size)]; +} + +- (NSDictionary *)testCreateData:(NSData *)buffer { + NSString* blobId = [self store:buffer]; + return @{ + @"blobId": blobId, + @"offset": @0, + @"size": @(buffer.length), + }; +} + +- (NSString *)testGetData:(NSDictionary *)data { + NSString *blobId = [data objectForKey:@"blobId"]; + long size = [[data objectForKey:@"size"] longValue]; + long offset = [[data objectForKey:@"offset"] longValue]; + [self resolve:blobId offset:offset size:size]; + return blobId; +} + +@end diff --git a/js/react_native/ios/OnnxruntimeModuleTest/OnnxruntimeModuleTest.mm b/js/react_native/ios/OnnxruntimeModuleTest/OnnxruntimeModuleTest.mm index ee08e50ab6502..f5805717f6615 100644 --- a/js/react_native/ios/OnnxruntimeModuleTest/OnnxruntimeModuleTest.mm +++ b/js/react_native/ios/OnnxruntimeModuleTest/OnnxruntimeModuleTest.mm @@ -2,6 +2,7 @@ // Licensed under the MIT License. #import "OnnxruntimeModule.h" +#import "FakeRCTBlobManager.h" #import "TensorHelper.h" #import @@ -13,24 +14,46 @@ @interface OnnxruntimeModuleTest : XCTestCase @implementation OnnxruntimeModuleTest +FakeRCTBlobManager *fakeBlobManager = nil; + ++ (void)initialize { + if (self == [OnnxruntimeModuleTest class]) { + fakeBlobManager = [FakeRCTBlobManager new]; + } +} + - (void)testOnnxruntimeModule { NSBundle *bundle = [NSBundle bundleForClass:[OnnxruntimeModuleTest class]]; NSString *dataPath = [bundle pathForResource:@"test_types_float" ofType:@"ort"]; + NSString *sessionKey = @""; + NSString *sessionKey2 = @""; OnnxruntimeModule *onnxruntimeModule = [OnnxruntimeModule new]; + [onnxruntimeModule setBlobManager:fakeBlobManager]; - // test loadModel() { + // test loadModelFromBuffer() NSMutableDictionary *options = [NSMutableDictionary dictionary]; - NSDictionary *resultMap = [onnxruntimeModule loadModel:dataPath options:options]; + NSData *fileData = [NSData dataWithContentsOfFile:dataPath]; - XCTAssertEqual(resultMap[@"key"], dataPath); + NSDictionary *resultMap = [onnxruntimeModule loadModelFromBuffer:fileData options:options]; + sessionKey = resultMap[@"key"]; NSArray *inputNames = resultMap[@"inputNames"]; XCTAssertEqual([inputNames count], 1); XCTAssertEqualObjects(inputNames[0], @"input"); NSArray *outputNames = resultMap[@"outputNames"]; XCTAssertEqual([outputNames count], 1); XCTAssertEqualObjects(outputNames[0], @"output"); + + // test loadModel() + NSDictionary *resultMap2 = [onnxruntimeModule loadModel:dataPath options:options]; + sessionKey2 = resultMap2[@"key"]; + NSArray *inputNames2 = resultMap2[@"inputNames"]; + XCTAssertEqual([inputNames2 count], 1); + XCTAssertEqualObjects(inputNames2[0], @"input"); + NSArray *outputNames2 = resultMap2[@"outputNames"]; + XCTAssertEqual([outputNames2 count], 1); + XCTAssertEqualObjects(outputNames2[0], @"output"); } // test run() @@ -45,10 +68,10 @@ - (void)testOnnxruntimeModule { inputTensorMap[@"type"] = JsTensorTypeFloat; // data - std::array outValues{std::numeric_limits::min(), 1.0f, -2.0f, 3.0f, - std::numeric_limits::max()}; + std::array outValues{std::numeric_limits::min(), 1.0f, -2.0f, 3.0f, + std::numeric_limits::max()}; - const NSInteger byteBufferSize = outValues.size() * sizeof(float_t); + const NSInteger byteBufferSize = outValues.size() * sizeof(float); unsigned char *byteBuffer = static_cast(malloc(byteBufferSize)); NSData *byteBufferRef = [NSData dataWithBytesNoCopy:byteBuffer length:byteBufferSize]; float *floatPtr = (float *)[byteBufferRef bytes]; @@ -57,8 +80,8 @@ - (void)testOnnxruntimeModule { } floatPtr = (float *)[byteBufferRef bytes]; - NSString *dataEncoded = [byteBufferRef base64EncodedStringWithOptions:0]; - inputTensorMap[@"data"] = dataEncoded; + XCTAssertNotNil(fakeBlobManager); + inputTensorMap[@"data"] = [fakeBlobManager testCreateData:byteBufferRef]; NSMutableDictionary *inputDataMap = [NSMutableDictionary dictionary]; inputDataMap[@"input"] = inputTensorMap; @@ -68,10 +91,60 @@ - (void)testOnnxruntimeModule { NSMutableArray *output = [NSMutableArray array]; [output addObject:@"output"]; - NSDictionary *resultMap = [onnxruntimeModule run:dataPath input:inputDataMap output:output options:options]; + NSDictionary *resultMap = [onnxruntimeModule run:sessionKey input:inputDataMap output:output options:options]; + NSDictionary *resultMap2 = [onnxruntimeModule run:sessionKey2 input:inputDataMap output:output options:options]; + + // Compare output & input, but data.blobId is different + // dims + XCTAssertTrue([[resultMap objectForKey:@"output"][@"dims"] isEqualToArray:inputTensorMap[@"dims"]]); + XCTAssertTrue([[resultMap2 objectForKey:@"output"][@"dims"] isEqualToArray:inputTensorMap[@"dims"]]); + + // type + XCTAssertEqual([resultMap objectForKey:@"output"][@"type"], JsTensorTypeFloat); + XCTAssertEqual([resultMap2 objectForKey:@"output"][@"type"], JsTensorTypeFloat); + + // data ({ blobId, offset, size }) + XCTAssertEqual([[resultMap objectForKey:@"output"][@"data"][@"offset"] longValue], 0); + XCTAssertEqual([[resultMap2 objectForKey:@"output"][@"data"][@"size"] longValue], byteBufferSize); + } + + // test dispose + { + [onnxruntimeModule dispose:sessionKey]; + [onnxruntimeModule dispose:sessionKey2]; + } +} + +- (void)testOnnxruntimeModule_AppendCoreml { + NSBundle *bundle = [NSBundle bundleForClass:[OnnxruntimeModuleTest class]]; + NSString *dataPath = [bundle pathForResource:@"test_types_float" ofType:@"ort"]; + NSString *sessionKey = @""; - XCTAssertTrue([[resultMap objectForKey:@"output"] isEqualToDictionary:inputTensorMap]); + OnnxruntimeModule *onnxruntimeModule = [OnnxruntimeModule new]; + [onnxruntimeModule setBlobManager:fakeBlobManager]; + + { + // test loadModel() with coreml options + NSMutableDictionary *options = [NSMutableDictionary dictionary]; + + // register coreml ep options + NSMutableArray *epList = [NSMutableArray array]; + [epList addObject:@"coreml"]; + NSArray *immutableEpList = [NSArray arrayWithArray:epList]; + [options setObject:immutableEpList forKey:@"executionProviders"]; + + NSDictionary *resultMap = [onnxruntimeModule loadModel:dataPath options:options]; + + sessionKey = resultMap[@"key"]; + NSArray *inputNames = resultMap[@"inputNames"]; + XCTAssertEqual([inputNames count], 1); + XCTAssertEqualObjects(inputNames[0], @"input"); + NSArray *outputNames = resultMap[@"outputNames"]; + XCTAssertEqual([outputNames count], 1); + XCTAssertEqualObjects(outputNames[0], @"output"); } + + { [onnxruntimeModule dispose:sessionKey]; } } @end diff --git a/js/react_native/ios/OnnxruntimeModuleTest/TensorHelperTest.mm b/js/react_native/ios/OnnxruntimeModuleTest/TensorHelperTest.mm index 3ed082e22237f..edd476d03914c 100644 --- a/js/react_native/ios/OnnxruntimeModuleTest/TensorHelperTest.mm +++ b/js/react_native/ios/OnnxruntimeModuleTest/TensorHelperTest.mm @@ -3,6 +3,7 @@ #import "TensorHelper.h" +#import "FakeRCTBlobManager.h" #import #import #include @@ -13,6 +14,14 @@ @interface TensorHelperTest : XCTestCase @implementation TensorHelperTest +FakeRCTBlobManager *testBlobManager = nil; + ++ (void)initialize { + if (self == [TensorHelperTest class]) { + testBlobManager = [FakeRCTBlobManager new]; + } +} + template static void testCreateInputTensorT(const std::array &outValues, std::function &convert, ONNXTensorElementDataType onnxType, NSString *jsTensorType) { @@ -34,12 +43,13 @@ static void testCreateInputTensorT(const std::array &outValues, std::funct typePtr[i] = outValues[i]; } - NSString *dataEncoded = [byteBufferRef base64EncodedStringWithOptions:0]; - inputTensorMap[@"data"] = dataEncoded; + XCTAssertNotNil(testBlobManager); + inputTensorMap[@"data"] = [testBlobManager testCreateData:byteBufferRef]; Ort::AllocatorWithDefaultOptions ortAllocator; std::vector allocations; - Ort::Value inputTensor = [TensorHelper createInputTensor:inputTensorMap + Ort::Value inputTensor = [TensorHelper createInputTensor:testBlobManager + input:inputTensorMap ortAllocator:ortAllocator allocations:allocations]; @@ -56,9 +66,9 @@ static void testCreateInputTensorT(const std::array &outValues, std::funct } - (void)testCreateInputTensorFloat { - std::array outValues{std::numeric_limits::min(), 2.0f, std::numeric_limits::max()}; - std::function convert = [](float_t value) { return [NSNumber numberWithFloat:value]; }; - testCreateInputTensorT(outValues, convert, ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, JsTensorTypeFloat); + std::array outValues{std::numeric_limits::min(), 2.0f, std::numeric_limits::max()}; + std::function convert = [](float value) { return [NSNumber numberWithFloat:value]; }; + testCreateInputTensorT(outValues, convert, ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, JsTensorTypeFloat); } - (void)testCreateInputTensorDouble { @@ -126,7 +136,8 @@ - (void)testCreateInputTensorString { Ort::AllocatorWithDefaultOptions ortAllocator; std::vector allocations; - Ort::Value inputTensor = [TensorHelper createInputTensor:inputTensorMap + Ort::Value inputTensor = [TensorHelper createInputTensor:testBlobManager + input:inputTensorMap ortAllocator:ortAllocator allocations:allocations]; @@ -194,10 +205,11 @@ static void testCreateOutputTensorT(const std::array &outValues, std::func typePtr[i] = outValues[i]; } - NSString *dataEncoded = [byteBufferRef base64EncodedStringWithOptions:0]; - inputTensorMap[@"data"] = dataEncoded; + inputTensorMap[@"data"] = [testBlobManager testCreateData:byteBufferRef]; + ; std::vector allocations; - Ort::Value inputTensor = [TensorHelper createInputTensor:inputTensorMap + Ort::Value inputTensor = [TensorHelper createInputTensor:testBlobManager + input:inputTensorMap ortAllocator:ortAllocator allocations:allocations]; @@ -208,16 +220,31 @@ static void testCreateOutputTensorT(const std::array &outValues, std::func auto output = session.Run(runOptions, inputNames.data(), feeds.data(), inputNames.size(), outputNames.data(), outputNames.size()); - NSDictionary *resultMap = [TensorHelper createOutputTensor:outputNames values:output]; + NSDictionary *resultMap = [TensorHelper createOutputTensor:testBlobManager outputNames:outputNames values:output]; + + // Compare output & input, but data.blobId is different + + NSDictionary *outputMap = [resultMap objectForKey:@"output"]; + + // dims + XCTAssertTrue([outputMap[@"dims"] isEqualToArray:inputTensorMap[@"dims"]]); + + // type + XCTAssertEqual(outputMap[@"type"], jsTensorType); + + // data ({ blobId, offset, size }) + NSDictionary *data = outputMap[@"data"]; - XCTAssertTrue([[resultMap objectForKey:@"output"] isEqualToDictionary:inputTensorMap]); + XCTAssertNotNil(data[@"blobId"]); + XCTAssertEqual([data[@"offset"] longValue], 0); + XCTAssertEqual([data[@"size"] longValue], byteBufferSize); } - (void)testCreateOutputTensorFloat { - std::array outValues{std::numeric_limits::min(), 1.0f, 2.0f, 3.0f, - std::numeric_limits::max()}; - std::function convert = [](float_t value) { return [NSNumber numberWithFloat:value]; }; - testCreateOutputTensorT(outValues, convert, JsTensorTypeFloat, @"test_types_float", @"ort"); + std::array outValues{std::numeric_limits::min(), 1.0f, 2.0f, 3.0f, + std::numeric_limits::max()}; + std::function convert = [](float value) { return [NSNumber numberWithFloat:value]; }; + testCreateOutputTensorT(outValues, convert, JsTensorTypeFloat, @"test_types_float", @"ort"); } - (void)testCreateOutputTensorDouble { diff --git a/js/react_native/ios/TensorHelper.h b/js/react_native/ios/TensorHelper.h index f0936cce8bdca..c7c7fa8fd9f45 100644 --- a/js/react_native/ios/TensorHelper.h +++ b/js/react_native/ios/TensorHelper.h @@ -5,7 +5,20 @@ #define TensorHelper_h #import -#import +#import + +// Note: Using below syntax for including ort c api and ort extensions headers to resolve a compiling error happened +// in an expo react native ios app (a redefinition error happened with multiple object types defined within +// ORT C API header). It's an edge case that the compiler allows both ort c api headers to be included when #include +// syntax doesn't match. For the case when extensions not enabled, it still requires a onnxruntime prefix directory for +// searching paths. Also in general, it's a convention to use #include for C/C++ headers rather then #import. See: +// https://google.github.io/styleguide/objcguide.html#import-and-include +// https://microsoft.github.io/objc-guide/Headers/ImportAndInclude.html +#ifdef ORT_ENABLE_EXTENSIONS +#include "onnxruntime_cxx_api.h" +#else +#include +#endif @interface TensorHelper : NSObject @@ -24,17 +37,19 @@ FOUNDATION_EXPORT NSString* const JsTensorTypeString; /** * It creates an input tensor from a map passed by react native js. - * 'data' must be a string type as data is encoded as base64. It first decodes it and creates a tensor. + * 'data' is blob object and the buffer is stored in RCTBlobManager. It first resolve it and creates a tensor. */ -+(Ort::Value)createInputTensor:(NSDictionary*)input ++(Ort::Value)createInputTensor:(RCTBlobManager *)blobManager + input:(NSDictionary*)input ortAllocator:(OrtAllocator*)ortAllocator - allocations:(std::vector&)allocatons; + allocations:(std::vector&)allocations; /** * It creates an output map from an output tensor. - * a data array is encoded as base64 string. + * a data array is store in RCTBlobManager. */ -+(NSDictionary*)createOutputTensor:(const std::vector&)outputNames ++(NSDictionary*)createOutputTensor:(RCTBlobManager *)blobManager + outputNames:(const std::vector&)outputNames values:(const std::vector&)values; @end diff --git a/js/react_native/ios/TensorHelper.mm b/js/react_native/ios/TensorHelper.mm index 00c1c79defd88..8555dfec275f8 100644 --- a/js/react_native/ios/TensorHelper.mm +++ b/js/react_native/ios/TensorHelper.mm @@ -21,11 +21,12 @@ @implementation TensorHelper /** * It creates an input tensor from a map passed by react native js. - * 'data' must be a string type as data is encoded as base64. It first decodes it and creates a tensor. + * 'data' is blob object and the buffer is stored in RCTBlobManager. It first resolve it and creates a tensor. */ -+ (Ort::Value)createInputTensor:(NSDictionary *)input ++ (Ort::Value)createInputTensor:(RCTBlobManager *)blobManager + input:(NSDictionary *)input ortAllocator:(OrtAllocator *)ortAllocator - allocations:(std::vector &)allocatons { + allocations:(std::vector &)allocations { // shape NSArray *dimsArray = [input objectForKey:@"dims"]; std::vector dims; @@ -48,22 +49,27 @@ @implementation TensorHelper } return inputTensor; } else { - NSString *data = [input objectForKey:@"data"]; - NSData *buffer = [[NSData alloc] initWithBase64EncodedString:data options:0]; + NSDictionary *data = [input objectForKey:@"data"]; + NSString *blobId = [data objectForKey:@"blobId"]; + long size = [[data objectForKey:@"size"] longValue]; + long offset = [[data objectForKey:@"offset"] longValue]; + auto buffer = [blobManager resolve:blobId offset:offset size:size]; Ort::Value inputTensor = [self createInputTensor:tensorType dims:dims buffer:buffer ortAllocator:ortAllocator - allocations:allocatons]; + allocations:allocations]; + [blobManager remove:blobId]; return inputTensor; } } /** * It creates an output map from an output tensor. - * a data array is encoded as base64 string. + * a data array is store in RCTBlobManager. */ -+ (NSDictionary *)createOutputTensor:(const std::vector &)outputNames ++ (NSDictionary *)createOutputTensor:(RCTBlobManager *)blobManager + outputNames:(const std::vector &)outputNames values:(const std::vector &)values { if (outputNames.size() != values.size()) { NSException *exception = [NSException exceptionWithName:@"create output tensor" @@ -109,8 +115,13 @@ + (NSDictionary *)createOutputTensor:(const std::vector &)outputNa } outputTensor[@"data"] = buffer; } else { - NSString *data = [self createOutputTensor:value]; - outputTensor[@"data"] = data; + NSData *data = [self createOutputTensor:value]; + NSString *blobId = [blobManager store:data]; + outputTensor[@"data"] = @{ + @"blobId" : blobId, + @"offset" : @0, + @"size" : @(data.length), + }; } outputTensorMap[[NSString stringWithUTF8String:outputName]] = outputTensor; @@ -137,7 +148,7 @@ + (NSDictionary *)createOutputTensor:(const std::vector &)outputNa allocations:(std::vector &)allocations { switch (tensorType) { case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT: - return createInputTensorT(ortAllocator, dims, buffer, allocations); + return createInputTensorT(ortAllocator, dims, buffer, allocations); case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8: return createInputTensorT(ortAllocator, dims, buffer, allocations); case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8: @@ -170,20 +181,19 @@ + (NSDictionary *)createOutputTensor:(const std::vector &)outputNa } } -template static NSString *createOutputTensorT(const Ort::Value &tensor) { +template static NSData *createOutputTensorT(const Ort::Value &tensor) { const auto data = tensor.GetTensorData(); - NSData *buffer = [NSData dataWithBytesNoCopy:(void *)data - length:tensor.GetTensorTypeAndShapeInfo().GetElementCount() * sizeof(T) - freeWhenDone:false]; - return [buffer base64EncodedStringWithOptions:0]; + return [NSData dataWithBytesNoCopy:(void *)data + length:tensor.GetTensorTypeAndShapeInfo().GetElementCount() * sizeof(T) + freeWhenDone:false]; } -+ (NSString *)createOutputTensor:(const Ort::Value &)tensor { ++ (NSData *)createOutputTensor:(const Ort::Value &)tensor { ONNXTensorElementDataType tensorType = tensor.GetTensorTypeAndShapeInfo().GetElementType(); switch (tensorType) { case ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT: - return createOutputTensorT(tensor); + return createOutputTensorT(tensor); case ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8: return createOutputTensorT(tensor); case ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8: diff --git a/js/react_native/lib/backend.ts b/js/react_native/lib/backend.ts index 4ebc364cd883f..b3f0c466308a5 100644 --- a/js/react_native/lib/backend.ts +++ b/js/react_native/lib/backend.ts @@ -1,11 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import {Buffer} from 'buffer'; import {Backend, InferenceSession, SessionHandler, Tensor,} from 'onnxruntime-common'; import {Platform} from 'react-native'; -import {binding, Binding} from './binding'; +import {binding, Binding, JSIBlob, jsiHelper} from './binding'; type SupportedTypedArray = Exclude; @@ -48,25 +47,35 @@ class OnnxruntimeSessionHandler implements SessionHandler { #inferenceSession: Binding.InferenceSession; #key: string; + #pathOrBuffer: string|Uint8Array; + inputNames: string[]; outputNames: string[]; - constructor(path: string) { + constructor(pathOrBuffer: string|Uint8Array) { this.#inferenceSession = binding; - this.#key = normalizePath(path); + this.#pathOrBuffer = pathOrBuffer; + this.#key = ''; + this.inputNames = []; this.outputNames = []; } async loadModel(options: InferenceSession.SessionOptions): Promise { try { + let results: Binding.ModelLoadInfoType; // load a model - const results: Binding.ModelLoadInfoType = await this.#inferenceSession.loadModel(this.#key, options); - // resolve promise if onnxruntime session is successfully created - if (results.key !== this.#key) { - throw new Error('Session key is invalid'); + if (typeof this.#pathOrBuffer === 'string') { + results = await this.#inferenceSession.loadModel(normalizePath(this.#pathOrBuffer), options); + } else { + if (!this.#inferenceSession.loadModelFromBlob) { + throw new Error('Native module method "loadModelFromBlob" is not defined'); + } + const modelBlob = jsiHelper.storeArrayBuffer(this.#pathOrBuffer); + results = await this.#inferenceSession.loadModelFromBlob(modelBlob, options); } - + // resolve promise if onnxruntime session is successfully created + this.#key = results.key; this.inputNames = results.inputNames; this.outputNames = results.outputNames; } catch (e) { @@ -75,7 +84,7 @@ class OnnxruntimeSessionHandler implements SessionHandler { } async dispose(): Promise { - return Promise.resolve(); + return this.#inferenceSession.dispose(this.#key); } startProfiling(): void { @@ -103,18 +112,18 @@ class OnnxruntimeSessionHandler implements SessionHandler { return output; } + encodeFeedsType(feeds: SessionHandler.FeedsType): Binding.FeedsType { const returnValue: {[name: string]: Binding.EncodedTensorType} = {}; for (const key in feeds) { if (Object.hasOwnProperty.call(feeds, key)) { - let data: string|string[]; + let data: JSIBlob|string[]; if (Array.isArray(feeds[key].data)) { data = feeds[key].data as string[]; } else { - // Base64-encode tensor data const buffer = (feeds[key].data as SupportedTypedArray).buffer; - data = Buffer.from(buffer, 0, buffer.byteLength).toString('base64'); + data = jsiHelper.storeArrayBuffer(buffer); } returnValue[key] = { @@ -136,9 +145,9 @@ class OnnxruntimeSessionHandler implements SessionHandler { if (Array.isArray(results[key].data)) { tensorData = results[key].data as string[]; } else { - const buffer: Buffer = Buffer.from(results[key].data as string, 'base64'); + const buffer = jsiHelper.resolveArrayBuffer(results[key].data as JSIBlob) as SupportedTypedArray; const typedArray = tensorTypeToTypedArray(results[key].type as Tensor.Type); - tensorData = new typedArray(buffer.buffer, buffer.byteOffset, buffer.length / typedArray.BYTES_PER_ELEMENT); + tensorData = new typedArray(buffer, buffer.byteOffset, buffer.byteLength / typedArray.BYTES_PER_ELEMENT); } returnValue[key] = new Tensor(results[key].type as Tensor.Type, tensorData, results[key].dims); @@ -156,9 +165,6 @@ class OnnxruntimeBackend implements Backend { async createSessionHandler(pathOrBuffer: string|Uint8Array, options?: InferenceSession.SessionOptions): Promise { - if (typeof pathOrBuffer !== 'string') { - throw new Error('Uint8Array is not supported'); - } const handler = new OnnxruntimeSessionHandler(pathOrBuffer); await handler.loadModel(options || {}); return handler; diff --git a/js/react_native/lib/binding.ts b/js/react_native/lib/binding.ts index afadbab971a5d..5ecf85dcd25ab 100644 --- a/js/react_native/lib/binding.ts +++ b/js/react_native/lib/binding.ts @@ -26,7 +26,14 @@ interface ModelLoadInfo { } /** - * Tensor type for react native, which doesn't allow ArrayBuffer, so data will be encoded as Base64 string. + * JSIBlob is a blob object that exchange ArrayBuffer by OnnxruntimeJSIHelper. + */ +export type JSIBlob = { + blobId: string; offset: number; size: number; +}; + +/** + * Tensor type for react native, which doesn't allow ArrayBuffer in native bridge, so data will be stored as JSIBlob. */ interface EncodedTensor { /** @@ -38,10 +45,10 @@ interface EncodedTensor { */ readonly type: string; /** - * the Base64 encoded string of the buffer data of the tensor. - * if data is string array, it won't be encoded as Base64 string. + * the JSIBlob object of the buffer data of the tensor. + * if data is string array, it won't be stored as JSIBlob. */ - readonly data: string|string[]; + readonly data: JSIBlob|string[]; } /** @@ -64,10 +71,41 @@ export declare namespace Binding { interface InferenceSession { loadModel(modelPath: string, options: SessionOptions): Promise; + loadModelFromBlob?(blob: JSIBlob, options: SessionOptions): Promise; + dispose(key: string): Promise; run(key: string, feeds: FeedsType, fetches: FetchesType, options: RunOptions): Promise; } } // export native binding -const {Onnxruntime} = NativeModules; +const {Onnxruntime, OnnxruntimeJSIHelper} = NativeModules; export const binding = Onnxruntime as Binding.InferenceSession; + +// install JSI helper global functions +OnnxruntimeJSIHelper.install(); + +declare global { + // eslint-disable-next-line no-var + var jsiOnnxruntimeStoreArrayBuffer: ((buffer: ArrayBuffer) => JSIBlob)|undefined; + // eslint-disable-next-line no-var + var jsiOnnxruntimeResolveArrayBuffer: ((blob: JSIBlob) => ArrayBuffer)|undefined; +} + +export const jsiHelper = { + storeArrayBuffer: globalThis.jsiOnnxruntimeStoreArrayBuffer || (() => { + throw new Error( + 'jsiOnnxruntimeStoreArrayBuffer is not found, ' + + 'please make sure OnnxruntimeJSIHelper installation is successful.'); + }), + resolveArrayBuffer: globalThis.jsiOnnxruntimeResolveArrayBuffer || (() => { + throw new Error( + 'jsiOnnxruntimeResolveArrayBuffer is not found, ' + + 'please make sure OnnxruntimeJSIHelper installation is successful.'); + }), +}; + +// Remove global functions after installation +{ + delete globalThis.jsiOnnxruntimeStoreArrayBuffer; + delete globalThis.jsiOnnxruntimeResolveArrayBuffer; +} diff --git a/js/react_native/lib/index.ts b/js/react_native/lib/index.ts index 957b22aab04c4..3bf9da3719e97 100644 --- a/js/react_native/lib/index.ts +++ b/js/react_native/lib/index.ts @@ -2,7 +2,17 @@ // Licensed under the MIT License. export * from 'onnxruntime-common'; -import {registerBackend} from 'onnxruntime-common'; +import {registerBackend, env} from 'onnxruntime-common'; +import {Platform} from 'react-native'; import {onnxruntimeBackend} from './backend'; +import {version} from './version'; registerBackend('cpu', onnxruntimeBackend, 1); +registerBackend('xnnpack', onnxruntimeBackend, 1); +if (Platform.OS === 'android') { + registerBackend('nnapi', onnxruntimeBackend, 1); +} else if (Platform.OS === 'ios') { + registerBackend('coreml', onnxruntimeBackend, 1); +} + +Object.defineProperty(env.versions, 'react-native', {value: version, enumerable: true}); diff --git a/js/react_native/lib/version.ts b/js/react_native/lib/version.ts new file mode 100644 index 0000000000000..96c2361cceabe --- /dev/null +++ b/js/react_native/lib/version.ts @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// This file is generated by /js/scripts/update-version.ts +// Do not modify file content manually. + +export const version = '1.17.0'; diff --git a/js/react_native/onnxruntime-react-native.podspec b/js/react_native/onnxruntime-react-native.podspec index aeb08b336b9a7..914a396be1f1d 100644 --- a/js/react_native/onnxruntime-react-native.podspec +++ b/js/react_native/onnxruntime-react-native.podspec @@ -2,6 +2,9 @@ require "json" package = JSON.parse(File.read(File.join(__dir__, "package.json"))) +# Expect to return the absolute path of the react native root project dir +root_dir = File.dirname(File.dirname(__dir__)) + Pod::Spec.new do |spec| spec.static_framework = true @@ -19,4 +22,22 @@ Pod::Spec.new do |spec| spec.dependency "React-Core" spec.dependency "onnxruntime-c" + + spec.xcconfig = { + 'OTHER_CPLUSPLUSFLAGS' => '-Wall -Wextra', + } + + if (File.exist?(File.join(root_dir, 'package.json'))) + # Read the react native root project directory package.json file + root_package = JSON.parse(File.read(File.join(root_dir, 'package.json'))) + if (root_package["onnxruntimeExtensionsEnabled"] == 'true') + spec.dependency "onnxruntime-extensions-c" + spec.xcconfig = { + 'OTHER_CPLUSPLUSFLAGS' => '-DORT_ENABLE_EXTENSIONS=1 -Wall -Wextra', + } + end + else + puts "Could not find package.json file in the expected directory: #{root_dir}. ONNX Runtime Extensions will not be enabled." + end + end diff --git a/js/react_native/package.json b/js/react_native/package.json index 178b632bcea31..39e6cb08bb06a 100644 --- a/js/react_native/package.json +++ b/js/react_native/package.json @@ -17,7 +17,6 @@ "ONNX Runtime" ], "devDependencies": { - "@types/fs-extra": "^9.0.13", "@types/jest": "^27.4.0", "@types/react": "^18.0.9", "@types/react-native": "^0.67.7", @@ -26,8 +25,7 @@ "prettier": "^2.6.2", "react": "^18.1.0", "react-native": "^0.69.7", - "react-native-builder-bob": "^0.18.2", - "typescript": "^4.9.4" + "react-native-builder-bob": "^0.18.2" }, "peerDependencies": { "react": "*", @@ -38,7 +36,7 @@ "registry": "https://registry.npmjs.org/" }, "source": "lib/index", - "version": "1.15.0", + "version": "1.17.0", "main": "dist/commonjs/index", "homepage": "https://github.com/microsoft/onnxruntime/blob/main/js/react_native/README.md", "files": [ @@ -70,14 +68,15 @@ [ "typescript", { - "project": "tsconfig.build.json" + "project": "tsconfig.build.json", + "tsc": "../node_modules/.bin/tsc" } ] ], "output": "dist" }, "dependencies": { - "@expo/config-plugins": "^4.1.5", + "@expo/config-plugins": "^7.2.4", "buffer": "^6.0.3", "onnxruntime-common": "file:../common" }, diff --git a/js/react_native/scripts/prepack.ts b/js/react_native/scripts/prepack.ts index 15ae69722108c..2e43294165a83 100644 --- a/js/react_native/scripts/prepack.ts +++ b/js/react_native/scripts/prepack.ts @@ -18,7 +18,7 @@ function updatePackageJson() { delete packageSelf.dependencies['onnxruntime-common']; } else { const version = packageCommon.version; - packageSelf.dependencies['onnxruntime-common'] = `~${version}`; + packageSelf.dependencies['onnxruntime-common'] = `${version}`; } fs.writeJSONSync(selfPackageJsonPath, packageSelf, {spaces: 2}); console.log('=== finished updating package.json.'); diff --git a/js/react_native/unimodule.json b/js/react_native/unimodule.json index 0f165fdb6178a..c2bd3c0f071c0 100644 --- a/js/react_native/unimodule.json +++ b/js/react_native/unimodule.json @@ -1,4 +1,4 @@ { - "name": "onnxruntime-react-native", - "platforms": ["ios", "android"] + "name": "onnxruntime-react-native", + "platforms": ["ios", "android"] } diff --git a/js/react_native/yarn.lock b/js/react_native/yarn.lock index d5925f65d2db7..0b47158ab705b 100644 --- a/js/react_native/yarn.lock +++ b/js/react_native/yarn.lock @@ -1235,14 +1235,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@expo/config-plugins@^4.1.5": - version "4.1.5" - resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-4.1.5.tgz#9d357d2cda9c095e511b51583ede8a3b76174068" - integrity sha512-RVvU40RtZt12HavuDAe+LDIq9lHj7sheOfMEHdmpJ/uTA8pgvkbc56XF6JHQD+yRr6+uhhb+JnAasGq49dsQbw== - dependencies: - "@expo/config-types" "^45.0.0" - "@expo/json-file" "8.2.36" - "@expo/plist" "0.0.18" +"@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" @@ -1251,31 +1251,31 @@ getenv "^1.0.0" glob "7.1.6" resolve-from "^5.0.0" - semver "^7.3.5" + semver "^7.5.3" slash "^3.0.0" xcode "^3.0.1" - xml2js "0.4.23" + xml2js "0.6.0" -"@expo/config-types@^45.0.0": - version "45.0.0" - resolved "https://registry.yarnpkg.com/@expo/config-types/-/config-types-45.0.0.tgz#963c2fdce8fbcbd003758b92ed8a25375f437ef6" - integrity sha512-/QGhhLWyaGautgEyU50UJr5YqKJix5t77ePTwreOVAhmZH+ff3nrrtYTTnccx+qF08ZNQmfAyYMCD3rQfzpiJA== +"@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.36": - version "8.2.36" - resolved "https://registry.yarnpkg.com/@expo/json-file/-/json-file-8.2.36.tgz#62a505cb7f30a34d097386476794680a3f7385ff" - integrity sha512-tOZfTiIFA5KmMpdW9KF7bc6CFiGjb0xnbieJhTGlHrLL+ps2G0OkqmuZ3pFEXBOMnJYUVpnSy++52LFxvpa5ZQ== +"@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 "^1.0.1" + json5 "^2.2.2" write-file-atomic "^2.3.0" -"@expo/plist@0.0.18": - version "0.0.18" - resolved "https://registry.yarnpkg.com/@expo/plist/-/plist-0.0.18.tgz#9abcde78df703a88f6d9fa1a557ee2f045d178b0" - integrity sha512-+48gRqUiz65R21CZ/IXa7RNBXgAI/uPSdvJqoN9x1hfL44DNbUoWHgHiEXTx7XelcATpDwNTz6sHLfy0iNqf+w== +"@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.0" + "@xmldom/xmldom" "~0.7.7" base64-js "^1.2.3" xmlbuilder "^14.0.0" @@ -1833,13 +1833,6 @@ dependencies: "@babel/types" "^7.3.0" -"@types/fs-extra@^9.0.13": - version "9.0.13" - resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-9.0.13.tgz#7594fbae04fe7f1918ce8b3d213f74ff44ac1f45" - integrity sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA== - dependencies: - "@types/node" "*" - "@types/graceful-fs@^4.1.2": version "4.1.5" resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" @@ -1939,10 +1932,10 @@ dependencies: "@types/yargs-parser" "*" -"@xmldom/xmldom@~0.7.0": - version "0.7.9" - resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.7.9.tgz#7f9278a50e737920e21b297b8a35286e9942c056" - integrity sha512-yceMpm/xd4W2a85iqZyO09gTnHvXF6pyiWjD2jcOJs7hRoZtNNOO1eJlhHj1ixA+xip2hOyGn+LgcvLCMo5zXA== +"@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== abab@^2.0.3, abab@^2.0.5: version "2.0.6" @@ -4458,18 +4451,16 @@ json-parse-even-better-errors@^2.3.0: 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@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" - integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== - dependencies: - minimist "^1.2.0" - json5@^2.1.3, 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: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + jsonfile@^2.1.0: version "2.4.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" @@ -5197,7 +5188,7 @@ onetime@^5.1.0, onetime@^5.1.2: mimic-fn "^2.1.0" "onnxruntime-common@file:../common": - version "1.15.0" + version "1.17.0" open@^6.2.0: version "6.4.0" @@ -5492,6 +5483,11 @@ punycode@^2.1.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" @@ -5746,6 +5742,11 @@ require-main-filename@^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== +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + resolve-cwd@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" @@ -5885,26 +5886,19 @@ semver@7.0.0: integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== semver@^5.5.0, semver@^5.6.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + 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: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.3.2: - version "7.3.7" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" - integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== - dependencies: - lru-cache "^6.0.0" - -semver@^7.3.5: - version "7.3.8" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" - integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== +semver@^7.3.2, 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" @@ -6361,13 +6355,14 @@ toidentifier@1.0.1: integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== tough-cookie@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" - integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== + version "4.1.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" + integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw== dependencies: psl "^1.1.33" punycode "^2.1.1" - universalify "^0.1.2" + universalify "^0.2.0" + url-parse "^1.5.3" tr46@^2.1.0: version "2.1.0" @@ -6415,11 +6410,6 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" -typescript@^4.9.4: - version "4.9.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.4.tgz#a2a3d2756c079abda241d75f149df9d561091e78" - integrity sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg== - uglify-es@^3.1.9: version "3.3.9" resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677" @@ -6466,11 +6456,16 @@ union-value@^1.0.0: is-extendable "^0.1.1" set-value "^2.0.1" -universalify@^0.1.0, universalify@^0.1.2: +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@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" + integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== + universalify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" @@ -6494,6 +6489,14 @@ urix@^0.1.0: resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= +url-parse@^1.5.3: + version "1.5.10" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" + integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + 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" @@ -6635,9 +6638,9 @@ which@^2.0.1, which@^2.0.2: isexe "^2.0.0" word-wrap@~1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + version "1.2.4" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.4.tgz#cb4b50ec9aca570abd1f52f33cd45b6c61739a9f" + integrity sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA== wrap-ansi@^6.2.0: version "6.2.0" @@ -6706,10 +6709,10 @@ xml-name-validator@^3.0.0: resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== -xml2js@0.4.23: - version "0.4.23" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" - integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== +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" diff --git a/js/scripts/prepare-onnx-node-tests.ts b/js/scripts/prepare-onnx-node-tests.ts index 1a3595702ceb5..64d6eb6648cfd 100644 --- a/js/scripts/prepare-onnx-node-tests.ts +++ b/js/scripts/prepare-onnx-node-tests.ts @@ -10,6 +10,7 @@ import * as path from 'path'; import {downloadZip, extractFile} from './utils'; const TEST_DATA_OPSET_VERSIONS = [ + ['opset19', '1.14.0'], ['opset18', '1.13.1'], ['opset17', '1.12.1'], ['opset16', '1.11.0'], diff --git a/js/scripts/update-version.ts b/js/scripts/update-version.ts new file mode 100644 index 0000000000000..df6a9ea334db5 --- /dev/null +++ b/js/scripts/update-version.ts @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// This script update source file "version.ts" under the following folders: +// /js/${arg0}/lib/version.ts +// +// version data is read from file /js/${arg0}/package.json + +import fs from 'fs-extra'; +import path from 'path'; + +const packageName = process.argv[2]; +if (['common', 'web', 'node', 'react_native'].indexOf(packageName) === -1) { + throw new Error('expect arg0 to be one of: common,web,node,react_native'); +} + +const PACKAGE_JSON_FILE = path.join(__dirname, '..', packageName, 'package.json'); +const version = JSON.parse(fs.readFileSync(PACKAGE_JSON_FILE).toString()).version; + +if (typeof version !== 'string') { + throw new Error(`failed to parse "version" from file: ${PACKAGE_JSON_FILE}`); +} + +const FILE_CONTENT = `// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// This file is generated by /js/scripts/update-version.ts +// Do not modify file content manually. + +export const version = ${JSON.stringify(version)}; +`; + +fs.writeFileSync(path.join(__dirname, '..', packageName, 'lib', 'version.ts'), FILE_CONTENT); diff --git a/js/tsconfig.json b/js/tsconfig.json index dfee3c056716c..d199cb9d0a6f5 100644 --- a/js/tsconfig.json +++ b/js/tsconfig.json @@ -2,7 +2,6 @@ "compilerOptions": { "module": "ES2015", "moduleResolution": "node16", - "declaration": true, "esModuleInterop": true, "target": "ES2020", "lib": ["ES2020", "ESNext.BigInt", "dom"], diff --git a/js/web/.gitignore b/js/web/.gitignore index 438068ff32c70..5b9e31ad5e169 100644 --- a/js/web/.gitignore +++ b/js/web/.gitignore @@ -15,6 +15,8 @@ test/**/*.js.map script/**/*.js script/**/*.js.map +!/types.d.ts + lib/wasm/binding/**/*.wasm !lib/wasm/binding/**/*.d.ts diff --git a/js/web/.npmignore b/js/web/.npmignore index e21a906c9abd6..8e08db5917149 100644 --- a/js/web/.npmignore +++ b/js/web/.npmignore @@ -4,8 +4,7 @@ /dist/**/*.report.html -/types/**/*.d.ts -!/types/lib/**/*.d.ts +/types/ karma.conf.js tsconfig.json diff --git a/js/web/README.md b/js/web/README.md index 9ab9a7dac76aa..c75a40ad6da28 100644 --- a/js/web/README.md +++ b/js/web/README.md @@ -50,7 +50,11 @@ ONNX Runtime Web currently support all operators in [ai.onnx](https://github.com #### WebGL backend -ONNX Runtime Web currently supports a subset of operators in [ai.onnx](https://github.com/onnx/onnx/blob/main/docs/Operators.md) operator set. See [operators.md](./docs/operators.md) for a complete, detailed list of which ONNX operators are supported by WebGL backend. +ONNX Runtime Web currently supports a subset of operators in [ai.onnx](https://github.com/onnx/onnx/blob/main/docs/Operators.md) operator set. See [webgl-operators.md](./docs/webgl-operators.md) for a complete, detailed list of which ONNX operators are supported by WebGL backend. + +#### WebGPU backend + +WebGPU backend is still an experimental feature. See [webgpu-operators.md](./docs/webgpu-operators.md) for a detailed list of which ONNX operators are supported by WebGPU backend. ## License diff --git a/js/web/docs/operators.md b/js/web/docs/webgl-operators.md similarity index 94% rename from js/web/docs/operators.md rename to js/web/docs/webgl-operators.md index 115884cb9d97c..de84134ddbb3f 100644 --- a/js/web/docs/operators.md +++ b/js/web/docs/webgl-operators.md @@ -19,7 +19,7 @@ See [Compatibility](../README.md#Compatibility) for a list of the supported plat | [Asinh](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Asinh) | | | [Atan](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Atan) | [7+](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Atan-7) | | [Atanh](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Atanh) | | -| [AveragePool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#AveragePool) | [7-9](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#AveragePool-7), [10](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#AveragePool-10), [11+](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#AveragePool-11) | +| [AveragePool](https://github.com/onnx/onnx/blob/main/docs/Operators.md#AveragePool) | [7-9](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#AveragePool-7), [10](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#AveragePool-10), [11-18](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#AveragePool-11), [19+](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#AveragePool-19) | | [BatchNormalization](https://github.com/onnx/onnx/blob/main/docs/Operators.md#BatchNormalization) | [7-8](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#BatchNormalization-7), [9-13](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#BatchNormalization-9), [14](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#BatchNormalization-14), [15+](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#BatchNormalization-15) | | [Bernoulli](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Bernoulli) | | | [BitShift](https://github.com/onnx/onnx/blob/main/docs/Operators.md#BitShift) | | @@ -28,7 +28,7 @@ See [Compatibility](../README.md#Compatibility) for a list of the supported plat | [BitwiseOr](https://github.com/onnx/onnx/blob/main/docs/Operators.md#BitwiseOr) | | | [BitwiseXor](https://github.com/onnx/onnx/blob/main/docs/Operators.md#BitwiseXor) | | | [BlackmanWindow](https://github.com/onnx/onnx/blob/main/docs/Operators.md#BlackmanWindow) | | -| [Cast](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Cast) | [6-8](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Cast-6), [9-12](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Cast-9), [13+](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Cast-13) | +| [Cast](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Cast) | [6-8](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Cast-6), [9-12](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Cast-9), [13-18](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Cast-13), [19+](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Cast-19) | | [CastLike](https://github.com/onnx/onnx/blob/main/docs/Operators.md#CastLike) | | | [Ceil](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Ceil) | [6-12](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Ceil-6), [13+](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Ceil-13) | | [Celu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Celu) | | @@ -47,6 +47,7 @@ See [Compatibility](../README.md#Compatibility) for a list of the supported plat | [Cosh](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Cosh) | | | [CumSum](https://github.com/onnx/onnx/blob/main/docs/Operators.md#CumSum) | | | [DFT](https://github.com/onnx/onnx/blob/main/docs/Operators.md#DFT) | | +| [DeformConv](https://github.com/onnx/onnx/blob/main/docs/Operators.md#DeformConv) | | | [DepthToSpace](https://github.com/onnx/onnx/blob/main/docs/Operators.md#DepthToSpace) | [1-10](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#DepthToSpace-1), [11-12](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#DepthToSpace-11), [13+](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#DepthToSpace-13) | | [DequantizeLinear](https://github.com/onnx/onnx/blob/main/docs/Operators.md#DequantizeLinear) | | | [Det](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Det) | | @@ -55,7 +56,7 @@ See [Compatibility](../README.md#Compatibility) for a list of the supported plat | [DynamicQuantizeLinear](https://github.com/onnx/onnx/blob/main/docs/Operators.md#DynamicQuantizeLinear) | | | [Einsum](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Einsum) | | | [Elu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Elu) | [6+](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Elu-6) | -| [Equal](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Equal) | [7-10](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Equal-7), [11-12](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Equal-11), [13+](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Equal-13) | +| [Equal](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Equal) | [7-10](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Equal-7), [11-12](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Equal-11), [13-18](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Equal-13), [19+](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Equal-19) | | [Erf](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Erf) | | | [Exp](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Exp) | [6-12](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Exp-6), [13+](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Exp-13) | | [Expand](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Expand) | | @@ -79,7 +80,7 @@ See [Compatibility](../README.md#Compatibility) for a list of the supported plat | [HardSigmoid](https://github.com/onnx/onnx/blob/main/docs/Operators.md#HardSigmoid) | | | [HardSwish](https://github.com/onnx/onnx/blob/main/docs/Operators.md#HardSwish) | | | [Hardmax](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Hardmax) | | -| [Identity](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Identity) | [1-12](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Identity-1), [13](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Identity-13), [14-15](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Identity-14), [16+](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Identity-16) | +| [Identity](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Identity) | [1-12](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Identity-1), [13](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Identity-13), [14-15](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Identity-14), [16-18](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Identity-16), [19+](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Identity-19) | | [If](https://github.com/onnx/onnx/blob/main/docs/Operators.md#If) | | | [InstanceNormalization](https://github.com/onnx/onnx/blob/main/docs/Operators.md#InstanceNormalization) | [6+](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#InstanceNormalization-6) | | [IsInf](https://github.com/onnx/onnx/blob/main/docs/Operators.md#IsInf) | | @@ -120,7 +121,7 @@ See [Compatibility](../README.md#Compatibility) for a list of the supported plat | [OptionalHasElement](https://github.com/onnx/onnx/blob/main/docs/Operators.md#OptionalHasElement) | | | [Or](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Or) | [7+](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Or-7) | | [PRelu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#PRelu) | [7-8](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#PRelu-7), [9-15](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#PRelu-9), [16+](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#PRelu-16) | -| [Pad](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Pad) | [2-10](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Pad-2), [11-12](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Pad-11), [13-17](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Pad-13), [18+](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Pad-18) | +| [Pad](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Pad) | [2-10](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Pad-2), [11-12](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Pad-11), [13-17](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Pad-13), [18](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Pad-18), [19+](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Pad-19) | | [Pow](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Pow) | [7-11](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Pow-7), [12](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Pow-12), [13-14](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Pow-13), [15+](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Pow-15) | | [QLinearConv](https://github.com/onnx/onnx/blob/main/docs/Operators.md#QLinearConv) | | | [QLinearMatMul](https://github.com/onnx/onnx/blob/main/docs/Operators.md#QLinearMatMul) | | @@ -143,8 +144,8 @@ See [Compatibility](../README.md#Compatibility) for a list of the supported plat | [ReduceSum](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceSum) | [1-10](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#ReduceSum-1), [11-12](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#ReduceSum-11) | | [ReduceSumSquare](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReduceSumSquare) | [1-10](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#ReduceSumSquare-1), [11-12](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#ReduceSumSquare-11), [13-17](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#ReduceSumSquare-13), [18+](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#ReduceSumSquare-18) | | [Relu](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Relu) | [6-12](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Relu-6), [13](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Relu-13), [14+](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Relu-14) | -| [Reshape](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Reshape) | [5-12](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Reshape-5), [13](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Reshape-13), [14+](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Reshape-14) | -| [Resize](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Resize) | [10](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Resize-10), [11-12](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Resize-11), [13-17](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Resize-13), [18+](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Resize-18) | +| [Reshape](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Reshape) | [5-12](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Reshape-5), [13](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Reshape-13), [14-18](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Reshape-14), [19+](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Reshape-19) | +| [Resize](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Resize) | [10](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Resize-10), [11-12](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Resize-11), [13-17](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Resize-13), [18](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Resize-18), [19+](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Resize-19) | | [ReverseSequence](https://github.com/onnx/onnx/blob/main/docs/Operators.md#ReverseSequence) | | | [RoiAlign](https://github.com/onnx/onnx/blob/main/docs/Operators.md#RoiAlign) | | | [Round](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Round) | | @@ -161,7 +162,7 @@ See [Compatibility](../README.md#Compatibility) for a list of the supported plat | [SequenceInsert](https://github.com/onnx/onnx/blob/main/docs/Operators.md#SequenceInsert) | | | [SequenceLength](https://github.com/onnx/onnx/blob/main/docs/Operators.md#SequenceLength) | | | [SequenceMap](https://github.com/onnx/onnx/blob/main/docs/Operators.md#SequenceMap) | | -| [Shape](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Shape) | [1-12](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Shape-1), [13-14](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Shape-13), [15+](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Shape-15) | +| [Shape](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Shape) | [1-12](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Shape-1), [13-14](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Shape-13), [15-18](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Shape-15), [19+](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Shape-19) | | [Shrink](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Shrink) | | | [Sigmoid](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Sigmoid) | [6-12](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Sigmoid-6), [13+](https://github.com/onnx/onnx/blob/main/docs/Changelog.md#Sigmoid-13) | | [Sign](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Sign) | | diff --git a/js/web/docs/webgpu-operators.md b/js/web/docs/webgpu-operators.md new file mode 100644 index 0000000000000..a87a894e3b3c5 --- /dev/null +++ b/js/web/docs/webgpu-operators.md @@ -0,0 +1,95 @@ +## Operators Support Table + +The following table shows ONNX +operators and the supported opset domain/versions in WebGPU EP by ONNX Runtime Web. For example, +`4-6, 8+` means ONNX Runtime Web currently support opset version 4 to 6, 8 and above. + +*This file is automatically generated from the +def files via [this script](../script/generate-webgpu-operator-md.ts). +Do not modify directly.* + +| Operator | Opset | Comments | +|:--------:|:-------------:|-----| +| Abs | ai.onnx(6-12,13+) | | +| Acos | ai.onnx(7+) | | +| Acosh | ai.onnx(9+) | | +| Add | ai.onnx(7-12,13,14+) | | +| ArgMax | ai.onnx(1-10,11-12,13+) | | +| ArgMin | ai.onnx(1-10,11-12,13+) | | +| Asin | ai.onnx(7+) | | +| Asinh | ai.onnx(9+) | | +| Atan | ai.onnx(7+) | | +| Atanh | ai.onnx(9+) | | +| AveragePool | ai.onnx(7-9,10,11+); com.ms.internal.nhwc(11+) | need perf optimization; need implementing activation | +| Cast | ai.onnx(6-8,9-12,13-18,19+) | | +| Ceil | ai.onnx(6-12,13+) | | +| Clip | ai.onnx(6-10,11,12,13+) | | +| Concat | ai.onnx(1-3,4-10,11-12,13+) | | +| Conv | ai.onnx(1-10,11+); com.ms.internal.nhwc(11+) | need perf optimization; conv3d is not supported; need implementing activation | +| ConvTranspose | ai.onnx(1-10,11+); com.ms.internal.nhwc(11+) | need perf optimization; ConvTranspose3d is not supported; need implementing activation | +| Cos | ai.onnx(7+) | | +| Cosh | ai.onnx(9+) | | +| Div | ai.onnx(7-12,13,14+) | | +| Einsum | ai.onnx(12+) | | +| Elu | ai.onnx(6+) | | +| Equal | ai.onnx(7-10,11-12,13-18,19+) | | +| Erf | ai.onnx(9-12,13+) | | +| Exp | ai.onnx(6-12,13+) | | +| Expand | ai.onnx(8-12,13+) | | +| Flatten | ai.onnx(1-8,9-10,11-12,13+) | | +| Floor | ai.onnx(6-12,13+) | | +| Gather | ai.onnx(1-10,11-12,13+) | | +| GatherElements | ai.onnx(11-12,13+) | | +| Gelu | com.microsoft(1+) | | +| Gemm | ai.onnx(7-8,9-10,11-12,13+) | | +| GlobalAveragePool | ai.onnx(1+); com.ms.internal.nhwc(1+) | | +| GlobalMaxPool | ai.onnx(1+); com.ms.internal.nhwc(1+) | | +| Greater | ai.onnx(7-8,9-12,13+) | | +| GreaterOrEqual | ai.onnx(12-15,16+) | | +| If | ai.onnx(1-10,11-12,13-18,19+) | | +| InstanceNormalization | ai.onnx(6+); com.ms.internal.nhwc(6+) | | +| LayerNormalization | ai.onnx(17+) | | +| LeakyRelu | ai.onnx(6-15,16+) | | +| Less | ai.onnx(7-8,9-12,13+) | | +| LessOrEqual | ai.onnx(12-15,16+) | | +| Log | ai.onnx(6-12,13+) | | +| MatMul | ai.onnx(1-12,13+) | | +| MaxPool | ai.onnx(1-7,8-9,10,11,12+); com.ms.internal.nhwc(11,12+) | need perf optimization; need implementing activation | +| MemcpyFromHost | ai.onnx(1+) | | +| MemcpyToHost | ai.onnx(1+) | | +| Mul | ai.onnx(7-12,13,14+) | | +| Neg | ai.onnx(6-12,13+) | | +| Not | ai.onnx(1+) | | +| Pad | ai.onnx(2-10,11-12,13-17,18,19+) | | +| Pow | ai.onnx(7-11,12,13-14,15+) | | +| Reciprocal | ai.onnx(6-12,13+) | | +| ReduceL1 | ai.onnx(1-10,11-12,13-17,18+) | | +| ReduceL2 | ai.onnx(1-10,11-12,13-17,18+) | | +| ReduceLogSum | ai.onnx(1-10,11-12,13-17,18+) | | +| ReduceLogSumExp | ai.onnx(1-10,11-12,13-17,18+) | | +| ReduceMax | ai.onnx(1-10,11,12,13-17,18+) | | +| ReduceMean | ai.onnx(1-10,11-12,13-17,18+) | | +| ReduceMin | ai.onnx(1-10,11,12,13-17,18+) | | +| ReduceProd | ai.onnx(1-10,11-12,13-17,18+) | | +| ReduceSum | ai.onnx(1-10,11-12,13+) | | +| ReduceSumSquare | ai.onnx(1-10,11-12,13-17,18+) | | +| Relu | ai.onnx(6-12,13,14+) | | +| Reshape | ai.onnx(5-12,13,14+) | no GPU kernel | +| Resize | ai.onnx(10,11-12,13-17,18,19+); com.ms.internal.nhwc(11-12,13-17,18,19+) | CoordinateTransformMode align_corners is not supported with downsampling | +| Shape | ai.onnx(1-12,13-14,15+) | no GPU kernel; an ORT warning is generated - need to fix | +| Sigmoid | ai.onnx(6-12,13+) | | +| Sin | ai.onnx(7+) | | +| Sinh | ai.onnx(9+) | | +| SkipLayerNormalization | com.microsoft(1+) | | +| Slice | ai.onnx(1-9,10,11-12,13+) | | +| Softmax | ai.onnx(1-10,11-12,13+) | | +| Split | ai.onnx(1,2-10,11-12,13-17,18+) | | +| Sqrt | ai.onnx(6-12,13+) | | +| Squeeze | ai.onnx(1-10,11-12,13+) | | +| Sub | ai.onnx(7-12,13,14+) | | +| Tan | ai.onnx(7+) | | +| Tanh | ai.onnx(6-12,13+) | | +| ThresholdedRelu | ai.onnx(10+) | | +| Tile | ai.onnx(6-12,13+) | | +| Transpose | ai.onnx(1-12,13+) | need perf optimization | +| Unsqueeze | ai.onnx(1-10,11-12,13+) | | diff --git a/js/web/karma.conf.js b/js/web/karma.conf.js index 2a4e71e064632..35f782d1fdca3 100644 --- a/js/web/karma.conf.js +++ b/js/web/karma.conf.js @@ -3,10 +3,22 @@ 'use strict'; -const bundleMode = require('minimist')(process.argv)['bundle-mode'] || 'dev'; // 'dev'|'perf'|undefined; -const karmaPlugins = require('minimist')(process.argv)['karma-plugins'] || undefined; -const timeoutMocha = require('minimist')(process.argv)['timeout-mocha'] || 60000; -const forceLocalHost = !!require('minimist')(process.argv)['force-localhost']; +const args = require('minimist')(process.argv, {}); +const bundleMode = args['bundle-mode'] || 'dev'; // 'dev'|'perf'|undefined; +const karmaPlugins = args['karma-plugins'] || undefined; +const timeoutMocha = args['timeout-mocha'] || 60000; +const forceLocalHost = !!args['force-localhost']; + +// parse chromium flags +let chromiumFlags = args['chromium-flags']; +if (!chromiumFlags) { + chromiumFlags = []; +} else if (typeof chromiumFlags === 'string') { + chromiumFlags = [chromiumFlags]; +} else if (!Array.isArray(chromiumFlags)) { + throw new Error(`Invalid command line arg: --chromium-flags: ${chromiumFlags}`); +} + const commonFile = bundleMode === 'dev' ? '../common/dist/ort-common.js' : '../common/dist/ort-common.min.js' const mainFile = bundleMode === 'dev' ? 'test/ort.dev.js' : 'test/ort.perf.js'; @@ -43,7 +55,7 @@ const hostname = getMachineIpAddress(); // In Node.js v17+, 'localhost' is using IPv6, so need to listen to '::' const listenAddress = Number.parseInt(process.versions.node.split('.')[0]) >= 17 ? '::' : '0.0.0.0'; -module.exports = function (config) { +module.exports = function(config) { config.set({ // global config of your BrowserStack account browserStack: { @@ -55,26 +67,30 @@ module.exports = function (config) { }, frameworks: ['mocha'], files: [ - { pattern: commonFile }, - { pattern: mainFile }, - { pattern: 'test/testdata-file-cache-*.json', included: false }, - { pattern: 'test/data/**/*', included: false, nocache: true }, - { pattern: 'dist/ort-wasm.wasm', included: false }, - { pattern: 'dist/ort-wasm-threaded.wasm', included: false }, - { pattern: 'dist/ort-wasm-simd.wasm', included: false }, - { pattern: 'dist/ort-wasm-simd-threaded.wasm', included: false }, - { pattern: 'dist/ort-wasm-threaded.worker.js', included: false }, + {pattern: commonFile}, + {pattern: mainFile}, + {pattern: 'test/testdata-file-cache-*.json', included: false}, + {pattern: 'test/data/**/*', included: false, nocache: true}, + {pattern: 'dist/ort-wasm.wasm', included: false}, + {pattern: 'dist/ort-wasm-threaded.wasm', included: false}, + {pattern: 'dist/ort-wasm-simd.wasm', included: false}, + {pattern: 'dist/ort-wasm-simd-threaded.wasm', included: false}, + {pattern: 'dist/ort-wasm-simd.jsep.wasm', included: false}, + {pattern: 'dist/ort-wasm-simd-threaded.jsep.wasm', included: false}, + {pattern: 'dist/ort-wasm-threaded.worker.js', included: false}, ], proxies: { '/base/test/ort-wasm.wasm': '/base/dist/ort-wasm.wasm', '/base/test/ort-wasm-threaded.wasm': '/base/dist/ort-wasm-threaded.wasm', '/base/test/ort-wasm-simd.wasm': '/base/dist/ort-wasm-simd.wasm', '/base/test/ort-wasm-simd-threaded.wasm': '/base/dist/ort-wasm-simd-threaded.wasm', + '/base/test/ort-wasm-simd.jsep.wasm': '/base/dist/ort-wasm-simd.jsep.wasm', + '/base/test/ort-wasm-simd-threaded.jsep.wasm': '/base/dist/ort-wasm-simd-threaded.jsep.wasm', '/base/test/ort-wasm-threaded.worker.js': '/base/dist/ort-wasm-threaded.worker.js', }, plugins: karmaPlugins, - client: { captureConsole: true, mocha: { expose: ['body'], timeout: timeoutMocha } }, - preprocessors: { mainFile: ['sourcemap'] }, + client: {captureConsole: true, mocha: {expose: ['body'], timeout: timeoutMocha}}, + preprocessors: {mainFile: ['sourcemap']}, reporters: ['mocha', 'BrowserStack'], browsers: [], captureTimeout: 120000, @@ -86,98 +102,44 @@ module.exports = function (config) { hostname, listenAddress, customLaunchers: { - ChromeTest: { base: 'ChromeHeadless', flags: ['--enable-features=SharedArrayBuffer'] }, - ChromePerf: { base: 'Chrome', flags: ['--window-size=1,1', '--enable-features=SharedArrayBuffer'] }, - ChromeDebug: { debug: true, base: 'Chrome', flags: ['--remote-debugging-port=9333', '--enable-features=SharedArrayBuffer'] }, - ChromeCanaryTest: { base: 'ChromeCanary', flags: ['--window-size=1,1', '--enable-features=SharedArrayBuffer', '--enable-unsafe-webgpu'] }, - ChromeCanaryProfileTest: { base: 'ChromeCanary', flags: ['--window-size=1,1', '--enable-features=SharedArrayBuffer', '--enable-unsafe-webgpu', '--disable-dawn-features=disallow_unsafe_apis'] }, - ChromeCanaryDebug: { debug: true, base: 'ChromeCanary', flags: ['--remote-debugging-port=9333', '--enable-features=SharedArrayBuffer', '--enable-unsafe-webgpu'] }, - ChromeCanaryProfileDebug: { debug: true, base: 'ChromeCanary', flags: ['--remote-debugging-port=9333', '--enable-features=SharedArrayBuffer', '--enable-unsafe-webgpu', '--disable-dawn-features=disallow_unsafe_apis'] }, + // the following flags are used to make sure Edge on CI agents to initialize WebGPU correctly. + EdgeTest: {base: 'Edge', flags: chromiumFlags}, + ChromeTest: {base: 'Chrome', flags: chromiumFlags}, + ChromeTestHeadless: {base: 'ChromeHeadless', flags: chromiumFlags}, + ChromeCanaryTest: {base: 'ChromeCanary', flags: chromiumFlags}, // // ==== BrowserStack browsers ==== // // Windows // - BS_WIN_10_Chrome_91: { - base: 'BrowserStack', - os: 'Windows', - os_version: '10', - browser: 'Chrome', - browser_version: '91' - }, - BS_WIN_10_Edge_91: { - base: 'BrowserStack', - os: 'Windows', - os_version: '10', - browser: 'Edge', - browser_version: '91' - }, - BS_WIN_10_Firefox_89: { - base: 'BrowserStack', - os: 'Windows', - os_version: '10', - browser: 'Firefox', - browser_version: '89' - }, + BS_WIN_10_Chrome_91: + {base: 'BrowserStack', os: 'Windows', os_version: '10', browser: 'Chrome', browser_version: '91'}, + BS_WIN_10_Edge_91: + {base: 'BrowserStack', os: 'Windows', os_version: '10', browser: 'Edge', browser_version: '91'}, + BS_WIN_10_Firefox_89: + {base: 'BrowserStack', os: 'Windows', os_version: '10', browser: 'Firefox', browser_version: '89'}, // macOS // - BS_MAC_11_Safari_14: { - base: 'BrowserStack', - os: 'OS X', - os_version: 'Big Sur', - browser: 'Safari', - browser_version: '14.0' - }, - BS_MAC_11_Chrome_91: { - base: 'BrowserStack', - os: 'OS X', - os_version: 'Big Sur', - browser: 'Chrome', - browser_version: '91' - }, + BS_MAC_11_Safari_14: + {base: 'BrowserStack', os: 'OS X', os_version: 'Big Sur', browser: 'Safari', browser_version: '14.0'}, + BS_MAC_11_Chrome_91: + {base: 'BrowserStack', os: 'OS X', os_version: 'Big Sur', browser: 'Chrome', browser_version: '91'}, // iPhone // - BS_IOS_14_iPhoneXS: { - base: 'BrowserStack', - device: 'iPhone XS', - real_mobile: true, - os: 'ios', - os_version: '14' - }, - BS_IOS_13_iPhoneXS: { - base: 'BrowserStack', - device: 'iPhone XS', - real_mobile: true, - os: 'ios', - os_version: '13' - }, + BS_IOS_14_iPhoneXS: {base: 'BrowserStack', device: 'iPhone XS', real_mobile: true, os: 'ios', os_version: '14'}, + BS_IOS_13_iPhoneXS: {base: 'BrowserStack', device: 'iPhone XS', real_mobile: true, os: 'ios', os_version: '13'}, // Android // - BS_ANDROID_11_Pixel_5: { - base: 'BrowserStack', - device: 'Google Pixel 5', - real_mobile: true, - os: 'android', - os_version: '11.0' - }, - BS_ANDROID_11_Galaxy_S_21: { - base: 'BrowserStack', - device: 'Samsung Galaxy S21', - real_mobile: true, - os: 'android', - os_version: '11.0' - }, - BS_ANDROID_10_Pixel_4: { - base: 'BrowserStack', - device: 'Google Pixel 4', - real_mobile: true, - os: 'android', - os_version: '10.0' - } + BS_ANDROID_11_Pixel_5: + {base: 'BrowserStack', device: 'Google Pixel 5', real_mobile: true, os: 'android', os_version: '11.0'}, + BS_ANDROID_11_Galaxy_S_21: + {base: 'BrowserStack', device: 'Samsung Galaxy S21', real_mobile: true, os: 'android', os_version: '11.0'}, + BS_ANDROID_10_Pixel_4: + {base: 'BrowserStack', device: 'Google Pixel 4', real_mobile: true, os: 'android', os_version: '10.0'} } }); }; diff --git a/js/web/lib/backend-wasm.ts b/js/web/lib/backend-wasm.ts index 961b331d7786e..ceb20044d97b6 100644 --- a/js/web/lib/backend-wasm.ts +++ b/js/web/lib/backend-wasm.ts @@ -4,7 +4,7 @@ import {Backend, env, InferenceSession, SessionHandler} from 'onnxruntime-common'; import {cpus} from 'os'; -import {initWasm} from './wasm/proxy-wrapper'; +import {initializeWebAssemblyInstance} from './wasm/proxy-wrapper'; import {OnnxruntimeWebAssemblySessionHandler} from './wasm/session-handler'; /** @@ -38,7 +38,7 @@ class OnnxruntimeWebAssemblyBackend implements Backend { initializeFlags(); // init wasm - await initWasm(); + await initializeWebAssemblyInstance(); } createSessionHandler(path: string, options?: InferenceSession.SessionOptions): Promise; createSessionHandler(buffer: Uint8Array, options?: InferenceSession.SessionOptions): Promise; diff --git a/js/web/lib/index.ts b/js/web/lib/index.ts index 749331058cc4a..d5ed536034f3e 100644 --- a/js/web/lib/index.ts +++ b/js/web/lib/index.ts @@ -7,7 +7,8 @@ // So we import code inside the if-clause to allow terser remove the code safely. export * from 'onnxruntime-common'; -import {registerBackend} from 'onnxruntime-common'; +import {registerBackend, env} from 'onnxruntime-common'; +import {version} from './version'; if (!BUILD_DEFS.DISABLE_WEBGL) { const onnxjsBackend = require('./backend-onnxjs').onnxjsBackend; @@ -16,10 +17,13 @@ if (!BUILD_DEFS.DISABLE_WEBGL) { if (!BUILD_DEFS.DISABLE_WASM) { const wasmBackend = require('./backend-wasm').wasmBackend; - if (!BUILD_DEFS.DISABLE_WEBGPU) { + if (!BUILD_DEFS.DISABLE_WEBGPU && typeof navigator !== 'undefined' && navigator.gpu) { registerBackend('webgpu', wasmBackend, 5); } registerBackend('cpu', wasmBackend, 10); registerBackend('wasm', wasmBackend, 10); registerBackend('xnnpack', wasmBackend, 9); + registerBackend('webnn', wasmBackend, 9); } + +Object.defineProperty(env.versions, 'web', {value: version, enumerable: true}); diff --git a/js/web/lib/onnxjs/attribute.ts b/js/web/lib/onnxjs/attribute.ts index 4379422666c7b..9abdb2943a552 100644 --- a/js/web/lib/onnxjs/attribute.ts +++ b/js/web/lib/onnxjs/attribute.ts @@ -2,9 +2,9 @@ // Licensed under the MIT License. import Long from 'long'; -import {onnx} from 'onnx-proto'; -import {onnxruntime} from './ort-schema/ort-generated'; +import {onnxruntime} from './ort-schema/flatbuffers/ort-generated'; +import {onnx} from './ort-schema/protobuf/onnx'; import {Tensor} from './tensor'; import {decodeUtf8String, LongUtil} from './util'; diff --git a/js/web/lib/onnxjs/backends/backend-webgl.ts b/js/web/lib/onnxjs/backends/backend-webgl.ts index cc00b8be809e4..74716ca0edcb3 100644 --- a/js/web/lib/onnxjs/backends/backend-webgl.ts +++ b/js/web/lib/onnxjs/backends/backend-webgl.ts @@ -72,6 +72,8 @@ export class WebGLBackend implements Backend { Logger.setWithEnv(env); + Object.defineProperty(env.webgl, 'context', {value: this.glContext.gl}); + Logger.verbose( 'WebGLBackend', `Created WebGLContext: ${typeof this.glContext} with matmulMaxBatchSize: ${ diff --git a/js/web/lib/onnxjs/backends/webgl/webgl-context-factory.ts b/js/web/lib/onnxjs/backends/webgl/webgl-context-factory.ts index e2b060955beb3..6bf12500ec8b5 100644 --- a/js/web/lib/onnxjs/backends/webgl/webgl-context-factory.ts +++ b/js/web/lib/onnxjs/backends/webgl/webgl-context-factory.ts @@ -20,7 +20,18 @@ export function createWebGLContext(contextId?: 'webgl'|'webgl2'): WebGLContext { context = cache.webgl; } - context = context || createNewWebGLContext(contextId); + if (!context) { + try { + // try to create webgl context from an offscreen canvas + const offscreenCanvas = createOffscreenCanvas(); + context = createNewWebGLContext(offscreenCanvas, contextId); + } catch (e) { + // if failed, fallback to try to use a normal canvas element + const canvas = createCanvas(); + context = createNewWebGLContext(canvas, contextId); + } + } + contextId = contextId || context.version === 1 ? 'webgl' : 'webgl2'; const gl = context.gl; @@ -44,8 +55,7 @@ export function createWebGLContext(contextId?: 'webgl'|'webgl2'): WebGLContext { return context; } -export function createNewWebGLContext(contextId?: 'webgl'|'webgl2'): WebGLContext { - const canvas = createCanvas(); +export function createNewWebGLContext(canvas: HTMLCanvasElement, contextId?: 'webgl'|'webgl2'): WebGLContext { const contextAttributes: WebGLContextAttributes = { alpha: false, depth: false, @@ -88,13 +98,17 @@ declare let OffscreenCanvas: {new (width: number, height: number): HTMLCanvasEle function createCanvas(): HTMLCanvasElement { if (typeof document === 'undefined') { - if (typeof OffscreenCanvas === 'undefined') { - throw new TypeError('failed to create canvas: OffscreenCanvas is not supported'); - } - return new OffscreenCanvas(1, 1); + throw new TypeError('failed to create canvas: document is not supported'); } const canvas: HTMLCanvasElement = document.createElement('canvas'); canvas.width = 1; canvas.height = 1; return canvas; } + +function createOffscreenCanvas(): HTMLCanvasElement { + if (typeof OffscreenCanvas === 'undefined') { + throw new TypeError('failed to create offscreen canvas: OffscreenCanvas is not supported'); + } + return new OffscreenCanvas(1, 1); +} diff --git a/js/web/lib/onnxjs/graph.ts b/js/web/lib/onnxjs/graph.ts index e9497cd8b364e..f16da42815957 100644 --- a/js/web/lib/onnxjs/graph.ts +++ b/js/web/lib/onnxjs/graph.ts @@ -1,10 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import {onnx} from 'onnx-proto'; - import {Attribute} from './attribute'; -import {onnxruntime} from './ort-schema/ort-generated'; +import {onnxruntime} from './ort-schema/flatbuffers/ort-generated'; +import {onnx} from './ort-schema/protobuf/onnx'; import {Tensor} from './tensor'; import {LongUtil, MAX_CLIP, MIN_CLIP, ProtoUtil} from './util'; @@ -333,8 +332,9 @@ class GraphImpl implements Graph, Graph.Transformer { for (const input of nodeProto.input) { const dataIndex = dataIndices.get(input); if (typeof dataIndex === 'undefined') { - // handle exception when opset > 9 and roi not given - if (input === '' && nodeProto.input.length === 3 && nodeProto.opType === 'Resize') { + // handle exception when opset > 9 and roi / scales not given + if (input === '' && (nodeProto.input.length === 3 || nodeProto.input.length === 4) && + nodeProto.opType === 'Resize') { continue; } throw new Error(`unrecognized input '${input}' for node: ${nodeProto.name}`); diff --git a/js/web/lib/onnxjs/model.ts b/js/web/lib/onnxjs/model.ts index b7a5fda996a7b..f9a1b6e76089d 100644 --- a/js/web/lib/onnxjs/model.ts +++ b/js/web/lib/onnxjs/model.ts @@ -2,11 +2,11 @@ // Licensed under the MIT License. import {flatbuffers} from 'flatbuffers'; -import {onnx} from 'onnx-proto'; import {Graph} from './graph'; import {OpSet} from './opset'; -import {onnxruntime} from './ort-schema/ort-generated'; +import {onnxruntime} from './ort-schema/flatbuffers/ort-generated'; +import {onnx} from './ort-schema/protobuf/onnx'; import {LongUtil} from './util'; import ortFbs = onnxruntime.experimental.fbs; diff --git a/js/web/lib/onnxjs/ort-schema/README.md b/js/web/lib/onnxjs/ort-schema/flatbuffers/README.md similarity index 99% rename from js/web/lib/onnxjs/ort-schema/README.md rename to js/web/lib/onnxjs/ort-schema/flatbuffers/README.md index 3a1a1c9fdb188..fff424be83a3a 100644 --- a/js/web/lib/onnxjs/ort-schema/README.md +++ b/js/web/lib/onnxjs/ort-schema/flatbuffers/README.md @@ -1,4 +1,5 @@ # ORT Format File + This directory contains [the generated ts file](ort-generated.ts) necessary to support the ORT file format. The file is generated from [the ORT file format schema](https://github.com/microsoft/onnxruntime/blob/d42399e1b07ce61e95aae88bc6b6ea5dcaae2011/onnxruntime/core/flatbuffers/schema/ort.fbs). Please do not directly modify [the generated ts header file](ort-generated.ts). [The ORT file format schema](https://github.com/microsoft/onnxruntime/blob/d42399e1b07ce61e95aae88bc6b6ea5dcaae2011/onnxruntime/core/flatbuffers/schema/ort.fbs) uses [FlatBuffers](https://github.com/google/flatbuffers) serialization library. To update [its generated ts file](ort-generated.ts), diff --git a/js/web/lib/onnxjs/ort-schema/ort-generated.ts b/js/web/lib/onnxjs/ort-schema/flatbuffers/ort-generated.ts similarity index 99% rename from js/web/lib/onnxjs/ort-schema/ort-generated.ts rename to js/web/lib/onnxjs/ort-schema/flatbuffers/ort-generated.ts index f2032c9678c91..32758c2bfd8b7 100644 --- a/js/web/lib/onnxjs/ort-schema/ort-generated.ts +++ b/js/web/lib/onnxjs/ort-schema/flatbuffers/ort-generated.ts @@ -52,7 +52,11 @@ export namespace onnxruntime.experimental.fbs { UINT64 = 13, COMPLEX64 = 14, COMPLEX128 = 15, - BFLOAT16 = 16 + BFLOAT16 = 16, + FLOAT8E4M3FN = 17, + FLOAT8E4M3FNUZ = 18, + FLOAT8E5M2 = 19, + FLOAT8E5M2FNUZ = 20, } } diff --git a/js/web/lib/onnxjs/ort-schema/protobuf/.gitignore b/js/web/lib/onnxjs/ort-schema/protobuf/.gitignore new file mode 100644 index 0000000000000..092bb6c1c9fb4 --- /dev/null +++ b/js/web/lib/onnxjs/ort-schema/protobuf/.gitignore @@ -0,0 +1,2 @@ +!onnx.js +!onnx.d.ts diff --git a/js/web/lib/onnxjs/ort-schema/protobuf/README.md b/js/web/lib/onnxjs/ort-schema/protobuf/README.md new file mode 100644 index 0000000000000..f5f52c602f1ad --- /dev/null +++ b/js/web/lib/onnxjs/ort-schema/protobuf/README.md @@ -0,0 +1,21 @@ +# ONNX protobuf + +This directory contains generated protobuf definition for onnx: + +- onnx.js +- onnx.d.ts + +These files are generated from [a fork of onnx-proto](https://github.com/fs-eire/onnx-proto/tree/update-v9). + +The ONNX protobuf uses protobufjs@7.2.4, which depends on long@5.2.3, the version contains 2 bugs: + +- type export does not work with commonjs. described in https://github.com/dcodeIO/long.js/pull/124. added a "postinstall" script to fix. +- in the generated typescript declaration file 'onnx.d.ts', the following line: + ```ts + import Long = require("long"); + ``` + need to be replaced to fix type import error: + ```ts + import Long from "long"; + ``` + this replacement is done and code format is also applied to file 'onnx.d.ts'. diff --git a/js/web/lib/onnxjs/ort-schema/protobuf/onnx.d.ts b/js/web/lib/onnxjs/ort-schema/protobuf/onnx.d.ts new file mode 100644 index 0000000000000..c60264dca2a8d --- /dev/null +++ b/js/web/lib/onnxjs/ort-schema/protobuf/onnx.d.ts @@ -0,0 +1,2627 @@ +import Long from 'long'; +import * as $protobuf from 'protobufjs'; + +/** Namespace onnx. */ +export namespace onnx { + + /** Version enum. */ + enum Version { + _START_VERSION = 0, + IR_VERSION_2017_10_10 = 1, + IR_VERSION_2017_10_30 = 2, + IR_VERSION_2017_11_3 = 3, + IR_VERSION_2019_1_22 = 4, + IR_VERSION_2019_3_18 = 5, + IR_VERSION_2019_9_19 = 6, + IR_VERSION_2020_5_8 = 7, + IR_VERSION_2021_7_30 = 8, + IR_VERSION = 9 + } + + /** Properties of an AttributeProto. */ + interface IAttributeProto { + /** AttributeProto name */ + name?: (string|null); + + /** AttributeProto refAttrName */ + refAttrName?: (string|null); + + /** AttributeProto docString */ + docString?: (string|null); + + /** AttributeProto type */ + type?: (onnx.AttributeProto.AttributeType|null); + + /** AttributeProto f */ + f?: (number|null); + + /** AttributeProto i */ + i?: (number|Long|null); + + /** AttributeProto s */ + s?: (Uint8Array|null); + + /** AttributeProto t */ + t?: (onnx.ITensorProto|null); + + /** AttributeProto g */ + g?: (onnx.IGraphProto|null); + + /** AttributeProto sparseTensor */ + sparseTensor?: (onnx.ISparseTensorProto|null); + + /** AttributeProto tp */ + tp?: (onnx.ITypeProto|null); + + /** AttributeProto floats */ + floats?: (number[]|null); + + /** AttributeProto ints */ + ints?: ((number | Long)[]|null); + + /** AttributeProto strings */ + strings?: (Uint8Array[]|null); + + /** AttributeProto tensors */ + tensors?: (onnx.ITensorProto[]|null); + + /** AttributeProto graphs */ + graphs?: (onnx.IGraphProto[]|null); + + /** AttributeProto sparseTensors */ + sparseTensors?: (onnx.ISparseTensorProto[]|null); + + /** AttributeProto typeProtos */ + typeProtos?: (onnx.ITypeProto[]|null); + } + + /** Represents an AttributeProto. */ + class AttributeProto implements IAttributeProto { + /** + * Constructs a new AttributeProto. + * @param [properties] Properties to set + */ + constructor(properties?: onnx.IAttributeProto); + + /** AttributeProto name. */ + public name: string; + + /** AttributeProto refAttrName. */ + public refAttrName: string; + + /** AttributeProto docString. */ + public docString: string; + + /** AttributeProto type. */ + public type: onnx.AttributeProto.AttributeType; + + /** AttributeProto f. */ + public f: number; + + /** AttributeProto i. */ + public i: (number|Long); + + /** AttributeProto s. */ + public s: Uint8Array; + + /** AttributeProto t. */ + public t?: (onnx.ITensorProto|null); + + /** AttributeProto g. */ + public g?: (onnx.IGraphProto|null); + + /** AttributeProto sparseTensor. */ + public sparseTensor?: (onnx.ISparseTensorProto|null); + + /** AttributeProto tp. */ + public tp?: (onnx.ITypeProto|null); + + /** AttributeProto floats. */ + public floats: number[]; + + /** AttributeProto ints. */ + public ints: (number|Long)[]; + + /** AttributeProto strings. */ + public strings: Uint8Array[]; + + /** AttributeProto tensors. */ + public tensors: onnx.ITensorProto[]; + + /** AttributeProto graphs. */ + public graphs: onnx.IGraphProto[]; + + /** AttributeProto sparseTensors. */ + public sparseTensors: onnx.ISparseTensorProto[]; + + /** AttributeProto typeProtos. */ + public typeProtos: onnx.ITypeProto[]; + + /** + * Creates a new AttributeProto instance using the specified properties. + * @param [properties] Properties to set + * @returns AttributeProto instance + */ + public static create(properties?: onnx.IAttributeProto): onnx.AttributeProto; + + /** + * Encodes the specified AttributeProto message. Does not implicitly {@link onnx.AttributeProto.verify|verify} + * messages. + * @param message AttributeProto message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: onnx.IAttributeProto, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified AttributeProto message, length delimited. Does not implicitly {@link + * onnx.AttributeProto.verify|verify} messages. + * @param message AttributeProto message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: onnx.IAttributeProto, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes an AttributeProto message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns AttributeProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): onnx.AttributeProto; + + /** + * Decodes an AttributeProto message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns AttributeProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): onnx.AttributeProto; + + /** + * Verifies an AttributeProto message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: {[k: string]: any}): (string|null); + + /** + * Creates an AttributeProto message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns AttributeProto + */ + public static fromObject(object: {[k: string]: any}): onnx.AttributeProto; + + /** + * Creates a plain object from an AttributeProto message. Also converts values to other types if specified. + * @param message AttributeProto + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: onnx.AttributeProto, options?: $protobuf.IConversionOptions): {[k: string]: any}; + + /** + * Converts this AttributeProto to JSON. + * @returns JSON object + */ + public toJSON(): {[k: string]: any}; + + /** + * Gets the default type url for AttributeProto + * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns The default type url + */ + public static getTypeUrl(typeUrlPrefix?: string): string; + } + + namespace AttributeProto { + + /** AttributeType enum. */ + enum AttributeType { + UNDEFINED = 0, + FLOAT = 1, + INT = 2, + STRING = 3, + TENSOR = 4, + GRAPH = 5, + SPARSE_TENSOR = 11, + TYPE_PROTO = 13, + FLOATS = 6, + INTS = 7, + STRINGS = 8, + TENSORS = 9, + GRAPHS = 10, + SPARSE_TENSORS = 12, + TYPE_PROTOS = 14 + } + } + + /** Properties of a ValueInfoProto. */ + interface IValueInfoProto { + /** ValueInfoProto name */ + name?: (string|null); + + /** ValueInfoProto type */ + type?: (onnx.ITypeProto|null); + + /** ValueInfoProto docString */ + docString?: (string|null); + } + + /** Represents a ValueInfoProto. */ + class ValueInfoProto implements IValueInfoProto { + /** + * Constructs a new ValueInfoProto. + * @param [properties] Properties to set + */ + constructor(properties?: onnx.IValueInfoProto); + + /** ValueInfoProto name. */ + public name: string; + + /** ValueInfoProto type. */ + public type?: (onnx.ITypeProto|null); + + /** ValueInfoProto docString. */ + public docString: string; + + /** + * Creates a new ValueInfoProto instance using the specified properties. + * @param [properties] Properties to set + * @returns ValueInfoProto instance + */ + public static create(properties?: onnx.IValueInfoProto): onnx.ValueInfoProto; + + /** + * Encodes the specified ValueInfoProto message. Does not implicitly {@link onnx.ValueInfoProto.verify|verify} + * messages. + * @param message ValueInfoProto message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: onnx.IValueInfoProto, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified ValueInfoProto message, length delimited. Does not implicitly {@link + * onnx.ValueInfoProto.verify|verify} messages. + * @param message ValueInfoProto message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: onnx.IValueInfoProto, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a ValueInfoProto message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns ValueInfoProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): onnx.ValueInfoProto; + + /** + * Decodes a ValueInfoProto message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns ValueInfoProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): onnx.ValueInfoProto; + + /** + * Verifies a ValueInfoProto message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: {[k: string]: any}): (string|null); + + /** + * Creates a ValueInfoProto message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns ValueInfoProto + */ + public static fromObject(object: {[k: string]: any}): onnx.ValueInfoProto; + + /** + * Creates a plain object from a ValueInfoProto message. Also converts values to other types if specified. + * @param message ValueInfoProto + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: onnx.ValueInfoProto, options?: $protobuf.IConversionOptions): {[k: string]: any}; + + /** + * Converts this ValueInfoProto to JSON. + * @returns JSON object + */ + public toJSON(): {[k: string]: any}; + + /** + * Gets the default type url for ValueInfoProto + * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns The default type url + */ + public static getTypeUrl(typeUrlPrefix?: string): string; + } + + /** Properties of a NodeProto. */ + interface INodeProto { + /** NodeProto input */ + input?: (string[]|null); + + /** NodeProto output */ + output?: (string[]|null); + + /** NodeProto name */ + name?: (string|null); + + /** NodeProto opType */ + opType?: (string|null); + + /** NodeProto domain */ + domain?: (string|null); + + /** NodeProto attribute */ + attribute?: (onnx.IAttributeProto[]|null); + + /** NodeProto docString */ + docString?: (string|null); + } + + /** Represents a NodeProto. */ + class NodeProto implements INodeProto { + /** + * Constructs a new NodeProto. + * @param [properties] Properties to set + */ + constructor(properties?: onnx.INodeProto); + + /** NodeProto input. */ + public input: string[]; + + /** NodeProto output. */ + public output: string[]; + + /** NodeProto name. */ + public name: string; + + /** NodeProto opType. */ + public opType: string; + + /** NodeProto domain. */ + public domain: string; + + /** NodeProto attribute. */ + public attribute: onnx.IAttributeProto[]; + + /** NodeProto docString. */ + public docString: string; + + /** + * Creates a new NodeProto instance using the specified properties. + * @param [properties] Properties to set + * @returns NodeProto instance + */ + public static create(properties?: onnx.INodeProto): onnx.NodeProto; + + /** + * Encodes the specified NodeProto message. Does not implicitly {@link onnx.NodeProto.verify|verify} messages. + * @param message NodeProto message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: onnx.INodeProto, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified NodeProto message, length delimited. Does not implicitly {@link + * onnx.NodeProto.verify|verify} messages. + * @param message NodeProto message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: onnx.INodeProto, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a NodeProto message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns NodeProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): onnx.NodeProto; + + /** + * Decodes a NodeProto message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns NodeProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): onnx.NodeProto; + + /** + * Verifies a NodeProto message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: {[k: string]: any}): (string|null); + + /** + * Creates a NodeProto message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns NodeProto + */ + public static fromObject(object: {[k: string]: any}): onnx.NodeProto; + + /** + * Creates a plain object from a NodeProto message. Also converts values to other types if specified. + * @param message NodeProto + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: onnx.NodeProto, options?: $protobuf.IConversionOptions): {[k: string]: any}; + + /** + * Converts this NodeProto to JSON. + * @returns JSON object + */ + public toJSON(): {[k: string]: any}; + + /** + * Gets the default type url for NodeProto + * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns The default type url + */ + public static getTypeUrl(typeUrlPrefix?: string): string; + } + + /** Properties of a TrainingInfoProto. */ + interface ITrainingInfoProto { + /** TrainingInfoProto initialization */ + initialization?: (onnx.IGraphProto|null); + + /** TrainingInfoProto algorithm */ + algorithm?: (onnx.IGraphProto|null); + + /** TrainingInfoProto initializationBinding */ + initializationBinding?: (onnx.IStringStringEntryProto[]|null); + + /** TrainingInfoProto updateBinding */ + updateBinding?: (onnx.IStringStringEntryProto[]|null); + } + + /** Represents a TrainingInfoProto. */ + class TrainingInfoProto implements ITrainingInfoProto { + /** + * Constructs a new TrainingInfoProto. + * @param [properties] Properties to set + */ + constructor(properties?: onnx.ITrainingInfoProto); + + /** TrainingInfoProto initialization. */ + public initialization?: (onnx.IGraphProto|null); + + /** TrainingInfoProto algorithm. */ + public algorithm?: (onnx.IGraphProto|null); + + /** TrainingInfoProto initializationBinding. */ + public initializationBinding: onnx.IStringStringEntryProto[]; + + /** TrainingInfoProto updateBinding. */ + public updateBinding: onnx.IStringStringEntryProto[]; + + /** + * Creates a new TrainingInfoProto instance using the specified properties. + * @param [properties] Properties to set + * @returns TrainingInfoProto instance + */ + public static create(properties?: onnx.ITrainingInfoProto): onnx.TrainingInfoProto; + + /** + * Encodes the specified TrainingInfoProto message. Does not implicitly {@link onnx.TrainingInfoProto.verify|verify} + * messages. + * @param message TrainingInfoProto message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: onnx.ITrainingInfoProto, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified TrainingInfoProto message, length delimited. Does not implicitly {@link + * onnx.TrainingInfoProto.verify|verify} messages. + * @param message TrainingInfoProto message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: onnx.ITrainingInfoProto, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a TrainingInfoProto message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns TrainingInfoProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): onnx.TrainingInfoProto; + + /** + * Decodes a TrainingInfoProto message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns TrainingInfoProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): onnx.TrainingInfoProto; + + /** + * Verifies a TrainingInfoProto message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: {[k: string]: any}): (string|null); + + /** + * Creates a TrainingInfoProto message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns TrainingInfoProto + */ + public static fromObject(object: {[k: string]: any}): onnx.TrainingInfoProto; + + /** + * Creates a plain object from a TrainingInfoProto message. Also converts values to other types if specified. + * @param message TrainingInfoProto + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: onnx.TrainingInfoProto, options?: $protobuf.IConversionOptions): {[k: string]: any}; + + /** + * Converts this TrainingInfoProto to JSON. + * @returns JSON object + */ + public toJSON(): {[k: string]: any}; + + /** + * Gets the default type url for TrainingInfoProto + * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns The default type url + */ + public static getTypeUrl(typeUrlPrefix?: string): string; + } + + /** Properties of a ModelProto. */ + interface IModelProto { + /** ModelProto irVersion */ + irVersion?: (number|Long|null); + + /** ModelProto opsetImport */ + opsetImport?: (onnx.IOperatorSetIdProto[]|null); + + /** ModelProto producerName */ + producerName?: (string|null); + + /** ModelProto producerVersion */ + producerVersion?: (string|null); + + /** ModelProto domain */ + domain?: (string|null); + + /** ModelProto modelVersion */ + modelVersion?: (number|Long|null); + + /** ModelProto docString */ + docString?: (string|null); + + /** ModelProto graph */ + graph?: (onnx.IGraphProto|null); + + /** ModelProto metadataProps */ + metadataProps?: (onnx.IStringStringEntryProto[]|null); + + /** ModelProto trainingInfo */ + trainingInfo?: (onnx.ITrainingInfoProto[]|null); + + /** ModelProto functions */ + functions?: (onnx.IFunctionProto[]|null); + } + + /** Represents a ModelProto. */ + class ModelProto implements IModelProto { + /** + * Constructs a new ModelProto. + * @param [properties] Properties to set + */ + constructor(properties?: onnx.IModelProto); + + /** ModelProto irVersion. */ + public irVersion: (number|Long); + + /** ModelProto opsetImport. */ + public opsetImport: onnx.IOperatorSetIdProto[]; + + /** ModelProto producerName. */ + public producerName: string; + + /** ModelProto producerVersion. */ + public producerVersion: string; + + /** ModelProto domain. */ + public domain: string; + + /** ModelProto modelVersion. */ + public modelVersion: (number|Long); + + /** ModelProto docString. */ + public docString: string; + + /** ModelProto graph. */ + public graph?: (onnx.IGraphProto|null); + + /** ModelProto metadataProps. */ + public metadataProps: onnx.IStringStringEntryProto[]; + + /** ModelProto trainingInfo. */ + public trainingInfo: onnx.ITrainingInfoProto[]; + + /** ModelProto functions. */ + public functions: onnx.IFunctionProto[]; + + /** + * Creates a new ModelProto instance using the specified properties. + * @param [properties] Properties to set + * @returns ModelProto instance + */ + public static create(properties?: onnx.IModelProto): onnx.ModelProto; + + /** + * Encodes the specified ModelProto message. Does not implicitly {@link onnx.ModelProto.verify|verify} messages. + * @param message ModelProto message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: onnx.IModelProto, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified ModelProto message, length delimited. Does not implicitly {@link + * onnx.ModelProto.verify|verify} messages. + * @param message ModelProto message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: onnx.IModelProto, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a ModelProto message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns ModelProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): onnx.ModelProto; + + /** + * Decodes a ModelProto message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns ModelProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): onnx.ModelProto; + + /** + * Verifies a ModelProto message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: {[k: string]: any}): (string|null); + + /** + * Creates a ModelProto message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns ModelProto + */ + public static fromObject(object: {[k: string]: any}): onnx.ModelProto; + + /** + * Creates a plain object from a ModelProto message. Also converts values to other types if specified. + * @param message ModelProto + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: onnx.ModelProto, options?: $protobuf.IConversionOptions): {[k: string]: any}; + + /** + * Converts this ModelProto to JSON. + * @returns JSON object + */ + public toJSON(): {[k: string]: any}; + + /** + * Gets the default type url for ModelProto + * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns The default type url + */ + public static getTypeUrl(typeUrlPrefix?: string): string; + } + + /** Properties of a StringStringEntryProto. */ + interface IStringStringEntryProto { + /** StringStringEntryProto key */ + key?: (string|null); + + /** StringStringEntryProto value */ + value?: (string|null); + } + + /** Represents a StringStringEntryProto. */ + class StringStringEntryProto implements IStringStringEntryProto { + /** + * Constructs a new StringStringEntryProto. + * @param [properties] Properties to set + */ + constructor(properties?: onnx.IStringStringEntryProto); + + /** StringStringEntryProto key. */ + public key: string; + + /** StringStringEntryProto value. */ + public value: string; + + /** + * Creates a new StringStringEntryProto instance using the specified properties. + * @param [properties] Properties to set + * @returns StringStringEntryProto instance + */ + public static create(properties?: onnx.IStringStringEntryProto): onnx.StringStringEntryProto; + + /** + * Encodes the specified StringStringEntryProto message. Does not implicitly {@link + * onnx.StringStringEntryProto.verify|verify} messages. + * @param message StringStringEntryProto message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: onnx.IStringStringEntryProto, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified StringStringEntryProto message, length delimited. Does not implicitly {@link + * onnx.StringStringEntryProto.verify|verify} messages. + * @param message StringStringEntryProto message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: onnx.IStringStringEntryProto, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a StringStringEntryProto message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns StringStringEntryProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): onnx.StringStringEntryProto; + + /** + * Decodes a StringStringEntryProto message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns StringStringEntryProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): onnx.StringStringEntryProto; + + /** + * Verifies a StringStringEntryProto message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: {[k: string]: any}): (string|null); + + /** + * Creates a StringStringEntryProto message from a plain object. Also converts values to their respective internal + * types. + * @param object Plain object + * @returns StringStringEntryProto + */ + public static fromObject(object: {[k: string]: any}): onnx.StringStringEntryProto; + + /** + * Creates a plain object from a StringStringEntryProto message. Also converts values to other types if specified. + * @param message StringStringEntryProto + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: onnx.StringStringEntryProto, options?: $protobuf.IConversionOptions): + {[k: string]: any}; + + /** + * Converts this StringStringEntryProto to JSON. + * @returns JSON object + */ + public toJSON(): {[k: string]: any}; + + /** + * Gets the default type url for StringStringEntryProto + * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns The default type url + */ + public static getTypeUrl(typeUrlPrefix?: string): string; + } + + /** Properties of a TensorAnnotation. */ + interface ITensorAnnotation { + /** TensorAnnotation tensorName */ + tensorName?: (string|null); + + /** TensorAnnotation quantParameterTensorNames */ + quantParameterTensorNames?: (onnx.IStringStringEntryProto[]|null); + } + + /** Represents a TensorAnnotation. */ + class TensorAnnotation implements ITensorAnnotation { + /** + * Constructs a new TensorAnnotation. + * @param [properties] Properties to set + */ + constructor(properties?: onnx.ITensorAnnotation); + + /** TensorAnnotation tensorName. */ + public tensorName: string; + + /** TensorAnnotation quantParameterTensorNames. */ + public quantParameterTensorNames: onnx.IStringStringEntryProto[]; + + /** + * Creates a new TensorAnnotation instance using the specified properties. + * @param [properties] Properties to set + * @returns TensorAnnotation instance + */ + public static create(properties?: onnx.ITensorAnnotation): onnx.TensorAnnotation; + + /** + * Encodes the specified TensorAnnotation message. Does not implicitly {@link onnx.TensorAnnotation.verify|verify} + * messages. + * @param message TensorAnnotation message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: onnx.ITensorAnnotation, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified TensorAnnotation message, length delimited. Does not implicitly {@link + * onnx.TensorAnnotation.verify|verify} messages. + * @param message TensorAnnotation message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: onnx.ITensorAnnotation, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a TensorAnnotation message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns TensorAnnotation + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): onnx.TensorAnnotation; + + /** + * Decodes a TensorAnnotation message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns TensorAnnotation + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): onnx.TensorAnnotation; + + /** + * Verifies a TensorAnnotation message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: {[k: string]: any}): (string|null); + + /** + * Creates a TensorAnnotation message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns TensorAnnotation + */ + public static fromObject(object: {[k: string]: any}): onnx.TensorAnnotation; + + /** + * Creates a plain object from a TensorAnnotation message. Also converts values to other types if specified. + * @param message TensorAnnotation + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: onnx.TensorAnnotation, options?: $protobuf.IConversionOptions): {[k: string]: any}; + + /** + * Converts this TensorAnnotation to JSON. + * @returns JSON object + */ + public toJSON(): {[k: string]: any}; + + /** + * Gets the default type url for TensorAnnotation + * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns The default type url + */ + public static getTypeUrl(typeUrlPrefix?: string): string; + } + + /** Properties of a GraphProto. */ + interface IGraphProto { + /** GraphProto node */ + node?: (onnx.INodeProto[]|null); + + /** GraphProto name */ + name?: (string|null); + + /** GraphProto initializer */ + initializer?: (onnx.ITensorProto[]|null); + + /** GraphProto sparseInitializer */ + sparseInitializer?: (onnx.ISparseTensorProto[]|null); + + /** GraphProto docString */ + docString?: (string|null); + + /** GraphProto input */ + input?: (onnx.IValueInfoProto[]|null); + + /** GraphProto output */ + output?: (onnx.IValueInfoProto[]|null); + + /** GraphProto valueInfo */ + valueInfo?: (onnx.IValueInfoProto[]|null); + + /** GraphProto quantizationAnnotation */ + quantizationAnnotation?: (onnx.ITensorAnnotation[]|null); + } + + /** Represents a GraphProto. */ + class GraphProto implements IGraphProto { + /** + * Constructs a new GraphProto. + * @param [properties] Properties to set + */ + constructor(properties?: onnx.IGraphProto); + + /** GraphProto node. */ + public node: onnx.INodeProto[]; + + /** GraphProto name. */ + public name: string; + + /** GraphProto initializer. */ + public initializer: onnx.ITensorProto[]; + + /** GraphProto sparseInitializer. */ + public sparseInitializer: onnx.ISparseTensorProto[]; + + /** GraphProto docString. */ + public docString: string; + + /** GraphProto input. */ + public input: onnx.IValueInfoProto[]; + + /** GraphProto output. */ + public output: onnx.IValueInfoProto[]; + + /** GraphProto valueInfo. */ + public valueInfo: onnx.IValueInfoProto[]; + + /** GraphProto quantizationAnnotation. */ + public quantizationAnnotation: onnx.ITensorAnnotation[]; + + /** + * Creates a new GraphProto instance using the specified properties. + * @param [properties] Properties to set + * @returns GraphProto instance + */ + public static create(properties?: onnx.IGraphProto): onnx.GraphProto; + + /** + * Encodes the specified GraphProto message. Does not implicitly {@link onnx.GraphProto.verify|verify} messages. + * @param message GraphProto message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: onnx.IGraphProto, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified GraphProto message, length delimited. Does not implicitly {@link + * onnx.GraphProto.verify|verify} messages. + * @param message GraphProto message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: onnx.IGraphProto, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a GraphProto message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns GraphProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): onnx.GraphProto; + + /** + * Decodes a GraphProto message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns GraphProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): onnx.GraphProto; + + /** + * Verifies a GraphProto message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: {[k: string]: any}): (string|null); + + /** + * Creates a GraphProto message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns GraphProto + */ + public static fromObject(object: {[k: string]: any}): onnx.GraphProto; + + /** + * Creates a plain object from a GraphProto message. Also converts values to other types if specified. + * @param message GraphProto + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: onnx.GraphProto, options?: $protobuf.IConversionOptions): {[k: string]: any}; + + /** + * Converts this GraphProto to JSON. + * @returns JSON object + */ + public toJSON(): {[k: string]: any}; + + /** + * Gets the default type url for GraphProto + * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns The default type url + */ + public static getTypeUrl(typeUrlPrefix?: string): string; + } + + /** Properties of a TensorProto. */ + interface ITensorProto { + /** TensorProto dims */ + dims?: ((number | Long)[]|null); + + /** TensorProto dataType */ + dataType?: (number|null); + + /** TensorProto segment */ + segment?: (onnx.TensorProto.ISegment|null); + + /** TensorProto floatData */ + floatData?: (number[]|null); + + /** TensorProto int32Data */ + int32Data?: (number[]|null); + + /** TensorProto stringData */ + stringData?: (Uint8Array[]|null); + + /** TensorProto int64Data */ + int64Data?: ((number | Long)[]|null); + + /** TensorProto name */ + name?: (string|null); + + /** TensorProto docString */ + docString?: (string|null); + + /** TensorProto rawData */ + rawData?: (Uint8Array|null); + + /** TensorProto externalData */ + externalData?: (onnx.IStringStringEntryProto[]|null); + + /** TensorProto dataLocation */ + dataLocation?: (onnx.TensorProto.DataLocation|null); + + /** TensorProto doubleData */ + doubleData?: (number[]|null); + + /** TensorProto uint64Data */ + uint64Data?: ((number | Long)[]|null); + } + + /** Represents a TensorProto. */ + class TensorProto implements ITensorProto { + /** + * Constructs a new TensorProto. + * @param [properties] Properties to set + */ + constructor(properties?: onnx.ITensorProto); + + /** TensorProto dims. */ + public dims: (number|Long)[]; + + /** TensorProto dataType. */ + public dataType: number; + + /** TensorProto segment. */ + public segment?: (onnx.TensorProto.ISegment|null); + + /** TensorProto floatData. */ + public floatData: number[]; + + /** TensorProto int32Data. */ + public int32Data: number[]; + + /** TensorProto stringData. */ + public stringData: Uint8Array[]; + + /** TensorProto int64Data. */ + public int64Data: (number|Long)[]; + + /** TensorProto name. */ + public name: string; + + /** TensorProto docString. */ + public docString: string; + + /** TensorProto rawData. */ + public rawData: Uint8Array; + + /** TensorProto externalData. */ + public externalData: onnx.IStringStringEntryProto[]; + + /** TensorProto dataLocation. */ + public dataLocation: onnx.TensorProto.DataLocation; + + /** TensorProto doubleData. */ + public doubleData: number[]; + + /** TensorProto uint64Data. */ + public uint64Data: (number|Long)[]; + + /** + * Creates a new TensorProto instance using the specified properties. + * @param [properties] Properties to set + * @returns TensorProto instance + */ + public static create(properties?: onnx.ITensorProto): onnx.TensorProto; + + /** + * Encodes the specified TensorProto message. Does not implicitly {@link onnx.TensorProto.verify|verify} messages. + * @param message TensorProto message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: onnx.ITensorProto, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified TensorProto message, length delimited. Does not implicitly {@link + * onnx.TensorProto.verify|verify} messages. + * @param message TensorProto message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: onnx.ITensorProto, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a TensorProto message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns TensorProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): onnx.TensorProto; + + /** + * Decodes a TensorProto message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns TensorProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): onnx.TensorProto; + + /** + * Verifies a TensorProto message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: {[k: string]: any}): (string|null); + + /** + * Creates a TensorProto message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns TensorProto + */ + public static fromObject(object: {[k: string]: any}): onnx.TensorProto; + + /** + * Creates a plain object from a TensorProto message. Also converts values to other types if specified. + * @param message TensorProto + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: onnx.TensorProto, options?: $protobuf.IConversionOptions): {[k: string]: any}; + + /** + * Converts this TensorProto to JSON. + * @returns JSON object + */ + public toJSON(): {[k: string]: any}; + + /** + * Gets the default type url for TensorProto + * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns The default type url + */ + public static getTypeUrl(typeUrlPrefix?: string): string; + } + + namespace TensorProto { + + /** DataType enum. */ + enum DataType { + UNDEFINED = 0, + FLOAT = 1, + UINT8 = 2, + INT8 = 3, + UINT16 = 4, + INT16 = 5, + INT32 = 6, + INT64 = 7, + STRING = 8, + BOOL = 9, + FLOAT16 = 10, + DOUBLE = 11, + UINT32 = 12, + UINT64 = 13, + COMPLEX64 = 14, + COMPLEX128 = 15, + BFLOAT16 = 16, + FLOAT8E4M3FN = 17, + FLOAT8E4M3FNUZ = 18, + FLOAT8E5M2 = 19, + FLOAT8E5M2FNUZ = 20 + } + + /** Properties of a Segment. */ + interface ISegment { + /** Segment begin */ + begin?: (number|Long|null); + + /** Segment end */ + end?: (number|Long|null); + } + + /** Represents a Segment. */ + class Segment implements ISegment { + /** + * Constructs a new Segment. + * @param [properties] Properties to set + */ + constructor(properties?: onnx.TensorProto.ISegment); + + /** Segment begin. */ + public begin: (number|Long); + + /** Segment end. */ + public end: (number|Long); + + /** + * Creates a new Segment instance using the specified properties. + * @param [properties] Properties to set + * @returns Segment instance + */ + public static create(properties?: onnx.TensorProto.ISegment): onnx.TensorProto.Segment; + + /** + * Encodes the specified Segment message. Does not implicitly {@link onnx.TensorProto.Segment.verify|verify} + * messages. + * @param message Segment message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: onnx.TensorProto.ISegment, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified Segment message, length delimited. Does not implicitly {@link + * onnx.TensorProto.Segment.verify|verify} messages. + * @param message Segment message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: onnx.TensorProto.ISegment, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a Segment message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns Segment + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): onnx.TensorProto.Segment; + + /** + * Decodes a Segment message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns Segment + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): onnx.TensorProto.Segment; + + /** + * Verifies a Segment message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: {[k: string]: any}): (string|null); + + /** + * Creates a Segment message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns Segment + */ + public static fromObject(object: {[k: string]: any}): onnx.TensorProto.Segment; + + /** + * Creates a plain object from a Segment message. Also converts values to other types if specified. + * @param message Segment + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: onnx.TensorProto.Segment, options?: $protobuf.IConversionOptions): + {[k: string]: any}; + + /** + * Converts this Segment to JSON. + * @returns JSON object + */ + public toJSON(): {[k: string]: any}; + + /** + * Gets the default type url for Segment + * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns The default type url + */ + public static getTypeUrl(typeUrlPrefix?: string): string; + } + + /** DataLocation enum. */ + enum DataLocation { DEFAULT = 0, EXTERNAL = 1 } + } + + /** Properties of a SparseTensorProto. */ + interface ISparseTensorProto { + /** SparseTensorProto values */ + values?: (onnx.ITensorProto|null); + + /** SparseTensorProto indices */ + indices?: (onnx.ITensorProto|null); + + /** SparseTensorProto dims */ + dims?: ((number | Long)[]|null); + } + + /** Represents a SparseTensorProto. */ + class SparseTensorProto implements ISparseTensorProto { + /** + * Constructs a new SparseTensorProto. + * @param [properties] Properties to set + */ + constructor(properties?: onnx.ISparseTensorProto); + + /** SparseTensorProto values. */ + public values?: (onnx.ITensorProto|null); + + /** SparseTensorProto indices. */ + public indices?: (onnx.ITensorProto|null); + + /** SparseTensorProto dims. */ + public dims: (number|Long)[]; + + /** + * Creates a new SparseTensorProto instance using the specified properties. + * @param [properties] Properties to set + * @returns SparseTensorProto instance + */ + public static create(properties?: onnx.ISparseTensorProto): onnx.SparseTensorProto; + + /** + * Encodes the specified SparseTensorProto message. Does not implicitly {@link onnx.SparseTensorProto.verify|verify} + * messages. + * @param message SparseTensorProto message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: onnx.ISparseTensorProto, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified SparseTensorProto message, length delimited. Does not implicitly {@link + * onnx.SparseTensorProto.verify|verify} messages. + * @param message SparseTensorProto message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: onnx.ISparseTensorProto, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a SparseTensorProto message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns SparseTensorProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): onnx.SparseTensorProto; + + /** + * Decodes a SparseTensorProto message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns SparseTensorProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): onnx.SparseTensorProto; + + /** + * Verifies a SparseTensorProto message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: {[k: string]: any}): (string|null); + + /** + * Creates a SparseTensorProto message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns SparseTensorProto + */ + public static fromObject(object: {[k: string]: any}): onnx.SparseTensorProto; + + /** + * Creates a plain object from a SparseTensorProto message. Also converts values to other types if specified. + * @param message SparseTensorProto + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: onnx.SparseTensorProto, options?: $protobuf.IConversionOptions): {[k: string]: any}; + + /** + * Converts this SparseTensorProto to JSON. + * @returns JSON object + */ + public toJSON(): {[k: string]: any}; + + /** + * Gets the default type url for SparseTensorProto + * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns The default type url + */ + public static getTypeUrl(typeUrlPrefix?: string): string; + } + + /** Properties of a TensorShapeProto. */ + interface ITensorShapeProto { + /** TensorShapeProto dim */ + dim?: (onnx.TensorShapeProto.IDimension[]|null); + } + + /** Represents a TensorShapeProto. */ + class TensorShapeProto implements ITensorShapeProto { + /** + * Constructs a new TensorShapeProto. + * @param [properties] Properties to set + */ + constructor(properties?: onnx.ITensorShapeProto); + + /** TensorShapeProto dim. */ + public dim: onnx.TensorShapeProto.IDimension[]; + + /** + * Creates a new TensorShapeProto instance using the specified properties. + * @param [properties] Properties to set + * @returns TensorShapeProto instance + */ + public static create(properties?: onnx.ITensorShapeProto): onnx.TensorShapeProto; + + /** + * Encodes the specified TensorShapeProto message. Does not implicitly {@link onnx.TensorShapeProto.verify|verify} + * messages. + * @param message TensorShapeProto message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: onnx.ITensorShapeProto, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified TensorShapeProto message, length delimited. Does not implicitly {@link + * onnx.TensorShapeProto.verify|verify} messages. + * @param message TensorShapeProto message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: onnx.ITensorShapeProto, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a TensorShapeProto message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns TensorShapeProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): onnx.TensorShapeProto; + + /** + * Decodes a TensorShapeProto message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns TensorShapeProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): onnx.TensorShapeProto; + + /** + * Verifies a TensorShapeProto message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: {[k: string]: any}): (string|null); + + /** + * Creates a TensorShapeProto message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns TensorShapeProto + */ + public static fromObject(object: {[k: string]: any}): onnx.TensorShapeProto; + + /** + * Creates a plain object from a TensorShapeProto message. Also converts values to other types if specified. + * @param message TensorShapeProto + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: onnx.TensorShapeProto, options?: $protobuf.IConversionOptions): {[k: string]: any}; + + /** + * Converts this TensorShapeProto to JSON. + * @returns JSON object + */ + public toJSON(): {[k: string]: any}; + + /** + * Gets the default type url for TensorShapeProto + * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns The default type url + */ + public static getTypeUrl(typeUrlPrefix?: string): string; + } + + namespace TensorShapeProto { + + /** Properties of a Dimension. */ + interface IDimension { + /** Dimension dimValue */ + dimValue?: (number|Long|null); + + /** Dimension dimParam */ + dimParam?: (string|null); + + /** Dimension denotation */ + denotation?: (string|null); + } + + /** Represents a Dimension. */ + class Dimension implements IDimension { + /** + * Constructs a new Dimension. + * @param [properties] Properties to set + */ + constructor(properties?: onnx.TensorShapeProto.IDimension); + + /** Dimension dimValue. */ + public dimValue?: (number|Long|null); + + /** Dimension dimParam. */ + public dimParam?: (string|null); + + /** Dimension denotation. */ + public denotation: string; + + /** Dimension value. */ + public value?: ('dimValue'|'dimParam'); + + /** + * Creates a new Dimension instance using the specified properties. + * @param [properties] Properties to set + * @returns Dimension instance + */ + public static create(properties?: onnx.TensorShapeProto.IDimension): onnx.TensorShapeProto.Dimension; + + /** + * Encodes the specified Dimension message. Does not implicitly {@link + * onnx.TensorShapeProto.Dimension.verify|verify} messages. + * @param message Dimension message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: onnx.TensorShapeProto.IDimension, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified Dimension message, length delimited. Does not implicitly {@link + * onnx.TensorShapeProto.Dimension.verify|verify} messages. + * @param message Dimension message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: onnx.TensorShapeProto.IDimension, writer?: $protobuf.Writer): + $protobuf.Writer; + + /** + * Decodes a Dimension message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns Dimension + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): onnx.TensorShapeProto.Dimension; + + /** + * Decodes a Dimension message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns Dimension + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): onnx.TensorShapeProto.Dimension; + + /** + * Verifies a Dimension message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: {[k: string]: any}): (string|null); + + /** + * Creates a Dimension message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns Dimension + */ + public static fromObject(object: {[k: string]: any}): onnx.TensorShapeProto.Dimension; + + /** + * Creates a plain object from a Dimension message. Also converts values to other types if specified. + * @param message Dimension + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: onnx.TensorShapeProto.Dimension, options?: $protobuf.IConversionOptions): + {[k: string]: any}; + + /** + * Converts this Dimension to JSON. + * @returns JSON object + */ + public toJSON(): {[k: string]: any}; + + /** + * Gets the default type url for Dimension + * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns The default type url + */ + public static getTypeUrl(typeUrlPrefix?: string): string; + } + } + + /** Properties of a TypeProto. */ + interface ITypeProto { + /** TypeProto tensorType */ + tensorType?: (onnx.TypeProto.ITensor|null); + + /** TypeProto sequenceType */ + sequenceType?: (onnx.TypeProto.ISequence|null); + + /** TypeProto mapType */ + mapType?: (onnx.TypeProto.IMap|null); + + /** TypeProto optionalType */ + optionalType?: (onnx.TypeProto.IOptional|null); + + /** TypeProto sparseTensorType */ + sparseTensorType?: (onnx.TypeProto.ISparseTensor|null); + + /** TypeProto denotation */ + denotation?: (string|null); + } + + /** Represents a TypeProto. */ + class TypeProto implements ITypeProto { + /** + * Constructs a new TypeProto. + * @param [properties] Properties to set + */ + constructor(properties?: onnx.ITypeProto); + + /** TypeProto tensorType. */ + public tensorType?: (onnx.TypeProto.ITensor|null); + + /** TypeProto sequenceType. */ + public sequenceType?: (onnx.TypeProto.ISequence|null); + + /** TypeProto mapType. */ + public mapType?: (onnx.TypeProto.IMap|null); + + /** TypeProto optionalType. */ + public optionalType?: (onnx.TypeProto.IOptional|null); + + /** TypeProto sparseTensorType. */ + public sparseTensorType?: (onnx.TypeProto.ISparseTensor|null); + + /** TypeProto denotation. */ + public denotation: string; + + /** TypeProto value. */ + public value?: ('tensorType'|'sequenceType'|'mapType'|'optionalType'|'sparseTensorType'); + + /** + * Creates a new TypeProto instance using the specified properties. + * @param [properties] Properties to set + * @returns TypeProto instance + */ + public static create(properties?: onnx.ITypeProto): onnx.TypeProto; + + /** + * Encodes the specified TypeProto message. Does not implicitly {@link onnx.TypeProto.verify|verify} messages. + * @param message TypeProto message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: onnx.ITypeProto, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified TypeProto message, length delimited. Does not implicitly {@link + * onnx.TypeProto.verify|verify} messages. + * @param message TypeProto message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: onnx.ITypeProto, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a TypeProto message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns TypeProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): onnx.TypeProto; + + /** + * Decodes a TypeProto message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns TypeProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): onnx.TypeProto; + + /** + * Verifies a TypeProto message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: {[k: string]: any}): (string|null); + + /** + * Creates a TypeProto message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns TypeProto + */ + public static fromObject(object: {[k: string]: any}): onnx.TypeProto; + + /** + * Creates a plain object from a TypeProto message. Also converts values to other types if specified. + * @param message TypeProto + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: onnx.TypeProto, options?: $protobuf.IConversionOptions): {[k: string]: any}; + + /** + * Converts this TypeProto to JSON. + * @returns JSON object + */ + public toJSON(): {[k: string]: any}; + + /** + * Gets the default type url for TypeProto + * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns The default type url + */ + public static getTypeUrl(typeUrlPrefix?: string): string; + } + + namespace TypeProto { + + /** Properties of a Tensor. */ + interface ITensor { + /** Tensor elemType */ + elemType?: (number|null); + + /** Tensor shape */ + shape?: (onnx.ITensorShapeProto|null); + } + + /** Represents a Tensor. */ + class Tensor implements ITensor { + /** + * Constructs a new Tensor. + * @param [properties] Properties to set + */ + constructor(properties?: onnx.TypeProto.ITensor); + + /** Tensor elemType. */ + public elemType: number; + + /** Tensor shape. */ + public shape?: (onnx.ITensorShapeProto|null); + + /** + * Creates a new Tensor instance using the specified properties. + * @param [properties] Properties to set + * @returns Tensor instance + */ + public static create(properties?: onnx.TypeProto.ITensor): onnx.TypeProto.Tensor; + + /** + * Encodes the specified Tensor message. Does not implicitly {@link onnx.TypeProto.Tensor.verify|verify} messages. + * @param message Tensor message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: onnx.TypeProto.ITensor, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified Tensor message, length delimited. Does not implicitly {@link + * onnx.TypeProto.Tensor.verify|verify} messages. + * @param message Tensor message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: onnx.TypeProto.ITensor, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a Tensor message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns Tensor + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): onnx.TypeProto.Tensor; + + /** + * Decodes a Tensor message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns Tensor + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): onnx.TypeProto.Tensor; + + /** + * Verifies a Tensor message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: {[k: string]: any}): (string|null); + + /** + * Creates a Tensor message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns Tensor + */ + public static fromObject(object: {[k: string]: any}): onnx.TypeProto.Tensor; + + /** + * Creates a plain object from a Tensor message. Also converts values to other types if specified. + * @param message Tensor + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: onnx.TypeProto.Tensor, options?: $protobuf.IConversionOptions): + {[k: string]: any}; + + /** + * Converts this Tensor to JSON. + * @returns JSON object + */ + public toJSON(): {[k: string]: any}; + + /** + * Gets the default type url for Tensor + * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns The default type url + */ + public static getTypeUrl(typeUrlPrefix?: string): string; + } + + /** Properties of a Sequence. */ + interface ISequence { + /** Sequence elemType */ + elemType?: (onnx.ITypeProto|null); + } + + /** Represents a Sequence. */ + class Sequence implements ISequence { + /** + * Constructs a new Sequence. + * @param [properties] Properties to set + */ + constructor(properties?: onnx.TypeProto.ISequence); + + /** Sequence elemType. */ + public elemType?: (onnx.ITypeProto|null); + + /** + * Creates a new Sequence instance using the specified properties. + * @param [properties] Properties to set + * @returns Sequence instance + */ + public static create(properties?: onnx.TypeProto.ISequence): onnx.TypeProto.Sequence; + + /** + * Encodes the specified Sequence message. Does not implicitly {@link onnx.TypeProto.Sequence.verify|verify} + * messages. + * @param message Sequence message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: onnx.TypeProto.ISequence, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified Sequence message, length delimited. Does not implicitly {@link + * onnx.TypeProto.Sequence.verify|verify} messages. + * @param message Sequence message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: onnx.TypeProto.ISequence, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a Sequence message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns Sequence + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): onnx.TypeProto.Sequence; + + /** + * Decodes a Sequence message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns Sequence + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): onnx.TypeProto.Sequence; + + /** + * Verifies a Sequence message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: {[k: string]: any}): (string|null); + + /** + * Creates a Sequence message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns Sequence + */ + public static fromObject(object: {[k: string]: any}): onnx.TypeProto.Sequence; + + /** + * Creates a plain object from a Sequence message. Also converts values to other types if specified. + * @param message Sequence + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: onnx.TypeProto.Sequence, options?: $protobuf.IConversionOptions): + {[k: string]: any}; + + /** + * Converts this Sequence to JSON. + * @returns JSON object + */ + public toJSON(): {[k: string]: any}; + + /** + * Gets the default type url for Sequence + * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns The default type url + */ + public static getTypeUrl(typeUrlPrefix?: string): string; + } + + /** Properties of a Map. */ + interface IMap { + /** Map keyType */ + keyType?: (number|null); + + /** Map valueType */ + valueType?: (onnx.ITypeProto|null); + } + + /** Represents a Map. */ + class Map implements IMap { + /** + * Constructs a new Map. + * @param [properties] Properties to set + */ + constructor(properties?: onnx.TypeProto.IMap); + + /** Map keyType. */ + public keyType: number; + + /** Map valueType. */ + public valueType?: (onnx.ITypeProto|null); + + /** + * Creates a new Map instance using the specified properties. + * @param [properties] Properties to set + * @returns Map instance + */ + public static create(properties?: onnx.TypeProto.IMap): onnx.TypeProto.Map; + + /** + * Encodes the specified Map message. Does not implicitly {@link onnx.TypeProto.Map.verify|verify} messages. + * @param message Map message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: onnx.TypeProto.IMap, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified Map message, length delimited. Does not implicitly {@link + * onnx.TypeProto.Map.verify|verify} messages. + * @param message Map message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: onnx.TypeProto.IMap, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a Map message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns Map + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): onnx.TypeProto.Map; + + /** + * Decodes a Map message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns Map + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): onnx.TypeProto.Map; + + /** + * Verifies a Map message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: {[k: string]: any}): (string|null); + + /** + * Creates a Map message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns Map + */ + public static fromObject(object: {[k: string]: any}): onnx.TypeProto.Map; + + /** + * Creates a plain object from a Map message. Also converts values to other types if specified. + * @param message Map + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: onnx.TypeProto.Map, options?: $protobuf.IConversionOptions): {[k: string]: any}; + + /** + * Converts this Map to JSON. + * @returns JSON object + */ + public toJSON(): {[k: string]: any}; + + /** + * Gets the default type url for Map + * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns The default type url + */ + public static getTypeUrl(typeUrlPrefix?: string): string; + } + + /** Properties of an Optional. */ + interface IOptional { + /** Optional elemType */ + elemType?: (onnx.ITypeProto|null); + } + + /** Represents an Optional. */ + class Optional implements IOptional { + /** + * Constructs a new Optional. + * @param [properties] Properties to set + */ + constructor(properties?: onnx.TypeProto.IOptional); + + /** Optional elemType. */ + public elemType?: (onnx.ITypeProto|null); + + /** + * Creates a new Optional instance using the specified properties. + * @param [properties] Properties to set + * @returns Optional instance + */ + public static create(properties?: onnx.TypeProto.IOptional): onnx.TypeProto.Optional; + + /** + * Encodes the specified Optional message. Does not implicitly {@link onnx.TypeProto.Optional.verify|verify} + * messages. + * @param message Optional message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: onnx.TypeProto.IOptional, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified Optional message, length delimited. Does not implicitly {@link + * onnx.TypeProto.Optional.verify|verify} messages. + * @param message Optional message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: onnx.TypeProto.IOptional, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes an Optional message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns Optional + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): onnx.TypeProto.Optional; + + /** + * Decodes an Optional message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns Optional + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): onnx.TypeProto.Optional; + + /** + * Verifies an Optional message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: {[k: string]: any}): (string|null); + + /** + * Creates an Optional message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns Optional + */ + public static fromObject(object: {[k: string]: any}): onnx.TypeProto.Optional; + + /** + * Creates a plain object from an Optional message. Also converts values to other types if specified. + * @param message Optional + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: onnx.TypeProto.Optional, options?: $protobuf.IConversionOptions): + {[k: string]: any}; + + /** + * Converts this Optional to JSON. + * @returns JSON object + */ + public toJSON(): {[k: string]: any}; + + /** + * Gets the default type url for Optional + * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns The default type url + */ + public static getTypeUrl(typeUrlPrefix?: string): string; + } + + /** Properties of a SparseTensor. */ + interface ISparseTensor { + /** SparseTensor elemType */ + elemType?: (number|null); + + /** SparseTensor shape */ + shape?: (onnx.ITensorShapeProto|null); + } + + /** Represents a SparseTensor. */ + class SparseTensor implements ISparseTensor { + /** + * Constructs a new SparseTensor. + * @param [properties] Properties to set + */ + constructor(properties?: onnx.TypeProto.ISparseTensor); + + /** SparseTensor elemType. */ + public elemType: number; + + /** SparseTensor shape. */ + public shape?: (onnx.ITensorShapeProto|null); + + /** + * Creates a new SparseTensor instance using the specified properties. + * @param [properties] Properties to set + * @returns SparseTensor instance + */ + public static create(properties?: onnx.TypeProto.ISparseTensor): onnx.TypeProto.SparseTensor; + + /** + * Encodes the specified SparseTensor message. Does not implicitly {@link + * onnx.TypeProto.SparseTensor.verify|verify} messages. + * @param message SparseTensor message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: onnx.TypeProto.ISparseTensor, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified SparseTensor message, length delimited. Does not implicitly {@link + * onnx.TypeProto.SparseTensor.verify|verify} messages. + * @param message SparseTensor message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: onnx.TypeProto.ISparseTensor, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a SparseTensor message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns SparseTensor + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): onnx.TypeProto.SparseTensor; + + /** + * Decodes a SparseTensor message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns SparseTensor + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): onnx.TypeProto.SparseTensor; + + /** + * Verifies a SparseTensor message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: {[k: string]: any}): (string|null); + + /** + * Creates a SparseTensor message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns SparseTensor + */ + public static fromObject(object: {[k: string]: any}): onnx.TypeProto.SparseTensor; + + /** + * Creates a plain object from a SparseTensor message. Also converts values to other types if specified. + * @param message SparseTensor + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: onnx.TypeProto.SparseTensor, options?: $protobuf.IConversionOptions): + {[k: string]: any}; + + /** + * Converts this SparseTensor to JSON. + * @returns JSON object + */ + public toJSON(): {[k: string]: any}; + + /** + * Gets the default type url for SparseTensor + * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns The default type url + */ + public static getTypeUrl(typeUrlPrefix?: string): string; + } + } + + /** Properties of an OperatorSetIdProto. */ + interface IOperatorSetIdProto { + /** OperatorSetIdProto domain */ + domain?: (string|null); + + /** OperatorSetIdProto version */ + version?: (number|Long|null); + } + + /** Represents an OperatorSetIdProto. */ + class OperatorSetIdProto implements IOperatorSetIdProto { + /** + * Constructs a new OperatorSetIdProto. + * @param [properties] Properties to set + */ + constructor(properties?: onnx.IOperatorSetIdProto); + + /** OperatorSetIdProto domain. */ + public domain: string; + + /** OperatorSetIdProto version. */ + public version: (number|Long); + + /** + * Creates a new OperatorSetIdProto instance using the specified properties. + * @param [properties] Properties to set + * @returns OperatorSetIdProto instance + */ + public static create(properties?: onnx.IOperatorSetIdProto): onnx.OperatorSetIdProto; + + /** + * Encodes the specified OperatorSetIdProto message. Does not implicitly {@link + * onnx.OperatorSetIdProto.verify|verify} messages. + * @param message OperatorSetIdProto message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: onnx.IOperatorSetIdProto, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified OperatorSetIdProto message, length delimited. Does not implicitly {@link + * onnx.OperatorSetIdProto.verify|verify} messages. + * @param message OperatorSetIdProto message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: onnx.IOperatorSetIdProto, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes an OperatorSetIdProto message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns OperatorSetIdProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): onnx.OperatorSetIdProto; + + /** + * Decodes an OperatorSetIdProto message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns OperatorSetIdProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): onnx.OperatorSetIdProto; + + /** + * Verifies an OperatorSetIdProto message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: {[k: string]: any}): (string|null); + + /** + * Creates an OperatorSetIdProto message from a plain object. Also converts values to their respective internal + * types. + * @param object Plain object + * @returns OperatorSetIdProto + */ + public static fromObject(object: {[k: string]: any}): onnx.OperatorSetIdProto; + + /** + * Creates a plain object from an OperatorSetIdProto message. Also converts values to other types if specified. + * @param message OperatorSetIdProto + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: onnx.OperatorSetIdProto, options?: $protobuf.IConversionOptions): + {[k: string]: any}; + + /** + * Converts this OperatorSetIdProto to JSON. + * @returns JSON object + */ + public toJSON(): {[k: string]: any}; + + /** + * Gets the default type url for OperatorSetIdProto + * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns The default type url + */ + public static getTypeUrl(typeUrlPrefix?: string): string; + } + + /** OperatorStatus enum. */ + enum OperatorStatus { EXPERIMENTAL = 0, STABLE = 1 } + + /** Properties of a FunctionProto. */ + interface IFunctionProto { + /** FunctionProto name */ + name?: (string|null); + + /** FunctionProto input */ + input?: (string[]|null); + + /** FunctionProto output */ + output?: (string[]|null); + + /** FunctionProto attribute */ + attribute?: (string[]|null); + + /** FunctionProto attributeProto */ + attributeProto?: (onnx.IAttributeProto[]|null); + + /** FunctionProto node */ + node?: (onnx.INodeProto[]|null); + + /** FunctionProto docString */ + docString?: (string|null); + + /** FunctionProto opsetImport */ + opsetImport?: (onnx.IOperatorSetIdProto[]|null); + + /** FunctionProto domain */ + domain?: (string|null); + } + + /** Represents a FunctionProto. */ + class FunctionProto implements IFunctionProto { + /** + * Constructs a new FunctionProto. + * @param [properties] Properties to set + */ + constructor(properties?: onnx.IFunctionProto); + + /** FunctionProto name. */ + public name: string; + + /** FunctionProto input. */ + public input: string[]; + + /** FunctionProto output. */ + public output: string[]; + + /** FunctionProto attribute. */ + public attribute: string[]; + + /** FunctionProto attributeProto. */ + public attributeProto: onnx.IAttributeProto[]; + + /** FunctionProto node. */ + public node: onnx.INodeProto[]; + + /** FunctionProto docString. */ + public docString: string; + + /** FunctionProto opsetImport. */ + public opsetImport: onnx.IOperatorSetIdProto[]; + + /** FunctionProto domain. */ + public domain: string; + + /** + * Creates a new FunctionProto instance using the specified properties. + * @param [properties] Properties to set + * @returns FunctionProto instance + */ + public static create(properties?: onnx.IFunctionProto): onnx.FunctionProto; + + /** + * Encodes the specified FunctionProto message. Does not implicitly {@link onnx.FunctionProto.verify|verify} + * messages. + * @param message FunctionProto message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: onnx.IFunctionProto, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified FunctionProto message, length delimited. Does not implicitly {@link + * onnx.FunctionProto.verify|verify} messages. + * @param message FunctionProto message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: onnx.IFunctionProto, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a FunctionProto message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns FunctionProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): onnx.FunctionProto; + + /** + * Decodes a FunctionProto message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns FunctionProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): onnx.FunctionProto; + + /** + * Verifies a FunctionProto message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: {[k: string]: any}): (string|null); + + /** + * Creates a FunctionProto message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns FunctionProto + */ + public static fromObject(object: {[k: string]: any}): onnx.FunctionProto; + + /** + * Creates a plain object from a FunctionProto message. Also converts values to other types if specified. + * @param message FunctionProto + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: onnx.FunctionProto, options?: $protobuf.IConversionOptions): {[k: string]: any}; + + /** + * Converts this FunctionProto to JSON. + * @returns JSON object + */ + public toJSON(): {[k: string]: any}; + + /** + * Gets the default type url for FunctionProto + * @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns The default type url + */ + public static getTypeUrl(typeUrlPrefix?: string): string; + } +} diff --git a/js/web/lib/onnxjs/ort-schema/protobuf/onnx.js b/js/web/lib/onnxjs/ort-schema/protobuf/onnx.js new file mode 100644 index 0000000000000..681855132d4e8 --- /dev/null +++ b/js/web/lib/onnxjs/ort-schema/protobuf/onnx.js @@ -0,0 +1,7658 @@ +/*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/ +"use strict"; + +var $protobuf = require("protobufjs/minimal"); + +// Common aliases +var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util; + +// Exported root namespace +var $root = $protobuf.roots["default"] || ($protobuf.roots["default"] = {}); + +$root.onnx = (function() { + + /** + * Namespace onnx. + * @exports onnx + * @namespace + */ + var onnx = {}; + + /** + * Version enum. + * @name onnx.Version + * @enum {number} + * @property {number} _START_VERSION=0 _START_VERSION value + * @property {number} IR_VERSION_2017_10_10=1 IR_VERSION_2017_10_10 value + * @property {number} IR_VERSION_2017_10_30=2 IR_VERSION_2017_10_30 value + * @property {number} IR_VERSION_2017_11_3=3 IR_VERSION_2017_11_3 value + * @property {number} IR_VERSION_2019_1_22=4 IR_VERSION_2019_1_22 value + * @property {number} IR_VERSION_2019_3_18=5 IR_VERSION_2019_3_18 value + * @property {number} IR_VERSION_2019_9_19=6 IR_VERSION_2019_9_19 value + * @property {number} IR_VERSION_2020_5_8=7 IR_VERSION_2020_5_8 value + * @property {number} IR_VERSION_2021_7_30=8 IR_VERSION_2021_7_30 value + * @property {number} IR_VERSION=9 IR_VERSION value + */ + onnx.Version = (function() { + var valuesById = {}, values = Object.create(valuesById); + values[valuesById[0] = "_START_VERSION"] = 0; + values[valuesById[1] = "IR_VERSION_2017_10_10"] = 1; + values[valuesById[2] = "IR_VERSION_2017_10_30"] = 2; + values[valuesById[3] = "IR_VERSION_2017_11_3"] = 3; + values[valuesById[4] = "IR_VERSION_2019_1_22"] = 4; + values[valuesById[5] = "IR_VERSION_2019_3_18"] = 5; + values[valuesById[6] = "IR_VERSION_2019_9_19"] = 6; + values[valuesById[7] = "IR_VERSION_2020_5_8"] = 7; + values[valuesById[8] = "IR_VERSION_2021_7_30"] = 8; + values[valuesById[9] = "IR_VERSION"] = 9; + return values; + })(); + + onnx.AttributeProto = (function() { + + /** + * Properties of an AttributeProto. + * @memberof onnx + * @interface IAttributeProto + * @property {string|null} [name] AttributeProto name + * @property {string|null} [refAttrName] AttributeProto refAttrName + * @property {string|null} [docString] AttributeProto docString + * @property {onnx.AttributeProto.AttributeType|null} [type] AttributeProto type + * @property {number|null} [f] AttributeProto f + * @property {number|Long|null} [i] AttributeProto i + * @property {Uint8Array|null} [s] AttributeProto s + * @property {onnx.ITensorProto|null} [t] AttributeProto t + * @property {onnx.IGraphProto|null} [g] AttributeProto g + * @property {onnx.ISparseTensorProto|null} [sparseTensor] AttributeProto sparseTensor + * @property {onnx.ITypeProto|null} [tp] AttributeProto tp + * @property {Array.|null} [floats] AttributeProto floats + * @property {Array.|null} [ints] AttributeProto ints + * @property {Array.|null} [strings] AttributeProto strings + * @property {Array.|null} [tensors] AttributeProto tensors + * @property {Array.|null} [graphs] AttributeProto graphs + * @property {Array.|null} [sparseTensors] AttributeProto sparseTensors + * @property {Array.|null} [typeProtos] AttributeProto typeProtos + */ + + /** + * Constructs a new AttributeProto. + * @memberof onnx + * @classdesc Represents an AttributeProto. + * @implements IAttributeProto + * @constructor + * @param {onnx.IAttributeProto=} [properties] Properties to set + */ + function AttributeProto(properties) { + this.floats = []; + this.ints = []; + this.strings = []; + this.tensors = []; + this.graphs = []; + this.sparseTensors = []; + this.typeProtos = []; + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * AttributeProto name. + * @member {string} name + * @memberof onnx.AttributeProto + * @instance + */ + AttributeProto.prototype.name = ""; + + /** + * AttributeProto refAttrName. + * @member {string} refAttrName + * @memberof onnx.AttributeProto + * @instance + */ + AttributeProto.prototype.refAttrName = ""; + + /** + * AttributeProto docString. + * @member {string} docString + * @memberof onnx.AttributeProto + * @instance + */ + AttributeProto.prototype.docString = ""; + + /** + * AttributeProto type. + * @member {onnx.AttributeProto.AttributeType} type + * @memberof onnx.AttributeProto + * @instance + */ + AttributeProto.prototype.type = 0; + + /** + * AttributeProto f. + * @member {number} f + * @memberof onnx.AttributeProto + * @instance + */ + AttributeProto.prototype.f = 0; + + /** + * AttributeProto i. + * @member {number|Long} i + * @memberof onnx.AttributeProto + * @instance + */ + AttributeProto.prototype.i = $util.Long ? $util.Long.fromBits(0,0,false) : 0; + + /** + * AttributeProto s. + * @member {Uint8Array} s + * @memberof onnx.AttributeProto + * @instance + */ + AttributeProto.prototype.s = $util.newBuffer([]); + + /** + * AttributeProto t. + * @member {onnx.ITensorProto|null|undefined} t + * @memberof onnx.AttributeProto + * @instance + */ + AttributeProto.prototype.t = null; + + /** + * AttributeProto g. + * @member {onnx.IGraphProto|null|undefined} g + * @memberof onnx.AttributeProto + * @instance + */ + AttributeProto.prototype.g = null; + + /** + * AttributeProto sparseTensor. + * @member {onnx.ISparseTensorProto|null|undefined} sparseTensor + * @memberof onnx.AttributeProto + * @instance + */ + AttributeProto.prototype.sparseTensor = null; + + /** + * AttributeProto tp. + * @member {onnx.ITypeProto|null|undefined} tp + * @memberof onnx.AttributeProto + * @instance + */ + AttributeProto.prototype.tp = null; + + /** + * AttributeProto floats. + * @member {Array.} floats + * @memberof onnx.AttributeProto + * @instance + */ + AttributeProto.prototype.floats = $util.emptyArray; + + /** + * AttributeProto ints. + * @member {Array.} ints + * @memberof onnx.AttributeProto + * @instance + */ + AttributeProto.prototype.ints = $util.emptyArray; + + /** + * AttributeProto strings. + * @member {Array.} strings + * @memberof onnx.AttributeProto + * @instance + */ + AttributeProto.prototype.strings = $util.emptyArray; + + /** + * AttributeProto tensors. + * @member {Array.} tensors + * @memberof onnx.AttributeProto + * @instance + */ + AttributeProto.prototype.tensors = $util.emptyArray; + + /** + * AttributeProto graphs. + * @member {Array.} graphs + * @memberof onnx.AttributeProto + * @instance + */ + AttributeProto.prototype.graphs = $util.emptyArray; + + /** + * AttributeProto sparseTensors. + * @member {Array.} sparseTensors + * @memberof onnx.AttributeProto + * @instance + */ + AttributeProto.prototype.sparseTensors = $util.emptyArray; + + /** + * AttributeProto typeProtos. + * @member {Array.} typeProtos + * @memberof onnx.AttributeProto + * @instance + */ + AttributeProto.prototype.typeProtos = $util.emptyArray; + + /** + * Creates a new AttributeProto instance using the specified properties. + * @function create + * @memberof onnx.AttributeProto + * @static + * @param {onnx.IAttributeProto=} [properties] Properties to set + * @returns {onnx.AttributeProto} AttributeProto instance + */ + AttributeProto.create = function create(properties) { + return new AttributeProto(properties); + }; + + /** + * Encodes the specified AttributeProto message. Does not implicitly {@link onnx.AttributeProto.verify|verify} messages. + * @function encode + * @memberof onnx.AttributeProto + * @static + * @param {onnx.IAttributeProto} message AttributeProto message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + AttributeProto.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.name != null && Object.hasOwnProperty.call(message, "name")) + writer.uint32(/* id 1, wireType 2 =*/10).string(message.name); + if (message.f != null && Object.hasOwnProperty.call(message, "f")) + writer.uint32(/* id 2, wireType 5 =*/21).float(message.f); + if (message.i != null && Object.hasOwnProperty.call(message, "i")) + writer.uint32(/* id 3, wireType 0 =*/24).int64(message.i); + if (message.s != null && Object.hasOwnProperty.call(message, "s")) + writer.uint32(/* id 4, wireType 2 =*/34).bytes(message.s); + if (message.t != null && Object.hasOwnProperty.call(message, "t")) + $root.onnx.TensorProto.encode(message.t, writer.uint32(/* id 5, wireType 2 =*/42).fork()).ldelim(); + if (message.g != null && Object.hasOwnProperty.call(message, "g")) + $root.onnx.GraphProto.encode(message.g, writer.uint32(/* id 6, wireType 2 =*/50).fork()).ldelim(); + if (message.floats != null && message.floats.length) { + writer.uint32(/* id 7, wireType 2 =*/58).fork(); + for (var i = 0; i < message.floats.length; ++i) + writer.float(message.floats[i]); + writer.ldelim(); + } + if (message.ints != null && message.ints.length) { + writer.uint32(/* id 8, wireType 2 =*/66).fork(); + for (var i = 0; i < message.ints.length; ++i) + writer.int64(message.ints[i]); + writer.ldelim(); + } + if (message.strings != null && message.strings.length) + for (var i = 0; i < message.strings.length; ++i) + writer.uint32(/* id 9, wireType 2 =*/74).bytes(message.strings[i]); + if (message.tensors != null && message.tensors.length) + for (var i = 0; i < message.tensors.length; ++i) + $root.onnx.TensorProto.encode(message.tensors[i], writer.uint32(/* id 10, wireType 2 =*/82).fork()).ldelim(); + if (message.graphs != null && message.graphs.length) + for (var i = 0; i < message.graphs.length; ++i) + $root.onnx.GraphProto.encode(message.graphs[i], writer.uint32(/* id 11, wireType 2 =*/90).fork()).ldelim(); + if (message.docString != null && Object.hasOwnProperty.call(message, "docString")) + writer.uint32(/* id 13, wireType 2 =*/106).string(message.docString); + if (message.tp != null && Object.hasOwnProperty.call(message, "tp")) + $root.onnx.TypeProto.encode(message.tp, writer.uint32(/* id 14, wireType 2 =*/114).fork()).ldelim(); + if (message.typeProtos != null && message.typeProtos.length) + for (var i = 0; i < message.typeProtos.length; ++i) + $root.onnx.TypeProto.encode(message.typeProtos[i], writer.uint32(/* id 15, wireType 2 =*/122).fork()).ldelim(); + if (message.type != null && Object.hasOwnProperty.call(message, "type")) + writer.uint32(/* id 20, wireType 0 =*/160).int32(message.type); + if (message.refAttrName != null && Object.hasOwnProperty.call(message, "refAttrName")) + writer.uint32(/* id 21, wireType 2 =*/170).string(message.refAttrName); + if (message.sparseTensor != null && Object.hasOwnProperty.call(message, "sparseTensor")) + $root.onnx.SparseTensorProto.encode(message.sparseTensor, writer.uint32(/* id 22, wireType 2 =*/178).fork()).ldelim(); + if (message.sparseTensors != null && message.sparseTensors.length) + for (var i = 0; i < message.sparseTensors.length; ++i) + $root.onnx.SparseTensorProto.encode(message.sparseTensors[i], writer.uint32(/* id 23, wireType 2 =*/186).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified AttributeProto message, length delimited. Does not implicitly {@link onnx.AttributeProto.verify|verify} messages. + * @function encodeDelimited + * @memberof onnx.AttributeProto + * @static + * @param {onnx.IAttributeProto} message AttributeProto message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + AttributeProto.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes an AttributeProto message from the specified reader or buffer. + * @function decode + * @memberof onnx.AttributeProto + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {onnx.AttributeProto} AttributeProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + AttributeProto.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.onnx.AttributeProto(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + message.name = reader.string(); + break; + } + case 21: { + message.refAttrName = reader.string(); + break; + } + case 13: { + message.docString = reader.string(); + break; + } + case 20: { + message.type = reader.int32(); + break; + } + case 2: { + message.f = reader.float(); + break; + } + case 3: { + message.i = reader.int64(); + break; + } + case 4: { + message.s = reader.bytes(); + break; + } + case 5: { + message.t = $root.onnx.TensorProto.decode(reader, reader.uint32()); + break; + } + case 6: { + message.g = $root.onnx.GraphProto.decode(reader, reader.uint32()); + break; + } + case 22: { + message.sparseTensor = $root.onnx.SparseTensorProto.decode(reader, reader.uint32()); + break; + } + case 14: { + message.tp = $root.onnx.TypeProto.decode(reader, reader.uint32()); + break; + } + case 7: { + if (!(message.floats && message.floats.length)) + message.floats = []; + if ((tag & 7) === 2) { + var end2 = reader.uint32() + reader.pos; + while (reader.pos < end2) + message.floats.push(reader.float()); + } else + message.floats.push(reader.float()); + break; + } + case 8: { + if (!(message.ints && message.ints.length)) + message.ints = []; + if ((tag & 7) === 2) { + var end2 = reader.uint32() + reader.pos; + while (reader.pos < end2) + message.ints.push(reader.int64()); + } else + message.ints.push(reader.int64()); + break; + } + case 9: { + if (!(message.strings && message.strings.length)) + message.strings = []; + message.strings.push(reader.bytes()); + break; + } + case 10: { + if (!(message.tensors && message.tensors.length)) + message.tensors = []; + message.tensors.push($root.onnx.TensorProto.decode(reader, reader.uint32())); + break; + } + case 11: { + if (!(message.graphs && message.graphs.length)) + message.graphs = []; + message.graphs.push($root.onnx.GraphProto.decode(reader, reader.uint32())); + break; + } + case 23: { + if (!(message.sparseTensors && message.sparseTensors.length)) + message.sparseTensors = []; + message.sparseTensors.push($root.onnx.SparseTensorProto.decode(reader, reader.uint32())); + break; + } + case 15: { + if (!(message.typeProtos && message.typeProtos.length)) + message.typeProtos = []; + message.typeProtos.push($root.onnx.TypeProto.decode(reader, reader.uint32())); + break; + } + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes an AttributeProto message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof onnx.AttributeProto + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {onnx.AttributeProto} AttributeProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + AttributeProto.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies an AttributeProto message. + * @function verify + * @memberof onnx.AttributeProto + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + AttributeProto.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.name != null && message.hasOwnProperty("name")) + if (!$util.isString(message.name)) + return "name: string expected"; + if (message.refAttrName != null && message.hasOwnProperty("refAttrName")) + if (!$util.isString(message.refAttrName)) + return "refAttrName: string expected"; + if (message.docString != null && message.hasOwnProperty("docString")) + if (!$util.isString(message.docString)) + return "docString: string expected"; + if (message.type != null && message.hasOwnProperty("type")) + switch (message.type) { + default: + return "type: enum value expected"; + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 11: + case 13: + case 6: + case 7: + case 8: + case 9: + case 10: + case 12: + case 14: + break; + } + if (message.f != null && message.hasOwnProperty("f")) + if (typeof message.f !== "number") + return "f: number expected"; + if (message.i != null && message.hasOwnProperty("i")) + if (!$util.isInteger(message.i) && !(message.i && $util.isInteger(message.i.low) && $util.isInteger(message.i.high))) + return "i: integer|Long expected"; + if (message.s != null && message.hasOwnProperty("s")) + if (!(message.s && typeof message.s.length === "number" || $util.isString(message.s))) + return "s: buffer expected"; + if (message.t != null && message.hasOwnProperty("t")) { + var error = $root.onnx.TensorProto.verify(message.t); + if (error) + return "t." + error; + } + if (message.g != null && message.hasOwnProperty("g")) { + var error = $root.onnx.GraphProto.verify(message.g); + if (error) + return "g." + error; + } + if (message.sparseTensor != null && message.hasOwnProperty("sparseTensor")) { + var error = $root.onnx.SparseTensorProto.verify(message.sparseTensor); + if (error) + return "sparseTensor." + error; + } + if (message.tp != null && message.hasOwnProperty("tp")) { + var error = $root.onnx.TypeProto.verify(message.tp); + if (error) + return "tp." + error; + } + if (message.floats != null && message.hasOwnProperty("floats")) { + if (!Array.isArray(message.floats)) + return "floats: array expected"; + for (var i = 0; i < message.floats.length; ++i) + if (typeof message.floats[i] !== "number") + return "floats: number[] expected"; + } + if (message.ints != null && message.hasOwnProperty("ints")) { + if (!Array.isArray(message.ints)) + return "ints: array expected"; + for (var i = 0; i < message.ints.length; ++i) + if (!$util.isInteger(message.ints[i]) && !(message.ints[i] && $util.isInteger(message.ints[i].low) && $util.isInteger(message.ints[i].high))) + return "ints: integer|Long[] expected"; + } + if (message.strings != null && message.hasOwnProperty("strings")) { + if (!Array.isArray(message.strings)) + return "strings: array expected"; + for (var i = 0; i < message.strings.length; ++i) + if (!(message.strings[i] && typeof message.strings[i].length === "number" || $util.isString(message.strings[i]))) + return "strings: buffer[] expected"; + } + if (message.tensors != null && message.hasOwnProperty("tensors")) { + if (!Array.isArray(message.tensors)) + return "tensors: array expected"; + for (var i = 0; i < message.tensors.length; ++i) { + var error = $root.onnx.TensorProto.verify(message.tensors[i]); + if (error) + return "tensors." + error; + } + } + if (message.graphs != null && message.hasOwnProperty("graphs")) { + if (!Array.isArray(message.graphs)) + return "graphs: array expected"; + for (var i = 0; i < message.graphs.length; ++i) { + var error = $root.onnx.GraphProto.verify(message.graphs[i]); + if (error) + return "graphs." + error; + } + } + if (message.sparseTensors != null && message.hasOwnProperty("sparseTensors")) { + if (!Array.isArray(message.sparseTensors)) + return "sparseTensors: array expected"; + for (var i = 0; i < message.sparseTensors.length; ++i) { + var error = $root.onnx.SparseTensorProto.verify(message.sparseTensors[i]); + if (error) + return "sparseTensors." + error; + } + } + if (message.typeProtos != null && message.hasOwnProperty("typeProtos")) { + if (!Array.isArray(message.typeProtos)) + return "typeProtos: array expected"; + for (var i = 0; i < message.typeProtos.length; ++i) { + var error = $root.onnx.TypeProto.verify(message.typeProtos[i]); + if (error) + return "typeProtos." + error; + } + } + return null; + }; + + /** + * Creates an AttributeProto message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof onnx.AttributeProto + * @static + * @param {Object.} object Plain object + * @returns {onnx.AttributeProto} AttributeProto + */ + AttributeProto.fromObject = function fromObject(object) { + if (object instanceof $root.onnx.AttributeProto) + return object; + var message = new $root.onnx.AttributeProto(); + if (object.name != null) + message.name = String(object.name); + if (object.refAttrName != null) + message.refAttrName = String(object.refAttrName); + if (object.docString != null) + message.docString = String(object.docString); + switch (object.type) { + default: + if (typeof object.type === "number") { + message.type = object.type; + break; + } + break; + case "UNDEFINED": + case 0: + message.type = 0; + break; + case "FLOAT": + case 1: + message.type = 1; + break; + case "INT": + case 2: + message.type = 2; + break; + case "STRING": + case 3: + message.type = 3; + break; + case "TENSOR": + case 4: + message.type = 4; + break; + case "GRAPH": + case 5: + message.type = 5; + break; + case "SPARSE_TENSOR": + case 11: + message.type = 11; + break; + case "TYPE_PROTO": + case 13: + message.type = 13; + break; + case "FLOATS": + case 6: + message.type = 6; + break; + case "INTS": + case 7: + message.type = 7; + break; + case "STRINGS": + case 8: + message.type = 8; + break; + case "TENSORS": + case 9: + message.type = 9; + break; + case "GRAPHS": + case 10: + message.type = 10; + break; + case "SPARSE_TENSORS": + case 12: + message.type = 12; + break; + case "TYPE_PROTOS": + case 14: + message.type = 14; + break; + } + if (object.f != null) + message.f = Number(object.f); + if (object.i != null) + if ($util.Long) + (message.i = $util.Long.fromValue(object.i)).unsigned = false; + else if (typeof object.i === "string") + message.i = parseInt(object.i, 10); + else if (typeof object.i === "number") + message.i = object.i; + else if (typeof object.i === "object") + message.i = new $util.LongBits(object.i.low >>> 0, object.i.high >>> 0).toNumber(); + if (object.s != null) + if (typeof object.s === "string") + $util.base64.decode(object.s, message.s = $util.newBuffer($util.base64.length(object.s)), 0); + else if (object.s.length >= 0) + message.s = object.s; + if (object.t != null) { + if (typeof object.t !== "object") + throw TypeError(".onnx.AttributeProto.t: object expected"); + message.t = $root.onnx.TensorProto.fromObject(object.t); + } + if (object.g != null) { + if (typeof object.g !== "object") + throw TypeError(".onnx.AttributeProto.g: object expected"); + message.g = $root.onnx.GraphProto.fromObject(object.g); + } + if (object.sparseTensor != null) { + if (typeof object.sparseTensor !== "object") + throw TypeError(".onnx.AttributeProto.sparseTensor: object expected"); + message.sparseTensor = $root.onnx.SparseTensorProto.fromObject(object.sparseTensor); + } + if (object.tp != null) { + if (typeof object.tp !== "object") + throw TypeError(".onnx.AttributeProto.tp: object expected"); + message.tp = $root.onnx.TypeProto.fromObject(object.tp); + } + if (object.floats) { + if (!Array.isArray(object.floats)) + throw TypeError(".onnx.AttributeProto.floats: array expected"); + message.floats = []; + for (var i = 0; i < object.floats.length; ++i) + message.floats[i] = Number(object.floats[i]); + } + if (object.ints) { + if (!Array.isArray(object.ints)) + throw TypeError(".onnx.AttributeProto.ints: array expected"); + message.ints = []; + for (var i = 0; i < object.ints.length; ++i) + if ($util.Long) + (message.ints[i] = $util.Long.fromValue(object.ints[i])).unsigned = false; + else if (typeof object.ints[i] === "string") + message.ints[i] = parseInt(object.ints[i], 10); + else if (typeof object.ints[i] === "number") + message.ints[i] = object.ints[i]; + else if (typeof object.ints[i] === "object") + message.ints[i] = new $util.LongBits(object.ints[i].low >>> 0, object.ints[i].high >>> 0).toNumber(); + } + if (object.strings) { + if (!Array.isArray(object.strings)) + throw TypeError(".onnx.AttributeProto.strings: array expected"); + message.strings = []; + for (var i = 0; i < object.strings.length; ++i) + if (typeof object.strings[i] === "string") + $util.base64.decode(object.strings[i], message.strings[i] = $util.newBuffer($util.base64.length(object.strings[i])), 0); + else if (object.strings[i].length >= 0) + message.strings[i] = object.strings[i]; + } + if (object.tensors) { + if (!Array.isArray(object.tensors)) + throw TypeError(".onnx.AttributeProto.tensors: array expected"); + message.tensors = []; + for (var i = 0; i < object.tensors.length; ++i) { + if (typeof object.tensors[i] !== "object") + throw TypeError(".onnx.AttributeProto.tensors: object expected"); + message.tensors[i] = $root.onnx.TensorProto.fromObject(object.tensors[i]); + } + } + if (object.graphs) { + if (!Array.isArray(object.graphs)) + throw TypeError(".onnx.AttributeProto.graphs: array expected"); + message.graphs = []; + for (var i = 0; i < object.graphs.length; ++i) { + if (typeof object.graphs[i] !== "object") + throw TypeError(".onnx.AttributeProto.graphs: object expected"); + message.graphs[i] = $root.onnx.GraphProto.fromObject(object.graphs[i]); + } + } + if (object.sparseTensors) { + if (!Array.isArray(object.sparseTensors)) + throw TypeError(".onnx.AttributeProto.sparseTensors: array expected"); + message.sparseTensors = []; + for (var i = 0; i < object.sparseTensors.length; ++i) { + if (typeof object.sparseTensors[i] !== "object") + throw TypeError(".onnx.AttributeProto.sparseTensors: object expected"); + message.sparseTensors[i] = $root.onnx.SparseTensorProto.fromObject(object.sparseTensors[i]); + } + } + if (object.typeProtos) { + if (!Array.isArray(object.typeProtos)) + throw TypeError(".onnx.AttributeProto.typeProtos: array expected"); + message.typeProtos = []; + for (var i = 0; i < object.typeProtos.length; ++i) { + if (typeof object.typeProtos[i] !== "object") + throw TypeError(".onnx.AttributeProto.typeProtos: object expected"); + message.typeProtos[i] = $root.onnx.TypeProto.fromObject(object.typeProtos[i]); + } + } + return message; + }; + + /** + * Creates a plain object from an AttributeProto message. Also converts values to other types if specified. + * @function toObject + * @memberof onnx.AttributeProto + * @static + * @param {onnx.AttributeProto} message AttributeProto + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + AttributeProto.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.arrays || options.defaults) { + object.floats = []; + object.ints = []; + object.strings = []; + object.tensors = []; + object.graphs = []; + object.typeProtos = []; + object.sparseTensors = []; + } + if (options.defaults) { + object.name = ""; + object.f = 0; + if ($util.Long) { + var long = new $util.Long(0, 0, false); + object.i = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long; + } else + object.i = options.longs === String ? "0" : 0; + if (options.bytes === String) + object.s = ""; + else { + object.s = []; + if (options.bytes !== Array) + object.s = $util.newBuffer(object.s); + } + object.t = null; + object.g = null; + object.docString = ""; + object.tp = null; + object.type = options.enums === String ? "UNDEFINED" : 0; + object.refAttrName = ""; + object.sparseTensor = null; + } + if (message.name != null && message.hasOwnProperty("name")) + object.name = message.name; + if (message.f != null && message.hasOwnProperty("f")) + object.f = options.json && !isFinite(message.f) ? String(message.f) : message.f; + if (message.i != null && message.hasOwnProperty("i")) + if (typeof message.i === "number") + object.i = options.longs === String ? String(message.i) : message.i; + else + object.i = options.longs === String ? $util.Long.prototype.toString.call(message.i) : options.longs === Number ? new $util.LongBits(message.i.low >>> 0, message.i.high >>> 0).toNumber() : message.i; + if (message.s != null && message.hasOwnProperty("s")) + object.s = options.bytes === String ? $util.base64.encode(message.s, 0, message.s.length) : options.bytes === Array ? Array.prototype.slice.call(message.s) : message.s; + if (message.t != null && message.hasOwnProperty("t")) + object.t = $root.onnx.TensorProto.toObject(message.t, options); + if (message.g != null && message.hasOwnProperty("g")) + object.g = $root.onnx.GraphProto.toObject(message.g, options); + if (message.floats && message.floats.length) { + object.floats = []; + for (var j = 0; j < message.floats.length; ++j) + object.floats[j] = options.json && !isFinite(message.floats[j]) ? String(message.floats[j]) : message.floats[j]; + } + if (message.ints && message.ints.length) { + object.ints = []; + for (var j = 0; j < message.ints.length; ++j) + if (typeof message.ints[j] === "number") + object.ints[j] = options.longs === String ? String(message.ints[j]) : message.ints[j]; + else + object.ints[j] = options.longs === String ? $util.Long.prototype.toString.call(message.ints[j]) : options.longs === Number ? new $util.LongBits(message.ints[j].low >>> 0, message.ints[j].high >>> 0).toNumber() : message.ints[j]; + } + if (message.strings && message.strings.length) { + object.strings = []; + for (var j = 0; j < message.strings.length; ++j) + object.strings[j] = options.bytes === String ? $util.base64.encode(message.strings[j], 0, message.strings[j].length) : options.bytes === Array ? Array.prototype.slice.call(message.strings[j]) : message.strings[j]; + } + if (message.tensors && message.tensors.length) { + object.tensors = []; + for (var j = 0; j < message.tensors.length; ++j) + object.tensors[j] = $root.onnx.TensorProto.toObject(message.tensors[j], options); + } + if (message.graphs && message.graphs.length) { + object.graphs = []; + for (var j = 0; j < message.graphs.length; ++j) + object.graphs[j] = $root.onnx.GraphProto.toObject(message.graphs[j], options); + } + if (message.docString != null && message.hasOwnProperty("docString")) + object.docString = message.docString; + if (message.tp != null && message.hasOwnProperty("tp")) + object.tp = $root.onnx.TypeProto.toObject(message.tp, options); + if (message.typeProtos && message.typeProtos.length) { + object.typeProtos = []; + for (var j = 0; j < message.typeProtos.length; ++j) + object.typeProtos[j] = $root.onnx.TypeProto.toObject(message.typeProtos[j], options); + } + if (message.type != null && message.hasOwnProperty("type")) + object.type = options.enums === String ? $root.onnx.AttributeProto.AttributeType[message.type] === undefined ? message.type : $root.onnx.AttributeProto.AttributeType[message.type] : message.type; + if (message.refAttrName != null && message.hasOwnProperty("refAttrName")) + object.refAttrName = message.refAttrName; + if (message.sparseTensor != null && message.hasOwnProperty("sparseTensor")) + object.sparseTensor = $root.onnx.SparseTensorProto.toObject(message.sparseTensor, options); + if (message.sparseTensors && message.sparseTensors.length) { + object.sparseTensors = []; + for (var j = 0; j < message.sparseTensors.length; ++j) + object.sparseTensors[j] = $root.onnx.SparseTensorProto.toObject(message.sparseTensors[j], options); + } + return object; + }; + + /** + * Converts this AttributeProto to JSON. + * @function toJSON + * @memberof onnx.AttributeProto + * @instance + * @returns {Object.} JSON object + */ + AttributeProto.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + /** + * Gets the default type url for AttributeProto + * @function getTypeUrl + * @memberof onnx.AttributeProto + * @static + * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns {string} The default type url + */ + AttributeProto.getTypeUrl = function getTypeUrl(typeUrlPrefix) { + if (typeUrlPrefix === undefined) { + typeUrlPrefix = "type.googleapis.com"; + } + return typeUrlPrefix + "/onnx.AttributeProto"; + }; + + /** + * AttributeType enum. + * @name onnx.AttributeProto.AttributeType + * @enum {number} + * @property {number} UNDEFINED=0 UNDEFINED value + * @property {number} FLOAT=1 FLOAT value + * @property {number} INT=2 INT value + * @property {number} STRING=3 STRING value + * @property {number} TENSOR=4 TENSOR value + * @property {number} GRAPH=5 GRAPH value + * @property {number} SPARSE_TENSOR=11 SPARSE_TENSOR value + * @property {number} TYPE_PROTO=13 TYPE_PROTO value + * @property {number} FLOATS=6 FLOATS value + * @property {number} INTS=7 INTS value + * @property {number} STRINGS=8 STRINGS value + * @property {number} TENSORS=9 TENSORS value + * @property {number} GRAPHS=10 GRAPHS value + * @property {number} SPARSE_TENSORS=12 SPARSE_TENSORS value + * @property {number} TYPE_PROTOS=14 TYPE_PROTOS value + */ + AttributeProto.AttributeType = (function() { + var valuesById = {}, values = Object.create(valuesById); + values[valuesById[0] = "UNDEFINED"] = 0; + values[valuesById[1] = "FLOAT"] = 1; + values[valuesById[2] = "INT"] = 2; + values[valuesById[3] = "STRING"] = 3; + values[valuesById[4] = "TENSOR"] = 4; + values[valuesById[5] = "GRAPH"] = 5; + values[valuesById[11] = "SPARSE_TENSOR"] = 11; + values[valuesById[13] = "TYPE_PROTO"] = 13; + values[valuesById[6] = "FLOATS"] = 6; + values[valuesById[7] = "INTS"] = 7; + values[valuesById[8] = "STRINGS"] = 8; + values[valuesById[9] = "TENSORS"] = 9; + values[valuesById[10] = "GRAPHS"] = 10; + values[valuesById[12] = "SPARSE_TENSORS"] = 12; + values[valuesById[14] = "TYPE_PROTOS"] = 14; + return values; + })(); + + return AttributeProto; + })(); + + onnx.ValueInfoProto = (function() { + + /** + * Properties of a ValueInfoProto. + * @memberof onnx + * @interface IValueInfoProto + * @property {string|null} [name] ValueInfoProto name + * @property {onnx.ITypeProto|null} [type] ValueInfoProto type + * @property {string|null} [docString] ValueInfoProto docString + */ + + /** + * Constructs a new ValueInfoProto. + * @memberof onnx + * @classdesc Represents a ValueInfoProto. + * @implements IValueInfoProto + * @constructor + * @param {onnx.IValueInfoProto=} [properties] Properties to set + */ + function ValueInfoProto(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * ValueInfoProto name. + * @member {string} name + * @memberof onnx.ValueInfoProto + * @instance + */ + ValueInfoProto.prototype.name = ""; + + /** + * ValueInfoProto type. + * @member {onnx.ITypeProto|null|undefined} type + * @memberof onnx.ValueInfoProto + * @instance + */ + ValueInfoProto.prototype.type = null; + + /** + * ValueInfoProto docString. + * @member {string} docString + * @memberof onnx.ValueInfoProto + * @instance + */ + ValueInfoProto.prototype.docString = ""; + + /** + * Creates a new ValueInfoProto instance using the specified properties. + * @function create + * @memberof onnx.ValueInfoProto + * @static + * @param {onnx.IValueInfoProto=} [properties] Properties to set + * @returns {onnx.ValueInfoProto} ValueInfoProto instance + */ + ValueInfoProto.create = function create(properties) { + return new ValueInfoProto(properties); + }; + + /** + * Encodes the specified ValueInfoProto message. Does not implicitly {@link onnx.ValueInfoProto.verify|verify} messages. + * @function encode + * @memberof onnx.ValueInfoProto + * @static + * @param {onnx.IValueInfoProto} message ValueInfoProto message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + ValueInfoProto.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.name != null && Object.hasOwnProperty.call(message, "name")) + writer.uint32(/* id 1, wireType 2 =*/10).string(message.name); + if (message.type != null && Object.hasOwnProperty.call(message, "type")) + $root.onnx.TypeProto.encode(message.type, writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim(); + if (message.docString != null && Object.hasOwnProperty.call(message, "docString")) + writer.uint32(/* id 3, wireType 2 =*/26).string(message.docString); + return writer; + }; + + /** + * Encodes the specified ValueInfoProto message, length delimited. Does not implicitly {@link onnx.ValueInfoProto.verify|verify} messages. + * @function encodeDelimited + * @memberof onnx.ValueInfoProto + * @static + * @param {onnx.IValueInfoProto} message ValueInfoProto message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + ValueInfoProto.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a ValueInfoProto message from the specified reader or buffer. + * @function decode + * @memberof onnx.ValueInfoProto + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {onnx.ValueInfoProto} ValueInfoProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + ValueInfoProto.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.onnx.ValueInfoProto(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + message.name = reader.string(); + break; + } + case 2: { + message.type = $root.onnx.TypeProto.decode(reader, reader.uint32()); + break; + } + case 3: { + message.docString = reader.string(); + break; + } + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a ValueInfoProto message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof onnx.ValueInfoProto + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {onnx.ValueInfoProto} ValueInfoProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + ValueInfoProto.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a ValueInfoProto message. + * @function verify + * @memberof onnx.ValueInfoProto + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + ValueInfoProto.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.name != null && message.hasOwnProperty("name")) + if (!$util.isString(message.name)) + return "name: string expected"; + if (message.type != null && message.hasOwnProperty("type")) { + var error = $root.onnx.TypeProto.verify(message.type); + if (error) + return "type." + error; + } + if (message.docString != null && message.hasOwnProperty("docString")) + if (!$util.isString(message.docString)) + return "docString: string expected"; + return null; + }; + + /** + * Creates a ValueInfoProto message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof onnx.ValueInfoProto + * @static + * @param {Object.} object Plain object + * @returns {onnx.ValueInfoProto} ValueInfoProto + */ + ValueInfoProto.fromObject = function fromObject(object) { + if (object instanceof $root.onnx.ValueInfoProto) + return object; + var message = new $root.onnx.ValueInfoProto(); + if (object.name != null) + message.name = String(object.name); + if (object.type != null) { + if (typeof object.type !== "object") + throw TypeError(".onnx.ValueInfoProto.type: object expected"); + message.type = $root.onnx.TypeProto.fromObject(object.type); + } + if (object.docString != null) + message.docString = String(object.docString); + return message; + }; + + /** + * Creates a plain object from a ValueInfoProto message. Also converts values to other types if specified. + * @function toObject + * @memberof onnx.ValueInfoProto + * @static + * @param {onnx.ValueInfoProto} message ValueInfoProto + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + ValueInfoProto.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + object.name = ""; + object.type = null; + object.docString = ""; + } + if (message.name != null && message.hasOwnProperty("name")) + object.name = message.name; + if (message.type != null && message.hasOwnProperty("type")) + object.type = $root.onnx.TypeProto.toObject(message.type, options); + if (message.docString != null && message.hasOwnProperty("docString")) + object.docString = message.docString; + return object; + }; + + /** + * Converts this ValueInfoProto to JSON. + * @function toJSON + * @memberof onnx.ValueInfoProto + * @instance + * @returns {Object.} JSON object + */ + ValueInfoProto.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + /** + * Gets the default type url for ValueInfoProto + * @function getTypeUrl + * @memberof onnx.ValueInfoProto + * @static + * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns {string} The default type url + */ + ValueInfoProto.getTypeUrl = function getTypeUrl(typeUrlPrefix) { + if (typeUrlPrefix === undefined) { + typeUrlPrefix = "type.googleapis.com"; + } + return typeUrlPrefix + "/onnx.ValueInfoProto"; + }; + + return ValueInfoProto; + })(); + + onnx.NodeProto = (function() { + + /** + * Properties of a NodeProto. + * @memberof onnx + * @interface INodeProto + * @property {Array.|null} [input] NodeProto input + * @property {Array.|null} [output] NodeProto output + * @property {string|null} [name] NodeProto name + * @property {string|null} [opType] NodeProto opType + * @property {string|null} [domain] NodeProto domain + * @property {Array.|null} [attribute] NodeProto attribute + * @property {string|null} [docString] NodeProto docString + */ + + /** + * Constructs a new NodeProto. + * @memberof onnx + * @classdesc Represents a NodeProto. + * @implements INodeProto + * @constructor + * @param {onnx.INodeProto=} [properties] Properties to set + */ + function NodeProto(properties) { + this.input = []; + this.output = []; + this.attribute = []; + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * NodeProto input. + * @member {Array.} input + * @memberof onnx.NodeProto + * @instance + */ + NodeProto.prototype.input = $util.emptyArray; + + /** + * NodeProto output. + * @member {Array.} output + * @memberof onnx.NodeProto + * @instance + */ + NodeProto.prototype.output = $util.emptyArray; + + /** + * NodeProto name. + * @member {string} name + * @memberof onnx.NodeProto + * @instance + */ + NodeProto.prototype.name = ""; + + /** + * NodeProto opType. + * @member {string} opType + * @memberof onnx.NodeProto + * @instance + */ + NodeProto.prototype.opType = ""; + + /** + * NodeProto domain. + * @member {string} domain + * @memberof onnx.NodeProto + * @instance + */ + NodeProto.prototype.domain = ""; + + /** + * NodeProto attribute. + * @member {Array.} attribute + * @memberof onnx.NodeProto + * @instance + */ + NodeProto.prototype.attribute = $util.emptyArray; + + /** + * NodeProto docString. + * @member {string} docString + * @memberof onnx.NodeProto + * @instance + */ + NodeProto.prototype.docString = ""; + + /** + * Creates a new NodeProto instance using the specified properties. + * @function create + * @memberof onnx.NodeProto + * @static + * @param {onnx.INodeProto=} [properties] Properties to set + * @returns {onnx.NodeProto} NodeProto instance + */ + NodeProto.create = function create(properties) { + return new NodeProto(properties); + }; + + /** + * Encodes the specified NodeProto message. Does not implicitly {@link onnx.NodeProto.verify|verify} messages. + * @function encode + * @memberof onnx.NodeProto + * @static + * @param {onnx.INodeProto} message NodeProto message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + NodeProto.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.input != null && message.input.length) + for (var i = 0; i < message.input.length; ++i) + writer.uint32(/* id 1, wireType 2 =*/10).string(message.input[i]); + if (message.output != null && message.output.length) + for (var i = 0; i < message.output.length; ++i) + writer.uint32(/* id 2, wireType 2 =*/18).string(message.output[i]); + if (message.name != null && Object.hasOwnProperty.call(message, "name")) + writer.uint32(/* id 3, wireType 2 =*/26).string(message.name); + if (message.opType != null && Object.hasOwnProperty.call(message, "opType")) + writer.uint32(/* id 4, wireType 2 =*/34).string(message.opType); + if (message.attribute != null && message.attribute.length) + for (var i = 0; i < message.attribute.length; ++i) + $root.onnx.AttributeProto.encode(message.attribute[i], writer.uint32(/* id 5, wireType 2 =*/42).fork()).ldelim(); + if (message.docString != null && Object.hasOwnProperty.call(message, "docString")) + writer.uint32(/* id 6, wireType 2 =*/50).string(message.docString); + if (message.domain != null && Object.hasOwnProperty.call(message, "domain")) + writer.uint32(/* id 7, wireType 2 =*/58).string(message.domain); + return writer; + }; + + /** + * Encodes the specified NodeProto message, length delimited. Does not implicitly {@link onnx.NodeProto.verify|verify} messages. + * @function encodeDelimited + * @memberof onnx.NodeProto + * @static + * @param {onnx.INodeProto} message NodeProto message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + NodeProto.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a NodeProto message from the specified reader or buffer. + * @function decode + * @memberof onnx.NodeProto + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {onnx.NodeProto} NodeProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + NodeProto.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.onnx.NodeProto(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (!(message.input && message.input.length)) + message.input = []; + message.input.push(reader.string()); + break; + } + case 2: { + if (!(message.output && message.output.length)) + message.output = []; + message.output.push(reader.string()); + break; + } + case 3: { + message.name = reader.string(); + break; + } + case 4: { + message.opType = reader.string(); + break; + } + case 7: { + message.domain = reader.string(); + break; + } + case 5: { + if (!(message.attribute && message.attribute.length)) + message.attribute = []; + message.attribute.push($root.onnx.AttributeProto.decode(reader, reader.uint32())); + break; + } + case 6: { + message.docString = reader.string(); + break; + } + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a NodeProto message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof onnx.NodeProto + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {onnx.NodeProto} NodeProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + NodeProto.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a NodeProto message. + * @function verify + * @memberof onnx.NodeProto + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + NodeProto.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.input != null && message.hasOwnProperty("input")) { + if (!Array.isArray(message.input)) + return "input: array expected"; + for (var i = 0; i < message.input.length; ++i) + if (!$util.isString(message.input[i])) + return "input: string[] expected"; + } + if (message.output != null && message.hasOwnProperty("output")) { + if (!Array.isArray(message.output)) + return "output: array expected"; + for (var i = 0; i < message.output.length; ++i) + if (!$util.isString(message.output[i])) + return "output: string[] expected"; + } + if (message.name != null && message.hasOwnProperty("name")) + if (!$util.isString(message.name)) + return "name: string expected"; + if (message.opType != null && message.hasOwnProperty("opType")) + if (!$util.isString(message.opType)) + return "opType: string expected"; + if (message.domain != null && message.hasOwnProperty("domain")) + if (!$util.isString(message.domain)) + return "domain: string expected"; + if (message.attribute != null && message.hasOwnProperty("attribute")) { + if (!Array.isArray(message.attribute)) + return "attribute: array expected"; + for (var i = 0; i < message.attribute.length; ++i) { + var error = $root.onnx.AttributeProto.verify(message.attribute[i]); + if (error) + return "attribute." + error; + } + } + if (message.docString != null && message.hasOwnProperty("docString")) + if (!$util.isString(message.docString)) + return "docString: string expected"; + return null; + }; + + /** + * Creates a NodeProto message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof onnx.NodeProto + * @static + * @param {Object.} object Plain object + * @returns {onnx.NodeProto} NodeProto + */ + NodeProto.fromObject = function fromObject(object) { + if (object instanceof $root.onnx.NodeProto) + return object; + var message = new $root.onnx.NodeProto(); + if (object.input) { + if (!Array.isArray(object.input)) + throw TypeError(".onnx.NodeProto.input: array expected"); + message.input = []; + for (var i = 0; i < object.input.length; ++i) + message.input[i] = String(object.input[i]); + } + if (object.output) { + if (!Array.isArray(object.output)) + throw TypeError(".onnx.NodeProto.output: array expected"); + message.output = []; + for (var i = 0; i < object.output.length; ++i) + message.output[i] = String(object.output[i]); + } + if (object.name != null) + message.name = String(object.name); + if (object.opType != null) + message.opType = String(object.opType); + if (object.domain != null) + message.domain = String(object.domain); + if (object.attribute) { + if (!Array.isArray(object.attribute)) + throw TypeError(".onnx.NodeProto.attribute: array expected"); + message.attribute = []; + for (var i = 0; i < object.attribute.length; ++i) { + if (typeof object.attribute[i] !== "object") + throw TypeError(".onnx.NodeProto.attribute: object expected"); + message.attribute[i] = $root.onnx.AttributeProto.fromObject(object.attribute[i]); + } + } + if (object.docString != null) + message.docString = String(object.docString); + return message; + }; + + /** + * Creates a plain object from a NodeProto message. Also converts values to other types if specified. + * @function toObject + * @memberof onnx.NodeProto + * @static + * @param {onnx.NodeProto} message NodeProto + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + NodeProto.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.arrays || options.defaults) { + object.input = []; + object.output = []; + object.attribute = []; + } + if (options.defaults) { + object.name = ""; + object.opType = ""; + object.docString = ""; + object.domain = ""; + } + if (message.input && message.input.length) { + object.input = []; + for (var j = 0; j < message.input.length; ++j) + object.input[j] = message.input[j]; + } + if (message.output && message.output.length) { + object.output = []; + for (var j = 0; j < message.output.length; ++j) + object.output[j] = message.output[j]; + } + if (message.name != null && message.hasOwnProperty("name")) + object.name = message.name; + if (message.opType != null && message.hasOwnProperty("opType")) + object.opType = message.opType; + if (message.attribute && message.attribute.length) { + object.attribute = []; + for (var j = 0; j < message.attribute.length; ++j) + object.attribute[j] = $root.onnx.AttributeProto.toObject(message.attribute[j], options); + } + if (message.docString != null && message.hasOwnProperty("docString")) + object.docString = message.docString; + if (message.domain != null && message.hasOwnProperty("domain")) + object.domain = message.domain; + return object; + }; + + /** + * Converts this NodeProto to JSON. + * @function toJSON + * @memberof onnx.NodeProto + * @instance + * @returns {Object.} JSON object + */ + NodeProto.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + /** + * Gets the default type url for NodeProto + * @function getTypeUrl + * @memberof onnx.NodeProto + * @static + * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns {string} The default type url + */ + NodeProto.getTypeUrl = function getTypeUrl(typeUrlPrefix) { + if (typeUrlPrefix === undefined) { + typeUrlPrefix = "type.googleapis.com"; + } + return typeUrlPrefix + "/onnx.NodeProto"; + }; + + return NodeProto; + })(); + + onnx.TrainingInfoProto = (function() { + + /** + * Properties of a TrainingInfoProto. + * @memberof onnx + * @interface ITrainingInfoProto + * @property {onnx.IGraphProto|null} [initialization] TrainingInfoProto initialization + * @property {onnx.IGraphProto|null} [algorithm] TrainingInfoProto algorithm + * @property {Array.|null} [initializationBinding] TrainingInfoProto initializationBinding + * @property {Array.|null} [updateBinding] TrainingInfoProto updateBinding + */ + + /** + * Constructs a new TrainingInfoProto. + * @memberof onnx + * @classdesc Represents a TrainingInfoProto. + * @implements ITrainingInfoProto + * @constructor + * @param {onnx.ITrainingInfoProto=} [properties] Properties to set + */ + function TrainingInfoProto(properties) { + this.initializationBinding = []; + this.updateBinding = []; + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * TrainingInfoProto initialization. + * @member {onnx.IGraphProto|null|undefined} initialization + * @memberof onnx.TrainingInfoProto + * @instance + */ + TrainingInfoProto.prototype.initialization = null; + + /** + * TrainingInfoProto algorithm. + * @member {onnx.IGraphProto|null|undefined} algorithm + * @memberof onnx.TrainingInfoProto + * @instance + */ + TrainingInfoProto.prototype.algorithm = null; + + /** + * TrainingInfoProto initializationBinding. + * @member {Array.} initializationBinding + * @memberof onnx.TrainingInfoProto + * @instance + */ + TrainingInfoProto.prototype.initializationBinding = $util.emptyArray; + + /** + * TrainingInfoProto updateBinding. + * @member {Array.} updateBinding + * @memberof onnx.TrainingInfoProto + * @instance + */ + TrainingInfoProto.prototype.updateBinding = $util.emptyArray; + + /** + * Creates a new TrainingInfoProto instance using the specified properties. + * @function create + * @memberof onnx.TrainingInfoProto + * @static + * @param {onnx.ITrainingInfoProto=} [properties] Properties to set + * @returns {onnx.TrainingInfoProto} TrainingInfoProto instance + */ + TrainingInfoProto.create = function create(properties) { + return new TrainingInfoProto(properties); + }; + + /** + * Encodes the specified TrainingInfoProto message. Does not implicitly {@link onnx.TrainingInfoProto.verify|verify} messages. + * @function encode + * @memberof onnx.TrainingInfoProto + * @static + * @param {onnx.ITrainingInfoProto} message TrainingInfoProto message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + TrainingInfoProto.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.initialization != null && Object.hasOwnProperty.call(message, "initialization")) + $root.onnx.GraphProto.encode(message.initialization, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + if (message.algorithm != null && Object.hasOwnProperty.call(message, "algorithm")) + $root.onnx.GraphProto.encode(message.algorithm, writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim(); + if (message.initializationBinding != null && message.initializationBinding.length) + for (var i = 0; i < message.initializationBinding.length; ++i) + $root.onnx.StringStringEntryProto.encode(message.initializationBinding[i], writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim(); + if (message.updateBinding != null && message.updateBinding.length) + for (var i = 0; i < message.updateBinding.length; ++i) + $root.onnx.StringStringEntryProto.encode(message.updateBinding[i], writer.uint32(/* id 4, wireType 2 =*/34).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified TrainingInfoProto message, length delimited. Does not implicitly {@link onnx.TrainingInfoProto.verify|verify} messages. + * @function encodeDelimited + * @memberof onnx.TrainingInfoProto + * @static + * @param {onnx.ITrainingInfoProto} message TrainingInfoProto message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + TrainingInfoProto.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a TrainingInfoProto message from the specified reader or buffer. + * @function decode + * @memberof onnx.TrainingInfoProto + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {onnx.TrainingInfoProto} TrainingInfoProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + TrainingInfoProto.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.onnx.TrainingInfoProto(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + message.initialization = $root.onnx.GraphProto.decode(reader, reader.uint32()); + break; + } + case 2: { + message.algorithm = $root.onnx.GraphProto.decode(reader, reader.uint32()); + break; + } + case 3: { + if (!(message.initializationBinding && message.initializationBinding.length)) + message.initializationBinding = []; + message.initializationBinding.push($root.onnx.StringStringEntryProto.decode(reader, reader.uint32())); + break; + } + case 4: { + if (!(message.updateBinding && message.updateBinding.length)) + message.updateBinding = []; + message.updateBinding.push($root.onnx.StringStringEntryProto.decode(reader, reader.uint32())); + break; + } + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a TrainingInfoProto message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof onnx.TrainingInfoProto + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {onnx.TrainingInfoProto} TrainingInfoProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + TrainingInfoProto.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a TrainingInfoProto message. + * @function verify + * @memberof onnx.TrainingInfoProto + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + TrainingInfoProto.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.initialization != null && message.hasOwnProperty("initialization")) { + var error = $root.onnx.GraphProto.verify(message.initialization); + if (error) + return "initialization." + error; + } + if (message.algorithm != null && message.hasOwnProperty("algorithm")) { + var error = $root.onnx.GraphProto.verify(message.algorithm); + if (error) + return "algorithm." + error; + } + if (message.initializationBinding != null && message.hasOwnProperty("initializationBinding")) { + if (!Array.isArray(message.initializationBinding)) + return "initializationBinding: array expected"; + for (var i = 0; i < message.initializationBinding.length; ++i) { + var error = $root.onnx.StringStringEntryProto.verify(message.initializationBinding[i]); + if (error) + return "initializationBinding." + error; + } + } + if (message.updateBinding != null && message.hasOwnProperty("updateBinding")) { + if (!Array.isArray(message.updateBinding)) + return "updateBinding: array expected"; + for (var i = 0; i < message.updateBinding.length; ++i) { + var error = $root.onnx.StringStringEntryProto.verify(message.updateBinding[i]); + if (error) + return "updateBinding." + error; + } + } + return null; + }; + + /** + * Creates a TrainingInfoProto message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof onnx.TrainingInfoProto + * @static + * @param {Object.} object Plain object + * @returns {onnx.TrainingInfoProto} TrainingInfoProto + */ + TrainingInfoProto.fromObject = function fromObject(object) { + if (object instanceof $root.onnx.TrainingInfoProto) + return object; + var message = new $root.onnx.TrainingInfoProto(); + if (object.initialization != null) { + if (typeof object.initialization !== "object") + throw TypeError(".onnx.TrainingInfoProto.initialization: object expected"); + message.initialization = $root.onnx.GraphProto.fromObject(object.initialization); + } + if (object.algorithm != null) { + if (typeof object.algorithm !== "object") + throw TypeError(".onnx.TrainingInfoProto.algorithm: object expected"); + message.algorithm = $root.onnx.GraphProto.fromObject(object.algorithm); + } + if (object.initializationBinding) { + if (!Array.isArray(object.initializationBinding)) + throw TypeError(".onnx.TrainingInfoProto.initializationBinding: array expected"); + message.initializationBinding = []; + for (var i = 0; i < object.initializationBinding.length; ++i) { + if (typeof object.initializationBinding[i] !== "object") + throw TypeError(".onnx.TrainingInfoProto.initializationBinding: object expected"); + message.initializationBinding[i] = $root.onnx.StringStringEntryProto.fromObject(object.initializationBinding[i]); + } + } + if (object.updateBinding) { + if (!Array.isArray(object.updateBinding)) + throw TypeError(".onnx.TrainingInfoProto.updateBinding: array expected"); + message.updateBinding = []; + for (var i = 0; i < object.updateBinding.length; ++i) { + if (typeof object.updateBinding[i] !== "object") + throw TypeError(".onnx.TrainingInfoProto.updateBinding: object expected"); + message.updateBinding[i] = $root.onnx.StringStringEntryProto.fromObject(object.updateBinding[i]); + } + } + return message; + }; + + /** + * Creates a plain object from a TrainingInfoProto message. Also converts values to other types if specified. + * @function toObject + * @memberof onnx.TrainingInfoProto + * @static + * @param {onnx.TrainingInfoProto} message TrainingInfoProto + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + TrainingInfoProto.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.arrays || options.defaults) { + object.initializationBinding = []; + object.updateBinding = []; + } + if (options.defaults) { + object.initialization = null; + object.algorithm = null; + } + if (message.initialization != null && message.hasOwnProperty("initialization")) + object.initialization = $root.onnx.GraphProto.toObject(message.initialization, options); + if (message.algorithm != null && message.hasOwnProperty("algorithm")) + object.algorithm = $root.onnx.GraphProto.toObject(message.algorithm, options); + if (message.initializationBinding && message.initializationBinding.length) { + object.initializationBinding = []; + for (var j = 0; j < message.initializationBinding.length; ++j) + object.initializationBinding[j] = $root.onnx.StringStringEntryProto.toObject(message.initializationBinding[j], options); + } + if (message.updateBinding && message.updateBinding.length) { + object.updateBinding = []; + for (var j = 0; j < message.updateBinding.length; ++j) + object.updateBinding[j] = $root.onnx.StringStringEntryProto.toObject(message.updateBinding[j], options); + } + return object; + }; + + /** + * Converts this TrainingInfoProto to JSON. + * @function toJSON + * @memberof onnx.TrainingInfoProto + * @instance + * @returns {Object.} JSON object + */ + TrainingInfoProto.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + /** + * Gets the default type url for TrainingInfoProto + * @function getTypeUrl + * @memberof onnx.TrainingInfoProto + * @static + * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns {string} The default type url + */ + TrainingInfoProto.getTypeUrl = function getTypeUrl(typeUrlPrefix) { + if (typeUrlPrefix === undefined) { + typeUrlPrefix = "type.googleapis.com"; + } + return typeUrlPrefix + "/onnx.TrainingInfoProto"; + }; + + return TrainingInfoProto; + })(); + + onnx.ModelProto = (function() { + + /** + * Properties of a ModelProto. + * @memberof onnx + * @interface IModelProto + * @property {number|Long|null} [irVersion] ModelProto irVersion + * @property {Array.|null} [opsetImport] ModelProto opsetImport + * @property {string|null} [producerName] ModelProto producerName + * @property {string|null} [producerVersion] ModelProto producerVersion + * @property {string|null} [domain] ModelProto domain + * @property {number|Long|null} [modelVersion] ModelProto modelVersion + * @property {string|null} [docString] ModelProto docString + * @property {onnx.IGraphProto|null} [graph] ModelProto graph + * @property {Array.|null} [metadataProps] ModelProto metadataProps + * @property {Array.|null} [trainingInfo] ModelProto trainingInfo + * @property {Array.|null} [functions] ModelProto functions + */ + + /** + * Constructs a new ModelProto. + * @memberof onnx + * @classdesc Represents a ModelProto. + * @implements IModelProto + * @constructor + * @param {onnx.IModelProto=} [properties] Properties to set + */ + function ModelProto(properties) { + this.opsetImport = []; + this.metadataProps = []; + this.trainingInfo = []; + this.functions = []; + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * ModelProto irVersion. + * @member {number|Long} irVersion + * @memberof onnx.ModelProto + * @instance + */ + ModelProto.prototype.irVersion = $util.Long ? $util.Long.fromBits(0,0,false) : 0; + + /** + * ModelProto opsetImport. + * @member {Array.} opsetImport + * @memberof onnx.ModelProto + * @instance + */ + ModelProto.prototype.opsetImport = $util.emptyArray; + + /** + * ModelProto producerName. + * @member {string} producerName + * @memberof onnx.ModelProto + * @instance + */ + ModelProto.prototype.producerName = ""; + + /** + * ModelProto producerVersion. + * @member {string} producerVersion + * @memberof onnx.ModelProto + * @instance + */ + ModelProto.prototype.producerVersion = ""; + + /** + * ModelProto domain. + * @member {string} domain + * @memberof onnx.ModelProto + * @instance + */ + ModelProto.prototype.domain = ""; + + /** + * ModelProto modelVersion. + * @member {number|Long} modelVersion + * @memberof onnx.ModelProto + * @instance + */ + ModelProto.prototype.modelVersion = $util.Long ? $util.Long.fromBits(0,0,false) : 0; + + /** + * ModelProto docString. + * @member {string} docString + * @memberof onnx.ModelProto + * @instance + */ + ModelProto.prototype.docString = ""; + + /** + * ModelProto graph. + * @member {onnx.IGraphProto|null|undefined} graph + * @memberof onnx.ModelProto + * @instance + */ + ModelProto.prototype.graph = null; + + /** + * ModelProto metadataProps. + * @member {Array.} metadataProps + * @memberof onnx.ModelProto + * @instance + */ + ModelProto.prototype.metadataProps = $util.emptyArray; + + /** + * ModelProto trainingInfo. + * @member {Array.} trainingInfo + * @memberof onnx.ModelProto + * @instance + */ + ModelProto.prototype.trainingInfo = $util.emptyArray; + + /** + * ModelProto functions. + * @member {Array.} functions + * @memberof onnx.ModelProto + * @instance + */ + ModelProto.prototype.functions = $util.emptyArray; + + /** + * Creates a new ModelProto instance using the specified properties. + * @function create + * @memberof onnx.ModelProto + * @static + * @param {onnx.IModelProto=} [properties] Properties to set + * @returns {onnx.ModelProto} ModelProto instance + */ + ModelProto.create = function create(properties) { + return new ModelProto(properties); + }; + + /** + * Encodes the specified ModelProto message. Does not implicitly {@link onnx.ModelProto.verify|verify} messages. + * @function encode + * @memberof onnx.ModelProto + * @static + * @param {onnx.IModelProto} message ModelProto message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + ModelProto.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.irVersion != null && Object.hasOwnProperty.call(message, "irVersion")) + writer.uint32(/* id 1, wireType 0 =*/8).int64(message.irVersion); + if (message.producerName != null && Object.hasOwnProperty.call(message, "producerName")) + writer.uint32(/* id 2, wireType 2 =*/18).string(message.producerName); + if (message.producerVersion != null && Object.hasOwnProperty.call(message, "producerVersion")) + writer.uint32(/* id 3, wireType 2 =*/26).string(message.producerVersion); + if (message.domain != null && Object.hasOwnProperty.call(message, "domain")) + writer.uint32(/* id 4, wireType 2 =*/34).string(message.domain); + if (message.modelVersion != null && Object.hasOwnProperty.call(message, "modelVersion")) + writer.uint32(/* id 5, wireType 0 =*/40).int64(message.modelVersion); + if (message.docString != null && Object.hasOwnProperty.call(message, "docString")) + writer.uint32(/* id 6, wireType 2 =*/50).string(message.docString); + if (message.graph != null && Object.hasOwnProperty.call(message, "graph")) + $root.onnx.GraphProto.encode(message.graph, writer.uint32(/* id 7, wireType 2 =*/58).fork()).ldelim(); + if (message.opsetImport != null && message.opsetImport.length) + for (var i = 0; i < message.opsetImport.length; ++i) + $root.onnx.OperatorSetIdProto.encode(message.opsetImport[i], writer.uint32(/* id 8, wireType 2 =*/66).fork()).ldelim(); + if (message.metadataProps != null && message.metadataProps.length) + for (var i = 0; i < message.metadataProps.length; ++i) + $root.onnx.StringStringEntryProto.encode(message.metadataProps[i], writer.uint32(/* id 14, wireType 2 =*/114).fork()).ldelim(); + if (message.trainingInfo != null && message.trainingInfo.length) + for (var i = 0; i < message.trainingInfo.length; ++i) + $root.onnx.TrainingInfoProto.encode(message.trainingInfo[i], writer.uint32(/* id 20, wireType 2 =*/162).fork()).ldelim(); + if (message.functions != null && message.functions.length) + for (var i = 0; i < message.functions.length; ++i) + $root.onnx.FunctionProto.encode(message.functions[i], writer.uint32(/* id 25, wireType 2 =*/202).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified ModelProto message, length delimited. Does not implicitly {@link onnx.ModelProto.verify|verify} messages. + * @function encodeDelimited + * @memberof onnx.ModelProto + * @static + * @param {onnx.IModelProto} message ModelProto message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + ModelProto.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a ModelProto message from the specified reader or buffer. + * @function decode + * @memberof onnx.ModelProto + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {onnx.ModelProto} ModelProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + ModelProto.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.onnx.ModelProto(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + message.irVersion = reader.int64(); + break; + } + case 8: { + if (!(message.opsetImport && message.opsetImport.length)) + message.opsetImport = []; + message.opsetImport.push($root.onnx.OperatorSetIdProto.decode(reader, reader.uint32())); + break; + } + case 2: { + message.producerName = reader.string(); + break; + } + case 3: { + message.producerVersion = reader.string(); + break; + } + case 4: { + message.domain = reader.string(); + break; + } + case 5: { + message.modelVersion = reader.int64(); + break; + } + case 6: { + message.docString = reader.string(); + break; + } + case 7: { + message.graph = $root.onnx.GraphProto.decode(reader, reader.uint32()); + break; + } + case 14: { + if (!(message.metadataProps && message.metadataProps.length)) + message.metadataProps = []; + message.metadataProps.push($root.onnx.StringStringEntryProto.decode(reader, reader.uint32())); + break; + } + case 20: { + if (!(message.trainingInfo && message.trainingInfo.length)) + message.trainingInfo = []; + message.trainingInfo.push($root.onnx.TrainingInfoProto.decode(reader, reader.uint32())); + break; + } + case 25: { + if (!(message.functions && message.functions.length)) + message.functions = []; + message.functions.push($root.onnx.FunctionProto.decode(reader, reader.uint32())); + break; + } + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a ModelProto message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof onnx.ModelProto + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {onnx.ModelProto} ModelProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + ModelProto.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a ModelProto message. + * @function verify + * @memberof onnx.ModelProto + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + ModelProto.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.irVersion != null && message.hasOwnProperty("irVersion")) + if (!$util.isInteger(message.irVersion) && !(message.irVersion && $util.isInteger(message.irVersion.low) && $util.isInteger(message.irVersion.high))) + return "irVersion: integer|Long expected"; + if (message.opsetImport != null && message.hasOwnProperty("opsetImport")) { + if (!Array.isArray(message.opsetImport)) + return "opsetImport: array expected"; + for (var i = 0; i < message.opsetImport.length; ++i) { + var error = $root.onnx.OperatorSetIdProto.verify(message.opsetImport[i]); + if (error) + return "opsetImport." + error; + } + } + if (message.producerName != null && message.hasOwnProperty("producerName")) + if (!$util.isString(message.producerName)) + return "producerName: string expected"; + if (message.producerVersion != null && message.hasOwnProperty("producerVersion")) + if (!$util.isString(message.producerVersion)) + return "producerVersion: string expected"; + if (message.domain != null && message.hasOwnProperty("domain")) + if (!$util.isString(message.domain)) + return "domain: string expected"; + if (message.modelVersion != null && message.hasOwnProperty("modelVersion")) + if (!$util.isInteger(message.modelVersion) && !(message.modelVersion && $util.isInteger(message.modelVersion.low) && $util.isInteger(message.modelVersion.high))) + return "modelVersion: integer|Long expected"; + if (message.docString != null && message.hasOwnProperty("docString")) + if (!$util.isString(message.docString)) + return "docString: string expected"; + if (message.graph != null && message.hasOwnProperty("graph")) { + var error = $root.onnx.GraphProto.verify(message.graph); + if (error) + return "graph." + error; + } + if (message.metadataProps != null && message.hasOwnProperty("metadataProps")) { + if (!Array.isArray(message.metadataProps)) + return "metadataProps: array expected"; + for (var i = 0; i < message.metadataProps.length; ++i) { + var error = $root.onnx.StringStringEntryProto.verify(message.metadataProps[i]); + if (error) + return "metadataProps." + error; + } + } + if (message.trainingInfo != null && message.hasOwnProperty("trainingInfo")) { + if (!Array.isArray(message.trainingInfo)) + return "trainingInfo: array expected"; + for (var i = 0; i < message.trainingInfo.length; ++i) { + var error = $root.onnx.TrainingInfoProto.verify(message.trainingInfo[i]); + if (error) + return "trainingInfo." + error; + } + } + if (message.functions != null && message.hasOwnProperty("functions")) { + if (!Array.isArray(message.functions)) + return "functions: array expected"; + for (var i = 0; i < message.functions.length; ++i) { + var error = $root.onnx.FunctionProto.verify(message.functions[i]); + if (error) + return "functions." + error; + } + } + return null; + }; + + /** + * Creates a ModelProto message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof onnx.ModelProto + * @static + * @param {Object.} object Plain object + * @returns {onnx.ModelProto} ModelProto + */ + ModelProto.fromObject = function fromObject(object) { + if (object instanceof $root.onnx.ModelProto) + return object; + var message = new $root.onnx.ModelProto(); + if (object.irVersion != null) + if ($util.Long) + (message.irVersion = $util.Long.fromValue(object.irVersion)).unsigned = false; + else if (typeof object.irVersion === "string") + message.irVersion = parseInt(object.irVersion, 10); + else if (typeof object.irVersion === "number") + message.irVersion = object.irVersion; + else if (typeof object.irVersion === "object") + message.irVersion = new $util.LongBits(object.irVersion.low >>> 0, object.irVersion.high >>> 0).toNumber(); + if (object.opsetImport) { + if (!Array.isArray(object.opsetImport)) + throw TypeError(".onnx.ModelProto.opsetImport: array expected"); + message.opsetImport = []; + for (var i = 0; i < object.opsetImport.length; ++i) { + if (typeof object.opsetImport[i] !== "object") + throw TypeError(".onnx.ModelProto.opsetImport: object expected"); + message.opsetImport[i] = $root.onnx.OperatorSetIdProto.fromObject(object.opsetImport[i]); + } + } + if (object.producerName != null) + message.producerName = String(object.producerName); + if (object.producerVersion != null) + message.producerVersion = String(object.producerVersion); + if (object.domain != null) + message.domain = String(object.domain); + if (object.modelVersion != null) + if ($util.Long) + (message.modelVersion = $util.Long.fromValue(object.modelVersion)).unsigned = false; + else if (typeof object.modelVersion === "string") + message.modelVersion = parseInt(object.modelVersion, 10); + else if (typeof object.modelVersion === "number") + message.modelVersion = object.modelVersion; + else if (typeof object.modelVersion === "object") + message.modelVersion = new $util.LongBits(object.modelVersion.low >>> 0, object.modelVersion.high >>> 0).toNumber(); + if (object.docString != null) + message.docString = String(object.docString); + if (object.graph != null) { + if (typeof object.graph !== "object") + throw TypeError(".onnx.ModelProto.graph: object expected"); + message.graph = $root.onnx.GraphProto.fromObject(object.graph); + } + if (object.metadataProps) { + if (!Array.isArray(object.metadataProps)) + throw TypeError(".onnx.ModelProto.metadataProps: array expected"); + message.metadataProps = []; + for (var i = 0; i < object.metadataProps.length; ++i) { + if (typeof object.metadataProps[i] !== "object") + throw TypeError(".onnx.ModelProto.metadataProps: object expected"); + message.metadataProps[i] = $root.onnx.StringStringEntryProto.fromObject(object.metadataProps[i]); + } + } + if (object.trainingInfo) { + if (!Array.isArray(object.trainingInfo)) + throw TypeError(".onnx.ModelProto.trainingInfo: array expected"); + message.trainingInfo = []; + for (var i = 0; i < object.trainingInfo.length; ++i) { + if (typeof object.trainingInfo[i] !== "object") + throw TypeError(".onnx.ModelProto.trainingInfo: object expected"); + message.trainingInfo[i] = $root.onnx.TrainingInfoProto.fromObject(object.trainingInfo[i]); + } + } + if (object.functions) { + if (!Array.isArray(object.functions)) + throw TypeError(".onnx.ModelProto.functions: array expected"); + message.functions = []; + for (var i = 0; i < object.functions.length; ++i) { + if (typeof object.functions[i] !== "object") + throw TypeError(".onnx.ModelProto.functions: object expected"); + message.functions[i] = $root.onnx.FunctionProto.fromObject(object.functions[i]); + } + } + return message; + }; + + /** + * Creates a plain object from a ModelProto message. Also converts values to other types if specified. + * @function toObject + * @memberof onnx.ModelProto + * @static + * @param {onnx.ModelProto} message ModelProto + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + ModelProto.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.arrays || options.defaults) { + object.opsetImport = []; + object.metadataProps = []; + object.trainingInfo = []; + object.functions = []; + } + if (options.defaults) { + if ($util.Long) { + var long = new $util.Long(0, 0, false); + object.irVersion = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long; + } else + object.irVersion = options.longs === String ? "0" : 0; + object.producerName = ""; + object.producerVersion = ""; + object.domain = ""; + if ($util.Long) { + var long = new $util.Long(0, 0, false); + object.modelVersion = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long; + } else + object.modelVersion = options.longs === String ? "0" : 0; + object.docString = ""; + object.graph = null; + } + if (message.irVersion != null && message.hasOwnProperty("irVersion")) + if (typeof message.irVersion === "number") + object.irVersion = options.longs === String ? String(message.irVersion) : message.irVersion; + else + object.irVersion = options.longs === String ? $util.Long.prototype.toString.call(message.irVersion) : options.longs === Number ? new $util.LongBits(message.irVersion.low >>> 0, message.irVersion.high >>> 0).toNumber() : message.irVersion; + if (message.producerName != null && message.hasOwnProperty("producerName")) + object.producerName = message.producerName; + if (message.producerVersion != null && message.hasOwnProperty("producerVersion")) + object.producerVersion = message.producerVersion; + if (message.domain != null && message.hasOwnProperty("domain")) + object.domain = message.domain; + if (message.modelVersion != null && message.hasOwnProperty("modelVersion")) + if (typeof message.modelVersion === "number") + object.modelVersion = options.longs === String ? String(message.modelVersion) : message.modelVersion; + else + object.modelVersion = options.longs === String ? $util.Long.prototype.toString.call(message.modelVersion) : options.longs === Number ? new $util.LongBits(message.modelVersion.low >>> 0, message.modelVersion.high >>> 0).toNumber() : message.modelVersion; + if (message.docString != null && message.hasOwnProperty("docString")) + object.docString = message.docString; + if (message.graph != null && message.hasOwnProperty("graph")) + object.graph = $root.onnx.GraphProto.toObject(message.graph, options); + if (message.opsetImport && message.opsetImport.length) { + object.opsetImport = []; + for (var j = 0; j < message.opsetImport.length; ++j) + object.opsetImport[j] = $root.onnx.OperatorSetIdProto.toObject(message.opsetImport[j], options); + } + if (message.metadataProps && message.metadataProps.length) { + object.metadataProps = []; + for (var j = 0; j < message.metadataProps.length; ++j) + object.metadataProps[j] = $root.onnx.StringStringEntryProto.toObject(message.metadataProps[j], options); + } + if (message.trainingInfo && message.trainingInfo.length) { + object.trainingInfo = []; + for (var j = 0; j < message.trainingInfo.length; ++j) + object.trainingInfo[j] = $root.onnx.TrainingInfoProto.toObject(message.trainingInfo[j], options); + } + if (message.functions && message.functions.length) { + object.functions = []; + for (var j = 0; j < message.functions.length; ++j) + object.functions[j] = $root.onnx.FunctionProto.toObject(message.functions[j], options); + } + return object; + }; + + /** + * Converts this ModelProto to JSON. + * @function toJSON + * @memberof onnx.ModelProto + * @instance + * @returns {Object.} JSON object + */ + ModelProto.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + /** + * Gets the default type url for ModelProto + * @function getTypeUrl + * @memberof onnx.ModelProto + * @static + * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns {string} The default type url + */ + ModelProto.getTypeUrl = function getTypeUrl(typeUrlPrefix) { + if (typeUrlPrefix === undefined) { + typeUrlPrefix = "type.googleapis.com"; + } + return typeUrlPrefix + "/onnx.ModelProto"; + }; + + return ModelProto; + })(); + + onnx.StringStringEntryProto = (function() { + + /** + * Properties of a StringStringEntryProto. + * @memberof onnx + * @interface IStringStringEntryProto + * @property {string|null} [key] StringStringEntryProto key + * @property {string|null} [value] StringStringEntryProto value + */ + + /** + * Constructs a new StringStringEntryProto. + * @memberof onnx + * @classdesc Represents a StringStringEntryProto. + * @implements IStringStringEntryProto + * @constructor + * @param {onnx.IStringStringEntryProto=} [properties] Properties to set + */ + function StringStringEntryProto(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * StringStringEntryProto key. + * @member {string} key + * @memberof onnx.StringStringEntryProto + * @instance + */ + StringStringEntryProto.prototype.key = ""; + + /** + * StringStringEntryProto value. + * @member {string} value + * @memberof onnx.StringStringEntryProto + * @instance + */ + StringStringEntryProto.prototype.value = ""; + + /** + * Creates a new StringStringEntryProto instance using the specified properties. + * @function create + * @memberof onnx.StringStringEntryProto + * @static + * @param {onnx.IStringStringEntryProto=} [properties] Properties to set + * @returns {onnx.StringStringEntryProto} StringStringEntryProto instance + */ + StringStringEntryProto.create = function create(properties) { + return new StringStringEntryProto(properties); + }; + + /** + * Encodes the specified StringStringEntryProto message. Does not implicitly {@link onnx.StringStringEntryProto.verify|verify} messages. + * @function encode + * @memberof onnx.StringStringEntryProto + * @static + * @param {onnx.IStringStringEntryProto} message StringStringEntryProto message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + StringStringEntryProto.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.key != null && Object.hasOwnProperty.call(message, "key")) + writer.uint32(/* id 1, wireType 2 =*/10).string(message.key); + if (message.value != null && Object.hasOwnProperty.call(message, "value")) + writer.uint32(/* id 2, wireType 2 =*/18).string(message.value); + return writer; + }; + + /** + * Encodes the specified StringStringEntryProto message, length delimited. Does not implicitly {@link onnx.StringStringEntryProto.verify|verify} messages. + * @function encodeDelimited + * @memberof onnx.StringStringEntryProto + * @static + * @param {onnx.IStringStringEntryProto} message StringStringEntryProto message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + StringStringEntryProto.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a StringStringEntryProto message from the specified reader or buffer. + * @function decode + * @memberof onnx.StringStringEntryProto + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {onnx.StringStringEntryProto} StringStringEntryProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + StringStringEntryProto.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.onnx.StringStringEntryProto(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + message.key = reader.string(); + break; + } + case 2: { + message.value = reader.string(); + break; + } + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a StringStringEntryProto message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof onnx.StringStringEntryProto + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {onnx.StringStringEntryProto} StringStringEntryProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + StringStringEntryProto.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a StringStringEntryProto message. + * @function verify + * @memberof onnx.StringStringEntryProto + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + StringStringEntryProto.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.key != null && message.hasOwnProperty("key")) + if (!$util.isString(message.key)) + return "key: string expected"; + if (message.value != null && message.hasOwnProperty("value")) + if (!$util.isString(message.value)) + return "value: string expected"; + return null; + }; + + /** + * Creates a StringStringEntryProto message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof onnx.StringStringEntryProto + * @static + * @param {Object.} object Plain object + * @returns {onnx.StringStringEntryProto} StringStringEntryProto + */ + StringStringEntryProto.fromObject = function fromObject(object) { + if (object instanceof $root.onnx.StringStringEntryProto) + return object; + var message = new $root.onnx.StringStringEntryProto(); + if (object.key != null) + message.key = String(object.key); + if (object.value != null) + message.value = String(object.value); + return message; + }; + + /** + * Creates a plain object from a StringStringEntryProto message. Also converts values to other types if specified. + * @function toObject + * @memberof onnx.StringStringEntryProto + * @static + * @param {onnx.StringStringEntryProto} message StringStringEntryProto + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + StringStringEntryProto.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + object.key = ""; + object.value = ""; + } + if (message.key != null && message.hasOwnProperty("key")) + object.key = message.key; + if (message.value != null && message.hasOwnProperty("value")) + object.value = message.value; + return object; + }; + + /** + * Converts this StringStringEntryProto to JSON. + * @function toJSON + * @memberof onnx.StringStringEntryProto + * @instance + * @returns {Object.} JSON object + */ + StringStringEntryProto.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + /** + * Gets the default type url for StringStringEntryProto + * @function getTypeUrl + * @memberof onnx.StringStringEntryProto + * @static + * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns {string} The default type url + */ + StringStringEntryProto.getTypeUrl = function getTypeUrl(typeUrlPrefix) { + if (typeUrlPrefix === undefined) { + typeUrlPrefix = "type.googleapis.com"; + } + return typeUrlPrefix + "/onnx.StringStringEntryProto"; + }; + + return StringStringEntryProto; + })(); + + onnx.TensorAnnotation = (function() { + + /** + * Properties of a TensorAnnotation. + * @memberof onnx + * @interface ITensorAnnotation + * @property {string|null} [tensorName] TensorAnnotation tensorName + * @property {Array.|null} [quantParameterTensorNames] TensorAnnotation quantParameterTensorNames + */ + + /** + * Constructs a new TensorAnnotation. + * @memberof onnx + * @classdesc Represents a TensorAnnotation. + * @implements ITensorAnnotation + * @constructor + * @param {onnx.ITensorAnnotation=} [properties] Properties to set + */ + function TensorAnnotation(properties) { + this.quantParameterTensorNames = []; + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * TensorAnnotation tensorName. + * @member {string} tensorName + * @memberof onnx.TensorAnnotation + * @instance + */ + TensorAnnotation.prototype.tensorName = ""; + + /** + * TensorAnnotation quantParameterTensorNames. + * @member {Array.} quantParameterTensorNames + * @memberof onnx.TensorAnnotation + * @instance + */ + TensorAnnotation.prototype.quantParameterTensorNames = $util.emptyArray; + + /** + * Creates a new TensorAnnotation instance using the specified properties. + * @function create + * @memberof onnx.TensorAnnotation + * @static + * @param {onnx.ITensorAnnotation=} [properties] Properties to set + * @returns {onnx.TensorAnnotation} TensorAnnotation instance + */ + TensorAnnotation.create = function create(properties) { + return new TensorAnnotation(properties); + }; + + /** + * Encodes the specified TensorAnnotation message. Does not implicitly {@link onnx.TensorAnnotation.verify|verify} messages. + * @function encode + * @memberof onnx.TensorAnnotation + * @static + * @param {onnx.ITensorAnnotation} message TensorAnnotation message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + TensorAnnotation.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.tensorName != null && Object.hasOwnProperty.call(message, "tensorName")) + writer.uint32(/* id 1, wireType 2 =*/10).string(message.tensorName); + if (message.quantParameterTensorNames != null && message.quantParameterTensorNames.length) + for (var i = 0; i < message.quantParameterTensorNames.length; ++i) + $root.onnx.StringStringEntryProto.encode(message.quantParameterTensorNames[i], writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified TensorAnnotation message, length delimited. Does not implicitly {@link onnx.TensorAnnotation.verify|verify} messages. + * @function encodeDelimited + * @memberof onnx.TensorAnnotation + * @static + * @param {onnx.ITensorAnnotation} message TensorAnnotation message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + TensorAnnotation.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a TensorAnnotation message from the specified reader or buffer. + * @function decode + * @memberof onnx.TensorAnnotation + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {onnx.TensorAnnotation} TensorAnnotation + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + TensorAnnotation.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.onnx.TensorAnnotation(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + message.tensorName = reader.string(); + break; + } + case 2: { + if (!(message.quantParameterTensorNames && message.quantParameterTensorNames.length)) + message.quantParameterTensorNames = []; + message.quantParameterTensorNames.push($root.onnx.StringStringEntryProto.decode(reader, reader.uint32())); + break; + } + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a TensorAnnotation message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof onnx.TensorAnnotation + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {onnx.TensorAnnotation} TensorAnnotation + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + TensorAnnotation.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a TensorAnnotation message. + * @function verify + * @memberof onnx.TensorAnnotation + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + TensorAnnotation.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.tensorName != null && message.hasOwnProperty("tensorName")) + if (!$util.isString(message.tensorName)) + return "tensorName: string expected"; + if (message.quantParameterTensorNames != null && message.hasOwnProperty("quantParameterTensorNames")) { + if (!Array.isArray(message.quantParameterTensorNames)) + return "quantParameterTensorNames: array expected"; + for (var i = 0; i < message.quantParameterTensorNames.length; ++i) { + var error = $root.onnx.StringStringEntryProto.verify(message.quantParameterTensorNames[i]); + if (error) + return "quantParameterTensorNames." + error; + } + } + return null; + }; + + /** + * Creates a TensorAnnotation message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof onnx.TensorAnnotation + * @static + * @param {Object.} object Plain object + * @returns {onnx.TensorAnnotation} TensorAnnotation + */ + TensorAnnotation.fromObject = function fromObject(object) { + if (object instanceof $root.onnx.TensorAnnotation) + return object; + var message = new $root.onnx.TensorAnnotation(); + if (object.tensorName != null) + message.tensorName = String(object.tensorName); + if (object.quantParameterTensorNames) { + if (!Array.isArray(object.quantParameterTensorNames)) + throw TypeError(".onnx.TensorAnnotation.quantParameterTensorNames: array expected"); + message.quantParameterTensorNames = []; + for (var i = 0; i < object.quantParameterTensorNames.length; ++i) { + if (typeof object.quantParameterTensorNames[i] !== "object") + throw TypeError(".onnx.TensorAnnotation.quantParameterTensorNames: object expected"); + message.quantParameterTensorNames[i] = $root.onnx.StringStringEntryProto.fromObject(object.quantParameterTensorNames[i]); + } + } + return message; + }; + + /** + * Creates a plain object from a TensorAnnotation message. Also converts values to other types if specified. + * @function toObject + * @memberof onnx.TensorAnnotation + * @static + * @param {onnx.TensorAnnotation} message TensorAnnotation + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + TensorAnnotation.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.arrays || options.defaults) + object.quantParameterTensorNames = []; + if (options.defaults) + object.tensorName = ""; + if (message.tensorName != null && message.hasOwnProperty("tensorName")) + object.tensorName = message.tensorName; + if (message.quantParameterTensorNames && message.quantParameterTensorNames.length) { + object.quantParameterTensorNames = []; + for (var j = 0; j < message.quantParameterTensorNames.length; ++j) + object.quantParameterTensorNames[j] = $root.onnx.StringStringEntryProto.toObject(message.quantParameterTensorNames[j], options); + } + return object; + }; + + /** + * Converts this TensorAnnotation to JSON. + * @function toJSON + * @memberof onnx.TensorAnnotation + * @instance + * @returns {Object.} JSON object + */ + TensorAnnotation.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + /** + * Gets the default type url for TensorAnnotation + * @function getTypeUrl + * @memberof onnx.TensorAnnotation + * @static + * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns {string} The default type url + */ + TensorAnnotation.getTypeUrl = function getTypeUrl(typeUrlPrefix) { + if (typeUrlPrefix === undefined) { + typeUrlPrefix = "type.googleapis.com"; + } + return typeUrlPrefix + "/onnx.TensorAnnotation"; + }; + + return TensorAnnotation; + })(); + + onnx.GraphProto = (function() { + + /** + * Properties of a GraphProto. + * @memberof onnx + * @interface IGraphProto + * @property {Array.|null} [node] GraphProto node + * @property {string|null} [name] GraphProto name + * @property {Array.|null} [initializer] GraphProto initializer + * @property {Array.|null} [sparseInitializer] GraphProto sparseInitializer + * @property {string|null} [docString] GraphProto docString + * @property {Array.|null} [input] GraphProto input + * @property {Array.|null} [output] GraphProto output + * @property {Array.|null} [valueInfo] GraphProto valueInfo + * @property {Array.|null} [quantizationAnnotation] GraphProto quantizationAnnotation + */ + + /** + * Constructs a new GraphProto. + * @memberof onnx + * @classdesc Represents a GraphProto. + * @implements IGraphProto + * @constructor + * @param {onnx.IGraphProto=} [properties] Properties to set + */ + function GraphProto(properties) { + this.node = []; + this.initializer = []; + this.sparseInitializer = []; + this.input = []; + this.output = []; + this.valueInfo = []; + this.quantizationAnnotation = []; + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GraphProto node. + * @member {Array.} node + * @memberof onnx.GraphProto + * @instance + */ + GraphProto.prototype.node = $util.emptyArray; + + /** + * GraphProto name. + * @member {string} name + * @memberof onnx.GraphProto + * @instance + */ + GraphProto.prototype.name = ""; + + /** + * GraphProto initializer. + * @member {Array.} initializer + * @memberof onnx.GraphProto + * @instance + */ + GraphProto.prototype.initializer = $util.emptyArray; + + /** + * GraphProto sparseInitializer. + * @member {Array.} sparseInitializer + * @memberof onnx.GraphProto + * @instance + */ + GraphProto.prototype.sparseInitializer = $util.emptyArray; + + /** + * GraphProto docString. + * @member {string} docString + * @memberof onnx.GraphProto + * @instance + */ + GraphProto.prototype.docString = ""; + + /** + * GraphProto input. + * @member {Array.} input + * @memberof onnx.GraphProto + * @instance + */ + GraphProto.prototype.input = $util.emptyArray; + + /** + * GraphProto output. + * @member {Array.} output + * @memberof onnx.GraphProto + * @instance + */ + GraphProto.prototype.output = $util.emptyArray; + + /** + * GraphProto valueInfo. + * @member {Array.} valueInfo + * @memberof onnx.GraphProto + * @instance + */ + GraphProto.prototype.valueInfo = $util.emptyArray; + + /** + * GraphProto quantizationAnnotation. + * @member {Array.} quantizationAnnotation + * @memberof onnx.GraphProto + * @instance + */ + GraphProto.prototype.quantizationAnnotation = $util.emptyArray; + + /** + * Creates a new GraphProto instance using the specified properties. + * @function create + * @memberof onnx.GraphProto + * @static + * @param {onnx.IGraphProto=} [properties] Properties to set + * @returns {onnx.GraphProto} GraphProto instance + */ + GraphProto.create = function create(properties) { + return new GraphProto(properties); + }; + + /** + * Encodes the specified GraphProto message. Does not implicitly {@link onnx.GraphProto.verify|verify} messages. + * @function encode + * @memberof onnx.GraphProto + * @static + * @param {onnx.IGraphProto} message GraphProto message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GraphProto.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.node != null && message.node.length) + for (var i = 0; i < message.node.length; ++i) + $root.onnx.NodeProto.encode(message.node[i], writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + if (message.name != null && Object.hasOwnProperty.call(message, "name")) + writer.uint32(/* id 2, wireType 2 =*/18).string(message.name); + if (message.initializer != null && message.initializer.length) + for (var i = 0; i < message.initializer.length; ++i) + $root.onnx.TensorProto.encode(message.initializer[i], writer.uint32(/* id 5, wireType 2 =*/42).fork()).ldelim(); + if (message.docString != null && Object.hasOwnProperty.call(message, "docString")) + writer.uint32(/* id 10, wireType 2 =*/82).string(message.docString); + if (message.input != null && message.input.length) + for (var i = 0; i < message.input.length; ++i) + $root.onnx.ValueInfoProto.encode(message.input[i], writer.uint32(/* id 11, wireType 2 =*/90).fork()).ldelim(); + if (message.output != null && message.output.length) + for (var i = 0; i < message.output.length; ++i) + $root.onnx.ValueInfoProto.encode(message.output[i], writer.uint32(/* id 12, wireType 2 =*/98).fork()).ldelim(); + if (message.valueInfo != null && message.valueInfo.length) + for (var i = 0; i < message.valueInfo.length; ++i) + $root.onnx.ValueInfoProto.encode(message.valueInfo[i], writer.uint32(/* id 13, wireType 2 =*/106).fork()).ldelim(); + if (message.quantizationAnnotation != null && message.quantizationAnnotation.length) + for (var i = 0; i < message.quantizationAnnotation.length; ++i) + $root.onnx.TensorAnnotation.encode(message.quantizationAnnotation[i], writer.uint32(/* id 14, wireType 2 =*/114).fork()).ldelim(); + if (message.sparseInitializer != null && message.sparseInitializer.length) + for (var i = 0; i < message.sparseInitializer.length; ++i) + $root.onnx.SparseTensorProto.encode(message.sparseInitializer[i], writer.uint32(/* id 15, wireType 2 =*/122).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GraphProto message, length delimited. Does not implicitly {@link onnx.GraphProto.verify|verify} messages. + * @function encodeDelimited + * @memberof onnx.GraphProto + * @static + * @param {onnx.IGraphProto} message GraphProto message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GraphProto.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GraphProto message from the specified reader or buffer. + * @function decode + * @memberof onnx.GraphProto + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {onnx.GraphProto} GraphProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GraphProto.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.onnx.GraphProto(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (!(message.node && message.node.length)) + message.node = []; + message.node.push($root.onnx.NodeProto.decode(reader, reader.uint32())); + break; + } + case 2: { + message.name = reader.string(); + break; + } + case 5: { + if (!(message.initializer && message.initializer.length)) + message.initializer = []; + message.initializer.push($root.onnx.TensorProto.decode(reader, reader.uint32())); + break; + } + case 15: { + if (!(message.sparseInitializer && message.sparseInitializer.length)) + message.sparseInitializer = []; + message.sparseInitializer.push($root.onnx.SparseTensorProto.decode(reader, reader.uint32())); + break; + } + case 10: { + message.docString = reader.string(); + break; + } + case 11: { + if (!(message.input && message.input.length)) + message.input = []; + message.input.push($root.onnx.ValueInfoProto.decode(reader, reader.uint32())); + break; + } + case 12: { + if (!(message.output && message.output.length)) + message.output = []; + message.output.push($root.onnx.ValueInfoProto.decode(reader, reader.uint32())); + break; + } + case 13: { + if (!(message.valueInfo && message.valueInfo.length)) + message.valueInfo = []; + message.valueInfo.push($root.onnx.ValueInfoProto.decode(reader, reader.uint32())); + break; + } + case 14: { + if (!(message.quantizationAnnotation && message.quantizationAnnotation.length)) + message.quantizationAnnotation = []; + message.quantizationAnnotation.push($root.onnx.TensorAnnotation.decode(reader, reader.uint32())); + break; + } + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GraphProto message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof onnx.GraphProto + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {onnx.GraphProto} GraphProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GraphProto.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GraphProto message. + * @function verify + * @memberof onnx.GraphProto + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GraphProto.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.node != null && message.hasOwnProperty("node")) { + if (!Array.isArray(message.node)) + return "node: array expected"; + for (var i = 0; i < message.node.length; ++i) { + var error = $root.onnx.NodeProto.verify(message.node[i]); + if (error) + return "node." + error; + } + } + if (message.name != null && message.hasOwnProperty("name")) + if (!$util.isString(message.name)) + return "name: string expected"; + if (message.initializer != null && message.hasOwnProperty("initializer")) { + if (!Array.isArray(message.initializer)) + return "initializer: array expected"; + for (var i = 0; i < message.initializer.length; ++i) { + var error = $root.onnx.TensorProto.verify(message.initializer[i]); + if (error) + return "initializer." + error; + } + } + if (message.sparseInitializer != null && message.hasOwnProperty("sparseInitializer")) { + if (!Array.isArray(message.sparseInitializer)) + return "sparseInitializer: array expected"; + for (var i = 0; i < message.sparseInitializer.length; ++i) { + var error = $root.onnx.SparseTensorProto.verify(message.sparseInitializer[i]); + if (error) + return "sparseInitializer." + error; + } + } + if (message.docString != null && message.hasOwnProperty("docString")) + if (!$util.isString(message.docString)) + return "docString: string expected"; + if (message.input != null && message.hasOwnProperty("input")) { + if (!Array.isArray(message.input)) + return "input: array expected"; + for (var i = 0; i < message.input.length; ++i) { + var error = $root.onnx.ValueInfoProto.verify(message.input[i]); + if (error) + return "input." + error; + } + } + if (message.output != null && message.hasOwnProperty("output")) { + if (!Array.isArray(message.output)) + return "output: array expected"; + for (var i = 0; i < message.output.length; ++i) { + var error = $root.onnx.ValueInfoProto.verify(message.output[i]); + if (error) + return "output." + error; + } + } + if (message.valueInfo != null && message.hasOwnProperty("valueInfo")) { + if (!Array.isArray(message.valueInfo)) + return "valueInfo: array expected"; + for (var i = 0; i < message.valueInfo.length; ++i) { + var error = $root.onnx.ValueInfoProto.verify(message.valueInfo[i]); + if (error) + return "valueInfo." + error; + } + } + if (message.quantizationAnnotation != null && message.hasOwnProperty("quantizationAnnotation")) { + if (!Array.isArray(message.quantizationAnnotation)) + return "quantizationAnnotation: array expected"; + for (var i = 0; i < message.quantizationAnnotation.length; ++i) { + var error = $root.onnx.TensorAnnotation.verify(message.quantizationAnnotation[i]); + if (error) + return "quantizationAnnotation." + error; + } + } + return null; + }; + + /** + * Creates a GraphProto message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof onnx.GraphProto + * @static + * @param {Object.} object Plain object + * @returns {onnx.GraphProto} GraphProto + */ + GraphProto.fromObject = function fromObject(object) { + if (object instanceof $root.onnx.GraphProto) + return object; + var message = new $root.onnx.GraphProto(); + if (object.node) { + if (!Array.isArray(object.node)) + throw TypeError(".onnx.GraphProto.node: array expected"); + message.node = []; + for (var i = 0; i < object.node.length; ++i) { + if (typeof object.node[i] !== "object") + throw TypeError(".onnx.GraphProto.node: object expected"); + message.node[i] = $root.onnx.NodeProto.fromObject(object.node[i]); + } + } + if (object.name != null) + message.name = String(object.name); + if (object.initializer) { + if (!Array.isArray(object.initializer)) + throw TypeError(".onnx.GraphProto.initializer: array expected"); + message.initializer = []; + for (var i = 0; i < object.initializer.length; ++i) { + if (typeof object.initializer[i] !== "object") + throw TypeError(".onnx.GraphProto.initializer: object expected"); + message.initializer[i] = $root.onnx.TensorProto.fromObject(object.initializer[i]); + } + } + if (object.sparseInitializer) { + if (!Array.isArray(object.sparseInitializer)) + throw TypeError(".onnx.GraphProto.sparseInitializer: array expected"); + message.sparseInitializer = []; + for (var i = 0; i < object.sparseInitializer.length; ++i) { + if (typeof object.sparseInitializer[i] !== "object") + throw TypeError(".onnx.GraphProto.sparseInitializer: object expected"); + message.sparseInitializer[i] = $root.onnx.SparseTensorProto.fromObject(object.sparseInitializer[i]); + } + } + if (object.docString != null) + message.docString = String(object.docString); + if (object.input) { + if (!Array.isArray(object.input)) + throw TypeError(".onnx.GraphProto.input: array expected"); + message.input = []; + for (var i = 0; i < object.input.length; ++i) { + if (typeof object.input[i] !== "object") + throw TypeError(".onnx.GraphProto.input: object expected"); + message.input[i] = $root.onnx.ValueInfoProto.fromObject(object.input[i]); + } + } + if (object.output) { + if (!Array.isArray(object.output)) + throw TypeError(".onnx.GraphProto.output: array expected"); + message.output = []; + for (var i = 0; i < object.output.length; ++i) { + if (typeof object.output[i] !== "object") + throw TypeError(".onnx.GraphProto.output: object expected"); + message.output[i] = $root.onnx.ValueInfoProto.fromObject(object.output[i]); + } + } + if (object.valueInfo) { + if (!Array.isArray(object.valueInfo)) + throw TypeError(".onnx.GraphProto.valueInfo: array expected"); + message.valueInfo = []; + for (var i = 0; i < object.valueInfo.length; ++i) { + if (typeof object.valueInfo[i] !== "object") + throw TypeError(".onnx.GraphProto.valueInfo: object expected"); + message.valueInfo[i] = $root.onnx.ValueInfoProto.fromObject(object.valueInfo[i]); + } + } + if (object.quantizationAnnotation) { + if (!Array.isArray(object.quantizationAnnotation)) + throw TypeError(".onnx.GraphProto.quantizationAnnotation: array expected"); + message.quantizationAnnotation = []; + for (var i = 0; i < object.quantizationAnnotation.length; ++i) { + if (typeof object.quantizationAnnotation[i] !== "object") + throw TypeError(".onnx.GraphProto.quantizationAnnotation: object expected"); + message.quantizationAnnotation[i] = $root.onnx.TensorAnnotation.fromObject(object.quantizationAnnotation[i]); + } + } + return message; + }; + + /** + * Creates a plain object from a GraphProto message. Also converts values to other types if specified. + * @function toObject + * @memberof onnx.GraphProto + * @static + * @param {onnx.GraphProto} message GraphProto + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GraphProto.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.arrays || options.defaults) { + object.node = []; + object.initializer = []; + object.input = []; + object.output = []; + object.valueInfo = []; + object.quantizationAnnotation = []; + object.sparseInitializer = []; + } + if (options.defaults) { + object.name = ""; + object.docString = ""; + } + if (message.node && message.node.length) { + object.node = []; + for (var j = 0; j < message.node.length; ++j) + object.node[j] = $root.onnx.NodeProto.toObject(message.node[j], options); + } + if (message.name != null && message.hasOwnProperty("name")) + object.name = message.name; + if (message.initializer && message.initializer.length) { + object.initializer = []; + for (var j = 0; j < message.initializer.length; ++j) + object.initializer[j] = $root.onnx.TensorProto.toObject(message.initializer[j], options); + } + if (message.docString != null && message.hasOwnProperty("docString")) + object.docString = message.docString; + if (message.input && message.input.length) { + object.input = []; + for (var j = 0; j < message.input.length; ++j) + object.input[j] = $root.onnx.ValueInfoProto.toObject(message.input[j], options); + } + if (message.output && message.output.length) { + object.output = []; + for (var j = 0; j < message.output.length; ++j) + object.output[j] = $root.onnx.ValueInfoProto.toObject(message.output[j], options); + } + if (message.valueInfo && message.valueInfo.length) { + object.valueInfo = []; + for (var j = 0; j < message.valueInfo.length; ++j) + object.valueInfo[j] = $root.onnx.ValueInfoProto.toObject(message.valueInfo[j], options); + } + if (message.quantizationAnnotation && message.quantizationAnnotation.length) { + object.quantizationAnnotation = []; + for (var j = 0; j < message.quantizationAnnotation.length; ++j) + object.quantizationAnnotation[j] = $root.onnx.TensorAnnotation.toObject(message.quantizationAnnotation[j], options); + } + if (message.sparseInitializer && message.sparseInitializer.length) { + object.sparseInitializer = []; + for (var j = 0; j < message.sparseInitializer.length; ++j) + object.sparseInitializer[j] = $root.onnx.SparseTensorProto.toObject(message.sparseInitializer[j], options); + } + return object; + }; + + /** + * Converts this GraphProto to JSON. + * @function toJSON + * @memberof onnx.GraphProto + * @instance + * @returns {Object.} JSON object + */ + GraphProto.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + /** + * Gets the default type url for GraphProto + * @function getTypeUrl + * @memberof onnx.GraphProto + * @static + * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns {string} The default type url + */ + GraphProto.getTypeUrl = function getTypeUrl(typeUrlPrefix) { + if (typeUrlPrefix === undefined) { + typeUrlPrefix = "type.googleapis.com"; + } + return typeUrlPrefix + "/onnx.GraphProto"; + }; + + return GraphProto; + })(); + + onnx.TensorProto = (function() { + + /** + * Properties of a TensorProto. + * @memberof onnx + * @interface ITensorProto + * @property {Array.|null} [dims] TensorProto dims + * @property {number|null} [dataType] TensorProto dataType + * @property {onnx.TensorProto.ISegment|null} [segment] TensorProto segment + * @property {Array.|null} [floatData] TensorProto floatData + * @property {Array.|null} [int32Data] TensorProto int32Data + * @property {Array.|null} [stringData] TensorProto stringData + * @property {Array.|null} [int64Data] TensorProto int64Data + * @property {string|null} [name] TensorProto name + * @property {string|null} [docString] TensorProto docString + * @property {Uint8Array|null} [rawData] TensorProto rawData + * @property {Array.|null} [externalData] TensorProto externalData + * @property {onnx.TensorProto.DataLocation|null} [dataLocation] TensorProto dataLocation + * @property {Array.|null} [doubleData] TensorProto doubleData + * @property {Array.|null} [uint64Data] TensorProto uint64Data + */ + + /** + * Constructs a new TensorProto. + * @memberof onnx + * @classdesc Represents a TensorProto. + * @implements ITensorProto + * @constructor + * @param {onnx.ITensorProto=} [properties] Properties to set + */ + function TensorProto(properties) { + this.dims = []; + this.floatData = []; + this.int32Data = []; + this.stringData = []; + this.int64Data = []; + this.externalData = []; + this.doubleData = []; + this.uint64Data = []; + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * TensorProto dims. + * @member {Array.} dims + * @memberof onnx.TensorProto + * @instance + */ + TensorProto.prototype.dims = $util.emptyArray; + + /** + * TensorProto dataType. + * @member {number} dataType + * @memberof onnx.TensorProto + * @instance + */ + TensorProto.prototype.dataType = 0; + + /** + * TensorProto segment. + * @member {onnx.TensorProto.ISegment|null|undefined} segment + * @memberof onnx.TensorProto + * @instance + */ + TensorProto.prototype.segment = null; + + /** + * TensorProto floatData. + * @member {Array.} floatData + * @memberof onnx.TensorProto + * @instance + */ + TensorProto.prototype.floatData = $util.emptyArray; + + /** + * TensorProto int32Data. + * @member {Array.} int32Data + * @memberof onnx.TensorProto + * @instance + */ + TensorProto.prototype.int32Data = $util.emptyArray; + + /** + * TensorProto stringData. + * @member {Array.} stringData + * @memberof onnx.TensorProto + * @instance + */ + TensorProto.prototype.stringData = $util.emptyArray; + + /** + * TensorProto int64Data. + * @member {Array.} int64Data + * @memberof onnx.TensorProto + * @instance + */ + TensorProto.prototype.int64Data = $util.emptyArray; + + /** + * TensorProto name. + * @member {string} name + * @memberof onnx.TensorProto + * @instance + */ + TensorProto.prototype.name = ""; + + /** + * TensorProto docString. + * @member {string} docString + * @memberof onnx.TensorProto + * @instance + */ + TensorProto.prototype.docString = ""; + + /** + * TensorProto rawData. + * @member {Uint8Array} rawData + * @memberof onnx.TensorProto + * @instance + */ + TensorProto.prototype.rawData = $util.newBuffer([]); + + /** + * TensorProto externalData. + * @member {Array.} externalData + * @memberof onnx.TensorProto + * @instance + */ + TensorProto.prototype.externalData = $util.emptyArray; + + /** + * TensorProto dataLocation. + * @member {onnx.TensorProto.DataLocation} dataLocation + * @memberof onnx.TensorProto + * @instance + */ + TensorProto.prototype.dataLocation = 0; + + /** + * TensorProto doubleData. + * @member {Array.} doubleData + * @memberof onnx.TensorProto + * @instance + */ + TensorProto.prototype.doubleData = $util.emptyArray; + + /** + * TensorProto uint64Data. + * @member {Array.} uint64Data + * @memberof onnx.TensorProto + * @instance + */ + TensorProto.prototype.uint64Data = $util.emptyArray; + + /** + * Creates a new TensorProto instance using the specified properties. + * @function create + * @memberof onnx.TensorProto + * @static + * @param {onnx.ITensorProto=} [properties] Properties to set + * @returns {onnx.TensorProto} TensorProto instance + */ + TensorProto.create = function create(properties) { + return new TensorProto(properties); + }; + + /** + * Encodes the specified TensorProto message. Does not implicitly {@link onnx.TensorProto.verify|verify} messages. + * @function encode + * @memberof onnx.TensorProto + * @static + * @param {onnx.ITensorProto} message TensorProto message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + TensorProto.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.dims != null && message.dims.length) { + writer.uint32(/* id 1, wireType 2 =*/10).fork(); + for (var i = 0; i < message.dims.length; ++i) + writer.int64(message.dims[i]); + writer.ldelim(); + } + if (message.dataType != null && Object.hasOwnProperty.call(message, "dataType")) + writer.uint32(/* id 2, wireType 0 =*/16).int32(message.dataType); + if (message.segment != null && Object.hasOwnProperty.call(message, "segment")) + $root.onnx.TensorProto.Segment.encode(message.segment, writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim(); + if (message.floatData != null && message.floatData.length) { + writer.uint32(/* id 4, wireType 2 =*/34).fork(); + for (var i = 0; i < message.floatData.length; ++i) + writer.float(message.floatData[i]); + writer.ldelim(); + } + if (message.int32Data != null && message.int32Data.length) { + writer.uint32(/* id 5, wireType 2 =*/42).fork(); + for (var i = 0; i < message.int32Data.length; ++i) + writer.int32(message.int32Data[i]); + writer.ldelim(); + } + if (message.stringData != null && message.stringData.length) + for (var i = 0; i < message.stringData.length; ++i) + writer.uint32(/* id 6, wireType 2 =*/50).bytes(message.stringData[i]); + if (message.int64Data != null && message.int64Data.length) { + writer.uint32(/* id 7, wireType 2 =*/58).fork(); + for (var i = 0; i < message.int64Data.length; ++i) + writer.int64(message.int64Data[i]); + writer.ldelim(); + } + if (message.name != null && Object.hasOwnProperty.call(message, "name")) + writer.uint32(/* id 8, wireType 2 =*/66).string(message.name); + if (message.rawData != null && Object.hasOwnProperty.call(message, "rawData")) + writer.uint32(/* id 9, wireType 2 =*/74).bytes(message.rawData); + if (message.doubleData != null && message.doubleData.length) { + writer.uint32(/* id 10, wireType 2 =*/82).fork(); + for (var i = 0; i < message.doubleData.length; ++i) + writer.double(message.doubleData[i]); + writer.ldelim(); + } + if (message.uint64Data != null && message.uint64Data.length) { + writer.uint32(/* id 11, wireType 2 =*/90).fork(); + for (var i = 0; i < message.uint64Data.length; ++i) + writer.uint64(message.uint64Data[i]); + writer.ldelim(); + } + if (message.docString != null && Object.hasOwnProperty.call(message, "docString")) + writer.uint32(/* id 12, wireType 2 =*/98).string(message.docString); + if (message.externalData != null && message.externalData.length) + for (var i = 0; i < message.externalData.length; ++i) + $root.onnx.StringStringEntryProto.encode(message.externalData[i], writer.uint32(/* id 13, wireType 2 =*/106).fork()).ldelim(); + if (message.dataLocation != null && Object.hasOwnProperty.call(message, "dataLocation")) + writer.uint32(/* id 14, wireType 0 =*/112).int32(message.dataLocation); + return writer; + }; + + /** + * Encodes the specified TensorProto message, length delimited. Does not implicitly {@link onnx.TensorProto.verify|verify} messages. + * @function encodeDelimited + * @memberof onnx.TensorProto + * @static + * @param {onnx.ITensorProto} message TensorProto message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + TensorProto.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a TensorProto message from the specified reader or buffer. + * @function decode + * @memberof onnx.TensorProto + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {onnx.TensorProto} TensorProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + TensorProto.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.onnx.TensorProto(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (!(message.dims && message.dims.length)) + message.dims = []; + if ((tag & 7) === 2) { + var end2 = reader.uint32() + reader.pos; + while (reader.pos < end2) + message.dims.push(reader.int64()); + } else + message.dims.push(reader.int64()); + break; + } + case 2: { + message.dataType = reader.int32(); + break; + } + case 3: { + message.segment = $root.onnx.TensorProto.Segment.decode(reader, reader.uint32()); + break; + } + case 4: { + if (!(message.floatData && message.floatData.length)) + message.floatData = []; + if ((tag & 7) === 2) { + var end2 = reader.uint32() + reader.pos; + while (reader.pos < end2) + message.floatData.push(reader.float()); + } else + message.floatData.push(reader.float()); + break; + } + case 5: { + if (!(message.int32Data && message.int32Data.length)) + message.int32Data = []; + if ((tag & 7) === 2) { + var end2 = reader.uint32() + reader.pos; + while (reader.pos < end2) + message.int32Data.push(reader.int32()); + } else + message.int32Data.push(reader.int32()); + break; + } + case 6: { + if (!(message.stringData && message.stringData.length)) + message.stringData = []; + message.stringData.push(reader.bytes()); + break; + } + case 7: { + if (!(message.int64Data && message.int64Data.length)) + message.int64Data = []; + if ((tag & 7) === 2) { + var end2 = reader.uint32() + reader.pos; + while (reader.pos < end2) + message.int64Data.push(reader.int64()); + } else + message.int64Data.push(reader.int64()); + break; + } + case 8: { + message.name = reader.string(); + break; + } + case 12: { + message.docString = reader.string(); + break; + } + case 9: { + message.rawData = reader.bytes(); + break; + } + case 13: { + if (!(message.externalData && message.externalData.length)) + message.externalData = []; + message.externalData.push($root.onnx.StringStringEntryProto.decode(reader, reader.uint32())); + break; + } + case 14: { + message.dataLocation = reader.int32(); + break; + } + case 10: { + if (!(message.doubleData && message.doubleData.length)) + message.doubleData = []; + if ((tag & 7) === 2) { + var end2 = reader.uint32() + reader.pos; + while (reader.pos < end2) + message.doubleData.push(reader.double()); + } else + message.doubleData.push(reader.double()); + break; + } + case 11: { + if (!(message.uint64Data && message.uint64Data.length)) + message.uint64Data = []; + if ((tag & 7) === 2) { + var end2 = reader.uint32() + reader.pos; + while (reader.pos < end2) + message.uint64Data.push(reader.uint64()); + } else + message.uint64Data.push(reader.uint64()); + break; + } + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a TensorProto message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof onnx.TensorProto + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {onnx.TensorProto} TensorProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + TensorProto.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a TensorProto message. + * @function verify + * @memberof onnx.TensorProto + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + TensorProto.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.dims != null && message.hasOwnProperty("dims")) { + if (!Array.isArray(message.dims)) + return "dims: array expected"; + for (var i = 0; i < message.dims.length; ++i) + if (!$util.isInteger(message.dims[i]) && !(message.dims[i] && $util.isInteger(message.dims[i].low) && $util.isInteger(message.dims[i].high))) + return "dims: integer|Long[] expected"; + } + if (message.dataType != null && message.hasOwnProperty("dataType")) + if (!$util.isInteger(message.dataType)) + return "dataType: integer expected"; + if (message.segment != null && message.hasOwnProperty("segment")) { + var error = $root.onnx.TensorProto.Segment.verify(message.segment); + if (error) + return "segment." + error; + } + if (message.floatData != null && message.hasOwnProperty("floatData")) { + if (!Array.isArray(message.floatData)) + return "floatData: array expected"; + for (var i = 0; i < message.floatData.length; ++i) + if (typeof message.floatData[i] !== "number") + return "floatData: number[] expected"; + } + if (message.int32Data != null && message.hasOwnProperty("int32Data")) { + if (!Array.isArray(message.int32Data)) + return "int32Data: array expected"; + for (var i = 0; i < message.int32Data.length; ++i) + if (!$util.isInteger(message.int32Data[i])) + return "int32Data: integer[] expected"; + } + if (message.stringData != null && message.hasOwnProperty("stringData")) { + if (!Array.isArray(message.stringData)) + return "stringData: array expected"; + for (var i = 0; i < message.stringData.length; ++i) + if (!(message.stringData[i] && typeof message.stringData[i].length === "number" || $util.isString(message.stringData[i]))) + return "stringData: buffer[] expected"; + } + if (message.int64Data != null && message.hasOwnProperty("int64Data")) { + if (!Array.isArray(message.int64Data)) + return "int64Data: array expected"; + for (var i = 0; i < message.int64Data.length; ++i) + if (!$util.isInteger(message.int64Data[i]) && !(message.int64Data[i] && $util.isInteger(message.int64Data[i].low) && $util.isInteger(message.int64Data[i].high))) + return "int64Data: integer|Long[] expected"; + } + if (message.name != null && message.hasOwnProperty("name")) + if (!$util.isString(message.name)) + return "name: string expected"; + if (message.docString != null && message.hasOwnProperty("docString")) + if (!$util.isString(message.docString)) + return "docString: string expected"; + if (message.rawData != null && message.hasOwnProperty("rawData")) + if (!(message.rawData && typeof message.rawData.length === "number" || $util.isString(message.rawData))) + return "rawData: buffer expected"; + if (message.externalData != null && message.hasOwnProperty("externalData")) { + if (!Array.isArray(message.externalData)) + return "externalData: array expected"; + for (var i = 0; i < message.externalData.length; ++i) { + var error = $root.onnx.StringStringEntryProto.verify(message.externalData[i]); + if (error) + return "externalData." + error; + } + } + if (message.dataLocation != null && message.hasOwnProperty("dataLocation")) + switch (message.dataLocation) { + default: + return "dataLocation: enum value expected"; + case 0: + case 1: + break; + } + if (message.doubleData != null && message.hasOwnProperty("doubleData")) { + if (!Array.isArray(message.doubleData)) + return "doubleData: array expected"; + for (var i = 0; i < message.doubleData.length; ++i) + if (typeof message.doubleData[i] !== "number") + return "doubleData: number[] expected"; + } + if (message.uint64Data != null && message.hasOwnProperty("uint64Data")) { + if (!Array.isArray(message.uint64Data)) + return "uint64Data: array expected"; + for (var i = 0; i < message.uint64Data.length; ++i) + if (!$util.isInteger(message.uint64Data[i]) && !(message.uint64Data[i] && $util.isInteger(message.uint64Data[i].low) && $util.isInteger(message.uint64Data[i].high))) + return "uint64Data: integer|Long[] expected"; + } + return null; + }; + + /** + * Creates a TensorProto message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof onnx.TensorProto + * @static + * @param {Object.} object Plain object + * @returns {onnx.TensorProto} TensorProto + */ + TensorProto.fromObject = function fromObject(object) { + if (object instanceof $root.onnx.TensorProto) + return object; + var message = new $root.onnx.TensorProto(); + if (object.dims) { + if (!Array.isArray(object.dims)) + throw TypeError(".onnx.TensorProto.dims: array expected"); + message.dims = []; + for (var i = 0; i < object.dims.length; ++i) + if ($util.Long) + (message.dims[i] = $util.Long.fromValue(object.dims[i])).unsigned = false; + else if (typeof object.dims[i] === "string") + message.dims[i] = parseInt(object.dims[i], 10); + else if (typeof object.dims[i] === "number") + message.dims[i] = object.dims[i]; + else if (typeof object.dims[i] === "object") + message.dims[i] = new $util.LongBits(object.dims[i].low >>> 0, object.dims[i].high >>> 0).toNumber(); + } + if (object.dataType != null) + message.dataType = object.dataType | 0; + if (object.segment != null) { + if (typeof object.segment !== "object") + throw TypeError(".onnx.TensorProto.segment: object expected"); + message.segment = $root.onnx.TensorProto.Segment.fromObject(object.segment); + } + if (object.floatData) { + if (!Array.isArray(object.floatData)) + throw TypeError(".onnx.TensorProto.floatData: array expected"); + message.floatData = []; + for (var i = 0; i < object.floatData.length; ++i) + message.floatData[i] = Number(object.floatData[i]); + } + if (object.int32Data) { + if (!Array.isArray(object.int32Data)) + throw TypeError(".onnx.TensorProto.int32Data: array expected"); + message.int32Data = []; + for (var i = 0; i < object.int32Data.length; ++i) + message.int32Data[i] = object.int32Data[i] | 0; + } + if (object.stringData) { + if (!Array.isArray(object.stringData)) + throw TypeError(".onnx.TensorProto.stringData: array expected"); + message.stringData = []; + for (var i = 0; i < object.stringData.length; ++i) + if (typeof object.stringData[i] === "string") + $util.base64.decode(object.stringData[i], message.stringData[i] = $util.newBuffer($util.base64.length(object.stringData[i])), 0); + else if (object.stringData[i].length >= 0) + message.stringData[i] = object.stringData[i]; + } + if (object.int64Data) { + if (!Array.isArray(object.int64Data)) + throw TypeError(".onnx.TensorProto.int64Data: array expected"); + message.int64Data = []; + for (var i = 0; i < object.int64Data.length; ++i) + if ($util.Long) + (message.int64Data[i] = $util.Long.fromValue(object.int64Data[i])).unsigned = false; + else if (typeof object.int64Data[i] === "string") + message.int64Data[i] = parseInt(object.int64Data[i], 10); + else if (typeof object.int64Data[i] === "number") + message.int64Data[i] = object.int64Data[i]; + else if (typeof object.int64Data[i] === "object") + message.int64Data[i] = new $util.LongBits(object.int64Data[i].low >>> 0, object.int64Data[i].high >>> 0).toNumber(); + } + if (object.name != null) + message.name = String(object.name); + if (object.docString != null) + message.docString = String(object.docString); + if (object.rawData != null) + if (typeof object.rawData === "string") + $util.base64.decode(object.rawData, message.rawData = $util.newBuffer($util.base64.length(object.rawData)), 0); + else if (object.rawData.length >= 0) + message.rawData = object.rawData; + if (object.externalData) { + if (!Array.isArray(object.externalData)) + throw TypeError(".onnx.TensorProto.externalData: array expected"); + message.externalData = []; + for (var i = 0; i < object.externalData.length; ++i) { + if (typeof object.externalData[i] !== "object") + throw TypeError(".onnx.TensorProto.externalData: object expected"); + message.externalData[i] = $root.onnx.StringStringEntryProto.fromObject(object.externalData[i]); + } + } + switch (object.dataLocation) { + default: + if (typeof object.dataLocation === "number") { + message.dataLocation = object.dataLocation; + break; + } + break; + case "DEFAULT": + case 0: + message.dataLocation = 0; + break; + case "EXTERNAL": + case 1: + message.dataLocation = 1; + break; + } + if (object.doubleData) { + if (!Array.isArray(object.doubleData)) + throw TypeError(".onnx.TensorProto.doubleData: array expected"); + message.doubleData = []; + for (var i = 0; i < object.doubleData.length; ++i) + message.doubleData[i] = Number(object.doubleData[i]); + } + if (object.uint64Data) { + if (!Array.isArray(object.uint64Data)) + throw TypeError(".onnx.TensorProto.uint64Data: array expected"); + message.uint64Data = []; + for (var i = 0; i < object.uint64Data.length; ++i) + if ($util.Long) + (message.uint64Data[i] = $util.Long.fromValue(object.uint64Data[i])).unsigned = true; + else if (typeof object.uint64Data[i] === "string") + message.uint64Data[i] = parseInt(object.uint64Data[i], 10); + else if (typeof object.uint64Data[i] === "number") + message.uint64Data[i] = object.uint64Data[i]; + else if (typeof object.uint64Data[i] === "object") + message.uint64Data[i] = new $util.LongBits(object.uint64Data[i].low >>> 0, object.uint64Data[i].high >>> 0).toNumber(true); + } + return message; + }; + + /** + * Creates a plain object from a TensorProto message. Also converts values to other types if specified. + * @function toObject + * @memberof onnx.TensorProto + * @static + * @param {onnx.TensorProto} message TensorProto + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + TensorProto.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.arrays || options.defaults) { + object.dims = []; + object.floatData = []; + object.int32Data = []; + object.stringData = []; + object.int64Data = []; + object.doubleData = []; + object.uint64Data = []; + object.externalData = []; + } + if (options.defaults) { + object.dataType = 0; + object.segment = null; + object.name = ""; + if (options.bytes === String) + object.rawData = ""; + else { + object.rawData = []; + if (options.bytes !== Array) + object.rawData = $util.newBuffer(object.rawData); + } + object.docString = ""; + object.dataLocation = options.enums === String ? "DEFAULT" : 0; + } + if (message.dims && message.dims.length) { + object.dims = []; + for (var j = 0; j < message.dims.length; ++j) + if (typeof message.dims[j] === "number") + object.dims[j] = options.longs === String ? String(message.dims[j]) : message.dims[j]; + else + object.dims[j] = options.longs === String ? $util.Long.prototype.toString.call(message.dims[j]) : options.longs === Number ? new $util.LongBits(message.dims[j].low >>> 0, message.dims[j].high >>> 0).toNumber() : message.dims[j]; + } + if (message.dataType != null && message.hasOwnProperty("dataType")) + object.dataType = message.dataType; + if (message.segment != null && message.hasOwnProperty("segment")) + object.segment = $root.onnx.TensorProto.Segment.toObject(message.segment, options); + if (message.floatData && message.floatData.length) { + object.floatData = []; + for (var j = 0; j < message.floatData.length; ++j) + object.floatData[j] = options.json && !isFinite(message.floatData[j]) ? String(message.floatData[j]) : message.floatData[j]; + } + if (message.int32Data && message.int32Data.length) { + object.int32Data = []; + for (var j = 0; j < message.int32Data.length; ++j) + object.int32Data[j] = message.int32Data[j]; + } + if (message.stringData && message.stringData.length) { + object.stringData = []; + for (var j = 0; j < message.stringData.length; ++j) + object.stringData[j] = options.bytes === String ? $util.base64.encode(message.stringData[j], 0, message.stringData[j].length) : options.bytes === Array ? Array.prototype.slice.call(message.stringData[j]) : message.stringData[j]; + } + if (message.int64Data && message.int64Data.length) { + object.int64Data = []; + for (var j = 0; j < message.int64Data.length; ++j) + if (typeof message.int64Data[j] === "number") + object.int64Data[j] = options.longs === String ? String(message.int64Data[j]) : message.int64Data[j]; + else + object.int64Data[j] = options.longs === String ? $util.Long.prototype.toString.call(message.int64Data[j]) : options.longs === Number ? new $util.LongBits(message.int64Data[j].low >>> 0, message.int64Data[j].high >>> 0).toNumber() : message.int64Data[j]; + } + if (message.name != null && message.hasOwnProperty("name")) + object.name = message.name; + if (message.rawData != null && message.hasOwnProperty("rawData")) + object.rawData = options.bytes === String ? $util.base64.encode(message.rawData, 0, message.rawData.length) : options.bytes === Array ? Array.prototype.slice.call(message.rawData) : message.rawData; + if (message.doubleData && message.doubleData.length) { + object.doubleData = []; + for (var j = 0; j < message.doubleData.length; ++j) + object.doubleData[j] = options.json && !isFinite(message.doubleData[j]) ? String(message.doubleData[j]) : message.doubleData[j]; + } + if (message.uint64Data && message.uint64Data.length) { + object.uint64Data = []; + for (var j = 0; j < message.uint64Data.length; ++j) + if (typeof message.uint64Data[j] === "number") + object.uint64Data[j] = options.longs === String ? String(message.uint64Data[j]) : message.uint64Data[j]; + else + object.uint64Data[j] = options.longs === String ? $util.Long.prototype.toString.call(message.uint64Data[j]) : options.longs === Number ? new $util.LongBits(message.uint64Data[j].low >>> 0, message.uint64Data[j].high >>> 0).toNumber(true) : message.uint64Data[j]; + } + if (message.docString != null && message.hasOwnProperty("docString")) + object.docString = message.docString; + if (message.externalData && message.externalData.length) { + object.externalData = []; + for (var j = 0; j < message.externalData.length; ++j) + object.externalData[j] = $root.onnx.StringStringEntryProto.toObject(message.externalData[j], options); + } + if (message.dataLocation != null && message.hasOwnProperty("dataLocation")) + object.dataLocation = options.enums === String ? $root.onnx.TensorProto.DataLocation[message.dataLocation] === undefined ? message.dataLocation : $root.onnx.TensorProto.DataLocation[message.dataLocation] : message.dataLocation; + return object; + }; + + /** + * Converts this TensorProto to JSON. + * @function toJSON + * @memberof onnx.TensorProto + * @instance + * @returns {Object.} JSON object + */ + TensorProto.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + /** + * Gets the default type url for TensorProto + * @function getTypeUrl + * @memberof onnx.TensorProto + * @static + * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns {string} The default type url + */ + TensorProto.getTypeUrl = function getTypeUrl(typeUrlPrefix) { + if (typeUrlPrefix === undefined) { + typeUrlPrefix = "type.googleapis.com"; + } + return typeUrlPrefix + "/onnx.TensorProto"; + }; + + /** + * DataType enum. + * @name onnx.TensorProto.DataType + * @enum {number} + * @property {number} UNDEFINED=0 UNDEFINED value + * @property {number} FLOAT=1 FLOAT value + * @property {number} UINT8=2 UINT8 value + * @property {number} INT8=3 INT8 value + * @property {number} UINT16=4 UINT16 value + * @property {number} INT16=5 INT16 value + * @property {number} INT32=6 INT32 value + * @property {number} INT64=7 INT64 value + * @property {number} STRING=8 STRING value + * @property {number} BOOL=9 BOOL value + * @property {number} FLOAT16=10 FLOAT16 value + * @property {number} DOUBLE=11 DOUBLE value + * @property {number} UINT32=12 UINT32 value + * @property {number} UINT64=13 UINT64 value + * @property {number} COMPLEX64=14 COMPLEX64 value + * @property {number} COMPLEX128=15 COMPLEX128 value + * @property {number} BFLOAT16=16 BFLOAT16 value + * @property {number} FLOAT8E4M3FN=17 FLOAT8E4M3FN value + * @property {number} FLOAT8E4M3FNUZ=18 FLOAT8E4M3FNUZ value + * @property {number} FLOAT8E5M2=19 FLOAT8E5M2 value + * @property {number} FLOAT8E5M2FNUZ=20 FLOAT8E5M2FNUZ value + */ + TensorProto.DataType = (function() { + var valuesById = {}, values = Object.create(valuesById); + values[valuesById[0] = "UNDEFINED"] = 0; + values[valuesById[1] = "FLOAT"] = 1; + values[valuesById[2] = "UINT8"] = 2; + values[valuesById[3] = "INT8"] = 3; + values[valuesById[4] = "UINT16"] = 4; + values[valuesById[5] = "INT16"] = 5; + values[valuesById[6] = "INT32"] = 6; + values[valuesById[7] = "INT64"] = 7; + values[valuesById[8] = "STRING"] = 8; + values[valuesById[9] = "BOOL"] = 9; + values[valuesById[10] = "FLOAT16"] = 10; + values[valuesById[11] = "DOUBLE"] = 11; + values[valuesById[12] = "UINT32"] = 12; + values[valuesById[13] = "UINT64"] = 13; + values[valuesById[14] = "COMPLEX64"] = 14; + values[valuesById[15] = "COMPLEX128"] = 15; + values[valuesById[16] = "BFLOAT16"] = 16; + values[valuesById[17] = "FLOAT8E4M3FN"] = 17; + values[valuesById[18] = "FLOAT8E4M3FNUZ"] = 18; + values[valuesById[19] = "FLOAT8E5M2"] = 19; + values[valuesById[20] = "FLOAT8E5M2FNUZ"] = 20; + return values; + })(); + + TensorProto.Segment = (function() { + + /** + * Properties of a Segment. + * @memberof onnx.TensorProto + * @interface ISegment + * @property {number|Long|null} [begin] Segment begin + * @property {number|Long|null} [end] Segment end + */ + + /** + * Constructs a new Segment. + * @memberof onnx.TensorProto + * @classdesc Represents a Segment. + * @implements ISegment + * @constructor + * @param {onnx.TensorProto.ISegment=} [properties] Properties to set + */ + function Segment(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * Segment begin. + * @member {number|Long} begin + * @memberof onnx.TensorProto.Segment + * @instance + */ + Segment.prototype.begin = $util.Long ? $util.Long.fromBits(0,0,false) : 0; + + /** + * Segment end. + * @member {number|Long} end + * @memberof onnx.TensorProto.Segment + * @instance + */ + Segment.prototype.end = $util.Long ? $util.Long.fromBits(0,0,false) : 0; + + /** + * Creates a new Segment instance using the specified properties. + * @function create + * @memberof onnx.TensorProto.Segment + * @static + * @param {onnx.TensorProto.ISegment=} [properties] Properties to set + * @returns {onnx.TensorProto.Segment} Segment instance + */ + Segment.create = function create(properties) { + return new Segment(properties); + }; + + /** + * Encodes the specified Segment message. Does not implicitly {@link onnx.TensorProto.Segment.verify|verify} messages. + * @function encode + * @memberof onnx.TensorProto.Segment + * @static + * @param {onnx.TensorProto.ISegment} message Segment message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Segment.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.begin != null && Object.hasOwnProperty.call(message, "begin")) + writer.uint32(/* id 1, wireType 0 =*/8).int64(message.begin); + if (message.end != null && Object.hasOwnProperty.call(message, "end")) + writer.uint32(/* id 2, wireType 0 =*/16).int64(message.end); + return writer; + }; + + /** + * Encodes the specified Segment message, length delimited. Does not implicitly {@link onnx.TensorProto.Segment.verify|verify} messages. + * @function encodeDelimited + * @memberof onnx.TensorProto.Segment + * @static + * @param {onnx.TensorProto.ISegment} message Segment message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Segment.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a Segment message from the specified reader or buffer. + * @function decode + * @memberof onnx.TensorProto.Segment + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {onnx.TensorProto.Segment} Segment + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Segment.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.onnx.TensorProto.Segment(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + message.begin = reader.int64(); + break; + } + case 2: { + message.end = reader.int64(); + break; + } + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a Segment message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof onnx.TensorProto.Segment + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {onnx.TensorProto.Segment} Segment + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Segment.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a Segment message. + * @function verify + * @memberof onnx.TensorProto.Segment + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + Segment.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.begin != null && message.hasOwnProperty("begin")) + if (!$util.isInteger(message.begin) && !(message.begin && $util.isInteger(message.begin.low) && $util.isInteger(message.begin.high))) + return "begin: integer|Long expected"; + if (message.end != null && message.hasOwnProperty("end")) + if (!$util.isInteger(message.end) && !(message.end && $util.isInteger(message.end.low) && $util.isInteger(message.end.high))) + return "end: integer|Long expected"; + return null; + }; + + /** + * Creates a Segment message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof onnx.TensorProto.Segment + * @static + * @param {Object.} object Plain object + * @returns {onnx.TensorProto.Segment} Segment + */ + Segment.fromObject = function fromObject(object) { + if (object instanceof $root.onnx.TensorProto.Segment) + return object; + var message = new $root.onnx.TensorProto.Segment(); + if (object.begin != null) + if ($util.Long) + (message.begin = $util.Long.fromValue(object.begin)).unsigned = false; + else if (typeof object.begin === "string") + message.begin = parseInt(object.begin, 10); + else if (typeof object.begin === "number") + message.begin = object.begin; + else if (typeof object.begin === "object") + message.begin = new $util.LongBits(object.begin.low >>> 0, object.begin.high >>> 0).toNumber(); + if (object.end != null) + if ($util.Long) + (message.end = $util.Long.fromValue(object.end)).unsigned = false; + else if (typeof object.end === "string") + message.end = parseInt(object.end, 10); + else if (typeof object.end === "number") + message.end = object.end; + else if (typeof object.end === "object") + message.end = new $util.LongBits(object.end.low >>> 0, object.end.high >>> 0).toNumber(); + return message; + }; + + /** + * Creates a plain object from a Segment message. Also converts values to other types if specified. + * @function toObject + * @memberof onnx.TensorProto.Segment + * @static + * @param {onnx.TensorProto.Segment} message Segment + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + Segment.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + if ($util.Long) { + var long = new $util.Long(0, 0, false); + object.begin = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long; + } else + object.begin = options.longs === String ? "0" : 0; + if ($util.Long) { + var long = new $util.Long(0, 0, false); + object.end = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long; + } else + object.end = options.longs === String ? "0" : 0; + } + if (message.begin != null && message.hasOwnProperty("begin")) + if (typeof message.begin === "number") + object.begin = options.longs === String ? String(message.begin) : message.begin; + else + object.begin = options.longs === String ? $util.Long.prototype.toString.call(message.begin) : options.longs === Number ? new $util.LongBits(message.begin.low >>> 0, message.begin.high >>> 0).toNumber() : message.begin; + if (message.end != null && message.hasOwnProperty("end")) + if (typeof message.end === "number") + object.end = options.longs === String ? String(message.end) : message.end; + else + object.end = options.longs === String ? $util.Long.prototype.toString.call(message.end) : options.longs === Number ? new $util.LongBits(message.end.low >>> 0, message.end.high >>> 0).toNumber() : message.end; + return object; + }; + + /** + * Converts this Segment to JSON. + * @function toJSON + * @memberof onnx.TensorProto.Segment + * @instance + * @returns {Object.} JSON object + */ + Segment.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + /** + * Gets the default type url for Segment + * @function getTypeUrl + * @memberof onnx.TensorProto.Segment + * @static + * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns {string} The default type url + */ + Segment.getTypeUrl = function getTypeUrl(typeUrlPrefix) { + if (typeUrlPrefix === undefined) { + typeUrlPrefix = "type.googleapis.com"; + } + return typeUrlPrefix + "/onnx.TensorProto.Segment"; + }; + + return Segment; + })(); + + /** + * DataLocation enum. + * @name onnx.TensorProto.DataLocation + * @enum {number} + * @property {number} DEFAULT=0 DEFAULT value + * @property {number} EXTERNAL=1 EXTERNAL value + */ + TensorProto.DataLocation = (function() { + var valuesById = {}, values = Object.create(valuesById); + values[valuesById[0] = "DEFAULT"] = 0; + values[valuesById[1] = "EXTERNAL"] = 1; + return values; + })(); + + return TensorProto; + })(); + + onnx.SparseTensorProto = (function() { + + /** + * Properties of a SparseTensorProto. + * @memberof onnx + * @interface ISparseTensorProto + * @property {onnx.ITensorProto|null} [values] SparseTensorProto values + * @property {onnx.ITensorProto|null} [indices] SparseTensorProto indices + * @property {Array.|null} [dims] SparseTensorProto dims + */ + + /** + * Constructs a new SparseTensorProto. + * @memberof onnx + * @classdesc Represents a SparseTensorProto. + * @implements ISparseTensorProto + * @constructor + * @param {onnx.ISparseTensorProto=} [properties] Properties to set + */ + function SparseTensorProto(properties) { + this.dims = []; + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * SparseTensorProto values. + * @member {onnx.ITensorProto|null|undefined} values + * @memberof onnx.SparseTensorProto + * @instance + */ + SparseTensorProto.prototype.values = null; + + /** + * SparseTensorProto indices. + * @member {onnx.ITensorProto|null|undefined} indices + * @memberof onnx.SparseTensorProto + * @instance + */ + SparseTensorProto.prototype.indices = null; + + /** + * SparseTensorProto dims. + * @member {Array.} dims + * @memberof onnx.SparseTensorProto + * @instance + */ + SparseTensorProto.prototype.dims = $util.emptyArray; + + /** + * Creates a new SparseTensorProto instance using the specified properties. + * @function create + * @memberof onnx.SparseTensorProto + * @static + * @param {onnx.ISparseTensorProto=} [properties] Properties to set + * @returns {onnx.SparseTensorProto} SparseTensorProto instance + */ + SparseTensorProto.create = function create(properties) { + return new SparseTensorProto(properties); + }; + + /** + * Encodes the specified SparseTensorProto message. Does not implicitly {@link onnx.SparseTensorProto.verify|verify} messages. + * @function encode + * @memberof onnx.SparseTensorProto + * @static + * @param {onnx.ISparseTensorProto} message SparseTensorProto message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + SparseTensorProto.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.values != null && Object.hasOwnProperty.call(message, "values")) + $root.onnx.TensorProto.encode(message.values, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + if (message.indices != null && Object.hasOwnProperty.call(message, "indices")) + $root.onnx.TensorProto.encode(message.indices, writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim(); + if (message.dims != null && message.dims.length) { + writer.uint32(/* id 3, wireType 2 =*/26).fork(); + for (var i = 0; i < message.dims.length; ++i) + writer.int64(message.dims[i]); + writer.ldelim(); + } + return writer; + }; + + /** + * Encodes the specified SparseTensorProto message, length delimited. Does not implicitly {@link onnx.SparseTensorProto.verify|verify} messages. + * @function encodeDelimited + * @memberof onnx.SparseTensorProto + * @static + * @param {onnx.ISparseTensorProto} message SparseTensorProto message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + SparseTensorProto.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a SparseTensorProto message from the specified reader or buffer. + * @function decode + * @memberof onnx.SparseTensorProto + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {onnx.SparseTensorProto} SparseTensorProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + SparseTensorProto.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.onnx.SparseTensorProto(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + message.values = $root.onnx.TensorProto.decode(reader, reader.uint32()); + break; + } + case 2: { + message.indices = $root.onnx.TensorProto.decode(reader, reader.uint32()); + break; + } + case 3: { + if (!(message.dims && message.dims.length)) + message.dims = []; + if ((tag & 7) === 2) { + var end2 = reader.uint32() + reader.pos; + while (reader.pos < end2) + message.dims.push(reader.int64()); + } else + message.dims.push(reader.int64()); + break; + } + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a SparseTensorProto message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof onnx.SparseTensorProto + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {onnx.SparseTensorProto} SparseTensorProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + SparseTensorProto.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a SparseTensorProto message. + * @function verify + * @memberof onnx.SparseTensorProto + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + SparseTensorProto.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.values != null && message.hasOwnProperty("values")) { + var error = $root.onnx.TensorProto.verify(message.values); + if (error) + return "values." + error; + } + if (message.indices != null && message.hasOwnProperty("indices")) { + var error = $root.onnx.TensorProto.verify(message.indices); + if (error) + return "indices." + error; + } + if (message.dims != null && message.hasOwnProperty("dims")) { + if (!Array.isArray(message.dims)) + return "dims: array expected"; + for (var i = 0; i < message.dims.length; ++i) + if (!$util.isInteger(message.dims[i]) && !(message.dims[i] && $util.isInteger(message.dims[i].low) && $util.isInteger(message.dims[i].high))) + return "dims: integer|Long[] expected"; + } + return null; + }; + + /** + * Creates a SparseTensorProto message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof onnx.SparseTensorProto + * @static + * @param {Object.} object Plain object + * @returns {onnx.SparseTensorProto} SparseTensorProto + */ + SparseTensorProto.fromObject = function fromObject(object) { + if (object instanceof $root.onnx.SparseTensorProto) + return object; + var message = new $root.onnx.SparseTensorProto(); + if (object.values != null) { + if (typeof object.values !== "object") + throw TypeError(".onnx.SparseTensorProto.values: object expected"); + message.values = $root.onnx.TensorProto.fromObject(object.values); + } + if (object.indices != null) { + if (typeof object.indices !== "object") + throw TypeError(".onnx.SparseTensorProto.indices: object expected"); + message.indices = $root.onnx.TensorProto.fromObject(object.indices); + } + if (object.dims) { + if (!Array.isArray(object.dims)) + throw TypeError(".onnx.SparseTensorProto.dims: array expected"); + message.dims = []; + for (var i = 0; i < object.dims.length; ++i) + if ($util.Long) + (message.dims[i] = $util.Long.fromValue(object.dims[i])).unsigned = false; + else if (typeof object.dims[i] === "string") + message.dims[i] = parseInt(object.dims[i], 10); + else if (typeof object.dims[i] === "number") + message.dims[i] = object.dims[i]; + else if (typeof object.dims[i] === "object") + message.dims[i] = new $util.LongBits(object.dims[i].low >>> 0, object.dims[i].high >>> 0).toNumber(); + } + return message; + }; + + /** + * Creates a plain object from a SparseTensorProto message. Also converts values to other types if specified. + * @function toObject + * @memberof onnx.SparseTensorProto + * @static + * @param {onnx.SparseTensorProto} message SparseTensorProto + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + SparseTensorProto.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.arrays || options.defaults) + object.dims = []; + if (options.defaults) { + object.values = null; + object.indices = null; + } + if (message.values != null && message.hasOwnProperty("values")) + object.values = $root.onnx.TensorProto.toObject(message.values, options); + if (message.indices != null && message.hasOwnProperty("indices")) + object.indices = $root.onnx.TensorProto.toObject(message.indices, options); + if (message.dims && message.dims.length) { + object.dims = []; + for (var j = 0; j < message.dims.length; ++j) + if (typeof message.dims[j] === "number") + object.dims[j] = options.longs === String ? String(message.dims[j]) : message.dims[j]; + else + object.dims[j] = options.longs === String ? $util.Long.prototype.toString.call(message.dims[j]) : options.longs === Number ? new $util.LongBits(message.dims[j].low >>> 0, message.dims[j].high >>> 0).toNumber() : message.dims[j]; + } + return object; + }; + + /** + * Converts this SparseTensorProto to JSON. + * @function toJSON + * @memberof onnx.SparseTensorProto + * @instance + * @returns {Object.} JSON object + */ + SparseTensorProto.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + /** + * Gets the default type url for SparseTensorProto + * @function getTypeUrl + * @memberof onnx.SparseTensorProto + * @static + * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns {string} The default type url + */ + SparseTensorProto.getTypeUrl = function getTypeUrl(typeUrlPrefix) { + if (typeUrlPrefix === undefined) { + typeUrlPrefix = "type.googleapis.com"; + } + return typeUrlPrefix + "/onnx.SparseTensorProto"; + }; + + return SparseTensorProto; + })(); + + onnx.TensorShapeProto = (function() { + + /** + * Properties of a TensorShapeProto. + * @memberof onnx + * @interface ITensorShapeProto + * @property {Array.|null} [dim] TensorShapeProto dim + */ + + /** + * Constructs a new TensorShapeProto. + * @memberof onnx + * @classdesc Represents a TensorShapeProto. + * @implements ITensorShapeProto + * @constructor + * @param {onnx.ITensorShapeProto=} [properties] Properties to set + */ + function TensorShapeProto(properties) { + this.dim = []; + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * TensorShapeProto dim. + * @member {Array.} dim + * @memberof onnx.TensorShapeProto + * @instance + */ + TensorShapeProto.prototype.dim = $util.emptyArray; + + /** + * Creates a new TensorShapeProto instance using the specified properties. + * @function create + * @memberof onnx.TensorShapeProto + * @static + * @param {onnx.ITensorShapeProto=} [properties] Properties to set + * @returns {onnx.TensorShapeProto} TensorShapeProto instance + */ + TensorShapeProto.create = function create(properties) { + return new TensorShapeProto(properties); + }; + + /** + * Encodes the specified TensorShapeProto message. Does not implicitly {@link onnx.TensorShapeProto.verify|verify} messages. + * @function encode + * @memberof onnx.TensorShapeProto + * @static + * @param {onnx.ITensorShapeProto} message TensorShapeProto message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + TensorShapeProto.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.dim != null && message.dim.length) + for (var i = 0; i < message.dim.length; ++i) + $root.onnx.TensorShapeProto.Dimension.encode(message.dim[i], writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified TensorShapeProto message, length delimited. Does not implicitly {@link onnx.TensorShapeProto.verify|verify} messages. + * @function encodeDelimited + * @memberof onnx.TensorShapeProto + * @static + * @param {onnx.ITensorShapeProto} message TensorShapeProto message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + TensorShapeProto.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a TensorShapeProto message from the specified reader or buffer. + * @function decode + * @memberof onnx.TensorShapeProto + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {onnx.TensorShapeProto} TensorShapeProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + TensorShapeProto.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.onnx.TensorShapeProto(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (!(message.dim && message.dim.length)) + message.dim = []; + message.dim.push($root.onnx.TensorShapeProto.Dimension.decode(reader, reader.uint32())); + break; + } + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a TensorShapeProto message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof onnx.TensorShapeProto + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {onnx.TensorShapeProto} TensorShapeProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + TensorShapeProto.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a TensorShapeProto message. + * @function verify + * @memberof onnx.TensorShapeProto + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + TensorShapeProto.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.dim != null && message.hasOwnProperty("dim")) { + if (!Array.isArray(message.dim)) + return "dim: array expected"; + for (var i = 0; i < message.dim.length; ++i) { + var error = $root.onnx.TensorShapeProto.Dimension.verify(message.dim[i]); + if (error) + return "dim." + error; + } + } + return null; + }; + + /** + * Creates a TensorShapeProto message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof onnx.TensorShapeProto + * @static + * @param {Object.} object Plain object + * @returns {onnx.TensorShapeProto} TensorShapeProto + */ + TensorShapeProto.fromObject = function fromObject(object) { + if (object instanceof $root.onnx.TensorShapeProto) + return object; + var message = new $root.onnx.TensorShapeProto(); + if (object.dim) { + if (!Array.isArray(object.dim)) + throw TypeError(".onnx.TensorShapeProto.dim: array expected"); + message.dim = []; + for (var i = 0; i < object.dim.length; ++i) { + if (typeof object.dim[i] !== "object") + throw TypeError(".onnx.TensorShapeProto.dim: object expected"); + message.dim[i] = $root.onnx.TensorShapeProto.Dimension.fromObject(object.dim[i]); + } + } + return message; + }; + + /** + * Creates a plain object from a TensorShapeProto message. Also converts values to other types if specified. + * @function toObject + * @memberof onnx.TensorShapeProto + * @static + * @param {onnx.TensorShapeProto} message TensorShapeProto + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + TensorShapeProto.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.arrays || options.defaults) + object.dim = []; + if (message.dim && message.dim.length) { + object.dim = []; + for (var j = 0; j < message.dim.length; ++j) + object.dim[j] = $root.onnx.TensorShapeProto.Dimension.toObject(message.dim[j], options); + } + return object; + }; + + /** + * Converts this TensorShapeProto to JSON. + * @function toJSON + * @memberof onnx.TensorShapeProto + * @instance + * @returns {Object.} JSON object + */ + TensorShapeProto.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + /** + * Gets the default type url for TensorShapeProto + * @function getTypeUrl + * @memberof onnx.TensorShapeProto + * @static + * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns {string} The default type url + */ + TensorShapeProto.getTypeUrl = function getTypeUrl(typeUrlPrefix) { + if (typeUrlPrefix === undefined) { + typeUrlPrefix = "type.googleapis.com"; + } + return typeUrlPrefix + "/onnx.TensorShapeProto"; + }; + + TensorShapeProto.Dimension = (function() { + + /** + * Properties of a Dimension. + * @memberof onnx.TensorShapeProto + * @interface IDimension + * @property {number|Long|null} [dimValue] Dimension dimValue + * @property {string|null} [dimParam] Dimension dimParam + * @property {string|null} [denotation] Dimension denotation + */ + + /** + * Constructs a new Dimension. + * @memberof onnx.TensorShapeProto + * @classdesc Represents a Dimension. + * @implements IDimension + * @constructor + * @param {onnx.TensorShapeProto.IDimension=} [properties] Properties to set + */ + function Dimension(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * Dimension dimValue. + * @member {number|Long|null|undefined} dimValue + * @memberof onnx.TensorShapeProto.Dimension + * @instance + */ + Dimension.prototype.dimValue = null; + + /** + * Dimension dimParam. + * @member {string|null|undefined} dimParam + * @memberof onnx.TensorShapeProto.Dimension + * @instance + */ + Dimension.prototype.dimParam = null; + + /** + * Dimension denotation. + * @member {string} denotation + * @memberof onnx.TensorShapeProto.Dimension + * @instance + */ + Dimension.prototype.denotation = ""; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * Dimension value. + * @member {"dimValue"|"dimParam"|undefined} value + * @memberof onnx.TensorShapeProto.Dimension + * @instance + */ + Object.defineProperty(Dimension.prototype, "value", { + get: $util.oneOfGetter($oneOfFields = ["dimValue", "dimParam"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new Dimension instance using the specified properties. + * @function create + * @memberof onnx.TensorShapeProto.Dimension + * @static + * @param {onnx.TensorShapeProto.IDimension=} [properties] Properties to set + * @returns {onnx.TensorShapeProto.Dimension} Dimension instance + */ + Dimension.create = function create(properties) { + return new Dimension(properties); + }; + + /** + * Encodes the specified Dimension message. Does not implicitly {@link onnx.TensorShapeProto.Dimension.verify|verify} messages. + * @function encode + * @memberof onnx.TensorShapeProto.Dimension + * @static + * @param {onnx.TensorShapeProto.IDimension} message Dimension message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Dimension.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.dimValue != null && Object.hasOwnProperty.call(message, "dimValue")) + writer.uint32(/* id 1, wireType 0 =*/8).int64(message.dimValue); + if (message.dimParam != null && Object.hasOwnProperty.call(message, "dimParam")) + writer.uint32(/* id 2, wireType 2 =*/18).string(message.dimParam); + if (message.denotation != null && Object.hasOwnProperty.call(message, "denotation")) + writer.uint32(/* id 3, wireType 2 =*/26).string(message.denotation); + return writer; + }; + + /** + * Encodes the specified Dimension message, length delimited. Does not implicitly {@link onnx.TensorShapeProto.Dimension.verify|verify} messages. + * @function encodeDelimited + * @memberof onnx.TensorShapeProto.Dimension + * @static + * @param {onnx.TensorShapeProto.IDimension} message Dimension message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Dimension.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a Dimension message from the specified reader or buffer. + * @function decode + * @memberof onnx.TensorShapeProto.Dimension + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {onnx.TensorShapeProto.Dimension} Dimension + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Dimension.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.onnx.TensorShapeProto.Dimension(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + message.dimValue = reader.int64(); + break; + } + case 2: { + message.dimParam = reader.string(); + break; + } + case 3: { + message.denotation = reader.string(); + break; + } + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a Dimension message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof onnx.TensorShapeProto.Dimension + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {onnx.TensorShapeProto.Dimension} Dimension + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Dimension.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a Dimension message. + * @function verify + * @memberof onnx.TensorShapeProto.Dimension + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + Dimension.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.dimValue != null && message.hasOwnProperty("dimValue")) { + properties.value = 1; + if (!$util.isInteger(message.dimValue) && !(message.dimValue && $util.isInteger(message.dimValue.low) && $util.isInteger(message.dimValue.high))) + return "dimValue: integer|Long expected"; + } + if (message.dimParam != null && message.hasOwnProperty("dimParam")) { + if (properties.value === 1) + return "value: multiple values"; + properties.value = 1; + if (!$util.isString(message.dimParam)) + return "dimParam: string expected"; + } + if (message.denotation != null && message.hasOwnProperty("denotation")) + if (!$util.isString(message.denotation)) + return "denotation: string expected"; + return null; + }; + + /** + * Creates a Dimension message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof onnx.TensorShapeProto.Dimension + * @static + * @param {Object.} object Plain object + * @returns {onnx.TensorShapeProto.Dimension} Dimension + */ + Dimension.fromObject = function fromObject(object) { + if (object instanceof $root.onnx.TensorShapeProto.Dimension) + return object; + var message = new $root.onnx.TensorShapeProto.Dimension(); + if (object.dimValue != null) + if ($util.Long) + (message.dimValue = $util.Long.fromValue(object.dimValue)).unsigned = false; + else if (typeof object.dimValue === "string") + message.dimValue = parseInt(object.dimValue, 10); + else if (typeof object.dimValue === "number") + message.dimValue = object.dimValue; + else if (typeof object.dimValue === "object") + message.dimValue = new $util.LongBits(object.dimValue.low >>> 0, object.dimValue.high >>> 0).toNumber(); + if (object.dimParam != null) + message.dimParam = String(object.dimParam); + if (object.denotation != null) + message.denotation = String(object.denotation); + return message; + }; + + /** + * Creates a plain object from a Dimension message. Also converts values to other types if specified. + * @function toObject + * @memberof onnx.TensorShapeProto.Dimension + * @static + * @param {onnx.TensorShapeProto.Dimension} message Dimension + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + Dimension.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) + object.denotation = ""; + if (message.dimValue != null && message.hasOwnProperty("dimValue")) { + if (typeof message.dimValue === "number") + object.dimValue = options.longs === String ? String(message.dimValue) : message.dimValue; + else + object.dimValue = options.longs === String ? $util.Long.prototype.toString.call(message.dimValue) : options.longs === Number ? new $util.LongBits(message.dimValue.low >>> 0, message.dimValue.high >>> 0).toNumber() : message.dimValue; + if (options.oneofs) + object.value = "dimValue"; + } + if (message.dimParam != null && message.hasOwnProperty("dimParam")) { + object.dimParam = message.dimParam; + if (options.oneofs) + object.value = "dimParam"; + } + if (message.denotation != null && message.hasOwnProperty("denotation")) + object.denotation = message.denotation; + return object; + }; + + /** + * Converts this Dimension to JSON. + * @function toJSON + * @memberof onnx.TensorShapeProto.Dimension + * @instance + * @returns {Object.} JSON object + */ + Dimension.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + /** + * Gets the default type url for Dimension + * @function getTypeUrl + * @memberof onnx.TensorShapeProto.Dimension + * @static + * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns {string} The default type url + */ + Dimension.getTypeUrl = function getTypeUrl(typeUrlPrefix) { + if (typeUrlPrefix === undefined) { + typeUrlPrefix = "type.googleapis.com"; + } + return typeUrlPrefix + "/onnx.TensorShapeProto.Dimension"; + }; + + return Dimension; + })(); + + return TensorShapeProto; + })(); + + onnx.TypeProto = (function() { + + /** + * Properties of a TypeProto. + * @memberof onnx + * @interface ITypeProto + * @property {onnx.TypeProto.ITensor|null} [tensorType] TypeProto tensorType + * @property {onnx.TypeProto.ISequence|null} [sequenceType] TypeProto sequenceType + * @property {onnx.TypeProto.IMap|null} [mapType] TypeProto mapType + * @property {onnx.TypeProto.IOptional|null} [optionalType] TypeProto optionalType + * @property {onnx.TypeProto.ISparseTensor|null} [sparseTensorType] TypeProto sparseTensorType + * @property {string|null} [denotation] TypeProto denotation + */ + + /** + * Constructs a new TypeProto. + * @memberof onnx + * @classdesc Represents a TypeProto. + * @implements ITypeProto + * @constructor + * @param {onnx.ITypeProto=} [properties] Properties to set + */ + function TypeProto(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * TypeProto tensorType. + * @member {onnx.TypeProto.ITensor|null|undefined} tensorType + * @memberof onnx.TypeProto + * @instance + */ + TypeProto.prototype.tensorType = null; + + /** + * TypeProto sequenceType. + * @member {onnx.TypeProto.ISequence|null|undefined} sequenceType + * @memberof onnx.TypeProto + * @instance + */ + TypeProto.prototype.sequenceType = null; + + /** + * TypeProto mapType. + * @member {onnx.TypeProto.IMap|null|undefined} mapType + * @memberof onnx.TypeProto + * @instance + */ + TypeProto.prototype.mapType = null; + + /** + * TypeProto optionalType. + * @member {onnx.TypeProto.IOptional|null|undefined} optionalType + * @memberof onnx.TypeProto + * @instance + */ + TypeProto.prototype.optionalType = null; + + /** + * TypeProto sparseTensorType. + * @member {onnx.TypeProto.ISparseTensor|null|undefined} sparseTensorType + * @memberof onnx.TypeProto + * @instance + */ + TypeProto.prototype.sparseTensorType = null; + + /** + * TypeProto denotation. + * @member {string} denotation + * @memberof onnx.TypeProto + * @instance + */ + TypeProto.prototype.denotation = ""; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * TypeProto value. + * @member {"tensorType"|"sequenceType"|"mapType"|"optionalType"|"sparseTensorType"|undefined} value + * @memberof onnx.TypeProto + * @instance + */ + Object.defineProperty(TypeProto.prototype, "value", { + get: $util.oneOfGetter($oneOfFields = ["tensorType", "sequenceType", "mapType", "optionalType", "sparseTensorType"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new TypeProto instance using the specified properties. + * @function create + * @memberof onnx.TypeProto + * @static + * @param {onnx.ITypeProto=} [properties] Properties to set + * @returns {onnx.TypeProto} TypeProto instance + */ + TypeProto.create = function create(properties) { + return new TypeProto(properties); + }; + + /** + * Encodes the specified TypeProto message. Does not implicitly {@link onnx.TypeProto.verify|verify} messages. + * @function encode + * @memberof onnx.TypeProto + * @static + * @param {onnx.ITypeProto} message TypeProto message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + TypeProto.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.tensorType != null && Object.hasOwnProperty.call(message, "tensorType")) + $root.onnx.TypeProto.Tensor.encode(message.tensorType, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + if (message.sequenceType != null && Object.hasOwnProperty.call(message, "sequenceType")) + $root.onnx.TypeProto.Sequence.encode(message.sequenceType, writer.uint32(/* id 4, wireType 2 =*/34).fork()).ldelim(); + if (message.mapType != null && Object.hasOwnProperty.call(message, "mapType")) + $root.onnx.TypeProto.Map.encode(message.mapType, writer.uint32(/* id 5, wireType 2 =*/42).fork()).ldelim(); + if (message.denotation != null && Object.hasOwnProperty.call(message, "denotation")) + writer.uint32(/* id 6, wireType 2 =*/50).string(message.denotation); + if (message.sparseTensorType != null && Object.hasOwnProperty.call(message, "sparseTensorType")) + $root.onnx.TypeProto.SparseTensor.encode(message.sparseTensorType, writer.uint32(/* id 8, wireType 2 =*/66).fork()).ldelim(); + if (message.optionalType != null && Object.hasOwnProperty.call(message, "optionalType")) + $root.onnx.TypeProto.Optional.encode(message.optionalType, writer.uint32(/* id 9, wireType 2 =*/74).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified TypeProto message, length delimited. Does not implicitly {@link onnx.TypeProto.verify|verify} messages. + * @function encodeDelimited + * @memberof onnx.TypeProto + * @static + * @param {onnx.ITypeProto} message TypeProto message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + TypeProto.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a TypeProto message from the specified reader or buffer. + * @function decode + * @memberof onnx.TypeProto + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {onnx.TypeProto} TypeProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + TypeProto.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.onnx.TypeProto(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + message.tensorType = $root.onnx.TypeProto.Tensor.decode(reader, reader.uint32()); + break; + } + case 4: { + message.sequenceType = $root.onnx.TypeProto.Sequence.decode(reader, reader.uint32()); + break; + } + case 5: { + message.mapType = $root.onnx.TypeProto.Map.decode(reader, reader.uint32()); + break; + } + case 9: { + message.optionalType = $root.onnx.TypeProto.Optional.decode(reader, reader.uint32()); + break; + } + case 8: { + message.sparseTensorType = $root.onnx.TypeProto.SparseTensor.decode(reader, reader.uint32()); + break; + } + case 6: { + message.denotation = reader.string(); + break; + } + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a TypeProto message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof onnx.TypeProto + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {onnx.TypeProto} TypeProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + TypeProto.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a TypeProto message. + * @function verify + * @memberof onnx.TypeProto + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + TypeProto.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.tensorType != null && message.hasOwnProperty("tensorType")) { + properties.value = 1; + { + var error = $root.onnx.TypeProto.Tensor.verify(message.tensorType); + if (error) + return "tensorType." + error; + } + } + if (message.sequenceType != null && message.hasOwnProperty("sequenceType")) { + if (properties.value === 1) + return "value: multiple values"; + properties.value = 1; + { + var error = $root.onnx.TypeProto.Sequence.verify(message.sequenceType); + if (error) + return "sequenceType." + error; + } + } + if (message.mapType != null && message.hasOwnProperty("mapType")) { + if (properties.value === 1) + return "value: multiple values"; + properties.value = 1; + { + var error = $root.onnx.TypeProto.Map.verify(message.mapType); + if (error) + return "mapType." + error; + } + } + if (message.optionalType != null && message.hasOwnProperty("optionalType")) { + if (properties.value === 1) + return "value: multiple values"; + properties.value = 1; + { + var error = $root.onnx.TypeProto.Optional.verify(message.optionalType); + if (error) + return "optionalType." + error; + } + } + if (message.sparseTensorType != null && message.hasOwnProperty("sparseTensorType")) { + if (properties.value === 1) + return "value: multiple values"; + properties.value = 1; + { + var error = $root.onnx.TypeProto.SparseTensor.verify(message.sparseTensorType); + if (error) + return "sparseTensorType." + error; + } + } + if (message.denotation != null && message.hasOwnProperty("denotation")) + if (!$util.isString(message.denotation)) + return "denotation: string expected"; + return null; + }; + + /** + * Creates a TypeProto message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof onnx.TypeProto + * @static + * @param {Object.} object Plain object + * @returns {onnx.TypeProto} TypeProto + */ + TypeProto.fromObject = function fromObject(object) { + if (object instanceof $root.onnx.TypeProto) + return object; + var message = new $root.onnx.TypeProto(); + if (object.tensorType != null) { + if (typeof object.tensorType !== "object") + throw TypeError(".onnx.TypeProto.tensorType: object expected"); + message.tensorType = $root.onnx.TypeProto.Tensor.fromObject(object.tensorType); + } + if (object.sequenceType != null) { + if (typeof object.sequenceType !== "object") + throw TypeError(".onnx.TypeProto.sequenceType: object expected"); + message.sequenceType = $root.onnx.TypeProto.Sequence.fromObject(object.sequenceType); + } + if (object.mapType != null) { + if (typeof object.mapType !== "object") + throw TypeError(".onnx.TypeProto.mapType: object expected"); + message.mapType = $root.onnx.TypeProto.Map.fromObject(object.mapType); + } + if (object.optionalType != null) { + if (typeof object.optionalType !== "object") + throw TypeError(".onnx.TypeProto.optionalType: object expected"); + message.optionalType = $root.onnx.TypeProto.Optional.fromObject(object.optionalType); + } + if (object.sparseTensorType != null) { + if (typeof object.sparseTensorType !== "object") + throw TypeError(".onnx.TypeProto.sparseTensorType: object expected"); + message.sparseTensorType = $root.onnx.TypeProto.SparseTensor.fromObject(object.sparseTensorType); + } + if (object.denotation != null) + message.denotation = String(object.denotation); + return message; + }; + + /** + * Creates a plain object from a TypeProto message. Also converts values to other types if specified. + * @function toObject + * @memberof onnx.TypeProto + * @static + * @param {onnx.TypeProto} message TypeProto + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + TypeProto.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) + object.denotation = ""; + if (message.tensorType != null && message.hasOwnProperty("tensorType")) { + object.tensorType = $root.onnx.TypeProto.Tensor.toObject(message.tensorType, options); + if (options.oneofs) + object.value = "tensorType"; + } + if (message.sequenceType != null && message.hasOwnProperty("sequenceType")) { + object.sequenceType = $root.onnx.TypeProto.Sequence.toObject(message.sequenceType, options); + if (options.oneofs) + object.value = "sequenceType"; + } + if (message.mapType != null && message.hasOwnProperty("mapType")) { + object.mapType = $root.onnx.TypeProto.Map.toObject(message.mapType, options); + if (options.oneofs) + object.value = "mapType"; + } + if (message.denotation != null && message.hasOwnProperty("denotation")) + object.denotation = message.denotation; + if (message.sparseTensorType != null && message.hasOwnProperty("sparseTensorType")) { + object.sparseTensorType = $root.onnx.TypeProto.SparseTensor.toObject(message.sparseTensorType, options); + if (options.oneofs) + object.value = "sparseTensorType"; + } + if (message.optionalType != null && message.hasOwnProperty("optionalType")) { + object.optionalType = $root.onnx.TypeProto.Optional.toObject(message.optionalType, options); + if (options.oneofs) + object.value = "optionalType"; + } + return object; + }; + + /** + * Converts this TypeProto to JSON. + * @function toJSON + * @memberof onnx.TypeProto + * @instance + * @returns {Object.} JSON object + */ + TypeProto.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + /** + * Gets the default type url for TypeProto + * @function getTypeUrl + * @memberof onnx.TypeProto + * @static + * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns {string} The default type url + */ + TypeProto.getTypeUrl = function getTypeUrl(typeUrlPrefix) { + if (typeUrlPrefix === undefined) { + typeUrlPrefix = "type.googleapis.com"; + } + return typeUrlPrefix + "/onnx.TypeProto"; + }; + + TypeProto.Tensor = (function() { + + /** + * Properties of a Tensor. + * @memberof onnx.TypeProto + * @interface ITensor + * @property {number|null} [elemType] Tensor elemType + * @property {onnx.ITensorShapeProto|null} [shape] Tensor shape + */ + + /** + * Constructs a new Tensor. + * @memberof onnx.TypeProto + * @classdesc Represents a Tensor. + * @implements ITensor + * @constructor + * @param {onnx.TypeProto.ITensor=} [properties] Properties to set + */ + function Tensor(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * Tensor elemType. + * @member {number} elemType + * @memberof onnx.TypeProto.Tensor + * @instance + */ + Tensor.prototype.elemType = 0; + + /** + * Tensor shape. + * @member {onnx.ITensorShapeProto|null|undefined} shape + * @memberof onnx.TypeProto.Tensor + * @instance + */ + Tensor.prototype.shape = null; + + /** + * Creates a new Tensor instance using the specified properties. + * @function create + * @memberof onnx.TypeProto.Tensor + * @static + * @param {onnx.TypeProto.ITensor=} [properties] Properties to set + * @returns {onnx.TypeProto.Tensor} Tensor instance + */ + Tensor.create = function create(properties) { + return new Tensor(properties); + }; + + /** + * Encodes the specified Tensor message. Does not implicitly {@link onnx.TypeProto.Tensor.verify|verify} messages. + * @function encode + * @memberof onnx.TypeProto.Tensor + * @static + * @param {onnx.TypeProto.ITensor} message Tensor message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Tensor.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.elemType != null && Object.hasOwnProperty.call(message, "elemType")) + writer.uint32(/* id 1, wireType 0 =*/8).int32(message.elemType); + if (message.shape != null && Object.hasOwnProperty.call(message, "shape")) + $root.onnx.TensorShapeProto.encode(message.shape, writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified Tensor message, length delimited. Does not implicitly {@link onnx.TypeProto.Tensor.verify|verify} messages. + * @function encodeDelimited + * @memberof onnx.TypeProto.Tensor + * @static + * @param {onnx.TypeProto.ITensor} message Tensor message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Tensor.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a Tensor message from the specified reader or buffer. + * @function decode + * @memberof onnx.TypeProto.Tensor + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {onnx.TypeProto.Tensor} Tensor + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Tensor.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.onnx.TypeProto.Tensor(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + message.elemType = reader.int32(); + break; + } + case 2: { + message.shape = $root.onnx.TensorShapeProto.decode(reader, reader.uint32()); + break; + } + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a Tensor message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof onnx.TypeProto.Tensor + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {onnx.TypeProto.Tensor} Tensor + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Tensor.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a Tensor message. + * @function verify + * @memberof onnx.TypeProto.Tensor + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + Tensor.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.elemType != null && message.hasOwnProperty("elemType")) + if (!$util.isInteger(message.elemType)) + return "elemType: integer expected"; + if (message.shape != null && message.hasOwnProperty("shape")) { + var error = $root.onnx.TensorShapeProto.verify(message.shape); + if (error) + return "shape." + error; + } + return null; + }; + + /** + * Creates a Tensor message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof onnx.TypeProto.Tensor + * @static + * @param {Object.} object Plain object + * @returns {onnx.TypeProto.Tensor} Tensor + */ + Tensor.fromObject = function fromObject(object) { + if (object instanceof $root.onnx.TypeProto.Tensor) + return object; + var message = new $root.onnx.TypeProto.Tensor(); + if (object.elemType != null) + message.elemType = object.elemType | 0; + if (object.shape != null) { + if (typeof object.shape !== "object") + throw TypeError(".onnx.TypeProto.Tensor.shape: object expected"); + message.shape = $root.onnx.TensorShapeProto.fromObject(object.shape); + } + return message; + }; + + /** + * Creates a plain object from a Tensor message. Also converts values to other types if specified. + * @function toObject + * @memberof onnx.TypeProto.Tensor + * @static + * @param {onnx.TypeProto.Tensor} message Tensor + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + Tensor.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + object.elemType = 0; + object.shape = null; + } + if (message.elemType != null && message.hasOwnProperty("elemType")) + object.elemType = message.elemType; + if (message.shape != null && message.hasOwnProperty("shape")) + object.shape = $root.onnx.TensorShapeProto.toObject(message.shape, options); + return object; + }; + + /** + * Converts this Tensor to JSON. + * @function toJSON + * @memberof onnx.TypeProto.Tensor + * @instance + * @returns {Object.} JSON object + */ + Tensor.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + /** + * Gets the default type url for Tensor + * @function getTypeUrl + * @memberof onnx.TypeProto.Tensor + * @static + * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns {string} The default type url + */ + Tensor.getTypeUrl = function getTypeUrl(typeUrlPrefix) { + if (typeUrlPrefix === undefined) { + typeUrlPrefix = "type.googleapis.com"; + } + return typeUrlPrefix + "/onnx.TypeProto.Tensor"; + }; + + return Tensor; + })(); + + TypeProto.Sequence = (function() { + + /** + * Properties of a Sequence. + * @memberof onnx.TypeProto + * @interface ISequence + * @property {onnx.ITypeProto|null} [elemType] Sequence elemType + */ + + /** + * Constructs a new Sequence. + * @memberof onnx.TypeProto + * @classdesc Represents a Sequence. + * @implements ISequence + * @constructor + * @param {onnx.TypeProto.ISequence=} [properties] Properties to set + */ + function Sequence(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * Sequence elemType. + * @member {onnx.ITypeProto|null|undefined} elemType + * @memberof onnx.TypeProto.Sequence + * @instance + */ + Sequence.prototype.elemType = null; + + /** + * Creates a new Sequence instance using the specified properties. + * @function create + * @memberof onnx.TypeProto.Sequence + * @static + * @param {onnx.TypeProto.ISequence=} [properties] Properties to set + * @returns {onnx.TypeProto.Sequence} Sequence instance + */ + Sequence.create = function create(properties) { + return new Sequence(properties); + }; + + /** + * Encodes the specified Sequence message. Does not implicitly {@link onnx.TypeProto.Sequence.verify|verify} messages. + * @function encode + * @memberof onnx.TypeProto.Sequence + * @static + * @param {onnx.TypeProto.ISequence} message Sequence message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Sequence.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.elemType != null && Object.hasOwnProperty.call(message, "elemType")) + $root.onnx.TypeProto.encode(message.elemType, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified Sequence message, length delimited. Does not implicitly {@link onnx.TypeProto.Sequence.verify|verify} messages. + * @function encodeDelimited + * @memberof onnx.TypeProto.Sequence + * @static + * @param {onnx.TypeProto.ISequence} message Sequence message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Sequence.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a Sequence message from the specified reader or buffer. + * @function decode + * @memberof onnx.TypeProto.Sequence + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {onnx.TypeProto.Sequence} Sequence + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Sequence.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.onnx.TypeProto.Sequence(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + message.elemType = $root.onnx.TypeProto.decode(reader, reader.uint32()); + break; + } + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a Sequence message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof onnx.TypeProto.Sequence + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {onnx.TypeProto.Sequence} Sequence + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Sequence.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a Sequence message. + * @function verify + * @memberof onnx.TypeProto.Sequence + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + Sequence.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.elemType != null && message.hasOwnProperty("elemType")) { + var error = $root.onnx.TypeProto.verify(message.elemType); + if (error) + return "elemType." + error; + } + return null; + }; + + /** + * Creates a Sequence message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof onnx.TypeProto.Sequence + * @static + * @param {Object.} object Plain object + * @returns {onnx.TypeProto.Sequence} Sequence + */ + Sequence.fromObject = function fromObject(object) { + if (object instanceof $root.onnx.TypeProto.Sequence) + return object; + var message = new $root.onnx.TypeProto.Sequence(); + if (object.elemType != null) { + if (typeof object.elemType !== "object") + throw TypeError(".onnx.TypeProto.Sequence.elemType: object expected"); + message.elemType = $root.onnx.TypeProto.fromObject(object.elemType); + } + return message; + }; + + /** + * Creates a plain object from a Sequence message. Also converts values to other types if specified. + * @function toObject + * @memberof onnx.TypeProto.Sequence + * @static + * @param {onnx.TypeProto.Sequence} message Sequence + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + Sequence.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) + object.elemType = null; + if (message.elemType != null && message.hasOwnProperty("elemType")) + object.elemType = $root.onnx.TypeProto.toObject(message.elemType, options); + return object; + }; + + /** + * Converts this Sequence to JSON. + * @function toJSON + * @memberof onnx.TypeProto.Sequence + * @instance + * @returns {Object.} JSON object + */ + Sequence.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + /** + * Gets the default type url for Sequence + * @function getTypeUrl + * @memberof onnx.TypeProto.Sequence + * @static + * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns {string} The default type url + */ + Sequence.getTypeUrl = function getTypeUrl(typeUrlPrefix) { + if (typeUrlPrefix === undefined) { + typeUrlPrefix = "type.googleapis.com"; + } + return typeUrlPrefix + "/onnx.TypeProto.Sequence"; + }; + + return Sequence; + })(); + + TypeProto.Map = (function() { + + /** + * Properties of a Map. + * @memberof onnx.TypeProto + * @interface IMap + * @property {number|null} [keyType] Map keyType + * @property {onnx.ITypeProto|null} [valueType] Map valueType + */ + + /** + * Constructs a new Map. + * @memberof onnx.TypeProto + * @classdesc Represents a Map. + * @implements IMap + * @constructor + * @param {onnx.TypeProto.IMap=} [properties] Properties to set + */ + function Map(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * Map keyType. + * @member {number} keyType + * @memberof onnx.TypeProto.Map + * @instance + */ + Map.prototype.keyType = 0; + + /** + * Map valueType. + * @member {onnx.ITypeProto|null|undefined} valueType + * @memberof onnx.TypeProto.Map + * @instance + */ + Map.prototype.valueType = null; + + /** + * Creates a new Map instance using the specified properties. + * @function create + * @memberof onnx.TypeProto.Map + * @static + * @param {onnx.TypeProto.IMap=} [properties] Properties to set + * @returns {onnx.TypeProto.Map} Map instance + */ + Map.create = function create(properties) { + return new Map(properties); + }; + + /** + * Encodes the specified Map message. Does not implicitly {@link onnx.TypeProto.Map.verify|verify} messages. + * @function encode + * @memberof onnx.TypeProto.Map + * @static + * @param {onnx.TypeProto.IMap} message Map message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Map.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.keyType != null && Object.hasOwnProperty.call(message, "keyType")) + writer.uint32(/* id 1, wireType 0 =*/8).int32(message.keyType); + if (message.valueType != null && Object.hasOwnProperty.call(message, "valueType")) + $root.onnx.TypeProto.encode(message.valueType, writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified Map message, length delimited. Does not implicitly {@link onnx.TypeProto.Map.verify|verify} messages. + * @function encodeDelimited + * @memberof onnx.TypeProto.Map + * @static + * @param {onnx.TypeProto.IMap} message Map message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Map.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a Map message from the specified reader or buffer. + * @function decode + * @memberof onnx.TypeProto.Map + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {onnx.TypeProto.Map} Map + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Map.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.onnx.TypeProto.Map(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + message.keyType = reader.int32(); + break; + } + case 2: { + message.valueType = $root.onnx.TypeProto.decode(reader, reader.uint32()); + break; + } + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a Map message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof onnx.TypeProto.Map + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {onnx.TypeProto.Map} Map + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Map.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a Map message. + * @function verify + * @memberof onnx.TypeProto.Map + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + Map.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.keyType != null && message.hasOwnProperty("keyType")) + if (!$util.isInteger(message.keyType)) + return "keyType: integer expected"; + if (message.valueType != null && message.hasOwnProperty("valueType")) { + var error = $root.onnx.TypeProto.verify(message.valueType); + if (error) + return "valueType." + error; + } + return null; + }; + + /** + * Creates a Map message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof onnx.TypeProto.Map + * @static + * @param {Object.} object Plain object + * @returns {onnx.TypeProto.Map} Map + */ + Map.fromObject = function fromObject(object) { + if (object instanceof $root.onnx.TypeProto.Map) + return object; + var message = new $root.onnx.TypeProto.Map(); + if (object.keyType != null) + message.keyType = object.keyType | 0; + if (object.valueType != null) { + if (typeof object.valueType !== "object") + throw TypeError(".onnx.TypeProto.Map.valueType: object expected"); + message.valueType = $root.onnx.TypeProto.fromObject(object.valueType); + } + return message; + }; + + /** + * Creates a plain object from a Map message. Also converts values to other types if specified. + * @function toObject + * @memberof onnx.TypeProto.Map + * @static + * @param {onnx.TypeProto.Map} message Map + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + Map.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + object.keyType = 0; + object.valueType = null; + } + if (message.keyType != null && message.hasOwnProperty("keyType")) + object.keyType = message.keyType; + if (message.valueType != null && message.hasOwnProperty("valueType")) + object.valueType = $root.onnx.TypeProto.toObject(message.valueType, options); + return object; + }; + + /** + * Converts this Map to JSON. + * @function toJSON + * @memberof onnx.TypeProto.Map + * @instance + * @returns {Object.} JSON object + */ + Map.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + /** + * Gets the default type url for Map + * @function getTypeUrl + * @memberof onnx.TypeProto.Map + * @static + * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns {string} The default type url + */ + Map.getTypeUrl = function getTypeUrl(typeUrlPrefix) { + if (typeUrlPrefix === undefined) { + typeUrlPrefix = "type.googleapis.com"; + } + return typeUrlPrefix + "/onnx.TypeProto.Map"; + }; + + return Map; + })(); + + TypeProto.Optional = (function() { + + /** + * Properties of an Optional. + * @memberof onnx.TypeProto + * @interface IOptional + * @property {onnx.ITypeProto|null} [elemType] Optional elemType + */ + + /** + * Constructs a new Optional. + * @memberof onnx.TypeProto + * @classdesc Represents an Optional. + * @implements IOptional + * @constructor + * @param {onnx.TypeProto.IOptional=} [properties] Properties to set + */ + function Optional(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * Optional elemType. + * @member {onnx.ITypeProto|null|undefined} elemType + * @memberof onnx.TypeProto.Optional + * @instance + */ + Optional.prototype.elemType = null; + + /** + * Creates a new Optional instance using the specified properties. + * @function create + * @memberof onnx.TypeProto.Optional + * @static + * @param {onnx.TypeProto.IOptional=} [properties] Properties to set + * @returns {onnx.TypeProto.Optional} Optional instance + */ + Optional.create = function create(properties) { + return new Optional(properties); + }; + + /** + * Encodes the specified Optional message. Does not implicitly {@link onnx.TypeProto.Optional.verify|verify} messages. + * @function encode + * @memberof onnx.TypeProto.Optional + * @static + * @param {onnx.TypeProto.IOptional} message Optional message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Optional.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.elemType != null && Object.hasOwnProperty.call(message, "elemType")) + $root.onnx.TypeProto.encode(message.elemType, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified Optional message, length delimited. Does not implicitly {@link onnx.TypeProto.Optional.verify|verify} messages. + * @function encodeDelimited + * @memberof onnx.TypeProto.Optional + * @static + * @param {onnx.TypeProto.IOptional} message Optional message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Optional.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes an Optional message from the specified reader or buffer. + * @function decode + * @memberof onnx.TypeProto.Optional + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {onnx.TypeProto.Optional} Optional + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Optional.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.onnx.TypeProto.Optional(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + message.elemType = $root.onnx.TypeProto.decode(reader, reader.uint32()); + break; + } + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes an Optional message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof onnx.TypeProto.Optional + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {onnx.TypeProto.Optional} Optional + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Optional.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies an Optional message. + * @function verify + * @memberof onnx.TypeProto.Optional + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + Optional.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.elemType != null && message.hasOwnProperty("elemType")) { + var error = $root.onnx.TypeProto.verify(message.elemType); + if (error) + return "elemType." + error; + } + return null; + }; + + /** + * Creates an Optional message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof onnx.TypeProto.Optional + * @static + * @param {Object.} object Plain object + * @returns {onnx.TypeProto.Optional} Optional + */ + Optional.fromObject = function fromObject(object) { + if (object instanceof $root.onnx.TypeProto.Optional) + return object; + var message = new $root.onnx.TypeProto.Optional(); + if (object.elemType != null) { + if (typeof object.elemType !== "object") + throw TypeError(".onnx.TypeProto.Optional.elemType: object expected"); + message.elemType = $root.onnx.TypeProto.fromObject(object.elemType); + } + return message; + }; + + /** + * Creates a plain object from an Optional message. Also converts values to other types if specified. + * @function toObject + * @memberof onnx.TypeProto.Optional + * @static + * @param {onnx.TypeProto.Optional} message Optional + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + Optional.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) + object.elemType = null; + if (message.elemType != null && message.hasOwnProperty("elemType")) + object.elemType = $root.onnx.TypeProto.toObject(message.elemType, options); + return object; + }; + + /** + * Converts this Optional to JSON. + * @function toJSON + * @memberof onnx.TypeProto.Optional + * @instance + * @returns {Object.} JSON object + */ + Optional.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + /** + * Gets the default type url for Optional + * @function getTypeUrl + * @memberof onnx.TypeProto.Optional + * @static + * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns {string} The default type url + */ + Optional.getTypeUrl = function getTypeUrl(typeUrlPrefix) { + if (typeUrlPrefix === undefined) { + typeUrlPrefix = "type.googleapis.com"; + } + return typeUrlPrefix + "/onnx.TypeProto.Optional"; + }; + + return Optional; + })(); + + TypeProto.SparseTensor = (function() { + + /** + * Properties of a SparseTensor. + * @memberof onnx.TypeProto + * @interface ISparseTensor + * @property {number|null} [elemType] SparseTensor elemType + * @property {onnx.ITensorShapeProto|null} [shape] SparseTensor shape + */ + + /** + * Constructs a new SparseTensor. + * @memberof onnx.TypeProto + * @classdesc Represents a SparseTensor. + * @implements ISparseTensor + * @constructor + * @param {onnx.TypeProto.ISparseTensor=} [properties] Properties to set + */ + function SparseTensor(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * SparseTensor elemType. + * @member {number} elemType + * @memberof onnx.TypeProto.SparseTensor + * @instance + */ + SparseTensor.prototype.elemType = 0; + + /** + * SparseTensor shape. + * @member {onnx.ITensorShapeProto|null|undefined} shape + * @memberof onnx.TypeProto.SparseTensor + * @instance + */ + SparseTensor.prototype.shape = null; + + /** + * Creates a new SparseTensor instance using the specified properties. + * @function create + * @memberof onnx.TypeProto.SparseTensor + * @static + * @param {onnx.TypeProto.ISparseTensor=} [properties] Properties to set + * @returns {onnx.TypeProto.SparseTensor} SparseTensor instance + */ + SparseTensor.create = function create(properties) { + return new SparseTensor(properties); + }; + + /** + * Encodes the specified SparseTensor message. Does not implicitly {@link onnx.TypeProto.SparseTensor.verify|verify} messages. + * @function encode + * @memberof onnx.TypeProto.SparseTensor + * @static + * @param {onnx.TypeProto.ISparseTensor} message SparseTensor message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + SparseTensor.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.elemType != null && Object.hasOwnProperty.call(message, "elemType")) + writer.uint32(/* id 1, wireType 0 =*/8).int32(message.elemType); + if (message.shape != null && Object.hasOwnProperty.call(message, "shape")) + $root.onnx.TensorShapeProto.encode(message.shape, writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified SparseTensor message, length delimited. Does not implicitly {@link onnx.TypeProto.SparseTensor.verify|verify} messages. + * @function encodeDelimited + * @memberof onnx.TypeProto.SparseTensor + * @static + * @param {onnx.TypeProto.ISparseTensor} message SparseTensor message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + SparseTensor.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a SparseTensor message from the specified reader or buffer. + * @function decode + * @memberof onnx.TypeProto.SparseTensor + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {onnx.TypeProto.SparseTensor} SparseTensor + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + SparseTensor.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.onnx.TypeProto.SparseTensor(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + message.elemType = reader.int32(); + break; + } + case 2: { + message.shape = $root.onnx.TensorShapeProto.decode(reader, reader.uint32()); + break; + } + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a SparseTensor message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof onnx.TypeProto.SparseTensor + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {onnx.TypeProto.SparseTensor} SparseTensor + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + SparseTensor.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a SparseTensor message. + * @function verify + * @memberof onnx.TypeProto.SparseTensor + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + SparseTensor.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.elemType != null && message.hasOwnProperty("elemType")) + if (!$util.isInteger(message.elemType)) + return "elemType: integer expected"; + if (message.shape != null && message.hasOwnProperty("shape")) { + var error = $root.onnx.TensorShapeProto.verify(message.shape); + if (error) + return "shape." + error; + } + return null; + }; + + /** + * Creates a SparseTensor message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof onnx.TypeProto.SparseTensor + * @static + * @param {Object.} object Plain object + * @returns {onnx.TypeProto.SparseTensor} SparseTensor + */ + SparseTensor.fromObject = function fromObject(object) { + if (object instanceof $root.onnx.TypeProto.SparseTensor) + return object; + var message = new $root.onnx.TypeProto.SparseTensor(); + if (object.elemType != null) + message.elemType = object.elemType | 0; + if (object.shape != null) { + if (typeof object.shape !== "object") + throw TypeError(".onnx.TypeProto.SparseTensor.shape: object expected"); + message.shape = $root.onnx.TensorShapeProto.fromObject(object.shape); + } + return message; + }; + + /** + * Creates a plain object from a SparseTensor message. Also converts values to other types if specified. + * @function toObject + * @memberof onnx.TypeProto.SparseTensor + * @static + * @param {onnx.TypeProto.SparseTensor} message SparseTensor + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + SparseTensor.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + object.elemType = 0; + object.shape = null; + } + if (message.elemType != null && message.hasOwnProperty("elemType")) + object.elemType = message.elemType; + if (message.shape != null && message.hasOwnProperty("shape")) + object.shape = $root.onnx.TensorShapeProto.toObject(message.shape, options); + return object; + }; + + /** + * Converts this SparseTensor to JSON. + * @function toJSON + * @memberof onnx.TypeProto.SparseTensor + * @instance + * @returns {Object.} JSON object + */ + SparseTensor.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + /** + * Gets the default type url for SparseTensor + * @function getTypeUrl + * @memberof onnx.TypeProto.SparseTensor + * @static + * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns {string} The default type url + */ + SparseTensor.getTypeUrl = function getTypeUrl(typeUrlPrefix) { + if (typeUrlPrefix === undefined) { + typeUrlPrefix = "type.googleapis.com"; + } + return typeUrlPrefix + "/onnx.TypeProto.SparseTensor"; + }; + + return SparseTensor; + })(); + + return TypeProto; + })(); + + onnx.OperatorSetIdProto = (function() { + + /** + * Properties of an OperatorSetIdProto. + * @memberof onnx + * @interface IOperatorSetIdProto + * @property {string|null} [domain] OperatorSetIdProto domain + * @property {number|Long|null} [version] OperatorSetIdProto version + */ + + /** + * Constructs a new OperatorSetIdProto. + * @memberof onnx + * @classdesc Represents an OperatorSetIdProto. + * @implements IOperatorSetIdProto + * @constructor + * @param {onnx.IOperatorSetIdProto=} [properties] Properties to set + */ + function OperatorSetIdProto(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * OperatorSetIdProto domain. + * @member {string} domain + * @memberof onnx.OperatorSetIdProto + * @instance + */ + OperatorSetIdProto.prototype.domain = ""; + + /** + * OperatorSetIdProto version. + * @member {number|Long} version + * @memberof onnx.OperatorSetIdProto + * @instance + */ + OperatorSetIdProto.prototype.version = $util.Long ? $util.Long.fromBits(0,0,false) : 0; + + /** + * Creates a new OperatorSetIdProto instance using the specified properties. + * @function create + * @memberof onnx.OperatorSetIdProto + * @static + * @param {onnx.IOperatorSetIdProto=} [properties] Properties to set + * @returns {onnx.OperatorSetIdProto} OperatorSetIdProto instance + */ + OperatorSetIdProto.create = function create(properties) { + return new OperatorSetIdProto(properties); + }; + + /** + * Encodes the specified OperatorSetIdProto message. Does not implicitly {@link onnx.OperatorSetIdProto.verify|verify} messages. + * @function encode + * @memberof onnx.OperatorSetIdProto + * @static + * @param {onnx.IOperatorSetIdProto} message OperatorSetIdProto message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + OperatorSetIdProto.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.domain != null && Object.hasOwnProperty.call(message, "domain")) + writer.uint32(/* id 1, wireType 2 =*/10).string(message.domain); + if (message.version != null && Object.hasOwnProperty.call(message, "version")) + writer.uint32(/* id 2, wireType 0 =*/16).int64(message.version); + return writer; + }; + + /** + * Encodes the specified OperatorSetIdProto message, length delimited. Does not implicitly {@link onnx.OperatorSetIdProto.verify|verify} messages. + * @function encodeDelimited + * @memberof onnx.OperatorSetIdProto + * @static + * @param {onnx.IOperatorSetIdProto} message OperatorSetIdProto message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + OperatorSetIdProto.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes an OperatorSetIdProto message from the specified reader or buffer. + * @function decode + * @memberof onnx.OperatorSetIdProto + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {onnx.OperatorSetIdProto} OperatorSetIdProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + OperatorSetIdProto.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.onnx.OperatorSetIdProto(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + message.domain = reader.string(); + break; + } + case 2: { + message.version = reader.int64(); + break; + } + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes an OperatorSetIdProto message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof onnx.OperatorSetIdProto + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {onnx.OperatorSetIdProto} OperatorSetIdProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + OperatorSetIdProto.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies an OperatorSetIdProto message. + * @function verify + * @memberof onnx.OperatorSetIdProto + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + OperatorSetIdProto.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.domain != null && message.hasOwnProperty("domain")) + if (!$util.isString(message.domain)) + return "domain: string expected"; + if (message.version != null && message.hasOwnProperty("version")) + if (!$util.isInteger(message.version) && !(message.version && $util.isInteger(message.version.low) && $util.isInteger(message.version.high))) + return "version: integer|Long expected"; + return null; + }; + + /** + * Creates an OperatorSetIdProto message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof onnx.OperatorSetIdProto + * @static + * @param {Object.} object Plain object + * @returns {onnx.OperatorSetIdProto} OperatorSetIdProto + */ + OperatorSetIdProto.fromObject = function fromObject(object) { + if (object instanceof $root.onnx.OperatorSetIdProto) + return object; + var message = new $root.onnx.OperatorSetIdProto(); + if (object.domain != null) + message.domain = String(object.domain); + if (object.version != null) + if ($util.Long) + (message.version = $util.Long.fromValue(object.version)).unsigned = false; + else if (typeof object.version === "string") + message.version = parseInt(object.version, 10); + else if (typeof object.version === "number") + message.version = object.version; + else if (typeof object.version === "object") + message.version = new $util.LongBits(object.version.low >>> 0, object.version.high >>> 0).toNumber(); + return message; + }; + + /** + * Creates a plain object from an OperatorSetIdProto message. Also converts values to other types if specified. + * @function toObject + * @memberof onnx.OperatorSetIdProto + * @static + * @param {onnx.OperatorSetIdProto} message OperatorSetIdProto + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + OperatorSetIdProto.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + object.domain = ""; + if ($util.Long) { + var long = new $util.Long(0, 0, false); + object.version = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long; + } else + object.version = options.longs === String ? "0" : 0; + } + if (message.domain != null && message.hasOwnProperty("domain")) + object.domain = message.domain; + if (message.version != null && message.hasOwnProperty("version")) + if (typeof message.version === "number") + object.version = options.longs === String ? String(message.version) : message.version; + else + object.version = options.longs === String ? $util.Long.prototype.toString.call(message.version) : options.longs === Number ? new $util.LongBits(message.version.low >>> 0, message.version.high >>> 0).toNumber() : message.version; + return object; + }; + + /** + * Converts this OperatorSetIdProto to JSON. + * @function toJSON + * @memberof onnx.OperatorSetIdProto + * @instance + * @returns {Object.} JSON object + */ + OperatorSetIdProto.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + /** + * Gets the default type url for OperatorSetIdProto + * @function getTypeUrl + * @memberof onnx.OperatorSetIdProto + * @static + * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns {string} The default type url + */ + OperatorSetIdProto.getTypeUrl = function getTypeUrl(typeUrlPrefix) { + if (typeUrlPrefix === undefined) { + typeUrlPrefix = "type.googleapis.com"; + } + return typeUrlPrefix + "/onnx.OperatorSetIdProto"; + }; + + return OperatorSetIdProto; + })(); + + /** + * OperatorStatus enum. + * @name onnx.OperatorStatus + * @enum {number} + * @property {number} EXPERIMENTAL=0 EXPERIMENTAL value + * @property {number} STABLE=1 STABLE value + */ + onnx.OperatorStatus = (function() { + var valuesById = {}, values = Object.create(valuesById); + values[valuesById[0] = "EXPERIMENTAL"] = 0; + values[valuesById[1] = "STABLE"] = 1; + return values; + })(); + + onnx.FunctionProto = (function() { + + /** + * Properties of a FunctionProto. + * @memberof onnx + * @interface IFunctionProto + * @property {string|null} [name] FunctionProto name + * @property {Array.|null} [input] FunctionProto input + * @property {Array.|null} [output] FunctionProto output + * @property {Array.|null} [attribute] FunctionProto attribute + * @property {Array.|null} [attributeProto] FunctionProto attributeProto + * @property {Array.|null} [node] FunctionProto node + * @property {string|null} [docString] FunctionProto docString + * @property {Array.|null} [opsetImport] FunctionProto opsetImport + * @property {string|null} [domain] FunctionProto domain + */ + + /** + * Constructs a new FunctionProto. + * @memberof onnx + * @classdesc Represents a FunctionProto. + * @implements IFunctionProto + * @constructor + * @param {onnx.IFunctionProto=} [properties] Properties to set + */ + function FunctionProto(properties) { + this.input = []; + this.output = []; + this.attribute = []; + this.attributeProto = []; + this.node = []; + this.opsetImport = []; + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * FunctionProto name. + * @member {string} name + * @memberof onnx.FunctionProto + * @instance + */ + FunctionProto.prototype.name = ""; + + /** + * FunctionProto input. + * @member {Array.} input + * @memberof onnx.FunctionProto + * @instance + */ + FunctionProto.prototype.input = $util.emptyArray; + + /** + * FunctionProto output. + * @member {Array.} output + * @memberof onnx.FunctionProto + * @instance + */ + FunctionProto.prototype.output = $util.emptyArray; + + /** + * FunctionProto attribute. + * @member {Array.} attribute + * @memberof onnx.FunctionProto + * @instance + */ + FunctionProto.prototype.attribute = $util.emptyArray; + + /** + * FunctionProto attributeProto. + * @member {Array.} attributeProto + * @memberof onnx.FunctionProto + * @instance + */ + FunctionProto.prototype.attributeProto = $util.emptyArray; + + /** + * FunctionProto node. + * @member {Array.} node + * @memberof onnx.FunctionProto + * @instance + */ + FunctionProto.prototype.node = $util.emptyArray; + + /** + * FunctionProto docString. + * @member {string} docString + * @memberof onnx.FunctionProto + * @instance + */ + FunctionProto.prototype.docString = ""; + + /** + * FunctionProto opsetImport. + * @member {Array.} opsetImport + * @memberof onnx.FunctionProto + * @instance + */ + FunctionProto.prototype.opsetImport = $util.emptyArray; + + /** + * FunctionProto domain. + * @member {string} domain + * @memberof onnx.FunctionProto + * @instance + */ + FunctionProto.prototype.domain = ""; + + /** + * Creates a new FunctionProto instance using the specified properties. + * @function create + * @memberof onnx.FunctionProto + * @static + * @param {onnx.IFunctionProto=} [properties] Properties to set + * @returns {onnx.FunctionProto} FunctionProto instance + */ + FunctionProto.create = function create(properties) { + return new FunctionProto(properties); + }; + + /** + * Encodes the specified FunctionProto message. Does not implicitly {@link onnx.FunctionProto.verify|verify} messages. + * @function encode + * @memberof onnx.FunctionProto + * @static + * @param {onnx.IFunctionProto} message FunctionProto message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + FunctionProto.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.name != null && Object.hasOwnProperty.call(message, "name")) + writer.uint32(/* id 1, wireType 2 =*/10).string(message.name); + if (message.input != null && message.input.length) + for (var i = 0; i < message.input.length; ++i) + writer.uint32(/* id 4, wireType 2 =*/34).string(message.input[i]); + if (message.output != null && message.output.length) + for (var i = 0; i < message.output.length; ++i) + writer.uint32(/* id 5, wireType 2 =*/42).string(message.output[i]); + if (message.attribute != null && message.attribute.length) + for (var i = 0; i < message.attribute.length; ++i) + writer.uint32(/* id 6, wireType 2 =*/50).string(message.attribute[i]); + if (message.node != null && message.node.length) + for (var i = 0; i < message.node.length; ++i) + $root.onnx.NodeProto.encode(message.node[i], writer.uint32(/* id 7, wireType 2 =*/58).fork()).ldelim(); + if (message.docString != null && Object.hasOwnProperty.call(message, "docString")) + writer.uint32(/* id 8, wireType 2 =*/66).string(message.docString); + if (message.opsetImport != null && message.opsetImport.length) + for (var i = 0; i < message.opsetImport.length; ++i) + $root.onnx.OperatorSetIdProto.encode(message.opsetImport[i], writer.uint32(/* id 9, wireType 2 =*/74).fork()).ldelim(); + if (message.domain != null && Object.hasOwnProperty.call(message, "domain")) + writer.uint32(/* id 10, wireType 2 =*/82).string(message.domain); + if (message.attributeProto != null && message.attributeProto.length) + for (var i = 0; i < message.attributeProto.length; ++i) + $root.onnx.AttributeProto.encode(message.attributeProto[i], writer.uint32(/* id 11, wireType 2 =*/90).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified FunctionProto message, length delimited. Does not implicitly {@link onnx.FunctionProto.verify|verify} messages. + * @function encodeDelimited + * @memberof onnx.FunctionProto + * @static + * @param {onnx.IFunctionProto} message FunctionProto message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + FunctionProto.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a FunctionProto message from the specified reader or buffer. + * @function decode + * @memberof onnx.FunctionProto + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {onnx.FunctionProto} FunctionProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + FunctionProto.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.onnx.FunctionProto(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + message.name = reader.string(); + break; + } + case 4: { + if (!(message.input && message.input.length)) + message.input = []; + message.input.push(reader.string()); + break; + } + case 5: { + if (!(message.output && message.output.length)) + message.output = []; + message.output.push(reader.string()); + break; + } + case 6: { + if (!(message.attribute && message.attribute.length)) + message.attribute = []; + message.attribute.push(reader.string()); + break; + } + case 11: { + if (!(message.attributeProto && message.attributeProto.length)) + message.attributeProto = []; + message.attributeProto.push($root.onnx.AttributeProto.decode(reader, reader.uint32())); + break; + } + case 7: { + if (!(message.node && message.node.length)) + message.node = []; + message.node.push($root.onnx.NodeProto.decode(reader, reader.uint32())); + break; + } + case 8: { + message.docString = reader.string(); + break; + } + case 9: { + if (!(message.opsetImport && message.opsetImport.length)) + message.opsetImport = []; + message.opsetImport.push($root.onnx.OperatorSetIdProto.decode(reader, reader.uint32())); + break; + } + case 10: { + message.domain = reader.string(); + break; + } + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a FunctionProto message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof onnx.FunctionProto + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {onnx.FunctionProto} FunctionProto + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + FunctionProto.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a FunctionProto message. + * @function verify + * @memberof onnx.FunctionProto + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + FunctionProto.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.name != null && message.hasOwnProperty("name")) + if (!$util.isString(message.name)) + return "name: string expected"; + if (message.input != null && message.hasOwnProperty("input")) { + if (!Array.isArray(message.input)) + return "input: array expected"; + for (var i = 0; i < message.input.length; ++i) + if (!$util.isString(message.input[i])) + return "input: string[] expected"; + } + if (message.output != null && message.hasOwnProperty("output")) { + if (!Array.isArray(message.output)) + return "output: array expected"; + for (var i = 0; i < message.output.length; ++i) + if (!$util.isString(message.output[i])) + return "output: string[] expected"; + } + if (message.attribute != null && message.hasOwnProperty("attribute")) { + if (!Array.isArray(message.attribute)) + return "attribute: array expected"; + for (var i = 0; i < message.attribute.length; ++i) + if (!$util.isString(message.attribute[i])) + return "attribute: string[] expected"; + } + if (message.attributeProto != null && message.hasOwnProperty("attributeProto")) { + if (!Array.isArray(message.attributeProto)) + return "attributeProto: array expected"; + for (var i = 0; i < message.attributeProto.length; ++i) { + var error = $root.onnx.AttributeProto.verify(message.attributeProto[i]); + if (error) + return "attributeProto." + error; + } + } + if (message.node != null && message.hasOwnProperty("node")) { + if (!Array.isArray(message.node)) + return "node: array expected"; + for (var i = 0; i < message.node.length; ++i) { + var error = $root.onnx.NodeProto.verify(message.node[i]); + if (error) + return "node." + error; + } + } + if (message.docString != null && message.hasOwnProperty("docString")) + if (!$util.isString(message.docString)) + return "docString: string expected"; + if (message.opsetImport != null && message.hasOwnProperty("opsetImport")) { + if (!Array.isArray(message.opsetImport)) + return "opsetImport: array expected"; + for (var i = 0; i < message.opsetImport.length; ++i) { + var error = $root.onnx.OperatorSetIdProto.verify(message.opsetImport[i]); + if (error) + return "opsetImport." + error; + } + } + if (message.domain != null && message.hasOwnProperty("domain")) + if (!$util.isString(message.domain)) + return "domain: string expected"; + return null; + }; + + /** + * Creates a FunctionProto message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof onnx.FunctionProto + * @static + * @param {Object.} object Plain object + * @returns {onnx.FunctionProto} FunctionProto + */ + FunctionProto.fromObject = function fromObject(object) { + if (object instanceof $root.onnx.FunctionProto) + return object; + var message = new $root.onnx.FunctionProto(); + if (object.name != null) + message.name = String(object.name); + if (object.input) { + if (!Array.isArray(object.input)) + throw TypeError(".onnx.FunctionProto.input: array expected"); + message.input = []; + for (var i = 0; i < object.input.length; ++i) + message.input[i] = String(object.input[i]); + } + if (object.output) { + if (!Array.isArray(object.output)) + throw TypeError(".onnx.FunctionProto.output: array expected"); + message.output = []; + for (var i = 0; i < object.output.length; ++i) + message.output[i] = String(object.output[i]); + } + if (object.attribute) { + if (!Array.isArray(object.attribute)) + throw TypeError(".onnx.FunctionProto.attribute: array expected"); + message.attribute = []; + for (var i = 0; i < object.attribute.length; ++i) + message.attribute[i] = String(object.attribute[i]); + } + if (object.attributeProto) { + if (!Array.isArray(object.attributeProto)) + throw TypeError(".onnx.FunctionProto.attributeProto: array expected"); + message.attributeProto = []; + for (var i = 0; i < object.attributeProto.length; ++i) { + if (typeof object.attributeProto[i] !== "object") + throw TypeError(".onnx.FunctionProto.attributeProto: object expected"); + message.attributeProto[i] = $root.onnx.AttributeProto.fromObject(object.attributeProto[i]); + } + } + if (object.node) { + if (!Array.isArray(object.node)) + throw TypeError(".onnx.FunctionProto.node: array expected"); + message.node = []; + for (var i = 0; i < object.node.length; ++i) { + if (typeof object.node[i] !== "object") + throw TypeError(".onnx.FunctionProto.node: object expected"); + message.node[i] = $root.onnx.NodeProto.fromObject(object.node[i]); + } + } + if (object.docString != null) + message.docString = String(object.docString); + if (object.opsetImport) { + if (!Array.isArray(object.opsetImport)) + throw TypeError(".onnx.FunctionProto.opsetImport: array expected"); + message.opsetImport = []; + for (var i = 0; i < object.opsetImport.length; ++i) { + if (typeof object.opsetImport[i] !== "object") + throw TypeError(".onnx.FunctionProto.opsetImport: object expected"); + message.opsetImport[i] = $root.onnx.OperatorSetIdProto.fromObject(object.opsetImport[i]); + } + } + if (object.domain != null) + message.domain = String(object.domain); + return message; + }; + + /** + * Creates a plain object from a FunctionProto message. Also converts values to other types if specified. + * @function toObject + * @memberof onnx.FunctionProto + * @static + * @param {onnx.FunctionProto} message FunctionProto + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + FunctionProto.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.arrays || options.defaults) { + object.input = []; + object.output = []; + object.attribute = []; + object.node = []; + object.opsetImport = []; + object.attributeProto = []; + } + if (options.defaults) { + object.name = ""; + object.docString = ""; + object.domain = ""; + } + if (message.name != null && message.hasOwnProperty("name")) + object.name = message.name; + if (message.input && message.input.length) { + object.input = []; + for (var j = 0; j < message.input.length; ++j) + object.input[j] = message.input[j]; + } + if (message.output && message.output.length) { + object.output = []; + for (var j = 0; j < message.output.length; ++j) + object.output[j] = message.output[j]; + } + if (message.attribute && message.attribute.length) { + object.attribute = []; + for (var j = 0; j < message.attribute.length; ++j) + object.attribute[j] = message.attribute[j]; + } + if (message.node && message.node.length) { + object.node = []; + for (var j = 0; j < message.node.length; ++j) + object.node[j] = $root.onnx.NodeProto.toObject(message.node[j], options); + } + if (message.docString != null && message.hasOwnProperty("docString")) + object.docString = message.docString; + if (message.opsetImport && message.opsetImport.length) { + object.opsetImport = []; + for (var j = 0; j < message.opsetImport.length; ++j) + object.opsetImport[j] = $root.onnx.OperatorSetIdProto.toObject(message.opsetImport[j], options); + } + if (message.domain != null && message.hasOwnProperty("domain")) + object.domain = message.domain; + if (message.attributeProto && message.attributeProto.length) { + object.attributeProto = []; + for (var j = 0; j < message.attributeProto.length; ++j) + object.attributeProto[j] = $root.onnx.AttributeProto.toObject(message.attributeProto[j], options); + } + return object; + }; + + /** + * Converts this FunctionProto to JSON. + * @function toJSON + * @memberof onnx.FunctionProto + * @instance + * @returns {Object.} JSON object + */ + FunctionProto.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + /** + * Gets the default type url for FunctionProto + * @function getTypeUrl + * @memberof onnx.FunctionProto + * @static + * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns {string} The default type url + */ + FunctionProto.getTypeUrl = function getTypeUrl(typeUrlPrefix) { + if (typeUrlPrefix === undefined) { + typeUrlPrefix = "type.googleapis.com"; + } + return typeUrlPrefix + "/onnx.FunctionProto"; + }; + + return FunctionProto; + })(); + + return onnx; +})(); + +module.exports = $root; diff --git a/js/web/lib/onnxjs/session.ts b/js/web/lib/onnxjs/session.ts index 3a27a424e7aed..790be3c740cd5 100644 --- a/js/web/lib/onnxjs/session.ts +++ b/js/web/lib/onnxjs/session.ts @@ -60,7 +60,7 @@ export class Session { this._model = new Model(); if (typeof arg === 'string') { const isOrtFormat = arg.endsWith('.ort'); - if (typeof fetch === 'undefined') { + if (typeof process !== 'undefined' && process.versions && process.versions.node) { // node const buf = await promisify(readFile)(arg); this.initialize(buf, isOrtFormat); diff --git a/js/web/lib/onnxjs/tensor.ts b/js/web/lib/onnxjs/tensor.ts index 4ec49f7b936ea..1a4c1dfe7494d 100644 --- a/js/web/lib/onnxjs/tensor.ts +++ b/js/web/lib/onnxjs/tensor.ts @@ -3,9 +3,9 @@ import {Guid} from 'guid-typescript'; import Long from 'long'; -import {onnx} from 'onnx-proto'; -import {onnxruntime} from './ort-schema/ort-generated'; +import {onnxruntime} from './ort-schema/flatbuffers/ort-generated'; +import {onnx} from './ort-schema/protobuf/onnx'; import {decodeUtf8String, ProtoUtil, ShapeUtil} from './util'; import ortFbs = onnxruntime.experimental.fbs; @@ -22,6 +22,7 @@ export declare namespace Tensor { uint16: Uint16Array; int32: Int32Array; uint32: Uint32Array; + int64: BigInt64Array; } export type DataType = keyof DataTypeMap; @@ -409,6 +410,8 @@ function dataviewConstructor(type: Tensor.DataType) { return Int32Array; case 'uint32': return Uint32Array; + case 'int64': + return BigInt64Array; case 'float32': return Float32Array; case 'float64': diff --git a/js/web/lib/onnxjs/util.ts b/js/web/lib/onnxjs/util.ts index 54806f90f28b5..0a76d75e79bbf 100644 --- a/js/web/lib/onnxjs/util.ts +++ b/js/web/lib/onnxjs/util.ts @@ -3,10 +3,10 @@ import {flatbuffers} from 'flatbuffers'; import Long from 'long'; -import {onnx} from 'onnx-proto'; import {Graph} from './graph'; -import {onnxruntime} from './ort-schema/ort-generated'; +import {onnxruntime} from './ort-schema/flatbuffers/ort-generated'; +import {onnx} from './ort-schema/protobuf/onnx'; import {Tensor} from './tensor'; // check the inputs shape before running an OP. @@ -210,7 +210,7 @@ export class BroadcastUtil { // both inputs are scalars if (outputShape.length === 0) { - c.set([], op(a.get([]), b.get([]))); + c.set([], op(a.get([]) as number, b.get([]) as number)); } // atleast one input is a non-scalar @@ -223,11 +223,11 @@ export class BroadcastUtil { let isAScalar = false; let isBScalar = false; if (a.dims.length === 0) { - valA = a.get([]); + valA = a.get([]) as number; isAScalar = true; } if (b.dims.length === 0) { - valB = b.get([]); + valB = b.get([]) as number; isBScalar = true; } let rest: number; @@ -242,11 +242,11 @@ export class BroadcastUtil { if (!isAScalar) { // map outputIndices (which is actually broadcasted) to the originalIndices BroadcastUtil.fillIndex(outputIndices, a.dims, originalIndicesA); - valA = a.get(originalIndicesA); + valA = a.get(originalIndicesA) as number; } if (!isBScalar) { BroadcastUtil.fillIndex(outputIndices, b.dims, originalIndicesB); - valB = b.get(originalIndicesB); + valB = b.get(originalIndicesB) as number; } c.set(outputIndices, op(valA, valB)); diff --git a/js/web/lib/version.ts b/js/web/lib/version.ts new file mode 100644 index 0000000000000..96c2361cceabe --- /dev/null +++ b/js/web/lib/version.ts @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// This file is generated by /js/scripts/update-version.ts +// Do not modify file content manually. + +export const version = '1.17.0'; diff --git a/js/web/lib/wasm/binding/ort-wasm.d.ts b/js/web/lib/wasm/binding/ort-wasm.d.ts index 2e51d3257ec9c..59da1369e152e 100644 --- a/js/web/lib/wasm/binding/ort-wasm.d.ts +++ b/js/web/lib/wasm/binding/ort-wasm.d.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -declare namespace JSEP { +export declare namespace JSEP { type BackendType = unknown; type AllocFunction = (size: number) => number; type FreeFunction = (size: number) => number; @@ -9,7 +9,11 @@ declare namespace JSEP { type DownloadFunction = (gpuDataId: number, dataOffset: number, size: number) => Promise; type CreateKernelFunction = (name: string, kernel: number, attribute: unknown) => void; type ReleaseKernelFunction = (kernel: number) => void; - type RunFunction = (kernel: number, contextDataOffset: number) => number; + type RunFunction = (kernel: number, contextDataOffset: number, sessionState: SessionState) => number; + export interface SessionState { + sessionId: number; + errors: Array>; + } } export interface OrtWasmModule extends EmscriptenModule { @@ -26,10 +30,11 @@ export interface OrtWasmModule extends EmscriptenModule { // #region ORT APIs _OrtInit(numThreads: number, loggingLevel: number): number; + _OrtGetLastError(errorCodeOffset: number, errorMessageOffset: number): void; + _OrtCreateSession(dataOffset: number, dataLength: number, sessionOptionsHandle: number): number; _OrtReleaseSession(sessionHandle: number): void; - _OrtGetInputCount(sessionHandle: number): number; - _OrtGetOutputCount(sessionHandle: number): number; + _OrtGetInputOutputCount(sessionHandle: number, inputCountOffset: number, outputCountOffset: number): number; _OrtGetInputName(sessionHandle: number, index: number): number; _OrtGetOutputName(sessionHandle: number, index: number): number; @@ -49,6 +54,7 @@ export interface OrtWasmModule extends EmscriptenModule { enableProfiling: boolean, profileFilePrefix: number, logId: number, logSeverityLevel: number, logVerbosityLevel: number, optimizedModelFilePath: number): number; _OrtAppendExecutionProvider(sessionOptionsHandle: number, name: number): number; + _OrtAddFreeDimensionOverride(sessionOptionsHandle: number, name: number, dim: number): number; _OrtAddSessionConfigEntry(sessionOptionsHandle: number, configKey: number, configValue: number): number; _OrtReleaseSessionOptions(sessionOptionsHandle: number): void; @@ -59,6 +65,38 @@ export interface OrtWasmModule extends EmscriptenModule { _OrtEndProfiling(sessionHandle: number): number; // #endregion + // #region ORT Training APIs + _OrtTrainingLoadCheckpoint?(dataOffset: number, dataLength: number): number; + + _OrtTrainingReleaseCheckpoint?(checkpointHandle: number): void; + + _OrtTrainingCreateSession? + (sessionOptionsHandle: number, checkpointHandle: number, trainOffset: number, trainLength: number, + evalOffset: number, evalLength: number, optimizerOffset: number, optimizerLength: number): number; + + _OrtTrainingLazyResetGrad?(trainingHandle: number): number; + + _OrtTrainingRunTrainStep? + (trainingHandle: number, inputsOffset: number, inputCount: number, outputsOffset: number, outputCount: number, + runOptionsHandle: number): number; + + _OrtTrainingOptimizerStep?(trainingHandle: number, runOptionsHandle: number): number; + + _OrtTrainingEvalStep? + (trainingHandle: number, inputsOffset: number, inputCount: number, outputsOffset: number, outputCount: number, + runOptionsHandle: number): number; + + _OrtTrainingGetParametersSize?(trainingHandle: number, paramSizeT: number, trainableOnly: boolean): number; + + _OrtTrainingCopyParametersToBuffer? + (trainingHandle: number, parametersBuffer: number, parameterCount: number, trainableOnly: boolean): number; + + _OrtTrainingCopyParametersFromBuffer? + (trainingHandle: number, parametersBuffer: number, parameterCount: number, trainableOnly: boolean): number; + + _OrtTrainingReleaseSession?(trainingHandle: number): void; + // #endregion + // #region config mainScriptUrlOrBlob?: string|Blob; // #endregion @@ -70,7 +108,10 @@ export interface OrtWasmModule extends EmscriptenModule { releaseKernel: JSEP.ReleaseKernelFunction, run: JSEP.RunFunction): void; _JsepOutput(context: number, index: number, data: number): number; + _JsepGetNodeName(kernel: number): number; + jsepOnRunStart?(sessionId: number): void; + jsepOnRunEnd?(sessionId: number): Promise; jsepRunPromise?: Promise; // #endregion } diff --git a/js/web/lib/wasm/jsep/backend-webgpu.ts b/js/web/lib/wasm/jsep/backend-webgpu.ts index 849e8d3f41bbc..5e77a0343b4ee 100644 --- a/js/web/lib/wasm/jsep/backend-webgpu.ts +++ b/js/web/lib/wasm/jsep/backend-webgpu.ts @@ -1,32 +1,32 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import {env} from 'onnxruntime-common'; +import {Env} from 'onnxruntime-common'; -import {LOG_DEBUG} from './log'; -import {TensorView} from './tensor'; +import {configureLogger, LOG_DEBUG} from './log'; +import {TensorView} from './tensor-view'; import {createGpuDataManager, GpuDataManager} from './webgpu/gpu-data-manager'; import {RunFunction, WEBGPU_OP_RESOLVE_RULES} from './webgpu/op-resolve-rules'; import {ProgramManager} from './webgpu/program-manager'; -import {ComputeContext, GpuData, GpuDataType, ProgramInfo, ProgramInfoLoader} from './webgpu/types'; +import {ComputeContext, GpuData, ProgramInfo, ProgramInfoLoader} from './webgpu/types'; /** - * get a unique key representing the program from the program info,input shapes and types. + * get a unique key representing the program from the program info, input shapes and types. * * @returns a unique key is a shorter string than the shader source, which contains all the information to identify a * program. if the key is the same, the program shader source should be the same, so we can reuse the program. * */ const getProgramInfoUniqueKey = - (programInfo: ProgramInfo|ProgramInfoLoader, inputTensorShapes: ReadonlyArray, - inputGpuDataTypes: readonly GpuDataType[]): string => { - const inputTensorShapesToString = inputTensorShapes.map(d => `${d.join(',')}`).join('_'); - const inputGpuDataTypesToString = inputGpuDataTypes.join('_'); + (programInfo: ProgramInfo|ProgramInfoLoader, inputTensors: readonly TensorView[]): string => { + // final key format: + // []:||... + const inputInfos = inputTensors.map(tensor => `${tensor.dataType};${tensor.dims.join(',')}`).join('|'); let key = programInfo.name; if (programInfo.cacheHint) { key += '[' + programInfo.cacheHint + ']'; } - key += ':' + inputTensorShapesToString + ';' + inputGpuDataTypesToString; + key += ':' + inputInfos; return key; }; @@ -82,19 +82,23 @@ export class WebGpuBackend { } /** - * a KernelID -> kernel info mapping. value is [ name, run function, [optional] preprocess_attribute_once function ] + * a KernelID -> kernel info mapping. value is + * [ op_type, name, run function, [optional] preprocess_attribute_once function ] */ - kernels: Map unknown) | undefined, unknown]]>; + kernels: Map unknown) | undefined, unknown]]>; commandEncoder: GPUCommandEncoder|null = null; computePassEncoder: GPUComputePassEncoder|null = null; pendingDispatchNumber = 0; - profilingEnabled = false; + supportTimestampQuery = false; profilingQuerySet: GPUQuerySet; + profilingQueryData: GpuData; profilingTimeBase?: bigint; - async initialize(): Promise { + env: Env; + + async initialize(env: Env): Promise { if (!navigator.gpu) { // WebGPU is not available. throw new Error('WebGpuBackend: WebGPU is not available.'); @@ -105,19 +109,29 @@ export class WebGpuBackend { throw new Error('WebGpuBackend: Failed to get GPU adapter.'); } + this.env = env; + const requiredFeatures: GPUFeatureName[] = []; const deviceDescriptor: GPUDeviceDescriptor = { requiredLimits: { maxComputeWorkgroupStorageSize: adapter.limits.maxComputeWorkgroupStorageSize, maxComputeWorkgroupsPerDimension: adapter.limits.maxComputeWorkgroupsPerDimension, maxStorageBufferBindingSize: adapter.limits.maxStorageBufferBindingSize, - } + maxBufferSize: adapter.limits.maxBufferSize, + maxComputeInvocationsPerWorkgroup: adapter.limits.maxComputeInvocationsPerWorkgroup, + maxComputeWorkgroupSizeX: adapter.limits.maxComputeWorkgroupSizeX, + maxComputeWorkgroupSizeY: adapter.limits.maxComputeWorkgroupSizeY, + maxComputeWorkgroupSizeZ: adapter.limits.maxComputeWorkgroupSizeZ, + }, + requiredFeatures, }; // WebGPU Spec: Timestamp Queries Inside Passes // https://github.com/gpuweb/gpuweb/blob/main/proposals/timestamp-query-inside-passes.md - if (adapter.features.has('timestamp-query-inside-passes') && env.webgpu.profilingMode === 'default') { - this.profilingEnabled = true; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - deviceDescriptor.requiredFeatures = ['timestamp-query-inside-passes' as any]; + if (adapter.features.has('timestamp-query-inside-passes')) { + this.supportTimestampQuery = true; + requiredFeatures.push('timestamp-query-inside-passes' as GPUFeatureName); + } + if (adapter.features.has('shader-f16')) { + requiredFeatures.push('shader-f16'); } this.device = await adapter.requestDevice(deviceDescriptor); @@ -126,6 +140,10 @@ export class WebGpuBackend { this.kernels = new Map(); this.kernelPersistentData = new Map(); this.kernelCustomData = new Map(); + + // set up flags for logger + configureLogger(env.logLevel!, !!env.debug); + // TODO: set up flags this.device.onuncapturederror = ev => { @@ -135,17 +153,21 @@ export class WebGpuBackend { } }; - if (this.profilingEnabled) { + if (this.supportTimestampQuery) { this.profilingQuerySet = this.device.createQuerySet({ type: 'timestamp', count: 2, }); } + + Object.defineProperty(this.env.webgpu, 'device', {value: this.device}); } dispose(): void { - // TODO: uninitialization - // this.glContext.dispose(); + // currently, we do not do anything in this function. In all known use cases, we don't have the requirement to + // actually dispose the WebGpuBackend instance, because it's always used as a singleton. + // + // revisit this place if we get real requirement to dispose the instance. } getCommandEncoder(): GPUCommandEncoder { @@ -206,7 +228,7 @@ export class WebGpuBackend { inputDatas[i] = gpuData; } - const key = getProgramInfoUniqueKey(program, inputs.map(i => i.dims), inputDatas.map(i => i.type)); + const key = getProgramInfoUniqueKey(program, inputs); let artifact = this.programManager.getArtifact(key); const programInfo = artifact ? artifact.programInfo : @@ -223,12 +245,16 @@ export class WebGpuBackend { const outputTensorViews: TensorView[] = []; const outputDatas: GpuData[] = []; for (let i = 0; i < programInfo.outputs.length; ++i) { - // value -1 and -2 are used for creating temporary and persistent outputs. so -2, -1 and 0, 1, 2, ... are valid + // value -1 and -2 are used for creating temporary and persistent outputs. + // value -3 is used for placeholder output. So -3, -2, -1 and 0, 1, 2, ... are valid // output indices. see type definition of ComputeContextInputsOutputsMapping for more details. - if (!Number.isInteger(validatedOutputIndices[i]) || validatedOutputIndices[i] < -2 || + if (!Number.isInteger(validatedOutputIndices[i]) || validatedOutputIndices[i] < -3 || validatedOutputIndices[i] >= programInfo.outputs.length) { throw new Error(`Invalid output index: ${validatedOutputIndices[i]}`); } + if (validatedOutputIndices[i] === -3) { + continue; + } const isTemporary = validatedOutputIndices[i] === -1; const isPersistent = validatedOutputIndices[i] === -2; const tensorView = (isTemporary || isPersistent) ? @@ -264,7 +290,7 @@ export class WebGpuBackend { 'info', () => `[ProgramManager] run "${programInfo.name}" (key=${key}) with ${normalizedDispatchGroup[0]}x${ normalizedDispatchGroup[1]}x${normalizedDispatchGroup[2]}`); - this.programManager.run(artifact, inputDatas, outputDatas, normalizedDispatchGroup); + this.programManager.run(artifact, inputs, inputDatas, outputDatas, normalizedDispatchGroup); return outputTensorViews; } @@ -277,9 +303,13 @@ export class WebGpuBackend { this.gpuDataManager.memcpy(src, dst); } - async download(gpuDataId: number, data: Uint8Array): Promise { + async download(gpuDataId: number, getTargetBuffer: () => Uint8Array): Promise { const arrayBuffer = await this.gpuDataManager.download(gpuDataId); - data.set(new Uint8Array(arrayBuffer)); + + // the underlying buffer may be changed after the async function is called. so we use a getter function to make sure + // the buffer is up-to-date. + const data = getTargetBuffer(); + data.set(new Uint8Array(arrayBuffer, 0, data.byteLength)); } alloc(size: number): number { @@ -290,13 +320,13 @@ export class WebGpuBackend { return this.gpuDataManager.release(ptr); } - createKernel(name: string, kernelId: number, attribute: unknown): void { - const op = WEBGPU_OP_RESOLVE_RULES.get(name); + createKernel(opType: string, kernelId: number, attribute: unknown, nodeName: string): void { + const op = WEBGPU_OP_RESOLVE_RULES.get(opType); if (!op) { - throw new Error(`kernel not implemented: ${name}`); + throw new Error(`kernel not implemented: ${opType}`); } - this.kernels.set(kernelId, [name, op[0], [op[1], attribute]]); + this.kernels.set(kernelId, [opType, nodeName, op[0], [op[1], attribute]]); } releaseKernel(kernelId: number): void { @@ -312,14 +342,14 @@ export class WebGpuBackend { this.kernels.delete(kernelId); } - computeKernel(kernelId: number, context: ComputeContext): number { + computeKernel(kernelId: number, context: ComputeContext, errors: Array>): number { const kernel = this.kernels.get(kernelId); if (!kernel) { throw new Error(`kernel not created: ${kernelId}`); } - const [name, kernelEntry, attributes] = kernel; + const [opType, nodeName, kernelEntry, attributes] = kernel; if (this.currentKernelId !== null) { - throw new Error(`kernel "${name}" is not allowed to be called recursively`); + throw new Error(`kernel "[${opType}] ${nodeName}" is not allowed to be called recursively`); } this.currentKernelId = kernelId; @@ -329,16 +359,27 @@ export class WebGpuBackend { attributes[0] = undefined; } - LOG_DEBUG('info', () => `[WebGPU] Start to run kernel "${name}"...`); + LOG_DEBUG('info', () => `[WebGPU] Start to run kernel "[${opType}] ${nodeName}"...`); + + const useErrorScope = this.env.debug; this.temporaryData = []; try { + if (useErrorScope) { + this.device.pushErrorScope('validation'); + } + kernelEntry(context, attributes[1]); return 0; // ORT_OK } catch (e) { - LOG_DEBUG('warning', `[WebGPU] Kernel "${name}" failed. Error: ${e}`); + LOG_DEBUG('warning', `[WebGPU] Kernel "[${opType}] ${nodeName}" failed. Error: ${e}`); return 1; // ORT_FAIL } finally { + if (useErrorScope) { + errors.push(this.device.popErrorScope().then( + err => err ? `GPU validation error for kernel "[${opType}] ${nodeName}": ${err.message}` : null)); + } + for (const data of this.temporaryData) { this.gpuDataManager.release(data.id); } diff --git a/js/web/lib/wasm/jsep/init.ts b/js/web/lib/wasm/jsep/init.ts index 4226a0ef46f57..78316cbe1c825 100644 --- a/js/web/lib/wasm/jsep/init.ts +++ b/js/web/lib/wasm/jsep/init.ts @@ -1,12 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import {OrtWasmModule} from '../binding/ort-wasm'; -import {getTensorElementSize} from '../wasm-common'; +import {Env} from 'onnxruntime-common'; + +import {JSEP, OrtWasmModule} from '../binding/ort-wasm'; +import {DataType, getTensorElementSize} from '../wasm-common'; import {WebGpuBackend} from './backend-webgpu'; import {LOG_DEBUG} from './log'; -import {TensorView} from './tensor'; +import {TensorView} from './tensor-view'; import {ShapeUtil} from './util'; import {ComputeContext, ComputeContextInputsOutputsMapping, ProgramInfo, ProgramInfoLoader} from './webgpu/types'; @@ -18,7 +20,29 @@ class TensorViewImpl implements TensorView { public readonly dims: readonly number[]) {} getFloat32Array(): Float32Array { - return new Float32Array(this.module.HEAP8.buffer, this.data, ShapeUtil.size(this.dims)); + if (this.dataType !== DataType.float) { + throw new Error('Invalid data type'); + } + const elementCount = ShapeUtil.size(this.dims); + return elementCount === 0 ? new Float32Array() : + new Float32Array(this.module.HEAP8.buffer, this.data, elementCount); + } + + getBigInt64Array(): BigInt64Array { + if (this.dataType !== DataType.int64) { + throw new Error('Invalid data type'); + } + const elementCount = ShapeUtil.size(this.dims); + return elementCount === 0 ? new BigInt64Array() : + new BigInt64Array(this.module.HEAP8.buffer, this.data, elementCount); + } + + getInt32Array(): Int32Array { + if (this.dataType !== DataType.int32) { + throw new Error('Invalid data type'); + } + const elementCount = ShapeUtil.size(this.dims); + return elementCount === 0 ? new Int32Array() : new Int32Array(this.module.HEAP8.buffer, this.data, elementCount); } reshape(newDims: readonly number[]): TensorView { @@ -29,12 +53,18 @@ class TensorViewImpl implements TensorView { } } -class OpKernelContext implements ComputeContext { +class ComputeContextImpl implements ComputeContext { readonly opKernelContext: number; readonly inputs: readonly TensorView[]; - get customData(): {[key: string]: unknown} { + readonly outputCount: number; + get kernelCustomData(): {[key: string]: unknown} { return this.backend.currentKernelCustomData; } + get customDataBuffer(): Uint8Array { + return this.module.HEAPU8.subarray(this.customDataOffset, this.customDataOffset + this.customDataSize); + } + private customDataOffset = 0; + private customDataSize = 0; constructor(private module: OrtWasmModule, private backend: WebGpuBackend, contextDataOffset: number) { const heapU32 = module.HEAPU32; @@ -42,6 +72,9 @@ class OpKernelContext implements ComputeContext { let dataIndex = (contextDataOffset >> 2); this.opKernelContext = heapU32[dataIndex++]; const inputCount = heapU32[dataIndex++]; + this.outputCount = heapU32[dataIndex++]; + this.customDataOffset = heapU32[dataIndex++]; + this.customDataSize = heapU32[dataIndex++]; const inputs: TensorView[] = []; for (let i = 0; i < inputCount; i++) { @@ -93,11 +126,15 @@ class OpKernelContext implements ComputeContext { } } -export const init = async(module: OrtWasmModule): Promise => { +export const init = async(module: OrtWasmModule, env: Env): Promise => { const init = module.jsepInit; if (init && navigator.gpu) { + if (!env.wasm.simd) { + throw new Error( + 'Not supported for WebGPU=ON and SIMD=OFF. Please set `env.wasm.simd` to true when using WebGPU EP'); + } const backend = new WebGpuBackend(); - await backend.initialize(); + await backend.initialize(env); init( // backend @@ -124,26 +161,30 @@ export const init = async(module: OrtWasmModule): Promise => { // jsepCopyAsync(src, dst, size) async(gpuDataId: number, dataOffset: number, size: number): Promise => { - const data = module.HEAPU8.subarray(dataOffset, dataOffset + size); - LOG_DEBUG( 'verbose', () => `[WebGPU] jsepCopyGpuToCpu: gpuDataId=${gpuDataId}, dataOffset=${dataOffset}, size=${size}`); - await backend.download(gpuDataId, data); + await backend.download(gpuDataId, () => module.HEAPU8.subarray(dataOffset, dataOffset + size)); }, // jsepCreateKernel - (name: string, kernel: number, attribute: unknown) => backend.createKernel(name, kernel, attribute), + (name: string, kernel: number, attribute: unknown) => backend.createKernel( + name, kernel, attribute, + env.debug || env.webgpu.profilingMode === 'default' ? module.UTF8ToString(module._JsepGetNodeName(kernel)) : + `${kernel}`), // jsepReleaseKernel (kernel: number) => backend.releaseKernel(kernel), // jsepRun - (kernel: number, contextDataOffset: number) => { - LOG_DEBUG('verbose', () => `[WebGPU] jsepRun: kernel=${kernel}, contextDataOffset=${contextDataOffset}`); - const context = new OpKernelContext(module, backend, contextDataOffset); - return backend.computeKernel(kernel, context); + (kernel: number, contextDataOffset: number, sessionState: JSEP.SessionState) => { + LOG_DEBUG( + 'verbose', + () => `[WebGPU] jsepRun: sessionId=${sessionState.sessionId}, kernel=${kernel}, contextDataOffset=${ + contextDataOffset}`); + const context = new ComputeContextImpl(module, backend, contextDataOffset); + return backend.computeKernel(kernel, context, sessionState.errors); }); } }; diff --git a/js/web/lib/wasm/jsep/log.ts b/js/web/lib/wasm/jsep/log.ts index 2e27e4905742e..cb7d828611206 100644 --- a/js/web/lib/wasm/jsep/log.ts +++ b/js/web/lib/wasm/jsep/log.ts @@ -1,11 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import {env} from 'onnxruntime-common'; +import {Env} from 'onnxruntime-common'; import {logLevelStringToEnum} from '../wasm-common'; -type LogLevel = NonNullable; +type LogLevel = NonNullable; type MessageString = string; type MessageFunction = () => string; type Message = MessageString|MessageFunction; @@ -17,12 +17,20 @@ const doLog = (level: number, message: string): void => { console.log(`[${logLevelPrefix[level]},${new Date().toISOString()}]${message}`); }; +let configLogLevel: LogLevel|undefined; +let debug: boolean|undefined; + +export const configureLogger = ($configLogLevel: LogLevel, $debug: boolean): void => { + configLogLevel = $configLogLevel; + debug = $debug; +}; + /** * A simple logging utility to log messages to the console. */ export const LOG = (logLevel: LogLevel, msg: Message): void => { const messageLevel = logLevelStringToEnum(logLevel); - const configLevel = logLevelStringToEnum(env.logLevel!); + const configLevel = logLevelStringToEnum(configLogLevel); if (messageLevel >= configLevel) { doLog(messageLevel, typeof msg === 'function' ? msg() : msg); } @@ -32,7 +40,7 @@ export const LOG = (logLevel: LogLevel, msg: Message): void => { * A simple logging utility to log messages to the console. Only logs when debug is enabled. */ export const LOG_DEBUG: typeof LOG = (...args: Parameters) => { - if (env.debug) { + if (debug) { LOG(...args); } }; diff --git a/js/web/lib/wasm/jsep/tensor-view.ts b/js/web/lib/wasm/jsep/tensor-view.ts new file mode 100644 index 0000000000000..69b9287f6de29 --- /dev/null +++ b/js/web/lib/wasm/jsep/tensor-view.ts @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import {Tensor} from 'onnxruntime-common'; + +import {tensorTypeToTypedArrayConstructor} from '../wasm-common'; + +export const createView = (dataBuffer: ArrayBuffer, type: Tensor.Type): Int32Array|Uint32Array|BigInt64Array| + BigUint64Array|Uint8Array|Float32Array|Float64Array|Int8Array|Int16Array|Uint16Array => + new (tensorTypeToTypedArrayConstructor(type))(dataBuffer); + +/** + * a TensorView does not own the data. + */ +export interface TensorView { + readonly data: number; + readonly dataType: number; + readonly dims: readonly number[]; + + /** + * get a Float32Array data view of the tensor data. tensor data must be on CPU. + */ + getFloat32Array(): Float32Array; + + /** + * get a BigInt64Array data view of the tensor data. tensor data must be on CPU. + */ + getBigInt64Array(): BigInt64Array; + + /** + * get a Int32Array data view of the tensor data. tensor data must be on CPU. + */ + getInt32Array(): Int32Array; + + /** + * create a new tensor view with the same data but different dimensions. + */ + reshape(newDims: readonly number[]): TensorView; +} diff --git a/js/web/lib/wasm/jsep/tensor.ts b/js/web/lib/wasm/jsep/tensor.ts deleted file mode 100644 index 720b2357df1f2..0000000000000 --- a/js/web/lib/wasm/jsep/tensor.ts +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -export declare namespace Tensor { - export interface DataTypeMap { - bool: Uint8Array; - float32: Float32Array; - float64: Float64Array; - string: string[]; - int8: Int8Array; - uint8: Uint8Array; - int16: Int16Array; - uint16: Uint16Array; - int32: Int32Array; - uint32: Uint32Array; - int64: BigInt64Array; - uint64: BigUint64Array; - } - - export type DataType = keyof DataTypeMap; - - export type StringType = Tensor.DataTypeMap['string']; - export type BooleanType = Tensor.DataTypeMap['bool']; - export type IntegerType = Tensor.DataTypeMap['int8']|Tensor.DataTypeMap['uint8']|Tensor.DataTypeMap['int16']| - Tensor.DataTypeMap['uint16']|Tensor.DataTypeMap['int32']|Tensor.DataTypeMap['uint32']| - Tensor.DataTypeMap['int64']|Tensor.DataTypeMap['uint64']; - export type FloatType = Tensor.DataTypeMap['float32']|Tensor.DataTypeMap['float64']; - export type NumberType = BooleanType|IntegerType|FloatType; - - export type Id = number; -} - -export const sizeof = (type: Tensor.DataType): number => { - switch (type) { - case 'bool': - case 'int8': - case 'uint8': - return 1; - case 'int16': - case 'uint16': - return 2; - case 'int32': - case 'uint32': - case 'float32': - return 4; - case 'int64': - case 'uint64': - case 'float64': - return 8; - default: - throw new Error(`cannot calculate sizeof() on type ${type}`); - } -}; - -const dataviewConstructor = (type: Tensor.DataType) => { - switch (type) { - case 'bool': - case 'uint8': - return Uint8Array; - case 'int8': - return Int8Array; - case 'int16': - return Int16Array; - case 'uint16': - return Uint16Array; - case 'int32': - return Int32Array; - case 'uint32': - return Uint32Array; - case 'int64': - return BigInt64Array; - case 'uint64': - return BigUint64Array; - case 'float32': - return Float32Array; - case 'float64': - return Float64Array; - default: - // should never run to here - throw new Error('unspecified error'); - } -}; - -export const createView = (dataBuffer: ArrayBuffer, type: Tensor.DataType): Int32Array|Uint32Array|BigInt64Array| - BigUint64Array|Uint8Array|Float32Array|Float64Array|Int8Array|Int16Array|Uint16Array => - new (dataviewConstructor(type))(dataBuffer); - -/** - * a TensorView does not own the data. - */ -export interface TensorView { - readonly data: number; - readonly dataType: number; - readonly dims: readonly number[]; - - /** - * get a Float32Array data view of the tensor data. tensor data must be on CPU. - */ - getFloat32Array(): Float32Array; - - /** - * create a new tensor view with the same data but different dimensions. - */ - reshape(newDims: readonly number[]): TensorView; -} diff --git a/js/web/lib/wasm/jsep/util.ts b/js/web/lib/wasm/jsep/util.ts index cd128ad5e501d..6922d7ff5df6e 100644 --- a/js/web/lib/wasm/jsep/util.ts +++ b/js/web/lib/wasm/jsep/util.ts @@ -4,46 +4,6 @@ /* eslint-disable no-param-reassign */ export class MatMulUtil { - /** - * Fix the input shapes for MatMul operation if they need fixing - * @param dimsA The shape of tensor A. Should be an array of positive integers - * @param dimsB The shape of tensor B. Should be an array of positive integers - * @returns A tuple containing the preprocessed input shapes as required by ONNX specifications - */ - static preprocessInputShapes(dimsA: readonly number[], dimsB: readonly number[]): - [readonly number[], readonly number[]] { - // If the first argument is 1-D, it is promoted to a matrix by prepending - // a 1 to its dimensions. After matrix multiplication the prepended 1 is - // removed. - const a = (dimsA.length === 1) ? [1, dimsA[0]] : dimsA; - - // If the second argument is 1-D, it is promoted to a matrix by appending - // a 1 to its dimensions. After matrix multiplication the appended 1 is - // removed. - const b = (dimsB.length === 1) ? [dimsB[0], 1] : dimsB; - - return [a, b]; - } - - /** - * Fix the output shape computed for MatMul operation if it needs fixing - * @param outputShape The computed outputShape. Should be an array (atleast of length 2) of positive integers. - * This will be mutated. - * @param aRank The rank of tensor A. - * @param bRank The rank of tensor B. - */ - static postprocessOutputShape(outputShape: number[], aRank: number, bRank: number): void { - // Remove prepended dimension if first input is 1d - if (aRank === 1) { - // outputShape = outputShape.slice(0, outputShape.length - 2).concat(outputShape.slice(outputShape.length - 1)); - outputShape.splice(outputShape.length - 2, 1); - } - // Remove appended dimension if second input is 1d - if (bRank === 1) { - outputShape.pop(); - } - } - /** * Calculate the expected shape when matrix multiplication * @param a The shape of tensor A. Should be a tuple of 2 positive integers @@ -102,39 +62,6 @@ export class BroadcastUtil { return cdims; } - /** - * Given the indices of a broadcasted tensor, calculate the original indices - * @param broadcastedIndices The given indices of the broadcasted tensor. - * @param originalShape The original shape of the tensor before broadcas - * @returns The calculated indices that maps to the original tensor. - */ - static index(broadcastedIndices: readonly number[], originalShape: readonly number[]): number[] { - // NOTE 1: we assume the parameter broadcastedIndices is valid. ie. it should have the same - // length as the broadcasted shape, and for each dimension the index should - // not be out of range. - const originalIndices = new Array(originalShape.length); - BroadcastUtil.fillIndex(broadcastedIndices, originalShape, originalIndices); - return originalIndices; - } - - /** - * Given the indices of a broadcasted tensor, calculate the original indices - * @param broadcastedIndices The given indices of the broadcasted tensor. - * @param originalShape The original shape of the tensor before broadcast - * @param originalIndices The mapping of broadcastedIndices to the originalIndices (output parameter - will be - * mutated). - */ - static fillIndex(broadcastedIndices: readonly number[], originalShape: readonly number[], originalIndices: number[]): - void { - // NOTE 1: we assume the parameter broadcastedIndices is valid. ie. it should have the same length as the - // broadcasted shape, and for each dimension the index should not be out of range. - // NOTE 2: we assume the parameter originalIndices has the same length as the originalShape - const dimOffset = broadcastedIndices.length - originalShape.length; - for (let i = 0; i < originalShape.length; i++) { - originalIndices[i] = broadcastedIndices[dimOffset + i] % originalShape[i]; - } - } - /** * Determine if a shape is unidirectional broadcastable to another shape * @param shape The input shape @@ -154,27 +81,6 @@ export class BroadcastUtil { } return true; } - - /** - * Determine the broadcasted dims in input shape based on the given output shape. - * Note that this function only returns the broadcasted dims. - * @param inputShape The input shape - * @param outputShape The output shape - * @returns The broadcasted dims in input shape. - */ - static getBroadcastDims(inputShape: readonly number[], outputShape: readonly number[]): number[] { - const inRank = inputShape.length; - const dims: number[] = []; - for (let i = 0; i < inRank; i++) { - const dim = inRank - 1 - i; - const a = inputShape[dim] || 1; - const b = outputShape[outputShape.length - 1 - i] || 1; - if (b > 1 && a === 1) { - dims.unshift(dim); - } - } - return dims; - } } @@ -213,11 +119,11 @@ export class ShapeUtil { let size = 1; for (let i = start; i < end; i++) { // safety check as this method is called by multiple other methods requiring size. - // size cannot be 0 or negative. - if (dims[i] <= 0) { + // size cannot be negative. + if (dims[i] < 0) { throw new Error( // eslint-disable-next-line max-len - 'cannot get valid size from specified dimension range. Most likely the range contains 0 or negative values in them.'); + 'cannot get valid size from specified dimension range. Most likely the range contains negative values in them.'); } size *= dims[i]; } @@ -240,38 +146,6 @@ export class ShapeUtil { return strides; } - static transpose(dims: readonly number[]): readonly number[] { - const copy = dims.slice(); - return copy.reverse(); - } - - static indicesToOffset(indices: readonly number[], strides: readonly number[], axis?: number): number { - if (axis === undefined) { - axis = indices.length; - } - let offset = 0; - for (let i = 0; i < axis; ++i) { - offset += strides[i] * indices[i]; - } - return offset; - } - - static offsetToIndices(offset: number, strides: readonly number[]): readonly number[] { - const rank = strides.length; - if (rank === 0) { - return []; - } else if (rank === 1) { - return [offset * strides[0]]; - } - const indices: number[] = new Array(strides.length); - for (let i = 0; i < indices.length - 1; ++i) { - indices[i] = Math.floor(offset / strides[i]); - offset -= indices[i] * strides[i]; - } - indices[indices.length - 1] = offset; - return indices; - } - /** * normailze axis of range [-r, r) into [0, r). */ @@ -286,98 +160,6 @@ export class ShapeUtil { return axes.map(x => this.normalizeAxis(x, tensorRank ?? axes.length)); } - /** - * Increment an index into a tensor (in lexicographic ordering), wrapping around the specified upper_bound. - * @param index Given index to increment (Will be mutated) - * @param dims The dimensions of the tensor for which the given index corresponds to - * @param axisToIncrementOn The 1-indexed axis to increment on. If undefined, axisToIncrementOn == rank - */ - static incrementIndex(index: number[], dims: readonly number[], axisToIncrementOn?: number): void { - if (dims.length === 0 || index.length === 0) { - throw new Error('Index incrementing unsupported for scalar Tensor'); - } - if (axisToIncrementOn === undefined) { - axisToIncrementOn = dims.length; - } else { - if (axisToIncrementOn <= 0 || axisToIncrementOn > dims.length) { - throw new Error('Incorrect axis to increment on'); - } - } - - for (let k = axisToIncrementOn - 1; k >= 0; --k) { - index[k]++; - if (index[k] < dims[k]) { - break; - } - index[k] = 0; - } - } - - /** - * Produces a new dimensions array based on the values in the 'originalDimensions' and 'shape' array - * Used in Reshape - * @param originalDims Original Shape array - * @param shapeHints array containing values to compute the new dimensions - * For example: - * originalDims = [2,2] and shapeHints = [0,-1] will return [2,2] - * originalDims = [2,2] and shapeHints = [4] will return [4] - * originalDims = [2,2] and shapeHints = [5] will throw an exception - * https://github.com/onnx/onnx/blob/main/docs/Operators.md#Reshape - */ - - static calculateReshapedDims(originalDims: readonly number[], shapeHints: ArrayLike): number[] { - // reshape to a Scalar Tensor - if (shapeHints.length === 0) { - if (originalDims.length === 0 || ShapeUtil.size(originalDims) === 1) { - return []; - } else { - throw new Error('cannot reshape to a scalar Tensor'); - } - } - - const nDims = shapeHints.length; - const reshapedDims = new Array(nDims); - let unknownDimension = -1; - let newTensorSize = 1; - for (let i = 0; i < nDims; i++) { - if (shapeHints[i] < -1) { - throw new Error('a dimension in shape hints cannot be less than -1'); - } - if (shapeHints[i] === -1) { - if (unknownDimension !== -1) { - throw new Error('at most one dimension in shape hints can be -1'); - } - unknownDimension = i; - } else { - if (shapeHints[i] === 0) { - if (i >= originalDims.length) { - throw new Error('the dimension with value zero exceeds the dimension size of the input tensor'); - } - reshapedDims[i] = originalDims[i]; - } else { - reshapedDims[i] = shapeHints[i]; - } - newTensorSize *= reshapedDims[i]; - } - } - - const oldTensorSize = ShapeUtil.size(originalDims); - if (unknownDimension !== -1) { - if (oldTensorSize % newTensorSize !== 0) { - throw new Error(`the input tensor cannot be reshaped to the requested shape. Input shape: [${ - originalDims}] Output shape: [${shapeHints}]`); - } - reshapedDims[unknownDimension] = oldTensorSize / newTensorSize; - } - // validate sizes from originalDims and reshapedDims match - else { - if (newTensorSize !== oldTensorSize) { - throw new Error('reshapedDims and originalDims don\'t have matching sizes'); - } - } - return reshapedDims; - } - /** * Sorts a given array based on the indices in the Perm array * Used in Transpose @@ -413,109 +195,6 @@ export class ShapeUtil { } return shape1.every((v, i) => v === shape2[i]); } - - /** - * Validates if the given `dims` or `shape` is valid in ONNX.js context and returns data size - * @param dims - input `dims` that needs to be checked - */ - static validateDimsAndCalcSize(dims: readonly number[]): number { - if (dims.length > 6) { - throw new TypeError('Only rank 0 to 6 is supported for tensor shape.'); - } - let size = 1; - for (const n of dims) { - if (!Number.isInteger(n)) { - throw new TypeError(`Invalid shape: ${n} is not an integer`); - } - if (n < 0 || n > 2147483647) { - throw new TypeError(`Invalid shape: length ${n} is not allowed`); - } - size *= n; - } - return size; - } - - /** - * Determines the shape of output tensor y = flatten(x, axis) - * @param dims - shape of input tensor - * @param axis - flatten axis, in the range [-r, r] - */ - static flattenShape(dims: readonly number[], axis: number): readonly number[] { - if (axis < 0) { - axis += dims.length; - } - const total = dims.reduce((x, y) => x * y, 1); - const right = dims.slice(axis).reduce((x, y) => x * y, 1); - const outputDims = [total / right, right]; - - return outputDims; - } - - /** - * Determines the shape of output tensor y = squeeze(x, axes) - * @param dims - shape of input tensor - * @param axes - squeeze axes - */ - static squeezeShape(dims: readonly number[], axes: readonly number[]): readonly number[] { - const outputDims = new Array(); - - // sanity check - axes = ShapeUtil.normalizeAxes(axes, dims.length); - - for (let i = 0; i < dims.length; i++) { - const inSqueezeList = axes.indexOf(i) >= 0; - if (inSqueezeList && dims[i] !== 1) { - throw new Error('squeeze an axis of size different than 1'); - } - - if ((axes.length === 0 && dims[i] > 1) || (axes.length > 0 && !inSqueezeList)) { - outputDims.push(dims[i]); - } - } - - return outputDims; - } - - /** - * Determines the shape of output tensor y = unsqueeze(x, axes) - * @param dims - shape of input tensor - * @param axes - unsqueeze axes - */ - static unsqueezeShape(dims: readonly number[], axes: readonly number[]): readonly number[] { - const outputDims = new Array(dims.length + axes.length); - - // initialize the array elements to 0 - outputDims.fill(0); - - // set all axes indices to 1 in outputDims and check for duplicates - for (let i = 0; i < axes.length; i++) { - const axis = ShapeUtil.normalizeAxis(axes[i], outputDims.length); - if (axis >= outputDims.length) { - throw new Error('\'axes\' has an out of range axis'); - } - if (outputDims[axis] !== 0) { - throw new Error('\'axes\' has a duplicate axis'); - } - - outputDims[axis] = 1; - } - - // fill in the zero entries of outputDims with the input tensor's shape - let inputDimsIterator = 0; - for (let i = 0; i < outputDims.length; i++) { - if (outputDims[i] === 0) { - outputDims[i] = dims[inputDimsIterator++]; - } - } - - // sanity check assertion. 'inputDimsIterator' - // should be equal to the length of 'dims' - if (inputDimsIterator !== dims.length) { - throw new Error('the unsqueezed dimension could not be established'); - } - - return outputDims; - } } export class PoolConvUtil { diff --git a/js/web/lib/wasm/jsep/webgpu/gpu-data-manager.ts b/js/web/lib/wasm/jsep/webgpu/gpu-data-manager.ts index 076ec8ca7b5ec..92fdd5abc3892 100644 --- a/js/web/lib/wasm/jsep/webgpu/gpu-data-manager.ts +++ b/js/web/lib/wasm/jsep/webgpu/gpu-data-manager.ts @@ -45,6 +45,11 @@ export interface GpuDataManager { * actually released. */ refreshPendingBuffers(): void; + + /** + * destroy all gpu buffers. Call this when the session.release is called. + */ + dispose(): void; } interface StorageCacheValue { @@ -52,10 +57,6 @@ interface StorageCacheValue { originalSize: number; } -interface DownloadCacheValue { - data: Promise; -} - /** * normalize the buffer size so that it fits the 128-bits (16 bytes) alignment. */ @@ -68,17 +69,17 @@ class GpuDataManagerImpl implements GpuDataManager { // GPU Data ID => GPU Data ( storage buffer ) storageCache: Map; - // GPU Data ID => GPU Data ( read buffer ) - downloadCache: Map; - // pending buffers for uploading ( data is unmapped ) private buffersForUploadingPending: GPUBuffer[]; // pending buffers for computing private buffersPending: GPUBuffer[]; - constructor(private backend: WebGpuBackend /* , private reuseBuffer: boolean */) { + // The reusable storage buffers for computing. + private freeBuffers: Map; + + constructor(private backend: WebGpuBackend) { this.storageCache = new Map(); - this.downloadCache = new Map(); + this.freeBuffers = new Map(); this.buffersForUploadingPending = []; this.buffersPending = []; } @@ -134,22 +135,37 @@ class GpuDataManagerImpl implements GpuDataManager { throw new Error('inconsistent source and destination gpu data size'); } const size = calcNormalizedBufferSize(sourceGpuDataCache.originalSize); + // GPU copy - this.backend.getCommandEncoder().copyBufferToBuffer( + const commandEncoder = this.backend.getCommandEncoder(); + this.backend.endComputePass(); + commandEncoder.copyBufferToBuffer( sourceGpuDataCache.gpuData.buffer, 0, destinationGpuDataCache.gpuData.buffer, 0, size); } // eslint-disable-next-line no-bitwise create(size: number, usage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST): GpuData { - // !!! - // !!! IMPORTANT: TODO: whether we should keep the storage buffer every time, or always create new ones. - // !!! This need to be figured out by performance test results. - // !!! - const bufferSize = calcNormalizedBufferSize(size); - // create gpu buffer - const gpuBuffer = this.backend.device.createBuffer({size: bufferSize, usage}); + let gpuBuffer; + // Currently, only storage buffers are reused. + // eslint-disable-next-line no-bitwise + if ((usage & GPUBufferUsage.STORAGE) === GPUBufferUsage.STORAGE) { + let buffers = this.freeBuffers.get(bufferSize); + if (!buffers) { + buffers = []; + this.freeBuffers.set(bufferSize, buffers); + } + if (buffers.length > 0) { + gpuBuffer = buffers.pop() as GPUBuffer; + } else { + // create gpu buffer + gpuBuffer = this.backend.device.createBuffer({size: bufferSize, usage}); + } + } else { + // create gpu buffer + gpuBuffer = this.backend.device.createBuffer({size: bufferSize, usage}); + } const gpuData = {id: createNewGpuDataId(), type: GpuDataType.default, buffer: gpuBuffer}; this.storageCache.set(gpuData.id, {gpuData, originalSize: size}); @@ -174,20 +190,10 @@ class GpuDataManagerImpl implements GpuDataManager { this.buffersPending.push(cachedData.gpuData.buffer); // cachedData.gpuData.buffer.destroy(); - const downloadingData = this.downloadCache.get(id); - if (downloadingData) { - this.downloadCache.delete(id); - } - return cachedData.originalSize; } async download(id: GpuDataId): Promise { - const downloadData = this.downloadCache.get(id); - if (downloadData) { - return downloadData.data; - } - const cachedData = this.storageCache.get(id); if (!cachedData) { throw new Error('data does not exist'); @@ -195,35 +201,56 @@ class GpuDataManagerImpl implements GpuDataManager { const commandEncoder = this.backend.getCommandEncoder(); this.backend.endComputePass(); + const bufferSize = calcNormalizedBufferSize(cachedData.originalSize); const gpuReadBuffer = this.backend.device.createBuffer( // eslint-disable-next-line no-bitwise - {size: cachedData.originalSize, usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ}); + {size: bufferSize, usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ}); commandEncoder.copyBufferToBuffer( cachedData.gpuData.buffer /* source buffer */, 0 /* source offset */, gpuReadBuffer /* destination buffer */, - 0 /* destination offset */, cachedData.originalSize /* size */ + 0 /* destination offset */, bufferSize /* size */ ); this.backend.flush(); - const readDataPromise = new Promise((resolve) => { + return new Promise((resolve) => { gpuReadBuffer.mapAsync(GPUMapMode.READ).then(() => { const data = gpuReadBuffer.getMappedRange().slice(0); gpuReadBuffer.destroy(); resolve(data); }); }); - - this.downloadCache.set(id, {data: readDataPromise}); - - return readDataPromise; } refreshPendingBuffers(): void { for (const buffer of this.buffersForUploadingPending) { + // upload buffer is only useful in the session creation time. So we don't need to reuse them in session running. buffer.destroy(); } + this.buffersForUploadingPending = []; for (const buffer of this.buffersPending) { - buffer.destroy(); + // eslint-disable-next-line no-bitwise + if ((buffer.usage & GPUBufferUsage.STORAGE) === GPUBufferUsage.STORAGE) { + // Put the pending buffer to freeBuffers list instead of really destroying it for buffer reusing. + this.freeBuffers.get(buffer.size)!.push(buffer); + } else { + buffer.destroy(); + } } + this.buffersPending = []; + } + + dispose() { + this.freeBuffers.forEach((buffers) => { + buffers.forEach(buffer => { + buffer.destroy(); + }); + }); + + this.storageCache.forEach((storage) => { + storage.gpuData.buffer.destroy(); + }); + + this.storageCache = new Map(); + this.freeBuffers = new Map(); } } diff --git a/js/web/lib/wasm/jsep/webgpu/op-resolve-rules.ts b/js/web/lib/wasm/jsep/webgpu/op-resolve-rules.ts index f25e30843914e..e92e6696d9a78 100644 --- a/js/web/lib/wasm/jsep/webgpu/op-resolve-rules.ts +++ b/js/web/lib/wasm/jsep/webgpu/op-resolve-rules.ts @@ -1,11 +1,28 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +import {argMax, argMin, parseArgMinMaxAttributes} from './ops/argminmax'; import * as binaryOps from './ops/binary-op'; +import {concat, parseConcatAttributes} from './ops/concat'; import {conv, parseConvAttributes} from './ops/conv'; +import {convTranspose, parseConvTransposeAttributes} from './ops/conv-transpose'; +import {einsum, parseEinsumAttributes} from './ops/einsum'; +import {expand} from './ops/expand'; +import {gather, parseGatherAttributes} from './ops/gather'; +import {gatherElements, parseGatherElementsAttributes} from './ops/gather-elements'; import {gemm, parseGemmAttributes} from './ops/gemm'; +import {instanceNorm, parseInstanceNormAttributes} from './ops/instance-norm'; +import {layerNorm, parseLayerNormAttributes} from './ops/layer-norm'; import {matMul} from './ops/matmul'; +import {pad, parsePadAttributes} from './ops/pad'; import * as pool from './ops/pool'; +import {parseReduceAttributes, reduceL1, reduceL2, reduceLogSum, reduceLogSumExp, reduceMax, reduceMean, reduceMin, reduceProd, reduceSum, reduceSumSquare} from './ops/reduce'; +import {parseResizeAttributes, resize} from './ops/resize'; +import {parseSkipLayerNormAttributes, skipLayerNorm} from './ops/skip-layer-norm'; +import {parseSliceAttributes, slice} from './ops/slice'; +import {parseSoftmaxAttributes, softmax} from './ops/softmax'; +import {parseSplitAttributes, split} from './ops/split'; +import {tile} from './ops/tile'; import {parseTransposeAttributes, transpose} from './ops/transpose'; import * as unaryOps from './ops/unary-op'; import {ComputeContext} from './types'; @@ -19,38 +36,78 @@ export const WEBGPU_OP_RESOLVE_RULES: Map = new ['Acos', [unaryOps.acos]], ['Acosh', [unaryOps.acosh]], ['Add', [binaryOps.add]], + ['ArgMax', [argMax, parseArgMinMaxAttributes]], + ['ArgMin', [argMin, parseArgMinMaxAttributes]], ['Asin', [unaryOps.asin]], ['Asinh', [unaryOps.asinh]], ['Atan', [unaryOps.atan]], ['Atanh', [unaryOps.atanh]], // TODO: support new attributes for AveragePool-10 ['AveragePool', [pool.averagePool, pool.parseAveragePoolAttributes]], + ['Cast', [unaryOps.cast, unaryOps.parseCastAttributes]], ['Ceil', [unaryOps.ceil]], ['ClipV10', [unaryOps.clipV10]], ['Clip', [unaryOps.clip]], + ['Concat', [concat, parseConcatAttributes]], ['Conv', [conv, parseConvAttributes]], + ['ConvTranspose', [convTranspose, parseConvTransposeAttributes]], ['Cos', [unaryOps.cos]], ['Cosh', [unaryOps.cosh]], ['Div', [binaryOps.div]], - ['Elu', [unaryOps.elu, unaryOps.parseEluAttributes]], + ['Einsum', [einsum, parseEinsumAttributes]], + ['Elu', [unaryOps.elu, unaryOps.parseAlphaAttributes]], + ['Equal', [binaryOps.equal]], ['Erf', [unaryOps.erf]], + ['Exp', [unaryOps.exp]], + ['Expand', [expand]], ['Floor', [unaryOps.floor]], + ['Gather', [gather, parseGatherAttributes]], + ['GatherElements', [gatherElements, parseGatherElementsAttributes]], + ['Gelu', [unaryOps.gelu]], ['Gemm', [gemm, parseGemmAttributes]], ['GlobalAveragePool', [pool.globalAveragePool, pool.parseGlobalAveragePoolAttributes]], ['GlobalMaxPool', [pool.globalMaxPool, pool.parseGlobalMaxPoolAttributes]], + ['Greater', [binaryOps.greater]], + ['GreaterOrEqual', [binaryOps.greaterOrEqual]], + ['InstanceNormalization', [instanceNorm, parseInstanceNormAttributes]], + ['LayerNormalization', [layerNorm, parseLayerNormAttributes]], + ['LeakyRelu', [unaryOps.leakyRelu, unaryOps.parseAlphaAttributes]], + ['Less', [binaryOps.less]], + ['LessOrEqual', [binaryOps.lessOrEqual]], + ['Log', [unaryOps.log]], ['MatMul', [matMul]], // TODO: support new attributes for MaxPool-8 and MaxPool-10 ['MaxPool', [pool.maxPool, pool.parseMaxPoolAttributes]], ['Mul', [binaryOps.mul]], ['Neg', [unaryOps.neg]], + ['Not', [unaryOps.not]], + ['Pad', [pad, parsePadAttributes]], ['Pow', [binaryOps.pow]], ['Reciprocal', [unaryOps.reciprocal]], + ['ReduceMin', [reduceMin, parseReduceAttributes]], + ['ReduceMean', [reduceMean, parseReduceAttributes]], + ['ReduceMax', [reduceMax, parseReduceAttributes]], + ['ReduceSum', [reduceSum, parseReduceAttributes]], + ['ReduceProd', [reduceProd, parseReduceAttributes]], + ['ReduceL1', [reduceL1, parseReduceAttributes]], + ['ReduceL2', [reduceL2, parseReduceAttributes]], + ['ReduceLogSum', [reduceLogSum, parseReduceAttributes]], + ['ReduceLogSumExp', [reduceLogSumExp, parseReduceAttributes]], + ['ReduceSumSquare', [reduceSumSquare, parseReduceAttributes]], + ['Relu', [unaryOps.relu]], + ['Resize', [resize, parseResizeAttributes]], ['Sigmoid', [unaryOps.sigmoid]], ['Sin', [unaryOps.sin]], ['Sinh', [unaryOps.sinh]], + ['Slice', [slice, parseSliceAttributes]], + ['SkipLayerNormalization', [skipLayerNorm, parseSkipLayerNormAttributes]], + ['Split', [split, parseSplitAttributes]], ['Sqrt', [unaryOps.sqrt]], + ['Softmax', [softmax, parseSoftmaxAttributes]], ['Sub', [binaryOps.sub]], ['Tan', [unaryOps.tan]], ['Tanh', [unaryOps.tanh]], + ['ThresholdedRelu', [unaryOps.thresholdedRelu, unaryOps.parseAlphaAttributes]], + ['Tile', [tile]], ['Transpose', [transpose, parseTransposeAttributes]], ]); diff --git a/js/web/lib/wasm/jsep/webgpu/ops/3rd-party/activation_util.ts b/js/web/lib/wasm/jsep/webgpu/ops/3rd-party/activation_util.ts index 5345367eadfef..dd4f13e76ee04 100644 --- a/js/web/lib/wasm/jsep/webgpu/ops/3rd-party/activation_util.ts +++ b/js/web/lib/wasm/jsep/webgpu/ops/3rd-party/activation_util.ts @@ -19,7 +19,7 @@ // // modified to fit the needs of the project -export declare type Activation = 'linear' | 'relu' | 'prelu' | 'elu' | 'relu6' | 'leakyrelu' | 'sigmoid'; +export declare type Activation = 'linear' | 'relu' | 'prelu' | 'elu' | 'relu6' | 'leakyrelu' | 'sigmoid' | 'gelu'; export const typeSnippet = (component: number) => { switch (component) { diff --git a/js/web/lib/wasm/jsep/webgpu/ops/3rd-party/conv2d_mm_webgpu.ts b/js/web/lib/wasm/jsep/webgpu/ops/3rd-party/conv2d_mm_webgpu.ts index b77e9bea7b871..08b1d1f30b233 100644 --- a/js/web/lib/wasm/jsep/webgpu/ops/3rd-party/conv2d_mm_webgpu.ts +++ b/js/web/lib/wasm/jsep/webgpu/ops/3rd-party/conv2d_mm_webgpu.ts @@ -20,7 +20,7 @@ // modified to fit the needs of the project import {LOG_DEBUG} from '../../../log'; -import {TensorView} from '../../../tensor'; +import {TensorView} from '../../../tensor-view'; import {ShapeUtil} from '../../../util'; import {GpuDataType, ProgramInfo, ProgramMetadata} from '../../types'; import {ConvAttributes} from '../conv'; @@ -174,7 +174,7 @@ export const createConv2DMatMulProgramInfo = const dispatch = [ Math.ceil(dispatchX / workGroupSize[0] / elementsPerThread[0]), Math.ceil(dispatchY / workGroupSize[1] / elementsPerThread[1]), - Math.ceil(batchSize / workGroupSize[2] / elementsPerThread[1]) + Math.ceil(batchSize / workGroupSize[2] / elementsPerThread[2]) ]; LOG_DEBUG('verbose', () => `[conv2d_mm_webgpu] dispatch = ${dispatch}`); @@ -242,9 +242,10 @@ export const createConv2DMatMulProgramInfo = isChannelsLast, fitAOuter, fitBOuter, fitInner, hasBias, undefined, false, elementsSize[0], elementsSize[1], elementsSize[2])} ${ - isVec4 ? makeMatMulPackedVec4Source(elementsPerThread, workGroupSize, !isChannelsLast, tileInner) : - makeMatMulPackedSource( - elementsPerThread, workGroupSize, !isChannelsLast, tileInner, false, undefined, - sequentialAccessByThreads)}` + isVec4 ? + makeMatMulPackedVec4Source(elementsPerThread, workGroupSize, undefined, !isChannelsLast, tileInner) : + makeMatMulPackedSource( + elementsPerThread, workGroupSize, undefined, !isChannelsLast, tileInner, false, undefined, + sequentialAccessByThreads)}` }; }; 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 new file mode 100644 index 0000000000000..ec6df438129fb --- /dev/null +++ b/js/web/lib/wasm/jsep/webgpu/ops/3rd-party/conv_backprop_webgpu.ts @@ -0,0 +1,270 @@ +/** + * @license + * Copyright 2021 Google LLC. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================================= + */ + +// sampled from [@tensorflow/tfjs] tfjs-backend-webgpu/src/conv_backprop_webgpu.ts + +import {LOG_DEBUG} from '../../../log'; +import {TensorView} from '../../../tensor-view'; +import {ShapeUtil} from '../../../util'; +import {GpuDataType, ProgramInfo, ProgramMetadata} from '../../types'; +import {inputVariable, outputVariable, ShaderHelper} from '../common'; +import {ConvTransposeAttributes} from '../conv-transpose'; + +const createConvTranspose2DOpProgramShaderSource = + (shaderHelper: ShaderHelper, inputs: readonly TensorView[], attributes: ConvTransposeAttributes, + outputShape: readonly number[], hasBias: boolean, is1DimensionDispatch: boolean, isVec4 = false): string => { + const isChannelsLast = attributes.format === 'NHWC'; + const rowDim = isChannelsLast ? 1 : 2; + const colDim = isChannelsLast ? 2 : 3; + const channelDim = isChannelsLast ? 3 : 1; + const outputSize = ShapeUtil.size(outputShape); + const workPerThread = isVec4 ? 2 : 1; + const group = attributes.group; + const wShape = inputs[1].dims; + const inputChannelsPerGroup = wShape[0] / group; + const outputChannelsPerGroup = wShape[1]; + + let declareFunctions = ` + fn setOutputAtIndex(flatIndex : u32, value : ${isVec4 ? 'vec4' : 'f32'}) { + result[flatIndex] = ${isVec4 ? 'vec4' : 'f32'}(value); + }`; + if (hasBias) { + declareFunctions += ` + fn getBiasByOutputCoords(coords : vec4) -> ${isVec4 ? 'vec4' : 'f32'} { + return bias[coords.${isChannelsLast ? 'w' : 'y'}${isVec4 ? '/ 4' : ''}]; + }`; + } + const components = isVec4 ? 4 : 1; + const w = inputVariable('W', inputs[1].dataType, inputs[1].dims, components); + const dy = inputVariable('Dy', inputs[0].dataType, inputs[0].dims, components); + const inputVariables = [dy, w]; + if (hasBias) { + inputVariables.push(inputVariable('bias', inputs[2].dataType, [outputShape[channelDim]], components)); + } + const output = outputVariable('result', inputs[0].dataType, outputShape, components); + const codeSnippet4 = `{ + let batch: u32 = ${is1DimensionDispatch ? 'global_id.z' : 'workgroup_id.z'} / outShape[1]; + let r = ${is1DimensionDispatch ? 'global_id.z' : 'workgroup_id.z'} % outShape[1]; + let c = ${is1DimensionDispatch ? 'global_id.y' : 'workgroup_id.y'} * ${workPerThread}; + let d1: u32 = ${is1DimensionDispatch ? 'global_id.x' : 'workgroup_id.x'} * 4; + + let dyCorner = vec2(i32(r), i32(c)) - vec2(pads); + + // Convolve dy(?, ?, d2) with w(:, :, d1, d2) to compute dx(xR, xC, d1). + // ? = to be determined. : = across all values in that axis. + var dotProd: array, ${workPerThread}>; + for (var i = 0; i < ${workPerThread}; i++) { + dotProd[i] = vec4(0.0); + } + for (var wR: u32 = 0; wR < filterDims[0]; wR = wR + 1) { + var dyR = (f32(dyCorner.x) + f32(wR)) / f32(strides.x); + let wRPerm = filterDims[0] - 1 - wR; + if (dyR < 0.0 || dyR >= f32(outBackprop[1]) || + fract(dyR) > 0.0 || wRPerm < 0) { + continue; + } + let idyR: u32 = u32(dyR); + + for (var wC: u32 = 0; wC < filterDims[1]; wC = wC + 1) { + let dyC = (f32(dyCorner.y) + f32(wC)) / f32(strides.y); + let dyC2 = (f32(dyCorner.y) + 1.0 + f32(wC)) / f32(strides.y); + let wCPerm = filterDims[1] - 1 - wC; + if (wCPerm < 0) { + continue; + } + var bDyCVal = true; + var bDyCVal2 = true; + if (dyC < 0.0 || dyC >= f32(outBackprop[2]) || + fract(dyC) > 0.0) { + bDyCVal = false; + } + if (dyC2 < 0.0 || dyC2 >= f32(outBackprop[2]) || + fract(dyC2) > 0.0) { + bDyCVal2 = false; + } + + let idyC: u32 = u32(dyC); + let idyC2: u32 = u32(dyC2); + if (bDyCVal && bDyCVal2) { + let d2Length = outBackprop[3]; + for (var d2 :u32 = 0; d2 < d2Length; d2 = d2 + 4) { + let wValue0 = ${w.get('u32(wRPerm)', 'u32(wCPerm)', 'd1', 'd2')}; + let wValue1 = ${w.get('u32(wRPerm)', 'u32(wCPerm)', 'd1 + 1', 'd2')}; + let wValue2 = ${w.get('u32(wRPerm)', 'u32(wCPerm)', 'd1 + 2', 'd2')}; + let wValue3 = ${w.get('u32(wRPerm)', 'u32(wCPerm)', 'd1 + 3', 'd2')}; + + var xValue = ${dy.get('batch', 'idyR', 'idyC', 'd2')}; + let tmpval = vec4(dot(xValue, wValue0), + dot(xValue, wValue1), + dot(xValue, wValue2), + dot(xValue, wValue3)); + dotProd[0] = dotProd[0] + tmpval; + + xValue = ${dy.get('batch', 'idyR', 'idyC2', 'd2')}; + + dotProd[1] = dotProd[1] + vec4(dot(xValue, wValue0), + dot(xValue, wValue1), + dot(xValue, wValue2), + dot(xValue, wValue3)); + } + } else if (bDyCVal) { + let d2Length = outBackprop[${channelDim}]; + for (var d2: u32 = 0; d2 < d2Length; d2 = d2 + 4) { + let wValue0 = ${w.get('u32(wRPerm)', 'u32(wCPerm)', 'd1', 'd2')}; + let wValue1 = ${w.get('u32(wRPerm)', 'u32(wCPerm)', 'd1 + 1', 'd2')}; + let wValue2 = ${w.get('u32(wRPerm)', 'u32(wCPerm)', 'd1 + 2', 'd2')}; + let wValue3 = ${w.get('u32(wRPerm)', 'u32(wCPerm)', 'd1 + 3', 'd2')}; + + var xValue = ${dy.get('batch', 'idyR', 'idyC', 'd2')}; + let tmpval = vec4(dot(xValue, wValue0), + dot(xValue, wValue1), + dot(xValue, wValue2), + dot(xValue, wValue3)); + dotProd[0] = dotProd[0] + tmpval; + } + } else if (bDyCVal2) { + let d2Length = outBackprop[3]; + for (var d2: u32 = 0; d2 < d2Length; d2 = d2 + 4) { + let wValue0 = ${w.get('u32(wRPerm)', 'u32(wCPerm)', 'd1', 'd2')}; + let wValue1 = ${w.get('u32(wRPerm)', 'u32(wCPerm)', 'd1 + 1', 'd2')}; + let wValue2 = ${w.get('u32(wRPerm)', 'u32(wCPerm)', 'd1 + 2', 'd2')}; + let wValue3 = ${w.get('u32(wRPerm)', 'u32(wCPerm)', 'd1 + 3', 'd2')}; + + var xValue = ${dy.get('batch', 'idyR', 'idyC2', 'd2')}; + let tmpval = vec4(dot(xValue, wValue0), + dot(xValue, wValue1), + dot(xValue, wValue2), + dot(xValue, wValue3)); + dotProd[1] = dotProd[1] + tmpval; + } + } + } + } + + for (var i: u32 = 0; i < ${workPerThread}; i = i + 1) { + let value = dotProd[i] + ${hasBias ? 'bias[c+i]' : '0.0'}; + ${output.set('batch', 'r', 'c + i', 'd1', 'value')}; + } + }`; + const codeSnippet = ` + let outputIndices = ${output.offsetToIndices('global_idx')}; + let batch = ${output.indicesGet('outputIndices', 0)}; + let d1 = ${output.indicesGet('outputIndices', channelDim)}; + let r = ${output.indicesGet('outputIndices', rowDim)}; + let c = ${output.indicesGet('outputIndices', colDim)}; + let dyCorner = vec2(i32(r), i32(c)) - pads; + let dyRCorner = dyCorner.x; + let dyCCorner = dyCorner.y; + let groupId = d1 / ${outputChannelsPerGroup}; + let wOutChannel = d1 - groupId * ${outputChannelsPerGroup}; + // Convolve dy(?, ?, d2) with w(:, :, d1, d2) to compute dx(xR, xC, d1). + // ? = to be determined. : = across all values in that axis. + var dotProd = 0.0; + for (var wR: u32 = 0; wR < effectiveFilterDims.x; wR = wR + 1) { + if (wR % dilations.x != 0) { + continue; + } + let dyR = (f32(dyRCorner) + f32(wR)) / f32(strides[0]); + let wRPerm = filterDims.x - 1 - wR / dilations.x; + if (dyR < 0.0 || dyR >= f32(outBackprop[${rowDim}]) || fract(dyR) > 0.0 || + wRPerm < 0) { + continue; + } + let idyR: u32 = u32(dyR); + + for (var wC: u32 = 0; wC < effectiveFilterDims.y; wC = wC + 1) { + if (wC % dilations.y != 0) { + continue; + } + let dyC = (f32(dyCCorner) + f32(wC)) / f32(strides.y); + let wCPerm = filterDims.y - 1 - wC / dilations.y; + if (dyC < 0.0 || dyC >= f32(outBackprop[${colDim}]) || + fract(dyC) > 0.0 || wCPerm < 0) { + continue; + } + let idyC: u32 = u32(dyC); + + for (var d2: u32 = 0; d2 < ${inputChannelsPerGroup}; d2 = d2 + 1) { + let inputChannel = groupId * ${inputChannelsPerGroup} + d2; + let xValue = ${ + isChannelsLast ? dy.get('batch', 'idyR', 'idyC', 'inputChannel') : + dy.get('batch', 'inputChannel', 'idyR', 'idyC')}; + let wValue = ${w.get('inputChannel', 'wOutChannel', 'u32(wRPerm)', 'u32(wCPerm)')}; + dotProd = dotProd + xValue * wValue; + } + } + } + let value = dotProd + ${hasBias ? 'bias[d1]' : '0.0'}; + ${output.setByOffset('global_idx', 'value')}; + `; + + return ` + ${shaderHelper.declareVariables(...inputVariables, output)} + ${declareFunctions} + const outShape : vec4 = vec4(${outputShape.join(',')}); + const outBackprop : vec4 = vec4(${inputs[0].dims.join(',')}); + const strides : vec2 = vec2(${attributes.strides[0]}, ${attributes.strides[1]}); + const filterDims : vec2 = vec2(${attributes.kernelShape[isChannelsLast ? 1 : 2]}, ${ + attributes.kernelShape[isChannelsLast ? 2 : 3]}); + const dilations : vec2 = vec2(${attributes.dilations[0]}, ${attributes.dilations[1]}); + const effectiveFilterDims : vec2 = filterDims + vec2( + ${ + attributes.dilations[0] <= 1 ? + 0 : + (attributes.kernelShape[isChannelsLast ? 1 : 2] - 1) * (attributes.dilations[0] - 1)}, + ${ + attributes.dilations[1] <= 1 ? + 0 : + (attributes.kernelShape[isChannelsLast ? 2 : 3] - 1) * (attributes.dilations[1] - 1)}); + const pads : vec2 = vec2(i32(effectiveFilterDims[0]) - 1 - (${attributes.pads[0] + attributes.pads[2]})/2, + i32(effectiveFilterDims[1]) - 1 - (${attributes.pads[1] + attributes.pads[3]})/2); + ${shaderHelper.mainStart()} + ${shaderHelper.guardAgainstOutOfBoundsWorkgroupSizes(outputSize)}; + ${isVec4 ? codeSnippet4 : codeSnippet}}`; + }; + +export const createConvTranspose2DProgramInfo = + (inputs: readonly TensorView[], metadata: ProgramMetadata, attributes: ConvTransposeAttributes, + squeezeOutputShapeFunction?: (shape: readonly number[]) => number[]): ProgramInfo => { + const hasBias = inputs.length > 2; + // const isChannelsLast = attributes.format === 'NHWC'; + const outputShape = attributes.outputShape; + const outputSize = ShapeUtil.size(outputShape); + + // const inChannels = inputs[0].dims[isChannelsLast ? 3 : 1]; + // TODO Enable isVec4 for performance + // Disabled due to weight matrix layout issue + // const isVec4 = attributes.group === 1 && isChannelsLast && inChannels % 4 === 0 && outChannels % 4 === 0; + const dispatch = [ + Math.ceil(outputSize / 64), + 1, + 1, + ]; + LOG_DEBUG('verbose', () => `[conv2d_backprop_webgpu] dispatch = ${dispatch}`); + + return { + ...metadata, + outputs: [{ + dims: squeezeOutputShapeFunction ? squeezeOutputShapeFunction(outputShape) : outputShape, + dataType: inputs[0].dataType, + gpuDataType: GpuDataType.default + }], + dispatchGroup: () => ({x: dispatch[0], y: dispatch[1], z: dispatch[2]}), + getShaderSource: (shaderHelper: ShaderHelper) => createConvTranspose2DOpProgramShaderSource( + shaderHelper, inputs, attributes, outputShape, hasBias, dispatch[1] === 1 && dispatch[2] === 1), + }; + }; diff --git a/js/web/lib/wasm/jsep/webgpu/ops/3rd-party/matmul_packed_webgpu.ts b/js/web/lib/wasm/jsep/webgpu/ops/3rd-party/matmul_packed_webgpu.ts index d30821e508083..8d43dbb378a69 100644 --- a/js/web/lib/wasm/jsep/webgpu/ops/3rd-party/matmul_packed_webgpu.ts +++ b/js/web/lib/wasm/jsep/webgpu/ops/3rd-party/matmul_packed_webgpu.ts @@ -19,19 +19,27 @@ // // modified to fit the needs of the project -const writeDataToSubAVec4Snippet = (transpose: boolean) => { +import {TensorView} from '../../../tensor-view'; +import {ShapeUtil} from '../../../util'; +import {GpuDataType, ProgramInfo, ProgramMetadata} from '../../types'; +import {getBroadcastDims, IndicesHelper, inputVariable, outputVariable, ShaderHelper} from '../common'; +import {getActicationSnippet, InternalActivationAttributes} from '../fuse-utils'; + +import {typeSnippet} from './activation_util'; + +const writeDataToSubAVec4Snippet = (transpose: boolean, batchDims?: IndicesHelper) => { if (transpose) { return ` mm_Asub[inputRow][inputCol] = mm_readA(batch, kStart + inputRow, - globalRowStart / innerElementSize + inputCol); + globalRowStart / innerElementSize + inputCol${batchDims ? ', batchIndices' : ''}); `; } else { return ` mm_Asub[inputRow][inputCol] = mm_readA(batch, globalRow + innerRow, - kStart / innerElementSize + inputCol); + kStart / innerElementSize + inputCol${batchDims ? ', batchIndices' : ''}); `; } }; @@ -62,8 +70,8 @@ const calculateResultSnippet = (transposeA: boolean, innerElementSize: number) = }; export const makeMatMulPackedVec4Source = - (workPerThread: number[], workgroupSize: [number, number, number], transposeA = false, tileInner = 32, - splitK = false, splitedDimInner = 32, isVectorA = false): string => { + (workPerThread: number[], workgroupSize: [number, number, number], batchDims?: IndicesHelper, transposeA = false, + tileInner = 32, splitK = false, splitedDimInner = 32): string => { const tileAOuter = workgroupSize[1] * workPerThread[1]; const tileBOuter = workgroupSize[0] * workPerThread[0]; const tileAWidth = transposeA ? tileAOuter : tileInner; @@ -95,12 +103,13 @@ fn main(@builtin(local_invocation_id) localId : vec3, @builtin(global_invocation_id) globalId : vec3, @builtin(workgroup_id) workgroupId : vec3) { let localRow = i32(localId.y); - let tileRow = ${isVectorA ? '0' : 'localRow * rowPerThread'}; + let tileRow = localRow * rowPerThread; let tileCol = i32(localId.x); - let globalRow = ${isVectorA ? '0' : 'i32(globalId.y) * rowPerThread'}; + let globalRow =i32(globalId.y) * rowPerThread; let globalCol = i32(globalId.x); let batch = ${splitK ? '0' : 'i32(globalId.z)'}; + ${batchDims ? `let batchIndices = ${batchDims.offsetToIndices('u32(batch)')};` : ''} let globalRowStart = i32(workgroupId.y) * ${tileAOuter}; let numTiles = ${splitK ? `${Math.ceil(splitedDimInner / tileInner)}` : '(dimInner - 1) / tileInner + 1'}; @@ -115,14 +124,15 @@ fn main(@builtin(local_invocation_id) localId : vec3, for (var innerRow = 0; innerRow < rowPerThread; innerRow = innerRow + 1) { let inputRow = tileRow + innerRow; let inputCol = tileCol; - ${writeDataToSubAVec4Snippet(transposeA)} + ${writeDataToSubAVec4Snippet(transposeA, batchDims)} } // Load one tile of B into local memory. for (var innerRow = 0; innerRow < ${rowPerThreadB}; innerRow = innerRow + 1) { let inputRow = tileRowB + innerRow; let inputCol = tileCol; - mm_Bsub[inputRow][inputCol] = mm_readB(batch, kStart + inputRow, globalCol); + mm_Bsub[inputRow][inputCol] = mm_readB(batch, kStart + inputRow, globalCol${ + batchDims ? ', batchIndices' : ''}); } kStart = kStart + tileInner; workgroupBarrier(); @@ -146,19 +156,19 @@ fn main(@builtin(local_invocation_id) localId : vec3, }`; }; -const writeDataToSubASnippet = (transpose: boolean) => { +const writeDataToSubASnippet = (transpose: boolean, batchDims?: IndicesHelper) => { if (transpose) { return ` mm_Asub[inputRow][inputCol] = mm_readA(batch, kStart + inputRow, - globalRowStart + inputCol); + globalRowStart + inputCol${batchDims ? ', batchIndices' : ''}); `; } else { return ` mm_Asub[inputRow][inputCol] = mm_readA(batch, globalRowStart + inputRow, - kStart + inputCol); + kStart + inputCol${batchDims ? ', batchIndices' : ''}); `; } }; @@ -169,8 +179,8 @@ const readDataFromSubASnippet = (transposeA: boolean) => // sequentialAccessByThreads means sequential data in memory is accessed by // threads, instead of a single thread (default behavior). export const makeMatMulPackedSource = - (workPerThread: number[], workgroupSize: [number, number, number], transposeA = false, tileInner = 32, - splitK = false, splitedDimInner = 32, sequentialAccessByThreads = false): string => { + (workPerThread: number[], workgroupSize: [number, number, number], batchDims?: IndicesHelper, transposeA = false, + tileInner = 32, splitK = false, splitedDimInner = 32, sequentialAccessByThreads = false): string => { const tileAOuter = workPerThread[1] * workgroupSize[1]; const tileBOuter = workPerThread[0] * workgroupSize[0]; const tileAWidth = transposeA ? tileAOuter : tileInner; @@ -197,7 +207,7 @@ export const makeMatMulPackedSource = // Load one tile of A into local memory. for (var inputRow = localRow; inputRow < ${tileAHight}; inputRow = inputRow + ${workgroupSize[1]}) { for (var inputCol = localCol; inputCol < ${tileAWidth}; inputCol = inputCol + ${workgroupSize[0]}) { - ${writeDataToSubASnippet(transposeA)} + ${writeDataToSubASnippet(transposeA, batchDims)} } } // Load one tile of B into local memory. @@ -205,7 +215,7 @@ export const makeMatMulPackedSource = for (var inputCol = localCol; inputCol < ${tileBOuter}; inputCol = inputCol + ${workgroupSize[0]}) { mm_Bsub[inputRow][inputCol] = mm_readB(batch, kStart + inputRow, - globalColStart + inputCol); + globalColStart + inputCol${batchDims ? ', batchIndices' : ''}); } } kStart = kStart + tileInner; @@ -255,7 +265,7 @@ for (var t = 0; t < numTiles; t = t + 1) { for (var innerCol = 0; innerCol < ${colPerThreadA}; innerCol = innerCol + 1) { let inputRow = tileRowA + innerRow; let inputCol = tileColA + innerCol; - ${writeDataToSubASnippet(transposeA)} + ${writeDataToSubASnippet(transposeA, batchDims)} } } @@ -266,7 +276,7 @@ for (var t = 0; t < numTiles; t = t + 1) { let inputCol = tileCol + innerCol; mm_Bsub[inputRow][inputCol] = mm_readB(batch, kStart + inputRow, - globalCol + innerCol); + globalCol + innerCol${batchDims ? ', batchIndices' : ''}); } } kStart = kStart + tileInner; @@ -310,6 +320,7 @@ fn main(@builtin(local_invocation_id) localId : vec3, @builtin(global_invocation_id) globalId : vec3, @builtin(workgroup_id) workgroupId : vec3) { let batch = ${splitK ? '0' : 'i32(globalId.z)'}; + ${batchDims ? `let batchIndices = ${batchDims.offsetToIndices('u32(batch)')};` : ''} let numTiles = ${splitK ? `${Math.ceil(splitedDimInner / tileInner)}` : '(dimInner - 1) / tileInner + 1'}; var kStart = ${splitK ? `i32(globalId.z) * ${splitedDimInner}` : '0'}; @@ -325,3 +336,143 @@ fn main(@builtin(local_invocation_id) localId : vec3, } `; }; + +const matMulReadWriteFnSource = + (component: number, hasBias: boolean, applyActivation: string, variables: IndicesHelper[]): string => { + const batchAVariable = variables[0]; + const batchBVariable = variables[1]; + const batchVariable = variables[2]; + const aVariable = variables[3]; + const bVariable = variables[4]; + const outputVariable = variables[5]; + const broadCastADims = getBroadcastDims(batchAVariable.shape, batchVariable.shape); + const broadCastBDims = getBroadcastDims(batchBVariable.shape, batchVariable.shape); + const getAIndices = () => { + const aRank = aVariable.shape.length; + const batchRank = batchVariable.shape.length; + let resStr = `var aIndices: ${aVariable.type.indices};`; + for (let i = aRank - 2 - 1, j = batchRank - 1; i >= 0; i--, j--) { + resStr += `\naIndices[${i}] = ${batchRank > 1 ? `batchIndices[${j}]` : 'batchIndices'};`; + } + broadCastADims.forEach(i => { + resStr += `\naIndices[${i}] = 0;`; + }); + resStr += `\naIndices[${aRank - 2}] = u32(row); + aIndices[${aRank - 1}] = u32(colIn);`; + return resStr; + }; + const getBIndices = () => { + const bRank = bVariable.shape.length; + const batchRank = batchVariable.shape.length; + let resStr = `var bIndices: ${bVariable.type.indices};`; + for (let i = bRank - 2 - 1, j = batchRank - 1; i >= 0; i--, j--) { + resStr += `\nbIndices[${i}] = ${batchRank > 1 ? `batchIndices[${j}]` : 'batchIndices'};`; + } + broadCastBDims.forEach(i => { + resStr += `\nbIndices[${i}] = 0;`; + }); + resStr += `\nbIndices[${bRank - 2}] = u32(row); + bIndices[${bRank - 1}] = u32(colIn);`; + return resStr; + }; + const source = ` + fn mm_readA(batch: i32, row: i32, colIn: i32, batchIndices: ${batchVariable.type.indices}) -> ${ + typeSnippet(component)} { + var value = ${typeSnippet(component)}(0.0); + let col = colIn * ${component}; + if(row < dimAOuter && col < dimInner) + { + ${getAIndices()} + value = ${aVariable.getByIndices('aIndices')}; + } + return value; + } + + fn mm_readB(batch: i32, row: i32, colIn: i32, batchIndices: ${batchVariable.type.indices}) -> ${ + typeSnippet(component)} { + var value = ${typeSnippet(component)}(0.0); + let col = colIn * ${component}; + if(row < dimInner && col < dimBOuter) + { + ${getBIndices()} + value = ${bVariable.getByIndices('bIndices')}; + } + return value; + } + + fn mm_write(batch: i32, row: i32, colIn: i32, valueIn: ${typeSnippet(component)}) { + let col = colIn * ${component}; + if (row < dimAOuter && col < dimBOuter) { + var value = valueIn; + let coords = vec3(batch, row, colIn); + ${hasBias ? 'value = value + bias[colIn];' : ''} + ${applyActivation} + ${outputVariable.setByIndices('vec3(coords)', 'value')} + } + } + `; + return source; + }; + +export const createMatmulProgramInfo = + (metadata: ProgramMetadata, inputs: readonly TensorView[], activationAttributes: InternalActivationAttributes, + outputShape: readonly number[], reshapedOutputShape?: readonly number[]): ProgramInfo => { + const aShape = inputs[0].dims; + const bShape = inputs[1].dims; + + const outerDimsA = aShape.slice(0, -2); + const outerDimsB = bShape.slice(0, -2); + const outerDims = reshapedOutputShape ? reshapedOutputShape.slice(0, -2) : outputShape.slice(0, -2); + const batchDims = inputVariable('batchDims', inputs[0].dataType, outerDims); + const batchADims = inputVariable('batchADims', inputs[0].dataType, outerDimsA); + const batchBDims = inputVariable('batchBDims', inputs[0].dataType, outerDimsB); + const variables = [batchADims, batchBDims, batchDims]; + const batchSize = ShapeUtil.size(outerDims); + + const dimAOuter = aShape[aShape.length - 2]; + const dimInner = aShape[aShape.length - 1]; + const dimBOuter = bShape[bShape.length - 1]; + const isVec4 = dimInner % 4 === 0 && dimBOuter % 4 === 0; + const {activationFunction, applyActivation} = getActicationSnippet(activationAttributes); + + // TODO: fine tune size + const elementsPerThread = dimAOuter <= 8 ? [4, 1, 1] : [4, 4, 1]; + const workgroupSize: [number, number, number] = [8, 8, 1]; + const dispatch = [ + Math.ceil(dimBOuter / workgroupSize[0] / elementsPerThread[0]), + Math.ceil(dimAOuter / workgroupSize[1] / elementsPerThread[1]), + Math.ceil(batchSize / workgroupSize[2] / elementsPerThread[2]) + ]; + + const components = isVec4 ? 4 : 1; + const A = inputVariable('a', inputs[0].dataType, [...outerDimsA, dimAOuter, dimInner / components], components); + const B = inputVariable('b', inputs[1].dataType, [...outerDimsB, dimInner, dimBOuter / components], components); + const output = + outputVariable('result', inputs[0].dataType, [batchSize, dimAOuter, dimBOuter / components], components); + variables.push(A); + variables.push(B); + variables.push(output); + const inputVariables = [A, B]; + const hasBias = inputs.length > 2; + const declareFunctions = matMulReadWriteFnSource(components, hasBias, applyActivation, variables); + if (hasBias) { + inputVariables.push(inputVariable('bias', inputs[2].dataType, [dimBOuter / components], components)); + } + const getShaderSource = (shaderHelper: ShaderHelper) => ` + const dimAOuter: i32 = ${dimAOuter}; + const dimBOuter: i32 = ${dimBOuter}; + const dimInner: i32 = ${dimInner}; + ${shaderHelper.declareVariables(...inputVariables, output)} + ${declareFunctions} + ${activationFunction} + ${ + isVec4 ? makeMatMulPackedVec4Source(elementsPerThread, workgroupSize, batchDims) : + makeMatMulPackedSource(elementsPerThread, workgroupSize, batchDims)} + ${batchDims.impl()}`; + return { + ...metadata, + outputs: [{dims: outputShape, dataType: inputs[0].dataType, gpuDataType: GpuDataType.default}], + getShaderSource, + dispatchGroup: () => ({x: dispatch[0], y: dispatch[1], z: dispatch[2]}) + }; + }; diff --git a/js/web/lib/wasm/jsep/webgpu/ops/argminmax.ts b/js/web/lib/wasm/jsep/webgpu/ops/argminmax.ts new file mode 100644 index 0000000000000..412e61a3cc0f9 --- /dev/null +++ b/js/web/lib/wasm/jsep/webgpu/ops/argminmax.ts @@ -0,0 +1,93 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// TODO: this is the same naive implementation we use for reduce that has +// performance limitations when the reduced axis is long. Need to add +// a optimized codepath for this. + +import {DataType} from '../../../wasm-common'; +import {TensorView} from '../../tensor-view'; +import {AttributeWithCacheKey, createAttributeWithCacheKey} from '../attribute-with-cache-key'; +import {ComputeContext, GpuDataType, ProgramInfoLoader, ProgramMetadata} from '../types'; + +import {createReduceProgramInfo, ReduceOp} from './reduce'; + +const validateInputs = (inputs: readonly TensorView[]): void => { + if (!inputs || inputs.length === 0 || inputs.length > 2) { + throw new Error('ArgMinMaxOp op requires 1 or 2 inputs.'); + } + if (inputs[0].dataType !== DataType.float) { + throw new Error('Invalid input type.'); + } +}; + +export interface ArgMinMaxAttributes extends AttributeWithCacheKey { + keepDims: boolean; + axis: number; + selectLastIndex: number; +} + +const createArgMinMaxAttributesFromInputs = + (inputs: readonly TensorView[], attributes: ArgMinMaxAttributes): ArgMinMaxAttributes => + createAttributeWithCacheKey( + {axis: attributes.axis, keepDims: attributes.keepDims, selectLastIndex: attributes.selectLastIndex}); + +const createArgMinMaxProgramInfoLoader = + (inputs: readonly TensorView[], name: string, attributes: ArgMinMaxAttributes, reduceOp: ReduceOp): + ProgramInfoLoader => { + const updatedAttributes: ArgMinMaxAttributes = + inputs.length === 1 ? attributes : createArgMinMaxAttributesFromInputs(inputs, attributes); + const cacheHint = updatedAttributes.cacheKey + inputs.map(x => x.dims.toString()).join('_'); + const metadata: ProgramMetadata = {name, inputTypes: [GpuDataType.default], cacheHint}; + return { + ...metadata, + get: () => createReduceProgramInfo( + metadata, [inputs[0]], reduceOp, [updatedAttributes.axis], DataType.int64, updatedAttributes.keepDims) + }; + }; + + +export const argMin = (context: ComputeContext, attributes: ArgMinMaxAttributes): void => { + validateInputs(context.inputs); + const argMinMaxOp: ReduceOp = (input, output, axes) => { + const idxZero = []; + for (let k = 0; k < input.shape.length; k++) { + if (axes.indexOf(k) >= 0 || axes.length === 0) { + idxZero.push(`inputIndices[${k}] = 0;`); // first element + } + } + return [ + `${idxZero.join('\n')}`, `var value = ${input.getByOffset('inputOffset')};\nvar bestIndex : i32 = 0;`, + `if (${input.getByOffset('inputOffset')} ${attributes.selectLastIndex > 0 ? '<=' : '<'} value) { + value = ${input.getByOffset('inputOffset')}; + bestIndex = i32(lastIndex); + }`, + '', output.setByOffset('global_idx', 'bestIndex') + ]; + }; + context.compute(createArgMinMaxProgramInfoLoader(context.inputs, 'ArgMin', attributes, argMinMaxOp), {inputs: [0]}); +}; + +export const argMax = (context: ComputeContext, attributes: ArgMinMaxAttributes): void => { + validateInputs(context.inputs); + const argMinMaxOp: ReduceOp = (input, output, axes) => { + const idxZero = []; + for (let k = 0; k < input.shape.length; k++) { + if (axes.indexOf(k) >= 0 || axes.length === 0) { + idxZero.push(`inputIndices[${k}] = 0;`); // first element + } + } + return [ + `${idxZero.join('\n')}`, `var value = ${input.getByOffset('inputOffset')};\nvar bestIndex : i32 = 0;`, + `if (${input.getByOffset('inputOffset')} ${attributes.selectLastIndex > 0 ? '>=' : '>'} value) { + value = ${input.getByOffset('inputOffset')}; + bestIndex = i32(lastIndex); + }`, + '', output.setByOffset('global_idx', 'bestIndex') + ]; + }; + context.compute(createArgMinMaxProgramInfoLoader(context.inputs, 'argMax', attributes, argMinMaxOp), {inputs: [0]}); +}; + +export const parseArgMinMaxAttributes = (attributes: Record): ArgMinMaxAttributes => + createAttributeWithCacheKey(attributes as Omit); diff --git a/js/web/lib/wasm/jsep/webgpu/ops/binary-op.ts b/js/web/lib/wasm/jsep/webgpu/ops/binary-op.ts index bf869d9e39061..9c05080f7e118 100644 --- a/js/web/lib/wasm/jsep/webgpu/ops/binary-op.ts +++ b/js/web/lib/wasm/jsep/webgpu/ops/binary-op.ts @@ -1,11 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import {TensorView} from '../../tensor'; +import {DataType} from '../../../wasm-common'; +import {TensorView} from '../../tensor-view'; import {BroadcastUtil, ShapeUtil} from '../../util'; import {ComputeContext, GpuDataType, ProgramInfo, ProgramInfoLoader, ProgramMetadata} from '../types'; -import {createIndicesHelper, ShaderHelper} from './common'; +import {inputVariable, outputVariable, ShaderHelper} from './common'; type BuiltinFunctionName = string; type BinaryCustomExpression = (expressionA: string, expressionB: string) => string; @@ -16,8 +17,8 @@ type BinaryFunctionCall = BuiltinFunctionName|BinaryCustomExpression|{ const createBinaryOpProgramShader = (shaderHelper: ShaderHelper, dimsA: readonly number[], dimsB: readonly number[], dimsOutput: readonly number[], - vectorize: boolean, doBroadcast: boolean, funcCall: BinaryFunctionCall, additionalImplementation?: string, - typeA = 'f32', typeB = 'f32', typeOutput = 'f32') => { + vectorize: boolean, doBroadcast: boolean, funcCall: BinaryFunctionCall, typeA: number, typeB: number, + typeOutput: number, additionalImplementation?: string) => { const outputSize = ShapeUtil.size(dimsOutput); const vecSize = Math.ceil(outputSize / 4); @@ -33,83 +34,103 @@ const createBinaryOpProgramShader = } let broadcastImpl = ''; - const outputIndicesHelper = createIndicesHelper('output', dimsOutput); + const output = outputVariable('outputData', typeOutput, dimsOutput, 4); + const a = inputVariable('aData', typeA, dimsA, 4); + const b = inputVariable('bData', typeB, dimsB, 4); if (doBroadcast) { const calcOffsetImpl = (dims: readonly number[]) => { const strides = ShapeUtil.computeStrides(dims); const offsets: string[] = []; for (let i = dims.length - 1; i >= 0; i--) { - const idx = dimsOutput.length === 0 ? '0u' : - (dimsOutput.length === 1) ? '(*outputIndices)' : - `(*outputIndices)[${i + dimsOutput.length - dims.length}]`; + const idx = output.indicesGet('outputIndices', i + dimsOutput.length - dims.length); offsets.push(`${strides[i]}u * (${idx} % ${dims[i]}u)`); } return offsets.length > 0 ? offsets.join('+') : '0u'; }; broadcastImpl = ` - ${outputIndicesHelper.o2iImpl} - - fn calcOffsetA(outputIndices: ptr) -> u32 { - return ${calcOffsetImpl(dimsA)}; - } + fn calcOffsetA(outputIndices: ${output.type.indices}) -> u32 { + return ${calcOffsetImpl(dimsA)}; + } - fn calcOffsetB(outputIndices: ptr) -> u32 { - return ${calcOffsetImpl(dimsB)}; - } - `; + fn calcOffsetB(outputIndices: ${output.type.indices}) -> u32 { + return ${calcOffsetImpl(dimsB)}; + } + `; } let assignment: string; if (vectorize) { if (doBroadcast) { - assignment = ` - ${outputIndicesHelper.indicesVariableDeclaration('outputIndices')} - ${outputIndicesHelper.o2iCall('global_idx * 4u', 'outputIndices')} - let offsetA = calcOffsetA(&outputIndices); - let offsetB = calcOffsetB(&outputIndices); - outputData[global_idx] = ${expressionVector('aData[offsetA / 4u]', 'bData[offsetB / 4u]')};`; + const isAOneElement = ShapeUtil.size(dimsA) === 1; + const isBOneElement = ShapeUtil.size(dimsB) === 1; + if (isAOneElement || isBOneElement) { + assignment = output.setByOffset( + 'global_idx', + expressionVector( + isAOneElement ? `${a.type.value}(${a.getByOffset('0')}.x)` : a.getByOffset('global_idx'), + isBOneElement ? `${b.type.value}(${b.getByOffset('0')}.x)` : b.getByOffset('global_idx'))); + } else { + assignment = ` + let outputIndices = ${output.offsetToIndices('global_idx * 4u')}; + let offsetA = calcOffsetA(outputIndices); + let offsetB = calcOffsetB(outputIndices); + ${ + output.setByOffset( + 'global_idx', expressionVector(a.getByOffset('offsetA / 4u'), b.getByOffset('offsetB / 4u')))} + `; + } } else { - assignment = `outputData[global_idx] = ${expressionVector('aData[global_idx]', 'bData[global_idx]')};`; + assignment = output.setByOffset( + 'global_idx', expressionVector(a.getByOffset('global_idx'), b.getByOffset('global_idx'))); } } else { if (!doBroadcast) { throw new Error('no necessary to use scalar implementation for element-wise binary op implementation.'); } - const singleAssignment = (x: number) => { + + const singleAssignment = (resStr: string, x: number, typeCast = '') => { const expressionA = `aData[indexA${x}][componentA${x}]`; const expressionB = `bData[indexB${x}][componentB${x}]`; return ` - ${outputIndicesHelper.o2iCall(`global_idx * 4u + ${x}u`, 'outputIndices')} - let offsetA${x} = calcOffsetA(&outputIndices); - let offsetB${x} = calcOffsetB(&outputIndices); - let indexA${x} = offsetA${x} / 4u; - let indexB${x} = offsetB${x} / 4u; - let componentA${x} = offsetA${x} % 4u; - let componentB${x} = offsetB${x} % 4u; - outputData[global_idx][${x}] = ${expressionScalar(expressionA, expressionB)};`; + let outputIndices${x} = ${output.offsetToIndices(`global_idx * 4u + ${x}u`)}; + let offsetA${x} = calcOffsetA(outputIndices${x}); + let offsetB${x} = calcOffsetB(outputIndices${x}); + let indexA${x} = offsetA${x} / 4u; + let indexB${x} = offsetB${x} / 4u; + let componentA${x} = offsetA${x} % 4u; + let componentB${x} = offsetB${x} % 4u; + ${resStr}[${x}] = ${typeCast}(${expressionScalar(expressionA, expressionB)}); + `; }; - - assignment = ` - ${outputIndicesHelper.indicesVariableDeclaration('outputIndices')} - ${singleAssignment(0)} - ${singleAssignment(1)} - ${singleAssignment(2)} - ${singleAssignment(3)}`; + if (typeOutput === DataType.bool) { + assignment = ` + var data = vec4(0); + ${singleAssignment('data', 0, 'u32')} + ${singleAssignment('data', 1, 'u32')} + ${singleAssignment('data', 2, 'u32')} + ${singleAssignment('data', 3, 'u32')} + outputData[global_idx] = dot(vec4(0x1, 0x100, 0x10000, 0x1000000), vec4(data));`; + } else { + assignment = ` + ${singleAssignment('outputData[global_idx]', 0)} + ${singleAssignment('outputData[global_idx]', 1)} + ${singleAssignment('outputData[global_idx]', 2)} + ${singleAssignment('outputData[global_idx]', 3)} + `; + } } return ` - @group(0) @binding(0) var aData : array>; - @group(0) @binding(1) var bData : array>; - @group(0) @binding(2) var outputData : array>; + ${shaderHelper.declareVariables(a, b, output)} - ${additionalImplementation ?? ''} - ${broadcastImpl} + ${additionalImplementation ?? ''} + ${broadcastImpl} - ${shaderHelper.mainStart()} - ${shaderHelper.guardAgainstOutOfBoundsWorkgroupSizes(vecSize)} - ${assignment} - }`; + ${shaderHelper.mainStart()} + ${shaderHelper.guardAgainstOutOfBoundsWorkgroupSizes(vecSize)} + ${assignment} + }`; }; const createBinaryOpProgramInfo = @@ -130,10 +151,12 @@ const createBinaryOpProgramInfo = } outputShape = calculatedShape; outputSize = ShapeUtil.size(outputShape); + const isAOneElement = ShapeUtil.size(a.dims) === 1; + const isBOneElement = ShapeUtil.size(b.dims) === 1; // check whether vectorize can be enabled let sharedDimension = 1; - for (let i = 0; i < outputShape.length; i++) { + for (let i = 1; i < outputShape.length; i++) { const dimA = a.dims[a.dims.length - i] ?? 1; const dimB = b.dims[b.dims.length - i] ?? 1; if (dimA === dimB) { @@ -142,11 +165,9 @@ const createBinaryOpProgramInfo = break; } } - if (sharedDimension % 4 === 0) { + if (sharedDimension % 4 === 0 || isAOneElement || isBOneElement) { vectorize = true; } - - } else { // element-wise vectorize = true; @@ -155,21 +176,22 @@ const createBinaryOpProgramInfo = return { ...metadata, getShaderSource: (shaderHelper) => createBinaryOpProgramShader( - shaderHelper, a.dims, b.dims, outputShape, vectorize, isBroadcast, funcCall, additionalImplementation), + shaderHelper, a.dims, b.dims, outputShape, vectorize, isBroadcast, funcCall, a.dataType, b.dataType, + outputDataType, additionalImplementation), outputs: [{dims: outputShape, dataType: outputDataType, gpuDataType: GpuDataType.default}], - dispatchGroup: () => - ({x: Math.ceil(outputSize / 64 /* workgroup size */ / (vectorize ? 4 : 1) /* vec size */)}) + dispatchGroup: () => ({x: Math.ceil(outputSize / 64 /* workgroup size */ / 4 /* component size */)}) }; }; const createBinaryOpProgramInfoLoader = (inputs: readonly TensorView[], name: string, funcCall: BinaryFunctionCall, additionalImplementation?: string, - cacheKey?: string): ProgramInfoLoader => { + cacheKey?: string, outputDataType?: number): ProgramInfoLoader => { const metadata: ProgramMetadata = {name, inputTypes: [GpuDataType.default, GpuDataType.default], cacheHint: cacheKey}; return { ...metadata, - get: () => createBinaryOpProgramInfo(metadata, inputs[0], inputs[1], funcCall, additionalImplementation) + get: () => createBinaryOpProgramInfo( + metadata, inputs[0], inputs[1], funcCall, additionalImplementation, outputDataType) }; }; @@ -181,24 +203,35 @@ export const div = (context: ComputeContext): void => { context.compute(createBinaryOpProgramInfoLoader(context.inputs, 'Div', (a, b) => `${a}/${b}`)); }; +export const equal = (context: ComputeContext): void => { + context.compute(createBinaryOpProgramInfoLoader( + context.inputs, 'Equal', ({scalar: (a, b) => `u32(${a}==${b})`, vector: (a, b) => `vec4(${a}==${b})`}), + undefined, undefined, DataType.bool)); +}; + export const mul = (context: ComputeContext): void => { context.compute(createBinaryOpProgramInfoLoader(context.inputs, 'Mul', (a, b) => `${a}*${b}`)); }; export const pow = (context: ComputeContext): void => { + const type = inputVariable('input', context.inputs[0].dataType, context.inputs[0].dims).type.value; + const roundStr = type === 'i32' ? 'round' : ''; context.compute(createBinaryOpProgramInfoLoader( - context.inputs, 'Pow', ({scalar: (a, b) => `pow_f32(${a},${b})`, vector: (a, b) => `pow_vf32(${a},${b})`}), ` - fn pow_f32(a : f32, b : f32) -> f32 { - if (b == 0.0) { - return 1.0; - } else if (a < 0.0 && b != floor(b)) { - return pow(a, b); // NaN + context.inputs, 'Pow', + ({scalar: (a, b) => `pow_custom(${a},${b})`, vector: (a, b) => `pow_vector_custom(${a},${b})`}), + ` + fn pow_custom(a : ${type}, b : ${type}) -> ${type} { + if (b == ${type}(0.0)) { + return ${type}(1.0); + } else if (a < ${type}(0.0) && f32(b) != floor(f32(b))) { + return ${type}(pow(f32(a), f32(b))); // NaN } - return select(sign(a), 1.0, round(abs(b) % 2.0) != 1.0) * pow(abs(a), b); + return select(sign(a), ${type}(1.0), round(f32(abs(b) % ${type}(2.0))) != 1.0) * ${type}(${ + roundStr}(pow(f32(abs(a)), f32(b)))); } - fn pow_vf32(a : vec4, b : vec4) -> vec4 { + fn pow_vector_custom(a : vec4<${type}>, b : vec4<${type}>) -> vec4<${type}> { // TODO: implement vectorized pow - return vec4(pow_f32(a.x, b.x), pow_f32(a.y, b.y), pow_f32(a.z, b.z), pow_f32(a.w, b.w)); + return vec4<${type}>(pow_custom(a.x, b.x), pow_custom(a.y, b.y), pow_custom(a.z, b.z), pow_custom(a.w, b.w)); } `)); }; @@ -206,3 +239,28 @@ export const pow = (context: ComputeContext): void => { export const sub = (context: ComputeContext): void => { context.compute(createBinaryOpProgramInfoLoader(context.inputs, 'Sub', (a, b) => `${a}-${b}`)); }; + +export const greater = (context: ComputeContext): void => { + context.compute(createBinaryOpProgramInfoLoader( + context.inputs, 'Greater', ({scalar: (a, b) => `u32(${a}>${b})`, vector: (a, b) => `vec4(${a}>${b})`}), + undefined, undefined, DataType.bool)); +}; + +export const less = (context: ComputeContext): void => { + context.compute(createBinaryOpProgramInfoLoader( + context.inputs, 'Less', ({scalar: (a, b) => `u32(${a}<${b})`, vector: (a, b) => `vec4(${a}<${b})`}), + undefined, undefined, DataType.bool)); +}; + +export const greaterOrEqual = (context: ComputeContext): void => { + context.compute(createBinaryOpProgramInfoLoader( + context.inputs, 'GreaterOrEqual', + ({scalar: (a, b) => `u32(${a}>=${b})`, vector: (a, b) => `vec4(${a}>=${b})`}), undefined, undefined, + DataType.bool)); +}; + +export const lessOrEqual = (context: ComputeContext): void => { + context.compute(createBinaryOpProgramInfoLoader( + context.inputs, 'LessOrEqual', ({scalar: (a, b) => `u32(${a}<=${b})`, vector: (a, b) => `vec4(${a}<=${b})`}), + undefined, undefined, DataType.bool)); +}; diff --git a/js/web/lib/wasm/jsep/webgpu/ops/common.ts b/js/web/lib/wasm/jsep/webgpu/ops/common.ts index 7305ab592d4a7..0ab777bfbdee9 100644 --- a/js/web/lib/wasm/jsep/webgpu/ops/common.ts +++ b/js/web/lib/wasm/jsep/webgpu/ops/common.ts @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +import {DataType} from '../../../wasm-common'; import {ShapeUtil} from '../../util'; /** @@ -15,109 +16,584 @@ import {ShapeUtil} from '../../util'; **/ export const WORKGROUP_SIZE = 64; +interface IndicesHelperTypes { + /** + * WGSL type of indices expression + */ + readonly indices: string; + + /** + * WGSL type of a value + */ + readonly value: string; + + /** + * WGSL type of storage type representing a value + * + * This is usually the same to `value`, but for some type (eg. bool), we need to use `u32` as storage type for + * value type `vec4` + */ + readonly storage: string; + + /** + * tensor type as represented in TensorView + */ + readonly tensor: number; +} + +/** + * A helper class for generating WGSL code for manipulating indices and data for a shader's input or output. + * + * This class is designed to offer a unified way to generate WGSL code for manipulating indices and data for a shader's + * input or output. + * + * The following is a list of terminologies used in this class: + * - `offset`: a uint32 value representing the offset of an element in the data buffer. + * - `indices`: an abstraction of a multi-dimensional array's indices representing the data's index on each dimension. + * - `value`: a value of a data element. + * + * Users are expected to create an instance of this class for each shader's input or output, and use the instance to + * generate WGSL code for manipulating indices and data. The following 2 exported functions are for users to call to + * create an instance of an indices helper: + * - `inputVariable()`: create an indices helper instance for an input. + * - `outputVariable()`: create an indices helper instance for an output. + * + * An indices helper instance contains helper functions for the following operations: + * - access readonly basic information, including: `name`(the name of the input or output), `usage`(whether it's an + * input or an output) and `shape`(the passed in shape). + * - `type`: access readonly type information, including: `indices`(the type of indices), `value`(the type of value at + * runtime), `storage`(the type of value at storage) and `tensor`(the tensor type as represented in TensorView). + * - generate WGSL code for getting indices from offset. Use `offsetToIndices()` for WGSL code snippet to calculate + * indices from offset, and use `indicesToOffset()` for WGSL code snippet to calculate offset from indices. + * - to manipulate an instance of indices, use `setIndices()` and `getIndices()` to set and get the indices on an + * indices variable. + * - to manipulate data, use `set()`/`get()` to access data at the given indices from parameter list, use + * `setByIndices()`/`getByIndices()` to access data at the given indices from an indices variable, and use + * `setByOffset()`/`getByOffset()` to access data at the given offset. + * - `impl`: get WGSL code of function implementation for the util functions mentioned above. + */ export interface IndicesHelper { /** - * WGSL code of function implementation for offset-to-indices + * get WGSL code of function implementation for the util functions. + * */ - o2iImpl: string; + readonly impl: () => string; + /** - * WGSL code of function call for offset-to-indices + * get type info */ - o2iCall: (varOffset: string, varIndices: string) => string; + readonly type: IndicesHelperTypes; + /** - * WGSL code of function implementation for indices-to-offset + * WGSL code of a expression for getting indices from offset. + * + * @param varOffset - a u32 expression representing the offset. + * + * @returns an `type.indices` expression */ - i2oImpl: string; + readonly offsetToIndices: (varOffset: string) => string; + /** - * WGSL code of function implementation for indices-to-offset + * WGSL code of an `u32` expression for getting offset from indices. + * + * @param varIndices - a `type.indices` expression representing the indices. * - * @param isPtr - whether the variable is a pointer. default is false. + * @returns an `u32` expression */ - i2oExpression: (varIndices: string, isPtr?: boolean) => string; + readonly indicesToOffset: (varIndices: string) => string; + /** - * WGSL code of indices variable declaration + * WGSL code of generating an indices literal * - * @param v - variable name. * @param init - initial value. */ - indicesVariableDeclaration: (v: string, init?: string[]) => string; + readonly indices: (...init: ReadonlyArray) => string; + /** - * data type of indices + * WGSL code of a statement for setting indices. + * + * @param varIndices - a variable name for the indices. + * @param idx - the index of the indices to set. can be a number or a string (WGSL `u32` expression). + * @param value - the value to set. can be a number or a string (WGSL `u32` expression). + * + * @returns a WGSL statement */ - iType: string; + readonly indicesSet: (varIndices: string, idx: number|string, value: number|string) => void; + + /** + * WGSL code of an `u32` expression for getting indices. + * + * @param varIndices - a variable name for the indices. + * @param idx - the index of the indices to get. can be a number or a string (WGSL `u32` expression). + * + * @returns an `u32` expression + */ + readonly indicesGet: (varIndices: string, idx: number|string) => string; + + /** + * WGSL code for a statement for setting data at the given indices. + * + * @param indicesAndValue - an array of numbers or strings (WGSL `u32` expression) representing the indices, followed + * by the value to set. This array should have exactly `shape.length + 1` elements. + */ + readonly set: (...indicesAndValue: ReadonlyArray) => string; + + /** + * WGSL code for a statement for setting data at the given indices variable. + * + * @param varIndices - a variable name for the indices. + * @param value - the value to set. should be a WGSL expression. + */ + readonly setByIndices: (varIndices: string, value: string) => string; + + /** + * WGSL code for a statement for setting data at the given offset. + * + * @param offset - a number or a string (WGSL `u32` expression) representing the offset. + * @param value - the value to set. should be a WGSL expression. + */ + readonly setByOffset: (offset: number|string, value: string) => string; + + /** + * WGSL code for an expression for getting data at the given indices. + * + * @param indices - an array of numbers or strings (WGSL `u32` expression) representing the indices. + */ + readonly get: (...indices: ReadonlyArray) => string; + + /** + * WGSL code for an expression for getting data at the given indices variable. + * + * @param varIndices - a variable name for the indices. + */ + readonly getByIndices: (varIndices: string) => string; + + /** + * WGSL code for an expression for getting data at the given offset. + * + * @param offset - a number or a string (WGSL `u32` expression) representing the offset. + */ + readonly getByOffset: (offset: number|string) => string; + + /** + * name of the data variable + */ + readonly name: string; + + /** + * whether the helper is for an input or an output. + */ + readonly usage: 'input'|'output'; + + /** + * the shape of the input or output. + */ + readonly shape: readonly number[]; } -export const createIndicesHelper = (name: string, shape: readonly number[]): IndicesHelper => { - const iType = shape.length < 2 ? 'u32' : `array`; +const getWgslMappedType = (type: number, components: 1|2|3|4): string|[string, string] => { + if (components === 3) { + throw new Error('vec3 has same alignment as vec4, use vec4 instead'); + } + + // return type is [ storage type, runtime type ] or a single string for both + switch (type) { + case DataType.float16: + return components > 1 ? `vec${components}` : 'f16'; + case DataType.float: + return components > 1 ? `vec${components}` : 'f32'; + case DataType.int32: + return components > 1 ? `vec${components}` : 'i32'; + case DataType.uint32: + return components > 1 ? `vec${components}` : 'u32'; + case DataType.int64: + if (components > 1) { + throw new Error('currently not supported vecX of uint64 yet'); + } + return ['vec2', 'i32']; + case DataType.uint64: + if (components > 1) { + throw new Error('currently not supported vecX of uint64 yet'); + } + return ['vec2', 'u32']; + case DataType.bool: + if (components !== 4) { + throw new Error('bool must be vec4'); + } + return ['u32', 'vec4']; - const strides = ShapeUtil.computeStrides(shape); - let o2iSnippet = ''; - for (let i = 0; i < shape.length - 1; i++) { - o2iSnippet += ` + default: + throw new Error(`Unknown data type: ${type}`); + } +}; + +export const tensorTypeToWsglStorageType = (type: DataType, components: 1|2|3|4 = 1) => { + const mappedType = getWgslMappedType(type, components); + return typeof mappedType === 'string' ? mappedType : mappedType[0]; +}; + +export const tensorTypeToWsglValueType = (type: DataType, components: 1|2|3|4 = 1) => { + const mappedType = getWgslMappedType(type, components); + return typeof mappedType === 'string' ? mappedType : mappedType[1]; +}; + +/** + * A helper function to get a IndicesHelper for a given input or output. + * + * @param name - the name of the input or output. + * @param tensorType - the tensor type of the input or output. + * @param shape - the tensor shape of the input or output. + * @param isInput - whether the helper is for an input or an output. + * @param components - indicates the number of components of each element. 1 for scalar, 2 for vec2, 3 for vec3, 4 for + * vec4. + */ +const createIndicesHelper = + (name: string, tensorType: number, shape: readonly number[], isInput: boolean, + components: 1|2|3|4): IndicesHelper => { + const rank = shape.length; + const indicesType = rank < 2 ? 'u32' : rank <= 4 ? `vec${rank}` : `array`; + const mappedType = getWgslMappedType(tensorType, components); + const valueType = typeof mappedType === 'string' ? mappedType : mappedType[1]; + const storageType = typeof mappedType === 'string' ? mappedType : mappedType[0]; + const type = {indices: indicesType, value: valueType, storage: storageType, tensor: tensorType}; + + const normalizeDim = (dim: number|string): string => typeof dim === 'string' ? dim : `${dim}u`; + + const implementationUsed = { + offsetToIndices: false, + indicesToOffset: false, + set: false, + setByIndices: false, + get: false, + getByIndices: false, + }; + + const strides = ShapeUtil.computeStrides(shape); + let o2iSnippet = ''; + for (let i = 0; i < rank - 1; i++) { + o2iSnippet += ` let dim${i} = current / ${strides[i]}u; let rest${i} = current % ${strides[i]}u; - (*indices)[${i}] = dim${i}; + indices[${i}] = dim${i}; current = rest${i}; `; - } - o2iSnippet += `(*indices)[${shape.length - 1}] = current;`; + } + o2iSnippet += `indices[${rank - 1}] = current;`; - const o2iImpl = shape.length < 2 ? '' : ` - fn ih_o2i_${name}(offset: u32, indices: ptr) { + const offsetToIndicesImplementation = rank < 2 ? '' : ` + fn o2i_${name}(offset: u32) -> ${type.indices} { + var indices: ${type.indices}; var current = offset; ${o2iSnippet} + return indices; }`; - const o2iCall = (varOffset: string, varIndices: string) => - shape.length < 2 ? `${varIndices}=${varOffset};` : `ih_o2i_${name}(${varOffset}, &${varIndices});`; - - const offsets: string[] = []; - if (shape.length === 0) { - offsets.push('0u'); - } else if (shape.length < 2) { - offsets.push('(*indices)'); - } else { - for (let i = shape.length - 1; i >= 0; i--) { - offsets.push(`${strides[i]}u * ((*indices)[${i}])`); - } - } + const offsetToIndices = (varOffset: string) => { + implementationUsed.offsetToIndices = true; + return rank < 2 ? varOffset : `o2i_${name}(${varOffset})`; + }; - const i2oImpl = shape.length < 2 ? '' : ` - fn ih_i2o_${name}(indices: ptr) -> u32 { + const offsets: string[] = []; + if (rank >= 2) { + for (let i = rank - 1; i >= 0; i--) { + offsets.push(`${strides[i]}u * (indices[${i}])`); + } + } + + const indicesToOffsetImplementation = rank < 2 ? '' : ` + fn i2o_${name}(indices: ${type.indices}) -> u32 { return ${offsets.join('+')}; }`; - const i2oExpression = (varIndices: string, isPtr?: boolean) => - shape.length < 2 ? `(${isPtr ? '*' : ''}${varIndices})` : `ih_i2o_${name}(${isPtr ? '' : '&'}${varIndices})`; + const indicesToOffset = (varIndices: string) => { + implementationUsed.indicesToOffset = true; + return rank < 2 ? varIndices : `i2o_${name}(${varIndices})`; + }; - const indicesVariableDeclaration = (v: string, init?: string[]) => - `var ${v}:${iType}${init ? `=${iType}(${init.join(',')})` : ''};`; + const indices = (...init: ReadonlyArray) => + rank === 0 ? '0u' : `${type.indices}(${init.map(normalizeDim).join(',')})`; - return {o2iImpl, o2iCall, i2oImpl, i2oExpression, indicesVariableDeclaration, iType}; -}; + const indicesGet = (varIndices: string, idx: number|string) => { + if (rank < 2) { + return `${varIndices}`; + } else { + return `${varIndices}[${idx}]`; + } + }; + + const indicesSet = (varIndices: string, idx: number|string, value: string) => { + if (rank < 2) { + return `${varIndices}=${value};`; + } else { + return `${varIndices}[${idx}]=${value};`; + } + }; + + const setByOffset = (offset: number|string, value: string) => (() => { + if (type.storage === type.value) { + return `${name}[${offset}]=${value};`; + } else if (type.storage === 'vec2' && type.value === 'i32') { + // int64, components === 1 + return `${name}[${offset}]=vec2(u32(${value}), select(0u, 0xFFFFFFFFu, ${value} < 0));`; + } else if (type.storage === 'vec2' && type.value === 'u32') { + // uint64, components === 1 + return `${name}[${offset}]=vec2(u32(${value}), 0u);`; + } else if (type.storage === 'u32' && type.value === 'vec4') { + // bool, components === 4 + return `${name}[${offset}]=dot(vec4(0x1, 0x100, 0x10000, 0x1000000), vec4(${value}));`; + } else { + throw new Error(`not supported combination of storage type ${type.storage} and value type ${type.value} yet`); + } + })(); + + const getByOffset = (offset: number|string) => (() => { + if (type.storage === type.value) { + return `${name}[${offset}]`; + } else if (type.storage === 'vec2' && type.value === 'i32') { + // int64, components === 1 + return `i32(${name}[${offset}].x)`; + } else if (type.storage === 'vec2' && type.value === 'u32') { + // uint64, components === 1 + return `u32(${name}[${offset}].x)`; + } else if (type.storage === 'u32' && type.value === 'vec4') { + // bool, components === 4 + return `vec4(bool(${name}[${offset}] & 0xFFu), bool(${name}[${offset}] & 0xFF00u), bool(${name}[${ + offset}] & 0xFF0000u), bool(${name}[${offset}] & 0xFF000000u))`; + } else { + throw new Error(`not supported combination of storage type ${type.storage} and value type ${type.value} yet`); + } + })(); + + const getByIndicesImplementation = rank < 2 ? '' : ` + fn get_${name}ByIndices(indices: ${type.indices}) -> ${valueType} { + return ${getByOffset(`i2o_${name}(indices)`)}; + }`; + + const getImplementation = rank < 2 ? '' : (() => { + const params = shape.map((_, i) => `d${i}: u32`).join(', '); + const dims = shape.map((_, i) => `d${i}`).join(', '); + return ` + fn get_${name}(${params}) -> ${valueType} { + return get_${name}ByIndices(${indices(dims)}); + }`; + })(); + + const get = (...indices: ReadonlyArray) => { + if (indices.length !== rank) { + throw new Error(`indices length must be ${rank}`); + } + + const normalizedIndices = indices.map(normalizeDim).join(','); + + if (rank === 0) { + return getByOffset('0u'); + } else if (rank === 1) { + return getByOffset(normalizedIndices[0]); + } else { + implementationUsed.get = true; + implementationUsed.getByIndices = true; + implementationUsed.indicesToOffset = true; + return `get_${name}(${normalizedIndices})`; + } + }; + + const getByIndices = (varIndices: string) => { + if (rank < 2) { + return getByOffset(varIndices); + } else { + implementationUsed.getByIndices = true; + implementationUsed.indicesToOffset = true; + return `get_${name}ByIndices(${varIndices})`; + } + }; + + const setByIndicesImplementation = rank < 2 ? '' : ` + fn set_${name}ByIndices(indices: ${type.indices}, value: ${valueType}) { + ${setByOffset(`i2o_${name}(indices)`, 'value')} + }`; + + const setImplementation = rank < 2 ? '' : (() => { + const params = shape.map((_, i) => `d${i}: u32`).join(', '); + const dims = shape.map((_, i) => `d${i}`).join(', '); + return ` + fn set_${name}(${params}, value: ${valueType}) { + set_${name}ByIndices(${indices(dims)}, value); + }`; + })(); + + const set = (...indicesAndValue: ReadonlyArray) => { + if (indicesAndValue.length !== rank + 1) { + throw new Error(`indices length must be ${rank}`); + } + const value = indicesAndValue[rank]; + if (typeof value !== 'string') { + throw new Error('value must be string'); + } + + const normalizedIndices = indicesAndValue.slice(0, rank).map(normalizeDim).join(','); + + if (rank === 0) { + return setByOffset('0u', value); + } else if (rank === 1) { + return setByOffset(normalizedIndices[0], value); + } else { + implementationUsed.set = true; + implementationUsed.setByIndices = true; + implementationUsed.indicesToOffset = true; + return `set_${name}(${normalizedIndices}, ${value})`; + } + }; + + const setByIndices = (varIndices: string, value: string) => { + if (rank < 2) { + return setByOffset(varIndices, value); + } else { + implementationUsed.setByIndices = true; + implementationUsed.indicesToOffset = true; + return `set_${name}ByIndices(${varIndices}, ${value});`; + } + }; + + const impl = () => { + const impls = []; + if (implementationUsed.offsetToIndices) { + impls.push(offsetToIndicesImplementation); + } + if (implementationUsed.indicesToOffset) { + impls.push(indicesToOffsetImplementation); + } + if (implementationUsed.set) { + impls.push(setImplementation); + } + if (implementationUsed.setByIndices) { + impls.push(setByIndicesImplementation); + } + if (implementationUsed.get) { + impls.push(getImplementation); + } + if (implementationUsed.getByIndices) { + impls.push(getByIndicesImplementation); + } + return impls.join('\n'); + }; + + return { + impl, + type, + offsetToIndices, + indicesToOffset, + indices, + indicesGet, + indicesSet, + set, + setByOffset, + setByIndices, + get, + getByOffset, + getByIndices, + // isVec4, + usage: isInput ? 'input' : 'output', + name, + shape + }; + }; + +/** + * Create a IndicesHelper for an input. + * + * @param name - the name of the input. + * @param type - the tensor type of the input. + * @param shape - the tensor shape of the input. + * @param components - the number of components of the input. available values are 1, 2, 3, 4. default is 1. + * @returns an IndicesHelper for the input. + */ +export const inputVariable = + (name: string, type: number, shape: readonly number[], components: 1|2|3|4 = 1): IndicesHelper => + createIndicesHelper(name, type, shape, true, components); + +/** + * Create a IndicesHelper for an output. + * + * @param name - the name of the output. + * @param type - the tensor type of the output. + * @param shape - the tensor shape of the output. + * @param components - the number of components of the input. available values are 1, 2, 3, 4. default is 1. + * @returns an IndicesHelper for the output. + */ +export const outputVariable = + (name: string, type: number, shape: readonly number[], components: 1|2|3|4 = 1): IndicesHelper => + createIndicesHelper(name, type, shape, false, components); /** * A ShaderHelper is a helper class for generating WGSL code. */ export interface ShaderHelper { + /** + * A helper function to generate the start of main function in WGSL source code. + * + * @example + * const getShaderSource = (shaderHelper: ShaderHelper) => ` + * ... + * + * ${shaderHelper.mainStart()} + * // your code here inside main() function + * ... + * } + * `; + * + * @param workgroupSize - an optional workgroup size. default is WORKGROUP_SIZE. + */ mainStart(workgroupSize?: number|[number, number, number]): string; + + /** + * A helper function to generate the code snippet for guarding against out-of-bounds size. + * + * @example + * const getShaderSource = (shaderHelper: ShaderHelper) => ` + * ... + * + * ${shaderHelper.mainStart()} + * ${shaderHelper.guardAgainstOutOfBoundsWorkgroupSizes(outputSize)} + * + * // your code here inside main() function + * ... + * } + * `; + * + * @param size - the size of the data to guard against. can be a number or a string (WGSL `u32` expression). + */ guardAgainstOutOfBoundsWorkgroupSizes(size: unknown): string; + + /** + * A helper function to generate the code snippet for declaring multiple inputs or outputs. + * + * @param variables - an array of IndicesHelper for the variables. + */ + declareVariables(...variables: IndicesHelper[]): string; + + /** + * Get additional implementation that needs to be added to the shader source. + */ + readonly additionalImplementations: string; } class ShaderHelperImpl implements ShaderHelper { constructor(private normalizedDispatchGroup: [number, number, number]) {} + guardAgainstOutOfBoundsWorkgroupSizes(size: number|string): string { // Guard against out-of-bounds work group sizes const sizeInCode = typeof size === 'number' ? `${size}u` : size; return `if (global_idx >= ${sizeInCode}) { return; }`; } + mainStart(workgroupSize: number|[number, number, number] = WORKGROUP_SIZE) { const workgroupSizeX = typeof workgroupSize === 'number' ? workgroupSize : workgroupSize[0]; const workgroupSizeY = typeof workgroupSize === 'number' ? 1 : workgroupSize[1]; const workgroupSizeZ = typeof workgroupSize === 'number' ? 1 : workgroupSize[2]; const is1DimensionDispatch = this.normalizedDispatchGroup[1] === 1 && this.normalizedDispatchGroup[2] === 1; - const paramList = is1DimensionDispatch ? '@builtin(global_invocation_id) global_id : vec3' : + const paramList = is1DimensionDispatch ? `@builtin(global_invocation_id) global_id : vec3, + @builtin(local_invocation_id) local_id : vec3` : `@builtin(local_invocation_index) local_index : u32, @builtin(workgroup_id) workgroup_id : vec3`; const globalIdxDefinition = is1DimensionDispatch ? @@ -131,7 +607,49 @@ class ShaderHelperImpl implements ShaderHelper { ${globalIdxDefinition} `; } + + declareVariable(variable: IndicesHelper, bindingIndex: number): string { + this.indicesHelpers.push(variable); + const access = variable.usage === 'input' ? 'read' : 'read_write'; + const storageType = variable.type.storage; + return `@group(0) @binding(${bindingIndex}) var ${variable.name}: array<${storageType}>;`; + } + + declareVariables(...variables: IndicesHelper[]): string { + let i = 0; + return variables.filter(v => ShapeUtil.size(v.shape) > 0).map(v => this.declareVariable(v, i++)).join('\n'); + } + + private indicesHelpers: IndicesHelper[] = []; + + get additionalImplementations(): string { + return this.indicesHelpers.map(i => i.impl()).join('\n'); + } } export const createShaderHelper = (dispatchGroup: [number, number, number]): ShaderHelper => new ShaderHelperImpl(dispatchGroup); + +/** + * This function comes from https://github.com/tensorflow/tfjs/blob/master/tfjs-core/src/ops/broadcast_util.ts#L18-L40 + * Returns the dimensions in the input shape that are broadcasted to + * produce the provided output shape. + * + * The returned dimensions are 0-indexed and sorted. An example: + * inShape = [4, 1, 3] + * outShape = [5, 4, 3, 3] + * result = [1]. Dimension 1 (2nd dimension of input) gets broadcasted 1 => 3. + */ +export const getBroadcastDims = (inShape: readonly number[], outShape: readonly number[]): number[] => { + const inRank = inShape.length; + const dims: number[] = []; + for (let i = 0; i < inRank; i++) { + const dim = inRank - 1 - i; + const a = inShape[dim] || 1; + const b = outShape[outShape.length - 1 - i] || 1; + if (b > 1 && a === 1) { + dims.unshift(dim); + } + } + return dims; +}; diff --git a/js/web/lib/wasm/jsep/webgpu/ops/concat.ts b/js/web/lib/wasm/jsep/webgpu/ops/concat.ts index d00f1768715ab..279632c190ded 100644 --- a/js/web/lib/wasm/jsep/webgpu/ops/concat.ts +++ b/js/web/lib/wasm/jsep/webgpu/ops/concat.ts @@ -1,12 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import {TensorView} from '../../tensor'; +import {TensorView} from '../../tensor-view'; import {ShapeUtil} from '../../util'; -import {AttributeWithCacheKey} from '../attribute-with-cache-key'; +import {AttributeWithCacheKey, createAttributeWithCacheKey} from '../attribute-with-cache-key'; import {ComputeContext, GpuDataType, ProgramInfo, ProgramInfoLoader, ProgramMetadata} from '../types'; -import {createIndicesHelper, IndicesHelper, ShaderHelper} from './common'; +import {IndicesHelper, inputVariable, outputVariable, ShaderHelper} from './common'; export interface ConcatAttributes extends AttributeWithCacheKey { readonly axis: number; @@ -46,29 +46,27 @@ const calculateInputIndexImpl = (numberOfTensors: number): string => ` return ${numberOfTensors}u; }`; -const readBufferDataImpl = (indicesHelper: readonly IndicesHelper[], tensorRank: number, dataType: string) => { - const numberOfTensors = indicesHelper.length; +const assignOutputData = (inputs: readonly IndicesHelper[], output: IndicesHelper) => { + const numberOfTensors = inputs.length; + const codeLines: string[] = []; for (let i = 0; i < numberOfTensors; ++i) { - const returnSnippet = `return input${i}[${indicesHelper[i].i2oExpression('indices', true)}];`; + const returnSnippet = output.setByOffset('global_idx', inputs[i].getByIndices('indices')); if (numberOfTensors === 1) { codeLines.push(returnSnippet); } else if (i === 0) { - codeLines.push(`if (textureIndex == ${i}u) { ${returnSnippet} }`); + codeLines.push(`if (inputIndex == ${i}u) { ${returnSnippet} }`); } else if (i === numberOfTensors - 1) { codeLines.push(`else { ${returnSnippet} }`); } else { - codeLines.push(`else if (textureIndex == ${i}) { ${returnSnippet} }`); + codeLines.push(`else if (inputIndex == ${i}) { ${returnSnippet} }`); } } - return ` - fn readBufferData(textureIndex: u32, indices: ptr) -> ${dataType} { - ${codeLines.join('\n')} - }`; + return codeLines.join('\n'); }; const createConcatProgramInfo = - (metadata: ProgramMetadata, inputs: readonly TensorView[], axis: number, dataType = 'f32'): ProgramInfo => { + (metadata: ProgramMetadata, inputs: readonly TensorView[], axis: number): ProgramInfo => { const inputShape = inputs[0].dims.slice(); if (axis >= inputShape.length || axis < (-1 * inputShape.length)) { throw new Error('axis specified for concat doesn\'t match input dimensionality'); @@ -92,50 +90,39 @@ const createConcatProgramInfo = } const outputSize = ShapeUtil.size(outputShape); - const rank = outputShape.length; const sizeInConcatAxis = new Array(inputs.length); - const inputStorageBuffersDeclarations = new Array(inputs.length); - const inputIndicesHelpers = new Array(inputs.length); + const inputVars = new Array(inputs.length); + const dataType = inputs[0].dataType; let previousSum = 0; for (let i = 0; i < inputs.length; ++i) { previousSum += inputs[i].dims[adjustedAxis]; sizeInConcatAxis[i] = previousSum; - inputStorageBuffersDeclarations[i] = - `@group(0) @binding(${i}) var input${i} : array<${dataType}>;`; - - inputIndicesHelpers[i] = createIndicesHelper(`input${i}`, inputs[i].dims); + inputVars[i] = inputVariable(`input${i}`, dataType, inputs[i].dims); } - const outputIndicesHelper = createIndicesHelper('output', outputShape); + const output = outputVariable('output', dataType, outputShape); - const indicesAxis = rank < 2 ? 'indices' : `indices[${adjustedAxis}]`; + const indicesAxis = output.indicesGet('indices', adjustedAxis); const getShaderSource = (shaderHelper: ShaderHelper) => ` - - ${inputStorageBuffersDeclarations.join('\n')} - @group(0) @binding(${inputs.length}) var output : array<${dataType}>; - - ${inputIndicesHelpers.map(i => i.i2oImpl).join('\n')} - ${outputIndicesHelper.o2iImpl} + ${shaderHelper.declareVariables(...inputVars, output)} const sizeInConcatAxis = array(${sizeInConcatAxis.map(i => `${i}u`).join(',')}); ${calculateInputIndexImpl(sizeInConcatAxis.length)} - ${readBufferDataImpl(inputIndicesHelpers, rank, dataType)} ${shaderHelper.mainStart()} ${shaderHelper.guardAgainstOutOfBoundsWorkgroupSizes(outputSize)} - ${outputIndicesHelper.indicesVariableDeclaration('indices')} - ${outputIndicesHelper.o2iCall('global_idx', 'indices')} + var indices = ${output.offsetToIndices('global_idx')}; - let textureIndex = calculateInputIndex(${indicesAxis}); - if (textureIndex != 0u) { - ${indicesAxis} -= sizeInConcatAxis[textureIndex - 1u]; + let inputIndex = calculateInputIndex(${indicesAxis}); + if (inputIndex != 0u) { + ${indicesAxis} -= sizeInConcatAxis[inputIndex - 1u]; } - output[global_idx] = readBufferData(textureIndex, &indices); + ${assignOutputData(inputVars, output)} }`; return { ...metadata, @@ -155,3 +142,6 @@ export const concat = (context: ComputeContext, attributes: ConcatAttributes): v validateInputs(context.inputs); context.compute(createConcatProgramInfoLoader(context.inputs, attributes)); }; + +export const parseConcatAttributes = (attributes: Record): ConcatAttributes => + createAttributeWithCacheKey({axis: attributes.axis as number}); diff --git a/js/web/lib/wasm/jsep/webgpu/ops/conv-grouped.ts b/js/web/lib/wasm/jsep/webgpu/ops/conv-grouped.ts index ebf305a129ce9..1b7b7e0b29a25 100644 --- a/js/web/lib/wasm/jsep/webgpu/ops/conv-grouped.ts +++ b/js/web/lib/wasm/jsep/webgpu/ops/conv-grouped.ts @@ -1,11 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import {TensorView} from '../../tensor'; +import {TensorView} from '../../tensor-view'; import {ShapeUtil} from '../../util'; import {GpuDataType, ProgramInfo, ProgramInfoLoader, ProgramMetadata} from '../types'; -import {createIndicesHelper, ShaderHelper} from './common'; +import {inputVariable, outputVariable, ShaderHelper} from './common'; import {calculateOutputShape, ConvAttributes} from './conv'; import {getActicationSnippet} from './fuse-utils'; @@ -25,48 +25,40 @@ const createGroupedConvProgramInfo = const wShape = inputs[1].dims; const outputChannelsPerGroup = wShape[0] / attributes.group; - const dataType = 'f32'; // TODO: support other data type const {activationFunction, applyActivation} = getActicationSnippet(attributes); - const inputStorageBuffersDeclarations = [ - `@group(0) @binding(0) var x : array<${dataType}>;`, - `@group(0) @binding(1) var w : array<${dataType}>;` - ]; - if (hasBias) { - inputStorageBuffersDeclarations.push(`@group(0) @binding(2) var b : array<${dataType}>;`); - } const isChannelLast = attributes.format === 'NHWC'; const outputShape = calculateOutputShape( xShape, wShape, attributes.dilations, attributes.pads, attributes.strides, isChannelLast); const outputSize = ShapeUtil.size(outputShape); - const outputIndicesHelper = createIndicesHelper('output', outputShape); - const xIndicesHelper = createIndicesHelper('x', xShape); - const wIndicesHelper = createIndicesHelper('w', wShape); + + const output = outputVariable('output', inputs[0].dataType, outputShape); + const x = inputVariable('x', inputs[0].dataType, xShape); + const w = inputVariable('w', inputs[1].dataType, wShape); + const inputVars = [x, w]; + if (hasBias) { + inputVars.push(inputVariable('b', inputs[2].dataType, inputs[2].dims)); + } const getShaderSource = (shaderHelper: ShaderHelper) => ` const strides: vec2 = vec2(${attributes.strides[0]}u, ${attributes.strides[1]}u); const pads: vec2 = vec2(${attributes.pads[0]}u, ${attributes.pads[1]}u); - ${inputStorageBuffersDeclarations.join('\n')} - @group(0) @binding(${inputStorageBuffersDeclarations.length}) var output : array<${dataType}>; + ${shaderHelper.declareVariables(...inputVars, output)} ${activationFunction} - ${outputIndicesHelper.o2iImpl} - ${xIndicesHelper.i2oImpl} - ${wIndicesHelper.i2oImpl} ${shaderHelper.mainStart()} ${shaderHelper.guardAgainstOutOfBoundsWorkgroupSizes(outputSize)} - ${outputIndicesHelper.indicesVariableDeclaration('outputIndices')} - ${outputIndicesHelper.o2iCall('global_idx', 'outputIndices')} + let outputIndices = ${output.offsetToIndices('global_idx')}; let batch: u32 = outputIndices[0]; let output_channel: u32 = outputIndices[${isChannelLast ? 3 : 1}]; let xRCCorner: vec2 = vec2(outputIndices[${isChannelLast ? 1 : 2}], outputIndices[${ isChannelLast ? 2 : 3}]) * strides - pads; let group_id: u32 = output_channel / ${outputChannelsPerGroup}u; - var value: ${dataType} = ${dataType}(0); + var value: ${output.type.value} = ${output.type.value}(0); for (var wInChannel: u32 = 0u; wInChannel < ${wShape[1]}u; wInChannel++) { let input_channel = group_id * ${wShape[1]}u + wInChannel; for (var wHeight: u32 = 0u; wHeight < ${wShape[2]}u; wHeight++) { @@ -82,26 +74,17 @@ const createGroupedConvProgramInfo = continue; } - ${ - xIndicesHelper.indicesVariableDeclaration( - 'xIndices', - isChannelLast ? ['batch', 'xHeight', 'xWidth', 'input_channel'] : - [ - 'batch', 'input_channel', 'xHeight', 'xWidth' - ])} - let xVal = x[${xIndicesHelper.i2oExpression('xIndices')}]; - ${ - wIndicesHelper.indicesVariableDeclaration('wIndices', [ - 'output_channel', 'wInChannel', 'wHeight', 'wWidth' - ])} - let wVal = w[${wIndicesHelper.i2oExpression('wIndices')}]; + let xVal = ${ + isChannelLast ? x.get('batch', 'xHeight', 'xWidth', 'input_channel') : + x.get('batch', 'input_channel', 'xHeight', 'xWidth')}; + let wVal = ${w.get('output_channel', 'wInChannel', 'wHeight', 'wWidth')}; value += xVal*wVal; } } } ${processBias} ${applyActivation} - output[global_idx] = value; + ${output.setByOffset('global_idx', 'value')} }`; return { ...metadata, diff --git a/js/web/lib/wasm/jsep/webgpu/ops/conv-transpose.ts b/js/web/lib/wasm/jsep/webgpu/ops/conv-transpose.ts new file mode 100644 index 0000000000000..e7d1ddf771650 --- /dev/null +++ b/js/web/lib/wasm/jsep/webgpu/ops/conv-transpose.ts @@ -0,0 +1,287 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import {DataType} from '../../../wasm-common'; +import {TensorView} from '../../tensor-view'; +import {createAttributeWithCacheKey} from '../attribute-with-cache-key'; +import {ComputeContext, GpuDataType, ProgramInfoLoader, ProgramMetadata} from '../types'; + +import {createConvTranspose2DProgramInfo} from './3rd-party/conv_backprop_webgpu'; +import {ConvAttributes} from './conv'; +import {parseInternalActivationAttributes} from './fuse-utils'; + +const computeTotalPad = + (inDim: number, stride: number, adj: number, kernel: number, dilation: number, outSize: number) => + (inDim - 1) * stride + adj + (kernel - 1) * dilation + 1 - outSize; + +const distributePadding = (totalPad: number, autoPad: string, pads: number[], head: number, tail: number) => { + const smallPad = Math.floor(totalPad / 2); + if (autoPad === 'SAME_UPPER') { + pads[head] = smallPad; + pads[tail] = totalPad - smallPad; + } else if (autoPad === 'SAME_LOWER') { + pads[head] = totalPad - smallPad; + pads[tail] = smallPad; + } +}; + +const calculateOutputShapeAndPads = + (inputShape: readonly number[], kernelShape: readonly number[], dilations: readonly number[], autoPad: string, + group: number, pads: number[], strides: readonly number[], isChannelLast: boolean, outputPadding: number[], + outputShape: number[]) => { + const spatialRank = inputShape.length - 2; + const updateOutputShape = outputShape.length === 0; + if (outputPadding.length === 0) { + for (let i = 0; i < spatialRank; ++i) { + outputPadding.push(0); + } + } + const batchSize = inputShape[0]; + const outChannels = kernelShape[isChannelLast ? 3 : 1] * group; + for (let i = 0, j = inputShape.length - spatialRank - (isChannelLast ? 1 : 0); i < spatialRank; ++i, ++j) { + const inSize = inputShape[j]; + const outSize = updateOutputShape ? inSize * strides[i] : outputShape[i]; + const totalPad = computeTotalPad(inSize, strides[i], pads[i], kernelShape[j], dilations[i], outSize); + distributePadding(totalPad, autoPad, pads, i, i + spatialRank); + if (updateOutputShape) { + outputShape.push( + strides[i] * (inSize - 1) + outputPadding[i] + (kernelShape[j] - 1) * dilations[i] + 1 - pads[i] - + pads[i + spatialRank]); + } + } + outputShape.splice(0, 0, batchSize); + outputShape.splice(isChannelLast ? 3 : 1, 0, outChannels); + }; + +export interface ConvTransposeAttributes extends ConvAttributes { + readonly outputPadding: readonly number[]; + readonly outputShape: readonly number[]; +} + + +const getAdjustedConvTransposeAttributes = + (attributes: T, inputs: readonly TensorView[]): T => { + const kernelShape = attributes.kernelShape.slice(); + // if kernelShape is not specified in the attributes of this op, infer it from the weight tensor dims + if (attributes.kernelShape.length === 0 || attributes.kernelShape.reduce((a, b) => a * b, 0) === 0) { + kernelShape.length = 0; + for (let i = 2; i < inputs[1].dims.length; ++i) { + kernelShape.push(inputs[1].dims[i]); + } + } + const isChannelsLast = attributes.format === 'NHWC'; + kernelShape.splice(0, 0, inputs[1].dims[0]); + kernelShape.splice(isChannelsLast ? 3 : 1, 0, inputs[1].dims[1]); + + const pads = attributes.pads.slice(); + const outputShape = attributes.outputShape.slice(); + const outputPadding = attributes.outputPadding.slice(); + const inputShape = inputs[0].dims; + let dilations = attributes.dilations.slice(); + if (dilations.reduce((a, b) => a + b, 0) === 0) { + const spatialRank = inputs[0].dims.length - 2; + dilations = new Array(spatialRank).fill(1); + } + let strides = attributes.strides.slice(); + if (strides.reduce((a, b) => a + b, 0) === 0) { + const spatialRank = inputs[0].dims.length - 2; + strides = new Array(spatialRank).fill(1); + } + // If outputShape is not specified in the attributes of this op, infer it from the parameters + // Similarly, automatically infer pads if not specified + calculateOutputShapeAndPads( + inputShape, kernelShape, dilations, attributes.autoPad, attributes.group, pads, strides, isChannelsLast, + outputPadding, outputShape); + + // always return a new object so does not modify the original attributes + const newAttributes: T = Object.assign({}, attributes); + Object.assign( + newAttributes, + {kernelShape, pads, outputPadding, outputShape, dilations, strides, cacheKey: attributes.cacheKey}); + return newAttributes; + }; + +export const parseConvTransposeAttributes = (attributes: Record): ConvTransposeAttributes => { + const activationAttributes = parseInternalActivationAttributes(attributes); + // TODO : Make this generic enough to compute default attributes for multi-dimensional conv + const format = attributes.format as 'NHWC' | 'NCHW'; + const autoPad = + ['NOTSET', 'VALID', 'SAME_UPPER', + 'SAME_LOWER'][typeof attributes.autoPad == 'undefined' ? 0 : attributes.autoPad as number]; + const dilations = attributes.dilations as [number, number]; + const group = attributes.group as number; + const kernelShape = attributes.kernelShape as [number, number]; + const pads = attributes.pads as [number, number, number, number]; + const strides = attributes.strides as [number, number]; + const wIsConst = (attributes.wIsConst as () => boolean)(); + const outputPadding = attributes.outputPadding as [number, number, number, number]; + const outputShape = attributes.outputShape as [number, number]; + return createAttributeWithCacheKey({ + autoPad, + format, + dilations, + group, + kernelShape, + outputPadding, + outputShape, + pads, + strides, + wIsConst, + ...activationAttributes + }); +}; + +const validateInputs = (inputs: readonly TensorView[], attributes: ConvTransposeAttributes): void => { + // Refer to the below link for all input checks + // https://github.com/onnx/onnx/blob/main/docs/Operators.md#ConvTranspose + if (!inputs || (inputs.length !== 2 && inputs.length !== 3)) { + throw new Error('Conv requires 2 or 3 inputs'); + } + + // TODO : Need to add support for multi-dimensional conv + if (inputs[0].dims.length !== 4 && inputs[0].dims.length !== 3) { + throw new Error('currently only support 2-dimensional conv'); + } + + if (inputs[0].dims.length !== inputs[1].dims.length) { + throw new Error('filter does not have same dimension as input'); + } + + // FILTER_IN_CHANNEL should be equal to DATA_CHANNEL + const dataChannel = inputs[0].dims[attributes.format === 'NHWC' ? inputs[0].dims.length - 1 : 1]; + const filterInChannel = inputs[1].dims[0]; + if (dataChannel !== filterInChannel) { + throw new Error('FILTER_IN_CHANNEL should be equal to DATA_CHANNEL'); + } + + const featureMaps = inputs[1].dims[1] * attributes.group; + + // if bias is provided it should be 1D and the number of elements should be equal to the number of feature maps + if (inputs.length === 3 && (inputs[2].dims.length !== 1 || inputs[2].dims[0] !== featureMaps)) { + throw new Error('invalid bias'); + } + + const spatialRank = inputs[0].dims.length - 2; + const dilationsSet = attributes.dilations.reduce((a, b) => a + b, 0) > 0; + // wrong dilations dimension + if (dilationsSet && attributes.dilations.length !== spatialRank) { + throw new Error(`dilations should be ${spatialRank}D`); + } + + const stridesSet = attributes.strides.reduce((a, b) => a + b, 0) > 0; + // Wrong strides dimension + if (stridesSet && attributes.strides.length !== spatialRank) { + throw new Error(`strides should be ${spatialRank}D`); + } + + // Wrong pads dimension + const padsSet = attributes.pads.reduce((a, b) => a + b, 0) > 0; + if (padsSet && attributes.pads.length !== spatialRank * 2) { + throw new Error(`pads should be ${spatialRank * 2}D`); + } + + // Wrong output padding dimension + if (attributes.outputPadding.length !== spatialRank && attributes.outputPadding.length !== 0) { + throw new Error(`output_padding should be ${spatialRank}D`); + } + + // if kernelShape is specified, it's data length must be 2 less than dims length of the weights tensor + // (the first 2 dims are batch_size and channels) + const kernelShapeSet = attributes.kernelShape.reduce((a, b) => a + b, 0) > 0; + if (kernelShapeSet && attributes.kernelShape.length !== 0 && + attributes.kernelShape.length !== inputs[1].dims.length - 2) { + throw new Error('invalid kernel shape'); + } + + // as with kernelShape, must have same number of spatial dims as input + if (attributes.outputShape.length !== 0 && attributes.outputShape.length !== inputs[0].dims.length - 2) { + throw new Error('invalid output shape'); + } + + // TODO : Need to add support for float64 + if (inputs[0].dataType !== DataType.float || inputs[1].dataType !== DataType.float) { + throw new Error('ConvTranspose input(X,W) should be float tensor'); + } + + if (inputs.length === 3 && inputs[2].dataType !== DataType.float) { + throw new Error('ConvTranspose input(bias) should be float tensor'); + } +}; + +const createConvTranspose2DProgramMetadata = (hasBias: boolean, cacheHint: string): ProgramMetadata => ({ + name: 'ConvTranspose2D', + inputTypes: hasBias ? [GpuDataType.default, GpuDataType.default, GpuDataType.default] : + [GpuDataType.default, GpuDataType.default], + cacheHint +}); + +const createConvTranspose2DProgramInfoLoader = + (inputs: readonly TensorView[], attributes: ConvTransposeAttributes, + squeezeOutputShapeFunction?: (shape: readonly number[]) => number[]): ProgramInfoLoader => { + const hasBias = inputs.length === 3; + const metadata = createConvTranspose2DProgramMetadata(hasBias, attributes.cacheKey); + return { + ...metadata, + get: () => createConvTranspose2DProgramInfo(inputs, metadata, attributes, squeezeOutputShapeFunction) + }; + }; + +const convTranspose2d = + (context: ComputeContext, inputs: readonly TensorView[], attributes: ConvTransposeAttributes): void => { + const adjustedAttributes = getAdjustedConvTransposeAttributes(attributes, inputs); + + context.compute(createConvTranspose2DProgramInfoLoader(inputs, adjustedAttributes)); + }; +const convTranspose1d = (context: ComputeContext, attributes: ConvTransposeAttributes): void => { + // extend the input to 2D by adding H dimension + const isChannelLast = attributes.format === 'NHWC'; + + const inputs = [ + context.inputs[0].reshape( + isChannelLast ? + // [N, W, C] -> [N, H=1, W, C] + [context.inputs[0].dims[0], 1, context.inputs[0].dims[1], context.inputs[0].dims[2]] : + // [N, C, W] -> [N, C, H=1, W] + [context.inputs[0].dims[0], context.inputs[0].dims[1], 1, context.inputs[0].dims[2]]), + //[FILTER_OUT_CHANNEL, FILTER_IN_CHANNEL, kW] -> [FILTER_OUT_CHANNEL, FILTER_IN_CHANNEL, kH=1, kW] + context.inputs[1].reshape([context.inputs[1].dims[0], context.inputs[1].dims[1], 1, context.inputs[1].dims[2]]) + ]; + if (inputs.length === 3) { + inputs.push(context.inputs[2]); + } + let kernelShape = attributes.kernelShape; + if (kernelShape.length === 0 || kernelShape[0] === 0) { + kernelShape = [context.inputs[1].dims[2]]; + } + let dilations = attributes.dilations; + if (dilations.length === 0 || dilations[0] === 0) { + dilations = [1]; + } + let strides = attributes.strides; + if (strides.length === 0 || strides[0] === 0) { + strides = [1]; + } + let pads = attributes.pads; + if (pads.length === 0) { + pads = [0, 0]; + } + pads = [0, pads[0], 0, pads[1]]; + strides = [1].concat(strides); + dilations = [1].concat(dilations); + kernelShape = [1].concat(kernelShape); + const adjustedAttributes = + getAdjustedConvTransposeAttributes({...attributes, pads, strides, dilations, kernelShape}, inputs); + context.compute(createConvTranspose2DProgramInfoLoader( + inputs, adjustedAttributes, + outputShape => isChannelLast ? [outputShape[0], outputShape[2], outputShape[3]] : + [outputShape[0], outputShape[1], outputShape[3]])); +}; + +export const convTranspose = (context: ComputeContext, attributes: ConvTransposeAttributes): void => { + validateInputs(context.inputs, attributes); + if (context.inputs[0].dims.length === 3) { + convTranspose1d(context, attributes); + } else { + convTranspose2d(context, context.inputs, attributes); + } +}; diff --git a/js/web/lib/wasm/jsep/webgpu/ops/conv.ts b/js/web/lib/wasm/jsep/webgpu/ops/conv.ts index b099dfaab3a3b..95a64e5787841 100644 --- a/js/web/lib/wasm/jsep/webgpu/ops/conv.ts +++ b/js/web/lib/wasm/jsep/webgpu/ops/conv.ts @@ -2,7 +2,7 @@ // Licensed under the MIT License. import {DataType} from '../../../wasm-common'; -import {TensorView} from '../../tensor'; +import {TensorView} from '../../tensor-view'; import {PoolConvUtil} from '../../util'; import {AttributeWithCacheKey, createAttributeWithCacheKey} from '../attribute-with-cache-key'; import {ComputeContext} from '../types'; @@ -10,6 +10,7 @@ import {ComputeContext} from '../types'; import {createGroupedConvProgramInfoLoader} from './conv-grouped'; import {createConv2DMatMulProgramInfoLoader} from './conv2d-mm'; import {InternalActivationAttributes, parseInternalActivationAttributes} from './fuse-utils'; +import {createMatmulProgramInfoLoader} from './matmul'; import {createTransposeProgramInfo, TransposeAttributes, transposeProgramMetadata} from './transpose'; export const calculateOutputShape = @@ -146,6 +147,10 @@ const conv2d = (context: ComputeContext, inputs: readonly TensorView[], attribut const hasBias = inputs.length === 3; // const hasPreluActivationWeights = false; /* TODO: add support for prelu activation weights */ const isChannelsLast = attributes.format === 'NHWC'; + if (!isChannelsLast || attributes.group !== 1) { + context.compute(createGroupedConvProgramInfoLoader(inputs, adjustedAttributes)); + return; + } // const batchSize = context.inputs[0].dims[0]; const inputHeight = inputs[0].dims[isChannelsLast ? 1 : 2]; @@ -160,21 +165,38 @@ const conv2d = (context: ComputeContext, inputs: readonly TensorView[], attribut const outHeight = outputShape[isChannelsLast ? 1 : 2]; const outWidth = outputShape[isChannelsLast ? 2 : 3]; const outChannels = outputShape[isChannelsLast ? 3 : 1]; + const batch = outputShape[0]; const sameSize = isChannelsLast && weightHeight === inputHeight && weightWidth === inputWidth && attributes.autoPad === 'VALID'; if (sameSize || (weightHeight === 1 && weightWidth === 1 && attributes.dilations[0] === 1 && attributes.dilations[1] === 1 && - attributes.strides[0] === 1 && attributes.strides[1] === 1 && - (attributes.autoPad === 'SAME_UPPER' || attributes.autoPad === 'SAME_LOWER' || - attributes.autoPad === 'VALID'))) { - // TODO: implement conv2dByMatMul() - context.compute(createGroupedConvProgramInfoLoader(inputs, adjustedAttributes)); - return; - } + attributes.strides[0] === 1 && attributes.strides[1] === 1 && attributes.pads[0] === 0 && + attributes.pads[1] === 0)) { + // conv2dByMatMul + const transposedWeight = (context.kernelCustomData.wT as TensorView | undefined) ?? + context.compute( + { + ...transposeProgramMetadata, + cacheHint: weightTransposeAttribute.cacheKey, + get: () => createTransposeProgramInfo(inputs[1], weightTransposeAttribute.perm) + }, + {inputs: [1], outputs: [attributes.wIsConst ? -2 : -1]})[0]; + if (attributes.wIsConst && !context.kernelCustomData.wT) { + context.kernelCustomData.wT = transposedWeight; + } + + const matmulInputs = []; + matmulInputs.push(inputs[0].reshape([batch, inputHeight * inputWidth, inputChannels])); + matmulInputs.push(transposedWeight.reshape([1, inputChannels, outChannels])); + if (hasBias) { + matmulInputs.push(inputs[2]); + } + const matmulOutputShape = [batch, outHeight * outWidth, outChannels]; + context.compute( + createMatmulProgramInfoLoader(matmulInputs, adjustedAttributes, outputShape, matmulOutputShape), + {inputs: matmulInputs}); - if (!isChannelsLast || attributes.group !== 1) { - context.compute(createGroupedConvProgramInfoLoader(inputs, adjustedAttributes)); return; } @@ -187,7 +209,7 @@ const conv2d = (context: ComputeContext, inputs: readonly TensorView[], attribut const sequentialAccessByThreads = /* backend.adapterInfo.isIntel() */ true; // STEP.1: transpose weight - const transposedWeight = (context.customData.wT as TensorView | undefined) ?? + const transposedWeight = (context.kernelCustomData.wT as TensorView | undefined) ?? context.compute( { ...transposeProgramMetadata, @@ -195,8 +217,8 @@ const conv2d = (context: ComputeContext, inputs: readonly TensorView[], attribut get: () => createTransposeProgramInfo(inputs[1], weightTransposeAttribute.perm) }, {inputs: [1], outputs: [attributes.wIsConst ? -2 : -1]})[0]; - if (attributes.wIsConst && !context.customData.wT) { - context.customData.wT = transposedWeight; + if (attributes.wIsConst && !context.kernelCustomData.wT) { + context.kernelCustomData.wT = transposedWeight; } // STEP.2: prepare reshaped inputs diff --git a/js/web/lib/wasm/jsep/webgpu/ops/conv2d-mm.ts b/js/web/lib/wasm/jsep/webgpu/ops/conv2d-mm.ts index 0abece9559630..21c0b97042fbb 100644 --- a/js/web/lib/wasm/jsep/webgpu/ops/conv2d-mm.ts +++ b/js/web/lib/wasm/jsep/webgpu/ops/conv2d-mm.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import {TensorView} from '../../tensor'; +import {TensorView} from '../../tensor-view'; import {GpuDataType, ProgramInfoLoader, ProgramMetadata} from '../types'; import {createConv2DMatMulProgramInfo} from './3rd-party/conv2d_mm_webgpu'; diff --git a/js/web/lib/wasm/jsep/webgpu/ops/einsum.ts b/js/web/lib/wasm/jsep/webgpu/ops/einsum.ts new file mode 100644 index 0000000000000..fc9ebf004ad25 --- /dev/null +++ b/js/web/lib/wasm/jsep/webgpu/ops/einsum.ts @@ -0,0 +1,290 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import {TensorView} from '../../tensor-view'; +import {ShapeUtil} from '../../util'; +import {AttributeWithCacheKey, createAttributeWithCacheKey} from '../attribute-with-cache-key'; +import {ComputeContext, GpuDataType, ProgramInfo, ProgramInfoLoader, ProgramMetadata} from '../types'; + +import {IndicesHelper, inputVariable, outputVariable, ShaderHelper} from './common'; + +export interface EinsumAttributes extends AttributeWithCacheKey { + readonly equation: string; +} +// The equation attribute value is a string which consists of left hand side (LHS) and optionally right hand side (RHS) +// separated by '->'. Ex. "ij,jk -> ik" expresses matrix multiplication +// "ij->ji" expresses matrix transpose +// "ii->i" diagonal elements of a square matrix +// LHS consists of a sequence of terms separated by commas. Each term corresponds to an input variable. +// Each symbol corresponds to a dimension in the input variable. The symbol can be either a letter, 'a' to 'z' or 'A' to +// 'Z' or '...' to represent arbitrary dimensions. + +const symbolPattern = + '[a-zA-Z]|\\.\\.\\.'; // The pattern each symbol in each term in the symbolic equation should match +const termPattern = '(' + symbolPattern + ')+'; // The pattern each term in the symbolic equation should match +const termPatternOnly = '^' + termPattern + '$'; // The patterns only matchs a term begin to end. +const lhsPattern = '(' + termPattern + ',)*' + termPattern; // The pattern the LHS should match +const lhsPatternOnly = '^' + lhsPattern + '$'; // The patterns only matchs a LHS begin to end. + +interface SymbolInfo { + count: number; // Symbol corresponding to a dimmension of an input + inputIndices: number[]; // Number of input variables the symbol corresponds to + dimValue: number; // Number of dimensions the symbol corresponds to +} + +class EinsumTerm { + constructor(inputIndex = -1) { + this.symbolToIndices = new Map(); + this.inputIndex = inputIndex; + } + + // Add a symbol to the term + addSymbol(symbol: string, index: number) { + let value = this.symbolToIndices.get(symbol); + if (value === undefined) { + value = [index]; + } else { + value.push(index); + } + this.symbolToIndices.set(symbol, value); + } + + symbolToIndices: Map; // Map from symbol to dimensions of the input corresponding to the term + inputIndex: number; // -1 for output and 0, 1, 2, ... for inputs +} + +class EinsumEquation { + constructor(inputs: readonly TensorView[], equation: string) { + this.hasEllipsis = false; + this.symbolToInfo = new Map(); + this.lhs = new Array(); + this.outputDims = []; + // As rhs needs to be updated allow using let instead of const for both lhs and rhs. + // eslint-disable-next-line prefer-const + let [lhs, rhs] = equation.includes('->') ? equation.split('->', 2) : [equation, '']; + if (!lhs.match(RegExp(lhsPatternOnly))) { + throw new Error('Invalid LHS term'); + } + const inputTerms = lhs.split(','); + inputTerms.forEach((inputTerm, index) => { + const dims = inputs[index].dims.slice(); + if (!inputTerm.match(RegExp(termPatternOnly))) { + throw new Error('Invalid LHS term'); + } + const einsumTerm = this.processTerm(inputTerm, true, dims, index); + this.lhs.push(einsumTerm); + }); + + // Initialize the RHS if not specified + if (rhs === '') { + // Construct RHS from LHS terms/symbols + rhs += [...this.symbolToInfo.entries()] + .filter(([sym, info]) => (info.count === 1 || sym === '...')) + .map(([sym]) => sym) + .join(''); + } else { + if (!rhs.match(RegExp(termPattern))) { + throw new Error('Invalid RHS'); + } + } + + // Compute output dims + const rhsSymbols = rhs.match(RegExp(symbolPattern, 'g')); + rhsSymbols?.forEach((symbol) => { + if (symbol === '...') { + this.outputDims = this.outputDims.concat(this.ellipsisDims); + } else { + const info = this.symbolToInfo.get(symbol); + if (info === undefined) { + throw new Error('Invalid RHS symbol'); + } + this.outputDims.push(info.dimValue); + } + }); + this.rhs = this.processTerm(rhs, true, this.outputDims); + } // End of EinsumEqation constructor + + // Add a symbol to the equation + addSymbol(symbol: string, dimValue: number, inputIndex: number) { + let info = this.symbolToInfo.get(symbol); + if (info !== undefined) { + if (info.dimValue !== dimValue && info.count !== 1) { + throw new Error('Dimension mismatch'); + } else { + info.count++; + info.inputIndices.push(inputIndex); + } + } else { + info = {count: 1, dimValue, inputIndices: [inputIndex]}; + } + this.symbolToInfo.set(symbol, info); + } + + // Process one input/output term + processTerm(term: string, isInput: boolean, dims: readonly number[], index = -1): EinsumTerm { + const rank = dims.length; + let ellipsis = false; + let ellipsisDims = []; + let nextDim = 0; + // For output empty string is allowed because the output may be reduced to a scalar value + if (!term.match(RegExp(termPatternOnly)) && (!isInput && term !== '')) { + throw new Error('Invalid LHS term'); + } + const indexSymbols = term.match(RegExp(symbolPattern, 'g')); + const einsumTerm = new EinsumTerm(index); + // symbol can be either a lettre, 'a' to 'z' or 'A' to 'Z', or '...' + indexSymbols?.forEach((symbol: string, i: number) => { + if (symbol === '...') { + if (ellipsis) { + throw new Error('Only one ellipsis is allowed per input term'); + } + ellipsis = true; + const ellipsisDimLength = rank - indexSymbols.length + 1; + if (ellipsisDimLength < 0) { + throw new Error('Ellipsis out of bounds'); + } + ellipsisDims = dims.slice(nextDim, nextDim + ellipsisDimLength); + if (this.hasEllipsis) { + if (this.ellipsisDims.length !== ellipsisDims.length || + this.ellipsisDims.toString() !== ellipsisDims.toString()) { + throw new Error('Ellipsis dimensions mismatch'); + } + } else if (isInput) { + this.hasEllipsis = true; + this.ellipsisDims = ellipsisDims; + } else { + throw new Error('Ellipsis must be specified in the LHS'); + } + // Add '0', '1', '2', '3', '4', etc to represent ellipsis dimensions to avoid special handling + for (let j = 0; j < ellipsisDims.length; j++) { + const symbol = String.fromCharCode('0'.charCodeAt(0) + i); + einsumTerm.addSymbol(symbol, i + j); + this.addSymbol(symbol, dims[nextDim++], index); + } + } else { + einsumTerm.addSymbol(symbol, i); + this.addSymbol(symbol, dims[nextDim++], index); + } + }); + return einsumTerm; + } + + symbolToInfo: Map; // All symbols in the equation + hasEllipsis: boolean; // The equation has ellipsis or not + ellipsisDims: number[]; // The dimensions of the equation ellipsis corresponds to. + lhs: EinsumTerm[]; // Terms on the left-hand side of the equation + rhs: EinsumTerm; // Term on the right-hand side of the equation + outputDims: number[]; // Output dimensions of the equation +} // End of class EinsumEquation + + +const createEinsumProgramMetadata = (inputCount: number, cacheHint: string): ProgramMetadata => + ({name: 'Einsum', inputTypes: Array(inputCount).fill(GpuDataType.default), cacheHint}); + +const createEinsumProgramInfo = + (metadata: ProgramMetadata, inputs: readonly TensorView[], einsumEquation: EinsumEquation): ProgramInfo => { + const dataType = inputs[0].dataType; + const inputVars = new Array(inputs.length); + for (let i = 0; i < inputs.length; ++i) { + inputVars[i] = inputVariable(`input${i}`, dataType, inputs[i].dims); + } + const outputShape = einsumEquation.outputDims; + const outputSize = ShapeUtil.size(outputShape); + const output = outputVariable('output', dataType, outputShape); + const idxCopy: string[] = []; + const rhsSymbols = Array.from(einsumEquation.rhs.symbolToIndices.keys()); + const initProd = 'var prod = 1.0;'; + const initSum = 'var sum = 0.0;'; + const updateSum = 'sum += prod;'; + const reduceOpsSetIndices: string[] = []; + const reduceOpsLoopHeaders: string[] = []; + const reduceOpsLoopFooters: string[] = []; + const reduceOpCompute: string[] = []; + const isReduceOpsWithoutLoop = einsumEquation.symbolToInfo.size === rhsSymbols.length; + einsumEquation.symbolToInfo.forEach((info, symbol) => { + if (rhsSymbols.includes(symbol)) { + const outputIndex = rhsSymbols.indexOf(symbol); + einsumEquation.lhs.forEach((term, i) => { + if (info.inputIndices.includes(i)) { + const indices = term.symbolToIndices.get(symbol); + if (indices === undefined) { + throw new Error('Invalid symbol error'); + } + indices.forEach((index) => { + idxCopy.push(`${ + inputVars[i].indicesSet( + `input${i}Indices`, index, output.indicesGet('outputIndices', outputIndex))}`); + }); + } + }); + } else { + einsumEquation.lhs.forEach((term, i) => { + const info = einsumEquation.symbolToInfo.get(symbol); + if (info === undefined) { + throw new Error('Invalid symbol error'); + } + if (info.inputIndices.includes(i)) { + const indices = term.symbolToIndices.get(symbol); + if (indices === undefined) { + throw new Error('Invalid symbol error'); + } + indices.forEach((index) => { + reduceOpsSetIndices.push(`${inputVars[i].indicesSet(`input${i}Indices`, index, `${symbol}`)}`); + }); + reduceOpCompute.push(`prod *= ${inputVars[i].getByIndices(`input${i}Indices`)};`); + } + }); + reduceOpsLoopHeaders.push(`for(var ${symbol}: u32 = 0; ${symbol} < ${ + einsumEquation.symbolToInfo.get(symbol)?.dimValue}; ${symbol}++) {`); + reduceOpsLoopFooters.push('}'); + } + }); + const reduceOps = isReduceOpsWithoutLoop ? + [ + ...idxCopy, + `let sum = ${inputVars.map((inputVar, i) => inputVar.getByIndices(`input${i}Indices`)).join(' * ')};` + ] : + [ + ...idxCopy, + initSum, + ...reduceOpsLoopHeaders, + ...reduceOpsSetIndices, + initProd, + ...reduceOpCompute, + updateSum, + ...reduceOpsLoopFooters, + ]; + const getShaderSource = (shaderHelper: ShaderHelper) => ` + ${shaderHelper.declareVariables(...inputVars, output)} + + ${shaderHelper.mainStart()} + ${shaderHelper.guardAgainstOutOfBoundsWorkgroupSizes(outputSize)} + var outputIndices = ${output.offsetToIndices('global_idx')}; + ${inputVars.map((inputVar, i) => `var input${i}Indices: ${inputVars[i].type.indices};`).join('\n')} + ${reduceOps.join('\n')}; + ${output.setByOffset('global_idx', 'sum')}; + }`; + return { + ...metadata, + outputs: [{dims: outputShape, dataType: inputs[0].dataType, gpuDataType: GpuDataType.default}], + getShaderSource, + dispatchGroup: () => ({x: Math.ceil(outputSize / 64 /* workgroup size */)}) + }; + }; + +const createEinsumProgramInfoLoader = + (inputs: readonly TensorView[], einsumEquation: EinsumEquation, attributes: EinsumAttributes): + ProgramInfoLoader => { + const metadata = createEinsumProgramMetadata(inputs.length, attributes.cacheKey); + return {...metadata, get: () => createEinsumProgramInfo(metadata, inputs, einsumEquation)}; + }; + +export const einsum = (context: ComputeContext, attributes: EinsumAttributes): void => { + const einsumEquation = new EinsumEquation(context.inputs, attributes.equation); + context.compute(createEinsumProgramInfoLoader(context.inputs, einsumEquation, attributes)); +}; + +export const parseEinsumAttributes = (attributes: Record): EinsumAttributes => { + const equation = (attributes.equation as string).replace(/\s+/g, ''); + return createAttributeWithCacheKey({equation}); +}; diff --git a/js/web/lib/wasm/jsep/webgpu/ops/expand.ts b/js/web/lib/wasm/jsep/webgpu/ops/expand.ts new file mode 100644 index 0000000000000..824ce682c0c4b --- /dev/null +++ b/js/web/lib/wasm/jsep/webgpu/ops/expand.ts @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import {TensorView} from '../../tensor-view'; +import {ShapeUtil} from '../../util'; +import {ComputeContext, GpuDataType, ProgramInfo, ProgramMetadata} from '../types'; + +import {inputVariable, outputVariable, ShaderHelper} from './common'; + +export const expandProgramMetadata = { + name: 'Expand', + inputTypes: [GpuDataType.default] +}; + +const validateInputs = (inputs: readonly TensorView[]): void => { + if (!inputs || inputs.length !== 2) { + throw new Error('Expand requires 2 input.'); + } + const inputShape = inputs[0].dims; + const shape = Array.from(inputs[1].getBigInt64Array(), Number); + + let shapeIndex = shape.length < inputShape.length ? 0 : shape.length - inputShape.length; + let inputShapeIndex = inputShape.length < shape.length ? 0 : inputShape.length - shape.length; + for (; shapeIndex < shape.length && inputShapeIndex < inputShape.length; ++shapeIndex, ++inputShapeIndex) { + if (shape[shapeIndex] !== inputShape[inputShapeIndex] && shape[shapeIndex] !== 1 && + inputShape[inputShapeIndex] !== 1) { + throw new Error('Expand requires shape to be broadcastable to input'); + } + } +}; + +const getAdjustedShape = (shape1: readonly number[], shape2: readonly number[]): number[] => { + const diff = shape1.length - shape2.length; + const shape: number[] = []; + for (let i = 0; i < diff; ++i) { + shape.push(shape1[i]); + } + for (let i = 0; i < shape2.length; ++i) { + shape.push(shape2[i] === 1 ? shape1[i + diff] : shape2[i]); + } + return shape; +}; + +const calculateOutputShape = (inputShape: readonly number[], shape: readonly number[]): number[] => + (inputShape.length > shape.length) ? getAdjustedShape(inputShape, shape) : getAdjustedShape(shape, inputShape); + + +const createExpandProgramInfo = (metadata: ProgramMetadata, inputs: readonly TensorView[]): ProgramInfo => { + const inputShape = inputs[0].dims; + const shape = Array.from(inputs[1].getBigInt64Array(), Number); + const outputShape: number[] = calculateOutputShape(inputShape, shape); + const outputSize = ShapeUtil.size(outputShape); + + const dataType = inputs[0].dataType; + const input = inputVariable('input', dataType, inputShape); + const output = outputVariable('output', dataType, outputShape); + + const getShaderSource = (shaderHelper: ShaderHelper) => ` + const inputShape = ${input.indices(...inputShape)}; + ${shaderHelper.declareVariables(input, output)} + ${shaderHelper.mainStart()} + ${shaderHelper.guardAgainstOutOfBoundsWorkgroupSizes(outputSize)} + let outputIndices = ${output.offsetToIndices('global_idx')}; + var inputIndices: ${input.type.indices}; + for (var i = 0; i < ${inputShape.length}; i++) { + if (${input.indicesGet('inputShape', 'i')} == 1) { + ${input.indicesSet('inputIndices', 'i', 0)} + } else { + ${ + input.indicesSet( + 'inputIndices', 'i', output.indicesGet('outputIndices', `i + ${outputShape.length - inputShape.length}`))} + } + } + ${output.setByOffset('global_idx', input.getByIndices('inputIndices'))} + }`; + return { + ...metadata, + getShaderSource, + outputs: [{dims: outputShape, dataType: inputs[0].dataType, gpuDataType: GpuDataType.default}], + dispatchGroup: () => ({x: Math.ceil(outputSize / 64 /* workgroup size */)}) + }; +}; + +export const expand = (context: ComputeContext): void => { + validateInputs(context.inputs); + const outputShape = Array.from(context.inputs[1].getBigInt64Array(), Number); + const cacheHint = outputShape.toString(); + context.compute( + {...expandProgramMetadata, cacheHint, get: () => createExpandProgramInfo(expandProgramMetadata, context.inputs)}, + {inputs: [0]}); +}; diff --git a/js/web/lib/wasm/jsep/webgpu/ops/gather-elements.ts b/js/web/lib/wasm/jsep/webgpu/ops/gather-elements.ts new file mode 100644 index 0000000000000..a7d355bc13704 --- /dev/null +++ b/js/web/lib/wasm/jsep/webgpu/ops/gather-elements.ts @@ -0,0 +1,110 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import {TensorView} from '../../tensor-view'; +import {ShapeUtil} from '../../util'; +import {AttributeWithCacheKey, createAttributeWithCacheKey} from '../attribute-with-cache-key'; +import {ComputeContext, GpuDataType, ProgramInfo, ProgramMetadata} from '../types'; + +import {inputVariable, outputVariable, ShaderHelper} from './common'; + +export interface GatherElementsAttributes extends AttributeWithCacheKey { + axis: number; +} + +const validateInputs = (inputs: readonly TensorView[]): void => { + if (!inputs || inputs.length !== 2) { + throw new Error('GatherElements requires 2 inputs.'); + } + + if (inputs[0].dims.length < 1) { + throw new Error('GatherElements requires that the data input be rank >= 1.'); + } + + if (inputs[0].dims.length !== inputs[1].dims.length) { + throw new Error(`GatherElements requires that the data input and + indices input tensors be of same rank.`); + } +}; + +const createGatherElementsProgramInfo = + (metadata: ProgramMetadata, inputs: readonly TensorView[], attributes: GatherElementsAttributes): ProgramInfo => { + const inputShape = inputs[0].dims; + const inputOutputDataType = inputs[0].dataType; + const inputRank = inputShape.length; + const inputStrides = ShapeUtil.computeStrides(inputShape); + const inputSize = ShapeUtil.size(inputShape); + + const indicesShape = inputs[1].dims; + const indicesDataType = inputs[1].dataType; + const indicesSize = ShapeUtil.size(indicesShape); + + const axis = ShapeUtil.normalizeAxis(attributes.axis, inputRank); + const axisDimLimit = inputShape[axis]; + + const outputShape = indicesShape.slice(0); + const outputSize = ShapeUtil.size(outputShape); + + const input = inputVariable('input', inputOutputDataType, inputShape); + const indices = inputVariable('indices', indicesDataType, [indicesSize]); + const output = outputVariable('output', inputOutputDataType, outputShape); + + + // int64 indices would be treated as little endian i32 with assumption they fall in i32 limits + // That assumption is safe as it's not possible to allocate >2gb buffer for input tensor + // Input data will be treated as u32 or two u32 for 8-byte tensors + const getShaderSource = (shaderHelper: ShaderHelper) => ` + const inputStrides = array(${inputStrides.map(i => `${i}u`).join(',')}); + ${shaderHelper.declareVariables(input, indices, output)} + ${shaderHelper.mainStart()} + ${shaderHelper.guardAgainstOutOfBoundsWorkgroupSizes(outputSize)} + + let outputIndices = ${output.offsetToIndices('global_idx')}; + + var idx = ${indices.getByOffset('global_idx')}; + if (idx < 0) { + idx = idx + ${axisDimLimit}; + } + + var srcOffset = u32(0); + + for (var i = 0; i < ${inputShape.length}; i++) { + if (i == ${axis}) { + srcOffset += u32(idx) * inputStrides[i]; + } else { + srcOffset += ${output.indicesGet('outputIndices', 'i')} * inputStrides[i]; + } + } + + // Should never hit this with valid values in indices + // This is a guard against malicious data in the indices input + if (srcOffset < 0 || srcOffset >= ${inputSize}) { + return; + } + + output[global_idx] = input[srcOffset]; + }`; + + return { + ...metadata, + outputs: [{dims: outputShape, dataType: inputs[0].dataType, gpuDataType: GpuDataType.default}], + getShaderSource, + dispatchGroup: () => ({x: Math.ceil(outputSize / 64 /* workgroup size */)}) + }; + }; + +export const parseGatherElementsAttributes = (attributes: Record): GatherElementsAttributes => + createAttributeWithCacheKey({axis: attributes.axis as number}); + +export const gatherElements = (context: ComputeContext, attributes: GatherElementsAttributes): void => { + const inputs = context.inputs; + validateInputs(inputs); + + const metadata = { + name: 'GatherElements', + inputTypes: [GpuDataType.default, GpuDataType.default], + cacheHint: attributes.cacheKey, + }; + + context.compute(createGatherElementsProgramInfo(metadata, context.inputs, attributes)); +}; diff --git a/js/web/lib/wasm/jsep/webgpu/ops/gather.ts b/js/web/lib/wasm/jsep/webgpu/ops/gather.ts new file mode 100644 index 0000000000000..47aae13d6799d --- /dev/null +++ b/js/web/lib/wasm/jsep/webgpu/ops/gather.ts @@ -0,0 +1,98 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import {TensorView} from '../../tensor-view'; +import {ShapeUtil} from '../../util'; +import {AttributeWithCacheKey, createAttributeWithCacheKey} from '../attribute-with-cache-key'; +import {ComputeContext, GpuDataType, ProgramInfo, ProgramMetadata} from '../types'; + +import {inputVariable, outputVariable, ShaderHelper} from './common'; + +export interface GatherAttributes extends AttributeWithCacheKey { + axis: number; +} + +const validateInputs = (inputs: readonly TensorView[]): void => { + if (!inputs || inputs.length !== 2) { + throw new Error('Gather requires 2 inputs.'); + } +}; + +const createGatherProgramInfo = + (metadata: ProgramMetadata, inputs: readonly TensorView[], attributes: GatherAttributes): ProgramInfo => { + const inputShape = inputs[0].dims; + const indicesShape = inputs[1].dims; + + const inputRank = inputShape.length; + const axis = ShapeUtil.normalizeAxis(attributes.axis, inputRank); + + const outputShape = inputShape.slice(0); + outputShape.splice(axis, 1, ...indicesShape); + + const axisDimLimit = inputShape[axis]; + const outputSize = ShapeUtil.size(outputShape); + + const data = inputVariable('data', inputs[0].dataType, inputs[0].dims); + const indices = inputVariable('inputIndices', inputs[1].dataType, inputs[1].dims); + const output = outputVariable('output', inputs[0].dataType, outputShape); + const calcDataIndices = (): string => { + const indicesRank = indicesShape.length; + let calcStr = `var indicesIndices = ${indices.type.indices}(0);`; + for (let i = 0; i < indicesRank; i++) { + calcStr += `${indicesRank > 1 ? `indicesIndices[${i}]` : 'indicesIndices'} = ${ + outputShape.length > 1 ? `outputIndices[${axis + i}]` : 'outputIndices'};`; + } + calcStr += ` + var idx = ${indices.getByIndices('indicesIndices')}; + if (idx < 0) { + idx = idx + ${axisDimLimit}; + } + var dataIndices = ${data.type.indices}(0); + `; + for (let i = 0, j = 0; i < inputRank; i++) { + if (i === axis) { + calcStr += `${inputRank > 1 ? `dataIndices[${i}]` : 'dataIndices'} = u32(idx);`; + j += indicesRank; + } else { + calcStr += `${inputRank > 1 ? `dataIndices[${i}]` : 'dataIndices'} = ${ + outputShape.length > 1 ? `outputIndices[${j}]` : 'outputIndices'};`; + j++; + } + } + return calcStr; + }; + + const getShaderSource = (shaderHelper: ShaderHelper) => ` + ${shaderHelper.declareVariables(data, indices, output)} + ${shaderHelper.mainStart()} + ${shaderHelper.guardAgainstOutOfBoundsWorkgroupSizes(outputSize)} + let outputIndices = ${output.offsetToIndices('global_idx')}; + ${calcDataIndices()}; + let value = ${data.getByIndices('dataIndices')}; + ${output.setByOffset('global_idx', 'value')}; + }`; + return { + ...metadata, + outputs: [ + {dims: outputShape, dataType: inputs[0].dataType, gpuDataType: GpuDataType.default}, + ], + getShaderSource, + dispatchGroup: () => ({x: Math.ceil(outputSize / 64 /* workgroup size */)}) + }; + }; + +export const parseGatherAttributes = (attributes: Record): GatherAttributes => + createAttributeWithCacheKey({axis: attributes.axis as number}); + +export const gather = (context: ComputeContext, attributes: GatherAttributes): void => { + const inputs = context.inputs; + validateInputs(inputs); + + const metadata = { + name: 'Gather', + inputTypes: [GpuDataType.default, GpuDataType.default], + cacheHint: attributes.cacheKey, + }; + + context.compute(createGatherProgramInfo(metadata, context.inputs, attributes)); +}; diff --git a/js/web/lib/wasm/jsep/webgpu/ops/gemm.ts b/js/web/lib/wasm/jsep/webgpu/ops/gemm.ts index 46816a2410586..1a36d4a7545d6 100644 --- a/js/web/lib/wasm/jsep/webgpu/ops/gemm.ts +++ b/js/web/lib/wasm/jsep/webgpu/ops/gemm.ts @@ -1,13 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import {DataType} from '../../../wasm-common'; -import {TensorView} from '../../tensor'; +import {TensorView} from '../../tensor-view'; import {GemmUtil, ShapeUtil} from '../../util'; import {AttributeWithCacheKey, createAttributeWithCacheKey} from '../attribute-with-cache-key'; import {ComputeContext, GpuDataType, ProgramInfo, ProgramInfoLoader, ProgramMetadata} from '../types'; -import {ShaderHelper} from './common'; +import {ShaderHelper, tensorTypeToWsglStorageType} from './common'; const validateInputs = (inputs: readonly TensorView[]): void => { if (!inputs) { @@ -22,11 +21,6 @@ const validateInputs = (inputs: readonly TensorView[]): void => { throw new Error('Invalid input shape of C'); } - if ((inputs[0].dataType !== DataType.float) || (inputs[1].dataType !== DataType.float) || - (inputs.length === 3 && inputs[2].dataType !== DataType.float)) { - throw new Error('Invalid input type.'); - } - if ((inputs[0].dataType !== inputs[1].dataType) || (inputs.length === 3 && inputs[0].dataType !== inputs[2].dataType)) { throw new Error('Input types are mismatched'); @@ -81,7 +75,7 @@ const createGemmProgramInfo = line = 'value += a[m * K + k] * b[k * N + n];'; } - const dataType = 'f32'; // TODO: support other data type + const dataType = tensorTypeToWsglStorageType(inputs[0].dataType); const calculateAlpha = attributes.alpha === 1 ? '' : 'value *= alpha;'; const calculateC = inputs.length === 3 ? `value += beta * c[${offsetC(M, N, inputs[2].dims)}];` : ''; const inputStorageBuffersDeclarations = [ diff --git a/js/web/lib/wasm/jsep/webgpu/ops/instance-norm.ts b/js/web/lib/wasm/jsep/webgpu/ops/instance-norm.ts new file mode 100644 index 0000000000000..5a148bda0a9f7 --- /dev/null +++ b/js/web/lib/wasm/jsep/webgpu/ops/instance-norm.ts @@ -0,0 +1,184 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import {TensorView} from '../../tensor-view'; +import {ShapeUtil} from '../../util'; +import {AttributeWithCacheKey, createAttributeWithCacheKey} from '../attribute-with-cache-key'; +import {ComputeContext, GpuDataType, ProgramInfo, ProgramMetadata} from '../types'; + +import {inputVariable, outputVariable, ShaderHelper, tensorTypeToWsglStorageType} from './common'; + +export interface InstanceNormAttributes extends AttributeWithCacheKey { + epsilon: number; + format: 'NHWC'|'NCHW'; +} + +const createInstanceNormProgramInfo = + (metadata: ProgramMetadata, inputs: readonly TensorView[], attributes: InstanceNormAttributes): ProgramInfo => { + const xShape = inputs[0].dims; + + const outputShape = xShape; + const axis = 2; + const normCount = ShapeUtil.sizeToDimension(xShape, axis); + const normSize = ShapeUtil.sizeFromDimension(xShape, axis); + const C = xShape[1]; + const x = inputVariable('x', inputs[0].dataType, [xShape[0], xShape[1], normSize]); + const scale = inputVariable('scale', inputs[1].dataType, inputs[1].dims); + const bias = inputVariable('bias', inputs[2].dataType, inputs[2].dims); + const output = outputVariable('output', inputs[0].dataType, [xShape[0], xShape[1], normSize]); + const variables = [x, scale, bias, output]; + const dataType = x.type.value; + const workgroupSize = 64; + const getShaderSource = (shaderHelper: ShaderHelper) => ` + + const C: u32 = ${C}; + const normSize: u32 = ${normSize}; + const epsilon: f32 = ${attributes.epsilon}; + var meanShared : ${dataType}; + var squaredNormShared : ${dataType}; + var workgroupShared : array<${dataType}, ${workgroupSize}>; + const workgroupSize = ${workgroupSize}u; + ${shaderHelper.declareVariables(...variables)} + ${shaderHelper.mainStart(workgroupSize)} + let norm = global_idx / workgroupSize; + let batch = norm / C; + let channel = norm % C; + let localIndex = local_id.x; + + // initialize workgroup memory + var initial: ${dataType} = 0; + for (var h = localIndex; h < normSize; h += workgroupSize) { + initial = initial + ${x.get('batch', 'channel', 'h')}; + } + workgroupShared[localIndex] = initial; + workgroupBarrier(); + + // Calculate the mean of current channel data. + for (var currSize = workgroupSize >> 1; currSize > 0; currSize = currSize >> 1) { + if (localIndex < currSize) { + workgroupShared[localIndex] = workgroupShared[localIndex] + workgroupShared[localIndex + currSize]; + } + workgroupBarrier(); + } + if (localIndex == 0) { + meanShared = workgroupShared[0] / ${dataType}(normSize); + } + workgroupBarrier(); + + // reinitialize workgroup memory. + initial = 0; + for (var h = localIndex; h < normSize; h += workgroupSize) { + let deviation = ${x.get('batch', 'channel', 'h')} - meanShared; + initial = initial + deviation * deviation; + } + workgroupShared[localIndex] = initial; + workgroupBarrier(); + + // Calculate the sum of square of deviation of current channel data. + for (var currSize = workgroupSize >> 1; currSize > 0; currSize = currSize >> 1) { + if (localIndex < currSize) { + workgroupShared[localIndex] = workgroupShared[localIndex] + workgroupShared[localIndex + currSize]; + } + workgroupBarrier(); + } + if (localIndex == 0) { + squaredNormShared = workgroupShared[0]; + } + workgroupBarrier(); + + let invStdDev = 1 / sqrt(squaredNormShared / ${dataType}(normSize) + epsilon); + let channelScale = invStdDev * ${scale.getByOffset('channel')}; + let channelShift = ${bias.getByOffset('channel')} - meanShared * channelScale; + for (var h = localIndex; h < normSize; h += workgroupSize) { + let value = ${x.get('batch', 'channel', 'h')} * channelScale + channelShift; + ${output.set('batch', 'channel', 'h', 'value')}; + } + }`; + return { + ...metadata, + outputs: [ + {dims: outputShape, dataType: inputs[0].dataType, gpuDataType: GpuDataType.default}, + ], + getShaderSource, + dispatchGroup: () => ({x: normCount}) + }; + }; + +const createInstanceNormNHWCProgramInfo = + (metadata: ProgramMetadata, inputs: readonly TensorView[], attributes: InstanceNormAttributes): ProgramInfo => { + const xShape = inputs[0].dims; + const outputShape = xShape; + const outputSize = ShapeUtil.size(outputShape); + const N = xShape[0]; + const C = xShape[xShape.length - 1]; + const H = ShapeUtil.sizeFromDimension(xShape, 1) / C; + + const dataType = tensorTypeToWsglStorageType(inputs[0].dataType); + + const normCount = C * N; + const getShaderSource = (shaderHelper: ShaderHelper) => ` + const N: u32 = ${N}; + const H: u32 = ${H}; + const C: u32 = ${C}; + const normSizeTyped: ${dataType} = ${H}; + const imageSize: u32 = ${H * C}; + const epsilon: f32 = ${attributes.epsilon}; + + @group(0) @binding(0) var x : array<${dataType}>; + @group(0) @binding(1) var scale : array<${dataType}>; + @group(0) @binding(2) var bias : array<${dataType}>; + @group(0) @binding(3) var output : array<${dataType}>; + + ${shaderHelper.mainStart()} + let currentImageNumber = global_idx / C; + let currentChannelNumber = global_idx % C; + + // offset is channel num * N + let offset = currentImageNumber * imageSize; + if (offset >= ${outputSize}) { return; } + var mean: ${dataType} = 0; + + for (var i: u32 = 0u; i < H; i++) { + mean = mean + x[offset + i * C + currentChannelNumber]; + } + mean = mean / normSizeTyped; + + var squaredNorm: ${dataType} = 0; + for (var i: u32 = 0u; i < H; i++) { + let deviation: f32 = x[offset + i * C + currentChannelNumber] - mean; + squaredNorm = squaredNorm + deviation * deviation; + } + let invStdDev = 1 / sqrt(squaredNorm / normSizeTyped + epsilon); + let channelScale = invStdDev * scale[currentChannelNumber]; + let channelShift = bias[currentChannelNumber] - mean * channelScale; + for (var i: u32 = 0u; i < H; i++) { + let currentOffset = offset + i * C + currentChannelNumber; + output[currentOffset] = x[currentOffset] * channelScale + channelShift; + } + }`; + return { + ...metadata, + outputs: [ + {dims: outputShape, dataType: inputs[0].dataType, gpuDataType: GpuDataType.default}, + ], + getShaderSource, + dispatchGroup: () => ({x: Math.ceil(normCount / 64 /* workgroup size */)}) + }; + }; + +export const parseInstanceNormAttributes = (attributes: InstanceNormAttributes): InstanceNormAttributes => + createAttributeWithCacheKey({epsilon: attributes.epsilon, format: attributes.format}); + +export const instanceNorm = (context: ComputeContext, attributes: InstanceNormAttributes): void => { + const metadata = { + name: 'InstanceNormalization', + inputTypes: [GpuDataType.default, GpuDataType.default, GpuDataType.default], + cacheHint: attributes.cacheKey, + }; + + if (attributes.format === 'NHWC') { + context.compute(createInstanceNormNHWCProgramInfo(metadata, context.inputs, attributes)); + } else { + context.compute(createInstanceNormProgramInfo(metadata, context.inputs, attributes)); + } +}; diff --git a/js/web/lib/wasm/jsep/webgpu/ops/layer-norm.ts b/js/web/lib/wasm/jsep/webgpu/ops/layer-norm.ts new file mode 100644 index 0000000000000..d6a79e9460c3f --- /dev/null +++ b/js/web/lib/wasm/jsep/webgpu/ops/layer-norm.ts @@ -0,0 +1,134 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import {DataType} from '../../../wasm-common'; +import {TensorView} from '../../tensor-view'; +import {ShapeUtil} from '../../util'; +import {AttributeWithCacheKey, createAttributeWithCacheKey} from '../attribute-with-cache-key'; +import {ComputeContext, GpuDataType, ProgramInfo, ProgramMetadata} from '../types'; + +import {ShaderHelper, tensorTypeToWsglStorageType} from './common'; + +export interface LayerNormAttributes extends AttributeWithCacheKey { + axis: number; + epsilon: number; +} + +const validateInputs = (inputs: readonly TensorView[]): void => { + if (!inputs || inputs.length < 2) { + throw new Error('layerNorm requires at least 2 inputs.'); + } + + if (inputs[0].dataType !== DataType.float || inputs[1].dataType !== DataType.float) { + throw new Error('inputs should be float type'); + } +}; + +const createLayerNormProgramInfo = + (metadata: ProgramMetadata, inputs: readonly TensorView[], attributes: LayerNormAttributes, outputCount: number): + ProgramInfo => { + const xShape = inputs[0].dims; + const scale = inputs[1]; + const bias = inputs[2]; + + const outputShape = xShape; + const outputSize = ShapeUtil.size(outputShape); + const axis = ShapeUtil.normalizeAxis(attributes.axis, xShape.length); + const normCount = ShapeUtil.sizeToDimension(xShape, axis); + const normSize = ShapeUtil.sizeFromDimension(xShape, axis); + + const scaleSize = ShapeUtil.size(scale.dims); + const biasSize = bias ? ShapeUtil.size(bias.dims) : 0; + if (scaleSize !== normSize || (bias && biasSize !== normSize)) { + throw new Error(`Size of X.shape()[axis:] == ${normSize}. + Size of scale and bias (if provided) must match this. + Got scale size of ${scaleSize} and bias size of ${biasSize}`); + } + + const meanInvStdDevDim = []; + for (let i = 0; i < xShape.length; ++i) { + if (i < axis) { + meanInvStdDevDim.push(xShape[i]); + } else { + meanInvStdDevDim.push(1); + } + } + + const dataType = tensorTypeToWsglStorageType(inputs[0].dataType); + + const hasMeanDataOutput = outputCount > 1; + const hasInvStdOutput = outputCount > 2; + let bindingIndex = 0; + const getShaderSource = (shaderHelper: ShaderHelper) => ` + const normSize: u32 = ${normSize}; + const normSizeTyped: ${dataType} = ${normSize}; + const epsilon: f32 = ${attributes.epsilon}; + + @group(0) @binding(${bindingIndex++}) var x : array<${dataType}>; + @group(0) @binding(${bindingIndex++}) var scale : array<${dataType}>; + ${bias ? `@group(0) @binding(${bindingIndex++}) var bias : array<${dataType}>;` : ''} + @group(0) @binding(${bindingIndex++}) var output : array<${dataType}>; + ${ + hasMeanDataOutput ? + `@group(0) @binding(${bindingIndex++}) var meanDataOutput : array<${dataType}>` : + ''}; + ${ + hasInvStdOutput ? + `@group(0) @binding(${bindingIndex++}) var invStdOutput : array<${dataType}>` : + ''}; + + ${shaderHelper.mainStart()} + let offset = global_idx * normSize; + if (offset >= ${outputSize}) { return; } + var mean: ${dataType} = 0; + var meanSquare: ${dataType} = 0; + + for (var h: u32 = 0u; h < normSize; h++) { + mean = mean + x[h + offset]; + meanSquare = meanSquare + x[h + offset] * x[h + offset]; + } + mean = mean / normSizeTyped; + meanSquare = sqrt(meanSquare / normSizeTyped - mean * mean + epsilon); + + for (var j: u32 = 0; j < normSize; j++) { + output[j + offset] = (x[j + offset] - mean) / meanSquare * scale[j] ${bias ? '+ bias[j]' : ''}; + } + + ${hasMeanDataOutput ? 'meanDataOutput[global_idx] = mean' : ''}; + ${hasInvStdOutput ? 'invStdOutput[global_idx] = 1 / meanSquare' : ''}; + }`; + const outputs = [{dims: outputShape, dataType: inputs[0].dataType, gpuDataType: GpuDataType.default}]; + if (hasMeanDataOutput) { + outputs.push( + {dims: meanInvStdDevDim, dataType: inputs[0].dataType, gpuDataType: GpuDataType.default}, + ); + } + if (hasInvStdOutput) { + outputs.push( + {dims: meanInvStdDevDim, dataType: inputs[0].dataType, gpuDataType: GpuDataType.default}, + ); + } + + return { + ...metadata, + outputs, + getShaderSource, + dispatchGroup: () => ({x: Math.ceil(normCount / 64 /* workgroup size */)}) + }; + }; + +export const parseLayerNormAttributes = (attributes: LayerNormAttributes): LayerNormAttributes => + createAttributeWithCacheKey({axis: attributes.axis, epsilon: attributes.epsilon}); + +export const layerNorm = (context: ComputeContext, attributes: LayerNormAttributes): void => { + validateInputs(context.inputs); + + const metadata = { + name: 'LayerNormalization', + inputTypes: context.inputs.length === 2 ? [GpuDataType.default, GpuDataType.default] : + [GpuDataType.default, GpuDataType.default, GpuDataType.default], + cacheHint: attributes.cacheKey + context.outputCount.toString(10) + context.inputs.length.toString(10), + }; + + context.compute(createLayerNormProgramInfo(metadata, context.inputs, attributes, context.outputCount)); +}; diff --git a/js/web/lib/wasm/jsep/webgpu/ops/matmul.ts b/js/web/lib/wasm/jsep/webgpu/ops/matmul.ts index 75191be3cf1ec..837ac8410f291 100644 --- a/js/web/lib/wasm/jsep/webgpu/ops/matmul.ts +++ b/js/web/lib/wasm/jsep/webgpu/ops/matmul.ts @@ -2,12 +2,12 @@ // Licensed under the MIT License. import {DataType} from '../../../wasm-common'; -import {TensorView} from '../../tensor'; -import {BroadcastUtil, ShapeUtil} from '../../util'; -import {ComputeContext, GpuDataType, ProgramInfo, ProgramInfoLoader, ProgramMetadata} from '../types'; +import {TensorView} from '../../tensor-view'; +import {BroadcastUtil} from '../../util'; +import {ComputeContext, GpuDataType, ProgramInfoLoader} from '../types'; -import {ShaderHelper} from './common'; -import {getActicationSnippet, InternalActivationAttributes} from './fuse-utils'; +import {createMatmulProgramInfo} from './3rd-party/matmul_packed_webgpu'; +import {InternalActivationAttributes} from './fuse-utils'; const createMatmulProgramMetadata = (hasBias: boolean, cacheHint: string) => ({ @@ -17,65 +17,14 @@ const createMatmulProgramMetadata = (hasBias: boolean, cacheHint: string) => ({ cacheHint }); -const createMatmulProgramInfo = - (metadata: ProgramMetadata, inputs: readonly TensorView[], activationAttributes: InternalActivationAttributes): - ProgramInfo => { - const aShape = inputs[0].dims; - const bShape = inputs[1].dims; - const outputShape = BroadcastUtil.calcShape(aShape, bShape, true); - if (!outputShape) { - throw new Error('Can\'t use matmul on the given tensors'); - } - const outputSize = ShapeUtil.size(outputShape); - // TODO: support broadcasting - - const dataType = 'f32'; // TODO: support other data type - const {activationFunction, applyActivation} = getActicationSnippet(activationAttributes); - - const M = outputShape[outputShape.length - 2]; - const K = aShape[aShape.length - 1]; - const N = outputShape[outputShape.length - 1]; - const getShaderSource = (shaderHelper: ShaderHelper) => ` - const M: u32 = ${M}u; - const N: u32 = ${N}u; - const K: u32 = ${K}u; - - @group(0) @binding(0) var a : array<${dataType}>; - @group(0) @binding(1) var b : array<${dataType}>; - @group(0) @binding(2) var output : array<${dataType}>; - - ${activationFunction} - - ${shaderHelper.mainStart()} - ${shaderHelper.guardAgainstOutOfBoundsWorkgroupSizes(outputSize)} - - let stack = global_idx / (M * N); - let mn = global_idx % (M * N); - let n = global_idx % N; - let m = mn / N; - - let offsetA = stack * (M * K); - let offsetB = stack * (K * N); - - var value = ${dataType}(0); - for (var k: u32 = 0u; k<${K}u; k++) { - value += a[offsetA + m * K + k] * b[offsetB + k * N + n]; - } - ${applyActivation} - output[global_idx] = value; - }`; - return { - ...metadata, - outputs: [{dims: outputShape, dataType: inputs[0].dataType, gpuDataType: GpuDataType.default}], - getShaderSource, - dispatchGroup: () => ({x: Math.ceil(outputSize / 64 /* workgroup size */)}) - }; - }; - export const createMatmulProgramInfoLoader = - (inputs: readonly TensorView[], activationAttributes: InternalActivationAttributes): ProgramInfoLoader => { + (inputs: readonly TensorView[], activationAttributes: InternalActivationAttributes, outputShape: readonly number[], + reshapedOutputShape?: readonly number[]): ProgramInfoLoader => { const metadata = createMatmulProgramMetadata(inputs.length > 2, activationAttributes.activationCacheKey); - return {...metadata, get: () => createMatmulProgramInfo(metadata, inputs, activationAttributes)}; + return { + ...metadata, + get: () => createMatmulProgramInfo(metadata, inputs, activationAttributes, outputShape, reshapedOutputShape) + }; }; const validateInputs = (inputs: readonly TensorView[]): void => { @@ -94,6 +43,9 @@ const validateInputs = (inputs: readonly TensorView[]): void => { export const matMul = (context: ComputeContext): void => { validateInputs(context.inputs); - - context.compute(createMatmulProgramInfoLoader(context.inputs, {activation: '', activationCacheKey: ''})); + const outputShape = BroadcastUtil.calcShape(context.inputs[0].dims, context.inputs[1].dims, true); + if (!outputShape) { + throw new Error('Can\'t use matmul on the given tensors'); + } + context.compute(createMatmulProgramInfoLoader(context.inputs, {activation: '', activationCacheKey: ''}, outputShape)); }; diff --git a/js/web/lib/wasm/jsep/webgpu/ops/pad.ts b/js/web/lib/wasm/jsep/webgpu/ops/pad.ts new file mode 100644 index 0000000000000..c2f89fd2845df --- /dev/null +++ b/js/web/lib/wasm/jsep/webgpu/ops/pad.ts @@ -0,0 +1,252 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import {DataType} from '../../../wasm-common'; +import {TensorView} from '../../tensor-view'; +import {ShapeUtil} from '../../util'; +import {AttributeWithCacheKey, createAttributeWithCacheKey} from '../attribute-with-cache-key'; +import {ComputeContext, GpuDataType, ProgramInfo, ProgramInfoLoader, ProgramMetadata} from '../types'; + +import {IndicesHelper, inputVariable, outputVariable, ShaderHelper} from './common'; + +export interface PadAttributes extends AttributeWithCacheKey { + // 0-constant, 1-reflect, 2-edge, 3-wrap + readonly mode: number; + readonly value: number; + readonly pads: number[]; +} + +const validateInputs = (inputs: readonly TensorView[]): void => { + if (!inputs || inputs.length < 1) { + throw new Error('Too few inputs'); + } + if (inputs[0].dataType !== DataType.float) { + throw new Error('Input type must be float.'); + } + + if (inputs.length >= 2) { + let validPads = inputs[0].dims.length * 2 === inputs[1].dims[0]; + if (inputs.length === 4) { + validPads = inputs[3].dims[0] * 2 === inputs[1].dims[0]; + } + if (!validPads) { + throw new Error('The pads should be a 1D tensor of shape [2 * input_rank] or [2 * num_axes].'); + } + } +}; + +const getPadConstant = + (output: IndicesHelper, outputDims: readonly number[], inputDims: readonly number[], + inputStrides: readonly number[], pads: number[], dataType: string, constantValue: number): string => { + const inputRank = inputDims.length; + + let block = ''; + for (let i = inputRank - 1; i >= 0; --i) { + block += ` + k = i32(${output.indicesGet('indices', i)}) - ${pads[i]}; + if (k < 0) { + break; + } + if (k >= ${inputDims[i]}) { + break; + } + offset += k * ${inputStrides[i]}; + `; + } + + return ` + value = ${dataType}(${constantValue}); + for (var i = 0; i < 1; i++) { + var offset = 0; + var k = 0; + ${block} + value = x[offset]; + } + `; + }; + +const getPadReflect = + (output: IndicesHelper, outputDims: readonly number[], inputDims: readonly number[], + inputStrides: readonly number[], pads: number[]): string => { + const inputRank = inputDims.length; + + let block = ''; + for (let i = inputRank - 1; i >= 0; --i) { + block += ` + k = i32(${output.indicesGet('indices', i)}) - ${pads[i]}; + if (k < 0) { + k = -k; + } + { + let _2n_1 = ${2 * (inputDims[i] - 1)}; + k = k % _2n_1; + if(k >= ${inputDims[i]}) { + k = _2n_1 - k; + } + } + offset += k * ${inputStrides[i]}; + `; + } + + return ` + var offset = 0; + var k = 0; + ${block} + value = x[offset]; + `; + }; + +const getPadEdge = + (output: IndicesHelper, outputDims: readonly number[], inputDims: readonly number[], + inputStrides: readonly number[], pads: number[]): string => { + const inputRank = inputDims.length; + + let block = ''; + for (let i = inputRank - 1; i >= 0; --i) { + block += ` + k = i32(${output.indicesGet('indices', i)}) - ${pads[i]}; + if (k < 0) { + k = 0; + } + if (k >= ${inputDims[i]}) { + k = ${inputDims[i] - 1}; + } + offset += k * ${inputStrides[i]}; + `; + } + + return ` + var offset = 0; + var k = 0; + ${block} + value = x[offset]; + `; + }; + +const getPadWrap = + (output: IndicesHelper, outputDims: readonly number[], inputDims: readonly number[], + inputStrides: readonly number[], pads: number[]): string => { + const inputRank = inputDims.length; + + let block = ''; + for (let i = inputRank - 1; i >= 0; --i) { + block += ` + k = i32(${output.indicesGet('indices', i)}) - ${pads[i]}; + if (k < 0) { + k += ${inputDims[i]}; + } + if (k >= ${inputDims[i]}) { + k -= ${inputDims[i]}; + } + offset += k * ${inputStrides[i]}; + `; + } + + return ` + var offset = 0; + var k = 0; + ${block} + value = x[offset]; + `; + }; + +const getPadSnippet = + (output: IndicesHelper, outputDims: readonly number[], inputDims: readonly number[], + inputStrides: readonly number[], attributes: PadAttributes, dataType: string): string => { + switch (attributes.mode) { + case 0: + return getPadConstant( + output, outputDims, inputDims, inputStrides, attributes.pads, dataType, attributes.value); + case 1: + return getPadReflect(output, outputDims, inputDims, inputStrides, attributes.pads); + case 2: + return getPadEdge(output, outputDims, inputDims, inputStrides, attributes.pads); + case 3: + return getPadWrap(output, outputDims, inputDims, inputStrides, attributes.pads); + default: + throw new Error('Invalid mode'); + } + }; + +const generatePadCode = + (shaderHelper: ShaderHelper, inputs: readonly TensorView[], attributes: PadAttributes, dataType: string): + string => { + const inputDims = inputs[0].dims; + const outputDims = ShapeUtil.padShape(inputDims.slice(), attributes.pads); + const outputSize = ShapeUtil.size(outputDims); + const inputStrides = ShapeUtil.computeStrides(inputDims); + + const output = outputVariable('output', inputs[0].dataType, outputDims); + const input = inputVariable('x', inputs[0].dataType, inputDims); + + const padSnippet = getPadSnippet(output, outputDims, inputDims, inputStrides, attributes, dataType); + const padCode = ` + ${shaderHelper.declareVariables(input, output)} + ${output.impl()} + ${shaderHelper.mainStart()} + ${shaderHelper.guardAgainstOutOfBoundsWorkgroupSizes(outputSize)} + + let indices = ${output.offsetToIndices('global_idx')}; + + var value = ${dataType}(0); + ${padSnippet} + output[global_idx] = value; + }`; + return padCode; + }; + +const createPadProgramInfo = + (inputs: readonly TensorView[], metadata: ProgramMetadata, attributes: PadAttributes): ProgramInfo => { + const outputShape = ShapeUtil.padShape(inputs[0].dims.slice(), attributes.pads); + return { + ...metadata, + outputs: [{dims: outputShape, dataType: inputs[0].dataType, gpuDataType: GpuDataType.default}], + getShaderSource: shaderHelper => generatePadCode(shaderHelper, inputs, attributes, 'f32'), + dispatchGroup: () => ({x: Math.ceil(ShapeUtil.size(outputShape) / 64 /* workgroup size */)}) + }; + }; + +const createPadAttributesFromInputs = (inputs: readonly TensorView[], attributes: PadAttributes): PadAttributes => { + if (inputs.length > 1) { + const bigInt64Pads = inputs[1].getBigInt64Array(); + const value = (inputs.length >= 3) ? inputs[2].getFloat32Array()[0] : 0.0; + + const inputRank = inputs[0].dims.length; + const updatePads = new Int32Array(2 * inputRank).fill(0); + if (inputs.length >= 4) { + const axes = inputs[3].getBigInt64Array(); + for (let i = 0; i < axes.length; i++) { + updatePads[Number(axes[i])] = Number(bigInt64Pads[i]); + updatePads[Number(axes[i]) + inputRank] = Number(bigInt64Pads[i + axes.length]); + } + } else { + bigInt64Pads.forEach((i, v) => updatePads[Number(i)] = (Number(v))); + } + + const pads: number[] = []; + updatePads.forEach(v => pads.push(v)); + + return createAttributeWithCacheKey({mode: attributes.mode, value, pads}); + } else { + return attributes; + } +}; + +const createPadProgramInfoLoader = (inputs: readonly TensorView[], attributes: PadAttributes): ProgramInfoLoader => { + const updatedAttributes = createPadAttributesFromInputs(inputs, attributes); + const metadata: + ProgramMetadata = {name: 'Pad', inputTypes: [GpuDataType.default], cacheHint: updatedAttributes.cacheKey}; + return {...metadata, get: () => createPadProgramInfo(inputs, metadata, updatedAttributes)}; +}; + +export const pad = (context: ComputeContext, attributes: PadAttributes): void => { + validateInputs(context.inputs); + context.compute(createPadProgramInfoLoader(context.inputs, attributes), {inputs: [0]}); +}; + +export const parsePadAttributes = (attributes: Record): PadAttributes => { + const mode = attributes.mode as number; + const value = attributes.value as number; + const pads = attributes.pads as number[]; + return createAttributeWithCacheKey({mode, value, pads}); +}; diff --git a/js/web/lib/wasm/jsep/webgpu/ops/pool.ts b/js/web/lib/wasm/jsep/webgpu/ops/pool.ts index c18a91afa5b90..120a0e9de5490 100644 --- a/js/web/lib/wasm/jsep/webgpu/ops/pool.ts +++ b/js/web/lib/wasm/jsep/webgpu/ops/pool.ts @@ -1,13 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import {DataType} from '../../../wasm-common'; -import {TensorView} from '../../tensor'; +import {TensorView} from '../../tensor-view'; import {PoolConvUtil, ShapeUtil} from '../../util'; import {AttributeWithCacheKey, createAttributeWithCacheKey} from '../attribute-with-cache-key'; import {ComputeContext, GpuDataType, ProgramInfo, ProgramMetadata} from '../types'; -import {createIndicesHelper, ShaderHelper} from './common'; +import {IndicesHelper, inputVariable, outputVariable, ShaderHelper} from './common'; // TODO: support: // - ceil_mode "test_maxpool_2d_ceil" @@ -22,17 +21,13 @@ const validateInputs = (inputs: readonly TensorView[]): void => { if (inputs[0].dims.length !== 4) { throw new Error('Pool ops supports 2-D inputs only for now.'); } - if (inputs[0].dataType !== DataType.float) { - throw new Error('Invalid input type.'); - } }; const getAdjustedPoolAttributesAndOutputShape = ( - inputs: readonly TensorView[], attributes: AttributeType, isGlobalOperator: boolean): [AttributeType, number[]] => { + input: TensorView, attributes: AttributeType, isGlobalOperator: boolean): [AttributeType, number[]] => { const isChannelsLast = attributes.format === 'NHWC'; - const inputShapeAsChannelFirst = isChannelsLast ? - [inputs[0].dims[0], inputs[0].dims[3], inputs[0].dims[1], inputs[0].dims[2]] : - inputs[0].dims.slice(); + const inputShapeAsChannelFirst = + isChannelsLast ? [input.dims[0], input.dims[3], input.dims[1], input.dims[2]] : input.dims.slice(); const hasDilations = Object.hasOwnProperty.call(attributes, 'dilations'); const kernelShape = attributes.kernelShape.slice(); const strides = attributes.strides.slice(); @@ -61,13 +56,14 @@ const getAdjustedPoolAttributesAndOutputShape = ( - shaderHelper: ShaderHelper, inputDims: readonly number[], outputShape: readonly number[], attributes: AttributeType, - op1: string, op2: string, dataType: string, start: string): string => { + shaderHelper: ShaderHelper, x: IndicesHelper, outputShape: readonly number[], attributes: AttributeType, + op1: string, op2: string, start: string): string => { const isChannelsLast = attributes.format === 'NHWC'; + const inputDims = x.shape; + const dataType = x.type.value; const rank = inputDims.length; const outputSize = ShapeUtil.size(outputShape); - const outputIndicesHelper = createIndicesHelper('output', outputShape); - const xIndicesHelper = createIndicesHelper('x', inputDims); + const output = outputVariable('output', x.type.tensor, outputShape); if (attributes.kernelShape.length <= 2) { const kw = attributes.kernelShape[attributes.kernelShape.length - 1]; @@ -86,14 +82,14 @@ const generatePoolingCode = x : array<${dataType}>; - @group(0) @binding(1) var output : array<${dataType}>; - - ${outputIndicesHelper.o2iImpl} - ${xIndicesHelper.i2oImpl} + ${shaderHelper.declareVariables(x, output)} ${shaderHelper.mainStart()} ${shaderHelper.guardAgainstOutOfBoundsWorkgroupSizes(outputSize)} - ${outputIndicesHelper.indicesVariableDeclaration('indices')} - ${outputIndicesHelper.o2iCall('global_idx', 'indices')} - ${outputIndicesHelper.indicesVariableDeclaration('xIndices')} - ${outputIndicesHelper.o2iCall('global_idx', 'xIndices')} + let indices = ${output.offsetToIndices('global_idx')}; + var xIndices = ${output.offsetToIndices('global_idx')}; var value: ${dataType} = ${dataType}(${start}); var pad = 0; @@ -169,22 +159,18 @@ const generatePoolingCode = x : array<${dataType}>; - @group(0) @binding(1) var output : array<${dataType}>; - - ${outputIndicesHelper.o2iImpl} - ${xIndicesHelper.i2oImpl} + ${shaderHelper.declareVariables(x, output)} const pads = array(${attributes.pads.map(i => `${i}u`).join(',')}); const inputDims = array(${inputDims.map(i => `${i}u`).join(',')}); @@ -194,14 +180,12 @@ const generatePoolingCode = ; - var value = ${dataType}(${start}); + var value = ${output.type.value}(${start}); var pad = 0; var isPad = false; @@ -253,29 +237,30 @@ export interface AveragePoolAttributes extends PoolCommonAttributes, AttributeWi } const createAveragePoolProgramInfo = - (inputs: readonly TensorView[], metadata: ProgramMetadata, isGlobalOperator: boolean, - attributes: AveragePoolAttributes): ProgramInfo => { - const [adjustedAttributes, outputShape] = - getAdjustedPoolAttributesAndOutputShape(inputs, attributes, isGlobalOperator); - const kernelSize = ShapeUtil.size(adjustedAttributes.kernelShape); - - const dataType = 'f32'; - - const op1 = 'value += x_val;'; - let op2 = ''; - if (adjustedAttributes.countIncludePad) { - op2 += `value /= ${dataType}(${kernelSize});`; - } else { - op2 += `value /= ${dataType}(${kernelSize} - pad);`; - } - return { - ...metadata, - outputs: [{dims: outputShape, dataType: inputs[0].dataType, gpuDataType: GpuDataType.default}], - getShaderSource: shaderHelper => generatePoolingCode( - shaderHelper, inputs[0].dims, outputShape, adjustedAttributes, op1, op2, dataType, '0.0'), - dispatchGroup: () => ({x: Math.ceil(ShapeUtil.size(outputShape) / 64 /* workgroup size */)}) - }; - }; + (input: TensorView, metadata: ProgramMetadata, isGlobalOperator: boolean, attributes: AveragePoolAttributes): + ProgramInfo => { + const [adjustedAttributes, outputShape] = + getAdjustedPoolAttributesAndOutputShape(input, attributes, isGlobalOperator); + const kernelSize = ShapeUtil.size(adjustedAttributes.kernelShape); + + const x = inputVariable('x', input.dataType, input.dims); + const dataType = x.type.value; + + const op1 = 'value += x_val;'; + let op2 = ''; + if (adjustedAttributes.countIncludePad) { + op2 += `value /= ${dataType}(${kernelSize});`; + } else { + op2 += `value /= ${dataType}(${kernelSize} - pad);`; + } + return { + ...metadata, + outputs: [{dims: outputShape, dataType: input.dataType, gpuDataType: GpuDataType.default}], + getShaderSource: shaderHelper => + generatePoolingCode(shaderHelper, x, outputShape, adjustedAttributes, op1, op2, '0.0'), + dispatchGroup: () => ({x: Math.ceil(ShapeUtil.size(outputShape) / 64 /* workgroup size */)}) + }; + }; export const parseAveragePoolAttributes = (attributes: Record): AveragePoolAttributes => { const countIncludePad = (attributes.count_include_pad as number) === 0 ? false : true; @@ -292,7 +277,8 @@ export const parseAveragePoolAttributes = (attributes: Record): export const averagePool = (context: ComputeContext, attributes: AveragePoolAttributes): void => { validateInputs(context.inputs); const metadata = {name: 'AveragePool', inputTypes: [GpuDataType.default], cacheHint: attributes.cacheKey}; - context.compute({...metadata, get: () => createAveragePoolProgramInfo(context.inputs, metadata, false, attributes)}); + context.compute( + {...metadata, get: () => createAveragePoolProgramInfo(context.inputs[0], metadata, false, attributes)}); }; const globalPoolAttributes = { @@ -315,7 +301,8 @@ export const parseGlobalAveragePoolAttributes = (attributes: Record { validateInputs(context.inputs); const metadata = {name: 'GlobalAveragePool', inputTypes: [GpuDataType.default], cacheHint: attributes.cacheKey}; - context.compute({...metadata, get: () => createAveragePoolProgramInfo(context.inputs, metadata, true, attributes)}); + context.compute( + {...metadata, get: () => createAveragePoolProgramInfo(context.inputs[0], metadata, true, attributes)}); }; export interface MaxPoolAttributes extends PoolCommonAttributes, AttributeWithCacheKey { @@ -324,27 +311,28 @@ export interface MaxPoolAttributes extends PoolCommonAttributes, AttributeWithCa } const createMaxPoolProgramInfo = - (inputs: readonly TensorView[], metadata: ProgramMetadata, isGlobalOperator: boolean, - attributes: MaxPoolAttributes): ProgramInfo => { - const [adjustedAttributes, outputShape] = - getAdjustedPoolAttributesAndOutputShape(inputs, attributes, isGlobalOperator); - const op1 = ` + (input: TensorView, metadata: ProgramMetadata, isGlobalOperator: boolean, attributes: MaxPoolAttributes): + ProgramInfo => { + const [adjustedAttributes, outputShape] = + getAdjustedPoolAttributesAndOutputShape(input, attributes, isGlobalOperator); + const op1 = ` value = max(x_val, value); `; - const op2 = ''; - return { - ...metadata, - outputs: [{dims: outputShape, dataType: inputs[0].dataType, gpuDataType: GpuDataType.default}], - getShaderSource: shaderHelper => - generatePoolingCode(shaderHelper, inputs[0].dims, outputShape, adjustedAttributes, op1, op2, 'f32', '-1e5'), - dispatchGroup: () => ({x: Math.ceil(ShapeUtil.size(outputShape) / 64 /* workgroup size */)}) - }; - }; + const op2 = ''; + const x = inputVariable('x', input.dataType, input.dims); + return { + ...metadata, + outputs: [{dims: outputShape, dataType: input.dataType, gpuDataType: GpuDataType.default}], + getShaderSource: shaderHelper => + generatePoolingCode(shaderHelper, x, outputShape, adjustedAttributes, op1, op2, '-1e5'), + dispatchGroup: () => ({x: Math.ceil(ShapeUtil.size(outputShape) / 64 /* workgroup size */)}) + }; + }; export const maxPool = (context: ComputeContext, attributes: MaxPoolAttributes): void => { validateInputs(context.inputs); const metadata = {name: 'MaxPool', inputTypes: [GpuDataType.default], cacheHint: attributes.cacheKey}; - context.compute({...metadata, get: () => createMaxPoolProgramInfo(context.inputs, metadata, false, attributes)}); + context.compute({...metadata, get: () => createMaxPoolProgramInfo(context.inputs[0], metadata, false, attributes)}); }; export const parseMaxPoolAttributes = (attributes: Record): MaxPoolAttributes => { @@ -371,5 +359,5 @@ export const parseGlobalMaxPoolAttributes = (attributes: Record export const globalMaxPool = (context: ComputeContext, attributes: MaxPoolAttributes): void => { validateInputs(context.inputs); const metadata = {name: 'GlobalMaxPool', inputTypes: [GpuDataType.default], cacheHint: attributes.cacheKey}; - context.compute({...metadata, get: () => createMaxPoolProgramInfo(context.inputs, metadata, true, attributes)}); + context.compute({...metadata, get: () => createMaxPoolProgramInfo(context.inputs[0], metadata, true, attributes)}); }; diff --git a/js/web/lib/wasm/jsep/webgpu/ops/reduce.ts b/js/web/lib/wasm/jsep/webgpu/ops/reduce.ts new file mode 100644 index 0000000000000..598b1db033c61 --- /dev/null +++ b/js/web/lib/wasm/jsep/webgpu/ops/reduce.ts @@ -0,0 +1,275 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import {DataType} from '../../../wasm-common'; +import {TensorView} from '../../tensor-view'; +import {ShapeUtil} from '../../util'; +import {AttributeWithCacheKey, createAttributeWithCacheKey} from '../attribute-with-cache-key'; +import {ComputeContext, GpuDataType, ProgramInfo, ProgramInfoLoader, ProgramMetadata} from '../types'; + +import {IndicesHelper, inputVariable, outputVariable, ShaderHelper} from './common'; + +const validateInputs = (inputs: readonly TensorView[]): void => { + if (!inputs || inputs.length === 0 || inputs.length > 2) { + throw new Error('Reduce op requires 1 or 2 inputs.'); + } + + if (inputs.length === 2 && inputs[1].dims.length !== 1) { + throw new Error('Invalid axes input dims.'); + } +}; + +export interface ReduceAttributes extends AttributeWithCacheKey { + keepDims: boolean; + noopWithEmptyAxes: boolean; + axes: number[]; +} + +export type ReduceOp = + (input: IndicesHelper, output: IndicesHelper, + axes: readonly number[]) => [string, string, string, string, ...string[]]; + +const noOp: ReduceOp = (input) => ['', '', `var value = ${input.getByOffset('inputOffset')};`, '']; +export const createReduceProgramInfo = + (metadata: ProgramMetadata, inputs: readonly TensorView[], reduceOp: ReduceOp, axesInput: number[], + outputDataType: DataType, keepDims = false, noopWithEmptyAxes = false): ProgramInfo => { + const outputShape: number[] = []; + const inputShape = inputs[0].dims; + + const axes = ShapeUtil.normalizeAxes(axesInput, inputs[0].dims.length); + const reduceOnAllAxes = !noopWithEmptyAxes && axes.length === 0; + inputShape.forEach((d, i) => { + if (reduceOnAllAxes || axes.indexOf(i) >= 0) { + if (keepDims) { + outputShape.push(1); + } // else { // skip this axis} + } else { + outputShape.push(d); + } + }); + + const idxCopy: string[] = []; // copy output indexes to input indexes + + const input = inputVariable('_A', inputs[0].dataType, inputShape); + const output = outputVariable('output', outputDataType, outputShape); + const ops = reduceOp(input, output, axes); + const inputOffsetAssignment = `inputOffset = ${input.indicesToOffset('inputIndices')};`; + const initinputOffsetLet = `let ${inputOffsetAssignment};`; + const initinputOffsetVar = `var ${inputOffsetAssignment};`; + const initinputOffset = (ops[1] === '') ? '' : initinputOffsetVar; + let reduceOps = ((ops[1] === '') ? initinputOffsetLet : inputOffsetAssignment) + '\n' + ops[2]; + + for (let k = 0, l = 0; k < inputs[0].dims.length; k++) { + // if this axis is reduced + if (reduceOnAllAxes || axes.indexOf(k) >= 0) { + if (keepDims) { + l++; + } + // loop over the d-th axis + reduceOps = `for(var j${k}: u32 = 0; j${k} < ${inputs[0].dims[k]}; j${k}++) { + ${ops[2].includes('lastIndex') ? `let lastIndex = j${k};` : ''} + ${input.indicesSet('inputIndices', k, `j${k}`)} + ${reduceOps} + }`; + } else { + idxCopy.push(`${input.indicesSet('inputIndices', k, output.indicesGet('outputIndices', l))};`); + l++; + } + } + + const outputSize = ShapeUtil.size(outputShape); + const getShaderSource = (shaderHelper: ShaderHelper) => ` + ${shaderHelper.declareVariables(input, output)} + + ${shaderHelper.mainStart()} + ${shaderHelper.guardAgainstOutOfBoundsWorkgroupSizes(outputSize)} + var inputIndices: ${input.type.indices}; + let outputIndices = ${output.offsetToIndices('global_idx')}; + + ${idxCopy.join('\n')} + ${ops[0]} // init ops for reduce max/min + ${initinputOffset} + ${ops[1]} + ${reduceOps} + ${ops[3]} + ${ops.length === 4 ? output.setByOffset('global_idx', 'value') : ops.slice(4).join('\n')} + }`; + + return { + ...metadata, + getShaderSource, + outputs: [{dims: outputShape, dataType: outputDataType, gpuDataType: GpuDataType.default}], + dispatchGroup: () => ({x: Math.ceil(outputSize / 64 /* workgroup size */)}) + }; + }; + +const createReduceAttributesFromInputs = + (inputs: readonly TensorView[], attributes: ReduceAttributes): ReduceAttributes => { + const axes: number[] = []; + if (inputs[1].dims[0] > 0) { + inputs[1].getBigInt64Array().forEach(v => axes.push(Number(v))); + } + return createAttributeWithCacheKey( + {axes, keepDims: attributes.keepDims, noopWithEmptyAxes: attributes.noopWithEmptyAxes}); + }; + +const createReduceProgramInfoLoader = + (inputs: readonly TensorView[], name: string, attributes: ReduceAttributes, + reduceOp: ReduceOp): ProgramInfoLoader => { + const updatedAttributes: ReduceAttributes = + inputs.length === 1 ? attributes : createReduceAttributesFromInputs(inputs, attributes); + const metadata: ProgramMetadata = { + name, + inputTypes: [GpuDataType.default], + cacheHint: updatedAttributes.cacheKey + '_' + inputs[0].dims.map(d => d.toString()).join(',') + }; + return { + ...metadata, + get: () => createReduceProgramInfo( + metadata, [inputs[0]], + updatedAttributes.noopWithEmptyAxes && updatedAttributes.axes.length === 0 ? noOp : reduceOp, + updatedAttributes.axes, inputs[0].dataType, updatedAttributes.keepDims, updatedAttributes.noopWithEmptyAxes) + }; + }; + +export const reduceLogSum = (context: ComputeContext, attributes: ReduceAttributes): void => { + validateInputs(context.inputs); + const reduceOp: ReduceOp = (input, output) => + [`var value = ${output.type.storage}(0);`, + '', + `value += ${input.getByOffset('inputOffset')};`, + 'value = log(value);', + ]; + context.compute(createReduceProgramInfoLoader(context.inputs, 'ReduceLogSum', attributes, reduceOp), {inputs: [0]}); +}; + +export const reduceL1 = (context: ComputeContext, attributes: ReduceAttributes): void => { + validateInputs(context.inputs); + const reduceOp: ReduceOp = (input, output) => + [`var value = ${output.type.storage}(0);`, + '', + `value += abs(${input.getByOffset('inputOffset')});`, + '', + ]; + context.compute(createReduceProgramInfoLoader(context.inputs, 'ReduceL1', attributes, reduceOp), {inputs: [0]}); +}; + +export const reduceL2 = (context: ComputeContext, attributes: ReduceAttributes): void => { + validateInputs(context.inputs); + const reduceOp: ReduceOp = (input, output) => + [`var t = ${output.type.value}(0); var value = ${output.type.value}(0);`, + '', + `t = ${input.getByOffset('inputOffset')}; value += (t * t);`, + 'value = sqrt(value);', + ]; + context.compute(createReduceProgramInfoLoader(context.inputs, 'ReduceL2', attributes, reduceOp), {inputs: [0]}); +}; + +export const reduceLogSumExp = (context: ComputeContext, attributes: ReduceAttributes): void => { + validateInputs(context.inputs); + const reduceOp: ReduceOp = (input, output) => + [`var value = ${output.type.storage}(0);`, + '', + `value += exp(${input.getByOffset('inputOffset')});`, + 'value = log(value);', + ]; + context.compute( + createReduceProgramInfoLoader(context.inputs, 'ReduceLogSumExp', attributes, reduceOp), {inputs: [0]}); +}; + +export const reduceMax = (context: ComputeContext, attributes: ReduceAttributes): void => { + validateInputs(context.inputs); + const reduceOp: ReduceOp = (input, _output, axes) => { + const idxZero = []; + for (let k = 0; k < input.shape.length; k++) { + if (axes.indexOf(k) >= 0 || axes.length === 0) { + idxZero.push(input.indicesSet('inputIndices', k, 0)); + } + } + + return [ + `${idxZero.join('\n')}`, + `var value = ${input.getByOffset('inputOffset')};`, + `value = max(value, ${input.getByOffset('inputOffset')});`, + '', + ]; + }; + context.compute(createReduceProgramInfoLoader(context.inputs, 'ReduceMax', attributes, reduceOp), {inputs: [0]}); +}; + +export const reduceMean = (context: ComputeContext, attributes: ReduceAttributes): void => { + validateInputs(context.inputs); + const reduceOp: ReduceOp = (input, output, axes) => { + let size = 1.0; + for (let k = 0; k < input.shape.length; k++) { + if (axes.indexOf(k) >= 0 || axes.length === 0) { + size *= input.shape[k]; + } + } + + return [ + 'var sum = f32(0);', + '', + `sum += f32(${input.getByOffset('inputOffset')});`, + `let value = ${output.type.value}(sum / ${size});`, + ]; + }; + context.compute(createReduceProgramInfoLoader(context.inputs, 'ReduceMean', attributes, reduceOp), {inputs: [0]}); +}; + +export const reduceMin = (context: ComputeContext, attributes: ReduceAttributes): void => { + validateInputs(context.inputs); + const reduceOp: ReduceOp = (input, _output, axes) => { + const idxZero = []; + for (let k = 0; k < input.shape.length; k++) { + if (axes.indexOf(k) >= 0 || axes.length === 0) { + idxZero.push(`inputIndices[${k}] = 0;`); // first element + } + } + + return [ + `${idxZero.join('\n')}`, + `var value = ${input.getByOffset('inputOffset')};`, + `value = min(value, ${input.getByOffset('inputOffset')});`, + '', + ]; + }; + context.compute(createReduceProgramInfoLoader(context.inputs, 'ReduceMin', attributes, reduceOp), {inputs: [0]}); +}; + +export const reduceProd = (context: ComputeContext, attributes: ReduceAttributes): void => { + validateInputs(context.inputs); + const reduceOp: ReduceOp = (input, output) => + [`var value = ${output.type.storage}(1);`, + '', + `value *= ${input.getByOffset('inputOffset')};`, + '', + ]; + context.compute(createReduceProgramInfoLoader(context.inputs, 'ReduceProd', attributes, reduceOp), {inputs: [0]}); +}; + +export const reduceSum = (context: ComputeContext, attributes: ReduceAttributes): void => { + validateInputs(context.inputs); + const reduceOp: ReduceOp = (input, output) => + [`var value = ${output.type.storage}(0);`, + '', + `value += ${input.getByOffset('inputOffset')};`, + '', + ]; + context.compute(createReduceProgramInfoLoader(context.inputs, 'ReduceSum', attributes, reduceOp), {inputs: [0]}); +}; + +export const reduceSumSquare = (context: ComputeContext, attributes: ReduceAttributes): void => { + validateInputs(context.inputs); + const reduceOp: ReduceOp = (input, output) => + [`var t = ${output.type.value}(0); var value = ${output.type.value}(0);`, + '', + `t = ${input.getByOffset('inputOffset')}; value += t * t;`, + '', + ]; + context.compute( + createReduceProgramInfoLoader(context.inputs, 'ReduceSumSquare', attributes, reduceOp), {inputs: [0]}); +}; + +export const parseReduceAttributes = (attributes: Record): ReduceAttributes => + createAttributeWithCacheKey(attributes as Omit); diff --git a/js/web/lib/wasm/jsep/webgpu/ops/resize.ts b/js/web/lib/wasm/jsep/webgpu/ops/resize.ts new file mode 100644 index 0000000000000..8b9dbbf57ac75 --- /dev/null +++ b/js/web/lib/wasm/jsep/webgpu/ops/resize.ts @@ -0,0 +1,578 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + + +import {TensorView} from '../../tensor-view'; +import {ShapeUtil} from '../../util'; +import {AttributeWithCacheKey, createAttributeWithCacheKey} from '../attribute-with-cache-key'; +import {ComputeContext, GpuDataType, ProgramInfo, ProgramInfoLoader, ProgramMetadata} from '../types'; + +import {IndicesHelper, inputVariable, outputVariable, ShaderHelper} from './common'; + +type CoordinateTransformMode = 'half_pixel'|'asymmetric'|'pytorch_half_pixel'|'tf_half_pixel_for_nn'|'align_corners'| + 'tf_crop_and_resize'|'half_pixel_symmetric'; + +type KeepAspectRatioPolicy = 'stretch'|'not_smaller'|'not_larger'; + +type Mode = 'nearest'|'linear'|'cubic'; + +type NearestMode = 'round_prefer_floor'|'round_prefer_ceil'|'floor'|'ceil'|'simple'; + +export interface ResizeAttributes extends AttributeWithCacheKey { + antialias: number; + axes: number[]; + coordinateTransformMode: CoordinateTransformMode; + cubicCoeffA: number; + excludeOutside: boolean; + extrapolationValue: number; + keepAspectRatioPolicy: KeepAspectRatioPolicy; + mode: Mode; + nearestMode: NearestMode; +} + +const validateScales = (scales: number[], attributes: ResizeAttributes): void => { + scales.every((value) => value > 0 || (() => { + throw new Error('Resize requires scales input values to be positive'); + })); + // Check scales dims based on mode: LINEAR, CUBIC + if (scales.length > 0) { + if (attributes.mode === 'linear') { + if (!(scales.length === 2 || (scales.length === 4 && scales[0] === 1 && scales[1] === 1) || + (scales.length === 4 && scales[0] === 1 && scales[3] === 1))) { + throw new Error('Resize requires scales input size to be 2 or 4 for linear mode'); + } + } else if (attributes.mode === 'cubic') { + if (!(scales.length === 2 || (scales.length === 4 && scales[0] === 1 && scales[1] === 1) || + (scales.length === 4 && scales[0] === 1 && scales[3] === 1))) { + throw new Error('Resize requires scales input size to be 2 or 4 for cubic mode'); + } + } + } +}; + +const updateScales = (scales: readonly number[], axes: readonly number[], rank: number): number[] => { + axes.every((value) => value >= 0 && value < rank || (() => { + throw new Error('Resize requires axes input values to be positive and less than rank'); + })); + const newScales = new Array(rank).fill(1.0); + axes.forEach((value, index) => newScales[value] = scales[index]); + return newScales; +}; + +const validateInputs = + (inputs: readonly TensorView[], attributes: ResizeAttributes, opsetVersion: number, scales: number[], + sizes: number[], roi: number[]): void => { + const [roiInputIndex, scalesInputIndex, sizesInputIndex] = + (opsetVersion > 10) ? [1, 2, 3] : [-1, (inputs.length > 1) ? 1 : -1, -1]; + const rank = inputs[0].dims.length; + if (roiInputIndex > 0 && inputs.length > roiInputIndex && inputs[roiInputIndex].dims.length > 0) { + inputs[roiInputIndex].getFloat32Array().forEach((value) => roi.push(value)); + + } else if (attributes.coordinateTransformMode === 'tf_crop_and_resize') { + throw new Error('Resize requires RoI input to be specified when coordinateTransformMode is tfCropAndResize'); + } + + if (scalesInputIndex > 0 && inputs.length > scalesInputIndex && inputs[scalesInputIndex].dims.length > 0) { + inputs[scalesInputIndex].getFloat32Array().forEach((value) => scales.push(value)); + if (scales.length !== 0 && + (scales.length !== rank && (opsetVersion >= 18 && scales.length !== attributes.axes.length))) { + throw new Error( + 'Resize requires scales input size to be same as input rank or axes size for opset 18 and up'); + } + validateScales(scales, attributes); + if (attributes.axes.length > 0) { + updateScales(scales, attributes.axes, rank).forEach((value, index) => scales[index] = value); + } + } + if (sizesInputIndex > 0 && inputs.length > sizesInputIndex) { + inputs[sizesInputIndex].getBigInt64Array().forEach((value) => sizes.push(Number(value))); + if (sizes.length !== rank || (opsetVersion >= 18 && sizes.length === attributes.axes.length)) { + throw new Error('Resize requires sizes input size to be same as input rank or axes size for opset 18 and up'); + } + } + + if (attributes.axes.length > 0) { + if (scales.length !== attributes.axes.length) { + throw new Error('Resize requires "scales" input size to be of axes rank when axes attributes is specified'); + } + if (sizes.length !== attributes.axes.length) { + throw new Error( + 'Resize requires "sizes" input size to be of rank axes rank when axes attributes is specified'); + } + } + if (typeof scales !== 'undefined' && typeof sizes !== 'undefined' && scales.length > 0 && sizes.length > rank) { + throw new Error('Resize requires only of scales or sizes to be specified'); + } + }; + +const getOriginalCoordinateFromResizedCoordinate = (coordinateTransferMode: CoordinateTransformMode): string => + 'fn getOriginalCoordinateFromResizedCoordinate(xResized: f32, xScale: f32, lengthResized: f32,\ + lengthOriginal: f32, roiStart: f32, roiEnd: f32) -> f32 { ' + + (() => { + switch (coordinateTransferMode) { + case 'asymmetric': + return 'return xResized / xScale;'; + case 'pytorch_half_pixel': + return 'if (lengthResized > 1) { \ + return (xResized + 0.5) / xScale - 0.5; \ + } else { \ + return 0.0; \ + }'; + case 'tf_half_pixel_for_nn': + return 'return (xResized + 0.5) / xScale;'; + case 'align_corners': + return 'if (lengthResized == 1) { \ + return 0.0; \ + } else { \ + return xResized * (lengthOriginal - 1) / (lengthResized - 1); \ + }'; + case 'tf_crop_and_resize': + return 'if (lengthResized > 1) { \ + return roiStart * (lengthOriginal - 1) + \ + (xResized * (roiEnd - roiStart) * (lengthOriginal - 1)) / (lengthResized - 1); \ + } else { \ + return 0.5 * (roiStart + roiEnd) * f32(lengthOriginal - 1); \ + }'; + case 'half_pixel_symmetric': + return [ + 'const outputWidth = xScale * lengthResized;', 'const adjustment = lengthResized / outputWidth;', + 'const center = lengthOriginal / 2;', 'const offset = center * (1 - adjustment);', + 'return offset + ((xResized + 0.5) / xScale) - 0.5;' + ].join('\n'); + case 'half_pixel': + return 'return ((xResized + 0.5) / xScale) - 0.5;'; + default: + throw new Error(`Coordinate transform mode ${coordinateTransferMode} is not supported`); + } + })() + + '}'; + +const getNearestPixelFromOriginal = (nearestMode: NearestMode, opsetVersion: number): string => + 'fn getNearestPixelFromOriginal(xOriginal: f32, isDownSample: bool) -> f32 {' + (() => { + switch (nearestMode) { + case 'round_prefer_ceil': + return 'if (fract(xOriginal) == 0.5) { \ + return ceil(xOriginal); \ + } else { \ + return round(xOriginal); \ + }'; + case 'floor': + return 'return floor(xOriginal);'; + case 'ceil': + return 'return ceil(xOriginal);'; + case 'round_prefer_floor': + return 'if (fract(xOriginal) == 0.5) { \ + return floor(xOriginal); \ + } else { \ + return round(xOriginal); \ + }'; + case 'simple': + default: + if (opsetVersion < 11) { + return 'if (isDownSample) \ + { \ + return ceil(xOriginal); \ + } else { \ + return xOriginal; \ + }'; + } + throw new Error(`Nearest mode ${nearestMode} is not supported`); + } + })() + + '}'; + +const updateRoI = (roi: readonly number[], axes: readonly number[], rank: number): number[] => { + const roiTmp = new Array(rank).fill(0).concat(new Array(rank).fill(1)); + const roiLocal = roi.length === 0 ? roiTmp : roi.slice(); + if (axes.length > 0) { + axes.forEach((v, i) => { + roiTmp[v] = roiLocal[i]; + roiTmp[i + rank] = roiLocal[axes.length + i]; + }); + return roiTmp; + } + return roiLocal; +}; + +const initOutputShape = + (inputShape: readonly number[], scales: readonly number[], sizes: readonly number[], axes: readonly number[]): + number[] => { + let outputShape: number[] = []; + if (sizes.length > 0) { + if (axes.length > 0) { + inputShape.forEach((v) => outputShape.push(v)); + if (Math.max(...axes) > inputShape.length) { + throw new Error('axes is out of bound'); + } + axes.forEach((v, i) => outputShape[v] = sizes[i]); + } else { + sizes.forEach((v) => outputShape.push(v)); + } + } else { + if (scales.length === 0) { + throw new Error('Resize requires either scales or sizes.'); + } else { + outputShape = inputShape.map((value, index) => Math.round(value * scales[index])); + } + } + return outputShape; + }; + +const adjustOutputShape = + (inputShape: readonly number[], outputShape: readonly number[], scales: number[], attributes: ResizeAttributes): + number[] => { + const scaleInPolicy = (() => { + switch (attributes.keepAspectRatioPolicy) { + case 'not_larger': + return attributes.axes.length > 0 ? Math.min(...attributes.axes.map(i => scales[i]), Number.MAX_VALUE) : + Math.min(...scales, Number.MAX_VALUE); + case 'not_smaller': + return attributes.axes.length > 0 ? Math.max(...attributes.axes.map(i => scales[i]), Number.MIN_VALUE) : + Math.max(...scales, Number.MIN_VALUE); + default: + throw new Error(`Keep aspect ratio policy ${attributes.keepAspectRatioPolicy} is not supported`); + } + })(); + scales.fill(1.0, 0, scales.length); + const adjustedOutputShape = inputShape.slice(); + if (attributes.axes.length > 0) { + attributes.axes.forEach((v) => scales[v] = scaleInPolicy); + attributes.axes.forEach((v) => adjustedOutputShape[v] = Math.round(inputShape[v] * scales[v])); + } else { + scales.fill(scaleInPolicy, 0, scales.length); + adjustedOutputShape.forEach((v, i) => adjustedOutputShape[i] = Math.round(v * scales[i])); + } + return adjustedOutputShape; + }; + +const calculateOriginalIndicesFromOutputIndices = + (output: IndicesHelper, inputShape: readonly number[], outputShape: readonly number[], scales: readonly number[], + roi: readonly number[]): string => ` + fn calculateOriginalIndicesFromOutputIndices(outputIndices: ${output.type.indices}) -> array { + const inputShape = array(${inputShape.map(i => `${i}u`).join(',')}); + const outputShape = array(${outputShape.map(i => `${i}u`).join(',')}); + const scales = array(${scales.map(i => `${i}f`).join(',')}); + const roi = array(${roi.map(i => `${i}f`).join(',')}); + var originalIndices: array; + for (var i:u32 = 0; i < ${outputShape.length}; i++) { + var outputIndex = ${outputShape.length === 1 ? 'outputIndices' : 'outputIndices[i]'}; + if (scales[i] == 1.0) { + originalIndices[i] = f32(outputIndex); + } else { + originalIndices[i] = getOriginalCoordinateFromResizedCoordinate(f32(outputIndex), scales[i], + f32(outputShape[i]), f32(inputShape[i]), roi[i], roi[i + ${inputShape.length}]); + } + } + return originalIndices; + }`; + +const calculateInputIndicesFromOutputIndices = + (input: IndicesHelper, output: IndicesHelper, inputShape: readonly number[], outputShape: readonly number[], + scales: readonly number[], roi: readonly number[], useExtrapolation: boolean): string => ` + fn calculateInputIndicesFromOutputIndices(outputIndices: ${output.type.indices}) -> ${input.type.indices} { + const inputShape = array(${inputShape.map(i => `${i}u`).join(',')}); + const outputShape = array(${outputShape.map(i => `${i}u`).join(',')}); + const scales = array(${scales.map(i => `${i}f`).join(',')}); + const roi = array(${roi.map(i => `${i}f`).join(',')}); + var inputIndices: ${input.type.indices}; + for (var i:u32 = 0; i < ${outputShape.length}; i++) { + var outputIndex = ${outputShape.length === 1 ? 'outputIndices' : 'outputIndices[i]'}; + var inputIndex: u32; + if (scales[i] == 1.0) { + inputIndex = outputIndex; + } else { + var original_idx = getOriginalCoordinateFromResizedCoordinate(f32(outputIndex), scales[i], + f32(outputShape[i]), f32(inputShape[i]), roi[i], roi[i + ${inputShape.length}]); + if (!${useExtrapolation} || (original_idx >= 0 && original_idx < f32(inputShape[i]))) { + if (original_idx < 0) { + inputIndex = 0; + } else if (original_idx > (f32(inputShape[i]) - 1)) { + inputIndex = inputShape[i] - 1; + } else { + inputIndex = u32(getNearestPixelFromOriginal(original_idx, scales[i] < 1)); + } + } else { + inputIndex = u32(original_idx); + } + } + ${input.indicesSet('inputIndices', 'i', 'inputIndex')} + } + return inputIndices; + }`; + +const checkInputIndices = (input: IndicesHelper, inputShape: readonly number[]): string => ` + fn checkInputIndices(inputIndices: ${input.type.indices}) -> bool { + const inputShape = array(${inputShape.map(i => `${i}u`).join(',')}); + for (var i:u32 = 0; i < ${inputShape.length}; i++) { + var inputIndex = ${inputShape.length === 1 ? 'inputIndices' : 'inputIndices[i]'}; + if (inputIndex < 0 || inputIndex >= inputShape[i]) { + return false; + } + } + return true; + }`; + +const bilinearInterpolation = + (input: IndicesHelper, output: IndicesHelper, inputShape: readonly number[], outputShape: readonly number[], + scales: readonly number[], useExtrapolation: boolean, extrapolationValue: number): string => { + const [batchIdx, heightIdx, widthIdx, channelIdx] = + inputShape.length === 2 ? [-1, 0, 1, -1] : (scales[1] === 1.0 ? [0, 2, 3, 1] : [0, 1, 2, 3]); + return ` + fn getInputValue(batch: u32, channel: u32, row: u32, col: u32) -> f32 { + var inputIndices: ${input.type.indices}; + inputIndices[${heightIdx}] = max(0, min(row, ${inputShape[heightIdx]} - 1)); + inputIndices[${widthIdx}] = max(0, min(col, ${inputShape[widthIdx]} - 1)); + if (${inputShape.length} > 2) { + inputIndices[${channelIdx}] = channel; + inputIndices[${batchIdx}] = batch; + }; + return input[${input.indicesToOffset('inputIndices')}]; + } + + fn bilinearInterpolation(outputIndices: ${output.type.indices}) -> f32 { + var originalIndices = calculateOriginalIndicesFromOutputIndices(outputIndices); + var row:f32 = originalIndices[${heightIdx}]; + var col:f32 = originalIndices[${widthIdx}]; + if (${useExtrapolation} && (row < 0 || row > (${inputShape[heightIdx]} - 1) || col < 0 || col > ${ + inputShape[widthIdx]} - 1)) { + return ${extrapolationValue}; + } + row = max(0, min(row, ${inputShape[heightIdx]} - 1)); + col = max(0, min(col, ${inputShape[widthIdx]} - 1)); + var row1: u32 = u32(row); + var col1: u32 = u32(col); + var row2: u32 = u32(row + 1); + var col2: u32 = u32(col + 1); + var channel: u32 = 0; + var batch: u32 = 0; + if (${inputShape.length > 2}) { + channel = u32(originalIndices[${channelIdx}]); + batch = u32(originalIndices[${batchIdx}]); + } + var x11: f32 = getInputValue(batch, channel, row1, col1); + var x12: f32 = getInputValue(batch, channel, row1, col2); + var x21: f32 = getInputValue(batch, channel, row2, col1); + var x22: f32 = getInputValue(batch, channel, row2, col2); + var dx1: f32 = row - f32(row1); + var dx2: f32 = f32(row2 ) - row; + var dy1 = col - f32(col1); + var dy2 = f32(col2) - col; + return (x11 * dx2 * dy2 + x12 * dx2 * dy1 + x21 * dx1 * dy2 + x22 * dx1 * dy1); + }`; + }; + +const bicubicInterpolation = + (input: IndicesHelper, output: IndicesHelper, inputShape: readonly number[], outputShape: readonly number[], + scales: readonly number[], roi: readonly number[], cubicCoeffA: number, useExtrapolation: boolean, + extrapolationValue: number, excludeOutside: boolean): string => { + const [heightIdx, widthIdx] = inputShape.length === 2 ? [0, 1] : (scales[1] === 1.0) ? [2, 3] : [1, 2]; + + const createCubicInterpolationFunction = (idx: number): string => { + const direction = idx === heightIdx ? 'row' : 'col'; + return ` + fn ${direction}CubicInterpolation(inputIndices: ${input.type.indices}, outputIndices: ${ + output.type.indices}) -> f32 { + var outputIndex = ${outputShape.length === 1 ? 'outputIndices' : `outputIndices[${idx}]`}; + var originalIdx: f32 = getOriginalCoordinateFromResizedCoordinate(f32(outputIndex), ${scales[idx]}, + f32(${outputShape[idx]}), f32(${inputShape[idx]}), ${roi[idx]}, ${roi[idx]} + ${inputShape.length}); + var fractOriginalIdx: f32 = originalIdx - floor(originalIdx); + var coefs = getCubicInterpolationCoefs(fractOriginalIdx); + + if (${useExtrapolation} && (originalIdx < 0 || originalIdx > (${inputShape[idx]} - 1))) { + return ${extrapolationValue}; + } + var data: array = array(0.0, 0.0, 0.0, 0.0); + for (var i: i32 = -1; i < 3; i++) { + var ${direction}: f32 = originalIdx + f32(i); + if (${direction} < 0 || ${direction} >= ${inputShape[idx]}) { + if (${excludeOutside}) { + coefs[i + 1] = 0.0; + continue; + } else if (${useExtrapolation}) { + return ${extrapolationValue}; + } else { + ${direction} = max(0, min(${direction}, ${inputShape[idx]} - 1)); + } + } + var inputIndicesCopy: ${input.type.indices} = inputIndices; + inputIndicesCopy[${idx}] = u32(${direction}); + data[i + 1] = ${idx === heightIdx ? `input[${input.indicesToOffset('inputIndicesCopy')}];` : ` + rowCubicInterpolation(inputIndicesCopy, outputIndices);`} + } + return cubicInterpolation1D(data, coefs); + }`; + }; + + return ` + ${createCubicInterpolationFunction(heightIdx)}; + ${createCubicInterpolationFunction(widthIdx)}; + fn getCubicInterpolationCoefs(s: f32) -> array { + var absS = abs(s); + var coeffs: array = array(0.0, 0.0, 0.0, 0.0); + var oneMinusAbsS: f32 = 1.0 - absS; + var twoMinusAbsS: f32 = 2.0 - absS; + var onePlusAbsS: f32 = 1.0 + absS; + coeffs[0] = ((${cubicCoeffA} * onePlusAbsS - 5 * ${cubicCoeffA}) * onePlusAbsS + 8 * ${ + cubicCoeffA}) * onePlusAbsS - 4 * ${cubicCoeffA}; + coeffs[1] = ((${cubicCoeffA} + 2) * absS - (${cubicCoeffA} + 3)) * absS * absS + 1; + coeffs[2] = ((${cubicCoeffA} + 2) * oneMinusAbsS - (${cubicCoeffA} + 3)) * oneMinusAbsS * oneMinusAbsS + 1; + coeffs[3] = ((${cubicCoeffA} * twoMinusAbsS - 5 * ${cubicCoeffA}) * twoMinusAbsS + 8 * ${ + cubicCoeffA}) * twoMinusAbsS - 4 * ${cubicCoeffA}; + return coeffs; + } + + fn cubicInterpolation1D(x: array, coefs: array) -> f32 { + var coefsSum: f32 = coefs[0] + coefs[1] + coefs[2] + coefs[3]; + return (x[0] * coefs[0] + x[1] * coefs[1]+ x[2] * coefs[2]+ x[3] * coefs[3]) / coefsSum; + } + + fn bicubicInterpolation(outputIndices: ${output.type.indices}) -> f32 { + var inputIndices: ${input.type.indices} = outputIndices; + return colCubicInterpolation(inputIndices, outputIndices); + } + `; + }; + +const createResizeProgramInfo = + (metadata: ProgramMetadata, inputTensor: TensorView, attributes: ResizeAttributes, opsetVersion: number, + scalesInput: readonly number[], sizes: readonly number[], roiInput: readonly number[]): ProgramInfo => { + const inputShape = inputTensor.dims; + const roi = updateRoI(roiInput, attributes.axes, inputShape.length); + + let outputShape = initOutputShape(inputShape, scalesInput, sizes, attributes.axes); + let scales = scalesInput.slice(); + if (scalesInput.length === 0) { + scales = inputShape.map((value, index) => value === 0 ? 1.0 : outputShape[index] / value); + if (attributes.keepAspectRatioPolicy !== 'stretch') { + outputShape = adjustOutputShape(inputShape, outputShape, scales, attributes); + } + } + const output = outputVariable('output', inputTensor.dataType, outputShape); + const input = inputVariable('input', inputTensor.dataType, inputShape); + const outputSize = ShapeUtil.size(outputShape); + const noScale = inputShape.length === outputShape.length && inputShape.every((d, i) => d === outputShape[i]); + const useExtrapolation = attributes.coordinateTransformMode === 'tf_crop_and_resize'; + const getShaderSource = (shaderHelper: ShaderHelper) => ` + ${getOriginalCoordinateFromResizedCoordinate(attributes.coordinateTransformMode)}; + ${(() => { + switch (attributes.mode) { + case 'nearest': + return ` + ${checkInputIndices(input, inputShape)}; + ${getNearestPixelFromOriginal(attributes.nearestMode, opsetVersion)}; + ${ + calculateInputIndicesFromOutputIndices( + input, output, inputShape, outputShape, scales, roi, useExtrapolation)}; + `; + case 'linear': + return ` + ${calculateOriginalIndicesFromOutputIndices(output, inputShape, outputShape, scales, roi)}; + ${ + bilinearInterpolation( + input, output, inputShape, outputShape, scales, useExtrapolation, attributes.extrapolationValue)}; + `; + case 'cubic': + return ` + ${ + bicubicInterpolation( + input, output, inputShape, outputShape, scales, roi, attributes.cubicCoeffA, useExtrapolation, + attributes.extrapolationValue, attributes.excludeOutside)}; + `; + default: + throw Error('Invalid resize mode'); + } + })()}; + ${shaderHelper.declareVariables(input, output)} + ${shaderHelper.mainStart()} + ${shaderHelper.guardAgainstOutOfBoundsWorkgroupSizes(outputSize)} + if (${noScale}) { + output[global_idx] = input[global_idx]; + } else { + let outputIndices = ${output.offsetToIndices('global_idx')}; + var inputIndices: ${input.type.indices}; + ${(() => { + switch (attributes.mode) { + case 'nearest': + return `inputIndices = calculateInputIndicesFromOutputIndices(outputIndices); + if (checkInputIndices(inputIndices)) { + output[global_idx] = input[${input.indicesToOffset('inputIndices')}]; + } else { + output[global_idx] = ${attributes.extrapolationValue}; + }`; + case 'linear': + return 'output[global_idx] = bilinearInterpolation(outputIndices);'; + case 'cubic': + return 'output[global_idx] = bicubicInterpolation(outputIndices);'; + default: + throw Error(`Unsupported resize mode: ${attributes.mode}`); + } + })()}; + } + }`; + + return { + ...metadata, + getShaderSource, + outputs: [{dims: outputShape, dataType: inputTensor.dataType, gpuDataType: GpuDataType.default}], + dispatchGroup: () => ({x: Math.ceil(outputSize / 64 /* workgroup size */)}) + }; + }; + +export const createResizeProgramInfoLoader = + (input: TensorView, attributes: ResizeAttributes, opsetVersion: number, scales: readonly number[], + sizes: readonly number[], roi: readonly number[]): ProgramInfoLoader => { + const metadata: ProgramMetadata = { + name: 'Resize', + inputTypes: [GpuDataType.default], + cacheHint: attributes.cacheKey + opsetVersion.toString() + + (scales.length > 0 ? '_scales_' + scales.toString() : '') + + (sizes.length > 0 ? '_sizes_' + sizes.toString() : ''), + }; + return { + ...metadata, + get: () => createResizeProgramInfo(metadata, input, attributes, opsetVersion, scales, sizes, roi) + }; + }; + +const getOpsetVersionFromCustomDataBuffer = (context: ComputeContext): number => { + const customDataBuffer = context.customDataBuffer; + const customDataBuffer32 = new Uint32Array(customDataBuffer, customDataBuffer.byteOffset, 1); + const opsetVersion = customDataBuffer32[0]; + return opsetVersion; +}; + +export const resize = (context: ComputeContext, attributes: ResizeAttributes): void => { + const scales: number[] = []; + const sizes: number[] = []; + const roi: number[] = []; + const opsetVersion = getOpsetVersionFromCustomDataBuffer(context); + validateInputs(context.inputs, attributes, opsetVersion, scales, sizes, roi); + context.compute( + createResizeProgramInfoLoader(context.inputs[0], attributes, opsetVersion, scales, sizes, roi), {inputs: [0]}); +}; + +export const parseResizeAttributes = (attributes: Record): ResizeAttributes => { + const antialias = attributes.antialias as number; + const axes = attributes.axes as number[]; + const coordinateTransformMode: CoordinateTransformMode = + attributes.coordinateTransformMode as CoordinateTransformMode; + const cubicCoeffA = attributes.cubicCoeffA as number; + const excludeOutside = attributes.excludeOutside as number !== 0; + const extrapolationValue = attributes.extrapolationValue as number; + const keepAspectRatioPolicy: KeepAspectRatioPolicy = attributes.keepAspectRatioPolicy as KeepAspectRatioPolicy; + const mode: Mode = attributes.mode as Mode; + // If nearestMode is not specified, use simple mode. + const nearestMode: NearestMode = (attributes.nearestMode === '' ? 'simple' : attributes.nearestMode) as NearestMode; + return createAttributeWithCacheKey({ + antialias, + axes, + coordinateTransformMode, + cubicCoeffA, + excludeOutside, + extrapolationValue, + keepAspectRatioPolicy, + mode, + nearestMode + }); +}; diff --git a/js/web/lib/wasm/jsep/webgpu/ops/skip-layer-norm.ts b/js/web/lib/wasm/jsep/webgpu/ops/skip-layer-norm.ts new file mode 100644 index 0000000000000..7bfdd73b8af18 --- /dev/null +++ b/js/web/lib/wasm/jsep/webgpu/ops/skip-layer-norm.ts @@ -0,0 +1,195 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import {DataType} from '../../../wasm-common'; +import {TensorView} from '../../tensor-view'; +import {ShapeUtil} from '../../util'; +import {AttributeWithCacheKey, createAttributeWithCacheKey} from '../attribute-with-cache-key'; +import {ComputeContext, GpuDataType, ProgramInfo, ProgramInfoLoader, ProgramMetadata} from '../types'; + +import {ShaderHelper, tensorTypeToWsglStorageType} from './common'; + +export interface SkipLayerNormAttributes extends AttributeWithCacheKey { + epsilon: number; +} + +const validateInputs = (inputs: readonly TensorView[]): void => { + if (!inputs || inputs.length < 3) { + throw new Error('layerNorm requires at least 3 inputs.'); + } + + if (inputs[0].dataType !== DataType.float || inputs[1].dataType !== DataType.float) { + throw new Error('inputs should be float type'); + } + const input: TensorView = inputs[0]; + const skip: TensorView = inputs[1]; + const gamma: TensorView = inputs[2]; + + if (input.dataType !== skip.dataType || input.dataType !== gamma.dataType) { + throw new Error('All inputs must have the same data type'); + } + + if (input.dims.length !== 3 && input.dims.length !== 2) { + throw new Error('Input must be 2D or 3D'); + } + + if (skip.dims.length !== 3 && skip.dims.length !== 2) { + throw new Error('Skip must be 2D or 3D'); + } + + const hiddenSize = input.dims[input.dims.length - 1]; + const sequenceLength = input.dims[input.dims.length - 2]; + if (skip.dims[skip.dims.length - 1] !== hiddenSize) { + throw new Error('Skip must have the same hidden size as input'); + } + if (skip.dims[skip.dims.length - 2] !== sequenceLength) { + throw new Error('Skip must have the same sequence length as input'); + } + + if (gamma.dims.length !== 1) { + throw new Error('Gamma must be 1D'); + } + if (gamma.dims[gamma.dims.length - 1] !== hiddenSize) { + throw new Error('Gamma must have the same hidden size as input'); + } + if (inputs.length > 3) { + const beta: TensorView = inputs[3]; + if (beta.dims.length !== 1) { + throw new Error('Beta must be 1D'); + } + if (beta.dims[beta.dims.length - 1] !== hiddenSize) { + throw new Error('Beta must have the same hidden size as input'); + } + } + + if (inputs.length > 4) { + const bias: TensorView = inputs[4]; + if (bias.dims.length !== 1) { + throw new Error('Bias must be 1D'); + } + if (bias.dims[bias.dims.length - 1] !== hiddenSize) { + throw new Error('Bias must have the same hidden size as input'); + } + } +}; + +const createSkipLayerNormProgramInfo = + (metadata: ProgramMetadata, inputs: readonly TensorView[], attributes: SkipLayerNormAttributes, outputCount: number, + isTraining: boolean): ProgramInfo => { + const inputShape = inputs[0].dims; + const inputSize = ShapeUtil.size(inputShape); + const outputShape = inputShape; + const outputSize = inputSize; + const hiddenSize = inputShape.slice(-1)[0]; + const meanInvStdDevDim = isTraining ? inputShape.slice(0, -1).concat(1) : []; + const hasBetaInput = inputs.length > 3; + const hasBiasInput = inputs.length > 4; + const dataType = tensorTypeToWsglStorageType(inputs[0].dataType); + const hasMeanOutput = isTraining && outputCount > 1; + const hasInvStdDevOutput = isTraining && outputCount > 2; + const hasInputSkipBiasSumOutput = outputCount > 3; + let bindingNumber = 0; + const getShaderSource = (shaderHelper: ShaderHelper) => ` + const hiddenSize: u32 = ${hiddenSize}; + const epsilon: f32 = ${attributes.epsilon}; + + @group(0) @binding(${bindingNumber++}) var x : array<${dataType}>; + @group(0) @binding(${bindingNumber++}) var skip : array<${dataType}>; + @group(0) @binding(${bindingNumber++}) var gamma : array<${dataType}>; + ${hasBetaInput ? `@group(0) @binding(${bindingNumber++}) var beta : array<${dataType}>;` : ''} + ${hasBiasInput ? `@group(0) @binding(${bindingNumber++}) var bias : array<${dataType}>;` : ''} + @group(0) @binding(${bindingNumber++}) var output : array<${dataType}>; + ${ + hasMeanOutput ? + `@group(0) @binding(${bindingNumber++}) var meanOutput : array<${dataType}>;` : + ''} + ${ + hasInvStdDevOutput ? + `@group(0) @binding(${bindingNumber++}) var invStdOutput : array<${dataType}>;` : + ''} + ${ + hasInputSkipBiasSumOutput ? + `@group(0) @binding(${bindingNumber++}) var inputSkipBiasSum : array<${dataType}>;` : + ''} + + ${shaderHelper.mainStart()} + ${shaderHelper.guardAgainstOutOfBoundsWorkgroupSizes(outputSize / hiddenSize)} + let offset = global_idx * hiddenSize; + var sum: f32 = 0.0; + var squareSum: f32 = 0.0; + for (var i: u32 = 0; i < hiddenSize; i++) { + let skipValue = skip[offset + i]; + let biasValue = ${hasBiasInput ? 'bias[i]' : '0.0'}; + let inputValue = x[offset + i]; + let value = inputValue + skipValue + biasValue; + ${hasInputSkipBiasSumOutput ? 'inputSkipBiasSum[offset + i] = value;' : ''} + output[offset + i] = value; + sum += value; + squareSum += value * value; + } + let mean: f32 = sum / f32(hiddenSize); + let variance: f32 = sqrt(squareSum / f32(hiddenSize) - mean * mean + epsilon); + ${hasMeanOutput ? 'meanOutput[global_idx] = mean;' : ''} + ${hasInvStdDevOutput ? 'invStdOutput[global_idx] = 1.0 / variance;' : ''} + for (var i: u32 = 0; i < hiddenSize; i++) { + output[offset + i] = (output[offset + i] - mean) / variance * gamma[i] + ${hasBetaInput ? 'beta[i]' : '0.0'}; + } + }`; + const outputs = [{dims: outputShape, dataType: inputs[0].dataType, gpuDataType: GpuDataType.default}]; + if (outputCount > 1) { + outputs.push({dims: meanInvStdDevDim, dataType: inputs[0].dataType, gpuDataType: GpuDataType.default}); + } + if (outputCount > 2) { + outputs.push({dims: meanInvStdDevDim, dataType: inputs[0].dataType, gpuDataType: GpuDataType.default}); + } + if (outputCount > 3) { + outputs.push({dims: inputShape, dataType: inputs[0].dataType, gpuDataType: GpuDataType.default}); + } + + return { + ...metadata, + getShaderSource, + outputs, + dispatchGroup: () => ({x: Math.ceil(outputSize / hiddenSize / 64)}) + }; + }; + +const createSkipLayerNormProgramInfoLoader = + (inputs: readonly TensorView[], attributes: SkipLayerNormAttributes, outputCount: number, isTraining: boolean): + ProgramInfoLoader => { + const inputTypes = new Array(inputs.length).fill(GpuDataType.default); + const metadata: ProgramMetadata = { + name: 'SkipLayerNormalization', + inputTypes, + cacheHint: attributes.cacheKey, + }; + return { + ...metadata, + get: () => createSkipLayerNormProgramInfo(metadata, inputs, attributes, outputCount, isTraining) + }; + }; + +export const skipLayerNorm = (context: ComputeContext, attributes: SkipLayerNormAttributes): void => { + // TODO: initialize isTraining from ComputeContext + const isTraining = false; + validateInputs(context.inputs); + // Mean and InvStdDev are only used in training mode and are not required for inference. + // They are added here for completeness only. + const outputs = [0]; + if (context.outputCount > 1) { + outputs.push(isTraining ? 1 : -3); + } + if (context.outputCount > 2) { + outputs.push(isTraining ? 2 : -3); + } + if (context.outputCount > 3) { + outputs.push(3); + } + context.compute( + createSkipLayerNormProgramInfoLoader(context.inputs, attributes, context.outputCount, isTraining), {outputs}); +}; + +export const parseSkipLayerNormAttributes = (attributes: Record): SkipLayerNormAttributes => { + const epsilon = attributes.epsilon as number; + return createAttributeWithCacheKey({epsilon}); +}; diff --git a/js/web/lib/wasm/jsep/webgpu/ops/slice.ts b/js/web/lib/wasm/jsep/webgpu/ops/slice.ts new file mode 100644 index 0000000000000..257b9ebc1fdac --- /dev/null +++ b/js/web/lib/wasm/jsep/webgpu/ops/slice.ts @@ -0,0 +1,199 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import {DataType} from '../../../wasm-common'; +import {TensorView} from '../../tensor-view'; +import {ShapeUtil} from '../../util'; +import {AttributeWithCacheKey, createAttributeWithCacheKey} from '../attribute-with-cache-key'; +import {ComputeContext, GpuDataType, ProgramInfo, ProgramInfoLoader, ProgramMetadata, TensorInfo} from '../types'; + +import {IndicesHelper, inputVariable, outputVariable, ShaderHelper} from './common'; + +export interface SliceAttributes extends AttributeWithCacheKey { + readonly starts: number[]; + readonly ends: number[]; + readonly axes: number[]; +} + +const validateInputs = (inputs: readonly TensorView[], attributes: SliceAttributes): void => { + if (!inputs || inputs.length < 1) { + throw new Error('too few inputs'); + } + if (attributes.axes.length !== 0) { + if (attributes.axes.length !== attributes.starts.length || attributes.axes.length !== attributes.ends.length) { + throw new Error('axes, starts and ends must have the same length'); + } + } else if (attributes.starts.length !== attributes.ends.length) { + throw new Error('starts and ends must have the same length'); + } + inputs.slice(1).forEach((_, idx) => { + if (inputs[idx + 1].dataType !== DataType.int32 && inputs[idx + 1].dataType !== DataType.int64) { + throw new Error(`Input ${idx} must be an array of int32 or int64`); + } + }); +}; + +const readInput = (inputs: readonly TensorView[], idx: number): number[] => { + const input: number[] = []; + if (inputs.length > idx) { + if (inputs[idx].dataType === DataType.int64) { + inputs[idx].getBigInt64Array().forEach(v => input.push(Number(v))); + } else if (inputs[idx].dataType === DataType.int32) { + inputs[idx].getInt32Array().forEach(v => input.push(Number(v))); + } else { + throw new Error(`Input ${idx} must be an array of int32 or int64`); + } + } + return input; +}; + +const createSliceAttributesFromInputs = + (inputs: readonly TensorView[], attributes: SliceAttributes): SliceAttributes => { + if (inputs.length > 1) { + const starts: number[] = readInput(inputs, 1); + const ends: number[] = readInput(inputs, 2); + let axes: number[] = readInput(inputs, 3); + if (axes.length === 0) { + axes = [...Array(inputs[0].dims.length).keys()]; + } + return createAttributeWithCacheKey({starts, ends, axes}); + } else { + return attributes; + } + }; + +const fixStartEndValues = + (value: number, index: number, inputShape: readonly number[], axes: readonly number[], steps: readonly number[]): + number => { + let newValue = value; + if (value < 0) { + newValue += inputShape[axes[index]]; + } + if (steps[index] < 0) { + return Math.max(0, Math.min(newValue, inputShape[axes[index]] - 1)); + } else { + return Math.max(0, Math.min(newValue, inputShape[axes[index]])); + } + }; + +const calculateInputIndicesImpl = + (input: IndicesHelper, output: IndicesHelper, inputShape: readonly number[], outputShape: readonly number[]): + string => `fn calculateInputIndices(outputIndices: ${output.type.indices}) -> ${input.type.indices} { + var inputIndices: ${input.type.indices}; + var carry = 0u; + for (var i = ${inputShape.length}; i >= 0; i--) { + var outputIndex = ${outputShape.length === 1 ? 'outputIndices' : 'outputIndices[i]'}; + var inputIndex = outputIndex * steps[i] + starts[i] + carry; + carry = inputIndex / inputShape[i]; + inputIndex = inputIndex % inputShape[i]; + if (signs[i] < 0) { + inputIndex = inputShape[i] - inputIndex - 1u + starts[i]; + } + ${inputShape.length === 1 ? 'inputIndices' : 'inputIndices[i]'} = inputIndex; + } + return inputIndices; + }`; + +const createSliceProgramInfo = + (metadata: ProgramMetadata, inputs: readonly TensorView[], attributes: SliceAttributes): ProgramInfo => { + const inputShape = inputs[0].dims; + const inputSize = ShapeUtil.size(inputShape); + const axes = (attributes.axes.length > 0) ? ShapeUtil.normalizeAxes(attributes.axes, inputShape.length) : + [...Array(inputShape.length).keys()]; + let steps = readInput(inputs, 4); + steps.forEach((step) => step !== 0 || (() => { + throw new Error('step cannot be 0'); + })); + if (steps.length === 0) { + steps = Array(axes.length).fill(1); + } + const starts = attributes.starts.map((start, i) => fixStartEndValues(start, i, inputShape, axes, steps)); + + const ends = attributes.ends.map((end, i) => fixStartEndValues(end, i, inputShape, axes, steps)); + + if (axes.length !== inputShape.length) { + for (let i = 0; i < inputShape.length; ++i) { + if (!axes.includes(i)) { + starts.splice(i, 0, 0); + ends.splice(i, 0, inputShape[i]); + steps.splice(i, 0, 1); + } + } + } + const signs = steps.map(step => Math.sign(step)); + // Convert negative steps to positive steps and reverse starts and ends + steps.forEach((step, i, array) => { + if (step < 0) { + const numSteps = (ends[i] - starts[i]) / step; + const newEnd = starts[i]; + const newStart = newEnd + numSteps * steps[i]; + starts[i] = newStart; + ends[i] = newEnd; + array[i] = -step; + } + }); + + const outputShape = inputShape.slice(0); + axes.forEach((axis, _) => { + outputShape[axis] = Math.ceil((ends[axis] - starts[axis]) / steps[axis]); + }); + + const outputTensorInfo: + TensorInfo = {dims: outputShape, dataType: inputs[0].dataType, gpuDataType: GpuDataType.default}; + + const output = outputVariable('output', inputs[0].dataType, outputShape); + const input = inputVariable('input', inputs[0].dataType, inputShape); + const outputSize = ShapeUtil.size(outputShape); + + const getShaderSource = (shaderHelper: ShaderHelper) => ` + ${shaderHelper.declareVariables(input, output)} + const signs = array(${signs.map(i => `${i}i`).join(',')}); + const starts = array(${starts.map(i => `${i}u`).join(',')}); + const ends = array(${ends.map(i => `${i}u`).join(',')}); + const steps = array(${steps.map(i => `${i}u`).join(',')}); + const inputShape = array(${inputShape.map(i => `${i}u`).join(',')}); + + ${calculateInputIndicesImpl(input, output, inputShape, outputShape)} + ${shaderHelper.mainStart()} + ${shaderHelper.guardAgainstOutOfBoundsWorkgroupSizes(outputSize)} + let outputIndices = ${output.offsetToIndices('global_idx')}; + let inputIndices = calculateInputIndices(outputIndices); + ${output.setByOffset('global_idx', input.getByIndices('inputIndices'))} + }`; + return { + ...metadata, + getShaderSource, + outputs: [outputTensorInfo], + dispatchGroup: () => ({x: Math.ceil(inputSize / 64 /* workgroup size */)}) + }; + }; + +const createSliceProgramInfoLoader = + (inputs: readonly TensorView[], attributes: SliceAttributes): ProgramInfoLoader => { + const updatedAttributes = createSliceAttributesFromInputs(inputs, attributes); + const metadata: ProgramMetadata = { + name: 'Slice', + inputTypes: [GpuDataType.default], + cacheHint: updatedAttributes.cacheKey + (inputs.length > 4 ? 'steps_' + inputs[4].dims.toString() : '') + }; + return {...metadata, get: () => createSliceProgramInfo(metadata, inputs, updatedAttributes)}; + }; + +export const slice = (context: ComputeContext, attributes: SliceAttributes): void => { + validateInputs(context.inputs, attributes); + const programInfoLoader = createSliceProgramInfoLoader(context.inputs, attributes); + const program = programInfoLoader.get(); + if (ShapeUtil.size(program.outputs[0].dims) > 0) { + context.compute(programInfoLoader, {inputs: [0]}); + } else { + // TODO: support empty output + throw new Error('slice: output size is 0'); + } +}; + +export const parseSliceAttributes = (attributes: Record): SliceAttributes => { + const starts = attributes.starts as number[]; + const ends = attributes.ends as number[]; + const axes = attributes.axes as number[]; + return createAttributeWithCacheKey({starts, ends, axes}); +}; diff --git a/js/web/lib/wasm/jsep/webgpu/ops/softmax.ts b/js/web/lib/wasm/jsep/webgpu/ops/softmax.ts new file mode 100644 index 0000000000000..495a4bcea4f47 --- /dev/null +++ b/js/web/lib/wasm/jsep/webgpu/ops/softmax.ts @@ -0,0 +1,145 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// TODO: this is the same naive implementation we use for reduce that has +// performance limitations when the reduced axis is long. Need to add +// a optimized codepath for this. + +import {TensorView} from '../../tensor-view'; +import {ShapeUtil} from '../../util'; +import {AttributeWithCacheKey, createAttributeWithCacheKey} from '../attribute-with-cache-key'; +import {ComputeContext, GpuDataType, ProgramInfo} from '../types'; + +import {ShaderHelper, tensorTypeToWsglStorageType} from './common'; + +const validateInputs = (inputs: readonly TensorView[]): void => { + if (!inputs || inputs.length !== 1) { + throw new Error('Softmax op requires 1 input.'); + } +}; + +export interface SoftmaxAttributes extends AttributeWithCacheKey { + readonly axis: number; +} + +export const softmaxProgramMetadata = { + name: 'Softmax', + inputTypes: [GpuDataType.default] +}; + + +const createSoftmaxProgramInfo = (input: TensorView, attributes: SoftmaxAttributes): ProgramInfo => { + const dataType = tensorTypeToWsglStorageType(input.dataType); + const shape = input.dims; + const outputSize = ShapeUtil.size(shape); + const WG = 64; + let axis = attributes.axis; + if (axis < 0) { + axis = shape.length + axis; + } + if (axis < shape.length - 1) { + throw new Error('softmax only supports last axis for now.'); + } + + const cols = shape[axis]; + const rows = outputSize / cols; + + // 6.2.4 in wgsl spec + const threadMaxDecl = dataType === 'f32' ? 'var threadMax: f32 = -3.402823e+38f;' : 'var threadMax: f16 = -65504.0h;'; + const getShaderSource = (_shaderHelper: ShaderHelper) => ` + var rowMaxShared : ${dataType}; + var rowSumShared : ${dataType}; + var threadShared : array<${dataType}, ${WG}>; + + @group(0) @binding(0) var x : array<${dataType}>; + @group(0) @binding(1) var result : array<${dataType}>; + + fn getValue(row: i32, col: i32, row_stride: i32) -> ${dataType} { + let index = row * row_stride + col; + return x[index]; + } + + fn setValue(row: i32, col: i32, row_stride: i32, value: ${dataType}) { + let index = row * row_stride + col; + result[index] = value; + } + + @compute @workgroup_size(${WG}, 1, 1) + fn main(@builtin(local_invocation_id) local_id : vec3, @builtin(global_invocation_id) global_id : vec3u) { + let gindex = i32(global_id.x); + let lindex = i32(local_id.x); + const wg = ${WG}; + let row = gindex / wg; + let cols = ${cols}; + let row_stride : i32 = ${cols}; + + // find the rows max + ${threadMaxDecl} + for (var col = lindex; col < cols; col += wg) { + let value = getValue(row, col, row_stride); + threadMax = max(threadMax, value); + } + if (lindex < cols) { + threadShared[lindex] = threadMax; + } + workgroupBarrier(); + + var reduceSize = min(cols, wg); + for (var currSize = reduceSize >> 1; currSize > 0; currSize = reduceSize >> 1) { + reduceSize = currSize + (reduceSize & 1); + if (lindex < currSize) { + threadShared[lindex] = max(threadShared[lindex], threadShared[lindex + reduceSize]); + } + workgroupBarrier(); + } + if (lindex == 0) { + rowMaxShared = threadShared[0]; + } + workgroupBarrier(); + + // find the rows sum + var threadSum: ${dataType} = 0.0; + for (var col = lindex; col < cols; col += wg) { + let subExp = exp(getValue(row, col, row_stride) - rowMaxShared); + threadSum += subExp; + } + threadShared[lindex] = threadSum; + workgroupBarrier(); + + for (var currSize = wg >> 1; currSize > 0; currSize = currSize >> 1) { + if (lindex < currSize) { + threadShared[lindex] = threadShared[lindex] + threadShared[lindex + currSize]; + } + workgroupBarrier(); + } + if (lindex == 0) { + rowSumShared = threadShared[0]; + } + workgroupBarrier(); + + // calculate final value for each element in the row + for (var col = lindex; col < cols; col += wg) { + let value = exp(getValue(row, col, row_stride) - rowMaxShared) / rowSumShared; + setValue(row, col, row_stride, value); + } + }`; + return { + ...softmaxProgramMetadata, + outputs: [{dims: shape, dataType: input.dataType, gpuDataType: GpuDataType.default}], + getShaderSource, + dispatchGroup: () => ({x: rows}) + }; +}; + + +export const softmax = (context: ComputeContext, attributes: SoftmaxAttributes): void => { + validateInputs(context.inputs); + context.compute({ + ...softmaxProgramMetadata, + cacheHint: attributes.cacheKey, + get: () => createSoftmaxProgramInfo(context.inputs[0], attributes) + }); +}; + +export const parseSoftmaxAttributes = (attributes: Record): SoftmaxAttributes => + createAttributeWithCacheKey({axis: attributes.axis as number}); diff --git a/js/web/lib/wasm/jsep/webgpu/ops/split.ts b/js/web/lib/wasm/jsep/webgpu/ops/split.ts new file mode 100644 index 0000000000000..3367091bbac23 --- /dev/null +++ b/js/web/lib/wasm/jsep/webgpu/ops/split.ts @@ -0,0 +1,133 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import {TensorView} from '../../tensor-view'; +import {ShapeUtil} from '../../util'; +import {AttributeWithCacheKey, createAttributeWithCacheKey} from '../attribute-with-cache-key'; +import {ComputeContext, GpuDataType, ProgramInfo, ProgramInfoLoader, ProgramMetadata, TensorInfo} from '../types'; + +import {IndicesHelper, inputVariable, outputVariable, ShaderHelper} from './common'; + +export interface SplitAttributes extends AttributeWithCacheKey { + readonly axis: number; + readonly numOutputs: number; + readonly splitSizes: number[]; +} + +const validateInputs = (inputs: readonly TensorView[]): void => { + if (!inputs || inputs.length < 1) { + throw new Error('too few inputs'); + } +}; + +const createSplitAttributesFromInputs = + (inputs: readonly TensorView[], attributes: SplitAttributes): SplitAttributes => { + const splitSizes: number[] = []; + let numOutputs: number = attributes.numOutputs; + if (inputs[1].dims[0] > 0) { + inputs[1].getBigInt64Array().forEach(v => splitSizes.push(Number(v))); + numOutputs = splitSizes.length; + } + return createAttributeWithCacheKey({numOutputs, axis: attributes.axis, splitSizes}); + }; + +const calculateOutputIndexImpl = (numberOfTensors: number): string => ` +fn calculateOutputIndex(index: u32) -> u32 { + for (var i: u32 = 0u; i < ${numberOfTensors}u; i += 1u ) { + if (index < sizeInConcatAxis[i]) { + return i; + } + } + return ${numberOfTensors}u; +}`; +const writeBufferDataImpl = (outputs: readonly IndicesHelper[]) => { + const numberOfTensors = outputs.length; + const codeLines: string[] = []; + for (let i = 0; i < numberOfTensors; ++i) { + const returnSnippet = outputs[i].setByIndices('indices', 'input[global_idx]'); + if (numberOfTensors === 1) { + codeLines.push(returnSnippet); + } else if (i === 0) { + codeLines.push(`if (outputNumber == ${i}u) { ${returnSnippet} }`); + } else if (i === numberOfTensors - 1) { + codeLines.push(`else { ${returnSnippet} }`); + } else { + codeLines.push(`else if (outputNumber == ${i}) { ${returnSnippet} }`); + } + } + return ` + fn writeBufferData(outputNumber: u32, indices: ${outputs[0].type.indices}, global_idx: u32) { + ${codeLines.join('\n')} + }`; +}; + +const createSplitProgramInfo = + (metadata: ProgramMetadata, inputs: readonly TensorView[], attributes: SplitAttributes): ProgramInfo => { + const inputShape = inputs[0].dims; + const inputSize = ShapeUtil.size(inputShape); + const dataType = inputs[0].dataType; + const rank = inputShape.length; + const axis = attributes.axis; + const adjustedAxis = (axis < 0) ? inputShape.length + axis : axis; + const outputs = new Array(attributes.numOutputs); + const input = inputVariable('input', dataType, inputShape); + const sizeInConcatAxis = new Array(attributes.numOutputs); + const outputsTensorInfo: TensorInfo[] = []; + const outputShapes: number[][] = []; + let previousSum = 0; + for (let i = 0; i < attributes.numOutputs; i++) { + previousSum += attributes.splitSizes[i]; + sizeInConcatAxis[i] = previousSum; + const outputShape = inputShape.slice(); + outputShape[attributes.axis] = attributes.splitSizes[i]; + outputShapes.push(outputShape); + outputs[i] = outputVariable(`output${i}`, dataType, outputShapes[i]); + outputsTensorInfo.push({dims: outputShapes[i], dataType: inputs[0].dataType, gpuDataType: GpuDataType.default}); + } + const indicesAxis = rank < 2 ? 'indices' : `indices[${adjustedAxis}]`; + const getShaderSource = (shaderHelper: ShaderHelper) => ` + ${shaderHelper.declareVariables(input, ...outputs)} + const sizeInConcatAxis = array(${sizeInConcatAxis.map(i => `${i}u`).join(',')}); + ${calculateOutputIndexImpl(sizeInConcatAxis.length)} + ${writeBufferDataImpl(outputs)} + + ${shaderHelper.mainStart()} + ${shaderHelper.guardAgainstOutOfBoundsWorkgroupSizes(inputSize)} + + var indices = ${input.offsetToIndices('global_idx')}; + let outputNumber = calculateOutputIndex(${indicesAxis}); + if (outputNumber != 0) { + ${indicesAxis} -= sizeInConcatAxis[outputNumber - 1u]; + } + writeBufferData(outputNumber, indices, global_idx); + }`; + return { + ...metadata, + getShaderSource, + outputs: outputsTensorInfo, + dispatchGroup: () => ({x: Math.ceil(inputSize / 64 /* workgroup size */)}) + }; + }; + +const createSplitProgramInfoLoader = + (inputs: readonly TensorView[], attributes: SplitAttributes): ProgramInfoLoader => { + const updatedAttributes = inputs.length === 1 ? attributes : createSplitAttributesFromInputs(inputs, attributes); + const metadata: + ProgramMetadata = {name: 'Split', inputTypes: [GpuDataType.default], cacheHint: updatedAttributes.cacheKey}; + return {...metadata, get: () => createSplitProgramInfo(metadata, [inputs[0]], updatedAttributes)}; + }; + +export const split = (context: ComputeContext, attributes: SplitAttributes): void => { + validateInputs(context.inputs); + context.compute(createSplitProgramInfoLoader(context.inputs, attributes), {inputs: [0]}); +}; + +export const parseSplitAttributes = (attributes: Record): SplitAttributes => { + const axis = attributes.axis as number; + const splitSizes: number[] = attributes.splitSizes as number[]; + const numOutputs = attributes.numOutputs as number < 0 ? splitSizes.length : attributes.numOutputs as number; + if (numOutputs !== splitSizes.length) { + throw new Error('numOutputs and splitSizes lengh must be equal'); + } + return createAttributeWithCacheKey({axis, numOutputs, splitSizes}); +}; diff --git a/js/web/lib/wasm/jsep/webgpu/ops/tile.ts b/js/web/lib/wasm/jsep/webgpu/ops/tile.ts new file mode 100644 index 0000000000000..109c29bfc8a80 --- /dev/null +++ b/js/web/lib/wasm/jsep/webgpu/ops/tile.ts @@ -0,0 +1,96 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import {DataType} from '../../../wasm-common'; +import {TensorView} from '../../tensor-view'; +import {ShapeUtil} from '../../util'; +import {ComputeContext, GpuDataType, ProgramInfo, ProgramMetadata} from '../types'; + +import {inputVariable, outputVariable, ShaderHelper} from './common'; + +export const tileProgramMetadata = { + name: 'Tile', + inputTypes: [GpuDataType.default] +}; + +const getRepeats = (repeatsTensorView: TensorView): readonly number[] => + Array.from(repeatsTensorView.getBigInt64Array(), Number); + + +const validateInputs = (inputs: readonly TensorView[]): void => { + if (!inputs || inputs.length !== 2) { + throw new Error('Tile requires 2 inputs.'); + } + + if (inputs[0].dataType !== DataType.float && inputs[0].dataType !== DataType.int32 && + inputs[0].dataType !== DataType.uint32) { + throw new Error('Tile only support float, int32, and uint32 data types'); + } + + if (inputs[1].dataType !== DataType.int64) { + throw new Error('Tile `repeats` input should be of int64 data type'); + } + + if (inputs[1].dims.length !== 1) { + throw new Error('Tile `repeats` input should be 1-D'); + } + + const repeats: readonly number[] = getRepeats(inputs[1]); + + if (repeats.length !== inputs[0].dims.length) { + throw new Error('Tile `repeats` input should have same number of elements as rank of input data tensor'); + } +}; + +const getOutputShape = (inputShape: readonly number[], repeats: readonly number[]): readonly number[] => { + const outputShape: number[] = []; + + for (let i = 0; i < inputShape.length; ++i) { + outputShape.push(inputShape[i] * repeats[i]); + } + + return outputShape; +}; + +export const createTileProgramInfo = + (tileProgramMetadata: ProgramMetadata, inputs: readonly TensorView[]): ProgramInfo => { + const inputShape = inputs[0].dims; + const repeats: readonly number[] = getRepeats(inputs[1]); + const outputShape = getOutputShape(inputShape, repeats); + const outputSize = ShapeUtil.size(outputShape); + + const dataType = inputs[0].dataType; + const input = inputVariable('input', dataType, inputShape); + const output = outputVariable('output', dataType, outputShape); + + const getShaderSource = (shaderHelper: ShaderHelper) => ` + const inputShape = ${input.indices(...inputShape)}; + ${shaderHelper.declareVariables(input, output)} + ${shaderHelper.mainStart()} + ${shaderHelper.guardAgainstOutOfBoundsWorkgroupSizes(outputSize)} + let outputIndices = ${output.offsetToIndices('global_idx')}; + var inputIndices: ${input.type.indices}; + for (var i = 0; i < ${inputShape.length}; i++) { + let inputDimValue = ${output.indicesGet('outputIndices', 'i')} % ${input.indicesGet('inputShape', 'i')}; + + ${input.indicesSet('inputIndices', 'i', 'inputDimValue')} + } + ${output.setByOffset('global_idx', input.getByIndices('inputIndices'))} + }`; + + return { + ...tileProgramMetadata, + outputs: [{dims: outputShape, dataType: inputs[0].dataType, gpuDataType: GpuDataType.default}], + getShaderSource, + dispatchGroup: () => ({x: Math.ceil(outputSize / 64 /* workgroup size */)}) + }; + }; + +export const tile = (context: ComputeContext): void => { + validateInputs(context.inputs); + const repeats: readonly number[] = getRepeats(context.inputs[1]); + const cacheHint = repeats.toString(); + context.compute( + {...tileProgramMetadata, cacheHint, get: () => createTileProgramInfo(tileProgramMetadata, context.inputs)}, + {inputs: [0]}); +}; diff --git a/js/web/lib/wasm/jsep/webgpu/ops/transpose.ts b/js/web/lib/wasm/jsep/webgpu/ops/transpose.ts index 11f29e60b3712..38dcaeab54c54 100644 --- a/js/web/lib/wasm/jsep/webgpu/ops/transpose.ts +++ b/js/web/lib/wasm/jsep/webgpu/ops/transpose.ts @@ -1,13 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import {DataType} from '../../../wasm-common'; -import {TensorView} from '../../tensor'; +import {TensorView} from '../../tensor-view'; import {ShapeUtil} from '../../util'; import {AttributeWithCacheKey, createAttributeWithCacheKey} from '../attribute-with-cache-key'; import {ComputeContext, GpuDataType, ProgramInfo} from '../types'; -import {createIndicesHelper, ShaderHelper} from './common'; +import {IndicesHelper, inputVariable, outputVariable, ShaderHelper} from './common'; export interface TransposeAttributes extends AttributeWithCacheKey { readonly perm: number[]; @@ -22,10 +21,6 @@ const validateInputs = (inputs: readonly TensorView[]): void => { if (!inputs || inputs.length !== 1) { throw new Error('Transpose requires 1 input.'); } - - if (inputs[0].dataType !== DataType.float) { - throw new Error('input should be float tensor'); - } }; const getAdjustedPerm = (inputShape: readonly number[], perm: number[]): number[] => @@ -34,19 +29,20 @@ const getAdjustedPerm = (inputShape: readonly number[], perm: number[]): number[ const getOutputShape = (inputShape: readonly number[], perm: number[]): readonly number[] => ShapeUtil.sortBasedOnPerm(inputShape, getAdjustedPerm(inputShape, perm)); -const permFunctionBody = (perm: number[], rank: number): string => { +const permFunctionBody = (perm: number[], rank: number, input: IndicesHelper, output: IndicesHelper): string => { const reverseFunc = []; - reverseFunc.push(`fn perm(a: ptr>, i: ptr>) {`); + reverseFunc.push(`fn perm(i: ${output.type.indices}) -> ${input.type.indices} { + var a: ${input.type.indices};`); for (let i = 0; i < rank; ++i) { - reverseFunc.push(`\t(*a)[${perm[i]}]=(*i)[${i}];`); + reverseFunc.push(input.indicesSet('a', perm[i], `i[${i}]`)); } - reverseFunc.push('\t}'); + reverseFunc.push('return a;}'); return reverseFunc.join('\n'); }; -export const createTransposeProgramInfo = (input: TensorView, permAttr: number[]): ProgramInfo => { - const dataType = 'f32'; // TODO: support other data type - const inputShape = input.dims; +export const createTransposeProgramInfo = (inputTensor: TensorView, permAttr: number[]): ProgramInfo => { + const dataType = inputTensor.dataType; + const inputShape = inputTensor.dims; const perm = getAdjustedPerm(inputShape, permAttr); const outputShape = getOutputShape(inputShape, perm); const rank = inputShape.length; @@ -55,30 +51,25 @@ export const createTransposeProgramInfo = (input: TensorView, permAttr: number[] // out Dims=[${unpackedOutputShape.toString()}] // based on perm=[${perm.toString()}] - const outputIndicesHelper = createIndicesHelper('output', outputShape); - const inputIndicesHelper = createIndicesHelper('a', inputShape); + const output = outputVariable('output', dataType, outputShape); + const input = inputVariable('a', dataType, inputShape); const getShaderSource = (shaderHelper: ShaderHelper) => ` - @group(0) @binding(0) var a : array<${dataType}>; - @group(0) @binding(1) var output : array<${dataType}>; + ${shaderHelper.declareVariables(input, output)} - ${permFunctionBody(perm, rank)} - ${outputIndicesHelper.o2iImpl} - ${inputIndicesHelper.i2oImpl} + ${permFunctionBody(perm, rank, input, output)} ${shaderHelper.mainStart()} ${shaderHelper.guardAgainstOutOfBoundsWorkgroupSizes(outputSize)} - ${outputIndicesHelper.indicesVariableDeclaration('indices')} - ${outputIndicesHelper.o2iCall('global_idx', 'indices')} - ${inputIndicesHelper.indicesVariableDeclaration('aIndices')} - perm(&aIndices, &indices); + let indices = ${output.offsetToIndices('global_idx')}; + let aIndices = perm(indices); - output[global_idx] = a[${inputIndicesHelper.i2oExpression('aIndices')}]; + ${output.setByOffset('global_idx', input.getByIndices('aIndices'))} }`; return { ...transposeProgramMetadata, - outputs: [{dims: outputShape, dataType: input.dataType, gpuDataType: GpuDataType.default}], + outputs: [{dims: outputShape, dataType: inputTensor.dataType, gpuDataType: GpuDataType.default}], getShaderSource, dispatchGroup: () => ({x: Math.ceil(outputSize / 64 /* workgroup size */)}) }; diff --git a/js/web/lib/wasm/jsep/webgpu/ops/unary-op.ts b/js/web/lib/wasm/jsep/webgpu/ops/unary-op.ts index 6ea0007ba0076..f08d7a77d1099 100644 --- a/js/web/lib/wasm/jsep/webgpu/ops/unary-op.ts +++ b/js/web/lib/wasm/jsep/webgpu/ops/unary-op.ts @@ -1,20 +1,21 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import {TensorView} from '../../tensor'; +import {DataType} from '../../../wasm-common'; +import {TensorView} from '../../tensor-view'; import {MAX_CLIP, MIN_CLIP, ShapeUtil} from '../../util'; import {AttributeWithCacheKey, createAttributeWithCacheKey} from '../attribute-with-cache-key'; import {ComputeContext, GpuDataType, ProgramInfo, ProgramInfoLoader, ProgramMetadata} from '../types'; -import {ShaderHelper} from './common'; +import {inputVariable, outputVariable, ShaderHelper, tensorTypeToWsglStorageType} from './common'; type BuiltinFunctionName = string; type ElementwiseCustomExpression = (expression: string) => string; type ElementwiseFunctionCall = BuiltinFunctionName|ElementwiseCustomExpression; const createElementwiseProgramShader = - (shaderHelper: ShaderHelper, datasize: number, funcCall: ElementwiseFunctionCall, - additionalImplementation?: string): string => { + (shaderHelper: ShaderHelper, datasize: number, inputDataType: number, outputDataType: number, + funcCall: ElementwiseFunctionCall, additionalImplementation?: string): string => { const vecSize = Math.ceil(datasize / 4); let expression = ''; @@ -23,38 +24,41 @@ const createElementwiseProgramShader = } else { expression = funcCall('a'); } + + const input = inputVariable('inputData', inputDataType, [vecSize], 4); + const output = outputVariable('outputData', outputDataType, [vecSize], 4); + return ` - @group(0) @binding(0) var inputData : array>; - @group(0) @binding(1) var outputData : array>; + ${shaderHelper.declareVariables(input, output)} ${additionalImplementation ?? ''} ${shaderHelper.mainStart()} ${shaderHelper.guardAgainstOutOfBoundsWorkgroupSizes(vecSize)} - let a = inputData[global_idx]; - outputData[global_idx] = ${expression}; + let a = ${input.getByOffset('global_idx')}; + ${output.setByOffset('global_idx', expression)} }`; }; const createElementwiseProgramInfo = - (metadata: ProgramMetadata, input: TensorView, funcCall: ElementwiseFunctionCall, + (metadata: ProgramMetadata, input: TensorView, outputDataType: number, funcCall: ElementwiseFunctionCall, additionalImplementation?: string): ProgramInfo => ({ ...metadata, - getShaderSource: shaderHelper => - createElementwiseProgramShader(shaderHelper, ShapeUtil.size(input.dims), funcCall, additionalImplementation), - outputs: [{dims: input.dims, dataType: input.dataType, gpuDataType: GpuDataType.default}], + getShaderSource: shaderHelper => createElementwiseProgramShader( + shaderHelper, ShapeUtil.size(input.dims), input.dataType, outputDataType, funcCall, additionalImplementation), + outputs: [{dims: input.dims, dataType: outputDataType, gpuDataType: GpuDataType.default}], dispatchGroup: (inputTensors) => ({x: Math.ceil(ShapeUtil.size(inputTensors[0].dims) / 64 /* workgroup size */ / 4 /* vec size */)}) }); const createElementwiseProgramInfoLoader = (input: TensorView, name: string, funcCall: ElementwiseFunctionCall, additionalImplementation?: string, - cacheKey?: string): ProgramInfoLoader => { + cacheKey?: string, outputDataType: number = input.dataType): ProgramInfoLoader => { const metadata: ProgramMetadata = {name, inputTypes: [GpuDataType.default], cacheHint: cacheKey}; return { ...metadata, - get: () => createElementwiseProgramInfo(metadata, input, funcCall, additionalImplementation) + get: () => createElementwiseProgramInfo(metadata, input, outputDataType, funcCall, additionalImplementation) }; }; @@ -85,17 +89,52 @@ export const atanh = (context: ComputeContext): void => { context.compute(createElementwiseProgramInfoLoader(context.inputs[0], 'Atanh', 'atanh')); }; +export interface CastAttributes extends AttributeWithCacheKey { + readonly to: number; + readonly saturate?: boolean; +} + +export const parseCastAttributes = (attributes: Record): CastAttributes => + createAttributeWithCacheKey(attributes as {to: number}); + + +export const cast = (context: ComputeContext, attributes: CastAttributes): void => { + let func: ElementwiseFunctionCall; + switch (attributes.to) { + case DataType.float16: + func = 'vec4'; + break; + case DataType.float: + func = 'vec4'; + break; + case DataType.uint32: + func = 'vec4'; + break; + case DataType.int32: + func = 'vec4'; + break; + case DataType.bool: + func = 'vec4'; + break; + default: + throw new RangeError(`not supported type (specified in attribute 'to' from 'Cast' operator): ${attributes.to}`); + } + context.compute(createElementwiseProgramInfoLoader( + context.inputs[0], 'Cast', func, undefined, attributes.cacheKey, attributes.to)); +}; + export interface ClipAttributes extends AttributeWithCacheKey { readonly min: number; readonly max: number; } export const clipV10 = (context: ComputeContext, attributes: ClipAttributes): void => { + const dataType = tensorTypeToWsglStorageType(context.inputs[0].dataType); context.compute( createElementwiseProgramInfoLoader( context.inputs[0], 'Clip', a => `clamp(${a}, clip_min_, clip_max_)`, ` - const clip_min_: vec4 = vec4(f32(${attributes.min})); - const clip_max_: vec4 = vec4(f32(${attributes.max})); + const clip_min_: vec4<${dataType}> = vec4(${dataType}(${attributes.min})); + const clip_max_: vec4<${dataType}> = vec4(${dataType}(${attributes.max})); `, attributes.cacheKey), {inputs: [0]}); @@ -123,11 +162,14 @@ export const cosh = (context: ComputeContext): void => { context.compute(createElementwiseProgramInfoLoader(context.inputs[0], 'Cosh', 'cosh')); }; -export interface EluAttributes extends AttributeWithCacheKey { +export interface AlphaAttributes extends AttributeWithCacheKey { readonly alpha: number; } -export const elu = (context: ComputeContext, attributes: EluAttributes): void => { +export const parseAlphaAttributes = (attributes: Record): AlphaAttributes => + createAttributeWithCacheKey(attributes as {alpha: number}); + +export const elu = (context: ComputeContext, attributes: AlphaAttributes): void => { context.compute(createElementwiseProgramInfoLoader( context.inputs[0], 'Elu', a => `elu_vf32(${a})`, ` const elu_alpha_: f32 = f32(${attributes.alpha}); @@ -142,29 +184,51 @@ export const elu = (context: ComputeContext, attributes: EluAttributes): void => attributes.cacheKey)); }; -export const parseEluAttributes = (attributes: Record): EluAttributes => - createAttributeWithCacheKey(attributes as {alpha: number}); +export const erfImpl = (dataType: string, varType = 'f32') => ` +const r0: ${varType} = 0.3275911; +const r1: ${varType} = 0.254829592; +const r2: ${varType} = -0.284496736; +const r3: ${varType} = 1.421413741; +const r4: ${varType} = -1.453152027; +const r5: ${varType} = 1.061405429; + +fn erf_vf32(v: ${dataType}) -> ${dataType} { + let absv = abs(v); + let x = 1.0 / (1.0 + r0 * absv); + return sign(v) * (1.0 - ((((r5 * x + r4) * x + r3) * x + r2) * x + r1) * x * exp(-absv * absv)); +}`; export const erf = (context: ComputeContext): void => { - context.compute(createElementwiseProgramInfoLoader(context.inputs[0], 'Erf', a => `erf_vf32(${a})`, ` - const r0: f32 = 0.3275911; - const r1: f32 = 0.254829592; - const r2: f32 = -0.284496736; - const r3: f32 = 1.421413741; - const r4: f32 = -1.453152027; - const r5: f32 = 1.061405429; + const dataType = tensorTypeToWsglStorageType(context.inputs[0].dataType); + context.compute(createElementwiseProgramInfoLoader( + context.inputs[0], 'Erf', a => `erf_vf32(${a})`, erfImpl(`vec4<${dataType}>`, dataType))); +}; - fn erf_vf32(v: vec4) -> vec4 { - let absv = abs(v); - let x = 1.0 / (1.0 + r0 * absv); - return sign(v) * (1.0 - ((((r5 * x + r4) * x + r3) * x + r2) * x + r1) * x * exp(-absv * absv)); - }`)); +export const exp = (context: ComputeContext): void => { + context.compute(createElementwiseProgramInfoLoader(context.inputs[0], 'Exp', 'exp')); }; export const floor = (context: ComputeContext): void => { context.compute(createElementwiseProgramInfoLoader(context.inputs[0], 'Floor', 'floor')); }; +export const gelu = (context: ComputeContext): void => { + const dataType = tensorTypeToWsglStorageType(context.inputs[0].dataType); + context.compute(createElementwiseProgramInfoLoader( + context.inputs[0], 'Gelu', a => `0.5 * ${a} * (1.0 + erf_vf32(${a} * 0.7071067811865475))`, + erfImpl(`vec4<${dataType}>`, dataType))); +}; + +export const leakyRelu = (context: ComputeContext, attributes: AlphaAttributes): void => { + context.compute(createElementwiseProgramInfoLoader( + context.inputs[0], 'LeakyRelu', a => `select(leaky_relu_alpha_ * ${a}, ${a}, ${a} >= vec4(0.0))`, + `const leaky_relu_alpha_: f32 = f32(${attributes.alpha});`, attributes.cacheKey)); +}; + +export const not = (context: ComputeContext): void => { + context.compute(createElementwiseProgramInfoLoader(context.inputs[0], 'Not', a => `!${a}`)); +}; + export const neg = (context: ComputeContext): void => { context.compute(createElementwiseProgramInfoLoader(context.inputs[0], 'Neg', a => `-${a}`)); }; @@ -173,6 +237,11 @@ export const reciprocal = (context: ComputeContext): void => { context.compute(createElementwiseProgramInfoLoader(context.inputs[0], 'Reciprocal', a => `1.0/${a}`)); }; +export const relu = (context: ComputeContext): void => { + context.compute(createElementwiseProgramInfoLoader( + context.inputs[0], 'Relu', a => `select(vec4(0.0), ${a}, ${a} > vec4(0.0))`)); +}; + export const sigmoid = (context: ComputeContext): void => { context.compute(createElementwiseProgramInfoLoader(context.inputs[0], 'Sigmoid', a => `(1.0 / (1.0 + exp(-${a})))`)); }; @@ -196,3 +265,14 @@ export const tan = (context: ComputeContext): void => { export const tanh = (context: ComputeContext): void => { context.compute(createElementwiseProgramInfoLoader(context.inputs[0], 'Tanh', 'tanh')); }; + +export const thresholdedRelu = (context: ComputeContext, attributes: AlphaAttributes): number => { + context.compute(createElementwiseProgramInfoLoader( + context.inputs[0], 'ThresholdedRelu', a => `select(vec4(0.0), ${a}, ${a} > thresholded_relu_alpha_)`, + `const thresholded_relu_alpha_: vec4 = vec4(${attributes.alpha});`, attributes.cacheKey)); + return 0; +}; + +export const log = (context: ComputeContext): void => { + context.compute(createElementwiseProgramInfoLoader(context.inputs[0], 'Log', 'log')); +}; diff --git a/js/web/lib/wasm/jsep/webgpu/program-manager.ts b/js/web/lib/wasm/jsep/webgpu/program-manager.ts index 951e76de5449e..cf2687e4c7382 100644 --- a/js/web/lib/wasm/jsep/webgpu/program-manager.ts +++ b/js/web/lib/wasm/jsep/webgpu/program-manager.ts @@ -1,8 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +import {tensorDataTypeEnumToString} from '../../wasm-common'; import {WebGpuBackend} from '../backend-webgpu'; import {LOG_DEBUG} from '../log'; +import {TensorView} from '../tensor-view'; import {createShaderHelper} from './ops/common'; import {Artifact, GpuData, ProgramInfo} from './types'; @@ -30,11 +32,12 @@ export class ProgramManager { setArtifact(key: unknown, artifact: Artifact): void { this.repo.set(key, artifact); } - run(buildArtifact: Artifact, inputs: GpuData[], outputs: GpuData[], dispatchGroup: [number, number, number]): void { + run(buildArtifact: Artifact, inputsTensorView: readonly TensorView[], inputs: GpuData[], outputs: GpuData[], + dispatchGroup: [number, number, number]): void { const device = this.backend.device; const computePassEncoder = this.backend.getComputePassEncoder(); - - if (this.backend.profilingEnabled) { + const profilingEnabled = this.backend.supportTimestampQuery && this.backend.env.webgpu.profilingMode === 'default'; + if (profilingEnabled) { // profiling write start timestamp // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -49,30 +52,37 @@ export class ProgramManager { for (const output of outputs) { entries.push({binding: entries.length, resource: {buffer: output.buffer}}); } - const bindGroup = device.createBindGroup({layout: buildArtifact.computePipeline.getBindGroupLayout(0), entries}); + const bindGroup = device.createBindGroup( + {layout: buildArtifact.computePipeline.getBindGroupLayout(0), entries, label: buildArtifact.programInfo.name}); computePassEncoder.setBindGroup(0, bindGroup); computePassEncoder.dispatchWorkgroups(...dispatchGroup); this.backend.pendingDispatchNumber++; - if (this.backend.profilingEnabled) { + if (profilingEnabled) { // profiling write end timestamp // eslint-disable-next-line @typescript-eslint/no-explicit-any (computePassEncoder as any).writeTimestamp(this.backend.profilingQuerySet, 1); - // eslint-disable-next-line no-bitwise - const queryData = this.backend.gpuDataManager.create(16, GPUBufferUsage.COPY_SRC | GPUBufferUsage.QUERY_RESOLVE); + if (this.backend.profilingQueryData == null) { + this.backend.profilingQueryData = + // eslint-disable-next-line no-bitwise + this.backend.gpuDataManager.create(16, GPUBufferUsage.COPY_SRC | GPUBufferUsage.QUERY_RESOLVE); + } // eslint-disable-next-line no-bitwise const syncData = this.backend.gpuDataManager.create(16, GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST); this.backend.endComputePass(); - this.backend.getCommandEncoder().resolveQuerySet(this.backend.profilingQuerySet, 0, 2, queryData.buffer, 0); - this.backend.getCommandEncoder().copyBufferToBuffer(queryData.buffer, 0, syncData.buffer, 0, 16); + this.backend.getCommandEncoder().resolveQuerySet( + this.backend.profilingQuerySet, 0, 2, this.backend.profilingQueryData.buffer, 0); + this.backend.getCommandEncoder().copyBufferToBuffer( + this.backend.profilingQueryData.buffer, 0, syncData.buffer, 0, 16); this.backend.flush(); const kernelId = this.backend.currentKernelId!; - const kernelName = this.backend.kernels.get(kernelId)![0]; + const kernelInfo = this.backend.kernels.get(kernelId)!; + const kernelName = `[${kernelInfo[0]}] ${kernelInfo[1]}`; syncData.buffer.mapAsync(GPUMapMode.READ).then(() => { const mappedData = new BigUint64Array(syncData.buffer.getMappedRange()); @@ -92,11 +102,18 @@ export class ProgramManager { throw new RangeError('incorrect timestamp range'); } - this.backend.gpuDataManager.release(queryData.id); this.backend.gpuDataManager.release(syncData.id); - + let inputShapes = ''; + inputsTensorView.forEach((value, i) => { + inputShapes += `input[${i}]: [${value.dims}] | ${tensorDataTypeEnumToString(value.dataType)}, `; + }); + let outputShapes = ''; + buildArtifact.programInfo.outputs.forEach((value, i) => { + outputShapes += `output[${i}]: [${value.dims}] | ${tensorDataTypeEnumToString(value.dataType)}, `; + }); // eslint-disable-next-line no-console - console.log(`[profiling] kernel "${kernelId}|${kernelName}" execution time: ${endTime - startTime} ns`); + console.log(`[profiling] kernel "${kernelId}|${kernelName}" ${inputShapes}${outputShapes}execution time: ${ + endTime - startTime} ns`); }); } @@ -109,13 +126,18 @@ export class ProgramManager { } build(programInfo: ProgramInfo, normalizedDispatchGroupSize: [number, number, number]): Artifact { const device = this.backend.device; - - const code = programInfo.getShaderSource(createShaderHelper(normalizedDispatchGroupSize)); - const shaderModule = device.createShaderModule({code}); + const extensions: string[] = []; + if (device.features.has('shader-f16')) { + extensions.push('enable f16;'); + } + const shaderHelper = createShaderHelper(normalizedDispatchGroupSize); + const userCode = programInfo.getShaderSource(shaderHelper); + const code = `${extensions.join('\n')}\n${shaderHelper.additionalImplementations}\n${userCode}`; + const shaderModule = device.createShaderModule({code, label: programInfo.name}); LOG_DEBUG('verbose', () => `[WebGPU] shader code: ${code}`); - const computePipeline = - device.createComputePipeline({compute: {module: shaderModule, entryPoint: 'main'}, layout: 'auto'}); + const computePipeline = device.createComputePipeline( + {compute: {module: shaderModule, entryPoint: 'main'}, layout: 'auto', label: programInfo.name}); return {programInfo, computePipeline}; } diff --git a/js/web/lib/wasm/jsep/webgpu/types.ts b/js/web/lib/wasm/jsep/webgpu/types.ts index 634e3a167184f..78f80b89774e2 100644 --- a/js/web/lib/wasm/jsep/webgpu/types.ts +++ b/js/web/lib/wasm/jsep/webgpu/types.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import {Tensor, TensorView} from '../tensor'; +import {TensorView} from '../tensor-view'; import {ShaderHelper} from './ops/common'; @@ -19,7 +19,6 @@ export interface GpuData { } export interface TensorInfo { - id?: Tensor.Id; dims: readonly number[]; dataType: number; gpuDataType: GpuDataType; @@ -132,7 +131,17 @@ export interface ComputeContext { /** * a custom data object that can be used to store any data that is needed by the kernel */ - readonly customData: {[key: string]: unknown}; + readonly kernelCustomData: {[key: string]: unknown}; + + /** + * a buffer that can be used to access custom data created each time the kernel is executed + */ + readonly customDataBuffer: Uint8Array; + + /** + * a number of outputs for the node + */ + readonly outputCount: number; compute(program: ProgramInfoLoader|ProgramInfo, inputsOutputsMapping?: ComputeContextInputsOutputsMapping): TensorView[]; diff --git a/js/web/lib/wasm/proxy-messages.ts b/js/web/lib/wasm/proxy-messages.ts index 7abd7062e01e5..e5a2d8c2351b8 100644 --- a/js/web/lib/wasm/proxy-messages.ts +++ b/js/web/lib/wasm/proxy-messages.ts @@ -29,7 +29,7 @@ interface MessageInitWasm extends MessageError { interface MessageInitOrt extends MessageError { type: 'init-ort'; - in ?: {numThreads: number; loggingLevel: number}; + in ?: Env; } interface MessageCreateSessionAllocate extends MessageError { diff --git a/js/web/lib/wasm/proxy-worker/main.ts b/js/web/lib/wasm/proxy-worker/main.ts index 9a247c56189a8..2ea3645bf387e 100644 --- a/js/web/lib/wasm/proxy-worker/main.ts +++ b/js/web/lib/wasm/proxy-worker/main.ts @@ -4,21 +4,27 @@ /// import {OrtWasmMessage} from '../proxy-messages'; -import {createSession, createSessionAllocate, createSessionFinalize, endProfiling, extractTransferableBuffers, initOrt, releaseSession, run} from '../wasm-core-impl'; +import {createSession, createSessionAllocate, createSessionFinalize, endProfiling, extractTransferableBuffers, initRuntime, releaseSession, run} from '../wasm-core-impl'; import {initializeWebAssembly} from '../wasm-factory'; self.onmessage = (ev: MessageEvent): void => { switch (ev.data.type) { case 'init-wasm': - initializeWebAssembly(ev.data.in) - .then( - () => postMessage({type: 'init-wasm'} as OrtWasmMessage), - err => postMessage({type: 'init-wasm', err} as OrtWasmMessage)); + try { + initializeWebAssembly(ev.data.in) + .then( + () => postMessage({type: 'init-wasm'} as OrtWasmMessage), + err => postMessage({type: 'init-wasm', err} as OrtWasmMessage)); + } catch (err) { + postMessage({type: 'init-wasm', err} as OrtWasmMessage); + } break; case 'init-ort': try { - const {numThreads, loggingLevel} = ev.data.in!; - initOrt(numThreads, loggingLevel); + initRuntime(ev.data.in).then(() => postMessage({type: 'init-ort'} as OrtWasmMessage), err => postMessage({ + type: 'init-ort', + err + } as OrtWasmMessage)); postMessage({type: 'init-ort'} as OrtWasmMessage); } catch (err) { postMessage({type: 'init-ort', err} as OrtWasmMessage); diff --git a/js/web/lib/wasm/proxy-wrapper.ts b/js/web/lib/wasm/proxy-wrapper.ts index 02c61800d9e66..815b223e40379 100644 --- a/js/web/lib/wasm/proxy-wrapper.ts +++ b/js/web/lib/wasm/proxy-wrapper.ts @@ -1,12 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import {env, InferenceSession} from 'onnxruntime-common'; +import {Env, env, InferenceSession} from 'onnxruntime-common'; -import {init as initJsep} from './jsep/init'; import {OrtWasmMessage, SerializableModeldata, SerializableSessionMetadata, SerializableTensor} from './proxy-messages'; import * as core from './wasm-core-impl'; -import {getInstance, initializeWebAssembly} from './wasm-factory'; +import {initializeWebAssembly} from './wasm-factory'; const isProxy = (): boolean => !!env.wasm.proxy && typeof document !== 'undefined'; let proxyWorker: Worker|undefined; @@ -99,7 +98,7 @@ const onProxyWorkerMessage = (ev: MessageEvent): void => { const scriptSrc = typeof document !== 'undefined' ? (document?.currentScript as HTMLScriptElement)?.src : undefined; -export const initWasm = async(): Promise => { +export const initializeWebAssemblyInstance = async(): Promise => { if (!BUILD_DEFS.DISABLE_WASM_PROXY && isProxy()) { if (initialized) { return; @@ -135,21 +134,16 @@ export const initWasm = async(): Promise => { } }; -export const initOrt = async(numThreads: number, loggingLevel: number): Promise => { +export const initializeRuntime = async(env: Env): Promise => { if (!BUILD_DEFS.DISABLE_WASM_PROXY && isProxy()) { ensureWorker(); return new Promise((resolve, reject) => { initOrtCallbacks = [resolve, reject]; - const message: OrtWasmMessage = {type: 'init-ort', in : {numThreads, loggingLevel}}; + const message: OrtWasmMessage = {type: 'init-ort', in : env}; proxyWorker!.postMessage(message); - - // TODO: support JSEP in worker }); } else { - core.initOrt(numThreads, loggingLevel); - - // init JSEP if available - await initJsep(getInstance()); + await core.initRuntime(env); } }; diff --git a/js/web/lib/wasm/run-options.ts b/js/web/lib/wasm/run-options.ts index 260a622a41b42..8fe230003413f 100644 --- a/js/web/lib/wasm/run-options.ts +++ b/js/web/lib/wasm/run-options.ts @@ -3,9 +3,8 @@ import {InferenceSession} from 'onnxruntime-common'; -import {iterateExtraOptions} from './options-utils'; -import {allocWasmString} from './string-utils'; import {getInstance} from './wasm-factory'; +import {allocWasmString, checkLastError, iterateExtraOptions} from './wasm-utils'; export const setRunOptions = (options: InferenceSession.RunOptions): [number, number[]] => { const wasm = getInstance(); @@ -41,7 +40,7 @@ export const setRunOptions = (options: InferenceSession.RunOptions): [number, nu runOptionsHandle = wasm._OrtCreateRunOptions( runOptions.logSeverityLevel!, runOptions.logVerbosityLevel!, !!runOptions.terminate!, tagDataOffset); if (runOptionsHandle === 0) { - throw new Error('Can\'t create run options'); + checkLastError('Can\'t create run options.'); } if (options?.extra !== undefined) { @@ -50,7 +49,7 @@ export const setRunOptions = (options: InferenceSession.RunOptions): [number, nu const valueDataOffset = allocWasmString(value, allocs); if (wasm._OrtAddRunConfigEntry(runOptionsHandle, keyDataOffset, valueDataOffset) !== 0) { - throw new Error(`Can't set a run config entry: ${key} - ${value}`); + checkLastError(`Can't set a run config entry: ${key} - ${value}.`); } }); } @@ -60,7 +59,7 @@ export const setRunOptions = (options: InferenceSession.RunOptions): [number, nu if (runOptionsHandle !== 0) { wasm._OrtReleaseRunOptions(runOptionsHandle); } - allocs.forEach(wasm._free); + allocs.forEach(alloc => wasm._free(alloc)); throw e; } }; diff --git a/js/web/lib/wasm/session-handler.ts b/js/web/lib/wasm/session-handler.ts index 038a46d82e61a..d8c5ae7886fe4 100644 --- a/js/web/lib/wasm/session-handler.ts +++ b/js/web/lib/wasm/session-handler.ts @@ -6,10 +6,10 @@ import {env, InferenceSession, SessionHandler, Tensor} from 'onnxruntime-common' import {promisify} from 'util'; import {SerializableModeldata} from './proxy-messages'; -import {createSession, createSessionAllocate, createSessionFinalize, endProfiling, initOrt, releaseSession, run} from './proxy-wrapper'; -import {logLevelStringToEnum} from './wasm-common'; +import {createSession, createSessionAllocate, createSessionFinalize, endProfiling, initializeRuntime, releaseSession, run} from './proxy-wrapper'; -let ortInit: boolean; +let runtimeInitialized: boolean; +let runtimeInitializationPromise: Promise|undefined; export class OnnxruntimeWebAssemblySessionHandler implements SessionHandler { private sessionId: number; @@ -21,18 +21,25 @@ export class OnnxruntimeWebAssemblySessionHandler implements SessionHandler { // fetch model from url and move to wasm heap. The arraybufffer that held the http // response is freed once we return const response = await fetch(path); + if (response.status !== 200) { + throw new Error(`failed to load model: ${path}`); + } const arrayBuffer = await response.arrayBuffer(); return createSessionAllocate(new Uint8Array(arrayBuffer)); } async loadModel(pathOrBuffer: string|Uint8Array, options?: InferenceSession.SessionOptions): Promise { - if (!ortInit) { - await initOrt(env.wasm.numThreads!, logLevelStringToEnum(env.logLevel!)); - ortInit = true; + if (!runtimeInitialized) { + if (!runtimeInitializationPromise) { + runtimeInitializationPromise = initializeRuntime(env); + } + await runtimeInitializationPromise; + runtimeInitializationPromise = undefined; + runtimeInitialized = true; } if (typeof pathOrBuffer === 'string') { - if (typeof fetch === 'undefined') { + if (typeof process !== 'undefined' && process.versions && process.versions.node) { // node const model = await promisify(readFile)(pathOrBuffer); [this.sessionId, this.inputNames, this.outputNames] = await createSession(model, options); diff --git a/js/web/lib/wasm/session-options.ts b/js/web/lib/wasm/session-options.ts index 10cc48257dc52..2659b471733f5 100644 --- a/js/web/lib/wasm/session-options.ts +++ b/js/web/lib/wasm/session-options.ts @@ -3,9 +3,8 @@ import {InferenceSession} from 'onnxruntime-common'; -import {iterateExtraOptions} from './options-utils'; -import {allocWasmString} from './string-utils'; import {getInstance} from './wasm-factory'; +import {allocWasmString, checkLastError, iterateExtraOptions} from './wasm-utils'; const getGraphOptimzationLevel = (graphOptimizationLevel: string|unknown): number => { switch (graphOptimizationLevel) { @@ -64,6 +63,29 @@ const setExecutionProviders = case 'xnnpack': epName = 'XNNPACK'; break; + case 'webnn': + epName = 'WEBNN'; + if (typeof ep !== 'string') { + const webnnOptions = ep as InferenceSession.WebNNExecutionProviderOption; + if (webnnOptions?.deviceType) { + const keyDataOffset = allocWasmString('deviceType', allocs); + const valueDataOffset = allocWasmString(webnnOptions.deviceType, allocs); + if (getInstance()._OrtAddSessionConfigEntry(sessionOptionsHandle, keyDataOffset, valueDataOffset) !== + 0) { + checkLastError(`Can't set a session config entry: 'deviceType' - ${webnnOptions.deviceType}.`); + } + } + if (webnnOptions?.powerPreference) { + const keyDataOffset = allocWasmString('powerPreference', allocs); + const valueDataOffset = allocWasmString(webnnOptions.powerPreference, allocs); + if (getInstance()._OrtAddSessionConfigEntry(sessionOptionsHandle, keyDataOffset, valueDataOffset) !== + 0) { + checkLastError( + `Can't set a session config entry: 'powerPreference' - ${webnnOptions.powerPreference}.`); + } + } + } + break; case 'webgpu': epName = 'JS'; break; @@ -71,12 +93,12 @@ const setExecutionProviders = case 'cpu': continue; default: - throw new Error(`not supported EP: ${epName}`); + throw new Error(`not supported execution provider: ${epName}`); } const epNameDataOffset = allocWasmString(epName, allocs); if (getInstance()._OrtAppendExecutionProvider(sessionOptionsHandle, epNameDataOffset) !== 0) { - throw new Error(`Can't append execution provider: ${epName}`); + checkLastError(`Can't append execution provider: ${epName}.`); } } }; @@ -114,20 +136,35 @@ export const setSessionOptions = (options?: InferenceSession.SessionOptions): [n !!sessionOptions.enableProfiling, 0, logIdDataOffset, logSeverityLevel, logVerbosityLevel, optimizedModelFilePathOffset); if (sessionOptionsHandle === 0) { - throw new Error('Can\'t create session options'); + checkLastError('Can\'t create session options.'); } if (sessionOptions.executionProviders) { setExecutionProviders(sessionOptionsHandle, sessionOptions.executionProviders, allocs); } + if (sessionOptions.freeDimensionOverrides) { + for (const [name, value] of Object.entries(sessionOptions.freeDimensionOverrides)) { + if (typeof name !== 'string') { + throw new Error(`free dimension override name must be a string: ${name}`); + } + if (typeof value !== 'number' || !Number.isInteger(value) || value < 0) { + throw new Error(`free dimension override value must be a non-negative integer: ${value}`); + } + const nameOffset = allocWasmString(name, allocs); + if (wasm._OrtAddFreeDimensionOverride(sessionOptionsHandle, nameOffset, value) !== 0) { + checkLastError(`Can't set a free dimension override: ${name} - ${value}.`); + } + } + } + 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) { - throw new Error(`Can't set a session config entry: ${key} - ${value}`); + checkLastError(`Can't set a session config entry: ${key} - ${value}.`); } }); } @@ -137,7 +174,7 @@ export const setSessionOptions = (options?: InferenceSession.SessionOptions): [n if (sessionOptionsHandle !== 0) { wasm._OrtReleaseSessionOptions(sessionOptionsHandle); } - allocs.forEach(wasm._free); + allocs.forEach(alloc => wasm._free(alloc)); throw e; } }; diff --git a/js/web/lib/wasm/string-utils.ts b/js/web/lib/wasm/string-utils.ts deleted file mode 100644 index d7ea4a4626311..0000000000000 --- a/js/web/lib/wasm/string-utils.ts +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -import {getInstance} from './wasm-factory'; - -export const allocWasmString = (data: string, allocs: number[]): number => { - const wasm = getInstance(); - - const dataLength = wasm.lengthBytesUTF8(data) + 1; - const dataOffset = wasm._malloc(dataLength); - wasm.stringToUTF8(data, dataOffset, dataLength); - allocs.push(dataOffset); - - return dataOffset; -}; diff --git a/js/web/lib/wasm/wasm-common.ts b/js/web/lib/wasm/wasm-common.ts index d0df08419fb5d..389773f3e8884 100644 --- a/js/web/lib/wasm/wasm-common.ts +++ b/js/web/lib/wasm/wasm-common.ts @@ -3,6 +3,8 @@ import {Tensor} from 'onnxruntime-common'; +// This file includes common definitions. They do NOT have dependency on the WebAssembly instance. + /** * Copied from ONNX definition. Use this to drop dependency 'onnx_proto' to decrease compiled .js file size. */ @@ -45,6 +47,8 @@ export const tensorDataTypeStringToEnum = (type: string): DataType => { return DataType.int32; case 'uint32': return DataType.uint32; + case 'float16': + return DataType.float16; case 'float32': return DataType.float; case 'float64': @@ -80,6 +84,8 @@ export const tensorDataTypeEnumToString = (typeProto: DataType): Tensor.Type => return 'int32'; case DataType.uint32: return 'uint32'; + case DataType.float16: + return 'float16'; case DataType.float: return 'float32'; case DataType.double: @@ -110,6 +116,8 @@ export const tensorTypeToTypedArrayConstructor = (type: Tensor.Type): Float32Arr Int8ArrayConstructor|Uint16ArrayConstructor|Int16ArrayConstructor|Int32ArrayConstructor|BigInt64ArrayConstructor| Uint8ArrayConstructor|Float64ArrayConstructor|Uint32ArrayConstructor|BigUint64ArrayConstructor => { switch (type) { + case 'float16': + return Uint16Array; case 'float32': return Float32Array; case 'uint8': @@ -140,7 +148,7 @@ export const tensorTypeToTypedArrayConstructor = (type: Tensor.Type): Float32Arr /** * Map string log level to integer value */ -export const logLevelStringToEnum = (logLevel: 'verbose'|'info'|'warning'|'error'|'fatal'): number => { +export const logLevelStringToEnum = (logLevel?: 'verbose'|'info'|'warning'|'error'|'fatal'): number => { switch (logLevel) { case 'verbose': return 0; diff --git a/js/web/lib/wasm/wasm-core-impl.ts b/js/web/lib/wasm/wasm-core-impl.ts index 16291aeb500ac..fcca82ab2aa54 100644 --- a/js/web/lib/wasm/wasm-core-impl.ts +++ b/js/web/lib/wasm/wasm-core-impl.ts @@ -1,24 +1,61 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import {InferenceSession, Tensor} from 'onnxruntime-common'; +import {Env, InferenceSession, Tensor} from 'onnxruntime-common'; import {SerializableModeldata, SerializableSessionMetadata, SerializableTensor} from './proxy-messages'; import {setRunOptions} from './run-options'; import {setSessionOptions} from './session-options'; -import {allocWasmString} from './string-utils'; -import {tensorDataTypeEnumToString, tensorDataTypeStringToEnum, tensorTypeToTypedArrayConstructor} from './wasm-common'; +import {logLevelStringToEnum, tensorDataTypeEnumToString, tensorDataTypeStringToEnum, tensorTypeToTypedArrayConstructor} from './wasm-common'; import {getInstance} from './wasm-factory'; +import {allocWasmString, checkLastError} from './wasm-utils'; + +/** + * get the input/output count of the session. + * @param sessionHandle the handle representing the session. should be non-zero. + * @returns a tuple including 2 numbers, representing the input count and output count. + */ +const getSessionInputOutputCount = (sessionHandle: number): [number, number] => { + const wasm = getInstance(); + const stack = wasm.stackSave(); + try { + const dataOffset = wasm.stackAlloc(8); + const errorCode = wasm._OrtGetInputOutputCount(sessionHandle, dataOffset, dataOffset + 4); + if (errorCode !== 0) { + checkLastError('Can\'t get session input/output count.'); + } + return [wasm.HEAP32[dataOffset / 4], wasm.HEAP32[dataOffset / 4 + 1]]; + } finally { + wasm.stackRestore(stack); + } +}; /** * initialize ORT environment. * @param numThreads SetGlobalIntraOpNumThreads(numThreads) * @param loggingLevel CreateEnv(static_cast(logging_level)) */ -export const initOrt = (numThreads: number, loggingLevel: number): void => { +const initOrt = (numThreads: number, loggingLevel: number): void => { const errorCode = getInstance()._OrtInit(numThreads, loggingLevel); if (errorCode !== 0) { - throw new Error(`Can't initialize onnxruntime. error code = ${errorCode}`); + checkLastError('Can\'t initialize onnxruntime.'); + } +}; + +/** + * intialize runtime environment. + * @param env passed in the environment config object. + */ +export const initRuntime = async(env: Env): Promise => { + // init ORT + initOrt(env.wasm.numThreads!, logLevelStringToEnum(env.logLevel)); + + if (!BUILD_DEFS.DISABLE_WEBGPU) { + // init JSEP if available + + // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires + const initJsep = require('./jsep/init').init; + await initJsep(getInstance(), env); } }; @@ -30,16 +67,25 @@ type SessionMetadata = [number, number[], number[]]; const activeSessions = new Map(); /** - * create an instance of InferenceSession. - * @returns the metadata of InferenceSession. 0-value handle for failure. + * allocate the memory and memcpy the model bytes, preparing for creating an instance of InferenceSession. + * @returns a 2-elements tuple - the pointer and size of the allocated buffer */ export const createSessionAllocate = (model: Uint8Array): [number, number] => { const wasm = getInstance(); const modelDataOffset = wasm._malloc(model.byteLength); + if (modelDataOffset === 0) { + throw new Error(`Can't create a session. failed to allocate a buffer of size ${model.byteLength}.`); + } wasm.HEAPU8.set(model, modelDataOffset); return [modelDataOffset, model.byteLength]; }; +/** + * create an inference session using the prepared buffer containing the model data. + * @param modelData a 2-elements tuple containing the pointer and size of the model data buffer. + * @param options an optional session options object. + * @returns a 3-elements tuple containing [session handle, input names, output names] + */ export const createSessionFinalize = (modelData: SerializableModeldata, options?: InferenceSession.SessionOptions): SerializableSessionMetadata => { const wasm = getInstance(); @@ -47,48 +93,55 @@ export const createSessionFinalize = let sessionHandle = 0; let sessionOptionsHandle = 0; let allocs: number[] = []; + const inputNamesUTF8Encoded = []; + const outputNamesUTF8Encoded = []; try { [sessionOptionsHandle, allocs] = setSessionOptions(options); sessionHandle = wasm._OrtCreateSession(modelData[0], modelData[1], sessionOptionsHandle); if (sessionHandle === 0) { - throw new Error('Can\'t create a session'); + checkLastError('Can\'t create a session.'); } - } finally { - wasm._free(modelData[0]); - if (sessionOptionsHandle !== 0) { - wasm._OrtReleaseSessionOptions(sessionOptionsHandle); + + const [inputCount, outputCount] = getSessionInputOutputCount(sessionHandle); + + const inputNames = []; + const outputNames = []; + for (let i = 0; i < inputCount; i++) { + const name = wasm._OrtGetInputName(sessionHandle, i); + if (name === 0) { + checkLastError('Can\'t get an input name.'); + } + inputNamesUTF8Encoded.push(name); + inputNames.push(wasm.UTF8ToString(name)); + } + for (let i = 0; i < outputCount; i++) { + const name = wasm._OrtGetOutputName(sessionHandle, i); + if (name === 0) { + checkLastError('Can\'t get an output name.'); + } + outputNamesUTF8Encoded.push(name); + outputNames.push(wasm.UTF8ToString(name)); } - allocs.forEach(wasm._free); - } - const inputCount = wasm._OrtGetInputCount(sessionHandle); - const outputCount = wasm._OrtGetOutputCount(sessionHandle); + activeSessions.set(sessionHandle, [sessionHandle, inputNamesUTF8Encoded, outputNamesUTF8Encoded]); + return [sessionHandle, inputNames, outputNames]; + } catch (e) { + inputNamesUTF8Encoded.forEach(buf => wasm._OrtFree(buf)); + outputNamesUTF8Encoded.forEach(buf => wasm._OrtFree(buf)); - const inputNames = []; - const inputNamesUTF8Encoded = []; - const outputNames = []; - const outputNamesUTF8Encoded = []; - for (let i = 0; i < inputCount; i++) { - const name = wasm._OrtGetInputName(sessionHandle, i); - if (name === 0) { - throw new Error('Can\'t get an input name'); + if (sessionHandle !== 0) { + wasm._OrtReleaseSession(sessionHandle); } - inputNamesUTF8Encoded.push(name); - inputNames.push(wasm.UTF8ToString(name)); - } - for (let i = 0; i < outputCount; i++) { - const name = wasm._OrtGetOutputName(sessionHandle, i); - if (name === 0) { - throw new Error('Can\'t get an output name'); + throw e; + } finally { + wasm._free(modelData[0]); + if (sessionOptionsHandle !== 0) { + wasm._OrtReleaseSessionOptions(sessionOptionsHandle); } - outputNamesUTF8Encoded.push(name); - outputNames.push(wasm.UTF8ToString(name)); + allocs.forEach(alloc => wasm._free(alloc)); } - - activeSessions.set(sessionHandle, [sessionHandle, inputNamesUTF8Encoded, outputNamesUTF8Encoded]); - return [sessionHandle, inputNames, outputNames]; }; @@ -106,14 +159,12 @@ export const releaseSession = (sessionId: number): void => { const wasm = getInstance(); const session = activeSessions.get(sessionId); if (!session) { - throw new Error('invalid session id'); + throw new Error(`cannot release session. invalid session id: ${sessionId}`); } - const sessionHandle = session[0]; - const inputNamesUTF8Encoded = session[1]; - const outputNamesUTF8Encoded = session[2]; + const [sessionHandle, inputNamesUTF8Encoded, outputNamesUTF8Encoded] = session; - inputNamesUTF8Encoded.forEach(wasm._OrtFree); - outputNamesUTF8Encoded.forEach(wasm._OrtFree); + inputNamesUTF8Encoded.forEach(buf => wasm._OrtFree(buf)); + outputNamesUTF8Encoded.forEach(buf => wasm._OrtFree(buf)); wasm._OrtReleaseSession(sessionHandle); activeSessions.delete(sessionId); }; @@ -127,11 +178,9 @@ export const run = async( const wasm = getInstance(); const session = activeSessions.get(sessionId); if (!session) { - throw new Error('invalid session id'); + throw new Error(`cannot run inference. invalid session id: ${sessionId}`); } - const sessionHandle = session[0]; - const inputNamesUTF8Encoded = session[1]; - const outputNamesUTF8Encoded = session[2]; + const [sessionHandle, inputNamesUTF8Encoded, outputNamesUTF8Encoded] = session; const inputCount = inputIndices.length; const outputCount = outputIndices.length; @@ -181,7 +230,7 @@ export const run = async( const tensor = wasm._OrtCreateTensor( tensorDataTypeStringToEnum(dataType), dataOffset, dataByteLength, dimsOffset, dims.length); if (tensor === 0) { - throw new Error('Can\'t create a tensor'); + checkLastError(`Can't create tensor for input[${i}].`); } inputValues.push(tensor); } finally { @@ -209,87 +258,106 @@ export const run = async( wasm.HEAPU32[outputNamesIndex++] = outputNamesUTF8Encoded[outputIndices[i]]; } + // jsepOnRunStart is only available when JSEP is enabled. + wasm.jsepOnRunStart?.(sessionId); + // support RunOptions let errorCode = wasm._OrtRun( sessionHandle, inputNamesOffset, inputValuesOffset, inputCount, outputNamesOffset, outputCount, outputValuesOffset, runOptionsHandle); - // eslint-disable-next-line @typescript-eslint/naming-convention const runPromise = wasm.jsepRunPromise; - if (runPromise && typeof runPromise.then !== 'undefined') { + if (runPromise) { + // jsepRunPromise is a Promise object. It is only available when JSEP is enabled. + // + // OrtRun() is a synchrnous call, but it internally calls async functions. Emscripten's ASYNCIFY allows it to + // work in this way. However, OrtRun() does not return a promise, so when code reaches here, it is earlier than + // the async functions are finished. + // + // To make it work, we created a Promise and resolve the promise when the C++ code actually reaches the end of + // OrtRun(). If the promise exists, we need to await for the promise to be resolved. errorCode = await runPromise; } + const jsepOnRunEnd = wasm.jsepOnRunEnd; + if (jsepOnRunEnd) { + // jsepOnRunEnd is only available when JSEP is enabled. + // + // it returns a promise, which is resolved or rejected when the following async functions are finished: + // - collecting GPU validation errors. + await jsepOnRunEnd(sessionId); + } + const output: SerializableTensor[] = []; - if (errorCode === 0) { - for (let i = 0; i < outputCount; i++) { - const tensor = wasm.HEAPU32[outputValuesOffset / 4 + i]; - - const beforeGetTensorDataStack = wasm.stackSave(); - // stack allocate 4 pointer value - const tensorDataOffset = wasm.stackAlloc(4 * 4); - - let type: Tensor.Type|undefined, dataOffset = 0; - try { - errorCode = wasm._OrtGetTensorData( - tensor, tensorDataOffset, tensorDataOffset + 4, tensorDataOffset + 8, tensorDataOffset + 12); - if (errorCode !== 0) { - throw new Error(`Can't access output tensor data. error code = ${errorCode}`); - } - let tensorDataIndex = tensorDataOffset / 4; - const dataType = wasm.HEAPU32[tensorDataIndex++]; - dataOffset = wasm.HEAPU32[tensorDataIndex++]; - const dimsOffset = wasm.HEAPU32[tensorDataIndex++]; - const dimsLength = wasm.HEAPU32[tensorDataIndex++]; - const dims = []; - for (let i = 0; i < dimsLength; i++) { - dims.push(wasm.HEAPU32[dimsOffset / 4 + i]); - } - wasm._OrtFree(dimsOffset); - - const size = dims.length === 0 ? 1 : dims.reduce((a, b) => a * b); - type = tensorDataTypeEnumToString(dataType); - if (type === 'string') { - const stringData: string[] = []; - let dataIndex = dataOffset / 4; - for (let i = 0; i < size; i++) { - const offset = wasm.HEAPU32[dataIndex++]; - const maxBytesToRead = i === size - 1 ? undefined : wasm.HEAPU32[dataIndex] - offset; - stringData.push(wasm.UTF8ToString(offset, maxBytesToRead)); - } - output.push([type, dims, stringData]); - } else { - const typedArrayConstructor = tensorTypeToTypedArrayConstructor(type); - const data = new typedArrayConstructor(size); - new Uint8Array(data.buffer, data.byteOffset, data.byteLength) - .set(wasm.HEAPU8.subarray(dataOffset, dataOffset + data.byteLength)); - output.push([type, dims, data]); - } - } finally { - wasm.stackRestore(beforeGetTensorDataStack); - if (type === 'string' && dataOffset) { - wasm._free(dataOffset); + if (errorCode !== 0) { + checkLastError('failed to call OrtRun().'); + } + + for (let i = 0; i < outputCount; i++) { + const tensor = wasm.HEAPU32[outputValuesOffset / 4 + i]; + + const beforeGetTensorDataStack = wasm.stackSave(); + // stack allocate 4 pointer value + const tensorDataOffset = wasm.stackAlloc(4 * 4); + + let type: Tensor.Type|undefined, dataOffset = 0; + try { + errorCode = wasm._OrtGetTensorData( + tensor, tensorDataOffset, tensorDataOffset + 4, tensorDataOffset + 8, tensorDataOffset + 12); + if (errorCode !== 0) { + checkLastError(`Can't access output tensor data on index ${i}.`); + } + let tensorDataIndex = tensorDataOffset / 4; + const dataType = wasm.HEAPU32[tensorDataIndex++]; + dataOffset = wasm.HEAPU32[tensorDataIndex++]; + const dimsOffset = wasm.HEAPU32[tensorDataIndex++]; + const dimsLength = wasm.HEAPU32[tensorDataIndex++]; + const dims = []; + for (let i = 0; i < dimsLength; i++) { + dims.push(wasm.HEAPU32[dimsOffset / 4 + i]); + } + wasm._OrtFree(dimsOffset); + + const size = dims.length === 0 ? 1 : dims.reduce((a, b) => a * b); + type = tensorDataTypeEnumToString(dataType); + if (type === 'string') { + const stringData: string[] = []; + let dataIndex = dataOffset / 4; + for (let i = 0; i < size; i++) { + const offset = wasm.HEAPU32[dataIndex++]; + const maxBytesToRead = i === size - 1 ? undefined : wasm.HEAPU32[dataIndex] - offset; + stringData.push(wasm.UTF8ToString(offset, maxBytesToRead)); } - wasm._OrtReleaseTensor(tensor); + output.push([type, dims, stringData]); + } else { + const typedArrayConstructor = tensorTypeToTypedArrayConstructor(type); + const data = new typedArrayConstructor(size); + new Uint8Array(data.buffer, data.byteOffset, data.byteLength) + .set(wasm.HEAPU8.subarray(dataOffset, dataOffset + data.byteLength)); + output.push([type, dims, data]); } + } finally { + wasm.stackRestore(beforeGetTensorDataStack); + if (type === 'string' && dataOffset) { + wasm._free(dataOffset); + } + wasm._OrtReleaseTensor(tensor); } } - if (errorCode === 0) { - return output; - } else { - throw new Error(`failed to call OrtRun(). error code = ${errorCode}.`); - } + return output; } finally { wasm.stackRestore(beforeRunStack); } } finally { - inputValues.forEach(wasm._OrtReleaseTensor); - inputAllocs.forEach(wasm._free); + inputValues.forEach(v => wasm._OrtReleaseTensor(v)); + inputAllocs.forEach(p => wasm._free(p)); - wasm._OrtReleaseRunOptions(runOptionsHandle); - runOptionsAllocs.forEach(wasm._free); + if (runOptionsHandle !== 0) { + wasm._OrtReleaseRunOptions(runOptionsHandle); + } + runOptionsAllocs.forEach(p => wasm._free(p)); } }; @@ -307,7 +375,7 @@ export const endProfiling = (sessionId: number): void => { // profile file name is not used yet, but it must be freed. const profileFileName = wasm._OrtEndProfiling(sessionHandle); if (profileFileName === 0) { - throw new Error('Can\'t get an profile file name'); + checkLastError('Can\'t get an profile file name.'); } wasm._OrtFree(profileFileName); }; diff --git a/js/web/lib/wasm/wasm-factory.ts b/js/web/lib/wasm/wasm-factory.ts index 683e15e884eac..7648f0c473f07 100644 --- a/js/web/lib/wasm/wasm-factory.ts +++ b/js/web/lib/wasm/wasm-factory.ts @@ -6,11 +6,16 @@ import * as path from 'path'; import {OrtWasmModule} from './binding/ort-wasm'; import {OrtWasmThreadedModule} from './binding/ort-wasm-threaded'; -import ortWasmFactory from './binding/ort-wasm.js'; -const ortWasmFactoryThreaded: EmscriptenModuleFactory = - // eslint-disable-next-line @typescript-eslint/no-require-imports - !BUILD_DEFS.DISABLE_WASM_THREAD ? require('./binding/ort-wasm-threaded.js') : ortWasmFactory; +/* eslint-disable @typescript-eslint/no-require-imports */ +const ortWasmFactory: EmscriptenModuleFactory = + BUILD_DEFS.DISABLE_WEBGPU ? require('./binding/ort-wasm.js') : require('./binding/ort-wasm-simd.jsep.js'); + +const ortWasmFactoryThreaded: EmscriptenModuleFactory = !BUILD_DEFS.DISABLE_WASM_THREAD ? + (BUILD_DEFS.DISABLE_WEBGPU ? require('./binding/ort-wasm-threaded.js') : + require('./binding/ort-wasm-simd-threaded.jsep.js')) : + ortWasmFactory; +/* eslint-enable @typescript-eslint/no-require-imports */ let wasm: OrtWasmModule|undefined; let initialized = false; @@ -95,10 +100,10 @@ export const initializeWebAssembly = async(flags: Env.WebAssemblyFlags): Promise const useThreads = numThreads > 1 && isMultiThreadSupported(); const useSimd = simd && isSimdSupported(); - const wasmPrefixOverride = typeof flags.wasmPaths === 'string' ? flags.wasmPaths : undefined; - const wasmFileName = getWasmFileName(false, useThreads); - const wasmOverrideFileName = getWasmFileName(useSimd, useThreads); - const wasmPathOverride = typeof flags.wasmPaths === 'object' ? flags.wasmPaths[wasmOverrideFileName] : undefined; + const wasmPaths = flags.wasmPaths; + const wasmPrefixOverride = typeof wasmPaths === 'string' ? wasmPaths : undefined; + const wasmFileName = getWasmFileName(useSimd, useThreads); + const wasmPathOverride = typeof wasmPaths === 'object' ? wasmPaths[wasmFileName] : undefined; let isTimeout = false; @@ -130,9 +135,22 @@ export const initializeWebAssembly = async(flags: Env.WebAssemblyFlags): Promise {type: 'text/javascript'})); } - if (fileName === wasmFileName) { - const prefix: string = wasmPrefixOverride ?? scriptDirectory; - return wasmPathOverride ?? prefix + wasmOverrideFileName; + if (fileName.endsWith('.wasm')) { + if (wasmPathOverride) { + return wasmPathOverride; + } + + const prefix = wasmPrefixOverride ?? scriptDirectory; + + if (!BUILD_DEFS.DISABLE_WEBGPU) { + if (wasmFileName === 'ort-wasm-simd.wasm') { + return prefix + 'ort-wasm-simd.jsep.wasm'; + } else if (wasmFileName === 'ort-wasm-simd-threaded.wasm') { + return prefix + 'ort-wasm-simd-threaded.jsep.wasm'; + } + } + + return prefix + wasmFileName; } return scriptDirectory + fileName; diff --git a/js/web/lib/wasm/options-utils.ts b/js/web/lib/wasm/wasm-utils.ts similarity index 51% rename from js/web/lib/wasm/options-utils.ts rename to js/web/lib/wasm/wasm-utils.ts index 21951eff7faba..37762b353f575 100644 --- a/js/web/lib/wasm/options-utils.ts +++ b/js/web/lib/wasm/wasm-utils.ts @@ -1,6 +1,19 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +import {getInstance} from './wasm-factory'; + +export const allocWasmString = (data: string, allocs: number[]): number => { + const wasm = getInstance(); + + const dataLength = wasm.lengthBytesUTF8(data) + 1; + const dataOffset = wasm._malloc(dataLength); + wasm.stringToUTF8(data, dataOffset, dataLength); + allocs.push(dataOffset); + + return dataOffset; +}; + interface ExtraOptionsHandler { (name: string, value: string): void; } @@ -29,3 +42,23 @@ export const iterateExtraOptions = } }); }; + +/** + * check web assembly API's last error and throw error if any error occurred. + * @param message a message used when an error occurred. + */ +export const checkLastError = (message: string): void => { + const wasm = getInstance(); + + const stack = wasm.stackSave(); + try { + const paramsOffset = wasm.stackAlloc(8); + wasm._OrtGetLastError(paramsOffset, paramsOffset + 4); + const errorCode = wasm.HEAP32[paramsOffset / 4]; + const errorMessagePointer = wasm.HEAPU32[paramsOffset / 4 + 1]; + const errorMessage = errorMessagePointer ? wasm.UTF8ToString(errorMessagePointer) : ''; + throw new Error(`${message} ERROR_CODE: ${errorCode}, ERROR_MESSAGE: ${errorMessage}`); + } finally { + wasm.stackRestore(stack); + } +}; diff --git a/js/web/package-lock.json b/js/web/package-lock.json index ad4456629041e..9567bc172c9ed 100644 --- a/js/web/package-lock.json +++ b/js/web/package-lock.json @@ -1,20 +1,20 @@ { "name": "onnxruntime-web", - "version": "1.15.0", + "version": "1.17.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "onnxruntime-web", - "version": "1.15.0", + "version": "1.17.0", "license": "MIT", "dependencies": { "flatbuffers": "^1.12.0", "guid-typescript": "^1.0.9", - "long": "^4.0.0", - "onnx-proto": "^4.0.4", + "long": "^5.2.3", "onnxruntime-common": "file:../common", - "platform": "^1.3.6" + "platform": "^1.3.6", + "protobufjs": "^7.2.4" }, "devDependencies": { "@chiragrupani/karma-chromium-edge-launcher": "^2.2.2", @@ -22,10 +22,8 @@ "@types/emscripten": "^1.39.6", "@types/flatbuffers": "^1.10.0", "@types/karma": "^6.1.0", - "@types/long": "^4.0.1", "@types/minimatch": "^5.1.2", "@types/minimist": "^1.2.2", - "@types/mocha": "^10.0.1", "@types/platform": "^1.3.4", "@webgpu/types": "^0.1.30", "base64-js": "^1.5.1", @@ -45,14 +43,13 @@ "karma-sourcemap-loader": "^0.4.0", "minimatch": "^7.4.2", "minimist": "^1.2.8", - "mocha": "^10.2.0", "numpy-parser": "^1.2.3", "strip-json-comments": "^5.0.0" } }, "../common": { "name": "onnxruntime-common", - "version": "1.15.0", + "version": "1.17.0", "license": "MIT", "devDependencies": { "typedoc": "^0.23.22" @@ -283,11 +280,6 @@ "@types/node": "*" } }, - "node_modules/@types/long": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", - "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" - }, "node_modules/@types/minimatch": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", @@ -300,12 +292,6 @@ "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", "dev": true }, - "node_modules/@types/mocha": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz", - "integrity": "sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==", - "dev": true - }, "node_modules/@types/node": { "version": "18.14.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz", @@ -367,15 +353,6 @@ "node": ">= 6.0.0" } }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/ansi-regex": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", @@ -410,12 +387,6 @@ "node": ">= 8" } }, - "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 - }, "node_modules/assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -542,12 +513,6 @@ "node": ">=8" } }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, "node_modules/browserstack": { "version": "1.5.3", "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.5.3.tgz", @@ -641,18 +606,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/chai": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", @@ -949,18 +902,6 @@ } } }, - "node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/decompress-response": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", @@ -1058,15 +999,6 @@ "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", "dev": true }, - "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -1110,9 +1042,9 @@ "dev": true }, "node_modules/electron": { - "version": "23.1.2", - "resolved": "https://registry.npmjs.org/electron/-/electron-23.1.2.tgz", - "integrity": "sha512-ajE6xzIwH7swf8TlTU5WklDqpI3mPj4Am6690YrpCXzcp+E+dmMBXIajUUNt4joDrFhJC/lC6ZqDS2Q1BApKgQ==", + "version": "23.3.13", + "resolved": "https://registry.npmjs.org/electron/-/electron-23.3.13.tgz", + "integrity": "sha512-BaXtHEb+KYKLouUXlUVDa/lj9pj4F5kiE0kwFdJV84Y2EU7euIDgPthfKtchhr5MVHmjtavRMIV/zAwEiSQ9rQ==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -1158,9 +1090,9 @@ } }, "node_modules/engine.io": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.4.1.tgz", - "integrity": "sha512-JFYQurD/nbsA5BSPmbaOSLa3tSVj8L6o4srSwXXY3NqE+gGUNmmPTbhn8tjzcCtSqhFgIeqef81ngny8JM25hw==", + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.4.2.tgz", + "integrity": "sha512-FKn/3oMiJjrOEOeUub2WCox6JhxBXq/Zn3fZOMCBxKnNYtsdKjxhl7yR3fZhM9PV+rdE75SU5SYMc+2PGzo+Tg==", "dev": true, "dependencies": { "@types/cookie": "^0.4.1", @@ -1413,31 +1345,6 @@ "node": ">= 0.8" } }, - "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, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "bin": { - "flat": "cli.js" - } - }, "node_modules/flatbuffers": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-1.12.0.tgz", @@ -1773,15 +1680,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } - }, "node_modules/http-cache-semantics": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", @@ -1995,15 +1893,6 @@ "node": ">=0.12.0" } }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/is-running": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-running/-/is-running-2.1.0.tgz", @@ -2019,18 +1908,6 @@ "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, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -2070,18 +1947,6 @@ "node": ">= 0.8" } }, - "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, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -2311,21 +2176,6 @@ "json-buffer": "3.0.1" } }, - "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, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -2367,9 +2217,9 @@ } }, "node_modules/long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" }, "node_modules/loupe": { "version": "2.3.6", @@ -2567,249 +2417,12 @@ "mkdirp": "bin/cmd.js" } }, - "node_modules/mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", - "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", - "dev": true, - "dependencies": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha.js" - }, - "engines": { - "node": ">= 14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" - } - }, - "node_modules/mocha/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/mocha/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "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/mocha/node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/mocha/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/mocha/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, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "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" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/mocha/node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/mocha/node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/mocha/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/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, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/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 - }, - "node_modules/mocha/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, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/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, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -2913,14 +2526,6 @@ "wrappy": "1" } }, - "node_modules/onnx-proto": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/onnx-proto/-/onnx-proto-4.0.4.tgz", - "integrity": "sha512-aldMOB3HRoo6q/phyB6QRQxSt895HNNw82BNyZ2CMh4bjeKv7g/c+VpAFtJuEMVfYLMbRx61hbuqnKceLeDcDA==", - "dependencies": { - "protobufjs": "^6.8.8" - } - }, "node_modules/onnxruntime-common": { "resolved": "../common", "link": true @@ -2943,36 +2548,6 @@ "node": ">=4" } }, - "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, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "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", @@ -2982,15 +2557,6 @@ "node": ">= 0.8" } }, - "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, - "engines": { - "node": ">=8" - } - }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -3069,9 +2635,9 @@ } }, "node_modules/protobufjs": { - "version": "6.11.3", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", - "integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==", + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.4.tgz", + "integrity": "sha512-AT+RJgD2sH8phPmCf7OUZR8xGdcJRga4+1cOaXJ64hvcSkVhNcRHOwIxUatPH15+nj59WAGTDv3LSGZPEQbJaQ==", "hasInstallScript": true, "dependencies": { "@protobufjs/aspromise": "^1.1.2", @@ -3084,13 +2650,11 @@ "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", - "@types/long": "^4.0.1", "@types/node": ">=13.7.0", - "long": "^4.0.0" + "long": "^5.0.0" }, - "bin": { - "pbjs": "bin/pbjs", - "pbts": "bin/pbts" + "engines": { + "node": ">=12.0.0" } }, "node_modules/ps-tree": { @@ -3184,15 +2748,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -3346,26 +2901,6 @@ "queue-microtask": "^1.2.2" } }, - "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" - } - ] - }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -3417,15 +2952,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -3512,9 +3038,9 @@ } }, "node_modules/socket.io-parser": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.2.tgz", - "integrity": "sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.3.tgz", + "integrity": "sha512-JMafRntWVO2DCJimKsRTh/wnqVvO4hrfwOqtO7f+uzwsQMuxO6VwImtYxaQ+ieoyshWOTJyV0fA21lccEXRPpQ==", "dev": true, "dependencies": { "@socket.io/component-emitter": "~3.1.0", @@ -3837,12 +3363,6 @@ "which": "bin/which" } }, - "node_modules/workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true - }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -3993,21 +3513,6 @@ "node": ">=10" } }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", @@ -4017,18 +3522,6 @@ "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } - }, - "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==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } } }, "dependencies": { @@ -4231,11 +3724,6 @@ "@types/node": "*" } }, - "@types/long": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", - "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" - }, "@types/minimatch": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", @@ -4248,12 +3736,6 @@ "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", "dev": true }, - "@types/mocha": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz", - "integrity": "sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==", - "dev": true - }, "@types/node": { "version": "18.14.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz", @@ -4309,12 +3791,6 @@ "debug": "4" } }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, "ansi-regex": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", @@ -4340,12 +3816,6 @@ "picomatch": "^2.0.4" } }, - "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 - }, "assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -4444,12 +3914,6 @@ "fill-range": "^7.0.1" } }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, "browserstack": { "version": "1.5.3", "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.5.3.tgz", @@ -4527,12 +3991,6 @@ "get-intrinsic": "^1.0.2" } }, - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - }, "chai": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", @@ -4773,12 +4231,6 @@ "ms": "2.1.2" } }, - "decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true - }, "decompress-response": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", @@ -4847,12 +4299,6 @@ "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", "dev": true }, - "diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true - }, "dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -4893,9 +4339,9 @@ "dev": true }, "electron": { - "version": "23.1.2", - "resolved": "https://registry.npmjs.org/electron/-/electron-23.1.2.tgz", - "integrity": "sha512-ajE6xzIwH7swf8TlTU5WklDqpI3mPj4Am6690YrpCXzcp+E+dmMBXIajUUNt4joDrFhJC/lC6ZqDS2Q1BApKgQ==", + "version": "23.3.13", + "resolved": "https://registry.npmjs.org/electron/-/electron-23.3.13.tgz", + "integrity": "sha512-BaXtHEb+KYKLouUXlUVDa/lj9pj4F5kiE0kwFdJV84Y2EU7euIDgPthfKtchhr5MVHmjtavRMIV/zAwEiSQ9rQ==", "dev": true, "requires": { "@electron/get": "^2.0.0", @@ -4933,9 +4379,9 @@ } }, "engine.io": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.4.1.tgz", - "integrity": "sha512-JFYQurD/nbsA5BSPmbaOSLa3tSVj8L6o4srSwXXY3NqE+gGUNmmPTbhn8tjzcCtSqhFgIeqef81ngny8JM25hw==", + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.4.2.tgz", + "integrity": "sha512-FKn/3oMiJjrOEOeUub2WCox6JhxBXq/Zn3fZOMCBxKnNYtsdKjxhl7yR3fZhM9PV+rdE75SU5SYMc+2PGzo+Tg==", "dev": true, "requires": { "@types/cookie": "^0.4.1", @@ -5151,22 +4597,6 @@ } } }, - "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, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true - }, "flatbuffers": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-1.12.0.tgz", @@ -5413,12 +4843,6 @@ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, "http-cache-semantics": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", @@ -5587,12 +5011,6 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, - "is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true - }, "is-running": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-running/-/is-running-2.1.0.tgz", @@ -5605,12 +5023,6 @@ "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", "dev": true }, - "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 - }, "is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -5638,15 +5050,6 @@ "integrity": "sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==", "dev": true }, - "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, - "requires": { - "argparse": "^2.0.1" - } - }, "json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -5847,15 +5250,6 @@ "json-buffer": "3.0.1" } }, - "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, - "requires": { - "p-locate": "^5.0.0" - } - }, "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -5891,9 +5285,9 @@ } }, "long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" }, "loupe": { "version": "2.3.6", @@ -6038,181 +5432,12 @@ "minimist": "^1.2.6" } }, - "mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", - "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", - "dev": true, - "requires": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "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 - }, - "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "requires": { - "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" - }, - "dependencies": { - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - } - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "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, - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - } - }, - "minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - }, - "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 - }, - "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 - }, - "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, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true - }, "negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -6289,14 +5514,6 @@ "wrappy": "1" } }, - "onnx-proto": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/onnx-proto/-/onnx-proto-4.0.4.tgz", - "integrity": "sha512-aldMOB3HRoo6q/phyB6QRQxSt895HNNw82BNyZ2CMh4bjeKv7g/c+VpAFtJuEMVfYLMbRx61hbuqnKceLeDcDA==", - "requires": { - "protobufjs": "^6.8.8" - } - }, "onnxruntime-common": { "version": "file:../common", "requires": { @@ -6315,36 +5532,12 @@ "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", "dev": true }, - "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, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "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, - "requires": { - "p-limit": "^3.0.2" - } - }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "dev": true }, - "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 - }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -6402,9 +5595,9 @@ "dev": true }, "protobufjs": { - "version": "6.11.3", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", - "integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==", + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.4.tgz", + "integrity": "sha512-AT+RJgD2sH8phPmCf7OUZR8xGdcJRga4+1cOaXJ64hvcSkVhNcRHOwIxUatPH15+nj59WAGTDv3LSGZPEQbJaQ==", "requires": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", @@ -6416,9 +5609,8 @@ "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", - "@types/long": "^4.0.1", "@types/node": ">=13.7.0", - "long": "^4.0.0" + "long": "^5.0.0" } }, "ps-tree": { @@ -6473,15 +5665,6 @@ "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", "dev": true }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -6590,12 +5773,6 @@ "queue-microtask": "^1.2.2" } }, - "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 - }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -6634,15 +5811,6 @@ } } }, - "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, "setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -6711,9 +5879,9 @@ } }, "socket.io-parser": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.2.tgz", - "integrity": "sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.3.tgz", + "integrity": "sha512-JMafRntWVO2DCJimKsRTh/wnqVvO4hrfwOqtO7f+uzwsQMuxO6VwImtYxaQ+ieoyshWOTJyV0fA21lccEXRPpQ==", "dev": true, "requires": { "@socket.io/component-emitter": "~3.1.0", @@ -6946,12 +6114,6 @@ "isexe": "^2.0.0" } }, - "workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true - }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -7057,18 +6219,6 @@ "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", "dev": true }, - "yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "requires": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - } - }, "yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", @@ -7078,12 +6228,6 @@ "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } - }, - "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==", - "dev": true } } } diff --git a/js/web/package.json b/js/web/package.json index 9b18dcbd237c8..8ae5b733e5f21 100644 --- a/js/web/package.json +++ b/js/web/package.json @@ -8,19 +8,20 @@ "type": "git" }, "author": "fs-eire", - "version": "1.15.0", + "version": "1.17.0", "jsdelivr": "dist/ort.min.js", "dependencies": { "flatbuffers": "^1.12.0", "guid-typescript": "^1.0.9", - "long": "^4.0.0", - "onnx-proto": "^4.0.4", + "long": "^5.2.3", "onnxruntime-common": "file:../common", - "platform": "^1.3.6" + "platform": "^1.3.6", + "protobufjs": "^7.2.4" }, "scripts": { + "preprepare": "node -e \"require('node:fs').copyFileSync('./node_modules/long/index.d.ts', './node_modules/long/umd/index.d.ts')\"", "prepare": "tsc", - "build:doc": "node ./script/generate-operator-md", + "build:doc": "node ./script/generate-webgl-operator-md && node ./script/generate-webgpu-operator-md", "pull:wasm": "node ./script/pull-prebuilt-wasm-artifacts", "test:e2e": "node ./test/e2e/run", "build": "node ./script/build", @@ -38,10 +39,8 @@ "@types/emscripten": "^1.39.6", "@types/flatbuffers": "^1.10.0", "@types/karma": "^6.1.0", - "@types/long": "^4.0.1", "@types/minimatch": "^5.1.2", "@types/minimist": "^1.2.2", - "@types/mocha": "^10.0.1", "@types/platform": "^1.3.4", "@webgpu/types": "^0.1.30", "base64-js": "^1.5.1", @@ -61,11 +60,26 @@ "karma-sourcemap-loader": "^0.4.0", "minimatch": "^7.4.2", "minimist": "^1.2.8", - "mocha": "^10.2.0", "numpy-parser": "^1.2.3", "strip-json-comments": "^5.0.0" }, "main": "dist/ort-web.node.js", - "types": "./types/lib/index.d.ts", + "exports": { + ".": { + "node": { + "types": "./types.d.ts", + "default": "./dist/ort-web.node.js" + }, + "default": { + "types": "./types.d.ts", + "default": "./dist/ort.min.js" + } + }, + "./webgpu": { + "types": "./types.d.ts", + "default": "./dist/ort.webgpu.min.js" + } + }, + "types": "./types.d.ts", "description": "A Javascript library for running ONNX models on browsers" } diff --git a/js/web/script/build.ts b/js/web/script/build.ts index ebdce462b9279..03510ae86b85f 100644 --- a/js/web/script/build.ts +++ b/js/web/script/build.ts @@ -34,8 +34,11 @@ const ROOT_FOLDER = path.join(__dirname, '..'); const WASM_BINDING_FOLDER = path.join(ROOT_FOLDER, 'lib', 'wasm', 'binding'); const WASM_BINDING_JS_PATH = path.join(WASM_BINDING_FOLDER, 'ort-wasm.js'); const WASM_BINDING_THREADED_JS_PATH = path.join(WASM_BINDING_FOLDER, 'ort-wasm-threaded.js'); +const WASM_BINDING_SIMD_THREADED_JSEP_JS_PATH = path.join(WASM_BINDING_FOLDER, 'ort-wasm-simd-threaded.jsep.js'); const WASM_BINDING_THREADED_WORKER_JS_PATH = path.join(WASM_BINDING_FOLDER, 'ort-wasm-threaded.worker.js'); const WASM_BINDING_THREADED_MIN_JS_PATH = path.join(WASM_BINDING_FOLDER, 'ort-wasm-threaded.min.js'); +const WASM_BINDING_SIMD_THREADED_JSEP_MIN_JS_PATH = + path.join(WASM_BINDING_FOLDER, 'ort-wasm-simd-threaded.jsep.min.js'); const WASM_BINDING_THREADED_MIN_WORKER_JS_PATH = path.join(WASM_BINDING_FOLDER, 'ort-wasm-threaded.min.worker.js'); const WASM_DIST_FOLDER = path.join(ROOT_FOLDER, 'dist'); @@ -43,8 +46,11 @@ const WASM_WASM_PATH = path.join(WASM_DIST_FOLDER, 'ort-wasm.wasm'); const WASM_THREADED_WASM_PATH = path.join(WASM_DIST_FOLDER, 'ort-wasm-threaded.wasm'); const WASM_SIMD_WASM_PATH = path.join(WASM_DIST_FOLDER, 'ort-wasm-simd.wasm'); const WASM_SIMD_THREADED_WASM_PATH = path.join(WASM_DIST_FOLDER, 'ort-wasm-simd-threaded.wasm'); +const WASM_SIMD_JSEP_WASM_PATH = path.join(WASM_DIST_FOLDER, 'ort-wasm-simd.jsep.wasm'); +const WASM_SIMD_THREADED_JSEP_WASM_PATH = path.join(WASM_DIST_FOLDER, 'ort-wasm-simd-threaded.jsep.wasm'); const WASM_THREADED_WORKER_JS_PATH = path.join(WASM_DIST_FOLDER, 'ort-wasm-threaded.worker.js'); const WASM_THREADED_JS_PATH = path.join(WASM_DIST_FOLDER, 'ort-wasm-threaded.js'); +const WASM_SIMD_THREADED_JSEP_JS_PATH = path.join(WASM_DIST_FOLDER, 'ort-wasm-simd-threaded.jsep.js'); function validateFile(path: string): void { npmlog.info('Build', `Ensure file: ${path}`); @@ -61,11 +67,14 @@ if (WASM) { try { validateFile(WASM_BINDING_JS_PATH); validateFile(WASM_BINDING_THREADED_JS_PATH); + validateFile(WASM_BINDING_SIMD_THREADED_JSEP_JS_PATH); validateFile(WASM_BINDING_THREADED_WORKER_JS_PATH); validateFile(WASM_WASM_PATH); validateFile(WASM_THREADED_WASM_PATH); validateFile(WASM_SIMD_WASM_PATH); validateFile(WASM_SIMD_THREADED_WASM_PATH); + validateFile(WASM_SIMD_JSEP_WASM_PATH); + validateFile(WASM_SIMD_THREADED_JSEP_WASM_PATH); } catch (e) { npmlog.error('Build', `WebAssembly files are not ready. build WASM first. ERR: ${e}`); throw e; @@ -86,7 +95,7 @@ if (WASM) { 'npx', [ 'terser', WASM_BINDING_THREADED_JS_PATH, '--compress', 'passes=2', '--format', 'comments=false', '--mangle', - 'reserved=[_scriptDir]', '--module' + 'reserved=[_scriptDir,startWorker]', '--module' ], {shell: true, encoding: 'utf-8', cwd: ROOT_FOLDER}); if (terser.status !== 0) { @@ -105,13 +114,38 @@ if (WASM) { } npmlog.info('Build', 'Minimizing file "ort-wasm-threaded.js"... DONE'); + npmlog.info('Build', 'Minimizing file "ort-wasm-simd-threaded.jsep.js"...'); + try { + const terser = spawnSync( + 'npx', + [ + 'terser', WASM_BINDING_SIMD_THREADED_JSEP_JS_PATH, '--compress', 'passes=2', '--format', 'comments=false', + '--mangle', 'reserved=[_scriptDir,startWorker]', '--module' + ], + {shell: true, encoding: 'utf-8', cwd: ROOT_FOLDER}); + if (terser.status !== 0) { + console.error(terser.error); + process.exit(terser.status === null ? undefined : terser.status); + } + + fs.writeFileSync(WASM_BINDING_SIMD_THREADED_JSEP_MIN_JS_PATH, terser.stdout); + fs.writeFileSync(WASM_SIMD_THREADED_JSEP_JS_PATH, `${COPYRIGHT_BANNER}${terser.stdout}`); + + validateFile(WASM_BINDING_SIMD_THREADED_JSEP_MIN_JS_PATH); + validateFile(WASM_SIMD_THREADED_JSEP_JS_PATH); + } catch (e) { + npmlog.error('Build', `Failed to run terser on ort-wasm-threaded.js. ERR: ${e}`); + throw e; + } + npmlog.info('Build', 'Minimizing file "ort-wasm-simd-threaded.jsep.js"... DONE'); + npmlog.info('Build', 'Minimizing file "ort-wasm-threaded.worker.js"...'); try { const terser = spawnSync( 'npx', [ 'terser', WASM_BINDING_THREADED_WORKER_JS_PATH, '--compress', 'passes=2', '--format', 'comments=false', - '--mangle', 'reserved=[_scriptDir]', '--toplevel' + '--mangle', 'reserved=[_scriptDir,startWorker]', '--toplevel' ], {shell: true, encoding: 'utf-8'}); if (terser.status !== 0) { @@ -142,7 +176,12 @@ npmlog.info('Build', 'Building bundle...'); webpackArgs.push('--env', `-f=${FILTER}`); } npmlog.info('Build.Bundle', `CMD: npx ${webpackArgs.join(' ')}`); - const webpack = spawnSync('npx', webpackArgs, {shell: true, stdio: 'inherit', cwd: ROOT_FOLDER}); + const webpack = spawnSync('npx', webpackArgs, { + shell: true, + stdio: 'inherit', + cwd: ROOT_FOLDER, + env: {...process.env, NODE_OPTIONS: (process.env.NODE_OPTIONS ?? '') + ' --max-old-space-size=5120'} + }); if (webpack.status !== 0) { console.error(webpack.error); process.exit(webpack.status === null ? undefined : webpack.status); diff --git a/js/web/script/generate-operator-md.ts b/js/web/script/generate-webgl-operator-md.ts similarity index 97% rename from js/web/script/generate-operator-md.ts rename to js/web/script/generate-webgl-operator-md.ts index 0a1d845faf535..878a4c9a4008b 100644 --- a/js/web/script/generate-operator-md.ts +++ b/js/web/script/generate-webgl-operator-md.ts @@ -71,7 +71,7 @@ assert.ok(opsets.length === 1 && opsets[0] === 'Onnx'); const onnxOpset = ops.get(opsets[0])!; const opTypes = Array.from(onnxOpset.keys()).sort(); -const doc = fs.createWriteStream(path.join(__dirname, '../docs/operators.md')); +const doc = fs.createWriteStream(path.join(__dirname, '../docs/webgl-operators.md')); doc.write(`## Operators Support Table${EOL}${EOL}`); doc.write(`The following table shows [ai.onnx](https://github.com/onnx/onnx/blob/main/docs/Operators.md)\ operators from which onnx opset version are currently supported by ONNX Runtime Web. For example, \`4-6, 8+\` means\ diff --git a/js/web/script/generate-webgpu-operator-md.ts b/js/web/script/generate-webgpu-operator-md.ts new file mode 100644 index 0000000000000..7408f17004f5e --- /dev/null +++ b/js/web/script/generate-webgpu-operator-md.ts @@ -0,0 +1,107 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import fs from 'fs'; +import {EOL} from 'os'; +import path from 'path'; + +// The following variable allows to insert comments per operator + +const COMMENTS: Record = { + 'AveragePool': 'need perf optimization; need implementing activation', + 'MaxPool': 'need perf optimization; need implementing activation', + 'Conv': 'need perf optimization; conv3d is not supported; need implementing activation', + 'ConvTranspose': 'need perf optimization; ConvTranspose3d is not supported; need implementing activation', + 'Transpose': 'need perf optimization', + 'Reshape': 'no GPU kernel', + 'Shape': 'no GPU kernel; an ORT warning is generated - need to fix', + 'Resize': 'CoordinateTransformMode align_corners is not supported with downsampling', +}; + +/* eslint-disable max-len */ +const MATCHERS = [ + /class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME\(\s*(?\w+),\s*(?\w+),\s*(?\d+),\s*(?\d+),\s*(?\w+)\)/g, + /class ONNX_OPERATOR_KERNEL_CLASS_NAME\(\s*(?\w+),\s*(?\w+),\s*(?\d+),\s*(?\w+)\)/g, + /class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME\(\s*(?\w+),\s*(?\w+),\s*(?\d+),\s*(?\d+),\s*(?\w+),\s*(?\w+)\)/g, + /class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME\(\s*(?\w+),\s*(?\w+),\s*(?\d+),\s*(?\w+),\s*(?\w+)\)/g, +]; +/* eslint-enable max-len */ + +const ALL_REGISTERED_OPERATORS: Map < string, { + opset: Map>; + comments: string; +} +> = new Map(); + +// parse js_execution_provider.cc +const JS_EXECUTION_PROVIDER_CONTENTS = + fs.readFileSync(path.join(__dirname, '../../../onnxruntime/core/providers/js/js_execution_provider.cc'), 'utf8') + + fs.readFileSync(path.join(__dirname, '../../../onnxruntime/contrib_ops/js/js_contrib_kernels.cc'), 'utf8'); +MATCHERS.forEach(m => { + for (const match of JS_EXECUTION_PROVIDER_CONTENTS.matchAll(m)) { + const groups = match.groups!; + const {ep, opsetDomain, opsetVersion, opsetVersionStart, opsetVersionEnd, op} = groups; + + if (ep !== 'kJsExecutionProvider') { + throw new Error(`invalid EP registration for EP name: ${ep}`); + } + let domain = ''; + switch (opsetDomain) { + case 'kOnnxDomain': + domain = 'ai.onnx'; + break; + case 'kMSInternalNHWCDomain': + domain = 'com.ms.internal.nhwc'; + break; + case 'kMSDomain': + domain = 'com.microsoft'; + break; + default: + throw new Error(`not supported domain: ${opsetDomain}`); + } + + let opInfo = ALL_REGISTERED_OPERATORS.get(op); + if (!opInfo) { + opInfo = {opset: new Map(), comments: COMMENTS[op]}; + ALL_REGISTERED_OPERATORS.set(op, opInfo); + } + const {opset} = opInfo; + let currentDomainInfo = opset.get(domain); + if (!currentDomainInfo) { + currentDomainInfo = []; + opset.set(domain, currentDomainInfo); + } + if (opsetVersion) { + currentDomainInfo.push([parseInt(opsetVersion, 10), undefined]); + } else { + currentDomainInfo.push([parseInt(opsetVersionStart, 10), parseInt(opsetVersionEnd, 10)]); + } + currentDomainInfo.sort((a, b) => a[0] - b[0]); + } +}); + +const doc = fs.createWriteStream(path.join(__dirname, '../docs/webgpu-operators.md')); +doc.write(`## Operators Support Table${EOL}${EOL}`); +doc.write(`The following table shows ONNX +operators and the supported opset domain/versions in WebGPU EP by ONNX Runtime Web. For example, +\`4-6, 8+\` means ONNX Runtime Web currently support opset version 4 to 6, 8 and above.${EOL}${EOL}`); +doc.write(`*This file is automatically generated from the +def files via [this script](../script/generate-webgpu-operator-md.ts). +Do not modify directly.*${EOL}${EOL}`); +doc.write(`| Operator | Opset | Comments |${EOL}`); +doc.write(`|:--------:|:-------------:|-----|${EOL}`); + +Array.from(ALL_REGISTERED_OPERATORS.keys()).sort().forEach(op => { + const {opset, comments} = ALL_REGISTERED_OPERATORS.get(op)!; + const opsetString = + Array.from(opset.keys()) + .sort() + .map( + domain => `${domain}(${ + [...new Set(opset.get(domain)!.map( + ver => ver[1] ? (ver[0] === ver[1] ? `${ver[0]}` : `${ver[0]}-${ver[1]}`) : `${ver[0]}+`))] + .join(',')})`) + .join('; '); + doc.write(`| ${op} | ${opsetString} | ${comments ?? ''} |${EOL}`); +}); +doc.end(); diff --git a/js/web/script/prepack.ts b/js/web/script/prepack.ts index be86c5687bec0..4c5941d8dae12 100644 --- a/js/web/script/prepack.ts +++ b/js/web/script/prepack.ts @@ -11,7 +11,7 @@ function updatePackageJson() { const packageCommon = fs.readJSONSync(commonPackageJsonPath); const packageSelf = fs.readJSONSync(selfPackageJsonPath); const version = packageCommon.version; - packageSelf.dependencies['onnxruntime-common'] = `~${version}`; + packageSelf.dependencies['onnxruntime-common'] = `${version}`; fs.writeJSONSync(selfPackageJsonPath, packageSelf, {spaces: 2}); console.log('=== finished updating package.json.'); } diff --git a/js/web/script/pull-prebuilt-wasm-artifacts.ts b/js/web/script/pull-prebuilt-wasm-artifacts.ts index bd6fa1af4fefe..aa0a1f88e1d6b 100644 --- a/js/web/script/pull-prebuilt-wasm-artifacts.ts +++ b/js/web/script/pull-prebuilt-wasm-artifacts.ts @@ -8,7 +8,7 @@ // 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 +// 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 // @@ -18,6 +18,35 @@ import https from 'https'; import jszip from 'jszip'; import path from 'path'; +const HELP_MESSAGE = ` +pull-prebuilt-wasm-artifacts + +Usage: + npm run pull:wasm [config] [buildID] [help|h] + + node ./pull-prebuilt-wasm-artifacts [config] [buildID] [help|h] + + + 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 +`; + +const argv = process.argv.slice(2); + +if (argv.indexOf('--help') !== -1 || argv.indexOf('-h') !== -1 || argv.indexOf('help') !== -1 || + argv.indexOf('h') !== -1) { + 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] ?? ''); + +const folderName = config === 'release' ? 'Release_wasm' : 'Debug_wasm'; + function downloadJson(url: string, onSuccess: (data: any) => void) { https.get(url, res => { const {statusCode} = res; @@ -70,18 +99,20 @@ function extractFile(zip: jszip, folder: string, file: string, artifactName: str }); } -console.log('=== Start to pull WebAssembly artifacts from CI ==='); +console.log(`=== Start to pull ${config} WebAssembly artifacts from CI for ${ + buildId ? `build "${buildId}"` : 'latest "main" branch'} ===`); -// 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' + - '&definitions=161' + +const filter = buildId ? `&buildIds=${buildId}` : + '&definitions=161' + '&resultFilter=succeeded%2CpartiallySucceeded' + '&$top=1' + '&repositoryId=Microsoft/onnxruntime' + '&repositoryType=GitHub' + - '&branchName=refs/heads/main', - data => { + '&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} ===`); @@ -93,7 +124,7 @@ downloadJson( data => { let zipLink; for (const v of data.value) { - if (v.name === 'Release_wasm') { + if (v.name === folderName) { zipLink = v.resource.downloadUrl; } } @@ -108,14 +139,20 @@ downloadJson( downloadZip(zipLink, buffer => { void jszip.loadAsync(buffer).then(zip => { - extractFile(zip, WASM_FOLDER, 'ort-wasm.wasm', 'Release_wasm'); - extractFile(zip, WASM_FOLDER, 'ort-wasm-threaded.wasm', 'Release_wasm'); - extractFile(zip, WASM_FOLDER, 'ort-wasm-simd.wasm', 'Release_wasm'); - extractFile(zip, WASM_FOLDER, 'ort-wasm-simd-threaded.wasm', 'Release_wasm'); - - extractFile(zip, JS_FOLDER, 'ort-wasm.js', 'Release_wasm'); - extractFile(zip, JS_FOLDER, 'ort-wasm-threaded.js', 'Release_wasm'); - extractFile(zip, JS_FOLDER, 'ort-wasm-threaded.worker.js', 'Release_wasm'); + extractFile(zip, WASM_FOLDER, 'ort-wasm.wasm', folderName); + extractFile(zip, WASM_FOLDER, 'ort-wasm-threaded.wasm', folderName); + extractFile(zip, WASM_FOLDER, 'ort-wasm-simd.wasm', folderName); + extractFile(zip, WASM_FOLDER, 'ort-wasm-simd-threaded.wasm', folderName); + extractFile(zip, WASM_FOLDER, 'ort-wasm-simd.jsep.wasm', folderName); + extractFile(zip, WASM_FOLDER, 'ort-wasm-simd-threaded.jsep.wasm', folderName); + extractFile(zip, WASM_FOLDER, 'ort-training-wasm-simd.wasm', folderName); + + extractFile(zip, JS_FOLDER, 'ort-wasm.js', folderName); + extractFile(zip, JS_FOLDER, 'ort-wasm-threaded.js', folderName); + extractFile(zip, JS_FOLDER, 'ort-wasm-threaded.worker.js', folderName); + extractFile(zip, JS_FOLDER, 'ort-wasm-simd.jsep.js', folderName); + extractFile(zip, JS_FOLDER, 'ort-wasm-simd-threaded.jsep.js', folderName); + extractFile(zip, JS_FOLDER, 'ort-training-wasm-simd.js', folderName); }); }); }); diff --git a/js/web/script/test-runner-cli-args.ts b/js/web/script/test-runner-cli-args.ts index e20c391513c67..f90f568879146 100644 --- a/js/web/script/test-runner-cli-args.ts +++ b/js/web/script/test-runner-cli-args.ts @@ -37,6 +37,7 @@ Options: webgpu wasm xnnpack + webnn -e=<...>, --env=<...> Specify the environment to run the test. Should be one of the following: chrome (default) edge (Windows only) @@ -65,7 +66,7 @@ Options: *** Backend Options *** - --wasm-number-threads Set the WebAssembly number of threads + -x, --wasm-number-threads Set the WebAssembly number of threads --wasm-init-timeout Set the timeout for WebAssembly backend initialization, in milliseconds --wasm-enable-simd Set whether to enable SIMD --wasm-enable-proxy Set whether to enable proxy worker @@ -79,6 +80,7 @@ Options: --no-sandbox This flag will be passed to Chrome. Sometimes Chrome need this flag to work together with Karma. + --chromium-flags=<...> This flag will be passed to Chrome and Edge browsers. Can be used multiple times. Examples: @@ -104,7 +106,7 @@ Examples: export declare namespace TestRunnerCliArgs { type Mode = 'suite0'|'suite1'|'model'|'unittest'|'op'; - type Backend = 'cpu'|'webgl'|'webgpu'|'wasm'|'onnxruntime'|'xnnpack'; + type Backend = 'cpu'|'webgl'|'webgpu'|'wasm'|'onnxruntime'|'xnnpack'|'webnn'; type Environment = 'chrome'|'edge'|'firefox'|'electron'|'safari'|'node'|'bs'; type BundleMode = 'prod'|'dev'|'perf'; } @@ -170,8 +172,9 @@ export interface TestRunnerCliArgs { cudaFlags?: Record; wasmOptions?: InferenceSession.WebAssemblyExecutionProviderOption; webglOptions?: InferenceSession.WebGLExecutionProviderOption; - globalEnvFlags?: Env; + globalEnvFlags?: Test.Options['globalEnvFlags']; noSandbox?: boolean; + chromiumFlags: string[]; } @@ -263,9 +266,9 @@ function parseWasmOptions(_args: minimist.ParsedArgs): InferenceSession.WebAssem } function parseWasmFlags(args: minimist.ParsedArgs): Env.WebAssemblyFlags { - const numThreads = args['wasm-number-threads']; + const numThreads = args.x || args['wasm-number-threads']; if (typeof numThreads !== 'undefined' && typeof numThreads !== 'number') { - throw new Error('Flag "wasm-number-threads" must be a number value'); + throw new Error('Flag "x"/"wasm-number-threads" must be a number value'); } const initTimeout = args['wasm-init-timeout']; if (typeof initTimeout !== 'undefined' && typeof initTimeout !== 'number') { @@ -294,7 +297,7 @@ function parseWebglOptions(_args: minimist.ParsedArgs): InferenceSession.WebGLEx return {name: 'webgl'}; } -function parseWebglFlags(args: minimist.ParsedArgs): Env.WebGLFlags { +function parseWebglFlags(args: minimist.ParsedArgs): Partial { const contextId = args['webgl-context-id']; if (contextId !== undefined && contextId !== 'webgl' && contextId !== 'webgl2') { throw new Error('Flag "webgl-context-id" is invalid'); @@ -318,7 +321,7 @@ function parseWebglFlags(args: minimist.ParsedArgs): Env.WebGLFlags { return {contextId, matmulMaxBatchSize, textureCacheMode, pack}; } -function parseWebgpuFlags(args: minimist.ParsedArgs): Env.WebGpuFlags { +function parseWebgpuFlags(args: minimist.ParsedArgs): Partial { const profilingMode = args['webgpu-profiling-mode']; if (profilingMode !== undefined && profilingMode !== 'off' && profilingMode !== 'default') { throw new Error('Flag "webgpu-profiling-mode" is invalid'); @@ -326,7 +329,7 @@ function parseWebgpuFlags(args: minimist.ParsedArgs): Env.WebGpuFlags { return {profilingMode}; } -function parseGlobalEnvFlags(args: minimist.ParsedArgs): Env { +function parseGlobalEnvFlags(args: minimist.ParsedArgs): NonNullable { const wasm = parseWasmFlags(args); const webgl = parseWebglFlags(args); const webgpu = parseWebgpuFlags(args); @@ -359,12 +362,13 @@ export function parseTestRunnerCliArgs(cmdlineArgs: string[]): TestRunnerCliArgs } // Option: -b=<...>, --backend=<...> - const browserBackends = ['webgl', 'webgpu', 'wasm', 'xnnpack']; + const browserBackends = ['webgl', 'webgpu', 'wasm', 'xnnpack', 'webnn']; - // TODO: remove this when Chrome support WebGPU. - // we need this for now because Chrome does not support webgpu yet, + // TODO: remove this when Chrome support WebNN. + // we need this for now because Chrome does not support webnn yet, // and ChromeCanary is not in CI. - const defaultBrowserBackends = ['webgl', /* 'webgpu', */ 'wasm', 'xnnpack']; + + const defaultBrowserBackends = ['webgl', 'webgpu', 'wasm', 'xnnpack' /*, 'webnn'*/]; const nodejsBackends = ['cpu', 'wasm']; const backendArgs = args.backend || args.b; const backend = (typeof backendArgs !== 'string') ? (env === 'node' ? nodejsBackends : defaultBrowserBackends) : @@ -377,6 +381,10 @@ export function parseTestRunnerCliArgs(cmdlineArgs: string[]): TestRunnerCliArgs const globalEnvFlags = parseGlobalEnvFlags(args); + if (backend.includes('webnn') && !globalEnvFlags.wasm!.proxy) { + throw new Error('Backend webnn requires flag "wasm-enable-proxy" to be set to true.'); + } + // Options: // --log-verbose=<...> // --log-info=<...> @@ -432,6 +440,17 @@ export function parseTestRunnerCliArgs(cmdlineArgs: string[]): TestRunnerCliArgs // Option: --no-sandbox const noSandbox = !!args['no-sandbox']; + // parse chromium flags + let chromiumFlags = args['chromium-flags']; + if (!chromiumFlags) { + chromiumFlags = []; + } else if (typeof chromiumFlags === 'string') { + chromiumFlags = [chromiumFlags]; + } else if (!Array.isArray(chromiumFlags)) { + throw new Error(`Invalid command line arg: --chromium-flags: ${chromiumFlags}`); + } + + npmlog.verbose('TestRunnerCli.Init', ` Mode: ${mode}`); npmlog.verbose('TestRunnerCli.Init', ` Env: ${env}`); npmlog.verbose('TestRunnerCli.Init', ` Debug: ${debug}`); @@ -455,6 +474,7 @@ export function parseTestRunnerCliArgs(cmdlineArgs: string[]): TestRunnerCliArgs webglOptions, wasmOptions, globalEnvFlags, - noSandbox + noSandbox, + chromiumFlags }; } diff --git a/js/web/script/test-runner-cli.ts b/js/web/script/test-runner-cli.ts index 72938789bc2df..f3764e63fcf45 100644 --- a/js/web/script/test-runner-cli.ts +++ b/js/web/script/test-runner-cli.ts @@ -53,10 +53,11 @@ async function main() { // The default backends and opset version lists. Those will be used in suite tests. const DEFAULT_BACKENDS: readonly TestRunnerCliArgs.Backend[] = - args.env === 'node' ? ['cpu', 'wasm'] : ['wasm', 'webgl', 'webgpu']; + args.env === 'node' ? ['cpu', 'wasm'] : ['wasm', 'webgl', 'webgpu', 'webnn']; const DEFAULT_OPSET_VERSIONS = fs.readdirSync(TEST_DATA_MODEL_NODE_ROOT, {withFileTypes: true}) .filter(dir => dir.isDirectory() && dir.name.startsWith('opset')) .map(dir => dir.name.slice(5)); + const MAX_OPSET_VERSION = Math.max(...DEFAULT_OPSET_VERSIONS.map(v => Number.parseInt(v, 10))); const FILE_CACHE_ENABLED = args.fileCache; // whether to enable file cache const FILE_CACHE_MAX_FILE_SIZE = 1 * 1024 * 1024; // The max size of the file that will be put into file cache @@ -70,16 +71,23 @@ async function main() { if (shouldLoadSuiteTestData) { npmlog.verbose('TestRunnerCli.Init', 'Loading test groups for suite test...'); + // collect all model test folders + const allNodeTestsFolders = + DEFAULT_OPSET_VERSIONS + .map(version => { + const suiteRootFolder = path.join(TEST_DATA_MODEL_NODE_ROOT, `opset${version}`); + if (!fs.existsSync(suiteRootFolder) || !fs.statSync(suiteRootFolder).isDirectory()) { + throw new Error(`model test root folder '${suiteRootFolder}' does not exist.`); + } + return fs.readdirSync(suiteRootFolder).map(f => `opset${version}/${f}`); + }) + .flat(); + for (const backend of DEFAULT_BACKENDS) { - for (const version of DEFAULT_OPSET_VERSIONS) { - let nodeTest = nodeTests.get(backend); - if (!nodeTest) { - nodeTest = []; - nodeTests.set(backend, nodeTest); - } - nodeTest.push(loadNodeTests(backend, version)); + if (args.backends.indexOf(backend) !== -1) { + nodeTests.set(backend, loadNodeTests(backend, allNodeTestsFolders)); + opTests.set(backend, loadOpTests(backend)); } - opTests.set(backend, loadOpTests(backend)); } } @@ -170,12 +178,11 @@ async function main() { const testCaseName = typeof testCase === 'string' ? testCase : testCase.name; let found = false; for (const testGroup of nodeTest) { - found = found || - testGroup.tests.some( - test => minimatch( - test.modelUrl, - path.join('**', testCaseName, '*.+(onnx|ort)').replace(/\\/g, '/'), - )); + found ||= minimatch + .match( + testGroup.tests.map(test => test.modelUrl).filter(url => url !== ''), + path.join('**', testCaseName, '*.+(onnx|ort)').replace(/\\/g, '/'), {matchBase: true}) + .length > 0; } if (!found) { throw new Error(`node model test case '${testCaseName}' in test list does not exist.`); @@ -207,43 +214,47 @@ async function main() { } } - function loadNodeTests(backend: string, version: string): Test.ModelTestGroup { - return suiteFromFolder( - `node-opset_v${version}-${backend}`, path.join(TEST_DATA_MODEL_NODE_ROOT, `opset${version}`), backend, - testlist[backend].node); - } + function loadNodeTests(backend: string, allFolders: string[]): Test.ModelTestGroup[] { + const allTests = testlist[backend]?.node; + + // key is folder name, value is test index array + const folderTestMatchCount = new Map(allFolders.map(f => [f, []])); + // key is test category, value is a list of model test + const opsetTests = new Map(); + + allTests.forEach((test, i) => { + const testName = typeof test === 'string' ? test : test.name; + const matches = minimatch.match(allFolders, path.join('**', testName).replace(/\\/g, '/')); + matches.forEach(m => folderTestMatchCount.get(m)!.push(i)); + }); + + for (const folder of allFolders) { + const testIds = folderTestMatchCount.get(folder); + const times = testIds ? testIds.length : 0; + if (times > 1) { + throw new Error(`multiple testlist rules matches test: ${path.join(TEST_DATA_MODEL_NODE_ROOT, folder)}`); + } - function suiteFromFolder( - name: string, suiteRootFolder: string, backend: string, - testlist?: readonly Test.TestList.Test[]): Test.ModelTestGroup { - const sessions: Test.ModelTest[] = []; - const tests = fs.readdirSync(suiteRootFolder); - for (const test of tests) { - let condition: Test.Condition|undefined; - let times: number|undefined; - if (testlist) { - const matches = testlist.filter( - p => minimatch( - path.join(suiteRootFolder, test), - path.join('**', typeof p === 'string' ? p : p.name).replace(/\\/g, '/'))); - if (matches.length === 0) { - times = 0; - } else if (matches.length === 1) { - const match = matches[0]; - if (typeof match !== 'string') { - condition = match.condition; - } - } else { - throw new Error(`multiple testlist rules matches test: ${path.join(suiteRootFolder, test)}`); - } + const test = testIds && testIds.length > 0 ? allTests[testIds[0]] : undefined; + const platformCondition = test && typeof test !== 'string' ? test.platformCondition : undefined; + + const opsetVersion = folder.split('/')[0]; + const category = `node-${opsetVersion}-${backend}`; + let modelTests = opsetTests.get(category); + if (!modelTests) { + modelTests = []; + opsetTests.set(category, modelTests); } - sessions.push(modelTestFromFolder(path.resolve(suiteRootFolder, test), backend, condition, times)); + modelTests.push( + modelTestFromFolder(path.resolve(TEST_DATA_MODEL_NODE_ROOT, folder), backend, platformCondition, times)); } - return {name, tests: sessions}; + + return Array.from(opsetTests.keys()).map(category => ({name: category, tests: opsetTests.get(category)!})); } function modelTestFromFolder( - testDataRootFolder: string, backend: string, condition?: Test.Condition, times?: number): Test.ModelTest { + testDataRootFolder: string, backend: string, platformCondition?: Test.PlatformCondition, + times?: number): Test.ModelTest { if (times === 0) { npmlog.verbose('TestRunnerCli.Init.Model', `Skip test data from folder: ${testDataRootFolder}`); return {name: path.basename(testDataRootFolder), backend, modelUrl: '', cases: []}; @@ -319,7 +330,7 @@ async function main() { npmlog.verbose('TestRunnerCli.Init.Model', ` Test set(s): ${cases.length} (${caseCount})`); npmlog.verbose('TestRunnerCli.Init.Model', '==============================================================='); - return {name: path.basename(testDataRootFolder), condition, modelUrl, backend, cases}; + return {name: path.basename(testDataRootFolder), platformCondition, modelUrl, backend, cases}; } function tryLocateModelTestFolder(searchPattern: string): string { @@ -378,6 +389,7 @@ async function main() { // field 'verbose' and 'backend' is not set for (const test of tests) { test.backend = backend; + test.opset = test.opset || {domain: '', version: MAX_OPSET_VERSION}; } npmlog.verbose('TestRunnerCli.Init.Op', 'Finished preparing test data.'); npmlog.verbose('TestRunnerCli.Init.Op', '==============================================================='); @@ -459,26 +471,38 @@ async function main() { // STEP 5. use Karma to run test npmlog.info('TestRunnerCli.Run', '(4/4) Running karma to start test runner...'); const webgpu = args.backends.indexOf('webgpu') > -1; + const webnn = args.backends.indexOf('webnn') > -1; const browser = getBrowserNameFromEnv( args.env, args.bundleMode === 'perf' ? 'perf' : args.debug ? 'debug' : 'test', - webgpu, config.options.globalEnvFlags?.webgpu?.profilingMode === 'default'); + webgpu, webnn); const karmaArgs = ['karma', 'start', `--browsers ${browser}`]; + const chromiumFlags = ['--enable-features=SharedArrayBuffer', ...args.chromiumFlags]; if (args.debug) { karmaArgs.push('--log-level info --timeout-mocha 9999999'); + chromiumFlags.push('--remote-debugging-port=9333'); } else { karmaArgs.push('--single-run'); } if (args.noSandbox) { karmaArgs.push('--no-sandbox'); } - if (webgpu) { + if (webgpu || webnn) { karmaArgs.push('--force-localhost'); } + if (webgpu) { + // flag 'allow_unsafe_apis' is required to enable experimental features like fp16 and profiling inside pass. + // flag 'use_dxc' is required to enable DXC compiler. + chromiumFlags.push('--enable-dawn-features=allow_unsafe_apis,use_dxc'); + } + if (webnn) { + chromiumFlags.push('--enable-experimental-web-platform-features'); + } karmaArgs.push(`--bundle-mode=${args.bundleMode}`); - if (browser === 'Edge') { + karmaArgs.push(...chromiumFlags.map(flag => `--chromium-flags=${flag}`)); + if (browser.startsWith('Edge')) { // There are currently 2 Edge browser launchers: // - karma-edge-launcher: used to launch the old Edge browser // - karma-chromium-edge-launcher: used to launch the new chromium-kernel Edge browser @@ -569,12 +593,12 @@ async function main() { } function getBrowserNameFromEnv( - env: TestRunnerCliArgs['env'], mode: 'debug'|'perf'|'test', webgpu: boolean, profile: boolean) { + env: TestRunnerCliArgs['env'], mode: 'debug'|'perf'|'test', webgpu: boolean, webnn: boolean) { switch (env) { case 'chrome': - return selectChromeBrowser(mode, webgpu, profile); + return selectChromeBrowser(mode, webgpu, webnn); case 'edge': - return 'Edge'; + return 'EdgeTest'; case 'firefox': return 'Firefox'; case 'electron': @@ -588,22 +612,18 @@ async function main() { } } - function selectChromeBrowser(mode: 'debug'|'perf'|'test', webgpu: boolean, profile: boolean) { - if (webgpu) { - switch (mode) { - case 'debug': - return profile ? 'ChromeCanaryProfileDebug' : 'ChromeCanaryDebug'; - default: - return profile ? 'ChromeCanaryProfileTest' : 'ChromeCanaryDebug'; - } + function selectChromeBrowser(mode: 'debug'|'perf'|'test', webgpu: boolean, webnn: boolean) { + if (webnn) { + return 'ChromeCanaryTest'; + } else if (webgpu) { + return 'ChromeTest'; } else { switch (mode) { case 'debug': - return 'ChromeDebug'; case 'perf': - return 'ChromePerf'; - default: return 'ChromeTest'; + default: + return 'ChromeTestHeadless'; } } } diff --git a/js/web/test/data/ops/_example.jsonc b/js/web/test/data/ops/_example.jsonc new file mode 100644 index 0000000000000..79d084a68d8a3 --- /dev/null +++ b/js/web/test/data/ops/_example.jsonc @@ -0,0 +1,110 @@ +// This file is an example of an operator test file. +// +// In this file, we demonstrate how to write a test file for ONNX operators. +// There are 2 operator tests defined in this file: +// +// - "Simple Abs test example": a simple operator test for Abs operator. This example shows how to write a simple test with minimal properties. +// +// - "Conv2D with padding": a simple operator test for Conv operator with padding. This example shows how to write a test with all optional properties. +// + +// test file starts with an array of test objects. +[ + // this is the first operator test object (Abs example). + { + "name": "Simple Abs op test example", // name of the test + "operator": "Abs", // OpType of the operator + "cases": [ + // in this example, we only have one test case. + { + // name of the test case + "name": "3D float32 test", + "inputs": [ + // specify the input tensor + { + "data": [1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14, -1, -2, -3, -4, -5, -6, -7, -8, 101, 102, 103, 104], + "dims": [2, 3, 4], + "type": "float32" + } + ], + "outputs": [ + { + "data": [1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14, 1, 2, 3, 4, 5, 6, 7, 8, 101, 102, 103, 104], + "dims": [2, 3, 4], + "type": "float32" + } + ] + } + ] + }, + // this is the second operator test object (Conv example). + { + // name of the test + "name": "Conv op test example", + + // OpType of the operator + "operator": "Conv", + + // [optional] specify the attributes of the operator + "attributes": [{ "name": "kernel_shape", "data": [2, 2], "type": "ints" }], + + // [optional] specify a regex pattern to match the platform description. + // + // If not specified, the test will run on all platforms. + // Otherwise, the test will only run on platforms that match the pattern. + "platformCondition": "", + + // [optional] specify input shape definitions. + // + // Sometimes, input shape definitions can offer shape information for ONNX Runtime to optimize its inferencing behavior. + // For example, ORT will transform a NCHW Conv operator into a NHWC operator when the input shape is 4 dimensional. + // If the input shape dimension is unknown, ORT will not perform this optimization. + // + // In operator test, we can specify input shape definitions to test the optimized behavior. + // + // The array of input shape definitions should have the same length as the number of model's inputs. + // + "inputShapeDefinitions": [ + // input 0 shape definition. use semantic names to specify the dynamic dimensions. + ["__input_0_dim_0", "__input_0_dim_1", "__input_0_dim_2", "__input_0_dim_3"], + // input 1 shape definition. use numbers to specify the static dimensions. + [1, 1, 2, 2] + ], + + // [optional] specify the opset of the operator. + "opset": { "domain": "", "version": 13 }, + + // test cases is required. + "cases": [ + { + "name": "NCHW Conv2D test", + "inputs": [ + { + "data": [10, 20, 30, 40, 50, 60, 70, 80, 90], + "dims": [1, 1, 3, 3], + "type": "float32" + }, + // an input or output can be optional, depending on the operator. + // if an input or output is optional, we can specify it as follows: + // + // { + // "data": null, + // "type": "float32" + // } + { + "data": [1, 2, 3, 4], + "dims": [1, 1, 2, 2], + "type": "float32" + } + ], + "outputs": [ + { + "data": [370, 470, 670, 770], + "dims": [1, 1, 2, 2], + "type": "float32" + } + ] + } + ] + } +] diff --git a/js/web/test/data/ops/abs-int32.jsonc b/js/web/test/data/ops/abs-int32.jsonc new file mode 100644 index 0000000000000..53538058dab7d --- /dev/null +++ b/js/web/test/data/ops/abs-int32.jsonc @@ -0,0 +1,26 @@ +[ + { + "name": "abs with no attributes", + "operator": "Abs", + "attributes": [], + "cases": [ + { + "name": "T[2,4] (int32)", + "inputs": [ + { + "data": [1, 2, 1, 3, 2, 3, 1, 2], + "dims": [2, 4], + "type": "int32" + } + ], + "outputs": [ + { + "data": [1, 2, 1, 3, 2, 3, 1, 2], + "dims": [2, 4], + "type": "int32" + } + ] + } + ] + } +] diff --git a/js/web/test/data/ops/abss.jsonc b/js/web/test/data/ops/abss.jsonc index 0c08d37941fb3..e8ddc79865771 100644 --- a/js/web/test/data/ops/abss.jsonc +++ b/js/web/test/data/ops/abss.jsonc @@ -8,64 +8,14 @@ "name": "T[2,3,4]", "inputs": [ { - "data": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 11, - 12, - 13, - 14, - -1, - -2, - -3, - -4, - -5, - -6, - -7, - -8, - 101, - 102, - 103, - 104 - ], + "data": [1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14, -1, -2, -3, -4, -5, -6, -7, -8, 101, 102, 103, 104], "dims": [2, 3, 4], "type": "float32" } ], "outputs": [ { - "data": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 11, - 12, - 13, - 14, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 101, - 102, - 103, - 104 - ], + "data": [1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14, 1, 2, 3, 4, 5, 6, 7, 8, 101, 102, 103, 104], "dims": [2, 3, 4], "type": "float32" } diff --git a/js/web/test/data/ops/acos.jsonc b/js/web/test/data/ops/acos.jsonc index 96a59e4d178f0..b9b4af18b7bff 100644 --- a/js/web/test/data/ops/acos.jsonc +++ b/js/web/test/data/ops/acos.jsonc @@ -49,16 +49,7 @@ ], "outputs": [ { - "data": [ - 1.4706, - 1.3694, - 1.2661, - 1.1593, - 0.451, - 0.6435, - 0.7954, - 0.9273 - ], + "data": [1.4706, 1.3694, 1.2661, 1.1593, 0.451, 0.6435, 0.7954, 0.9273], "dims": [2, 4], "type": "float32" } diff --git a/js/web/test/data/ops/add.jsonc b/js/web/test/data/ops/add.jsonc index 3398e02b509f2..e5b4ff2b53148 100644 --- a/js/web/test/data/ops/add.jsonc +++ b/js/web/test/data/ops/add.jsonc @@ -79,64 +79,14 @@ "type": "float32" }, { - "data": [ - 2, - 6, - 1, - 2, - 1, - 3, - 1, - 4, - 3, - 5, - 3, - 4, - 1, - 4, - 1, - 6, - 4, - 4, - 5, - 6, - 2, - 4, - 2, - 6 - ], + "data": [2, 6, 1, 2, 1, 3, 1, 4, 3, 5, 3, 4, 1, 4, 1, 6, 4, 4, 5, 6, 2, 4, 2, 6], "dims": [3, 2, 4], "type": "float32" } ], "outputs": [ { - "data": [ - 3, - 8, - 4, - 6, - 6, - 9, - 8, - 12, - 4, - 7, - 6, - 8, - 6, - 10, - 8, - 14, - 5, - 6, - 8, - 10, - 7, - 10, - 9, - 14 - ], + "data": [3, 8, 4, 6, 6, 9, 8, 12, 4, 7, 6, 8, 6, 10, 8, 14, 5, 6, 8, 10, 7, 10, 9, 14], "dims": [3, 2, 4], "type": "float32" } diff --git a/js/web/test/data/ops/asin.jsonc b/js/web/test/data/ops/asin.jsonc index 23039d6563f30..748ca18aa78a4 100644 --- a/js/web/test/data/ops/asin.jsonc +++ b/js/web/test/data/ops/asin.jsonc @@ -49,16 +49,7 @@ ], "outputs": [ { - "data": [ - 0.10016742, - 0.20135792, - 0.30469265, - 0.41151685, - 1.11976951, - 0.92729522, - 0.7753975, - 0.64350111 - ], + "data": [0.10016742, 0.20135792, 0.30469265, 0.41151685, 1.11976951, 0.92729522, 0.7753975, 0.64350111], "dims": [2, 4], "type": "float32" } diff --git a/js/web/test/data/ops/cast.jsonc b/js/web/test/data/ops/cast.jsonc new file mode 100644 index 0000000000000..a90d1c35782df --- /dev/null +++ b/js/web/test/data/ops/cast.jsonc @@ -0,0 +1,248 @@ +[ + { + "name": "Cast float32 to int32", + "operator": "Cast", + "attributes": [{ "name": "to", "type": "int", "data": 6 }], + "cases": [ + { + "name": "2x3", + "inputs": [ + { + "data": [0.0, 0.5, 100.0, -234.0, -7.99, 1000000000], + "dims": [2, 3], + "type": "float32" + } + ], + "outputs": [ + { + "data": [0, 0, 100, -234, -7, 1000000000], + "dims": [2, 3], + "type": "int32" + } + ] + }, + { + "name": "Scalar", + "inputs": [ + { + "data": [1], + "dims": [], + "type": "float32" + } + ], + "outputs": [ + { + "data": [1], + "dims": [], + "type": "int32" + } + ] + } + ] + }, + { + "name": "Cast int32 to float32", + "operator": "Cast", + "attributes": [{ "name": "to", "type": "int", "data": 1 }], + "cases": [ + { + "name": "2x3", + "inputs": [ + { + "data": [0, 0, 100, -234, -7, 1000000000], + "dims": [2, 3], + "type": "int32" + } + ], + "outputs": [ + { + "data": [0, 0, 100, -234, -7, 1000000000], + "dims": [2, 3], + "type": "float32" + } + ] + }, + { + "name": "Scalar", + "inputs": [ + { + "data": [1], + "dims": [], + "type": "int32" + } + ], + "outputs": [ + { + "data": [1], + "dims": [], + "type": "float32" + } + ] + } + ] + }, + { + "name": "Cast int32 to uint32", + "operator": "Cast", + "attributes": [{ "name": "to", "type": "int", "data": 12 }], + "cases": [ + { + "name": "2x3", + "inputs": [ + { + "data": [0, -1, 100, -234, -7, 1000000000], + "dims": [2, 3], + "type": "int32" + } + ], + "outputs": [ + { + "data": [0, 4294967295, 100, 4294967062, 4294967289, 1000000000], + "dims": [2, 3], + "type": "uint32" + } + ] + }, + { + "name": "Scalar", + "inputs": [ + { + "data": [1], + "dims": [], + "type": "int32" + } + ], + "outputs": [ + { + "data": [1], + "dims": [], + "type": "uint32" + } + ] + } + ] + }, + { + "name": "Cast uint32 to int32", + "operator": "Cast", + "attributes": [{ "name": "to", "type": "int", "data": 6 }], + "cases": [ + { + "name": "2x3", + "inputs": [ + { + "data": [0, 4294967295, 100, 1000000000], + "dims": [2, 2], + "type": "uint32" + } + ], + "outputs": [ + { + "data": [0, -1, 100, 1000000000], + "dims": [2, 2], + "type": "int32" + } + ] + }, + { + "name": "Scalar", + "inputs": [ + { + "data": [1], + "dims": [], + "type": "uint32" + } + ], + "outputs": [ + { + "data": [1], + "dims": [], + "type": "int32" + } + ] + } + ] + }, + { + "name": "Cast int32 to bool", + "operator": "Cast", + "attributes": [{ "name": "to", "type": "int", "data": 9 }], + "cases": [ + { + "name": "2x3", + "inputs": [ + { + "data": [0, 1, 1, 0], + "dims": [2, 2], + "type": "int32" + } + ], + "outputs": [ + { + "data": [false, true, true, false], + "dims": [2, 2], + "type": "bool" + } + ] + }, + { + "name": "Scalar", + "inputs": [ + { + "data": [1], + "dims": [], + "type": "int32" + } + ], + "outputs": [ + { + "data": [true], + "dims": [], + "type": "bool" + } + ] + } + ] + }, + { + "name": "Cast bool to int32", + "operator": "Cast", + "attributes": [{ "name": "to", "type": "int", "data": 6 }], + "cases": [ + { + "name": "2x3", + "inputs": [ + { + "data": [false, true, true, false], + "dims": [2, 2], + "type": "bool" + } + ], + "outputs": [ + { + "data": [0, 1, 1, 0], + "dims": [2, 2], + "type": "int32" + } + ] + }, + { + "name": "Scalar", + "inputs": [ + { + "data": [true], + "dims": [], + "type": "bool" + } + ], + "outputs": [ + { + "data": [1], + "dims": [], + "type": "int32" + } + ] + } + ] + } +] diff --git a/js/web/test/data/ops/concat.jsonc b/js/web/test/data/ops/concat.jsonc index f2afdf933523f..d98376a72e8b5 100644 --- a/js/web/test/data/ops/concat.jsonc +++ b/js/web/test/data/ops/concat.jsonc @@ -21,8 +21,8 @@ "outputs": [ { "data": [ - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 2, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16 ], "dims": [8, 4], "type": "float32" @@ -97,8 +97,8 @@ "outputs": [ { "data": [ - 1, 2, 3, 4, 1, 2, 3, 4, 5, 6, 7, 8, 5, 6, 7, 8, 9, 10, 11, 12, 9, - 10, 11, 12, 13, 14, 15, 16, 13, 14, 15, 16 + 1, 2, 3, 4, 1, 2, 3, 4, 5, 6, 7, 8, 5, 6, 7, 8, 9, 10, 11, 12, 9, 10, 11, 12, 13, 14, 15, 16, 13, 14, 15, + 16 ], "dims": [4, 8], "type": "float32" @@ -173,8 +173,8 @@ "outputs": [ { "data": [ - 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 1, 2, 5, 6, - 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16 + 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, + 16 ], "dims": [4, 2, 4], "type": "float32" @@ -205,8 +205,8 @@ "outputs": [ { "data": [ - 1, 2, 5, 6, 3, 4, 7, 8, 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, - 12, 15, 16, 9, 10, 13, 14, 11, 12, 15, 16 + 1, 2, 5, 6, 3, 4, 7, 8, 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 9, 10, 13, 14, 11, 12, 15, + 16 ], "dims": [2, 4, 4], "type": "float32" @@ -237,8 +237,8 @@ "outputs": [ { "data": [ - 1, 2, 5, 6, 1, 2, 5, 6, 3, 4, 7, 8, 3, 4, 7, 8, 9, 10, 13, 14, 9, - 10, 13, 14, 11, 12, 15, 16, 11, 12, 15, 16 + 1, 2, 5, 6, 1, 2, 5, 6, 3, 4, 7, 8, 3, 4, 7, 8, 9, 10, 13, 14, 9, 10, 13, 14, 11, 12, 15, 16, 11, 12, 15, + 16 ], "dims": [2, 2, 8], "type": "float32" @@ -257,16 +257,16 @@ "inputs": [ { "data": [ - 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, - 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, 28, 31, 32 + 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, + 28, 31, 32 ], "dims": [2, 2, 2, 4], "type": "float32" }, { "data": [ - 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, - 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, 28, 31, 32 + 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, + 28, 31, 32 ], "dims": [2, 2, 2, 4], "type": "float32" @@ -275,10 +275,9 @@ "outputs": [ { "data": [ - 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, - 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, 28, 31, 32, 1, 2, 5, 6, 3, - 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, 22, 19, 20, - 23, 24, 25, 26, 29, 30, 27, 28, 31, 32 + 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, + 28, 31, 32, 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, 22, 19, 20, 23, 24, 25, 26, + 29, 30, 27, 28, 31, 32 ], "dims": [4, 2, 2, 4], "type": "float32" @@ -297,16 +296,16 @@ "inputs": [ { "data": [ - 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, - 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, 28, 31, 32 + 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, + 28, 31, 32 ], "dims": [2, 2, 2, 4], "type": "float32" }, { "data": [ - 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, - 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, 28, 31, 32 + 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, + 28, 31, 32 ], "dims": [2, 2, 2, 4], "type": "float32" @@ -315,10 +314,9 @@ "outputs": [ { "data": [ - 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 1, 2, 5, 6, - 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, 22, 19, 20, - 23, 24, 25, 26, 29, 30, 27, 28, 31, 32, 17, 18, 21, 22, 19, 20, - 23, 24, 25, 26, 29, 30, 27, 28, 31, 32 + 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, + 16, 17, 18, 21, 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, 28, 31, 32, 17, 18, 21, 22, 19, 20, 23, 24, 25, + 26, 29, 30, 27, 28, 31, 32 ], "dims": [2, 4, 2, 4], "type": "float32" @@ -337,16 +335,16 @@ "inputs": [ { "data": [ - 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, - 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, 28, 31, 32 + 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, + 28, 31, 32 ], "dims": [2, 2, 2, 4], "type": "float32" }, { "data": [ - 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, - 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, 28, 31, 32 + 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, + 28, 31, 32 ], "dims": [2, 2, 2, 4], "type": "float32" @@ -355,10 +353,9 @@ "outputs": [ { "data": [ - 1, 2, 5, 6, 3, 4, 7, 8, 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, - 12, 15, 16, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, 22, 19, 20, - 23, 24, 17, 18, 21, 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, 28, - 31, 32, 25, 26, 29, 30, 27, 28, 31, 32 + 1, 2, 5, 6, 3, 4, 7, 8, 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 9, 10, 13, 14, 11, 12, 15, + 16, 17, 18, 21, 22, 19, 20, 23, 24, 17, 18, 21, 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, 28, 31, 32, 25, + 26, 29, 30, 27, 28, 31, 32 ], "dims": [2, 2, 4, 4], "type": "float32" @@ -377,16 +374,16 @@ "inputs": [ { "data": [ - 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, - 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, 28, 31, 32 + 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, + 28, 31, 32 ], "dims": [2, 2, 2, 4], "type": "float32" }, { "data": [ - 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, - 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, 28, 31, 32 + 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, + 28, 31, 32 ], "dims": [2, 2, 2, 4], "type": "float32" @@ -395,10 +392,9 @@ "outputs": [ { "data": [ - 1, 2, 5, 6, 1, 2, 5, 6, 3, 4, 7, 8, 3, 4, 7, 8, 9, 10, 13, 14, 9, - 10, 13, 14, 11, 12, 15, 16, 11, 12, 15, 16, 17, 18, 21, 22, 17, - 18, 21, 22, 19, 20, 23, 24, 19, 20, 23, 24, 25, 26, 29, 30, 25, - 26, 29, 30, 27, 28, 31, 32, 27, 28, 31, 32 + 1, 2, 5, 6, 1, 2, 5, 6, 3, 4, 7, 8, 3, 4, 7, 8, 9, 10, 13, 14, 9, 10, 13, 14, 11, 12, 15, 16, 11, 12, 15, + 16, 17, 18, 21, 22, 17, 18, 21, 22, 19, 20, 23, 24, 19, 20, 23, 24, 25, 26, 29, 30, 25, 26, 29, 30, 27, + 28, 31, 32, 27, 28, 31, 32 ], "dims": [2, 2, 2, 8], "type": "float32" diff --git a/js/web/test/data/ops/concat_int32.jsonc b/js/web/test/data/ops/concat_int32.jsonc new file mode 100644 index 0000000000000..6e2ce18c6f7c5 --- /dev/null +++ b/js/web/test/data/ops/concat_int32.jsonc @@ -0,0 +1,406 @@ +[ + { + "name": "Concat 2D axis=0", + "operator": "Concat", + "attributes": [{ "name": "axis", "data": 0, "type": "int" }], + "cases": [ + { + "name": "[4,4]", + "inputs": [ + { + "data": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], + "dims": [4, 4], + "type": "int32" + }, + { + "data": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], + "dims": [4, 4], + "type": "int32" + } + ], + "outputs": [ + { + "data": [ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16 + ], + "dims": [8, 4], + "type": "int32" + } + ] + }, + { + "name": "[2,4]", + "inputs": [ + { + "data": [1, 2, 5, 6, 3, 4, 7, 8], + "dims": [2, 4], + "type": "int32" + }, + { + "data": [1, 2, 3, 4, 5, 6, 7, 8], + "dims": [2, 4], + "type": "int32" + } + ], + "outputs": [ + { + "data": [1, 2, 5, 6, 3, 4, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8], + "dims": [4, 4], + "type": "int32" + } + ] + }, + { + "name": "[2,3]", + "inputs": [ + { + "data": [1, 2, 3, 4, 5, 6], + "dims": [2, 3], + "type": "int32" + }, + { + "data": [1, 2, 3, 4, 5, 6], + "dims": [2, 3], + "type": "int32" + } + ], + "outputs": [ + { + "data": [1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6], + "dims": [4, 3], + "type": "int32" + } + ] + } + ] + }, + { + "name": "Concat 2D axis=1", + "operator": "Concat", + "attributes": [{ "name": "axis", "data": 1, "type": "int" }], + "cases": [ + { + "name": "[4,4]", + "inputs": [ + { + "data": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], + "dims": [4, 4], + "type": "int32" + }, + { + "data": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], + "dims": [4, 4], + "type": "int32" + } + ], + "outputs": [ + { + "data": [ + 1, 2, 3, 4, 1, 2, 3, 4, 5, 6, 7, 8, 5, 6, 7, 8, 9, 10, 11, 12, 9, 10, 11, 12, 13, 14, 15, 16, 13, 14, 15, + 16 + ], + "dims": [4, 8], + "type": "int32" + } + ] + }, + { + "name": "[2,4]", + "inputs": [ + { + "data": [1, 2, 5, 6, 3, 4, 7, 8], + "dims": [2, 4], + "type": "int32" + }, + { + "data": [1, 2, 3, 4, 5, 6, 7, 8], + "dims": [2, 4], + "type": "int32" + } + ], + "outputs": [ + { + "data": [1, 2, 5, 6, 1, 2, 3, 4, 3, 4, 7, 8, 5, 6, 7, 8], + "dims": [2, 8], + "type": "int32" + } + ] + }, + { + "name": "[2,3]", + "inputs": [ + { + "data": [1, 2, 3, 4, 5, 6], + "dims": [2, 3], + "type": "int32" + }, + { + "data": [1, 2, 3, 4, 5, 6], + "dims": [2, 3], + "type": "int32" + } + ], + "outputs": [ + { + "data": [1, 2, 3, 1, 2, 3, 4, 5, 6, 4, 5, 6], + "dims": [2, 6], + "type": "int32" + } + ] + } + ] + }, + { + "name": "Concat 3D axis=0", + "operator": "Concat", + "attributes": [{ "name": "axis", "data": 0, "type": "int" }], + "cases": [ + { + "name": "[2,2,4]", + "inputs": [ + { + "data": [1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16], + "dims": [2, 2, 4], + "type": "int32" + }, + { + "data": [1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16], + "dims": [2, 2, 4], + "type": "int32" + } + ], + "outputs": [ + { + "data": [ + 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, + 16 + ], + "dims": [4, 2, 4], + "type": "int32" + } + ] + } + ] + }, + { + "name": "Concat 3D axis=1", + "operator": "Concat", + "attributes": [{ "name": "axis", "data": 1, "type": "int" }], + "cases": [ + { + "name": "[2,2,4]", + "inputs": [ + { + "data": [1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16], + "dims": [2, 2, 4], + "type": "int32" + }, + { + "data": [1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16], + "dims": [2, 2, 4], + "type": "int32" + } + ], + "outputs": [ + { + "data": [ + 1, 2, 5, 6, 3, 4, 7, 8, 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 9, 10, 13, 14, 11, 12, 15, + 16 + ], + "dims": [2, 4, 4], + "type": "int32" + } + ] + } + ] + }, + { + "name": "Concat 3D axis=2", + "operator": "Concat", + "attributes": [{ "name": "axis", "data": 2, "type": "int" }], + "cases": [ + { + "name": "[2,2,4]", + "inputs": [ + { + "data": [1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16], + "dims": [2, 2, 4], + "type": "int32" + }, + { + "data": [1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16], + "dims": [2, 2, 4], + "type": "int32" + } + ], + "outputs": [ + { + "data": [ + 1, 2, 5, 6, 1, 2, 5, 6, 3, 4, 7, 8, 3, 4, 7, 8, 9, 10, 13, 14, 9, 10, 13, 14, 11, 12, 15, 16, 11, 12, 15, + 16 + ], + "dims": [2, 2, 8], + "type": "int32" + } + ] + } + ] + }, + { + "name": "Concat 4D axis=0", + "operator": "Concat", + "attributes": [{ "name": "axis", "data": 0, "type": "int" }], + "cases": [ + { + "name": "[2,2,2,4]", + "inputs": [ + { + "data": [ + 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, + 28, 31, 32 + ], + "dims": [2, 2, 2, 4], + "type": "int32" + }, + { + "data": [ + 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, + 28, 31, 32 + ], + "dims": [2, 2, 2, 4], + "type": "int32" + } + ], + "outputs": [ + { + "data": [ + 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, + 28, 31, 32, 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, 22, 19, 20, 23, 24, 25, 26, + 29, 30, 27, 28, 31, 32 + ], + "dims": [4, 2, 2, 4], + "type": "int32" + } + ] + } + ] + }, + { + "name": "Concat 4D axis=1", + "operator": "Concat", + "attributes": [{ "name": "axis", "data": 1, "type": "int" }], + "cases": [ + { + "name": "[2,2,2,4]", + "inputs": [ + { + "data": [ + 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, + 28, 31, 32 + ], + "dims": [2, 2, 2, 4], + "type": "int32" + }, + { + "data": [ + 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, + 28, 31, 32 + ], + "dims": [2, 2, 2, 4], + "type": "int32" + } + ], + "outputs": [ + { + "data": [ + 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, + 16, 17, 18, 21, 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, 28, 31, 32, 17, 18, 21, 22, 19, 20, 23, 24, 25, + 26, 29, 30, 27, 28, 31, 32 + ], + "dims": [2, 4, 2, 4], + "type": "int32" + } + ] + } + ] + }, + { + "name": "Concat 4D axis=2", + "operator": "Concat", + "attributes": [{ "name": "axis", "data": 2, "type": "int" }], + "cases": [ + { + "name": "[2,2,2,4]", + "inputs": [ + { + "data": [ + 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, + 28, 31, 32 + ], + "dims": [2, 2, 2, 4], + "type": "int32" + }, + { + "data": [ + 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, + 28, 31, 32 + ], + "dims": [2, 2, 2, 4], + "type": "int32" + } + ], + "outputs": [ + { + "data": [ + 1, 2, 5, 6, 3, 4, 7, 8, 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 9, 10, 13, 14, 11, 12, 15, + 16, 17, 18, 21, 22, 19, 20, 23, 24, 17, 18, 21, 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, 28, 31, 32, 25, + 26, 29, 30, 27, 28, 31, 32 + ], + "dims": [2, 2, 4, 4], + "type": "int32" + } + ] + } + ] + }, + { + "name": "Concat 4D axis=3", + "operator": "Concat", + "attributes": [{ "name": "axis", "data": 3, "type": "int" }], + "cases": [ + { + "name": "[2,2,2,4]", + "inputs": [ + { + "data": [ + 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, + 28, 31, 32 + ], + "dims": [2, 2, 2, 4], + "type": "int32" + }, + { + "data": [ + 1, 2, 5, 6, 3, 4, 7, 8, 9, 10, 13, 14, 11, 12, 15, 16, 17, 18, 21, 22, 19, 20, 23, 24, 25, 26, 29, 30, 27, + 28, 31, 32 + ], + "dims": [2, 2, 2, 4], + "type": "int32" + } + ], + "outputs": [ + { + "data": [ + 1, 2, 5, 6, 1, 2, 5, 6, 3, 4, 7, 8, 3, 4, 7, 8, 9, 10, 13, 14, 9, 10, 13, 14, 11, 12, 15, 16, 11, 12, 15, + 16, 17, 18, 21, 22, 17, 18, 21, 22, 19, 20, 23, 24, 19, 20, 23, 24, 25, 26, 29, 30, 25, 26, 29, 30, 27, + 28, 31, 32, 27, 28, 31, 32 + ], + "dims": [2, 2, 2, 8], + "type": "int32" + } + ] + } + ] + } +] diff --git a/js/web/test/data/ops/conv-transpose.jsonc b/js/web/test/data/ops/conv-transpose.jsonc new file mode 100644 index 0000000000000..a249dc807fa0b --- /dev/null +++ b/js/web/test/data/ops/conv-transpose.jsonc @@ -0,0 +1,289 @@ +[ + { + "name": "ConvTranspose without bias addition A", + "operator": "ConvTranspose", + "attributes": [{ "name": "kernel_shape", "data": [2, 2], "type": "ints" }], + "cases": [ + { + "name": "T[0]", + "inputs": [ + { + "data": [10, 20, 30, 40], + "dims": [1, 1, 2, 2], + "type": "float32" + }, + { + "data": [1, 2, 3, 4], + "dims": [1, 1, 2, 2], + "type": "float32" + } + ], + "outputs": [ + { + "data": [10, 40, 40, 60, 200, 160, 90, 240, 160], + "dims": [1, 1, 3, 3], + "type": "float32" + } + ] + } + ] + }, + { + "name": "ConvTranspose without bias addition B", + "operator": "ConvTranspose", + "attributes": [{ "name": "kernel_shape", "data": [2, 2], "type": "ints" }], + "cases": [ + { + "name": "T[0]", + "inputs": [ + { + "data": [10, 20, 30, 40, 50, 60, 70, 80], + "dims": [1, 2, 2, 2], + "type": "float32" + }, + { + "data": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], + "dims": [2, 2, 2, 2], + "type": "float32" + } + ], + "outputs": [ + { + "data": [ + 400, 940, 560, 1080, 2520, 1480, 760, 1740, 1000, 640, 1500, 880, 1720, 3960, 2280, 1160, 2620, 1480 + ], + "dims": [1, 2, 3, 3], + "type": "float32" + } + ] + } + ] + }, + { + "name": "ConvTranspose with bias addition A", + "operator": "ConvTranspose", + "attributes": [{ "name": "kernel_shape", "data": [2, 2], "type": "ints" }], + "cases": [ + { + "name": "T[0]", + "inputs": [ + { + "data": [10, 20, 30, 40], + "dims": [1, 4, 1, 1], + "type": "float32" + }, + { + "data": [ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + ], + "dims": [4, 4, 2, 2], + "type": "float32" + }, + { + "data": [0.1, 0.2, 0.3, 0.4], + "dims": [4], + "type": "float32" + } + ], + "outputs": [ + { + "data": [ + 100.0999984741211, 100.0999984741211, 100.0999984741211, 100.0999984741211, 100.19999694824219, + 100.19999694824219, 100.19999694824219, 100.19999694824219, 100.30000305175781, 100.30000305175781, + 100.30000305175781, 100.30000305175781, 100.4000015258789, 100.4000015258789, 100.4000015258789, + 100.4000015258789 + ], + "dims": [1, 4, 2, 2], + "type": "float32" + } + ] + } + ] + }, + { + "name": "ConvTranspose with bias addition B", + "operator": "ConvTranspose", + "attributes": [{ "name": "kernel_shape", "data": [2, 2], "type": "ints" }], + "cases": [ + { + "name": "T[0]", + "inputs": [ + { + "data": [6, 8, 7, 9, 15, 11, 8, 12, 9], + "dims": [1, 1, 3, 3], + "type": "float32" + }, + { + "data": [1, 1, 1, 1], + "dims": [1, 1, 2, 2], + "type": "float32" + }, + { + "data": [5], + "dims": [1], + "type": "float32" + } + ], + "outputs": [ + { + "data": [11, 19, 20, 12, 20, 43, 46, 23, 22, 49, 52, 25, 13, 25, 26, 14], + "dims": [1, 1, 4, 4], + "type": "float32" + } + ] + } + ] + }, + { + "name": "ConvTranspose- group - A", + "operator": "ConvTranspose", + "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- group - B", + "operator": "ConvTranspose", + "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- group - C", + "operator": "ConvTranspose", + "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- pointwise", + "operator": "ConvTranspose", + "attributes": [{ "name": "kernel_shape", "data": [1, 1], "type": "ints" }], + "cases": [ + { + "name": "T[0]", + "inputs": [ + { + "data": [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0], + "dims": [1, 2, 2, 2], + "type": "float32" + }, + { + "data": [0.0, 1.0, 2.0, 3.0], + "dims": [2, 2, 1, 1], + "type": "float32" + }, + { + "data": [1, 2], + "dims": [2], + "type": "float32" + } + ], + "outputs": [ + { + "data": [9, 11, 13, 15, 14, 18, 22, 26], + "dims": [1, 2, 2, 2], + "type": "float32" + } + ] + } + ] + } +] diff --git a/js/web/test/data/ops/conv.jsonc b/js/web/test/data/ops/conv.jsonc index 35f736045461b..928192bb219f2 100644 --- a/js/web/test/data/ops/conv.jsonc +++ b/js/web/test/data/ops/conv.jsonc @@ -71,40 +71,7 @@ "type": "float32" }, { - "data": [ - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1 - ], + "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "dims": [4, 2, 2, 2], "type": "float32" }, @@ -170,26 +137,7 @@ "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 - ], + "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], "dims": [1, 2, 3, 3], "type": "float32" }, @@ -201,26 +149,7 @@ ], "outputs": [ { - "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 - ], + "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" } @@ -241,49 +170,14 @@ "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, 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 - ], + "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" }, @@ -295,20 +189,7 @@ ], "outputs": [ { - "data": [ - 27.1, - 37.1, - 57.1, - 67.1, - 293.2, - 319.2, - 371.2, - 397.2, - 847.3, - 889.3, - 409.3, - 428.3 - ], + "data": [27.1, 37.1, 57.1, 67.1, 293.2, 319.2, 371.2, 397.2, 847.3, 889.3, 409.3, 428.3], "dims": [1, 3, 2, 2], "type": "float32" } @@ -329,87 +210,21 @@ "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 + 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 - ], + "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": [ - 34, - 44, - 54, - 74, - 84, - 94, - 386, - 412, - 438, - 490, - 516, - 542, - 1122, - 1164, - 1206, - 1290, - 1332, - 1374 - ], + "data": [34, 44, 54, 74, 84, 94, 386, 412, 438, 490, 516, 542, 1122, 1164, 1206, 1290, 1332, 1374], "dims": [1, 3, 2, 3], "type": "float32" } @@ -428,63 +243,16 @@ "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 + 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 ], "dims": [1, 8, 2, 2], "type": "float32" }, { - "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 - ], - "dims":[2, 8, 1, 1], - "type":"float32" + "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], + "dims": [2, 8, 1, 1], + "type": "float32" }, { "data": [0.5, 0.4], @@ -492,11 +260,9 @@ "type": "float32" } ], - "outputs":[ + "outputs": [ { - "data": [ - 560.5,588.5,616.5,644.5,1456.4,1548.4,1640.4,1732.4 - ], + "data": [560.5, 588.5, 616.5, 644.5, 1456.4, 1548.4, 1640.4, 1732.4], "dims": [1, 2, 2, 2], "type": "float32" } diff --git a/js/web/test/data/ops/cos.jsonc b/js/web/test/data/ops/cos.jsonc index 584eefad8e764..b116868ec62ea 100644 --- a/js/web/test/data/ops/cos.jsonc +++ b/js/web/test/data/ops/cos.jsonc @@ -49,16 +49,7 @@ ], "outputs": [ { - "data": [ - 0.99500417, - 0.98006658, - 0.95533649, - 0.92106099, - 0.62160997, - 0.69670671, - 0.76484219, - 0.82533561 - ], + "data": [0.99500417, 0.98006658, 0.95533649, 0.92106099, 0.62160997, 0.69670671, 0.76484219, 0.82533561], "dims": [2, 4], "type": "float32" } diff --git a/js/web/test/data/ops/depth-to-space.jsonc b/js/web/test/data/ops/depth-to-space.jsonc index 22425b5472e82..ad4bea5097960 100644 --- a/js/web/test/data/ops/depth-to-space.jsonc +++ b/js/web/test/data/ops/depth-to-space.jsonc @@ -25,16 +25,20 @@ "name": "4D reshape [2, 8, 1, 2]", "inputs": [ { - "data": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31], + "data": [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31 + ], "dims": [2, 8, 1, 2], "type": "float32" } ], "outputs": [ { - "data": [0, 4, 1, 5, 8, 12, 9, 13, 2, 6, 3, 7, 10, 14, 11, 15, 16, 20, - 17, 21, 24, 28, 25, 29, 18, 22, 19, 23, 26, 30, 27, 31], + "data": [ + 0, 4, 1, 5, 8, 12, 9, 13, 2, 6, 3, 7, 10, 14, 11, 15, 16, 20, 17, 21, 24, 28, 25, 29, 18, 22, 19, 23, 26, + 30, 27, 31 + ], "dims": [2, 2, 2, 4], "type": "float32" } @@ -45,8 +49,10 @@ { "name": "Depth-to-space of a 4-D tensor with DCR mode", "operator": "DepthToSpace", - "attributes": [{ "name": "mode", "data": "DCR", "type": "string" }, - { "name": "blocksize", "data": 2, "type": "int" }], + "attributes": [ + { "name": "mode", "data": "DCR", "type": "string" }, + { "name": "blocksize", "data": 2, "type": "int" } + ], "cases": [ { "name": "4D reshape [1, 8, 1, 1]", @@ -69,16 +75,20 @@ "name": "4D reshape [2, 8, 1, 2]", "inputs": [ { - "data": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31], + "data": [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31 + ], "dims": [2, 8, 1, 2], "type": "float32" } ], "outputs": [ { - "data": [0, 4, 1, 5, 8, 12, 9, 13, 2, 6, 3, 7, 10, 14, 11, 15, 16, 20, - 17, 21, 24, 28, 25, 29, 18, 22, 19, 23, 26, 30, 27, 31], + "data": [ + 0, 4, 1, 5, 8, 12, 9, 13, 2, 6, 3, 7, 10, 14, 11, 15, 16, 20, 17, 21, 24, 28, 25, 29, 18, 22, 19, 23, 26, + 30, 27, 31 + ], "dims": [2, 2, 2, 4], "type": "float32" } @@ -89,8 +99,10 @@ { "name": "Depth-to-space of a 4-D tensor with CRD mode", "operator": "DepthToSpace", - "attributes": [{ "name": "mode", "data": "CRD", "type": "string" }, - { "name": "blocksize", "data": 2, "type": "int" }], + "attributes": [ + { "name": "mode", "data": "CRD", "type": "string" }, + { "name": "blocksize", "data": 2, "type": "int" } + ], "cases": [ { "name": "4D reshape [1, 8, 1, 1]", @@ -113,16 +125,20 @@ "name": "4D reshape [2, 8, 1, 2]", "inputs": [ { - "data": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31], + "data": [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31 + ], "dims": [2, 8, 1, 2], "type": "float32" } ], "outputs": [ { - "data": [0, 2, 1, 3, 4, 6, 5, 7, 8, 10, 9, 11, 12, 14, 13, 15, 16, 18, - 17, 19, 20, 22, 21, 23, 24, 26, 25, 27, 28, 30, 29, 31], + "data": [ + 0, 2, 1, 3, 4, 6, 5, 7, 8, 10, 9, 11, 12, 14, 13, 15, 16, 18, 17, 19, 20, 22, 21, 23, 24, 26, 25, 27, 28, + 30, 29, 31 + ], "dims": [2, 2, 2, 4], "type": "float32" } diff --git a/js/web/test/data/ops/div.jsonc b/js/web/test/data/ops/div.jsonc index 3d4e42ac835df..a2bf079a7dceb 100644 --- a/js/web/test/data/ops/div.jsonc +++ b/js/web/test/data/ops/div.jsonc @@ -79,32 +79,7 @@ "type": "float32" }, { - "data": [ - 2, - 6, - 1, - 2, - 1, - 3, - 1, - 4, - 3, - 5, - 3, - 4, - 1, - 4, - 1, - 6, - 4, - 4, - 5, - 6, - 2, - 4, - 2, - 6 - ], + "data": [2, 6, 1, 2, 1, 3, 1, 4, 3, 5, 3, 4, 1, 4, 1, 6, 4, 4, 5, 6, 2, 4, 2, 6], "dims": [3, 2, 4], "type": "float32" } @@ -112,30 +87,8 @@ "outputs": [ { "data": [ - 0.5, - 0.3333, - 3, - 2, - 5, - 2, - 7, - 2, - 0.3333, - 0.4, - 1, - 1, - 5, - 1.5, - 7, - 1.3333, - 0.25, - 0.5, - 0.6, - 0.6667, - 2.5, - 1.5, - 3.5, - 1.3333 + 0.5, 0.3333, 3, 2, 5, 2, 7, 2, 0.3333, 0.4, 1, 1, 5, 1.5, 7, 1.3333, 0.25, 0.5, 0.6, 0.6667, 2.5, 1.5, + 3.5, 1.3333 ], "dims": [3, 2, 4], "type": "float32" diff --git a/js/web/test/data/ops/div_int32.jsonc b/js/web/test/data/ops/div_int32.jsonc new file mode 100644 index 0000000000000..f86ff82759250 --- /dev/null +++ b/js/web/test/data/ops/div_int32.jsonc @@ -0,0 +1,31 @@ +[ + { + "name": "Div with no attributes", + "operator": "Div", + "attributes": [], + "cases": [ + { + "name": "T[2,4] T[2,4] (int32)", + "inputs": [ + { + "data": [1, 2, 1, 8, 2, 12, 9, 2], + "dims": [2, 4], + "type": "int32" + }, + { + "data": [2, 1, 1, 2, 2, 3, 1, 4], + "dims": [2, 4], + "type": "int32" + } + ], + "outputs": [ + { + "data": [0, 2, 1, 4, 1, 4, 9, 0], + "dims": [2, 4], + "type": "int32" + } + ] + } + ] + } +] diff --git a/js/web/test/data/ops/einsum.jsonc b/js/web/test/data/ops/einsum.jsonc new file mode 100644 index 0000000000000..baf30cf982148 --- /dev/null +++ b/js/web/test/data/ops/einsum.jsonc @@ -0,0 +1,635 @@ +[ + { + "name": "einsum", + "operator": "Einsum", + "opset": { + "domain": "", + "version": 12 + }, + "attributes": [ + { + "name": "equation", + "data": "i,i", + "type": "string" + } + ], + "cases": [ + { + "name": "Dotproduct/scalar product", + "inputs": [ + { + "data": [1, 2, 3], + "dims": [3], + "type": "float32" + }, + { + "data": [4, 5, 6], + "dims": [3], + "type": "float32" + } + ], + "outputs": [ + { + "data": [32], + "dims": [], + "type": "float32" + } + ] + } + ] + }, + { + "name": "einsum", + "operator": "Einsum", + "opset": { + "domain": "", + "version": 12 + }, + "attributes": [ + { + "name": "equation", + "data": "i,i->i", + "type": "string" + } + ], + "cases": [ + { + "name": "elementwise product", + "inputs": [ + { + "data": [1, 2, 3], + "dims": [3], + "type": "float32" + }, + { + "data": [4, 5, 6], + "dims": [3], + "type": "float32" + } + ], + "outputs": [ + { + "data": [4, 10, 18], + "dims": [3], + "type": "float32" + } + ] + } + ] + }, + { + "name": "einsum", + "operator": "Einsum", + "opset": { + "domain": "", + "version": 12 + }, + "attributes": [ + { + "name": "equation", + "data": "i,j", + "type": "string" + } + ], + "cases": [ + { + "name": "Product without specifying RSH", + "inputs": [ + { + "data": [1, 2, 3], + "dims": [3], + "type": "float32" + }, + { + "data": [4, 5, 6], + "dims": [3], + "type": "float32" + } + ], + "outputs": [ + { + "data": [4, 5, 6, 8, 10, 12, 12, 15, 18], + "dims": [3, 3], + "type": "float32" + } + ] + } + ] + }, + { + "name": "einsum", + "operator": "Einsum", + "opset": { + "domain": "", + "version": 12 + }, + "attributes": [ + { + "name": "equation", + "data": "i,j->ij", + "type": "string" + } + ], + "cases": [ + { + "name": "Product", + "inputs": [ + { + "data": [1, 2, 3], + "dims": [3], + "type": "float32" + }, + { + "data": [4, 5, 6], + "dims": [3], + "type": "float32" + } + ], + "outputs": [ + { + "data": [4, 5, 6, 8, 10, 12, 12, 15, 18], + "dims": [3, 3], + "type": "float32" + } + ] + } + ] + }, + { + "name": "einsum", + "operator": "Einsum", + "opset": { + "domain": "", + "version": 12 + }, + "attributes": [ + { + "name": "equation", + "data": "ii,jj", + "type": "string" + } + ], + "cases": [ + { + "name": "Diagonal elementwise multiplication", + "inputs": [ + { + "data": [1, 2, 3, 4, 5, 6, 7, 8, 9], + "dims": [3, 3], + "type": "float32" + }, + { + "data": [1, 0, 0, 0, 1, 0, 0, 0, 1], + "dims": [3, 3], + "type": "float32" + } + ], + "outputs": [ + { + "data": [45], + "dims": [], + "type": "float32" + } + ] + } + ] + }, + { + "name": "einsum", + "operator": "Einsum", + "opset": { + "domain": "", + "version": 12 + }, + "attributes": [ + { + "name": "equation", + "data": "ii,jj -> ij", + "type": "string" + } + ], + "cases": [ + { + "name": "Dotproduct", + "inputs": [ + { + "data": [1, 2, 3, 4, 5, 6, 7, 8, 9], + "dims": [3, 3], + "type": "float32" + }, + { + "data": [1, 0, 0, 0, 1, 0, 0, 0, 1], + "dims": [3, 3], + "type": "float32" + } + ], + "outputs": [ + { + "data": [1, 1, 1, 5, 5, 5, 9, 9, 9], + "dims": [3, 3], + "type": "float32" + } + ] + } + ] + }, + { + "name": "einsum", + "operator": "Einsum", + "opset": { + "domain": "", + "version": 12 + }, + "attributes": [ + { + "name": "equation", + "data": "ij,jk->ik", + "type": "string" + } + ], + "cases": [ + { + "name": "Multiply", + "inputs": [ + { + "data": [1, 2, 3, 4, 5, 6], + "dims": [2, 3], + "type": "float32" + }, + { + "data": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], + "dims": [3, 4], + "type": "float32" + } + ], + "outputs": [ + { + "data": [38, 44, 50, 56, 83, 98, 113, 128], + "dims": [2, 4], + "type": "float32" + } + ] + } + ] + }, + { + "name": "einsum", + "operator": "Einsum", + "opset": { + "domain": "", + "version": 12 + }, + "attributes": [ + { + "name": "equation", + "data": "ij->ji", + "type": "string" + } + ], + "cases": [ + { + "name": "Transpose", + "inputs": [ + { + "data": [1, 2, 3, 4, 5, 6], + "dims": [2, 3], + "type": "float32" + } + ], + "outputs": [ + { + "data": [1, 4, 2, 5, 3, 6], + "dims": [3, 2], + "type": "float32" + } + ] + } + ] + }, + { + "name": "einsum", + "operator": "Einsum", + "opset": { + "domain": "", + "version": 12 + }, + "attributes": [ + { + "name": "equation", + "data": "ij->i", + "type": "string" + } + ], + "cases": [ + { + "name": "ReduceSum", + "inputs": [ + { + "data": [1, 2, 3, 4, 5, 6, 7, 8, 9], + "dims": [3, 3], + "type": "float32" + } + ], + "outputs": [ + { + "data": [6, 15, 24], + "dims": [3], + "type": "float32" + } + ] + } + ] + }, + { + "name": "einsum", + "operator": "Einsum", + "opset": { + "domain": "", + "version": 12 + }, + "attributes": [ + { + "name": "equation", + "data": "ii->i", + "type": "string" + } + ], + "cases": [ + { + "name": "Diagonal", + "inputs": [ + { + "data": [1, 2, 3, 4, 5, 6, 7, 8, 9], + "dims": [3, 3], + "type": "float32" + } + ], + "outputs": [ + { + "data": [1, 5, 9], + "dims": [3], + "type": "float32" + } + ] + } + ] + }, + { + "name": "einsum", + "operator": "Einsum", + "opset": { + "domain": "", + "version": 12 + }, + "attributes": [ + { + "name": "equation", + "data": "ij...,jk...->ik...", + "type": "string" + } + ], + "cases": [ + { + "name": "Multiply with ellipsis - A", + "inputs": [ + { + "data": [1, 2, 3, 4, 5, 6], + "dims": [2, 3, 1], + "type": "float32" + }, + { + "data": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], + "dims": [3, 4, 1], + "type": "float32" + } + ], + "outputs": [ + { + "data": [38, 44, 50, 56, 83, 98, 113, 128], + "dims": [2, 4, 1], + "type": "float32" + } + ] + } + ] + }, + { + "name": "einsum", + "operator": "Einsum", + "opset": { + "domain": "", + "version": 12 + }, + "attributes": [ + { + "name": "equation", + "data": "...ij,...jk->...ik", + "type": "string" + } + ], + "cases": [ + { + "name": "Multiply with ellipsis - B", + "inputs": [ + { + "data": [1, 2, 3, 4, 5, 6], + "dims": [1, 2, 3], + "type": "float32" + }, + { + "data": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], + "dims": [1, 3, 4], + "type": "float32" + } + ], + "outputs": [ + { + "data": [38, 44, 50, 56, 83, 98, 113, 128], + "dims": [1, 2, 4], + "type": "float32" + } + ] + } + ] + }, + { + "name": "einsum", + "operator": "Einsum", + "opset": { + "domain": "", + "version": 12 + }, + "attributes": [ + { + "name": "equation", + "data": "i...j,j...k->i...k", + "type": "string" + } + ], + "cases": [ + { + "name": "Multiply with ellipsis - C", + "inputs": [ + { + "data": [1, 2, 3, 4, 5, 6], + "dims": [2, 1, 3], + "type": "float32" + }, + { + "data": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], + "dims": [3, 1, 4], + "type": "float32" + } + ], + "outputs": [ + { + "data": [38, 44, 50, 56, 83, 98, 113, 128], + "dims": [2, 1, 4], + "type": "float32" + } + ] + } + ] + }, + { + "name": "einsum", + "operator": "Einsum", + "opset": { + "domain": "", + "version": 12 + }, + "attributes": [ + { + "name": "equation", + "data": "...ij,jk->...ik", + "type": "string" + } + ], + "cases": [ + { + "name": "Multiply with ellipsis - D", + "inputs": [ + { + "data": [1, 2, 3, 4, 5, 6], + "dims": [1, 2, 3], + "type": "float32" + }, + { + "data": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], + "dims": [3, 4], + "type": "float32" + } + ], + "outputs": [ + { + "data": [38, 44, 50, 56, 83, 98, 113, 128], + "dims": [1, 2, 4], + "type": "float32" + } + ] + } + ] + }, + { + "name": "einsum", + "operator": "Einsum", + "opset": { + "domain": "", + "version": 12 + }, + "attributes": [ + { + "name": "equation", + "data": "...ij->...ji", + "type": "string" + } + ], + "cases": [ + { + "name": "Transpose with ellipsis", + "inputs": [ + { + "data": [1, 2, 3, 4, 5, 6], + "dims": [1, 2, 3], + "type": "float32" + } + ], + "outputs": [ + { + "data": [1, 4, 2, 5, 3, 6], + "dims": [1, 3, 2], + "type": "float32" + } + ] + } + ] + }, + { + "name": "einsum", + "operator": "Einsum", + "opset": { + "domain": "", + "version": 12 + }, + "attributes": [ + { + "name": "equation", + "data": "...ij->...i", + "type": "string" + } + ], + "cases": [ + { + "name": "ReduceSum with ellipsis", + "inputs": [ + { + "data": [1, 2, 3, 4, 5, 6, 7, 8, 9], + "dims": [1, 3, 3], + "type": "float32" + } + ], + "outputs": [ + { + "data": [6, 15, 24], + "dims": [1, 3], + "type": "float32" + } + ] + } + ] + }, + { + "name": "einsum", + "operator": "Einsum", + "opset": { + "domain": "", + "version": 12 + }, + "attributes": [ + { + "name": "equation", + "data": "...ii->...i", + "type": "string" + } + ], + "cases": [ + { + "name": "Diagonal with ellipsis", + "inputs": [ + { + "data": [1, 2, 3, 4, 5, 6, 7, 8, 9], + "dims": [1, 3, 3], + "type": "float32" + } + ], + "outputs": [ + { + "data": [1, 5, 9], + "dims": [1, 3], + "type": "float32" + } + ] + } + ] + } +] diff --git a/js/web/test/data/ops/exp.jsonc b/js/web/test/data/ops/exp.jsonc index 2459d1df6f280..b9cdae532cefc 100644 --- a/js/web/test/data/ops/exp.jsonc +++ b/js/web/test/data/ops/exp.jsonc @@ -49,16 +49,7 @@ ], "outputs": [ { - "data": [ - 2.71828183, - 7.3890561, - 2.71828183, - 20.08553692, - 7.3890561, - 20.08553692, - 2.71828183, - 7.3890561 - ], + "data": [2.71828183, 7.3890561, 2.71828183, 20.08553692, 7.3890561, 20.08553692, 2.71828183, 7.3890561], "dims": [2, 4], "type": "float32" } diff --git a/js/web/test/data/ops/expand.jsonc b/js/web/test/data/ops/expand.jsonc new file mode 100644 index 0000000000000..460122b4e085c --- /dev/null +++ b/js/web/test/data/ops/expand.jsonc @@ -0,0 +1,89 @@ +[ + { + "name": "Expand 1 - float32", + "operator": "Expand", + "attributes": [], + "cases": [ + { + "name": "Expand 1 - float32", + "inputs": [ + { + "data": [1], + "dims": [1, 1], + "type": "float32" + }, + { + "data": [1, 4], + "dims": [2], + "type": "int64" + } + ], + "outputs": [ + { + "data": [1, 1, 1, 1], + "dims": [1, 4], + "type": "float32" + } + ] + } + ] + }, + { + "name": "Expand 2 - float32", + "operator": "Expand", + "attributes": [], + "cases": [ + { + "name": "Expand 2 - float32", + "inputs": [ + { + "data": [1], + "dims": [1, 1], + "type": "float32" + }, + { + "data": [1, 6], + "dims": [2], + "type": "int64" + } + ], + "outputs": [ + { + "data": [1, 1, 1, 1, 1, 1], + "dims": [1, 6], + "type": "float32" + } + ] + } + ] + }, + { + "name": "Expand 1D - float32", + "operator": "Expand", + "attributes": [], + "cases": [ + { + "name": "Expand 1D - float32", + "inputs": [ + { + "data": [1], + "dims": [1], + "type": "float32" + }, + { + "data": [4], + "dims": [1], + "type": "int64" + } + ], + "outputs": [ + { + "data": [1, 1, 1, 1], + "dims": [4], + "type": "float32" + } + ] + } + ] + } +] diff --git a/js/web/test/data/ops/gather-elements.jsonc b/js/web/test/data/ops/gather-elements.jsonc new file mode 100644 index 0000000000000..caab3c11f64de --- /dev/null +++ b/js/web/test/data/ops/gather-elements.jsonc @@ -0,0 +1,234 @@ +[ + { + "name": "GatherElements float32 data + int32 indices-1", + "operator": "GatherElements", + "attributes": [{ "name": "axis", "data": 1, "type": "int" }], + "cases": [ + { + "name": "float32 data + int32 indices-1", + "inputs": [ + { + "data": [1, 2, 3, 4], + "dims": [2, 2], + "type": "float32" + }, + { + "data": [0, 0, 1, 0], + "dims": [2, 2], + "type": "int32" + } + ], + "outputs": [ + { + "data": [1, 1, 4, 3], + "dims": [2, 2], + "type": "float32" + } + ] + } + ] + }, + { + "name": "GatherElements float32 data + int32 indices-2", + "operator": "GatherElements", + "attributes": [{ "name": "axis", "data": 1, "type": "int" }], + "cases": [ + { + "name": "float32 data + int32 indices-2", + "inputs": [ + { + "data": [1, 2, 3, 4], + "dims": [2, 2], + "type": "float32" + }, + { + "data": [0, 1, 1, 0], + "dims": [2, 2], + "type": "int32" + } + ], + "outputs": [ + { + "data": [1, 2, 4, 3], + "dims": [2, 2], + "type": "float32" + } + ] + } + ] + }, + { + "name": "GatherElements float32 data + int64 indices - 1", + "operator": "GatherElements", + "attributes": [{ "name": "axis", "data": 1, "type": "int" }], + "cases": [ + { + "name": "float32 data + int64 indices - 1", + "inputs": [ + { + "data": [1, 2, 3, 4], + "dims": [2, 2], + "type": "float32" + }, + { + "data": [0, 0, -1, 0], + "dims": [2, 2], + "type": "int64" + } + ], + "outputs": [ + { + "data": [1, 1, 4, 3], + "dims": [2, 2], + "type": "float32" + } + ] + } + ] + }, + { + "name": "GatherElements float32 data + int64 indices - 2", + "operator": "GatherElements", + "attributes": [{ "name": "axis", "data": 1, "type": "int" }], + "cases": [ + { + "name": "float32 data + int64 indices - 2", + "inputs": [ + { + "data": [1, 2, 3, 4], + "dims": [2, 2], + "type": "float32" + }, + { + "data": [0, 0, -2, 0], + "dims": [2, 2], + "type": "int64" + } + ], + "outputs": [ + { + "data": [1, 1, 3, 3], + "dims": [2, 2], + "type": "float32" + } + ] + } + ] + }, + { + "name": "GatherElements int32 data + int32 indices-1", + "operator": "GatherElements", + "attributes": [{ "name": "axis", "data": 1, "type": "int" }], + "cases": [ + { + "name": "int32 data + int32 indices-1", + "inputs": [ + { + "data": [1, 2, 3, 4], + "dims": [2, 2], + "type": "int32" + }, + { + "data": [0, 0, 1, 0], + "dims": [2, 2], + "type": "int32" + } + ], + "outputs": [ + { + "data": [1, 1, 4, 3], + "dims": [2, 2], + "type": "int32" + } + ] + } + ] + }, + { + "name": "GatherElements uint32 data + int32 indices-1", + "operator": "GatherElements", + "attributes": [{ "name": "axis", "data": 1, "type": "int" }], + "cases": [ + { + "name": "uint32 data + int32 indices-1", + "inputs": [ + { + "data": [1, 2, 3, 4], + "dims": [2, 2], + "type": "uint32" + }, + { + "data": [0, 0, 1, 0], + "dims": [2, 2], + "type": "int32" + } + ], + "outputs": [ + { + "data": [1, 1, 4, 3], + "dims": [2, 2], + "type": "uint32" + } + ] + } + ] + }, + { + "name": "GatherElements float32 data + int32 indices-1 + Negative axis + Negative indices", + "operator": "GatherElements", + "attributes": [{ "name": "axis", "data": -1, "type": "int" }], + "cases": [ + { + "name": "GatherElements float32 data + int32 indices-1 + Negative axis + Negative indices", + "inputs": [ + { + "data": [1, 2, 3, 4], + "dims": [2, 2], + "type": "float32" + }, + { + "data": [0, 0, -1, 0], + "dims": [2, 2], + "type": "int32" + } + ], + "outputs": [ + { + "data": [1, 1, 4, 3], + "dims": [2, 2], + "type": "float32" + } + ] + } + ] + }, + { + "name": "GatherElements float32 data + int32 indices-3", + "operator": "GatherElements", + "attributes": [{ "name": "axis", "data": 0, "type": "int" }], + "cases": [ + { + "name": "GatherElements float32 data + int32 indices-3", + "inputs": [ + { + "data": [1, 2, 3, 4, 5, 6, 7, 8, 9], + "dims": [3, 3], + "type": "float32" + }, + { + "data": [1, 2, 0, 2, 0, 0], + "dims": [2, 3], + "type": "int32" + } + ], + "outputs": [ + { + "data": [4, 8, 3, 7, 2, 3], + "dims": [2, 3], + "type": "float32" + } + ] + } + ] + } +] diff --git a/js/web/test/data/ops/gelu.jsonc b/js/web/test/data/ops/gelu.jsonc new file mode 100644 index 0000000000000..b1546353bfeaf --- /dev/null +++ b/js/web/test/data/ops/gelu.jsonc @@ -0,0 +1,44 @@ +[ + { + "name": "gelu", + "operator": "Gelu", + "opset": { "domain": "com.microsoft", "version": 1 }, + "attributes": [], + "cases": [ + { + "name": "T[0]", + "inputs": [ + { + "data": [1.0, -2.0, 0, 2.0], + "dims": [2, 2], + "type": "float32" + } + ], + "outputs": [ + { + "data": [0.8413447141647339, -0.04550027847290039, 0, 1.9544997215270996], + "dims": [2, 2], + "type": "float32" + } + ] + }, + { + "name": "Scalar", + "inputs": [ + { + "data": [1.0], + "dims": [], + "type": "float32" + } + ], + "outputs": [ + { + "data": [0.8413447141647339], + "dims": [], + "type": "float32" + } + ] + } + ] + } +] diff --git a/js/web/test/data/ops/global-average-pool.jsonc b/js/web/test/data/ops/global-average-pool.jsonc index 9e67163456048..fdf3a8fe1e7a2 100644 --- a/js/web/test/data/ops/global-average-pool.jsonc +++ b/js/web/test/data/ops/global-average-pool.jsonc @@ -9,81 +9,13 @@ "inputs": [ { "data": [ - 1.764052391052246, - 0.40015721321105957, - 0.978738009929657, - 2.2408931255340576, - 1.8675580024719238, - -0.9772778749465942, - 0.9500884413719177, - -0.15135720372200012, - -0.10321885347366333, - 0.4105985164642334, - 0.14404356479644775, - 1.4542734622955322, - 0.7610377073287964, - 0.12167501449584961, - 0.44386324286460876, - 0.3336743414402008, - 1.4940791130065918, - -0.2051582634449005, - 0.3130677044391632, - -0.8540957570075989, - -2.5529897212982178, - 0.653618574142456, - 0.8644362092018127, - -0.7421650290489197, - 2.269754648208618, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 100, - 100, - 100, - 100, - 100, - 100, - 100, - 100, - 100, - 100, - 100, - 100, - 100, - 100, - 100, - 100, - 100, - 100, - 100, - 100, - 100, - 100, - 100, - 100, - 100 + 1.764052391052246, 0.40015721321105957, 0.978738009929657, 2.2408931255340576, 1.8675580024719238, + -0.9772778749465942, 0.9500884413719177, -0.15135720372200012, -0.10321885347366333, 0.4105985164642334, + 0.14404356479644775, 1.4542734622955322, 0.7610377073287964, 0.12167501449584961, 0.44386324286460876, + 0.3336743414402008, 1.4940791130065918, -0.2051582634449005, 0.3130677044391632, -0.8540957570075989, + -2.5529897212982178, 0.653618574142456, 0.8644362092018127, -0.7421650290489197, 2.269754648208618, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 100, 100, 100, 100, 100, 100, 100, + 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100 ], "dims": [1, 3, 5, 5], "type": "float32" @@ -102,81 +34,21 @@ "inputs": [ { "data": [ - 1.764052391052246, - 0.40015721321105957, - 0.978738009929657, - 2.2408931255340576, - 1.8675580024719238, - -0.9772778749465942, - 0.9500884413719177, - -0.15135720372200012, - -0.10321885347366333, - 0.4105985164642334, - 0.14404356479644775, - 1.4542734622955322, - 0.7610377073287964, - 0.12167501449584961, - 0.44386324286460876, - 0.3336743414402008, - 1.4940791130065918, - -0.2051582634449005, - 0.3130677044391632, - -0.8540957570075989, - -2.5529897212982178, - 0.653618574142456, - 0.8644362092018127, - -0.7421650290489197, - 2.269754648208618, - -1.4543657302856445, - 0.04575851559638977, - -0.18718385696411133, - 1.5327792167663574, - 1.4693588018417358, - 0.154947429895401, - 0.37816253304481506, - -0.8877857327461243, - -1.980796456336975, - -0.34791216254234314, - 0.15634897351264954, - 1.2302906513214111, - 1.202379822731018, - -0.38732680678367615, - -0.302302747964859, - -1.0485529899597168, - -1.420017957687378, - -1.7062702178955078, - 1.950775384902954, - -0.5096521973609924, - -0.4380742907524109, - -1.2527953386306763, - 0.7774903774261475, - -1.6138978004455566, - -0.21274028718471527, - -0.8954665660858154, - 0.38690251111984253, - -0.5108051300048828, - -1.18063223361969, - -0.02818222902715206, - 0.4283318817615509, - 0.06651721894741058, - 0.30247190594673157, - -0.6343221068382263, - -0.3627411723136902, - -0.6724604368209839, - -0.35955315828323364, - -0.8131462931632996, - -1.7262825965881348, - 0.17742614448070526, - -0.4017809331417084, - -1.630198359489441, - 0.46278226375579834, - -0.9072983860969543, - 0.05194539576768875, - 0.7290905714035034, - 0.12898291647434235, - 1.1394007205963135, - -1.234825849533081, - 0.4023416340351105 + 1.764052391052246, 0.40015721321105957, 0.978738009929657, 2.2408931255340576, 1.8675580024719238, + -0.9772778749465942, 0.9500884413719177, -0.15135720372200012, -0.10321885347366333, 0.4105985164642334, + 0.14404356479644775, 1.4542734622955322, 0.7610377073287964, 0.12167501449584961, 0.44386324286460876, + 0.3336743414402008, 1.4940791130065918, -0.2051582634449005, 0.3130677044391632, -0.8540957570075989, + -2.5529897212982178, 0.653618574142456, 0.8644362092018127, -0.7421650290489197, 2.269754648208618, + -1.4543657302856445, 0.04575851559638977, -0.18718385696411133, 1.5327792167663574, 1.4693588018417358, + 0.154947429895401, 0.37816253304481506, -0.8877857327461243, -1.980796456336975, -0.34791216254234314, + 0.15634897351264954, 1.2302906513214111, 1.202379822731018, -0.38732680678367615, -0.302302747964859, + -1.0485529899597168, -1.420017957687378, -1.7062702178955078, 1.950775384902954, -0.5096521973609924, + -0.4380742907524109, -1.2527953386306763, 0.7774903774261475, -1.6138978004455566, -0.21274028718471527, + -0.8954665660858154, 0.38690251111984253, -0.5108051300048828, -1.18063223361969, -0.02818222902715206, + 0.4283318817615509, 0.06651721894741058, 0.30247190594673157, -0.6343221068382263, -0.3627411723136902, + -0.6724604368209839, -0.35955315828323364, -0.8131462931632996, -1.7262825965881348, 0.17742614448070526, + -0.4017809331417084, -1.630198359489441, 0.46278226375579834, -0.9072983860969543, 0.05194539576768875, + 0.7290905714035034, 0.12898291647434235, 1.1394007205963135, -1.234825849533081, 0.4023416340351105 ], "dims": [1, 3, 5, 5], "type": "float32" @@ -184,11 +56,7 @@ ], "outputs": [ { - "data": [ - 0.47517386078834534, - -0.19405530393123627, - -0.2832600772380829 - ], + "data": [0.47517386078834534, -0.19405530393123627, -0.2832600772380829], "dims": [1, 3, 1, 1], "type": "float32" } diff --git a/js/web/test/data/ops/image-scaler.jsonc b/js/web/test/data/ops/image-scaler.jsonc index c4891f0340cc0..250ed4cbcd202 100644 --- a/js/web/test/data/ops/image-scaler.jsonc +++ b/js/web/test/data/ops/image-scaler.jsonc @@ -11,32 +11,7 @@ "name": "T[1,2,3,4]", "inputs": [ { - "data": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11 - ], + "data": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], "dims": [1, 2, 3, 4], "type": "float32" } @@ -44,30 +19,11 @@ "outputs": [ { "data": [ - 0.0, - 0.003921568859368563, - 0.007843137718737125, - 0.011764706578105688, - 0.01568627543747425, - 0.019607844296842813, - 0.023529413156211376, - 0.02745098201557994, - 0.0313725508749485, - 0.035294119734317064, - 0.03921568859368563, - 0.04313725745305419, - 0.0, - 0.003921568859368563, - 0.007843137718737125, - 0.011764706578105688, - 0.01568627543747425, - 0.019607844296842813, - 0.023529413156211376, - 0.02745098201557994, - 0.0313725508749485, - 0.035294119734317064, - 0.03921568859368563, - 0.04313725745305419 + 0.0, 0.003921568859368563, 0.007843137718737125, 0.011764706578105688, 0.01568627543747425, + 0.019607844296842813, 0.023529413156211376, 0.02745098201557994, 0.0313725508749485, 0.035294119734317064, + 0.03921568859368563, 0.04313725745305419, 0.0, 0.003921568859368563, 0.007843137718737125, + 0.011764706578105688, 0.01568627543747425, 0.019607844296842813, 0.023529413156211376, + 0.02745098201557994, 0.0313725508749485, 0.035294119734317064, 0.03921568859368563, 0.04313725745305419 ], "dims": [1, 2, 3, 4], "type": "float32" diff --git a/js/web/test/data/ops/instance-norm.jsonc b/js/web/test/data/ops/instance-norm.jsonc new file mode 100644 index 0000000000000..6a4e6912405ee --- /dev/null +++ b/js/web/test/data/ops/instance-norm.jsonc @@ -0,0 +1,79 @@ +[ + { + "name": "Simple test with NHWC", + "operator": "InstanceNormalization", + "inputShapeDefinitions": "rankOnly", + "opset": { "domain": "", "version": 17 }, + "cases": [ + { + "name": "Simple test", + "inputs": [ + { + "data": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 9, 8, 7, 6, 5, 4], + "dims": [1, 4, 2, 2], + "type": "float32" + }, + { + "data": [1, 2, 3, 4], + "dims": [4], + "type": "float32" + }, + { + "data": [4, 5, 6, 7], + "dims": [4], + "type": "float32" + } + ], + "outputs": [ + { + "data": [ + 2.6583645343780518, 3.552788257598877, 4.447211742401123, 5.341635704040527, 2.3167295455932617, + 4.105576515197754, 5.8944244384765625, 7.683271408081055, 6, 10.242595672607422, 6, 1.7574005126953125, + 12.36654281616211, 8.788846969604492, 5.211153030395508, 1.633458137512207 + ], + "dims": [1, 4, 2, 2], + "type": "float32" + } + ] + } + ] + }, + { + "name": "Simple test with NCHW", + "operator": "InstanceNormalization", + "opset": { "domain": "", "version": 17 }, + "cases": [ + { + "name": "Simple test", + "inputs": [ + { + "data": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 9, 8, 7, 6, 5, 4], + "dims": [1, 4, 2, 2], + "type": "float32" + }, + { + "data": [1, 2, 3, 4], + "dims": [4], + "type": "float32" + }, + { + "data": [4, 5, 6, 7], + "dims": [4], + "type": "float32" + } + ], + "outputs": [ + { + "data": [ + 2.6583645343780518, 3.552788257598877, 4.447211742401123, 5.341635704040527, 2.3167295455932617, + 4.105576515197754, 5.8944244384765625, 7.683271408081055, 6, 10.242595672607422, 6, 1.7574005126953125, + 12.36654281616211, 8.788846969604492, 5.211153030395508, 1.633458137512207 + ], + "dims": [1, 4, 2, 2], + "type": "float32" + } + ] + } + ] + } +] diff --git a/js/web/test/data/ops/layer-norm.jsonc b/js/web/test/data/ops/layer-norm.jsonc new file mode 100644 index 0000000000000..d27d7e7083001 --- /dev/null +++ b/js/web/test/data/ops/layer-norm.jsonc @@ -0,0 +1,33 @@ +[ + { + "name": "Simple test without bias", + "operator": "LayerNormalization", + "cases": [ + { + "name": "Simple test without bias", + "inputs": [ + { + "data": [1, 2, 3, 4, 5, 6, 7, 8], + "dims": [1, 2, 4], + "type": "float32" + }, + { + "data": [1, 2, 3, 4], + "dims": [4], + "type": "float32" + } + ], + "outputs": [ + { + "data": [ + -1.3416354656219482, -0.8944236636161804, 1.3416354656219482, 5.366541862487793, -1.3416354656219482, + -0.8944236636161804, 1.3416354656219482, 5.366541862487793 + ], + "dims": [1, 2, 4], + "type": "float32" + } + ] + } + ] + } +] diff --git a/js/web/test/data/ops/leaky-relu.jsonc b/js/web/test/data/ops/leaky-relu.jsonc index 6352a7b09529f..7bfa8c64cbb8c 100644 --- a/js/web/test/data/ops/leaky-relu.jsonc +++ b/js/web/test/data/ops/leaky-relu.jsonc @@ -8,14 +8,14 @@ "name": "T[0]", "inputs": [ { - "data": [-1.0, 0.0, 1.0, 1.0, -2.0], + "data": [-1.0, 0.0, 1.0, -2.0], "dims": [1, 4], "type": "float32" } ], "outputs": [ { - "data": [-0.01, 0.0, 1.0, 1.0], + "data": [-0.01, 0.0, 1.0, -0.02], "dims": [1, 4], "type": "float32" } diff --git a/js/web/test/data/ops/log.jsonc b/js/web/test/data/ops/log.jsonc index 1c1d266ccfb62..84a8b87c6ca13 100644 --- a/js/web/test/data/ops/log.jsonc +++ b/js/web/test/data/ops/log.jsonc @@ -49,16 +49,7 @@ ], "outputs": [ { - "data": [ - 0.0, - 0.69314718, - 0.0, - 1.09861229, - 0.69314718, - 1.09861229, - 0.0, - 0.69314718 - ], + "data": [0.0, 0.69314718, 0.0, 1.09861229, 0.69314718, 1.09861229, 0.0, 0.69314718], "dims": [2, 4], "type": "float32" } diff --git a/js/web/test/data/ops/matmul-broadcast.jsonc b/js/web/test/data/ops/matmul-broadcast.jsonc new file mode 100644 index 0000000000000..170924bb585af --- /dev/null +++ b/js/web/test/data/ops/matmul-broadcast.jsonc @@ -0,0 +1,219 @@ +[ + { + "name": "matmul tests with no attributes", + "operator": "MatMul", + "attributes": [], + "cases": [ + { + "name": "multiplies 5D broadcasted to 6D tensors", + "inputs": [ + { + "data": [ + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, + 143, 144, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 145, 146, 147, + 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192 + ], + "dims": [4, 3, 2, 4, 2], + "type": "float32" + }, + { + "data": [ + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 64, 65, 66, 67, 68, 69, 70, 71, 72, 64, 65, 66, 67, 68, 69, 70, 71, 72 + ], + "dims": [2, 4, 3, 2, 2, 3], + "type": "float32" + } + ], + "outputs": [ + { + "data": [ + 7377, 7476, 7575, 7675, 7778, 7881, 7973, 8080, 8187, 8271, 8382, 8493, 9259, 9374, 9489, 9581, 9700, + 9819, 9903, 10026, 10149, 10225, 10352, 10479, 11333, 11464, 11595, 11679, 11814, 11949, 12025, 12164, + 12303, 12371, 12514, 12657, 369, 516, 663, 379, 530, 681, 389, 544, 699, 399, 558, 717, 1387, 1550, 1713, + 1421, 1588, 1755, 1455, 1626, 1797, 1489, 1664, 1839, 2597, 2776, 2955, 2655, 2838, 3021, 2713, 2900, + 3087, 2771, 2962, 3153, 3999, 4194, 4389, 4081, 4280, 4479, 4163, 4366, 4569, 4245, 4452, 4659, 5593, + 5804, 6015, 5699, 5914, 6129, 5805, 6024, 6243, 5911, 6134, 6357, 7379, 7606, 7833, 7509, 7740, 7971, + 7639, 7874, 8109, 7769, 8008, 8247, 9357, 9600, 9843, 9511, 9758, 10005, 9665, 9916, 10167, 9819, 10074, + 10329, 11527, 11786, 12045, 11705, 11968, 12231, 11883, 12150, 12417, 12061, 12332, 12603, 13889, 14164, + 14439, 14091, 14370, 14649, 14293, 14576, 14859, 14495, 14782, 15069, 171, 174, 177, 397, 404, 411, 623, + 634, 645, 849, 864, 879, 1189, 1208, 1227, 1439, 1462, 1485, 1689, 1716, 1743, 1939, 1970, 2001, 2399, + 2434, 2469, 2673, 2712, 2751, 2947, 2990, 3033, 3221, 3268, 3315, 3801, 3852, 3903, 4099, 4154, 4209, + 4397, 4456, 4515, 4695, 4758, 4821, 5395, 5462, 5529, 5717, 5788, 5859, 6039, 6114, 6189, 6361, 6440, + 6519, 7181, 7264, 7347, 7527, 7614, 7701, 7873, 7964, 8055, 8219, 8314, 8409, 729, 1020, 1311, 739, 1034, + 1329, 749, 1048, 1347, 759, 1062, 1365, 2611, 2918, 3225, 2645, 2956, 3267, 2679, 2994, 3309, 2713, 3032, + 3351, 4685, 5008, 5331, 4743, 5070, 5397, 4801, 5132, 5463, 4859, 5194, 5529, 6951, 7290, 7629, 7033, + 7376, 7719, 7115, 7462, 7809, 7197, 7548, 7899, 9409, 9764, 10119, 9515, 9874, 10233, 9621, 9984, 10347, + 9727, 10094, 10461, 12059, 12430, 12801, 12189, 12564, 12939, 12319, 12698, 13077, 12449, 12832, 13215, + 3813, 3912, 4011, 3967, 4070, 4173, 4121, 4228, 4335, 4275, 4386, 4497, 5119, 5234, 5349, 5297, 5416, + 5535, 5475, 5598, 5721, 5653, 5780, 5907, 6617, 6748, 6879, 6819, 6954, 7089, 7021, 7160, 7299, 7223, + 7366, 7509, 8307, 8454, 8601, 8533, 8684, 8835, 8759, 8914, 9069, 8985, 9144, 9303, 10189, 10352, 10515, + 10439, 10606, 10773, 10689, 10860, 11031, 10939, 11114, 11289, 12263, 12442, 12621, 12537, 12720, 12903, + 12811, 12998, 13185, 13085, 13276, 13467, 14529, 14724, 14919, 14827, 15026, 15225, 15125, 15328, 15531, + 15423, 15630, 15837, 16987, 17198, 17409, 17309, 17524, 17739, 17631, 17850, 18069, 17953, 18176, 18399, + 19637, 19864, 20091, 19983, 20214, 20445, 20329, 20564, 20799, 20675, 20914, 21153, 609, 852, 1095, 619, + 866, 1113, 629, 880, 1131, 639, 894, 1149, 2203, 2462, 2721, 2237, 2500, 2763, 2271, 2538, 2805, 2305, + 2576, 2847, 3989, 4264, 4539, 4047, 4326, 4605, 4105, 4388, 4671, 4163, 4450, 4737, 63, 66, 69, 145, 152, + 159, 227, 238, 249, 309, 324, 339, 505, 524, 543, 611, 634, 657, 717, 744, 771, 823, 854, 885, 1139, 1174, + 1209, 1269, 1308, 1347, 1399, 1442, 1485, 1529, 1576, 1623, 1965, 2016, 2067, 2119, 2174, 2229, 2273, + 2332, 2391, 2427, 2490, 2553, 2983, 3050, 3117, 3161, 3232, 3303, 3339, 3414, 3489, 3517, 3596, 3675, + 4193, 4276, 4359, 4395, 4482, 4569, 4597, 4688, 4779, 4799, 4894, 4989, 16443, 16734, 17025, 16669, 16964, + 17259, 16895, 17194, 17493, 17121, 17424, 17727, 19189, 19496, 19803, 19439, 19750, 20061, 19689, 20004, + 20319, 19939, 20258, 20577, 22127, 22450, 22773, 22401, 22728, 23055, 22675, 23006, 23337, 22949, 23284, + 23619, 22206, 22545, 22884, 22468, 22811, 23154, 22730, 23077, 23424, 22992, 23343, 23694, 23782, 24137, + 24492, 24050, 24409, 24768, 24318, 24681, 25044, 24586, 24953, 25320, 25415, 25786, 26157, 25689, 26064, + 26439, 25963, 26342, 26721, 26237, 26620, 27003 + ], + "dims": [2, 4, 3, 2, 4, 3], + "type": "float32" + } + ] + }, + { + "name": "multiplies 4D broadcasted to 6D tensors", + "inputs": [ + { + "data": [1, 2, 3, 4, 5, 6, 7, 8, 17, 18, 19, 20, 21, 22, 23, 24, 9, 10, 11, 12, 13, 14, 15, 16], + "dims": [3, 1, 4, 2], + "type": "float32" + }, + { + "data": [ + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 64, 65, 66, 67, 68, 69, 70, 71, 72, 64, 65, 66, 67, 68, 69, 70, 71, 72 + ], + "dims": [2, 4, 3, 2, 2, 3], + "type": "float32" + } + ], + "outputs": [ + { + "data": [ + 225, 228, 231, 523, 530, 537, 821, 832, 843, 1119, 1134, 1149, 243, 246, 249, 565, 572, 579, 887, 898, + 909, 1209, 1224, 1239, 3029, 3064, 3099, 3375, 3414, 3453, 3721, 3764, 3807, 4067, 4114, 4161, 89, 124, + 159, 99, 138, 177, 109, 152, 195, 119, 166, 213, 163, 182, 201, 197, 220, 243, 231, 258, 285, 265, 296, + 327, 277, 296, 315, 335, 358, 381, 393, 420, 447, 451, 482, 513, 63, 66, 69, 145, 152, 159, 227, 238, 249, + 309, 324, 339, 81, 84, 87, 187, 194, 201, 293, 304, 315, 399, 414, 429, 1139, 1174, 1209, 1269, 1308, + 1347, 1399, 1442, 1485, 1529, 1576, 1623, 1349, 1384, 1419, 1503, 1542, 1581, 1657, 1700, 1743, 1811, + 1858, 1905, 847, 866, 885, 1025, 1048, 1071, 1203, 1230, 1257, 1381, 1412, 1443, 961, 980, 999, 1163, + 1186, 1209, 1365, 1392, 1419, 1567, 1598, 1629, 171, 174, 177, 397, 404, 411, 623, 634, 645, 849, 864, + 879, 189, 192, 195, 439, 446, 453, 689, 700, 711, 939, 954, 969, 2399, 2434, 2469, 2673, 2712, 2751, 2947, + 2990, 3033, 3221, 3268, 3315, 2609, 2644, 2679, 2907, 2946, 2985, 3205, 3248, 3291, 3503, 3550, 3597, + 1531, 1550, 1569, 1853, 1876, 1899, 2175, 2202, 2229, 2497, 2528, 2559, 1645, 1664, 1683, 1991, 2014, + 2037, 2337, 2364, 2391, 2683, 2714, 2745, 9, 12, 15, 19, 26, 33, 29, 40, 51, 39, 54, 69, 27, 30, 33, 61, + 68, 75, 95, 106, 117, 129, 144, 159, 509, 544, 579, 567, 606, 645, 625, 668, 711, 683, 730, 777, 719, 754, + 789, 801, 840, 879, 883, 926, 969, 965, 1012, 1059, 505, 524, 543, 611, 634, 657, 717, 744, 771, 823, 854, + 885, 619, 638, 657, 749, 772, 795, 879, 906, 933, 1009, 1040, 1071, 117, 120, 123, 271, 278, 285, 425, + 436, 447, 579, 594, 609, 135, 138, 141, 313, 320, 327, 491, 502, 513, 669, 684, 699, 1769, 1804, 1839, + 1971, 2010, 2049, 2173, 2216, 2259, 2375, 2422, 2469, 1979, 2014, 2049, 2205, 2244, 2283, 2431, 2474, + 2517, 2657, 2704, 2751, 1189, 1208, 1227, 1439, 1462, 1485, 1689, 1716, 1743, 1939, 1970, 2001, 1303, + 1322, 1341, 1577, 1600, 1623, 1851, 1878, 1905, 2125, 2156, 2187, 225, 228, 231, 523, 530, 537, 821, 832, + 843, 1119, 1134, 1149, 243, 246, 249, 565, 572, 579, 887, 898, 909, 1209, 1224, 1239, 3029, 3064, 3099, + 3375, 3414, 3453, 3721, 3764, 3807, 4067, 4114, 4161, 89, 124, 159, 99, 138, 177, 109, 152, 195, 119, 166, + 213, 163, 182, 201, 197, 220, 243, 231, 258, 285, 265, 296, 327, 277, 296, 315, 335, 358, 381, 393, 420, + 447, 451, 482, 513, 63, 66, 69, 145, 152, 159, 227, 238, 249, 309, 324, 339, 81, 84, 87, 187, 194, 201, + 293, 304, 315, 399, 414, 429, 1139, 1174, 1209, 1269, 1308, 1347, 1399, 1442, 1485, 1529, 1576, 1623, + 1349, 1384, 1419, 1503, 1542, 1581, 1657, 1700, 1743, 1811, 1858, 1905, 847, 866, 885, 1025, 1048, 1071, + 1203, 1230, 1257, 1381, 1412, 1443, 961, 980, 999, 1163, 1186, 1209, 1365, 1392, 1419, 1567, 1598, 1629, + 171, 174, 177, 397, 404, 411, 623, 634, 645, 849, 864, 879, 189, 192, 195, 439, 446, 453, 689, 700, 711, + 939, 954, 969, 2399, 2434, 2469, 2673, 2712, 2751, 2947, 2990, 3033, 3221, 3268, 3315, 2294, 2329, 2364, + 2556, 2595, 2634, 2818, 2861, 2904, 3080, 3127, 3174, 1270, 1289, 1308, 1538, 1561, 1584, 1806, 1833, + 1860, 2074, 2105, 2136, 1303, 1322, 1341, 1577, 1600, 1623, 1851, 1878, 1905, 2125, 2156, 2187 + ], + "dims": [2, 4, 3, 2, 4, 3], + "type": "float32" + } + ] + }, + { + "name": "multiplies 6D with 4D tensors", + "inputs": [ + { + "data": [ + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 64, 65, 66, 67, 68, 69, 70, 71, 72, 64, 65, 66, 67, 68, 69, 70, 71, 72 + ], + "dims": [2, 4, 3, 2, 3, 2], + "type": "float32" + }, + { + "data": [1, 2, 3, 4, 5, 6, 7, 8, 17, 18, 19, 20, 21, 22, 23, 24, 9, 10, 11, 12, 13, 14, 15, 16], + "dims": [3, 1, 2, 4], + "type": "float32" + } + ], + "outputs": [ + { + "data": [ + 443, 590, 737, 884, 455, 606, 757, 908, 467, 622, 777, 932, 479, 638, 797, 956, 491, 654, 817, 980, 503, + 670, 837, 1004, 3251, 3422, 3593, 3764, 3327, 3502, 3677, 3852, 3403, 3582, 3761, 3940, 59, 62, 65, 68, + 135, 142, 149, 156, 211, 222, 233, 244, 167, 182, 197, 212, 211, 230, 249, 268, 255, 278, 301, 324, 299, + 326, 353, 380, 343, 374, 405, 436, 387, 422, 457, 492, 119, 158, 197, 236, 131, 174, 217, 260, 143, 190, + 237, 284, 155, 206, 257, 308, 167, 222, 277, 332, 179, 238, 297, 356, 1199, 1262, 1325, 1388, 1275, 1342, + 1409, 1476, 1351, 1422, 1493, 1564, 1427, 1502, 1577, 1652, 1503, 1582, 1661, 1740, 1579, 1662, 1745, + 1828, 959, 1046, 1133, 1220, 1003, 1094, 1185, 1276, 1047, 1142, 1237, 1332, 1091, 1190, 1289, 1388, 1135, + 1238, 1341, 1444, 1179, 1286, 1393, 1500, 335, 446, 557, 668, 347, 462, 577, 692, 359, 478, 597, 716, 371, + 494, 617, 740, 383, 510, 637, 764, 395, 526, 657, 788, 2567, 2702, 2837, 2972, 2643, 2782, 2921, 3060, + 2719, 2862, 3005, 3148, 2795, 2942, 3089, 3236, 2871, 3022, 3173, 3324, 2947, 3102, 3257, 3412, 1751, + 1910, 2069, 2228, 1795, 1958, 2121, 2284, 1839, 2006, 2173, 2340, 1883, 2054, 2225, 2396, 1927, 2102, + 2277, 2452, 1971, 2150, 2329, 2508, 11, 14, 17, 20, 23, 30, 37, 44, 35, 46, 57, 68, 47, 62, 77, 92, 59, + 78, 97, 116, 71, 94, 117, 140, 515, 542, 569, 596, 591, 622, 653, 684, 667, 702, 737, 772, 743, 782, 821, + 860, 819, 862, 905, 948, 895, 942, 989, 1036, 563, 614, 665, 716, 607, 662, 717, 772, 651, 710, 769, 828, + 695, 758, 821, 884, 739, 806, 873, 940, 783, 854, 925, 996, 227, 302, 377, 452, 239, 318, 397, 476, 251, + 334, 417, 500, 263, 350, 437, 524, 275, 366, 457, 548, 287, 382, 477, 572, 1883, 1982, 2081, 2180, 1959, + 2062, 2165, 2268, 2035, 2142, 2249, 2356, 2111, 2222, 2333, 2444, 2187, 2302, 2417, 2532, 2263, 2382, + 2501, 2620, 1355, 1478, 1601, 1724, 1399, 1526, 1653, 1780, 1443, 1574, 1705, 1836, 1487, 1622, 1757, + 1892, 1531, 1670, 1809, 1948, 1575, 1718, 1861, 2004, 443, 590, 737, 884, 455, 606, 757, 908, 467, 622, + 777, 932, 479, 638, 797, 956, 491, 654, 817, 980, 503, 670, 837, 1004, 3251, 3422, 3593, 3764, 3327, 3502, + 3677, 3852, 3403, 3582, 3761, 3940, 59, 62, 65, 68, 135, 142, 149, 156, 211, 222, 233, 244, 167, 182, 197, + 212, 211, 230, 249, 268, 255, 278, 301, 324, 299, 326, 353, 380, 343, 374, 405, 436, 387, 422, 457, 492, + 119, 158, 197, 236, 131, 174, 217, 260, 143, 190, 237, 284, 155, 206, 257, 308, 167, 222, 277, 332, 179, + 238, 297, 356, 1199, 1262, 1325, 1388, 1275, 1342, 1409, 1476, 1351, 1422, 1493, 1564, 1427, 1502, 1577, + 1652, 1503, 1582, 1661, 1740, 1579, 1662, 1745, 1828, 959, 1046, 1133, 1220, 1003, 1094, 1185, 1276, 1047, + 1142, 1237, 1332, 1091, 1190, 1289, 1388, 1135, 1238, 1341, 1444, 1179, 1286, 1393, 1500, 335, 446, 557, + 668, 347, 462, 577, 692, 359, 478, 597, 716, 371, 494, 617, 740, 383, 510, 637, 764, 395, 526, 657, 788, + 2567, 2702, 2837, 2972, 2643, 2782, 2921, 3060, 2719, 2862, 3005, 3148, 2453, 2582, 2711, 2840, 2529, + 2662, 2795, 2928, 2605, 2742, 2879, 3016, 1553, 1694, 1835, 1976, 1480, 1616, 1752, 1888, 1443, 1574, + 1705, 1836, 1487, 1622, 1757, 1892, 1531, 1670, 1809, 1948, 1575, 1718, 1861, 2004 + ], + "dims": [2, 4, 3, 2, 3, 4], + "type": "float32" + } + ] + } + ] + } +] diff --git a/js/web/test/data/ops/matmul.jsonc b/js/web/test/data/ops/matmul.jsonc index 8363ed785131d..2c2cf509d7e3e 100644 --- a/js/web/test/data/ops/matmul.jsonc +++ b/js/web/test/data/ops/matmul.jsonc @@ -74,18 +74,14 @@ "name": "multiplies 3D tensors", "inputs": [ { - "data": [ - 1, 2, 3, 4, 5, 6, 7, 8, 17, 18, 19, 20, 21, 22, 23, 24, 9, 10, 11, - 12, 13, 14, 15, 16 - ], + "data": [1, 2, 3, 4, 5, 6, 7, 8, 17, 18, 19, 20, 21, 22, 23, 24, 9, 10, 11, 12, 13, 14, 15, 16], "dims": [3, 2, 4], "type": "float32" }, { "data": [ - 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 1, 2, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36 + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36 ], "dims": [3, 4, 3], "type": "float32" @@ -93,10 +89,7 @@ ], "outputs": [ { - "data": [ - 190, 200, 210, 470, 496, 522, 422, 496, 570, 510, 600, 690, 1254, - 1296, 1338, 1726, 1784, 1842 - ], + "data": [190, 200, 210, 470, 496, 522, 422, 496, 570, 510, 600, 690, 1254, 1296, 1338, 1726, 1784, 1842], "dims": [3, 2, 3], "type": "float32" } @@ -107,23 +100,19 @@ "inputs": [ { "data": [ - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, - 69, 70, 71, 72, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36 + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36 ], "dims": [2, 3, 4, 3], "type": "float32" }, { "data": [ - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, - 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 1, 2, 3, 4, 5, - 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45 + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45 ], "dims": [2, 3, 3, 5], "type": "float32" @@ -132,18 +121,13 @@ "outputs": [ { "data": [ - 5824, 5938, 6052, 6166, 6280, 6283, 6406, 6529, 6652, 6775, 6742, - 6874, 7006, 7138, 7270, 7201, 7342, 7483, 7624, 7765, 9910, 10060, - 10210, 10360, 10510, 10504, 10663, 10822, 10981, 11140, 11098, - 11266, 11434, 11602, 11770, 11692, 11869, 12046, 12223, 12400, - 15076, 15262, 15448, 15634, 15820, 15805, 16000, 16195, 16390, - 16585, 16534, 16738, 16942, 17146, 17350, 17263, 17476, 17689, - 17902, 18115, 46, 52, 58, 64, 70, 100, 115, 130, 145, 160, 154, - 178, 202, 226, 250, 208, 241, 274, 307, 340, 892, 934, 976, 1018, - 1060, 1081, 1132, 1183, 1234, 1285, 1270, 1330, 1390, 1450, 1510, - 1459, 1528, 1597, 1666, 1735, 2818, 2896, 2974, 3052, 3130, 3142, - 3229, 3316, 3403, 3490, 3466, 3562, 3658, 3754, 3850, 3790, 3895, - 4000, 4105, 4210 + 5824, 5938, 6052, 6166, 6280, 6283, 6406, 6529, 6652, 6775, 6742, 6874, 7006, 7138, 7270, 7201, 7342, + 7483, 7624, 7765, 9910, 10060, 10210, 10360, 10510, 10504, 10663, 10822, 10981, 11140, 11098, 11266, + 11434, 11602, 11770, 11692, 11869, 12046, 12223, 12400, 15076, 15262, 15448, 15634, 15820, 15805, 16000, + 16195, 16390, 16585, 16534, 16738, 16942, 17146, 17350, 17263, 17476, 17689, 17902, 18115, 46, 52, 58, 64, + 70, 100, 115, 130, 145, 160, 154, 178, 202, 226, 250, 208, 241, 274, 307, 340, 892, 934, 976, 1018, 1060, + 1081, 1132, 1183, 1234, 1285, 1270, 1330, 1390, 1450, 1510, 1459, 1528, 1597, 1666, 1735, 2818, 2896, + 2974, 3052, 3130, 3142, 3229, 3316, 3403, 3490, 3466, 3562, 3658, 3754, 3850, 3790, 3895, 4000, 4105, 4210 ], "dims": [2, 3, 4, 5], "type": "float32" @@ -160,20 +144,15 @@ }, { "data": [ - 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, - 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, - 137, 138, 139, 140, 141, 142, 143, 144, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 42, 43, 44, 45, 46, 47, 48, 145, 146, 147, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, - 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, - 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, - 191, 192 + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, + 143, 144, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 145, 146, 147, + 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192 ], "dims": [4, 3, 2, 4, 2], "type": "float32" @@ -182,14 +161,11 @@ "outputs": [ { "data": [ - 369, 376, 414, 422, 425, 432, 478, 486, 481, 488, 542, 550, 537, - 544, 606, 614, 593, 600, 670, 678, 649, 656, 734, 742, 705, 712, - 798, 806, 761, 768, 862, 870, 817, 824, 926, 934, 873, 880, 990, - 998, 929, 936, 1054, 1062, 985, 992, 1118, 1126, 33, 40, 30, 38, - 89, 96, 94, 102, 145, 152, 158, 166, 201, 208, 222, 230, 257, 264, - 286, 294, 313, 320, 350, 358, 1041, 1048, 1182, 1190, 1097, 1104, - 1246, 1254, 1153, 1160, 1310, 1318, 1209, 1216, 1374, 1382, 1265, - 1272, 1438, 1446, 1321, 1328, 1502, 1510 + 369, 376, 414, 422, 425, 432, 478, 486, 481, 488, 542, 550, 537, 544, 606, 614, 593, 600, 670, 678, 649, + 656, 734, 742, 705, 712, 798, 806, 761, 768, 862, 870, 817, 824, 926, 934, 873, 880, 990, 998, 929, 936, + 1054, 1062, 985, 992, 1118, 1126, 33, 40, 30, 38, 89, 96, 94, 102, 145, 152, 158, 166, 201, 208, 222, 230, + 257, 264, 286, 294, 313, 320, 350, 358, 1041, 1048, 1182, 1190, 1097, 1104, 1246, 1254, 1153, 1160, 1310, + 1318, 1209, 1216, 1374, 1382, 1265, 1272, 1438, 1446, 1321, 1328, 1502, 1510 ], "dims": [4, 3, 2, 2, 2], "type": "float32" @@ -200,29 +176,21 @@ "name": "multiplies 4D broadcasted to 5D tensors", "inputs": [ { - "data": [ - 1, 2, 3, 4, 5, 6, 7, 8, 17, 18, 19, 20, 21, 22, 23, 24, 9, 10, 11, - 12, 13, 14, 15, 16 - ], + "data": [1, 2, 3, 4, 5, 6, 7, 8, 17, 18, 19, 20, 21, 22, 23, 24, 9, 10, 11, 12, 13, 14, 15, 16], "dims": [3, 1, 2, 4], "type": "float32" }, { "data": [ - 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, - 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, - 137, 138, 139, 140, 141, 142, 143, 144, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 42, 43, 44, 45, 46, 47, 48, 145, 146, 147, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, - 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, - 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, - 191, 192 + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, + 143, 144, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 145, 146, 147, + 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192 ], "dims": [4, 3, 2, 4, 2], "type": "float32" @@ -231,14 +199,11 @@ "outputs": [ { "data": [ - 530, 540, 1362, 1388, 610, 620, 1570, 1596, 5042, 5116, 6130, - 6220, 5634, 5708, 6850, 6940, 3538, 3580, 4882, 4940, 3874, 3916, - 5346, 5404, 1010, 1020, 2610, 2636, 1090, 1100, 2818, 2844, 8594, - 8668, 10450, 10540, 9186, 9260, 11170, 11260, 5554, 5596, 7666, - 7724, 5890, 5932, 8130, 8188, 50, 60, 114, 140, 130, 140, 322, - 348, 1490, 1564, 1810, 1900, 2082, 2156, 2530, 2620, 1522, 1564, - 2098, 2156, 1858, 1900, 2562, 2620, 1490, 1500, 3858, 3884, 1570, - 1580, 4066, 4092, 12146, 12220, 14770, 14860, 12738, 12812, 15490, + 530, 540, 1362, 1388, 610, 620, 1570, 1596, 5042, 5116, 6130, 6220, 5634, 5708, 6850, 6940, 3538, 3580, + 4882, 4940, 3874, 3916, 5346, 5404, 1010, 1020, 2610, 2636, 1090, 1100, 2818, 2844, 8594, 8668, 10450, + 10540, 9186, 9260, 11170, 11260, 5554, 5596, 7666, 7724, 5890, 5932, 8130, 8188, 50, 60, 114, 140, 130, + 140, 322, 348, 1490, 1564, 1810, 1900, 2082, 2156, 2530, 2620, 1522, 1564, 2098, 2156, 1858, 1900, 2562, + 2620, 1490, 1500, 3858, 3884, 1570, 1580, 4066, 4092, 12146, 12220, 14770, 14860, 12738, 12812, 15490, 15580, 7570, 7612, 10450, 10508, 7906, 7948, 10914, 10972 ], "dims": [4, 3, 2, 2, 2], @@ -251,12 +216,10 @@ "inputs": [ { "data": [ - 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, - 89, 90, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, - 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72 + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72 ], "dims": [5, 3, 1, 2, 3], "type": "float32" @@ -270,24 +233,86 @@ "outputs": [ { "data": [ - 1342, 1564, 1786, 2008, 2230, 1396, 1627, 1858, 2089, 2320, 1450, - 1690, 1930, 2170, 2410, 1504, 1753, 2002, 2251, 2500, 1558, 1816, - 2074, 2332, 2590, 1612, 1879, 2146, 2413, 2680, 46, 52, 58, 64, - 70, 100, 115, 130, 145, 160, 154, 178, 202, 226, 250, 208, 241, - 274, 307, 340, 262, 304, 346, 388, 430, 316, 367, 418, 469, 520, - 370, 430, 490, 550, 610, 424, 493, 562, 631, 700, 478, 556, 634, - 712, 790, 532, 619, 706, 793, 880, 586, 682, 778, 874, 970, 640, - 745, 850, 955, 1060, 694, 808, 922, 1036, 1150, 748, 871, 994, - 1117, 1240, 802, 934, 1066, 1198, 1330, 856, 997, 1138, 1279, - 1420, 910, 1060, 1210, 1360, 1510, 964, 1123, 1282, 1441, 1600, - 1018, 1186, 1354, 1522, 1690, 1072, 1249, 1426, 1603, 1780, 1126, - 1312, 1498, 1684, 1870, 1180, 1375, 1570, 1765, 1960, 1234, 1438, - 1642, 1846, 2050, 1288, 1501, 1714, 1927, 2140 + 1342, 1564, 1786, 2008, 2230, 1396, 1627, 1858, 2089, 2320, 1450, 1690, 1930, 2170, 2410, 1504, 1753, + 2002, 2251, 2500, 1558, 1816, 2074, 2332, 2590, 1612, 1879, 2146, 2413, 2680, 46, 52, 58, 64, 70, 100, + 115, 130, 145, 160, 154, 178, 202, 226, 250, 208, 241, 274, 307, 340, 262, 304, 346, 388, 430, 316, 367, + 418, 469, 520, 370, 430, 490, 550, 610, 424, 493, 562, 631, 700, 478, 556, 634, 712, 790, 532, 619, 706, + 793, 880, 586, 682, 778, 874, 970, 640, 745, 850, 955, 1060, 694, 808, 922, 1036, 1150, 748, 871, 994, + 1117, 1240, 802, 934, 1066, 1198, 1330, 856, 997, 1138, 1279, 1420, 910, 1060, 1210, 1360, 1510, 964, + 1123, 1282, 1441, 1600, 1018, 1186, 1354, 1522, 1690, 1072, 1249, 1426, 1603, 1780, 1126, 1312, 1498, + 1684, 1870, 1180, 1375, 1570, 1765, 1960, 1234, 1438, 1642, 1846, 2050, 1288, 1501, 1714, 1927, 2140 ], "dims": [5, 3, 1, 2, 5], "type": "float32" } ] + }, + { + "name": "multiplies 2D with 4D tensors vec4", + "inputs": [ + { + "data": [1, 2, 1, 3, 2, 3, 1, 2], + "dims": [2, 4], + "type": "float32" + }, + { + "data": [ + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, + 30, 31 + ], + "dims": [3, 2, 4, 4], + "type": "float32" + } + ], + "outputs": [ + { + "data": [ + 395, 402, 409, 416, 436, 444, 452, 460, 507, 514, 521, 528, 564, 572, 580, 588, 619, 626, 633, 640, 692, + 700, 708, 716, 731, 738, 745, 752, 820, 828, 836, 844, 843, 850, 857, 864, 948, 956, 964, 972, 955, 962, + 630, 637, 1076, 1084, 866, 874 + ], + "dims": [3, 2, 2, 4], + "type": "float32" + } + ] + }, + { + "name": "multiplies 5D with 3D tensors vec4", + "inputs": [ + { + "data": [ + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, + 30, 31 + ], + "dims": [3, 1, 2, 4, 4], + "type": "float32" + }, + { + "data": [1, 2, 1, 3, 2, 3, 1, 2, 1, 2, 3, 4, 5, 6, 7, 8], + "dims": [1, 4, 4], + "type": "float32" + } + ], + "outputs": [ + { + "data": [ + 460, 662, 616, 867, 496, 714, 664, 935, 532, 766, 712, 1003, 568, 818, 760, 1071, 604, 870, 808, 1139, + 640, 922, 856, 1207, 676, 974, 904, 1275, 712, 1026, 952, 1343, 748, 1078, 1000, 1411, 784, 1130, 1048, + 1479, 820, 1182, 1096, 1547, 856, 1234, 1144, 1615, 892, 1286, 1192, 1683, 928, 1338, 1240, 1751, 964, + 1390, 1288, 1819, 1000, 1442, 1336, 1887, 1036, 1494, 1384, 1955, 1072, 1546, 1432, 2023, 1108, 1598, + 1480, 2091, 1144, 1650, 1528, 2159, 1180, 1702, 1576, 2227, 1216, 1754, 1624, 2295, 1252, 1806, 1672, + 2363, 610, 954, 590, 1075 + ], + "dims": [3, 1, 2, 4, 4], + "type": "float32" + } + ] } ] } diff --git a/js/web/test/data/ops/mul.jsonc b/js/web/test/data/ops/mul.jsonc index 99867c87c6baa..bd09efaaa96a3 100644 --- a/js/web/test/data/ops/mul.jsonc +++ b/js/web/test/data/ops/mul.jsonc @@ -79,64 +79,14 @@ "type": "float32" }, { - "data": [ - 2, - 6, - 1, - 2, - 1, - 3, - 1, - 4, - 3, - 5, - 3, - 4, - 1, - 4, - 1, - 6, - 4, - 4, - 5, - 6, - 2, - 4, - 2, - 6 - ], + "data": [2, 6, 1, 2, 1, 3, 1, 4, 3, 5, 3, 4, 1, 4, 1, 6, 4, 4, 5, 6, 2, 4, 2, 6], "dims": [3, 2, 4], "type": "float32" } ], "outputs": [ { - "data": [ - 2, - 12, - 3, - 8, - 5, - 18, - 7, - 32, - 3, - 10, - 9, - 16, - 5, - 24, - 7, - 48, - 4, - 8, - 15, - 24, - 10, - 24, - 14, - 48 - ], + "data": [2, 12, 3, 8, 5, 18, 7, 32, 3, 10, 9, 16, 5, 24, 7, 48, 4, 8, 15, 24, 10, 24, 14, 48], "dims": [3, 2, 4], "type": "float32" } diff --git a/js/web/test/data/ops/neg-int32.jsonc b/js/web/test/data/ops/neg-int32.jsonc new file mode 100644 index 0000000000000..807333db4a96d --- /dev/null +++ b/js/web/test/data/ops/neg-int32.jsonc @@ -0,0 +1,26 @@ +[ + { + "name": "neg with no attributes", + "operator": "Neg", + "attributes": [], + "cases": [ + { + "name": "T[2,4] (int32)", + "inputs": [ + { + "data": [1, 2, -1, -2, 0, 1, -1, 0], + "dims": [2, 4], + "type": "int32" + } + ], + "outputs": [ + { + "data": [-1, -2, 1, 2, 0, -1, 1, 0], + "dims": [2, 4], + "type": "int32" + } + ] + } + ] + } +] diff --git a/js/web/test/data/ops/pad-big.jsonc b/js/web/test/data/ops/pad-big.jsonc index 8c03685de05a3..601e1d58a4377 100644 --- a/js/web/test/data/ops/pad-big.jsonc +++ b/js/web/test/data/ops/pad-big.jsonc @@ -2,6 +2,7 @@ { "name": "constant 2D", "operator": "Pad", + "opset": { "domain": "", "version": 10 }, "attributes": [ { "name": "mode", "data": "reflect", "type": "string" }, { "name": "pads", "data": [0, 0, 1, 1, 0, 0, 1, 1], "type": "ints" } @@ -12,49158 +13,9798 @@ "inputs": [ { "data": [ - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1 + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1 ], "dims": [1, 3, 128, 128], "type": "float32" @@ -49172,50706 +9813,10107 @@ "outputs": [ { "data": [ - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391, - 0.5058823823928833, - 0.501960813999176, - 0.5058823823928833, - 0.5098039507865906, - 0.5137255191802979, - 0.5176470875740051, - 0.5215686559677124, - 0.5254902243614197, - 0.529411792755127, - 0.5333333611488342, - 0.5372549295425415, - 0.5411764979362488, - 0.545098066329956, - 0.5490196347236633, - 0.5529412031173706, - 0.5568627715110779, - 0.5607843399047852, - 0.5647059082984924, - 0.5686274766921997, - 0.572549045085907, - 0.5764706134796143, - 0.5803921818733215, - 0.5843137502670288, - 0.5882353186607361, - 0.5921568870544434, - 0.5960784554481506, - 0.6000000238418579, - 0.6039215922355652, - 0.6078431606292725, - 0.6117647290229797, - 0.615686297416687, - 0.6196078658103943, - 0.6235294342041016, - 0.6274510025978088, - 0.6313725709915161, - 0.6352941393852234, - 0.6392157077789307, - 0.6431372761726379, - 0.6470588445663452, - 0.6509804129600525, - 0.6549019813537598, - 0.658823549747467, - 0.6627451181411743, - 0.6666666865348816, - 0.6705882549285889, - 0.6745098233222961, - 0.6784313917160034, - 0.6823529601097107, - 0.686274528503418, - 0.6901960968971252, - 0.6941176652908325, - 0.6980392336845398, - 0.7019608020782471, - 0.7058823704719543, - 0.7098039388656616, - 0.7137255072593689, - 0.7176470756530762, - 0.7215686440467834, - 0.7254902124404907, - 0.729411780834198, - 0.7333333492279053, - 0.7372549176216125, - 0.7411764860153198, - 0.7450980544090271, - 0.7490196228027344, - 0.7529411911964417, - 0.7568627595901489, - 0.7607843279838562, - 0.7647058963775635, - 0.7686274647712708, - 0.772549033164978, - 0.7764706015586853, - 0.7803921699523926, - 0.7843137383460999, - 0.7882353067398071, - 0.7921568751335144, - 0.7960784435272217, - 0.800000011920929, - 0.8039215803146362, - 0.8078431487083435, - 0.8117647171020508, - 0.8156862854957581, - 0.8196078538894653, - 0.8235294222831726, - 0.8274509906768799, - 0.8313725590705872, - 0.8352941274642944, - 0.8392156958580017, - 0.843137264251709, - 0.8470588326454163, - 0.8509804010391235, - 0.8549019694328308, - 0.8588235378265381, - 0.8627451062202454, - 0.8666666746139526, - 0.8705882430076599, - 0.8745098114013672, - 0.8784313797950745, - 0.8823529481887817, - 0.886274516582489, - 0.8901960849761963, - 0.8941176533699036, - 0.8980392217636108, - 0.9019607901573181, - 0.9058823585510254, - 0.9098039269447327, - 0.9137254953384399, - 0.9176470637321472, - 0.9215686321258545, - 0.9254902005195618, - 0.929411768913269, - 0.9333333373069763, - 0.9372549057006836, - 0.9411764740943909, - 0.9450980424880981, - 0.9490196108818054, - 0.9529411792755127, - 0.95686274766922, - 0.9607843160629272, - 0.9647058844566345, - 0.9686274528503418, - 0.9725490212440491, - 0.9764705896377563, - 0.9803921580314636, - 0.9843137264251709, - 0.9882352948188782, - 0.9921568632125854, - 0.9960784316062927, - 1, - 0.9960784316062927, - 0.003921568859368563, - 0, - 0.003921568859368563, - 0.007843137718737125, - 0.0117647061124444, - 0.01568627543747425, - 0.019607843831181526, - 0.0235294122248888, - 0.027450980618596077, - 0.0313725508749485, - 0.03529411926865578, - 0.03921568766236305, - 0.04313725605607033, - 0.0470588244497776, - 0.05098039284348488, - 0.054901961237192154, - 0.05882352963089943, - 0.062745101749897, - 0.06666667014360428, - 0.07058823853731155, - 0.07450980693101883, - 0.0784313753247261, - 0.08235294371843338, - 0.08627451211214066, - 0.09019608050584793, - 0.0941176488995552, - 0.09803921729326248, - 0.10196078568696976, - 0.10588235408067703, - 0.10980392247438431, - 0.11372549086809158, - 0.11764705926179886, - 0.12156862765550613, - 0.125490203499794, - 0.12941177189350128, - 0.13333334028720856, - 0.13725490868091583, - 0.1411764770746231, - 0.14509804546833038, - 0.14901961386203766, - 0.15294118225574493, - 0.1568627506494522, - 0.16078431904315948, - 0.16470588743686676, - 0.16862745583057404, - 0.1725490242242813, - 0.1764705926179886, - 0.18039216101169586, - 0.18431372940540314, - 0.1882352977991104, - 0.1921568661928177, - 0.19607843458652496, - 0.20000000298023224, - 0.20392157137393951, - 0.2078431397676468, - 0.21176470816135406, - 0.21568627655506134, - 0.21960784494876862, - 0.2235294133424759, - 0.22745098173618317, - 0.23137255012989044, - 0.23529411852359772, - 0.239215686917305, - 0.24313725531101227, - 0.24705882370471954, - 0.250980406999588, - 0.2549019753932953, - 0.25882354378700256, - 0.26274511218070984, - 0.2666666805744171, - 0.2705882489681244, - 0.27450981736183167, - 0.27843138575553894, - 0.2823529541492462, - 0.2862745225429535, - 0.29019609093666077, - 0.29411765933036804, - 0.2980392277240753, - 0.3019607961177826, - 0.30588236451148987, - 0.30980393290519714, - 0.3137255012989044, - 0.3176470696926117, - 0.32156863808631897, - 0.32549020648002625, - 0.3294117748737335, - 0.3333333432674408, - 0.33725491166114807, - 0.34117648005485535, - 0.3450980484485626, - 0.3490196168422699, - 0.3529411852359772, - 0.35686275362968445, - 0.3607843220233917, - 0.364705890417099, - 0.3686274588108063, - 0.37254902720451355, - 0.3764705955982208, - 0.3803921639919281, - 0.3843137323856354, - 0.38823530077934265, - 0.3921568691730499, - 0.3960784375667572, - 0.4000000059604645, - 0.40392157435417175, - 0.40784314274787903, - 0.4117647111415863, - 0.4156862795352936, - 0.41960784792900085, - 0.42352941632270813, - 0.4274509847164154, - 0.4313725531101227, - 0.43529412150382996, - 0.43921568989753723, - 0.4431372582912445, - 0.4470588266849518, - 0.45098039507865906, - 0.45490196347236633, - 0.4588235318660736, - 0.4627451002597809, - 0.46666666865348816, - 0.47058823704719543, - 0.4745098054409027, - 0.47843137383461, - 0.48235294222831726, - 0.48627451062202454, - 0.4901960790157318, - 0.4941176474094391, - 0.49803921580314636, - 0.4941176474094391 + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, + 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, + 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, + 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, + 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, + 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, + 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, + 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, + 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, + 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, + 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, + 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, + 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, + 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, + 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, + 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, + 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, + 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, + 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, + 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, + 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, + 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, + 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, + 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, + 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, + 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, + 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, + 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, + 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, + 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, + 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, + 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, + 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, + 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, + 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, + 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, + 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, + 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, + 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, + 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, + 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, + 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, + 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, + 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, + 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, + 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, + 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, + 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, + 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, + 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, + 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, + 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, + 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, + 0.501960813999176, 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, + 0.5215686559677124, 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, + 0.5411764979362488, 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, + 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, + 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, + 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, + 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, + 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, + 0.658823549747467, 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, + 0.6784313917160034, 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, + 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, + 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, + 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, + 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, + 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, + 0.7960784435272217, 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, + 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, + 0.8352941274642944, 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, + 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, + 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, + 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, + 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, + 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, + 0.9529411792755127, 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, + 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, + 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, + 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, + 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, + 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, + 0.062745101749897, 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, + 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, + 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, + 0.12156862765550613, 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, + 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, + 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, + 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, + 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, + 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, + 0.239215686917305, 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, + 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, + 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, + 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, + 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, + 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, + 0.35686275362968445, 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, + 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, + 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, + 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, + 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, + 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, + 0.4745098054409027, 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, + 0.4941176474094391, 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, + 0.5058823823928833, 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, + 0.5254902243614197, 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, + 0.545098066329956, 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, + 0.5647059082984924, 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, + 0.5843137502670288, 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, + 0.6039215922355652, 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, + 0.6235294342041016, 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, + 0.6431372761726379, 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, + 0.6627451181411743, 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, + 0.6823529601097107, 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, + 0.7019608020782471, 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, + 0.7215686440467834, 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, + 0.7411764860153198, 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, + 0.7607843279838562, 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, + 0.7803921699523926, 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, + 0.800000011920929, 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, + 0.8196078538894653, 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, + 0.8392156958580017, 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, + 0.8588235378265381, 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, + 0.8784313797950745, 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, + 0.8980392217636108, 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, + 0.9176470637321472, 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, + 0.9372549057006836, 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, + 0.95686274766922, 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, + 0.9764705896377563, 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, + 0.9960784316062927, 1, 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, + 0.007843137718737125, 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, + 0.027450980618596077, 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, + 0.0470588244497776, 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, + 0.06666667014360428, 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, + 0.08627451211214066, 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, + 0.10588235408067703, 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, + 0.125490203499794, 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, + 0.14509804546833038, 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, + 0.16470588743686676, 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, + 0.18431372940540314, 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, + 0.20392157137393951, 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, + 0.2235294133424759, 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, + 0.24313725531101227, 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, + 0.26274511218070984, 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, + 0.2823529541492462, 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, + 0.3019607961177826, 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, + 0.32156863808631897, 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, + 0.34117648005485535, 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, + 0.3607843220233917, 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, + 0.3803921639919281, 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, + 0.4000000059604645, 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, + 0.41960784792900085, 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, + 0.43921568989753723, 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, + 0.4588235318660736, 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, + 0.47843137383461, 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, + 0.49803921580314636, 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, + 0.5098039507865906, 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, + 0.529411792755127, 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, + 0.5490196347236633, 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, + 0.5686274766921997, 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, + 0.5882353186607361, 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, + 0.6078431606292725, 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, + 0.6274510025978088, 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, + 0.6470588445663452, 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, + 0.6666666865348816, 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, + 0.686274528503418, 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, + 0.7058823704719543, 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, + 0.7254902124404907, 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, + 0.7450980544090271, 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, + 0.7647058963775635, 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, + 0.7843137383460999, 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, + 0.8039215803146362, 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, + 0.8235294222831726, 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, + 0.843137264251709, 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, + 0.8627451062202454, 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, + 0.8823529481887817, 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, + 0.9019607901573181, 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, + 0.9215686321258545, 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, + 0.9411764740943909, 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, + 0.9607843160629272, 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, + 0.9803921580314636, 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, + 0.9960784316062927, 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, + 0.0117647061124444, 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, + 0.0313725508749485, 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, + 0.05098039284348488, 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, + 0.07058823853731155, 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, + 0.09019608050584793, 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, + 0.10980392247438431, 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, + 0.12941177189350128, 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, + 0.14901961386203766, 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, + 0.16862745583057404, 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, + 0.1882352977991104, 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, + 0.2078431397676468, 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, + 0.22745098173618317, 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, + 0.24705882370471954, 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, + 0.2666666805744171, 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, + 0.2862745225429535, 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, + 0.30588236451148987, 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, + 0.32549020648002625, 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, + 0.3450980484485626, 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, + 0.364705890417099, 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, + 0.3843137323856354, 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, + 0.40392157435417175, 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, + 0.42352941632270813, 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, + 0.4431372582912445, 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, + 0.4627451002597809, 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, + 0.48235294222831726, 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, + 0.4941176474094391, 0.5058823823928833, 0.501960813999176, 0.5058823823928833, 0.5098039507865906, + 0.5137255191802979, 0.5176470875740051, 0.5215686559677124, 0.5254902243614197, 0.529411792755127, + 0.5333333611488342, 0.5372549295425415, 0.5411764979362488, 0.545098066329956, 0.5490196347236633, + 0.5529412031173706, 0.5568627715110779, 0.5607843399047852, 0.5647059082984924, 0.5686274766921997, + 0.572549045085907, 0.5764706134796143, 0.5803921818733215, 0.5843137502670288, 0.5882353186607361, + 0.5921568870544434, 0.5960784554481506, 0.6000000238418579, 0.6039215922355652, 0.6078431606292725, + 0.6117647290229797, 0.615686297416687, 0.6196078658103943, 0.6235294342041016, 0.6274510025978088, + 0.6313725709915161, 0.6352941393852234, 0.6392157077789307, 0.6431372761726379, 0.6470588445663452, + 0.6509804129600525, 0.6549019813537598, 0.658823549747467, 0.6627451181411743, 0.6666666865348816, + 0.6705882549285889, 0.6745098233222961, 0.6784313917160034, 0.6823529601097107, 0.686274528503418, + 0.6901960968971252, 0.6941176652908325, 0.6980392336845398, 0.7019608020782471, 0.7058823704719543, + 0.7098039388656616, 0.7137255072593689, 0.7176470756530762, 0.7215686440467834, 0.7254902124404907, + 0.729411780834198, 0.7333333492279053, 0.7372549176216125, 0.7411764860153198, 0.7450980544090271, + 0.7490196228027344, 0.7529411911964417, 0.7568627595901489, 0.7607843279838562, 0.7647058963775635, + 0.7686274647712708, 0.772549033164978, 0.7764706015586853, 0.7803921699523926, 0.7843137383460999, + 0.7882353067398071, 0.7921568751335144, 0.7960784435272217, 0.800000011920929, 0.8039215803146362, + 0.8078431487083435, 0.8117647171020508, 0.8156862854957581, 0.8196078538894653, 0.8235294222831726, + 0.8274509906768799, 0.8313725590705872, 0.8352941274642944, 0.8392156958580017, 0.843137264251709, + 0.8470588326454163, 0.8509804010391235, 0.8549019694328308, 0.8588235378265381, 0.8627451062202454, + 0.8666666746139526, 0.8705882430076599, 0.8745098114013672, 0.8784313797950745, 0.8823529481887817, + 0.886274516582489, 0.8901960849761963, 0.8941176533699036, 0.8980392217636108, 0.9019607901573181, + 0.9058823585510254, 0.9098039269447327, 0.9137254953384399, 0.9176470637321472, 0.9215686321258545, + 0.9254902005195618, 0.929411768913269, 0.9333333373069763, 0.9372549057006836, 0.9411764740943909, + 0.9450980424880981, 0.9490196108818054, 0.9529411792755127, 0.95686274766922, 0.9607843160629272, + 0.9647058844566345, 0.9686274528503418, 0.9725490212440491, 0.9764705896377563, 0.9803921580314636, + 0.9843137264251709, 0.9882352948188782, 0.9921568632125854, 0.9960784316062927, 1, 0.9960784316062927, + 0.003921568859368563, 0, 0.003921568859368563, 0.007843137718737125, 0.0117647061124444, + 0.01568627543747425, 0.019607843831181526, 0.0235294122248888, 0.027450980618596077, 0.0313725508749485, + 0.03529411926865578, 0.03921568766236305, 0.04313725605607033, 0.0470588244497776, 0.05098039284348488, + 0.054901961237192154, 0.05882352963089943, 0.062745101749897, 0.06666667014360428, 0.07058823853731155, + 0.07450980693101883, 0.0784313753247261, 0.08235294371843338, 0.08627451211214066, 0.09019608050584793, + 0.0941176488995552, 0.09803921729326248, 0.10196078568696976, 0.10588235408067703, 0.10980392247438431, + 0.11372549086809158, 0.11764705926179886, 0.12156862765550613, 0.125490203499794, 0.12941177189350128, + 0.13333334028720856, 0.13725490868091583, 0.1411764770746231, 0.14509804546833038, 0.14901961386203766, + 0.15294118225574493, 0.1568627506494522, 0.16078431904315948, 0.16470588743686676, 0.16862745583057404, + 0.1725490242242813, 0.1764705926179886, 0.18039216101169586, 0.18431372940540314, 0.1882352977991104, + 0.1921568661928177, 0.19607843458652496, 0.20000000298023224, 0.20392157137393951, 0.2078431397676468, + 0.21176470816135406, 0.21568627655506134, 0.21960784494876862, 0.2235294133424759, 0.22745098173618317, + 0.23137255012989044, 0.23529411852359772, 0.239215686917305, 0.24313725531101227, 0.24705882370471954, + 0.250980406999588, 0.2549019753932953, 0.25882354378700256, 0.26274511218070984, 0.2666666805744171, + 0.2705882489681244, 0.27450981736183167, 0.27843138575553894, 0.2823529541492462, 0.2862745225429535, + 0.29019609093666077, 0.29411765933036804, 0.2980392277240753, 0.3019607961177826, 0.30588236451148987, + 0.30980393290519714, 0.3137255012989044, 0.3176470696926117, 0.32156863808631897, 0.32549020648002625, + 0.3294117748737335, 0.3333333432674408, 0.33725491166114807, 0.34117648005485535, 0.3450980484485626, + 0.3490196168422699, 0.3529411852359772, 0.35686275362968445, 0.3607843220233917, 0.364705890417099, + 0.3686274588108063, 0.37254902720451355, 0.3764705955982208, 0.3803921639919281, 0.3843137323856354, + 0.38823530077934265, 0.3921568691730499, 0.3960784375667572, 0.4000000059604645, 0.40392157435417175, + 0.40784314274787903, 0.4117647111415863, 0.4156862795352936, 0.41960784792900085, 0.42352941632270813, + 0.4274509847164154, 0.4313725531101227, 0.43529412150382996, 0.43921568989753723, 0.4431372582912445, + 0.4470588266849518, 0.45098039507865906, 0.45490196347236633, 0.4588235318660736, 0.4627451002597809, + 0.46666666865348816, 0.47058823704719543, 0.4745098054409027, 0.47843137383461, 0.48235294222831726, + 0.48627451062202454, 0.4901960790157318, 0.4941176474094391, 0.49803921580314636, 0.4941176474094391 ], "dims": [1, 3, 130, 130], "type": "float32" diff --git a/js/web/test/data/ops/pad.jsonc b/js/web/test/data/ops/pad.jsonc index 2d0de76516934..62414213b1d1e 100644 --- a/js/web/test/data/ops/pad.jsonc +++ b/js/web/test/data/ops/pad.jsonc @@ -2,6 +2,7 @@ { "name": "constant 2D", "operator": "Pad", + "opset": { "domain": "", "version": 10 }, "attributes": [ { "name": "mode", "data": "constant", "type": "string" }, { "name": "value", "data": 1.2, "type": "float" }, @@ -20,55 +21,9 @@ "outputs": [ { "data": [ - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.0, - 2.0, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 3.0, - 4.0, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2, - 1.2 + 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, + 1.2, 1.2, 1.0, 2.0, 1.2, 1.2, 1.2, 1.2, 1.2, 3.0, 4.0, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, + 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2 ], "dims": [7, 7], "type": "float32" @@ -80,6 +35,7 @@ { "name": "constant 3D", "operator": "Pad", + "opset": { "domain": "", "version": 10 }, "attributes": [ { "name": "mode", "data": "constant", "type": "string" }, { "name": "value", "data": 2.3, "type": "float" }, @@ -90,32 +46,7 @@ "name": "[2,3,4]->[5,8,7]", "inputs": [ { - "data": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8 - ], + "data": [1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8], "dims": [2, 3, 4], "type": "float32" } @@ -123,286 +54,20 @@ "outputs": [ { "data": [ - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 1.0, - 2.0, - 3.0, - 4.0, - 2.3, - 2.3, - 2.3, - 5.0, - 6.0, - 7.0, - 8.0, - 2.3, - 2.3, - 2.3, - 1.0, - 2.0, - 3.0, - 4.0, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 5.0, - 6.0, - 7.0, - 8.0, - 2.3, - 2.3, - 2.3, - 1.0, - 2.0, - 3.0, - 4.0, - 2.3, - 2.3, - 2.3, - 5.0, - 6.0, - 7.0, - 8.0, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3, - 2.3 + 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, + 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, + 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, + 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 1.0, 2.0, 3.0, 4.0, 2.3, 2.3, 2.3, 5.0, 6.0, 7.0, 8.0, 2.3, + 2.3, 2.3, 1.0, 2.0, 3.0, 4.0, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, + 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, + 2.3, 2.3, 5.0, 6.0, 7.0, 8.0, 2.3, 2.3, 2.3, 1.0, 2.0, 3.0, 4.0, 2.3, 2.3, 2.3, 5.0, 6.0, 7.0, 8.0, 2.3, + 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, + 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, + 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, + 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, + 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, + 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, + 2.3, 2.3, 2.3, 2.3, 2.3, 2.3, 2.3 ], "dims": [5, 8, 7], "type": "float32" @@ -414,6 +79,7 @@ { "name": "Reflect 1D", "operator": "Pad", + "opset": { "domain": "", "version": 10 }, "attributes": [ { "name": "mode", "data": "reflect", "type": "string" }, { "name": "pads", "data": [5, 7], "type": "ints" } @@ -430,23 +96,7 @@ ], "outputs": [ { - "data": [ - 2.0, - 1.0, - 2.0, - 3.0, - 2.0, - 1.0, - 2.0, - 3.0, - 2.0, - 1.0, - 2.0, - 3.0, - 2.0, - 1.0, - 2.0 - ], + "data": [2.0, 1.0, 2.0, 3.0, 2.0, 1.0, 2.0, 3.0, 2.0, 1.0, 2.0, 3.0, 2.0, 1.0, 2.0], "dims": [15], "type": "float32" } @@ -457,6 +107,7 @@ { "name": "Reflect 2D", "operator": "Pad", + "opset": { "domain": "", "version": 10 }, "attributes": [ { "name": "mode", "data": "reflect", "type": "string" }, { "name": "pads", "data": [3, 2, 2, 5], "type": "ints" } @@ -474,69 +125,9 @@ "outputs": [ { "data": [ - 3.0, - 4.0, - 3.0, - 4.0, - 3.0, - 4.0, - 3.0, - 4.0, - 3.0, - 1.0, - 2.0, - 1.0, - 2.0, - 1.0, - 2.0, - 1.0, - 2.0, - 1.0, - 3.0, - 4.0, - 3.0, - 4.0, - 3.0, - 4.0, - 3.0, - 4.0, - 3.0, - 1.0, - 2.0, - 1.0, - 2.0, - 1.0, - 2.0, - 1.0, - 2.0, - 1.0, - 3.0, - 4.0, - 3.0, - 4.0, - 3.0, - 4.0, - 3.0, - 4.0, - 3.0, - 1.0, - 2.0, - 1.0, - 2.0, - 1.0, - 2.0, - 1.0, - 2.0, - 1.0, - 3.0, - 4.0, - 3.0, - 4.0, - 3.0, - 4.0, - 3.0, - 4.0, - 3.0 + 3.0, 4.0, 3.0, 4.0, 3.0, 4.0, 3.0, 4.0, 3.0, 1.0, 2.0, 1.0, 2.0, 1.0, 2.0, 1.0, 2.0, 1.0, 3.0, 4.0, 3.0, + 4.0, 3.0, 4.0, 3.0, 4.0, 3.0, 1.0, 2.0, 1.0, 2.0, 1.0, 2.0, 1.0, 2.0, 1.0, 3.0, 4.0, 3.0, 4.0, 3.0, 4.0, + 3.0, 4.0, 3.0, 1.0, 2.0, 1.0, 2.0, 1.0, 2.0, 1.0, 2.0, 1.0, 3.0, 4.0, 3.0, 4.0, 3.0, 4.0, 3.0, 4.0, 3.0 ], "dims": [7, 9], "type": "float32" @@ -548,6 +139,7 @@ { "name": "Reflect 3D", "operator": "Pad", + "opset": { "domain": "", "version": 10 }, "attributes": [ { "name": "mode", "data": "reflect", "type": "string" }, { "name": "pads", "data": [1, 2, 2, 2, 3, 1], "type": "ints" } @@ -557,32 +149,7 @@ "name": "[2,3,4]->[5, 8, 7]", "inputs": [ { - "data": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8 - ], + "data": [1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8], "dims": [2, 3, 4], "type": "float32" } @@ -590,286 +157,20 @@ "outputs": [ { "data": [ - 7.0, - 6.0, - 5.0, - 6.0, - 7.0, - 8.0, - 7.0, - 3.0, - 2.0, - 1.0, - 2.0, - 3.0, - 4.0, - 3.0, - 7.0, - 6.0, - 5.0, - 6.0, - 7.0, - 8.0, - 7.0, - 3.0, - 2.0, - 1.0, - 2.0, - 3.0, - 4.0, - 3.0, - 7.0, - 6.0, - 5.0, - 6.0, - 7.0, - 8.0, - 7.0, - 3.0, - 2.0, - 1.0, - 2.0, - 3.0, - 4.0, - 3.0, - 7.0, - 6.0, - 5.0, - 6.0, - 7.0, - 8.0, - 7.0, - 3.0, - 2.0, - 1.0, - 2.0, - 3.0, - 4.0, - 3.0, - 3.0, - 2.0, - 1.0, - 2.0, - 3.0, - 4.0, - 3.0, - 7.0, - 6.0, - 5.0, - 6.0, - 7.0, - 8.0, - 7.0, - 3.0, - 2.0, - 1.0, - 2.0, - 3.0, - 4.0, - 3.0, - 7.0, - 6.0, - 5.0, - 6.0, - 7.0, - 8.0, - 7.0, - 3.0, - 2.0, - 1.0, - 2.0, - 3.0, - 4.0, - 3.0, - 7.0, - 6.0, - 5.0, - 6.0, - 7.0, - 8.0, - 7.0, - 3.0, - 2.0, - 1.0, - 2.0, - 3.0, - 4.0, - 3.0, - 7.0, - 6.0, - 5.0, - 6.0, - 7.0, - 8.0, - 7.0, - 7.0, - 6.0, - 5.0, - 6.0, - 7.0, - 8.0, - 7.0, - 3.0, - 2.0, - 1.0, - 2.0, - 3.0, - 4.0, - 3.0, - 7.0, - 6.0, - 5.0, - 6.0, - 7.0, - 8.0, - 7.0, - 3.0, - 2.0, - 1.0, - 2.0, - 3.0, - 4.0, - 3.0, - 7.0, - 6.0, - 5.0, - 6.0, - 7.0, - 8.0, - 7.0, - 3.0, - 2.0, - 1.0, - 2.0, - 3.0, - 4.0, - 3.0, - 7.0, - 6.0, - 5.0, - 6.0, - 7.0, - 8.0, - 7.0, - 3.0, - 2.0, - 1.0, - 2.0, - 3.0, - 4.0, - 3.0, - 3.0, - 2.0, - 1.0, - 2.0, - 3.0, - 4.0, - 3.0, - 7.0, - 6.0, - 5.0, - 6.0, - 7.0, - 8.0, - 7.0, - 3.0, - 2.0, - 1.0, - 2.0, - 3.0, - 4.0, - 3.0, - 7.0, - 6.0, - 5.0, - 6.0, - 7.0, - 8.0, - 7.0, - 3.0, - 2.0, - 1.0, - 2.0, - 3.0, - 4.0, - 3.0, - 7.0, - 6.0, - 5.0, - 6.0, - 7.0, - 8.0, - 7.0, - 3.0, - 2.0, - 1.0, - 2.0, - 3.0, - 4.0, - 3.0, - 7.0, - 6.0, - 5.0, - 6.0, - 7.0, - 8.0, - 7.0, - 7.0, - 6.0, - 5.0, - 6.0, - 7.0, - 8.0, - 7.0, - 3.0, - 2.0, - 1.0, - 2.0, - 3.0, - 4.0, - 3.0, - 7.0, - 6.0, - 5.0, - 6.0, - 7.0, - 8.0, - 7.0, - 3.0, - 2.0, - 1.0, - 2.0, - 3.0, - 4.0, - 3.0, - 7.0, - 6.0, - 5.0, - 6.0, - 7.0, - 8.0, - 7.0, - 3.0, - 2.0, - 1.0, - 2.0, - 3.0, - 4.0, - 3.0, - 7.0, - 6.0, - 5.0, - 6.0, - 7.0, - 8.0, - 7.0, - 3.0, - 2.0, - 1.0, - 2.0, - 3.0, - 4.0, - 3.0 + 7.0, 6.0, 5.0, 6.0, 7.0, 8.0, 7.0, 3.0, 2.0, 1.0, 2.0, 3.0, 4.0, 3.0, 7.0, 6.0, 5.0, 6.0, 7.0, 8.0, 7.0, + 3.0, 2.0, 1.0, 2.0, 3.0, 4.0, 3.0, 7.0, 6.0, 5.0, 6.0, 7.0, 8.0, 7.0, 3.0, 2.0, 1.0, 2.0, 3.0, 4.0, 3.0, + 7.0, 6.0, 5.0, 6.0, 7.0, 8.0, 7.0, 3.0, 2.0, 1.0, 2.0, 3.0, 4.0, 3.0, 3.0, 2.0, 1.0, 2.0, 3.0, 4.0, 3.0, + 7.0, 6.0, 5.0, 6.0, 7.0, 8.0, 7.0, 3.0, 2.0, 1.0, 2.0, 3.0, 4.0, 3.0, 7.0, 6.0, 5.0, 6.0, 7.0, 8.0, 7.0, + 3.0, 2.0, 1.0, 2.0, 3.0, 4.0, 3.0, 7.0, 6.0, 5.0, 6.0, 7.0, 8.0, 7.0, 3.0, 2.0, 1.0, 2.0, 3.0, 4.0, 3.0, + 7.0, 6.0, 5.0, 6.0, 7.0, 8.0, 7.0, 7.0, 6.0, 5.0, 6.0, 7.0, 8.0, 7.0, 3.0, 2.0, 1.0, 2.0, 3.0, 4.0, 3.0, + 7.0, 6.0, 5.0, 6.0, 7.0, 8.0, 7.0, 3.0, 2.0, 1.0, 2.0, 3.0, 4.0, 3.0, 7.0, 6.0, 5.0, 6.0, 7.0, 8.0, 7.0, + 3.0, 2.0, 1.0, 2.0, 3.0, 4.0, 3.0, 7.0, 6.0, 5.0, 6.0, 7.0, 8.0, 7.0, 3.0, 2.0, 1.0, 2.0, 3.0, 4.0, 3.0, + 3.0, 2.0, 1.0, 2.0, 3.0, 4.0, 3.0, 7.0, 6.0, 5.0, 6.0, 7.0, 8.0, 7.0, 3.0, 2.0, 1.0, 2.0, 3.0, 4.0, 3.0, + 7.0, 6.0, 5.0, 6.0, 7.0, 8.0, 7.0, 3.0, 2.0, 1.0, 2.0, 3.0, 4.0, 3.0, 7.0, 6.0, 5.0, 6.0, 7.0, 8.0, 7.0, + 3.0, 2.0, 1.0, 2.0, 3.0, 4.0, 3.0, 7.0, 6.0, 5.0, 6.0, 7.0, 8.0, 7.0, 7.0, 6.0, 5.0, 6.0, 7.0, 8.0, 7.0, + 3.0, 2.0, 1.0, 2.0, 3.0, 4.0, 3.0, 7.0, 6.0, 5.0, 6.0, 7.0, 8.0, 7.0, 3.0, 2.0, 1.0, 2.0, 3.0, 4.0, 3.0, + 7.0, 6.0, 5.0, 6.0, 7.0, 8.0, 7.0, 3.0, 2.0, 1.0, 2.0, 3.0, 4.0, 3.0, 7.0, 6.0, 5.0, 6.0, 7.0, 8.0, 7.0, + 3.0, 2.0, 1.0, 2.0, 3.0, 4.0, 3.0 ], "dims": [5, 8, 7], "type": "float32" @@ -881,6 +182,7 @@ { "name": "Edge 2D", "operator": "Pad", + "opset": { "domain": "", "version": 10 }, "attributes": [ { "name": "mode", "data": "edge", "type": "string" }, { "name": "pads", "data": [3, 2, 2, 3], "type": "ints" } @@ -898,55 +200,9 @@ "outputs": [ { "data": [ - 1.0, - 1.0, - 1.0, - 2.0, - 2.0, - 2.0, - 2.0, - 1.0, - 1.0, - 1.0, - 2.0, - 2.0, - 2.0, - 2.0, - 1.0, - 1.0, - 1.0, - 2.0, - 2.0, - 2.0, - 2.0, - 1.0, - 1.0, - 1.0, - 2.0, - 2.0, - 2.0, - 2.0, - 3.0, - 3.0, - 3.0, - 4.0, - 4.0, - 4.0, - 4.0, - 3.0, - 3.0, - 3.0, - 4.0, - 4.0, - 4.0, - 4.0, - 3.0, - 3.0, - 3.0, - 4.0, - 4.0, - 4.0, - 4.0 + 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, + 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, 4.0, 4.0, 4.0, 4.0, 3.0, 3.0, 3.0, 4.0, 4.0, 4.0, 4.0, + 3.0, 3.0, 3.0, 4.0, 4.0, 4.0, 4.0 ], "dims": [7, 7], "type": "float32" @@ -958,6 +214,7 @@ { "name": "Edge 3D", "operator": "Pad", + "opset": { "domain": "", "version": 10 }, "attributes": [ { "name": "mode", "data": "edge", "type": "string" }, { "name": "pads", "data": [1, 2, 2, 2, 3, 1], "type": "ints" } @@ -967,32 +224,7 @@ "name": "[2,3,4]->[5, 8, 7]", "inputs": [ { - "data": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8 - ], + "data": [1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8], "dims": [2, 3, 4], "type": "float32" } @@ -1000,286 +232,20 @@ "outputs": [ { "data": [ - 1.0, - 1.0, - 1.0, - 2.0, - 3.0, - 4.0, - 4.0, - 1.0, - 1.0, - 1.0, - 2.0, - 3.0, - 4.0, - 4.0, - 1.0, - 1.0, - 1.0, - 2.0, - 3.0, - 4.0, - 4.0, - 5.0, - 5.0, - 5.0, - 6.0, - 7.0, - 8.0, - 8.0, - 1.0, - 1.0, - 1.0, - 2.0, - 3.0, - 4.0, - 4.0, - 1.0, - 1.0, - 1.0, - 2.0, - 3.0, - 4.0, - 4.0, - 1.0, - 1.0, - 1.0, - 2.0, - 3.0, - 4.0, - 4.0, - 1.0, - 1.0, - 1.0, - 2.0, - 3.0, - 4.0, - 4.0, - 1.0, - 1.0, - 1.0, - 2.0, - 3.0, - 4.0, - 4.0, - 1.0, - 1.0, - 1.0, - 2.0, - 3.0, - 4.0, - 4.0, - 1.0, - 1.0, - 1.0, - 2.0, - 3.0, - 4.0, - 4.0, - 5.0, - 5.0, - 5.0, - 6.0, - 7.0, - 8.0, - 8.0, - 1.0, - 1.0, - 1.0, - 2.0, - 3.0, - 4.0, - 4.0, - 1.0, - 1.0, - 1.0, - 2.0, - 3.0, - 4.0, - 4.0, - 1.0, - 1.0, - 1.0, - 2.0, - 3.0, - 4.0, - 4.0, - 1.0, - 1.0, - 1.0, - 2.0, - 3.0, - 4.0, - 4.0, - 5.0, - 5.0, - 5.0, - 6.0, - 7.0, - 8.0, - 8.0, - 5.0, - 5.0, - 5.0, - 6.0, - 7.0, - 8.0, - 8.0, - 5.0, - 5.0, - 5.0, - 6.0, - 7.0, - 8.0, - 8.0, - 1.0, - 1.0, - 1.0, - 2.0, - 3.0, - 4.0, - 4.0, - 5.0, - 5.0, - 5.0, - 6.0, - 7.0, - 8.0, - 8.0, - 5.0, - 5.0, - 5.0, - 6.0, - 7.0, - 8.0, - 8.0, - 5.0, - 5.0, - 5.0, - 6.0, - 7.0, - 8.0, - 8.0, - 5.0, - 5.0, - 5.0, - 6.0, - 7.0, - 8.0, - 8.0, - 5.0, - 5.0, - 5.0, - 6.0, - 7.0, - 8.0, - 8.0, - 5.0, - 5.0, - 5.0, - 6.0, - 7.0, - 8.0, - 8.0, - 5.0, - 5.0, - 5.0, - 6.0, - 7.0, - 8.0, - 8.0, - 1.0, - 1.0, - 1.0, - 2.0, - 3.0, - 4.0, - 4.0, - 5.0, - 5.0, - 5.0, - 6.0, - 7.0, - 8.0, - 8.0, - 5.0, - 5.0, - 5.0, - 6.0, - 7.0, - 8.0, - 8.0, - 5.0, - 5.0, - 5.0, - 6.0, - 7.0, - 8.0, - 8.0, - 5.0, - 5.0, - 5.0, - 6.0, - 7.0, - 8.0, - 8.0, - 5.0, - 5.0, - 5.0, - 6.0, - 7.0, - 8.0, - 8.0, - 5.0, - 5.0, - 5.0, - 6.0, - 7.0, - 8.0, - 8.0, - 5.0, - 5.0, - 5.0, - 6.0, - 7.0, - 8.0, - 8.0, - 1.0, - 1.0, - 1.0, - 2.0, - 3.0, - 4.0, - 4.0, - 5.0, - 5.0, - 5.0, - 6.0, - 7.0, - 8.0, - 8.0, - 5.0, - 5.0, - 5.0, - 6.0, - 7.0, - 8.0, - 8.0, - 5.0, - 5.0, - 5.0, - 6.0, - 7.0, - 8.0, - 8.0, - 5.0, - 5.0, - 5.0, - 6.0, - 7.0, - 8.0, - 8.0 + 1.0, 1.0, 1.0, 2.0, 3.0, 4.0, 4.0, 1.0, 1.0, 1.0, 2.0, 3.0, 4.0, 4.0, 1.0, 1.0, 1.0, 2.0, 3.0, 4.0, 4.0, + 5.0, 5.0, 5.0, 6.0, 7.0, 8.0, 8.0, 1.0, 1.0, 1.0, 2.0, 3.0, 4.0, 4.0, 1.0, 1.0, 1.0, 2.0, 3.0, 4.0, 4.0, + 1.0, 1.0, 1.0, 2.0, 3.0, 4.0, 4.0, 1.0, 1.0, 1.0, 2.0, 3.0, 4.0, 4.0, 1.0, 1.0, 1.0, 2.0, 3.0, 4.0, 4.0, + 1.0, 1.0, 1.0, 2.0, 3.0, 4.0, 4.0, 1.0, 1.0, 1.0, 2.0, 3.0, 4.0, 4.0, 5.0, 5.0, 5.0, 6.0, 7.0, 8.0, 8.0, + 1.0, 1.0, 1.0, 2.0, 3.0, 4.0, 4.0, 1.0, 1.0, 1.0, 2.0, 3.0, 4.0, 4.0, 1.0, 1.0, 1.0, 2.0, 3.0, 4.0, 4.0, + 1.0, 1.0, 1.0, 2.0, 3.0, 4.0, 4.0, 5.0, 5.0, 5.0, 6.0, 7.0, 8.0, 8.0, 5.0, 5.0, 5.0, 6.0, 7.0, 8.0, 8.0, + 5.0, 5.0, 5.0, 6.0, 7.0, 8.0, 8.0, 1.0, 1.0, 1.0, 2.0, 3.0, 4.0, 4.0, 5.0, 5.0, 5.0, 6.0, 7.0, 8.0, 8.0, + 5.0, 5.0, 5.0, 6.0, 7.0, 8.0, 8.0, 5.0, 5.0, 5.0, 6.0, 7.0, 8.0, 8.0, 5.0, 5.0, 5.0, 6.0, 7.0, 8.0, 8.0, + 5.0, 5.0, 5.0, 6.0, 7.0, 8.0, 8.0, 5.0, 5.0, 5.0, 6.0, 7.0, 8.0, 8.0, 5.0, 5.0, 5.0, 6.0, 7.0, 8.0, 8.0, + 1.0, 1.0, 1.0, 2.0, 3.0, 4.0, 4.0, 5.0, 5.0, 5.0, 6.0, 7.0, 8.0, 8.0, 5.0, 5.0, 5.0, 6.0, 7.0, 8.0, 8.0, + 5.0, 5.0, 5.0, 6.0, 7.0, 8.0, 8.0, 5.0, 5.0, 5.0, 6.0, 7.0, 8.0, 8.0, 5.0, 5.0, 5.0, 6.0, 7.0, 8.0, 8.0, + 5.0, 5.0, 5.0, 6.0, 7.0, 8.0, 8.0, 5.0, 5.0, 5.0, 6.0, 7.0, 8.0, 8.0, 1.0, 1.0, 1.0, 2.0, 3.0, 4.0, 4.0, + 5.0, 5.0, 5.0, 6.0, 7.0, 8.0, 8.0, 5.0, 5.0, 5.0, 6.0, 7.0, 8.0, 8.0, 5.0, 5.0, 5.0, 6.0, 7.0, 8.0, 8.0, + 5.0, 5.0, 5.0, 6.0, 7.0, 8.0, 8.0 ], "dims": [5, 8, 7], "type": "float32" diff --git a/js/web/test/data/ops/pow-big-number.jsonc b/js/web/test/data/ops/pow-big-number.jsonc index e28c08c057189..17693fa2d4a9c 100644 --- a/js/web/test/data/ops/pow-big-number.jsonc +++ b/js/web/test/data/ops/pow-big-number.jsonc @@ -3,7 +3,7 @@ "name": "Pow with no attributes - big number", "operator": "Pow", "attributes": [], - "condition": "^((?!iOS).)*$", // does NOT contains 'iOS': large number cannot be handled in a half_float environment + "platformCondition": "^((?!iOS).)*$", // does NOT contains 'iOS': large number cannot be handled in a half_float environment "cases": [ { "name": "T[2,4] T[3,2,4]", @@ -14,32 +14,7 @@ "type": "float32" }, { - "data": [ - 2, - 6, - 1, - 2, - 1, - 3, - 1, - 4, - 3, - 5, - 3, - 4, - 1, - 4, - 1, - 6, - 4, - 4, - 5, - 6, - 2, - 4, - 2, - 6 - ], + "data": [2, 6, 1, 2, 1, 3, 1, 4, 3, 5, 3, 4, 1, 4, 1, 6, 4, 4, 5, 6, 2, 4, 2, 6], "dims": [3, 2, 4], "type": "float32" } @@ -47,30 +22,7 @@ "outputs": [ { "data": [ - 1, - 64, - 3, - 16, - 5, - 216, - 7, - 4096, - 1, - 32, - 27, - 256, - 5, - 1296, - 7, - 262144, - 1, - 16, - 243, - 4096, - 25, - 1296, - 49, - 262144 + 1, 64, 3, 16, 5, 216, 7, 4096, 1, 32, 27, 256, 5, 1296, 7, 262144, 1, 16, 243, 4096, 25, 1296, 49, 262144 ], "dims": [3, 2, 4], "type": "float32" diff --git a/js/web/test/data/ops/pow_int32.jsonc b/js/web/test/data/ops/pow_int32.jsonc new file mode 100644 index 0000000000000..5364561584b04 --- /dev/null +++ b/js/web/test/data/ops/pow_int32.jsonc @@ -0,0 +1,31 @@ +[ + { + "name": "Pow with no attributes", + "operator": "Pow", + "attributes": [], + "cases": [ + { + "name": "T[2,4] T[2,4] (int32)", + "inputs": [ + { + "data": [1, 2, 1, 8, 2, 12, 9, 2], + "dims": [2, 4], + "type": "int32" + }, + { + "data": [2, 1, 1, 2, 2, 3, 1, 4], + "dims": [2, 4], + "type": "int32" + } + ], + "outputs": [ + { + "data": [1, 2, 1, 64, 4, 1728, 9, 16], + "dims": [2, 4], + "type": "int32" + } + ] + } + ] + } +] diff --git a/js/web/test/data/ops/reshape-int32.jsonc b/js/web/test/data/ops/reshape-int32.jsonc new file mode 100644 index 0000000000000..3b7b115419d64 --- /dev/null +++ b/js/web/test/data/ops/reshape-int32.jsonc @@ -0,0 +1,97 @@ +[ + { + "name": "Reshape with '0' and '-1' in the shape tensor input", + "operator": "Reshape", + "attributes": [], + "cases": [ + { + "name": "T[0]", + "inputs": [ + { + "data": [1, 1, 1, 1], + "dims": [2, 2], + "type": "float32" + }, + { + "data": [-1, 0], + "dims": [2], + "type": "int32" + } + ], + "outputs": [ + { + "data": [1, 1, 1, 1], + "dims": [2, 2], + "type": "float32" + } + ] + }, + { + "name": "Scalar to 1D", + "inputs": [ + { + "data": [1], + "dims": [], + "type": "float32" + }, + { + "data": [1], + "dims": [1], + "type": "int32" + } + ], + "outputs": [ + { + "data": [1], + "dims": [1], + "type": "float32" + } + ] + }, + { + "name": "Scalar to 2D", + "inputs": [ + { + "data": [1], + "dims": [], + "type": "float32" + }, + { + "data": [1, 1], + "dims": [2], + "type": "int32" + } + ], + "outputs": [ + { + "data": [1], + "dims": [1, 1], + "type": "float32" + } + ] + }, + { + "name": "Scalar to 2D with -1 in shape hints", + "inputs": [ + { + "data": [1], + "dims": [], + "type": "float32" + }, + { + "data": [-1, 1], + "dims": [2], + "type": "int32" + } + ], + "outputs": [ + { + "data": [1], + "dims": [1, 1], + "type": "float32" + } + ] + } + ] + } +] diff --git a/js/web/test/data/ops/reshape.jsonc b/js/web/test/data/ops/reshape.jsonc index 3b7b115419d64..7f16d2691436e 100644 --- a/js/web/test/data/ops/reshape.jsonc +++ b/js/web/test/data/ops/reshape.jsonc @@ -1,6 +1,6 @@ [ { - "name": "Reshape with '0' and '-1' in the shape tensor input", + "name": "Reshape float32 with '0' and '-1' in the shape tensor input", "operator": "Reshape", "attributes": [], "cases": [ @@ -15,7 +15,7 @@ { "data": [-1, 0], "dims": [2], - "type": "int32" + "type": "int64" } ], "outputs": [ @@ -37,7 +37,7 @@ { "data": [1], "dims": [1], - "type": "int32" + "type": "int64" } ], "outputs": [ @@ -59,7 +59,7 @@ { "data": [1, 1], "dims": [2], - "type": "int32" + "type": "int64" } ], "outputs": [ @@ -81,7 +81,7 @@ { "data": [-1, 1], "dims": [2], - "type": "int32" + "type": "int64" } ], "outputs": [ @@ -93,5 +93,100 @@ ] } ] + }, + { + "name": "Reshape int32 with '0' and '-1' in the shape tensor input", + "operator": "Reshape", + "attributes": [], + "cases": [ + { + "name": "T[0]", + "inputs": [ + { + "data": [1, 1, 1, 1], + "dims": [2, 2], + "type": "int32" + }, + { + "data": [-1, 0], + "dims": [2], + "type": "int64" + } + ], + "outputs": [ + { + "data": [1, 1, 1, 1], + "dims": [2, 2], + "type": "int32" + } + ] + }, + { + "name": "Scalar to 1D", + "inputs": [ + { + "data": [1], + "dims": [], + "type": "int32" + }, + { + "data": [1], + "dims": [1], + "type": "int64" + } + ], + "outputs": [ + { + "data": [1], + "dims": [1], + "type": "int32" + } + ] + }, + { + "name": "Scalar to 2D", + "inputs": [ + { + "data": [1], + "dims": [], + "type": "int32" + }, + { + "data": [1, 1], + "dims": [2], + "type": "int64" + } + ], + "outputs": [ + { + "data": [1], + "dims": [1, 1], + "type": "int32" + } + ] + }, + { + "name": "Scalar to 2D with -1 in shape hints", + "inputs": [ + { + "data": [1], + "dims": [], + "type": "int32" + }, + { + "data": [-1, 1], + "dims": [2], + "type": "int64" + } + ], + "outputs": [ + { + "data": [1], + "dims": [1, 1], + "type": "int32" + } + ] + } + ] } ] diff --git a/js/web/test/data/ops/resize-pack.jsonc b/js/web/test/data/ops/resize-pack.jsonc index 24f7c38c56f1e..7b9a2ef96d0bc 100644 --- a/js/web/test/data/ops/resize-pack.jsonc +++ b/js/web/test/data/ops/resize-pack.jsonc @@ -2,12 +2,7 @@ { "name": "ResizeBilinearPacked with mode half_pixel", "operator": "Resize", - "opsets": [ - { - "domain": "", - "version": "11" - } - ], + "opset": { "domain": "", "version": 11 }, "attributes": [ // { "name": "scales", "data": [1.0, 1.0, 2.0, 3.0], "type": "floats" }, { @@ -43,24 +38,7 @@ ], "outputs": [ { - "data": [ - 1, - 1.25, - 1.75, - 2, - 1.5, - 1.75, - 2.25, - 2.5, - 2.5, - 2.75, - 3.25, - 3.5, - 3, - 3.25, - 3.75, - 4 - ], + "data": [1, 1.25, 1.75, 2, 1.5, 1.75, 2.25, 2.5, 2.5, 2.75, 3.25, 3.5, 3, 3.25, 3.75, 4], "dims": [1, 1, 4, 4], "type": "float32" } @@ -71,12 +49,7 @@ { "name": "ResizeBilinearPacked with mode align_corners", "operator": "Resize", - "opsets": [ - { - "domain": "", - "version": "11" - } - ], + "opset": { "domain": "", "version": 11 }, "attributes": [ { "name": "coordinate_transformation_mode", @@ -111,24 +84,7 @@ ], "outputs": [ { - "data": [ - 1, - 1.3333, - 1.6666, - 2, - 1.6666, - 2, - 2.3333, - 2.6666, - 2.3333, - 2.6666, - 3, - 3.3333, - 3, - 3.3333, - 3.6666, - 4 - ], + "data": [1, 1.3333, 1.6666, 2, 1.6666, 2, 2.3333, 2.6666, 2.3333, 2.6666, 3, 3.3333, 3, 3.3333, 3.6666, 4], "dims": [1, 1, 4, 4], "type": "float32" } @@ -139,12 +95,7 @@ { "name": "ResizeBilinearPacked with asymmetric", "operator": "Resize", - "opsets": [ - { - "domain": "", - "version": "11" - } - ], + "opset": { "domain": "", "version": 11 }, "attributes": [ { "name": "coordinate_transformation_mode", @@ -179,24 +130,7 @@ ], "outputs": [ { - "data": [ - 1.0, - 1.5, - 2.0, - 2.0, - 2.0, - 2.5, - 3.0, - 3.0, - 3.0, - 3.5, - 4.0, - 4.0, - 3.0, - 3.5, - 4.0, - 4.0 - ], + "data": [1.0, 1.5, 2.0, 2.0, 2.0, 2.5, 3.0, 3.0, 3.0, 3.5, 4.0, 4.0, 3.0, 3.5, 4.0, 4.0], "dims": [1, 1, 4, 4], "type": "float32" } @@ -228,24 +162,7 @@ ], "outputs": [ { - "data": [ - 1.0, - 1.5, - 2.0, - 2.0, - 2.0, - 2.5, - 3.0, - 3.0, - 3.0, - 3.5, - 4.0, - 4.0, - 3.0, - 3.5, - 4.0, - 4.0 - ], + "data": [1.0, 1.5, 2.0, 2.0, 2.0, 2.5, 3.0, 3.0, 3.0, 3.5, 4.0, 4.0, 3.0, 3.5, 4.0, 4.0], "dims": [1, 1, 4, 4], "type": "float32" } @@ -273,78 +190,10 @@ "outputs": [ { "data": [ - 1.0, - 1.5, - 2.0, - 2.5, - 3.0, - 3.0, - 2.0, - 2.5, - 3.0, - 3.5, - 4.0, - 4, - 3.0, - 3.5, - 4.0, - 4.5, - 5.0, - 5.0, - 4.0, - 4.5, - 5.0, - 5.5, - 6.0, - 6.0, - 5.0, - 5.5, - 6.0, - 6.5, - 7.0, - 7.0, - 6.0, - 6.5, - 7.0, - 7.5, - 8.0, - 8.0, - 7.0, - 7.5, - 8.0, - 8.5, - 9.0, - 9.0, - 8.0, - 8.5, - 9.0, - 9.5, - 10.0, - 10.0, - 9.0, - 9.5, - 10.0, - 10.5, - 11.0, - 11.0, - 10.0, - 10.5, - 11.0, - 11.5, - 12.0, - 12.0, - 10.0, - 10.5, - 11.0, - 11.5, - 12.0, - 12.0, - 10.0, - 10.5, - 11.0, - 11.5, - 12.0, - 12.0 + 1.0, 1.5, 2.0, 2.5, 3.0, 3.0, 2.0, 2.5, 3.0, 3.5, 4.0, 4, 3.0, 3.5, 4.0, 4.5, 5.0, 5.0, 4.0, 4.5, 5.0, + 5.5, 6.0, 6.0, 5.0, 5.5, 6.0, 6.5, 7.0, 7.0, 6.0, 6.5, 7.0, 7.5, 8.0, 8.0, 7.0, 7.5, 8.0, 8.5, 9.0, 9.0, + 8.0, 8.5, 9.0, 9.5, 10.0, 10.0, 9.0, 9.5, 10.0, 10.5, 11.0, 11.0, 10.0, 10.5, 11.0, 11.5, 12.0, 12.0, + 10.0, 10.5, 11.0, 11.5, 12.0, 12.0, 10.0, 10.5, 11.0, 11.5, 12.0, 12.0 ], "dims": [1, 1, 12, 6], "type": "float32" @@ -373,54 +222,9 @@ "outputs": [ { "data": [ - 1.0, - 1.5, - 2.0, - 2.0, - 2.0, - 2.5, - 3.0, - 3.0, - 3.0, - 3.5, - 4.0, - 4.0, - 4.0, - 4.5, - 5.0, - 5.0, - 5.0, - 5.5, - 6.0, - 6.0, - 5.0, - 5.5, - 6.0, - 6.0, - 7.0, - 7.5, - 8.0, - 8.0, - 8.0, - 8.5, - 9.0, - 9.0, - 9.0, - 9.5, - 10.0, - 10.0, - 10.0, - 10.5, - 11.0, - 11.0, - 11.0, - 11.5, - 12.0, - 12.0, - 11.0, - 11.5, - 12.0, - 12.0 + 1.0, 1.5, 2.0, 2.0, 2.0, 2.5, 3.0, 3.0, 3.0, 3.5, 4.0, 4.0, 4.0, 4.5, 5.0, 5.0, 5.0, 5.5, 6.0, 6.0, 5.0, + 5.5, 6.0, 6.0, 7.0, 7.5, 8.0, 8.0, 8.0, 8.5, 9.0, 9.0, 9.0, 9.5, 10.0, 10.0, 10.0, 10.5, 11.0, 11.0, 11.0, + 11.5, 12.0, 12.0, 11.0, 11.5, 12.0, 12.0 ], "dims": [1, 2, 6, 4], "type": "float32" diff --git a/js/web/test/data/ops/sin.jsonc b/js/web/test/data/ops/sin.jsonc index 074afa51e349c..5849e93ee5e13 100644 --- a/js/web/test/data/ops/sin.jsonc +++ b/js/web/test/data/ops/sin.jsonc @@ -49,16 +49,7 @@ ], "outputs": [ { - "data": [ - 0.0998, - 0.1987, - 0.2955, - 0.3894, - 0.7833, - 0.7173, - 0.6442, - 0.5646 - ], + "data": [0.0998, 0.1987, 0.2955, 0.3894, 0.7833, 0.7173, 0.6442, 0.5646], "dims": [2, 4], "type": "float32" } diff --git a/js/web/test/data/ops/skip-layer-norm.jsonc b/js/web/test/data/ops/skip-layer-norm.jsonc new file mode 100644 index 0000000000000..b7406ea303f55 --- /dev/null +++ b/js/web/test/data/ops/skip-layer-norm.jsonc @@ -0,0 +1,122 @@ +[ + { + "name": "SkipLayerNormalization", + "operator": "SkipLayerNormalization", + "opset": { "domain": "com.microsoft", "version": 1 }, + "attributes": [ + { + "name": "epsilon", + "data": 1e-5, + "type": "float" + } + ], + "inputShapeDefinitions": [[1, 2, 4], [1, 2, 4], [4], [4], [4]], + "cases": [ + { + "name": "default", + "inputs": [ + { + "data": [1, 2, 3, 4, 5, 6, 7, 8], + "dims": [1, 2, 4], + "type": "float32" + }, + { + "data": [1, 1, 1, 1, 1, 1, 1, 1], + "dims": [1, 2, 4], + "type": "float32" + }, + { + "data": [1, 1, 1, 1], + "dims": [4], + "type": "float32" + }, + { + "data": [1, 1, 1, 1], + "dims": [4], + "type": "float32" + }, + { + "data": [1, 1, 1, 1], + "dims": [4], + "type": "float32" + } + ], + "outputs": [ + { + "data": [ + -0.34163546562194824, 0.5527881383895874, 1.4472118616104126, 2.3416354656219482, -0.34163546562194824, + 0.5527881383895874, 1.4472118616104126, 2.3416354656219482 + ], + "dims": [1, 2, 4], + "type": "float32" + }, + { + "data": null, + "type": "float32" + }, + { + "data": null, + "type": "float32" + }, + { + "data": null, + "type": "float32" + } + ] + }, + { + "name": "default", + "inputs": [ + { + "data": [1, 2, 3, 4, 5, 6, 7, 8], + "dims": [1, 2, 4], + "type": "float32" + }, + { + "data": [1, 1, 1, 1, 1, 1, 1, 1], + "dims": [1, 2, 4], + "type": "float32" + }, + { + "data": [1, 1, 1, 1], + "dims": [4], + "type": "float32" + }, + { + "data": [1, 1, 1, 1], + "dims": [4], + "type": "float32" + }, + { + "data": [1, 1, 1, 1], + "dims": [4], + "type": "float32" + } + ], + "outputs": [ + { + "data": [ + -0.34163546562194824, 0.5527881383895874, 1.4472118616104126, 2.3416354656219482, -0.34163546562194824, + 0.5527881383895874, 1.4472118616104126, 2.3416354656219482 + ], + "dims": [1, 2, 4], + "type": "float32" + }, + { + "data": null, + "type": "float32" + }, + { + "data": null, + "type": "float32" + }, + { + "data": [3, 4, 5, 6, 7, 8, 9, 10], + "dims": [1, 2, 4], + "type": "float32" + } + ] + } + ] + } +] diff --git a/js/web/test/data/ops/slice.jsonc b/js/web/test/data/ops/slice.jsonc new file mode 100644 index 0000000000000..9c90817a80c36 --- /dev/null +++ b/js/web/test/data/ops/slice.jsonc @@ -0,0 +1,40 @@ +[ + { + "name": "Slice float32", + "operator": "Slice", + "attributes": [], + "cases": [ + { + "name": "T[5] T[1] T[1] (float32)", + "inputs": [ + { + "data": [ + 0.3964604139328003, -0.8916832804679871, -1.6578896045684814, 1.960708737373352, 1.181204915046692 + ], + "dims": [5], + "type": "float32" + }, + { "data": [3], "dims": [1], "type": "int64" }, + { "data": [4], "dims": [1], "type": "int64" } + ], + "outputs": [{ "data": [1.960708737373352], "dims": [1], "type": "float32" }] + } + ] + }, + { + "name": "Slice int32", + "operator": "Slice", + "attributes": [], + "cases": [ + { + "name": "T[5] T[1] T[1] (int32)", + "inputs": [ + { "data": [0, 0, -1, 1, 0], "dims": [5], "type": "int32" }, + { "data": [3], "dims": [1], "type": "int64" }, + { "data": [4], "dims": [1], "type": "int64" } + ], + "outputs": [{ "data": [1], "dims": [1], "type": "int32" }] + } + ] + } +] diff --git a/js/web/test/data/ops/softmax.jsonc b/js/web/test/data/ops/softmax.jsonc index c9dbe79199a37..85d4096ee0493 100644 --- a/js/web/test/data/ops/softmax.jsonc +++ b/js/web/test/data/ops/softmax.jsonc @@ -15,12 +15,7 @@ ], "outputs": [ { - "data": [ - 0.2689414322376251, - 0.7310585975646973, - 0.2689414322376251, - 0.7310585975646973 - ], + "data": [0.2689414322376251, 0.7310585975646973, 0.2689414322376251, 0.7310585975646973], "dims": [2, 2], "type": "float32" } diff --git a/js/web/test/data/ops/split.jsonc b/js/web/test/data/ops/split.jsonc index 2eb9e8f14f6c9..46fc323cc6b0f 100644 --- a/js/web/test/data/ops/split.jsonc +++ b/js/web/test/data/ops/split.jsonc @@ -2,6 +2,7 @@ { "name": "Split on Axis 0", "operator": "Split", + "opset": { "domain": "", "version": 12 }, "attributes": [ { "name": "axis", "data": 0, "type": "int" }, { "name": "split", "data": [2, 4], "type": "ints" } @@ -34,6 +35,7 @@ { "name": "Split on Axis 1 - 2D", "operator": "Split", + "opset": { "domain": "", "version": 12 }, "attributes": [ { "name": "axis", "data": 1, "type": "int" }, { "name": "split", "data": [2, 4], "type": "ints" } @@ -43,20 +45,7 @@ "name": "T[6]", "inputs": [ { - "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 - ], + "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": [2, 6], "type": "float32" } diff --git a/js/web/test/data/ops/sub.jsonc b/js/web/test/data/ops/sub.jsonc index 2c1f4e054414c..6225054bb1676 100644 --- a/js/web/test/data/ops/sub.jsonc +++ b/js/web/test/data/ops/sub.jsonc @@ -79,64 +79,14 @@ "type": "float32" }, { - "data": [ - 2, - 6, - 1, - 2, - 1, - 3, - 1, - 4, - 3, - 5, - 3, - 4, - 1, - 4, - 1, - 6, - 4, - 4, - 5, - 6, - 2, - 4, - 2, - 6 - ], + "data": [2, 6, 1, 2, 1, 3, 1, 4, 3, 5, 3, 4, 1, 4, 1, 6, 4, 4, 5, 6, 2, 4, 2, 6], "dims": [3, 2, 4], "type": "float32" } ], "outputs": [ { - "data": [ - -1, - -4, - 2, - 2, - 4, - 3, - 6, - 4, - -2, - -3, - 0, - 0, - 4, - 2, - 6, - 2, - -3, - -2, - -2, - -2, - 3, - 2, - 5, - 2 - ], + "data": [-1, -4, 2, 2, 4, 3, 6, 4, -2, -3, 0, 0, 4, 2, 6, 2, -3, -2, -2, -2, 3, 2, 5, 2], "dims": [3, 2, 4], "type": "float32" } diff --git a/js/web/test/data/ops/tan.jsonc b/js/web/test/data/ops/tan.jsonc index 4ff43c1edf91f..aa77f05d4876a 100644 --- a/js/web/test/data/ops/tan.jsonc +++ b/js/web/test/data/ops/tan.jsonc @@ -49,16 +49,7 @@ ], "outputs": [ { - "data": [ - 0.10033467, - 0.20271004, - 0.30933625, - 0.42279322, - 1.26015822, - 1.02963856, - 0.84228838, - 0.68413681 - ], + "data": [0.10033467, 0.20271004, 0.30933625, 0.42279322, 1.26015822, 1.02963856, 0.84228838, 0.68413681], "dims": [2, 4], "type": "float32" } diff --git a/js/web/test/data/ops/tile.jsonc b/js/web/test/data/ops/tile.jsonc new file mode 100644 index 0000000000000..3b1794d1d27b5 --- /dev/null +++ b/js/web/test/data/ops/tile.jsonc @@ -0,0 +1,147 @@ +[ + { + "name": "Tile 2D - float32", + "operator": "Tile", + "attributes": [], + "cases": [ + { + "name": "T[1,2]", + "inputs": [ + { + "data": [1, 2, 3, 4], + "dims": [2, 2], + "type": "float32" + }, + { + "data": [1, 2], + "dims": [2], + "type": "int64" + } + ], + "outputs": [ + { + "data": [1, 2, 1, 2, 3, 4, 3, 4], + "dims": [2, 4], + "type": "float32" + } + ] + } + ] + }, + { + "name": "Tile 2D - int32", + "operator": "Tile", + "attributes": [], + "cases": [ + { + "name": "T[1,2]", + "inputs": [ + { + "data": [1, 2, 3, 4], + "dims": [2, 2], + "type": "int32" + }, + { + "data": [1, 2], + "dims": [2], + "type": "int64" + } + ], + "outputs": [ + { + "data": [1, 2, 1, 2, 3, 4, 3, 4], + "dims": [2, 4], + "type": "int32" + } + ] + } + ] + }, + { + "name": "Tile 2D - uint32", + "operator": "Tile", + "attributes": [], + "cases": [ + { + "name": "T[1,2]", + "inputs": [ + { + "data": [1, 2, 3, 4], + "dims": [2, 2], + "type": "uint32" + }, + { + "data": [2, 1], + "dims": [2], + "type": "int64" + } + ], + "outputs": [ + { + "data": [1, 2, 3, 4, 1, 2, 3, 4], + "dims": [4, 2], + "type": "uint32" + } + ] + } + ] + }, + { + "name": "Tile 1D - float32", + "operator": "Tile", + "attributes": [], + "cases": [ + { + "name": "T[2]", + "inputs": [ + { + "data": [1, 2], + "dims": [2], + "type": "float32" + }, + { + "data": [4], + "dims": [1], + "type": "int64" + } + ], + "outputs": [ + { + "data": [1, 2, 1, 2, 1, 2, 1, 2], + "dims": [8], + "type": "float32" + } + ] + } + ] + }, + { + "name": "Tile 2D all dims", + "operator": "Tile", + "attributes": [], + "cases": [ + { + "name": "T[2]", + "inputs": [ + { + "data": [0, 1, 2, 3], + "dims": [2, 2], + "type": "float32" + }, + { + "data": [2, 2], + "dims": [2], + "type": "int64" + } + ], + "outputs": [ + { + "data": [0, 1, 0, 1, 2, 3, 2, 3, 0, 1, 0, 1, 2, 3, 2, 3], + "dims": [4, 4], + "type": "float32" + } + ] + } + ] + } +] diff --git a/js/web/test/data/ops/transpose.jsonc b/js/web/test/data/ops/transpose.jsonc index cb851bf321c1d..285d14018e74d 100644 --- a/js/web/test/data/ops/transpose.jsonc +++ b/js/web/test/data/ops/transpose.jsonc @@ -32,64 +32,14 @@ "name": "T[2,3]", "inputs": [ { - "data": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24 - ], + "data": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24], "dims": [2, 3, 4], "type": "float32" } ], "outputs": [ { - "data": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24 - ], + "data": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24], "dims": [2, 3, 4], "type": "float32" } @@ -106,64 +56,14 @@ "name": "T[2,3]", "inputs": [ { - "data": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24 - ], + "data": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24], "dims": [2, 3, 4], "type": "float32" } ], "outputs": [ { - "data": [ - 1, - 5, - 9, - 2, - 6, - 10, - 3, - 7, - 11, - 4, - 8, - 12, - 13, - 17, - 21, - 14, - 18, - 22, - 15, - 19, - 23, - 16, - 20, - 24 - ], + "data": [1, 5, 9, 2, 6, 10, 3, 7, 11, 4, 8, 12, 13, 17, 21, 14, 18, 22, 15, 19, 23, 16, 20, 24], "dims": [2, 4, 3], "type": "float32" } @@ -180,64 +80,14 @@ "name": "T[2,3]", "inputs": [ { - "data": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24 - ], + "data": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24], "dims": [2, 3, 4], "type": "float32" } ], "outputs": [ { - "data": [ - 1, - 13, - 5, - 17, - 9, - 21, - 2, - 14, - 6, - 18, - 10, - 22, - 3, - 15, - 7, - 19, - 11, - 23, - 4, - 16, - 8, - 20, - 12, - 24 - ], + "data": [1, 13, 5, 17, 9, 21, 2, 14, 6, 18, 10, 22, 3, 15, 7, 19, 11, 23, 4, 16, 8, 20, 12, 24], "dims": [4, 3, 2], "type": "float32" } @@ -254,64 +104,14 @@ "name": "T[2,3]", "inputs": [ { - "data": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24 - ], + "data": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24], "dims": [2, 3, 4], "type": "float32" } ], "outputs": [ { - "data": [ - 1, - 5, - 9, - 13, - 17, - 21, - 2, - 6, - 10, - 14, - 18, - 22, - 3, - 7, - 11, - 15, - 19, - 23, - 4, - 8, - 12, - 16, - 20, - 24 - ], + "data": [1, 5, 9, 13, 17, 21, 2, 6, 10, 14, 18, 22, 3, 7, 11, 15, 19, 23, 4, 8, 12, 16, 20, 24], "dims": [4, 2, 3], "type": "float32" } @@ -328,64 +128,14 @@ "name": "T[2,3]", "inputs": [ { - "data": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24 - ], + "data": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24], "dims": [2, 3, 4], "type": "float32" } ], "outputs": [ { - "data": [ - 1, - 13, - 2, - 14, - 3, - 15, - 4, - 16, - 5, - 17, - 6, - 18, - 7, - 19, - 8, - 20, - 9, - 21, - 10, - 22, - 11, - 23, - 12, - 24 - ], + "data": [1, 13, 2, 14, 3, 15, 4, 16, 5, 17, 6, 18, 7, 19, 8, 20, 9, 21, 10, 22, 11, 23, 12, 24], "dims": [3, 4, 2], "type": "float32" } @@ -402,64 +152,14 @@ "name": "T[2,3]", "inputs": [ { - "data": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24 - ], + "data": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24], "dims": [2, 3, 4], "type": "float32" } ], "outputs": [ { - "data": [ - 1, - 2, - 3, - 4, - 13, - 14, - 15, - 16, - 5, - 6, - 7, - 8, - 17, - 18, - 19, - 20, - 9, - 10, - 11, - 12, - 21, - 22, - 23, - 24 - ], + "data": [1, 2, 3, 4, 13, 14, 15, 16, 5, 6, 7, 8, 17, 18, 19, 20, 9, 10, 11, 12, 21, 22, 23, 24], "dims": [3, 2, 4], "type": "float32" } diff --git a/js/web/test/data/ops/transpose_int32_uint32.jsonc b/js/web/test/data/ops/transpose_int32_uint32.jsonc new file mode 100644 index 0000000000000..fedc3d41ca488 --- /dev/null +++ b/js/web/test/data/ops/transpose_int32_uint32.jsonc @@ -0,0 +1,50 @@ +[ + { + "name": "Transpose int32", + "operator": "Transpose", + "attributes": [{ "name": "perm", "data": [1, 0, 2], "type": "ints" }], + "cases": [ + { + "name": "T[2,3]", + "inputs": [ + { + "data": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24], + "dims": [2, 3, 4], + "type": "int32" + } + ], + "outputs": [ + { + "data": [1, 2, 3, 4, 13, 14, 15, 16, 5, 6, 7, 8, 17, 18, 19, 20, 9, 10, 11, 12, 21, 22, 23, 24], + "dims": [3, 2, 4], + "type": "int32" + } + ] + } + ] + }, + { + "name": "Transpose uint32", + "operator": "Transpose", + "attributes": [{ "name": "perm", "data": [1, 0, 2], "type": "ints" }], + "cases": [ + { + "name": "T[2,3]", + "inputs": [ + { + "data": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24], + "dims": [2, 3, 4], + "type": "uint32" + } + ], + "outputs": [ + { + "data": [1, 2, 3, 4, 13, 14, 15, 16, 5, 6, 7, 8, 17, 18, 19, 20, 9, 10, 11, 12, 21, 22, 23, 24], + "dims": [3, 2, 4], + "type": "uint32" + } + ] + } + ] + } +] diff --git a/js/web/test/data/ops/upsample.jsonc b/js/web/test/data/ops/upsample.jsonc index 5a05ff69c7e15..6c11a8fa3f6a5 100644 --- a/js/web/test/data/ops/upsample.jsonc +++ b/js/web/test/data/ops/upsample.jsonc @@ -2,9 +2,7 @@ { "name": "Upsample - Nearest", "operator": "Upsample", - "attributes": [ - { "name": "scales", "data": [1.0, 1.0, 2.0, 3.0], "type": "floats" } - ], + "attributes": [{ "name": "scales", "data": [1.0, 1.0, 2.0, 3.0], "type": "floats" }], "cases": [ { "name": "X", @@ -18,55 +16,11 @@ "outputs": [ { "data": [ - 1.0, - 1.0, - 1.0, - 3.0, - 3.0, - 3.0, - 1.0, - 1.0, - 1.0, - 3.0, - 3.0, - 3.0, - 3.0, - 3.0, - 3.0, - 5.0, - 5.0, - 5.0, - 3.0, - 3.0, - 3.0, - 5.0, - 5.0, - 5.0, + 1.0, 1.0, 1.0, 3.0, 3.0, 3.0, 1.0, 1.0, 1.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 5.0, 5.0, 5.0, 3.0, 3.0, 3.0, + 5.0, 5.0, 5.0, - 3.0, - 3.0, - 3.0, - 5.0, - 5.0, - 5.0, - 3.0, - 3.0, - 3.0, - 5.0, - 5.0, - 5.0, - 7.0, - 7.0, - 7.0, - 9.0, - 9.0, - 9.0, - 7.0, - 7.0, - 7.0, - 9.0, - 9.0, - 9.0 + 3.0, 3.0, 3.0, 5.0, 5.0, 5.0, 3.0, 3.0, 3.0, 5.0, 5.0, 5.0, 7.0, 7.0, 7.0, 9.0, 9.0, 9.0, 7.0, 7.0, 7.0, + 9.0, 9.0, 9.0 ], "dims": [1, 2, 4, 6], "type": "float32" @@ -78,9 +32,7 @@ { "name": "Upsample - Nearest2X", "operator": "Upsample", - "attributes": [ - { "name": "scales", "data": [1.0, 1.0, 2.0, 2.0], "type": "floats" } - ], + "attributes": [{ "name": "scales", "data": [1.0, 1.0, 2.0, 2.0], "type": "floats" }], "cases": [ { "name": "X", @@ -94,39 +46,9 @@ "outputs": [ { "data": [ - 1.0, - 1.0, - 3.0, - 3.0, - 1.0, - 1.0, - 3.0, - 3.0, - 3.0, - 3.0, - 5.0, - 5.0, - 3.0, - 3.0, - 5.0, - 5.0, + 1.0, 1.0, 3.0, 3.0, 1.0, 1.0, 3.0, 3.0, 3.0, 3.0, 5.0, 5.0, 3.0, 3.0, 5.0, 5.0, - 3.0, - 3.0, - 5.0, - 5.0, - 3.0, - 3.0, - 5.0, - 5.0, - 7.0, - 7.0, - 9.0, - 9.0, - 7.0, - 7.0, - 9.0, - 9.0 + 3.0, 3.0, 5.0, 5.0, 3.0, 3.0, 5.0, 5.0, 7.0, 7.0, 9.0, 9.0, 7.0, 7.0, 9.0, 9.0 ], "dims": [1, 2, 4, 4], "type": "float32" @@ -138,9 +60,7 @@ { "name": "Upsample - Nearest222X", "operator": "Upsample", - "attributes": [ - { "name": "scales", "data": [2.0, 1.0, 2.0, 2.0], "type": "floats" } - ], + "attributes": [{ "name": "scales", "data": [2.0, 1.0, 2.0, 2.0], "type": "floats" }], "cases": [ { "name": "X", @@ -154,73 +74,13 @@ "outputs": [ { "data": [ - 1.0, - 1.0, - 3.0, - 3.0, - 1.0, - 1.0, - 3.0, - 3.0, - 3.0, - 3.0, - 5.0, - 5.0, - 3.0, - 3.0, - 5.0, - 5.0, + 1.0, 1.0, 3.0, 3.0, 1.0, 1.0, 3.0, 3.0, 3.0, 3.0, 5.0, 5.0, 3.0, 3.0, 5.0, 5.0, - 3.0, - 3.0, - 5.0, - 5.0, - 3.0, - 3.0, - 5.0, - 5.0, - 7.0, - 7.0, - 9.0, - 9.0, - 7.0, - 7.0, - 9.0, - 9.0, + 3.0, 3.0, 5.0, 5.0, 3.0, 3.0, 5.0, 5.0, 7.0, 7.0, 9.0, 9.0, 7.0, 7.0, 9.0, 9.0, - 1.0, - 1.0, - 3.0, - 3.0, - 1.0, - 1.0, - 3.0, - 3.0, - 3.0, - 3.0, - 5.0, - 5.0, - 3.0, - 3.0, - 5.0, - 5.0, + 1.0, 1.0, 3.0, 3.0, 1.0, 1.0, 3.0, 3.0, 3.0, 3.0, 5.0, 5.0, 3.0, 3.0, 5.0, 5.0, - 3.0, - 3.0, - 5.0, - 5.0, - 3.0, - 3.0, - 5.0, - 5.0, - 7.0, - 7.0, - 9.0, - 9.0, - 7.0, - 7.0, - 9.0, - 9.0 + 3.0, 3.0, 5.0, 5.0, 3.0, 3.0, 5.0, 5.0, 7.0, 7.0, 9.0, 9.0, 7.0, 7.0, 9.0, 9.0 ], "dims": [2, 2, 4, 4], "type": "float32" @@ -232,9 +92,7 @@ { "name": "Upsample - Nearest15X", "operator": "Upsample", - "attributes": [ - { "name": "scales", "data": [1.0, 1.0, 2.0, 1.5], "type": "floats" } - ], + "attributes": [{ "name": "scales", "data": [1.0, 1.0, 2.0, 1.5], "type": "floats" }], "cases": [ { "name": "X", @@ -248,31 +106,9 @@ "outputs": [ { "data": [ - 1.0, - 1.0, - 3.0, - 1.0, - 1.0, - 3.0, - 3.0, - 3.0, - 5.0, - 3.0, - 3.0, - 5.0, + 1.0, 1.0, 3.0, 1.0, 1.0, 3.0, 3.0, 3.0, 5.0, 3.0, 3.0, 5.0, - 3.0, - 3.0, - 5.0, - 3.0, - 3.0, - 5.0, - 7.0, - 7.0, - 9.0, - 7.0, - 7.0, - 9.0 + 3.0, 3.0, 5.0, 3.0, 3.0, 5.0, 7.0, 7.0, 9.0, 7.0, 7.0, 9.0 ], "dims": [1, 2, 4, 3], "type": "float32" @@ -328,71 +164,11 @@ "outputs": [ { "data": [ - 1.0, - 1.5, - 2.0, - 2.5, - 3.0, - 3.0, - 3.0, - 3.0, - 2.0, - 2.5, - 3.0, - 3.5, - 4.0, - 4.0, - 4.0, - 4.0, - 3.0, - 3.5, - 4.0, - 4.5, - 5.0, - 5.0, - 5.0, - 5.0, - 3.0, - 3.5, - 4.0, - 4.5, - 5.0, - 5.0, - 5.0, - 5.0, + 1.0, 1.5, 2.0, 2.5, 3.0, 3.0, 3.0, 3.0, 2.0, 2.5, 3.0, 3.5, 4.0, 4.0, 4.0, 4.0, 3.0, 3.5, 4.0, 4.5, 5.0, + 5.0, 5.0, 5.0, 3.0, 3.5, 4.0, 4.5, 5.0, 5.0, 5.0, 5.0, - 3.0, - 3.5, - 4.0, - 4.5, - 5.0, - 5.0, - 5.0, - 5.0, - 5.0, - 5.5, - 6.0, - 6.5, - 7.0, - 7.0, - 7.0, - 7.0, - 7.0, - 7.5, - 8.0, - 8.5, - 9.0, - 9.0, - 9.0, - 9.0, - 7.0, - 7.5, - 8.0, - 8.5, - 9.0, - 9.0, - 9.0, - 9.0 + 3.0, 3.5, 4.0, 4.5, 5.0, 5.0, 5.0, 5.0, 5.0, 5.5, 6.0, 6.5, 7.0, 7.0, 7.0, 7.0, 7.0, 7.5, 8.0, 8.5, 9.0, + 9.0, 9.0, 9.0, 7.0, 7.5, 8.0, 8.5, 9.0, 9.0, 9.0, 9.0 ], "dims": [2, 1, 4, 8], "type": "float32" @@ -421,38 +197,8 @@ "outputs": [ { "data": [ - 1.0, - 1.5, - 2.0, - 2.5, - 3.0, - 3.0, - 3.0, - 3.0, - 2.0, - 2.5, - 3.0, - 3.5, - 4.0, - 4.0, - 4.0, - 4.0, - 3.0, - 3.5, - 4.0, - 4.5, - 5.0, - 5.0, - 5.0, - 5.0, - 3.0, - 3.5, - 4.0, - 4.5, - 5.0, - 5.0, - 5.0, - 5.0 + 1.0, 1.5, 2.0, 2.5, 3.0, 3.0, 3.0, 3.0, 2.0, 2.5, 3.0, 3.5, 4.0, 4.0, 4.0, 4.0, 3.0, 3.5, 4.0, 4.5, 5.0, + 5.0, 5.0, 5.0, 3.0, 3.5, 4.0, 4.5, 5.0, 5.0, 5.0, 5.0 ], "dims": [4, 8], "type": "float32" diff --git a/js/web/test/e2e/browser-test-wasm-image-tensor-image.js b/js/web/test/e2e/browser-test-wasm-image-tensor-image.js index 8346357a72993..f82fa48fad3ff 100644 --- a/js/web/test/e2e/browser-test-wasm-image-tensor-image.js +++ b/js/web/test/e2e/browser-test-wasm-image-tensor-image.js @@ -3,64 +3,111 @@ 'use strict'; +const IMAGE_HEIGHT = 20 +const IMAGE_WIDTH = 15 + function getRndColor() { - let r = 255*Math.random()|0, - g = 255*Math.random()|0, - b = 255*Math.random()|0; - return 'rgb(' + r + ',' + g + ',' + b + ')'; + let r = 255 * Math.random() | 0, g = 255 * Math.random() | 0, b = 255 * Math.random() | 0, + a = 255 * Math.random() | 0; + return 'rgb(' + r + ',' + g + ',' + b + ',' + a + ')'; } -it('Browser E2E testing - Tensor <--> Image E2E test', async function () { +function compareTensors(tensorA, tensorB, msg) { + for (let i = 0; i < IMAGE_HEIGHT * IMAGE_WIDTH * 3; i++) { + if (tensorA.data[i] !== tensorB.data[i]) { + console.log('Element - ' + i + ' - ' + tensorA.data[i] + ' - ' + tensorB.data[i]); + throw new Error(msg); + } + } +} +// TODO: this testing need to be revised +// +// work item list: +// - format the code +// - remove 'wasm' from file name +// - test depending on public website (https://media.istockphoto.com/) should be changed to depends on a localhost +// - the test is composed by 3 different test cases. split them to 3 different cases. +// - some test cases are wriiten incorrectly. +// +it('Browser E2E testing - Tensor <--> Image E2E test', async function() { // Creating Image HTML Image Element - let img = document.createElement('img'); + let img = new Image(); img.crossOrigin = 'Anonymous'; + + // Creating canvas element const canvas = document.createElement('canvas'); - canvas.height = 200; - canvas.width = 200; + canvas.height = IMAGE_HEIGHT; + canvas.width = IMAGE_WIDTH; const context = canvas.getContext('2d'); let y, x; - for(y = 0; y < 200; y++) { - for(x = 0; x < 200; x++) { - context.fillStyle = getRndColor(); - context.fillRect(x, y, 1, 1); - } + // Filling the canvas with random data + for (y = 0; y < IMAGE_HEIGHT; y++) { + for (x = 0; x < IMAGE_WIDTH; x++) { + context.fillStyle = getRndColor(); + context.fillRect(x, y, 1, 1); + } + } + + // Copying the canavas data to the image + img.src = canvas.toDataURL(); + + // Testing HTML Image Element --> Tensor --> ImageData --> Tensor + img.onload = + async () => { + // Image HTML element to tensor API - HTML + const inputTensorHTML = await ort.Tensor.fromImage(img, {norm: {bias: [2, 3, 9, 5], mean: [5, 6, 17, 8]}}); + // Tensor to ImageDAta API + let newImage = inputTensorHTML.toImageData({norm: {bias: [2 / 5, 3 / 6, 9 / 17, 5 / 8], mean: [5, 6, 17, 8]}}); + // ImageData to tensor API + let inputTensorImageData = + await ort.Tensor.fromImage(newImage, options = {norm: {bias: [2, 3, 9, 5], mean: [5, 6, 17, 8]}}); + + // TODO: fix this test case + // + // the line above does not return as expected because syntax error. + // the reason why it does not fail is because it throws exception, and the exception is not caught. the line below + // is not executed. to fix this, wrap a try-catch to deal with exceptions. + + compareTensors(inputTensorHTML, inputTensorImageData, 'BUG in HTML image element & ImageData use case'); } - img = canvas.toDataURL(); + // Copying the canavas data to the image as Data URL + let image = canvas.toDataURL(); - // Image HTML element to tensor API - const inputTensorHTML = await ort.Tensor.fromImage(img); + // Testing Data URL --> Tensor --> Data URL --> Tensor + // Data URL to tensor API - + const inputTensorDataURL = + await ort.Tensor.fromImage(image, {format: 'RBG', norm: {bias: [1, 10, 5, 0], mean: [5, 7, 11, 0]}}); // Tensor to ImageDAta API - let newImage = inputTensorHTML.toImageData(); + let newImage = inputTensorDataURL.toDataURL({norm: {bias: [1 / 5, 10 / 7, 5 / 11, 0], mean: [5, 7, 11, 0]}}); // ImageData to tensor API - let inputTensorImageData = await ort.Tensor.fromImage(newImage); + let inputTensorImageData = + await ort.Tensor.fromImage(newImage, {format: 'RGBA', norm: {bias: [1, 10, 5, 0], mean: [5, 7, 11, 0]}}); - for (let i = 0; i < newImage.height*newImage.width*3; i++) { - if(inputTensorImageData.data[i]!==inputTensorHTML.data[i]){ - console.log("Element - " + i + " - " + inputTensorHTML.data[i] + " - " + inputTensorImageData.data[i]); - throw new Error('BUG in ImageData & URL'); - } - } + // TODO: fix this + // creating tensor from image data should not depend on `options.format`. + // data url with type 'image/png' has a determined 'RGBA' format - let online = navigator.onLine; + compareTensors(inputTensorDataURL, inputTensorImageData, 'BUG in ImageData & Data URL use case'); - if(online){ + // Testing URL --> Tensor --> ImageData --> Tensor + let online = navigator.onLine; + if (online) { // URL element to tensor API - const inputTensorURL = await ort.Tensor.fromImage('https://media.istockphoto.com/id/172859087/photo/square-eggs.jpg?s=2048x2048&w=is&k=20&c=KiBRyyYaoUUSjcJLBh1-qqVu7LW6UQZBopZdva0f5e4='); + const inputTensorURL = await ort.Tensor.fromImage( + 'https://media.istockphoto.com/id/172859087/photo/square-eggs.jpg?s=2048x2048&w=is&k=20&c=KiBRyyYaoUUSjcJLBh1-qqVu7LW6UQZBopZdva0f5e4=', + {norm: {bias: [2, 3, 9, 0], mean: [5, 6, 17, 0]}}); // Tensor to ImageDAta API - newImage = inputTensorURL.toImageData(); + let newImage = + inputTensorURL.toImageData({format: 'RGB', norm: {bias: [2 / 5, 3 / 6, 9 / 17, 0], mean: [5, 6, 17, 0]}}); // ImageData to tensor API - inputTensorImageData = await ort.Tensor.fromImage(newImage); + let inputTensorImageData = + await ort.Tensor.fromImage(newImage, {format: 'RGB', norm: {bias: [2, 3, 9, 0], mean: [5, 6, 17, 0]}}); - for (let i = 0; i < newImage.height*newImage.width*3; i++) { - if(inputTensorURL.data[i]!==inputTensorImageData.data[i]){ - console.log("Element - " + i + " - " + inputTensorURL.data[i] + " - " + inputTensorImageData.data[i]); - throw new Error('BUG in ImageData & URL'); - } - } - }else{ - console.log("No internet connection - didn't test Image URL to tensor API"); + compareTensors(inputTensorURL, inputTensorImageData, 'BUG in ImageData & URL'); + } else { + console.log('No internet connection - didn\'t test Image URL to tensor API'); } }); diff --git a/js/web/test/e2e/browser-test-wasm-multi-session-create.js b/js/web/test/e2e/browser-test-wasm-multi-session-create.js index 1ac7a99b52ceb..5efc3e712f2ed 100644 --- a/js/web/test/e2e/browser-test-wasm-multi-session-create.js +++ b/js/web/test/e2e/browser-test-wasm-multi-session-create.js @@ -3,7 +3,7 @@ 'use strict'; -it('Browser E2E testing - WebAssembly backend (multiple inference session create calls)', async function () { +it('Browser E2E testing - WebAssembly backend (multiple inference session create calls)', async function() { const sessionPromiseA = createSession(ort); const sessionPromiseB = createSession(ort); await Promise.all([sessionPromiseA, sessionPromiseB]); diff --git a/js/web/test/e2e/browser-test-wasm-no-threads.js b/js/web/test/e2e/browser-test-wasm-no-threads.js index f86d6c7dbc1a0..25723a14f4afd 100644 --- a/js/web/test/e2e/browser-test-wasm-no-threads.js +++ b/js/web/test/e2e/browser-test-wasm-no-threads.js @@ -3,7 +3,7 @@ 'use strict'; -it('Browser E2E testing - WebAssembly backend (no threads)', async function () { +it('Browser E2E testing - WebAssembly backend (no threads)', async function() { ort.env.wasm.numThreads = 1; - await testFunction(ort, { executionProviders: ['wasm'] }); + await testFunction(ort, {executionProviders: ['wasm']}); }); diff --git a/js/web/test/e2e/browser-test-wasm-path-override-filename.js b/js/web/test/e2e/browser-test-wasm-path-override-filename.js index e71a0840bedf6..4e5ffc369d742 100644 --- a/js/web/test/e2e/browser-test-wasm-path-override-filename.js +++ b/js/web/test/e2e/browser-test-wasm-path-override-filename.js @@ -3,15 +3,13 @@ 'use strict'; -it('Browser E2E testing - WebAssembly backend (path override filename)', async function () { +it('Browser E2E testing - WebAssembly backend (path override filename)', async function() { // disable SIMD and multi-thread ort.env.wasm.numThreads = 1; ort.env.wasm.simd = false; // override .wasm file path for 'ort-wasm.wasm' - ort.env.wasm.wasmPaths = { - 'ort-wasm.wasm': new URL('./test-wasm-path-override/renamed.wasm', document.baseURI).href - }; + ort.env.wasm.wasmPaths = {'ort-wasm.wasm': new URL('./test-wasm-path-override/renamed.wasm', document.baseURI).href}; - await testFunction(ort, { executionProviders: ['wasm'] }); + await testFunction(ort, {executionProviders: ['wasm']}); }); diff --git a/js/web/test/e2e/browser-test-wasm-path-override-prefix.js b/js/web/test/e2e/browser-test-wasm-path-override-prefix.js index ebb6efe57bb75..f03422fd424c6 100644 --- a/js/web/test/e2e/browser-test-wasm-path-override-prefix.js +++ b/js/web/test/e2e/browser-test-wasm-path-override-prefix.js @@ -3,8 +3,7 @@ 'use strict'; -it('Browser E2E testing - WebAssembly backend (path override prefix)', async function () { - +it('Browser E2E testing - WebAssembly backend (path override prefix)', async function() { // disable SIMD and multi-thread ort.env.wasm.numThreads = 1; ort.env.wasm.simd = false; @@ -12,5 +11,5 @@ it('Browser E2E testing - WebAssembly backend (path override prefix)', async fun // override .wasm file path prefix ort.env.wasm.wasmPaths = new URL('./test-wasm-path-override/', document.baseURI).href; - await testFunction(ort, { executionProviders: ['wasm'] }); + await testFunction(ort, {executionProviders: ['wasm']}); }); diff --git a/js/web/test/e2e/browser-test-wasm-proxy-no-threads.js b/js/web/test/e2e/browser-test-wasm-proxy-no-threads.js index 83bdfdcde9c92..1c2483dd2d70e 100644 --- a/js/web/test/e2e/browser-test-wasm-proxy-no-threads.js +++ b/js/web/test/e2e/browser-test-wasm-proxy-no-threads.js @@ -3,8 +3,8 @@ 'use strict'; -it('Browser E2E testing - WebAssembly backend (proxy, no threads)', async function () { +it('Browser E2E testing - WebAssembly backend (proxy, no threads)', async function() { ort.env.wasm.numThreads = 1; ort.env.wasm.proxy = true; - await testFunction(ort, { executionProviders: ['wasm'] }); + await testFunction(ort, {executionProviders: ['wasm']}); }); diff --git a/js/web/test/e2e/browser-test-wasm-proxy.js b/js/web/test/e2e/browser-test-wasm-proxy.js index eae66a23ec356..7c5c27e51d209 100644 --- a/js/web/test/e2e/browser-test-wasm-proxy.js +++ b/js/web/test/e2e/browser-test-wasm-proxy.js @@ -3,7 +3,7 @@ 'use strict'; -it('Browser E2E testing - WebAssembly backend (proxy)', async function () { +it('Browser E2E testing - WebAssembly backend (proxy)', async function() { ort.env.wasm.proxy = true; - await testFunction(ort, { executionProviders: ['wasm'] }); + await testFunction(ort, {executionProviders: ['wasm']}); }); diff --git a/js/web/test/e2e/browser-test-wasm.js b/js/web/test/e2e/browser-test-wasm.js index dec40f95b16c3..8e4f500d16749 100644 --- a/js/web/test/e2e/browser-test-wasm.js +++ b/js/web/test/e2e/browser-test-wasm.js @@ -3,6 +3,6 @@ 'use strict'; -it('Browser E2E testing - WebAssembly backend', async function () { - await testFunction(ort, { executionProviders: ['wasm'] }); +it('Browser E2E testing - WebAssembly backend', async function() { + await testFunction(ort, {executionProviders: ['wasm']}); }); diff --git a/js/web/test/e2e/browser-test-webgl.js b/js/web/test/e2e/browser-test-webgl.js index b5ac3e29a9617..e503f38ae5735 100644 --- a/js/web/test/e2e/browser-test-webgl.js +++ b/js/web/test/e2e/browser-test-webgl.js @@ -3,6 +3,6 @@ 'use strict'; -it('Browser E2E testing - WebGL backend', async function () { - await testFunction(ort, { executionProviders: ['webgl'] }); +it('Browser E2E testing - WebGL backend', async function() { + await testFunction(ort, {executionProviders: ['webgl']}); }); diff --git a/js/web/test/e2e/common.js b/js/web/test/e2e/common.js index 7f478a5095c90..d333aad8a2098 100644 --- a/js/web/test/e2e/common.js +++ b/js/web/test/e2e/common.js @@ -7,20 +7,19 @@ function assert(cond) { if (!cond) throw new Error(); } -var createSession = function(ort, options) { +var createSession = + function(ort, options) { return ort.InferenceSession.create('./model.onnx', options || {}); } -var testFunction = async function (ort, options) { +var testFunction = async function(ort, options) { const session = await createSession(ort, options); const dataA = Float32Array.from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]); const dataB = Float32Array.from([10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120]); - const fetches = await session.run({ - a: new ort.Tensor('float32', dataA, [3, 4]), - b: new ort.Tensor('float32', dataB, [4, 3]) - }); + const fetches = + await session.run({a: new ort.Tensor('float32', dataA, [3, 4]), b: new ort.Tensor('float32', dataB, [4, 3])}); const c = fetches.c; diff --git a/js/web/test/e2e/karma.conf.js b/js/web/test/e2e/karma.conf.js index 7607f0d6a9b7b..b7ff408fa29c6 100644 --- a/js/web/test/e2e/karma.conf.js +++ b/js/web/test/e2e/karma.conf.js @@ -15,23 +15,24 @@ if (typeof USER_DATA !== 'string') { throw new Error('flag --user-data= is required'); } -module.exports = function (config) { +module.exports = function(config) { const distPrefix = SELF_HOST ? './node_modules/onnxruntime-web/dist/' : 'http://localhost:8081/dist/'; config.set({ frameworks: ['mocha'], files: [ - { pattern: distPrefix + ORT_MAIN }, - { pattern: './common.js' }, - { pattern: TEST_MAIN }, - { pattern: './node_modules/onnxruntime-web/dist/*.wasm', included: false, nocache: true }, - { pattern: './model.onnx', included: false } + {pattern: distPrefix + ORT_MAIN}, + {pattern: './common.js'}, + {pattern: TEST_MAIN}, + {pattern: './node_modules/onnxruntime-web/dist/*.wasm', included: false, nocache: true}, + {pattern: './model.onnx', included: false}, ], + plugins: [require('@chiragrupani/karma-chromium-edge-launcher'), ...config.plugins], proxies: { '/model.onnx': '/base/model.onnx', '/test-wasm-path-override/ort-wasm.wasm': '/base/node_modules/onnxruntime-web/dist/ort-wasm.wasm', '/test-wasm-path-override/renamed.wasm': '/base/node_modules/onnxruntime-web/dist/ort-wasm.wasm', }, - client: { captureConsole: true, mocha: { expose: ['body'], timeout: 60000 } }, + client: {captureConsole: true, mocha: {expose: ['body'], timeout: 60000}}, reporters: ['mocha'], captureTimeout: 120000, reportSlowerThan: 100, @@ -42,15 +43,13 @@ module.exports = function (config) { hostname: 'localhost', browsers: [], customLaunchers: { - Chrome_default: { - base: 'ChromeHeadless', - chromeDataDir: USER_DATA - }, + Chrome_default: {base: 'ChromeHeadless', chromeDataDir: USER_DATA}, Chrome_no_threads: { base: 'ChromeHeadless', chromeDataDir: USER_DATA, // TODO: no-thread flags - } + }, + Edge_default: {base: 'Edge', edgeDataDir: USER_DATA} } }); }; diff --git a/js/web/test/e2e/node-test-main-no-threads.js b/js/web/test/e2e/node-test-main-no-threads.js index 15182a197de4d..e586c68ca98a9 100644 --- a/js/web/test/e2e/node-test-main-no-threads.js +++ b/js/web/test/e2e/node-test-main-no-threads.js @@ -6,7 +6,7 @@ const ort = require('onnxruntime-web'); const testFunction = require('./common'); -it('Node.js E2E testing - WebAssembly backend (no threads)', async function () { +it('Node.js E2E testing - WebAssembly backend (no threads)', async function() { ort.env.wasm.numThreads = 1; - await testFunction(ort, { executionProviders: ['wasm'] }); + await testFunction(ort, {executionProviders: ['wasm']}); }); diff --git a/js/web/test/e2e/node-test-main.js b/js/web/test/e2e/node-test-main.js index 84d12a77b6cbf..ce39227b2e19c 100644 --- a/js/web/test/e2e/node-test-main.js +++ b/js/web/test/e2e/node-test-main.js @@ -6,8 +6,8 @@ const ort = require('onnxruntime-web'); const testFunction = require('./common'); -it('Node.js E2E testing - WebAssembly backend', async function () { - await testFunction(ort, { executionProviders: ['wasm'] }); +it('Node.js E2E testing - WebAssembly backend', async function() { + await testFunction(ort, {executionProviders: ['wasm']}); process.exit(); }); diff --git a/js/web/test/e2e/node-test-wasm-path-override-filename.js b/js/web/test/e2e/node-test-wasm-path-override-filename.js index 5ff6c358d9d9e..47670061367dd 100644 --- a/js/web/test/e2e/node-test-wasm-path-override-filename.js +++ b/js/web/test/e2e/node-test-wasm-path-override-filename.js @@ -7,15 +7,13 @@ const path = require('path'); const ort = require('onnxruntime-web'); const testFunction = require('./common'); -it('Node.js E2E testing - WebAssembly backend (path override filename)', async function () { +it('Node.js E2E testing - WebAssembly backend (path override filename)', async function() { // disable SIMD and multi-thread ort.env.wasm.numThreads = 1; ort.env.wasm.simd = false; // override .wasm file path for 'ort-wasm.wasm' - ort.env.wasm.wasmPaths = { - 'ort-wasm.wasm': path.join(__dirname, 'test-wasm-path-override/renamed.wasm') - }; + ort.env.wasm.wasmPaths = {'ort-wasm.wasm': path.join(__dirname, 'test-wasm-path-override/renamed.wasm')}; - await testFunction(ort, { executionProviders: ['wasm'] }); + await testFunction(ort, {executionProviders: ['wasm']}); }); diff --git a/js/web/test/e2e/node-test-wasm-path-override-prefix.js b/js/web/test/e2e/node-test-wasm-path-override-prefix.js index 6416298bfe9aa..122991d3683de 100644 --- a/js/web/test/e2e/node-test-wasm-path-override-prefix.js +++ b/js/web/test/e2e/node-test-wasm-path-override-prefix.js @@ -7,7 +7,7 @@ const path = require('path'); const ort = require('onnxruntime-web'); const testFunction = require('./common'); -it('Node.js E2E testing - WebAssembly backend (path override prefix)', async function () { +it('Node.js E2E testing - WebAssembly backend (path override prefix)', async function() { // disable SIMD and multi-thread ort.env.wasm.numThreads = 1; ort.env.wasm.simd = false; @@ -15,5 +15,5 @@ it('Node.js E2E testing - WebAssembly backend (path override prefix)', async fun // override .wasm file path prefix ort.env.wasm.wasmPaths = path.join(__dirname, 'test-wasm-path-override/'); - await testFunction(ort, { executionProviders: ['wasm'] }); + await testFunction(ort, {executionProviders: ['wasm']}); }); diff --git a/js/web/test/e2e/package.json b/js/web/test/e2e/package.json index 0384cb49813c4..5f11a27de6dfc 100644 --- a/js/web/test/e2e/package.json +++ b/js/web/test/e2e/package.json @@ -1,5 +1,6 @@ { "devDependencies": { + "@chiragrupani/karma-chromium-edge-launcher": "^2.2.2", "fs-extra": "^11.1.0", "globby": "^13.1.3", "karma": "^6.4.1", diff --git a/js/web/test/e2e/run.js b/js/web/test/e2e/run.js index 909d72782bd76..2776f6dff46ab 100644 --- a/js/web/test/e2e/run.js +++ b/js/web/test/e2e/run.js @@ -5,8 +5,9 @@ const path = require('path'); const fs = require('fs-extra'); -const { spawn } = require('child_process'); +const {spawn} = require('child_process'); const startServer = require('./simple-http-server'); +const minimist = require('minimist'); // copy whole folder to out-side of /js/ because we need to test in a folder that no `package.json` file // exists in its parent folder. @@ -31,13 +32,15 @@ function getNextUserDataDir() { return dir; } -async function main() { +// commandline arguments +const BROWSER = minimist(process.argv.slice(2)).browser || 'Chrome_default'; +async function main() { // find packed package const {globbySync} = await import('globby'); const ORT_COMMON_FOLDER = path.resolve(JS_ROOT_FOLDER, 'common'); - const ORT_COMMON_PACKED_FILEPATH_CANDIDATES = globbySync('onnxruntime-common-*.tgz', { cwd: ORT_COMMON_FOLDER }); + const ORT_COMMON_PACKED_FILEPATH_CANDIDATES = globbySync('onnxruntime-common-*.tgz', {cwd: ORT_COMMON_FOLDER}); const PACKAGES_TO_INSTALL = []; @@ -48,7 +51,7 @@ async function main() { } const ORT_WEB_FOLDER = path.resolve(JS_ROOT_FOLDER, 'web'); - const ORT_WEB_PACKED_FILEPATH_CANDIDATES = globbySync('onnxruntime-web-*.tgz', { cwd: ORT_WEB_FOLDER }); + const ORT_WEB_PACKED_FILEPATH_CANDIDATES = globbySync('onnxruntime-web-*.tgz', {cwd: ORT_WEB_FOLDER}); if (ORT_WEB_PACKED_FILEPATH_CANDIDATES.length !== 1) { throw new Error('cannot find exactly single package for onnxruntime-web.'); } @@ -57,7 +60,7 @@ async function main() { // we start here: // install dev dependencies - await runInShell(`npm install"`); + await runInShell(`npm install`); // npm install with "--cache" to install packed packages with an empty cache folder await runInShell(`npm install --cache "${NPM_CACHE_FOLDER}" ${PACKAGES_TO_INSTALL.map(i => `"${i}"`).join(' ')}`); @@ -69,11 +72,11 @@ async function main() { await testAllNodejsCases(); // test cases with self-host (ort hosted in same origin) - await testAllBrowserCases({ hostInKarma: true }); + await testAllBrowserCases({hostInKarma: true}); // test cases without self-host (ort hosted in same origin) startServer(path.resolve(TEST_E2E_RUN_FOLDER, 'node_modules', 'onnxruntime-web')); - await testAllBrowserCases({ hostInKarma: false }); + await testAllBrowserCases({hostInKarma: false}); // no error occurs, exit with code 0 process.exit(0); @@ -101,27 +104,27 @@ async function testAllNodejsCases() { await runInShell('node ./node_modules/mocha/bin/mocha ./node-test-wasm-path-override-prefix.js'); } -async function testAllBrowserCases({ hostInKarma }) { - await runKarma({ hostInKarma, main: './browser-test-webgl.js'}); - await runKarma({ hostInKarma, main: './browser-test-webgl.js', ortMain: 'ort.webgl.min.js'}); - await runKarma({ hostInKarma, main: './browser-test-wasm.js'}); - await runKarma({ hostInKarma, main: './browser-test-wasm.js', ortMain: 'ort.wasm.min.js'}); - await runKarma({ hostInKarma, main: './browser-test-wasm-multi-session-create.js'}); - await runKarma({ hostInKarma, main: './browser-test-wasm-no-threads.js'}); - await runKarma({ hostInKarma, main: './browser-test-wasm-no-threads.js', ortMain: 'ort.wasm-core.min.js'}); - await runKarma({ hostInKarma, main: './browser-test-wasm-proxy.js'}); - await runKarma({ hostInKarma, main: './browser-test-wasm-proxy-no-threads.js'}); - await runKarma({ hostInKarma, main: './browser-test-wasm-path-override-filename.js'}); - await runKarma({ hostInKarma, main: './browser-test-wasm-path-override-filename.js', ortMain: 'ort.wasm.min.js'}); - await runKarma({ hostInKarma, main: './browser-test-wasm-path-override-prefix.js'}); - await runKarma({ hostInKarma, main: './browser-test-wasm-path-override-prefix.js', ortMain: 'ort.wasm.min.js'}); - await runKarma({ hostInKarma, main: './browser-test-wasm-image-tensor-image.js'}); +async function testAllBrowserCases({hostInKarma}) { + await runKarma({hostInKarma, main: './browser-test-webgl.js'}); + await runKarma({hostInKarma, main: './browser-test-webgl.js', ortMain: 'ort.webgl.min.js'}); + await runKarma({hostInKarma, main: './browser-test-wasm.js'}); + await runKarma({hostInKarma, main: './browser-test-wasm.js', ortMain: 'ort.wasm.min.js'}); + await runKarma({hostInKarma, main: './browser-test-wasm-multi-session-create.js'}); + await runKarma({hostInKarma, main: './browser-test-wasm-no-threads.js'}); + await runKarma({hostInKarma, main: './browser-test-wasm-no-threads.js', ortMain: 'ort.wasm-core.min.js'}); + await runKarma({hostInKarma, main: './browser-test-wasm-proxy.js'}); + await runKarma({hostInKarma, main: './browser-test-wasm-proxy-no-threads.js'}); + await runKarma({hostInKarma, main: './browser-test-wasm-path-override-filename.js'}); + await runKarma({hostInKarma, main: './browser-test-wasm-path-override-filename.js', ortMain: 'ort.wasm.min.js'}); + await runKarma({hostInKarma, main: './browser-test-wasm-path-override-prefix.js'}); + await runKarma({hostInKarma, main: './browser-test-wasm-path-override-prefix.js', ortMain: 'ort.wasm.min.js'}); + await runKarma({hostInKarma, main: './browser-test-wasm-image-tensor-image.js'}); } -async function runKarma({ hostInKarma, main, browser = 'Chrome_default', ortMain = 'ort.min.js' }) { +async function runKarma({hostInKarma, main, browser = BROWSER, ortMain = 'ort.min.js'}) { const selfHostFlag = hostInKarma ? '--self-host' : ''; - await runInShell( - `npx karma start --single-run --browsers ${browser} ${selfHostFlag} --ort-main=${ortMain} --test-main=${main} --user-data=${getNextUserDataDir()}`); + await runInShell(`npx karma start --single-run --browsers ${browser} ${selfHostFlag} --ort-main=${ + ortMain} --test-main=${main} --user-data=${getNextUserDataDir()}`); } async function runInShell(cmd) { @@ -130,8 +133,8 @@ async function runInShell(cmd) { console.log(' > ' + cmd); console.log('==============================================================='); let complete = false; - const childProcess = spawn(cmd, { shell: true, stdio: 'inherit', cwd: TEST_E2E_RUN_FOLDER }); - childProcess.on('close', function (code) { + const childProcess = spawn(cmd, {shell: true, stdio: 'inherit', cwd: TEST_E2E_RUN_FOLDER}); + childProcess.on('close', function(code) { if (code !== 0) { process.exit(code); } else { @@ -144,8 +147,8 @@ async function runInShell(cmd) { } async function delay(ms) { - return new Promise(function (resolve) { - setTimeout(function () { + return new Promise(function(resolve) { + setTimeout(function() { resolve(); }, ms); }); diff --git a/js/web/test/e2e/simple-http-server.js b/js/web/test/e2e/simple-http-server.js index bf5c8ccf55ca6..1244aaddafd23 100644 --- a/js/web/test/e2e/simple-http-server.js +++ b/js/web/test/e2e/simple-http-server.js @@ -29,35 +29,33 @@ const validRequests = { '/dist/ort.wasm-core.min.js': ['dist/ort.wasm-core.min.js', 'text/javascript'], }; -module.exports = function (dir) { - http.createServer(function (request, response) { - console.log('request ', request.url); - - const requestData = validRequests[request.url]; - if (!request) { - response.writeHead(404); - response.end('404'); - } else { - const [filePath, contentType] = requestData; - fs.readFile(path.resolve(dir, filePath), function (error, content) { - if (error) { - if (error.code == 'ENOENT') { - response.writeHead(404); - response.end('404'); - } - else { - response.writeHead(500); - response.end('500'); - } +module.exports = function(dir) { + http.createServer(function(request, response) { + console.log(`request ${request.url.replace(/\n|\r/g, '')}`); + + const requestData = validRequests[request.url]; + if (!request) { + response.writeHead(404); + response.end('404'); + } else { + const [filePath, contentType] = requestData; + fs.readFile(path.resolve(dir, filePath), function(error, content) { + if (error) { + if (error.code == 'ENOENT') { + response.writeHead(404); + response.end('404'); + } else { + response.writeHead(500); + response.end('500'); + } + } else { + response.setHeader('access-control-allow-origin', '*'); + response.writeHead(200, {'Content-Type': contentType}); + response.end(content, 'utf-8'); + } + }); } - else { - response.setHeader('access-control-allow-origin', '*'); - response.writeHead(200, { 'Content-Type': contentType }); - response.end(content, 'utf-8'); - } - }); - } - - }).listen(8081); + }) + .listen(8081); console.log('Server running at http://127.0.0.1:8081/'); }; diff --git a/js/web/test/op-test-schema.json b/js/web/test/op-test-schema.json new file mode 100644 index 0000000000000..d6eab6a4ba7bc --- /dev/null +++ b/js/web/test/op-test-schema.json @@ -0,0 +1,345 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "title": "Name", + "description": "the name of the test case" + }, + "operator": { + "type": "string", + "pattern": "[A-Z][a-zA-Z]*", + "title": "Operator", + "description": "the operator to use for the test case" + }, + "attributes": { + "type": "array", + "description": "the attributes to use for the test case", + "items": { + "type": "object", + "oneOf": [ + { + "properties": { + "name": { + "type": "string", + "description": "the name of the attribute" + }, + "type": { + "const": "int", + "description": "the type of the attribute" + }, + "data": { + "type": "integer", + "description": "the value of the attribute" + } + }, + "required": ["name", "data", "type"], + "additionalProperties": false + }, + { + "properties": { + "name": { + "type": "string", + "description": "the name of the attribute" + }, + "type": { + "const": "ints", + "description": "the type of the attribute" + }, + "data": { + "type": "array", + "items": { + "type": "integer" + }, + "description": "the value of the attribute" + } + }, + "required": ["name", "data", "type"], + "additionalProperties": false + }, + { + "properties": { + "name": { + "type": "string", + "description": "the name of the attribute" + }, + "type": { + "const": "float", + "description": "the type of the attribute" + }, + "data": { + "type": "number", + "description": "the value of the attribute" + } + }, + "required": ["name", "data", "type"], + "additionalProperties": false + }, + { + "properties": { + "name": { + "type": "string", + "description": "the name of the attribute" + }, + "type": { + "const": "floats", + "description": "the type of the attribute" + }, + "data": { + "type": "array", + "items": { + "type": "number" + }, + "description": "the value of the attribute" + } + }, + "required": ["name", "data", "type"], + "additionalProperties": false + }, + { + "properties": { + "name": { + "type": "string", + "description": "the name of the attribute" + }, + "type": { + "const": "string", + "description": "the type of the attribute" + }, + "data": { + "type": "string", + "description": "the value of the attribute" + } + }, + "required": ["name", "data", "type"], + "additionalProperties": false + }, + { + "properties": { + "name": { + "type": "string", + "description": "the name of the attribute" + }, + "type": { + "const": "strings", + "description": "the type of the attribute" + }, + "data": { + "type": "array", + "items": { + "type": "string" + }, + "description": "the value of the attribute" + } + }, + "required": ["name", "data", "type"], + "additionalProperties": false + } + ] + } + }, + "opset": { + "type": "object", + "description": "opset is an optional field that specifies the opset to use for the test case. If not specified, the latest opset of \"\"(onnx.ai) is used.", + "properties": { + "domain": { + "type": "string", + "description": "the domain of the opset" + }, + "version": { + "type": "integer", + "description": "the version of the opset" + } + }, + "required": ["domain", "version"], + "additionalProperties": false + }, + "cases": { + "type": "array", + "description": "the test cases", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "the name of the test case" + }, + "inputs": { + "type": "array", + "description": "the test case inputs", + "items": { + "oneOf": [ + { + "type": "object", + "properties": { + "type": { + "enum": [ + "float32", + "float64", + "int8", + "int16", + "int32", + "int64", + "uint8", + "uint16", + "uint32", + "uint64", + "bool", + "string" + ] + }, + "data": { + "type": "array", + "items": { + "type": ["number", "string", "boolean"] + } + }, + "dims": { + "type": "array", + "items": { + "type": "integer", + "minimum": 0 + } + } + }, + "required": ["type", "data", "dims"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "enum": [ + "float32", + "float64", + "int8", + "int16", + "int32", + "int64", + "uint8", + "uint16", + "uint32", + "uint64", + "bool", + "string" + ] + }, + "data": { + "type": "null" + } + }, + "required": ["type", "data"], + "additionalProperties": false + } + ] + } + }, + "outputs": { + "type": "array", + "description": "the test case outputs", + "items": { + "oneOf": [ + { + "type": "object", + "properties": { + "type": { + "enum": [ + "float32", + "float64", + "int8", + "int16", + "int32", + "int64", + "uint8", + "uint16", + "uint32", + "uint64", + "bool", + "string" + ] + }, + "data": { + "type": "array", + "items": { + "type": ["number", "string", "boolean"] + } + }, + "dims": { + "type": "array", + "items": { + "type": "integer", + "minimum": 0 + } + } + }, + "required": ["type", "data", "dims"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { + "enum": [ + "float32", + "float64", + "int8", + "int16", + "int32", + "int64", + "uint8", + "uint16", + "uint32", + "uint64", + "bool", + "string" + ] + }, + "data": { + "type": "null" + } + }, + "required": ["type", "data"], + "additionalProperties": false + } + ] + } + } + }, + "required": ["name", "inputs", "outputs"], + "additionalProperties": false + } + }, + "inputShapeDefinitions": { + "description": "inputShapeDefinitions is an optional field that specifies the shapes constraints for the test case inputs. It can be one of the following:\n - \"none\": no shape constraints for the test case inputs.\n - \"rankOnly\": the rank of the test case inputs are specified automatically, but not the shape.\n - \"static\": the shape of the test case inputs are fully specified automatically.\n - an array of shapes: the shapes constraints for the test case inputs. shape can be represented by an array, whose element is either a number for a static dimension or a string for a semantic(dynamic) dimension.", + "oneOf": [ + { + "type": "array", + "items": { + "oneOf": [ + { + "type": "array", + "items": { + "type": ["integer", "string"] + } + }, + { "type": "null" } + ] + } + }, + { + "enum": ["none", "rankOnly", "static"] + } + ] + }, + "platformCondition": { + "type": "string", + "description": "the condition for the test case, a regex string applied on platform name. If not specified, the test will run on all platforms. Otherwise, the test will only run on platforms that match the pattern. see https://github.com/bestiejs/platform.js/" + } + }, + "required": ["name", "operator", "cases"], + "additionalProperties": false + } +} diff --git a/js/web/test/suite-test-list.jsonc b/js/web/test/suite-test-list.jsonc index 17928899c91b1..6e65645ef4756 100644 --- a/js/web/test/suite-test-list.jsonc +++ b/js/web/test/suite-test-list.jsonc @@ -152,7 +152,7 @@ "test_softmax_example", { "name": "test_softmax_large_number", - "condition": "^((?!iOS).)*$" // does NOT contains 'iOS': large number cannot be handled in a half_float environment + "platformCondition": "^((?!iOS).)*$" // does NOT contains 'iOS': large number cannot be handled in a half_float environment }, "test_sub_bcast", "test_sub_example", @@ -183,7 +183,7 @@ "opset{7,8,9,10,11,12,13,14,15,16,17}/test_reduce_min_keepdims_random", { "name": "opset{7,8,9,10,11,12,13,14,15,16,17}/test_reduce_prod_default_axes_keepdims_example", - "condition": "^((?!iOS).)*$" // does NOT contains 'iOS': large number cannot be handled in a half_float environment + "platformCondition": "^((?!iOS).)*$" // does NOT contains 'iOS': large number cannot be handled in a half_float environment }, "opset{7,8,9,10,11,12,13,14,15,16,17}/test_reduce_prod_default_axes_keepdims_random", "opset{7,8,9,10,11,12,13,14,15,16,17}/test_reduce_prod_do_not_keepdims_example", @@ -257,6 +257,7 @@ "greater.jsonc", //"identity.jsonc", "image-scaler.jsonc", + "instance-norm.jsonc", "less.jsonc", "log.jsonc", "matmul.jsonc", @@ -271,7 +272,7 @@ "pad-big.jsonc", "pow.jsonc", "pow-big-number.jsonc", - "reshape.jsonc", + "reshape-int32.jsonc", "softmax.jsonc", "sin.jsonc", "split.jsonc", @@ -305,38 +306,38 @@ // "test_and2d", // "test_and3d", // "test_and4d", - // // "test_argmax_default_axis_example_select_last_index", - // // "test_argmax_default_axis_example", - // // "test_argmax_default_axis_random_select_last_index", - // // "test_argmax_default_axis_random", - // // "test_argmax_keepdims_example_select_last_index", - // // "test_argmax_keepdims_example", - // // "test_argmax_keepdims_random_select_last_index", - // // "test_argmax_keepdims_random", - // // "test_argmax_negative_axis_keepdims_example_select_last_index", - // // "test_argmax_negative_axis_keepdims_example", - // // "test_argmax_negative_axis_keepdims_random_select_last_index", - // // "test_argmax_negative_axis_keepdims_random", - // // "test_argmax_no_keepdims_example_select_last_index", - // // "test_argmax_no_keepdims_example", - // // "test_argmax_no_keepdims_random_select_last_index", - // // "test_argmax_no_keepdims_random", - // // "test_argmin_default_axis_example_select_last_index", - // // "test_argmin_default_axis_example", - // // "test_argmin_default_axis_random_select_last_index", - // // "test_argmin_default_axis_random", - // // "test_argmin_keepdims_example_select_last_index", - // // "test_argmin_keepdims_example", - // // "test_argmin_keepdims_random_select_last_index", - // // "test_argmin_keepdims_random", - // // "test_argmin_negative_axis_keepdims_example_select_last_index", - // // "test_argmin_negative_axis_keepdims_example", - // // "test_argmin_negative_axis_keepdims_random_select_last_index", - // // "test_argmin_negative_axis_keepdims_random", - // // "test_argmin_no_keepdims_example_select_last_index", - // // "test_argmin_no_keepdims_example", - // // "test_argmin_no_keepdims_random_select_last_index", - // // "test_argmin_no_keepdims_random", + "test_argmax_default_axis_example_select_last_index", + "test_argmax_default_axis_example", + "test_argmax_default_axis_random_select_last_index", + "test_argmax_default_axis_random", + "test_argmax_keepdims_example_select_last_index", + "test_argmax_keepdims_example", + "test_argmax_keepdims_random_select_last_index", + "test_argmax_keepdims_random", + "test_argmax_negative_axis_keepdims_example_select_last_index", + "test_argmax_negative_axis_keepdims_example", + "test_argmax_negative_axis_keepdims_random_select_last_index", + "test_argmax_negative_axis_keepdims_random", + "test_argmax_no_keepdims_example_select_last_index", + "test_argmax_no_keepdims_example", + "test_argmax_no_keepdims_random_select_last_index", + "test_argmax_no_keepdims_random", + "test_argmin_default_axis_example_select_last_index", + "test_argmin_default_axis_example", + "test_argmin_default_axis_random_select_last_index", + "test_argmin_default_axis_random", + "test_argmin_keepdims_example_select_last_index", + "test_argmin_keepdims_example", + "test_argmin_keepdims_random_select_last_index", + "test_argmin_keepdims_random", + "test_argmin_negative_axis_keepdims_example_select_last_index", + "test_argmin_negative_axis_keepdims_example", + "test_argmin_negative_axis_keepdims_random_select_last_index", + "test_argmin_negative_axis_keepdims_random", + "test_argmin_no_keepdims_example_select_last_index", + "test_argmin_no_keepdims_example", + "test_argmin_no_keepdims_random_select_last_index", + "test_argmin_no_keepdims_random", "test_asin_example", "test_asin", "test_asinh_example", @@ -361,9 +362,9 @@ "test_basic_conv_with_padding", "test_basic_conv_without_padding", // "test_basic_convinteger", - "test_batchnorm_epsilon_training_mode", + // "test_batchnorm_epsilon_training_mode", "test_batchnorm_epsilon", - "test_batchnorm_example_training_mode", + // "test_batchnorm_example_training_mode", "test_batchnorm_example", // // "test_bernoulli_double_expanded", // // "test_bernoulli_double", @@ -432,34 +433,34 @@ // // "test_compress_1", // // "test_compress_default_axis", // // "test_compress_negative_axis", - // "test_concat_1d_axis_0", - // "test_concat_1d_axis_negative_1", - // "test_concat_2d_axis_0", - // "test_concat_2d_axis_1", - // "test_concat_2d_axis_negative_1", - // "test_concat_2d_axis_negative_2", - // "test_concat_3d_axis_0", - // "test_concat_3d_axis_1", - // "test_concat_3d_axis_2", - // "test_concat_3d_axis_negative_1", - // "test_concat_3d_axis_negative_2", - // "test_concat_3d_axis_negative_3", + "test_concat_1d_axis_0", + "test_concat_1d_axis_negative_1", + "test_concat_2d_axis_0", + "test_concat_2d_axis_1", + "test_concat_2d_axis_negative_1", + "test_concat_2d_axis_negative_2", + "test_concat_3d_axis_0", + "test_concat_3d_axis_1", + "test_concat_3d_axis_2", + "test_concat_3d_axis_negative_1", + "test_concat_3d_axis_negative_2", + "test_concat_3d_axis_negative_3", "test_conv_with_autopad_same", "test_conv_with_strides_and_asymmetric_padding", "test_conv_with_strides_no_padding", "test_conv_with_strides_padding", // // "test_convinteger_with_padding", // // "test_convinteger_without_padding", - // // "test_convtranspose_1d", + "test_convtranspose_1d", // // "test_convtranspose_3d", - // // "test_convtranspose_autopad_same", - // // "test_convtranspose_dilations", - // // "test_convtranspose_kernel_shape", - // // "test_convtranspose_output_shape", - // // "test_convtranspose_pad", - // // "test_convtranspose_pads", - // // "test_convtranspose_with_kernel", - // // "test_convtranspose", + "test_convtranspose_autopad_same", + "test_convtranspose_dilations", + "test_convtranspose_kernel_shape", + "opset{9,17}/test_convtranspose_output_shape", + "test_convtranspose_pad", + "test_convtranspose_pads", + "test_convtranspose_with_kernel", + "test_convtranspose", "test_cos_example", "test_cos", "test_cosh_example", @@ -505,7 +506,7 @@ // // "test_dynamicquantizelinear_min_adjusted_expanded", // // "test_dynamicquantizelinear_min_adjusted", // // "test_dynamicquantizelinear", - // // "test_edge_pad", + "test_edge_pad", // "test_einsum_batch_diagonal", // "test_einsum_batch_matmul", // "test_einsum_inner_prod", @@ -517,30 +518,31 @@ // "test_equal_bcast", // "test_equal", "test_erf", - // "test_exp_example", - // "test_exp", - // "test_expand_dim_changed", - // "test_expand_dim_unchanged", + "test_exp_example", + "test_exp", + "test_expand_dim_changed", + "test_expand_dim_unchanged", // "test_eyelike_populate_off_main_diagonal", // "test_eyelike_with_dtype", // "test_eyelike_without_dtype", - // "test_flatten_axis0", - // "test_flatten_axis1", - // "test_flatten_axis2", - // "test_flatten_axis3", - // "test_flatten_default_axis", - // "test_flatten_negative_axis1", - // "test_flatten_negative_axis2", - // "test_flatten_negative_axis3", - // "test_flatten_negative_axis4", + "test_flatten_axis0", + "test_flatten_axis1", + "test_flatten_axis2", + "test_flatten_axis3", + "test_flatten_default_axis", + "test_flatten_negative_axis1", + "test_flatten_negative_axis2", + "test_flatten_negative_axis3", + "test_flatten_negative_axis4", "test_floor_example", "test_floor", - // "test_gather_0", - // "test_gather_1", - // "test_gather_2d_indices", - // "test_gather_elements_0", - // "test_gather_elements_1", - // "test_gather_elements_negative_indices", + "test_gather_0", + "test_gather_1", + "test_gather_2d_indices", + "test_gather_negative_indices", + "test_gather_elements_0", + "test_gather_elements_1", + "test_gather_elements_negative_indices", // "test_gather_negative_indices", // // "test_gathernd_example_float32", // // "test_gathernd_example_int32_batch_dim1", @@ -562,12 +564,12 @@ "test_globalaveragepool", "test_globalmaxpool_precomputed", "test_globalmaxpool", - // "test_greater_bcast", - // "test_greater_equal_bcast_expanded", - // "test_greater_equal_bcast", - // "test_greater_equal_expanded", - // "test_greater_equal", - // "test_greater", + "test_greater_bcast", + "test_greater_equal_bcast_expanded", + "test_greater_equal_bcast", + "test_greater_equal_expanded", + "test_greater_equal", + "test_greater", // // "test_gridsample_aligncorners_true", // // "test_gridsample_bicubic", // // "test_gridsample_bilinear", @@ -600,59 +602,64 @@ // // "test_hardsigmoid", // // "test_hardswish_expanded", // // "test_hardswish", - // // "test_instancenorm_epsilon", - // // "test_instancenorm_example", + "test_if", + // TODO: Uncomment 'test_if_seq' and 'test_if_opt' once the test infra + // supports Sequence and Optional types + // "test_if_seq", + // "test_if_opt", + "test_instancenorm_epsilon", + "test_instancenorm_example", // "test_isinf_negative", // "test_isinf_positive", // "test_isinf", // "test_isnan", - // // "test_layer_normalization_2d_axis_negative_1_expanded", - // // "test_layer_normalization_2d_axis_negative_1", - // // "test_layer_normalization_2d_axis_negative_2_expanded", - // // "test_layer_normalization_2d_axis_negative_2", - // // "test_layer_normalization_2d_axis0_expanded", - // // "test_layer_normalization_2d_axis0", - // // "test_layer_normalization_2d_axis1_expanded", - // // "test_layer_normalization_2d_axis1", + "test_layer_normalization_2d_axis_negative_1_expanded", + "test_layer_normalization_2d_axis_negative_1", + "test_layer_normalization_2d_axis_negative_2_expanded", + "test_layer_normalization_2d_axis_negative_2", + "test_layer_normalization_2d_axis0_expanded", + "test_layer_normalization_2d_axis0", + "test_layer_normalization_2d_axis1_expanded", + "test_layer_normalization_2d_axis1", // // "test_layer_normalization_3d_axis_negative_1_epsilon_expanded", - // // "test_layer_normalization_3d_axis_negative_1_epsilon", + "test_layer_normalization_3d_axis_negative_1_epsilon", // // "test_layer_normalization_3d_axis_negative_2_epsilon_expanded", - // // "test_layer_normalization_3d_axis_negative_2_epsilon", + "test_layer_normalization_3d_axis_negative_2_epsilon", // // "test_layer_normalization_3d_axis_negative_3_epsilon_expanded", - // // "test_layer_normalization_3d_axis_negative_3_epsilon", + "test_layer_normalization_3d_axis_negative_3_epsilon", // // "test_layer_normalization_3d_axis0_epsilon_expanded", - // // "test_layer_normalization_3d_axis0_epsilon", - // // "test_layer_normalization_3d_axis1_epsilon_expanded", - // // "test_layer_normalization_3d_axis1_epsilon", + "test_layer_normalization_3d_axis0_epsilon", + "test_layer_normalization_3d_axis1_epsilon_expanded", + "test_layer_normalization_3d_axis1_epsilon", // // "test_layer_normalization_3d_axis2_epsilon_expanded", - // // "test_layer_normalization_3d_axis2_epsilon", - // // "test_layer_normalization_4d_axis_negative_1_expanded", - // // "test_layer_normalization_4d_axis_negative_1", + "test_layer_normalization_3d_axis2_epsilon", + "test_layer_normalization_4d_axis_negative_1_expanded", + "test_layer_normalization_4d_axis_negative_1", // // "test_layer_normalization_4d_axis_negative_2_expanded", - // // "test_layer_normalization_4d_axis_negative_2", - // // "test_layer_normalization_4d_axis_negative_3_expanded", - // // "test_layer_normalization_4d_axis_negative_3", - // // "test_layer_normalization_4d_axis_negative_4_expanded", - // // "test_layer_normalization_4d_axis_negative_4", - // // "test_layer_normalization_4d_axis0_expanded", - // // "test_layer_normalization_4d_axis0", - // // "test_layer_normalization_4d_axis1_expanded", - // // "test_layer_normalization_4d_axis1", + "test_layer_normalization_4d_axis_negative_2", + "test_layer_normalization_4d_axis_negative_3_expanded", + "test_layer_normalization_4d_axis_negative_3", + "test_layer_normalization_4d_axis_negative_4_expanded", + "test_layer_normalization_4d_axis_negative_4", + "test_layer_normalization_4d_axis0_expanded", + "test_layer_normalization_4d_axis0", + "test_layer_normalization_4d_axis1_expanded", + "test_layer_normalization_4d_axis1", // // "test_layer_normalization_4d_axis2_expanded", - // // "test_layer_normalization_4d_axis2", - // // "test_layer_normalization_4d_axis3_expanded", - // // "test_layer_normalization_4d_axis3", - // // "test_layer_normalization_default_axis_expanded", - // // "test_layer_normalization_default_axis", - // "test_leakyrelu_default", - // "test_leakyrelu_example", - // "test_leakyrelu", - // "test_less_bcast", - // "test_less_equal_bcast_expanded", - // "test_less_equal_bcast", - // "test_less_equal_expanded", - // "test_less_equal", - // "test_less", + "test_layer_normalization_4d_axis2", + "test_layer_normalization_4d_axis3_expanded", + "test_layer_normalization_4d_axis3", + "test_layer_normalization_default_axis_expanded", + "test_layer_normalization_default_axis", + "test_leakyrelu_default", + "test_leakyrelu_example", + "test_leakyrelu", + "test_less_bcast", + "test_less_equal_bcast_expanded", + "test_less_equal_bcast", + "test_less_equal_expanded", + "test_less_equal", + "test_less", "test_log_example", "test_log", // // "test_logsoftmax_axis_0_expanded", @@ -838,9 +845,9 @@ // "test_nonmaxsuppression_two_batches", // "test_nonmaxsuppression_two_classes", // "test_nonzero_example", - // "test_not_2d", - // "test_not_3d", - // "test_not_4d", + "test_not_2d", + "test_not_3d", + "test_not_4d", // // "test_onehot_negative_indices", // // "test_onehot_with_axis", // // "test_onehot_with_negative_axis", @@ -884,86 +891,87 @@ // "test_range_int32_type_negative_delta", "test_reciprocal_example", "test_reciprocal", - // "test_reduce_l1_default_axes_keepdims_example", - // "test_reduce_l1_default_axes_keepdims_random", - // "test_reduce_l1_do_not_keepdims_example", - // "test_reduce_l1_do_not_keepdims_random", - // "test_reduce_l1_keep_dims_example", - // "test_reduce_l1_keep_dims_random", - // "test_reduce_l1_negative_axes_keep_dims_example", - // "test_reduce_l1_negative_axes_keep_dims_random", - // "test_reduce_l2_default_axes_keepdims_example", - // "test_reduce_l2_default_axes_keepdims_random", - // "test_reduce_l2_do_not_keepdims_example", - // "test_reduce_l2_do_not_keepdims_random", - // "test_reduce_l2_keep_dims_example", - // "test_reduce_l2_keep_dims_random", - // "test_reduce_l2_negative_axes_keep_dims_example", - // "test_reduce_l2_negative_axes_keep_dims_random", - // "test_reduce_log_sum_asc_axes", - // "test_reduce_log_sum_default", - // "test_reduce_log_sum_desc_axes", - // "test_reduce_log_sum_exp_default_axes_keepdims_example", - // "test_reduce_log_sum_exp_default_axes_keepdims_random", - // "test_reduce_log_sum_exp_do_not_keepdims_example", - // "test_reduce_log_sum_exp_do_not_keepdims_random", - // "test_reduce_log_sum_exp_keepdims_example", - // "test_reduce_log_sum_exp_keepdims_random", - // "test_reduce_log_sum_exp_negative_axes_keepdims_example", - // "test_reduce_log_sum_exp_negative_axes_keepdims_random", - // "test_reduce_log_sum_negative_axes", - // "test_reduce_log_sum", - // "test_reduce_max_default_axes_keepdim_example", - // "test_reduce_max_default_axes_keepdims_random", - // "test_reduce_max_do_not_keepdims_example", - // "test_reduce_max_do_not_keepdims_random", - // "test_reduce_max_keepdims_example", - // "test_reduce_max_keepdims_random", - // "test_reduce_max_negative_axes_keepdims_example", - // "test_reduce_max_negative_axes_keepdims_random", - // "test_reduce_mean_default_axes_keepdims_example", - // "test_reduce_mean_default_axes_keepdims_random", - // "test_reduce_mean_do_not_keepdims_example", - // "test_reduce_mean_do_not_keepdims_random", - // "test_reduce_mean_keepdims_example", - // "test_reduce_mean_keepdims_random", - // "test_reduce_mean_negative_axes_keepdims_example", - // "test_reduce_mean_negative_axes_keepdims_random", - // "test_reduce_min_default_axes_keepdims_example", - // "test_reduce_min_default_axes_keepdims_random", - // "test_reduce_min_do_not_keepdims_example", - // "test_reduce_min_do_not_keepdims_random", - // "test_reduce_min_keepdims_example", - // "test_reduce_min_keepdims_random", - // "test_reduce_min_negative_axes_keepdims_example", - // "test_reduce_min_negative_axes_keepdims_random", - // "test_reduce_prod_default_axes_keepdims_example", - // "test_reduce_prod_default_axes_keepdims_random", - // "test_reduce_prod_do_not_keepdims_example", - // "test_reduce_prod_do_not_keepdims_random", - // "test_reduce_prod_keepdims_example", - // "test_reduce_prod_keepdims_random", - // "test_reduce_prod_negative_axes_keepdims_example", - // "test_reduce_prod_negative_axes_keepdims_random", - // "test_reduce_sum_default_axes_keepdims_example", - // "test_reduce_sum_default_axes_keepdims_random", - // "test_reduce_sum_do_not_keepdims_example", - // "test_reduce_sum_do_not_keepdims_random", - // "test_reduce_sum_empty_axes_input_noop_example", - // "test_reduce_sum_empty_axes_input_noop_random", - // "test_reduce_sum_keepdims_example", - // "test_reduce_sum_keepdims_random", - // "test_reduce_sum_negative_axes_keepdims_example", - // "test_reduce_sum_negative_axes_keepdims_random", - // "test_reduce_sum_square_default_axes_keepdims_example", - // "test_reduce_sum_square_default_axes_keepdims_random", - // "test_reduce_sum_square_do_not_keepdims_example", - // "test_reduce_sum_square_do_not_keepdims_random", - // "test_reduce_sum_square_keepdims_example", - // "test_reduce_sum_square_keepdims_random", - // "test_reduce_sum_square_negative_axes_keepdims_example", - // "test_reduce_sum_square_negative_axes_keepdims_random", - // // "test_reflect_pad", + "test_reduce_l1_default_axes_keepdims_example", + "test_reduce_l1_default_axes_keepdims_random", + "test_reduce_l1_do_not_keepdims_example", + "test_reduce_l1_do_not_keepdims_random", + "test_reduce_l1_keep_dims_example", + "test_reduce_l1_keep_dims_random", + "test_reduce_l1_negative_axes_keep_dims_example", + "test_reduce_l1_negative_axes_keep_dims_random", + "test_reduce_l2_default_axes_keepdims_example", + "test_reduce_l2_default_axes_keepdims_random", + "test_reduce_l2_do_not_keepdims_example", + "test_reduce_l2_do_not_keepdims_random", + "test_reduce_l2_keep_dims_example", + "test_reduce_l2_keep_dims_random", + "test_reduce_l2_negative_axes_keep_dims_example", + "test_reduce_l2_negative_axes_keep_dims_random", + "test_reduce_log_sum_asc_axes", + "test_reduce_log_sum_default", + "test_reduce_log_sum_desc_axes", + // tests "test_reduce_log_sum_exp_*" on opset17/opset18 are excluded because they use float64. + "opset{7,8,9}/test_reduce_log_sum_exp_default_axes_keepdims_example", + "opset{7,8,9}/test_reduce_log_sum_exp_default_axes_keepdims_random", + "opset{7,8,9}/test_reduce_log_sum_exp_do_not_keepdims_example", + "opset{7,8,9}/test_reduce_log_sum_exp_do_not_keepdims_random", + "opset{7,8,9}/test_reduce_log_sum_exp_keepdims_example", + "opset{7,8,9}/test_reduce_log_sum_exp_keepdims_random", + "opset11/test_reduce_log_sum_exp_negative_axes_keepdims_example", + "opset11/test_reduce_log_sum_exp_negative_axes_keepdims_random", + "test_reduce_log_sum_negative_axes", + "test_reduce_log_sum", + "test_reduce_max_default_axes_keepdim_example", + "test_reduce_max_default_axes_keepdims_random", + "test_reduce_max_do_not_keepdims_example", + "test_reduce_max_do_not_keepdims_random", + "test_reduce_max_keepdims_example", + "test_reduce_max_keepdims_random", + "test_reduce_max_negative_axes_keepdims_example", + "test_reduce_max_negative_axes_keepdims_random", + "test_reduce_mean_default_axes_keepdims_example", + "test_reduce_mean_default_axes_keepdims_random", + "test_reduce_mean_do_not_keepdims_example", + "test_reduce_mean_do_not_keepdims_random", + "test_reduce_mean_keepdims_example", + "test_reduce_mean_keepdims_random", + "test_reduce_mean_negative_axes_keepdims_example", + "test_reduce_mean_negative_axes_keepdims_random", + "test_reduce_min_default_axes_keepdims_example", + "test_reduce_min_default_axes_keepdims_random", + "test_reduce_min_do_not_keepdims_example", + "test_reduce_min_do_not_keepdims_random", + "test_reduce_min_keepdims_example", + "test_reduce_min_keepdims_random", + "test_reduce_min_negative_axes_keepdims_example", + "test_reduce_min_negative_axes_keepdims_random", + "test_reduce_prod_default_axes_keepdims_example", + "test_reduce_prod_default_axes_keepdims_random", + "test_reduce_prod_do_not_keepdims_example", + "test_reduce_prod_do_not_keepdims_random", + "test_reduce_prod_keepdims_example", + "test_reduce_prod_keepdims_random", + "test_reduce_prod_negative_axes_keepdims_example", + "test_reduce_prod_negative_axes_keepdims_random", + "test_reduce_sum_default_axes_keepdims_example", + "test_reduce_sum_default_axes_keepdims_random", + "test_reduce_sum_do_not_keepdims_example", + "test_reduce_sum_do_not_keepdims_random", + "test_reduce_sum_empty_axes_input_noop_example", + "test_reduce_sum_empty_axes_input_noop_random", + "test_reduce_sum_keepdims_example", + "test_reduce_sum_keepdims_random", + "test_reduce_sum_negative_axes_keepdims_example", + "test_reduce_sum_negative_axes_keepdims_random", + "test_reduce_sum_square_default_axes_keepdims_example", + "test_reduce_sum_square_default_axes_keepdims_random", + "test_reduce_sum_square_do_not_keepdims_example", + "test_reduce_sum_square_do_not_keepdims_random", + "test_reduce_sum_square_keepdims_example", + "test_reduce_sum_square_keepdims_random", + "test_reduce_sum_square_negative_axes_keepdims_example", + "test_reduce_sum_square_negative_axes_keepdims_random", + "test_reflect_pad", "test_relu", // "test_reshape_allowzero_reordered", "test_reshape_extended_dims", @@ -976,34 +984,34 @@ "test_reshape_reordered_last_dims", "test_reshape_zero_and_negative_dim", "test_reshape_zero_dim", - // "test_resize_downsample_linear", - // "test_resize_downsample_nearest", - // "test_resize_downsample_scales_cubic_A_n0p5_exclude_outside", + "test_resize_downsample_linear", + "test_resize_downsample_nearest", + "test_resize_downsample_scales_cubic_A_n0p5_exclude_outside", // "test_resize_downsample_scales_cubic_align_corners", - // "test_resize_downsample_scales_cubic", + "test_resize_downsample_scales_cubic", // "test_resize_downsample_scales_linear_align_corners", - // "test_resize_downsample_scales_linear", - // "test_resize_downsample_scales_nearest", - // "test_resize_downsample_sizes_cubic", - // "test_resize_downsample_sizes_linear_pytorch_half_pixel", - // "test_resize_downsample_sizes_nearest_tf_half_pixel_for_nn", - // "test_resize_downsample_sizes_nearest", - // "test_resize_nearest", - // "test_resize_tf_crop_and_resize", - // "test_resize_upsample_linear", - // "test_resize_upsample_nearest", - // "test_resize_upsample_scales_cubic_A_n0p5_exclude_outside", - // "test_resize_upsample_scales_cubic_align_corners", - // "test_resize_upsample_scales_cubic_asymmetric", - // "test_resize_upsample_scales_cubic", - // "test_resize_upsample_scales_linear_align_corners", - // "test_resize_upsample_scales_linear", - // "test_resize_upsample_scales_nearest", - // "test_resize_upsample_sizes_cubic", - // "test_resize_upsample_sizes_nearest_ceil_half_pixel", - // "test_resize_upsample_sizes_nearest_floor_align_corners", - // "test_resize_upsample_sizes_nearest_round_prefer_ceil_asymmetric", - // "test_resize_upsample_sizes_nearest", + "test_resize_downsample_scales_linear", + "test_resize_downsample_scales_nearest", + "test_resize_downsample_sizes_cubic", + "test_resize_downsample_sizes_linear_pytorch_half_pixel", + "test_resize_downsample_sizes_nearest_tf_half_pixel_for_nn", + "test_resize_downsample_sizes_nearest", + "test_resize_nearest", + "test_resize_tf_crop_and_resize", + "test_resize_upsample_linear", + "test_resize_upsample_nearest", + "test_resize_upsample_scales_cubic_A_n0p5_exclude_outside", + "test_resize_upsample_scales_cubic_align_corners", + "test_resize_upsample_scales_cubic_asymmetric", + "test_resize_upsample_scales_cubic", + "test_resize_upsample_scales_linear_align_corners", + "test_resize_upsample_scales_linear", + "test_resize_upsample_scales_nearest", + "test_resize_upsample_sizes_cubic", + "opset{12,13,17,18}/test_resize_upsample_sizes_nearest_ceil_half_pixel", + "opset{12,13,17,18}/test_resize_upsample_sizes_nearest_floor_align_corners", + "opset{12,13,17,18}/test_resize_upsample_sizes_nearest_round_prefer_ceil_asymmetric", + "test_resize_upsample_sizes_nearest", // // "test_reversesequence_batch", // // "test_reversesequence_time", // // "test_rnn_seq_length", @@ -1121,20 +1129,20 @@ "test_sinh", // // "test_size_example", // // "test_size", - // "test_slice_default_axes", - // "test_slice_default_steps", + "test_slice_default_axes", + "test_slice_default_steps", // "test_slice_end_out_of_bounds", - // "test_slice_neg_steps", - // "test_slice_neg", - // "test_slice_negative_axes", + "test_slice_neg_steps", + "test_slice_neg", + "test_slice_negative_axes", // "test_slice_start_out_of_bounds", - // "test_slice", + "test_slice", // "test_softmax_axis_0_expanded", // "test_softmax_axis_0", // "test_softmax_axis_1_expanded", // "test_softmax_axis_1", - // "test_softmax_axis_2_expanded", - // "test_softmax_axis_2", + "test_softmax_axis_2_expanded", + "test_softmax_axis_2", // "test_softmax_cross_entropy_input_shape_is_NCd1_mean_weight_negative_ignore_index_expanded", // "test_softmax_cross_entropy_input_shape_is_NCd1_mean_weight_negative_ignore_index_log_prob_expanded", // "test_softmax_cross_entropy_input_shape_is_NCd1_mean_weight_negative_ignore_index_log_prob", @@ -1203,31 +1211,31 @@ // "test_softmax_cross_entropy_sum_log_prob_expanded", // "test_softmax_cross_entropy_sum_log_prob", // "test_softmax_cross_entropy_sum", - // "test_softmax_default_axis_expanded", - // "test_softmax_default_axis", - // "test_softmax_example_expanded", - // "test_softmax_example", - // "test_softmax_large_number_expanded", - // "test_softmax_large_number", - // "test_softmax_negative_axis_expanded", - // "test_softmax_negative_axis", + "opset13/test_softmax_default_axis_expanded", + "opset13/test_softmax_default_axis", + "test_softmax_example_expanded", + "test_softmax_example", + "test_softmax_large_number_expanded", + "test_softmax_large_number", + "test_softmax_negative_axis_expanded", + "test_softmax_negative_axis", // // "test_softplus_example", // // "test_softplus", // // "test_softsign_example", // // "test_softsign", // "test_spacetodepth_example", // "test_spacetodepth", - // // "test_split_equal_parts_1d", - // // "test_split_equal_parts_2d", - // // "test_split_equal_parts_default_axis", - // // "test_split_variable_parts_1d", - // // "test_split_variable_parts_2d", - // // "test_split_variable_parts_default_axis", + "test_split_equal_parts_1d", + "test_split_equal_parts_2d", + "test_split_equal_parts_default_axis", + "test_split_variable_parts_1d", + "test_split_variable_parts_2d", + "test_split_variable_parts_default_axis", // // "test_split_zero_size_splits", "test_sqrt_example", "test_sqrt", - // "test_squeeze_negative_axes", - // "test_squeeze", + "test_squeeze_negative_axes", + "test_squeeze", // // "test_stft_with_window", // // "test_stft", // // "test_strnormalizer_export_monday_casesensintive_lower", @@ -1254,11 +1262,11 @@ // // "test_tfidfvectorizer_tf_onlybigrams_levelempty", // // "test_tfidfvectorizer_tf_onlybigrams_skip5", // // "test_tfidfvectorizer_tf_uniandbigrams_skip5", - // "test_thresholdedrelu_default", - // "test_thresholdedrelu_example", - // "test_thresholdedrelu", - // // "test_tile_precomputed", - // // "test_tile", + "test_thresholdedrelu_default", + "test_thresholdedrelu_example", + "test_thresholdedrelu", + "test_tile_precomputed", + "test_tile", // // "test_top_k_negative_axis", // // "test_top_k_smallest", // // "test_top_k", @@ -1274,7 +1282,7 @@ "test_transpose_all_permutations_3", "test_transpose_all_permutations_4", "test_transpose_all_permutations_5", - "test_transpose_default" + "test_transpose_default", // "test_tril_neg", // "test_tril_one_row_neg", // "test_tril_out_neg", @@ -1298,15 +1306,16 @@ // // "test_unique_sorted_with_axis", // // "test_unique_sorted_with_negative_axis", // // "test_unique_sorted_without_axis", - // "test_unsqueeze_axis_0", - // "test_unsqueeze_axis_1", - // "test_unsqueeze_axis_2", - // "test_unsqueeze_axis_3", - // "test_unsqueeze_negative_axes", - // "test_unsqueeze_three_axes", - // "test_unsqueeze_two_axes", - // "test_unsqueeze_unsorted_axes", - // "test_unsqueeze", + "test_unsqueeze_axis_0", + "test_unsqueeze_axis_1", + "test_unsqueeze_axis_2", + "test_unsqueeze_axis_3", + "test_unsqueeze_negative_axes", + "test_unsqueeze_three_axes", + "test_unsqueeze_two_axes", + "test_unsqueeze_unsorted_axes", + "test_unsqueeze", + "test_wrap_pad" // "test_upsample_nearest", // "test_where_example", // "test_where_long_example", @@ -1319,7 +1328,67 @@ // "test_xor3d", // "test_xor4d" ], - "ops": [] + "ops": [ + "abs.jsonc", + "abs-int32.jsonc", + "acos.jsonc", + "add.jsonc", + "add_int32.jsonc", + //"and.jsonc", + "asin.jsonc", + "ceil.jsonc", + "concat.jsonc", + "concat_int32.jsonc", + "cast.jsonc", + "conv.jsonc", + "cos.jsonc", + "div.jsonc", + "div_int32.jsonc", + //"depth-to-space.jsonc", + "equal.jsonc", + "exp.jsonc", + "expand.jsonc", + "floor.jsonc", + "gather-elements.jsonc", + "gemm.jsonc", + "global-average-pool.jsonc", + "greater.jsonc", + "instance-norm.jsonc", + "less.jsonc", + "log.jsonc", + "matmul.jsonc", + "matmul-broadcast.jsonc", + "mul.jsonc", + "mul_int32.jsonc", + //"neg.jsonc", + "neg-int32.jsonc", + "not.jsonc", + //"or.jsonc", + "layer-norm.jsonc", + "leaky-relu.jsonc", + "reduce-min.jsonc", + "relu.jsonc", + "gelu.jsonc", + "pad.jsonc", + "pad-big.jsonc", + "pow.jsonc", + "pow_int32.jsonc", + "pow-big-number.jsonc", + "reshape.jsonc", + "skip-layer-norm.jsonc", + "slice.jsonc", + //"softmax.jsonc", + "sin.jsonc", + //"split.jsonc", + "sqrt.jsonc", + "sub.jsonc", + "sub_int32.jsonc", + "tan.jsonc", + "tile.jsonc", + "transpose.jsonc", + "transpose_int32_uint32.jsonc" + //"xor.jsonc" + ] }, "wasm": { "onnx": ["resnet50", "squeezenet", "tiny_yolov2", "emotion_ferplus"], @@ -1419,5 +1488,104 @@ "test_instancenorm_example" ], "ops": [] + }, + "webnn": { + "onnx": ["resnet50", "squeezenet", "tiny_yolov2", "emotion_ferplus"], + "node": [ + // Check in node tests that have native Wasm implementations. + // (i.e.) not tests that rely on the fallback cpu implementations. + // Use the 'cpu' level of node tests to test those implementations. + "test_add_bcast", + "test_add", + "test_sub_bcast", + "test_sub_example", + "test_sub", + "test_mul_bcast", + "test_mul_example", + "test_mul", + "test_div_bcast", + "test_div_example", + "test_div", + "test_xor_bcast3v1d", + "test_xor_bcast3v2d", + "test_xor_bcast4v2d", + "test_xor_bcast4v3d", + "test_xor_bcast4v4d", + "test_xor2d", + "test_xor3d", + "test_xor4d", + "test_or_bcast3v1d", + "test_or_bcast3v2d", + "test_or_bcast4v2d", + "test_or_bcast4v3d", + "test_or_bcast4v4d", + "test_and_bcast3v1d", + "test_and_bcast3v2d", + "test_and_bcast4v2d", + "test_and_bcast4v3d", + "test_and_bcast4v4d", + "test_and2d", + "test_and3d", + "test_and4d", + "test_prelu_broadcast", + "test_prelu_example", + "test_basic_conv_with_padding", + "test_basic_conv_without_padding", + "test_batchnorm_epsilon", + "test_batchnorm_example", + "opset{10,11,12}/test_cast_STRING_to_FLOAT", + "test_clip_splitbounds", + "test_clip_outbounds", + "test_clip_inbounds", + "test_clip_example", + "test_clip_default_min", + "test_clip_default_max", + "test_clip_default_inbounds", + "test_clip", + "test_conv_with_strides_and_asymmetric_padding", + "test_conv_with_strides_no_padding", + "test_conv_with_strides_padding", + "test_gemm_nobroadcast", + "test_gemm_broadcast", + "test_matmul_2d", + "test_matmul_3d", + "test_matmul_4d", + "test_softmax_axis_0", + "test_softmax_axis_1", + "test_softmax_axis_2", + "test_softmax_default_axis", + "test_softmax_example", + "test_softmax_large_number", + "test_sum_example", + "test_sum_one_input", + "test_sum_two_inputs", + "test_averagepool_1d_default", + "test_averagepool_2d_default", + "test_averagepool_2d_pads", + "test_averagepool_2d_precomputed_pads", + "test_averagepool_2d_precomputed_same_upper", + "test_averagepool_2d_precomputed_strides", + "test_averagepool_2d_same_upper", + "test_averagepool_2d_same_lower", + "test_averagepool_2d_strides", + "test_averagepool_3d_default", + "test_maxpool_1d_default", + "test_maxpool_2d_default", + "test_maxpool_2d_pads", + "test_maxpool_2d_precomputed_pads", + "test_maxpool_2d_precomputed_same_upper", + "test_maxpool_2d_precomputed_strides", + "test_maxpool_2d_same_lower", + "test_maxpool_2d_same_upper", + "test_maxpool_2d_strides", + "test_maxpool_3d_default", + "test_globalaveragepool_precomputed", + "test_globalaveragepool", + "test_globalmaxpool_precomputed", + "test_globalmaxpool", + "test_instancenorm_epsilon", + "test_instancenorm_example" + ], + "ops": [] } } diff --git a/js/web/test/test-main.ts b/js/web/test/test-main.ts index b4099aa1269aa..49d0ac225be2f 100644 --- a/js/web/test/test-main.ts +++ b/js/web/test/test-main.ts @@ -64,7 +64,7 @@ for (const logConfig of ORT_WEB_TEST_CONFIG.log) { Logger.set(logConfig.category, logConfig.config); } -import {ModelTestContext, OpTestContext, runModelTestSet, runOpTest} from './test-runner'; +import {ModelTestContext, OpTestContext, ProtoOpTestContext, runModelTestSet, runOpTest} from './test-runner'; import {readJsonFile} from './test-shared'; // Unit test @@ -86,14 +86,14 @@ function shouldSkipTest(test: Test.ModelTest|Test.OperatorTest) { if (!test.cases || test.cases.length === 0) { return true; } - if (!test.condition) { + if (!test.platformCondition) { return false; } if (!platform.description) { throw new Error('failed to check current platform'); } - const regex = new RegExp(test.condition); + const regex = new RegExp(test.platformCondition); return !regex.test(platform.description); } @@ -110,9 +110,9 @@ for (const group of ORT_WEB_TEST_CONFIG.model) { test, ORT_WEB_TEST_CONFIG.profile, ORT_WEB_TEST_CONFIG.options.sessionOptions); }); - after('release session', () => { + after('release session', async () => { if (context) { - context.release(); + await context.release(); } }); @@ -131,22 +131,35 @@ for (const group of ORT_WEB_TEST_CONFIG.op) { describe(`#OpTest# - ${group.name}`, () => { for (const test of group.tests) { const describeTest = shouldSkipTest(test) ? describe.skip : describe; - describeTest(`[${test.backend!}]${test.operator} - ${test.name}`, () => { - let context: OpTestContext; + const backend = test.backend!; + const useProtoOpTest = backend !== 'webgl'; + describeTest(`[${backend}]${test.operator} - ${test.name}`, () => { + let context: ProtoOpTestContext|OpTestContext; before('Initialize Context', async () => { - context = new OpTestContext(test); + context = useProtoOpTest ? new ProtoOpTestContext(test, ORT_WEB_TEST_CONFIG.options.sessionOptions) : + new OpTestContext(test); await context.init(); if (ORT_WEB_TEST_CONFIG.profile) { - OpTestContext.profiler.start(); + if (context instanceof ProtoOpTestContext) { + context.session.startProfiling(); + } else { + OpTestContext.profiler.start(); + } } }); - after('Dispose Context', () => { - if (ORT_WEB_TEST_CONFIG.profile) { - OpTestContext.profiler.stop(); + after('Dispose Context', async () => { + if (context) { + if (ORT_WEB_TEST_CONFIG.profile) { + if (context instanceof ProtoOpTestContext) { + context.session.endProfiling(); + } else { + OpTestContext.profiler.stop(); + } + } + await context.dispose(); } - context.dispose(); }); for (const testCase of test.cases) { diff --git a/js/web/test/test-runner.ts b/js/web/test/test-runner.ts index 26ebcbbd6e212..46d80a9f56f35 100644 --- a/js/web/test/test-runner.ts +++ b/js/web/test/test-runner.ts @@ -2,21 +2,21 @@ // Licensed under the MIT License. import {expect} from 'chai'; -import {readFile} from 'fs'; -import {onnx} from 'onnx-proto'; import * as ort from 'onnxruntime-common'; import {extname} from 'path'; -import {inspect, promisify} from 'util'; +import {inspect} from 'util'; import {Attribute} from '../lib/onnxjs/attribute'; import {InferenceHandler, resolveBackend, SessionHandler} from '../lib/onnxjs/backend'; import {createWebGLContext} from '../lib/onnxjs/backends/webgl/webgl-context-factory'; import {Logger, Profiler} from '../lib/onnxjs/instrument'; import {Operator} from '../lib/onnxjs/operators'; +import {onnx} from '../lib/onnxjs/ort-schema/protobuf/onnx'; import {Tensor} from '../lib/onnxjs/tensor'; import {ProtoUtil} from '../lib/onnxjs/util'; +import {tensorDataTypeStringToEnum} from '../lib/wasm/wasm-common'; -import {base64toBuffer, createMockGraph} from './test-shared'; +import {base64toBuffer, createMockGraph, readFile} from './test-shared'; import {Test} from './test-types'; // the threshold that used to compare 2 float numbers. See above for TensorResultValidator.floatEqual(). @@ -46,19 +46,8 @@ function fromInternalTensor(tensor: Tensor): ort.Tensor { return new ort.Tensor(tensor.type, tensor.data as ort.Tensor.DataType, tensor.dims); } -async function loadFile(uri: string): Promise { - if (typeof fetch === 'undefined') { - // node - return promisify(readFile)(uri); - } else { - // browser - const response = await fetch(uri); - return new Uint8Array(await response.arrayBuffer()); - } -} - async function loadTensorProto(uriOrData: string|Uint8Array, allowInt64 = false): Promise { - const buf = (typeof uriOrData === 'string') ? await loadFile(uriOrData) : uriOrData; + const buf = (typeof uriOrData === 'string') ? await readFile(uriOrData) : uriOrData; const tensorProto = onnx.TensorProto.decode(buf); let tensor: ort.Tensor; @@ -221,11 +210,12 @@ export class ModelTestContext { Logger.verbose('TestRunner.Perf', '***Perf Data End'); } - release(): void { + async release(): Promise { if (this.profile) { this.session.endProfiling(); } this.logPerfData(); + await this.session.release(); } /** @@ -311,7 +301,7 @@ export class TensorResultValidator { } else if (backend === 'webgpu') { this.absoluteThreshold = WEBGPU_THRESHOLD_ABSOLUTE_ERROR; this.relativeThreshold = WEBGPU_THRESHOLD_RELATIVE_ERROR; - } else if (backend === 'wasm' || backend === 'xnnpack') { + } else if (backend === 'wasm' || backend === 'xnnpack' || backend === 'webnn') { this.absoluteThreshold = WASM_THRESHOLD_ABSOLUTE_ERROR; this.relativeThreshold = WASM_THRESHOLD_RELATIVE_ERROR; } else if (backend === 'onnxruntime') { @@ -399,8 +389,9 @@ export class TensorResultValidator { case 'int16': case 'int32': case 'uint32': + case 'int64': case 'bool': - return this.integerEqual( + return TensorResultValidator.integerEqual( actual.numberData as number[] | Uint8Array | Int8Array | Uint16Array | Int16Array | Uint32Array | Int32Array, expected.numberData as number[] | Uint8Array | Int8Array | Uint16Array | Int16Array | Uint32Array | @@ -473,7 +464,7 @@ export class TensorResultValidator { return true; } - integerEqual( + static integerEqual( actual: number[]|Uint8Array|Int8Array|Uint16Array|Int16Array|Uint32Array|Int32Array, expected: number[]|Uint8Array|Int8Array|Uint16Array|Int16Array|Uint32Array|Int32Array): boolean { if (actual.length !== expected.length) { @@ -547,7 +538,7 @@ function initializeOperator( } /** - * a OpTestContext object contains all states in a OpTest + * a OpTestContext object contains all states in a OpTest. used for webgl backend. */ export class OpTestContext { static profiler = Profiler.create(); @@ -561,11 +552,11 @@ export class OpTestContext { } createOperator(): Operator { return initializeOperator( - this.sessionHandler, this.opTest.operator, this.opTest.attributes, - this.opTest.opsets ?? [{domain: '', version: 7}]); + this.sessionHandler, this.opTest.operator, this.opTest.attributes || [], + [this.opTest.opset ?? {domain: '', version: 7}]); } - dispose(): void { + async dispose(): Promise { this.inferenceHandler.dispose(); this.sessionHandler.dispose(); } @@ -577,6 +568,217 @@ export class OpTestContext { } } +/** + * a ProtoOpTestContext uses a protobuf model for operator test. used for ORT based backend. + */ +export class ProtoOpTestContext { + private readonly loadedData: Uint8Array; // model data, inputs, outputs + session: ort.InferenceSession; + readonly backendHint: string; + constructor(test: Test.OperatorTest, private readonly sessionOptions: ort.InferenceSession.SessionOptions = {}) { + const opsetImport = onnx.OperatorSetIdProto.create(test.opset); + const operator = test.operator; + const attribute = (test.attributes || []).map(attr => { + const protoAttr = onnx.AttributeProto.create({name: attr.name}); + switch (attr.type) { + case 'float': + protoAttr.type = onnx.AttributeProto.AttributeType.FLOAT; + protoAttr.f = attr.data as number; + break; + case 'int': + protoAttr.type = onnx.AttributeProto.AttributeType.INT; + protoAttr.i = attr.data as number; + break; + case 'string': + protoAttr.type = onnx.AttributeProto.AttributeType.STRING; + protoAttr.s = new TextEncoder().encode(attr.data as string); + break; + case 'floats': + protoAttr.type = onnx.AttributeProto.AttributeType.FLOATS; + protoAttr.floats = attr.data as number[]; + break; + case 'ints': + protoAttr.type = onnx.AttributeProto.AttributeType.INTS; + protoAttr.ints = attr.data as number[]; + break; + case 'strings': + protoAttr.type = onnx.AttributeProto.AttributeType.STRINGS; + protoAttr.strings = (attr.data as string[]).map(s => new TextEncoder().encode(s)); + break; + default: + throw new Error(`Unsupported attribute type: ${attr.type}`); + } + return protoAttr; + }); + + if (test.cases.length === 0) { + throw new Error(`No test cases found for test: ${test.name} [${test.operator}]`); + } + const inputCount = test.cases[0].inputs!.length; + const outputCount = test.cases[0].outputs!.length; + if (test.cases.some( + testCase => testCase.inputs!.length !== inputCount || testCase.outputs!.length !== outputCount)) { + throw new Error( + `Test cases for test: ${test.name} [${test.operator}] must have the same number of inputs and outputs`); + } + + const model = onnx.ModelProto.create(); + model.irVersion = onnx.Version.IR_VERSION; + model.opsetImport.push(opsetImport); + model.graph = onnx.GraphProto.create(); + + model.graph.node = [onnx.NodeProto.create({ + input: test.cases[0].inputs!.map((_, i) => `input_${i}`), + output: test.cases[0].outputs!.map((_, i) => `output_${i}`), + opType: operator, + domain: test.opset?.domain, + name: operator, + attribute + })]; + + // normalize input shape definitions + let normalizedInputShapeDefinitions: ReadonlyArray; + if (!test.inputShapeDefinitions || test.inputShapeDefinitions === 'none') { + // if inputShapeDefinitions is not specified, use undefined for all inputs + normalizedInputShapeDefinitions = new Array(inputCount).fill(undefined); + } else if (test.inputShapeDefinitions === 'rankOnly') { + // check if all test cases have data + if (test.cases.some(testCase => testCase.inputs!.some(input => !input.data || !input.dims))) { + throw new Error(`Test cases for test: ${test.name} [${ + test.operator}] must have data for each inputs when inputShapeDefinitions is 'rankOnly'`); + } + + // if inputShapeDefinitions is 'rankOnly', use semantic names for all inputs. This means only rank is specified. + normalizedInputShapeDefinitions = + test.cases[0].inputs!.map((input: Test.TensorValue, i) => input.dims.map((_, j) => `_input_${i}_d${j}`)); + + // check if all test cases have the same rank for each inputs + if (test.cases.some( + testCase => testCase.inputs!.some( + (input: Test.TensorValue, i) => + input.dims.length !== (test.cases[0].inputs![i] as Test.TensorValue).dims.length))) { + throw new Error(`Test cases for test: ${test.name} [${ + test.operator}] must have the same rank for each inputs in different test cases`); + } + } else if (test.inputShapeDefinitions === 'static') { + // check if all test cases have data + if (test.cases.some(testCase => testCase.inputs!.some(input => !input.data || !input.dims))) { + throw new Error(`Test cases for test: ${test.name} [${ + test.operator}] must have data for each inputs when inputShapeDefinitions is 'rankOnly'`); + } + + // if inputShapeDefinitions is 'static', use the shape of the first test case for all inputs. + normalizedInputShapeDefinitions = test.cases[0].inputs!.map((input: Test.TensorValue) => input.dims); + + // 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)))) { + throw new Error(`Test cases for test: ${test.name} [${ + test.operator}] must have the same shape for each inputs in different test cases`); + } + } else { + // if inputShapeDefinitions is specified as an array, use it as is. + // check if inputShapeDefinitions has the same number of inputs as test cases + if (test.inputShapeDefinitions && test.inputShapeDefinitions.length !== inputCount) { + throw new Error( + `Input shape definitions for test: ${test.name} [${test.operator}] must have the same number of inputs`); + } + normalizedInputShapeDefinitions = test.inputShapeDefinitions; + } + + model.graph.input = test.cases[0].inputs!.map((input, i) => { + const shapeDefinition = normalizedInputShapeDefinitions[i]; + const shape = shapeDefinition ? onnx.TensorShapeProto.create({ + dim: shapeDefinition.map( + dim => onnx.TensorShapeProto.Dimension.create(typeof dim === 'string' ? {dimParam: dim} : {dimValue: dim})) + }) : + undefined; + return onnx.ValueInfoProto.create({ + name: `input_${i}`, + type: onnx.TypeProto.create({ + tensorType: onnx.TypeProto.Tensor.create({elemType: tensorDataTypeStringToEnum(input.type), shape}), + }), + }); + }); + + model.graph.output = test.cases[0].outputs!.map((output, i) => onnx.ValueInfoProto.create({ + name: `output_${i}`, + type: onnx.TypeProto.create({ + tensorType: onnx.TypeProto.Tensor.create({elemType: tensorDataTypeStringToEnum(output.type)}), + }), + })); + + model.graph.name = test.name; + + this.backendHint = test.backend!; + this.loadedData = onnx.ModelProto.encode(model).finish(); + + // in debug mode, open a new tab in browser for the generated onnx model. + if (ort.env.debug) { + const modelFile = + new File([this.loadedData], `op_test_generated_model_${test.name}.onnx`, {type: 'application/octet-stream'}); + const modelTempUrl = URL.createObjectURL(modelFile); + const a = document.createElement('a'); + a.href = modelTempUrl; + a.download = modelFile.name; + a.target = '_blank'; + a.click(); + URL.revokeObjectURL(modelTempUrl); + } + } + async init(): Promise { + this.session = await ort.InferenceSession.create( + this.loadedData, {executionProviders: [this.backendHint], ...this.sessionOptions}); + } + + async dispose(): Promise { + await this.session.release(); + } +} + +async function runProtoOpTestcase( + session: ort.InferenceSession, testCase: Test.OperatorTestCase, validator: TensorResultValidator): Promise { + const feeds: Record = {}; + const fetches: string[] = []; + testCase.inputs!.forEach((input, i) => { + if (input.data) { + let data: number[]|BigUint64Array|BigInt64Array = input.data; + if (input.type === 'uint64') { + data = BigUint64Array.from(input.data.map(BigInt)); + } else if (input.type === 'int64') { + data = BigInt64Array.from(input.data.map(BigInt)); + } + feeds[`input_${i}`] = new ort.Tensor(input.type, data, input.dims); + } + }); + + const outputs: ort.Tensor[] = []; + const expectedOutputNames: string[] = []; + testCase.outputs!.forEach((output, i) => { + if (output.data) { + let data: number[]|BigUint64Array|BigInt64Array = output.data; + if (output.type === 'uint64') { + data = BigUint64Array.from(output.data.map(BigInt)); + } else if (output.type === 'int64') { + data = BigInt64Array.from(output.data.map(BigInt)); + } + outputs.push(new ort.Tensor(output.type, data, output.dims)); + expectedOutputNames.push(`output_${i}`); + fetches.push(`output_${i}`); + } + }); + + const results = await session.run(feeds, fetches); + + const actualOutputNames = Object.getOwnPropertyNames(results); + expect(actualOutputNames.length).to.equal(expectedOutputNames.length); + expect(actualOutputNames).to.have.members(expectedOutputNames); + + const actualOutputs = actualOutputNames.map(name => results[name]); + validator.checkApiTensorResult(actualOutputs, outputs); +} function createTensor(dims: number[], type: Tensor.DataType, data: number[]): Tensor { const tensor = new Tensor(dims, type); @@ -589,11 +791,11 @@ function createTensor(dims: number[], type: Tensor.DataType, data: number[]): Te async function runOpTestcase( inferenceHandler: InferenceHandler, operator: Operator, testcase: Test.OperatorTestCase, validator: TensorResultValidator): Promise { - testcase.inputs.forEach((input, i) => { + testcase.inputs.forEach((input: Test.TensorValue, i) => { Logger.verbose('TestOpRunner', ` Input '${i}': ${input.type}[${input.dims.join(',')}]`); }); - const inputTensors = - testcase.inputs.map(input => createTensor(input.dims, input.type as Tensor.DataType, input.data)); + const inputTensors = testcase.inputs.map( + (input: Test.TensorValue) => createTensor(input.dims, input.type as Tensor.DataType, input.data)); const results = operator.impl(inferenceHandler, inputTensors, operator.context); @@ -608,15 +810,20 @@ async function runOpTestcase( results.forEach((output, i) => { Logger.verbose('TestOpRunner', ` Result'${i}': ${output.type}[${output.dims.join(',')}]`); }); - const expectedTensors = - testcase.outputs.map(output => createTensor(output.dims, output.type as Tensor.DataType, output.data)); + const expectedTensors = testcase.outputs.map( + (output: Test.TensorValue) => createTensor(output.dims, output.type as Tensor.DataType, output.data)); validator.checkTensorResult(results, expectedTensors); } /** * run a single operator test case. */ -export async function runOpTest(testcase: Test.OperatorTestCase, context: OpTestContext): Promise { - await runOpTestcase( - context.inferenceHandler, context.createOperator(), testcase, new TensorResultValidator(context.backendHint)); +export async function runOpTest( + testcase: Test.OperatorTestCase, context: ProtoOpTestContext|OpTestContext): Promise { + if (context instanceof ProtoOpTestContext) { + await runProtoOpTestcase(context.session, testcase, new TensorResultValidator(context.backendHint)); + } else { + await runOpTestcase( + context.inferenceHandler, context.createOperator(), testcase, new TensorResultValidator(context.backendHint)); + } } diff --git a/js/web/test/test-shared.ts b/js/web/test/test-shared.ts index 41a485bb3dad9..68d7852ce86da 100644 --- a/js/web/test/test-shared.ts +++ b/js/web/test/test-shared.ts @@ -16,8 +16,8 @@ export function bufferToBase64(buffer: Uint8Array): string { return base64.fromByteArray(buffer); } -async function readFile(file: string) { - if (typeof fetch === 'undefined') { +export async function readFile(file: string) { + if (typeof process !== 'undefined' && process.versions && process.versions.node) { // node return promisify(fs.readFile)(file); } else { diff --git a/js/web/test/test-types.ts b/js/web/test/test-types.ts index 966b1e704a5b7..1f95d1cd8e682 100644 --- a/js/web/test/test-types.ts +++ b/js/web/test/test-types.ts @@ -29,11 +29,19 @@ export declare namespace Test { type: Tensor.Type; } + /** + * This interface represent a placeholder for an empty tensor. Should only be used in testing. + */ + interface EmptyTensorValue { + data: null; + type: Tensor.Type; + } + /** * Represent a string to describe the current environment. * Used in ModelTest and OperatorTest to determine whether to run the test or not. */ - export type Condition = string; + export type PlatformCondition = string; export interface ModelTestCase { name: string; @@ -46,7 +54,7 @@ export declare namespace Test { name: string; modelUrl: string; backend?: string; // value should be populated at build time - condition?: Condition; + platformCondition?: PlatformCondition; cases: readonly ModelTestCase[]; } @@ -57,8 +65,8 @@ export declare namespace Test { export interface OperatorTestCase { name: string; - inputs: readonly TensorValue[]; - outputs: readonly TensorValue[]; + inputs: ReadonlyArray; + outputs: ReadonlyArray; } export interface OperatorTestOpsetImport { @@ -66,13 +74,16 @@ export declare namespace Test { version: number; } + export type InputShapeDefinition = ReadonlyArray; + export interface OperatorTest { name: string; operator: string; - opsets?: readonly OperatorTestOpsetImport[]; + inputShapeDefinitions?: 'none'|'rankOnly'|'static'|ReadonlyArray; + opset?: OperatorTestOpsetImport; backend?: string; // value should be populated at build time - condition?: Condition; - attributes: readonly AttributeValue[]; + platformCondition?: PlatformCondition; + attributes?: readonly AttributeValue[]; cases: readonly OperatorTestCase[]; } @@ -86,7 +97,7 @@ export declare namespace Test { export type TestName = string; export interface TestDescription { name: string; - condition: Condition; + platformCondition: PlatformCondition; } export type Test = TestName|TestDescription; } @@ -99,6 +110,12 @@ export declare namespace Test { [backend: string]: {[group: string]: readonly TestList.Test[]}; } + interface EnvOptions extends Partial> { + wasm: Partial; + webgl: Partial; + webgpu: Partial; + } + /** * Represent ONNX Runtime Web global options */ @@ -111,7 +128,7 @@ export declare namespace Test { cudaFlags?: Record; wasmOptions?: InferenceSession.WebAssemblyExecutionProviderOption; webglOptions?: InferenceSession.WebGLExecutionProviderOption; - globalEnvFlags?: Env; + globalEnvFlags?: EnvOptions; } /** diff --git a/js/web/tsconfig.json b/js/web/tsconfig.json index 865c393b5b2b6..0a4d19af9981f 100644 --- a/js/web/tsconfig.json +++ b/js/web/tsconfig.json @@ -3,8 +3,9 @@ "compilerOptions": { "module": "CommonJS", "downlevelIteration": true, + "declaration": true, "declarationDir": "./types", - "typeRoots": ["./node_modules/@webgpu/types", "./node_modules/@types"] + "typeRoots": ["./node_modules/@webgpu/types", "./node_modules/@types", "../node_modules/@types"] }, "include": ["lib", "script", "test"], "exclude": ["lib/wasm/proxy-worker"] diff --git a/js/web/types.d.ts b/js/web/types.d.ts new file mode 100644 index 0000000000000..c6cff64c8a732 --- /dev/null +++ b/js/web/types.d.ts @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +declare module 'onnxruntime-web' { + export * from 'onnxruntime-common'; +} + +declare module 'onnxruntime-web/webgpu' { + export * from 'onnxruntime-web'; +} diff --git a/js/web/webpack.config.js b/js/web/webpack.config.js index 1c842ddced25a..81c69ffdcf6bf 100644 --- a/js/web/webpack.config.js +++ b/js/web/webpack.config.js @@ -7,12 +7,12 @@ const path = require('path'); const webpack = require('webpack'); const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; const NodePolyfillPlugin = require('node-polyfill-webpack-plugin'); -const TerserPlugin = require("terser-webpack-plugin"); +const TerserPlugin = require('terser-webpack-plugin'); const minimist = require('minimist'); // commandline args const args = minimist(process.argv); -const bundleMode = args['bundle-mode'] || 'prod'; // 'prod'|'dev'|'perf'|'node'|undefined; +const bundleMode = args['bundle-mode'] || 'prod'; // 'prod'|'dev'|'perf'|'node'|undefined; const useAnalyzer = !!args.a || !!args['use-analyzer']; // -a, --use-analyzer const filter = args.f || args.filter; @@ -45,84 +45,63 @@ function defaultTerserPluginOptions(target) { format: { comments: false, }, - compress: { - passes: 2 - }, - mangle: { - reserved: ["_scriptDir"] - } + compress: {passes: 2}, + mangle: {reserved: ['_scriptDir', 'startWorker']} } }; } const DEFAULT_BUILD_DEFS = { DISABLE_WEBGL: false, - DISABLE_WEBGPU: false, + DISABLE_WEBGPU: true, DISABLE_WASM: false, DISABLE_WASM_PROXY: false, DISABLE_WASM_THREAD: false, }; // common config for release bundle -function buildConfig({ filename, format, target, mode, devtool, build_defs }) { +function buildConfig({filename, format, target, mode, devtool, build_defs}) { const config = { target: [format === 'commonjs' ? 'node' : 'web', target], entry: path.resolve(__dirname, 'lib/index.ts'), - output: { - path: path.resolve(__dirname, 'dist'), - filename, - library: { - type: format - } - }, + output: {path: path.resolve(__dirname, 'dist'), filename, library: {type: format}}, resolve: { extensions: ['.ts', '.js'], alias: { - "util": false, + 'util': false, }, fallback: { - "crypto": false, - "fs": false, - "path": false, - "util": false, - "os": false, - "worker_threads": false, - "perf_hooks": false, + 'crypto': false, + 'fs': false, + 'path': false, + 'util': false, + 'os': false, + 'worker_threads': false, + 'perf_hooks': false, } }, plugins: [ - new webpack.DefinePlugin({ BUILD_DEFS: build_defs }), - new webpack.WatchIgnorePlugin({ paths: [/\.js$/, /\.d\.ts$/] }) + new webpack.DefinePlugin({BUILD_DEFS: build_defs}), new webpack.WatchIgnorePlugin({paths: [/\.js$/, /\.d\.ts$/]}) ], module: { - rules: [{ - test: /\.ts$/, - use: [ - { - loader: 'ts-loader', - options: { - compilerOptions: { target } - } - } - ] - }, { - test: /ort-wasm.*\.worker\.js$/, - type: 'asset/source' - }] + rules: [ + {test: /\.ts$/, use: [{loader: 'ts-loader', options: {compilerOptions: {target}}}]}, + {test: /ort-wasm.*\.worker\.js$/, type: 'asset/source'} + ] }, mode, + node: false, devtool }; if (useAnalyzer) { - config.plugins.unshift(new BundleAnalyzerPlugin({ - analyzerMode: 'static', - reportFilename: `${filename}.report.html` - })); + config.plugins.unshift( + new BundleAnalyzerPlugin({analyzerMode: 'static', reportFilename: `${filename}.report.html`})); } if (mode === 'production') { config.resolve.alias['./binding/ort-wasm-threaded.js'] = './binding/ort-wasm-threaded.min.js'; + config.resolve.alias['./binding/ort-wasm-threaded-simd.jsep.js'] = './binding/ort-wasm-threaded-simd.jsep.min.js'; config.resolve.alias['./binding/ort-wasm-threaded.worker.js'] = './binding/ort-wasm-threaded.min.worker.js'; const options = defaultTerserPluginOptions(target); @@ -132,45 +111,36 @@ function buildConfig({ filename, format, target, mode, devtool, build_defs }) { // add a custom plugin to check whether code contains 'BUILD_DEFS' config.plugins.push({ apply: (compiler) => { - compiler.hooks.afterCompile.tap( - 'Check BUILD_DEFS', - (compilation) => { - for (const filename of compilation.assetsInfo.keys()) { - if (filename.endsWith('.js')) { - const asset = compilation.assets[filename]; - if (asset) { - const content = asset.source(); - if (typeof content !== 'string') { - throw new Error(`content for target file '${filename}' is not string.`); - } - if (content.includes('DISABLE_WEBGL') - || content.includes('DISABLE_WASM') - || content.includes('DISABLE_WASM_PROXY') - || content.includes('DISABLE_WASM_THREAD')) { - throw new Error(`target file '${filename}' contains data fields from "BUILD_DEFS".`); - } + compiler.hooks.afterCompile.tap('Check BUILD_DEFS', (compilation) => { + for (const filename of compilation.assetsInfo.keys()) { + if (filename.endsWith('.js')) { + const asset = compilation.assets[filename]; + if (asset) { + const content = asset.source(); + if (typeof content !== 'string') { + throw new Error(`content for target file '${filename}' is not string.`); + } + if (content.includes('DISABLE_WEBGL') || content.includes('DISABLE_WASM') || + content.includes('DISABLE_WASM_PROXY') || content.includes('DISABLE_WASM_THREAD')) { + throw new Error(`target file '${filename}' contains data fields from "BUILD_DEFS".`); } } } - }); + } + }); } }); } else { - config.plugins.push(new webpack.BannerPlugin({ banner: COPYRIGHT_BANNER, raw: true })); + config.plugins.push(new webpack.BannerPlugin({banner: COPYRIGHT_BANNER, raw: true})); } return config; } // "ort{.min}.js" config -function buildOrtConfig({ - suffix = '', - target = 'es2017', - mode = 'production', - devtool = 'source-map', - build_defs = DEFAULT_BUILD_DEFS -}) { - const config = buildConfig({ filename: `ort${suffix}.js`, format: 'umd', target, mode, devtool, build_defs }); +function buildOrtConfig( + {suffix = '', target = 'es2017', mode = 'production', devtool = 'source-map', build_defs = DEFAULT_BUILD_DEFS}) { + const config = buildConfig({filename: `ort${suffix}.js`, format: 'umd', target, mode, devtool, build_defs}); // set global name 'ort' config.output.library.name = 'ort'; return config; @@ -185,14 +155,10 @@ function buildOrtWebConfig({ devtool = 'source-map', build_defs = DEFAULT_BUILD_DEFS }) { - const config = buildConfig({ filename: `ort-web${suffix}.js`, format, target, mode, devtool, build_defs }); + const config = buildConfig({filename: `ort-web${suffix}.js`, format, target, mode, devtool, build_defs}); // exclude onnxruntime-common from bundle config.externals = { - 'onnxruntime-common': { - commonjs: "onnxruntime-common", - commonjs2: "onnxruntime-common", - root: 'ort' - } + 'onnxruntime-common': {commonjs: 'onnxruntime-common', commonjs2: 'onnxruntime-common', root: 'ort'} }; // in nodejs, treat as external dependencies if (format === 'commonjs') { @@ -211,7 +177,8 @@ function buildTestRunnerConfig({ format = 'umd', target = 'es2017', mode = 'production', - devtool = 'source-map' + devtool = 'source-map', + build_defs = DEFAULT_BUILD_DEFS }) { const config = { target: ['web', target], @@ -219,9 +186,7 @@ function buildTestRunnerConfig({ output: { path: path.resolve(__dirname, 'test'), filename: `ort${suffix}.js`, - library: { - type: format - }, + library: {type: format}, devtoolNamespace: '', }, externals: { @@ -244,30 +209,19 @@ function buildTestRunnerConfig({ } }, plugins: [ - new webpack.DefinePlugin({ BUILD_DEFS: DEFAULT_BUILD_DEFS }), - new webpack.WatchIgnorePlugin({ paths: [/\.js$/, /\.d\.ts$/] }), - new NodePolyfillPlugin({ - excludeAliases: ["console", "Buffer"] - }), + new webpack.DefinePlugin({BUILD_DEFS: build_defs}), + new webpack.WatchIgnorePlugin({paths: [/\.js$/, /\.d\.ts$/]}), + new NodePolyfillPlugin({excludeAliases: ['console', 'Buffer']}), ], module: { - rules: [{ - test: /\.ts$/, - use: [ - { - loader: 'ts-loader', - options: { - compilerOptions: { target } - } - } - ] - }, { - test: /ort-wasm.*\.worker\.js$/, - type: 'asset/source' - }] + rules: [ + {test: /\.ts$/, use: [{loader: 'ts-loader', options: {compilerOptions: {target}}}]}, + {test: /ort-wasm.*\.worker\.js$/, type: 'asset/source'} + ] }, - mode: mode, - devtool: devtool, + mode, + node: false, + devtool, }; if (mode === 'production') { @@ -283,60 +237,85 @@ module.exports = () => { switch (bundleMode) { case 'prod': builds.push( - // ort.min.js - buildOrtConfig({ suffix: '.min' }), - // ort.js - buildOrtConfig({ mode: 'development', devtool: 'inline-source-map' }), - // ort.es6.min.js - buildOrtConfig({ suffix: '.es6.min', target: 'es6' }), - // ort.es5.min.js - buildOrtConfig({ suffix: '.es5.min', target: 'es5' }), + // ort.min.js + buildOrtConfig({suffix: '.min'}), + // ort.js + buildOrtConfig({mode: 'development', devtool: 'inline-source-map'}), + // ort.es6.min.js + buildOrtConfig({suffix: '.es6.min', target: 'es6'}), + // ort.es5.min.js + buildOrtConfig({suffix: '.es5.min', target: 'es5'}), - // ort.wasm.min.js - buildOrtConfig({ - suffix: '.wasm.min', build_defs: { - ...DEFAULT_BUILD_DEFS, - DISABLE_WEBGL: true, - } - }), - // ort.webgl.min.js - buildOrtConfig({ - suffix: '.webgl.min', build_defs: { - ...DEFAULT_BUILD_DEFS, - DISABLE_WASM: true, - } - }), - // ort.wasm-core.min.js - buildOrtConfig({ - suffix: '.wasm-core.min', build_defs: { - ...DEFAULT_BUILD_DEFS, - DISABLE_WEBGL: true, - DISABLE_WASM_PROXY: true, - DISABLE_WASM_THREAD: true, - } - }), + // ort.wasm.min.js + buildOrtConfig({ + suffix: '.wasm.min', + build_defs: { + ...DEFAULT_BUILD_DEFS, + DISABLE_WEBGL: true, + } + }), + // ort.webgl.min.js + buildOrtConfig({ + suffix: '.webgl.min', + build_defs: { + ...DEFAULT_BUILD_DEFS, + DISABLE_WASM: true, + } + }), + // ort.wasm-core.min.js + buildOrtConfig({ + suffix: '.wasm-core.min', + build_defs: { + ...DEFAULT_BUILD_DEFS, + DISABLE_WEBGL: true, + DISABLE_WASM_PROXY: true, + DISABLE_WASM_THREAD: true, + } + }), + // ort.webgpu.min.js + buildOrtConfig({ + suffix: '.webgpu.min', + build_defs: { + ...DEFAULT_BUILD_DEFS, + DISABLE_WEBGPU: false, + } + }), - // ort-web.min.js - buildOrtWebConfig({ suffix: '.min' }), - // ort-web.js - buildOrtWebConfig({ mode: 'development', devtool: 'inline-source-map' }), - // ort-web.es6.min.js - buildOrtWebConfig({ suffix: '.es6.min', target: 'es6' }), - // ort-web.es5.min.js - buildOrtWebConfig({ suffix: '.es5.min', target: 'es5' }), + // ort-web.min.js + buildOrtWebConfig({suffix: '.min'}), + // ort-web.js + buildOrtWebConfig({mode: 'development', devtool: 'inline-source-map'}), + // ort-web.es6.min.js + buildOrtWebConfig({suffix: '.es6.min', target: 'es6'}), + // ort-web.es5.min.js + buildOrtWebConfig({suffix: '.es5.min', target: 'es5'}), ); case 'node': builds.push( - // ort-web.node.js - buildOrtWebConfig({ suffix: '.node', format: 'commonjs' }), + // ort-web.node.js + buildOrtWebConfig({suffix: '.node', format: 'commonjs'}), ); break; case 'dev': - builds.push(buildTestRunnerConfig({ suffix: '.dev', mode: 'development', devtool: 'inline-source-map' })); + builds.push(buildTestRunnerConfig({ + suffix: '.dev', + mode: 'development', + devtool: 'inline-source-map', + build_defs: { + ...DEFAULT_BUILD_DEFS, + DISABLE_WEBGPU: false, + } + })); break; case 'perf': - builds.push(buildTestRunnerConfig({ suffix: '.perf' })); + builds.push(buildTestRunnerConfig({ + suffix: '.perf', + build_defs: { + ...DEFAULT_BUILD_DEFS, + DISABLE_WEBGPU: false, + } + })); break; default: throw new Error(`unsupported bundle mode: ${bundleMode}`); diff --git a/js/webpack.shared.mjs b/js/webpack.shared.mjs new file mode 100644 index 0000000000000..d1b95722ff4de --- /dev/null +++ b/js/webpack.shared.mjs @@ -0,0 +1,94 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +'use strict'; + +import webpack from 'webpack'; +import TerserPlugin from 'terser-webpack-plugin'; +import {resolve, dirname} from 'node:path'; +import {readFileSync} from 'node:fs'; +import {fileURLToPath} from 'node:url'; + +/** + * ECMAScript version for default onnxruntime JavaScript API builds + */ +export const DEFAULT_ES_VERSION = 'es2017'; + +// how to use "__dirname" in ESM: https://shramko.dev/blog/dirname-error +const __dirname = dirname(fileURLToPath(import.meta.url)); + +const terserEcmaVersionFromWebpackEsVersion = (target) => { + switch (target) { + case 'es5': + return 5; + case 'es6': + case 'es2015': + return 2015; + case 'es2017': + return 2017; + default: + throw new RangeError(`not supported ECMA version: ${target}`); + } +}; + +const getPackageFullName = (name) => { + switch (name) { + case 'common': + return `ONNX Runtime Common`; + case 'node': + return `ONNX Runtime Node.js Binding`; + case 'web': + return `ONNX Runtime Web`; + case 'react-native': + return `ONNX Runtime React-native`; + default: + throw new RangeError(`unknown package name: ${name}`); + } +}; + +/** + * Get package version by reading the file "package.json" under the package folder + * @param {'common'|'node'|'web'|'react-native'} name - the package name + * @returns a string representing the package version + */ +const getPackageVersion = (name) => { + const normalizedName = name.replace('-', '_'); + const packageJsonFileContent = readFileSync(resolve(__dirname, normalizedName, 'package.json')); + const packageJson = JSON.parse(packageJsonFileContent); + return packageJson.version; +}; + +/** + * + * @param {'development'|'production'} mode - specify webpack build mode + * @param {'common'|'node'|'web'|'react-native'} packageName - specify the name of the package + * @param {'es5'|'es6'|'es2015'|'es2017'} esVersion - specify the ECMAScript version + * @returns + */ +export const addCopyrightBannerPlugin = (mode, packageName, esVersion) => { + const COPYRIGHT_BANNER = `/*! + * ${getPackageFullName(packageName)} v${getPackageVersion(packageName)} + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + */`; + + if (mode === 'production') { + // in 'production' mode, webpack uses terser to minimize the code. + // we set options.format.preamble to make sure terser generates correct copyright banner. + return new TerserPlugin({ + extractComments: false, + terserOptions: { + ecma: terserEcmaVersionFromWebpackEsVersion(esVersion), + format: { + preamble: COPYRIGHT_BANNER, + comments: false, + }, + compress: {passes: 2} + } + }); + } else { + // in 'development' mode, webpack does not minimize the code. + // we use the webpack builtin plugin BannerPlugin to insert the banner. + return new webpack.BannerPlugin({banner: COPYRIGHT_BANNER, raw: true}); + } +}; diff --git a/objectivec/cxx_api.h b/objectivec/cxx_api.h index 3e4821c24ad5d..b57c865a92bc5 100644 --- a/objectivec/cxx_api.h +++ b/objectivec/cxx_api.h @@ -11,29 +11,28 @@ #endif // defined(__clang__) // paths are different when building the Swift Package Manager package as the headers come from the iOS pod archive +// clang-format off +#define STRINGIFY(x) #x #ifdef SPM_BUILD -#include "onnxruntime/onnxruntime_c_api.h" -#include "onnxruntime/onnxruntime_cxx_api.h" - -#if __has_include("onnxruntime/coreml_provider_factory.h") -#define ORT_OBJC_API_COREML_EP_AVAILABLE 1 -#include "onnxruntime/coreml_provider_factory.h" +#define ORT_C_CXX_HEADER_FILE_PATH(x) STRINGIFY(onnxruntime/x) #else -#define ORT_OBJC_API_COREML_EP_AVAILABLE 0 +#define ORT_C_CXX_HEADER_FILE_PATH(x) STRINGIFY(x) #endif +// clang-format on +#if __has_include(ORT_C_CXX_HEADER_FILE_PATH(onnxruntime_training_c_api.h)) +#include ORT_C_CXX_HEADER_FILE_PATH(onnxruntime_training_c_api.h) +#include ORT_C_CXX_HEADER_FILE_PATH(onnxruntime_training_cxx_api.h) #else -#include "onnxruntime_c_api.h" -#include "onnxruntime_cxx_api.h" +#include ORT_C_CXX_HEADER_FILE_PATH(onnxruntime_c_api.h) +#include ORT_C_CXX_HEADER_FILE_PATH(onnxruntime_cxx_api.h) +#endif -#if __has_include("coreml_provider_factory.h") +#if __has_include(ORT_C_CXX_HEADER_FILE_PATH(coreml_provider_factory.h)) #define ORT_OBJC_API_COREML_EP_AVAILABLE 1 -#include "coreml_provider_factory.h" +#include ORT_C_CXX_HEADER_FILE_PATH(coreml_provider_factory.h) #else #define ORT_OBJC_API_COREML_EP_AVAILABLE 0 - -#endif - #endif #if defined(__clang__) diff --git a/objectivec/cxx_utils.h b/objectivec/cxx_utils.h new file mode 100644 index 0000000000000..0b3666d3a299d --- /dev/null +++ b/objectivec/cxx_utils.h @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import + +#include +#include +#include + +#import "cxx_api.h" + +NS_ASSUME_NONNULL_BEGIN +@class ORTValue; + +namespace utils { + +NSString* toNSString(const std::string& str); +NSString* _Nullable toNullableNSString(const std::optional& str); + +std::string toStdString(NSString* str); +std::optional toStdOptionalString(NSString* _Nullable str); + +std::vector toStdStringVector(NSArray* strs); +NSArray* toNSStringNSArray(const std::vector& strs); + +NSArray* _Nullable wrapUnownedCAPIOrtValues(const std::vector& values, NSError** error); + +std::vector getWrappedCAPIOrtValues(NSArray* values); + +} // namespace utils + +NS_ASSUME_NONNULL_END diff --git a/objectivec/cxx_utils.mm b/objectivec/cxx_utils.mm new file mode 100644 index 0000000000000..01d095509b7f0 --- /dev/null +++ b/objectivec/cxx_utils.mm @@ -0,0 +1,94 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import "cxx_utils.h" + +#include +#include +#include + +#import "error_utils.h" + +#import "ort_value_internal.h" + +NS_ASSUME_NONNULL_BEGIN + +namespace utils { + +NSString* toNSString(const std::string& str) { + NSString* nsStr = [NSString stringWithUTF8String:str.c_str()]; + if (!nsStr) { + ORT_CXX_API_THROW("Failed to convert std::string to NSString", ORT_INVALID_ARGUMENT); + } + + return nsStr; +} + +NSString* _Nullable toNullableNSString(const std::optional& str) { + if (str.has_value()) { + return toNSString(*str); + } + return nil; +} + +std::string toStdString(NSString* str) { + return std::string([str UTF8String]); +} + +std::optional toStdOptionalString(NSString* _Nullable str) { + if (str) { + return std::optional([str UTF8String]); + } + return std::nullopt; +} + +std::vector toStdStringVector(NSArray* strs) { + std::vector result; + result.reserve(strs.count); + for (NSString* str in strs) { + result.push_back([str UTF8String]); + } + return result; +} + +NSArray* toNSStringNSArray(const std::vector& strs) { + NSMutableArray* result = [NSMutableArray arrayWithCapacity:strs.size()]; + for (const std::string& str : strs) { + [result addObject:toNSString(str)]; + } + return result; +} + +NSArray* _Nullable wrapUnownedCAPIOrtValues(const std::vector& CAPIValues, NSError** error) { + NSMutableArray* result = [NSMutableArray arrayWithCapacity:CAPIValues.size()]; + for (size_t i = 0; i < CAPIValues.size(); ++i) { + // Wrap the C OrtValue in a C++ Ort::Value to automatically handle its release. + // Then, transfer that C++ Ort::Value to a new ORTValue. + Ort::Value CXXAPIValue{CAPIValues[i]}; + ORTValue* val = [[ORTValue alloc] initWithCXXAPIOrtValue:std::move(CXXAPIValue) + externalTensorData:nil + error:error]; + if (!val) { + // clean up remaining C OrtValues which haven't been wrapped by a C++ Ort::Value yet + for (size_t j = i + 1; j < CAPIValues.size(); ++j) { + Ort::GetApi().ReleaseValue(CAPIValues[j]); + } + return nil; + } + [result addObject:val]; + } + return result; +} + +std::vector getWrappedCAPIOrtValues(NSArray* values) { + std::vector result; + result.reserve(values.count); + for (ORTValue* val in values) { + result.push_back(static_cast([val CXXAPIOrtValue])); + } + return result; +} + +} // namespace utils + +NS_ASSUME_NONNULL_END diff --git a/objectivec/docs/jazzy_config.yaml b/objectivec/docs/jazzy_config.yaml index 676f89d79d886..700bb9b46ef2d 100644 --- a/objectivec/docs/jazzy_config.yaml +++ b/objectivec/docs/jazzy_config.yaml @@ -4,7 +4,9 @@ author_url: https://www.onnxruntime.ai github_url: https://github.com/microsoft/onnxruntime objc: true -umbrella_header: ../include/onnxruntime.h +# Specify the training header as umbrella_header so that every public header is included. +# The training header is a superset of the inference-only header. +umbrella_header: ../include/onnxruntime_training.h framework_root: .. readme: ./main_page.md diff --git a/objectivec/error_utils.h b/objectivec/error_utils.h index 274e74aec17ff..4df71ce38dfc8 100644 --- a/objectivec/error_utils.h +++ b/objectivec/error_utils.h @@ -10,6 +10,7 @@ NS_ASSUME_NONNULL_BEGIN void ORTSaveCodeAndDescriptionToError(int code, const char* description, NSError** error); +void ORTSaveCodeAndDescriptionToError(int code, NSString* description, NSError** error); void ORTSaveOrtExceptionToError(const Ort::Exception& e, NSError** error); void ORTSaveExceptionToError(const std::exception& e, NSError** error); diff --git a/objectivec/error_utils.mm b/objectivec/error_utils.mm index 91863262cacfc..335cf8894d549 100644 --- a/objectivec/error_utils.mm +++ b/objectivec/error_utils.mm @@ -18,6 +18,14 @@ void ORTSaveCodeAndDescriptionToError(int code, const char* descriptionCstr, NSE userInfo:@{NSLocalizedDescriptionKey : description}]; } +void ORTSaveCodeAndDescriptionToError(int code, NSString* description, NSError** error) { + if (!error) return; + + *error = [NSError errorWithDomain:kOrtErrorDomain + code:code + userInfo:@{NSLocalizedDescriptionKey : description}]; +} + void ORTSaveOrtExceptionToError(const Ort::Exception& e, NSError** error) { ORTSaveCodeAndDescriptionToError(e.GetOrtErrorCode(), e.what(), error); } diff --git a/objectivec/include/onnxruntime.h b/objectivec/include/onnxruntime.h index c859f6a191807..c7bfe6ff926c9 100644 --- a/objectivec/include/onnxruntime.h +++ b/objectivec/include/onnxruntime.h @@ -5,8 +5,9 @@ // the headers below can also be imported individually #import "ort_coreml_execution_provider.h" -#import "ort_xnnpack_execution_provider.h" +#import "ort_custom_op_registration.h" #import "ort_enums.h" #import "ort_env.h" #import "ort_session.h" #import "ort_value.h" +#import "ort_xnnpack_execution_provider.h" diff --git a/objectivec/include/onnxruntime_training.h b/objectivec/include/onnxruntime_training.h new file mode 100644 index 0000000000000..504447ea6f88f --- /dev/null +++ b/objectivec/include/onnxruntime_training.h @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// this header contains the entire ONNX Runtime training Objective-C API +// the headers below can also be imported individually + +#import "onnxruntime.h" +#import "ort_checkpoint.h" +#import "ort_training_session.h" diff --git a/objectivec/include/ort_checkpoint.h b/objectivec/include/ort_checkpoint.h new file mode 100644 index 0000000000000..85e58443bffc5 --- /dev/null +++ b/objectivec/include/ort_checkpoint.h @@ -0,0 +1,119 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import +#include + +NS_ASSUME_NONNULL_BEGIN + +/** + * An ORT checkpoint is a snapshot of the state of a model at a given point in time. + * + * This class holds the entire training session state that includes model parameters, + * their gradients, optimizer parameters, and user properties. The `ORTTrainingSession` leverages the + * `ORTCheckpoint` by accessing and updating the contained training state. + * + * Available since 1.16. + * + * @note This class is only available when the training APIs are enabled. + */ +@interface ORTCheckpoint : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +/** + * Creates a checkpoint from directory on disk. + * + * @param path The path to the checkpoint directory. + * @param error Optional error information set if an error occurs. + * @return The instance, or nil if an error occurs. + * + * @warning The construction of the checkpoint state requires instantiation of `ORTEnv`. + * The intialization will fail if the `ORTEnv` is not properly initialized. + */ +- (nullable instancetype)initWithPath:(NSString*)path + error:(NSError**)error NS_DESIGNATED_INITIALIZER; + +/** + * Saves a checkpoint to directory on disk. + * + * @param path The path to the checkpoint directory. + * @param includeOptimizerState Flag to indicate whether to save the optimizer state or not. + * @param error Optional error information set if an error occurs. + * @return Whether the checkpoint was saved successfully. + */ +- (BOOL)saveCheckpointToPath:(NSString*)path + withOptimizerState:(BOOL)includeOptimizerState + error:(NSError**)error; + +/** + * Adds an int property to this checkpoint. + * + * @param name The name of the property. + * @param value The value of the property. + * @param error Optional error information set if an error occurs. + * @return Whether the property was added successfully. + */ +- (BOOL)addIntPropertyWithName:(NSString*)name + value:(int64_t)value + error:(NSError**)error; + +/** + * Adds a float property to this checkpoint. + * + * @param name The name of the property. + * @param value The value of the property. + * @param error Optional error information set if an error occurs. + * @return Whether the property was added successfully. + */ +- (BOOL)addFloatPropertyWithName:(NSString*)name + value:(float)value + error:(NSError**)error; + +/** + * Adds a string property to this checkpoint. + * + * @param name The name of the property. + * @param value The value of the property. + * @param error Optional error information set if an error occurs. + * @return Whether the property was added successfully. + */ + +- (BOOL)addStringPropertyWithName:(NSString*)name + value:(NSString*)value + error:(NSError**)error; + +/** + * Gets an int property from this checkpoint. + * + * @param name The name of the property. + * @param error Optional error information set if an error occurs. + * @return The value of the property or 0 if an error occurs. + */ +- (int64_t)getIntPropertyWithName:(NSString*)name + error:(NSError**)error __attribute__((swift_error(nonnull_error))); + +/** + * Gets a float property from this checkpoint. + * + * @param name The name of the property. + * @param error Optional error information set if an error occurs. + * @return The value of the property or 0.0f if an error occurs. + */ +- (float)getFloatPropertyWithName:(NSString*)name + error:(NSError**)error __attribute__((swift_error(nonnull_error))); + +/** + * + * Gets a string property from this checkpoint. + * + * @param name The name of the property. + * @param error Optional error information set if an error occurs. + * @return The value of the property. + */ +- (nullable NSString*)getStringPropertyWithName:(NSString*)name + error:(NSError**)error __attribute__((swift_error(nonnull_error))); + +@end + +NS_ASSUME_NONNULL_END diff --git a/objectivec/include/ort_custom_op_registration.h b/objectivec/include/ort_custom_op_registration.h new file mode 100644 index 0000000000000..8d50b92b7662a --- /dev/null +++ b/objectivec/include/ort_custom_op_registration.h @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +/** C API type forward declaration. */ +struct OrtStatus; + +/** C API type forward declaration. */ +struct OrtApiBase; + +/** C API type forward declaration. */ +struct OrtSessionOptions; + +/** + * Pointer to a custom op registration function that uses the ONNX Runtime C API. + * + * The signature is defined in the ONNX Runtime C API: + * https://github.com/microsoft/onnxruntime/blob/67f4cd54fab321d83e4a75a40efeee95a6a17079/include/onnxruntime/core/session/onnxruntime_c_api.h#L697 + * + * This is a low-level type intended for interoperating with libraries which provide such a function for custom op + * registration, such as [ONNX Runtime Extensions](https://github.com/microsoft/onnxruntime-extensions). + */ +typedef struct OrtStatus* (*ORTCAPIRegisterCustomOpsFnPtr)(struct OrtSessionOptions* /*options*/, + const struct OrtApiBase* /*api*/); diff --git a/objectivec/include/ort_enums.h b/objectivec/include/ort_enums.h index d505ce2c4e5d5..78de233972ccf 100644 --- a/objectivec/include/ort_enums.h +++ b/objectivec/include/ort_enums.h @@ -38,12 +38,13 @@ typedef NS_ENUM(int32_t, ORTTensorElementDataType) { ORTTensorElementDataTypeUInt32, ORTTensorElementDataTypeInt64, ORTTensorElementDataTypeUInt64, + ORTTensorElementDataTypeString, }; /** * The ORT graph optimization levels. * See here for more details: - * https://onnxruntime.ai/docs/performance/graph-optimizations.html + * https://onnxruntime.ai/docs/performance/model-optimizations/graph-optimizations.html */ typedef NS_ENUM(int32_t, ORTGraphOptimizationLevel) { ORTGraphOptimizationLevelNone, diff --git a/objectivec/include/ort_env.h b/objectivec/include/ort_env.h index 8c4184c26ee91..8456b57bfa402 100644 --- a/objectivec/include/ort_env.h +++ b/objectivec/include/ort_env.h @@ -16,7 +16,7 @@ extern "C" { * * Available since 1.15. */ -NSString* ORTVersion(void); +NSString* _Nullable ORTVersion(void); #ifdef __cplusplus } diff --git a/objectivec/include/ort_session.h b/objectivec/include/ort_session.h index 92269f45c4f11..1b0c47de22aaf 100644 --- a/objectivec/include/ort_session.h +++ b/objectivec/include/ort_session.h @@ -3,6 +3,7 @@ #import +#import "ort_custom_op_registration.h" #import "ort_enums.h" NS_ASSUME_NONNULL_BEGIN @@ -196,12 +197,19 @@ NS_ASSUME_NONNULL_BEGIN * Available since 1.14. * * The registration function must have the signature: - * OrtStatus* (*fn)(OrtSessionOptions* options, const OrtApiBase* api); + * `OrtStatus* (*fn)(OrtSessionOptions* options, const OrtApiBase* api);` + * + * The signature is defined in the ONNX Runtime C API: + * https://github.com/microsoft/onnxruntime/blob/67f4cd54fab321d83e4a75a40efeee95a6a17079/include/onnxruntime/core/session/onnxruntime_c_api.h#L697 * * See https://onnxruntime.ai/docs/reference/operators/add-custom-op.html for more information on custom ops. * See https://github.com/microsoft/onnxruntime/blob/342a5bf2b756d1a1fc6fdc582cfeac15182632fe/onnxruntime/test/testdata/custom_op_library/custom_op_library.cc#L115 * for an example of a custom op library registration function. * + * @note The caller must ensure that `registrationFuncName` names a valid function that is visible to the native ONNX + * Runtime code and has the correct signature. + * They must ensure that the function does what they expect it to do because this method will just call it. + * * @param registrationFuncName The name of the registration function to call. * @param error Optional error information set if an error occurs. * @return Whether the registration function was successfully called. @@ -209,6 +217,46 @@ NS_ASSUME_NONNULL_BEGIN - (BOOL)registerCustomOpsUsingFunction:(NSString*)registrationFuncName error:(NSError**)error; +/** + * Registers custom ops for use with `ORTSession`s using this SessionOptions by calling the specified function + * pointed to by `registerCustomOpsFn`. + * + * Available since 1.16. + * + * The registration function must have the signature: + * `OrtStatus* (*fn)(OrtSessionOptions* options, const OrtApiBase* api);` + * + * The signature is defined in the ONNX Runtime C API: + * https://github.com/microsoft/onnxruntime/blob/67f4cd54fab321d83e4a75a40efeee95a6a17079/include/onnxruntime/core/session/onnxruntime_c_api.h#L697 + * + * See https://onnxruntime.ai/docs/reference/operators/add-custom-op.html for more information on custom ops. + * See https://github.com/microsoft/onnxruntime/blob/342a5bf2b756d1a1fc6fdc582cfeac15182632fe/onnxruntime/test/testdata/custom_op_library/custom_op_library.cc#L115 + * for an example of a custom op library registration function. + * + * @note The caller must ensure that `registerCustomOpsFn` is a valid function pointer and has the correct signature. + * They must ensure that the function does what they expect it to do because this method will just call it. + * + * @param registerCustomOpsFn A pointer to the registration function to call. + * @param error Optional error information set if an error occurs. + * @return Whether the registration function was successfully called. + */ +- (BOOL)registerCustomOpsUsingFunctionPointer:(ORTCAPIRegisterCustomOpsFnPtr)registerCustomOpsFn + error:(NSError**)error; + +/** + * Registers ONNX Runtime Extensions custom ops that have been built in to ONNX Runtime. + * + * Available since 1.16. + * + * @note ONNX Runtime must have been built with the `--use_extensions` flag for the ONNX Runtime Extensions custom ops + * to be able to be registered with this method. When using a separate ONNX Runtime Extensions library, use + * `registerCustomOpsUsingFunctionPointer:error:` instead. + * + * @param error Optional error information set if an error occurs. + * @return Whether the ONNX Runtime Extensions custom ops were successfully registered. + */ +- (BOOL)enableOrtExtensionsCustomOpsWithError:(NSError**)error; + @end /** diff --git a/objectivec/include/ort_training_session.h b/objectivec/include/ort_training_session.h new file mode 100644 index 0000000000000..15c0137817ae2 --- /dev/null +++ b/objectivec/include/ort_training_session.h @@ -0,0 +1,263 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import +#include + +NS_ASSUME_NONNULL_BEGIN + +@class ORTCheckpoint; +@class ORTEnv; +@class ORTValue; +@class ORTSessionOptions; + +/** + * Trainer class that provides methods to train, evaluate and optimize ONNX models. + * + * The training session requires four training artifacts: + * 1. Training onnx model + * 2. Evaluation onnx model (optional) + * 3. Optimizer onnx model + * 4. Checkpoint directory + * + * [onnxruntime-training python utility](https://github.com/microsoft/onnxruntime/blob/main/orttraining/orttraining/python/training/onnxblock/README.md) + * can be used to generate above training artifacts. + * + * Available since 1.16. + * + * @note This class is only available when the training APIs are enabled. + */ +@interface ORTTrainingSession : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +/** + * Creates a training session from the training artifacts that can be used to begin or resume training. + * + * The initializer instantiates the training session based on provided env and session options, which can be used to + * begin or resume training from a given checkpoint state. The checkpoint state represents the parameters of training + * session which will be moved to the device specified in the session option if needed. + * + * @param env The `ORTEnv` instance to use for the training session. + * @param sessionOptions The `ORTSessionOptions` to use for the training session. + * @param checkpoint Training states that are used as a starting point for training. + * @param trainModelPath The path to the training onnx model. + * @param evalModelPath The path to the evaluation onnx model. + * @param optimizerModelPath The path to the optimizer onnx model used to perform gradient descent. + * @param error Optional error information set if an error occurs. + * @return The instance, or nil if an error occurs. + * + * @note Note that the training session created with a checkpoint state uses this state to store the entire training + * state (including model parameters, its gradients, the optimizer states and the properties). The training session + * keeps a strong (owning) pointer to the checkpoint state. + */ +- (nullable instancetype)initWithEnv:(ORTEnv*)env + sessionOptions:(ORTSessionOptions*)sessionOptions + checkpoint:(ORTCheckpoint*)checkpoint + trainModelPath:(NSString*)trainModelPath + evalModelPath:(nullable NSString*)evalModelPath + optimizerModelPath:(nullable NSString*)optimizerModelPath + error:(NSError**)error NS_DESIGNATED_INITIALIZER; + +/** + * Performs a training step, which is equivalent to a forward and backward propagation in a single step. + * + * The training step computes the outputs of the training model and the gradients of the trainable parameters + * for the given input values. The train step is performed based on the training model that was provided to the training session. + * It is equivalent to running forward and backward propagation in a single step. The computed gradients are stored inside + * the training session state so they can be later consumed by `optimizerStep`. The gradients can be lazily reset by + * calling `lazyResetGrad` method. + * + * @param inputs The input values to the training model. + * @param error Optional error information set if an error occurs. + * @return The output values of the training model. + */ +- (nullable NSArray*)trainStepWithInputValues:(NSArray*)inputs + error:(NSError**)error; + +/** + * Performs a evaluation step that computes the outputs of the evaluation model for the given inputs. + * The eval step is performed based on the evaluation model that was provided to the training session. + * + * @param inputs The input values to the eval model. + * @param error Optional error information set if an error occurs. + * @return The output values of the eval model. + * + */ +- (nullable NSArray*)evalStepWithInputValues:(NSArray*)inputs + error:(NSError**)error; + +/** + * Reset the gradients of all trainable parameters to zero lazily. + * + * Calling this method sets the internal state of the training session such that the gradients of the trainable parameters + * in the ORTCheckpoint will be scheduled to be reset just before the new gradients are computed on the next + * invocation of the `trainStep` method. + * + * @param error Optional error information set if an error occurs. + * @return YES if the gradients are set to reset successfully, NO otherwise. + */ +- (BOOL)lazyResetGradWithError:(NSError**)error; + +/** + * Performs the weight updates for the trainable parameters using the optimizer model. The optimizer step is performed + * based on the optimizer model that was provided to the training session. The updated parameters are stored inside the + * training state so that they can be used by the next `trainStep` method call. + * + * @param error Optional error information set if an error occurs. + * @return YES if the optimizer step was performed successfully, NO otherwise. + */ +- (BOOL)optimizerStepWithError:(NSError**)error; + +/** + * Returns the names of the user inputs for the training model that can be associated with + * the `ORTValue` provided to the `trainStep`. + * + * @param error Optional error information set if an error occurs. + * @return The names of the user inputs for the training model. + */ +- (nullable NSArray*)getTrainInputNamesWithError:(NSError**)error; + +/** + * Returns the names of the user inputs for the evaluation model that can be associated with + * the `ORTValue` provided to the `evalStep`. + * + * @param error Optional error information set if an error occurs. + * @return The names of the user inputs for the evaluation model. + */ +- (nullable NSArray*)getEvalInputNamesWithError:(NSError**)error; + +/** + * Returns the names of the user outputs for the training model that can be associated with + * the `ORTValue` returned by the `trainStep`. + * + * @param error Optional error information set if an error occurs. + * @return The names of the user outputs for the training model. + */ +- (nullable NSArray*)getTrainOutputNamesWithError:(NSError**)error; + +/** + * Returns the names of the user outputs for the evaluation model that can be associated with + * the `ORTValue` returned by the `evalStep`. + * + * @param error Optional error information set if an error occurs. + * @return The names of the user outputs for the evaluation model. + */ +- (nullable NSArray*)getEvalOutputNamesWithError:(NSError**)error; + +/** + * Registers a linear learning rate scheduler for the training session. + * + * The scheduler gradually decreases the learning rate from the initial value to zero over the course of the training. + * The decrease is performed by multiplying the current learning rate by a linearly updated factor. + * Before the decrease, the learning rate is gradually increased from zero to the initial value during a warmup phase. + * + * @param warmupStepCount The number of steps to perform the linear warmup. + * @param totalStepCount The total number of steps to perform the linear decay. + * @param initialLr The initial learning rate. + * @param error Optional error information set if an error occurs. + * @return YES if the scheduler was registered successfully, NO otherwise. + */ +- (BOOL)registerLinearLRSchedulerWithWarmupStepCount:(int64_t)warmupStepCount + totalStepCount:(int64_t)totalStepCount + initialLr:(float)initialLr + error:(NSError**)error; + +/** + * Update the learning rate based on the registered learning rate scheduler. + * + * Performs a scheduler step that updates the learning rate that is being used by the training session. + * This function should typically be called before invoking the optimizer step for each round, or as necessary + * to update the learning rate being used by the training session. + * + * @note A valid predefined learning rate scheduler must be first registered to invoke this method. + * + * @param error Optional error information set if an error occurs. + * @return YES if the scheduler step was performed successfully, NO otherwise. + */ +- (BOOL)schedulerStepWithError:(NSError**)error; + +/** + * Returns the current learning rate being used by the training session. + * + * @param error Optional error information set if an error occurs. + * @return The current learning rate or 0.0f if an error occurs. + */ +- (float)getLearningRateWithError:(NSError**)error __attribute__((swift_error(nonnull_error))); + +/** + * Sets the learning rate being used by the training session. + * + * The current learning rate is maintained by the training session and can be overwritten by invoking this method + * with the desired learning rate. This function should not be used when a valid learning rate scheduler is registered. + * It should be used either to set the learning rate derived from a custom learning rate scheduler or to set a constant + * learning rate to be used throughout the training session. + * + * @note It does not set the initial learning rate that may be needed by the predefined learning rate schedulers. + * To set the initial learning rate for learning rate schedulers, use the `registerLinearLRScheduler` method. + * + * @param lr The learning rate to be used by the training session. + * @param error Optional error information set if an error occurs. + * @return YES if the learning rate was set successfully, NO otherwise. + */ +- (BOOL)setLearningRate:(float)lr + error:(NSError**)error; + +/** + * Loads the training session model parameters from a contiguous buffer. + * + * @param buffer Contiguous buffer to load the parameters from. + * @param error Optional error information set if an error occurs. + * @return YES if the parameters were loaded successfully, NO otherwise. + */ +- (BOOL)fromBufferWithValue:(ORTValue*)buffer + error:(NSError**)error; + +/** + * Returns a contiguous buffer that holds a copy of all training state parameters. + * + * @param onlyTrainable If YES, returns a buffer that holds only the trainable parameters, otherwise returns a buffer + * that holds all the parameters. + * @param error Optional error information set if an error occurs. + * @return A contiguous buffer that holds a copy of all training state parameters. + */ +- (nullable ORTValue*)toBufferWithTrainable:(BOOL)onlyTrainable + error:(NSError**)error; + +/** + * Exports the training session model that can be used for inference. + * + * If the training session was provided with an eval model, the training session can generate an inference model if it + * knows the inference graph outputs. The input inference graph outputs are used to prune the eval model so that the + * inference model's outputs align with the provided outputs. The exported model is saved at the path provided and + * can be used for inferencing with `ORTSession`. + * + * @note The method reloads the eval model from the path provided to the initializer and expects this path to be valid. + * + * @param inferenceModelPath The path to the serialized the inference model. + * @param graphOutputNames The names of the outputs that are needed in the inference model. + * @param error Optional error information set if an error occurs. + * @return YES if the inference model was exported successfully, NO otherwise. + */ +- (BOOL)exportModelForInferenceWithOutputPath:(NSString*)inferenceModelPath + graphOutputNames:(NSArray*)graphOutputNames + error:(NSError**)error; +@end + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * This function sets the seed for generating random numbers. + * Use this function to generate reproducible results. It should be noted that completely reproducible results are not guaranteed. + * + * @param seed Manually set seed to use for random number generation. + */ +void ORTSetSeed(int64_t seed); + +#ifdef __cplusplus +} +#endif + +NS_ASSUME_NONNULL_END diff --git a/objectivec/include/ort_value.h b/objectivec/include/ort_value.h index 60a9bbed0e683..641c15ba69d2d 100644 --- a/objectivec/include/ort_value.h +++ b/objectivec/include/ort_value.h @@ -32,6 +32,21 @@ NS_ASSUME_NONNULL_BEGIN shape:(NSArray*)shape error:(NSError**)error; +/** + * Creates a value that is a string tensor. + * The string data will be copied into a buffer owned by this ORTValue instance. + * + * Available since 1.16. + * + * @param tensorStringData The tensor string data. + * @param shape The tensor shape. + * @param error Optional error information set if an error occurs. + * @return The instance, or nil if an error occurs. + */ +- (nullable instancetype)initWithTensorStringData:(NSArray*)tensorStringData + shape:(NSArray*)shape + error:(NSError**)error; + /** * Gets the type information. * @@ -63,6 +78,19 @@ NS_ASSUME_NONNULL_BEGIN */ - (nullable NSMutableData*)tensorDataWithError:(NSError**)error; +/** + * Gets the tensor string data. + * This assumes that the value is a string tensor. + * + * This returns a copy of the value's underlying string data. + * + * Available since 1.16. + * + * @param error Optional error information set if an error occurs. + * @return The copy of the tensor string data, or nil if an error occurs. + */ +- (nullable NSArray*)tensorStringDataWithError:(NSError**)error; + @end /** diff --git a/objectivec/ort_checkpoint.mm b/objectivec/ort_checkpoint.mm new file mode 100644 index 0000000000000..12386457fadf1 --- /dev/null +++ b/objectivec/ort_checkpoint.mm @@ -0,0 +1,111 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import "ort_checkpoint_internal.h" + +#include +#include +#include +#import "cxx_api.h" + +#import "error_utils.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation ORTCheckpoint { + std::optional _checkpoint; +} + +- (nullable instancetype)initWithPath:(NSString*)path + error:(NSError**)error { + if ((self = [super init]) == nil) { + return nil; + } + + try { + _checkpoint = Ort::CheckpointState::LoadCheckpoint(path.UTF8String); + return self; + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error) +} + +- (BOOL)saveCheckpointToPath:(NSString*)path + withOptimizerState:(BOOL)includeOptimizerState + error:(NSError**)error { + try { + Ort::CheckpointState::SaveCheckpoint([self CXXAPIOrtCheckpoint], path.UTF8String, includeOptimizerState); + return YES; + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error) +} + +- (BOOL)addIntPropertyWithName:(NSString*)name + value:(int64_t)value + error:(NSError**)error { + try { + [self CXXAPIOrtCheckpoint].AddProperty(name.UTF8String, value); + return YES; + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error) +} + +- (BOOL)addFloatPropertyWithName:(NSString*)name + value:(float)value + error:(NSError**)error { + try { + [self CXXAPIOrtCheckpoint].AddProperty(name.UTF8String, value); + return YES; + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error) +} + +- (BOOL)addStringPropertyWithName:(NSString*)name + value:(NSString*)value + error:(NSError**)error { + try { + [self CXXAPIOrtCheckpoint].AddProperty(name.UTF8String, value.UTF8String); + return YES; + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error) +} + +- (nullable NSString*)getStringPropertyWithName:(NSString*)name error:(NSError**)error { + try { + Ort::Property value = [self CXXAPIOrtCheckpoint].GetProperty(name.UTF8String); + if (std::string* str = std::get_if(&value)) { + return [NSString stringWithUTF8String:str->c_str()]; + } + ORT_CXX_API_THROW("Property is not a string.", ORT_INVALID_ARGUMENT); + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error) +} + +- (int64_t)getIntPropertyWithName:(NSString*)name error:(NSError**)error { + try { + Ort::Property value = [self CXXAPIOrtCheckpoint].GetProperty(name.UTF8String); + if (int64_t* i = std::get_if(&value)) { + return *i; + } + ORT_CXX_API_THROW("Property is not an integer.", ORT_INVALID_ARGUMENT); + } + ORT_OBJC_API_IMPL_CATCH(error, 0) +} + +- (float)getFloatPropertyWithName:(NSString*)name error:(NSError**)error { + try { + Ort::Property value = [self CXXAPIOrtCheckpoint].GetProperty(name.UTF8String); + if (float* f = std::get_if(&value)) { + return *f; + } + ORT_CXX_API_THROW("Property is not a float.", ORT_INVALID_ARGUMENT); + } + ORT_OBJC_API_IMPL_CATCH(error, 0.0f) +} + +- (Ort::CheckpointState&)CXXAPIOrtCheckpoint { + return *_checkpoint; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/objectivec/ort_checkpoint_internal.h b/objectivec/ort_checkpoint_internal.h new file mode 100644 index 0000000000000..3d1550cc592cf --- /dev/null +++ b/objectivec/ort_checkpoint_internal.h @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import "ort_checkpoint.h" + +#import "cxx_api.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface ORTCheckpoint () + +- (Ort::CheckpointState&)CXXAPIOrtCheckpoint; + +@end + +NS_ASSUME_NONNULL_END diff --git a/objectivec/ort_enums.mm b/objectivec/ort_enums.mm index 0144a333d1dc6..60939812df531 100644 --- a/objectivec/ort_enums.mm +++ b/objectivec/ort_enums.mm @@ -4,6 +4,7 @@ #import "ort_enums_internal.h" #include +#include #import "cxx_api.h" @@ -39,13 +40,13 @@ struct TensorElementTypeInfo { ORTTensorElementDataType type; ONNXTensorElementDataType capi_type; - size_t element_size; + std::optional element_size; }; // supported ORT tensor element data types // define the mapping from ORTTensorElementDataType to C API ONNXTensorElementDataType here constexpr TensorElementTypeInfo kElementTypeInfos[]{ - {ORTTensorElementDataTypeUndefined, ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED, 0}, + {ORTTensorElementDataTypeUndefined, ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED, std::nullopt}, {ORTTensorElementDataTypeFloat, ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, sizeof(float)}, {ORTTensorElementDataTypeInt8, ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8, sizeof(int8_t)}, {ORTTensorElementDataTypeUInt8, ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8, sizeof(uint8_t)}, @@ -53,6 +54,7 @@ {ORTTensorElementDataTypeUInt32, ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT32, sizeof(uint32_t)}, {ORTTensorElementDataTypeInt64, ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64, sizeof(int64_t)}, {ORTTensorElementDataTypeUInt64, ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT64, sizeof(uint64_t)}, + {ORTTensorElementDataTypeString, ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING, std::nullopt}, }; struct GraphOptimizationLevelInfo { @@ -119,9 +121,11 @@ ORTTensorElementDataType CAPIToPublicTensorElementType(ONNXTensorElementDataType size_t SizeOfCAPITensorElementType(ONNXTensorElementDataType capi_type) { return SelectAndTransform( kElementTypeInfos, - [capi_type](const auto& type_info) { return type_info.capi_type == capi_type; }, - [](const auto& type_info) { return type_info.element_size; }, - "unsupported tensor element type"); + [capi_type](const auto& type_info) { + return type_info.element_size.has_value() && type_info.capi_type == capi_type; + }, + [](const auto& type_info) { return *type_info.element_size; }, + "unsupported tensor element type or tensor element type does not have a known size"); } GraphOptimizationLevel PublicToCAPIGraphOptimizationLevel(ORTGraphOptimizationLevel opt_level) { diff --git a/objectivec/ort_env.mm b/objectivec/ort_env.mm index cd83ac5a85742..7043785563df5 100644 --- a/objectivec/ort_env.mm +++ b/objectivec/ort_env.mm @@ -12,9 +12,8 @@ NS_ASSUME_NONNULL_BEGIN -NSString* ORTVersion(void) { - std::string result = OrtGetApiBase()->GetVersionString(); - return [NSString stringWithUTF8String:result.c_str()]; +NSString* _Nullable ORTVersion(void) { + return [NSString stringWithUTF8String:OrtGetApiBase()->GetVersionString()]; } @implementation ORTEnv { diff --git a/objectivec/ort_session.mm b/objectivec/ort_session.mm index c4f57b0a6fae2..d27c3e2cefcfb 100644 --- a/objectivec/ort_session.mm +++ b/objectivec/ort_session.mm @@ -66,22 +66,26 @@ - (BOOL)runWithInputs:(NSDictionary*)inputs } std::vector inputNames, outputNames; - std::vector inputValues; - std::vector outputValues; + std::vector inputCAPIValues; + std::vector outputCAPIValues; + inputNames.reserve(inputs.count); + inputCAPIValues.reserve(inputs.count); for (NSString* inputName in inputs) { inputNames.push_back(inputName.UTF8String); - inputValues.push_back(static_cast([inputs[inputName] CXXAPIOrtValue])); + inputCAPIValues.push_back(static_cast([inputs[inputName] CXXAPIOrtValue])); } + outputNames.reserve(outputs.count); + outputCAPIValues.reserve(outputs.count); for (NSString* outputName in outputs) { outputNames.push_back(outputName.UTF8String); - outputValues.push_back(static_cast([outputs[outputName] CXXAPIOrtValue])); + outputCAPIValues.push_back(static_cast([outputs[outputName] CXXAPIOrtValue])); } Ort::ThrowOnError(Ort::GetApi().Run(*_session, [runOptions CXXAPIOrtRunOptions], - inputNames.data(), inputValues.data(), inputNames.size(), - outputNames.data(), outputNames.size(), outputValues.data())); + inputNames.data(), inputCAPIValues.data(), inputNames.size(), + outputNames.data(), outputNames.size(), outputCAPIValues.data())); return YES; } @@ -103,30 +107,39 @@ - (BOOL)runWithInputs:(NSDictionary*)inputs NSArray* outputNameArray = outputNameSet.allObjects; std::vector inputNames, outputNames; - std::vector inputValues; - std::vector outputValues; + std::vector inputCAPIValues; + std::vector outputCAPIValues; + inputNames.reserve(inputs.count); + inputCAPIValues.reserve(inputs.count); for (NSString* inputName in inputs) { inputNames.push_back(inputName.UTF8String); - inputValues.push_back(static_cast([inputs[inputName] CXXAPIOrtValue])); + inputCAPIValues.push_back(static_cast([inputs[inputName] CXXAPIOrtValue])); } + outputNames.reserve(outputNameArray.count); + outputCAPIValues.reserve(outputNameArray.count); for (NSString* outputName in outputNameArray) { outputNames.push_back(outputName.UTF8String); - outputValues.push_back(nullptr); + outputCAPIValues.push_back(nullptr); } Ort::ThrowOnError(Ort::GetApi().Run(*_session, [runOptions CXXAPIOrtRunOptions], - inputNames.data(), inputValues.data(), inputNames.size(), - outputNames.data(), outputNames.size(), outputValues.data())); + inputNames.data(), inputCAPIValues.data(), inputNames.size(), + outputNames.data(), outputNames.size(), outputCAPIValues.data())); NSMutableDictionary* outputs = [[NSMutableDictionary alloc] init]; for (NSUInteger i = 0; i < outputNameArray.count; ++i) { - ORTValue* outputValue = [[ORTValue alloc] initWithCAPIOrtValue:outputValues[i] externalTensorData:nil error:error]; + // Wrap the C OrtValue in a C++ Ort::Value to automatically handle its release. + // Then, transfer that C++ Ort::Value to a new ORTValue. + Ort::Value outputCXXAPIValue{outputCAPIValues[i]}; + ORTValue* outputValue = [[ORTValue alloc] initWithCXXAPIOrtValue:std::move(outputCXXAPIValue) + externalTensorData:nil + error:error]; if (!outputValue) { - // clean up remaining C API OrtValues which haven't been wrapped by an ORTValue yet - for (NSUInteger j = i; j < outputNameArray.count; ++j) { - Ort::GetApi().ReleaseValue(outputValues[j]); + // clean up remaining C OrtValues which haven't been wrapped by a C++ Ort::Value yet + for (NSUInteger j = i + 1; j < outputNameArray.count; ++j) { + Ort::GetApi().ReleaseValue(outputCAPIValues[j]); } return nil; } @@ -296,6 +309,27 @@ - (BOOL)registerCustomOpsUsingFunction:(NSString*)registrationFuncName ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error) } +- (BOOL)registerCustomOpsUsingFunctionPointer:(ORTCAPIRegisterCustomOpsFnPtr)registerCustomOpsFn + error:(NSError**)error { + try { + if (!registerCustomOpsFn) { + ORT_CXX_API_THROW("registerCustomOpsFn must not be null", ORT_INVALID_ARGUMENT); + } + Ort::ThrowOnError((*registerCustomOpsFn)(static_cast(*_sessionOptions), + OrtGetApiBase())); + return YES; + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error) +} + +- (BOOL)enableOrtExtensionsCustomOpsWithError:(NSError**)error { + try { + _sessionOptions->EnableOrtCustomOps(); + return YES; + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error) +} + #pragma mark - Internal - (Ort::SessionOptions&)CXXAPIOrtSessionOptions { diff --git a/objectivec/ort_training_session.mm b/objectivec/ort_training_session.mm new file mode 100644 index 0000000000000..285151b412bf0 --- /dev/null +++ b/objectivec/ort_training_session.mm @@ -0,0 +1,224 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import "ort_training_session_internal.h" + +#import +#import +#import + +#import "cxx_api.h" +#import "cxx_utils.h" +#import "error_utils.h" +#import "ort_checkpoint_internal.h" +#import "ort_session_internal.h" +#import "ort_enums_internal.h" +#import "ort_env_internal.h" +#import "ort_value_internal.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation ORTTrainingSession { + std::optional _session; + ORTCheckpoint* _checkpoint; +} + +- (Ort::TrainingSession&)CXXAPIOrtTrainingSession { + return *_session; +} + +- (nullable instancetype)initWithEnv:(ORTEnv*)env + sessionOptions:(ORTSessionOptions*)sessionOptions + checkpoint:(ORTCheckpoint*)checkpoint + trainModelPath:(NSString*)trainModelPath + evalModelPath:(nullable NSString*)evalModelPath + optimizerModelPath:(nullable NSString*)optimizerModelPath + error:(NSError**)error { + if ((self = [super init]) == nil) { + return nil; + } + + try { + std::optional evalPath = utils::toStdOptionalString(evalModelPath); + std::optional optimizerPath = utils::toStdOptionalString(optimizerModelPath); + + _checkpoint = checkpoint; + _session = Ort::TrainingSession{ + [env CXXAPIOrtEnv], + [sessionOptions CXXAPIOrtSessionOptions], + [checkpoint CXXAPIOrtCheckpoint], + trainModelPath.UTF8String, + evalPath, + optimizerPath}; + return self; + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error) +} + +- (nullable NSArray*)trainStepWithInputValues:(NSArray*)inputs + error:(NSError**)error { + try { + std::vector inputValues = utils::getWrappedCAPIOrtValues(inputs); + + size_t outputCount; + Ort::ThrowOnError(Ort::GetTrainingApi().TrainingSessionGetTrainingModelOutputCount(*_session, &outputCount)); + std::vector outputValues(outputCount, nullptr); + + Ort::RunOptions runOptions; + Ort::ThrowOnError(Ort::GetTrainingApi().TrainStep( + *_session, + runOptions, + inputValues.size(), + inputValues.data(), + outputValues.size(), + outputValues.data())); + + return utils::wrapUnownedCAPIOrtValues(outputValues, error); + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error) +} +- (nullable NSArray*)evalStepWithInputValues:(NSArray*)inputs + error:(NSError**)error { + try { + // create vector of OrtValue from NSArray with same size as inputValues + std::vector inputValues = utils::getWrappedCAPIOrtValues(inputs); + + size_t outputCount; + Ort::ThrowOnError(Ort::GetTrainingApi().TrainingSessionGetEvalModelOutputCount(*_session, &outputCount)); + std::vector outputValues(outputCount, nullptr); + + Ort::RunOptions runOptions; + Ort::ThrowOnError(Ort::GetTrainingApi().EvalStep( + *_session, + runOptions, + inputValues.size(), + inputValues.data(), + outputValues.size(), + outputValues.data())); + + return utils::wrapUnownedCAPIOrtValues(outputValues, error); + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error) +} + +- (BOOL)lazyResetGradWithError:(NSError**)error { + try { + [self CXXAPIOrtTrainingSession].LazyResetGrad(); + return YES; + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error) +} + +- (BOOL)optimizerStepWithError:(NSError**)error { + try { + [self CXXAPIOrtTrainingSession].OptimizerStep(); + return YES; + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error) +} + +- (nullable NSArray*)getTrainInputNamesWithError:(NSError**)error { + try { + std::vector inputNames = [self CXXAPIOrtTrainingSession].InputNames(true); + return utils::toNSStringNSArray(inputNames); + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error) +} + +- (nullable NSArray*)getTrainOutputNamesWithError:(NSError**)error { + try { + std::vector outputNames = [self CXXAPIOrtTrainingSession].OutputNames(true); + return utils::toNSStringNSArray(outputNames); + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error) +} + +- (nullable NSArray*)getEvalInputNamesWithError:(NSError**)error { + try { + std::vector inputNames = [self CXXAPIOrtTrainingSession].InputNames(false); + return utils::toNSStringNSArray(inputNames); + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error) +} + +- (nullable NSArray*)getEvalOutputNamesWithError:(NSError**)error { + try { + std::vector outputNames = [self CXXAPIOrtTrainingSession].OutputNames(false); + return utils::toNSStringNSArray(outputNames); + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error) +} + +- (BOOL)registerLinearLRSchedulerWithWarmupStepCount:(int64_t)warmupStepCount + totalStepCount:(int64_t)totalStepCount + initialLr:(float)initialLr + error:(NSError**)error { + try { + [self CXXAPIOrtTrainingSession].RegisterLinearLRScheduler(warmupStepCount, totalStepCount, initialLr); + return YES; + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error) +} + +- (BOOL)schedulerStepWithError:(NSError**)error { + try { + [self CXXAPIOrtTrainingSession].SchedulerStep(); + return YES; + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error) +} + +- (float)getLearningRateWithError:(NSError**)error { + try { + return [self CXXAPIOrtTrainingSession].GetLearningRate(); + } + ORT_OBJC_API_IMPL_CATCH(error, 0.0f); +} + +- (BOOL)setLearningRate:(float)lr + error:(NSError**)error { + try { + [self CXXAPIOrtTrainingSession].SetLearningRate(lr); + return YES; + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error) +} + +- (BOOL)fromBufferWithValue:(ORTValue*)buffer + error:(NSError**)error { + try { + [self CXXAPIOrtTrainingSession].FromBuffer([buffer CXXAPIOrtValue]); + return YES; + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error) +} + +- (nullable ORTValue*)toBufferWithTrainable:(BOOL)onlyTrainable + error:(NSError**)error { + try { + Ort::Value val = [self CXXAPIOrtTrainingSession].ToBuffer(onlyTrainable); + return [[ORTValue alloc] initWithCXXAPIOrtValue:std::move(val) + externalTensorData:nil + error:error]; + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error) +} + +- (BOOL)exportModelForInferenceWithOutputPath:(NSString*)inferenceModelPath + graphOutputNames:(NSArray*)graphOutputNames + error:(NSError**)error { + try { + [self CXXAPIOrtTrainingSession].ExportModelForInferencing(utils::toStdString(inferenceModelPath), + utils::toStdStringVector(graphOutputNames)); + return YES; + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error) +} + +@end + +void ORTSetSeed(int64_t seed) { + Ort::SetSeed(seed); +} + +NS_ASSUME_NONNULL_END diff --git a/objectivec/ort_training_session_internal.h b/objectivec/ort_training_session_internal.h new file mode 100644 index 0000000000000..453c941d5f513 --- /dev/null +++ b/objectivec/ort_training_session_internal.h @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import "ort_training_session.h" + +#import "cxx_api.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface ORTTrainingSession () + +- (Ort::TrainingSession&)CXXAPIOrtTrainingSession; + +@end + +NS_ASSUME_NONNULL_END diff --git a/objectivec/ort_value.mm b/objectivec/ort_value.mm index ce77ca752c246..b9dc1a9885c61 100644 --- a/objectivec/ort_value.mm +++ b/objectivec/ort_value.mm @@ -71,6 +71,12 @@ - (nullable instancetype)initWithTensorData:(NSMutableData*)tensorData shape:(NSArray*)shape error:(NSError**)error { try { + if (elementType == ORTTensorElementDataTypeString) { + ORT_CXX_API_THROW( + "ORTTensorElementDataTypeString element type provided. " + "Please call initWithTensorStringData:shape:error: instead to create an ORTValue with string data.", + ORT_INVALID_ARGUMENT); + } const auto memoryInfo = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU); const auto ONNXElementType = PublicToCAPITensorElementType(elementType); const auto shapeVector = [shape]() { @@ -85,9 +91,49 @@ - (nullable instancetype)initWithTensorData:(NSMutableData*)tensorData memoryInfo, tensorData.mutableBytes, tensorData.length, shapeVector.data(), shapeVector.size(), ONNXElementType); - return [self initWithCAPIOrtValue:ortValue.release() - externalTensorData:tensorData - error:error]; + return [self initWithCXXAPIOrtValue:std::move(ortValue) + externalTensorData:tensorData + error:error]; + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error) +} + +- (nullable instancetype)initWithTensorStringData:(NSArray*)tensorStringData + shape:(NSArray*)shape + error:(NSError**)error { + try { + Ort::AllocatorWithDefaultOptions allocator; + size_t tensorSize = 1U; + const auto shapeVector = [&tensorSize, shape]() { + std::vector result{}; + result.reserve(shape.count); + for (NSNumber* dim in shape) { + const auto dimValue = dim.longLongValue; + if (dimValue < 0 || !SafeMultiply(static_cast(dimValue), tensorSize, tensorSize)) { + ORT_CXX_API_THROW("Failed to compute the tensor size.", ORT_RUNTIME_EXCEPTION); + } + result.push_back(dimValue); + } + return result; + }(); + + if (tensorSize != [tensorStringData count]) { + ORT_CXX_API_THROW( + "Computed tensor size does not equal the length of the provided tensor string data.", + ORT_INVALID_ARGUMENT); + } + + Ort::Value ortValue = Ort::Value::CreateTensor( + allocator, shapeVector.data(), shapeVector.size(), ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING); + + size_t index = 0; + for (NSString* stringData in tensorStringData) { + ortValue.FillStringTensorElement([stringData UTF8String], index++); + } + + return [self initWithCXXAPIOrtValue:std::move(ortValue) + externalTensorData:nil + error:error]; } ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error) } @@ -110,6 +156,12 @@ - (nullable ORTTensorTypeAndShapeInfo*)tensorTypeAndShapeInfoWithError:(NSError* - (nullable NSMutableData*)tensorDataWithError:(NSError**)error { try { const auto tensorTypeAndShapeInfo = _typeInfo->GetTensorTypeAndShapeInfo(); + if (tensorTypeAndShapeInfo.GetElementType() == ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING) { + ORT_CXX_API_THROW( + "This ORTValue holds string data. Please call tensorStringDataWithError: " + "instead to retrieve the string data from this ORTValue.", + ORT_RUNTIME_EXCEPTION); + } const size_t elementCount = tensorTypeAndShapeInfo.GetElementCount(); const size_t elementSize = SizeOfCAPITensorElementType(tensorTypeAndShapeInfo.GetElementType()); size_t rawDataLength; @@ -127,19 +179,44 @@ - (nullable NSMutableData*)tensorDataWithError:(NSError**)error { ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error) } +- (nullable NSArray*)tensorStringDataWithError:(NSError**)error { + try { + const auto tensorTypeAndShapeInfo = _typeInfo->GetTensorTypeAndShapeInfo(); + const size_t elementCount = tensorTypeAndShapeInfo.GetElementCount(); + const size_t tensorStringDataLength = _value->GetStringTensorDataLength(); + std::vector tensorStringData(tensorStringDataLength, '\0'); + std::vector offsets(elementCount); + _value->GetStringTensorContent(tensorStringData.data(), tensorStringDataLength, + offsets.data(), offsets.size()); + + NSMutableArray* result = [NSMutableArray arrayWithCapacity:elementCount]; + for (size_t idx = 0; idx < elementCount; ++idx) { + const size_t strLength = (idx == elementCount - 1) ? tensorStringDataLength - offsets[idx] + : offsets[idx + 1] - offsets[idx]; + [result addObject:[[NSString alloc] initWithBytes:tensorStringData.data() + offsets[idx] + length:strLength + encoding:NSUTF8StringEncoding]]; + } + return result; + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error) +} + #pragma mark - Internal -- (nullable instancetype)initWithCAPIOrtValue:(OrtValue*)CAPIOrtValue - externalTensorData:(nullable NSMutableData*)externalTensorData - error:(NSError**)error { +- (nullable instancetype)initWithCXXAPIOrtValue:(Ort::Value&&)existingCXXAPIOrtValue + externalTensorData:(nullable NSMutableData*)externalTensorData + error:(NSError**)error { if ((self = [super init]) == nil) { return nil; } try { - _value = Ort::Value{CAPIOrtValue}; - _typeInfo = _value->GetTypeInfo(); + _typeInfo = existingCXXAPIOrtValue.GetTypeInfo(); _externalTensorData = externalTensorData; + + // transfer C++ Ort::Value ownership to this instance + _value = std::move(existingCXXAPIOrtValue); return self; } ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error); diff --git a/objectivec/ort_value_internal.h b/objectivec/ort_value_internal.h index 345c0fcaf810a..6bc2e9b59309a 100644 --- a/objectivec/ort_value_internal.h +++ b/objectivec/ort_value_internal.h @@ -9,9 +9,18 @@ NS_ASSUME_NONNULL_BEGIN @interface ORTValue () -- (nullable instancetype)initWithCAPIOrtValue:(OrtValue*)CAPIOrtValue - externalTensorData:(nullable NSMutableData*)externalTensorData - error:(NSError**)error NS_DESIGNATED_INITIALIZER; +/** + * Creates a value from an existing C++ API Ort::Value and takes ownership from it. + * Note: Ownership is guaranteed to be transferred on success but not otherwise. + * + * @param existingCXXAPIOrtValue The existing C++ API Ort::Value. + * @param externalTensorData Any external tensor data referenced by `existingCXXAPIOrtValue`. + * @param error Optional error information set if an error occurs. + * @return The instance, or nil if an error occurs. + */ +- (nullable instancetype)initWithCXXAPIOrtValue:(Ort::Value&&)existingCXXAPIOrtValue + externalTensorData:(nullable NSMutableData*)externalTensorData + error:(NSError**)error NS_DESIGNATED_INITIALIZER; - (Ort::Value&)CXXAPIOrtValue; diff --git a/objectivec/test/assertion_utils.h b/objectivec/test/assertion_utils.h index f2b73e6d5366c..2b72435b95494 100644 --- a/objectivec/test/assertion_utils.h +++ b/objectivec/test/assertion_utils.h @@ -29,4 +29,18 @@ NS_ASSUME_NONNULL_BEGIN XCTAssertNotNil(error); \ } while (0) +#define ORTAssertEqualFloatAndNoError(expected, result, error) \ + do { \ + XCTAssertEqualWithAccuracy(expected, result, 1e-3f, @"Expected %f but got %f. Error:%@", expected, result, error); \ + XCTAssertNil(error); \ + } while (0) + +#define ORTAssertEqualFloatArrays(expected, result) \ + do { \ + XCTAssertEqual(expected.count, result.count); \ + for (size_t i = 0; i < expected.count; ++i) { \ + XCTAssertEqualWithAccuracy([expected[i] floatValue], [result[i] floatValue], 1e-3f); \ + } \ + } while (0) + NS_ASSUME_NONNULL_END diff --git a/objectivec/test/ort_checkpoint_test.mm b/objectivec/test/ort_checkpoint_test.mm new file mode 100644 index 0000000000000..9b2196fabbe0d --- /dev/null +++ b/objectivec/test/ort_checkpoint_test.mm @@ -0,0 +1,117 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import + +#import "ort_checkpoint.h" +#import "ort_training_session.h" +#import "ort_env.h" +#import "ort_session.h" + +#import "test/test_utils.h" +#import "test/assertion_utils.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface ORTCheckpointTest : XCTestCase +@property(readonly, nullable) ORTEnv* ortEnv; +@end + +@implementation ORTCheckpointTest + +- (void)setUp { + [super setUp]; + + self.continueAfterFailure = NO; + + NSError* err = nil; + _ortEnv = [[ORTEnv alloc] initWithLoggingLevel:ORTLoggingLevelWarning + error:&err]; + ORTAssertNullableResultSuccessful(_ortEnv, err); +} + ++ (NSString*)getCheckpointPath { + NSBundle* bundle = [NSBundle bundleForClass:[ORTCheckpointTest class]]; + NSString* path = [[bundle resourcePath] stringByAppendingPathComponent:@"checkpoint.ckpt"]; + return path; +} + ++ (NSString*)getTrainingModelPath { + NSBundle* bundle = [NSBundle bundleForClass:[ORTCheckpointTest class]]; + NSString* path = [[bundle resourcePath] stringByAppendingPathComponent:@"training_model.onnx"]; + return path; +} + +- (void)testSaveCheckpoint { + NSError* error = nil; + ORTCheckpoint* checkpoint = [[ORTCheckpoint alloc] initWithPath:[ORTCheckpointTest getCheckpointPath] error:&error]; + ORTAssertNullableResultSuccessful(checkpoint, error); + + // save checkpoint + NSString* path = [test_utils::createTemporaryDirectory(self) stringByAppendingPathComponent:@"save_checkpoint.ckpt"]; + XCTAssertNotNil(path); + BOOL result = [checkpoint saveCheckpointToPath:path withOptimizerState:NO error:&error]; + + ORTAssertBoolResultSuccessful(result, error); +} + +- (void)testInitCheckpoint { + NSError* error = nil; + ORTCheckpoint* checkpoint = [[ORTCheckpoint alloc] initWithPath:[ORTCheckpointTest getCheckpointPath] error:&error]; + ORTAssertNullableResultSuccessful(checkpoint, error); +} + +- (void)testIntProperty { + NSError* error = nil; + // Load checkpoint + ORTCheckpoint* checkpoint = [[ORTCheckpoint alloc] initWithPath:[ORTCheckpointTest getCheckpointPath] error:&error]; + ORTAssertNullableResultSuccessful(checkpoint, error); + + // Add property + BOOL result = [checkpoint addIntPropertyWithName:@"test" value:314 error:&error]; + ORTAssertBoolResultSuccessful(result, error); + + // Get property + int64_t value = [checkpoint getIntPropertyWithName:@"test" error:&error]; + XCTAssertEqual(value, 314); +} + +- (void)testFloatProperty { + NSError* error = nil; + // Load checkpoint + ORTCheckpoint* checkpoint = [[ORTCheckpoint alloc] initWithPath:[ORTCheckpointTest getCheckpointPath] error:&error]; + ORTAssertNullableResultSuccessful(checkpoint, error); + + // Add property + BOOL result = [checkpoint addFloatPropertyWithName:@"test" value:3.14f error:&error]; + ORTAssertBoolResultSuccessful(result, error); + + // Get property + float value = [checkpoint getFloatPropertyWithName:@"test" error:&error]; + XCTAssertEqual(value, 3.14f); +} + +- (void)testStringProperty { + NSError* error = nil; + // Load checkpoint + ORTCheckpoint* checkpoint = [[ORTCheckpoint alloc] initWithPath:[ORTCheckpointTest getCheckpointPath] error:&error]; + ORTAssertNullableResultSuccessful(checkpoint, error); + + // Add property + BOOL result = [checkpoint addStringPropertyWithName:@"test" value:@"hello" error:&error]; + ORTAssertBoolResultSuccessful(result, error); + + // Get property + NSString* value = [checkpoint getStringPropertyWithName:@"test" error:&error]; + XCTAssertEqualObjects(value, @"hello"); +} + +- (void)tearDown { + _ortEnv = nil; + + [super tearDown]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/objectivec/test/ort_session_test.mm b/objectivec/test/ort_session_test.mm index 790ad1c04f294..f00f5db2f995f 100644 --- a/objectivec/test/ort_session_test.mm +++ b/objectivec/test/ort_session_test.mm @@ -50,6 +50,13 @@ + (NSString*)getAddModelPath { return path; } ++ (NSString*)getStringModelPath { + NSBundle* bundle = [NSBundle bundleForClass:[ORTSessionTest class]]; + NSString* path = [bundle pathForResource:@"identity_string" + ofType:@"ort"]; + return path; +} + + (NSMutableData*)dataWithScalarFloat:(float)value { NSMutableData* data = [[NSMutableData alloc] initWithBytes:&value length:sizeof(value)]; return data; @@ -238,6 +245,56 @@ - (void)testAppendXnnpackEP { error:&err]; ORTAssertNullableResultSuccessful(session, err); } + +static bool gDummyRegisterCustomOpsFnCalled = false; + +static OrtStatus* _Nullable DummyRegisterCustomOpsFn(OrtSessionOptions* /*session_options*/, + const OrtApiBase* /*api*/) { + gDummyRegisterCustomOpsFnCalled = true; + return nullptr; +} + +- (void)testRegisterCustomOpsUsingFunctionPointer { + NSError* err = nil; + ORTSessionOptions* sessionOptions = [ORTSessionTest makeSessionOptions]; + + gDummyRegisterCustomOpsFnCalled = false; + BOOL registerResult = [sessionOptions registerCustomOpsUsingFunctionPointer:&DummyRegisterCustomOpsFn + error:&err]; + ORTAssertBoolResultSuccessful(registerResult, err); + + XCTAssertEqual(gDummyRegisterCustomOpsFnCalled, true); +} + +- (void)testStringInputs { + NSError* err = nil; + NSArray* stringData = @[ @"ONNX Runtime", @"is the", @"best", @"AI Framework" ]; + ORTValue* stringValue = [[ORTValue alloc] initWithTensorStringData:stringData shape:@[ @2, @2 ] error:&err]; + ORTAssertNullableResultSuccessful(stringValue, err); + + ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv + modelPath:[ORTSessionTest getStringModelPath] + sessionOptions:[ORTSessionTest makeSessionOptions] + error:&err]; + ORTAssertNullableResultSuccessful(session, err); + + NSDictionary* outputs = + [session runWithInputs:@{@"input:0" : stringValue} + outputNames:[NSSet setWithArray:@[ @"output:0" ]] + runOptions:[ORTSessionTest makeRunOptions] + error:&err]; + ORTAssertNullableResultSuccessful(outputs, err); + + ORTValue* outputStringValue = outputs[@"output:0"]; + XCTAssertNotNil(outputStringValue); + + NSArray* outputStringData = [outputStringValue tensorStringDataWithError:&err]; + ORTAssertNullableResultSuccessful(outputStringData, err); + + XCTAssertEqual([stringData count], [outputStringData count]); + XCTAssertTrue([stringData isEqualToArray:outputStringData]); +} + @end NS_ASSUME_NONNULL_END diff --git a/objectivec/test/ort_training_session_test.mm b/objectivec/test/ort_training_session_test.mm new file mode 100644 index 0000000000000..683965dc7606c --- /dev/null +++ b/objectivec/test/ort_training_session_test.mm @@ -0,0 +1,359 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import + +#import "ort_checkpoint.h" +#import "ort_training_session.h" +#import "ort_env.h" +#import "ort_session.h" +#import "ort_value.h" + +#import "test/test_utils.h" +#import "test/assertion_utils.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface ORTTrainingSessionTest : XCTestCase +@property(readonly, nullable) ORTEnv* ortEnv; +@property(readonly, nullable) ORTCheckpoint* checkpoint; +@property(readonly, nullable) ORTTrainingSession* session; +@end + +@implementation ORTTrainingSessionTest + +- (void)setUp { + [super setUp]; + + self.continueAfterFailure = NO; + + NSError* err = nil; + _ortEnv = [[ORTEnv alloc] initWithLoggingLevel:ORTLoggingLevelWarning + error:&err]; + ORTAssertNullableResultSuccessful(_ortEnv, err); + _checkpoint = [[ORTCheckpoint alloc] initWithPath:[ORTTrainingSessionTest + getFilePathFromName:@"checkpoint.ckpt"] + error:&err]; + ORTAssertNullableResultSuccessful(_checkpoint, err); + _session = [self makeTrainingSessionWithCheckpoint:_checkpoint]; +} + ++ (NSString*)getFilePathFromName:(NSString*)name { + NSBundle* bundle = [NSBundle bundleForClass:[ORTTrainingSessionTest class]]; + NSString* path = [[bundle resourcePath] stringByAppendingPathComponent:name]; + return path; +} + ++ (NSMutableData*)loadTensorDataFromFile:(NSString*)filePath skipHeader:(BOOL)skipHeader { + NSError* error = nil; + NSString* fileContents = [NSString stringWithContentsOfFile:filePath + encoding:NSUTF8StringEncoding + error:&error]; + ORTAssertNullableResultSuccessful(fileContents, error); + + NSArray* lines = [fileContents componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]]; + + if (skipHeader) { + lines = [lines subarrayWithRange:NSMakeRange(1, lines.count - 1)]; + } + + NSArray* dataArray = [lines[0] componentsSeparatedByCharactersInSet: + [NSCharacterSet characterSetWithCharactersInString:@",[] "]]; + NSMutableData* tensorData = [NSMutableData data]; + + for (NSString* str in dataArray) { + if (str.length > 0) { + float value = [str floatValue]; + [tensorData appendBytes:&value length:sizeof(float)]; + } + } + + return tensorData; +} + +- (ORTTrainingSession*)makeTrainingSessionWithCheckpoint:(ORTCheckpoint*)checkpoint { + NSError* error = nil; + ORTSessionOptions* sessionOptions = [[ORTSessionOptions alloc] initWithError:&error]; + ORTAssertNullableResultSuccessful(sessionOptions, error); + + ORTTrainingSession* session = [[ORTTrainingSession alloc] + initWithEnv:self.ortEnv + sessionOptions:sessionOptions + checkpoint:checkpoint + trainModelPath:[ORTTrainingSessionTest getFilePathFromName:@"training_model.onnx"] + evalModelPath:[ORTTrainingSessionTest getFilePathFromName:@"eval_model.onnx"] + optimizerModelPath:[ORTTrainingSessionTest getFilePathFromName:@"adamw.onnx"] + error:&error]; + + ORTAssertNullableResultSuccessful(session, error); + return session; +} + +- (void)testInitTrainingSession { + NSError* error = nil; + + // check that inputNames contains input-0 + NSArray* inputNames = [self.session getTrainInputNamesWithError:&error]; + ORTAssertNullableResultSuccessful(inputNames, error); + + XCTAssertTrue(inputNames.count > 0); + XCTAssertTrue([inputNames containsObject:@"input-0"]); + + // check that outNames contains onnx::loss::21273 + NSArray* outputNames = [self.session getTrainOutputNamesWithError:&error]; + ORTAssertNullableResultSuccessful(outputNames, error); + + XCTAssertTrue(outputNames.count > 0); + XCTAssertTrue([outputNames containsObject:@"onnx::loss::21273"]); +} + +- (void)testInitTrainingSessionWithEval { + NSError* error = nil; + + // check that inputNames contains input-0 + NSArray* inputNames = [self.session getEvalInputNamesWithError:&error]; + ORTAssertNullableResultSuccessful(inputNames, error); + + XCTAssertTrue(inputNames.count > 0); + XCTAssertTrue([inputNames containsObject:@"input-0"]); + + // check that outNames contains onnx::loss::21273 + NSArray* outputNames = [self.session getEvalOutputNamesWithError:&error]; + ORTAssertNullableResultSuccessful(outputNames, error); + + XCTAssertTrue(outputNames.count > 0); + XCTAssertTrue([outputNames containsObject:@"onnx::loss::21273"]); +} + +- (void)runTrainStep { + // load input and expected output + NSError* error = nil; + NSMutableData* expectedOutput = [ORTTrainingSessionTest loadTensorDataFromFile:[ORTTrainingSessionTest + getFilePathFromName:@"loss_1.out"] + skipHeader:YES]; + + NSMutableData* input = [ORTTrainingSessionTest loadTensorDataFromFile:[ORTTrainingSessionTest + getFilePathFromName:@"input-0.in"] + skipHeader:YES]; + + int32_t labels[] = {1, 1}; + + // create ORTValue array for input and labels + NSMutableArray* inputValues = [NSMutableArray array]; + + ORTValue* inputTensor = [[ORTValue alloc] initWithTensorData:input + elementType:ORTTensorElementDataTypeFloat + shape:@[ @2, @784 ] + error:&error]; + ORTAssertNullableResultSuccessful(inputTensor, error); + [inputValues addObject:inputTensor]; + + ORTValue* labelTensor = [[ORTValue alloc] initWithTensorData:[NSMutableData dataWithBytes:labels + length:sizeof(labels)] + elementType:ORTTensorElementDataTypeInt32 + shape:@[ @2 ] + error:&error]; + + ORTAssertNullableResultSuccessful(labelTensor, error); + [inputValues addObject:labelTensor]; + + NSArray* outputs = [self.session trainStepWithInputValues:inputValues error:&error]; + ORTAssertNullableResultSuccessful(outputs, error); + XCTAssertTrue(outputs.count > 0); + + BOOL result = [self.session lazyResetGradWithError:&error]; + ORTAssertBoolResultSuccessful(result, error); + + outputs = [self.session trainStepWithInputValues:inputValues error:&error]; + ORTAssertNullableResultSuccessful(outputs, error); + XCTAssertTrue(outputs.count > 0); + + ORTValue* outputValue = outputs[0]; + ORTValueTypeInfo* typeInfo = [outputValue typeInfoWithError:&error]; + ORTAssertNullableResultSuccessful(typeInfo, error); + XCTAssertEqual(typeInfo.type, ORTValueTypeTensor); + XCTAssertNotNil(typeInfo.tensorTypeAndShapeInfo); + + ORTTensorTypeAndShapeInfo* tensorInfo = [outputValue tensorTypeAndShapeInfoWithError:&error]; + ORTAssertNullableResultSuccessful(tensorInfo, error); + XCTAssertEqual(tensorInfo.elementType, ORTTensorElementDataTypeFloat); + + NSMutableData* tensorData = [outputValue tensorDataWithError:&error]; + ORTAssertNullableResultSuccessful(tensorData, error); + ORTAssertEqualFloatArrays(test_utils::getFloatArrayFromData(tensorData), + test_utils::getFloatArrayFromData(expectedOutput)); +} + +- (void)testTrainStepOutput { + [self runTrainStep]; +} + +- (void)testOptimizerStep { + // load input and expected output + NSError* error = nil; + NSMutableData* expectedOutput1 = [ORTTrainingSessionTest loadTensorDataFromFile:[ORTTrainingSessionTest + getFilePathFromName:@"loss_1.out"] + skipHeader:YES]; + + NSMutableData* expectedOutput2 = [ORTTrainingSessionTest loadTensorDataFromFile:[ORTTrainingSessionTest + getFilePathFromName:@"loss_2.out"] + skipHeader:YES]; + + NSMutableData* input = [ORTTrainingSessionTest loadTensorDataFromFile:[ORTTrainingSessionTest + getFilePathFromName:@"input-0.in"] + skipHeader:YES]; + + int32_t labels[] = {1, 1}; + + // create ORTValue array for input and labels + NSMutableArray* inputValues = [NSMutableArray array]; + + ORTValue* inputTensor = [[ORTValue alloc] initWithTensorData:input + elementType:ORTTensorElementDataTypeFloat + shape:@[ @2, @784 ] + error:&error]; + ORTAssertNullableResultSuccessful(inputTensor, error); + [inputValues addObject:inputTensor]; + + ORTValue* labelTensor = [[ORTValue alloc] initWithTensorData:[NSMutableData dataWithBytes:labels + length:sizeof(labels)] + elementType:ORTTensorElementDataTypeInt32 + shape:@[ @2 ] + error:&error]; + ORTAssertNullableResultSuccessful(labelTensor, error); + [inputValues addObject:labelTensor]; + + // run train step, optimizer steps and check loss + NSArray* outputs = [self.session trainStepWithInputValues:inputValues error:&error]; + ORTAssertNullableResultSuccessful(outputs, error); + + NSMutableData* loss = [outputs[0] tensorDataWithError:&error]; + ORTAssertNullableResultSuccessful(loss, error); + ORTAssertEqualFloatArrays(test_utils::getFloatArrayFromData(loss), + test_utils::getFloatArrayFromData(expectedOutput1)); + + BOOL result = [self.session lazyResetGradWithError:&error]; + ORTAssertBoolResultSuccessful(result, error); + + outputs = [self.session trainStepWithInputValues:inputValues error:&error]; + ORTAssertNullableResultSuccessful(outputs, error); + + loss = [outputs[0] tensorDataWithError:&error]; + ORTAssertNullableResultSuccessful(loss, error); + ORTAssertEqualFloatArrays(test_utils::getFloatArrayFromData(loss), + test_utils::getFloatArrayFromData(expectedOutput1)); + + result = [self.session optimizerStepWithError:&error]; + ORTAssertBoolResultSuccessful(result, error); + + outputs = [self.session trainStepWithInputValues:inputValues error:&error]; + ORTAssertNullableResultSuccessful(outputs, error); + loss = [outputs[0] tensorDataWithError:&error]; + ORTAssertNullableResultSuccessful(loss, error); + ORTAssertEqualFloatArrays(test_utils::getFloatArrayFromData(loss), + test_utils::getFloatArrayFromData(expectedOutput2)); +} + +- (void)testSetLearningRate { + NSError* error = nil; + + float learningRate = 0.1f; + BOOL result = [self.session setLearningRate:learningRate error:&error]; + ORTAssertBoolResultSuccessful(result, error); + + float actualLearningRate = [self.session getLearningRateWithError:&error]; + ORTAssertEqualFloatAndNoError(learningRate, actualLearningRate, error); +} + +- (void)testLinearLRScheduler { + NSError* error = nil; + + float learningRate = 0.1f; + BOOL result = [self.session registerLinearLRSchedulerWithWarmupStepCount:2 + totalStepCount:4 + initialLr:learningRate + error:&error]; + + ORTAssertBoolResultSuccessful(result, error); + + [self runTrainStep]; + + result = [self.session optimizerStepWithError:&error]; + ORTAssertBoolResultSuccessful(result, error); + result = [self.session schedulerStepWithError:&error]; + ORTAssertBoolResultSuccessful(result, error); + ORTAssertEqualFloatAndNoError(0.05f, [self.session getLearningRateWithError:&error], error); + + result = [self.session optimizerStepWithError:&error]; + ORTAssertBoolResultSuccessful(result, error); + result = [self.session schedulerStepWithError:&error]; + ORTAssertBoolResultSuccessful(result, error); + ORTAssertEqualFloatAndNoError(0.1f, [self.session getLearningRateWithError:&error], error); + + result = [self.session optimizerStepWithError:&error]; + ORTAssertBoolResultSuccessful(result, error); + result = [self.session schedulerStepWithError:&error]; + ORTAssertBoolResultSuccessful(result, error); + ORTAssertEqualFloatAndNoError(0.05f, [self.session getLearningRateWithError:&error], error); + + result = [self.session optimizerStepWithError:&error]; + ORTAssertBoolResultSuccessful(result, error); + result = [self.session schedulerStepWithError:&error]; + ORTAssertBoolResultSuccessful(result, error); + ORTAssertEqualFloatAndNoError(0.0f, [self.session getLearningRateWithError:&error], error); +} + +- (void)testExportModelForInference { + NSError* error = nil; + + NSString* inferenceModelPath = [test_utils::createTemporaryDirectory(self) + stringByAppendingPathComponent:@"inference_model.onnx"]; + XCTAssertNotNil(inferenceModelPath); + + NSArray* graphOutputNames = [NSArray arrayWithObjects:@"output-0", nil]; + + BOOL result = [self.session exportModelForInferenceWithOutputPath:inferenceModelPath + graphOutputNames:graphOutputNames + error:&error]; + + ORTAssertBoolResultSuccessful(result, error); + XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:inferenceModelPath]); + + [self addTeardownBlock:^{ + NSError* error = nil; + [[NSFileManager defaultManager] removeItemAtPath:inferenceModelPath error:&error]; + }]; +} + +- (void)testToBuffer { + NSError* error = nil; + ORTValue* buffer = [self.session toBufferWithTrainable:YES error:&error]; + ORTAssertNullableResultSuccessful(buffer, error); + + ORTValueTypeInfo* typeInfo = [buffer typeInfoWithError:&error]; + ORTAssertNullableResultSuccessful(typeInfo, error); + XCTAssertEqual(typeInfo.type, ORTValueTypeTensor); + XCTAssertNotNil(typeInfo.tensorTypeAndShapeInfo); +} + +- (void)testFromBuffer { + NSError* error = nil; + + ORTValue* buffer = [self.session toBufferWithTrainable:YES error:&error]; + ORTAssertNullableResultSuccessful(buffer, error); + + BOOL result = [self.session fromBufferWithValue:buffer error:&error]; + ORTAssertBoolResultSuccessful(result, error); +} + +- (void)tearDown { + _session = nil; + _checkpoint = nil; + _ortEnv = nil; + + [super tearDown]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/objectivec/test/ort_training_utils_test.mm b/objectivec/test/ort_training_utils_test.mm new file mode 100644 index 0000000000000..1695ddc57b562 --- /dev/null +++ b/objectivec/test/ort_training_utils_test.mm @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import +#import "ort_training_session.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface ORTTrainingUtilsTest : XCTestCase +@end + +@implementation ORTTrainingUtilsTest + +- (void)setUp { + [super setUp]; + + self.continueAfterFailure = NO; +} + +- (void)testSetSeed { + ORTSetSeed(2718); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/objectivec/test/ort_value_test.mm b/objectivec/test/ort_value_test.mm index 734ad39095de9..b22d73bbd9948 100644 --- a/objectivec/test/ort_value_test.mm +++ b/objectivec/test/ort_value_test.mm @@ -74,6 +74,19 @@ - (void)testInitTensorFailsWithDataSmallerThanShape { ORTAssertNullableResultUnsuccessful(ortValue, err); } +- (void)testInitTensorWithStringDataSucceeds { + NSArray* stringData = @[ @"ONNX Runtime", @"is", @"the", @"best", @"AI", @"Framework" ]; + NSError* err = nil; + ORTValue* stringValue = [[ORTValue alloc] initWithTensorStringData:stringData shape:@[ @3, @2 ] error:&err]; + ORTAssertNullableResultSuccessful(stringValue, err); + + NSArray* returnedStringData = [stringValue tensorStringDataWithError:&err]; + ORTAssertNullableResultSuccessful(returnedStringData, err); + + XCTAssertEqual([stringData count], [returnedStringData count]); + XCTAssertTrue([stringData isEqualToArray:returnedStringData]); +} + @end NS_ASSUME_NONNULL_END diff --git a/objectivec/test/test_utils.h b/objectivec/test/test_utils.h new file mode 100644 index 0000000000000..8a5e6e4821fc0 --- /dev/null +++ b/objectivec/test/test_utils.h @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import +#import + +#import "ort_session.h" +#import "ort_env.h" +#import "ort_value.h" + +NS_ASSUME_NONNULL_BEGIN + +namespace test_utils { + +NSString* _Nullable createTemporaryDirectory(XCTestCase* testCase); + +NSArray* getFloatArrayFromData(NSData* data); + +} // namespace test_utils + +NS_ASSUME_NONNULL_END diff --git a/objectivec/test/test_utils.mm b/objectivec/test/test_utils.mm new file mode 100644 index 0000000000000..ef8e8c563b19f --- /dev/null +++ b/objectivec/test/test_utils.mm @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import "test_utils.h" + +NS_ASSUME_NONNULL_BEGIN + +namespace test_utils { + +NSString* createTemporaryDirectory(XCTestCase* testCase) { + NSString* temporaryDirectory = NSTemporaryDirectory(); + NSString* directoryPath = [temporaryDirectory stringByAppendingPathComponent:@"ort-objective-c-test"]; + + NSError* error = nil; + [[NSFileManager defaultManager] createDirectoryAtPath:directoryPath + withIntermediateDirectories:YES + attributes:nil + error:&error]; + + XCTAssertNil(error, @"Error creating temporary directory: %@", error.localizedDescription); + + // add teardown block to delete the temporary directory + [testCase addTeardownBlock:^{ + NSError* error = nil; + [[NSFileManager defaultManager] removeItemAtPath:directoryPath error:&error]; + XCTAssertNil(error, @"Error removing temporary directory: %@", error.localizedDescription); + }]; + + return directoryPath; +} + +NSArray* getFloatArrayFromData(NSData* data) { + NSMutableArray* array = [NSMutableArray array]; + float value; + for (size_t i = 0; i < data.length / sizeof(float); ++i) { + [data getBytes:&value range:NSMakeRange(i * sizeof(float), sizeof(float))]; + [array addObject:[NSNumber numberWithFloat:value]]; + } + return array; +} + +} // namespace test_utils + +NS_ASSUME_NONNULL_END diff --git a/objectivec/test/testdata/identity_string.ort b/objectivec/test/testdata/identity_string.ort new file mode 100644 index 0000000000000..96ba0f37c6949 Binary files /dev/null and b/objectivec/test/testdata/identity_string.ort differ diff --git a/onnxruntime/__init__.py b/onnxruntime/__init__.py index d052d9644c890..fd147eaa11f3f 100644 --- a/onnxruntime/__init__.py +++ b/onnxruntime/__init__.py @@ -7,7 +7,7 @@ For more information on ONNX Runtime, please see `aka.ms/onnxruntime `_ or the `Github project `_. """ -__version__ = "1.15.0" +__version__ = "1.17.0" __author__ = "Microsoft" # we need to do device version validation (for example to check Cuda version for an onnxruntime-training package). @@ -34,10 +34,12 @@ from onnxruntime.capi._pybind_state import SessionIOBinding # noqa: F401 from onnxruntime.capi._pybind_state import SessionOptions # noqa: F401 from onnxruntime.capi._pybind_state import create_and_register_allocator # noqa: F401 + from onnxruntime.capi._pybind_state import create_and_register_allocator_v2 # noqa: F401 from onnxruntime.capi._pybind_state import disable_telemetry_events # noqa: F401 from onnxruntime.capi._pybind_state import enable_telemetry_events # noqa: F401 from onnxruntime.capi._pybind_state import get_all_providers # noqa: F401 from onnxruntime.capi._pybind_state import get_available_providers # noqa: F401 + from onnxruntime.capi._pybind_state import get_build_info # noqa: F401 from onnxruntime.capi._pybind_state import get_device # noqa: F401 from onnxruntime.capi._pybind_state import get_version_string # noqa: F401 from onnxruntime.capi._pybind_state import set_default_logger_severity # noqa: F401 diff --git a/onnxruntime/contrib_ops/cpu/bert/attention.cc b/onnxruntime/contrib_ops/cpu/bert/attention.cc index 1f6fe1d874d4d..4711ccf487cc8 100644 --- a/onnxruntime/contrib_ops/cpu/bert/attention.cc +++ b/onnxruntime/contrib_ops/cpu/bert/attention.cc @@ -8,6 +8,7 @@ #include "core/util/math.h" #include "core/util/math_cpuonly.h" #include "core/common/safeint.h" +#include "core/common/span_utils.h" #include "core/platform/threadpool.h" using onnxruntime::narrow; @@ -15,7 +16,7 @@ using onnxruntime::concurrency::ThreadPool; namespace onnxruntime { namespace contrib { -static void FreePackedWeights(BufferUniquePtr* array, size_t array_size) { +static void FreePackedWeights(gsl::span> array, size_t array_size) { for (size_t i = 0; i < array_size; i++) { array[i].reset(); } @@ -41,7 +42,7 @@ class Attention : public OpKernel, public AttentionCPUBase { size_t input_hidden_size, const T* weights_data, size_t weight_matrix_col_size, PrePackedWeights* prepacked_weights); - BufferUniquePtr packed_weights_[3]; + std::array, 3> packed_weights_; size_t packed_weights_size_[3] = {0, 0, 0}; bool is_prepack_ = false; TensorShape weight_shape_; @@ -76,15 +77,14 @@ bool Attention::IsPackWeightsSuccessful(int qkv_index, } size_t loop_len = narrow(num_heads_); - size_t packed_weights_data_size = packb_size * loop_len; // The same size would be computed by AllocArray() below - auto* packed_weights_data = static_cast(alloc->AllocArray(packb_size, loop_len)); - + size_t packed_weights_data_size = SafeInt(packb_size) * loop_len; + packed_weights_[qkv_index] = IAllocator::MakeUniquePtr(alloc, packed_weights_data_size, true); + packed_weights_size_[qkv_index] = packb_size; + std::byte* packed_weights_data = static_cast(packed_weights_[qkv_index].get()); // Initialize memory to 0 as there could be some padding associated with pre-packed // buffer memory and we do not want it uninitialized and generate different hashes // if and when we try to cache this pre-packed buffer for sharing between sessions. memset(packed_weights_data, 0, packed_weights_data_size); - packed_weights_[qkv_index] = BufferUniquePtr(packed_weights_data, BufferDeleter(std::move(alloc))); - packed_weights_size_[qkv_index] = packb_size; for (size_t i = 0; i < loop_len; i++) { MlasGemmPackB(CblasNoTrans, head_size, input_hidden_size, weights_data, weight_matrix_col_size, packed_weights_data); diff --git a/onnxruntime/contrib_ops/cpu/bert/attention_base.cc b/onnxruntime/contrib_ops/cpu/bert/attention_base.cc index dfeaa59fafeee..5d224bdc2235f 100644 --- a/onnxruntime/contrib_ops/cpu/bert/attention_base.cc +++ b/onnxruntime/contrib_ops/cpu/bert/attention_base.cc @@ -125,7 +125,6 @@ Status AttentionBase::CheckInputs(const TensorShape& input_shape, } int64_t past_sequence_length = 0; - int64_t original_past_sequence_length = 0; if (past != nullptr) { // past is optional if (k_hidden_size != v_hidden_size) { return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Input 'past' expect k_hidden_size == v_hidden_size"); @@ -158,7 +157,6 @@ Status AttentionBase::CheckInputs(const TensorShape& input_shape, if (!past_present_share_buffer_) { past_sequence_length = past_dims[3]; - original_past_sequence_length = past_sequence_length; } else { if (past_seq_len == nullptr || !onnxruntime::IsScalarOr1ElementVector(past_seq_len)) { return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, @@ -243,7 +241,6 @@ Status AttentionBase::CheckInputs(const TensorShape& input_shape, output_parameters->batch_size = static_cast(batch_size); output_parameters->sequence_length = static_cast(sequence_length); output_parameters->past_sequence_length = static_cast(past_sequence_length); - output_parameters->original_past_sequence_length = static_cast(original_past_sequence_length); output_parameters->kv_sequence_length = static_cast(kv_sequence_length); output_parameters->total_sequence_length = static_cast(total_sequence_length); output_parameters->max_sequence_length = static_cast(max_sequence_length); diff --git a/onnxruntime/contrib_ops/cpu/bert/attention_common.h b/onnxruntime/contrib_ops/cpu/bert/attention_common.h index 485a04243d8d2..4c9c15d07a9b8 100644 --- a/onnxruntime/contrib_ops/cpu/bert/attention_common.h +++ b/onnxruntime/contrib_ops/cpu/bert/attention_common.h @@ -27,6 +27,8 @@ enum AttentionQkvFormat { QKV_BSN3H, // for TRT fused attention, qkv are packed Q_K_V_BNSH_QKV_BS3NH, // for TRT fused causal attention, data has two formats (qkv is 3BNSH, gemm_buffer is BS3NH) Q_KV_BSNH_BSN2H, // for TRT fused cross attention, kv are packed + Q_K_V_TNH, // for memory efficient attention, qkv are not packed, and paddings are removed. + QKV_TN3H, // for TRT fused attention, qkv are packed and paddings are removed }; enum AttentionKernelType { @@ -35,6 +37,7 @@ enum AttentionKernelType { AttentionKernel_TrtFlashAttention, AttentionKernel_TrtFusedCrossAttention, AttentionKernel_CutlassMemoryEfficientAttention, + AttentionKernel_FlashAttention, AttentionKernel_Default }; @@ -42,16 +45,15 @@ enum AttentionKernelType { 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 original_past_sequence_length; // original 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 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; bool is_unidirectional; bool past_present_share_buffer; @@ -97,8 +99,16 @@ constexpr const char* kDisableTrtFlashAttention = "ORT_DISABLE_TRT_FLASH_ATTENTI // Environment variable to enable or disable cutlass memory efficient attention. Default is 0 (enabled). constexpr const char* kDisableMemoryEfficientAttention = "ORT_DISABLE_MEMORY_EFFICIENT_ATTENTION"; +// Environment variable to enable or disable flash attention. Default is 0 (enabled). +constexpr const char* kDisableFlashAttention = "ORT_DISABLE_FLASH_ATTENTION"; + // Minimum sequence length to enable memory efficient attention in FP32. -constexpr int kMinSequenceLengthForMemoryEfficientAttentionFp32 = 256; +constexpr int kMinSeqLenForMemoryEfficientAttentionFp32 = 256; + +// Minimum sequence length to prefer flash attention when input format is packed QKV for MultiHeadAttention +constexpr const char* kMinSeqLenForFlashAttentionPackedQKV = "ORT_MIN_SEQ_LEN_FLASH_ATTENTION_PACKED_QKV"; +// Default value for the above setting. +constexpr int kDefaultMinSeqLenForFlashAttentionPackedQKV = 513; } // namespace attention diff --git a/onnxruntime/contrib_ops/cpu/bert/attention_cpu_base.h b/onnxruntime/contrib_ops/cpu/bert/attention_cpu_base.h index 90da56e165266..b761b1afd8529 100644 --- a/onnxruntime/contrib_ops/cpu/bert/attention_cpu_base.h +++ b/onnxruntime/contrib_ops/cpu/bert/attention_cpu_base.h @@ -58,10 +58,10 @@ class AttentionCPUBase : public AttentionBase { auto attention_probs = allocator->Alloc(bytes); BufferUniquePtr scratch_buffer(attention_probs, BufferDeleter(allocator)); - bool has_unidirectional = (is_unidirectional_ && sequence_length > 1); + bool causal = (is_unidirectional_ && sequence_length > 1); void* mask_data = nullptr; - if (mask_index != nullptr || has_unidirectional) { + if (mask_index != nullptr || causal) { size_t mask_data_bytes = SafeInt(batch_size) * sequence_length * total_sequence_length * sizeof(T); mask_data = allocator->Alloc(mask_data_bytes); memset(mask_data, 0, mask_data_bytes); @@ -85,7 +85,7 @@ class AttentionCPUBase : public AttentionBase { } ComputeAttentionProbs(static_cast(attention_probs), Q, K, - mask_index_data, mask_index_dims, static_cast(mask_data), has_unidirectional, + mask_index_data, mask_index_dims, static_cast(mask_data), causal, 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, relative_position_bias_data); @@ -116,7 +116,7 @@ class AttentionCPUBase : public AttentionBase { const int32_t* mask_index, // mask index. nullptr if no mask. gsl::span mask_index_dims, // mask index shape T* mask_data, // buffer for mask data. - bool has_unidirectional, // has unidirectional mask + bool causal, // has causal (unidirectional) mask int batch_size, // batch size of self-attention int sequence_length, // sequence length of self-attention (S) int kv_sequence_length, // sequence length of cross-attention (L) @@ -139,7 +139,7 @@ class AttentionCPUBase : public AttentionBase { // mask_data is nullptr when mask_index is nullptr and not unidirectional, otherwise its shape is BxSxT if (mask_data != nullptr) { PrepareMask(mask_index, mask_index_dims, mask_data, - has_unidirectional, batch_size, sequence_length, past_sequence_length, mask_filter_value_); + causal, batch_size, sequence_length, past_sequence_length, mask_filter_value_); } else { // no any mask const int memset_loop_len = batch_size * num_heads_; const double memset_cost = static_cast(sequence_length) * total_sequence_length; @@ -191,16 +191,6 @@ class AttentionCPUBase : public AttentionBase { Q + q_input_chunk_length * i, k, 1.0, output, nullptr); - // Fix unidirectional mask to be parity with huggingface implementation. - if (has_unidirectional && mask_data != nullptr) { - for (int s_i = 0; s_i < sequence_length - 1; s_i++) { - for (int m_i = past_sequence_length + s_i + 1; m_i < total_sequence_length; m_i++) { - int j = s_i * total_sequence_length + m_i; - output[j] = mask_data[mask_offset + j]; - } - } - } - if (relative_position_bias_data != nullptr) { for (int j = 0; j < sequence_length * total_sequence_length; j++) { output[j] += relative_position_bias_data[output_offset + j]; diff --git a/onnxruntime/contrib_ops/cpu/bert/attention_helper.h b/onnxruntime/contrib_ops/cpu/bert/attention_helper.h index 76cf7ed8f8b9f..f1a0ce994e081 100644 --- a/onnxruntime/contrib_ops/cpu/bert/attention_helper.h +++ b/onnxruntime/contrib_ops/cpu/bert/attention_helper.h @@ -3,6 +3,7 @@ #pragma once +#include #include "core/util/math.h" #include "core/util/math_cpuonly.h" #include "core/common/safeint.h" @@ -64,7 +65,7 @@ template void PrepareMask(const int32_t* mask_index, gsl::span mask_index_dims, T* mask_data, - bool is_unidirectional, + bool causal, int batch_size, int sequence_length, int past_sequence_length, @@ -85,11 +86,11 @@ void PrepareMask(const int32_t* mask_index, p_mask[i] = (mask_index[i] > 0) ? static_cast(0.0f) : static_cast(mask_filter_value); } - if (is_unidirectional) { + if (causal) { for (int b_i = 0; b_i < batch_size; b_i++) { for (int s_i = 0; s_i < sequence_length - 1; s_i++) { for (int m_i = past_sequence_length + s_i + 1; m_i < all_sequence_length; m_i++) { - p_mask[s_i * all_sequence_length + m_i] += static_cast(mask_filter_value); + p_mask[s_i * all_sequence_length + m_i] = std::numeric_limits::lowest(); } } p_mask += static_cast(sequence_length) * all_sequence_length; @@ -139,13 +140,14 @@ void PrepareMask(const int32_t* mask_index, } // Apply unidirectional mask. - if (is_unidirectional) { + if (causal) { for (int s_i = 0; s_i < sequence_length - 1; s_i++) { for (int m_i = past_sequence_length + s_i + 1; m_i < all_sequence_length; m_i++) { - p_mask[s_i * all_sequence_length + m_i] += static_cast(mask_filter_value); + p_mask[s_i * all_sequence_length + m_i] = std::numeric_limits::lowest(); } } } + ptrdiff_t mask_to_advance = SafeInt(sequence_length) * all_sequence_length; p_mask += mask_to_advance; } diff --git a/onnxruntime/contrib_ops/cpu/bert/embed_layer_norm.cc b/onnxruntime/contrib_ops/cpu/bert/embed_layer_norm.cc index 81d525c598d96..570f4108c3f62 100644 --- a/onnxruntime/contrib_ops/cpu/bert/embed_layer_norm.cc +++ b/onnxruntime/contrib_ops/cpu/bert/embed_layer_norm.cc @@ -149,7 +149,7 @@ Status EmbedLayerNorm::Compute(OpKernelContext* context) const { } // Calculate mask - if (nullptr != mask) { + if (nullptr != mask && nullptr != mask_index) { const int32_t* mask_data = mask->Data(); int32_t* mask_index_data = mask_index->MutableData(); for (int b = 0; b < batch_size; b++) { @@ -162,7 +162,7 @@ Status EmbedLayerNorm::Compute(OpKernelContext* context) const { } mask_index_data[b] = cur_sum; } - } else { + } else if (mask_index != nullptr) { memset(mask_index->MutableData(), 0, batch_size * sizeof(int32_t)); } diff --git a/onnxruntime/contrib_ops/cpu/bert/multihead_attention.cc b/onnxruntime/contrib_ops/cpu/bert/multihead_attention.cc index 54c488df3b5fc..0b55cb7804c61 100644 --- a/onnxruntime/contrib_ops/cpu/bert/multihead_attention.cc +++ b/onnxruntime/contrib_ops/cpu/bert/multihead_attention.cc @@ -225,6 +225,33 @@ Status AddBiasReshape(const Tensor* qkv, // Input: Q/K/V data - query is return Status::OK(); } +template +Status MaybeTransposeToBNSHAndAddBias(OpKernelContext* context, AllocatorPtr allocator, + int batch_size, int num_heads, int sequence_length, int head_size, + const Tensor* in, const Tensor* bias, int bias_offset, OrtValue& out) { + auto element_type = DataTypeImpl::GetType(); + std::vector new_dims({batch_size, num_heads, sequence_length, head_size}); + gsl::span new_dims_span{new_dims}; + TensorShape v_BNLH(new_dims_span); + Tensor::InitOrtValue(element_type, v_BNLH, allocator, out); + if (bias == nullptr) { + std::unique_ptr reshaped; + if (in->Shape().GetDims().size() == 3) { + reshaped = std::make_unique(in->DataType(), in->Shape(), const_cast(in->DataRaw()), in->Location()); + ORT_RETURN_IF_ERROR(Reshape_BSD_to_BSNH(reshaped.get(), batch_size, sequence_length, num_heads, head_size)); + } + ORT_RETURN_IF_ERROR(Transpose_BSNH_to_BNSH((reshaped == nullptr) ? in : reshaped.get(), out)); + } else { + const auto* qkv_bias = bias->Data(); + if (sequence_length == 1) { + ORT_RETURN_IF_ERROR(AddBiasReshape(in, qkv_bias, out, bias_offset, batch_size, sequence_length, num_heads, head_size, num_heads * head_size, context)); + } else { + ORT_RETURN_IF_ERROR(AddBiasTranspose(in, qkv_bias, out, bias_offset, batch_size, sequence_length, num_heads, head_size, num_heads * head_size, context)); + } + } + return Status::OK(); +}; + template Status MultiHeadAttention::Compute(OpKernelContext* context) const { const Tensor* query = context->Input(0); @@ -259,7 +286,8 @@ Status MultiHeadAttention::Compute(OpKernelContext* context) const { num_heads_, scale, mask_filter_value_, - past_present_share_buffer)); + past_present_share_buffer, + false)); const int batch_size = parameters.batch_size; const int q_sequence_length = parameters.sequence_length; @@ -276,8 +304,6 @@ Status MultiHeadAttention::Compute(OpKernelContext* context) const { output_shape[2] = static_cast(parameters.v_hidden_size); Tensor* output = context->Output(0, output_shape); - auto element_type = DataTypeImpl::GetType(); - const auto* qkv_bias = (bias == nullptr) ? nullptr : bias->Data(); constexpr int q_bias_offset = 0; const int k_bias_offset = qk_hidden_size; const int v_bias_offset = 2 * qk_hidden_size; @@ -291,20 +317,7 @@ Status MultiHeadAttention::Compute(OpKernelContext* context) const { Tensor* present_v = context->Output(2, present_v_shape); AllocatorPtr allocator; - - if (qkv_bias == nullptr) { - // We assume query, key/past_key, and value/past_value are already in the correct shape - - // Check that key/value or past_key/past_value is valid - ORT_ENFORCE((key != nullptr && value != nullptr) || (past_key != nullptr && past_value != nullptr)); - return ApplyAttention(query->Data(), - (key != nullptr) ? key->Data() : past_key->Data(), - (value != nullptr) ? value->Data() : past_value->Data(), - key_padding_mask, nullptr /* past */, nullptr /* past_k */, nullptr /* past_v */, - output, present_k, present_v, - batch_size, q_sequence_length, kv_sequence_length, - qk_head_size, v_head_size, v_hidden_size, extra_add_qk, context); - } + ORT_RETURN_IF_ERROR(context->GetTempSpaceAllocator(&allocator)); // For each of Q/K/V, there are multiple scenarios: // 1) Combined QKV bias is null @@ -315,27 +328,8 @@ Status MultiHeadAttention::Compute(OpKernelContext* context) const { // b) Q/K/V has seq_len > 1 OrtValue Q; - { - ORT_RETURN_IF_ERROR(context->GetTempSpaceAllocator(&allocator)); - std::vector new_dims({batch_size, num_heads_, q_sequence_length, qk_head_size}); - gsl::span new_dims_span{new_dims}; - TensorShape q_BNSH(new_dims_span); - Tensor::InitOrtValue(element_type, q_BNSH, allocator, Q); - if (qkv_bias == nullptr) { - Tensor* query_reshaped = nullptr; - if (query->Shape().GetDims().size() == 3) { - query_reshaped = const_cast(query); - ORT_RETURN_IF_ERROR(Reshape_BSD_to_BSNH(query_reshaped, batch_size, q_sequence_length, num_heads_, qk_head_size)); - } - ORT_RETURN_IF_ERROR(Transpose_BSNH_to_BNSH((query_reshaped == nullptr) ? query : query_reshaped, Q)); - } else { - if (q_sequence_length == 1) { - ORT_RETURN_IF_ERROR(AddBiasReshape(query, qkv_bias, Q, q_bias_offset, batch_size, q_sequence_length, num_heads_, qk_head_size, qk_hidden_size, context)); - } else { - ORT_RETURN_IF_ERROR(AddBiasTranspose(query, qkv_bias, Q, q_bias_offset, batch_size, q_sequence_length, num_heads_, qk_head_size, qk_hidden_size, context)); - } - } - } + ORT_RETURN_IF_ERROR(MaybeTransposeToBNSHAndAddBias( + context, allocator, batch_size, num_heads_, q_sequence_length, qk_head_size, query, bias, q_bias_offset, Q)); if (kv_BNSH) { // No bias add needed for K/V, key already of shape BxNxLxH, value already of shape BxNxLxH_v @@ -347,50 +341,11 @@ Status MultiHeadAttention::Compute(OpKernelContext* context) const { } OrtValue K; - { - ORT_RETURN_IF_ERROR(context->GetTempSpaceAllocator(&allocator)); - std::vector new_dims({batch_size, num_heads_, kv_sequence_length, qk_head_size}); - gsl::span new_dims_span{new_dims}; - TensorShape k_BNLH(new_dims_span); - Tensor::InitOrtValue(element_type, k_BNLH, allocator, K); - if (qkv_bias == nullptr) { - Tensor* key_reshaped = nullptr; - if (key->Shape().GetDims().size() == 3) { - key_reshaped = const_cast(key); - ORT_RETURN_IF_ERROR(Reshape_BSD_to_BSNH(key_reshaped, batch_size, kv_sequence_length, num_heads_, qk_head_size)); - } - ORT_RETURN_IF_ERROR(Transpose_BSNH_to_BNSH((key_reshaped == nullptr) ? key : key_reshaped, K)); - } else { - if (kv_sequence_length == 1) { - ORT_RETURN_IF_ERROR(AddBiasReshape(key, qkv_bias, K, k_bias_offset, batch_size, kv_sequence_length, num_heads_, qk_head_size, qk_hidden_size, context)); - } else { - ORT_RETURN_IF_ERROR(AddBiasTranspose(key, qkv_bias, K, k_bias_offset, batch_size, kv_sequence_length, num_heads_, qk_head_size, qk_hidden_size, context)); - } - } - } - OrtValue V; - { - ORT_RETURN_IF_ERROR(context->GetTempSpaceAllocator(&allocator)); - std::vector new_dims({batch_size, num_heads_, kv_sequence_length, v_head_size}); - gsl::span new_dims_span{new_dims}; - TensorShape v_BNLH(new_dims_span); - Tensor::InitOrtValue(element_type, v_BNLH, allocator, V); - if (qkv_bias == nullptr) { - Tensor* value_reshaped = nullptr; - if (value->Shape().GetDims().size() == 3) { - value_reshaped = const_cast(value); - ORT_RETURN_IF_ERROR(Reshape_BSD_to_BSNH(value_reshaped, batch_size, kv_sequence_length, num_heads_, v_head_size)); - } - ORT_RETURN_IF_ERROR(Transpose_BSNH_to_BNSH((value_reshaped == nullptr) ? value : value_reshaped, V)); - } else { - if (kv_sequence_length == 1) { - ORT_RETURN_IF_ERROR(AddBiasReshape(value, qkv_bias, V, v_bias_offset, batch_size, kv_sequence_length, num_heads_, v_head_size, v_hidden_size, context)); - } else { - ORT_RETURN_IF_ERROR(AddBiasTranspose(value, qkv_bias, V, v_bias_offset, batch_size, kv_sequence_length, num_heads_, v_head_size, v_hidden_size, context)); - } - } - } + ORT_RETURN_IF_ERROR(MaybeTransposeToBNSHAndAddBias( + context, allocator, batch_size, num_heads_, kv_sequence_length, qk_head_size, key, bias, k_bias_offset, K)); + ORT_RETURN_IF_ERROR(MaybeTransposeToBNSHAndAddBias( + context, allocator, batch_size, num_heads_, kv_sequence_length, v_head_size, value, bias, v_bias_offset, V)); // Compute the attention score and apply the score to V return ApplyAttention(Q.GetMutable()->MutableData(), K.GetMutable()->MutableData(), V.GetMutable()->MutableData(), diff --git a/onnxruntime/contrib_ops/cpu/bert/multihead_attention_helper.h b/onnxruntime/contrib_ops/cpu/bert/multihead_attention_helper.h index 3e1600ae45acc..1dc85e6d345d7 100644 --- a/onnxruntime/contrib_ops/cpu/bert/multihead_attention_helper.h +++ b/onnxruntime/contrib_ops/cpu/bert/multihead_attention_helper.h @@ -25,7 +25,8 @@ Status CheckInputs(const T* query, int num_heads, float mask_filter_value, float scale, - bool past_present_share_buffer) { + bool past_present_share_buffer, + bool dmmha_packing) { // key_padding_mask (K/V) : (B) or (2*B + 1) or (B, L) or None // relative_position_bias : (B, 1, S, L) // past_key : (B, N, S*, H) @@ -41,7 +42,7 @@ Status CheckInputs(const T* query, // value (V) : None // bias (Q/K/V) : None // When packed qkv is used: - // query (Q) : (B, L, N, 3, H) + // query (Q) : (B, L, N, 3, H) or (B, S, 3*D) // key (K) : None // value (V) : None // bias (Q/K/V) : None or (D + D + D_v) @@ -56,7 +57,9 @@ Status CheckInputs(const T* query, int batch_size = static_cast(query_dims[0]); int sequence_length = static_cast(query_dims[1]); - int hidden_size = query_dims.size() == 3 ? static_cast(query_dims[2]) : (num_heads * static_cast(query_dims[4])); + int hidden_size = (query_dims.size() == 3) + ? (dmmha_packing ? (static_cast(query_dims[2]) / 3) : static_cast(query_dims[2])) + : (num_heads * static_cast(query_dims[4])); int head_size = static_cast(hidden_size) / num_heads; int kv_sequence_length = sequence_length; @@ -331,13 +334,15 @@ Status CheckInputs(const T* query, float mask_filter_value, float scale, bool past_present_share_buffer, + bool dmmha_packing, int max_threads_per_block) { if (max_threads_per_block > 0 && num_heads > max_threads_per_block) { 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, relative_position_bias, past_key, past_value, - past_seq_len, parameters, num_heads, mask_filter_value, scale, past_present_share_buffer); + past_seq_len, parameters, num_heads, mask_filter_value, scale, past_present_share_buffer, + dmmha_packing); } } // namespace multihead_attention_helper diff --git a/onnxruntime/contrib_ops/cpu/cpu_contrib_kernels.cc b/onnxruntime/contrib_ops/cpu/cpu_contrib_kernels.cc index 31b1b12d3816d..0ec5088808656 100644 --- a/onnxruntime/contrib_ops/cpu/cpu_contrib_kernels.cc +++ b/onnxruntime/contrib_ops/cpu/cpu_contrib_kernels.cc @@ -27,6 +27,9 @@ class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, WordC class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, GatherND); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, TransposeMatMul); // backward compatibility class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, FusedMatMul); +#ifndef ORT_MINIMAL_BUILD +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, MatMulFpQ4); +#endif #if !defined(DISABLE_SPARSE_TENSORS) class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, SparseToDenseMatMul); #endif @@ -53,8 +56,13 @@ class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, QLine class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, QLinearAveragePool); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, uint8_t, DequantizeLinear); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, int8_t, DequantizeLinear); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, uint16_t, DequantizeLinear); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, int16_t, DequantizeLinear); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, int32_t, DequantizeLinear); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, uint8_t, QuantizeLinear); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, int8_t, QuantizeLinear); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, uint16_t, QuantizeLinear); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, int16_t, QuantizeLinear); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, uint8_t, QLinearLeakyRelu); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, int8_t, QLinearLeakyRelu); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, uint8_t, QLinearSigmoid); @@ -79,6 +87,7 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, // ******** End: Quantization ******************* // #ifdef MLAS_F16VEC_INTRINSICS_SUPPORTED +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, MLFloat16, FusedConv); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, MLFloat16, NhwcFusedConv); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSInternalNHWCDomain, 12, MLFloat16, MaxPool); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSInternalNHWCDomain, 11, MLFloat16, AveragePool); @@ -158,7 +167,7 @@ Status RegisterNchwcKernels(KernelRegistry& kernel_registry) { #ifdef MLAS_F16VEC_INTRINSICS_SUPPORTED Status RegisterFp16Kernels(KernelRegistry& kernel_registry) { static const BuildKernelCreateInfoFn function_table[] = { - BuildKernelCreateInfo, // default entry to avoid the list become empty after ops-reducing + BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, @@ -186,8 +195,13 @@ Status RegisterQuantizationKernels(KernelRegistry& kernel_registry) { BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, @@ -248,6 +262,9 @@ Status RegisterCpuContribKernels(KernelRegistry& kernel_registry) { BuildKernelCreateInfo, BuildKernelCreateInfo, // backward compatibility BuildKernelCreateInfo, +#ifndef ORT_MINIMAL_BUILD + BuildKernelCreateInfo, +#endif BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, diff --git a/onnxruntime/contrib_ops/cpu/matmul_fpq4.cc b/onnxruntime/contrib_ops/cpu/matmul_fpq4.cc new file mode 100644 index 0000000000000..9bccdf2fe2090 --- /dev/null +++ b/onnxruntime/contrib_ops/cpu/matmul_fpq4.cc @@ -0,0 +1,97 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// +// This module define MatMulFp32Q4 operator, it is basically +// matmul float32 with right hand side being a 2-D matrix +// pre-packed and block-compacted into int4 +// + +#ifndef ORT_MINIMAL_BUILD + +#include "core/common/safeint.h" +#include "core/framework/op_kernel.h" +#include "core/providers/cpu/math/matmul_helper.h" +#include "core/providers/common.h" +#include "core/mlas/inc/mlas_q4.h" + +namespace onnxruntime { +namespace contrib { + +class MatMulFpQ4 final : public OpKernel { + public: + MatMulFpQ4(const OpKernelInfo& info) : OpKernel(info) { + const auto t = info.GetAttrOrDefault("blk_quant_type", static_cast(1)); + blk_quant_type_ = t == 0 ? BlkQ4Sym : BlkQ4Zp8; + } + + Status Compute(OpKernelContext* context) const override; + MLAS_BLK_QUANT_TYPE blk_quant_type_{BlkQ4Zp8}; +}; + +Status MatMulFpQ4::Compute(OpKernelContext* ctx) const { + concurrency::ThreadPool* thread_pool = ctx->GetOperatorThreadPool(); + + const Tensor* a = ctx->Input(0); + + const Tensor* b = ctx->Input(1); + const auto blob_shape = b->Shape(); + ORT_ENFORCE(blob_shape.NumDimensions() == 1, "Second input of MatMulFpQ4 must be a 1D blob!"); + const auto blob_len = blob_shape[0]; + + const Tensor* bshape_tr = ctx->Input(2); + TensorShape b_shape(bshape_tr->DataAsSpan()); + ORT_ENFORCE(b_shape.NumDimensions() == 2, "Right hand side of MatMulFpQ4 must be a 2D matrix!"); + + MatMulComputeHelper helper; + ORT_RETURN_IF_ERROR(helper.Compute(a->Shape(), b_shape)); + const size_t max_len = helper.OutputOffsets().size(); + const size_t M = static_cast(helper.M()); + const size_t N = static_cast(helper.N()); + const size_t K = static_cast(helper.K()); + const size_t lda = helper.Lda(false); + + auto buf_size = MlasQ4GemmPackBSize(blk_quant_type_, N, K); + ORT_ENFORCE(buf_size > 0, "Operator MatMulFpQ4 not yet supported on this hardware platform."); + ORT_ENFORCE( + (size_t)blob_len == buf_size, + "Quantized and packed blob size differ from expected!"); + + Tensor* y = ctx->Output(0, helper.OutputShape()); + + // Bail out early if the output is going to be empty + if (y->Shape().Size() == 0) + return Status::OK(); + + const auto* a_data = a->Data(); + const auto* blob_data = b->Data(); + auto* y_data = y->MutableData(); + + std::vector gemm_params(max_len); + for (size_t i = 0; i < max_len; i++) { + gemm_params[i].A = a_data + helper.LeftOffsets()[i]; + gemm_params[i].lda = lda; + gemm_params[i].B = blob_data; + gemm_params[i].C = y_data + helper.OutputOffsets()[i]; + gemm_params[i].ldc = N; + } + MlasQ4GemmBatch(blk_quant_type_, M, N, K, max_len, gemm_params.data(), thread_pool); + + return Status::OK(); +} + +ONNX_OPERATOR_KERNEL_EX( + MatMulFpQ4, + kMSDomain, + 1, + kCpuExecutionProvider, + KernelDefBuilder() + .TypeConstraint("T1", DataTypeImpl::GetTensorType()) + .TypeConstraint("T2", DataTypeImpl::GetTensorType()) + .TypeConstraint("T3", DataTypeImpl::GetTensorType()), + MatMulFpQ4); + +} // namespace contrib +} // namespace onnxruntime + +#endif // ORT_MINIMAL_BUILD diff --git a/onnxruntime/contrib_ops/cpu/mean_variance_normalization_exp.cc b/onnxruntime/contrib_ops/cpu/mean_variance_normalization_exp.cc index 564a49d33c7c5..b10a622be8d7d 100644 --- a/onnxruntime/contrib_ops/cpu/mean_variance_normalization_exp.cc +++ b/onnxruntime/contrib_ops/cpu/mean_variance_normalization_exp.cc @@ -13,6 +13,6 @@ ONNX_CPU_OPERATOR_VERSIONED_KERNEL( 1, 8, KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()), - MeanVarianceNormalization_0); + MeanVarianceNormalization); } // namespace contrib } // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cpu/nchwc_ops.cc b/onnxruntime/contrib_ops/cpu/nchwc_ops.cc index ad4a7a591a9b1..13748b43b1ae6 100644 --- a/onnxruntime/contrib_ops/cpu/nchwc_ops.cc +++ b/onnxruntime/contrib_ops/cpu/nchwc_ops.cc @@ -189,16 +189,16 @@ Status NchwcConv::Compute(OpKernelContext* context) const { TensorShape input_shape = X->Shape().Slice(2); ORT_RETURN_IF_ERROR(conv_attrs_.InferPadsAndOutputShape(input_shape, kernel_shape, strides, dilations, pads, Y_dims)); auto* Y = context->Output(0, Y_dims); - auto* y_data = Y->MutableData(); + auto y_data = Y->MutableDataAsSpan(); // Check for the optional Conv/Sum fusion. if (Sum != nullptr) { const auto& sum_shape = Sum->Shape(); ORT_RETURN_IF_NOT(Y->Shape() == sum_shape, "output and sum shape must match"); // If the output was not allocated inplace with the sum tensor, then copy here. - const auto* sum_data = Sum->Data(); - if (y_data != sum_data) { - memcpy(y_data, sum_data, SafeInt(sum_shape.Size()) * sizeof(float)); + auto sum_data = Sum->DataAsSpan(); + if (y_data.data() != sum_data.data()) { + gsl::copy(sum_data, y_data); } } @@ -213,7 +213,7 @@ Status NchwcConv::Compute(OpKernelContext* context) const { X->Data(), W->Data(), B != nullptr ? B->Data() : nullptr, - y_data, + y_data.data(), &activation_, Sum == nullptr, context->GetOperatorThreadPool()); diff --git a/onnxruntime/contrib_ops/cpu/quantization/attention_quant.cc b/onnxruntime/contrib_ops/cpu/quantization/attention_quant.cc index b1915970eac90..6201b892a89b0 100644 --- a/onnxruntime/contrib_ops/cpu/quantization/attention_quant.cc +++ b/onnxruntime/contrib_ops/cpu/quantization/attention_quant.cc @@ -32,7 +32,7 @@ class QAttention : public OpKernel, public AttentionCPUBase { /*out*/ bool& used_shared_buffers) override; private: - BufferUniquePtr packed_weights_; + IAllocatorUniquePtr packed_weights_; size_t packed_weights_size_; TensorShape weight_shape_; bool weights_is_signed_; @@ -90,15 +90,15 @@ Status QAttention::PrePack(const Tensor& weights, int input_idx, AllocatorPtr const size_t loop_len = 3 * static_cast(num_heads_); size_t packed_weights_data_size = packed_weights_size_ * loop_len; - auto* packed_weights_data = static_cast(alloc->Alloc(packed_weights_data_size)); + + packed_weights_ = IAllocator::MakeUniquePtr(alloc, packed_weights_data_size, true); + std::byte* packed_weights_data = static_cast(packed_weights_.get()); // Initialize memory to 0 as there could be some padding associated with pre-packed // buffer memory and we don not want it uninitialized and generate different hashes // if and when we try to cache this pre-packed buffer for sharing between sessions. memset(packed_weights_data, 0, packed_weights_data_size); - packed_weights_ = BufferUniquePtr(packed_weights_data, BufferDeleter(std::move(alloc))); - for (size_t i = 0; i < loop_len; i++) { MlasGemmPackB(head_size, input_hidden_size, weights_data, hidden_size_x3, false /*AIsSigned*/, weights_is_signed_, packed_weights_data); packed_weights_data += packed_weights_size_; diff --git a/onnxruntime/contrib_ops/cpu/quantization/dynamic_quantize_lstm.cc b/onnxruntime/contrib_ops/cpu/quantization/dynamic_quantize_lstm.cc index 88aa8b5bf135d..aa47f365c0005 100644 --- a/onnxruntime/contrib_ops/cpu/quantization/dynamic_quantize_lstm.cc +++ b/onnxruntime/contrib_ops/cpu/quantization/dynamic_quantize_lstm.cc @@ -59,15 +59,17 @@ Status DynamicQuantizeLSTM::TryPackWeights(const Tensor& weights, PackedWeights& return Status::OK(); } - size_t packed_weights_data_size = SafeInt(packed_weights_size * num_directions_); - auto* packed_weights_data = alloc->Alloc(packed_weights_data_size); + size_t packed_weights_data_size = SafeInt(packed_weights_size) * num_directions_; + + packed_weights.buffer_ = IAllocator::MakeUniquePtr(alloc, packed_weights_data_size, true); + + auto* packed_weights_data = packed_weights.buffer_.get(); // Initialize memory to 0 as there could be some padding associated with pre-packed // buffer memory and we don not want it uninitialized and generate different hashes // if and when we try to cache this pre-packed buffer for sharing between sessions. memset(packed_weights_data, 0, packed_weights_data_size); - packed_weights.buffer_ = BufferUniquePtr(packed_weights_data, BufferDeleter(alloc)); packed_weights.buffer_size_ = packed_weights_data_size; packed_weights.weights_size_ = packed_weights_size; packed_weights.shape_ = shape; diff --git a/onnxruntime/contrib_ops/cpu/quantization/dynamic_quantize_matmul.cc b/onnxruntime/contrib_ops/cpu/quantization/dynamic_quantize_matmul.cc index 11d3e40a846bc..69eabcfe2654a 100644 --- a/onnxruntime/contrib_ops/cpu/quantization/dynamic_quantize_matmul.cc +++ b/onnxruntime/contrib_ops/cpu/quantization/dynamic_quantize_matmul.cc @@ -218,7 +218,7 @@ Status DynamicQuantizeMatMul::Compute(OpKernelContext* ctx) const { uint8_t* a_data_quant = static_cast(allocator->Alloc(SafeInt(num_of_elements) * sizeof(uint8_t))); BufferUniquePtr a_buffer_quant_holder(a_data_quant, BufferDeleter(std::move(allocator))); - ParQuantizeLinear(a_data, a_data_quant, narrow(num_of_elements), a_scale, a_zero_point, ctx->GetOperatorThreadPool()); + ParQuantizeLinearStd(a_data, a_data_quant, narrow(num_of_elements), a_scale, a_zero_point, ctx->GetOperatorThreadPool()); bool is_b_scale_supported = IsBQuantParamSupported(b_scale_tensor->Shape(), b ? b->Shape() : b_shape_); ORT_RETURN_IF_ERROR(ComputeCommon( diff --git a/onnxruntime/contrib_ops/cpu/quantization/qembed_layer_norm.cc b/onnxruntime/contrib_ops/cpu/quantization/qembed_layer_norm.cc index 50e77daec3551..2907abbfe7c62 100644 --- a/onnxruntime/contrib_ops/cpu/quantization/qembed_layer_norm.cc +++ b/onnxruntime/contrib_ops/cpu/quantization/qembed_layer_norm.cc @@ -167,7 +167,7 @@ Status ComputeInternal(OpKernelContext* context, float epsilon) { } // Calculate mask - if (nullptr != mask) { + if (nullptr != mask && nullptr != mask_index) { const int32_t* mask_data = mask->Data(); int32_t* mask_index_data = mask_index->MutableData(); for (int b = 0; b < batch_size; b++) { @@ -180,7 +180,7 @@ Status ComputeInternal(OpKernelContext* context, float epsilon) { } mask_index_data[b] = cur_sum; } - } else { + } else if (mask_index != nullptr) { memset(mask_index->MutableData(), 0, batch_size * sizeof(int32_t)); } return Status::OK(); diff --git a/onnxruntime/contrib_ops/cpu/quantization/quant_gemm.cc b/onnxruntime/contrib_ops/cpu/quantization/quant_gemm.cc index 0eb10ef84a57c..ff8ad090820b3 100644 --- a/onnxruntime/contrib_ops/cpu/quantization/quant_gemm.cc +++ b/onnxruntime/contrib_ops/cpu/quantization/quant_gemm.cc @@ -2,6 +2,7 @@ // Licensed under the MIT License. #include "core/common/safeint.h" +#include "core/common/narrow.h" #include "core/providers/cpu/math/gemm_base.h" #include "core/providers/cpu/math/gemm_helper.h" #include "core/providers/cpu/quantization/matmul_integer_base.h" @@ -28,9 +29,9 @@ class QGemm : protected GemmBase, public MatMulIntegerBase { if (!helper.State().IsOK()) return helper.State(); - size_t M = SafeInt(helper.M()); - size_t N = SafeInt(helper.N()); - size_t K = SafeInt(helper.K()); + ptrdiff_t M = helper.M(); + ptrdiff_t N = helper.N(); + ptrdiff_t K = helper.K(); // validate scales and zero points const auto* a_zp = context->Input(IN_A_ZERO_POINT); @@ -39,7 +40,7 @@ class QGemm : protected GemmBase, public MatMulIntegerBase { const auto* a_scale = context->Input(IN_A_SCALE); const auto* b_scale = context->Input(IN_B_SCALE); const auto* y_scale = context->Input(IN_Y_SCALE); - CheckInputs(a_zp, b_zp, y_zp, a_scale, b_scale, y_scale, helper); + ORT_RETURN_IF_ERROR(CheckInputs(a_zp, b_zp, y_zp, a_scale, b_scale, y_scale, helper)); AllocatorPtr allocator; ORT_RETURN_IF_ERROR(context->GetTempSpaceAllocator(&allocator)); @@ -47,14 +48,14 @@ class QGemm : protected GemmBase, public MatMulIntegerBase { bool a_is_signed = a->IsDataType(); const uint8_t* a_data = static_cast(a->DataRaw()); - BufferUniquePtr a_trans_buffer; + std::optional a_trans_buffer; if (trans_A_ == CblasTrans) { a_data = quantization::TransPoseInputData(a_data, a_trans_buffer, allocator, K, M); } bool b_is_signed; const uint8_t* b_data = nullptr; - BufferUniquePtr b_trans_buffer; + std::optional b_trans_buffer; if (nullptr == b) { b_data = static_cast(packed_b_.get()); b_is_signed = b_is_signed_; @@ -66,25 +67,28 @@ class QGemm : protected GemmBase, public MatMulIntegerBase { } } - auto y = context->Output(OUT_Y, {SafeInt(M), SafeInt(N)}); + auto y = context->Output(OUT_Y, {M, N}); if (M == 0 || N == 0) return Status::OK(); // prepare output buffer of GEMM int32_t* gemm_output_data = nullptr; - BufferUniquePtr gemm_output_buffer; + std::optional gemm_output_buffer; bool need_requant = y_scale != nullptr; if (need_requant) { - gemm_output_data = static_cast(allocator->Alloc(SafeInt(M * N) * sizeof(int32_t))); - gemm_output_buffer.reset(gemm_output_data); + TensorShape outputshape{static_cast(M), static_cast(N)}; + gemm_output_buffer.emplace(DataTypeImpl::GetType(), outputshape, allocator); + gemm_output_data = gemm_output_buffer->MutableData(); } else { + // y_scale is NULL. Then y_zp must also be NULL. In this case Y's type must be int32_t. This is checked by the + // OP schema type. So the following cast is safe. gemm_output_data = static_cast(y->MutableDataRaw()); } if (c != nullptr) { - GemmBroadcastBias(M, N, 1.f, c->Data(), &(c->Shape()), gemm_output_data); + GemmBroadcastBias(M, N, 1, c->Data(), &(c->Shape()), gemm_output_data); } - MLAS_GEMM_QUANT_SHAPE_PARAMS gemm_shape{M, N, K, a_is_signed, b_is_signed, c != nullptr}; + MLAS_GEMM_QUANT_SHAPE_PARAMS gemm_shape{narrow(M), narrow(N), narrow(K), a_is_signed, b_is_signed, c != nullptr}; MLAS_GEMM_QUANT_DATA_PARAMS gemm_param; gemm_param.A = a_data; @@ -102,8 +106,8 @@ class QGemm : protected GemmBase, public MatMulIntegerBase { gemm_param.PerColumnZeroPoints = !IsScalarOr1ElementVector(b_zp); std::vector output_scales = ComputeOutputScale(a_scale, b_scale, y_scale); - std::unique_ptr scale_bias_proc_ptr; - std::unique_ptr requant_proc_ptr; + std::optional scale_bias_proc_ptr; + std::optional requant_proc_ptr; SetPostProcessor(y_zp, N, output_scales, y, gemm_param, scale_bias_proc_ptr, requant_proc_ptr); MlasGemmBatch(gemm_shape, &gemm_param, 1, context->GetOperatorThreadPool()); @@ -136,29 +140,30 @@ class QGemm : protected GemmBase, public MatMulIntegerBase { OUT_Y = 0 }; - static void CheckInputs(const Tensor* a_zp, const Tensor* b_zp, const Tensor* y_zp, - const Tensor* a_scale, const Tensor* b_scale, const Tensor* y_scale, const GemmHelper& helper) { - ORT_ENFORCE(IsScalarOr1ElementVector(a_scale), - "QGemm : scale of input a must be a scalar or 1D tensor of size 1"); - ORT_ENFORCE(IsScalarOr1ElementVector(a_zp), - "QGemm : zero point of input a must be a scalar or 1D tensor of size 1"); + static Status CheckInputs(const Tensor* a_zp, const Tensor* b_zp, const Tensor* y_zp, + const Tensor* a_scale, const Tensor* b_scale, const Tensor* y_scale, const GemmHelper& helper) { + ORT_RETURN_IF_NOT(IsScalarOr1ElementVector(a_scale), + "QGemm : scale of input a must be a scalar or 1D tensor of size 1"); + ORT_RETURN_IF_NOT(IsScalarOr1ElementVector(a_zp), + "QGemm : zero point of input a must be a scalar or 1D tensor of size 1"); const auto& b_zp_shape = b_zp->Shape(); const auto& b_scale_shape = b_scale->Shape(); - ORT_ENFORCE(b_zp_shape.NumDimensions() == 0 || - (b_zp_shape.NumDimensions() == 1 && (b_zp_shape[0] == 1 || b_zp_shape[0] == helper.N())), - "QGemm : zero point of input b must be a scalar or 1D tensor of size 1 or N"); - ORT_ENFORCE(b_scale_shape.NumDimensions() == 0 || - (b_scale_shape.NumDimensions() == 1 && (b_scale_shape[0] == 1 || b_scale_shape[0] == helper.N())), - "QGemm : scale of input b must be a scalar or 1D tensor of size 1 or N"); - ORT_ENFORCE(b_scale_shape.NumDimensions() == b_zp_shape.NumDimensions() && - (b_scale_shape.NumDimensions() == 0 || (b_scale_shape[0] == b_zp_shape[0])), - "QGemm : zero point and scale of input b should have same shape size"); - - ORT_ENFORCE(y_zp == nullptr || IsScalarOr1ElementVector(y_zp), - "QGemm : zero point of y must be null or a scalar or 1D tensor of size 1"); - ORT_ENFORCE(y_scale == nullptr || IsScalarOr1ElementVector(y_scale), - "QGemm : scale of y must be null or a scalar or 1D tensor of size 1"); + ORT_RETURN_IF_NOT(b_zp_shape.NumDimensions() == 0 || + (b_zp_shape.NumDimensions() == 1 && (b_zp_shape[0] == 1 || b_zp_shape[0] == helper.N())), + "QGemm : zero point of input b must be a scalar or 1D tensor of size 1 or N"); + ORT_RETURN_IF_NOT(b_scale_shape.NumDimensions() == 0 || + (b_scale_shape.NumDimensions() == 1 && (b_scale_shape[0] == 1 || b_scale_shape[0] == helper.N())), + "QGemm : scale of input b must be a scalar or 1D tensor of size 1 or N"); + ORT_RETURN_IF_NOT(b_scale_shape.NumDimensions() == b_zp_shape.NumDimensions() && + (b_scale_shape.NumDimensions() == 0 || (b_scale_shape[0] == b_zp_shape[0])), + "QGemm : zero point and scale of input b should have same shape size"); + + ORT_RETURN_IF_NOT(y_zp == nullptr || IsScalarOr1ElementVector(y_zp), + "QGemm : zero point of y must be null or a scalar or 1D tensor of size 1"); + ORT_RETURN_IF_NOT(y_scale == nullptr || IsScalarOr1ElementVector(y_scale), + "QGemm : scale of y must be null or a scalar or 1D tensor of size 1"); + return Status::OK(); } std::vector ComputeOutputScale(const Tensor* a_scale, const Tensor* b_scale, const Tensor* y_scale) const { @@ -180,12 +185,12 @@ class QGemm : protected GemmBase, public MatMulIntegerBase { const std::vector& output_scales, Tensor* y, MLAS_GEMM_QUANT_DATA_PARAMS& gemm_param, - std::unique_ptr& scale_bias_proc_ptr, - std::unique_ptr& requant_proc_ptr) { + std::optional& scale_bias_proc_ptr, + std::optional& requant_proc_ptr) { if (nullptr != y_zp) { bool is_y_signed = y->IsDataType(); int32_t y_zero_point = is_y_signed ? *y_zp->Data() : *y_zp->Data(); - requant_proc_ptr = std::make_unique( + requant_proc_ptr.emplace( y->MutableDataRaw(), out_lda, nullptr, @@ -193,16 +198,16 @@ class QGemm : protected GemmBase, public MatMulIntegerBase { output_scales.size() > 1, y_zero_point, is_y_signed); - gemm_param.OutputProcessor = requant_proc_ptr.get(); + gemm_param.OutputProcessor = &*requant_proc_ptr; } else { - scale_bias_proc_ptr = std::make_unique( + scale_bias_proc_ptr.emplace( static_cast(y->MutableDataRaw()), out_lda, output_scales.data(), nullptr, MLAS_QGEMM_OUTPUT_MODE::ZeroMode, output_scales.size() > 1 ? MLAS_QUANTIZATION_GRANULARITY::PerColumn : MLAS_QUANTIZATION_GRANULARITY::PerMatrix); - gemm_param.OutputProcessor = scale_bias_proc_ptr.get(); + gemm_param.OutputProcessor = &*scale_bias_proc_ptr; } } }; diff --git a/onnxruntime/contrib_ops/cpu/quantization/quantize_ops.cc b/onnxruntime/contrib_ops/cpu/quantization/quantize_ops.cc deleted file mode 100644 index 9d2931e9c98d0..0000000000000 --- a/onnxruntime/contrib_ops/cpu/quantization/quantize_ops.cc +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "core/providers/cpu/quantization/quantize_linear.h" -#include "core/providers/common.h" - -namespace onnxruntime { -namespace contrib { - -ONNX_CPU_OPERATOR_TYPED_MS_KERNEL( - DequantizeLinear, - 1, - uint8_t, - KernelDefBuilder() - .TypeConstraint("T1", DataTypeImpl::GetTensorType()) - .TypeConstraint("T2", DataTypeImpl::GetTensorType()), - DequantizeLinear); - -ONNX_CPU_OPERATOR_TYPED_MS_KERNEL( - DequantizeLinear, - 1, - int8_t, - KernelDefBuilder() - .TypeConstraint("T1", DataTypeImpl::GetTensorType()) - .TypeConstraint("T2", DataTypeImpl::GetTensorType()), - DequantizeLinear); - -ONNX_CPU_OPERATOR_TYPED_MS_KERNEL( - QuantizeLinear, - 1, - uint8_t, - KernelDefBuilder() - .TypeConstraint("T1", DataTypeImpl::GetTensorType()) - .TypeConstraint("T2", DataTypeImpl::GetTensorType()), - QuantizeLinear); - -ONNX_CPU_OPERATOR_TYPED_MS_KERNEL( - QuantizeLinear, - 1, - int8_t, - KernelDefBuilder() - .TypeConstraint("T1", DataTypeImpl::GetTensorType()) - .TypeConstraint("T2", DataTypeImpl::GetTensorType()), - QuantizeLinear); - -} // namespace contrib -} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cpu/skip_layer_norm.cc b/onnxruntime/contrib_ops/cpu/skip_layer_norm.cc index b3668bcc0be6a..e86a12d9fb873 100644 --- a/onnxruntime/contrib_ops/cpu/skip_layer_norm.cc +++ b/onnxruntime/contrib_ops/cpu/skip_layer_norm.cc @@ -6,6 +6,7 @@ #include "core/providers/common.h" #include "core/platform/threadpool.h" #include "skip_layer_norm.h" +#include "skip_layer_norm_helper.h" namespace onnxruntime { namespace contrib { @@ -45,51 +46,15 @@ Status SkipLayerNorm::Compute(OpKernelContext* p_ctx) const { const auto& input_dims = input->Shape().GetDims(); size_t input_dims_size = input_dims.size(); - if (input_dims_size != 3 && input_dims_size != 2) { - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, - "input is expected to have 3 or 2 dimensions, got ", input_dims_size); - } - int hidden_size = static_cast(input_dims[input_dims_size - 1]); - if (input->Shape() != skip->Shape()) { - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, - "skip is expected to have same shape as input"); - } - - const auto& gamma_dims = gamma->Shape().GetDims(); - if (gamma_dims.size() != 1) { - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, - "gamma is expected to have 1 dimension, got ", gamma_dims.size()); - } - if (gamma_dims[0] != hidden_size) { - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, - "Last dimension of gamma and input does not match"); - } - - if (nullptr != beta) { - const auto& beta_dims = beta->Shape().GetDims(); - if (beta_dims.size() != 1) { - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, - "beta is expected to have 1 dimension, got ", beta_dims.size()); - } - if (beta_dims[0] != hidden_size) { - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, - "Last dimension of beta and input does not match"); - } - } - - if (nullptr != bias) { - const auto& bias_dims = bias->Shape().GetDims(); - if (bias_dims.size() != 1) { - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, - "bias is expected to have 1 dimension, got ", bias_dims.size()); - } - if (bias_dims[0] != hidden_size) { - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, - "Last dimension of bias and input does not match"); - } - } + ORT_RETURN_IF_ERROR(onnxruntime::contrib::skip_layer_norm_helper::CheckInputs(input, + skip, + gamma, + beta, + bias, + hidden_size, + input_dims_size)); int64_t task_count = input->Shape().SizeToDimension(input_dims_size - 1); @@ -105,13 +70,15 @@ Status SkipLayerNorm::Compute(OpKernelContext* p_ctx) const { // of the input and skip tensors T* skip_input_bias_add_output_data = skip_input_bias_add_output != nullptr ? skip_input_bias_add_output->MutableData() : nullptr; + const auto& skip_size = skip->Shape().Size(); + concurrency::ThreadPool::TryBatchParallelFor( p_ctx->GetOperatorThreadPool(), static_cast(task_count), [&](ptrdiff_t task_idx) { auto offset = task_idx * hidden_size; const T* p_input = input_data + offset; - const T* p_skip = skip_data + offset; + const T* p_skip = skip_data + (offset % skip_size); T* p_output = output_data + offset; T* p_skip_input_bias_add_output_data = skip_input_bias_add_output_data != nullptr ? skip_input_bias_add_output_data + offset : nullptr; diff --git a/onnxruntime/contrib_ops/cpu/skip_layer_norm_helper.h b/onnxruntime/contrib_ops/cpu/skip_layer_norm_helper.h new file mode 100644 index 0000000000000..6271f822287e6 --- /dev/null +++ b/onnxruntime/contrib_ops/cpu/skip_layer_norm_helper.h @@ -0,0 +1,84 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/common/common.h" +#include "core/providers/common.h" +#include "contrib_ops/cpu/bert/attention_common.h" + +namespace onnxruntime { +namespace contrib { +namespace skip_layer_norm_helper { + +template +Status CheckInputs(const T* input, + const T* skip, + const T* gamma, + const T* beta, + const T* bias, + int hidden_size_check, + size_t input_dims_size_check) { + const auto& input_dims_check = input->Shape().GetDims(); + const auto& skip_dims_check = skip->Shape().GetDims(); + size_t skip_dims_size_check = skip_dims_check.size(); + + if (skip_dims_size_check != 3 && skip_dims_size_check != 2) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "skip is expected to have 3 or 2 dimensions, got ", skip_dims_size_check); + } + + if ((input->Shape() != skip->Shape()) && ((skip_dims_check[0] != 1 || skip_dims_size_check != 2) && input_dims_size_check != 3)) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "skip is expected to have same shape as input or, a batch size of 1 or no batch size when input has 3 dimensions"); + } + + if (input_dims_size_check != 3 && input_dims_size_check != 2) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "input is expected to have 3 or 2 dimensions, got ", input_dims_size_check); + } + + if (skip_dims_check[skip_dims_size_check - 1] != input_dims_check[input_dims_size_check - 1] || skip_dims_check[skip_dims_size_check - 2] != input_dims_check[input_dims_size_check - 2]) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "last two dimensions of skip needs to be same as input"); + } + + const auto& gamma_dims = gamma->Shape().GetDims(); + if (gamma_dims.size() != 1) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "gamma is expected to have 1 dimension, got ", gamma_dims.size()); + } + if (gamma_dims[0] != hidden_size_check) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "Last dimension of gamma and input does not match"); + } + + if (nullptr != beta) { + const auto& beta_dims = beta->Shape().GetDims(); + if (beta_dims.size() != 1) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "beta is expected to have 1 dimension, got ", beta_dims.size()); + } + if (beta_dims[0] != hidden_size_check) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "Last dimension of beta and input does not match"); + } + } + + if (nullptr != bias) { + const auto& bias_dims = bias->Shape().GetDims(); + if (bias_dims.size() != 1) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "bias is expected to have 1 dimension, got ", bias_dims.size()); + } + if (bias_dims[0] != hidden_size_check) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "Last dimension of bias and input does not match"); + } + } + return Status::OK(); +} + +} // namespace skip_layer_norm_helper +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cpu/tensor/shrunken_gather.cc b/onnxruntime/contrib_ops/cpu/tensor/shrunken_gather.cc index b8885a0e1fe7f..6359f340e8615 100644 --- a/onnxruntime/contrib_ops/cpu/tensor/shrunken_gather.cc +++ b/onnxruntime/contrib_ops/cpu/tensor/shrunken_gather.cc @@ -37,7 +37,7 @@ void ShrunkenGatherCommon::CheckInput(const Tensor* input_tensor, const Tensor* auto axis = HandleNegativeAxis(axis_in, narrow(input_rank)); const int64_t N = indices_shape.Size(); - const int64_t indices_max = input_shape[axis]; + const int64_t indices_max = input_shape[gsl::narrow_cast(axis)]; ORT_ENFORCE(indices_max >= N, "ShrunkenGather indices elem count should <= input dim on axis: ", axis, ", got indices elem count:", N, " input dim: ", indices_max); } diff --git a/onnxruntime/contrib_ops/cpu/tokenizer.cc b/onnxruntime/contrib_ops/cpu/tokenizer.cc index 45998b6d83104..1787fb9b3c4a6 100644 --- a/onnxruntime/contrib_ops/cpu/tokenizer.cc +++ b/onnxruntime/contrib_ops/cpu/tokenizer.cc @@ -242,7 +242,7 @@ Status Tokenizer::SeparatorExpressionTokenizer(OpKernelContext* ctx, token_len, utf8_chars); if (!valid) { return Status(common::ONNXRUNTIME, common::INVALID_ARGUMENT, - "Match contains invalid utf8 chars: " + submatch.as_string()); + "Match contains invalid utf8 chars: " + std::string{submatch}); } if (utf8_chars >= size_t(mincharnum_)) { tokens.emplace_back(text.data() + start_pos, token_len); @@ -384,7 +384,7 @@ Status Tokenizer::TokenExpression(OpKernelContext* ctx, utf8_chars = 0; if (!utf8_len(reinterpret_cast(submatch.data()), token_len, utf8_chars)) { return Status(common::ONNXRUNTIME, common::INVALID_ARGUMENT, - "Match contains invalid utf8 chars: " + submatch.as_string()); + "Match contains invalid utf8 chars: " + std::string{submatch}); } if (utf8_chars >= size_t(mincharnum_)) { row.push_back(submatch); diff --git a/onnxruntime/contrib_ops/cpu/transformers/beam_search.cc b/onnxruntime/contrib_ops/cpu/transformers/beam_search.cc index 80cae088d109e..c391f47e1927b 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/beam_search.cc +++ b/onnxruntime/contrib_ops/cpu/transformers/beam_search.cc @@ -34,7 +34,7 @@ #include "contrib_ops/cpu/transformers/beam_search_scorer.h" #include "contrib_ops/cpu/transformers/beam_search_impl_gpt.h" #include "contrib_ops/cpu/transformers/beam_search_impl_t5.h" -#include "contrib_ops/cpu/transformers/subgraph_whisper_encoder.h" +#include "contrib_ops/cpu/transformers/beam_search_impl_whisper.h" #include "contrib_ops/cpu/transformers/greedy_search_impl_gpt.h" using namespace ONNX_NAMESPACE; @@ -61,7 +61,7 @@ namespace transformers { void BeamSearch::Init(const OpKernelInfo& info) { parameters_.ParseFromAttributes(info); - // Model_type could be either 0 (GPT-2) or 1 (encoder-decoder like T5) + // Model_type could be either 0 (GPT-2), 1 (encoder-decoder like T5), or 2 (Whisper) ORT_ENFORCE(parameters_.model_type == IGenerationParameters::kModelTypeGpt || parameters_.model_type == IGenerationParameters::kModelTypeT5 || parameters_.model_type == IGenerationParameters::kModelTypeWhisper); @@ -69,7 +69,7 @@ void BeamSearch::Init(const OpKernelInfo& info) { ONNX_NAMESPACE::GraphProto proto; if (parameters_.model_type != IGenerationParameters::kModelTypeGpt) { - // Make sure the encoder sub-graph attribute is present for the T5 model. + // Make sure the encoder sub-graph attribute is present for the T5 and Whisper models. ORT_ENFORCE(info.GetAttr("encoder", &proto).IsOK()); } @@ -151,33 +151,28 @@ Status BeamSearch::SetupSubgraphExecutionInfo(const SessionState& session_state, } } else if (parameters_.model_type == IGenerationParameters::kModelTypeWhisper) { if (attribute_name == "encoder") { - ORT_ENFORCE(t5_encoder_subgraph_ == nullptr, + ORT_ENFORCE(whisper_encoder_subgraph_ == nullptr, "SetupSubgraphExecutionInfo should only be called once for each subgraph."); - t5_encoder_subgraph_ = std::make_unique(node, - attribute_name, - subgraph_session_state.GetGraphViewer()); - 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"); - } 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"); - } + whisper_encoder_subgraph_ = std::make_unique(node, + attribute_name, + subgraph_session_state.GetGraphViewer()); + ORT_RETURN_IF_ERROR(whisper_encoder_subgraph_->Setup(session_state, subgraph_session_state)); + encoder_feeds_fetches_manager_ = whisper_encoder_subgraph_->GetFeedsFetchesManager(); + + ORT_RETURN_IF(whisper_encoder_subgraph_->num_subgraph_inputs != 2, + "Encoder subgraph shall have 2 inputs (encoder_input_ids, decoder_input_ids)"); } else if (attribute_name == "decoder") { - ORT_ENFORCE(t5_decoder_subgraph_ == nullptr, + ORT_ENFORCE(whisper_decoder_subgraph_ == nullptr, "SetupSubgraphExecutionInfo should only be called once for each subgraph."); - t5_decoder_subgraph_ = std::make_unique(node, - attribute_name, - subgraph_session_state.GetGraphViewer()); - ORT_RETURN_IF_ERROR(t5_decoder_subgraph_->Setup(session_state, subgraph_session_state)); - decoder_feeds_fetches_manager_ = t5_decoder_subgraph_->GetFeedsFetchesManager(); - parameters_.SetSubgraphParameters(t5_decoder_subgraph_->vocab_size, - t5_decoder_subgraph_->num_heads, - t5_decoder_subgraph_->head_size, - t5_decoder_subgraph_->num_layers); + whisper_decoder_subgraph_ = std::make_unique(node, + attribute_name, + subgraph_session_state.GetGraphViewer()); + ORT_RETURN_IF_ERROR(whisper_decoder_subgraph_->Setup(session_state, subgraph_session_state)); + decoder_feeds_fetches_manager_ = whisper_decoder_subgraph_->GetFeedsFetchesManager(); + parameters_.SetSubgraphParameters(whisper_decoder_subgraph_->vocab_size, + whisper_decoder_subgraph_->num_heads, + whisper_decoder_subgraph_->head_size, + whisper_decoder_subgraph_->num_layers); } } @@ -215,15 +210,16 @@ Status BeamSearch::Compute(OpKernelContext* ctx) const { thread_pool, ctx->GetComputeStream(), dumper_, parameters, GenerationCpuDeviceHelper::CreateGptInputs, add_to_feeds_func_ ? add_to_feeds_func_ : GenerationCpuDeviceHelper::AddToFeeds, - reorder_past_state_func_ ? reorder_past_state_func_ : nullptr, // Only CUDA implementation needs the reorder helper for now topk_func_ ? topk_func_ : GenerationCpuDeviceHelper::TopK, process_logits_func_ ? process_logits_func_ : GenerationCpuDeviceHelper::ProcessLogits, init_beam_state_func_ ? init_beam_state_func_ : GenerationCpuDeviceHelper::InitBeamState, device_copy_func_ ? device_copy_func_ : GenerationCpuDeviceHelper::DeviceCopy, device_copy_int32_func_ ? device_copy_int32_func_ : GenerationCpuDeviceHelper::DeviceCopy, update_gpt_feeds_func_ ? update_gpt_feeds_func_ : GenerationCpuDeviceHelper::UpdateGptFeeds, - cuda_device_prop_, - cuda_device_arch_}; + create_beam_scorer_func_}; +#ifdef USE_CUDA + ORT_RETURN_IF_ERROR(impl.InitializeCuda(reorder_past_state_func_, cuda_device_prop_, cuda_device_arch_)); +#endif ORT_RETURN_IF_ERROR(impl.Initialize()); return impl.Execute(init_run_decoder_feeds_fetches_manager_, *decoder_feeds_fetches_manager_); @@ -237,15 +233,16 @@ Status BeamSearch::Compute(OpKernelContext* ctx) const { thread_pool, ctx->GetComputeStream(), dumper_, parameters, GenerationCpuDeviceHelper::CreateGptInputs, add_to_feeds_func_ ? add_to_feeds_func_ : GenerationCpuDeviceHelper::AddToFeeds, - reorder_past_state_func_ ? reorder_past_state_func_ : nullptr, // Only CUDA implementation needs the reorder helper for now topk_func_ ? topk_func_ : GenerationCpuDeviceHelper::TopK, process_logits_fp16_func_, init_beam_state_fp16_func_, device_copy_func_, device_copy_int32_func_, update_gpt_feeds_fp16_func_, - cuda_device_prop_, - cuda_device_arch_}; + create_beam_scorer_func_}; +#ifdef USE_CUDA + ORT_RETURN_IF_ERROR(impl.InitializeCuda(reorder_past_state_func_, cuda_device_prop_, cuda_device_arch_)); +#endif ORT_RETURN_IF_ERROR(impl.Initialize()); return impl.Execute(init_run_decoder_feeds_fetches_manager_, *decoder_feeds_fetches_manager_); @@ -263,8 +260,6 @@ Status BeamSearch::Compute(OpKernelContext* ctx) const { *ctx_internal, *encoder_session_state, *decoder_session_state, *t5_encoder_subgraph_, *t5_decoder_subgraph_, thread_pool, ctx->GetComputeStream(), dumper_, parameters, add_to_feeds_func_ ? add_to_feeds_func_ : GenerationCpuDeviceHelper::AddToFeeds, - reorder_past_state_func_ ? reorder_past_state_func_ : nullptr, // Only CUDA implementation needs the reorder helper for now - init_cache_indir_func_ ? init_cache_indir_func_ : nullptr, // Only CUDA implementation needs the init cache_indir for now topk_func_ ? topk_func_ : GenerationCpuDeviceHelper::TopK, process_logits_func_ ? process_logits_func_ : GenerationCpuDeviceHelper::ProcessLogits, init_beam_state_func_ ? init_beam_state_func_ : GenerationCpuDeviceHelper::InitBeamState, @@ -275,8 +270,10 @@ Status BeamSearch::Compute(OpKernelContext* ctx) const { expand_buffer_int32_func_ ? expand_buffer_int32_func_ : GenerationCpuDeviceHelper::ExpandBuffer, expand_buffer_float_func_ ? expand_buffer_float_func_ : GenerationCpuDeviceHelper::ExpandBuffer, expand_buffer_float16_func_ ? expand_buffer_float16_func_ : GenerationCpuDeviceHelper::ExpandBuffer, - cuda_device_prop_, - cuda_device_arch_}; + 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 ORT_RETURN_IF_ERROR(impl.Initialize()); return impl.Execute(*encoder_feeds_fetches_manager_, *decoder_feeds_fetches_manager_); @@ -285,8 +282,6 @@ Status BeamSearch::Compute(OpKernelContext* ctx) const { *ctx_internal, *encoder_session_state, *decoder_session_state, *t5_encoder_subgraph_, *t5_decoder_subgraph_, thread_pool, ctx->GetComputeStream(), dumper_, parameters, add_to_feeds_func_ ? add_to_feeds_func_ : GenerationCpuDeviceHelper::AddToFeeds, - reorder_past_state_func_ ? reorder_past_state_func_ : nullptr, // Only CUDA implementation needs the reorder helper for now - init_cache_indir_func_ ? init_cache_indir_func_ : nullptr, // Only CUDA implementation needs the init cache_indir for now topk_func_ ? topk_func_ : GenerationCpuDeviceHelper::TopK, process_logits_fp16_func_, init_beam_state_fp16_func_, @@ -297,9 +292,10 @@ Status BeamSearch::Compute(OpKernelContext* ctx) const { expand_buffer_int32_func_, expand_buffer_float_func_, expand_buffer_float16_func_, - cuda_device_prop_, - cuda_device_arch_}; - + 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 ORT_RETURN_IF_ERROR(impl.Initialize()); return impl.Execute(*encoder_feeds_fetches_manager_, *decoder_feeds_fetches_manager_); @@ -309,48 +305,45 @@ Status BeamSearch::Compute(OpKernelContext* ctx) const { // Change the CreateEncoderInputs function for Whisper shapes if (parameters_.model_type == IGenerationParameters::kModelTypeWhisper) { // Subgraph has constraint that the output is either float or float16 - if (!t5_decoder_subgraph_->IsOutputFloat16()) { - BeamSearchT5 impl{ - *ctx_internal, *encoder_session_state, *decoder_session_state, *t5_encoder_subgraph_, - *t5_decoder_subgraph_, thread_pool, ctx->GetComputeStream(), dumper_, parameters, + if (!whisper_decoder_subgraph_->IsOutputFloat16()) { + BeamSearchWhisper impl{ + *ctx_internal, *encoder_session_state, *decoder_session_state, *whisper_encoder_subgraph_, + *whisper_decoder_subgraph_, thread_pool, ctx->GetComputeStream(), dumper_, parameters, add_to_feeds_func_ ? add_to_feeds_func_ : GenerationCpuDeviceHelper::AddToFeeds, - reorder_past_state_func_ ? reorder_past_state_func_ : nullptr, // Only CUDA implementation needs the reorder helper for now - init_cache_indir_func_ ? init_cache_indir_func_ : nullptr, // Only CUDA implementation needs the init cache_indir for now topk_func_ ? topk_func_ : GenerationCpuDeviceHelper::TopK, process_logits_func_ ? process_logits_func_ : GenerationCpuDeviceHelper::ProcessLogits, init_beam_state_func_ ? init_beam_state_func_ : GenerationCpuDeviceHelper::InitBeamState, device_copy_func_ ? device_copy_func_ : GenerationCpuDeviceHelper::DeviceCopy, device_copy_int32_func_ ? device_copy_int32_func_ : GenerationCpuDeviceHelper::DeviceCopy, - create_encoder_inputs_func_ ? create_encoder_inputs_func_ : GenerationCpuDeviceHelper::CreateWhisperEncoderInputs, + create_whisper_encoder_inputs_func_ ? create_whisper_encoder_inputs_func_ : GenerationCpuDeviceHelper::CreateWhisperEncoderInputs, update_decoder_feeds_func_ ? update_decoder_feeds_func_ : GenerationCpuDeviceHelper::UpdateDecoderFeeds, - expand_buffer_int32_func_ ? expand_buffer_int32_func_ : GenerationCpuDeviceHelper::ExpandBuffer, expand_buffer_float_func_ ? expand_buffer_float_func_ : GenerationCpuDeviceHelper::ExpandBuffer, expand_buffer_float16_func_ ? expand_buffer_float16_func_ : GenerationCpuDeviceHelper::ExpandBuffer, - cuda_device_prop_, - cuda_device_arch_}; + 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 ORT_RETURN_IF_ERROR(impl.Initialize()); return impl.Execute(*encoder_feeds_fetches_manager_, *decoder_feeds_fetches_manager_); } else { - BeamSearchT5 impl{ - *ctx_internal, *encoder_session_state, *decoder_session_state, *t5_encoder_subgraph_, - *t5_decoder_subgraph_, thread_pool, ctx->GetComputeStream(), dumper_, parameters, + BeamSearchWhisper impl{ + *ctx_internal, *encoder_session_state, *decoder_session_state, *whisper_encoder_subgraph_, + *whisper_decoder_subgraph_, thread_pool, ctx->GetComputeStream(), dumper_, parameters, add_to_feeds_func_ ? add_to_feeds_func_ : GenerationCpuDeviceHelper::AddToFeeds, - reorder_past_state_func_ ? reorder_past_state_func_ : nullptr, // Only CUDA implementation needs the reorder helper for now - init_cache_indir_func_ ? init_cache_indir_func_ : nullptr, // Only CUDA implementation needs the init cache_indir for now topk_func_ ? topk_func_ : GenerationCpuDeviceHelper::TopK, process_logits_fp16_func_, init_beam_state_fp16_func_, device_copy_func_, device_copy_int32_func_, - create_encoder_inputs_func_ ? create_encoder_inputs_func_ : GenerationCpuDeviceHelper::CreateWhisperEncoderInputs, - update_decoder_feeds_fp16_func_, - expand_buffer_int32_func_, + create_whisper_encoder_inputs_func_ ? create_whisper_encoder_inputs_func_ : GenerationCpuDeviceHelper::CreateWhisperEncoderInputs, + update_decoder_feeds_fp16_func_ ? update_decoder_feeds_fp16_func_ : GenerationCpuDeviceHelper::UpdateDecoderFeeds, expand_buffer_float_func_, expand_buffer_float16_func_, - cuda_device_prop_, - cuda_device_arch_}; - + 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 ORT_RETURN_IF_ERROR(impl.Initialize()); return impl.Execute(*encoder_feeds_fetches_manager_, *decoder_feeds_fetches_manager_); diff --git a/onnxruntime/contrib_ops/cpu/transformers/beam_search.h b/onnxruntime/contrib_ops/cpu/transformers/beam_search.h index 63b0418a12d59..93b7e08fabf94 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/beam_search.h +++ b/onnxruntime/contrib_ops/cpu/transformers/beam_search.h @@ -11,6 +11,8 @@ #include "contrib_ops/cpu/transformers/subgraph_gpt.h" #include "contrib_ops/cpu/transformers/subgraph_t5_encoder.h" #include "contrib_ops/cpu/transformers/subgraph_t5_decoder.h" +#include "contrib_ops/cpu/transformers/subgraph_whisper_encoder.h" +#include "contrib_ops/cpu/transformers/subgraph_whisper_decoder.h" #include "contrib_ops/cpu/transformers/generation_device_helper.h" namespace onnxruntime { @@ -44,8 +46,6 @@ class BeamSearch : public IControlFlowKernel { // device helpers that is same for both GPT and encoder-decoder models. void SetDeviceHelpers( - const GenerationDeviceHelper::ReorderPastStateFunc& reorder_past_state_func, - const GenerationDeviceHelper::InitCacheIndirFunc& init_cache_indir_func, const GenerationDeviceHelper::AddToFeedsFunc& add_to_feeds_func, const GenerationDeviceHelper::TopkFunc& topk_func, const GenerationDeviceHelper::DeviceCopyFunc& device_copy_func, @@ -53,9 +53,8 @@ class BeamSearch : public IControlFlowKernel { const GenerationDeviceHelper::ProcessLogitsFunc& process_logits_func, const GenerationDeviceHelper::ProcessLogitsFunc& process_logits_fp16_func, const GenerationDeviceHelper::InitBeamStateFunc& init_beam_state_func, - const GenerationDeviceHelper::InitBeamStateFunc& init_beam_state_fp16_func) { - reorder_past_state_func_ = reorder_past_state_func; - init_cache_indir_func_ = init_cache_indir_func; + const GenerationDeviceHelper::InitBeamStateFunc& init_beam_state_fp16_func, + const GenerationDeviceHelper::CreateBeamScorer& create_beam_scorer_func) { add_to_feeds_func_ = add_to_feeds_func; topk_func_ = topk_func; device_copy_func_ = device_copy_func; @@ -64,8 +63,18 @@ class BeamSearch : public IControlFlowKernel { process_logits_fp16_func_ = process_logits_fp16_func; init_beam_state_func_ = init_beam_state_func; init_beam_state_fp16_func_ = init_beam_state_fp16_func; + create_beam_scorer_func_ = create_beam_scorer_func; } +#ifdef USE_CUDA + void SetDeviceHelpers_Cuda( + const GenerationDeviceHelper::ReorderPastStateFunc& reorder_past_state_func, + const GenerationDeviceHelper::InitCacheIndirFunc& init_cache_indir_func) { + reorder_past_state_func_ = reorder_past_state_func; + init_cache_indir_func_ = init_cache_indir_func; + } +#endif + void SetDeviceHelpers_Gpt( const GenerationDeviceHelper::UpdateGptFeedsFunc& update_gpt_feeds_func, const GenerationDeviceHelper::UpdateGptFeedsFunc& update_gpt_feeds_fp16_func) { @@ -87,13 +96,13 @@ class BeamSearch : public IControlFlowKernel { expand_buffer_float16_func_ = expand_buffer_float16_func; } +#ifdef USE_CUDA const void* cuda_device_prop_ = nullptr; int cuda_device_arch_ = 0; +#endif private: // Device specific functions - GenerationDeviceHelper::ReorderPastStateFunc reorder_past_state_func_; - GenerationDeviceHelper::InitCacheIndirFunc init_cache_indir_func_; GenerationDeviceHelper::AddToFeedsFunc add_to_feeds_func_; GenerationDeviceHelper::TopkFunc topk_func_; GenerationDeviceHelper::DeviceCopyFunc device_copy_func_; @@ -104,6 +113,12 @@ class BeamSearch : public IControlFlowKernel { GenerationDeviceHelper::InitBeamStateFunc init_beam_state_func_; GenerationDeviceHelper::InitBeamStateFunc init_beam_state_fp16_func_; + GenerationDeviceHelper::CreateBeamScorer create_beam_scorer_func_; + +#ifdef USE_CUDA + GenerationDeviceHelper::ReorderPastStateFunc reorder_past_state_func_; + GenerationDeviceHelper::InitCacheIndirFunc init_cache_indir_func_; +#endif //------------------------------------------------------------ // Device specific functions for GPT @@ -115,10 +130,14 @@ class BeamSearch : public IControlFlowKernel { // Device specific functions for encoder-decoder model like T5 //------------------------------------------------------------ GenerationDeviceHelper::CreateEncoderInputsFunc create_encoder_inputs_func_; - GenerationDeviceHelper::UpdateDecoderFeedsFunc update_decoder_feeds_func_; GenerationDeviceHelper::UpdateDecoderFeedsFunc update_decoder_feeds_fp16_func_; + //------------------------------------------------------------ + // Device specific functions for Whisper + //------------------------------------------------------------ + GenerationDeviceHelper::CreateWhisperEncoderInputsFunc create_whisper_encoder_inputs_func_; + GenerationDeviceHelper::ExpandBufferFunc expand_buffer_int32_func_; GenerationDeviceHelper::ExpandBufferFunc expand_buffer_float_func_; GenerationDeviceHelper::ExpandBufferFunc expand_buffer_float16_func_; @@ -143,6 +162,10 @@ class BeamSearch : public IControlFlowKernel { std::unique_ptr t5_encoder_subgraph_; std::unique_ptr t5_decoder_subgraph_; + // Relevant only for Whisper + std::unique_ptr whisper_encoder_subgraph_; + std::unique_ptr whisper_decoder_subgraph_; + FeedsFetchesManager* encoder_feeds_fetches_manager_; FeedsFetchesManager* decoder_feeds_fetches_manager_; FeedsFetchesManager* init_run_decoder_feeds_fetches_manager_; diff --git a/onnxruntime/contrib_ops/cpu/transformers/beam_search_impl_base.h b/onnxruntime/contrib_ops/cpu/transformers/beam_search_impl_base.h index 43024cc5bba3d..8832b4314bad3 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/beam_search_impl_base.h +++ b/onnxruntime/contrib_ops/cpu/transformers/beam_search_impl_base.h @@ -13,42 +13,37 @@ namespace contrib { namespace transformers { template -struct BeamSearchState : public IBeamSearchState { - void Init(AllocatorPtr allocator, - int batch_size, - int num_beams, - int vocab_size, - int sequence_length, - int max_length, - int num_heads, - int head_size, - int has_decoder_masked_attention, - bool output_scores, - bool use_position) { - size_t batch_beam_size = SafeInt(batch_size) * num_beams; - - size_t next_token_size = SafeInt(batch_beam_size) * vocab_size; +struct BeamSearchState : IBeamSearchState { + BeamSearchState(const IGenerationParameters& parameters, + AllocatorPtr allocator, + int has_decoder_masked_attention, + bool use_position) { + size_t batch_beam_size = SafeInt(parameters.batch_size) * parameters.num_beams; + + size_t next_token_size = SafeInt(batch_beam_size) * parameters.vocab_size; this->next_token_logits = AllocateBuffer(allocator, next_token_logits_buffer_, next_token_size); this->next_token_scores = AllocateBuffer(allocator, next_token_scores_buffer_, next_token_size); - this->next_tokens = AllocateBuffer(allocator, next_tokens_buffer_, SafeInt(2) * batch_beam_size); - this->next_indices = AllocateBuffer(allocator, next_indices_buffer_, SafeInt(2) * batch_beam_size); - this->next_scores = AllocateBuffer(allocator, next_scores_buffer_, SafeInt(2) * batch_beam_size); constexpr size_t max_parts_of_vocab = 128; - size_t topk_buffer_size = SafeInt(batch_beam_size) * (max_parts_of_vocab + 1) * num_beams * 2 * 2; + size_t topk_buffer_size = SafeInt(batch_beam_size) * (max_parts_of_vocab + 1) * parameters.num_beams * 2 * 2; this->topk_buffer = AllocateBuffer(allocator, topk_temp_buffer_, topk_buffer_size); + if (allocator->Info().device.Type() == OrtDevice::GPU) { + size_t sequences_elements = SafeInt(2) * batch_beam_size * parameters.max_length; + this->sequences_device = AllocateBuffer(allocator, sequences_device_buffer_, sequences_elements); + } + if (use_position) { this->next_positions = AllocateBuffer(allocator, next_positions_buffer_, batch_beam_size); } this->beam_scores = AllocateBuffer(allocator, beam_scores_buffer_, batch_beam_size); - if (output_scores) { - size_t elements = SafeInt(max_length - sequence_length) * batch_size * num_beams * vocab_size; + if (parameters.output_scores) { + size_t elements = SafeInt(parameters.max_length - parameters.sequence_length) * parameters.batch_size * parameters.num_beams * parameters.vocab_size; this->scores = AllocateBuffer(allocator, scores_buffer_, elements); this->remaining_scores = this->scores; } @@ -56,16 +51,19 @@ struct BeamSearchState : public IBeamSearchState { if (has_decoder_masked_attention) { // We need a temp staging buffer to do the past 'K' state re-ordering that is needed // when using DecoderMaskedSelfAttention - TensorShape staging_for_past_state_reorder_buffer_shape = {static_cast(batch_beam_size), num_heads, max_length, head_size}; + TensorShape staging_for_past_state_reorder_buffer_shape = {static_cast(batch_beam_size), parameters.num_heads, parameters.max_length, parameters.head_size}; Tensor temp(DataTypeImpl::GetType(), staging_for_past_state_reorder_buffer_shape, allocator); this->staging_for_past_state_reorder = std::move(temp); + } + } - // We need a buffer on GPU to hold the final chosen indices after BeamScorer has finished processing - // TODO: This is a temporary work-around as BeamScorer currently only runs on CPU. - // We can remove these kinds of work-arounds once BeamScorer runs on CUDA eventually. - this->chosen_indices = AllocateBuffer(allocator, chosen_indices_buffer_, batch_beam_size); + void EnsurePastStateReorderStagingBuffer(AllocatorPtr allocator, int64_t sz) { + auto current_buffer_size = this->staging_for_past_state_reorder.Shape().Size(); + if (sz > current_buffer_size) { + TensorShape buffer_shape = {sz}; + this->staging_for_past_state_reorder = Tensor(DataTypeImpl::GetType(), buffer_shape, allocator); } } @@ -79,60 +77,53 @@ struct BeamSearchState : public IBeamSearchState { BufferUniquePtr beam_scores_buffer_; BufferUniquePtr scores_buffer_; BufferUniquePtr topk_temp_buffer_; - BufferUniquePtr chosen_indices_buffer_; + BufferUniquePtr sequences_device_buffer_; }; -struct BeamSearchCpuState : public IBeamSearchCpuState { +struct BeamSearchCpuState : IBeamSearchCpuState { Sequences sequences; - void Init(AllocatorPtr allocator, size_t batch_beam_size, int max_length, int sequence_length, bool is_cuda) { - this->sequence_lengths = AllocateBuffer(allocator, sequence_lengths_buffer_, batch_beam_size); + BeamSearchCpuState(const IGenerationParameters& parameters, AllocatorPtr allocator, bool is_cuda) + : parameters_{parameters} { + sequence_lengths = AllocateBuffer(allocator, sequence_lengths_buffer_, batch_beam_size_); - size_t sequences_bytes = SafeInt(2) * batch_beam_size * max_length; - this->sequences_space = AllocateBuffer(allocator, sequences_space_buffer_, sequences_bytes); - memset(this->sequences_space.data(), 0, this->sequences_space.size_bytes()); + size_t sequences_bytes = SafeInt(2) * batch_beam_size_ * parameters.max_length; + sequences_space = AllocateBuffer(allocator, sequences_space_buffer_, sequences_bytes, true /* fill */); + sequences.Init(sequences_space, batch_beam_size_, parameters.sequence_length, parameters.max_length); if (is_cuda) { // buffers used by CUDA operator but not by CPU operator. - this->topk_scores = AllocateBuffer(allocator, topk_scores_buffer_, 2 * batch_beam_size); - this->topk_tokens = AllocateBuffer(allocator, topk_tokens_buffer_, 2 * batch_beam_size); - this->topk_indices = AllocateBuffer(allocator, topk_indices_buffer_, 2 * batch_beam_size); - this->final_beam_scores = AllocateBuffer(allocator, final_beam_scores_buffer_, batch_beam_size); + topk_scores = AllocateBuffer(allocator, topk_scores_buffer_, 2 * static_cast(batch_beam_size_)); + topk_tokens = AllocateBuffer(allocator, topk_tokens_buffer_, 2 * static_cast(batch_beam_size_)); + topk_indices = AllocateBuffer(allocator, topk_indices_buffer_, 2 * static_cast(batch_beam_size_)); + final_beam_scores = AllocateBuffer(allocator, final_beam_scores_buffer_, batch_beam_size_); } - - this->sequences.Init(this->sequences_space, static_cast(batch_beam_size), sequence_length, max_length); } - // Copy expanded input_ids to sequences[0] - void SetSequence(gsl::span input_ids_in_cpu, - size_t batch_beam_size, - int max_length, - int sequence_length) { - gsl::span sequences_0 = sequences_space; - for (size_t i = 0; i < batch_beam_size; i++) { - for (int j = 0; j < sequence_length; j++) { - const size_t index = SafeInt(i) * max_length + j; - sequences_0[index] = input_ids_in_cpu[SafeInt(i) * sequence_length + j]; + // Copy expanded input_ids to sequences_space + void SetExpandedSequence(gsl::span input_ids_in_cpu) { + for (int i = 0; i < batch_beam_size_; i++) { + for (int j = 0; j < parameters_.sequence_length; j++) { + const size_t index = SafeInt(i) * parameters_.max_length + j; + sequences_space[index] = input_ids_in_cpu[SafeInt(i) * parameters_.sequence_length + j]; } } } - // Copy unexpanded input_ids to sequences[0] - void SetSequence(gsl::span input_ids_in_cpu, - size_t batch_beam_size, - int beam_size, - int max_length, - int sequence_length) { - gsl::span sequences_0 = sequences_space; - for (size_t i = 0; i < batch_beam_size; i++) { - for (int j = 0; j < sequence_length; j++) { - const size_t index = SafeInt(i) * max_length + j; - sequences_0[index] = input_ids_in_cpu[SafeInt(i / beam_size) * sequence_length + j]; + // Copy unexpanded input_ids to sequences_space (only difference from SetExpandedSequence is i is divided by parameters_.num_beams + void SetUnexpandedSequence(gsl::span input_ids_in_cpu) { + for (int i = 0; i < batch_beam_size_; i++) { + for (int j = 0; j < parameters_.sequence_length; j++) { + const size_t index = SafeInt(i) * parameters_.max_length + j; + sequences_space[index] = input_ids_in_cpu[SafeInt(i / parameters_.num_beams) * parameters_.sequence_length + j]; } } } private: + const IGenerationParameters& parameters_; + const int batch_beam_size_{parameters_.batch_size * parameters_.num_beams}; + BufferUniquePtr final_beam_scores_buffer_; BufferUniquePtr sequence_lengths_buffer_; BufferUniquePtr topk_scores_buffer_; @@ -141,7 +132,7 @@ struct BeamSearchCpuState : public IBeamSearchCpuState { BufferUniquePtr sequences_space_buffer_; }; -// Base class of beam search implementation that is common for both GPT-2 and T5. +// Base class of beam search implementation that is common for GPT-2, T5, and Whisper. template class BeamSearchBase : public GenerateBase { public: @@ -180,7 +171,6 @@ class BeamSearchBase : public GenerateBase { // Process logits and append next tokens to sequences. Status GenerateNextToken(const OrtValue& logits, gsl::span& beam_next_tokens, - gsl::span& beam_indices, BeamSearchState& beam_state, BeamSearchCpuState& cpu_state, int counter); @@ -194,7 +184,7 @@ class BeamSearchBase : public GenerateBase { BeamSearchParameters* parameters_; - std::unique_ptr beam_scorer_; + std::unique_ptr beam_scorer_; // Device specific functions GenerationDeviceHelper::ProcessLogitsFunc process_logits_func_; @@ -204,14 +194,16 @@ class BeamSearchBase : public GenerateBase { template Status BeamSearchBase::CheckInputs(const OpKernelContextInternal& context) { // Input shapes: - // input_ids : (batch_size, sequence_length) - // vocab_mask : (vocab_size) or nullptr + // input_ids : (batch_size, sequence_length) + // vocab_mask : (vocab_size) or nullptr + // decoder_input_ids : (batch_size, initial_decode_sequence_length) ORT_RETURN_IF_ERROR(this->CheckInputsImpl(parameters_, - context.Input(0), // input_ids - context.Input(7), // vocab_mask - context.Input(8), // prefix_vocab_mask - context.Input(9), // attention_mask - nullptr)); // presence_mask + context.Input(0), // input_ids + context.Input(7), // vocab_mask + context.Input(8), // prefix_vocab_mask + context.Input(9), // attention_mask + nullptr, // presence_mask + context.Input(10))); // decoder_input_ids return Status::OK(); } @@ -250,7 +242,7 @@ Status BeamSearchBase::ProcessLogits( BeamSearchCpuState& cpu_state, AllocatorPtr& allocator, int counter) { - return process_logits_func_(logits, &beam_state, &cpu_state, &(cpu_state.sequences), allocator, + return process_logits_func_(logits, &beam_state, &(cpu_state.sequences), allocator, thread_pool_, &logits_processors_, beam_scorer_.get(), parameters_, counter, ort_stream_, GetConsoleDumper()); } @@ -259,36 +251,69 @@ template Status BeamSearchBase::GenerateNextToken( const OrtValue& logits, gsl::span& beam_next_tokens, - gsl::span& beam_indices, BeamSearchState& beam_state, BeamSearchCpuState& cpu_state, int counter) { // Process logits to get next token scores ORT_RETURN_IF_ERROR(ProcessLogits(logits, beam_state, cpu_state, temp_space_allocator_, counter)); - gsl::span& beam_scores = beam_scorer_->GetNextScores(); - // It is optional to clone beam_scores. Change it to use same buffer also works for CPU: - // beam_state.beam_scores = beam_scores - // Here we make a copy to reduce the coupling with little cost (the buffer size is small). - ORT_RETURN_IF_ERROR(device_copy_func_(beam_state.beam_scores, - beam_scores, - ort_stream_, - DeviceCopyDirection::hostToDevice)); + if (this->IsCuda()) { + auto beam_scores = beam_scorer_->GetNextScores(); + // It is optional to clone beam_scores. Change it to use same buffer also works: + // beam_state.beam_scores = beam_scores + // Here we make a copy to reduce the coupling with little cost (the buffer size is small). + ORT_RETURN_IF_ERROR(device_copy_func_(beam_state.beam_scores, + beam_scores, + ort_stream_, + DeviceCopyDirection::deviceToDevice)); - beam_next_tokens = beam_scorer_->GetNextTokens(); - beam_indices = beam_scorer_->GetNextIndices(); + beam_next_tokens = beam_scorer_->GetNextTokens(); #ifdef DEBUG_GENERATION - cpu_dumper_.Print("beam_scores from scorer", beam_scores.data(), parameters_->batch_size, parameters_->num_beams); - cpu_dumper_.Print("beam_next_tokens", beam_next_tokens.data(), parameters_->batch_size, parameters_->num_beams); - cpu_dumper_.Print("beam_indices", beam_indices.data(), parameters_->batch_size, parameters_->num_beams); + auto beam_indices = beam_scorer_->GetNextIndicesGPU(); + cuda_dumper_->Print("beam_scores from scorer", beam_state.beam_scores.data(), parameters_->batch_size, parameters_->num_beams); + cuda_dumper_->Print("beam_next_tokens", beam_next_tokens.data(), parameters_->batch_size, parameters_->num_beams); + cuda_dumper_->Print("beam_indices", beam_indices.data(), parameters_->batch_size, parameters_->num_beams); #endif - cpu_state.sequences.AppendNextTokenToSequences(beam_indices, beam_next_tokens); + // the Cuda beam scorer does the AppendNextTokenSequences, all that's left for Cuda is a this small step + cpu_state.sequences.AfterDeviceAppendedNextToken(); #ifdef DEBUG_GENERATION - cpu_state.sequences.PrintSequences(&cpu_dumper_); + // CUDA equivalent of cpu_state.sequences.PrintSequences + auto sequences_buffer = cpu_state.sequences.GetCurrentDeviceSequences(); + for (int i = 0; i < parameters_->batch_size * parameters_->num_beams; i++) { + gsl::span sequence = sequences_buffer.subspan(i * parameters_->max_length, cpu_state.sequences.GetSequenceLength()); + cuda_dumper_->Print("sequences", i, false); + cuda_dumper_->Print(nullptr, sequence.data(), 1, static_cast(sequence.size())); + } #endif + } else { + auto beam_scores = beam_scorer_->GetNextScores(); + // It is optional to clone beam_scores. Change it to use same buffer also works for CPU: + // beam_state.beam_scores = beam_scores + // Here we make a copy to reduce the coupling with little cost (the buffer size is small). + ORT_RETURN_IF_ERROR(device_copy_func_(beam_state.beam_scores, + beam_scores, + ort_stream_, + DeviceCopyDirection::hostToDevice)); + + beam_next_tokens = beam_scorer_->GetNextTokens(); + auto beam_indices = beam_scorer_->GetNextIndicesCPU(); + +#ifdef DEBUG_GENERATION + cpu_dumper_.Print("beam_scores from scorer", beam_scores.data(), parameters_->batch_size, parameters_->num_beams); + cpu_dumper_.Print("beam_next_tokens", beam_next_tokens.data(), parameters_->batch_size, parameters_->num_beams); + cpu_dumper_.Print("beam_indices", beam_indices.data(), parameters_->batch_size, parameters_->num_beams); +#endif + + cpu_state.sequences.AppendNextTokenToSequences(beam_indices, beam_next_tokens); + +#ifdef DEBUG_GENERATION + cpu_state.sequences.PrintSequences(&cpu_dumper_); +#endif + } + return Status::OK(); } diff --git a/onnxruntime/contrib_ops/cpu/transformers/beam_search_impl_gpt.h b/onnxruntime/contrib_ops/cpu/transformers/beam_search_impl_gpt.h index 3ea4a4c242431..205d94fae9fab 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/beam_search_impl_gpt.h +++ b/onnxruntime/contrib_ops/cpu/transformers/beam_search_impl_gpt.h @@ -27,15 +27,13 @@ class BeamSearchGpt : public BeamSearchBase { BeamSearchParameters& params, const GenerationDeviceHelper::CreateGptInputsFunc& create_inputs_func, const GenerationDeviceHelper::AddToFeedsFunc& add_to_feeds_func, - const GenerationDeviceHelper::ReorderPastStateFunc& reorder_past_state_func, const GenerationDeviceHelper::TopkFunc& topk_func, const GenerationDeviceHelper::ProcessLogitsFunc& process_logits_func, const GenerationDeviceHelper::InitBeamStateFunc& init_beam_state_func, const GenerationDeviceHelper::DeviceCopyFunc& device_copy_func, const GenerationDeviceHelper::DeviceCopyFunc& device_copy_int32_func, const GenerationDeviceHelper::UpdateGptFeedsFunc& update_feeds_func, - const void* cuda_device_prop, - int cuda_device_arch) + const GenerationDeviceHelper::CreateBeamScorer& create_beam_scorer_func) : BeamSearchBase(context, decoder_session_state, thread_pool, ort_stream, cuda_dumper, params, topk_func, process_logits_func, device_copy_func, device_copy_int32_func), @@ -45,18 +43,27 @@ class BeamSearchGpt : public BeamSearchBase { create_inputs_func_(create_inputs_func), add_to_feeds_func_(add_to_feeds_func), init_beam_state_func_(init_beam_state_func), - reorder_past_state_func_(reorder_past_state_func), update_feeds_func_(update_feeds_func), - cuda_device_prop_(cuda_device_prop), - cuda_device_arch_(cuda_device_arch) { + create_beam_scorer_func_(create_beam_scorer_func) {} + +#ifdef USE_CUDA + Status InitializeCuda( + const GenerationDeviceHelper::ReorderPastStateFunc& reorder_past_state_func, + const void* cuda_device_prop, + int cuda_device_arch) { + reorder_past_state_func_ = reorder_past_state_func; + cuda_device_prop_ = cuda_device_prop; + cuda_device_arch_ = cuda_device_arch; if (gpt_subgraph_.has_decoder_masked_attention_) { - ORT_ENFORCE(cuda_device_arch_ >= 530, - "Decoder masked self attention can only be used on " - "GPU cards of compute capability 5.3 or higher. " - "This card has compute capability ", - cuda_device_arch_); + ORT_RETURN_IF_NOT(cuda_device_arch_ >= 530, + "Decoder masked self attention can only be used on " + "GPU cards of compute capability 5.3 or higher. " + "This card has compute capability ", + cuda_device_arch_); } + return Status::OK(); } +#endif // Execute beam search in iterations util stopping criteria is reached. // In each iteration, GPT subgraph is called, and next token for each sequence is generated. @@ -93,8 +100,11 @@ class BeamSearchGpt : public BeamSearchBase { GenerationDeviceHelper::CreateGptInputsFunc create_inputs_func_; GenerationDeviceHelper::AddToFeedsFunc add_to_feeds_func_; GenerationDeviceHelper::InitBeamStateFunc init_beam_state_func_; +#ifdef USE_CUDA GenerationDeviceHelper::ReorderPastStateFunc reorder_past_state_func_; +#endif GenerationDeviceHelper::UpdateGptFeedsFunc update_feeds_func_; + GenerationDeviceHelper::CreateBeamScorer create_beam_scorer_func_; const void* cuda_device_prop_ = nullptr; int cuda_device_arch_ = 0; @@ -180,18 +190,15 @@ Status BeamSearchGpt::Execute(const FeedsFetchesManager* init_run_feeds_fetch const FeedsFetchesManager& feeds_fetches_manager) { auto status = Status::OK(); const BeamSearchParameters* parameters = this->parameters_; - int64_t sequences_dims[] = {parameters->batch_size, parameters->num_return_sequences, parameters->max_length}; - TensorShape sequences_shape(&sequences_dims[0], sizeof(sequences_dims) / sizeof(sequences_dims[0])); + TensorShape sequences_shape{parameters->batch_size, parameters->num_return_sequences, parameters->max_length}; Tensor* output_sequences = this->context_.Output(0, sequences_shape); - int64_t sequences_scores_dims[] = {parameters->batch_size, parameters->num_return_sequences}; - TensorShape sequences_scores_shape(&sequences_scores_dims[0], 2); + TensorShape sequences_scores_shape{parameters->batch_size, parameters->num_return_sequences}; Tensor* output_sequences_scores = this->context_.Output(1, sequences_scores_shape); - int64_t scores_dims[] = { + TensorShape scores_shape{ static_cast(parameters->max_length) - static_cast(parameters->sequence_length), parameters->batch_size, parameters->num_beams, parameters->vocab_size}; - TensorShape scores_shape(&scores_dims[0], sizeof(scores_dims) / sizeof(scores_dims[0])); Tensor* output_scores = this->context_.Output(2, scores_shape); // Update the flag to indicate whether scores exists in output @@ -202,26 +209,13 @@ Status BeamSearchGpt::Execute(const FeedsFetchesManager* init_run_feeds_fetch std::vector fetches; // Initialize resources - onnxruntime::OrtStlAllocator hypothesis_score_allocator(this->cpu_allocator_); - onnxruntime::OrtStlAllocator beam_hyps_allocator(this->cpu_allocator_); - this->beam_scorer_ = std::make_unique(static_cast(parameters->batch_size), - static_cast(parameters->num_beams), - static_cast(parameters->max_length), - parameters->length_penalty, - parameters->early_stopping, - static_cast(parameters->num_return_sequences), - parameters->pad_token_id, - parameters->eos_token_id, - hypothesis_score_allocator, - beam_hyps_allocator); - this->beam_scorer_->Initialize(this->cpu_allocator_, parameters->sequence_length); - - BeamSearchCpuState cpu_state; - cpu_state.Init(this->cpu_allocator_, - static_cast(parameters->BatchBeamSize()), - parameters->max_length, - parameters->sequence_length, - this->IsCuda()); + this->beam_scorer_ = create_beam_scorer_func_ + ? create_beam_scorer_func_(*parameters, this->temp_space_allocator_, this->cpu_allocator_, this->ort_stream_) + : std::make_unique(*parameters, this->cpu_allocator_); + + BeamSearchCpuState cpu_state{*parameters, + this->cpu_allocator_, + this->IsCuda()}; // buffer in GPU for input_ids, position_ids and attention_mask IAllocatorUniquePtr buffer; @@ -230,7 +224,7 @@ Status BeamSearchGpt::Execute(const FeedsFetchesManager* init_run_feeds_fetch gpt_subgraph_.has_decoder_masked_attention_)); if (gpt_subgraph_.past_present_share_buffer_) { // Reuse past and present - fetches.reserve(static_cast(gpt_subgraph_.GetFirstPresentOutputIndex()) + gpt_subgraph_.num_layers); + fetches.reserve(static_cast(gpt_subgraph_.GetFirstPresentOutputIndex()) + gpt_subgraph_.num_layers); fetches.resize(gpt_subgraph_.GetFirstPresentOutputIndex(), OrtValue()); for (int layer = 0; layer < gpt_subgraph_.num_layers; layer++) { int feed_idx = gpt_subgraph_.GetFirstPastInputIndex() + layer; @@ -243,19 +237,10 @@ Status BeamSearchGpt::Execute(const FeedsFetchesManager* init_run_feeds_fetch } } - BeamSearchState beam_state; - constexpr bool use_position = true; - beam_state.Init(this->temp_space_allocator_, - parameters->batch_size, - parameters->num_beams, - parameters->vocab_size, - parameters->sequence_length, - parameters->max_length, - parameters->num_heads, - parameters->head_size, - gpt_subgraph_.has_decoder_masked_attention_, - parameters->output_scores, - use_position); + BeamSearchState beam_state{*parameters, + this->temp_space_allocator_, + gpt_subgraph_.has_decoder_masked_attention_, + true /* use_position */}; init_beam_state_func_(&beam_state, cpu_state.sequence_lengths, @@ -263,19 +248,24 @@ Status BeamSearchGpt::Execute(const FeedsFetchesManager* init_run_feeds_fetch parameters->num_beams, this->ort_stream_); - gsl::span input_ids = expanded_input_ids_in_cpu.Get().DataAsSpan(); - cpu_state.SetSequence(input_ids, - static_cast(parameters->BatchBeamSize()), - parameters->max_length, - parameters->sequence_length); + cpu_state.SetExpandedSequence(expanded_input_ids_in_cpu.Get().DataAsSpan()); + + // beam_state.sequences_device is the GPU version of cpu_state.sequences_space, + // this copies it over to the GPU after setting it up on the CPU + if (this->IsCuda()) { + cpu_state.sequences.InitDevice(beam_state.sequences_device); + ORT_RETURN_IF_ERROR(this->device_copy_int32_func_(beam_state.sequences_device.subspan(0, beam_state.sequences_device.size() / 2), + cpu_state.sequences_space.subspan(0, cpu_state.sequences_space.size() / 2), + nullptr, + DeviceCopyDirection::hostToDevice)); + } #ifdef DEBUG_GENERATION const IConsoleDumper* dumper = this->GetConsoleDumper(); #endif // Position ids for all iterations except the first. It uses memory buffer owned by next_positions. OrtValue position_ids; - int64_t dims[] = {parameters->BatchBeamSize(), 1}; - TensorShape shape(&dims[0], 2); + TensorShape shape{parameters->BatchBeamSize(), 1}; Tensor::InitOrtValue(DataTypeImpl::GetType(), shape, beam_state.next_positions.data(), @@ -333,22 +323,20 @@ Status BeamSearchGpt::Execute(const FeedsFetchesManager* init_run_feeds_fetch const OrtValue& logits = fetches[0]; gsl::span beam_next_tokens; - gsl::span beam_indices; ORT_RETURN_IF_ERROR(this->GenerateNextToken(logits, beam_next_tokens, - beam_indices, beam_state, cpu_state, iteration_counter)); // When all batches are finished, stop earlier to avoid wasting computation. - if (this->beam_scorer_->IsDone()) { + if (this->beam_scorer_->IsDone()) break; - } // Increase sequence length after a new token is generated. ++current_length; +#ifdef USE_CUDA // Reorder past state after first run if the GPT subgraph (the one used after the first iteration) // contains DecoderMaskedSelfAttention nodes if (iteration_counter == 1 && gpt_subgraph_.has_decoder_masked_attention_) { @@ -365,6 +353,7 @@ Status BeamSearchGpt::Execute(const FeedsFetchesManager* init_run_feeds_fetch this->ort_stream_)); } } +#endif // Prepare inputs for next round of subgraph call. if (current_length < parameters->max_length) { @@ -375,15 +364,20 @@ Status BeamSearchGpt::Execute(const FeedsFetchesManager* init_run_feeds_fetch ORT_RETURN_IF_ERROR(UpdateFeeds(fetches, feeds, current_length, position_ids, increase_position, ReinterpretAsSpan(beam_next_tokens), - ReinterpretAsSpan(beam_indices), gpt_subgraph_.has_decoder_masked_attention_ - ? ReinterpretAsSpan(beam_state.chosen_indices) + ? place_holder + : ReinterpretAsSpan(this->beam_scorer_->GetNextIndicesCPU()), + gpt_subgraph_.has_decoder_masked_attention_ + ? ReinterpretAsSpan(this->beam_scorer_->GetNextIndicesGPU()) : place_holder, current_length - 1, parameters->sequence_length, gpt_subgraph_.has_decoder_masked_attention_)); } + if (this->beam_scorer_->IsDoneLater()) + break; + if (gpt_subgraph_.past_present_share_buffer_) { // clear fetched values before presents[] for (int idx = 0; idx < gpt_subgraph_.GetFirstPresentOutputIndex(); idx++) { @@ -394,25 +388,16 @@ Status BeamSearchGpt::Execute(const FeedsFetchesManager* init_run_feeds_fetch } } - gsl::span final_beam_scores(beam_state.beam_scores.data(), beam_state.beam_scores.size()); - if (this->IsCuda()) { - ORT_RETURN_IF_ERROR(this->device_copy_func_(cpu_state.final_beam_scores, - final_beam_scores, - nullptr, - DeviceCopyDirection::deviceToHost)); - final_beam_scores = gsl::make_span(cpu_state.final_beam_scores.data(), - cpu_state.final_beam_scores.size()); - } - - this->beam_scorer_->Finalize(&(cpu_state.sequences), + gsl::span final_beam_scores = beam_state.beam_scores; + this->beam_scorer_->Finalize(cpu_state.sequences, final_beam_scores, output_sequences, output_sequences_scores); // Output per token scores - if (output_scores != nullptr) { + if (output_scores) { gsl::span target = output_scores->MutableDataAsSpan(); - gsl::span source = gsl::span(beam_state.scores.data(), beam_state.scores.size()); + gsl::span source = beam_state.scores; assert(target.size() == source.size()); ORT_RETURN_IF_ERROR(this->device_copy_func_(target, source, nullptr, DeviceCopyDirection::deviceToDevice)); } 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 51e8ae7b13765..14a0db57c45de 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/beam_search_impl_t5.h +++ b/onnxruntime/contrib_ops/cpu/transformers/beam_search_impl_t5.h @@ -11,7 +11,6 @@ namespace onnxruntime { namespace contrib { - namespace transformers { // Beam search implementation for T5 model. @@ -28,8 +27,6 @@ class BeamSearchT5 : public BeamSearchBase { IConsoleDumper* cuda_dumper, BeamSearchParameters& params, const GenerationDeviceHelper::AddToFeedsFunc& add_to_feeds_func, - const GenerationDeviceHelper::ReorderPastStateFunc& reorder_past_state_func, - const GenerationDeviceHelper::InitCacheIndirFunc& init_cache_indir_func, const GenerationDeviceHelper::TopkFunc& topk_func, const GenerationDeviceHelper::ProcessLogitsFunc& process_logits_func, const GenerationDeviceHelper::InitBeamStateFunc& init_beam_state_func, @@ -40,8 +37,7 @@ class BeamSearchT5 : public BeamSearchBase { const GenerationDeviceHelper::ExpandBufferFunc& expand_buffer_int32_func, const GenerationDeviceHelper::ExpandBufferFunc& expand_buffer_float_func, const GenerationDeviceHelper::ExpandBufferFunc& expand_buffer_float16_func, - const void* cuda_device_prop, - int cuda_device_arch) + const GenerationDeviceHelper::CreateBeamScorer& create_beam_scorer_func) : BeamSearchBase(context, decoder_session_state, thread_pool, ort_stream, cuda_dumper, params, topk_func, process_logits_func, device_copy_func, device_copy_int32_func), @@ -50,23 +46,33 @@ class BeamSearchT5 : public BeamSearchBase { decoder_subgraph_(decoder_subgraph), add_to_feeds_func_(add_to_feeds_func), init_beam_state_func_(init_beam_state_func), - reorder_past_state_func_(reorder_past_state_func), - init_cache_indir_func_(init_cache_indir_func), create_encoder_inputs_func_(create_encoder_inputs_func), update_decoder_feeds_func_(update_decoder_feeds_func), expand_buffer_int32_func_(expand_buffer_int32_func), expand_buffer_float_func_(expand_buffer_float_func), expand_buffer_float16_func_(expand_buffer_float16_func), - cuda_device_prop_(cuda_device_prop), - cuda_device_arch_(cuda_device_arch) { + create_beam_scorer_func_(create_beam_scorer_func) {} + +#ifdef USE_CUDA + Status InitializeCuda( + const GenerationDeviceHelper::ReorderPastStateFunc& reorder_past_state_func, + const GenerationDeviceHelper::InitCacheIndirFunc& init_cache_indir_func, + const void* cuda_device_prop, + int cuda_device_arch) { + reorder_past_state_func_ = reorder_past_state_func; + init_cache_indir_func_ = init_cache_indir_func; + cuda_device_prop_ = cuda_device_prop; + cuda_device_arch_ = cuda_device_arch; if (decoder_subgraph_.has_decoder_masked_attention_) { - ORT_ENFORCE(cuda_device_arch_ >= 530, - "Decoder masked multihead attention can only be used on " - "GPU cards of compute capability 5.3 or higher. " - "This card has compute capability ", - cuda_device_arch_); + ORT_RETURN_IF_NOT(cuda_device_arch_ >= 530, + "Decoder masked multihead attention can only be used on " + "GPU cards of compute capability 5.3 or higher. " + "This card has compute capability ", + cuda_device_arch_); } + return Status::OK(); } +#endif // Execute beam search in iterations util stopping criteria is reached. Status Execute(const FeedsFetchesManager& encoder_feeds_fetches_manager, @@ -81,13 +87,16 @@ class BeamSearchT5 : public BeamSearchBase { // Device specific functions GenerationDeviceHelper::AddToFeedsFunc add_to_feeds_func_; GenerationDeviceHelper::InitBeamStateFunc init_beam_state_func_; +#ifdef USE_CUDA GenerationDeviceHelper::ReorderPastStateFunc reorder_past_state_func_; GenerationDeviceHelper::InitCacheIndirFunc init_cache_indir_func_; +#endif GenerationDeviceHelper::CreateEncoderInputsFunc create_encoder_inputs_func_; GenerationDeviceHelper::UpdateDecoderFeedsFunc update_decoder_feeds_func_; GenerationDeviceHelper::ExpandBufferFunc expand_buffer_int32_func_; GenerationDeviceHelper::ExpandBufferFunc expand_buffer_float_func_; GenerationDeviceHelper::ExpandBufferFunc expand_buffer_float16_func_; + GenerationDeviceHelper::CreateBeamScorer create_beam_scorer_func_; const void* cuda_device_prop_ = nullptr; int cuda_device_arch_ = 0; @@ -99,7 +108,9 @@ Status BeamSearchT5::Execute(const FeedsFetchesManager& encoder_feeds_fetches auto status = Status::OK(); const BeamSearchParameters* parameters = this->parameters_; - ORT_ENFORCE(parameters->sequence_length == 1); + if (parameters->model_type == IGenerationParameters::kModelTypeT5) { + ORT_ENFORCE(parameters->sequence_length == 1); + } // Allocate output tensors. int64_t sequences_dims[] = {parameters->batch_size, parameters->num_return_sequences, parameters->max_length}; @@ -131,14 +142,12 @@ Status BeamSearchT5::Execute(const FeedsFetchesManager& encoder_feeds_fetches const OrtValue* encoder_attn_mask_value = this->context_.GetInputOrtValue(9); - BeamSearchCpuState cpu_state; - cpu_state.Init(this->cpu_allocator_, - static_cast(parameters->BatchBeamSize()), - parameters->max_length, - parameters->sequence_length, - this->IsCuda()); + BeamSearchCpuState cpu_state{*parameters, + this->cpu_allocator_, + this->IsCuda()}; IAllocatorUniquePtr buffer; + OrtValue decoder_input_ids; // Tensor in CPU, and it will be used to initialize sequence in cpu_state ORT_RETURN_IF_ERROR(this->encoder_subgraph_.CreateInitialFeeds( encoder_input_ids, @@ -183,40 +192,10 @@ Status BeamSearchT5::Execute(const FeedsFetchesManager& encoder_feeds_fetches // Initialize resources // ------------------------------------ - // Copy decoder_input_ids (in CPU) to sequence. It contains decoder_start_token_id for each beam. - cpu_state.SetSequence(decoder_input_ids.Get().DataAsSpan(), - static_cast(parameters->BatchBeamSize()), - parameters->num_beams, - parameters->max_length, - parameters->sequence_length); - - onnxruntime::OrtStlAllocator hypothesis_score_allocator(this->cpu_allocator_); - onnxruntime::OrtStlAllocator beam_hyps_allocator(this->cpu_allocator_); - this->beam_scorer_ = std::make_unique(static_cast(parameters->batch_size), - static_cast(parameters->num_beams), - static_cast(parameters->max_length), - parameters->length_penalty, - parameters->early_stopping, - static_cast(parameters->num_return_sequences), - parameters->pad_token_id, - parameters->eos_token_id, - hypothesis_score_allocator, - beam_hyps_allocator); - this->beam_scorer_->Initialize(this->cpu_allocator_, parameters->sequence_length); - - BeamSearchState beam_state; - constexpr bool use_position = false; - beam_state.Init(this->temp_space_allocator_, - parameters->batch_size, - parameters->num_beams, - parameters->vocab_size, - parameters->sequence_length, - parameters->max_length, - parameters->num_heads, - parameters->head_size, - decoder_subgraph_.has_decoder_masked_attention_, - parameters->output_scores, - use_position); + BeamSearchState beam_state{*parameters, + this->temp_space_allocator_, + decoder_subgraph_.has_decoder_masked_attention_, + false /* use_position */}; init_beam_state_func_(&beam_state, cpu_state.sequence_lengths, @@ -224,11 +203,27 @@ Status BeamSearchT5::Execute(const FeedsFetchesManager& encoder_feeds_fetches parameters->num_beams, this->ort_stream_); + // Copy decoder_input_ids (in CPU) to sequence. It contains decoder_start_token_id for each beam. + cpu_state.SetUnexpandedSequence(decoder_input_ids.Get().DataAsSpan()); + + // beam_state.sequences_device is the GPU version of cpu_state.sequences_space, + // this copies it over to the GPU after setting it up on the CPU + if (this->IsCuda()) { + cpu_state.sequences.InitDevice(beam_state.sequences_device); + ORT_RETURN_IF_ERROR(this->device_copy_int32_func_(beam_state.sequences_device.subspan(0, beam_state.sequences_device.size() / 2), + cpu_state.sequences_space.subspan(0, cpu_state.sequences_space.size() / 2), + nullptr, + DeviceCopyDirection::hostToDevice)); + } + + this->beam_scorer_ = create_beam_scorer_func_ + ? create_beam_scorer_func_(*parameters, this->temp_space_allocator_, this->cpu_allocator_, this->ort_stream_) + : std::make_unique(*parameters, this->cpu_allocator_); + // ------------------------------------------------------------------------------ // Generate next token from logits output from encoder, and initialize decoder inputs. // ------------------------------------------------------------------------------ gsl::span beam_next_tokens; - gsl::span beam_indices; int iteration_counter = 0; std::vector decoder_feeds; @@ -240,7 +235,6 @@ Status BeamSearchT5::Execute(const FeedsFetchesManager& encoder_feeds_fetches ++iteration_counter; ORT_RETURN_IF_ERROR(this->GenerateNextToken(encoder_fetches[0], beam_next_tokens, - beam_indices, beam_state, cpu_state, iteration_counter)); @@ -265,7 +259,8 @@ Status BeamSearchT5::Execute(const FeedsFetchesManager& encoder_feeds_fetches decoder_subgraph_.has_decoder_masked_attention_)); if (decoder_subgraph_.past_present_share_buffer_) { - decoder_fetches.reserve(static_cast(decoder_subgraph_.GetFirstPresentOutputIndex()) + 2 * static_cast(decoder_subgraph_.num_layers)); + decoder_fetches.reserve(static_cast(decoder_subgraph_.GetFirstPresentOutputIndex()) + + 2 * static_cast(decoder_subgraph_.num_layers)); decoder_fetches.resize(decoder_subgraph_.GetFirstPresentOutputIndex(), OrtValue()); for (int layer = 0; layer < 2 * decoder_subgraph_.num_layers; layer++) { int feed_idx = decoder_subgraph_.GetFirstPastInputIndex() + layer; @@ -280,6 +275,12 @@ Status BeamSearchT5::Execute(const FeedsFetchesManager& encoder_feeds_fetches if (decoder_subgraph_.has_decoder_masked_attention_) { size_t offset = static_cast(decoder_subgraph_.GetFirstPastInputIndex()); + // Need to check cross attention's past key tensor size, suppose all layers cross attention key size are same + auto first_cross_attention_key = decoder_feeds[offset + 2 * static_cast(decoder_subgraph_.num_layers)].GetMutable(); + auto cross_attention_past_key_sz = first_cross_attention_key->Shape().Size(); + beam_state.EnsurePastStateReorderStagingBuffer(this->temp_space_allocator_, cross_attention_past_key_sz); + +#ifdef USE_CUDA // Here we only need to reorder the past key for self-attention and cross-attention. for (size_t i = 0; i < 2 * static_cast(decoder_subgraph_.num_layers); ++i) { ORT_RETURN_IF_ERROR(reorder_past_state_func_(cuda_device_prop_, @@ -289,6 +290,7 @@ Status BeamSearchT5::Execute(const FeedsFetchesManager& encoder_feeds_fetches } size_t cache_indir_input_offset = static_cast(decoder_subgraph_.GetFirstPastInputIndex()) + 4 * static_cast(decoder_subgraph_.num_layers) + 2; ORT_RETURN_IF_ERROR(init_cache_indir_func_(*decoder_feeds[cache_indir_input_offset].GetMutable(), this->ort_stream_)); +#endif } } @@ -336,7 +338,6 @@ Status BeamSearchT5::Execute(const FeedsFetchesManager& encoder_feeds_fetches const OrtValue& logits = decoder_fetches[0]; ORT_RETURN_IF_ERROR(this->GenerateNextToken(logits, beam_next_tokens, - beam_indices, beam_state, cpu_state, iteration_counter)); @@ -346,6 +347,12 @@ Status BeamSearchT5::Execute(const FeedsFetchesManager& encoder_feeds_fetches break; } + // TODO: If this is safe to do after update_decoder_feeds_func, move it later so that we can speculatively run the next steps while we wait + // for the done result to transfer to the CPU + if (this->beam_scorer_->IsDoneLater()) { + break; + } + // Increase sequence length after a new token is generated. ++current_length; @@ -360,9 +367,11 @@ Status BeamSearchT5::Execute(const FeedsFetchesManager& encoder_feeds_fetches decoder_feeds, num_present_outputs, ReinterpretAsSpan(beam_next_tokens), - ReinterpretAsSpan(beam_indices), decoder_subgraph_.has_decoder_masked_attention_ - ? ReinterpretAsSpan(beam_state.chosen_indices) + ? place_holder + : ReinterpretAsSpan(this->beam_scorer_->GetNextIndicesCPU()), + decoder_subgraph_.has_decoder_masked_attention_ + ? ReinterpretAsSpan(this->beam_scorer_->GetNextIndicesGPU()) : place_holder, parameters->num_beams, decoder_subgraph_.GetFirstPastInputIndex(), @@ -386,25 +395,16 @@ Status BeamSearchT5::Execute(const FeedsFetchesManager& encoder_feeds_fetches } } - gsl::span final_beam_scores(beam_state.beam_scores.data(), beam_state.beam_scores.size()); - if (this->IsCuda()) { - ORT_RETURN_IF_ERROR(this->device_copy_func_(cpu_state.final_beam_scores, - final_beam_scores, - nullptr, - DeviceCopyDirection::deviceToHost)); - final_beam_scores = gsl::make_span(cpu_state.final_beam_scores.data(), - cpu_state.final_beam_scores.size()); - } - - this->beam_scorer_->Finalize(&(cpu_state.sequences), + gsl::span final_beam_scores = beam_state.beam_scores; + this->beam_scorer_->Finalize(cpu_state.sequences, final_beam_scores, output_sequences, output_sequences_scores); // Output per token scores - if (output_scores != nullptr) { + if (output_scores) { gsl::span target = output_scores->MutableDataAsSpan(); - gsl::span source = gsl::span(beam_state.scores.data(), beam_state.scores.size()); + gsl::span source = beam_state.scores; assert(target.size() == source.size()); ORT_RETURN_IF_ERROR(this->device_copy_func_(target, source, nullptr, DeviceCopyDirection::deviceToDevice)); } diff --git a/onnxruntime/contrib_ops/cpu/transformers/beam_search_impl_whisper.h b/onnxruntime/contrib_ops/cpu/transformers/beam_search_impl_whisper.h new file mode 100644 index 0000000000000..198dec011c56f --- /dev/null +++ b/onnxruntime/contrib_ops/cpu/transformers/beam_search_impl_whisper.h @@ -0,0 +1,405 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/common/span_utils.h" +#include "contrib_ops/cpu/transformers/generation_shared.h" // for DEBUG_GENERATION +#include "contrib_ops/cpu/transformers/beam_search_impl_base.h" +#include "contrib_ops/cpu/transformers/subgraph_whisper_encoder.h" +#include "contrib_ops/cpu/transformers/subgraph_whisper_decoder.h" + +namespace onnxruntime { +namespace contrib { +namespace transformers { + +// Beam search implementation for Whisper model. +template +class BeamSearchWhisper : public BeamSearchBase { + public: + BeamSearchWhisper(OpKernelContextInternal& context, + const SessionState& encoder_session_state, + const SessionState& decoder_session_state, + WhisperEncoderSubgraph& encoder_subgraph, + WhisperDecoderSubgraph& decoder_subgraph, + concurrency::ThreadPool* thread_pool, + Stream* ort_stream, + IConsoleDumper* cuda_dumper, + BeamSearchParameters& params, + const GenerationDeviceHelper::AddToFeedsFunc& add_to_feeds_func, + const GenerationDeviceHelper::TopkFunc& topk_func, + const GenerationDeviceHelper::ProcessLogitsFunc& process_logits_func, + const GenerationDeviceHelper::InitBeamStateFunc& init_beam_state_func, + const GenerationDeviceHelper::DeviceCopyFunc& device_copy_func, + const GenerationDeviceHelper::DeviceCopyFunc& device_copy_int32_func, + const GenerationDeviceHelper::CreateWhisperEncoderInputsFunc& create_encoder_inputs_func, + const GenerationDeviceHelper::UpdateDecoderFeedsFunc& update_decoder_feeds_func, + const GenerationDeviceHelper::ExpandBufferFunc& expand_buffer_float_func, + const GenerationDeviceHelper::ExpandBufferFunc& expand_buffer_float16_func, + const GenerationDeviceHelper::CreateBeamScorer& create_beam_scorer_func) + : BeamSearchBase(context, decoder_session_state, thread_pool, + ort_stream, cuda_dumper, params, + topk_func, process_logits_func, device_copy_func, device_copy_int32_func), + encoder_session_state_(encoder_session_state), + encoder_subgraph_(encoder_subgraph), + decoder_subgraph_(decoder_subgraph), + add_to_feeds_func_(add_to_feeds_func), + init_beam_state_func_(init_beam_state_func), + create_encoder_inputs_func_(create_encoder_inputs_func), + update_decoder_feeds_func_(update_decoder_feeds_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) {} + +#ifdef USE_CUDA + Status InitializeCuda( + const GenerationDeviceHelper::ReorderPastStateFunc& reorder_past_state_func, + const GenerationDeviceHelper::InitCacheIndirFunc& init_cache_indir_func, + const void* cuda_device_prop, + int cuda_device_arch) { + reorder_past_state_func_ = reorder_past_state_func; + init_cache_indir_func_ = init_cache_indir_func; + cuda_device_prop_ = cuda_device_prop; + cuda_device_arch_ = cuda_device_arch; + if (decoder_subgraph_.has_decoder_masked_attention_) { + ORT_RETURN_IF_NOT(cuda_device_arch_ >= 530, + "Decoder masked multihead attention can only be used on " + "GPU cards of compute capability 5.3 or higher. " + "This card has compute capability ", + cuda_device_arch_); + } + return Status::OK(); + } +#endif + + // Execute beam search in iterations util stopping criteria is reached. + Status Execute(const FeedsFetchesManager& encoder_feeds_fetches_manager, + const FeedsFetchesManager& decoder_feeds_fetches_manager); + + private: + const SessionState& encoder_session_state_; + + WhisperEncoderSubgraph& encoder_subgraph_; + WhisperDecoderSubgraph& decoder_subgraph_; + + // Device specific functions + GenerationDeviceHelper::AddToFeedsFunc add_to_feeds_func_; + GenerationDeviceHelper::InitBeamStateFunc init_beam_state_func_; +#ifdef USE_CUDA + GenerationDeviceHelper::ReorderPastStateFunc reorder_past_state_func_; + GenerationDeviceHelper::InitCacheIndirFunc init_cache_indir_func_; +#endif + GenerationDeviceHelper::CreateWhisperEncoderInputsFunc create_encoder_inputs_func_; + GenerationDeviceHelper::UpdateDecoderFeedsFunc update_decoder_feeds_func_; + GenerationDeviceHelper::ExpandBufferFunc expand_buffer_float_func_; + GenerationDeviceHelper::ExpandBufferFunc expand_buffer_float16_func_; + GenerationDeviceHelper::CreateBeamScorer create_beam_scorer_func_; + + const void* cuda_device_prop_ = nullptr; + int cuda_device_arch_ = 0; +}; + +template +Status BeamSearchWhisper::Execute(const FeedsFetchesManager& encoder_feeds_fetches_manager, + const FeedsFetchesManager& decoder_feeds_fetches_manager) { + auto status = Status::OK(); + + const BeamSearchParameters* parameters = this->parameters_; + + // Allocate output tensors. + int64_t sequences_dims[] = {parameters->batch_size, parameters->num_return_sequences, parameters->max_length}; + TensorShape sequences_shape(&sequences_dims[0], sizeof(sequences_dims) / sizeof(sequences_dims[0])); + Tensor* output_sequences = this->context_.Output(0, sequences_shape); + + int64_t sequences_scores_dims[] = {parameters->batch_size, parameters->num_return_sequences}; + constexpr int64_t dims = sizeof(sequences_scores_dims) / sizeof(sequences_scores_dims[0]); + TensorShape sequences_scores_shape(&sequences_scores_dims[0], dims); + Tensor* output_sequences_scores = this->context_.Output(1, sequences_scores_shape); + + int64_t scores_dims[] = { + static_cast(parameters->max_length) - static_cast(parameters->sequence_length), + parameters->batch_size, parameters->num_beams, parameters->vocab_size}; + TensorShape scores_shape(&scores_dims[0], sizeof(scores_dims) / sizeof(scores_dims[0])); + Tensor* output_scores = this->context_.Output(2, scores_shape); + + // Update the flag to indicate whether scores exists in output + this->parameters_->output_scores = (output_scores != nullptr); + + // ------------------------------------ + // Call encoder subgraph. + // ------------------------------------ + std::vector encoder_feeds; + std::vector encoder_fetches; + + const OrtValue* encoder_input_ids_value = this->context_.GetInputOrtValue(0); + const Tensor& encoder_input_ids = encoder_input_ids_value->Get(); + + BeamSearchCpuState cpu_state{*parameters, + this->cpu_allocator_, + this->IsCuda()}; + + IAllocatorUniquePtr buffer; + + const OrtValue* initial_decoder_input_ids_value = this->context_.GetInputOrtValue(10); + + OrtValue decoder_input_ids; // Tensor in CPU, and it will be used to initialize sequence in cpu_state + ORT_RETURN_IF_ERROR(this->encoder_subgraph_.CreateInitialFeeds( + encoder_input_ids, + initial_decoder_input_ids_value, + parameters->decoder_start_token_id, + this->implicit_inputs_, + encoder_feeds, + this->create_encoder_inputs_func_, + this->add_to_feeds_func_, + buffer, + decoder_input_ids, + this->ort_stream_)); + +#ifdef DEBUG_NODE_INPUTS_OUTPUTS + const_cast(this->encoder_session_state_).IncrementGraphExecutionCounter(); +#endif + ORT_RETURN_IF_ERROR(utils::ExecuteSubgraph(this->encoder_session_state_, + encoder_feeds_fetches_manager, + encoder_feeds, + encoder_fetches, + {}, + ExecutionMode::ORT_SEQUENTIAL, + this->context_.GetTerminateFlag(), + this->context_.Logger(), + this->ort_stream_)); + +#ifdef DEBUG_GENERATION + const IConsoleDumper* dumper = this->GetConsoleDumper(); + for (int i = 0; i < this->encoder_subgraph_.num_subgraph_inputs; i++) { + dumper->Print("encoder_feeds", static_cast(i), true); + dumper->Print("", encoder_feeds[i]); + } + + for (int i = 0; i <= encoder_subgraph_.GetFirstPresentOutputIndex(); i++) { + dumper->Print("encoder_fetches", i, true); + dumper->Print("", encoder_fetches[i]); + } +#endif + + // ------------------------------------ + // Initialize resources + // ------------------------------------ + + BeamSearchState beam_state{*parameters, + this->temp_space_allocator_, + decoder_subgraph_.has_decoder_masked_attention_, + false /* use_position */}; + + init_beam_state_func_(&beam_state, + cpu_state.sequence_lengths, + parameters->batch_size, + parameters->num_beams, + this->ort_stream_); + + // Copy decoder_input_ids (in CPU) to sequence. It contains the initial decoder token ids for each beam. + cpu_state.SetUnexpandedSequence(decoder_input_ids.Get().DataAsSpan()); + + // beam_state.sequences_device is the GPU version of cpu_state.sequences_space, + // this copies it over to the GPU after setting it up on the CPU + if (this->IsCuda()) { + cpu_state.sequences.InitDevice(beam_state.sequences_device); + ORT_RETURN_IF_ERROR(this->device_copy_int32_func_(beam_state.sequences_device.subspan(0, beam_state.sequences_device.size() / 2), + cpu_state.sequences_space.subspan(0, cpu_state.sequences_space.size() / 2), + nullptr, + DeviceCopyDirection::hostToDevice)); + } + + this->beam_scorer_ = create_beam_scorer_func_ + ? create_beam_scorer_func_(*parameters, this->temp_space_allocator_, this->cpu_allocator_, this->ort_stream_) + : std::make_unique(*parameters, this->cpu_allocator_); + + // ------------------------------------------------------------------------------ + // Generate next token from logits output from encoder, and initialize decoder inputs. + // ------------------------------------------------------------------------------ + gsl::span beam_next_tokens; + + int iteration_counter = 0; + std::vector decoder_feeds; + int current_length = parameters->sequence_length; + + std::vector decoder_fetches; + + if (current_length + 1 < parameters->max_length) { + ++iteration_counter; + ORT_RETURN_IF_ERROR(this->GenerateNextToken(encoder_fetches[0], + 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_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_)); + + if (decoder_subgraph_.past_present_share_buffer_) { + decoder_fetches.reserve(static_cast(decoder_subgraph_.GetFirstPresentOutputIndex()) + + 2 * static_cast(decoder_subgraph_.num_layers)); + decoder_fetches.resize(decoder_subgraph_.GetFirstPresentOutputIndex(), OrtValue()); + for (int layer = 0; layer < 2 * decoder_subgraph_.num_layers; layer++) { + int feed_idx = decoder_subgraph_.GetFirstPastInputIndex() + layer; + OrtValue& past_tensor_value = decoder_feeds[feed_idx]; + Tensor* past_tensor = past_tensor_value.GetMutable(); + OrtValue present_tensor_value; + Tensor::InitOrtValue(past_tensor->DataType(), past_tensor->Shape(), past_tensor->MutableData(), + past_tensor->Location(), present_tensor_value); + decoder_fetches.push_back(present_tensor_value); + } + } + + if (decoder_subgraph_.has_decoder_masked_attention_) { + size_t offset = static_cast(decoder_subgraph_.GetFirstPastInputIndex()); + // Need to check cross attention's past key tensor size, suppose all layers cross attention key size are same + auto first_cross_attention_key = decoder_feeds[offset + 2 * static_cast(decoder_subgraph_.num_layers)].GetMutable(); + auto cross_attention_past_key_sz = first_cross_attention_key->Shape().Size(); + beam_state.EnsurePastStateReorderStagingBuffer(this->temp_space_allocator_, cross_attention_past_key_sz); + +#ifdef USE_CUDA + // Here we only need to reorder the past key for self-attention and cross-attention. + for (size_t i = 0; i < 2 * static_cast(decoder_subgraph_.num_layers); ++i) { + ORT_RETURN_IF_ERROR(reorder_past_state_func_(cuda_device_prop_, + *decoder_feeds[offset + 2 * i].GetMutable(), + beam_state.staging_for_past_state_reorder, + this->ort_stream_)); + } + size_t cache_indir_input_offset = static_cast(decoder_subgraph_.GetFirstPastInputIndex()) + 4 * static_cast(decoder_subgraph_.num_layers) + 2; + ORT_RETURN_IF_ERROR(init_cache_indir_func_(*decoder_feeds[cache_indir_input_offset].GetMutable(), this->ort_stream_)); +#endif + } + } + + 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); + + for (int i = 0; i <= decoder_subgraph_.GetFirstPastInputIndex(); i++) { + dumper->Print("decoder_feeds", i, true); + dumper->Print("", decoder_feeds[i]); + } + auto offset = decoder_subgraph_.GetFirstPastInputIndex() + 4 * decoder_subgraph_.num_layers; + dumper->Print("past_sequence_length", offset, true); + dumper->Print("", decoder_feeds[offset]); +#endif + +#ifdef DEBUG_NODE_INPUTS_OUTPUTS + const_cast(this->decoder_session_state_).IncrementGraphExecutionCounter(); +#endif + status = utils::ExecuteSubgraph(this->decoder_session_state_, + decoder_feeds_fetches_manager, + decoder_feeds, + decoder_fetches, + {}, + ExecutionMode::ORT_SEQUENTIAL, + this->context_.GetTerminateFlag(), + this->context_.Logger(), + this->ort_stream_); + + ORT_RETURN_IF_ERROR(status); + +#ifdef DEBUG_GENERATION + for (int i = 0; i <= decoder_subgraph_.GetFirstPresentOutputIndex(); i++) { + dumper->Print("decoder_fetches", i, true); + dumper->Print("", decoder_fetches[i]); + } +#endif + + const OrtValue& logits = decoder_fetches[0]; + ORT_RETURN_IF_ERROR(this->GenerateNextToken(logits, + beam_next_tokens, + beam_state, + cpu_state, + iteration_counter)); + + // When all batches are finished, stop earlier to avoid wasting computation. + if (this->beam_scorer_->IsDone()) { + break; + } + + // TODO: If this is safe to do after update_decoder_feeds_func, move it later so that we can speculatively run the next steps while we wait + // for the done result to transfer to the CPU + if (this->beam_scorer_->IsDoneLater()) { + break; + } + + // Increase sequence length after a new token is generated. + ++current_length; + + // Prepare inputs for next round of subgraph call. + if (current_length < parameters->max_length) { + gsl::span place_holder; + const int num_present_outputs = 2 * parameters->num_layers; // number of outputs with name like present_* + ORT_RETURN_IF_ERROR(this->update_decoder_feeds_func_( + this->temp_space_allocator_, + this->ort_stream_, + decoder_fetches, + decoder_feeds, + num_present_outputs, + ReinterpretAsSpan(beam_next_tokens), + decoder_subgraph_.has_decoder_masked_attention_ + ? place_holder + : ReinterpretAsSpan(this->beam_scorer_->GetNextIndicesCPU()), + decoder_subgraph_.has_decoder_masked_attention_ + ? ReinterpretAsSpan(this->beam_scorer_->GetNextIndicesGPU()) + : place_holder, + parameters->num_beams, + decoder_subgraph_.GetFirstPastInputIndex(), + decoder_subgraph_.GetFirstPresentOutputIndex(), + decoder_subgraph_.UseSequenceAsInputIds(), + current_length, + parameters->sequence_length, + decoder_subgraph_.past_present_share_buffer_, + decoder_subgraph_.has_decoder_masked_attention_, + cpu_state.sequences, + this->GetConsoleDumper())); + } + + if (decoder_subgraph_.past_present_share_buffer_) { + // clear fetched values before presents[] + for (int idx = 0; idx < decoder_subgraph_.GetFirstPresentOutputIndex(); idx++) { + decoder_fetches[idx] = OrtValue(); + } + } else { + decoder_fetches.clear(); + } + } + + gsl::span final_beam_scores = beam_state.beam_scores; + this->beam_scorer_->Finalize(cpu_state.sequences, + final_beam_scores, + output_sequences, + output_sequences_scores); + + // Output per token scores + if (output_scores) { + gsl::span target = output_scores->MutableDataAsSpan(); + gsl::span source = beam_state.scores; + assert(target.size() == source.size()); + ORT_RETURN_IF_ERROR(this->device_copy_func_(target, source, nullptr, DeviceCopyDirection::deviceToDevice)); + } + + return status; +} + +} // namespace transformers +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cpu/transformers/beam_search_parameters.cc b/onnxruntime/contrib_ops/cpu/transformers/beam_search_parameters.cc index 85c1204576a32..76011a5c89b66 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/beam_search_parameters.cc +++ b/onnxruntime/contrib_ops/cpu/transformers/beam_search_parameters.cc @@ -31,15 +31,30 @@ void BeamSearchParameters::ParseFromInputs(OpKernelContext* context) { ORT_ENFORCE(context != nullptr); const Tensor* input_ids = context->Input(0); const auto& dims = input_ids->Shape().GetDims(); + int initial_decode_sequence_length = 0; if (this->model_type == IGenerationParameters::kModelTypeWhisper) { ORT_ENFORCE(dims.size() == 3, "input_features shall have 3 dimensions. Got ", dims.size()); + const Tensor* decoder_input_ids = context->Input(10); + if (decoder_input_ids == nullptr) { + initial_decode_sequence_length = 1; + } else { + const auto& decoder_dims = decoder_input_ids->Shape().GetDims(); + initial_decode_sequence_length = static_cast(decoder_dims[1]); + ORT_ENFORCE(decoder_dims.size() == 2, "decoder_input_ids shall have 2 dimensions. Got ", decoder_dims.size()); + } } else { ORT_ENFORCE(dims.size() == 2, "input_ids shall have 2 dimensions. Got ", dims.size()); } batch_size = static_cast(dims[0]); - // For T5, output sequence starts with decoder_start_token_id, so its sequence length is 1 - sequence_length = (this->model_type == IGenerationParameters::kModelTypeGpt) ? static_cast(dims[1]) : 1; + if (this->model_type == IGenerationParameters::kModelTypeGpt) { + sequence_length = static_cast(dims[1]); + } else if (this->model_type == IGenerationParameters::kModelTypeWhisper) { + sequence_length = initial_decode_sequence_length; + } else { + // For T5, output sequence starts with decoder_start_token_id, so its sequence length is 1 + sequence_length = 1; + } auto* max_length_tensor = context->Input(1); max_length = max_length_tensor ? static_cast(*max_length_tensor->Data()) : kMaxSequenceLength; @@ -66,10 +81,10 @@ void BeamSearchParameters::ParseFromInputs(OpKernelContext* context) { auto* length_penalty_tensor = context->Input(5); if (length_penalty_tensor) { - if (length_penalty_tensor->DataType() == DataTypeImpl::GetType()) { - length_penalty = static_cast(*length_penalty_tensor->Data()); + if (length_penalty_tensor->IsDataType()) { + length_penalty = *length_penalty_tensor->Data(); } else { - length_penalty = static_cast(*length_penalty_tensor->Data()); + length_penalty = static_cast(*length_penalty_tensor->Data()); } } else { length_penalty = 1.0f; @@ -77,15 +92,20 @@ void BeamSearchParameters::ParseFromInputs(OpKernelContext* context) { auto* repetition_penalty_tensor = context->Input(6); if (repetition_penalty_tensor) { - if (repetition_penalty_tensor->DataType() == DataTypeImpl::GetType()) { - repetition_penalty = static_cast(*repetition_penalty_tensor->Data()); + if (repetition_penalty_tensor->IsDataType()) { + repetition_penalty = *repetition_penalty_tensor->Data(); } else { - repetition_penalty = static_cast(*repetition_penalty_tensor->Data()); + repetition_penalty = static_cast(*repetition_penalty_tensor->Data()); } } else { repetition_penalty = 1.0f; } ORT_ENFORCE(repetition_penalty > 0.0f, "repetition_penalty shall be greater than 0, got ", repetition_penalty); + + auto* logits_processor_tensor = context->Input(11); + logits_processor = logits_processor_tensor ? static_cast(*logits_processor_tensor->Data()) : 0; + ORT_ENFORCE(logits_processor >= 0, + "logits_processor shall be a non-negative integer, got ", logits_processor); } void BeamSearchParameters::SetSubgraphParameters(int vocabulary_size, int heads, int hidden_size_per_head, int layers) { diff --git a/onnxruntime/contrib_ops/cpu/transformers/beam_search_scorer.cc b/onnxruntime/contrib_ops/cpu/transformers/beam_search_scorer.cc index e26d4245c8f18..7e2e5b2129221 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/beam_search_scorer.cc +++ b/onnxruntime/contrib_ops/cpu/transformers/beam_search_scorer.cc @@ -4,6 +4,7 @@ #include #include #include "core/common/common.h" +#include "core/common/narrow.h" #include "core/common/safeint.h" #include "core/common/span_utils.h" #include "core/framework/allocator.h" @@ -18,43 +19,35 @@ namespace contrib { namespace transformers { using ::onnxruntime::rnn::detail::Allocate; -BeamHypotheses::BeamHypotheses(int num_beams, - float length_penalty, - bool early_stopping, - onnxruntime::OrtStlAllocator& hypothesis_score_allocator) - : num_beams_(num_beams), - length_penalty_(length_penalty), - early_stopping_(early_stopping), - worst_score_(1e9), - beams_(hypothesis_score_allocator) { +void BeamHypotheses::Init(float length_penalty, gsl::span beams) { + beams_ = beams; + beams_used_ = 0; + length_penalty_ = length_penalty; + done_ = false; } void BeamHypotheses::Add(gsl::span& hypothesis, float sum_logprobs) { auto length = hypothesis.size(); float score = sum_logprobs / pow(static_cast(length), length_penalty_); - if (this->Size() < num_beams_ || score > worst_score_) { - HypothesisScore item(hypothesis, score); - beams_.push(item); - if (this->Size() > num_beams_) { - beams_.pop(); - } - worst_score_ = beams_.top().score; - } -} + size_t index = beams_used_; + // If the array is full, don't add unless it's better than the worst element + if (index == beams_.size()) { + if (score <= beams_[--index].score) + return; + } else + beams_used_++; -bool BeamHypotheses::IsDone(float best_sum_logprobs, int current_length) { - // If there are enough hypotheses and that none of the hypotheses being generated can become better - // than the worst one in the heap, then we are done with this sentence. + // Rotate existing elements over while the new element scores higher + for (; index > 0 && score > beams_[index - 1].score; index--) + beams_[index] = beams_[index - 1]; - if (Size() < num_beams_) - return false; - - if (early_stopping_) - return true; + beams_[index] = HypothesisScore{hypothesis, score}; +} +bool BeamHypotheses::CanImprove(float best_sum_logprobs, int current_length) const { float current_score = best_sum_logprobs / pow(static_cast(current_length), length_penalty_); - return worst_score_ >= current_score; + return beams_.back().score < current_score; } void BeamHypotheses::Output( @@ -63,84 +56,48 @@ void BeamHypotheses::Output( gsl::span& sequences, // buffer filled with pad token ID, shape (num_return_sequences, max_length) gsl::span& sequences_scores) // buffer of shape (num_return_sequences) or empty { - ORT_ENFORCE(top_k <= Size()); - int remove_count = Size() - top_k; - for (int i = 0; i < remove_count; i++) { - beams_.pop(); - } - - // Since pop get the worst sequence, so output it in the reverse order. - // The first (worst) beam shall be put at the last position among top_k sequences. - int index = top_k - 1; - while (!beams_.empty()) { - auto item = beams_.top(); - gsl::span& source = item.hypothesis; + // Copy the top_k beams into the sequences + ORT_ENFORCE(top_k <= beams_used_); + for (int index = 0; index < top_k; index++) { + auto& item = beams_[index]; gsl::span target = sequences.subspan(static_cast(index) * max_length, max_length); // Note that word_ids might be less than max_length. // Since the sequences has been filled with pad token ID, so padding is not needed here. - gsl::copy(source, target); + gsl::copy(item.hypothesis, target); if (!sequences_scores.empty()) sequences_scores[index] = item.score; - - beams_.pop(); - index--; - } -} - -BeamSearchScorer::BeamSearchScorer(size_t batch_size, - size_t num_beams, - size_t max_length, - float length_penalty, - bool early_stopping, - size_t num_return_sequences, - int pad_token_id, - int eos_token_id, - onnxruntime::OrtStlAllocator& hypothesis_score_allocator, - onnxruntime::OrtStlAllocator& beam_hyps_allocator) - : batch_size_(batch_size), - num_beams_(num_beams), - max_length_(max_length), - num_beam_hyps_to_keep_(num_return_sequences), - pad_token_id_(pad_token_id), - eos_token_id_(eos_token_id), - hypothesis_buffer_length_(0), - hypothesis_buffer_offset_(0), - beam_hyps_(beam_hyps_allocator) { - for (size_t i = 0; i < batch_size; i++) { - beam_hyps_.push_back(BeamHypotheses(num_beams, length_penalty, early_stopping, hypothesis_score_allocator)); - } -} - -bool BeamSearchScorer::IsDone() { - for (size_t batch = 0; batch < batch_size_; batch++) { - if (!done_[batch]) - return false; } - return true; } -void BeamSearchScorer::Initialize(AllocatorPtr& allocator, int sequence_length) { - ORT_ENFORCE(next_beam_scores_.empty()); // Make sure this is called only once. - +BeamSearchScorer::BeamSearchScorer(const IGenerationParameters& parameters, + AllocatorPtr& allocator) + : batch_size_{static_cast(parameters.batch_size)}, + num_beams_{static_cast(parameters.num_beams)}, + max_length_{static_cast(parameters.max_length)}, + num_return_sequences_{static_cast(parameters.num_return_sequences)}, + pad_token_id_{parameters.pad_token_id}, + eos_token_id_{parameters.eos_token_id}, + early_stopping_{parameters.early_stopping}, + not_done_count_{parameters.batch_size} { size_t batch_beam_size = batch_size_ * num_beams_; - constexpr bool no_fill = false; // Do not fill values after allocation - done_ = Allocate(allocator, batch_size_, done_ptr_, no_fill); - std::fill_n(done_.data(), done_.size(), false); + auto beams = Allocate(allocator, batch_beam_size, hypothesis_scores_ptr_); + beam_hyps_ = Allocate(allocator, batch_size_, beam_hyps_ptr_); + for (size_t i = 0; i < batch_size_; i++) + beam_hyps_[i].Init(parameters.length_penalty, beams.subspan(i * num_beams_, num_beams_)); - next_beam_scores_ = Allocate(allocator, batch_beam_size, next_beam_scores_ptr_, no_fill); - next_beam_tokens_ = Allocate(allocator, batch_beam_size, next_beam_tokens_ptr_, no_fill); - next_beam_indices_ = Allocate(allocator, batch_beam_size, next_beam_indices_ptr_, no_fill); + next_beam_scores_ = Allocate(allocator, batch_beam_size, next_beam_scores_ptr_); + next_beam_tokens_ = Allocate(allocator, batch_beam_size, next_beam_tokens_ptr_); + next_beam_indices_ = Allocate(allocator, batch_beam_size, next_beam_indices_ptr_); // Space to store intermediate sequence with length sequence_length, sequence_length + 1, ..., max_sequence_length. - size_t per_beam = (SafeInt(max_length_) * (max_length_ + 1) - (sequence_length - 1) * sequence_length) / 2; - hypothesis_buffer_length_ = batch_beam_size * per_beam; - hypothesis_buffer_ = Allocate(allocator, hypothesis_buffer_length_, hypothesis_buffer_ptr_, no_fill); + size_t per_beam = (SafeInt(max_length_) * (max_length_ + 1) - (parameters.sequence_length - 1) * parameters.sequence_length) / 2; + hypothesis_buffer_ = Allocate(allocator, batch_beam_size * per_beam, hypothesis_buffer_ptr_); } -void BeamSearchScorer::Process(ISequences* sequences, +void BeamSearchScorer::Process(ISequences& sequences, gsl::span& next_scores, gsl::span& next_tokens, gsl::span& next_indices) { @@ -148,15 +105,15 @@ void BeamSearchScorer::Process(ISequences* sequences, // It contains word ID of whole sequence generated so far. // It is different from subgraph input_ids, which only need one word when past state is not empty. - const int sequence_length = sequences->GetSequenceLength(); + const int sequence_length = sequences.GetSequenceLength(); ORT_ENFORCE(next_scores.size() == next_tokens.size()); ORT_ENFORCE(next_scores.size() == next_indices.size()); for (size_t batch = 0; batch < batch_size_; batch++) { BeamHypotheses& beam_hyp = beam_hyps_[batch]; - if (done_[batch]) { - ORT_ENFORCE(beam_hyp.Size() >= gsl::narrow_cast(num_beams_), + if (beam_hyp.done_) { + ORT_ENFORCE(beam_hyp.beams_used_ == gsl::narrow_cast(num_beams_), "Batch can only be done if all beams have been generated"); // Pad the batch. @@ -185,10 +142,11 @@ void BeamSearchScorer::Process(ISequences* sequences, } // Clone the sequence and append to buffer. - gsl::span src = sequences->GetSequence(batch_beam_idx); - auto clone = hypothesis_buffer_.subspan(hypothesis_buffer_offset_, sequence_length); + gsl::span src = sequences.GetSequence(batch_beam_idx); + auto clone = hypothesis_buffer_.subspan(static_cast(hypothesis_buffer_used_), sequence_length); + gsl::copy(src, clone); - hypothesis_buffer_offset_ += static_cast(sequence_length); + hypothesis_buffer_used_ += sequence_length; auto sequence = ReinterpretAsSpan(clone); beam_hyp.Add(sequence, next_score); } else { @@ -205,37 +163,41 @@ void BeamSearchScorer::Process(ISequences* sequences, } ORT_ENFORCE(beam_idx == num_beams_); - ORT_ENFORCE(hypothesis_buffer_offset_ <= hypothesis_buffer_length_); + ORT_ENFORCE(static_cast(hypothesis_buffer_used_) <= hypothesis_buffer_.size()); // Check if we are done so that we can save a pad step if all(done) - if (!done_[batch]) { + if (static_cast(beam_hyp.beams_used_) < num_beams_) + continue; + + if (!early_stopping_) { gsl::span topk_scores = next_scores.subspan(batch * num_beams_, top_k); const auto best_sum_logprobs = std::max_element(topk_scores.begin(), topk_scores.end()); - if (beam_hyp.IsDone(*best_sum_logprobs, sequence_length)) { - done_[batch] = true; - } + if (beam_hyp.CanImprove(*best_sum_logprobs, sequence_length)) + continue; } + + beam_hyp.done_ = true; + not_done_count_--; } } -void BeamSearchScorer::Finalize(ISequences* sequences, +void BeamSearchScorer::Finalize(ISequences& sequences, gsl::span& final_beam_scores, Tensor* output_sequences, Tensor* output_sequence_scores) { - ORT_ENFORCE(sequences != nullptr); ORT_ENFORCE(output_sequences != nullptr); // Finalize all open beam hypotheses and add to generated hypotheses. for (size_t batch_index = 0; batch_index < batch_size_; batch_index++) { BeamHypotheses& beam_hyp = beam_hyps_[batch_index]; - if (done_[batch_index]) { + if (beam_hyp.done_) { continue; } for (size_t beam_index = 0; beam_index < num_beams_; beam_index++) { size_t batch_beam_index = batch_index * num_beams_ + beam_index; float final_score = final_beam_scores[batch_beam_index]; - auto final_tokens = sequences->GetSequence(batch_beam_index); + auto final_tokens = sequences.GetSequence(narrow(batch_beam_index)); beam_hyp.Add(final_tokens, final_score); } } @@ -248,30 +210,22 @@ void BeamSearchScorer::Finalize(ISequences* sequences, // Score of each sequence, with shape (batch_size * num_return_sequences). gsl::span sequence_scores; - if (output_sequence_scores != nullptr) { + if (output_sequence_scores) { sequence_scores = output_sequence_scores->MutableDataAsSpan(); } - // Span is empty when output_sequence_scores is NULL. - gsl::span batch_sequence_score; - // Select the best hypotheses according to number of sequences to return. for (size_t batch_index = 0; batch_index < batch_size_; batch_index++) { BeamHypotheses& beam_hyp = beam_hyps_[batch_index]; - const size_t num_return_sequences = num_beam_hyps_to_keep_; - auto batch_output = output.subspan(batch_index * num_return_sequences * max_length_, - num_return_sequences * max_length_); - - if (output_sequence_scores != nullptr) { - batch_sequence_score = sequence_scores.subspan(batch_index * num_return_sequences, num_return_sequences); - } + auto batch_output = output.subspan(batch_index * num_return_sequences_ * max_length_, + num_return_sequences_ * max_length_); + gsl::span sequence_scores_buffer; + if (!sequence_scores.empty()) + sequence_scores_buffer = sequence_scores.subspan(batch_index * num_return_sequences_, num_return_sequences_); - beam_hyp.Output( - num_return_sequences, - max_length_, - batch_output, - batch_sequence_score); + beam_hyp.Output(narrow(num_return_sequences_), narrow(max_length_), batch_output, + sequence_scores_buffer); } } diff --git a/onnxruntime/contrib_ops/cpu/transformers/beam_search_scorer.h b/onnxruntime/contrib_ops/cpu/transformers/beam_search_scorer.h index fdd404efa04f7..94b6d340d9f4a 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/beam_search_scorer.h +++ b/onnxruntime/contrib_ops/cpu/transformers/beam_search_scorer.h @@ -20,92 +20,61 @@ namespace contrib { namespace transformers { struct HypothesisScore { - HypothesisScore(gsl::span& _hypothesis, float _score) - : hypothesis(_hypothesis), score(_score) {} - gsl::span hypothesis; float score; }; -class HypothesisScoreCompare { - public: - bool operator()(const HypothesisScore& a, const HypothesisScore& b) { - return a.score > b.score; - } -}; - -class BeamHypotheses { - public: - BeamHypotheses(int num_beams, - float length_penalty, - bool early_stopping, - onnxruntime::OrtStlAllocator& hypothesis_score_allocator); - - // Number of hypotheses - int Size() { return static_cast(beams_.size()); } +struct BeamHypotheses { + // As these are constructed as an uninitialized array of memory, we need an Init method + void Init(float length_penalty, gsl::span beams); // Add a new hypothesis void Add(gsl::span& hypothesis, float sum_logprobs); - bool IsDone(float best_sum_logprobs, int current_length); + // Return true if this beats the worst score in the hypothesis + bool CanImprove(float best_sum_logprobs, int current_length) const; - // Output results. Note that it will clear all beams. + // Output results void Output(int top_k, // number of sequences to return int max_length, // max sequence length gsl::span& sequences, // buffer with pad token, shape (num_return_sequences, max_length) gsl::span& sequences_scores); // buffer for sequence scores, with shape (num_return_sequences) - private: - int num_beams_; + gsl::span beams_; // Beam width sized array of hypotheses, sorted by highest scoring + int beams_used_; // Number of elements used in beams_ float length_penalty_; - bool early_stopping_; - float worst_score_; - - // Min-heap for top k - std::priority_queue, HypothesisScoreCompare> beams_; + bool done_; }; -class BeamSearchScorer : public IBeamScorer { - public: - BeamSearchScorer(size_t batch_size, - size_t num_beams, - size_t max_length, - float length_penalty, - bool early_stopping, - size_t num_return_sequences, - int pad_token_id, - int eos_token_id, - onnxruntime::OrtStlAllocator& hypothesis_score_allocator, - onnxruntime::OrtStlAllocator& beam_hyps_allocator); - - void Initialize(AllocatorPtr& allocator, int sequence_length) override; - - void Process(ISequences* sequences, +struct BeamSearchScorer : IBeamScorer { + BeamSearchScorer(const IGenerationParameters& parameters, + AllocatorPtr& allocator); + + void Process(ISequences& sequences, gsl::span& next_scores, gsl::span& next_tokens, gsl::span& next_indices) override; - void Finalize(ISequences* sequences, + void Finalize(ISequences& sequences, gsl::span& final_beam_scores, Tensor* output_sequences, Tensor* output_sequence_scores) override; - bool IsDone(); + bool IsDone() const override { return not_done_count_ == 0; } - gsl::span& GetNextScores() { return next_beam_scores_; } - gsl::span& GetNextTokens() { return next_beam_tokens_; } - gsl::span& GetNextIndices() override { return next_beam_indices_; } + gsl::span GetNextScores() override { return next_beam_scores_; } + gsl::span GetNextTokens() override { return next_beam_tokens_; } + gsl::span GetNextIndicesCPU() override { return next_beam_indices_; } private: size_t batch_size_; size_t num_beams_; size_t max_length_; - size_t num_beam_hyps_to_keep_; + size_t num_return_sequences_; int pad_token_id_; int eos_token_id_; - - IAllocatorUniquePtr done_ptr_; // Allocated buffer for done_ - gsl::span done_; // Flags indicates whether each batch is finished or not. Shape is (batch_size). + bool early_stopping_; + int not_done_count_; // When zero, every batch entry is done (starts at batch_size_) IAllocatorUniquePtr next_beam_scores_ptr_; gsl::span next_beam_scores_; @@ -118,10 +87,11 @@ class BeamSearchScorer : public IBeamScorer { IAllocatorUniquePtr hypothesis_buffer_ptr_; // Allocated buffer to hold all hypotheses gsl::span hypothesis_buffer_; // Span of the allocated buffer - size_t hypothesis_buffer_length_; // Total number of elements - size_t hypothesis_buffer_offset_; // Offset of available buffer, or length of used buffer. + int hypothesis_buffer_used_{}; // Offset of available buffer, or length of used buffer. - onnxruntime::FastAllocVector beam_hyps_; + IAllocatorUniquePtr hypothesis_scores_ptr_; // num_beams_ * batch_size_, divided into num_beams_ chunks per BeamHypothesis in beam_hyps_ + IAllocatorUniquePtr beam_hyps_ptr_; + gsl::span beam_hyps_; // Shape is batch_size_ }; } // namespace transformers diff --git a/onnxruntime/contrib_ops/cpu/transformers/generate_impl_base.h b/onnxruntime/contrib_ops/cpu/transformers/generate_impl_base.h index 89f398b9c6155..e889281abb023 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/generate_impl_base.h +++ b/onnxruntime/contrib_ops/cpu/transformers/generate_impl_base.h @@ -82,13 +82,13 @@ class GenerateBase { implicit_inputs_(context_.GetImplicitInputs()), ort_stream_(ort_stream), cuda_dumper_(cuda_dumper), - cpu_allocator_(nullptr), + cpu_allocator_(decoder_session_state.GetAllocator( + decoder_session_state.GetExecutionProviders() + .Get(onnxruntime::kCpuExecutionProvider) + ->GetOrtDeviceByMemType(OrtMemTypeDefault))), temp_space_allocator_(nullptr), topk_func_(topk_func), device_copy_func_(device_copy_func) { - cpu_allocator_ = decoder_session_state.GetExecutionProviders() - .Get(onnxruntime::kCpuExecutionProvider) - ->GetAllocator(OrtMemTypeDefault); } virtual ~GenerateBase() = default; @@ -122,14 +122,21 @@ class GenerateBase { const Tensor* vocab_mask, const Tensor* prefix_vocab_mask, const Tensor* attention_mask, - const Tensor* presence_mask) const { + const Tensor* presence_mask, + const Tensor* decoder_input_ids) const { const auto& dims = input_ids->Shape().GetDims(); if (parameters->model_type == IGenerationParameters::kModelTypeWhisper) { if (dims.size() != 3) { return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Input 'input_features' is expected to have 3 dimensions, got ", dims.size()); } - + if (decoder_input_ids != nullptr) { + const auto& decoder_dims = decoder_input_ids->Shape().GetDims(); + if (decoder_dims.size() != 2) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "Input 'decoder_input_ids' is expected to have 2 dimensions, got ", decoder_dims.size()); + } + } } else if (dims.size() != 2) { return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Input 'input_ids' is expected to have 2 dimensions, got ", dims.size()); @@ -189,7 +196,7 @@ class GenerateBase { return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Input 'attention_mask' is expected to have 2 dimensions, got ", dims_attn.size()); } - if (!SpanEq(dims_attn, dims)) { + if (parameters->model_type != IGenerationParameters::kModelTypeWhisper && !SpanEq(dims_attn, dims)) { return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Input 'attention_mask' is expected to have same shape as input_ids"); } @@ -220,9 +227,13 @@ class GenerateBase { } protected: - bool IsCuda() const { return ort_stream_ != nullptr; } + bool IsCuda() const { + return ort_stream_ != nullptr; + } - const IConsoleDumper* GetConsoleDumper() const { return IsCuda() ? cuda_dumper_ : &(cpu_dumper_); } + const IConsoleDumper* GetConsoleDumper() const { + return IsCuda() ? cuda_dumper_ : &(cpu_dumper_); + } OpKernelContextInternal& context_; diff --git a/onnxruntime/contrib_ops/cpu/transformers/generation_device_helper.cc b/onnxruntime/contrib_ops/cpu/transformers/generation_device_helper.cc index 76630a30df429..88348ad88dc27 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/generation_device_helper.cc +++ b/onnxruntime/contrib_ops/cpu/transformers/generation_device_helper.cc @@ -223,11 +223,13 @@ Status CreateGptInputs( return Status::OK(); } -Status AddToFeeds(const IExecutionProvider* /*execution_provider*/, - Stream* /*ort_stream*/, +Status AddToFeeds(Stream* /*ort_stream*/, std::initializer_list inputs, std::vector& feeds, - IAllocatorUniquePtr& /*buffer*/) { + IAllocatorUniquePtr& /*buffer*/, + AllocatorPtr /*device_allocator*/, + AllocatorPtr /*host_allocator*/, + const OrtMemoryInfo& /*location*/) { for (auto& input : inputs) { if (input.IsAllocated()) { feeds.push_back(input); @@ -278,7 +280,6 @@ void InitGreedyState(transformers::IGreedySearchState* greedy_state, template Status ProcessLogits(const OrtValue& logits, // logits output of subgraph transformers::IBeamSearchState* beam_state, // state - transformers::IBeamSearchCpuState* cpu_state, // state in CPU transformers::ISequences* sequences, // sequences AllocatorPtr& allocator, // default allocator onnxruntime::concurrency::ThreadPool* thread_pool, // thread pool (for CPU only) @@ -288,7 +289,6 @@ Status ProcessLogits(const OrtValue& logits, // int step, // iteration counter Stream* stream, // cuda stream (for CUDA only) const transformers::IConsoleDumper* dumper) { // tensor dumper - ORT_UNUSED_PARAMETER(cpu_state); #ifndef DEBUG_GENERATION ORT_UNUSED_PARAMETER(dumper); #endif @@ -429,7 +429,7 @@ Status ProcessLogits(const OrtValue& logits, // #endif beam_scorer->Process( - sequences, + *sequences, next_scores, next_tokens, next_indices); @@ -871,22 +871,19 @@ Status UpdateDecoderFeeds( } //------------------------------------------------ -// Modified Encoder functions for Whisper Model +// Modified encoder function for Whisper Model //------------------------------------------------ template Status CreateWhisperEncoderInputs( const Tensor* original_encoder_input_features, - const OrtValue* attn_mask_value, - int pad_token_id, + const OrtValue* original_decoder_input_ids_value, int start_token_id, AllocatorPtr allocator, OrtValue& encoder_input_features, - OrtValue& encoder_attention_mask, OrtValue& decoder_input_ids) { const TensorShape& input_features_shape = original_encoder_input_features->Shape(); ORT_ENFORCE(input_features_shape.NumDimensions() == 3); const int64_t& batch_size = input_features_shape[0]; - const int64_t& sequence_length = input_features_shape[1]; // Allocate attention_mask based on shape of input_ids auto element_type = DataTypeImpl::GetType(); @@ -901,37 +898,10 @@ Status CreateWhisperEncoderInputs( allocator->Info(), encoder_input_features); - if (attn_mask_value != nullptr) { - const Tensor& attention_mask = attn_mask_value->Get(); - Tensor::InitOrtValue(element_type, input_features_shape, const_cast(&attention_mask)->MutableData(), - allocator->Info(), encoder_attention_mask); - } else { - auto mask_type = DataTypeImpl::GetType(); - Tensor::InitOrtValue(mask_type, input_features_shape, allocator, encoder_attention_mask); - - // Set attention mask to be 0 for pad tokens, and 1 for all other tokens. - int32_t* mask_data = encoder_attention_mask.GetMutable()->MutableData(); - const int32_t* word_id = original_encoder_input_features->Data(); - int32_t* mask = mask_data; - for (int i = 0; i < batch_size; i++) { - int32_t abs_position = 0; - for (int j = 0; j < sequence_length; j++, word_id++, mask++) { - // T5Tokenizer might add one EOS pad token at the end. - // That EOS token shall have attention mask 1 even when EOS token is same as pad token. - // Here we only set attention mask to be 0 for left padding only, so as to be parity with huggingface. - if (*word_id == pad_token_id && abs_position == 0) { - *mask = 0; - } else { - *mask = 1; - abs_position++; - } - } - } - } - // decoder_input_ids is optional. - if (start_token_id >= 0) { + if (original_decoder_input_ids_value == nullptr) { // Filled decoder_input_ids with start token ID + ORT_ENFORCE(start_token_id >= 0); int64_t dims[] = {batch_size, 1}; TensorShape decoder_input_ids_shape(&dims[0], 2); Tensor::InitOrtValue(element_type, decoder_input_ids_shape, allocator, decoder_input_ids); @@ -939,6 +909,17 @@ Status CreateWhisperEncoderInputs( for (int i = 0; i < batch_size; i++, data++) { *data = start_token_id; } + } else { + // decoder_input_ids is of shape (batch_size, initial_sequence_length) + // Example: [[ decoder start token (i.e. start of transcript), language token, task token, timestamp token ]] + const Tensor* original_decoder_input_ids = &(original_decoder_input_ids_value->Get()); + const TensorShape& original_decoder_input_ids_shape = original_decoder_input_ids->Shape(); + ORT_ENFORCE(original_decoder_input_ids_shape.NumDimensions() == 2); + Tensor::InitOrtValue(element_type, + original_decoder_input_ids_shape, + const_cast(original_decoder_input_ids)->MutableData(), + allocator->Info(), + decoder_input_ids); } return Status::OK(); @@ -963,7 +944,6 @@ template void InitGreedyState( template Status ProcessLogits( const OrtValue& logits, transformers::IBeamSearchState* beam_state, - transformers::IBeamSearchCpuState* cpu_state, transformers::ISequences* sequences, AllocatorPtr& allocator, onnxruntime::concurrency::ThreadPool* thread_pool, @@ -1039,6 +1019,26 @@ template Status UpdateDecoderFeeds( transformers::Sequences& sequences, const transformers::IConsoleDumper* dumper); +template Status UpdateDecoderFeeds( + AllocatorPtr allocator, + Stream* stream, + const std::vector& last_outputs, + std::vector& next_inputs, + int num_present_tensors, + gsl::span beam_next_tokens, + gsl::span beam_indices, + gsl::span beam_indices_gpu, + int num_beams, + int t5_decoder_first_past_input_idx, + int t5_decoder_first_present_output_idx, + bool use_sequence_as_input_ids, + int current_length, + int input_sequence_len, + bool past_present_share_buffer, + bool need_cache_indir, + transformers::Sequences& sequences, + const transformers::IConsoleDumper* dumper); + template void ExpandInputs(const OrtValue& input, int num_beams, AllocatorPtr allocator, OrtValue& expanded); template Status ExpandBuffer( @@ -1070,23 +1070,20 @@ template Status ExpandBuffer( template Status CreateWhisperEncoderInputs( const Tensor* original_encoder_input_features, - const OrtValue* attn_mask_value, - int pad_token_id, + const OrtValue* original_decoder_input_ids_value, int start_token_id, AllocatorPtr allocator, OrtValue& encoder_input_features, - OrtValue& encoder_attention_mask, OrtValue& decoder_input_ids); template Status CreateWhisperEncoderInputs( const Tensor* original_encoder_input_features, - const OrtValue* attn_mask_value, - int pad_token_id, + const OrtValue* original_decoder_input_ids_value, int start_token_id, AllocatorPtr allocator, OrtValue& encoder_input_features, - OrtValue& encoder_attention_mask, OrtValue& decoder_input_ids); + } // namespace GenerationCpuDeviceHelper } // namespace contrib } // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cpu/transformers/generation_device_helper.h b/onnxruntime/contrib_ops/cpu/transformers/generation_device_helper.h index 782795eaad3aa..ba1b0b662f1a5 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/generation_device_helper.h +++ b/onnxruntime/contrib_ops/cpu/transformers/generation_device_helper.h @@ -33,6 +33,7 @@ enum DeviceCopyDirection { namespace GenerationDeviceHelper { +#ifdef USE_CUDA using ReorderPastStateFunc = std::function; +#endif using TopkFunc = std::function; using AddToFeedsFunc = std::function inputs, std::vector& feeds, - IAllocatorUniquePtr& buffer)>; + IAllocatorUniquePtr& buffer, + AllocatorPtr device_allocator, + AllocatorPtr host_allocator, + const OrtMemoryInfo& location)>; template using InitBeamStateFunc = std::function; +using CreateBeamScorer = std::function( + const transformers::IGenerationParameters& parameters, + AllocatorPtr& allocator, + AllocatorPtr& allocator_cpu, + Stream* stream)>; + template using InitGreedyStateFunc = std::function* greedy_state, @@ -88,7 +98,6 @@ template using ProcessLogitsFunc = std::function* beam_state, // state - transformers::IBeamSearchCpuState* cpu_state, // state in CPU transformers::ISequences* sequences, // sequences AllocatorPtr& allocator, // default allocator onnxruntime::concurrency::ThreadPool* thread_pool, // thread pool (for CPU only) @@ -175,6 +184,17 @@ using UpdateDecoderFeedsFunc = std::function; +//------------------------------------------------ +// Modified functions for Whisper Model +//------------------------------------------------ +using CreateWhisperEncoderInputsFunc = std::function; + template using ExpandBufferFunc = std::function inputs, std::vector& feeds, - IAllocatorUniquePtr& buffer); + IAllocatorUniquePtr& buffer, + AllocatorPtr device_allocator, + AllocatorPtr host_allocator, + const OrtMemoryInfo& location); template void InitBeamState(transformers::IBeamSearchState* beam_state, @@ -218,7 +240,6 @@ void InitGreedyState(transformers::IGreedySearchState* greedy_state, template Status ProcessLogits(const OrtValue& logits, // logits output of subgraph transformers::IBeamSearchState* beam_state, // state - transformers::IBeamSearchCpuState* cpu_state, // state in CPU transformers::ISequences* sequences, // sequences AllocatorPtr& allocator, // default allocator onnxruntime::concurrency::ThreadPool* thread_pool, // thread pool (for CPU only) @@ -325,12 +346,10 @@ Status UpdateDecoderFeeds( template Status CreateWhisperEncoderInputs( const Tensor* original_encoder_input_features, - const OrtValue* attn_mask_value, - int pad_token_id, + const OrtValue* original_decoder_input_ids_value, int start_token_id, AllocatorPtr allocator, OrtValue& encoder_input_ids, - OrtValue& encoder_attention_mask, OrtValue& decoder_input_ids); // --------------------------------------------------------------- diff --git a/onnxruntime/contrib_ops/cpu/transformers/generation_shared.h b/onnxruntime/contrib_ops/cpu/transformers/generation_shared.h index 79e9f04fad1e2..719dd302d274d 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/generation_shared.h +++ b/onnxruntime/contrib_ops/cpu/transformers/generation_shared.h @@ -39,8 +39,7 @@ struct IBeamSearchState { // in total, it will be: // 2 * (batch_size * num_beams * (parts_vocab + 1), 2 * num_beams) - // The final chosen indices after BeamScorer has finished processing - gsl::span chosen_indices; // shape (batch_size, num_beams) + gsl::span sequences_device; // shape (2 * batch_size * max_length) Tensor staging_for_past_state_reorder; // Tensor of shape (batch_size * num_beams, num_heads, max_length, head_size) }; @@ -93,37 +92,40 @@ struct ISamplingState { gsl::span cumulative_probs; }; -class ISequences { - public: +struct ISequences { virtual ~ISequences() {} virtual gsl::span GetSequence(int beam_index) const = 0; + virtual gsl::span GetCurrentDeviceSequences() const = 0; // Get all current beam_index sequences in one continuous block (to pass to CUDA) + virtual gsl::span GetNextDeviceSequences() = 0; // Get all next beam_index sequences in one continuous block (to pass to CUDA) virtual int GetSequenceLength() const = 0; }; -class ILogitsProcessorList { - public: +struct ILogitsProcessorList { virtual ~ILogitsProcessorList() {} virtual void Process(const ISequences* sequences, gsl::span& next_token_scores, int step) = 0; }; // Interface for all scorers for beam search or beam sample. -class IBeamScorer { - public: +struct IBeamScorer { virtual ~IBeamScorer() {} - virtual void Initialize(AllocatorPtr& allocator, int sequence_length) = 0; - - virtual void Process(ISequences* sequences, + virtual void Process(ISequences& sequences, gsl::span& next_scores, gsl::span& next_tokens, gsl::span& next_indices) = 0; - virtual void Finalize(ISequences* sequences, + virtual void Finalize(ISequences& sequences, gsl::span& final_beam_scores, Tensor* output_sequences, Tensor* output_sequence_scores) = 0; - virtual gsl::span& GetNextIndices() = 0; + virtual bool IsDone() const = 0; // GPU version will return false here, as it asynchronously queues up the event + virtual bool IsDoneLater() const { return false; } // GPU version waits for the asynchous result to complete here + + virtual gsl::span GetNextScores() = 0; + virtual gsl::span GetNextTokens() = 0; + virtual gsl::span GetNextIndicesCPU() = 0; + virtual gsl::span GetNextIndicesGPU() { return {}; } // If this is non CPU, returns the device buffer of the indices }; struct IGenerationParameters { @@ -131,6 +133,8 @@ struct IGenerationParameters { static constexpr int kModelTypeT5 = 1; static constexpr int kModelTypeWhisper = 2; + static constexpr int kLogitsProcessorTypeWhisper = 1; + // Parameters from node attributes int model_type; // 0 for GPT-2; 1 for encoder-decoder like T5; 2 for float inputs like Whisper int eos_token_id; @@ -148,6 +152,7 @@ struct IGenerationParameters { float repetition_penalty; int batch_size; // deduce from first dimension of input_ids int sequence_length; // deduce from second dimension of input_ids of GPT-2 or decoder_input_ids of T5 + int logits_processor; gsl::span vocab_mask; gsl::span prefix_vocab_mask; diff --git a/onnxruntime/contrib_ops/cpu/transformers/greedy_search.cc b/onnxruntime/contrib_ops/cpu/transformers/greedy_search.cc index 35dfedd90ff75..78395e347bc42 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/greedy_search.cc +++ b/onnxruntime/contrib_ops/cpu/transformers/greedy_search.cc @@ -198,14 +198,14 @@ Status GreedySearch::Compute(OpKernelContext* ctx) const { parameters, GenerationCpuDeviceHelper::CreateGptInputs, add_to_feeds_func_ ? add_to_feeds_func_ : GenerationCpuDeviceHelper::AddToFeeds, - reorder_past_state_func_ ? reorder_past_state_func_ : nullptr, // Only CUDA implementation needs the reorder helper for now topk_func_ ? topk_func_ : GenerationCpuDeviceHelper::TopK, process_logits_func_ ? process_logits_func_ : GenerationCpuDeviceHelper::GreedySearchProcessLogits, init_greedy_state_func_ ? init_greedy_state_func_ : GenerationCpuDeviceHelper::InitGreedyState, device_copy_func_ ? device_copy_func_ : GenerationCpuDeviceHelper::DeviceCopy, - update_gpt_feeds_func_ ? update_gpt_feeds_func_ : GenerationCpuDeviceHelper::UpdateGptFeeds, - cuda_device_prop_, - cuda_device_arch_}; + update_gpt_feeds_func_ ? update_gpt_feeds_func_ : GenerationCpuDeviceHelper::UpdateGptFeeds}; +#ifdef USE_CUDA + ORT_RETURN_IF_ERROR(impl.InitializeCuda(reorder_past_state_func_, cuda_device_prop_, cuda_device_arch_)); +#endif ORT_RETURN_IF_ERROR(impl.Initialize()); return impl.Execute(init_run_decoder_feeds_fetches_manager_, *decoder_feeds_fetches_manager_); @@ -222,14 +222,14 @@ Status GreedySearch::Compute(OpKernelContext* ctx) const { parameters, GenerationCpuDeviceHelper::CreateGptInputs, add_to_feeds_func_ ? add_to_feeds_func_ : GenerationCpuDeviceHelper::AddToFeeds, - reorder_past_state_func_ ? reorder_past_state_func_ : nullptr, // Only CUDA implementation needs the reorder helper for now topk_func_ ? topk_func_ : GenerationCpuDeviceHelper::TopK, process_logits_fp16_func_, init_greedy_state_fp16_func_, device_copy_func_, - update_gpt_feeds_fp16_func_, - cuda_device_prop_, - cuda_device_arch_}; + update_gpt_feeds_fp16_func_}; +#ifdef USE_CUDA + ORT_RETURN_IF_ERROR(impl.InitializeCuda(reorder_past_state_func_, cuda_device_prop_, cuda_device_arch_)); +#endif ORT_RETURN_IF_ERROR(impl.Initialize()); return impl.Execute(init_run_decoder_feeds_fetches_manager_, *decoder_feeds_fetches_manager_); diff --git a/onnxruntime/contrib_ops/cpu/transformers/greedy_search.h b/onnxruntime/contrib_ops/cpu/transformers/greedy_search.h index 0faaf25c041f1..a065255766e31 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/greedy_search.h +++ b/onnxruntime/contrib_ops/cpu/transformers/greedy_search.h @@ -44,7 +44,6 @@ class GreedySearch : public IControlFlowKernel { // device helpers that is same for both GPT and encoder-decoder models. void SetDeviceHelpers( - const GenerationDeviceHelper::ReorderPastStateFunc& reorder_past_state_func, const GenerationDeviceHelper::AddToFeedsFunc& add_to_feeds_func, const GenerationDeviceHelper::TopkFunc& topk_func, const GenerationDeviceHelper::DeviceCopyFunc& device_copy_func, @@ -52,7 +51,6 @@ class GreedySearch : public IControlFlowKernel { const GenerationDeviceHelper::GreedySearchProcessLogitsFunc& process_logits_fp16_func, const GenerationDeviceHelper::InitGreedyStateFunc& init_greedy_state_func, const GenerationDeviceHelper::InitGreedyStateFunc& init_greedy_state_fp16_func) { - reorder_past_state_func_ = reorder_past_state_func; add_to_feeds_func_ = add_to_feeds_func; topk_func_ = topk_func; device_copy_func_ = device_copy_func; @@ -62,6 +60,12 @@ class GreedySearch : public IControlFlowKernel { init_greedy_state_fp16_func_ = init_greedy_state_fp16_func; } +#ifdef USE_CUDA + void SetDeviceHelpers_Cuda(const GenerationDeviceHelper::ReorderPastStateFunc& reorder_past_state_func) { + reorder_past_state_func_ = reorder_past_state_func; + } +#endif + void SetDeviceHelpers_Gpt( const GenerationDeviceHelper::UpdateGptFeedsFunc& update_gpt_feeds_func, const GenerationDeviceHelper::UpdateGptFeedsFunc& update_gpt_feeds_fp16_func) { @@ -69,12 +73,13 @@ class GreedySearch : public IControlFlowKernel { update_gpt_feeds_fp16_func_ = update_gpt_feeds_fp16_func; } +#ifdef USE_CUDA const void* cuda_device_prop_ = nullptr; int cuda_device_arch_ = 0; +#endif private: // Device specific functions - GenerationDeviceHelper::ReorderPastStateFunc reorder_past_state_func_; GenerationDeviceHelper::AddToFeedsFunc add_to_feeds_func_; GenerationDeviceHelper::TopkFunc topk_func_; GenerationDeviceHelper::DeviceCopyFunc device_copy_func_; @@ -85,6 +90,10 @@ class GreedySearch : public IControlFlowKernel { GenerationDeviceHelper::InitGreedyStateFunc init_greedy_state_func_; GenerationDeviceHelper::InitGreedyStateFunc init_greedy_state_fp16_func_; +#ifdef USE_CUDA + GenerationDeviceHelper::ReorderPastStateFunc reorder_past_state_func_; +#endif + //------------------------------------------------------------ // Device specific functions for GPT //------------------------------------------------------------ diff --git a/onnxruntime/contrib_ops/cpu/transformers/greedy_search_impl_base.h b/onnxruntime/contrib_ops/cpu/transformers/greedy_search_impl_base.h index 4fd3370040723..be974ed2159d9 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/greedy_search_impl_base.h +++ b/onnxruntime/contrib_ops/cpu/transformers/greedy_search_impl_base.h @@ -205,14 +205,16 @@ class GreedySearchBase : public GenerateBase { template Status GreedySearchBase::CheckInputs(const OpKernelContextInternal& context) { // Input shapes: - // input_ids : (batch_size, sequence_length) - // vocab_mask : (vocab_size) or nullptr + // input_ids : (batch_size, sequence_length) + // vocab_mask : (vocab_size) or nullptr + // decoder_input_ids : (batch_size, initial_decode_sequence_length) ORT_RETURN_IF_ERROR(this->CheckInputsImpl(parameters_, - context.Input(0), // input_ids - context.Input(4), // vocab_mask - context.Input(5), // prefix_vocab_mask - context.Input(6), // attention_mask - context.Input(7))); // presence_mask + context.Input(0), // input_ids + context.Input(4), // vocab_mask + context.Input(5), // prefix_vocab_mask + context.Input(6), // attention_mask + context.Input(7), // presence_mask + context.Input(10))); // decoder_input_ids return Status::OK(); } diff --git a/onnxruntime/contrib_ops/cpu/transformers/greedy_search_impl_gpt.h b/onnxruntime/contrib_ops/cpu/transformers/greedy_search_impl_gpt.h index f1acaf878ed06..4504b099e32bd 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/greedy_search_impl_gpt.h +++ b/onnxruntime/contrib_ops/cpu/transformers/greedy_search_impl_gpt.h @@ -38,14 +38,11 @@ class GreedySearchGpt : public GreedySearchBase { ParametersT& params, const GenerationDeviceHelper::CreateGptInputsFunc& create_inputs_func, const GenerationDeviceHelper::AddToFeedsFunc& add_to_feeds_func, - const GenerationDeviceHelper::ReorderPastStateFunc& reorder_past_state_func, const GenerationDeviceHelper::TopkFunc& topk_func, const GenerationDeviceHelper::GreedySearchProcessLogitsFunc& process_logits_func, const GenerationDeviceHelper::InitGreedyStateFunc& init_greedy_state_func, const GenerationDeviceHelper::DeviceCopyFunc& device_copy_func, - const GenerationDeviceHelper::UpdateGptFeedsFunc& update_feeds_func, - const void* cuda_device_prop, - int cuda_device_arch) + const GenerationDeviceHelper::UpdateGptFeedsFunc& update_feeds_func) : GreedySearchBase(context, decoder_session_state, thread_pool, @@ -61,18 +58,26 @@ class GreedySearchGpt : public GreedySearchBase { create_inputs_func_(create_inputs_func), add_to_feeds_func_(add_to_feeds_func), init_greedy_state_func_(init_greedy_state_func), - reorder_past_state_func_(reorder_past_state_func), - update_feeds_func_(update_feeds_func), - cuda_device_prop_(cuda_device_prop), - cuda_device_arch_(cuda_device_arch) { + update_feeds_func_(update_feeds_func) {} + +#ifdef USE_CUDA + Status InitializeCuda( + const GenerationDeviceHelper::ReorderPastStateFunc& reorder_past_state_func, + const void* cuda_device_prop, + int cuda_device_arch) { + reorder_past_state_func_ = reorder_past_state_func; + cuda_device_prop_ = cuda_device_prop; + cuda_device_arch_ = cuda_device_arch; if (gpt_subgraph_.has_decoder_masked_attention_) { - ORT_ENFORCE(cuda_device_arch_ >= 530, - "Decoder masked self attention can only be used on " - "GPU cards of compute capability 5.3 or higher. " - "This card has compute capability ", - cuda_device_arch_); + ORT_RETURN_IF_NOT(cuda_device_arch_ >= 530, + "Decoder masked self attention can only be used on " + "GPU cards of compute capability 5.3 or higher. " + "This card has compute capability ", + cuda_device_arch_); } + return Status::OK(); } +#endif // Execute beam search in iterations util stopping criteria is reached. // In each iteration, GPT subgraph is called, and next token for each sequence is generated. @@ -104,7 +109,9 @@ class GreedySearchGpt : public GreedySearchBase { GenerationDeviceHelper::CreateGptInputsFunc create_inputs_func_; GenerationDeviceHelper::AddToFeedsFunc add_to_feeds_func_; GenerationDeviceHelper::InitGreedyStateFunc init_greedy_state_func_; +#ifdef USE_CUDA GenerationDeviceHelper::ReorderPastStateFunc reorder_past_state_func_; +#endif GenerationDeviceHelper::UpdateGptFeedsFunc update_feeds_func_; const void* cuda_device_prop_ = nullptr; @@ -222,7 +229,7 @@ Status GreedySearchGpt::Execute(const FeedsFetchesManager* init_ ORT_RETURN_IF_ERROR(CreateInitialFeeds(greedy_state.sequence_lengths, expanded_input_ids_in_cpu, feeds, buffer)); if (gpt_subgraph_.past_present_share_buffer_) { // Reuse past and present - fetches.reserve((int64_t)gpt_subgraph_.GetFirstPresentOutputIndex() + gpt_subgraph_.num_layers); + fetches.reserve(static_cast(gpt_subgraph_.GetFirstPresentOutputIndex()) + gpt_subgraph_.num_layers); fetches.resize(gpt_subgraph_.GetFirstPresentOutputIndex(), OrtValue()); for (int layer = 0; layer < gpt_subgraph_.num_layers; layer++) { int feed_idx = gpt_subgraph_.GetFirstPastInputIndex() + layer; @@ -329,6 +336,7 @@ Status GreedySearchGpt::Execute(const FeedsFetchesManager* init_ // Increase sequence length after a new token is generated. ++current_length; +#ifdef USE_CUDA // Reorder past state after first run if the GPT subgraph (the one used after the first iteration) // contains DecoderMaskedSelfAttention nodes if (iteration_counter == 1 && gpt_subgraph_.has_decoder_masked_attention_) { @@ -345,6 +353,7 @@ Status GreedySearchGpt::Execute(const FeedsFetchesManager* init_ this->ort_stream_)); } } +#endif // Prepare inputs for next round of subgraph call. if (current_length < parameters->max_length) { diff --git a/onnxruntime/contrib_ops/cpu/transformers/logits_processor.cc b/onnxruntime/contrib_ops/cpu/transformers/logits_processor.cc index d0641fedf978e..9f77c32f0c7cc 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/logits_processor.cc +++ b/onnxruntime/contrib_ops/cpu/transformers/logits_processor.cc @@ -238,6 +238,128 @@ void PresencePenaltyLogitsProcessor::Process(const ISequences*, #endif } +template +TimestampLogitsProcessor::TimestampLogitsProcessor(int eos_token_id, int max_initial_timestamp_index) + : eos_token_id_(eos_token_id), max_initial_timestamp_index_(max_initial_timestamp_index) {} + +template +void TimestampLogitsProcessor::Process(const ISequences* sequences, + NextTokenScores& next_token_scores) { + const int beg_token_id_ = eos_token_id_ + 107; + const int not_token_id_ = eos_token_id_ + 106; + const int solm_token_id_ = eos_token_id_ + 105; + const int sot_token_id_ = eos_token_id_ + 1; + constexpr int translate_token_id_ = 50358; + constexpr int transcribe_token_id_ = 50359; + + const int batch_beam_size = next_token_scores.batch_beam_size; + const int vocab_size = next_token_scores.vocab_size; + for (int i = 0; i < batch_beam_size; i++) { + gsl::span beam_token_scores = next_token_scores.GetScores(i); + gsl::span sequence = sequences->GetSequence(i); + const size_t seq_length = sequence.size(); + + // Find first timestamp + size_t sample_begin = 0; + for (size_t j = 0; j < seq_length; j++) { + sample_begin++; + if (sequence[j] >= beg_token_id_) { + break; + } + } + + // Suppress tokens + for (int j = 0; j < vocab_size; j++) { + // Suppress notimestamps and solm tokens + if (j == not_token_id_ || j == solm_token_id_) { + beam_token_scores[j] = std::numeric_limits::lowest(); + } + + // Suppress sot, translate and transcribe tokens + if (seq_length > sample_begin) { + if (j == sot_token_id_ || j == translate_token_id_ || j == transcribe_token_id_) { + beam_token_scores[j] = std::numeric_limits::lowest(); + } + } + } + + // Timestamps should be in pair except the first one + const bool last_was_timestamp = seq_length > 0 && sequence.back() >= beg_token_id_; + const bool penultimate_was_timestamp = seq_length <= sample_begin || sequence[seq_length - 2] >= beg_token_id_; + if (last_was_timestamp) { + if (penultimate_was_timestamp) { + // If timestamps show up in pair, or it's the first timestamp, no more timestamp is generated + for (int j = beg_token_id_; j < vocab_size; j++) { + beam_token_scores[j] = std::numeric_limits::lowest(); + } + } else { + // If timestamp doesn't show up in pair, generate timestamp + for (int j = 0; j < eos_token_id_; j++) { + beam_token_scores[j] = std::numeric_limits::lowest(); + } + } + } + + // Find timestamp tokens + std::vector timestamps; + for (const auto& word_id : sequence) { + if (word_id >= beg_token_id_) { + timestamps.push_back(word_id); + } + } + + // Timestamps will not decrease + const size_t timestamps_len = timestamps.size(); + if (timestamps_len > 0) { + int timestamp_last = 0; + if (last_was_timestamp && !penultimate_was_timestamp) { + // For single timestamp at the end, next timestamp must not be smaller + timestamp_last = timestamps.back(); + } else { + // For paired timestamp at the end, next timestamp must be greater + timestamp_last = timestamps.back() + 1; + } + + for (int j = beg_token_id_; j < timestamp_last; j++) { + beam_token_scores[j] = std::numeric_limits::lowest(); + } + } + + if (seq_length == sample_begin) { + const int last_allowed = beg_token_id_ + max_initial_timestamp_index_; + for (int j = last_allowed + 1; j < vocab_size; j++) { + beam_token_scores[j] = std::numeric_limits::lowest(); + } + } + + // Caculate logsumexp on timestamps + float timestamp_logprob = std::numeric_limits::lowest(); + { + float logsumexp = 0.0f; + const float logprob_max = *std::max_element(beam_token_scores.begin() + beg_token_id_, beam_token_scores.end()); + for (int j = beg_token_id_; j < vocab_size; ++j) { + if (beam_token_scores[j] > std::numeric_limits::lowest()) { + logsumexp += expf(beam_token_scores[j] - logprob_max); + } + } + if (logsumexp > 0.0f) { + timestamp_logprob = logf(logsumexp) + logprob_max; + } + } + + const float max_text_token_logprob = *std::max_element(beam_token_scores.begin(), beam_token_scores.begin() + beg_token_id_); + if (timestamp_logprob > max_text_token_logprob) { + for (int j = 0; j < beg_token_id_; ++j) { + beam_token_scores[j] = std::numeric_limits::lowest(); + } + } + } + +#ifdef DEBUG_GENERATION + DumpScores("TimestampLogitsProcessor", next_token_scores); +#endif +} + void LogitsProcessorList::Init(const BeamSearchParameters& parameters) { LogitsProcessorInitImpl(parameters); } diff --git a/onnxruntime/contrib_ops/cpu/transformers/logits_processor.h b/onnxruntime/contrib_ops/cpu/transformers/logits_processor.h index 49a2a5bb324a6..664c497a106d4 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/logits_processor.h +++ b/onnxruntime/contrib_ops/cpu/transformers/logits_processor.h @@ -138,6 +138,19 @@ class PresencePenaltyLogitsProcessor : public ILogitsProcessor { float presence_penalty_; }; +template +class TimestampLogitsProcessor : public ILogitsProcessor { + public: + TimestampLogitsProcessor(int eos_token_id, int max_initial_timestamp_index); + + void Process(const ISequences* sequences, + NextTokenScores& next_token_scores) override; + + private: + int eos_token_id_; + int max_initial_timestamp_index_; +}; + class LogitsProcessorList : public ILogitsProcessorList { public: LogitsProcessorList() = default; @@ -193,6 +206,13 @@ class LogitsProcessorList : public ILogitsProcessorList { processor_list_.push_back(presence_penalty_processor_.get()); } + // Add timestamp processor for whisper model + if (parameters.model_type == IGenerationParameters::kModelTypeWhisper && parameters.logits_processor == IGenerationParameters::kLogitsProcessorTypeWhisper) { + constexpr int max_initial_timestamp_index = 50; + timestamp_processor_ = std::make_unique>(parameters.eos_token_id, max_initial_timestamp_index); + processor_list_.push_back(timestamp_processor_.get()); + } + batch_beam_size_ = parameters.BatchBeamSize(); vocab_size_ = parameters.vocab_size; } @@ -208,6 +228,7 @@ class LogitsProcessorList : public ILogitsProcessorList { std::unique_ptr> min_length_processor_; std::unique_ptr> temperature_processor_; std::unique_ptr> presence_penalty_processor_; + std::unique_ptr> timestamp_processor_; }; } // namespace transformers diff --git a/onnxruntime/contrib_ops/cpu/transformers/sampling.cc b/onnxruntime/contrib_ops/cpu/transformers/sampling.cc index 9c1b432c53deb..101b059848908 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/sampling.cc +++ b/onnxruntime/contrib_ops/cpu/transformers/sampling.cc @@ -134,14 +134,14 @@ Status Sampling::Compute(OpKernelContext* ctx) const { parameters, GenerationCpuDeviceHelper::CreateGptInputs, add_to_feeds_func_ ? add_to_feeds_func_ : GenerationCpuDeviceHelper::AddToFeeds, - reorder_past_state_func_ ? reorder_past_state_func_ : nullptr, // Only CUDA implementation needs the reorder helper for now topk_func_ ? topk_func_ : GenerationCpuDeviceHelper::TopK, process_logits_func_ ? process_logits_func_ : GenerationCpuDeviceHelper::GreedySearchProcessLogits, init_greedy_state_func_ ? init_greedy_state_func_ : GenerationCpuDeviceHelper::InitGreedyState, device_copy_func_ ? device_copy_func_ : GenerationCpuDeviceHelper::DeviceCopy, - update_gpt_feeds_func_ ? update_gpt_feeds_func_ : GenerationCpuDeviceHelper::UpdateGptFeeds, - gpu_device_prop_, - gpu_device_arch_}; + update_gpt_feeds_func_ ? update_gpt_feeds_func_ : GenerationCpuDeviceHelper::UpdateGptFeeds}; +#ifdef USE_CUDA + ORT_RETURN_IF_ERROR(impl.InitializeCuda(reorder_past_state_func_, gpu_device_prop_, gpu_device_arch_)); +#endif ORT_RETURN_IF_ERROR(impl.Initialize()); return impl.Execute(init_run_decoder_feeds_fetches_manager_, *decoder_feeds_fetches_manager_); @@ -158,15 +158,14 @@ Status Sampling::Compute(OpKernelContext* ctx) const { parameters, GenerationCpuDeviceHelper::CreateGptInputs, add_to_feeds_func_ ? add_to_feeds_func_ : GenerationCpuDeviceHelper::AddToFeeds, - reorder_past_state_func_ ? reorder_past_state_func_ : nullptr, // Only CUDA implementation needs the reorder helper for now topk_func_ ? topk_func_ : GenerationCpuDeviceHelper::TopK, process_logits_fp16_func_, init_greedy_state_fp16_func_, device_copy_func_, - update_gpt_feeds_fp16_func_, - gpu_device_prop_, - gpu_device_arch_}; - + update_gpt_feeds_fp16_func_}; +#ifdef USE_CUDA + ORT_RETURN_IF_ERROR(impl.InitializeCuda(reorder_past_state_func_, gpu_device_prop_, gpu_device_arch_)); +#endif ORT_RETURN_IF_ERROR(impl.Initialize()); return impl.Execute(init_run_decoder_feeds_fetches_manager_, *decoder_feeds_fetches_manager_); diff --git a/onnxruntime/contrib_ops/cpu/transformers/sampling.h b/onnxruntime/contrib_ops/cpu/transformers/sampling.h index 87f04bf615217..8f048921a68e0 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/sampling.h +++ b/onnxruntime/contrib_ops/cpu/transformers/sampling.h @@ -41,7 +41,6 @@ class Sampling : public IControlFlowKernel { // device helpers that is same for both GPT and encoder-decoder models. void SetDeviceHelpers( - const GenerationDeviceHelper::ReorderPastStateFunc& reorder_past_state_func, const GenerationDeviceHelper::AddToFeedsFunc& add_to_feeds_func, const GenerationDeviceHelper::TopkFunc& topk_func, const GenerationDeviceHelper::DeviceCopyFunc& device_copy_func, @@ -49,7 +48,6 @@ class Sampling : public IControlFlowKernel { const GenerationDeviceHelper::GreedySearchProcessLogitsFunc& process_logits_fp16_func, const GenerationDeviceHelper::InitGreedyStateFunc& init_greedy_state_func, const GenerationDeviceHelper::InitGreedyStateFunc& init_greedy_state_fp16_func) { - reorder_past_state_func_ = reorder_past_state_func; add_to_feeds_func_ = add_to_feeds_func; topk_func_ = topk_func; device_copy_func_ = device_copy_func; @@ -59,6 +57,12 @@ class Sampling : public IControlFlowKernel { init_greedy_state_fp16_func_ = init_greedy_state_fp16_func; } +#ifdef USE_CUDA + void SetDeviceHelpers_Cuda(const GenerationDeviceHelper::ReorderPastStateFunc& reorder_past_state_func) { + reorder_past_state_func_ = reorder_past_state_func; + } +#endif + void SetDeviceHelpers_Gpt( const GenerationDeviceHelper::UpdateGptFeedsFunc& update_gpt_feeds_func, const GenerationDeviceHelper::UpdateGptFeedsFunc& update_gpt_feeds_fp16_func) { @@ -66,12 +70,13 @@ class Sampling : public IControlFlowKernel { update_gpt_feeds_fp16_func_ = update_gpt_feeds_fp16_func; } +#ifdef USE_CUDA const void* gpu_device_prop_ = nullptr; int gpu_device_arch_ = 0; +#endif private: // Device specific functions - GenerationDeviceHelper::ReorderPastStateFunc reorder_past_state_func_; GenerationDeviceHelper::AddToFeedsFunc add_to_feeds_func_; GenerationDeviceHelper::TopkFunc topk_func_; GenerationDeviceHelper::DeviceCopyFunc device_copy_func_; @@ -82,6 +87,10 @@ class Sampling : public IControlFlowKernel { GenerationDeviceHelper::InitGreedyStateFunc init_greedy_state_func_; GenerationDeviceHelper::InitGreedyStateFunc init_greedy_state_fp16_func_; +#ifdef USE_CUDA + GenerationDeviceHelper::ReorderPastStateFunc reorder_past_state_func_; +#endif + //------------------------------------------------------------ // Device specific functions for GPT //------------------------------------------------------------ diff --git a/onnxruntime/contrib_ops/cpu/transformers/sequences.cc b/onnxruntime/contrib_ops/cpu/transformers/sequences.cc index a42aa47bfde63..723c271897a78 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/sequences.cc +++ b/onnxruntime/contrib_ops/cpu/transformers/sequences.cc @@ -22,12 +22,14 @@ void Sequences::Init(gsl::span buffer, int batch_beam_size, int sequenc current_length_ = sequence_length; } +void Sequences::InitDevice(gsl::span buffer) { + device_sequences[0] = buffer.subspan(0, buffer.size() / 2); + device_sequences[1] = buffer.subspan(buffer.size() / 2); +} + gsl::span Sequences::GetSequence(int beam_index) const { - gsl::span buffer(sequences[current_sequences_buffer].data(), - sequences[current_sequences_buffer].size()); - gsl::span sequence = buffer.subspan(SafeInt(beam_index) * max_length_, - static_cast(current_length_)); - return sequence; + gsl::span buffer = sequences[current_sequences_buffer]; + return buffer.subspan(SafeInt(beam_index) * max_length_, static_cast(current_length_)); } int Sequences::GetSequenceLength() const { @@ -47,9 +49,8 @@ void Sequences::PrintSequences(const IConsoleDumper* dumper) const { void Sequences::AppendNextTokenToSequences( gsl::span& beam_indices, gsl::span& beam_next_tokens) { - gsl::span input(sequences[current_sequences_buffer].data(), - sequences[current_sequences_buffer].size()); - gsl::span output = sequences[1 - current_sequences_buffer]; + gsl::span input = sequences[current_sequences_buffer]; + gsl::span output = sequences[current_sequences_buffer ^ 1]; for (int i = 0; i < batch_beam_size_; i++) { int beam_index = beam_indices[i]; @@ -58,22 +59,19 @@ void Sequences::AppendNextTokenToSequences( gsl::span target = output.subspan(SafeInt(i) * max_length_, static_cast(current_length_)); gsl::copy(source, target); - } - // Append next token to each beam. - for (int i = 0; i < batch_beam_size_; i++) { + // Append next token to each beam. output[SafeInt(i) * max_length_ + current_length_] = beam_next_tokens[i]; } ++current_length_; // Rotate buffer for next round. - current_sequences_buffer = 1 - current_sequences_buffer; + current_sequences_buffer ^= 1; } -void Sequences::AppendNextTokenToSequences( - gsl::span& next_tokens) { - gsl::span output(sequences[current_sequences_buffer].data(), sequences[current_sequences_buffer].size()); +void Sequences::AppendNextTokenToSequences(gsl::span& next_tokens) { + auto output = sequences[0]; // Append next token to each sequence. for (int i = 0; i < batch_beam_size_; i++) { @@ -83,6 +81,11 @@ void Sequences::AppendNextTokenToSequences( ++current_length_; } +void Sequences::AfterDeviceAppendedNextToken() { + ++current_length_; + current_sequences_buffer ^= 1; +} + } // namespace transformers } // namespace contrib } // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cpu/transformers/sequences.h b/onnxruntime/contrib_ops/cpu/transformers/sequences.h index cd7b714028ed7..99c9474a2ca4d 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/sequences.h +++ b/onnxruntime/contrib_ops/cpu/transformers/sequences.h @@ -13,13 +13,14 @@ namespace transformers { // This class keeps track of sequences generated. class Sequences : public ISequences { public: - Sequences() {} - // Initialize the sequence. void Init(gsl::span buffer, int batch_beam_size, int sequence_length, int max_length); + void InitDevice(gsl::span buffer); // Returns a sequence of word IDs for a given beam index ( beam_index < batch_beam_size). gsl::span GetSequence(int beam_index) const override; + gsl::span GetCurrentDeviceSequences() const override { return device_sequences[current_sequences_buffer]; } + gsl::span GetNextDeviceSequences() override { return device_sequences[current_sequences_buffer ^ 1]; } // Returns current sequence length. int GetSequenceLength() const override; @@ -37,11 +38,14 @@ class Sequences : public ISequences { void AppendNextTokenToSequences( gsl::span& next_tokens); + void AfterDeviceAppendedNextToken(); + private: // Two buffers of shape (batch_size, num_beams, max_seq_length) to store sequences. // At each time, there is only one buffer is active. The other one will be active in next token. // Each AppendNextTokenToSequences call will trigger a rotation of active buffer. gsl::span sequences[2]; + gsl::span device_sequences[2]; // Index (either 0 or 1) of two buffers that is currently is active. int current_sequences_buffer; diff --git a/onnxruntime/contrib_ops/cpu/transformers/subgraph_base.cc b/onnxruntime/contrib_ops/cpu/transformers/subgraph_base.cc index 5f0d1db87bef3..5f9d48fe5094a 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/subgraph_base.cc +++ b/onnxruntime/contrib_ops/cpu/transformers/subgraph_base.cc @@ -68,8 +68,7 @@ Status Subgraph::Setup(const SessionState& session_state, feed_names.reserve(static_cast(num_subgraph_inputs) + static_cast(num_implicit_inputs)); // Use the first output (logits) to find device location. - const OrtMemoryInfo& default_location = utils::FindMemoryInfoForValue(subgraph_session_state, - subgraph_output_names[0]); + 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()); @@ -83,8 +82,8 @@ Status Subgraph::Setup(const SessionState& session_state, for (size_t i = 0, end = feed_names.size(); i < end; ++i) { if (i >= subgraph_input_names.size()) { // Implicit inputs - const auto& location = utils::FindMemoryInfoForValue(session_state, feed_names[i]); - feed_locations.push_back(location.device); + const auto& location = utils::FindDeviceForValue(session_state, feed_names[i]); + feed_locations.push_back(location); } else { if (feed_names[i] == "past_sequence_length") { // when past_sequence_length is needed in subgraph, treat it as past_present_share_buffer @@ -95,7 +94,7 @@ Status Subgraph::Setup(const SessionState& session_state, // beam_width is on CPU memory feed_locations.push_back(OrtDevice()); } else { - feed_locations.push_back(default_location.device); + feed_locations.push_back(default_location); } } } @@ -105,7 +104,7 @@ Status Subgraph::Setup(const SessionState& session_state, ORT_RETURN_IF_ERROR(utils::InitializeFeedFetchCopyInfo(subgraph_session_state, *feeds_fetches_manager_)); // Setup the locations where we want the subgraph output to end up on - InlinedVector fetch_locations; + InlinedVector fetch_locations; fetch_locations.reserve(num_subgraph_outputs); // Past state need to be where we can feed them in to the next iteration, so set the location to match the feed. @@ -119,7 +118,6 @@ Status Subgraph::Setup(const SessionState& session_state, auto& inputs = subgraph.GetInputs(); auto& outputs = subgraph.GetOutputs(); ORT_RETURN_IF_ERROR(Validate(inputs, outputs)); - return Status::OK(); } diff --git a/onnxruntime/contrib_ops/cpu/transformers/subgraph_gpt.cc b/onnxruntime/contrib_ops/cpu/transformers/subgraph_gpt.cc index 55a7654931646..b07d485577919 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/subgraph_gpt.cc +++ b/onnxruntime/contrib_ops/cpu/transformers/subgraph_gpt.cc @@ -47,7 +47,7 @@ Status GptSubgraph::CreateInitialFeeds( AllocatorPtr cpu_allocator = session_state_->GetAllocator(input_ids.Location()); // Store allocator, which will be used in remaining feeds - auto default_allocator = provider->GetAllocator(OrtMemTypeDefault); + auto default_allocator = session_state_->GetAllocator(provider->GetOrtDeviceByMemType(OrtMemTypeDefault)); allocator_ = default_allocator; // The ordering is the same as used in Setup @@ -65,17 +65,20 @@ Status GptSubgraph::CreateInitialFeeds( expanded_position_ids, expanded_attention_mask)); - ORT_RETURN_IF_ERROR(add_to_feeds_func(provider, - ort_stream, + 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, {expanded_input_ids, expanded_position_ids, expanded_attention_mask}, feeds, - buffer)); + buffer, + default_allocator, + pinned_allocator, + location)); auto past_type = IsOutputFloat16() ? DataTypeImpl::GetType() : DataTypeImpl::GetType(); if (!past_present_share_buffer_) { // Initialize empty past state - int64_t past_state_dims[] = {2, batch_size * num_beams, num_heads, 0, head_size}; - TensorShape past_shape(&past_state_dims[0], 5); + TensorShape past_shape{2, batch_size * num_beams, num_heads, 0, head_size}; OrtValue empty_past; Tensor::InitOrtValue(past_type, past_shape, default_allocator, empty_past); @@ -85,8 +88,7 @@ Status GptSubgraph::CreateInitialFeeds( } } else { // Past state feeds - int64_t past_state_dims[] = {2, batch_size * num_beams, num_heads, past_present_share_buffer_max_seq_len, head_size}; - TensorShape past_shape(&past_state_dims[0], 5); + TensorShape past_shape{2, batch_size * num_beams, num_heads, past_present_share_buffer_max_seq_len, head_size}; // The remaining inputs are past state except the last one or three (see below for details) // If `need_cache_indir` is false, then the last input is `past_sequence_length` diff --git a/onnxruntime/contrib_ops/cpu/transformers/subgraph_t5_decoder.h b/onnxruntime/contrib_ops/cpu/transformers/subgraph_t5_decoder.h index 408eddd707fc3..085d8f3903976 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/subgraph_t5_decoder.h +++ b/onnxruntime/contrib_ops/cpu/transformers/subgraph_t5_decoder.h @@ -66,7 +66,7 @@ class T5DecoderSubgraph : public Subgraph { return use_sequence_as_input_ids_; } - private: + protected: int first_past_input_index_; int first_present_output_index_; bool has_hidden_state_; diff --git a/onnxruntime/contrib_ops/cpu/transformers/subgraph_t5_encoder.cc b/onnxruntime/contrib_ops/cpu/transformers/subgraph_t5_encoder.cc index 79532f79f4ef4..887a2b5cc5196 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/subgraph_t5_encoder.cc +++ b/onnxruntime/contrib_ops/cpu/transformers/subgraph_t5_encoder.cc @@ -116,7 +116,7 @@ Status T5EncoderSubgraph::CreateInitialFeeds( AllocatorPtr cpu_allocator = session_state_->GetAllocator(original_encoder_input_ids.Location()); if (cpu_allocator == nullptr) { const IExecutionProvider* provider = GetProvider(); - cpu_allocator = provider->GetAllocator(OrtMemTypeDefault); + cpu_allocator = session_state_->GetAllocator(provider->GetOrtDeviceByMemType(OrtMemTypeDefault)); } ORT_RETURN_IF(cpu_allocator == nullptr, "cpu_allocator shouldn't be nullptr"); @@ -133,12 +133,17 @@ Status T5EncoderSubgraph::CreateInitialFeeds( decoder_input_ids)); const IExecutionProvider* provider = GetProvider(); + 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( - provider, ort_stream, {encoder_input_ids, encoder_attention_mask, decoder_input_ids}, feeds, - buffer)); + buffer, + default_allocator, + pinned_allocator, + location)); for (const auto* entry : implicit_inputs) { feeds.push_back(*entry); diff --git a/onnxruntime/contrib_ops/cpu/transformers/subgraph_whisper_decoder.cc b/onnxruntime/contrib_ops/cpu/transformers/subgraph_whisper_decoder.cc new file mode 100644 index 0000000000000..887a6a8984b83 --- /dev/null +++ b/onnxruntime/contrib_ops/cpu/transformers/subgraph_whisper_decoder.cc @@ -0,0 +1,275 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/framework/framework_common.h" +#include "core/framework/session_state.h" +#include "core/framework/tensorprotoutils.h" +#include "core/framework/utils.h" +#include "core/providers/cpu/tensor/utils.h" +#include "core/common/gsl.h" +#include "contrib_ops/cpu/transformers/subgraph_t5_decoder.h" +#include "contrib_ops/cpu/transformers/subgraph_whisper_decoder.h" +#include "contrib_ops/cpu/transformers/dump_tensor.h" +#include "contrib_ops/cpu/transformers/generation_device_helper.h" +#include "contrib_ops/cpu/transformers/sequences.h" + +namespace onnxruntime { +namespace contrib { +namespace transformers { + +/* Whisper Decoder Subgraph. + + Inputs: + input_ids: int32 (B, 1) + encoder_hidden_states: (B, encode_sequence_length, encoder_hidden_size) + + 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) + ... (for each self attention layer) + + past_key_cross_0: (B, num_heads, encode_sequence_length, head_size) + past_value_cross_0: (B, num_heads, encode_sequence_length, head_size) + ... (for each cross attention layer) + + past_seq_len: int32 (1) - the length of past sequence(optional) + num_beams: int32 (1) - the number of beams(optional) + cache_indirection: int32 (B, num_beams, max_seq_length) - the cache indirection(optional) + + Outputs: + logits: (B, 1, vocab_size) + + present_key_self_0: (B, num_heads, past_decode_sequence_length + 1, head_size) + present_value_self_0: (B, num_heads, past_decode_sequence_length + 1, head_size) + ... (for each self attention layer) + + Note: + B = batch_size * num_beams + Data type of input or output is float or float16 if not specified. +*/ + +Status WhisperDecoderSubgraph::Validate(const std::vector& subgraph_inputs, + const std::vector& subgraph_outputs) { + bool has_hidden_state = subgraph_inputs[1]->Name() == "encoder_hidden_states" ? true : false; + SetPastInputIndex(has_hidden_state); + + ORT_RETURN_IF(first_past_input_index_ != 1 && first_past_input_index_ != 2, + "kFirstPastInputIndex currently only supports 1 or 2"); + + if (!past_present_share_buffer_) { + ORT_RETURN_IF(has_decoder_masked_attention_, "decoder_masked_attention shall use with past_present_share_buffer"); + ORT_RETURN_IF(num_subgraph_inputs < 4 + first_past_input_index_ || + (num_subgraph_inputs - first_past_input_index_) % 4 != 0, + "number of inputs expected to be kFirstPastInputIndex + 4 * layers, got:", num_subgraph_inputs); + } else if (has_decoder_masked_attention_) { + ORT_RETURN_IF(num_subgraph_inputs < 7 + first_past_input_index_ || + (num_subgraph_inputs - first_past_input_index_ - 3) % 4 != 0, + "number of inputs expected to be kFirstPastInputIndex + 4 * layers + 3, got:", num_subgraph_inputs); + } else { + ORT_RETURN_IF(num_subgraph_inputs < 5 + first_past_input_index_ || + (num_subgraph_inputs - first_past_input_index_ - 1) % 4 != 0, + "number of inputs expected to be kFirstPastInputIndex + 4 * layers + 1, got:", num_subgraph_inputs); + } + + ORT_RETURN_IF(num_subgraph_outputs < 3 || (num_subgraph_outputs - first_present_output_index_) % 2 != 0, + "number of outputs expected to be 1 + 2 * layers, got:", num_subgraph_outputs); + + ORT_RETURN_IF(subgraph_inputs[0]->Name() != "input_ids", + "decoder subgraph input 0 shall be named as input_ids, got: ", subgraph_inputs[0]->Name()); + if (first_past_input_index_ == 2) { + ORT_RETURN_IF(subgraph_inputs[1]->Name() != "encoder_hidden_states", + "decoder subgraph input 1 shall be named as encoder_hidden_states, got: ", + subgraph_inputs[1]->Name()); + } + + // check subgraph outputs + ORT_RETURN_IF(subgraph_outputs[0]->Name() != "logits", + "decoder subgraph output 0 shall be named as logits, got: ", subgraph_outputs[0]->Name()); + + const ONNX_NAMESPACE::TensorShapeProto* logits_shape = subgraph_outputs[0]->Shape(); + const ONNX_NAMESPACE::TensorShapeProto* past_shape = subgraph_outputs[first_present_output_index_]->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_) / 2; + + // If input_ids's shape is ['batch_size', 1] then use next token as input_ids. + // Otherwise in the case of shape ['batch_size', 'sequence'], use sequence as input_ids. + const ONNX_NAMESPACE::TensorShapeProto* input_ids_shape = subgraph_inputs[0]->Shape(); + if (input_ids_shape->dim(1).has_dim_value() && input_ids_shape->dim(1).dim_value() == 1) { + use_sequence_as_input_ids_ = false; + } + + 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, + "decoder subgraph input 0 (input_ids) shall have int32 type"); + + auto float_type = subgraph_inputs[1]->TypeAsProto()->tensor_type().elem_type(); + ORT_RETURN_IF(float_type != float32_type && float_type != float16_type, + "decoder subgraph input 1 (encoder_hidden_states) shall have float or float16 type"); + + for (int i = first_past_input_index_; i < first_past_input_index_ + 4 * num_layers; i++) { + ORT_RETURN_IF(subgraph_inputs[i]->TypeAsProto()->tensor_type().elem_type() != float_type, + "decoder subgraph past inputs shall have same data type as that of encoder_hidden_states"); + } + + for (int i = 0; i < num_subgraph_outputs; i++) { + ORT_RETURN_IF(subgraph_outputs[i]->TypeAsProto()->tensor_type().elem_type() != float_type, + "decoder subgraph output shall have same data type as that of encoder_hidden_states"); + } + + is_output_float16_ = (subgraph_outputs[0]->TypeAsProto()->tensor_type().elem_type() == float16_type); + + return Status::OK(); +} + +// Create inputs for decoder from the following data sources: +// encoder feeds: encoder_input_ids, 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_hidden_states, +// present_key_self_0, present_value_self_0, ..., present_key_cross_0, present_value_cross_0, ... +Status WhisperDecoderSubgraph::CreateInitialFeeds( + AllocatorPtr cpu_allocator, + gsl::span beam_next_tokens, + const std::vector& implicit_inputs, + const std::vector& encoder_feeds, + const std::vector& encoder_fetches, + std::vector& decoder_feeds, + const GenerationDeviceHelper::DeviceCopyFunc& device_copy_int32_func, + const GenerationDeviceHelper::ExpandBufferFunc& expand_buffer_float_func, + const GenerationDeviceHelper::ExpandBufferFunc& expand_buffer_float16_func, + 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, + bool need_cache_indir) { + ORT_ENFORCE(session_state_ != nullptr, "Setup must be called before CreateInitialFeeds"); + + // Allocate subgraph inputs from same device as inputs of encoder subgraph. + AllocatorPtr allocator = session_state_->GetAllocator(encoder_feeds[0].Get().Location()); + + // 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; + 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(static_cast(cur_len) * batch_beam_size * sizeof(int)); + auto seq_copy = IAllocator::MakeUniquePtr(buffer_allocator, total_size); + int* seq_copy_ptr = seq_copy.get(); + + if (!use_sequence_as_input_ids_) { + ORT_RETURN_IF_ERROR(device_copy_int32_func( + input_ids.GetMutable()->MutableDataAsSpan(), + beam_next_tokens, + stream, + DeviceCopyDirection::hostToDevice)); + } else { + for (int i = 0; i < batch_beam_size; i++) { + gsl::span sequence = sequences.GetSequence(i); + const int32_t* sequence_data = sequence.data(); + long long seq_index = (long long)i * cur_len; + memcpy(seq_copy_ptr + seq_index, sequence_data, total_size); + } + gsl::span temp_input(input_ids_data, total_size); + gsl::span temp_sequence(seq_copy_ptr, total_size); + ORT_RETURN_IF_ERROR(device_copy_int32_func( + temp_input, + temp_sequence, + stream, + DeviceCopyDirection::hostToDevice)); + } + + // The ordering is the same as used in Setup. + decoder_feeds.reserve(static_cast(num_subgraph_inputs) + static_cast(num_implicit_inputs)); + decoder_feeds.push_back(input_ids); + + if (!past_present_share_buffer_) { + past_present_share_buffer_max_seq_len = 0; + } + + // When first_past_input_index_ == 2, the encoder_hidden_states and past states are copied from the second output + // of encoder. + // When first_past_input_index_ == 1, the past states are copied from the second output of encoder. + // TODO: MAKE IT MORE READABLE + for (size_t j = static_cast(3) - first_past_input_index_; 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, + true, + 0 /*max_sequence_length*/)); + } else { + ORT_RETURN_IF_ERROR(expand_buffer_float_func(stream, + encoder_fetches[j], + num_beam, + allocator, + expanded_hidden_states, + true, + 0 /*max_sequence_length*/)); + } + decoder_feeds.push_back(expanded_hidden_states); + } else { + // 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); + } + } + + if (past_present_share_buffer_) { + // Past sequence length feed + ORT_RETURN_IF_ERROR(AppendPastSequenceLength(decoder_feeds, cpu_allocator, cur_len - 1)); + // Add beam search specific inputs + if (need_cache_indir) { + const int64_t batch_size = static_cast(batch_beam_size / num_beam); + ORT_RETURN_IF_ERROR(AppendBeamWidthAndCacheIndir(decoder_feeds, cpu_allocator, allocator, batch_size, num_beam, + past_present_share_buffer_max_seq_len)); + } + } + + // Pass through implicit inputs. + for (const auto* entry : implicit_inputs) { + decoder_feeds.push_back(*entry); + } + + return Status::OK(); +} + +} // namespace transformers +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cpu/transformers/subgraph_whisper_decoder.h b/onnxruntime/contrib_ops/cpu/transformers/subgraph_whisper_decoder.h new file mode 100644 index 0000000000000..7fc3bd108026c --- /dev/null +++ b/onnxruntime/contrib_ops/cpu/transformers/subgraph_whisper_decoder.h @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "contrib_ops/cpu/transformers/subgraph_base.h" +#include "contrib_ops/cpu/transformers/sequences.h" +#include "contrib_ops/cpu/transformers/subgraph_t5_decoder.h" + +namespace onnxruntime { +namespace contrib { +namespace transformers { + +// A class for Whisper decoder subgraph inputs and outputs preparation. +class WhisperDecoderSubgraph : public T5DecoderSubgraph { + public: + WhisperDecoderSubgraph( + const onnxruntime::Node& node_in, + const std::string& attribute_name, + const GraphViewer& subgraph_in) : T5DecoderSubgraph(node_in, attribute_name, subgraph_in) { + first_past_input_index_ = 1; + } + + // Create inputs for first inference of decoder subgraph. + Status CreateInitialFeeds( + AllocatorPtr cpu_allocator, + gsl::span beam_next_tokens, + const std::vector& implicit_inputs, + const std::vector& encoder_feeds, + const std::vector& encoder_fetches, + std::vector& decoder_feeds, + const GenerationDeviceHelper::DeviceCopyFunc& device_copy_int32_func, + const GenerationDeviceHelper::ExpandBufferFunc& expand_buffer_float_func, + const GenerationDeviceHelper::ExpandBufferFunc& expand_buffer_float16_func, + 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); + + Status Validate(const std::vector& subgraph_inputs, + const std::vector& subgraph_outputs) override; + + void SetPastInputIndex(bool has_hidden_state) { + has_hidden_state_ = has_hidden_state; + if (!has_hidden_state_) { + first_past_input_index_ = 1; + } else { + first_past_input_index_ = 2; + } + } +}; + +} // namespace transformers +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cpu/transformers/subgraph_whisper_encoder.cc b/onnxruntime/contrib_ops/cpu/transformers/subgraph_whisper_encoder.cc index 9b583fbb69fea..8480edc405e53 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/subgraph_whisper_encoder.cc +++ b/onnxruntime/contrib_ops/cpu/transformers/subgraph_whisper_encoder.cc @@ -14,12 +14,11 @@ namespace onnxruntime { namespace contrib { namespace transformers { -/* Whisper Encoder Subgraph (It also contains decoder initialization where decoder_input_ids are filled with start token ID). +/* Whisper Encoder Subgraph (It also contains decoder initialization for decoder_input_ids). Inputs: - encoder_input_features: float (B, encode_sequence_length) - encoder_attention_mask: int32 (B, encode_sequence_length) - decoder_input_ids: int32 (B, 1) + encoder_input_features: float (B, feature_size, encode_sequence_length) + decoder_input_ids: int32 (B, initial_decode_sequence_length) Outputs: logits: (B, 1, vocab_size) @@ -41,7 +40,7 @@ namespace transformers { Status WhisperEncoderSubgraph::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_inputs != 2, "expect 2 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, @@ -49,9 +48,7 @@ Status WhisperEncoderSubgraph::Validate(const std::vector& subgr 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", + ORT_RETURN_IF(subgraph_inputs[1]->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", @@ -74,12 +71,11 @@ Status WhisperEncoderSubgraph::Validate(const std::vector& subgr 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() != float32_type && subgraph_inputs[0]->TypeAsProto()->tensor_type().elem_type() != float16_type, + ORT_RETURN_IF(subgraph_inputs[0]->TypeAsProto()->tensor_type().elem_type() != float32_type && + subgraph_inputs[0]->TypeAsProto()->tensor_type().elem_type() != float16_type, "encoder subgraph input 0 (encoder_input_features) shall have float32 or float16 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"); + "encoder subgraph input 1 (decoder_input_ids) shall have int32 type"); auto output_type = subgraph_outputs[0]->TypeAsProto()->tensor_type().elem_type(); ORT_RETURN_IF(output_type != float32_type && output_type != float16_type, @@ -94,6 +90,60 @@ Status WhisperEncoderSubgraph::Validate(const std::vector& subgr return Status::OK(); } + +// Create inputs for first inference of subgraph. +Status WhisperEncoderSubgraph::CreateInitialFeeds( + const Tensor& original_encoder_input_ids, + const OrtValue* original_decoder_input_ids_value, + int start_token_id, + const std::vector& implicit_inputs, + std::vector& feeds, + const GenerationDeviceHelper::CreateWhisperEncoderInputsFunc& create_encoder_inputs_func, + const GenerationDeviceHelper::AddToFeedsFunc& add_to_feeds_func, + IAllocatorUniquePtr& buffer, + OrtValue& decoder_input_ids, + Stream* ort_stream) { + ORT_ENFORCE(session_state_ != nullptr, "Setup must be called before CreateInitialFeeds"); + + // The ordering is the same as used in Setup. + feeds.reserve(static_cast(num_subgraph_inputs) + static_cast(num_implicit_inputs)); + + // Allocate subgraph inputs to be same device as encoder_input_ids. + AllocatorPtr cpu_allocator = session_state_->GetAllocator(original_encoder_input_ids.Location()); + if (cpu_allocator == nullptr) { + const IExecutionProvider* provider = GetProvider(); + cpu_allocator = session_state_->GetAllocator(provider->GetOrtDeviceByMemType(OrtMemTypeDefault)); + } + ORT_RETURN_IF(cpu_allocator == nullptr, "cpu_allocator shouldn't be nullptr"); + + OrtValue encoder_input_ids; + ORT_RETURN_IF_ERROR(create_encoder_inputs_func(&original_encoder_input_ids, + original_decoder_input_ids_value, + start_token_id, + cpu_allocator, + encoder_input_ids, + decoder_input_ids)); + + const IExecutionProvider* provider = GetProvider(); + 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, decoder_input_ids}, + feeds, + buffer, + default_allocator, + pinned_allocator, + location)); + + for (const auto* entry : implicit_inputs) { + feeds.push_back(*entry); + } + + return Status::OK(); +} + } // namespace transformers } // namespace contrib } // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cpu/transformers/subgraph_whisper_encoder.h b/onnxruntime/contrib_ops/cpu/transformers/subgraph_whisper_encoder.h index c48f3f10e5f5f..10e7f43b0ea83 100644 --- a/onnxruntime/contrib_ops/cpu/transformers/subgraph_whisper_encoder.h +++ b/onnxruntime/contrib_ops/cpu/transformers/subgraph_whisper_encoder.h @@ -18,9 +18,23 @@ class WhisperEncoderSubgraph : public T5EncoderSubgraph { const std::string& attribute_name, const GraphViewer& subgraph_in) : T5EncoderSubgraph(node_in, attribute_name, subgraph_in) {} + // Create inputs for first inference of subgraph. + Status CreateInitialFeeds( + const Tensor& encoder_input_ids, + const OrtValue* original_decoder_input_ids_value, + int start_token_id, + const std::vector& implicit_inputs, + std::vector& feeds, + const GenerationDeviceHelper::CreateWhisperEncoderInputsFunc& create_encoder_inputs_func, + const GenerationDeviceHelper::AddToFeedsFunc& add_to_feeds_func, + IAllocatorUniquePtr& buffer, + OrtValue& expanded_decoder_input_ids, + Stream* ort_stream); + Status Validate(const std::vector& subgraph_inputs, const std::vector& subgraph_outputs) override; }; + } // namespace transformers } // namespace contrib } // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/bert/add_bias_transpose.cu b/onnxruntime/contrib_ops/cuda/bert/add_bias_transpose.cu index 8782201a64e6b..d846f55f1e28d 100644 --- a/onnxruntime/contrib_ops/cuda/bert/add_bias_transpose.cu +++ b/onnxruntime/contrib_ops/cuda/bert/add_bias_transpose.cu @@ -1,5 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. + #include "core/providers/cuda/cuda_common.h" #include "core/providers/cuda/cu_inc/common.cuh" #include "contrib_ops/cuda/bert/add_bias_transpose.h" @@ -36,7 +37,7 @@ __global__ void AddBiasTransposeTrt(const T* input, const T* biases, T* output) const int h = threadIdx.x; if (h < H) { - output[out_offset + h] = input[in_offset + h] + biases[m * NH + n * H + h]; + output[out_offset + h] = input[in_offset + h] + (nullptr == biases ? T{} : biases[m * NH + n * H + h]); } } @@ -61,7 +62,7 @@ __global__ void AddBiasTransposeTrtLarge(const int head_size, const T* input, co int h = threadIdx.x; while (h < H) { - output[out_offset + h] = input[in_offset + h] + biases[m * NH + n * H + h]; + output[out_offset + h] = input[in_offset + h] + (nullptr == biases ? T{} : biases[m * NH + n * H + h]); h += stride; } } @@ -92,7 +93,7 @@ __global__ void AddBiasTransposeTrt(const T* query, const T* key, const T* value const int h = threadIdx.x; if (h < H) { - output[out_offset + h] = input[in_offset + h] + biases[m * NH + n * H + h]; + output[out_offset + h] = input[in_offset + h] + (nullptr == biases ? T{} : biases[m * NH + n * H + h]); } } @@ -118,7 +119,7 @@ __global__ void AddBiasTransposeTrtLarge(const int head_size, int h = threadIdx.x; if (h < H) { - output[out_offset + h] = input[in_offset + h] + biases[m * NH + n * H + h]; + output[out_offset + h] = input[in_offset + h] + (nullptr == biases ? T{} : biases[m * NH + n * H + h]); h += stride; } } @@ -149,7 +150,7 @@ __global__ void AddBiasTransposeTrtKV(const T* key, const T* value, const T* bia const int h = threadIdx.x; if (h < H) { - output[out_offset + h] = input[in_offset + h] + biases[(m + 1) * NH + n * H + h]; + output[out_offset + h] = input[in_offset + h] + (nullptr == biases ? T{} : biases[(m + 1) * NH + n * H + h]); } } @@ -177,7 +178,7 @@ __global__ void AddBiasTransposeTrtKVLarge(const int head_size, int h = threadIdx.x; while (h < H) { - output[out_offset + h] = input[in_offset + h] + biases[(m + 1) * NH + n * H + h]; + output[out_offset + h] = input[in_offset + h] + (nullptr == biases ? T{} : biases[(m + 1) * NH + n * H + h]); h += stride; } } @@ -208,9 +209,9 @@ __global__ void AddBiasTransposeQKV(int M, const T* input, const T* biases, T* o const int h = threadIdx.x; if (h < head_size) { - output[out_offset + h] = input[in_offset + h] + biases[m * NH + n * H + h]; + output[out_offset + h] = input[in_offset + h] + (nullptr == biases ? T{} : biases[m * NH + n * H + h]); if (nullptr != qkv_add_bias) { - qkv_add_bias[in_offset + h] = input[in_offset + h] + biases[m * NH + n * H + h]; + qkv_add_bias[in_offset + h] = input[in_offset + h] + (nullptr == biases ? T{} : biases[m * NH + n * H + h]); } } } @@ -271,9 +272,9 @@ __global__ void AddBiasTransposeQKV(int M, const T* input, const T* biases, T* o k = *reinterpret_cast(&input[src_k_idx]); v = *reinterpret_cast(&input[src_v_idx]); - q_bias = *reinterpret_cast(&biases[n * H + head_idx]); - k_bias = *reinterpret_cast(&biases[NH + n * H + head_idx]); - v_bias = *reinterpret_cast(&biases[2 * NH + n * H + head_idx]); + q_bias = nullptr == biases ? Vec_t{} : *reinterpret_cast(&biases[n * H + head_idx]); + k_bias = nullptr == biases ? Vec_t{} : *reinterpret_cast(&biases[NH + n * H + head_idx]); + v_bias = nullptr == biases ? Vec_t{} : *reinterpret_cast(&biases[2 * NH + n * H + head_idx]); } q = add_vec(q, q_bias); @@ -403,7 +404,7 @@ __global__ void AddBiasTransposeQKV(const T* input, const T* biases, T* output, h; // H if (h < head_size) { - output[out_offset] = input[in_offset] + biases[bias_offset]; + output[out_offset] = input[in_offset] + (nullptr == biases ? T{} : biases[bias_offset]); } } @@ -432,9 +433,9 @@ __global__ void AddBiasTransposeQKVLarge(const int head_size, const T* input, co int h = threadIdx.x; while (h < H) { - output[out_offset + h] = input[in_offset + h] + biases[m * NH + n * H + h]; + output[out_offset + h] = input[in_offset + h] + (nullptr == biases ? T{} : biases[m * NH + n * H + h]); if (nullptr != qkv_add_bias) { - qkv_add_bias[in_offset + h] = input[in_offset + h] + biases[m * NH + n * H + h]; + qkv_add_bias[in_offset + h] = input[in_offset + h] + (nullptr == biases ? T{} : biases[m * NH + n * H + h]); } h += stride; } @@ -483,7 +484,7 @@ __global__ void AddBiasTransposeCutlass(const T* input, const T* biases, T* outp h; // H if (h < head_size) { - output[out_offset] = input[in_offset] + biases[bias_offset]; + output[out_offset] = input[in_offset] + (nullptr == biases ? T{} : biases[bias_offset]); } } @@ -545,7 +546,7 @@ __global__ void AddBiasTransposeCutlass(int M, const T* input, const T* biases, const int h = threadIdx.x; if (h < head_size) { - output[out_offset + h] = input[in_offset + h] + biases[m * NH + n * H + h]; + output[out_offset + h] = input[in_offset + h] + (nullptr == biases ? T{} : biases[m * NH + n * H + h]); } } @@ -573,7 +574,7 @@ __global__ void AddBiasTransposeCutlassLarge(const int head_size, const T* input int h = threadIdx.x; while (h < H) { - output[out_offset + h] = input[in_offset + h] + biases[m * NH + n * H + h]; + output[out_offset + h] = input[in_offset + h] + (nullptr == biases ? T{} : biases[m * NH + n * H + h]); h += stride; } } @@ -603,7 +604,7 @@ __global__ void AddBiasTranspose(const T* input, const T* biases, T* output) { const int h = threadIdx.x; if (h < head_size) { - output[out_offset + h] = input[in_offset + h] + biases[m * NH + n * H + h]; + output[out_offset + h] = input[in_offset + h] + (nullptr == biases ? T{} : biases[m * NH + n * H + h]); } } @@ -640,7 +641,7 @@ void InvokeAddBiasTranspose( cudaStream_t stream, const int num_matrices, const int format, const int max_threads_per_block, const int batch_size, const int sequence_length, const int num_heads, const int qk_head_size, const T* input, const T* biases, T* output, T* qkv_add_bias, const int v_head_size, int total_matrix_count, - bool do_rotary = false, int original_past_sequence_length = 0) { + bool do_rotary = false, int past_sequence_length = 0) { assert(num_heads <= max_threads_per_block); if (do_rotary) { @@ -650,11 +651,14 @@ void InvokeAddBiasTranspose( if (format != 1 && format != 2 && format != 3) { ORT_THROW("format must be 1, 2 or 3 for rotary attention"); } + if (qk_head_size != 64 && qk_head_size !=128) { + ORT_THROW("qk_head_size must be 64 or 128 for rotary attention"); + } if (v_head_size != -1 && qk_head_size != v_head_size) { ORT_THROW("qk_head_size must be equal to v_head_size for rotary attention"); } - const int step = original_past_sequence_length == 0 ? sequence_length : original_past_sequence_length; + const int step = past_sequence_length == 0 ? sequence_length : past_sequence_length; size_t smem_size = 2 * qk_head_size * sizeof(T); const dim3 grid(sequence_length, num_heads, batch_size); @@ -724,7 +728,7 @@ void LaunchAddBiasTranspose( cudaStream_t stream, const int num_matrices, const int format, const int max_threads_per_block, const int batch_size, const int sequence_length, const int num_heads, const int qk_head_size, const half* input, const half* biases, half* output, bool enable_half4, const int v_head_size, - half* qkv_add_bias, int total_matrix_count, bool do_rotary, int original_past_sequence_length) { + half* qkv_add_bias, int total_matrix_count, bool do_rotary, int past_sequence_length) { total_matrix_count = std::max(num_matrices, total_matrix_count); if (enable_half4 && 0 == (qk_head_size % 4) && (v_head_size == -1 || 0 == (v_head_size % 4)) && !do_rotary) { const int H = qk_head_size / 4; @@ -750,7 +754,7 @@ void LaunchAddBiasTranspose( InvokeAddBiasTranspose( stream, num_matrices, format, max_threads_per_block, batch_size, sequence_length, num_heads, qk_head_size, input, biases, output, - qkv_add_bias, v_head_size, total_matrix_count, do_rotary, original_past_sequence_length); + qkv_add_bias, v_head_size, total_matrix_count, do_rotary, past_sequence_length); } } @@ -760,7 +764,7 @@ void LaunchAddBiasTranspose( const int batch_size, const int sequence_length, const int num_heads, const int qk_head_size, const float* input, const float* biases, float* output, bool /*enable_half4*/, const int v_head_size, float* qkv_add_bias, int total_matrix_count, bool do_rotary, - int original_past_sequence_length) { + int past_sequence_length) { total_matrix_count = std::max(num_matrices, total_matrix_count); if (0 == (qk_head_size % 4) && (v_head_size == -1 || 0 == (v_head_size % 4)) && !do_rotary) { const int H = qk_head_size / 4; @@ -786,7 +790,7 @@ void LaunchAddBiasTranspose( InvokeAddBiasTranspose( stream, num_matrices, format, max_threads_per_block, batch_size, sequence_length, num_heads, qk_head_size, input, biases, output, - qkv_add_bias, v_head_size, total_matrix_count, do_rotary, original_past_sequence_length); + qkv_add_bias, v_head_size, total_matrix_count, do_rotary, past_sequence_length); } } @@ -903,7 +907,7 @@ void InvokeAddBias( // K { const dim3 grid(kv_sequence_length, batch_size, num_matrices); - const T* biases_k = biases + num_heads * head_size; + const T* biases_k = nullptr == biases ? nullptr : biases + num_heads * head_size; if (head_size * num_heads <= max_threads_per_block) { const dim3 block(head_size, num_heads, 1); @@ -918,7 +922,7 @@ void InvokeAddBias( { const dim3 grid(kv_sequence_length, batch_size, num_matrices); - const T* biases_v = biases + 2 * num_heads * head_size; + const T* biases_v = nullptr == biases ? nullptr : biases + 2 * num_heads * head_size; if (v_head_size * num_heads <= max_threads_per_block) { const dim3 block(v_head_size, num_heads, 1); AddBiasTransposeTrt<<>>(value, biases_v, v); diff --git a/onnxruntime/contrib_ops/cuda/bert/add_bias_transpose.h b/onnxruntime/contrib_ops/cuda/bert/add_bias_transpose.h index 86e1983b56fce..d903267c99a01 100644 --- a/onnxruntime/contrib_ops/cuda/bert/add_bias_transpose.h +++ b/onnxruntime/contrib_ops/cuda/bert/add_bias_transpose.h @@ -33,7 +33,7 @@ void LaunchAddBiasTranspose( cudaStream_t stream, const int num_matrices, const int format, const int max_threads_per_block, const int batch_size, const int sequence_length, const int num_heads, const int qk_head_size, const T* input, const T* biases, T* output, bool enable_half4, const int v_head_size, T* qkv_add_bias = nullptr, - int total_matrix_count = -1, bool do_rotary = false, int original_past_sequence_length = 0); + int total_matrix_count = -1, bool do_rotary = false, int past_sequence_length = 0); // Add (bias) and Transpose for separated inputs of Q, K and V, and output Trt format. // For self attention: diff --git a/onnxruntime/contrib_ops/cuda/bert/attention.cc b/onnxruntime/contrib_ops/cuda/bert/attention.cc index def1508ca2368..f0385ea5abdfb 100644 --- a/onnxruntime/contrib_ops/cuda/bert/attention.cc +++ b/onnxruntime/contrib_ops/cuda/bert/attention.cc @@ -8,6 +8,7 @@ #include "contrib_ops/cuda/bert/attention.h" #include "contrib_ops/cuda/bert/bert_padding.h" #include "contrib_ops/cuda/bert/cutlass_fmha/memory_efficient_attention.h" +#include "contrib_ops/cuda/bert/flash_attention/flash_api.h" using namespace onnxruntime::cuda; using namespace ::onnxruntime::common; @@ -39,20 +40,36 @@ REGISTER_KERNEL_TYPED(MLFloat16) template Attention::Attention(const OpKernelInfo& info) : CudaKernel(info), AttentionBase(info, false) { - disable_fused_self_attention_ = sizeof(T) != 2 || - ParseEnvironmentVariableWithDefault(attention::kDisableFusedSelfAttention, false); + disable_fused_self_attention_ = + sizeof(T) != 2 || + ParseEnvironmentVariableWithDefault(attention::kDisableFusedSelfAttention, false); - enable_trt_flash_attention_ = sizeof(T) == 2 && - !ParseEnvironmentVariableWithDefault(attention::kDisableTrtFlashAttention, false); + enable_trt_flash_attention_ = + sizeof(T) == 2 && + !ParseEnvironmentVariableWithDefault(attention::kDisableTrtFlashAttention, false); - enable_fused_causal_attention_ = sizeof(T) == 2 && - ParseEnvironmentVariableWithDefault(attention::kEnableFusedCausalAttention, false); + enable_fused_causal_attention_ = + sizeof(T) == 2 && + ParseEnvironmentVariableWithDefault(attention::kEnableFusedCausalAttention, false); -#if USE_FLASH_ATTENTION - disable_memory_efficient_attention_ = ParseEnvironmentVariableWithDefault(attention::kDisableMemoryEfficientAttention, false); +#if USE_MEMORY_EFFICIENT_ATTENTION + disable_memory_efficient_attention_ = + ParseEnvironmentVariableWithDefault(attention::kDisableMemoryEfficientAttention, false); #else disable_memory_efficient_attention_ = true; #endif + +#if USE_FLASH_ATTENTION + disable_flash_attention_ = + sizeof(T) != 2 || + onnxruntime::ParseEnvironmentVariableWithDefault(attention::kDisableFlashAttention, false); + min_seq_len_for_flash_attention_packed_qkv_ = ParseEnvironmentVariableWithDefault( + attention::kMinSeqLenForFlashAttentionPackedQKV, + attention::kDefaultMinSeqLenForFlashAttentionPackedQKV); +#else + disable_flash_attention_ = true; + min_seq_len_for_flash_attention_packed_qkv_ = 0; +#endif } template @@ -100,68 +117,94 @@ Status Attention::ComputeInternal(OpKernelContext* context) const { MHARunner* fused_runner = nullptr; // Check whether we can use fused kernel - int sm = device_prop.major * 10 + device_prop.minor; - bool is_mask_1d_seq_len = parameters.mask_type == AttentionMaskType::MASK_1D_KEY_SEQ_LEN; - bool is_mask_1d_key_seq_len_start = parameters.mask_type == AttentionMaskType::MASK_1D_KEY_SEQ_LEN_START; - - if (is_unidirectional_ && enable_fused_causal_attention_) { // GPT - // GPT fused kernels requires left side padding. mask can be: - // none (no padding), 1D sequence lengths or 2d mask. - // Fused kernels don't support different sequence lengths of q and kv, so only apply to the first token - // where past state is empty. - bool is_mask_2d_key_padding = parameters.mask_type == AttentionMaskType::MASK_2D_KEY_PADDING; - bool use_causal_fused_runner = (nullptr == mask_index || is_mask_1d_seq_len || is_mask_2d_key_padding) && - nullptr == relative_position_bias && - parameters.past_sequence_length == 0 && - parameters.hidden_size == parameters.v_hidden_size && - FusedMHARunnerFP16v2::is_supported(sm, parameters.head_size, sequence_length, - enable_trt_flash_attention_, true); - if (use_causal_fused_runner) { - // Here we assume that num_heads, head_size and is_unidirectional does not change for an Attention node. - if (nullptr == fused_fp16_runner_.get()) { - fused_fp16_runner_ = FusedMHARunnerFP16v2::Create(num_heads_, parameters.head_size, sm, is_unidirectional_, - enable_trt_flash_attention_, parameters.scale); - } + const int sm = device_prop.major * 10 + device_prop.minor; + const bool is_mask_1d_seq_len = parameters.mask_type == AttentionMaskType::MASK_1D_KEY_SEQ_LEN; - // Here we assume all causal kernels can be loaded into shared memory. TODO: add a function to check. - fused_runner = fused_fp16_runner_.get(); - } - } else { // BERT - bool use_fused_runner = !disable_fused_self_attention_ && - (nullptr == mask_index || is_mask_1d_seq_len) && - nullptr == past && - nullptr == present && - nullptr == relative_position_bias && - parameters.hidden_size == parameters.v_hidden_size && - FusedMHARunnerFP16v2::is_supported(sm, parameters.head_size, sequence_length, - enable_trt_flash_attention_, false); - - if (use_fused_runner) { - // Here we assume that num_heads, head_size and is_unidirectional does not change for an Attention node. - if (nullptr == fused_fp16_runner_.get()) { - fused_fp16_runner_ = FusedMHARunnerFP16v2::Create(num_heads_, parameters.head_size, sm, is_unidirectional_, - enable_trt_flash_attention_, parameters.scale); - } +#if USE_FLASH_ATTENTION + bool use_flash_attention = !disable_flash_attention_ && + (nullptr == relative_position_bias) && + nullptr == past && + nullptr == present && + parameters.hidden_size == parameters.v_hidden_size && + nullptr == mask_index && + 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 when sequence length <= 512. + if (use_flash_attention && parameters.sequence_length < min_seq_len_for_flash_attention_packed_qkv_) { + use_flash_attention = false; + } +#else + constexpr bool use_flash_attention = false; +#endif - // In case some kernel not loaded due to shared memory limit, we need to double check here. - const int S = fused_fp16_runner_->getSFromMaxSeqLen(sequence_length); - if (fused_fp16_runner_->isValid(S)) { + if (!use_flash_attention) { + if (is_unidirectional_ && enable_fused_causal_attention_) { // GPT + // GPT fused kernels requires left side padding. mask can be: + // none (no padding), 1D sequence lengths or 2d mask. + // Fused kernels don't support different sequence lengths of q and kv, so only apply to the first token + // where past state is empty. + bool is_mask_2d_key_padding = parameters.mask_type == AttentionMaskType::MASK_2D_KEY_PADDING; + bool use_causal_fused_runner = (nullptr == mask_index || is_mask_1d_seq_len || is_mask_2d_key_padding) && + nullptr == relative_position_bias && + parameters.past_sequence_length == 0 && + parameters.hidden_size == parameters.v_hidden_size && + FusedMHARunnerFP16v2::is_supported(sm, parameters.head_size, sequence_length, + enable_trt_flash_attention_, true); + if (use_causal_fused_runner) { + // Here we assume that num_heads, head_size and is_unidirectional does not change for an Attention node. + if (nullptr == fused_fp16_runner_.get()) { + fused_fp16_runner_ = FusedMHARunnerFP16v2::Create(num_heads_, parameters.head_size, sm, is_unidirectional_, + enable_trt_flash_attention_, parameters.scale); + } + + // Here we assume all causal kernels can be loaded into shared memory. TODO: add a function to check. fused_runner = fused_fp16_runner_.get(); } + } else { // BERT + bool use_fused_runner = !disable_fused_self_attention_ && + (nullptr == mask_index || is_mask_1d_seq_len) && + nullptr == past && + nullptr == present && + nullptr == relative_position_bias && + parameters.hidden_size == parameters.v_hidden_size && + FusedMHARunnerFP16v2::is_supported(sm, parameters.head_size, sequence_length, + enable_trt_flash_attention_, false); + + if (use_fused_runner) { + // Here we assume that num_heads, head_size and is_unidirectional does not change for an Attention node. + if (nullptr == fused_fp16_runner_.get()) { + fused_fp16_runner_ = FusedMHARunnerFP16v2::Create(num_heads_, parameters.head_size, sm, is_unidirectional_, + enable_trt_flash_attention_, parameters.scale); + } + + // In case some kernel not loaded due to shared memory limit, we need to double check here. + const int S = fused_fp16_runner_->getSFromMaxSeqLen(sequence_length); + if (fused_fp16_runner_->isValid(S)) { + fused_runner = fused_fp16_runner_.get(); + } + } } } -#if USE_FLASH_ATTENTION - bool is_good_for_rpb = relative_position_bias != nullptr && parameters.sequence_length % (4 * sizeof(T)) == 0; - bool use_memory_efficient_attention = fused_runner == nullptr && - !disable_memory_efficient_attention_ && - (nullptr == mask_index || is_mask_1d_key_seq_len_start) && - nullptr == past && - nullptr == present && - (nullptr == relative_position_bias || is_good_for_rpb) && - (sizeof(T) == 2 || // sequence length threshold is 0 in FP16 - parameters.sequence_length >= attention::kMinSequenceLengthForMemoryEfficientAttentionFp32) && - has_memory_efficient_attention(sm, sizeof(T) == 2); +#if USE_MEMORY_EFFICIENT_ATTENTION + bool use_memory_efficient_attention = + !use_flash_attention && + fused_runner == nullptr && + !disable_memory_efficient_attention_ && + nullptr == past && + nullptr == present && + (parameters.head_size & 7) == 0 && + (parameters.v_head_size & 7) == 0 && + (nullptr == mask_index || parameters.mask_type == AttentionMaskType::MASK_1D_KEY_SEQ_LEN_START) && + (sizeof(T) == 2 || parameters.sequence_length >= attention::kMinSeqLenForMemoryEfficientAttentionFp32) && + has_memory_efficient_attention(sm, sizeof(T) == 2); + + if (use_memory_efficient_attention) { + bool is_good_for_rpb = relative_position_bias != nullptr && parameters.sequence_length % (4 * sizeof(T)) == 0; + use_memory_efficient_attention = (nullptr == relative_position_bias || is_good_for_rpb); + } #else constexpr bool use_memory_efficient_attention = false; #endif @@ -198,6 +241,7 @@ Status Attention::ComputeInternal(OpKernelContext* context) const { parameters.kv_sequence_length, parameters.total_sequence_length, fused_runner, + use_flash_attention, use_fused_cross_attention, use_memory_efficient_attention); auto work_space = GetScratchBuffer(workSpaceSize, context->GetComputeStream()); @@ -205,29 +249,30 @@ Status Attention::ComputeInternal(OpKernelContext* context) const { typedef typename ToCudaType::MappedType CudaT; AttentionData data; data.gemm_buffer = reinterpret_cast(gemm_buffer.get()); - data.bias = nullptr == bias ? nullptr : reinterpret_cast(bias->Data()); - data.query = nullptr; - data.key = nullptr; - data.value = nullptr; - data.mask_index = (nullptr == mask_index) ? nullptr : mask_index->Data(); - data.mask_index_dims = (nullptr == mask_index) ? gsl::span() : mask_index->Shape().GetDims(); - data.past = (nullptr == past) ? nullptr : reinterpret_cast(past->Data()); - data.past_key = nullptr; - data.past_value = nullptr; - data.relative_position_bias = (nullptr == relative_position_bias) ? nullptr : reinterpret_cast(relative_position_bias->Data()); + if (nullptr != bias) { + data.bias = reinterpret_cast(bias->Data()); + } + if (nullptr != mask_index) { + data.mask_index = mask_index->Data(); + data.mask_index_dims = mask_index->Shape().GetDims(); + } + if (nullptr != past) { + data.past = reinterpret_cast(past->Data()); + } + if (nullptr != relative_position_bias) { + data.relative_position_bias = reinterpret_cast(relative_position_bias->Data()); + } data.has_qkv_workspace = true; data.workspace = reinterpret_cast(work_space.get()); data.output = reinterpret_cast(output->MutableData()); - data.present = (nullptr == present) ? nullptr : reinterpret_cast(present->MutableData()); - data.present_key = nullptr; - data.present_value = nullptr; + if (nullptr != present) { + data.present = reinterpret_cast(present->MutableData()); + } data.fused_runner = reinterpret_cast(fused_runner); - data.fused_cross_attention_kernel = nullptr; + data.use_flash_attention = use_flash_attention; data.use_memory_efficient_attention = use_memory_efficient_attention; - data.cumulated_sequence_length_q_cache = nullptr; - data.cumulated_sequence_length_kv_cache = nullptr; - return QkvToContext(device_prop, cublas, Stream(context), parameters, data); + return QkvToContext(device_prop, cublas, context->GetComputeStream(), parameters, data); } } // namespace cuda diff --git a/onnxruntime/contrib_ops/cuda/bert/attention.h b/onnxruntime/contrib_ops/cuda/bert/attention.h index ba7c56c04fdde..455e55ba05a66 100644 --- a/onnxruntime/contrib_ops/cuda/bert/attention.h +++ b/onnxruntime/contrib_ops/cuda/bert/attention.h @@ -21,10 +21,12 @@ class Attention final : public CudaKernel, public AttentionBase { Status ComputeInternal(OpKernelContext* context) const override; protected: + bool disable_flash_attention_; bool disable_fused_self_attention_; bool enable_trt_flash_attention_; bool enable_fused_causal_attention_; bool disable_memory_efficient_attention_; + int min_seq_len_for_flash_attention_packed_qkv_; mutable std::unique_ptr fused_fp16_runner_; }; diff --git a/onnxruntime/contrib_ops/cuda/bert/attention_concat.cu b/onnxruntime/contrib_ops/cuda/bert/attention_concat.cu deleted file mode 100644 index 5d9cfcc69773a..0000000000000 --- a/onnxruntime/contrib_ops/cuda/bert/attention_concat.cu +++ /dev/null @@ -1,249 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "core/providers/cuda/cuda_common.h" -#include "contrib_ops/cuda/bert/attention_impl.h" - -using namespace onnxruntime::cuda; - -namespace onnxruntime { -namespace contrib { -namespace cuda { - -template -__global__ void ConcatTensorToTensor(const int tensor_add_sequence_length, - const T* tensor_in, - const T* tensor_add, - T* tensor_out) { - const int h = threadIdx.x; - const int n = threadIdx.y; - const int s = blockIdx.x; - const int b = blockIdx.y; - const int chunk_id = blockIdx.z; - - const int all_sequence_length = gridDim.x; - const int batch_size = gridDim.y; - const int num_heads = blockDim.y; - const int H = blockDim.x; - - // K: number of identical tensors - // tensor_in: K x BxNxPxH - // tensor_add: K x BxNxLxH - // tensor_out: K x BxNxTxH, where T = P + L - const int tensor_in_sequence_length = all_sequence_length - tensor_add_sequence_length; - - const int present_SH = all_sequence_length * H; - const int present_NSH = num_heads * present_SH; - int out_offset = b * present_NSH + n * present_SH + s * H + h + chunk_id * (present_NSH * batch_size); - if (s < tensor_in_sequence_length) { - const int past_SH = tensor_in_sequence_length * H; - const int past_NSH = num_heads * past_SH; - const int in_offset = b * past_NSH + n * past_SH + s * H + h + chunk_id * (past_NSH * batch_size); - tensor_out[out_offset] = tensor_in[in_offset]; - } else if (s < all_sequence_length) { - const int SH = tensor_add_sequence_length * H; - const int NSH = num_heads * SH; - const int in_offset = b * NSH + n * SH + (s - tensor_in_sequence_length) * H + h + chunk_id * (NSH * batch_size); - tensor_out[out_offset] = tensor_add[in_offset]; - } -} - -template -__global__ void ConcatTensorToTensorLarge(const int tensor_add_sequence_length, - const int H, - const T* tensor_in, - const T* tensor_add, - T* tensor_out) { - // Use when (H*)*num_heads > 1024 - int h = threadIdx.x; - const int n = threadIdx.y; - const int s = blockIdx.x; - const int b = blockIdx.y; - const int chunk_id = blockIdx.z; - - const int all_sequence_length = gridDim.x; - const int batch_size = gridDim.y; - const int num_heads = blockDim.y; - const int stride = blockDim.x; - - // K: number of identical tensor - // tensor_in: K x BxNxPxH - // tensor_add: K x BxNxLxH - // tensor_out: K x BxNxTxH - const int tensor_in_sequence_length = all_sequence_length - tensor_add_sequence_length; - - const int present_SH = all_sequence_length * H; - const int present_NSH = num_heads * present_SH; - while (h < H) { - int out_offset = b * present_NSH + n * present_SH + s * H + h + chunk_id * (present_NSH * batch_size); - if (s < tensor_in_sequence_length) { - const int past_SH = tensor_in_sequence_length * H; - const int past_NSH = num_heads * past_SH; - const int in_offset = b * past_NSH + n * past_SH + s * H + h + chunk_id * (past_NSH * batch_size); - tensor_out[out_offset] = tensor_in[in_offset]; - } else if (s < all_sequence_length) { - const int SH = tensor_add_sequence_length * H; - const int NSH = num_heads * SH; - const int in_offset = b * NSH + n * SH + (s - tensor_in_sequence_length) * H + h + chunk_id * (NSH * batch_size); - tensor_out[out_offset] = tensor_add[in_offset]; - } - - h += stride; - } -} - -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) { - const dim3 grid(all_sequence_length, batch_size, matrix_num); - if (0 == (head_size & 1)) { - const int H = head_size / 2; - if (H * num_heads <= max_threads_per_block) { - const dim3 block(H, num_heads, 1); - ConcatTensorToTensor<<>>(sequence_length, - reinterpret_cast(tensor_in), - reinterpret_cast(tensor_add), - reinterpret_cast(tensor_out)); - } else { - const dim3 block(max_threads_per_block / num_heads, num_heads, 1); - ConcatTensorToTensorLarge<<>>(sequence_length, - H, - reinterpret_cast(tensor_in), - reinterpret_cast(tensor_add), - reinterpret_cast(tensor_out)); - } - } else { - if (head_size * num_heads <= max_threads_per_block) { - const dim3 block(head_size, num_heads, 1); - ConcatTensorToTensor<<>>(sequence_length, tensor_in, tensor_add, tensor_out); - } else { - const dim3 block(max_threads_per_block / num_heads, num_heads, 1); - ConcatTensorToTensorLarge<<>>(sequence_length, - head_size, - tensor_in, - tensor_add, - tensor_out); - } - } - return CUDA_CALL(cudaGetLastError()); -} - -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) { - const dim3 grid(all_sequence_length, batch_size, matrix_num); - if (0 == (head_size % 4)) { - const int H = head_size / 4; - if (H * num_heads <= max_threads_per_block) { - const dim3 block(H, num_heads, 1); - ConcatTensorToTensor<<>>(sequence_length, - reinterpret_cast(tensor_in), - reinterpret_cast(tensor_add), - reinterpret_cast(tensor_out)); - } else { - const dim3 block(max_threads_per_block / num_heads, num_heads, 1); - ConcatTensorToTensorLarge<<>>(sequence_length, - H, - reinterpret_cast(tensor_in), - reinterpret_cast(tensor_add), - reinterpret_cast(tensor_out)); - } - } else if (0 == (head_size & 1)) { - const int H = head_size / 2; - if (H * num_heads <= max_threads_per_block) { - const dim3 block(H, num_heads, 1); - ConcatTensorToTensor<<>>(sequence_length, - reinterpret_cast(tensor_in), - reinterpret_cast(tensor_add), - reinterpret_cast(tensor_out)); - } else { - const dim3 block(max_threads_per_block / num_heads, num_heads, 1); - ConcatTensorToTensorLarge<<>>(sequence_length, - H, - reinterpret_cast(tensor_in), - reinterpret_cast(tensor_add), - reinterpret_cast(tensor_out)); - } - } else { // this should be an "odd" case. probably not worth catching it in the half2 kernel. - if (head_size * num_heads <= max_threads_per_block) { - const dim3 block(head_size, num_heads, 1); - ConcatTensorToTensor<<>>(sequence_length, tensor_in, tensor_add, tensor_out); - } else { - const dim3 block(max_threads_per_block / num_heads, num_heads, 1); - ConcatTensorToTensorLarge<<>>(sequence_length, - head_size, - tensor_in, - tensor_add, - tensor_out); - } - } - 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); -} - -} // 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 d6741d68f306d..b4a4ae208ceb1 100644 --- a/onnxruntime/contrib_ops/cuda/bert/attention_impl.cu +++ b/onnxruntime/contrib_ops/cuda/bert/attention_impl.cu @@ -26,22 +26,19 @@ limitations under the License. // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include -#include -#include #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_impl.h" #include "contrib_ops/cuda/bert/attention_softmax.h" #include "contrib_ops/cuda/bert/transformer_common.h" -#include "contrib_ops/cuda/bert/add_bias_transpose.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/cpu/bert/attention_base.h" #include "contrib_ops/cuda/bert/bert_padding.h" #include "contrib_ops/cuda/transformers/dump_cuda_tensor.h" #include "contrib_ops/cuda/bert/cutlass_fmha/memory_efficient_attention.h" +#include "contrib_ops/cuda/bert/flash_attention/flash_api.h" +#include "contrib_ops/cuda/bert/attention_impl.h" using namespace onnxruntime::cuda; using namespace onnxruntime::contrib::attention_softmax_cuda; @@ -64,7 +61,8 @@ size_t AlignSize(size_t bytes) { void CumulatedSequenceLengthCache::Initialize(int32_t sequence_length, cudaStream_t stream) { if (this->sequence_length != sequence_length) { ORT_ENFORCE(buffer.get() != nullptr && this->max_batch_size > 0); - LaunchTrtSequenceOffset(reinterpret_cast(buffer.get()), nullptr, this->max_batch_size, sequence_length, stream); + LaunchTrtSequenceOffset(reinterpret_cast(buffer.get()), nullptr, + this->max_batch_size, sequence_length, stream); this->sequence_length = sequence_length; } } @@ -114,6 +112,7 @@ size_t GetAttentionWorkspaceSize( size_t kv_sequence_length, size_t total_sequence_length, void* fused_runner, + bool use_flash_attention, bool use_fused_cross_attention, bool use_memory_efficient_attention) { // Note that q, k and v might need alignment for fused attention kernels. @@ -121,6 +120,14 @@ size_t GetAttentionWorkspaceSize( ((sequence_length + kv_sequence_length) * qk_head_size + kv_sequence_length * v_head_size); #if USE_FLASH_ATTENTION + if (use_flash_attention) { + return qkv_bytes + onnxruntime::flash::get_softmax_lse_size(sequence_length, batch_size, num_heads); + } +#else + ORT_UNUSED_PARAMETER(use_flash_attention); +#endif + +#if USE_MEMORY_EFFICIENT_ATTENTION if (use_memory_efficient_attention) { size_t fmha_buffer_bytes = 0; if (MemoryEfficientAttentionParams::need_workspace(v_head_size, element_size == sizeof(float))) { @@ -146,755 +153,285 @@ size_t GetAttentionWorkspaceSize( } template -__global__ void AddBiasTransAppendKvToPresentSmall( - const T* qkv, const T* biases, T* present, - const int head_size, const int past_sequence_length, const int max_sequence_length) { - // Input: BxSxMxNxH (Format 1) - // Output: (2, B, N, [P..P+S) of MaxS, H), - // B is batch_size, S is sequence_length, M is number of matrices, N is num_heads, H is head_size - const int n = threadIdx.y; - const int s = blockIdx.x; - const int b = blockIdx.y; - const int N = blockDim.y; - const int S = gridDim.x; - const int B = gridDim.y; - - constexpr int M = 3; // Matrix count in qkv - const int m = blockIdx.z + 1; // k = 1, v = 2 - - const int NH = N * head_size; - const int NHS = NH * S; - - qkv += (n * head_size + (s * M + m) * NH + b * M * NHS); - if (biases) { - biases += (m * NH + n * head_size); - } - - const int MsH = max_sequence_length * head_size; - const int NMsH = N * MsH; - const int BNMsH = B * NMsH; - present += ((past_sequence_length + s) * head_size + n * MsH + b * NMsH + (m - 1) * BNMsH); - - for (int h = threadIdx.x; h < head_size; h += blockDim.x) { - T bias = (biases ? biases[h] : (T)0.0f); - present[h] = qkv[h] + bias; - } -} - -template -__global__ void AddBiasTransAppendKvToPresent( - const T* qkv, const T* biases, T* present, - const int head_size, const int past_sequence_length, const int max_sequence_length) { - // Input: BxSxMxNxH (Format 1) - // Output: (2, B, N, [P..P+S) of MaxS, H), - // B is batch_size, S is sequence_length, M is number of matrices, N is num_heads, H is head_size - const int n = blockIdx.x; - const int s = blockIdx.y; - const int b = (blockIdx.z >> 1); - const int N = gridDim.x; - const int S = gridDim.y; - const int B = (gridDim.z >> 1); - - constexpr int M = 3; // Matrix count in qkv - const int m = (blockIdx.z & 0x1) + 1; // k = 1, v = 2 - - const int NH = N * head_size; - const int NHS = NH * S; - - qkv += (n * head_size + (s * M + m) * NH + b * M * NHS); - if (biases) { - biases += (m * NH + n * head_size); - } - - const int MsH = max_sequence_length * head_size; - const int NMsH = N * MsH; - const int BNMsH = B * NMsH; - present += ((past_sequence_length + s) * head_size + n * MsH + b * NMsH + (m - 1) * BNMsH); - - for (int h = threadIdx.x; h < head_size; h += blockDim.x) { - T bias = (biases ? biases[h] : (T)0.0f); - present[h] = qkv[h] + bias; - } -} - -// qkv buffer is merged tensor of shape (B,S,3,N,H), k v is the second/third of the 3. -// bias is of shape (3, NxH) or nullptr -// append to present of (2, B, N, (P..T) of M, H), -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) { - assert(head_size <= (1 << 30)); - - int64_t nh = (int64_t)head_size * num_heads; - if (nh <= max_threads_per_block) { - const dim3 grid(sequence_length, batch_size, 2); // 2 for k and v - const dim3 block(max_threads_per_block / num_heads, num_heads, 1); - - AddBiasTransAppendKvToPresentSmall<<>>( - qkv_buffer, biases, present, head_size, past_sequence_length, max_sequence_length); - } else { - const dim3 grid(num_heads, sequence_length, batch_size * 2); // 2 for k and v - const dim3 block(std::min(head_size, max_threads_per_block), 1, 1); - AddBiasTransAppendKvToPresent<<>>( - qkv_buffer, biases, present, head_size, past_sequence_length, max_sequence_length); - } - - return CUDA_CALL(cudaGetLastError()); -} +Status FusedTrtCrossAttention( + cudaStream_t stream, + contrib::AttentionParameters& parameters, + AttentionData& data) { + assert(data.qkv_format == AttentionQkvFormat::Q_KV_BSNH_BSN2H); -template Status LaunchAddBiasTransAppendKvToPresent(cudaStream_t stream, - const int max_sequence_length, - const int total_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* bias, - const float* qkv_buffer, - float* present); - -template Status LaunchAddBiasTransAppendKvToPresent(cudaStream_t stream, - const int max_sequence_length, - const int total_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* bias, - const half* qkv_buffer, - half* present); + // We only enable fused cross attention when there is no key padding mask. + // Otherwise, key have effective batch size 2 * batch_size, which is different from batch_size of query. + assert(data.mask_index == nullptr); -template -Status PrepareQkv(contrib::AttentionParameters& parameters, - AttentionData& data, - cudaStream_t stream, - int max_threads_per_block, - T* q, T* k, T* v, AttentionQkvFormat& qkv_format) { const int batch_size = parameters.batch_size; const int sequence_length = parameters.sequence_length; - const int kv_sequence_length = parameters.kv_sequence_length; - const int num_heads = parameters.num_heads; - const int qk_head_size = parameters.head_size; - const int v_head_size = parameters.v_head_size; - const bool past_present_share_buffer = parameters.past_present_share_buffer; - void* fused_runner = data.fused_runner; - bool use_memory_efficient_attention = data.use_memory_efficient_attention; - - T* qkv = data.workspace; + int* q_sequence_offset = GetCumulatedSequenceLength(data.cumulated_sequence_length_q_cache, + data.mask_index, batch_size, + sequence_length, stream, + data.scratch); - bool use_fused_kernel = (nullptr != fused_runner && !parameters.is_unidirectional); - bool use_fused_causal = (nullptr != fused_runner && parameters.is_unidirectional); - - // Default format for memory efficient attention. - // When there is past state, the format shall be BxNxSxH, so we disable memory efficient attention when there is past. DUMP_TENSOR_INIT(); - if (nullptr != data.gemm_buffer) { - if (data.bias == nullptr) { - assert(nullptr == fused_runner); - // For quantized attention, bias has been added so only need transpose here. - // gemm_buffer should be BxSx3xNxH => qkv: 3xBxNxSxH - assert(qk_head_size == v_head_size); - int matrix_to_trans = (past_present_share_buffer ? 1 : 3); - ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, matrix_to_trans, sequence_length, batch_size, qk_head_size, num_heads, - max_threads_per_block, false, data.gemm_buffer, qkv, 3)); - qkv_format = AttentionQkvFormat::Q_K_V_BNSH; - } else { - // For fused TRT attention, transpose qkv to BxSxNx3xH (format 2) - // For memory efficient attention, transpose to 3xBxSxNxH (format 3) - // For unfused kernel, transpose to 3xBxNxSxH (format 1) - // For fused causal kernel, use format 1 since we need have K and V to update present state, - // at the same time, we update gemm_buffer BxSx3xNxH with bias which is used as input for fused causal kernel. - const int format = (use_fused_kernel ? 2 : (use_memory_efficient_attention ? 3 : 1)); - qkv_format = use_fused_kernel - ? AttentionQkvFormat::QKV_BSN3H - : (use_memory_efficient_attention - ? AttentionQkvFormat::Q_K_V_BSNH - : (use_fused_causal ? AttentionQkvFormat::Q_K_V_BNSH_QKV_BS3NH : AttentionQkvFormat::Q_K_V_BNSH)); - - // For fused causal, we will update gemm_buffer with bias directly. - T* qkv_add_bias = use_fused_causal ? data.gemm_buffer : nullptr; - - int matrix_to_transpose = ((format == AttentionQkvFormat::Q_K_V_BNSH && past_present_share_buffer) ? 1 : 3); - // format 1: BxSx(NH + NH + NH_v) => BxNxSxH + BxNxSxH + BxNxSxH_v - // format 2: BxSx(NH + NH + NH) => BxSxNx(H + H + H) - LaunchAddBiasTranspose(stream, matrix_to_transpose, format, max_threads_per_block, - batch_size, sequence_length, num_heads, qk_head_size, - data.gemm_buffer, data.bias, qkv, true, v_head_size, qkv_add_bias, - 3, parameters.do_rotary, parameters.original_past_sequence_length); - } - } - // attention with past/present state - else if (data.past_key != nullptr || data.present_key != nullptr) { - if (data.bias == nullptr) { - // cross attention with past state - if (data.past_key != nullptr && data.present_key == nullptr) { - assert(data.past_value != nullptr); - assert(data.query != nullptr); - assert(data.key == nullptr); - assert(data.value == nullptr); - ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, 1, sequence_length, batch_size, qk_head_size, num_heads, - max_threads_per_block, false, data.query, q)); - } - // cross attention with present state or self attention with present state - else if (data.past_key == nullptr && data.present_key != nullptr) { - assert(data.past_value == nullptr); - assert(data.present_value != nullptr); - assert(data.query != nullptr); - assert(data.key != nullptr); - assert(data.value != nullptr); - - // TODO: supporting packed qkv for self attention may benefit performance - ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, 1, sequence_length, batch_size, qk_head_size, num_heads, - max_threads_per_block, false, data.query, q)); - - // TODO: supporting packed kv for cross attention may benefit performance - ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, 1, kv_sequence_length, batch_size, qk_head_size, num_heads, - max_threads_per_block, false, data.key, data.present_key)); - ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, 1, kv_sequence_length, batch_size, v_head_size, num_heads, - max_threads_per_block, false, data.value, data.present_value)); - } - // self attention with past and present state - else { - assert(data.past_key != nullptr); - assert(data.past_value != nullptr); - assert(data.present_key != nullptr); - assert(data.present_value != nullptr); - assert(data.query != nullptr); - assert(data.key != nullptr); - assert(data.value != nullptr); - // TODO: supporting packed qkv for self attention may benefit performance - ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, 1, sequence_length, batch_size, qk_head_size, num_heads, - max_threads_per_block, false, data.query, q)); - ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, 1, kv_sequence_length, batch_size, qk_head_size, num_heads, - max_threads_per_block, false, data.key, k)); - ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, 1, kv_sequence_length, batch_size, v_head_size, num_heads, - max_threads_per_block, false, data.value, v)); - } - qkv_format = AttentionQkvFormat::Q_K_V_BNSH; - } -#if USE_FLASH_ATTENTION - // When past_key/past_value are inputted directly as key/value and there is no present_key/present_value - else if (use_memory_efficient_attention && data.past_key != nullptr && data.past_value != nullptr && parameters.pass_past_in_kv) { - // Transpose past_key and past_value to use memory efficient attention - - // past_key (BxNxSxH) => temp_k_workspace (BxSxNxH) - ORT_RETURN_IF_ERROR(LaunchTransCtx(stream, kv_sequence_length, batch_size, qk_head_size, num_heads, - max_threads_per_block, false, data.past_key, data.temp_k_workspace)); - // past_value (BxNxSxH_v) => temp_v_workspace (BxSxNxH_v) - ORT_RETURN_IF_ERROR(LaunchTransCtx(stream, kv_sequence_length, batch_size, qk_head_size, num_heads, - max_threads_per_block, false, data.past_value, data.temp_v_workspace)); - - // query => q, temp_k_workspace => k, temp_v_workspace => v - LaunchAddBias(stream, max_threads_per_block, - batch_size, sequence_length, kv_sequence_length, - num_heads, qk_head_size, v_head_size, - data.bias, data.query, data.temp_k_workspace, data.temp_v_workspace, q, k, v); - - DUMP_TENSOR_D("q(BSNH)", q, batch_size * sequence_length, num_heads, qk_head_size); - DUMP_TENSOR_D("k(BSNH)", k, batch_size * kv_sequence_length, num_heads, qk_head_size); - DUMP_TENSOR_D("v(BSNH)", v, batch_size * kv_sequence_length, num_heads, v_head_size); - qkv_format = AttentionQkvFormat::Q_K_V_BSNH; - - data.past_key = nullptr; - data.past_value = nullptr; - } - // When there is no past_key/past_value and there is present_key/present_value (e.g. get initial kv to use as past_kv in the next iteration) - else if (use_memory_efficient_attention && data.present_key != nullptr && data.present_value != nullptr) { - // Use memory efficient attention kernel - LaunchAddBias(stream, max_threads_per_block, - batch_size, sequence_length, kv_sequence_length, - num_heads, qk_head_size, v_head_size, - data.bias, data.query, data.key, data.value, q, data.temp_k_workspace, data.temp_v_workspace); - - // temp_k_workspace (BxSxNxH) => present_k (BxNxSxH) - ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, 1, kv_sequence_length, batch_size, qk_head_size, num_heads, - max_threads_per_block, false, data.temp_k_workspace, data.present_key)); - - // temp_v_workspace (BxSxNxH_v) => present_v (BxNxSxH_v) - ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, 1, kv_sequence_length, batch_size, v_head_size, num_heads, - max_threads_per_block, false, data.temp_v_workspace, data.present_value)); - - DUMP_TENSOR_D("q(BSNH)", q, batch_size * sequence_length, num_heads, qk_head_size); - DUMP_TENSOR_D("k(BSNH)", data.temp_k_workspace, batch_size * kv_sequence_length, num_heads, qk_head_size); - DUMP_TENSOR_D("v(BSNH)", data.temp_v_workspace, batch_size * kv_sequence_length, num_heads, v_head_size); - qkv_format = AttentionQkvFormat::Q_K_V_BSNH; - } -#endif - else { - // Use unfused kernel for Q, use unfused kernel for K and V if needed - constexpr int format = 0; - // Query (BxSxNxH) => Q (BxNxSxH) - LaunchAddBiasTranspose(stream, 1, format, max_threads_per_block, - batch_size, sequence_length, num_heads, qk_head_size, - data.query, data.bias, q, - true, -1); - - if (!parameters.pass_past_in_kv) { - T* k_dest = (data.past_key == nullptr && data.present_key != nullptr) ? data.present_key : k; - T* v_dest = (data.past_value == nullptr && data.present_value != nullptr) ? data.present_value : v; - - // Key (BxLxNxH) => K (BxNxLxH) - LaunchAddBiasTranspose(stream, 1, format, max_threads_per_block, - batch_size, kv_sequence_length, num_heads, qk_head_size, - data.key, data.bias + num_heads * qk_head_size, k_dest, - true, -1); - - // Value (BxLxNxH_v) => V (BxNxLxH_v) - LaunchAddBiasTranspose(stream, 1, format, max_threads_per_block, - batch_size, kv_sequence_length, num_heads, v_head_size, - data.value, data.bias + 2 * num_heads * qk_head_size, v_dest, - true, -1); - - DUMP_TENSOR_D("q(BNSH)", q, batch_size * num_heads, sequence_length, qk_head_size); - DUMP_TENSOR_D("k(BNSH)", k_dest, batch_size * num_heads, kv_sequence_length, qk_head_size); - DUMP_TENSOR_D("v(BNSH)", v_dest, batch_size * num_heads, kv_sequence_length, v_head_size); - } - qkv_format = AttentionQkvFormat::Q_K_V_BNSH; - } - } else if (data.key == nullptr) { // gemm_buffer == nullptr and packed qkv - assert(data.bias == nullptr); - assert(qk_head_size == v_head_size); + DUMP_TENSOR_D("q_sequence_offset", q_sequence_offset, 1, batch_size + 1); - DUMP_TENSOR_D("packed_qkv", data.query, batch_size * sequence_length, num_heads, 3, qk_head_size); - - if (use_memory_efficient_attention) { - // unpack qkv to BSNH. Note that there is no bias so we need not output query to q. - constexpr int format = 4; - T* qkv_add_bias = nullptr; - LaunchAddBiasTranspose(stream, 3, format, max_threads_per_block, - batch_size, sequence_length, num_heads, qk_head_size, - data.query, data.bias, qkv, - true, v_head_size, qkv_add_bias, 3); - DUMP_TENSOR_D("q(BSNH)", q, batch_size * sequence_length, num_heads, qk_head_size); - DUMP_TENSOR_D("k(BSNH)", k, batch_size * kv_sequence_length, num_heads, qk_head_size); - DUMP_TENSOR_D("v(BSNH)", v, batch_size * kv_sequence_length, num_heads, v_head_size); - qkv_format = AttentionQkvFormat::Q_K_V_BSNH; - } else { - if (!use_fused_kernel) { - return ORT_MAKE_STATUS(ONNXRUNTIME, NOT_IMPLEMENTED, "packed QKV format is not implemented for current GPU. Please disable it in fusion options."); - } - - qkv_format = AttentionQkvFormat::QKV_BSN3H; - } - } else if (data.value == nullptr) { // gemm_buffer == nullptr and packed kv - // TODO: unpack kv to BNSH for unfused kernel so that we can remove the following constraint. - // CheckInputs verified this constraint. - assert(data.bias == nullptr); - assert(qk_head_size == v_head_size); - - DUMP_TENSOR_D("packed_kv", data.key, batch_size * kv_sequence_length, num_heads, 2, qk_head_size); - - if (use_memory_efficient_attention) { - // unpack kv to BSNH. Note that there is no bias so we need not output query to q. - constexpr int format = 4; - T* qkv_add_bias = nullptr; - const T* kv_bias = (data.bias == nullptr ? data.bias : data.bias + parameters.hidden_size); - LaunchAddBiasTranspose(stream, 2, format, max_threads_per_block, - batch_size, kv_sequence_length, num_heads, qk_head_size, - data.key, kv_bias, k, - true, v_head_size, qkv_add_bias, 2); - DUMP_TENSOR_D("k(BSNH)", k, batch_size * kv_sequence_length, num_heads, qk_head_size); - DUMP_TENSOR_D("v(BSNH)", v, batch_size * kv_sequence_length, num_heads, v_head_size); - qkv_format = AttentionQkvFormat::Q_K_V_BSNH; - } else { - if (data.fused_cross_attention_kernel == nullptr) { - return ORT_MAKE_STATUS(ONNXRUNTIME, NOT_IMPLEMENTED, "packed KV format is not implemented for current GPU. Please disable packed kv in fusion options."); - } - - qkv_format = AttentionQkvFormat::Q_KV_BSNH_BSN2H; - } - } else { // gemm_buffer == nullptr and not packed - assert(data.query != nullptr && data.key != nullptr && data.value != nullptr && data.bias != nullptr); - - DUMP_TENSOR_D("query", data.query, batch_size * sequence_length, num_heads, qk_head_size); - DUMP_TENSOR_D("query_bias", data.bias, num_heads, qk_head_size); - DUMP_TENSOR_D("key", data.key, batch_size * kv_sequence_length, num_heads, qk_head_size); - DUMP_TENSOR_D("key_bias", data.bias + num_heads * qk_head_size, num_heads, qk_head_size); - DUMP_TENSOR_D("value", data.value, batch_size * kv_sequence_length, num_heads, v_head_size); - DUMP_TENSOR_D("value_bias", data.bias + 2 * num_heads * qk_head_size, num_heads, v_head_size); - - if (data.relative_position_bias != nullptr && parameters.broadcast_res_pos_bias) { - DUMP_TENSOR_D("relative_position_bias", data.relative_position_bias, num_heads, sequence_length, kv_sequence_length); - } - - if (data.mask_index != nullptr && parameters.mask_type == AttentionMaskType::MASK_1D_KEY_SEQ_LEN_START) { - DUMP_TENSOR_D("mask_index", data.mask_index, 3 * batch_size + 2, 1); - } + int* kv_sequence_offset = q_sequence_offset + (GetSequenceOffsetSize(batch_size, false) / sizeof(int)); + kv_sequence_offset = GetCumulatedSequenceLength(data.cumulated_sequence_length_kv_cache, + data.mask_index, batch_size, parameters.kv_sequence_length, stream, + kv_sequence_offset); + CUDA_RETURN_IF_ERROR(cudaGetLastError()); - if (data.fused_cross_attention_kernel != nullptr) { - assert(qk_head_size == v_head_size); + DUMP_TENSOR_D("kv_sequence_offset", kv_sequence_offset, 1, batch_size + 1); - // For fused cross attention, besides adding bias, K and V needed to be packed: - // K (BxSxNxH), V (BxSxNxH) => BxSxNx2xH - LaunchAddBiasTransposeTrt( - stream, max_threads_per_block, - batch_size, sequence_length, - num_heads, qk_head_size, - data.bias, data.query, data.key, data.value, qkv, true, kv_sequence_length); + FusedMultiHeadCrossAttentionKernel const* cross_attention_kernel = + reinterpret_cast(data.fused_cross_attention_kernel); - qkv_format = AttentionQkvFormat::Q_KV_BSNH_BSN2H; - } -#if USE_FLASH_ATTENTION - else if (use_memory_efficient_attention) { - LaunchAddBias(stream, max_threads_per_block, - batch_size, sequence_length, kv_sequence_length, - num_heads, qk_head_size, v_head_size, - data.bias, data.query, data.key, data.value, q, k, v); - - DUMP_TENSOR_D("q(BSNH)", q, batch_size * sequence_length, num_heads, qk_head_size); - DUMP_TENSOR_D("k(BSNH)", k, batch_size * kv_sequence_length, num_heads, qk_head_size); - DUMP_TENSOR_D("v(BSNH)", v, batch_size * kv_sequence_length, num_heads, v_head_size); - qkv_format = AttentionQkvFormat::Q_K_V_BSNH; - } -#endif - else if (use_fused_kernel) { - assert(qk_head_size == v_head_size); - - // Q (BxSxNxH), K (BxSxNxH), V (BxSxNxH) => BxSxNx(H + H + H) - LaunchAddBiasTransposeTrt( - stream, max_threads_per_block, - batch_size, sequence_length, - num_heads, qk_head_size, - data.bias, data.query, data.key, data.value, qkv, false, kv_sequence_length); - DUMP_TENSOR_D("qkv(BSN3H)", qkv, batch_size, sequence_length, num_heads, 2 * qk_head_size + v_head_size); - - qkv_format = AttentionQkvFormat::QKV_BSN3H; - } else { // unfused kernel - ORT_ENFORCE(!use_fused_causal, "MultiHeadAttention has not enabled fused causal"); - - // Query (BxSxNxH) => Q (BxNxSxH) - constexpr int format = 0; - LaunchAddBiasTranspose(stream, 1, format, max_threads_per_block, - batch_size, sequence_length, num_heads, qk_head_size, - data.query, data.bias, q, - true, -1); - - // Key (BxLxNxH) => K (BxNxLxH) - LaunchAddBiasTranspose(stream, 1, format, max_threads_per_block, - batch_size, kv_sequence_length, num_heads, qk_head_size, - data.key, data.bias + num_heads * qk_head_size, k, - true, -1); - - // Value (BxLxNxH_v) => K (BxNxLxH_v) - LaunchAddBiasTranspose(stream, 1, format, max_threads_per_block, - batch_size, kv_sequence_length, num_heads, v_head_size, - data.value, data.bias + 2 * num_heads * qk_head_size, v, - true, -1); - - DUMP_TENSOR_D("q(BNSH)", q, batch_size * num_heads, sequence_length, qk_head_size); - DUMP_TENSOR_D("k(BNSH)", k, batch_size * num_heads, kv_sequence_length, qk_head_size); - DUMP_TENSOR_D("v(BNSH)", v, batch_size * num_heads, kv_sequence_length, v_head_size); - qkv_format = AttentionQkvFormat::Q_K_V_BNSH; - } + // When there is no bias, we can directly use q and packed kv from inputs. + void const* query = data.q; + void const* packed_kv = data.k; + if (data.value == nullptr && data.bias == nullptr) { + query = data.query; + packed_kv = data.key; } - CUDA_RETURN_IF_ERROR(cudaGetLastError()); + run_fused_cross_attention( + query, // Q + packed_kv, // packed KV + q_sequence_offset, // cumulated sequence length of Q + kv_sequence_offset, // cumulated sequence length of KV + data.output, // output + cross_attention_kernel, // kernels + batch_size, // batch size + parameters.num_heads, // number of heads + parameters.head_size, // head size of Q/K/V + sequence_length, // sequence length of Q + parameters.kv_sequence_length, // sequence length of KV + stream); + + DUMP_TENSOR("trt cross output", data.output, + batch_size, sequence_length, parameters.num_heads, parameters.v_head_size); return Status::OK(); } +template <> +Status FusedTrtCrossAttention( + cudaStream_t stream, + contrib::AttentionParameters& parameters, + AttentionData& data) { + return ORT_MAKE_STATUS(ONNXRUNTIME, StatusCode::NOT_IMPLEMENTED, + "Trt fused cross attention does not support float tensor"); +} + template -Status QkvToContext( - const cudaDeviceProp& device_prop, - cublasHandle_t& cublas, +Status FusedTrtSelfAttention( cudaStream_t stream, contrib::AttentionParameters& parameters, AttentionData& data) { - constexpr size_t element_size = sizeof(T); - const int max_threads_per_block = device_prop.maxThreadsPerBlock; const int batch_size = parameters.batch_size; const int sequence_length = parameters.sequence_length; - const int kv_sequence_length = parameters.kv_sequence_length; - const int total_sequence_length = parameters.total_sequence_length; - const int num_heads = parameters.num_heads; - const int qk_head_size = parameters.head_size; - const int v_head_size = parameters.v_head_size; - const bool past_present_share_buffer = parameters.past_present_share_buffer; - const float mask_filter_value = parameters.mask_filter_value; - void* fused_runner = data.fused_runner; + const bool causal = parameters.is_unidirectional; - // At most one fused kernel is enabled. - assert(int(data.use_memory_efficient_attention) + int(fused_runner != nullptr) + int(data.fused_cross_attention_kernel != nullptr) <= 1); - - const int batches = batch_size * num_heads; - - T* qkv = nullptr; - T* q = nullptr; - T* k = nullptr; - T* v = nullptr; - T* scratch1 = data.workspace; - if (data.has_qkv_workspace) { - const int size_per_batch_q = sequence_length * qk_head_size; - const int size_per_batch_k = kv_sequence_length * qk_head_size; - const int size_per_batch_v = kv_sequence_length * v_head_size; - const size_t elements_q = static_cast(batches) * static_cast(size_per_batch_q); - const size_t elements_k = static_cast(batches) * static_cast(size_per_batch_k); - const size_t elements_v = static_cast(batches) * static_cast(size_per_batch_v); - qkv = data.workspace; - q = qkv; - k = q + elements_q; - v = k + elements_k; - scratch1 = v + elements_v; - } - - bool use_fused_kernel = (nullptr != fused_runner && !parameters.is_unidirectional); - bool use_fused_causal = (nullptr != fused_runner && parameters.is_unidirectional); - - AttentionQkvFormat qkv_format = AttentionQkvFormat::Q_K_V_BSNH; - ORT_RETURN_IF_ERROR(PrepareQkv(parameters, data, stream, max_threads_per_block, q, k, v, qkv_format)); - - int present_size_per_batch_k = 0; - int present_size_per_batch_v = 0; - if (!past_present_share_buffer) { - // 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. - present_size_per_batch_k = total_sequence_length * qk_head_size; - present_size_per_batch_v = total_sequence_length * v_head_size; - - if (nullptr != data.present) { - assert(qkv_format == AttentionQkvFormat::Q_K_V_BNSH || 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, k, data.present)); - - // Update pointers to present_k and present_v. - k = data.present; - v = data.present + batches * present_size_per_batch_k; - } + int* sequence_offset = reinterpret_cast(data.scratch); - if (nullptr != data.past_key || nullptr != data.present_key) { - if (nullptr != data.past_key && nullptr == data.present_key) { - k = const_cast(data.past_key); - v = const_cast(data.past_value); - } else if (nullptr == data.past_key && nullptr != data.present_key) { - if (qkv_format == AttentionQkvFormat::Q_K_V_BNSH) { - k = data.present_key; - v = data.present_value; - } - else { - assert(qkv_format == AttentionQkvFormat::Q_K_V_BSNH); - k = data.temp_k_workspace; - v = data.temp_v_workspace; - } - } else if (parameters.pass_past_in_kv) { - // past_key and past_value are used directly as key and value in attention computations - k = const_cast(data.past_key); - v = const_cast(data.past_value); - - // This path has a memory copy from past_key and past_value to present_key and present_value - // Avoid this path since the memory copy is unnecessary because past_key == present_key and - // past_value == present_value - int64_t k_size = (int64_t)batch_size * num_heads * parameters.total_sequence_length * qk_head_size; - int64_t v_size = (int64_t)batch_size * num_heads * parameters.total_sequence_length * v_head_size; - cudaMemcpyAsync(data.present_key, data.past_key, k_size * sizeof(T), cudaMemcpyDeviceToDevice, stream); - cudaMemcpyAsync(data.present_value, data.past_value, v_size * sizeof(T), cudaMemcpyDeviceToDevice, stream); - } else { - ORT_RETURN_IF_ERROR( - LaunchConcatTensorToTensor(stream, parameters.total_sequence_length, sequence_length, batch_size, qk_head_size, num_heads, - max_threads_per_block, 1, data.past_key, k, data.present_key)); - ORT_RETURN_IF_ERROR( - LaunchConcatTensorToTensor(stream, parameters.total_sequence_length, sequence_length, batch_size, v_head_size, num_heads, - max_threads_per_block, 1, data.past_value, v, data.present_value)); - // Update pointers to present_k and present_v. - k = data.present_key; - v = data.present_value; - } - } + DUMP_TENSOR_INIT(); + if (parameters.mask_type == AttentionMaskType::MASK_2D_KEY_PADDING) { + DUMP_TENSOR_D("mask", reinterpret_cast(data.mask_index), batch_size, sequence_length); + LaunchTrtSequenceOffset2d(sequence_offset, data.mask_index, batch_size, sequence_length, stream); } else { - assert(qk_head_size == v_head_size); - assert(data.fused_cross_attention_kernel == nullptr); - assert(!use_fused_kernel); - assert(data.gemm_buffer != nullptr); - assert(!data.use_memory_efficient_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); - } - - // 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, - use_fused_causal ? nullptr : data.bias, // For fused causal, bias has been added to gemm_buffer - data.gemm_buffer, data.present)); - - present_size_per_batch_k = parameters.max_sequence_length * qk_head_size; - present_size_per_batch_v = present_size_per_batch_k; - k = data.present; - v = data.present + batches * present_size_per_batch_k; + sequence_offset = GetCumulatedSequenceLength(data.cumulated_sequence_length_q_cache, + data.mask_index, batch_size, sequence_length, stream, + sequence_offset); } + DUMP_TENSOR_D("sequence_offset", sequence_offset, 1, (data.mask_index != nullptr ? 2 : 1) * batch_size + 1); + CUDA_RETURN_IF_ERROR(cudaGetLastError()); - // Q, K and V are ready now - DUMP_TENSOR_INIT(); - - if (data.fused_cross_attention_kernel != nullptr) { - assert(qkv_format == AttentionQkvFormat::Q_KV_BSNH_BSN2H); - - // We only enable fused cross attention when there is no key padding mask. - // Otherwise, key have effective batch size 2 * batch_size, which is different from batch_size of query. - assert(data.mask_index == nullptr); - - int* q_sequence_offset = GetCumulatedSequenceLength(data.cumulated_sequence_length_q_cache, - data.mask_index, batch_size, sequence_length, stream, - scratch1); + FusedMHARunnerFP16v2* fused_fp16_runner = reinterpret_cast(data.fused_runner); - DUMP_TENSOR_D("q_sequence_offset", q_sequence_offset, 1, batch_size + 1); + const int S = causal ? sequence_length : fused_fp16_runner->getSFromMaxSeqLen(sequence_length); - int* kv_sequence_offset = q_sequence_offset + (GetSequenceOffsetSize(batch_size, false) / sizeof(int)); - kv_sequence_offset = GetCumulatedSequenceLength(data.cumulated_sequence_length_kv_cache, - data.mask_index, batch_size, kv_sequence_length, stream, - kv_sequence_offset); - CUDA_RETURN_IF_ERROR(cudaGetLastError()); + // B = 2 * batch_size when there is padding in input, and B = batch_size when padding is removed. + const int B = (nullptr == data.mask_index ? batch_size : 2 * batch_size); - DUMP_TENSOR_D("kv_sequence_offset", kv_sequence_offset, 1, batch_size + 1); + fused_fp16_runner->setup(S, B); - FusedMultiHeadCrossAttentionKernel const* cross_attention_kernel = - reinterpret_cast(data.fused_cross_attention_kernel); + if (!causal) { + assert(data.qkv_format == AttentionQkvFormat::QKV_BSN3H); - // When there is no bias, we can directly use q and packed kv from inputs. - void const* query = q; - void const* packed_kv = k; - if (data.value == nullptr && data.bias == nullptr) { - query = data.query; - packed_kv = data.key; + // When there is no bias, we can directly use packed qkv from inputs. + void const* packed_qkv = data.q; + if (data.query != nullptr && data.key == nullptr && data.bias == nullptr) { + packed_qkv = data.query; } - run_fused_cross_attention( - query, // Q - packed_kv, // packed KV - q_sequence_offset, // cumulated sequence length of Q - kv_sequence_offset, // cumulated sequence length of KV - data.output, // output - cross_attention_kernel, // kernels - batch_size, // batch size - num_heads, // number of heads - qk_head_size, // head size of Q/K/V - sequence_length, // sequence length of Q - kv_sequence_length, // sequence length of KV - stream); - - DUMP_TENSOR("trt cross output", data.output, batch_size * sequence_length, num_heads, v_head_size); - return Status::OK(); + fused_fp16_runner->run(packed_qkv, sequence_offset, data.output, stream); + DUMP_TENSOR("fused output", data.output, + batch_size, sequence_length, parameters.num_heads, parameters.v_head_size); + } else { + assert(data.qkv_format == AttentionQkvFormat::Q_K_V_BNSH_QKV_BS3NH); + fused_fp16_runner->run(data.gemm_buffer, sequence_offset, data.output, stream); + DUMP_TENSOR("fused causal output", data.output, + batch_size, sequence_length, parameters.num_heads, parameters.v_head_size); } + return Status::OK(); +} - // Run TRT fused attention. - if (use_fused_kernel || use_fused_causal) { - int* sequence_offset = reinterpret_cast(scratch1); - if (parameters.mask_type == AttentionMaskType::MASK_2D_KEY_PADDING) { - DUMP_TENSOR_D("mask", reinterpret_cast(data.mask_index), batch_size, sequence_length); - LaunchTrtSequenceOffset2d(sequence_offset, data.mask_index, batch_size, sequence_length, stream); - } else { - sequence_offset = GetCumulatedSequenceLength(data.cumulated_sequence_length_q_cache, - data.mask_index, batch_size, sequence_length, stream, - sequence_offset); - } - DUMP_TENSOR_D("sequence_offset", sequence_offset, 1, (data.mask_index != nullptr ? 2 : 1) * batch_size + 1); - CUDA_RETURN_IF_ERROR(cudaGetLastError()); +// Template Specialization for float type +template <> +Status FusedTrtSelfAttention( + cudaStream_t stream, + contrib::AttentionParameters& parameters, + AttentionData& data) { + return ORT_MAKE_STATUS(ONNXRUNTIME, StatusCode::NOT_IMPLEMENTED, + "Trt fused attention does not support float tensor"); +} - FusedMHARunnerFP16v2* fused_fp16_runner = reinterpret_cast(fused_runner); +#if USE_FLASH_ATTENTION +template +Status FlashAttention( + const cudaDeviceProp& device_prop, + cudaStream_t stream, + contrib::AttentionParameters& parameters, + AttentionData& data, + float scale) { + assert(data.qkv_format == AttentionQkvFormat::Q_K_V_BSNH); + assert(nullptr == data.mask_index); + assert(nullptr == data.relative_position_bias); + assert(parameters.head_size == parameters.v_head_size); + + void* query = reinterpret_cast(data.q); + void* key = reinterpret_cast(data.k); + void* value = reinterpret_cast(data.v); + // For packed KV, we can use query input directly. + if (data.gemm_buffer == nullptr && data.key != nullptr && data.value == nullptr && data.bias == nullptr) { + query = reinterpret_cast(const_cast(data.query)); + } - const int S = use_fused_causal ? sequence_length : fused_fp16_runner->getSFromMaxSeqLen(sequence_length); + DUMP_TENSOR_INIT(); + DUMP_TENSOR_D("q(BSNH)", reinterpret_cast(query), + parameters.batch_size, parameters.sequence_length, parameters.num_heads, parameters.head_size); + DUMP_TENSOR_D("k(BSNH)", data.k, + parameters.batch_size, parameters.total_sequence_length, parameters.num_heads, parameters.head_size); + DUMP_TENSOR_D("v(BSNH)", data.v, + parameters.batch_size, parameters.total_sequence_length, + parameters.num_heads, parameters.v_head_size); + + ORT_RETURN_IF_ERROR(onnxruntime::flash::mha_fwd( + device_prop, stream, query, key, value, data.output, reinterpret_cast(data.scratch), + parameters.batch_size, parameters.num_heads, parameters.num_heads, parameters.head_size, + parameters.sequence_length, parameters.total_sequence_length, scale, parameters.is_unidirectional)); + + DUMP_TENSOR("flash attention output", data.output, + parameters.batch_size, parameters.sequence_length, parameters.num_heads, parameters.v_head_size); - // B = 2 * batch_size when there is padding in input, and B = batch_size when padding is removed. - const int B = (nullptr == data.mask_index ? batch_size : 2 * batch_size); + return Status::OK(); +} - fused_fp16_runner->setup(S, B); +template <> +Status FlashAttention( + const cudaDeviceProp& device_prop, + cudaStream_t stream, + contrib::AttentionParameters& parameters, + AttentionData& data, + float scale) { + return ORT_MAKE_STATUS(ONNXRUNTIME, StatusCode::NOT_IMPLEMENTED, "flash attention does not support float tensor"); +} +#endif - if (use_fused_kernel) { - assert(qkv_format == AttentionQkvFormat::QKV_BSN3H); +#if USE_MEMORY_EFFICIENT_ATTENTION +template +Status EfficientAttention( + const cudaDeviceProp& device_prop, + cudaStream_t stream, + contrib::AttentionParameters& parameters, + AttentionData& data, + float scale) { + // We only enable fused cross attention when there is no key padding mask. + // Otherwise, key have effective batch size 2 * batch_size, which is different from batch_size of query. + assert(data.qkv_format == AttentionQkvFormat::Q_K_V_BSNH); + + const void* query = data.q; + const void* key = data.k; + const void* value = data.v; + // For packed KV, we can use query input directly. + if (data.gemm_buffer == nullptr && data.key != nullptr && data.value == nullptr) { + assert(data.bias == nullptr); + query = data.query; + } - // When there is no bias, we can directly use packed qkv from inputs. - void const* packed_qkv = qkv; - if (data.query != nullptr && data.key == nullptr && data.bias == nullptr) { - packed_qkv = data.query; - } + DUMP_TENSOR_INIT(); + DUMP_TENSOR_D("q(BSNH)", reinterpret_cast(query), + parameters.batch_size, parameters.sequence_length, parameters.num_heads, parameters.head_size); + DUMP_TENSOR_D("k(BSNH)", data.k, + parameters.batch_size, parameters.total_sequence_length, parameters.num_heads, parameters.head_size); + DUMP_TENSOR_D("v(BSNH)", data.v, + parameters.batch_size, parameters.total_sequence_length, + parameters.num_heads, parameters.v_head_size); + + MemoryEfficientAttentionParams p; + p.sm = device_prop.major * 10 + device_prop.minor; + p.is_half = sizeof(T) == 2; + p.batch_size = parameters.batch_size; + p.num_heads = parameters.num_heads; + p.sequence_length = parameters.sequence_length; + p.kv_sequence_length = parameters.total_sequence_length; + p.qk_head_size = parameters.head_size; + p.v_head_size = parameters.v_head_size; + p.causal = parameters.is_unidirectional; + p.scale = scale; + p.seqlen_k_ptr = nullptr == data.mask_index + ? nullptr + : const_cast(reinterpret_cast(data.mask_index)); + p.seqstart_q_ptr = nullptr == data.mask_index + ? nullptr + : const_cast(reinterpret_cast( + data.mask_index + parameters.batch_size)); + p.seqstart_k_ptr = nullptr == data.mask_index + ? nullptr + : const_cast(reinterpret_cast( + data.mask_index + 2 * parameters.batch_size + 1)); + p.query = query; + p.key = key; + p.value = value; + p.attn_bias = nullptr == data.relative_position_bias ? nullptr : data.relative_position_bias; + p.is_attn_bias_batched = !parameters.broadcast_res_pos_bias; + p.output = data.output; + p.workspace = MemoryEfficientAttentionParams::need_workspace(parameters.v_head_size, sizeof(T) == sizeof(float)) + ? data.scratch + : nullptr; + p.stream = stream; + run_memory_efficient_attention(p); + DUMP_TENSOR("efficient attention output", data.output, + parameters.batch_size, parameters.sequence_length, parameters.num_heads, parameters.v_head_size); - fused_fp16_runner->run(packed_qkv, sequence_offset, data.output, stream); - DUMP_TENSOR("fused output", data.output, batch_size * sequence_length, num_heads, v_head_size); - } else { - assert(qkv_format == AttentionQkvFormat::Q_K_V_BNSH_QKV_BS3NH); - fused_fp16_runner->run(data.gemm_buffer, sequence_offset, data.output, stream); - DUMP_TENSOR("fused causal output", data.output, batch_size * sequence_length, num_heads, v_head_size); - } - return Status::OK(); - } + return Status::OK(); +} +#endif - // For raw attention mask, the scalar 1/sqrt(H) is moved to combine with softmax computation. - const float scale = parameters.scale == 0.0f ? 1.f / sqrt(static_cast(qk_head_size)) - : parameters.scale; +template +Status UnfusedAttention( + const cudaDeviceProp& device_prop, + cublasHandle_t& cublas, + Stream* ort_stream, + contrib::AttentionParameters& parameters, + AttentionData& data, + float scale) { + assert(data.qkv_format == AttentionQkvFormat::Q_K_V_BNSH); -#if USE_FLASH_ATTENTION - if (data.use_memory_efficient_attention) { - // We only enable fused cross attention when there is no key padding mask. - // Otherwise, key have effective batch size 2 * batch_size, which is different from batch_size of query. - assert(qkv_format == AttentionQkvFormat::Q_K_V_BSNH); - - const void* query = q; - const void* key = k; - const void* value = v; - // For packed KV, we can use query input directly. - if (data.gemm_buffer == nullptr && data.key != nullptr && data.value == nullptr) { - assert(data.bias == nullptr); - query = data.query; - } + auto stream = static_cast(ort_stream->GetHandle()); - MemoryEfficientAttentionParams p; - p.sm = device_prop.major * 10 + device_prop.minor; - p.is_half = sizeof(T) == 2; - p.batch_size = parameters.batch_size; - p.num_heads = parameters.num_heads; - p.sequence_length = parameters.sequence_length; - p.kv_sequence_length = parameters.total_sequence_length; - p.qk_head_size = parameters.head_size; - p.v_head_size = parameters.v_head_size; - p.causal = parameters.is_unidirectional; - p.scale = scale; - p.seqlen_k_ptr = nullptr == data.mask_index ? nullptr : const_cast(reinterpret_cast(data.mask_index)); - p.seqstart_q_ptr = nullptr == data.mask_index ? nullptr : const_cast(reinterpret_cast(data.mask_index + batch_size)); - p.seqstart_k_ptr = nullptr == data.mask_index ? nullptr : const_cast(reinterpret_cast(data.mask_index + 2 * batch_size + 1)); - p.query = query; - p.key = key; - p.value = value; - p.attn_bias = nullptr == data.relative_position_bias ? nullptr : data.relative_position_bias; - p.is_attn_bias_batched = !parameters.broadcast_res_pos_bias; - p.output = data.output; - p.workspace = MemoryEfficientAttentionParams::need_workspace(v_head_size, sizeof(T) == sizeof(float)) ? scratch1 : nullptr; - p.stream = stream; - run_memory_efficient_attention(p); - DUMP_TENSOR("cutlass output", data.output, batch_size * sequence_length, num_heads, v_head_size); - return Status::OK(); - } -#endif + const int batch_size = parameters.batch_size; + const int sequence_length = parameters.sequence_length; + const int total_sequence_length = parameters.total_sequence_length; + const int num_heads = parameters.num_heads; + const int qk_head_size = parameters.head_size; + const int v_head_size = parameters.v_head_size; + const int batches = batch_size * num_heads; - // The following are unfused attention. - assert(qkv_format == AttentionQkvFormat::Q_K_V_BNSH); const int* mask_index = data.mask_index; gsl::span& mask_index_dims = data.mask_index_dims; // Raw attention mask could be 2D (BxT) or 3D (BxSxT) or 4D(Bx1xMxM), where M is the max sequence length. bool use_raw_attention_mask = (nullptr != mask_index && mask_index_dims.size() >= 2); - // Compute Q*K' (as K'*Q), scaled by 1/sqrt(H) and store in scratch1: BxNxSxT + // Compute Q*K' (as K'*Q), scaled by 1/sqrt(H) and store in scratch: BxNxSxT // Q: BxNxSxH, K (present_k): BxNxTxH, Q*K': BxNxSxT float one = 1.0f; float zero = 0.f; @@ -903,22 +440,31 @@ Status QkvToContext( cublasSetStream(cublas, stream); - DUMP_TENSOR_D("q[BNSH]", q, batch_size, num_heads, sequence_length, qk_head_size); - DUMP_TENSOR_D("k[BNSH]", k, batch_size, num_heads, total_sequence_length, qk_head_size); + DUMP_TENSOR_INIT(); + DUMP_TENSOR_D("q[BNSH]", data.q, batch_size, num_heads, sequence_length, qk_head_size); + DUMP_TENSOR_D("k[BNSH]", data.k, batch_size, num_heads, total_sequence_length, qk_head_size); + + const int present_sequence_length = parameters.past_present_share_buffer + ? parameters.max_sequence_length + : total_sequence_length; + const int present_size_per_batch_k = present_sequence_length * qk_head_size; + const int present_size_per_batch_v = present_sequence_length * v_head_size; + CUBLAS_RETURN_IF_ERROR(cublasGemmStridedBatchedHelper( cublas, CUBLAS_OP_T, CUBLAS_OP_N, total_sequence_length, sequence_length, qk_head_size, - &alpha, k, qk_head_size, present_size_per_batch_k, - q, qk_head_size, sequence_length * qk_head_size, - &zero, scratch1, total_sequence_length, sequence_length * total_sequence_length, batches, device_prop)); + &alpha, data.k, qk_head_size, present_size_per_batch_k, + data.q, qk_head_size, sequence_length * qk_head_size, + &zero, data.scratch, total_sequence_length, sequence_length * total_sequence_length, batches, device_prop)); - DUMP_TENSOR_D("Q", q, batch_size * num_heads, sequence_length, qk_head_size); - DUMP_TENSOR_D("K", k, batch_size * num_heads, qk_head_size, sequence_length); - DUMP_TENSOR_D("QK", scratch1, batch_size * num_heads, sequence_length, total_sequence_length); + DUMP_TENSOR_D("Q", data.q, batch_size, num_heads, sequence_length, qk_head_size); + DUMP_TENSOR_D("K", data.k, batch_size, num_heads, qk_head_size, sequence_length); + DUMP_TENSOR_D("QK", data.scratch, batch_size, num_heads, sequence_length, total_sequence_length); + constexpr size_t element_size = sizeof(T); const size_t bytes = GetAttentionScratchSize(element_size, batch_size, num_heads, sequence_length, total_sequence_length); - T* scratch2 = scratch1 + (bytes / element_size); + T* scratch2 = data.scratch + (bytes / element_size); // Apply softmax and store result R to scratch2: BxNxSxT if (use_raw_attention_mask) { // 2d, 3d or 4d attention mask @@ -928,13 +474,15 @@ Status QkvToContext( const TransformerOptions* options = TransformerOptions::GetInstance(); bool use_persistent_softmax = options->IsPrecisionMode() && !options->DisablePersistentSoftmax(); - T* persistent_softmax_workspace = scratch1; // replace Q*K' in place with masked score for persistent softmax. + // replace Q*K' in place with masked score for persistent softmax. + T* persistent_softmax_workspace = data.scratch; ORT_RETURN_IF_ERROR( - ComputeSoftmaxWithRawMask(stream, total_sequence_length, sequence_length, batch_size, num_heads, - mask_index, nullptr, data.relative_position_bias, parameters.broadcast_res_pos_bias, - scratch1, scratch2, parameters.is_unidirectional, scale, mask_dimension, - parameters.max_sequence_length, use_persistent_softmax, persistent_softmax_workspace, - mask_filter_value)); + ComputeSoftmaxWithRawMask( + ort_stream, total_sequence_length, sequence_length, batch_size, num_heads, + mask_index, nullptr, data.relative_position_bias, parameters.broadcast_res_pos_bias, + data.scratch, scratch2, parameters.is_unidirectional, scale, mask_dimension, + parameters.max_sequence_length, use_persistent_softmax, persistent_softmax_workspace, + parameters.mask_filter_value)); } else if (nullptr != mask_index) { // 1d mask index assert(mask_index_dims.size() == 1); // mask_index has 1D shape: either (batch_size) or (2*batch_size). Only the later one has start postions. @@ -942,273 +490,123 @@ Status QkvToContext( ORT_RETURN_IF_ERROR(ComputeSoftmaxWithMask1D( stream, total_sequence_length, sequence_length, batch_size, num_heads, mask_index, mask_start, data.relative_position_bias, parameters.broadcast_res_pos_bias, - scratch1, scratch2, parameters.is_unidirectional)); + data.scratch, scratch2, parameters.is_unidirectional)); } else { // no mask ORT_RETURN_IF_ERROR( - ComputeSoftmax(stream, total_sequence_length, sequence_length, batch_size, num_heads, data.relative_position_bias, - parameters.broadcast_res_pos_bias, scratch1, scratch2, parameters.is_unidirectional)); + ComputeSoftmax( + stream, total_sequence_length, sequence_length, batch_size, num_heads, data.relative_position_bias, + parameters.broadcast_res_pos_bias, data.scratch, scratch2, parameters.is_unidirectional)); } - DUMP_TENSOR_D("Softmax", scratch2, batch_size * num_heads, sequence_length, total_sequence_length); - DUMP_TENSOR_D("V", v, batch_size * num_heads, sequence_length, v_head_size); + DUMP_TENSOR_D("Softmax", scratch2, batch_size, num_heads, sequence_length, total_sequence_length); + DUMP_TENSOR_D("V", data.v, batch_size, num_heads, sequence_length, v_head_size); // compute R*V (as V*R), and store in temp_output (space used by Q): BxNxSxH_v - T* temp_output = qkv; + T* temp_output = data.q; CUBLAS_RETURN_IF_ERROR(cublasGemmStridedBatchedHelper( cublas, CUBLAS_OP_N, CUBLAS_OP_N, v_head_size, sequence_length, total_sequence_length, - &one, v, v_head_size, present_size_per_batch_v, + &one, data.v, v_head_size, present_size_per_batch_v, scratch2, total_sequence_length, sequence_length * total_sequence_length, &zero, temp_output, v_head_size, sequence_length * v_head_size, batches, device_prop)); // Temp_output is BxNxSxH_v, transpose to output BxSxNxH_v Status result = LaunchTransCtx(stream, sequence_length, batch_size, v_head_size, num_heads, - max_threads_per_block, false, temp_output, data.output); - DUMP_TENSOR("unfused output", data.output, batch_size * sequence_length, num_heads, v_head_size); + device_prop.maxThreadsPerBlock, false, temp_output, data.output); + DUMP_TENSOR("unfused output", data.output, batch_size, sequence_length, num_heads, v_head_size); return result; } template -Status DecoderQkvToContext( +Status QkvToContext( const cudaDeviceProp& device_prop, - cudaStream_t stream, cublasHandle_t& cublas, - const size_t element_size, - const int batch_size, - const int sequence_length, - const int kv_sequence_length, - const int num_heads, - const int head_size, - const bool static_kv, - const bool use_past, - const bool has_layer_state, - const bool has_key_padding_mask, - const float mask_filter_value, - const T* gemm_query_buffer, - const T* gemm_kv_buffer, - const bool* key_padding_mask, - const T* key_cache, - const T* value_cache, - T* qkv_buffer, - T* workspace_buffer, - T* output, - T* new_key_cache, - T* new_value_cache) { + Stream* ort_stream, + contrib::AttentionParameters& parameters, + AttentionData& data) { + auto stream = static_cast(ort_stream->GetHandle()); const int max_threads_per_block = device_prop.maxThreadsPerBlock; - const int BN = batch_size * num_heads; - const int BHN = BN * head_size; - const int BNS = BN * sequence_length; - const int k_buffer_offset = sequence_length * BHN; - const int v_buffer_offset = (sequence_length + kv_sequence_length) * BHN; - - T* temp_qkv_buffer = workspace_buffer; - - const T* q = qkv_buffer; - // transpose q and copy them to qkv_buffer - ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, 1, sequence_length, batch_size, head_size, num_heads, - max_threads_per_block, true, gemm_query_buffer, qkv_buffer)); - - const T* k = qkv_buffer + k_buffer_offset; - const T* v = qkv_buffer + v_buffer_offset; - if (!has_layer_state || !use_past) { - if (!static_kv) { - // transpose kv and copy them to qkv_buffer - ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, 2, sequence_length, batch_size, head_size, num_heads, - max_threads_per_block, true, gemm_kv_buffer, qkv_buffer + k_buffer_offset)); - } else { - // transpose kv and copy them to qkv_buffer - ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, 2, kv_sequence_length, batch_size, head_size, num_heads, - max_threads_per_block, true, gemm_kv_buffer, qkv_buffer + k_buffer_offset)); - } - } else { - if (!static_kv) { - // transpose kv and copy them to temp_buffer - ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, 2, sequence_length, batch_size, head_size, num_heads, - max_threads_per_block, true, gemm_kv_buffer, temp_qkv_buffer)); - // concat cache-k with k and copy to qkv_buffer - if (nullptr != key_cache) { - ORT_RETURN_IF_ERROR(LaunchConcatTensorToTensor(stream, kv_sequence_length, - sequence_length, batch_size, head_size, num_heads, - max_threads_per_block, 1, - key_cache, - temp_qkv_buffer, - qkv_buffer + k_buffer_offset)); - } - // concat cache-v with v and copy to qkv_buffer - if (nullptr != value_cache) { - ORT_RETURN_IF_ERROR(LaunchConcatTensorToTensor(stream, kv_sequence_length, - sequence_length, batch_size, head_size, num_heads, - max_threads_per_block, 1, - value_cache, - temp_qkv_buffer + k_buffer_offset, - qkv_buffer + v_buffer_offset)); - } + const int batch_size = parameters.batch_size; + const int sequence_length = parameters.sequence_length; + const int total_sequence_length = parameters.total_sequence_length; + const int num_heads = parameters.num_heads; + const int qk_head_size = parameters.head_size; + const int v_head_size = parameters.v_head_size; + void* fused_runner = data.fused_runner; + + // At most one fused kernel is enabled. + assert((int(data.use_flash_attention) + + int(data.use_memory_efficient_attention) + + int(fused_runner != nullptr) + + int(data.fused_cross_attention_kernel != nullptr)) <= 1); + + 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, + sequence_length, total_sequence_length, parameters.pass_past_in_kv, + 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 (has_layer_state) { - if (use_past && static_kv) { - CUDA_RETURN_IF_ERROR(cudaMemcpyAsync(new_key_cache, key_cache, kv_sequence_length * BHN * sizeof(T), - cudaMemcpyDeviceToDevice, stream)); - CUDA_RETURN_IF_ERROR(cudaMemcpyAsync(new_value_cache, value_cache, kv_sequence_length * BHN * sizeof(T), - cudaMemcpyDeviceToDevice, stream)); - } else { - CUDA_RETURN_IF_ERROR(cudaMemcpyAsync(new_key_cache, k, kv_sequence_length * BHN * sizeof(T), - cudaMemcpyDeviceToDevice, stream)); - CUDA_RETURN_IF_ERROR(cudaMemcpyAsync(new_value_cache, v, kv_sequence_length * BHN * sizeof(T), - cudaMemcpyDeviceToDevice, stream)); + 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); } - } - // scratch1: BxNxSxL buffer - // scratch2: BxNxSxL buffer - // scratch3: BxNxSxH buffer - T* scratch1 = temp_qkv_buffer + 3 * BHN * sequence_length; - T* scratch2 = scratch1 + BNS * kv_sequence_length; - T* scratch3 = scratch2 + BNS * kv_sequence_length; - - // compute Q*K' (as K'*Q), scaled by 1/sqrt(H) and store in scratch1: BxNxSxL - // Q: BxNxSxH, K (present_k): BxNxLxH, Q*K': BxNxSxL - const float rsqrt_head_size = 1.f / sqrt(static_cast(head_size)); - const int temp_matrix_size = sequence_length * kv_sequence_length; - float one = 1.0f; - float zero = 0.f; + // For fused causal, bias has been added to gemm_buffer. + const T* bias = (nullptr != fused_runner && parameters.is_unidirectional) ? nullptr : data.bias; - float alpha = rsqrt_head_size; - const int strideA = kv_sequence_length * head_size; - const int strideB = sequence_length * head_size; - if (use_past && static_kv) { - CUBLAS_RETURN_IF_ERROR(cublasGemmStridedBatchedHelper( - cublas, CUBLAS_OP_T, CUBLAS_OP_N, - kv_sequence_length, sequence_length, head_size, - &alpha, key_cache, head_size, strideA, - q, head_size, strideB, - &zero, scratch1, kv_sequence_length, temp_matrix_size, BN, device_prop)); - } else { - CUBLAS_RETURN_IF_ERROR(cublasGemmStridedBatchedHelper( - cublas, CUBLAS_OP_T, CUBLAS_OP_N, - kv_sequence_length, sequence_length, head_size, - &alpha, k, head_size, strideA, - q, head_size, strideB, - &zero, scratch1, kv_sequence_length, temp_matrix_size, BN, device_prop)); + // 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; } - constexpr bool is_unidirectional = false; - const T* add_before_softmax = nullptr; - if (has_key_padding_mask) { - constexpr int mask_dimension = 2; - constexpr int max_sequence_length = 0; - ORT_RETURN_IF_ERROR(ComputeSoftmaxWithRawMask(stream, kv_sequence_length, sequence_length, batch_size, - num_heads, nullptr, key_padding_mask, add_before_softmax, - false/*broadcast rpb*/, scratch1, scratch2, is_unidirectional, - 1.0f, mask_dimension, max_sequence_length, false, nullptr, - mask_filter_value)); - } else { - ORT_RETURN_IF_ERROR(ComputeSoftmax(stream, kv_sequence_length, sequence_length, batch_size, num_heads, - add_before_softmax, false/*broadcast rpb*/, scratch1, scratch2, - is_unidirectional)); + // Q, K and V are ready now + if (data.fused_cross_attention_kernel != nullptr) { + return FusedTrtCrossAttention(stream, parameters, data); } - // compute P*V (as V*P), and store in scratch3: BxNxSxH - if (use_past && static_kv) { - CUBLAS_RETURN_IF_ERROR(cublasGemmStridedBatchedHelper( - cublas, CUBLAS_OP_N, CUBLAS_OP_N, - head_size, sequence_length, kv_sequence_length, - &one, value_cache, head_size, strideA, - scratch2, kv_sequence_length, temp_matrix_size, - &zero, scratch3, head_size, strideB, BN, device_prop)); - } else { - CUBLAS_RETURN_IF_ERROR(cublasGemmStridedBatchedHelper( - cublas, CUBLAS_OP_N, CUBLAS_OP_N, - head_size, sequence_length, kv_sequence_length, - &one, v, head_size, strideA, - scratch2, kv_sequence_length, temp_matrix_size, - &zero, scratch3, head_size, strideB, BN, device_prop)); + // Run TRT fused attention. + if (nullptr != fused_runner) { + return FusedTrtSelfAttention(stream, parameters, data); } - // scratch3 is BxNxSxH, transpose to output SxBxNxH - return LaunchTransCtx(stream, sequence_length, batch_size, head_size, num_heads, - max_threads_per_block, true, scratch3, output); -} + // For raw attention mask, the scalar 1/sqrt(H) is moved to combine with softmax computation. + const float scale = parameters.scale == 0.0f ? 1.f / sqrt(static_cast(qk_head_size)) + : parameters.scale; -Status LaunchDecoderAttentionKernel( - const cudaDeviceProp& device_prop, - cudaStream_t stream, - cublasHandle_t& cublas, - const size_t element_size, - const int batch_size, - const int sequence_length, - const int kv_sequence_length, - const int num_heads, - const int head_size, - const bool static_kv, - const bool use_past, - const bool has_layer_state, - const bool has_key_padding_mask, - const float mask_filter_value, - const void* gemm_query_buffer, - const void* gemm_kv_buffer, - const bool* key_padding_mask, - const void* key_cache, - const void* value_cache, - void* qkv_buffer, - void* workspace_buffer, - void* output, - void* new_key_cache, - void* new_value_cache) { - if (element_size == 2) { - return DecoderQkvToContext( - device_prop, - stream, - cublas, - element_size, - batch_size, - sequence_length, - kv_sequence_length, - num_heads, - head_size, - static_kv, - use_past, - has_layer_state, - has_key_padding_mask, - mask_filter_value, - reinterpret_cast(gemm_query_buffer), - reinterpret_cast(gemm_kv_buffer), - key_padding_mask, - reinterpret_cast(key_cache), - reinterpret_cast(value_cache), - reinterpret_cast(qkv_buffer), - reinterpret_cast(workspace_buffer), - reinterpret_cast(output), - reinterpret_cast(new_key_cache), - reinterpret_cast(new_value_cache)); - } else { - return DecoderQkvToContext( - device_prop, - stream, - cublas, - element_size, - batch_size, - sequence_length, - kv_sequence_length, - num_heads, - head_size, - static_kv, - use_past, - has_layer_state, - has_key_padding_mask, - mask_filter_value, - reinterpret_cast(gemm_query_buffer), - reinterpret_cast(gemm_kv_buffer), - key_padding_mask, - reinterpret_cast(key_cache), - reinterpret_cast(value_cache), - reinterpret_cast(qkv_buffer), - reinterpret_cast(workspace_buffer), - reinterpret_cast(output), - reinterpret_cast(new_key_cache), - reinterpret_cast(new_value_cache)); +#if USE_FLASH_ATTENTION + if (data.use_flash_attention) { + return FlashAttention(device_prop, stream, parameters, data, scale); + } +#endif + +#if USE_MEMORY_EFFICIENT_ATTENTION + if (data.use_memory_efficient_attention) { + return EfficientAttention(device_prop, stream, parameters, data, scale); } +#endif + + return UnfusedAttention(device_prop, cublas, ort_stream, parameters, data, scale); } // Template Instantiation @@ -1219,14 +617,14 @@ template struct AttentionData; template Status QkvToContext( const cudaDeviceProp& device_prop, cublasHandle_t& cublas, - cudaStream_t stream, + Stream* ort_stream, contrib::AttentionParameters& parameters, AttentionData& data); template Status QkvToContext( const cudaDeviceProp& device_prop, cublasHandle_t& cublas, - cudaStream_t stream, + Stream* ort_stream, contrib::AttentionParameters& parameters, AttentionData& data); diff --git a/onnxruntime/contrib_ops/cuda/bert/attention_impl.h b/onnxruntime/contrib_ops/cuda/bert/attention_impl.h index 3c0fa164fb3a1..d0a5fb51a25d6 100644 --- a/onnxruntime/contrib_ops/cuda/bert/attention_impl.h +++ b/onnxruntime/contrib_ops/cuda/bert/attention_impl.h @@ -2,11 +2,12 @@ // Licensed under the MIT License. #pragma once -#include "core/providers/cuda/shared_inc/cuda_utils.h" + #include #include -#include "contrib_ops/cpu/bert/attention_common.h" +#include "core/common/gsl.h" #include "core/framework/allocator.h" +#include "contrib_ops/cpu/bert/attention_common.h" namespace onnxruntime { namespace contrib { @@ -43,78 +44,66 @@ size_t GetAttentionWorkspaceSize( size_t kv_sequence_length, size_t total_sequence_length, void* fused_runner, + bool use_flash_attention, bool use_fused_cross_attention, bool use_memory_efficient_attention); template struct AttentionData { - T* gemm_buffer; - const T* bias; + T* gemm_buffer = nullptr; + const T* bias = nullptr; - const T* query; - const T* key; - const T* value; - const int* mask_index; + 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; - const T* past_key; - const T* past_value; - const T* relative_position_bias; - - bool has_qkv_workspace; - T* workspace; - T* temp_k_workspace; - T* temp_v_workspace; - - T* output; - T* present; - T* present_key; - T* present_value; - - void* fused_runner; - const void* fused_cross_attention_kernel; - - bool use_memory_efficient_attention; - - mutable CumulatedSequenceLengthCache* cumulated_sequence_length_q_cache; - mutable CumulatedSequenceLengthCache* cumulated_sequence_length_kv_cache; + const T* past = nullptr; + const T* past_key = nullptr; + const T* past_value = nullptr; + const T* relative_position_bias = nullptr; + + bool has_qkv_workspace = false; + T* workspace = nullptr; + T* temp_k_workspace = nullptr; + T* temp_v_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; + + mutable CumulatedSequenceLengthCache* cumulated_sequence_length_q_cache = nullptr; + mutable CumulatedSequenceLengthCache* cumulated_sequence_length_kv_cache = nullptr; + + // Intermediate data + T* q = nullptr; + T* k = nullptr; + T* v = nullptr; + T* scratch = nullptr; + AttentionQkvFormat qkv_format = AttentionQkvFormat::Q_K_V_BSNH; }; +template +Status PrepareQkv(contrib::AttentionParameters& parameters, + AttentionData& data, + cudaStream_t stream, + int max_threads_per_block); + template Status QkvToContext( const cudaDeviceProp& device_prop, cublasHandle_t& cublas, - cudaStream_t stream, + Stream* stream, contrib::AttentionParameters& parameters, AttentionData& data); -Status LaunchDecoderAttentionKernel( - const cudaDeviceProp& prop, // Device Properties - cudaStream_t stream, // Cuda stream - cublasHandle_t& cublas, // Cublas handle - const size_t element_size, // Element size of input tensor - const int batch_size, // Batch size (B) - const int sequence_length, // Sequence length (S) - const int kv_sequence_length, // Key/Value/Cache sequence length - const int num_heads, // Number of attention heads (N) - const int head_size, // Hidden size per head (H) - const bool static_kv, // Whether cross attention or not - const bool use_past, // Whether use cache or not - const bool has_layer_state, // Whether output cache or not - const bool has_key_padding_mask, // Whether use key_padding_mask or not - const float mask_filter_value, // Mask filter value - const void* gemm_query_buffer, // Query buffer - const void* gemm_kv_buffer, // Key and value buffer - const bool* key_padding_mask, // Key padding mask - const void* key_cache, // Input key cache - const void* value_cache, // Input value cache - void* qkv_buffer, // Temporary buffer - void* workspace_buffer, // Temporary buffer - void* output, // Output tensor - void* new_key_cache, // New_key_cache tensor - void* new_value_cache // New_value_cache tensor -); - // 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, @@ -159,27 +148,32 @@ Status LaunchConcatTensorToTensor(cudaStream_t stream, const half* tensor_add, half* tensor_out); -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); - -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); +template +Status ConcatPastToPresent(int batch_size, int num_heads, int qk_head_size, int v_head_size, + int sequence_length, int total_sequence_length, bool pass_past_in_kv, + cudaStream_t stream, + int max_threads_per_block, + 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); + +template +Status LaunchStridedCopy(cudaStream_t stream, + const T* in, int4 in_shape, longlong4 in_strides, // coord (b,n,s,h) + T* out, longlong4 out_strides, // coord (b,n,s,h) + int max_threads_per_block); + } // namespace cuda } // namespace contrib } // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/bert/attention_kv_cache.cu b/onnxruntime/contrib_ops/cuda/bert/attention_kv_cache.cu new file mode 100644 index 0000000000000..89be0f1115f41 --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/attention_kv_cache.cu @@ -0,0 +1,466 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "contrib_ops/cuda/bert/attention_impl.h" +#include "core/providers/cuda/cuda_common.h" +#include "core/providers/cuda/cu_inc/common.cuh" + +using namespace onnxruntime::cuda; + +namespace onnxruntime { +namespace contrib { +namespace cuda { + +template +__global__ void ConcatTensorToTensor(const int tensor_add_sequence_length, + const T* tensor_in, + const T* tensor_add, + T* tensor_out) { + const int h = threadIdx.x; + const int n = threadIdx.y; + const int s = blockIdx.x; + const int b = blockIdx.y; + const int chunk_id = blockIdx.z; + + const int all_sequence_length = gridDim.x; + const int batch_size = gridDim.y; + const int num_heads = blockDim.y; + const int H = blockDim.x; + + // K: number of identical tensors + // tensor_in: K x BxNxPxH + // tensor_add: K x BxNxLxH + // tensor_out: K x BxNxTxH, where T = P + L + const int tensor_in_sequence_length = all_sequence_length - tensor_add_sequence_length; + + const int present_SH = all_sequence_length * H; + const int present_NSH = num_heads * present_SH; + int out_offset = b * present_NSH + n * present_SH + s * H + h + chunk_id * (present_NSH * batch_size); + if (s < tensor_in_sequence_length) { + const int past_SH = tensor_in_sequence_length * H; + const int past_NSH = num_heads * past_SH; + const int in_offset = b * past_NSH + n * past_SH + s * H + h + chunk_id * (past_NSH * batch_size); + tensor_out[out_offset] = tensor_in[in_offset]; + } else if (s < all_sequence_length) { + const int SH = tensor_add_sequence_length * H; + const int NSH = num_heads * SH; + const int in_offset = b * NSH + n * SH + (s - tensor_in_sequence_length) * H + h + chunk_id * (NSH * batch_size); + tensor_out[out_offset] = tensor_add[in_offset]; + } +} + +template +__global__ void ConcatTensorToTensorLarge(const int tensor_add_sequence_length, + const int H, + const T* tensor_in, + const T* tensor_add, + T* tensor_out) { + // Use when (H*)*num_heads > 1024 + int h = threadIdx.x; + const int n = threadIdx.y; + const int s = blockIdx.x; + const int b = blockIdx.y; + const int chunk_id = blockIdx.z; + + const int all_sequence_length = gridDim.x; + const int batch_size = gridDim.y; + const int num_heads = blockDim.y; + const int stride = blockDim.x; + + // K: number of identical tensor + // tensor_in: K x BxNxPxH + // tensor_add: K x BxNxLxH + // tensor_out: K x BxNxTxH + const int tensor_in_sequence_length = all_sequence_length - tensor_add_sequence_length; + + const int present_SH = all_sequence_length * H; + const int present_NSH = num_heads * present_SH; + while (h < H) { + int out_offset = b * present_NSH + n * present_SH + s * H + h + chunk_id * (present_NSH * batch_size); + if (s < tensor_in_sequence_length) { + const int past_SH = tensor_in_sequence_length * H; + const int past_NSH = num_heads * past_SH; + const int in_offset = b * past_NSH + n * past_SH + s * H + h + chunk_id * (past_NSH * batch_size); + tensor_out[out_offset] = tensor_in[in_offset]; + } else if (s < all_sequence_length) { + const int SH = tensor_add_sequence_length * H; + const int NSH = num_heads * SH; + const int in_offset = b * NSH + n * SH + (s - tensor_in_sequence_length) * H + h + chunk_id * (NSH * batch_size); + tensor_out[out_offset] = tensor_add[in_offset]; + } + + h += stride; + } +} + +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) { + const dim3 grid(all_sequence_length, batch_size, matrix_num); + if (0 == (head_size & 1)) { + const int H = head_size / 2; + if (H * num_heads <= max_threads_per_block) { + const dim3 block(H, num_heads, 1); + ConcatTensorToTensor<<>>(sequence_length, + reinterpret_cast(tensor_in), + reinterpret_cast(tensor_add), + reinterpret_cast(tensor_out)); + } else { + const dim3 block(max_threads_per_block / num_heads, num_heads, 1); + ConcatTensorToTensorLarge<<>>(sequence_length, + H, + reinterpret_cast(tensor_in), + reinterpret_cast(tensor_add), + reinterpret_cast(tensor_out)); + } + } else { + if (head_size * num_heads <= max_threads_per_block) { + const dim3 block(head_size, num_heads, 1); + ConcatTensorToTensor<<>>(sequence_length, tensor_in, tensor_add, tensor_out); + } else { + const dim3 block(max_threads_per_block / num_heads, num_heads, 1); + ConcatTensorToTensorLarge<<>>(sequence_length, + head_size, + tensor_in, + tensor_add, + tensor_out); + } + } + return CUDA_CALL(cudaGetLastError()); +} + +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) { + const dim3 grid(all_sequence_length, batch_size, matrix_num); + if (0 == (head_size % 4)) { + const int H = head_size / 4; + if (H * num_heads <= max_threads_per_block) { + const dim3 block(H, num_heads, 1); + ConcatTensorToTensor<<>>(sequence_length, + reinterpret_cast(tensor_in), + reinterpret_cast(tensor_add), + reinterpret_cast(tensor_out)); + } else { + const dim3 block(max_threads_per_block / num_heads, num_heads, 1); + ConcatTensorToTensorLarge<<>>(sequence_length, + H, + reinterpret_cast(tensor_in), + reinterpret_cast(tensor_add), + reinterpret_cast(tensor_out)); + } + } else if (0 == (head_size & 1)) { + const int H = head_size / 2; + if (H * num_heads <= max_threads_per_block) { + const dim3 block(H, num_heads, 1); + ConcatTensorToTensor<<>>(sequence_length, + reinterpret_cast(tensor_in), + reinterpret_cast(tensor_add), + reinterpret_cast(tensor_out)); + } else { + const dim3 block(max_threads_per_block / num_heads, num_heads, 1); + ConcatTensorToTensorLarge<<>>(sequence_length, + H, + reinterpret_cast(tensor_in), + reinterpret_cast(tensor_add), + reinterpret_cast(tensor_out)); + } + } else { // this should be an "odd" case. probably not worth catching it in the half2 kernel. + if (head_size * num_heads <= max_threads_per_block) { + const dim3 block(head_size, num_heads, 1); + ConcatTensorToTensor<<>>(sequence_length, tensor_in, tensor_add, tensor_out); + } else { + const dim3 block(max_threads_per_block / num_heads, num_heads, 1); + ConcatTensorToTensorLarge<<>>(sequence_length, + head_size, + tensor_in, + tensor_add, + tensor_out); + } + } + 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, bool pass_past_in_kv, + 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) { + 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 if (nullptr != data.past_key || nullptr != data.present_key) { + if (nullptr != data.past_key && nullptr == data.present_key) { + data.k = const_cast(data.past_key); + data.v = const_cast(data.past_value); + } else if (nullptr == data.past_key && nullptr != data.present_key) { + if (data.qkv_format == AttentionQkvFormat::Q_K_V_BNSH) { + data.k = data.present_key; + data.v = data.present_value; + } else { + assert(data.qkv_format == AttentionQkvFormat::Q_K_V_BSNH); + data.k = data.temp_k_workspace; + data.v = data.temp_v_workspace; + } + } else if (pass_past_in_kv) { + // past_key and past_value are used directly as key and value in attention computations + data.k = const_cast(data.past_key); + data.v = const_cast(data.past_value); + + // This path has a memory copy from past_key and past_value to present_key and present_value + // Avoid this path since the memory copy is unnecessary because past_key == present_key and + // past_value == present_value + int64_t k_size = (int64_t)batch_size * num_heads * total_sequence_length * qk_head_size; + int64_t v_size = (int64_t)batch_size * num_heads * total_sequence_length * v_head_size; + cudaMemcpyAsync(data.present_key, data.past_key, k_size * sizeof(T), cudaMemcpyDeviceToDevice, stream); + cudaMemcpyAsync(data.present_value, data.past_value, v_size * sizeof(T), cudaMemcpyDeviceToDevice, stream); + } else { + 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; + } + } + + 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, bool pass_past_in_kv, + 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, bool pass_past_in_kv, + cudaStream_t stream, + int max_threads_per_block, + AttentionData& data); + +// ---------------------------------------------------------------------------------- +// Below kernels are for past and present sharing buffer +// ---------------------------------------------------------------------------------- + +template +__global__ void AddBiasTransAppendKvToPresentSmall( + const T* qkv, const T* biases, T* present, + const int head_size, const int past_sequence_length, const int max_sequence_length) { + // Input: BxSxMxNxH (Format 1) + // Output: (2, B, N, [P..P+S) of MaxS, H), + // B is batch_size, S is sequence_length, M is number of matrices, N is num_heads, H is head_size + const int n = threadIdx.y; + const int s = blockIdx.x; + const int b = blockIdx.y; + const int N = blockDim.y; + const int S = gridDim.x; + const int B = gridDim.y; + + constexpr int M = 3; // Matrix count in qkv + const int m = blockIdx.z + 1; // k = 1, v = 2 + + const int NH = N * head_size; + const int NHS = NH * S; + + qkv += (n * head_size + (s * M + m) * NH + b * M * NHS); + if (biases) { + biases += (m * NH + n * head_size); + } + + const int MsH = max_sequence_length * head_size; + const int NMsH = N * MsH; + const int BNMsH = B * NMsH; + present += ((past_sequence_length + s) * head_size + n * MsH + b * NMsH + (m - 1) * BNMsH); + + for (int h = threadIdx.x; h < head_size; h += blockDim.x) { + T bias = (biases ? biases[h] : (T)0.0f); + present[h] = qkv[h] + bias; + } +} + +template +__global__ void AddBiasTransAppendKvToPresent( + const T* qkv, const T* biases, T* present, + const int head_size, const int past_sequence_length, const int max_sequence_length) { + // Input: BxSxMxNxH (Format 1) + // Output: (2, B, N, [P..P+S) of MaxS, H), + // B is batch_size, S is sequence_length, M is number of matrices, N is num_heads, H is head_size + const int n = blockIdx.x; + const int s = blockIdx.y; + const int b = (blockIdx.z >> 1); + const int N = gridDim.x; + const int S = gridDim.y; + const int B = (gridDim.z >> 1); + + constexpr int M = 3; // Matrix count in qkv + const int m = (blockIdx.z & 0x1) + 1; // k = 1, v = 2 + + const int NH = N * head_size; + const int NHS = NH * S; + + qkv += (n * head_size + (s * M + m) * NH + b * M * NHS); + if (biases) { + biases += (m * NH + n * head_size); + } + + const int MsH = max_sequence_length * head_size; + const int NMsH = N * MsH; + const int BNMsH = B * NMsH; + present += ((past_sequence_length + s) * head_size + n * MsH + b * NMsH + (m - 1) * BNMsH); + + for (int h = threadIdx.x; h < head_size; h += blockDim.x) { + T bias = (biases ? biases[h] : (T)0.0f); + present[h] = qkv[h] + bias; + } +} + +// qkv buffer is merged tensor of shape (B,S,3,N,H), k v is the second/third of the 3. +// bias is of shape (3, NxH) or nullptr +// append to present of (2, B, N, (P..T) of M, H), +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) { + assert(head_size <= (1 << 30)); + + int64_t nh = (int64_t)head_size * num_heads; + if (nh <= max_threads_per_block) { + const dim3 grid(sequence_length, batch_size, 2); // 2 for k and v + const dim3 block(max_threads_per_block / num_heads, num_heads, 1); + + AddBiasTransAppendKvToPresentSmall<<>>( + qkv_buffer, biases, present, head_size, past_sequence_length, max_sequence_length); + } else { + const dim3 grid(num_heads, sequence_length, batch_size * 2); // 2 for k and v + const dim3 block(std::min(head_size, max_threads_per_block), 1, 1); + AddBiasTransAppendKvToPresent<<>>( + qkv_buffer, biases, present, head_size, past_sequence_length, max_sequence_length); + } + + return CUDA_CALL(cudaGetLastError()); +} + +template Status LaunchAddBiasTransAppendKvToPresent(cudaStream_t stream, + const int max_sequence_length, + const int total_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* bias, + const float* qkv_buffer, + float* present); + +template Status LaunchAddBiasTransAppendKvToPresent(cudaStream_t stream, + const int max_sequence_length, + const int total_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* bias, + const half* qkv_buffer, + half* present); +#endif + +} // 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 new file mode 100644 index 0000000000000..5c65a30918ece --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/attention_prepare_qkv.cu @@ -0,0 +1,492 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "contrib_ops/cuda/bert/attention_impl.h" +#include "core/providers/cuda/cu_inc/common.cuh" +#include "contrib_ops/cuda/bert/add_bias_transpose.h" +#include "contrib_ops/cuda/transformers/dump_cuda_tensor.h" + +using namespace onnxruntime::cuda; + +namespace onnxruntime { +namespace contrib { +namespace cuda { + +template +Status PrepareQkv_Attention(contrib::AttentionParameters& parameters, + AttentionData& data, + cudaStream_t stream, + int max_threads_per_block, + AttentionQkvFormat& qkv_format) { + const int batch_size = parameters.batch_size; + const int sequence_length = parameters.sequence_length; + const int num_heads = parameters.num_heads; + const int qk_head_size = parameters.head_size; + const int v_head_size = parameters.v_head_size; + const bool past_present_share_buffer = parameters.past_present_share_buffer; + void* fused_runner = data.fused_runner; + bool use_flash_or_efficient_attention = data.use_flash_attention || data.use_memory_efficient_attention; + + T* qkv = data.workspace; + + bool use_fused_kernel = (nullptr != fused_runner && !parameters.is_unidirectional); + bool use_fused_causal = (nullptr != fused_runner && parameters.is_unidirectional); + + if (data.bias == nullptr) { + assert(nullptr == fused_runner); + // For quantized attention, bias has been added so only need transpose here. + // gemm_buffer should be BxSx3xNxH => qkv: 3xBxNxSxH + assert(qk_head_size == v_head_size); + int matrix_to_trans = (past_present_share_buffer ? 1 : 3); + ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, matrix_to_trans, sequence_length, batch_size, qk_head_size, num_heads, + max_threads_per_block, false, data.gemm_buffer, qkv, 3)); + qkv_format = AttentionQkvFormat::Q_K_V_BNSH; + } else { + // For fused TRT attention, transpose qkv to BxSxNx3xH (format 2) + // For flash or memory efficient attention, transpose to 3xBxSxNxH (format 3) + // For unfused kernel, transpose to 3xBxNxSxH (format 1) + // For fused causal kernel, use format 1 since we need have K and V to update present state, + // at the same time, we update gemm_buffer BxSx3xNxH with bias which is used as input for fused causal kernel. + const int format = (use_fused_kernel ? 2 : (use_flash_or_efficient_attention ? 3 : 1)); + qkv_format = use_fused_kernel + ? AttentionQkvFormat::QKV_BSN3H + : (use_flash_or_efficient_attention + ? AttentionQkvFormat::Q_K_V_BSNH + : (use_fused_causal + ? AttentionQkvFormat::Q_K_V_BNSH_QKV_BS3NH + : AttentionQkvFormat::Q_K_V_BNSH)); + + // For fused causal, we will update gemm_buffer with bias directly. + T* qkv_add_bias = use_fused_causal ? data.gemm_buffer : nullptr; + + int matrix_to_transpose = ((format == AttentionQkvFormat::Q_K_V_BNSH && past_present_share_buffer) ? 1 : 3); + // format 1: BxSx(NH + NH + NH_v) => BxNxSxH + BxNxSxH + BxNxSxH_v + // format 2: BxSx(NH + NH + NH) => BxSxNx(H + H + H) + LaunchAddBiasTranspose(stream, matrix_to_transpose, format, max_threads_per_block, + batch_size, sequence_length, num_heads, qk_head_size, + data.gemm_buffer, data.bias, qkv, true, v_head_size, qkv_add_bias, + 3, parameters.do_rotary, parameters.past_sequence_length); + } + return Status::OK(); +} + +// For MultiHeadAttention with past state +template +Status PrepareQkv_MHA_WithPast(contrib::AttentionParameters& parameters, + AttentionData& data, + cudaStream_t stream, + int max_threads_per_block, + T* q, T* k, T* v, AttentionQkvFormat& qkv_format) { + const int batch_size = parameters.batch_size; + const int sequence_length = parameters.sequence_length; + const int kv_sequence_length = parameters.kv_sequence_length; + const int num_heads = parameters.num_heads; + const int qk_head_size = parameters.head_size; + const int v_head_size = parameters.v_head_size; + + DUMP_TENSOR_INIT(); + + if (data.bias == nullptr) { + // Below logic does not support fused attention with past without bias + // When there is past state, the format shall be BxNxSxH, so we disable fused attention when there is past. + + // cross attention with past state + if (data.past_key != nullptr && data.present_key == nullptr) { + assert(data.past_value != nullptr); + assert(data.query != nullptr); + assert(data.key == nullptr); + assert(data.value == nullptr); + ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, 1, sequence_length, batch_size, qk_head_size, num_heads, + max_threads_per_block, false, data.query, q)); + } + // cross attention with present state or self attention with present state + else if (data.past_key == nullptr && data.present_key != nullptr) { + assert(data.past_value == nullptr); + assert(data.present_value != nullptr); + assert(data.query != nullptr); + assert(data.key != nullptr); + assert(data.value != nullptr); + + // TODO: supporting packed qkv for self attention may benefit performance + ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, 1, sequence_length, batch_size, qk_head_size, num_heads, + max_threads_per_block, false, data.query, q)); + + // TODO: supporting packed kv for cross attention may benefit performance + ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, 1, kv_sequence_length, batch_size, qk_head_size, num_heads, + max_threads_per_block, false, data.key, data.present_key)); + ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, 1, kv_sequence_length, batch_size, v_head_size, num_heads, + max_threads_per_block, false, data.value, data.present_value)); + } + // self attention with past and present state + else { + assert(data.past_key != nullptr); + assert(data.past_value != nullptr); + assert(data.present_key != nullptr); + assert(data.present_value != nullptr); + assert(data.query != nullptr); + assert(data.key != nullptr); + assert(data.value != nullptr); + // TODO: supporting packed qkv for self attention may benefit performance + ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, 1, sequence_length, batch_size, qk_head_size, num_heads, + max_threads_per_block, false, data.query, q)); + ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, 1, kv_sequence_length, batch_size, qk_head_size, num_heads, + max_threads_per_block, false, data.key, k)); + ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, 1, kv_sequence_length, batch_size, v_head_size, num_heads, + max_threads_per_block, false, data.value, v)); + } + qkv_format = AttentionQkvFormat::Q_K_V_BNSH; + } +#if USE_MEMORY_EFFICIENT_ATTENTION || USE_FLASH_ATTENTION + // When past_key/past_value are inputted directly as key/value and there is no present_key/present_value + else if ((data.use_memory_efficient_attention || data.use_flash_attention) && + data.past_key != nullptr && + data.past_value != nullptr && + parameters.pass_past_in_kv) { + // Transpose past_key and past_value to use memory efficient attention + + // past_key (BxNxSxH) => temp_k_workspace (BxSxNxH) + ORT_RETURN_IF_ERROR(LaunchTransCtx(stream, kv_sequence_length, batch_size, qk_head_size, num_heads, + max_threads_per_block, false, data.past_key, data.temp_k_workspace)); + // past_value (BxNxSxH_v) => temp_v_workspace (BxSxNxH_v) + ORT_RETURN_IF_ERROR(LaunchTransCtx(stream, kv_sequence_length, batch_size, qk_head_size, num_heads, + max_threads_per_block, false, data.past_value, data.temp_v_workspace)); + + // query => q, temp_k_workspace => k, temp_v_workspace => v + LaunchAddBias(stream, max_threads_per_block, + batch_size, sequence_length, kv_sequence_length, + num_heads, qk_head_size, v_head_size, + data.bias, data.query, data.temp_k_workspace, data.temp_v_workspace, q, k, v); + + DUMP_TENSOR_D("q(BSNH)", q, batch_size, sequence_length, num_heads, qk_head_size); + DUMP_TENSOR_D("k(BSNH)", k, batch_size, kv_sequence_length, num_heads, qk_head_size); + DUMP_TENSOR_D("v(BSNH)", v, batch_size, kv_sequence_length, num_heads, v_head_size); + qkv_format = AttentionQkvFormat::Q_K_V_BSNH; + + data.past_key = nullptr; + data.past_value = nullptr; + } + // When there is no past_key/past_value and there is present_key/present_value + // (e.g. get initial kv to use as past_kv in the next iteration) + else if ((data.use_memory_efficient_attention || data.use_flash_attention) && + data.present_key != nullptr && + data.present_value != nullptr) { + // Use memory efficient attention kernel + LaunchAddBias(stream, max_threads_per_block, + batch_size, sequence_length, kv_sequence_length, + num_heads, qk_head_size, v_head_size, + data.bias, data.query, data.key, data.value, q, data.temp_k_workspace, data.temp_v_workspace); + + // temp_k_workspace (BxSxNxH) => present_k (BxNxSxH) + ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, 1, kv_sequence_length, batch_size, qk_head_size, num_heads, + max_threads_per_block, false, data.temp_k_workspace, data.present_key)); + + // temp_v_workspace (BxSxNxH_v) => present_v (BxNxSxH_v) + ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, 1, kv_sequence_length, batch_size, v_head_size, num_heads, + max_threads_per_block, false, data.temp_v_workspace, data.present_value)); + + DUMP_TENSOR_D("q(BSNH)", q, batch_size, sequence_length, num_heads, qk_head_size); + DUMP_TENSOR_D("k(BSNH)", data.temp_k_workspace, batch_size, kv_sequence_length, num_heads, qk_head_size); + DUMP_TENSOR_D("v(BSNH)", data.temp_v_workspace, batch_size, kv_sequence_length, num_heads, v_head_size); + qkv_format = AttentionQkvFormat::Q_K_V_BSNH; + } +#endif + else { + // Use unfused kernel for Q, use unfused kernel for K and V if needed + constexpr int format = 0; + // Query (BxSxNxH) => Q (BxNxSxH) + LaunchAddBiasTranspose(stream, 1, format, max_threads_per_block, + batch_size, sequence_length, num_heads, qk_head_size, + data.query, data.bias, q, + true, -1); + + if (!parameters.pass_past_in_kv) { + T* k_dest = (data.past_key == nullptr && data.present_key != nullptr) ? data.present_key : k; + T* v_dest = (data.past_value == nullptr && data.present_value != nullptr) ? data.present_value : v; + + // Key (BxLxNxH) => K (BxNxLxH) + LaunchAddBiasTranspose(stream, 1, format, max_threads_per_block, + batch_size, kv_sequence_length, num_heads, qk_head_size, + data.key, data.bias + num_heads * qk_head_size, k_dest, + true, -1); + + // Value (BxLxNxH_v) => V (BxNxLxH_v) + LaunchAddBiasTranspose(stream, 1, format, max_threads_per_block, + batch_size, kv_sequence_length, num_heads, v_head_size, + data.value, data.bias + 2 * num_heads * qk_head_size, v_dest, + true, -1); + + DUMP_TENSOR_D("q(BNSH)", q, batch_size, num_heads, sequence_length, qk_head_size); + DUMP_TENSOR_D("k(BNSH)", k_dest, batch_size, num_heads, kv_sequence_length, qk_head_size); + DUMP_TENSOR_D("v(BNSH)", v_dest, batch_size, num_heads, kv_sequence_length, v_head_size); + } + qkv_format = AttentionQkvFormat::Q_K_V_BNSH; + } + return Status::OK(); +} + +// For MultiHeadAttention without past state, with packed QKV inputs +template +Status PrepareQkv_MHA_PackedQKV(contrib::AttentionParameters& parameters, + AttentionData& data, + cudaStream_t stream, + int max_threads_per_block, + T* q, T* k, T* v, AttentionQkvFormat& qkv_format) { + const int batch_size = parameters.batch_size; + const int sequence_length = parameters.sequence_length; + const int num_heads = parameters.num_heads; + const int qk_head_size = parameters.head_size; + const int v_head_size = parameters.v_head_size; + void* fused_runner = data.fused_runner; + + T* qkv = data.workspace; + + bool use_fused_kernel = (nullptr != fused_runner && !parameters.is_unidirectional); + + assert(data.bias == nullptr); + assert(qk_head_size == v_head_size); + + DUMP_TENSOR_INIT(); + DUMP_TENSOR_D("packed_qkv", data.query, batch_size * sequence_length, num_heads, 3, qk_head_size); + + if (data.use_memory_efficient_attention || data.use_flash_attention) { + // unpack qkv to BSNH. Note that there is no bias so we need not output query to q. + constexpr int format = 4; + T* qkv_add_bias = nullptr; + LaunchAddBiasTranspose(stream, 3, format, max_threads_per_block, + batch_size, sequence_length, num_heads, qk_head_size, + data.query, data.bias, qkv, + true, v_head_size, qkv_add_bias, 3); + DUMP_TENSOR_D("q(BSNH)", q, batch_size, sequence_length, num_heads, qk_head_size); + DUMP_TENSOR_D("k(BSNH)", k, batch_size, sequence_length, num_heads, qk_head_size); + DUMP_TENSOR_D("v(BSNH)", v, batch_size, sequence_length, num_heads, v_head_size); + qkv_format = AttentionQkvFormat::Q_K_V_BSNH; + } else { + if (!use_fused_kernel) { + return ORT_MAKE_STATUS( + ONNXRUNTIME, NOT_IMPLEMENTED, + "packed QKV format is not implemented for current GPU. Please disable it in fusion options."); + } + + qkv_format = AttentionQkvFormat::QKV_BSN3H; + } + return Status::OK(); +} + +// For MultiHeadAttention without past state, with packed KV inputs +template +Status PrepareQkv_MHA_PackedKV(contrib::AttentionParameters& parameters, + AttentionData& data, + cudaStream_t stream, + int max_threads_per_block, + T* q, T* k, T* v, AttentionQkvFormat& qkv_format) { + const int batch_size = parameters.batch_size; + const int kv_sequence_length = parameters.kv_sequence_length; + const int num_heads = parameters.num_heads; + const int qk_head_size = parameters.head_size; + const int v_head_size = parameters.v_head_size; + + // TODO: unpack kv to BNSH for unfused kernel so that we can remove the following constraint. + // CheckInputs verified this constraint. + assert(data.bias == nullptr); + assert(qk_head_size == v_head_size); + + DUMP_TENSOR_INIT(); + DUMP_TENSOR_D("packed_kv", data.key, batch_size * kv_sequence_length, num_heads, 2, qk_head_size); + + if (data.use_memory_efficient_attention || data.use_flash_attention) { + // unpack kv to BSNH. Note that there is no bias so we need not output query to q. + constexpr int format = 4; + T* qkv_add_bias = nullptr; + const T* kv_bias = (data.bias == nullptr ? data.bias : data.bias + parameters.hidden_size); + LaunchAddBiasTranspose(stream, 2, format, max_threads_per_block, + batch_size, kv_sequence_length, num_heads, qk_head_size, + data.key, kv_bias, k, + true, v_head_size, qkv_add_bias, 2); + DUMP_TENSOR_D("k(BSNH)", k, batch_size, kv_sequence_length, num_heads, qk_head_size); + DUMP_TENSOR_D("v(BSNH)", v, batch_size, kv_sequence_length, num_heads, v_head_size); + qkv_format = AttentionQkvFormat::Q_K_V_BSNH; + } else { + if (data.fused_cross_attention_kernel == nullptr) { + return ORT_MAKE_STATUS( + ONNXRUNTIME, NOT_IMPLEMENTED, + "packed KV format is not implemented for current GPU. Please disable packed kv in fusion options."); + } + + qkv_format = AttentionQkvFormat::Q_KV_BSNH_BSN2H; + } + return Status::OK(); +} + +// For MultiHeadAttention without past state, with Q, K and V inputs +template +Status PrepareQkv_MHA_NotPacked(contrib::AttentionParameters& parameters, + AttentionData& data, + cudaStream_t stream, + int max_threads_per_block, + T* q, T* k, T* v, AttentionQkvFormat& qkv_format) { + const int batch_size = parameters.batch_size; + const int sequence_length = parameters.sequence_length; + const int kv_sequence_length = parameters.kv_sequence_length; + const int num_heads = parameters.num_heads; + const int qk_head_size = parameters.head_size; + const int v_head_size = parameters.v_head_size; + void* fused_runner = data.fused_runner; + + T* qkv = data.workspace; + + bool use_fused_kernel = (nullptr != fused_runner && !parameters.is_unidirectional); + bool use_fused_causal = (nullptr != fused_runner && parameters.is_unidirectional); + + // gemm_buffer == nullptr and not packed + assert(data.query != nullptr && data.key != nullptr && data.value != nullptr); + + DUMP_TENSOR_INIT(); + DUMP_TENSOR_D("query", data.query, batch_size, sequence_length, num_heads, qk_head_size); + DUMP_TENSOR_D("key", data.key, batch_size, kv_sequence_length, num_heads, qk_head_size); + DUMP_TENSOR_D("value", data.value, batch_size, kv_sequence_length, num_heads, v_head_size); + +#if DUMP_TENSOR_LEVEL > 1 + if (data.bias != nullptr) { + DUMP_TENSOR_D("query_bias", data.bias, num_heads, qk_head_size); + DUMP_TENSOR_D("key_bias", data.bias + num_heads * qk_head_size, num_heads, qk_head_size); + DUMP_TENSOR_D("value_bias", data.bias + 2 * num_heads * qk_head_size, num_heads, v_head_size); + } +#endif + + if (data.relative_position_bias != nullptr && parameters.broadcast_res_pos_bias) { + DUMP_TENSOR_D("relative_position_bias", data.relative_position_bias, + num_heads, sequence_length, kv_sequence_length); + } + + if (data.mask_index != nullptr && parameters.mask_type == AttentionMaskType::MASK_1D_KEY_SEQ_LEN_START) { + DUMP_TENSOR_D("mask_index", data.mask_index, 3 * batch_size + 2, 1); + } + + if (data.fused_cross_attention_kernel != nullptr) { + assert(qk_head_size == v_head_size); + + // For fused cross attention, besides adding bias, K and V needed to be packed: + // K (BxSxNxH), V (BxSxNxH) => BxSxNx2xH + LaunchAddBiasTransposeTrt( + stream, max_threads_per_block, + batch_size, sequence_length, + num_heads, qk_head_size, + data.bias, data.query, data.key, data.value, qkv, true, kv_sequence_length); + + qkv_format = AttentionQkvFormat::Q_KV_BSNH_BSN2H; + } +#if USE_MEMORY_EFFICIENT_ATTENTION || USE_FLASH_ATTENTION + else if (data.use_memory_efficient_attention || data.use_flash_attention) { + LaunchAddBias(stream, max_threads_per_block, + batch_size, sequence_length, kv_sequence_length, + num_heads, qk_head_size, v_head_size, + data.bias, data.query, data.key, data.value, q, k, v); + + DUMP_TENSOR_D("q(BSNH)", q, batch_size, sequence_length, num_heads, qk_head_size); + DUMP_TENSOR_D("k(BSNH)", k, batch_size, kv_sequence_length, num_heads, qk_head_size); + DUMP_TENSOR_D("v(BSNH)", v, batch_size, kv_sequence_length, num_heads, v_head_size); + qkv_format = AttentionQkvFormat::Q_K_V_BSNH; + } +#endif + else if (use_fused_kernel) { + assert(qk_head_size == v_head_size); + + // Q (BxSxNxH), K (BxSxNxH), V (BxSxNxH) => BxSxNx(H + H + H) + LaunchAddBiasTransposeTrt( + stream, max_threads_per_block, + batch_size, sequence_length, + num_heads, qk_head_size, + data.bias, data.query, data.key, data.value, qkv, false, kv_sequence_length); + DUMP_TENSOR_D("qkv(BSN3H)", qkv, batch_size, sequence_length, num_heads, 2 * qk_head_size + v_head_size); + + qkv_format = AttentionQkvFormat::QKV_BSN3H; + } else { // unfused kernel + ORT_ENFORCE(!use_fused_causal, "MultiHeadAttention has not enabled fused causal"); + + // Query (BxSxNxH) => Q (BxNxSxH) + constexpr int format = 0; + LaunchAddBiasTranspose( + stream, 1, format, max_threads_per_block, + batch_size, sequence_length, num_heads, qk_head_size, + data.query, data.bias, q, + true, -1); + + // Key (BxLxNxH) => K (BxNxLxH) + LaunchAddBiasTranspose( + stream, 1, format, max_threads_per_block, + batch_size, kv_sequence_length, num_heads, qk_head_size, + data.key, nullptr == data.bias ? nullptr : data.bias + num_heads * qk_head_size, k, + true, -1); + + // Value (BxLxNxH_v) => K (BxNxLxH_v) + LaunchAddBiasTranspose( + stream, 1, format, max_threads_per_block, + batch_size, kv_sequence_length, num_heads, v_head_size, + data.value, nullptr == data.bias ? nullptr : data.bias + 2 * num_heads * qk_head_size, v, + true, -1); + + DUMP_TENSOR_D("q(BNSH)", q, batch_size, num_heads, sequence_length, qk_head_size); + DUMP_TENSOR_D("k(BNSH)", k, batch_size, num_heads, kv_sequence_length, qk_head_size); + DUMP_TENSOR_D("v(BNSH)", v, batch_size, num_heads, kv_sequence_length, v_head_size); + qkv_format = AttentionQkvFormat::Q_K_V_BNSH; + } + return Status::OK(); +} + +template +Status PrepareQkv(contrib::AttentionParameters& parameters, + AttentionData& data, + cudaStream_t stream, + int max_threads_per_block) { + data.scratch = data.workspace; + if (data.has_qkv_workspace) { + const int size_per_batch_q = parameters.sequence_length * parameters.head_size; + const int size_per_batch_k = parameters.kv_sequence_length * parameters.head_size; + const int size_per_batch_v = parameters.kv_sequence_length * parameters.v_head_size; + const int batches = parameters.batch_size * parameters.num_heads; + const size_t elements_q = static_cast(batches) * static_cast(size_per_batch_q); + const size_t elements_k = static_cast(batches) * static_cast(size_per_batch_k); + const size_t elements_v = static_cast(batches) * static_cast(size_per_batch_v); + data.q = data.workspace; + data.k = data.workspace + elements_q; + data.v = data.k + elements_k; + data.scratch = data.v + elements_v; + } + + if (nullptr != data.gemm_buffer) { // Attention operator + ORT_RETURN_IF_ERROR(PrepareQkv_Attention(parameters, data, stream, max_threads_per_block, + data.qkv_format)); + } else if (data.past_key != nullptr || data.present_key != nullptr) { // mha operator with past/present state + ORT_RETURN_IF_ERROR(PrepareQkv_MHA_WithPast(parameters, data, stream, max_threads_per_block, + data.q, data.k, data.v, data.qkv_format)); + } else if (data.key == nullptr) { // multihead attention operator, no past, packed qkv + ORT_RETURN_IF_ERROR(PrepareQkv_MHA_PackedQKV(parameters, data, stream, max_threads_per_block, + data.q, data.k, data.v, data.qkv_format)); + } else if (data.value == nullptr) { // multihead attention operator, no past, packed kv + ORT_RETURN_IF_ERROR(PrepareQkv_MHA_PackedKV(parameters, data, stream, max_threads_per_block, + data.q, data.k, data.v, data.qkv_format)); + } else { // multihead attention operator, no past, separated Q/K/V inputs + ORT_RETURN_IF_ERROR(PrepareQkv_MHA_NotPacked(parameters, data, stream, max_threads_per_block, + data.q, data.k, data.v, data.qkv_format)); + } + + CUDA_RETURN_IF_ERROR(cudaGetLastError()); + return Status::OK(); +} + +// Template Instantiation +template Status PrepareQkv( + contrib::AttentionParameters& parameters, + AttentionData& data, + cudaStream_t stream, + int max_threads_per_block); + +template Status PrepareQkv( + contrib::AttentionParameters& parameters, + AttentionData& data, + cudaStream_t stream, + int max_threads_per_block); + +} // 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 d50cba24b0b28..01ea02f48d3ab 100644 --- a/onnxruntime/contrib_ops/cuda/bert/attention_softmax.cu +++ b/onnxruntime/contrib_ops/cuda/bert/attention_softmax.cu @@ -18,7 +18,6 @@ limitations under the License. */ #include -#include #include #include "core/providers/cuda/cu_inc/common.cuh" #include "core/providers/cuda/cuda_common.h" @@ -108,7 +107,7 @@ __device__ inline void SoftmaxSmall(const int all_sequence_length, const bool broadcast_rel_pos_bias, const T* input, T* output, - bool is_unidirectional) { + bool causal) { using BlockReduce = cub::BlockReduce; __shared__ typename BlockReduce::TempStorage tmp_storage; @@ -119,23 +118,16 @@ __device__ inline void SoftmaxSmall(const int all_sequence_length, const int offset = (blockIdx.y * gridDim.x + blockIdx.x) * all_sequence_length; const int index = offset + threadIdx.x; - bool is_valid = false; // whether it has attention mask == 1. - - // Update end position for unidirectional. + // Update end position for causal. int end = valid_end; - if (is_unidirectional) { - int end_unid = all_sequence_length - sequence_length + (blockIdx.x % sequence_length) + 1; - if (end_unid <= valid_start) { - // In this situation, mask of [0, end_unid) and [valid_start, valid_end) has -10000, - // and [end_unid, valid_start) and [valid_end, all_seq_len) has -20000. - // So [0, end_unid) will also have value after softmax. - is_valid = threadIdx.x < end_unid; - } else { - end = min(valid_end, end_unid); + if (causal) { + const int end_causal = all_sequence_length - sequence_length + (blockIdx.x % sequence_length) + 1; + if (end_causal < end) { + end = end_causal; } } - is_valid = is_valid || (threadIdx.x >= valid_start && threadIdx.x < end); + const bool is_valid = (threadIdx.x >= valid_start && threadIdx.x < end); // e^x is represented as infinity if x is large enough, like 100.f. // Infinity divided by Infinity is a NAN. Thus, softmax gets a NAN if one or more item are large enough. @@ -172,7 +164,7 @@ __device__ inline void SoftmaxSmall(const int all_sequence_length, // threadIdx.x might be larger than all_sequence_length due to alignment to 32x. if (threadIdx.x < all_sequence_length) { - output[index] = T(thread_data_exp * sum_reverse_block); + output[index] = is_valid ? T(thread_data_exp * sum_reverse_block) : T(0.f); } } @@ -185,7 +177,7 @@ __global__ void SoftmaxLargeKernel(const int all_sequence_length, const bool broadcast_rel_pos_bias, const T* input, T* output, - bool is_unidirectional) { + bool causal) { extern __shared__ float cached_data[]; // float[all_sequence_length] using BlockReduce = cub::BlockReduce; @@ -194,20 +186,12 @@ __global__ void SoftmaxLargeKernel(const int all_sequence_length, __shared__ float sum_reverse_block; __shared__ float max_block; - // Update end position for unidirectional. + // Update end position for causal. int end = valid_end; - int end_unid = -1; - if (is_unidirectional) { - end_unid = all_sequence_length - sequence_length + (blockIdx.x % sequence_length) + 1; - if (end_unid <= valid_start) { - ; - // In this situation, mask of [0, end_unid) and [valid_start, valid_end) has -10000, - // and [end_unid, valid_start) and [valid_end, all_seq_len) has -20000. - // So [0, end_unid) will also have value after softmax. - // KEEP SMALL KERNEL CODE LOGIC HERE as COMMENT - // is_valid = threadIdx.x < end_unid; // is_valid initialized with false - } else { - end = min(valid_end, end_unid); + if (causal) { + int end_causal = all_sequence_length - sequence_length + (blockIdx.x % sequence_length) + 1; + if (end_causal < end) { + end = end_causal; } } @@ -218,7 +202,7 @@ __global__ void SoftmaxLargeKernel(const int all_sequence_length, float thread_data_max = -CUDART_INF_F; for (int seq_idx = threadIdx.x; seq_idx < all_sequence_length; seq_idx += TPB) { const int index = offset + seq_idx; - bool is_valid = (seq_idx < end_unid) || (seq_idx >= valid_start && seq_idx < end); + const bool is_valid = (seq_idx >= valid_start && seq_idx < end); // e^x is represented as infinity if x is large enough, like 100.f. // Infinity divided by Infinity is a NAN. Thus, softmax gets a NAN if one or more item are large enough. @@ -244,7 +228,7 @@ __global__ void SoftmaxLargeKernel(const int all_sequence_length, float thread_data_exp(0.f); for (int seq_idx = threadIdx.x; seq_idx < all_sequence_length; seq_idx += TPB) { - bool is_valid = (seq_idx < end_unid) || (seq_idx >= valid_start && seq_idx < end); + const bool is_valid = (seq_idx >= valid_start && seq_idx < end); cached_data[seq_idx] = is_valid ? expf(cached_data[seq_idx] - max_block) : 0.0f; thread_data_exp += cached_data[seq_idx]; } @@ -258,7 +242,8 @@ __global__ void SoftmaxLargeKernel(const int all_sequence_length, // threadIdx.x might be larger than all_sequence_length due to alignment to 32x. for (int seq_idx = threadIdx.x; seq_idx < all_sequence_length; seq_idx += TPB) { - output[offset + seq_idx] = T(cached_data[seq_idx] * sum_reverse_block); + const bool is_valid = (seq_idx >= valid_start && seq_idx < end); + output[offset + seq_idx] = is_valid ? T(cached_data[seq_idx] * sum_reverse_block) : T(0.f); } } @@ -271,7 +256,7 @@ __global__ void SoftmaxWithRawMaskLargeKernel(const int all_sequence_length, const bool broadcast_rel_pos_bias, const T* input, T* output, - const bool is_unidirectional, + const bool causal, const float rsqrt_head_size, const int mask_dimension, const int max_sequence_length, @@ -301,10 +286,10 @@ __global__ void SoftmaxWithRawMaskLargeKernel(const int all_sequence_length, } const int sequence_index = blockIdx.x % sequence_length; - if (is_unidirectional) { + if (causal) { int from_index = all_sequence_length - sequence_length + sequence_index; // offset in all sequence length. if (seq_idx > from_index) { - thread_data = mask_filter_value; + thread_data = -CUDART_INF_F; } } @@ -377,7 +362,7 @@ __device__ inline void SoftmaxWithRawMaskSmall(const int all_sequence_length, const bool broadcast_rel_pos_bias, const T* input, T* output, - const bool is_unidirectional, + const bool causal, const float rsqrt_head_size, const int mask_dimension, const int max_sequence_length, @@ -398,10 +383,10 @@ __device__ inline void SoftmaxWithRawMaskSmall(const int all_sequence_length, thread_data = float(input[index]) * rsqrt_head_size; const int sequence_index = blockIdx.x % sequence_length; - if (is_unidirectional) { + if (causal) { int from_index = all_sequence_length - sequence_length + sequence_index; // offset in all sequence length. if (threadIdx.x > from_index) { - thread_data = mask_filter_value; + thread_data = -CUDART_INF_F; } } @@ -469,9 +454,9 @@ __global__ void SoftmaxKernelSmall(const int all_sequence_length, const bool broadcast_rel_pos_bias, const T* input, T* output, - bool is_unidirectional) { + bool causal) { SoftmaxSmall(all_sequence_length, sequence_length, all_sequence_length, 0, - rel_pos_bias, broadcast_rel_pos_bias, input, output, is_unidirectional); + rel_pos_bias, broadcast_rel_pos_bias, input, output, causal); } template @@ -487,33 +472,33 @@ __global__ void SoftmaxKernel(const int all_sequence_length, 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 bool broadcast_rel_pos_bias, T* input, T* output, bool is_unidirectional) { + const bool broadcast_rel_pos_bias, 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, rel_pos_bias, broadcast_rel_pos_bias, input, output, is_unidirectional); + all_sequence_length, sequence_length, rel_pos_bias, broadcast_rel_pos_bias, input, output, causal); } else if (all_sequence_length <= 64) { const int blockSize = 64; SoftmaxKernelSmall<<>>( - all_sequence_length, sequence_length, rel_pos_bias, broadcast_rel_pos_bias, input, output, is_unidirectional); + all_sequence_length, sequence_length, rel_pos_bias, broadcast_rel_pos_bias, input, output, causal); } else if (all_sequence_length <= 128) { const int blockSize = 128; SoftmaxKernelSmall<<>>( - all_sequence_length, sequence_length, rel_pos_bias, broadcast_rel_pos_bias, input, output, is_unidirectional); + all_sequence_length, sequence_length, rel_pos_bias, broadcast_rel_pos_bias, input, output, causal); } else if (all_sequence_length <= 256) { const int blockSize = 256; SoftmaxKernelSmall<<>>( - all_sequence_length, sequence_length, rel_pos_bias, broadcast_rel_pos_bias, input, output, is_unidirectional); + all_sequence_length, sequence_length, rel_pos_bias, broadcast_rel_pos_bias, input, output, causal); } else if (all_sequence_length <= 512) { const int blockSize = 512; SoftmaxKernelSmall<<>>( - all_sequence_length, sequence_length, rel_pos_bias, broadcast_rel_pos_bias, input, output, is_unidirectional); + all_sequence_length, sequence_length, rel_pos_bias, broadcast_rel_pos_bias, input, output, causal); } else if (all_sequence_length <= 1024) { const int blockSize = 1024; SoftmaxKernelSmall<<>>( - all_sequence_length, sequence_length, rel_pos_bias, broadcast_rel_pos_bias, input, output, is_unidirectional); - } else if (!is_unidirectional) { + all_sequence_length, sequence_length, rel_pos_bias, broadcast_rel_pos_bias, input, output, causal); + } else if (!causal) { const int blockSize = 1024; SoftmaxKernel<<>>( all_sequence_length, rel_pos_bias, broadcast_rel_pos_bias, input, output); @@ -537,7 +522,7 @@ __global__ void MaskedSoftmaxKernelSmall(const int all_sequence_length, const bool broadcast_rel_pos_bias, const T* input, T* output, - bool is_unidirectional) { + bool causal) { __shared__ int start_position; __shared__ int end_position; @@ -555,7 +540,7 @@ __global__ void MaskedSoftmaxKernelSmall(const int all_sequence_length, __syncthreads(); SoftmaxSmall(all_sequence_length, sequence_length, end_position, start_position, - rel_pos_bias, broadcast_rel_pos_bias, input, output, is_unidirectional); + rel_pos_bias, broadcast_rel_pos_bias, input, output, causal); } template @@ -688,7 +673,7 @@ __global__ void SoftmaxWithRawMaskSmallKernel(const int all_sequence_length, const bool broadcast_rel_pos_bias, const T* input, T* output, - const bool is_unidirectional, + const bool causal, const float rsqrt_head_size, const int mask_dimension, const int max_sequence_length, @@ -697,7 +682,7 @@ __global__ void SoftmaxWithRawMaskSmallKernel(const int all_sequence_length, SoftmaxWithRawMaskSmall( all_sequence_length, sequence_length, attention_mask, key_padding_mask, rel_pos_bias, broadcast_rel_pos_bias, input, output, - is_unidirectional, rsqrt_head_size, mask_dimension, max_sequence_length, + causal, rsqrt_head_size, mask_dimension, max_sequence_length, skip_softmax, mask_filter_value); } @@ -765,40 +750,40 @@ Status ComputeSoftmaxWithMask1D(cudaStream_t stream, const bool broadcast_rel_pos_bias, const T* input, T* output, - const bool is_unidirectional) { + const bool causal) { const dim3 grid(sequence_length * num_heads, batch_size, 1); if (all_sequence_length <= 32) { const int blockSize = 32; MaskedSoftmaxKernelSmall <<>>(all_sequence_length, sequence_length, mask_index, mask_start, - rel_pos_bias, broadcast_rel_pos_bias, input, output, is_unidirectional); + rel_pos_bias, broadcast_rel_pos_bias, input, output, causal); } else if (all_sequence_length <= 64) { const int blockSize = 64; MaskedSoftmaxKernelSmall <<>>(all_sequence_length, sequence_length, mask_index, mask_start, - rel_pos_bias, broadcast_rel_pos_bias, input, output, is_unidirectional); + rel_pos_bias, broadcast_rel_pos_bias, input, output, causal); } else if (all_sequence_length <= 128) { const int blockSize = 128; MaskedSoftmaxKernelSmall <<>>(all_sequence_length, sequence_length, mask_index, mask_start, - rel_pos_bias, broadcast_rel_pos_bias, input, output, is_unidirectional); + rel_pos_bias, broadcast_rel_pos_bias, input, output, causal); } else if (all_sequence_length <= 256) { const int blockSize = 256; MaskedSoftmaxKernelSmall <<>>(all_sequence_length, sequence_length, mask_index, mask_start, - rel_pos_bias, broadcast_rel_pos_bias, input, output, is_unidirectional); + rel_pos_bias, broadcast_rel_pos_bias, input, output, causal); } else if (all_sequence_length <= 512) { const int blockSize = 512; MaskedSoftmaxKernelSmall <<>>(all_sequence_length, sequence_length, mask_index, mask_start, - rel_pos_bias, broadcast_rel_pos_bias, input, output, is_unidirectional); + rel_pos_bias, broadcast_rel_pos_bias, input, output, causal); } else if (all_sequence_length <= 1024) { const int blockSize = 1024; MaskedSoftmaxKernelSmall <<>>(all_sequence_length, sequence_length, mask_index, mask_start, - rel_pos_bias, broadcast_rel_pos_bias, input, output, is_unidirectional); - } else if (!is_unidirectional) { + rel_pos_bias, broadcast_rel_pos_bias, input, output, causal); + } else if (!causal) { const int blockSize = 1024; MaskedSoftmaxKernel <<>>(all_sequence_length, mask_index, mask_start, @@ -811,7 +796,7 @@ Status ComputeSoftmaxWithMask1D(cudaStream_t stream, } template -Status ComputeSoftmaxWithRawMask(cudaStream_t stream, +Status ComputeSoftmaxWithRawMask(Stream* ort_stream, const int all_sequence_length, const int sequence_length, const int batch_size, @@ -822,13 +807,14 @@ Status ComputeSoftmaxWithRawMask(cudaStream_t stream, const bool broadcast_rel_pos_bias, const T* input, T* output, - const bool is_unidirectional, + const bool causal, const float rsqrt_head_size, const int mask_dimension, const int max_sequence_length, const bool use_persistent_softmax, T* persistent_softmax_workspace, const float mask_filter_value) { + auto stream = static_cast(ort_stream->GetHandle()); const dim3 grid(sequence_length * num_heads, batch_size, 1); T* out = use_persistent_softmax ? persistent_softmax_workspace : output; @@ -837,42 +823,42 @@ Status ComputeSoftmaxWithRawMask(cudaStream_t stream, SoftmaxWithRawMaskSmallKernel <<>>(all_sequence_length, sequence_length, attention_mask, key_padding_mask, rel_pos_bias, broadcast_rel_pos_bias, input, - out, is_unidirectional, rsqrt_head_size, mask_dimension, max_sequence_length, + out, causal, rsqrt_head_size, mask_dimension, max_sequence_length, use_persistent_softmax, mask_filter_value); } else if (all_sequence_length <= 64) { const int blockSize = 64; SoftmaxWithRawMaskSmallKernel <<>>(all_sequence_length, sequence_length, attention_mask, key_padding_mask, rel_pos_bias, broadcast_rel_pos_bias, input, - out, is_unidirectional, rsqrt_head_size, mask_dimension, max_sequence_length, + out, causal, rsqrt_head_size, mask_dimension, max_sequence_length, use_persistent_softmax, mask_filter_value); } else if (all_sequence_length <= 128) { const int blockSize = 128; SoftmaxWithRawMaskSmallKernel <<>>(all_sequence_length, sequence_length, attention_mask, key_padding_mask, rel_pos_bias, broadcast_rel_pos_bias, input, - out, is_unidirectional, rsqrt_head_size, mask_dimension, max_sequence_length, + out, causal, rsqrt_head_size, mask_dimension, max_sequence_length, use_persistent_softmax, mask_filter_value); } else if (all_sequence_length <= 256) { const int blockSize = 256; SoftmaxWithRawMaskSmallKernel <<>>(all_sequence_length, sequence_length, attention_mask, key_padding_mask, rel_pos_bias, broadcast_rel_pos_bias, input, - out, is_unidirectional, rsqrt_head_size, mask_dimension, max_sequence_length, + out, causal, rsqrt_head_size, mask_dimension, max_sequence_length, use_persistent_softmax, mask_filter_value); } else if (all_sequence_length <= 512) { const int blockSize = 512; SoftmaxWithRawMaskSmallKernel <<>>(all_sequence_length, sequence_length, attention_mask, key_padding_mask, rel_pos_bias, broadcast_rel_pos_bias, input, - out, is_unidirectional, rsqrt_head_size, mask_dimension, max_sequence_length, + out, causal, rsqrt_head_size, mask_dimension, max_sequence_length, use_persistent_softmax, mask_filter_value); } else if (all_sequence_length <= 1024) { const int blockSize = 1024; SoftmaxWithRawMaskSmallKernel <<>>(all_sequence_length, sequence_length, attention_mask, key_padding_mask, rel_pos_bias, broadcast_rel_pos_bias, input, - out, is_unidirectional, rsqrt_head_size, mask_dimension, max_sequence_length, + out, causal, rsqrt_head_size, mask_dimension, max_sequence_length, use_persistent_softmax, mask_filter_value); } else { const int blockSize = 256; @@ -881,13 +867,13 @@ Status ComputeSoftmaxWithRawMask(cudaStream_t stream, <<>>( all_sequence_length, sequence_length, attention_mask, key_padding_mask, rel_pos_bias, broadcast_rel_pos_bias, input, - out, is_unidirectional, rsqrt_head_size, mask_dimension, max_sequence_length, + out, causal, rsqrt_head_size, mask_dimension, max_sequence_length, use_persistent_softmax, mask_filter_value); } if (use_persistent_softmax) { return onnxruntime::cuda::dispatch_warpwise_softmax_forward( - stream, + ort_stream, output, persistent_softmax_workspace, all_sequence_length, @@ -902,12 +888,12 @@ Status ComputeSoftmaxWithRawMask(cudaStream_t stream, template Status ComputeSoftmax( cudaStream_t stream, const int all_sequence_length, const int sequence_length, const int batch_size, const int num_heads, const float* rel_pos_bias, - const bool broadcast_rel_pos_bias, float* input, float* output, bool is_unidirectional); + const bool broadcast_rel_pos_bias, float* input, float* output, bool causal); template Status ComputeSoftmax( cudaStream_t stream, const int all_sequence_length, const int sequence_length, const int batch_size, const int num_heads, const half* rel_pos_bias, - const bool broadcast_rel_pos_bias, half* input, half* output, bool is_unidirectional); + const bool broadcast_rel_pos_bias, half* input, half* output, bool causal); template Status ComputeSoftmaxWithCumSeqLength( const float* input, @@ -940,7 +926,7 @@ template Status ComputeSoftmaxWithMask1D(cudaStream_t stream, const bool broadcast_rel_pos_bias, const float* input, float* output, - const bool is_unidirectional); + const bool causal); template Status ComputeSoftmaxWithMask1D(cudaStream_t stream, const int all_sequence_length, @@ -953,9 +939,9 @@ template Status ComputeSoftmaxWithMask1D(cudaStream_t stream, const bool broadcast_rel_pos_bias, const half* input, half* output, - const bool is_unidirectional); + const bool causal); -template Status ComputeSoftmaxWithRawMask(cudaStream_t stream, +template Status ComputeSoftmaxWithRawMask(Stream* ort_stream, const int all_sequence_length, const int sequence_length, const int batch_size, @@ -966,7 +952,7 @@ template Status ComputeSoftmaxWithRawMask(cudaStream_t stream, const bool broadcast_rel_pos_bias, const float* input, float* output, - const bool is_unidirectional, + const bool causal, const float rsqrt_head_size, const int mask_dimension, const int max_sequence_length, @@ -974,7 +960,7 @@ template Status ComputeSoftmaxWithRawMask(cudaStream_t stream, float* persistent_softmax_workspace, const float mask_filter_value); -template Status ComputeSoftmaxWithRawMask(cudaStream_t stream, +template Status ComputeSoftmaxWithRawMask(Stream* ort_stream, const int all_sequence_length, const int sequence_length, const int batch_size, @@ -985,7 +971,7 @@ template Status ComputeSoftmaxWithRawMask(cudaStream_t stream, const bool broadcast_rel_pos_bias, const half* input, half* output, - const bool is_unidirectional, + const bool causal, const float rsqrt_head_size, const int mask_dimension, const int max_sequence_length, diff --git a/onnxruntime/contrib_ops/cuda/bert/attention_softmax.h b/onnxruntime/contrib_ops/cuda/bert/attention_softmax.h index 4af9e4d695d70..46d2423fa7009 100644 --- a/onnxruntime/contrib_ops/cuda/bert/attention_softmax.h +++ b/onnxruntime/contrib_ops/cuda/bert/attention_softmax.h @@ -10,7 +10,7 @@ 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 bool broadcast_rel_pos_bias, T* input, T* output, bool is_unidirectional); + const bool broadcast_rel_pos_bias, T* input, T* output, bool causal); template Status ComputeSoftmaxWithCumSeqLength( @@ -35,10 +35,10 @@ Status ComputeSoftmaxWithMask1D(cudaStream_t stream, const bool broadcast_rel_pos_bias, const T* input, T* output, - const bool is_unidirectional); + const bool causal); template -Status ComputeSoftmaxWithRawMask(cudaStream_t stream, +Status ComputeSoftmaxWithRawMask(Stream* ort_stream, const int all_sequence_length, const int sequence_length, const int batch_size, @@ -49,7 +49,7 @@ Status ComputeSoftmaxWithRawMask(cudaStream_t stream, const bool broadcast_rel_pos_bias, const T* input, T* output, - const bool is_unidirectional, + const bool causal, const float rsqrt_head_size, const int mask_dimension, const int max_sequence_length, diff --git a/onnxruntime/contrib_ops/cuda/bert/attention_strided_copy.cu b/onnxruntime/contrib_ops/cuda/bert/attention_strided_copy.cu new file mode 100644 index 0000000000000..1466f5fcfe0be --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/attention_strided_copy.cu @@ -0,0 +1,158 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/providers/cuda/cuda_common.h" +#include "contrib_ops/cuda/bert/attention_impl.h" + +using namespace onnxruntime::cuda; + +namespace onnxruntime { +namespace contrib { +namespace cuda { + +template +__global__ void StridedCopy(const T* in, const int H, longlong4 in_strides, // coord (b,n,s,h) + T* out, longlong4 out_strides // coord (b,n,s,h) +) { + const int h = threadIdx.x; + const int n = threadIdx.y; + const int s = blockIdx.x; + const int b = blockIdx.y; + if (h < H) { + const int in_offset = b * in_strides.x + n * in_strides.y + s * in_strides.z + h * in_strides.w; + const int out_offset = b * out_strides.x + n * out_strides.y + s * out_strides.z + h * out_strides.w; + out[out_offset] = in[in_offset]; + } +} + +template +__global__ void StridedCopyLarge(const T* in, const int H, longlong4 in_strides, // coord (b,n,s,h) + T* out, longlong4 out_strides // coord (b,n,s,h) +) { + // Use when (H*)*num_heads > 1024 + int h = threadIdx.x; + const int n = threadIdx.y; + const int s = blockIdx.x; + const int b = blockIdx.y; + + const int h_step = blockDim.x; + + while (h < H) { + const int in_offset = b * in_strides.x + n * in_strides.y + s * in_strides.z + h * in_strides.w; + const int out_offset = b * out_strides.x + n * out_strides.y + s * out_strides.z + h * out_strides.w; + out[out_offset] = in[in_offset]; + h += h_step; + } +} + +template +struct ToByteType; + +template <> +struct ToByteType<2> { + using T = int16_t; +}; + +template <> +struct ToByteType<4> { + using T = int32_t; +}; + +template <> +struct ToByteType<8> { + using T = int64_t; +}; + +template <> +struct ToByteType<16> { + using T = uint4; +}; + +template <> +struct ToByteType<32> { + using T = ulonglong4; +}; + +template +using ToBytes = typename ToByteType::T; + +template +Status LaunchStridedCopy(cudaStream_t stream, + const T* in, int4 in_shape, longlong4 in_strides, // coord (b,n,s,h) + T* out, longlong4 out_strides, // coord (b,n,s,h) + int max_threads_per_block) { + int batch_size = in_shape.x; + int num_heads = in_shape.y; + int sequence_length = in_shape.z; + int head_size = in_shape.w; + if (sequence_length == 0) { + return Status::OK(); + } + + const dim3 grid(sequence_length, batch_size); + if (0 == (head_size % 4)) { // pack 4 element together + using Bytes = ToBytes; + const int H = head_size / 4; + in_strides.x /= 4; + in_strides.y /= 4; + in_strides.z /= 4; + out_strides.x /= 4; + out_strides.y /= 4; + out_strides.z /= 4; + if (H * num_heads <= max_threads_per_block) { + const dim3 block(H, num_heads, 1); + StridedCopy<<>>(reinterpret_cast(in), H, in_strides, + reinterpret_cast(out), out_strides); + } else { + const dim3 block(max_threads_per_block / num_heads, num_heads, 1); + StridedCopyLarge<<>>(reinterpret_cast(in), H, in_strides, + reinterpret_cast(out), out_strides); + } + } else if (0 == (head_size % 2)) { // pack 2 element together + using Bytes = ToBytes; + const int H = head_size / 2; + in_strides.x /= 2; + in_strides.y /= 2; + in_strides.z /= 2; + out_strides.x /= 2; + out_strides.y /= 2; + out_strides.z /= 2; + if (H * num_heads <= max_threads_per_block) { + const dim3 block(H, num_heads, 1); + StridedCopy<<>>(reinterpret_cast(in), H, in_strides, + reinterpret_cast(out), out_strides); + } else { + const dim3 block(max_threads_per_block / num_heads, num_heads, 1); + StridedCopyLarge<<>>(reinterpret_cast(in), H, in_strides, + reinterpret_cast(out), out_strides); + } + } else { + using Bytes = ToBytes; + if (head_size * num_heads <= max_threads_per_block) { + const dim3 block(head_size, num_heads, 1); + StridedCopy<<>>(reinterpret_cast(in), head_size, in_strides, + reinterpret_cast(out), out_strides); + } else { + const dim3 block(max_threads_per_block / num_heads, num_heads, 1); + StridedCopyLarge<<>>(reinterpret_cast(in), head_size, in_strides, + reinterpret_cast(out), out_strides); + } + } + return CUDA_CALL(cudaGetLastError()); +} + +template Status LaunchStridedCopy( + cudaStream_t stream, + const float* in, int4 in_shape, longlong4 in_strides, + float* out, longlong4 out_strides, + int max_threads_per_block); + +template Status LaunchStridedCopy( + cudaStream_t stream, + const half* in, int4 in_shape, longlong4 in_strides, + half* out, longlong4 out_strides, + int max_threads_per_block); + +} // namespace cuda +} // namespace contrib +} // namespace onnxruntime 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 ed38cabc464a2..ed330b0fca332 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 @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#if USE_FLASH_ATTENTION +#if USE_MEMORY_EFFICIENT_ATTENTION #if defined(__GNUC__) #pragma GCC diagnostic push @@ -89,12 +89,17 @@ void LaunchCutlassFmha(const MemoryEfficientAttentionParams& params) { template void DispatchIsAligned(const MemoryEfficientAttentionParams& params) { using AlignedAK = AttentionKernel; - +#if defined(_MSC_VER) && !defined(__clang__) +#pragma warning(push) +#pragma warning(disable : 6287) +#endif // Run a more efficient kernel with `isAligned=True` when memory is correctly aligned. bool is_aligned = params.qk_head_size % AlignedAK::kAlignmentQ == 0 && params.qk_head_size % AlignedAK::kAlignmentK == 0 && params.v_head_size % AlignedAK::kAlignmentV == 0; - +#if defined(_MSC_VER) && !defined(__clang__) +#pragma warning(pop) +#endif DISPATCH_BOOL(is_aligned, kIsAligned, ([&]() { LaunchCutlassFmha(params); })); @@ -119,4 +124,4 @@ void DispatchBlockSize(const MemoryEfficientAttentionParams& params) { #pragma GCC diagnostic pop #endif -#endif // USE_FLASH_ATTENTION +#endif // USE_MEMORY_EFFICIENT_ATTENTION diff --git a/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/fmha_sm50.cu b/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/fmha_sm50.cu index 237f7ea8c9c42..540a2699587eb 100644 --- a/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/fmha_sm50.cu +++ b/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/fmha_sm50.cu @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#if USE_FLASH_ATTENTION +#if USE_MEMORY_EFFICIENT_ATTENTION #include "contrib_ops/cuda/bert/cutlass_fmha/fmha_launch_template.h" @@ -21,4 +21,4 @@ void run_memory_efficient_attention_sm50(const MemoryEfficientAttentionParams& p } // namespace contrib } // namespace onnxruntime -#endif // USE_FLASH_ATTENTION +#endif // USE_MEMORY_EFFICIENT_ATTENTION diff --git a/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/fmha_sm70.cu b/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/fmha_sm70.cu index 941ea87baa398..005425c56e0ae 100644 --- a/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/fmha_sm70.cu +++ b/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/fmha_sm70.cu @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#if USE_FLASH_ATTENTION +#if USE_MEMORY_EFFICIENT_ATTENTION #include "contrib_ops/cuda/bert/cutlass_fmha/fmha_launch_template.h" @@ -21,4 +21,4 @@ void run_memory_efficient_attention_sm70(const MemoryEfficientAttentionParams& p } // namespace contrib } // namespace onnxruntime -#endif // USE_FLASH_ATTENTION +#endif // USE_MEMORY_EFFICIENT_ATTENTION diff --git a/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/fmha_sm75.cu b/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/fmha_sm75.cu index 5a0e7c9ed5b7a..955423b6c6762 100644 --- a/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/fmha_sm75.cu +++ b/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/fmha_sm75.cu @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#if USE_FLASH_ATTENTION +#if USE_MEMORY_EFFICIENT_ATTENTION #include "contrib_ops/cuda/bert/cutlass_fmha/fmha_launch_template.h" @@ -21,4 +21,4 @@ void run_memory_efficient_attention_sm75(const MemoryEfficientAttentionParams& p } // namespace contrib } // namespace onnxruntime -#endif // USE_FLASH_ATTENTION +#endif // USE_MEMORY_EFFICIENT_ATTENTION diff --git a/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/fmha_sm80.cu b/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/fmha_sm80.cu index d0775a29c4cf1..0b54d90c4da30 100644 --- a/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/fmha_sm80.cu +++ b/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/fmha_sm80.cu @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#if USE_FLASH_ATTENTION +#if USE_MEMORY_EFFICIENT_ATTENTION #include "contrib_ops/cuda/bert/cutlass_fmha/fmha_launch_template.h" @@ -21,4 +21,4 @@ void run_memory_efficient_attention_sm80(const MemoryEfficientAttentionParams& p } // namespace contrib } // namespace onnxruntime -#endif // USE_FLASH_ATTENTION +#endif // USE_MEMORY_EFFICIENT_ATTENTION diff --git a/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/memory_efficient_attention.cu b/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/memory_efficient_attention.cu index 284211f96514d..750cace39ae39 100644 --- a/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/memory_efficient_attention.cu +++ b/onnxruntime/contrib_ops/cuda/bert/cutlass_fmha/memory_efficient_attention.cu @@ -1,6 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#if USE_FLASH_ATTENTION +#if USE_MEMORY_EFFICIENT_ATTENTION #include "contrib_ops/cuda/bert/cutlass_fmha/memory_efficient_attention.h" @@ -27,4 +27,4 @@ void run_memory_efficient_attention(const MemoryEfficientAttentionParams& params } // namespace contrib } // namespace onnxruntime -#endif // USE_FLASH_ATTENTION +#endif // USE_MEMORY_EFFICIENT_ATTENTION 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 326ff451e600a..f725be8d7cf89 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 @@ -2,7 +2,7 @@ // Licensed under the MIT License. #pragma once -#if USE_FLASH_ATTENTION +#if USE_MEMORY_EFFICIENT_ATTENTION #include "core/providers/cuda/cuda_common.h" #include "contrib_ops/cpu/bert/attention_common.h" @@ -58,4 +58,4 @@ void run_memory_efficient_attention_sm50(const MemoryEfficientAttentionParams& p } // namespace contrib } // namespace onnxruntime -#endif // USE_FLASH_ATTENTION +#endif // USE_MEMORY_EFFICIENT_ATTENTION diff --git a/onnxruntime/contrib_ops/cuda/bert/decoder_attention.cc b/onnxruntime/contrib_ops/cuda/bert/decoder_attention.cc index c9f1920190111..3f703ae3d05e6 100644 --- a/onnxruntime/contrib_ops/cuda/bert/decoder_attention.cc +++ b/onnxruntime/contrib_ops/cuda/bert/decoder_attention.cc @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "contrib_ops/cuda/bert/attention_impl.h" #include "contrib_ops/cuda/bert/decoder_attention.h" +#include "contrib_ops/cuda/bert/decoder_attention_impl.h" #include "contrib_ops/cuda/bert/transformer_cuda_common.h" #include "core/framework/op_kernel.h" #include "core/providers/cuda/shared_inc/fpgeneric.h" @@ -85,7 +85,8 @@ Status CheckInputs(const TensorShape& query_shape, } if (kv_weights_dims[0] != hidden_size || kv_weights_dims[1] != 2 * static_cast(hidden_size)) { - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "kv_weights shall have shape (hidden size, 2 * hidden size)"); + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "kv_weights shall have shape (hidden size, 2 * hidden size)"); } const auto& bias_dims = bias_shape.GetDims(); @@ -137,7 +138,8 @@ Status CheckInputs(const TensorShape& query_shape, const auto& value_cache_dims = value_cache->Shape().GetDims(); if (value_cache_dims.size() != 4) { - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Input 'value_cache' is expected to have 4 dimension, got ", + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "Input 'value_cache' is expected to have 4 dimension, got ", value_cache_dims.size()); } @@ -353,10 +355,12 @@ Status DecoderAttention::ComputeInternal(OpKernelContext* context) const { } } - size_t bytes = element_size * batch_size * (static_cast(sequence_length) + static_cast(2) * kv_sequence_length) * hidden_size; + size_t bytes = element_size * batch_size * + (static_cast(sequence_length) + static_cast(2) * kv_sequence_length) * hidden_size; auto qkv_buffer_p = GetScratchBuffer(bytes, context->GetComputeStream()); - bytes = element_size * 2 * batch_size * sequence_length * num_heads_ * (static_cast(2) * head_size + static_cast(kv_sequence_length)); + bytes = element_size * 2 * batch_size * sequence_length * num_heads_ * + (static_cast(2) * head_size + static_cast(kv_sequence_length)); auto workspace_p = GetScratchBuffer(bytes, context->GetComputeStream()); Tensor* output(context->Output(0, query_shape)); @@ -369,7 +373,7 @@ Status DecoderAttention::ComputeInternal(OpKernelContext* context) const { #ifdef USE_ROCM GetTuningContext(), #endif - stream, + context->GetComputeStream(), cublas, element_size, batch_size, diff --git a/onnxruntime/contrib_ops/cuda/bert/decoder_attention_impl.cu b/onnxruntime/contrib_ops/cuda/bert/decoder_attention_impl.cu new file mode 100644 index 0000000000000..1dc22a9c8ea98 --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/decoder_attention_impl.cu @@ -0,0 +1,263 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "contrib_ops/cuda/bert/decoder_attention_impl.h" +#include "core/providers/cuda/cuda_common.h" +#include "core/providers/cuda/shared_inc/fpgeneric.h" +#include "contrib_ops/cuda/bert/attention_softmax.h" + +using namespace onnxruntime::contrib::attention_softmax_cuda; + +namespace onnxruntime { +namespace contrib { +namespace cuda { + +template +Status DecoderQkvToContext( + const cudaDeviceProp& device_prop, + Stream* ort_stream, + cublasHandle_t& cublas, + const size_t element_size, + const int batch_size, + const int sequence_length, + const int kv_sequence_length, + const int num_heads, + const int head_size, + const bool static_kv, + const bool use_past, + const bool has_layer_state, + const bool has_key_padding_mask, + const float mask_filter_value, + const T* gemm_query_buffer, + const T* gemm_kv_buffer, + const bool* key_padding_mask, + const T* key_cache, + const T* value_cache, + T* qkv_buffer, + T* workspace_buffer, + T* output, + T* new_key_cache, + T* new_value_cache) { + const int max_threads_per_block = device_prop.maxThreadsPerBlock; + const int BN = batch_size * num_heads; + const int BHN = BN * head_size; + const int BNS = BN * sequence_length; + const int k_buffer_offset = sequence_length * BHN; + const int v_buffer_offset = (sequence_length + kv_sequence_length) * BHN; + + T* temp_qkv_buffer = workspace_buffer; + auto stream = static_cast(ort_stream->GetHandle()); + + const T* q = qkv_buffer; + // transpose q and copy them to qkv_buffer + ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, 1, sequence_length, batch_size, head_size, num_heads, + max_threads_per_block, true, gemm_query_buffer, qkv_buffer)); + + const T* k = qkv_buffer + k_buffer_offset; + const T* v = qkv_buffer + v_buffer_offset; + if (!has_layer_state || !use_past) { + if (!static_kv) { + // transpose kv and copy them to qkv_buffer + ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, 2, sequence_length, batch_size, head_size, num_heads, + max_threads_per_block, true, gemm_kv_buffer, qkv_buffer + k_buffer_offset)); + } else { + // transpose kv and copy them to qkv_buffer + ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, 2, kv_sequence_length, batch_size, head_size, num_heads, + max_threads_per_block, true, gemm_kv_buffer, qkv_buffer + k_buffer_offset)); + } + } else { + if (!static_kv) { + // transpose kv and copy them to temp_buffer + ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, 2, sequence_length, batch_size, head_size, num_heads, + max_threads_per_block, true, gemm_kv_buffer, temp_qkv_buffer)); + // concat cache-k with k and copy to qkv_buffer + if (nullptr != key_cache) { + ORT_RETURN_IF_ERROR(LaunchConcatTensorToTensor(stream, kv_sequence_length, + sequence_length, batch_size, head_size, num_heads, + max_threads_per_block, 1, + key_cache, + temp_qkv_buffer, + qkv_buffer + k_buffer_offset)); + } + // concat cache-v with v and copy to qkv_buffer + if (nullptr != value_cache) { + ORT_RETURN_IF_ERROR(LaunchConcatTensorToTensor(stream, kv_sequence_length, + sequence_length, batch_size, head_size, num_heads, + max_threads_per_block, 1, + value_cache, + temp_qkv_buffer + k_buffer_offset, + qkv_buffer + v_buffer_offset)); + } + } + } + + if (has_layer_state) { + if (use_past && static_kv) { + CUDA_RETURN_IF_ERROR(cudaMemcpyAsync(new_key_cache, key_cache, kv_sequence_length * BHN * sizeof(T), + cudaMemcpyDeviceToDevice, stream)); + CUDA_RETURN_IF_ERROR(cudaMemcpyAsync(new_value_cache, value_cache, kv_sequence_length * BHN * sizeof(T), + cudaMemcpyDeviceToDevice, stream)); + } else { + CUDA_RETURN_IF_ERROR(cudaMemcpyAsync(new_key_cache, k, kv_sequence_length * BHN * sizeof(T), + cudaMemcpyDeviceToDevice, stream)); + CUDA_RETURN_IF_ERROR(cudaMemcpyAsync(new_value_cache, v, kv_sequence_length * BHN * sizeof(T), + cudaMemcpyDeviceToDevice, stream)); + } + } + + // scratch1: BxNxSxL buffer + // scratch2: BxNxSxL buffer + // scratch3: BxNxSxH buffer + T* scratch1 = temp_qkv_buffer + 3 * BHN * sequence_length; + T* scratch2 = scratch1 + BNS * kv_sequence_length; + T* scratch3 = scratch2 + BNS * kv_sequence_length; + + // compute Q*K' (as K'*Q), scaled by 1/sqrt(H) and store in scratch1: BxNxSxL + // Q: BxNxSxH, K (present_k): BxNxLxH, Q*K': BxNxSxL + const float rsqrt_head_size = 1.f / sqrt(static_cast(head_size)); + const int temp_matrix_size = sequence_length * kv_sequence_length; + float one = 1.0f; + float zero = 0.f; + + float alpha = rsqrt_head_size; + const int strideA = kv_sequence_length * head_size; + const int strideB = sequence_length * head_size; + if (use_past && static_kv) { + CUBLAS_RETURN_IF_ERROR(cublasGemmStridedBatchedHelper( + cublas, CUBLAS_OP_T, CUBLAS_OP_N, + kv_sequence_length, sequence_length, head_size, + &alpha, key_cache, head_size, strideA, + q, head_size, strideB, + &zero, scratch1, kv_sequence_length, temp_matrix_size, BN, device_prop)); + } else { + CUBLAS_RETURN_IF_ERROR(cublasGemmStridedBatchedHelper( + cublas, CUBLAS_OP_T, CUBLAS_OP_N, + kv_sequence_length, sequence_length, head_size, + &alpha, k, head_size, strideA, + q, head_size, strideB, + &zero, scratch1, kv_sequence_length, temp_matrix_size, BN, device_prop)); + } + + constexpr bool is_unidirectional = false; + const T* add_before_softmax = nullptr; + if (has_key_padding_mask) { + constexpr int mask_dimension = 2; + constexpr int max_sequence_length = 0; + ORT_RETURN_IF_ERROR(ComputeSoftmaxWithRawMask( + ort_stream, kv_sequence_length, sequence_length, batch_size, + num_heads, nullptr, key_padding_mask, add_before_softmax, + false /*broadcast rpb*/, scratch1, scratch2, is_unidirectional, + 1.0f, mask_dimension, max_sequence_length, false, nullptr, + mask_filter_value)); + } else { + ORT_RETURN_IF_ERROR(ComputeSoftmax( + stream, kv_sequence_length, sequence_length, batch_size, num_heads, + add_before_softmax, false /*broadcast rpb*/, scratch1, scratch2, + is_unidirectional)); + } + + // compute P*V (as V*P), and store in scratch3: BxNxSxH + if (use_past && static_kv) { + CUBLAS_RETURN_IF_ERROR(cublasGemmStridedBatchedHelper( + cublas, CUBLAS_OP_N, CUBLAS_OP_N, + head_size, sequence_length, kv_sequence_length, + &one, value_cache, head_size, strideA, + scratch2, kv_sequence_length, temp_matrix_size, + &zero, scratch3, head_size, strideB, BN, device_prop)); + } else { + CUBLAS_RETURN_IF_ERROR(cublasGemmStridedBatchedHelper( + cublas, CUBLAS_OP_N, CUBLAS_OP_N, + head_size, sequence_length, kv_sequence_length, + &one, v, head_size, strideA, + scratch2, kv_sequence_length, temp_matrix_size, + &zero, scratch3, head_size, strideB, BN, device_prop)); + } + + // scratch3 is BxNxSxH, transpose to output SxBxNxH + return LaunchTransCtx(stream, sequence_length, batch_size, head_size, num_heads, + max_threads_per_block, true, scratch3, output); +} + +Status LaunchDecoderAttentionKernel( + const cudaDeviceProp& device_prop, + Stream* stream, + cublasHandle_t& cublas, + const size_t element_size, + const int batch_size, + const int sequence_length, + const int kv_sequence_length, + const int num_heads, + const int head_size, + const bool static_kv, + const bool use_past, + const bool has_layer_state, + const bool has_key_padding_mask, + const float mask_filter_value, + const void* gemm_query_buffer, + const void* gemm_kv_buffer, + const bool* key_padding_mask, + const void* key_cache, + const void* value_cache, + void* qkv_buffer, + void* workspace_buffer, + void* output, + void* new_key_cache, + void* new_value_cache) { + if (element_size == 2) { + return DecoderQkvToContext( + device_prop, + stream, + cublas, + element_size, + batch_size, + sequence_length, + kv_sequence_length, + num_heads, + head_size, + static_kv, + use_past, + has_layer_state, + has_key_padding_mask, + mask_filter_value, + reinterpret_cast(gemm_query_buffer), + reinterpret_cast(gemm_kv_buffer), + key_padding_mask, + reinterpret_cast(key_cache), + reinterpret_cast(value_cache), + reinterpret_cast(qkv_buffer), + reinterpret_cast(workspace_buffer), + reinterpret_cast(output), + reinterpret_cast(new_key_cache), + reinterpret_cast(new_value_cache)); + } else { + return DecoderQkvToContext( + device_prop, + stream, + cublas, + element_size, + batch_size, + sequence_length, + kv_sequence_length, + num_heads, + head_size, + static_kv, + use_past, + has_layer_state, + has_key_padding_mask, + mask_filter_value, + reinterpret_cast(gemm_query_buffer), + reinterpret_cast(gemm_kv_buffer), + key_padding_mask, + reinterpret_cast(key_cache), + reinterpret_cast(value_cache), + reinterpret_cast(qkv_buffer), + reinterpret_cast(workspace_buffer), + reinterpret_cast(output), + reinterpret_cast(new_key_cache), + reinterpret_cast(new_value_cache)); + } +} + +} // namespace cuda +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/bert/decoder_attention_impl.h b/onnxruntime/contrib_ops/cuda/bert/decoder_attention_impl.h new file mode 100644 index 0000000000000..9db9ccb45e330 --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/decoder_attention_impl.h @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "contrib_ops/cuda/bert/attention_impl.h" + +namespace onnxruntime { +namespace contrib { +namespace cuda { + +Status LaunchDecoderAttentionKernel( + const cudaDeviceProp& prop, // Device Properties + Stream* stream, // ORT Stream + cublasHandle_t& cublas, // Cublas handle + const size_t element_size, // Element size of input tensor + const int batch_size, // Batch size (B) + const int sequence_length, // Sequence length (S) + const int kv_sequence_length, // Key/Value/Cache sequence length + const int num_heads, // Number of attention heads (N) + const int head_size, // Hidden size per head (H) + const bool static_kv, // Whether cross attention or not + const bool use_past, // Whether use cache or not + const bool has_layer_state, // Whether output cache or not + const bool has_key_padding_mask, // Whether use key_padding_mask or not + const float mask_filter_value, // Mask filter value + const void* gemm_query_buffer, // Query buffer + const void* gemm_kv_buffer, // Key and value buffer + const bool* key_padding_mask, // Key padding mask + const void* key_cache, // Input key cache + const void* value_cache, // Input value cache + void* qkv_buffer, // Temporary buffer + void* workspace_buffer, // Temporary buffer + void* output, // Output tensor + void* new_key_cache, // New_key_cache tensor + void* new_value_cache // New_value_cache tensor +); + +} // namespace cuda +} // namespace contrib +} // namespace onnxruntime 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 5a1fbe2ad8524..4bdc6db30b036 100644 --- a/onnxruntime/contrib_ops/cuda/bert/decoder_masked_multihead_attention.cc +++ b/onnxruntime/contrib_ops/cuda/bert/decoder_masked_multihead_attention.cc @@ -22,6 +22,7 @@ static constexpr int kBeamWidthInputIndex = 8; static constexpr int kCacheIndirectionInputIndex = 9; static constexpr int kPastInputIndex = 5; static constexpr int kPresentOutputIndex = 1; +static constexpr int kBiasIndex = 10; #define REGISTER_KERNEL_TYPED(T1, T2) \ ONNX_OPERATOR_TYPED_KERNEL_EX( \ @@ -63,13 +64,15 @@ Status DecoderMaskedMultiHeadAttention::ComputeInternal(OpKernelContext* const Tensor* past_seq_len = context->Input(kPastSequenceLengthInputIndex); const Tensor* beam_width = context->Input(kBeamWidthInputIndex); const Tensor* cache_indir = context->Input(kCacheIndirectionInputIndex); + const Tensor* bias = context->Input(kBiasIndex); auto& device_prop = GetDeviceProp(); DecoderMaskedMultiHeadAttentionParams parameters; + bool is_dmmha_packing = (key == nullptr && value == nullptr); ORT_RETURN_IF_ERROR(multihead_attention_helper::CheckInputs(query, key, value, - nullptr, // bias + bias, mask_index, relative_position_bias, past_key, @@ -80,8 +83,16 @@ Status DecoderMaskedMultiHeadAttention::ComputeInternal(OpKernelContext* mask_filter_value_, scale_, past_present_share_buffer_, + is_dmmha_packing, // dmmha_packing device_prop.maxThreadsPerBlock)); + 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); + } + int batch_size = parameters.batch_size; int sequence_length = parameters.sequence_length; @@ -140,6 +151,9 @@ Status DecoderMaskedMultiHeadAttention::ComputeInternal(OpKernelContext* // parameters.k and paraneters.v are nullptr parameters.k_cache = const_cast(key->Data()); parameters.v_cache = const_cast(value->Data()); + parameters.k_bias = nullptr; + parameters.v_bias = nullptr; + } else { // Sanity check ORT_ENFORCE(past_present_share_buffer_); @@ -165,9 +179,14 @@ Status DecoderMaskedMultiHeadAttention::ComputeInternal(OpKernelContext* } parameters.is_cross_attention = false; - - parameters.k = const_cast(key->Data()); - parameters.v = const_cast(value->Data()); + parameters.is_packed_qkv = is_dmmha_packing; + + parameters.k = is_dmmha_packing + ? const_cast(query->Data() + parameters.hidden_size) + : const_cast(key->Data()); + parameters.v = is_dmmha_packing + ? 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; } 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 5552bdebfc008..69ed07101e647 100644 --- a/onnxruntime/contrib_ops/cuda/bert/decoder_masked_self_attention.cc +++ b/onnxruntime/contrib_ops/cuda/bert/decoder_masked_self_attention.cc @@ -185,6 +185,14 @@ Status DecoderMaskedSelfAttention::ComputeInternal(OpKernelContext* cont parameters.cache_indir = cache_indir->Data(); } + // NeoX rotary embedding + if (do_rotary_) { + ORT_ENFORCE(parameters.head_size == 64 || parameters.head_size == 128, + "Current implementation of rotary embedding only supports head size of 64 or 128"); + parameters.rotary_embedding_dim = parameters.head_size; + parameters.t_step = parameters.past_sequence_length; + } + switch (parameters.head_size) { case 32: mmha_launch_kernel(parameters, cuda_stream); diff --git a/onnxruntime/contrib_ops/cuda/bert/embed_layer_norm.cc b/onnxruntime/contrib_ops/cuda/bert/embed_layer_norm.cc index b4b2845b3d534..864e2d1623923 100644 --- a/onnxruntime/contrib_ops/cuda/bert/embed_layer_norm.cc +++ b/onnxruntime/contrib_ops/cuda/bert/embed_layer_norm.cc @@ -66,7 +66,7 @@ Status EmbedLayerNorm::ComputeInternal(OpKernelContext* context) const { return LaunchEmbedLayerNormKernel( Stream(context), output->MutableData(), - mask_index->MutableData(), + nullptr == mask_index ? nullptr : mask_index->MutableData(), input_ids->Data(), nullptr == segment_ids ? nullptr : segment_ids->Data(), nullptr == mask ? nullptr : mask->Data(), diff --git a/onnxruntime/contrib_ops/cuda/bert/embed_layer_norm_impl.cu b/onnxruntime/contrib_ops/cuda/bert/embed_layer_norm_impl.cu index 3a881056036a6..a2dfca8cd6f09 100644 --- a/onnxruntime/contrib_ops/cuda/bert/embed_layer_norm_impl.cu +++ b/onnxruntime/contrib_ops/cuda/bert/embed_layer_norm_impl.cu @@ -212,11 +212,14 @@ Status LaunchEmbedLayerNormKernel( void* embedding_sum, const int* position_ids, const bool broadcast_position_ids) { - if (nullptr == input_mask) { - CUDA_RETURN_IF_ERROR(cudaMemsetAsync(mask_index, 0, sizeof(int) * batch_size, stream)); - } else { - ORT_RETURN_IF_ERROR( - ComputeMaskIndex(stream, sequence_length, batch_size, input_mask, static_cast(mask_index))); + + if (mask_index != nullptr) { + if (nullptr == input_mask) { + CUDA_RETURN_IF_ERROR(cudaMemsetAsync(mask_index, 0, sizeof(int) * batch_size, stream)); + } else { + ORT_RETURN_IF_ERROR( + ComputeMaskIndex(stream, sequence_length, batch_size, input_mask, static_cast(mask_index))); + } } if (element_size == 2) { diff --git a/onnxruntime/contrib_ops/cuda/bert/embed_layer_norm_impl.h b/onnxruntime/contrib_ops/cuda/bert/embed_layer_norm_impl.h index 605f8b8dfd598..aaf1d891dab3a 100644 --- a/onnxruntime/contrib_ops/cuda/bert/embed_layer_norm_impl.h +++ b/onnxruntime/contrib_ops/cuda/bert/embed_layer_norm_impl.h @@ -1,5 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. + #pragma once #include "core/common/common.h" 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 4e7bfd2db4e87..c8877a5e3f872 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 @@ -25,6 +25,7 @@ // (2) When dealing with masked tokens, this kernel implementation deviates from FasterTransformer by applying // mask filter values. Appropriate commentary exists in the code below. +#include "contrib_ops/cuda/bert/rotary_embedding_util.h" #include "decoder_masked_multihead_attention_impl.h" #include "decoder_masked_multihead_attention_impl_utils.h" #include @@ -137,9 +138,9 @@ __global__ void masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentio float qk = 0.0F; - int qkv_base_offset = params.is_mha - ? bi * params.hidden_size + hi * head_size - : bi * (3 * params.hidden_size) + hi * head_size; + int qkv_base_offset = params.is_mha && !params.is_packed_qkv + ? bi * params.hidden_size + hi * head_size + : bi * (3 * params.hidden_size) + hi * head_size; const size_t bi_total_seq_length = bi * params.total_sequence_length; @@ -161,38 +162,16 @@ __global__ void masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentio q = vec_conversion(*reinterpret_cast(&reinterpret_cast(params.q)[qk_offset])); } - Qk_vec_k k; - - if (!params.is_cross_attention) { - zero(k); - - if (!is_masked) { - k = vec_conversion(*reinterpret_cast(&reinterpret_cast(params.k)[qk_offset])); - } - } + // The offset in the bias buffer. + int qk_bias_offset = hi * head_size + tidx * QK_VEC_SIZE; // Trigger the loads from the Q and K bias buffers. - Qk_vec_k q_bias; - Qk_vec_k k_bias; - if (!params.is_mha) { - // The offset in the bias buffer. - int qk_bias_offset = hi * head_size + tidx * QK_VEC_SIZE; - - zero(q_bias); - - if (!is_masked) { - q_bias = vec_conversion(*reinterpret_cast(&reinterpret_cast(params.q_bias)[qk_bias_offset])); - } + if (params.q_bias && !is_masked) { + Qk_vec_k q_bias; - zero(k_bias); + q_bias = vec_conversion(*reinterpret_cast(&reinterpret_cast(params.q_bias)[qk_bias_offset])); - if (!is_masked) { - k_bias = vec_conversion(*reinterpret_cast(&reinterpret_cast(params.k_bias)[qk_bias_offset])); - } - - // Computes the Q/K values with bias. q = add_vec(q, q_bias); - k = add_vec(k, k_bias); } T* params_k_cache = reinterpret_cast(params.k_cache); @@ -205,6 +184,66 @@ __global__ void masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentio } if (!params.is_cross_attention) { + Qk_vec_k k; + + zero(k); + + if (!is_masked) { + k = vec_conversion(*reinterpret_cast(&reinterpret_cast(params.k)[qk_offset])); + + if (params.k_bias) { + Qk_vec_k k_bias; + + k_bias = vec_conversion(*reinterpret_cast(&reinterpret_cast(params.k_bias)[qk_bias_offset])); + + k = add_vec(k, k_bias); + } + } + + if (params.rotary_embedding_dim > 0) { + const bool do_rotary = !is_masked && QK_VEC_SIZE * tidx < params.rotary_embedding_dim; + + T* q_smem = reinterpret_cast(smem_); + T* k_smem = q_smem + params.rotary_embedding_dim; + + const int half_rotary_dim = params.rotary_embedding_dim / 2; + const int half_idx = (tidx * QK_VEC_SIZE) / half_rotary_dim; + const int intra_half_idx = (tidx * QK_VEC_SIZE) % half_rotary_dim; + const int smem_pitch = half_rotary_dim; + + assert(half_rotary_dim % QK_VEC_SIZE == 0); + + if (do_rotary) { + *reinterpret_cast(q_smem + half_idx * smem_pitch + intra_half_idx) = q; + *reinterpret_cast(k_smem + half_idx * smem_pitch + intra_half_idx) = k; + } + + __syncthreads(); + + const int transpose_idx = half_idx * (half_rotary_dim / 2) + intra_half_idx / 2; + constexpr int tidx_factor = (QK_VEC_SIZE > 1) ? QK_VEC_SIZE / 2 : 1; + + if (do_rotary) { + vec_from_smem_transpose(q, q_smem, transpose_idx, smem_pitch); + vec_from_smem_transpose(k, k_smem, transpose_idx, smem_pitch); + + apply_rotary_embedding( + q, k, transpose_idx / tidx_factor, params.rotary_embedding_dim, params.t_step); + + write_smem_transpose(k, k_smem, transpose_idx, smem_pitch); + write_smem_transpose(q, q_smem, transpose_idx, smem_pitch); + } + + __syncthreads(); + + if (do_rotary) { + q = *reinterpret_cast(q_smem + half_idx * smem_pitch + intra_half_idx); + k = *reinterpret_cast(k_smem + half_idx * smem_pitch + intra_half_idx); + } + + __syncthreads(); + } + if (!is_masked) { // Write the K values to the global memory cache. // NOTE: The stores are uncoalesced as we have multiple chunks of 16B spread across the memory @@ -230,7 +269,7 @@ __global__ void masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentio qk = dot(q, k); if (QK_VECS_PER_WARP <= WARP_SIZE) { - #pragma unroll +#pragma unroll for (int mask = QK_VECS_PER_WARP / 2; mask >= 1; mask /= 2) { qk += __shfl_xor_sync(shfl_mask(QK_VECS_PER_WARP), qk, mask); } @@ -248,9 +287,7 @@ __global__ void masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentio qk *= inv_sqrt_dh; if (params.relative_attention_bias != nullptr) { qk = add_vec(qk, - reinterpret_cast(params.relative_attention_bias)[hi * params.sequence_length - * params.total_sequence_length - + tlength]); + reinterpret_cast(params.relative_attention_bias)[hi * params.sequence_length * params.total_sequence_length + tlength]); } qk_max = qk; qk_smem[tlength] = qk; @@ -312,24 +349,22 @@ __global__ void masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentio // The keys loaded from the key cache. K_vec_k k_vec[K_VECS_PER_THREAD]; + if (ti < tlength) { + if (has_beams) { + const int beam_offset = beam_indices[ti] * params.num_heads * params.max_sequence_length * head_size; - if (has_beams) { #pragma unroll - for (int ii = 0; ii < K_VECS_PER_THREAD; ++ii) { - int jj = ii * params.max_sequence_length + ti; + for (int ii = 0; ii < K_VECS_PER_THREAD; ++ii) { + int jj = ii * params.max_sequence_length + ti; - if (ti < tlength) { - const int beam_offset = beam_indices[ti] * params.num_heads * params.max_sequence_length * head_size; k_vec[ii] = vec_conversion( (*reinterpret_cast(&k_cache_batch[beam_offset + jj * QK_ELTS_IN_16B]))); } - } - } else { + } else { #pragma unroll - for (int ii = 0; ii < K_VECS_PER_THREAD; ++ii) { - int jj = ii * params.max_sequence_length + ti; + for (int ii = 0; ii < K_VECS_PER_THREAD; ++ii) { + int jj = ii * params.max_sequence_length + ti; - if (ti < tlength) { k_vec[ii] = vec_conversion( (*reinterpret_cast(&k_cache_batch[jj * QK_ELTS_IN_16B]))); } @@ -351,9 +386,7 @@ __global__ void masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentio if (ti < tlength && tidx % THREADS_PER_KEY == 0) { if (params.relative_attention_bias != nullptr) { qk = add_vec(qk, - reinterpret_cast(params.relative_attention_bias)[hi * params.sequence_length - * params.total_sequence_length - + ti]); + reinterpret_cast(params.relative_attention_bias)[hi * params.sequence_length * params.total_sequence_length + ti]); } qk_max = fmaxf(qk_max, qk); qk_smem[ti] = qk; @@ -442,7 +475,7 @@ __global__ void masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentio // One group of threads computes the product(s) for the current timestep. V_vec_k v_bias; - if (!params.is_mha) { + if (params.v_bias && !params.is_cross_attention) { zero(v_bias); T* params_v_bias = reinterpret_cast(params.v_bias); @@ -482,7 +515,7 @@ __global__ void masked_multihead_attention_kernel(DecoderMaskedMultiHeadAttentio V_vec_k v; v = vec_conversion(*reinterpret_cast(&reinterpret_cast(params.v)[v_offset])); - if (!params.is_mha) { + if (params.v_bias) { v = add_vec(v, v_bias); } 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 41b0bb21a25b8..6d7f368db4dd4 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 @@ -13,9 +13,14 @@ namespace cuda { struct DecoderMaskedMultiHeadAttentionParams : 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; void* q = nullptr; void* q_bias = nullptr; 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 56258073e7c61..6b012432cd0f5 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 @@ -163,8 +163,13 @@ inline size_t CalcDynamicBlockMemory(const DecoderMaskedMultiHeadAttentionParams // The amount of storage needed to finalize the outputs. size_t red_sz = rows_per_red * params.head_size * sizeof(T) / 2; + size_t transpose_rotary_size = 0; + if (params.rotary_embedding_dim > 0) { + transpose_rotary_size = 2 * params.rotary_embedding_dim * sizeof(T); + } + // The max. - return std::max(softmax_sz, red_sz); + return std::max(std::max(softmax_sz, red_sz), transpose_rotary_size); } } // namespace decoder_masked_self_attention_details diff --git a/onnxruntime/contrib_ops/cuda/bert/flash_attention/block_info.h b/onnxruntime/contrib_ops/cuda/bert/flash_attention/block_info.h new file mode 100644 index 0000000000000..9db98061bbd66 --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/flash_attention/block_info.h @@ -0,0 +1,40 @@ +/****************************************************************************** + * Copyright (c) 2023, Tri Dao. + ******************************************************************************/ +#pragma once + +namespace onnxruntime { +namespace flash { +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +struct BlockInfo { + template + __device__ BlockInfo(const Params& params, const int bidb) + : sum_s_q(!Varlen || params.cu_seqlens_q == nullptr ? -1 : params.cu_seqlens_q[bidb]), + sum_s_k(!Varlen || params.cu_seqlens_k == nullptr ? -1 : params.cu_seqlens_k[bidb]), + actual_seqlen_q(!Varlen || params.cu_seqlens_q == nullptr ? params.seqlen_q : params.cu_seqlens_q[bidb + 1] - sum_s_q), + actual_seqlen_k(!Varlen || params.cu_seqlens_k == nullptr ? params.seqlen_k : params.cu_seqlens_k[bidb + 1] - sum_s_k) { + } + + template + inline __device__ index_t q_offset(const index_t batch_stride, const index_t row_stride, const int bidb) const { + return sum_s_q == -1 ? bidb * batch_stride : uint32_t(sum_s_q) * row_stride; + } + + template + inline __device__ index_t k_offset(const index_t batch_stride, const index_t row_stride, const int bidb) const { + return sum_s_k == -1 ? bidb * batch_stride : uint32_t(sum_s_k) * row_stride; + } + + const int sum_s_q; + const int sum_s_k; + const int actual_seqlen_q; + const int actual_seqlen_k; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////////////// +} // namespace flash +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash.h b/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash.h new file mode 100644 index 0000000000000..9394a19c9897a --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash.h @@ -0,0 +1,85 @@ +/****************************************************************************** + * Copyright (c) 2023, Tri Dao. + ******************************************************************************/ +#pragma once + +#include +#include + +namespace onnxruntime { +namespace flash { + +constexpr int TOTAL_DIM = 0; +constexpr int H_DIM = 1; +constexpr int D_DIM = 2; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +struct Qkv_params { + using index_t = uint32_t; + // The QKV matrices. + void* __restrict__ q_ptr; + void* __restrict__ k_ptr; + void* __restrict__ v_ptr; + + // The stride between rows of the Q, K and V matrices. + index_t q_batch_stride; + index_t k_batch_stride; + index_t v_batch_stride; + index_t q_row_stride; + index_t k_row_stride; + index_t v_row_stride; + index_t q_head_stride; + index_t k_head_stride; + index_t v_head_stride; + + // The number of heads. + int h, h_k; + // In the case of multi-query and grouped-query attention (MQA/GQA), nheads_k could be + // different from nheads (query). + int h_h_k_ratio; // precompute h / h_k, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +struct Flash_fwd_params : public Qkv_params { + // The O matrix (output). + void* __restrict__ o_ptr; + + // The stride between rows of O. + index_t o_batch_stride; + index_t o_row_stride; + index_t o_head_stride; + + // The pointer to the P matrix. + void* __restrict__ p_ptr; + + // The pointer to the softmax sum. + void* __restrict__ softmax_lse_ptr; + + // The dimensions. + int b, seqlen_q, seqlen_k, d, seqlen_q_rounded, seqlen_k_rounded, d_rounded; + + // The scaling factors for the kernel. + float scale_softmax; + float scale_softmax_log2; + + // array of length b+1 holding starting offset of each sequence. + int* __restrict__ cu_seqlens_q; + int* __restrict__ cu_seqlens_k; + + int* __restrict__ blockmask; + + bool is_bf16 = false; + bool is_causal; + + const cudaDeviceProp* dprops; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +void run_mha_fwd_(Flash_fwd_params& params, cudaStream_t stream); + +} // namespace flash +} // namespace onnxruntime \ No newline at end of file diff --git a/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_api.cc b/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_api.cc new file mode 100644 index 0000000000000..87831d1eddfe9 --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_api.cc @@ -0,0 +1,198 @@ +/****************************************************************************** + * Copyright (c) 2023, Tri Dao. + ******************************************************************************/ + +#if USE_FLASH_ATTENTION + +#include "contrib_ops/cuda/bert/flash_attention/flash_api.h" +#include +#include "core/providers/cuda/cuda_common.h" +#include "contrib_ops/cuda/bert/flash_attention/flash.h" +#include "contrib_ops/cuda/bert/flash_attention/static_switch.h" + +namespace onnxruntime { +namespace flash { + +void set_params_fprop(Flash_fwd_params& params, + // sizes + size_t batch_size, + size_t seqlen_q, + size_t seqlen_k, + size_t seqlen_q_rounded, + size_t seqlen_k_rounded, + size_t num_heads, + size_t num_heads_k, + size_t head_size, + size_t head_size_rounded, + // device pointers + void* q, + void* k, + void* v, + void* out, + void* cu_seqlens_q_d, + void* cu_seqlens_k_d, + void* p_d, + void* softmax_lse_d, + float softmax_scale, + bool is_causal) { + // Set the pointers and strides. + params.q_ptr = q; + params.k_ptr = k; + params.v_ptr = v; + params.o_ptr = out; + + // All stride are in elements, not bytes. + params.q_row_stride = num_heads * head_size; + params.k_row_stride = num_heads_k * head_size; + params.v_row_stride = num_heads * head_size; + params.q_head_stride = head_size; + params.k_head_stride = head_size; + params.v_head_stride = head_size; + params.o_row_stride = num_heads * head_size; + params.o_head_stride = head_size; + params.is_bf16 = false; + + if (cu_seqlens_q_d == nullptr) { + params.q_batch_stride = seqlen_q * num_heads * head_size; // stride(0) + params.k_batch_stride = seqlen_k * num_heads_k * head_size; // stride(0) + params.v_batch_stride = seqlen_k * num_heads_k * head_size; // stride(0) + params.o_batch_stride = seqlen_q * num_heads * head_size; // stride(0) + } else { + params.q_batch_stride = 0; + params.k_batch_stride = 0; + params.v_batch_stride = 0; + params.o_batch_stride = 0; + } + + params.cu_seqlens_q = static_cast(cu_seqlens_q_d); + params.cu_seqlens_k = static_cast(cu_seqlens_k_d); + + // P = softmax(QK^T) + params.p_ptr = p_d; + + // Softmax sum + params.softmax_lse_ptr = softmax_lse_d; + + // Set the dimensions. + params.b = batch_size; + params.h = num_heads; + params.h_k = num_heads_k; + params.h_h_k_ratio = num_heads / num_heads_k; + params.seqlen_q = seqlen_q; + params.seqlen_k = seqlen_k; + params.seqlen_q_rounded = seqlen_q_rounded; + params.seqlen_k_rounded = seqlen_k_rounded; + params.d = head_size; + params.d_rounded = head_size_rounded; + + // Set the different scale values. + params.scale_softmax = softmax_scale; + params.scale_softmax_log2 = softmax_scale * M_LOG2E; + + params.is_causal = is_causal; +} + +size_t get_softmax_lse_size(int seqlen, int batch_size, int num_heads) { + size_t bytes = sizeof(float) * batch_size * num_heads * seqlen; + return bytes; +} + +void run_mha_fwd(Flash_fwd_params& params, cudaStream_t stream) { + FP16_SWITCH(!params.is_bf16, [&] { + FWD_HEADDIM_SWITCH(params.d, [&] { + run_mha_fwd_(params, stream); + }); + }); +} + +Status mha_fwd(const cudaDeviceProp& dprops, + cudaStream_t stream, + void* q, // batch_size x seqlen_q x num_heads x head_size + void* k, // batch_size x seqlen_k x num_heads_k x head_size + void* v, // batch_size x seqlen_k x num_heads_k x head_size + void* out, // batch_size x seqlen_q x num_heads x head_size + void* softmax_lse, // batch_size x num_heads x seqlen_q + int batch_size, + int num_heads, + int num_heads_k, + int head_size, + int seqlen_q, + int seqlen_k, + float softmax_scale, + bool is_causal) { + auto round_multiple = [](int x, int m) { return (x + m - 1) / m * m; }; + const int head_size_rounded = round_multiple(head_size, 32); + const int seqlen_q_rounded = round_multiple(seqlen_q, 128); + const int seqlen_k_rounded = round_multiple(seqlen_k, 128); + + Flash_fwd_params params; + params.dprops = &dprops; + set_params_fprop(params, + batch_size, + seqlen_q, seqlen_k, + seqlen_q_rounded, seqlen_k_rounded, + num_heads, num_heads_k, + head_size, head_size_rounded, + q, k, v, out, + /*cu_seqlens_q*/ nullptr, + /*cu_seqlens_k*/ nullptr, + nullptr, + softmax_lse, + softmax_scale, + is_causal); + + run_mha_fwd(params, stream); + return Status::OK(); +} + +Status mha_varlen_fwd(const cudaDeviceProp& dprops, + cudaStream_t stream, + void* q, // half (total_q, num_heads, head_size) + void* k, // half (total_k, num_heads, head_size) + void* v, // half (total_k, num_heads, head_size) + void* out, // half (total_q, num_heads, head_size) + int* cu_seqlens_q, // int (batch_size + 1) + int* cu_seqlens_k, // int (batch_size + 1) + void* softmax_lse, // float (batch_size, num_heads, max_seqlen_q) + int batch_size, + int num_heads, + int num_heads_k, + int head_size, + int max_seqlen_q, + int max_seqlen_k, + float softmax_scale, + bool is_causal) { + auto round_multiple = [](int x, int m) { return (x + m - 1) / m * m; }; + const int head_size_rounded = round_multiple(head_size, 32); + const int seqlen_q_rounded = round_multiple(max_seqlen_q, 128); + const int seqlen_k_rounded = round_multiple(max_seqlen_k, 128); + + Flash_fwd_params params; + params.dprops = &dprops; + set_params_fprop(params, + batch_size, + max_seqlen_q, max_seqlen_k, + seqlen_q_rounded, seqlen_k_rounded, + num_heads, num_heads_k, + head_size, head_size_rounded, + q, k, v, out, + cu_seqlens_q, + cu_seqlens_k, + nullptr, + softmax_lse, + softmax_scale, + is_causal); + run_mha_fwd(params, stream); + return Status::OK(); +} + +bool is_supported(const cudaDeviceProp& dprops, int head_size, int num_heads, int num_heads_k) { + bool is_sm8x = dprops.major == 8 && dprops.minor >= 0; + bool is_sm90 = dprops.major == 9 && dprops.minor == 0; + return (is_sm8x || is_sm90) && (head_size % 8 == 0) && (head_size <= 256) && (num_heads % num_heads_k == 0); +} + +} // namespace flash +} // namespace onnxruntime + +#endif // USE_FLASH_ATTENTION diff --git a/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_api.h b/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_api.h new file mode 100644 index 0000000000000..2ae46d34c373a --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_api.h @@ -0,0 +1,78 @@ +/****************************************************************************** + * Copyright (c) 2022, Tri Dao. + * Copyright (c) 2011-2021, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the NVIDIA CORPORATION 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 NVIDIA CORPORATION 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. + * + ******************************************************************************/ + +#pragma once + +#if USE_FLASH_ATTENTION + +#include "core/providers/cuda/cuda_common.h" + +namespace onnxruntime { +namespace flash { +Status mha_fwd(const cudaDeviceProp& dprops, + cudaStream_t stream, + void* q, // batch_size x seqlen_q x num_heads x head_size + void* k, // batch_size x seqlen_k x num_heads_k x head_size + void* v, // batch_size x seqlen_k x num_heads_k x head_size + void* out, // batch_size x seqlen_q x num_heads x head_size + void* softmax_lse, // batch_size x num_heads x seqlen_q + int batch_size, + int num_heads, + int num_heads_k, + int head_size, + int seqlen_q, + int seqlen_k, + float softmax_scale, + bool is_causal); + +Status mha_varlen_fwd(const cudaDeviceProp& dprops, + cudaStream_t stream, + void* q, // half (total_q, num_heads, head_size) + void* k, // half (total_k, num_heads, head_size) + void* v, // half (total_k, num_heads, v_head_size) + void* out, // half (total_q, num_heads, v_head_size) + int* cu_seqlens_q, // int (batch_size + 1) + int* cu_seqlens_k, // int (batch_size + 1) + void* softmax_lse, // float (batch_size, num_heads, max_seqlen_q) + int batch_size, + int num_heads, + int num_heads_k, + int head_size, + int max_seqlen_q, + int max_seqlen_k, + float softmax_scale, + bool is_causal); + +size_t get_softmax_lse_size(int max_seqlen_q, int batch_size, int num_heads); + +bool is_supported(const cudaDeviceProp& dprops, int head_size, int num_heads, int num_heads_k); + +} // namespace flash +} // namespace onnxruntime + +#endif // USE_FLASH_ATTENTION diff --git a/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_fwd_hdim128_fp16_sm80.cu b/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_fwd_hdim128_fp16_sm80.cu new file mode 100644 index 0000000000000..44ea92e58c86e --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_fwd_hdim128_fp16_sm80.cu @@ -0,0 +1,18 @@ +// Copyright (c) 2023, Tri Dao. + +// Splitting the different head dimensions to different files to speed up compilation. +#if USE_FLASH_ATTENTION + +#include "contrib_ops/cuda/bert/flash_attention/flash_fwd_launch_template.h" + +namespace onnxruntime { +namespace flash { + +template <> +void run_mha_fwd_(Flash_fwd_params& params, cudaStream_t stream) { + run_mha_fwd_hdim128(params, stream); +} + +} // namespace flash +} // namespace onnxruntime +#endif diff --git a/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_fwd_hdim160_fp16_sm80.cu b/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_fwd_hdim160_fp16_sm80.cu new file mode 100644 index 0000000000000..a2bf16bc74e72 --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_fwd_hdim160_fp16_sm80.cu @@ -0,0 +1,18 @@ +// Copyright (c) 2023, Tri Dao. + +// Splitting the different head dimensions to different files to speed up compilation. +#if USE_FLASH_ATTENTION + +#include "contrib_ops/cuda/bert/flash_attention/flash_fwd_launch_template.h" + +namespace onnxruntime { +namespace flash { + +template <> +void run_mha_fwd_(Flash_fwd_params& params, cudaStream_t stream) { + run_mha_fwd_hdim160(params, stream); +} + +} // namespace flash +} // namespace onnxruntime +#endif diff --git a/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_fwd_hdim192_fp16_sm80.cu b/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_fwd_hdim192_fp16_sm80.cu new file mode 100644 index 0000000000000..56fc04126ab12 --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_fwd_hdim192_fp16_sm80.cu @@ -0,0 +1,18 @@ +// Copyright (c) 2023, Tri Dao. + +// Splitting the different head dimensions to different files to speed up compilation. +#if USE_FLASH_ATTENTION + +#include "contrib_ops/cuda/bert/flash_attention/flash_fwd_launch_template.h" + +namespace onnxruntime { +namespace flash { + +template <> +void run_mha_fwd_(Flash_fwd_params& params, cudaStream_t stream) { + run_mha_fwd_hdim192(params, stream); +} + +} // namespace flash +} // namespace onnxruntime +#endif diff --git a/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_fwd_hdim224_fp16_sm80.cu b/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_fwd_hdim224_fp16_sm80.cu new file mode 100644 index 0000000000000..6fb24640710a3 --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_fwd_hdim224_fp16_sm80.cu @@ -0,0 +1,18 @@ +// Copyright (c) 2023, Tri Dao. + +// Splitting the different head dimensions to different files to speed up compilation. +#if USE_FLASH_ATTENTION + +#include "contrib_ops/cuda/bert/flash_attention/flash_fwd_launch_template.h" + +namespace onnxruntime { +namespace flash { + +template <> +void run_mha_fwd_(Flash_fwd_params& params, cudaStream_t stream) { + run_mha_fwd_hdim224(params, stream); +} + +} // namespace flash +} // namespace onnxruntime +#endif diff --git a/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_fwd_hdim256_fp16_sm80.cu b/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_fwd_hdim256_fp16_sm80.cu new file mode 100644 index 0000000000000..94d51e922d7cb --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_fwd_hdim256_fp16_sm80.cu @@ -0,0 +1,18 @@ +// Copyright (c) 2023, Tri Dao. + +// Splitting the different head dimensions to different files to speed up compilation. +#if USE_FLASH_ATTENTION + +#include "contrib_ops/cuda/bert/flash_attention/flash_fwd_launch_template.h" + +namespace onnxruntime { +namespace flash { + +template <> +void run_mha_fwd_(Flash_fwd_params& params, cudaStream_t stream) { + run_mha_fwd_hdim256(params, stream); +} + +} // namespace flash +} // namespace onnxruntime +#endif diff --git a/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_fwd_hdim32_fp16_sm80.cu b/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_fwd_hdim32_fp16_sm80.cu new file mode 100644 index 0000000000000..d32eec27634ce --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_fwd_hdim32_fp16_sm80.cu @@ -0,0 +1,18 @@ +// Copyright (c) 2023, Tri Dao. + +// Splitting the different head dimensions to different files to speed up compilation. +#if USE_FLASH_ATTENTION + +#include "contrib_ops/cuda/bert/flash_attention/flash_fwd_launch_template.h" + +namespace onnxruntime { +namespace flash { + +template <> +void run_mha_fwd_(Flash_fwd_params& params, cudaStream_t stream) { + run_mha_fwd_hdim32(params, stream); +} + +} // namespace flash +} // namespace onnxruntime +#endif diff --git a/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_fwd_hdim64_fp16_sm80.cu b/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_fwd_hdim64_fp16_sm80.cu new file mode 100644 index 0000000000000..65a2e42192532 --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_fwd_hdim64_fp16_sm80.cu @@ -0,0 +1,18 @@ +// Copyright (c) 2023, Tri Dao. + +// Splitting the different head dimensions to different files to speed up compilation. +#if USE_FLASH_ATTENTION + +#include "contrib_ops/cuda/bert/flash_attention/flash_fwd_launch_template.h" + +namespace onnxruntime { +namespace flash { + +template <> +void run_mha_fwd_(Flash_fwd_params& params, cudaStream_t stream) { + run_mha_fwd_hdim64(params, stream); +} + +} // namespace flash +} // namespace onnxruntime +#endif diff --git a/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_fwd_hdim96_fp16_sm80.cu b/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_fwd_hdim96_fp16_sm80.cu new file mode 100644 index 0000000000000..f37ee5005855a --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_fwd_hdim96_fp16_sm80.cu @@ -0,0 +1,18 @@ +// Copyright (c) 2023, Tri Dao. + +// Splitting the different head dimensions to different files to speed up compilation. +#if USE_FLASH_ATTENTION + +#include "contrib_ops/cuda/bert/flash_attention/flash_fwd_launch_template.h" + +namespace onnxruntime { +namespace flash { + +template <> +void run_mha_fwd_(Flash_fwd_params& params, cudaStream_t stream) { + run_mha_fwd_hdim96(params, stream); +} + +} // namespace flash +} // namespace onnxruntime +#endif diff --git a/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_fwd_kernel.h b/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_fwd_kernel.h new file mode 100644 index 0000000000000..b5af31e432d42 --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_fwd_kernel.h @@ -0,0 +1,532 @@ +/****************************************************************************** + * Copyright (c) 2023, Tri Dao. + ******************************************************************************/ +#pragma once + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#endif + +#include +#include +#include + +#include +#include +#include +#include + +#include "contrib_ops/cuda/bert/flash_attention/block_info.h" +#include "contrib_ops/cuda/bert/flash_attention/kernel_traits.h" +#include "contrib_ops/cuda/bert/flash_attention/utils.h" +#include "contrib_ops/cuda/bert/flash_attention/softmax.h" + +namespace onnxruntime { +namespace flash { +using namespace cute; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +CUTE_HOST_DEVICE auto +make_tiled_copy_A_warpcontiguousM(Copy_Atom const& copy_atom, + TiledMMA const& tiled_mma) { + using TileShape_MNK = typename TiledMMA::TiledShape_MNK; + using AtomShape_MNK = typename TiledMMA::AtomShape_MNK; + constexpr int AtomShape_M = decltype(cute::size<0>(AtomShape_MNK{}))::value; + constexpr int kNWarps = decltype(cute::size<0>(TileShape_MNK{}))::value / AtomShape_M; + constexpr int MMAStride_M = MMA_M * AtomShape_M; + auto t = make_tile(cute::Layout, cute::Int>, + cute::Stride<_1, cute::Int>>{}, + make_layout(cute::size<2>(TileShape_MNK{}))); + + return make_tiled_copy_impl(copy_atom, tiled_mma.get_layoutA_TV(), t); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +CUTE_HOST_DEVICE auto +make_tiled_copy_C_warpcontiguousM(Copy_Atom const& copy_atom, + TiledMMA const& tiled_mma) { + using TileShape_MNK = typename TiledMMA::TiledShape_MNK; + using AtomShape_MNK = typename TiledMMA::AtomShape_MNK; + constexpr int AtomShape_M = decltype(cute::size<0>(AtomShape_MNK{}))::value; + constexpr int kNWarps = decltype(cute::size<0>(TileShape_MNK{}))::value / AtomShape_M; + constexpr int MMAStride_M = MMA_M * AtomShape_M; + auto t = make_tile(cute::Layout, cute::Int>, + cute::Stride<_1, cute::Int>>{}, + // TODO: Shouldn't this be size<1>? + make_layout(cute::size<2>(TileShape_MNK{}))); + // if (cute::thread0()) {printf("make_tiled_copy_C_warpcontiguousM "); print(t); printf("\n"); } + return make_tiled_copy_impl(copy_atom, tiled_mma.get_layoutC_TV(), t); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +inline __device__ void softmax_rescale_o(Tensor0& scores, Tensor1& scores_max, Tensor1& scores_sum, + Tensor2& acc_o, float softmax_scale_log2) { + if (Is_first) { + flash::template reduce_max(scores, scores_max); + flash::scale_apply_exp2(scores, scores_max, softmax_scale_log2); + flash::reduce_sum(scores, scores_sum); + } else { + cute::Tensor scores_max_prev = make_fragment_like(scores_max); + copy(scores_max, scores_max_prev); + flash::template reduce_max(scores, scores_max); + // Reshape acc_o from (MMA=4, MMA_M, MMA_K) to (nrow=(2, MMA_M), ncol=(2, MMA_K)) + cute::Tensor acc_o_rowcol = make_tensor(acc_o.data(), flash::convert_layout_acc_rowcol(acc_o.layout())); +#pragma unroll + for (int mi = 0; mi < cute::size(scores_max); ++mi) { + float scores_max_cur = !Check_inf + ? scores_max(mi) + : (scores_max(mi) == -INFINITY ? 0.0f : scores_max(mi)); + float scores_scale = exp2f((scores_max_prev(mi) - scores_max_cur) * softmax_scale_log2); + scores_sum(mi) *= scores_scale; +#pragma unroll + for (int ni = 0; ni < cute::size<1>(acc_o_rowcol); ++ni) { + acc_o_rowcol(mi, ni) *= scores_scale; + } + } + flash::scale_apply_exp2(scores, scores_max, softmax_scale_log2); + cute::Tensor scores_sum_cur = make_fragment_like(scores_sum); + flash::reduce_sum(scores, scores_sum_cur); +#pragma unroll + for (int mi = 0; mi < cute::size(scores_sum); ++mi) { + scores_sum(mi) += scores_sum_cur(mi); + } + } +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +inline __device__ void write_softmax_to_gmem( + cute::Tensor const& tOrP, cute::Tensor& tPgP, TiledCopy gmem_thr_copy_P) { + // Reshape tOrP from (8, MMA_M, MMA_N) to (8, MMA_M * MMA_N) + cute::Layout l = tOrP.layout(); + cute::Tensor tPrP = make_tensor(tOrP.data(), make_layout(get<0>(l), make_layout(get<1>(l), get<2>(l)))); + CUTE_STATIC_ASSERT_V(cute::size<2>(tPgP) == _1{}); + CUTE_STATIC_ASSERT_V(cute::size<1>(tPrP) == cute::size<1>(tPgP)); +#pragma unroll + for (int mi = 0; mi < cute::size<1>(tPrP); ++mi) { + copy(gmem_thr_copy_P, tPrP(_, mi), tPgP(_, mi, 0)); + } +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +inline __device__ void compute_attn_1rowblock(const Params& params, const int bidb, const int bidh, const int m_block) { + using Element = typename Kernel_traits::Element; + using ElementAccum = typename Kernel_traits::ElementAccum; + using index_t = typename Kernel_traits::index_t; + + // Shared memory. + extern __shared__ char smem_[]; + + // The thread index. + const int tidx = threadIdx.x; + + constexpr int kBlockM = Kernel_traits::kBlockM; + constexpr int kBlockN = Kernel_traits::kBlockN; + constexpr int kHeadDim = Kernel_traits::kHeadDim; + constexpr int kNWarps = Kernel_traits::kNWarps; + constexpr int MMA_M = kBlockM / decltype(cute::size<0>(typename Kernel_traits::TiledMma::TiledShape_MNK{}))::value; + + const BlockInfo binfo(params, bidb); + if (m_block * kBlockM >= binfo.actual_seqlen_q || binfo.actual_seqlen_k == 0) return; + + int n_block_max = cute::ceil_div(binfo.actual_seqlen_k, kBlockN); + if (Is_causal) { + n_block_max = std::min(n_block_max, cute::ceil_div((m_block + 1) * kBlockM + binfo.actual_seqlen_k - binfo.actual_seqlen_q, kBlockN)); + } + + // We iterate over the blocks in reverse order. This is because the last block is the only one + // that needs masking when we read K and V from global memory. Moreover, iterating in reverse + // might save us 1 register (we just need n_block instead of both n_block and n_block_max). + + const index_t row_offset_q = binfo.q_offset(params.q_batch_stride, params.q_row_stride, bidb) + m_block * kBlockM * params.q_row_stride + bidh * params.q_head_stride; + // We move K and V to the last block. + const index_t row_offset_k = binfo.k_offset(params.k_batch_stride, params.k_row_stride, bidb) + (n_block_max - 1) * kBlockN * params.k_row_stride + (bidh / params.h_h_k_ratio) * params.k_head_stride; + const index_t row_offset_v = binfo.k_offset(params.v_batch_stride, params.v_row_stride, bidb) + (n_block_max - 1) * kBlockN * params.v_row_stride + (bidh / params.h_h_k_ratio) * params.v_head_stride; + const index_t row_offset_p = ((bidb * params.h + bidh) * params.seqlen_q_rounded + m_block * kBlockM) * params.seqlen_k_rounded + (n_block_max - 1) * kBlockN; + + cute::Tensor gQ = make_tensor(make_gmem_ptr(reinterpret_cast(params.q_ptr) + row_offset_q), + cute::Shape, cute::Int>{}, + make_stride(params.q_row_stride, _1{})); + cute::Tensor gK = make_tensor(make_gmem_ptr(reinterpret_cast(params.k_ptr) + row_offset_k), + cute::Shape, cute::Int>{}, + make_stride(params.k_row_stride, _1{})); + cute::Tensor gV = make_tensor(make_gmem_ptr(reinterpret_cast(params.v_ptr) + row_offset_v), + cute::Shape, cute::Int>{}, + make_stride(params.v_row_stride, _1{})); + cute::Tensor gP = make_tensor(make_gmem_ptr(reinterpret_cast(params.p_ptr) + row_offset_p), + cute::Shape, cute::Int>{}, + make_stride(params.seqlen_k_rounded, _1{})); + + cute::Tensor sQ = make_tensor(make_smem_ptr(reinterpret_cast(smem_)), + typename Kernel_traits::SmemLayoutQ{}); + // Careful we're using the same smem for sQ and sK | sV if Share_Q_K_smem; + cute::Tensor sK = make_tensor(sQ.data() + (Kernel_traits::Share_Q_K_smem ? 0 : cute::size(sQ)), + typename Kernel_traits::SmemLayoutKV{}); + cute::Tensor sV = make_tensor(sK.data() + cute::size(sK), typename Kernel_traits::SmemLayoutKV{}); + cute::Tensor sVt = make_tensor(sV.data(), typename Kernel_traits::SmemLayoutVtransposed{}); + cute::Tensor sVtNoSwizzle = make_tensor(sV.data(), typename Kernel_traits::SmemLayoutVtransposedNoSwizzle{}); + + typename Kernel_traits::GmemTiledCopyQKV gmem_tiled_copy_QKV; + auto gmem_thr_copy_QKV = gmem_tiled_copy_QKV.get_thread_slice(tidx); + typename Kernel_traits::GmemTiledCopyP gmem_tiled_copy_P; + auto gmem_thr_copy_P = gmem_tiled_copy_P.get_thread_slice(tidx); + + cute::Tensor tQgQ = gmem_thr_copy_QKV.partition_S(gQ); + cute::Tensor tQsQ = gmem_thr_copy_QKV.partition_D(sQ); + cute::Tensor tKgK = gmem_thr_copy_QKV.partition_S(gK); // (KCPY, KCPY_N, KCPY_K) + cute::Tensor tKsK = gmem_thr_copy_QKV.partition_D(sK); + cute::Tensor tVgV = gmem_thr_copy_QKV.partition_S(gV); // (VCPY, VCPY_N, VCPY_K) + cute::Tensor tVsV = gmem_thr_copy_QKV.partition_D(sV); + cute::Tensor tPgP = gmem_thr_copy_P.partition_D(gP); + + typename Kernel_traits::TiledMma tiled_mma; + auto thr_mma = tiled_mma.get_thread_slice(tidx); + cute::Tensor tSrQ = thr_mma.partition_fragment_A(sQ); // (MMA,MMA_M,MMA_K) + cute::Tensor tSrK = thr_mma.partition_fragment_B(sK); // (MMA,MMA_N,MMA_K) + cute::Tensor tOrVt = thr_mma.partition_fragment_B(sVtNoSwizzle); // (MMA, MMA_K,MMA_N) + + cute::Tensor acc_o = partition_fragment_C(tiled_mma, cute::Shape, cute::Int>{}); // MMA, MMA_M, MMA_K + + // + // Copy Atom retiling + // + + auto smem_tiled_copy_Q = make_tiled_copy_A(typename Kernel_traits::SmemCopyAtom{}, tiled_mma); + auto smem_thr_copy_Q = smem_tiled_copy_Q.get_thread_slice(tidx); + cute::Tensor tSsQ = smem_thr_copy_Q.partition_S(sQ); + + auto smem_tiled_copy_K = make_tiled_copy_B(typename Kernel_traits::SmemCopyAtom{}, tiled_mma); + auto smem_thr_copy_K = smem_tiled_copy_K.get_thread_slice(tidx); + cute::Tensor tSsK = smem_thr_copy_K.partition_S(sK); + + auto smem_tiled_copy_V = make_tiled_copy_B(typename Kernel_traits::SmemCopyAtomTransposed{}, tiled_mma); + auto smem_thr_copy_V = smem_tiled_copy_V.get_thread_slice(tidx); + cute::Tensor tOsVt = smem_thr_copy_V.partition_S(sVt); + + // TODO: this might need to change if we change the mma instruction in SM70 + cute::Tensor scores_max = make_tensor(cute::Shape(acc_o)>>{}); + cute::Tensor scores_sum = make_fragment_like(scores_max); + + // + // PREDICATES + // + + // Construct identity layout for sQ and sK + cute::Tensor cQ = make_identity_tensor(make_shape(cute::size<0>(sQ), cute::size<1>(sQ))); // (BLK_M,BLK_K) -> (blk_m,blk_k) + cute::Tensor cKV = make_identity_tensor(make_shape(cute::size<0>(sK), cute::size<1>(sK))); // (BLK_N,BLK_K) -> (blk_n,blk_k) + + // Repeat the partitioning with identity layouts + cute::Tensor tQcQ = gmem_thr_copy_QKV.partition_S(cQ); // (ACPY,ACPY_M,ACPY_K) -> (blk_m,blk_k) + cute::Tensor tKVcKV = gmem_thr_copy_QKV.partition_S(cKV); // (BCPY,BCPY_N,BCPY_K) -> (blk_n,blk_k) + + // Allocate predicate tensors for k + cute::Tensor tQpQ = make_tensor(make_shape(cute::size<2>(tQsQ))); + cute::Tensor tKVpKV = make_tensor(make_shape(cute::size<2>(tKsK))); + + // Set predicates for k bounds + if (!Is_even_K) { +#pragma unroll + for (int k = 0; k < cute::size(tQpQ); ++k) { + tQpQ(k) = get<1>(tQcQ(0, 0, k)) < params.d; + } +#pragma unroll + for (int k = 0; k < cute::size(tKVpKV); ++k) { + tKVpKV(k) = get<1>(tKVcKV(0, 0, k)) < params.d; + } + } + + // Prologue + + cute::Tensor tQrQ = make_fragment_like(tQgQ); + // We don't need to clear the sQ smem tiles since we'll only write out the valid outputs + flash::copy(gmem_tiled_copy_QKV, tQgQ, tQsQ, tQcQ, tQpQ, + binfo.actual_seqlen_q - m_block * kBlockM); + if (Kernel_traits::Is_Q_in_regs) { + cute::cp_async_fence(); + } + + if (Kernel_traits::Share_Q_K_smem) { + flash::cp_async_wait<0>(); + __syncthreads(); + cute::Tensor tSrQ_copy_view = smem_thr_copy_Q.retile_D(tSrQ); + CUTE_STATIC_ASSERT_V(cute::size<1>(tSsQ) == cute::size<1>(tSrQ_copy_view)); // M + cute::copy(smem_tiled_copy_Q, tSsQ, tSrQ_copy_view); + __syncthreads(); + } + + int n_block = n_block_max - 1; + // We don't need to clear the sK smem tiles since we'll mask out the scores anyway. + flash::copy(gmem_tiled_copy_QKV, tKgK, tKsK, tKVcKV, tKVpKV, + binfo.actual_seqlen_k - n_block * kBlockN); + cute::cp_async_fence(); + + if (Kernel_traits::Is_Q_in_regs && !Kernel_traits::Share_Q_K_smem) { + flash::cp_async_wait<1>(); + __syncthreads(); + cute::Tensor tSrQ_copy_view = smem_thr_copy_Q.retile_D(tSrQ); + CUTE_STATIC_ASSERT_V(cute::size<1>(tSsQ) == cute::size<1>(tSrQ_copy_view)); // M + cute::copy(smem_tiled_copy_Q, tSsQ, tSrQ_copy_view); + } + + clear(acc_o); + + // For performance reason, we separate out two kinds of iterations: + // those that need masking on S, and those that don't. + // We need masking on S for the very last block when K and V has length not multiple of kBlockN. + // We also need masking on S if it's causal, for the last ceil_div(kBlockM, kBlockN) blocks. + // We will have at least 1 "masking" iteration. + + // If not even_N, then seqlen_k might end in the middle of a block. In that case we need to + // mask 2 blocks (e.g. when kBlockM == kBlockN), not just 1. + constexpr int n_masking_steps = !Is_causal + ? 1 + : (Is_even_MN ? cute::ceil_div(kBlockM, kBlockN) : cute::ceil_div(kBlockM, kBlockN) + 1); +#pragma unroll + for (int masking_step = 0; masking_step < n_masking_steps; ++masking_step, --n_block) { + cute::Tensor acc_s = partition_fragment_C(tiled_mma, cute::Shape, cute::Int>{}); // (MMA=4, MMA_M, MMA_N) + clear(acc_s); + flash::cp_async_wait<0>(); + __syncthreads(); + + // Advance gV + if (masking_step > 0) { + tVgV.data() = tVgV.data() + (-int(kBlockN * params.v_row_stride)); + flash::copy(gmem_tiled_copy_QKV, tVgV, tVsV, tKVcKV, tKVpKV); + } else { + // Clear the smem tiles to account for predicated off loads + flash::copy( + gmem_tiled_copy_QKV, tVgV, tVsV, tKVcKV, tKVpKV, binfo.actual_seqlen_k - n_block * kBlockN); + } + cute::cp_async_fence(); + + flash::gemm( + acc_s, tSrQ, tSrK, tSsQ, tSsK, tiled_mma, smem_tiled_copy_Q, smem_tiled_copy_K, + smem_thr_copy_Q, smem_thr_copy_K); + // if (cute::thread0()) { print(acc_s); } + + // Reshape acc_s from (MMA=4, MMA_M, MMA_N) to (nrow=(2, MMA_M), ncol=(2, MMA_N)) + cute::Tensor scores = make_tensor(acc_s.data(), flash::convert_layout_acc_rowcol(acc_s.layout())); + + // We don't put the masking before the matmul S = Q K^T because we don't clear sK + // for rows outside actual_seqlen_k. So those rows could have Inf / NaN, and the matmul + // can produce Inf / NaN. + if (!Is_causal) { + if (!Is_even_MN) { + flash::apply_mask(scores, binfo.actual_seqlen_k - n_block * kBlockN); + } + } else { + // I can't get the stride from idx_row + flash::apply_mask_causal(scores, n_block * kBlockN, binfo.actual_seqlen_k, + // m_block * kBlockM + get<0>(idx_row(0)), + m_block * kBlockM + (tidx / 32) * 16 + (tidx % 32) / 4, + binfo.actual_seqlen_q, + kNWarps * 16); + } + + flash::cp_async_wait<0>(); + __syncthreads(); + if (n_block > 0) { + // Advance gK + tKgK.data() = tKgK.data() + (-int(kBlockN * params.k_row_stride)); + flash::copy(gmem_tiled_copy_QKV, tKgK, tKsK, tKVcKV, tKVpKV); + // This cp_async_fence needs to be in the if block, otherwise the synchronization + // isn't right and we get race conditions. + cute::cp_async_fence(); + } + + // TODO: when we have key_padding_mask we'll need to Check_inf + masking_step == 0 + ? softmax_rescale_o(scores, scores_max, scores_sum, acc_o, params.scale_softmax_log2) + : softmax_rescale_o(scores, scores_max, scores_sum, acc_o, params.scale_softmax_log2); + + // Convert scores from fp32 to fp16/bf16 + cute::Tensor rP = flash::convert_type(scores); + // Reshape rP from (nrow=(2, MMA_M), ncol=(2, MMA_N)) to ((2, 2, 2), MMA_M, MMA_N / 2) + // if using m16n8k16 or ((2, 2, 1), MMA_M, MMA_N) if using m16n8k8. + cute::Tensor tOrP = make_tensor(rP.data(), flash::convert_layout_rowcol_Aregs(rP.layout())); + // if (Return_softmax) { + // cute::Tensor tOrP_copy = make_fragment_like(tOrP); + // copy(tOrP, tOrP_copy); + // flash::write_softmax_to_gmem(tOrP_copy, tPgP, gmem_thr_copy_P); + // tPgP.data() = tPgP.data() + (-kBlockN); + // } + + flash::gemm_A_in_regs(acc_o, tOrP, tOrVt, tOsVt, tiled_mma, smem_tiled_copy_V, smem_thr_copy_V); + + // This check is at the end of the loop since we always have at least 1 iteration + if (n_masking_steps > 1 && n_block <= 0) { + --n_block; + break; + } + } + + // These are the iterations where we don't need masking on S + for (; n_block >= 0; --n_block) { + cute::Tensor acc_s = partition_fragment_C(tiled_mma, cute::Shape, cute::Int>{}); // (MMA=4, MMA_M, MMA_N) + clear(acc_s); + flash::cp_async_wait<0>(); + __syncthreads(); + // Advance gV + tVgV.data() = tVgV.data() + (-int(kBlockN * params.v_row_stride)); + flash::copy(gmem_tiled_copy_QKV, tVgV, tVsV, tKVcKV, tKVpKV); + cute::cp_async_fence(); + + flash::gemm( + acc_s, tSrQ, tSrK, tSsQ, tSsK, tiled_mma, smem_tiled_copy_Q, smem_tiled_copy_K, + smem_thr_copy_Q, smem_thr_copy_K); + + flash::cp_async_wait<0>(); + __syncthreads(); + if (n_block > 0) { + // Advance gK + tKgK.data() = tKgK.data() + (-int(kBlockN * params.k_row_stride)); + flash::copy(gmem_tiled_copy_QKV, tKgK, tKsK, tKVcKV, tKVpKV); + // This cp_async_fence needs to be in the if block, otherwise the synchronization + // isn't right and we get race conditions. + cute::cp_async_fence(); + } + + // Reshape acc_s from (MMA=4, MMA_M, MMA_N) to (nrow=(2, MMA_M), ncol=(2, MMA_N)) + cute::Tensor scores = make_tensor(acc_s.data(), flash::convert_layout_acc_rowcol(acc_s.layout())); + softmax_rescale_o(scores, scores_max, scores_sum, acc_o, params.scale_softmax_log2); + + cute::Tensor rP = flash::convert_type(scores); + // Reshape rP from (nrow=(2, MMA_M), ncol=(2, MMA_N)) to ((2, 2, 2), MMA_M, MMA_N / 2) + // if using m16n8k16 or ((2, 2, 1), MMA_M, MMA_N) if using m16n8k8. + cute::Tensor tOrP = make_tensor(rP.data(), flash::convert_layout_rowcol_Aregs(rP.layout())); + // if (Return_softmax) { + // cute::Tensor tOrP_copy = make_fragment_like(tOrP); + // copy(tOrP, tOrP_copy); + // flash::write_softmax_to_gmem(tOrP_copy, tPgP, gmem_thr_copy_P); + // tPgP.data() = tPgP.data() + (-kBlockN); + // } + + flash::gemm_A_in_regs(acc_o, tOrP, tOrVt, tOsVt, tiled_mma, smem_tiled_copy_V, smem_thr_copy_V); + } + + // Epilogue + + // Reshape acc_o from (MMA=4, MMA_M, MMA_K) to (nrow=(2, MMA_M), ncol=(2, MMA_K)) + cute::Tensor acc_o_rowcol = make_tensor(acc_o.data(), flash::convert_layout_acc_rowcol(acc_o.layout())); + cute::Tensor lse = make_fragment_like(scores_sum); +#pragma unroll + for (int mi = 0; mi < cute::size<0>(acc_o_rowcol); ++mi) { + float sum = scores_sum(mi); + float inv_sum = (sum == 0.f || sum != sum) ? 1.f : 1.f / sum; + lse(mi) = (sum == 0.f || sum != sum) ? INFINITY : scores_max(mi) * params.scale_softmax + __logf(sum); + float scale = inv_sum; +#pragma unroll + for (int ni = 0; ni < cute::size<1>(acc_o_rowcol); ++ni) { + acc_o_rowcol(mi, ni) *= scale; + } + } + + // Convert acc_o from fp32 to fp16/bf16 + cute::Tensor rO = flash::convert_type(acc_o); + cute::Tensor sO = make_tensor(sQ.data(), typename Kernel_traits::SmemLayoutO{}); // (SMEM_M,SMEM_N) + // Partition sO to match the accumulator partitioning + auto smem_tiled_copy_O = make_tiled_copy_C(typename Kernel_traits::SmemCopyAtomO{}, tiled_mma); + auto smem_thr_copy_O = smem_tiled_copy_O.get_thread_slice(tidx); // auto smem_thr_copy_O = make_tiled_copy_C_warpcontiguousM(typename Kernel_traits::SmemCopyAtomO{}, tiled_mma).get_thread_slice(tidx); + cute::Tensor taccOrO = smem_thr_copy_O.retile_S(rO); // ((Atom,AtomNum), MMA_M, MMA_N) + cute::Tensor taccOsO = smem_thr_copy_O.partition_D(sO); // ((Atom,AtomNum),PIPE_M,PIPE_N) + + // sO has the same size as sQ, so we don't need to sync here. + if (Kernel_traits::Share_Q_K_smem) { + __syncthreads(); + } + + cute::copy(smem_tiled_copy_O, taccOrO, taccOsO); + + const index_t row_offset_o = binfo.q_offset(params.o_batch_stride, params.o_row_stride, bidb) + m_block * kBlockM * params.o_row_stride + bidh * params.o_head_stride; + const index_t row_offset_lse = (bidb * params.h + bidh) * params.seqlen_q + m_block * kBlockM; + cute::Tensor gO = make_tensor(make_gmem_ptr(reinterpret_cast(params.o_ptr) + row_offset_o), + cute::Shape, cute::Int>{}, + make_stride(params.o_row_stride, _1{})); + cute::Tensor gLSE = make_tensor(make_gmem_ptr(reinterpret_cast(params.softmax_lse_ptr) + row_offset_lse), + cute::Shape>{}, cute::Stride<_1>{}); + + typename Kernel_traits::GmemTiledCopyO gmem_tiled_copy_O; + auto gmem_thr_copy_O = gmem_tiled_copy_O.get_thread_slice(tidx); + cute::Tensor tOsO = gmem_thr_copy_O.partition_S(sO); // ((Atom,AtomNum),ATOM_M,ATOM_N) + cute::Tensor tOgO = gmem_thr_copy_O.partition_D(gO); + + __syncthreads(); + + cute::Tensor tOrO = make_tensor(cute::shape(tOgO)); + cute::copy(gmem_tiled_copy_O, tOsO, tOrO); + + cute::Tensor caccO = make_identity_tensor(cute::Shape, cute::Int>{}); // (BLK_M,BLK_K) -> (blk_m,blk_k) + cute::Tensor taccOcO = thr_mma.partition_C(caccO); // (MMA,MMA_M,MMA_K) + static_assert(decltype(cute::size<0>(taccOcO))::value == 4); + // Convert to ((2, 2), MMA_M, MMA_K) then take only the row indices. + cute::Tensor taccOcO_row = logical_divide(taccOcO, cute::Shape<_2>{})(make_coord(0, _), _, 0); + CUTE_STATIC_ASSERT_V(cute::size(lse) == cute::size(taccOcO_row)); // MMA_M + if (get<1>(taccOcO_row(0)) == 0) { +#pragma unroll + for (int mi = 0; mi < cute::size(lse); ++mi) { + const int row = get<0>(taccOcO_row(mi)); + if (row < binfo.actual_seqlen_q - m_block * kBlockM) { + gLSE(row) = lse(mi); + } + } + } + + // Construct identity layout for sO + cute::Tensor cO = make_identity_tensor(make_shape(cute::size<0>(sO), cute::size<1>(sO))); // (BLK_M,BLK_K) -> (blk_m,blk_k) + // Repeat the partitioning with identity layouts + cute::Tensor tOcO = gmem_thr_copy_O.partition_D(cO); // (ACPY,ACPY_M,ACPY_K) -> (blk_m,blk_k) + cute::Tensor tOpO = make_tensor(make_shape(cute::size<2>(tOgO))); + if (!Is_even_K) { +#pragma unroll + for (int k = 0; k < cute::size(tOpO); ++k) { + tOpO(k) = get<1>(tOcO(0, 0, k)) < params.d; + } + } + // Clear_OOB_K must be false since we don't want to write zeros to gmem + flash::copy( + gmem_tiled_copy_O, tOrO, tOgO, tOcO, tOpO, binfo.actual_seqlen_q - m_block * kBlockM); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +inline __device__ void compute_attn(const Params& params) { + const int m_block = blockIdx.x; + // The block index for the batch. + const int bidb = blockIdx.y; + // The block index for the head. + const int bidh = blockIdx.z; + + // We want the fwd and bwd to generate the same dropout pattern (RNG), without restricting + // them to have the same number of threads or have to traverse the attention matrix + // in the same order. + // In the Philox RNG, we use the offset to store the batch, head, and the lane id + // (within a warp). We use the subsequence to store the location of the 16 x 32 blocks within + // the attention matrix. This way, as long as we have the batch, head, and the location of + // the 16 x 32 block within the attention matrix, we can generate the exact same dropout pattern. + + flash::compute_attn_1rowblock(params, bidb, bidh, m_block); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +} // namespace flash +} // namespace onnxruntime + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif diff --git a/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_fwd_launch_template.h b/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_fwd_launch_template.h new file mode 100644 index 0000000000000..e633ef4d45fbb --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/flash_attention/flash_fwd_launch_template.h @@ -0,0 +1,210 @@ +/****************************************************************************** + * Copyright (c) 2023, Tri Dao. + ******************************************************************************/ +#pragma once + +#include "contrib_ops/cuda/bert/flash_attention/static_switch.h" +#include "contrib_ops/cuda/bert/flash_attention/flash.h" +#include "contrib_ops/cuda/bert/flash_attention/flash_fwd_kernel.h" + +namespace onnxruntime { +namespace flash { + +template +__global__ void flash_fwd_kernel(Flash_fwd_params params) { + flash::compute_attn(params); +} + +template +void run_flash_fwd(Flash_fwd_params& params, cudaStream_t stream) { + constexpr size_t smem_size = Kernel_traits::kSmemSize; + + // Work-around for gcc 7. It doesn't like nested BOOL_SWITCH. + // https://github.com/kokkos/kokkos-kernels/issues/349 + // https://github.com/HazyResearch/flash-attention/issues/21 + + const int num_m_block = (params.seqlen_q + Kernel_traits::kBlockM - 1) / Kernel_traits::kBlockM; + dim3 grid(num_m_block, params.b, params.h); + // We also use is_even_N to set Unpadded in the BlockInfo constructor, so we need to check + // for cu_seqlens_q as well. + const bool is_even_MN = params.cu_seqlens_q == nullptr && params.cu_seqlens_k == nullptr && params.seqlen_k % Kernel_traits::kBlockN == 0 && params.seqlen_q % Kernel_traits::kBlockM == 0; + const bool is_even_K = params.d == Kernel_traits::kHeadDim; + BOOL_SWITCH(is_even_MN, IsEvenMNConst, [&] { + BOOL_SWITCH(is_even_K, IsEvenKConst, [&] { + // Will only return softmax if dropout, to reduce compilation time. + auto kernel = &flash_fwd_kernel; + // auto kernel = &flash_fwd_kernel; + if (smem_size >= 48 * 1024) { + cudaFuncSetAttribute( + kernel, cudaFuncAttributeMaxDynamicSharedMemorySize, smem_size); + // ORT_ENFORCE(cudaFuncSetAttribute( + // kernel, cudaFuncAttributeMaxDynamicSharedMemorySize, smem_size)); + } + int ctas_per_sm; + cudaOccupancyMaxActiveBlocksPerMultiprocessor( + &ctas_per_sm, kernel, Kernel_traits::kNThreads, smem_size); + // cudaError status_ = cudaOccupancyMaxActiveBlocksPerMultiprocessor( + // &ctas_per_sm, kernel, Kernel_traits::kNThreads, smem_size); + // printf("smem_size = %d, CTAs per SM = %d\n", int(smem_size), ctas_per_sm); + kernel<<>>(params); + }); + }); +} + +template +void run_mha_fwd_hdim32(Flash_fwd_params& params, cudaStream_t stream) { + constexpr int Headdim = 32; + BOOL_SWITCH(params.is_causal, Is_causal, [&] { + run_flash_fwd, Is_causal>(params, stream); + }); +} + +template +void run_mha_fwd_hdim64(Flash_fwd_params& params, cudaStream_t stream) { + constexpr int Headdim = 64; + BOOL_SWITCH(params.is_causal, Is_causal, [&] { + // Using 8 warps is 18% slower for seqlen=2k, 2 warps is 5% slower + // Using block size (64 x 256) is 27% slower for seqlen=2k + // Using block size (256 x 64) is 85% slower for seqlen=2k, because of register spilling + run_flash_fwd, Is_causal>(params, stream); + // run_flash_fwd, Is_causal>(params, stream); + // run_flash_fwd, Is_causal>(params, stream); + }); +} + +template +void run_mha_fwd_hdim96(Flash_fwd_params& params, cudaStream_t stream) { + constexpr int Headdim = 96; + const bool is_sm8x = params.dprops->major == 8 && params.dprops->minor > 0; + BOOL_SWITCH(params.is_causal, Is_causal, [&] { + // For sm86 or sm89, 64 x 64 is the fastest for causal (because it's square), + if (is_sm8x) { + if constexpr (!Is_causal) { + run_flash_fwd, Is_causal>(params, stream); + } else { + run_flash_fwd, Is_causal>(params, stream); + } + } else { + run_flash_fwd, Is_causal>(params, stream); + } + // run_flash_fwd, Is_causal>(params, stream); + // run_flash_fwd, Is_causal>(params, stream); + // These two are always slower + // run_flash_fwd>(params, stream); + // run_flash_fwd>(params, stream); + }); +} + +template +void run_mha_fwd_hdim128(Flash_fwd_params& params, cudaStream_t stream) { + constexpr int Headdim = 128; + const bool is_sm8x = params.dprops->major == 8 && params.dprops->minor > 0; + BOOL_SWITCH(params.is_causal, Is_causal, [&] { + // For sm86 or sm89, 64 x 64 is the fastest for causal (because it's square), + // and 128 x 32 (48 KB smem) is the fastest for non-causal since we get 2 CTAs per SM. + if (is_sm8x) { + if constexpr (!Is_causal) { + run_flash_fwd, Is_causal>(params, stream); + } else { + run_flash_fwd, Is_causal>(params, stream); + } + } else { + run_flash_fwd, Is_causal>(params, stream); + } + // run_flash_fwd, Is_causal>(params, stream); + // run_flash_fwd, Is_causal>(params, stream); + // run_flash_fwd, Is_causal>(params, stream); + // Using 8 warps (128 x 128 and 256 x 64) is 28% slower for seqlen=2k + // run_flash_fwd, Is_causal>(params, stream); + // run_flash_fwd, Is_causal>(params, stream); + // 1st ones are good for H100, A100 + // 2nd one is good for A6000 bc we get slightly better occupancy + }); +} + +template +void run_mha_fwd_hdim160(Flash_fwd_params& params, cudaStream_t stream) { + constexpr int Headdim = 160; + const bool is_sm8x = params.dprops->major == 8 && params.dprops->minor > 0; + BOOL_SWITCH(params.is_causal, Is_causal, [&] { + // For A100, H100, 128 x 32 is the fastest. + // For sm86 or sm89, 64 x 64 is the fastest for causal (because it's square), + // and 128 x 64 with 8 warps is the fastest for non-causal. + if (is_sm8x) { + if constexpr (!Is_causal) { + run_flash_fwd, Is_causal>(params, stream); + } else { + run_flash_fwd, Is_causal>(params, stream); + } + } else { + run_flash_fwd, Is_causal>(params, stream); + } + // run_flash_fwd, Is_causal>(params, stream); + // run_flash_fwd, Is_causal>(params, stream); + // run_flash_fwd>(params, stream); + // run_flash_fwd>(params, stream); + // run_flash_fwd>(params, stream); + // run_flash_fwd>(params, stream); + // run_flash_fwd>(params, stream); + }); +} + +template +void run_mha_fwd_hdim192(Flash_fwd_params& params, cudaStream_t stream) { + constexpr int Headdim = 192; + BOOL_SWITCH(params.is_causal, Is_causal, [&] { + run_flash_fwd, Is_causal>(params, stream); + // run_flash_fwd, Is_causal>(params, stream); + // run_flash_fwd, Is_causal>(params, stream); + // run_flash_fwd>(params, stream); + // run_flash_fwd>(params, stream); + // run_flash_fwd>(params, stream); + }); +} + +template +void run_mha_fwd_hdim224(Flash_fwd_params& params, cudaStream_t stream) { + constexpr size_t Headdim = 224; + constexpr size_t threshold = 2 * Headdim * (128 + 2 * 64); + size_t max_smem_per_block = params.dprops->sharedMemPerBlockOptin; + // printf("max_smem_per_block = %d\n", max_smem_per_block); + BOOL_SWITCH(params.is_causal, Is_causal, [&] { + if (max_smem_per_block >= threshold) { // 112 KB + run_flash_fwd, Is_causal>(params, stream); + } else { + run_flash_fwd, Is_causal>(params, stream); + } + // run_flash_fwd, Is_causal>(params, stream); + // run_flash_fwd, Is_causal>(params, stream); + // We can't do 128 x 32 with 8 warps because with headdim 224, kBlockKSmem = 32. + // If we have N = 32, there are only 1024 elements to load at once, where each load + // is 8 elements. This means we can only use 128 threads and not 256 threads. + // run_flash_fwd, Is_causal>(params, stream); + }); +} + +template +void run_mha_fwd_hdim256(Flash_fwd_params& params, cudaStream_t stream) { + constexpr size_t Headdim = 256; + constexpr size_t min_threshold = 2 * Headdim * (128 + 2 * 64); + constexpr size_t max_threshold = 4 * Headdim * (64 + 2 * 64); + size_t max_smem_per_sm = params.dprops->sharedMemPerMultiprocessor; + size_t max_smem_per_block = params.dprops->sharedMemPerBlockOptin; + // printf("max_smem_per_sm = %d, max_smem_per_block = %d\n", max_smem_per_sm, max_smem_per_block); + BOOL_SWITCH(params.is_causal, Is_causal, [&] { + // For A100, we want to run with 128 x 64 (128KB smem). + // For H100 we want to run with 64 x 64 (96KB smem) since then we can get 2 CTAs per SM. + if (max_smem_per_block >= min_threshold && max_smem_per_sm < max_threshold) { + run_flash_fwd, Is_causal>(params, stream); + } else { + run_flash_fwd, Is_causal>(params, stream); + } + // 64 KB + // run_flash_fwd, Is_causal>(params, stream); + // 96 KB + // run_flash_fwd, Is_causal>(params, stream); + }); +} + +} // namespace flash +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/bert/flash_attention/kernel_traits.h b/onnxruntime/contrib_ops/cuda/bert/flash_attention/kernel_traits.h new file mode 100644 index 0000000000000..0c967faa85c45 --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/flash_attention/kernel_traits.h @@ -0,0 +1,351 @@ +/****************************************************************************** + * Copyright (c) 2023, Tri Dao. + ******************************************************************************/ +#pragma once + +#include + +#include +#include +#include + +using namespace cute; + +namespace onnxruntime { +namespace flash { + +template +struct Flash_kernel_traits { +#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 800 + using Element = elem_type; + static constexpr bool Has_cp_async = true; +#else + using Element = cutlass::half_t; + static constexpr bool Has_cp_async = false; +#endif + + using ElementAccum = float; + using index_t = uint32_t; + +#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 800 + using MMA_Atom_Arch = std::conditional_t< + std::is_same_v, + MMA_Atom, + MMA_Atom>; + using ValLayoutMNK = cute::Layout>; +#else + using MMA_Atom_Arch = MMA_Atom; + using ValLayoutMNK = cute::Layout>; +#endif + +#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 750 + using SmemCopyAtom = Copy_Atom; + using SmemCopyAtomTransposed = Copy_Atom; +#else + using SmemCopyAtom = Copy_Atom; + using SmemCopyAtomTransposed = Copy_Atom; +#endif +}; + +// If Share_Q_K_smem is true, that forces Is_Q_in_regs to be true +template > +struct Flash_fwd_kernel_traits : public Base { + using Element = typename Base::Element; + using ElementAccum = typename Base::ElementAccum; + using index_t = typename Base::index_t; + static constexpr bool Has_cp_async = Base::Has_cp_async; + using SmemCopyAtom = typename Base::SmemCopyAtom; + using SmemCopyAtomTransposed = typename Base::SmemCopyAtomTransposed; + + static constexpr bool Share_Q_K_smem = Share_Q_K_smem_; + static constexpr bool Is_Q_in_regs = Is_Q_in_regs_ || Share_Q_K_smem; + + // The number of threads. + static constexpr int kNWarps = kNWarps_; + static constexpr int kNThreads = kNWarps * 32; + + static constexpr int kBlockM = kBlockM_; + static constexpr int kBlockN = kBlockN_; + static constexpr int kHeadDim = kHeadDim_; + static_assert(kHeadDim % 32 == 0); + static constexpr int kBlockKSmem = kHeadDim % 64 == 0 ? 64 : 32; + static constexpr int kBlockKGmem = kHeadDim % 128 == 0 ? 128 : (kHeadDim % 64 == 0 ? 64 : 32); + static constexpr int kSwizzle = kBlockKSmem == 32 ? 2 : 3; + + using TiledMma = TiledMMA< + typename Base::MMA_Atom_Arch, + Layout, _1, _1>>, // 4x1x1 or 8x1x1 thread group + typename Base::ValLayoutMNK>; // 1x2x1 or 1x2x2 value group for 16x16x16 MMA and LDSM + + using SmemLayoutAtomQ = decltype(composition(Swizzle{}, + // This has to be kBlockKSmem, using kHeadDim gives wrong results for d=128 + Layout>, + Stride, _1>>{})); + using SmemLayoutQ = decltype(tile_to_shape( + SmemLayoutAtomQ{}, + Shape, Int>{})); + + using SmemLayoutKV = decltype(tile_to_shape( + SmemLayoutAtomQ{}, + Shape, Int>{})); + + // This has to be kBlockN and not 8, otherwise we get wrong results for d=128 + using SmemLayoutAtomVtransposedNoSwizzle = Layout, Int>, + Stride<_1, Int>>; + using SmemLayoutAtomVtransposed = decltype(composition(Swizzle{}, SmemLayoutAtomVtransposedNoSwizzle{})); + using SmemLayoutVtransposed = decltype(tile_to_shape( + SmemLayoutAtomVtransposed{}, + Shape, Int>{})); + // Maybe the VtransposeNoSwizzle just needs to have the right shape + // And the strides don't matter? + using SmemLayoutVtransposedNoSwizzle = decltype(tile_to_shape( + SmemLayoutAtomVtransposedNoSwizzle{}, + Shape, Int>{})); + // using SmemLayoutVtransposedNoSwizzle = decltype(SmemLayoutVtransposed{}.layout_fn()); + + using SmemLayoutAtomO = decltype(composition(Swizzle{}, + Layout, Int>, + Stride, _1>>{})); + using SmemLayoutO = decltype(tile_to_shape( + SmemLayoutAtomO{}, + Shape, Int>{})); + using SmemCopyAtomO = Copy_Atom; + + static constexpr int kSmemQCount = cute::size(SmemLayoutQ{}); + static constexpr int kSmemKVCount = cute::size(SmemLayoutKV{}) * 2; + static constexpr int kSmemQSize = kSmemQCount * sizeof(Element); + static constexpr int kSmemKVSize = kSmemKVCount * sizeof(Element); + static constexpr int kSmemSize = Share_Q_K_smem ? std::max(kSmemQSize, kSmemKVSize) : kSmemQSize + kSmemKVSize; + + static constexpr int kGmemElemsPerLoad = sizeof(cute::uint128_t) / sizeof(Element); + static_assert(kHeadDim % kGmemElemsPerLoad == 0, "kHeadDim must be a multiple of kGmemElemsPerLoad"); + // Using kBlockKSmem here is 6-10% faster than kBlockKGmem for d=128 because of bank conflicts. + // For example, for d=128, smem is split into 2 "pages", each page takes care of columns + // 0-63 and 64-127. If we have 16 threads per row for gmem read, when we write to smem, + // thread 0 - 7 will write to the first page and thread 8 - 15 will write to the second page, + // to the same banks. + static constexpr int kGmemThreadsPerRow = kBlockKSmem / kGmemElemsPerLoad; + static_assert(kNThreads % kGmemThreadsPerRow == 0, "kNThreads must be a multiple of kGmemThreadsPerRow"); + using GmemLayoutAtom = cute::Layout, cute::Int>, + cute::Stride, _1>>; + + // We use CACHEGLOBAL instead of CACHEALWAYS for both Q and K/V, since we won't be reading + // from the same address by the same threadblock. This is slightly faster. + using Gmem_copy_struct = std::conditional_t< + Has_cp_async, + SM80_CP_ASYNC_CACHEGLOBAL, + DefaultCopy>; + using GmemTiledCopyQKV = decltype(make_tiled_copy(Copy_Atom{}, + GmemLayoutAtom{}, + Layout>{})); // Val layout, 8 vals per read + using GmemTiledCopyO = decltype(make_tiled_copy(Copy_Atom{}, + GmemLayoutAtom{}, + Layout>{})); // Val layout, 8 vals per store + static constexpr int kGmemThreadsPerRowP = kBlockN / kGmemElemsPerLoad; + static_assert(kNThreads % kGmemThreadsPerRowP == 0, "kNThreads must be a multiple of kGmemThreadsPerRowP"); + using GmemLayoutAtomP = Layout, Int>, + Stride, _1>>; + + using GmemTiledCopyP = decltype(make_tiled_copy(Copy_Atom{}, + GmemLayoutAtomP{}, + Layout>{})); // Val layout, 8 vals per store +}; + +// Is_V_in_regs is an option to reduce smem usage, but will increase register pressue. +// No_double_buffer is another option to reduce smem usage, but will slow things down. +template > +struct Flash_bwd_kernel_traits : public Base { + using Element = typename Base::Element; + using ElementAccum = typename Base::ElementAccum; + using index_t = typename Base::index_t; + static constexpr bool Has_cp_async = Base::Has_cp_async; + using SmemCopyAtom = typename Base::SmemCopyAtom; + using SmemCopyAtomTransposed = typename Base::SmemCopyAtomTransposed; + + static constexpr bool Is_V_in_regs = Is_V_in_regs_; + static constexpr bool No_double_buffer = No_double_buffer_; + + // The number of threads. + static constexpr int kNWarps = kNWarps_; + static constexpr int kNThreads = kNWarps * 32; + + static constexpr int kBlockM = kBlockM_; + static constexpr int kBlockN = kBlockN_; + static constexpr int kHeadDim = kHeadDim_; + static_assert(kHeadDim % 32 == 0); + static constexpr int kBlockKSmem = kHeadDim % 64 == 0 ? 64 : 32; + static constexpr int kBlockKGmem = kHeadDim % 128 == 0 ? 128 : (kHeadDim % 64 == 0 ? 64 : 32); + static constexpr int kSwizzle = kBlockKSmem == 32 ? 2 : 3; + + static constexpr int AtomLayoutMSdP = AtomLayoutMSdP_; + static_assert(kNWarps % AtomLayoutMSdP == 0); + static_assert(kNWarps % AtomLayoutNdKV == 0); + static_assert(kNWarps % AtomLayoutMdQ == 0); + + using TiledMmaSdP = TiledMMA< + typename Base::MMA_Atom_Arch, + cute::Layout, cute::Int, _1>>, + typename Base::ValLayoutMNK>; // 1x2x1 or 1x2x2 value group for 16x16x16 MMA and LDSM + + using TiledMmadKV = TiledMMA< + typename Base::MMA_Atom_Arch, + cute::Layout, cute::Int, _1>>, + typename Base::ValLayoutMNK>; // 1x2x1 or 1x2x2 value group for 16x16x16 MMA and LDSM + + using TiledMmadQ = TiledMMA< + typename Base::MMA_Atom_Arch, + cute::Layout, cute::Int, _1>>, // 2x4x1 or 4x2x1 thread group + typename Base::ValLayoutMNK>; // 1x2x1 or 1x2x2 value group for 16x16x16 MMA and LDSM + + using SmemLayoutAtomQdO = decltype(composition(Swizzle{}, + cute::Layout>, + cute::Stride, _1>>{})); + using SmemLayoutQdO = decltype(tile_to_shape( + SmemLayoutAtomQdO{}, + cute::make_shape(cute::Int{}, cute::Int{}))); + + using SmemLayoutAtomKV = decltype(composition(Swizzle{}, + cute::Layout, cute::Int>, + cute::Stride, _1>>{})); + using SmemLayoutKV = decltype(tile_to_shape( + // SmemLayoutAtomQdO{}, + SmemLayoutAtomKV{}, + cute::make_shape(cute::Int{}, cute::Int{}))); + + using SmemLayoutAtomKtransposedNoSwizzle = Layout, Int>, + Stride<_1, Int>>; + using SmemLayoutAtomKtransposed = decltype(composition(Swizzle{}, SmemLayoutAtomKtransposedNoSwizzle{})); + using SmemLayoutKtransposed = decltype(tile_to_shape( + SmemLayoutAtomKtransposed{}, + make_shape(Int{}, Int{}))); + // Maybe the KtransposeNoSwizzle just needs to have the right shape + // And the strides don't matter? + using SmemLayoutKtransposedNoSwizzle = decltype(tile_to_shape( + SmemLayoutAtomKtransposedNoSwizzle{}, + make_shape(Int{}, Int{}))); + // using SmemLayoutKtransposedNoSwizzle = decltype(SmemLayoutKtransposed{}.layout_fn()); + + // TODO: generalize to other values of kBlockN + // TODO: what should be the Swizzle here? 3 is faster than 1, and 1 is faster than 2 + // static constexpr int kPBlockN = kBlockN; + static_assert(kBlockN >= 64); + // TD [2023-03-19]: Idk why kPBlockN = 16 and kSwizzlePdS=3 is the fastest. + static constexpr int kPBlockN = 64; + static_assert(kPBlockN == 16 || kPBlockN == 32 || kPBlockN == 64); + // static constexpr int kSwizzlePdS = kPBlockN == 16 ? 1 : (kPBlockN == 32 ? 2 : 3); + static constexpr int kSwizzlePdS = 3; + using SmemLayoutAtomPdS = decltype(composition(Swizzle{}, + cute::Layout, cute::Int>, + cute::Stride, _1>>{})); + using SmemLayoutPdS = decltype(tile_to_shape( + SmemLayoutAtomPdS{}, + cute::make_shape(cute::Int{}, cute::Int{}))); + using SmemLayoutAtomPdStransposedNoSwizzle = Layout, Int>, + Stride<_1, Int>>; + using SmemLayoutAtomPdStransposed = decltype(composition(Swizzle{}, SmemLayoutAtomPdStransposedNoSwizzle{})); + using SmemLayoutPdStransposed = decltype(tile_to_shape( + SmemLayoutAtomPdStransposed{}, + make_shape(Int{}, Int{}))); + using SmemLayoutPdStransposedNoSwizzle = decltype(tile_to_shape( + SmemLayoutAtomPdStransposedNoSwizzle{}, + make_shape(Int{}, Int{}))); + // using SmemLayoutPdStransposedNoSwizzle = decltype(SmemLayoutPdStransposed{}.layout_fn()); + using SmemCopyAtomPdS = Copy_Atom; + + using SmemLayoutAtomQdOtransposedNoSwizzle = Layout, Int>, + Stride<_1, Int>>; + using SmemLayoutAtomQdOtransposed = decltype(composition(Swizzle{}, SmemLayoutAtomQdOtransposedNoSwizzle{})); + using SmemLayoutQdOtransposed = decltype(tile_to_shape( + SmemLayoutAtomQdOtransposed{}, + make_shape(Int{}, Int{}))); + using SmemLayoutQdOtransposedNoSwizzle = decltype(tile_to_shape( + SmemLayoutAtomQdOtransposedNoSwizzle{}, + make_shape(Int{}, Int{}))); + // using SmemLayoutQdOtransposedNoSwizzle = decltype(SmemLayoutQdOtransposed{}.layout_fn()); + + using SmemLayoutAtomdKV = decltype(composition(Swizzle{}, + Layout>, + Stride, _1>>{})); + using SmemLayoutdKV = decltype(tile_to_shape( + SmemLayoutAtomdKV{}, + make_shape(Int{}, Int{}))); + using SmemCopyAtomdKV = Copy_Atom; + + using SmemLayoutAtomdQ = decltype(composition(Swizzle{}, + Layout>, + Stride, _1>>{})); + using SmemLayoutdQ = decltype(tile_to_shape( + SmemLayoutAtomdQ{}, + make_shape(Int{}, Int{}))); + using SmemCopyAtomdQ = Copy_Atom; + + static constexpr int kSmemQdOCount = cute::size(SmemLayoutQdO{}) * (No_double_buffer ? 2 : 3); // Double buffer for sQ + static constexpr int kSmemKVCount = cute::size(SmemLayoutKV{}) * 2; + static constexpr int kSmemdSCount = cute::size(SmemLayoutPdS{}); + static constexpr int kSmemPCount = cute::size(SmemLayoutPdS{}); + static constexpr int kSmemdQCount = cute::size(SmemLayoutdQ{}); + static constexpr int kSmemdPsumCount = kBlockM; + static constexpr int kSmemQdOSize = kSmemQdOCount * sizeof(Element); + static constexpr int kSmemKVSize = kSmemKVCount * sizeof(Element); + static constexpr int kSmemdSSize = kSmemdSCount * sizeof(Element); + static constexpr int kSmemPSize = kSmemPCount * sizeof(Element); + static constexpr int kSmemdQSize = kSmemdQCount * sizeof(Element); + static constexpr int kSmemdPsumSize = kSmemdPsumCount * sizeof(ElementAccum); + static constexpr int kSmemSize = kSmemQdOSize + (!Is_V_in_regs + ? kSmemKVSize + kSmemdSSize + std::max(kSmemPSize, kSmemdQSize) + : std::max(kSmemKVSize, kSmemKVSize / 2 + kSmemdSSize + std::max(kSmemPSize, kSmemdQSize))); + static constexpr int kSmemSize1colblock = kSmemQdOSize + (!Is_V_in_regs + ? kSmemKVSize + kSmemdSSize + kSmemPSize + : std::max(kSmemKVSize, kSmemKVSize / 2 + kSmemdSSize + kSmemPSize)); + static constexpr int kSmemSize1rowblock = kSmemQdOSize / 3 * 2 + kSmemKVSize / 2 * 3 + kSmemdSSize + kSmemPSize; + + static constexpr int kGmemElemsPerLoad = sizeof(cute::uint128_t) / sizeof(Element); + static_assert(kHeadDim % kGmemElemsPerLoad == 0, "kHeadDim must be a multiple of kGmemElemsPerLoad"); + // Using kBlockKSmem instead of kHeadDim here to avoid bank conflicts, but doesn't seem + // to affect speed in practice. + static constexpr int kGmemThreadsPerRow = kBlockKSmem / kGmemElemsPerLoad; + static_assert(kNThreads % kGmemThreadsPerRow == 0, "kNThreads must be a multiple of kGmemThreadsPerRow"); + using GmemLayoutAtom = cute::Layout, cute::Int>, + cute::Stride, _1>>; + + // We use CACHEGLOBAL instead of CACHEALWAYS for both Q and K/V, since we won't be reading + // from the same address by the same threadblock. This is slightly faster. + using Gmem_copy_struct = std::conditional_t< + Has_cp_async, + SM80_CP_ASYNC_CACHEGLOBAL, + DefaultCopy>; + using GmemTiledCopyQKV = decltype(make_tiled_copy(Copy_Atom{}, + GmemLayoutAtom{}, + cute::Layout>{})); // Val layout, 8 vals per read + using GmemTiledCopydO = decltype(make_tiled_copy(Copy_Atom{}, + GmemLayoutAtom{}, + cute::Layout>{})); // Val layout, 8 vals per store + using GmemTiledCopydKV = decltype(make_tiled_copy(Copy_Atom{}, + GmemLayoutAtom{}, + cute::Layout>{})); // Val layout, 8 vals per store + using GmemTiledCopydQ = decltype(make_tiled_copy(Copy_Atom{}, + GmemLayoutAtom{}, + cute::Layout>{})); // Val layout, 8 vals per store + using GmemLayoutAtomdQaccum = std::conditional_t< + kBlockKSmem == 32, + cute::Layout, // Thread layout, 8 threads per row + cute::Stride<_8, _1>>, + cute::Layout, // Thread layout, 16 threads per row + cute::Stride<_16, _1>>>; + using GmemTiledCopydQaccum = decltype(make_tiled_copy(Copy_Atom{}, + GmemLayoutAtomdQaccum{}, + cute::Layout>{})); // Val layout, 4 vals per store + + using GmemTiledCopydQaccumAtomicAdd = decltype(make_tiled_copy(Copy_Atom{}, + cute::Layout, // Thread layout, 8 threads per row + cute::Stride<_32, _1>>{}, + cute::Layout>{})); // Val layout, 1 val per store +}; + +} // namespace flash +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/bert/flash_attention/softmax.h b/onnxruntime/contrib_ops/cuda/bert/flash_attention/softmax.h new file mode 100644 index 0000000000000..842edf3a98a86 --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/flash_attention/softmax.h @@ -0,0 +1,206 @@ +/****************************************************************************** + * Copyright (c) 2023, Tri Dao. + ******************************************************************************/ +#pragma once + +#include + +#include + +#include +#include + +#include "contrib_ops/cuda/bert/flash_attention/utils.h" + +namespace onnxruntime { +namespace flash { + +using namespace cute; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +__device__ inline void thread_reduce_(Tensor const& tensor, Tensor& summary, Operator& op) { + static_assert(Layout0::rank == 2, "Only support 2D Tensor"); + static_assert(Layout1::rank == 1, "Only support 1D Tensor"); + CUTE_STATIC_ASSERT_V(size<0>(summary) == size<0>(tensor)); +#pragma unroll + for (int mi = 0; mi < size<0>(tensor); mi++) { + summary(mi) = zero_init ? tensor(mi, 0) : op(summary(mi), tensor(mi, 0)); +#pragma unroll + for (int ni = 1; ni < size<1>(tensor); ni++) { + summary(mi) = op(summary(mi), tensor(mi, ni)); + } + } +} + +template +__device__ inline void quad_allreduce_(Tensor& dst, Tensor& src, Operator& op) { + CUTE_STATIC_ASSERT_V(size(dst) == size(src)); +#pragma unroll + for (int i = 0; i < size(dst); i++) { + dst(i) = Allreduce<4>::run(src(i), op); + } +} + +template +__device__ inline void reduce_(Tensor const& tensor, Tensor& summary, Operator& op) { + thread_reduce_(tensor, summary, op); + quad_allreduce_(summary, summary, op); +} + +template +__device__ inline void reduce_max(Tensor const& tensor, Tensor& max) { + MaxOp max_op; + reduce_(tensor, max, max_op); +} + +template +__device__ inline void reduce_sum(Tensor const& tensor, Tensor& sum) { + SumOp sum_op; + reduce_(tensor, sum, sum_op); +} + +// Apply the exp to all the elements. +template +inline __device__ void scale_apply_exp2(Tensor& tensor, Tensor const& max, const float scale) { + static_assert(Layout0::rank == 2, "Only support 2D Tensor"); + static_assert(Layout1::rank == 1, "Only support 1D Tensor"); + CUTE_STATIC_ASSERT_V(size<0>(max) == size<0>(tensor)); +#pragma unroll + for (int mi = 0; mi < size<0>(tensor); ++mi) { + // If max is -inf, then all elements must have been -inf (possibly due to masking). + // We don't want (-inf - (-inf)) since that would give NaN. + // If we don't have float around M_LOG2E the multiplication is done in fp64. + const float max_scaled = max(mi) == -INFINITY ? 0.f : max(mi) * (Scale_max ? scale : float(M_LOG2E)); +#pragma unroll + for (int ni = 0; ni < size<1>(tensor); ++ni) { + // Instead of computing exp(x - max), we compute exp2(x * log_2(e) - + // max * log_2(e)) This allows the compiler to use the ffma + // instruction instead of fadd and fmul separately. + tensor(mi, ni) = exp2f(tensor(mi, ni) * scale - max_scaled); + } + } +} + +// Apply the exp to all the elements. +template +inline __device__ void max_scale_exp2_sum(Tensor& tensor, Tensor& max, Tensor& sum, const float scale) { + static_assert(Layout0::rank == 2, "Only support 2D Tensor"); + static_assert(Layout1::rank == 1, "Only support 1D Tensor"); + CUTE_STATIC_ASSERT_V(size<0>(max) == size<0>(tensor)); +#pragma unroll + for (int mi = 0; mi < size<0>(tensor); ++mi) { + MaxOp max_op; + max(mi) = zero_init ? tensor(mi, 0) : max_op(max(mi), tensor(mi, 0)); +#pragma unroll + for (int ni = 1; ni < size<1>(tensor); ni++) { + max(mi) = max_op(max(mi), tensor(mi, ni)); + } + max(mi) = Allreduce<4>::run(max(mi), max_op); + // If max is -inf, then all elements must have been -inf (possibly due to masking). + // We don't want (-inf - (-inf)) since that would give NaN. + const float max_scaled = max(mi) == -INFINITY ? 0.f : max(mi) * scale; + sum(mi) = 0; +#pragma unroll + for (int ni = 0; ni < size<1>(tensor); ++ni) { + // Instead of computing exp(x - max), we compute exp2(x * log_2(e) - + // max * log_2(e)) This allows the compiler to use the ffma + // instruction instead of fadd and fmul separately. + tensor(mi, ni) = exp2f(tensor(mi, ni) * scale - max_scaled); + sum(mi) += tensor(mi, ni); + } + SumOp sum_op; + sum(mi) = Allreduce<4>::run(sum(mi), sum_op); + } +} + +template +inline __device__ void apply_mask(Tensor& tensor, const int max_seqlen_k, + const int col_idx_offset_ = 0) { + // tensor has shape (ncol=(2, MMA_M), nrow=(2, MMA_N)) + static_assert(Layout::rank == 2, "Only support 2D Tensor"); + const int lane_id = threadIdx.x % 32; + const int col_idx_offset = col_idx_offset_ + (lane_id % 4) * 2; +#pragma unroll + for (int nj = 0; nj < size<1, 1>(tensor); ++nj) { + const int col_idx_base = col_idx_offset + nj * 8; +#pragma unroll + for (int j = 0; j < size<1, 0>(tensor); ++j) { + const int col_idx = col_idx_base + j; + if (col_idx >= max_seqlen_k) { +// Without the "make_coord" we get wrong results +#pragma unroll + for (int mi = 0; mi < size<0>(tensor); ++mi) { + tensor(mi, make_coord(j, nj)) = -INFINITY; + } + } + } + } +} + +template +inline __device__ void apply_mask_causal(Tensor& tensor, const int col_idx_offset_, + const int max_seqlen_k, const int row_idx_offset_, + const int max_seqlen_q, const int warp_row_stride) { + // tensor has shape (ncol=(2, MMA_M), nrow=(2, MMA_N)) + static_assert(Layout::rank == 2, "Only support 2D Tensor"); + const int lane_id = threadIdx.x % 32; + // const int row_idx_offset = row_idx_offset_ + lane_id / 4; + const int row_idx_offset = row_idx_offset_; + const int col_idx_offset = col_idx_offset_ + (lane_id % 4) * 2; +#pragma unroll + for (int mi = 0; mi < size<0, 1>(tensor); ++mi) { + const int row_idx_base = row_idx_offset + mi * warp_row_stride; +#pragma unroll + for (int i = 0; i < size<0, 0>(tensor); ++i) { + const int row_idx = row_idx_base + i * 8; + const int col_idx_limit = std::min(max_seqlen_k, row_idx + 1 + max_seqlen_k - max_seqlen_q); +#pragma unroll + for (int nj = 0; nj < size<1, 1>(tensor); ++nj) { + const int col_idx_base = col_idx_offset + nj * 8; +#pragma unroll + for (int j = 0; j < size<1, 0>(tensor); ++j) { + const int col_idx = col_idx_base + j; + if (col_idx >= col_idx_limit) { + tensor(make_coord(i, mi), make_coord(j, nj)) = -INFINITY; + } + } + } + // if (cute::thread0()) { + // printf("mi = %d, i = %d, row_idx = %d, max_seqlen_k = %d\n", mi, i, row_idx, max_seqlen_k); + // print(tensor(make_coord(i, mi), _)); + // // print(tensor(_, j + nj * size<1, 0>(tensor))); + // } + } + } +} + +template +inline __device__ void apply_mask_causal_w_idx( + Tensor& tensor, Tensor const& idx_rowcol, + const int col_idx_offset_, const int max_seqlen_k, const int row_idx_offset_) { + // tensor has shape (ncol=(2, MMA_M), nrow=(2, MMA_N)) + static_assert(Layout0::rank == 2, "Only support 2D Tensor"); + static_assert(Layout1::rank == 2, "Only support 2D Tensor"); + CUTE_STATIC_ASSERT_V(size<0>(tensor) == size<0>(idx_rowcol)); + CUTE_STATIC_ASSERT_V(size<1>(tensor) == size<1>(idx_rowcol)); +#pragma unroll + for (int mi = 0; mi < size<0>(tensor); ++mi) { + const int col_idx_limit = std::min(max_seqlen_k, 1 + row_idx_offset_ + get<0>(idx_rowcol(mi, 0))); +#pragma unroll + for (int ni = 0; ni < size<1, 1>(tensor); ++ni) { + if (col_idx_offset_ + get<1>(idx_rowcol(0, ni)) >= col_idx_limit) { + tensor(mi, ni) = -INFINITY; + } + } + // if (cute::thread0()) { + // printf("ni = %d, j = %d, col_idx = %d, max_seqlen_k = %d\n", ni, j, col_idx, max_seqlen_k); + // print(tensor(_, make_coord(j, ni))); + // // print(tensor(_, j + ni * size<1, 0>(tensor))); + // } + } +} + +} // namespace flash +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/bert/flash_attention/static_switch.h b/onnxruntime/contrib_ops/cuda/bert/flash_attention/static_switch.h new file mode 100644 index 0000000000000..05ac2476690c2 --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/flash_attention/static_switch.h @@ -0,0 +1,60 @@ +// Inspired by https://github.com/NVIDIA/DALI/blob/main/include/dali/core/static_switch.h +// and https://github.com/pytorch/pytorch/blob/master/aten/src/ATen/Dispatch.h +#pragma once + +/// @param COND - a boolean expression to switch by +/// @param CONST_NAME - a name given for the constexpr bool variable. +/// @param ... - code to execute for true and false +/// +/// Usage: +/// ``` +/// BOOL_SWITCH(flag, BoolConst, [&] { +/// some_function(...); +/// }); +/// ``` +#define BOOL_SWITCH(COND, CONST_NAME, ...) \ + [&] { \ + if (COND) { \ + constexpr static bool CONST_NAME = true; \ + return __VA_ARGS__(); \ + } else { \ + constexpr static bool CONST_NAME = false; \ + return __VA_ARGS__(); \ + } \ + }() + +#define FP16_SWITCH(COND, ...) \ + [&] { \ + assert(COND); \ + using elem_type = cutlass::half_t; \ + return __VA_ARGS__(); \ + }() + +#define FWD_HEADDIM_SWITCH(HEADDIM, ...) \ + [&] { \ + if (HEADDIM <= 32) { \ + constexpr static int kHeadDim = 32; \ + return __VA_ARGS__(); \ + } else if (HEADDIM <= 64) { \ + constexpr static int kHeadDim = 64; \ + return __VA_ARGS__(); \ + } else if (HEADDIM <= 96) { \ + constexpr static int kHeadDim = 96; \ + return __VA_ARGS__(); \ + } else if (HEADDIM <= 128) { \ + constexpr static int kHeadDim = 128; \ + return __VA_ARGS__(); \ + } else if (HEADDIM <= 160) { \ + constexpr static int kHeadDim = 160; \ + return __VA_ARGS__(); \ + } else if (HEADDIM <= 192) { \ + constexpr static int kHeadDim = 192; \ + return __VA_ARGS__(); \ + } else if (HEADDIM <= 224) { \ + constexpr static int kHeadDim = 224; \ + return __VA_ARGS__(); \ + } else if (HEADDIM <= 256) { \ + constexpr static int kHeadDim = 256; \ + return __VA_ARGS__(); \ + } \ + }() diff --git a/onnxruntime/contrib_ops/cuda/bert/flash_attention/utils.h b/onnxruntime/contrib_ops/cuda/bert/flash_attention/utils.h new file mode 100644 index 0000000000000..49ee687419d0e --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/flash_attention/utils.h @@ -0,0 +1,371 @@ +/****************************************************************************** + * Copyright (c) 2023, Tri Dao. + ******************************************************************************/ +#pragma once + +#include +#include +#include + +#include + +#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 800 +#include +#endif + +#include +#include + +#include +#include +#include +#include + +//////////////////////////////////////////////////////////////////////////////////////////////////// +namespace onnxruntime { +namespace flash { + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +inline __device__ uint32_t relu2(const uint32_t x); + +template <> +inline __device__ uint32_t relu2(const uint32_t x) { + uint32_t res; + const uint32_t zero = 0u; +#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 800 + asm volatile("max.f16x2 %0, %1, %2;\n" + : "=r"(res) + : "r"(x), "r"(zero)); +#else + asm volatile( + "{\n" + "\t .reg .f16x2 sela;\n" + "\t set.gtu.u32.f16x2 sela, %1, %2;\n" + "\t and.b32 %0, sela, %1;\n" + "}\n" + : "=r"(res) + : "r"(x), "r"(zero)); +#endif + return res; +} + +#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 800 +template <> +inline __device__ uint32_t relu2(const uint32_t x) { + uint32_t res; + const uint32_t zero = 0u; + asm volatile("max.bf16x2 %0, %1, %2;\n" + : "=r"(res) + : "r"(x), "r"(zero)); + return res; +} +#endif + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 800 + +template +inline __device__ uint32_t convert_relu2(const float2 x); + +template <> +inline __device__ uint32_t convert_relu2(const float2 x) { + uint32_t res; + const uint32_t a = reinterpret_cast(x.x); + const uint32_t b = reinterpret_cast(x.y); + asm volatile("cvt.rn.relu.f16x2.f32 %0, %1, %2;\n" + : "=r"(res) + : "r"(b), "r"(a)); + return res; +} + +template <> +inline __device__ uint32_t convert_relu2(const float2 x) { + uint32_t res; + const uint32_t a = reinterpret_cast(x.x); + const uint32_t b = reinterpret_cast(x.y); + asm volatile("cvt.rn.relu.bf16x2.f32 %0, %1, %2;\n" + : "=r"(res) + : "r"(b), "r"(a)); + return res; +} + +#endif + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +inline __device__ float2 half2_unpack(uint32_t a); + +template <> +inline __device__ float2 half2_unpack<__half>(uint32_t a) { + return __half22float2(reinterpret_cast<__half2(&)>(a)); +} + +#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 800 +template <> +inline __device__ float2 half2_unpack<__nv_bfloat16>(uint32_t a) { + return __bfloat1622float2(reinterpret_cast<__nv_bfloat162(&)>(a)); +} +#endif + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +// Convert two half2's or bf162's into float, then take their dot product. +template +inline __device__ float hfma2_to_float(const uint32_t a, const uint32_t b) { + float2 af = flash::half2_unpack(a); + float2 bf = flash::half2_unpack(b); + return af.x * bf.x + af.y * bf.y; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +// Converted two vectors of 8 half's or bf16's into float, then take their dot product. +template +inline __device__ float hmulsum8(const uint4 a, const uint4 b) { + float sum; + sum = flash::hfma2_to_float(a.x, b.x); + sum += flash::hfma2_to_float(a.y, b.y); + sum += flash::hfma2_to_float(a.z, b.z); + sum += flash::hfma2_to_float(a.w, b.w); + return sum; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +struct MaxOp { + __device__ inline T operator()(T const& x, T const& y) { return x > y ? x : y; } +}; + +template <> +struct MaxOp { + // This is slightly faster + __device__ inline float operator()(float const& x, float const& y) { return max(x, y); } +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +struct SumOp { + __device__ inline T operator()(T const& x, T const& y) { return x + y; } +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +struct Allreduce { + static_assert(THREADS == 32 || THREADS == 16 || THREADS == 8 || THREADS == 4); + template + static __device__ inline T run(T x, Operator& op) { + constexpr int OFFSET = THREADS / 2; + x = op(x, __shfl_xor_sync(uint32_t(-1), x, OFFSET)); + return Allreduce::run(x, op); + } +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template <> +struct Allreduce<2> { + template + static __device__ inline T run(T x, Operator& op) { + x = op(x, __shfl_xor_sync(uint32_t(-1), x, 1)); + return x; + } +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +inline __device__ void gemm(Tensor0& acc, Tensor1& tCrA, Tensor2& tCrB, Tensor3 const& tCsA, + Tensor4 const& tCsB, TiledMma tiled_mma, + TiledCopyA smem_tiled_copy_A, TiledCopyB smem_tiled_copy_B, + ThrCopyA smem_thr_copy_A, ThrCopyB smem_thr_copy_B) { + CUTE_STATIC_ASSERT_V(size<1>(tCrA) == size<1>(acc)); // MMA_M + CUTE_STATIC_ASSERT_V(size<1>(tCrB) == size<2>(acc)); // MMA_N + CUTE_STATIC_ASSERT_V(size<2>(tCrA) == size<2>(tCrB)); // MMA_K + Tensor tCrA_copy_view = smem_thr_copy_A.retile_D(tCrA); + CUTE_STATIC_ASSERT_V(size<1>(tCsA) == size<1>(tCrA_copy_view)); // M + Tensor tCrB_copy_view = smem_thr_copy_B.retile_D(tCrB); + CUTE_STATIC_ASSERT_V(size<1>(tCsB) == size<1>(tCrB_copy_view)); // N + if (!A_in_regs) { + cute::copy(smem_tiled_copy_A, tCsA(_, _, _0{}), tCrA_copy_view(_, _, _0{})); + } + if (!B_in_regs) { + cute::copy(smem_tiled_copy_B, tCsB(_, _, _0{}), tCrB_copy_view(_, _, _0{})); + } +#pragma unroll + for (int i = 0; i < size<2>(tCrA); ++i) { + if (i < size<2>(tCrA) - 1) { + if (!A_in_regs) { + cute::copy(smem_tiled_copy_A, tCsA(_, _, i + 1), tCrA_copy_view(_, _, i + 1)); + } + if (!B_in_regs) { + cute::copy(smem_tiled_copy_B, tCsB(_, _, i + 1), tCrB_copy_view(_, _, i + 1)); + } + } + cute::gemm(tiled_mma, tCrA(_, _, i), tCrB(_, _, i), acc); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +inline __device__ void gemm_A_in_regs(Tensor0& acc, Tensor1& tCrA, Tensor2& tCrB, Tensor3 const& tCsB, + TiledMma tiled_mma, TiledCopy smem_tiled_copy_B, + ThrCopy smem_thr_copy_B) { + CUTE_STATIC_ASSERT_V(size<1>(tCrA) == size<1>(acc)); // MMA_M + CUTE_STATIC_ASSERT_V(size<1>(tCrB) == size<2>(acc)); // MMA_N + CUTE_STATIC_ASSERT_V(size<2>(tCrA) == size<2>(tCrB)); // MMA_K + Tensor tCrB_copy_view = smem_thr_copy_B.retile_D(tCrB); + CUTE_STATIC_ASSERT_V(size<1>(tCsB) == size<1>(tCrB_copy_view)); // N + cute::copy(smem_tiled_copy_B, tCsB(_, _, _0{}), tCrB_copy_view(_, _, _0{})); +#pragma unroll + for (int i = 0; i < size<2>(tCrA); ++i) { + if (i < size<2>(tCrA) - 1) { + cute::copy(smem_tiled_copy_B, tCsB(_, _, i + 1), tCrB_copy_view(_, _, i + 1)); + } + cute::gemm(tiled_mma, tCrA(_, _, i), tCrB(_, _, i), acc); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +// Convert acc_layout from (MMA=4, MMA_M, MMA_N) to (nrow=(2, MMA_M), ncol=(2, MMA_N)) +template +inline __device__ auto convert_layout_acc_rowcol(Layout acc_layout) { + static_assert(decltype(size<0>(acc_layout))::value == 4); + static_assert(decltype(rank(acc_layout))::value == 3); + auto l = logical_divide(acc_layout, Shape<_2>{}); // ((2, 2), MMA_M, MMA_N) + return make_layout(make_layout(get<0, 1>(l), get<1>(l)), make_layout(get<0, 0>(l), get<2>(l))); +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +// Convert rowcol_layout from (nrow=(2, MMA_M), ncol=(2, MMA_N)) to ((2, 2, 2), MMA_M, MMA_N / 2) +// if using m16n8k16, or to ((2, 2, 1), MMA_M, MMA_N) if using m16n8k8. +template +inline __device__ auto convert_layout_rowcol_Aregs(Layout rowcol_layout) { + using X = Underscore; + static_assert(decltype(size<0, 0>(rowcol_layout))::value == 2); + static_assert(decltype(size<1, 0>(rowcol_layout))::value == 2); + constexpr int mma_shape_K = get<2>(typename MMA_traits::Shape_MNK{}); + static_assert(mma_shape_K == 8 || mma_shape_K == 16); + constexpr int MMA_N_divisor = mma_shape_K == 8 ? 1 : 2; + auto l = logical_divide(rowcol_layout, Shape>>{}); // ((2, MMA_M), (2, (2, MMA_N / 2))) + return make_layout(make_layout(get<1, 0>(l), get<0, 0>(l), get<1, 1, 0>(l)), + get<0, 1>(l), + get<1, 1, 1>(l)); +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +inline __device__ auto convert_type(Tensor const& tensor) { + using From_type = typename Engine::value_type; + constexpr int numel = decltype(size(tensor))::value; + cutlass::NumericArrayConverter convert_op; + // HACK: this requires tensor to be "contiguous" + auto frag = convert_op(*reinterpret_cast*>(tensor.data())); + return make_tensor(make_rmem_ptr(&frag), tensor.layout()); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +inline __device__ void relu_(Tensor& tensor) { + constexpr int numel = decltype(size(tensor))::value; + static_assert(numel % 2 == 0); + using value_t = typename Engine::value_type; + // HACK: this requires tensor to be "contiguous" + Tensor tensor_uint32 = recast(tensor); +#pragma unroll + for (int i = 0; i < size(tensor_uint32); ++i) { + tensor_uint32(i) = relu2(tensor_uint32(i)); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +// On SM80 and above, we can fuse fp32 -> fp16/bf16 conversion and relu into 1 instruction +template +inline __device__ auto convert_type_relu(Tensor const& tensor) { + using From_type = typename Engine::value_type; + static_assert(std::is_same_v || std::is_same_v); + static_assert(std::is_same_v); + constexpr int numel = decltype(size(tensor))::value; + static_assert(numel % 2 == 0); +#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 800 + // HACK: this requires tensor to be "contiguous" + Tensor tensor_float2 = recast(tensor); + Tensor out_uint32 = make_tensor(tensor_float2.layout()); +#pragma unroll + for (int i = 0; i < size(out_uint32); ++i) { + out_uint32(i) = convert_relu2(tensor_float2(i)); + } + Tensor out = make_tensor(make_rmem_ptr(out_uint32.data()), tensor.layout()); +#else + Tensor out = flash::convert_type(tensor); + flash::relu_(out); +#endif + return out; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +// Blocks until all but N previous cp.async.commit_group operations have committed. +// This differs from cute::cp_async_wait in that when N = 0 we don't call cp.async.wait_all +// (which is equivalent to commit_group then wait_group 0). +// Instead we just call cp.async.wait_group 0, which is slightly faster. +// https://github.com/NVIDIA/cutlass/blob/master/include/cute/arch/copy_sm80.hpp#L113 +template +CUTE_HOST_DEVICE void cp_async_wait() { +#if defined(CUTE_ARCH_CP_ASYNC_SM80_ENABLED) + asm volatile("cp.async.wait_group %0;\n" ::"n"(N)); +#endif +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +inline __device__ void copy(TiledCopy thr_copy, Tensor const& S, + Tensor& D, Tensor const& identity_MN, + Tensor const& predicate_K, int max_MN = 0) { + CUTE_STATIC_ASSERT_V(rank(S) == Int<3>{}); + CUTE_STATIC_ASSERT_V(rank(D) == Int<3>{}); + CUTE_STATIC_ASSERT_V(size<0>(S) == size<0>(D)); // MMA + CUTE_STATIC_ASSERT_V(size<1>(S) == size<1>(D)); // MMA_M + CUTE_STATIC_ASSERT_V(size<2>(S) == size<2>(D)); // MMA_K + // There's no case where !Clear_OOB_K && Clear_OOB_MN + static_assert(!(Clear_OOB_MN && !Clear_OOB_K)); +#pragma unroll + for (int m = 0; m < size<1>(S); ++m) { + if (Is_even_MN || get<0>(identity_MN(0, m, 0)) < max_MN) { +#pragma unroll + for (int k = 0; k < size<2>(S); ++k) { + if (Is_even_K || predicate_K(k)) { + copy(thr_copy, S(_, m, k), D(_, m, k)); + } else if (Clear_OOB_K) { + clear(D(_, m, k)); + } + } + } else if (Clear_OOB_MN) { + clear(D(_, m, _)); + } + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace flash +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/bert/multihead_attention.cc b/onnxruntime/contrib_ops/cuda/bert/multihead_attention.cc index ab0488afc5d51..25f3f59165e43 100644 --- a/onnxruntime/contrib_ops/cuda/bert/multihead_attention.cc +++ b/onnxruntime/contrib_ops/cuda/bert/multihead_attention.cc @@ -7,6 +7,7 @@ #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/flash_attention/flash_api.h" using namespace onnxruntime::cuda; using namespace ::onnxruntime::common; @@ -51,6 +52,17 @@ MultiHeadAttention::MultiHeadAttention(const OpKernelInfo& info) !ParseEnvironmentVariableWithDefault(attention::kDisableTrtFlashAttention, false); #if USE_FLASH_ATTENTION + disable_flash_attention_ = sizeof(T) != 2 || + ParseEnvironmentVariableWithDefault(attention::kDisableFlashAttention, false); + min_seq_len_for_flash_attention_packed_qkv_ = ParseEnvironmentVariableWithDefault( + attention::kMinSeqLenForFlashAttentionPackedQKV, + attention::kDefaultMinSeqLenForFlashAttentionPackedQKV); +#else + disable_flash_attention_ = true; + min_seq_len_for_flash_attention_packed_qkv_ = 0; +#endif + +#if USE_MEMORY_EFFICIENT_ATTENTION disable_memory_efficient_attention_ = ParseEnvironmentVariableWithDefault(attention::kDisableMemoryEfficientAttention, false); #else disable_memory_efficient_attention_ = true; @@ -94,6 +106,7 @@ Status MultiHeadAttention::ComputeInternal(OpKernelContext* context) const { mask_filter_value_, scale_, false, // past_present_share_buffer + false, // dmmha_packing device_prop.maxThreadsPerBlock)); int sequence_length = parameters.sequence_length; @@ -117,9 +130,35 @@ Status MultiHeadAttention::ComputeInternal(OpKernelContext* context) const { int sm = device_prop.major * 10 + device_prop.minor; bool is_mask_1d_seq_len = parameters.mask_type == AttentionMaskType::MASK_1D_KEY_SEQ_LEN; - bool is_mask_1d_key_seq_len_start = parameters.mask_type == AttentionMaskType::MASK_1D_KEY_SEQ_LEN_START; - bool use_fused_cross_attention = !disable_fused_cross_attention_ && + const bool pass_key_value_as_past = (parameters.pass_past_in_kv && nullptr != key && nullptr != value); + +#if USE_FLASH_ATTENTION || USE_MEMORY_EFFICIENT_ATTENTION + // Exclude this case since PrepareQkv will convert the format to BNSH. + bool past_no_bias = (pass_key_value_as_past || past_key != nullptr || present_key != nullptr) && bias == nullptr; +#endif + +#if USE_FLASH_ATTENTION + bool use_flash_attention = !disable_flash_attention_ && + !past_no_bias && + nullptr == relative_position_bias && + nullptr == key_padding_mask && + 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. + if (use_flash_attention && key == nullptr && value == nullptr && + parameters.sequence_length < min_seq_len_for_flash_attention_packed_qkv_) { + use_flash_attention = false; + } +#else + constexpr bool use_flash_attention = false; +#endif + + bool use_fused_cross_attention = !use_flash_attention && + !disable_fused_cross_attention_ && nullptr == key_padding_mask && nullptr == relative_position_bias && (nullptr == past_key && nullptr == past_value && !parameters.pass_past_in_kv) && @@ -140,7 +179,8 @@ Status MultiHeadAttention::ComputeInternal(OpKernelContext* context) const { } } - bool use_fused_runner = !disable_fused_self_attention_ && + bool use_fused_runner = !use_flash_attention && + !disable_fused_self_attention_ && fused_cross_attention_kernel == nullptr && nullptr == relative_position_bias && (value != nullptr || key == nullptr) && @@ -165,25 +205,30 @@ Status MultiHeadAttention::ComputeInternal(OpKernelContext* context) const { } } -#if USE_FLASH_ATTENTION +#if USE_MEMORY_EFFICIENT_ATTENTION bool is_long_sequence = sizeof(T) == 2 || // sequence length threshold is 0 for FP16 - parameters.sequence_length >= attention::kMinSequenceLengthForMemoryEfficientAttentionFp32 || - parameters.kv_sequence_length >= attention::kMinSequenceLengthForMemoryEfficientAttentionFp32; + parameters.sequence_length >= attention::kMinSeqLenForMemoryEfficientAttentionFp32 || + parameters.kv_sequence_length >= attention::kMinSeqLenForMemoryEfficientAttentionFp32; bool is_good_for_rpb = relative_position_bias != nullptr && parameters.sequence_length % (4 * sizeof(T)) == 0; - bool use_memory_efficient_attention = fused_runner == nullptr && + bool use_memory_efficient_attention = !use_flash_attention && + fused_runner == nullptr && fused_cross_attention_kernel == nullptr && !disable_memory_efficient_attention_ && + (parameters.head_size & 7) == 0 && + (parameters.v_head_size & 7) == 0 && is_long_sequence && + !past_no_bias && (relative_position_bias == nullptr || is_good_for_rpb) && - (nullptr == key_padding_mask || is_mask_1d_key_seq_len_start) && + (nullptr == key_padding_mask || parameters.mask_type == AttentionMaskType::MASK_1D_KEY_SEQ_LEN_START) && has_memory_efficient_attention(sm, sizeof(T) == 2); #else constexpr bool use_memory_efficient_attention = false; #endif // When packed kv or packed qkv is used, there is no needed for add bias transpose thus no qkv workspace. + // TODO(tianleiwu): flash attention or memory efficient attention might not need qkv workspace sometime. bool no_qkv_workspace = nullptr == value && (use_fused_cross_attention || (nullptr != fused_runner && nullptr == key)) && nullptr == key_padding_mask && @@ -203,6 +248,7 @@ Status MultiHeadAttention::ComputeInternal(OpKernelContext* context) const { parameters.kv_sequence_length, parameters.total_sequence_length, fused_runner, + use_flash_attention, use_fused_cross_attention, use_memory_efficient_attention); } @@ -211,20 +257,18 @@ Status MultiHeadAttention::ComputeInternal(OpKernelContext* context) const { const size_t past_k_bytes = element_size * parameters.batch_size * parameters.kv_sequence_length * parameters.num_heads * parameters.head_size; const size_t past_v_bytes = element_size * parameters.batch_size * parameters.kv_sequence_length * parameters.num_heads * parameters.v_head_size; - auto temp_k_work_space = (parameters.pass_past_in_kv || use_memory_efficient_attention) ? GetScratchBuffer(past_k_bytes, context->GetComputeStream()) : nullptr; - auto temp_v_work_space = (parameters.pass_past_in_kv || use_memory_efficient_attention) ? GetScratchBuffer(past_v_bytes, context->GetComputeStream()) : nullptr; + const bool use_temp_k_v_workspace = parameters.pass_past_in_kv || use_memory_efficient_attention || use_flash_attention; + auto temp_k_work_space = use_temp_k_v_workspace ? GetScratchBuffer(past_k_bytes, context->GetComputeStream()) : nullptr; + auto temp_v_work_space = use_temp_k_v_workspace ? GetScratchBuffer(past_v_bytes, context->GetComputeStream()) : nullptr; typedef typename ToCudaType::MappedType CudaT; AttentionData data; - data.gemm_buffer = nullptr; data.bias = (nullptr == bias) ? nullptr : reinterpret_cast(bias->Data()); data.query = reinterpret_cast(query->Data()); data.key = (nullptr == key || parameters.pass_past_in_kv) ? nullptr : reinterpret_cast(key->Data()); data.value = (nullptr == value || parameters.pass_past_in_kv) ? nullptr : reinterpret_cast(value->Data()); data.mask_index = (nullptr == key_padding_mask) ? nullptr : key_padding_mask->Data(); data.mask_index_dims = (nullptr == key_padding_mask) ? gsl::span() : key_padding_mask->Shape().GetDims(); - data.past = nullptr; - const bool pass_key_value_as_past = (parameters.pass_past_in_kv && nullptr != key && nullptr != value); data.past_key = pass_key_value_as_past ? reinterpret_cast(key->Data()) : (nullptr == past_key) ? nullptr : reinterpret_cast(past_key->Data()); @@ -234,14 +278,14 @@ Status MultiHeadAttention::ComputeInternal(OpKernelContext* context) const { data.relative_position_bias = (nullptr == relative_position_bias) ? nullptr : reinterpret_cast(relative_position_bias->Data()); data.has_qkv_workspace = !no_qkv_workspace; data.workspace = reinterpret_cast(work_space.get()); - data.temp_k_workspace = (parameters.pass_past_in_kv || use_memory_efficient_attention) ? reinterpret_cast(temp_k_work_space.get()) : nullptr; - data.temp_v_workspace = (parameters.pass_past_in_kv || use_memory_efficient_attention) ? reinterpret_cast(temp_v_work_space.get()) : nullptr; + data.temp_k_workspace = use_temp_k_v_workspace ? reinterpret_cast(temp_k_work_space.get()) : nullptr; + data.temp_v_workspace = use_temp_k_v_workspace ? reinterpret_cast(temp_v_work_space.get()) : nullptr; data.output = reinterpret_cast(output->MutableData()); - data.present = nullptr; data.present_key = (nullptr == present_key) ? nullptr : reinterpret_cast(present_key->MutableData()); data.present_value = (nullptr == present_value) ? nullptr : reinterpret_cast(present_value->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_memory_efficient_attention = use_memory_efficient_attention; data.cumulated_sequence_length_q_cache = &(this->cumulated_sequence_length_q_cache_); data.cumulated_sequence_length_kv_cache = &(this->cumulated_sequence_length_kv_cache_); @@ -249,7 +293,7 @@ Status MultiHeadAttention::ComputeInternal(OpKernelContext* context) const { cublasHandle_t cublas = GetCublasHandle(context); return QkvToContext( - device_prop, cublas, Stream(context), parameters, data); + device_prop, cublas, context->GetComputeStream(), parameters, data); } } // namespace cuda diff --git a/onnxruntime/contrib_ops/cuda/bert/multihead_attention.h b/onnxruntime/contrib_ops/cuda/bert/multihead_attention.h index af5045e70d3b4..33fa3d50e4564 100644 --- a/onnxruntime/contrib_ops/cuda/bert/multihead_attention.h +++ b/onnxruntime/contrib_ops/cuda/bert/multihead_attention.h @@ -28,7 +28,9 @@ class MultiHeadAttention final : public CudaKernel { bool disable_fused_self_attention_; bool enable_trt_flash_attention_; bool disable_fused_cross_attention_; + bool disable_flash_attention_; bool disable_memory_efficient_attention_; + int min_seq_len_for_flash_attention_packed_qkv_; mutable std::unique_ptr fused_fp16_runner_; mutable const FusedMultiHeadCrossAttentionKernel* fused_fp16_cross_attention_kernel_; mutable CumulatedSequenceLengthCache cumulated_sequence_length_q_cache_; diff --git a/onnxruntime/contrib_ops/cuda/bert/packed_attention.cc b/onnxruntime/contrib_ops/cuda/bert/packed_attention.cc index da768f777523d..ec8b1d051b3d9 100644 --- a/onnxruntime/contrib_ops/cuda/bert/packed_attention.cc +++ b/onnxruntime/contrib_ops/cuda/bert/packed_attention.cc @@ -33,7 +33,60 @@ REGISTER_KERNEL_TYPED(float) REGISTER_KERNEL_TYPED(MLFloat16) template -PackedAttention::PackedAttention(const OpKernelInfo& info) : CudaKernel(info) { +TrtFusedAttention::TrtFusedAttention() { + disable_fused_runner_ = sizeof(T) != 2 || + ParseEnvironmentVariableWithDefault(attention::kDisableFusedSelfAttention, false); + + enable_trt_flash_attention_ = sizeof(T) == 2 && + !ParseEnvironmentVariableWithDefault(attention::kDisableTrtFlashAttention, false); +} + +template +MHARunner* TrtFusedAttention::GetFusedRunner(const cudaDeviceProp& device_prop, + const PackedAttentionParameters& parameters) const { + MHARunner* fused_runner = nullptr; + + bool use_fused_runner = !disable_fused_runner_ && + !parameters.has_relative_position_bias && + parameters.hidden_size == parameters.v_hidden_size; + + if (!use_fused_runner) { + return fused_runner; + } + + // Check whether we can use fused kernel + int sm = device_prop.major * 10 + device_prop.minor; + bool is_fMHA_supported = FusedMHARunnerFP16v2::is_supported(sm, + parameters.head_size, + parameters.sequence_length, + enable_trt_flash_attention_, + false /*causal*/); + + if (!is_fMHA_supported) { + return fused_runner; + } + + // Assuming that num_heads and head_size do not change. + if (nullptr == fused_fp16_runner_.get()) { + fused_fp16_runner_ = FusedMHARunnerFP16v2::Create(parameters.num_heads, parameters.head_size, sm, false /*causal*/, + enable_trt_flash_attention_, parameters.scale); + } + + // In case some kernel not loaded due to shared memory limit, we need to double check here. + const int S = fused_fp16_runner_->getSFromMaxSeqLen(parameters.sequence_length); + if (fused_fp16_runner_->isValid(S)) { + fused_runner = fused_fp16_runner_.get(); + } + + return fused_runner; +} + +// template class instantiation +template class TrtFusedAttention; +template class TrtFusedAttention; + +template +PackedAttention::PackedAttention(const OpKernelInfo& info) : TrtFusedAttention(), 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); @@ -43,12 +96,6 @@ PackedAttention::PackedAttention(const OpKernelInfo& info) : CudaKernel(info) if (!info.GetAttrs("qkv_hidden_sizes", qkv_hidden_sizes_).IsOK()) { qkv_hidden_sizes_.clear(); } - - disable_fused_runner_ = sizeof(T) != 2 || - ParseEnvironmentVariableWithDefault(attention::kDisableFusedSelfAttention, false); - - enable_trt_flash_attention_ = sizeof(T) == 2 && - !ParseEnvironmentVariableWithDefault(attention::kDisableTrtFlashAttention, false); } template @@ -77,7 +124,6 @@ Status PackedAttention::CheckInputs(const TensorShape& input_shape, // token_offset : (B, S) // cu_seq_len_shape : (B + 1) // relative_position_bias : (B, N, S, S), (1, N, S, S) or NULL - const auto& input_dims = input_shape.GetDims(); if (input_dims.size() != 2) { return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, @@ -124,6 +170,7 @@ Status PackedAttention::CheckInputs(const TensorShape& input_shape, "Input 'cumulative_sequence_length' should have 1 dimension with size equal to batch_size + 1"); } + const int num_heads = this->GetNumHeads(); int64_t q_hidden_size = bias_dims[0] / static_cast(3); int64_t k_hidden_size = q_hidden_size; int64_t v_hidden_size = k_hidden_size; @@ -134,7 +181,7 @@ Status PackedAttention::CheckInputs(const TensorShape& input_shape, } for (size_t i = 0; i < qkv_hidden_sizes_.size(); i++) { - if (qkv_hidden_sizes_[i] % num_heads_ != 0) { + if (qkv_hidden_sizes_[i] % num_heads != 0) { return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "hidden_size should be divisible by num_heads:", qkv_hidden_sizes_[i]); } @@ -176,7 +223,7 @@ Status PackedAttention::CheckInputs(const TensorShape& input_shape, broadcast_res_pos_bias = true; } - if (relative_position_bias_dims[1] != num_heads_) { + if (relative_position_bias_dims[1] != num_heads) { return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Input 'relative_position_bias' dimension 1 should be same as number of heads, got ", relative_position_bias_dims[1]); @@ -200,10 +247,10 @@ Status PackedAttention::CheckInputs(const TensorShape& input_shape, parameters.input_hidden_size = static_cast(input_hidden_size); parameters.hidden_size = static_cast(q_hidden_size); parameters.v_hidden_size = static_cast(v_hidden_size); - parameters.head_size = static_cast(q_hidden_size) / num_heads_; - parameters.v_head_size = static_cast(v_hidden_size) / num_heads_; - parameters.num_heads = num_heads_; - parameters.scale = scale_; + parameters.head_size = static_cast(q_hidden_size) / num_heads; + parameters.v_head_size = static_cast(v_hidden_size) / num_heads; + parameters.num_heads = num_heads; + parameters.scale = this->GetScale(); parameters.token_count = static_cast(token_count); parameters.has_relative_position_bias = nullptr != relative_position_bias; parameters.broadcast_res_pos_bias = broadcast_res_pos_bias; @@ -211,46 +258,6 @@ Status PackedAttention::CheckInputs(const TensorShape& input_shape, return Status::OK(); } -template -MHARunner* PackedAttention::TryGettingFusedRunner(const PackedAttentionParameters& parameters) const { - MHARunner* fused_runner = nullptr; - - bool use_fused_runner = !disable_fused_runner_ && - !parameters.has_relative_position_bias && - parameters.hidden_size == parameters.v_hidden_size; - - if (!use_fused_runner) { - return fused_runner; - } - - // Check whether we can use fused kernel - auto& device_prop = GetDeviceProp(); - int sm = device_prop.major * 10 + device_prop.minor; - bool is_fMHA_supported = FusedMHARunnerFP16v2::is_supported(sm, - parameters.head_size, - parameters.sequence_length, - enable_trt_flash_attention_, - false); - - if (!is_fMHA_supported) { - return fused_runner; - } - - // Assuming that num_heads and head_size do not change. - if (nullptr == fused_fp16_runner_.get()) { - fused_fp16_runner_.reset(new FusedMHARunnerFP16v2(num_heads_, parameters.head_size, sm, false /* causal_mask*/, - enable_trt_flash_attention_, parameters.scale)); - } - - // In case some kernel not loaded due to shared memory limit, we need to double check here. - const int S = fused_fp16_runner_->getSFromMaxSeqLen(parameters.sequence_length); - if (fused_fp16_runner_->isValid(S)) { - fused_runner = fused_fp16_runner_.get(); - } - - return fused_runner; -} - template Status PackedAttention::ComputeInternal(OpKernelContext* context) const { const Tensor* input = context->Input(0); @@ -272,7 +279,21 @@ Status PackedAttention::ComputeInternal(OpKernelContext* context) const { TensorShapeVector output_shape{parameters.token_count, parameters.v_hidden_size}; Tensor* output = context->Output(0, output_shape); - MHARunner* fused_runner = TryGettingFusedRunner(parameters); + auto& device_prop = this->GetDeviceProp(); + MHARunner* fused_runner = this->GetFusedRunner(device_prop, parameters); + + bool use_memory_efficient_attention = false; +#if USE_MEMORY_EFFICIENT_ATTENTION + if (nullptr == fused_runner) { + int sm = device_prop.major * 10 + device_prop.minor; + bool is_good_for_rpb = !parameters.has_relative_position_bias || parameters.sequence_length % (4 * sizeof(T)) == 0; + use_memory_efficient_attention = is_good_for_rpb && + sizeof(T) == 2 && // only enable for fp16 + (parameters.head_size & 7) == 0 && + (parameters.v_head_size & 7) == 0 && + has_memory_efficient_attention(sm, sizeof(T) == 2); + } +#endif typedef typename ToCudaType::MappedType CudaT; CudaT one = ToCudaType::FromFloat(1.0f); @@ -282,10 +303,9 @@ Status PackedAttention::ComputeInternal(OpKernelContext* context) const { int m = parameters.token_count; int n = parameters.hidden_size + parameters.hidden_size + parameters.v_hidden_size; int k = parameters.input_hidden_size; - gemm_buffer = GetScratchBuffer(static_cast(m) * n, context->GetComputeStream()); + gemm_buffer = this->GetScratchBuffer(static_cast(m) * n, context->GetComputeStream()); - auto& device_prop = GetDeviceProp(); - cublasHandle_t cublas = GetCublasHandle(context); + cublasHandle_t cublas = this->GetCublasHandle(context); // Gemm, note that CUDA assumes col-major, so result(N, M) = 1 * weights x input + 1 x bias // The bias part is not included here since we fuse bias, transpose and output 3 matrice into one cuda kernel. @@ -296,14 +316,18 @@ Status PackedAttention::ComputeInternal(OpKernelContext* context) const { &zero, reinterpret_cast(gemm_buffer.get()), n, device_prop)); constexpr size_t element_size = sizeof(T); + constexpr bool no_qkv_workspace = false; // need workspace to add bias size_t workSpaceSize = GetAttentionWorkspaceSize(element_size, parameters.batch_size, parameters.num_heads, parameters.head_size, parameters.v_head_size, parameters.sequence_length, - fused_runner); - auto work_space = GetScratchBuffer(workSpaceSize, context->GetComputeStream()); + fused_runner, + false, + use_memory_efficient_attention, + no_qkv_workspace); + auto work_space = this->GetScratchBuffer(workSpaceSize, context->GetComputeStream()); typedef typename ToCudaType::MappedType CudaT; PackedAttentionData data; @@ -315,6 +339,7 @@ Status PackedAttention::ComputeInternal(OpKernelContext* context) const { data.cumulative_sequence_length = cumulative_sequence_length->Data(); data.output = reinterpret_cast(output->MutableData()); data.fused_runner = reinterpret_cast(fused_runner); + data.use_memory_efficient_attention = use_memory_efficient_attention; return QkvToContext(device_prop, cublas, Stream(context), parameters, data); } diff --git a/onnxruntime/contrib_ops/cuda/bert/packed_attention.h b/onnxruntime/contrib_ops/cuda/bert/packed_attention.h index 873a1a3c3b4c9..0cdd8021de4a1 100644 --- a/onnxruntime/contrib_ops/cuda/bert/packed_attention.h +++ b/onnxruntime/contrib_ops/cuda/bert/packed_attention.h @@ -17,7 +17,21 @@ namespace cuda { using namespace onnxruntime::cuda; template -class PackedAttention final : public CudaKernel { +class TrtFusedAttention { + public: + TrtFusedAttention(); + + protected: + MHARunner* GetFusedRunner(const cudaDeviceProp& device_prop, const PackedAttentionParameters& parameters) const; + + private: + bool disable_fused_runner_; + bool enable_trt_flash_attention_; + mutable std::unique_ptr fused_fp16_runner_; +}; + +template +class PackedAttention final : public TrtFusedAttention, public CudaKernel { public: PackedAttention(const OpKernelInfo& info); Status ComputeInternal(OpKernelContext* context) const override; @@ -31,15 +45,13 @@ class PackedAttention final : public CudaKernel { const Tensor* relative_position_bias, PackedAttentionParameters& parameters) const; - MHARunner* TryGettingFusedRunner(const PackedAttentionParameters& parameters) const; + int GetNumHeads() const { return num_heads_; } + float GetScale() const { return scale_; } private: - int32_t num_heads_; // number of attention heads + int num_heads_; // number of attention heads + float scale_; // scale for softmax. Default is 0.0f, which will be replaced by 1/sqrt(num_heads) later std::vector qkv_hidden_sizes_; // Q, K, V hidden sizes parsed from the qkv_hidden_sizes attribute. - float scale_; // the scale to be used for softmax - bool disable_fused_runner_; - bool enable_trt_flash_attention_; - mutable std::unique_ptr fused_fp16_runner_; }; } // namespace cuda diff --git a/onnxruntime/contrib_ops/cuda/bert/packed_attention_impl.cu b/onnxruntime/contrib_ops/cuda/bert/packed_attention_impl.cu index ff0900a6b92cd..aba0efdbd7d5f 100644 --- a/onnxruntime/contrib_ops/cuda/bert/packed_attention_impl.cu +++ b/onnxruntime/contrib_ops/cuda/bert/packed_attention_impl.cu @@ -16,6 +16,7 @@ #include "contrib_ops/cuda/transformers/dump_cuda_tensor.h" #include "contrib_ops/cuda/bert/cutlass_fmha/memory_efficient_attention.h" #include "contrib_ops/cuda/bert/rotary_embedding_util.h" +#include "contrib_ops/cuda/bert/flash_attention/flash_api.h" using namespace onnxruntime::cuda; using namespace onnxruntime::contrib::attention_softmax_cuda; @@ -46,29 +47,42 @@ size_t GetAttentionWorkspaceSize( size_t qk_head_size, size_t v_head_size, size_t sequence_length, - void* fused_runner) { + void* fused_runner, + bool use_flash_attention, + bool use_memory_efficient_attention, + bool no_qkv_workspace) { // Note that q, k and v might need alignment for fused attention kernels. - const size_t qkv_bytes = element_size * batch_size * num_heads * sequence_length * (qk_head_size + qk_head_size + v_head_size); + const size_t qkv_bytes = no_qkv_workspace ? 0 : (element_size * batch_size * num_heads * sequence_length * (qk_head_size + qk_head_size + v_head_size)); + +#if USE_FLASH_ATTENTION + // Use portion of workspace for softmax buffer. + if (use_flash_attention) { + size_t flash_buffer_bytes = onnxruntime::flash::get_softmax_lse_size(sequence_length, batch_size, num_heads); + return qkv_bytes + flash_buffer_bytes; + } +#else + ORT_UNUSED_PARAMETER(use_flash_attention); +#endif if (fused_runner != nullptr) { return qkv_bytes; } +#if USE_MEMORY_EFFICIENT_ATTENTION + if (use_memory_efficient_attention) { + size_t fmha_buffer_bytes = 0; + if (MemoryEfficientAttentionParams::need_workspace(v_head_size, element_size == sizeof(float))) { + fmha_buffer_bytes = batch_size * sequence_length * num_heads * v_head_size * sizeof(float); + } + return qkv_bytes + fmha_buffer_bytes; + } +#else + ORT_UNUSED_PARAMETER(use_memory_efficient_attention); +#endif + return qkv_bytes + 2 * GetAttentionScratchSize(element_size, batch_size, num_heads, sequence_length); } -template -__global__ void AddBiasTransposeQKVPacked(const T* input, - const T* biases, - int32_t N, - int32_t H_QK, - int32_t H_V, - T* q, - T* k, - T* v, - const int32_t* token_offset, - int32_t token_count); - // Grid: (S, B) // Block: 256 // For unfused PackedAttention @@ -138,11 +152,11 @@ __global__ void AddBiasTransposeQKVPacked( } } -// Grid: (S, B) +// Grid: (T) // Block: 256 // For memory efficient fMHA from CUTLASS. For future use, doesn't support fMHA from CUTLASS yet. // Input: Tx3xNxH -// Output: 3xBxNxSxH +// Output: 3xTxNxH // T is token_count // B is batch_size // S is sequence_length @@ -152,53 +166,32 @@ template __global__ void AddBiasTransposeQKVPackedCutlass( const T* input, const T* biases, - int32_t N, - int32_t H_QK, - int32_t H_V, + int32_t D_QK, + int32_t D_V, T* q, T* k, T* v, - const int32_t* token_offset, int32_t token_count) { - int s = blockIdx.x; - int b = blockIdx.y; - - int S = gridDim.x; - - const int packing_token_idx = b * S + s; - const int padding_token_idx = token_offset[packing_token_idx]; - b = padding_token_idx / S; - s = padding_token_idx - b % S; + int token_idx = blockIdx.x; - input += packing_token_idx * N * (H_QK + H_QK + H_V); - int k_offset = N * H_QK; - int v_offset = N * H_QK + N * H_QK; - q += (b * S * N + s * N) * H_QK; - k += (b * S * N + s * N) * H_QK; - v += (b * S * N + s * N) * H_V; + input += token_idx * (D_QK + D_QK + D_V); + q += token_idx * D_QK; + k += token_idx * D_QK; + v += token_idx * D_V; - if (packing_token_idx < token_count) { - for (int i = threadIdx.x; i < N * H_QK; i += blockDim.x) { + if (token_idx < token_count) { + for (int i = threadIdx.x; i < D_QK; i += blockDim.x) { q[i] = input[i] + biases[i]; - k[i] = input[i + k_offset] + biases[i + k_offset]; - } - - for (int i = threadIdx.x; i < N * H_V; i += blockDim.x) { - v[i] = input[i + v_offset] + biases[i + v_offset]; - } - } else { - for (int i = threadIdx.x; i < N * H_QK; i += blockDim.x) { - q[i] = biases[i]; - k[i] = biases[i + k_offset]; + k[i] = input[D_QK + i] + biases[D_QK + i]; } - for (int i = threadIdx.x; i < N * H_V; i += blockDim.x) { - v[i] = biases[i + v_offset]; + for (int i = threadIdx.x; i < D_V; i += blockDim.x) { + v[i] = input[D_QK + D_QK + i] + biases[D_QK + D_QK + i]; } } } -// Grid: (S, B) +// Grid: (T) // Block: 256 // For fMHA from TRT // Input: Tx3xNxH @@ -254,18 +247,16 @@ void InvokeAddBiasTranspose( output + 2 * batch_size * sequence_length * num_heads * qk_head_size, token_offset, token_count); - } else if (format == AttentionQkvFormat::Q_K_V_BSNH) { // TODO: add memory efficient support - const dim3 grid(sequence_length, batch_size); + } else if (format == AttentionQkvFormat::Q_K_V_BSNH) { + const dim3 grid(token_count); AddBiasTransposeQKVPackedCutlass<<>>( input, biases, - num_heads, - qk_head_size, - v_head_size, + num_heads * qk_head_size, + num_heads * v_head_size, output, - output + batch_size * sequence_length * num_heads * qk_head_size, - output + 2 * batch_size * sequence_length * num_heads * qk_head_size, - token_offset, + output + token_count * num_heads * qk_head_size, + output + 2 * token_count * num_heads * qk_head_size, token_count); } else { ORT_ENFORCE(format == AttentionQkvFormat::QKV_BSN3H); @@ -381,15 +372,14 @@ Status LaunchTransposeRemovePadding( const int batch_size, const int seq_len, const int number_heads, const int head_size, cudaStream_t stream); - // input: [batch_size, number_heads, seq_len, head_size] - // output: [token_count, number_heads * head_size] +// input: [batch_size, number_heads, seq_len, head_size] +// output: [token_count, number_heads * head_size] template <> Status LaunchTransposeRemovePadding( half* output, const half* input, const int* token_offset, const int token_count, const int batch_size, const int seq_len, const int number_heads, const int head_size, cudaStream_t stream) { - // Make sure memory is aligned to 128 bit ORT_ENFORCE(!(reinterpret_cast(input) & 0xF) && !(reinterpret_cast(output) & 0xF), "alignment"); @@ -460,7 +450,7 @@ Status FusedScaledDotProductAttention( const int qk_head_size = parameters.head_size; const int v_head_size = parameters.v_head_size; void* fused_runner = data.fused_runner; - assert(nullptr != fused_runner); + ORT_RETURN_IF_NOT(nullptr != fused_runner, "fused_runner cannot be NULL"); LaunchAddBiasTranspose(data.gemm_buffer, data.bias, data.workspace, batch_size, sequence_length, @@ -476,6 +466,74 @@ Status FusedScaledDotProductAttention( return Status::OK(); } +#if USE_MEMORY_EFFICIENT_ATTENTION +template +Status FusedScaledDotProductAttentionCutlass( + const cudaDeviceProp& device_prop, + cudaStream_t stream, + PackedAttentionParameters& parameters, + PackedAttentionData& data) { + const int batch_size = parameters.batch_size; + const int sequence_length = parameters.sequence_length; + const int num_heads = parameters.num_heads; + const int qk_head_size = parameters.head_size; + const int v_head_size = parameters.v_head_size; + LaunchAddBiasTranspose(data.gemm_buffer, data.bias, data.workspace, + batch_size, sequence_length, + num_heads, qk_head_size, v_head_size, + AttentionQkvFormat::Q_K_V_BSNH, data.token_offset, + parameters.token_count, stream); + DUMP_TENSOR_INIT(); + + DUMP_TENSOR_D("PackedAttention cutlass data.gemm_buffer", data.gemm_buffer, parameters.token_count, 3, num_heads * qk_head_size); + DUMP_TENSOR_D("PackedAttention cutlass data.bias", data.bias, 1, 3 * num_heads * qk_head_size); + + // Q, K and V pointers + const int model_dimension_qk = num_heads * qk_head_size; + const int model_dimension_v = num_heads * v_head_size; + const size_t elements_qk = static_cast(parameters.token_count) * static_cast(model_dimension_qk); + const size_t elements_v = static_cast(parameters.token_count) * static_cast(model_dimension_v); + T* qkv = data.workspace; + T* query = qkv; + T* key = query + elements_qk; + T* value = key + elements_qk; + T* accum_workspace = value + elements_v; + + DUMP_TENSOR_D("PackedAttention cutlass q(BSNH)", query, parameters.token_count, num_heads * qk_head_size); + DUMP_TENSOR_D("PackedAttention cutlass k(BSNH)", key, parameters.token_count, num_heads * qk_head_size); + DUMP_TENSOR_D("PackedAttention cutlass v(BSNH)", value, parameters.token_count, num_heads * v_head_size); + DUMP_TENSOR_D("PackedAttention cutlass cumulative_sequence_length", data.cumulative_sequence_length, 1, batch_size + 1); + + MemoryEfficientAttentionParams p; + p.sm = device_prop.major * 10 + device_prop.minor; + p.is_half = sizeof(T) == 2; + p.batch_size = parameters.batch_size; + p.num_heads = parameters.num_heads; + p.sequence_length = parameters.sequence_length; + p.kv_sequence_length = parameters.sequence_length; + p.qk_head_size = parameters.head_size; + p.v_head_size = parameters.v_head_size; + p.causal = false; + 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.query = query; + p.key = key; + p.value = value; + p.attn_bias = data.relative_position_bias; + p.is_attn_bias_batched = !parameters.broadcast_res_pos_bias; + p.output = data.output; + p.workspace = MemoryEfficientAttentionParams::need_workspace(v_head_size, sizeof(T) == sizeof(float)) ? accum_workspace : nullptr; + p.stream = stream; + run_memory_efficient_attention(p); + + DUMP_TENSOR("PackedAttention cutlass output", data.output, parameters.token_count, num_heads, v_head_size); + return Status::OK(); +} +#endif + template Status UnfusedScaledDotProductAttention( const cudaDeviceProp& device_prop, @@ -515,8 +573,8 @@ Status UnfusedScaledDotProductAttention( // Q, K and V are ready now DUMP_TENSOR_INIT(); - DUMP_TENSOR_D("gemm_buffer", data.gemm_buffer, parameters.token_count, (num_heads * (qk_head_size * 2 + v_head_size))); - DUMP_TENSOR_D("data.workspace", data.workspace, 3 * batch_size, num_heads, sequence_length, qk_head_size); + DUMP_TENSOR_D("PackedAttention unfused gemm_buffer", data.gemm_buffer, parameters.token_count, (num_heads * (qk_head_size * 2 + v_head_size))); + DUMP_TENSOR_D("PackedAttention unfused data.workspace", data.workspace, 3 * batch_size, num_heads, sequence_length, qk_head_size); // Compute Q*K' (as K'*Q), scaled by 1/sqrt(H) and store in scaled_qk: BxNxSxT // Q: BxNxSxH, K: BxNxSxH, Q*K': BxNxSxS @@ -537,7 +595,7 @@ Status UnfusedScaledDotProductAttention( scaled_qk, sequence_length, sequence_length * sequence_length, batches, device_prop)); - DUMP_TENSOR_D("QK", scaled_qk, batch_size * num_heads, sequence_length, sequence_length); + DUMP_TENSOR_D("PackedAttention unfused QK", scaled_qk, batch_size * num_heads, sequence_length, sequence_length); const size_t bytes = GetAttentionScratchSize(element_size, batch_size, num_heads, sequence_length); @@ -554,7 +612,7 @@ Status UnfusedScaledDotProductAttention( num_heads, attention_score, stream)); - DUMP_TENSOR_D("Softmax", attention_score, batch_size * num_heads, sequence_length, sequence_length); + DUMP_TENSOR_D("PackedAttention unfused Softmax", attention_score, batch_size * num_heads, sequence_length, sequence_length); // compute R*V (as V*R), and store in temp_output (space used by Q): BxNxSxH_v T* temp_output = qkv; @@ -572,7 +630,7 @@ Status UnfusedScaledDotProductAttention( batch_size, sequence_length, num_heads, v_head_size, stream); - DUMP_TENSOR("unfused output", data.output, parameters.token_count, num_heads, v_head_size); + DUMP_TENSOR("PackedAttention unfused output", data.output, parameters.token_count, num_heads, v_head_size); return result; } @@ -586,9 +644,15 @@ Status QkvToContext( void* fused_runner = data.fused_runner; if (nullptr != fused_runner) { return FusedScaledDotProductAttention(device_prop, stream, parameters, data); - } else { - return UnfusedScaledDotProductAttention(device_prop, cublas, stream, parameters, data); } + +#if USE_MEMORY_EFFICIENT_ATTENTION + if (data.use_memory_efficient_attention) { + return FusedScaledDotProductAttentionCutlass(device_prop, stream, parameters, data); + } +#endif + + return UnfusedScaledDotProductAttention(device_prop, cublas, stream, parameters, data); } template Status QkvToContext( @@ -605,6 +669,17 @@ template Status QkvToContext( PackedAttentionParameters& parameters, PackedAttentionData& data); +template Status LaunchTransposeRemovePadding( + float* output, const float* input, + const int* token_offset, const int token_count, + const int batch_size, const int seq_len, const int number_heads, const int head_size, + cudaStream_t stream); + +template Status LaunchTransposeRemovePadding( + half* output, const half* input, + const int* token_offset, const int token_count, + const int batch_size, const int seq_len, const int number_heads, const int head_size, + cudaStream_t stream); } // namespace cuda } // namespace contrib } // 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 1eb26575df394..629ca59c73f16 100644 --- a/onnxruntime/contrib_ops/cuda/bert/packed_attention_impl.h +++ b/onnxruntime/contrib_ops/cuda/bert/packed_attention_impl.h @@ -24,7 +24,10 @@ size_t GetAttentionWorkspaceSize( size_t qk_head_size, size_t v_head_size, size_t sequence_length, - void* fused_runner); + void* fused_runner, + bool use_flash_attention, + bool use_memory_efficient_attention, + bool no_qkv_workspace); template struct PackedAttentionData { @@ -38,6 +41,8 @@ struct PackedAttentionData { T* output; void* fused_runner; + + bool use_memory_efficient_attention; }; template @@ -48,6 +53,13 @@ Status QkvToContext( contrib::PackedAttentionParameters& parameters, PackedAttentionData& data); +template +Status LaunchTransposeRemovePadding( + T* output, const T* input, + const int* token_offset, const int token_count, + const int batch_size, const int seq_len, const int number_heads, const int head_size, + cudaStream_t stream); + } // namespace cuda } // namespace contrib } // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/bert/packed_multihead_attention.cc b/onnxruntime/contrib_ops/cuda/bert/packed_multihead_attention.cc new file mode 100644 index 0000000000000..1b026e64778e3 --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/packed_multihead_attention.cc @@ -0,0 +1,326 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "contrib_ops/cuda/bert/packed_multihead_attention.h" +#include "core/platform/env_var_utils.h" +#include "core/providers/cuda/cuda_common.h" +#include "core/providers/cuda/shared_inc/fpgeneric.h" +#include "contrib_ops/cuda/bert/packed_attention_impl.h" +#include "contrib_ops/cuda/bert/packed_multihead_attention_impl.h" +#include "contrib_ops/cuda/bert/bert_padding.h" +#include "contrib_ops/cuda/bert/cutlass_fmha/memory_efficient_attention.h" +#include "contrib_ops/cuda/bert/flash_attention/flash_api.h" + +using namespace onnxruntime::cuda; +using namespace ::onnxruntime::common; +using namespace ONNX_NAMESPACE; + +namespace onnxruntime { +namespace contrib { +namespace cuda { + +#define REGISTER_KERNEL_TYPED(T) \ + ONNX_OPERATOR_TYPED_KERNEL_EX( \ + PackedMultiHeadAttention, \ + kMSDomain, \ + 1, \ + T, \ + kCudaExecutionProvider, \ + (*KernelDefBuilder::Create()) \ + .TypeConstraint("T", DataTypeImpl::GetTensorType()), \ + PackedMultiHeadAttention); + +REGISTER_KERNEL_TYPED(float) +REGISTER_KERNEL_TYPED(MLFloat16) + +template +PackedMultiHeadAttention::PackedMultiHeadAttention(const OpKernelInfo& info) + : TrtFusedAttention(), 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); + + scale_ = info.GetAttrOrDefault("scale", 0.0f); + +#if USE_FLASH_ATTENTION + disable_flash_attention_ = sizeof(T) != 2 || onnxruntime::ParseEnvironmentVariableWithDefault( + attention::kDisableFlashAttention, false); + min_seq_len_for_flash_attention_packed_qkv_ = ParseEnvironmentVariableWithDefault( + attention::kMinSeqLenForFlashAttentionPackedQKV, + attention::kDefaultMinSeqLenForFlashAttentionPackedQKV); +#else + disable_flash_attention_ = true; + min_seq_len_for_flash_attention_packed_qkv_ = 0; +#endif + +#if USE_MEMORY_EFFICIENT_ATTENTION + disable_memory_efficient_attention_ = onnxruntime::ParseEnvironmentVariableWithDefault( + attention::kDisableMemoryEfficientAttention, false); +#else + disable_memory_efficient_attention_ = true; +#endif +} + +template +Status PackedMultiHeadAttention::CheckInputs(const TensorShape& query_shape, + const Tensor* key, + const Tensor* value, + const Tensor* bias, + const TensorShape& token_offset_shape, + const TensorShape& cu_seq_len_shape, + const Tensor* relative_position_bias, + PackedAttentionParameters& parameters) const { + // Shapes of inputs and output: + // When Q, K and V are not packed: + // Input 'query': (token_count, hidden_size) + // Input 'key': (token_count, hidden_size) + // Input 'value': (token_count, v_hidden_size) + // When Q, K and V are packed: + // Input 'query': (token_count, num_heads, 3, head_size) + // Input 'key': None + // Input 'value': None + // Input 'token_offset': (batch_size, sequence_length) + // Input 'cumulative_sequence_length': (batch_size + 1) + // Input 'relative_position_bias': (batch_size or 1, num_heads, sequence_length, sequence_length) or None + // Output 'output': (token_count, v_hidden_size) + + const auto& query_dims = query_shape.GetDims(); + if (query_dims.size() != 2 && query_dims.size() != 4) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "Input 'query' is expected to have 2 or 4 dimensions in packing mode, got ", + query_dims.size()); + } + int64_t token_count = query_dims[0]; + int64_t hidden_size = (query_dims.size() == 2) ? query_dims[1] : (query_dims[1] * query_dims[3]); + + const auto& token_offset_dims = token_offset_shape.GetDims(); + if (token_offset_dims.size() != 2) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "Input 'token_offset' is expected to have 2 dimensions in packing mode, got ", + token_offset_dims.size()); + } + + int64_t batch_size = token_offset_dims[0]; + int64_t sequence_length = token_offset_dims[1]; + + int64_t v_hidden_size = hidden_size; + if (query_dims.size() == 4) { + if (key != nullptr || value != nullptr) { + return ORT_MAKE_STATUS( + ONNXRUNTIME, INVALID_ARGUMENT, + "Input 'key' and 'value' is expected to be empty when 'query' has 4 dimensions in packing mode"); + } + } else { // query_dims.size() == 2 + if (key == nullptr) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "Input 'key' is expected when 'query' has 2 dimensions in packing mode"); + } + + const auto& key_dims = key->Shape().GetDims(); + if (key_dims.size() != 2) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Input 'key' is expected to have 2 dimension, got ", + key_dims.size()); + } + if (key_dims != query_dims) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Input 'query' and 'key' is expected to have same shape"); + } + + if (value == nullptr) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "Input 'value' is expected when 'query' has 2 dimensions in packing mode"); + } + const auto& value_dims = value->Shape().GetDims(); + if (value_dims.size() != 2) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Input 'value' is expected to have 2 dimensions, got ", + value_dims.size()); + } + if (value_dims[0] != token_count) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "Input 2 dimension 0 should have same length as dimension 0 of input 0"); + } + v_hidden_size = value_dims[1]; + } + + if (bias != nullptr) { + const auto& bias_dims = bias->Shape().GetDims(); + if (bias_dims.size() != 1) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Input 'bias' is expected to have 1 dimension, got ", + bias_dims.size()); + } + + if (bias_dims[0] != hidden_size + hidden_size + v_hidden_size) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Input 'bias' size is expected to be ", + hidden_size + hidden_size + v_hidden_size, ", got ", bias_dims[0]); + } + } + + const auto& cu_seq_len_dims = cu_seq_len_shape.GetDims(); + if (cu_seq_len_dims.size() != 1 || cu_seq_len_dims[0] != batch_size + 1) { + return ORT_MAKE_STATUS( + ONNXRUNTIME, INVALID_ARGUMENT, + "Input 'cumulative_sequence_length' should have 1 dimension with size equal to batch_size + 1"); + } + + // TODO(tianleiwu): move relative position bias shape checker to a helper function. It is shared by multiple ops. + const int num_heads = this->GetNumHeads(); + bool broadcast_res_pos_bias = false; + if (relative_position_bias != nullptr) { + const auto& relative_position_bias_dims = relative_position_bias->Shape().GetDims(); + + if (relative_position_bias_dims.size() != 4) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "Input 'relative_position_bias' is expected to have 4 dimensions, got ", + relative_position_bias_dims.size()); + } + + if (relative_position_bias_dims[0] != batch_size && relative_position_bias_dims[0] != 1) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "Input 'relative_position_bias' dimension 0 should be same as batch_size or 1, got ", + relative_position_bias_dims[0]); + } + if (relative_position_bias_dims[0] == 1 && 1 != batch_size) { + broadcast_res_pos_bias = true; + } + + if (relative_position_bias_dims[1] != num_heads) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "Input 'relative_position_bias' dimension 1 should be same as number of heads, got ", + relative_position_bias_dims[1]); + } + + if (relative_position_bias_dims[2] != sequence_length) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "Input 'relative_position_bias' dimension 2 should be same as sequence_length, got ", + relative_position_bias_dims[2]); + } + + if (relative_position_bias_dims[3] != sequence_length) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "Input 'relative_position_bias' dimension 3 should be same as sequence_length, got ", + relative_position_bias_dims[3]); + } + } + + parameters.batch_size = static_cast(batch_size); + parameters.sequence_length = static_cast(sequence_length); + parameters.input_hidden_size = -1; // not applicable + parameters.hidden_size = static_cast(hidden_size); + parameters.v_hidden_size = static_cast(v_hidden_size); + parameters.head_size = static_cast(hidden_size) / num_heads; + parameters.v_head_size = static_cast(v_hidden_size) / num_heads; + parameters.num_heads = num_heads; + parameters.scale = this->GetScale(); + parameters.token_count = static_cast(token_count); + parameters.has_relative_position_bias = (nullptr != relative_position_bias); + parameters.broadcast_res_pos_bias = broadcast_res_pos_bias; + + return Status::OK(); +} + +template +Status PackedMultiHeadAttention::ComputeInternal(OpKernelContext* context) const { + const Tensor* query = context->Input(0); + const Tensor* key = context->Input(1); + const Tensor* value = context->Input(2); + const Tensor* bias = context->Input(3); + const Tensor* token_offset = context->Input(4); + const Tensor* cumulative_sequence_length = context->Input(5); + const Tensor* relative_position_bias = context->Input(6); + + PackedAttentionParameters parameters; + ORT_RETURN_IF_ERROR(CheckInputs(query->Shape(), + key, + value, + bias, + token_offset->Shape(), + cumulative_sequence_length->Shape(), + relative_position_bias, + parameters)); + + TensorShapeVector output_shape{parameters.token_count, parameters.v_hidden_size}; + Tensor* output = context->Output(0, output_shape); + + auto& device_prop = this->GetDeviceProp(); + + bool use_flash_attention = false; +#if USE_FLASH_ATTENTION + if (!disable_flash_attention_) { + use_flash_attention = !parameters.has_relative_position_bias && + 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 when sequence length <= 512. + if (use_flash_attention && key == nullptr && value == nullptr && + parameters.sequence_length < min_seq_len_for_flash_attention_packed_qkv_) { + use_flash_attention = false; + } + } +#endif + + MHARunner* fused_runner = use_flash_attention ? nullptr : this->GetFusedRunner(device_prop, parameters); + + bool use_memory_efficient_attention = false; + +#if USE_MEMORY_EFFICIENT_ATTENTION + if (!use_flash_attention && nullptr == fused_runner && !disable_memory_efficient_attention_) { + int sm = device_prop.major * 10 + device_prop.minor; + bool is_good_for_rpb = !parameters.has_relative_position_bias || parameters.sequence_length % (4 * sizeof(T)) == 0; + use_memory_efficient_attention = + is_good_for_rpb && + (sizeof(T) == 2 || parameters.sequence_length >= attention::kMinSeqLenForMemoryEfficientAttentionFp32) && + (parameters.head_size & 7) == 0 && + (parameters.v_head_size & 7) == 0 && + has_memory_efficient_attention(sm, sizeof(T) == 2); + } +#endif + + typedef typename ToCudaType::MappedType CudaT; + + cublasHandle_t cublas = this->GetCublasHandle(context); + + constexpr size_t element_size = sizeof(T); + // When the source and target format is same (like TN3H => TN3H, or TNH => TNH) and no bias, need not transpose qkv. + const bool no_qkv_workspace = (fused_runner != nullptr && key == nullptr && bias == nullptr) || + ((use_memory_efficient_attention || use_flash_attention) && + value != nullptr && + bias == nullptr); + size_t workSpaceSize = GetAttentionWorkspaceSize(element_size, + parameters.batch_size, + parameters.num_heads, + parameters.head_size, + parameters.v_head_size, + parameters.sequence_length, + fused_runner, + use_flash_attention, + use_memory_efficient_attention, + no_qkv_workspace); + auto work_space = this->GetScratchBuffer(workSpaceSize, context->GetComputeStream()); + + typedef typename ToCudaType::MappedType CudaT; + PackedMultiHeadAttentionData data; + data.query = reinterpret_cast(query->Data()); + data.key = (key == nullptr) ? nullptr : reinterpret_cast(key->Data()); + data.value = (value == nullptr) ? nullptr : reinterpret_cast(value->Data()); + data.bias = (bias == nullptr) ? nullptr : reinterpret_cast(bias->Data()); + data.relative_position_bias = (nullptr == relative_position_bias) + ? nullptr + : reinterpret_cast(relative_position_bias->Data()); + data.workspace = reinterpret_cast(work_space.get()); + data.token_offset = token_offset->Data(); + data.cumulative_sequence_length = cumulative_sequence_length->Data(); + data.output = reinterpret_cast(output->MutableData()); + data.fused_runner = reinterpret_cast(fused_runner); + data.use_flash_attention = use_flash_attention; + data.use_memory_efficient_attention = use_memory_efficient_attention; + data.no_qkv_workspace = no_qkv_workspace; + data.source_qkv_format = (key == nullptr) ? AttentionQkvFormat::QKV_TN3H : AttentionQkvFormat::Q_K_V_TNH; + + return QkvToContext(device_prop, cublas, this->Stream(context), parameters, data); +} + +} // namespace cuda +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/bert/packed_multihead_attention.h b/onnxruntime/contrib_ops/cuda/bert/packed_multihead_attention.h new file mode 100644 index 0000000000000..e30c603dc30aa --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/packed_multihead_attention.h @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "contrib_ops/cuda/bert/packed_attention.h" + +namespace onnxruntime { +namespace contrib { +namespace cuda { + +template +class PackedMultiHeadAttention final : public TrtFusedAttention, public CudaKernel { + public: + PackedMultiHeadAttention(const OpKernelInfo& info); + Status ComputeInternal(OpKernelContext* context) const override; + + private: + Status CheckInputs(const TensorShape& query_shape, + const Tensor* key, + const Tensor* value, + const Tensor* bias, + const TensorShape& token_offset_shape, + const TensorShape& cu_seq_len_shape, + const Tensor* relative_position_bias, + PackedAttentionParameters& parameters) const; + int GetNumHeads() const { return num_heads_; } + float GetScale() const { return scale_; } + + int num_heads_; // number of attention heads + float scale_; // the scale for softmax in memory efficient attention or unfused attention. + + bool disable_memory_efficient_attention_; + bool disable_flash_attention_; + int min_seq_len_for_flash_attention_packed_qkv_; +}; + +} // namespace cuda +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/bert/packed_multihead_attention_impl.cu b/onnxruntime/contrib_ops/cuda/bert/packed_multihead_attention_impl.cu new file mode 100644 index 0000000000000..e09fd9e6b36e5 --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/packed_multihead_attention_impl.cu @@ -0,0 +1,863 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include +#include +#include +#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/packed_attention_impl.h" +#include "contrib_ops/cuda/bert/packed_multihead_attention_impl.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 "contrib_ops/cuda/bert/bert_padding.h" +#include "contrib_ops/cuda/transformers/dump_cuda_tensor.h" +#include "contrib_ops/cuda/bert/cutlass_fmha/memory_efficient_attention.h" +#include "contrib_ops/cuda/bert/rotary_embedding_util.h" +#include "contrib_ops/cuda/bert/flash_attention/flash_api.h" + +using namespace onnxruntime::cuda; +using namespace onnxruntime::contrib::attention_softmax_cuda; + +#define CHECK_CUDA(expr) CUDA_RETURN_IF_ERROR(expr) + +namespace onnxruntime { +namespace contrib { +namespace cuda { + +static constexpr int32_t kMAX_THREADS_PER_BLOCK = 256; + +#define ADD_BIAS(value, bias_value) (biases == nullptr) ? value : (value + bias_value) +#define GET_BIAS(bias_value) (biases == nullptr) ? T{} : bias_value + +// Grid: (S, B) +// Block: 256 +// For unfused PackedMultiHeadAttention +// Inputs (query, key, value): TxNxH +// Output: 3xBxNxSxH +// Where: +// T is token_count +// B is batch_size +// S is sequence_length +// N is num_heads +// H is head_size +template +__global__ void TransposeQKV_TNH_3BNSH( + const T* query, + const T* key, + const T* value, + const T* biases, + int32_t N, + int32_t H_QK, + int32_t H_V, + T* q, + T* k, + T* v, + const int32_t* token_offset, + int32_t token_count) { + int s = blockIdx.x; + int b = blockIdx.y; + + int S = gridDim.x; + + const int packing_token_idx = b * S + s; + const int padding_token_idx = token_offset[packing_token_idx]; + b = padding_token_idx / S; + s = padding_token_idx % S; + + const int D_QK = N * H_QK; + const int D_V = N * H_V; + query += packing_token_idx * D_QK; + key += packing_token_idx * D_QK; + value += packing_token_idx * D_V; + + int k_offset = D_QK; + int v_offset = D_QK + D_QK; + q += (b * N * S + s) * H_QK; + k += (b * N * S + s) * H_QK; + v += (b * N * S + s) * H_V; + + if (packing_token_idx < token_count) { + for (int i = threadIdx.x; i < D_QK; i += blockDim.x) { + int h = i % H_QK; + int n = i / H_QK; + q[n * S * H_QK + h] = ADD_BIAS(query[i], biases[i]); + k[n * S * H_QK + h] = ADD_BIAS(key[i], biases[i + k_offset]); + } + + for (int i = threadIdx.x; i < D_V; i += blockDim.x) { + int h = i % H_V; + int n = i / H_V; + v[n * S * H_V + h] = ADD_BIAS(value[i], biases[i + v_offset]); + } + } else { + for (int i = threadIdx.x; i < D_QK; i += blockDim.x) { + int h = i % H_QK; + int n = i / H_QK; + q[n * S * H_QK + h] = GET_BIAS(biases[i]); + k[n * S * H_QK + h] = GET_BIAS(biases[i + k_offset]); + } + + for (int i = threadIdx.x; i < D_V; i += blockDim.x) { + int h = i % H_V; + int n = i / H_V; + v[n * S * H_V + h] = GET_BIAS(biases[i + v_offset]); + } + } +} + +// Grid: (T) +// Block: 256 +// For memory efficient fMHA from CUTLASS. +// query, key, value: TxNxH +// q, k, v: TxNxH +// T is token_count +// B is batch_size +// S is sequence_length +// N is num_heads +// H is head_size +template +__global__ void TransposeQKV_TNH_3TNH( + const T* query, + const T* key, + const T* value, + const T* biases, + int32_t N, + int32_t H_QK, + int32_t H_V, + T* q, + T* k, + T* v, + int32_t token_count) { + int token_idx = blockIdx.x; + + const int D_QK = N * H_QK; + const int D_V = N * H_V; + + query += token_idx * D_QK; + key += token_idx * D_QK; + value += token_idx * D_V; + + q += token_idx * D_QK; + k += token_idx * D_QK; + v += token_idx * D_V; + + if (token_idx < token_count) { + for (int i = threadIdx.x; i < D_QK; i += blockDim.x) { + q[i] = ADD_BIAS(query[i], biases[i]); + k[i] = ADD_BIAS(key[i], biases[D_QK + i]); + } + + for (int i = threadIdx.x; i < D_V; i += blockDim.x) { + v[i] = ADD_BIAS(value[i], biases[D_QK + D_QK + i]); + } + } +} + +// Grid: (T) +// Block: 256 +// For Trt fused attention. +// Inputs (query, key, value): TxNxH +// Output: TxNx3xH +// T is token_count +// B is batch_size +// S is sequence_length +// N is num_heads +// H is head_size +template +__global__ void TransposeQKV_TNH_TN3H( + const T* query, + const T* key, + const T* value, + const T* biases, + int32_t N, + int32_t H_QK, + int32_t H_V, + T* output, + int32_t token_count) { + int token_idx = blockIdx.x; + + const int D_QK = N * H_QK; + const int D_V = N * H_V; + query += token_idx * D_QK; + key += token_idx * D_QK; + value += token_idx * D_V; + output += token_idx * (D_QK + D_QK + D_V); + + if (token_idx < token_count) { + for (int i = threadIdx.x; i < D_QK; i += blockDim.x) { + int n = i / H_QK; + int h = i % H_QK; + + int index = n * (H_QK + H_QK + H_V) + h; + output[index] = ADD_BIAS(query[i], biases[i]); + + index = n * (H_QK + H_QK + H_V) + H_QK + h; + output[index] = ADD_BIAS(key[i], biases[D_QK + i]); + } + + for (int i = threadIdx.x; i < D_V; i += blockDim.x) { + int n = i / H_V; + int h = i % H_V; + int index = n * (H_QK + H_QK + H_V) + H_QK + H_QK + h; + output[index] = ADD_BIAS(value[i], biases[D_QK + D_QK + i]); + } + } +} + +// Grid: (S, B) +// Block: 256 +// For unfused PackedMultiHeadAttention +// Input: TxNx3xH +// Output: 3xBxNxSxH +// Where: +// T is token_count +// B is batch_size +// S is sequence_length +// N is num_heads +// H is head_size +template +__global__ void TransposeQKV_TN3H_3BNSH( + const T* input, // packed qkv + const T* biases, + int32_t N, + int32_t H_QK, + int32_t H_V, + T* q, + T* k, + T* v, + const int32_t* token_offset, + int32_t token_count) { + int s = blockIdx.x; + int b = blockIdx.y; + + int S = gridDim.x; + + const int packing_token_idx = b * S + s; + const int padding_token_idx = token_offset[packing_token_idx]; + b = padding_token_idx / S; + s = padding_token_idx % S; + + int Hx3 = (H_QK + H_QK + H_V); + + input += packing_token_idx * N * Hx3; + int k_offset = H_QK; + int v_offset = H_QK + H_QK; + q += (b * N * S + s) * H_QK; + k += (b * N * S + s) * H_QK; + v += (b * N * S + s) * H_V; + + if (packing_token_idx < token_count) { + for (int i = threadIdx.x; i < N * Hx3; i += blockDim.x) { + int n = i / Hx3; + int h = i % Hx3; + + if (h < k_offset) { + q[n * S * H_QK + h] = ADD_BIAS(input[i], biases[n * H_QK + h]); + } else if (h < v_offset) { + k[n * S * H_QK + (h - k_offset)] = ADD_BIAS(input[i], biases[(N + n) * H_QK + (h - H_QK)]); + } else { + v[n * S * H_V + (h - v_offset)] = ADD_BIAS(input[i], biases[(N + N) * H_QK + n * H_V + (h - H_QK - H_QK)]); + } + } + } else { + for (int i = threadIdx.x; i < N * Hx3; i += blockDim.x) { + int n = i / Hx3; + int h = i % Hx3; + + if (h < k_offset) { + q[n * S * H_QK + h] = GET_BIAS(biases[n * H_QK + h]); + } else if (h < v_offset) { + k[n * S * H_QK + (h - k_offset)] = GET_BIAS(biases[(N + n) * H_QK + (h - H_QK)]); + } else { + v[n * S * H_V + (h - v_offset)] = GET_BIAS(biases[(N + N) * H_QK + n * H_V + (h - H_QK - H_QK)]); + } + } + } +} + +// TODO: merge TransposeQKV_TN3H_3TNH with AddBiasTransposeQKVPackedCutlass + +// Grid: (T) +// Block: 256 +// For memory efficient fMHA from CUTLASS. +// Input: TxNx3xH +// Output: 3xTxNxH +// T is token_count +// B is batch_size +// S is sequence_length +// N is num_heads +// H is head_size +template +__global__ void TransposeQKV_TN3H_3TNH( + const T* input, + const T* biases, + int32_t N, + int32_t H_QK, + int32_t H_V, + T* q, + T* k, + T* v, + int32_t token_count) { + int token_idx = blockIdx.x; + + const int D_QK = N * H_QK; + const int D_V = N * H_V; + + input += token_idx * (D_QK + D_QK + D_V); + q += token_idx * D_QK; + k += token_idx * D_QK; + v += token_idx * D_V; + + if (token_idx < token_count) { + for (int i = threadIdx.x; i < D_QK; i += blockDim.x) { + int n = i / H_QK; + int h = i % H_QK; + q[i] = ADD_BIAS(input[n * (H_QK + H_QK + H_V) + h], biases[i]); + k[i] = ADD_BIAS(input[n * (H_QK + H_QK + H_V) + H_QK + h], biases[D_QK + i]); + } + + for (int i = threadIdx.x; i < N * H_V; i += blockDim.x) { + int n = i / H_V; + int h = i % H_V; + v[i] = ADD_BIAS(input[n * (H_QK + H_QK + H_V) + H_QK + H_QK + h], biases[D_QK + D_QK + i]); + } + } +} + +// Grid: (T) +// Block: 256 +// For TRT fused attention. +// Input: TxNx3xH +// Output: TxNx3xH +// T is token_count +// B is batch_size +// S is sequence_length +// N is num_heads +// H is head_size +template +__global__ void AddBias_TN3H_TN3H( + const T* input, + const T* biases, + int32_t N, + int32_t H_QK, + int32_t H_V, + T* output, + int32_t token_count) { + int token_idx = blockIdx.x; + + const int D_QK = N * H_QK; + const int D_V = N * H_V; + + input += token_idx * (D_QK + D_QK + D_V); + output += token_idx * (D_QK + D_QK + D_V); + + if (token_idx < token_count) { + for (int i = threadIdx.x; i < D_QK; i += blockDim.x) { + int n = i / H_QK; + int h = i % H_QK; + + int index = n * (H_QK + H_QK + H_V) + h; + output[index] = ADD_BIAS(input[index], biases[i]); + + index = n * (H_QK + H_QK + H_V) + H_QK + h; + output[index] = ADD_BIAS(input[index], biases[D_QK + i]); + } + + for (int i = threadIdx.x; i < D_V; i += blockDim.x) { + int n = i / H_V; + int h = i % H_V; + int index = n * (H_QK + H_QK + H_V) + H_QK + H_QK + h; + output[index] = ADD_BIAS(input[index], biases[D_QK + D_QK + i]); + } + } +} + +template +void InvokeTranspose( + const T* query, const T* key, const T* value, const T* bias, T* output, + const int batch_size, const int sequence_length, + const int num_heads, const int qk_head_size, const int v_head_size, + AttentionQkvFormat source_format, AttentionQkvFormat target_format, + const int32_t* token_offset, int32_t token_count, + cudaStream_t stream) { + if (key != nullptr && value != nullptr) { + assert(source_format == AttentionQkvFormat::Q_K_V_TNH); + + if (target_format == AttentionQkvFormat::Q_K_V_BNSH) { + const dim3 grid(sequence_length, batch_size); + TransposeQKV_TNH_3BNSH<<>>( + query, + key, + value, + bias, + num_heads, + qk_head_size, + v_head_size, + output, + output + batch_size * sequence_length * num_heads * qk_head_size, + output + 2 * batch_size * sequence_length * num_heads * qk_head_size, + token_offset, + token_count); + } else if (target_format == AttentionQkvFormat::Q_K_V_TNH) { + const dim3 grid(token_count); + TransposeQKV_TNH_3TNH<<>>( + query, + key, + value, + bias, + num_heads, + qk_head_size, + v_head_size, + output, + output + token_count * num_heads * qk_head_size, + output + 2 * token_count * num_heads * qk_head_size, + token_count); + } else { + assert(target_format == AttentionQkvFormat::QKV_TN3H); + const dim3 grid(token_count); + TransposeQKV_TNH_TN3H<<>>( + query, + key, + value, + bias, + num_heads, + qk_head_size, + v_head_size, + output, + token_count); + } + + } else { + assert(key == nullptr && value == nullptr); + assert(source_format == AttentionQkvFormat::QKV_TN3H); + if (target_format == AttentionQkvFormat::Q_K_V_BNSH) { + const dim3 grid(sequence_length, batch_size); + TransposeQKV_TN3H_3BNSH<<>>( + query, + bias, + num_heads, + qk_head_size, + v_head_size, + output, + output + batch_size * sequence_length * num_heads * qk_head_size, + output + 2 * batch_size * sequence_length * num_heads * qk_head_size, + token_offset, + token_count); + } else if (target_format == AttentionQkvFormat::Q_K_V_TNH) { + const dim3 grid(token_count); + TransposeQKV_TN3H_3TNH<<>>( + query, + bias, + num_heads, + qk_head_size, + v_head_size, + output, + output + token_count * num_heads * qk_head_size, + output + 2 * token_count * num_heads * qk_head_size, + token_count); + } else { + assert(target_format == AttentionQkvFormat::QKV_TN3H); + assert(bias != nullptr); + const dim3 grid(token_count); + AddBias_TN3H_TN3H<<>>( + query, + bias, + num_heads, + qk_head_size, + v_head_size, + output, + token_count); + } + } +} + +template +struct T4; + +template <> +struct T4 { + using Type = float4; +}; + +template <> +struct T4 { + using Type = Half4; +}; + +template +struct T2; + +template <> +struct T2 { + using Type = float2; +}; + +template <> +struct T2 { + using Type = half2; +}; + +template +void LaunchTranspose( + const T* query, const T* key, const T* value, const T* bias, T* output, + const int batch_size, const int sequence_length, + const int num_heads, const int qk_head_size, const int v_head_size, + AttentionQkvFormat source_format, AttentionQkvFormat target_format, + const int32_t* token_offset, int32_t token_count, + cudaStream_t stream) { + if (0 == (qk_head_size & 3) && 0 == (v_head_size & 3)) { + using T4Type = typename T4::Type; + const int H = qk_head_size / 4; + const int H_v = v_head_size / 4; + const T4Type* query2 = reinterpret_cast(query); + const T4Type* key2 = reinterpret_cast(key); + const T4Type* value2 = reinterpret_cast(value); + const T4Type* bias2 = reinterpret_cast(bias); + T4Type* output2 = reinterpret_cast(output); + InvokeTranspose( + query2, key2, value2, bias2, output2, + batch_size, sequence_length, + num_heads, H, H_v, + source_format, target_format, + token_offset, token_count, stream); + } else if (0 == (qk_head_size & 1) && 0 == (v_head_size & 1)) { + using T2Type = typename T2::Type; + const int H = qk_head_size / 2; + const int H_v = v_head_size / 2; + const T2Type* query2 = reinterpret_cast(query); + const T2Type* key2 = reinterpret_cast(key); + const T2Type* value2 = reinterpret_cast(value); + const T2Type* bias2 = reinterpret_cast(bias); + T2Type* output2 = reinterpret_cast(output); + InvokeTranspose( + query2, key2, value2, bias2, output2, + batch_size, sequence_length, + num_heads, H, H_v, + source_format, target_format, + token_offset, token_count, stream); + } else { + InvokeTranspose( + query, key, value, bias, output, + batch_size, sequence_length, + num_heads, qk_head_size, v_head_size, + source_format, target_format, + token_offset, token_count, stream); + } +} + +template +Status FusedAttentionTrt( + const cudaDeviceProp& device_prop, + cudaStream_t stream, + PackedAttentionParameters& parameters, + PackedMultiHeadAttentionData& data) { + const int batch_size = parameters.batch_size; + const int sequence_length = parameters.sequence_length; + const int num_heads = parameters.num_heads; + const int qk_head_size = parameters.head_size; + const int v_head_size = parameters.v_head_size; + void* fused_runner = data.fused_runner; + ORT_RETURN_IF_NOT(nullptr != fused_runner, "fused_runner cannot be NULL"); + + // When packed QKV is used, we can directly pass it to fused runner. Otherwise, we need transpose to BSN3H format. + const T* qkv = data.query; + if (!data.no_qkv_workspace) { + LaunchTranspose(data.query, data.key, data.value, data.bias, data.workspace, + batch_size, sequence_length, + num_heads, qk_head_size, v_head_size, + data.source_qkv_format, AttentionQkvFormat::QKV_TN3H, + data.token_offset, parameters.token_count, stream); + qkv = data.workspace; + } + + FusedMHARunnerFP16v2* fused_fp16_runner = reinterpret_cast(fused_runner); + const int S = fused_fp16_runner->getSFromMaxSeqLen(sequence_length); + fused_fp16_runner->setup(S, batch_size); + + fused_fp16_runner->run(qkv, data.cumulative_sequence_length, data.output, stream); + return Status::OK(); +} + +#if USE_FLASH_ATTENTION +template +Status FlashAttention( + const cudaDeviceProp& device_prop, + cudaStream_t stream, + PackedAttentionParameters& parameters, + PackedMultiHeadAttentionData& data) { + const int batch_size = parameters.batch_size; + const int sequence_length = parameters.sequence_length; + const int num_heads = parameters.num_heads; + const int qk_head_size = parameters.head_size; + const int v_head_size = parameters.v_head_size; + + // Q, K and V pointers + const int model_dimension_qk = num_heads * qk_head_size; + const int model_dimension_v = num_heads * v_head_size; + const size_t elements_qk = static_cast(parameters.token_count) * static_cast(model_dimension_qk); + const size_t elements_v = static_cast(parameters.token_count) * static_cast(model_dimension_v); + + // When separated Q, K, V is used, we can directly use them in Cutlass FMHA. Otherwise, transpose BSN3H to 3BSNH + if (!data.no_qkv_workspace) { + LaunchTranspose(data.query, data.key, data.value, data.bias, data.workspace, + batch_size, sequence_length, + num_heads, qk_head_size, v_head_size, + data.source_qkv_format, AttentionQkvFormat::Q_K_V_TNH, + data.token_offset, parameters.token_count, stream); + } + + float scale = parameters.scale == 0.0f ? 1.f / sqrt(static_cast(qk_head_size)) + : parameters.scale; + int32_t* cu_seqlens_q = const_cast(data.cumulative_sequence_length); + int32_t* cu_seqlens_k = const_cast(data.cumulative_sequence_length); + const void* query = data.no_qkv_workspace ? data.query : data.workspace; + const void* key = data.no_qkv_workspace ? data.key : (data.workspace + elements_qk); + const void* value = data.no_qkv_workspace ? data.value : (data.workspace + elements_qk + elements_qk); + void* softmax_lse_buffer = data.no_qkv_workspace + ? data.workspace + : (data.workspace + elements_qk + elements_qk + elements_v); + + ORT_RETURN_IF_ERROR( + onnxruntime::flash::mha_varlen_fwd( + device_prop, + stream, + const_cast(query), + const_cast(key), + const_cast(value), + data.output, + cu_seqlens_q, + cu_seqlens_k, + softmax_lse_buffer, + batch_size, + num_heads, + num_heads, // num_heads_k + qk_head_size, + sequence_length, + sequence_length, + scale, + false // is causal + )); + + DUMP_TENSOR_INIT(); + DUMP_TENSOR_D("q(BSNH)", reinterpret_cast(query), parameters.token_count, num_heads, qk_head_size); + DUMP_TENSOR_D("k(BSNH)", reinterpret_cast(key), parameters.token_count, num_heads, qk_head_size); + DUMP_TENSOR_D("v(BSNH)", reinterpret_cast(value), parameters.token_count, num_heads, v_head_size); + DUMP_TENSOR_D("cumulative_sequence_length", data.cumulative_sequence_length, 1, batch_size + 1); + DUMP_TENSOR("PackedMHA flash output", data.output, parameters.token_count, num_heads, v_head_size); + + return Status::OK(); +} +#endif + +#if USE_MEMORY_EFFICIENT_ATTENTION +template +Status FusedAttentionCutlass( + const cudaDeviceProp& device_prop, + cudaStream_t stream, + PackedAttentionParameters& parameters, + PackedMultiHeadAttentionData& data) { + const int batch_size = parameters.batch_size; + const int sequence_length = parameters.sequence_length; + const int num_heads = parameters.num_heads; + const int qk_head_size = parameters.head_size; + const int v_head_size = parameters.v_head_size; + + // Q, K and V pointers + const int model_dimension_qk = num_heads * qk_head_size; + const int model_dimension_v = num_heads * v_head_size; + const size_t elements_qk = static_cast(parameters.token_count) * static_cast(model_dimension_qk); + const size_t elements_v = static_cast(parameters.token_count) * static_cast(model_dimension_v); + + // When separated Q, K, V is used, we can directly use them in Cutlass FMHA. Otherwise, transpose BSN3H to 3BSNH + if (!data.no_qkv_workspace) { + LaunchTranspose(data.query, data.key, data.value, data.bias, data.workspace, + batch_size, sequence_length, + num_heads, qk_head_size, v_head_size, + data.source_qkv_format, AttentionQkvFormat::Q_K_V_TNH, + data.token_offset, parameters.token_count, stream); + } + + MemoryEfficientAttentionParams p; + p.sm = device_prop.major * 10 + device_prop.minor; + p.is_half = sizeof(T) == 2; + p.batch_size = parameters.batch_size; + p.num_heads = parameters.num_heads; + p.sequence_length = parameters.sequence_length; + p.kv_sequence_length = parameters.sequence_length; + p.qk_head_size = parameters.head_size; + p.v_head_size = parameters.v_head_size; + p.causal = false; + 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.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); + p.attn_bias = data.relative_position_bias; + p.is_attn_bias_batched = !parameters.broadcast_res_pos_bias; + p.output = data.output; + p.workspace = MemoryEfficientAttentionParams::need_workspace(v_head_size, sizeof(T) == sizeof(float)) + ? (data.workspace + (data.no_qkv_workspace ? 0 : (elements_qk + elements_qk + elements_v))) + : nullptr; + p.stream = stream; + run_memory_efficient_attention(p); + + DUMP_TENSOR_INIT(); + DUMP_TENSOR_D("q(BSNH)", reinterpret_cast(p.query), parameters.token_count, num_heads, qk_head_size); + DUMP_TENSOR_D("k(BSNH)", reinterpret_cast(p.key), parameters.token_count, num_heads, qk_head_size); + DUMP_TENSOR_D("v(BSNH)", reinterpret_cast(p.value), parameters.token_count, num_heads, v_head_size); + DUMP_TENSOR_D("cumulative_sequence_length", data.cumulative_sequence_length, 1, batch_size + 1); + DUMP_TENSOR("PackedMHA cutlass output", data.output, parameters.token_count, num_heads, v_head_size); + + return Status::OK(); +} +#endif + +template +Status UnfusedAttention( + const cudaDeviceProp& device_prop, + cublasHandle_t& cublas, + cudaStream_t stream, + PackedAttentionParameters& parameters, + PackedMultiHeadAttentionData& data) { + constexpr size_t element_size = sizeof(T); + const int batch_size = parameters.batch_size; + const int sequence_length = parameters.sequence_length; + const int num_heads = parameters.num_heads; + const int qk_head_size = parameters.head_size; + const int v_head_size = parameters.v_head_size; + + const int batches = batch_size * num_heads; + const int size_per_batch_q = sequence_length * qk_head_size; + const int size_per_batch_k = sequence_length * qk_head_size; + const int size_per_batch_v = sequence_length * v_head_size; + const size_t elements_q = static_cast(batches) * static_cast(size_per_batch_q); + const size_t elements_k = static_cast(batches) * static_cast(size_per_batch_k); + const size_t elements_v = static_cast(batches) * static_cast(size_per_batch_v); + + // Q, K and V pointers when fused attention is not used + LaunchTranspose(data.query, data.key, data.value, data.bias, data.workspace, + batch_size, sequence_length, + num_heads, qk_head_size, v_head_size, + data.source_qkv_format, AttentionQkvFormat::Q_K_V_BNSH, + data.token_offset, parameters.token_count, stream); + + T* qkv = data.workspace; + T* q = qkv; + T* k = q + elements_q; + T* v = k + elements_k; + T* scaled_qk = qkv + elements_q + elements_k + elements_v; + + // Compute Q*K' (as K'*Q), scaled by 1/sqrt(H) and store in scaled_qk: BxNxSxT + // Q: BxNxSxH, K: BxNxSxH, Q*K': BxNxSxS + float one = 1.0f; + float zero = 0.f; + float scale = parameters.scale == 0.0f ? 1.f / sqrt(static_cast(qk_head_size)) + : parameters.scale; + + cublasSetStream(cublas, stream); + + CUBLAS_RETURN_IF_ERROR(cublasGemmStridedBatchedHelper( + cublas, CUBLAS_OP_T, CUBLAS_OP_N, + sequence_length, sequence_length, qk_head_size, + &scale, + k, qk_head_size, sequence_length * qk_head_size, + q, qk_head_size, sequence_length * qk_head_size, + &zero, + scaled_qk, sequence_length, sequence_length * sequence_length, + batches, device_prop)); + + // Q, K and V are ready now + DUMP_TENSOR_INIT(); + DUMP_TENSOR_D("q (BNSH)", q, batch_size, num_heads, sequence_length, qk_head_size); + DUMP_TENSOR_D("k (BNSH)", k, batch_size, num_heads, sequence_length, qk_head_size); + DUMP_TENSOR_D("v (BNSH)", v, batch_size, num_heads, sequence_length, v_head_size); + DUMP_TENSOR_D("QK", scaled_qk, batch_size, num_heads, sequence_length, sequence_length); + + const size_t bytes = GetAttentionScratchSize(element_size, batch_size, num_heads, + sequence_length); + T* attention_score = scaled_qk + (bytes / element_size); + + // Apply softmax and store result R to attention_score: BxNxSxS + ORT_RETURN_IF_ERROR(ComputeSoftmaxWithCumSeqLength( + scaled_qk, + data.relative_position_bias, + parameters.broadcast_res_pos_bias, + data.cumulative_sequence_length, + batch_size, + sequence_length, + num_heads, + attention_score, stream)); + + DUMP_TENSOR_D("Softmax", attention_score, batch_size, num_heads, sequence_length, sequence_length); + + // compute R*V (as V*R), and store in temp_output (space used by Q): BxNxSxH_v + T* temp_output = qkv; + CUBLAS_RETURN_IF_ERROR(cublasGemmStridedBatchedHelper( + cublas, CUBLAS_OP_N, CUBLAS_OP_N, + v_head_size, sequence_length, sequence_length, + &one, v, v_head_size, sequence_length * v_head_size, + attention_score, sequence_length, sequence_length * sequence_length, + &zero, temp_output, v_head_size, sequence_length * v_head_size, batches, device_prop)); + + // Temp_output is BxNxSxH_v, transpose and remove padding to output TxNxH_v + Status result = LaunchTransposeRemovePadding( + data.output, temp_output, + data.token_offset, parameters.token_count, + batch_size, sequence_length, num_heads, v_head_size, + stream); + + DUMP_TENSOR("PackedMHA unfused output", data.output, parameters.token_count, num_heads, v_head_size); + return result; +} + +template +Status QkvToContext( + const cudaDeviceProp& device_prop, + cublasHandle_t& cublas, + cudaStream_t stream, + PackedAttentionParameters& parameters, + PackedMultiHeadAttentionData& data) { + void* fused_runner = data.fused_runner; + if (nullptr != fused_runner) { + return FusedAttentionTrt(device_prop, stream, parameters, data); + } + +#if USE_FLASH_ATTENTION + if (data.use_flash_attention) { + return FlashAttention(device_prop, stream, parameters, data); + } +#endif + +#if USE_MEMORY_EFFICIENT_ATTENTION + if (data.use_memory_efficient_attention) { + return FusedAttentionCutlass(device_prop, stream, parameters, data); + } +#endif + + return UnfusedAttention(device_prop, cublas, stream, parameters, data); +} + +template Status QkvToContext( + const cudaDeviceProp& device_prop, + cublasHandle_t& cublas, + cudaStream_t stream, + PackedAttentionParameters& parameters, + PackedMultiHeadAttentionData& data); + +template Status QkvToContext( + const cudaDeviceProp& device_prop, + cublasHandle_t& cublas, + cudaStream_t stream, + PackedAttentionParameters& parameters, + PackedMultiHeadAttentionData& data); + +} // namespace cuda +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/bert/packed_multihead_attention_impl.h b/onnxruntime/contrib_ops/cuda/bert/packed_multihead_attention_impl.h new file mode 100644 index 0000000000000..eeca72f16e64e --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/packed_multihead_attention_impl.h @@ -0,0 +1,46 @@ +// 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 +#include "contrib_ops/cpu/bert/attention_common.h" + +namespace onnxruntime { +namespace contrib { +namespace cuda { + +template +struct PackedMultiHeadAttentionData { + const T* query; + const T* key; + const T* value; + const T* bias; + const T* relative_position_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, + cublasHandle_t& cublas, + cudaStream_t stream, + contrib::PackedAttentionParameters& parameters, + PackedMultiHeadAttentionData& data); + +} // namespace cuda +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/bert/relative_attn_bias.cc b/onnxruntime/contrib_ops/cuda/bert/relative_attn_bias.cc index ceae4d511a642..92ba808dd85c2 100644 --- a/onnxruntime/contrib_ops/cuda/bert/relative_attn_bias.cc +++ b/onnxruntime/contrib_ops/cuda/bert/relative_attn_bias.cc @@ -66,7 +66,7 @@ Status RelPosAttnBias::ComputeInternal(OpKernelContext* context) const { const int64_t key_len = *key_length->Data(); if (query_len != key_len) { - ORT_THROW("Relatvie position bias currently only support query length equal to key length in Self Attention."); + ORT_THROW("Relative position bias currently only support query length equal to key length in Self Attention."); } Tensor* output = context->Output(0, {1, num_heads, query_len, key_len}); @@ -100,17 +100,33 @@ Status GatedRelativePositionBias::ComputeInternal(OpKernelContext* context) c const Tensor& weight_tensor = *context->Input(3); const Tensor& bias_tensor = *context->Input(4); const Tensor& eco_a_tensor = *context->Input(5); + const Tensor* token_offset_tensor = context->Input(6); const auto& query_dims = query_tensor.Shape().GetDims(); - ORT_ENFORCE(query_dims.size() == 3); - ORT_ENFORCE(query_dims[2] > 0); - ORT_ENFORCE(query_dims[2] % num_heads_ == 0); - const auto batch_size = SafeInt(query_dims[0]); - const auto seq_len = SafeInt(query_dims[1]); - const auto head_size = SafeInt(query_dims[2] / num_heads_); + + bool is_padding_removed = (token_offset_tensor != nullptr); + ORT_ENFORCE(query_dims.size() == (is_padding_removed ? 2 : 3)); + int hidden_size = static_cast(query_dims[query_dims.size() - 1]); + + ORT_ENFORCE(hidden_size > 0); + ORT_ENFORCE(hidden_size % num_heads_ == 0); + const auto head_size = SafeInt(hidden_size / num_heads_); + + int batch_size; + int seq_len; + int token_count = 0; + if (is_padding_removed) { + const auto& token_offset_dims = token_offset_tensor->Shape().GetDims(); + batch_size = SafeInt(token_offset_dims[0]); + seq_len = SafeInt(token_offset_dims[1]); + token_count = SafeInt(query_dims[0]); + } else { + batch_size = SafeInt(query_dims[0]); + seq_len = SafeInt(query_dims[1]); + } ORT_ENFORCE(query_bias_tensor.Shape().NumDimensions() == 1); - ORT_ENFORCE(query_bias_tensor.Shape()[0] == query_dims[2]); + ORT_ENFORCE(query_bias_tensor.Shape()[0] == hidden_size); const auto& rel_pos_dims = rel_pos_tensor.Shape().GetDims(); ORT_ENFORCE(rel_pos_dims.size() == 4); @@ -149,21 +165,31 @@ Status GatedRelativePositionBias::ComputeInternal(OpKernelContext* context) c size_t workspace_size = sizeof(T) * (elements_in_query + (reuse_output ? (size_t)0 : elements_after_gemm)); auto workspace = GetScratchBuffer(workspace_size, context->GetComputeStream()); - // format 1: BxSx(NH * total_matrix) => matrix_to_transpose * (BxNxSxH) - constexpr int format = 1; - constexpr int total_maxtrix = 1; - constexpr int num_matrix_to_transpose = 1; - LaunchAddBiasTranspose(Stream(context), num_matrix_to_transpose, format, device_prop.maxThreadsPerBlock, - batch_size, seq_len, num_heads_, head_size, - reinterpret_cast(query_tensor.template Data()), - reinterpret_cast(query_bias_tensor.template Data()), - reinterpret_cast(workspace.get()), - false, head_size, reinterpret_cast(static_cast(nullptr)), total_maxtrix); + cudaStream_t stream = Stream(context); + if (!is_padding_removed) { + // format 1: BxSx(NH * total_matrix) => matrix_to_transpose * (BxNxSxH) + constexpr int format = 1; + constexpr int total_maxtrix = 1; + constexpr int num_matrix_to_transpose = 1; + LaunchAddBiasTranspose(stream, num_matrix_to_transpose, format, device_prop.maxThreadsPerBlock, + batch_size, seq_len, num_heads_, head_size, + reinterpret_cast(query_tensor.Data()), + reinterpret_cast(query_bias_tensor.Data()), + reinterpret_cast(workspace.get()), + false, head_size, reinterpret_cast(static_cast(nullptr)), total_maxtrix); + } else { + RestorePaddingAddBiasTranspose(reinterpret_cast(query_tensor.Data()), + reinterpret_cast(query_bias_tensor.Data()), + reinterpret_cast(workspace.get()), + batch_size, seq_len, num_heads_, head_size, + token_offset_tensor->Data(), + token_count, stream); + } // reuse output if possible CudaT* gemm_output = reuse_output ? reinterpret_cast(output->template MutableData()) : (reinterpret_cast(workspace.get()) + elements_in_query); - int ld_gemm_output = reuse_output ? seq_len : D; + int ld_gemm_output = reuse_output ? seq_len : static_cast(D); const CudaT one = ToCudaType::FromFloat(1.0f); const CudaT zero = ToCudaType::FromFloat(0.0f); @@ -177,7 +203,7 @@ Status GatedRelativePositionBias::ComputeInternal(OpKernelContext* context) c &zero, gemm_output, ld_gemm_output, device_prop)); auto status = LaunchGatedRelativePositionBiasKernel( - device_prop, Stream(context), + device_prop, stream, reinterpret_cast(output->template MutableData()), reinterpret_cast(rel_pos_tensor.template Data()), reinterpret_cast(gemm_output), diff --git a/onnxruntime/contrib_ops/cuda/bert/relative_attn_bias_impl.cu b/onnxruntime/contrib_ops/cuda/bert/relative_attn_bias_impl.cu index e72828b8fc8e7..ad8acd9211923 100644 --- a/onnxruntime/contrib_ops/cuda/bert/relative_attn_bias_impl.cu +++ b/onnxruntime/contrib_ops/cuda/bert/relative_attn_bias_impl.cu @@ -29,6 +29,146 @@ namespace cuda { using namespace onnxruntime::cuda; +static constexpr int32_t kMAX_THREADS_PER_BLOCK = 256; + +// Grid: (S, B) +// Block: 256 +// For packed input +// query: TxNxH +// Output: BxNxSxH +// Where: +// T is token_count +// B is batch_size +// S is sequence_length +// N is num_heads +// H is head_size +template +__global__ void TransposeQKV_TNH_3BNSH( + const T* query, + const T* biases, + int32_t N, + int32_t H_QK, + T* q, + const int32_t* token_offset, + int32_t token_count) { + int s = blockIdx.x; + int b = blockIdx.y; + + int S = gridDim.x; + + const int packing_token_idx = b * S + s; + const int padding_token_idx = token_offset[packing_token_idx]; + b = padding_token_idx / S; + s = padding_token_idx % S; + + const int D_QK = N * H_QK; + query += packing_token_idx * D_QK; + + q += (b * N * S + s) * H_QK; + + if (packing_token_idx < token_count) { + for (int i = threadIdx.x; i < D_QK; i += blockDim.x) { + int h = i % H_QK; + int n = i / H_QK; + q[n * S * H_QK + h] = (biases == nullptr) ? query[i] : (query[i] + biases[i]); + } + } else { + for (int i = threadIdx.x; i < D_QK; i += blockDim.x) { + int h = i % H_QK; + int n = i / H_QK; + q[n * S * H_QK + h] = (biases == nullptr) ? T{} : biases[i]; + } + } +} + +template +void InvokeTranspose( + const T* query, const T* bias, T* output, + const int batch_size, const int sequence_length, const int num_heads, const int qk_head_size, + const int32_t* token_offset, int32_t token_count, cudaStream_t stream) { + const dim3 grid(sequence_length, batch_size); + TransposeQKV_TNH_3BNSH<<>>( + query, + bias, + num_heads, + qk_head_size, + output, + token_offset, + token_count); +} + +template +struct T4; + +template <> +struct T4 { + using Type = float4; +}; + +template <> +struct T4 { + using Type = Half4; +}; + +template +struct T2; + +template <> +struct T2 { + using Type = float2; +}; + +template <> +struct T2 { + using Type = half2; +}; + +template +void RestorePaddingAddBiasTranspose( + const T* query, const T* bias, T* output, + const int batch_size, const int sequence_length, const int num_heads, const int qk_head_size, + const int32_t* token_offset, int32_t token_count, cudaStream_t stream) { + if (0 == (qk_head_size & 3)) { + using T4Type = typename T4::Type; + const int H = qk_head_size / 4; + const T4Type* query2 = reinterpret_cast(query); + const T4Type* bias2 = reinterpret_cast(bias); + T4Type* output2 = reinterpret_cast(output); + InvokeTranspose( + query2, bias2, output2, + batch_size, sequence_length, + num_heads, H, + token_offset, token_count, stream); + } else if (0 == (qk_head_size & 1)) { + using T2Type = typename T2::Type; + const int H = qk_head_size / 2; + const T2Type* query2 = reinterpret_cast(query); + const T2Type* bias2 = reinterpret_cast(bias); + T2Type* output2 = reinterpret_cast(output); + InvokeTranspose( + query2, bias2, output2, + batch_size, sequence_length, + num_heads, H, + token_offset, token_count, stream); + } else { + InvokeTranspose( + query, bias, output, + batch_size, sequence_length, + num_heads, qk_head_size, + token_offset, token_count, stream); + } +} + +template void RestorePaddingAddBiasTranspose( + const float* query, const float* bias, float* output, + const int batch_size, const int sequence_length, const int num_heads, const int qk_head_size, + const int32_t* token_offset, int32_t token_count, cudaStream_t stream); + +template void RestorePaddingAddBiasTranspose( + const half* query, const half* bias, half* output, + const int batch_size, const int sequence_length, const int num_heads, const int qk_head_size, + const int32_t* token_offset, int32_t token_count, cudaStream_t stream); + template __global__ void buildRelativeAttentionBias(T* relative_attention_bias, const T* relative_attention_bias_table, @@ -156,7 +296,7 @@ struct TypeMapper : public V_vec_m_ {}; // The following operator overriding is not common so we put it in anonymous namespace #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ > 530 inline __device__ half2 operator*(const float a, const half2 b) { - return __hmul2_rn(__float2half2_rn(a), b); + return __hmul2(__float2half2_rn(a), b); } #else inline __device__ half2 operator*(const float a, const half2 b) { @@ -247,11 +387,11 @@ Status LaunchGatedRelativePositionBiasKernel( const T* qw, // query * weight const T* bias, const T* eco_a, - const int batch_size, - const int num_heads, - const int seq_len, - const int D, - const int ldqw) { + int batch_size, + int num_heads, + int seq_len, + int D, + int ldqw) { ORT_ENFORCE(D <= 32 && D > 0 && (D % 2 == 0)); ORT_ENFORCE(ldqw == seq_len || ldqw == D); @@ -279,7 +419,7 @@ Status LaunchGatedRelativePositionBiasKernel( reinterpret_cast(output), reinterpret_cast(rel_pos), qw, bias, eco_a, D, ldqw, equiv_seq_len); - } else if (seq_len & 1 == 0) { + } else if ((seq_len & 1) == 0) { using vec_type = typename TypeMapper::Type; GatedRelativePositionBiasKernelSmallD<<>>( reinterpret_cast(output), diff --git a/onnxruntime/contrib_ops/cuda/bert/relative_attn_bias_impl.h b/onnxruntime/contrib_ops/cuda/bert/relative_attn_bias_impl.h index 572db0c0237b3..74edc49dff630 100644 --- a/onnxruntime/contrib_ops/cuda/bert/relative_attn_bias_impl.h +++ b/onnxruntime/contrib_ops/cuda/bert/relative_attn_bias_impl.h @@ -36,6 +36,12 @@ Status LaunchGatedRelativePositionBiasKernel( const int D, const int ldqw); +template +void RestorePaddingAddBiasTranspose( + const T* query, const T* bias, T* output, + const int batch_size, const int sequence_length, const int num_heads, const int qk_head_size, + const int32_t* token_offset, int32_t token_count, cudaStream_t stream); + } // namespace cuda } // namespace contrib } // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/bert/skip_layer_norm.cc b/onnxruntime/contrib_ops/cuda/bert/skip_layer_norm.cc index 4cf45b5d3379d..78174181acdc8 100644 --- a/onnxruntime/contrib_ops/cuda/bert/skip_layer_norm.cc +++ b/onnxruntime/contrib_ops/cuda/bert/skip_layer_norm.cc @@ -4,6 +4,8 @@ #include "core/providers/cuda/cuda_common.h" #include "core/providers/cuda/nn/layer_norm_impl.h" #include "skip_layer_norm.h" +#include "skip_layer_norm_impl.h" +#include "contrib_ops/cpu/skip_layer_norm_helper.h" namespace onnxruntime { namespace contrib { @@ -38,6 +40,10 @@ template SkipLayerNorm::SkipLayerNorm(const OpKernelInfo& op_kernel_info) : CudaKernel(op_kernel_info) { ORT_ENFORCE(op_kernel_info.GetAttr("epsilon", &epsilon_).IsOK()); ORT_ENFORCE(epsilon_ >= 0); + + const CUDAExecutionProvider* cuda_ep = static_cast(op_kernel_info.GetExecutionProvider()); + + strict_ = cuda_ep->IsSkipLayerNormInStrictMode(); } template @@ -55,77 +61,59 @@ Status SkipLayerNorm::ComputeInternal(OpKernelContext* ctx) const // of the input and skip tensors Tensor* skip_input_bias_add_output = ctx->Output(3, input->Shape()); - if (input->Shape() != skip->Shape()) { - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, - "skip is expected to have same shape as input"); - } - - if (input->Shape().Size() == 0) { - return Status::OK(); - } - const auto& input_dims = input->Shape().GetDims(); size_t input_dims_size = input_dims.size(); - if (input_dims_size != 3 && input_dims_size != 2) { - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, - "input is expected to have 3 or 2 dimensions, got ", input_dims_size); - } + const auto& skip_dims = skip->Shape().GetDims(); + size_t skip_dims_size = skip_dims.size(); int hidden_size = static_cast(input_dims[input_dims_size - 1]); - const auto& gamma_dims = gamma->Shape().GetDims(); - if (gamma_dims.size() != 1) { - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, - "gamma is expected to have 1 dimension, got ", gamma_dims.size()); - } - if (gamma_dims[0] != hidden_size) { - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, - "Last dimension of gamma and input does not match"); - } + ORT_RETURN_IF_ERROR(onnxruntime::contrib::skip_layer_norm_helper::CheckInputs(input, + skip, + gamma, + beta, + bias, + hidden_size, + input_dims_size)); - if (!Simplified) { - if (nullptr != beta) { - const auto& beta_dims = beta->Shape().GetDims(); - if (beta_dims.size() != 1) { - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, - "beta is expected to have 1 dimension, got ", beta_dims.size()); - } - if (beta_dims[0] != hidden_size) { - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, - "Last dimension of beta and input does not match"); - } - } - } - - if (nullptr != bias) { - const auto& bias_dims = bias->Shape().GetDims(); - if (bias_dims.size() != 1) { - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, - "bias is expected to have 1 dimension, got ", bias_dims.size()); - } - if (bias_dims[0] != hidden_size) { - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, - "Last dimension of bias and input does not match"); - } - } + const bool skip_broadcasted = (skip_dims[0] == 1 || skip_dims_size == 2) ? true : false; + const int skip_size = static_cast(skip_dims[skip_dims_size - 1] * skip_dims[skip_dims_size - 2]); int row_count = gsl::narrow(input->Shape().SizeToDimension(input_dims_size - 1)); typedef typename ToCudaType::MappedType CudaT; - HostApplyLayerNorm( - GetDeviceProp(), - Stream(ctx), - reinterpret_cast(output->MutableData()), // Y_data - nullptr, // mean_data - nullptr, // inv_var_data - reinterpret_cast(input->Data()), // X_data - row_count, // n1 - hidden_size, // n2 - (double)epsilon_, // epsilon - reinterpret_cast(gamma->Data()), // gamma - (beta != nullptr) ? reinterpret_cast(beta->Data()) : nullptr, // beta - reinterpret_cast(skip->Data()), // skip or residual to add - (bias != nullptr) ? reinterpret_cast(bias->Data()) : nullptr, // bias to add - skip_input_bias_add_output != nullptr ? reinterpret_cast(skip_input_bias_add_output->MutableData()) : nullptr); + + if (strict_) { + HostApplyLayerNorm( + GetDeviceProp(), + Stream(ctx), + reinterpret_cast(output->MutableData()), // Y_data + nullptr, // mean_data + nullptr, // inv_var_data + reinterpret_cast(input->Data()), // X_data + row_count, // n1 + hidden_size, // n2 + (double)epsilon_, // epsilon + reinterpret_cast(gamma->Data()), // gamma + (beta != nullptr) ? reinterpret_cast(beta->Data()) : nullptr, // beta + reinterpret_cast(skip->Data()), // skip or residual to add + (bias != nullptr) ? reinterpret_cast(bias->Data()) : nullptr, // bias to add + skip_input_bias_add_output != nullptr ? reinterpret_cast(skip_input_bias_add_output->MutableData()) : nullptr); + } else { + LaunchSkipLayerNormKernel( + Stream(ctx), + reinterpret_cast(output->MutableData()), + skip_input_bias_add_output != nullptr ? reinterpret_cast(skip_input_bias_add_output->MutableData()) : nullptr, + reinterpret_cast(input->Data()), + reinterpret_cast(skip->Data()), + reinterpret_cast(gamma->Data()), + (beta != nullptr) ? reinterpret_cast(beta->Data()) : nullptr, + (bias != nullptr) ? reinterpret_cast(bias->Data()) : nullptr, + epsilon_, + hidden_size, + row_count, + skip_broadcasted, + skip_size); + } CUDA_RETURN_IF_ERROR(cudaGetLastError()); return Status::OK(); diff --git a/onnxruntime/contrib_ops/cuda/bert/skip_layer_norm.h b/onnxruntime/contrib_ops/cuda/bert/skip_layer_norm.h index 9d47373fba4f0..06b3945427833 100644 --- a/onnxruntime/contrib_ops/cuda/bert/skip_layer_norm.h +++ b/onnxruntime/contrib_ops/cuda/bert/skip_layer_norm.h @@ -19,6 +19,7 @@ class SkipLayerNorm final : public CudaKernel { private: float epsilon_; + bool strict_; }; } // namespace cuda diff --git a/onnxruntime/contrib_ops/cuda/bert/skip_layer_norm_impl.cu b/onnxruntime/contrib_ops/cuda/bert/skip_layer_norm_impl.cu new file mode 100644 index 0000000000000..f2ee076a8a03d --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/skip_layer_norm_impl.cu @@ -0,0 +1,245 @@ +/* + The implementation of this file is based on skipLayerNorm plugin in TensorRT demo: + https://github.com/NVIDIA/TensorRT/tree/release/5.1/demo/BERT/ + +Copyright 2019 NVIDIA Corporation + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// Modifications: Add SkipLayerNormKernelVec to +// leverage vectorized load/write. +// and templatize ComputeSkipLayerNorm for different +// data types. +// Copyright (c) Advanced Micro Devices, Inc. All rights reserved. +// Licensed under the MIT License. + +#include "contrib_ops/cuda/bert/layer_norm.cuh" +#include "contrib_ops/cuda/bert/skip_layer_norm_impl.h" +#include + +namespace onnxruntime { +namespace contrib { +namespace cuda { + +namespace { +template +T maybe2half(float x); + +template <> +float maybe2half(float x) { + return x; +} + +template <> +half maybe2half(float x) { + return __float2half_rn(x); +} + +// Using only power of 2 numbers will lead to waste of compute for same size such as 768, which is a very common case +// in BERT. Ideally we can step by wrap_size * num_unroll, but listing too many steps will cause long compile time. +constexpr int kSizes[] = {32, 64, 128, 384, 768, 1024, 2048}; +constexpr int kMinBlockSize = 32; +constexpr int kMaxBlockSize = 256; + +int NextSize(int x) { + size_t len = sizeof(kSizes) / sizeof(kSizes[0]); + for (size_t i = 0; i < len; ++i) { + if (x <= kSizes[i]) { + return kSizes[i]; + } + } + return kSizes[len - 1]; +} + +template +bool CanVectorized(T* output, T* skip_input_bias_add_output, const T* input, const T* skip, const T* gamma, + const T* beta, const T* bias, const int ld, const int next_size) { + constexpr int alignment = std::alignment_of>::value; + return ld % NumUnroll == 0 && reinterpret_cast(output) % alignment == 0 && + reinterpret_cast(skip_input_bias_add_output) % alignment == 0 && + reinterpret_cast(input) % alignment == 0 && reinterpret_cast(skip) % alignment == 0 && + reinterpret_cast(gamma) % alignment == 0 && reinterpret_cast(beta) % alignment == 0 && + reinterpret_cast(bias) % alignment == 0 && next_size / NumUnroll >= kMinBlockSize && + next_size / NumUnroll <= kMaxBlockSize; +} +} // namespace + +template +__global__ void SkipLayerNormKernel( + const int ld, const T* input, const T* skip, + const T* beta, const T* gamma, const T* bias, + const T epsilon, T* output, T* skip_input_bias_add_output, const bool skip_broadcasted, int skip_size) { + const T reverse_ld = T(1.f / ld); + const int offset = blockIdx.x * ld; + + KeyValuePairSum pair_sum; + // reduce x and x^2 + cub::KeyValuePair thread_data(0, 0); + + + for (int i = threadIdx.x; i < ld; i += TPB) { + const int idx = offset + i; + + const T skip_data = skip_broadcasted ? skip[idx % skip_size] : skip[idx]; + const T val = (bias == nullptr) ? input[idx] + skip_data : input[idx] + skip_data + bias[i]; + + const T rldval = reverse_ld * val; + thread_data = pair_sum(thread_data, cub::KeyValuePair(rldval, rldval * val)); + + if (skip_input_bias_add_output != nullptr) { + skip_input_bias_add_output[idx] = val; + } + + output[idx] = val; + } + if (Simplified) { + SimplifiedLayerNorm(thread_data.value, ld, offset, gamma, epsilon, output); + return; + } + LayerNorm(thread_data, ld, offset, beta, gamma, epsilon, output); +} + +// Vectorized kernel +template +__global__ void SkipLayerNormKernelSmall( + const int ld, const T* input, const T* skip, const T* beta, const T* gamma, + const T* bias, const T epsilon, T* output, T* skip_input_bias_add_output, + bool hasBias, bool hasSkipInputBiasAdditionOutput, const bool skip_broadcasted, const int skip_size) { + const T rld = T(1.f / ld); + const int idx = blockIdx.x * ld + threadIdx.x * ILP; // grid_size = n / ld + + using VecT = aligned_vector; + + T input_v[ILP], skip_v[ILP], bias_v[ILP], skip_input_bias_add_output_v[ILP]; + + VecT* input_val = reinterpret_cast(&input_v); + *input_val = *reinterpret_cast(&input[idx]); + + VecT* skip_val = reinterpret_cast(&skip_v); + if (skip_broadcasted){ + *skip_val = *reinterpret_cast(&skip[idx % skip_size]); + }else{ + *skip_val = *reinterpret_cast(&skip[idx]); + } + + if (hasBias) { + VecT* bias_val = reinterpret_cast(&bias_v); + *bias_val = *reinterpret_cast(&bias[threadIdx.x * ILP]); + } + + cub::KeyValuePair thread_data(T(0.f), T(0.f)); + + if (ILP * threadIdx.x < ld) { + T rldval_sum = T(0.f); + T rldvalsq_sum = T(0.f); +#pragma unroll + for (int i = 0; i < ILP; i++) { + input_v[i] += hasBias ? skip_v[i] + bias_v[i] : skip_v[i]; + + if (hasSkipInputBiasAdditionOutput) { + skip_input_bias_add_output_v[i] = input_v[i]; + } + + const T rldval = rld * input_v[i]; + rldval_sum += rldval; + rldvalsq_sum += rldval * input_v[i]; + } + + if (hasSkipInputBiasAdditionOutput) { + *(reinterpret_cast(&skip_input_bias_add_output[idx])) = *reinterpret_cast(&skip_input_bias_add_output_v); + } + + thread_data = cub::KeyValuePair(rldval_sum, rldvalsq_sum); + } + + if (Simplified) { + SimplifiedLayerNormSmall(input_v, thread_data.value, ld, idx, gamma, epsilon, output); + return; + } + LayerNormSmall(input_v, thread_data, ld, idx, beta, gamma, epsilon, output); +} + +template +void LaunchSkipLayerNormKernel( + cudaStream_t stream, T* output, T* skip_input_bias_add_output, const T* input, const T* skip, const T* gamma, + const T* beta, const T* bias, float epsilon, int ld, int row_count, bool skip_broadcasted, int skip_size) { + if (row_count == 0) { + return; + } + + bool hasBias = (bias == nullptr) ? false : true; + bool hasSkipInputBiasAdditionOutput = (skip_input_bias_add_output == nullptr) ? false : true; + + const int next_size = NextSize(ld); + const int grid_size = row_count; + bool flag_vec2 = + CanVectorized(output, skip_input_bias_add_output, input, skip, gamma, beta, bias, ld, next_size); + bool flag_vec4 = + CanVectorized(output, skip_input_bias_add_output, input, skip, gamma, beta, bias, ld, next_size); + + switch (next_size) { +#define LAUNCH_SKIP_LAYER_NORM_KERNEL_SMALL(num_unroll) \ + SkipLayerNormKernelSmall \ + <<>>(ld, input, skip, beta, gamma, bias, maybe2half(epsilon), output, \ + skip_input_bias_add_output, hasBias, hasSkipInputBiasAdditionOutput, skip_broadcasted, skip_size) +#define LAUNCH_SKIP_LAYER_NORM_KERNEL() \ + SkipLayerNormKernel<<>>( \ + ld, input, skip, beta, gamma, bias, maybe2half(epsilon), output, skip_input_bias_add_output, skip_broadcasted, skip_size) +#define CASE_NEXT_SIZE(next_size_value) \ + case next_size_value: { \ + if (flag_vec4) { \ + constexpr int block_size = next_size_value / 4; \ + LAUNCH_SKIP_LAYER_NORM_KERNEL_SMALL(4); \ + } else if (flag_vec2) { \ + constexpr int block_size = next_size_value / 2; \ + LAUNCH_SKIP_LAYER_NORM_KERNEL_SMALL(2); \ + } else { \ + if (next_size_value <= kMaxBlockSize) { \ + constexpr int block_size = next_size_value; \ + LAUNCH_SKIP_LAYER_NORM_KERNEL_SMALL(1); \ + } else { \ + LAUNCH_SKIP_LAYER_NORM_KERNEL(); \ + } \ + } \ + } break + CASE_NEXT_SIZE(kSizes[0]); + CASE_NEXT_SIZE(kSizes[1]); + CASE_NEXT_SIZE(kSizes[2]); + CASE_NEXT_SIZE(kSizes[3]); + CASE_NEXT_SIZE(kSizes[4]); + CASE_NEXT_SIZE(kSizes[5]); + CASE_NEXT_SIZE(kSizes[6]); +#undef CASE_NEXT_SIZE +#undef LAUNCH_SKIP_LAYER_NORM_KERNEL +#undef LAUNCH_SKIP_LAYER_NORM_KERNEL_SMALL + } +} + +#define SKIPLAYERNORM_IMPL(T, Simplified) \ + template void LaunchSkipLayerNormKernel(cudaStream_t stream, T * output, \ + T * skip_input_bias_add_output, \ + const T* input, const T* skip, const T* gamma, \ + const T* beta, const T* bias, float epsilon, \ + int ld, int row_count, bool skip_broadcasted, int skip_size); +SKIPLAYERNORM_IMPL(float, true); +SKIPLAYERNORM_IMPL(float, false); +SKIPLAYERNORM_IMPL(half, true); +SKIPLAYERNORM_IMPL(half, false); + +} // namespace cuda +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/bert/skip_layer_norm_impl.h b/onnxruntime/contrib_ops/cuda/bert/skip_layer_norm_impl.h new file mode 100644 index 0000000000000..ffb5850c827fe --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/bert/skip_layer_norm_impl.h @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once +#include "core/common/common.h" + +namespace onnxruntime { +namespace contrib { +namespace cuda { + +template +void LaunchSkipLayerNormKernel( + cudaStream_t stream, + T* output, // normalized output tensor + T* skip_input_bias_add_output, // sum of the input and skip (and bias if it exists) tensors output + const T* input, // input tensor + const T* skip, // skip tensor + const T* gamma, // Layer normalization gamma tensor + const T* beta, // Layer normalization beta tensor + const T* bias, // Layer normalization beta tensor + float epsilon, // Layer normalization epsilon + int hidden_size, // hidden size, it is the leading dimension (ld) + int row_count, // number of rows. That is total number of elements divided by hidden size. + bool skip_broadcasted, // determines if broadcasting should be implemented + int skip_size); // determines size of the skip tensor + +} // namespace cuda +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/bert/tensorrt_fused_multihead_attention/flash_attention/fmha_flash_attention.h b/onnxruntime/contrib_ops/cuda/bert/tensorrt_fused_multihead_attention/flash_attention/fmha_flash_attention.h index 5f2e3e6fafee3..d07f6d1347293 100644 --- a/onnxruntime/contrib_ops/cuda/bert/tensorrt_fused_multihead_attention/flash_attention/fmha_flash_attention.h +++ b/onnxruntime/contrib_ops/cuda/bert/tensorrt_fused_multihead_attention/flash_attention/fmha_flash_attention.h @@ -269,7 +269,7 @@ class FusedMultiHeadFlashAttentionKernel ORT_ENFORCE(headsize <= 0x3FFFFFFF); ORT_ENFORCE(qStep <= 0xFFFF); ORT_ENFORCE(kvStep <= 0xFFFF); - return static_cast(qStep << 16 | kvStep) << 32 | (headsize << 2) | (interleaved ? 2U : 0U) | (unroll ? 1U : 0U); + return static_cast(qStep << 16 | kvStep) << 32 | (static_cast(headsize) << 2) | (interleaved ? 2U : 0U) | (unroll ? 1U : 0U); } void updateSteps(Fused_multihead_attention_params_v2 const& param, int32_t& qStep, int32_t& kvStep) const { diff --git a/onnxruntime/contrib_ops/cuda/bert/tensorrt_fused_multihead_attention/flash_attention/sharedCubinLoader.h b/onnxruntime/contrib_ops/cuda/bert/tensorrt_fused_multihead_attention/flash_attention/sharedCubinLoader.h index c760753a5c92c..db0a1746d429c 100644 --- a/onnxruntime/contrib_ops/cuda/bert/tensorrt_fused_multihead_attention/flash_attention/sharedCubinLoader.h +++ b/onnxruntime/contrib_ops/cuda/bert/tensorrt_fused_multihead_attention/flash_attention/sharedCubinLoader.h @@ -166,10 +166,10 @@ class TSharedCubinKernelFactory { auto const id = hashID(type, sm); auto const findIter = mKernels.find(id); if (findIter == mKernels.end()) { - auto* newKernel = new TKernelList{pKernelList, nbKernels, type, sm}; + auto newKernel = std::make_unique(pKernelList, nbKernels, type, sm); newKernel->loadCubinKernels(); - mKernels.insert(std::make_pair(id, std::unique_ptr(newKernel))); - return newKernel; + auto const insert_result = mKernels.insert(std::make_pair(id, std::move(newKernel))); + return insert_result.first->second.get(); } return findIter->second.get(); } diff --git a/onnxruntime/contrib_ops/cuda/bert/tensorrt_fused_multihead_attention/fused_multihead_attention.h b/onnxruntime/contrib_ops/cuda/bert/tensorrt_fused_multihead_attention/fused_multihead_attention.h index f83d1cd08a63b..f01d59830951a 100644 --- a/onnxruntime/contrib_ops/cuda/bert/tensorrt_fused_multihead_attention/fused_multihead_attention.h +++ b/onnxruntime/contrib_ops/cuda/bert/tensorrt_fused_multihead_attention/fused_multihead_attention.h @@ -161,10 +161,12 @@ class TFusedMHAKernelFactory { const auto id = hashID(type, sm); const auto findIter = mKernels.find(id); if (findIter == mKernels.end()) { - TFusedMHAKernelList* newKernel = new TFusedMHAKernelList{pKernelList, nbKernels, type, sm}; + GSL_SUPPRESS(r.11) + std::unique_ptr newKernel(new TFusedMHAKernelList{pKernelList, nbKernels, type, sm}); newKernel->loadXMMAKernels(); - mKernels.insert(std::make_pair(id, std::unique_ptr(newKernel))); - return newKernel; + TFusedMHAKernelList* ret = newKernel.get(); + mKernels.emplace(id, std::move(newKernel)); + return ret; } return findIter->second.get(); } diff --git a/onnxruntime/contrib_ops/cuda/bert/tensorrt_fused_multihead_attention/fused_multihead_attention_v2.h b/onnxruntime/contrib_ops/cuda/bert/tensorrt_fused_multihead_attention/fused_multihead_attention_v2.h index 82bb466437270..ce42e33ba1bfd 100644 --- a/onnxruntime/contrib_ops/cuda/bert/tensorrt_fused_multihead_attention/fused_multihead_attention_v2.h +++ b/onnxruntime/contrib_ops/cuda/bert/tensorrt_fused_multihead_attention/fused_multihead_attention_v2.h @@ -18,6 +18,11 @@ // Modified based on FasterTransformer 5.2 #pragma once +#if defined(_MSC_VER) +#pragma warning(push) +// Global initializer accesses extern object cubin_fmha_v2_fp16_Causal_64_40_sm86_cu_cubin_len +#pragma warning(disable : 26427) +#endif #include "contrib_ops/cuda/bert/tensorrt_fused_multihead_attention/fused_multihead_attention.h" #include @@ -850,6 +855,139 @@ static const struct FusedMultiHeadAttentionKernelMetaInfoV2 { false, false}, + {DATA_TYPE_FP16, + 32, + 32, + kSM_80, + cubin_fmha_v2_fp16_32_32_sm80_cu_cubin, + cubin_fmha_v2_fp16_32_32_sm80_cu_cubin_len, + "fmha_v2_fp16_32_32_sm80_kernel", + 8192, + 128, + 0, + false, + false}, + {DATA_TYPE_FP16, + 64, + 32, + kSM_80, + cubin_fmha_v2_fp16_64_32_sm80_cu_cubin, + cubin_fmha_v2_fp16_64_32_sm80_cu_cubin_len, + "fmha_v2_fp16_64_32_sm80_kernel", + 16384, + 128, + 0, + false, + false}, + {DATA_TYPE_FP16, + 96, + 32, + kSM_80, + cubin_fmha_v2_fp16_96_32_sm80_cu_cubin, + cubin_fmha_v2_fp16_96_32_sm80_cu_cubin_len, + "fmha_v2_fp16_96_32_sm80_kernel", + 24576, + 128, + 0, + false, + false}, + {DATA_TYPE_FP16, + 128, + 32, + kSM_80, + cubin_fmha_v2_fp16_128_32_sm80_cu_cubin, + cubin_fmha_v2_fp16_128_32_sm80_cu_cubin_len, + "fmha_v2_fp16_128_32_sm80_kernel", + 32768, + 128, + 0, + false, + false}, + {DATA_TYPE_FP16, + 128, + 32, + kSM_80, + cubin_fmha_v2_fp16_128_32_sm80_cu_cubin, + cubin_fmha_v2_fp16_128_32_sm80_cu_cubin_len, + "fmha_v2_fp16_128_32_sm80_kernel_nl", + 20480, + 128, + 32, + false, + false}, + {DATA_TYPE_FP16, + 192, + 32, + kSM_80, + cubin_fmha_v2_fp16_192_32_sm80_cu_cubin, + cubin_fmha_v2_fp16_192_32_sm80_cu_cubin_len, + "fmha_v2_fp16_192_32_sm80_kernel", + 16384, + 128, + 0, + false, + false}, + {DATA_TYPE_FP16, + 192, + 32, + kSM_80, + cubin_fmha_v2_fp16_192_32_sm80_cu_cubin, + cubin_fmha_v2_fp16_192_32_sm80_cu_cubin_len, + "fmha_v2_fp16_192_32_sm80_kernel_nl", + 16384, + 128, + 32, + false, + false}, + {DATA_TYPE_FP16, + 256, + 32, + kSM_80, + cubin_fmha_v2_fp16_256_32_sm80_cu_cubin, + cubin_fmha_v2_fp16_256_32_sm80_cu_cubin_len, + "fmha_v2_fp16_256_32_sm80_kernel", + 20480, + 128, + 0, + false, + false}, + {DATA_TYPE_FP16, + 256, + 32, + kSM_80, + cubin_fmha_v2_fp16_256_32_sm80_cu_cubin, + cubin_fmha_v2_fp16_256_32_sm80_cu_cubin_len, + "fmha_v2_fp16_256_32_sm80_kernel_nl", + 20480, + 128, + 32, + false, + false}, + {DATA_TYPE_FP16, + 384, + 32, + kSM_80, + cubin_fmha_v2_fp16_384_32_sm80_cu_cubin, + cubin_fmha_v2_fp16_384_32_sm80_cu_cubin_len, + "fmha_v2_fp16_384_32_sm80_kernel", + 32768, + 256, + 0, + false, + false}, + {DATA_TYPE_FP16, + 384, + 32, + kSM_80, + cubin_fmha_v2_fp16_384_32_sm80_cu_cubin, + cubin_fmha_v2_fp16_384_32_sm80_cu_cubin_len, + "fmha_v2_fp16_384_32_sm80_kernel_nl", + 32768, + 256, + 32, + false, + false}, + // GA10x: sm86 uses sm80 kernels {DATA_TYPE_FP16, 32, @@ -3233,3 +3371,6 @@ inline const FusedMultiHeadAttentionXMMAKernelV2* getXMMAKernelsV2(Data_type typ } // namespace cuda } // namespace contrib } // namespace onnxruntime +#if defined(_MSC_VER) +#pragma warning(pop) +#endif \ No newline at end of file diff --git a/onnxruntime/contrib_ops/cuda/bert/tensorrt_fused_multihead_attention/mha_runner.cu b/onnxruntime/contrib_ops/cuda/bert/tensorrt_fused_multihead_attention/mha_runner.cu index 2518f721079c9..8fb6575d27cc0 100644 --- a/onnxruntime/contrib_ops/cuda/bert/tensorrt_fused_multihead_attention/mha_runner.cu +++ b/onnxruntime/contrib_ops/cuda/bert/tensorrt_fused_multihead_attention/mha_runner.cu @@ -29,6 +29,7 @@ union __half2_uint32_t_union { void set_alpha_fp16(uint32_t& alpha, float norm) { __half2_uint32_t_union temp; + temp.u32 = 0; temp.fp162 = __float2half2_rn(norm); alpha = temp.u32; } diff --git a/onnxruntime/contrib_ops/cuda/bert/transformer_common.cc b/onnxruntime/contrib_ops/cuda/bert/transformer_common.cc index 0c22bc5a29777..675d12eb2388f 100644 --- a/onnxruntime/contrib_ops/cuda/bert/transformer_common.cc +++ b/onnxruntime/contrib_ops/cuda/bert/transformer_common.cc @@ -1,5 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. + #include #include "core/providers/shared_library/provider_api.h" // Include this otherwise Windows build complains Env::Default() missing #include "core/platform/env_var_utils.h" diff --git a/onnxruntime/contrib_ops/cuda/collective/nccl_kernels.cc b/onnxruntime/contrib_ops/cuda/collective/nccl_kernels.cc index 30cb474d0374c..bb924a0d49cfe 100644 --- a/onnxruntime/contrib_ops/cuda/collective/nccl_kernels.cc +++ b/onnxruntime/contrib_ops/cuda/collective/nccl_kernels.cc @@ -1,7 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. + #include "nccl_kernels.h" #include "mpi_include.h" +#include "core/providers/cuda/tensor/transpose.h" +#include "core/providers/cuda/cuda_check_memory.h" namespace onnxruntime { namespace contrib { @@ -12,6 +15,9 @@ namespace cuda { static ncclDataType_t GetNcclDataType(onnxruntime::MLDataType type) { if (type == DataTypeImpl::GetType()) { return ncclUint8; + } else if (type == DataTypeImpl::GetType()) { + // CUDA bool is 8-bit large. + return ncclUint8; } else if (type == DataTypeImpl::GetType()) { return ncclInt8; } else if (type == DataTypeImpl::GetType()) { @@ -99,14 +105,14 @@ Status AllReduce::ComputeInternal(OpKernelContext* context) const { void* output_data = context->Output(0, in_shape)->MutableDataRaw(); ncclDataType_t dtype = GetNcclDataType(input_tensor->DataType()); -#ifdef ORT_USE_NCCL NCCL_RETURN_IF_ERROR(ncclAllReduce(input_data, output_data, input_count, dtype, ncclSum, comm, Stream(context))); -#endif return Status::OK(); } AllGather::AllGather(const OpKernelInfo& info) : NcclKernel(info) { info.GetAttrOrDefault("group_size", &group_size_, static_cast(1)); + info.GetAttrOrDefault("axis", &axis_, static_cast(0)); + cuda_ep_ = static_cast(info.GetExecutionProvider()); } Status AllGather::ComputeInternal(OpKernelContext* context) const { @@ -114,19 +120,67 @@ Status AllGather::ComputeInternal(OpKernelContext* context) const { auto input_tensor = context->Input(0); const void* input_data = input_tensor->DataRaw(); - const auto in_shape = input_tensor->Shape(); + const auto& in_shape = input_tensor->Shape(); int64_t input_count = in_shape.Size(); - // construct output shape - TensorShape out_shape(in_shape); - out_shape[0] = group_size_ * out_shape[0]; - void* output_data = context->Output(0, out_shape)->MutableDataRaw(); + if (axis_ > 0) { + // Need transpose + // TODO: fuse transpose with allgather + std::vector permutation(in_shape.NumDimensions()); + AllocatorPtr alloc; + auto status = context->GetTempSpaceAllocator(&alloc); + if (!status.IsOK()) + return status; + + std::iota(std::begin(permutation), std::end(permutation), 0); + + // swap rank 0 and rank axis + permutation[axis_] = 0; + permutation[0] = axis_; + std::vector transposed_input_dims; + transposed_input_dims.reserve(in_shape.NumDimensions()); + for (auto e : permutation) { + transposed_input_dims.push_back(in_shape[e]); + } + + // Allocate a temporary tensor to hold transposed input + auto temp_input = Tensor::Create(input_tensor->DataType(), TensorShape(transposed_input_dims), alloc); + + // Perform the transpose + ORT_RETURN_IF_ERROR(onnxruntime::cuda::Transpose::DoTranspose(cuda_ep_->GetDeviceProp(), + Stream(context), + GetCublasHandle(context), + permutation, *input_tensor, *temp_input)); + // Allocate a tempoarary buffer for all gather + TensorShape all_gather_out_shape(transposed_input_dims); + all_gather_out_shape[0] = group_size_ * all_gather_out_shape[0]; + auto all_gather_output = Tensor::Create(temp_input->DataType(), all_gather_out_shape, alloc); + ncclDataType_t dtype = GetNcclDataType(temp_input->DataType()); + NCCL_RETURN_IF_ERROR(ncclAllGather(temp_input->DataRaw(), + all_gather_output->MutableDataRaw(), + input_count, dtype, comm, Stream(context))); + // release temp_input + temp_input.release(); + // transpose to output + TensorShape out_shape(in_shape); + out_shape[axis_] = group_size_ * out_shape[axis_]; + auto* output_tensor = context->Output(0, out_shape); + + return onnxruntime::cuda::Transpose::DoTranspose(cuda_ep_->GetDeviceProp(), + Stream(context), + GetCublasHandle(context), + permutation, *all_gather_output, *output_tensor); + } else { + // construct output shape + TensorShape out_shape(in_shape); + out_shape[axis_] = group_size_ * out_shape[axis_]; - ncclDataType_t dtype = GetNcclDataType(input_tensor->DataType()); -#ifdef ORT_USE_NCCL - NCCL_RETURN_IF_ERROR(ncclAllGather(input_data, output_data, input_count, dtype, comm, Stream(context))); -#endif - return Status::OK(); + void* output_data = context->Output(0, out_shape)->MutableDataRaw(); + + ncclDataType_t dtype = GetNcclDataType(input_tensor->DataType()); + NCCL_RETURN_IF_ERROR(ncclAllGather(input_data, output_data, input_count, dtype, comm, Stream(context))); + return Status::OK(); + } } AllToAll::AllToAll(const OpKernelInfo& info) : NcclKernel(info) { @@ -146,7 +200,9 @@ Status AllToAll::ComputeInternal(OpKernelContext* context) const { char* output_data = static_cast(context->Output(0, out_shape)->MutableDataRaw()); -#ifdef ORT_USE_NCCL + CheckIfMemoryOnCurrentGpuDevice(input_data); + CheckIfMemoryOnCurrentGpuDevice(output_data); + NCCL_RETURN_IF_ERROR(ncclGroupStart()); for (int32_t r = 0; r < group_size_; r++) { NCCL_RETURN_IF_ERROR(ncclSend(input_data, rank_stride, dtype, r, comm, Stream(context))); @@ -155,7 +211,6 @@ Status AllToAll::ComputeInternal(OpKernelContext* context) const { output_data += (rank_stride * element_size); } NCCL_RETURN_IF_ERROR(ncclGroupEnd()); -#endif return Status::OK(); } @@ -178,7 +233,7 @@ ONNX_OPERATOR_KERNEL_EX( kCudaExecutionProvider, (*KernelDefBuilder::Create()) .AllocateInputsContiguously() - .TypeConstraint("T", DataTypeImpl::AllIEEEFloatTensorTypes()), + .TypeConstraint("T", DataTypeImpl::AllTensorTypes()), AllGather); ONNX_OPERATOR_KERNEL_EX( @@ -187,9 +242,8 @@ ONNX_OPERATOR_KERNEL_EX( 1, kCudaExecutionProvider, (*KernelDefBuilder::Create()) - .VariadicAlias(0, 0) // outputs and inputs are mapped one to one .AllocateInputsContiguously() - .TypeConstraint("T", DataTypeImpl::AllIEEEFloatTensorTypes()), + .TypeConstraint("T", DataTypeImpl::AllTensorTypes()), AllToAll); } // namespace cuda diff --git a/onnxruntime/contrib_ops/cuda/collective/nccl_kernels.h b/onnxruntime/contrib_ops/cuda/collective/nccl_kernels.h index 4f7093dd49363..24df69ea50224 100644 --- a/onnxruntime/contrib_ops/cuda/collective/nccl_kernels.h +++ b/onnxruntime/contrib_ops/cuda/collective/nccl_kernels.h @@ -67,6 +67,8 @@ class AllGather final : public NcclKernel { private: int64_t group_size_ = -1; + int64_t axis_ = -1; + const CUDAExecutionProvider* cuda_ep_; }; class AllToAll final : public NcclKernel { diff --git a/onnxruntime/contrib_ops/cuda/cuda_contrib_kernels.cc b/onnxruntime/contrib_ops/cuda/cuda_contrib_kernels.cc index d9a77c7bab5ad..86c1cb93e8b6f 100644 --- a/onnxruntime/contrib_ops/cuda/cuda_contrib_kernels.cc +++ b/onnxruntime/contrib_ops/cuda/cuda_contrib_kernels.cc @@ -15,10 +15,7 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1 class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, float, Gelu); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, double, Gelu); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, MLFloat16, Gelu); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, float, BiasGelu); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, double, BiasGelu); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, MLFloat16, BiasGelu); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, BFloat16, BiasGelu); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, BiasGelu); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, MLFloat16, BiasSplitGelu); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, float, BiasSplitGelu); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, MLFloat16, BiasAdd); @@ -65,6 +62,8 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1 class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, MLFloat16, Attention); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, float, PackedAttention); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, MLFloat16, PackedAttention); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, float, PackedMultiHeadAttention); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, MLFloat16, PackedMultiHeadAttention); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, BeamSearch); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, float, ConvTransposeWithDynamicPads); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 1, float, Crop); @@ -167,10 +166,7 @@ Status RegisterCudaContribKernels(KernelRegistry& kernel_registry) { BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, + BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, @@ -213,6 +209,8 @@ Status RegisterCudaContribKernels(KernelRegistry& kernel_registry) { BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, diff --git a/onnxruntime/contrib_ops/cuda/diffusion/bias_split_gelu_impl.cu b/onnxruntime/contrib_ops/cuda/diffusion/bias_split_gelu_impl.cu index 8069cbc0a1e0e..19e05a9573f7c 100644 --- a/onnxruntime/contrib_ops/cuda/diffusion/bias_split_gelu_impl.cu +++ b/onnxruntime/contrib_ops/cuda/diffusion/bias_split_gelu_impl.cu @@ -41,7 +41,7 @@ __global__ void biasSplitGeluKernel(T const* input, T const* bias, T* output) { auto value_right = (float)(input[index_input + HHS] + bias[index_bias + HHS]); // Gelu is applied to right side only: Gelu(x) = x * 0.5 * (erf(x / sqrt(2)) + 1.0) - float gelu_right = value_right * 0.5f * (erff(value_right / 1.41421356237f) + 1.0f); + float gelu_right = value_right * 0.5f * (erff(value_right / static_cast(M_SQRT2)) + 1.0f); float result = value_left * gelu_right; output[index_output] = static_cast(result); index_input += TPB; diff --git a/onnxruntime/contrib_ops/cuda/diffusion/group_norm.cc b/onnxruntime/contrib_ops/cuda/diffusion/group_norm.cc index 36a2bd11257d6..301b2e76b1b2d 100644 --- a/onnxruntime/contrib_ops/cuda/diffusion/group_norm.cc +++ b/onnxruntime/contrib_ops/cuda/diffusion/group_norm.cc @@ -66,6 +66,8 @@ GroupNorm::GroupNorm(const OpKernelInfo& op_info) : CudaKernel(op_info) { ORT_ENFORCE(op_info.GetAttr("activation", &activation).IsOK()); ORT_ENFORCE(activation == 0 || activation == 1); // 0 is None, 1 is Swish use_swish_activation_ = (activation == 1); + + channels_last_ = (op_info.GetAttrOrDefault("channels_last", static_cast(1)) != 0); } Status GroupNorm::ComputeInternal(OpKernelContext* context) const { @@ -74,6 +76,11 @@ Status GroupNorm::ComputeInternal(OpKernelContext* context) const { const Tensor* beta = context->Input(2); Tensor* output = context->Output(0, input->Shape()); + if (!channels_last_) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "only the channels_last layout is supported"); + } + const auto& input_dims = input->Shape().GetDims(); if (input_dims.size() != 4) { return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, @@ -111,6 +118,13 @@ Status GroupNorm::ComputeInternal(OpKernelContext* context) const { "number of channels should be divisiable by num_groups"); } + if (context->GetUseDeterministicCompute()) { + static std::once_flag log_warning; + std::call_once(log_warning, []() { + LOGS_DEFAULT(WARNING) << "GroupNorm has no deterministic CUDA kernel, its outputs may still be nondeterministic."; + }); + } + auto workspace = GetScratchBuffer(GetGroupNormWorkspaceSizeInBytes(), context->GetComputeStream()); utils::MLTypeCallDispatcher dispatcher(input->GetElementType()); diff --git a/onnxruntime/contrib_ops/cuda/diffusion/group_norm.h b/onnxruntime/contrib_ops/cuda/diffusion/group_norm.h index 8578a1642198f..52c006e6bdb96 100644 --- a/onnxruntime/contrib_ops/cuda/diffusion/group_norm.h +++ b/onnxruntime/contrib_ops/cuda/diffusion/group_norm.h @@ -20,6 +20,7 @@ class GroupNorm final : public CudaKernel { bool use_swish_activation_; float epsilon_; int num_groups_; + bool channels_last_; }; } // namespace cuda diff --git a/onnxruntime/contrib_ops/cuda/math/bias_gelu.cc b/onnxruntime/contrib_ops/cuda/math/bias_gelu.cc new file mode 100644 index 0000000000000..7815ca49f327c --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/math/bias_gelu.cc @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "contrib_ops/cuda/math/bias_gelu.h" + +#include "contrib_ops/cuda/math/bias_gelu_impl.h" + +using namespace onnxruntime::common; +namespace onnxruntime { +namespace contrib { +namespace cuda { + +ONNX_OPERATOR_KERNEL_EX( + BiasGelu, kMSDomain, 1, kCudaExecutionProvider, + (*KernelDefBuilder::Create()).TypeConstraint("T", BuildKernelDefConstraints()), + BiasGelu); + +template +void BiasGelu::KernelLaunchDispatcher::operator()(cudaStream_t stream, int64_t input_size, int64_t bias_size, + const Tensor& X, const Tensor& B, Tensor& Y) const { + using CudaT = typename ToCudaType::MappedType; + LaunchBiasGeluKernel(stream, input_size, bias_size, reinterpret_cast(X.template Data()), + reinterpret_cast(B.template Data()), + reinterpret_cast(Y.template MutableData())); +} + +Status BiasGelu::ComputeInternal(OpKernelContext* context) const { + const auto* X = context->Input(0); + ORT_ENFORCE(X); + const auto* B = context->Input(1); + ORT_ENFORCE(B); + + const auto& input_shape = X->Shape(); + const auto& bias_shape = B->Shape(); + ORT_ENFORCE(input_shape.NumDimensions() >= 1 && bias_shape.NumDimensions() == 1 && + input_shape.GetDims().back() == bias_shape.GetDims().back(), + "B must be 1-dimensional and match the last dimension of X."); + + auto* Y = context->Output(0, input_shape); + ORT_ENFORCE(Y); + + const auto input_size = input_shape.Size(); + const auto bias_size = bias_shape.Size(); + utils::MLTypeCallDispatcher dispatcher{X->GetElementType()}; + dispatcher.Invoke(Stream(context), input_size, bias_size, *X, *B, *Y); + + return Status::OK(); +} + +} // namespace cuda +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/math/binary_elementwise_ops.h b/onnxruntime/contrib_ops/cuda/math/bias_gelu.h similarity index 51% rename from onnxruntime/contrib_ops/cuda/math/binary_elementwise_ops.h rename to onnxruntime/contrib_ops/cuda/math/bias_gelu.h index 9807321d43856..e27e2523d99d5 100644 --- a/onnxruntime/contrib_ops/cuda/math/binary_elementwise_ops.h +++ b/onnxruntime/contrib_ops/cuda/math/bias_gelu.h @@ -3,10 +3,7 @@ #pragma once -#include "core/providers/cuda/math/binary_elementwise_ops.h" -#include "core/providers/cuda/cuda_common.h" -#include "core/providers/cuda/shared_inc/fast_divmod.h" -#include "core/providers/cpu/tensor/utils.h" +#include "core/providers/cuda/cuda_kernel.h" using namespace onnxruntime::cuda; @@ -15,13 +12,17 @@ namespace contrib { namespace cuda { // AddGelu fuse Add + Gelu -template -class BiasGelu final : public BinaryElementwise { +class BiasGelu final : public CudaKernel { public: - BiasGelu(const OpKernelInfo& info) : BinaryElementwise(info) { - } - + BiasGelu(const OpKernelInfo& info) : CudaKernel(info) {} Status ComputeInternal(OpKernelContext* context) const override; + + private: + template + struct KernelLaunchDispatcher { + void operator()(cudaStream_t stream, int64_t input_size, int64_t bias_size, const Tensor& X, const Tensor& B, + Tensor& Y) const; + }; }; } // namespace cuda diff --git a/onnxruntime/contrib_ops/cuda/math/bias_gelu_impl.cu b/onnxruntime/contrib_ops/cuda/math/bias_gelu_impl.cu new file mode 100644 index 0000000000000..5a13520254e6d --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/math/bias_gelu_impl.cu @@ -0,0 +1,125 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "contrib_ops/cuda/math/bias_gelu_impl.h" + +#include "core/providers/cuda/cu_inc/common.cuh" + +using namespace onnxruntime::cuda; + +namespace onnxruntime { +namespace contrib { +namespace cuda { + +namespace { + +constexpr int kElementsPerThread = GridDim::maxElementsPerThread; +#ifdef USE_ROCM +constexpr int kThreadsPerBlock = 512; +#else +constexpr int kThreadsPerBlock = GridDim::maxThreadsPerBlock; +#endif + +} // namespace + +template +__global__ void BiasGeluKernel(int64_t bias_size, const T* X, const T* B, T* Y) { + const auto kElementsPerBlock = kElementsPerThread * blockDim.x; + const auto input_base_idx = bias_size * blockIdx.x + kElementsPerBlock * blockIdx.y + threadIdx.x; + const auto bias_base_idx = kElementsPerBlock * blockIdx.y + threadIdx.x; + const auto element_stride = blockDim.x; + + T reg_X[kElementsPerThread]; + T reg_B[kElementsPerThread]; + + { + auto input_idx = input_base_idx; + auto bias_idx = bias_base_idx; +#pragma unroll + for (int element_idx = 0; element_idx < kElementsPerThread; ++element_idx) { + if (bias_idx < bias_size) { + reg_X[element_idx] = X[input_idx]; + reg_B[element_idx] = B[bias_idx]; + input_idx += element_stride; + bias_idx += element_stride; + } + } + } + + { + auto input_idx = input_base_idx; + auto bias_idx = bias_base_idx; +#pragma unroll + for (int element_idx = 0; element_idx < kElementsPerThread; ++element_idx) { + if (bias_idx < bias_size) { + Y[input_idx] = _Gelu(reg_X[element_idx] + reg_B[element_idx]); + input_idx += element_stride; + bias_idx += element_stride; + } + } + } +} + +template +__global__ void VectorizedBiasGeluKernel(int64_t bias_size, const T* X, const T* B, T* Y) { + const auto kElementsPerBlock = kElementsPerThread * blockDim.x; + const auto bias_idx = kElementsPerBlock * blockIdx.y + kElementsPerThread * threadIdx.x; + if (bias_idx >= bias_size) { + return; + } + + const auto input_idx = bias_size * blockIdx.x + kElementsPerBlock * blockIdx.y + kElementsPerThread * threadIdx.x; + + using LoadT = aligned_vector; + + T reg_X[kElementsPerThread]; + T reg_B[kElementsPerThread]; + T reg_Y[kElementsPerThread]; + + LoadT* value_X = reinterpret_cast(®_X); + LoadT* value_B = reinterpret_cast(®_B); + *value_X = *reinterpret_cast(&X[input_idx]); + *value_B = *reinterpret_cast(&B[bias_idx]); + +#pragma unroll + for (int element_idx = 0; element_idx < kElementsPerThread; ++element_idx) { + reg_Y[element_idx] = _Gelu(reg_X[element_idx] + reg_B[element_idx]); + } + + *(reinterpret_cast(&Y[input_idx])) = *reinterpret_cast(®_Y[0]); +} + +template +void LaunchBiasGeluKernel(cudaStream_t stream, int64_t input_size, int64_t bias_size, const T* X, const T* B, T* Y) { + // given a 2D grid of blocks: + // each grid column handles bias_size elements + // there are input_size / bias_size columns. + int num_threads_per_block = std::min(static_cast(CeilDiv(bias_size, kElementsPerThread)), kThreadsPerBlock); + const auto grid_width = CeilDiv(bias_size, kElementsPerThread * num_threads_per_block); + const auto grid_height = input_size / bias_size; + const dim3 grid_dim{static_cast(grid_height), static_cast(grid_width)}; + + constexpr int vec_alignment = std::alignment_of>::value; + if (bias_size % kElementsPerThread == 0 && reinterpret_cast(X) % vec_alignment == 0 && + reinterpret_cast(B) % vec_alignment == 0 && reinterpret_cast(Y) % vec_alignment == 0) { + VectorizedBiasGeluKernel<<>>(bias_size, X, B, Y); + } else { + BiasGeluKernel<<>>(bias_size, X, B, Y); + } +} + +// explicit instantiations +#define SPECIALIZED_BIAS_GELU_IMPL(T) \ + template void LaunchBiasGeluKernel(cudaStream_t stream, int64_t input_size, int64_t bias_size, const T* X, \ + const T* B, T* Y) + +SPECIALIZED_BIAS_GELU_IMPL(half); +SPECIALIZED_BIAS_GELU_IMPL(float); +SPECIALIZED_BIAS_GELU_IMPL(double); +SPECIALIZED_BIAS_GELU_IMPL(BFloat16); + +#undef SPECIALIZED_BIAS_GELU_IMPL + +} // namespace cuda +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/math/bias_gelu_impl.h b/onnxruntime/contrib_ops/cuda/math/bias_gelu_impl.h new file mode 100644 index 0000000000000..7679856fc48ec --- /dev/null +++ b/onnxruntime/contrib_ops/cuda/math/bias_gelu_impl.h @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include + +namespace onnxruntime { +namespace contrib { +namespace cuda { + +template +void LaunchBiasGeluKernel(cudaStream_t stream, int64_t input_size, int64_t bias_size, const T* X, const T* B, T* Y); + +} // namespace cuda +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/math/binary_elementwise_ops.cc b/onnxruntime/contrib_ops/cuda/math/binary_elementwise_ops.cc deleted file mode 100644 index 2fb1075f61211..0000000000000 --- a/onnxruntime/contrib_ops/cuda/math/binary_elementwise_ops.cc +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "contrib_ops/cuda/math/binary_elementwise_ops.h" -#include "contrib_ops/cuda/math/binary_elementwise_ops_impl.h" - -using namespace onnxruntime::common; -namespace onnxruntime { -namespace contrib { -namespace cuda { - -#define CONTRIB_BINARY_ELEMENTWISE_REGISTER_KERNEL_TYPED(x, ver, T) \ - ONNX_OPERATOR_TYPED_KERNEL_EX( \ - x, \ - kMSDomain, \ - ver, \ - T, \ - kCudaExecutionProvider, \ - (*KernelDefBuilder::Create()).TypeConstraint("T", DataTypeImpl::GetTensorType()), \ - x); - -#define CONTRIB_BINARY_ELEMENTWISE_COMPUTE(x, T) \ - template <> \ - Status x::ComputeInternal(OpKernelContext* context) const { \ - BinaryElementwisePreparation prepare; \ - ORT_RETURN_IF_ERROR(Prepare(context, &prepare)); \ - Impl_##x::MappedType>( \ - Stream(context), \ - prepare.output_rank_or_simple_broadcast, \ - &prepare.lhs_padded_strides, \ - reinterpret_cast::MappedType*>(prepare.lhs_tensor->Data()), \ - &prepare.rhs_padded_strides, \ - reinterpret_cast::MappedType*>(prepare.rhs_tensor->Data()), \ - &prepare.fdm_output_strides, \ - prepare.fdm_H, \ - prepare.fdm_C, \ - reinterpret_cast::MappedType*>(prepare.output_tensor->MutableData()), \ - prepare.output_tensor->Shape().Size()); \ - return Status::OK(); \ - } - -#define CONTRIB_BINARY_OP_TYPED(name, ver, T) \ - CONTRIB_BINARY_ELEMENTWISE_REGISTER_KERNEL_TYPED(name, ver, T) \ - CONTRIB_BINARY_ELEMENTWISE_COMPUTE(name, T) - -// since different ops has different types, we cannot use BINARY_OPS() directly -// the postfix of means the types supported by the op: -// B: uint8_t -// W: uint16_t -// U: uint32_t -// Z: uint64_t -// C: int8_t -// S: int16_t -// I: int32_t -// L: int64_t -// H: float16 -// F: float -// D: double -// O: bool - -#define CONTRIB_BINARY_OP_HFD(name, ver) \ - CONTRIB_BINARY_OP_TYPED(name, ver, MLFloat16) \ - CONTRIB_BINARY_OP_TYPED(name, ver, float) \ - CONTRIB_BINARY_OP_TYPED(name, ver, double) \ - CONTRIB_BINARY_OP_TYPED(name, ver, BFloat16) - -CONTRIB_BINARY_OP_HFD(BiasGelu, 1) - -} // namespace cuda -} // namespace contrib -} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/math/binary_elementwise_ops_impl.cu b/onnxruntime/contrib_ops/cuda/math/binary_elementwise_ops_impl.cu deleted file mode 100644 index bb522fe9e21fd..0000000000000 --- a/onnxruntime/contrib_ops/cuda/math/binary_elementwise_ops_impl.cu +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include -#include "contrib_ops/cuda/math/binary_elementwise_ops_impl.h" -#include "core/providers/cuda/cu_inc/common.cuh" -#include "core/providers/cuda/cu_inc/binary_elementwise_impl.cuh" - -namespace onnxruntime { -namespace contrib { -namespace cuda { - -#define OP(name, expr) \ - template \ - struct OP_##name { \ - __device__ __inline__ T operator()(T a, T b) const { \ - return (expr); \ - } \ - }; - -#define CONTRIB_BINARY_ELEMENTWISE_IMPL(name) \ - CONTRIB_BINARY_ELEMENTWISE_IMPL_DECLARATION(name) { \ - BinaryElementWiseImpl(stream, \ - output_rank_or_simple_broadcast, \ - lhs_padded_strides, \ - lhs_data, \ - rhs_padded_strides, \ - rhs_data, \ - fdm_output_strides, \ - fdm_H, \ - fdm_C, \ - output_data, \ - OP_##name(), \ - count); \ - } - -#define CONTRIB_SPECIALIZED_BINARY_ELEMENTWISE_IMPL(x, T) \ - template void Impl_##x(cudaStream_t stream, \ - int32_t output_rank, \ - const TArray* lhs_padded_strides, \ - const T* lhs_data, \ - const TArray* rhs_padded_strides, \ - const T* rhs_data, \ - const TArray* fdm_output_strides, \ - const onnxruntime::cuda::fast_divmod& fdm_H, \ - const onnxruntime::cuda::fast_divmod& fdm_C, \ - T* output_data, size_t count); - -#define CONTRIB_SPECIALIZED_BINARY_ELEMENTWISE_IMPL_UZILHFD(x) \ - CONTRIB_SPECIALIZED_BINARY_ELEMENTWISE_IMPL(x, uint32_t) \ - CONTRIB_SPECIALIZED_BINARY_ELEMENTWISE_IMPL(x, uint64_t) \ - CONTRIB_SPECIALIZED_BINARY_ELEMENTWISE_IMPL(x, int32_t) \ - CONTRIB_SPECIALIZED_BINARY_ELEMENTWISE_IMPL(x, int64_t) \ - CONTRIB_SPECIALIZED_BINARY_ELEMENTWISE_IMPL(x, half) \ - CONTRIB_SPECIALIZED_BINARY_ELEMENTWISE_IMPL(x, float) \ - CONTRIB_SPECIALIZED_BINARY_ELEMENTWISE_IMPL(x, double) - -#define CONTRIB_SPECIALIZED_BINARY_ELEMENTWISE_IMPL_OIL(x) \ - CONTRIB_SPECIALIZED_BINARY_ELEMENTWISE_IMPL(x, bool) \ - CONTRIB_SPECIALIZED_BINARY_ELEMENTWISE_IMPL(x, int32_t) \ - CONTRIB_SPECIALIZED_BINARY_ELEMENTWISE_IMPL(x, int64_t) - -#define CONTRIB_SPECIALIZED_BINARY_ELEMENTWISE_IMPL_HFD(x) \ - CONTRIB_SPECIALIZED_BINARY_ELEMENTWISE_IMPL(x, half) \ - CONTRIB_SPECIALIZED_BINARY_ELEMENTWISE_IMPL(x, float) \ - CONTRIB_SPECIALIZED_BINARY_ELEMENTWISE_IMPL(x, double) \ - CONTRIB_SPECIALIZED_BINARY_ELEMENTWISE_IMPL(x, BFloat16) - -// create declarations for op and impl -#define CONTRIB_BINARY_OP_NAME_EXPR(name, expr) \ - OP(name, expr) \ - CONTRIB_BINARY_ELEMENTWISE_IMPL(name) - -CONTRIB_BINARY_OPS() - -#undef CONTRIB_BINARY_OP_NAME_EXPR - -// create specialized impl -// the postfix of means the types supported by the op: -// B: uint8_t -// W: uint16_t -// U: uint32_t -// Z: uint64_t -// C: int8_t -// S: int16_t -// I: int32_t -// L: int64_t -// H: float16 -// F: float -// D: double -// O: bool - -CONTRIB_SPECIALIZED_BINARY_ELEMENTWISE_IMPL_HFD(BiasGelu) - -} // namespace cuda -} // namespace contrib -} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/math/binary_elementwise_ops_impl.h b/onnxruntime/contrib_ops/cuda/math/binary_elementwise_ops_impl.h deleted file mode 100644 index dc0382fcb3887..0000000000000 --- a/onnxruntime/contrib_ops/cuda/math/binary_elementwise_ops_impl.h +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include "core/providers/cuda/shared_inc/cuda_utils.h" - -using namespace onnxruntime::cuda; - -namespace onnxruntime { -namespace contrib { -namespace cuda { -// These macros simplifies coding. To add a new op with following steps: -// 1. Add a new entry in CONTRIB_BINARY_OPS() list -// 2. (optional) Define templated single element operator in binary_elementwise_ops_impl.cu -// 3. (optional) Implement specialized single element operator -// 4. Add op kernel class definition in binary_elementwise_ops.h -// 5. Add op kernel registration and compute specialization in binary_elementwise_ops.cc -#define CONTRIB_BINARY_OPS() \ - CONTRIB_BINARY_OP_NAME_EXPR(BiasGelu, _Gelu(a + b)) - -// NOTE that cu files are compiled with nvcc and should not refer to any onnxruntime headers -// so struct BinaryElementwisePreparation cannot be used here -#define CONTRIB_BINARY_ELEMENTWISE_IMPL_DECLARATION(name) \ - template \ - void Impl_##name( \ - cudaStream_t stream, \ - int32_t output_rank_or_simple_broadcast, \ - const TArray* lhs_padded_strides, \ - const T* lhs_data, \ - const TArray* rhs_padded_strides, \ - const T* rhs_data, \ - const TArray* fdm_output_strides, \ - const onnxruntime::cuda::fast_divmod& fdm_H, \ - const onnxruntime::cuda::fast_divmod& fdm_C, \ - T* output_data, \ - size_t count) -#define CONTRIB_BINARY_OP_NAME_EXPR(name, expr) CONTRIB_BINARY_ELEMENTWISE_IMPL_DECLARATION(name); -CONTRIB_BINARY_OPS() -#undef CONTRIB_BINARY_OP_NAME_EXPR -} // namespace cuda -} // namespace contrib -} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/math/fft_ops.cc b/onnxruntime/contrib_ops/cuda/math/fft_ops.cc index 5fddcd7e937e6..4b524dcf795a2 100644 --- a/onnxruntime/contrib_ops/cuda/math/fft_ops.cc +++ b/onnxruntime/contrib_ops/cuda/math/fft_ops.cc @@ -100,7 +100,7 @@ Status FFTBase::DoFFT(OpKernelContext* context, const Tensor* X, bool complex // process the last dim(s) if (onesided_) { if (complex_input && !complex_output) { // IRFFT - int64_t inferred_size = input_shape[i] * 2 - 1; + int64_t inferred_size = 2 * (input_shape[i] - 1); output_dims.push_back(inferred_size); signal_dims.push_back(inferred_size); } else if (!complex_input && complex_output) { // RFFT diff --git a/onnxruntime/contrib_ops/cuda/quantization/attention_quantization.cc b/onnxruntime/contrib_ops/cuda/quantization/attention_quantization.cc index c155e0b641552..705f2d49fe2bf 100644 --- a/onnxruntime/contrib_ops/cuda/quantization/attention_quantization.cc +++ b/onnxruntime/contrib_ops/cuda/quantization/attention_quantization.cc @@ -174,8 +174,9 @@ Status QAttention::ComputeInternal(OpKernelContext* context) const { Tensor* present = context->Output(1, present_shape); void* fused_runner = nullptr; // TODO(tianleiwu): use fused kernel to speed up - bool use_fused_cross_attention = false; - bool use_memory_efficient_attention = false; + constexpr bool use_fused_cross_attention = false; + constexpr bool use_memory_efficient_attention = false; + constexpr bool use_flash_attention = false; size_t workSpaceSize = GetAttentionWorkspaceSize(element_size, batch_size, parameters.num_heads, @@ -185,6 +186,7 @@ Status QAttention::ComputeInternal(OpKernelContext* context) const { parameters.kv_sequence_length, parameters.total_sequence_length, fused_runner, + use_flash_attention, use_fused_cross_attention, use_memory_efficient_attention); @@ -193,29 +195,23 @@ Status QAttention::ComputeInternal(OpKernelContext* context) const { typedef typename ToCudaType::MappedType CudaT; AttentionData data; data.gemm_buffer = reinterpret_cast(gemm_buffer.get()); - data.bias = nullptr; // bias has been added - data.query = nullptr; - data.key = nullptr; - data.value = nullptr; - data.mask_index = (nullptr == mask_index) ? nullptr : mask_index->Data(); - data.mask_index_dims = (nullptr == mask_index) ? gsl::span() : mask_index->Shape().GetDims(); - data.past = (nullptr == past_tensor) ? nullptr : reinterpret_cast(past_tensor->Data()); - data.past_key = nullptr; - data.past_value = nullptr; - data.relative_position_bias = nullptr; // add_qk is not supported in quantized attention + if (nullptr != mask_index) { + data.mask_index = mask_index->Data(); + data.mask_index_dims = mask_index->Shape().GetDims(); + } + + if (nullptr != past_tensor) { + data.past = reinterpret_cast(past_tensor->Data()); + } + data.has_qkv_workspace = true; data.workspace = reinterpret_cast(work_space.get()); data.output = reinterpret_cast(output->MutableData()); - data.present = (nullptr == present) ? nullptr : reinterpret_cast(present->MutableData()); - data.present_key = nullptr; - data.present_value = nullptr; - data.fused_runner = fused_runner; - data.fused_cross_attention_kernel = nullptr; - data.use_memory_efficient_attention = use_memory_efficient_attention; - data.cumulated_sequence_length_q_cache = nullptr; - data.cumulated_sequence_length_kv_cache = nullptr; - - return QkvToContext(GetDeviceProp(), cublas, Stream(context), parameters, data); + if (nullptr != present) { + data.present = reinterpret_cast(present->MutableData()); + } + + return QkvToContext(GetDeviceProp(), cublas, context->GetComputeStream(), parameters, data); } } // namespace cuda diff --git a/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_attention.cc b/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_attention.cc index 8122b2de5916b..3cecebedae2f0 100644 --- a/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_attention.cc +++ b/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_attention.cc @@ -47,8 +47,6 @@ ONNX_OPERATOR_KERNEL_EX( .InputMemoryType(OrtMemTypeCPUInput, InputIds::Scale_Values_Gemm), QOrderedAttention); -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11040 - Status QOrderedAttention::PutIntoMergedWeight(const Tensor& tensor, AllocatorPtr alloc, int qkv_index, cudaStream_t cuda_stream) { ++qkv_weight_const_count_; ORT_ENFORCE(tensor.Shape().NumDimensions() == 2, "QKV weight must be 2d tensors!"); @@ -155,10 +153,7 @@ inline void debug_print([[maybe_unused]] const T* arr, #endif } -#endif - QOrderedAttention::QOrderedAttention(const OpKernelInfo& info) : CudaKernel(info), AttentionBase(info, true) { -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11040 input_hidden_size_ = 0; int cuda_runtime_version = 0; CUDA_CALL_THROW(cudaRuntimeGetVersion(&cuda_runtime_version)); @@ -183,17 +178,9 @@ QOrderedAttention::QOrderedAttention(const OpKernelInfo& info) : CudaKernel(info qkv_weight_const_count_ = scale_qkv_weight_const_count_ = qkv_bias_const_cout_ = 0; const_scale_input_ = const_scale_qkv_layer_[0] = const_scale_qkv_layer_[1] = const_scale_qkv_layer_[2] = 0.0f; - -#else - - ORT_ENFORCE(false, "Compiling with CUDA_VERSION >= 11.4 is needed!"); - -#endif } Status QOrderedAttention::ComputeInternal(OpKernelContext* context) const { -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11040 - ORT_ENFORCE(qkv_bias_const_cout_ == 3 && scale_qkv_weight_const_count_ == 3 && qkv_weight_const_count_ == 3, "qkv gemm weight and their scales, qkv gemm bias must all be constant!"); ORT_ENFORCE(const_scale_input_ > 0.0f, "input scale must be constant"); @@ -307,13 +294,6 @@ Status QOrderedAttention::ComputeInternal(OpKernelContext* context) const { false, (const float*)context_layer, (float*)output->MutableData())); // debug_print(output->Data(), m * n / 3, head_size, "attention output"); -#else - - ORT_UNUSED_PARAMETER(context); - ORT_ENFORCE(false, "Compiling with CUDA_VERSION >= 11.4 is needed!"); - -#endif - return Status::OK(); } diff --git a/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_attention.h b/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_attention.h index ece573fc3def6..9d4e563c1feab 100644 --- a/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_attention.h +++ b/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_attention.h @@ -18,8 +18,6 @@ class QOrderedAttention final : public CudaKernel, public AttentionBase { Status ComputeInternal(OpKernelContext* context) const override; -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11040 - public: Status PrePack(const Tensor& tensor, int input_idx, AllocatorPtr alloc, /*out*/ bool& is_packed, @@ -43,8 +41,6 @@ class QOrderedAttention final : public CudaKernel, public AttentionBase { Status PutIntoMergedWeight(const Tensor& tensor, AllocatorPtr alloc, int qkv_index, cudaStream_t cuda_stream); Status PutIntoMergedWeightScale(const Tensor& tensor, AllocatorPtr alloc, int qkv_index); Status PutIntoMergedBias(const Tensor& tensor, AllocatorPtr alloc, int qkv_index); - -#endif }; } // namespace cuda diff --git a/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_attention_impl.cu b/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_attention_impl.cu index 3ef89c7848ddf..f4d5a7b404a62 100644 --- a/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_attention_impl.cu +++ b/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_attention_impl.cu @@ -11,8 +11,6 @@ namespace onnxruntime { namespace contrib { namespace cuda { -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11040 - __global__ void BuildTableForSoftmaxPowerOfKernel(const double base, float* table) { int g = threadIdx.x - 255; @@ -164,8 +162,6 @@ Status QOrderBatchTransposeInt8Matrix(cudaStream_t stream, const cudaDeviceProp& return CUDA_CALL(cudaGetLastError()); } -#endif - } // namespace cuda } // namespace contrib } // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_attention_impl.h b/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_attention_impl.h index da1b037d17b07..394a5a811b1e3 100644 --- a/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_attention_impl.h +++ b/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_attention_impl.h @@ -9,8 +9,6 @@ namespace onnxruntime { namespace contrib { namespace cuda { -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11040 - Status BuildTableForSoftmaxPowerOf( cudaStream_t stream, const double base, float* table); @@ -27,8 +25,6 @@ Status QOrderBatchTransposeInt8Matrix( const int batch_size, const int rows, const int cols, const int8_t* input, int8_t* output); -#endif - } // namespace cuda } // namespace contrib } // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_longformer_attention.cc b/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_longformer_attention.cc index 768269452b8d5..4e0140f34e869 100644 --- a/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_longformer_attention.cc +++ b/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_longformer_attention.cc @@ -41,8 +41,6 @@ ONNX_OPERATOR_KERNEL_EX( QOrderedLongformerAttention::QOrderedLongformerAttention(const OpKernelInfo& info) : CudaKernel(info), LongformerAttentionBase(info) { -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11040 - use_compact_memory_ = ParseEnvironmentVariableWithDefault(longformer::kUseCompactMemory, false); const cublasLtOrder_t InputOrders[2] = {CUBLASLT_ORDER_ROW, CUBLASLT_ORDER_COL32}; const cublasLtOrder_t weight_tiles_for_input_col32[2] = {CUBLASLT_ORDER_COL4_4R2_8C, CUBLASLT_ORDER_COL32_2R_4R4}; @@ -68,18 +66,10 @@ QOrderedLongformerAttention::QOrderedLongformerAttention(const OpKernelInfo& inf order_output_ = GetCublasLtOrderAttr( info, "order_output", 1, (const cublasLtOrder_t*)&order_input_, "QOrderedLongformerAttention: oder_output must be same as order_input"); - -#else - - ORT_ENFORCE(false, "Compiling with CUDA_VERSION >= 11.4 is needed!"); - -#endif } Status QOrderedLongformerAttention::ComputeInternal(OpKernelContext* context) const { -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11040 - const Tensor* input = context->Input(0); const Tensor* weights = context->Input(2); const Tensor* bias = context->Input(4); @@ -264,13 +254,6 @@ QOrderedLongformerAttention::ComputeInternal(OpKernelContext* context) const { // Defer release of pinned memory since cudaStreamSynchronize is not used here and kernel need access the buffer. this->AddDeferredReleaseCPUPtr(pinned_buffer.release(), context->GetComputeStream()); -#else - - ORT_UNUSED_PARAMETER(context); - ORT_ENFORCE(false, "Compiling with CUDA_VERSION >= 11.4 is needed!"); - -#endif - return Status::OK(); } diff --git a/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_matmul.cc b/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_matmul.cc index f939a0e895a92..a64f628f245e6 100644 --- a/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_matmul.cc +++ b/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_matmul.cc @@ -33,7 +33,6 @@ ONNX_OPERATOR_KERNEL_EX( QOrderedMatMul); QOrderedMatMul::QOrderedMatMul(const OpKernelInfo& info) : CudaKernel(info) { -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11040 int cuda_runtime_version = 0; CUDA_CALL_THROW(cudaRuntimeGetVersion(&cuda_runtime_version)); ORT_ENFORCE(cuda_runtime_version >= 11040, "QOrderedMatmul need cuda runtime higher than 11.4"); @@ -49,19 +48,11 @@ QOrderedMatMul::QOrderedMatMul(const OpKernelInfo& info) : CudaKernel(info) { const_scale_A_ = const_scale_B_ = const_scale_C_ = const_scale_Y_ = 0.0; origin_scale_B_vector_ = nullptr; const_bias_size_ = 0; - -#else - - ORT_ENFORCE(false, "Compiling with CUDA_VERSION >= 11.4 is needed!"); - -#endif } Status QOrderedMatMul::PrePack(const Tensor& tensor, int input_idx, AllocatorPtr alloc, /*out*/ bool& is_packed, /*out*/ PrePackedWeights* /* prepacked_weights */) { -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11040 - is_packed = false; if (order_B_ == CUBLASLT_ORDER_COL) { if (input_idx == QOrderedMatMulScaleA) { @@ -104,22 +95,10 @@ Status QOrderedMatMul::PrePack(const Tensor& tensor, int input_idx, AllocatorPtr } } -#else - - ORT_UNUSED_PARAMETER(tensor); - ORT_UNUSED_PARAMETER(input_idx); - ORT_UNUSED_PARAMETER(alloc); - ORT_UNUSED_PARAMETER(is_packed); - ORT_ENFORCE(false, "Compiling with CUDA_VERSION >= 11.4 is needed!"); - -#endif - return Status::OK(); } Status QOrderedMatMul::ComputeInternal(OpKernelContext* context) const { -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11040 - ORT_ENFORCE(order_B_ == CUBLASLT_ORDER_COL, "COL32 related order processing will be implemented later!"); int64_t rowsA = 0, colsA = 0, batchA = 1, elementsA = 0; @@ -187,14 +166,6 @@ Status QOrderedMatMul::ComputeInternal(OpKernelContext* context) const { bias, &beta, C, gsl::narrow(batchC), tensor_Y->MutableData(), (cublasLtOrder_t)order_B_, pointer_mode)); - -#else - - ORT_UNUSED_PARAMETER(context); - ORT_ENFORCE(false, "Compiling with CUDA_VERSION >= 11.4 is needed!"); - -#endif - return Status::OK(); } diff --git a/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_matmul_utils.cc b/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_matmul_utils.cc index 95679c5913065..ef814532effe8 100644 --- a/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_matmul_utils.cc +++ b/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_matmul_utils.cc @@ -10,8 +10,6 @@ namespace onnxruntime { namespace contrib { namespace cuda { -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11040 - static Status cublasLtMatMulInt8SetupAlgo(cublasLtHandle_t cublasLt_handle, cublasLtMatmulAlgo_t& algo, int algo_id, int swizzle, int custom_option, int tile, int splitk_val, @@ -121,11 +119,6 @@ Status QOrdered_MatMul(cublasLtHandle_t cublasLt_handle, cudaStream_t stream, int8_t* D, cublasLtOrder_t weight_order, cublasLtPointerMode_t pointer_mode) { -#if defined(CUDA_VERSION) && CUDA_VERSION < 11040 - ORT_RETURN_IF(pointer_mode > CUBLASLT_POINTER_MODE_ALPHA_DEVICE_VECTOR_BETA_ZERO, - "Need CUDA 11.4.2 to support CUBLASLT_POINTER_MODE_ALPHA_DEVICE_VECTOR_BETA_HOST") -#endif - ORT_RETURN_IF(weight_order != CUBLASLT_ORDER_COL, "Weight should be ORDER_COL"); const cublasOperation_t transpose_op = CUBLAS_OP_T; @@ -206,8 +199,6 @@ Status QOrdered_MatMul(cublasLtHandle_t cublasLt_handle, cudaStream_t stream, return Status::OK(); } -#endif - } // namespace cuda } // namespace contrib } // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_matmul_utils.h b/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_matmul_utils.h index bfe9ba2dbba69..d20863228cee0 100644 --- a/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_matmul_utils.h +++ b/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_matmul_utils.h @@ -13,8 +13,6 @@ namespace onnxruntime { namespace contrib { namespace cuda { -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11040 - class CublasLtMMAlgoMap { public: static CublasLtMMAlgoMap& Instance(); @@ -76,8 +74,6 @@ inline Status QOrdered_MatMul(cublasLtHandle_t cublasLt_handle, cudaStream_t str pointer_mode); } -#endif - } // namespace cuda } // namespace contrib } // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_qdq.cc b/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_qdq.cc index 5bd1fe4f45c7c..b4ec1a69a4b72 100644 --- a/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_qdq.cc +++ b/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_qdq.cc @@ -1,5 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. - +#include "core/framework/tensor_shape.h" #include "contrib_ops/cuda/quantization/qordered_ops/qordered_qdq.h" #include "contrib_ops/cuda/quantization/qordered_ops/qordered_qdq_impl.h" #include "gsl/gsl" @@ -38,8 +40,6 @@ ONNX_OPERATOR_KERNEL_EX( .InputMemoryType(OrtMemTypeCPUInput, 1), // scale_A DequantizeWithOrder); -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11040 - void UpdateTileRequire(cublasLtOrder_t order, int64_t& row_tile, int64_t& col_tile) { switch (order) { case CUBLASLT_ORDER_ROW: @@ -91,10 +91,7 @@ cublasLtOrder_t GetCublasLtOrderAttr(const OpKernelInfo& info, const char* order return order; } -#endif - QuantizeWithOrder::QuantizeWithOrder(const OpKernelInfo& info) : CudaKernel(info) { -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11040 int cuda_runtime_version = 0; CUDA_CALL_THROW(cudaRuntimeGetVersion(&cuda_runtime_version)); ORT_ENFORCE(cuda_runtime_version >= 11040, "QOrderedMatmul need cuda runtime higher than 11.4"); @@ -103,17 +100,9 @@ QuantizeWithOrder::QuantizeWithOrder(const OpKernelInfo& info) : CudaKernel(info order_output_ = GetCublasLtOrderAttr(info, "order_output"); ORT_ENFORCE(order_input_ == CUBLASLT_ORDER_ROW, "Only CUBLASLT_ORDER_ROW is supported for order_input"); - -#else - - ORT_UNUSED_PARAMETER(info); - ORT_ENFORCE(false, "Compiling with CUDA_VERSION >= 11.4 is needed!"); - -#endif } DequantizeWithOrder::DequantizeWithOrder(const OpKernelInfo& info) : CudaKernel(info) { -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11040 int cuda_runtime_version = 0; CUDA_CALL_THROW(cudaRuntimeGetVersion(&cuda_runtime_version)); ORT_ENFORCE(cuda_runtime_version >= 11040, "QOrderedMatmul need cuda runtime higher than 11.4"); @@ -129,17 +118,9 @@ DequantizeWithOrder::DequantizeWithOrder(const OpKernelInfo& info) : CudaKernel( "Only CUBLASLT_ORDER_ROW are supported for order_output"); ORT_ENFORCE(order_input_ == CUBLASLT_ORDER_COL32 || order_input_ == CUBLASLT_ORDER_ROW, "Only CUBLASLT_ORDER_COL32 or CUBLASLT_ORDER_ROW is supported for order_input"); -#else - - ORT_UNUSED_PARAMETER(info); - ORT_ENFORCE(false, "Compiling with CUDA_VERSION >= 11.4 is needed!"); - -#endif } Status QuantizeWithOrder::ComputeInternal(OpKernelContext* context) const { -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11040 - int64_t rows = 0, cols = 0, batch = 0, n = 0; const Tensor& input_tensor = *context->Input(0); ORT_RETURN_IF_ERROR(CheckTensorOrder( @@ -178,18 +159,9 @@ Status QuantizeWithOrder::ComputeInternal(OpKernelContext* context) const { } return Status::OK(); - -#else - - ORT_UNUSED_PARAMETER(context); - ORT_ENFORCE(false, "Compiling with CUDA_VERSION >= 11.4 is needed!"); - -#endif } Status DequantizeWithOrder::ComputeInternal(OpKernelContext* context) const { -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11040 - int64_t rows = 0, cols = 0, batch = 0, n = 0; const Tensor& input_tensor = *context->Input(0); @@ -223,13 +195,6 @@ Status DequantizeWithOrder::ComputeInternal(OpKernelContext* context) const { } return Status::OK(); - -#else - - ORT_UNUSED_PARAMETER(context); - ORT_ENFORCE(false, "Compiling with CUDA_VERSION >= 11.4 is needed!"); - -#endif } } // namespace cuda diff --git a/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_qdq_impl.cu b/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_qdq_impl.cu index e99b06fe8925f..baff8e76ec73b 100644 --- a/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_qdq_impl.cu +++ b/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_qdq_impl.cu @@ -14,8 +14,6 @@ namespace onnxruntime { namespace contrib { namespace cuda { -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11040 - template struct DequantizeVec { }; @@ -510,8 +508,6 @@ int64_t CalcLeadingDimensionLt(int64_t rows, int64_t cols, cublasLtOrder_t order } } -#endif - } // namespace cuda } // namespace contrib } // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_qdq_impl.h b/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_qdq_impl.h index 6026ce2a6d2db..c4b2c553bd9ff 100644 --- a/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_qdq_impl.h +++ b/onnxruntime/contrib_ops/cuda/quantization/qordered_ops/qordered_qdq_impl.h @@ -9,8 +9,6 @@ namespace onnxruntime { namespace contrib { namespace cuda { -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11040 - template Status QOrderQuantize( cudaStream_t stream, const cudaDeviceProp& device_prop, @@ -79,8 +77,6 @@ cublasLtOrder_t GetCublasLtOrderAttr( int64_t CalcLeadingDimensionLt( int64_t rows, int64_t cols, cublasLtOrder_t order); -#endif - } // namespace cuda } // namespace contrib } // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/transformers/beam_search.cc b/onnxruntime/contrib_ops/cuda/transformers/beam_search.cc index 8eee86e0d1236..d18460e016444 100644 --- a/onnxruntime/contrib_ops/cuda/transformers/beam_search.cc +++ b/onnxruntime/contrib_ops/cuda/transformers/beam_search.cc @@ -25,6 +25,8 @@ ONNX_OPERATOR_KERNEL_EX( .InputMemoryType(OrtMemTypeCPUInput, 5) // 'length_penalty' needs to be on CPU .InputMemoryType(OrtMemTypeCPUInput, 6) // 'repetition_penalty' needs to be on CPU .InputMemoryType(OrtMemTypeCPUInput, 9) // 'attention_mask' needs to be on CPU + .InputMemoryType(OrtMemTypeCPUInput, 10) // 'decoder_input_ids' needs to be on CPU + .InputMemoryType(OrtMemTypeCPUInput, 11) // 'logits_processor' needs to be on CPU .OutputMemoryType(OrtMemTypeCPUOutput, 0) // 'sequences' output on CPU .OutputMemoryType(OrtMemTypeCPUOutput, 1) // 'sequences_scores' output on CPU .TypeConstraint("T", {DataTypeImpl::GetTensorType(), @@ -35,16 +37,19 @@ transformers::CudaTensorConsoleDumper g_cuda_dumper; BeamSearch::BeamSearch(const OpKernelInfo& info) : onnxruntime::contrib::transformers::BeamSearch(info) { - SetDeviceHelpers(GenerationCudaDeviceHelper::ReorderPastState, - GenerationCudaDeviceHelper::InitCacheIndir, - GenerationCudaDeviceHelper::AddToFeeds, + SetDeviceHelpers(GenerationCudaDeviceHelper::AddToFeeds, GenerationCudaDeviceHelper::TopK, GenerationCudaDeviceHelper::DeviceCopy, GenerationCudaDeviceHelper::DeviceCopy, GenerationCudaDeviceHelper::ProcessLogits, GenerationCudaDeviceHelper::ProcessLogits, GenerationCudaDeviceHelper::InitBeamState, - GenerationCudaDeviceHelper::InitBeamState); + GenerationCudaDeviceHelper::InitBeamState, + GenerationCudaDeviceHelper::CreateBeamScorer); + +#ifndef USE_ROCM + SetDeviceHelpers_Cuda(GenerationCudaDeviceHelper::ReorderPastState, GenerationCudaDeviceHelper::InitCacheIndir); +#endif SetDeviceHelpers_Gpt(GenerationCudaDeviceHelper::UpdateGptFeeds, GenerationCudaDeviceHelper::UpdateGptFeeds); @@ -57,10 +62,12 @@ BeamSearch::BeamSearch(const OpKernelInfo& info) SetConsoleDumper(&g_cuda_dumper); +#ifndef USE_ROCM cuda_device_prop_ = &reinterpret_cast(info.GetExecutionProvider())->GetDeviceProp(); cuda_device_arch_ = static_cast(cuda_device_prop_)->major * 100 + static_cast(cuda_device_prop_)->minor * 10; +#endif } Status BeamSearch::ComputeInternal(OpKernelContext* context) const { diff --git a/onnxruntime/contrib_ops/cuda/transformers/beam_search_topk.cu b/onnxruntime/contrib_ops/cuda/transformers/beam_search_topk.cu index dcbc733f2acb2..5ac10f6321e63 100644 --- a/onnxruntime/contrib_ops/cuda/transformers/beam_search_topk.cu +++ b/onnxruntime/contrib_ops/cuda/transformers/beam_search_topk.cu @@ -139,10 +139,7 @@ __launch_bounds__(thread_block_size) __global__ void BeamSearchOnlineTopKStage2K input_tokens += vector_id * k * parts_per_beam; TopK thread_topk; - for (int i = 0; i < max_k; ++i) { - thread_topk.key[i] = -1; - thread_topk.value[i] = NumericLimits::Min(); - } + thread_topk.Init(); for (int idx = thread_id; idx < k * parts_per_beam; idx += thread_block_size) { value_shared_buf[idx] = input_values[idx]; diff --git a/onnxruntime/contrib_ops/cuda/transformers/generation_cuda_impl.cu b/onnxruntime/contrib_ops/cuda/transformers/generation_cuda_impl.cu index dd5c97c517da9..07a8896210d2c 100644 --- a/onnxruntime/contrib_ops/cuda/transformers/generation_cuda_impl.cu +++ b/onnxruntime/contrib_ops/cuda/transformers/generation_cuda_impl.cu @@ -6,6 +6,7 @@ #include "cub/util_type.cuh" #include #include +#include "contrib_ops/cuda/bert/utils.cuh" #include "contrib_ops/cuda/transformers/generation_cuda_impl.h" namespace onnxruntime { @@ -74,7 +75,7 @@ __global__ void LogitsProcessKernel( int padded_vocab_size, int total_elements, int demote_token_id, - int32_t* sequences, + const int32_t* sequences, int max_sequence_length, int current_sequence_length, float repetition_penalty, @@ -90,7 +91,7 @@ __global__ void LogitsProcessKernel( } else { // RepetitionPenaltyLogitsProcessor if (repetition_penalty != 1.0f) { - int32_t* current_sequence = sequences + batch_beam_index * max_sequence_length; + const int32_t* current_sequence = sequences + batch_beam_index * max_sequence_length; bool found = false; for (int i = 0; i < current_sequence_length; i++) { if (current_sequence[i] == word_id) { @@ -106,7 +107,7 @@ __global__ void LogitsProcessKernel( // NoRepeatNGramLogitsProcessor if (no_repeat_ngram_size > 0 && current_sequence_length >= no_repeat_ngram_size) { - int32_t* current_sequence = sequences + batch_beam_index * max_sequence_length; + const int32_t* current_sequence = sequences + batch_beam_index * max_sequence_length; bool found = false; for (int i = no_repeat_ngram_size - 1; i < current_sequence_length; i++) { if (current_sequence[i] == word_id) { // last token of n-gram matched @@ -175,7 +176,7 @@ void LaunchLogitsProcessKernel( int vocab_size, int padded_vocab_size, int demote_token_id, - int32_t* sequences, + const int32_t* sequences, int max_sequence_length, int current_sequence_length, float repetition_penalty, @@ -216,7 +217,7 @@ template void LaunchLogitsProcessKernel( int vocab_size, int padded_vocab_size, int demote_token_id, - int32_t* sequences, + const int32_t* sequences, int max_sequence_length, int current_sequence_length, float repetition_penalty, @@ -235,13 +236,322 @@ template void LaunchLogitsProcessKernel( int vocab_size, int padded_vocab_size, int demote_token_id, - int32_t* sequences, + const int32_t* sequences, int max_sequence_length, int current_sequence_length, float repetition_penalty, int no_repeat_ngram_size, cudaStream_t stream); +__global__ void InitializeBeamHypotheses(BeamHypotheses* beam_hyps, int beam_hyps_count, float length_penalty, HypothesisScore* beams, int num_beams) { + int index = blockIdx.x * blockDim.x + threadIdx.x; + if (index >= beam_hyps_count) + return; + + BeamHypotheses& beam_hyp = beam_hyps[index]; + beam_hyp.beams_ = beams + index * num_beams; + beam_hyp.beams_count_ = num_beams; + beam_hyp.beams_used_ = 0; + beam_hyp.length_penalty_ = length_penalty; + beam_hyp.done_ = false; +} + +// For counts that are typically far less than 256, this will round up the count to the next multiple of 32 +// If this winds up being >256 then it uses a block size of 256 and calculates the appropriate grid_size +struct GridBlock32 { + GridBlock32(int count) { + block_size_ = (count + 31) & ~31; // Round up to nearest multiple of 32 + if (block_size_ > 256) { + grid_size_ = (block_size_ + 255) / 256; + block_size_ = 256; + } + } + + int grid_size_{1}; + int block_size_; +}; + +void LaunchInitializeBeamHypotheses(gsl::span beam_hyps, + float length_penalty, + gsl::span beams, + int num_beams, + cudaStream_t stream) { + GridBlock32 gb32{static_cast(beam_hyps.size())}; + InitializeBeamHypotheses<<>>(beam_hyps.data(), + static_cast(beam_hyps.size()), + length_penalty, + beams.data(), + num_beams); +} + +__device__ void BeamHypotheses::Add(const int32_t* hypothesis, int hypothesis_length, float sum_logprobs) { + float score = sum_logprobs / pow(static_cast(hypothesis_length), length_penalty_); + + size_t index = beams_used_; + // If the array is full, don't add unless it's better than the worst element + if (index == beams_count_) { + if (score <= beams_[--index].score) + return; + } else + beams_used_++; + + // Rotate existing elements over while the new element scores higher + for (; index > 0 && score > beams_[index - 1].score; index--) + beams_[index] = beams_[index - 1]; + + beams_[index] = HypothesisScore{hypothesis, hypothesis_length, score}; +} + +__device__ bool BeamHypotheses::CanImprove(float best_sum_logprobs, int current_length) const { + float current_score = best_sum_logprobs / pow(static_cast(current_length), length_penalty_); + return beams_[beams_count_ - 1].score < current_score; +} + +__device__ void BeamHypotheses::Output( + int top_k, + int max_length, + int pad_token_id, + int32_t* sequences, // buffer of shape (num_return_sequences, max_length) + float* sequences_scores) // buffer of shape (num_return_sequences) or empty +{ + // Copy the top_k beams into the sequences + for (int index = 0; index < top_k; index++) { + auto& item = beams_[index]; + int32_t* target = sequences + index * max_length; + + // Note that word_ids might be less than max_length. + for (int i = 0; i < item.hypothesis_length; i++) + target[i] = item.hypothesis[i]; + // Pad remaining values with pad token id + for (int i = item.hypothesis_length; i < max_length; i++) + target[i] = pad_token_id; + + if (sequences_scores) + sequences_scores[index] = item.score; + } +} + +__global__ void BeamSearchScorer_Process(BeamScorerState& state_cpu, + BeamScorerState& state, + const int32_t* sequences_buffer, + int sequence_length, + BeamHypotheses* beam_hyps_, + float* next_beam_scores_, + int32_t* next_beam_tokens_, + int32_t* next_beam_indices_, + int32_t* hypothesis_buffer_, + const float* next_scores, + const int32_t* next_tokens, + const int32_t* next_indices) { + // Sequences shape is (batch_size * num_beams, total_sequence_length) + // It contains word ID of whole sequence generated so far. + // It is different from subgraph input_ids, which only need one word when past state is not empty. + + int batch = threadIdx.x; + int batch_start = batch * state.num_beams_; + + cuda::BeamHypotheses& beam_hyp = beam_hyps_[batch]; + if (!beam_hyp.done_) { + // Next tokens for this sentence. + size_t beam_idx = 0; + size_t top_k = 2 * state.num_beams_; + for (size_t j = 0; j < top_k; j++) { + int32_t next_token = next_tokens[batch * top_k + j]; + float next_score = next_scores[batch * top_k + j]; + int32_t next_index = next_indices[batch * top_k + j]; + + int batch_beam_idx = batch_start + next_index; + // Add to generated hypotheses if end of sentence. + if ((state.eos_token_id_ >= 0) && (next_token == state.eos_token_id_)) { + bool is_beam_token_worse_than_top_num_beams = (j >= state.num_beams_); + if (is_beam_token_worse_than_top_num_beams) { + continue; + } + + // Clone the sequence and append to buffer. + const int32_t* src = sequences_buffer + batch_beam_idx * state.max_length_; + auto clone = hypothesis_buffer_ + atomicAdd(&state.hypothesis_buffer_used_, sequence_length); + + for (unsigned i = 0; i < sequence_length; i++) + clone[i] = src[i]; + beam_hyp.Add(clone, sequence_length, next_score); + } else { + // Add next predicted token since it is not eos_token. + next_beam_scores_[batch_start + beam_idx] = next_score; + next_beam_tokens_[batch_start + beam_idx] = next_token; + next_beam_indices_[batch_start + beam_idx] = batch_beam_idx; + ++beam_idx; + } + + // Once the beam for next step is full, don't add more tokens to it. + if (beam_idx == state.num_beams_) + break; + } + + // Check if we are done so that we can save a pad step if all(done) + if (beam_hyp.beams_used_ == state.num_beams_) { + if (state.early_stopping_ || !beam_hyp.CanImprove(*std::max_element(next_scores + batch_start, next_scores + batch_start + top_k), sequence_length)) { + beam_hyp.done_ = true; + if (atomicAdd(&state.not_done_count_, -1) == 1) + state_cpu.not_done_count_ = 0; // Update the CPU side + } + } + } else { + // Pad the batch. + for (size_t beam_idx = 0; beam_idx < state.num_beams_; beam_idx++) { + next_beam_scores_[batch_start + beam_idx] = 0.0f; + next_beam_tokens_[batch_start + beam_idx] = state.pad_token_id_; + next_beam_indices_[batch_start + beam_idx] = 0; + } + } +} + +void LaunchBeamSearchScorer_Process(BeamScorerState& state_cpu, + BeamScorerState& state, + gsl::span sequences, + int sequence_length, + gsl::span beam_hyps, + gsl::span next_beam_scores, + gsl::span next_beam_tokens, + gsl::span next_beam_indices, + gsl::span hypothesis_buffer, + gsl::span next_scores, + gsl::span next_tokens, + gsl::span next_indices, + cudaStream_t stream) { + BeamSearchScorer_Process<<<1, state_cpu.batch_size_, 0, stream>>>(state_cpu, + state, + sequences.data(), + sequence_length, + beam_hyps.data(), + next_beam_scores.data(), + next_beam_tokens.data(), + next_beam_indices.data(), + hypothesis_buffer.data(), + next_scores.data(), + next_tokens.data(), + next_indices.data()); +} + +__global__ void BeamSearchScorer_AppendNextTokenToSequences1(BeamScorerState& state, + int batch_beam_size, + const int32_t* sequences_buffer, + int32_t* next_sequences, + int sequence_length, + int32_t* next_beam_indices_) { + int beam_idx = threadIdx.x + blockIdx.x * blockDim.x; + if (beam_idx >= batch_beam_size) + return; + int sequence_index = threadIdx.y + blockIdx.y * blockDim.y; + if (sequence_index >= sequence_length) + return; + + int beam_index = next_beam_indices_[beam_idx]; + next_sequences[beam_idx * state.max_length_ + sequence_index] = sequences_buffer[beam_index * state.max_length_ + sequence_index]; +} + +__global__ void BeamSearchScorer_AppendNextTokenToSequences2(BeamScorerState& state, + int32_t* next_sequences, + int sequence_length, + const int32_t* next_beam_tokens_) { + int beam_idx = threadIdx.x; + next_sequences[beam_idx * state.max_length_ + sequence_length] = next_beam_tokens_[beam_idx]; +} + +void LaunchBeamSearchScorer_AppendNextTokenToSequences(BeamScorerState& state_cpu, + BeamScorerState& state, + gsl::span sequences, + gsl::span next_sequences, + int sequence_length, + gsl::span next_beam_tokens, + gsl::span next_beam_indices, + cudaStream_t stream) { + const int max_threads = 512; + int batch_beam_size = state_cpu.batch_size_ * state_cpu.num_beams_; + dim3 block_size; + dim3 grid_size; + if (batch_beam_size * sequence_length <= max_threads) { // Can fit into a single thread block + block_size.x = batch_beam_size; + block_size.y = sequence_length; + } else { + if (sequence_length <= max_threads) // Sequence length fits into thread block, but batch_beam_size does not, so chunk it + { + block_size.x = max_threads / sequence_length; + block_size.y = sequence_length; + + grid_size.x = (batch_beam_size + block_size.x - 1) / block_size.x; + } else { // Exceed max_threads in every dimension, so divide into max_thread chunks + block_size.x = 1; + block_size.y = max_threads; + + grid_size.x = batch_beam_size; + grid_size.y = (sequence_length + block_size.y - 1) / block_size.y; + } + } + BeamSearchScorer_AppendNextTokenToSequences1<<>>(state, + batch_beam_size, + sequences.data(), + next_sequences.data(), + sequence_length, + next_beam_indices.data()); + + BeamSearchScorer_AppendNextTokenToSequences2<<<1, batch_beam_size, 0, stream>>>(state, + next_sequences.data(), + sequence_length, + next_beam_tokens.data()); +} + +__global__ void BeamSearchScorer_Finalize(BeamScorerState& state, + const int32_t* sequences_buffer, + int sequence_length, + BeamHypotheses* beam_hyps_, + const float* final_beam_scores, + int32_t* output, + float* sequence_scores) { + int batch_index = blockIdx.x * blockDim.x + threadIdx.x; + if (batch_index >= state.batch_size_) + return; + + // Finalize all open beam hypotheses and add to generated hypotheses. + cuda::BeamHypotheses& beam_hyp = beam_hyps_[batch_index]; + if (!beam_hyp.done_) { + for (size_t beam_index = 0; beam_index < state.num_beams_; beam_index++) { + size_t batch_beam_index = batch_index * state.num_beams_ + beam_index; + float final_score = final_beam_scores[batch_beam_index]; + auto final_tokens = sequences_buffer + batch_beam_index * state.max_length_; + beam_hyp.Add(final_tokens, sequence_length, final_score); + } + } + + // Select the best hypotheses according to number of sequences to return. + auto batch_output = output + batch_index * state.num_return_sequences_ * state.max_length_; + + beam_hyp.Output( + state.num_return_sequences_, + state.max_length_, + state.pad_token_id_, + batch_output, + sequence_scores ? sequence_scores + batch_index * state.num_return_sequences_ : nullptr); +} + +void LaunchBeamSearchScorer_Finalize(int batch_size, + BeamScorerState& state, + gsl::span sequences, + int sequence_length, + gsl::span beam_hyps, + gsl::span final_beam_scores, + gsl::span output, + gsl::span sequence_scores, + cudaStream_t stream) { + BeamSearchScorer_Finalize<<<1, batch_size, 0, stream>>>(state, + sequences.data(), + sequence_length, + beam_hyps.data(), + final_beam_scores.data(), + output.data(), + sequence_scores.data()); +} + __global__ void AddProbsKernel(float* log_probs, float* cum_log_probs, const int vocab_size, @@ -727,7 +1037,7 @@ void TorchMultinomialKernelLauncher(float* d_input, int numSM = props.multiProcessorCount; int maxThreads = props.maxThreadsPerBlock; - int warp_size = 32; // at::cuda::warp_size(); + int warp_size = props.warpSize; int requiredWarps = (vocab_size + warp_size - 1) / warp_size; int requiredThreads = std::min(maxThreads, requiredWarps * warp_size); int requiredShared = requiredThreads * sizeof(float); @@ -805,6 +1115,206 @@ void UpdateDecoderMaskedMultiHeadAttentionCacheIndirection(int32_t* tgt_indir_ca max_seq_length, current_length); } + +#ifndef USE_ROCM +namespace { +template +struct TypeMapper : public V_vec_m_ {}; + +template <> +struct TypeMapper { + using Type = uint2; +}; + +template <> +struct TypeMapper { + using Type = uint4; +}; +} // namespace +#endif + +template +__global__ void KeyCacheExpansionKernel(const T* input, + T* output, + int beam_width, + int max_seq_length, + int head_size) { + const int num_heads = gridDim.y; + const int sequence_length = gridDim.z; + + const int bbid = blockIdx.x; + const int batch_id = bbid / beam_width; + const int head_id = blockIdx.y; + const int s = blockIdx.z; + const int tidx = threadIdx.x; + + const int input_offset = ((batch_id * num_heads + head_id) * sequence_length + s) * head_size + tidx; + const int output_offset = ((bbid * num_heads + head_id) * max_seq_length + s) * head_size + tidx; + + if (tidx < head_size) { + output[output_offset] = input[input_offset]; + } +} + +template +void KeyCacheExpansionKernelLauncher(const T* key_cache, + T* key_cache_expanded, + int batch_size, + int beam_width, + int num_heads, + int sequence_length, + int max_seq_length, + int head_size, + cudaStream_t stream) { + const dim3 grid(batch_size * beam_width, num_heads, sequence_length); + + int equiv_head_size = (head_size & 1) == 0 ? (head_size >> 1) : head_size; + equiv_head_size = (equiv_head_size & 1) == 0 ? (equiv_head_size >> 1) : equiv_head_size; + + // Here we know head_size is smaller than max_thread_num_per_block + int tpb = std::max(GPU_WARP_SIZE_HOST, equiv_head_size); + + // round up tpb to power of 2 + --tpb; + tpb |= (tpb >> 1); + tpb |= (tpb >> 2); + tpb |= (tpb >> 4); + tpb |= (tpb >> 8); + tpb |= (tpb >> 16); + tpb++; + +#ifndef USE_ROCM + if ((head_size % 4) == 0) { + using vec_type = typename TypeMapper::Type; + const dim3 block(tpb); + KeyCacheExpansionKernel<<>>(reinterpret_cast(key_cache), + reinterpret_cast(key_cache_expanded), + beam_width, + max_seq_length, + equiv_head_size); + } else if ((head_size & 1) == 0) { + using vec_type = typename TypeMapper::Type; + const dim3 block(tpb); + KeyCacheExpansionKernel<<>>(reinterpret_cast(key_cache), + reinterpret_cast(key_cache_expanded), + beam_width, + max_seq_length, + equiv_head_size); + } else { +#endif + const dim3 block(tpb); + KeyCacheExpansionKernel<<>>(key_cache, + key_cache_expanded, + beam_width, + max_seq_length, + head_size); +#ifndef USE_ROCM + } +#endif +} + +template void KeyCacheExpansionKernelLauncher(const float* key_cache, + float* key_cache_expanded, + int batch_size, + int beam_width, + int num_heads, + int sequence_length, + int max_seq_length, + int head_size, + cudaStream_t stream); + +template void KeyCacheExpansionKernelLauncher(const half* key_cache, + half* key_cache_expanded, + int batch_size, + int beam_width, + int num_heads, + int sequence_length, + int max_seq_length, + int head_size, + cudaStream_t stream); + +template void KeyCacheExpansionKernelLauncher(const int32_t* key_cache, + int32_t* key_cache_expanded, + int batch_size, + int beam_width, + int num_heads, + int sequence_length, + int max_seq_length, + int head_size, + cudaStream_t stream); + +template +__global__ void BufferExpansionKernel(const T* input, + T* output, + int chunk_size) { + const int batch_id = blockIdx.x; + const int beam_id = blockIdx.y; + const int tidx = threadIdx.x; + const int beam_size = gridDim.y; + const int idx = blockIdx.z * blockDim.x + tidx; + + const int input_offset = batch_id * chunk_size + idx; + const int output_offset = batch_id * beam_size * chunk_size + beam_id * chunk_size + idx; + + if (idx < chunk_size) { + output[output_offset] = input[input_offset]; + } +} + +template +void BufferExpansionKernelLauncher(const T* input, + T* output, + int batch_size, + int beam_width, + int chunk_size, + cudaStream_t stream) { + const dim3 block(128); + +#ifndef USE_ROCM + if ((chunk_size % 4) == 0) { + using vec_type = typename TypeMapper::Type; + const dim3 grid(batch_size, beam_width, (chunk_size / 4 + block.x - 1) / block.x); + BufferExpansionKernel<<>>(reinterpret_cast(input), + reinterpret_cast(output), + chunk_size / 4); + } else if ((chunk_size & 1) == 0) { + using vec_type = typename TypeMapper::Type; + const dim3 grid(batch_size, beam_width, (chunk_size / 2 + block.x - 1) / block.x); + BufferExpansionKernel<<>>(reinterpret_cast(input), + reinterpret_cast(output), + chunk_size / 2); + } else { +#endif + const dim3 grid(batch_size, beam_width, (chunk_size + block.x - 1) / block.x); + BufferExpansionKernel<<>>(input, + output, + chunk_size); +#ifndef USE_ROCM + } +#endif +} + +template void BufferExpansionKernelLauncher(const float* input, + float* output, + int batch_size, + int beam_width, + int chunk_size, + cudaStream_t stream); + +template void BufferExpansionKernelLauncher(const half* input, + half* output, + int batch_size, + int beam_width, + int chunk_size, + cudaStream_t stream); + +template void BufferExpansionKernelLauncher(const int32_t* input, + int32_t* output, + int batch_size, + int beam_width, + int chunk_size, + cudaStream_t stream); + } // namespace cuda } // namespace contrib } // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/transformers/generation_cuda_impl.h b/onnxruntime/contrib_ops/cuda/transformers/generation_cuda_impl.h index 87b551b453ec5..8c52f6fd52385 100644 --- a/onnxruntime/contrib_ops/cuda/transformers/generation_cuda_impl.h +++ b/onnxruntime/contrib_ops/cuda/transformers/generation_cuda_impl.h @@ -38,13 +38,88 @@ void LaunchLogitsProcessKernel( int vocab_size, int padded_vocab_size, int demote_token_id, - int32_t* sequences, + const int32_t* sequences, int max_sequence_length, int current_sequence_length, float repetition_penalty, int no_repeat_ngram_size, cudaStream_t stream); +struct HypothesisScore { + const int32_t* hypothesis; + int hypothesis_length; + float score; +}; + +struct BeamHypotheses { + HypothesisScore* beams_; // Beam width sized array of hypotheses, sorted by highest scoring + int beams_count_; + int beams_used_; // Number of elements used in beams_ + float length_penalty_; + bool done_; + + // Add a new hypothesis + __device__ void Add(const int32_t* hypothesis, int hypothesis_length, float sum_logprobs); + + // Return true if this beats the worst score in the hypothesis + __device__ bool CanImprove(float best_sum_logprobs, int current_length) const; + + // Output results + __device__ void Output(int top_k, // number of sequences to return + int max_length, // max sequence length + int pad_token_id, // pad token + int32_t* sequences, // buffer with pad token, shape (num_return_sequences, max_length) + float* sequences_scores); // buffer for sequence scores, with shape (num_return_sequences) +}; + +struct BeamScorerState { + int batch_size_; + int num_beams_; + int max_length_; + int num_return_sequences_; + int pad_token_id_; + int eos_token_id_; + bool early_stopping_; + int not_done_count_; // When zero, every batch entry is done (starts at batch_size_) + + int hypothesis_buffer_used_; // Offset of available buffer, or length of used buffer. +}; + +void LaunchInitializeBeamHypotheses(gsl::span beam_hyps, float length_penalty, gsl::span beams, int num_beams, cudaStream_t stream); + +void LaunchBeamSearchScorer_Process(BeamScorerState& state_cpu, + BeamScorerState& state, + gsl::span sequences, + int sequence_length, + gsl::span beam_hyps_, + gsl::span next_beam_scores_, + gsl::span next_beam_tokens_, + gsl::span next_beam_indices_, + gsl::span hypothesis_buffer_, + gsl::span next_scores, + gsl::span next_tokens, + gsl::span next_indices, + cudaStream_t stream); + +void LaunchBeamSearchScorer_AppendNextTokenToSequences(BeamScorerState& state_cpu, + BeamScorerState& state, + gsl::span sequences, + gsl::span next_sequences, + int sequence_length, + gsl::span next_beam_tokens, + gsl::span next_beam_indices, + cudaStream_t stream); + +void LaunchBeamSearchScorer_Finalize(int batch_size, + BeamScorerState& state, + gsl::span sequences, + int sequence_length, + gsl::span beam_hyps_, + gsl::span final_beam_scores, + gsl::span output, + gsl::span sequence_scores, + cudaStream_t stream); + void LaunchNextTokenKernel(const int64_t* next_token_indices, int32_t* next_indices, int32_t* next_tokens, @@ -119,6 +194,25 @@ void UpdateDecoderMaskedMultiHeadAttentionCacheIndirection(int32_t* tgt_indir_ca int current_length, cudaStream_t stream); +template +void KeyCacheExpansionKernelLauncher(const T* key_cache, + T* key_cache_expanded, + int batch_size, + int beam_width, + int num_heads, + int sequence_length, + int max_seq_length, + int head_size, + cudaStream_t stream); + +template +void BufferExpansionKernelLauncher(const T* input, + T* output, + int batch_size, + int beam_width, + int chunk_size, + cudaStream_t stream); + } // namespace cuda } // namespace contrib } // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/cuda/transformers/generation_device_helper.cc b/onnxruntime/contrib_ops/cuda/transformers/generation_device_helper.cc index b51c022c3e572..e4de33499c6ca 100644 --- a/onnxruntime/contrib_ops/cuda/transformers/generation_device_helper.cc +++ b/onnxruntime/contrib_ops/cuda/transformers/generation_device_helper.cc @@ -147,6 +147,7 @@ Status TopK(const Tensor* input, const int axis, const unsigned k, bool largest, Status result; if (input->IsDataType()) { result = TopKImpl(nullptr, // We limit number of beams in BeamSearchParameters, so K <= 256 and use NULL here + false /*use_deterministic_compute*/, stream, input->Data(), static_cast(output_values.MutableDataRaw()), @@ -161,6 +162,7 @@ Status TopK(const Tensor* input, const int axis, const unsigned k, bool largest, dimension); } else if (input->IsDataType()) { result = TopKImpl(nullptr, + false /*use_deterministic_compute*/, stream, input->Data(), static_cast(output_values.MutableDataRaw()), @@ -185,18 +187,19 @@ Status TopK(const Tensor* input, const int axis, const unsigned k, bool largest, return result; } -Status AddToFeeds(const IExecutionProvider* execution_provider, - Stream* ort_stream, +Status AddToFeeds(Stream* ort_stream, std::initializer_list inputs, std::vector& feeds, - IAllocatorUniquePtr& buffer) { + IAllocatorUniquePtr& buffer, + AllocatorPtr device_allocator, + AllocatorPtr host_allocator, + const OrtMemoryInfo& location) { #ifdef ENABLE_NVTX_PROFILE profile::NvtxNestedRangeCreator addToFeedsRange("AddToFeeds", profile::Color::Blue); addToFeedsRange.Begin(); #endif // Copy tensors to GPU, then add to feeds - const CUDAExecutionProvider* provider = reinterpret_cast(execution_provider); size_t total_bytes = 0; for (auto& input : inputs) { if (input.IsAllocated()) { @@ -206,9 +209,8 @@ Status AddToFeeds(const IExecutionProvider* execution_provider, ORT_ENFORCE(total_bytes > 0); - AllocatorPtr pinned_allocator = provider->GetAllocator(OrtMemTypeCPU); cudaStream_t stream = ort_stream ? static_cast(ort_stream->GetHandle()) : nullptr; - auto pinned_buffer = IAllocator::MakeUniquePtr(pinned_allocator, total_bytes); + auto pinned_buffer = IAllocator::MakeUniquePtr(host_allocator, total_bytes); char* pinned_data = static_cast(pinned_buffer.get()); // Copy tensors to one pinned memory buffer (so that we only need copy to GPU once) char* destination = pinned_data; @@ -235,7 +237,7 @@ Status AddToFeeds(const IExecutionProvider* execution_provider, } } if (!buffer) { - buffer = provider->GetScratchBuffer(total_bytes, ort_stream, WaitCudaNotificationOnDevice); + buffer = IAllocator::MakeUniquePtr(device_allocator, total_bytes, false, ort_stream, WaitCudaNotificationOnDevice); } char* gpu_data = buffer.get(); CUDA_RETURN_IF_ERROR(cudaMemcpyAsync(gpu_data, pinned_data, total_bytes, cudaMemcpyHostToDevice, stream)); @@ -247,7 +249,6 @@ Status AddToFeeds(const IExecutionProvider* execution_provider, CUDA_RETURN_IF_ERROR(cudaEventRecord(isCopyDone, stream)); CUDA_RETURN_IF_ERROR(cudaEventSynchronize(isCopyDone)); // TODO(tianleiwu): allocate a buffer for subgraph inputs so that we can reuse the buffer in each subgraph call. - const OrtMemoryInfo& location = provider->GetAllocator(OrtMemTypeDefault)->Info(); for (auto& input : inputs) { if (input.IsAllocated()) { const Tensor& tensor = input.Get(); @@ -328,7 +329,6 @@ void InitGreedyState(transformers::IGreedySearchState* greedy_state, template Status ProcessLogits(const OrtValue& logits, // logits output of subgraph transformers::IBeamSearchState* beam_state, // state - transformers::IBeamSearchCpuState* cpu_state, // state in CPU transformers::ISequences* sequences, // sequences AllocatorPtr& allocator, // default allocator onnxruntime::concurrency::ThreadPool* thread_pool, // thread pool (for CPU only) @@ -417,7 +417,7 @@ Status ProcessLogits(const OrtValue& logits, // const CudaT* X_data = is_reuse_logits_buffer ? logits_data : reinterpret_cast(next_token_logits.data()); ORT_RETURN_IF_ERROR((dispatch_blockwise_softmax_forward( - cuda_stream, Y_data, X_data, vocab_size, + ort_stream, Y_data, X_data, vocab_size, is_reuse_logits_buffer ? padded_vocab_size : vocab_size, vocab_size, batch_size * num_beams))); @@ -426,20 +426,6 @@ Status ProcessLogits(const OrtValue& logits, // dumper->Print("next_token_scores after softmax", next_token_scores.data(), batch_size, num_beams, vocab_size); #endif - // Sequences generated by beam scorer is currently stored in CPU. - // Copy sequences to device only when repetition penalty or no repeat ngram is used in kernel - BufferUniquePtr sequences_buffer; - int current_sequence_length = sequences->GetSequenceLength(); - bool run_ngram = parameters->no_repeat_ngram_size > 0 && current_sequence_length >= parameters->no_repeat_ngram_size; - if (parameters->repetition_penalty != 1.0f || run_ngram) { - size_t bytes = SafeInt(sizeof(int32_t)) * batch_beam_size * parameters->max_length; - void* data = allocator->Alloc(bytes); - BufferUniquePtr temp_buffer(data, BufferDeleter(allocator)); - sequences_buffer = std::move(temp_buffer); - CUDA_RETURN_IF_ERROR(cudaMemcpyAsync(sequences_buffer.get(), sequences->GetSequence(0).data(), bytes, - cudaMemcpyHostToDevice, cuda_stream)); - } - cuda::LaunchLogitsProcessKernel( next_token_scores.data(), parameters->vocab_mask.data(), @@ -451,10 +437,10 @@ Status ProcessLogits(const OrtValue& logits, // parameters->num_beams, vocab_size, vocab_size, - (parameters->min_length > 0 && current_sequence_length < parameters->min_length) ? parameters->eos_token_id : -1, - reinterpret_cast(sequences_buffer.get()), + (parameters->min_length > 0 && sequences->GetSequenceLength() < parameters->min_length) ? parameters->eos_token_id : -1, + sequences->GetCurrentDeviceSequences().data(), parameters->max_length, - current_sequence_length, + sequences->GetSequenceLength(), parameters->repetition_penalty, parameters->no_repeat_ngram_size, cuda_stream); @@ -510,13 +496,6 @@ Status ProcessLogits(const OrtValue& logits, // dumper->Print("next_indices before scorer", beam_state->next_indices.data(), batch_size, 2 * num_beams); dumper->Print("next_scores before scorer", beam_state->next_scores.data(), batch_size, 2 * num_beams); #endif - - // TODO: Remove these kinds of cross-device copies once BeamScorer runs on CUDA - CUDA_RETURN_IF_ERROR(cudaMemcpyAsync(cpu_state->topk_scores.data(), - beam_state->next_scores.data(), - beam_state->next_scores.size_bytes(), - cudaMemcpyDeviceToHost, - cuda_stream)); } else { // Apply top-k selection like the following: // next_token_scores = next_token_scores.view(batch_size, num_beams * vocab_size) @@ -552,63 +531,24 @@ Status ProcessLogits(const OrtValue& logits, // cuda::LaunchNextTokenKernel(next_token_indices, beam_state->next_indices.data(), beam_state->next_tokens.data(), batch_size, top_k, vocab_size, cuda_stream); - const float* data = topk_scores->Data(); #ifdef DEBUG_GENERATION - dumper->Print("next_scores before scorer", data, batch_size, top_k); + dumper->Print("next_scores before scorer", topk_scores->Data(), batch_size, top_k); dumper->Print("next_tokens before scorer", beam_state->next_tokens.data(), batch_size, top_k); dumper->Print("next_indices before scorer", beam_state->next_indices.data(), batch_size, top_k); #endif - - // TODO: Remove these kinds of cross-device copies once BeamScorer runs on CUDA - CUDA_RETURN_IF_ERROR(cudaMemcpyAsync(cpu_state->topk_scores.data(), - data, - topk_scores->SizeInBytes(), - cudaMemcpyDeviceToHost, - cuda_stream)); } - // TODO: Remove these kinds of cross-device copies once BeamScorer runs on CUDA - CUDA_RETURN_IF_ERROR(cudaMemcpyAsync(cpu_state->topk_tokens.data(), - beam_state->next_tokens.data(), - beam_state->next_tokens.size_bytes(), - cudaMemcpyDeviceToHost, - cuda_stream)); - CUDA_RETURN_IF_ERROR(cudaMemcpyAsync(cpu_state->topk_indices.data(), - beam_state->next_indices.data(), - beam_state->next_indices.size_bytes(), - cudaMemcpyDeviceToHost, - cuda_stream)); - CUDA_RETURN_IF_ERROR(cudaStreamSynchronize(cuda_stream)); - - gsl::span next_scores(cpu_state->topk_scores.data(), beam_state->next_scores.size()); - gsl::span next_tokens(cpu_state->topk_tokens.data(), beam_state->next_tokens.size()); - gsl::span next_indices(cpu_state->topk_indices.data(), beam_state->next_indices.size()); + // gsl::span doesn't convert from non const to const, so all we're doing here is making each const. + gsl::span next_scores(beam_state->next_scores.data(), beam_state->next_scores.size()); + gsl::span next_tokens(beam_state->next_tokens.data(), beam_state->next_tokens.size()); + gsl::span next_indices(beam_state->next_indices.data(), beam_state->next_indices.size()); - // TODO: Implement BeamScorer on CUDA beam_scorer->Process( - sequences, + *sequences, next_scores, next_tokens, next_indices); - // TODO: This is a temporary work-around as BeamScorer currently only runs on CPU. - // We can remove these kinds of work-arounds once BeamScorer runs on CUDA eventually. - auto chosen_indices = beam_scorer->GetNextIndices(); - auto beam_state_chosen_indices = beam_state->chosen_indices; - - if (!beam_state_chosen_indices.empty()) { - // If we have allocated `chosen_indices` in beam_state, it means that we - // will be needing the chosen indices from BeamScorer as we are using - // DecoderMaskedSelfAttention, so copy it over. - CUDA_RETURN_IF_ERROR(cudaMemcpyAsync(beam_state_chosen_indices.data(), - chosen_indices.data(), - chosen_indices.size_bytes(), - cudaMemcpyHostToDevice, - cuda_stream)); - - CUDA_RETURN_IF_ERROR(cudaStreamSynchronize(cuda_stream)); - } - #ifdef ENABLE_NVTX_PROFILE processLogitsRange.End(); #endif @@ -616,6 +556,167 @@ Status ProcessLogits(const OrtValue& logits, // return Status::OK(); } +struct CudaBeamSearchScorer : transformers::IBeamScorer { + CudaBeamSearchScorer(const transformers::IGenerationParameters& parameters, + AllocatorPtr& allocator, AllocatorPtr& allocator_cpu, + Stream* stream); + + void Process(transformers::ISequences& sequences, + gsl::span& next_scores, + gsl::span& next_tokens, + gsl::span& next_indices) override; + + void Finalize(transformers::ISequences& sequences, + gsl::span& final_beam_scores, + Tensor* output_sequences, + Tensor* output_sequence_scores) override; + + bool IsDone() const override { return false; } // For CUDA we speculatively run the next step while we wait for the GPU to report status. We use 'IsDoneLater()' for this + bool IsDoneLater() const override; + + gsl::span GetNextScores() override { return next_beam_scores_; } + gsl::span GetNextTokens() override { return next_beam_tokens_; } + gsl::span GetNextIndicesCPU() override { + CUDA_CALL_THROW(cudaMemcpyAsync(next_beam_indices_cpu_.data(), next_beam_indices_.data(), next_beam_indices_.size_bytes(), cudaMemcpyDeviceToHost, stream_)); + CUDA_CALL_THROW(cudaStreamSynchronize(stream_)); + return next_beam_indices_cpu_; + } + gsl::span GetNextIndicesGPU() override { return next_beam_indices_; } + + private: + mutable cuda::AutoDestoryCudaEvent event_process_complete_; + IAllocatorUniquePtr state_cpu_; + IAllocatorUniquePtr state_gpu_; + cudaStream_t stream_; + + IAllocatorUniquePtr next_beam_scores_ptr_; + gsl::span next_beam_scores_; + + IAllocatorUniquePtr next_beam_tokens_ptr_; + gsl::span next_beam_tokens_; + + IAllocatorUniquePtr next_beam_indices_ptr_; + gsl::span next_beam_indices_; + + IAllocatorUniquePtr next_beam_indices_cpu_ptr_; + gsl::span next_beam_indices_cpu_; + + IAllocatorUniquePtr hypothesis_buffer_ptr_; // Allocated buffer to hold all hypotheses + gsl::span hypothesis_buffer_; // Span of the allocated buffer + size_t hypothesis_buffer_used_{}; // Offset of available buffer, or length of used buffer. + + IAllocatorUniquePtr hypothesis_scores_ptr_; // num_beams_ * batch_size_, divided into num_beams_ chunks per BeamHypothesis in beam_hyps_ + IAllocatorUniquePtr beam_hyps_ptr_; + gsl::span beam_hyps_; // Shape is batch_size_ +}; + +template +gsl::span Allocate(std::shared_ptr allocator, + size_t size, + IAllocatorUniquePtr& unique_ptr) { + unique_ptr = IAllocator::MakeUniquePtr(std::move(allocator), size); + return gsl::make_span(unique_ptr.get(), size); +} + +template +IAllocatorUniquePtr AllocateCPUPinned() { + T* p; + CUDA_CALL_THROW(cudaMallocHost(&p, sizeof(T))); + return IAllocatorUniquePtr{p, [](cuda::BeamScorerState* p) { ORT_IGNORE_RETURN_VALUE(cudaFreeHost(p)); }}; +} + +CudaBeamSearchScorer::CudaBeamSearchScorer(const transformers::IGenerationParameters& parameters, + AllocatorPtr& allocator, AllocatorPtr& allocator_cpu, Stream* stream) + : stream_{stream ? reinterpret_cast(stream->GetHandle()) : nullptr} { + CUDA_CALL_THROW(cudaEventCreate(&event_process_complete_.Get())); + + state_cpu_ = AllocateCPUPinned(); + state_cpu_->batch_size_ = static_cast(parameters.batch_size); + state_cpu_->num_beams_ = static_cast(parameters.num_beams); + state_cpu_->max_length_ = static_cast(parameters.max_length); + state_cpu_->num_return_sequences_ = static_cast(parameters.num_return_sequences); + state_cpu_->pad_token_id_ = parameters.pad_token_id; + state_cpu_->eos_token_id_ = parameters.eos_token_id; + state_cpu_->early_stopping_ = parameters.early_stopping; + state_cpu_->not_done_count_ = parameters.batch_size; + state_cpu_->hypothesis_buffer_used_ = 0; + state_gpu_ = IAllocator::MakeUniquePtr(allocator, 1); + CUDA_CALL_THROW(cudaMemcpyAsync(state_gpu_.get(), state_cpu_.get(), sizeof(cuda::BeamScorerState), ::cudaMemcpyHostToDevice, stream_)); + + size_t batch_beam_size = state_cpu_->batch_size_ * state_cpu_->num_beams_; + + auto beams = Allocate(allocator, batch_beam_size, hypothesis_scores_ptr_); + beam_hyps_ = Allocate(allocator, state_cpu_->batch_size_, beam_hyps_ptr_); + + cuda::LaunchInitializeBeamHypotheses(beam_hyps_, parameters.length_penalty, beams, parameters.num_beams, stream_); + + next_beam_scores_ = Allocate(allocator, batch_beam_size, next_beam_scores_ptr_); + next_beam_tokens_ = Allocate(allocator, batch_beam_size, next_beam_tokens_ptr_); + next_beam_indices_ = Allocate(allocator, batch_beam_size, next_beam_indices_ptr_); + next_beam_indices_cpu_ = Allocate(allocator_cpu, batch_beam_size, next_beam_indices_cpu_ptr_); + + // Space to store intermediate sequence with length sequence_length, sequence_length + 1, ..., max_sequence_length. + size_t per_beam = (SafeInt(state_cpu_->max_length_) * (state_cpu_->max_length_ + 1) - (parameters.sequence_length - 1) * parameters.sequence_length) / 2; + hypothesis_buffer_ = Allocate(allocator, batch_beam_size * per_beam, hypothesis_buffer_ptr_); +} + +void CudaBeamSearchScorer::Process(transformers::ISequences& sequences, + gsl::span& next_scores, + gsl::span& next_tokens, + gsl::span& next_indices) { + cuda::LaunchBeamSearchScorer_Process(*state_cpu_, + *state_gpu_, + sequences.GetCurrentDeviceSequences(), + sequences.GetSequenceLength(), + beam_hyps_, + next_beam_scores_, + next_beam_tokens_, + next_beam_indices_, + hypothesis_buffer_, + next_scores, + next_tokens, + next_indices, + stream_); + CUDA_CALL_THROW(cudaEventRecord(event_process_complete_.Get(), stream_)); + + cuda::LaunchBeamSearchScorer_AppendNextTokenToSequences(*state_cpu_, + *state_gpu_, + sequences.GetCurrentDeviceSequences(), + sequences.GetNextDeviceSequences(), + sequences.GetSequenceLength(), + next_beam_tokens_, + next_beam_indices_, + stream_); +} + +bool CudaBeamSearchScorer::IsDoneLater() const { + CUDA_CALL_THROW(cudaEventSynchronize(event_process_complete_.Get())); + return state_cpu_->not_done_count_ == 0; +} + +void CudaBeamSearchScorer::Finalize(transformers::ISequences& sequences, + gsl::span& final_beam_scores, + Tensor* output_sequences, + Tensor* output_sequence_scores) { + ORT_ENFORCE(output_sequences != nullptr); + + // Word IDs of each sequence, with shape (batch_size * num_return_sequences, max_sequence_length). + gsl::span output{output_sequences->MutableData(), static_cast(output_sequences->Shape().Size())}; + + // Score of each sequence, with shape (batch_size * num_return_sequences). + gsl::span sequence_scores; + if (output_sequence_scores) { + sequence_scores = gsl::span{output_sequence_scores->MutableData(), static_cast(output_sequence_scores->Shape().Size())}; + } + + cuda::LaunchBeamSearchScorer_Finalize(state_cpu_->batch_size_, *state_gpu_, sequences.GetCurrentDeviceSequences(), sequences.GetSequenceLength(), beam_hyps_, final_beam_scores, output, sequence_scores, stream_); +} + +std::unique_ptr CreateBeamScorer(const transformers::IGenerationParameters& parameters, + AllocatorPtr& allocator, AllocatorPtr& allocator_cpu, Stream* stream) { + return std::make_unique(parameters, allocator, allocator_cpu, stream); +} + template Status GreedySearchProcessLogits( const OrtValue& logits, // logits output of subgraph @@ -682,7 +783,7 @@ Status GreedySearchProcessLogits( // Move the pointer in increments of padded_vocab_size to account for any padding // if any in the logits weight of the MatMul. const CudaT* current_logits = logits_data + (input_length - 1) * padded_vocab_size; - for (int i = 0; i < batch_beam_size; i++) { + for (ptrdiff_t i = 0; i < batch_beam_size; i++) { // We only copy what is relevant (i.e.) vocab_size as padded_vocab_size will contain // some logits corresponding to the "padded" vocab size which we will ignore // for token generation. @@ -764,7 +865,7 @@ Status GreedySearchProcessLogits( if (do_sampling) { ORT_RETURN_IF_ERROR(SamplingCudaHelper::Sample(allocator, - cuda_stream, + stream, next_token_scores, sampling_state, greedy_state, @@ -820,7 +921,8 @@ Status DeviceCopy(gsl::span target, gsl::span source, Stream* ort_st } else { CUDA_RETURN_IF_ERROR(cudaMemcpyAsync(target.data(), source.data(), source.size_bytes(), static_cast(copyDirection), cuda_stream)); - CUDA_RETURN_IF_ERROR(cudaStreamSynchronize(cuda_stream)); + if (copyDirection != DeviceCopyDirection::deviceToDevice) + CUDA_RETURN_IF_ERROR(cudaStreamSynchronize(cuda_stream)); } return Status::OK(); } @@ -830,10 +932,10 @@ Status PickGptPastState(const std::vector& last_outputs, std::vector& next_inputs, gsl::span& beam_indices, AllocatorPtr allocator, - int gpt_subgraph_first_past_input_idx, - int gpt_subgraph_first_present_output_idx, + ptrdiff_t gpt_subgraph_first_past_input_idx, + ptrdiff_t gpt_subgraph_first_present_output_idx, Stream* ort_stream) { - int num_present_tensors = static_cast(last_outputs.size()) - gpt_subgraph_first_present_output_idx; + ptrdiff_t num_present_tensors = static_cast(last_outputs.size()) - gpt_subgraph_first_present_output_idx; for (int i = 0; i < num_present_tensors; ++i) { const OrtValue& present = last_outputs[gpt_subgraph_first_present_output_idx + i]; @@ -851,6 +953,7 @@ Status PickGptPastState(const std::vector& last_outputs, gsl::span past_span = gsl::make_span(past.GetMutable()->MutableData(), past_shape.Size()); gsl::span present_span = gsl::make_span(present.Get().Data(), past_shape.Size()); + for (size_t j = 0; j < beam_indices.size(); j++) { int32_t beam_index = beam_indices[j]; gsl::span present_key = present_span.subspan(beam_index * block_size_per_beam, block_size_per_beam); @@ -878,8 +981,8 @@ Status PickT5PastState(const std::vector& last_outputs, int num_present_tensors, gsl::span& beam_indices, AllocatorPtr allocator, - int t5_decoder_first_past_input_idx, - int t5_decoder_first_present_output_idx, + ptrdiff_t t5_decoder_first_past_input_idx, + ptrdiff_t t5_decoder_first_present_output_idx, Stream* ort_stream) { cudaStream_t cuda_stream = ort_stream ? static_cast(ort_stream->GetHandle()) : nullptr; for (int i = 0; i < num_present_tensors; ++i) { @@ -936,17 +1039,17 @@ Status UpdateGptFeeds( // Update input_ids with next tokens. int batch_beam_size = static_cast(beam_next_tokens.size()); - int64_t dims[] = {batch_beam_size, 1}; - TensorShape input_ids_shape(&dims[0], 2); + TensorShape input_ids_shape{batch_beam_size, 1}; auto element_type = DataTypeImpl::GetType(); OrtValue input_ids; Tensor::InitOrtValue(element_type, input_ids_shape, allocator, input_ids); int32_t* input_ids_data = input_ids.GetMutable()->MutableData(); cudaStream_t cuda_stream = ort_stream ? static_cast(ort_stream->GetHandle()) : nullptr; - // TODO(hasesh): When BeamScorer is implemented on CUDA, figure out a way to avoid this cross-device copy + // num_beams == 1 using cudaMemcpyHostToDevice is because GreedySearch still uses CPU, BeamSearch is fully GPU CUDA_RETURN_IF_ERROR(cudaMemcpyAsync(input_ids_data, beam_next_tokens.data(), beam_next_tokens.size_bytes(), - cudaMemcpyHostToDevice, cuda_stream)); + num_beams == 1 ? cudaMemcpyHostToDevice : cudaMemcpyDeviceToDevice, cuda_stream)); + next_inputs[0] = input_ids; // Update position IDs @@ -956,8 +1059,7 @@ Status UpdateGptFeeds( // Update attention mask const OrtValue& old_mask = next_inputs[2]; const int32_t* old_mask_data = old_mask.Get().Data(); - int64_t mask_dims[] = {batch_beam_size, current_length}; - TensorShape mask_shape(&mask_dims[0], 2); + TensorShape mask_shape{batch_beam_size, current_length}; OrtValue attention_mask; auto mask_type = DataTypeImpl::GetType(); Tensor::InitOrtValue(mask_type, mask_shape, allocator, attention_mask); @@ -971,7 +1073,7 @@ Status UpdateGptFeeds( if (past_present_share_buffer) { // Update past sequence length input - const int past_sequence_length_idx = (static_cast(last_outputs.size()) - gpt_subgraph_first_present_output_idx) + gpt_subgraph_first_past_input_idx; + const ptrdiff_t past_sequence_length_idx = (static_cast(last_outputs.size()) - gpt_subgraph_first_present_output_idx) + gpt_subgraph_first_past_input_idx; *(next_inputs[past_sequence_length_idx].GetMutable()->MutableData()) = past_sequence_len; // Update beam search specific input for DecoderMaskedSelfAttention (cache indirection) if present @@ -1016,12 +1118,11 @@ Status UpdateGptFeeds( ORT_RETURN_IF_ERROR(PickGptPastState(last_outputs, next_inputs, beam_indices_cpu, allocator, gpt_subgraph_first_past_input_idx, gpt_subgraph_first_present_output_idx, ort_stream)); + // Make sure data is ready before next subgraph execution. + CUDA_RETURN_IF_ERROR(cudaStreamSynchronize(cuda_stream)); } } - // Make sure data is ready before next subgraph execution. - CUDA_RETURN_IF_ERROR(cudaStreamSynchronize(cuda_stream)); - #ifdef ENABLE_NVTX_PROFILE updateFeedsRange.End(); #endif @@ -1058,10 +1159,9 @@ Status UpdateDecoderFeeds( // Only need copy beam next tokens to input_ids, and copy present_*_self_* to past_*_self_*, // Update input_ids with next tokens. - int batch_beam_size = static_cast(beam_next_tokens.size()); + int batch_beam_size = gsl::narrow(beam_next_tokens.size()); int sequence_length = !use_sequence_as_input_ids ? 1 : current_length; - int64_t dims[] = {batch_beam_size, sequence_length}; - TensorShape input_ids_shape(&dims[0], 2); + TensorShape input_ids_shape{batch_beam_size, sequence_length}; auto element_type = DataTypeImpl::GetType(); OrtValue input_ids; Tensor::InitOrtValue(element_type, input_ids_shape, allocator, input_ids); @@ -1072,12 +1172,11 @@ Status UpdateDecoderFeeds( CUDA_RETURN_IF_ERROR(cudaMemcpyAsync(input_ids_data, beam_next_tokens.data(), beam_next_tokens.size_bytes(), cudaMemcpyHostToDevice, cuda_stream)); } else { - int32_t* input_ids_data = input_ids.GetMutable()->MutableData(); for (int i = 0; i < batch_beam_size; i++) { gsl::span sequence = sequences.GetSequence(i); const int32_t* sequence_data = sequence.data(); CUDA_RETURN_IF_ERROR( - cudaMemcpyAsync(input_ids_data + i * current_length, + cudaMemcpyAsync(input_ids_data + static_cast(i) * current_length, sequence_data, current_length * sizeof(int32_t), cudaMemcpyHostToDevice, @@ -1093,11 +1192,11 @@ Status UpdateDecoderFeeds( #endif // Update past state - ORT_ENFORCE(last_outputs.size() >= static_cast(1 + num_present_tensors)); + ORT_ENFORCE(last_outputs.size() >= static_cast(num_present_tensors) + 1); if (past_present_share_buffer) { // Update past sequence length input - const int past_sequence_length_idx = 2 * (static_cast(last_outputs.size()) - t5_decoder_first_present_output_idx) + t5_decoder_first_past_input_idx; + const ptrdiff_t past_sequence_length_idx = 2 * (static_cast(last_outputs.size()) - t5_decoder_first_present_output_idx) + t5_decoder_first_past_input_idx; *(next_inputs[past_sequence_length_idx].GetMutable()->MutableData()) = current_length - 1; // Update beam search specific input for DecoderMaskedSelfAttention (cache indirection) if present @@ -1136,7 +1235,7 @@ Status UpdateDecoderFeeds( // TODO(tianleiwu): remove num_beams==1 once GreedySearch operator is available. if (num_beams == 1) { // feed present_* output to past_* inputs one by one - for (int i = 0; i < num_present_tensors; ++i) { + for (ptrdiff_t i = 0; i < num_present_tensors; ++i) { next_inputs[t5_decoder_first_past_input_idx + i] = last_outputs[t5_decoder_first_present_output_idx + i]; } @@ -1153,6 +1252,16 @@ Status UpdateDecoderFeeds( return Status::OK(); } +namespace { +template +struct ToCudaTypeWrapper : public ToCudaType {}; + +template <> +struct ToCudaTypeWrapper { + using MappedType = int32_t; +}; +} // namespace + template Status ExpandBuffer(Stream* ort_stream, const OrtValue& input, @@ -1189,23 +1298,18 @@ Status ExpandBuffer(Stream* ort_stream, const T* input_data = input.Get().Data(); T* expanded_data = expanded.GetMutable()->MutableData(); - T* target = expanded_data; + + using CudaT = typename ToCudaTypeWrapper::MappedType; if (max_sequence_length == 0) { const int64_t& chunk_size = static_cast(input_shape.Size() / batch_size); - for (int i = 0; i < batch_size; i++) { - for (int j = 0; j < num_beams; j++) { - CUDA_RETURN_IF_ERROR( - cudaMemcpyAsync( - target, - input_data + i * chunk_size, - sizeof(T) * chunk_size, - cudaMemcpyDeviceToDevice, - cuda_stream)); - target += chunk_size; - } - } + cuda::BufferExpansionKernelLauncher(reinterpret_cast(input_data), + reinterpret_cast(expanded_data), + static_cast(batch_size), + num_beams, + static_cast(chunk_size), + cuda_stream); return Status::OK(); } @@ -1214,24 +1318,16 @@ Status ExpandBuffer(Stream* ort_stream, // Expand from [B, N, S, H] to [B*beam, N, S_max, H] const int64_t& num_heads = input_shape[1]; const int64_t& head_size = input_shape[3]; - const int64_t& input_offset = sequence_length * head_size; - const int64_t& output_offset = max_sequence_length * head_size; - const int64_t& NSH = input_offset * num_heads; - - for (int i = 0; i < batch_size; i++) { - for (int j = 0; j < num_beams; j++) { - for (int k = 0; k < num_heads; k++) { - CUDA_RETURN_IF_ERROR( - cudaMemcpyAsync( - target, - input_data + i * NSH + k * input_offset, - sizeof(T) * SafeInt(input_offset), - cudaMemcpyDeviceToDevice, - cuda_stream)); - target += output_offset; - } - } - } + + cuda::KeyCacheExpansionKernelLauncher(reinterpret_cast(input_data), + reinterpret_cast(expanded_data), + static_cast(batch_size), + num_beams, + static_cast(num_heads), + static_cast(sequence_length), + max_sequence_length, + static_cast(head_size), + cuda_stream); return Status::OK(); } @@ -1252,7 +1348,6 @@ template void InitGreedyState( template Status ProcessLogits( const OrtValue& logits, transformers::IBeamSearchState* beam_state, - transformers::IBeamSearchCpuState* cpu_state, transformers::ISequences* sequences, AllocatorPtr& allocator, onnxruntime::concurrency::ThreadPool* thread_pool, @@ -1324,7 +1419,6 @@ template void InitGreedyState( template Status ProcessLogits( const OrtValue& logits, transformers::IBeamSearchState* beam_state, - transformers::IBeamSearchCpuState* cpu_state, transformers::ISequences* sequences, AllocatorPtr& allocator, onnxruntime::concurrency::ThreadPool* thread_pool, diff --git a/onnxruntime/contrib_ops/cuda/transformers/generation_device_helper.h b/onnxruntime/contrib_ops/cuda/transformers/generation_device_helper.h index 5ed956f9a2ecd..f5f062d7a101b 100644 --- a/onnxruntime/contrib_ops/cuda/transformers/generation_device_helper.h +++ b/onnxruntime/contrib_ops/cuda/transformers/generation_device_helper.h @@ -39,11 +39,13 @@ Status TopK(const Tensor* input, const int axis, const unsigned k, bool largest, Tensor& output_values, Tensor& output_indices); -Status AddToFeeds(const IExecutionProvider* execution_provider, - Stream* ort_stream, +Status AddToFeeds(Stream* ort_stream, std::initializer_list inputs, std::vector& feeds, - IAllocatorUniquePtr& buffer); + IAllocatorUniquePtr& buffer, + AllocatorPtr device_allocator, + AllocatorPtr host_allocator, + const OrtMemoryInfo& location); template void InitBeamState(transformers::IBeamSearchState* beam_state, @@ -52,6 +54,8 @@ void InitBeamState(transformers::IBeamSearchState* beam_state, int num_beams, Stream* ort_stream); +std::unique_ptr CreateBeamScorer(const transformers::IGenerationParameters& parameters, AllocatorPtr& allocator, AllocatorPtr& allocator_cpu, Stream* ort_stream); + template void InitGreedyState(transformers::IGreedySearchState* greedy_state, gsl::span& sequence_lengths, @@ -60,7 +64,6 @@ void InitGreedyState(transformers::IGreedySearchState* greedy_state, template Status ProcessLogits(const OrtValue& logits, // logits output of subgraph transformers::IBeamSearchState* beam_state, // state - transformers::IBeamSearchCpuState* cpu_state, // state in CPU transformers::ISequences* sequences, // sequences AllocatorPtr& allocator, // default allocator onnxruntime::concurrency::ThreadPool* thread_pool, // thread pool (for CPU only) diff --git a/onnxruntime/contrib_ops/cuda/transformers/greedy_search.cc b/onnxruntime/contrib_ops/cuda/transformers/greedy_search.cc index 836de640af5bc..d9014ca8f5c24 100644 --- a/onnxruntime/contrib_ops/cuda/transformers/greedy_search.cc +++ b/onnxruntime/contrib_ops/cuda/transformers/greedy_search.cc @@ -31,8 +31,7 @@ transformers::CudaTensorConsoleDumper g_cuda_dumper_greedysearch; GreedySearch::GreedySearch(const OpKernelInfo& info) : onnxruntime::contrib::transformers::GreedySearch(info) { - SetDeviceHelpers(GenerationCudaDeviceHelper::ReorderPastState, - GenerationCudaDeviceHelper::AddToFeeds, + SetDeviceHelpers(GenerationCudaDeviceHelper::AddToFeeds, GenerationCudaDeviceHelper::TopK, GenerationCudaDeviceHelper::DeviceCopy, GenerationCudaDeviceHelper::GreedySearchProcessLogits, @@ -40,6 +39,10 @@ GreedySearch::GreedySearch(const OpKernelInfo& info) GenerationCudaDeviceHelper::InitGreedyState, GenerationCudaDeviceHelper::InitGreedyState); +#ifndef USE_ROCM + SetDeviceHelpers_Cuda(GenerationCudaDeviceHelper::ReorderPastState); +#endif + SetDeviceHelpers_Gpt(GenerationCudaDeviceHelper::UpdateGptFeeds, GenerationCudaDeviceHelper::UpdateGptFeeds); diff --git a/onnxruntime/contrib_ops/cuda/transformers/sampling.cc b/onnxruntime/contrib_ops/cuda/transformers/sampling.cc index 3e145380a9781..49c7bee28d223 100644 --- a/onnxruntime/contrib_ops/cuda/transformers/sampling.cc +++ b/onnxruntime/contrib_ops/cuda/transformers/sampling.cc @@ -32,8 +32,7 @@ transformers::CudaTensorConsoleDumper g_cuda_dumper_sampling; Sampling::Sampling(const OpKernelInfo& info) : onnxruntime::contrib::transformers::Sampling(info) { - SetDeviceHelpers(GenerationCudaDeviceHelper::ReorderPastState, - GenerationCudaDeviceHelper::AddToFeeds, + SetDeviceHelpers(GenerationCudaDeviceHelper::AddToFeeds, GenerationCudaDeviceHelper::TopK, GenerationCudaDeviceHelper::DeviceCopy, GenerationCudaDeviceHelper::GreedySearchProcessLogits, @@ -41,15 +40,21 @@ Sampling::Sampling(const OpKernelInfo& info) GenerationCudaDeviceHelper::InitGreedyState, GenerationCudaDeviceHelper::InitGreedyState); +#ifndef USE_ROCM + SetDeviceHelpers_Cuda(GenerationCudaDeviceHelper::ReorderPastState); +#endif + SetDeviceHelpers_Gpt(GenerationCudaDeviceHelper::UpdateGptFeeds, GenerationCudaDeviceHelper::UpdateGptFeeds); SetConsoleDumper(&g_cuda_dumper_sampling); +#ifndef USE_ROCM gpu_device_prop_ = &reinterpret_cast(info.GetExecutionProvider())->GetDeviceProp(); gpu_device_arch_ = static_cast(gpu_device_prop_)->major * 100 + static_cast(gpu_device_prop_)->minor * 10; +#endif } Status Sampling::ComputeInternal(OpKernelContext* context) const { diff --git a/onnxruntime/contrib_ops/cuda/transformers/sampling_cuda_helper.h b/onnxruntime/contrib_ops/cuda/transformers/sampling_cuda_helper.h index 3d10895f61ad3..339c07dbc5aaf 100644 --- a/onnxruntime/contrib_ops/cuda/transformers/sampling_cuda_helper.h +++ b/onnxruntime/contrib_ops/cuda/transformers/sampling_cuda_helper.h @@ -20,7 +20,7 @@ namespace SamplingCudaHelper { template Status Sample(AllocatorPtr& allocator, - cudaStream_t cuda_stream, + Stream* stream, gsl::span& next_token_scores, transformers::ISamplingState* sampling_state, transformers::IGreedySearchState* greedy_state, @@ -30,6 +30,8 @@ Status Sample(AllocatorPtr& allocator, ORT_UNUSED_PARAMETER(dumper); typedef typename ToCudaType::MappedType CudaT; + auto cuda_stream = static_cast(stream->GetHandle()); + gsl::span& d_index_in = sampling_state->d_index_in; gsl::span& d_offset = sampling_state->d_offset; @@ -91,7 +93,7 @@ Status Sample(AllocatorPtr& allocator, #endif gsl::span& d_sorted_softmaxed_score = sampling_state->d_sorted_softmaxed_score; - ORT_RETURN_IF_ERROR((dispatch_blockwise_softmax_forward(cuda_stream, + ORT_RETURN_IF_ERROR((dispatch_blockwise_softmax_forward(stream, d_sorted_softmaxed_score.data(), reinterpret_cast(d_sorted_score.data()), parameters->vocab_size, @@ -125,7 +127,7 @@ Status Sample(AllocatorPtr& allocator, #endif gsl::span& d_softmaxed_score = sampling_state->d_softmaxed_score; - ORT_RETURN_IF_ERROR((dispatch_blockwise_softmax_forward(cuda_stream, + ORT_RETURN_IF_ERROR((dispatch_blockwise_softmax_forward(stream, d_softmaxed_score.data(), reinterpret_cast(next_token_scores.data()), parameters->vocab_size, diff --git a/onnxruntime/contrib_ops/js/gelu.cc b/onnxruntime/contrib_ops/js/gelu.cc new file mode 100644 index 0000000000000..57de4e21a200e --- /dev/null +++ b/onnxruntime/contrib_ops/js/gelu.cc @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "gelu.h" + +namespace onnxruntime { +namespace contrib { +namespace js { + +ONNX_OPERATOR_KERNEL_EX( + Gelu, + kMSDomain, + 1, + kJsExecutionProvider, + (*KernelDefBuilder::Create()) + .TypeConstraint("T", DataTypeImpl::GetTensorType()), + Gelu); + +} // namespace js +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/js/gelu.h b/onnxruntime/contrib_ops/js/gelu.h new file mode 100644 index 0000000000000..ca2677ec0e367 --- /dev/null +++ b/onnxruntime/contrib_ops/js/gelu.h @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/providers/js/js_kernel.h" + +namespace onnxruntime { +namespace contrib { +namespace js { + +using onnxruntime::js::JsKernel; +JSEP_KERNEL_IMPL(Gelu, Gelu); + +} // namespace js +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/js/js_contrib_kernels.cc b/onnxruntime/contrib_ops/js/js_contrib_kernels.cc new file mode 100644 index 0000000000000..0bf6a4a168e68 --- /dev/null +++ b/onnxruntime/contrib_ops/js/js_contrib_kernels.cc @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "contrib_ops/js/js_contrib_kernels.h" + +namespace onnxruntime { +namespace contrib { +namespace js { + +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kJsExecutionProvider, kMSDomain, 1, Gelu); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kJsExecutionProvider, kMSDomain, 1, SkipLayerNormalization); + +template <> +KernelCreateInfo BuildKernelCreateInfo() { + KernelCreateInfo info; + return info; +} + +Status RegisterJsContribKernels(KernelRegistry& kernel_registry) { + static const BuildKernelCreateInfoFn function_table[] = { + BuildKernelCreateInfo, + BuildKernelCreateInfo}; + + for (auto& function_table_entry : function_table) { + KernelCreateInfo info = function_table_entry(); + if (info.kernel_def != nullptr) { // filter disabled entries where type is void + ORT_RETURN_IF_ERROR(kernel_registry.Register(std::move(info))); + } + } + return Status::OK(); +} + +} // namespace js +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/js/js_contrib_kernels.h b/onnxruntime/contrib_ops/js/js_contrib_kernels.h new file mode 100644 index 0000000000000..273065dbdee5c --- /dev/null +++ b/onnxruntime/contrib_ops/js/js_contrib_kernels.h @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/framework/op_kernel.h" +#include "core/framework/kernel_registry.h" + +namespace onnxruntime { +namespace contrib { +namespace js { + +Status RegisterJsContribKernels(KernelRegistry& kernel_registry); + +} // namespace js +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/js/skip_layer_norm.cc b/onnxruntime/contrib_ops/js/skip_layer_norm.cc new file mode 100644 index 0000000000000..ee315f9b31e3b --- /dev/null +++ b/onnxruntime/contrib_ops/js/skip_layer_norm.cc @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "contrib_ops/js/skip_layer_norm.h" + +namespace onnxruntime { +namespace contrib { +namespace js { + +ONNX_OPERATOR_KERNEL_EX( + SkipLayerNormalization, + kMSDomain, + 1, + kJsExecutionProvider, + (*KernelDefBuilder::Create()) + .TypeConstraint("T", DataTypeImpl::GetTensorType()) + .TypeConstraint("U", DataTypeImpl::GetTensorType()), + SkipLayerNorm); + +} // namespace js +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/js/skip_layer_norm.h b/onnxruntime/contrib_ops/js/skip_layer_norm.h new file mode 100644 index 0000000000000..c3011e96ae29f --- /dev/null +++ b/onnxruntime/contrib_ops/js/skip_layer_norm.h @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once +#include "core/common/common.h" +#include "core/providers/js/js_kernel.h" + +namespace onnxruntime { +namespace contrib { +namespace js { + +using onnxruntime::js::JsKernel; + +class SkipLayerNorm final : public JsKernel { + public: + SkipLayerNorm(const OpKernelInfo& op_kernel_info) : JsKernel(op_kernel_info) { + ORT_ENFORCE(op_kernel_info.GetAttr("epsilon", &epsilon_).IsOK()); + ORT_ENFORCE(epsilon_ >= 0); + JSEP_INIT_KERNEL_ATTRIBUTE(SkipLayerNormalization, ({ + "epsilon" : $1 + }), + epsilon_); + } + + private: + float epsilon_; +}; + +} // namespace js +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/rocm/bert/attention.cu b/onnxruntime/contrib_ops/rocm/bert/attention.cu index 96c05eaa90891..96cc17734874c 100644 --- a/onnxruntime/contrib_ops/rocm/bert/attention.cu +++ b/onnxruntime/contrib_ops/rocm/bert/attention.cu @@ -39,7 +39,12 @@ REGISTER_KERNEL_TYPED(float) REGISTER_KERNEL_TYPED(MLFloat16) template -Attention::Attention(const OpKernelInfo& info) : RocmKernel(info), AttentionBase(info, true) {} +Attention::Attention(const OpKernelInfo& info) + : RocmKernel(info), AttentionBase(info, true), attn_type_(kAttention) { + using HipT = typename ToHipType::MappedType; + using AttentionTunableOp = GemmSoftmaxGemmPermuteTunableOp; + tunable_op_ = std::make_shared(); +} template Status Attention::ComputeInternal(OpKernelContext* context) const { @@ -52,7 +57,7 @@ Status Attention::ComputeInternal(OpKernelContext* context) const { const Tensor* past_seq_len = context->Input(kPastSequenceLengthInputIndex); auto& device_prop = GetDeviceProp(); - AttentionParameters attn; + RocmAttentionParameters attn; ORT_RETURN_IF_ERROR(CheckInputs(input->Shape(), weights->Shape(), bias->Shape(), @@ -63,7 +68,7 @@ Status Attention::ComputeInternal(OpKernelContext* context) const { device_prop.maxThreadsPerBlock, past_seq_len)); ORT_ENFORCE(attn.sequence_length == attn.kv_sequence_length); // self attention - ORT_ENFORCE(attn.qkv_format == Q_K_V_BNSH); // non-packed, permuted + ORT_ENFORCE(attn.qkv_format == Q_K_V_BNSH); // non-packed, permuted TensorShapeVector output_shape(3); output_shape[0] = static_cast(attn.batch_size); @@ -86,6 +91,13 @@ Status Attention::ComputeInternal(OpKernelContext* context) const { using AttentionGeneric = GemmSoftmaxGemmPermuteGenericPipeline; using AttentionTunableOp = GemmSoftmaxGemmPermuteTunableOp; + ORT_RETURN_IF_ERROR(ClassifyAttentionMode(attn_type_, &attn, /*qkv=*/{}, /*past=*/{past}, /*present=*/{present})); + ORT_ENFORCE(attn.mode == QFMT_KFMT_VFMT_NONE_NONE_NONE_NONE || + attn.mode == QFMT_KFMT_VFMT_NONE_NONE_2BNTH_NONE || + attn.mode == QFMT_KFMT_VFMT_NONE_NONE_2BNMH_NONE || + attn.mode == QFMT_KFMT_VFMT_2BNPH_NONE_2BNTH_NONE || + attn.mode == QFMT_KFMT_VFMT_2BNMH_NONE_2BNMH_NONE); + size_t qkv_project_output_bytes = QkvProjectGeneric::GetOutputNumBytes(&attn); size_t shared_workspace_bytes = std::max(QkvProjectGeneric::GetWorkspaceNumBytes(&attn), AttentionGeneric::GetWorkspaceNumBytes(&attn)); @@ -100,7 +112,7 @@ Status Attention::ComputeInternal(OpKernelContext* context) const { { auto& params = gemm_permute_params; params.tuning_ctx = GetTuningContext(); - params.stream = stream; + params.stream = context->GetComputeStream(); params.handle = rocblas; params.attention = &attn; params.device_prop = &device_prop; @@ -116,27 +128,46 @@ Status Attention::ComputeInternal(OpKernelContext* context) const { ORT_RETURN_IF_ERROR(QkvProjectGeneric::Run(&gemm_permute_params)); auto [q_buffer, k_buffer, v_buffer] = QkvProjectGeneric::UnspliceOutputQKV(&gemm_permute_params); + // NOTE: GemmPermute always output 3BNSH, k_buffer and v_buffer can be treated as 2BNSH if (nullptr != present) { - // Concat past (2xBxNxS'xH) to present (2xBxNxTxH): - // past_k (BxNxS'xH) + k (BxNxSxH) => present_k (BxNxTxH) - // past_v (BxNxS'xH) + v (BxNxSxH) => present_v (BxNxTxH) - const int batches = attn.batch_size * attn.num_heads; - const int present_size_per_batch = attn.total_sequence_length * attn.head_size; - ORT_RETURN_IF_ERROR( - LaunchConcatPastToPresent(Stream(context), - attn.total_sequence_length, - attn.sequence_length, - attn.batch_size, - attn.head_size, - attn.num_heads, - device_prop.maxThreadsPerBlock, - nullptr == past ? nullptr : reinterpret_cast(past->DataRaw()), - k_buffer, - reinterpret_cast(present->MutableDataRaw()))); + Strides dst_strides; // the output buffer is present Tensor, the buffer is the same + + int4 add_shape{2 * attn.batch_size, attn.num_heads, attn.sequence_length, attn.head_size}; + HipT* add_dest = nullptr; // destination of concatenated data to present + const HipT* const add_src = k_buffer; // source of concatenated data to present + const auto add_src_strides = Strides::BNSHMemory( + 2 * attn.batch_size, attn.num_heads, attn.sequence_length, attn.head_size); + + if (attn.mode == QFMT_KFMT_VFMT_NONE_NONE_2BNTH_NONE) { + dst_strides = Strides::BNSHMemory(2 * attn.batch_size, attn.num_heads, attn.total_sequence_length, attn.head_size); + add_dest = reinterpret_cast(present->MutableDataRaw()) /* + dst_strides.OffsetAt(0, 0, 0, 0)*/; + } else if (attn.mode == QFMT_KFMT_VFMT_2BNPH_NONE_2BNTH_NONE) { + dst_strides = Strides::BNSHMemory(2 * attn.batch_size, attn.num_heads, attn.total_sequence_length, attn.head_size); + add_dest = reinterpret_cast(present->MutableDataRaw()) + dst_strides.OffsetAt(0, 0, attn.past_sequence_length, 0); + + // We only need to copy past to present in this case. All other cases will be build the present incrementally + const int4 past_shape = {2 * attn.batch_size, attn.num_heads, attn.past_sequence_length, attn.head_size}; + HipT* const past_dest = reinterpret_cast(present->MutableDataRaw()); + const HipT* const past_src = reinterpret_cast(past->DataRaw()); + const Strides past_src_strides = Strides::BNSHMemory( + 2 * attn.batch_size, attn.num_heads, attn.past_sequence_length, attn.head_size); + + ORT_RETURN_IF_ERROR(LaunchStridedCopy(stream, past_src, past_shape, past_src_strides.ForBNSHCoord(), + past_dest, dst_strides.ForBNSHCoord(), device_prop.maxThreadsPerBlock)); + } else if (attn.mode == QFMT_KFMT_VFMT_NONE_NONE_2BNMH_NONE) { + dst_strides = Strides::BNSHMemory(2 * attn.batch_size, attn.num_heads, attn.max_sequence_length, attn.head_size); + add_dest = reinterpret_cast(present->MutableDataRaw()) /* + dst_strides.OffsetAt(0, 0, 0, 0)*/; + } else if (attn.mode == QFMT_KFMT_VFMT_2BNMH_NONE_2BNMH_NONE) { + dst_strides = Strides::BNSHMemory(2 * attn.batch_size, attn.num_heads, attn.max_sequence_length, attn.head_size); + add_dest = reinterpret_cast(present->MutableDataRaw()) + dst_strides.OffsetAt(0, 0, attn.past_sequence_length, 0); + } + + ORT_RETURN_IF_ERROR(LaunchStridedCopy(stream, add_src, add_shape, add_src_strides.ForBNSHCoord(), + add_dest, dst_strides.ForBNSHCoord(), device_prop.maxThreadsPerBlock)); - // update pointers to present_k and present_v. + // update pointers to present_k and present_v. TODO: switch to ConvertToOffsetedBufferViews k_buffer = reinterpret_cast(present->MutableDataRaw()); - v_buffer = reinterpret_cast(present->MutableDataRaw()) + batches * present_size_per_batch; + v_buffer = reinterpret_cast(present->MutableDataRaw()) + dst_strides.OffsetAt(attn.batch_size, 0, 0, 0); } // For testing, environment variable ORT_TRANSFORMER_OPTIONS=1 could enable persistent softmax @@ -147,12 +178,13 @@ Status Attention::ComputeInternal(OpKernelContext* context) const { { auto& params = gemm_softmax_gemm_permute_params; params.tuning_ctx = GetTuningContext(); - params.stream = Stream(context); + params.stream = context->GetComputeStream(); params.handle = rocblas; params.attention = &attn; params.device_prop = &device_prop; // FIXME: the params.scale seems to be different from AttentionParameters::scale; params.scale = 1.0f / sqrt(static_cast(attn.head_size)); + // TODO: switch to ConvertToOffsetedBufferViews params.q_buffer = q_buffer; params.k_buffer = k_buffer; params.v_buffer = v_buffer; @@ -172,7 +204,7 @@ Status Attention::ComputeInternal(OpKernelContext* context) const { if (this->GetTuningContext()->IsTunableOpEnabled() && !use_persistent_softmax) { - return AttentionTunableOp{}(&gemm_softmax_gemm_permute_params); + return (*std::static_pointer_cast(tunable_op_))(&gemm_softmax_gemm_permute_params); } else { return AttentionGeneric::Run(&gemm_softmax_gemm_permute_params, use_persistent_softmax); } diff --git a/onnxruntime/contrib_ops/rocm/bert/attention.h b/onnxruntime/contrib_ops/rocm/bert/attention.h index 11d4d0e2b4ab1..7204fd660a516 100644 --- a/onnxruntime/contrib_ops/rocm/bert/attention.h +++ b/onnxruntime/contrib_ops/rocm/bert/attention.h @@ -5,6 +5,7 @@ #include "core/providers/rocm/rocm_kernel.h" #include "contrib_ops/cpu/bert/attention_base.h" +#include "contrib_ops/rocm/bert/attention_impl.h" namespace onnxruntime { namespace contrib { @@ -17,6 +18,14 @@ class Attention final : public RocmKernel, public AttentionBase { public: Attention(const OpKernelInfo& info); Status ComputeInternal(OpKernelContext* context) const override; + + public: + AttentionType attn_type_; + + // type-erased GemmSoftmaxGemmPermuteTunableOp, the reason for this is: + // 1. We don't want to include the cuh file where GemmSoftmaxGemmPermuteTunableOp is defined. + // 2. We don't want to construct the object repeatly (which is expansive) during Compute. + std::shared_ptr tunable_op_; }; } // namespace rocm diff --git a/onnxruntime/contrib_ops/rocm/bert/attention_impl.cu b/onnxruntime/contrib_ops/rocm/bert/attention_impl.cu index 32f225451e438..b0ed3ff82226a 100644 --- a/onnxruntime/contrib_ops/rocm/bert/attention_impl.cu +++ b/onnxruntime/contrib_ops/rocm/bert/attention_impl.cu @@ -30,6 +30,7 @@ limitations under the License. #include "contrib_ops/cpu/bert/attention_base.h" #include "contrib_ops/rocm/bert/attention_impl.h" #include "contrib_ops/rocm/bert/attention_softmax.h" +#include "contrib_ops/rocm/bert/decoder_attention_impl.h" using namespace onnxruntime::rocm; @@ -78,11 +79,109 @@ inline int3 Get2DMaskStrides(int total_sequence_length) { return {total_sequence_length, 0, 1}; } +Status ClassifyAttentionMode( + AttentionType attn_type, + RocmAttentionParameters* attn, + const std::vector& qkv, + const std::vector& past, + const std::vector& present) { + size_t num_qkv = std::count_if(qkv.cbegin(), qkv.cend(), [](auto it) { return it != nullptr; }); + size_t num_past = std::count_if(past.cbegin(), past.cend(), [](auto it) { return it != nullptr; }); + size_t num_present = std::count_if(present.cbegin(), present.cend(), [](auto it) { return it != nullptr; }); + + auto hint = MakeString(num_qkv, " qkv inputs, ", num_past, " past inputs and ", num_present, " present inputs"); + LOGS_DEFAULT(VERBOSE) << hint; + + if (attn_type == kAttention) { + ORT_ENFORCE(num_qkv == 0); + if (num_past == 0 && num_present == 0) { + attn->mode = QFMT_KFMT_VFMT_NONE_NONE_NONE_NONE; + return Status::OK(); + } else if (num_past == 0 && num_present == 1) { + if (attn->past_present_share_buffer == false) { + attn->mode = QFMT_KFMT_VFMT_NONE_NONE_2BNTH_NONE; + return Status::OK(); + } else { + attn->mode = QFMT_KFMT_VFMT_NONE_NONE_2BNMH_NONE; + return Status::OK(); + } + } else if (num_past == 1 && num_present == 1) { + if (attn->past_present_share_buffer == false) { + attn->mode = QFMT_KFMT_VFMT_2BNPH_NONE_2BNTH_NONE; + return Status::OK(); + } else { + attn->mode = QFMT_KFMT_VFMT_2BNMH_NONE_2BNMH_NONE; + return Status::OK(); + } + } + } else if (attn_type == kMultiHeadAttention || attn_type == kDecoderMaskedMultiHeadAttention) { + if (num_qkv == 3 && num_past == 0 && num_present == 0) { + if (attn->qkv_format == Q_K_V_BSNH) { + attn->mode = BSNH_BLNH_BLNH_NONE_NONE_NONE_NONE; + return Status::OK(); + } else if (attn->pass_past_in_kv) { + attn->mode = BSNH_BNLH_BNLH_NONE_NONE_NONE_NONE; + return Status::OK(); + } + } else if (num_qkv == 3 && num_past == 0 && num_present == 2) { + if (attn->past_present_share_buffer == false) { + if (attn->qkv_format == Q_K_V_BSNH) { + attn->mode = BSNH_BLNH_BLNH_NONE_NONE_BNTH_BNTH; + return Status::OK(); + } else if (attn->pass_past_in_kv) { + attn->mode = BSNH_BNLH_BNLH_NONE_NONE_BNTH_BNTH; + return Status::OK(); + } + } else { + if (attn->qkv_format == Q_K_V_BSNH) { + attn->mode = BSNH_BLNH_BLNH_NONE_NONE_BNMH_BNMH; + return Status::OK(); + } else if (attn->pass_past_in_kv) { + attn->mode = BSNH_BNLH_BNLH_NONE_NONE_BNMH_BNMH; + return Status::OK(); + } + } + } else if (num_qkv == 3 && num_past == 2 && num_present == 2) { + if (attn->past_present_share_buffer == false) { + if (attn->qkv_format == Q_K_V_BSNH) { + attn->mode = BSNH_BLNH_BLNH_BNPH_BNPH_BNTH_BNTH; + return Status::OK(); + } else if (attn->pass_past_in_kv) { + attn->mode = BSNH_BNLH_BNLH_BNPH_BNPH_BNTH_BNTH; + return Status::OK(); + } + } else { + if (attn->qkv_format == Q_K_V_BSNH) { + attn->mode = BSNH_BLNH_BLNH_BNMH_BNMH_BNMH_BNMH; + return Status::OK(); + } else if (attn->pass_past_in_kv) { + attn->mode = BSNH_BNLH_BNLH_BNMH_BNMH_BNMH_BNMH; + return Status::OK(); + } + } + } else if (num_qkv == 1 && num_past == 0 && num_present == 0) { + if (attn->qkv_format == QKV_BSN3H) { + attn->mode = BLN3H_NONE_NONE_NONE_NONE_NONE_NONE; + return Status::OK(); + } + } else if (num_qkv == 2 && num_past == 0 && num_present == 0) { + if (attn->qkv_format == Q_KV_BSNH_BSN2H) { + attn->mode = BSNH_BLN2H_NONE_NONE_NONE_NONE_NONE; + return Status::OK(); + } + } + } + return ORT_MAKE_STATUS( + ONNXRUNTIME, INVALID_ARGUMENT, + "Unsupported AttentionMode for ", attn_type, ". Got qkv format ", attn->qkv_format, + ". Got ", hint); +} + template Status DecoderQkvToContext( const hipDeviceProp_t& prop, RocmTuningContext* tuning_ctx, - hipStream_t stream, + Stream* ort_stream, rocblas_handle& rocblas, const size_t element_size, const int batch_size, @@ -113,11 +212,12 @@ Status DecoderQkvToContext( const int v_buffer_offset = (sequence_length + kv_sequence_length) * BHN; T* temp_qkv_buffer = workspace_buffer; + auto stream = static_cast(ort_stream->GetHandle()); const T* q = qkv_buffer; // transpose q and copy them to qkv_buffer ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, 1, sequence_length, batch_size, head_size, - num_heads, max_threads_per_block, true, gemm_query_buffer, qkv_buffer)); + num_heads, max_threads_per_block, true, gemm_query_buffer, qkv_buffer)); const T* k = qkv_buffer + k_buffer_offset; const T* v = qkv_buffer + v_buffer_offset; @@ -125,31 +225,31 @@ Status DecoderQkvToContext( if (!static_kv) { // transpose kv and copy them to qkv_buffer ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, 2, sequence_length, batch_size, head_size, num_heads, - max_threads_per_block, true, gemm_kv_buffer, qkv_buffer + k_buffer_offset)); + max_threads_per_block, true, gemm_kv_buffer, qkv_buffer + k_buffer_offset)); } else { // transpose kv and copy them to qkv_buffer ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, 2, kv_sequence_length, batch_size, head_size, num_heads, - max_threads_per_block, true, gemm_kv_buffer, qkv_buffer + k_buffer_offset)); + max_threads_per_block, true, gemm_kv_buffer, qkv_buffer + k_buffer_offset)); } } else { if (!static_kv) { // transpose kv and copy them to temp_buffer ORT_RETURN_IF_ERROR(LaunchTransQkv(stream, 2, sequence_length, batch_size, head_size, num_heads, - max_threads_per_block, true, gemm_kv_buffer, temp_qkv_buffer)); + max_threads_per_block, true, gemm_kv_buffer, temp_qkv_buffer)); // concat cache-k with k and copy to qkv_buffer if (nullptr != key_cache) { ORT_RETURN_IF_ERROR(LaunchConcatTensorToTensor(stream, kv_sequence_length, sequence_length, - batch_size, head_size, num_heads, - max_threads_per_block, 1, key_cache, - temp_qkv_buffer, qkv_buffer + k_buffer_offset)); + batch_size, head_size, num_heads, + max_threads_per_block, 1, key_cache, + temp_qkv_buffer, qkv_buffer + k_buffer_offset)); } // concat cache-v with v and copy to qkv_buffer if (nullptr != value_cache) { ORT_RETURN_IF_ERROR(LaunchConcatTensorToTensor(stream, kv_sequence_length, sequence_length, - batch_size, head_size, num_heads, - max_threads_per_block, 1, value_cache, - temp_qkv_buffer + k_buffer_offset, - qkv_buffer + v_buffer_offset)); + batch_size, head_size, num_heads, + max_threads_per_block, 1, value_cache, + temp_qkv_buffer + k_buffer_offset, + qkv_buffer + v_buffer_offset)); } } } @@ -184,7 +284,7 @@ Status DecoderQkvToContext( const int strideB = sequence_length * head_size; if (use_past && static_kv) { ORT_RETURN_IF_ERROR(blas::column_major::StridedBatchedGemm( - tuning_ctx, stream, rocblas, + tuning_ctx, ort_stream, rocblas, blas::BlasOp::Trans, blas::BlasOp::NonTrans, kv_sequence_length, sequence_length, head_size, /*alpha=*/rsqrt_head_size, @@ -195,7 +295,7 @@ Status DecoderQkvToContext( BN)); } else { ORT_RETURN_IF_ERROR(blas::column_major::StridedBatchedGemm( - tuning_ctx, stream, rocblas, + tuning_ctx, ort_stream, rocblas, blas::BlasOp::Trans, blas::BlasOp::NonTrans, kv_sequence_length, sequence_length, head_size, /*alpha=*/rsqrt_head_size, @@ -209,18 +309,18 @@ Status DecoderQkvToContext( if (has_key_padding_mask) { int3 strides = Get2DMaskStrides(kv_sequence_length); ORT_RETURN_IF_ERROR(ComputeSoftmaxWithRawMask( - stream, kv_sequence_length, sequence_length, batch_size, num_heads, + ort_stream, kv_sequence_length, sequence_length, batch_size, num_heads, strides, nullptr, key_padding_mask, nullptr, scratch1, scratch2, false, 1.0f, false, nullptr, mask_filter_value)); } else { ORT_RETURN_IF_ERROR(ComputeSoftmax(stream, kv_sequence_length, sequence_length, batch_size, - num_heads, nullptr, scratch1, scratch2, false)); + num_heads, nullptr, scratch1, scratch2, false)); } // compute P*V (as V*P), and store in scratch3: BxNxSxH if (use_past && static_kv) { ORT_RETURN_IF_ERROR(blas::column_major::StridedBatchedGemm( - tuning_ctx, stream, rocblas, + tuning_ctx, ort_stream, rocblas, blas::BlasOp::NonTrans, blas::BlasOp::NonTrans, head_size, sequence_length, kv_sequence_length, /*alpha=*/1.0f, @@ -231,7 +331,7 @@ Status DecoderQkvToContext( BN)); } else { ORT_RETURN_IF_ERROR(blas::column_major::StridedBatchedGemm( - tuning_ctx, stream, rocblas, + tuning_ctx, ort_stream, rocblas, blas::BlasOp::NonTrans, blas::BlasOp::NonTrans, head_size, sequence_length, kv_sequence_length, /*alpha=*/1.0f, @@ -250,7 +350,7 @@ Status DecoderQkvToContext( Status LaunchDecoderAttentionKernel( const hipDeviceProp_t& prop, RocmTuningContext* tuning_ctx, - hipStream_t stream, + Stream* stream, rocblas_handle& rocblas, const size_t element_size, const int batch_size, diff --git a/onnxruntime/contrib_ops/rocm/bert/attention_impl.h b/onnxruntime/contrib_ops/rocm/bert/attention_impl.h index 896520e4b4b1a..3164e8c211099 100644 --- a/onnxruntime/contrib_ops/rocm/bert/attention_impl.h +++ b/onnxruntime/contrib_ops/rocm/bert/attention_impl.h @@ -5,6 +5,7 @@ #include #include +#include "contrib_ops/cpu/bert/attention_common.h" #include "core/providers/rocm/shared_inc/rocm_utils.h" #include "core/providers/rocm/tunable/rocm_tunable.h" @@ -27,34 +28,6 @@ size_t GetAttentionWorkspaceSize( int sequence_length, int past_sequence_length); -Status LaunchDecoderAttentionKernel( - const hipDeviceProp_t& prop, // Device Properties - RocmTuningContext* tuning_ctx, // context for tuning - hipStream_t stream, // Hip stream - rocblas_handle& rocblas, // Rocblas handle - const size_t element_size, // Element size of input tensor - const int batch_size, // Batch size (B) - const int sequence_length, // Sequence length (S) - const int kv_sequence_length, // Key/Value/Cache sequence length - const int num_heads, // Number of attention heads (N) - const int head_size, // Hidden layer size per head (H) - const bool static_kv, // Whether cross attention or not - const bool use_past, // Whether use cache or not - const bool has_layer_state, // Whether output cache or not - const bool has_key_padding_mask, // Whether use key_padding_mask or not - const float mask_filter_value, // Mask filter value - const void* gemm_query_buffer, // Query buffer - const void* gemm_kv_buffer, // Key and value buffer - const bool* key_padding_mask, // Key padding mask - const void* key_cache, // Input key cache - const void* value_cache, // Input value cache - void* qkv_buffer, // Temporary buffer - void* workspace_buffer, // Temporary buffer - void* output, // Output tensor - void* new_key_cache, // New_key_cache tensor - void* new_value_cache // New_value_cache tensor -); - Status LaunchTransCtx(hipStream_t stream, const int sequence_length, const int batch_size, const int head_size, const int num_heads, const int max_threads_per_block, const bool reversed_bs, const float* input, float* output); @@ -97,28 +70,6 @@ Status LaunchConcatTensorToTensor(hipStream_t stream, const half* tensor_add, half* tensor_out); -Status LaunchConcatPastToPresent(hipStream_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); - -Status LaunchConcatPastToPresent(hipStream_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); - inline rocblas_status _compat_rocblas_gemm_strided_batched_ex(rocblas_handle handle, rocblas_operation transa, rocblas_operation transb, @@ -181,6 +132,48 @@ class CompatRocblasMathModeSetter { } }; +enum AttentionType { + kAttention, + kMultiHeadAttention, + kDecoderMaskedMultiHeadAttention, +}; + +enum AttentionMode { + // Q,K,V,PastK,PastV,PresentK,PresentV + QFMT_KFMT_VFMT_NONE_NONE_NONE_NONE, + QFMT_KFMT_VFMT_NONE_NONE_2BNTH_NONE, + QFMT_KFMT_VFMT_NONE_NONE_2BNMH_NONE, + QFMT_KFMT_VFMT_2BNPH_NONE_2BNTH_NONE, + QFMT_KFMT_VFMT_2BNMH_NONE_2BNMH_NONE, + BSNH_BLNH_BLNH_NONE_NONE_NONE_NONE, + BSNH_BNLH_BNLH_NONE_NONE_NONE_NONE, + BSNH_BLNH_BLNH_NONE_NONE_BNTH_BNTH, + BSNH_BNLH_BNLH_NONE_NONE_BNTH_BNTH, + BSNH_BLNH_BLNH_NONE_NONE_BNMH_BNMH, + BSNH_BNLH_BNLH_NONE_NONE_BNMH_BNMH, + BSNH_BLNH_BLNH_BNPH_BNPH_BNTH_BNTH, + BSNH_BNLH_BNLH_BNPH_BNPH_BNTH_BNTH, + BSNH_BLNH_BLNH_BNMH_BNMH_BNMH_BNMH, + BSNH_BNLH_BNLH_BNMH_BNMH_BNMH_BNMH, + BLN3H_NONE_NONE_NONE_NONE_NONE_NONE, + BSNH_BLN2H_NONE_NONE_NONE_NONE_NONE, +}; + +struct RocmAttentionParameters : AttentionParameters { + AttentionMode mode; +}; + +Status ClassifyAttentionMode(AttentionType type, + RocmAttentionParameters* attn, + const std::vector& qkv, + const std::vector& past, + const std::vector& present); + +template +Status LaunchStridedCopy(hipStream_t stream, + const T* in, int4 in_shape, longlong4 in_strides, // coord (b,n,s,h) + T* out, longlong4 out_strides, // coord (b,n,s,h) + int max_threads_per_block); } // namespace rocm } // namespace contrib } // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/rocm/bert/attention_softmax.h b/onnxruntime/contrib_ops/rocm/bert/attention_softmax.h index dc0cdb4d6a6e6..5bcd46f9b9ea8 100644 --- a/onnxruntime/contrib_ops/rocm/bert/attention_softmax.h +++ b/onnxruntime/contrib_ops/rocm/bert/attention_softmax.h @@ -109,7 +109,7 @@ __device__ inline void SoftmaxSmall(const int all_sequence_length, const T* add_before_softmax, const T* input, T* output, - bool is_unidirectional) { + bool causal) { using BlockReduce = hipcub::BlockReduce; __shared__ typename BlockReduce::TempStorage tmp_storage; @@ -122,21 +122,16 @@ __device__ inline void SoftmaxSmall(const int all_sequence_length, bool is_valid = false; // whether it has attention mask == 1. - // Update end position for unidirectional. + // Update end position for causal. int end = valid_end; - if (is_unidirectional) { - int end_unid = all_sequence_length - sequence_length + (blockIdx.x % sequence_length) + 1; - if (end_unid <= valid_start) { - // In this situation, mask of [0, end_unid) and [valid_start, valid_end) has -10000, - // and [end_unid, valid_start) and [valid_end, all_seq_len) has -20000. - // So [0, end_unid) will also have value after softmax. - is_valid = threadIdx.x < end_unid; - } else { - end = min(valid_end, end_unid); + if (causal) { + const int end_causal = all_sequence_length - sequence_length + (blockIdx.x % sequence_length) + 1; + if (end_causal < end) { + end = end_causal; } } - is_valid = is_valid || (threadIdx.x >= valid_start && threadIdx.x < end); + is_valid = (threadIdx.x >= valid_start && threadIdx.x < end); // e^x is represented as infinity if x is large enough, like 100.f. // Infinity divided by Infinity is a NAN. Thus, softmax gets a NAN if one or more item are large enough. @@ -169,7 +164,7 @@ __device__ inline void SoftmaxSmall(const int all_sequence_length, // threadIdx.x might be larger than all_sequence_length due to alignment to 32x. if (threadIdx.x < all_sequence_length) { - output[index] = T(thread_data_exp * sum_reverse_block); + output[index] = is_valid ? T(thread_data_exp * sum_reverse_block) : T(0.f); } } @@ -186,7 +181,7 @@ __global__ void SoftmaxWithRawMaskSmallKernel( const T* add_before_softmax, const T* input, T* output, - const bool is_unidirectional, + const bool causal, const float rsqrt_head_size, const bool skip_softmax, const float mask_filter_value) { @@ -207,10 +202,10 @@ __global__ void SoftmaxWithRawMaskSmallKernel( thread_data = float(input[index]) * rsqrt_head_size; const int sequence_index = blockIdx.x % sequence_length; - if (is_unidirectional) { + if (causal) { int from_index = all_sequence_length - sequence_length + sequence_index; // offset in all sequence length. if (threadIdx.x > from_index) { - thread_data = mask_filter_value; + thread_data = -ROCMRT_INF_F; } } @@ -269,9 +264,9 @@ __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 is_unidirectional) { + const T* add_before_softmax, const T* input, T* output, bool causal) { SoftmaxSmall(all_sequence_length, sequence_length, all_sequence_length, 0, - add_before_softmax, input, output, is_unidirectional); + add_before_softmax, input, output, causal); } template @@ -283,33 +278,33 @@ 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 is_unidirectional) { + const T* add_before_softmax, 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, is_unidirectional); + all_sequence_length, sequence_length, add_before_softmax, input, output, causal); } else if (all_sequence_length <= 64) { const int blockSize = 64; SoftmaxKernelSmall<<>>( - all_sequence_length, sequence_length, add_before_softmax, input, output, is_unidirectional); + all_sequence_length, sequence_length, add_before_softmax, input, output, causal); } else if (all_sequence_length <= 128) { const int blockSize = 128; SoftmaxKernelSmall<<>>( - all_sequence_length, sequence_length, add_before_softmax, input, output, is_unidirectional); + all_sequence_length, sequence_length, add_before_softmax, input, output, causal); } else if (all_sequence_length <= 256) { const int blockSize = 256; SoftmaxKernelSmall<<>>( - all_sequence_length, sequence_length, add_before_softmax, input, output, is_unidirectional); + all_sequence_length, sequence_length, add_before_softmax, input, output, causal); } else if (all_sequence_length <= 512) { const int blockSize = 512; SoftmaxKernelSmall<<>>( - all_sequence_length, sequence_length, add_before_softmax, input, output, is_unidirectional); + all_sequence_length, sequence_length, add_before_softmax, input, output, causal); } else if (all_sequence_length <= 1024) { const int blockSize = 1024; SoftmaxKernelSmall<<>>( - all_sequence_length, sequence_length, add_before_softmax, input, output, is_unidirectional); - } else if (!is_unidirectional) { + all_sequence_length, sequence_length, add_before_softmax, input, output, causal); + } else if (!causal) { const int blockSize = 1024; SoftmaxKernel<<>>( all_sequence_length, add_before_softmax, input, output); @@ -324,7 +319,7 @@ 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, - bool is_unidirectional) { + bool causal) { __shared__ int start_position; __shared__ int end_position; @@ -342,7 +337,7 @@ __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, is_unidirectional); + add_before_softmax, input, output, causal); } template @@ -372,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 is_unidirectional) { + const T* add_before_softmax, 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, is_unidirectional); + add_before_softmax, input, output, causal); if (all_sequence_length <= 32) { DISPATCH_KERNEL_SMALL_WITH_BLOCKSIZE(32); @@ -392,7 +387,7 @@ Status ComputeSoftmaxWithMask1D( DISPATCH_KERNEL_SMALL_WITH_BLOCKSIZE(512); } else if (all_sequence_length <= 1024) { DISPATCH_KERNEL_SMALL_WITH_BLOCKSIZE(1024); - } else if (!is_unidirectional) { + } else if (!causal) { const int blockSize = 1024; MaskedSoftmaxKernel<<>>( all_sequence_length, mask_index, mask_start, @@ -407,7 +402,7 @@ Status ComputeSoftmaxWithMask1D( } template -Status ComputeSoftmaxWithRawMask(hipStream_t stream, +Status ComputeSoftmaxWithRawMask(Stream* ort_stream, const int all_sequence_length, const int sequence_length, const int batch_size, @@ -418,7 +413,7 @@ Status ComputeSoftmaxWithRawMask(hipStream_t stream, const T* add_before_softmax, const T* input, T* output, - const bool is_unidirectional, + const bool causal, const float rsqrt_head_size, const bool use_persistent_softmax, T* persistent_softmax_workspace, @@ -426,12 +421,13 @@ Status ComputeSoftmaxWithRawMask(hipStream_t stream, const dim3 grid(sequence_length * num_heads, batch_size, 1); T* out = use_persistent_softmax ? persistent_softmax_workspace : output; + auto stream = static_cast(ort_stream->GetHandle()); #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, \ - is_unidirectional, rsqrt_head_size, \ + causal, rsqrt_head_size, \ use_persistent_softmax, mask_filter_value); if (all_sequence_length <= 32) { @@ -453,7 +449,7 @@ Status ComputeSoftmaxWithRawMask(hipStream_t stream, #undef DISPATCH_KERNEL_SMALL_WITH_BLOCKSIZE if (use_persistent_softmax) { - return dispatch_warpwise_softmax_forward(stream, + return dispatch_warpwise_softmax_forward(ort_stream, output, persistent_softmax_workspace, all_sequence_length, 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 486d6dca28717..5401c850bc8f7 100644 --- a/onnxruntime/contrib_ops/rocm/bert/batched_gemm_permute_pipelines.cuh +++ b/onnxruntime/contrib_ops/rocm/bert/batched_gemm_permute_pipelines.cuh @@ -107,7 +107,7 @@ struct GemmPermuteGenericPipeline { auto* attn = params->attention; // input should be BxSx3xNxH => gemm_buffer: 3xBxNxSxH return LaunchTransQkv( - params->Stream(), 3, attn->sequence_length, attn->batch_size, attn->head_size, attn->num_heads, + params->StreamHandle(), 3, attn->sequence_length, attn->batch_size, attn->head_size, attn->num_heads, params->device_prop->maxThreadsPerBlock, false, params->workspace_buffer, params->out_buffer); } diff --git a/onnxruntime/contrib_ops/rocm/bert/batched_gemm_softmax_gemm_permute_ck_impl/impl.cuh b/onnxruntime/contrib_ops/rocm/bert/batched_gemm_softmax_gemm_permute_ck_impl/impl.cuh index ae4aef5f99799..0599318a4022d 100644 --- a/onnxruntime/contrib_ops/rocm/bert/batched_gemm_softmax_gemm_permute_ck_impl/impl.cuh +++ b/onnxruntime/contrib_ops/rocm/bert/batched_gemm_softmax_gemm_permute_ck_impl/impl.cuh @@ -52,10 +52,11 @@ template , AccDT, DT, PassThrough, PassThrough, D0Op, PassThrough, PassThrough, GemmPadded, TensorDefault, TensorDefault, TensorDefault, TensorDefault, 1, 256, 128, 64, 32, 128, 32, 8, 8, 2, 32, 32, 1, 2, 4, S<4, 64, 1>, S<1, 0, 2>, S<1, 0, 2>, 2, 8, 8, true, S<4, 64, 1>, S<1, 0, 2>, S<1, 0, 2>, 2, 8, 8, true, S< 8, 32, 1>, S<0, 2, 1>, S<0, 2, 1>, 1, 4, 2, false, 1, 2, S<1, 32, 1, 8>, 8, MaskingSpec, 1>, DeviceBatchedGemmSoftmaxGemmPermute_Xdl_CShuffle< NumDimG, NumDimM, NumDimN, NumDimK, NumDimO, DT, DT, DT, DT, D0sDT, ck::Tuple<>, AccDT, DT, PassThrough, PassThrough, D0Op, PassThrough, PassThrough, GemmDefault, TensorDefault, TensorDefault, TensorDefault, TensorDefault, 1, 256, 256, 128, 32, 64, 32, 8, 8, 2, 32, 32, 2, 4, 2, S<4, 64, 1>, S<1, 0, 2>, S<1, 0, 2>, 2, 8, 8, true, S<4, 64, 1>, S<1, 0, 2>, S<1, 0, 2>, 2, 8, 8, true, S<16, 16, 1>, S<0, 2, 1>, S<0, 2, 1>, 1, 4, 2, false, 1, 2, S<1, 32, 1, 8>, 8, MaskingSpec>, DeviceBatchedGemmSoftmaxGemmPermute_Xdl_CShuffle< NumDimG, NumDimM, NumDimN, NumDimK, NumDimO, DT, DT, DT, DT, D0sDT, ck::Tuple<>, AccDT, DT, PassThrough, PassThrough, D0Op, PassThrough, PassThrough, GemmDefault, TensorDefault, TensorDefault, TensorDefault, TensorDefault, 1, 256, 256, 128, 32, 128, 32, 8, 8, 2, 32, 32, 2, 4, 4, S<4, 64, 1>, S<1, 0, 2>, S<1, 0, 2>, 2, 8, 8, true, S<4, 64, 1>, S<1, 0, 2>, S<1, 0, 2>, 2, 8, 8, true, S< 8, 32, 1>, S<0, 2, 1>, S<0, 2, 1>, 1, 4, 2, false, 1, 2, S<1, 32, 1, 8>, 8, MaskingSpec>, #if ROCM_VERSION >= 50500 @@ -71,6 +72,7 @@ using device_batched_gemm_softmax_gemm_permute_instances = DeviceBatchedGemmSoftmaxGemmPermute_Xdl_CShuffle< NumDimG, NumDimM, NumDimN, NumDimK, NumDimO, DT, DT, DT, DT, D0sDT, ck::Tuple<>, AccDT, DT, PassThrough, PassThrough, D0Op, PassThrough, PassThrough, GemmDefault, TensorDefault, TensorDefault, TensorDefault, TensorDefault, 1, 256, 64, 256, 64, 128, 32, 8, 8, 2, 16, 16, 1, 16, 8, S<8, 32, 1>, S<1, 0, 2>, S<1, 0, 2>, 2, 8, 8, true, S<8, 32, 1>, S<1, 0, 2>, S<1, 0, 2>, 2, 8, 8, true, S< 8, 32, 1>, S<0, 2, 1>, S<0, 2, 1>, 1, 4, 2, false, 1, 8, S<1, 16, 1,16>, 8, MaskingSpec>, DeviceBatchedGemmSoftmaxGemmPermute_Xdl_CShuffle< NumDimG, NumDimM, NumDimN, NumDimK, NumDimO, DT, DT, DT, DT, D0sDT, ck::Tuple<>, AccDT, DT, PassThrough, PassThrough, D0Op, PassThrough, PassThrough, GemmDefault, TensorDefault, TensorDefault, TensorDefault, TensorDefault, 1, 256, 64, 256, 64, 64, 32, 8, 8, 2, 16, 16, 1, 16, 4, S<8, 32, 1>, S<1, 0, 2>, S<1, 0, 2>, 2, 8, 8, true, S<8, 32, 1>, S<1, 0, 2>, S<1, 0, 2>, 2, 8, 8, true, S<16, 16, 1>, S<0, 2, 1>, S<0, 2, 1>, 1, 4, 2, false, 1, 4, S<1, 32, 1, 8>, 8, MaskingSpec>, // Padded fallback kernel + DeviceBatchedGemmSoftmaxGemmPermute_Xdl_CShuffle< NumDimG, NumDimM, NumDimN, NumDimK, NumDimO, DT, DT, DT, DT, D0sDT, ck::Tuple<>, AccDT, DT, PassThrough, PassThrough, D0Op, PassThrough, PassThrough, GemmPadded, TensorDefault, TensorDefault, TensorDefault, TensorDefault, 1, 256, 128, 128, 64, 128, 32, 8, 8, 2, 32, 32, 1, 4, 4, S<8, 32, 1>, S<1, 0, 2>, S<1, 0, 2>, 2, 8, 8, false, S<8, 32, 1>, S<1, 0, 2>, S<1, 0, 2>, 2, 8, 8, false, S< 8, 32, 1>, S<0, 2, 1>, S<0, 2, 1>, 1, 4, 2, false, 1, 2, S<1, 32, 1, 8>, 8, MaskingSpec, 1>, DeviceBatchedGemmSoftmaxGemmPermute_Xdl_CShuffle< NumDimG, NumDimM, NumDimN, NumDimK, NumDimO, DT, DT, DT, DT, D0sDT, ck::Tuple<>, AccDT, DT, PassThrough, PassThrough, D0Op, PassThrough, PassThrough, GemmPadded, TensorDefault, TensorDefault, TensorDefault, TensorDefault, 1, 256, 128, 128, 64, 128, 32, 8, 8, 2, 32, 32, 1, 4, 4, S<8, 32, 1>, S<1, 0, 2>, S<1, 0, 2>, 2, 8, 8, false, S<8, 32, 1>, S<1, 0, 2>, S<1, 0, 2>, 2, 8, 8, false, S< 8, 32, 1>, S<0, 2, 1>, S<0, 2, 1>, 1, 4, 2, false, 1, 2, S<1, 32, 1, 8>, 8, MaskingSpec>, DeviceBatchedGemmSoftmaxGemmPermute_Xdl_CShuffle< NumDimG, NumDimM, NumDimN, NumDimK, NumDimO, DT, DT, DT, DT, D0sDT, ck::Tuple<>, AccDT, DT, PassThrough, PassThrough, D0Op, PassThrough, PassThrough, GemmPadded, TensorDefault, TensorDefault, TensorDefault, TensorDefault, 1, 256, 128, 64, 32, 128, 32, 8, 8, 2, 32, 32, 1, 2, 4, S<4, 64, 1>, S<1, 0, 2>, S<1, 0, 2>, 2, 8, 8, true, S<4, 64, 1>, S<1, 0, 2>, S<1, 0, 2>, 2, 8, 8, true, S< 8, 32, 1>, S<0, 2, 1>, S<0, 2, 1>, 1, 4, 2, false, 1, 2, S<1, 32, 1, 8>, 8, MaskingSpec> // clang-format on diff --git a/onnxruntime/contrib_ops/rocm/bert/batched_gemm_softmax_gemm_permute_pipelines.cuh b/onnxruntime/contrib_ops/rocm/bert/batched_gemm_softmax_gemm_permute_pipelines.cuh index 4b38ccafc5cf7..246b66078537a 100644 --- a/onnxruntime/contrib_ops/rocm/bert/batched_gemm_softmax_gemm_permute_pipelines.cuh +++ b/onnxruntime/contrib_ops/rocm/bert/batched_gemm_softmax_gemm_permute_pipelines.cuh @@ -11,7 +11,7 @@ T: total sequence length N: num of heads H: head dimension -The following use qkv_format == Q_K_V_BNSH as a example: +The following use qkv_format == Q_K_V_BNSH (mode == BSNH_BNLH_BNLH_NONE_NONE_NONE_NONE) as a example: BN: B*N, which is the batch size of GEMMs. NOTE: To be disambiguated with batch size of Attention Op @@ -57,6 +57,50 @@ non-biased, masked, convert the mask to [B,1,1_or_S,T] and perform broadcast Broadcast add is not actually perform the broadcasting, just broadcast the load operation from memory. The impl details are in composable kernels. The scale and add logic is performed via Acc0ElementOp +# Classified modes: + +| Q | K | V | past(K)| pastV | present(K)| presentV | Op, desc +| ---- | ---- | ---- | ------ | ----- | --------- | -------- | --------- +| QFMT | KFMT | VFMT | - | - | - | - | A, basic, qkv is impl dependent by qkv_format +| QFMT | KFMT | VFMT | 2BNPH | - | 2BNTH *^ | - | A, past_present_share_buffer = false, qkv is impl dependent by qkv_format +| QFMT | KFMT | VFMT | 2BNMH | - | 2BNMH *^ | - | A, past_present_share_buffer = true, qkv is impl dependent by qkv_format +| BSNH | BLNH*| BLNH^| - | - | - | - | MHA basic +| BSNH | BNLH*| BNLH^| - | - | - | - | MHA cross, pass_past_in_kv = true +| BSNH | - | - | - | - | BNLH * | BNLH ^ | MHA cross, pass_past_in_kv = false +| BSNH | BLNH | BLNH | - | - | BNTH * | BNTH ^ | MHA cross, past_present_share_buffer = false +| BSNH | BNLH | BNLH | - | - | BNTH * | BNTH ^ | MHA cross, past_present_share_buffer = false +| BSNH | BLNH | BLNH | - | - | BNMH * | BNMH ^ | MHA cross, past_present_share_buffer = true +| BSNH | BNLH | BNLH | - | - | BNMH * | BNMH ^ | MHA cross, past_present_share_buffer = true +| BSNH | BLNH | BLNH | BNPH | BNPH | BNTH * | BNTH ^ | MHA self, past_present_share_buffer = false +| BSNH | BNLH | BNLH | BNPH | BNPH | BNTH * | BNTH ^ | MHA self, past_present_share_buffer = false +| BSNH | BLNH | BLNH | BNMH | BNMH | BNMH * | BNMH ^ | MHA self, past_present_share_buffer = true +| BSNH | BNLH | BNLH | BNMH | BNMH | BNMH * | BNMH ^ | MHA self, past_present_share_buffer = true +| BLN3H*^| - | - | - | - | - | - | MHA basic, qkv_packed +| BSNH | BLN2H*^| - | - | - | - | - | MHA basic, kv_packed + +Q, K, V, past(K), pastV, present(K), presentV is the Input of the contrib OpKernel + +About k_buffer and v_buffer, we always explicitly concat past to present and use present_k for k_buffer and present_v for v_buffer + +- Marked with `*` indicate the Tensor is used for k_buffer passing. +- Marked with `^` indicate the Tensor is used for v_buffer passing. + +# Supported Op + +- A: Attention +- MHA: MultiHeadAttention + +# Dim Value + +- B: batch_size +- N: num_heads +- H: head_size + +- S: sequence_length +- L: kv_sequence_length +- P: past_sequence_length +- T: total_sequence_length = P + L +- M: max_sequence_length */ #include "core/framework/tensor_shape.h" @@ -67,6 +111,7 @@ are in composable kernels. The scale and add logic is performed via Acc0ElementO #include "contrib_ops/rocm/bert/attention_softmax.h" #ifdef USE_COMPOSABLE_KERNEL #include "contrib_ops/rocm/bert/batched_gemm_softmax_gemm_permute_ck_impl/impl.cuh" +#include "core/providers/rocm/composable_kernel_common.h" #include "ck/ck.hpp" #include "ck/tensor_operation/gpu/device/tensor_layout.hpp" @@ -87,66 +132,208 @@ inline int3 Get2DMaskStrides(int total_sequence_length) { return {total_sequence_length, 0, 1}; } +// A stride maps from natural coordinate to physical offset of underlying memory storage buffer offset. We need to +// specify both of the natural coordinate order, say (b,n,s,h), (b,s,n,h) or (b,n,h,s), and memory order, say BNSH or +// BSNH, to determain the strides. To obtain the offset, we just do the inner product of coordinate with the strides. +// This wrapper create the stride vector from the physical dimension (or physical shape). +struct Strides { + // Create the strides for BNSH physically indexed memory buffer + static Strides BNSHMemory(int batch_dim, + int num_head_dim, + int seqlen_dim, + int head_size_dim) { + ORT_UNUSED_PARAMETER(batch_dim); + return Strides{longlong4{ + static_cast(num_head_dim) * seqlen_dim * head_size_dim, + static_cast(seqlen_dim) * head_size_dim, + static_cast(head_size_dim), + static_cast(1), + }}; + } + + // Create the strides for BSNH physically indexed memory buffer + static Strides BSNHMemory(int batch_dim, + int seqlen_dim, + int num_head_dim, + int head_size_dim) { + ORT_UNUSED_PARAMETER(batch_dim); + return Strides{longlong4{ + static_cast(seqlen_dim) * num_head_dim * head_size_dim, + static_cast(head_size_dim), + static_cast(num_head_dim) * head_size_dim, + static_cast(1), + }}; + } + + template + T ForBNSHCoord() const { + using E = typename T::value_type; + return T{static_cast(strides_for_bnsh_coord.x), + static_cast(strides_for_bnsh_coord.y), + static_cast(strides_for_bnsh_coord.z), + static_cast(strides_for_bnsh_coord.w)}; + } + + template + T ForBSNHCoord() const { + using E = typename T::value_type; + return T{static_cast(strides_for_bnsh_coord.x), + static_cast(strides_for_bnsh_coord.z), + static_cast(strides_for_bnsh_coord.y), + static_cast(strides_for_bnsh_coord.w)}; + } + + template + T ForBNHSCoord() const { + using E = typename T::value_type; + return T{static_cast(strides_for_bnsh_coord.x), + static_cast(strides_for_bnsh_coord.y), + static_cast(strides_for_bnsh_coord.w), + static_cast(strides_for_bnsh_coord.z)}; + } + + int64_t OffsetAt(int b, int n, int s, int h) const { + return strides_for_bnsh_coord.x * b + strides_for_bnsh_coord.y * n + + strides_for_bnsh_coord.z * s + strides_for_bnsh_coord.w * h; + } + + // store intermediate strides in the canonical (b,n,s,h) coordinate order + longlong4 strides_for_bnsh_coord; +}; + template -std::tuple GetQkvBuffers( - const AttentionParameters* attn, - const T* query, - const T* key, - const T* value) { - switch (attn->qkv_format) { - case Q_K_V_BNSH: - case Q_K_V_BSNH: +std::tuple ConvertToOffsetedBufferViews( + const RocmAttentionParameters* attn, + const T* query = nullptr, // q or packed_qkv + const T* key = nullptr, // k or packed kv + const T* value = nullptr, // + const T* present = nullptr, // present or present_k + const T* present_v = nullptr) { + switch (attn->mode) { + case QFMT_KFMT_VFMT_NONE_NONE_NONE_NONE: + case BSNH_BNLH_BNLH_NONE_NONE_NONE_NONE: + case BSNH_BLNH_BLNH_NONE_NONE_NONE_NONE: { return {reinterpret_cast(query), reinterpret_cast(key), reinterpret_cast(value)}; - case Q_KV_BSNH_BSN2H: { + } + case QFMT_KFMT_VFMT_NONE_NONE_2BNTH_NONE: + case QFMT_KFMT_VFMT_2BNPH_NONE_2BNTH_NONE: { + auto offset = static_cast(attn->batch_size) * attn->num_heads * attn->total_sequence_length * + attn->head_size; + return {reinterpret_cast(query), + reinterpret_cast(present), + reinterpret_cast(present) + offset}; + } + case QFMT_KFMT_VFMT_NONE_NONE_2BNMH_NONE: + case QFMT_KFMT_VFMT_2BNMH_NONE_2BNMH_NONE: { + auto offset = static_cast(attn->batch_size) * attn->num_heads * attn->max_sequence_length * + attn->head_size; + return {reinterpret_cast(query), + reinterpret_cast(present), + reinterpret_cast(present) + offset}; + } + case BSNH_BLNH_BLNH_NONE_NONE_BNTH_BNTH: + case BSNH_BNLH_BNLH_NONE_NONE_BNTH_BNTH: + case BSNH_BLNH_BLNH_NONE_NONE_BNMH_BNMH: + case BSNH_BNLH_BNLH_NONE_NONE_BNMH_BNMH: + case BSNH_BLNH_BLNH_BNPH_BNPH_BNTH_BNTH: + case BSNH_BNLH_BNLH_BNPH_BNPH_BNTH_BNTH: + case BSNH_BLNH_BLNH_BNMH_BNMH_BNMH_BNMH: + case BSNH_BNLH_BNLH_BNMH_BNMH_BNMH_BNMH: + return {reinterpret_cast(query), + reinterpret_cast(present), + reinterpret_cast(present_v)}; + case BSNH_BLN2H_NONE_NONE_NONE_NONE_NONE: { auto packed_kv = reinterpret_cast(key); return {reinterpret_cast(query), packed_kv, packed_kv + attn->head_size}; } - case QKV_BSN3H: { + case BLN3H_NONE_NONE_NONE_NONE_NONE_NONE: { auto packed_qkv = reinterpret_cast(query); return {packed_qkv, packed_qkv + 1 * attn->head_size, packed_qkv + 2 * attn->head_size}; } default: - return {nullptr, nullptr, nullptr}; + ORT_ENFORCE("unreachable"); + return {}; } } -inline std::tuple GetQkvStrides(const AttentionParameters* attn) { +inline std::tuple GetQkvStrides(const RocmAttentionParameters* attn) { // G0 not used, because it is the slowest dimension - const int& G1 = attn->num_heads; - const int& M = attn->sequence_length; - const int& N = attn->total_sequence_length; - const int& K = attn->head_size; - const int& O = attn->v_head_size; - - int4 q_strides, k_strides, v_strides; - switch (attn->qkv_format) { - case Q_K_V_BNSH: - q_strides = {G1 * M * K, M * K, K, 1}; - k_strides = {G1 * N * K, N * K, K, 1}; // matrices are transposed - v_strides = {G1 * N * O, N * O, 1, O}; - break; - case Q_KV_BSNH_BSN2H: - ORT_ENFORCE(K == O); - q_strides = {M * G1 * K, K, G1 * K, 1}; // [G0, M, G1, K] layout - k_strides = {N * G1 * 2 * K, 2 * K, G1 * 2 * K, 1}; // [G0, N, G1, K] layout - v_strides = {N * G1 * 2 * O, 2 * O, 1, G1 * 2 * O}; // [G0, N, G1, O] layout - break; - case QKV_BSN3H: - ORT_ENFORCE(K == O); - q_strides = {M * G1 * 3 * K, 3 * K, G1 * 3 * K, 1}; // [G0, M, G1, K] layout - k_strides = {N * G1 * 3 * K, 3 * K, G1 * 3 * K, 1}; // [G0, N, G1, K] layout - v_strides = {N * G1 * 3 * O, 3 * O, 1, G1 * 3 * O}; // [G0, N, G1, O] layout - break; + const int& B = attn->batch_size; + const int& N = attn->num_heads; + const int& S = attn->sequence_length; + const int& L = attn->kv_sequence_length; + const int& T = attn->total_sequence_length; + const int& M = attn->max_sequence_length; + const int& H = attn->head_size; + const int& Hv = attn->v_head_size; + + switch (attn->mode) { + case QFMT_KFMT_VFMT_NONE_NONE_NONE_NONE: + if (attn->qkv_format == Q_K_V_BNSH) { + return { + Strides::BNSHMemory(B, N, S, H), + Strides::BNSHMemory(B, N, L, H), + Strides::BNSHMemory(B, N, L, Hv), + }; + } else if (attn->qkv_format == Q_K_V_BSNH) { + return { + Strides::BSNHMemory(B, S, N, H), + Strides::BSNHMemory(B, L, N, H), + Strides::BSNHMemory(B, L, N, Hv), + }; + } + case BSNH_BLNH_BLNH_NONE_NONE_BNTH_BNTH: + case BSNH_BNLH_BNLH_NONE_NONE_BNTH_BNTH: + case BSNH_BLNH_BLNH_BNPH_BNPH_BNTH_BNTH: + case BSNH_BNLH_BNLH_BNPH_BNPH_BNTH_BNTH: + return { + Strides::BSNHMemory(B, S, N, H), + Strides::BNSHMemory(B, N, T, H), + Strides::BNSHMemory(B, N, T, Hv), + }; + case BSNH_BLNH_BLNH_NONE_NONE_BNMH_BNMH: + case BSNH_BNLH_BNLH_NONE_NONE_BNMH_BNMH: + case BSNH_BLNH_BLNH_BNMH_BNMH_BNMH_BNMH: + case BSNH_BNLH_BNLH_BNMH_BNMH_BNMH_BNMH: + return { + Strides::BSNHMemory(B, S, N, H), + Strides::BNSHMemory(B, N, M, H), + Strides::BNSHMemory(B, N, M, Hv), + }; + case BSNH_BLNH_BLNH_NONE_NONE_NONE_NONE: + return { + Strides::BSNHMemory(B, S, N, H), + Strides::BSNHMemory(B, L, N, H), + Strides::BSNHMemory(B, L, N, Hv), + }; + case BSNH_BNLH_BNLH_NONE_NONE_NONE_NONE: + return { + Strides::BSNHMemory(B, S, N, H), + Strides::BNSHMemory(B, N, L, H), + Strides::BNSHMemory(B, N, L, Hv), + }; + case BSNH_BLN2H_NONE_NONE_NONE_NONE_NONE: + return { + Strides::BSNHMemory(B, S, N, H), + Strides::BSNHMemory(B, L, N, 2 * H), + Strides::BSNHMemory(B, L, N, 2 * Hv), + }; + case BLN3H_NONE_NONE_NONE_NONE_NONE_NONE: + return { + Strides::BSNHMemory(B, L, N, 3 * H), + Strides::BSNHMemory(B, L, N, 3 * H), + Strides::BSNHMemory(B, L, N, 3 * Hv), + }; default: - break; + ORT_ENFORCE("unreachable"); + return {}; } - return {q_strides, k_strides, v_strides}; } inline std::tuple GetRawMaskBufferAddrSizesAndStrides( - const int* buffer, const AttentionParameters* attn) { + const int* buffer, const RocmAttentionParameters* attn) { const int* offseted_buffer{buffer}; // how to view the mask buffer int3 sizes{0, 0, 0}; // the logical shape of the view int3 strides{-1, -1, -1}; // the physical memory layout @@ -184,9 +371,11 @@ struct GemmSoftmaxGemmPermuteParams : onnxruntime::rocm::tunable::OpParams { "_T", attention->total_sequence_length, "_N", attention->num_heads, "_H", attention->head_size, + "_Hv", attention->v_head_size, bias_buffer != nullptr ? "_B" : "_NB", "_M", mask_index_dims.size(), - "_QKV", attention->qkv_format); + "_QKV", attention->qkv_format, + "_MODE", attention->mode); } std::tuple GetGemmsMNKOBatch() const { @@ -194,13 +383,13 @@ struct GemmSoftmaxGemmPermuteParams : onnxruntime::rocm::tunable::OpParams { auto m = attention->sequence_length; auto n = attention->total_sequence_length; auto k = attention->head_size; - auto o = attention->head_size; + auto o = attention->v_head_size; auto batch = attention->batch_size * attention->num_heads; return {m, n, k, o, batch}; } rocblas_handle handle; - const AttentionParameters* attention; + const RocmAttentionParameters* attention; const hipDeviceProp_t* device_prop; float scale; @@ -220,6 +409,20 @@ struct GemmSoftmaxGemmPermuteParams : onnxruntime::rocm::tunable::OpParams { void* workspace_buffer{nullptr}; }; +inline bool IsKVBNMH(AttentionMode mode) { + switch (mode) { + case QFMT_KFMT_VFMT_NONE_NONE_2BNMH_NONE: + case QFMT_KFMT_VFMT_2BNMH_NONE_2BNMH_NONE: + case BSNH_BLNH_BLNH_NONE_NONE_BNMH_BNMH: + case BSNH_BNLH_BNLH_NONE_NONE_BNMH_BNMH: + case BSNH_BLNH_BLNH_BNMH_BNMH_BNMH_BNMH: + case BSNH_BNLH_BNLH_BNMH_BNMH_BNMH_BNMH: + return true; + default: + return false; + } +} + template struct GemmSoftmaxGemmPermuteGenericPipeline { static bool UseRawAttentionMask(const GemmSoftmaxGemmPermuteParams* params) { @@ -239,7 +442,7 @@ struct GemmSoftmaxGemmPermuteGenericPipeline { return {gemm1_out, softmax_out, gemm2_out}; } - inline static size_t GetWorkspaceNumBytes(const AttentionParameters* attn) { + inline static size_t GetWorkspaceNumBytes(const RocmAttentionParameters* attn) { return GetAttentionWorkspaceSize( sizeof(T), attn->batch_size, @@ -252,6 +455,12 @@ struct GemmSoftmaxGemmPermuteGenericPipeline { inline static Status Gemm1(const GemmSoftmaxGemmPermuteParams* params) { auto [m, n, k, o, batch] = params->GetGemmsMNKOBatch(); auto [gemm1_out, softmax_out, gemm2_out] = GetWorkspacePlan(params); + + int k_buffer_stride = n * k; + if (IsKVBNMH(params->attention->mode)) { + k_buffer_stride = params->attention->max_sequence_length * params->attention->head_size; + } + // GEMM1 [m,k] * [n,k]' -> [m,n] return blas::row_major::StridedBatchedGemm( params->TuningContext(), params->Stream(), params->handle, @@ -260,7 +469,7 @@ struct GemmSoftmaxGemmPermuteGenericPipeline { // For raw attention mask, the scalar is moved to softmax computation. /*alpha=*/UseRawAttentionMask(params) ? 1.0f : params->scale, params->q_buffer, k, m * k, - params->k_buffer, k, n * k, + params->k_buffer, k, k_buffer_stride, /*beta=*/0.0f, gemm1_out, n, m * n, batch); @@ -289,7 +498,7 @@ struct GemmSoftmaxGemmPermuteGenericPipeline { auto [gemm1_out, softmax_out, gemm2_out] = GetWorkspacePlan(params); const int* mask_start = (mask_1d_size > attn->batch_size) ? mask_1d + attn->batch_size : nullptr; return ComputeSoftmaxWithMask1D( - params->Stream(), attn->total_sequence_length, attn->sequence_length, attn->batch_size, attn->num_heads, + params->StreamHandle(), attn->total_sequence_length, attn->sequence_length, attn->batch_size, attn->num_heads, mask_1d, mask_start, params->bias_buffer, gemm1_out, softmax_out, attn->is_unidirectional); } @@ -298,13 +507,19 @@ struct GemmSoftmaxGemmPermuteGenericPipeline { auto attn = params->attention; auto [gemm1_out, softmax_out, gemm2_out] = GetWorkspacePlan(params); return ComputeSoftmax( - params->Stream(), attn->total_sequence_length, attn->sequence_length, attn->batch_size, attn->num_heads, + params->StreamHandle(), attn->total_sequence_length, attn->sequence_length, attn->batch_size, attn->num_heads, params->bias_buffer, gemm1_out, softmax_out, attn->is_unidirectional); } inline static Status Gemm2(const GemmSoftmaxGemmPermuteParams* params) { auto [m, n, k, o, batch] = params->GetGemmsMNKOBatch(); auto [gemm1_out, softmax_out, gemm2_out] = GetWorkspacePlan(params); + + int v_buffer_stride = n * o; + if (IsKVBNMH(params->attention->mode)) { + v_buffer_stride = params->attention->max_sequence_length * params->attention->v_head_size; + } + // GEMM2 [m,n] * [n,o] -> [m,o] // semantically, the output buffer contains B*N matrices of shape [S,H], compactly, thus B,N,S,H. return blas::row_major::StridedBatchedGemm( @@ -313,7 +528,7 @@ struct GemmSoftmaxGemmPermuteGenericPipeline { m, o, n, /*alpha=*/1.0f, softmax_out, n, m * n, - params->v_buffer, o, n * o, + params->v_buffer, o, v_buffer_stride, /*beta=*/0.0f, gemm2_out, o, m * o, batch); @@ -325,14 +540,58 @@ struct GemmSoftmaxGemmPermuteGenericPipeline { auto attn = params->attention; auto [gemm1_out, softmax_out, gemm2_out] = GetWorkspacePlan(params); return LaunchTransCtx( - params->Stream(), + params->StreamHandle(), attn->sequence_length, attn->batch_size, attn->head_size, attn->num_heads, params->device_prop->maxThreadsPerBlock, false, gemm2_out, params->out_buffer); } + static Status GetSupportedStatus(const GemmSoftmaxGemmPermuteParams* params) { + const auto& attn = params->attention; + // TODO: address the BNMH k,v strides + switch (attn->mode) { + case QFMT_KFMT_VFMT_NONE_NONE_NONE_NONE: + case QFMT_KFMT_VFMT_NONE_NONE_2BNTH_NONE: + case QFMT_KFMT_VFMT_2BNPH_NONE_2BNTH_NONE: + case QFMT_KFMT_VFMT_NONE_NONE_2BNMH_NONE: + case QFMT_KFMT_VFMT_2BNMH_NONE_2BNMH_NONE: + if (attn->qkv_format == Q_K_V_BNSH) { + return Status::OK(); + } else { + return TUNABLE_OP_UNSUPPORTED("GenericPipeline only supports qkv_format as Q_K_V_BNSH, got ", + attn->qkv_format); + } + case BSNH_BLNH_BLNH_NONE_NONE_NONE_NONE: + return TUNABLE_OP_UNSUPPORTED("GenericPipeline only supports qkv_format as Q_K_V_BNSH but k, v are BLNH"); + case BSNH_BNLH_BNLH_NONE_NONE_NONE_NONE: + case BSNH_BLNH_BLNH_NONE_NONE_BNTH_BNTH: + case BSNH_BNLH_BNLH_NONE_NONE_BNTH_BNTH: + case BSNH_BLNH_BLNH_BNPH_BNPH_BNTH_BNTH: + case BSNH_BNLH_BNLH_BNPH_BNPH_BNTH_BNTH: + case BSNH_BLNH_BLNH_NONE_NONE_BNMH_BNMH: + case BSNH_BLNH_BLNH_BNMH_BNMH_BNMH_BNMH: + case BSNH_BNLH_BNLH_NONE_NONE_BNMH_BNMH: + case BSNH_BNLH_BNLH_BNMH_BNMH_BNMH_BNMH: + // If sequence_length is 1, query of B1NH can be simply viewed as BN1H. + if (attn->sequence_length == 1) { + return Status::OK(); + } else { + return TUNABLE_OP_UNSUPPORTED("GenericPipeline only supports qkv_format as Q_K_V_BNSH, ", + "only if sequence_length is 1, query of BSNH can be viewed as BNSH"); + } + case BLN3H_NONE_NONE_NONE_NONE_NONE_NONE: + case BSNH_BLN2H_NONE_NONE_NONE_NONE_NONE: + return TUNABLE_OP_UNSUPPORTED("GenericPipeline only supports qkv_format as Q_K_V_BNSH"); + default: + return TUNABLE_OP_UNSUPPORTED("unknonw"); + } + return TUNABLE_OP_UNSUPPORTED("unknonw case"); + } + static Status Run(const GemmSoftmaxGemmPermuteParams* params, bool use_persistent_softmax) { - TUNABLE_OP_RETURN_UNSUPPORTED_ARGUMENT_IF( - params->attention->qkv_format != Q_K_V_BNSH, "GenericPipeline only supports qkv_format as Q_K_V_BNSH"); + auto supported_status = GetSupportedStatus(params); + if (!supported_status.IsOK()) { + return supported_status; + } ORT_RETURN_IF_ERROR(Gemm1(params)); if (UseRawAttentionMask(params)) { @@ -354,19 +613,35 @@ class GemmSoftmaxGemmPermuteTunableOp : public tunable::TunableOpqkv_format) { - case Q_K_V_BNSH: - case Q_K_V_BSNH: - case Q_KV_BSNH_BSN2H: - case QKV_BSN3H: + inline static bool IsSupportedMode(const RocmAttentionParameters* attn) { + switch (attn->mode) { + case QFMT_KFMT_VFMT_NONE_NONE_NONE_NONE: + case QFMT_KFMT_VFMT_2BNPH_NONE_2BNTH_NONE: + // depends on qkv format + if (attn->qkv_format == Q_K_V_BNSH || attn->qkv_format == Q_K_V_BSNH) { + return true; + } else { + return false; + } + case BSNH_BLNH_BLNH_BNPH_BNPH_BNTH_BNTH: + case BSNH_BNLH_BNLH_BNPH_BNPH_BNTH_BNTH: + case BSNH_BLNH_BLNH_BNMH_BNMH_BNMH_BNMH: + case BSNH_BNLH_BNLH_BNMH_BNMH_BNMH_BNMH: + case BSNH_BLNH_BLNH_NONE_NONE_NONE_NONE: + case BSNH_BNLH_BNLH_NONE_NONE_NONE_NONE: + case BSNH_BLNH_BLNH_NONE_NONE_BNTH_BNTH: + case BSNH_BNLH_BNLH_NONE_NONE_BNTH_BNTH: + case BSNH_BLNH_BLNH_NONE_NONE_BNMH_BNMH: + case BSNH_BNLH_BNLH_NONE_NONE_BNMH_BNMH: + case BSNH_BLN2H_NONE_NONE_NONE_NONE_NONE: + case BLN3H_NONE_NONE_NONE_NONE_NONE_NONE: return true; default: return false; } } - inline static bool IsSupportedMaskType(const AttentionParameters* attn) { + inline static bool IsSupportedMaskType(const RocmAttentionParameters* attn) { switch (attn->mask_type) { case MASK_NONE: case MASK_2D_DUMMY: @@ -379,12 +654,17 @@ class GemmSoftmaxGemmPermuteTunableOp : public tunable::TunableOp::GetWorkspaceNumBytes(attn); + +#ifdef USE_COMPOSABLE_KERNEL + if (IsSupportedMaskType(attn)) { + auto [buffer, sizes, strides] = GetRawMaskBufferAddrSizesAndStrides(nullptr, attn); + num_bytes = std::max(num_bytes, sizeof(T) * sizes.x * sizes.y * sizes.z); } - auto [buffer, sizes, strides] = GetRawMaskBufferAddrSizesAndStrides(nullptr, attn); - return sizeof(T) * sizes.x * sizes.y * sizes.z; +#endif + + return num_bytes; } template @@ -421,7 +701,7 @@ class GemmSoftmaxGemmPermuteTunableOp : public tunable::TunableOp(out + out_offset) = store; } else { #pragma unroll - for (int i = tidx; i < mask_lengths.z; i++) { + for (int i = 0; i < mask_lengths.z - tidx; i++) { out[out_offset + i] = cvt(mask_buffer[in_offset + i]); } } @@ -441,7 +721,7 @@ class GemmSoftmaxGemmPermuteTunableOp : public tunable::TunableOp<<Stream()>>>( + ConvertToFilledMaskValue<<StreamHandle()>>>( reinterpret_cast(params->workspace_buffer), {lengths.y * lengths.z, lengths.z, 1}, // out desc buffer, lengths, strides, // mask desc cvt); @@ -451,22 +731,6 @@ class GemmSoftmaxGemmPermuteTunableOp : public tunable::TunableOp -struct DataTypeAdaptor { - using type = T; -}; - -template <> -struct DataTypeAdaptor { - using type = ck::half_t; -}; - -template <> -struct DataTypeAdaptor { - using type = ck::bhalf16_t; -}; -} // namespace template auto GetCKGemmSoftmaxGemmPermuteTypeStringAndOps() { @@ -475,7 +739,7 @@ auto GetCKGemmSoftmaxGemmPermuteTypeStringAndOps() { using Nop = ck::tensor_operation::element_wise::PassThrough; using Acc0ElementOp = internal::PreSoftmaxAttentionScoreOp; - using CKDataType = typename DataTypeAdaptor::type; + using CKDataType = typename CKDataTypeAdaptor::type; using D0DataType = typename ck::detail::tuple_concat< std::conditional_t, ck::Tuple<>>, std::conditional_t, ck::Tuple<>>>::type; @@ -492,8 +756,8 @@ auto GetCKGemmSoftmaxGemmPermuteTypeStringAndOps() { auto op = [impl = std::move(impl), invoker = std::move(invoker)]( const GemmSoftmaxGemmPermuteParams* params) -> Status { TUNABLE_OP_RETURN_UNSUPPORTED_ARGUMENT_IF( - !GemmSoftmaxGemmPermuteTunableOp::IsSupportedQkvFormat(params->attention), - "qkv format is not supported, got ", params->attention->qkv_format); + !GemmSoftmaxGemmPermuteTunableOp::IsSupportedMode(params->attention), + "attention mode is not supported, got ", params->attention->mode); if constexpr (USE_BIAS) { TUNABLE_OP_RETURN_UNSUPPORTED_ARGUMENT_IF( params->bias_buffer == nullptr, "biased version only support input with bias"); @@ -522,16 +786,15 @@ auto GetCKGemmSoftmaxGemmPermuteTypeStringAndOps() { { auto [m, n, k, o, batch] = params->GetGemmsMNKOBatch(); ORT_ENFORCE(M == m && N == n && K == k && O == o && G0 * G1 == batch, "semantic mismatch"); - ORT_ENFORCE(K == O, "inner product dimension mismatch"); } auto [qs, ks, vs] = GetQkvStrides(attn); std::vector q_buffer_lengths = {G0, G1, M, K}; - std::vector q_buffer_strides = {qs.x, qs.y, qs.z, qs.w}; + std::vector q_buffer_strides = qs.template ForBNSHCoord>(); std::vector k_buffer_lengths = {G0, G1, N, K}; - std::vector k_buffer_strides = {ks.x, ks.y, ks.z, ks.w}; + std::vector k_buffer_strides = ks.template ForBNSHCoord>(); std::vector v_buffer_lengths = {G0, G1, O, N}; - std::vector v_buffer_strides = {vs.x, vs.y, vs.z, vs.w}; + std::vector v_buffer_strides = vs.template ForBNHSCoord>(); std::vector out_buffer_lengths = {G0, G1, M, O}; std::vector out_buffer_strides = {M * G1 * O, O, G1 * O, 1}; // permute 0213 @@ -580,7 +843,7 @@ auto GetCKGemmSoftmaxGemmPermuteTypeStringAndOps() { if constexpr (USE_MASK) { ORT_RETURN_IF_ERROR(GemmSoftmaxGemmPermuteTunableOp::LaunchConvertToFilledMaskValue(params)); } - invoker->Run(arg.get(), StreamConfig{params->Stream()}); + invoker->Run(arg.get(), StreamConfig{params->StreamHandle()}); return Status::OK(); }; ret.emplace_back(std::make_pair(std::move(type_string), std::move(op))); diff --git a/onnxruntime/contrib_ops/rocm/bert/decoder_attention_impl.h b/onnxruntime/contrib_ops/rocm/bert/decoder_attention_impl.h new file mode 100644 index 0000000000000..d71c6d8440a44 --- /dev/null +++ b/onnxruntime/contrib_ops/rocm/bert/decoder_attention_impl.h @@ -0,0 +1,46 @@ +// 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 "core/providers/rocm/shared_inc/rocm_utils.h" +#include "core/providers/rocm/tunable/rocm_tunable.h" + +namespace onnxruntime { +namespace contrib { +namespace rocm { + +Status LaunchDecoderAttentionKernel( + const hipDeviceProp_t& prop, // Device Properties + RocmTuningContext* tuning_ctx, // context for tuning + Stream* stream, // ORT Stream + rocblas_handle& rocblas, // Rocblas handle + const size_t element_size, // Element size of input tensor + const int batch_size, // Batch size (B) + const int sequence_length, // Sequence length (S) + const int kv_sequence_length, // Key/Value/Cache sequence length + const int num_heads, // Number of attention heads (N) + const int head_size, // Hidden layer size per head (H) + const bool static_kv, // Whether cross attention or not + const bool use_past, // Whether use cache or not + const bool has_layer_state, // Whether output cache or not + const bool has_key_padding_mask, // Whether use key_padding_mask or not + const float mask_filter_value, // Mask filter value + const void* gemm_query_buffer, // Query buffer + const void* gemm_kv_buffer, // Key and value buffer + const bool* key_padding_mask, // Key padding mask + const void* key_cache, // Input key cache + const void* value_cache, // Input value cache + void* qkv_buffer, // Temporary buffer + void* workspace_buffer, // Temporary buffer + void* output, // Output tensor + void* new_key_cache, // New_key_cache tensor + void* new_value_cache // New_value_cache tensor +); + +} // namespace rocm +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/rocm/bert/elementwise.h b/onnxruntime/contrib_ops/rocm/bert/elementwise.h new file mode 100644 index 0000000000000..dd78f47f48b9b --- /dev/null +++ b/onnxruntime/contrib_ops/rocm/bert/elementwise.h @@ -0,0 +1,82 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/common/common.h" +#include "core/providers/rocm/tunable/rocm_tunable.h" + +namespace onnxruntime { +namespace contrib { +namespace rocm { + +template +Status LaunchElementwiseKernel(RocmTuningContext* tuning_ctx, Stream* stream, + const T* input, int input_length, + const T* bias, int bias_length, + T* output); + +// The following is LaunchElementwiseKernel implementation detail. Their interfaces are exposed for kernel explorer. +namespace internal { + +template +struct ElementwiseParams : OpParams { + ElementwiseParams(RocmTuningContext* tuning_ctx, onnxruntime::Stream* stream, + const T* input, const T* bias, T* output, int input_length, int bias_length) + : OpParams(tuning_ctx, stream), + input(input), + bias(bias), + output(output), + input_length(input_length), + bias_length(bias_length) {} + + std::string Signature() const override { + std::string sig = std::to_string(input_length) + "_" + std::to_string(bias_length); + return sig; + } + + const T* input; + const T* bias; + T* output; + int input_length; + int bias_length; +}; + +template +class ElementwiseOp { + public: + Status operator()(const ElementwiseParams* params); + Status IsSupported(const ElementwiseParams* params); +}; + +template +Status ElementwiseStaticSelection(const ElementwiseParams* params); + +template +class ElementwiseTunableOp : public TunableOp> { + public: + ElementwiseTunableOp(); +}; + +} // namespace internal + +#define ELEMENTWISE_FWD_DECL(FnName, T) \ + namespace functor { \ + struct FnName; \ + } + +ELEMENTWISE_FWD_DECL(FastGeLU, float); +ELEMENTWISE_FWD_DECL(FastGeLU, half); +ELEMENTWISE_FWD_DECL(FastGeLU, BFloat16); + +ELEMENTWISE_FWD_DECL(GeLU, float); +ELEMENTWISE_FWD_DECL(GeLU, half); +ELEMENTWISE_FWD_DECL(GeLU, BFloat16); + +ELEMENTWISE_FWD_DECL(ReLU, float); +ELEMENTWISE_FWD_DECL(ReLU, half); +ELEMENTWISE_FWD_DECL(ReLU, BFloat16); + +} // namespace rocm +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/rocm/bert/elementwise_impl/impl.cuh b/onnxruntime/contrib_ops/rocm/bert/elementwise_impl/impl.cuh new file mode 100644 index 0000000000000..3055d59cf17ae --- /dev/null +++ b/onnxruntime/contrib_ops/rocm/bert/elementwise_impl/impl.cuh @@ -0,0 +1,256 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/providers/rocm/tunable/util.h" +#include "core/providers/rocm/cu_inc/common.cuh" +#include "contrib_ops/rocm/bert/elementwise.h" + +namespace onnxruntime { +namespace contrib { +namespace rocm { + +namespace functor { + +struct FastGeLU { + template + __host__ __device__ __forceinline__ void operator()(T& y, const T& x) const { + constexpr const float b = 0.7978845608028654f; // sqrt(2.0/M_PI) + + // const T cdf = a + a * _Tanh(in * (c * in * in + b)); + const T xb = x * T(b); + const T u = xb * T(0.044715f) * x * x + xb; + const T emu = __expf(-u - u); + const T cdf = T(1.0f) / (T(1.0f) + emu); + y = x * cdf; + } +}; + +struct GeLU { + template + __host__ __device__ __forceinline__ void operator()(T& y, const T& x) const { + y = T(0.5f) * x * (T(1.f) + T(erf(0.70710678118f * float(x)))); + } +}; + +struct ReLU { + template + __host__ __device__ __forceinline__ void operator()(T& y, const T& x) const { + y = x >= T{} ? x : T{}; + } +}; + +} // namespace functor + +using onnxruntime::rocm::CeilDiv; +using onnxruntime::rocm::GPU_WARP_SIZE; + +template +__global__ void ElementwiseKernel( + const T* __restrict__ input, int input_length, + const T* __restrict__ bias, int bias_length, + T* __restrict__ output) { + const int idx = blockIdx.x * TPB + threadIdx.x; + Fn f{}; + + if (idx < input_length) { + const T x = input[idx] + (bias == nullptr ? T{} : bias[idx % bias_length]); + f(output[idx], x); + } +} + +template +__global__ void ElementwiseKernelVec( + const T* __restrict__ input, int input_length, + const T* __restrict__ bias, int bias_length, + T* output) { + using VecT = onnxruntime::rocm::aligned_vector; + Fn f{}; + + const int idx = (blockIdx.x * TPB + threadIdx.x) * ILP; + if (idx < input_length) { + T input_v[ILP]; + VecT* input_val = reinterpret_cast(&input_v); + *input_val = *reinterpret_cast(&input[idx]); + T output_v[ILP]; + VecT* output_val = reinterpret_cast(&output_v); + T bias_v[ILP]; + if (bias != nullptr) { + VecT* bias_val = reinterpret_cast(&bias_v); + *bias_val = *reinterpret_cast(&bias[idx % bias_length]); + } + +#pragma unroll + for (int i = 0; i < ILP; i++) { + const T x = (bias == nullptr) ? input_v[i] : (T)(input_v[i] + bias_v[i]); + f(output_v[i], x); + } + *(reinterpret_cast(&output[idx])) = *output_val; + } +} + +template +Status LaunchElementwiseKernel( + RocmTuningContext* tuning_ctx, Stream* stream, + const T* input, int input_length, + const T* bias, int bias_length, + T* output) { + internal::ElementwiseParams params(tuning_ctx, stream, input, bias, output, input_length, bias_length); + if (tuning_ctx->IsTunableOpEnabled()) { + static internal::ElementwiseTunableOp op; + return op(¶ms); + } + + return internal::ElementwiseStaticSelection(¶ms); +} + +namespace internal { + +template +Status ElementwiseOp::operator()(const ElementwiseParams* params) { + dim3 blocks(CeilDiv(params->input_length, ThreadsPerBlock * VecSize)); + ElementwiseKernelVec<<StreamHandle()>>>( + params->input, params->input_length, + params->bias, params->bias_length, + params->output); + return HIP_CALL(hipGetLastError()); +} + +template +Status ElementwiseOp::IsSupported(const ElementwiseParams* params) { + // TODO(anyone): Add tail handling for FastGelu + TUNABLE_OP_RETURN_UNSUPPORTED_ARGUMENT_IF( + !((params->bias_length > 0 && params->bias_length % VecSize == 0 && params->input_length % VecSize == 0) || + (params->bias_length == 0 && params->input_length % VecSize == 0))); + // Avoid redundant configurations + TUNABLE_OP_RETURN_UNSUPPORTED_ARGUMENT_IF(!(params->input_length > (ThreadsPerBlock - GPU_WARP_SIZE) * VecSize)); + + return Status::OK(); +} + +template +Status ElementwiseStaticSelection(const ElementwiseParams* params) { + constexpr int block_size = 256; + if constexpr (std::is_same_v) { + if (params->bias != nullptr) { + if (0 == (params->bias_length % 8) && (params->input_length >= 3145728)) { // 3145728=8*128*3072 + const int grid_size = (params->input_length / 8 + block_size - 1) / block_size; + ElementwiseKernelVec<<StreamHandle()>>>( + params->input, params->input_length, params->bias, params->bias_length, params->output); + } else if (0 == (params->bias_length % 4)) { + const int grid_size = (params->input_length / 4 + block_size - 1) / block_size; + ElementwiseKernelVec<<StreamHandle()>>>( + params->input, params->input_length, params->bias, params->bias_length, params->output); + } else if (0 == (params->bias_length % 2)) { + const int grid_size = (params->input_length / 2 + block_size - 1) / block_size; + ElementwiseKernelVec<<StreamHandle()>>>( + params->input, params->input_length, params->bias, params->bias_length, params->output); + } else { + const int grid_size = (params->input_length + block_size - 1) / block_size; + ElementwiseKernel<<StreamHandle()>>>( + params->input, params->input_length, params->bias, params->bias_length, params->output); + } + } else { + if (0 == (params->input_length % 8) && (params->input_length >= 3145728)) { // 3145728=8*128*3072 + const int grid_size = (params->input_length / 8 + block_size - 1) / block_size; + ElementwiseKernelVec<<StreamHandle()>>>( + params->input, params->input_length, params->bias, params->bias_length, params->output); + } else if (0 == (params->input_length % 4)) { + const int grid_size = (params->input_length / 4 + block_size - 1) / block_size; + ElementwiseKernelVec<<StreamHandle()>>>( + params->input, params->input_length, params->bias, params->bias_length, params->output); + } else if (0 == (params->input_length % 2)) { + const int grid_size = (params->input_length / 2 + block_size - 1) / block_size; + ElementwiseKernelVec<<StreamHandle()>>>( + params->input, params->input_length, params->bias, params->bias_length, params->output); + } else { + const int grid_size = (params->input_length + block_size - 1) / block_size; + ElementwiseKernel<<StreamHandle()>>>( + params->input, params->input_length, params->bias, params->bias_length, params->output); + } + } + } else { + const int grid_size = (params->input_length + block_size - 1) / block_size; + ElementwiseKernel<<StreamHandle()>>>( + params->input, params->input_length, params->bias, params->bias_length, params->output); + } + return HIP_CALL(hipGetLastError()); +} + +template +ElementwiseTunableOp::ElementwiseTunableOp() { + this->RegisterOp(ElementwiseStaticSelection); + + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); + this->RegisterOp(ElementwiseOp{}); +} + +#undef ADD_OP + +} // namespace internal + +} // namespace rocm +} // namespace contrib +} // namespace onnxruntime + +#define ELEMENTWISE_KERNEL_IMPL(Fn, T) \ + namespace onnxruntime { \ + namespace contrib { \ + namespace rocm { \ + template Status LaunchElementwiseKernel( \ + RocmTuningContext * tuning_ctx, Stream* stream, \ + const T* input, int input_length, \ + const T* bias, int bias_length, \ + T* output); \ + namespace internal { \ + template class ElementwiseTunableOp; \ + } \ + } \ + } \ + } diff --git a/onnxruntime/contrib_ops/rocm/bert/elementwise_impl/impl_fastgelu.cu b/onnxruntime/contrib_ops/rocm/bert/elementwise_impl/impl_fastgelu.cu new file mode 100644 index 0000000000000..3e9534f459338 --- /dev/null +++ b/onnxruntime/contrib_ops/rocm/bert/elementwise_impl/impl_fastgelu.cu @@ -0,0 +1,8 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "contrib_ops/rocm/bert/elementwise_impl/impl.cuh" + +ELEMENTWISE_KERNEL_IMPL(functor::FastGeLU, float); +ELEMENTWISE_KERNEL_IMPL(functor::FastGeLU, half); +ELEMENTWISE_KERNEL_IMPL(functor::FastGeLU, BFloat16); diff --git a/onnxruntime/contrib_ops/rocm/bert/elementwise_impl/impl_gelu.cu b/onnxruntime/contrib_ops/rocm/bert/elementwise_impl/impl_gelu.cu new file mode 100644 index 0000000000000..dafc524405eb9 --- /dev/null +++ b/onnxruntime/contrib_ops/rocm/bert/elementwise_impl/impl_gelu.cu @@ -0,0 +1,8 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "contrib_ops/rocm/bert/elementwise_impl/impl.cuh" + +ELEMENTWISE_KERNEL_IMPL(functor::GeLU, float); +ELEMENTWISE_KERNEL_IMPL(functor::GeLU, half); +ELEMENTWISE_KERNEL_IMPL(functor::GeLU, BFloat16); diff --git a/onnxruntime/contrib_ops/rocm/bert/elementwise_impl/impl_relu.cu b/onnxruntime/contrib_ops/rocm/bert/elementwise_impl/impl_relu.cu new file mode 100644 index 0000000000000..67e50869133f5 --- /dev/null +++ b/onnxruntime/contrib_ops/rocm/bert/elementwise_impl/impl_relu.cu @@ -0,0 +1,8 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "contrib_ops/rocm/bert/elementwise_impl/impl.cuh" + +ELEMENTWISE_KERNEL_IMPL(functor::ReLU, float); +ELEMENTWISE_KERNEL_IMPL(functor::ReLU, half); +ELEMENTWISE_KERNEL_IMPL(functor::ReLU, BFloat16); diff --git a/onnxruntime/contrib_ops/rocm/bert/fast_gelu.cc b/onnxruntime/contrib_ops/rocm/bert/fast_gelu.cc index b81c511124c0d..9cb414e4e8980 100644 --- a/onnxruntime/contrib_ops/rocm/bert/fast_gelu.cc +++ b/onnxruntime/contrib_ops/rocm/bert/fast_gelu.cc @@ -1,15 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -// Modifications: Remove GetDeviceProp in LaunchFastGeluKernel. -// Copyright (c) Advanced Micro Devices, Inc. All rights reserved. -// Licensed under the MIT License. +#include "contrib_ops/rocm/bert/fast_gelu.h" #include "core/providers/rocm/rocm_common.h" #include "core/providers/rocm/miopen_common.h" -#include "contrib_ops/rocm/bert/fast_gelu.h" -#include "contrib_ops/rocm/bert/fast_gelu_impl.h" #include "contrib_ops/cpu/bert/bias_gelu_helper.h" +#include "contrib_ops/rocm/bert/elementwise.h" #include "contrib_ops/rocm/bert/transformer_common.h" namespace onnxruntime { @@ -48,13 +45,13 @@ Status FastGelu::ComputeInternal(OpKernelContext* context) const { int64_t bias_length = (nullptr == bias) ? 0 : bias->Shape().Size(); typedef typename ToHipType::MappedType HipT; - return LaunchFastGeluKernel(GetTuningContext(), - Stream(context), - static_cast(input_length), - static_cast(bias_length), - reinterpret_cast(input->Data()), - (nullptr != bias) ? reinterpret_cast(bias->Data()) : nullptr, - reinterpret_cast(output->MutableData())); + const HipT* input_buffer = reinterpret_cast(input->Data()); + const HipT* bias_buffer = (nullptr != bias) ? reinterpret_cast(bias->Data()) : nullptr; + return LaunchElementwiseKernel( + GetTuningContext(), context->GetComputeStream(), + input_buffer, static_cast(input_length), + bias_buffer, static_cast(bias_length), + reinterpret_cast(output->MutableData())); } } // namespace rocm diff --git a/onnxruntime/contrib_ops/rocm/bert/fast_gelu.h b/onnxruntime/contrib_ops/rocm/bert/fast_gelu.h index 1bef59334c2f3..42bfe5a0b0246 100644 --- a/onnxruntime/contrib_ops/rocm/bert/fast_gelu.h +++ b/onnxruntime/contrib_ops/rocm/bert/fast_gelu.h @@ -5,7 +5,6 @@ #include "core/common/common.h" #include "core/providers/rocm/rocm_kernel.h" -#include "contrib_ops/rocm/bert/fast_gelu_impl.h" namespace onnxruntime { namespace contrib { diff --git a/onnxruntime/contrib_ops/rocm/bert/fast_gelu_impl.cu b/onnxruntime/contrib_ops/rocm/bert/fast_gelu_impl.cu deleted file mode 100644 index f0ec070663d64..0000000000000 --- a/onnxruntime/contrib_ops/rocm/bert/fast_gelu_impl.cu +++ /dev/null @@ -1,68 +0,0 @@ -/* - The implementation of this file is based on gelu plugin in TensorRT demo: - https://github.com/NVIDIA/TensorRT/tree/release/5.1/demo/BERT/ - -Copyright 2019 NVIDIA Corporation - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Modifications: Add (bias) before Gelu is merged into this op to get better performance. -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// Modifications: Add FastGeluKernelVec to leverage vectorized load/write -// and modify FastGeluKernel to get better performance. -// Copyright (c) Advanced Micro Devices, Inc. All rights reserved. -// Licensed under the MIT License. - -#include "core/providers/rocm/rocm_common.h" -#include "core/providers/rocm/cu_inc/common.cuh" -#include "core/providers/rocm/shared_inc/rocm_call.h" -#include "contrib_ops/rocm/bert/fast_gelu_impl_kernel.h" -#include "contrib_ops/rocm/bert/fast_gelu_impl.h" -#include "contrib_ops/rocm/bert/fast_gelu_tunable_op.h" - -using namespace onnxruntime::rocm; - -namespace onnxruntime { -namespace contrib { -namespace rocm { - -template -Status LaunchFastGeluKernel(RocmTuningContext* tuning_ctx, hipStream_t stream, int input_length, int bias_length, - const T* input, const T* bias, T* output) { - FastGeluParams params(tuning_ctx, stream, input, bias, output, input_length, bias_length); - if (tuning_ctx->IsTunableOpEnabled()) { - static FastGeluTunableOp op; - return op(¶ms); - } - - return FastGeluStaticSelection(¶ms); -} - -template Status LaunchFastGeluKernel(RocmTuningContext* tuning_ctx, hipStream_t stream, - int input_length, int bias_length, - const float* input, const float* bias, float* output); - -template Status LaunchFastGeluKernel(RocmTuningContext* tuning_ctx, hipStream_t stream, - int input_length, int bias_length, - const BFloat16* input, const BFloat16* bias, BFloat16* output); - -template Status LaunchFastGeluKernel(RocmTuningContext* tuning_ctx, hipStream_t stream, - int input_length, int bias_length, - const half* input, const half* bias, half* output); - -} // namespace rocm -} // namespace contrib -} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/rocm/bert/fast_gelu_impl.h b/onnxruntime/contrib_ops/rocm/bert/fast_gelu_impl.h deleted file mode 100644 index f120c0559f9b0..0000000000000 --- a/onnxruntime/contrib_ops/rocm/bert/fast_gelu_impl.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// Modifications: Remove cudaDeviceProp in LaunchFastGeluKernel. -// Copyright (c) Advanced Micro Devices, Inc. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include "core/common/common.h" -#include "core/providers/rocm/tunable/rocm_tunable.h" - -namespace onnxruntime { -namespace contrib { -namespace rocm { - -template -Status LaunchFastGeluKernel(RocmTuningContext* tuning_ctx, hipStream_t stream, int input_length, int bias_length, - const T* input, const T* bias, T* output); - -} // namespace rocm -} // namespace contrib -} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/rocm/bert/fast_gelu_impl_kernel.h b/onnxruntime/contrib_ops/rocm/bert/fast_gelu_impl_kernel.h deleted file mode 100644 index 1cf99b635461d..0000000000000 --- a/onnxruntime/contrib_ops/rocm/bert/fast_gelu_impl_kernel.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include "core/providers/rocm/tunable/util.h" -#include "core/providers/rocm/cu_inc/common.cuh" - -namespace onnxruntime { -namespace contrib { -namespace rocm { - -template -__global__ void FastGeluKernel(int input_length, int bias_length, const T* input, const T* bias, T* output) { - const int idx = blockIdx.x * TPB + threadIdx.x; - // constants for approximating the normal cdf - const T a = T(0.5f); - const T b = T(0.7978845608028654f); // sqrt(2.0/M_PI) - const T c = T(0.035677408136300125f); // 0.044715 * sqrt(2.0/M_PI) - const T oneT = T(1.0f); - const T twoT = T(2.0f); - if (idx < input_length) { - const T x = input[idx]; - const T in = (bias == nullptr) ? x : (T)(x + bias[idx % bias_length]); - - // const T cdf = a + a * _Tanh(in * (c * in * in + b)); - const T u = twoT * in * (c * in * in + b); - const T emu = __expf(-u); - const T cdf = a + a * (twoT / (oneT + emu) - oneT); - - output[idx] = in * cdf; - } -} - -template -__global__ void FastGeluKernelVec(int input_length, int bias_length, const T* input, const T* bias, - T* output) { - using VecT = onnxruntime::rocm::aligned_vector; - const T a = T(0.5f); - const T b = T(0.7978845608028654f); - const T c = T(0.035677408136300125f); - const T oneT = T(1.0f); - const T twoT = T(2.0f); - - const int idx = (blockIdx.x * TPB + threadIdx.x) * ILP; - if (idx < input_length) { - T input_v[ILP]; - VecT* input_val = reinterpret_cast(&input_v); - *input_val = *reinterpret_cast(&input[idx]); - T output_v[ILP]; - VecT* output_val = reinterpret_cast(&output_v); - T bias_v[ILP]; - if (bias != nullptr) { - VecT* bias_val = reinterpret_cast(&bias_v); - *bias_val = *reinterpret_cast(&bias[idx % bias_length]); - } - -#pragma unroll - for (int i = 0; i < ILP; i++) { - const T x = (bias == nullptr) ? input_v[i] : (T)(input_v[i] + bias_v[i]); - const T u = twoT * x * (c * x * x + b); - const T emu = __expf(-u); - const T cdf = a + a * (twoT / (oneT + emu) - oneT); - output_v[i] = x * cdf; - } - *(reinterpret_cast(&output[idx])) = *output_val; - } -} - -} // namespace rocm -} // namespace contrib -} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/rocm/bert/fast_gelu_tunable_op.h b/onnxruntime/contrib_ops/rocm/bert/fast_gelu_tunable_op.h deleted file mode 100644 index 5b91fb6e4fb65..0000000000000 --- a/onnxruntime/contrib_ops/rocm/bert/fast_gelu_tunable_op.h +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include -#include -#include -#include -#include "core/providers/rocm/tunable/rocm_tunable.h" -#include "core/providers/rocm/cu_inc/common.cuh" -#include "contrib_ops/rocm/bert/fast_gelu_impl_kernel.h" - -using onnxruntime::rocm::CeilDiv; -using onnxruntime::rocm::GPU_WARP_SIZE; - -namespace onnxruntime { -namespace contrib { -namespace rocm { - -template -struct FastGeluParams : OpParams { - FastGeluParams(RocmTuningContext* tuning_ctx, hipStream_t stream, const T* input, const T* bias, T* output, int input_length, int bias_length) : OpParams(tuning_ctx, stream), input(input), bias(bias), output(output), input_length(input_length), bias_length(bias_length) {} - - std::string Signature() const override { - std::string sig = std::to_string(input_length) + "_" + std::to_string(bias_length); - return sig; - } - - const T* input; - const T* bias; - T* output; - int input_length; - int bias_length; -}; - -template -class FastGeluOp { - public: - Status operator()(const FastGeluParams* params) { - FastGeluKernelVec - <<input_length, ThreadsPerBlock * VecSize)), - dim3(ThreadsPerBlock), - 0, params->stream>>>( - params->input_length, params->bias_length, params->input, params->bias, params->output); - return HIP_CALL(hipGetLastError()); - } - - Status IsSupported(const FastGeluParams* params) { - // TODO(anyone): Add tail handling for FastGelu - TUNABLE_OP_RETURN_UNSUPPORTED_ARGUMENT_IF( - !((params->bias_length > 0 && params->bias_length % VecSize == 0 && params->input_length % VecSize == 0) || - (params->bias_length == 0 && params->input_length % VecSize == 0))); - // Avoid redundant configurations - TUNABLE_OP_RETURN_UNSUPPORTED_ARGUMENT_IF(!(params->input_length > (ThreadsPerBlock - GPU_WARP_SIZE) * VecSize)); - - return Status::OK(); - } -}; - -template -Status FastGeluStaticSelection(const FastGeluParams* params) { - constexpr int block_size = 256; - const int grid_size = (params->input_length + block_size - 1) / block_size; - FastGeluKernel<<stream>>>( - params->input_length, params->bias_length, params->input, params->bias, params->output); - return HIP_CALL(hipGetLastError()); -} - -template <> -Status FastGeluStaticSelection(const FastGeluParams* params) { - constexpr int block_size = 256; - if (params->bias != nullptr) { - if (0 == (params->bias_length % 8) && (params->input_length >= 3145728)) { // 3145728=8*128*3072 - const int grid_size = (params->input_length / 8 + block_size - 1) / block_size; - FastGeluKernelVec<<stream>>>( - params->input_length, params->bias_length, params->input, params->bias, params->output); - } else if (0 == (params->bias_length % 4)) { - const int grid_size = (params->input_length / 4 + block_size - 1) / block_size; - FastGeluKernelVec<<stream>>>( - params->input_length, params->bias_length, params->input, params->bias, params->output); - } else if (0 == (params->bias_length % 2)) { - const int grid_size = (params->input_length / 2 + block_size - 1) / block_size; - FastGeluKernelVec<<stream>>>( - params->input_length, params->bias_length, params->input, params->bias, params->output); - } else { - const int grid_size = (params->input_length + block_size - 1) / block_size; - FastGeluKernel<<stream>>>( - params->input_length, params->bias_length, params->input, params->bias, params->output); - } - } else { - if (0 == (params->input_length % 8) && (params->input_length >= 3145728)) { // 3145728=8*128*3072 - const int grid_size = (params->input_length / 8 + block_size - 1) / block_size; - FastGeluKernelVec<<stream>>>( - params->input_length, params->bias_length, params->input, params->bias, params->output); - } else if (0 == (params->input_length % 4)) { - const int grid_size = (params->input_length / 4 + block_size - 1) / block_size; - FastGeluKernelVec<<stream>>>( - params->input_length, params->bias_length, params->input, params->bias, params->output); - } else if (0 == (params->input_length % 2)) { - const int grid_size = (params->input_length / 2 + block_size - 1) / block_size; - FastGeluKernelVec<<stream>>>( - params->input_length, params->bias_length, params->input, params->bias, params->output); - } else { - const int grid_size = (params->input_length + block_size - 1) / block_size; - FastGeluKernel<<stream>>>( - params->input_length, params->bias_length, params->input, params->bias, params->output); - } - } - return HIP_CALL(hipGetLastError()); -} - -#define ADD_OP(threads_per_block) \ - this->RegisterOp(FastGeluOp{}); \ - this->RegisterOp(FastGeluOp{}); \ - this->RegisterOp(FastGeluOp{}); \ - this->RegisterOp(FastGeluOp{}); \ - this->RegisterOp(FastGeluOp{}); - -template -class FastGeluTunableOp : public TunableOp> { - public: - FastGeluTunableOp() { - this->RegisterOp(FastGeluStaticSelection); - ADD_OP(64); - ADD_OP(128); - ADD_OP(192); - ADD_OP(256); - ADD_OP(320); - ADD_OP(384); - ADD_OP(448); - ADD_OP(512); - - // NOTE: the 1st kernel is FastGelu Original implementation. - this->SetDefaultId(0); - } -}; - -#undef ADD_OP - -} // namespace rocm -} // namespace contrib -} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/rocm/bert/gemm_fast_gelu.cc b/onnxruntime/contrib_ops/rocm/bert/gemm_fast_gelu.cc index 8b0cc98964581..1121e82a99d3f 100644 --- a/onnxruntime/contrib_ops/rocm/bert/gemm_fast_gelu.cc +++ b/onnxruntime/contrib_ops/rocm/bert/gemm_fast_gelu.cc @@ -58,8 +58,7 @@ Status GemmFastGelu::ComputeInternal(OpKernelContext* ctx) const { using onnxruntime::rocm::tunable::blas::BlasOp; return blas::row_major::GemmFastGelu( - GetTuningContext(), - Stream(ctx), GetRocblasHandle(ctx), + GetTuningContext(), ctx->GetComputeStream(), GetRocblasHandle(ctx), transa ? BlasOp::Trans : BlasOp::NonTrans, transb ? BlasOp::Trans : BlasOp::NonTrans, helper.M(), helper.N(), helper.K(), diff --git a/onnxruntime/contrib_ops/rocm/bert/gemm_fast_gelu_ck.cuh b/onnxruntime/contrib_ops/rocm/bert/gemm_fast_gelu_ck.cuh index f1fa3a7f5c848..cbf24ee2f5487 100644 --- a/onnxruntime/contrib_ops/rocm/bert/gemm_fast_gelu_ck.cuh +++ b/onnxruntime/contrib_ops/rocm/bert/gemm_fast_gelu_ck.cuh @@ -8,6 +8,8 @@ #include #ifdef USE_COMPOSABLE_KERNEL +#include "core/providers/rocm/composable_kernel_common.h" + #include "ck/ck.hpp" #include "ck/library/tensor_operation_instance/gpu/gemm_add_fastgelu.hpp" #include "ck/library/tensor_operation_instance/gpu/gemm_fastgelu.hpp" @@ -28,20 +30,7 @@ namespace internal { #ifdef USE_COMPOSABLE_KERNEL -template -struct DataTypeAdaptor { - using type = T; -}; - -template <> -struct DataTypeAdaptor { - using type = ck::half_t; -}; - -template <> -struct DataTypeAdaptor { - using type = ck::bhalf16_t; -}; +using onnxruntime::rocm::CKDataTypeAdaptor; using Row = ck::tensor_layout::gemm::RowMajor; using Col = ck::tensor_layout::gemm::ColumnMajor; @@ -52,7 +41,7 @@ using FastGelu = ck::tensor_operation::element_wise::FastGelu; template auto GetCKGemmAddFastGeluTypeStringAndOps() { - using CKDataType = typename DataTypeAdaptor::type; + using CKDataType = typename CKDataTypeAdaptor::type; using DeviceGemmAddFastGelu = ck::tensor_operation::device::DeviceGemmMultipleD< ALayout, BLayout, ck::Tuple, Row, CKDataType, CKDataType, ck::Tuple, CKDataType, @@ -79,7 +68,7 @@ auto GetCKGemmAddFastGeluTypeStringAndOps() { nop, nop, addfastgelu); TUNABLE_OP_RETURN_UNSUPPORTED_ARGUMENT_IF(!impl->IsSupportedArgument(arg.get()), impl->GetTypeString(), " does not support ", params->Signature()); - invoker->Run(arg.get(), StreamConfig{params->stream}); + invoker->Run(arg.get(), StreamConfig{params->StreamHandle()}); return Status::OK(); }; ret.emplace_back(std::make_pair(std::move(type_string), std::move(ck_gemmfastgelu_op))); @@ -89,7 +78,7 @@ auto GetCKGemmAddFastGeluTypeStringAndOps() { template auto GetCKGemmFastGeluTypeStringAndOps() { - using CKDataType = typename DataTypeAdaptor::type; + using CKDataType = typename CKDataTypeAdaptor::type; using DeviceGemmFastGelu = ck::tensor_operation::device::DeviceGemmMultipleD< ALayout, BLayout, ck::Tuple<>, Row, CKDataType, CKDataType, ck::Tuple<>, CKDataType, @@ -120,7 +109,7 @@ auto GetCKGemmFastGeluTypeStringAndOps() { nop, nop, fastgelu); TUNABLE_OP_RETURN_UNSUPPORTED_ARGUMENT_IF(!impl->IsSupportedArgument(arg.get()), impl->GetTypeString(), " does not support ", params->Signature()); - invoker->Run(arg.get(), StreamConfig{params->stream}); + invoker->Run(arg.get(), StreamConfig{params->StreamHandle()}); return Status::OK(); }; ret.emplace_back(std::make_pair(std::move(type_string), std::move(ck_gemmfastgelu_op))); diff --git a/onnxruntime/contrib_ops/rocm/bert/gemm_fast_gelu_impl.h b/onnxruntime/contrib_ops/rocm/bert/gemm_fast_gelu_impl.h index 637572e51b315..c4b4e68ed6275 100644 --- a/onnxruntime/contrib_ops/rocm/bert/gemm_fast_gelu_impl.h +++ b/onnxruntime/contrib_ops/rocm/bert/gemm_fast_gelu_impl.h @@ -14,7 +14,7 @@ namespace blas { #define GEMMFASTGELU(T, ScalarT) \ common::Status GemmFastGelu( \ - RocmTuningContext* tuning_ctx, hipStream_t stream, rocblas_handle handle, \ + RocmTuningContext* tuning_ctx, Stream* stream, rocblas_handle handle, \ BlasOp opa, BlasOp opb, \ std::int64_t m, std::int64_t n, std::int64_t k, \ ScalarT alpha, const T* a, std::int64_t lda, const T* b, std::int64_t ldb, \ diff --git a/onnxruntime/contrib_ops/rocm/bert/gemm_fast_gelu_tunable.cuh b/onnxruntime/contrib_ops/rocm/bert/gemm_fast_gelu_tunable.cuh index 24058f80db19b..229f868a215fd 100644 --- a/onnxruntime/contrib_ops/rocm/bert/gemm_fast_gelu_tunable.cuh +++ b/onnxruntime/contrib_ops/rocm/bert/gemm_fast_gelu_tunable.cuh @@ -6,26 +6,29 @@ #include #include -#include "contrib_ops/rocm/bert/fast_gelu_impl.h" +#include "contrib_ops/rocm/bert/elementwise.h" #include "contrib_ops/rocm/bert/gemm_fast_gelu_ck.cuh" #include "contrib_ops/rocm/bert/gemm_fast_gelu_common.h" #include "core/providers/rocm/tunable/gemm.h" +#include "core/providers/rocm/tunable/gemm_hipblaslt.h" #include "core/providers/rocm/tunable/rocm_tunable.h" namespace onnxruntime { -namespace contrib{ +namespace contrib { namespace rocm { namespace blas { namespace internal { +using namespace onnxruntime::rocm::tunable::blas::internal; + template Status GemmFastGeluUnfused(const GemmFastGeluParams* params) { namespace column_major = onnxruntime::rocm::tunable::blas::column_major; ORT_RETURN_IF_ERROR(column_major::Gemm(params->tuning_ctx, params->stream, params->handle, - params->opb, params->opa, - params->n, params->m, params->k, - params->alpha, params->b, params->ldb, params->a, params->lda, - params->beta, params->c, params->ldc)); + params->opb, params->opa, + params->n, params->m, params->k, + params->alpha, params->b, params->ldb, params->a, params->lda, + params->beta, params->c, params->ldc)); int64_t fast_gelu_input_length = params->m * params->n; int64_t bias_length = (params->bias != nullptr) ? params->n : 0; @@ -41,13 +44,11 @@ Status GemmFastGeluUnfused(const GemmFastGeluParams* params) { // // Note: If any change cause directly usage of GemmFastGeluUnfused, add PreTuning() and PostTuning() in FastGeluTunableOp // to protect original input value. - return onnxruntime::contrib::rocm::LaunchFastGeluKernel(params->tuning_ctx, - params->stream, - static_cast(fast_gelu_input_length), - static_cast(bias_length), - params->c, - params->bias, - params->c); + return onnxruntime::contrib::rocm::LaunchElementwiseKernel( + params->tuning_ctx, params->Stream(), + params->c, static_cast(fast_gelu_input_length), + params->bias, static_cast(bias_length), + params->c); } template @@ -65,6 +66,13 @@ class GemmFastGeluTunableOp : public TunableOp> { this->RegisterOp(std::move(op)); } #endif + +#ifdef USE_HIPBLASLT + for (auto&& [_, op] : GetHipBlasLtGemmFastGeluTypeStringAndOps()) { + ORT_UNUSED_PARAMETER(_); + this->RegisterOp(std::move(op)); + } +#endif } }; diff --git a/onnxruntime/contrib_ops/rocm/bert/layer_norm.cuh b/onnxruntime/contrib_ops/rocm/bert/layer_norm.cuh index 9b7dbd5291a8b..3f9183ef10828 100644 --- a/onnxruntime/contrib_ops/rocm/bert/layer_norm.cuh +++ b/onnxruntime/contrib_ops/rocm/bert/layer_norm.cuh @@ -109,6 +109,61 @@ __device__ inline void LayerNorm( } } +template +__device__ inline void SimplifiedLayerNorm( + const U& thread_data, const int ld, const int offset, const V* gamma, const U epsilon, V* output) { + // Assuming thread_data is already divided by ld + + using BlockReduce = hipcub::BlockReduce; + __shared__ typename BlockReduce::TempStorage temp_storage; + __shared__ U rsigma; // 1 / std.dev. + + const U sum = BlockReduce(temp_storage).Sum(thread_data); + + if (threadIdx.x == 0) { + rsigma = Rsqrt(sum + epsilon); + } + __syncthreads(); + + for (int i = threadIdx.x; i < ld; i += TPB) { + const int idx = offset + i; + const U val = static_cast(output[idx]); + const U g = static_cast(gamma[i]); + output[idx] = static_cast(g * val * rsigma); + } +} + +template +__device__ inline void SimplifiedLayerNormVec( + const U& thread_data, const int ld, const int offset, const V* gamma, const U epsilon, V* output) { + // Assuming thread_data is already divided by ld + using VecV = aligned_vector; + using BlockReduce = hipcub::BlockReduce; + __shared__ typename BlockReduce::TempStorage temp_storage; + __shared__ U rsigma; // 1 / std.dev. + + const U sum = BlockReduce(temp_storage).Sum(thread_data); + + if (threadIdx.x == 0) { + rsigma = Rsqrt(sum + epsilon); + } + __syncthreads(); + + if (ILP * threadIdx.x < ld) { + for (int i = threadIdx.x * ILP; i < ld; i += TPB * ILP) { + int idx = offset + i; + const VecV gamma_v = *reinterpret_cast(gamma + i); + VecV output_v = *reinterpret_cast(output + idx); + + #pragma unroll + for (int k = 0; k < ILP; k++) { + output_v.val[k] = U(gamma_v.val[k]) * U(output_v.val[k]) * rsigma; + } + *(reinterpret_cast(output + idx)) = output_v; + } + } +} + template __device__ inline void LayerNormVec( const hipcub::KeyValuePair& thread_data, const int ld, const int offset, const V* beta, @@ -182,6 +237,36 @@ __device__ inline void LayerNormSmall(const T* input_v, const hipcub::KeyValuePa } } +template +__device__ inline void SimplifiedLayerNormSmall(const T* input_v, const U& thread_data, const int ld, const int idx, + const V* gamma, const U epsilon, V* output) { + // Assuming thread_data is already divided by ld + // Small settings: the block covers the leading dimension TPB >= ld. The input + // value is available in a register + using VecV = aligned_vector; + using BlockReduce = hipcub::BlockReduce; + __shared__ typename BlockReduce::TempStorage temp_storage; + __shared__ U rsigma; // 1 / std.dev. + + const U sum = BlockReduce(temp_storage).Sum(thread_data); + + if (threadIdx.x == 0) { + rsigma = Rsqrt(sum + epsilon); + } + __syncthreads(); + + if (ILP * threadIdx.x < ld) { + const VecV gamma_v = *reinterpret_cast(gamma + threadIdx.x * ILP); + VecV output_v; + + #pragma unroll + for (int i = 0; i < ILP; i++) { + output_v.val[i] = U(gamma_v.val[i]) * U(input_v[i]) * rsigma; + } + *(reinterpret_cast(output + idx)) = output_v; + } +} + } // namespace rocm } // namespace contrib } // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/rocm/bert/multihead_attention.cu b/onnxruntime/contrib_ops/rocm/bert/multihead_attention.cu index 445894d07fb78..6f98312e4067d 100644 --- a/onnxruntime/contrib_ops/rocm/bert/multihead_attention.cu +++ b/onnxruntime/contrib_ops/rocm/bert/multihead_attention.cu @@ -17,7 +17,7 @@ namespace onnxruntime { namespace contrib { namespace rocm { -#define REGISTER_KERNEL_TYPED(T) \ +#define REGISTER_MHA_KERNEL_TYPED(T) \ ONNX_OPERATOR_TYPED_KERNEL_EX( \ MultiHeadAttention, \ kMSDomain, \ @@ -26,14 +26,39 @@ namespace rocm { kRocmExecutionProvider, \ (*KernelDefBuilder::Create()) \ .TypeConstraint("T", DataTypeImpl::GetTensorType()), \ - MultiHeadAttention); + MultiHeadAttention) -REGISTER_KERNEL_TYPED(float) -REGISTER_KERNEL_TYPED(MLFloat16) +REGISTER_MHA_KERNEL_TYPED(float); +REGISTER_MHA_KERNEL_TYPED(MLFloat16); + +static constexpr int kPastSequenceLengthInputIndex = 7; +static constexpr int kBeamWidthInputIndex = 8; +static constexpr int kPastInputIndex = 5; +static constexpr int kPresentOutputIndex = 1; + +#define REGISTER_DMMHA_KERNEL_TYPED(T) \ + ONNX_OPERATOR_TYPED_KERNEL_EX( \ + DecoderMaskedMultiHeadAttention, \ + kMSDomain, \ + 1, \ + T, \ + kRocmExecutionProvider, \ + (*KernelDefBuilder::Create()) \ + .MayInplace(kPastInputIndex, kPresentOutputIndex) \ + .MayInplace(kPastInputIndex + 1, kPresentOutputIndex + 1) \ + .TypeConstraint("T", DataTypeImpl::GetTensorType()) \ + .InputMemoryType(OrtMemTypeCPUInput, kPastSequenceLengthInputIndex) \ + .InputMemoryType(OrtMemTypeCPUInput, kBeamWidthInputIndex), \ + MultiHeadAttention) + +REGISTER_DMMHA_KERNEL_TYPED(float); +REGISTER_DMMHA_KERNEL_TYPED(MLFloat16); template MultiHeadAttention::MultiHeadAttention(const OpKernelInfo& info) - : RocmKernel(info) { + : RocmKernel(info), + attn_type_(info.node().OpType() == "DecoderMaskedMultiHeadAttention" ? kDecoderMaskedMultiHeadAttention + : kMultiHeadAttention) { int64_t num_heads = 0; ORT_ENFORCE(info.GetAttr("num_heads", &num_heads).IsOK() && num_heads > 0); num_heads_ = static_cast(num_heads); @@ -41,6 +66,12 @@ MultiHeadAttention::MultiHeadAttention(const OpKernelInfo& info) mask_filter_value_ = info.GetAttrOrDefault("mask_filter_value", -10000.0f); scale_ = info.GetAttrOrDefault("scale", 0.0f); + + past_present_share_buffer_ = info.GetAttrOrDefault("past_present_share_buffer", 0LL) != 0LL; + + using HipT = typename ToHipType::MappedType; + using AttentionTunableOp = GemmSoftmaxGemmPermuteTunableOp; + tunable_op_ = std::make_shared(); } template @@ -52,74 +83,189 @@ Status MultiHeadAttention::ComputeInternal(OpKernelContext* context) const { const Tensor* query = context->Input(0); const Tensor* key = context->Input(1); const Tensor* value = context->Input(2); - const Tensor* bias = context->Input(3); - const Tensor* key_padding_mask = context->Input(4); - const Tensor* relative_position_bias = context->Input(5); - const Tensor* past_key = context->Input(6); - const Tensor* past_value = context->Input(7); - // TODO: Add support for bias, key_padding_mask and attention cache. - ORT_ENFORCE(bias == nullptr && key_padding_mask == nullptr && past_key == nullptr && past_value == nullptr, - "bias, key_padding_mask and attention cache is not supported"); + const Tensor* bias{}; + const Tensor* key_padding_mask{}; + const Tensor* relative_position_bias{}; + const Tensor* past_key{}; + const Tensor* past_value{}; + const Tensor* past_seq_len{}; + + if (attn_type_ == kMultiHeadAttention) { + bias = context->Input(3); + key_padding_mask = context->Input(4); + relative_position_bias = context->Input(5); + past_key = context->Input(6); + past_value = context->Input(7); + } else if (attn_type_ == kDecoderMaskedMultiHeadAttention) { + key_padding_mask = context->Input(3); + relative_position_bias = context->Input(4); + past_key = context->Input(5); + past_value = context->Input(6); + past_seq_len = context->Input(kPastSequenceLengthInputIndex); + // const Tensor* beam_width = context->Input(8); // NOTE: not used + // const Tensor* cache_indirection = context->Input(9); // TODO: should not present for ROCm EP + bias = context->Input(10); + } + + if (nullptr != bias) { + return ORT_MAKE_STATUS(ONNXRUNTIME, NOT_IMPLEMENTED, + "qkv_bias is not supported on ROCm EP. " + "User should fuse the qkv bias to qkv projection instead."); + } auto& device_prop = GetDeviceProp(); - AttentionParameters attn; + RocmAttentionParameters attn; ORT_RETURN_IF_ERROR( multihead_attention_helper::CheckInputs( query, key, value, bias, key_padding_mask, relative_position_bias, - past_key, past_value, /*past_seq_len=*/nullptr, + past_key, past_value, past_seq_len, &attn, num_heads_, mask_filter_value_, scale_, - false, device_prop.maxThreadsPerBlock)); - // TODO: support more qkv formats - ORT_ENFORCE(attn.qkv_format == Q_KV_BSNH_BSN2H || attn.qkv_format == QKV_BSN3H, "Got ", attn.qkv_format); + past_present_share_buffer_, false, device_prop.maxThreadsPerBlock)); - int sequence_length = attn.sequence_length; + if (attn_type_ == kDecoderMaskedMultiHeadAttention && attn.sequence_length != 1) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "Input sequence length should be 1 to use DecoderMaskedMultiHeadAttention"); + } TensorShapeVector output_shape(3); output_shape[0] = static_cast(attn.batch_size); - output_shape[1] = static_cast(sequence_length); + output_shape[1] = static_cast(attn.sequence_length); output_shape[2] = static_cast(attn.v_hidden_size); Tensor* output = context->Output(0, output_shape); std::vector present_dims{ attn.batch_size, attn.num_heads, - attn.total_sequence_length, + past_present_share_buffer_ ? attn.max_sequence_length : attn.total_sequence_length, attn.head_size, }; TensorShape present_shape(present_dims); Tensor* present_key = context->Output(1, present_shape); Tensor* present_value = context->Output(2, present_shape); - // TODO: Add support for attention cache - ORT_ENFORCE(present_key == nullptr && present_value == nullptr, "attention cache is not supported"); + + ORT_RETURN_IF_ERROR(ClassifyAttentionMode( + attn_type_, &attn, + /*qkv=*/{query, key, value}, + /*past=*/{past_key, past_value}, + /*present=*/{present_key, present_value})); using HipT = typename ToHipType::MappedType; using AttentionTunableOp = GemmSoftmaxGemmPermuteTunableOp; auto workspace_bytes = AttentionTunableOp::GetWorkspaceNumBytes(&attn); auto workspace = GetScratchBuffer(workspace_bytes, context->GetComputeStream()); + hipStream_t stream = Stream(context); + if (nullptr != present_key) { // process past present concat + Strides dst_strides; + + int4 past_shape; + Strides past_src_strides; + const HipT* past_key_src; + const HipT* past_value_src; + HipT* past_key_dst{}; + HipT* past_value_dst{}; + + int4 add_shape; + Strides add_src_strides; + const HipT* add_key_src = reinterpret_cast(key->DataRaw()); + const HipT* add_value_src = reinterpret_cast(value->DataRaw()); + HipT* add_key_dst; + HipT* add_value_dst; + + if (attn.mode == BSNH_BLNH_BLNH_BNPH_BNPH_BNTH_BNTH || + attn.mode == BSNH_BNLH_BNLH_BNPH_BNPH_BNTH_BNTH) { + dst_strides = Strides::BNSHMemory(attn.batch_size, attn.num_heads, attn.total_sequence_length, attn.head_size); + + past_shape = {attn.batch_size, attn.num_heads, attn.past_sequence_length, attn.head_size}; + past_src_strides = Strides::BNSHMemory(attn.batch_size, attn.num_heads, attn.past_sequence_length, attn.head_size); + past_key_src = reinterpret_cast(past_key->DataRaw()); + past_value_src = reinterpret_cast(past_value->DataRaw()); + past_key_dst = reinterpret_cast(present_key->MutableDataRaw()); + past_value_dst = reinterpret_cast(present_value->MutableDataRaw()); + + if (attn.mode == BSNH_BLNH_BLNH_BNPH_BNPH_BNTH_BNTH) { + add_src_strides = Strides::BSNHMemory(attn.batch_size, attn.kv_sequence_length, attn.num_heads, attn.head_size); + } else if (attn.mode == BSNH_BNLH_BNLH_BNPH_BNPH_BNTH_BNTH) { + add_src_strides = Strides::BNSHMemory(attn.batch_size, attn.num_heads, attn.kv_sequence_length, attn.head_size); + } + } else if (attn.mode == BSNH_BLNH_BLNH_NONE_NONE_BNTH_BNTH || + attn.mode == BSNH_BNLH_BNLH_NONE_NONE_BNTH_BNTH) { + dst_strides = Strides::BNSHMemory(attn.batch_size, attn.num_heads, attn.total_sequence_length, attn.head_size); + + if (attn.mode == BSNH_BLNH_BLNH_NONE_NONE_BNTH_BNTH) { + add_src_strides = Strides::BSNHMemory(attn.batch_size, attn.kv_sequence_length, attn.num_heads, attn.head_size); + } else if (attn.mode == BSNH_BNLH_BNLH_NONE_NONE_BNTH_BNTH) { + add_src_strides = Strides::BNSHMemory(attn.batch_size, attn.num_heads, attn.kv_sequence_length, attn.head_size); + } + } else if ( + attn.mode == BSNH_BLNH_BLNH_NONE_NONE_BNMH_BNMH || + attn.mode == BSNH_BNLH_BNLH_NONE_NONE_BNMH_BNMH || + attn.mode == BSNH_BLNH_BLNH_BNMH_BNMH_BNMH_BNMH || + attn.mode == BSNH_BNLH_BNLH_BNMH_BNMH_BNMH_BNMH) { + dst_strides = Strides::BNSHMemory(attn.batch_size, attn.num_heads, attn.max_sequence_length, attn.head_size); + + if (attn.mode == BSNH_BLNH_BLNH_NONE_NONE_BNMH_BNMH || attn.mode == BSNH_BLNH_BLNH_BNMH_BNMH_BNMH_BNMH) { + add_src_strides = Strides::BSNHMemory(attn.batch_size, attn.kv_sequence_length, attn.num_heads, attn.head_size); + } else if (attn.mode == BSNH_BNLH_BNLH_NONE_NONE_BNMH_BNMH || attn.mode == BSNH_BNLH_BNLH_BNMH_BNMH_BNMH_BNMH) { + add_src_strides = Strides::BNSHMemory(attn.batch_size, attn.num_heads, attn.kv_sequence_length, attn.head_size); + } + } else { + return ORT_MAKE_STATUS(ONNXRUNTIME, NOT_IMPLEMENTED, + "past present concatenation is not implemented for attention mode ", attn.mode); + } + add_shape = {attn.batch_size, attn.num_heads, attn.kv_sequence_length, attn.head_size}; // kernel in coord (b,n,s,h) + add_key_dst = reinterpret_cast(present_key->MutableDataRaw()) + dst_strides.OffsetAt(0, 0, attn.past_sequence_length, 0); + add_value_dst = reinterpret_cast(present_value->MutableDataRaw()) + dst_strides.OffsetAt(0, 0, attn.past_sequence_length, 0); + + if (past_key_dst) { + ORT_RETURN_IF_ERROR(LaunchStridedCopy( + stream, past_key_src, past_shape, past_src_strides.ForBNSHCoord(), + past_key_dst, dst_strides.ForBNSHCoord(), device_prop.maxThreadsPerBlock)); + } + if (past_value_dst) { + ORT_RETURN_IF_ERROR(LaunchStridedCopy( + stream, past_value_src, past_shape, past_src_strides.ForBNSHCoord(), + past_value_dst, dst_strides.ForBNSHCoord(), device_prop.maxThreadsPerBlock)); + } + + ORT_RETURN_IF_ERROR(LaunchStridedCopy( + stream, add_key_src, add_shape, add_src_strides.ForBNSHCoord(), + add_key_dst, dst_strides.ForBNSHCoord(), device_prop.maxThreadsPerBlock)); + ORT_RETURN_IF_ERROR(LaunchStridedCopy( + stream, add_value_src, add_shape, add_src_strides.ForBNSHCoord(), + add_value_dst, dst_strides.ForBNSHCoord(), device_prop.maxThreadsPerBlock)); + } + GemmSoftmaxGemmPermuteParams params; params.tuning_ctx = GetTuningContext(); - params.stream = Stream(context); + params.stream = context->GetComputeStream(); params.handle = GetRocblasHandle(context); params.attention = &attn; params.device_prop = &device_prop; params.scale = scale_ == 0 ? 1.0f / sqrt(attn.head_size) : scale_; - std::tie(params.q_buffer, params.k_buffer, params.v_buffer) = GetQkvBuffers( + std::tie(params.q_buffer, params.k_buffer, params.v_buffer) = ConvertToOffsetedBufferViews( &attn, - query->DataRaw(), - key == nullptr ? nullptr : key->DataRaw(), - value == nullptr ? nullptr : value->DataRaw()); + nullptr == query ? nullptr : reinterpret_cast(query->DataRaw()), + nullptr == key ? nullptr : reinterpret_cast(key->DataRaw()), + nullptr == value ? nullptr : reinterpret_cast(value->DataRaw()), + nullptr == present_key ? nullptr : reinterpret_cast(present_key->DataRaw()), + nullptr == present_value ? nullptr : reinterpret_cast(present_value->DataRaw())); params.out_buffer = reinterpret_cast(output->MutableDataRaw()); + if (key_padding_mask != nullptr) { + params.mask_index_buffer = key_padding_mask->Data(); + params.mask_index_dims = key_padding_mask->Shape().AsShapeVector(); + } + if (relative_position_bias != nullptr) { params.bias_buffer = reinterpret_cast(relative_position_bias->DataRaw()); } params.workspace_buffer = reinterpret_cast(workspace.get()); - return AttentionTunableOp{}(¶ms); + return (*std::static_pointer_cast(tunable_op_))(¶ms); } } // namespace rocm diff --git a/onnxruntime/contrib_ops/rocm/bert/multihead_attention.h b/onnxruntime/contrib_ops/rocm/bert/multihead_attention.h index 25bc1cf811561..84d8b76bbfebe 100644 --- a/onnxruntime/contrib_ops/rocm/bert/multihead_attention.h +++ b/onnxruntime/contrib_ops/rocm/bert/multihead_attention.h @@ -20,6 +20,26 @@ class MultiHeadAttention final : public RocmKernel { Status ComputeInternal(OpKernelContext* context) const override; protected: + AttentionType attn_type_; + int num_heads_; // number of attention heads + float mask_filter_value_; + float scale_; + bool past_present_share_buffer_{false}; + + // type-erased GemmSoftmaxGemmPermuteTunableOp, the reason for this is: + // 1. We don't want to include the cuh file where GemmSoftmaxGemmPermuteTunableOp is defined. + // 2. We don't want to construct the object repeatly (which is expansive) during Compute. + std::shared_ptr tunable_op_; +}; + +template +class DecoderMaskedMultiHeadAttention final : public RocmKernel { + public: + DecoderMaskedMultiHeadAttention(const OpKernelInfo& info); + Status ComputeInternal(OpKernelContext* context) const override; + + protected: + AttentionType mha_type; int num_heads_; // number of attention heads float mask_filter_value_; float scale_; diff --git a/onnxruntime/contrib_ops/rocm/bert/skip_layer_norm.cc b/onnxruntime/contrib_ops/rocm/bert/skip_layer_norm.cc index 5b0f57c8f7aa1..9e649fb591896 100644 --- a/onnxruntime/contrib_ops/rocm/bert/skip_layer_norm.cc +++ b/onnxruntime/contrib_ops/rocm/bert/skip_layer_norm.cc @@ -20,26 +20,36 @@ namespace rocm { kRocmExecutionProvider, \ (*KernelDefBuilder::Create()) \ .TypeConstraint("T", DataTypeImpl::GetTensorType()), \ - SkipLayerNorm); + SkipLayerNorm); \ + ONNX_OPERATOR_TYPED_KERNEL_EX( \ + SkipSimplifiedLayerNormalization, \ + kMSDomain, \ + 1, \ + T, \ + kRocmExecutionProvider, \ + (*KernelDefBuilder::Create()) \ + .TypeConstraint("T", DataTypeImpl::GetTensorType()), \ + SkipLayerNorm); REGISTER_KERNEL_TYPED(float) REGISTER_KERNEL_TYPED(MLFloat16) using namespace ONNX_NAMESPACE; -template -SkipLayerNorm::SkipLayerNorm(const OpKernelInfo& op_kernel_info) : RocmKernel(op_kernel_info) { +template +SkipLayerNorm::SkipLayerNorm(const OpKernelInfo& op_kernel_info) : RocmKernel(op_kernel_info) { ORT_ENFORCE(op_kernel_info.GetAttr("epsilon", &epsilon_).IsOK()); ORT_ENFORCE(epsilon_ >= 0); } -template -Status SkipLayerNorm::ComputeInternal(OpKernelContext* ctx) const { +template +Status SkipLayerNorm::ComputeInternal(OpKernelContext* ctx) const { const Tensor* input = ctx->Input(0); const Tensor* skip = ctx->Input(1); const Tensor* gamma = ctx->Input(2); - const Tensor* beta = ctx->Input(3); - const Tensor* bias = ctx->Input(4); + + const Tensor* beta = Simplified ? nullptr : ctx->Input(3); + const Tensor* bias = Simplified ? ctx->Input(3) : ctx->Input(4); Tensor* output = ctx->Output(0, input->Shape()); @@ -102,9 +112,9 @@ Status SkipLayerNorm::ComputeInternal(OpKernelContext* ctx) const { int64_t element_count = input->Shape().Size(); typedef typename ToHipType::MappedType HipT; - return LaunchSkipLayerNormKernel( + return LaunchSkipLayerNormKernel( GetTuningContext(), - Stream(ctx), + ctx->GetComputeStream(), reinterpret_cast(output->MutableData()), skip_input_bias_add_output != nullptr ? reinterpret_cast(skip_input_bias_add_output->MutableData()) : nullptr, reinterpret_cast(input->Data()), diff --git a/onnxruntime/contrib_ops/rocm/bert/skip_layer_norm.h b/onnxruntime/contrib_ops/rocm/bert/skip_layer_norm.h index 07d7037227b98..02228bc59cedc 100644 --- a/onnxruntime/contrib_ops/rocm/bert/skip_layer_norm.h +++ b/onnxruntime/contrib_ops/rocm/bert/skip_layer_norm.h @@ -11,7 +11,7 @@ namespace rocm { using namespace onnxruntime::rocm; -template +template class SkipLayerNorm final : public RocmKernel { public: SkipLayerNorm(const OpKernelInfo& op_kernel_info); diff --git a/onnxruntime/contrib_ops/rocm/bert/skip_layer_norm_impl.cu b/onnxruntime/contrib_ops/rocm/bert/skip_layer_norm_impl.cu index c6ac1196ba7b1..8387c49a3310b 100644 --- a/onnxruntime/contrib_ops/rocm/bert/skip_layer_norm_impl.cu +++ b/onnxruntime/contrib_ops/rocm/bert/skip_layer_norm_impl.cu @@ -39,9 +39,9 @@ namespace onnxruntime { namespace contrib { namespace rocm { -template +template Status LaunchSkipLayerNormKernel( - RocmTuningContext* tuning_ctx, hipStream_t stream, V* output, T* skip_input_bias_add_output, const T* input, + RocmTuningContext* tuning_ctx, Stream* stream, V* output, T* skip_input_bias_add_output, const T* input, const T* skip, const V* gamma, const V* beta, const T* bias, float epsilon, int ld, int element_count) { // this must be true because element_count is the total size of the tensor assert(element_count % ld == 0); @@ -50,21 +50,33 @@ Status LaunchSkipLayerNormKernel( gamma, beta, bias, epsilon, ld, element_count); if (tuning_ctx->IsTunableOpEnabled()) { - static SkipLayerNormTunableOp op; + static SkipLayerNormTunableOp op; return op(¶ms); } - return SkipLayerNormStaticSelection(¶ms); + return SkipLayerNormStaticSelection(¶ms); } -template Status LaunchSkipLayerNormKernel( - RocmTuningContext* tuning_ctx, hipStream_t stream, float* output, float* skip_input_bias_add_output, const float* input, +template Status LaunchSkipLayerNormKernel( + RocmTuningContext* tuning_ctx, Stream* stream, float* output, float* skip_input_bias_add_output, const float* input, const float* skip, const float* gamma, const float* beta, const float* bias, float epsilon, int ld, int element_count); -template Status LaunchSkipLayerNormKernel( - RocmTuningContext* tuning_ctx, hipStream_t stream, half* output, half* skip_input_bias_add_output, const half* input, +template Status LaunchSkipLayerNormKernel( + RocmTuningContext* tuning_ctx, Stream* stream, half* output, half* skip_input_bias_add_output, const half* input, + const half* skip, const half* gamma, const half* beta, + const half* bias, float epsilon, int ld, + int element_count); + +template Status LaunchSkipLayerNormKernel( + RocmTuningContext* tuning_ctx, Stream* stream, float* output, float* skip_input_bias_add_output, const float* input, + const float* skip, const float* gamma, const float* beta, + const float* bias, float epsilon, int ld, + int element_count); + +template Status LaunchSkipLayerNormKernel( + RocmTuningContext* tuning_ctx, Stream* stream, half* output, half* skip_input_bias_add_output, const half* input, const half* skip, const half* gamma, const half* beta, const half* bias, float epsilon, int ld, int element_count); diff --git a/onnxruntime/contrib_ops/rocm/bert/skip_layer_norm_impl.h b/onnxruntime/contrib_ops/rocm/bert/skip_layer_norm_impl.h index 2f2e5fbdd3087..5e2a92447d2f5 100644 --- a/onnxruntime/contrib_ops/rocm/bert/skip_layer_norm_impl.h +++ b/onnxruntime/contrib_ops/rocm/bert/skip_layer_norm_impl.h @@ -10,10 +10,10 @@ namespace onnxruntime { namespace contrib { namespace rocm { -template +template Status LaunchSkipLayerNormKernel( RocmTuningContext* tuning, - hipStream_t stream, + Stream* stream, V* output, // output tensor T* skip_input_bias_add_output, // optional output tensor const T* input, // input tensor diff --git a/onnxruntime/contrib_ops/rocm/bert/skip_layer_norm_impl_kernel.h b/onnxruntime/contrib_ops/rocm/bert/skip_layer_norm_impl_kernel.h index 56ed185ffe110..fcfbc8969e498 100644 --- a/onnxruntime/contrib_ops/rocm/bert/skip_layer_norm_impl_kernel.h +++ b/onnxruntime/contrib_ops/rocm/bert/skip_layer_norm_impl_kernel.h @@ -23,7 +23,7 @@ half maybe2half(float x) { return __float2half_rn(x); } -template +template __global__ void SkipLayerNormKernel( const int ld, const T* input, const T* skip, const V* beta, const V* gamma, const T* bias, const U epsilon, V* output, T* skip_input_bias_add_output) { @@ -47,11 +47,16 @@ __global__ void SkipLayerNormKernel( output[idx] = static_cast(val); } + if constexpr (Simplified) { + SimplifiedLayerNorm(thread_data.value, ld, offset, gamma, epsilon, output); + return; + } + LayerNorm(thread_data, ld, offset, beta, gamma, epsilon, output); } // Vectorized kernel -template +template __global__ void SkipLayerNormKernelVec( const int ld, const T* input, const T* skip, const V* beta, const V* gamma, const T* bias, const U epsilon, V* output, T* skip_input_bias_add_output, @@ -94,11 +99,16 @@ __global__ void SkipLayerNormKernelVec( } } + if constexpr (Simplified) { + SimplifiedLayerNormVec(thread_data.value, ld, offset, gamma, epsilon, output); + return; + } + LayerNormVec(thread_data, ld, offset, beta, gamma, epsilon, output); } // Vectorized kernel -template +template __global__ void SkipLayerNormKernelSmall( const int ld, const T* input, const T* skip, const V* beta, const V* gamma, const T* bias, const U epsilon, V* output, T* skip_input_bias_add_output, @@ -138,6 +148,12 @@ __global__ void SkipLayerNormKernelSmall( thread_data = hipcub::KeyValuePair(rldval_sum, rldvalsq_sum); } + + if constexpr (Simplified) { + SimplifiedLayerNormSmall(input_v.val, thread_data.value, ld, idx, gamma, epsilon, output); + return; + } + LayerNormSmall(input_v.val, thread_data, ld, idx, beta, gamma, epsilon, output); } diff --git a/onnxruntime/contrib_ops/rocm/bert/skip_layer_norm_tunable_op.h b/onnxruntime/contrib_ops/rocm/bert/skip_layer_norm_tunable_op.h index a0b2507220ae1..0391704ce1c56 100644 --- a/onnxruntime/contrib_ops/rocm/bert/skip_layer_norm_tunable_op.h +++ b/onnxruntime/contrib_ops/rocm/bert/skip_layer_norm_tunable_op.h @@ -20,7 +20,7 @@ namespace rocm { template struct SkipLayerNormParams : OpParams { - SkipLayerNormParams(RocmTuningContext* tuning_ctx, hipStream_t stream, V* output, T* skip_input_bias_add_output, const T* input, + SkipLayerNormParams(RocmTuningContext* tuning_ctx, onnxruntime::Stream* stream, V* output, T* skip_input_bias_add_output, const T* input, const T* skip, const V* gamma, const V* beta, const T* bias, float epsilon, int ld, int element_count) : OpParams(tuning_ctx, stream), output(output), skip_input_bias_add_output(skip_input_bias_add_output), input(input), skip(skip), gamma(gamma), beta(beta), bias(bias), epsilon(epsilon), ld(ld), element_count(element_count) {} @@ -42,51 +42,51 @@ struct SkipLayerNormParams : OpParams { int element_count; }; -template +template Status SkipLayerNormSmallOp(const SkipLayerNormParams* params) { // Loosen the hard constraint for ld (hidden_size) to include more possible *Small kernels, // which could offer better performance in some combinations of ThreadsPerBlock and VecSize. TUNABLE_OP_RETURN_UNSUPPORTED_ARGUMENT_IF( !((params->ld <= 8192 && params->ld % VecSize == 0 && params->ld <= ThreadsPerBlock * VecSize && params->ld > (ThreadsPerBlock - GPU_WARP_SIZE) * VecSize))); - SkipLayerNormKernelSmall<<element_count, params->ld)), - dim3(ThreadsPerBlock), - 0, params->stream>>>( + SkipLayerNormKernelSmall<<element_count, params->ld)), + dim3(ThreadsPerBlock), + 0, params->StreamHandle()>>>( params->ld, params->input, params->skip, params->beta, params->gamma, params->bias, static_cast(params->epsilon), params->output, params->skip_input_bias_add_output, (params->bias == nullptr) ? false : true, (params->skip_input_bias_add_output == nullptr) ? false : true); return HIP_CALL(hipGetLastError()); } -template +template Status SkipLayerNormRegularOp(const SkipLayerNormParams* params) { TUNABLE_OP_RETURN_UNSUPPORTED_ARGUMENT_IF( !((params->ld > 0 && params->ld % VecSize == 0 && (params->ld >= ThreadsPerBlock * VecSize || (params->ld < GPU_WARP_SIZE && params->ld > (ThreadsPerBlock - GPU_WARP_SIZE) * VecSize))))); - SkipLayerNormKernelVec<<element_count, params->ld)), - dim3(ThreadsPerBlock), - 0, params->stream>>>( + SkipLayerNormKernelVec<<element_count, params->ld)), + dim3(ThreadsPerBlock), + 0, params->StreamHandle()>>>( params->ld, params->input, params->skip, params->beta, params->gamma, params->bias, static_cast(params->epsilon), params->output, params->skip_input_bias_add_output, (params->bias == nullptr) ? false : true, (params->skip_input_bias_add_output == nullptr) ? false : true); return HIP_CALL(hipGetLastError()); } -template +template Status SkipLayerNormStaticSelection(const SkipLayerNormParams* params) { bool hasBias = (params->bias == nullptr) ? false : true; bool hasSkipInputBiasAdditionOutput = (params->skip_input_bias_add_output == nullptr) ? false : true; const int grid_size = params->element_count / params->ld; const int block_size = 256; -#define LAUNCH_SKIPLAYERNORM_SMALL_FORWARD(ELEMENTS, TPB, ILP) \ - if (params->ld <= ELEMENTS) { \ - SkipLayerNormKernelSmall<<stream>>>( \ - params->ld, params->input, params->skip, params->beta, params->gamma, params->bias, \ - static_cast(params->epsilon), params->output, params->skip_input_bias_add_output, \ - hasBias, hasSkipInputBiasAdditionOutput); \ - break; \ +#define LAUNCH_SKIPLAYERNORM_SMALL_FORWARD(ELEMENTS, TPB, ILP) \ + if (params->ld <= ELEMENTS) { \ + SkipLayerNormKernelSmall<<StreamHandle()>>>( \ + params->ld, params->input, params->skip, params->beta, params->gamma, params->bias, \ + static_cast(params->epsilon), params->output, params->skip_input_bias_add_output, \ + hasBias, hasSkipInputBiasAdditionOutput); \ + break; \ } if (0 == (params->ld % 4)) { do { @@ -97,7 +97,7 @@ Status SkipLayerNormStaticSelection(const SkipLayerNormParams* params) { LAUNCH_SKIPLAYERNORM_SMALL_FORWARD(768, 192, 4) LAUNCH_SKIPLAYERNORM_SMALL_FORWARD(1024, 256, 4) - SkipLayerNormKernel<<stream>>>( + SkipLayerNormKernel<<StreamHandle()>>>( params->ld, params->input, params->skip, params->beta, params->gamma, params->bias, static_cast(params->epsilon), params->output, params->skip_input_bias_add_output); } while (0); @@ -108,7 +108,7 @@ Status SkipLayerNormStaticSelection(const SkipLayerNormParams* params) { LAUNCH_SKIPLAYERNORM_SMALL_FORWARD(128, 128, 1) LAUNCH_SKIPLAYERNORM_SMALL_FORWARD(384, 384, 1) - SkipLayerNormKernel<<stream>>>( + SkipLayerNormKernel<<StreamHandle()>>>( params->ld, params->input, params->skip, params->beta, params->gamma, params->bias, static_cast(params->epsilon), params->output, params->skip_input_bias_add_output); } while (0); @@ -116,12 +116,12 @@ Status SkipLayerNormStaticSelection(const SkipLayerNormParams* params) { return HIP_CALL(hipPeekAtLastError()); } // namespace rocm -#define ADD_OP_FOR_ALL_VEC_SIZE(name, threads_per_block) \ - this->RegisterOp(name); \ - this->RegisterOp(name); \ - this->RegisterOp(name); \ - this->RegisterOp(name); \ - this->RegisterOp(name); +#define ADD_OP_FOR_ALL_VEC_SIZE(name, threads_per_block) \ + this->RegisterOp(name); \ + this->RegisterOp(name); \ + this->RegisterOp(name); \ + this->RegisterOp(name); \ + this->RegisterOp(name); #define ADD_OP_FOR_ALL_THREADS_PER_BLOCK_ALL_VEC_SIZE(name) \ ADD_OP_FOR_ALL_VEC_SIZE(name, 64) \ @@ -140,11 +140,11 @@ Status SkipLayerNormStaticSelection(const SkipLayerNormParams* params) { ADD_OP_FOR_ALL_VEC_SIZE(name, 896) \ ADD_OP_FOR_ALL_VEC_SIZE(name, 1024) -template +template class SkipLayerNormTunableOp : public TunableOp> { public: SkipLayerNormTunableOp() { - this->RegisterOp(SkipLayerNormStaticSelection); + this->RegisterOp(SkipLayerNormStaticSelection); ADD_OP_FOR_ALL_THREADS_PER_BLOCK_ALL_VEC_SIZE(SkipLayerNormSmallOp) ADD_OP_FOR_ALL_THREADS_PER_BLOCK_ALL_VEC_SIZE(SkipLayerNormRegularOp) diff --git a/onnxruntime/contrib_ops/rocm/diffusion/group_norm.cc b/onnxruntime/contrib_ops/rocm/diffusion/group_norm.cc index 9b0e6251b3f2a..c665da89af36c 100644 --- a/onnxruntime/contrib_ops/rocm/diffusion/group_norm.cc +++ b/onnxruntime/contrib_ops/rocm/diffusion/group_norm.cc @@ -21,7 +21,7 @@ namespace { template struct DispatchGroupNorm { Status operator()(RocmTuningContext* tuning_ctx, - hipStream_t stream, + Stream* stream, Tensor* output, const Tensor* input, const Tensor* gamma, @@ -68,6 +68,8 @@ GroupNorm::GroupNorm(const OpKernelInfo& op_info) : RocmKernel(op_info) { ORT_ENFORCE(op_info.GetAttr("activation", &activation).IsOK()); ORT_ENFORCE(activation == 0 || activation == 1); // 0 is None, 1 is Swish use_swish_activation_ = (activation == 1); + + channels_last_ = (op_info.GetAttrOrDefault("channels_last", static_cast(1)) != 0); } Status GroupNorm::ComputeInternal(OpKernelContext* context) const { @@ -76,6 +78,11 @@ Status GroupNorm::ComputeInternal(OpKernelContext* context) const { const Tensor* beta = context->Input(2); Tensor* output = context->Output(0, input->Shape()); + if (!channels_last_) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "only the channels_last layout is supported"); + } + const auto& input_dims = input->Shape().GetDims(); if (input_dims.size() != 4) { return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, @@ -110,13 +117,20 @@ Status GroupNorm::ComputeInternal(OpKernelContext* context) const { if (num_channels % num_groups_ != 0) { return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, - "number of channels should be divisiable by num_groups"); + "number of channels should be divisible by num_groups"); + } + + if (context->GetUseDeterministicCompute()) { + static std::once_flag log_warning; + std::call_once(log_warning, []() { + LOGS_DEFAULT(WARNING) << "GroupNorm has no deterministic GPU kernel, its outputs may still be nondeterministic."; + }); } auto workspace = GetScratchBuffer(GetGroupNormWorkspaceSizeInBytes(), context->GetComputeStream()); utils::MLTypeCallDispatcher dispatcher(input->GetElementType()); - return dispatcher.InvokeRet(GetTuningContext(), Stream(context), + return dispatcher.InvokeRet(GetTuningContext(), context->GetComputeStream(), output, input, gamma, beta, workspace.get(), epsilon_, batch_size, diff --git a/onnxruntime/contrib_ops/rocm/diffusion/group_norm_ck.cuh b/onnxruntime/contrib_ops/rocm/diffusion/group_norm_ck.cuh index 4ce7b1284dda7..e87813fb19956 100644 --- a/onnxruntime/contrib_ops/rocm/diffusion/group_norm_ck.cuh +++ b/onnxruntime/contrib_ops/rocm/diffusion/group_norm_ck.cuh @@ -8,6 +8,8 @@ #include #ifdef USE_COMPOSABLE_KERNEL +#include "core/providers/rocm/composable_kernel_common.h" + #include "ck/ck.hpp" #include "ck/tensor_operation/gpu/device/tensor_layout.hpp" #include "ck/tensor_operation/gpu/element/element_wise_operation.hpp" @@ -22,15 +24,7 @@ namespace rocm { #ifdef USE_COMPOSABLE_KERNEL -template -struct DataTypeAdaptor { - using type = T; -}; - -template <> -struct DataTypeAdaptor { - using type = ck::half_t; -}; +using onnxruntime::rocm::CKDataTypeAdaptor; using Swish = ck::tensor_operation::element_wise::Swish; using Pass = ck::tensor_operation::element_wise::PassThrough; @@ -40,9 +34,9 @@ constexpr int NumReduceDim = 3; template auto GetCKGroupNormNHWCTypeStringAndOps() { - using InDataType = typename DataTypeAdaptor::type; - using OutDataType = typename DataTypeAdaptor::type; - using AccDataType = typename DataTypeAdaptor::type; + using InDataType = typename CKDataTypeAdaptor::type; + using OutDataType = typename CKDataTypeAdaptor::type; + using AccDataType = typename CKDataTypeAdaptor::type; using GammaDataType = float; using BetaDataType = float; @@ -86,7 +80,7 @@ auto GetCKGroupNormNHWCTypeStringAndOps() { activation); TUNABLE_OP_RETURN_UNSUPPORTED_ARGUMENT_IF(!impl->IsSupportedArgument(arg.get()), impl->GetTypeString(), " does not support ", params->Signature()); - invoker->Run(arg.get(), StreamConfig{params->stream}); + invoker->Run(arg.get(), StreamConfig{params->StreamHandle()}); return Status::OK(); }; ret.emplace_back(std::make_pair(std::move(type_string), std::move(ck_group_norm_op))); diff --git a/onnxruntime/contrib_ops/rocm/diffusion/group_norm_common.h b/onnxruntime/contrib_ops/rocm/diffusion/group_norm_common.h index c0fbe6c7c6b82..008ae20b0561f 100644 --- a/onnxruntime/contrib_ops/rocm/diffusion/group_norm_common.h +++ b/onnxruntime/contrib_ops/rocm/diffusion/group_norm_common.h @@ -35,7 +35,7 @@ int32_t findMaxDivisor(int32_t n, int32_t maxAllowedDivisor) { template struct GroupNormNHWCParams : OpParams { - GroupNormNHWCParams(RocmTuningContext* tuning_ctx, hipStream_t stream, T* dst, float* redBuffer, const T* src, const float* gamma, + GroupNormNHWCParams(RocmTuningContext* tuning_ctx, onnxruntime::Stream* stream, T* dst, float* redBuffer, const T* src, const float* gamma, const float* beta, int32_t n, int32_t h, int32_t w, int32_t c, int32_t groups, float epsilon, bool withSwish) : OpParams(tuning_ctx, stream), dst(dst), src(src), gamma(gamma), beta(beta), redBuffer(redBuffer), epsilon(epsilon), n(n), h(h), w(w), c(c), groups(groups), withSwish(withSwish) { int32_t maxBlocksPerHW = 1024; diff --git a/onnxruntime/contrib_ops/rocm/diffusion/group_norm_impl.cu b/onnxruntime/contrib_ops/rocm/diffusion/group_norm_impl.cu index 5ee7ad40b036d..dbd5009e63676 100644 --- a/onnxruntime/contrib_ops/rocm/diffusion/group_norm_impl.cu +++ b/onnxruntime/contrib_ops/rocm/diffusion/group_norm_impl.cu @@ -15,7 +15,7 @@ namespace rocm { template Status LaunchGroupNormKernel( RocmTuningContext* tuning_ctx, - hipStream_t stream, + Stream* stream, T* output, const T* input, const float* gamma, @@ -49,12 +49,12 @@ Status LaunchGroupNormKernel( return GroupNormNHWCStaticSelection(¶ms); } -template Status LaunchGroupNormKernel(RocmTuningContext* tuning_ctx, hipStream_t stream, half* output, +template Status LaunchGroupNormKernel(RocmTuningContext* tuning_ctx, Stream* stream, half* output, const half* input, const float* gamma, const float* beta, void* workspace, float epsilon, int batch_size, int num_channels, int height, int width, int num_groups, bool swish); -template Status LaunchGroupNormKernel(RocmTuningContext* tuning_ctx, hipStream_t stream, float* output, +template Status LaunchGroupNormKernel(RocmTuningContext* tuning_ctx, Stream* stream, float* output, const float* input, const float* gamma, const float* beta, void* workspace, float epsilon, int batch_size, int num_channels, int height, int width, int num_groups, bool swish); diff --git a/onnxruntime/contrib_ops/rocm/diffusion/group_norm_impl.h b/onnxruntime/contrib_ops/rocm/diffusion/group_norm_impl.h index ff5f2f19df5be..a0f7e0aca5def 100644 --- a/onnxruntime/contrib_ops/rocm/diffusion/group_norm_impl.h +++ b/onnxruntime/contrib_ops/rocm/diffusion/group_norm_impl.h @@ -27,7 +27,7 @@ constexpr size_t GetGroupNormWorkspaceSizeInBytes() { template Status LaunchGroupNormKernel( RocmTuningContext* tuning_ctx, - hipStream_t stream, + Stream* stream, T* output, // normalized output tensor const T* input, // input tensor const float* gamma, // gamma (also known as weight or scale) diff --git a/onnxruntime/contrib_ops/rocm/diffusion/group_norm_triton.cuh b/onnxruntime/contrib_ops/rocm/diffusion/group_norm_triton.cuh new file mode 100644 index 0000000000000..526d220d4be24 --- /dev/null +++ b/onnxruntime/contrib_ops/rocm/diffusion/group_norm_triton.cuh @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include +#include +#include + +#include "contrib_ops/rocm/diffusion/group_norm_common.h" +#include "core/providers/rocm/triton_kernel.h" + +using namespace onnxruntime::rocm; + +namespace onnxruntime { +namespace contrib { +namespace rocm { + +#ifdef USE_TRITON_KERNEL + +namespace { + +template +std::string GetGroupNormTritonGroupName() { + std::string ret = "GroupNormTriton_"; + std::string swish_suffix = WithSwish ? "Swish_" : "Pass_"; + ret += swish_suffix; + ret += GetDataTypeName(); + return ret; +} + +} // namespace + +template +auto GetTritonGroupNormNHWCTypeStringAndOps() { + std::vector>>> ret; + auto group_name = GetGroupNormTritonGroupName(); + auto* kernel_list = GetOrtTritonKernelByGroup(group_name); + if (kernel_list == nullptr) { + return ret; + } + + for (auto i : *kernel_list) { + // Check params match + auto* metadata = GetOrtTritonKernelMetadata(i); + auto block_size = metadata->constants.at("BLOCK_SIZE"); + auto hw_size = metadata->constants.at("HW_SIZE"); + auto impl = [i, block_size, hw_size](const GroupNormNHWCParams* params) -> Status { + TUNABLE_OP_RETURN_UNSUPPORTED_ARGUMENT_IF( + params->cPerGroup > block_size || params->cPerGroup * 2 <= block_size, + "Arg block_size (", block_size, ") is not the next power of 2 of cPerGroup (", params->cPerGroup, ")."); + TUNABLE_OP_RETURN_UNSUPPORTED_ARGUMENT_IF( + params->hw % hw_size != 0, "Arg hw_size (", hw_size, ") is not a divisor of hw (", params->hw, ")."); + if constexpr (WithSwish) { + TUNABLE_OP_RETURN_UNSUPPORTED_ARGUMENT_IF(!params->withSwish, "Swish version does not support GN w/o swish."); + } else { + TUNABLE_OP_RETURN_UNSUPPORTED_ARGUMENT_IF(params->withSwish, "Pass version does not support GN w/ swish."); + } + // Construct args for launch kernel + struct { + void* X; + void* Y; + const void* gamma; + const void* beta; + int hw; + int c; + int c_per_group; + float eps; + } args = { + (void*)params->src, + (void*)params->dst, + (const void*)params->gamma, + (const void*)params->beta, + params->hw, + params->c, + params->cPerGroup, + params->epsilon}; + + // Grid dim is (batch_count, groups, 1) + return LaunchTritonKernel(params->stream, i, params->n, params->groups, 1, &args, sizeof(args)); + }; + ret.emplace_back(std::make_pair(metadata->name, std::move(impl))); + } + return ret; +} + +#endif // USE_TRITON_KERNEL + +} // namespace rocm +} // namespace contrib +} // namespace onnxruntime diff --git a/onnxruntime/contrib_ops/rocm/diffusion/group_norm_triton.py b/onnxruntime/contrib_ops/rocm/diffusion/group_norm_triton.py new file mode 100644 index 0000000000000..56b3a030b289e --- /dev/null +++ b/onnxruntime/contrib_ops/rocm/diffusion/group_norm_triton.py @@ -0,0 +1,104 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# -------------------------------------------------------------------------- + +from itertools import product + +import triton +import triton.language as tl + + +@triton.jit +def group_norm_kernel( + input_ptr, + output_ptr, + gamma_ptr, + beta_ptr, + img_size, + c, + c_per_group, + eps, + BLOCK_SIZE: tl.constexpr, + HW_SIZE: tl.constexpr, + ACTIVATION_SWISH: tl.constexpr, +): + row_x = tl.program_id(0) + row_y = tl.program_id(1) + stride = img_size * c + input_ptr += row_x * stride + row_y * c_per_group + output_ptr += row_x * stride + row_y * c_per_group + gamma_ptr += row_y * c_per_group + beta_ptr += row_y * c_per_group + + cols = tl.arange(0, BLOCK_SIZE) + hw = tl.arange(0, HW_SIZE) + offsets = hw[:, None] * c + cols[None, :] + mask = (cols < c_per_group)[None, :] + + # Calculate mean and variance + _sum = tl.zeros([HW_SIZE, BLOCK_SIZE], dtype=tl.float32) + _square_sum = tl.zeros([HW_SIZE, BLOCK_SIZE], dtype=tl.float32) + for i in range(tl.cdiv(img_size, HW_SIZE)): + x_ptr = input_ptr + i * HW_SIZE * c + a = tl.load(x_ptr + offsets, mask=mask, other=0.0).to(tl.float32) + _sum += a + _square_sum += a * a + + # Set axis=None (or leave it unspecified) to reduce all axes. + # TODO: In older Triton we have to reduce an axis at a time, but in our case + # for some configs it may have some issue when reducing sequentially along the axes. + group_mean = tl.sum(_sum, axis=None) / (img_size * c_per_group) + group_var = tl.sum(_square_sum, axis=None) / (img_size * c_per_group) - group_mean * group_mean + + rstd = 1 / tl.sqrt(group_var + eps) + + # Normalize and apply linear transformation + gamma = tl.load(gamma_ptr + cols, mask=cols < c_per_group).to(tl.float32) + beta = tl.load(beta_ptr + cols, mask=cols < c_per_group).to(tl.float32) + for i in range(tl.cdiv(img_size, HW_SIZE)): + x_ptr = input_ptr + i * HW_SIZE * c + y_ptr = output_ptr + i * HW_SIZE * c + x = tl.load(x_ptr + offsets, mask=mask, other=0.0).to(tl.float32) + x_hat = (x - group_mean) * rstd + y = x_hat * gamma + beta + if ACTIVATION_SWISH: + y *= tl.sigmoid(y) + tl.store(y_ptr + offsets, y, mask=mask) + + +# We can have more combinations of blocks and hw_sizes, e.g., +# blocks = [16, 32, 64, 128, 256, 512] +# hw_sizes = [8, 16, 32, 64, 128, 256, 512] +# but this will result in too many functions and slow down the compilation. +with_swish = [True, False] +dtypes = ["fp32", "fp16"] +blocks = [16, 32, 64, 128] +hw_sizes = [8, 16, 32, 64, 128, 256] +warps = [1, 2, 4, 8, 16] +name_pattern = "GroupNormTriton_{}_{}_b{}_hw{}_w{}" +sig_pattern = "*{},*{},*fp32,*fp32,i32,i32,i32,fp32" +group_pattern = "GroupNormTriton_{}_{}" + + +def get_function_table(): + func_table = [] + + for swish, dtype, hw_size, warp, b in product(with_swish, dtypes, hw_sizes, warps, blocks): + swish_suffix = "Swish" if swish else "Pass" + name = name_pattern.format(swish_suffix, dtype, b, hw_size, warp) + group = group_pattern.format(swish_suffix, dtype) + sig = sig_pattern.format(dtype, dtype) + kwargs = { + "num_warps": warp, + "constants": {"BLOCK_SIZE": b, "HW_SIZE": hw_size, "ACTIVATION_SWISH": int(swish)}, + } + func_desc = {"name": name, "group": group, "func": group_norm_kernel, "sig": sig, "kwargs": kwargs} + func_table.append(func_desc) + return func_table + + +if __name__ == "__main__": + func_table = get_function_table() + for func_desc in func_table: + print(func_desc) diff --git a/onnxruntime/contrib_ops/rocm/diffusion/group_norm_tunable_op.h b/onnxruntime/contrib_ops/rocm/diffusion/group_norm_tunable_op.h index 7ca38608b8def..25d820f7ed326 100644 --- a/onnxruntime/contrib_ops/rocm/diffusion/group_norm_tunable_op.h +++ b/onnxruntime/contrib_ops/rocm/diffusion/group_norm_tunable_op.h @@ -11,6 +11,7 @@ #include "contrib_ops/rocm/diffusion/group_norm_common.h" #include "contrib_ops/rocm/diffusion/group_norm_impl.h" #include "contrib_ops/rocm/diffusion/group_norm_impl_kernel.cuh" +#include "contrib_ops/rocm/diffusion/group_norm_triton.cuh" namespace onnxruntime { namespace contrib { @@ -34,11 +35,12 @@ void groupNormNHWCSum(const GroupNormNHWCParams* params) { // The number of instances. grid.z = params->n; -#define LAUNCH_GROUPNORM_SUM(ThreadsPerBlock, VecSize) \ - groupNormNHWCSumKernel \ - <<stream>>>(params->src, params->redBuffer, params->cPerBlock, \ - params->hwPerBlock, params->hw, params->hwc, params->c, \ - params->cPerGroup, params->groups, params->groupsPerBlock); \ +#define LAUNCH_GROUPNORM_SUM(ThreadsPerBlock, VecSize) \ + groupNormNHWCSumKernel \ + <<StreamHandle()>>>( \ + params->src, params->redBuffer, params->cPerBlock, \ + params->hwPerBlock, params->hw, params->hwc, params->c, \ + params->cPerGroup, params->groups, params->groupsPerBlock); \ break; switch (params->cPerBlock) { @@ -63,7 +65,7 @@ Status GroupNormNHWCSumOp(const GroupNormNHWCParams* params) { grid.z = params->n; groupNormNHWCSumKernel - <<stream>>>( + <<StreamHandle()>>>( params->src, params->redBuffer, params->cPerBlock, params->hwPerBlock, params->hw, params->hwc, params->c, params->cPerGroup, params->groups, params->groupsPerBlock); return HIP_CALL(hipGetLastError()); @@ -85,12 +87,13 @@ void groupNormNHWCScale(const GroupNormNHWCParams* params) { // The number of instances. grid.z = params->n; -#define LAUNCH_GROUPNORM_SCALE(ThreadsPerBlock, VecSize) \ - groupNormNHWCScaleKernel \ - <<stream>>>(params->dst, params->src, params->gamma, params->beta, \ - params->redBuffer, params->epsilon, params->c, params->cPerBlock, \ - params->cPerGroup, params->groups, params->hwc, params->invHWC, \ - params->hw, params->hwPerBlock, params->withSwish); \ +#define LAUNCH_GROUPNORM_SCALE(ThreadsPerBlock, VecSize) \ + groupNormNHWCScaleKernel \ + <<StreamHandle()>>>( \ + params->dst, params->src, params->gamma, params->beta, \ + params->redBuffer, params->epsilon, params->c, params->cPerBlock, \ + params->cPerGroup, params->groups, params->hwc, params->invHWC, \ + params->hw, params->hwPerBlock, params->withSwish); \ break; switch (params->cPerBlock) { @@ -115,7 +118,7 @@ Status GroupNormNHWCScaleOp(const GroupNormNHWCParams* params) { grid.z = params->n; groupNormNHWCScaleKernel - <<stream>>>( + <<StreamHandle()>>>( params->dst, params->src, params->gamma, params->beta, params->redBuffer, params->epsilon, params->c, params->cPerBlock, params->cPerGroup, params->groups, params->hwc, params->invHWC, params->hw, params->hwPerBlock, params->withSwish); return HIP_CALL(hipGetLastError()); @@ -125,7 +128,7 @@ template class GroupNormNHWCOp { public: Status operator()(const GroupNormNHWCParams* params) { - HIP_RETURN_IF_ERROR(hipMemsetAsync(params->redBuffer, 0, GetGroupNormWorkspaceSizeInBytes(), params->stream)); + HIP_RETURN_IF_ERROR(hipMemsetAsync(params->redBuffer, 0, GetGroupNormWorkspaceSizeInBytes(), params->StreamHandle())); auto status = GroupNormNHWCSumOp(params); ORT_RETURN_IF_ERROR(status); HIP_RETURN_IF_ERROR(hipGetLastError()); @@ -154,7 +157,7 @@ class GroupNormNHWCOp { template Status GroupNormNHWCStaticSelection(const GroupNormNHWCParams* params) { - HIP_RETURN_IF_ERROR(hipMemsetAsync(params->redBuffer, 0, GetGroupNormWorkspaceSizeInBytes(), params->stream)); + HIP_RETURN_IF_ERROR(hipMemsetAsync(params->redBuffer, 0, GetGroupNormWorkspaceSizeInBytes(), params->StreamHandle())); groupNormNHWCSum(params); HIP_RETURN_IF_ERROR(hipGetLastError()); groupNormNHWCScale(params); @@ -192,6 +195,17 @@ class GroupNormNHWCTunableOp : public TunableOp> { this->RegisterOp(std::move(op)); } #endif // USE_COMPOSABLE_KERNEL + +#ifdef USE_TRITON_KERNEL + for (auto&& [_, op] : GetTritonGroupNormNHWCTypeStringAndOps()) { + ORT_UNUSED_PARAMETER(_); + this->RegisterOp(std::move(op)); + } + for (auto&& [_, op] : GetTritonGroupNormNHWCTypeStringAndOps()) { + ORT_UNUSED_PARAMETER(_); + this->RegisterOp(std::move(op)); + } +#endif } }; diff --git a/onnxruntime/contrib_ops/rocm/fused_conv.cc b/onnxruntime/contrib_ops/rocm/fused_conv.cc index bbfea1d673ff9..d597e0d57fbcb 100644 --- a/onnxruntime/contrib_ops/rocm/fused_conv.cc +++ b/onnxruntime/contrib_ops/rocm/fused_conv.cc @@ -121,6 +121,7 @@ class FusedConv : public onnxruntime::rocm::Conv { ORT_THROW_IF_ERROR(MapMode(activation)); MIOPEN_CALL_THROW(miopenCreateActivationDescriptor(&activation_desc_)); MIOPEN_CALL_THROW(miopenSetActivationDescriptor(activation_desc_, activation_mode_, 0.0, 0.0, 0.0)); + MIOPEN_CALL_THROW(miopenCreateOperatorArgs(&fusion_args_)); } ORT_DISALLOW_COPY_AND_ASSIGNMENT(FusedConv); @@ -130,6 +131,10 @@ class FusedConv : public onnxruntime::rocm::Conv { MIOPEN_CALL_THROW(miopenDestroyActivationDescriptor(activation_desc_)); activation_desc_ = nullptr; } + + if (fusion_args_) { + miopenDestroyOperatorArgs(fusion_args_); + } } Status ComputeInternal(OpKernelContext* context) const override { @@ -157,20 +162,20 @@ class FusedConv : public onnxruntime::rocm::Conv { if (should_try_fusion_api) { auto& fusion_info = *cached_item.fusion; - MIOPEN_RETURN_IF_ERROR(miopenSetOpArgsConvForward(fusion_info.fusion_args, + MIOPEN_RETURN_IF_ERROR(miopenSetOpArgsConvForward(fusion_args_, fusion_info.conv_op, &alpha, &beta, Base::s_.w_data)); if (has_z) { - MIOPEN_RETURN_IF_ERROR(miopenSetOpArgsBiasForward(fusion_info.fusion_args, + MIOPEN_RETURN_IF_ERROR(miopenSetOpArgsBiasForward(fusion_args_, fusion_info.bias_z_op, &alpha, &beta, Base::s_.z_data)); } if (has_b) { - MIOPEN_RETURN_IF_ERROR(miopenSetOpArgsBiasForward(fusion_info.fusion_args, + MIOPEN_RETURN_IF_ERROR(miopenSetOpArgsBiasForward(fusion_args_, fusion_info.bias_b_op, &alpha, &beta, @@ -178,7 +183,7 @@ class FusedConv : public onnxruntime::rocm::Conv { } if (activation_desc_) { const float relu_notused = 0.0; - MIOPEN_RETURN_IF_ERROR(miopenSetOpArgsActivForward(fusion_info.fusion_args, + MIOPEN_RETURN_IF_ERROR(miopenSetOpArgsActivForward(fusion_args_, fusion_info.act_op, &alpha, &beta, @@ -192,7 +197,7 @@ class FusedConv : public onnxruntime::rocm::Conv { Base::s_.x_data, Base::s_.y_tensor, Base::s_.y_data, - fusion_info.fusion_args); + fusion_args_); } if (miopenStatusSuccess != fusion_status) { MIOPEN_RETURN_IF_ERROR(miopenConvolutionForward(this->GetMiopenHandle(context), @@ -258,6 +263,8 @@ class FusedConv : public onnxruntime::rocm::Conv { miopenActivationMode_t activation_mode_; miopenActivationDescriptor_t activation_desc_ = nullptr; + miopenOperatorArgs_t fusion_args_ = nullptr; + // MIOpen Fusion API // TODO: create one fusion descriptor shared by multiple FusedConv // objects @@ -271,38 +278,19 @@ class FusedConv : public onnxruntime::rocm::Conv { miopenFusionOpDescriptor_t bias_b_op = nullptr; miopenFusionOpDescriptor_t bias_z_op = nullptr; miopenFusionOpDescriptor_t act_op = nullptr; - miopenOperatorArgs_t fusion_args = nullptr; // TODO: There is a potential problem. miopenHandle_t may be destroyed and // re-created later, sharing the same address. Currently there is any way // to detect it? mutable std::unordered_set compiled_on; - FusedConvFusionData(const FusedConvFusionData&) = delete; - FusedConvFusionData& operator=(const FusedConvFusionData&) = delete; - - FusedConvFusionData(FusedConvFusionData&& other) { - *this = std::move(other); - } - FusedConvFusionData& operator=(FusedConvFusionData&& other) { - std::swap(this->plan, other.plan); - std::swap(this->fusion_args, other.fusion_args); - this->conv_op = other.conv_op; - this->bias_b_op = other.bias_b_op; - this->bias_z_op = other.bias_z_op; - this->act_op = other.act_op; - this->compiled_on = std::move(other.compiled_on); - return *this; - } + ORT_DISALLOW_COPY_ASSIGNMENT_AND_MOVE(FusedConvFusionData); FusedConvFusionData() {} ~FusedConvFusionData() { if (plan) { miopenDestroyFusionPlan(plan); } - if (fusion_args) { - miopenDestroyOperatorArgs(fusion_args); - } } }; @@ -312,8 +300,7 @@ class FusedConv : public onnxruntime::rocm::Conv { // TODO: Add a timestamp for eviction // std::chrono::time_point last_access; - FusionPlanCacheItem() { - } + FusionPlanCacheItem() {} miopenStatus_t CompileOnHandle(miopenHandle_t handle) const { if (!fusion->plan) { @@ -334,7 +321,7 @@ class FusedConv : public onnxruntime::rocm::Conv { if (Status::OK() != creation_result) { return false; } - if (!fusion || !fusion->plan || !fusion->fusion_args) { + if (!fusion || !fusion->plan) { return false; } auto compiling_status = CompileOnHandle(handle); @@ -377,7 +364,6 @@ class FusedConv : public onnxruntime::rocm::Conv { MIOPEN_RETURN_IF_ERROR(miopenCreateFusionPlan(&fusion.plan, miopenVerticalFusion, Base::s_.x_tensor)); - MIOPEN_RETURN_IF_ERROR(miopenCreateOperatorArgs(&fusion.fusion_args)); auto status = miopenCreateOpConvForward(fusion.plan, &fusion.conv_op, Base::s_.conv_desc, Base::s_.w_desc); if (status == miopenStatusUnsupportedOp) { auto msg = MakeString("MIOpen does not support the conv fusion for node \"", diff --git a/onnxruntime/contrib_ops/rocm/rocm_contrib_kernels.cc b/onnxruntime/contrib_ops/rocm/rocm_contrib_kernels.cc index 15f39e7dcdb09..7bc0f99081169 100644 --- a/onnxruntime/contrib_ops/rocm/rocm_contrib_kernels.cc +++ b/onnxruntime/contrib_ops/rocm/rocm_contrib_kernels.cc @@ -15,10 +15,7 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1 class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, float, Gelu); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, double, Gelu); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, MLFloat16, Gelu); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, float, BiasGelu); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, double, BiasGelu); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, MLFloat16, BiasGelu); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, BFloat16, BiasGelu); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, BiasGelu); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, MLFloat16, BiasSplitGelu); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, float, BiasSplitGelu); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, MLFloat16, BiasAdd); @@ -55,6 +52,7 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kOnnxDomain, class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kOnnxDomain, 1, MLFloat16, Affine); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, float, Attention); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, MLFloat16, Attention); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, BeamSearch); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, float, ConvTransposeWithDynamicPads); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kOnnxDomain, 1, float, Crop); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kOnnxDomain, 1, double, Crop); @@ -63,6 +61,8 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1 class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, MLFloat16, MultiHeadAttention); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, float, DecoderAttention); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, MLFloat16, DecoderAttention); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, float, DecoderMaskedMultiHeadAttention); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, MLFloat16, DecoderMaskedMultiHeadAttention); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kOnnxDomain, 1, int32_t, DynamicSlice); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kOnnxDomain, 1, int64_t, DynamicSlice); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, float, EmbedLayerNormalization); @@ -84,6 +84,8 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kOnnxDomain, class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kOnnxDomain, 1, MLFloat16, ScaledTanh); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, float, SkipLayerNormalization); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, MLFloat16, SkipLayerNormalization); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, float, SkipSimplifiedLayerNormalization); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, MLFloat16, SkipSimplifiedLayerNormalization); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kOnnxDomain, 1, float, ThresholdedRelu); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kOnnxDomain, 1, double, ThresholdedRelu); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kOnnxDomain, 1, MLFloat16, ThresholdedRelu); @@ -146,10 +148,7 @@ Status RegisterRocmContribKernels(KernelRegistry& kernel_registry) { BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, + BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, @@ -183,6 +182,8 @@ Status RegisterRocmContribKernels(KernelRegistry& kernel_registry) { // BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, + BuildKernelCreateInfo, + // BuildKernelCreateInfo, // BuildKernelCreateInfo, // BuildKernelCreateInfo, @@ -194,6 +195,8 @@ Status RegisterRocmContribKernels(KernelRegistry& kernel_registry) { 1, float, DecoderAttention)>, BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, // BuildKernelCreateInfo, // BuildKernelCreateInfo, BuildKernelCreateInfo, @@ -218,6 +221,8 @@ Status RegisterRocmContribKernels(KernelRegistry& kernel_registry) { // BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, // BuildKernelCreateInfo, // BuildKernelCreateInfo, // BuildKernelCreateInfo, diff --git a/onnxruntime/core/common/cpuid_info.cc b/onnxruntime/core/common/cpuid_info.cc index a23409292bb74..6a82b3fcc734d 100644 --- a/onnxruntime/core/common/cpuid_info.cc +++ b/onnxruntime/core/common/cpuid_info.cc @@ -135,38 +135,34 @@ void CPUIDInfo::ArmLinuxInit() { LOGS_DEFAULT(WARNING) << "Failed to init pytorch cpuinfo library, may cause CPU EP performance degradation due to undetected CPU features."; return; } + is_hybrid_ = cpuinfo_get_uarchs_count() > 1; + has_arm_neon_dot_ = cpuinfo_has_arm_neon_dot(); + has_fp16_ = cpuinfo_has_arm_neon_fp16_arith(); + const uint32_t core_cnt = cpuinfo_get_cores_count(); + core_uarchs_.resize(core_cnt, cpuinfo_uarch_unknown); + is_armv8_narrow_ld_.resize(core_cnt, false); + for (uint32_t c = 0; c < core_cnt; c++) { + const struct cpuinfo_processor* proc = cpuinfo_get_processor(c); + if (proc == nullptr) { + continue; + } + const struct cpuinfo_core* corep = proc->core; + if (corep == nullptr) { + continue; + } + auto coreid = proc->linux_id; + auto uarch = corep->uarch; + core_uarchs_[coreid] = uarch; + if (uarch == cpuinfo_uarch_cortex_a53 || uarch == cpuinfo_uarch_cortex_a55r0 || + uarch == cpuinfo_uarch_cortex_a55) { + is_armv8_narrow_ld_[coreid] = true; + } + } #else pytorch_cpuinfo_init_ = false; + has_arm_neon_dot_ = ((getauxval(AT_HWCAP) & HWCAP_ASIMDDP) != 0); + has_fp16_ |= has_arm_neon_dot_; #endif - - if (pytorch_cpuinfo_init_) { - is_hybrid_ = cpuinfo_get_uarchs_count() > 1; - has_arm_neon_dot_ = cpuinfo_has_arm_neon_dot(); - has_fp16_ = cpuinfo_has_arm_neon_fp16_arith(); - const uint32_t core_cnt = cpuinfo_get_cores_count(); - core_uarchs_.resize(core_cnt, cpuinfo_uarch_unknown); - is_armv8_narrow_ld_.resize(core_cnt, false); - for (uint32_t c = 0; c < core_cnt; c++) { - const struct cpuinfo_processor* proc = cpuinfo_get_processor(c); - if (proc == nullptr) { - continue; - } - const struct cpuinfo_core* corep = proc->core; - if (corep == nullptr) { - continue; - } - auto coreid = proc->linux_id; - auto uarch = corep->uarch; - core_uarchs_[coreid] = uarch; - if (uarch == cpuinfo_uarch_cortex_a53 || uarch == cpuinfo_uarch_cortex_a55r0 || - uarch == cpuinfo_uarch_cortex_a55) { - is_armv8_narrow_ld_[coreid] = true; - } - } - } else { - has_arm_neon_dot_ = ((getauxval(AT_HWCAP) & HWCAP_ASIMDDP) != 0); - has_fp16_ |= has_arm_neon_dot_; - } } #elif defined(_WIN32) diff --git a/onnxruntime/core/common/logging/sinks/ostream_sink.cc b/onnxruntime/core/common/logging/sinks/ostream_sink.cc index 1e72af8c54f81..0db3d8709d48c 100644 --- a/onnxruntime/core/common/logging/sinks/ostream_sink.cc +++ b/onnxruntime/core/common/logging/sinks/ostream_sink.cc @@ -7,6 +7,21 @@ namespace onnxruntime { namespace logging { +#ifndef ORT_MINIMAL_BUILD +struct Color { + constexpr static const char* kWarn = "\033[0;93m"; // yellow + constexpr static const char* kError = "\033[1;31m"; // bold red + constexpr static const char* kFatal = "\033[1;37;41m"; // bold white on red background + constexpr static const char* kEnd = "\033[m"; +#ifdef _WIN32 + constexpr static const wchar_t* kLWarn = L"\033[0;93m"; // yellow + constexpr static const wchar_t* kLError = L"\033[1;31m"; // bold red + constexpr static const wchar_t* kLFatal = L"\033[1;37;41m"; // bold white on red background + constexpr static const wchar_t* kLEnd = L"\033[m"; +#endif +}; +#endif + void OStreamSink::SendImpl(const Timestamp& timestamp, const std::string& logger_id, const Capture& message) { // operator for formatting of timestamp in ISO8601 format including microseconds using date::operator<<; @@ -20,8 +35,27 @@ void OStreamSink::SendImpl(const Timestamp& timestamp, const std::string& logger std::ostringstream msg; +#ifndef ORT_MINIMAL_BUILD + if (message.Severity() == Severity::kWARNING) { + msg << Color::kWarn; + } else if (message.Severity() == Severity::kERROR) { + msg << Color::kError; + } else if (message.Severity() == Severity::kFATAL) { + msg << Color::kFatal; + } +#endif + msg << timestamp << " [" << message.SeverityPrefix() << ":" << message.Category() << ":" << logger_id << ", " - << message.Location().ToString() << "] " << message.Message() << "\n"; + << message.Location().ToString() << "] " << message.Message(); + +#ifndef ORT_MINIMAL_BUILD + if (message.Severity() == Severity::kWARNING || + message.Severity() == Severity::kERROR || + message.Severity() == Severity::kFATAL) { + msg << Color::kEnd; + } +#endif + msg << "\n"; (*stream_) << msg.str(); @@ -43,8 +77,27 @@ void WOStreamSink::SendImpl(const Timestamp& timestamp, const std::string& logge std::wostringstream msg; +#ifndef ORT_MINIMAL_BUILD + if (message.Severity() == Severity::kWARNING) { + msg << Color::kLWarn; + } else if (message.Severity() == Severity::kERROR) { + msg << Color::kLError; + } else if (message.Severity() == Severity::kFATAL) { + msg << Color::kLFatal; + } +#endif + msg << timestamp << L" [" << message.SeverityPrefix() << L":" << message.Category() << L":" << ToWideString(logger_id) << L", " - << ToWideString(message.Location().ToString()) << L"] " << ToWideString(message.Message()) << L"\n"; + << ToWideString(message.Location().ToString()) << L"] " << ToWideString(message.Message()); + +#ifndef ORT_MINIMAL_BUILD + if (message.Severity() == Severity::kWARNING || + message.Severity() == Severity::kERROR || + message.Severity() == Severity::kFATAL) { + msg << Color::kLEnd; + } +#endif + msg << L"\n"; (*stream_) << msg.str(); diff --git a/onnxruntime/core/flatbuffers/checkpoint_version.h b/onnxruntime/core/flatbuffers/checkpoint_version.h new file mode 100644 index 0000000000000..6cad27c35024b --- /dev/null +++ b/onnxruntime/core/flatbuffers/checkpoint_version.h @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +namespace onnxruntime { + +// The versions below highlight the checkpoint format version history. +// Everytime the checkpoint format changes, the version should be incremented +// and the changes should be documented here and in the +// onnxruntime/core/flatbuffers/schema/README.md file. +// Version 1: Introduces the On-Device Training Checkpoint format +// The format includes support for the ModuleState (stores the module parameters), OptimizerGroups +// (stores the optimizer states), and PropertyBag +// (stores custom user properties with support for int64, float and strings). +constexpr const int kCheckpointVersion = 1; + +/** + * @brief Check if the given checkpoint version is supported in this build + * @param checkpoint_version The checkpoint version to check + * @return true if the checkpoint version is supported, false otherwise + */ +inline constexpr bool IsCheckpointVersionSupported(const int checkpoint_version) { + return kCheckpointVersion == checkpoint_version; +} + +} // namespace onnxruntime diff --git a/onnxruntime/core/flatbuffers/flatbuffers_utils.h b/onnxruntime/core/flatbuffers/flatbuffers_utils.h index a04bb60453035..55bde0b2df806 100644 --- a/onnxruntime/core/flatbuffers/flatbuffers_utils.h +++ b/onnxruntime/core/flatbuffers/flatbuffers_utils.h @@ -5,6 +5,8 @@ #include +#include "flatbuffers/flatbuffers.h" + #include "core/common/common.h" #include "core/common/path_string.h" #include "core/common/status.h" @@ -13,18 +15,6 @@ namespace ONNX_NAMESPACE { class ValueInfoProto; } -namespace flatbuffers { -class FlatBufferBuilder; - -template -struct Offset; - -struct String; - -template -class Vector; -} // namespace flatbuffers - namespace onnxruntime { namespace fbs { @@ -45,12 +35,12 @@ onnxruntime::common::Status SaveValueInfoOrtFormat( void LoadStringFromOrtFormat(std::string& dst, const flatbuffers::String* fbs_string); -// This macro is to be used on a protobuf message (protobug_msg), which will not create an empty string field (str_field) +// This macro is to be used on a protobuf message (protobuf_msg), which will not create an empty string field (str_field) // if fbs_string is null -#define LOAD_STR_FROM_ORT_FORMAT(protobug_msg, str_field, fbs_string) \ +#define LOAD_STR_FROM_ORT_FORMAT(protobuf_msg, str_field, fbs_string) \ { \ if (fbs_string) \ - protobug_msg.set_##str_field(fbs_string->c_str()); \ + protobuf_msg.set_##str_field(fbs_string->c_str()); \ } onnxruntime::common::Status LoadValueInfoOrtFormat( diff --git a/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/Checkpoint.py b/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/Checkpoint.py new file mode 100644 index 0000000000000..ec68fd373cf91 --- /dev/null +++ b/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/Checkpoint.py @@ -0,0 +1,87 @@ +# automatically generated by the FlatBuffers compiler, do not modify + +# namespace: fbs + +import flatbuffers +from flatbuffers.compat import import_numpy +np = import_numpy() + +class Checkpoint(object): + __slots__ = ['_tab'] + + @classmethod + def GetRootAsCheckpoint(cls, buf, offset): + n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset) + x = Checkpoint() + x.Init(buf, n + offset) + return x + + @classmethod + def CheckpointBufferHasIdentifier(cls, buf, offset, size_prefixed=False): + return flatbuffers.util.BufferHasIdentifier(buf, offset, b"\x4F\x44\x54\x43", size_prefixed=size_prefixed) + + # Checkpoint + def Init(self, buf, pos): + self._tab = flatbuffers.table.Table(buf, pos) + + # Checkpoint + def Version(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4)) + if o != 0: + return self._tab.Get(flatbuffers.number_types.Int32Flags, o + self._tab.Pos) + return 0 + + # Checkpoint + def ModuleState(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6)) + if o != 0: + x = self._tab.Indirect(o + self._tab.Pos) + from ort_flatbuffers_py.fbs.ModuleState import ModuleState + obj = ModuleState() + obj.Init(self._tab.Bytes, x) + return obj + return None + + # Checkpoint + def OptimizerGroups(self, j): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8)) + if o != 0: + x = self._tab.Vector(o) + x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * 4 + x = self._tab.Indirect(x) + from ort_flatbuffers_py.fbs.OptimizerGroup import OptimizerGroup + obj = OptimizerGroup() + obj.Init(self._tab.Bytes, x) + return obj + return None + + # Checkpoint + def OptimizerGroupsLength(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8)) + if o != 0: + return self._tab.VectorLen(o) + return 0 + + # Checkpoint + def OptimizerGroupsIsNone(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8)) + return o == 0 + + # Checkpoint + def PropertyBag(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10)) + if o != 0: + x = self._tab.Indirect(o + self._tab.Pos) + from ort_flatbuffers_py.fbs.PropertyBag import PropertyBag + obj = PropertyBag() + obj.Init(self._tab.Bytes, x) + return obj + return None + +def CheckpointStart(builder): builder.StartObject(4) +def CheckpointAddVersion(builder, version): builder.PrependInt32Slot(0, version, 0) +def CheckpointAddModuleState(builder, moduleState): builder.PrependUOffsetTRelativeSlot(1, flatbuffers.number_types.UOffsetTFlags.py_type(moduleState), 0) +def CheckpointAddOptimizerGroups(builder, optimizerGroups): builder.PrependUOffsetTRelativeSlot(2, flatbuffers.number_types.UOffsetTFlags.py_type(optimizerGroups), 0) +def CheckpointStartOptimizerGroupsVector(builder, numElems): return builder.StartVector(4, numElems, 4) +def CheckpointAddPropertyBag(builder, propertyBag): builder.PrependUOffsetTRelativeSlot(3, flatbuffers.number_types.UOffsetTFlags.py_type(propertyBag), 0) +def CheckpointEnd(builder): return builder.EndObject() diff --git a/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/FloatProperty.py b/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/FloatProperty.py new file mode 100644 index 0000000000000..49c5c6d4725c9 --- /dev/null +++ b/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/FloatProperty.py @@ -0,0 +1,44 @@ +# automatically generated by the FlatBuffers compiler, do not modify + +# namespace: fbs + +import flatbuffers +from flatbuffers.compat import import_numpy +np = import_numpy() + +class FloatProperty(object): + __slots__ = ['_tab'] + + @classmethod + def GetRootAsFloatProperty(cls, buf, offset): + n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset) + x = FloatProperty() + x.Init(buf, n + offset) + return x + + @classmethod + def FloatPropertyBufferHasIdentifier(cls, buf, offset, size_prefixed=False): + return flatbuffers.util.BufferHasIdentifier(buf, offset, b"\x4F\x44\x54\x43", size_prefixed=size_prefixed) + + # FloatProperty + def Init(self, buf, pos): + self._tab = flatbuffers.table.Table(buf, pos) + + # FloatProperty + def Name(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4)) + if o != 0: + return self._tab.String(o + self._tab.Pos) + return None + + # FloatProperty + def Value(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6)) + if o != 0: + return self._tab.Get(flatbuffers.number_types.Float32Flags, o + self._tab.Pos) + return 0.0 + +def FloatPropertyStart(builder): builder.StartObject(2) +def FloatPropertyAddName(builder, name): builder.PrependUOffsetTRelativeSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(name), 0) +def FloatPropertyAddValue(builder, value): builder.PrependFloat32Slot(1, value, 0.0) +def FloatPropertyEnd(builder): return builder.EndObject() diff --git a/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/IntProperty.py b/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/IntProperty.py new file mode 100644 index 0000000000000..195a1547fe7cf --- /dev/null +++ b/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/IntProperty.py @@ -0,0 +1,44 @@ +# automatically generated by the FlatBuffers compiler, do not modify + +# namespace: fbs + +import flatbuffers +from flatbuffers.compat import import_numpy +np = import_numpy() + +class IntProperty(object): + __slots__ = ['_tab'] + + @classmethod + def GetRootAsIntProperty(cls, buf, offset): + n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset) + x = IntProperty() + x.Init(buf, n + offset) + return x + + @classmethod + def IntPropertyBufferHasIdentifier(cls, buf, offset, size_prefixed=False): + return flatbuffers.util.BufferHasIdentifier(buf, offset, b"\x4F\x44\x54\x43", size_prefixed=size_prefixed) + + # IntProperty + def Init(self, buf, pos): + self._tab = flatbuffers.table.Table(buf, pos) + + # IntProperty + def Name(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4)) + if o != 0: + return self._tab.String(o + self._tab.Pos) + return None + + # IntProperty + def Value(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6)) + if o != 0: + return self._tab.Get(flatbuffers.number_types.Int64Flags, o + self._tab.Pos) + return 0 + +def IntPropertyStart(builder): builder.StartObject(2) +def IntPropertyAddName(builder, name): builder.PrependUOffsetTRelativeSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(name), 0) +def IntPropertyAddValue(builder, value): builder.PrependInt64Slot(1, value, 0) +def IntPropertyEnd(builder): return builder.EndObject() diff --git a/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/ModuleState.py b/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/ModuleState.py new file mode 100644 index 0000000000000..2be826fee2cc3 --- /dev/null +++ b/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/ModuleState.py @@ -0,0 +1,82 @@ +# automatically generated by the FlatBuffers compiler, do not modify + +# namespace: fbs + +import flatbuffers +from flatbuffers.compat import import_numpy +np = import_numpy() + +class ModuleState(object): + __slots__ = ['_tab'] + + @classmethod + def GetRootAsModuleState(cls, buf, offset): + n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset) + x = ModuleState() + x.Init(buf, n + offset) + return x + + @classmethod + def ModuleStateBufferHasIdentifier(cls, buf, offset, size_prefixed=False): + return flatbuffers.util.BufferHasIdentifier(buf, offset, b"\x4F\x44\x54\x43", size_prefixed=size_prefixed) + + # ModuleState + def Init(self, buf, pos): + self._tab = flatbuffers.table.Table(buf, pos) + + # ModuleState + def RequiresGradParams(self, j): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4)) + if o != 0: + x = self._tab.Vector(o) + x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * 4 + x = self._tab.Indirect(x) + from ort_flatbuffers_py.fbs.Tensor import Tensor + obj = Tensor() + obj.Init(self._tab.Bytes, x) + return obj + return None + + # ModuleState + def RequiresGradParamsLength(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4)) + if o != 0: + return self._tab.VectorLen(o) + return 0 + + # ModuleState + def RequiresGradParamsIsNone(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4)) + return o == 0 + + # ModuleState + def FrozenParams(self, j): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6)) + if o != 0: + x = self._tab.Vector(o) + x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * 4 + x = self._tab.Indirect(x) + from ort_flatbuffers_py.fbs.Tensor import Tensor + obj = Tensor() + obj.Init(self._tab.Bytes, x) + return obj + return None + + # ModuleState + def FrozenParamsLength(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6)) + if o != 0: + return self._tab.VectorLen(o) + return 0 + + # ModuleState + def FrozenParamsIsNone(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6)) + return o == 0 + +def ModuleStateStart(builder): builder.StartObject(2) +def ModuleStateAddRequiresGradParams(builder, requiresGradParams): builder.PrependUOffsetTRelativeSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(requiresGradParams), 0) +def ModuleStateStartRequiresGradParamsVector(builder, numElems): return builder.StartVector(4, numElems, 4) +def ModuleStateAddFrozenParams(builder, frozenParams): builder.PrependUOffsetTRelativeSlot(1, flatbuffers.number_types.UOffsetTFlags.py_type(frozenParams), 0) +def ModuleStateStartFrozenParamsVector(builder, numElems): return builder.StartVector(4, numElems, 4) +def ModuleStateEnd(builder): return builder.EndObject() diff --git a/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/OptimizerGroup.py b/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/OptimizerGroup.py new file mode 100644 index 0000000000000..d56069660aee3 --- /dev/null +++ b/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/OptimizerGroup.py @@ -0,0 +1,79 @@ +# automatically generated by the FlatBuffers compiler, do not modify + +# namespace: fbs + +import flatbuffers +from flatbuffers.compat import import_numpy +np = import_numpy() + +class OptimizerGroup(object): + __slots__ = ['_tab'] + + @classmethod + def GetRootAsOptimizerGroup(cls, buf, offset): + n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset) + x = OptimizerGroup() + x.Init(buf, n + offset) + return x + + @classmethod + def OptimizerGroupBufferHasIdentifier(cls, buf, offset, size_prefixed=False): + return flatbuffers.util.BufferHasIdentifier(buf, offset, b"\x4F\x44\x54\x43", size_prefixed=size_prefixed) + + # OptimizerGroup + def Init(self, buf, pos): + self._tab = flatbuffers.table.Table(buf, pos) + + # OptimizerGroup + def GroupName(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4)) + if o != 0: + return self._tab.String(o + self._tab.Pos) + return None + + # OptimizerGroup + def Step(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6)) + if o != 0: + return self._tab.Get(flatbuffers.number_types.Int64Flags, o + self._tab.Pos) + return 0 + + # OptimizerGroup + def InitialLearningRate(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8)) + if o != 0: + return self._tab.Get(flatbuffers.number_types.Float32Flags, o + self._tab.Pos) + return 0.0 + + # OptimizerGroup + def OptimizerStates(self, j): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10)) + if o != 0: + x = self._tab.Vector(o) + x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * 4 + x = self._tab.Indirect(x) + from ort_flatbuffers_py.fbs.ParameterOptimizerState import ParameterOptimizerState + obj = ParameterOptimizerState() + obj.Init(self._tab.Bytes, x) + return obj + return None + + # OptimizerGroup + def OptimizerStatesLength(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10)) + if o != 0: + return self._tab.VectorLen(o) + return 0 + + # OptimizerGroup + def OptimizerStatesIsNone(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10)) + return o == 0 + +def OptimizerGroupStart(builder): builder.StartObject(4) +def OptimizerGroupAddGroupName(builder, groupName): builder.PrependUOffsetTRelativeSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(groupName), 0) +def OptimizerGroupAddStep(builder, step): builder.PrependInt64Slot(1, step, 0) +def OptimizerGroupAddInitialLearningRate(builder, initialLearningRate): builder.PrependFloat32Slot(2, initialLearningRate, 0.0) +def OptimizerGroupAddOptimizerStates(builder, optimizerStates): builder.PrependUOffsetTRelativeSlot(3, flatbuffers.number_types.UOffsetTFlags.py_type(optimizerStates), 0) +def OptimizerGroupStartOptimizerStatesVector(builder, numElems): return builder.StartVector(4, numElems, 4) +def OptimizerGroupEnd(builder): return builder.EndObject() diff --git a/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/ParameterOptimizerState.py b/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/ParameterOptimizerState.py new file mode 100644 index 0000000000000..8e7cf8963c6a8 --- /dev/null +++ b/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/ParameterOptimizerState.py @@ -0,0 +1,63 @@ +# automatically generated by the FlatBuffers compiler, do not modify + +# namespace: fbs + +import flatbuffers +from flatbuffers.compat import import_numpy +np = import_numpy() + +class ParameterOptimizerState(object): + __slots__ = ['_tab'] + + @classmethod + def GetRootAsParameterOptimizerState(cls, buf, offset): + n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset) + x = ParameterOptimizerState() + x.Init(buf, n + offset) + return x + + @classmethod + def ParameterOptimizerStateBufferHasIdentifier(cls, buf, offset, size_prefixed=False): + return flatbuffers.util.BufferHasIdentifier(buf, offset, b"\x4F\x44\x54\x43", size_prefixed=size_prefixed) + + # ParameterOptimizerState + def Init(self, buf, pos): + self._tab = flatbuffers.table.Table(buf, pos) + + # ParameterOptimizerState + def ParamName(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4)) + if o != 0: + return self._tab.String(o + self._tab.Pos) + return None + + # ParameterOptimizerState + def Momentums(self, j): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6)) + if o != 0: + x = self._tab.Vector(o) + x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * 4 + x = self._tab.Indirect(x) + from ort_flatbuffers_py.fbs.Tensor import Tensor + obj = Tensor() + obj.Init(self._tab.Bytes, x) + return obj + return None + + # ParameterOptimizerState + def MomentumsLength(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6)) + if o != 0: + return self._tab.VectorLen(o) + return 0 + + # ParameterOptimizerState + def MomentumsIsNone(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6)) + return o == 0 + +def ParameterOptimizerStateStart(builder): builder.StartObject(2) +def ParameterOptimizerStateAddParamName(builder, paramName): builder.PrependUOffsetTRelativeSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(paramName), 0) +def ParameterOptimizerStateAddMomentums(builder, momentums): builder.PrependUOffsetTRelativeSlot(1, flatbuffers.number_types.UOffsetTFlags.py_type(momentums), 0) +def ParameterOptimizerStateStartMomentumsVector(builder, numElems): return builder.StartVector(4, numElems, 4) +def ParameterOptimizerStateEnd(builder): return builder.EndObject() diff --git a/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/PropertyBag.py b/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/PropertyBag.py new file mode 100644 index 0000000000000..17849f72d326b --- /dev/null +++ b/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/PropertyBag.py @@ -0,0 +1,109 @@ +# automatically generated by the FlatBuffers compiler, do not modify + +# namespace: fbs + +import flatbuffers +from flatbuffers.compat import import_numpy +np = import_numpy() + +class PropertyBag(object): + __slots__ = ['_tab'] + + @classmethod + def GetRootAsPropertyBag(cls, buf, offset): + n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset) + x = PropertyBag() + x.Init(buf, n + offset) + return x + + @classmethod + def PropertyBagBufferHasIdentifier(cls, buf, offset, size_prefixed=False): + return flatbuffers.util.BufferHasIdentifier(buf, offset, b"\x4F\x44\x54\x43", size_prefixed=size_prefixed) + + # PropertyBag + def Init(self, buf, pos): + self._tab = flatbuffers.table.Table(buf, pos) + + # PropertyBag + def Ints(self, j): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4)) + if o != 0: + x = self._tab.Vector(o) + x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * 4 + x = self._tab.Indirect(x) + from ort_flatbuffers_py.fbs.IntProperty import IntProperty + obj = IntProperty() + obj.Init(self._tab.Bytes, x) + return obj + return None + + # PropertyBag + def IntsLength(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4)) + if o != 0: + return self._tab.VectorLen(o) + return 0 + + # PropertyBag + def IntsIsNone(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4)) + return o == 0 + + # PropertyBag + def Floats(self, j): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6)) + if o != 0: + x = self._tab.Vector(o) + x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * 4 + x = self._tab.Indirect(x) + from ort_flatbuffers_py.fbs.FloatProperty import FloatProperty + obj = FloatProperty() + obj.Init(self._tab.Bytes, x) + return obj + return None + + # PropertyBag + def FloatsLength(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6)) + if o != 0: + return self._tab.VectorLen(o) + return 0 + + # PropertyBag + def FloatsIsNone(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6)) + return o == 0 + + # PropertyBag + def Strings(self, j): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8)) + if o != 0: + x = self._tab.Vector(o) + x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * 4 + x = self._tab.Indirect(x) + from ort_flatbuffers_py.fbs.StringProperty import StringProperty + obj = StringProperty() + obj.Init(self._tab.Bytes, x) + return obj + return None + + # PropertyBag + def StringsLength(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8)) + if o != 0: + return self._tab.VectorLen(o) + return 0 + + # PropertyBag + def StringsIsNone(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8)) + return o == 0 + +def PropertyBagStart(builder): builder.StartObject(3) +def PropertyBagAddInts(builder, ints): builder.PrependUOffsetTRelativeSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(ints), 0) +def PropertyBagStartIntsVector(builder, numElems): return builder.StartVector(4, numElems, 4) +def PropertyBagAddFloats(builder, floats): builder.PrependUOffsetTRelativeSlot(1, flatbuffers.number_types.UOffsetTFlags.py_type(floats), 0) +def PropertyBagStartFloatsVector(builder, numElems): return builder.StartVector(4, numElems, 4) +def PropertyBagAddStrings(builder, strings): builder.PrependUOffsetTRelativeSlot(2, flatbuffers.number_types.UOffsetTFlags.py_type(strings), 0) +def PropertyBagStartStringsVector(builder, numElems): return builder.StartVector(4, numElems, 4) +def PropertyBagEnd(builder): return builder.EndObject() diff --git a/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/StringProperty.py b/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/StringProperty.py new file mode 100644 index 0000000000000..97c46ec1a4777 --- /dev/null +++ b/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/StringProperty.py @@ -0,0 +1,44 @@ +# automatically generated by the FlatBuffers compiler, do not modify + +# namespace: fbs + +import flatbuffers +from flatbuffers.compat import import_numpy +np = import_numpy() + +class StringProperty(object): + __slots__ = ['_tab'] + + @classmethod + def GetRootAsStringProperty(cls, buf, offset): + n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset) + x = StringProperty() + x.Init(buf, n + offset) + return x + + @classmethod + def StringPropertyBufferHasIdentifier(cls, buf, offset, size_prefixed=False): + return flatbuffers.util.BufferHasIdentifier(buf, offset, b"\x4F\x44\x54\x43", size_prefixed=size_prefixed) + + # StringProperty + def Init(self, buf, pos): + self._tab = flatbuffers.table.Table(buf, pos) + + # StringProperty + def Name(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4)) + if o != 0: + return self._tab.String(o + self._tab.Pos) + return None + + # StringProperty + def Value(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6)) + if o != 0: + return self._tab.String(o + self._tab.Pos) + return None + +def StringPropertyStart(builder): builder.StartObject(2) +def StringPropertyAddName(builder, name): builder.PrependUOffsetTRelativeSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(name), 0) +def StringPropertyAddValue(builder, value): builder.PrependUOffsetTRelativeSlot(1, flatbuffers.number_types.UOffsetTFlags.py_type(value), 0) +def StringPropertyEnd(builder): return builder.EndObject() diff --git a/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/TensorDataType.py b/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/TensorDataType.py index baa6dc1c1fdb4..aa97e56e7869f 100644 --- a/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/TensorDataType.py +++ b/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/TensorDataType.py @@ -20,4 +20,8 @@ class TensorDataType(object): COMPLEX64 = 14 COMPLEX128 = 15 BFLOAT16 = 16 + FLOAT8E4M3FN = 17 + FLOAT8E4M3FNUZ = 18 + FLOAT8E5M2 = 19 + FLOAT8E5M2FNUZ = 20 diff --git a/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/__init__.py b/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/__init__.py index f81c64382237c..9aa70a0372739 100644 --- a/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/__init__.py +++ b/onnxruntime/core/flatbuffers/ort_flatbuffers_py/fbs/__init__.py @@ -1,7 +1,6 @@ from os.path import dirname, basename, isfile, join, splitext import glob - modules = glob.glob(join(dirname(__file__), "*.py")) -__all__ = [splitext(basename(f))[0] for f in modules if isfile(f) and not f.endswith("__init__.py")] +__all__ = [splitext(basename(f))[0] for f in modules if isfile(f) and not f.endswith('__init__.py')] from . import * diff --git a/onnxruntime/core/flatbuffers/ort_format_version.h b/onnxruntime/core/flatbuffers/ort_format_version.h index 61e0afb982785..70adb44d88cc1 100644 --- a/onnxruntime/core/flatbuffers/ort_format_version.h +++ b/onnxruntime/core/flatbuffers/ort_format_version.h @@ -11,7 +11,6 @@ namespace onnxruntime { // The current model versions for saving the ort format models // This version is NOT onnxruntime version -// Only update this version when there is a file format change which will break the compatibilites // Once this model version is updated, the kSupportedOrtModelVersions in IsOrtModelVersionSupported // below will also need to be updated. // See onnxruntime/core/flatbuffers/schema/README.md for more details on versioning. @@ -20,13 +19,15 @@ namespace onnxruntime { // Version 3 - add `graph_doc_string` to Model // Version 4 - update kernel def hashing to not depend on ordering of type constraint types (NOT BACKWARDS COMPATIBLE) // Version 5 - deprecate kernel def hashes and add KernelTypeStrResolver info to replace them (NOT BACKWARDS COMPATIBLE) -constexpr const int kOrtModelVersion = 5; +// Version 6 - add float 8 types +constexpr const int kOrtModelVersion = 6; // Check if the given ort model version is supported in this build inline bool IsOrtModelVersionSupported(const int ort_model_version) { // The ort model versions we will support in this build // This may contain more versions than the kOrtModelVersion, based on the compatibilities constexpr std::array kSupportedOrtModelVersions{ + kOrtModelVersion - 1, kOrtModelVersion, }; diff --git a/onnxruntime/core/flatbuffers/schema/README.md b/onnxruntime/core/flatbuffers/schema/README.md index c87aea0be94f9..932478111ee68 100644 --- a/onnxruntime/core/flatbuffers/schema/README.md +++ b/onnxruntime/core/flatbuffers/schema/README.md @@ -1,32 +1,39 @@ -# ORT File Format +# ORT Flatbuffer Schemas This directory contains [the ORT file format schema](ort.fbs) and [the generated C++ header file](ort.fbs.h) for the ORT file format. +This directory also contains [the on-device training checkpoint schema](ort_training_checkpoint.fbs) and +[the corresponding auto generated C++ header file](ort_training_checkpoint.fbs.h) for the checkpoint format. -[The ORT file format schema](ort.fbs) uses the [FlatBuffers](https://github.com/google/flatbuffers) serialization -library. +[The ORT file format schema](ort.fbs) and [the on-device training checkpoint schema](ort_training_checkpoint.fbs) +uses the [FlatBuffers](https://github.com/google/flatbuffers) serialization library. -Please do not directly modify [the generated C++ header file](ort.fbs.h) or [the generated Python binding -files](../ort_flatbuffers_py). +Please do not directly modify the generated C++ header file for [the ORT file format]((ort.fbs.h)) +or for [the training checkpoint file format](ort_training_checkpoint.fbs.h), +or [the generated Python binding files](../ort_flatbuffers_py). -The flatbuffers compiler (flatc) is built as part of an ONNX Runtime build. It is located in the external/flatbuffers +The flatbuffers compiler (flatc) is built as part of an ONNX Runtime build. It is located in the _deps/flatbuffers-build/ subdirectory of the build output directory. e.g. - Windows Debug build - - \build\Windows\Debug\external\flatbuffers\Debug\flatc.exe + - \build\Windows\Debug\_deps\flatbuffers-build\Debug\flatc.exe - Linux Debug build - - /build/Linux/external/flatbuffers/Debug/flatc + - /build/Linux/Debug/_deps/flatbuffers-build/flatc It is possible to use another flatc as well, e.g., from a separate installation. Note that ONNX Runtime uses FlatBuffers 1.12. -To update the ORT file format schema and generated files: -1. Modify [the ORT file format schema](ort.fbs). +To update the flatbuffers schemas and generated files: +1. Modify [the ORT file format schema](ort.fbs) or [training checkpoint schema](ort_training_checkpoint.fbs). 2. Run [compile_schema.py](./compile_schema.py) to generate the C++ and Python bindings. ``` python onnxruntime/core/flatbuffers/schema/compile_schema.py --flatc ``` +3. Update the version history and record the changes. Changes made to [the ORT file format schema](ort.fbs) +warrants not only updating the ort format version, but also the checkpoint version since the checkpoint schema +depends on the ort format schema. + # ORT FB format version history In [ort_format_version.h](../ort_format_version.h), see `IsOrtModelVersionSupported()` for the supported versions and @@ -53,7 +60,19 @@ Update kernel def hashing to not depend on ordering of type constraint types (NO Remove kernel def hashes and add KernelTypeStrResolver info to replace them (LIMITED BACKWARDS COMPATIBILITY). The change to the ORT format itself is not backwards compatibility-breaking, but ORT provides limited backwards compatibility for processing older models with missing KernelTypeStrResolver info. - The motivation for this update is to support additional execution providers with statically registered kernels. The original approach of using kernel def hashes was not so extensible as it required the execution provider providing hashes to be enabled at model conversion time. + +## Version 6 +Support for float 8 types. See [Float stored in 8 bits](https://onnx.ai/onnx/technical/float8.html) +for further details about their format and usage. + +# Checkpoint format version history +In [checkpoint_version.h](../checkpoint_version.h), see `IsCheckpointVersionSupported()` for the supported versions and +`kCheckpointVersion` for the current version. + +## Version 1 +Initial support for the On-Device Training Checkpoint format. +The format includes support for the ModuleState (stores the module parameters), OptimizerGroups +(stores the optimizer states), and PropertyBag (stores custom user properties with support for int64, float and strings). diff --git a/onnxruntime/core/flatbuffers/schema/compile_schema.py b/onnxruntime/core/flatbuffers/schema/compile_schema.py index e0c6c399e55c9..e9b090c237815 100644 --- a/onnxruntime/core/flatbuffers/schema/compile_schema.py +++ b/onnxruntime/core/flatbuffers/schema/compile_schema.py @@ -11,15 +11,24 @@ SCRIPT_DIR = pathlib.Path(__file__).parent.resolve() -def update_namespace(schema_path: pathlib.Path, updated_schema_path: pathlib.Path): - # create a copy of the schema so we can replace the namespace so that the generated module name doesn't clash - # with the 'onnxruntime' package. +def update_schema_names(schema_path: pathlib.Path, updated_schema_path: pathlib.Path, names_to_update: dict[str, str]): + """Replace the occurrence of every key in names_to_update with the corresponding value + + This function parses the schema file at schema_path line by line and replaces the occurrence of + every key in names_to_update with the corresponding value. The updated schema is written to updated_schema_path. + + Args: + schema_path (pathlib.Path): Input schema file path. + updated_schema_path (pathlib.Path): Output schema file path. + names_to_update (dict[str, str]): Dictionary of names to update. + The key is the name to replace and the value is the new name. + """ with open(schema_path) as input, open(updated_schema_path, "w") as output: for line in input: - # convert any line with the namespace to use ort_flatbuffers_py instead of onnxruntime as the top level - # namespace. this doesn't change how anything works - it just avoids a naming clash with the 'real' - # onnxruntime python package - output.write(line.replace("onnxruntime.fbs", "ort_flatbuffers_py.fbs")) + updated_line = line + for old_name, new_name in names_to_update.items(): + updated_line = updated_line.replace(old_name, new_name) + output.write(updated_line) def generate_python(flatc: pathlib.Path, schema_path: pathlib.Path, output_dir: pathlib.Path): @@ -64,7 +73,7 @@ def main(): required=True, type=pathlib.Path, help="Path to flatbuffers flatc executable. " - "Can be found in the build directory under external/flatbuffers//", + "Can be found in the build directory under _deps/flatbuffers-build//", ) all_languages = ["python", "cpp"] @@ -81,16 +90,38 @@ def main(): languages = args.languages if args.languages is not None else all_languages flatc = args.flatc.resolve(strict=True) schema_path = SCRIPT_DIR / "ort.fbs" + training_schema_path = SCRIPT_DIR / "ort_training_checkpoint.fbs" if "python" in languages: with tempfile.TemporaryDirectory() as temp_dir_name: temp_dir = pathlib.Path(temp_dir_name).resolve() updated_schema_path = temp_dir / "ort.py.fbs" - update_namespace(schema_path, updated_schema_path) + # Create a copy of the schema so we can replace the namespace so that the generated module name doesn't + # clash with the 'onnxruntime' package. + # We do this for both the ort format as well as the training checkpoint format schema. + # We convert any line with the namespace to use ort_flatbuffers_py instead of onnxruntime as the top level + # namespace. This doesn't change how anything works - it just avoids a naming clash with the 'real' + # onnxruntime python package + update_schema_names( + schema_path, updated_schema_path, {"namespace onnxruntime.fbs;": "namespace ort_flatbuffers_py.fbs;"} + ) output_dir = temp_dir / "out" output_dir.mkdir() generate_python(flatc, updated_schema_path, output_dir) + + updated_training_schema_path = temp_dir / "ort_training_checkpoint.py.fbs" + # Also replace the `include "ort.fbs";` with `include "ort.py.fbs";` since we update the file name + # that is written to in the previous step. + update_schema_names( + training_schema_path, + updated_training_schema_path, + { + "namespace onnxruntime.fbs;": "namespace ort_flatbuffers_py.fbs;", + 'include "ort.fbs";': 'include "ort.py.fbs";', + }, + ) + generate_python(flatc, updated_training_schema_path, output_dir) create_init_py(output_dir) # replace generated files in repo @@ -101,6 +132,7 @@ def main(): if "cpp" in languages: generate_cpp(flatc, schema_path) + generate_cpp(flatc, training_schema_path) if __name__ == "__main__": diff --git a/onnxruntime/core/flatbuffers/schema/ort.fbs b/onnxruntime/core/flatbuffers/schema/ort.fbs index 62f4362938513..937d59f605627 100644 --- a/onnxruntime/core/flatbuffers/schema/ort.fbs +++ b/onnxruntime/core/flatbuffers/schema/ort.fbs @@ -61,6 +61,11 @@ enum TensorDataType : int32 { COMPLEX64 = 14, COMPLEX128 = 15, BFLOAT16 = 16, + // Float 8 types. See https://onnx.ai/onnx/technical/float8.html. + FLOAT8E4M3FN = 17, + FLOAT8E4M3FNUZ = 18, + FLOAT8E5M2 = 19, + FLOAT8E5M2FNUZ = 20, } table TensorTypeAndShape { @@ -70,11 +75,11 @@ table TensorTypeAndShape { table MapType { key_type:TensorDataType; - value_type:onnxruntime.fbs.TypeInfo; + value_type:TypeInfo; } table SequenceType { - elem_type:onnxruntime.fbs.TypeInfo; + elem_type:TypeInfo; } // Node @@ -108,7 +113,7 @@ table Node { inputs:[string]; outputs:[string]; - attributes:[onnxruntime.fbs.Attribute]; + attributes:[Attribute]; input_arg_counts:[int32]; implicit_inputs:[string]; @@ -303,7 +308,6 @@ table KernelTypeStrResolver { table InferenceSession { // This is the ORT format model version // The version number is defined as kOrtModelVersion in /onnxruntime/core/flatbuffers/ort_format_version.h - // Please update it when there is a change to this schema which will break the compatibilities ort_version:string; model:Model; diff --git a/onnxruntime/core/flatbuffers/schema/ort.fbs.h b/onnxruntime/core/flatbuffers/schema/ort.fbs.h index 827970c70e4c2..e0f5342c29621 100644 --- a/onnxruntime/core/flatbuffers/schema/ort.fbs.h +++ b/onnxruntime/core/flatbuffers/schema/ort.fbs.h @@ -215,11 +215,15 @@ enum class TensorDataType : int32_t { COMPLEX64 = 14, COMPLEX128 = 15, BFLOAT16 = 16, + FLOAT8E4M3FN = 17, + FLOAT8E4M3FNUZ = 18, + FLOAT8E5M2 = 19, + FLOAT8E5M2FNUZ = 20, MIN = UNDEFINED, - MAX = BFLOAT16 + MAX = FLOAT8E5M2FNUZ }; -inline const TensorDataType (&EnumValuesTensorDataType())[17] { +inline const TensorDataType (&EnumValuesTensorDataType())[21] { static const TensorDataType values[] = { TensorDataType::UNDEFINED, TensorDataType::FLOAT, @@ -237,13 +241,17 @@ inline const TensorDataType (&EnumValuesTensorDataType())[17] { TensorDataType::UINT64, TensorDataType::COMPLEX64, TensorDataType::COMPLEX128, - TensorDataType::BFLOAT16 + TensorDataType::BFLOAT16, + TensorDataType::FLOAT8E4M3FN, + TensorDataType::FLOAT8E4M3FNUZ, + TensorDataType::FLOAT8E5M2, + TensorDataType::FLOAT8E5M2FNUZ }; return values; } inline const char * const *EnumNamesTensorDataType() { - static const char * const names[18] = { + static const char * const names[22] = { "UNDEFINED", "FLOAT", "UINT8", @@ -261,13 +269,17 @@ inline const char * const *EnumNamesTensorDataType() { "COMPLEX64", "COMPLEX128", "BFLOAT16", + "FLOAT8E4M3FN", + "FLOAT8E4M3FNUZ", + "FLOAT8E5M2", + "FLOAT8E5M2FNUZ", nullptr }; return names; } inline const char *EnumNameTensorDataType(TensorDataType e) { - if (flatbuffers::IsOutRange(e, TensorDataType::UNDEFINED, TensorDataType::BFLOAT16)) return ""; + if (flatbuffers::IsOutRange(e, TensorDataType::UNDEFINED, TensorDataType::FLOAT8E5M2FNUZ)) return ""; const size_t index = static_cast(e); return EnumNamesTensorDataType()[index]; } diff --git a/onnxruntime/core/flatbuffers/schema/ort_training_checkpoint.fbs b/onnxruntime/core/flatbuffers/schema/ort_training_checkpoint.fbs new file mode 100644 index 0000000000000..c8244b0a426f3 --- /dev/null +++ b/onnxruntime/core/flatbuffers/schema/ort_training_checkpoint.fbs @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +include "ort.fbs"; + +namespace onnxruntime.fbs; + +table ModuleState { + requires_grad_params:[Tensor]; + frozen_params:[Tensor]; +} + +table ParameterOptimizerState { + param_name:string; + momentums:[Tensor]; +} + +table OptimizerGroup { + group_name:string; + step:int64; + initial_learning_rate:float; + optimizer_states:[ParameterOptimizerState]; +} + +table IntProperty { + name:string; + value:int64; +} + +table FloatProperty { + name:string; + value:float; +} + +table StringProperty { + name:string; + value:string; +} + +table PropertyBag { + ints:[IntProperty]; + floats:[FloatProperty]; + strings:[StringProperty]; +} + +table Checkpoint { + version:int32; + module_state:ModuleState; + optimizer_groups:[OptimizerGroup]; + property_bag:PropertyBag; +} + +root_type Checkpoint; +file_identifier "ODTC"; // ORT On-Device-Training Checkpoint diff --git a/onnxruntime/core/flatbuffers/schema/ort_training_checkpoint.fbs.h b/onnxruntime/core/flatbuffers/schema/ort_training_checkpoint.fbs.h new file mode 100644 index 0000000000000..48feebb197694 --- /dev/null +++ b/onnxruntime/core/flatbuffers/schema/ort_training_checkpoint.fbs.h @@ -0,0 +1,674 @@ +// automatically generated by the FlatBuffers compiler, do not modify + + +#ifndef FLATBUFFERS_GENERATED_ORTTRAININGCHECKPOINT_ONNXRUNTIME_FBS_H_ +#define FLATBUFFERS_GENERATED_ORTTRAININGCHECKPOINT_ONNXRUNTIME_FBS_H_ + +#include "flatbuffers/flatbuffers.h" + +#include "ort.fbs.h" + +namespace onnxruntime { +namespace fbs { + +struct ModuleState; +struct ModuleStateBuilder; + +struct ParameterOptimizerState; +struct ParameterOptimizerStateBuilder; + +struct OptimizerGroup; +struct OptimizerGroupBuilder; + +struct IntProperty; +struct IntPropertyBuilder; + +struct FloatProperty; +struct FloatPropertyBuilder; + +struct StringProperty; +struct StringPropertyBuilder; + +struct PropertyBag; +struct PropertyBagBuilder; + +struct Checkpoint; +struct CheckpointBuilder; + +struct ModuleState FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef ModuleStateBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_REQUIRES_GRAD_PARAMS = 4, + VT_FROZEN_PARAMS = 6 + }; + const flatbuffers::Vector> *requires_grad_params() const { + return GetPointer> *>(VT_REQUIRES_GRAD_PARAMS); + } + const flatbuffers::Vector> *frozen_params() const { + return GetPointer> *>(VT_FROZEN_PARAMS); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_REQUIRES_GRAD_PARAMS) && + verifier.VerifyVector(requires_grad_params()) && + verifier.VerifyVectorOfTables(requires_grad_params()) && + VerifyOffset(verifier, VT_FROZEN_PARAMS) && + verifier.VerifyVector(frozen_params()) && + verifier.VerifyVectorOfTables(frozen_params()) && + verifier.EndTable(); + } +}; + +struct ModuleStateBuilder { + typedef ModuleState Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_requires_grad_params(flatbuffers::Offset>> requires_grad_params) { + fbb_.AddOffset(ModuleState::VT_REQUIRES_GRAD_PARAMS, requires_grad_params); + } + void add_frozen_params(flatbuffers::Offset>> frozen_params) { + fbb_.AddOffset(ModuleState::VT_FROZEN_PARAMS, frozen_params); + } + explicit ModuleStateBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ModuleStateBuilder &operator=(const ModuleStateBuilder &); + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateModuleState( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset>> requires_grad_params = 0, + flatbuffers::Offset>> frozen_params = 0) { + ModuleStateBuilder builder_(_fbb); + builder_.add_frozen_params(frozen_params); + builder_.add_requires_grad_params(requires_grad_params); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateModuleStateDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const std::vector> *requires_grad_params = nullptr, + const std::vector> *frozen_params = nullptr) { + auto requires_grad_params__ = requires_grad_params ? _fbb.CreateVector>(*requires_grad_params) : 0; + auto frozen_params__ = frozen_params ? _fbb.CreateVector>(*frozen_params) : 0; + return onnxruntime::fbs::CreateModuleState( + _fbb, + requires_grad_params__, + frozen_params__); +} + +struct ParameterOptimizerState FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef ParameterOptimizerStateBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_PARAM_NAME = 4, + VT_MOMENTUMS = 6 + }; + const flatbuffers::String *param_name() const { + return GetPointer(VT_PARAM_NAME); + } + const flatbuffers::Vector> *momentums() const { + return GetPointer> *>(VT_MOMENTUMS); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_PARAM_NAME) && + verifier.VerifyString(param_name()) && + VerifyOffset(verifier, VT_MOMENTUMS) && + verifier.VerifyVector(momentums()) && + verifier.VerifyVectorOfTables(momentums()) && + verifier.EndTable(); + } +}; + +struct ParameterOptimizerStateBuilder { + typedef ParameterOptimizerState Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_param_name(flatbuffers::Offset param_name) { + fbb_.AddOffset(ParameterOptimizerState::VT_PARAM_NAME, param_name); + } + void add_momentums(flatbuffers::Offset>> momentums) { + fbb_.AddOffset(ParameterOptimizerState::VT_MOMENTUMS, momentums); + } + explicit ParameterOptimizerStateBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ParameterOptimizerStateBuilder &operator=(const ParameterOptimizerStateBuilder &); + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateParameterOptimizerState( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset param_name = 0, + flatbuffers::Offset>> momentums = 0) { + ParameterOptimizerStateBuilder builder_(_fbb); + builder_.add_momentums(momentums); + builder_.add_param_name(param_name); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateParameterOptimizerStateDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const char *param_name = nullptr, + const std::vector> *momentums = nullptr) { + auto param_name__ = param_name ? _fbb.CreateString(param_name) : 0; + auto momentums__ = momentums ? _fbb.CreateVector>(*momentums) : 0; + return onnxruntime::fbs::CreateParameterOptimizerState( + _fbb, + param_name__, + momentums__); +} + +struct OptimizerGroup FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef OptimizerGroupBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_GROUP_NAME = 4, + VT_STEP = 6, + VT_INITIAL_LEARNING_RATE = 8, + VT_OPTIMIZER_STATES = 10 + }; + const flatbuffers::String *group_name() const { + return GetPointer(VT_GROUP_NAME); + } + int64_t step() const { + return GetField(VT_STEP, 0); + } + float initial_learning_rate() const { + return GetField(VT_INITIAL_LEARNING_RATE, 0.0f); + } + const flatbuffers::Vector> *optimizer_states() const { + return GetPointer> *>(VT_OPTIMIZER_STATES); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_GROUP_NAME) && + verifier.VerifyString(group_name()) && + VerifyField(verifier, VT_STEP) && + VerifyField(verifier, VT_INITIAL_LEARNING_RATE) && + VerifyOffset(verifier, VT_OPTIMIZER_STATES) && + verifier.VerifyVector(optimizer_states()) && + verifier.VerifyVectorOfTables(optimizer_states()) && + verifier.EndTable(); + } +}; + +struct OptimizerGroupBuilder { + typedef OptimizerGroup Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_group_name(flatbuffers::Offset group_name) { + fbb_.AddOffset(OptimizerGroup::VT_GROUP_NAME, group_name); + } + void add_step(int64_t step) { + fbb_.AddElement(OptimizerGroup::VT_STEP, step, 0); + } + void add_initial_learning_rate(float initial_learning_rate) { + fbb_.AddElement(OptimizerGroup::VT_INITIAL_LEARNING_RATE, initial_learning_rate, 0.0f); + } + void add_optimizer_states(flatbuffers::Offset>> optimizer_states) { + fbb_.AddOffset(OptimizerGroup::VT_OPTIMIZER_STATES, optimizer_states); + } + explicit OptimizerGroupBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + OptimizerGroupBuilder &operator=(const OptimizerGroupBuilder &); + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateOptimizerGroup( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset group_name = 0, + int64_t step = 0, + float initial_learning_rate = 0.0f, + flatbuffers::Offset>> optimizer_states = 0) { + OptimizerGroupBuilder builder_(_fbb); + builder_.add_step(step); + builder_.add_optimizer_states(optimizer_states); + builder_.add_initial_learning_rate(initial_learning_rate); + builder_.add_group_name(group_name); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateOptimizerGroupDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const char *group_name = nullptr, + int64_t step = 0, + float initial_learning_rate = 0.0f, + const std::vector> *optimizer_states = nullptr) { + auto group_name__ = group_name ? _fbb.CreateString(group_name) : 0; + auto optimizer_states__ = optimizer_states ? _fbb.CreateVector>(*optimizer_states) : 0; + return onnxruntime::fbs::CreateOptimizerGroup( + _fbb, + group_name__, + step, + initial_learning_rate, + optimizer_states__); +} + +struct IntProperty FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef IntPropertyBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NAME = 4, + VT_VALUE = 6 + }; + const flatbuffers::String *name() const { + return GetPointer(VT_NAME); + } + int64_t value() const { + return GetField(VT_VALUE, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_NAME) && + verifier.VerifyString(name()) && + VerifyField(verifier, VT_VALUE) && + verifier.EndTable(); + } +}; + +struct IntPropertyBuilder { + typedef IntProperty Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_name(flatbuffers::Offset name) { + fbb_.AddOffset(IntProperty::VT_NAME, name); + } + void add_value(int64_t value) { + fbb_.AddElement(IntProperty::VT_VALUE, value, 0); + } + explicit IntPropertyBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + IntPropertyBuilder &operator=(const IntPropertyBuilder &); + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateIntProperty( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset name = 0, + int64_t value = 0) { + IntPropertyBuilder builder_(_fbb); + builder_.add_value(value); + builder_.add_name(name); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateIntPropertyDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const char *name = nullptr, + int64_t value = 0) { + auto name__ = name ? _fbb.CreateString(name) : 0; + return onnxruntime::fbs::CreateIntProperty( + _fbb, + name__, + value); +} + +struct FloatProperty FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef FloatPropertyBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NAME = 4, + VT_VALUE = 6 + }; + const flatbuffers::String *name() const { + return GetPointer(VT_NAME); + } + float value() const { + return GetField(VT_VALUE, 0.0f); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_NAME) && + verifier.VerifyString(name()) && + VerifyField(verifier, VT_VALUE) && + verifier.EndTable(); + } +}; + +struct FloatPropertyBuilder { + typedef FloatProperty Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_name(flatbuffers::Offset name) { + fbb_.AddOffset(FloatProperty::VT_NAME, name); + } + void add_value(float value) { + fbb_.AddElement(FloatProperty::VT_VALUE, value, 0.0f); + } + explicit FloatPropertyBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + FloatPropertyBuilder &operator=(const FloatPropertyBuilder &); + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateFloatProperty( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset name = 0, + float value = 0.0f) { + FloatPropertyBuilder builder_(_fbb); + builder_.add_value(value); + builder_.add_name(name); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateFloatPropertyDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const char *name = nullptr, + float value = 0.0f) { + auto name__ = name ? _fbb.CreateString(name) : 0; + return onnxruntime::fbs::CreateFloatProperty( + _fbb, + name__, + value); +} + +struct StringProperty FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef StringPropertyBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NAME = 4, + VT_VALUE = 6 + }; + const flatbuffers::String *name() const { + return GetPointer(VT_NAME); + } + const flatbuffers::String *value() const { + return GetPointer(VT_VALUE); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_NAME) && + verifier.VerifyString(name()) && + VerifyOffset(verifier, VT_VALUE) && + verifier.VerifyString(value()) && + verifier.EndTable(); + } +}; + +struct StringPropertyBuilder { + typedef StringProperty Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_name(flatbuffers::Offset name) { + fbb_.AddOffset(StringProperty::VT_NAME, name); + } + void add_value(flatbuffers::Offset value) { + fbb_.AddOffset(StringProperty::VT_VALUE, value); + } + explicit StringPropertyBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + StringPropertyBuilder &operator=(const StringPropertyBuilder &); + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateStringProperty( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset name = 0, + flatbuffers::Offset value = 0) { + StringPropertyBuilder builder_(_fbb); + builder_.add_value(value); + builder_.add_name(name); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateStringPropertyDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const char *name = nullptr, + const char *value = nullptr) { + auto name__ = name ? _fbb.CreateString(name) : 0; + auto value__ = value ? _fbb.CreateString(value) : 0; + return onnxruntime::fbs::CreateStringProperty( + _fbb, + name__, + value__); +} + +struct PropertyBag FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef PropertyBagBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_INTS = 4, + VT_FLOATS = 6, + VT_STRINGS = 8 + }; + const flatbuffers::Vector> *ints() const { + return GetPointer> *>(VT_INTS); + } + const flatbuffers::Vector> *floats() const { + return GetPointer> *>(VT_FLOATS); + } + const flatbuffers::Vector> *strings() const { + return GetPointer> *>(VT_STRINGS); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_INTS) && + verifier.VerifyVector(ints()) && + verifier.VerifyVectorOfTables(ints()) && + VerifyOffset(verifier, VT_FLOATS) && + verifier.VerifyVector(floats()) && + verifier.VerifyVectorOfTables(floats()) && + VerifyOffset(verifier, VT_STRINGS) && + verifier.VerifyVector(strings()) && + verifier.VerifyVectorOfTables(strings()) && + verifier.EndTable(); + } +}; + +struct PropertyBagBuilder { + typedef PropertyBag Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_ints(flatbuffers::Offset>> ints) { + fbb_.AddOffset(PropertyBag::VT_INTS, ints); + } + void add_floats(flatbuffers::Offset>> floats) { + fbb_.AddOffset(PropertyBag::VT_FLOATS, floats); + } + void add_strings(flatbuffers::Offset>> strings) { + fbb_.AddOffset(PropertyBag::VT_STRINGS, strings); + } + explicit PropertyBagBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + PropertyBagBuilder &operator=(const PropertyBagBuilder &); + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreatePropertyBag( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset>> ints = 0, + flatbuffers::Offset>> floats = 0, + flatbuffers::Offset>> strings = 0) { + PropertyBagBuilder builder_(_fbb); + builder_.add_strings(strings); + builder_.add_floats(floats); + builder_.add_ints(ints); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreatePropertyBagDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const std::vector> *ints = nullptr, + const std::vector> *floats = nullptr, + const std::vector> *strings = nullptr) { + auto ints__ = ints ? _fbb.CreateVector>(*ints) : 0; + auto floats__ = floats ? _fbb.CreateVector>(*floats) : 0; + auto strings__ = strings ? _fbb.CreateVector>(*strings) : 0; + return onnxruntime::fbs::CreatePropertyBag( + _fbb, + ints__, + floats__, + strings__); +} + +struct Checkpoint FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef CheckpointBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_VERSION = 4, + VT_MODULE_STATE = 6, + VT_OPTIMIZER_GROUPS = 8, + VT_PROPERTY_BAG = 10 + }; + int32_t version() const { + return GetField(VT_VERSION, 0); + } + const onnxruntime::fbs::ModuleState *module_state() const { + return GetPointer(VT_MODULE_STATE); + } + const flatbuffers::Vector> *optimizer_groups() const { + return GetPointer> *>(VT_OPTIMIZER_GROUPS); + } + const onnxruntime::fbs::PropertyBag *property_bag() const { + return GetPointer(VT_PROPERTY_BAG); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_VERSION) && + VerifyOffset(verifier, VT_MODULE_STATE) && + verifier.VerifyTable(module_state()) && + VerifyOffset(verifier, VT_OPTIMIZER_GROUPS) && + verifier.VerifyVector(optimizer_groups()) && + verifier.VerifyVectorOfTables(optimizer_groups()) && + VerifyOffset(verifier, VT_PROPERTY_BAG) && + verifier.VerifyTable(property_bag()) && + verifier.EndTable(); + } +}; + +struct CheckpointBuilder { + typedef Checkpoint Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_version(int32_t version) { + fbb_.AddElement(Checkpoint::VT_VERSION, version, 0); + } + void add_module_state(flatbuffers::Offset module_state) { + fbb_.AddOffset(Checkpoint::VT_MODULE_STATE, module_state); + } + void add_optimizer_groups(flatbuffers::Offset>> optimizer_groups) { + fbb_.AddOffset(Checkpoint::VT_OPTIMIZER_GROUPS, optimizer_groups); + } + void add_property_bag(flatbuffers::Offset property_bag) { + fbb_.AddOffset(Checkpoint::VT_PROPERTY_BAG, property_bag); + } + explicit CheckpointBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + CheckpointBuilder &operator=(const CheckpointBuilder &); + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateCheckpoint( + flatbuffers::FlatBufferBuilder &_fbb, + int32_t version = 0, + flatbuffers::Offset module_state = 0, + flatbuffers::Offset>> optimizer_groups = 0, + flatbuffers::Offset property_bag = 0) { + CheckpointBuilder builder_(_fbb); + builder_.add_property_bag(property_bag); + builder_.add_optimizer_groups(optimizer_groups); + builder_.add_module_state(module_state); + builder_.add_version(version); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateCheckpointDirect( + flatbuffers::FlatBufferBuilder &_fbb, + int32_t version = 0, + flatbuffers::Offset module_state = 0, + const std::vector> *optimizer_groups = nullptr, + flatbuffers::Offset property_bag = 0) { + auto optimizer_groups__ = optimizer_groups ? _fbb.CreateVector>(*optimizer_groups) : 0; + return onnxruntime::fbs::CreateCheckpoint( + _fbb, + version, + module_state, + optimizer_groups__, + property_bag); +} + +inline const onnxruntime::fbs::Checkpoint *GetCheckpoint(const void *buf) { + return flatbuffers::GetRoot(buf); +} + +inline const onnxruntime::fbs::Checkpoint *GetSizePrefixedCheckpoint(const void *buf) { + return flatbuffers::GetSizePrefixedRoot(buf); +} + +inline const char *CheckpointIdentifier() { + return "ODTC"; +} + +inline bool CheckpointBufferHasIdentifier(const void *buf) { + return flatbuffers::BufferHasIdentifier( + buf, CheckpointIdentifier()); +} + +inline bool VerifyCheckpointBuffer( + flatbuffers::Verifier &verifier) { + return verifier.VerifyBuffer(CheckpointIdentifier()); +} + +inline bool VerifySizePrefixedCheckpointBuffer( + flatbuffers::Verifier &verifier) { + return verifier.VerifySizePrefixedBuffer(CheckpointIdentifier()); +} + +inline void FinishCheckpointBuffer( + flatbuffers::FlatBufferBuilder &fbb, + flatbuffers::Offset root) { + fbb.Finish(root, CheckpointIdentifier()); +} + +inline void FinishSizePrefixedCheckpointBuffer( + flatbuffers::FlatBufferBuilder &fbb, + flatbuffers::Offset root) { + fbb.FinishSizePrefixed(root, CheckpointIdentifier()); +} + +} // namespace fbs +} // namespace onnxruntime + +#endif // FLATBUFFERS_GENERATED_ORTTRAININGCHECKPOINT_ONNXRUNTIME_FBS_H_ diff --git a/onnxruntime/core/framework/allocation_planner.cc b/onnxruntime/core/framework/allocation_planner.cc index c1c8a69e73d9b..0bf27fdf5e5dc 100644 --- a/onnxruntime/core/framework/allocation_planner.cc +++ b/onnxruntime/core/framework/allocation_planner.cc @@ -136,7 +136,7 @@ class PlannerImpl { gsl::span outer_scope_node_args, const ExecutionProviders& providers, const KernelCreateInfoMap& kernel_create_info_map, const SubgraphsKernelCreateInfoMaps& subgraphs_kernel_create_info_maps, - const InlinedHashMap& outer_scope_node_arg_to_location_map, + const InlinedHashMap& outer_scope_node_arg_to_location_map, const OrtValueNameIdxMap& ort_value_name_idx_map, const ISequentialPlannerContext& context, SequentialExecutionPlan& plan) : context_(&context), @@ -169,7 +169,7 @@ class PlannerImpl { const KernelCreateInfoMap& kernel_create_info_map_; const SubgraphsKernelCreateInfoMaps& subgraphs_kernel_create_info_maps_; - const InlinedHashMap& outer_scope_node_arg_to_location_map_; + const InlinedHashMap& outer_scope_node_arg_to_location_map_; const OrtValueNameIdxMap& ort_value_name_idx_map_; @@ -707,7 +707,7 @@ class PlannerImpl { if (!is_implicit_input) { OrtMemType mem_type = p_kernel_def->InputMemoryType(arg_idx); - plan_.SetLocation(static_cast(index), exec_provider->GetAllocator(mem_type)->Info()); + plan_.SetLocation(static_cast(index), exec_provider->GetOrtDeviceByMemType(mem_type)); set_node_arg_has_explicit_consumer.insert(index); } else { // implicit input // Only process an implicit input if there are explicit consumers at this graph level @@ -779,16 +779,16 @@ class PlannerImpl { if (already_seen_ep_for_node_arg == map_implicitly_consumed_node_arg_to_ep.end()) { // First time we are encountering this implicitly consumed input at this graph level (or) - plan_.SetLocation(static_cast(index), exec_provider->GetAllocator(OrtMemType::OrtMemTypeDefault)->Info()); + plan_.SetLocation(static_cast(index), exec_provider->GetOrtDeviceByMemType(OrtMemType::OrtMemTypeDefault)); map_implicitly_consumed_node_arg_to_ep.insert({index, exec_provider}); } else if (already_seen_ep_for_node_arg->second == exec_provider) { // The EP that we previously seen for this implicit input is the same one as the current EP // we have seen - plan_.SetLocation(static_cast(index), exec_provider->GetAllocator(OrtMemType::OrtMemTypeDefault)->Info()); + plan_.SetLocation(static_cast(index), exec_provider->GetOrtDeviceByMemType(OrtMemType::OrtMemTypeDefault)); } else { // Default the location to CPU plan_.SetLocation(static_cast(index), - execution_providers_.Get(CPU)->GetAllocator(OrtMemType::OrtMemTypeDefault)->Info()); + execution_providers_.Get(CPU)->GetOrtDeviceByMemType(OrtMemType::OrtMemTypeDefault)); set_implicitly_consumed_node_arg_has_heterogenous_ep_consumers.insert(index); } } @@ -811,10 +811,7 @@ class PlannerImpl { if (!node_output->Exists()) continue; OrtValueIndex index = Index(node_output->Name()); ProcessDef(index, node_output); - auto allocator = exec_provider->GetAllocator(p_kernel_def->OutputMemoryType(i)); - ORT_ENFORCE(allocator); - plan_.SetLocation(static_cast(index), - allocator->Info()); + plan_.SetLocation(static_cast(index), exec_provider->GetOrtDeviceByMemType(p_kernel_def->OutputMemoryType(i))); } } } @@ -822,17 +819,14 @@ class PlannerImpl { return Status::OK(); } - OrtMemoryInfo GetLocationForNodeInput(size_t input_index, const Node& node, - const KernelCreateInfoMap& kernel_create_info_map) { + OrtDevice GetLocationForNodeInput(size_t input_index, const Node& node, const KernelCreateInfoMap& kernel_create_info_map) { auto* p_provider = execution_providers_.Get(node); ORT_ENFORCE(p_provider); const KernelCreateInfo& kernel_create_info = GetKernelCreateInfo(kernel_create_info_map, node.Index()); - if (utils::IsInputOnCpu(node, &kernel_create_info, input_index)) - // weights are not output from any node, so it's OK to put its location on CPU provider - return execution_providers_.GetDefaultCpuMemoryInfo(); - return p_provider->GetAllocator(OrtMemTypeDefault)->Info(); + // weights are not output from any node, so it's OK to put its location on CPU provider + return p_provider->GetOrtDeviceByMemType(utils::IsInputOnCpu(node, &kernel_create_info, input_index) ? OrtMemTypeCPUInput : OrtMemTypeDefault); } void GeneratePlanForWeightsHelper(const GraphViewer& graph_viewer, @@ -840,7 +834,7 @@ class PlannerImpl { const KernelCreateInfoMap& kernel_create_info_map, const std::string& subgraph_kernel_create_info_map_key_base, size_t graph_depth, - /*out*/ std::vector>& locations) { + /*out*/ std::vector>& locations) { // Iterate over nodes in current level firstly to record location of usages // in current graph for (const auto& node : graph_viewer.Nodes()) { @@ -949,13 +943,13 @@ class PlannerImpl { // used on different devices within the same graph level (see (1) for reason), and for // nested subgraphs, we can rely on the utils::CopyInputsAcrossDevices() to copy it // over to the appropriate device before the subgraphs are executed. - std::vector> locations(plan_.allocation_plan.size()); + std::vector> locations(plan_.allocation_plan.size()); GeneratePlanForWeightsHelper(graph_viewer_, graph_viewer_.GetAllInitializedTensors(), kernel_create_info_map_, "", 0, locations); for (size_t i = 0; i != locations.size(); ++i) { - const std::vector& loc = locations[i]; + const std::vector& loc = locations[i]; if (loc.empty()) continue; plan_.allocation_plan[i].alloc_kind = AllocKind::kAllocateStatically; // The planned location for an initializer is the location of its first usage. @@ -1024,7 +1018,7 @@ class PlannerImpl { }; // waiting_list keeps all values who want to reuse some upstream values' memory - std::map*>>> waiting_list; + std::map*>>> waiting_list; // for each node, dependents_map keeps all its dependent upstream nodes that are sure to be completed ahead std::map> dependents_map; @@ -1328,6 +1322,7 @@ class PlannerImpl { #endif ORT_RETURN_IF_ERROR(ComputeSingleStreamReusePlan(i)); ClearUseCount(); + freelist_.clear(); // DONOT share freelist across streams } #if !defined(ORT_MINIMAL_BUILD) && defined(ORT_MEMORY_PROFILE) CalculateLifetime(ort_value_usecount); @@ -1717,33 +1712,42 @@ class PlannerImpl { } #ifndef ORT_ENABLE_STREAM - void PartitionIntoStreams(const logging::Logger& /*logger*/, const ExecutionProviders& /*execution_providers*/, + void PartitionIntoStreams(const logging::Logger& /*logger*/, + const ExecutionProviders& /*execution_providers*/, const PathString& /*partition_config_file*/) { - stream_nodes_.push_back({}); - node_stream_map_.resize(SafeInt(graph_viewer_.MaxNodeIndex()) + 1); - for (auto node_index : graph_viewer_.GetNodesInTopologicalOrder()) { - stream_nodes_[0].push_back(node_index); - node_stream_map_[node_index] = 0; + if (graph_viewer_.NumberOfNodes() > 0) { + stream_nodes_.push_back({}); + node_stream_map_.resize(SafeInt(graph_viewer_.MaxNodeIndex()) + 1); + for (auto node_index : graph_viewer_.GetNodesInTopologicalOrder()) { + stream_nodes_[0].push_back(node_index); + node_stream_map_[node_index] = 0; + } + num_logic_streams_ = 1; } - num_logic_streams_ = 1; } Status BuildExecutionPlan(const ExecutionProviders& execution_providers) { // 1. create logic stream instance auto& execution_plan = plan_.execution_plan; - ORT_ENFORCE(num_logic_streams_ == 1 && !stream_nodes_[0].empty()); - execution_plan.reserve(1); - auto first_node_index = stream_nodes_[0][0]; - auto* node = graph_viewer_.GetNode(first_node_index); - onnxruntime::ProviderType exec_provider_name = node->GetExecutionProviderType(); - const IExecutionProvider* ep = execution_providers.Get(exec_provider_name); - ORT_ENFORCE(ep); - auto& node_device_mem_location = ep->GetAllocator(OrtMemType::OrtMemTypeDefault)->Info(); - execution_plan.emplace_back(std::make_unique(node_device_mem_location.device)); - // 2. add steps to the execution plan - for (auto node_index : stream_nodes_[0]) { - execution_plan[0]->steps_.emplace_back(std::make_unique(node_index)); + + if (graph_viewer_.NumberOfNodes() > 0) { + ORT_ENFORCE(num_logic_streams_ == 1 && !stream_nodes_[0].empty()); + execution_plan.reserve(1); + auto first_node_index = stream_nodes_[0][0]; + auto* node = graph_viewer_.GetNode(first_node_index); + onnxruntime::ProviderType exec_provider_name = node->GetExecutionProviderType(); + const IExecutionProvider* ep = execution_providers.Get(exec_provider_name); + ORT_ENFORCE(ep); + auto node_device_mem_location = ep->GetOrtDeviceByMemType(OrtMemType::OrtMemTypeDefault); + execution_plan.emplace_back(std::make_unique(node_device_mem_location)); + // 2. add steps to the execution plan + for (auto node_index : stream_nodes_[0]) { + execution_plan[0]->steps_.emplace_back(std::make_unique(node_index)); + } + } else { + // graph with no nodes. e.g. subgraph of If might return the input as-is or a constant value from an initializer } + return Status::OK(); } @@ -1778,18 +1782,18 @@ class PlannerImpl { onnxruntime::ProviderType exec_provider_name = node->GetExecutionProviderType(); const IExecutionProvider* ep = execution_providers.Get(exec_provider_name); ORT_ENFORCE(ep); - auto& node_device_mem_location = ep->GetAllocator(OrtMemType::OrtMemTypeDefault)->Info(); - execution_plan.emplace_back(std::make_unique(node_device_mem_location.device)); + auto node_device_mem_location = ep->GetOrtDeviceByMemType(OrtMemType::OrtMemTypeDefault); + execution_plan.emplace_back(std::make_unique(node_device_mem_location)); } else { execution_plan.emplace_back(nullptr); } } - // 2. determing following things: - // a. which node need to generate notification - // b. which node need to trigger downstream + // 2. Determining following things: + // a. which node needs to generate the notification + // b. which node needs to trigger downstream #ifdef ENABLE_TRAINING // We will leverage the topological order for the training scenario. - // The nodes before yieldOp in topo order will be executed in RunForward() and nodes after will be executed in RunBackward() + // The nodes before yieldOp in topo-order will be executed in RunForward() and nodes after will be executed in RunBackward() // This partition may not be exactly the same as forward model/gradient model, for example, some nodes in gradient model are // before yieldOp thus will be executed in RunForward() // But the final result is still correct, as long as all the nodes will be executed in either RunForward() or RunBackward() @@ -1824,7 +1828,7 @@ class PlannerImpl { if (node_stream_map_[it->Index()] != i #ifdef ENABLE_TRAINING // Do not insert Barrier/TriggerDownStream step if the producer and consumer are in different sides of yieldOp - // As in this case producer will surely be ready before consumer is running. + // As in this case producer will surely be ready before the consumer is running. && !AreNodesSeparatedByYield(node_index, it->Index()) #endif ) { @@ -1837,13 +1841,16 @@ class PlannerImpl { for (size_t i = 0; i < num_logic_streams_; ++i) { for (auto node_index : stream_nodes_[i]) { auto* node = graph_viewer_.GetNode(node_index); + auto stream_device = execution_plan[i]->device_.Type(); // Neither trigger ActivateNotification/WaitOnEPStep for Shape op (whose output is ready for all the EPs), nor // upstream is on CPU device (As currently we never invoke RegisterWaitFn(CPU, ...) for all kinds of EP, thus no wait_handle can be retrieved for this case) - if (node->OpType() != "Shape" && execution_plan[i]->device_.Type() != OrtDevice::CPU) { + if (node->OpType() != "Shape" && stream_device != OrtDevice::CPU) { for (auto it = node->OutputNodesBegin(); it != node->OutputNodesEnd(); ++it) { + bool output_consumed_in_subgraph = true; for (auto* output : node->OutputDefs()) { if (output->Exists()) { if (std::find(it->InputDefs().begin(), it->InputDefs().end(), output) != it->InputDefs().end()) { + output_consumed_in_subgraph = false; // output direclty consumed in current graph OrtValueIndex output_arg_idx; ORT_THROW_IF_ERROR(ort_value_name_idx_map_.GetIdx(output->Name(), output_arg_idx)); // there are two cases we need notification: @@ -1851,18 +1858,31 @@ class PlannerImpl { // 2. the consumer is in the same stream(non-cpu device), but it consumes a CPU tensor from an non-shape op. // for example, a resize cuda kernel consumer a tensor from MemCpyToHost cuda kernel on the same stream. // in this case, the FIFO can't guarantee the cpu tensor is ready when resize kernel is launching - OrtDevice::DeviceType output_arg_device = plan_.allocation_plan[output_arg_idx].location.device.Type(); - WaitNotificationFn wait_handle = stream_handle_registry.GetWaitHandle(execution_plan[i]->device_.Type(), output_arg_device); + OrtDevice::DeviceType output_arg_device = plan_.allocation_plan[output_arg_idx].location.Type(); + WaitNotificationFn wait_handle = stream_handle_registry.GetWaitHandle(stream_device, output_arg_device); if ((node_stream_map_[it->Index()] != i || output_arg_device == OrtDevice::CPU) && wait_handle != nullptr) { if (node_to_notification.find(node_index) == node_to_notification.end()) { node_to_notification[node_index] = plan_.notification_owners.size(); plan_.notification_owners.push_back(i); } - // if node_index is already in the map, it will NOT be overwritten by insert() node_to_wait[it->Index()].insert({node_index, wait_handle}); } } + } // output->Exists + } // for each output + if (output_consumed_in_subgraph) { + const auto downstream = node_stream_map_[it->Index()]; + if (downstream != i) { + auto downstream_device = execution_plan[downstream]->device_.Type(); + WaitNotificationFn wait_handle = stream_handle_registry.GetWaitHandle(stream_device, downstream_device); + if (wait_handle) { + if (node_to_notification.find(node_index) == node_to_notification.end()) { + node_to_notification[node_index] = plan_.notification_owners.size(); + plan_.notification_owners.push_back(i); + } + node_to_wait[it->Index()].insert({node_index, wait_handle}); + } } } } @@ -1877,8 +1897,8 @@ class PlannerImpl { auto* node = graph_viewer_.GetNode(node_index); onnxruntime::ProviderType exec_provider_name = node->GetExecutionProviderType(); const IExecutionProvider* ep = execution_providers.Get(exec_provider_name); - auto& node_device_mem_location = ep->GetAllocator(OrtMemType::OrtMemTypeDefault)->Info(); - ORT_ENFORCE(execution_plan[node_stream_map_[node_index]]->device_.Type() == node_device_mem_location.device.Type()); + auto node_device_mem_location = ep->GetOrtDeviceByMemType(OrtMemType::OrtMemTypeDefault); + ORT_ENFORCE(execution_plan[node_stream_map_[node_index]]->device_.Type() == node_device_mem_location.Type()); } } @@ -2052,8 +2072,7 @@ class PlannerImpl { } #endif - static bool - IsNonTensor(const onnxruntime::NodeArg& nodearg) { + static bool IsNonTensor(const onnxruntime::NodeArg& nodearg) { // TODO: unclear why we should go through a string-representation of type auto ptype = nodearg.Type(); auto& type_proto = ONNX_NAMESPACE::Utils::DataTypeUtils::ToTypeProto(ptype); @@ -2100,7 +2119,7 @@ Status PlannerImpl::CreatePlan( const PathString& partition_config_file, const logging::Logger& logger) { // 1. partition graph into streams - PartitionIntoStreams(logger, execution_providers_, partition_config_file); + PartitionIntoStreams(logger, execution_providers_, this->parent_node_ ? PathString{} : partition_config_file); // 2. initialize the plan based on stream partition result int num_ml_values = ort_value_name_idx_map_.MaxIdx() + 1; @@ -2154,7 +2173,7 @@ Status SequentialPlanner::CreatePlan( const ExecutionProviders& providers, const KernelCreateInfoMap& kernel_create_info_map, const SubgraphsKernelCreateInfoMaps& subgraphs_kernel_create_info_maps, - const InlinedHashMap& outer_scope_node_arg_to_location_map, + const InlinedHashMap& outer_scope_node_arg_to_location_map, const OrtValueNameIdxMap& ort_value_name_idx_map, const ISequentialPlannerContext& context, #ifdef ORT_ENABLE_STREAM @@ -2250,8 +2269,7 @@ Status DeviceBasedPartitioner::PartitionGraph(const onnxruntime::GraphViewer& gr const auto& op_type = node->OpType(); const auto& node_name = node->Name(); auto* ep = execution_providers.Get(*node); - auto& device_mem_location = ep->GetAllocator(OrtMemType::OrtMemTypeDefault)->Info(); - auto device_type = device_mem_location.device.Type(); + auto device_type = ep->GetOrtDeviceByMemType(OrtMemType::OrtMemTypeDefault).Type(); // log the device auto it = device_to_stream.find(device_type); @@ -2327,7 +2345,7 @@ void DeviceBasedPartitioner::Initialize() { } void DeviceBasedPartitioner::SaveConfig() const { - try { + ORT_TRY { json json_config; json_config["type"] = "DeviceBasedPartitioner"; if (!node_names_by_stream_.empty()) { @@ -2351,7 +2369,8 @@ void DeviceBasedPartitioner::SaveConfig() const { of_stream << json_config.dump(); of_stream.close(); } - } catch (const std::exception& ex) { + } + ORT_CATCH(const std::exception& ex) { LOGS(logger_, WARNING) << "Caught exception during saving DeviceBasedPartitioner config: " << ex.what(); } } diff --git a/onnxruntime/core/framework/allocation_planner.h b/onnxruntime/core/framework/allocation_planner.h index aa62460768796..10ea5920b8809 100644 --- a/onnxruntime/core/framework/allocation_planner.h +++ b/onnxruntime/core/framework/allocation_planner.h @@ -119,7 +119,7 @@ class SequentialPlanner { const ExecutionProviders& providers, const KernelCreateInfoMap& kernel_create_info_map, const SubgraphsKernelCreateInfoMaps& subgraphs_kernel_create_info_maps, - const InlinedHashMap& outer_scope_arg_to_location_map, + const InlinedHashMap& outer_scope_arg_to_location_map, const OrtValueNameIdxMap& ort_value_name_idx_map, const ISequentialPlannerContext& context, #ifdef ORT_ENABLE_STREAM diff --git a/onnxruntime/core/framework/allocator.cc b/onnxruntime/core/framework/allocator.cc index 1d20f3b780828..2499ead9effbd 100644 --- a/onnxruntime/core/framework/allocator.cc +++ b/onnxruntime/core/framework/allocator.cc @@ -3,7 +3,6 @@ #include "core/common/safeint.h" #include "core/framework/allocator.h" -#include "core/framework/allocatormgr.h" #include "core/mlas/inc/mlas.h" #include "core/framework/utils.h" #include "core/session/ort_apis.h" @@ -138,21 +137,21 @@ ORT_API_STATUS_IMPL(OrtApis::CreateMemoryInfo, _In_ const char* name1, enum OrtA enum OrtMemType mem_type1, _Outptr_ OrtMemoryInfo** out) { if (strcmp(name1, onnxruntime::CPU) == 0) { *out = new OrtMemoryInfo(onnxruntime::CPU, type, OrtDevice(), id1, mem_type1); - } else if (strcmp(name1, onnxruntime::CUDA) == 0) { + } else if (strcmp(name1, onnxruntime::CUDA) == 0 || + strcmp(name1, onnxruntime::OpenVINO_GPU) == 0 || + strcmp(name1, onnxruntime::DML) == 0 || + strcmp(name1, onnxruntime::HIP) == 0 || + strcmp(name1, onnxruntime::WEBGPU_BUFFER) == 0) { *out = new OrtMemoryInfo( - onnxruntime::CUDA, type, OrtDevice(OrtDevice::GPU, OrtDevice::MemType::DEFAULT, static_cast(id1)), id1, + name1, type, OrtDevice(OrtDevice::GPU, OrtDevice::MemType::DEFAULT, static_cast(id1)), id1, mem_type1); } else if (strcmp(name1, onnxruntime::CUDA_PINNED) == 0) { *out = new OrtMemoryInfo( onnxruntime::CUDA_PINNED, type, OrtDevice(OrtDevice::CPU, OrtDevice::MemType::CUDA_PINNED, static_cast(id1)), id1, mem_type1); - } else if (strcmp(name1, onnxruntime::OpenVINO_GPU) == 0) { + } else if (strcmp(name1, onnxruntime::HIP_PINNED) == 0) { *out = new OrtMemoryInfo( - onnxruntime::OpenVINO_GPU, type, OrtDevice(OrtDevice::GPU, OrtDevice::MemType::DEFAULT, static_cast(id1)), - id1, mem_type1); - } else if (strcmp(name1, onnxruntime::DML) == 0) { - *out = new OrtMemoryInfo( - onnxruntime::DML, type, OrtDevice(OrtDevice::GPU, OrtDevice::MemType::DEFAULT, static_cast(id1)), + onnxruntime::HIP_PINNED, type, OrtDevice(OrtDevice::CPU, OrtDevice::MemType::HIP_PINNED, static_cast(id1)), id1, mem_type1); } else { return OrtApis::CreateStatus(ORT_INVALID_ARGUMENT, "Specified device is not supported."); diff --git a/onnxruntime/core/framework/allocatormgr.cc b/onnxruntime/core/framework/allocator_utils.cc similarity index 65% rename from onnxruntime/core/framework/allocatormgr.cc rename to onnxruntime/core/framework/allocator_utils.cc index 192206fbd2206..7493ac7d0a4e8 100644 --- a/onnxruntime/core/framework/allocatormgr.cc +++ b/onnxruntime/core/framework/allocator_utils.cc @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/framework/allocatormgr.h" +#include "core/framework/allocator_utils.h" #include #include @@ -15,19 +15,6 @@ namespace onnxruntime { using namespace common; -namespace { -int32_t MakeKey(OrtMemType mem_type, OrtDevice device) { - // shorten device id so we can fit everything - uint8_t short_device = narrow(device.Id()); - // and convert mem_type. OrtMemType weirdly uses -2 as the first value so we offset by that before narrowing - uint8_t ort_mem_type = narrow(mem_type + 2); - - // NOTE: OrtMemType is the type of memory for a kernel's input/output - // OrtDevice.MemType is the device memory type. - return int32_t(device.Type()) << 24 | int32_t(device.MemType()) << 16 | short_device << 8 | ort_mem_type; -} -} // namespace - AllocatorPtr CreateAllocator(const AllocatorCreationInfo& info) { auto device_allocator = info.device_alloc_factory(info.device_id); @@ -42,6 +29,9 @@ AllocatorPtr CreateAllocator(const AllocatorCreationInfo& info) { int initial_growth_chunk_size_bytes = info.arena_cfg.initial_growth_chunk_size_bytes == -1 ? BFCArena::DEFAULT_INITIAL_GROWTH_CHUNK_SIZE_BYTES : info.arena_cfg.initial_growth_chunk_size_bytes; + int64_t max_power_of_two_extend_bytes = info.arena_cfg.max_power_of_two_extend_bytes == -1 + ? BFCArena::DEFAULT_MAX_POWER_OF_TWO_EXTEND_BYTES + : info.arena_cfg.max_power_of_two_extend_bytes; ArenaExtendStrategy arena_extend_str; switch (info.arena_cfg.arena_extend_strategy) { case static_cast(ArenaExtendStrategy::kSameAsRequested): @@ -77,37 +67,12 @@ AllocatorPtr CreateAllocator(const AllocatorCreationInfo& info) { arena_extend_str, initial_chunk_size_bytes, max_dead_bytes_per_chunk, - initial_growth_chunk_size_bytes)); + initial_growth_chunk_size_bytes, + max_power_of_two_extend_bytes)); } } else { return device_allocator; } } -// Update allocator in the provider if already present; ignore if not. -void AllocatorManager::ReplaceAllocator(AllocatorPtr allocator) { - const auto& info = allocator->Info(); - auto iter = allocators_.find(MakeKey(info.mem_type, info.device)); - if (iter != allocators_.end()) { - iter->second = allocator; - } -} - -void AllocatorManager::InsertAllocator(AllocatorPtr allocator) { - const OrtMemoryInfo& info = allocator->Info(); - int32_t key = MakeKey(info.mem_type, info.device); - auto iter = allocators_.find(key); - if (iter != allocators_.end()) { - ORT_THROW("Duplicate allocator for OrtMemType:", info.mem_type, " device:", info.device.ToString(), - " Existing allocator: ", iter->second->Info().name, - " New allocator: ", allocator->Info().name); - } - - allocators_[key] = allocator; -} - -AllocatorPtr AllocatorManager::GetAllocator(OrtMemType mem_type, OrtDevice device) const { - auto iter = allocators_.find(MakeKey(mem_type, device)); - return iter != allocators_.end() ? iter->second : nullptr; -} } // namespace onnxruntime diff --git a/onnxruntime/core/framework/allocatormgr.h b/onnxruntime/core/framework/allocator_utils.h similarity index 64% rename from onnxruntime/core/framework/allocatormgr.h rename to onnxruntime/core/framework/allocator_utils.h index 7a92b80c674d4..7dda1d1a6fd8f 100644 --- a/onnxruntime/core/framework/allocatormgr.h +++ b/onnxruntime/core/framework/allocator_utils.h @@ -18,7 +18,7 @@ struct AllocatorCreationInfo { AllocatorCreationInfo(AllocatorFactory device_alloc_factory, OrtDevice::DeviceId device_id = 0, bool use_arena = true, - OrtArenaCfg arena_cfg = {0, -1, -1, -1, -1}, + OrtArenaCfg arena_cfg = {0, -1, -1, -1, -1, -1L}, bool stream_aware_arena = false, bool cross_stream_reusing = false) : device_alloc_factory(device_alloc_factory), @@ -42,23 +42,4 @@ struct AllocatorCreationInfo { // Valid values can be found in onnxruntime_c_api.h. AllocatorPtr CreateAllocator(const AllocatorCreationInfo& info); -// Used for sharing allocators across EPs. e.g. CUDA with TensorRT, CPU with XNNPACK -// NOTE: This isn't managing the lifetime of the allocators (they're all in shared_ptr instances anyway). -// It really just provides a way to collect and pass around allocators between the calls to -// IExecutionProvider::RegisterAllocator for each registered EP. Once those calls complete it is no longer needed. -class AllocatorManager { - // - public: - AllocatorManager() = default; - void InsertAllocator(AllocatorPtr allocator); - void ReplaceAllocator(AllocatorPtr allocator); - // Get an allocator for the device. Return nullptr if it doesn't exist - AllocatorPtr GetAllocator(OrtMemType mem_type, OrtDevice device) const; - - private: - // key from OrtMemType+OrtDevice mapped to AllocatorPtr - using AllocatorMap = std::unordered_map; - AllocatorMap allocators_; -}; - } // namespace onnxruntime diff --git a/onnxruntime/core/framework/bfc_arena.cc b/onnxruntime/core/framework/bfc_arena.cc index 097e8e9eadad2..13f9656ae0595 100644 --- a/onnxruntime/core/framework/bfc_arena.cc +++ b/onnxruntime/core/framework/bfc_arena.cc @@ -11,7 +11,8 @@ BFCArena::BFCArena(std::unique_ptr resource_allocator, ArenaExtendStrategy arena_extend_strategy, int initial_chunk_size_bytes, int max_dead_bytes_per_chunk, - int initial_growth_chunk_size_bytes) + int initial_growth_chunk_size_bytes, + int64_t max_power_of_two_extend_bytes) : IAllocator(OrtMemoryInfo(resource_allocator->Info().name, OrtAllocatorType::OrtArenaAllocator, resource_allocator->Info().device, @@ -23,11 +24,13 @@ BFCArena::BFCArena(std::unique_ptr resource_allocator, next_allocation_id_(1), initial_chunk_size_bytes_(initial_chunk_size_bytes), max_dead_bytes_per_chunk_(max_dead_bytes_per_chunk), - initial_growth_chunk_size_bytes_(initial_growth_chunk_size_bytes) { + initial_growth_chunk_size_bytes_(initial_growth_chunk_size_bytes), + max_power_of_two_extend_bytes_(max_power_of_two_extend_bytes) { LOGS_DEFAULT(INFO) << "Creating BFCArena for " << device_allocator_->Info().name << " with following configs: initial_chunk_size_bytes: " << initial_chunk_size_bytes_ << " max_dead_bytes_per_chunk: " << max_dead_bytes_per_chunk_ << " initial_growth_chunk_size_bytes: " << initial_growth_chunk_size_bytes_ + << " max_power_of_two_extend_bytes: " << max_power_of_two_extend_bytes_ << " memory limit: " << total_memory << " arena_extend_strategy: " << static_cast(arena_extend_strategy); @@ -144,7 +147,12 @@ Status BFCArena::Extend(size_t rounded_bytes) { // we allocated the same number of bytes as the current region // the 2x is to double the minimum size of the next amount we'll allocate if (!increased_allocation) { - curr_region_allocation_bytes_ *= 2; + if (arena_extend_strategy_ == ArenaExtendStrategy::kNextPowerOfTwo && + curr_region_allocation_bytes_ * 2 < max_power_of_two_extend_bytes_) { + curr_region_allocation_bytes_ *= 2; + } else { + curr_region_allocation_bytes_ = max_power_of_two_extend_bytes_; + } } } else if (arena_extend_strategy_ == ArenaExtendStrategy::kSameAsRequested) { // BFC Arena could cause internal and external fragmentation. But, running training with @@ -847,13 +855,15 @@ StreamAwareArena::StreamAwareArena(std::unique_ptr resource_allocato ArenaExtendStrategy arena_extend_strategy, int initial_chunk_size_bytes, int max_dead_bytes_per_chunk, - int initial_growth_chunk_size_bytes) : BFCArena(std::move(resource_allocator), - total_memory, - arena_extend_strategy, - initial_chunk_size_bytes, - max_dead_bytes_per_chunk, - initial_growth_chunk_size_bytes), - enable_cross_stream_reusing_(enable_cross_stream_sharing) { + int initial_growth_chunk_size_bytes, + int64_t max_power_of_two_extend_bytes) : BFCArena(std::move(resource_allocator), + total_memory, + arena_extend_strategy, + initial_chunk_size_bytes, + max_dead_bytes_per_chunk, + initial_growth_chunk_size_bytes, + max_power_of_two_extend_bytes), + enable_cross_stream_reusing_(enable_cross_stream_sharing) { arena_type_ = ArenaType::StreamAwareArena; } diff --git a/onnxruntime/core/framework/bfc_arena.h b/onnxruntime/core/framework/bfc_arena.h index 311a9ae7869f0..e16b90ded3381 100644 --- a/onnxruntime/core/framework/bfc_arena.h +++ b/onnxruntime/core/framework/bfc_arena.h @@ -59,6 +59,7 @@ class BFCArena : public IAllocator { static const int DEFAULT_INITIAL_CHUNK_SIZE_BYTES = 1 * 1024 * 1024; static const int DEFAULT_MAX_DEAD_BYTES_PER_CHUNK = 128 * 1024 * 1024; static const int DEFAULT_INITIAL_GROWTH_CHUNK_SIZE_BYTES = 2 * 1024 * 1024; + static const int64_t DEFAULT_MAX_POWER_OF_TWO_EXTEND_BYTES = 1024 * 1024 * 1024; // 1GB static const size_t DEFAULT_MAX_MEM = std::numeric_limits::max(); enum ArenaType { @@ -71,7 +72,8 @@ class BFCArena : public IAllocator { ArenaExtendStrategy arena_extend_strategy = DEFAULT_ARENA_EXTEND_STRATEGY, int initial_chunk_size_bytes = DEFAULT_INITIAL_CHUNK_SIZE_BYTES, int max_dead_bytes_per_chunk = DEFAULT_MAX_DEAD_BYTES_PER_CHUNK, - int initial_growth_chunk_size_bytes = DEFAULT_INITIAL_GROWTH_CHUNK_SIZE_BYTES); + int initial_growth_chunk_size_bytes = DEFAULT_INITIAL_GROWTH_CHUNK_SIZE_BYTES, + int64_t max_power_of_two_extend_bytes = DEFAULT_MAX_POWER_OF_TWO_EXTEND_BYTES); ~BFCArena() override; @@ -505,6 +507,7 @@ class BFCArena : public IAllocator { const int initial_chunk_size_bytes_; const int max_dead_bytes_per_chunk_; const int initial_growth_chunk_size_bytes_; + const int64_t max_power_of_two_extend_bytes_; // This flag is only relevant if Shrink() is invoked. // This is a boolean flag that controls whether the first allocation region @@ -522,7 +525,8 @@ class StreamAwareArena : public BFCArena { ArenaExtendStrategy arena_extend_strategy = DEFAULT_ARENA_EXTEND_STRATEGY, int initial_chunk_size_bytes = DEFAULT_INITIAL_CHUNK_SIZE_BYTES, int max_dead_bytes_per_chunk = DEFAULT_MAX_DEAD_BYTES_PER_CHUNK, - int initial_growth_chunk_size_bytes = DEFAULT_INITIAL_GROWTH_CHUNK_SIZE_BYTES); + int initial_growth_chunk_size_bytes = DEFAULT_INITIAL_GROWTH_CHUNK_SIZE_BYTES, + int64_t max_power_of_two_extend_bytes = DEFAULT_MAX_POWER_OF_TWO_EXTEND_BYTES); // If size is 0, then this function returns either NULL, // or a unique pointer value that can later be successfully diff --git a/onnxruntime/core/framework/cloud_executor.cc b/onnxruntime/core/framework/cloud_executor.cc deleted file mode 100644 index 5c5a33e69fe1a..0000000000000 --- a/onnxruntime/core/framework/cloud_executor.cc +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#ifdef USE_AZURE -#include "core/framework/cloud_executor.h" -#include "core/framework/cloud_invoker.h" -#include "core/framework/session_state.h" - -namespace onnxruntime { - -common::Status CloudExecutor::Execute(const SessionState& session_state, gsl::span, - gsl::span feeds, gsl::span, - std::vector& fetches, - const std::unordered_map&, - const logging::Logger&) { - // collect input names - const auto& inputs = session_state.GetGraphViewer().GetInputs(); - InlinedVector input_names; - input_names.reserve(inputs.size()); - for (const auto& input : inputs) { - input_names.push_back(input->Name()); - } - - // collect output names - const auto& outputs = session_state.GetGraphViewer().GetOutputs(); - InlinedVector output_names; - output_names.reserve(outputs.size()); - for (const auto& output : outputs) { - output_names.push_back(output->Name()); - } - - // create invoker - static const OrtDevice cpu_device; - auto allocator = session_state.GetAllocator(cpu_device); - std::unique_ptr invoker; - - auto status = CloudEndPointInvoker::CreateInvoker( - session_state.GetSessionOptions().config_options.configurations, - allocator, invoker); - - if (invoker) { - return invoker->Send(run_options_, input_names, feeds, output_names, fetches); - } else { - return status; - } -} - -} // namespace onnxruntime -#endif \ No newline at end of file diff --git a/onnxruntime/core/framework/cloud_executor.h b/onnxruntime/core/framework/cloud_executor.h deleted file mode 100644 index e91acf1508e2c..0000000000000 --- a/onnxruntime/core/framework/cloud_executor.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#ifdef USE_AZURE -#include "core/framework/iexecutor.h" -namespace onnxruntime { - -class CloudExecutor : public onnxruntime::IExecutor { - public: - explicit CloudExecutor(const std::unordered_map& run_options) : run_options_(run_options){}; - ~CloudExecutor() = default; - ORT_DISALLOW_COPY_ASSIGNMENT_AND_MOVE(CloudExecutor); - - common::Status Execute(const SessionState& session_state, gsl::span feed_mlvalue_idxs, - gsl::span feeds, gsl::span fetch_mlvalue_idxs, - std::vector& fetches, - const std::unordered_map& fetch_allocators, - const logging::Logger& logger) override; - - private: - const std::unordered_map& run_options_; -}; -} // namespace onnxruntime -#endif diff --git a/onnxruntime/core/framework/cloud_invoker.cc b/onnxruntime/core/framework/cloud_invoker.cc deleted file mode 100644 index d6883d408f2e4..0000000000000 --- a/onnxruntime/core/framework/cloud_invoker.cc +++ /dev/null @@ -1,304 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#ifdef USE_AZURE -#include "http_client.h" -#include "core/common/common.h" -#include "core/framework/cloud_invoker.h" -#include "core/framework/ort_value.h" - -#define CHECK_TRITON_ERR(ret, msg) \ - if (!ret.IsOk()) { \ - return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, msg, ", triton err: ", ret.Message().c_str()); \ - } - -using namespace onnxruntime::common; - -namespace onnxruntime { - -namespace tc = triton::client; - -const char* kAzureUri = "azure.uri"; -const char* kAzureModelName = "azure.model_name"; -const char* kAzureModelVer = "azure.model_version"; -const char* kAzureVerbose = "azure.verbose"; -const char* kAzureEndpointType = "azure.endpoint_type"; -const char* kAzureAuthKey = "azure.auth_key"; -const char* kAzureTriton = "triton"; - -CloudEndPointInvoker::CloudEndPointInvoker(const CloudEndPointConfig& config, - const AllocatorPtr& allocator) : config_(config), allocator_(allocator) { - if (!allocator_) { - ORT_THROW("Cannot create invoker on invalid allocator"); - } -} - -class AzureTritonInvoker : public CloudEndPointInvoker { - public: - AzureTritonInvoker(const CloudEndPointConfig& config, const AllocatorPtr& allocator); - onnxruntime::Status Send(const CloudEndPointConfig& run_options, - const InlinedVector& input_names, - gsl::span ort_inputs, - const InlinedVector& output_names, - std::vector& ort_outputs) const override; - - private: - static std::string MapDataType(int32_t ort_data_type); - onnxruntime::TensorPtr CreateTensor(const std::string& data_type, const onnxruntime::VectorInt64& dim) const; - - std::string uri_; - std::string model_name_; - std::string model_ver_ = "1"; - std::string verbose_ = "0"; - std::unique_ptr triton_client_; -}; - -std::string AzureTritonInvoker::MapDataType(int32_t ort_data_type) { - std::string triton_data_type; - switch (ort_data_type) { - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: - triton_data_type = "FP32"; - break; - case ONNX_NAMESPACE::TensorProto_DataType_UINT8: - triton_data_type = "UINT8"; - break; - case ONNX_NAMESPACE::TensorProto_DataType_INT8: - triton_data_type = "INT8"; - break; - case ONNX_NAMESPACE::TensorProto_DataType_UINT16: - triton_data_type = "UINT16"; - break; - case ONNX_NAMESPACE::TensorProto_DataType_INT16: - triton_data_type = "INT16"; - break; - case ONNX_NAMESPACE::TensorProto_DataType_INT32: - triton_data_type = "INT32"; - break; - case ONNX_NAMESPACE::TensorProto_DataType_INT64: - triton_data_type = "INT64"; - break; - // do we need to support string? - // case ONNX_NAMESPACE::TensorProto_DataType_STRING: - // triton_data_type = "BYTES"; - // break; - case ONNX_NAMESPACE::TensorProto_DataType_BOOL: - triton_data_type = "BOOL"; - break; - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT16: - triton_data_type = "FP16"; - break; - case ONNX_NAMESPACE::TensorProto_DataType_DOUBLE: - triton_data_type = "FP64"; - break; - case ONNX_NAMESPACE::TensorProto_DataType_UINT32: - triton_data_type = "UINT32"; - break; - case ONNX_NAMESPACE::TensorProto_DataType_UINT64: - triton_data_type = "UINT64"; - break; - case ONNX_NAMESPACE::TensorProto_DataType_BFLOAT16: - triton_data_type = "BF16"; - break; - default: - break; - } - return triton_data_type; -} - -onnxruntime::TensorPtr AzureTritonInvoker::CreateTensor(const std::string& data_type, const onnxruntime::VectorInt64& dim) const { - if (data_type == "FP32") { - return std::make_unique(onnxruntime::DataTypeImpl::GetType(), TensorShape{dim}, allocator_); - } else if (data_type == "UINT8") { - return std::make_unique(onnxruntime::DataTypeImpl::GetType(), TensorShape{dim}, allocator_); - } else if (data_type == "INT8") { - return std::make_unique(onnxruntime::DataTypeImpl::GetType(), TensorShape{dim}, allocator_); - } else if (data_type == "UINT16") { - return std::make_unique(onnxruntime::DataTypeImpl::GetType(), TensorShape{dim}, allocator_); - } else if (data_type == "INT16") { - return std::make_unique(onnxruntime::DataTypeImpl::GetType(), TensorShape{dim}, allocator_); - } else if (data_type == "INT32") { - return std::make_unique(onnxruntime::DataTypeImpl::GetType(), TensorShape{dim}, allocator_); - } else if (data_type == "INT64") { - return std::make_unique(onnxruntime::DataTypeImpl::GetType(), TensorShape{dim}, allocator_); - } else if (data_type == "BOOL") { - return std::make_unique(onnxruntime::DataTypeImpl::GetType(), TensorShape{dim}, allocator_); - } else if (data_type == "FP16") { - return std::make_unique(onnxruntime::DataTypeImpl::GetType(), TensorShape{dim}, allocator_); - } else if (data_type == "FP64") { - return std::make_unique(onnxruntime::DataTypeImpl::GetType(), TensorShape{dim}, allocator_); - } else if (data_type == "UINT32") { - return std::make_unique(onnxruntime::DataTypeImpl::GetType(), TensorShape{dim}, allocator_); - } else if (data_type == "UINT64") { - return std::make_unique(onnxruntime::DataTypeImpl::GetType(), TensorShape{dim}, allocator_); - } else if (data_type == "BF16") { - return std::make_unique(onnxruntime::DataTypeImpl::GetType(), TensorShape{dim}, allocator_); - } else { - return {}; - } -} - -AzureTritonInvoker::AzureTritonInvoker(const CloudEndPointConfig& config, - const AllocatorPtr& allocator) : CloudEndPointInvoker(config, allocator) { - ReadConfig(kAzureUri, uri_); - ReadConfig(kAzureModelName, model_name_); - ReadConfig(kAzureModelVer, model_ver_, false); - ReadConfig(kAzureVerbose, verbose_, false); - - auto err = tc::InferenceServerHttpClient::Create(&triton_client_, uri_, verbose_ != "0"); - if (!err.IsOk()) { - ORT_THROW("Failed to initialize triton client, triton err: " + err.Message()); - } -} - -onnxruntime::Status AzureTritonInvoker::Send(const CloudEndPointConfig& run_options, - const InlinedVector& input_names, - gsl::span ort_inputs, - const InlinedVector& output_names, - std::vector& ort_outputs) const { - const auto auth_key_iter = run_options.find(kAzureAuthKey); - if (run_options.end() == auth_key_iter) { - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, - "auth key must be specified for triton client"); - } - - if (ort_inputs.size() != input_names.size()) { - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, - "Number of inputs mismatch with number of input names for triton invoker: ", - ort_inputs.size(), " != ", input_names.size()); - } - - auto tensor_type = DataTypeImpl::GetType(); - std::vector> triton_input_vec; - std::vector triton_inputs; - std::vector> triton_output_vec; - std::vector triton_outputs; - tc::Error err; - - try { - // assemble triton inputs - auto iter = input_names.begin(); - for (int i = 0; i < static_cast(ort_inputs.size()); i++) { - const OrtValue& ort_input = ort_inputs[i]; - if (!ort_input.IsTensor()) { - // do we need to support tensor sequence and sparse tensor? - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Triton client only accept tensor(s) as input"); - } - - const auto& input_tensor = ort_input.Get(); - const auto& ort_input_shape = input_tensor.Shape(); - - tc::InferInput* triton_input = {}; - std::string triton_data_type = MapDataType(input_tensor.GetElementType()); - if (triton_data_type.empty()) { - return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Triton client does not support data type: ", - ONNX_NAMESPACE::TensorProto_DataType_Name(input_tensor.GetElementType())); - } - - onnxruntime::VectorInt64 dims(ort_input_shape.NumDimensions()); - ort_input_shape.CopyDims(dims.data(), ort_input_shape.NumDimensions()); - - err = tc::InferInput::Create(&triton_input, *iter, dims, MapDataType(input_tensor.GetElementType())); - triton_input_vec.emplace_back(triton_input); - CHECK_TRITON_ERR(err, (std::string{"Failed to create triton input for "} + *iter).c_str()); - - triton_inputs.push_back(triton_input); - triton_input->AppendRaw(static_cast(input_tensor.DataRaw()), input_tensor.SizeInBytes()); - ++iter; - } // for - - iter = output_names.begin(); - while (iter != output_names.end()) { - tc::InferRequestedOutput* triton_output; - err = tc::InferRequestedOutput::Create(&triton_output, *iter); - triton_output_vec.emplace_back(triton_output); - CHECK_TRITON_ERR(err, (std::string{"Failed to create triton output for "} + *iter).c_str()); - triton_outputs.push_back(triton_output); - ++iter; - } - - std::unique_ptr results_ptr; - tc::InferResult* results = {}; - tc::InferOptions options(model_name_); - options.model_version_ = model_ver_; - options.client_timeout_ = 0; - - tc::Headers http_headers; - http_headers["Authorization"] = std::string{"Bearer "} + auth_key_iter->second; - - err = triton_client_->Infer(&results, options, triton_inputs, triton_outputs, - http_headers, tc::Parameters(), - tc::InferenceServerHttpClient::CompressionType::NONE, // support compression in config? - tc::InferenceServerHttpClient::CompressionType::NONE); - results_ptr.reset(results); - CHECK_TRITON_ERR(err, "Triton client failed to do inference"); - - if (ort_outputs.empty()) { - ort_outputs.resize(output_names.size()); - } - - int output_index = 0; - iter = output_names.begin(); - - while (iter != output_names.end()) { - std::vector dims; - err = results_ptr->Shape(*iter, &dims); - CHECK_TRITON_ERR(err, (std::string{"Failed to get shape for output "} + *iter).c_str()); - - std::string type; - err = results_ptr->Datatype(*iter, &type); - CHECK_TRITON_ERR(err, (std::string{"Failed to get type for output "} + *iter).c_str()); - - const uint8_t* raw_data = {}; - size_t raw_size; - err = results_ptr->RawData(*iter, &raw_data, &raw_size); - CHECK_TRITON_ERR(err, (std::string{"Failed to get raw data for output "} + *iter).c_str()); - - auto output_tensor = CreateTensor(type, dims); - if (!output_tensor) { - return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Failed to create output tensor for output", *iter); - } - // how to skip memcpy? - memcpy(output_tensor->MutableDataRaw(), raw_data, raw_size); - ort_outputs[output_index++].Init(output_tensor.release(), tensor_type, tensor_type->GetDeleteFunc()); - ++iter; - } - } catch (const std::exception& ex) { - return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Caught exception in TritonInvokder::Send", ex.what()); - } - return Status::OK(); -} - -void CloudEndPointInvoker::ReadConfig(const char* config_name, std::string& config_val, bool required) { - const auto iter = config_.find(config_name); - if (config_.end() != iter) { - config_val = iter->second; - } else if (required) { - ORT_THROW("Triton invoker failed to initialize due to missed config: ", config_name); - } -} - -Status CloudEndPointInvoker::CreateInvoker(const CloudEndPointConfig& config, - const AllocatorPtr& allocator, - std::unique_ptr& invoker) { - auto status = Status::OK(); - ORT_TRY { - const auto iter = config.find(kAzureEndpointType); - if (config.end() != iter) { - if (iter->second == kAzureTriton) { - invoker = std::make_unique(config, allocator); - return status; - } // else other endpoint types ... - } - status = ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, - "Cannot create azure invoker due to missed or mismatched endpoint type."); - } - ORT_CATCH(const std::exception& ex) { - ORT_HANDLE_EXCEPTION([&]() { - status = ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, ex.what()); - }); - } - return status; -} - -} // namespace onnxruntime -#endif \ No newline at end of file diff --git a/onnxruntime/core/framework/cloud_invoker.h b/onnxruntime/core/framework/cloud_invoker.h deleted file mode 100644 index 4505899605aa2..0000000000000 --- a/onnxruntime/core/framework/cloud_invoker.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. -#pragma once - -#ifdef USE_AZURE -#include -#include "gsl/gsl" -#include "core/framework/tensor.h" -#include "core/common/inlined_containers.h" - -namespace onnxruntime { - -using CloudEndPointConfig = std::unordered_map; -using TensorPtr = std::unique_ptr; -using TensorPtrArray = onnxruntime::InlinedVector; - -class CloudEndPointInvoker { - public: - CloudEndPointInvoker(const CloudEndPointConfig& config, const AllocatorPtr& allocator); - virtual ~CloudEndPointInvoker() = default; - ORT_DISALLOW_COPY_ASSIGNMENT_AND_MOVE(CloudEndPointInvoker); - - static Status CreateInvoker(const CloudEndPointConfig& config, - const AllocatorPtr& allocator, - std::unique_ptr& invoker); - - virtual onnxruntime::Status Send(const CloudEndPointConfig& run_options, - const InlinedVector& input_names, - gsl::span ort_inputs, - const InlinedVector& output_names, - std::vector& ort_outputs) const = 0; - - protected: - void ReadConfig(const char* config_name, std::string& config_val, bool required = true); - CloudEndPointConfig config_; - const AllocatorPtr& allocator_; -}; -} // namespace onnxruntime -#endif diff --git a/onnxruntime/core/framework/data_types.cc b/onnxruntime/core/framework/data_types.cc index a7f4804397f90..6c4aec417a033 100644 --- a/onnxruntime/core/framework/data_types.cc +++ b/onnxruntime/core/framework/data_types.cc @@ -11,7 +11,6 @@ #include "core/framework/tensor.h" #include "core/framework/TensorSeq.h" #include "core/graph/onnx_protobuf.h" -#include "core/util/math.h" #ifdef __GNUC__ #pragma GCC diagnostic push @@ -27,18 +26,34 @@ using namespace ONNX_NAMESPACE; namespace onnxruntime { -MLFloat16::MLFloat16(float f) : val{math::floatToHalf(f)} {} - -float MLFloat16::ToFloat() const { - return math::halfToFloat(val); -} - // Return the MLDataType used for a generic Tensor template <> MLDataType DataTypeImpl::GetType() { return TensorTypeBase::Type(); } +const MLFloat16 MLFloat16::NaN(MLFloat16::FromBits(MLFloat16::kPositiveQNaNBits)); +const MLFloat16 MLFloat16::NegativeNaN(MLFloat16::FromBits(MLFloat16::kNegativeQNaNBits)); +const MLFloat16 MLFloat16::Infinity(MLFloat16::FromBits(MLFloat16::kPositiveInfinityBits)); +const MLFloat16 MLFloat16::NegativeInfinity(MLFloat16::FromBits(MLFloat16::kNegativeInfinityBits)); +const MLFloat16 MLFloat16::Epsilon(MLFloat16::FromBits(MLFloat16::kEpsilonBits)); +const MLFloat16 MLFloat16::MinValue(MLFloat16::FromBits(MLFloat16::kMinValueBits)); +const MLFloat16 MLFloat16::MaxValue(MLFloat16::FromBits(MLFloat16::kMaxValueBits)); +const MLFloat16 MLFloat16::Zero(MLFloat16::FromBits(0)); +const MLFloat16 MLFloat16::One(MLFloat16::FromBits(MLFloat16::kOneBits)); +const MLFloat16 MLFloat16::MinusOne(MLFloat16::FromBits(MLFloat16::kMinusOneBits)); + +const BFloat16 BFloat16::NaN(BFloat16::FromBits(BFloat16::kPositiveQNaNBits)); +const BFloat16 BFloat16::NegativeNaN(BFloat16::FromBits(BFloat16::kNegativeQNaNBits)); +const BFloat16 BFloat16::Infinity(BFloat16::FromBits(BFloat16::kPositiveInfinityBits)); +const BFloat16 BFloat16::NegativeInfinity(BFloat16::FromBits(BFloat16::kNegativeInfinityBits)); +const BFloat16 BFloat16::Epsilon(BFloat16::FromBits(BFloat16::kEpsilonBits)); +const BFloat16 BFloat16::MinValue(BFloat16::FromBits(BFloat16::kMinValueBits)); +const BFloat16 BFloat16::MaxValue(BFloat16::FromBits(BFloat16::kMaxValueBits)); +const BFloat16 BFloat16::Zero(BFloat16::FromBits(0)); +const BFloat16 BFloat16::One(BFloat16::FromBits(BFloat16::kOneBits)); +const BFloat16 BFloat16::MinusOne(BFloat16::FromBits(BFloat16::kMinusOneBits)); + } // namespace onnxruntime // This conflicts with the above GetType<>() specialization @@ -618,6 +633,13 @@ ORT_REGISTER_TENSOR_TYPE(uint64_t); ORT_REGISTER_TENSOR_TYPE(MLFloat16); ORT_REGISTER_TENSOR_TYPE(BFloat16); +#if !defined(DISABLE_FLOAT8_TYPES) +ORT_REGISTER_TENSOR_TYPE(Float8E4M3FN); +ORT_REGISTER_TENSOR_TYPE(Float8E4M3FNUZ); +ORT_REGISTER_TENSOR_TYPE(Float8E5M2); +ORT_REGISTER_TENSOR_TYPE(Float8E5M2FNUZ); +#endif + #if !defined(DISABLE_SPARSE_TENSORS) ORT_REGISTER_SPARSE_TENSOR_TYPE(int32_t); ORT_REGISTER_SPARSE_TENSOR_TYPE(float); @@ -633,6 +655,14 @@ ORT_REGISTER_SPARSE_TENSOR_TYPE(uint32_t); ORT_REGISTER_SPARSE_TENSOR_TYPE(uint64_t); ORT_REGISTER_SPARSE_TENSOR_TYPE(MLFloat16); ORT_REGISTER_SPARSE_TENSOR_TYPE(BFloat16); + +#if !defined(DISABLE_FLOAT8_TYPES) +ORT_REGISTER_SPARSE_TENSOR_TYPE(Float8E4M3FN); +ORT_REGISTER_SPARSE_TENSOR_TYPE(Float8E4M3FNUZ); +ORT_REGISTER_SPARSE_TENSOR_TYPE(Float8E5M2); +ORT_REGISTER_SPARSE_TENSOR_TYPE(Float8E5M2FNUZ); +#endif + #endif #if !defined(DISABLE_ML_OPS) @@ -661,11 +691,44 @@ ORT_REGISTER_SEQ_TENSOR_TYPE(std::string); ORT_REGISTER_SEQ_TENSOR_TYPE(MLFloat16); ORT_REGISTER_SEQ_TENSOR_TYPE(BFloat16); +#if !defined(DISABLE_FLOAT8_TYPES) + +ORT_REGISTER_SEQ_TENSOR_TYPE(Float8E4M3FN); +ORT_REGISTER_SEQ_TENSOR_TYPE(Float8E4M3FNUZ); +ORT_REGISTER_SEQ_TENSOR_TYPE(Float8E5M2); +ORT_REGISTER_SEQ_TENSOR_TYPE(Float8E5M2FNUZ); + +#endif + #if !defined(DISABLE_ML_OPS) ORT_REGISTER_SEQ(VectorMapStringToFloat); ORT_REGISTER_SEQ(VectorMapInt64ToFloat); #endif +#if !defined(DISABLE_FLOAT8_TYPES) + +#define ORT_REGISTER_OPTIONAL_ORT_TYPE(ORT_TYPE) \ + ORT_REGISTER_OPTIONAL_TYPE(ORT_TYPE, int32_t); \ + ORT_REGISTER_OPTIONAL_TYPE(ORT_TYPE, float); \ + ORT_REGISTER_OPTIONAL_TYPE(ORT_TYPE, bool); \ + ORT_REGISTER_OPTIONAL_TYPE(ORT_TYPE, std::string); \ + ORT_REGISTER_OPTIONAL_TYPE(ORT_TYPE, int8_t); \ + ORT_REGISTER_OPTIONAL_TYPE(ORT_TYPE, uint8_t); \ + ORT_REGISTER_OPTIONAL_TYPE(ORT_TYPE, uint16_t); \ + ORT_REGISTER_OPTIONAL_TYPE(ORT_TYPE, int16_t); \ + ORT_REGISTER_OPTIONAL_TYPE(ORT_TYPE, int64_t); \ + ORT_REGISTER_OPTIONAL_TYPE(ORT_TYPE, double); \ + ORT_REGISTER_OPTIONAL_TYPE(ORT_TYPE, uint32_t); \ + ORT_REGISTER_OPTIONAL_TYPE(ORT_TYPE, uint64_t); \ + ORT_REGISTER_OPTIONAL_TYPE(ORT_TYPE, MLFloat16); \ + ORT_REGISTER_OPTIONAL_TYPE(ORT_TYPE, BFloat16); \ + ORT_REGISTER_OPTIONAL_TYPE(ORT_TYPE, Float8E4M3FN); \ + ORT_REGISTER_OPTIONAL_TYPE(ORT_TYPE, Float8E4M3FNUZ); \ + ORT_REGISTER_OPTIONAL_TYPE(ORT_TYPE, Float8E5M2); \ + ORT_REGISTER_OPTIONAL_TYPE(ORT_TYPE, Float8E5M2FNUZ); + +#else + #define ORT_REGISTER_OPTIONAL_ORT_TYPE(ORT_TYPE) \ ORT_REGISTER_OPTIONAL_TYPE(ORT_TYPE, int32_t); \ ORT_REGISTER_OPTIONAL_TYPE(ORT_TYPE, float); \ @@ -682,6 +745,8 @@ ORT_REGISTER_SEQ(VectorMapInt64ToFloat); ORT_REGISTER_OPTIONAL_TYPE(ORT_TYPE, MLFloat16); \ ORT_REGISTER_OPTIONAL_TYPE(ORT_TYPE, BFloat16); +#endif + ORT_REGISTER_OPTIONAL_ORT_TYPE(Tensor) ORT_REGISTER_OPTIONAL_ORT_TYPE(TensorSeq) @@ -737,6 +802,12 @@ void RegisterAllProtos(const std::function& reg_fn) { REGISTER_TENSOR_PROTO(uint64_t, reg_fn); REGISTER_TENSOR_PROTO(MLFloat16, reg_fn); REGISTER_TENSOR_PROTO(BFloat16, reg_fn); +#if !defined(DISABLE_FLOAT8_TYPES) + REGISTER_TENSOR_PROTO(Float8E4M3FN, reg_fn); + REGISTER_TENSOR_PROTO(Float8E4M3FNUZ, reg_fn); + REGISTER_TENSOR_PROTO(Float8E5M2, reg_fn); + REGISTER_TENSOR_PROTO(Float8E5M2FNUZ, reg_fn); +#endif #if !defined(DISABLE_SPARSE_TENSORS) REGISTER_SPARSE_TENSOR_PROTO(int32_t, reg_fn); @@ -753,6 +824,12 @@ void RegisterAllProtos(const std::function& reg_fn) { REGISTER_SPARSE_TENSOR_PROTO(uint64_t, reg_fn); REGISTER_SPARSE_TENSOR_PROTO(MLFloat16, reg_fn); REGISTER_SPARSE_TENSOR_PROTO(BFloat16, reg_fn); +#if !defined(DISABLE_FLOAT8_TYPES) + REGISTER_SPARSE_TENSOR_PROTO(Float8E4M3FN, reg_fn); + REGISTER_SPARSE_TENSOR_PROTO(Float8E4M3FNUZ, reg_fn); + REGISTER_SPARSE_TENSOR_PROTO(Float8E5M2, reg_fn); + REGISTER_SPARSE_TENSOR_PROTO(Float8E5M2FNUZ, reg_fn); +#endif #endif #if !defined(DISABLE_ML_OPS) @@ -781,12 +858,46 @@ void RegisterAllProtos(const std::function& reg_fn) { REGISTER_SEQ_TENSOR_PROTO(MLFloat16, reg_fn); REGISTER_SEQ_TENSOR_PROTO(BFloat16, reg_fn); +#if !defined(DISABLE_FLOAT8_TYPES) + + REGISTER_SEQ_TENSOR_PROTO(Float8E4M3FN, reg_fn); + REGISTER_SEQ_TENSOR_PROTO(Float8E4M3FNUZ, reg_fn); + REGISTER_SEQ_TENSOR_PROTO(Float8E5M2, reg_fn); + REGISTER_SEQ_TENSOR_PROTO(Float8E5M2FNUZ, reg_fn); + +#endif + #if !defined(DISABLE_ML_OPS) REGISTER_ONNX_PROTO(VectorMapStringToFloat, reg_fn); REGISTER_ONNX_PROTO(VectorMapInt64ToFloat, reg_fn); #endif #if !defined(DISABLE_OPTIONAL_TYPE) + +#if !defined(DISABLE_FLOAT8_TYPES) + +#define REGISTER_OPTIONAL_PROTO_ORT_TYPE(ORT_TYPE, reg_fn) \ + REGISTER_OPTIONAL_PROTO(ORT_TYPE, int32_t, reg_fn); \ + REGISTER_OPTIONAL_PROTO(ORT_TYPE, float, reg_fn); \ + REGISTER_OPTIONAL_PROTO(ORT_TYPE, bool, reg_fn); \ + REGISTER_OPTIONAL_PROTO(ORT_TYPE, std::string, reg_fn); \ + REGISTER_OPTIONAL_PROTO(ORT_TYPE, int8_t, reg_fn); \ + REGISTER_OPTIONAL_PROTO(ORT_TYPE, uint8_t, reg_fn); \ + REGISTER_OPTIONAL_PROTO(ORT_TYPE, uint16_t, reg_fn); \ + REGISTER_OPTIONAL_PROTO(ORT_TYPE, int16_t, reg_fn); \ + REGISTER_OPTIONAL_PROTO(ORT_TYPE, int64_t, reg_fn); \ + REGISTER_OPTIONAL_PROTO(ORT_TYPE, double, reg_fn); \ + REGISTER_OPTIONAL_PROTO(ORT_TYPE, uint32_t, reg_fn); \ + REGISTER_OPTIONAL_PROTO(ORT_TYPE, uint64_t, reg_fn); \ + REGISTER_OPTIONAL_PROTO(ORT_TYPE, MLFloat16, reg_fn); \ + REGISTER_OPTIONAL_PROTO(ORT_TYPE, BFloat16, reg_fn); \ + REGISTER_OPTIONAL_PROTO(ORT_TYPE, Float8E4M3FN, reg_fn); \ + REGISTER_OPTIONAL_PROTO(ORT_TYPE, Float8E4M3FNUZ, reg_fn); \ + REGISTER_OPTIONAL_PROTO(ORT_TYPE, Float8E5M2, reg_fn); \ + REGISTER_OPTIONAL_PROTO(ORT_TYPE, Float8E5M2FNUZ, reg_fn); + +#else + #define REGISTER_OPTIONAL_PROTO_ORT_TYPE(ORT_TYPE, reg_fn) \ REGISTER_OPTIONAL_PROTO(ORT_TYPE, int32_t, reg_fn); \ REGISTER_OPTIONAL_PROTO(ORT_TYPE, float, reg_fn); \ @@ -803,6 +914,8 @@ void RegisterAllProtos(const std::function& reg_fn) { REGISTER_OPTIONAL_PROTO(ORT_TYPE, MLFloat16, reg_fn); \ REGISTER_OPTIONAL_PROTO(ORT_TYPE, BFloat16, reg_fn); +#endif + REGISTER_OPTIONAL_PROTO_ORT_TYPE(Tensor, reg_fn); REGISTER_OPTIONAL_PROTO_ORT_TYPE(TensorSeq, reg_fn); #endif @@ -852,6 +965,14 @@ const char* DataTypeImpl::ToString(MLDataType type) { return "float16"; case TensorProto_DataType_BFLOAT16: return "bfloat16"; + case TensorProto_DataType_FLOAT8E4M3FN: + return "Float8E4M3FN"; + case TensorProto_DataType_FLOAT8E4M3FNUZ: + return "Float8E4M3FNUZ"; + case TensorProto_DataType_FLOAT8E5M2: + return "Float8E5M2"; + case TensorProto_DataType_FLOAT8E5M2FNUZ: + return "Float8E5M2FNUZ"; default: break; } @@ -907,6 +1028,20 @@ const TensorTypeBase* DataTypeImpl::TensorTypeFromONNXEnum(int type) { return DataTypeImpl::GetTensorType()->AsTensorType(); case TensorProto_DataType_BFLOAT16: return DataTypeImpl::GetTensorType()->AsTensorType(); + +#if !defined(DISABLE_FLOAT8_TYPES) + + case TensorProto_DataType_FLOAT8E4M3FN: + return DataTypeImpl::GetTensorType()->AsTensorType(); + case TensorProto_DataType_FLOAT8E4M3FNUZ: + return DataTypeImpl::GetTensorType()->AsTensorType(); + case TensorProto_DataType_FLOAT8E5M2: + return DataTypeImpl::GetTensorType()->AsTensorType(); + case TensorProto_DataType_FLOAT8E5M2FNUZ: + return DataTypeImpl::GetTensorType()->AsTensorType(); + +#endif + default: ORT_NOT_IMPLEMENTED("tensor type ", type, " is not supported"); } @@ -942,6 +1077,20 @@ const SequenceTensorTypeBase* DataTypeImpl::SequenceTensorTypeFromONNXEnum(int t return DataTypeImpl::GetSequenceTensorType()->AsSequenceTensorType(); case TensorProto_DataType_BFLOAT16: return DataTypeImpl::GetSequenceTensorType()->AsSequenceTensorType(); + +#if !defined(DISABLE_FLOAT8_TYPES) + + case TensorProto_DataType_FLOAT8E4M3FN: + return DataTypeImpl::GetSequenceTensorType()->AsSequenceTensorType(); + case TensorProto_DataType_FLOAT8E4M3FNUZ: + return DataTypeImpl::GetSequenceTensorType()->AsSequenceTensorType(); + case TensorProto_DataType_FLOAT8E5M2: + return DataTypeImpl::GetSequenceTensorType()->AsSequenceTensorType(); + case TensorProto_DataType_FLOAT8E5M2FNUZ: + return DataTypeImpl::GetSequenceTensorType()->AsSequenceTensorType(); + +#endif + default: ORT_NOT_IMPLEMENTED("sequence tensor type ", type, " is not supported"); } @@ -978,6 +1127,20 @@ const SparseTensorTypeBase* DataTypeImpl::SparseTensorTypeFromONNXEnum(int type) return DataTypeImpl::GetSparseTensorType()->AsSparseTensorType(); case TensorProto_DataType_BFLOAT16: return DataTypeImpl::GetSparseTensorType()->AsSparseTensorType(); + +#if !defined(DISABLE_FLOAT8_TYPES) + + case TensorProto_DataType_FLOAT8E4M3FN: + return DataTypeImpl::GetSparseTensorType()->AsSparseTensorType(); + case TensorProto_DataType_FLOAT8E4M3FNUZ: + return DataTypeImpl::GetSparseTensorType()->AsSparseTensorType(); + case TensorProto_DataType_FLOAT8E5M2: + return DataTypeImpl::GetSparseTensorType()->AsSparseTensorType(); + case TensorProto_DataType_FLOAT8E5M2FNUZ: + return DataTypeImpl::GetSparseTensorType()->AsSparseTensorType(); + +#endif + default: ORT_NOT_IMPLEMENTED("sparse tensor type ", type, " is not supported"); } @@ -1012,6 +1175,15 @@ ORT_REGISTER_PRIM_TYPE(uint64_t); ORT_REGISTER_PRIM_TYPE(MLFloat16); ORT_REGISTER_PRIM_TYPE(BFloat16); +#if !defined(DISABLE_FLOAT8_TYPES) + +ORT_REGISTER_PRIM_TYPE(Float8E4M3FN); +ORT_REGISTER_PRIM_TYPE(Float8E4M3FNUZ); +ORT_REGISTER_PRIM_TYPE(Float8E5M2); +ORT_REGISTER_PRIM_TYPE(Float8E5M2FNUZ); + +#endif + namespace { template struct GetTensorTypesImpl { @@ -1063,18 +1235,6 @@ std::vector GetSequenceTensorTypesFromTypeList() { } // namespace -const std::vector& DataTypeImpl::AllFixedSizeTensorExceptHalfTypes() { - static std::vector all_fixed_size_tensor_types = - GetTensorTypesFromTypeList(); - return all_fixed_size_tensor_types; -} - -const std::vector& DataTypeImpl::AllIEEEFloatTensorExceptHalfTypes() { - static std::vector all_IEEE_float_tensor_except_half_types = - GetTensorTypesFromTypeList(); - return all_IEEE_float_tensor_except_half_types; -} - const std::vector& DataTypeImpl::AllIEEEFloatTensorTypes() { static std::vector all_IEEE_float_tensor_types = GetTensorTypesFromTypeList(); @@ -1082,26 +1242,66 @@ const std::vector& DataTypeImpl::AllIEEEFloatTensorTypes() { } const std::vector& DataTypeImpl::AllFixedSizeTensorTypes() { - static std::vector all_fixed_size_tensor_types = - GetTensorTypesFromTypeList(); - return all_fixed_size_tensor_types; + return AllFixedSizeTensorTypesIRv4(); +} + +const std::vector& DataTypeImpl::AllFixedSizeTensorTypesIRv4() { + static std::vector all_fixed_size_tensor_types_ir4 = + GetTensorTypesFromTypeList(); + return all_fixed_size_tensor_types_ir4; +} + +const std::vector& DataTypeImpl::AllFixedSizeTensorTypesIRv9() { + static std::vector all_fixed_size_tensor_types_ir9 = + GetTensorTypesFromTypeList(); + return all_fixed_size_tensor_types_ir9; } const std::vector& DataTypeImpl::AllTensorTypes() { + return AllTensorTypesIRv4(); +} + +const std::vector& DataTypeImpl::AllTensorTypesIRv4() { + static std::vector all_tensor_types = + GetTensorTypesFromTypeList(); + return all_tensor_types; +} + +const std::vector& DataTypeImpl::AllTensorTypesIRv9() { static std::vector all_tensor_types = - GetTensorTypesFromTypeList(); + GetTensorTypesFromTypeList(); return all_tensor_types; } const std::vector& DataTypeImpl::AllFixedSizeSequenceTensorTypes() { + return AllFixedSizeSequenceTensorTypesIRv4(); +} + +const std::vector& DataTypeImpl::AllFixedSizeSequenceTensorTypesIRv4() { static std::vector all_fixed_size_sequence_tensor_types = - GetSequenceTensorTypesFromTypeList(); + GetSequenceTensorTypesFromTypeList(); + return all_fixed_size_sequence_tensor_types; +} + +const std::vector& DataTypeImpl::AllFixedSizeSequenceTensorTypesIRv9() { + static std::vector all_fixed_size_sequence_tensor_types = + GetSequenceTensorTypesFromTypeList(); return all_fixed_size_sequence_tensor_types; } const std::vector& DataTypeImpl::AllSequenceTensorTypes() { + return AllSequenceTensorTypesIRv4(); +} + +const std::vector& DataTypeImpl::AllSequenceTensorTypesIRv4() { + static std::vector all_sequence_tensor_types = + GetSequenceTensorTypesFromTypeList(); + return all_sequence_tensor_types; +} + +const std::vector& DataTypeImpl::AllSequenceTensorTypesIRv9() { static std::vector all_sequence_tensor_types = - GetSequenceTensorTypesFromTypeList(); + GetSequenceTensorTypesFromTypeList(); return all_sequence_tensor_types; } @@ -1112,10 +1312,26 @@ const std::vector& DataTypeImpl::AllNumericTensorTypes() { } const std::vector& DataTypeImpl::AllFixedSizeTensorAndSequenceTensorTypes() { + return AllFixedSizeTensorAndSequenceTensorTypesIRv4(); +} + +const std::vector& DataTypeImpl::AllFixedSizeTensorAndSequenceTensorTypesIRv4() { + static std::vector all_fixed_size_tensor_and_sequence_tensor_types = + []() { + auto temp = AllFixedSizeTensorTypesIRv4(); + const auto& seq = AllFixedSizeSequenceTensorTypesIRv4(); + temp.insert(temp.end(), seq.begin(), seq.end()); + return temp; + }(); + + return all_fixed_size_tensor_and_sequence_tensor_types; +} + +const std::vector& DataTypeImpl::AllFixedSizeTensorAndSequenceTensorTypesIRv9() { static std::vector all_fixed_size_tensor_and_sequence_tensor_types = []() { - auto temp = AllFixedSizeTensorTypes(); - const auto& seq = AllFixedSizeSequenceTensorTypes(); + auto temp = AllFixedSizeTensorTypesIRv9(); + const auto& seq = AllFixedSizeSequenceTensorTypesIRv9(); temp.insert(temp.end(), seq.begin(), seq.end()); return temp; }(); @@ -1124,24 +1340,56 @@ const std::vector& DataTypeImpl::AllFixedSizeTensorAndSequenceTensor } const std::vector& DataTypeImpl::AllTensorAndSequenceTensorTypes() { - static std::vector all_tensor_and_sequence_types = + return AllTensorAndSequenceTensorTypesIRv4(); +} + +const std::vector& DataTypeImpl::AllTensorAndSequenceTensorTypesIRv4() { + static std::vector all_tensor_and_sequence_types_with_float8 = []() { - auto temp = AllTensorTypes(); - const auto& seq = AllSequenceTensorTypes(); + auto temp = AllTensorTypesIRv4(); + const auto& seq = AllSequenceTensorTypesIRv4(); temp.insert(temp.end(), seq.begin(), seq.end()); return temp; }(); + return all_tensor_and_sequence_types_with_float8; +} - return all_tensor_and_sequence_types; +const std::vector& DataTypeImpl::AllTensorAndSequenceTensorTypesIRv9() { + static std::vector all_tensor_and_sequence_types_with_float8 = + []() { + auto temp = AllTensorTypesIRv9(); + const auto& seq = AllSequenceTensorTypesIRv9(); + temp.insert(temp.end(), seq.begin(), seq.end()); + return temp; + }(); + return all_tensor_and_sequence_types_with_float8; } const std::vector& DataTypeImpl::AllOptionalAndTensorAndSequenceTensorTypes() { + return AllOptionalAndTensorAndSequenceTensorTypesIRv4(); +} + +const std::vector& DataTypeImpl::AllOptionalAndTensorAndSequenceTensorTypesIRv4() { + static std::vector all_optional_and_tensor_and_sequence_types = + []() { + auto temp = AllOptionalTypesIRv4(); + const auto tensor = AllTensorTypesIRv4(); + temp.insert(temp.end(), tensor.begin(), tensor.end()); + const auto& seq = AllSequenceTensorTypesIRv4(); + temp.insert(temp.end(), seq.begin(), seq.end()); + return temp; + }(); + + return all_optional_and_tensor_and_sequence_types; +} + +const std::vector& DataTypeImpl::AllOptionalAndTensorAndSequenceTensorTypesIRv9() { static std::vector all_optional_and_tensor_and_sequence_types = []() { - auto temp = AllOptionalTypes(); - const auto tensor = AllTensorTypes(); + auto temp = AllOptionalTypesIRv9(); + const auto tensor = AllTensorTypesIRv9(); temp.insert(temp.end(), tensor.begin(), tensor.end()); - const auto& seq = AllSequenceTensorTypes(); + const auto& seq = AllSequenceTensorTypesIRv9(); temp.insert(temp.end(), seq.begin(), seq.end()); return temp; }(); @@ -1150,10 +1398,26 @@ const std::vector& DataTypeImpl::AllOptionalAndTensorAndSequenceTens } const std::vector& DataTypeImpl::AllOptionalTypes() { + return AllOptionalTypesIRv4(); +} + +const std::vector& DataTypeImpl::AllOptionalTypesIRv4() { + static std::vector all_optional_types = + []() { + auto temp = GetOptionalTensorTypesFromTypeList(); + const auto& seq = GetOptionalSequenceTensorTypesFromTypeList(); + temp.insert(temp.end(), seq.begin(), seq.end()); + return temp; + }(); + + return all_optional_types; +} + +const std::vector& DataTypeImpl::AllOptionalTypesIRv9() { static std::vector all_optional_types = []() { - auto temp = GetOptionalTensorTypesFromTypeList(); - const auto& seq = GetOptionalSequenceTensorTypesFromTypeList(); + auto temp = GetOptionalTensorTypesFromTypeList(); + const auto& seq = GetOptionalSequenceTensorTypesFromTypeList(); temp.insert(temp.end(), seq.begin(), seq.end()); return temp; }(); @@ -1162,10 +1426,28 @@ const std::vector& DataTypeImpl::AllOptionalTypes() { } const std::vector& DataTypeImpl::AllTensorAndSequenceTensorAndOptionalTypes() { + return AllTensorAndSequenceTensorAndOptionalTypesIRv4(); +} + +const std::vector& DataTypeImpl::AllTensorAndSequenceTensorAndOptionalTypesIRv4() { + static std::vector all_tensor_and_sequence_types_and_optional_types = + []() { + auto temp = AllTensorTypesIRv4(); + const auto& seq = AllSequenceTensorTypesIRv4(); + const auto& opt = AllOptionalTypes(); + temp.insert(temp.end(), seq.begin(), seq.end()); + temp.insert(temp.end(), opt.begin(), opt.end()); + return temp; + }(); + + return all_tensor_and_sequence_types_and_optional_types; +} + +const std::vector& DataTypeImpl::AllTensorAndSequenceTensorAndOptionalTypesIRv9() { static std::vector all_tensor_and_sequence_types_and_optional_types = []() { - auto temp = AllTensorTypes(); - const auto& seq = AllSequenceTensorTypes(); + auto temp = AllTensorTypesIRv9(); + const auto& seq = AllSequenceTensorTypesIRv9(); const auto& opt = AllOptionalTypes(); temp.insert(temp.end(), seq.begin(), seq.end()); temp.insert(temp.end(), opt.begin(), opt.end()); diff --git a/onnxruntime/core/framework/debug_node_inputs_outputs_utils.cc b/onnxruntime/core/framework/debug_node_inputs_outputs_utils.cc index ec9f4888c7c52..ec50bb7d6a5cb 100644 --- a/onnxruntime/core/framework/debug_node_inputs_outputs_utils.cc +++ b/onnxruntime/core/framework/debug_node_inputs_outputs_utils.cc @@ -5,6 +5,7 @@ #include "core/framework/debug_node_inputs_outputs_utils.h" #include "core/framework/print_tensor_utils.h" +#include "core/framework/print_tensor_statistics_utils.h" #include #include #include @@ -60,6 +61,9 @@ bool FilterNode(const NodeDumpOptions& dump_options, const Node& node) { template void DumpTensorToStdOut(const Tensor& tensor, const NodeDumpOptions& dump_options) { onnxruntime::utils::PrintCpuTensor(tensor, dump_options.snippet_threshold, dump_options.snippet_edge_items); + if (dump_options.dump_flags & NodeDumpOptions::DumpFlags::StatisticsData) { + onnxruntime::utils::PrintCpuTensorStats(tensor); + } } PathString MakeTensorFileName(const std::string& tensor_name, const NodeDumpOptions& dump_options) { @@ -335,7 +339,7 @@ void DumpTensor( if (tensor_location.device.Type() == OrtDevice::GPU) { const auto& execution_providers = session_state.GetExecutionProviders(); const auto* cpu_execution_provider = execution_providers.Get(onnxruntime::kCpuExecutionProvider); - auto cpu_allocator = cpu_execution_provider->GetAllocator(OrtMemTypeDefault); + auto cpu_allocator = session_state.GetAllocator(cpu_execution_provider->GetOrtDeviceByMemType(OrtMemTypeDefault)); Tensor cpu_tensor{data_type, tensor.Shape(), cpu_allocator}; const auto& data_transfer_mgr = session_state.GetDataTransferMgr(); auto status = data_transfer_mgr.CopyTensor(tensor, cpu_tensor); @@ -376,6 +380,9 @@ const NodeDumpOptions& NodeDumpOptionsFromEnvironmentVariables() { if (ParseEnvironmentVariableWithDefault(env_vars::kDumpNodePlacement, true)) { opts.dump_flags |= NodeDumpOptions::DumpFlags::NodePlacement; } + if (ParseEnvironmentVariableWithDefault(env_vars::kDumpStatisticsData, false)) { + opts.dump_flags |= NodeDumpOptions::DumpFlags::StatisticsData; + } opts.filter.name_pattern = Env::Default().GetEnvironmentVar(env_vars::kNameFilter); opts.filter.op_type_pattern = Env::Default().GetEnvironmentVar(env_vars::kOpTypeFilter); diff --git a/onnxruntime/core/framework/debug_node_inputs_outputs_utils.h b/onnxruntime/core/framework/debug_node_inputs_outputs_utils.h index eb93621aebbcd..bde005fc204c8 100644 --- a/onnxruntime/core/framework/debug_node_inputs_outputs_utils.h +++ b/onnxruntime/core/framework/debug_node_inputs_outputs_utils.h @@ -36,6 +36,9 @@ constexpr const char* kDumpNodePlacement = "ORT_DEBUG_NODE_IO_DUMP_NODE_PLACEMEN constexpr const char* kDumpInputData = "ORT_DEBUG_NODE_IO_DUMP_INPUT_DATA"; // set to non-zero to dump node output data constexpr const char* kDumpOutputData = "ORT_DEBUG_NODE_IO_DUMP_OUTPUT_DATA"; +// Output statistics data like min, max, count of NaN, count of infinity etc. +constexpr const char* kDumpStatisticsData = "ORT_DEBUG_NODE_IO_DUMP_STATISTICS_DATA"; + // specify a node name filter to limit the nodes that are dumped // see NodeDumpOptions::FilterOptions constexpr const char* kNameFilter = "ORT_DEBUG_NODE_IO_NAME_FILTER"; @@ -70,7 +73,8 @@ struct NodeDumpOptions { InputData = 1 << 1, OutputData = 1 << 2, NodePlacement = 1 << 3, - AllData = Shape | InputData | OutputData | NodePlacement, + StatisticsData = 1 << 4, + AllData = Shape | InputData | OutputData | NodePlacement | StatisticsData, }; // specifies the information to dump per node diff --git a/onnxruntime/core/framework/device_stream_collection.cc b/onnxruntime/core/framework/device_stream_collection.cc index 669fb0bc79cb0..13948289e1c37 100644 --- a/onnxruntime/core/framework/device_stream_collection.cc +++ b/onnxruntime/core/framework/device_stream_collection.cc @@ -21,15 +21,9 @@ struct DummyStream : Stream { class DeviceStreamCollectionImpl { public: - DeviceStreamCollectionImpl(size_t num_streams, const SessionState& sess_state) : num_streams_(num_streams), root_stream_device_(OrtDevice()) { + DeviceStreamCollectionImpl(size_t num_streams, const AllocatorMap& allocators, bool is_main_graph) : num_streams_(num_streams), allocators_(allocators), is_main_graph_(is_main_graph) { device_streams_.resize(num_streams, nullptr); owned_streams_.reserve(num_streams); - auto& providers = sess_state.GetExecutionProviders(); - eps_.reserve(providers.NumProviders()); - for (auto& ep : providers) { - eps_.push_back(ep); - } - is_main_graph_ = sess_state.GetGraphViewer().ParentNode() == nullptr; root_stream_ = std::make_unique(nullptr, root_stream_device_); } @@ -38,16 +32,13 @@ class DeviceStreamCollectionImpl { void ReleaseSingleStreamBuffers(Stream* stream) { if (!stream) return; - for (auto& ep : eps_) { - auto& allocators = ep->GetAllocators(); - for (auto& alloc : allocators) { - if (alloc->Info().device == stream->GetDevice() && - alloc->Info().alloc_type == OrtArenaAllocator) { - auto* arena_alloc = static_cast(alloc.get()); - auto* stream_aware_alloc = StreamAwareArena::FromBFCArena(*arena_alloc); - if (stream_aware_alloc) { - stream_aware_alloc->ReleaseStreamBuffers(stream); - } + for (auto it : allocators_) { + if (it.second->Info().device == stream->GetDevice() && + it.second->Info().alloc_type == OrtArenaAllocator) { + auto* arena_alloc = static_cast(it.second.get()); + auto* stream_aware_alloc = StreamAwareArena::FromBFCArena(*arena_alloc); + if (stream_aware_alloc) { + stream_aware_alloc->ReleaseStreamBuffers(stream); } } } @@ -99,9 +90,7 @@ class DeviceStreamCollectionImpl { size_t num_streams_; std::vector device_streams_; InlinedVector> owned_streams_; - // due to training's partial execution, the device streams collection may need to be hold - // with a different lifetime of session state, we need to hold the reference of EPs. - InlinedVector> eps_; + const AllocatorMap& allocators_; bool is_main_graph_ = false; // This is used in ExecutionFrame when memory pattern is enabled, to allocate the peak size memory // labelled this stream in the current thread, instead of the default stream which will be used in all the threads (thus caused thread safe issue) @@ -110,8 +99,8 @@ class DeviceStreamCollectionImpl { void ReleaseSingleStreamBuffers(); }; -DeviceStreamCollection::DeviceStreamCollection(size_t num_streams, - const SessionState& sess_state) : impl_(std::make_unique(num_streams, sess_state)) {} +DeviceStreamCollection::DeviceStreamCollection(size_t num_streams, const AllocatorMap& allocators, bool is_main_graph) + : impl_(std::make_unique(num_streams, allocators, is_main_graph)) {} DeviceStreamCollection::~DeviceStreamCollection() {} @@ -139,5 +128,16 @@ Stream* DeviceStreamCollection::GetRootStream() const { return impl_->GetRootStream(); } +DeviceStreamCollectionHolder::DeviceStreamCollectionHolder(const SessionState* session_state) + : session_state_(session_state), + p_(session_state->AcquireDeviceStreamCollection()) { +} + +DeviceStreamCollectionHolder::~DeviceStreamCollectionHolder() { + if (p_) { + session_state_->RecycleDeviceStreamCollection(std::move(p_)); + } +} + } // namespace onnxruntime #endif diff --git a/onnxruntime/core/framework/device_stream_collection.h b/onnxruntime/core/framework/device_stream_collection.h index 8a1ed8a41ef89..c76c7c731571c 100644 --- a/onnxruntime/core/framework/device_stream_collection.h +++ b/onnxruntime/core/framework/device_stream_collection.h @@ -14,7 +14,7 @@ class DeviceStreamCollectionImpl; // this collection may be cached and reused for future iterations. class DeviceStreamCollection { public: - DeviceStreamCollection(size_t num_streams, const SessionState& sess_state); + DeviceStreamCollection(size_t num_streams, const AllocatorMap& allocators, bool is_main_graph); ~DeviceStreamCollection(); // Add the device stream instance to given index. // and set the current collection as the owner of the device stream. @@ -45,5 +45,17 @@ class DeviceStreamCollection { private: std::unique_ptr impl_; }; + +struct DeviceStreamCollectionHolder { + DeviceStreamCollectionHolder(const SessionState* session_state); + DeviceStreamCollectionHolder() = delete; + DeviceStreamCollectionHolder(const DeviceStreamCollectionHolder&) = delete; + + ~DeviceStreamCollectionHolder(); + + const SessionState* session_state_; + std::unique_ptr p_; +}; + } // namespace onnxruntime #endif diff --git a/onnxruntime/core/framework/element_type_lists.h b/onnxruntime/core/framework/element_type_lists.h index 19b5e40bb81f6..3d956ec26d22e 100644 --- a/onnxruntime/core/framework/element_type_lists.h +++ b/onnxruntime/core/framework/element_type_lists.h @@ -9,6 +9,7 @@ #include "boost/mp11.hpp" #include "core/common/type_list.h" +#include "core/framework/float8.h" #include "core/framework/float16.h" namespace onnxruntime { @@ -17,7 +18,7 @@ namespace onnxruntime { // Element type refers to the element type of a Tensor, Sequence, etc. namespace element_type_lists { -using AllFixedSizeExceptHalf = +using AllFixedSizeExceptHalfIRv4 = TypeList< float, double, @@ -31,7 +32,9 @@ using AllFixedSizeExceptHalf = uint8_t, bool>; -using AllFixedSize = +using AllFixedSizeExceptHalf = AllFixedSizeExceptHalfIRv4; + +using AllFixedSizeIRv4 = TypeList< float, double, @@ -47,15 +50,48 @@ using AllFixedSize = BFloat16, bool>; -using All = +#if !defined(DISABLE_FLOAT8_TYPES) +using AllFixedSizeIRv9 = boost::mp11::mp_push_back< - AllFixedSize, + AllFixedSizeIRv4, + Float8E4M3FN, + Float8E4M3FNUZ, + Float8E5M2, + Float8E5M2FNUZ>; +#else +using AllFixedSizeIRv9 = AllFixedSizeIRv4; +#endif + +using AllFixedSize = AllFixedSizeIRv4; + +using AllIRv4 = + boost::mp11::mp_push_back< + AllFixedSizeIRv4, std::string>; -using AllIeeeFloatExceptHalf = +#if !defined(DISABLE_FLOAT8_TYPES) +using AllIRv9 = + boost::mp11::mp_push_back< + AllIRv4, + Float8E4M3FN, + Float8E4M3FNUZ, + Float8E5M2, + Float8E5M2FNUZ>; + +#else +using AllIRv9 = AllIRv4; +#endif + +using All = AllIRv4; + +#if !defined(DISABLE_FLOAT8_TYPES) +using AllFloat8 = TypeList< - float, - double>; + Float8E4M3FN, + Float8E4M3FNUZ, + Float8E5M2, + Float8E5M2FNUZ>; +#endif using AllIeeeFloat = TypeList< @@ -63,7 +99,7 @@ using AllIeeeFloat = double, MLFloat16>; -using AllNumeric = +using AllNumericIRv4 = TypeList< float, double, @@ -78,6 +114,8 @@ using AllNumeric = MLFloat16, BFloat16>; +using AllNumeric = AllNumericIRv4; + } // namespace element_type_lists } // namespace onnxruntime diff --git a/onnxruntime/core/framework/execution_frame.cc b/onnxruntime/core/framework/execution_frame.cc index 3f0261a15acfc..d9c49dc6bea1d 100644 --- a/onnxruntime/core/framework/execution_frame.cc +++ b/onnxruntime/core/framework/execution_frame.cc @@ -28,6 +28,7 @@ using namespace onnxruntime::common; namespace onnxruntime { #ifdef ORT_ENABLE_STREAM static StreamAwareArena* AsStreamBasedAllocator(AllocatorPtr allocator) { + ORT_ENFORCE(allocator.get() != nullptr, "allocator is nullptr"); if (allocator->Info().alloc_type == OrtArenaAllocator) { BFCArena* arena_ptr = static_cast(allocator.get()); return StreamAwareArena::FromBFCArena(*arena_ptr); @@ -102,7 +103,7 @@ void IExecutionFrame::UpdateFetches(gsl::span fetch_mlvalue_idxs, OrtValue& dest = all_values_[ort_value_idx]; if (!dest.IsAllocated()) { - AllocatorPtr allocator = GetAllocator(src.Location()); + AllocatorPtr allocator = GetAllocator(src.Location().device); auto p_tensor = std::make_unique(src.DataType(), src.Shape(), allocator); auto ml_tensor = DataTypeImpl::GetType(); dest.Init(p_tensor.release(), ml_tensor, ml_tensor->GetDeleteFunc()); @@ -137,7 +138,7 @@ Status IExecutionFrame::GetOutputs(gsl::span fetch_mlvalue_idxs, std: #endif -// Return nullptr if index map to an value that is an unused optional input/output +// Return nullptr if index map to a value that is an unused optional input/output const OrtValue* IExecutionFrame::GetNodeInputOrOutputMLValue(int index) const { int ort_value_idx = GetNodeIdxToMLValueIdx(index); return ort_value_idx != NodeIndexInfo::kInvalidEntry ? &(all_values_[ort_value_idx]) : nullptr; @@ -147,9 +148,9 @@ OrtValue* IExecutionFrame::GetMutableNodeInputOrOutputMLValue(int index) { return const_cast(GetNodeInputOrOutputMLValue(index)); } -// TO DO: make it thread safe -// This method is not thread safe! -// Return S_OK and nullptr if index map to an value that is an unused optional input/output +// TO DO: make it thread-safe +// This method is not thread-safe! +// Return S_OK and nullptr if index map to a value that is an unused optional input/output Status IExecutionFrame::GetOrCreateNodeOutputMLValue(const int output_index, int output_arg_index, const TensorShape* shape, OrtValue*& p_ort_value, @@ -191,13 +192,13 @@ Status IExecutionFrame::GetOrCreateNodeOutputMLValue(const int output_index, int } bool IExecutionFrame::TryGetInferredShape(int /*index*/, TensorShape& /*shape*/) const { - // By default, there is not information about inferred shape, so this default + // By default, there is no information about inferred shape, so this default // implementation always returns false. The derived class of IExecutionFrame // can override this function to provide, for example, activations' shape information. return false; } -AllocatorPtr IExecutionFrame::GetAllocator(const OrtMemoryInfo& info) const { +AllocatorPtr IExecutionFrame::GetAllocator(const OrtDevice& info) const { return GetAllocatorImpl(info); } @@ -213,7 +214,7 @@ Status IExecutionFrame::ReleaseMLValueImpl(int ort_value_idx) { } int IExecutionFrame::GetNodeIdxToMLValueIdx(int index) const { - // the validity of index is checked by GetMLValueIndex + // The validity of the index is checked by GetMLValueIndex int ort_value_idx = node_index_info_.GetMLValueIndex(index); return ort_value_idx; } @@ -226,8 +227,7 @@ void IExecutionFrame::Init(gsl::span feed_mlvalue_idxs, gsl::span feed_mlvalue_idxs, gsl::span feed_mlvalue_idxs, gsl::span feed_mlvalue_idxs, gsl::span feed_mlvalue_idxs, gsl::span())); @@ -421,14 +421,14 @@ ExecutionFrame::ExecutionFrame(gsl::span feed_mlvalue_idxs, gsl::span // Planning of one memory type should only happen once. #if !defined(ORT_MINIMAL_BUILD) && defined(ORT_MEMORY_PROFILE) ORT_ENFORCE( - static_activation_memory_sizes_in_byte_.find(location.name) == + static_activation_memory_sizes_in_byte_.find(location.ToString()) == static_activation_memory_sizes_in_byte_.end(), "Memory type ", - location.name, + location.ToString(), " should only appear once."); // static_activation_memory_in_bytes_ is max virtual memory size the planner computes. // Memory dynamically allocated when executing kernels is not recorded using this field. - static_activation_memory_sizes_in_byte_[location.name] = peak_size; + static_activation_memory_sizes_in_byte_[location.ToString()] = peak_size; #endif // the memory pattern buffer will leave in the whole execution. #ifdef ORT_ENABLE_STREAM @@ -494,7 +494,7 @@ const DataTransferManager& ExecutionFrame::GetDataTransferManager() const { } Status ExecutionFrame::AllocateMLValueTensorSelfOwnBuffer(OrtValue& ort_value, int ort_value_index, - MLDataType element_type, const OrtMemoryInfo& location, + MLDataType element_type, const OrtDevice& location, const TensorShape& shape) { return AllocateMLValueTensorSelfOwnBufferHelper(ort_value, ort_value_index, element_type, location, shape); } @@ -514,7 +514,7 @@ Stream* ExecutionFrame::GetValueStream(int ort_value_idx) const { Status ExecutionFrame::AllocateMLValueTensorSelfOwnBufferHelper(OrtValue& ort_value, int ort_value_index, MLDataType element_type, - const OrtMemoryInfo& location, + const OrtDevice& location, const TensorShape& shape) { if (ort_value_index == NodeIndexInfo::kInvalidEntry) { return Status(ONNXRUNTIME, FAIL, "Trying to allocate memory for unused optional inputs/outputs"); @@ -536,7 +536,7 @@ Status ExecutionFrame::AllocateMLValueTensorSelfOwnBufferHelper(OrtValue& ort_va AllocatorPtr alloc = nullptr; // if we have pre-calculated memory pattern, and the ort_value is not output mlvalue - // try to allocated on pre-allocated big chunk. + // try to allocate on pre-allocated big chunk. const auto& per_alloc_plan = GetAllocationPlan(ort_value_index); if (mem_patterns_ && per_alloc_plan.alloc_kind != AllocKind::kAllocateOutput && @@ -558,11 +558,11 @@ Status ExecutionFrame::AllocateMLValueTensorSelfOwnBufferHelper(OrtValue& ort_va } else { // the block size may vary especially if the model has NonZero ops, or different sequence lengths are // fed in, so use VERBOSE as the log level as it's expected. - // TODO: Should we re-use the block if the size is large enough? Would probably need to allow it + // TODO: Should we reuse the block if the size is large enough? Would probably need to allow it // to be freed if the size difference was too large so our memory usage doesn't stick at a high water mark LOGS(session_state_.Logger(), VERBOSE) << "For ort_value with index: " << ort_value_index << ", block in memory pattern size is: " << block->size_ - << " but the actually size is: " << size + << " but the actual size is: " << size << ", fall back to default allocation behavior"; } } @@ -573,6 +573,8 @@ Status ExecutionFrame::AllocateMLValueTensorSelfOwnBufferHelper(OrtValue& ort_va // no memory pattern, or the pattern is not correct. if (!alloc) alloc = GetAllocator(location); + ORT_ENFORCE(alloc && alloc.get() != nullptr, "Failed to get allocator for ", location.ToString()); + Stream* current_stream = GetValueStream(ort_value_index); if (current_stream) { #ifdef ORT_ENABLE_STREAM @@ -607,7 +609,7 @@ Status ExecutionFrame::AllocateMLValueTensorSelfOwnBufferHelper(OrtValue& ort_va // Dynamic activation size would be accessed by multiple threads // if parallel executor is used. std::unique_lock lock(mtx_); - dynamic_activation_memory_sizes_in_byte_[location.name] += size; + dynamic_activation_memory_sizes_in_byte_[location.ToString()] += size; session_state_.GetMemoryProfiler()->GetMemoryInfo().SetDynamicAllocation(ort_value_index); #endif } @@ -616,7 +618,7 @@ Status ExecutionFrame::AllocateMLValueTensorSelfOwnBufferHelper(OrtValue& ort_va } Status ExecutionFrame::AllocateMLValueTensorPreAllocateBuffer(OrtValue& ort_value, int ort_value_index_reuse, - MLDataType element_type, const OrtMemoryInfo& location, + MLDataType element_type, const OrtDevice& location, const TensorShape& shape, bool is_strided_tensor) { OrtValue& ort_value_reuse = GetMutableMLValue(ort_value_index_reuse); @@ -661,9 +663,9 @@ Status ExecutionFrame::AllocateMLValueTensorPreAllocateBuffer(OrtValue& ort_valu Status ExecutionFrame::AllocateTensorWithPreAllocateBufferHelper(OrtValue& ort_value, void* pBuffer, MLDataType element_type, - const OrtMemoryInfo& location, + const OrtDevice& location, const TensorShape& shape) { - Tensor::InitOrtValue(element_type, shape, pBuffer, location, ort_value, 0L); + Tensor::InitOrtValue(element_type, shape, pBuffer, GetAllocator(location)->Info(), ort_value, 0L); return Status::OK(); } @@ -821,12 +823,12 @@ Status ExecutionFrame::AllocateAsPerAllocationPlan(OrtValue& ort_value, int ort_ } } -AllocatorPtr ExecutionFrame::GetAllocatorImpl(const OrtMemoryInfo& info) const { +AllocatorPtr ExecutionFrame::GetAllocatorImpl(const OrtDevice& info) const { return session_state_.GetAllocator(info); } // This method is not thread safe! -// Return S_OK and nullptr if index map to an value that is an unused optional input/output +// Return S_OK and nullptr if index map to a value that is an unused optional input/output Status ExecutionFrame::CreateNodeOutputMLValueImpl(OrtValue& ort_value, int ort_value_idx, const TensorShape* shape) { return AllocateAsPerAllocationPlan(ort_value, ort_value_idx, shape); } @@ -931,7 +933,7 @@ bool ExecutionFrame::TryGetInferredShape(int index, TensorShape& shape) const { } // Search for inferred shape. - // If inferred shape is found, it's assigned to "shape" so that caller can use it. + // If the inferred shape is found, it's assigned to "shape" so that caller can use it. if (inferred_shapes_ != nullptr) { auto it = inferred_shapes_->find(ort_value_idx); if (it != inferred_shapes_->end()) { diff --git a/onnxruntime/core/framework/execution_frame.h b/onnxruntime/core/framework/execution_frame.h index 983f791a1f020..1576c16684faa 100644 --- a/onnxruntime/core/framework/execution_frame.h +++ b/onnxruntime/core/framework/execution_frame.h @@ -86,7 +86,7 @@ class IExecutionFrame { */ Status GetOutputs(std::vector& fetches); - AllocatorPtr GetAllocator(const OrtMemoryInfo& info) const; + AllocatorPtr GetAllocator(const OrtDevice& info) const; Status ReleaseMLValue(int ort_value_idx); @@ -113,7 +113,7 @@ class IExecutionFrame { // for the node. virtual void VerifyOutputSizes(int /*output_index*/, const Node& /*node*/, const TensorShape& /*output_shape*/) {} - virtual AllocatorPtr GetAllocatorImpl(const OrtMemoryInfo& info) const = 0; + virtual AllocatorPtr GetAllocatorImpl(const OrtDevice& info) const = 0; virtual Status CreateNodeOutputMLValueImpl(OrtValue& ort_value, int ort_value_idx, const TensorShape* shape) = 0; @@ -151,10 +151,10 @@ class ExecutionFrame final : public IExecutionFrame { // Fix the unit tests so they set an execution plan that results in these methods being called by // GetOrCreateNodeOutputMLValue instead Status AllocateMLValueTensorSelfOwnBuffer(OrtValue& ort_value, int ort_value_index, MLDataType element_type, - const OrtMemoryInfo& location, const TensorShape& shape); + const OrtDevice& location, const TensorShape& shape); Status AllocateMLValueTensorPreAllocateBuffer(OrtValue& ort_value, int ort_value_index_reuse, MLDataType element_type, - const OrtMemoryInfo& location, const TensorShape& shape, + const OrtDevice& location, const TensorShape& shape, bool is_strided_tensor = false); // thread-safe @@ -193,7 +193,7 @@ class ExecutionFrame final : public IExecutionFrame { private: ORT_DISALLOW_COPY_ASSIGNMENT_AND_MOVE(ExecutionFrame); - AllocatorPtr GetAllocatorImpl(const OrtMemoryInfo& info) const override; + AllocatorPtr GetAllocatorImpl(const OrtDevice& info) const override; Status ReleaseMLValueImpl(int ort_value_idx) override; Status CreateNodeOutputMLValueImpl(OrtValue& ort_value, int ort_value_idx, const TensorShape* shape) override; void VerifyOutputSizes(int output_index, const Node& node, const TensorShape& output_shape) override; @@ -205,10 +205,10 @@ class ExecutionFrame final : public IExecutionFrame { common::Status AllocateAsPerAllocationPlan(OrtValue& ort_value, int ort_value_index, const TensorShape* shape); Status AllocateMLValueTensorSelfOwnBufferHelper(OrtValue& ort_value, int ort_value_index, MLDataType element_type, - const OrtMemoryInfo& location, const TensorShape& shape); + const OrtDevice& location, const TensorShape& shape); Status AllocateTensorWithPreAllocateBufferHelper(OrtValue& ort_value, void* pBuffer, MLDataType element_type, - const OrtMemoryInfo& location, const TensorShape& shape); + const OrtDevice& location, const TensorShape& shape); void TraceAllocate(int ort_value_idx, size_t size); void TraceFree(int ort_value_idx); @@ -236,7 +236,7 @@ class ExecutionFrame final : public IExecutionFrame { std::optional planner_; // Big chunks on different locations that will be used by mem_pattern. - InlinedHashMap buffers_; + InlinedHashMap buffers_; // Given the input shapes of the executed graph, ExecutionFrame tries inferring // all symbolic shapes. inferred_shapes_[i] is the shape of OrtValue indexed diff --git a/onnxruntime/core/framework/execution_plan_base.h b/onnxruntime/core/framework/execution_plan_base.h index 226fedf410abe..d0b9262d46898 100644 --- a/onnxruntime/core/framework/execution_plan_base.h +++ b/onnxruntime/core/framework/execution_plan_base.h @@ -15,10 +15,10 @@ class ExecutionPlanBase { * @param ort_value_index The index of the mlvalue * @return memory location */ - virtual const struct OrtMemoryInfo& GetLocation(size_t ort_value_index) const = 0; - virtual void SetLocation(size_t ort_value_index, const struct OrtMemoryInfo&) = 0; + virtual const struct OrtDevice& GetLocation(size_t ort_value_index) const = 0; + virtual void SetLocation(size_t ort_value_index, const struct OrtDevice&) = 0; // return all memory locations for all the MLValues - virtual InlinedHashSet GetAllLocations() const = 0; + virtual InlinedHashSet GetAllLocations() const = 0; virtual ~ExecutionPlanBase() = default; }; diff --git a/onnxruntime/core/framework/execution_provider.cc b/onnxruntime/core/framework/execution_provider.cc index e9e13dbbbda84..7f8009216ce3a 100644 --- a/onnxruntime/core/framework/execution_provider.cc +++ b/onnxruntime/core/framework/execution_provider.cc @@ -11,26 +11,6 @@ namespace onnxruntime { -namespace { -// It assumes max(OrtMemType) <= 1, min(OrtMemType) = -2 -inline int MakeKey(int id, OrtMemType mem_type) { - return id << 2 | (mem_type + 2); -} -} // namespace - -AllocatorPtr IExecutionProvider::GetAllocator(OrtMemType mem_type) const { - // if mem_type is OrtMemType::OrtMemTypeDefault, it will allocate memory from the current device - // otherwise (mem_type is OrtMemTypeCpu...) it will allocate memory from Cpu as input/output, thus set the device_id - // to 0 as there is only 1 CPU in each machine. - int device_id = GetDeviceId(); - if (mem_type != OrtMemType::OrtMemTypeDefault) device_id = 0; - auto iter = allocators_.find(MakeKey(device_id, mem_type)); - if (iter != allocators_.end()) { - return iter->second; - } - return nullptr; -} - std::vector> IExecutionProvider::GetCapability(const onnxruntime::GraphViewer& graph, const IKernelLookup& kernel_lookup) const { @@ -47,54 +27,6 @@ IExecutionProvider::GetCapability(const onnxruntime::GraphViewer& graph, return result; } -// Update allocator in the provider if already present; ignore if not. -// We match using the device id, OrtMemType and OrtDevice info. -// We ignore the allocator name, and OrtAllocatorType (whether internally an arena is used or not). -// TODO: We should remove OrtAllocatorType from OrtMemoryInfo as it's an implementation detail of the allocator. -void IExecutionProvider::ReplaceAllocator(AllocatorPtr allocator) { - const auto& info = allocator->Info(); - - // TODO: This only works on allocators that are stored in this class. If a derived class overrides GetAllocator - // (e.g. the CUDA EP) and stores AllocatorPtr instances in the derived class we know nothing about them. - // In theory we could call GetAllocator instead of allocators_.find, however the CUDA EP does things this way to - // return a per-thread allocator from the GetAllocator override, and it's not clear if that could/should be replaced. - auto iter = allocators_.find(MakeKey(info.id, info.mem_type)); - if (iter != allocators_.end()) { - // check device as mem_type is relative to the device - // e.g. OrtMemTypeDefault is CPU for a CPU EP and GPU for a CUDA EP. An individual EP will only have one - // allocator for an OrtMemType value, so this check is to ensure we don't replace with an incompatible allocator. - if (iter->second->Info().device == info.device) { - IAllocator* existing_alloc = iter->second.get(); - for (auto& entry : allocator_list_) { - if (entry.get() == existing_alloc) { - entry = allocator; - break; - } - } - - iter->second = allocator; - } - } -} - -void IExecutionProvider::InsertAllocator(AllocatorPtr allocator) { - const OrtMemoryInfo& info = allocator->Info(); - const int key = MakeKey(info.id, info.mem_type); - - auto iter = allocators_.find(key); - if (iter != allocators_.end()) { - ORT_THROW("Duplicate allocator for OrtMemType:", info.mem_type, " device:", info.device.ToString(), - " Existing allocator: ", iter->second->Info().name, - " New allocator: ", allocator->Info().name); - } else { - allocators_.insert({key, allocator}); - allocator_list_.push_back(allocator); - } -} - -void IExecutionProvider::RegisterAllocator(AllocatorManager&) { -} - #if !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) common::Status IExecutionProvider::Compile(const std::vector& /*fused_nodes_and_graphs*/, std::vector& /*node_compute_funcs*/) { diff --git a/onnxruntime/core/framework/execution_providers.h b/onnxruntime/core/framework/execution_providers.h index 2b602703ff75e..7bf11f8293a36 100644 --- a/onnxruntime/core/framework/execution_providers.h +++ b/onnxruntime/core/framework/execution_providers.h @@ -73,14 +73,6 @@ class ExecutionProviders { const_iterator begin() const noexcept { return exec_providers_.cbegin(); } const_iterator end() const noexcept { return exec_providers_.cend(); } - const AllocatorPtr GetDefaultCpuAllocator() const { - return Get(onnxruntime::kCpuExecutionProvider)->GetAllocator(OrtMemTypeDefault); - } - - OrtMemoryInfo GetDefaultCpuMemoryInfo() const { - return GetDefaultCpuAllocator()->Info(); - } - const std::vector& GetIds() const { return exec_provider_ids_; } const ProviderOptionsMap& GetAllProviderOptions() const { return exec_provider_options_; } diff --git a/onnxruntime/core/framework/fallback_cpu_capability.cc b/onnxruntime/core/framework/fallback_cpu_capability.cc index eb081652a538a..3d971e6aa29a2 100644 --- a/onnxruntime/core/framework/fallback_cpu_capability.cc +++ b/onnxruntime/core/framework/fallback_cpu_capability.cc @@ -126,9 +126,13 @@ std::unordered_set GetCpuPreferredNodes(const onnxruntime::GraphViewe for (size_t i = 0; i < node->InputDefs().size(); ++i) { auto* input = node->InputDefs()[i]; - // skip placing on CPU if the data typs is float16 or bfloat16 + // skip placing on CPU if the data typs is float16 or bfloat16 or float8e4m3fn, float8e4m3fnuz, floate5m2, floate5m2fnuz if (input->Type() == DataTypeUtils::ToType("float16") || - input->Type() == DataTypeUtils::ToType("bfloat16")) { + input->Type() == DataTypeUtils::ToType("bfloat16") || + input->Type() == DataTypeUtils::ToType("float8e4m3fn") || + input->Type() == DataTypeUtils::ToType("float8e4m3fnuz") || + input->Type() == DataTypeUtils::ToType("float8e5m2") || + input->Type() == DataTypeUtils::ToType("float8e5m2fnuz")) { place_in_cpu = false; break; } diff --git a/onnxruntime/core/framework/graph_partitioner.cc b/onnxruntime/core/framework/graph_partitioner.cc index 2ba1a7cd1c693..dede1ecc95885 100644 --- a/onnxruntime/core/framework/graph_partitioner.cc +++ b/onnxruntime/core/framework/graph_partitioner.cc @@ -53,8 +53,8 @@ struct PartitionParams { std::reference_wrapper func_mgr; std::reference_wrapper fused_kernel_registry; std::reference_wrapper fused_node_unique_id; - std::reference_wrapper transform_layout_function; - std::reference_wrapper debug_graph_fn; + std::reference_wrapper transform_layout_function; + std::reference_wrapper debug_graph_fn; #endif // !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) }; } // namespace @@ -125,8 +125,8 @@ struct GetCapabilityForEPParams { #if !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) GraphPartitioner::Mode mode; - std::reference_wrapper transform_layout; - std::reference_wrapper debug_graph_fn; + std::reference_wrapper transform_layout; + std::reference_wrapper debug_graph_fn; #endif // !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) }; } // namespace @@ -281,7 +281,8 @@ static Node* PlaceNode(Graph& graph, const IndexedSubGraph& capability, // 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)) { + 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; @@ -334,8 +335,8 @@ static Status PartitionOnnxFormatModelImpl(Graph& graph, FuncManager& func_mgr, IExecutionProvider& current_ep, GraphPartitioner::Mode mode, int& fused_node_unique_id, - const layout_transformer::TransformLayoutFunction& transform_layout_function, - const layout_transformer::DebugGraphFn& debug_graph_fn) { + const layout_transformation::TransformLayoutFunction& transform_layout_fn, + const layout_transformation::DebugGraphFn& debug_graph_fn) { // 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) { @@ -349,7 +350,7 @@ 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_function, debug_graph_fn)); + transform_layout_fn, debug_graph_fn)); } } @@ -371,7 +372,7 @@ static Status PartitionOnnxFormatModelImpl(Graph& graph, FuncManager& func_mgr, std::ref(current_ep), std::ref(capabilities), mode, - std::cref(transform_layout_function), + std::cref(transform_layout_fn), std::cref(debug_graph_fn)}; ORT_RETURN_IF_ERROR(GetCapabilityForEP(get_capability_params)); @@ -666,10 +667,11 @@ static Status PartitionOrtFormatModelImpl(const PartitionParams& partition_param auto& fused_kernel_registry = partition_params.fused_kernel_registry.get(); ORT_RETURN_IF_ERROR(fused_kernel_registry.Register( - KernelCreateInfo(std::move(kernel_def), - [](FuncManager& func_mgr, const OpKernelInfo& info, std::unique_ptr& out) -> Status { - return FunctionKernel::Create(func_mgr, info, out); - }))); + KernelCreateInfo( + std::move(kernel_def), + [](FuncManager& func_mgr, const OpKernelInfo& info, std::unique_ptr& out) -> Status { + return FunctionKernel::Create(func_mgr, info, out); + }))); // now that we're done compiling we can remove the original nodes from the Graph and wire in the new one graph.FinalizeFuseSubGraph(indexed_sub_graph, node); @@ -692,9 +694,9 @@ static Status PartitionOrtFormatModel(const PartitionParams& partition_params, } Status GraphPartitioner::Partition(Graph& graph, FuncManager& func_mgr, - const layout_transformer::TransformLayoutFunction& transform_layout_function, + const layout_transformation::TransformLayoutFunction& transform_layout_function, Mode mode, - const layout_transformer::DebugGraphFn& debug_graph_fn) const { + const layout_transformation::DebugGraphFn& debug_graph_fn) const { // It is a greedy partitioning algorithm per provider preferences user provided when calling ONNX RUNTIME right now. // 1. Execution providers' capabilities are checked one by one. // 2. All sub-graphs that an execution provider returns will be assigned to it if it's not assigned yet. diff --git a/onnxruntime/core/framework/graph_partitioner.h b/onnxruntime/core/framework/graph_partitioner.h index fad96a50dbb52..36a27e906c651 100644 --- a/onnxruntime/core/framework/graph_partitioner.h +++ b/onnxruntime/core/framework/graph_partitioner.h @@ -29,9 +29,9 @@ class GraphPartitioner { // Run partitioning. Status Partition(Graph& graph, FuncManager& func_mgr, - const layout_transformer::TransformLayoutFunction& transform_layout_function, + const layout_transformation::TransformLayoutFunction& transform_layout_function, Mode mode = Mode::kNormal, - const layout_transformer::DebugGraphFn& debug_graph_fn = {}) const; + const layout_transformation::DebugGraphFn& debug_graph_fn = {}) const; private: ORT_DISALLOW_COPY_ASSIGNMENT_AND_MOVE(GraphPartitioner); diff --git a/onnxruntime/core/framework/iexecutor.h b/onnxruntime/core/framework/iexecutor.h index af55ee13ece19..7a174ba0a280b 100644 --- a/onnxruntime/core/framework/iexecutor.h +++ b/onnxruntime/core/framework/iexecutor.h @@ -20,7 +20,7 @@ class Logger; class IExecutor { public: - using CustomAllocator = std::function; + using CustomAllocator = std::function; virtual ~IExecutor() = default; diff --git a/onnxruntime/core/framework/kernel_registry.cc b/onnxruntime/core/framework/kernel_registry.cc index a4ab218ceb86e..d695e0e04c2b0 100644 --- a/onnxruntime/core/framework/kernel_registry.cc +++ b/onnxruntime/core/framework/kernel_registry.cc @@ -116,35 +116,41 @@ bool MatchKernelDefTypes(const std::unordered_map= node_version); + kernel_start_version <= since_ver && kernel_end_version >= since_ver); if (!valid_version) { std::ostringstream ostr; - ostr << "Op with name (" << node.Name() << ")" - << " and type (" << node.OpType() << ")" - << " Version mismatch." - << " node_version: " << node_version + ostr << " Version mismatch." + << " node_version: " << since_ver << " kernel start version: " << kernel_start_version << " kernel_end_version: " << kernel_end_version; error_str = ostr.str(); + } + return valid_version; +} + +bool KernelRegistry::VerifyKernelDef(const Node& node, + const KernelDef& kernel_def, + const IKernelTypeStrResolver* kernel_type_str_resolver, + const TypeConstraintMap* type_constraint_values, + std::string& error_str) { + // check if version matches + bool valid_version = VerifyVersion(node.SinceVersion(), kernel_def, error_str); + + if (!valid_version) { return false; } @@ -157,12 +163,9 @@ bool KernelRegistry::VerifyKernelDef(const Node& node, if (!matched) { std::ostringstream ostr; - ostr << "Found kernel for Op with name (" << node.Name() << ")" - << " and type (" << node.OpType() << ")" + ostr << "Kernel found kernel" << " in the supported version range" - << " (node_version: " << node_version - << " kernel start version: " << kernel_start_version - << " kernel_end_version: " << kernel_end_version << ")." + << " (node_version: " << node.SinceVersion() << ")." << " However the types are incompatible. " << mismatch_reason; error_str = ostr.str(); } @@ -203,6 +206,7 @@ Status KernelRegistry::TryFindKernelImpl(const Node& node, if (!verify_kernel_def_error_strs.empty()) { std::ostringstream oss; oss << "Op with name (" << node.Name() << ")" + << " domain (" << node.Domain() << ")" << " and type (" << node.OpType() << ")" << " kernel is not supported in " << expected_provider << "." << " Encountered following errors: ("; @@ -229,6 +233,68 @@ Status KernelRegistry::TryFindKernel(const Node& node, ProviderType exec_provide return TryFindKernelImpl(node, exec_provider, nullptr, &type_constraints, out); } +static bool KernelDefCompatible(int version, const KernelDef& kernel_def, + const KernelRegistry::TypeConstraintMap& type_constraint_values, + std::string& error_str) { + if (!VerifyVersion(version, kernel_def, error_str)) { + return false; + } + + const auto& kernel_type_constraints = kernel_def.TypeConstraints(); + bool matched = MatchKernelDefTypes(kernel_type_constraints, type_constraint_values); + + if (!matched) { + std::ostringstream ostr; + ostr << "Kernel found kernel" + << " in the supported version range" + << " (node_version: " << version << ")." + << " However the types are incompatible."; + error_str = ostr.str(); + } + + return matched; +} + +Status KernelRegistry::TryFindKernel(ProviderType exec_provider, + std::string_view op_type, + std::string_view domain, + int version, + const KernelRegistry::TypeConstraintMap& type_constraints, + const KernelCreateInfo** out) const { + auto range = kernel_creator_fn_map_.equal_range(GetMapKey(op_type, domain, exec_provider)); + if (out) *out = nullptr; + + std::vector verify_kernel_def_error_strs; + + for (auto i = range.first; i != range.second; ++i) { + std::string error_str; + if (KernelDefCompatible(version, *i->second.kernel_def, type_constraints, error_str)) { + if (out) { + *out = &i->second; + } + return Status::OK(); + } + + verify_kernel_def_error_strs.push_back(error_str); + } + + if (!verify_kernel_def_error_strs.empty()) { + std::ostringstream oss; + oss << "Op type (" << op_type << ")" + << " domain (" << domain << ")" + << " kernel is not supported in " << exec_provider << "." + << " Encountered following errors: ("; + std::copy(verify_kernel_def_error_strs.begin(), verify_kernel_def_error_strs.end(), + std::ostream_iterator(oss, "\n")); + oss << ")"; + + VLOGS_DEFAULT(2) << "TryFindKernel failed, Reason: " << oss.str(); + return Status(common::ONNXRUNTIME, common::FAIL, oss.str()); + } + + return Status(common::ONNXRUNTIME, common::FAIL, "Kernel not found"); +} + Status KernelRegistry::Register(KernelDefBuilder& kernel_builder, const KernelCreateFn& kernel_creator) { return Register(KernelCreateInfo(kernel_builder.Build(), kernel_creator)); diff --git a/onnxruntime/core/framework/kernel_registry_manager.cc b/onnxruntime/core/framework/kernel_registry_manager.cc index 73cd1c3445199..38c8a4a4e3d5e 100644 --- a/onnxruntime/core/framework/kernel_registry_manager.cc +++ b/onnxruntime/core/framework/kernel_registry_manager.cc @@ -23,7 +23,8 @@ Status KernelRegistryManager::CreateKernel(const Node& node, OpKernelInfo kernel_info(node, *kernel_create_info.kernel_def, execution_provider, session_state.GetConstantInitializedTensors(), session_state.GetOrtValueNameIdxMap(), - session_state.GetDataTransferMgr()); + session_state.GetDataTransferMgr(), + session_state.GetAllocators()); return kernel_create_info.kernel_create_func(session_state.GetMutableFuncMgr(), kernel_info, out); } diff --git a/onnxruntime/core/framework/kernel_type_str_resolver.cc b/onnxruntime/core/framework/kernel_type_str_resolver.cc index 1923534750e4f..732029d408c6b 100644 --- a/onnxruntime/core/framework/kernel_type_str_resolver.cc +++ b/onnxruntime/core/framework/kernel_type_str_resolver.cc @@ -29,7 +29,9 @@ Status KernelTypeStrResolver::ResolveKernelTypeStr(const Node& node, std::string ORT_RETURN_IF(type_str_it == type_str_map.end(), "Failed to find args for kernel type string '", kernel_type_str, - "'. If type constraint names are available, ensure that they are used in the kernel def type " + "' for node type '", node.OpType(), "'. ", + "If type constraint names are available, ", + "ensure that they are used in the kernel def type " "constraints instead of op input or output names. Not doing so will result in this error."); resolved_args = type_str_it->second; return Status::OK(); diff --git a/onnxruntime/core/framework/kernel_type_str_resolver.h b/onnxruntime/core/framework/kernel_type_str_resolver.h index 6655b52f41449..31a806dd52291 100644 --- a/onnxruntime/core/framework/kernel_type_str_resolver.h +++ b/onnxruntime/core/framework/kernel_type_str_resolver.h @@ -7,8 +7,10 @@ #include #include +#include "flatbuffers/flatbuffers.h" + #if !defined(ORT_MINIMAL_BUILD) -#include "onnx/defs/schema.h" +#include "core/graph/onnx_protobuf.h" #endif // !defined(ORT_MINIMAL_BUILD) #include "core/common/gsl.h" @@ -18,12 +20,6 @@ #include "core/graph/graph.h" #include "core/platform/ort_mutex.h" -namespace flatbuffers { -class FlatBufferBuilder; -template -struct Offset; -} // namespace flatbuffers - namespace onnxruntime { namespace fbs { diff --git a/onnxruntime/core/framework/kernel_type_str_resolver_utils.cc b/onnxruntime/core/framework/kernel_type_str_resolver_utils.cc index 7984fb219ce29..ea93db58339c7 100644 --- a/onnxruntime/core/framework/kernel_type_str_resolver_utils.cc +++ b/onnxruntime/core/framework/kernel_type_str_resolver_utils.cc @@ -9,7 +9,7 @@ #include "core/common/common.h" #include "core/flatbuffers/schema/ort.fbs.h" -#include "core/optimizer/transpose_optimizer/layout_transformation_potentially_added_ops.h" +#include "core/optimizer/layout_transformation/layout_transformation_potentially_added_ops.h" namespace onnxruntime::kernel_type_str_resolver_utils { @@ -53,124 +53,129 @@ Status AddLayoutTransformationRequiredOpsToKernelTypeStrResolver(KernelTypeStrRe // clang-format off constexpr uint8_t kLayoutTransformationRequiredOpsKernelTypeStrResolverBytes[] = { 0x10, 0x00, 0x00, 0x00, 0x6b, 0x74, 0x73, 0x72, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0xfc, 0x04, 0x00, 0x00, - 0x48, 0x06, 0x00, 0x00, 0xac, 0x06, 0x00, 0x00, 0xa4, 0x05, 0x00, 0x00, 0x2c, 0x03, 0x00, 0x00, - 0xd0, 0x01, 0x00, 0x00, 0xe0, 0x05, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, - 0x58, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x38, 0x05, 0x00, 0x00, 0xc0, 0x02, 0x00, 0x00, - 0xb0, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x48, 0x03, 0x00, 0x00, - 0x30, 0xf9, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x3a, 0x53, 0x71, 0x75, 0x65, 0x65, 0x7a, 0x65, - 0x3a, 0x31, 0x00, 0x00, 0x54, 0xf9, 0xff, 0xff, 0x7c, 0x06, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x82, 0xf9, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x01, 0x7c, 0xf9, 0xff, 0xff, 0x78, 0xf9, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, - 0x63, 0x6f, 0x6d, 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x3a, 0x4e, 0x68, - 0x77, 0x63, 0x4d, 0x61, 0x78, 0x50, 0x6f, 0x6f, 0x6c, 0x3a, 0x31, 0x00, 0xac, 0xf9, 0xff, 0xff, - 0x24, 0x06, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0xda, 0xf9, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0xd4, 0xf9, 0xff, 0xff, - 0xd0, 0xf9, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x3a, 0x55, 0x6e, 0x73, 0x71, 0x75, 0x65, 0x65, - 0x7a, 0x65, 0x3a, 0x31, 0x31, 0x00, 0x00, 0x00, 0xf8, 0xf9, 0xff, 0xff, 0xd8, 0x05, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0xbc, 0x06, 0x00, 0x00, + 0x4c, 0x02, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x14, 0x06, 0x00, 0x00, + 0x88, 0x01, 0x00, 0x00, 0xb8, 0x05, 0x00, 0x00, 0x1c, 0x05, 0x00, 0x00, 0x18, 0x07, 0x00, 0x00, + 0xcc, 0x04, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x54, 0x05, 0x00, 0x00, + 0x3c, 0x06, 0x00, 0x00, 0xf8, 0x02, 0x00, 0x00, 0x7c, 0x02, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x38, 0x03, 0x00, 0x00, 0xec, 0xf8, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x6d, 0x2e, + 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x3a, 0x4e, 0x68, 0x77, 0x63, 0x4d, 0x61, + 0x78, 0x50, 0x6f, 0x6f, 0x6c, 0x3a, 0x31, 0x00, 0x20, 0xf9, 0xff, 0xff, 0xf0, 0x06, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x26, 0xfa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x20, 0xfa, 0xff, 0xff, 0x1c, 0xfa, 0xff, 0xff, + 0x0e, 0xf9, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x08, 0xf9, 0xff, 0xff, 0x44, 0xf9, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x3a, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x73, 0x65, 0x3a, 0x31, - 0x00, 0x00, 0x00, 0x00, 0x44, 0xfa, 0xff, 0xff, 0x8c, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x72, 0xfa, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x01, 0x6c, 0xfa, 0xff, 0xff, 0x68, 0xfa, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x3a, 0x53, 0x71, 0x75, 0x65, 0x65, 0x7a, 0x65, 0x3a, 0x31, 0x33, 0x00, - 0x90, 0xfa, 0xff, 0xff, 0x40, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xbe, 0xfa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, - 0xb8, 0xfa, 0xff, 0xff, 0xb4, 0xfa, 0xff, 0xff, 0xe4, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xa0, 0xfa, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, - 0xd0, 0xfa, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x3a, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, - 0x79, 0x3a, 0x31, 0x34, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xfa, 0xff, 0xff, 0x1c, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6c, 0xf9, 0xff, 0xff, 0xa4, 0x06, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x5a, 0xf9, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x01, 0x54, 0xf9, 0xff, 0xff, 0x90, 0xf9, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x3a, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x3a, 0x31, 0x00, 0xb4, 0xf9, 0xff, 0xff, + 0x5c, 0x06, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xa2, 0xf9, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x9c, 0xf9, 0xff, 0xff, + 0xd8, 0xf9, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3a, 0x53, 0x71, 0x75, + 0x65, 0x65, 0x7a, 0x65, 0x3a, 0x31, 0x33, 0x00, 0x00, 0xfa, 0xff, 0xff, 0xb4, 0x01, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x48, 0xfa, 0xff, 0xff, + 0x01, 0x00, 0x00, 0x00, 0x1c, 0xfa, 0xff, 0xff, 0xf4, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0xfa, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x01, 0x04, 0xfa, 0xff, 0xff, 0x40, 0xfa, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x3a, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x3a, 0x31, 0x34, 0x00, 0x00, 0x00, 0x00, + 0x68, 0xfa, 0xff, 0xff, 0x3c, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x56, 0xfa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, + 0x50, 0xfa, 0xff, 0xff, 0x8c, 0xfa, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x3a, 0x47, 0x61, 0x74, 0x68, 0x65, 0x72, 0x3a, 0x31, 0x33, 0x00, 0x00, 0xb4, 0xfa, 0xff, 0xff, + 0x00, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xfc, 0xfa, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0xd0, 0xfa, 0xff, 0xff, 0x40, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x26, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x20, 0xfb, 0xff, 0xff, 0x1c, 0xfb, 0xff, 0xff, - 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x3a, 0x53, 0x71, 0x75, 0x65, 0x65, 0x7a, 0x65, 0x3a, 0x31, 0x31, 0x00, - 0x40, 0xfb, 0xff, 0xff, 0x90, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6e, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, - 0x68, 0xfb, 0xff, 0xff, 0x64, 0xfb, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0xbe, 0xfa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0xb8, 0xfa, 0xff, 0xff, 0xf4, 0xfa, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x3a, 0x47, 0x61, 0x74, 0x68, 0x65, 0x72, 0x3a, + 0x31, 0x31, 0x00, 0x00, 0x1c, 0xfb, 0xff, 0xff, 0x98, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x64, 0xfb, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x38, 0xfb, 0xff, 0xff, 0xd8, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x26, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, + 0x20, 0xfb, 0xff, 0xff, 0x5c, 0xfb, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x3a, 0x55, 0x6e, 0x73, 0x71, 0x75, 0x65, 0x65, 0x7a, 0x65, 0x3a, 0x31, 0x33, 0x00, 0x00, 0x00, - 0x90, 0xfb, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x61, 0x78, 0x65, 0x73, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x88, 0xfb, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0xb8, 0xfb, 0xff, 0xff, 0x18, 0x04, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0xe6, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0xe0, 0xfb, 0xff, 0xff, 0xdc, 0xfb, 0xff, 0xff, + 0x88, 0xfb, 0xff, 0xff, 0x88, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x76, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, + 0x70, 0xfb, 0xff, 0xff, 0xac, 0xfb, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x61, 0x78, 0x65, 0x73, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0xd4, 0xfb, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x3a, 0x55, 0x6e, 0x73, 0x71, 0x75, 0x65, 0x65, 0x7a, 0x65, 0x3a, 0x31, - 0x00, 0x00, 0x00, 0x00, 0x04, 0xfc, 0xff, 0xff, 0xcc, 0x03, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x32, 0xfc, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x01, 0x2c, 0xfc, 0xff, 0xff, 0x28, 0xfc, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x3a, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x3a, 0x31, 0x33, 0x00, 0x00, 0x00, 0x00, - 0x50, 0xfc, 0xff, 0xff, 0x80, 0x03, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7e, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, - 0x78, 0xfc, 0xff, 0xff, 0x74, 0xfc, 0xff, 0xff, 0x28, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0xe4, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, - 0x1b, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x6d, 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, - 0x74, 0x3a, 0x51, 0x4c, 0x69, 0x6e, 0x65, 0x61, 0x72, 0x43, 0x6f, 0x6e, 0x76, 0x3a, 0x31, 0x00, - 0xc0, 0xfc, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x79, 0x5f, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0xb8, 0xfc, 0xff, 0xff, 0x06, 0x00, 0x00, 0x00, 0xe8, 0xfc, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x54, 0x33, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1e, 0xfd, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, - 0xe8, 0xfc, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x18, 0xfd, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x54, 0x31, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0xfd, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, - 0x48, 0xfd, 0xff, 0xff, 0x44, 0xfd, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x54, 0x32, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x3c, 0xfd, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x44, 0xfd, 0xff, 0xff, - 0x03, 0x00, 0x00, 0x00, 0x74, 0xfd, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x3a, 0x55, 0x6e, 0x73, 0x71, 0x75, 0x65, 0x65, 0x7a, 0x65, 0x3a, 0x31, + 0x31, 0x00, 0x00, 0x00, 0xfc, 0xfb, 0xff, 0xff, 0x14, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xea, 0xfb, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x01, 0xe4, 0xfb, 0xff, 0xff, 0x20, 0xfc, 0xff, 0xff, 0x28, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, + 0xa8, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x6d, 0x2e, 0x6d, 0x69, 0x63, 0x72, + 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x3a, 0x51, 0x4c, 0x69, 0x6e, 0x65, 0x61, 0x72, 0x43, 0x6f, 0x6e, + 0x76, 0x3a, 0x31, 0x00, 0x6c, 0xfc, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x54, 0x34, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x68, 0xfd, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x98, 0xfd, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x77, 0x5f, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x90, 0xfd, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, - 0xc0, 0xfd, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0xbc, 0xfc, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x90, 0xfc, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x79, 0x5f, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe4, 0xfc, 0xff, 0xff, 0x06, 0x00, 0x00, 0x00, + 0xb8, 0xfc, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x78, 0x5f, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0xb8, 0xfd, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0xe8, 0xfd, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x3a, 0x47, 0x61, 0x74, 0x68, 0x65, 0x72, 0x3a, 0x31, 0x00, 0x00, 0x00, - 0x10, 0xfe, 0xff, 0xff, 0x00, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0xfc, 0xfd, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x2c, 0xfe, 0xff, 0xff, - 0xa4, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x5a, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x54, 0xfe, 0xff, 0xff, - 0x50, 0xfe, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x3a, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, - 0x73, 0x65, 0x3a, 0x31, 0x33, 0x00, 0x00, 0x00, 0x78, 0xfe, 0xff, 0xff, 0x58, 0x01, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0xa6, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0xa0, 0xfe, 0xff, 0xff, 0x9c, 0xfe, 0xff, 0xff, + 0x0c, 0xfd, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0xe0, 0xfc, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x54, 0x33, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xd6, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, + 0x3c, 0xfd, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x10, 0xfd, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x54, 0x32, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x64, 0xfd, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, + 0x6c, 0xfd, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x40, 0xfd, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x77, 0x5f, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x94, 0xfd, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x68, 0xfd, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x54, 0x31, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xbc, 0xfd, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x58, 0xfd, 0xff, 0xff, 0x94, 0xfd, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x3a, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x3a, 0x31, 0x00, - 0xc0, 0xfe, 0xff, 0xff, 0x10, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xee, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, - 0xe8, 0xfe, 0xff, 0xff, 0xe4, 0xfe, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x3a, 0x53, 0x71, 0x75, 0x65, 0x65, 0x7a, 0x65, 0x3a, 0x31, 0x31, 0x00, + 0xb8, 0xfd, 0xff, 0xff, 0x58, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xa6, 0xfd, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, + 0xa0, 0xfd, 0xff, 0xff, 0xdc, 0xfd, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x3a, 0x49, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x74, 0x79, 0x3a, 0x31, 0x36, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xff, 0xff, 0xff, - 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x42, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x01, 0x3c, 0xff, 0xff, 0xff, 0x38, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x3a, 0x47, 0x61, 0x74, 0x68, 0x65, 0x72, 0x3a, 0x31, 0x31, 0x00, 0x00, - 0x60, 0xff, 0xff, 0xff, 0xb0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x4c, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x7c, 0xff, 0xff, 0xff, - 0x54, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0xaa, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0xa4, 0xff, 0xff, 0xff, - 0xa0, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x3a, 0x47, 0x61, 0x74, - 0x68, 0x65, 0x72, 0x3a, 0x31, 0x33, 0x00, 0x00, 0xc8, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x07, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x54, 0x69, 0x6e, 0x64, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x3a, 0x31, 0x39, 0x00, 0x00, 0x00, 0x00, 0x04, 0xfe, 0xff, 0xff, + 0xa0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xf2, 0xfd, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0xec, 0xfd, 0xff, 0xff, + 0x28, 0xfe, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x3a, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, + 0x73, 0x65, 0x3a, 0x31, 0x33, 0x00, 0x00, 0x00, 0x50, 0xfe, 0xff, 0xff, 0xc0, 0x01, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x3e, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x38, 0xfe, 0xff, 0xff, 0x74, 0xfe, 0xff, 0xff, + 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x3a, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x3a, 0x31, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x9c, 0xfe, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x92, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x8c, 0xfe, 0xff, 0xff, + 0xc8, 0xfe, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x3a, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x3a, 0x31, 0x33, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xfe, 0xff, 0xff, 0x20, 0x01, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xde, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0xd8, 0xfe, 0xff, 0xff, 0x14, 0xff, 0xff, 0xff, + 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x3a, 0x55, 0x6e, 0x73, 0x71, 0x75, 0x65, 0x65, 0x7a, 0x65, 0x3a, 0x31, + 0x00, 0x00, 0x00, 0x00, 0x3c, 0xff, 0xff, 0xff, 0xd4, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x2a, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x01, 0x24, 0xff, 0xff, 0xff, 0x60, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x3a, 0x47, 0x61, 0x74, 0x68, 0x65, 0x72, 0x3a, 0x31, 0x00, 0x00, 0x00, + 0x88, 0xff, 0xff, 0xff, 0x88, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x76, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, + 0x70, 0xff, 0xff, 0xff, 0xac, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x54, 0x69, 0x6e, 0x64, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xdc, 0xff, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x3a, 0x53, 0x71, 0x75, + 0x65, 0x65, 0x7a, 0x65, 0x3a, 0x31, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x08, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x54, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x07, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, }; // clang-format on diff --git a/onnxruntime/core/framework/mem_pattern.h b/onnxruntime/core/framework/mem_pattern.h index ae3180678908b..1addbd843beb8 100644 --- a/onnxruntime/core/framework/mem_pattern.h +++ b/onnxruntime/core/framework/mem_pattern.h @@ -59,10 +59,10 @@ class MemoryPattern { }; struct MemoryPatternGroup { - std::vector locations; + std::vector locations; std::vector patterns; - const MemoryPattern* GetPatterns(const OrtMemoryInfo& location) const { + const MemoryPattern* GetPatterns(const OrtDevice& location) const { for (size_t i = 0; i < locations.size(); i++) if (locations[i] == location) { return &patterns[i]; diff --git a/onnxruntime/core/framework/memory_info.cc b/onnxruntime/core/framework/memory_info.cc index 41c8191778af5..afb338f47f334 100644 --- a/onnxruntime/core/framework/memory_info.cc +++ b/onnxruntime/core/framework/memory_info.cc @@ -130,7 +130,7 @@ void PrintInforPerTensor(const MemoryInfo::AllocInfoPerTensor& alloc_info, const std::cout << "Index: " << alloc_info.mlvalue_index << ", "; std::cout << "Reuse inplace: " << alloc_info.inplace_reuse << ", "; std::cout << "Alloc type: " << alloc_info.alloc_kind << ", "; - std::cout << "Location: " << alloc_info.location.name << ", "; + std::cout << "Location: " << alloc_info.location.ToString() << ", "; std::cout << "lifetime: (" << alloc_info.lifetime_interval.first << ", " << alloc_info.lifetime_interval.second << "), "; std::cout << "planned block: (" << mem_info.planned_block.offset_ << ", " << (mem_info.planned_block.offset_ + mem_info.planned_block.size_) << "), "; @@ -142,24 +142,24 @@ void PrintInforPerTensor(const MemoryInfo::AllocInfoPerTensor& alloc_info, const void MemoryInfo::PrintMemoryInfoForLocation(const OrtDevice::DeviceType location) { for (const auto& map : tensors_memory_info_map_) { - if (map.first.device.Type() != location) continue; - std::cout << "Initializer in " << map.first.name << "\n"; + if (map.first.Type() != location) continue; + std::cout << "Initializer in " << map.first.ToString() << "\n"; const auto& initailizer_map = map.second.at(MapType::Initializer); for (const auto& item : initailizer_map) { - if (AllocPlan(item.first)->location.device.Type() != location) continue; + if (AllocPlan(item.first)->location.Type() != location) continue; PrintInforPerTensor(*AllocPlan(item.first), item.second, initailizer_map.GetAllocAddress(item.first)); } - std::cout << "\nStatic Activation in " << map.first.name << "\n"; + std::cout << "\nStatic Activation in " << map.first.ToString() << "\n"; const auto& static_activation_map = map.second.at(MapType::StaticActivation); for (const auto& item : static_activation_map) { - if (AllocPlan(item.first)->location.device.Type() != location) continue; + if (AllocPlan(item.first)->location.Type() != location) continue; PrintInforPerTensor(*AllocPlan(item.first), item.second, static_activation_map.GetAllocAddress(item.first)); } - std::cout << "\nDynamic Activation in " << map.first.name << "\n"; + std::cout << "\nDynamic Activation in " << map.first.ToString() << "\n"; const auto& dynamic_activation_map = map.second.at(MapType::DynamicActivation); for (const auto& item : dynamic_activation_map) { - if (AllocPlan(item.first)->location.device.Type() != location) continue; + if (AllocPlan(item.first)->location.Type() != location) continue; PrintInforPerTensor(*AllocPlan(item.first), item.second, dynamic_activation_map.GetAllocAddress(item.first)); } } @@ -273,10 +273,10 @@ void MemoryProfiler::CreateEvents(const std::string& p_name, // Create Event for each tensor auto& time_step_trace = GetMemoryInfo().time_step_trace_; for (const auto& location_map : GetMemoryInfo().tensors_memory_info_map_) { - const OrtMemoryInfo& memory_info = location_map.first; + const OrtDevice& memory_info = location_map.first; const auto& maptype_to_map_mapping = location_map.second; - if (memory_info.device.Type() != device_type) continue; + if (memory_info.Type() != device_type) continue; // If there is no tensor of a map_type, we skip creating event for that map_type if (maptype_to_map_mapping.find(map_type) == maptype_to_map_mapping.end()) continue; diff --git a/onnxruntime/core/framework/memory_info.h b/onnxruntime/core/framework/memory_info.h index 4b11dcaf7ada6..e38ccb3d94d45 100644 --- a/onnxruntime/core/framework/memory_info.h +++ b/onnxruntime/core/framework/memory_info.h @@ -122,7 +122,7 @@ class MemoryInfo { bool inplace_reuse{false}; OrtValueIndex reused_buffer{0}; // The index of the reused tensor, if no reuse, it is its own tensor. AllocKind alloc_kind{AllocKind::kAllocate}; - OrtMemoryInfo location; + OrtDevice location; }; struct AllocationSummary { @@ -185,7 +185,7 @@ class MemoryInfo { } // Key: The map type. E.g., initializer, activation. Value: A map from the tensor index to its memory information - std::map > tensors_memory_info_map_; + std::map > tensors_memory_info_map_; // Key: The tensor index. Value: The Allocation information per tensor std::map tensor_alloc_info_map_; diff --git a/onnxruntime/core/framework/onnxruntime_map_type_info.cc b/onnxruntime/core/framework/onnxruntime_map_type_info.cc index b87ea179c0700..3963504273599 100644 --- a/onnxruntime/core/framework/onnxruntime_map_type_info.cc +++ b/onnxruntime/core/framework/onnxruntime_map_type_info.cc @@ -66,6 +66,18 @@ ToONNXTensorElementDataType(ONNX_NAMESPACE::TensorProto_DataType data_type) { case TensorType::TensorProto_DataType_BFLOAT16: { return ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16; } // Non-IEEE floating-point format based on IEEE754 single-precision + case TensorType::TensorProto_DataType_FLOAT8E4M3FN: { + return ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FN; + } // Non-IEEE floating-point format based on IEEE754 single-precision + case TensorType::TensorProto_DataType_FLOAT8E4M3FNUZ: { + return ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FNUZ; + } // Non-IEEE floating-point format based on IEEE754 single-precision + case TensorType::TensorProto_DataType_FLOAT8E5M2: { + return ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2; + } // Non-IEEE floating-point format based on IEEE754 single-precision + case TensorType::TensorProto_DataType_FLOAT8E5M2FNUZ: { + return ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2FNUZ; + } // Non-IEEE floating-point format based on IEEE754 single-precision default: { return ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED; } diff --git a/onnxruntime/core/framework/onnxruntime_typeinfo.cc b/onnxruntime/core/framework/onnxruntime_typeinfo.cc index 678e7e6e78237..a884927abddb7 100644 --- a/onnxruntime/core/framework/onnxruntime_typeinfo.cc +++ b/onnxruntime/core/framework/onnxruntime_typeinfo.cc @@ -18,9 +18,7 @@ #include "core/framework/onnxruntime_optional_type_info.h" #include "core/framework/TensorSeq.h" -using onnxruntime::BFloat16; using onnxruntime::DataTypeImpl; -using onnxruntime::MLFloat16; #if !defined(DISABLE_SPARSE_TENSORS) using onnxruntime::SparseTensor; #endif diff --git a/onnxruntime/core/framework/op_kernel.cc b/onnxruntime/core/framework/op_kernel.cc index 5590a1de4b85a..94b6224440ed0 100644 --- a/onnxruntime/core/framework/op_kernel.cc +++ b/onnxruntime/core/framework/op_kernel.cc @@ -21,8 +21,8 @@ const onnxruntime::KernelDef& OpKernel::KernelDef() const { return op_kernel_info_->GetKernelDef(); } -const OrtMemoryInfo& OpKernel::Allocator(OrtMemType mem_type) const { - return op_kernel_info_->GetMemoryInfo(mem_type); +const OrtDevice OpKernel::GetDevice(OrtMemType mem_type) const { + return op_kernel_info_->GetDevice(mem_type); } OpKernelContext::OpKernelContext(_Inout_ IExecutionFrame* frame, _In_ const OpKernel* kernel, @@ -93,7 +93,7 @@ int OpKernelContext::NumVariadicInputs(size_t arg_num) const { } Status OpKernelContext::GetTempSpaceAllocator(AllocatorPtr* output) const { - *output = GetAllocator(kernel_->Allocator(OrtMemTypeDefault)); + *output = GetAllocator(kernel_->GetDevice(OrtMemTypeDefault)); if (!*output) return Status(common::ONNXRUNTIME, common::FAIL, "TempSpace allocator not found"); return Status::OK(); @@ -104,7 +104,7 @@ Status OpKernelContext::GetTempSpaceCPUAllocator(AllocatorPtr* output) const { // (which is called via ExecutionFrame), the allocator lookup // logic doesn't key on OrtAllocatorType, so any OrtAllocatorType // is good here. - *output = GetAllocator(OrtMemoryInfo(CPU, OrtAllocatorType::OrtArenaAllocator)); + *output = GetAllocator(OrtDevice()); if (!*output) return Status(common::ONNXRUNTIME, common::FAIL, "CPU allocator not found"); return Status::OK(); @@ -182,8 +182,8 @@ OrtValue* OpKernelContext::GetOutputMLValue(int index) { return execution_frame_->GetMutableNodeInputOrOutputMLValue(output_arg_index); } -AllocatorPtr OpKernelContext::GetAllocator(const OrtMemoryInfo& memory_info) const { - return execution_frame_->GetAllocator(memory_info); +AllocatorPtr OpKernelContext::GetAllocator(const OrtDevice& device) const { + return execution_frame_->GetAllocator(device); } #ifdef ENABLE_ATEN diff --git a/onnxruntime/core/framework/op_kernel_info.cc b/onnxruntime/core/framework/op_kernel_info.cc index f976edcef93cb..841fdb585f0d8 100644 --- a/onnxruntime/core/framework/op_kernel_info.cc +++ b/onnxruntime/core/framework/op_kernel_info.cc @@ -14,7 +14,8 @@ OpKernelInfo::OpKernelInfo(const onnxruntime::Node& node, const IExecutionProvider& execution_provider, const std::unordered_map& constant_initialized_tensors, const OrtValueNameIdxMap& ort_value_name_idx_map, - const DataTransferManager& data_transfer_mgr) + const DataTransferManager& data_transfer_mgr, + const AllocatorMap& allocators) : OpNodeProtoHelper(&proto_helper_context_), node_(node), kernel_def_(kernel_def), @@ -22,20 +23,21 @@ OpKernelInfo::OpKernelInfo(const onnxruntime::Node& node, constant_initialized_tensors_(constant_initialized_tensors), ort_value_name_idx_map_(ort_value_name_idx_map), data_transfer_mgr_(data_transfer_mgr), - proto_helper_context_(node) {} + proto_helper_context_(node), + allocators_(allocators) {} OpKernelInfo::OpKernelInfo(const OpKernelInfo& other) : OpKernelInfo(other.node_, other.kernel_def_, *other.execution_provider_, other.constant_initialized_tensors_, - other.ort_value_name_idx_map_, other.data_transfer_mgr_) {} + other.ort_value_name_idx_map_, other.data_transfer_mgr_, other.allocators_) {} -const OrtMemoryInfo& OpKernelInfo::GetMemoryInfo(OrtMemType mem_type) const { - AllocatorPtr alloc = GetAllocator(mem_type); - if (alloc == nullptr) ORT_THROW("cannot find allocator"); - return alloc->Info(); +AllocatorPtr OpKernelInfo::GetAllocator(OrtMemType mem_type) const { + auto it = allocators_.find(execution_provider_->GetOrtDeviceByMemType(mem_type)); + if (it != allocators_.end()) return it->second; + return nullptr; } -AllocatorPtr OpKernelInfo::GetAllocator(OrtMemType mem_type) const { - return execution_provider_->GetAllocator(mem_type); +const OrtDevice OpKernelInfo::GetDevice(OrtMemType mem_type) const { + return execution_provider_->GetOrtDeviceByMemType(mem_type); } const KernelDef& OpKernelInfo::GetKernelDef() const { diff --git a/onnxruntime/core/framework/ort_value_pattern_planner.h b/onnxruntime/core/framework/ort_value_pattern_planner.h index 2db9c265bbb5f..947562f239be1 100644 --- a/onnxruntime/core/framework/ort_value_pattern_planner.h +++ b/onnxruntime/core/framework/ort_value_pattern_planner.h @@ -33,7 +33,7 @@ class OrtValuePatternPlanner { private: // This map itself is const after the construction // MemPatternPlanner has copying disabled to using node map - NodeHashMap planner_map_; + NodeHashMap planner_map_; const ExecutionPlanBase& execution_planner_; }; } // namespace onnxruntime diff --git a/onnxruntime/core/framework/partial_graph_execution_state.cc b/onnxruntime/core/framework/partial_graph_execution_state.cc index 4cc53feb26945..8a749008945c0 100644 --- a/onnxruntime/core/framework/partial_graph_execution_state.cc +++ b/onnxruntime/core/framework/partial_graph_execution_state.cc @@ -67,7 +67,7 @@ StreamExecutionContext& PartialGraphExecutionState::GetExecutionContext(gsl::spa const DeviceStreamCollection* device_streams) { if (execution_context_ == nullptr) { auto* execution_plan = session_state.GetExecutionPlan(); - LOGS(sess_logger, INFO) << "Number of streams: " << execution_plan->execution_plan.size(); + LOGS(sess_logger, VERBOSE) << "Number of streams: " << execution_plan->execution_plan.size(); int32_t valid_streams = 0; for (auto& stream : execution_plan->execution_plan) { if (stream && stream->steps_.size() > 0) diff --git a/onnxruntime/core/framework/prepacked_weights.h b/onnxruntime/core/framework/prepacked_weights.h index 41ef2631c94c8..fbf99b81937ee 100644 --- a/onnxruntime/core/framework/prepacked_weights.h +++ b/onnxruntime/core/framework/prepacked_weights.h @@ -16,8 +16,8 @@ struct PrePackedWeights final { // Hence we hold them in container. It is upto the developer implementing each PrePack() // method to define what gets stored in which position of the container. - std::vector> buffers_; // cache pre-packed buffers associated with the kernel - std::vector buffer_sizes_; // cache sizes of pre-packed buffers (in bytes) + std::vector> buffers_; // cache pre-packed buffers associated with the kernel + std::vector buffer_sizes_; // cache sizes of pre-packed buffers (in bytes) // Produces a hash of the buffers stored in the given instance of this class HashValue GetHash() const; diff --git a/onnxruntime/core/framework/prepacked_weights_container.cc b/onnxruntime/core/framework/prepacked_weights_container.cc index 8b6f146dffa2f..b6d44dd248bdd 100644 --- a/onnxruntime/core/framework/prepacked_weights_container.cc +++ b/onnxruntime/core/framework/prepacked_weights_container.cc @@ -2,7 +2,7 @@ // Licensed under the MIT License. #include "core/framework/prepacked_weights_container.h" -#include "core/framework/allocatormgr.h" +#include "core/framework/allocator_utils.h" namespace onnxruntime { diff --git a/onnxruntime/core/framework/print_tensor_statistics_utils.h b/onnxruntime/core/framework/print_tensor_statistics_utils.h new file mode 100644 index 0000000000000..fd036114f3e76 --- /dev/null +++ b/onnxruntime/core/framework/print_tensor_statistics_utils.h @@ -0,0 +1,151 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +#pragma once + +#include +#include "core/framework/print_tensor_utils.h" + +namespace onnxruntime { +namespace utils { + +template +int my_fpclassify(const T& val) { + return std::fpclassify(val); +} + +template <> +int my_fpclassify(const MLFloat16& val) { + return std::fpclassify(val.ToFloat()); +} + +template <> +int my_fpclassify(const BFloat16& val) { + return std::fpclassify(val.ToFloat()); +} + +template +void PrintFloatStats(const T* data, size_t count) { + size_t inf = 0; + size_t nan = 0; + size_t zero = 0; + size_t subnormal = 0; + for (size_t i = 0; i < count; i++) { + switch (my_fpclassify(*data)) { + case FP_INFINITE: + inf++; + break; + case FP_NAN: + nan++; + break; + case FP_SUBNORMAL: + subnormal++; + break; + case FP_ZERO: + zero++; + break; + default: + break; + } + } + + if (inf) + std::cout << ",Inf=" << inf; + if (nan) + std::cout << ",NaN=" << nan; + if (zero) + std::cout << ",Zero=" << zero; + if (subnormal) + std::cout << ",SubNormal=" << subnormal; +} + +template +void PrintCommonStats(const T* data, size_t count) { + T min = data[0]; + T max = min; + for (size_t i = 1; i < count; i++) { + auto value = data[i]; + if (value > max) { + max = value; + } + if (value < min) { + min = value; + } + } + + std::cout << "Min="; + PrintValue(min); + + std::cout << ",Max="; + PrintValue(max); +} + +template +void PrintHalfStats(const T* data, size_t count) { + float min = data[0].ToFloat(); + float max = min; + for (size_t i = 1; i < count; i++) { + float value = data[i].ToFloat(); + if (value > max) { + max = value; + } + + if (value < min) { + min = value; + } + } + + std::cout << "Min="; + PrintValue(min); + + std::cout << ",Max="; + PrintValue(max); +} + +template +void PrintTensorStats(const T* tensor, size_t count) { + PrintCommonStats(tensor, count); +} + +template <> +void PrintTensorStats(const float* tensor, size_t count) { + PrintCommonStats(tensor, count); + PrintFloatStats(tensor, count); +} + +template <> +void PrintTensorStats(const double* tensor, size_t count) { + PrintCommonStats(tensor, count); + PrintFloatStats(tensor, count); +} + +template <> +void PrintTensorStats(const MLFloat16* tensor, size_t count) { + PrintHalfStats(tensor, count); + PrintFloatStats(tensor, count); +} + +template <> +void PrintTensorStats(const BFloat16* tensor, size_t count) { + PrintHalfStats(tensor, count); + PrintFloatStats(tensor, count); +} + +template +void PrintCpuTensorStats(const Tensor& tensor) { + const auto& shape = tensor.Shape(); + auto num_items = shape.Size(); + if (num_items == 0) { + return; + } + + const T* data = tensor.Data(); + PrintTensorStats(data, num_items); + std::cout << std::endl; +} + +template <> +void PrintCpuTensorStats(const Tensor&) { +} + +} // namespace utils +} // namespace onnxruntime diff --git a/onnxruntime/core/framework/print_tensor_utils.h b/onnxruntime/core/framework/print_tensor_utils.h index 9509ca264677e..6bd4e2d3af3fd 100644 --- a/onnxruntime/core/framework/print_tensor_utils.h +++ b/onnxruntime/core/framework/print_tensor_utils.h @@ -139,9 +139,9 @@ void PrintCpuTensor(const Tensor& tensor, int threshold = kDefaultSnippetThresho bool is_snippet = (threshold > 0 && static_cast(threshold) < num_items); size_t num_dims = shape.NumDimensions(); if (num_dims >= 3) { - int dim0 = static_cast(shape.SizeToDimension(num_dims - 2)); - int dim1 = static_cast(shape[num_dims - 2]); - int dim2 = static_cast(shape[num_dims - 1]); + int64_t dim0 = shape.SizeToDimension(num_dims - 2); + int64_t dim1 = shape[num_dims - 2]; + int64_t dim2 = shape[num_dims - 1]; if (is_snippet) { PrintCpuTensorSnippet(data, dim0, dim1, dim2, edge_items); } else { @@ -150,11 +150,11 @@ void PrintCpuTensor(const Tensor& tensor, int threshold = kDefaultSnippetThresho return; } - size_t num_rows = 1; + int64_t num_rows = 1; if (num_dims > 1) { - num_rows = static_cast(shape[0]); + num_rows = shape[0]; } - size_t row_size = num_items / num_rows; + int64_t row_size = num_items / num_rows; if (is_snippet) { PrintCpuTensorSnippet(data, num_rows, row_size, edge_items); diff --git a/onnxruntime/core/framework/sequential_execution_plan.h b/onnxruntime/core/framework/sequential_execution_plan.h index 8806b0dccb3ed..3152154e52d7e 100644 --- a/onnxruntime/core/framework/sequential_execution_plan.h +++ b/onnxruntime/core/framework/sequential_execution_plan.h @@ -31,7 +31,7 @@ class SessionScope; struct AllocPlanPerValue { AllocKind alloc_kind{AllocKind::kNotSet}; MLDataType value_type{nullptr}; - OrtMemoryInfo location; + OrtDevice location; // reused_buffer is valid only if alloc_kind == kReuse. It indicates // which OrtValue's buffer must be reused for this OrtValue. OrtValueIndex reused_buffer{0}; @@ -79,7 +79,7 @@ struct AllocPlanPerValue { ProgramCounter program_counter; public: - AllocPlanPerValue() : location(CPU, OrtInvalidAllocator) {} + AllocPlanPerValue() : location() {} }; using NotificationIndex = size_t; @@ -126,10 +126,10 @@ struct SequentialExecutionPlan : public ExecutionPlanBase { // The steps within a sequence are executed in order, and happened on the same device. struct LogicStream { std::vector> steps_; - const OrtDevice& device_; + const OrtDevice device_; public: - LogicStream(const OrtDevice& device) : device_(device) {} + LogicStream(const OrtDevice device) : device_(device) {} }; // a execution plan is composed by multiple logic stream. // by default all the nodes with the same device will be group in to the same stream. @@ -178,16 +178,16 @@ struct SequentialExecutionPlan : public ExecutionPlanBase { return value_to_stream_map; } - const OrtMemoryInfo& GetLocation(size_t ort_value_index) const override { + const OrtDevice& GetLocation(size_t ort_value_index) const override { return allocation_plan[ort_value_index].location; } - void SetLocation(size_t ort_value_index, const struct OrtMemoryInfo& info) override { + void SetLocation(size_t ort_value_index, const struct OrtDevice& info) override { allocation_plan[ort_value_index].location = info; } - InlinedHashSet GetAllLocations() const override { - InlinedHashSet locations; + InlinedHashSet GetAllLocations() const override { + InlinedHashSet locations; locations.reserve(allocation_plan.size()); for (auto& alloc_plan : allocation_plan) { locations.insert(alloc_plan.location); diff --git a/onnxruntime/core/framework/session_options.h b/onnxruntime/core/framework/session_options.h index a72bc7938ac61..aff90b8d40bde 100644 --- a/onnxruntime/core/framework/session_options.h +++ b/onnxruntime/core/framework/session_options.h @@ -7,10 +7,11 @@ #include #include "core/common/gsl.h" #include "core/common/inlined_containers.h" +#include "core/framework/config_options.h" +#include "core/framework/ort_value.h" #include "core/session/onnxruntime_c_api.h" #include "core/optimizer/graph_transformer_level.h" #include "core/util/thread_utils.h" -#include "core/framework/config_options.h" #if !defined(ORT_MINIMAL_BUILD) || defined(ORT_MINIMAL_BUILD_CUSTOM_OPS) #include "core/framework/library_handles.h" diff --git a/onnxruntime/core/framework/session_state.cc b/onnxruntime/core/framework/session_state.cc index ab2be13579cc4..f0e5fbbd38721 100644 --- a/onnxruntime/core/framework/session_state.cc +++ b/onnxruntime/core/framework/session_state.cc @@ -69,7 +69,8 @@ SessionState::SessionState(Graph& graph, const logging::Logger& logger, profiling::Profiler& profiler, const SessionOptions& sess_options, - PrepackedWeightsContainer* prepacked_weights_container) + PrepackedWeightsContainer* prepacked_weights_container, + AllocatorMap* parent_allocators) : graph_(graph), execution_providers_(execution_providers), logger_(logger), @@ -86,45 +87,37 @@ SessionState::SessionState(Graph& graph, { enable_mem_pattern_ = sess_options_.enable_mem_pattern && sess_options_.execution_mode == ExecutionMode::ORT_SEQUENTIAL; - SetupAllocators(); -} - -void SessionState::SetupAllocators() { - for (const auto& provider : execution_providers_) { - for (const auto& allocator : provider->GetAllocators()) { - const OrtMemoryInfo& memory_info = allocator->Info(); - if (allocators_.find(memory_info) != allocators_.end()) { - // EPs are ordered by priority so ignore the duplicate allocator for this memory location. - LOGS(logger_, INFO) << "Allocator already registered for " << allocator->Info() - << ". Ignoring allocator from " << provider->Type(); - } else { - // slightly weird indirection to go back to the provider to get the allocator each time it's needed - // in order to support scenarios such as the CUDA EP's per-thread allocator. - allocators_[memory_info] = [&provider](OrtMemType mem_type) { - return provider->GetAllocator(mem_type); - }; + if (parent_allocators) { + allocators_ = parent_allocators; + } else { + allocators_unique_ptr_ = std::make_unique(); + allocators_ = allocators_unique_ptr_.get(); + // The allocator registration rule: + // Each location (OrtDevice) will only have 1 allocator used for whole session. + // The EP which is registered first will have higher priority + for (auto& ep : execution_providers_) { + auto allocators = ep->CreatePreferredAllocators(); + for (auto& alloc : allocators) { + allocators_->insert({alloc->Info().device, alloc}); // DONT overwrite existing key } } } } AllocatorPtr SessionState::GetAllocator(const OrtMemoryInfo& location) const noexcept { - AllocatorPtr result; - auto entry = allocators_.find(location); - if (entry != allocators_.cend()) { - result = entry->second(location.mem_type); - } + return GetAllocator(location.device); +} - return result; +AllocatorPtr SessionState::GetAllocator(const OrtDevice& device) const noexcept { + auto it = allocators_->find(device); + if (it != allocators_->end()) return it->second; + return nullptr; } -AllocatorPtr SessionState::GetAllocator(OrtDevice device) const noexcept { - for (const auto& iter : allocators_) { - if (iter.first.device == device) { - return iter.second(iter.first.mem_type); - } +void SessionState::UpdateAllocatorsWithEnvAllocators(const std::vector& env_allocators) { + for (const auto& env_alloc : env_allocators) { + (*allocators_)[env_alloc->Info().device] = env_alloc; } - return nullptr; } void SessionState::CreateGraphInfo() { @@ -484,7 +477,7 @@ Status SessionState::PrepackConstantInitializedTensors(InlinedHashMapInfo().GetAllocator(OrtMemType::OrtMemTypeDefault); + AllocatorPtr session_cpu_alloc = GetAllocator(kernel->Info().GetDevice(OrtMemType::OrtMemTypeDefault)); ORT_RETURN_IF_ERROR(kernel->PrePack(const_initialized_tensor, input_idx, session_cpu_alloc, // use allocator tied to this session is_packed, @@ -723,7 +716,7 @@ Status SessionState::GeneratePatternGroupCache(gsl::span tensor_ if (!ml_type->IsTensorType()) continue; - if (exe_plan->allocation_plan[ml_value_idx].location.mem_type != OrtMemType::OrtMemTypeDefault) + if (exe_plan->allocation_plan[ml_value_idx].location.MemType() != OrtDevice::MemType::DEFAULT) continue; const auto* ml_data_type = static_cast(ml_type)->GetElementType(); @@ -1037,7 +1030,10 @@ Status SessionState::CreateSubgraphSessionState() { for (auto& node : graph_.Nodes()) { for (auto& entry : node.GetAttributeNameToMutableSubgraphMap()) { const auto& ep = node.GetExecutionProviderType(); - if (!ep.empty() && ep != kCpuExecutionProvider && ep != kCudaExecutionProvider && ep != kRocmExecutionProvider) { + if (!ep.empty() && + ep != kCpuExecutionProvider && ep != kCudaExecutionProvider && + ep != kRocmExecutionProvider && ep != kDmlExecutionProvider && + ep != kJsExecutionProvider) { // 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; @@ -1050,7 +1046,7 @@ Status SessionState::CreateSubgraphSessionState() { auto subgraph_session_state = std::make_unique(*subgraph, execution_providers_, thread_pool_, inter_op_thread_pool_, data_transfer_mgr_, - logger_, profiler_, sess_options_); + logger_, profiler_, sess_options_, nullptr, allocators_); // Pass fused function manager to subgraph subgraph_session_state->fused_funcs_mgr_.SetFusedFuncs(fused_funcs_mgr_); @@ -1228,7 +1224,7 @@ static Status OuterScopeNodeArgLocationAccumulator(const SequentialExecutionPlan const OrtValueNameIdxMap& ort_value_name_to_idx_map, const Node& parent_node, const GraphViewer& subgraph, - /*out*/ InlinedHashMap& outer_scope_arg_to_location_map) { + /*out*/ InlinedHashMap& outer_scope_arg_to_location_map) { // Process implicit inputs to the node outer_scope_arg_to_location_map.reserve(parent_node.ImplicitInputDefs().size() + parent_node.InputDefs().size()); auto process_implicit_input = [&plan, &ort_value_name_to_idx_map, @@ -1324,7 +1320,7 @@ Status SessionState::FinalizeSessionStateImpl(const std::basic_string& constant_initializers_use_count, - const InlinedHashMap& outer_scope_node_arg_to_location_map, + const InlinedHashMap& outer_scope_node_arg_to_location_map, bool graph_info_already_created) { if (!graph_info_already_created) { CreateGraphInfo(); @@ -1372,7 +1368,7 @@ Status SessionState::FinalizeSessionStateImpl(const std::basic_stringRegisterStreamHandlers(GetStreamHandleRegistryInstance()); + ep->RegisterStreamHandlers(GetStreamHandleRegistryInstance(), *allocators_); } #endif @@ -1479,7 +1475,7 @@ Status SessionState::FinalizeSessionStateImpl(const std::basic_string Status { @@ -1539,7 +1535,7 @@ Status SessionState::FinalizeSessionStateImpl(const std::basic_string subgraph_outer_scope_node_arg_to_location_map; + InlinedHashMap subgraph_outer_scope_node_arg_to_location_map; ORT_RETURN_IF_ERROR(OuterScopeNodeArgLocationAccumulator(*p_seq_exec_plan_, GetOrtValueNameIdxMap(), node, subgraph_session_state.GetGraphViewer(), @@ -1594,7 +1590,7 @@ std::unique_ptr SessionState::AcquireDeviceStreamCollect device_stream_pool_.pop_back(); return device_stream; } else { - auto device_stream = std::make_unique(this->GetExecutionPlan()->execution_plan.size(), *this); + auto device_stream = std::make_unique(this->GetExecutionPlan()->execution_plan.size(), *allocators_, graph_viewer_->ParentNode() == nullptr); BindToDeviceStream(*this->GetExecutionPlan(), *device_stream, *stream_handles_registry_); return device_stream; } diff --git a/onnxruntime/core/framework/session_state.h b/onnxruntime/core/framework/session_state.h index e40e11fbd0a4c..51bb02918d82f 100644 --- a/onnxruntime/core/framework/session_state.h +++ b/onnxruntime/core/framework/session_state.h @@ -8,6 +8,8 @@ #include #include +#include "flatbuffers/flatbuffers.h" + #include "core/common/gsl.h" #include "core/common/common.h" @@ -43,12 +45,6 @@ #include "core/framework/program_region.h" #endif -namespace flatbuffers { -class FlatBufferBuilder; -template -struct Offset; -} // namespace flatbuffers - namespace onnxruntime { namespace fbs { @@ -99,7 +95,8 @@ class SessionState { const logging::Logger& logger, profiling::Profiler& profiler, const SessionOptions& sess_options, - PrepackedWeightsContainer* prepacked_weights_container = nullptr); + PrepackedWeightsContainer* prepacked_weights_container = nullptr, + AllocatorMap* parent_allocators = nullptr); ~SessionState() { for (auto& kvp : deleter_for_initialized_tensors_) { @@ -129,7 +126,14 @@ class SessionState { AllocatorPtr GetAllocator(const OrtMemoryInfo& location) const noexcept; /** Get the allocator for a given OrtDevice. The first allocator that matches will be returned. */ - AllocatorPtr GetAllocator(OrtDevice device) const noexcept; + AllocatorPtr GetAllocator(const OrtDevice& device) const noexcept; + + /* + * Get allocators. + */ + const AllocatorMap& GetAllocators() const { return *allocators_; } + + void UpdateAllocatorsWithEnvAllocators(const std::vector&); const OrtValueNameIdxMap& GetOrtValueNameIdxMap() const noexcept { return ort_value_name_idx_map_; } @@ -353,8 +357,6 @@ class SessionState { private: ORT_DISALLOW_COPY_ASSIGNMENT_AND_MOVE(SessionState); - void SetupAllocators(); - // Populate OrtValueNameIdxMap and create the graph viewer. void CreateGraphInfo(); @@ -388,7 +390,7 @@ class SessionState { const SessionOptions& session_options, bool remove_initializers, InlinedHashMap& constant_initializers_use_count, - const InlinedHashMap& outer_scope_node_arg_to_location_map = {}, + const InlinedHashMap& outer_scope_node_arg_to_location_map = {}, bool graph_info_already_created = false); #ifdef ENABLE_TRAINING @@ -438,22 +440,17 @@ class SessionState { } }; - // using std::map as OrtMemoryInfo would need a custom hash function to be used with std::unordered_map, + // using std::map as OrtDevice would need a custom hash function to be used with std::unordered_map, // and as this isn't considered performance critical currently it's not worth the maintenance overhead of adding one. // We do get an allocator from ExecutionFrame so this is looked up frequently, however there most likely aren't many // entries in the map - // - // NOTE: We store a delegate to get the allocator to support scenarios such as the CUDA EP where a thread_local - // allocator is returned. - // - // TODO: The CUDA EP may not need to use the per-thread allocator for allocations that would use this map - // (e.g. primarily from ExecutionFrame and utils::Copy{Inputs|Outputs}AcrossDevices). It does need it - // for internal allocations by CUDAExecutionProvider::GetScratchBuffer, but could access the per-thread allocator - // directly instead of going through CUDAExecutionProvider::GetAllocator. - // If that can be validated we could simply store the AllocatorPtr here and get rid of the delegate. - std::map, - OrtMemoryInfoLessThanIgnoreNameAndAllocType> - allocators_; + // SessionState will contain other SessionState objects for subgraph. The unique ptr will be initialized only the + // SessionState object is in the parent graph, the raw pointer will be initialized when session state is in parent + // graph (from the unique ptr) or in the subgraph (from the raw pointer from parent session state). The raw pointer + // will be used all the way to access std::map, unique pointer is only releasing the resource + // when the parent session state is releasing. + std::unique_ptr allocators_unique_ptr_; + AllocatorMap* allocators_; OrtValueNameIdxMap ort_value_name_idx_map_; diff --git a/onnxruntime/core/framework/session_state_utils.cc b/onnxruntime/core/framework/session_state_utils.cc index 0a1720b5b7aac..df3a7afebc176 100644 --- a/onnxruntime/core/framework/session_state_utils.cc +++ b/onnxruntime/core/framework/session_state_utils.cc @@ -217,7 +217,7 @@ common::Status SaveInitializedTensors( } else { const auto& planned_mem_info = exec_plan.GetLocation(ort_value_index); const auto& user_mem_info = it->second->Get().Location(); - retval = user_mem_info.device == planned_mem_info.device; + retval = user_mem_info.device == planned_mem_info; if (!retval) { LOGS(logger, WARNING) << "Cannot use user supplied initializer with name: (" << name << ") because the ORT planned memory location device " @@ -254,10 +254,11 @@ common::Status SaveInitializedTensors( auto initialized_tensors_to_allocate = id_to_initialized_tensor; for (int ort_value_index : initializer_allocation_order) { const auto entry = initialized_tensors_to_allocate.find(ort_value_index); - if (!(utils::HasExternalData(*entry->second) && exec_plan.GetLocation(ort_value_index).device.Type() == OrtDevice::CPU)) { + ORT_ENFORCE(entry != initialized_tensors_to_allocate.end(), + "OrtValue index: ", ort_value_index, " from initializer_allocation_order not found among initialized tensors"); + if (!(utils::HasExternalData(*entry->second) && exec_plan.GetLocation(ort_value_index).Type() == OrtDevice::CPU)) { // can not trace string tensor - ORT_ENFORCE(entry != initialized_tensors_to_allocate.end() && - entry->second->data_type() != ONNX_NAMESPACE::TensorProto_DataType_STRING); + ORT_ENFORCE(entry->second->data_type() != ONNX_NAMESPACE::TensorProto_DataType_STRING, "Can not trace string tensor"); ORT_RETURN_IF_ERROR(planner.Trace(entry->first, entry->second)); } initialized_tensors_to_allocate.erase(entry); @@ -277,7 +278,7 @@ common::Status SaveInitializedTensors( // 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. - InlinedHashMap planned_initializers_memory_sizes_in_byte; + InlinedHashMap planned_initializers_memory_sizes_in_byte; ORT_RETURN_IF_ERROR( planner.FinalizePlan(planned_initializers_memory_sizes_in_byte)); @@ -286,7 +287,7 @@ common::Status SaveInitializedTensors( for (auto i : planned_initializers_memory_sizes_in_byte) { LOGS(logger, INFO) << "[Memory] SessionStateInitializer statically allocates " - << i.second << " bytes for " << i.first << std::endl; + << i.second << " bytes for " << i.first.ToString() << std::endl; } OrtCallback deleter{nullptr, nullptr}; @@ -377,7 +378,7 @@ common::Status SaveInputOutputNamesToNodeMapping(const onnxruntime::GraphViewer& int arg_index; ORT_RETURN_IF_ERROR(name_to_id.GetIdx(arg.Name(), arg_index)); - const auto& device = exec_plan->GetLocation(arg_index).device; + const auto& device = exec_plan->GetLocation(arg_index); SessionState::NodeInfo node_info(index, &node, &kci, device); @@ -417,7 +418,7 @@ common::Status SaveInputOutputNamesToNodeMapping(const onnxruntime::GraphViewer& for (const auto& input_def : node_implicit_inputs) { int arg_index; ORT_RETURN_IF_ERROR(name_to_id.GetIdx(input_def->Name(), arg_index)); - auto& device = exec_plan->GetLocation(arg_index).device; + auto& device = exec_plan->GetLocation(arg_index); SessionState::NodeInfo node_info(std::numeric_limits::max(), &node, &kci, device); ORT_RETURN_IF_ERROR(session_state.AddInputNameToNodeInfoMapping(input_def->Name(), node_info)); } @@ -433,7 +434,7 @@ common::Status SaveInputOutputNamesToNodeMapping(const onnxruntime::GraphViewer& int arg_index; ORT_RETURN_IF_ERROR(name_to_id.GetIdx(arg.Name(), arg_index)); - const auto& device = exec_plan->GetLocation(arg_index).device; + const auto& device = exec_plan->GetLocation(arg_index); SessionState::NodeInfo node_info(index, &node, &kci, device); @@ -465,7 +466,7 @@ common::Status SaveInputOutputNamesToNodeMapping(const onnxruntime::GraphViewer& << name << " is not used by any node."; int arg_index; ORT_RETURN_IF_ERROR(name_to_id.GetIdx(name, arg_index)); - auto& device = exec_plan->GetLocation(arg_index).device; + auto& device = exec_plan->GetLocation(arg_index); SessionState::NodeInfo empty_node_info(std::numeric_limits::max(), nullptr, nullptr, device); ORT_RETURN_IF_ERROR(session_state.AddInputNameToNodeInfoMapping(name, empty_node_info)); } diff --git a/onnxruntime/core/framework/simple_tensor_allocator.cc b/onnxruntime/core/framework/simple_tensor_allocator.cc index 3d8a935c3b1ea..ad9e0393baa01 100644 --- a/onnxruntime/core/framework/simple_tensor_allocator.cc +++ b/onnxruntime/core/framework/simple_tensor_allocator.cc @@ -12,7 +12,7 @@ common::Status SimpleTensorAllocator::Trace(int /*id*/, const ONNX_NAMESPACE::Te common::Status SimpleTensorAllocator::GetPreallocatedBuffer(int ort_value_index, const std::string& /*name*/, std::optional& /*buf_out*/, AllocatorPtr& alloc_out) { - const struct OrtMemoryInfo& location = seq_plan_.GetLocation(ort_value_index); + const struct OrtDevice& location = seq_plan_.GetLocation(ort_value_index); // just return allocator and let others handle it. alloc_out = GetAllocator(location); return Status::OK(); diff --git a/onnxruntime/core/framework/simple_tensor_allocator.h b/onnxruntime/core/framework/simple_tensor_allocator.h index ecdee8a12f0b2..a27e16733554e 100644 --- a/onnxruntime/core/framework/simple_tensor_allocator.h +++ b/onnxruntime/core/framework/simple_tensor_allocator.h @@ -24,7 +24,7 @@ class SimpleTensorAllocator : public ITensorAllocator { : ITensorAllocator(session_state), seq_plan_(execution_plan) {} - common::Status FinalizePlan(InlinedHashMap& planned_memory_sizes_in_byte) override { + common::Status FinalizePlan(InlinedHashMap& planned_memory_sizes_in_byte) override { // There is no memory plan to allocate a big block of memory, so // planned memory sizes in different locations are all empty. planned_memory_sizes_in_byte.clear(); diff --git a/onnxruntime/core/framework/stream_execution_context.h b/onnxruntime/core/framework/stream_execution_context.h index 1815e0d1222d3..92a7b4fa5b283 100644 --- a/onnxruntime/core/framework/stream_execution_context.h +++ b/onnxruntime/core/framework/stream_execution_context.h @@ -46,7 +46,9 @@ class StreamExecutionContext { return v_.fetch_sub(1, std::memory_order_relaxed) == 1; } - int32_t Get() { return v_.load(std::memory_order_relaxed); } + int32_t Get() { + return gsl::narrow_cast(v_.load(std::memory_order_relaxed)); + } void Inc() { ++v_; diff --git a/onnxruntime/core/framework/tensor.cc b/onnxruntime/core/framework/tensor.cc index af3bad3085e4a..a9e5038e19e02 100644 --- a/onnxruntime/core/framework/tensor.cc +++ b/onnxruntime/core/framework/tensor.cc @@ -5,7 +5,6 @@ #include #include "core/common/safeint.h" -#include "core/framework/allocatormgr.h" #include "core/framework/data_types.h" #include "core/framework/ort_value.h" #include "core/framework/utils.h" diff --git a/onnxruntime/core/framework/tensor_allocator.cc b/onnxruntime/core/framework/tensor_allocator.cc index 868d3bfe2478a..9e81e8cd4783d 100644 --- a/onnxruntime/core/framework/tensor_allocator.cc +++ b/onnxruntime/core/framework/tensor_allocator.cc @@ -6,8 +6,8 @@ namespace onnxruntime { -AllocatorPtr ITensorAllocator::GetAllocator(const OrtMemoryInfo& memory_info) { - return session_state_.GetAllocator(memory_info); +AllocatorPtr ITensorAllocator::GetAllocator(const OrtDevice& device) { + return session_state_.GetAllocator(device); } std::unique_ptr ITensorAllocator::Create(bool enable_mem_pattern, diff --git a/onnxruntime/core/framework/tensor_allocator.h b/onnxruntime/core/framework/tensor_allocator.h index 2ab683bae7823..923320681e683 100644 --- a/onnxruntime/core/framework/tensor_allocator.h +++ b/onnxruntime/core/framework/tensor_allocator.h @@ -25,7 +25,7 @@ class ITensorAllocator { const SessionState& session_state, InlinedVector& weights_buffers); - AllocatorPtr GetAllocator(const OrtMemoryInfo& memory_info); + AllocatorPtr GetAllocator(const OrtDevice& device); /** * @@ -34,7 +34,7 @@ class ITensorAllocator { * When there is no more tensor to trace, call this function to finalize the * allocation. */ - virtual common::Status FinalizePlan(InlinedHashMap& planned_memory_sizes_in_byte) = 0; + virtual common::Status FinalizePlan(InlinedHashMap& planned_memory_sizes_in_byte) = 0; /** * Handing out buffers reserved in @see #Trace() via parameter buf_out, diff --git a/onnxruntime/core/framework/tensor_allocator_with_mem_pattern.h b/onnxruntime/core/framework/tensor_allocator_with_mem_pattern.h index fdfe179ad02c1..92c264e57279c 100644 --- a/onnxruntime/core/framework/tensor_allocator_with_mem_pattern.h +++ b/onnxruntime/core/framework/tensor_allocator_with_mem_pattern.h @@ -18,12 +18,12 @@ class TensorAllocatorWithMemPattern : public ITensorAllocator { OrtValuePatternPlanner planner_; MemoryPatternGroup mem_patterns_; InlinedVector& weights_buffers_; - InlinedHashMap buffers_; + InlinedHashMap buffers_; bool is_sealed_ = false; const ExecutionPlanBase& seq_plan_; common::Status AllocatePlannedBuffersAndReportTotalSize( - InlinedHashMap& planned_memory_sizes_in_byte) { + InlinedHashMap& planned_memory_sizes_in_byte) { const size_t location_len = mem_patterns_.locations.size(); planned_memory_sizes_in_byte.reserve(location_len); for (size_t i = 0; i < location_len; ++i) { @@ -54,7 +54,7 @@ class TensorAllocatorWithMemPattern : public ITensorAllocator { return Status(common::ONNXRUNTIME, common::FAIL, "duplicated location"); } - planned_memory_sizes_in_byte[location.name] += peak_size; + planned_memory_sizes_in_byte[location] += peak_size; } return Status::OK(); } @@ -67,7 +67,7 @@ class TensorAllocatorWithMemPattern : public ITensorAllocator { weights_buffers_(weights_buffers), seq_plan_(execution_plan) {} - common::Status FinalizePlan(InlinedHashMap& planned_memory_sizes_in_byte) override { + common::Status FinalizePlan(InlinedHashMap& planned_memory_sizes_in_byte) override { ORT_RETURN_IF_ERROR(planner_.GeneratePatterns(mem_patterns_)); ORT_RETURN_IF_ERROR(AllocatePlannedBuffersAndReportTotalSize(planned_memory_sizes_in_byte)); is_sealed_ = true; @@ -79,7 +79,7 @@ class TensorAllocatorWithMemPattern : public ITensorAllocator { if (!is_sealed_) { return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Internal error."); } - const struct OrtMemoryInfo& location = seq_plan_.GetLocation(ort_value_index); + const struct OrtDevice& location = seq_plan_.GetLocation(ort_value_index); auto pattern = mem_patterns_.GetPatterns(location); if (pattern == nullptr) { return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Mem pattern for initializer ", name, " is not found"); @@ -97,7 +97,7 @@ class TensorAllocatorWithMemPattern : public ITensorAllocator { if (it == buffers_.end()) { if (block != nullptr && block->size_ == 0) { // Because the size is 0, this miss find is expected. we won't allocate a buffer with size of zero. - buf_out.emplace(nullptr, 0, location); + buf_out.emplace(nullptr, 0, GetAllocator(location)->Info()); return Status::OK(); } return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Weight buffer for initializer '", name, "' is not found"); @@ -107,7 +107,7 @@ class TensorAllocatorWithMemPattern : public ITensorAllocator { return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Get preallocated buffer for initializer '", name, "' failed"); } - buf_out.emplace(reinterpret_cast(it->second) + block->offset_, block->size_, location); + buf_out.emplace(reinterpret_cast(it->second) + block->offset_, block->size_, GetAllocator(location)->Info()); return Status::OK(); } common::Status Trace(int id, const ONNX_NAMESPACE::TensorProto* value) override { diff --git a/onnxruntime/core/framework/tensor_type_and_shape.cc b/onnxruntime/core/framework/tensor_type_and_shape.cc index 1b73ed1d837b2..f3e1acbbe523d 100644 --- a/onnxruntime/core/framework/tensor_type_and_shape.cc +++ b/onnxruntime/core/framework/tensor_type_and_shape.cc @@ -18,9 +18,7 @@ #include "core/session/onnxruntime_c_api.h" #include "core/session/ort_apis.h" -using onnxruntime::BFloat16; using onnxruntime::DataTypeImpl; -using onnxruntime::MLFloat16; #if !defined(DISABLE_SPARSE_TENSORS) using onnxruntime::SparseTensor; #endif @@ -108,6 +106,18 @@ constexpr ONNXTensorElementDataType TensorDataTypeToOnnxRuntimeTensorElementData case o::TensorProto_DataType_DOUBLE: type = ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE; break; + case o::TensorProto_DataType_FLOAT8E4M3FN: + type = ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FN; + break; + case o::TensorProto_DataType_FLOAT8E4M3FNUZ: + type = ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FNUZ; + break; + case o::TensorProto_DataType_FLOAT8E5M2: + type = ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2; + break; + case o::TensorProto_DataType_FLOAT8E5M2FNUZ: + type = ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2FNUZ; + break; case o::TensorProto_DataType_FLOAT16: type = ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16; break; diff --git a/onnxruntime/core/framework/tensorprotoutils.cc b/onnxruntime/core/framework/tensorprotoutils.cc index 22faa67373780..08ed811d9ac38 100644 --- a/onnxruntime/core/framework/tensorprotoutils.cc +++ b/onnxruntime/core/framework/tensorprotoutils.cc @@ -20,51 +20,52 @@ #include "core/framework/callback.h" #include "core/framework/data_types.h" #include "core/platform/path_lib.h" +#include "core/framework/to_tensor_proto_element_type.h" #include "core/session/ort_apis.h" #include "onnx/defs/tensor_proto_util.h" using namespace ONNX_NAMESPACE; using namespace ::onnxruntime::common; +using namespace ::onnxruntime::utils; -// Provide template specializations for onnxruntime-specific types. -namespace ONNX_NAMESPACE { -template <> -TensorProto ToTensor(const onnxruntime::MLFloat16& value) { - TensorProto t; - t.set_data_type(TensorProto_DataType_FLOAT16); - t.add_int32_data(value.val); - return t; -} - -template <> -TensorProto ToTensor(const std::vector& values) { +TensorProto ToTensorInitialize(TensorProto_DataType datatype) { TensorProto t; t.clear_int32_data(); - t.set_data_type(TensorProto_DataType_FLOAT16); - for (const onnxruntime::MLFloat16& val : values) { - t.add_int32_data(val.val); - } + t.set_data_type(datatype); return t; } -template <> -TensorProto ToTensor(const onnxruntime::BFloat16& value) { - TensorProto t; - t.set_data_type(TensorProto_DataType_BFLOAT16); - t.add_int32_data(value.val); +TensorProto ToScalarTensor(TensorProto_DataType datatype, int32_t value) { + TensorProto t = ToTensorInitialize(datatype); + t.add_int32_data(value); return t; } -template <> -TensorProto ToTensor(const std::vector& values) { - TensorProto t; - t.clear_int32_data(); - t.set_data_type(TensorProto_DataType_BFLOAT16); - for (const onnxruntime::BFloat16& val : values) { - t.add_int32_data(val.val); +#define TO_TENSOR_ORT_TYPE(TYPE) \ + template <> \ + TensorProto ToTensor(const onnxruntime::TYPE& value) { \ + return ToScalarTensor(ToTensorProtoElementType(), value.val); \ + } \ + template <> \ + TensorProto ToTensor(const std::vector& values) { \ + TensorProto t = ToTensorInitialize(ToTensorProtoElementType()); \ + for (const onnxruntime::TYPE& val : values) { \ + t.add_int32_data(val.val); \ + } \ + return t; \ } - return t; -} + +namespace ONNX_NAMESPACE { + +// Provide template specializations for onnxruntime-specific types. +TO_TENSOR_ORT_TYPE(MLFloat16) +TO_TENSOR_ORT_TYPE(BFloat16) +#if !defined(DISABLE_FLOAT8_TYPES) +TO_TENSOR_ORT_TYPE(Float8E4M3FN) +TO_TENSOR_ORT_TYPE(Float8E4M3FNUZ) +TO_TENSOR_ORT_TYPE(Float8E5M2) +TO_TENSOR_ORT_TYPE(Float8E5M2FNUZ) +#endif bool operator==(const ONNX_NAMESPACE::TensorShapeProto_Dimension& l, const ONNX_NAMESPACE::TensorShapeProto_Dimension& r) { @@ -139,8 +140,8 @@ static Status GetExternalDataInfo(const ONNX_NAMESPACE::TensorProto& tensor_prot external_file_path = location; } else { if (tensor_proto_dir != nullptr) { - external_file_path = onnxruntime::ConcatPathComponent(tensor_proto_dir, - external_data_info->GetRelPath()); + external_file_path = onnxruntime::ConcatPathComponent(tensor_proto_dir, + external_data_info->GetRelPath()); } else { external_file_path = external_data_info->GetRelPath(); } @@ -230,6 +231,13 @@ INSTANTIATE_UNPACK_EXTERNAL_TENSOR(bool) INSTANTIATE_UNPACK_EXTERNAL_TENSOR(MLFloat16) INSTANTIATE_UNPACK_EXTERNAL_TENSOR(BFloat16) +#if !defined(DISABLE_FLOAT8_TYPES) +INSTANTIATE_UNPACK_EXTERNAL_TENSOR(Float8E4M3FN) +INSTANTIATE_UNPACK_EXTERNAL_TENSOR(Float8E4M3FNUZ) +INSTANTIATE_UNPACK_EXTERNAL_TENSOR(Float8E5M2) +INSTANTIATE_UNPACK_EXTERNAL_TENSOR(Float8E5M2FNUZ) +#endif + template <> Status UnpackTensorWithExternalData(const ONNX_NAMESPACE::TensorProto& /*tensor*/, const ORTCHAR_T* /*tensor_proto_dir*/, size_t /*expected_num_elements*/, @@ -362,7 +370,7 @@ Status UnpackTensor(const ONNX_NAMESPACE::TensorProto& tensor, const void* raw_d if (v < 0 || v > max_value) { return Status(common::ONNXRUNTIME, common::INVALID_ARGUMENT, "data overflow"); } - p_data[i] = MLFloat16(static_cast(v)); + p_data[i] = MLFloat16::FromBits(static_cast(v)); } return Status::OK(); @@ -403,6 +411,150 @@ Status UnpackTensor(const ONNX_NAMESPACE::TensorProto& tensor, const void* raw_d return Status::OK(); } +#if !defined(DISABLE_FLOAT8_TYPES) + +// UnpackTensor +template <> +Status UnpackTensor(const ONNX_NAMESPACE::TensorProto& tensor, const void* raw_data, size_t raw_data_len, + /*out*/ Float8E4M3FN* p_data, size_t expected_size) { + if (nullptr == p_data) { + const size_t size = raw_data != nullptr ? raw_data_len : tensor.int32_data_size(); + if (size == 0) + return Status::OK(); + + return Status(common::ONNXRUNTIME, common::INVALID_ARGUMENT); + } + if (ONNX_NAMESPACE::TensorProto_DataType_FLOAT8E4M3FN != tensor.data_type()) { + return Status(common::ONNXRUNTIME, common::INVALID_ARGUMENT); + } + + if (raw_data != nullptr) { + return UnpackTensorWithRawData(raw_data, raw_data_len, expected_size, p_data); + } + + if (static_cast(tensor.int32_data_size()) != expected_size) + return Status(common::ONNXRUNTIME, common::INVALID_ARGUMENT, + "UnpackTensor: the pre-allocate size does not match the size in proto"); + + constexpr int max_value = std::numeric_limits::max(); + for (int i = 0; i < static_cast(expected_size); i++) { + int v = tensor.int32_data()[i]; + if (v < 0 || v > max_value) { + return Status(common::ONNXRUNTIME, common::INVALID_ARGUMENT, "data overflow"); + } + p_data[i] = Float8E4M3FN(static_cast(v), Float8E4M3FN::FromBits()); + } + + return Status::OK(); +} + +// UnpackTensor +template <> +Status UnpackTensor(const ONNX_NAMESPACE::TensorProto& tensor, const void* raw_data, size_t raw_data_len, + /*out*/ Float8E4M3FNUZ* p_data, size_t expected_size) { + if (nullptr == p_data) { + const size_t size = raw_data != nullptr ? raw_data_len : tensor.int32_data_size(); + if (size == 0) + return Status::OK(); + + return Status(common::ONNXRUNTIME, common::INVALID_ARGUMENT); + } + if (ONNX_NAMESPACE::TensorProto_DataType_FLOAT8E4M3FNUZ != tensor.data_type()) { + return Status(common::ONNXRUNTIME, common::INVALID_ARGUMENT); + } + + if (raw_data != nullptr) { + return UnpackTensorWithRawData(raw_data, raw_data_len, expected_size, p_data); + } + + if (static_cast(tensor.int32_data_size()) != expected_size) + return Status(common::ONNXRUNTIME, common::INVALID_ARGUMENT, + "UnpackTensor: the pre-allocate size does not match the size in proto"); + + constexpr int max_value = std::numeric_limits::max(); + for (int i = 0; i < static_cast(expected_size); i++) { + int v = tensor.int32_data()[i]; + if (v < 0 || v > max_value) { + return Status(common::ONNXRUNTIME, common::INVALID_ARGUMENT, "data overflow"); + } + p_data[i] = Float8E4M3FNUZ(static_cast(v), Float8E4M3FNUZ::FromBits()); + } + + return Status::OK(); +} + +// UnpackTensor +template <> +Status UnpackTensor(const ONNX_NAMESPACE::TensorProto& tensor, const void* raw_data, size_t raw_data_len, + /*out*/ Float8E5M2* p_data, size_t expected_size) { + if (nullptr == p_data) { + const size_t size = raw_data != nullptr ? raw_data_len : tensor.int32_data_size(); + if (size == 0) + return Status::OK(); + + return Status(common::ONNXRUNTIME, common::INVALID_ARGUMENT); + } + if (ONNX_NAMESPACE::TensorProto_DataType_FLOAT8E5M2 != tensor.data_type()) { + return Status(common::ONNXRUNTIME, common::INVALID_ARGUMENT); + } + + if (raw_data != nullptr) { + return UnpackTensorWithRawData(raw_data, raw_data_len, expected_size, p_data); + } + + if (static_cast(tensor.int32_data_size()) != expected_size) + return Status(common::ONNXRUNTIME, common::INVALID_ARGUMENT, + "UnpackTensor: the pre-allocate size does not match the size in proto"); + + constexpr int max_value = std::numeric_limits::max(); + for (int i = 0; i < static_cast(expected_size); i++) { + int v = tensor.int32_data()[i]; + if (v < 0 || v > max_value) { + return Status(common::ONNXRUNTIME, common::INVALID_ARGUMENT, "data overflow"); + } + p_data[i] = Float8E5M2(static_cast(v), Float8E5M2::FromBits()); + } + + return Status::OK(); +} + +// UnpackTensor +template <> +Status UnpackTensor(const ONNX_NAMESPACE::TensorProto& tensor, const void* raw_data, size_t raw_data_len, + /*out*/ Float8E5M2FNUZ* p_data, size_t expected_size) { + if (nullptr == p_data) { + const size_t size = raw_data != nullptr ? raw_data_len : tensor.int32_data_size(); + if (size == 0) + return Status::OK(); + + return Status(common::ONNXRUNTIME, common::INVALID_ARGUMENT); + } + if (ONNX_NAMESPACE::TensorProto_DataType_FLOAT8E5M2FNUZ != tensor.data_type()) { + return Status(common::ONNXRUNTIME, common::INVALID_ARGUMENT); + } + + if (raw_data != nullptr) { + return UnpackTensorWithRawData(raw_data, raw_data_len, expected_size, p_data); + } + + if (static_cast(tensor.int32_data_size()) != expected_size) + return Status(common::ONNXRUNTIME, common::INVALID_ARGUMENT, + "UnpackTensor: the pre-allocate size does not match the size in proto"); + + constexpr int max_value = std::numeric_limits::max(); + for (int i = 0; i < static_cast(expected_size); i++) { + int v = tensor.int32_data()[i]; + if (v < 0 || v > max_value) { + return Status(common::ONNXRUNTIME, common::INVALID_ARGUMENT, "data overflow"); + } + p_data[i] = Float8E5M2FNUZ(static_cast(v), Float8E5M2FNUZ::FromBits()); + } + + return Status::OK(); +} + +#endif + // UnpackTensor from raw data, external data or the type specific data field. // Uses the model path to construct the full path for loading external data. In case when model_path is empty // it uses current directory. @@ -446,6 +598,13 @@ INSTANTIATE_UNPACK_TENSOR(MLFloat16) INSTANTIATE_UNPACK_TENSOR(BFloat16) INSTANTIATE_UNPACK_TENSOR(std::string) +#if !defined(DISABLE_FLOAT8_TYPES) +INSTANTIATE_UNPACK_TENSOR(Float8E4M3FN) +INSTANTIATE_UNPACK_TENSOR(Float8E4M3FNUZ) +INSTANTIATE_UNPACK_TENSOR(Float8E5M2) +INSTANTIATE_UNPACK_TENSOR(Float8E5M2FNUZ) +#endif + #define CASE_PROTO_TRACE(X, Y) \ case ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_##X: \ if (!IAllocator::CalcMemSizeForArrayWithAlignment(size, sizeof(Y), out)) { \ @@ -480,6 +639,12 @@ common::Status GetSizeInBytesFromTensorProto(const ONNX_NAMESPACE::TensorProto& CASE_PROTO_TRACE(FLOAT16, MLFloat16); CASE_PROTO_TRACE(BFLOAT16, BFloat16); CASE_PROTO_TRACE(STRING, std::string); +#if !defined(DISABLE_FLOAT8_TYPES) + CASE_PROTO_TRACE(FLOAT8E4M3FN, Float8E4M3FN); + CASE_PROTO_TRACE(FLOAT8E4M3FNUZ, Float8E4M3FNUZ); + CASE_PROTO_TRACE(FLOAT8E5M2, Float8E5M2); + CASE_PROTO_TRACE(FLOAT8E5M2FNUZ, Float8E5M2FNUZ); +#endif default: return common::Status(common::ONNXRUNTIME, common::NOT_IMPLEMENTED); } @@ -714,6 +879,12 @@ Status TensorProtoToTensor(const Env& env, const ORTCHAR_T* model_path, CASE_PROTO(UINT64, uint64_t); CASE_PROTO(FLOAT16, MLFloat16); CASE_PROTO(BFLOAT16, BFloat16); +#if !defined(DISABLE_FLOAT8_TYPES) + CASE_PROTO(FLOAT8E4M3FN, Float8E4M3FN); + CASE_PROTO(FLOAT8E4M3FNUZ, Float8E4M3FNUZ); + CASE_PROTO(FLOAT8E5M2, Float8E5M2); + CASE_PROTO(FLOAT8E5M2FNUZ, Float8E5M2FNUZ); +#endif case ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_STRING: ORT_RETURN_IF_ERROR(UnpackTensor(tensor_proto, raw_data, raw_data_len, static_cast(preallocated), @@ -789,6 +960,12 @@ ONNXTensorElementDataType CApiElementTypeFromProtoType(int type) { CASE_TYPE(COMPLEX64) CASE_TYPE(COMPLEX128) CASE_TYPE(BFLOAT16) +#if !defined(DISABLE_FLOAT8_TYPES) + CASE_TYPE(FLOAT8E4M3FN) + CASE_TYPE(FLOAT8E4M3FNUZ) + CASE_TYPE(FLOAT8E5M2) + CASE_TYPE(FLOAT8E5M2FNUZ) +#endif default: return ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED; } @@ -831,6 +1008,8 @@ ONNX_NAMESPACE::TensorProto TensorToTensorProto(const Tensor& tensor, const std: common::Status ConstantNodeProtoToTensorProto(const ONNX_NAMESPACE::NodeProto& node, const Path& model_path, ONNX_NAMESPACE::TensorProto& tensor, const std::string& tensor_name) { + ORT_RETURN_IF_NOT(node.attribute_size() > 0, "Constant node: ", node.name(), " has no data attributes"); + const AttributeProto& constant_attribute = node.attribute(0); switch (constant_attribute.type()) { @@ -1313,7 +1492,7 @@ Status UnpackInitializerData(const onnx::TensorProto& initializer, if (initializer.data_location() == TensorProto_DataLocation_EXTERNAL) { ORT_RETURN_IF_ERROR(ReadExternalDataForTensor( initializer, - model_path.IsEmpty() ? nullptr : model_path.ParentPath().ToPathString().c_str(), + (model_path.IsEmpty() || model_path.ParentPath().IsEmpty()) ? nullptr : model_path.ParentPath().ToPathString().c_str(), unpacked_tensor)); return Status::OK(); } @@ -1332,6 +1511,12 @@ Status UnpackInitializerData(const onnx::TensorProto& initializer, CASE_UNPACK(UINT64, uint64_t, uint64_data_size); CASE_UNPACK(FLOAT16, onnxruntime::MLFloat16, int32_data_size); CASE_UNPACK(BFLOAT16, onnxruntime::BFloat16, int32_data_size); +#if !defined(DISABLE_FLOAT8_TYPES) + CASE_UNPACK(FLOAT8E4M3FN, onnxruntime::Float8E4M3FN, int32_data_size); + CASE_UNPACK(FLOAT8E4M3FNUZ, onnxruntime::Float8E4M3FNUZ, int32_data_size); + CASE_UNPACK(FLOAT8E5M2, onnxruntime::Float8E5M2, int32_data_size); + CASE_UNPACK(FLOAT8E5M2FNUZ, onnxruntime::Float8E5M2FNUZ, int32_data_size); +#endif default: break; } diff --git a/onnxruntime/core/framework/transform_layout_functions.h b/onnxruntime/core/framework/transform_layout_functions.h index 2dd6f86c803eb..ef806170a52f8 100644 --- a/onnxruntime/core/framework/transform_layout_functions.h +++ b/onnxruntime/core/framework/transform_layout_functions.h @@ -10,7 +10,7 @@ class Graph; class IExecutionProvider; // Layout transformation related functions. -namespace layout_transformer { +namespace layout_transformation { // DebugGraphFn can be used to debug the graph modifications made during layout transformation. // See kDebugLayoutTransformation in /include/onnxruntime/core/session/onnxruntime_session_options_config_keys.h for // more details. @@ -23,5 +23,5 @@ using DebugGraphFn = std::function; // and used in layout transformation (core/optimizers/transpose_optimizer) using TransformLayoutFunction = std::function; -} // namespace layout_transformer +} // namespace layout_transformation } // namespace onnxruntime diff --git a/onnxruntime/core/framework/transpose_helper.cc b/onnxruntime/core/framework/transpose_helper.cc index a5535d919b642..38f68215a0484 100644 --- a/onnxruntime/core/framework/transpose_helper.cc +++ b/onnxruntime/core/framework/transpose_helper.cc @@ -1,8 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#include "core/framework/copy.h" +#include "core/framework/element_type_lists.h" #include "core/framework/transpose_helper.h" #include "core/mlas/inc/mlas.h" +#include "core/providers/cpu/tensor/utils.h" namespace onnxruntime { @@ -56,7 +59,8 @@ typename std::enable_if::value, void>::type SimpleTranspos // `input_shape_override` overrides the shape of `input` for compute purposes. void TransposeSingleAxisOutwards(gsl::span permutations, const Tensor& input, Tensor& output, - size_t from, size_t to, const TensorShape* input_shape_override = nullptr) { + size_t from, size_t to, const TensorShape* input_shape_override = nullptr, + concurrency::ThreadPool* tp = nullptr) { ORT_UNUSED_PARAMETER(permutations); const auto& input_shape = input_shape_override ? *input_shape_override : input.Shape(); @@ -100,25 +104,20 @@ void TransposeSingleAxisOutwards(gsl::span permutations, const Ten break; } default: { - // we need to use memcpy for each block - for (int64_t l = 0; l < num_loops; ++l) { - uint8_t* output_for_first_writer = output_data; + TensorPitches src_strides(input_dims); - for (auto wwpl = 0; wwpl < writes_per_writer_per_loop; ++wwpl) { - uint8_t* output_for_current_writer = output_for_first_writer; - - for (int64_t w = 0; w < num_writers; ++w) { - memcpy(output_for_current_writer, input_data, bytes_per_write); - // skip to output position for next writer - output_for_current_writer += (writes_per_writer_per_loop * bytes_per_write); - input_data += bytes_per_write; - } + TensorPitches contig_dst_strides(output); - output_for_first_writer += bytes_per_write; - } - - output_data += writes_per_loop * bytes_per_write; + const auto dims = input_dims.size(); + TensorShapeVector dst_strides(dims); + for (size_t dim = 0; dim < dims; ++dim) { + dst_strides[permutations[dim]] = contig_dst_strides[dim]; } + + ORT_THROW_IF_ERROR(DispatchStridedCopy(tp, + output, 0, dst_strides, + input_shape, + input, 0, src_strides)); } } } @@ -233,9 +232,9 @@ void TransposeSingleAxisInwards(gsl::span permutations, const Tens // `input_shape_override` overrides the shape of `input` for compute purposes. void SingleAxisTranspose(gsl::span permutations, const Tensor& input, Tensor& output, size_t from, - size_t to, const TensorShape* input_shape_override) { + size_t to, const TensorShape* input_shape_override, concurrency::ThreadPool* tp) { if (from > to) { - TransposeSingleAxisOutwards(permutations, input, output, from, to, input_shape_override); + TransposeSingleAxisOutwards(permutations, input, output, from, to, input_shape_override, tp); } else { TransposeSingleAxisInwards(permutations, input, output, from, to, input_shape_override); } diff --git a/onnxruntime/core/framework/transpose_helper.h b/onnxruntime/core/framework/transpose_helper.h index bb7a04d097174..c34d5ef3f27f6 100644 --- a/onnxruntime/core/framework/transpose_helper.h +++ b/onnxruntime/core/framework/transpose_helper.h @@ -35,11 +35,13 @@ We fall back to the default implementation in all other cases, and if the input #include "core/common/inlined_containers.h" #include "core/framework/tensor_shape.h" #include "core/framework/tensor.h" +#include "core/platform/threadpool.h" #include "core/common/gsl.h" namespace onnxruntime { bool IsTransposeMovingSingleAxis(gsl::span permutations, size_t& from, size_t& to); void SingleAxisTranspose(gsl::span permutations, const Tensor& input, Tensor& output, size_t from, - size_t to, const TensorShape* input_shape_override = nullptr); + size_t to, const TensorShape* input_shape_override = nullptr, + concurrency::ThreadPool* tp = nullptr); } // namespace onnxruntime diff --git a/onnxruntime/core/framework/tunable.h b/onnxruntime/core/framework/tunable.h index 7c4467d348745..96b4cc53a022c 100644 --- a/onnxruntime/core/framework/tunable.h +++ b/onnxruntime/core/framework/tunable.h @@ -24,28 +24,34 @@ #include "core/common/logging/logging.h" #endif #include "core/framework/execution_provider.h" +#include "core/framework/stream_handles.h" #include "core/framework/tuning_context.h" namespace onnxruntime { -template +template struct OpParams { OpParams() : tuning_ctx{nullptr}, stream{} {} - OpParams(TuningContextT* tuning_ctx, StreamT stream) : tuning_ctx(tuning_ctx), stream(stream) {} + OpParams(TuningContextT* tuning_ctx, Stream* stream) : tuning_ctx(tuning_ctx), stream(stream) {} virtual ~OpParams() = default; virtual std::string Signature() const = 0; - virtual StreamT Stream() const { return stream; } - virtual TuningContextT* TuningContext() const { return tuning_ctx; } + inline onnxruntime::Stream* Stream() const { return stream; } + inline TuningContextT* TuningContext() const { return tuning_ctx; } + inline NativeStreamT StreamHandle() const { + return nullptr != stream ? static_cast(stream->GetHandle()) : nullptr; + } // NOTE: the reason of TuningContext does not contains the Stream is that ORT now supports multiple stream and the // stream may change from call to call. TuningContextT* tuning_ctx; - StreamT stream; + onnxruntime::Stream* stream; }; template class ITimer { public: + using NativeStreamT = StreamT; + explicit ITimer(StreamT stream) : stream_{stream} {} virtual ~ITimer() = default; @@ -118,11 +124,12 @@ class Op { // NOTE: onnxruntime's Status currently does not have a StatusCode::UNSUPPORTED. Currently, we do not want to extend the // enum. So we reuse StatusCode::INVALID_ARGUMENT for this purpose. It can be interpreted as "The input argument is not // valid for this specialized kernel implementation.". This semantic is crucial for the tuning mechanism. -#define TUNABLE_OP_RETURN_UNSUPPORTED_ARGUMENT_IF(condition, ...) \ - do { \ - if (condition) { \ - return ORT_MAKE_STATUS(NONE, INVALID_ARGUMENT, __VA_ARGS__); \ - } \ +#define TUNABLE_OP_UNSUPPORTED(...) ORT_MAKE_STATUS(NONE, INVALID_ARGUMENT, __VA_ARGS__) +#define TUNABLE_OP_RETURN_UNSUPPORTED_ARGUMENT_IF(condition, ...) \ + do { \ + if (condition) { \ + return TUNABLE_OP_UNSUPPORTED(__VA_ARGS__); \ + } \ } while (false) template @@ -209,15 +216,14 @@ class TunableOp { private: static void WarmUp(Op& op, const ParamsT* param) { - constexpr const int num_iter = 4; + constexpr const int num_iter = 1; for (int i = 0; i < num_iter; i++) { ORT_THROW_IF_ERROR(op(param)); } } - static double Profile(Op& op, const ParamsT* param) { - constexpr const int num_iter = 100; - TimerT timer{param->Stream()}; + static double Profile(Op& op, const ParamsT* param, int num_iter) { + TimerT timer{param->StreamHandle()}; timer.Start(); for (int i = 0; i < num_iter; i++) { ORT_THROW_IF_ERROR(op(param)); @@ -242,12 +248,16 @@ class TunableOp { } int FindFastestImpl(const ParamsT* params, const std::vector>& candidates) { + ITuningContext* ctx = params->TuningContext(); auto op_sig = Signature(); auto param_sig = params->Signature(); LOGS_DEFAULT(VERBOSE) << "FindFastestImpl for " << op_sig << '(' << param_sig << ')'; auto min_time = std::numeric_limits::infinity(); int id = -1; + constexpr const int max_tuning_iter = 100; + constexpr const int approx_num_iter = 3; + for (size_t i = 0; i < candidates.size(); i++) { auto& candidate = const_cast&>(candidates[i]); if (!IsSupported(candidate, params)) { @@ -256,13 +266,23 @@ class TunableOp { } WarmUp(candidate, params); - auto time = Profile(candidate, params); + + auto approx_duration = Profile(candidate, params, approx_num_iter); + if (approx_duration > 2 * min_time) { + LOGS_DEFAULT(VERBOSE) << "FindFastestImpl skip slow instance " << op_sig << '(' << param_sig << ") id=" << i; + continue; + } + int tuning_iter = std::max(1, int(std::min(double(max_tuning_iter), ctx->GetMaxTuningDurationMs() / approx_duration))); + + LOGS_DEFAULT(VERBOSE) << "FindFastestImpl run instance " << op_sig << '(' << param_sig << ") id=" << i << " " << tuning_iter << " times."; + + auto time = Profile(candidate, params, tuning_iter); if (time < min_time) { min_time = time; id = static_cast(i); } } - ORT_ENFORCE(id >= 0, "Cannot found viable op"); + ORT_ENFORCE(id >= 0, "Could not find viable op"); LOGS_DEFAULT(VERBOSE) << "FindFastestImpl for " << op_sig << '(' << param_sig << ") found fastest with id=" << id; std::this_thread::sleep_for(std::chrono::milliseconds(50)); return id; diff --git a/onnxruntime/core/framework/tuning_context.h b/onnxruntime/core/framework/tuning_context.h index 3fea4cb85f750..aae70d85814bc 100644 --- a/onnxruntime/core/framework/tuning_context.h +++ b/onnxruntime/core/framework/tuning_context.h @@ -3,10 +3,12 @@ #pragma once +#include #include #include "core/common/common.h" #include "core/platform/ort_mutex.h" +#include "core/framework/allocator.h" #include "core/framework/tuning_results.h" namespace onnxruntime { @@ -28,6 +30,8 @@ class ITuningContext { virtual void DisableTuning() = 0; virtual bool IsTuningEnabled() const = 0; + virtual void SetMaxTuningDurationMs(int max_duration_ms) = 0; + virtual int GetMaxTuningDurationMs() const = 0; virtual void EnableTunableOpAndTuning() final { EnableTunableOp(); EnableTuning(); @@ -46,8 +50,11 @@ class ITuningContext { virtual TuningResults GetTuningResults() const; virtual Status LoadTuningResults(const TuningResults& tr); + void RegisterAllocatorsView(const AllocatorMap* allocators) { allocators_ = allocators; } + protected: IExecutionProvider* ep_; + const AllocatorMap* allocators_; }; class TuningResultsManager { diff --git a/onnxruntime/core/framework/utils.cc b/onnxruntime/core/framework/utils.cc index 52ff368d69051..b6dd8517341bb 100644 --- a/onnxruntime/core/framework/utils.cc +++ b/onnxruntime/core/framework/utils.cc @@ -22,9 +22,6 @@ #include "core/framework/TensorSeq.h" #include "core/framework/run_options.h" #include "core/session/onnxruntime_run_options_config_keys.h" -#ifdef USE_AZURE -#include "core/framework/cloud_executor.h" -#endif #ifdef ENABLE_TRAINING #include "core/framework/partial_graph_execution_state.h" #endif @@ -235,9 +232,9 @@ static bool HaveCpuExecutionProvidersOnly(const ExecutionProviders& execution_pr return true; } -static const OrtMemoryInfo& FindMemoryInfoForValue(const OrtValueNameIdxMap& map, - const SequentialExecutionPlan& plan, - std::string_view name) { +static const OrtDevice& FindDeviceForValue(const OrtValueNameIdxMap& map, + const SequentialExecutionPlan& plan, + std::string_view name) { int idx = -1; auto status = map.GetIdx(name, idx); ORT_THROW_IF_ERROR(status); @@ -246,12 +243,11 @@ static const OrtMemoryInfo& FindMemoryInfoForValue(const OrtValueNameIdxMap& map return location; } -const OrtMemoryInfo& FindMemoryInfoForValue(const SessionState& session_state, - std::string_view name) { +const OrtDevice& FindDeviceForValue(const SessionState& session_state, std::string_view name) { const auto* exec_plan_ptr = session_state.GetExecutionPlan(); ORT_ENFORCE(exec_plan_ptr); - return FindMemoryInfoForValue(session_state.GetOrtValueNameIdxMap(), *exec_plan_ptr, name); + return FindDeviceForValue(session_state.GetOrtValueNameIdxMap(), *exec_plan_ptr, name); } // get the target device info for the node consuming each input provided in the feeds. @@ -281,7 +277,7 @@ static common::Status CalculateStaticCopyInfoForFeed(const SessionState& session const auto& name_to_id = session_state.GetOrtValueNameIdxMap(); int index; ORT_RETURN_IF_ERROR(name_to_id.GetIdx(input_name, index)); - const auto& device = exec_plan->GetLocation(index).device; + const auto& device = exec_plan->GetLocation(index); copy_info.target_device = device; } #endif @@ -307,22 +303,8 @@ static common::Status CalculateStaticCopyInfoForFetches(const SessionState& sess for (size_t idx = 0, end = fetch_names.size(); idx < end; ++idx) { const std::string& output_name = fetch_names[idx]; - const auto& info = FindMemoryInfoForValue(session_state, output_name); - copy_info[idx].source_device = info.device; - - // If for some reason using just the device from the allocation plan isn't enough, the following - // would use the NodeInfo from the node producing the output - // - // std::vector node_info_vec; - // auto status = session_state.GetOutputNodeInfo(output_name, node_info_vec); - // if (status.IsOK()) { - // const auto& node_info = node_info_vec.front(); // only one entry as only one node can produce a given output - // copy_info[idx].source_device = *node_info.device; - //} else { - // // edge case where an initializer directly provides output so no NodeInfo involved - // const auto& info = FindMemoryInfoForValue(session_state, output_name); - // copy_info[idx].source_device = info.device; - //} + const auto& info = FindDeviceForValue(session_state, output_name); + copy_info[idx].source_device = info; } return Status::OK(); @@ -364,17 +346,17 @@ static bool FinalizeCopyInfoForFeeds(gsl::span feed_locations, return copy_needed; } -static bool FinalizeCopyInfoForFetches(gsl::span& fetch_alloc_info, +static bool FinalizeCopyInfoForFetches(gsl::span& fetch_alloc_info, std::vector& copy_info) { ORT_ENFORCE(fetch_alloc_info.size() == copy_info.size()); bool copy_needed = false; auto num_outputs = fetch_alloc_info.size(); for (size_t i = 0; i < num_outputs; ++i) { - const OrtMemoryInfo* alloc_info = fetch_alloc_info[i]; + const OrtDevice* alloc_info = fetch_alloc_info[i]; if (alloc_info != nullptr) { - copy_info[i].target_device = alloc_info->device; + copy_info[i].target_device = *alloc_info; } if (copy_info[i].source_device != copy_info[i].target_device) { @@ -389,7 +371,7 @@ static bool FinalizeCopyInfoForFetches(gsl::span& fe // This can be used by control flow nodes prior to the execution of the overall graph. void FinalizeFeedFetchCopyInfo(FeedsFetchesManager& feeds_fetches_manager, gsl::span feed_locations, - gsl::span fetch_alloc_info) { + gsl::span fetch_alloc_info) { if (feeds_fetches_manager.GetDeviceCopyChecks().status == DeviceCopyCheck::NoCopy) return; @@ -413,7 +395,7 @@ static void FinalizeFeedFetchCopyInfo(FeedsFetchesManager& feeds_fetches_manager auto num_outputs = feeds_fetches_manager.GetFeedsFetchesInfo().output_names.size(); std::vector feed_locations(num_inputs); - std::vector fetch_alloc_info(num_outputs, nullptr); + std::vector fetch_alloc_info(num_outputs, nullptr); for (size_t i = 0; i < num_inputs; ++i) { const auto& feed = feeds[i]; @@ -438,15 +420,15 @@ static void FinalizeFeedFetchCopyInfo(FeedsFetchesManager& feeds_fetches_manager const auto& fetch = fetches[i]; if (fetch.IsAllocated()) { if (fetch.IsTensor()) { - fetch_alloc_info[i] = &fetch.Get().Location(); + fetch_alloc_info[i] = &fetch.Get().Location().device; } else if (fetch.IsTensorSequence()) { const auto& tensor_seq = fetch.Get(); if (tensor_seq.Size() != std::size_t{0}) { - fetch_alloc_info[i] = &tensor_seq.Get(0).Location(); + fetch_alloc_info[i] = &tensor_seq.Get(0).Location().device; } } else if (fetch.IsSparseTensor()) { #if !defined(DISABLE_SPARSE_TENSORS) - fetch_alloc_info[i] = &fetch.Get().Location(); + fetch_alloc_info[i] = &fetch.Get().Location().device; #endif } } @@ -496,30 +478,14 @@ static common::Status CopyInputsAcrossDevices(const SessionState& session_state, // TODO: this sync is because the graph inputs can be consumed by multiple stream, // but we can only place the MemCpyAsync on one of the stream. Ideally we should make // other stream wait on the event of the memory copy stream, instead of host sync stream. + std::unordered_set visited; for (auto* stream : feed_streams) { - if (stream) - stream->Flush(); + if (stream && visited.insert(stream).second) stream->Flush(); } return Status::OK(); } #ifdef ORT_ENABLE_STREAM -struct DeviceStreamCollectionHolder { - DeviceStreamCollectionHolder( - const SessionState& session_state) : session_state_(session_state), - p_(session_state.AcquireDeviceStreamCollection()) { - } - - ~DeviceStreamCollectionHolder() { - if (p_) { - session_state_.RecycleDeviceStreamCollection(std::move(p_)); - } - } - - const SessionState& session_state_; - std::unique_ptr p_; -}; - static void UpdateWithParentStream(DeviceStreamCollection& device_stream_collection, Stream* parent_stream) { if (parent_stream) { @@ -566,7 +532,7 @@ common::Status CopyOneInputAcrossDevices(const SessionState& session_state, cons Stream* device_stream = nullptr; #ifdef ORT_ENABLE_STREAM - DeviceStreamCollectionHolder device_stream_collection_holder(session_state); + DeviceStreamCollectionHolder device_stream_collection_holder(&session_state); if (device_stream_collection_holder.p_ != nullptr) { DeviceStreamCollection* device_stream_collection = device_stream_collection_holder.p_.get(); size_t num_streams = device_stream_collection->NumStreams(); @@ -765,7 +731,10 @@ common::Status ExecuteGraph(const SessionState& session_state, FeedsFetchesManager& feeds_fetches_manager, gsl::span feeds, std::vector& fetches, ExecutionMode execution_mode, const bool& terminate_flag, - const logging::Logger& logger, bool sync_execution_provider, + const logging::Logger& logger, +#ifdef ORT_ENABLE_STREAM + DeviceStreamCollectionHolder& device_stream_collection_holder, +#endif bool only_execute_path_to_fetches, Stream* parent_stream) { ORT_RETURN_IF_ERROR(utils::InitializeFeedFetchCopyInfo(session_state, feeds_fetches_manager)); @@ -773,18 +742,14 @@ common::Status ExecuteGraph(const SessionState& session_state, // finalize the copy info using the provided feeds and fetches. will update device_copy_checks in the background FinalizeFeedFetchCopyInfo(feeds_fetches_manager, feeds, fetches); #ifdef ORT_ENABLE_STREAM - DeviceStreamCollectionHolder device_stream_collection_holder(session_state); DeviceStreamCollection* device_stream_collection = device_stream_collection_holder.p_.get(); auto retval = ExecuteGraphImpl(session_state, feeds_fetches_manager, feeds, fetches, {}, execution_mode, terminate_flag, logger, device_stream_collection, only_execute_path_to_fetches, parent_stream); - if (device_stream_collection) - ORT_CHECK_AND_SET_RETVAL(device_stream_collection->CleanUp(sync_execution_provider)); return retval; #else - ORT_UNUSED_PARAMETER(sync_execution_provider); return ExecuteGraphImpl(session_state, feeds_fetches_manager, feeds, fetches, {}, execution_mode, terminate_flag, logger, only_execute_path_to_fetches, @@ -796,26 +761,19 @@ common::Status ExecuteGraph(const SessionState& session_state, FeedsFetchesManager& feeds_fetches_manager, gsl::span feeds, std::vector& fetches, ExecutionMode execution_mode, const RunOptions& run_options, - const logging::Logger& logger) { -#ifdef USE_AZURE - const auto iter = run_options.config_options.configurations.find("use_azure"); - if (iter != run_options.config_options.configurations.end() && iter->second != "0") { - CloudExecutor cloud_executor(run_options.config_options.configurations); - const auto& feeds_fetches_info = feeds_fetches_manager.GetFeedsFetchesInfo(); - return cloud_executor.Execute(session_state, - feeds_fetches_info.feeds_mlvalue_idxs, feeds, - feeds_fetches_info.fetches_mlvalue_idxs, fetches, {}, - logger); - } +#ifdef ORT_ENABLE_STREAM + DeviceStreamCollectionHolder& device_stream_collection_holder, #endif - bool synchronize_execution_providers = run_options.config_options.GetConfigOrDefault(kOrtRunOptionsConfigDisableSynchronizeExecutionProviders, "0") == "0"; + const logging::Logger& logger) { return ExecuteGraph(session_state, feeds_fetches_manager, feeds, fetches, execution_mode, run_options.terminate, logger, - synchronize_execution_providers, +#ifdef ORT_ENABLE_STREAM + device_stream_collection_holder, +#endif run_options.only_execute_path_to_fetches); } @@ -961,7 +919,7 @@ common::Status ExecuteSubgraph(const SessionState& session_state, const FeedsFet Stream* parent_stream, bool sync_subgraph_fetches) { #ifdef ORT_ENABLE_STREAM - DeviceStreamCollectionHolder device_stream_collection_holder(session_state); + DeviceStreamCollectionHolder device_stream_collection_holder(&session_state); DeviceStreamCollection* device_stream_collection = device_stream_collection_holder.p_.get(); auto retval = ExecuteGraphImpl(session_state, feeds_fetches_manager, feeds, fetches, fetch_allocators, diff --git a/onnxruntime/core/framework/utils.h b/onnxruntime/core/framework/utils.h index bd1a6b2bf6b39..ea6a629f87cb8 100644 --- a/onnxruntime/core/framework/utils.h +++ b/onnxruntime/core/framework/utils.h @@ -66,8 +66,7 @@ common::Status CopyOneInputAcrossDevices(const SessionState& session_state, cons const OrtValue& orig_mlvalue, OrtValue& new_mlvalue); // Searches the allocation plan from the session_state to find the OrtMemoryInfo for the value 'name'. -const OrtMemoryInfo& FindMemoryInfoForValue(const SessionState& session_state, - std::string_view name); +const OrtDevice& FindDeviceForValue(const SessionState& session_state, std::string_view name); // Initialize the feed and fetch copy info using session_state. // Determines the device that each graph input that will be fed will be consumed on, @@ -79,19 +78,25 @@ common::Status InitializeFeedFetchCopyInfo(const SessionState& session_state, // and fetches that will be used in graph execution. void FinalizeFeedFetchCopyInfo(FeedsFetchesManager& feeds_fetches_manager, gsl::span feed_locations, - gsl::span fetch_alloc_info); + gsl::span fetch_alloc_info); // Execute the main graph. The feed_fetches_manager will be finalized based on the provided feeds and fetches. common::Status ExecuteGraph(const SessionState& session_state, FeedsFetchesManager& feeds_fetches_manager, gsl::span feeds, std::vector& fetches, ExecutionMode execution_mode, const bool& terminate_flag, const logging::Logger& logger, - bool sync_execution_provider, +#ifdef ORT_ENABLE_STREAM + DeviceStreamCollectionHolder& device_stream_collection_holder, +#endif bool only_execute_path_to_fetches = false, Stream* parent_stream = nullptr); common::Status ExecuteGraph(const SessionState& session_state, FeedsFetchesManager& feeds_fetches_manager, gsl::span feeds, std::vector& fetches, - ExecutionMode execution_mode, const RunOptions& run_options, const logging::Logger& logger); + ExecutionMode execution_mode, const RunOptions& run_options, +#ifdef ORT_ENABLE_STREAM + DeviceStreamCollectionHolder& device_stream_collection_holder, +#endif + const logging::Logger& logger); #ifdef ENABLE_TRAINING common::Status ExecutePartialGraph(const SessionState& session_state, FeedsFetchesManager& feeds_fetches_manager, @@ -192,9 +197,33 @@ constexpr ONNXTensorElementDataType GetONNXTensorElementDataType() { return ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT64; } +#if !defined(DISABLE_FLOAT8_TYPES) + +template <> +constexpr ONNXTensorElementDataType GetONNXTensorElementDataType() { + return ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FN; +} + +template <> +constexpr ONNXTensorElementDataType GetONNXTensorElementDataType() { + return ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FNUZ; +} + +template <> +constexpr ONNXTensorElementDataType GetONNXTensorElementDataType() { + return ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2; +} + +template <> +constexpr ONNXTensorElementDataType GetONNXTensorElementDataType() { + return ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E5M2FNUZ; +} + +#endif + int32_t ONNXTensorElementDataTypeToProtoTensorType(ONNXTensorElementDataType); -#ifdef ENABLE_TRAINING_CORE +#ifdef ENABLE_TRAINING common::Status VerifyInputTensorsAllocatedContiguously(OpKernelContext* context); #endif diff --git a/onnxruntime/core/graph/contrib_ops/attn_lstm_schema_defs.h b/onnxruntime/core/graph/contrib_ops/attn_lstm_schema_defs.h index 59f451f756190..9af74fcab1515 100644 --- a/onnxruntime/core/graph/contrib_ops/attn_lstm_schema_defs.h +++ b/onnxruntime/core/graph/contrib_ops/attn_lstm_schema_defs.h @@ -3,13 +3,7 @@ #pragma once -#if !defined(ORT_MINIMAL_BUILD) -#include "onnx/defs/schema.h" -#else -#include "onnx/defs/data_type_utils.h" -#endif -#include "onnx/onnx_pb.h" -#include "onnx/onnx-operators_pb.h" +#include "core/graph/onnx_protobuf.h" namespace onnxruntime { namespace contrib { diff --git a/onnxruntime/core/graph/contrib_ops/bert_defs.cc b/onnxruntime/core/graph/contrib_ops/bert_defs.cc index 3767cb8b0a5fe..e5956a575d73d 100644 --- a/onnxruntime/core/graph/contrib_ops/bert_defs.cc +++ b/onnxruntime/core/graph/contrib_ops/bert_defs.cc @@ -125,7 +125,9 @@ void RestorePaddingTypeAndShapeInference(ONNX_NAMESPACE::InferenceContext& ctx) } } -void MultiHeadAttentionTypeAndShapeInference(ONNX_NAMESPACE::InferenceContext& ctx, int past_input_index) { +void MultiHeadAttentionTypeAndShapeInference(ONNX_NAMESPACE::InferenceContext& ctx, + int past_key_index, + bool dmmha_packing = false) { // Output 0 has shape (batch_size, sequence_length, v_hidden_size) // Q, K and V without packing: @@ -144,7 +146,9 @@ void MultiHeadAttentionTypeAndShapeInference(ONNX_NAMESPACE::InferenceContext& c // Input 2 nullptr // Packed QKV: - // Input 0 (batch_size, sequence_length, num_heads, 3, head_size) + // Input 0 (batch_size, sequence_length, num_heads, 3, head_size) or + // (batch_size, sequence_length, 3 * hidden_size)) + // for DecoderMaskedMultiHeadAttention. // Input 1 nullptr // Input 2 nullptr @@ -184,7 +188,9 @@ void MultiHeadAttentionTypeAndShapeInference(ONNX_NAMESPACE::InferenceContext& c ONNX_NAMESPACE::TensorShapeProto output_shape; *output_shape.add_dim() = query_dims[0]; *output_shape.add_dim() = query_dims[1]; - *output_shape.add_dim() = value_dims.size() == 3 ? value_dims[2] : value_dims[1] * value_dims[3]; + *output_shape.add_dim() = value_dims.size() == 3 + ? (dmmha_packing ? value_dims[2] / 3 : value_dims[2]) + : value_dims[1] * value_dims[3]; updateOutputShape(ctx, 0, output_shape); return; } @@ -198,17 +204,17 @@ void MultiHeadAttentionTypeAndShapeInference(ONNX_NAMESPACE::InferenceContext& c } if (ctx.getNumOutputs() > 1) { // has present output - if (hasInputShape(ctx, past_input_index)) { - auto& past_shape = getInputShape(ctx, past_input_index); + if (hasInputShape(ctx, past_key_index)) { + auto& past_shape = getInputShape(ctx, past_key_index); auto& past_dims = past_shape.dim(); if (past_dims.size() != 4) { - fail_shape_inference("The past input shall be 5 dimensions"); + fail_shape_inference("The past_key input shall be 4 dimensions"); } auto past_present_share_buffer = getAttribute(ctx, "past_present_share_buffer", 0); if (past_present_share_buffer) { - propagateElemTypeFromInputToOutput(ctx, past_input_index, 1); - propagateElemTypeFromInputToOutput(ctx, static_cast(past_input_index) + 1, 2); + propagateElemTypeFromInputToOutput(ctx, past_key_index, 1); + propagateElemTypeFromInputToOutput(ctx, static_cast(past_key_index) + 1, 2); } else { if (sequence_length > 0 && past_dims[2].has_dim_value()) { int64_t total_sequence_length = sequence_length + past_shape.dim(3).dim_value(); @@ -476,6 +482,135 @@ ONNX_MS_OPERATOR_SET_SCHEMA( PackedAttentionTypeAndShapeInference(ctx); })); +constexpr const char* PackedMultiHeadAttention_ver1_doc = R"DOC( +This is the packed version of MultiHeadAttention. + +Sequences in one batch usually don't have same length and they are padded to have same length, +e.g., below is a batch with 3 sequences and * is padding token. + Sequence_0: 0, 1*, 2*, 3* + Sequence_1: 4, 5, 6*, 7* + Sequence_2: 8, 9, 10, 11 + +PackedMultiHeadAttention is designed to takes in packed input, i.e., only the real tokens without padding. +An input as above will be packed into 3 tensors like below: + - query ([q0, q4, q5, q8, q9, q10, q11]) + - key ([k0, k4, k5, k8, k9, k10, k11]) + - value ([v0, v4, v5, v8, v9, v10, v11]) + - token_offset: 0, 4, 5, 8, 9, 10, 11, 1*, 2*, 3*, 6*, 7* + - cumulative_sequence_length: 0, 1, 1+2, 1+2+4 + +The query, key and value tensors contain result of hidden embedding of real tokens after input projections. +Token_offset records the offset of token in the unpacked input. +cumulative_sequence_length records cumulated length of each sequnces length. + +The operator only supports BERT like model with padding on right now. +)DOC"; + +// Shape inference for PackedMultiHeadAttention. Here are the shapes of inputs and output: +// When Q, K and V are not packed: +// Input 'query': (token_count, hidden_size) +// Input 'key': (token_count, hidden_size) +// Input 'value': (token_count, v_hidden_size) +// When Q, K and V are packed: +// Input 'query': (token_count, num_heads, 3, head_size) +// Input 'key': None +// Input 'value': None +// Input 'bias': (hidden_size + hidden_size + v_hidden_size) +// Input 'token_offset': (batch_size, sequence_length) +// Input 'cumulative_sequence_length': (batch_size + 1) +// Input 'relative_position_bias': (batch_size or 1, num_heads, sequence_length, sequence_length) or None +// Output 'output': (token_count, v_hidden_size) +void PackedMultiHeadAttentionTypeAndShapeInference(ONNX_NAMESPACE::InferenceContext& ctx) { + // Type inference + ONNX_NAMESPACE::propagateElemTypeFromInputToOutput(ctx, 0, 0); + + // Shape inference + if (hasInputShape(ctx, 0)) { + auto& query_shape = getInputShape(ctx, 0); + auto& query_dims = query_shape.dim(); + + if (query_dims.size() != 2 && query_dims.size() != 4) { + fail_shape_inference("Inputs 0 (query) shall be 2 or 4 dimensions"); + } + + if (query_dims.size() == 4) { // packed QKV + ONNX_NAMESPACE::TensorShapeProto output_shape; + *output_shape.add_dim() = query_dims[0]; + *output_shape.add_dim() = query_dims[1] * query_dims[3]; + updateOutputShape(ctx, 0, output_shape); + return; + } + + if (hasInputShape(ctx, 2)) { + auto& value_shape = getInputShape(ctx, 2); + auto& value_dims = value_shape.dim(); + if (value_dims.size() != 2) { + fail_shape_inference("Inputs 2 (value) shall be 2 dimensions"); + } + + ONNX_NAMESPACE::TensorShapeProto output_shape; + *output_shape.add_dim() = query_dims[0]; + *output_shape.add_dim() = value_dims[1]; + updateOutputShape(ctx, 0, output_shape); + return; + } + } +} + +ONNX_MS_OPERATOR_SET_SCHEMA( + PackedMultiHeadAttention, 1, + OpSchema() + .SetDoc(PackedMultiHeadAttention_ver1_doc) + .Attr("num_heads", "Number of attention heads", AttributeProto::INT) + .Attr("mask_filter_value", "The value to be filled in the attention mask. Default value is -10000.0f", + AttributeProto::FLOAT, OPTIONAL_VALUE) + .Attr("scale", + "Custom scale will be used if specified. Default value is 1/sqrt(head_size)", + AttributeProto::FLOAT, + OPTIONAL_VALUE) + .Input(0, + "query", + "Query with shape (token_count, hidden_size) or packed qkv with shape (token_count, num_heads, 3, head_size)", + "T") + .Input(1, + "key", + "Key with shape (token_count, hidden_size)", + "T", + OpSchema::Optional) + .Input(2, + "value", + "Value with shape (token_count, v_hidden_size)", + "T", + OpSchema::Optional) + .Input(3, + "bias", + "Bias tensor with shape (hidden_size + hidden_size + v_hidden_size) from input projection", + "T", + OpSchema::Optional) + .Input(4, + "token_offset", + "Offset of each token before packing, with shape (batch_size, sequence_length).", + "M") + .Input(5, + "cumulative_sequence_length", + "A tensor with shape (batch_size + 1). It specifies the cumulative sequence length.", + "M") + .Input(6, + "relative_position_bias", + "It specifies the additional bias to QxK'. The shape is (batch_size, num_heads, sequence_length, sequence_length)" + " or (1, num_heads, sequence_length, sequence_length)", + "T", + OpSchema::Optional) + .Output(0, + "output", + "output tensor with shape (token_count, v_hidden_size)", + "T") + .TypeConstraint("T", {"tensor(float)", "tensor(float16)"}, "Constrain input and output to float tensors.") + .TypeConstraint("M", {"tensor(int32)"}, "Constrain mask, offset and sequence length to integer types") + .TypeAndShapeInferenceFunction([](ONNX_NAMESPACE::InferenceContext& ctx) { + PackedMultiHeadAttentionTypeAndShapeInference(ctx); + })); + constexpr const char* DecoderMaskedSelfAttention_ver1_doc = R"DOC( Self attention that supports input sequence length of 1. @@ -511,6 +646,10 @@ ONNX_MS_OPERATOR_SET_SCHEMA( "The value to be filled in the attention mask. Default value is -10000.0f", AttributeProto::FLOAT, OPTIONAL_VALUE) + .Attr("do_rotary", + "Whether to use rotary position embedding. Default value is 0.", + AttributeProto::INT, + OPTIONAL_VALUE) .Input(0, "input", "Input tensor with shape (batch_size, 1, input_hidden_size)", @@ -609,18 +748,21 @@ ONNX_MS_OPERATOR_SET_SCHEMA( OPTIONAL_VALUE) .Input(0, "query", - "Query with shape (batch_size, 1, hidden_size)", + "Query with shape (batch_size, 1, hidden_size) or packed QKV with shape " + "(batch_size, 1, 2 * hidden_size + v_hidden_size)", "T") .Input(1, "key", "Key with shape (batch_size, 1, hidden_size) for self attention " "or past_key with shape (batch_size, num_heads, kv_sequence_length, head_size) for cross attention", - "T") + "T", + OpSchema::Optional) .Input(2, "value", "Value with shape (batch_size, 1, v_hidden_size) for self attention " "or past_value with shape (batch_size, num_heads, kv_sequence_length, head_size) for cross attention", - "T") + "T", + OpSchema::Optional) .Input(3, "mask_index", "Mask values of shape (batch_size, total_sequence_length) or (batch_size, kv_sequence_length)", @@ -636,6 +778,8 @@ 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 + // 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 " "(batch_size, num_heads, max_sequence_length, head_size / x, x) is reordered to " @@ -663,10 +807,16 @@ ONNX_MS_OPERATOR_SET_SCHEMA( OpSchema::Optional) .Input(9, "cache_indirection", + // This input is useful for CUDA EP only. "A buffer of shape [batch_size, beam_width, max_output_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) + .Input(10, + "bias", + "Bias tensor with shape (hidden_size + hidden_size + v_hidden_size) from input projection", + "T", + OpSchema::Optional) .Output(0, "output", "3D output tensor with shape (batch_size, sequence_length, v_hidden_size)", @@ -694,7 +844,8 @@ ONNX_MS_OPERATOR_SET_SCHEMA( {"tensor(int32)"}, "Constrain mask index to integer types") .TypeAndShapeInferenceFunction([](ONNX_NAMESPACE::InferenceContext& ctx) { - MultiHeadAttentionTypeAndShapeInference(ctx, 5); + bool is_dmmha_packing = !hasInputShape(ctx, 1) && !hasInputShape(ctx, 2); + MultiHeadAttentionTypeAndShapeInference(ctx, 5, is_dmmha_packing); })); constexpr const char* MultiHeadAttention_ver1_doc = R"DOC( @@ -855,6 +1006,7 @@ ONNX_MS_OPERATOR_SET_SCHEMA( OpSchema() .SetDoc(EmbedLayerNormalization_ver1_doc) .Attr("epsilon", "The epsilon value to use to avoid division by zero.", AttributeProto::FLOAT, kDefaultEmbedLayerNormEpsilon) + .Attr("mask_index_type", "The mask index tensor type for shape inference (0: None, 1: 1D mask_index)", AttributeProto::INT, OPTIONAL_VALUE) .Input(0, "input_ids", "2D words IDs with shape (batch_size, sequence_length)", "T1") .Input(1, "segment_ids", "2D segment IDs with shape (batch_size, sequence_length)", "T1", OpSchema::Optional) .Input(2, "word_embedding", "2D with shape (,hidden_size)", "T") @@ -865,7 +1017,7 @@ ONNX_MS_OPERATOR_SET_SCHEMA( .Input(7, "mask", "2D attention mask with shape (batch_size, sequence_length)", "T1", OpSchema::Optional) .Input(8, "position_ids", "2D position ids with shape (batch_size, sequence_length) or (1, sequence_length)", "T1", OpSchema::Optional) .Output(0, "output", "3D output tensor with shape (batch_size, sequence_length, hidden_size)", "T") - .Output(1, "mask_index", "1D mask_index tensor with shape (batch_size)", "T1") + .Output(1, "mask_index", "1D mask_index tensor with shape (batch_size)", "T1", OpSchema::Optional) .Output(2, "embedding_sum", "sum of word_embedding and position_embedding without layer normalization", "T", OpSchema::Optional) .TypeConstraint("T1", {"tensor(int32)"}, "Constrain input and output integer tensors types") .TypeConstraint("T", {"tensor(float)", "tensor(float16)"}, "Constrain input and output float tensors types.") @@ -945,7 +1097,7 @@ ONNX_MS_OPERATOR_SET_SCHEMA( .SetDoc("Skip and Layer Normalization Fusion") .Attr("epsilon", "The epsilon value to use to avoid division by zero.", AttributeProto::FLOAT, kDefaultSkipLayerNormEpsilon) .Input(0, "input", "3D input tensor with shape (batch_size, sequence_length, hidden_size)", "T") - .Input(1, "skip", "3D skip tensor with shape (batch_size, sequence_length, hidden_size)", "T") + .Input(1, "skip", "3D skip tensor with shape (batch_size, sequence_length, hidden_size) or (1, sequence_length, hidden_size) or (sequence_length, hidden_size)", "T") .Input(2, "gamma", "1D input tensor with shape (hidden_size)", "T") .Input(3, "beta", "1D skip tensor with shape (hidden_size", "T", OpSchema::Optional) .Input(4, "bias", "1D bias tensor with shape (hidden_size", "T", OpSchema::Optional) @@ -1170,25 +1322,45 @@ ONNX_MS_OPERATOR_SET_SCHEMA( OpSchema() .SetDoc(GatedRelativePositionBias_ver1_doc) .Attr("num_heads", "Number of attention heads", AttributeProto::INT) - .Input(0, "query_layer", "tensor with shape (batch_size, seq_len, num_heads x head_size)", "T") + .Input(0, "query_layer", "tensor with shape (batch_size, seq_len, num_heads x head_size) or (token_count, num_heads x head_size)", "T") .Input(1, "query_bias", "1-d tensor with shape (num_heads x head_size)", "T") .Input(2, "rel_pos", "tensor with shape (1, num_head, seq_len, seq_len)", "T") .Input(3, "weight", "gemm weight for the gated_ur_linear, shape (head_size, D), D is divisible by 2", "T") .Input(4, "bias", "bias for the gated_ur_linear, shape (D)", "T") .Input(5, "eco_a", "tensor of shape (1, num_heads, 1, 1)", "T") + .Input(6, "token_offset", "offset of each token with shape (batch_size, seq_len)", "M", OpSchema::Optional) .Output(0, "output", "output tensor with shape (batch_size, num_heads, seq_len, seq_len)", "T") .TypeConstraint("T", {"tensor(float)", "tensor(float16)"}, "Constrain input and output types to float tensors.") + .TypeConstraint("M", {"tensor(int32)"}, "Constrain token_offset to integer types") .TypeAndShapeInferenceFunction([](ONNX_NAMESPACE::InferenceContext& ctx) { propagateElemTypeFromInputToOutput(ctx, 0, 0); int64_t num_heads = getAttribute(ctx, "num_heads", -1L); - if (hasInputShape(ctx, 0)) { - auto& query_layer_shape = getInputShape(ctx, 0); + + // When padding is removed: + // query_layer: (token_count, num_heads x head_size) + // token_offset: (batch_size, seq_len) + // Otherwise: + // query_layer: (batch_size, seq_len, num_heads x head_size) + // token_offset: None + // Output shape: (batch_size, num_heads, seq_len, seq_len) + if (hasInputShape(ctx, 6)) { + auto& token_offset_shape = getInputShape(ctx, 6); TensorShapeProto output_shape; - *output_shape.add_dim() = query_layer_shape.dim(0); + *output_shape.add_dim() = token_offset_shape.dim(0); output_shape.add_dim()->set_dim_value(num_heads); - *output_shape.add_dim() = query_layer_shape.dim(1); - *output_shape.add_dim() = query_layer_shape.dim(1); + *output_shape.add_dim() = token_offset_shape.dim(1); + *output_shape.add_dim() = token_offset_shape.dim(1); updateOutputShape(ctx, 0, output_shape); + } else if (hasInputShape(ctx, 0)) { + auto& query_layer_shape = getInputShape(ctx, 0); + if (query_layer_shape.dim().size() == 3) { + TensorShapeProto output_shape; + *output_shape.add_dim() = query_layer_shape.dim(0); + output_shape.add_dim()->set_dim_value(num_heads); + *output_shape.add_dim() = query_layer_shape.dim(1); + *output_shape.add_dim() = query_layer_shape.dim(1); + updateOutputShape(ctx, 0, output_shape); + } } })); diff --git a/onnxruntime/core/graph/contrib_ops/collective_defs.cc b/onnxruntime/core/graph/contrib_ops/collective_defs.cc index c4815a75dbd53..9e63e0d5e83f6 100644 --- a/onnxruntime/core/graph/contrib_ops/collective_defs.cc +++ b/onnxruntime/core/graph/contrib_ops/collective_defs.cc @@ -30,6 +30,10 @@ void RegisterCollectiveOps() { ONNX_CONTRIB_OPERATOR_SCHEMA(AllGather) .SetDomain(kMSDomain) .SinceVersion(1) + .Attr("axis", + "the axis to gather on.", + AttributeProto::INT, + static_cast(1)) .Attr("group_size", "total size in the group that need to be gathered.", AttributeProto::INT, @@ -38,10 +42,11 @@ void RegisterCollectiveOps() { .Output(0, "output", "gathered tensors", "T", OpSchema::Variadic) .TypeConstraint( "T", - {"tensor(float16)", "tensor(float)", "tensor(double)"}, - "Constrain to float, float16 and double tensors.") + {"tensor(float16)", "tensor(float)", "tensor(double)", "tensor(int64)", "tensor(bool)"}, + "Constrain to bool, float, float16 and double tensors.") .TypeAndShapeInferenceFunction([](ONNX_NAMESPACE::InferenceContext& ctx) { auto group_size = getAttribute(ctx, "group_size", 1); + auto axis = getAttribute(ctx, "axis", 0); assert(group_size >= static_cast(1)); // propagate type for output propagateElemTypeFromInputToOutput(ctx, 0, 0); @@ -52,8 +57,8 @@ void RegisterCollectiveOps() { auto input_type = ctx.getInputType(0); if (hasShape(*input_type)) { auto shape = input_type->tensor_type().shape(); - auto dim = shape.dim(0) * group_size; - *shape.mutable_dim(0) = dim; + auto dim = shape.dim(static_cast(axis)) * group_size; + *shape.mutable_dim(static_cast(axis)) = dim; *output_type->mutable_tensor_type()->mutable_shape() = shape; } }); @@ -69,8 +74,8 @@ void RegisterCollectiveOps() { .Output(0, "output", "collected tensors", "T", OpSchema::Variadic) .TypeConstraint( "T", - {"tensor(float16)", "tensor(float)", "tensor(double)"}, - "Constrain to float, float16 and double tensors.") + {"tensor(float16)", "tensor(float)", "tensor(double)", "tensor(int64)", "tensor(bool)"}, + "Constrain to bool, float, float16 and double tensors.") .TypeAndShapeInferenceFunction([](ONNX_NAMESPACE::InferenceContext& ctx) { propagateShapeAndTypeFromFirstInput(ctx); }); diff --git a/onnxruntime/core/graph/contrib_ops/contrib_defs.cc b/onnxruntime/core/graph/contrib_ops/contrib_defs.cc index f9e541a24d587..a79203a94a3a7 100644 --- a/onnxruntime/core/graph/contrib_ops/contrib_defs.cc +++ b/onnxruntime/core/graph/contrib_ops/contrib_defs.cc @@ -3,11 +3,8 @@ #include "core/graph/contrib_ops/contrib_defs.h" #include -#if !defined(ORT_MINIMAL_BUILD) -#include "onnx/defs/schema.h" -#else -#include "onnx/defs/data_type_utils.h" -#endif +#include "core/graph/onnx_protobuf.h" + #include "onnx/defs/shape_inference.h" #include "onnx/defs/tensor_proto_util.h" @@ -16,6 +13,7 @@ #include "core/graph/contrib_ops/range_schema_defs.h" #include "core/graph/op.h" #include "core/mlas/inc/mlas.h" +#include "core/mlas/inc/mlas_q4.h" #include "core/graph/contrib_ops/onnx_function_util.h" #include "contrib_ops/cpu/transformers/beam_search_parameters.h" #include "onnx/defs/function.h" @@ -1081,7 +1079,7 @@ ONNX_MS_OPERATOR_SET_SCHEMA(BeamSearch, 1, "Size of the vocabulary. " "If not provided, it will be inferred from the decoder subgraph's output shape", AttributeProto::INT, static_cast(-1)) - .Input(0, "input_ids", "The sequence used as a prompt for the generation. Shape is (batch_size, sequence_length)", "F") + .Input(0, "input_ids", "The sequence used as a prompt for the generation in the encoder subgraph. Shape is (batch_size, sequence_length)", "F") .Input(1, "max_length", "The maximum length of the sequence to be generated. Shape is (1)", "I") .Input(2, "min_length", "The minimum length below which the score of eos_token_id is set to -Inf. Shape is (1)", "I", OpSchema::Optional) .Input(3, "num_beams", "Number of beams for beam search. 1 means no beam search. Shape is (1)", "I") @@ -1095,6 +1093,8 @@ ONNX_MS_OPERATOR_SET_SCHEMA(BeamSearch, 1, .Input(7, "vocab_mask", "Mask of vocabulary. Words that masked with 0 are not allowed to be generated, and 1 is allowed. Shape is (vacab_size)", "M", OpSchema::Optional) .Input(8, "prefix_vocab_mask", "Mask of vocabulary for first step. Words that masked with 0 are not allowed to be generated, and 1 is allowed. Shape is (batch_size, vocab_size)", "M", OpSchema::Optional) .Input(9, "attention_mask", "Custom attention mask. Shape is (batch_size, sequence_length)", "I", OpSchema::Optional) + .Input(10, "decoder_input_ids", "The forced input id sequence for the decoder subgraph. Shape is (batch_size, initial_sequence_length)", "I", OpSchema::Optional) + .Input(11, "logits_processor", "Specific logits processor for different types of beamsearch models. Default value 0 means no specific logit processor. Accepts value >= 0. Shape is (1)", "I", OpSchema::Optional) .Output(0, "sequences", "Word IDs of generated sequences. Shape is (batch_size, num_return_sequences, max_sequence_length)", "I") .Output(1, "sequences_scores", "Final beam score of the generated sequences. Shape is (batch_size, num_return_sequences)", "T", OpSchema::Optional) .Output(2, "scores", @@ -1240,22 +1240,22 @@ ONNX_MS_OPERATOR_SET_SCHEMA(MaxpoolWithMask, 1, ONNX_MS_OPERATOR_SET_SCHEMA(Rfft, 1, OpSchema() - .SetDoc(R"DOC()DOC") - .Input(0, "X", "input tensor", "T") - .Attr("signal_ndim", "", AttributeProto::INT, static_cast(1)) - .Attr("normalized", "", AttributeProto::INT, static_cast(0)) - .Attr("onesided", "", AttributeProto::INT, static_cast(1)) - .Output(0, "Y", "output tensor", "T") + .SetDoc(R"DOC(This function computes the n-point one dimensional Fourier transform for a real-valued input where n is an even number.)DOC") + .Input(0, "X", "input tensor of size n in the signal dim", "T") + .Attr("signal_ndim", "number of dimensions comprising the signal, collected in reverse order (e.g. 1 = last dimension is the signal)", AttributeProto::INT, static_cast(1)) + .Attr("normalized", "must be 0, normalization currently not supported", AttributeProto::INT, static_cast(0)) + .Attr("onesided", "must be 1, only one sided FFTs supported", AttributeProto::INT, static_cast(1)) + .Output(0, "Y", "output tensor of size (n//2 + 1) in the signal dim and 2 in the last dimension for the real and complex parts", "T") .TypeConstraint("T", {"tensor(float)", "tensor(double)", "tensor(float16)"}, "Constrain input and output types to float or half tensors.")); ONNX_MS_OPERATOR_SET_SCHEMA(Irfft, 1, OpSchema() - .SetDoc(R"DOC()DOC") - .Input(0, "X", "input tensor", "T") - .Attr("signal_ndim", "", AttributeProto::INT) - .Attr("normalized", "", AttributeProto::INT, static_cast(0)) - .Attr("onesided", "", AttributeProto::INT, static_cast(1)) - .Output(0, "Y", "output tensor", "T") + .SetDoc(R"DOC(This function computes the inverse of the one-dimensional n-point RFFT computed in 'com.microsoft.rfft'.)DOC") + .Input(0, "X", "input tensor with size (n//2 + 1) in the signal dim and 2 in the last dimension for the real and complex parts", "T") + .Attr("signal_ndim", "number of dimensions comprising the signal", AttributeProto::INT) + .Attr("normalized", "must be 0, normalization currently not supported", AttributeProto::INT, static_cast(0)) + .Attr("onesided", "must be 1, only one sided FFTs supported", AttributeProto::INT, static_cast(1)) + .Output(0, "Y", "output tensor with size n in the signal dim", "T") .TypeConstraint("T", {"tensor(float)", "tensor(double)", "tensor(float16)"}, "Constrain input and output types to float or half tensors.")); ONNX_MS_OPERATOR_SET_SCHEMA(ComplexMul, 1, @@ -1686,6 +1686,140 @@ Matrix product that behaves like numpy.matmul: https://docs.scipy.org/doc/numpy- ONNX_NAMESPACE::matmulShapeInference(ctx, 0, 1); })); +/** + * @brief Shape inference for MatMul with right hand side matrix quantized into int4 + * @param ctx + * @param input_a_idx points to the left hand size matrix input + * @param input_b_idx points to the quantized right hand side matrix + * @param input_bshape_idx points to the shape tensor of the right hand side matrix + */ +static void matmulQ4ShapeInference(ONNX_NAMESPACE::InferenceContext& ctx, int input_a_idx, int input_b_idx, int input_bshape_idx, MLAS_BLK_QUANT_TYPE blk_quant_type) { + if (!hasInputShape(ctx, input_a_idx) || !hasInputShape(ctx, input_b_idx)) { + return; + } + + const auto& a_shape = ctx.getInputType(input_a_idx)->tensor_type().shape(); + if (a_shape.dim_size() == 0) { + fail_shape_inference("Input tensors of wrong rank (0)."); + } + + const auto& blob_shape = ctx.getInputType(input_b_idx)->tensor_type().shape(); + const auto& shape_shape = ctx.getInputType(input_bshape_idx)->tensor_type().shape(); + if (shape_shape.dim_size() != 1 && shape_shape.dim(0).dim_value() != 2) { + fail_shape_inference("B input for MatMul must be a 2-D matrix!"); + } + + const TensorProto* b_shape_tensor = ctx.getInputData(input_bshape_idx); + if (nullptr == b_shape_tensor) { + // Can't find shape info, quiting + return; + } + + ONNX_NAMESPACE::TensorShapeProto shapeL, shapeR; + + std::vector shape_r_data = ParseData(b_shape_tensor); + for (int d = 0; d < 2; d++) { + shapeR.add_dim()->set_dim_value(shape_r_data[d]); + } + + // First promote each shape to at least rank-2. This logic is + // specific to matmul, not generic broadcasting. + { + if (a_shape.dim_size() == 1) { + shapeL.add_dim()->set_dim_value(1); + *shapeL.add_dim() = a_shape.dim(0); + } else { + *shapeL.mutable_dim() = a_shape.dim(); + } + } + + size_t expectedPackSize = MlasQ4GemmPackBSize( + blk_quant_type, + static_cast(shapeR.dim(shapeR.dim_size() - 1).dim_value()), + static_cast(shapeR.dim(shapeR.dim_size() - 2).dim_value())); + if (expectedPackSize == 0) { + fail_shape_inference("4b quantization not yet supported on this hardware platform!"); + } + if (blob_shape.dim_size() != 1 && (size_t)blob_shape.dim(0).dim_value() != expectedPackSize) { + fail_shape_inference("Input q4 tensors of wrong size!"); + } + + // Check for compatible matrix multiply dimensions + { + const auto& dimL = shapeL.dim(shapeL.dim_size() - 1); + const auto& dimR = shapeR.dim(shapeR.dim_size() - 2); + if (dimL.has_dim_value() && dimR.has_dim_value() && dimL.dim_value() != dimR.dim_value()) { + fail_shape_inference("Incompatible dimensions for matrix multiplication"); + } + } + + ONNX_NAMESPACE::TensorShapeProto resultShape; + + // Now call out to generic multidimensional broadcasting for + // the broadcastable prefixes. + { + ONNX_NAMESPACE::TensorShapeProto prefixShapeL, prefixShapeR; + for (int i = 0; i < shapeL.dim_size() - 2; ++i) { + *prefixShapeL.add_dim() = shapeL.dim(i); + } + for (int i = 0; i < shapeR.dim_size() - 2; ++i) { + *prefixShapeR.add_dim() = shapeR.dim(i); + } + bidirectionalBroadcastShapeInference(prefixShapeL, prefixShapeR, resultShape); + } + + // Back to matmul-specific. Add the trailing dimensions back in. + { + if (a_shape.dim_size() != 1) { + *resultShape.add_dim() = shapeL.dim(shapeL.dim_size() - 2); + } + *resultShape.add_dim() = shapeR.dim(shapeR.dim_size() - 1); + } + + *ctx.getOutputType(0)->mutable_tensor_type()->mutable_shape() = resultShape; +} + +#ifndef ORT_MINIMAL_BUILD +ONNX_MS_OPERATOR_SET_SCHEMA(MatMulFpQ4, 1, + OpSchema() + .SetDoc(R"DOC( +Matrix product with right hand matrix being pre-packed and quantized int4 data blob. +During quantization, the matrix is divided into blocks, where each block is a +continguous subset inside each column. Each block is quantized into a +sequence of 4b integers with a scaling factor and an optional offset. +Currently 3 quantization types are supported: +(0): block size 32, no offset, (1): block size 32, with offset, (2): block size 64, +no offset +)DOC") + .Attr("blk_quant_type", "Quantization type", AttributeProto::INT, static_cast(1)) + .Input(0, "A", "N-dimensional matrix A", "T1") + .Input(1, "B", "1-dimensional data blob", "T2") + .Input(2, "B_shape", "Shape information of B", "T3") + .Output(0, "Y", "Matrix multiply results from A * B", "T1") + .TypeConstraint("T1", {"tensor(float)"}, "Constrain input matrix data types as single precision float tensor") + .TypeConstraint("T2", {"tensor(uint8)"}, "Constrain input B data types as data blob") + .TypeConstraint("T3", {"tensor(int64)"}, "Constrain shape of B must be int64 tensor.") + .TypeAndShapeInferenceFunction([](ONNX_NAMESPACE::InferenceContext& ctx) { + auto a_type = ctx.getInputType(0); + auto b_type = ctx.getInputType(1); + auto b_shape_type = ctx.getInputType(2); + auto y_type = ctx.getOutputType(0); + if (nullptr == a_type || nullptr == b_type || nullptr == b_shape_type || nullptr == y_type || + a_type->value_case() != ONNX_NAMESPACE::TypeProto::kTensorType || + b_type->value_case() != ONNX_NAMESPACE::TypeProto::kTensorType || + b_shape_type->value_case() != ONNX_NAMESPACE::TypeProto::kTensorType) { + fail_type_inference( + "inputs are expected to have tensor type and output type should not be null."); + } + + y_type->mutable_tensor_type()->set_elem_type(ONNX_NAMESPACE::TensorProto::FLOAT); + auto blk_quant_v = getAttribute(ctx, "blk_quant_type", 1); + MLAS_BLK_QUANT_TYPE blk_quant_type = blk_quant_v == 0 ? BlkQ4Sym : BlkQ4Zp8; + + matmulQ4ShapeInference(ctx, 0, 1, 2, blk_quant_type); + })); +#endif + constexpr const char* TransposeMatMul_doc = R"DOC( Duplicate of FusedMatMul. Going forward FusedMatMul should be used. This OP will be supported for backward compatibility. Matrix product that behaves like numpy.matmul: https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.matmul.html @@ -2775,7 +2909,7 @@ This op functions in much the same was as Dropout-11 and Dropout-13 do, execpt t /*min_arity*/ 1) .Attr("operator", "Name of ATen operator.", AttributeProto::STRING) .Attr("overload_name", "Overload name of ATen operator.", AttributeProto::STRING, false) - .TypeConstraint("T", OpSchema::all_tensor_types_with_bfloat(), + .TypeConstraint("T", OpSchema::all_tensor_types_ir4(), "Allow inputs and outputs to be any kind of tensor."); #endif @@ -2818,7 +2952,7 @@ Having this op allows runtime to do operator re-ordering to reduce compute FLOPs .Output(0, "output", "Tensor of rank r.", "T", OpSchema::Single, true, 1, OpSchema::Differentiable) .TypeConstraint( "T", - OpSchema::all_tensor_types_with_bfloat(), + OpSchema::all_tensor_types_ir4(), "Constrain input and output types to any tensor type.") .TypeConstraint("Tind", {"tensor(int32)", "tensor(int64)"}, "Constrain indices to integer types") .TypeAndShapeInferenceFunction([](InferenceContext& ctx) { diff --git a/onnxruntime/core/graph/contrib_ops/contrib_defs.h b/onnxruntime/core/graph/contrib_ops/contrib_defs.h index 4c24b284c6ddb..2d5b4f8e76cc2 100644 --- a/onnxruntime/core/graph/contrib_ops/contrib_defs.h +++ b/onnxruntime/core/graph/contrib_ops/contrib_defs.h @@ -4,7 +4,7 @@ #pragma once #if !defined(ORT_MINIMAL_BUILD) -#include "onnx/defs/schema.h" +#include "core/graph/onnx_protobuf.h" #include "core/graph/contrib_ops/ms_schema.h" #else #include "onnx/defs/data_type_utils.h" diff --git a/onnxruntime/core/graph/contrib_ops/diffusion_defs.cc b/onnxruntime/core/graph/contrib_ops/diffusion_defs.cc index c6d3db7fbe6da..c2f5edaa6149b 100644 --- a/onnxruntime/core/graph/contrib_ops/diffusion_defs.cc +++ b/onnxruntime/core/graph/contrib_ops/diffusion_defs.cc @@ -44,9 +44,13 @@ ONNX_MS_OPERATOR_SET_SCHEMA( .Attr("activation", "Activation after group normalization: 0 for None, 1 for Swish", AttributeProto::INT) + .Attr("channels_last", + "1 if the input and output are in the NHWC layout, 0 if it is in the NCHW layout. Defaults to 1.", + AttributeProto::INT, + static_cast(1)) .Input(0, "X", - "Input data tensor. Dimensions are (N x H x W x C), where N is the batch size, C is the number of channels, and H and W are the height and width of the data", + "Input data tensor. Dimensions are (N x H x W x C) when channels_last is 1 or (N x C x H x W) otherwise, where N is the batch size, C is the number of channels, and H and W are the height and width of the data", "T") .Input(1, "gamma", @@ -61,7 +65,7 @@ ONNX_MS_OPERATOR_SET_SCHEMA( "The output tensor of the same shape as X", "T") .TypeConstraint("T", {"tensor(float16)", "tensor(float)"}, "Constrain input X and output Y types to float tensors.") - .TypeConstraint("M", {"tensor(float)"}, "Constrain gamma and beta to float tensors.") + .TypeConstraint("M", {"tensor(float16)", "tensor(float)"}, "Constrain gamma and beta to float tensors.") .TypeAndShapeInferenceFunction(ONNX_NAMESPACE::propagateShapeAndTypeFromFirstInput)); constexpr const char* BiasSplitGelu_ver1_doc = R"DOC( diff --git a/onnxruntime/core/graph/contrib_ops/internal_nhwc_onnx_opset.cc b/onnxruntime/core/graph/contrib_ops/internal_nhwc_onnx_schemas.cc similarity index 97% rename from onnxruntime/core/graph/contrib_ops/internal_nhwc_onnx_opset.cc rename to onnxruntime/core/graph/contrib_ops/internal_nhwc_onnx_schemas.cc index b8a12ed1a6784..3ce7c40e754dc 100644 --- a/onnxruntime/core/graph/contrib_ops/internal_nhwc_onnx_opset.cc +++ b/onnxruntime/core/graph/contrib_ops/internal_nhwc_onnx_schemas.cc @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "internal_nhwc_onnx_opset.h" +#include "core/graph/contrib_ops/internal_nhwc_onnx_schemas.h" #include "onnx/defs/operator_sets.h" @@ -9,6 +9,8 @@ #include "core/graph/contrib_ops/nhwc_inference_context.h" #include "core/graph/contrib_ops/ms_schema.h" // contrib::GetOpSchema +#ifndef ORT_MINIMAL_BUILD + namespace onnxruntime { namespace contrib { class ONNX_OPERATOR_SET_SCHEMA_CLASS_NAME(Microsoft, 1, QLinearAveragePool); @@ -144,6 +146,7 @@ void OpSet_Internal_NHWC_ONNX::ForEachSchema(const std::function()); fn(GetOpSchema()); fn(GetOpSchema()); +#ifndef ORT_MINIMAL_BUILD + fn(GetOpSchema()); +#endif fn(GetOpSchema()); fn(GetOpSchema()); fn(GetOpSchema()); fn(GetOpSchema()); fn(GetOpSchema()); fn(GetOpSchema()); + fn(GetOpSchema()); fn(GetOpSchema()); fn(GetOpSchema()); fn(GetOpSchema()); diff --git a/onnxruntime/core/graph/contrib_ops/ms_schema.h b/onnxruntime/core/graph/contrib_ops/ms_schema.h index 4ecb17db253e7..afbb6712c76ab 100644 --- a/onnxruntime/core/graph/contrib_ops/ms_schema.h +++ b/onnxruntime/core/graph/contrib_ops/ms_schema.h @@ -3,7 +3,7 @@ #pragma once -#include "onnx/defs/schema.h" +#include "core/graph/onnx_protobuf.h" namespace onnxruntime { namespace contrib { @@ -12,4 +12,4 @@ namespace contrib { template ::ONNX_NAMESPACE::OpSchema GetOpSchema(); } // namespace contrib -} // namespace onnxruntime \ No newline at end of file +} // namespace onnxruntime diff --git a/onnxruntime/core/graph/contrib_ops/onnx_deprecated_operators.cc b/onnxruntime/core/graph/contrib_ops/onnx_deprecated_operators.cc index ee66dc614b788..be39a2d7ec2b2 100644 --- a/onnxruntime/core/graph/contrib_ops/onnx_deprecated_operators.cc +++ b/onnxruntime/core/graph/contrib_ops/onnx_deprecated_operators.cc @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "onnx/defs/schema.h" +#include "core/graph/onnx_protobuf.h" #include "onnx/defs/shape_inference.h" #include "onnx/defs/tensor_proto_util.h" @@ -503,4 +503,4 @@ ONNX_CONTRIB_OPERATOR_SET_SCHEMA( // End of ONNX exp ops(Affine, Crop, ParametricSoftplus, ImageScaler, ThresholdedRelu, DynamicSlice, ScaledTanh, MVN) // old version history maintenance } // namespace contrib -} // namespace onnxruntime \ No newline at end of file +} // namespace onnxruntime diff --git a/onnxruntime/core/graph/contrib_ops/onnx_deprecated_opset.h b/onnxruntime/core/graph/contrib_ops/onnx_deprecated_opset.h index ccc9ade10c213..13341605b1372 100644 --- a/onnxruntime/core/graph/contrib_ops/onnx_deprecated_opset.h +++ b/onnxruntime/core/graph/contrib_ops/onnx_deprecated_opset.h @@ -3,7 +3,7 @@ #pragma once -#include "onnx/defs/schema.h" +#include "core/graph/onnx_protobuf.h" #include "core/graph/contrib_ops/ms_schema.h" // This file contains deprecated ONNX operators that have been removed from ONNX spec, but we still need to keep them @@ -59,4 +59,4 @@ class OpSet_ONNX_Deprecated { } }; } // namespace contrib -} // namespace onnxruntime \ No newline at end of file +} // namespace onnxruntime diff --git a/onnxruntime/core/graph/contrib_ops/onnx_function_util.cc b/onnxruntime/core/graph/contrib_ops/onnx_function_util.cc index 02b4454bb568b..2382240e9e357 100644 --- a/onnxruntime/core/graph/contrib_ops/onnx_function_util.cc +++ b/onnxruntime/core/graph/contrib_ops/onnx_function_util.cc @@ -1,5 +1,6 @@ #include "core/graph/contrib_ops/onnx_function_util.h" #include "core/util/math.h" +#include "core/framework/float8.h" #include "core/framework/float16.h" namespace ONNX_NAMESPACE { @@ -77,6 +78,24 @@ TensorProto ToTensor(double value, TensorProto_DataType elem_type) { case TensorProto_DataType::TensorProto_DataType_BFLOAT16: t.add_int32_data(onnxruntime::BFloat16((float)value).val); break; + +#if !defined(DISABLE_FLOAT8_TYPES) + + case TensorProto_DataType::TensorProto_DataType_FLOAT8E4M3FN: + t.add_int32_data(onnxruntime::Float8E4M3FN((float)value, true).val); + break; + case TensorProto_DataType::TensorProto_DataType_FLOAT8E4M3FNUZ: + t.add_int32_data(onnxruntime::Float8E4M3FNUZ((float)value, true).val); + break; + case TensorProto_DataType::TensorProto_DataType_FLOAT8E5M2: + t.add_int32_data(onnxruntime::Float8E5M2((float)value, true).val); + break; + case TensorProto_DataType::TensorProto_DataType_FLOAT8E5M2FNUZ: + t.add_int32_data(onnxruntime::Float8E5M2FNUZ((float)value, true).val); + break; + +#endif + default: assert(false); } diff --git a/onnxruntime/core/graph/contrib_ops/onnx_function_util.h b/onnxruntime/core/graph/contrib_ops/onnx_function_util.h index 5e10cfed72127..237b61aa161c8 100644 --- a/onnxruntime/core/graph/contrib_ops/onnx_function_util.h +++ b/onnxruntime/core/graph/contrib_ops/onnx_function_util.h @@ -6,8 +6,7 @@ #include #include -#include "onnx/onnx-operators_pb.h" -#include "onnx/defs/schema.h" +#include "core/graph/onnx_protobuf.h" #include "onnx/defs/function.h" #include "onnx/defs/parser.h" @@ -21,4 +20,4 @@ inline static FunctionBodyHelper::NodeDef Const(const std::string& name, double return FunctionBodyHelper::NodeDef{ {name}, "Constant", {}, {{"value", ToTensor(value, elem_type)}}}; } -} // namespace ONNX_NAMESPACE \ No newline at end of file +} // namespace ONNX_NAMESPACE diff --git a/onnxruntime/core/graph/contrib_ops/quantization_defs.cc b/onnxruntime/core/graph/contrib_ops/quantization_defs.cc index 375c5878d1151..4313fae767fe5 100644 --- a/onnxruntime/core/graph/contrib_ops/quantization_defs.cc +++ b/onnxruntime/core/graph/contrib_ops/quantization_defs.cc @@ -136,8 +136,9 @@ Performs element-wise binary {name} on 8 bit data types (with Numpy-style broadc static const char* QuantizeLinear_ver1_doc = R"DOC( The linear quantization operator. It consumes a full precision data, a scale, a zero point to compute the low precision / quantized tensor. -The quantization formula is y = saturate ((x / y_scale) + y_zero_point).For saturation, it saturates to [0, 255] if it's uint8, or [-128, 127] if it's int8. -For (x / y_scale), it's rounding to nearest ties to even. Refer to https://en.wikipedia.org/wiki/Rounding for details. +The quantization formula is y = saturate ((x / y_scale) + y_zero_point). For saturation, it saturates to [0, 255] if it's uint8, [-128, 127] if it's int8, +[0, 65,535] if it's uint16, and [-32,768, 32,767] if it's int16. For (x / y_scale), it's rounding to nearest ties to even. +Refer to https://en.wikipedia.org/wiki/Rounding for details. Scale and zero point must have same shape. They must be either scalar (per tensor) or 1-D tensor (per 'axis').)DOC"; ONNX_MS_OPERATOR_SET_SCHEMA( @@ -152,23 +153,24 @@ ONNX_MS_OPERATOR_SET_SCHEMA( AttributeProto::INT, false) .Input(0, "x", "N-D full precision Input tensor to be quantized.", "T1") .Input(1, "y_scale", - "Scale for doing quantization to get 'y'. It could be a scalar or a 1-D tensor," - "which means a per-tensor or per-axis quantization. If it's a 1-D tensor, " - "its number of elements should be equal to the dimension value of 'axis' dimension of input 'x'.", + "Scale for doing quantization to get 'y'. It can be a scalar, which means per-tensor/layer " + "quantization, or a 1-D tensor for per-axis quantization.", "T1") .Input(2, "y_zero_point", - "Zero point for doing quantization to get 'y'. It could be a scalar or a 1-D tensor, which means a " - "per-tensor" - "or per-axis quantization. If it's a 1-D tensor, its number of elements should be equal to the " - "dimension value of 'axis' dimension of input 'x'.", - "T2") + "Zero point for doing quantization to get 'y'. Shape must match y_scale. Default is " + "uint8 with zero point of 0 if it's not specified.", + "T2", OpSchema::Optional) .Output(0, "y", "N-D quantized output tensor. It has same shape as input 'x'.", "T2") .TypeConstraint("T1", {"tensor(float16)", "tensor(float)"}, "Constrain 'x', 'y_scale' to float tensors.") - .TypeConstraint("T2", {"tensor(int8)", "tensor(uint8)"}, - "Constrain 'y_zero_point' and 'y' to 8-bit integer tensors.") + .TypeConstraint("T2", {"tensor(int8)", "tensor(uint8)", "tensor(int16)", "tensor(uint16)"}, + "Constrain 'y_zero_point' and 'y' to 8-bit and 16-bit integer tensors.") .SetDoc(QuantizeLinear_ver1_doc) .TypeAndShapeInferenceFunction([](ONNX_NAMESPACE::InferenceContext& ctx) { - propagateElemTypeFromInputToOutput(ctx, 2, 0); + if (ctx.getNumInputs() == 3 && ctx.getInputType(2) != nullptr) { + propagateElemTypeFromInputToOutput(ctx, 2, 0); + } else { + updateOutputElemType(ctx, 0, ONNX_NAMESPACE::TensorProto::UINT8); + } if (!hasInputShape(ctx, 0)) return; @@ -192,21 +194,19 @@ ONNX_MS_OPERATOR_SET_SCHEMA(DequantizeLinear, 1, AttributeProto::INT, false) .Input(0, "x", "N-D quantized Input tensor to be de-quantized.", "T1") .Input(1, "x_scale", - "Scale for input 'x'. It could be a scalar or a 1-D tensor, which means a " - "per-tensor or per-axis quantization." - "If it's a 1-D tensor, its number of elements should be equal to the dimension " - "value of 'axis' dimension of input 'x'.", + "Scale for input 'x'. It can be a scalar, which means a per-tensor/layer " + "dequantization, or a 1-D tensor for per-axis dequantization.", "T2") .Input(2, "x_zero_point", - "Zero point for input 'x'. It could be a scalar or a 1-D tensor, which means a " - "per-tensor or per-axis quantization." - "If it's a 1-D tensor, its number of elements should be equal to the dimension " - "value of 'axis' dimension of input 'x'.", - "T1") + "Zero point for input 'x'. Shape must match x_scale. It's optional. " + "Zero point is 0 when it's not specified.", + "T1", OpSchema::Optional) .Output(0, "y", "N-D full precision output tensor. It has same shape as input 'x'.", "T2") - .TypeConstraint("T1", {"tensor(int8)", "tensor(uint8)"}, - "Constrain 'x' and 'x_zero_point' to 8-bit integer tensors.") + .TypeConstraint("T1", {"tensor(int8)", "tensor(uint8)", "tensor(int16)", + "tensor(uint16)", "tensor(int32)"}, + "Constrain 'x' and 'x_zero_point' to 8-bit integer tensors, " + "16-bit integer tensors, or 32-bit signed integer tensors.") .TypeConstraint("T2", {"tensor(float16)", "tensor(float)"}, "Constrain 'y', 'x_scale' to float tensors.") .SetDoc(DequantizeLinear_ver1_doc) diff --git a/onnxruntime/core/graph/contrib_ops/quantization_defs.h b/onnxruntime/core/graph/contrib_ops/quantization_defs.h index c31d9e7e6ccd8..0951a9546b181 100644 --- a/onnxruntime/core/graph/contrib_ops/quantization_defs.h +++ b/onnxruntime/core/graph/contrib_ops/quantization_defs.h @@ -4,13 +4,7 @@ #include -#if !defined(ORT_MINIMAL_BUILD) -#include "onnx/defs/schema.h" -#else -#include "onnx/defs/data_type_utils.h" -#endif -#include "onnx/onnx_pb.h" -#include "onnx/onnx-operators_pb.h" +#include "core/graph/onnx_protobuf.h" namespace onnxruntime { namespace contrib { diff --git a/onnxruntime/core/graph/contrib_ops/range_schema_defs.h b/onnxruntime/core/graph/contrib_ops/range_schema_defs.h index 7abee0e331a7c..c468030fbd5f8 100644 --- a/onnxruntime/core/graph/contrib_ops/range_schema_defs.h +++ b/onnxruntime/core/graph/contrib_ops/range_schema_defs.h @@ -3,13 +3,7 @@ #pragma once -#if !defined(ORT_MINIMAL_BUILD) -#include "onnx/defs/schema.h" -#else -#include "onnx/defs/data_type_utils.h" -#endif -#include "onnx/onnx_pb.h" -#include "onnx/onnx-operators_pb.h" +#include "core/graph/onnx_protobuf.h" namespace onnxruntime { namespace contrib { diff --git a/onnxruntime/core/graph/contrib_ops/shape_inference_functions.cc b/onnxruntime/core/graph/contrib_ops/shape_inference_functions.cc index 9c9e73bf1f948..eeef20e9dff5e 100644 --- a/onnxruntime/core/graph/contrib_ops/shape_inference_functions.cc +++ b/onnxruntime/core/graph/contrib_ops/shape_inference_functions.cc @@ -2,13 +2,18 @@ // Licensed under the MIT License. #include "core/graph/contrib_ops/shape_inference_functions.h" +#include "core/graph/onnx_protobuf.h" #include +#include namespace onnxruntime { namespace contrib { void EmbedLayerNormalizationShapeInference(::ONNX_NAMESPACE::InferenceContext& ctx) { propagateElemTypeFromInputToOutput(ctx, 2, 0); - propagateElemTypeFromInputToOutput(ctx, 0, 1); + auto mask_index_type = getAttribute(ctx, "mask_index_type", 1); + if (mask_index_type > 0) { + propagateElemTypeFromInputToOutput(ctx, 0, 1); + } if (!hasInputShape(ctx, 0)) { // TODO(kreeger): In this case update the output to (?, ?, hidden_size). return; @@ -97,11 +102,13 @@ void EmbedLayerNormalizationShapeInference(::ONNX_NAMESPACE::InferenceContext& c updateOutputShape(ctx, 0, output_shape); // mask_index shape is (batch_size) - ONNX_NAMESPACE::TensorShapeProto mask_index_shape; - *mask_index_shape.add_dim() = input_ids_dims[0]; - updateOutputShape(ctx, 1, mask_index_shape); + if (mask_index_type > 0) { + ONNX_NAMESPACE::TensorShapeProto mask_index_shape; + *mask_index_shape.add_dim() = input_ids_dims[0]; + updateOutputShape(ctx, 1, mask_index_shape); + } - if (ctx.getNumOutputs() > 2) { + if (ctx.getNumOutputs() == 3 || (ctx.getNumOutputs() == 2 && mask_index_type == 0)) { updateOutputShape(ctx, 2, output_shape); propagateElemTypeFromInputToOutput(ctx, 0, 2); } diff --git a/onnxruntime/core/graph/dml_ops/dml_defs.h b/onnxruntime/core/graph/dml_ops/dml_defs.h index 3fb4a4cdcd063..5479005382ec9 100644 --- a/onnxruntime/core/graph/dml_ops/dml_defs.h +++ b/onnxruntime/core/graph/dml_ops/dml_defs.h @@ -3,13 +3,7 @@ #pragma once -#if !defined(ORT_MINIMAL_BUILD) -#include "onnx/defs/schema.h" -#else -#include "onnx/defs/data_type_utils.h" -#endif -#include "onnx/onnx_pb.h" -#include "onnx/onnx-operators_pb.h" +#include "core/graph/onnx_protobuf.h" namespace onnxruntime { namespace dml { diff --git a/onnxruntime/core/graph/function_utils.cc b/onnxruntime/core/graph/function_utils.cc index 9a479e60b4b9b..7477f48088a15 100644 --- a/onnxruntime/core/graph/function_utils.cc +++ b/onnxruntime/core/graph/function_utils.cc @@ -47,8 +47,8 @@ std::unique_ptr CreateSchema( // Due to this, a user of this style of schema must manually check whether any applicable type constraints // for each input or output are satisfied prior to creating a node that uses this schema // - op_schema->TypeConstraint("TAggregatedTypes", ONNX_NAMESPACE::OpSchema::all_tensor_types_with_bfloat(), - "all_tensor_types_with_bfloat"); + op_schema->TypeConstraint("TAggregatedTypes", ONNX_NAMESPACE::OpSchema::all_tensor_types_ir4(), + "all_tensor_types_ir4"); } int i = 0; @@ -99,10 +99,10 @@ static void IOTypeConstraintHelper(const ONNX_NAMESPACE::FunctionProto& onnx_fun // Create an all permissive list of data types. This will be used in case of model local functions // when we cannot infer the type constraints from function proto body InlinedHashSet all_types; - all_types.reserve(ONNX_NAMESPACE::OpSchema::all_tensor_types_with_bfloat().size() + + all_types.reserve(ONNX_NAMESPACE::OpSchema::all_tensor_types_ir4().size() + ONNX_NAMESPACE::OpSchema::all_tensor_sequence_types().size()); - all_types.insert(ONNX_NAMESPACE::OpSchema::all_tensor_types_with_bfloat().cbegin(), - ONNX_NAMESPACE::OpSchema::all_tensor_types_with_bfloat().cend()); + all_types.insert(ONNX_NAMESPACE::OpSchema::all_tensor_types_ir4().cbegin(), + ONNX_NAMESPACE::OpSchema::all_tensor_types_ir4().cend()); all_types.insert(ONNX_NAMESPACE::OpSchema::all_tensor_sequence_types().cbegin(), ONNX_NAMESPACE::OpSchema::all_tensor_sequence_types().cend()); @@ -129,7 +129,7 @@ static void IOTypeConstraintHelper(const ONNX_NAMESPACE::FunctionProto& onnx_fun "Too many inputs for op " + node.op_type()); } - auto& in_name = node.input().Get(i); + const auto& in_name = node.input().Get(i); auto iter = input_name_idx_map.find(in_name); if (iter != input_name_idx_map.end()) { int idx = iter->second; @@ -259,15 +259,17 @@ static void IOTypeConstraintHelper(const ONNX_NAMESPACE::FunctionProto& onnx_fun op_schema->TypeConstraint(tc.first, tc.second, ""); } + const auto attr_end = attribute_type_map.end(); for (auto& attribute_name : onnx_func_proto.attribute()) { - if (attribute_type_map.count(attribute_name)) - op_schema->Attr(attribute_name, "", attribute_type_map[attribute_name], false); + auto hit = attribute_type_map.find(attribute_name); + if (hit != attr_end) + op_schema->Attr(attribute_name, "", hit->second, false); } } std::unique_ptr CreateSchema(const std::string& function_domain, const std::string& function_name, - const InlinedHashMap& model_local_functions, + const std::unordered_map& model_local_functions, const std::unordered_map& domain_version_map, const SchemaRegistryManager& schema_registry, const logging::Logger& logger, @@ -291,13 +293,16 @@ std::unique_ptr CreateSchema(const std::string& functi op_schema->SetDomain(function_domain); op_schema->SetDoc(onnx_func_proto->doc_string()); op_schema->SinceVersion(static_cast(since_version)); - InlinedHashMap input_name_idx_map; - InlinedHashMap output_name_idx_map; - for (int i = 0; i < onnx_func_proto->input_size(); ++i) { + InlinedHashMap input_name_idx_map; + input_name_idx_map.reserve(onnx_func_proto->input_size()); + for (int i = 0, input_size = onnx_func_proto->input_size(); i < input_size; ++i) { input_name_idx_map[onnx_func_proto->input().Get(i)] = i; } - for (int i = 0; i < onnx_func_proto->output_size(); ++i) { + + InlinedHashMap output_name_idx_map; + output_name_idx_map.reserve(onnx_func_proto->output_size()); + for (int i = 0, output_size = onnx_func_proto->output_size(); i < output_size; ++i) { output_name_idx_map[onnx_func_proto->output().Get(i)] = i; } @@ -310,6 +315,7 @@ std::unique_ptr CreateSchema(const std::string& functi schema_registry.GetLastReleasedOpsetVersions(false); std::unordered_map func_domain_to_version; + func_domain_to_version.reserve(onnx_func_proto->opset_import().size()); for (auto& opSet : onnx_func_proto->opset_import()) { const auto& domain = opSet.domain(); const auto version = gsl::narrow_cast(opSet.version()); @@ -327,17 +333,25 @@ std::unique_ptr CreateSchema(const std::string& functi } } + // Instantiate once and reuse for all shape inference calls. + constexpr bool check_type_true = true; + constexpr int error_mode_throw = 1; + constexpr bool enable_data_propagation_false = false; + static const ONNX_NAMESPACE::ShapeInferenceOptions inference_options{check_type_true, error_mode_throw, enable_data_propagation_false}; + + // model_local_functions is a member of Model instance and will be alive at the time this is invoked. op_schema->TypeAndShapeInferenceFunction( - [onnx_func_proto, func_domain_to_version, &model_local_functions](ONNX_NAMESPACE::InferenceContext& ctx) { - auto schema_registry = ONNX_NAMESPACE::OpSchemaRegistry::Instance(); - ONNX_NAMESPACE::ShapeInferenceOptions options{true, 1, false}; - std::unordered_map map_copy(model_local_functions.begin(), - model_local_functions.end()); - std::unordered_map empty_map; - ONNX_NAMESPACE::shape_inference::SymbolTableImpl symbolTable; + [onnx_func_proto, func_domain_to_version = std::move(func_domain_to_version), &model_local_functions](ONNX_NAMESPACE::InferenceContext& ctx) { + auto* schema_registry = ONNX_NAMESPACE::OpSchemaRegistry::Instance(); + + // https://github.com/microsoft/onnxruntime/issues/17061 + // We are passing a nullptr for the symbol table, because symbol table must be global + // for all the shape inferencing to work correctly. Otherwise, unrelated shapes get + // the same symbolic shapes and are marked for memory re-use. This is a Temp fix. + constexpr ONNX_NAMESPACE::shape_inference::SymbolTableImpl* symbolTable = nullptr; ONNX_NAMESPACE::shape_inference::InferShapeForFunctionNode(*onnx_func_proto, func_domain_to_version, - schema_registry, ctx, options, map_copy, - &symbolTable, &empty_map); + schema_registry, ctx, inference_options, model_local_functions, + symbolTable, nullptr); }); op_schema->Finalize(); @@ -346,29 +360,29 @@ std::unique_ptr CreateSchema(const std::string& functi class Inliner { private: - std::string prefix; - const onnxruntime::NodeAttributes& attr_map; - std::vector> rename_scopes; + std::string prefix_; + const onnxruntime::NodeAttributes& attr_map_; + std::vector> rename_scopes_; - Inliner(std::string prefix_, const onnxruntime::NodeAttributes& attr_map_) : prefix(prefix_), - attr_map(attr_map_) { + Inliner(const std::string& prefix, const onnxruntime::NodeAttributes& attr_map) : prefix_(prefix), + attr_map_(attr_map) { // Create an empty mapping for the top-level scope. - rename_scopes.emplace_back(); + rename_scopes_.emplace_back(); } // Replace given name with a unique version of the name, and cache the // renaming-binding in current scope. void make_unique(std::string& name) { - auto new_name = prefix + name; - auto& current_scope = rename_scopes.back(); + auto new_name = prefix_ + name; + auto& current_scope = rename_scopes_.back(); current_scope[name] = new_name; - name = new_name; + name = std::move(new_name); } void rename(std::string& name, bool is_new_def) { if (name.empty()) return; - for (auto i = rename_scopes.size(); i > 0; --i) { - const auto& map = rename_scopes[i - 1]; + for (auto i = rename_scopes_.size(); i > 0; --i) { + const auto& map = rename_scopes_[i - 1]; auto iter = map.find(name); if (iter != map.end()) { name = iter->second; @@ -389,31 +403,35 @@ class Inliner { // is used in an output-context where it is not optional. ORT_ENFORCE(actuals.size() <= formals.size(), "Number of actual parameters cannot exceed number of formal parameters"); - auto& current_scope = rename_scopes.back(); + auto& current_scope = rename_scopes_.back(); int i = 0; for (; i < actuals.size(); ++i) { std::string& formal = *formals.Mutable(i); std::string rename_as = actuals.Get(i); - if constexpr (isOutput) + if constexpr (isOutput) { if (rename_as.empty()) - rename_as = prefix + formal; + rename_as.assign(prefix_).append(formal); + } current_scope[formal] = rename_as; if (!rename_as.empty()) - formal = rename_as; + formal = std::move(rename_as); } for (; i < formals.size(); ++i) { std::string& formal = *formals.Mutable(i); - std::string rename_as = isOutput ? prefix + formal : std::string(""); + std::string rename_as; + if constexpr (isOutput) { + rename_as.assign(prefix_).append(formal); + } current_scope[formal] = rename_as; if (!rename_as.empty()) - formal = rename_as; + formal = std::move(rename_as); } } // Process a node: void transform(NodeProto& n) { if (!n.name().empty()) - n.set_name(prefix + n.name()); + n.set_name(prefix_ + n.name()); for (auto& x : *n.mutable_input()) { rename(x, false); @@ -422,13 +440,14 @@ class Inliner { rename(y, true); } auto& attributes = *n.mutable_attribute(); + const auto attr_map_end = attr_map_.cend(); for (auto attr_iter = attributes.begin(); attr_iter != attributes.end();) { auto& attr = *attr_iter; if (!attr.ref_attr_name().empty()) { // Attribute-references must be replaced by the corresponding attribute-value in the call-node // if the call-node contains the attribute. Otherwise, this attribute must be removed. - auto entry = attr_map.find(attr.ref_attr_name()); - if (entry != attr_map.cend()) { + auto entry = attr_map_.find(attr.ref_attr_name()); + if (entry != attr_map_end) { // Copy value of attribute, but retain original name: std::string name = attr.name(); attr = entry->second; @@ -450,7 +469,7 @@ class Inliner { // Process a sub-graph, contained as an attribute in a control-flow op node. void transform(GraphProto& graph) { - rename_scopes.emplace_back(); + rename_scopes_.emplace_back(); for (auto& x : *graph.mutable_input()) make_unique(*x.mutable_name()); for (auto& init : *graph.mutable_initializer()) @@ -459,12 +478,13 @@ class Inliner { make_unique(*y.mutable_name()); for (auto& n : *graph.mutable_node()) transform(n); - rename_scopes.pop_back(); + rename_scopes_.pop_back(); } public: // The main specialization method: specialize a FunctionProto for a particular call-site. - static void specialize(const NodeProto& callnode, FunctionProto& callee, const onnxruntime::NodeAttributes& attr_map, std::string unique_prefix) { + static void specialize(const NodeProto& callnode, FunctionProto& callee, const onnxruntime::NodeAttributes& attr_map, + const std::string& unique_prefix) { Inliner inliner(unique_prefix, attr_map); inliner.bind(*callee.mutable_input(), callnode.input()); @@ -475,21 +495,18 @@ class Inliner { } }; -void Specialize(ONNX_NAMESPACE::FunctionProto& called_function, const ONNX_NAMESPACE::NodeProto calling_node, - const onnxruntime::NodeAttributes& attr_map, std::string unique_prefix) { +void Specialize(ONNX_NAMESPACE::FunctionProto& called_function, const ONNX_NAMESPACE::NodeProto& calling_node, + const onnxruntime::NodeAttributes& attr_map, const std::string& unique_prefix) { Inliner::specialize(calling_node, called_function, attr_map, unique_prefix); } -void Specialize(ONNX_NAMESPACE::FunctionProto& called_function, Node& calling_node, std::string unique_prefix) { +void Specialize(ONNX_NAMESPACE::FunctionProto& called_function, const Node& calling_node, const std::string& unique_prefix) { ONNX_NAMESPACE::NodeProto calling_node_proto; calling_node.ToProto(calling_node_proto); onnxruntime::NodeAttributes attr_map = calling_node.GetAttributes(); for (auto& attribute_proto : called_function.attribute_proto()) { - auto entry = attr_map.find(attribute_proto.name()); - if (entry == attr_map.cend()) { - attr_map[attribute_proto.name()] = attribute_proto; - } + ORT_IGNORE_RETURN_VALUE(attr_map.emplace(attribute_proto.name(), attribute_proto)); } Specialize(called_function, calling_node_proto, attr_map, unique_prefix); } diff --git a/onnxruntime/core/graph/function_utils.h b/onnxruntime/core/graph/function_utils.h index e271d9b240d66..34e5e57189bd5 100644 --- a/onnxruntime/core/graph/function_utils.h +++ b/onnxruntime/core/graph/function_utils.h @@ -5,7 +5,7 @@ #include #include "core/common/common.h" -#include "onnx/onnx_pb.h" +#include "core/graph/onnx_protobuf.h" #include "core/graph/graph.h" #include "core/graph/indexed_sub_graph.h" #include "core/graph/function.h" @@ -20,7 +20,7 @@ namespace function_utils { * @param nodes_to_fuse The metadata for the subgraph that EP want to fuse. * @param allow_aggregated_tensor_type if true, it will use a type constraint called * TAggregatedTypes for all inputs and outputs, - * and that this will match all tensor types in the all_tensor_types_with_bfloat list. + * and that this will match all tensor types in the all_tensor_types_ir4 list. */ std::unique_ptr CreateSchema(const Graph& graph, const IndexedSubGraph& nodes_to_fuse, @@ -31,6 +31,8 @@ std::unique_ptr CreateSchema(const Graph& graph, * @param function_name The name of the function. * @param model_local_functions The map of local functions in the same onnx model. * This will be used as context for the function's type/shape inference. + * This argument is captured by shape inferencing lambda by reference and must + * be alive at the time of the shape inferencing. * @param domain_version_map Domain to version map used in current onnx model. * @param schema_registry The schema registry current model is using. * @param logger The logger current model is using. @@ -38,7 +40,7 @@ std::unique_ptr CreateSchema(const Graph& graph, */ std::unique_ptr CreateSchema(const std::string& function_domain, const std::string& function_name, - const InlinedHashMap& model_local_functions, + const std::unordered_map& model_local_functions, const std::unordered_map& domain_version_map, const SchemaRegistryManager& schema_registry, const logging::Logger& logger, @@ -53,10 +55,10 @@ inline std::string GetFunctionIdentifier(std::string_view function_domain, std:: return function_domain.data() + std::string(":") + function_name.data(); } -void Specialize(ONNX_NAMESPACE::FunctionProto& called_function, const ONNX_NAMESPACE::NodeProto calling_node, - const onnxruntime::NodeAttributes& attr_map, std::string unique_prefix); +void Specialize(ONNX_NAMESPACE::FunctionProto& called_function, const ONNX_NAMESPACE::NodeProto& calling_node, + const onnxruntime::NodeAttributes& attr_map, const std::string& unique_prefix); -void Specialize(ONNX_NAMESPACE::FunctionProto& called_function, Node& calling_node, std::string unique_prefix); +void Specialize(ONNX_NAMESPACE::FunctionProto& called_function, const Node& calling_node, const std::string& unique_prefix); } // namespace function_utils diff --git a/onnxruntime/core/graph/graph.cc b/onnxruntime/core/graph/graph.cc index 22f82baf5cd0d..383c1d689d3c3 100644 --- a/onnxruntime/core/graph/graph.cc +++ b/onnxruntime/core/graph/graph.cc @@ -585,7 +585,7 @@ bool Node::TryGetFunctionProto(ONNX_NAMESPACE::FunctionProto& onnx_function_prot // Check if this node has a schema defined function proto. if (op_->HasContextDependentFunction()) { NodeProto node_proto; - ToProto(node_proto); + ToProto(node_proto, true); std::vector input_types; for (size_t i = 0, n = InputDefs().size(); i < n; i++) { auto p_node_arg = InputDefs().at(i); @@ -1124,7 +1124,7 @@ void Node::ForEachDef(std::function& new_graph) { // // create instance. need to call private ctor so can't use make_unique -// GSL_SUPPRESS(r .11) +// GSL_SUPPRESS(r.11) // new_graph.reset(new Graph(nullptr, &graph_proto, domain_to_version, ir_version)); // // // as we just loaded from file we want to fully initialize/Resolve, but not let that change @@ -1301,7 +1301,9 @@ Graph::Graph(const Model& owning_model, for (auto& node_arg : graph_proto_->value_info()) { if (utils::HasName(node_arg) && utils::HasType(node_arg)) { - name_to_type_map[node_arg.name()] = node_arg.type(); + if (node_arg.name().size() > 0) { + name_to_type_map[node_arg.name()] = node_arg.type(); + } } } @@ -1564,7 +1566,7 @@ void Graph::RemoveEdge(NodeIndex src_node_index, NodeIndex dst_node_index, int s #endif // !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) #if !defined(ORT_MINIMAL_BUILD) -GSL_SUPPRESS(es .84) // ignoring return value from unordered_map::insert causes noisy complaint +GSL_SUPPRESS(es.84) // ignoring return value from unordered_map::insert causes noisy complaint Status Graph::BuildConnections(std::unordered_set& outer_scope_node_args_consumed) { // recurse into subgraphs first so we can update any nodes in this graph that are used by those subgraphs if (!resolve_context_.nodes_with_subgraphs.empty()) { @@ -1843,7 +1845,7 @@ void Graph::KahnsTopologicalSort(const std::function& enter, } } -GSL_SUPPRESS(es .84) // noisy warning about ignoring return value from insert(...) +GSL_SUPPRESS(es.84) // noisy warning about ignoring return value from insert(...) Status Graph::PerformTopologicalSortAndCheckIsAcyclic() { nodes_in_topological_order_.clear(); std::unordered_set downstream_nodes; // nodes downstream of the node we're currently checking @@ -2207,7 +2209,7 @@ Status Graph::UpdateShapeInference(Node& node) { } // Implementation of type-inference and type-checking for a single node -GSL_SUPPRESS(f .23) // spurious warning about inferred_type never being checked for null +GSL_SUPPRESS(f.23) // spurious warning about inferred_type never being checked for null Status Graph::InferAndVerifyTypeMatch(Node& node, const OpSchema& op, const ResolveOptions& options) { auto& node_name = node.Name(); @@ -2648,7 +2650,7 @@ Status Graph::VerifyInputAndInitializerNames() { } for (auto& initializer_pair : name_to_initial_tensor_) { - GSL_SUPPRESS(es .84) + GSL_SUPPRESS(es.84) inputs_and_initializers.insert(initializer_pair.first); // Initializers are expected to be included in inputs (according to ONNX spec). // onnxruntime relaxes this constraint. No duplicate-name check here. @@ -2829,7 +2831,6 @@ void Graph::AddInitializedTensor(const TensorProto& tensor) { // will be a matching graph input for this initializer (we prefer shape info from the graph input). TypeProto t; t.mutable_tensor_type()->set_elem_type(tensor.data_type()); - ORT_IGNORE_RETURN_VALUE(GetOrCreateNodeArg(tensor.name(), &t)); } } @@ -3313,7 +3314,7 @@ bool Graph::AddControlEdge(NodeIndex src_node_index, NodeIndex dst_node_index) { return false; } - GSL_SUPPRESS(es .84) { // ignoring return from insert() + GSL_SUPPRESS(es.84) { // ignoring return from insert() nodes_[src_node_index]->MutableRelationships().output_edges.insert(Node::EdgeEnd(*nodes_[dst_node_index])); nodes_[dst_node_index]->MutableRelationships().input_edges.insert(Node::EdgeEnd(*nodes_[src_node_index])); nodes_[dst_node_index]->MutableRelationships().control_inputs.insert(nodes_[src_node_index]->Name()); @@ -3379,17 +3380,26 @@ ONNX_NAMESPACE::GraphProto Graph::ToGraphProto() const { } ONNX_NAMESPACE::GraphProto Graph::ToGraphProtoWithExternalInitializers(const std::string& external_file_name, + const PathString& destination_file_path, size_t initializer_size_threshold) const { GraphProto result; ToGraphProtoInternal(result); - std::ofstream external_stream(external_file_name, std::ofstream::out | std::ofstream::binary); + Path parent_path = Path::Parse(destination_file_path).ParentPath(); + Path external_file_path = Path::Parse(ToPathString(external_file_name)); + // Check if parent_path is relative path (length = 0) + if (parent_path.ToPathString().length()) { + // Save external data file in same directory as model + external_file_path = parent_path.Append(external_file_path); + } + + std::ofstream external_stream(external_file_path.ToPathString(), std::ofstream::out | std::ofstream::binary); ORT_ENFORCE(external_stream.is_open()); int64_t external_offset = 0; // Add the initializers to the result graph. -#if !defined(DISABLE_SPARSE_TENSORS) const auto& model_path = ModelPath(); +#if !defined(DISABLE_SPARSE_TENSORS) const auto sparse_end = sparse_tensor_names_.end(); #endif @@ -3406,7 +3416,7 @@ ONNX_NAMESPACE::GraphProto Graph::ToGraphProtoWithExternalInitializers(const std TensorProto* output_proto = result.add_initializer(); std::vector raw_data; - ORT_THROW_IF_ERROR(utils::UnpackInitializerData(initializer, Path(), raw_data)); + ORT_THROW_IF_ERROR(utils::UnpackInitializerData(initializer, model_path, raw_data)); size_t tensor_bytes_size = raw_data.size(); if (tensor_bytes_size < initializer_size_threshold) { *output_proto = initializer; @@ -3641,7 +3651,7 @@ void Graph::ComputeOverridableInitializers() { #if !defined(ORT_MINIMAL_BUILD) -GSL_SUPPRESS(es .84) // warning about ignoring return value from insert(...) +GSL_SUPPRESS(es.84) // warning about ignoring return value from insert(...) Status Graph::SetGraphInputsOutputs() { // If loaded from a model file, we start from the specified inputs and // outputs set earlier by InitializeStateFromModelFileGraphProto(). @@ -3827,7 +3837,7 @@ Status Graph::PopulateNodeArgToProducerConsumerLookupsFromNodes() { } // calling private ctor -GSL_SUPPRESS(r .11) +GSL_SUPPRESS(r.11) gsl::not_null Graph::AllocateNode() { ORT_ENFORCE(nodes_.size() < static_cast(std::numeric_limits::max())); std::unique_ptr new_node(new Node(nodes_.size(), *this)); @@ -3867,13 +3877,17 @@ Node& Graph::CreateFusedSubGraphNode(const IndexedSubGraph& sub_graph, const std int cur_idx = 0; for (const auto& arg_name : func_meta_def->inputs) { - input_args.push_back(GetNodeArg(arg_name)); + // In some cases, it needs to get the NodeArgs from ancestors. + // For example, if the subgraph we are going to build is the subgraph of the original graph + // and the NodeArgs of the outer scope values are defined in the top-level original graph. + input_args.push_back(GetNodeArgIncludingParentGraphs(arg_name)); input_indexes[arg_name] = cur_idx++; } cur_idx = 0; for (const auto& arg_name : func_meta_def->outputs) { - output_args.push_back(GetNodeArg(arg_name)); + // In some cases, it needs to get the NodeArgs from ancestors. + output_args.push_back(GetNodeArgIncludingParentGraphs(arg_name)); output_indexes[arg_name] = cur_idx++; } @@ -4015,9 +4029,8 @@ Status Graph::InlineFunction(Node& callnode) { // create a uniq_identifier to append to every node name and intermediate input\outputs // to make sure there are no unintended duplicates std::stringstream ss; - ss << "_" << static_cast(&callnode) << "_"; - auto uniq_identifier = ss.str(); - + ss << "_inline_" << callnode.OpType(); + auto uniq_identifier = GenerateNodeName(ss.str()); // Replace a (function-call) node by an inlined graph. if (!callnode.GetFunctionBody()) { // This is the normal use-case: inlining a FunctionProto (representing @@ -4030,13 +4043,25 @@ Status Graph::InlineFunction(Node& callnode) { return &this->GetOrCreateNodeArg(name, nullptr); }; + // Process constant nodes first and create NodeArg for these as they become initializers + // It is important for the initializers to have NodeArg created, first they are needed + // if the initializer is unused and removed, second if the node depends on the initializer, + // we can have Type attached to it. for (const auto& inlined_node : inlined_fp.node()) { if (inlined_node.op_type() == kConstant) { // Copy constant nodes _value to name_to_initial_tensor_ const gsl::not_null tensor{graph_proto_->add_initializer()}; ORT_RETURN_IF_ERROR(utils::ConstantNodeProtoToTensorProto(inlined_node, model_path, *tensor, inlined_node.output(0))); - name_to_initial_tensor_[tensor->name()] = tensor; - } else { + auto insert_result = name_to_initial_tensor_.emplace(tensor->name(), tensor); + ORT_ENFORCE(insert_result.second, "Constant node name: ", tensor->name(), " in inlined function: ", + inlined_fp.name(), " conflicts with graph initializer. Check Specializing code."); + TypeProto t{TypeProtoFromTensorProto(*tensor)}; + ORT_IGNORE_RETURN_VALUE(GetOrCreateNodeArg(tensor->name(), &t)); + } + } + + for (const auto& inlined_node : inlined_fp.node()) { + if (inlined_node.op_type() != kConstant) { InlinedVector inputs; InlinedVector outputs; @@ -4062,43 +4087,10 @@ Status Graph::InlineFunction(Node& callnode) { // TODO: Unclear that this feature is needed. Can this be removed? const Graph& subgraph = callnode.GetFunctionBody()->Body(); - // Map of function input outputs to nodes input/outputs - std::unordered_map remap_input_output; - // Set of node input output names as these names need to be preserved during inlining - std::unordered_set func_input_output_names; - - for (size_t i = 0; i < subgraph.GetInputsIncludingInitializers().size(); ++i) { - auto* input = subgraph.GetInputsIncludingInitializers()[i]; - if (input->Name() != callnode.MutableInputDefs()[i]->Name()) { - remap_input_output[input->Name()] = callnode.MutableInputDefs()[i]; - } - func_input_output_names.insert(input->Name()); - } - - for (size_t i = 0; i < subgraph.GetOutputs().size(); ++i) { - auto* output = subgraph.GetOutputs()[i]; - if (output->Name() != callnode.MutableOutputDefs()[i]->Name()) { - remap_input_output[output->Name()] = callnode.MutableOutputDefs()[i]; - } - func_input_output_names.insert(output->Name()); - } - - for (auto& init : subgraph.name_to_initial_tensor_) { - const gsl::not_null tensor{graph_proto_->add_initializer()}; - *tensor = *init.second; - tensor->set_name(tensor->name() + uniq_identifier); - name_to_initial_tensor_[tensor->name()] = tensor; - } for (const auto& subgraph_node : subgraph.Nodes()) { - if (subgraph_node.OpType() == kConstant) { - // Copy constant nodes _value to name_to_initial_tensor_ - ONNX_NAMESPACE::NodeProto subgraph_node_proto{}; - subgraph_node.ToProto(subgraph_node_proto); - const gsl::not_null tensor{graph_proto_->add_initializer()}; - ORT_RETURN_IF_ERROR(utils::ConstantNodeProtoToTensorProto(subgraph_node_proto, model_path, *tensor, subgraph_node_proto.output(0))); - name_to_initial_tensor_[tensor->name()] = tensor; - } else { - std::vector inputs, outputs; + if (subgraph_node.OpType() != kConstant) { + InlinedVector inputs; + InlinedVector outputs; for (auto* input : subgraph_node.InputDefs()) { auto& n_input = GetOrCreateNodeArg(input->Name(), input->TypeAsProto()); inputs.push_back(&n_input); @@ -4115,14 +4107,44 @@ Status Graph::InlineFunction(Node& callnode) { subgraph_node.Domain()); } } + + // Process constant nodes and iniitalizers after all other nodes + // so NodeArgs are created from the nodes + for (const auto& subgraph_node : subgraph.Nodes()) { + if (subgraph_node.OpType() == kConstant) { + // Copy constant nodes _value to name_to_initial_tensor_ + ONNX_NAMESPACE::NodeProto subgraph_node_proto{}; + subgraph_node.ToProto(subgraph_node_proto); + const gsl::not_null tensor{graph_proto_->add_initializer()}; + ORT_RETURN_IF_ERROR(utils::ConstantNodeProtoToTensorProto(subgraph_node_proto, model_path, *tensor, subgraph_node_proto.output(0))); + auto insert_result = name_to_initial_tensor_.emplace(tensor->name(), tensor); + ORT_ENFORCE(insert_result.second, "Constant node name: ", tensor->name(), " in inlined subgraph: ", + subgraph.Name(), " conflicts with graph initializer. Check Specializing code."); + if (GetNodeArg(tensor->name()) == nullptr) { + TypeProto t{TypeProtoFromTensorProto(*tensor)}; + ORT_IGNORE_RETURN_VALUE(GetOrCreateNodeArg(tensor->name(), &t)); + } + } + } + + for (auto& init : subgraph.name_to_initial_tensor_) { + const gsl::not_null tensor{graph_proto_->add_initializer()}; + *tensor = *init.second; + tensor->set_name(tensor->name() + uniq_identifier); + auto insert_result = name_to_initial_tensor_.emplace(tensor->name(), tensor); + ORT_ENFORCE(insert_result.second, "Initializer name: ", tensor->name(), " in inlined subgraph: ", + subgraph.Name(), " conflicts with graph initializer. Check Specializing code."); + if (GetNodeArg(tensor->name()) == nullptr) { + TypeProto t{TypeProtoFromTensorProto(*tensor)}; + ORT_IGNORE_RETURN_VALUE(GetOrCreateNodeArg(tensor->name(), &t)); + } + } } RemoveNode(callnode.Index()); // std::cout << "Graph after inlining\n\n" << *this << std::endl << std::flush; - ORT_RETURN_IF_ERROR(this->Resolve()); - return Status::OK(); } diff --git a/onnxruntime/core/graph/graph_flatbuffers_utils.cc b/onnxruntime/core/graph/graph_flatbuffers_utils.cc index 1d1fb85bf5998..8e962403556dd 100644 --- a/onnxruntime/core/graph/graph_flatbuffers_utils.cc +++ b/onnxruntime/core/graph/graph_flatbuffers_utils.cc @@ -16,16 +16,16 @@ using namespace ONNX_NAMESPACE; namespace onnxruntime::fbs::utils { -#if !defined(ORT_MINIMAL_BUILD) - template inline flatbuffers::Offset> SaveDims(flatbuffers::FlatBufferBuilder& builder, const DimsFieldType& dims) { std::vector dims_data(dims.size()); - std::copy(dims.cbegin(), dims.cend(), dims_data.begin()); + std::copy(dims.begin(), dims.end(), dims_data.begin()); return builder.CreateVector(dims_data); } +#if !defined(ORT_MINIMAL_BUILD) + Status SaveInitializerOrtFormat(flatbuffers::FlatBufferBuilder& builder, const TensorProto& initializer, const Path& model_path, @@ -339,4 +339,70 @@ Status LoadAttributeOrtFormat(const fbs::Attribute& fbs_attr, return Status::OK(); } +#ifdef ENABLE_TRAINING_APIS + +Status SaveOrtTensorOrtFormat( + const std::string& tensor_name, const onnxruntime::Tensor& ort_tensor, + flatbuffers::FlatBufferBuilder& builder, + flatbuffers::Offset& fbs_tensor) { + ORT_RETURN_IF(ort_tensor.IsDataTypeString(), + "TensorProto_DataType_STRING is not supported while saving a tensor to ORT format."); + + const auto fbs_tensor_name = builder.CreateString(tensor_name); + const auto fbs_tensor_dims = SaveDims(builder, ort_tensor.Shape().GetDims()); + flatbuffers::Offset> raw_data = builder.CreateVector( + static_cast(ort_tensor.DataRaw()), + ort_tensor.SizeInBytes()); + + fbs::TensorBuilder tb(builder); + tb.add_name(fbs_tensor_name); + tb.add_doc_string(0); + tb.add_dims(fbs_tensor_dims); + tb.add_data_type(static_cast(ort_tensor.GetElementType())); + tb.add_raw_data(raw_data); + fbs_tensor = tb.Finish(); + return Status::OK(); +} + +template +struct UnpackTensorWithType { + Status operator()(const ONNX_NAMESPACE::TensorProto& tensor_proto, const fbs::Tensor& fbs_tensor, + onnxruntime::Tensor& ort_tensor) const { + return onnxruntime::utils::UnpackTensor( + tensor_proto, fbs_tensor.raw_data()->Data(), + fbs_tensor.raw_data()->size(), + ort_tensor.MutableData(), + static_cast(ort_tensor.Shape().Size())); + } +}; + +Status LoadOrtTensorOrtFormat(const fbs::Tensor& fbs_tensor, const AllocatorPtr allocator, + std::string& tensor_name, onnxruntime::Tensor& ort_tensor) { + auto* fbs_tensor_name = fbs_tensor.name(); + ORT_RETURN_IF_NOT(fbs_tensor_name, "Flatbuffer tensor is invalid. Expected: A valid tensor name. Actual: nullptr."); + tensor_name = fbs_tensor_name->str(); + + auto* tensor_dims = fbs_tensor.dims(); + ORT_RETURN_IF_NOT(tensor_dims, "Flatbuffer tensor is invalid. Expected: Valid tensor dims. Actual: nullptr."); + + const auto tensor_data_type = static_cast(fbs_tensor.data_type()); + const DataTypeImpl* tensor_dtype = DataTypeImpl::TensorTypeFromONNXEnum( + tensor_data_type) + ->GetElementType(); + ort_tensor = onnxruntime::Tensor( + tensor_dtype, TensorShape(tensor_dims->data(), tensor_dims->size()), allocator); + + // The tensor proto is used as a dummy here. The actual data is stored in the raw_data field of the flatbuffer. + // The data is copied from the raw_data field to the ort_tensor. + ONNX_NAMESPACE::TensorProto unused_tensor_proto; + unused_tensor_proto.set_data_type(tensor_data_type); + + onnxruntime::utils::MLTypeCallDispatcher + dispatcher(tensor_data_type); + return dispatcher.InvokeRet(unused_tensor_proto, fbs_tensor, ort_tensor); +} + +#endif // ENABLE_TRAINING_APIS + } // namespace onnxruntime::fbs::utils diff --git a/onnxruntime/core/graph/graph_flatbuffers_utils.h b/onnxruntime/core/graph/graph_flatbuffers_utils.h index 0088babad2dd0..b625cbf3ca492 100644 --- a/onnxruntime/core/graph/graph_flatbuffers_utils.h +++ b/onnxruntime/core/graph/graph_flatbuffers_utils.h @@ -5,8 +5,11 @@ #include +#include "flatbuffers/flatbuffers.h" + #include "core/common/status.h" #include "core/graph/ort_format_load_options.h" +#include "core/framework/tensor.h" namespace ONNX_NAMESPACE { class AttributeProto; @@ -17,12 +20,6 @@ class SparseTensorProto; #endif // !defined(DISABLE_SPARSE_TENSORS) } // namespace ONNX_NAMESPACE -namespace flatbuffers { -class FlatBufferBuilder; -template -struct Offset; -} // namespace flatbuffers - namespace onnxruntime { class Graph; @@ -89,6 +86,30 @@ Status LoadAttributeOrtFormat(const fbs::Attribute& fbs_attr, const OrtFormatLoadOptions& load_options, const logging::Logger& logger); +#ifdef ENABLE_TRAINING_APIS + +/// @brief Save an ORT Tensor to a flatbuffer tensor +/// @param[in] tensor_name Name of the tensor +/// @param[in] ort_tensor ORT tensor to serialize to a flatbuffer tensor +/// @param[in] builder flatbuffer builder to use for creating the flatbuffer tensor +/// @param[out] fbs_tensor flatbuffer tensor to serialize the ORT tensor to +/// @return Status indicating success or providing error information +Status SaveOrtTensorOrtFormat( + const std::string& tensor_name, const onnxruntime::Tensor& ort_tensor, + flatbuffers::FlatBufferBuilder& builder, + flatbuffers::Offset& fbs_tensor); + +/// @brief Load an ORT tensor from a flatbuffer tensor +/// @param[in] fbs_tensor flatbuffer tensor to load the ORT tensor from +/// @param[in] allocator Allocator to use for creating the ORT tensor +/// @param[out] tensor_name Name of the tensor +/// @param[out] ort_tensor ORT tensor to load the flatbuffer tensor into +/// @return Status indicating success or providing error information +Status LoadOrtTensorOrtFormat(const fbs::Tensor& fbs_tensor, const AllocatorPtr allocator, + std::string& tensor_name, onnxruntime::Tensor& ort_tensor); + +#endif + } // namespace utils } // namespace fbs } // namespace onnxruntime diff --git a/onnxruntime/core/graph/graph_utils.cc b/onnxruntime/core/graph/graph_utils.cc index a819d30cce645..20e8161ee79fd 100644 --- a/onnxruntime/core/graph/graph_utils.cc +++ b/onnxruntime/core/graph/graph_utils.cc @@ -214,6 +214,10 @@ bool MatchesOpSinceVersion(const Node& node, std::initializer_list versions) { + return std::find(versions.begin(), versions.end(), node.SinceVersion()) != versions.end(); +} + bool MatchesOpSetDomain(const Node& node, std::string_view domain) { const auto& node_domain = node.Domain(); return node_domain == domain; @@ -223,6 +227,13 @@ bool IsSupportedOptypeVersionAndDomain(const Node& node, std::string_view op_type, std::initializer_list versions, std::string_view domain) { + std::vector versions_vec(versions); + return IsSupportedOptypeVersionAndDomain(node, op_type, versions_vec, domain); +} + +bool IsSupportedOptypeVersionAndDomain(const Node& node, std::string_view op_type, + gsl::span versions, + std::string_view domain) { return (node.OpType() == op_type && // we don't have op schemas in the minimal build so there's no way to check the deprecated flag #if !defined(ORT_MINIMAL_BUILD) @@ -412,10 +423,6 @@ void GraphEdge::RemoveGraphEdges(Graph& graph, const std::vector& edg #if !defined(ORT_MINIMAL_BUILD) -bool MatchesOpSinceVersion(const Node& node, gsl::span versions) { - return std::find(versions.begin(), versions.end(), node.SinceVersion()) != versions.end(); -} - int GetNodeInputIndexFromInputName(const Node& node, const std::string& input_name) { return GetIndexFromName(node, input_name, true); } diff --git a/onnxruntime/core/graph/graph_utils.h b/onnxruntime/core/graph/graph_utils.h index 4d1555d6ace83..cf76ec785fda5 100644 --- a/onnxruntime/core/graph/graph_utils.h +++ b/onnxruntime/core/graph/graph_utils.h @@ -3,16 +3,9 @@ #pragma once -#if !defined(ORT_MINIMAL_BUILD) -#include "onnx/defs/schema.h" -#else -#include "onnx/defs/data_type_utils.h" -#endif -#include "onnx/onnx_pb.h" -#include "onnx/onnx-operators_pb.h" - #include "core/common/inlined_containers.h" #include "core/common/span_utils.h" +#include "core/graph/onnx_protobuf.h" #include "core/graph/graph.h" namespace onnxruntime { @@ -25,6 +18,10 @@ bool IsSupportedOptypeVersionAndDomain(const Node& node, std::string_view op_type, std::initializer_list versions, std::string_view domain = kOnnxDomain); +bool IsSupportedOptypeVersionAndDomain(const Node& node, + std::string_view op_type, + gsl::span versions, + std::string_view domain = kOnnxDomain); #if !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) @@ -104,7 +101,6 @@ struct GraphEdge { #endif // !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) -#if !defined(ORT_MINIMAL_BUILD) /** Checks if the node has the same operator since version as the given one. */ bool MatchesOpSinceVersion(const Node& node, std::initializer_list versions); bool MatchesOpSinceVersion(const Node& node, gsl::span versions); @@ -112,6 +108,7 @@ bool MatchesOpSinceVersion(const Node& node, gsl::spanset_version(version); } + model_local_functions_.reserve(model_local_functions.size()); for (auto& func : model_local_functions) { auto func_ptr = model_proto_.add_functions(); func_ptr->CopyFrom(func); - model_local_functions_[function_utils::GetFunctionIdentifier(func_ptr->domain(), func_ptr->name())] = func_ptr; + model_local_functions_.insert_or_assign(function_utils::GetFunctionIdentifier(func_ptr->domain(), func_ptr->name()), func_ptr); } model_local_function_templates_.reserve(model_proto_.functions().size()); @@ -115,7 +116,7 @@ Model::Model(const std::string& graph_name, } // need to call private ctor so can't use make_shared - GSL_SUPPRESS(r .11) + GSL_SUPPRESS(r.11) graph_.reset(new Graph(*this, model_proto_.mutable_graph(), *p_domain_to_version, IrVersion(), schema_registry, logger, options.strict_shape_type_inference)); } @@ -214,9 +215,9 @@ Model::Model(ModelProto&& model_proto, const PathString& model_path, } } - std::vector model_local_functions; + model_local_functions_.reserve(model_proto_.functions().size()); for (auto& func : model_proto_.functions()) { - model_local_functions_[function_utils::GetFunctionIdentifier(func.domain(), func.name())] = &func; + model_local_functions_.insert_or_assign(function_utils::GetFunctionIdentifier(func.domain(), func.name()), &func); } model_local_function_templates_.reserve(model_proto_.functions().size()); @@ -238,7 +239,7 @@ Model::Model(ModelProto&& model_proto, const PathString& model_path, } // create instance. need to call private ctor so can't use make_unique - GSL_SUPPRESS(r .11) + GSL_SUPPRESS(r.11) graph_.reset(new Graph(*this, model_proto_.mutable_graph(), domain_to_version, IrVersion(), schema_registry, logger, options.strict_shape_type_inference)); } @@ -344,10 +345,12 @@ ModelProto Model::ToProto() { } ModelProto Model::ToGraphProtoWithExternalInitializers(const std::string& external_file_name, + const PathString& file_path, size_t initializer_size_threshold) { ModelProto result(model_proto_); const auto& graph = *graph_; *(result.mutable_graph()) = graph.ToGraphProtoWithExternalInitializers(external_file_name, + file_path, initializer_size_threshold); return result; } @@ -388,7 +391,7 @@ Status Model::Load(const ModelProto& model_proto, } // need to call private ctor so can't use make_shared - GSL_SUPPRESS(r .11) + GSL_SUPPRESS(r.11) auto status = Status::OK(); ORT_TRY { @@ -428,7 +431,7 @@ Status Model::Load(ModelProto&& model_proto, } // need to call private ctor so can't use make_shared - GSL_SUPPRESS(r .11) + GSL_SUPPRESS(r.11) auto status = Status::OK(); ORT_TRY { model = std::make_unique(std::move(model_proto), model_path, local_registries, logger, options); @@ -475,7 +478,7 @@ static Status LoadModelHelper(const T& file_path, Loader loader) { } if (!status.IsOK()) { - GSL_SUPPRESS(es .84) + GSL_SUPPRESS(es.84) ORT_IGNORE_RETURN_VALUE(Env::Default().FileClose(fd)); return status; } @@ -548,7 +551,7 @@ static Status SaveModel(Model& model, const T& file_path) { }); } if (!status.IsOK()) { - GSL_SUPPRESS(es .84) + GSL_SUPPRESS(es.84) ORT_IGNORE_RETURN_VALUE(Env::Default().FileClose(fd)); return status; } @@ -572,7 +575,7 @@ static Status SaveModelWithExternalInitializers(Model& model, ORT_RETURN_IF_ERROR(status); ORT_TRY { - status = Model::SaveWithExternalInitializers(model, fd, external_file_name, + status = Model::SaveWithExternalInitializers(model, fd, file_path, external_file_name, initializer_size_threshold); } ORT_CATCH(const std::exception& ex) { @@ -581,7 +584,7 @@ static Status SaveModelWithExternalInitializers(Model& model, }); } if (!status.IsOK()) { - GSL_SUPPRESS(es .84) + GSL_SUPPRESS(es.84) ORT_IGNORE_RETURN_VALUE(Env::Default().FileClose(fd)); return status; } @@ -593,8 +596,8 @@ Status Model::Load(const PathString& file_path, return LoadModel(file_path, model_proto); } -GSL_SUPPRESS(r .30) // spurious warnings. p_model is potentially reset in the internal call to Load -GSL_SUPPRESS(r .35) +GSL_SUPPRESS(r.30) // spurious warnings. p_model is potentially reset in the internal call to Load +GSL_SUPPRESS(r.35) Status Model::Load(const PathString& file_path, std::shared_ptr& p_model, const IOnnxRuntimeOpSchemaRegistryList* local_registries, const logging::Logger& logger, const ModelOptions& options) { @@ -722,6 +725,7 @@ Status Model::Save(Model& model, int p_fd) { Status Model::SaveWithExternalInitializers(Model& model, int fd, + const PathString& file_path, const std::string& external_file_name, size_t initializer_size_threshold) { if (fd < 0) { @@ -730,7 +734,7 @@ Status Model::SaveWithExternalInitializers(Model& model, ORT_RETURN_IF_ERROR(model.MainGraph().Resolve()); - auto model_proto = model.ToGraphProtoWithExternalInitializers(external_file_name, initializer_size_threshold); + auto model_proto = model.ToGraphProtoWithExternalInitializers(external_file_name, file_path, initializer_size_threshold); google::protobuf::io::FileOutputStream output(fd); const bool result = model_proto.SerializeToZeroCopyStream(&output) && output.Flush(); if (result) { diff --git a/onnxruntime/core/graph/model.h b/onnxruntime/core/graph/model.h index bd1f53b43ca2d..6bdb68dd734f0 100644 --- a/onnxruntime/core/graph/model.h +++ b/onnxruntime/core/graph/model.h @@ -7,6 +7,9 @@ #include #include #include + +#include "flatbuffers/flatbuffers.h" + #include "core/common/path.h" #include "core/graph/graph_viewer.h" #include "core/graph/ort_format_load_options.h" @@ -15,12 +18,6 @@ #include "core/graph/function_template.h" #endif -namespace flatbuffers { -class FlatBufferBuilder; -template -struct Offset; -} // namespace flatbuffers - namespace onnxruntime { namespace fbs { @@ -191,6 +188,7 @@ class Model { // Save initializer larger than the given threshold (in bytes) into an external binary file // with the given name. This function is useful to avoid hitting the size limit of protobuf files. ONNX_NAMESPACE::ModelProto ToGraphProtoWithExternalInitializers(const std::string& external_file_name, + const PathString& file_path, size_t initializer_size_threshold); #ifdef _WIN32 @@ -217,6 +215,7 @@ class Model { static common::Status SaveWithExternalInitializers(Model& model, int fd, + const PathString& file_path, const std::string& external_file_name, size_t initializer_size_threshold); @@ -311,7 +310,8 @@ class Model { // map from function id to pointer of model local function proto // FunctionProto is hosted in ModelProto. // this map will be used for the local functions' schema's type/shape inference. - InlinedHashMap model_local_functions_; + // This container is used by ONNX code and must be an std::unordered_map. + std::unordered_map model_local_functions_; // this is the container that host the generated schemas for model local functions. // the generated schemare will be used for graph resolving and type/shape inference. // those schemas' type/shape inference will reference to the model_local_functions_ as context, diff --git a/onnxruntime/core/graph/node_attr_utils.h b/onnxruntime/core/graph/node_attr_utils.h index 461ec01d67f70..9433cfabc974e 100644 --- a/onnxruntime/core/graph/node_attr_utils.h +++ b/onnxruntime/core/graph/node_attr_utils.h @@ -7,8 +7,7 @@ #include "core/common/gsl.h" -#include "onnx/onnx_pb.h" - +#include "core/graph/onnx_protobuf.h" #include "core/graph/basic_types.h" namespace onnxruntime::utils { diff --git a/onnxruntime/core/graph/onnx_protobuf.h b/onnxruntime/core/graph/onnx_protobuf.h index b1e109e6d50ea..a24ff37e76eca 100644 --- a/onnxruntime/core/graph/onnx_protobuf.h +++ b/onnxruntime/core/graph/onnx_protobuf.h @@ -2,6 +2,21 @@ // Licensed under the MIT License. #pragma once +#include "onnxruntime_config.h" + +#ifdef _WIN32 +#pragma warning(push) +#pragma warning(disable : 4244) +#endif + +#if defined(__GNUC__) +#pragma GCC diagnostic push + +#ifdef HAS_SHORTEN_64_TO_32 +#pragma GCC diagnostic ignored "-Wshorten-64-to-32" +#endif + +#endif #if !defined(ORT_MINIMAL_BUILD) #include "onnx/defs/schema.h" @@ -11,3 +26,11 @@ #include "onnx/onnx_pb.h" #include "onnx/onnx-operators_pb.h" + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#ifdef _WIN32 +#pragma warning(pop) +#endif diff --git a/onnxruntime/core/graph/op.h b/onnxruntime/core/graph/op.h index f66e1eef37dcd..2a720a3ccad45 100644 --- a/onnxruntime/core/graph/op.h +++ b/onnxruntime/core/graph/op.h @@ -5,13 +5,7 @@ #include #include -#if !defined(ORT_MINIMAL_BUILD) -#include "onnx/defs/schema.h" -#else -#include "onnx/defs/data_type_utils.h" -#endif -#include "onnx/onnx_pb.h" -#include "onnx/onnx-operators_pb.h" +#include "core/graph/onnx_protobuf.h" #include "core/common/status.h" #include "core/graph/constants.h" diff --git a/onnxruntime/core/graph/op_identifier_utils.h b/onnxruntime/core/graph/op_identifier_utils.h index 14cec1f3f0c93..8a9351a2d0ddc 100644 --- a/onnxruntime/core/graph/op_identifier_utils.h +++ b/onnxruntime/core/graph/op_identifier_utils.h @@ -3,25 +3,13 @@ #pragma once +#include "flatbuffers/flatbuffers.h" + #include "core/graph/op_identifier.h" #include "core/common/status.h" #include "core/graph/graph.h" - -#if !defined(ORT_MINIMAL_BUILD) - -#include "onnx/defs/schema.h" // for ONNX_NAMESPACE::OpSchema - -#endif // !defined(ORT_MINIMAL_BUILD) - -namespace flatbuffers { -class FlatBufferBuilder; - -template -struct Offset; - -struct String; -} // namespace flatbuffers +#include "core/graph/onnx_protobuf.h" namespace onnxruntime { diff --git a/onnxruntime/core/graph/runtime_optimization_record_container.h b/onnxruntime/core/graph/runtime_optimization_record_container.h index 5db784f1a27af..a28b19e786de0 100644 --- a/onnxruntime/core/graph/runtime_optimization_record_container.h +++ b/onnxruntime/core/graph/runtime_optimization_record_container.h @@ -9,17 +9,11 @@ #include #include +#include "flatbuffers/flatbuffers.h" + #include "core/common/common.h" #include "core/graph/runtime_optimization_record.h" -namespace flatbuffers { -class FlatBufferBuilder; -template -struct Offset; -template -class Vector; -} // namespace flatbuffers - namespace onnxruntime { namespace fbs { diff --git a/onnxruntime/core/graph/schema_registry.cc b/onnxruntime/core/graph/schema_registry.cc index c6b817d6807ec..4dc714bd8af79 100644 --- a/onnxruntime/core/graph/schema_registry.cc +++ b/onnxruntime/core/graph/schema_registry.cc @@ -99,7 +99,7 @@ common::Status OnnxRuntimeOpSchemaRegistry::RegisterOpSchemaInternal(ONNX_NAMESP << "than the operator set version " << ver_range_it->second.opset_version << std::endl; return common::Status(common::ONNXRUNTIME, common::INVALID_ARGUMENT, ostream.str()); } - GSL_SUPPRESS(es .84) + GSL_SUPPRESS(es.84) map_[op_name][op_domain].emplace(std::make_pair(ver, op_schema)); return common::Status::OK(); } @@ -172,7 +172,7 @@ void SchemaRegistryManager::GetDomainToVersionMapForRegistries(DomainToVersionMa // If the map doesn't yet contain this domain, insert it with this registry's value. // Otherwise, merge the existing range in the map. if (iter == domain_version_map.end()) { - GSL_SUPPRESS(es .84) + GSL_SUPPRESS(es.84) domain_version_map.insert(local_domain); } else { iter->second = std::max(iter->second, local_domain.second); @@ -194,7 +194,7 @@ DomainToVersionMap SchemaRegistryManager::GetLastReleasedOpsetVersions(bool is_o continue; auto it = domain_version_map.find(domain.first); if (it == domain_version_map.end()) { - GSL_SUPPRESS(es .84) + GSL_SUPPRESS(es.84) domain_version_map.insert(std::make_pair(domain.first, domain.second)); } else { it->second = std::max(it->second, domain.second); @@ -217,7 +217,7 @@ DomainToVersionMap SchemaRegistryManager::GetLatestOpsetVersions(bool is_onnx_on continue; auto it = domain_version_map.find(domain.first); if (it == domain_version_map.end()) { - GSL_SUPPRESS(es .84) + GSL_SUPPRESS(es.84) domain_version_map.insert(std::make_pair(domain.first, domain.second.second)); } else { it->second = std::max(it->second, domain.second.second); @@ -271,7 +271,7 @@ void SchemaRegistryManager::GetSchemaAndHistory( } if (new_version < version) { - GSL_SUPPRESS(es .84) + GSL_SUPPRESS(es.84) unchecked_registry_indices.insert(unchecked_registry_indices.end(), checked_registry_indices.begin(), checked_registry_indices.end()); diff --git a/onnxruntime/core/mlas/inc/mlas.h b/onnxruntime/core/mlas/inc/mlas.h index d44e0ab155066..fd6b3df93444b 100644 --- a/onnxruntime/core/mlas/inc/mlas.h +++ b/onnxruntime/core/mlas/inc/mlas.h @@ -1439,7 +1439,7 @@ class MLAS_HALF_GEMM_POSTPROCESSOR { /** * @brief Half precision activation functions, with optional sum tensor. * Supplied sum tensor must be the same layout as the GEMM output tensor. - * And the supplied sum tensor will be added to the final result. + * And the supplied sum tensor will be added to the tensor before activation. */ class MLAS_HALF_GEMM_ACTIVATION_PROCESSOR : public MLAS_HALF_GEMM_POSTPROCESSOR { diff --git a/onnxruntime/core/mlas/inc/mlas_q4.h b/onnxruntime/core/mlas/inc/mlas_q4.h new file mode 100644 index 0000000000000..65b48a3009e72 --- /dev/null +++ b/onnxruntime/core/mlas/inc/mlas_q4.h @@ -0,0 +1,231 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Licensed under the MIT License. + +Module Name: + + mlas_q4.h + +Abstract: + + This module contains the public data structures and procedure prototypes + for blocked int4 quantization and dequantization. + + Int4 block quantization is used to compress weight tensors of large + language models. + +--*/ + +#pragma once + +#include "mlas.h" + +#include +#include + +/** + * @brief Define types of block quantization + */ +typedef enum { + BlkQ4Sym = 0, /*!< int4 Symmetric Block Quantization, zero_point = 0 */ + BlkQ4Zp8 = 1, /*!< int4 Block Quantization, zero_point is int8 type */ + BlkQ4Sym64 = 2, /*!< int4 Symmetric Block Quantization, 64 values per block*/ + BlkQ4Sym128 = 4 /*!< int4 Symmetric Block Quantization, 128 values per block*/ +} MLAS_BLK_QUANT_TYPE; + +/** + * @brief Computes the number of bytes required to pack and int4-quantize + * a weight matrix + * @param QType type of block quantization + * @param N the number of columns of matrix B. + * @param K the number of rows of matrix B. + * @return size of the packing buffer, 0 if the operation is not yet supported. +*/ +size_t +MLASCALL +MlasQ4GemmPackBSize( + MLAS_BLK_QUANT_TYPE QType, + size_t N, + size_t K + ); + +/** + * @brief Prepack and Quantize fp32 weight tensor to int4 blocks + * + * @param QType type of block quantization + * @param PackedBuf destination buffer + * @param FpData the pointer to fp32 matrix + * @param N the number of columns of matrix B. + * @param K the number of rows of matrix B. + * @param ldb leading dimension of B +*/ +void +MLASCALL +MlasQ4GemmPackB( + MLAS_BLK_QUANT_TYPE QType, + void* PackedBuf, + const float* FpData, + size_t N, + size_t K, + size_t ldb + ); + + +/** + * @brief Unpack and dequantize from int4 to fp32, reverse operation of + * MlasQ4GemmPackB + * @param QType type of block quantization + * @param FpData destination buffer, the fp32 matrix + * @param PackedBuf int4 quantized and packed data + * @param N the number of columns of matrix B. + * @param K the number of rows of matrix B. + * @param ldb leading dimension of B + */ +void +MLASCALL +MlasQ4GemmUnPackB( + MLAS_BLK_QUANT_TYPE QType, + float* FpData, + const void* PackedBuf, + size_t N, + size_t K, + size_t ldb + ); + + +template +class MLAS_GEMM_POSTPROCESSOR +{ + public: + virtual void Process(T*, /**< the address of matrix to process */ + size_t, /**< the start row index of matrix */ + size_t, /**< the start col index of matrix */ + size_t, /**< the element count per row to process */ + size_t, /**< the element count per col to process */ + size_t /**< the leading dimension of matrix */ + ) const = 0; + + virtual ~MLAS_GEMM_POSTPROCESSOR() {} +}; + + +/** + * @brief Data parameters for Q4 GEMM routine + * C = A * B + Bias + * A must be a float32 matrix + * B must be a quantized and packed int4 blob + * All except C are [in] parameters + */ +struct MLAS_Q4_GEMM_DATA_PARAMS { + const float* A = nullptr; /**< address of A (float32 matrix)*/ + const void* B = nullptr; /**< address of B (quantized and packed int4 blob)*/ + const float* Bias = nullptr; /**< address of Bias, vector size N */ + float* C = nullptr; /**< address of result matrix */ + size_t lda = 0; /**< leading dimension of A */ + size_t ldc = 0; /**< leading dimension of C*/ + const MLAS_GEMM_POSTPROCESSOR* OutputProcessor = nullptr; +}; + +/** + * @brief Batched GEMM: C = A * B + Bias + * A must be a float32 matrix + * B must be a quantized and packed int4 blob + * + * @param[in] QType type of block quantization used in B + * @param[in] M row size of matrix A and C + * @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] BatchN number of batches + * @param[inout] DataParams An array (size BatchN) of parameter blocks + * @param[in] ThreadPool + * @return + */ +void MLASCALL +MlasQ4GemmBatch( + MLAS_BLK_QUANT_TYPE QType, + const size_t M, + const size_t N, + const size_t K, + const size_t BatchN, + const MLAS_Q4_GEMM_DATA_PARAMS* DataParams, + MLAS_THREADPOOL* ThreadPool = nullptr + ); + + +/** + * @brief Calculate the buffer size needed for int8 block quantize + * @param[in] QType Type of block quantization used + * @param[in] M Number of rows of the input matrix + * @param[in] K Number of columns of the input matrix + * @return buffer size (in bytes) needed, 0 if not yet supported on current hardware +*/ +size_t +MLASCALL +MlasQ80BlkQuantSize(MLAS_BLK_QUANT_TYPE QType, size_t M, size_t K); + +/** + * @brief Given an input float 2-D matrix, perform blocked int8 quantize + * + * @param QType Type of block quantization used + * @param Qblob Pointer to the output buffer + * @param A Pointer to the float matrix + * @param M Number of rows of the input matrix + * @param K Number of columns of the input matrix + * @param lda leading dimension of the input matrix + * @param ThreadPool +*/ +void +MLASCALL +MlasQ80BlkQuant( + MLAS_BLK_QUANT_TYPE QType, + void* Qblob, + const float* A, + size_t M, + size_t K, + size_t lda, + MLAS_THREADPOOL* ThreadPool + ); + + +/** + * @brief Data parameters for Q8Q4 GEMM routine + * C = A * B + Bias + * A must be a block quantized int8 matrix + * B must be a block quantized and packed int4 blob + * All except C are [in] parameters + */ +struct MLAS_Q8Q4_GEMM_DATA_PARAMS { + const void* A = nullptr; /**< address of A (quantized int8 blob)*/ + const void* B = nullptr; /**< address of B (quantized and packed int4 blob)*/ + const float* Bias = nullptr; /**< address of Bias, vector size N */ + float* C = nullptr; /**< address of result matrix */ + size_t ldc = 0; /**< leading dimension of C*/ + const MLAS_GEMM_POSTPROCESSOR* OutputProcessor = nullptr; +}; + +/** + * @brief Batched GEMM: C = A * B + Bias + * A must be a quantized int8 blob + * B must be a quantized and packed int4 blob + * + * @param[in] QType type of block quantization used in B + * @param[in] M row size of matrix A and C + * @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] BatchN number of batches + * @param[inout] DataParams An array (size BatchN) of parameter blocks + * @param[in] ThreadPool + * @return + */ +void MLASCALL +MlasQ8Q4GemmBatch( + MLAS_BLK_QUANT_TYPE QType, + const size_t M, + const size_t N, + const size_t K, + const size_t BatchN, + const MLAS_Q8Q4_GEMM_DATA_PARAMS* DataParams, + MLAS_THREADPOOL* ThreadPool + ); diff --git a/onnxruntime/core/mlas/lib/activate_fp16.cpp b/onnxruntime/core/mlas/lib/activate_fp16.cpp index f62ffe0db9b93..776ec67fccc1a 100644 --- a/onnxruntime/core/mlas/lib/activate_fp16.cpp +++ b/onnxruntime/core/mlas/lib/activate_fp16.cpp @@ -689,35 +689,35 @@ MlasActivationKernel( size_t n = CountN; while (n >= 8) { - MLAS_FLOAT16X8 Vector = MlasLoadFloat16x8(buffer); MLAS_FLOAT16X8 AVec = MlasLoadFloat16x8(addsrc); + MLAS_FLOAT16X8 Vector = MlasLoadFloat16x8(buffer); addsrc += 8; - Vector = ActivationFunction.Activate(Vector); Vector = MlasAddFloat16x8(Vector, AVec); + Vector = ActivationFunction.Activate(Vector); MlasStoreFloat16x8(buffer, Vector); buffer += 8; n -= 8; } if (n >= 4) { - MLAS_FLOAT16X4 Vector = MlasLoadFloat16x4(buffer); MLAS_FLOAT16X4 AVec = MlasLoadFloat16x4(addsrc); + MLAS_FLOAT16X4 Vector = MlasLoadFloat16x4(buffer); addsrc += 4; - Vector = ActivationFunction.Activate(Vector); Vector = MlasAddFloat16x4(Vector, AVec); + Vector = ActivationFunction.Activate(Vector); MlasStoreFloat16x4(buffer, Vector); buffer += 4; n -= 4; } if (n > 0) { - MLAS_FLOAT16X4 buf; - std::memcpy(&buf, buffer, n * sizeof(_mlas_fp16_)); MLAS_FLOAT16X4 addbuf; + MLAS_FLOAT16X4 buf; std::memcpy(&addbuf, addsrc, n * sizeof(_mlas_fp16_)); - MLAS_FLOAT16X4 res = ActivationFunction.Activate(buf); - res = MlasAddFloat16x4(res, addbuf); - MlasStorePartialFloat16x4(buffer, res, n); + std::memcpy(&buf, buffer, n * sizeof(_mlas_fp16_)); + buf = MlasAddFloat16x4(buf, addbuf); + buf = ActivationFunction.Activate(buf); + MlasStorePartialFloat16x4(buffer, buf, n); } CRow += ldc; @@ -858,8 +858,6 @@ MLAS_HALF_GEMM_ACTIVATION_PROCESSOR::Process( ) const { std::vector buffer(CountM*CountN); - MLAS_HALF_GEMM_2FLOAT_PROCESSOR proc(this->Activation_, buffer.data(), CountN); - proc.Process(C, StartM, StartN, CountM, CountN, ldc); _mlas_fp16_* Output = reinterpret_cast<_mlas_fp16_*>(C); auto* CRow = buffer.data(); @@ -876,6 +874,8 @@ MLAS_HALF_GEMM_ACTIVATION_PROCESSOR::Process( } CAdd += ldc; } + MlasActivation(&this->Activation_, CRow, nullptr, 1, CountN, CountN); + CvtFloat2Half(Output, CRow, CountN); CRow += CountN; Output += ldc; diff --git a/onnxruntime/core/mlas/lib/amx_common.h b/onnxruntime/core/mlas/lib/amx_common.h new file mode 100644 index 0000000000000..3eb0700932faa --- /dev/null +++ b/onnxruntime/core/mlas/lib/amx_common.h @@ -0,0 +1,80 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Licensed under the MIT License. + +Module Name: + + amx_common.h + +Abstract: + + Intrinsic and inline functions for amx processing. + +--*/ + +#pragma once + +#include "mlasi.h" + +#ifdef WIN32 +#define tile_dpbssd(dst, src1, src2) _tile_dpbssd(dst, src1, src2) + +#define tile_dpbsud(dst, src1, src2) _tile_dpbsud(dst, src1, src2) + +#define tile_dpbusd(dst, src1, src2) _tile_dpbusd(dst, src1, src2) + +#define tile_dpbuud(dst, src1, src2) _tile_dpbuud(dst, src1, src2) + +#define tile_loadd(dst, base, stride) _tile_loadd(dst, base, stride) + +#define tile_stream_loadd(dst, base, stride) _tile_stream_loadd(dst, base, stride) + +#define tile_stored(dst, base, stride) _tile_stored(dst, base, stride) + +#define tile_loadconfig(config) \ + _tile_loadconfig(config) + +#define tile_storeconfig(config) _tile_storeconfig(config) + +#else + +#define tile_dpbusd_internal(dst,src1,src2) \ +__asm__ volatile (".set Payload1, 0x01\n\t" \ + ".set Payload1, Payload1 + (("#src2" & 15) ^ 15) << 3\n\t" \ + ".set ModRMByte, 0xC0\n\t" \ + ".set ModRMByte, ModRMByte + ("#dst" << 3)\n\t" \ + ".set ModRMByte, ModRMByte + ("#src1")\n\t" \ + ".byte 0xC4, 0xE2, Payload1, 0x5E, ModRMByte\n\t") + +#define tile_dpbusd(dst,src1,src2) \ +tile_dpbusd_internal(dst,src1,src2) + +#define tile_loadd_internal1(dst,base,stride) \ + __asm__ volatile (".set ModRMByte, 0x04\n\t" \ + ".set ModRMByte, ModRMByte + ("#dst" << 3)\n\t" \ + ".byte 0xC4, 0xE2, 0x7B, 0x4B, ModRMByte, 0x18\n\t" \ + :: "a" ((const void*) (base)), "b" ((long) (stride))) + +#define tile_loadd(dst,base,stride) \ + tile_loadd_internal1(dst, base, stride) + + +#define tile_stored_internal1(dst,base,stride) \ + __asm__ volatile (".set ModRMByte, 0x04\n\t" \ + ".set ModRMByte, ModRMByte + ("#dst" << 3)\n\t" \ + ".byte 0xC4, 0xE2, 0x7A, 0x4B, ModRMByte, 0x18\n\t" \ + :: "a" ((const void*) (base)), "b" ((long) (stride))) + +#define tile_stored(dst,base,stride) \ +tile_stored_internal1(dst, base, stride) + + +#define tile_loadconfig(config) \ +__asm__ volatile (".byte 0xC4, 0xE2, 0x78, 0x49, 0x00" :: "a" (((const void *)config))) \ + +#define tile_storeconfig(config) \ +__asm__ volatile (".byte 0xC4, 0xE2, 0x79, 0x49, 0x00" :: "a" (((const void *)config))) \ + +#endif diff --git a/onnxruntime/core/mlas/lib/mlasi.h b/onnxruntime/core/mlas/lib/mlasi.h index ea620877edbdd..b6ac4a1ca1d6c 100644 --- a/onnxruntime/core/mlas/lib/mlasi.h +++ b/onnxruntime/core/mlas/lib/mlasi.h @@ -51,7 +51,14 @@ Module Name: #endif #if defined(__x86_64__) || defined(__i386__) #include +#if defined(__GNUC__) && __GNUC__ >= 12 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // GCC 12 warns about uninitialized variables in immintrin.h. #include +#pragma GCC diagnostic pop +#else +#include +#endif #endif #if defined(__VSX__) #include @@ -626,6 +633,24 @@ void int8_t ZeroPoint ); +typedef +void +(MLASCALL MLAS_QUANTIZE_LINEAR_U16_KERNEL)( + const float* Input, + uint16_t* Output, + size_t N, + float Scale, + uint16_t ZeroPoint); + +typedef +void +(MLASCALL MLAS_QUANTIZE_LINEAR_S16_KERNEL)( + const float* Input, + int16_t* Output, + size_t N, + float Scale, + int16_t ZeroPoint); + template struct MLAS_QUANT_KERNEL { @@ -742,6 +767,8 @@ extern "C" { MLAS_QLINEAR_BINARY_OP_U8_KERNEL MlasQLinearAddU8Kernel; MLAS_QUANTIZE_LINEAR_S8_KERNEL MlasQuantizeLinearS8Kernel; MLAS_QUANTIZE_LINEAR_U8_KERNEL MlasQuantizeLinearU8Kernel; + MLAS_QUANTIZE_LINEAR_S16_KERNEL MlasQuantizeLinearS16Kernel; + MLAS_QUANTIZE_LINEAR_U16_KERNEL MlasQuantizeLinearU16Kernel; #if defined(MLAS_TARGET_AMD64) MLAS_COMPUTE_UNARY_FLOAT_KERNEL MlasErfKernelFma3; MLAS_COMPUTE_UNARY_FLOAT_KERNEL MlasComputeExpF32KernelFma3; @@ -782,7 +809,7 @@ extern "C" { // value. // -#define MLAS_DEFAULT_PREFERRED_BUFFER_ALIGNMENT 32 +#define MLAS_DEFAULT_PREFERRED_BUFFER_ALIGNMENT 64 // // Define the target number of per-thread multiplies before using another @@ -824,9 +851,7 @@ extern const MLAS_GEMM_QUANT_DISPATCH MlasGemmU8X8DispatchSse; extern const MLAS_GEMM_QUANT_DISPATCH MlasGemmU8S8DispatchSse41; extern const MLAS_GEMM_QUANT_DISPATCH MlasGemmU8S8DispatchAvx2; extern const MLAS_GEMM_QUANT_DISPATCH MlasGemmU8U8DispatchAvx2; -#ifdef MLAS_AMX_SUPPORTED extern const MLAS_GEMM_QUANT_DISPATCH MlasGemmU8S8DispatchAmx; -#endif extern const MLAS_GEMM_QUANT_DISPATCH MlasGemmU8X8DispatchNeon; extern const MLAS_GEMM_QUANT_DISPATCH MlasGemmX8S8DispatchNeon; extern const MLAS_GEMM_QUANT_DISPATCH MlasGemmU8X8DispatchUdot; @@ -857,6 +882,14 @@ extern const MLAS_CONV_SYM_DISPATCH MlasConvSymS8DispatchNeon; extern const MLAS_CONV_SYM_DISPATCH MlasConvSymU8DispatchDot; extern const MLAS_CONV_SYM_DISPATCH MlasConvSymS8DispatchDot; +struct MLAS_Q8Q4GEMM_DISPATCH; + +extern const MLAS_Q8Q4GEMM_DISPATCH MlasQ8Q4GemmDispatchAvx512vnni; + +struct MLAS_FPQ4GEMM_DISPATCH; + +extern const MLAS_FPQ4GEMM_DISPATCH MlasFpQ4GemmDispatchAvx512; + // // Quantized depthwise convolution kernels. // @@ -927,7 +960,9 @@ struct MLAS_PLATFORM { const MLAS_GEMM_QUANT_DISPATCH* GemmU8S8Dispatch; const MLAS_GEMM_QUANT_DISPATCH* GemmU8U8Dispatch; #elif defined(MLAS_TARGET_ARM64) - const MLAS_GEMM_QUANT_DISPATCH* GemmU8X8Dispatch; + const MLAS_GEMM_QUANT_DISPATCH* GemmU8U8Dispatch; + const MLAS_GEMM_QUANT_DISPATCH* GemmU8S8Dispatch; + const MLAS_GEMM_QUANT_DISPATCH* GemmS8S8Dispatch; #endif const MLAS_SYMM_QGEMM_DISPATCH* SymmQgemmDispatch{nullptr}; @@ -944,6 +979,8 @@ struct MLAS_PLATFORM { const MLAS_GEMM_QUANT_DISPATCH* GemmU8X8Dispatch; MLAS_QUANTIZE_LINEAR_S8_KERNEL* QuantizeLinearS8Kernel; MLAS_QUANTIZE_LINEAR_U8_KERNEL* QuantizeLinearU8Kernel; + MLAS_QUANTIZE_LINEAR_S16_KERNEL* QuantizeLinearS16Kernel; + MLAS_QUANTIZE_LINEAR_U16_KERNEL* QuantizeLinearU16Kernel; #endif #if defined(MLAS_TARGET_AMD64) MLAS_SGEMM_KERNEL_M1_ROUTINE* KernelM1Routine; @@ -971,6 +1008,8 @@ struct MLAS_PLATFORM { MLAS_REDUCE_MINIMUM_MAXIMUM_FLOAT_KERNEL* ReduceMinimumMaximumF32Kernel; MLAS_QUANTIZE_LINEAR_S8_KERNEL* QuantizeLinearS8Kernel; MLAS_QUANTIZE_LINEAR_U8_KERNEL* QuantizeLinearU8Kernel; + MLAS_QUANTIZE_LINEAR_S16_KERNEL* QuantizeLinearS16Kernel; + MLAS_QUANTIZE_LINEAR_U16_KERNEL* QuantizeLinearU16Kernel; uint32_t NchwcBlockSize; uint32_t PreferredBufferAlignment; int32_t MaximumThreadCount; @@ -980,6 +1019,8 @@ struct MLAS_PLATFORM { static constexpr int32_t MaximumThreadCount = MLAS_MAXIMUM_THREAD_COUNT; #endif + const MLAS_FPQ4GEMM_DISPATCH* FpQ4GemmDispatch{nullptr}; + const MLAS_Q8Q4GEMM_DISPATCH* Q8Q4GemmDispatch{nullptr}; }; inline diff --git a/onnxruntime/core/mlas/lib/platform.cpp b/onnxruntime/core/mlas/lib/platform.cpp index c52d4f3b0b8c4..96bc1d8010bed 100644 --- a/onnxruntime/core/mlas/lib/platform.cpp +++ b/onnxruntime/core/mlas/lib/platform.cpp @@ -55,7 +55,7 @@ MLASCPUIDInfo::MLASCPUIDInfo() #if defined(BUILD_MLAS_NO_ONNXRUNTIME) MLASCPUIDInfo::MLASCPUIDInfo() { - has_arm_neon_dot_ = ((getauxval(AT_HWCAP) & HWCAP_ASIMDDP) != 0); + has_arm_neon_dot_ = ((getauxval(AT_HWCAP) & HWCAP_ASIMDDP) != 0); // raw hack! Need CPUIDInfo implementation for more precise detection has_fp16_ = has_arm_neon_dot_; @@ -112,6 +112,14 @@ MLAS_INTERNAL_DATA MLAS_DECLSPEC_ALIGN(const int16_t MlasOpmask16BitTableAvx512[ #define _XCR_XFEATURE_ENABLED_MASK 0 #endif +#if !defined(XFEATURE_MASK_XTILE) +#define XFEATURE_XTILECFG 17 +#define XFEATURE_XTILEDATA 18 +#define XFEATURE_MASK_XTILECFG (1 << XFEATURE_XTILECFG) +#define XFEATURE_MASK_XTILEDATA (1 << XFEATURE_XTILEDATA) +#define XFEATURE_MASK_XTILE (XFEATURE_MASK_XTILECFG | XFEATURE_MASK_XTILEDATA) +#endif + inline uint64_t MlasReadExtendedControlRegister( @@ -142,11 +150,6 @@ bool MlasInitAMX() { #if defined(__linux__) -#define XFEATURE_XTILECFG 17 -#define XFEATURE_XTILEDATA 18 -#define XFEATURE_MASK_XTILECFG (1 << XFEATURE_XTILECFG) -#define XFEATURE_MASK_XTILEDATA (1 << XFEATURE_XTILEDATA) -#define XFEATURE_MASK_XTILE (XFEATURE_MASK_XTILECFG | XFEATURE_MASK_XTILEDATA) #define ARCH_GET_XCOMP_PERM 0x1022 #define ARCH_REQ_XCOMP_PERM 0x1023 @@ -230,6 +233,8 @@ Return Value: this->QLinearAddU8Kernel = MlasQLinearAddU8Kernel; this->QuantizeLinearS8Kernel = MlasQuantizeLinearS8Kernel; this->QuantizeLinearU8Kernel = MlasQuantizeLinearU8Kernel; + this->QuantizeLinearS16Kernel = MlasQuantizeLinearS16Kernel; + this->QuantizeLinearU16Kernel = MlasQuantizeLinearU16Kernel; this->NchwcBlockSize = 8; this->PreferredBufferAlignment = MLAS_DEFAULT_PREFERRED_BUFFER_ALIGNMENT; @@ -393,6 +398,7 @@ Return Value: this->GemvU8S8Kernel = MlasGemvU8S8KernelAvx512Core; this->GemmU8U8Kernel = MlasGemmU8U8KernelAvx512Core; this->ConvSymU8S8Dispatch = &MlasConvSymDispatchAvx512Core; + this->FpQ4GemmDispatch = &MlasFpQ4GemmDispatchAvx512; // // Check if the processor supports AVX512VNNI. @@ -404,22 +410,25 @@ Return Value: this->GemmU8S8Kernel = MlasGemmU8S8KernelAvx512Vnni; this->GemvU8S8Kernel = MlasGemvU8S8KernelAvx512Vnni; this->ConvSymU8S8Dispatch = &MlasConvSymDispatchAvx512Vnni; + this->Q8Q4GemmDispatch = &MlasQ8Q4GemmDispatchAvx512vnni; } } } -#ifdef MLAS_AMX_SUPPORTED +#ifndef __APPLE__ // // Check if the processor supports AMX-TILE and AMX-INT8 // features. // - if ((Cpuid7[3] & 0b1 << 24) != 0 && (Cpuid7[3] & 0b1 << 25) != 0) { + if ((Cpuid7[3] & 0b1 << 24) != 0 && + (Cpuid7[3] & 0b1 << 25) != 0 && + (xcr0 & XFEATURE_MASK_XTILE) == XFEATURE_MASK_XTILE) { if (MlasInitAMX()) { this->GemmU8U8Dispatch = &MlasGemmU8S8DispatchAmx; this->GemmU8S8Dispatch = &MlasGemmU8S8DispatchAmx; } } -#endif // MLAS_AMX_SUPPORTED +#endif // __APPLE__ #endif // ORT_MINIMAL_BUILD @@ -434,7 +443,9 @@ Return Value: #if defined(MLAS_TARGET_ARM64) - this->GemmU8X8Dispatch = &MlasGemmU8X8DispatchNeon; + this->GemmU8U8Dispatch = &MlasGemmU8X8DispatchNeon; + this->GemmU8S8Dispatch = &MlasGemmX8S8DispatchNeon; + this->GemmS8S8Dispatch = &MlasGemmX8S8DispatchNeon; this->SymmQgemmDispatch = &MlasSymmQgemmS8DispatchNeon; this->ConvSymU8S8Dispatch = &MlasConvSymU8DispatchNeon; this->ConvSymS8S8Dispatch = &MlasConvSymS8DispatchNeon; @@ -447,14 +458,19 @@ Return Value: #if defined(_WIN32) HasDotProductInstructions = (IsProcessorFeaturePresent(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE) != 0); -#elif defined(__linux__) - HasDotProductInstructions = MLAS_CPUIDINFO::GetCPUIDInfo().HasArmNeonDot(); +#elif !defined(__APPLE__) // The next few lines result in an EXC_BAD_INSTRUCTION runtime error on a M1 Mac so we + // disable it there. + uint64_t isar0_el1; + asm("mrs %[reg], ID_AA64ISAR0_EL1\n" : [reg] "=r"(isar0_el1) : :); + HasDotProductInstructions = ((isar0_el1 >> 44) & 0xfu) == 0x1u; #else - HasDotProductInstructions = false; + HasDotProductInstructions = MLAS_CPUIDINFO::GetCPUIDInfo().HasArmNeonDot(); #endif if (HasDotProductInstructions) { - this->GemmU8X8Dispatch = &MlasGemmU8X8DispatchUdot; + this->GemmU8U8Dispatch = &MlasGemmU8X8DispatchUdot; + this->GemmU8S8Dispatch = &MlasGemmU8X8DispatchUdot; + this->GemmS8S8Dispatch = &MlasGemmS8S8DispatchSdot; this->SymmQgemmDispatch = &MlasSymmQgemmS8DispatchSdot; this->ConvSymU8S8Dispatch = &MlasConvSymU8DispatchDot; this->ConvSymS8S8Dispatch = &MlasConvSymS8DispatchDot; @@ -466,6 +482,8 @@ Return Value: this->GemmDoubleKernel = MlasDgemmKernel; this->QuantizeLinearS8Kernel = MlasQuantizeLinearS8Kernel; this->QuantizeLinearU8Kernel = MlasQuantizeLinearU8Kernel; + this->QuantizeLinearS16Kernel = MlasQuantizeLinearS16Kernel; + this->QuantizeLinearU16Kernel = MlasQuantizeLinearU16Kernel; #if defined(__linux__) unsigned long hwcap2 = getauxval(AT_HWCAP2); diff --git a/onnxruntime/core/mlas/lib/power/QuantizePower.cpp b/onnxruntime/core/mlas/lib/power/QuantizePower.cpp index 0d38288c6d42c..830a3a6a492db 100644 --- a/onnxruntime/core/mlas/lib/power/QuantizePower.cpp +++ b/onnxruntime/core/mlas/lib/power/QuantizePower.cpp @@ -1,3 +1,4 @@ +#include #include "mlasi.h" #include @@ -82,8 +83,15 @@ Return Value: auto ShortVector0 = vec_pack(IntegerVector0, IntegerVector1); auto ShortVector1 = vec_pack(IntegerVector2, IntegerVector3); - auto CharVector = vec_pack(ShortVector0, ShortVector1); - vec_xst(CharVector, 0, (int8_t *) Output); + + if constexpr (std::is_same_v || std::is_same_v) { + auto CharVector = vec_pack(ShortVector0, ShortVector1); + vec_xst(CharVector, 0, Output); + } else { + static_assert(std::is_same_v || std::is_same_v); + vec_xst(ShortVector0, 0, Output); + vec_xst(ShortVector1, 0, &Output[8]); + } Output += 16; Input += 16; @@ -124,3 +132,30 @@ MlasQuantizeLinearS8Kernel( { MlasQuantizeLinearKernel(Input, Output, N, Scale, ZeroPoint); } + +void +MLASCALL +MlasQuantizeLinearU16Kernel( + const float* Input, + uint16_t* Output, + size_t N, + float Scale, + uint16_t ZeroPoint + ) +{ + MlasQuantizeLinearKernel(Input, Output, N, Scale, ZeroPoint); +} + +void +MLASCALL +MlasQuantizeLinearS16Kernel( + const float* Input, + int16_t* Output, + size_t N, + float Scale, + int16_t ZeroPoint + ) +{ + MlasQuantizeLinearKernel(Input, Output, N, Scale, ZeroPoint); +} + diff --git a/onnxruntime/core/mlas/lib/q4_dq.cpp b/onnxruntime/core/mlas/lib/q4_dq.cpp new file mode 100644 index 0000000000000..85c0d13006126 --- /dev/null +++ b/onnxruntime/core/mlas/lib/q4_dq.cpp @@ -0,0 +1,296 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Licensed under the MIT License. + +Module Name: + + q4_dq.cpp + +Abstract: + + This module contains the data structures and implementations + for blocked int4 quantization and dequantization. + + Int4 block quantization is used to compress weight tensors of large + language models. + +--*/ + +#include "q4common.h" + +template +constexpr +size_t +BlkQ4BufSize(size_t N, size_t K) +{ + const size_t KBlocks = MlasDivRoundup(K, T::BlkLen); + return N * KBlocks * T::BlobSize; +} + +size_t +MLASCALL +MlasQ4GemmPackBSize(MLAS_BLK_QUANT_TYPE QType, size_t N, size_t K) +{ + if (GetMlasPlatform().FpQ4GemmDispatch == nullptr) { + return 0; + } + + switch (QType) { + case BlkQ4Sym: + return BlkQ4BufSize(N, K); + case BlkQ4Sym64: + return BlkQ4BufSize(N, K); + case BlkQ4Sym128: + return BlkQ4BufSize(N, K); + default: + return BlkQ4BufSize(N, K); + } +} + + +template +MLAS_FORCEINLINE +void +MlasQ4GemmPackBImpl(void* PackedBuf, const float* FpData, size_t N, size_t K, size_t ldb) +{ + auto* dst_ptr = reinterpret_cast(PackedBuf); + + for (size_t n = 0; n < N; n ++) { + const float* src = FpData; // starting from top of the column + + for (size_t k = 0; k < K; k += T::BlkLen) { + size_t klen = std::min(size_t(T::BlkLen), K - k); + float amax = 0.0f; // abs(max) + float max = 0.0f; + + for (size_t l = 0; l < klen; l++) { + const float v = src[ldb * l]; + if (amax < fabsf(v)) { + amax = fabsf(v); + max = v; + } + } + + const float scale = max / (-8); + const float reciprocal_scale = scale ? 1.0f / scale : 0.0f; + MlasQ4BlkScale(dst_ptr) = scale; + uint8_t* data = MlasQ4BlkData(dst_ptr); + + for (size_t kk = 0; kk < klen; kk += 32) { + size_t kklen = std::min((size_t)32, klen - kk); + for (size_t l = 0; l < 16; l++) { + const float v0 = l < kklen ? src[ldb * (kk + l)] * reciprocal_scale : 0; + const uint8_t vi0 = (uint8_t)std::min(15.0f, std::max(0.0f, v0 + 8.5f)); + + const size_t l1 = l + 16; + const float v1 = (l1 < kklen) ? src[ldb * (kk + l1)] * reciprocal_scale : 0; + const uint8_t vi1 = (uint8_t)std::min(15.0f, std::max(0.0f, v1 + 8.5f)); + + data[l] = vi0 | (vi1 << 4); + } + data += 16; + } + + // Move to next block of values in this column + dst_ptr += T::BlobSize; + src += ldb * klen; + } + + FpData++; // move to next column + } +} + +template<> +MLAS_FORCEINLINE +void +MlasQ4GemmPackBImpl( + void* PackedBuf, const float* FpData, size_t N, size_t K, size_t ldb) +{ + auto* dst_ptr = reinterpret_cast(PackedBuf); + + for (size_t n = 0; n < N; n++) { + const float* src = FpData; // starting from top of the column + + for (size_t k = 0; k < K; k += MLAS_Q4TYPE_BLK1::BlkLen) { + size_t klen = std::min(MLAS_Q4TYPE_BLK1::BlkLen, K - k); + float min = std::numeric_limits::max(); + float max = -min; + + for (size_t l = 0; l < klen; l++) { + const float v = src[ldb * l]; + if (v < min) min = v; + if (v > max) max = v; + } + min = std::min(min, 0.0f); + max = std::max(max, 0.0f); + + const float scale = (max - min) / ((1 << 4) - 1); + const float reciprocal_scale = scale ? 1.0f / scale : 0.0f; + float zero_point_fp = min; + if (scale != 0.0f) { + zero_point_fp = 0.f - min / scale; + } + + // Handle any clamping + uint8_t& zp = MlasQ4BlkZeroPoint(dst_ptr); + if (zero_point_fp < 0.0f) { + zp = 0; + } else if (zero_point_fp > 15.0f) { + zp = 15; + } else { + zp = (uint8_t)roundf(zero_point_fp); + } + MlasQ4BlkScale(dst_ptr) = scale; + uint8_t* data = MlasQ4BlkData(dst_ptr); + + for (size_t kk = 0; kk < klen; kk += 32) { + size_t kklen = std::min((size_t)32, klen - kk); + for (size_t l = 0; l < 16; l++) { + const float v0 = l < kklen ? src[ldb * (kk + l)] : 0; + const uint8_t vi0 = (uint8_t)std::min( + 15.0f, std::max(0.0f, roundf(v0 * reciprocal_scale + zp))); + + const size_t l1 = l + 16; + const float v1 = (l1 < kklen) ? src[ldb * (kk + l1)] : 0; + const uint8_t vi1 = (uint8_t)std::min( + 15.0f, std::max(0.0f, roundf(v1 * reciprocal_scale + zp))); + + data[l] = vi0 | (vi1 << 4); + } + data += 16; + } + // move to next block of values in this column + dst_ptr += MLAS_Q4TYPE_BLK1::BlobSize; + src += ldb * klen; + } + FpData++; // move to next column + } +} + +void +MLASCALL +MlasQ4GemmPackB( + MLAS_BLK_QUANT_TYPE QType, + void* PackedBuf, + const float* FpData, + size_t N, + size_t K, + size_t ldb + ) +{ + switch (QType) { + case BlkQ4Sym: + return MlasQ4GemmPackBImpl(PackedBuf, FpData, N, K, ldb); + case BlkQ4Sym64: + return MlasQ4GemmPackBImpl(PackedBuf, FpData, N, K, ldb); + case BlkQ4Sym128: + return MlasQ4GemmPackBImpl(PackedBuf, FpData, N, K, ldb); + default: + return MlasQ4GemmPackBImpl(PackedBuf, FpData, N, K, ldb); + } +} + +template +MLAS_FORCEINLINE +void +MlasQ4GemmUnPackBImpl(float* FpData, const void* PackedBuf, size_t N, size_t K, size_t ldb) +{ + const auto* src = reinterpret_cast(PackedBuf); + for (size_t n = 0; n < N; n++) { + for (size_t k = 0; k < K; k += T::BlkLen) { + size_t CountK = std::min(K - k, T::BlkLen); + + float* dest = FpData + ldb * k + n; + const float scale = MlasQ4BlkScale(src); + const uint8_t* data = MlasQ4BlkData(src); + + for (size_t kk = 0; kk < CountK; kk += 32) { + size_t kklen = std::min((size_t)32, CountK - kk); + for (size_t l = 0; l < 16; l++) { + const uint8_t vi = data[l]; + + if (l < kklen) { + const int vi0 = (vi & 0x0F) - 8; + const float v0 = vi0 * scale; + dest[ldb * (kk + l)] = v0; + } + + const size_t l1 = l + 16; + if (l1 < kklen) { + const int vi1 = (vi >> 4) - 8; + const float v1 = vi1 * scale; + dest[ldb * (kk + l1)] = v1; + } + } + data += 16; + } + src += T::BlobSize; + } + } +} + +template<> +MLAS_FORCEINLINE +void +MlasQ4GemmUnPackBImpl( + float* FpData, const void* PackedBuf, size_t N, size_t K, size_t ldb) +{ + const auto* src = reinterpret_cast(PackedBuf); + for (size_t n = 0; n < N; n++) { + for (size_t k = 0; k < K; k += MLAS_Q4TYPE_BLK1::BlkLen) { + size_t CountK = std::min(K - k, MLAS_Q4TYPE_BLK1::BlkLen); + + float* dest = FpData + ldb * k + n; + const float s = MlasQ4BlkScale(src); + const uint8_t z = MlasQ4BlkZeroPoint(src); + const uint8_t* pp = MlasQ4BlkData(src); + + for (size_t kk = 0; kk < CountK; kk += 32) { + size_t kklen = std::min((size_t)32, CountK - kk); + for (size_t l = 0; l < 16; l++) { + const uint8_t vi = pp[l]; + + if (l < kklen) { + const int8_t vi0 = vi & 0x0F; + const float v0 = (vi0 - z) * s; + dest[ldb * (kk + l)] = v0; + } + + size_t l1 = l + 16; + if (l1 < kklen) { + const int8_t vi1 = vi >> 4; + const float v1 = (vi1 - z) * s; + dest[ldb * (kk + l1)] = v1; + } + } + pp += 16; + } + src += MLAS_Q4TYPE_BLK1::BlobSize; + } + } +} + +void +MLASCALL +MlasQ4GemmUnPackB( + MLAS_BLK_QUANT_TYPE QType, + float* FpData, + const void* PackedBuf, + size_t N, + size_t K, + size_t ldb + ) +{ + switch (QType) { + case BlkQ4Sym: + return MlasQ4GemmUnPackBImpl(FpData, PackedBuf, N, K, ldb); + case BlkQ4Sym64: + return MlasQ4GemmUnPackBImpl(FpData, PackedBuf, N, K, ldb); + case BlkQ4Sym128: + return MlasQ4GemmUnPackBImpl(FpData, PackedBuf, N, K, ldb); + default: + return MlasQ4GemmUnPackBImpl(FpData, PackedBuf, N, K, ldb); + } +} diff --git a/onnxruntime/core/mlas/lib/q4_dq_cli.cpp b/onnxruntime/core/mlas/lib/q4_dq_cli.cpp new file mode 100644 index 0000000000000..9c330b9eaf12a --- /dev/null +++ b/onnxruntime/core/mlas/lib/q4_dq_cli.cpp @@ -0,0 +1,304 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Licensed under the MIT License. + +Module Name: + + q4_dq_cli.cpp + +Abstract: + + This module implements a command line tool that quantize fp32 into int4, + or reverse this process.. + +--*/ + +#include "mlas_q4.h" + +#include +#include +#include +#include +#include +#include + +char* +getCmdOption(char** begin, char** end, const std::string& option) +{ + char** itr = std::find(begin, end, option); + if (itr != end && ++itr != end) { + return *itr; + } + return nullptr; +} + +void +usage(const char* cli) +{ + std::cout << std::endl; + std::cout << "This utility performs int4 quantize and dequantize of a matrix, usage: " << std::endl; + std::cout << " " << cli << " ACTION NUM_ROWS NUM_COLS [OPTIONS]" << std::endl; + std::cout << " ACTION: can be either q (quantize) or dq (de-quantize)." << std::endl; + std::cout << " NUM_ROWS: number of rows in the matrix." << std::endl; + std::cout << " NUM_COLS: number of columns in the matrix." << std::endl; + std::cout << "options:" << std::endl; + std::cout << " --quant_type {0, 1}." << std::endl; + std::cout << " Type of the block quantization." << std::endl; + std::cout << " 0: Symmetric block quant, with fp32 scale." << std::endl; + std::cout << " 1: (default) Block quant with fp32 scale and int8 zero-point." << std::endl; + std::cout << " --input_file {PATH}." << std::endl; + std::cout << " Path to the input file." << std::endl; + std::cout << " --input_offset {N}." << std::endl; + std::cout << " Skip the first N bytes when reading the input file." << std::endl; + std::cout << " Ignored when read from std in." << std::endl; + std::cout << " --output_file {PATH}." << std::endl; + std::cout << " Path to the output file. Write to std out when missing" << std::endl; + std::cout << " --output_format {txt,bin}" << std::endl; + std::cout << " txt: (default) text format: space separated numbers." << std::endl; + std::cout << " bin: Binary format, can not be output to std out." << std::endl; + std::cout << std::endl; +} + + +// +// Variable for commands +// +struct Cli { + bool dqmode = false; // false -> quantize, true -> dequantize + + size_t num_rows = 0; + size_t num_cols = 0; + + MLAS_BLK_QUANT_TYPE quant_type = BlkQ4Zp8; + + char* input_file = nullptr; + size_t input_offset = 0; + + char* output_file = nullptr; + bool output_bin = false; // false -> csv, true -> binary +}; + + +bool +parseArgs(int argc, char* argv[], Cli& cli) +{ + if (argc < 4) { + return false; + } + + if (strncmp(argv[1], "q", 2) == 0) { + cli.dqmode = false; + } else if (strncmp(argv[1], "dq", 3) == 0) { + cli.dqmode = true; + } else { + return false; + } + + errno = 0; + cli.num_rows = (size_t)strtoul(argv[2], nullptr, 0); + if (cli.num_rows == 0 || errno != 0) { + return false; + } + cli.num_cols = (size_t)strtoul(argv[3], nullptr, 0); + if (cli.num_cols == 0 || errno != 0) { + return false; + } + + char* quant_t = getCmdOption(argv + 4, argv + argc, "--quant_type"); + if (quant_t) { + if (strncmp(quant_t, "0", 2) == 0) { + cli.quant_type = BlkQ4Sym; + } + } + + cli.input_file = getCmdOption(argv + 4, argv + argc, "--input_file"); + char* offset_str = getCmdOption(argv + 4, argv + argc, "--input_offset"); + if (offset_str != nullptr) { + errno = 0; + cli.input_offset = (size_t)strtoul(offset_str, nullptr, 0); + if (errno != 0) { + return false; + } + } + + cli.output_file = getCmdOption(argv + 4, argv + argc, "--output_file"); + char* output_format_str = getCmdOption(argv + 4, argv + argc, "--output_format"); + if (output_format_str != nullptr) { + if (strncmp(output_format_str, "csv", 4) == 0) { + cli.output_bin = false; + } else if (strncmp(output_format_str, "bin", 4) == 0) { + cli.output_bin = true; + if (!cli.output_file) { + // can't dump binary file to std-out + return false; + } + } else { + return false; + } + } + return true; +} + + +void +readBinFile(const char* filename, size_t start, size_t expected_size, std::vector& buf) +{ + // open the file: + std::streampos fileSize; + std::ifstream file(filename, std::ios::binary); + + // get its size: + file.seekg(0, std::ios::end); + fileSize = file.tellg(); + file.seekg(0, std::ios::beg); + + file.seekg(start); + fileSize -= start; + if ((size_t)fileSize < expected_size) { + return; + } + + // read the data: + buf.resize(expected_size); + file.read((char*)buf.data(), expected_size); +} + + +void +writeUint8Txt(std::ostream& out, const uint8_t* data, size_t len) +{ + for (size_t i = 0; i < len; i++) { + out << (int)data[i] << " "; + if (((i+1) % 21 == 0)) { + out << std::endl; + } + } + out << std::endl; +} + + +int +quantize(const Cli& cli) +{ + std::vector srcbuf; + readBinFile(cli.input_file, cli.input_offset, cli.num_rows * cli.num_cols * sizeof(float), srcbuf); + if (srcbuf.size() == 0) { + std::cerr << "Failed to read expected amount of data from file " << cli.input_file + << std::endl; + return -1; + } + + size_t qsize = MlasQ4GemmPackBSize(cli.quant_type, cli.num_cols, cli.num_rows); + if (qsize == 0) { + std::cerr << "Int4 Quantization not yet supported on this platform!"; + return -1; + } + std::vector dstbuf(qsize); + MlasQ4GemmPackB(cli.quant_type, dstbuf.data(), (const float*)srcbuf.data(), cli.num_cols, + cli.num_rows, cli.num_cols); + + if (cli.output_bin) { + std::ofstream out(cli.output_file, std::ios::out | std::ios::binary); + if (!out) { + std::cerr << "Cannot open output file " << cli.output_file << std::endl; + return -1; + } + out.write((const char*)dstbuf.data(), dstbuf.size()); + } else { + std::streambuf* buf; + if (cli.output_file) { + std::ofstream out(cli.output_file, std::ios::out); + if (!out) { + std::cerr << "Cannot open output file " << cli.output_file << std::endl; + return -1; + } + buf = out.rdbuf(); + } else { + buf = std::cout.rdbuf(); + } +#if defined(__GNUC__) && __GNUC__ >= 12 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored \ + "-Wdangling-pointer" // TODO: suppress warning about dangling pointer until we have a fix + std::ostream stream(buf); +#pragma GCC diagnostic pop +#else + std::ostream stream(buf); +#endif + + writeUint8Txt(stream, dstbuf.data(), dstbuf.size()); + } + return 0; +} + +int +dequantize(const Cli& cli) +{ + size_t qsize = MlasQ4GemmPackBSize(cli.quant_type, cli.num_cols, cli.num_rows); + if (qsize == 0) { + std::cerr << "Int4 Quantization not yet supported on this platform!"; + return -1; + } + std::vector srcbuf; + readBinFile(cli.input_file, cli.input_offset, qsize, srcbuf); + if (srcbuf.size() == 0) { + std::cerr << "Failed to read expected amount of data from file " << cli.input_file + << std::endl; + return -1; + } + + std::vector dstbuf(cli.num_rows * cli.num_cols); + MlasQ4GemmUnPackB(cli.quant_type, dstbuf.data(), srcbuf.data(), cli.num_cols, cli.num_rows, + cli.num_cols); + + if (cli.output_bin) { + std::ofstream out(cli.output_file, std::ios::out | std::ios::binary); + if (!out) { + std::cerr << "Cannot open output file " << cli.output_file << std::endl; + return -1; + } + out.write((const char*)dstbuf.data(), std::streamsize(dstbuf.size()) * sizeof(float)); + } else { + std::streambuf* buf; + std::ofstream file_output_stream; + if (cli.output_file) { + file_output_stream.open(cli.output_file, std::ios::out); + if (file_output_stream.fail()) { + std::cerr << "Cannot open output file " << cli.output_file << std::endl; + return -1; + } + buf = file_output_stream.rdbuf(); + } else { + buf = std::cout.rdbuf(); + } + std::ostream stream(buf); + size_t lcount = 0; + for (float v : dstbuf) { + stream << v << " "; + if (++lcount >= 16) { + stream << std::endl; + lcount = 0; + } + } + stream << std::endl; + } + return 0; +} + + +int +main(int argc, char* argv[]) +{ + Cli cli; + if (!parseArgs(argc, argv, cli)) { + usage(argv[0]); + return -1; + } + if (cli.dqmode) { + return dequantize(cli); + } else { + return quantize(cli); + } +} diff --git a/onnxruntime/core/mlas/lib/q4common.h b/onnxruntime/core/mlas/lib/q4common.h new file mode 100644 index 0000000000000..532437797a084 --- /dev/null +++ b/onnxruntime/core/mlas/lib/q4common.h @@ -0,0 +1,154 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Licensed under the MIT License. + +Module Name: + + q4common.h + +Abstract: + + Define int4 block quantization types. + + Int4 block quantization is used to compress weight tensors of large + language models. It takes a number (must be multiple of 32) of floating + point values, calculates their quantization parameters, and saves + the parameters and the quantized data in a blob. +--*/ + +#include "mlas_q4.h" +#include "mlasi.h" + +#include +#include + +// +// Functions for locating data from a quantized blob +// +template +MLAS_FORCEINLINE +float& +MlasQ4BlkScale(uint8_t* BlkPtr) +{ + return *reinterpret_cast(BlkPtr); +} + +template +MLAS_FORCEINLINE +float +MlasQ4BlkScale(const uint8_t* BlkPtr) +{ + return *reinterpret_cast(BlkPtr); +} + +template +uint8_t& +MlasQ4BlkZeroPoint(uint8_t* BlkPtr); + +template +uint8_t +MlasQ4BlkZeroPoint(const uint8_t* BlkPtr); + +template +MLAS_FORCEINLINE +uint8_t* +MlasQ4BlkData(uint8_t* BlkPtr) +{ + return BlkPtr + sizeof(float); +} + +template +MLAS_FORCEINLINE +const uint8_t* +MlasQ4BlkData(const uint8_t* BlkPtr) +{ + return BlkPtr + sizeof(float); +} + +/** + * @brief Every block quantization type, its block size (BlkLen) + * Must be multiple of 32! + */ +constexpr size_t MLAS_QUANT4_BLK_UNIT = 32; + +/** + * @brief Representing int4 quantize type, block quant type 0: + * + * Block size 32, use 32 fp32 numbers to find quantization parameter: + * scale (fp 32) and no zero point, then quantize the numbers + * into int4. The resulting blob takes 16 + 4 = 20 bytes. + */ +struct MLAS_Q4TYPE_BLK0 { + static constexpr size_t BlkLen = MLAS_QUANT4_BLK_UNIT; + static constexpr size_t BlobSize = BlkLen / 2 + sizeof(float); +}; + +/** + * @brief Representing int4 quantize type, block quant type 1: + * + * Block size 32, use 32 fp32 numbers to find quantization parameter: + * scale (fp 32) and zero point (int8), and then quantize the numbers + * into int4. The resulting blob takes 16 + 5 = 21 bytes. + * + * So far this is the only type that includes a zero-point value. + * Maybe we should consider store the quantization parameters seperatedly. + */ +struct MLAS_Q4TYPE_BLK1 { + static constexpr size_t BlkLen = MLAS_QUANT4_BLK_UNIT; + static constexpr size_t BlobSize = BlkLen / 2 + sizeof(float) + sizeof(uint8_t); +}; + +template<> +inline uint8_t& +MlasQ4BlkZeroPoint(uint8_t* BlkPtr) +{ + return *(BlkPtr + sizeof(float)); +} + +template<> +inline uint8_t +MlasQ4BlkZeroPoint(const uint8_t* BlkPtr) +{ + return *(BlkPtr + sizeof(float)); +} + +template<> +inline uint8_t* +MlasQ4BlkData(uint8_t* BlkPtr) +{ + return BlkPtr + sizeof(float) + sizeof(uint8_t); +} + +template<> +inline const uint8_t* +MlasQ4BlkData(const uint8_t* BlkPtr) +{ + return BlkPtr + sizeof(float) + sizeof(uint8_t); +} + +/** + * @brief Representing int4 quantize type, block quant type 2: + * + * Block size 64, use 64 fp32 numbers to find quantization parameter: + * scale (fp 32) and no zero point, then quantize the numbers + * into int4. The resulting blob takes 32 + 4 = 36 bytes. + */ +struct MLAS_Q4TYPE_BLK2 { + static constexpr size_t BlkLen = MLAS_QUANT4_BLK_UNIT * 2; + static constexpr size_t BlobSize = BlkLen / 2 + sizeof(float); +}; + + +/** + * @brief Representing int4 quantize type, block quant type 4: + * + * Block size 128, use 128 fp32 numbers to find quantization parameter: + * scale (fp 32) and no zero point, then quantize the numbers + * into int4. The resulting blob takes 32 + 4 = 36 bytes. + */ +struct MLAS_Q4TYPE_BLK4 { + static constexpr size_t BlkLen = MLAS_QUANT4_BLK_UNIT * 4; + static constexpr size_t BlobSize = BlkLen / 2 + sizeof(float); +}; diff --git a/onnxruntime/core/mlas/lib/q4gemm.cpp b/onnxruntime/core/mlas/lib/q4gemm.cpp new file mode 100644 index 0000000000000..a734f53432bb6 --- /dev/null +++ b/onnxruntime/core/mlas/lib/q4gemm.cpp @@ -0,0 +1,179 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Licensed under the MIT License. + +Module Name: + + q4gemm.cpp + +Abstract: + + This module implements the fp32 matrix multiplication with compressed + weight tensor (right hand side). The assumption is the right hand side + tensor can be pre-packed and compressed using int-4 quantization to save + memory. +--*/ + +#include "q4gemm.h" + + +size_t +MLASCALL +MlasQ80BlkQuantSize(MLAS_BLK_QUANT_TYPE QType, size_t M, size_t K) +{ + if (GetMlasPlatform().Q8Q4GemmDispatch == nullptr) { + return 0; + } + switch (QType) { + case BlkQ4Zp8: + return MlasQ80BlkQuantSizeImpl(M, K); + case BlkQ4Sym64: + return MlasQ80BlkQuantSizeImpl(M, K); + case BlkQ4Sym128: + return MlasQ80BlkQuantSizeImpl(M, K); + default: + return MlasQ80BlkQuantSizeImpl(M, K); + } +} + + +void +MLASCALL +MlasQ80BlkQuant( + MLAS_BLK_QUANT_TYPE QType, + void* Qblob, + const float* A, + size_t M, + size_t K, + size_t lda, + MLAS_THREADPOOL* ThreadPool + ) +{ + auto* dispatch = GetMlasPlatform().Q8Q4GemmDispatch; + dispatch->Quants[QType](Qblob, A, M, K, lda, ThreadPool); +} + + +template +MLAS_FORCEINLINE +void +MlasQ4GemmBatchDriver( + MLAS_BLK_QUANT_TYPE QType, + const size_t M, + const size_t N, + const size_t K, + const size_t BatchN, + const ParamBlockType* DataParams, + MLAS_THREADPOOL* ThreadPool + ) +{ + //const MLAS_Q4GEMM_DISPATCH* dispatch = MlasQ4GemmGetDispatch(); + //MLAS_Q4GEMM_OPERATION* operation = dispatch->Operation; + void (*operation)(const size_t, const ParamBlockType*, const size_t, const size_t, const size_t, + const size_t) = nullptr; + + if constexpr (std::is_same_v) + { + operation = GetMlasPlatform().FpQ4GemmDispatch->Operations[QType]; + } + else { + operation = GetMlasPlatform().Q8Q4GemmDispatch->Operations[QType]; + } + + if (ThreadPool == nullptr) { + for (size_t gemm_i = 0; gemm_i < BatchN; gemm_i++) { + auto Data = &DataParams[gemm_i]; + operation(K, Data, 0, M, 0, N); + } + return; + } + + // + // Compute the number of target threads given the complexity of the SGEMM + // operation. Small requests should run using the single threaded path. + // + + const double Complexity = double(M) * double(N) * double(K) * double(BatchN); + + ptrdiff_t TargetThreadCount = ptrdiff_t(Complexity / double(MLAS_QGEMM_THREAD_COMPLEXITY)) + 1; + + ptrdiff_t MaximumThreadCount = MlasGetMaximumThreadCount(ThreadPool) * 8; + + if (TargetThreadCount >= MaximumThreadCount) { + TargetThreadCount = MaximumThreadCount; + } + + ptrdiff_t ThreadsPerGemm = TargetThreadCount / BatchN; + if (ThreadsPerGemm < 1) { + ThreadsPerGemm = 1; + } + + constexpr size_t StrideM = 128; + + size_t nc = N; + if (ThreadsPerGemm > 1) { + // more than one thread per GEMM + + const size_t BlockedM = MlasDivRoundup(M, StrideM); + const size_t max_nc = MlasDivRoundup(N * BlockedM, ThreadsPerGemm); + if (max_nc < nc) { + nc = std::min(nc, MlasDivRoundup(max_nc, MLAS_QGEMM_STRIDEN_THREAD_ALIGN) * + MLAS_QGEMM_STRIDEN_THREAD_ALIGN); + } + } + const size_t StrideN = nc; + + const size_t ThreadCountM = MlasDivRoundup(M, StrideM); + const size_t ThreadCountN = MlasDivRoundup(N, StrideN); + ThreadsPerGemm = ThreadCountM * ThreadCountN; + + MlasTrySimpleParallel(ThreadPool, ThreadsPerGemm * BatchN, [&](ptrdiff_t tid) { + const auto gemm_i = tid / ThreadsPerGemm; + const auto blk_i = tid % ThreadsPerGemm; + auto Data = &DataParams[gemm_i]; + + const ptrdiff_t ThreadIdN = blk_i / ThreadCountM; + const ptrdiff_t ThreadIdM = blk_i % ThreadCountM; + + const size_t RangeStartM = ThreadIdM * StrideM; + const size_t RangeCountM = std::min(M - RangeStartM, (size_t)StrideM); + + const size_t RangeStartN = ThreadIdN * StrideN; + const size_t RangeCountN = std::min(N - RangeStartN, (size_t)StrideN); + + operation(K, Data, RangeStartM, RangeCountM, RangeStartN, RangeCountN); + }); +} + + +void +MLASCALL +MlasQ4GemmBatch( + MLAS_BLK_QUANT_TYPE QType, + const size_t M, + const size_t N, + const size_t K, + const size_t BatchN, + const MLAS_Q4_GEMM_DATA_PARAMS* DataParams, + MLAS_THREADPOOL* ThreadPool + ) +{ + MlasQ4GemmBatchDriver(QType, M, N, K, BatchN, DataParams, ThreadPool); +} + +void +MLASCALL +MlasQ8Q4GemmBatch( + MLAS_BLK_QUANT_TYPE QType, + const size_t M, + const size_t N, + const size_t K, + const size_t BatchN, + const MLAS_Q8Q4_GEMM_DATA_PARAMS* DataParams, + MLAS_THREADPOOL* ThreadPool + ) +{ + MlasQ4GemmBatchDriver(QType, M, N, K, BatchN, DataParams, ThreadPool); +} diff --git a/onnxruntime/core/mlas/lib/q4gemm.h b/onnxruntime/core/mlas/lib/q4gemm.h new file mode 100644 index 0000000000000..1562f9c0b4236 --- /dev/null +++ b/onnxruntime/core/mlas/lib/q4gemm.h @@ -0,0 +1,288 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Licensed under the MIT License. + +Module Name: + + q4gemm.h + +Abstract: + + int4 block quantization gemm kernel template declarations. + + Int4 block quantization is used to compress weight tensors of large + language models. It takes a number (must be multiple of 32) of floating + point values, calculates their quantization parameters, and saves + the parameters and the quantized data in a blob. +--*/ + +#include "q4common.h" + + +template +MLAS_FORCEINLINE +size_t +MlasQ4GemmKernel( + const float* A, + const uint8_t* PackedB, + float* C, + size_t CountM, + size_t CountN, + size_t CountK, + size_t lda, + size_t ldb, + size_t ldc, + const float* Bias +); + +template +MLAS_FORCEINLINE +void +MlasBlkQ4DequantB(float* FpData, const uint8_t* PackedB, size_t CountN, size_t CountK, size_t ldb); + + +template +MLAS_FORCEINLINE void +AddBiasAvx(const float* Bias, float* C, size_t CountM, size_t CountN, size_t ldc); + + + +template +void MLASCALL +MlasQ4GemmOperation( + const size_t K, + const MLAS_Q4_GEMM_DATA_PARAMS* DataParams, + const size_t RangeStartM, + const size_t RangeCountM, + const size_t RangeStartN, + const size_t RangeCountN +) +{ + const size_t lda = DataParams->lda; + const size_t ldc = DataParams->ldc; + + const size_t k_blks = MlasDivRoundup(K, Q4TYPE::BlkLen); + const size_t ldb = k_blks * Q4TYPE::BlobSize; + const float* A = DataParams->A + RangeStartM * lda; + const uint8_t* PackedB = (const uint8_t*)DataParams->B; + float* C = DataParams->C + RangeStartM * ldc + RangeStartN; + const float* Bias = DataParams->Bias; + + if (RangeCountM == 1) { + size_t CountN; + for (size_t n = 0; n < RangeCountN; n += CountN) { + CountN = std::min(RangeCountN - n, (size_t)128); + + // + // Step through each slice of matrix A along the M dimension. + // + const float* bias = (Bias == nullptr) ? nullptr : Bias + RangeStartN + n; + const uint8_t* b_col = PackedB + (RangeStartN + n) * ldb; + float* c_blk = C + n; + const float* a_row = A; + + size_t RowsRemaining = RangeCountM; + while (RowsRemaining > 0) { + auto RowsHandled = MlasQ4GemmKernel( + a_row, b_col, c_blk, RowsRemaining, CountN, K, lda, ldb, ldc, bias); + + if (DataParams->OutputProcessor != nullptr) { + DataParams->OutputProcessor->Process( + DataParams->C, RangeStartM + RangeCountM - RowsRemaining, RangeStartN, + RowsHandled, CountN, ldc); + } + + c_blk += ldc * RowsHandled; + a_row += lda * RowsHandled; + RowsRemaining -= RowsHandled; + } + } + return; + } + + constexpr size_t StrideN = 32; + size_t bufsize = k_blks * Q4TYPE::BlkLen * StrideN * sizeof(float); + MlasThreadedBufAlloc(bufsize); + auto* dequant_b = reinterpret_cast(ThreadedBufHolder.get()); + // + // Step through each slice of matrix B along the N dimension. + // + + size_t CountN; + for (size_t n = 0; n < RangeCountN; n += CountN) { + CountN = std::min(RangeCountN - n, (size_t)StrideN); + + // + // Step through each slice of matrix A along the M dimension. + // + const float* bias = (Bias == nullptr) ? nullptr : Bias + RangeStartN + n; + const uint8_t* b_col = PackedB + (RangeStartN + n) * ldb; + float* c_blk = C + n; + const float* a_row = A; + + MlasBlkQ4DequantB(dequant_b, b_col, CountN, K, ldb); + + size_t RowsRemaining = RangeCountM; + while (RowsRemaining > 0) { +#if defined(MLAS_TARGET_AMD64_IX86) || defined(MLAS_TARGET_POWER) + auto RowsHandled = GetMlasPlatform().GemmFloatKernel( + a_row, dequant_b, c_blk, K, RowsRemaining, CountN, lda, ldc, 1.f, true); +#else + auto RowsHandled = MlasSgemmKernelZero(a_row, dequant_b, c_blk, K, RowsRemaining, + CountN, lda, ldc, 1.f); +#endif + + if (bias) { + AddBiasAvx(bias, c_blk, RowsHandled, CountN, ldc); + } + if (DataParams->OutputProcessor != nullptr) { + DataParams->OutputProcessor->Process( + DataParams->C, RangeStartM + RangeCountM - RowsRemaining, RangeStartN, + RowsHandled, CountN, ldc); + } + + c_blk += ldc * RowsHandled; + a_row += lda * RowsHandled; + RowsRemaining -= RowsHandled; + } + } +} + +typedef +void +(MLAS_Q4GEMM_OPERATION)( + const size_t K, + const MLAS_Q4_GEMM_DATA_PARAMS* DataParams, + const size_t RangeStartM, + const size_t RangeCountM, + const size_t RangeStartN, + const size_t RangeCountN + ); + +struct MLAS_FPQ4GEMM_DISPATCH { + MLAS_Q4GEMM_OPERATION** Operations; +}; + +/** + * @brief Compute the size of a quantized block, one byte per value + fp32 scale + * @tparam QType + * @return + */ +template +constexpr size_t +Q8BlobUnitSize() +{ + return (QType::BlkLen + sizeof(float)); +} + +template +constexpr size_t +MlasQ80BlkQuantSizeImpl(size_t M, size_t K) +{ + const size_t KBlocks = MlasDivRoundup(K, QType::BlkLen); + + const size_t NumBlocks = M * KBlocks; + + return NumBlocks * Q8BlobUnitSize(); +} + +typedef +void +(MLAS_Q80_BLKQUANT)( + void* Qblob, + const float* A, + size_t M, + size_t K, + size_t lda, + MLAS_THREADPOOL* ThreadPool + ); + +template +MLAS_FORCEINLINE +size_t +MlasQ8Q4GemmKernel( + const int8_t* QuantA, + const uint8_t* PackedB, + float* C, + size_t CountM, + size_t CountN, + size_t CountK, + size_t lda, + size_t ldb, + size_t ldc, + const float* Bias + ); + + +template +void MLASCALL +MlasQ8Q4GemmOperation( + const size_t K, + const MLAS_Q8Q4_GEMM_DATA_PARAMS* DataParams, + const size_t RangeStartM, + const size_t RangeCountM, + const size_t RangeStartN, + const size_t RangeCountN +) +{ + const size_t k_blks = MlasDivRoundup(K, Q4TYPE::BlkLen); + const size_t ldb = k_blks * Q4TYPE::BlobSize; + const size_t lda = k_blks * Q8BlobUnitSize(); + const size_t ldc = DataParams->ldc; + + const int8_t* A = reinterpret_cast(DataParams->A) + RangeStartM * lda; + const uint8_t* PackedB = (const uint8_t*)DataParams->B; + float* C = DataParams->C + RangeStartM * ldc + RangeStartN; + const float* Bias = DataParams->Bias; + + // + // Step through each slice of matrix B along the N dimension. + // + + size_t CountN; + for (size_t n = 0; n < RangeCountN; n += CountN) { + CountN = std::min(RangeCountN - n, (size_t)128); + + // + // Step through each slice of matrix A along the M dimension. + // + const float* bias = (Bias == nullptr) ? nullptr : Bias + RangeStartN + n; + const uint8_t* b_col = PackedB + (RangeStartN + n) * ldb; + float* c_blk = C + n; + const int8_t* a_row = A; + + size_t RowsRemaining = RangeCountM; + while (RowsRemaining > 0) { + auto RowsHandled = MlasQ8Q4GemmKernel( + a_row, b_col, c_blk, RowsRemaining, CountN, K, lda, ldb, ldc, bias); + + if (DataParams->OutputProcessor != nullptr) { + DataParams->OutputProcessor->Process( + DataParams->C, RangeStartM + RangeCountM - RowsRemaining, RangeStartN, + RowsHandled, CountN, DataParams->ldc); + } + + c_blk += ldc * RowsHandled; + a_row += lda * RowsHandled; + RowsRemaining -= RowsHandled; + } + } +} + +typedef +void +(MLAS_Q8Q4GEMM_OPERATION)( + const size_t K, + const MLAS_Q8Q4_GEMM_DATA_PARAMS* DataParams, + const size_t RangeStartM, + const size_t RangeCountM, + const size_t RangeStartN, + const size_t RangeCountN + ); + +struct MLAS_Q8Q4GEMM_DISPATCH { + MLAS_Q80_BLKQUANT** Quants; + MLAS_Q8Q4GEMM_OPERATION** Operations; +}; diff --git a/onnxruntime/core/mlas/lib/q4gemm_avx512.cpp b/onnxruntime/core/mlas/lib/q4gemm_avx512.cpp new file mode 100644 index 0000000000000..f7af82ed12e0f --- /dev/null +++ b/onnxruntime/core/mlas/lib/q4gemm_avx512.cpp @@ -0,0 +1,1509 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Licensed under the MIT License. + +Module Name: + + q4gemm_avx512.cpp + +Abstract: + + This module implements the fp32 matrix multiplication with compressed + weight tensor (right hand side). The assumption is the right hand side + tensor can be pre-packed and compressed using int-4 quantization to save + memory. + Specificially on x64 avx512 +--*/ + +#include "q4gemm.h" + +#include +#include + +struct MLAS_FP_Q4_GEMM_KERNEL_AVX512VNNI { + static constexpr size_t StrideM = 256; +}; + +/** + * @brief Horizontally sum 4 vectors and store + * the results in the returned vector + */ +static MLAS_FORCEINLINE __m128 +FoldAccumulators(const __m512& acc0, const __m512& acc1, const __m512& acc2, const __m512& acc3) +{ + __m512 acc_lo01 = _mm512_unpacklo_ps(acc0, acc1); + __m512 acc_hi01 = _mm512_unpackhi_ps(acc0, acc1); + __m512 acc_lo23 = _mm512_unpacklo_ps(acc2, acc3); + __m512 acc_hi23 = _mm512_unpackhi_ps(acc2, acc3); + + __m512 acc_lo0123 = _mm512_castpd_ps( + _mm512_unpacklo_pd(_mm512_castps_pd(acc_lo01), _mm512_castps_pd(acc_lo23))); + __m512 acc_hi0123 = _mm512_castpd_ps( + _mm512_unpackhi_pd(_mm512_castps_pd(acc_lo01), _mm512_castps_pd(acc_lo23))); + acc_lo0123 = _mm512_add_ps(acc_lo0123, acc_hi0123); + acc_hi0123 = _mm512_castpd_ps( + _mm512_unpacklo_pd(_mm512_castps_pd(acc_hi01), _mm512_castps_pd(acc_hi23))); + acc_lo0123 = _mm512_add_ps(acc_lo0123, acc_hi0123); + acc_hi0123 = _mm512_castpd_ps( + _mm512_unpackhi_pd(_mm512_castps_pd(acc_hi01), _mm512_castps_pd(acc_hi23))); + acc_lo0123 = _mm512_add_ps(acc_lo0123, acc_hi0123); + + __m256 acc_y = + _mm256_add_ps(_mm512_extractf32x8_ps(acc_lo0123, 0), _mm512_extractf32x8_ps(acc_lo0123, 1)); + return _mm_add_ps(_mm256_extractf32x4_ps(acc_y, 0), _mm256_extractf32x4_ps(acc_y, 1)); +} + + +template +MLAS_FORCEINLINE +size_t +MlasQ4GemmKernelAvx512f( + const float* A, + const uint8_t* PackedB, + float* C, + size_t CountM, + size_t CountN, + size_t CountK, + size_t lda, + size_t ldb, + size_t ldc, + const float* Bias + ) +{ + // We process 32 quantized values in a batch. + static_assert(MLAS_QUANT4_BLK_UNIT == 32); + static_assert(Q4Type::BlkLen % MLAS_QUANT4_BLK_UNIT == 0); + + const __m256i lowMask = _mm256_set1_epi8(0xF); + + for (size_t m = 0; m < CountM; m++) { + const auto* b_col = PackedB; + auto* sum_ptr = C; + const auto* bias_ptr = Bias; + + int64_t nblk = (int64_t)(CountN) - 4; + while (nblk >= 0) { + __m512 acc_lo0 = _mm512_setzero_ps(); + __m512 acc_lo1 = _mm512_setzero_ps(); + __m512 acc_lo2 = _mm512_setzero_ps(); + __m512 acc_lo3 = _mm512_setzero_ps(); + const auto* b = b_col; + + for (size_t k = 0; k < CountK; k += Q4Type::BlkLen) { + size_t ck = std::min(CountK - k, Q4Type::BlkLen); + + const float scale_v0 = MlasQ4BlkScale(b); + const float scale_v1 = MlasQ4BlkScale(b + ldb); + const float scale_v2 = MlasQ4BlkScale(b + ldb * 2); + const float scale_v3 = MlasQ4BlkScale(b + ldb * 3); + + const __m128i* b0ptr = (const __m128i*)MlasQ4BlkData(b); + const __m128i* b1ptr = (const __m128i*)MlasQ4BlkData(b + ldb); + const __m128i* b2ptr = (const __m128i*)MlasQ4BlkData(b + ldb * 2); + const __m128i* b3ptr = (const __m128i*)MlasQ4BlkData(b + ldb * 3); + + for (size_t kk = 0; kk < ck; kk += MLAS_QUANT4_BLK_UNIT) { + size_t kklen = std::min((size_t)MLAS_QUANT4_BLK_UNIT, ck - kk); + + // Load A row vectors + uint32_t mask = 0xffffffff >> (MLAS_QUANT4_BLK_UNIT - kklen); + __m512 av_lo = _mm512_maskz_loadu_ps(__mmask16(mask), A + k + kk); + + mask = mask >> 16; + __m512 av_hi = mask == 0 ? _mm512_setzero_ps() + : _mm512_maskz_loadu_ps(__mmask16(mask), A + k + kk + 16); + + // Load B col vectors + const __m128i bvi4_0 = _mm_loadu_si128(b0ptr++); + const __m128i bvi4_1 = _mm_loadu_si128(b1ptr++); + const __m128i bvi4_2 = _mm_loadu_si128(b2ptr++); + const __m128i bvi4_3 = _mm_loadu_si128(b3ptr++); + + // expand 4b into byte array + __m256i bytes0 = _mm256_set_m128i(_mm_srli_epi16(bvi4_0, 4), bvi4_0); + __m256i bytes1 = _mm256_set_m128i(_mm_srli_epi16(bvi4_1, 4), bvi4_1); + __m256i bytes2 = _mm256_set_m128i(_mm_srli_epi16(bvi4_2, 4), bvi4_2); + __m256i bytes3 = _mm256_set_m128i(_mm_srli_epi16(bvi4_3, 4), bvi4_3); + bytes0 = _mm256_and_si256(lowMask, bytes0); + bytes1 = _mm256_and_si256(lowMask, bytes1); + bytes2 = _mm256_and_si256(lowMask, bytes2); + bytes3 = _mm256_and_si256(lowMask, bytes3); + + // Subtract zero-point from the integers + if constexpr (std::is_same_v) { + // Subtract zero-point from the integers + bytes0 = _mm256_sub_epi8( + bytes0, _mm256_set1_epi8(MlasQ4BlkZeroPoint(b))); + bytes1 = _mm256_sub_epi8( + bytes1, + _mm256_set1_epi8(MlasQ4BlkZeroPoint(b + ldb))); + bytes2 = _mm256_sub_epi8( + bytes2, + _mm256_set1_epi8(MlasQ4BlkZeroPoint(b + ldb * 2))); + bytes3 = _mm256_sub_epi8( + bytes3, + _mm256_set1_epi8(MlasQ4BlkZeroPoint(b + ldb * 3))); + } else { + // Subtract 8 from the integers + const __m256i eight = _mm256_set1_epi8(8); + bytes0 = _mm256_sub_epi8(bytes0, eight); + bytes1 = _mm256_sub_epi8(bytes1, eight); + bytes2 = _mm256_sub_epi8(bytes2, eight); + bytes3 = _mm256_sub_epi8(bytes3, eight); + } + + // Convert to 16-bit int + const __m256i vx16_lo0 = + _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes0, 0)); + const __m256i vx16_hi0 = + _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes0, 1)); + const __m256i vx16_lo1 = + _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes1, 0)); + const __m256i vx16_hi1 = + _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes1, 1)); + const __m256i vx16_lo2 = + _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes2, 0)); + const __m256i vx16_hi2 = + _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes2, 1)); + const __m256i vx16_lo3 = + _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes3, 0)); + const __m256i vx16_hi3 = + _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes3, 1)); + + // Convert to 32-bit int -> float 32 + __m512 bvf_lo0 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_lo0)); + __m512 bvf_hi0 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_hi0)); + __m512 bvf_lo1 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_lo1)); + __m512 bvf_hi1 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_hi1)); + __m512 bvf_lo2 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_lo2)); + __m512 bvf_hi2 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_hi2)); + __m512 bvf_lo3 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_lo3)); + __m512 bvf_hi3 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_hi3)); + + __m512 s = _mm512_set1_ps(scale_v0); + bvf_lo0 = _mm512_mul_ps(bvf_lo0, s); + bvf_hi0 = _mm512_mul_ps(bvf_hi0, s); + s = _mm512_set1_ps(scale_v1); + bvf_lo1 = _mm512_mul_ps(bvf_lo1, s); + bvf_hi1 = _mm512_mul_ps(bvf_hi1, s); + s = _mm512_set1_ps(scale_v2); + bvf_lo2 = _mm512_mul_ps(bvf_lo2, s); + bvf_hi2 = _mm512_mul_ps(bvf_hi2, s); + s = _mm512_set1_ps(scale_v3); + bvf_lo3 = _mm512_mul_ps(bvf_lo3, s); + bvf_hi3 = _mm512_mul_ps(bvf_hi3, s); + + acc_lo0 = _mm512_fmadd_ps(bvf_lo0, av_lo, acc_lo0); + acc_lo0 = _mm512_fmadd_ps(bvf_hi0, av_hi, acc_lo0); + acc_lo1 = _mm512_fmadd_ps(bvf_lo1, av_lo, acc_lo1); + acc_lo1 = _mm512_fmadd_ps(bvf_hi1, av_hi, acc_lo1); + acc_lo2 = _mm512_fmadd_ps(bvf_lo2, av_lo, acc_lo2); + acc_lo2 = _mm512_fmadd_ps(bvf_hi2, av_hi, acc_lo2); + acc_lo3 = _mm512_fmadd_ps(bvf_lo3, av_lo, acc_lo3); + acc_lo3 = _mm512_fmadd_ps(bvf_hi3, av_hi, acc_lo3); + } + + b += Q4Type::BlobSize; + } + + __m128 acc_x = FoldAccumulators(acc_lo0, acc_lo1, acc_lo2, acc_lo3); + if (Bias != nullptr) { + acc_x = _mm_add_ps(acc_x, _mm_loadu_ps(bias_ptr)); + } + _mm_storeu_ps(sum_ptr, acc_x); + + // move to next 4 columns + b_col += 4 * ldb; + sum_ptr += 4; + bias_ptr += 4; + nblk -= 4; + } + + // left over columns less than 4 ? + nblk += 4; + if (nblk > 0) { + __m512 acc_lo[4]{}; + const auto* b = b_col; + + for (size_t k = 0; k < CountK; k += Q4Type::BlkLen) { + size_t ck = std::min(CountK - k, Q4Type::BlkLen); + + float scale_v[4]; + const __m128i* b_ptr[4]; + for (int64_t nn = 0; nn < nblk; nn++) { + const auto* bb = b + ldb * nn; + scale_v[nn] = MlasQ4BlkScale(bb); + b_ptr[nn] = (const __m128i*)MlasQ4BlkData(bb); + } + + for (size_t kk = 0; kk < ck; kk += MLAS_QUANT4_BLK_UNIT) { + size_t kklen = std::min((size_t)MLAS_QUANT4_BLK_UNIT, ck - kk); + + uint32_t mask = 0xffffffff >> (MLAS_QUANT4_BLK_UNIT - kklen); + __m512 av_lo = _mm512_maskz_loadu_ps(__mmask16(mask), A + k + kk); + + mask = mask >> 16; + __m512 av_hi = mask == 0 + ? _mm512_setzero_ps() + : _mm512_maskz_loadu_ps(__mmask16(mask), A + k + kk + 16); + + for (int64_t nn = 0; nn < nblk; nn++) { + const __m128i bvi4 = _mm_loadu_si128(b_ptr[nn]++); + __m256i bytes = _mm256_set_m128i(_mm_srli_epi16(bvi4, 4), bvi4); + bytes = _mm256_and_si256(lowMask, bytes); + + if constexpr (std::is_same_v) { + // Subtract zero-point from the integers + const auto* bb = b + ldb * nn; + const uint8_t zp = MlasQ4BlkZeroPoint(bb); + bytes = _mm256_sub_epi8(bytes, _mm256_set1_epi8(zp)); + } else { + // Subtract 8 from the integers + const __m256i eight = _mm256_set1_epi8(8); + bytes = _mm256_sub_epi8(bytes, eight); + } + + // Convert to 16-bit int + const __m256i vx16_lo = + _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes, 0)); + const __m256i vx16_hi = + _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes, 1)); + + // Convert to 32-bit int -> float 32 + __m512 bvf_lo = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_lo)); + __m512 bvf_hi = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_hi)); + __m512 s = _mm512_set1_ps(scale_v[nn]); + bvf_lo = _mm512_mul_ps(bvf_lo, s); + bvf_hi = _mm512_mul_ps(bvf_hi, s); + + acc_lo[nn] = _mm512_fmadd_ps(bvf_lo, av_lo, acc_lo[nn]); + acc_lo[nn] = _mm512_fmadd_ps(bvf_hi, av_hi, acc_lo[nn]); + } + } + b += Q4Type::BlobSize; + } + + for (int64_t nn = 0; nn < nblk; nn++) { + sum_ptr[nn] = _mm512_reduce_add_ps(acc_lo[nn]); + sum_ptr[nn] += Bias == nullptr ? 0.0f : bias_ptr[nn]; + } + } + + // Prepare pointers for the next row + C += ldc; + A += lda; + } + return CountM; +} + +template<> +MLAS_FORCEINLINE +size_t +MlasQ4GemmKernel( + const float* A, + const uint8_t* PackedB, + float* C, + size_t CountM, + size_t CountN, + size_t CountK, + size_t lda, + size_t ldb, + size_t ldc, + const float* Bias + ) +{ + return MlasQ4GemmKernelAvx512f(A, PackedB, C, CountM, CountN, CountK, lda, + ldb, ldc, Bias); +} + +template<> +MLAS_FORCEINLINE +size_t +MlasQ4GemmKernel( + const float* A, + const uint8_t* PackedB, + float* C, + size_t CountM, + size_t CountN, + size_t CountK, + size_t lda, + size_t ldb, + size_t ldc, + const float* Bias + ) +{ + return MlasQ4GemmKernelAvx512f(A, PackedB, C, CountM, CountN, CountK, lda, + ldb, ldc, Bias); +} + +template<> +MLAS_FORCEINLINE +size_t +MlasQ4GemmKernel( + const float* A, + const uint8_t* PackedB, + float* C, + size_t CountM, + size_t CountN, + size_t CountK, + size_t lda, + size_t ldb, + size_t ldc, + const float* Bias + ) +{ + return MlasQ4GemmKernelAvx512f(A, PackedB, C, CountM, CountN, CountK, lda, + ldb, ldc, Bias); +} + +template<> +MLAS_FORCEINLINE +size_t +MlasQ4GemmKernel( + const float* A, + const uint8_t* PackedB, + float* C, + size_t CountM, + size_t CountN, + size_t CountK, + size_t lda, + size_t ldb, + size_t ldc, + const float* Bias + ) +{ + return MlasQ4GemmKernelAvx512f(A, PackedB, C, CountM, CountN, CountK, lda, + ldb, ldc, Bias); +} + + +MLAS_FORCEINLINE +void +Transpose16x16Avx512( + float* dest, + __m512i r0, + __m512i r1, + __m512i r2, + __m512i r3, + __m512i r4, + __m512i r5, + __m512i r6, + __m512i r7, + __m512i r8, + __m512i r9, + __m512i ra, + __m512i rb, + __m512i rc, + __m512i rd, + __m512i re, + __m512i rf) +{ + + __m512i t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, ta, tb, tc, td, te, tf; + + t0 = _mm512_unpacklo_epi32( + r0, r1); // 0 16 1 17 4 20 5 21 8 24 9 25 12 28 13 29 + t1 = _mm512_unpackhi_epi32( + r0, r1); // 2 18 3 19 6 22 7 23 10 26 11 27 14 30 15 31 + t2 = _mm512_unpacklo_epi32(r2, r3); // 32 48 33 49 ... + t3 = _mm512_unpackhi_epi32(r2, r3); // 34 50 35 51 ... + t4 = _mm512_unpacklo_epi32(r4, r5); // 64 80 65 81 ... + t5 = _mm512_unpackhi_epi32(r4, r5); // 66 82 67 83 ... + t6 = _mm512_unpacklo_epi32(r6, r7); // 96 112 97 113 ... + t7 = _mm512_unpackhi_epi32(r6, r7); // 98 114 99 115 ... + t8 = _mm512_unpacklo_epi32(r8, r9); // 128 ... + t9 = _mm512_unpackhi_epi32(r8, r9); // 130 ... + ta = _mm512_unpacklo_epi32(ra, rb); // 160 ... + tb = _mm512_unpackhi_epi32(ra, rb); // 162 ... + tc = _mm512_unpacklo_epi32(rc, rd); // 196 ... + td = _mm512_unpackhi_epi32(rc, rd); // 198 ... + te = _mm512_unpacklo_epi32(re, rf); // 228 ... + tf = _mm512_unpackhi_epi32(re, rf); // 230 ... + + r0 = _mm512_unpacklo_epi64(t0, t2); // 0 16 32 48 ... + r1 = _mm512_unpackhi_epi64(t0, t2); // 1 17 33 49 ... + r2 = _mm512_unpacklo_epi64(t1, t3); // 2 18 34 49 ... + r3 = _mm512_unpackhi_epi64(t1, t3); // 3 19 35 51 ... + r4 = _mm512_unpacklo_epi64(t4, t6); // 64 80 96 112 ... + r5 = _mm512_unpackhi_epi64(t4, t6); // 65 81 97 114 ... + r6 = _mm512_unpacklo_epi64(t5, t7); // 66 82 98 113 ... + r7 = _mm512_unpackhi_epi64(t5, t7); // 67 83 99 115 ... + r8 = _mm512_unpacklo_epi64(t8, ta); // 128 144 160 176 ... + r9 = _mm512_unpackhi_epi64(t8, ta); // 129 145 161 178 ... + ra = _mm512_unpacklo_epi64(t9, tb); // 130 146 162 177 ... + rb = _mm512_unpackhi_epi64(t9, tb); // 131 147 163 179 ... + rc = _mm512_unpacklo_epi64(tc, te); // 192 208 228 240 ... + rd = _mm512_unpackhi_epi64(tc, te); // 193 209 229 241 ... + re = _mm512_unpacklo_epi64(td, tf); // 194 210 230 242 ... + rf = _mm512_unpackhi_epi64(td, tf); // 195 211 231 243 ... + + t0 = + _mm512_shuffle_i32x4(r0, r4, 0x88); // 0 16 32 48 8 24 40 56 64 80 96 112 ... + t1 = _mm512_shuffle_i32x4(r1, r5, 0x88); // 1 17 33 49 ... + t2 = _mm512_shuffle_i32x4(r2, r6, 0x88); // 2 18 34 50 ... + t3 = _mm512_shuffle_i32x4(r3, r7, 0x88); // 3 19 35 51 ... + t4 = _mm512_shuffle_i32x4(r0, r4, 0xdd); // 4 20 36 52 ... + t5 = _mm512_shuffle_i32x4(r1, r5, 0xdd); // 5 21 37 53 ... + t6 = _mm512_shuffle_i32x4(r2, r6, 0xdd); // 6 22 38 54 ... + t7 = _mm512_shuffle_i32x4(r3, r7, 0xdd); // 7 23 39 55 ... + t8 = _mm512_shuffle_i32x4(r8, rc, 0x88); // 128 144 160 176 ... + t9 = _mm512_shuffle_i32x4(r9, rd, 0x88); // 129 145 161 177 ... + ta = _mm512_shuffle_i32x4(ra, re, 0x88); // 130 146 162 178 ... + tb = _mm512_shuffle_i32x4(rb, rf, 0x88); // 131 147 163 179 ... + tc = _mm512_shuffle_i32x4(r8, rc, 0xdd); // 132 148 164 180 ... + td = _mm512_shuffle_i32x4(r9, rd, 0xdd); // 133 149 165 181 ... + te = _mm512_shuffle_i32x4(ra, re, 0xdd); // 134 150 166 182 ... + tf = _mm512_shuffle_i32x4(rb, rf, 0xdd); // 135 151 167 183 ... + + r0 = _mm512_shuffle_i32x4(t0, t8, 0x88); // 0 16 32 48 64 80 96 112 ... 240 + r1 = _mm512_shuffle_i32x4(t1, t9, 0x88); // 1 17 33 49 66 81 97 113 ... 241 + r2 = _mm512_shuffle_i32x4(t2, ta, 0x88); // 2 18 34 50 67 82 98 114 ... 242 + r3 = _mm512_shuffle_i32x4(t3, tb, 0x88); // 3 19 35 51 68 83 99 115 ... 243 + r4 = _mm512_shuffle_i32x4(t4, tc, 0x88); // 4 ... + r5 = _mm512_shuffle_i32x4(t5, td, 0x88); // 5 ... + r6 = _mm512_shuffle_i32x4(t6, te, 0x88); // 6 ... + r7 = _mm512_shuffle_i32x4(t7, tf, 0x88); // 7 ... + r8 = _mm512_shuffle_i32x4(t0, t8, 0xdd); // 8 ... + r9 = _mm512_shuffle_i32x4(t1, t9, 0xdd); // 9 ... + ra = _mm512_shuffle_i32x4(t2, ta, 0xdd); // 10 ... + rb = _mm512_shuffle_i32x4(t3, tb, 0xdd); // 11 ... + rc = _mm512_shuffle_i32x4(t4, tc, 0xdd); // 12 ... + rd = _mm512_shuffle_i32x4(t5, td, 0xdd); // 13 ... + re = _mm512_shuffle_i32x4(t6, te, 0xdd); // 14 ... + rf = _mm512_shuffle_i32x4(t7, tf, 0xdd); // 15 31 47 63 79 96 111 127 ... 255 + + _mm512_storeu_si512(dest, r0); + dest += 16; + _mm512_storeu_si512(dest, r1); + dest += 16; + _mm512_storeu_si512(dest, r2); + dest += 16; + _mm512_storeu_si512(dest, r3); + dest += 16; + _mm512_storeu_si512(dest, r4); + dest += 16; + _mm512_storeu_si512(dest, r5); + dest += 16; + _mm512_storeu_si512(dest, r6); + dest += 16; + _mm512_storeu_si512(dest, r7); + dest += 16; + _mm512_storeu_si512(dest, r8); + dest += 16; + _mm512_storeu_si512(dest, r9); + dest += 16; + _mm512_storeu_si512(dest, ra); + dest += 16; + _mm512_storeu_si512(dest, rb); + dest += 16; + _mm512_storeu_si512(dest, rc); + dest += 16; + _mm512_storeu_si512(dest, rd); + dest += 16; + _mm512_storeu_si512(dest, re); + dest += 16; + _mm512_storeu_si512(dest, rf); + dest += 16; +} + + +template +MLAS_FORCEINLINE +void +BlkQ4DequantBAvx512f( + float* FpData, const uint8_t* PackedB, size_t CountN, size_t CountK, size_t ldb) +{ + const __m256i lowMask = _mm256_set1_epi8(0xF); + + const auto* b_col = PackedB; + + int64_t nblk = (int64_t)(CountN)-16; + while (nblk >= 0) { + const auto* b = b_col; + + for (size_t k = 0; k < CountK; k += Q4Type::BlkLen) { + size_t ck = std::min(CountK - k, Q4Type::BlkLen); + + const float scale_v0 = MlasQ4BlkScale(b); + const float scale_v1 = MlasQ4BlkScale(b + ldb); + const float scale_v2 = MlasQ4BlkScale(b + ldb * 2); + const float scale_v3 = MlasQ4BlkScale(b + ldb * 3); + const float scale_v4 = MlasQ4BlkScale(b + ldb * 4); + const float scale_v5 = MlasQ4BlkScale(b + ldb * 5); + const float scale_v6 = MlasQ4BlkScale(b + ldb * 6); + const float scale_v7 = MlasQ4BlkScale(b + ldb * 7); + const float scale_v8 = MlasQ4BlkScale(b + ldb * 8); + const float scale_v9 = MlasQ4BlkScale(b + ldb * 9); + const float scale_va = MlasQ4BlkScale(b + ldb * 10); + const float scale_vb = MlasQ4BlkScale(b + ldb * 11); + const float scale_vc = MlasQ4BlkScale(b + ldb * 12); + const float scale_vd = MlasQ4BlkScale(b + ldb * 13); + const float scale_ve = MlasQ4BlkScale(b + ldb * 14); + const float scale_vf = MlasQ4BlkScale(b + ldb * 15); + + const __m128i* b0ptr = (const __m128i*)MlasQ4BlkData(b); + const __m128i* b1ptr = (const __m128i*)MlasQ4BlkData(b + ldb); + const __m128i* b2ptr = (const __m128i*)MlasQ4BlkData(b + ldb * 2); + const __m128i* b3ptr = (const __m128i*)MlasQ4BlkData(b + ldb * 3); + const __m128i* b4ptr = (const __m128i*)MlasQ4BlkData(b + ldb * 4); + const __m128i* b5ptr = (const __m128i*)MlasQ4BlkData(b + ldb * 5); + const __m128i* b6ptr = (const __m128i*)MlasQ4BlkData(b + ldb * 6); + const __m128i* b7ptr = (const __m128i*)MlasQ4BlkData(b + ldb * 7); + const __m128i* b8ptr = (const __m128i*)MlasQ4BlkData(b + ldb * 8); + const __m128i* b9ptr = (const __m128i*)MlasQ4BlkData(b + ldb * 9); + const __m128i* baptr = (const __m128i*)MlasQ4BlkData(b + ldb * 10); + const __m128i* bbptr = (const __m128i*)MlasQ4BlkData(b + ldb * 11); + const __m128i* bcptr = (const __m128i*)MlasQ4BlkData(b + ldb * 12); + const __m128i* bdptr = (const __m128i*)MlasQ4BlkData(b + ldb * 13); + const __m128i* beptr = (const __m128i*)MlasQ4BlkData(b + ldb * 14); + const __m128i* bfptr = (const __m128i*)MlasQ4BlkData(b + ldb * 15); + + for (size_t kk = 0; kk < ck; kk += MLAS_QUANT4_BLK_UNIT) { + size_t kklen = std::min((size_t)MLAS_QUANT4_BLK_UNIT, ck - kk); + + // Load B col vectors + const __m128i bvi4_0 = _mm_loadu_si128(b0ptr++); + const __m128i bvi4_1 = _mm_loadu_si128(b1ptr++); + const __m128i bvi4_2 = _mm_loadu_si128(b2ptr++); + const __m128i bvi4_3 = _mm_loadu_si128(b3ptr++); + + // expand 4b into byte array + __m256i bytes0 = _mm256_set_m128i(_mm_srli_epi16(bvi4_0, 4), bvi4_0); + __m256i bytes1 = _mm256_set_m128i(_mm_srli_epi16(bvi4_1, 4), bvi4_1); + __m256i bytes2 = _mm256_set_m128i(_mm_srli_epi16(bvi4_2, 4), bvi4_2); + __m256i bytes3 = _mm256_set_m128i(_mm_srli_epi16(bvi4_3, 4), bvi4_3); + bytes0 = _mm256_and_si256(lowMask, bytes0); + bytes1 = _mm256_and_si256(lowMask, bytes1); + bytes2 = _mm256_and_si256(lowMask, bytes2); + bytes3 = _mm256_and_si256(lowMask, bytes3); + + // Subtract zero-point from the integers + if constexpr (std::is_same_v) { + // Subtract zero-point from the integers + bytes0 = _mm256_sub_epi8( + bytes0, _mm256_set1_epi8(MlasQ4BlkZeroPoint(b))); + bytes1 = _mm256_sub_epi8( + bytes1, _mm256_set1_epi8(MlasQ4BlkZeroPoint(b + ldb))); + bytes2 = _mm256_sub_epi8( + bytes2, + _mm256_set1_epi8(MlasQ4BlkZeroPoint(b + ldb * 2))); + bytes3 = _mm256_sub_epi8( + bytes3, + _mm256_set1_epi8(MlasQ4BlkZeroPoint(b + ldb * 3))); + } else { + // Subtract 8 from the integers + const __m256i eight = _mm256_set1_epi8(8); + bytes0 = _mm256_sub_epi8(bytes0, eight); + bytes1 = _mm256_sub_epi8(bytes1, eight); + bytes2 = _mm256_sub_epi8(bytes2, eight); + bytes3 = _mm256_sub_epi8(bytes3, eight); + } + + // Convert to 16-bit int + __m256i vx16_lo0 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes0, 0)); + __m256i vx16_hi0 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes0, 1)); + __m256i vx16_lo1 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes1, 0)); + __m256i vx16_hi1 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes1, 1)); + __m256i vx16_lo2 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes2, 0)); + __m256i vx16_hi2 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes2, 1)); + __m256i vx16_lo3 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes3, 0)); + __m256i vx16_hi3 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes3, 1)); + + // Convert to 32-bit int -> float 32 + __m512 bvf_lo0 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_lo0)); + __m512 bvf_hi0 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_hi0)); + __m512 bvf_lo1 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_lo1)); + __m512 bvf_hi1 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_hi1)); + __m512 bvf_lo2 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_lo2)); + __m512 bvf_hi2 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_hi2)); + __m512 bvf_lo3 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_lo3)); + __m512 bvf_hi3 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_hi3)); + + __m512 s = _mm512_set1_ps(scale_v0); + bvf_lo0 = _mm512_mul_ps(bvf_lo0, s); + bvf_hi0 = _mm512_mul_ps(bvf_hi0, s); + s = _mm512_set1_ps(scale_v1); + bvf_lo1 = _mm512_mul_ps(bvf_lo1, s); + bvf_hi1 = _mm512_mul_ps(bvf_hi1, s); + s = _mm512_set1_ps(scale_v2); + bvf_lo2 = _mm512_mul_ps(bvf_lo2, s); + bvf_hi2 = _mm512_mul_ps(bvf_hi2, s); + s = _mm512_set1_ps(scale_v3); + bvf_lo3 = _mm512_mul_ps(bvf_lo3, s); + bvf_hi3 = _mm512_mul_ps(bvf_hi3, s); + + // Load B col vectors + const __m128i bvi4_4 = _mm_loadu_si128(b4ptr++); + const __m128i bvi4_5 = _mm_loadu_si128(b5ptr++); + const __m128i bvi4_6 = _mm_loadu_si128(b6ptr++); + const __m128i bvi4_7 = _mm_loadu_si128(b7ptr++); + + // expand 4b into byte array + bytes0 = _mm256_set_m128i(_mm_srli_epi16(bvi4_4, 4), bvi4_4); + bytes1 = _mm256_set_m128i(_mm_srli_epi16(bvi4_5, 4), bvi4_5); + bytes2 = _mm256_set_m128i(_mm_srli_epi16(bvi4_6, 4), bvi4_6); + bytes3 = _mm256_set_m128i(_mm_srli_epi16(bvi4_7, 4), bvi4_7); + bytes0 = _mm256_and_si256(lowMask, bytes0); + bytes1 = _mm256_and_si256(lowMask, bytes1); + bytes2 = _mm256_and_si256(lowMask, bytes2); + bytes3 = _mm256_and_si256(lowMask, bytes3); + + // Subtract zero-point from the integers + if constexpr (std::is_same_v) { + // Subtract zero-point from the integers + bytes0 = _mm256_sub_epi8( + bytes0, + _mm256_set1_epi8(MlasQ4BlkZeroPoint(b + ldb * 4))); + bytes1 = _mm256_sub_epi8( + bytes1, + _mm256_set1_epi8(MlasQ4BlkZeroPoint(b + ldb * 5))); + bytes2 = _mm256_sub_epi8( + bytes2, + _mm256_set1_epi8(MlasQ4BlkZeroPoint(b + ldb * 6))); + bytes3 = _mm256_sub_epi8( + bytes3, + _mm256_set1_epi8(MlasQ4BlkZeroPoint(b + ldb * 7))); + } else { + // Subtract 8 from the integers + const __m256i eight = _mm256_set1_epi8(8); + bytes0 = _mm256_sub_epi8(bytes0, eight); + bytes1 = _mm256_sub_epi8(bytes1, eight); + bytes2 = _mm256_sub_epi8(bytes2, eight); + bytes3 = _mm256_sub_epi8(bytes3, eight); + } + + // Convert to 16-bit int + vx16_lo0 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes0, 0)); + vx16_hi0 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes0, 1)); + vx16_lo1 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes1, 0)); + vx16_hi1 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes1, 1)); + vx16_lo2 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes2, 0)); + vx16_hi2 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes2, 1)); + vx16_lo3 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes3, 0)); + vx16_hi3 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes3, 1)); + + // Convert to 32-bit int -> float 32 + __m512 bvf_lo4 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_lo0)); + __m512 bvf_hi4 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_hi0)); + __m512 bvf_lo5 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_lo1)); + __m512 bvf_hi5 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_hi1)); + __m512 bvf_lo6 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_lo2)); + __m512 bvf_hi6 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_hi2)); + __m512 bvf_lo7 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_lo3)); + __m512 bvf_hi7 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_hi3)); + + s = _mm512_set1_ps(scale_v4); + bvf_lo4 = _mm512_mul_ps(bvf_lo4, s); + bvf_hi4 = _mm512_mul_ps(bvf_hi4, s); + s = _mm512_set1_ps(scale_v5); + bvf_lo5 = _mm512_mul_ps(bvf_lo5, s); + bvf_hi5 = _mm512_mul_ps(bvf_hi5, s); + s = _mm512_set1_ps(scale_v6); + bvf_lo6 = _mm512_mul_ps(bvf_lo6, s); + bvf_hi6 = _mm512_mul_ps(bvf_hi6, s); + s = _mm512_set1_ps(scale_v7); + bvf_lo7 = _mm512_mul_ps(bvf_lo7, s); + bvf_hi7 = _mm512_mul_ps(bvf_hi7, s); + + // Load B col vectors + const __m128i bvi4_8 = _mm_loadu_si128(b8ptr++); + const __m128i bvi4_9 = _mm_loadu_si128(b9ptr++); + const __m128i bvi4_a = _mm_loadu_si128(baptr++); + const __m128i bvi4_b = _mm_loadu_si128(bbptr++); + + // expand 4b into byte array + bytes0 = _mm256_set_m128i(_mm_srli_epi16(bvi4_8, 4), bvi4_8); + bytes1 = _mm256_set_m128i(_mm_srli_epi16(bvi4_9, 4), bvi4_9); + bytes2 = _mm256_set_m128i(_mm_srli_epi16(bvi4_a, 4), bvi4_a); + bytes3 = _mm256_set_m128i(_mm_srli_epi16(bvi4_b, 4), bvi4_b); + bytes0 = _mm256_and_si256(lowMask, bytes0); + bytes1 = _mm256_and_si256(lowMask, bytes1); + bytes2 = _mm256_and_si256(lowMask, bytes2); + bytes3 = _mm256_and_si256(lowMask, bytes3); + + // Subtract zero-point from the integers + if constexpr (std::is_same_v) { + // Subtract zero-point from the integers + bytes0 = _mm256_sub_epi8( + bytes0, + _mm256_set1_epi8(MlasQ4BlkZeroPoint(b + ldb * 8))); + bytes1 = _mm256_sub_epi8( + bytes1, + _mm256_set1_epi8(MlasQ4BlkZeroPoint(b + ldb * 9))); + bytes2 = _mm256_sub_epi8( + bytes2, + _mm256_set1_epi8(MlasQ4BlkZeroPoint(b + ldb * 10))); + bytes3 = _mm256_sub_epi8( + bytes3, + _mm256_set1_epi8(MlasQ4BlkZeroPoint(b + ldb * 11))); + } else { + // Subtract 8 from the integers + const __m256i eight = _mm256_set1_epi8(8); + bytes0 = _mm256_sub_epi8(bytes0, eight); + bytes1 = _mm256_sub_epi8(bytes1, eight); + bytes2 = _mm256_sub_epi8(bytes2, eight); + bytes3 = _mm256_sub_epi8(bytes3, eight); + } + + // Convert to 16-bit int + vx16_lo0 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes0, 0)); + vx16_hi0 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes0, 1)); + vx16_lo1 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes1, 0)); + vx16_hi1 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes1, 1)); + vx16_lo2 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes2, 0)); + vx16_hi2 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes2, 1)); + vx16_lo3 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes3, 0)); + vx16_hi3 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes3, 1)); + + // Convert to 32-bit int -> float 32 + __m512 bvf_lo8 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_lo0)); + __m512 bvf_hi8 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_hi0)); + __m512 bvf_lo9 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_lo1)); + __m512 bvf_hi9 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_hi1)); + __m512 bvf_loa = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_lo2)); + __m512 bvf_hia = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_hi2)); + __m512 bvf_lob = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_lo3)); + __m512 bvf_hib = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_hi3)); + + s = _mm512_set1_ps(scale_v8); + bvf_lo8 = _mm512_mul_ps(bvf_lo8, s); + bvf_hi8 = _mm512_mul_ps(bvf_hi8, s); + s = _mm512_set1_ps(scale_v9); + bvf_lo9 = _mm512_mul_ps(bvf_lo9, s); + bvf_hi9 = _mm512_mul_ps(bvf_hi9, s); + s = _mm512_set1_ps(scale_va); + bvf_loa = _mm512_mul_ps(bvf_loa, s); + bvf_hia = _mm512_mul_ps(bvf_hia, s); + s = _mm512_set1_ps(scale_vb); + bvf_lob = _mm512_mul_ps(bvf_lob, s); + bvf_hib = _mm512_mul_ps(bvf_hib, s); + + // Load B col vectors + const __m128i bvi4_c = _mm_loadu_si128(bcptr++); + const __m128i bvi4_d = _mm_loadu_si128(bdptr++); + const __m128i bvi4_e = _mm_loadu_si128(beptr++); + const __m128i bvi4_f = _mm_loadu_si128(bfptr++); + + // expand 4b into byte array + bytes0 = _mm256_set_m128i(_mm_srli_epi16(bvi4_c, 4), bvi4_c); + bytes1 = _mm256_set_m128i(_mm_srli_epi16(bvi4_d, 4), bvi4_d); + bytes2 = _mm256_set_m128i(_mm_srli_epi16(bvi4_e, 4), bvi4_e); + bytes3 = _mm256_set_m128i(_mm_srli_epi16(bvi4_f, 4), bvi4_f); + bytes0 = _mm256_and_si256(lowMask, bytes0); + bytes1 = _mm256_and_si256(lowMask, bytes1); + bytes2 = _mm256_and_si256(lowMask, bytes2); + bytes3 = _mm256_and_si256(lowMask, bytes3); + + // Subtract zero-point from the integers + if constexpr (std::is_same_v) { + // Subtract zero-point from the integers + bytes0 = _mm256_sub_epi8( + bytes0, + _mm256_set1_epi8(MlasQ4BlkZeroPoint(b + ldb * 12))); + bytes1 = _mm256_sub_epi8( + bytes1, + _mm256_set1_epi8(MlasQ4BlkZeroPoint(b + ldb * 13))); + bytes2 = _mm256_sub_epi8( + bytes2, + _mm256_set1_epi8(MlasQ4BlkZeroPoint(b + ldb * 14))); + bytes3 = _mm256_sub_epi8( + bytes3, + _mm256_set1_epi8(MlasQ4BlkZeroPoint(b + ldb * 15))); + } else { + // Subtract 8 from the integers + const __m256i eight = _mm256_set1_epi8(8); + bytes0 = _mm256_sub_epi8(bytes0, eight); + bytes1 = _mm256_sub_epi8(bytes1, eight); + bytes2 = _mm256_sub_epi8(bytes2, eight); + bytes3 = _mm256_sub_epi8(bytes3, eight); + } + + // Convert to 16-bit int + vx16_lo0 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes0, 0)); + vx16_hi0 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes0, 1)); + vx16_lo1 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes1, 0)); + vx16_hi1 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes1, 1)); + vx16_lo2 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes2, 0)); + vx16_hi2 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes2, 1)); + vx16_lo3 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes3, 0)); + vx16_hi3 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes3, 1)); + + // Convert to 32-bit int -> float 32 + __m512 bvf_loc = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_lo0)); + __m512 bvf_hic = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_hi0)); + __m512 bvf_lod = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_lo1)); + __m512 bvf_hid = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_hi1)); + __m512 bvf_loe = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_lo2)); + __m512 bvf_hie = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_hi2)); + __m512 bvf_lof = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_lo3)); + __m512 bvf_hif = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_hi3)); + + s = _mm512_set1_ps(scale_vc); + bvf_loc = _mm512_mul_ps(bvf_loc, s); + bvf_hic = _mm512_mul_ps(bvf_hic, s); + s = _mm512_set1_ps(scale_vd); + bvf_lod = _mm512_mul_ps(bvf_lod, s); + bvf_hid = _mm512_mul_ps(bvf_hid, s); + s = _mm512_set1_ps(scale_ve); + bvf_loe = _mm512_mul_ps(bvf_loe, s); + bvf_hie = _mm512_mul_ps(bvf_hie, s); + s = _mm512_set1_ps(scale_vf); + bvf_lof = _mm512_mul_ps(bvf_lof, s); + bvf_hif = _mm512_mul_ps(bvf_hif, s); + Transpose16x16Avx512(FpData, _mm512_castps_si512(bvf_lo0), + _mm512_castps_si512(bvf_lo1), _mm512_castps_si512(bvf_lo2), + _mm512_castps_si512(bvf_lo3), _mm512_castps_si512(bvf_lo4), + _mm512_castps_si512(bvf_lo5), _mm512_castps_si512(bvf_lo6), + _mm512_castps_si512(bvf_lo7), _mm512_castps_si512(bvf_lo8), + _mm512_castps_si512(bvf_lo9), _mm512_castps_si512(bvf_loa), + _mm512_castps_si512(bvf_lob), _mm512_castps_si512(bvf_loc), + _mm512_castps_si512(bvf_lod), _mm512_castps_si512(bvf_loe), + _mm512_castps_si512(bvf_lof)); + if (kklen > 16) { + Transpose16x16Avx512(FpData + 16 * 16, _mm512_castps_si512(bvf_hi0), + _mm512_castps_si512(bvf_hi1), _mm512_castps_si512(bvf_hi2), + _mm512_castps_si512(bvf_hi3), _mm512_castps_si512(bvf_hi4), + _mm512_castps_si512(bvf_hi5), _mm512_castps_si512(bvf_hi6), + _mm512_castps_si512(bvf_hi7), _mm512_castps_si512(bvf_hi8), + _mm512_castps_si512(bvf_hi9), _mm512_castps_si512(bvf_hia), + _mm512_castps_si512(bvf_hib), _mm512_castps_si512(bvf_hic), + _mm512_castps_si512(bvf_hid), _mm512_castps_si512(bvf_hie), + _mm512_castps_si512(bvf_hif)); + } + FpData += 16 * kklen; + } + + b += Q4Type::BlobSize; + } + + // move to next 16 columns + b_col += 16 * ldb; + nblk -= 16; + } + + // left over columns less than 16 ? + nblk += 16; + if (nblk > 0) { + const auto* b = b_col; + + for (size_t k = 0; k < CountK; k += Q4Type::BlkLen) { + size_t ck = std::min(CountK - k, Q4Type::BlkLen); + + float scale_v[16]; + const __m128i* b_ptr[16]; + for (int64_t nn = 0; nn < nblk; nn++) { + const auto* bb = b + ldb * nn; + scale_v[nn] = MlasQ4BlkScale(bb); + b_ptr[nn] = (const __m128i*)MlasQ4BlkData(bb); + } + + for (size_t kk = 0; kk < ck; kk += MLAS_QUANT4_BLK_UNIT) { + size_t kklen = std::min((size_t)MLAS_QUANT4_BLK_UNIT, ck - kk); + __m512 bvf_lo[16]; + __m512 bvf_hi[16]; + for (int64_t nn = 0; nn < nblk; nn++) { + const __m128i bvi4 = _mm_loadu_si128(b_ptr[nn]++); + __m256i bytes = _mm256_set_m128i(_mm_srli_epi16(bvi4, 4), bvi4); + bytes = _mm256_and_si256(lowMask, bytes); + + if constexpr (std::is_same_v) { + // Subtract zero-point from the integers + const auto* bb = b + ldb * nn; + const uint8_t zp = MlasQ4BlkZeroPoint(bb); + bytes = _mm256_sub_epi8(bytes, _mm256_set1_epi8(zp)); + } else { + // Subtract 8 from the integers + const __m256i eight = _mm256_set1_epi8(8); + bytes = _mm256_sub_epi8(bytes, eight); + } + + // Convert to 16-bit int + const __m256i vx16_lo = + _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes, 0)); + const __m256i vx16_hi = + _mm256_cvtepi8_epi16(_mm256_extracti128_si256(bytes, 1)); + + // Convert to 32-bit int -> float 32 + bvf_lo[nn] = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_lo)); + bvf_hi[nn] = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(vx16_hi)); + const __m512 s = _mm512_set1_ps(scale_v[nn]); + bvf_lo[nn] = _mm512_mul_ps(bvf_lo[nn], s); + bvf_hi[nn] = _mm512_mul_ps(bvf_hi[nn], s); + } + for (int64_t nn = nblk; nn < 16; nn++) { + bvf_lo[nn] = _mm512_setzero_ps(); + bvf_hi[nn] = _mm512_setzero_ps(); + } + Transpose16x16Avx512( + FpData, _mm512_castps_si512(bvf_lo[0]), _mm512_castps_si512(bvf_lo[1]), + _mm512_castps_si512(bvf_lo[2]), _mm512_castps_si512(bvf_lo[3]), + _mm512_castps_si512(bvf_lo[4]), _mm512_castps_si512(bvf_lo[5]), + _mm512_castps_si512(bvf_lo[6]), _mm512_castps_si512(bvf_lo[7]), + _mm512_castps_si512(bvf_lo[8]), _mm512_castps_si512(bvf_lo[9]), + _mm512_castps_si512(bvf_lo[10]), _mm512_castps_si512(bvf_lo[11]), + _mm512_castps_si512(bvf_lo[12]), _mm512_castps_si512(bvf_lo[13]), + _mm512_castps_si512(bvf_lo[14]), _mm512_castps_si512(bvf_lo[15])); + if (kklen > 16) { + Transpose16x16Avx512( + FpData + 16 * 16, _mm512_castps_si512(bvf_hi[0]), + _mm512_castps_si512(bvf_hi[1]), _mm512_castps_si512(bvf_hi[2]), + _mm512_castps_si512(bvf_hi[3]), _mm512_castps_si512(bvf_hi[4]), + _mm512_castps_si512(bvf_hi[5]), _mm512_castps_si512(bvf_hi[6]), + _mm512_castps_si512(bvf_hi[7]), _mm512_castps_si512(bvf_hi[8]), + _mm512_castps_si512(bvf_hi[9]), _mm512_castps_si512(bvf_hi[10]), + _mm512_castps_si512(bvf_hi[11]), _mm512_castps_si512(bvf_hi[12]), + _mm512_castps_si512(bvf_hi[13]), _mm512_castps_si512(bvf_hi[14]), + _mm512_castps_si512(bvf_hi[15])); + } + FpData += 16 * kklen; + } + b += Q4Type::BlobSize; + } + } +} + + +template<> +MLAS_FORCEINLINE void +MlasBlkQ4DequantB( + float* FpData, const uint8_t* PackedB, size_t CountN, size_t CountK, size_t ldb) +{ + BlkQ4DequantBAvx512f(FpData, PackedB, CountN, CountK, ldb); +} + +template <> +MLAS_FORCEINLINE void +MlasBlkQ4DequantB( + float* FpData, const uint8_t* PackedB, size_t CountN, size_t CountK, size_t ldb) +{ + BlkQ4DequantBAvx512f(FpData, PackedB, CountN, CountK, ldb); +} + +template <> +MLAS_FORCEINLINE void +MlasBlkQ4DequantB( + float* FpData, const uint8_t* PackedB, size_t CountN, size_t CountK, size_t ldb) +{ + BlkQ4DequantBAvx512f(FpData, PackedB, CountN, CountK, ldb); +} + +template <> +MLAS_FORCEINLINE void +MlasBlkQ4DequantB( + float* FpData, const uint8_t* PackedB, size_t CountN, size_t CountK, size_t ldb) +{ + BlkQ4DequantBAvx512f(FpData, PackedB, CountN, CountK, ldb); +} + +/** + * @brief For testing purpose, + * Dequantize the data intp fp32, and then pack them for use + * in sgemm kernel. equivalent to MlasQ4GemmUnPackB and then + * MlasSgemmCopyPackB + * @param QType + * @param FpData + * @param PackedB + * @param CountN + * @param CountK + * @param ldb + */ +void +MlasBlkQ4DequantSgemmPackB( + MLAS_BLK_QUANT_TYPE QType, + float* FpData, + const uint8_t* PackedB, + size_t CountN, + size_t CountK, + size_t ldb) +{ + switch (QType) { + case BlkQ4Zp8: + return BlkQ4DequantBAvx512f(FpData, PackedB, CountN, CountK, ldb); + case BlkQ4Sym64: + return BlkQ4DequantBAvx512f(FpData, PackedB, CountN, CountK, ldb); + case BlkQ4Sym128: + return BlkQ4DequantBAvx512f(FpData, PackedB, CountN, CountK, ldb); + default: + return BlkQ4DequantBAvx512f(FpData, PackedB, CountN, CountK, ldb); + } +} + +template<> +MLAS_FORCEINLINE +void +AddBiasAvx( + const float* Bias, + float* C, + size_t CountM, + size_t CountN, + size_t ldc + ) +{ + for (size_t m = 0; m < CountM; m++) { + const float* bias = Bias; + float* sum = C; + for (size_t n = 0; n < CountN; n += 4) { + if (CountN - n < 4) { + for (size_t nn = n; nn < CountN; nn++) { + *sum += *bias; + sum++; + bias++; + } + break; + } + + __m128 acc_x = _mm_loadu_ps(sum); + acc_x = _mm_add_ps(acc_x, _mm_loadu_ps(bias)); + _mm_storeu_ps(sum, acc_x); + bias += 4; + sum += 4; + } + C += ldc; + } +} + + +static MLAS_Q4GEMM_OPERATION* Q4Operations_avx512vnni[] = { + MlasQ4GemmOperation, + MlasQ4GemmOperation, + MlasQ4GemmOperation, + nullptr, + MlasQ4GemmOperation +}; + +const MLAS_FPQ4GEMM_DISPATCH MlasFpQ4GemmDispatchAvx512 = { + Q4Operations_avx512vnni +}; + + +//////////////////////////////////////////////////////////// +// Block int8 quantization, currently we only +// implement symmetric quant, with no zero-point + +template +MLAS_FORCEINLINE void +MlasQ80BlkQuantRow(const float* A, void* Qblob, size_t size) +{ + static_assert(QType::BlkLen % 16 == 0); + const __m512 signBit = _mm512_set1_ps(-0.0f); + int8_t* blob = reinterpret_cast(Qblob); + for (size_t k = 0; k < size; k += QType::BlkLen) { + const size_t step = std::min(QType::BlkLen, size - k); + + __m512 maxAbs = _mm512_setzero_ps(); + for (size_t kk = 0; kk < step; kk += 16) { + const size_t klen = std::min(size_t(16), step - kk); + + uint32_t mask = 0xffff >> (16 - klen); + __m512 v0 = _mm512_maskz_loadu_ps(__mmask16(mask), A + k + kk); + + // Compute max(abs(e)) for the block + maxAbs = _mm512_max_ps(maxAbs, _mm512_andnot_ps(signBit, v0)); + } + + __m256 max8 = + _mm256_max_ps(_mm512_extractf32x8_ps(maxAbs, 1), _mm512_extractf32x8_ps(maxAbs, 0)); + __m128 max4 = _mm_max_ps(_mm256_extractf128_ps(max8, 1), _mm256_castps256_ps128(max8)); + max4 = _mm_max_ps(max4, _mm_movehl_ps(max4, max4)); + max4 = _mm_max_ss(max4, _mm_movehdup_ps(max4)); + const float maxScalar = _mm_cvtss_f32(max4); + + // Quantize these floats + const float scale = maxScalar / 127.f; + *reinterpret_cast(blob) = scale; + blob += sizeof(float); + + const float inverse_scale = (maxScalar != 0.0f) ? 127.f / maxScalar : 0.0f; + const __m512 mul = _mm512_set1_ps(inverse_scale); + __m128i* dst = reinterpret_cast<__m128i*>(blob); + + for (size_t kk = 0; kk < step; kk += 16) { + const size_t klen = std::min(size_t(16), step - kk); + + uint32_t mask = 0xffff >> (16 - klen); + __m512 v0 = _mm512_maskz_loadu_ps(__mmask16(mask), A + k + kk); + v0 = _mm512_mul_ps(v0, mul); + + // Round to nearest integer + v0 = _mm512_roundscale_ps(v0, _MM_ROUND_NEAREST); + + // Convert floats to integers + __m512i i0 = _mm512_cvtps_epi32(v0); + + // Convert int32 to int8 + _mm_storeu_si128(dst++, _mm512_cvtepi32_epi8(i0)); + } + if (step < QType::BlkLen) { + memset(blob + step, 0, QType::BlkLen - step); + } + blob += QType::BlkLen; + } +} + +template +void +Q80BlkQuant(void* Qblob, const float* A, size_t M, size_t K, size_t lda, MLAS_THREADPOOL* ThreadPool) +{ + const size_t parts = (size_t)ceil(double(M) * K / (16.0 * 1024)); + const size_t TargetThreadCnt = + std::max(std::min(parts, (size_t)MlasGetMaximumThreadCount(ThreadPool)), (size_t)1); + const size_t linesize = MlasQ80BlkQuantSizeImpl(1, K); + + size_t M_stride = MlasDivRoundup(M, TargetThreadCnt); + size_t threads = MlasDivRoundup(M, M_stride); + MlasTrySimpleParallel(ThreadPool, threads, [&](ptrdiff_t tid) { + const size_t m = tid * M_stride; + const float* src = A + lda * m; + uint8_t* dst = reinterpret_cast(Qblob) + m * linesize; + for (size_t i = 0; i < std::min(M_stride, M-m); i++) { + MlasQ80BlkQuantRow(src, dst, K); + src += lda; + dst += linesize; + } + }); +} + +static MLAS_Q80_BLKQUANT* Q80Quant_avx512vnni[] = { + Q80BlkQuant, + Q80BlkQuant, + Q80BlkQuant, + nullptr, + Q80BlkQuant +}; + + +static +MLAS_FORCEINLINE +__m128 +FoldAccumulators( + const __m256& acc0, + const __m256& acc1, + const __m256& acc2, + const __m256& acc3 + ) +{ + __m256 acc_lo01 = _mm256_unpacklo_ps(acc0, acc1); + __m256 acc_hi01 = _mm256_unpackhi_ps(acc0, acc1); + __m256 acc_lo23 = _mm256_unpacklo_ps(acc2, acc3); + __m256 acc_hi23 = _mm256_unpackhi_ps(acc2, acc3); + + __m256 acc_lo0123 = _mm256_castpd_ps( + _mm256_unpacklo_pd(_mm256_castps_pd(acc_lo01), _mm256_castps_pd(acc_lo23))); + __m256 acc_hi0123 = _mm256_castpd_ps( + _mm256_unpackhi_pd(_mm256_castps_pd(acc_lo01), _mm256_castps_pd(acc_lo23))); + acc_lo0123 = _mm256_add_ps(acc_lo0123, acc_hi0123); + acc_hi0123 = _mm256_castpd_ps( + _mm256_unpacklo_pd(_mm256_castps_pd(acc_hi01), _mm256_castps_pd(acc_hi23))); + acc_lo0123 = _mm256_add_ps(acc_lo0123, acc_hi0123); + acc_hi0123 = _mm256_castpd_ps( + _mm256_unpackhi_pd(_mm256_castps_pd(acc_hi01), _mm256_castps_pd(acc_hi23))); + acc_lo0123 = _mm256_add_ps(acc_lo0123, acc_hi0123); + + return _mm_add_ps(_mm256_extractf32x4_ps(acc_lo0123, 0), _mm256_extractf32x4_ps(acc_lo0123, 1)); +} + +static inline float +mm256_reduce_add_ps(__m256& x) +{ + /* ( x3+x7, x2+x6, x1+x5, x0+x4 ) */ + const __m128 x128 = _mm_add_ps(_mm256_extractf128_ps(x, 1), _mm256_castps256_ps128(x)); + /* ( -, -, x1+x3+x5+x7, x0+x2+x4+x6 ) */ + const __m128 x64 = _mm_add_ps(x128, _mm_movehl_ps(x128, x128)); + /* ( -, -, -, x0+x1+x2+x3+x4+x5+x6+x7 ) */ + const __m128 x32 = _mm_add_ss(x64, _mm_shuffle_ps(x64, x64, 0x55)); + /* Conversion to float is a no-op on x86-64 */ + return _mm_cvtss_f32(x32); +} + + +template +MLAS_FORCEINLINE +size_t +MlasQ8Q4GemmKernelAvx512f( + const int8_t* QuantA, + const uint8_t* PackedB, + float* C, + size_t CountM, + size_t CountN, + size_t CountK, + size_t lda, + size_t ldb, + size_t ldc, + const float* Bias + ) +{ + // We process 32 quantized values in a batch. + static_assert(MLAS_QUANT4_BLK_UNIT == 32); + static_assert(Q4Type::BlkLen % MLAS_QUANT4_BLK_UNIT == 0); + + const __m256i zero = _mm256_setzero_si256(); + const __m256i lowMask = _mm256_set1_epi8(0xF); + + for (size_t m = 0; m < CountM; m++) { + const uint8_t* b_col = PackedB; + auto* sum_ptr = C; + auto* bias_ptr = Bias; + + int64_t nblk = (int64_t)(CountN) - 4; + while (nblk >= 0) { + __m256 acc_lo0 = _mm256_setzero_ps(); + __m256 acc_lo1 = _mm256_setzero_ps(); + __m256 acc_lo2 = _mm256_setzero_ps(); + __m256 acc_lo3 = _mm256_setzero_ps(); + const int8_t* ablob = QuantA; + const auto* b = b_col; + + for (size_t k = 0; k < CountK; k += Q4Type::BlkLen) { + const float a_scale = *reinterpret_cast(ablob); + ablob += sizeof(float); + const float scale_v0 = MlasQ4BlkScale(b) * a_scale; + const float scale_v1 = MlasQ4BlkScale(b + ldb) * a_scale; + const float scale_v2 = MlasQ4BlkScale(b + ldb * 2) * a_scale; + const float scale_v3 = MlasQ4BlkScale(b + ldb * 3) * a_scale; + + const __m128i* b0ptr = (const __m128i*)MlasQ4BlkData(b); + const __m128i* b1ptr = (const __m128i*)MlasQ4BlkData(b + ldb); + const __m128i* b2ptr = (const __m128i*)MlasQ4BlkData(b + ldb * 2); + const __m128i* b3ptr = (const __m128i*)MlasQ4BlkData(b + ldb * 3); + + for (size_t kk = 0; kk < Q4Type::BlkLen; kk += MLAS_QUANT4_BLK_UNIT) { + // Load A row vector + const __m256i a_bytes = _mm256_loadu_si256((const __m256i*)ablob); + ablob += MLAS_QUANT4_BLK_UNIT; + + // Load 4 B column vectors (quantized to int4 blobs) + const __m128i bvi4_0 = _mm_loadu_si128(b0ptr++); + const __m128i bvi4_1 = _mm_loadu_si128(b1ptr++); + const __m128i bvi4_2 = _mm_loadu_si128(b2ptr++); + const __m128i bvi4_3 = _mm_loadu_si128(b3ptr++); + + // expand 4b into byte array + __m256i bytes0 = _mm256_set_m128i(_mm_srli_epi16(bvi4_0, 4), bvi4_0); + __m256i bytes1 = _mm256_set_m128i(_mm_srli_epi16(bvi4_1, 4), bvi4_1); + __m256i bytes2 = _mm256_set_m128i(_mm_srli_epi16(bvi4_2, 4), bvi4_2); + __m256i bytes3 = _mm256_set_m128i(_mm_srli_epi16(bvi4_3, 4), bvi4_3); + bytes0 = _mm256_and_si256(lowMask, bytes0); + bytes1 = _mm256_and_si256(lowMask, bytes1); + bytes2 = _mm256_and_si256(lowMask, bytes2); + bytes3 = _mm256_and_si256(lowMask, bytes3); + + // Subtract zero-point from the integers + if constexpr (std::is_same_v) { + bytes0 = _mm256_sub_epi8( + bytes0, _mm256_set1_epi8(MlasQ4BlkZeroPoint(b))); + bytes1 = _mm256_sub_epi8( + bytes1, + _mm256_set1_epi8(MlasQ4BlkZeroPoint(b + ldb))); + bytes2 = _mm256_sub_epi8( + bytes2, + _mm256_set1_epi8(MlasQ4BlkZeroPoint(b + ldb * 2))); + bytes3 = _mm256_sub_epi8( + bytes3, + _mm256_set1_epi8(MlasQ4BlkZeroPoint(b + ldb * 3))); + } else { + const __m256i eight = _mm256_set1_epi8(8); + bytes0 = _mm256_sub_epi8(bytes0, eight); + bytes1 = _mm256_sub_epi8(bytes1, eight); + bytes2 = _mm256_sub_epi8(bytes2, eight); + bytes3 = _mm256_sub_epi8(bytes3, eight); + } + + // to use vnni unsigned x signed int, negate all negative + // b vals to make it all positive, and then also negate the + // corresponding a vals to compensate + const __m256i summed_pairs0 = _mm256_dpbusd_epi32( + zero, _mm256_sign_epi8(bytes0, bytes0), _mm256_sign_epi8(a_bytes, bytes0)); + const __m256i summed_pairs1 = _mm256_dpbusd_epi32( + zero, _mm256_sign_epi8(bytes1, bytes1), _mm256_sign_epi8(a_bytes, bytes1)); + const __m256i summed_pairs2 = _mm256_dpbusd_epi32( + zero, _mm256_sign_epi8(bytes2, bytes2), _mm256_sign_epi8(a_bytes, bytes2)); + const __m256i summed_pairs3 = _mm256_dpbusd_epi32( + zero, _mm256_sign_epi8(bytes3, bytes3), _mm256_sign_epi8(a_bytes, bytes3)); + + const __m256 sums0 = _mm256_cvtepi32_ps(summed_pairs0); + const __m256 sums1 = _mm256_cvtepi32_ps(summed_pairs1); + const __m256 sums2 = _mm256_cvtepi32_ps(summed_pairs2); + const __m256 sums3 = _mm256_cvtepi32_ps(summed_pairs3); + acc_lo0 = _mm256_fmadd_ps(_mm256_set1_ps(scale_v0), sums0, acc_lo0); + acc_lo1 = _mm256_fmadd_ps(_mm256_set1_ps(scale_v1), sums1, acc_lo1); + acc_lo2 = _mm256_fmadd_ps(_mm256_set1_ps(scale_v2), sums2, acc_lo2); + acc_lo3 = _mm256_fmadd_ps(_mm256_set1_ps(scale_v3), sums3, acc_lo3); + } + b += Q4Type::BlobSize; + } + + __m128 acc_x = FoldAccumulators(acc_lo0, acc_lo1, acc_lo2, acc_lo3); + if (Bias != nullptr) { + acc_x = _mm_add_ps(acc_x, _mm_loadu_ps(bias_ptr)); + } + _mm_storeu_ps(sum_ptr, acc_x); + + // move to next 4 columns + b_col += 4 * ldb; + sum_ptr += 4; + bias_ptr += 4; + nblk -= 4; + } + + // left over columns less than 4 ? + nblk += 4; + if (nblk > 0) { + __m256 acc_lo[4]{}; + const int8_t* ablob = QuantA; + const auto* b = b_col; + + for (size_t k = 0; k < CountK; k += Q4Type::BlkLen) { + const float a_scale = *reinterpret_cast(ablob); + ablob += sizeof(float); + + float scale_v[4]; + const __m128i* b_ptr[4]; + for (int64_t nn = 0; nn < nblk; nn++) { + const auto* bb = b + ldb * nn; + scale_v[nn] = MlasQ4BlkScale(bb) * a_scale; + b_ptr[nn] = (const __m128i*)MlasQ4BlkData(bb); + } + + for (size_t kk = 0; kk < Q4Type::BlkLen; kk += MLAS_QUANT4_BLK_UNIT) { + const __m256i a_bytes = _mm256_loadu_si256((const __m256i*)ablob); + ablob += MLAS_QUANT4_BLK_UNIT; + + for (int64_t nn = 0; nn < nblk; nn++) { + const __m128i bvi4 = _mm_loadu_si128(b_ptr[nn]++); + __m256i b_bytes = _mm256_set_m128i(_mm_srli_epi16(bvi4, 4), bvi4); + b_bytes = _mm256_and_si256(lowMask, b_bytes); + + if constexpr (std::is_same_v) { + // Subtract zero-point from the integers + const auto* bb = b + ldb * nn; + const uint8_t zp = MlasQ4BlkZeroPoint(bb); + b_bytes = _mm256_sub_epi8(b_bytes, _mm256_set1_epi8(zp)); + } else { + // Subtract 8 from the integers + const __m256i eight = _mm256_set1_epi8(8); + b_bytes = _mm256_sub_epi8(b_bytes, eight); + } + + // to use vnni unsigned x signed int, negate all negative + // b vals to make it all positive, + const __m256i ax = _mm256_sign_epi8(b_bytes, b_bytes); + // and then also negate the corresponding a vals to compensate + const __m256i sy = _mm256_sign_epi8(a_bytes, b_bytes); + const __m256i summed_pairs = _mm256_dpbusd_epi32(zero, ax, sy); + const __m256 sum = _mm256_cvtepi32_ps(summed_pairs); + acc_lo[nn] = _mm256_fmadd_ps(_mm256_set1_ps(scale_v[nn]), sum, acc_lo[nn]); + } + } + b += Q4Type::BlobSize; + } + + for (int64_t nn = 0; nn < nblk; nn++) { + sum_ptr[nn] = mm256_reduce_add_ps(acc_lo[nn]); + sum_ptr[nn] += Bias == nullptr ? 0.0f : bias_ptr[nn]; + } + } + + // Prepare pointers for the next row + C += ldc; + QuantA += lda; + } + return CountM; +} + + +template<> +MLAS_FORCEINLINE +size_t +MlasQ8Q4GemmKernel( + const int8_t* QuantA, + const uint8_t* PackedB, + float* C, + size_t CountM, + size_t CountN, + size_t CountK, + size_t lda, + size_t ldb, + size_t ldc, + const float* Bias + ) +{ + return MlasQ8Q4GemmKernelAvx512f(QuantA, PackedB, C, CountM, CountN, CountK, + lda, ldb, ldc, Bias); +} + +template<> +MLAS_FORCEINLINE +size_t +MlasQ8Q4GemmKernel( + const int8_t* QuantA, + const uint8_t* PackedB, + float* C, + size_t CountM, + size_t CountN, + size_t CountK, + size_t lda, + size_t ldb, + size_t ldc, + const float* Bias + ) +{ + return MlasQ8Q4GemmKernelAvx512f(QuantA, PackedB, C, CountM, CountN, CountK, + lda, ldb, ldc, Bias); +} + +template<> +MLAS_FORCEINLINE +size_t +MlasQ8Q4GemmKernel( + const int8_t* QuantA, + const uint8_t* PackedB, + float* C, + size_t CountM, + size_t CountN, + size_t CountK, + size_t lda, + size_t ldb, + size_t ldc, + const float* Bias + ) +{ + return MlasQ8Q4GemmKernelAvx512f(QuantA, PackedB, C, CountM, CountN, CountK, + lda, ldb, ldc, Bias); +} + +template<> +MLAS_FORCEINLINE +size_t +MlasQ8Q4GemmKernel( + const int8_t* QuantA, + const uint8_t* PackedB, + float* C, + size_t CountM, + size_t CountN, + size_t CountK, + size_t lda, + size_t ldb, + size_t ldc, + const float* Bias + ) +{ + return MlasQ8Q4GemmKernelAvx512f(QuantA, PackedB, C, CountM, CountN, CountK, + lda, ldb, ldc, Bias); +} + + +static MLAS_Q8Q4GEMM_OPERATION* Q8Q4Operations_avx512vnni[] = { + MlasQ8Q4GemmOperation, + MlasQ8Q4GemmOperation, + MlasQ8Q4GemmOperation, + nullptr, + MlasQ8Q4GemmOperation +}; + + +const MLAS_Q8Q4GEMM_DISPATCH MlasQ8Q4GemmDispatchAvx512vnni = { + Q80Quant_avx512vnni, + Q8Q4Operations_avx512vnni +}; diff --git a/onnxruntime/core/mlas/lib/qgemm.h b/onnxruntime/core/mlas/lib/qgemm.h index a1ce54b6bf2c1..1fcd44e78a28c 100644 --- a/onnxruntime/core/mlas/lib/qgemm.h +++ b/onnxruntime/core/mlas/lib/qgemm.h @@ -882,13 +882,9 @@ MlasGemmQuantGetDispatch( } #elif defined(MLAS_TARGET_ARM64) if(BIsSigned) { - if(GetMlasPlatform().GemmU8X8Dispatch == &MlasGemmU8X8DispatchNeon) { - GemmQuantDispatch = &MlasGemmX8S8DispatchNeon; - } else { - GemmQuantDispatch = AIsSigned? &MlasGemmS8S8DispatchSdot : &MlasGemmU8X8DispatchUdot; - } + GemmQuantDispatch = AIsSigned ? GetMlasPlatform().GemmS8S8Dispatch : GetMlasPlatform().GemmU8S8Dispatch; } else if(!AIsSigned) { - GemmQuantDispatch = GetMlasPlatform().GemmU8X8Dispatch; + GemmQuantDispatch = GetMlasPlatform().GemmU8U8Dispatch; } #elif defined(MLAS_TARGET_ARM64EC) || (defined(MLAS_TARGET_ARM) && !defined(_MSC_VER)) if(BIsSigned || !AIsSigned) { diff --git a/onnxruntime/core/mlas/lib/qgemm_kernel_amx.cpp b/onnxruntime/core/mlas/lib/qgemm_kernel_amx.cpp index fd9d8c7b584f3..479a82e712c5e 100644 --- a/onnxruntime/core/mlas/lib/qgemm_kernel_amx.cpp +++ b/onnxruntime/core/mlas/lib/qgemm_kernel_amx.cpp @@ -16,6 +16,7 @@ Module Name: #include "mlasi.h" #include "qgemm.h" +#include "amx_common.h" #define TMM0 0 @@ -168,9 +169,12 @@ MlasGemmQuantCopyPackB( // Tile configure structure struct tileconfig_t { uint8_t palette_id = 0; - uint8_t reserved[15] = {0}; - uint16_t colb[16] = {0}; - uint8_t rows[16] = {0}; + uint8_t start_row = 0; + uint8_t reserved1[14] = {0}; + uint16_t colb[8] = {0}; + uint8_t reserved2[16] = {0}; + uint8_t rows[8] = {0}; + uint8_t reserved3[8] = {0}; }; template <> @@ -197,17 +201,20 @@ MlasGemmQuantThreadInit() MlasThreadedBufAlloc(bufsize); - static thread_local bool tile_configured = false; static thread_local struct tileconfig_t tc = {0}; - if (!tile_configured) { + struct tileconfig_t current_tc = {0}; + tile_storeconfig(¤t_tc); + + if (tc.palette_id == 0 || (std::memcmp(¤t_tc.colb, &tc.colb, sizeof(uint16_t) * 8) != 0 && + std::memcmp(¤t_tc.rows, &tc.rows, sizeof(uint8_t) * 8) != 0)) { // Filling tile configure structure. tc.palette_id = 1; for (int t = 0; t < 8; t++) { tc.rows[t] = 16; tc.colb[t] = 64; } - _tile_loadconfig(&tc); - tile_configured = true; + + tile_loadconfig(&tc); } } @@ -233,14 +240,14 @@ InitHalfTileWithRowColSums( row6 = _mm512_add_epi32(colsum, _mm512_set1_epi32(rowsum_ptr[6])); row7 = _mm512_add_epi32(colsum, _mm512_set1_epi32(rowsum_ptr[7])); if (!ZeroMode){ - row0 = _mm512_add_epi32(row0, _mm512_loadu_epi32(c_ptr)); - row1 = _mm512_add_epi32(row1, _mm512_loadu_epi32(c_ptr+ldc)); - row2 = _mm512_add_epi32(row2, _mm512_loadu_epi32(c_ptr+ldc*2)); - row3 = _mm512_add_epi32(row3, _mm512_loadu_epi32(c_ptr+ldc*3)); - row4 = _mm512_add_epi32(row4, _mm512_loadu_epi32(c_ptr+ldc*4)); - row5 = _mm512_add_epi32(row5, _mm512_loadu_epi32(c_ptr+ldc*5)); - row6 = _mm512_add_epi32(row6, _mm512_loadu_epi32(c_ptr+ldc*6)); - row7 = _mm512_add_epi32(row7, _mm512_loadu_epi32(c_ptr+ldc*7)); + row0 = _mm512_add_epi32(row0, _mm512_loadu_si512(c_ptr)); + row1 = _mm512_add_epi32(row1, _mm512_loadu_si512(c_ptr+ldc)); + row2 = _mm512_add_epi32(row2, _mm512_loadu_si512(c_ptr+ldc*2)); + row3 = _mm512_add_epi32(row3, _mm512_loadu_si512(c_ptr+ldc*3)); + row4 = _mm512_add_epi32(row4, _mm512_loadu_si512(c_ptr+ldc*4)); + row5 = _mm512_add_epi32(row5, _mm512_loadu_si512(c_ptr+ldc*5)); + row6 = _mm512_add_epi32(row6, _mm512_loadu_si512(c_ptr+ldc*6)); + row7 = _mm512_add_epi32(row7, _mm512_loadu_si512(c_ptr+ldc*7)); } _mm512_storeu_si512(Tile, row0); _mm512_storeu_si512(Tile+16, row1); @@ -285,14 +292,14 @@ InitHalfTileWithRowColSumsZeroPoints( row6 = _mm512_add_epi32(colsum, row6); row7 = _mm512_add_epi32(colsum, row7); if (!ZeroMode){ - row0 = _mm512_add_epi32(row0, _mm512_loadu_epi32(c_ptr)); - row1 = _mm512_add_epi32(row1, _mm512_loadu_epi32(c_ptr+ldc)); - row2 = _mm512_add_epi32(row2, _mm512_loadu_epi32(c_ptr+ldc*2)); - row3 = _mm512_add_epi32(row3, _mm512_loadu_epi32(c_ptr+ldc*3)); - row4 = _mm512_add_epi32(row4, _mm512_loadu_epi32(c_ptr+ldc*4)); - row5 = _mm512_add_epi32(row5, _mm512_loadu_epi32(c_ptr+ldc*5)); - row6 = _mm512_add_epi32(row6, _mm512_loadu_epi32(c_ptr+ldc*6)); - row7 = _mm512_add_epi32(row7, _mm512_loadu_epi32(c_ptr+ldc*7)); + row0 = _mm512_add_epi32(row0, _mm512_loadu_si512(c_ptr)); + row1 = _mm512_add_epi32(row1, _mm512_loadu_si512(c_ptr+ldc)); + row2 = _mm512_add_epi32(row2, _mm512_loadu_si512(c_ptr+ldc*2)); + row3 = _mm512_add_epi32(row3, _mm512_loadu_si512(c_ptr+ldc*3)); + row4 = _mm512_add_epi32(row4, _mm512_loadu_si512(c_ptr+ldc*4)); + row5 = _mm512_add_epi32(row5, _mm512_loadu_si512(c_ptr+ldc*5)); + row6 = _mm512_add_epi32(row6, _mm512_loadu_si512(c_ptr+ldc*6)); + row7 = _mm512_add_epi32(row7, _mm512_loadu_si512(c_ptr+ldc*7)); } _mm512_storeu_si512(Tile, row0); _mm512_storeu_si512(Tile+16, row1); @@ -430,58 +437,58 @@ MlasGemmQuantKernel( size_t n = CountN; for (; n >= 2 * TILE_N; n -= 2 * TILE_N) { - __m512i colsum = _mm512_loadu_epi32(col_sum_ptr); + __m512i colsum = _mm512_loadu_si512(col_sum_ptr); col_sum_ptr += TILE_N; if (ZeroPointB != nullptr){ - __m512i zeropoint = _mm512_loadu_epi32(zp_ptr); + __m512i zeropoint = _mm512_loadu_si512(zp_ptr); zp_ptr += TILE_N; InitTileWithRowColSumsZeroPoints( Tile4, m0, FullMask, RowSumBuffer, colsum, zeropoint, ZeroMode, c_blk, ldc); - _tile_loadd(TMM4, Tile4, TILE_N * sizeof(int32_t)); + tile_loadd(TMM4, Tile4, TILE_N * sizeof(int32_t)); if (m1 != 0){ InitTileWithRowColSumsZeroPoints( Tile5, m1, FullMask, RowSumBuffer + TILE_M, colsum, zeropoint, ZeroMode, c16_blk, ldc); - _tile_loadd(TMM5, Tile5, TILE_N * sizeof(int32_t)); + tile_loadd(TMM5, Tile5, TILE_N * sizeof(int32_t)); } } else { InitTileWithRowColSums( Tile4, m0, FullMask, RowSumBuffer, colsum, ZeroMode, c_blk, ldc); - _tile_loadd(TMM4, Tile4, TILE_N * sizeof(int32_t)); + tile_loadd(TMM4, Tile4, TILE_N * sizeof(int32_t)); if (m1 != 0){ InitTileWithRowColSums( Tile5, m1, FullMask, RowSumBuffer + TILE_M, colsum, ZeroMode, c16_blk, ldc); - _tile_loadd(TMM5, Tile5, TILE_N * sizeof(int32_t)); + tile_loadd(TMM5, Tile5, TILE_N * sizeof(int32_t)); } } - colsum = _mm512_loadu_epi32(col_sum_ptr); + colsum = _mm512_loadu_si512(col_sum_ptr); col_sum_ptr += TILE_N; if (ZeroPointB != nullptr) { - __m512i zeropoint = _mm512_loadu_epi32(zp_ptr); + __m512i zeropoint = _mm512_loadu_si512(zp_ptr); zp_ptr += TILE_N; InitTileWithRowColSumsZeroPoints( Tile6, m0, FullMask, RowSumBuffer, colsum, zeropoint, ZeroMode, c_blk + TILE_N, ldc); - _tile_loadd(TMM6, Tile6, TILE_N * sizeof(int32_t)); + tile_loadd(TMM6, Tile6, TILE_N * sizeof(int32_t)); if (m1 != 0){ InitTileWithRowColSumsZeroPoints( Tile7, m1, FullMask, RowSumBuffer + TILE_M, colsum, zeropoint, ZeroMode, c16_blk + TILE_N, ldc); - _tile_loadd(TMM7, Tile7, TILE_N * sizeof(int32_t)); + tile_loadd(TMM7, Tile7, TILE_N * sizeof(int32_t)); } } else { InitTileWithRowColSums( Tile6, m0, FullMask, RowSumBuffer, colsum, ZeroMode, c_blk + TILE_N, ldc); - _tile_loadd(TMM6, Tile6, TILE_N * sizeof(int32_t)); + tile_loadd(TMM6, Tile6, TILE_N * sizeof(int32_t)); if (m1 != 0){ InitTileWithRowColSums( Tile7, m1, FullMask, RowSumBuffer + TILE_M, colsum, ZeroMode, c16_blk + TILE_N, ldc); - _tile_loadd(TMM7, Tile7, TILE_N * sizeof(int32_t)); + tile_loadd(TMM7, Tile7, TILE_N * sizeof(int32_t)); } } @@ -489,33 +496,36 @@ MlasGemmQuantKernel( const MLAS_GEMM_U8S8_KERNEL_AMX::PackedAType* a_blk = A; const MLAS_GEMM_U8S8_KERNEL_AMX::PackedAType* a_next_blk = A + PackedCountK * TILE_M; for (size_t k = PackedCountK; k > 0; k -=TILE_K) { - _tile_loadd(TMM0, b_blk, TILE_K); - _tile_loadd(TMM2, a_blk, static_cast(PackedCountK)); - _tile_loadd(TMM1, (void*)(b_blk + PackedCountK * TILE_N), TILE_K); - _tile_dpbusd(TMM4, TMM2, TMM0); - _tile_dpbusd(TMM6, TMM2, TMM1); + tile_loadd(TMM0, b_blk, TILE_K); + tile_loadd(TMM2, a_blk, static_cast(PackedCountK)); + tile_loadd(TMM1, (void*)(b_blk + PackedCountK * TILE_N), TILE_K); + + tile_dpbusd(TMM4, TMM2, TMM0); + tile_dpbusd(TMM6, TMM2, TMM1); if (m1 > 0){ - _tile_loadd(TMM3, a_next_blk, static_cast(PackedCountK)); - _tile_dpbusd(TMM5, TMM3, TMM0); - _tile_dpbusd(TMM7, TMM3, TMM1); + tile_loadd(TMM3, a_next_blk, static_cast(PackedCountK)); + tile_dpbusd(TMM5, TMM3, TMM0); + tile_dpbusd(TMM7, TMM3, TMM1); } b_blk += TILE_N * TILE_K; a_blk += TILE_K; a_next_blk += TILE_K; } if (m0 == TILE_M) { - _tile_stored(TMM4, c_blk, static_cast(ldc * sizeof(int32_t))); - _tile_stored(TMM6, (void*)(c_blk + TILE_N), static_cast(ldc * sizeof(int32_t))); + tile_stored(TMM4, c_blk, static_cast(ldc * sizeof(int32_t))); + tile_stored(TMM6, (void*)(c_blk + TILE_N), static_cast(ldc * sizeof(int32_t))); + } else { - _tile_stored(TMM4, Tile4, TILE_N * sizeof(int32_t)); - _tile_stored(TMM6, Tile6, TILE_N * sizeof(int32_t)); + tile_stored(TMM4, Tile4, TILE_N * sizeof(int32_t)); + tile_stored(TMM6, Tile6, TILE_N * sizeof(int32_t)); + MoveTile(Tile4, m0, FullMask, c_blk, ldc); MoveTile(Tile6, m0, FullMask, c_blk + TILE_N, ldc); } if (m1 != 0){ - _tile_stored(TMM5, Tile5, TILE_N * sizeof(int32_t)); + tile_stored(TMM5, Tile5, TILE_N * sizeof(int32_t)); MoveTile(Tile5, m1, FullMask, c16_blk, ldc); - _tile_stored(TMM7, Tile7, TILE_N * sizeof(int32_t)); + tile_stored(TMM7, Tile7, TILE_N * sizeof(int32_t)); MoveTile(Tile7, m1, FullMask, c16_blk + TILE_N, ldc); } c_blk += 2 * TILE_N; @@ -534,23 +544,23 @@ MlasGemmQuantKernel( InitTileWithRowColSumsZeroPoints( Tile4, m0, static_cast(nmasks), RowSumBuffer, colsum, zeropoint, ZeroMode, c_blk, ldc); - _tile_loadd(TMM4, Tile4, TILE_N * sizeof(int32_t)); + tile_loadd(TMM4, Tile4, TILE_N * sizeof(int32_t)); if (m1 > 0){ InitTileWithRowColSumsZeroPoints( Tile5, m1, static_cast(nmasks), RowSumBuffer + TILE_M, colsum, zeropoint, ZeroMode, c16_blk, ldc); - _tile_loadd(TMM5, Tile5, TILE_N * sizeof(int32_t)); + tile_loadd(TMM5, Tile5, TILE_N * sizeof(int32_t)); } } else { InitTileWithRowColSums( Tile4, m0, static_cast(nmasks), RowSumBuffer, colsum, ZeroMode, c_blk, ldc); - _tile_loadd(TMM4, Tile4, TILE_N * sizeof(int32_t)); + tile_loadd(TMM4, Tile4, TILE_N * sizeof(int32_t)); if (m1 > 0){ InitTileWithRowColSums( Tile5, m1, static_cast(nmasks), RowSumBuffer + TILE_M, colsum, ZeroMode, c16_blk, ldc); - _tile_loadd(TMM5, Tile5, TILE_N * sizeof(int32_t)); + tile_loadd(TMM5, Tile5, TILE_N * sizeof(int32_t)); } } if (nmask_high != 0){ @@ -560,23 +570,23 @@ MlasGemmQuantKernel( InitTileWithRowColSumsZeroPoints( Tile6, m0, nmask_high, RowSumBuffer, colsum, zeropoint, ZeroMode, c_blk + TILE_N, ldc); - _tile_loadd(TMM6, Tile6, TILE_N * sizeof(int32_t)); + tile_loadd(TMM6, Tile6, TILE_N * sizeof(int32_t)); if (m1 > 0){ InitTileWithRowColSumsZeroPoints( Tile7, m1, nmask_high, RowSumBuffer + TILE_M, colsum, zeropoint, ZeroMode, c16_blk + TILE_N, ldc); - _tile_loadd(TMM7, Tile7, TILE_N * sizeof(int32_t)); + tile_loadd(TMM7, Tile7, TILE_N * sizeof(int32_t)); } } else { InitTileWithRowColSums( Tile6, m0, nmask_high, RowSumBuffer, colsum, ZeroMode, c_blk + TILE_N, ldc); - _tile_loadd(TMM6, Tile6, TILE_N * sizeof(int32_t)); + tile_loadd(TMM6, Tile6, TILE_N * sizeof(int32_t)); if (m1 > 0){ InitTileWithRowColSums( Tile7, m1, nmask_high, RowSumBuffer + TILE_M, colsum, ZeroMode, c16_blk + TILE_N, ldc); - _tile_loadd(TMM7, Tile7, TILE_N * sizeof(int32_t)); + tile_loadd(TMM7, Tile7, TILE_N * sizeof(int32_t)); } } } @@ -584,18 +594,19 @@ MlasGemmQuantKernel( const MLAS_GEMM_U8S8_KERNEL_AMX::PackedAType* a_blk = A; const MLAS_GEMM_U8S8_KERNEL_AMX::PackedAType* a_next_blk = A + PackedCountK * TILE_M; for (size_t k = PackedCountK; k > 0; k -=TILE_K) { - _tile_loadd(TMM0, b_blk, TILE_K); - _tile_loadd(TMM2, a_blk, static_cast(PackedCountK)); - _tile_dpbusd(TMM4, TMM2, TMM0); + tile_loadd(TMM0, b_blk, TILE_K); + tile_loadd(TMM2, a_blk, static_cast(PackedCountK)); + + tile_dpbusd(TMM4, TMM2, TMM0); if (m1 > 0){ - _tile_loadd(TMM3, a_next_blk, static_cast(PackedCountK)); - _tile_dpbusd(TMM5, TMM3, TMM0); + tile_loadd(TMM3, a_next_blk, static_cast(PackedCountK)); + tile_dpbusd(TMM5, TMM3, TMM0); } if (nmask_high != 0){ - _tile_loadd(TMM1, (void*)(b_blk + PackedCountK * TILE_N), TILE_K); - _tile_dpbusd(TMM6, TMM2, TMM1); + tile_loadd(TMM1, (void*)(b_blk + PackedCountK * TILE_N), TILE_K); + tile_dpbusd(TMM6, TMM2, TMM1); if (m1 > 0){ - _tile_dpbusd(TMM7, TMM3, TMM1); + tile_dpbusd(TMM7, TMM3, TMM1); } } b_blk += TILE_N * TILE_K; @@ -603,20 +614,20 @@ MlasGemmQuantKernel( a_next_blk += TILE_K; } if ((static_cast(nmasks) & 0x8000) != 0 && m0 == TILE_M){ - _tile_stored(TMM4, c_blk, static_cast(ldc * sizeof(int32_t))); + tile_stored(TMM4, c_blk, static_cast(ldc * sizeof(int32_t))); } else { - _tile_stored(TMM4, Tile4, TILE_N * sizeof(int32_t)); + tile_stored(TMM4, Tile4, TILE_N * sizeof(int32_t)); MoveTile(Tile4, m0, static_cast(nmasks), c_blk, ldc); } if (m1 > 0){ - _tile_stored(TMM5, Tile5, TILE_N * sizeof(int32_t)); + tile_stored(TMM5, Tile5, TILE_N * sizeof(int32_t)); MoveTile(Tile5, m1, static_cast(nmasks), c16_blk, ldc); } if (nmask_high != 0){ - _tile_stored(TMM6, Tile6, TILE_N * sizeof(int32_t)); + tile_stored(TMM6, Tile6, TILE_N * sizeof(int32_t)); MoveTile(Tile6, m0, nmask_high, c_blk + TILE_N, ldc); if (m1 > 0){ - _tile_stored(TMM7, Tile7, TILE_N * sizeof(int32_t)); + tile_stored(TMM7, Tile7, TILE_N * sizeof(int32_t)); MoveTile(Tile7, m1, nmask_high, c16_blk + TILE_N, ldc); } } @@ -638,76 +649,78 @@ MlasGemmQuantKernel( const MLAS_GEMM_U8S8_KERNEL_AMX::PackedAType* a_next_blk = A + PackedCountK * TILE_M; if (ZeroPointB != nullptr){ - __m512i colsum = _mm512_loadu_epi32(col_sum_ptr); + __m512i colsum = _mm512_loadu_si512(col_sum_ptr); col_sum_ptr += TILE_N; - __m512i zeropoint = _mm512_loadu_epi32(zp_ptr); + __m512i zeropoint = _mm512_loadu_si512(zp_ptr); zp_ptr += TILE_N; - _tile_loadd(TMM0, b_blk, TILE_K); + tile_loadd(TMM0, b_blk, TILE_K); InitHalfTileWithRowColSumsZeroPoints(Tile4, RowSumBuffer, colsum, zeropoint, c_blk, ldc, ZeroMode); - _tile_loadd(TMM2, a_blk, static_cast(PackedCountK)); + tile_loadd(TMM2, a_blk, static_cast(PackedCountK)); InitHalfTileWithRowColSumsZeroPoints(Tile4+128, RowSumBuffer+8, colsum, zeropoint, c_blk+ldc*8, ldc, ZeroMode); - _tile_loadd(TMM4, Tile4, TILE_N * sizeof(int32_t)); + tile_loadd(TMM4, Tile4, TILE_N * sizeof(int32_t)); InitHalfTileWithRowColSumsZeroPoints(Tile5, RowSumBuffer+TILE_M, colsum, zeropoint, c16_blk, ldc, ZeroMode); - _tile_loadd(TMM3, a_next_blk, static_cast(PackedCountK)); + tile_loadd(TMM3, a_next_blk, static_cast(PackedCountK)); InitHalfTileWithRowColSumsZeroPoints(Tile5+128, RowSumBuffer+TILE_M+8, colsum, zeropoint, c16_blk+ldc*8, ldc, ZeroMode); - _tile_loadd(TMM5, Tile5, TILE_N * sizeof(int32_t)); - colsum = _mm512_loadu_epi32(col_sum_ptr); + tile_loadd(TMM5, Tile5, TILE_N * sizeof(int32_t)); + colsum = _mm512_loadu_si512(col_sum_ptr); col_sum_ptr += TILE_N; - zeropoint = _mm512_loadu_epi32(zp_ptr); + zeropoint = _mm512_loadu_si512(zp_ptr); zp_ptr += TILE_N; InitHalfTileWithRowColSumsZeroPoints(Tile6, RowSumBuffer, colsum, zeropoint, c_blk+TILE_N, ldc, ZeroMode); - _tile_loadd(TMM1, (void*)(b_blk + PackedCountK * TILE_N), TILE_K); + tile_loadd(TMM1, (void*)(b_blk + PackedCountK * TILE_N), TILE_K); InitHalfTileWithRowColSumsZeroPoints(Tile6+128, RowSumBuffer+8, colsum, zeropoint, c_blk+ldc*8+TILE_N, ldc, ZeroMode); - _tile_loadd(TMM6, Tile6, TILE_N * sizeof(int32_t)); - _tile_dpbusd(TMM4, TMM2, TMM0); + tile_loadd(TMM6, Tile6, TILE_N * sizeof(int32_t)); + tile_dpbusd(TMM4, TMM2, TMM0); InitHalfTileWithRowColSumsZeroPoints(Tile7, RowSumBuffer+TILE_M, colsum, zeropoint, c16_blk+TILE_N, ldc, ZeroMode); InitHalfTileWithRowColSumsZeroPoints(Tile7+128, RowSumBuffer+TILE_M+8, colsum, zeropoint, c16_blk+ldc*8+TILE_N, ldc, ZeroMode); } else { - __m512i colsum = _mm512_loadu_epi32(col_sum_ptr); + __m512i colsum = _mm512_loadu_si512(col_sum_ptr); col_sum_ptr += TILE_N; - _tile_loadd(TMM0, b_blk, TILE_K); + tile_loadd(TMM0, b_blk, TILE_K); InitHalfTileWithRowColSums(Tile4, RowSumBuffer, colsum, c_blk, ldc, ZeroMode); - _tile_loadd(TMM2, a_blk, static_cast(PackedCountK)); + tile_loadd(TMM2, a_blk, static_cast(PackedCountK)); InitHalfTileWithRowColSums(Tile4+128, RowSumBuffer+8, colsum, c_blk+ldc*8, ldc, ZeroMode); - _tile_loadd(TMM4, Tile4, TILE_N * sizeof(int32_t)); + tile_loadd(TMM4, Tile4, TILE_N * sizeof(int32_t)); InitHalfTileWithRowColSums(Tile5, RowSumBuffer+TILE_M, colsum, c16_blk, ldc, ZeroMode); - _tile_loadd(TMM3, a_next_blk, static_cast(PackedCountK)); + tile_loadd(TMM3, a_next_blk, static_cast(PackedCountK)); InitHalfTileWithRowColSums(Tile5+128, RowSumBuffer+TILE_M+8, colsum, c16_blk+ldc*8, ldc, ZeroMode); - _tile_loadd(TMM5, Tile5, TILE_N * sizeof(int32_t)); - colsum = _mm512_loadu_epi32(col_sum_ptr); + tile_loadd(TMM5, Tile5, TILE_N * sizeof(int32_t)); + colsum = _mm512_loadu_si512(col_sum_ptr); col_sum_ptr += TILE_N; InitHalfTileWithRowColSums(Tile6, RowSumBuffer, colsum, c_blk+TILE_N, ldc, ZeroMode); - _tile_loadd(TMM1, (void*)(b_blk + PackedCountK * TILE_N), TILE_K); + tile_loadd(TMM1, (void*)(b_blk + PackedCountK * TILE_N), TILE_K); InitHalfTileWithRowColSums(Tile6+128, RowSumBuffer+8, colsum, c_blk+ldc*8+TILE_N, ldc, ZeroMode); - _tile_loadd(TMM6, Tile6, TILE_N * sizeof(int32_t)); - _tile_dpbusd(TMM4, TMM2, TMM0); + tile_loadd(TMM6, Tile6, TILE_N * sizeof(int32_t)); + tile_dpbusd(TMM4, TMM2, TMM0); InitHalfTileWithRowColSums(Tile7, RowSumBuffer+TILE_M, colsum, c16_blk+TILE_N, ldc, ZeroMode); InitHalfTileWithRowColSums(Tile7+128, RowSumBuffer+TILE_M+8, colsum, c16_blk+ldc*8+TILE_N, ldc, ZeroMode); } - _tile_loadd(TMM7, Tile7, TILE_N * sizeof(int32_t)); + tile_loadd(TMM7, Tile7, TILE_N * sizeof(int32_t)); for (size_t k = PackedCountK - TILE_K; k > 0; k -= TILE_K) { b_blk += TILE_N * TILE_K; a_blk += TILE_K; a_next_blk += TILE_K; - _tile_dpbusd(TMM5, TMM3, TMM0); - _tile_loadd(TMM0, b_blk, TILE_K); - _tile_dpbusd(TMM6, TMM2, TMM1); - _tile_loadd(TMM2, a_blk, static_cast(PackedCountK)); - _tile_dpbusd(TMM7, TMM3, TMM1); - _tile_loadd(TMM3, a_next_blk, static_cast(PackedCountK)); - _tile_loadd(TMM1, (void*)(b_blk + PackedCountK * TILE_N), TILE_K); - _tile_dpbusd(TMM4, TMM2, TMM0); + tile_dpbusd(TMM5, TMM3, TMM0); + tile_loadd(TMM0, b_blk, TILE_K); + tile_dpbusd(TMM6, TMM2, TMM1); + tile_loadd(TMM2, a_blk, static_cast(PackedCountK)); + tile_dpbusd(TMM7, TMM3, TMM1); + tile_loadd(TMM3, a_next_blk, static_cast(PackedCountK)); + tile_loadd(TMM1, (void*)(b_blk + PackedCountK * TILE_N), TILE_K); + tile_dpbusd(TMM4, TMM2, TMM0); } - _tile_dpbusd(TMM5, TMM3, TMM0); - _tile_dpbusd(TMM6, TMM2, TMM1); - _tile_dpbusd(TMM7, TMM3, TMM1); + tile_dpbusd(TMM5, TMM3, TMM0); + tile_dpbusd(TMM6, TMM2, TMM1); + tile_dpbusd(TMM7, TMM3, TMM1); + b_blk += PackedCountK * TILE_N + TILE_N * TILE_K; - _tile_stored(TMM4, c_blk, static_cast(ldc * sizeof(int32_t))); - _tile_stored(TMM5, c16_blk, static_cast(ldc * sizeof(int32_t))); - _tile_stored(TMM6, (void*)(c_blk + TILE_N), static_cast(ldc * sizeof(int32_t))); + tile_stored(TMM4, c_blk, static_cast(ldc * sizeof(int32_t))); + tile_stored(TMM5, c16_blk, static_cast(ldc * sizeof(int32_t))); + tile_stored(TMM6, (void*)(c_blk + TILE_N), static_cast(ldc * sizeof(int32_t))); + c_blk += 2 * TILE_N; - _tile_stored(TMM7, (void*)(c16_blk + TILE_N), static_cast(ldc * sizeof(int32_t))); + tile_stored(TMM7, (void*)(c16_blk + TILE_N), static_cast(ldc * sizeof(int32_t))); c16_blk += 2 * TILE_N; } @@ -721,20 +734,20 @@ MlasGemmQuantKernel( InitTileWithRowColSumsZeroPoints( Tile4, TILE_M, static_cast(nmasks), RowSumBuffer, colsum, zeropoint, ZeroMode, c_blk, ldc); - _tile_loadd(TMM4, Tile4, TILE_N * sizeof(int32_t)); + tile_loadd(TMM4, Tile4, TILE_N * sizeof(int32_t)); InitTileWithRowColSumsZeroPoints( Tile5, TILE_M, static_cast(nmasks), RowSumBuffer + TILE_M, colsum, zeropoint, ZeroMode, c16_blk, ldc); - _tile_loadd(TMM5, Tile5, TILE_N * sizeof(int32_t)); + tile_loadd(TMM5, Tile5, TILE_N * sizeof(int32_t)); } else { InitTileWithRowColSums( Tile4, TILE_M, static_cast(nmasks), RowSumBuffer, colsum, ZeroMode, c_blk, ldc); - _tile_loadd(TMM4, Tile4, TILE_N * sizeof(int32_t)); + tile_loadd(TMM4, Tile4, TILE_N * sizeof(int32_t)); InitTileWithRowColSums( Tile5, TILE_M, static_cast(nmasks), RowSumBuffer + TILE_M, colsum, ZeroMode, c16_blk, ldc); - _tile_loadd(TMM5, Tile5, TILE_N * sizeof(int32_t)); + tile_loadd(TMM5, Tile5, TILE_N * sizeof(int32_t)); } if (nmask_high != 0){ colsum = _mm512_maskz_loadu_epi32(nmask_high, col_sum_ptr); @@ -743,52 +756,58 @@ MlasGemmQuantKernel( InitTileWithRowColSumsZeroPoints( Tile6, TILE_M, nmask_high, RowSumBuffer, colsum, zeropoint, ZeroMode, c_blk + TILE_N, ldc); - _tile_loadd(TMM6, Tile6, TILE_N * sizeof(int32_t)); + tile_loadd(TMM6, Tile6, TILE_N * sizeof(int32_t)); InitTileWithRowColSumsZeroPoints( Tile7, TILE_M, nmask_high, RowSumBuffer + TILE_M, colsum, zeropoint, ZeroMode, c16_blk + TILE_N, ldc); - _tile_loadd(TMM7, Tile7, TILE_N * sizeof(int32_t)); + tile_loadd(TMM7, Tile7, TILE_N * sizeof(int32_t)); } else { InitTileWithRowColSums( Tile6, TILE_M, nmask_high, RowSumBuffer, colsum, ZeroMode, c_blk + TILE_N, ldc); - _tile_loadd(TMM6, Tile6, TILE_N * sizeof(int32_t)); + tile_loadd(TMM6, Tile6, TILE_N * sizeof(int32_t)); InitTileWithRowColSums( Tile7, TILE_M, nmask_high, RowSumBuffer + TILE_M, colsum, ZeroMode, c16_blk + TILE_N, ldc); - _tile_loadd(TMM7, Tile7, TILE_N * sizeof(int32_t)); + tile_loadd(TMM7, Tile7, TILE_N * sizeof(int32_t)); } } const MLAS_GEMM_U8S8_KERNEL_AMX::PackedAType* a_blk = A; const MLAS_GEMM_U8S8_KERNEL_AMX::PackedAType* a_next_blk = A + PackedCountK * TILE_M; for (size_t k = PackedCountK; k > 0; k -=TILE_K) { - _tile_loadd(TMM0, b_blk, TILE_K); - _tile_loadd(TMM2, a_blk, static_cast(PackedCountK)); - _tile_loadd(TMM3, a_next_blk, static_cast(PackedCountK)); - _tile_dpbusd(TMM4, TMM2, TMM0); - _tile_dpbusd(TMM5, TMM3, TMM0); + tile_loadd(TMM0, b_blk, TILE_K); + tile_loadd(TMM2, a_blk, static_cast(PackedCountK)); + tile_loadd(TMM3, a_next_blk, static_cast(PackedCountK)); + + tile_dpbusd(TMM4, TMM2, TMM0); + tile_dpbusd(TMM5, TMM3, TMM0); + if (nmask_high != 0){ - _tile_loadd(TMM1, (void*)(b_blk + PackedCountK * TILE_N), TILE_K); - _tile_dpbusd(TMM6, TMM2, TMM1); - _tile_dpbusd(TMM7, TMM3, TMM1); + tile_loadd(TMM1, (void*)(b_blk + PackedCountK * TILE_N), TILE_K); + tile_dpbusd(TMM6, TMM2, TMM1); + tile_dpbusd(TMM7, TMM3, TMM1); + } b_blk += TILE_N * TILE_K; a_blk += TILE_K; a_next_blk += TILE_K; } if ((static_cast(nmasks) & 0x8000) != 0){ - _tile_stored(TMM4, c_blk, static_cast(ldc * sizeof(int32_t))); - _tile_stored(TMM5, c16_blk, static_cast(ldc * sizeof(int32_t))); + tile_stored(TMM4, c_blk, static_cast(ldc * sizeof(int32_t))); + tile_stored(TMM5, c16_blk, static_cast(ldc * sizeof(int32_t))); + } else { - _tile_stored(TMM4, Tile4, TILE_N * sizeof(int32_t)); - _tile_stored(TMM5, Tile5, TILE_N * sizeof(int32_t)); + tile_stored(TMM4, Tile4, TILE_N * sizeof(int32_t)); + tile_stored(TMM5, Tile5, TILE_N * sizeof(int32_t)); + MoveTile(Tile4, TILE_M, static_cast(nmasks), c_blk, ldc); MoveTile(Tile5, TILE_M, static_cast(nmasks), c16_blk, ldc); } if (nmask_high != 0){ - _tile_stored(TMM6, Tile6, TILE_N * sizeof(int32_t)); - _tile_stored(TMM7, Tile7, TILE_N * sizeof(int32_t)); + tile_stored(TMM6, Tile6, TILE_N * sizeof(int32_t)); + tile_stored(TMM7, Tile7, TILE_N * sizeof(int32_t)); + MoveTile(Tile6, TILE_M, nmask_high, c_blk + TILE_N, ldc); MoveTile(Tile7, TILE_M, nmask_high, c16_blk + TILE_N, ldc); } diff --git a/onnxruntime/core/mlas/lib/quantize.cpp b/onnxruntime/core/mlas/lib/quantize.cpp index c6e8af38c0020..133ad79594c55 100644 --- a/onnxruntime/core/mlas/lib/quantize.cpp +++ b/onnxruntime/core/mlas/lib/quantize.cpp @@ -21,6 +21,7 @@ Module Name: #include "mlasi.h" #if defined(MLAS_NEON64_INTRINSICS) || defined(MLAS_SSE2_INTRINSICS) +#include // // QuantizeLinear implementation using NEON or SSE2 intrinsics. @@ -79,6 +80,20 @@ MlasQuantizeLinearPackBytes( MLAS_INT32X4 IntegerVector ); +template +void +MlasQuantizeLinearStore4PackedValues( + MLAS_INT32X4 IntegerVector, + OutputType* Output + ); + +template +void +MlasQuantizeLinearStoreSingleValue( + MLAS_INT32X4 IntegerVector, + OutputType* Output + ); + #if defined(MLAS_NEON64_INTRINSICS) template @@ -100,6 +115,104 @@ MlasQuantizeLinearPackBytes( return vreinterpretq_s32_u8(ByteVector); } +template<> +MLAS_INT32X4 +MlasQuantizeLinearPackBytes( + MLAS_INT32X4 IntegerVector + ) +{ + // + // Swizzle the least significant u16 from each int32_t element to the + // bottom eight bytes of the vector register. + // + + uint16x8_t WordVector = vreinterpretq_u16_s32(IntegerVector); + WordVector = vuzp1q_u16(WordVector, WordVector); + return vreinterpretq_s32_u16(WordVector); +} + +template<> +MLAS_INT32X4 +MlasQuantizeLinearPackBytes( + MLAS_INT32X4 IntegerVector + ) +{ + // + // Swizzle the least significant u16 from each int32_t element to the + // bottom eight bytes of the vector register. + // + + int16x8_t WordVector = vreinterpretq_s16_s32(IntegerVector); + WordVector = vuzp1q_s16(WordVector, WordVector); + return vreinterpretq_s32_s16(WordVector); +} + +template +MLAS_FORCEINLINE +void +MlasQuantizeLinearStore4PackedValues( + MLAS_INT32X4 IntegerVector, + OutputType* Output + ) +{ + // Copies the lower 4 packed elements of the vector into memory (Output). + + if constexpr (std::is_same_v || std::is_same_v) { + vst1q_lane_s32(reinterpret_cast(Output), IntegerVector, 0); + } else { + static_assert(std::is_same_v || std::is_same_v); + vst1q_lane_s64(reinterpret_cast(Output), vreinterpretq_s64_s32(IntegerVector), 0); + } +} + +template <> +MLAS_FORCEINLINE +void +MlasQuantizeLinearStoreSingleValue( + MLAS_INT32X4 IntegerVector, + uint8_t* Output + ) +{ + // Copies the lower 8-bit element of the vector into memory (Output). + vst1q_lane_u8(Output, vreinterpretq_u8_s32(IntegerVector), 0); +} + +template <> +MLAS_FORCEINLINE +void +MlasQuantizeLinearStoreSingleValue( + MLAS_INT32X4 IntegerVector, + int8_t* Output + ) +{ + // Copies the lower 8-bit element of the vector into memory (Output). + vst1q_lane_s8(Output, vreinterpretq_s8_s32(IntegerVector), 0); +} + +template <> +MLAS_FORCEINLINE +void +MlasQuantizeLinearStoreSingleValue( + MLAS_INT32X4 IntegerVector, + uint16_t* Output + ) +{ + // Copies the lower 16-bit element of the vector into memory (Output). + vst1q_lane_u16(Output, vreinterpretq_u16_s32(IntegerVector), 0); +} + +template <> +MLAS_FORCEINLINE +void +MlasQuantizeLinearStoreSingleValue( + MLAS_INT32X4 IntegerVector, + int16_t* Output + ) +{ + // Copies the lower 16-bit element of the vector into memory (Output). + vst1q_lane_s16(Output, vreinterpretq_s16_s32(IntegerVector), 0); +} + #else template<> @@ -128,6 +241,86 @@ MlasQuantizeLinearPackBytes( return IntegerVector; } +template<> +MLAS_FORCEINLINE +MLAS_INT32X4 +MlasQuantizeLinearPackBytes( + MLAS_INT32X4 IntegerVector + ) +{ +#if defined(MLAS_SSE41_INTRINSICS) + IntegerVector = _mm_packus_epi32(IntegerVector, IntegerVector); // 16-bit values packed in lower 8 bytes. +#else + // Cannot use _mm_packus_epi32 because that was not available until SSE4.1. + // Instead, emulate by sign-extending the first 16-bits of each packed 32-bit element. + // Afterwards, can use _mm_packs_epi32, which is available on SSE2. + // See: https://stackoverflow.com/a/11028244 + + IntegerVector = _mm_slli_epi32(IntegerVector, 16); + IntegerVector = _mm_srai_epi32(IntegerVector, 16); // Sign-extend: undo left shift with right arithmetic shift + IntegerVector = _mm_packs_epi32(IntegerVector, IntegerVector); // 16-bit values packed in lower 8 bytes. +#endif // defined(MLAS_SSE41_INTRINSICS) + + return IntegerVector; +} + +template<> +MLAS_FORCEINLINE +MLAS_INT32X4 +MlasQuantizeLinearPackBytes( + MLAS_INT32X4 IntegerVector + ) +{ + IntegerVector = _mm_packs_epi32(IntegerVector, IntegerVector); // 16-bit values packed in lower 8 bytes. + + return IntegerVector; +} + +template +MLAS_FORCEINLINE +void +MlasQuantizeLinearStore4PackedValues( + MLAS_INT32X4 IntegerVector, + OutputType* Output + ) +{ + // Copies the lower 4 packed elements of the vector into memory (Output). + + if constexpr (std::is_same_v || std::is_same_v) { + *(reinterpret_cast(Output)) = _mm_cvtsi128_si32(IntegerVector); + } else { + static_assert(std::is_same_v || std::is_same_v); + +#if defined(MLAS_TARGET_IX86) + // x86 does not support _mm_cvtsi128_si64, so use _mm_maskmoveu_si128 instead. + constexpr uint32_t bytes_high_bit = 0x80808080; + const __m128i first_8_bytes_mask = _mm_set_epi32(0, 0, bytes_high_bit, bytes_high_bit); + _mm_maskmoveu_si128(IntegerVector, first_8_bytes_mask, reinterpret_cast(Output)); +#else + *(reinterpret_cast(Output)) = _mm_cvtsi128_si64(IntegerVector); +#endif // defined(MLAS_TARGET_IX86) + } +} + +template +MLAS_FORCEINLINE +void +MlasQuantizeLinearStoreSingleValue( + MLAS_INT32X4 IntegerVector, + OutputType* Output + ) +{ + static_assert(std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v); + + // Copies the lower element of the vector into memory (Output). + // Expects that the 32-bit element in lane 0 is already within the valid numerical + // range of the OutputType. + *Output = static_cast(_mm_cvtsi128_si32(IntegerVector)); +} + #endif template @@ -180,12 +373,7 @@ Return Value: MinimumValueVector, MaximumValueVector, ZeroPointVector); IntegerVector = MlasQuantizeLinearPackBytes(IntegerVector); - -#if defined(MLAS_NEON64_INTRINSICS) - vst1q_lane_s32((int32_t*)Output, IntegerVector, 0); -#else - *((int32_t*)Output) = _mm_cvtsi128_si32(IntegerVector); -#endif + MlasQuantizeLinearStore4PackedValues(IntegerVector, Output); Input += 4; Output += 4; @@ -202,11 +390,7 @@ Return Value: auto IntegerVector = MlasQuantizeLinearVector(FloatVector, ScaleVector, MinimumValueVector, MaximumValueVector, ZeroPointVector); -#if defined(MLAS_NEON64_INTRINSICS) - vst1q_lane_u8((uint8_t*)Output + n, vreinterpretq_u8_s32(IntegerVector), 0); -#else - *((uint8_t*)Output + n) = (uint8_t)_mm_cvtsi128_si32(IntegerVector); -#endif + MlasQuantizeLinearStoreSingleValue(IntegerVector, &Output[n]); } } @@ -236,6 +420,32 @@ MlasQuantizeLinearU8Kernel( MlasQuantizeLinearKernel(Input, Output, N, Scale, ZeroPoint); } +void +MLASCALL +MlasQuantizeLinearU16Kernel( + const float* Input, + uint16_t* Output, + size_t N, + float Scale, + uint16_t ZeroPoint +) +{ + MlasQuantizeLinearKernel(Input, Output, N, Scale, ZeroPoint); +} + +void +MLASCALL +MlasQuantizeLinearS16Kernel( + const float* Input, + int16_t* Output, + size_t N, + float Scale, + int16_t ZeroPoint +) +{ + MlasQuantizeLinearKernel(Input, Output, N, Scale, ZeroPoint); +} + template<> void MLASCALL @@ -274,6 +484,44 @@ MlasQuantizeLinear( Input, Output, N, Scale, ZeroPoint); } +template<> +void +MLASCALL +MlasQuantizeLinear( + const float* Input, + uint16_t* Output, + size_t N, + float Scale, + uint16_t ZeroPoint + ) +{ +#if defined(MLAS_TARGET_AMD64) + GetMlasPlatform().QuantizeLinearU16Kernel( +#else + MlasQuantizeLinearU16Kernel( +#endif + Input, Output, N, Scale, ZeroPoint); +} + +template<> +void +MLASCALL +MlasQuantizeLinear( + const float* Input, + int16_t* Output, + size_t N, + float Scale, + int16_t ZeroPoint + ) +{ +#if defined(MLAS_TARGET_AMD64) + GetMlasPlatform().QuantizeLinearS16Kernel( +#else + MlasQuantizeLinearS16Kernel( +#endif + Input, Output, N, Scale, ZeroPoint); +} + #else #if defined(MLAS_TARGET_POWER) @@ -306,6 +554,34 @@ MlasQuantizeLinear( GetMlasPlatform().QuantizeLinearU8Kernel(Input, Output, N, Scale, ZeroPoint); } +template<> +void +MLASCALL +MlasQuantizeLinear( + const float* Input, + int16_t* Output, + size_t N, + float Scale, + int16_t ZeroPoint + ) +{ + GetMlasPlatform().QuantizeLinearS16Kernel(Input, Output, N, Scale, ZeroPoint); +} + +template<> +void +MLASCALL +MlasQuantizeLinear( + const float* Input, + uint16_t* Output, + size_t N, + float Scale, + uint16_t ZeroPoint + ) +{ + GetMlasPlatform().QuantizeLinearU16Kernel(Input, Output, N, Scale, ZeroPoint); +} + #endif // @@ -381,6 +657,29 @@ MlasQuantizeLinear( float Scale, uint8_t ZeroPoint ); + +template +void +MLASCALL +MlasQuantizeLinear( + const float* Input, + int16_t* Output, + size_t N, + float Scale, + int16_t ZeroPoint + ); + +template +void +MLASCALL +MlasQuantizeLinear( + const float* Input, + uint16_t* Output, + size_t N, + float Scale, + uint16_t ZeroPoint + ); + #endif #endif diff --git a/onnxruntime/core/mlas/lib/x86_64/QgemmU8S8KernelAmxCommon.S b/onnxruntime/core/mlas/lib/x86_64/QgemmU8S8KernelAmxCommon.S new file mode 100644 index 0000000000000..7d042e2d8f476 --- /dev/null +++ b/onnxruntime/core/mlas/lib/x86_64/QgemmU8S8KernelAmxCommon.S @@ -0,0 +1,234 @@ +/*++ + +Copyright (c) 2023 Intel Corporation. All rights reserved. + +Licensed under the MIT License. + +Module Name: + + AssembleAmx.h + +Abstract: + + This module contains macros to build AMX instructions for toolchains that + do not natively support this newer instruction set extension. + +--*/ + +// +// Map friendly register names to the encoded register index. +// + + .equ .LTmmIndex_tmm0, 0 + .equ .LTmmIndex_tmm1, 1 + .equ .LTmmIndex_tmm2, 2 + .equ .LTmmIndex_tmm3, 3 + .equ .LTmmIndex_tmm4, 4 + .equ .LTmmIndex_tmm5, 5 + .equ .LTmmIndex_tmm6, 6 + .equ .LTmmIndex_tmm7, 7 + +/*++ + +Macro Description: + + This macro builds a AMX instruction of the form: + + instr tmm1,tmm2,tmm3 + +Arguments: + + prefix - Specifies the opcode for the AMX instruction. + + DestReg - Specifies the destination AMX tile. + + Src1Reg - Specifies the first source AMX tile. + + Src2Reg - Specifies the second source AMX tile. + +--*/ + + .macro DPTmmTmmTmm prefix, DestReg, Src1Reg, Src2Reg + + .set Payload0, 0x02 # "0F 38" prefix + .set Payload0, Payload0 + ((((.LTmmIndex_\DestReg\() >> 3) & 1) ^ 1) << 7) + .set Payload0, Payload0 + (1 << 6) + .set Payload0, Payload0 + ((((.LTmmIndex_\Src2Reg\() >> 3) & 1) ^ 1) << 5) + + .set Payload1, \prefix\() + .set Payload1, Payload1 + (((.LTmmIndex_\Src2Reg\() & 15) ^ 15) << 3) + + .set ModRMByte, 0xC0 # register form + .set ModRMByte, ModRMByte + ((.LTmmIndex_\DestReg\() & 7) << 3) + .set ModRMByte, ModRMByte + (.LTmmIndex_\Src1Reg\() & 7) + + .byte 0xC4, Payload0, Payload1, 0x5E, ModRMByte + + .endm + + + .macro TdpbssdTmmTmmTmm DestReg, Src1Reg, Src2Reg + + DPTmmTmmTmm 0x03, \DestReg\(), \Src1Reg\(), \Src2Reg\() + + .endm + + + .macro TdpbsudTmmTmmTmm DestReg, Src1Reg, Src2Reg + + DPTmmTmmTmm 0x02, \DestReg\(), \Src1Reg\(), \Src2Reg\() + + .endm + + + .macro TdpbusdTmmTmmTmm DestReg, Src1Reg, Src2Reg + + DPTmmTmmTmm 0x01, \DestReg\(), \Src1Reg\(), \Src2Reg\() + + .endm + + + .macro TdpbuudTmmTmmTmm DestReg, Src1Reg, Src2Reg + + DPTmmTmmTmm 0x00, \DestReg\(), \Src1Reg\(), \Src2Reg\() + + .endm + +/*++ + +Macro Description: + + This macro builds a AMX tile release instruction. + +Arguments: + + + +--*/ + +// .macro TileReleaseMacro + +// .byte 0xC4, 0xE2, 0x78, 0x49, 0xC0 + +// .endm + + +/*++ + +Macro Description: + + This macro builds an AMX tile zero instruction of the form: + + instr tmm1 + +Arguments: + + SrcReg - Specifies the source AMX tile. + +--*/ + + .macro TileZeroMacro SrcReg + + .set ModRMByte, 0xC0 # register form + .set ModRMByte, ModRMByte + ((.LTmmIndex_\SrcReg\() & 7) << 3) + .byte 0xC4, 0xE2, 0x7B, 0x49, ModRMByte + + .endm + +/*++ + +Macro Description: + + This macro builds an AMX memory instruction of the form: + + instr tmm, base, stride + +Arguments: + + instr - Specifies the opcode for the AMX instruction. + + SrcReg - Specifies the target AMX tile. + + BaseReg - Specifies the base address of memory location. + + Stride - Specifies the stride for the memory instruction + +--*/ + + .macro TileLoadMacro instr, SrcReg, BaseReg, Stride + + .set Payload0, 0x02 # "0F 38" prefix + .set Payload0, Payload0 + ((((.LTmmIndex_\SrcReg\() >> 3) & 1) ^ 1) << 7) + .set Payload0, Payload0 + ((((3 >> 3) & 1) ^ 1) << 6) + .set Payload0, Payload0 + ((((0 >> 3) & 1) ^ 1) << 5) + + .set ModRMByte, 0x00 # memory form + .set ModRMByte, ModRMByte + (1 << 2) # SibBye required + .set ModRMByte, ModRMByte + ((.LTmmIndex_\SrcReg\() & 7) << 3) + + .set SibByte, 0x00 # scale factor 1(SS) + .set SibByte, SibByte + ((3 & 7) << 3) + .set SibByte, SibByte + (0 & 7) + + .byte 0xC4, Payload0, \instr\(), 0x4B, ModRMByte, SibByte + + .endm + + + .macro TileloaddTmmMem DstReg, BaseReg, Stride + TileLoadMacro 0x7B, \DstReg\(), \BaseReg\(), \Stride\() + .endm + + .macro TileloaddT1TmmMem DstReg, BaseReg, Stride + TileLoadMacro 0x79, \DstReg\(), \BaseReg\(), \Stride\() + .endm + + + .macro TileStoredMemTmm SrcReg, BaseReg, Stride + TileLoadMacro 0x7A, \SrcReg\(), \BaseReg\(), \Stride\() + .endm + + +/*++ + +Macro Description: + + This macro builds an AMX tile configuration instruction of the form: + + instr base + +Arguments: + + instr - Specifies the opcode for the AMX instruction. + + BaseReg - Specifies the memory address of the tile configuration. + +--*/ + + .macro tilecfgMacro instr, BaseReg + .set Payload0, 0x02 # "0F 38" prefix + .set Payload0, Payload0 + (1 << 7) + .set Payload0, Payload0 + (1 << 6) + .set Payload0, Payload0 + ((((0 >> 3) & 1) ^ 1) << 5) + + .set ModRMByte, 0x00 # memory form & no reg + .set ModRMByte, ModRMByte + (0 & 7) + + .byte 0xC4, Payload0, \instr\(), 0x49, ModRMByte + + .endm + + + .macro ldtilecfgMacro BaseReg + + tilecfgMacro 0x78, \BaseReg\() + + .endm + + + .macro sttilecfgMacro BaseReg + + tilecfgMacro 0x79, \BaseReg\() + + .endm + diff --git a/onnxruntime/core/optimizer/attention_fusion_helper.h b/onnxruntime/core/optimizer/attention_fusion_helper.h index 2aeda6137c834..6233e5b839bb9 100644 --- a/onnxruntime/core/optimizer/attention_fusion_helper.h +++ b/onnxruntime/core/optimizer/attention_fusion_helper.h @@ -345,7 +345,7 @@ bool ValidateUnidirMask(const Graph& graph, const NodeArg& mask, bool& is_unidir return false; } } else if (tensor_proto->data_type() == ONNX_NAMESPACE::TensorProto_DataType_FLOAT) { - std::vector float_data = ONNX_NAMESPACE::ParseData(tensor_proto); + std::vector float_data = ONNX_NAMESPACE::ParseData(tensor_proto); if (!ValidateUnidirMask(float_data, shape->dim(2).dim_value(), is_unidirectional)) { DEBUG_LOG("Mask is neither unidirectional nor all ones"); return false; diff --git a/onnxruntime/core/optimizer/bias_gelu_fusion.cc b/onnxruntime/core/optimizer/bias_gelu_fusion.cc index fadf227a0817f..b90143e8f6121 100644 --- a/onnxruntime/core/optimizer/bias_gelu_fusion.cc +++ b/onnxruntime/core/optimizer/bias_gelu_fusion.cc @@ -41,11 +41,7 @@ Status BiasGeluFusion::ApplyImpl(Graph& graph, bool& modified, int graph_level, continue; } - int last_dim_shape1 = input1_shape->dim_size() - 1; - int last_dim_shape2 = input2_shape->dim_size() - 1; - if (!utils::HasDimValue(input1_shape->dim(last_dim_shape1)) || - !utils::HasDimValue(input2_shape->dim(last_dim_shape2)) || - input1_shape->dim(last_dim_shape1).dim_value() != input2_shape->dim(last_dim_shape2).dim_value()) { + if (input1_shape->dim(input1_shape->dim_size() - 1) != input2_shape->dim(input2_shape->dim_size() - 1)) { continue; } diff --git a/onnxruntime/core/optimizer/common_subexpression_elimination.cc b/onnxruntime/core/optimizer/common_subexpression_elimination.cc index e94d8179e758d..b2e7ef0b4f558 100644 --- a/onnxruntime/core/optimizer/common_subexpression_elimination.cc +++ b/onnxruntime/core/optimizer/common_subexpression_elimination.cc @@ -324,7 +324,8 @@ bool IsNodeSupported(const Node& node) { // would result in it having multiple consumers for its output, and it being used in multiple QDQ node groups. return !node.ContainsSubgraph() && optimizer_utils::IsOperationDeterministic(node.Domain(), node.OpType()) && - !(node.Domain() == kOnnxDomain && node.OpType() == "DequantizeLinear"); + !(node.Domain() == kOnnxDomain && node.OpType() == "DequantizeLinear") && + !(node.Domain() == kMSDomain && node.OpType() == "DequantizeLinear"); } } // namespace diff --git a/onnxruntime/core/optimizer/compute_optimizer/shared_utils.cc b/onnxruntime/core/optimizer/compute_optimizer/shared_utils.cc index ee900801ad071..913f3b6811183 100644 --- a/onnxruntime/core/optimizer/compute_optimizer/shared_utils.cc +++ b/onnxruntime/core/optimizer/compute_optimizer/shared_utils.cc @@ -4,6 +4,7 @@ #ifdef ENABLE_TRAINING #include +#include "core/framework/random_seed.h" #include "core/graph/graph_utils.h" #include "core/optimizer/initializer.h" #include "core/optimizer/utils.h" @@ -183,12 +184,76 @@ NodeArg* CreateInitializerFromVector(Graph& graph, total_count *= dim; } - ORT_ENFORCE(total_count == static_cast(values.size())); + ORT_ENFORCE(total_count == static_cast(values.size()), + "The total count of dims does not match the size of values. ", + "total_count: ", total_count, " values.size(): ", values.size()); const_tensor.set_raw_data(values.data(), values.size() * sizeof(int64_t)); return &graph_utils::AddInitializer(graph, const_tensor); } +NodeArg* InsertNodesForValidIndices(Graph& graph, + NodeArg* input_to_filter, + NodeArg* invalid_value, + const std::string& execution_provider_type) { + InlinedVector sub_input_args{input_to_filter, invalid_value}; + + InlinedVector sub_output_args{&graph.GetOrCreateNodeArg(graph.GenerateNodeArgName("sub_result"), + input_to_filter->TypeAsProto())}; + + Node& sub_node = graph.AddNode(graph.GenerateNodeName("sub_invalid_value"), "Sub", "sub invalid value", sub_input_args, + sub_output_args, nullptr, kOnnxDomain); + ORT_ENFORCE(graph.SetOpSchemaFromRegistryForNode(sub_node), "Failed to set op schema for " + sub_node.Name()); + sub_node.SetExecutionProviderType(execution_provider_type); + + auto non_zero_out_arg = &graph.GetOrCreateNodeArg(graph.GenerateNodeArgName("filter_valid_result"), + input_to_filter->TypeAsProto()); + + Node& non_zero_node = graph.AddNode(graph.GenerateNodeName("filter_valid_value"), "NonZero", + "filtering valid value", + {sub_node.MutableOutputDefs()[0]}, + {non_zero_out_arg}, nullptr, kOnnxDomain); + + ORT_ENFORCE(graph.SetOpSchemaFromRegistryForNode(non_zero_node), + "Failed to set op schema for " + non_zero_node.Name()); + + const std::string dim_name = MakeString("valid_indices_count_", utils::GetRandomSeed()); + + // 1D input NonZero generates output of shape (1,dim_name). + ONNX_NAMESPACE::TensorShapeProto non_zero_output_shape; + non_zero_output_shape.add_dim()->set_dim_value(1); + non_zero_output_shape.add_dim()->set_dim_param(dim_name); + non_zero_out_arg->SetShape(non_zero_output_shape); + non_zero_node.SetExecutionProviderType(execution_provider_type); + + InlinedVector squeeze_input_args; + squeeze_input_args.push_back(non_zero_out_arg); + + bool opset_lower_than_13 = onnxruntime::optimizer::compute_optimizer::GetONNXOpSetVersion(graph) < 13; + onnxruntime::NodeAttributes attributes; + if (opset_lower_than_13) { + attributes["axes"] = ONNX_NAMESPACE::MakeAttribute("axes", std::vector{0}); + } else { + squeeze_input_args.push_back(onnxruntime::optimizer::compute_optimizer::CreateInitializerFromVector( + graph, {1}, {0}, graph.GenerateNodeArgName("axes"))); + } + + auto squeeze_out_arg = &graph.GetOrCreateNodeArg(graph.GenerateNodeArgName("squeeze_adaptor"), + non_zero_out_arg->TypeAsProto()); + Node& squeeze_node = graph.AddNode(graph.GenerateNodeName("squeeze_adaptor"), "Squeeze", "nonzero_squeezer", + squeeze_input_args, {squeeze_out_arg}, &attributes, kOnnxDomain); + ORT_ENFORCE(graph.SetOpSchemaFromRegistryForNode(squeeze_node), + "Failed to set op schema for " + squeeze_node.Name()); + + // After Squeeze, the shape becomes (dim_name). + ONNX_NAMESPACE::TensorShapeProto squeeze_output_shape; + squeeze_output_shape.add_dim()->set_dim_param(dim_name); + squeeze_out_arg->SetShape(squeeze_output_shape); + squeeze_node.SetExecutionProviderType(execution_provider_type); + + return squeeze_out_arg; +} + } // namespace onnxruntime::optimizer::compute_optimizer #endif diff --git a/onnxruntime/core/optimizer/compute_optimizer/shared_utils.h b/onnxruntime/core/optimizer/compute_optimizer/shared_utils.h index ce08cc8763d48..963f3da1d0f31 100644 --- a/onnxruntime/core/optimizer/compute_optimizer/shared_utils.h +++ b/onnxruntime/core/optimizer/compute_optimizer/shared_utils.h @@ -36,6 +36,8 @@ const OPSET_VERSION_LIST opset_13_9_6_1{13, 9, 6, 1}; const OPSET_VERSION_LIST opset_14_13_5_1{14, 13, 5, 1}; const OPSET_VERSION_LIST opset_14_13_7_6_1{14, 13, 7, 6, 1}; const OPSET_VERSION_LIST opset_13_12_10_7_6_1{13, 12, 10, 7, 6, 1}; +const OPSET_VERSION_LIST opset_19_13_9_6_1{19, 13, 9, 6, 1}; +const OPSET_VERSION_LIST opset_19_14_13_5_1{19, 14, 13, 5, 1}; /** * @brief Base class for all upstream operator passthrough actors. @@ -174,5 +176,30 @@ NodeArg* CreateInitializerFromVector(Graph& graph, const InlinedVector& values, const std::string& name); +/** + * @brief Insert a pattern of 'Sub + NonZero + Squeeze' into the graph. + * This pattern is used to filter out the valid indices of the input tensor which is not padding idx. + * After inserting the pattern, the graph will be like: + * input_to_filter invalid_value + * (shape: [total_indices_count]) + * \ / + * Sub + * | + * NonZero + * | + * Squeeze + * | + * output (shape: [valid_indices_count]) + * + * @param graph The graph to insert the pattern. + * @param input_to_filter The input tensor to filter. + * @param invalid_value The invalid index value to remove. + * @param execution_provider_type The execution provider type of the inserted nodes. + */ +NodeArg* InsertNodesForValidIndices(Graph& graph, + NodeArg* input_to_filter, + NodeArg* invalid_value, + const std::string& execution_provider_type); + } // namespace onnxruntime::optimizer::compute_optimizer #endif diff --git a/onnxruntime/core/optimizer/compute_optimizer/upstream_gather.cc b/onnxruntime/core/optimizer/compute_optimizer/upstream_gather.cc index 299d85dd86791..094ea1e24dd92 100644 --- a/onnxruntime/core/optimizer/compute_optimizer/upstream_gather.cc +++ b/onnxruntime/core/optimizer/compute_optimizer/upstream_gather.cc @@ -34,7 +34,7 @@ UpStreamGatherGraphTransformer::UpStreamGatherGraphTransformer( {GetFullQualifiedOpName("Cast", kOnnxDomain), OpPassThroughConfig(std::make_shared>(), - opset_13_9_6_1)}, + opset_19_13_9_6_1)}, {GetFullQualifiedOpName("Div", kOnnxDomain), OpPassThroughConfig(std::make_shared>(), opset_14_13_7_6_1)}, @@ -53,7 +53,7 @@ UpStreamGatherGraphTransformer::UpStreamGatherGraphTransformer( opset_13_9_1)}, {GetFullQualifiedOpName("Reshape", kOnnxDomain), OpPassThroughConfig(std::make_shared(), - opset_14_13_5_1)}, + opset_19_14_13_5_1)}, {GetFullQualifiedOpName("Softmax", kOnnxDomain), OpPassThroughConfig(std::make_shared(), opset_13_11_1)}, @@ -138,20 +138,65 @@ SliceInfo UpStreamGatherGraphTransformer::PropagateSlicingForInput( std::to_string(!info.is_scalar_slice)); InlinedVector input_args; - input_args.reserve(slice_node.InputDefs().size()); + input_args.resize(slice_node.InputDefs().size()); + + int axis_input_index = -1; // -1 means axis is passed in attribute. + if (std::holds_alternative(info.axis_attr_name_or_input_index)) { + axis_input_index = std::get(info.axis_attr_name_or_input_index); + } + + auto create_axes_input = [&info, new_axis, &graph]() -> NodeArg* { + InlinedVector dims; + if (info.rank_of_axis_value == 1) { + dims.push_back(1); + } + return CreateInitializerFromVector(graph, dims, {new_axis}, graph.GenerateNodeArgName("axes")); + }; + // The first slice op's data input should be current_node's current_node_input_index-th input. // For some cases when rank changes, slice op's slice input should also be adapted. - input_args.push_back(current_node.MutableInputDefs()[current_node_input_index]); - for (size_t i = 1; i < slice_node.InputDefs().size(); ++i) { - input_args.push_back(slice_node.MutableInputDefs()[i]); + int i = 0; + for (; i < static_cast(slice_node.InputDefs().size()); ++i) { + if (i == info.GetDataInputIndex()) { + input_args[i] = current_node.MutableInputDefs()[current_node_input_index]; + } else if (axis_input_index != -1 && i == axis_input_index) { + if (info.non_negative_axis == new_axis) { + input_args[i] = slice_node.MutableInputDefs()[i]; + } else { + input_args[i] = create_axes_input(); + } + } else { + input_args[i] = slice_node.MutableInputDefs()[i]; + } + } + + // It is possible axes input is null. + if (axis_input_index != -1 && info.non_negative_axis != new_axis) { + for (; i <= axis_input_index; ++i) { + if (i == axis_input_index) { + input_args.push_back(create_axes_input()); + } else { + NodeArg& empty_input = graph.GetOrCreateNodeArg("", nullptr); + input_args.push_back(&empty_input); + } + } } // Update the axis attribute if new_axis is not the same as the original slicing axis (which happens when data // layout got changed by Transpose or Reshape ops) onnxruntime::NodeAttributes attributes = slice_node.GetAttributes(); - if (info.non_negative_axis != new_axis) { - attributes[info.axis_attr_name] = - ONNX_NAMESPACE::MakeAttribute(info.axis_attr_name, static_cast(new_axis)); + + if (axis_input_index == -1 && info.non_negative_axis != new_axis) { + std::string attr_name = std::get(info.axis_attr_name_or_input_index); + if (info.rank_of_axis_value == 0) { + attributes[attr_name] = + ONNX_NAMESPACE::MakeAttribute(attr_name, static_cast(new_axis)); + } else if (info.rank_of_axis_value == 1) { + attributes[attr_name] = + ONNX_NAMESPACE::MakeAttribute(attr_name, std::vector{static_cast(new_axis)}); + } else { + ORT_THROW("Unexpected rank of axis attribute value: " + std::to_string(info.rank_of_axis_value)); + } } InlinedVector output_args; @@ -183,7 +228,8 @@ SliceInfo UpStreamGatherGraphTransformer::PropagateSlicingForInput( auto new_slice_out_arg = new_slice_node->MutableOutputDefs()[new_slice_output_index_to_connect]; UpdateSliceOutputShape(*new_slice_out_arg, new_axis, info.output_dim_on_axis); - auto new_slice_info = SliceInfo(graph, new_slice_node, info.is_scalar_slice, info.axis_attr_name, new_axis); + auto new_slice_info = SliceInfo(graph, new_slice_node, info.is_scalar_slice, info.axis_attr_name_or_input_index, + new_axis, info.rank_of_axis_value); new_slice_info.entry_node_name = info.entry_node_name; new_slice_info.entry_slice_arg_name = info.entry_slice_arg_name; return new_slice_info; @@ -263,7 +309,8 @@ std::optional IsSupportedGatherND(Graph& graph, Node& node, return std::nullopt; } - return SliceInfo(graph, &node, false, "batch_dims", static_cast(batch_dims), true); + return SliceInfo(graph, &node, false, "batch_dims", static_cast(batch_dims), + 0 /* rank of axis attribute value */, true); } std::optional IsSupportedGather(Graph& graph, Node& node, @@ -304,7 +351,7 @@ std::optional IsSupportedGather(Graph& graph, Node& node, } } - return SliceInfo(graph, &node, dim_size == 0, "axis", axis, true); + return SliceInfo(graph, &node, dim_size == 0, "axis", axis, 0 /* rank of axis attribute value */, true); } std::optional IsSupportedShrunkenGather(Graph& graph, Node& node, @@ -342,7 +389,70 @@ std::optional IsSupportedShrunkenGather(Graph& graph, Node& node, return std::nullopt; } - return SliceInfo(graph, &node, false /*is_slice_scalar*/, "axis", axis, true); + return SliceInfo(graph, &node, false /*is_slice_scalar*/, "axis", axis, 0 /* rank of axis attribute value */, true); +} + +/** + * @brief Check if the Slice node can be up-streamed to the previous node. + * + * If "Slice" node is operating on one single axis, then it is supported. + * @return std::optional + */ +std::optional IsSupportedSlice(Graph& graph, Node& node, + const InlinedHashSet& + compatible_execution_providers, + const logging::Logger& logger) { + if (!graph_utils::IsSupportedOptypeVersionAndDomain(node, "Slice", {10, 11, 13}) || + !graph_utils::IsSupportedProvider(node, compatible_execution_providers)) { + return std::nullopt; + } + + const NodeArg* data_input = node.InputDefs()[0]; + const NodeArg* starts_input = node.InputDefs()[1]; + const NodeArg* ends_input = node.InputDefs()[2]; + const NodeArg* axes_input = node.InputDefs().size() > 3 ? node.InputDefs()[3] : nullptr; + + if (data_input->Shape() == nullptr || starts_input->Shape() == nullptr || ends_input->Shape() == nullptr || + (axes_input && axes_input->Exists() && axes_input->Shape() == nullptr)) { + LOG_DEBUG_INFO(logger, "Skip Slice node " + node.Name() + " due to undefined shape."); + return std::nullopt; + } + + // Make sure starts/ends/axes/steps are all 1D tensors, since we only support single-dimension slicing. + if (starts_input->Shape()->dim_size() != 1 || ends_input->Shape()->dim_size() != 1 || + (axes_input && axes_input->Exists() && axes_input->Shape()->dim_size() != 1)) { + LOG_DEBUG_INFO(logger, "Skip Slice node " + node.Name() + " due to unsupported dim size: " + + std::to_string(starts_input->Shape()->dim_size()) + ", " + + std::to_string(ends_input->Shape()->dim_size()) + ", " + + std::to_string(axes_input && axes_input->Exists() ? axes_input->Shape()->dim_size() : 0)); + return std::nullopt; + } + + // Try to parse the 'axes' value. + int axis = 0; + if (axes_input && axes_input->Exists()) { + InlinedVector axes_values; + if (!graph_utils::IsConstantInitializer(graph, axes_input->Name()) || + !optimizer_utils::AppendTensorFromInitializer(graph, *axes_input, axes_values, true) || + axes_values.size() != 1) { + LOG_DEBUG_INFO(logger, "Skip Slice node " + node.Name() + " due to unsupported axes value."); + return std::nullopt; + } + axis = static_cast(axes_values[0]); + } else { + // If 'axes' is not specified, then it is [0, .., r-1], so we force data rank to be 1. + if (data_input->Shape()->dim_size() != 1) { + LOG_DEBUG_INFO(logger, "Skip Slice node " + node.Name() + " due to unsupported data rank: " + + std::to_string(data_input->Shape()->dim_size())); + return std::nullopt; + } + } + + if (axis < 0) + axis += data_input->Shape()->dim_size(); + + return SliceInfo(graph, &node, false /*is_slice_scalar*/, 3 /* axis input index */, axis, + 1 /* rank of axes value */, true); } } // namespace @@ -358,6 +468,9 @@ std::optional UpStreamGatherGraphTransformer::IsSupportedForUpstream( if (!gather_info.has_value()) { gather_info = IsSupportedShrunkenGather(graph, node, GetCompatibleExecutionProviders(), logger); } + if (!gather_info.has_value()) { + gather_info = IsSupportedSlice(graph, node, GetCompatibleExecutionProviders(), logger); + } return gather_info; } diff --git a/onnxruntime/core/optimizer/compute_optimizer/upstream_gather_actors.cc b/onnxruntime/core/optimizer/compute_optimizer/upstream_gather_actors.cc index a3ac4312053aa..dd38ee9b07ee6 100644 --- a/onnxruntime/core/optimizer/compute_optimizer/upstream_gather_actors.cc +++ b/onnxruntime/core/optimizer/compute_optimizer/upstream_gather_actors.cc @@ -462,6 +462,27 @@ bool LayerNormalizationGatherActor::PreCheck(const Graph& /* graph */, return true; } +bool LayerNormalizationGatherActor::PostProcess(Graph& /*graph*/, Node& current_node, + const SliceInfo& info_without_node, + const logging::Logger& /*logger*/, + const std::unordered_map& /*propagate_input_indices*/, + const std::unordered_map>& + /*all_input_cmp_rets*/, + const std::unordered_map& /*new_gather_infos*/) { + // Update LayerNormalization's axis attribute if it is scalar slice. + if (info_without_node.is_scalar_slice) { + auto axis = static_cast(current_node.GetAttributes().at("axis").i()); + auto original_ln_input_rank = info_without_node.input_rank; + axis = axis < 0 ? axis + original_ln_input_rank : axis; + auto new_axis = axis - 1; + + auto& attributes = current_node.GetMutableAttributes(); + attributes["axis"] = ONNX_NAMESPACE::MakeAttribute("axis", static_cast(new_axis)); + } + + return true; +} + bool SoftmaxGatherActor::PreCheck(const Graph& graph, const Node& current_node, const SliceInfo& info, const logging::Logger& logger, std::unordered_map& propagate_input_indices, @@ -479,6 +500,28 @@ bool SoftmaxGatherActor::PreCheck(const Graph& graph, const Node& current_node, propagate_input_indices, all_input_cmp_rets, shape_update_func); } +bool SoftmaxGatherActor::PostProcess(Graph& graph, Node& current_node, const SliceInfo& info_without_node, + const logging::Logger& logger, + const std::unordered_map& propagate_input_indices, + const std::unordered_map>& all_input_cmp_rets, + const std::unordered_map& new_gather_infos) { + SimplePointwiseGatherActor::PostProcess(graph, current_node, info_without_node, logger, + propagate_input_indices, all_input_cmp_rets, new_gather_infos); + + // Update Softmax's axis attribute if it is scalar slice. + if (info_without_node.is_scalar_slice) { + auto axis = static_cast(current_node.GetAttributes().at("axis").i()); + auto original_ln_input_rank = info_without_node.input_rank; + axis = axis < 0 ? axis + original_ln_input_rank : axis; + auto new_axis = axis - 1; + + auto& attributes = current_node.GetMutableAttributes(); + attributes["axis"] = ONNX_NAMESPACE::MakeAttribute("axis", static_cast(new_axis)); + } + + return true; +} + bool ReshapeGatherActor::PreCheck(const Graph& graph, const Node& current_node, const SliceInfo& info, const logging::Logger& logger, std::unordered_map& propagate_input_indices, @@ -566,6 +609,11 @@ bool ReshapeGatherActor::PreCheck(const Graph& graph, const Node& current_node, return true; } + LOG_DEBUG_INFO(logger, "Skip handle the Reshape, new_shape_const_values[info.non_negative_axis]:" + + std::to_string(new_shape_const_values[info.non_negative_axis]) + + ", info.output_dim_on_axis.has_dim_value(): " + + std::to_string(info.output_dim_on_axis.has_dim_value()) + "."); + return false; } @@ -604,11 +652,12 @@ bool ReshapeGatherActor::PostProcess( return true; } - // If it selected shape is a dim value, we can update the shape tensor directory. + // If the selected shape is a dim value, we can update the shape tensor directory. if (info_without_node.output_dim_on_axis.has_dim_value()) { new_shape_const_values[slice_axis] = info_without_node.output_dim_on_axis.dim_value(); auto new_shape_arg = - CreateInitializerFromVector(graph, {static_cast(new_shape_const_values.size())}, new_shape_const_values, + CreateInitializerFromVector(graph, {static_cast(new_shape_const_values.size())}, + new_shape_const_values, graph.GenerateNodeArgName(current_node.MutableInputDefs()[1]->Name())); graph_utils::ReplaceNodeInput(current_node, 1, *new_shape_arg); return true; diff --git a/onnxruntime/core/optimizer/compute_optimizer/upstream_gather_actors.h b/onnxruntime/core/optimizer/compute_optimizer/upstream_gather_actors.h index 514368cea16c7..0c21be1397636 100644 --- a/onnxruntime/core/optimizer/compute_optimizer/upstream_gather_actors.h +++ b/onnxruntime/core/optimizer/compute_optimizer/upstream_gather_actors.h @@ -25,11 +25,21 @@ struct SliceInfo : public UpstreamOperatorInfoBase { public: SliceInfo(const Graph& graph, Node* slice_node, bool is_slice_scalar, - const std::string& slice_axis_attr_name, + std::variant axis_name_or_index, int slice_axis, + int rank_of_axis, bool is_entry_node_ptr = false) : UpstreamOperatorInfoBase(slice_node, is_entry_node_ptr), is_scalar_slice(is_slice_scalar) { - axis_attr_name = slice_axis_attr_name; + axis_attr_name_or_input_index = axis_name_or_index; + rank_of_axis_value = rank_of_axis; + + if (std::holds_alternative(axis_name_or_index)) { + int axis_input_index = std::get(axis_name_or_index); + ORT_ENFORCE(axis_input_index >= 0, "Axis input index is invalid"); + } + + ORT_ENFORCE(rank_of_axis_value == 0 || rank_of_axis_value == 1, "Rank of axis value is invalid: " + + std::to_string(rank_of_axis_value)); const NodeArg* input = node_ptr->InputDefs()[kSliceDataInputIndex_]; const NodeArg* output = node_ptr->OutputDefs()[kSliceOutputIndex_]; @@ -65,8 +75,16 @@ struct SliceInfo : public UpstreamOperatorInfoBase { } bool is_scalar_slice; // whether the slice is a scalar, if it is after Gather, the rank will be reduced by 1. - std::string axis_attr_name; + + // The index of the input that contains the axis value. If it is a string, then axis will be treated as an attribute. + std::variant axis_attr_name_or_input_index; + int non_negative_axis; // The axis to slice on + + // The rank of value for axis attribute. For example, for Gather, its axis attribute is a scalar, so the rank is 0. + // For Slice, its axes attribute is a 1D tensor, so the rank is 1. + int rank_of_axis_value; + std::string entry_slice_arg_name; int input_rank; // rank of the Gather data input tensor @@ -171,7 +189,7 @@ class LayerNormalizationGatherActor : public UpStreamGatherOperatorActorBase { const logging::Logger& /* logger */, const std::unordered_map& /* propagate_input_indices */, const std::unordered_map>& /* all_input_cmp_rets */, - const std::unordered_map& /* new_gather_infos */) override { return true; } + const std::unordered_map& /* new_gather_infos */) override; }; class SoftmaxGatherActor : public SimplePointwiseGatherActor { @@ -184,6 +202,12 @@ class SoftmaxGatherActor : public SimplePointwiseGatherActor { std::unordered_map& propagate_input_indices, std::unordered_map>& all_input_cmp_rets, std::function& shape_update_func) override; + + bool PostProcess(Graph& /* graph */, Node& /* current_node */, const SliceInfo& /* info_without_node */, + const logging::Logger& /* logger */, + const std::unordered_map& /* propagate_input_indices */, + const std::unordered_map>& /* all_input_cmp_rets */, + const std::unordered_map& /* new_gather_infos */) override; }; class ReshapeGatherActor : public UpStreamGatherOperatorActorBase { diff --git a/onnxruntime/core/optimizer/compute_optimizer/upstream_reshape.cc b/onnxruntime/core/optimizer/compute_optimizer/upstream_reshape.cc index 25734a6e80fea..f7b48de2caaf5 100644 --- a/onnxruntime/core/optimizer/compute_optimizer/upstream_reshape.cc +++ b/onnxruntime/core/optimizer/compute_optimizer/upstream_reshape.cc @@ -29,7 +29,7 @@ UpStreamReshapeGraphTransformer::UpStreamReshapeGraphTransformer( std::make_shared>(), opset_1)}, {GetFullQualifiedOpName("Cast", kOnnxDomain), OpPassThroughConfig( - std::make_shared>(), opset_13_9_6_1)}, + std::make_shared>(), opset_19_13_9_6_1)}, {GetFullQualifiedOpName("Dropout", kOnnxDomain), OpPassThroughConfig( std::make_shared>(), opset_13_12_10_7_6_1)}, @@ -246,21 +246,26 @@ std::optional UpStreamReshapeGraphTransformer::IsSupportedForUpstre return std::nullopt; } - bool are_first_two_dims_concrete = utils::HasDimValue(data_shape->dim(0)) && utils::HasDimValue(data_shape->dim(1)); - int64_t merged_dims_value = are_first_two_dims_concrete - ? data_shape->dim(0).dim_value() * data_shape->dim(1).dim_value() - : -1; + if (!utils::HasDimValue(data_shape->dim(2))) { + LOG_DEBUG_INFO(logger, "Skip Reshape node " + node.Name() + " due to data shape's last dim is not concrete."); + return std::nullopt; + } InlinedVector new_shape_const_values; optimizer_utils::AppendTensorFromInitializer(graph, *node.InputDefs()[1], new_shape_const_values, true); - if (new_shape_const_values.size() != 2 || - !(new_shape_const_values[0] == -1 || new_shape_const_values[0] == merged_dims_value)) { - LOG_DEBUG_INFO(logger, "Skip Reshape node " + node.Name() + " due to target shape is not merging first two dims."); + if (new_shape_const_values.size() != 2) { + LOG_DEBUG_INFO(logger, "Skip Reshape node " + node.Name() + " due to target shape is rank 2."); return std::nullopt; } - if (!utils::HasDimValue(data_shape->dim(2))) { - LOG_DEBUG_INFO(logger, "Skip Reshape node " + node.Name() + " due to the last dim size is not concrete value."); + if (new_shape_const_values[1] != data_shape->dim(2).dim_value()) { + LOG_DEBUG_INFO(logger, "Skip Reshape node " + node.Name() + + " due to target shape's last dim is not equal to data shape's last dim."); + return std::nullopt; + } + + // If the first dim of Reshape output don't have dim_value or dim_param, we can't do the optimization. + if (!(reshape_out_shape->dim(0).has_dim_value() || reshape_out_shape->dim(0).has_dim_param())) { return std::nullopt; } diff --git a/onnxruntime/core/optimizer/compute_optimizer/upstream_transformer_base.cc b/onnxruntime/core/optimizer/compute_optimizer/upstream_transformer_base.cc index 03e87013346d7..f08e37296d259 100644 --- a/onnxruntime/core/optimizer/compute_optimizer/upstream_transformer_base.cc +++ b/onnxruntime/core/optimizer/compute_optimizer/upstream_transformer_base.cc @@ -50,8 +50,9 @@ Status UpStreamGraphTransformerBase::ApplyImpl(Graph& graph, bool& modif const auto& order = graph_viewer.GetNodesInTopologicalOrder(); const auto& graph_outputs = graph.GetOutputs(); - size_t reordered_node_count = 0; // For summary - size_t passthrough_count = 0; + [[maybe_unused]] size_t reordered_node_count = 0; // For summary + [[maybe_unused]] size_t passthrough_count = 0; + for (const auto index : order) { auto* node_ptr = graph.GetNode(index); if (!node_ptr) diff --git a/onnxruntime/core/optimizer/concat_slice_elimination.cc b/onnxruntime/core/optimizer/concat_slice_elimination.cc index dcee53e5c86f0..f7a2b3be4466c 100644 --- a/onnxruntime/core/optimizer/concat_slice_elimination.cc +++ b/onnxruntime/core/optimizer/concat_slice_elimination.cc @@ -33,7 +33,10 @@ Status ConcatSliceElimination::ApplyImpl(Graph& graph, bool& modified, int graph modified = true; } } - LOGS(logger, INFO) << "Total fused concat node count: " << fused_count; + + if (fused_count > 0) { + LOGS(logger, INFO) << "Total fused concat node count: " << fused_count; + } return Status::OK(); } diff --git a/onnxruntime/core/optimizer/constant_folding.cc b/onnxruntime/core/optimizer/constant_folding.cc index 80e2bbedef974..f46273f2680a9 100644 --- a/onnxruntime/core/optimizer/constant_folding.cc +++ b/onnxruntime/core/optimizer/constant_folding.cc @@ -123,17 +123,6 @@ Status ConstantFolding::ApplyImpl(Graph& graph, bool& modified, int graph_level, } else { InitializedTensorSet constant_inputs; - // we currently constant fold using the CPU EP only. - // if the node is assigned to a different EP we can run it if it's an ONNX op as we have CPU based - // implementations for all ONNX ops. If the node/op is from a different op domain or if the CPU implementation - // does not support the specific input type(s) required by the node (currently we only support a subset of - // types in some CPU kernels) then we can't proceed with constant folding for the node. - auto ep_type = node->GetExecutionProviderType(); - bool cpu_ep = ep_type == kCpuExecutionProvider; - if (!cpu_ep && node->Domain() != kOnnxDomain) { - continue; - } - // Check if constant folding can be applied on this node. const auto can_constant_fold_node = [&](const Node& n, bool skip_inputs_constant_check = false) { return graph_utils::IsSupportedProvider(n, GetCompatibleExecutionProviders()) && @@ -196,18 +185,31 @@ Status ConstantFolding::ApplyImpl(Graph& graph, bool& modified, int graph_level, fetch_mlvalue_idxs.push_back(info.GetMLValueIndex(node_out->Name())); } - // override the EP assigned to the node so that it will use the CPU kernel for Compute. - if (!cpu_ep) { + const bool node_on_cpu_ep = node->GetExecutionProviderType() == kCpuExecutionProvider; + + std::unique_ptr kernel; + + if (!node_on_cpu_ep) { + // We need to copy the string here instead of taking a reference to it since node->SetExecutionProviderType + // will change the value of the reference + auto ep_type = node->GetExecutionProviderType(); + + // override the EP assigned to the node so that it will use the CPU kernel for Compute. node->SetExecutionProviderType(kCpuExecutionProvider); - } - auto kernel = info.CreateKernel(node); + kernel = info.CreateKernel(node); - // undo the EP change to the value that was assigned at graph partitioning time - if (!cpu_ep) { + // undo the EP change to the value that was assigned at graph partitioning time node->SetExecutionProviderType(ep_type); + } else { + kernel = info.CreateKernel(node); } + // We currently constant fold using the CPU EP only. + // If we can't find a CPU kernel for this node, then we can't proceed with constant folding. + // + // TODO(adrianlizarraga): Support constant folding with other execution providers. For example, we may be able + // to use a CUDA kernel to constant fold operators with data types not supported by the CPU EP kernel. if (kernel == nullptr) { LOGS(logger, WARNING) << "Could not find a CPU kernel and hence " << "can't constant fold " << node->OpType() << " node '" << node->Name() << "'"; diff --git a/onnxruntime/core/optimizer/constant_sharing.cc b/onnxruntime/core/optimizer/constant_sharing.cc index c06349ec9b5ca..a3c5a72ee79fd 100644 --- a/onnxruntime/core/optimizer/constant_sharing.cc +++ b/onnxruntime/core/optimizer/constant_sharing.cc @@ -35,7 +35,6 @@ using SupportedTypeList = boost::mp11::mp_list TENSOR_ELEM_COUNT_THRESHOLD) { + if (num_elements > ConstantSharing::TENSOR_ELEM_COUNT_THRESHOLD) { return false; } } - if (num_elements > 0 && num_elements <= TENSOR_ELEM_COUNT_THRESHOLD) { + if (num_elements > 0 && num_elements <= ConstantSharing::TENSOR_ELEM_COUNT_THRESHOLD) { return true; } @@ -253,8 +252,9 @@ Status ConstantSharing::ApplyImpl(Graph& graph, bool& modified, int /*graph_leve modified = true; } - - LOGS(logger, INFO) << "Total shared scalar initializer count: " << shared_count; + if (shared_count > 0) { + LOGS(logger, INFO) << "Total shared scalar initializer count: " << shared_count; + } return Status::OK(); } diff --git a/onnxruntime/core/optimizer/constant_sharing.h b/onnxruntime/core/optimizer/constant_sharing.h index d1ea0bce53fc0..3d0cb875da463 100644 --- a/onnxruntime/core/optimizer/constant_sharing.h +++ b/onnxruntime/core/optimizer/constant_sharing.h @@ -29,6 +29,8 @@ class ConstantSharing : public GraphTransformer { excluded_initializers_(excluded_initializers) { } + static constexpr int64_t TENSOR_ELEM_COUNT_THRESHOLD = 8; + 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 54fe7c4087483..c090ab2a6cc9b 100644 --- a/onnxruntime/core/optimizer/conv_activation_fusion.cc +++ b/onnxruntime/core/optimizer/conv_activation_fusion.cc @@ -7,6 +7,7 @@ #include "core/common/inlined_containers.h" #include "core/framework/tensorprotoutils.h" +#include "core/mlas/inc/mlas.h" #include "core/graph/graph_utils.h" #include "core/graph/node_attr_utils.h" #include "core/optimizer/utils.h" @@ -49,18 +50,30 @@ bool ConvFusionDataTypeCheck(const Node& conv_node) { // Assess the support level for the other compatible EPs and if they also // only support float, remove the EP check altogether. const std::string_view node_ep = conv_node.GetExecutionProviderType(); - if (node_ep == kCudaExecutionProvider || node_ep == kCpuExecutionProvider) { + if (node_ep == kCudaExecutionProvider) { if (!HasElementDataType(*conv_node.InputDefs()[0], ONNX_NAMESPACE::TensorProto_DataType_FLOAT)) { return false; } } + if (node_ep == kCpuExecutionProvider) { +#ifdef MLAS_F16VEC_INTRINSICS_SUPPORTED + if (!HasElementDataType(*conv_node.InputDefs()[0], ONNX_NAMESPACE::TensorProto_DataType_FLOAT) && + !HasElementDataType(*conv_node.InputDefs()[0], ONNX_NAMESPACE::TensorProto_DataType_FLOAT16)) { + return false; + } +#else + if (!HasElementDataType(*conv_node.InputDefs()[0], ONNX_NAMESPACE::TensorProto_DataType_FLOAT)) { + return false; + } +#endif // MLAS_F16VEC_INTRINSICS_SUPPORTED + } return true; } -class ConvActivation : public NodeSelector { +class ConvActivationSelector : public NodeSelector { public: - ConvActivation() = default; + ConvActivationSelector() = default; std::optional Select(const GraphViewer& graph_viewer, const Node& node) const override { const std::string_view node_ep = node.GetExecutionProviderType(); @@ -159,7 +172,7 @@ class ConvAddRelu : public NodeSelector { namespace actions { using NTO = NodesToOptimize; -class FuseConvActivation : public ReplaceWithNew { +class FuseConvActivationAction : public ReplaceWithNew { private: std::string OpType(const RuntimeState&) const override { return "FusedConv"; } @@ -245,9 +258,9 @@ class FuseConvAddRelu : public ReplaceWithNew { void RegisterConvActivationFusionRules(SelectorActionRegistry& registry) { const auto name = "ConvAct"; - auto action = std::make_unique(); + auto action = std::make_unique(); #if !defined(ORT_MINIMAL_BUILD) - auto selector = std::make_unique(); + auto selector = std::make_unique(); registry.RegisterSelectorAndAction(name, {{"Conv", {1, 11}}}, std::move(selector), std::move(action)); #else diff --git a/onnxruntime/core/optimizer/conv_add_act_fusion.cc b/onnxruntime/core/optimizer/conv_add_act_fusion.cc index 5e34bce3625d9..7c8bfeaec5f0f 100644 --- a/onnxruntime/core/optimizer/conv_add_act_fusion.cc +++ b/onnxruntime/core/optimizer/conv_add_act_fusion.cc @@ -40,20 +40,28 @@ const Node* GetLoneConsumerNode(const GraphViewer& graph_viewer, const Node& nod return &*node.OutputNodesBegin(); } -class ConvAddActivation : public NodeSelector { +class ConvAddActivationSelector : public NodeSelector { public: - ConvAddActivation() = default; - + ConvAddActivationSelector() = default; std::optional Select(const GraphViewer& graph_viewer, const Node& node) const override { const std::string_view node_ep = node.GetExecutionProviderType(); - if (node_ep != kCpuExecutionProvider || !HasElementDataType(*node.InputDefs()[0], ONNX_NAMESPACE::TensorProto_DataType_FLOAT)) { +#ifdef MLAS_F16VEC_INTRINSICS_SUPPORTED + if (node_ep != kCpuExecutionProvider || + (!HasElementDataType(*node.InputDefs()[0], ONNX_NAMESPACE::TensorProto_DataType_FLOAT) && + !HasElementDataType(*node.InputDefs()[0], ONNX_NAMESPACE::TensorProto_DataType_FLOAT16))) { + return std::nullopt; + } +#else + if (node_ep != kCpuExecutionProvider || + !HasElementDataType(*node.InputDefs()[0], ONNX_NAMESPACE::TensorProto_DataType_FLOAT)) { return std::nullopt; } +#endif // MLAS_F16VEC_INTRINSICS_SUPPORTED // we can't assign `conv_node` as the producer-node, even it is, because we have to make sure // 1. Its type is 'conv', 2. it has to satisfy the other requirements,like shape, please refer to SelectConvProducer for more info const Node* conv_node = nullptr; const auto* add_node = GetLoneConsumerNode(graph_viewer, node); - if (!add_node) { + if (add_node == nullptr) { return std::nullopt; } // Let's support addition first, leave any-element-wise-op fusion in the future. @@ -64,13 +72,13 @@ class ConvAddActivation : public NodeSelector { if (graph_utils::IsSupportedOptypeVersionAndDomain(*add_node, "Add", {7, 13, 14})) { conv_node = SelectProducerConv(*add_node); } - if (!conv_node) { + if (conv_node == nullptr) { return std::nullopt; } // GetLoneConsumerNode will ensure outputedge_count is 1 const auto* act_node = GetLoneConsumerNode(graph_viewer, *add_node); // even the next node is not a activation node, it's also fine. - if (!act_node) { + if (act_node == nullptr) { // we can't fuse add-activation when add_node has multiple consumer nodes act_node = nullptr; } else if (SelectActivation(graph_viewer, *act_node)) { @@ -82,7 +90,7 @@ class ConvAddActivation : public NodeSelector { NodesToOptimizeIndicesBuilder builder{}; builder.target_node = conv_node->Index(); builder.output_nodes = {add_node->Index()}; - if (act_node) { + if (act_node != nullptr) { builder.output_nodes.push_back(act_node->Index()); } return builder.Build(); @@ -167,17 +175,27 @@ class ConvAddActivation : public NodeSelector { // Check if this is a single use convolution that hasn't already // been fused with another Add/Sum node. The Add/Sum can also only be // fused if the convolution isn't itself fused with an activation. - if ((inputs_node[n]->OpType() == "Conv") && (pre_input_defs_count < 4) && (producer_input_args_count.size() < 4) && - (graph_utils::GetNodeAttribute(*inputs_node[n], "activation") == nullptr) && (inputs_node[n]->GetOutputEdgesCount() == 1)) { - if (pre_input_defs_count < 3) { - // The optional bias parameter is empty so set to an empty string. + if ((inputs_node[n]->OpType() == "Conv") && (pre_input_defs_count < 4) && + (producer_input_args_count.size() < 4) && + (graph_utils::GetNodeAttribute(*inputs_node[n], "activation") == nullptr) && + (inputs_node[n]->GetOutputEdgesCount() == 1)) { + if (pre_input_defs_count < 3) { // The optional bias parameter is empty so set to an empty string. + // TODO, add a new null arguments for bias + continue; + } + return inputs_node[n]; + } + if (inputs_node[n]->OpType() == "NhwcFusedConv" && (pre_input_defs_count < 4) && + (producer_input_args_count.size() < 5) && + (graph_utils::GetNodeAttribute(*inputs_node[n], "activation") == nullptr) && + (inputs_node[n]->GetOutputEdgesCount() == 1)) { + if (pre_input_defs_count < 3) { // The optional bias parameter is empty so set to an empty string. // TODO, add a new null arguments for bias continue; } return inputs_node[n]; } } - return nullptr; } }; @@ -187,9 +205,14 @@ class ConvAddActivation : public NodeSelector { namespace actions { using NTO = NodesToOptimize; -class FuseConvAddActivation : public ReplaceWithNew { +class FuseConvAddActivationAction : public ReplaceWithNew { + public: + FuseConvAddActivationAction() = default; + private: - std::string OpType(const RuntimeState&) const override { return "FusedConv"; } + std::string OpType(const RuntimeState& runtimeState) const override { + return (runtimeState.selected_nodes.Target().OpType() == "Conv") ? "FusedConv" : "NhwcFusedConv"; + } std::string Domain(const RuntimeState&) const override { return kMSDomain; } @@ -262,11 +285,14 @@ class FuseConvAddActivation : public ReplaceWithNew { } // namespace actions void RegisterConvAddActivationFusionRules(SelectorActionRegistry& registry) { - const auto name = "ConvAddAct"; - auto action = std::make_unique(); - auto selector = std::make_unique(); - registry.RegisterSelectorAndAction(name, {{"Conv", {1, 11}}}, + auto action = std::make_unique(); + auto selector = std::make_unique(); + registry.RegisterSelectorAndAction("ConvAddAct", {{"Conv", {1, 11}}}, std::move(selector), std::move(action)); + auto action_nhwc = std::make_unique(); + auto selector_nhwc = std::make_unique(); + registry.RegisterSelectorAndAction("NhwcFusedConvAct", {{"NhwcFusedConv", {1, 11}}}, + std::move(selector_nhwc), std::move(action_nhwc)); } SelectorActionRegistry CreateSelectorActionRegistry() { diff --git a/onnxruntime/core/optimizer/double_qdq_pairs_remover.cc b/onnxruntime/core/optimizer/double_qdq_pairs_remover.cc index 8dd446d82b5da..624679e7b1b4b 100644 --- a/onnxruntime/core/optimizer/double_qdq_pairs_remover.cc +++ b/onnxruntime/core/optimizer/double_qdq_pairs_remover.cc @@ -1,127 +1,51 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "core/optimizer/double_qdq_pairs_remover.h" +#include #include "core/graph/graph_utils.h" #include "core/optimizer/initializer.h" +#include "core/optimizer/qdq_transformer/qdq_util.h" namespace onnxruntime { -Status DoubleQDQPairsRemover::ApplyImpl( - Graph& graph, - bool& modified, - int /*graph_level*/, - const logging::Logger& /*logger*/) const { - const GraphViewer graph_viewer(graph); - const auto& node_topology_list = graph_viewer.GetNodesInTopologicalOrder(); - - for (const auto& self_index : node_topology_list) { - NodeIndex parent_index = 0; - NodeIndex child_index = 0; - NodeIndex grandchild_index = 0; - if (IsNodeRemovable(graph, self_index, parent_index, child_index, grandchild_index)) { - graph.RemoveEdge(parent_index, self_index, 0, 0); - graph.RemoveEdge(self_index, child_index, 0, 0); - graph.RemoveEdge(child_index, grandchild_index, 0, 0); - graph_utils::ReplaceNodeInput(*graph.GetNode(grandchild_index), 0, *graph.GetNode(self_index)->MutableInputDefs()[0]); - graph.AddEdge(parent_index, grandchild_index, 0, 0); - graph.RemoveNode(child_index); - graph.RemoveNode(self_index); - modified = true; - } - } - return Status::OK(); -} - -bool DoubleQDQPairsRemover::IsNodeRemovable( - Graph& graph, - const NodeIndex& self_index, - NodeIndex& parent_index, - NodeIndex& child_index, - NodeIndex& grandchild_index) { - // Check if the self is a DQ, and have one parent and one child, and cannot be a graph output - Node* self = graph.GetNode(self_index); - if (self == nullptr || - self->OpType() != "DequantizeLinear" || - self->GetInputEdgesCount() != 1 || - self->GetOutputEdgesCount() != 1 || - self->InputDefs().size() != InputIndex::TOTAL_COUNT || - graph.NodeProducesGraphOutput(*self)) { - return false; - } - - // Type is either "tensor(uint8)" or "tensor(int8)" - const auto self_zp_type = *self->InputDefs()[InputIndex::ZERO_POINT_ID]->Type(); - // child should be a Q, and have only one child, have the same type as self, and cannot be a graph output - child_index = self->OutputEdgesBegin()->GetNode().Index(); - const Node* child = graph.GetNode(child_index); - if (child == nullptr || - child->OpType() != "QuantizeLinear" || - child->GetOutputEdgesCount() != 1 || - child->InputDefs().size() != InputIndex::TOTAL_COUNT || - *child->InputDefs()[InputIndex::ZERO_POINT_ID]->Type() != self_zp_type || - graph.NodeProducesGraphOutput(*child)) { - return false; - } - - // parent should be a Q, and have only one output, and cannot be a graph output - parent_index = self->InputEdgesBegin()->GetNode().Index(); - Node* parent = graph.GetNode(parent_index); - if (parent == nullptr || - parent->GetOutputEdgesCount() != 1 || - parent->OpType() != "QuantizeLinear" || - graph.NodeProducesGraphOutput(*parent)) { - return false; - } - - // grandchild should be a DQ - grandchild_index = child->OutputEdgesBegin()->GetNode().Index(); - Node* grandchild = graph.GetNode(grandchild_index); - if (grandchild == nullptr || - grandchild->OpType() != "DequantizeLinear") { - return false; - } - const auto get_constant_initializer = [&graph](const std::string& initializer_name) { - return graph.GetConstantInitializer(initializer_name, true); - }; - if (!QDQ::IsQDQPairSupported(*parent, *self, get_constant_initializer, graph.ModelPath()) || - !QDQ::IsQDQPairSupported(*child, *grandchild, get_constant_initializer, graph.ModelPath())) { - return false; - } - float new_scale = 0.0f; - if (self_zp_type == "tensor(uint8)") { - uint8_t new_zero_point = 0; - if (!FindNewZeroPointAndScale(graph, *self, *child, new_scale, new_zero_point)) { - return false; - } - ApplyNewInputValue(graph, *grandchild, InputIndex::SCALE_ID, new_scale); - ApplyNewInputValue(graph, *parent, InputIndex::SCALE_ID, new_scale); - ApplyNewInputValue(graph, *grandchild, InputIndex::ZERO_POINT_ID, new_zero_point); - ApplyNewInputValue(graph, *parent, InputIndex::ZERO_POINT_ID, new_zero_point); - } else { - int8_t new_zero_point = 0; - if (!FindNewZeroPointAndScale(graph, *self, *child, new_scale, new_zero_point)) { - return false; - } - ApplyNewInputValue(graph, *grandchild, InputIndex::SCALE_ID, new_scale); - ApplyNewInputValue(graph, *parent, InputIndex::SCALE_ID, new_scale); - ApplyNewInputValue(graph, *grandchild, InputIndex::ZERO_POINT_ID, new_zero_point); - ApplyNewInputValue(graph, *parent, InputIndex::ZERO_POINT_ID, new_zero_point); - } - return true; +// Applies a new zero point or scale as the input for a Q/DQ node. +template +static void ApplyNewInputValue(Graph& graph, Node& node, QDQ::InputIndex index, T value) { + const auto* input_tensor = graph_utils::GetConstantInitializer(graph, node.InputDefs()[index]->Name()); + Initializer input_init{*input_tensor, graph.ModelPath()}; + ONNX_NAMESPACE::TensorProto new_input_tensor(*input_tensor); + input_init.data()[0] = value; + input_init.ToProto(new_input_tensor); + auto new_name = graph.GenerateNodeArgName("DoubleQDQRemoved_" + node.InputDefs()[index]->Name()); + new_input_tensor.set_name(new_name); + NodeArg& new_input = graph_utils::AddInitializer(graph, new_input_tensor); + graph_utils::ReplaceNodeInput(node, index, new_input); } +// Returns a new zero point and scale value for the given Q/DQ nodes. template -bool DoubleQDQPairsRemover::FindNewZeroPointAndScale(const Graph& graph, const Node& node1, const Node& node2, float& new_scale, T& new_zero_point) { +static bool FindNewZeroPointAndScale(const Graph& graph, const Node& node1, const Node& node2, + float& new_scale, T& new_zero_point, bool& skip_reset) { + // scale & zero point share same initializer, no need to reset the value + const std::string& node1_scale_name = node1.InputDefs()[QDQ::InputIndex::SCALE_ID]->Name(); + const std::string& node2_scale_name = node2.InputDefs()[QDQ::InputIndex::SCALE_ID]->Name(); + const std::string& node1_zp_name = node1.InputDefs()[QDQ::InputIndex::ZERO_POINT_ID]->Name(); + const std::string& node2_zp_name = node2.InputDefs()[QDQ::InputIndex::ZERO_POINT_ID]->Name(); + skip_reset = false; + if (node1_scale_name == node2_scale_name && node1_zp_name == node2_zp_name) { + skip_reset = true; + return true; + } // if Q/DQ scale and zero point are not constant, return false const ONNX_NAMESPACE::TensorProto* node1_scale_tensor_proto = - graph_utils::GetConstantInitializer(graph, node1.InputDefs()[InputIndex::SCALE_ID]->Name()); + graph_utils::GetConstantInitializer(graph, node1_scale_name); const ONNX_NAMESPACE::TensorProto* node2_scale_tensor_proto = - graph_utils::GetConstantInitializer(graph, node2.InputDefs()[InputIndex::SCALE_ID]->Name()); + graph_utils::GetConstantInitializer(graph, node2_scale_name); const ONNX_NAMESPACE::TensorProto* node1_zp_tensor_proto = - graph_utils::GetConstantInitializer(graph, node1.InputDefs()[InputIndex::ZERO_POINT_ID]->Name()); + graph_utils::GetConstantInitializer(graph, node1_zp_name); const ONNX_NAMESPACE::TensorProto* node2_zp_tensor_proto = - graph_utils::GetConstantInitializer(graph, node2.InputDefs()[InputIndex::ZERO_POINT_ID]->Name()); + graph_utils::GetConstantInitializer(graph, node2_zp_name); Initializer zero_point_init_1{*node1_zp_tensor_proto, graph.ModelPath()}; Initializer zero_point_init_2{*node2_zp_tensor_proto, graph.ModelPath()}; Initializer scale_init_1{*node1_scale_tensor_proto, graph.ModelPath()}; @@ -136,6 +60,11 @@ bool DoubleQDQPairsRemover::FindNewZeroPointAndScale(const Graph& graph, const N T zero_point_2 = zero_point_init_2.data()[0]; const float scale_1 = scale_init_1.data()[0]; const float scale_2 = scale_init_2.data()[0]; + // No need to rest the value if values are equal + if (zero_point_1 == zero_point_2 && abs(scale_1 - scale_2) < 1E-20) { + skip_reset = true; + return true; + } T q_min = std::numeric_limits::min(); T q_max = std::numeric_limits::max(); @@ -152,16 +81,141 @@ bool DoubleQDQPairsRemover::FindNewZeroPointAndScale(const Graph& graph, const N return true; } -template -void DoubleQDQPairsRemover::ApplyNewInputValue(Graph& graph, Node& node, const InputIndex& index, T value) { - const auto* input_tensor = graph_utils::GetConstantInitializer(graph, node.InputDefs()[index]->Name()); - Initializer input_init{*input_tensor, graph.ModelPath()}; - TensorProto new_input_tensor(*input_tensor); - input_init.data()[0] = value; - input_init.ToProto(new_input_tensor); - auto new_name = graph.GenerateNodeArgName("DoubleQDQRemoved_" + node.InputDefs()[index]->Name()); - new_input_tensor.set_name(new_name); - NodeArg& new_input = graph_utils::AddInitializer(graph, new_input_tensor); - graph_utils::ReplaceNodeInput(node, index, new_input); +// Recomputes the zero point and scale of the outer Q/DQ nodes (i.e., Q1 and DQ2). This is necessary because +// the original two QDQ pairs may have different zero-points and scales. Ex: Q1 -> DQ1 -> Q2 -> DQ2, where +// the first pair has (zp1, scale1) and the second pair has (zp2, scale2). +// After removing the middle two nodes, the zero point and scale of the final (outer) ops must be recomputed +// for correctness. +template +static bool RecomputeOuterQDQZeroPointAndScale(Graph& graph, Node& q1, const Node& dq1, const Node& q2, Node& dq2) { + bool skip_reset = false; + float new_scale = 0.0f; + ZeroPointType new_zero_point = 0; + if (!FindNewZeroPointAndScale(graph, dq1, q2, new_scale, new_zero_point, skip_reset)) { + return false; + } + if (skip_reset) { + return true; + } + ApplyNewInputValue(graph, dq2, QDQ::InputIndex::SCALE_ID, new_scale); + ApplyNewInputValue(graph, q1, QDQ::InputIndex::SCALE_ID, new_scale); + ApplyNewInputValue(graph, dq2, QDQ::InputIndex::ZERO_POINT_ID, new_zero_point); + ApplyNewInputValue(graph, q1, QDQ::InputIndex::ZERO_POINT_ID, new_zero_point); + + return true; +} + +// Checks if the provided node index (dq1_index) is a part of a valid double QDQ pair sequence +// (i.e., Q1 -> DQ1 -> Q2 -> DQ2) that can be reduced to the outer Q/DQ nodes (i.e., Q1 -> DQ2). +// If so, the zero point and scale of the outer Q/DQ nodes are recomputed and the node indices of the other nodes +// in the sequence (i.e., Q1, Q2, and DQ2) are returned via output parameters. +static bool IsReducibleDoubleQDQSequence(Graph& graph, NodeIndex& q1_index, NodeIndex dq1_index, + NodeIndex& q2_index, NodeIndex& dq2_index) { + // Ensure that dq1 is a DQ operator, has one parent and one child, and is not a graph output + Node* dq1 = graph.GetNode(dq1_index); + if (dq1 == nullptr || + dq1->OpType() != "DequantizeLinear" || + dq1->GetInputEdgesCount() != 1 || + dq1->GetOutputEdgesCount() != 1 || + graph.NodeProducesGraphOutput(*dq1)) { + return false; + } + + // Ensure that q2 is a Q operator, has only one child, and is not a graph output + q2_index = dq1->OutputEdgesBegin()->GetNode().Index(); + const Node* q2 = graph.GetNode(q2_index); + if (q2 == nullptr || + q2->OpType() != "QuantizeLinear" || + q2->GetOutputEdgesCount() != 1 || + graph.NodeProducesGraphOutput(*q2)) { + return false; + } + + // Ensure that q1 is a Q operator, has only one output, and is not a graph output + q1_index = dq1->InputEdgesBegin()->GetNode().Index(); + Node* q1 = graph.GetNode(q1_index); + if (q1 == nullptr || + q1->GetOutputEdgesCount() != 1 || + q1->OpType() != "QuantizeLinear" || + graph.NodeProducesGraphOutput(*q1)) { + return false; + } + + // Ensure the dq2 is a DQ operator. + dq2_index = q2->OutputEdgesBegin()->GetNode().Index(); + Node* dq2 = graph.GetNode(dq2_index); + if (dq2 == nullptr || + dq2->OpType() != "DequantizeLinear") { + return false; + } + + const auto get_constant_initializer = [&graph](const std::string& initializer_name) { + return graph.GetConstantInitializer(initializer_name, true); + }; + + // Each QDQ pair (i.e., q1 -> dq1, q2 -> dq2) has to meet the following additional requirements: + // - Scalar/constant zero-point and scale. + // - The DQ and Q ops within a pair must have the same scale and zero-point. + // However, each pair is allowed to have different scales and zero-points. + // + // TODO: IsQDQPairSupported() requires an explicit zero-point input, but technically a default + // value of 0 could be fine. + if (!QDQ::IsQDQPairSupported(*q1, *dq1, get_constant_initializer, graph.ModelPath()) || + !QDQ::IsQDQPairSupported(*q2, *dq2, get_constant_initializer, graph.ModelPath())) { + return false; + } + + const auto& dq1_input_defs = dq1->InputDefs(); + const ONNX_NAMESPACE::TensorProto* dq1_zp_tensor_proto = graph.GetConstantInitializer( + dq1_input_defs[QDQ::InputIndex::ZERO_POINT_ID]->Name(), true); + + assert(dq1_zp_tensor_proto != nullptr); // IsQDQPairSupported should have checked that this exists. + + auto dq1_zp_type = dq1_zp_tensor_proto->data_type(); + + if (dq1_zp_type == ONNX_NAMESPACE::TensorProto_DataType_UINT8) { + return RecomputeOuterQDQZeroPointAndScale(graph, *q1, *dq1, *q2, *dq2); + } + + if (dq1_zp_type == ONNX_NAMESPACE::TensorProto_DataType_INT8) { + return RecomputeOuterQDQZeroPointAndScale(graph, *q1, *dq1, *q2, *dq2); + } + + if (dq1_zp_type == ONNX_NAMESPACE::TensorProto_DataType_UINT16) { + return RecomputeOuterQDQZeroPointAndScale(graph, *q1, *dq1, *q2, *dq2); + } + + if (dq1_zp_type == ONNX_NAMESPACE::TensorProto_DataType_INT16) { + return RecomputeOuterQDQZeroPointAndScale(graph, *q1, *dq1, *q2, *dq2); + } + + return false; // Unsupported zero-point type } + +Status DoubleQDQPairsRemover::ApplyImpl( + Graph& graph, + bool& modified, + int /*graph_level*/, + const logging::Logger& /*logger*/) const { + const GraphViewer graph_viewer(graph); + const auto& node_topology_list = graph_viewer.GetNodesInTopologicalOrder(); + + for (const auto& dq1_index : node_topology_list) { + NodeIndex q1_index = 0; + NodeIndex q2_index = 0; + NodeIndex dq2_index = 0; + if (IsReducibleDoubleQDQSequence(graph, q1_index, dq1_index, q2_index, dq2_index)) { + graph.RemoveEdge(q1_index, dq1_index, 0, 0); + graph.RemoveEdge(dq1_index, q2_index, 0, 0); + graph.RemoveEdge(q2_index, dq2_index, 0, 0); + graph_utils::ReplaceNodeInput(*graph.GetNode(dq2_index), 0, *graph.GetNode(dq1_index)->MutableInputDefs()[0]); + graph.AddEdge(q1_index, dq2_index, 0, 0); + graph.RemoveNode(q2_index); + graph.RemoveNode(dq1_index); + modified = true; + } + } + return Status::OK(); +} + } // namespace onnxruntime diff --git a/onnxruntime/core/optimizer/double_qdq_pairs_remover.h b/onnxruntime/core/optimizer/double_qdq_pairs_remover.h index 294cd842d47e4..1833b007674fd 100644 --- a/onnxruntime/core/optimizer/double_qdq_pairs_remover.h +++ b/onnxruntime/core/optimizer/double_qdq_pairs_remover.h @@ -3,19 +3,16 @@ #pragma once -#include "core/common/common.h" #include "core/optimizer/graph_transformer.h" -#include "core/optimizer/qdq_transformer/qdq_util.h" namespace onnxruntime { -using ONNX_NAMESPACE::TensorProto; -using ONNX_NAMESPACE::TensorProto_DataType; -using QDQ::InputIndex; - /** * @Class DoubleQDQPairsRemover * @brief Remove one pair of Q-DQ from Double Q-DQ pairs. + * Specifically, this transformer converts the sequence Q1 -> DQ1 -> Q2 -> DQ2, where the first pair has (zp1, scale1) + * and the second pair has (zp2, scale2), into the sequence Q1 -> DQ2 by removing the middle two nodes. The zero-point + * and scale of the final QDQ pair is recomputed to preserve equality to the original sequence. */ class DoubleQDQPairsRemover : public GraphTransformer { public: @@ -27,27 +24,5 @@ class DoubleQDQPairsRemover : public GraphTransformer { bool& modified, int graph_level, const logging::Logger& logger) const override; - - static bool IsNodeRemovable( - Graph& graph, - const NodeIndex& self_index, - NodeIndex& parent_index, - NodeIndex& child_index, - NodeIndex& grandchild_index); - - template - static bool FindNewZeroPointAndScale( - const Graph& graph, - const Node& node1, - const Node& node2, - float& new_scale, - T& new_zero_point); - - template - static void ApplyNewInputValue( - Graph& graph, - Node& node, - const InputIndex& index, - T value); }; } // namespace onnxruntime diff --git a/onnxruntime/core/optimizer/fast_gelu_fusion.cc b/onnxruntime/core/optimizer/fast_gelu_fusion.cc index e25cc33114d61..a38a0fc06fbb2 100644 --- a/onnxruntime/core/optimizer/fast_gelu_fusion.cc +++ b/onnxruntime/core/optimizer/fast_gelu_fusion.cc @@ -151,7 +151,7 @@ MatchResult FastGeluFusion::CheckSecondFormula(Graph& graph, Node& pow1_node, if (p_cast1_node != nullptr) { Node& cast1_node = *graph.GetNode(p_cast1_node->Index()); // this is fused Cast node, so expect 2 output edges - if (!(graph_utils::IsSupportedOptypeVersionAndDomain(cast1_node, "Cast", {9, 13}) && + if (!(graph_utils::IsSupportedOptypeVersionAndDomain(cast1_node, "Cast", {9, 13, 19}) && CheckNode(graph, cast1_node, pow1_node.GetExecutionProviderType(), false)) || cast1_node.GetOutputEdgesCount() != 2) { return matchResult; @@ -262,7 +262,7 @@ Status FastGeluFusion::ApplyImpl(Graph& graph, bool& modified, int graph_level, if (p_cast3_node == nullptr) continue; Node& cast3_node = *graph.GetNode(p_cast3_node->Index()); - if (!(graph_utils::IsSupportedOptypeVersionAndDomain(cast3_node, "Cast", {9, 13}) && + if (!(graph_utils::IsSupportedOptypeVersionAndDomain(cast3_node, "Cast", {9, 13, 19}) && CheckNode(graph, cast3_node, node.GetExecutionProviderType(), true))) { continue; } diff --git a/onnxruntime/core/optimizer/graph_transformer_mgr.cc b/onnxruntime/core/optimizer/graph_transformer_mgr.cc index ce17708f3231e..039283bb2d4e1 100644 --- a/onnxruntime/core/optimizer/graph_transformer_mgr.cc +++ b/onnxruntime/core/optimizer/graph_transformer_mgr.cc @@ -19,7 +19,8 @@ common::Status GraphTransformerManager::GetSteps(unsigned& steps) const { return Status::OK(); } -common::Status GraphTransformerManager::ApplyTransformers(Graph& graph, TransformerLevel level, const logging::Logger& logger) const { +common::Status GraphTransformerManager::ApplyTransformers(Graph& graph, TransformerLevel level, + const logging::Logger& logger) const { const auto& transformers = level_to_transformer_map_.find(level); if (transformers == level_to_transformer_map_.end()) { return Status::OK(); @@ -43,7 +44,8 @@ common::Status GraphTransformerManager::ApplyTransformers(Graph& graph, Transfor return Status::OK(); } -common::Status GraphTransformerManager::Register(std::unique_ptr transformer, TransformerLevel level) { +common::Status GraphTransformerManager::Register(std::unique_ptr transformer, + TransformerLevel level) { const auto& name = transformer->Name(); if (transformers_info_.find(name) != transformers_info_.end()) { return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "This transformer is already registered " + name); diff --git a/onnxruntime/core/optimizer/graph_transformer_utils.cc b/onnxruntime/core/optimizer/graph_transformer_utils.cc index fe7698d040b4f..54511aa02a57c 100644 --- a/onnxruntime/core/optimizer/graph_transformer_utils.cc +++ b/onnxruntime/core/optimizer/graph_transformer_utils.cc @@ -53,6 +53,7 @@ #include "core/optimizer/nchwc_transformer.h" #include "core/optimizer/noop_elimination.h" #include "core/optimizer/not_where_fusion.h" +#include "core/optimizer/pre_shape_node_elimination.h" #ifdef MLAS_TARGET_AMD64_IX86 #include "core/optimizer/qdq_transformer/avx2_weight_s8_to_u8.h" #endif @@ -68,7 +69,7 @@ #include "core/optimizer/rule_based_graph_transformer.h" #include "core/optimizer/skip_layer_norm_fusion.h" #include "core/optimizer/slice_elimination.h" -#include "core/optimizer/transpose_optimizer/ort_transpose_optimizer.h" +#include "core/optimizer/transpose_optimizer.h" #include "core/optimizer/unsqueeze_elimination.h" #ifdef ENABLE_TRAINING #include "orttraining/core/optimizer/bias_softmax_dropout_fusion.h" @@ -76,6 +77,10 @@ #include "orttraining/core/optimizer/sce_loss_grad_bias_fusion.h" #include "orttraining/core/optimizer/memory_optimizer.h" #endif +#ifdef ENABLE_TRITON +#include "orttraining/core/optimizer/triton_fusion.h" +#include "orttraining/core/framework/triton/triton_op_executor.h" +#endif // ENABLE_TRITON #endif // !defined(ORT_MINIMAL_BUILD) @@ -112,6 +117,7 @@ InlinedVector> GenerateRewriteRules( rules.push_back(std::make_unique()); rules.push_back(std::make_unique()); rules.push_back(std::make_unique()); + rules.push_back(std::make_unique()); rules.push_back(std::make_unique()); rules.push_back(std::make_unique()); rules.push_back(std::make_unique()); @@ -234,7 +240,9 @@ InlinedVector> GenerateTransformers( // run TransposeOptimizer last as it works in a slightly different way by moving Transpose nodes around. // shouldn't affect the end result - just easier to debug any issue if it's last. - auto cpu_allocator = cpu_execution_provider.GetAllocator(OrtMemTypeDefault); + // local CPU allocator is enough as this allocator is finally passed to a local tensor. + // We will also benefit by using a local allocator as we don't need to pass allocator as parameter for EP API refactor + AllocatorPtr cpu_allocator = std::make_shared(); transformers.emplace_back(std::make_unique(std::move(cpu_allocator))); } break; @@ -295,22 +303,12 @@ InlinedVector> GenerateTransformers( transformers.emplace_back(std::make_unique(cpu_cuda_dml_rocm_eps)); transformers.emplace_back(std::make_unique(cpu_cuda_dml_rocm_eps)); - transformers.emplace_back(std::make_unique(cpu_cuda_rocm_eps)); - transformers.emplace_back(std::make_unique(cuda_rocm_eps)); -#ifdef ENABLE_TRAINING - transformers.emplace_back(std::make_unique(cuda_rocm_eps)); - transformers.emplace_back(std::make_unique(cuda_rocm_eps)); - transformers.emplace_back(std::make_unique(cpu_cuda_rocm_eps)); -#endif transformers.emplace_back(std::make_unique(cpu_cuda_dml_rocm_eps)); transformers.emplace_back(std::make_unique(cpu_cuda_rocm_eps)); transformers.emplace_back(std::make_unique(cpu_cuda_dml_rocm_eps)); - transformers.emplace_back(std::make_unique(cpu_cuda_dml_rocm_eps)); - transformers.emplace_back(std::make_unique(dml_ep)); - // GeluApproximation has side effects which may change results. It needs to be manually enabled, // or alternatively the model can be updated offline using a model conversion script // e.g. fusion_gelu_approximation function used by onnxruntime/python/tools/transformers/onnx_model_bert.py @@ -318,6 +316,25 @@ InlinedVector> GenerateTransformers( transformers.emplace_back(std::make_unique(cpu_cuda_rocm_eps)); } +#ifdef ENABLE_TRITON + if (training::framework::triton::TritonOpExecutor::Instance().IsInitialized()) { + transformers.emplace_back( + std::make_unique(training::framework::triton::TritonOpExecutor::Instance().GetConfigJson(), + InlinedHashSet{onnxruntime::kCudaExecutionProvider})); + } +#endif // ENABLE_TRITON + + transformers.emplace_back(std::make_unique(cpu_cuda_rocm_eps)); + transformers.emplace_back(std::make_unique(cuda_rocm_eps)); +#ifdef ENABLE_TRAINING + transformers.emplace_back(std::make_unique(cuda_rocm_eps)); + transformers.emplace_back(std::make_unique(cuda_rocm_eps)); + transformers.emplace_back(std::make_unique(cpu_cuda_rocm_eps)); +#endif + + transformers.emplace_back(std::make_unique(cpu_cuda_dml_rocm_eps)); + transformers.emplace_back(std::make_unique(dml_ep)); + #ifdef MLAS_TARGET_AMD64_IX86 if (avx2_precision_mode) { transformers.emplace_back(std::make_unique(cpu_ep)); @@ -349,8 +366,12 @@ InlinedVector> GenerateTransformers( if (MlasNchwcGetBlockSize() > 1) { transformers.emplace_back(std::make_unique()); } - auto cpu_allocator = cpu_execution_provider.GetAllocator(OrtMemTypeDefault); - transformers.emplace_back(std::make_unique(std::move(cpu_allocator))); + AllocatorPtr cpu_allocator = std::make_shared(); + auto cpu_registry = cpu_execution_provider.GetKernelRegistry(); + auto nhwc_transformer = std::make_unique(std::move(cpu_allocator), std::move(cpu_registry)); + if (nhwc_transformer->IsActive()) { + transformers.emplace_back(std::move(nhwc_transformer)); + } // NCHWCtransformer should have a higher priority versus this. Because NCHWCtransformer also do the similar things // of fusion patterns and target on CPU. However, NCHWCtransformer will reorder the layout to nchwc which is only available for // x86-64 cpu, not edge cpu like arm. But This transformer could be used by opencl-ep/cpu-ep. So @@ -421,9 +442,12 @@ InlinedVector> GenerateTransformersForMinimalB // currently the only level 3 optimizer is the NhwcTransformer which is fully supported at runtime if (!saving) { #ifndef DISABLE_CONTRIB_OPS - const InlinedHashSet cpu_ep = {onnxruntime::kCpuExecutionProvider}; - auto cpu_allocator = cpu_execution_provider.GetAllocator(OrtMemTypeDefault); - transformers.emplace_back(std::make_unique(std::move(cpu_allocator))); + AllocatorPtr cpu_allocator = std::make_shared(); + auto cpu_registry = cpu_execution_provider.GetKernelRegistry(); + auto nhwc_transformer = std::make_unique(std::move(cpu_allocator), std::move(cpu_registry)); + if (nhwc_transformer->IsActive()) { + transformers.emplace_back(std::move(nhwc_transformer)); + } #else ORT_UNUSED_PARAMETER(cpu_execution_provider); #endif diff --git a/onnxruntime/core/optimizer/identical_children_consolidation.cc b/onnxruntime/core/optimizer/identical_children_consolidation.cc index 07dc25dabde5f..350da9605a13d 100644 --- a/onnxruntime/core/optimizer/identical_children_consolidation.cc +++ b/onnxruntime/core/optimizer/identical_children_consolidation.cc @@ -44,7 +44,7 @@ bool IdenticalChildrenConsolidation::IsSupportedParentNode(const Node* node) con std::vector> IdenticalChildrenConsolidation::DivideIdenticalChildrenIntoGroups( const Graph& graph, Node* node, - const string_view& op) const { + const string_view& op) { unordered_map> identical_children_map; for (auto i = node->OutputEdgesBegin(); i != node->OutputEdgesEnd(); ++i) { if (i->GetNode().OpType() == op) { @@ -60,68 +60,69 @@ std::vector> IdenticalChildrenConsolidation::DivideIdenti return groups; } -string_view IdenticalChildrenConsolidation::IdentityBuilder(const Graph& graph, const Node& node) const { - std::string identity; +std::string IdenticalChildrenConsolidation::IdentityBuilder(const Graph& graph, const Node& node) { + std::ostringstream identity; for (const auto* input_def : node.InputDefs()) { if (input_def->Exists() && !input_def->Name().empty()) { auto name = input_def->Name(); if (graph_utils::NodeArgIsConstant(graph, *input_def)) { if (optimizer_utils::IsScalar(*input_def)) { const auto* data = graph_utils::GetConstantInitializer(graph, name); - identity.append(constant_prefix); + identity << constant_prefix; Initializer value{*data, graph.ModelPath()}; switch (static_cast(data->data_type())) { case TensorProto::DataType::TensorProto_DataType_INT8: - identity.append(std::to_string(value.data()[0])); + identity << *value.data(); break; case TensorProto::DataType::TensorProto_DataType_INT16: - identity.append(std::to_string(value.data()[0])); + identity << *value.data(); break; case TensorProto::DataType::TensorProto_DataType_INT32: - identity.append(std::to_string(value.data()[0])); + identity << *value.data(); break; case TensorProto::DataType::TensorProto_DataType_UINT8: - identity.append(std::to_string(value.data()[0])); + identity << *value.data(); break; case TensorProto::DataType::TensorProto_DataType_UINT16: - identity.append(std::to_string(value.data()[0])); + identity << *value.data(); break; case TensorProto::DataType::TensorProto_DataType_BOOL: - identity.append(std::to_string(value.data()[0])); + identity << *value.data(); break; case TensorProto::DataType::TensorProto_DataType_INT64: - identity.append(std::to_string(value.data()[0])); + identity << *value.data(); break; case TensorProto::DataType::TensorProto_DataType_UINT32: - identity.append(std::to_string(value.data()[0])); + identity << *value.data(); break; case TensorProto::DataType::TensorProto_DataType_UINT64: - identity.append(std::to_string(value.data()[0])); + identity << *value.data(); break; case TensorProto::DataType::TensorProto_DataType_FLOAT: - identity.append(std::to_string(value.data()[0])); + identity << *value.data(); break; case TensorProto::DataType::TensorProto_DataType_DOUBLE: - identity.append(std::to_string(value.data()[0])); + identity << *value.data(); break; case TensorProto::DataType::TensorProto_DataType_STRING: - identity.append(value.data()[0]); + identity << *value.data(); break; default: break; } } else { // TODO: handle non-scalar constant inputs, using checksum or something else - return ignore_identity; + return std::string{ignore_identity}; } } else { - identity.append(name); + identity << name; } } else { - return ignore_identity; + return std::string{ignore_identity}; } - identity.append("####"); + identity << "####"; } - return {identity}; + + return identity.str(); } } // namespace onnxruntime \ No newline at end of file diff --git a/onnxruntime/core/optimizer/identical_children_consolidation.h b/onnxruntime/core/optimizer/identical_children_consolidation.h index 2be32b3e016e5..0289ec245bcd6 100644 --- a/onnxruntime/core/optimizer/identical_children_consolidation.h +++ b/onnxruntime/core/optimizer/identical_children_consolidation.h @@ -43,13 +43,13 @@ class IdenticalChildrenConsolidation : public GraphTransformer { private: Status ApplyImpl(Graph& graph, bool& modified, int graph_level, const logging::Logger& logger) const override; bool IsSupportedParentNode(const Node* node) const; - std::vector > DivideIdenticalChildrenIntoGroups(const Graph& graph, Node* node, const string_view& op) const; - string_view IdentityBuilder(const Graph& graph, const Node& node) const; + static std::vector > DivideIdenticalChildrenIntoGroups(const Graph& graph, Node* node, const string_view& op); + static std::string IdentityBuilder(const Graph& graph, const Node& node); unordered_map > supported_ops = { {"DequantizeLinear", {"QuantizeLinear"}}, {"QuantizeLinear", {"DequantizeLinear"}}}; - string_view constant_prefix = "ItIsSpecialConstantPrefix_"; - string_view ignore_identity = "IgNoReD_IdEnTiTy"; + static constexpr string_view constant_prefix = "ItIsSpecialConstantPrefix_"; + static constexpr string_view ignore_identity = "IgNoReD_IdEnTiTy"; }; } // namespace onnxruntime diff --git a/onnxruntime/core/optimizer/initializer.cc b/onnxruntime/core/optimizer/initializer.cc index 8904a2995c8f5..9cdc0d9ef0473 100644 --- a/onnxruntime/core/optimizer/initializer.cc +++ b/onnxruntime/core/optimizer/initializer.cc @@ -289,23 +289,24 @@ Initializer& Initializer::sqrt() { namespace { template struct ScaleByAxis { - void operator()(Tensor& data, const Tensor& scalers, const int64_t block_size, const int64_t num_blocks) const { + void operator()(Tensor& data, const Tensor& scalers, const size_t block_size, const size_t num_blocks) const { ToNumeric to_numeric; const auto scaler_size = scalers.Shape().Size(); T* dst = data.MutableData(); const T* scalers_data = scalers.Data(); if (scaler_size == 1) { const auto numeric_scaler = to_numeric(scalers_data[0]); - for (int64_t block_offset = 0, limit = block_size * num_blocks; block_offset < limit; ++block_offset) { + for (size_t block_offset = 0, limit = block_size * num_blocks; block_offset < limit; ++block_offset) { dst[block_offset] = T(to_numeric(dst[block_offset]) * numeric_scaler); } - } else - for (int64_t block_offset = 0, i = 0; i < num_blocks; i++) { + } else { + for (size_t block_offset = 0, i = 0; i < num_blocks; i++) { const auto numeric_scaler = to_numeric(scalers_data[i]); - for (int64_t j = 0; j < block_size; ++j, ++block_offset) { + for (size_t j = 0; j < block_size; ++j, ++block_offset) { dst[block_offset] = T(to_numeric(dst[block_offset]) * numeric_scaler); } } + } } }; @@ -313,8 +314,8 @@ struct ScaleByAxis { void Initializer::scale_by_axis(const Initializer& scalers, int axis) { ORT_ENFORCE(axis >= 0, "Axis must be non-negative"); - const int64_t block_size = data_.Shape().SizeFromDimension(gsl::narrow_cast(axis)); - const int64_t num_blocks = size() / block_size; + const size_t block_size = narrow(data_.Shape().SizeFromDimension(gsl::narrow_cast(axis))); + const size_t num_blocks = size() / block_size; ORT_ENFORCE(scalers.size() == 1 || scalers.size() == num_blocks, "Invalid other(scalers) size"); utils::MLTypeCallDispatcher t_disp(data_.GetElementType()); t_disp.Invoke(data_, scalers.data_, block_size, num_blocks); diff --git a/onnxruntime/core/optimizer/initializer.h b/onnxruntime/core/optimizer/initializer.h index 070dd76eeed43..dfe054ba1aced 100644 --- a/onnxruntime/core/optimizer/initializer.h +++ b/onnxruntime/core/optimizer/initializer.h @@ -9,6 +9,7 @@ #include #include "core/common/common.h" +#include "core/common/narrow.h" #include "core/common/path.h" #include "core/framework/allocator.h" #include "core/optimizer/graph_transformer.h" @@ -70,7 +71,7 @@ class Initializer final { return data_.Shape().GetDims(); } - int64_t size() const { return data_.Shape().Size(); } + size_t size() const { return narrow(data_.Shape().Size()); } #if !defined(ORT_EXTENDED_MINIMAL_BUILD) Initializer& add(float value); diff --git a/onnxruntime/core/optimizer/insert_cast_transformer.cc b/onnxruntime/core/optimizer/insert_cast_transformer.cc index 1a7fabdbe7876..7c087ec77d9fe 100644 --- a/onnxruntime/core/optimizer/insert_cast_transformer.cc +++ b/onnxruntime/core/optimizer/insert_cast_transformer.cc @@ -84,9 +84,7 @@ static bool NodeNeedsInputCastToFp32(const onnxruntime::Node& node) { // going to a node that will need a Cast. // // Return true if all the fp16 inputs and outputs are connected to nodes that will be cast to fp32. -static bool IsIsolatedFp16NodeOnCpu(const onnxruntime::Node& node, onnxruntime::Graph& graph) { - bool isolated_fp16_node = false; - +static bool IsIsolatedFp16NodeOnCpu(const onnxruntime::Node& node, onnxruntime::Graph& graph, const KernelRegistry& cpu_kernel_registry) { // we can check if it's an isolated fp16 node // if node has input coming from other nodes (only consuming graph inputs or initializers if it doesn't), // does not have a subgraph (would have to alter subgraph inputs if we cast the input to this node), @@ -96,70 +94,135 @@ static bool IsIsolatedFp16NodeOnCpu(const onnxruntime::Node& node, onnxruntime:: !node.ContainsSubgraph() && !graph.NodeProducesGraphOutput(node) && node.GetExecutionProviderType() == kCpuExecutionProvider) { - do { - // find the number of fp16 inputs as we need to make sure they're all coming from nodes that will be cast - const auto& input_defs = node.InputDefs(); - size_t num_fp16_inputs = std::count_if(input_defs.cbegin(), input_defs.cend(), - [](const NodeArg* input_def) { - return IsMLFloat16Tensor(*input_def); - }); - - if (num_fp16_inputs == 0) { - break; - } + // + // Three tasks here: + // 1. make sure all tensor(float16) inputs and first output coming from or + // going to nodes that will be cast to fp32 + // 2. check the current node is float16 node. + // 3. check the current node has a float32 implementation + // Only return true when all three are satisfied + // + const auto* schema = node.Op(); + if (!schema) { + // no way to know whether it is safe to convert this to fp32, give up + return false; + } - size_t num_fp16_input_edges = 0; + const TypeConstraintMap& type_schema = schema->typeConstraintMap(); + InlinedHashMap type_constraint_map; + type_constraint_map.reserve(type_schema.size()); - // check if all nodes providing our fp16 input need to be cast to fp32 - for (auto input_edge = node.InputEdgesBegin(), end = node.InputEdgesEnd(); input_edge != end; ++input_edge) { - const NodeArg& input_def = *input_defs[input_edge->GetDstArgIndex()]; + // For each formal parameters, there might be 0-n + // actual inputs, this makes it very tricky to find out which + // actual input should map to which formal parameter - if (IsMLFloat16Tensor(input_def)) { - // if the node producing our fp16 input does not need its input cast to fp32 we should run in fp16 - if (!NodeNeedsInputCastToFp32(input_edge->GetNode())) { - break; - } + const auto& input_arg_counts = node.InputArgCount(); + const auto& input_defs = node.InputDefs(); + const auto& formal_inputs = schema->inputs(); + const size_t num_inputs = std::min(formal_inputs.size(), input_arg_counts.size()); + + InlinedHashSet fp16_args; + int input_idx_start = 0; + for (size_t formal_idx = 0; + formal_idx < num_inputs; + input_idx_start += input_arg_counts[formal_idx], formal_idx++) { + const auto& type_str = formal_inputs[formal_idx].GetTypeStr(); + TypeConstraintMap::const_iterator it = type_schema.find(type_str); + if (it == type_schema.end()) { + // Don't care about parameter that does not have a type constraint. + continue; + } - ++num_fp16_input_edges; + // type_str is like T, T1 or T2 ... + for (int input_idx = 0; input_idx < input_arg_counts[formal_idx]; input_idx++) { + const size_t idx = static_cast(input_idx_start) + static_cast(input_idx); + ORT_ENFORCE(idx < input_defs.size()); + const NodeArg* input_def = input_defs[idx]; + if (!input_def || !input_def->Exists()) { + continue; + } + if (IsMLFloat16Tensor(*input_def)) { + fp16_args.emplace(static_cast(idx)); + type_constraint_map[type_str] = DataTypeImpl::GetTensorType(); + break; // we don't have multiple tensors feeding into one input } + type_constraint_map[type_str] = DataTypeImpl::TypeFromProto(*(input_def->TypeAsProto())); + break; // we don't have multiple tensors feeding into one input } + } + + if (fp16_args.empty()) { + return false; + } - // one or more fp16 inputs are coming from a graph input or initializer - if (num_fp16_inputs != num_fp16_input_edges) { - break; + // check if all nodes providing our fp16 input need to be cast to fp32 + for (auto input_edge = node.InputEdgesBegin(), end = node.InputEdgesEnd(); input_edge != end; ++input_edge) { + const int arg_idx = input_edge->GetDstArgIndex(); + if (fp16_args.find(arg_idx) != fp16_args.end()) { + // if the node producing our fp16 input does not need its input cast to fp32 we should run in fp16 + if (!NodeNeedsInputCastToFp32(input_edge->GetNode())) { + return false; + } } + } - // if we got here all nodes providing our fp16 input/s will be cast to fp32. - // check if the same applies to all nodes consuming our fp16 output. + // if we got here all nodes providing our fp16 input/s will be cast to fp32. + // check if the same applies to the nodes consuming our fp16 output. + fp16_args.clear(); + const auto& output_defs = node.OutputDefs(); + const auto& formal_outputs = schema->outputs(); + const size_t num_outputs = std::min(formal_outputs.size(), output_defs.size()); + for (size_t idx = 0; idx < num_outputs; idx++) { + const auto& type_str = formal_outputs[idx].GetTypeStr(); + TypeConstraintMap::const_iterator it = type_schema.find(type_str); + if (it == type_schema.end()) { + // Don't care about parameter that does not have a type constraint. + continue; + } - bool node_has_fp16_output = false; + const NodeArg* output_def = output_defs[idx]; + if (!output_def || !output_def->Exists()) { + continue; + } + if (IsMLFloat16Tensor(*output_def)) { + fp16_args.emplace((int)idx); + type_constraint_map[type_str] = DataTypeImpl::GetTensorType(); + } else { + type_constraint_map[type_str] = DataTypeImpl::TypeFromProto(*(output_def->TypeAsProto())); + } + } - for (auto output_edge = node.OutputEdgesBegin(), end = node.OutputEdgesEnd(); output_edge != end; ++output_edge) { - const NodeArg& output_def = *node.OutputDefs()[output_edge->GetSrcArgIndex()]; - if (IsMLFloat16Tensor(output_def)) { - node_has_fp16_output = true; + if (fp16_args.empty()) { + return false; // no fp16 output + } - // if the node consuming our fp16 output does not need a cast, we should run in fp16 - if (!NodeNeedsInputCastToFp32(output_edge->GetNode())) { - break; - } + for (auto output_edge = node.OutputEdgesBegin(), end = node.OutputEdgesEnd(); output_edge != end; ++output_edge) { + const int arg_idx = output_edge->GetSrcArgIndex(); + if (fp16_args.find(arg_idx) != fp16_args.end()) { + // if the node producing our fp16 input does not need its input cast to fp32 we should run in fp16 + if (!NodeNeedsInputCastToFp32(output_edge->GetNode())) { + return false; } } + } - if (node_has_fp16_output) { - // all nodes providing our fp16 input/s will be cast to fp32, and - // we produce one or more fp16 outputs, and all nodes consuming those outputs will be cast to fp32 - isolated_fp16_node = true; - } - } while (false); + // now all fp16 inputs and outputs would have a cast + // make sure fp32 version of the kernel is available. + const KernelCreateInfo* kernel_create_info{}; + const auto lookup_status = cpu_kernel_registry.TryFindKernel( + kCpuExecutionProvider, node.OpType(), node.Domain(), + node.SinceVersion(), type_constraint_map, &kernel_create_info); + if (lookup_status.IsOK() && kernel_create_info != nullptr) { + return true; + } } - return isolated_fp16_node; + return false; } -Status ForceSingleNodeCPUFloat16ToFloat32(onnxruntime::Graph& graph) { +static Status ForceSingleNodeCPUFloat16ToFloat32(onnxruntime::Graph& graph, const KernelRegistry& cpu_kernel_registry) { for (auto& node : graph.Nodes()) { - if (IsIsolatedFp16NodeOnCpu(node, graph)) { + if (IsIsolatedFp16NodeOnCpu(node, graph, cpu_kernel_registry)) { // unassign the node so that NeedInsertCast will return true for it, forcing it to fp32 node.SetExecutionProviderType(""); } @@ -338,7 +401,7 @@ class RemoveDuplicateCastTransformer : public GraphTransformer { Status InsertCastTransformer::ApplyImpl(onnxruntime::Graph& graph, bool& modified, int graph_level, const logging::Logger& logger) const { if (force_cpu_fp32_) - ORT_RETURN_IF_ERROR(ForceSingleNodeCPUFloat16ToFloat32(graph)); + ORT_RETURN_IF_ERROR(ForceSingleNodeCPUFloat16ToFloat32(graph, *cpu_kernel_registries_)); GraphViewer graph_viewer(graph); auto& order = graph_viewer.GetNodesInTopologicalOrder(); diff --git a/onnxruntime/core/optimizer/insert_cast_transformer.h b/onnxruntime/core/optimizer/insert_cast_transformer.h index 86d3a3a960f0b..8be08d51585cf 100644 --- a/onnxruntime/core/optimizer/insert_cast_transformer.h +++ b/onnxruntime/core/optimizer/insert_cast_transformer.h @@ -6,6 +6,8 @@ #include "core/graph/graph_viewer.h" #include "core/framework/op_kernel.h" #include "core/optimizer/graph_transformer.h" +#include "core/framework/kernel_registry_manager.h" +#include "core/framework/kernel_registry.h" namespace onnxruntime { @@ -16,19 +18,26 @@ Transformer to insert cast node that casts float16 to float for cpu nodes */ class InsertCastTransformer : public onnxruntime::GraphTransformer { public: - InsertCastTransformer(const std::string& name) + /** + * @brief Initializer + * @param name for logging purpose + * @param cpu_kernel_registry used to query whether an op node can be safely created + */ + InsertCastTransformer(const std::string& name, const KernelRegistry* cpu_kernel_registry) : onnxruntime::GraphTransformer(name), - force_cpu_fp32_(true) { - } + cpu_kernel_registries_(cpu_kernel_registry), + force_cpu_fp32_(cpu_kernel_registry != nullptr) {} private: Status ApplyImpl(onnxruntime::Graph& graph, bool& modified, int graph_level, const logging::Logger& logger) const override; bool NeedInsertCast(const onnxruntime::Node* node, const onnxruntime::NodeArg* input) const; + const KernelRegistry* cpu_kernel_registries_; + // Currently because we only have very few cpu kernels support float16, place those nodes on float16 // will introduce many cast between fp32 and fp16, which will slow the execution. // A better solution is to have a cost model to evaluate does it works to place the node on float16. // Here for simplify, we only force the single-node-float16 sub-graph to float32 - bool force_cpu_fp32_; + const bool force_cpu_fp32_; }; } // namespace onnxruntime diff --git a/onnxruntime/core/optimizer/isinf_reducesum_fusion.cc b/onnxruntime/core/optimizer/isinf_reducesum_fusion.cc index 58bf17ed591d7..bc0523d517ee6 100644 --- a/onnxruntime/core/optimizer/isinf_reducesum_fusion.cc +++ b/onnxruntime/core/optimizer/isinf_reducesum_fusion.cc @@ -45,7 +45,7 @@ Status IsInfReduceSumFusion::ApplyImpl(Graph& graph, bool& modified, int graph_l // This Cast can be skipped as we are replacing the subgraph with IsAllFinite, which supports FP16 auto cast1_node_iter = isinf_node.InputNodesBegin(); if (cast1_node_iter != isinf_node.InputNodesEnd() && - graph_utils::IsSupportedOptypeVersionAndDomain(*cast1_node_iter, "Cast", {9, 13}) && + graph_utils::IsSupportedOptypeVersionAndDomain(*cast1_node_iter, "Cast", {9, 13, 19}) && cast1_node_iter->GetOutputEdgesCount() == 1) { // check input type of cast node Node& cast1_node = *graph.GetNode(cast1_node_iter->Index()); @@ -65,7 +65,7 @@ Status IsInfReduceSumFusion::ApplyImpl(Graph& graph, bool& modified, int graph_l } Node& cast2_node = *graph.GetNode(cast2_node_itr->Index()); - if (!graph_utils::IsSupportedOptypeVersionAndDomain(cast2_node, "Cast", {9, 13}) || + if (!graph_utils::IsSupportedOptypeVersionAndDomain(cast2_node, "Cast", {9, 13, 19}) || cast2_node.GetOutputEdgesCount() != 1 || graph.NodeProducesGraphOutput(cast2_node)) { continue; diff --git a/onnxruntime/core/optimizer/layer_norm_fusion.cc b/onnxruntime/core/optimizer/layer_norm_fusion.cc index 9bbb3c4d576ed..159e3b23d1ab0 100644 --- a/onnxruntime/core/optimizer/layer_norm_fusion.cc +++ b/onnxruntime/core/optimizer/layer_norm_fusion.cc @@ -4,8 +4,8 @@ #include "core/optimizer/layer_norm_fusion.h" #include "core/graph/graph_utils.h" #include "core/optimizer/utils.h" -#include "core/optimizer/transpose_optimizer/optimizer_api.h" #include "float.h" +#include #include using namespace ONNX_NAMESPACE; @@ -32,6 +32,52 @@ static bool IsSupportedDataType(const Node& node, int first_n_inputs = -1) { return true; } +static bool CheckAxesOnReduceMean(std::vector& axes_values, int64_t rank) { + // axes has be to be consecutive and constains the last dim. + std::sort(axes_values.begin(), axes_values.end()); + if (axes_values.back() > 0) { + // if reduce_mean node has input shape [N, C1, C2, C3] and axes_values = [1, 2], it's invalid. + // handle axes_values with both positive and negative values. + if (rank == -1) { + return false; + } + std::transform(axes_values.begin(), axes_values.end(), axes_values.begin(), + [rank](int64_t v) { return v >= 0 ? v - rank : v; }); + std::sort(axes_values.begin(), axes_values.end()); + } + // check if axes are consecutive + for (size_t i = 1; i < axes_values.size(); i++) { + if (axes_values[i] != axes_values[i - 1] + 1) { + axes_values.clear(); + break; + } + } + + if (axes_values.empty() || axes_values.back() != -1) { + // axes_values should contain the last dim. + return false; + } + return true; +} + +static std::vector GetAxesFromReduceMeanNode(Node& reduce_mean_node, const Graph& graph) { + const onnxruntime::NodeAttributes& attributes = reduce_mean_node.GetAttributes(); + std::vector axes_values; + // TODO: modify this codes when opset >= 18 (axes is an input). + if (attributes.find("axes") != attributes.end()) { + axes_values = RetrieveValues(attributes.at("axes")); + } else if (reduce_mean_node.InputDefs().size() == 2) { + const auto* axes = reduce_mean_node.InputDefs()[1]; + const auto* axes_const = graph.GetConstantInitializer(axes->Name(), true); + if (axes_const != nullptr) { + Initializer initializer{*axes_const, graph.ModelPath()}; + auto span_axes = initializer.DataAsSpan(); + axes_values.insert(axes_values.end(), span_axes.begin(), span_axes.end()); + } + } + return axes_values; +}; + /** Layer Normalization will fuse LayerNormalization into one node : +---------------------+ @@ -180,7 +226,7 @@ Status LayerNormFusion::ApplyImpl(Graph& graph, bool& modified, int graph_level, if (p_reduce_mean_input_node) { Node& reduce_mean_input_node = *graph.GetNode(p_reduce_mean_input_node->Index()); // If input to the 1st ReduceMean is a Cast, and the Cast has same consumer count as subCnt + 1 - if (graph_utils::IsSupportedOptypeVersionAndDomain(reduce_mean_input_node, "Cast", {9, 13}) && + if (graph_utils::IsSupportedOptypeVersionAndDomain(reduce_mean_input_node, "Cast", {9, 13, 19}) && reduce_mean_input_node.GetExecutionProviderType() == reduce_mean_node.GetExecutionProviderType() && optimizer_utils::CheckOutputEdges(graph, reduce_mean_input_node, static_cast(subCnt) + 1)) { nodes_to_remove.insert(nodes_to_remove.begin(), reduce_mean_input_node); @@ -193,7 +239,7 @@ Status LayerNormFusion::ApplyImpl(Graph& graph, bool& modified, int graph_level, const Node* p_cast1 = nullptr; if (!p_sub_node_dup && sub_node.GetOutputEdgesCount() == 1) { Node& cast_node = *graph.GetNode(sub_node.OutputNodesBegin()->Index()); - if (graph_utils::IsSupportedOptypeVersionAndDomain(cast_node, "Cast", {9, 13}) && + if (graph_utils::IsSupportedOptypeVersionAndDomain(cast_node, "Cast", {9, 13, 19}) && cast_node.GetExecutionProviderType() == reduce_mean_node.GetExecutionProviderType() && optimizer_utils::CheckOutputEdges(graph, cast_node, 2u) && IsSupportedDataType(cast_node)) { p_cast1 = &cast_node; @@ -292,7 +338,7 @@ Status LayerNormFusion::ApplyImpl(Graph& graph, bool& modified, int graph_level, const Node* p_cast2 = graph_utils::FirstParentByType(pow_node, "Cast"); if (p_cast2 != nullptr && p_cast2 != p_cast1) { Node& cast_node = *graph.GetNode(p_cast2->Index()); - if (!graph_utils::IsSupportedOptypeVersionAndDomain(cast_node, "Cast", {9, 13}) || + if (!graph_utils::IsSupportedOptypeVersionAndDomain(cast_node, "Cast", {9, 13, 19}) || cast_node.GetExecutionProviderType() != reduce_mean_node.GetExecutionProviderType() || !optimizer_utils::CheckOutputEdges(graph, cast_node, 1)) { continue; @@ -310,7 +356,7 @@ Status LayerNormFusion::ApplyImpl(Graph& graph, bool& modified, int graph_level, // can be removed. This is one possible place a Cast Op can exist, that is between Div and Mul nodes. // div --> mul or div --> cast --> mul Node* next_node = graph.GetNode(div_node.OutputNodesBegin()->Index()); - if (graph_utils::IsSupportedOptypeVersionAndDomain(*next_node, "Cast", {9, 13}) && + if (graph_utils::IsSupportedOptypeVersionAndDomain(*next_node, "Cast", {9, 13, 19}) && optimizer_utils::CheckOutputEdges(graph, *next_node, 1)) { nodes_to_remove.push_back(*next_node); next_node = graph.GetNode(next_node->OutputNodesBegin()->Index()); @@ -337,56 +383,51 @@ Status LayerNormFusion::ApplyImpl(Graph& graph, bool& modified, int graph_level, nodes_to_remove.push_back(last_add_node); // get axes attributes - const onnxruntime::NodeAttributes& attributes = reduce_mean_node.GetAttributes(); - std::vector axes_values; - // TODO: modify this codes when opset >= 18 (axes is an input). - if (attributes.find("axes") != attributes.end()) { - axes_values = RetrieveValues(attributes.at("axes")); - } else if (reduce_mean_node.InputDefs().size() == 2) { - auto axes = reduce_mean_node.InputDefs()[1]; - auto axes_const = graph.GetConstantInitializer(axes->Name(), true); - if (axes_const != nullptr) { - Initializer initializer{*axes_const, graph.ModelPath()}; - axes_values.insert(axes_values.end(), initializer.DataAsSpan().begin(), initializer.DataAsSpan().end()); - } + + auto axes_values = GetAxesFromReduceMeanNode(reduce_mean_node, graph); + auto axes2_values = GetAxesFromReduceMeanNode(reduce_mean2_node, graph); + + // empty axes means reduce over all axes, which is not supported on layer-norm + if (axes_values.empty() || axes2_values.empty()) { + continue; + } + + auto input_shape = reduce_mean_node.MutableInputDefs()[0]->Shape(); + auto rank = input_shape ? input_shape->dim().size() : -1; + if (!CheckAxesOnReduceMean(axes_values, rank) || + !CheckAxesOnReduceMean(axes2_values, rank) || + axes_values != axes2_values) { + continue; } +#ifdef ENABLE_TRAINING_CORE +#else + // scale as 1D + if (axes_values.size() != 1) { + continue; + } +#endif + // Get the inputs for the new LayerNormalization node. // scale and bias could be multi-dims; we only support it for training at the moment // because SkipLayerNorm kernel, for example, has dependency on single dim size NodeArg* scale = nullptr; NodeArg* bias = nullptr; for (size_t i = 0; i < mul_node.MutableInputDefs().size(); i++) { - if (graph_utils::NodeArgIsConstant(graph, *(mul_node.MutableInputDefs()[i])) || - graph_utils::IsGraphInput(graph, mul_node.MutableInputDefs()[i])) { -#ifdef ENABLE_TRAINING_CORE - if (axes_values.empty() || - mul_node.MutableInputDefs()[i]->Shape()->dim_size() == static_cast(axes_values.size())) { - scale = mul_node.MutableInputDefs()[i]; - } -#else - // Scale must be 1d. - if (mul_node.MutableInputDefs()[i]->Shape()->dim_size() == 1) { - scale = mul_node.MutableInputDefs()[i]; - } -#endif + if (mul_node.MutableInputDefs()[i]->Shape() == nullptr) { + continue; + } + if (mul_node.MutableInputDefs()[i]->Shape()->dim_size() == static_cast(axes_values.size())) { + scale = mul_node.MutableInputDefs()[i]; } } for (size_t i = 0; i < last_add_node.MutableInputDefs().size(); i++) { - if (graph_utils::NodeArgIsConstant(graph, *(last_add_node.MutableInputDefs()[i])) || - graph_utils::IsGraphInput(graph, last_add_node.MutableInputDefs()[i])) { -#ifdef ENABLE_TRAINING_CORE - if (axes_values.empty() || - last_add_node.MutableInputDefs()[i]->Shape()->dim_size() == static_cast(axes_values.size())) { - bias = last_add_node.MutableInputDefs()[i]; - } -#else - // Bias must be 1d. - if (last_add_node.MutableInputDefs()[i]->Shape()->dim_size() == 1) { - bias = last_add_node.MutableInputDefs()[i]; - } -#endif + if (last_add_node.MutableInputDefs()[i]->Shape() == nullptr) { + continue; + } + if (last_add_node.MutableInputDefs()[i]->Shape()->dim_size() == static_cast(axes_values.size())) { + bias = last_add_node.MutableInputDefs()[i]; } } if (scale == nullptr || bias == nullptr) { @@ -423,6 +464,9 @@ Status LayerNormFusion::ApplyImpl(Graph& graph, bool& modified, int graph_level, layer_norm_node.AddAttribute("epsilon", DEFAULT_LAYERNORM_EPSILON); } + // The axis definition of layer_norm is ranging from axis to the last dim + layer_norm_node.AddAttribute("axis", static_cast(axes_values[0])); + // Set stash_type to double if any input is double, default value if float. if (x_input->TypeAsProto()->tensor_type().elem_type() == ONNX_NAMESPACE::TensorProto_DataType_DOUBLE || scale->TypeAsProto()->tensor_type().elem_type() == ONNX_NAMESPACE::TensorProto_DataType_DOUBLE) { @@ -573,7 +617,7 @@ Status SimplifiedLayerNormFusion::ApplyImpl(Graph& graph, bool& modified, int gr if (is_gpu_ep && p_pow_input_node) { Node& pow_input_node = *graph.GetNode(p_pow_input_node->Index()); // If input to Pow is a Cast, and the Cast has 2 consumers only (Pow, Div) - if (graph_utils::IsSupportedOptypeVersionAndDomain(pow_input_node, "Cast", {9, 13}) && + if (graph_utils::IsSupportedOptypeVersionAndDomain(pow_input_node, "Cast", {9, 13, 19}) && pow_input_node.GetExecutionProviderType() == pow_node.GetExecutionProviderType() && optimizer_utils::CheckOutputEdges(graph, pow_input_node, 2)) { nodes_to_remove.insert(nodes_to_remove.begin(), pow_input_node); @@ -583,7 +627,7 @@ Status SimplifiedLayerNormFusion::ApplyImpl(Graph& graph, bool& modified, int gr // div --> mul or div --> cast --> mul Node* next_node = graph.GetNode(div_node.OutputNodesBegin()->Index()); - if (graph_utils::IsSupportedOptypeVersionAndDomain(*next_node, "Cast", {9, 13}) && + if (graph_utils::IsSupportedOptypeVersionAndDomain(*next_node, "Cast", {9, 13, 19}) && optimizer_utils::CheckOutputEdges(graph, *next_node, 1)) { if (!is_gpu_ep) continue; nodes_to_remove.push_back(*next_node); @@ -598,38 +642,45 @@ Status SimplifiedLayerNormFusion::ApplyImpl(Graph& graph, bool& modified, int gr nodes_to_remove.push_back(mul_node); // get axes attributes - const onnxruntime::NodeAttributes& attributes = reduce_mean_node.GetAttributes(); - std::vector axes_values; - if (attributes.find("axes") != attributes.end()) { - axes_values = RetrieveValues(attributes.at("axes")); - } else if (reduce_mean_node.InputDefs().size() == 2) { - auto axes = reduce_mean_node.InputDefs()[1]; - auto axes_const = graph.GetConstantInitializer(axes->Name(), true); - if (axes_const != nullptr && axes_const->data_type() == ONNX_NAMESPACE::TensorProto_DataType_INT64) { - Initializer initializer{*axes_const, graph.ModelPath()}; - axes_values.insert(axes_values.end(), initializer.DataAsSpan().begin(), initializer.DataAsSpan().end()); - } + std::vector axes_values = GetAxesFromReduceMeanNode(reduce_mean_node, graph); + + if (axes_values.empty()) { + continue; + } + + auto rmean_input_shape = reduce_mean_node.MutableInputDefs()[0]->Shape(); + auto rank = rmean_input_shape ? rmean_input_shape->dim().size() : -1; + if (!CheckAxesOnReduceMean(axes_values, rank)) { + continue; + } + +#ifdef ENABLE_TRAINING_CORE +#else + // scale as 1D + if (axes_values.size() != 1) { + continue; } +#endif // Get the inputs for the new LayerNormalization node. // scale and bias could be multi-dims; we only support it for training at the moment // because SkipLayerNorm kernel, for example, has dependency on single dim size NodeArg* scale = nullptr; for (size_t i = 0; i < mul_node.MutableInputDefs().size(); i++) { - if (graph_utils::NodeArgIsConstant(graph, *(mul_node.MutableInputDefs()[i])) || - graph_utils::IsGraphInput(graph, mul_node.MutableInputDefs()[i])) { + if (mul_node.MutableInputDefs()[i]->Shape() == nullptr) { + continue; + } #ifdef ENABLE_TRAINING_CORE - if (axes_values.empty() || - mul_node.MutableInputDefs()[i]->Shape()->dim_size() == static_cast(axes_values.size())) { - scale = mul_node.MutableInputDefs()[i]; - } + if (axes_values.empty() || + mul_node.MutableInputDefs()[i]->Shape()->dim_size() == static_cast(axes_values.size())) { + scale = mul_node.MutableInputDefs()[i]; + } #else - // Scale must be 1d. - if (mul_node.MutableInputDefs()[i]->Shape()->dim_size() == 1) { - scale = mul_node.MutableInputDefs()[i]; - } -#endif + // Scale must be 1d. + if (mul_node.MutableInputDefs()[i]->Shape()->dim_size() == 1) { + scale = mul_node.MutableInputDefs()[i]; } +#endif } if (scale == nullptr) { @@ -659,6 +710,8 @@ Status SimplifiedLayerNormFusion::ApplyImpl(Graph& graph, bool& modified, int gr layer_norm_node.AddAttribute("stash_type", static_cast(ONNX_NAMESPACE::TensorProto_DataType_DOUBLE)); } + layer_norm_node.AddAttribute("axis", static_cast(axes_values[0])); + // Assign provider to this new node. Provider should be same as the provider for old node. layer_norm_node.SetExecutionProviderType(reduce_mean_node.GetExecutionProviderType()); diff --git a/onnxruntime/core/optimizer/layout_transformation/layout_transformation.cc b/onnxruntime/core/optimizer/layout_transformation/layout_transformation.cc new file mode 100644 index 0000000000000..2d12c407e6e31 --- /dev/null +++ b/onnxruntime/core/optimizer/layout_transformation/layout_transformation.cc @@ -0,0 +1,195 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// The ONNX Runtime specific implementation of the generic transpose optimizer API. + +#include "core/optimizer/layout_transformation/layout_transformation.h" + +#include "core/common/common.h" +#include "core/optimizer/transpose_optimization/ort_transpose_optimization.h" +#include "core/optimizer/transpose_optimization/ort_optimizer_utils.h" + +using namespace onnx_transpose_optimization; + +namespace onnxruntime { +namespace layout_transformation { + +// Layout sensitive NCHW ops. TransformLayoutForEP will wrap these with Transpose nodes to convert the input +// data to NHWC and output data back to NCHW, and move the op to the internal NHWC domain (kMSInternalNHWCDomain). +// The EP requesting these ops MUST be able to handle the node with the operator in the kMSInternalNHWCDomain. +// Once all the layout sensitive ops requested by the EP are wrapped the transpose optimizer will attempt to remove +// as many of the layout transposes as possible. +const std::unordered_set& GetORTLayoutSensitiveOps() { + static std::unordered_set ort_layout_sensitive_ops = []() { + const auto& layout_sensitive_ops = onnx_transpose_optimization::GetLayoutSensitiveOps(); + std::unordered_set ort_specific_ops = + { "FusedConv", + "QLinearAveragePool", + "QLinearGlobalAveragePool" +#if defined(USE_CUDA) || defined(USE_ROCM) || defined(USE_QNN) || defined(USE_WEBNN) + // The CUDA/ROCM Resize kernel is layout sensitive as it only handles NCHW input. + // The CPU kernel and ONNX spec are not limited to handling NCHW input so are not layout sensitive, and + // onnx_layout_transformation::HandleResize is used. + , + "Resize" +#endif + }; + + ort_specific_ops.insert(layout_sensitive_ops.cbegin(), layout_sensitive_ops.cend()); + return ort_specific_ops; + }(); + + return ort_layout_sensitive_ops; +} + +// Cost check for aggressively pushing the Transpose nodes involved in the layout transformation further out. +static CostCheckResult +PostLayoutTransformCostCheck(const api::GraphRef& graph, const api::NodeRef& node, + const std::vector& perm, + const std::unordered_set& outputs_leading_to_transpose) { + // we aggressively push the layout transpose nodes. + // Exception: pushing through a Concat can result in Transpose nodes being added to multiple other inputs which + // can potentially be worse for performance. Use the cost check in that case. + if (node.OpType() != "Concat" && + (perm == ChannelFirstToLastPerm(perm.size()) || perm == ChannelLastToFirstPerm(perm.size()))) { + return CostCheckResult::kPushTranspose; + } + + // for other nodes use the default ORT cost check + return OrtEPCostCheck(graph, node, perm, outputs_leading_to_transpose); +} + +Status TransformLayoutForEP(Graph& graph, bool& modified, const IExecutionProvider& execution_provider, + AllocatorPtr cpu_allocator, + const DebugGraphFn& debug_graph_fn) { + // We pass in nullptr for the new_node_ep param as new nodes will be assigned by the graph partitioner after + // TransformLayoutForEP returns. + // sub graph recurse will be added later. + auto api_graph = MakeApiGraph(graph, cpu_allocator, /*new_node_ep*/ nullptr); + const auto& layout_sensitive_ops = GetORTLayoutSensitiveOps(); + + // to convert to NHWC we need to wrap layout sensitive nodes to Transpose from NCHW to NHWC and back. + for (auto& node : api_graph->Nodes()) { + if (layout_sensitive_ops.count(node->OpType())) { + if (node->GetExecutionProviderType() != execution_provider.Type()) { + continue; + } + + auto domain = node->Domain(); + // Skip if domain is incorrect + if (domain != kOnnxDomain && domain != kMSDomain) { + continue; + } + + // 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); + // Changing the domain for the node requires creating a new node and replacing the old one + // therefore set the modified flag. + modified = true; + continue; + } + + // Skip if unknown rank + auto shape = api_graph->GetValueInfo(node->Inputs()[0])->Shape(); + if (!shape.has_value()) { + continue; + } + + // Convert to channels last + size_t rank = shape->size(); + + bool has_channel_last_attr = node->GetAttributeInt("channels_last").has_value() ? true : false; + if (has_channel_last_attr) { + node->SetAttributeInt("channels_last", 1); + } + + auto input_perm = onnx_transpose_optimization::ChannelFirstToLastPerm(rank); + auto output_perm = onnx_transpose_optimization::ChannelLastToFirstPerm(rank); + + // 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") { + // 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. + // + // Current code skips layout conversion for ROI because it needs special handling as ROI size is 2*rank. + // Enable passing in ROI for layout conversion when an EP which supports ROI starts using layout transformer. + // NNAPI which currently uses layout transformer does not support it. + std::vector*> input_perms{&input_perm, nullptr}; + for (size_t i = 2; i < node->Inputs().size(); i++) { + auto constant = api_graph->GetConstant(node->Inputs()[i]); + if (constant != nullptr && constant->Data().size() > 0) { + input_perms.push_back(&input_perm); + } else { + // TODO: Fix inconsistency. We should Transpose the non-const inputs so that the result of our changes + // is consistent - all layout specific inputs are in NHWC format when we're done. + // This may need to check the opset to see if it's safe so that an empty non-constant input doesn't + // have an invalid Transpose added to it. + // Caveat: Typically `scales` and `sizes` are constants so this may not happen in a production model. + input_perms.push_back(nullptr); + } + } + WrapTransposesAroundNode(*api_graph, *node, input_perms, {&output_perm}); + } else { + WrapTransposesAroundNode(*api_graph, *node, {&input_perm}, {&output_perm}); + } + + // TODO: Technically Resize doesn't need to change domain as the ONNX Resize spec is not layout sensitive. + SwapNodeOpTypeAndDomain(*api_graph, *node, node->OpType(), kMSInternalNHWCDomain); + modified = true; + } + } + + // debug the changes made inserting Transpose nodes around layout sensitive ops. + if (debug_graph_fn) { + debug_graph_fn(graph); + } + + const auto max_node_idx = graph.MaxNodeIndex(); + OptimizeResult result = onnx_transpose_optimization::Optimize(*api_graph, execution_provider.Type(), + PostLayoutTransformCostCheck, OrtExtendedHandlers()); + + if (result.error_msg) { + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Layout/Transpose optimization for ", execution_provider.Type(), + " failed: ", result.error_msg.value()); + } + + modified = modified || (graph.MaxNodeIndex() > max_node_idx); + + // debug transpose optimization for the current EP + if (modified && debug_graph_fn) { + debug_graph_fn(graph); + } + + return Status::OK(); +} + +bool IsSupportedOpset(const Graph& graph) { + const auto& version_map = graph.DomainToVersionMap(); + const auto& onnx_version = version_map.find(kOnnxDomain); + return (onnx_version != version_map.end() && + onnx_version->second >= onnx_transpose_optimization::kMinSupportedOpset && + onnx_version->second <= kMaxSupportedOpset); +} + +void WrapTransposesAroundNode(api::GraphRef& graph, api::NodeRef& node, + const std::vector*>& input_perms, + const std::vector*>& output_perms) { + for (size_t i = 0; i < input_perms.size(); ++i) { + const std::vector* input_perm = input_perms[i]; + if (input_perm != nullptr) { + TransposeInput(graph, node, i, *input_perm, InvertPerm(*input_perm)); + } + } + for (size_t i = 0; i < output_perms.size(); ++i) { + const std::vector* output_perm = output_perms[i]; + if (output_perm != nullptr) { + TransposeOutput(graph, node, i, *output_perm, InvertPerm(*output_perm)); + } + } +} +} // namespace layout_transformation +} // namespace onnxruntime diff --git a/onnxruntime/core/optimizer/layout_transformation/layout_transformation.h b/onnxruntime/core/optimizer/layout_transformation/layout_transformation.h new file mode 100644 index 0000000000000..23971975ecc3e --- /dev/null +++ b/onnxruntime/core/optimizer/layout_transformation/layout_transformation.h @@ -0,0 +1,97 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +#pragma once + +/* Layout Transformation Tools + * These methods help change the channel ordering of layout sensitive ops (like Conv). ONNX currently only supports + * channel first ordering for ops, so this requires changing the op type and domain to a contrib op supporting + * the new ordering. The existence of a robust transpose optimizer means that we can freely add transpose ops during + * conversion and then call Optimize to remove as many as possible. To change the channel ordering of some/all ops + * in a model, a user of this tool should do the following: + * + * 1. Iterate over the graph nodes and identify nodes to convert. For each one: + * a. Change the op type and domain (and possibly attributes) to the op/contrib op with the desired ordering. + * b. The model is now invalid since the input tensors are in the original ordering (and all consumers + * expect the original ordering). Use WrapTransposesAroundNode helper to insert transposes around the + * inputs/outputs of the op to correct this. + * 2. The model is now correct but has many unnecessary Transpose ops. Call Optimize on the graph. + * + * After step 1, the Transpose ops will wrap converted ops in a similar manner to q/dq ops in quantization. + * The perm attributes essentially encode the information about which ops are being reordered. + */ + +#include "core/common/status.h" +#include "core/framework/allocator.h" +#include "core/framework/transform_layout_functions.h" +#include "core/optimizer/transpose_optimization/ort_transpose_optimization.h" + +namespace onnxruntime { +class Graph; +class IExecutionProvider; + +namespace layout_transformation { +///

+/// Transforms data layout to the EPs preferred layout and runs the transpose optimizer for nodes assigned to the EP. +/// When converting from NCHW to NHWC uses the kMSInternalNHWCDomain domain for updated nodes. +/// +/// This can be used by a compiling EP such as NNAPI, where the synthetic domain is a signal that the node has been +/// updated to the EP's required layout, or an EP with statically registered kernels such as XNNPACK where a kernel +/// is registered for the NHWC version of an ONNX operator. The NHWC version of the ONNX operator uses the synthetic +/// domain and is defined by onnxruntime/core/graph/contrib_ops/internal_nhwc_onnx_opset.cc +/// +/// Transforms are applied to layout sensitive nodes assigned to execution_provider provided by the caller, +/// and any other non-layout sensitive nodes in order to optimize the transposes as much as possible. +/// +/// We call this for all EPs as transpose optimization for a Transpose -> Resize combination is EP specific so must +/// run after the node is assigned to an EP. +/// +/// graph to transform +/// indicates whether the graph is modified during transformation +/// execution provider for which the transformation needs to be performed +/// a CPU allocator used in layout transformation. +/// Optional functor to debug the graph produced during layout transformation. +/// This is called after layout transformation if new nodes are inserted, and again after those are optimized. +/// +Status TransformLayoutForEP(onnxruntime::Graph& graph, bool& modified, + const onnxruntime::IExecutionProvider& execution_provider, + onnxruntime::AllocatorPtr cpu_allocator, + const onnxruntime::layout_transformation::DebugGraphFn& debug_graph_fn = {}); + +/// +/// Checks if the opset of the Graph is supported by the layout transformer. +/// +/// Graph to check +/// +bool IsSupportedOpset(const Graph& graph); + +/// +/// Gets a list of layout sensitive ops for ORT. This list contains ONNX standard defined +/// layout sensitive ops + contrib ops + ops which are not layout sensitive but are treated as +/// layout sensitive by ORT EPs (example Resize). +/// +/// unordered set of op_types which are layout sensitive +const std::unordered_set& GetORTLayoutSensitiveOps(); + +/// +/// Inserts transposes around op inputs/outputs. Alternatively transposes initializers or uses existing Transpose +/// nodes if possible. Populates shape information on affected node inputs/outputs to reflect the change. +/// +/// Ex: +/// * -> NhwcConv -> ** +/// becomes +/// * -> Transpose -> NhwcConv -> Transpose -> ** +/// Conv inputs/outputs have new shape. Shapes of * and ** are unchanged (carrying NCHW data). +/// +/// input_perms/output_perms are matched with node inputs/outputs positionally. Their lengths must be at most equal to +/// the number of inputs/outputs, respectively. nullptr entries indicate an input or output should not be transposed. +/// +/// Graph containing the node +/// Node to modify +/// Input permutations. nullptr entries indicate to skip corresponding input. +/// Output permutations. nullptr entries indicate to skip corresponding output. +void WrapTransposesAroundNode(onnx_transpose_optimization::api::GraphRef& graph, + onnx_transpose_optimization::api::NodeRef& node, + const std::vector*>& input_perms, + const std::vector*>& output_perms); +} // namespace layout_transformation +} // namespace onnxruntime diff --git a/onnxruntime/core/optimizer/transpose_optimizer/layout_tranformer_dev_notes.md b/onnxruntime/core/optimizer/layout_transformation/layout_transformation_dev_notes.md similarity index 100% rename from onnxruntime/core/optimizer/transpose_optimizer/layout_tranformer_dev_notes.md rename to onnxruntime/core/optimizer/layout_transformation/layout_transformation_dev_notes.md diff --git a/onnxruntime/core/optimizer/transpose_optimizer/layout_transformation_potentially_added_ops.h b/onnxruntime/core/optimizer/layout_transformation/layout_transformation_potentially_added_ops.h similarity index 100% rename from onnxruntime/core/optimizer/transpose_optimizer/layout_transformation_potentially_added_ops.h rename to onnxruntime/core/optimizer/layout_transformation/layout_transformation_potentially_added_ops.h diff --git a/onnxruntime/core/optimizer/nhwc_transformer.cc b/onnxruntime/core/optimizer/nhwc_transformer.cc index 29c8de161aa76..e67557dcf9391 100644 --- a/onnxruntime/core/optimizer/nhwc_transformer.cc +++ b/onnxruntime/core/optimizer/nhwc_transformer.cc @@ -2,18 +2,170 @@ // Licensed under the MIT License. #include +#include "core/mlas/inc/mlas.h" #include "core/graph/graph_utils.h" #include "core/optimizer/initializer.h" #include "core/optimizer/nhwc_transformer.h" #include "core/optimizer/utils.h" -#include "core/optimizer/transpose_optimizer/optimizer_utils.h" +#include "core/optimizer/layout_transformation/layout_transformation.h" +#include "core/optimizer/transpose_optimization/ort_optimizer_utils.h" +#include "core/optimizer/transpose_optimization/ort_transpose_optimization.h" using namespace ONNX_NAMESPACE; using namespace ::onnxruntime::common; -using namespace onnx_layout_transformation; +using namespace onnx_transpose_optimization; +using namespace nhwc_map_internal; namespace onnxruntime { +using namespace layout_transformation; + +static inline const OpTransformInfo* +NhwcConvLookup( + const OpTransformMap& conv_table, + const api::GraphRef& graph, + api::NodeRef& node) { + const auto& optype = node.OpType(); + const auto& domain = node.Domain(); + const auto inputs = node.Inputs(); + if (inputs.empty()) { + // node with no input, can't be our transformation candidate. + return nullptr; + } + const auto info = graph.GetValueInfo(inputs[0]); + const api::DataType dtype = info->DType(); + OpIdInfo key{optype, domain, dtype}; + + const auto iter = conv_table.find(key); + if (iter == conv_table.end()) { + return nullptr; + } + return &(iter->second); +} + +NhwcTransformer::NhwcTransformer(AllocatorPtr cpu_allocator, std::shared_ptr cpu_kernel_registry) noexcept + : GraphTransformer("NhwcTransformer"), cpu_allocator_(std::move(cpu_allocator)) { + if (!cpu_kernel_registry) { + // This is a CPU op nodes optimizer, not useful if cpu EP is not available. + return; + } + + // + // Constructing a mapping table from operators to be transformed to their target. + // Make sure that the new nodes we are about to create during graph transformation, + // their kernels are available in the cpu EP. + // + + { + // int8 qconv -> int8 nhwc qconv + OpKernelRegistryId qconv_int8{ + "QLinearConv", kMSDomain, 1, {{"T1", {DataTypeImpl::GetTensorType()}}}}; + const KernelCreateInfo* kernel_create_info{}; + const auto status = cpu_kernel_registry->TryFindKernel( + kCpuExecutionProvider, qconv_int8.op_type_, qconv_int8.domain_, + qconv_int8.version_, qconv_int8.type_constraints_, &kernel_create_info); + if (status.IsOK() && kernel_create_info != nullptr) { + kernel_create_info = nullptr; + conv_table_.emplace( + OpIdInfo("QLinearConv", kOnnxDomain, api::DataType::INT8), + OpTransformInfo{qconv_int8.op_type_, qconv_int8.domain_, qconv_int8.version_, true}); + conv_table_.emplace( + OpIdInfo("QLinearConv", kMSDomain, api::DataType::INT8), + OpTransformInfo{qconv_int8.op_type_, qconv_int8.domain_, qconv_int8.version_, true}); + } + } + + { + // uint8 qconv -> int8 nhwc qconv + OpKernelRegistryId qconv_uint8{ + "QLinearConv", kMSDomain, 1, {{"T1", {DataTypeImpl::GetTensorType()}}}}; + const KernelCreateInfo* kernel_create_info{}; + const auto status = cpu_kernel_registry->TryFindKernel( + kCpuExecutionProvider, qconv_uint8.op_type_, qconv_uint8.domain_, + qconv_uint8.version_, qconv_uint8.type_constraints_, &kernel_create_info); + if (status.IsOK() && kernel_create_info != nullptr) { + kernel_create_info = nullptr; + conv_table_.emplace( + OpIdInfo("QLinearConv", kOnnxDomain, api::DataType::UINT8), + OpTransformInfo{qconv_uint8.op_type_, qconv_uint8.domain_, qconv_uint8.version_, true}); + conv_table_.emplace( + OpIdInfo("QLinearConv", kMSDomain, api::DataType::UINT8), + OpTransformInfo{qconv_uint8.op_type_, qconv_uint8.domain_, qconv_uint8.version_, true}); + } + } + + { + // fp16 conv -> fp16 nhwc conv + OpKernelRegistryId nhwc_conv_fp16{ + "NhwcFusedConv", kMSDomain, 1, {{"T", {DataTypeImpl::GetTensorType()}}}}; + + const KernelCreateInfo* kernel_create_info{}; + const auto status = cpu_kernel_registry->TryFindKernel( + kCpuExecutionProvider, nhwc_conv_fp16.op_type_, nhwc_conv_fp16.domain_, + nhwc_conv_fp16.version_, nhwc_conv_fp16.type_constraints_, &kernel_create_info); + if (status.IsOK() && kernel_create_info != nullptr) { + kernel_create_info = nullptr; + conv_table_.emplace( + OpIdInfo("Conv", kOnnxDomain, api::DataType::FLOAT16), + OpTransformInfo{nhwc_conv_fp16.op_type_, nhwc_conv_fp16.domain_, nhwc_conv_fp16.version_, false}); + conv_table_.emplace( + OpIdInfo("FusedConv", kMSDomain, api::DataType::FLOAT16), + OpTransformInfo{nhwc_conv_fp16.op_type_, nhwc_conv_fp16.domain_, nhwc_conv_fp16.version_, false}); + } + } + + { + // fp16 MaxPool -> fp16 nhwc MaxPool + OpKernelRegistryId nhwc_maxpool_fp16{ + "MaxPool", kMSInternalNHWCDomain, 12, {{"T", {DataTypeImpl::GetTensorType()}}}}; + + const KernelCreateInfo* kernel_create_info{}; + const auto status = cpu_kernel_registry->TryFindKernel( + kCpuExecutionProvider, nhwc_maxpool_fp16.op_type_, nhwc_maxpool_fp16.domain_, + nhwc_maxpool_fp16.version_, nhwc_maxpool_fp16.type_constraints_, &kernel_create_info); + if (status.IsOK() && kernel_create_info != nullptr) { + kernel_create_info = nullptr; + conv_table_.emplace( + OpIdInfo("MaxPool", kOnnxDomain, api::DataType::FLOAT16), + OpTransformInfo{nhwc_maxpool_fp16.op_type_, nhwc_maxpool_fp16.domain_, nhwc_maxpool_fp16.version_, false}); + } + } + + { + // fp16 AveragePool -> fp16 nhwc AveragePool + OpKernelRegistryId nhwc_avgpool_fp16{ + "AveragePool", kMSInternalNHWCDomain, 11, {{"T", {DataTypeImpl::GetTensorType()}}}}; + + const KernelCreateInfo* kernel_create_info{}; + const auto status = cpu_kernel_registry->TryFindKernel( + kCpuExecutionProvider, nhwc_avgpool_fp16.op_type_, nhwc_avgpool_fp16.domain_, + nhwc_avgpool_fp16.version_, nhwc_avgpool_fp16.type_constraints_, &kernel_create_info); + if (status.IsOK() && kernel_create_info != nullptr) { + kernel_create_info = nullptr; + conv_table_.emplace( + OpIdInfo("AveragePool", kOnnxDomain, api::DataType::FLOAT16), + OpTransformInfo{nhwc_avgpool_fp16.op_type_, nhwc_avgpool_fp16.domain_, nhwc_avgpool_fp16.version_, false}); + } + } + + { + // fp16 GlobalAveragePool -> fp16 nhwc GlobalAveragePool + OpKernelRegistryId nhwc_gavgpool_fp16{ + "GlobalAveragePool", kMSInternalNHWCDomain, 1, {{"T", {DataTypeImpl::GetTensorType()}}}}; + + const KernelCreateInfo* kernel_create_info{}; + const auto status = cpu_kernel_registry->TryFindKernel( + kCpuExecutionProvider, nhwc_gavgpool_fp16.op_type_, nhwc_gavgpool_fp16.domain_, + nhwc_gavgpool_fp16.version_, nhwc_gavgpool_fp16.type_constraints_, &kernel_create_info); + if (status.IsOK() && kernel_create_info != nullptr) { + kernel_create_info = nullptr; + conv_table_.emplace( + OpIdInfo("GlobalAveragePool", kOnnxDomain, api::DataType::FLOAT16), + OpTransformInfo{nhwc_gavgpool_fp16.op_type_, nhwc_gavgpool_fp16.domain_, nhwc_gavgpool_fp16.version_, false}); + } + } +}; + Status NhwcTransformer::ApplyImpl(Graph& graph, bool& modified, int graph_level, const logging::Logger& logger) const { #if defined(ORT_MINIMAL_BUILD) // update the producer/consumer info as previous optimizations may have invalidated it. @@ -28,7 +180,6 @@ Status NhwcTransformer::ApplyImpl(Graph& graph, bool& modified, int graph_level, } auto api_graph = MakeApiGraph(graph, cpu_allocator_, kCpuExecutionProvider); - modified = false; for (std::unique_ptr& node : api_graph->Nodes()) { // If the node is not supported in the CPU EP, skip it @@ -36,46 +187,48 @@ Status NhwcTransformer::ApplyImpl(Graph& graph, bool& modified, int graph_level, continue; } - // Only QLinearConv needs to be handled explicitly. The rest will be transformed if needed during transpose - // optimization. - if (node->OpType() == "QLinearConv") { - auto domain = node->Domain(); - - // Skip if domain is incorrect - if (domain != kOnnxDomain && domain != kMSDomain) { - continue; - } - - // Skip if already transformed - if (node->GetAttributeIntDefault("channels_last", 0) == 1) { - continue; - } - - // Skip if unknown rank - auto shape = NodeFromApiNode(*node).InputDefs()[0]->Shape(); - if (shape == nullptr) { - continue; - } - - // Convert to channels last - size_t rank = shape->dim_size(); - node->SetAttributeInt("channels_last", 1); + // Only Conv and QLinearConv needs to be handled explicitly. The rest will be + // transformed if needed during transpose optimization. + const auto* transform = NhwcConvLookup(conv_table_, *api_graph, *node); + if (nullptr == transform) { + continue; + } - std::vector input_perm = ChannelFirstToLastPerm(rank); - std::vector output_perm = ChannelLastToFirstPerm(rank); - WrapTransposesAroundNode(*api_graph, *node, {&input_perm}, {&output_perm}); + // Skip if already transformed + if (transform->has_channels_last_attrib_ && + node->GetAttributeIntDefault("channels_last", 0) == 1) { + continue; + } - if (domain != kMSDomain) { - SwapNodeOpTypeDomainAndSinceVersion(*api_graph, *node, "QLinearConv", kMSDomain, 1); - } + // Skip if unknown rank + auto shape = NodeFromApiNode(*node).InputDefs()[0]->Shape(); + if (shape == nullptr) { + continue; + } - modified = true; + // Convert to channels last + if (transform->has_channels_last_attrib_) { + node->SetAttributeInt("channels_last", 1); } + size_t rank = shape->dim_size(); + std::vector input_perm = ChannelFirstToLastPerm(rank); + std::vector output_perm = ChannelLastToFirstPerm(rank); + WrapTransposesAroundNode(*api_graph, *node, {&input_perm}, {&output_perm}); + + // Replace the operator if needed + if (node->Domain() != transform->domain_ || + node->OpType() != transform->optype_ || + node->SinceVersion() != transform->version_) { + SwapNodeOpTypeDomainAndSinceVersion( + *api_graph, *node, transform->optype_, + transform->domain_, transform->version_); + } + + modified = true; } if (modified) { - Optimize(*api_graph, /*allow_extended_ops*/ true, kCpuExecutionProvider, OptimizerMode::OPTIMIZE_TRANSPOSE, - OrtEPCostCheck); + Optimize(*api_graph, kCpuExecutionProvider, OrtEPCostCheck, OrtExtendedHandlers()); } return Status::OK(); diff --git a/onnxruntime/core/optimizer/nhwc_transformer.h b/onnxruntime/core/optimizer/nhwc_transformer.h index a435a8b946fb0..000732060b889 100644 --- a/onnxruntime/core/optimizer/nhwc_transformer.h +++ b/onnxruntime/core/optimizer/nhwc_transformer.h @@ -5,7 +5,64 @@ #include "core/common/common.h" #include "core/framework/execution_provider.h" +#include "core/framework/kernel_registry.h" #include "core/optimizer/graph_transformer.h" +#include "core/optimizer/transpose_optimization/onnx_transpose_optimization.h" + +// +// Data structures internal to nhwc transformer implementation. +// Maybe we should use Pimpl Idiom to hide all these into +// an implementation class. But it would add an extra pointer +// chasing during runtime. +// +namespace nhwc_map_internal { + +/** + * @brief For identifying layout sensive operators + * as candidates for transforming to NHWC ops. + */ +struct OpIdInfo { + const std::string optype_; + const std::string domain_; + const onnx_transpose_optimization::api::DataType data_type_; + + OpIdInfo(const std::basic_string_view& op, + const std::basic_string_view& domain, + onnx_transpose_optimization::api::DataType data_type) + : optype_(op), domain_(domain), data_type_(data_type) { + } + + bool operator==(const OpIdInfo& other) const { + return optype_ == other.optype_ && domain_ == other.domain_ && data_type_ == other.data_type_; + } +}; + +/** + * @brief Hash function for \ref OpIdInfo + */ +class OpIdHash { + public: + size_t operator()(const OpIdInfo& op) const { + size_t h1 = std::hash{}(op.optype_); + size_t h2 = std::hash{}(op.domain_); + size_t h3 = size_t(op.data_type_); + return h2 ^ (h1 << 4) ^ (h3 << 16); + } +}; + +/** + * @brief Information needed for operator layout transformation + */ +struct OpTransformInfo { + const std::string optype_; + const std::string domain_; + const int version_; + const bool has_channels_last_attrib_; +}; + +using OpTransformMap = std::unordered_map; + +} // namespace nhwc_map_internal namespace onnxruntime { @@ -17,14 +74,29 @@ and inserts nodes to transpose tensors as needed. */ class NhwcTransformer : public GraphTransformer { private: - AllocatorPtr cpu_allocator_; - public: - explicit NhwcTransformer(AllocatorPtr cpu_allocator) noexcept - : GraphTransformer("NhwcTransformer"), cpu_allocator_(std::move(cpu_allocator)){}; + explicit NhwcTransformer(AllocatorPtr cpu_allocator, std::shared_ptr cpu_kernel_registry) noexcept; + + /** + * @brief Usually called right after constructor, it shows whether + * this transformer should be used under current hardware configuration. + * + * @return whether this transformer would be useful under current hardware config + */ + bool IsActive() { + return !conv_table_.empty(); + } private: Status ApplyImpl(Graph& graph, bool& modified, int graph_level, const logging::Logger& logger) const override; + + AllocatorPtr cpu_allocator_; + + /** + * A mapping table to identify operators that need to be transformed, and map + * them to the new operators that accept NHWC layout + */ + nhwc_map_internal::OpTransformMap conv_table_; }; } // namespace onnxruntime diff --git a/onnxruntime/core/optimizer/optimizer_execution_frame.cc b/onnxruntime/core/optimizer/optimizer_execution_frame.cc index e10874f79e394..fc7e694b6a69b 100644 --- a/onnxruntime/core/optimizer/optimizer_execution_frame.cc +++ b/onnxruntime/core/optimizer/optimizer_execution_frame.cc @@ -35,7 +35,7 @@ OptimizerExecutionFrame::Info::Info(const std::vector& nodes, const std::function& is_sparse_initializer_func) : execution_provider_(execution_provider), is_sparse_initializer_func_(is_sparse_initializer_func) { - allocator_ptr_ = execution_provider_.GetAllocator(mem_type_); + allocator_ptr_ = std::make_shared(); ORT_ENFORCE(allocator_ptr_, "Failed to get allocator for optimizer"); ORT_THROW_IF_ERROR(data_transfer_mgr_.RegisterDataTransfer(std::make_unique())); @@ -89,7 +89,7 @@ OptimizerExecutionFrame::Info::Info(const std::vector& nodes, const std::function& is_sparse_initializer_func) : execution_provider_(execution_provider), is_sparse_initializer_func_(is_sparse_initializer_func) { - allocator_ptr_ = execution_provider_.GetAllocator(mem_type_); + allocator_ptr_ = std::make_shared(); ORT_ENFORCE(allocator_ptr_, "Failed to get allocator for optimizer"); ORT_THROW_IF_ERROR(data_transfer_mgr_.RegisterDataTransfer(std::make_unique())); @@ -175,8 +175,8 @@ OptimizerExecutionFrame::OptimizerExecutionFrame(const Info& info, Init(gsl::span(), gsl::span(), info.GetInitializers(), info.GetSparseInitializerLookupFunc(), fetches); } -AllocatorPtr OptimizerExecutionFrame::GetAllocatorImpl(const OrtMemoryInfo& info) const { - return info_.GetAllocator(info); +AllocatorPtr OptimizerExecutionFrame::GetAllocatorImpl(const OrtDevice&) const { + return info_.GetAllocator(); } Status OptimizerExecutionFrame::CopyTensor(const Tensor& src, Tensor& dest) const { diff --git a/onnxruntime/core/optimizer/optimizer_execution_frame.h b/onnxruntime/core/optimizer/optimizer_execution_frame.h index 4f3a1cc62cbf1..e1b8a91545f64 100644 --- a/onnxruntime/core/optimizer/optimizer_execution_frame.h +++ b/onnxruntime/core/optimizer/optimizer_execution_frame.h @@ -34,10 +34,6 @@ class OptimizerExecutionFrame final : public IExecutionFrame { const std::function& is_sparse_initializer_func); ~Info() = default; - AllocatorPtr GetAllocator(const OrtMemoryInfo& info) const { - return execution_provider_.GetAllocator(info.mem_type); - } - const AllocatorPtr& GetAllocator() const { return allocator_ptr_; } @@ -68,7 +64,6 @@ class OptimizerExecutionFrame final : public IExecutionFrame { } private: - const OrtMemType mem_type_{OrtMemTypeDefault}; AllocatorPtr allocator_ptr_; DataTransferManager data_transfer_mgr_; // MLValues for optimizer @@ -92,7 +87,7 @@ class OptimizerExecutionFrame final : public IExecutionFrame { private: ORT_DISALLOW_COPY_ASSIGNMENT_AND_MOVE(OptimizerExecutionFrame); - AllocatorPtr GetAllocatorImpl(const OrtMemoryInfo& info) const override; + AllocatorPtr GetAllocatorImpl(const OrtDevice& info) const override; Status CreateNodeOutputMLValueImpl(OrtValue& ort_value, int ort_value_idx, const TensorShape* shape) override; diff --git a/onnxruntime/core/optimizer/pre_shape_node_elimination.cc b/onnxruntime/core/optimizer/pre_shape_node_elimination.cc new file mode 100644 index 0000000000000..23980c9c10e6b --- /dev/null +++ b/onnxruntime/core/optimizer/pre_shape_node_elimination.cc @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/common/logging/logging.h" +#include "core/optimizer/rewrite_rule.h" +#include "core/optimizer/pre_shape_node_elimination.h" +#include "core/optimizer/utils.h" +#include "core/graph/graph.h" +#include "core/graph/graph_utils.h" + +namespace onnxruntime { + +Status PreShapeNodeElimination::Apply(Graph& graph, Node& node, RewriteRuleEffect& rule_effect, const logging::Logger&) const { + std::vector consumerIndices; + + // Save Consumer Nodes Indices (Shape) + for (auto it = node.OutputEdgesBegin(), end = node.OutputEdgesEnd(); it != end; ++it) { + const auto& consumer = (*it).GetNode(); + const auto consumer_idx = consumer.Index(); + consumerIndices.push_back(consumer_idx); + } + + // Remove output edges of the cast node + graph_utils::RemoveNodeOutputEdges(graph, node); + + // Change input defs of shape nodes + for (size_t consumer_idx : consumerIndices) { + Node& shape_node = *graph.GetNode(consumer_idx); + shape_node.MutableInputDefs()[0] = node.MutableInputDefs()[0]; + } + + graph.RemoveNode(node.Index()); + rule_effect = RewriteRuleEffect::kRemovedCurrentNode; + + return Status::OK(); +} + +bool PreShapeNodeElimination::SatisfyCondition(const Graph& graph, const Node& node, const logging::Logger& logger) const { + if (!graph_utils::CanRemoveNode(graph, node, logger)) { + return false; + } + + auto output_nodes = graph.GetConsumerNodes(node.OutputDefs()[0]->Name()); + + if (output_nodes.empty()) { + return false; + } + + for (const Node* next_node : output_nodes) { + // Check if the next node is not of type "Shape" + if (!graph_utils::IsSupportedOptypeVersionAndDomain(*next_node, "Shape", {13, 15, 19}, kOnnxDomain)) { + return false; + } + } + + // All output nodes are of type "Shape" + return true; +} + +} // namespace onnxruntime diff --git a/onnxruntime/core/optimizer/pre_shape_node_elimination.h b/onnxruntime/core/optimizer/pre_shape_node_elimination.h new file mode 100644 index 0000000000000..91e9257bab3d3 --- /dev/null +++ b/onnxruntime/core/optimizer/pre_shape_node_elimination.h @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/optimizer/rewrite_rule.h" + +namespace onnxruntime { + +/** +@class PreShapeNodeElimination + +Rewrite rule that eliminates some particular nodes if the next node is a Shape node. + +It is attempted to be triggered only on nodes with op type "Cast". +*/ +class PreShapeNodeElimination : public RewriteRule { + public: + PreShapeNodeElimination() noexcept : RewriteRule("PreShapeNodeElimination") {} + + std::vector TargetOpTypes() const noexcept override { + return {"Cast"}; + } + + private: + bool SatisfyCondition(const Graph& graph, const Node& node, const logging::Logger& logger) const override; + + Status Apply(Graph& graph, Node& node, RewriteRuleEffect& rule_effect, const logging::Logger& logger) const override; +}; + +} // namespace onnxruntime diff --git a/onnxruntime/core/optimizer/propagate_cast_ops.cc b/onnxruntime/core/optimizer/propagate_cast_ops.cc index 64ec520740e51..e4f34e066851f 100644 --- a/onnxruntime/core/optimizer/propagate_cast_ops.cc +++ b/onnxruntime/core/optimizer/propagate_cast_ops.cc @@ -127,8 +127,45 @@ static bool IsRelevantOutput(const Node* node, const NodeArg* output) { return true; } +// Check whether the node is a cast operation from float16/float to the specified data_type. +static bool IsCastTo(const Node* node, TensorProto_DataType data_type) { + if (node->OpType() == "Cast") { + const NodeAttributes& attributes = node->GetAttributes(); + const auto attr_hit = attributes.find("to"); + ORT_ENFORCE(attr_hit != attributes.end(), "Node: ", node->Name(), + " is a Cast node and it must have 'to' attribute set."); + const NodeArg* input = node->InputDefs()[0]; + auto input_data_type = static_cast(input->TypeAsProto()->tensor_type().elem_type()); + // Allow cast nodes with same input and output type float/float16 to eliminate such casts. + return (input_data_type == TensorProto::FLOAT16 || input_data_type == TensorProto::FLOAT) && + attr_hit->second.i() == static_cast(data_type); + } + return false; +} + +// when node is softmax, and its input comes from a cast-to-fp32 node, and its output is only consumed by one cast-to-fp16 node, then we can treat it as a fp16-allowed op, +// as ort's softmax implementation already does the necessary cast logic, for example do reduce sum at fp32 +static bool SoftmaxCanBeFP16(const Node& node) { + if (node.OpType() != "Softmax") + return false; + // 1. input comes from a cast-to-fp32 node + const Node* input_node = graph_utils::GetInputNode(node, 0); + if (!(input_node && IsCastTo(input_node, TensorProto::FLOAT))) + return false; + // 2. output is consumed by a cast-to-fp16 node ONLY + if (node.GetOutputEdgesCount() != 1) + return false; + const Node* output_node = &(*node.OutputNodesBegin()); + if (!(output_node && IsCastTo(output_node, TensorProto::FLOAT16))) + return false; + + return true; +} + // Check whether the given opcode is fp16 allowed for the given level of optimization. -static bool IsFP16Allow(const std::string& op_type, size_t level, const FP16AllowOps& fp16_allow_level0_ops) { +static bool IsFP16Allow(const Node* node, size_t level, const FP16AllowOps& fp16_allow_level0_ops) { + if (!node) + return false; // XXX: Shall we add a check for unsupported level or just ignore it as the current code does? constexpr size_t MaxSupportedCastPropagationLevel = 2; @@ -142,27 +179,11 @@ static bool IsFP16Allow(const std::string& op_type, size_t level, const FP16Allo static const std::array, MaxSupportedCastPropagationLevel> allowed_ops = {level1_fp16_allow_set, level2_fp16_allow_set}; - bool fp16_allow = Contains(fp16_allow_level0_ops, op_type); + bool fp16_allow = Contains(fp16_allow_level0_ops, node->OpType()); for (size_t i = 1, limit = std::min(level, MaxSupportedCastPropagationLevel); i <= limit && !fp16_allow; ++i) { - fp16_allow = Contains(allowed_ops[i - 1].get(), op_type); - } - return fp16_allow; -} - -// Check whether the node is a cast operation from float16/float to the specified data_type. -static bool IsCastTo(const Node* node, TensorProto_DataType data_type) { - if (node->OpType() == "Cast") { - const NodeAttributes& attributes = node->GetAttributes(); - const auto attr_hit = attributes.find("to"); - ORT_ENFORCE(attr_hit != attributes.end(), "Node: ", node->Name(), - " is a Cast node and it must have 'to' attribute set."); - const NodeArg* input = node->InputDefs()[0]; - auto input_data_type = static_cast(input->TypeAsProto()->tensor_type().elem_type()); - // Allow cast nodes with same input and output type float/float16 to eliminate such casts. - return (input_data_type == TensorProto::FLOAT16 || input_data_type == TensorProto::FLOAT) && - attr_hit->second.i() == static_cast(data_type); + fp16_allow = Contains(allowed_ops[i - 1].get(), node->OpType()); } - return false; + return fp16_allow || SoftmaxCanBeFP16(*node); } // Check whether the node-arg element type is same the specified data type @@ -568,8 +589,7 @@ static void SearchUpstream(Graph& graph, NodeArg* node_arg, Node* dst_node, // This Cast node and the Cast node that will be created later will cancel out require_cast[node_arg].push_back(dst_node); } else { - std::string op_type = node->OpType(); - if (!IsFP16Allow(op_type, level, fp16_allow_ops)) { + if (!IsFP16Allow(node, level, fp16_allow_ops)) { // Cannot traverse-up beyond this point if (node_arg->Exists() && IsType(*node_arg, TensorProto_DataType_FLOAT)) { require_cast[node_arg].push_back(dst_node); @@ -630,12 +650,11 @@ static void SearchDownstream(Graph& graph, NodeArg* node_arg, const FP16AllowOps& fp16_allow_ops) { for (Node* node : graph.GetMutableConsumerNodes(node_arg->Name())) { if (node) { - const std::string& op_type = node->OpType(); if (IsCastTo(node, TensorProto_DataType_FLOAT)) { // This Cast node and the Cast node that will be created later will cancel out require_cast[node_arg].push_back(node); } else { - if (!IsFP16Allow(op_type, level, fp16_allow_ops)) { + if (!IsFP16Allow(node, level, fp16_allow_ops)) { if (node_arg->Exists() && IsType(*node_arg, TensorProto_DataType_FLOAT)) { require_cast[node_arg].push_back(node); @@ -975,7 +994,7 @@ static bool PropagateFP32CastsFromInputsToOutputs(Graph& graph, Node* node, NodeIndices& inserted_nodes, const logging::Logger& logger) { bool modified = false; - if (IsFP16Allow(node->OpType(), level, fp16_allow_ops)) { + if (IsFP16Allow(node, level, fp16_allow_ops)) { bool has_float_inputs = false; bool all_float_inputs_have_casts = true; InlinedVector casts; @@ -1084,7 +1103,7 @@ static bool PropagateFP16CastsFromOutputsToInputs(Graph& graph, Node* node, NodeIndices& inserted_nodes, const logging::Logger& logger) { bool modified = false; - if (IsFP16Allow(node->OpType(), level, fp16_allow_ops)) { + if (IsFP16Allow(node, level, fp16_allow_ops)) { bool has_float_outputs = false; bool all_float_outputs_have_casts = true; InlinedVector casts; // Cast nodes to propagate. @@ -1336,7 +1355,7 @@ Status PropagateCastOps::ApplyImpl(Graph& graph, bool& modified, int graph_level // Using InsertFP16Cast and InsertFP32Casts insert float16 casts on all inputs and float casts on all outputs. // Each consumer of each output gets a separate float cast inserted. Doing so will convert the computation of // current node from 32 bit float to 16 bit float operation. These cast operations will be eventually reduced. - if (IsFP16Allow(node.OpType(), level_, fp16_allow_ops_0_)) { + if (IsFP16Allow(node_ptr, level_, fp16_allow_ops_0_)) { // Insert FP16 Cast on all float inputs converted_nodes.insert(node.Index()); for (NodeArg* input_arg : node.MutableInputDefs()) { diff --git a/onnxruntime/core/optimizer/qdq_transformer/avx2_weight_s8_to_u8.cc b/onnxruntime/core/optimizer/qdq_transformer/avx2_weight_s8_to_u8.cc index 0959e7e61c8de..6f0f38b1de56e 100644 --- a/onnxruntime/core/optimizer/qdq_transformer/avx2_weight_s8_to_u8.cc +++ b/onnxruntime/core/optimizer/qdq_transformer/avx2_weight_s8_to_u8.cc @@ -99,7 +99,7 @@ static bool TryConvertDynamicQuantizeLSTM(Node& op_node, Graph& graph) { Initializer w_temp(*weight_tensor_proto, graph.ModelPath()); { int8_t* p = w_temp.data(); - for (int i = 0; i < w_temp.size(); i++) { + for (size_t i = 0; i < w_temp.size(); i++) { if (*p < -64 || *p > 64) { should_convert = true; } @@ -111,7 +111,7 @@ static bool TryConvertDynamicQuantizeLSTM(Node& op_node, Graph& graph) { Initializer r_temp(*r_tensor_proto, graph.ModelPath()); { int8_t* p = r_temp.data(); - for (int i = 0; i < r_temp.size(); i++) { + for (size_t i = 0; i < r_temp.size(); i++) { if (*p < -64 || *p > 64) { should_convert = true; } @@ -129,7 +129,7 @@ static bool TryConvertDynamicQuantizeLSTM(Node& op_node, Graph& graph) { weights_proto_u8.set_data_type(ONNX_NAMESPACE::TensorProto_DataType_UINT8); weights_proto_u8.set_name(weight_tensor_proto->name() + "_s8_2_u8"); weights_proto_u8.mutable_dims()->CopyFrom(weight_tensor_proto->dims()); - weights_proto_u8.set_raw_data(w_temp.data(), w_temp.size()); + weights_proto_u8.set_raw_data(w_temp.data(), static_cast(w_temp.size())); input_defs[w_idx] = &graph_utils::AddInitializer(graph, weights_proto_u8); ONNX_NAMESPACE::TensorProto weight_zp_proto_u8; @@ -140,7 +140,7 @@ static bool TryConvertDynamicQuantizeLSTM(Node& op_node, Graph& graph) { r_proto_u8.set_data_type(ONNX_NAMESPACE::TensorProto_DataType_UINT8); r_proto_u8.set_name(r_tensor_proto->name() + "_s8_2_u8"); r_proto_u8.mutable_dims()->CopyFrom(r_tensor_proto->dims()); - r_proto_u8.set_raw_data(r_temp.data(), r_temp.size()); + r_proto_u8.set_raw_data(r_temp.data(), static_cast(r_temp.size())); input_defs[r_idx] = &graph_utils::AddInitializer(graph, r_proto_u8); ONNX_NAMESPACE::TensorProto r_zp_proto_u8; diff --git a/onnxruntime/core/optimizer/qdq_transformer/clip_quantizelinear.cc b/onnxruntime/core/optimizer/qdq_transformer/clip_quantizelinear.cc index 55d0a31e64e44..50653b368857d 100644 --- a/onnxruntime/core/optimizer/qdq_transformer/clip_quantizelinear.cc +++ b/onnxruntime/core/optimizer/qdq_transformer/clip_quantizelinear.cc @@ -1,8 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/optimizer/initializer.h" #include "core/optimizer/qdq_transformer/clip_quantizelinear.h" + +#include + +#include "core/optimizer/initializer.h" +#include "core/optimizer/qdq_transformer/qdq_util.h" #include "core/optimizer/utils.h" #include "core/graph/graph_utils.h" @@ -49,14 +53,26 @@ static bool GetQConstantLowerUpper(const Graph& graph, const Node& node, float& switch (zp_initializer.data_type()) { case ONNX_NAMESPACE::TensorProto_DataType_INT8: { const int8_t zero_point = zp_initializer.data()[0]; - lower = scale * (-128 - zero_point); - upper = scale * (127 - zero_point); + lower = scale * (std::numeric_limits::lowest() - zero_point); + upper = scale * (std::numeric_limits::max() - zero_point); break; } case ONNX_NAMESPACE::TensorProto_DataType_UINT8: { const uint8_t zero_point = zp_initializer.data()[0]; - lower = scale * (0 - zero_point); - upper = scale * (255 - zero_point); + lower = scale * (std::numeric_limits::lowest() - zero_point); + upper = scale * (std::numeric_limits::max() - zero_point); + break; + } + case ONNX_NAMESPACE::TensorProto_DataType_INT16: { + const int16_t zero_point = zp_initializer.data()[0]; + lower = scale * (std::numeric_limits::lowest() - zero_point); + upper = scale * (std::numeric_limits::max() - zero_point); + break; + } + case ONNX_NAMESPACE::TensorProto_DataType_UINT16: { + const uint16_t zero_point = zp_initializer.data()[0]; + lower = scale * (std::numeric_limits::lowest() - zero_point); + upper = scale * (std::numeric_limits::max() - zero_point); break; } default: @@ -73,7 +89,7 @@ bool ClipQuantFusion::SatisfyCondition(const Graph& graph, const Node& node, con // if Clip is followed by QuantizeLinear, it can be fused into QuantizeLinear potentially const auto& next_node = *node.OutputNodesBegin(); - if (!graph_utils::IsSupportedOptypeVersionAndDomain(next_node, "QuantizeLinear", {10, 13})) { + if (!QDQ::MatchQNode(next_node)) { return false; } diff --git a/onnxruntime/core/optimizer/qdq_transformer/ensure_unique_dq_for_node_unit.cc b/onnxruntime/core/optimizer/qdq_transformer/ensure_unique_dq_for_node_unit.cc index e50efd8aa199c..cc0f7854791d4 100644 --- a/onnxruntime/core/optimizer/qdq_transformer/ensure_unique_dq_for_node_unit.cc +++ b/onnxruntime/core/optimizer/qdq_transformer/ensure_unique_dq_for_node_unit.cc @@ -52,7 +52,9 @@ Status DuplicateDQForOutputEdge(const graph_utils::GraphEdge& original_dq_output QDQ::DQOpName, MakeString("Added by ", kTransformerName), dq_inputs, - {&new_dq_output_nodearg}); + {&new_dq_output_nodearg}, + nullptr, // attributes + original_dq_node.Domain()); // set up edges // remove DQ -> Y diff --git a/onnxruntime/core/optimizer/qdq_transformer/qdq_propagation.cc b/onnxruntime/core/optimizer/qdq_transformer/qdq_propagation.cc index fc1a8cd86bc48..f0e76312d6e00 100644 --- a/onnxruntime/core/optimizer/qdq_transformer/qdq_propagation.cc +++ b/onnxruntime/core/optimizer/qdq_transformer/qdq_propagation.cc @@ -17,7 +17,7 @@ namespace onnxruntime { namespace { bool CanNodePropagate(const Node& node) { return graph_utils::IsSupportedOptypeVersionAndDomain(node, "MaxPool", {12}) || - graph_utils::IsSupportedOptypeVersionAndDomain(node, "Reshape", {5, 13, 14}) || + graph_utils::IsSupportedOptypeVersionAndDomain(node, "Reshape", {5, 13, 14, 19}) || graph_utils::IsSupportedOptypeVersionAndDomain(node, "Transpose", {1, 13}) || graph_utils::IsSupportedOptypeVersionAndDomain(node, "Squeeze", {1, 11, 13}) || graph_utils::IsSupportedOptypeVersionAndDomain(node, "Unsqueeze", {1, 11, 13}); @@ -31,7 +31,7 @@ bool CanNodePropagate(const Node& node) { // 2. scale_initializer_nodearg and zp_initializer_nodearg_ptr (if not null) are constant initializers Status InsertQDQPair(Graph& graph, const ExtendedGraphEdge& insertion_edge, NodeArg& scale_initializer_nodearg, NodeArg* zp_initializer_nodearg_ptr, - const logging::Logger& logger) { + const std::string& qdq_domain, const logging::Logger& logger) { auto* src_node = insertion_edge.GetMutableNodeAtEnd(graph, ExtendedGraphEdge::End::Source); auto* dst_node = insertion_edge.GetMutableNodeAtEnd(graph, ExtendedGraphEdge::End::Destination); @@ -75,7 +75,9 @@ Status InsertQDQPair(Graph& graph, const ExtendedGraphEdge& insertion_edge, make_q_or_dq_inputs(pre_q_nodearg, scale_initializer_nodearg, zp_initializer_nodearg_ptr), // outputs - {&q_to_dq_nodearg}); + {&q_to_dq_nodearg}, + nullptr, // attributes + qdq_domain); ORT_RETURN_IF_NOT(graph.SetOpSchemaFromRegistryForNode(q_node), "Failed to set op schema for added Q node."); @@ -86,7 +88,9 @@ Status InsertQDQPair(Graph& graph, const ExtendedGraphEdge& insertion_edge, make_q_or_dq_inputs(q_to_dq_nodearg, scale_initializer_nodearg, zp_initializer_nodearg_ptr), // outputs - {&post_dq_nodearg}); + {&post_dq_nodearg}, + nullptr, // attributes + qdq_domain); ORT_RETURN_IF_NOT(graph.SetOpSchemaFromRegistryForNode(dq_node), "Failed to set op schema for added DQ node."); @@ -237,7 +241,7 @@ Status PropagateDQForward(Graph& graph, gsl::span node_indices, break; } - ORT_RETURN_IF_ERROR(InsertQDQPair(graph, *curr_edge, dq_scale, dq_zero_point, logger)); + ORT_RETURN_IF_ERROR(InsertQDQPair(graph, *curr_edge, dq_scale, dq_zero_point, dq_node.Domain(), logger)); modified = true; } } @@ -286,7 +290,7 @@ Status PropagateQBackward(Graph& graph, gsl::span node_indices, break; } - ORT_RETURN_IF_ERROR(InsertQDQPair(graph, *curr_edge, q_scale, q_zero_point, logger)); + ORT_RETURN_IF_ERROR(InsertQDQPair(graph, *curr_edge, q_scale, q_zero_point, q_node.Domain(), logger)); modified = true; } } diff --git a/onnxruntime/core/optimizer/qdq_transformer/qdq_util.cc b/onnxruntime/core/optimizer/qdq_transformer/qdq_util.cc index 79ac9d64cb420..221c06d7c8dcf 100644 --- a/onnxruntime/core/optimizer/qdq_transformer/qdq_util.cc +++ b/onnxruntime/core/optimizer/qdq_transformer/qdq_util.cc @@ -102,11 +102,13 @@ bool QOrDQNodeHasConstantScalarScaleAndZeroPoint( #if !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) bool MatchQNode(const Node& node) { - return graph_utils::IsSupportedOptypeVersionAndDomain(node, QOpName, {10, 13}); + return graph_utils::IsSupportedOptypeVersionAndDomain(node, QOpName, {10, 13, 19}) || + graph_utils::IsSupportedOptypeVersionAndDomain(node, QOpName, {1}, kMSDomain); } bool MatchDQNode(const Node& node) { - return graph_utils::IsSupportedOptypeVersionAndDomain(node, DQOpName, {10, 13}); + return graph_utils::IsSupportedOptypeVersionAndDomain(node, DQOpName, {10, 13, 19}) || + graph_utils::IsSupportedOptypeVersionAndDomain(node, DQOpName, {1}, kMSDomain); } #endif // !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) diff --git a/onnxruntime/core/optimizer/qdq_transformer/relu_quantizelinear.cc b/onnxruntime/core/optimizer/qdq_transformer/relu_quantizelinear.cc index b695328531114..3a8f2db62302d 100644 --- a/onnxruntime/core/optimizer/qdq_transformer/relu_quantizelinear.cc +++ b/onnxruntime/core/optimizer/qdq_transformer/relu_quantizelinear.cc @@ -3,6 +3,7 @@ #include "core/optimizer/initializer.h" #include "core/optimizer/qdq_transformer/relu_quantizelinear.h" +#include "core/optimizer/qdq_transformer/qdq_util.h" #include "core/optimizer/utils.h" #include "core/graph/graph_utils.h" @@ -18,7 +19,7 @@ bool ReluQuantFusion::SatisfyCondition(const Graph& graph, const Node& node, con // if Relu is followed by QuantizeLinear, it can be fused into QuantizeLinear potentially const auto& next_node = *node.OutputNodesBegin(); - if (!graph_utils::IsSupportedOptypeVersionAndDomain(next_node, "QuantizeLinear", {10, 13})) { + if (!QDQ::MatchQNode(next_node)) { return false; } diff --git a/onnxruntime/core/optimizer/qdq_transformer/s8_to_u8.h b/onnxruntime/core/optimizer/qdq_transformer/s8_to_u8.h index 6b25ec6931472..6caa35ea61ed7 100644 --- a/onnxruntime/core/optimizer/qdq_transformer/s8_to_u8.h +++ b/onnxruntime/core/optimizer/qdq_transformer/s8_to_u8.h @@ -50,7 +50,7 @@ inline bool Int8TensorProto2Uint8( Initializer temp(*src, graph.ModelPath()); int8_t* p = temp.data(); bool should_convert = false; - for (int i = 0; i < temp.size(); i++) { + for (size_t i = 0; i < temp.size(); i++) { if (*p < -64 || *p > 64) { should_convert = true; } @@ -75,4 +75,4 @@ inline bool Int8TensorProto2Uint8( extern bool ConvertS8WeightToU8(Graph& graph, Node& op_node, size_t weights_idx, size_t weight_zp_idx); -} // namespace onnxruntime::QDQ \ No newline at end of file +} // namespace onnxruntime::QDQ diff --git a/onnxruntime/core/optimizer/qdq_transformer/selectors_actions/qdq_selector_action_transformer.cc b/onnxruntime/core/optimizer/qdq_transformer/selectors_actions/qdq_selector_action_transformer.cc index d7039cb4b7cfc..0e383c3031ca6 100644 --- a/onnxruntime/core/optimizer/qdq_transformer/selectors_actions/qdq_selector_action_transformer.cc +++ b/onnxruntime/core/optimizer/qdq_transformer/selectors_actions/qdq_selector_action_transformer.cc @@ -2,6 +2,7 @@ // Licensed under the MIT License. #include "core/optimizer/qdq_transformer/selectors_actions/qdq_selector_action_transformer.h" +#include #include "core/mlas/inc/mlas.h" #include "core/optimizer/qdq_transformer/selectors_actions/qdq_actions.h" @@ -32,7 +33,8 @@ void SplitQDQRules(SelectorActionRegistry& qdq_selector_action_registry) { // create rules for ops that don't change the data void DropQDQNodesRules(SelectorActionRegistry& qdq_selector_action_registry) { // 3 nodes. DQ, target, Q. Merge into target and remove DQ and Q. - const std::string action_name{"drop"}; + const std::string drop_action_name{"drop"}; + const std::string drop_action_no_int16_name{"drop_no_int16_support"}; NTO::NodeLocation dq{NTO::NodeType::kInput, 0}; NTO::NodeLocation q{NTO::NodeType::kOutput, 0}; @@ -42,22 +44,33 @@ void DropQDQNodesRules(SelectorActionRegistry& qdq_selector_action_registry) { MoveToSlot(dq, ArgType::kInput, 0, ArgType::kInput, 0), MoveToSlot(q, ArgType::kOutput, 0, ArgType::kOutput, 0)}; - std::unique_ptr action = std::make_unique(std::move(moves)); + std::unique_ptr drop_action_no_int16 = std::make_unique( + std::vector(moves)); // Copy before std::move(moves) + std::unique_ptr drop_action = std::make_unique(std::move(moves)); #if !defined(ORT_MINIMAL_BUILD) - std::unique_ptr selector = std::make_unique(); - qdq_selector_action_registry.RegisterSelectorAndAction(action_name, + // Use a separate selector + action that disallows 16-bit types for MaxPool and Resize. + // int16 MaxPool is not supported by the ONNX specification. + // int16 Resize is not supported by the ORT implementation (although allowed by ONNX). + std::unique_ptr selector_disallow_16bit = std::make_unique(false); + qdq_selector_action_registry.RegisterSelectorAndAction(drop_action_no_int16_name, + {{"MaxPool", {12}}, + {"Resize", {}}}, + std::move(selector_disallow_16bit), + std::move(drop_action_no_int16)); + + std::unique_ptr selector = std::make_unique(true); + qdq_selector_action_registry.RegisterSelectorAndAction(drop_action_name, {{"Gather", {}}, {"Reshape", {}}, {"Transpose", {}}, - {"MaxPool", {12}}, - {"Resize", {}}, {"Squeeze", {}}, {"Unsqueeze", {}}}, std::move(selector), - std::move(action)); + std::move(drop_action)); #else - qdq_selector_action_registry.RegisterAction(action_name, std::move(action)); + qdq_selector_action_registry.RegisterAction(drop_action_no_int16_name, std::move(drop_action_no_int16)); + qdq_selector_action_registry.RegisterAction(drop_action_name, std::move(drop_action)); #endif } @@ -74,6 +87,7 @@ void DropDQNodesRules(SelectorActionRegistry& qdq_selector_action_registry) { std::unique_ptr action = std::make_unique(std::move(moves)); #if !defined(ORT_MINIMAL_BUILD) + // TODO: Enable 16-bit types in selector when ArgMax supports 16-bit integer input tensors. std::unique_ptr selector = std::make_unique(); qdq_selector_action_registry.RegisterSelectorAndAction(action_name, {{"ArgMax", {}}}, @@ -91,6 +105,7 @@ void UnaryOpQDQRules(SelectorActionRegistry& qdq_selector_action_registry) { std::unique_ptr action = std::make_unique(kMSDomain); #if !defined(ORT_MINIMAL_BUILD) + // TODO: Enable 16-bit types in selector when unary QLinear* ops support 16-bit. std::unique_ptr selector = std::make_unique(); qdq_selector_action_registry.RegisterSelectorAndAction(action_name, {{"AveragePool", {}}, @@ -112,6 +127,7 @@ void BinaryOpQDQRules(SelectorActionRegistry& qdq_selector_action_registry) { std::unique_ptr action = std::make_unique(kMSDomain); #if !defined(ORT_MINIMAL_BUILD) + // TODO: Enable 16-bit types in selector when binary QLinear* ops support 16-bit. std::unique_ptr selector = std::make_unique(); qdq_selector_action_registry.RegisterSelectorAndAction(action_name, {{"Add", {}}, @@ -131,6 +147,7 @@ void VariadicOpQDQRules(SelectorActionRegistry& qdq_selector_action_registry) { std::unique_ptr action = std::make_unique(kMSDomain); #if !defined(ORT_MINIMAL_BUILD) + // TODO: Enable 16-bit types in selector when QLinearConcat supports 16-bit. std::unique_ptr selector = std::make_unique(); qdq_selector_action_registry.RegisterSelectorAndAction(action_name, @@ -152,6 +169,7 @@ void ConvQDQRules(SelectorActionRegistry& qdq_selector_action_registry, bool is_ std::unique_ptr action = std::make_unique(); #if !defined(ORT_MINIMAL_BUILD) + // TODO: Enable 16-bit types in selector when QLinearConv supports 16-bit. std::unique_ptr selector = std::make_unique(is_int8_allowed); qdq_selector_action_registry.RegisterSelectorAndAction(action_name, @@ -174,6 +192,7 @@ void MatMulQDQRules(SelectorActionRegistry& qdq_selector_action_registry, bool i std::unique_ptr action = std::make_unique(); #if !defined(ORT_MINIMAL_BUILD) + // TODO: Enable 16-bit types in selector when QLinearMatMul and MatMulInteger support 16-bit. std::unique_ptr selector = std::make_unique(is_int8_allowed); qdq_selector_action_registry.RegisterSelectorAndAction(action_name, {{"MatMul", {}}}, @@ -195,6 +214,7 @@ void GemmQDQRules(SelectorActionRegistry& qdq_selector_action_registry) { std::unique_ptr action = std::make_unique(); #if !defined(ORT_MINIMAL_BUILD) + // TODO: Enable 16-bit types in selector when QGemm supports 16-bit. std::unique_ptr selector = std::make_unique(); qdq_selector_action_registry.RegisterSelectorAndAction(action_name, {{"Gemm", {}}}, @@ -215,6 +235,7 @@ void WhereQDQRules(SelectorActionRegistry& qdq_selector_action_registry) { std::unique_ptr action = std::make_unique(); #if !defined(ORT_MINIMAL_BUILD) + // TODO: Enable 16-bit types in selector when QLinearWhere supports 16-bit. std::unique_ptr selector = std::make_unique(); qdq_selector_action_registry.RegisterSelectorAndAction(action_name, {{"Where", {}}}, diff --git a/onnxruntime/core/optimizer/qdq_transformer/selectors_actions/qdq_selectors.cc b/onnxruntime/core/optimizer/qdq_transformer/selectors_actions/qdq_selectors.cc index 928c32a42767c..5015e48fdb7b8 100644 --- a/onnxruntime/core/optimizer/qdq_transformer/selectors_actions/qdq_selectors.cc +++ b/onnxruntime/core/optimizer/qdq_transformer/selectors_actions/qdq_selectors.cc @@ -14,6 +14,12 @@ namespace onnxruntime { namespace QDQ { namespace { + +constexpr bool Is16BitIntType(int32_t data_type) { + return (data_type == ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_INT16) || + (data_type == ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_UINT16); +} + // adjust for an optional input/output that has an entry but does not exist int NumActualValues(const Node& node, bool input) { const auto& defs = input ? node.InputDefs() : node.OutputDefs(); @@ -110,6 +116,17 @@ bool DropQDQNodeGroupSelector::Check(const GraphViewer& graph_viewer, return false; } + int32_t dt_input = dq_nodes[0]->InputDefs()[0]->TypeAsProto()->tensor_type().elem_type(); + int32_t dt_output = q_nodes[0]->OutputDefs()[0]->TypeAsProto()->tensor_type().elem_type(); + + if (dt_input != dt_output) { + return false; + } + + if (!allow_16bit_ && Is16BitIntType(dt_input)) { + return false; + } + const Node& dq_node = *dq_nodes.front(); const Node& q_node = *q_nodes.front(); @@ -124,7 +141,7 @@ bool DropDQNodeGroupSelector::Check(const GraphViewer& graph_viewer, const Node& node, const std::vector& dq_nodes, const std::vector& q_nodes) const { - int num_dq_inputs = NumActualValues(node, true); + constexpr int num_dq_inputs = 1; if (num_dq_inputs != gsl::narrow_cast(dq_nodes.size())) { return false; } @@ -136,6 +153,12 @@ bool DropDQNodeGroupSelector::Check(const GraphViewer& graph_viewer, (void)q_nodes; const Node& dq_node = *dq_nodes.front(); + const int32_t dt_input = dq_node.InputDefs()[0]->TypeAsProto()->tensor_type().elem_type(); + + // 16-bit int types must be explicitly allowed. + if (!allow_16bit_ && Is16BitIntType(dt_input)) { + return false; + } auto get_const_initializer = [&graph_viewer](const std::string& initializer_name) { return graph_viewer.GetConstantInitializer(initializer_name, true); @@ -154,7 +177,16 @@ bool UnaryNodeGroupSelector::Check(const GraphViewer& graph_viewer, const Node& int32_t dt_input = dq_nodes[0]->InputDefs()[0]->TypeAsProto()->tensor_type().elem_type(); int32_t dt_output = q_nodes[0]->OutputDefs()[0]->TypeAsProto()->tensor_type().elem_type(); - return dt_input == dt_output; + if (dt_input != dt_output) { + return false; + } + + // 16-bit int types must be explicitly allowed. + if (!allow_16bit_ && Is16BitIntType(dt_input)) { + return false; + } + + return true; } bool BinaryNodeGroupSelector::Check(const GraphViewer& graph_viewer, @@ -168,8 +200,18 @@ bool BinaryNodeGroupSelector::Check(const GraphViewer& graph_viewer, int32_t dt_input_1 = dq_nodes[0]->InputDefs()[0]->TypeAsProto()->tensor_type().elem_type(); int32_t dt_input_2 = dq_nodes[1]->InputDefs()[0]->TypeAsProto()->tensor_type().elem_type(); int32_t dt_output = q_nodes[0]->OutputDefs()[0]->TypeAsProto()->tensor_type().elem_type(); - return dt_input_1 == dt_input_2 && - dt_input_1 == dt_output; + + // All input and output types must match. + if (dt_input_1 != dt_input_2 || dt_input_1 != dt_output) { + return false; + } + + // 16-bit int types must be explicitly allowed. + if (!allow_16bit_ && Is16BitIntType(dt_input_1)) { + return false; + } + + return true; } bool VariadicNodeGroupSelector::Check(const GraphViewer& graph_viewer, @@ -194,7 +236,17 @@ bool VariadicNodeGroupSelector::Check(const GraphViewer& graph_viewer, return false; } } - return dt_input == dt_output; + + if (dt_input != dt_output) { + return false; + } + + // 16-bit int types must be explicitly allowed. + if (!allow_16bit_ && Is16BitIntType(dt_input)) { + return false; + } + + return true; } void InputVariadicSelector::UpdateBuilder(NodesToOptimizeIndicesBuilder& builder) const { @@ -227,12 +279,19 @@ bool ConvNodeGroupSelector::Check(const GraphViewer& graph_viewer, } } - if (dq_nodes.size() < 3) { // no bias - return true; + if (dq_nodes.size() == 3) { // has bias + int32_t dt_bias = dq_nodes[2]->InputDefs()[0]->TypeAsProto()->tensor_type().elem_type(); + if (dt_bias != ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_INT32) { + return false; + } } - int32_t dt_bias = dq_nodes[2]->InputDefs()[0]->TypeAsProto()->tensor_type().elem_type(); - return dt_bias == ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_INT32; + // 16-bit int types must be explicitly allowed. + if (!allow_16bit_ && (Is16BitIntType(dt_input) || Is16BitIntType(dt_weight))) { + return false; + } + + return true; } void ConvSelector::UpdateBuilder(NodesToOptimizeIndicesBuilder& builder) const { @@ -256,6 +315,11 @@ bool MatMulNodeGroupSelector::Check(const GraphViewer& graph_viewer, } } + // 16-bit int types must be explicitly allowed. + if (!allow_16bit_ && (Is16BitIntType(dt_input) || Is16BitIntType(dt_weight))) { + return false; + } + // potential match for QLinearMatMul or MatMulIntegerToFloat bool qlinear = !q_nodes.empty(); @@ -299,6 +363,11 @@ bool GemmNodeGroupSelector::Check(const GraphViewer& graph_viewer, } } + // 16-bit int types must be explicitly allowed. + if (!allow_16bit_ && (Is16BitIntType(dt_A) || Is16BitIntType(dt_B))) { + return false; + } + if (dq_nodes.size() < 3) { // no bias return true; } @@ -326,27 +395,68 @@ bool WhereNodeGroupSelector::Check(const GraphViewer& graph_viewer, const Node& const int32_t dt_input_1 = dq_nodes[0]->InputDefs()[0]->TypeAsProto()->tensor_type().elem_type(); const int32_t dt_input_2 = dq_nodes[1]->InputDefs()[0]->TypeAsProto()->tensor_type().elem_type(); const int32_t dt_output = q_nodes[0]->OutputDefs()[0]->TypeAsProto()->tensor_type().elem_type(); - return dt_input_1 == dt_input_2 && - dt_input_1 == dt_output; + + // All input and output types must match. + if (dt_input_1 != dt_input_2 || dt_input_1 != dt_output) { + return false; + } + + // 16-bit int types must be explicitly allowed. + if (!allow_16bit_ && Is16BitIntType(dt_input_1)) { + return false; + } + + return true; +} + +bool PadNodeGroupSelector::Check(const GraphViewer& graph_viewer, const Node& node, + const std::vector& dq_nodes, + const std::vector& q_nodes) const { + // Pad can have 1 or 2 dq input, the optional input constant_value can be quantized or non-quantized. + // QNN supports data input quantized with constant_value input non-quantized. + int num_dq_inputs = static_cast(dq_nodes.size()); + if (num_dq_inputs > 2) { + return false; + } + + if (!CheckQDQNodes(graph_viewer, node, dq_nodes, q_nodes, num_dq_inputs)) { + return false; + } + + const int32_t dt_input_1 = dq_nodes[0]->InputDefs()[0]->TypeAsProto()->tensor_type().elem_type(); + const int32_t dt_output = q_nodes[0]->OutputDefs()[0]->TypeAsProto()->tensor_type().elem_type(); + if (dq_nodes.size() > 1) { + const int32_t dt_input_2 = dq_nodes[1]->InputDefs()[0]->TypeAsProto()->tensor_type().elem_type(); + return dt_input_1 == dt_input_2 && + dt_input_1 == dt_output; + } else { + return dt_input_1 == dt_output; + } } -bool InstanceNormalizationNodeGroupSelector::Check(const GraphViewer& graph_viewer, - const Node& node, - const std::vector& dq_nodes, - const std::vector& q_nodes) const { +bool InstanceAndLayerNormalizationNodeGroupSelector::Check(const GraphViewer& graph_viewer, + const Node& node, + const std::vector& dq_nodes, + const std::vector& q_nodes) const { if (!CheckQDQNodes(graph_viewer, node, dq_nodes, q_nodes)) { return false; } int32_t dt_input = dq_nodes[0]->InputDefs()[0]->TypeAsProto()->tensor_type().elem_type(); int32_t dt_scale = dq_nodes[1]->InputDefs()[0]->TypeAsProto()->tensor_type().elem_type(); - int32_t dt_bias = dq_nodes[2]->InputDefs()[0]->TypeAsProto()->tensor_type().elem_type(); + int32_t dt_bias = 0; + bool has_bias = false; + // bias is optional for LayerNorm + if (dq_nodes.size() > 2) { + has_bias = true; + dt_bias = dq_nodes[2]->InputDefs()[0]->TypeAsProto()->tensor_type().elem_type(); + } int32_t dt_output = q_nodes[0]->OutputDefs()[0]->TypeAsProto()->tensor_type().elem_type(); // Input, output, and scale need to be the same type. The bias is int32. return (dt_input == dt_output) && (dt_input == dt_scale) && - (dt_bias == ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_INT32); + (has_bias ? dt_bias == ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_INT32 : true); } bool BatchNormalizationNodeGroupSelector::Check(const GraphViewer& graph_viewer, @@ -373,6 +483,55 @@ bool BatchNormalizationNodeGroupSelector::Check(const GraphViewer& graph_viewer, return true; } +bool LogicalComparisonNodeGroupSelector::Check(const GraphViewer& graph_viewer, + const Node& node, + const std::vector& dq_nodes, + const std::vector& q_nodes) const { + if (!CheckQDQNodes(graph_viewer, node, dq_nodes, q_nodes, -1, true)) { + return false; + } + + int32_t dt_input_1 = dq_nodes[0]->InputDefs()[0]->TypeAsProto()->tensor_type().elem_type(); + int32_t dt_input_2 = dq_nodes[1]->InputDefs()[0]->TypeAsProto()->tensor_type().elem_type(); + return dt_input_1 == dt_input_2; +} + +bool TopKNodeGroupSelector::Check(const GraphViewer& graph_viewer, + const Node& node, + const std::vector& dq_nodes, + const std::vector& q_nodes) const { + constexpr int num_dq_inputs = 1; + constexpr int num_q_outputs = 1; + if (num_dq_inputs != gsl::narrow_cast(dq_nodes.size())) { + return false; + } + + if (const auto dq_validation_status = QDQ::ValidateNodeGroupDQNodes(graph_viewer, node, dq_nodes); + !dq_validation_status.IsOK()) { + return false; + } + + if (num_q_outputs != gsl::narrow_cast(q_nodes.size())) { + return false; + } + + const Node& dq_node = *dq_nodes.front(); + const Node& q_node = *q_nodes.front(); + + int32_t dt_input = dq_node.InputDefs()[0]->TypeAsProto()->tensor_type().elem_type(); + int32_t dt_output = q_node.OutputDefs()[0]->TypeAsProto()->tensor_type().elem_type(); + + if (dt_input != dt_output) { + return false; + } + + auto get_const_initializer = [&graph_viewer](const std::string& initializer_name) { + return graph_viewer.GetConstantInitializer(initializer_name, true); + }; + + return IsQDQPairSupported(q_node, dq_node, get_const_initializer, graph_viewer.ModelPath()); +} + } // namespace QDQ } // namespace onnxruntime diff --git a/onnxruntime/core/optimizer/qdq_transformer/selectors_actions/qdq_selectors.h b/onnxruntime/core/optimizer/qdq_transformer/selectors_actions/qdq_selectors.h index c9d2b9bebf869..be7f7e0288eda 100644 --- a/onnxruntime/core/optimizer/qdq_transformer/selectors_actions/qdq_selectors.h +++ b/onnxruntime/core/optimizer/qdq_transformer/selectors_actions/qdq_selectors.h @@ -52,45 +52,75 @@ class NodeGroupSelector { // Single DQ -> node that does not change data -> Q. // Zero point and scale are constant scalars and must match class DropQDQNodeGroupSelector : public NodeGroupSelector { + public: + explicit DropQDQNodeGroupSelector(bool allow_16bit = true) : allow_16bit_(allow_16bit) {} + + private: bool Check(const GraphViewer& graph_viewer, const Node& node, const std::vector& dq_nodes, const std::vector& q_nodes) const override; + + bool allow_16bit_; }; // Single DQ -> node. class DropDQNodeGroupSelector : public NodeGroupSelector { + public: + explicit DropDQNodeGroupSelector(bool allow_16bit = true) : allow_16bit_(allow_16bit) {} + + private: bool Check(const GraphViewer& graph_viewer, const Node& node, const std::vector& dq_nodes, const std::vector& q_nodes) const override; + + bool allow_16bit_; }; // single input. default is to only support uint8. class UnaryNodeGroupSelector : public NodeGroupSelector { + public: + explicit UnaryNodeGroupSelector(bool allow_16bit = true) : allow_16bit_(allow_16bit) {} + + private: bool Check(const GraphViewer& graph_viewer, const Node& node, const std::vector& dq_nodes, const std::vector& q_nodes) const override; + + bool allow_16bit_; }; // 2 DQ nodes providing input -> node -> Q class BinaryNodeGroupSelector : public NodeGroupSelector { + public: + explicit BinaryNodeGroupSelector(bool allow_16bit = true) : allow_16bit_(allow_16bit) {} + + private: bool Check(const GraphViewer& graph_viewer, const Node& node, const std::vector& dq_nodes, const std::vector& q_nodes) const override; + + bool allow_16bit_; }; // Variadic DQ nodes -> node -> Q class VariadicNodeGroupSelector : public NodeGroupSelector { + public: + explicit VariadicNodeGroupSelector(bool allow_16bit = true) : allow_16bit_(allow_16bit) {} + private: bool Check(const GraphViewer& graph_viewer, const Node& node, const std::vector& dq_nodes, const std::vector& q_nodes) const override; + + bool allow_16bit_; }; // DQ nodes for X, W and optionally B -> node -> Q class ConvNodeGroupSelector : public NodeGroupSelector { public: // default to 'true' - ConvNodeGroupSelector(bool int8_allowed = true) : int8_allowed_(int8_allowed) {} + ConvNodeGroupSelector(bool int8_allowed = true, bool allow_16bit = true) + : int8_allowed_(int8_allowed), allow_16bit_(allow_16bit) {} private: bool Check(const GraphViewer& graph_viewer, const Node& node, @@ -98,11 +128,25 @@ class ConvNodeGroupSelector : public NodeGroupSelector { const std::vector& q_nodes) const override; bool int8_allowed_; + bool allow_16bit_; }; class WhereNodeGroupSelector : public NodeGroupSelector { public: - WhereNodeGroupSelector() = default; + explicit WhereNodeGroupSelector(bool allow_16bit = true) + : allow_16bit_(allow_16bit) {} + + private: + bool Check(const GraphViewer& graph_viewer, const Node& node, + const std::vector& dq_nodes, + const std::vector& q_nodes) const override; + + bool allow_16bit_; +}; + +class PadNodeGroupSelector : public NodeGroupSelector { + public: + PadNodeGroupSelector() = default; private: bool Check(const GraphViewer& graph_viewer, const Node& node, @@ -115,9 +159,11 @@ class WhereNodeGroupSelector : public NodeGroupSelector { class MatMulNodeGroupSelector : public NodeGroupSelector { public: MatMulNodeGroupSelector(bool int8_allowed = true, - bool matmulintegertofloat_allowed = false) + bool matmulintegertofloat_allowed = false, + bool allow_16bit = true) : int8_allowed_(int8_allowed), - matmulintegertofloat_allowed_(matmulintegertofloat_allowed) { + matmulintegertofloat_allowed_(matmulintegertofloat_allowed), + allow_16bit_(allow_16bit) { } private: @@ -126,20 +172,26 @@ class MatMulNodeGroupSelector : public NodeGroupSelector { const std::vector& q_nodes) const override; bool int8_allowed_; bool matmulintegertofloat_allowed_; + bool allow_16bit_; }; // Input: DQ nodes for A, B and optional C // Output: optional Q node for Y class GemmNodeGroupSelector : public NodeGroupSelector { + public: + explicit GemmNodeGroupSelector(bool allow_16bit = true) : allow_16bit_(allow_16bit) {} + private: bool Check(const GraphViewer& graph_viewer, const Node& node, const std::vector& dq_nodes, const std::vector& q_nodes) const override; + + bool allow_16bit_; }; // Input: DQ nodes for input, scale, and B // Output: Q node for output -class InstanceNormalizationNodeGroupSelector : public NodeGroupSelector { +class InstanceAndLayerNormalizationNodeGroupSelector : public NodeGroupSelector { private: bool Check(const GraphViewer& graph_viewer, const Node& node, const std::vector& dq_nodes, @@ -160,6 +212,22 @@ class BatchNormalizationNodeGroupSelector : public NodeGroupSelector { bool int8_allowed_; }; +// 2 DQ nodes providing input -> node with bool output tensor. +// Example: Equal, Less, Greater. +class LogicalComparisonNodeGroupSelector : public NodeGroupSelector { + bool Check(const GraphViewer& graph_viewer, const Node& node, + const std::vector& dq_nodes, + const std::vector& q_nodes) const override; +}; + +// TopK has 1 DQ input node and 1 Q output node. +// Zero point and scale are constant scalars and must match +class TopKNodeGroupSelector : public NodeGroupSelector { + bool Check(const GraphViewer& graph_viewer, const Node& node, + const std::vector& dq_nodes, + const std::vector& q_nodes) const override; +}; + /* * NodeSelector instances for use in the QDQ::SelectorActionTransformer. */ @@ -189,28 +257,33 @@ class BaseSelector : public NodeSelector { class DropQDQNodesSelector : public BaseSelector { public: - DropQDQNodesSelector() : BaseSelector(std::make_unique()) {} + explicit DropQDQNodesSelector(bool allow_16bit = false) + : BaseSelector(std::make_unique(allow_16bit)) {} }; class DropDQNodesSelector : public BaseSelector { public: - DropDQNodesSelector() : BaseSelector(std::make_unique()) {} + explicit DropDQNodesSelector(bool allow_16bit = false) + : BaseSelector(std::make_unique(allow_16bit)) {} }; class UnarySelector : public BaseSelector { public: - UnarySelector() : BaseSelector(std::make_unique()) {} + explicit UnarySelector(bool allow_16bit = false) + : BaseSelector(std::make_unique(allow_16bit)) {} }; class BinarySelector : public BaseSelector { public: - BinarySelector() : BaseSelector(std::make_unique()) {} + explicit BinarySelector(bool allow_16bit = false) + : BaseSelector(std::make_unique(allow_16bit)) {} }; // Variadic DQ nodes -> node -> Q class InputVariadicSelector : public BaseSelector { public: - InputVariadicSelector() : BaseSelector(std::make_unique()) {} + explicit InputVariadicSelector(bool allow_16bit = false) + : BaseSelector(std::make_unique(allow_16bit)) {} void UpdateBuilder(NodesToOptimizeIndicesBuilder&) const override; }; @@ -226,46 +299,36 @@ class OutputVariadicSelector : public BaseSelector { // DQ nodes for X, W and optionally B -> node -> Q class ConvSelector : public BaseSelector { public: - ConvSelector(bool int8_allowed = false) : BaseSelector(std::make_unique(int8_allowed)) {} + ConvSelector(bool int8_allowed = false, bool allow_16bit = false) + : BaseSelector(std::make_unique(int8_allowed, allow_16bit)) {} void UpdateBuilder(NodesToOptimizeIndicesBuilder&) const override; }; + class WhereSelector : public BaseSelector { public: - WhereSelector() : BaseSelector(std::make_unique()) {} + explicit WhereSelector(bool allow_16bit = false) + : BaseSelector(std::make_unique(allow_16bit)) {} }; + // 2 DQ nodes for input -> node -> optional Q if QLinearMatMul, MatMulIntegerToFloat if not class MatMulSelector : public BaseSelector { public: - MatMulSelector(bool int8_allowed) - : BaseSelector(std::make_unique(int8_allowed, /*matmulintegertofloat_allowed*/ true)) {} + MatMulSelector(bool int8_allowed, bool allow_16bit = false) + : BaseSelector(std::make_unique(int8_allowed, /*matmulintegertofloat_allowed*/ true, + allow_16bit)) {} }; // Input: DQ nodes for A, B and optional C // Output: optional Q node for Y class GemmSelector : public BaseSelector { public: - GemmSelector() - : BaseSelector(std::make_unique()) {} + explicit GemmSelector(bool allow_16bit = false) + : BaseSelector(std::make_unique(allow_16bit)) {} void UpdateBuilder(NodesToOptimizeIndicesBuilder&) const override; }; -// Input: DQ nodes for input, scale, and B (bias) -// Output: Q node for output -class InstanceNormalizationSelector : public BaseSelector { - public: - InstanceNormalizationSelector() - : BaseSelector(std::make_unique()) {} -}; - -// DQ nodes for X, W and optionally B, (mean, var not required) -> node -> Q -class BatchNormalizationSelector : public BaseSelector { - public: - BatchNormalizationSelector(bool int8_allowed = false) - : BaseSelector(std::make_unique(int8_allowed)) {} -}; - } // namespace QDQ } // namespace onnxruntime diff --git a/onnxruntime/core/optimizer/qdq_transformer/selectors_actions/shared/utils.cc b/onnxruntime/core/optimizer/qdq_transformer/selectors_actions/shared/utils.cc index 895524aea30b3..3f1b2f0458bc0 100644 --- a/onnxruntime/core/optimizer/qdq_transformer/selectors_actions/shared/utils.cc +++ b/onnxruntime/core/optimizer/qdq_transformer/selectors_actions/shared/utils.cc @@ -36,12 +36,19 @@ static const OpVersionsAndSelector::OpVersionsMap GetMiscOpVersionsMap() { {"Resize", {}}, {"Split", {}}, {"Squeeze", {}}, - {"Unsqueeze", {}}}; + {"Unsqueeze", {}}, + {"Tile", {}}}; +} + +static const OpVersionsAndSelector::OpVersionsMap GetDropDQOpVersionsMap() { + return {{"ArgMax", {}}, + {"ArgMin", {}}}; } static const OpVersionsAndSelector::OpVersionsMap GetUnaryOpVersionsMap() { return {{"AveragePool", {}}, {"GlobalAveragePool", {}}, + {"GlobalMaxPool", {}}, {"LeakyRelu", {}}, {"ReduceMean", {}}, {"ReduceMin", {}}, @@ -54,21 +61,40 @@ static const OpVersionsAndSelector::OpVersionsMap GetUnaryOpVersionsMap() { {"HardSwish", {}}, {"Sigmoid", {}}, {"Slice", {}}, + {"LogSoftmax", {}}, {"Softmax", {}}, {"Sqrt", {}}, {"Atan", {}}, + {"Asin", {}}, + {"Sin", {}}, + {"Cos", {}}, + {"Sign", {}}, {"Tanh", {}}, - {"Exp", {}}}; + {"Exp", {}}, + {"Log", {}}, + {"LRN", {}}, + {"Ceil", {}}, + {"Floor", {}}, + {"Round", {}}, + {"Abs", {}}, + {"Neg", {}}, + {"DepthToSpace", {}}, + {"SpaceToDepth", {}}, + {"Clip", {}}}; } static const OpVersionsAndSelector::OpVersionsMap GetBinaryOpVersionsMap() { return {{"Add", {}}, {"Div", {}}, {"Mul", {}}, {"Pow", {}}, - {"Sub", {}}}; + {"Sub", {}}, + {"PRelu", {}}, + {"GridSample", {}}}; } static const OpVersionsAndSelector::OpVersionsMap GetVariadicOpVersionsMap() { - return {{"Concat", {}}}; + return {{"Concat", {}}, + {"Max", {}}, + {"Min", {}}}; } static const OpVersionsAndSelector::OpVersionsMap GetConvOpVersionsMap() { return {{"Conv", {}}}; @@ -82,12 +108,30 @@ static const OpVersionsAndSelector::OpVersionsMap GetMatMulOpVersionsMap() { static const OpVersionsAndSelector::OpVersionsMap GetGemmOpVersionsMap() { return {{"Gemm", {}}}; } -static const OpVersionsAndSelector::OpVersionsMap GetInstanceNormalizationOpVersionsMap() { - return {{"InstanceNormalization", {}}}; +static const OpVersionsAndSelector::OpVersionsMap GetInstanceAndLayerNormalizationOpVersionsMap() { + return {{"InstanceNormalization", {}}, + {"LayerNormalization", {}}}; } static const OpVersionsAndSelector::OpVersionsMap GetBatchNormalizationOpVersionsMap() { return {{"BatchNormalization", {}}}; } +static const OpVersionsAndSelector::OpVersionsMap GetLogicalComparisonOpVersionsMap() { + return {{"Equal", {}}, + {"Greater", {}}, + {"GreaterOrEqual", {}}, + {"Less", {}}, + {"LessOrEqual", {}}}; +} +static const OpVersionsAndSelector::OpVersionsMap GetWhereOpVersionsMap() { + return {{"Where", {}}}; +} +static const OpVersionsAndSelector::OpVersionsMap GetPadOpVersionsMap() { + return {{"Pad", {}}}; +} + +static const OpVersionsAndSelector::OpVersionsMap GetTopKOpVersionsMap() { + return {{"TopK", {}}}; +} /* Selector rules registration related */ void RegisterMiscSelectors(Selectors& qdq_selectors) { @@ -97,6 +141,13 @@ void RegisterMiscSelectors(Selectors& qdq_selectors) { std::move(selector)); } +void RegisterDropDQSelectors(Selectors& qdq_selectors) { + /* register selectors for ops that have a sigle DQ -> node */ + std::unique_ptr selector = std::make_unique(); + qdq_selectors.RegisterSelector(GetDropDQOpVersionsMap(), + std::move(selector)); +} + void RegisterUnarySelectors(Selectors& qdq_selectors) { /* regsiter selectors for unary ops */ std::unique_ptr selector = std::make_unique(); @@ -147,10 +198,10 @@ void RegisterGemmSelector(Selectors& qdq_selectors) { std::move(selector)); } -void RegisterInstanceNormalizationSelector(Selectors& qdq_selectors) { +void RegisterInstanceAndLayerNormalizationSelector(Selectors& qdq_selectors) { /* register selector for InstanceNormalization op */ - std::unique_ptr selector = std::make_unique(); - qdq_selectors.RegisterSelector(GetInstanceNormalizationOpVersionsMap(), + std::unique_ptr selector = std::make_unique(); + qdq_selectors.RegisterSelector(GetInstanceAndLayerNormalizationOpVersionsMap(), std::move(selector)); } @@ -161,8 +212,37 @@ void RegisterBatchNormalizationSelector(Selectors& qdq_selectors) { std::move(selector)); } +void RegisterLogicalComparisonSelectors(Selectors& qdq_selectors) { + /* register selectors for logical comparison ops */ + std::unique_ptr selector = std::make_unique(); + qdq_selectors.RegisterSelector(GetLogicalComparisonOpVersionsMap(), + std::move(selector)); +} + +void RegisterWhereSelectors(Selectors& qdq_selectors) { + /* register selectors for Where ops */ + std::unique_ptr selector = std::make_unique(); + qdq_selectors.RegisterSelector(GetWhereOpVersionsMap(), + std::move(selector)); +} + +void RegisterPadSelectors(Selectors& qdq_selectors) { + /* register selectors for Pad ops */ + std::unique_ptr selector = std::make_unique(); + qdq_selectors.RegisterSelector(GetPadOpVersionsMap(), + std::move(selector)); +} + +void RegisterTopKSelector(Selectors& qdq_selectors) { + /* register selector for TopK op */ + std::unique_ptr selector = std::make_unique(); + qdq_selectors.RegisterSelector(GetTopKOpVersionsMap(), + std::move(selector)); +} + void SelectorManager::CreateSelectors() { RegisterMiscSelectors(qdq_selectors_); + RegisterDropDQSelectors(qdq_selectors_); RegisterUnarySelectors(qdq_selectors_); RegisterBinarySelectors(qdq_selectors_); RegisterVariadicSelectors(qdq_selectors_); @@ -170,8 +250,12 @@ void SelectorManager::CreateSelectors() { RegisterConvTransposeSelector(qdq_selectors_); RegisterMatMulSelector(qdq_selectors_); RegisterGemmSelector(qdq_selectors_); - RegisterInstanceNormalizationSelector(qdq_selectors_); + RegisterInstanceAndLayerNormalizationSelector(qdq_selectors_); RegisterBatchNormalizationSelector(qdq_selectors_); + RegisterLogicalComparisonSelectors(qdq_selectors_); + RegisterWhereSelectors(qdq_selectors_); + RegisterPadSelectors(qdq_selectors_); + RegisterTopKSelector(qdq_selectors_); } void SelectorManager::InitializeSelectorsMap() { diff --git a/onnxruntime/core/optimizer/qdq_transformer/selectors_actions/shared/utils.h b/onnxruntime/core/optimizer/qdq_transformer/selectors_actions/shared/utils.h index c64f40d0dd227..246f26c1760ec 100644 --- a/onnxruntime/core/optimizer/qdq_transformer/selectors_actions/shared/utils.h +++ b/onnxruntime/core/optimizer/qdq_transformer/selectors_actions/shared/utils.h @@ -10,7 +10,7 @@ #include "core/graph/basic_types.h" #if !defined(ORT_MINIMAL_BUILD) -#include "onnx/defs/schema.h" +#include "core/graph/onnx_protobuf.h" #endif namespace onnxruntime { @@ -85,4 +85,4 @@ Status ValidateNodeGroupDQNodes(const GraphViewer& graph_viewer, gsl::span dq_nodes); } // namespace QDQ -} // namespace onnxruntime \ No newline at end of file +} // namespace onnxruntime diff --git a/onnxruntime/core/optimizer/reshape_fusion.cc b/onnxruntime/core/optimizer/reshape_fusion.cc index c6e52299ca123..7768a835d5042 100644 --- a/onnxruntime/core/optimizer/reshape_fusion.cc +++ b/onnxruntime/core/optimizer/reshape_fusion.cc @@ -50,7 +50,10 @@ Status ReshapeFusion::ApplyImpl(Graph& graph, bool& modified, int graph_level, c modified = true; } } - LOGS(logger, INFO) << "Total fused reshape node count: " << fused_count; + + if (fused_count > 0) { + LOGS(logger, INFO) << "Total fused reshape node count: " << fused_count; + } return Status::OK(); } diff --git a/onnxruntime/core/optimizer/selectors_actions/selector_action_transformer.cc b/onnxruntime/core/optimizer/selectors_actions/selector_action_transformer.cc index 540e0e92d30cd..e182b6c695d2f 100644 --- a/onnxruntime/core/optimizer/selectors_actions/selector_action_transformer.cc +++ b/onnxruntime/core/optimizer/selectors_actions/selector_action_transformer.cc @@ -93,9 +93,10 @@ static Status MatchAndProcess( Status status = Status::OK(); do { - // TODO: for now this just needs to support ONNX ops. If we ever had a transformer that was going to - // target non-ONNX ops we'd need to rework a few things to include the op domain in the matches - if (node.Domain() != kOnnxDomain) { + // TODO: for now this just needs to support ONNX and Micrsoft Domain ops. + // If we ever had a transformer that was going to target non-ONNX ops, + // we'd need to rework a few things to include the op domain in the matches + if (node.Domain() != kOnnxDomain && node.Domain() != kMSDomain) { break; } diff --git a/onnxruntime/core/optimizer/skip_layer_norm_fusion.cc b/onnxruntime/core/optimizer/skip_layer_norm_fusion.cc index ba2f1ea52fcc9..cf70a7d821d72 100644 --- a/onnxruntime/core/optimizer/skip_layer_norm_fusion.cc +++ b/onnxruntime/core/optimizer/skip_layer_norm_fusion.cc @@ -12,7 +12,8 @@ using namespace onnxruntime::common; namespace onnxruntime { // LayerNorm supports limited data types. -static constexpr std::array supported_data_types{"tensor(float16)", "tensor(float)", "tensor(bfloat16)"}; +static constexpr std::array supported_data_types{ + "tensor(float16)", "tensor(float)", "tensor(bfloat16)"}; static bool IsSupportedDataType(const Node& node) { for (const auto& input_arg : node.InputDefs()) { diff --git a/onnxruntime/core/optimizer/transpose_optimization/ReadMe.md b/onnxruntime/core/optimizer/transpose_optimization/ReadMe.md new file mode 100644 index 0000000000000..673723cda88c6 --- /dev/null +++ b/onnxruntime/core/optimizer/transpose_optimization/ReadMe.md @@ -0,0 +1,6 @@ +Generic transpose optimizer that has an abstraction layer so it is independent of the ORT implementation. + +optimizer_api.h: Defines the API for the abstraction layer +ort_optimizer_api_impl.*: ORT implementation of the abstraction layer +transpose_optimizer.*: Generic implementation of logic to be able to move a Transpose node past another node. +ort_transpose_optimizer.*: ORT specific extensions to transpose optimization. diff --git a/onnxruntime/core/optimizer/transpose_optimizer/transpose_optimizer.cc b/onnxruntime/core/optimizer/transpose_optimization/onnx_transpose_optimization.cc similarity index 85% rename from onnxruntime/core/optimizer/transpose_optimizer/transpose_optimizer.cc rename to onnxruntime/core/optimizer/transpose_optimization/onnx_transpose_optimization.cc index 358c89f1c9f95..2c11bf144999e 100644 --- a/onnxruntime/core/optimizer/transpose_optimizer/transpose_optimizer.cc +++ b/onnxruntime/core/optimizer/transpose_optimization/onnx_transpose_optimization.cc @@ -1,54 +1,19 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "optimizer_api.h" +#include "onnx_transpose_optimization.h" #include #include #include #include +#include #include "core/common/gsl.h" #include "core/common/make_string.h" #include "core/graph/constants.h" -namespace onnx_layout_transformation { - -struct OptimizerCtx { - int64_t opset; - api::GraphRef& graph; - bool allow_extended_ops; - CostCheckFn cost_check_fn; - const std::string provider_type; - OptimizerMode mode; - std::unordered_set layout_sensitive_ops; -}; - -// Each op handler points to a (potentially shared) function for determining which input indices are eligible for -// optimization. Handlers are only called if a transpose is on an eligible index, and if the optimization heuristics -// predict that pushing the transpose will be beneficial. Most of the time this function returns a static value, but -// for Sum/Concat/QLinearConcat it needs to be dynamic. -using TransposibleInputsFn = std::vector (*)(OptimizerCtx& ctx, api::NodeRef& node); - -// Struct containing information passed to op handlers. Decreases binary size and allows perm_inv to be precomputed. -struct HandlerArgs { - OptimizerCtx& ctx; - api::NodeRef& transpose; - api::NodeRef& node; - const std::vector& perm; - const std::vector& perm_inv; - // Cached result from calling transposible_inputs_fn - std::vector& transposible_inputs; -}; - -using HandlerFunction = bool (*)(HandlerArgs& args); - -struct HandlerInfo { - TransposibleInputsFn transposible_inputs_fn; - HandlerFunction handler_fn; - // Does the handler have to transpose outputs? Used for cost estimation. - bool transposes_outputs = true; -}; +namespace onnx_transpose_optimization { /////// /////// /* Small utilities for editing nodes and manipulating axes/permutations */ @@ -198,7 +163,7 @@ static std::optional> ReadFromAttrOrInput(OptimizerCtx& ctx } // Computes inverse permutation. Unsafe if perm is not a valid permutation. -static std::vector InvertPerm(const std::vector& perm) { +std::vector InvertPerm(const std::vector& perm) { size_t rank = perm.size(); std::vector perm_inv(rank); for (size_t i = 0; i < rank; ++i) { @@ -488,8 +453,8 @@ static void Permute1DConstant(api::GraphRef& graph, api::NodeRef& node, api::Ten // Replaces ith input to node with transposed value. Might create a new Transpose node, find an existing one, // or transpose an initializer. -static void TransposeInput(api::GraphRef& graph, api::NodeRef& node, size_t i, - const std::vector& perm, const std::vector& perm_inv) { +void TransposeInput(api::GraphRef& graph, api::NodeRef& node, size_t i, + const std::vector& perm, const std::vector& perm_inv) { std::string_view input = node.Inputs()[i]; // Remove this node as a consumer node.SetInput(i, ""); @@ -610,25 +575,20 @@ static bool NormalizeInputRanks(OptimizerCtx ctx, api::NodeRef& node, size_t tar // Transposes specified inputs according to perm. // NOTE: if a Transpose is expected to be above an input to this node, use the inverse of its permutation to cancel it. -static void TransposeInputs(OptimizerCtx& ctx, api::NodeRef& node, const std::vector& perm, - const std::vector& input_indices) { +void TransposeInputs(OptimizerCtx& ctx, api::NodeRef& node, const std::vector& perm, + const std::vector& input_indices) { auto perm_inv = InvertPerm(perm); for (size_t j : input_indices) { TransposeInput(ctx.graph, node, j, perm, perm_inv); } } -inline static void TransposeFirstInput(OptimizerCtx& ctx, api::NodeRef& node, const std::vector& perm) { - std::vector indices{0}; - TransposeInputs(ctx, node, perm, indices); -} - // Inserts a Transpose op on the ith output of a node. Returns the new, transposed output. // Updates shape information assuming that the output from the node will have a transposed shape (using perm_inv) // but the overall (returned) output will match the initial shape. -static std::string_view TransposeOutput(api::GraphRef& graph, api::NodeRef& node, size_t i, - const std::vector& perm, - const std::vector& perm_inv) { +std::string_view TransposeOutput(api::GraphRef& graph, api::NodeRef& node, size_t i, + const std::vector& perm, + const std::vector& perm_inv) { // Make transpose without input initially, then add it to avoid cyclic reference. // X -> Node -> Y, Transpose @@ -650,10 +610,11 @@ static std::string_view TransposeOutput(api::GraphRef& graph, api::NodeRef& node // Inserts a Transpose op on all node outputs and updates the shapes of the node outputs. Skips if perm is identity. // See TransposeOutput for details on shape updates. -static void TransposeOutputs(OptimizerCtx& ctx, api::NodeRef& node, const std::vector& perm) { +void TransposeOutputs(OptimizerCtx& ctx, api::NodeRef& node, const std::vector& perm) { if (IsIdentityPerm(perm)) { return; } + auto perm_inv = InvertPerm(perm); for (size_t j = 0; j < node.Outputs().size(); ++j) { TransposeOutput(ctx.graph, node, j, perm, perm_inv); @@ -692,16 +653,17 @@ static int EstimateValueRank(const api::GraphRef& graph, std::string_view input) return rank; } -static const HandlerInfo* GetHandler(api::NodeRef& node, bool allow_extended_ops); +static const HandlerInfo* GetHandler(api::NodeRef& node, const HandlerMap& extended_handlers); // Returns true if the provided transpose node is only consumed by nodes we can likely push it through. -static bool CanLikelyRemoveTranspose(const api::GraphRef& graph, api::NodeRef& transpose) { +static bool CanLikelyRemoveTranspose(const api::GraphRef& graph, api::NodeRef& transpose, + const HandlerMap& extended_handlers) { auto consumers = graph.GetValueConsumers(transpose.Outputs()[0]); if (!consumers->comprehensive) { return false; } for (auto& node : consumers->nodes) { - if (GetHandler(*node, true) == nullptr) { + if (GetHandler(*node, extended_handlers) == nullptr) { return false; } } @@ -711,7 +673,8 @@ static bool CanLikelyRemoveTranspose(const api::GraphRef& graph, api::NodeRef& t // Estimates the cost of transposing an input. Currently uses rank heuristic. Negative if transpose is removed. // Feel free to improve as needed. static int EstimateTransposeValueCost(const api::GraphRef& graph, std::string_view input, - const std::vector& perm_inv) { + const std::vector& perm_inv, + const HandlerMap& extended_handlers) { // Case 1: Transposing constants probably costs nothing. std::unique_ptr constant = graph.GetConstant(input); if (constant != nullptr) { @@ -723,7 +686,7 @@ static int EstimateTransposeValueCost(const api::GraphRef& graph, std::string_vi if (node != nullptr && node->IsOp("Transpose")) { std::optional> perm2 = GetPermAttrIfValid(*node); if (perm2 != std::nullopt) { - if (*perm2 == perm_inv && CanLikelyRemoveTranspose(graph, *node)) { + if (*perm2 == perm_inv && CanLikelyRemoveTranspose(graph, *node, extended_handlers)) { return -EstimateValueRank(graph, input); } else { return 0; @@ -738,11 +701,12 @@ static int EstimateTransposeValueCost(const api::GraphRef& graph, std::string_vi // Estimates total cost of transposing a node's inputs. Negative if transposing is beneficial. static int EstimateTransposeInputsCost(const api::GraphRef& graph, const api::NodeRef& node, const std::vector& perm_inv, - const std::vector& input_indices) { + const std::vector& input_indices, + const HandlerMap& extended_handlers) { auto inputs = node.Inputs(); int cost = 0; for (size_t j : input_indices) { - cost += EstimateTransposeValueCost(graph, inputs[j], perm_inv); + cost += EstimateTransposeValueCost(graph, inputs[j], perm_inv, extended_handlers); } return cost; } @@ -776,7 +740,7 @@ static bool HandleSimpleNodeBase(HandlerArgs& args, bool broadcast_inputs) { } // Transposes all inputs and all outputs -static bool HandleSimpleNode(HandlerArgs& args) { +bool HandleSimpleNode(HandlerArgs& args) { return HandleSimpleNodeBase(args, /*broadcast_inputs*/ false); } @@ -791,17 +755,10 @@ std::vector AllInputs(OptimizerCtx& ctx, api::NodeRef& node) { } constexpr HandlerInfo simple_node_handler = {&AllInputs, &HandleSimpleNode}; - -std::vector FirstInput(OptimizerCtx& ctx, api::NodeRef& node) { - (void)ctx; - (void)node; - return {0}; -} - constexpr HandlerInfo node_1_inp_handler = {&FirstInput, &HandleSimpleNode}; // Node with all inputs broadcastable -static bool HandleSimpleNodeBroadcast(HandlerArgs& args) { +bool HandleSimpleNodeBroadcast(HandlerArgs& args) { return HandleSimpleNodeBase(args, /*broadcast_inputs*/ true); } @@ -821,7 +778,7 @@ std::vector NonScalarInputs(OptimizerCtx& ctx, api::NodeRef& node) { constexpr HandlerInfo broadcast_node_handler = {&NonScalarInputs, &HandleSimpleNodeBroadcast}; // Transposes all inputs and all outputs. Updates axis attribute. -static bool HandleSimpleNodeWithAxis(HandlerArgs& args, std::optional default_axis = std::nullopt) { +bool HandleSimpleNodeWithAxis(HandlerArgs& args, std::optional default_axis /*std::nullopt*/) { size_t rank = args.perm.size(); std::optional axis = args.node.GetAttributeInt("axis"); if (axis == std::nullopt) { @@ -971,7 +928,7 @@ static void PermuteInput(api::GraphRef& graph, api::NodeRef& node, size_t i, con } static bool HandleResize([[maybe_unused]] HandlerArgs& args) { -#if defined(USE_CUDA) || defined(USE_ROCM) || defined(USE_QNN) +#if defined(USE_CUDA) || defined(USE_ROCM) || defined(USE_QNN) || defined(USE_WEBNN) // The CUDA Resize kernel requires that the input is NCHW, so we can't push a Transpose through a Resize // in ORT builds with CUDA enabled. // The ROCm EP is generated from the CUDA EP kernel so the same applies to builds with ROCm enabled. @@ -1088,7 +1045,7 @@ static bool HandleReduceOpWithArg(HandlerArgs& args) { return true; } -static bool HandleReduceOps(HandlerArgs& args) { +bool HandleReduceOps(HandlerArgs& args) { if ((args.node.OpType() == "ReduceSum" && args.ctx.opset < 13) || // or all other reduce operators since opset 18 (args.node.OpType() != "ReduceSum" && args.ctx.opset < 18)) { @@ -1216,29 +1173,37 @@ static bool HandleUnsqueeze(HandlerArgs& args) { constexpr HandlerInfo unsqueeze_handler = {&FirstInput, &HandleUnsqueeze}; -static bool HandleQuantizeDequantizeScale(const api::GraphRef& graph, const std::vector& perm, - api::NodeRef& node, int64_t opset) { - if (opset >= 13) { - size_t rank = perm.size(); - // Update axis in Opset >= 13 if scale/zero_point are non-scalar - auto inputs = node.Inputs(); +bool TransposeQuantizeDequantizeAxis(const api::GraphRef& graph, const std::vector& perm, api::NodeRef& node) { + size_t rank = perm.size(); - auto inp_shape = graph.GetValueInfo(inputs[1])->Shape(); - bool scalar_params = inp_shape.has_value() && inp_shape->size() == 0; + // Update axis if scale/zero_point are non-scalar + auto inputs = node.Inputs(); - if (!scalar_params) { - int64_t axis = node.GetAttributeIntDefault("axis", 1); - if (!NormalizeAndValidateAxis(axis, rank)) { - return false; - } - node.SetAttributeInt("axis", perm[gsl::narrow_cast(axis)]); + auto inp_shape = graph.GetValueInfo(inputs[1])->Shape(); + bool scalar_params = inp_shape.has_value() && inp_shape->size() == 0; + + if (!scalar_params) { + int64_t axis = node.GetAttributeIntDefault("axis", 1); + if (!NormalizeAndValidateAxis(axis, rank)) { + return false; } + node.SetAttributeInt("axis", perm[gsl::narrow_cast(axis)]); } return true; } +static bool HandleQuantizeDequantizeAxis(const api::GraphRef& graph, const std::vector& perm, + api::NodeRef& node, int64_t opset) { + if (opset < 13) { + // no `axis` attribute until opset 13 + return true; + } + + return TransposeQuantizeDequantizeAxis(graph, perm, node); +} + static bool HandleQuantizeDequantizeLinear(HandlerArgs& args) { - if (!HandleQuantizeDequantizeScale(args.ctx.graph, args.perm, args.node, args.ctx.opset)) { + if (!HandleQuantizeDequantizeAxis(args.ctx.graph, args.perm, args.node, args.ctx.opset)) { return false; } @@ -1680,85 +1645,6 @@ static bool HandleReshape(HandlerArgs& args) { constexpr HandlerInfo reshape_handler = {&FirstInput, &HandleReshape, /*transposes_outputs*/ false}; -static bool HandleQLinearConcat(HandlerArgs& args) { - return HandleSimpleNodeWithAxis(args); -} - -std::vector QLinearConcatInputs(OptimizerCtx& ctx, api::NodeRef& node) { - (void)ctx; - std::vector indices; - size_t num_inputs = node.Inputs().size(); - for (size_t i = 2; i < num_inputs; i += 3) { - indices.push_back(i); - } - return indices; -} - -constexpr HandlerInfo q_linear_concat_handler = {&QLinearConcatInputs, &HandleQLinearConcat}; - -static bool HandleQLinearBinaryOp(HandlerArgs& args) { - return HandleSimpleNodeBase(args, /*broadcast_inputs*/ true); -} - -std::vector QLinearBinaryOpInputs(OptimizerCtx& ctx, api::NodeRef& node) { - (void)ctx; - (void)node; - // Inputs are: [A, A_scale, A_zero_point, B, B_scale, B_zero_point, C_scale, C_zero_point], - // we want [A, B]. - return {0, 3}; -} - -constexpr HandlerInfo q_linear_binary_op_handler = {&QLinearBinaryOpInputs, &HandleQLinearBinaryOp}; - -static bool HandleQLinearPoolOp(HandlerArgs& args) { - // Swap between channel first/last variants. Only works for applicable values of perm. - int64_t channels_last = args.node.GetAttributeIntDefault("channels_last", 0); - size_t rank = args.perm.size(); - if (rank < 2) return false; - auto p = ChannelLastToFirstPerm(rank); - if ((!channels_last && args.perm == p) || (channels_last && args.perm_inv == p)) { - args.node.SetAttributeInt("channels_last", 1 - channels_last); - TransposeFirstInput(args.ctx, args.node, args.perm_inv); - TransposeOutputs(args.ctx, args.node, args.perm); - return true; - } - return false; -} - -constexpr HandlerInfo q_linear_pool_op_handler = {&FirstInput, &HandleQLinearPoolOp}; - -static bool HandleMaxPool(HandlerArgs& args) { - // For CPU EP replace with NhwcMaxPool if possible. Only int8 and uint8 dtypes are supported by NhwcMaxPool. - if (args.node.GetExecutionProviderType() != "CPUExecutionProvider") { - return false; - } - - auto outputs = args.node.Outputs(); - if (outputs.size() == 2 && outputs[1] != "") { - // Can't optimize if optional "indices" output is provided - return false; - } - - auto info = args.ctx.graph.GetValueInfo(outputs[0]); - api::DataType dtype = info->DType(); - if (dtype != api::DataType::UINT8 && dtype != api::DataType::INT8) { - return false; - } - - size_t rank = args.perm.size(); - if (args.perm != ChannelLastToFirstPerm(rank)) { - return false; - } - - auto new_node = SwapNodeOpTypeDomainAndSinceVersion(args.ctx.graph, args.node, "NhwcMaxPool", "com.microsoft", 1); - new_node->ClearAttribute("storage_order"); // Only relevant for indices output. Prohibited for NhwcMaxPool. - TransposeFirstInput(args.ctx, *new_node, args.perm_inv); - TransposeOutputs(args.ctx, *new_node, args.perm); - return true; -} - -constexpr HandlerInfo max_pool_op_handler = {&FirstInput, &HandleMaxPool}; - // TODO: check binary size of this and replace it with constexpr if large static const std::unordered_map handler_map{ {"Cast", simple_node_handler}, @@ -1863,39 +1749,36 @@ static const std::unordered_map handler_ma {"Reshape", reshape_handler}, }; -static const std::unordered_map extended_handler_map{ - {"com.microsoft.QLinearReduceMean", reduce_op_handler}, - {"com.microsoft.QLinearSigmoid", node_1_inp_handler}, - {"com.microsoft.QLinearLeakyRelu", node_1_inp_handler}, - {"com.microsoft.QLinearConcat", q_linear_concat_handler}, - {"com.microsoft.QLinearAdd", q_linear_binary_op_handler}, - {"com.microsoft.QLinearMul", q_linear_binary_op_handler}, - {"com.microsoft.QLinearAveragePool", q_linear_pool_op_handler}, - {"com.microsoft.QLinearGlobalAveragePool", q_linear_pool_op_handler}, - {"MaxPool", max_pool_op_handler}, -}; +constexpr bool IsOnnxDomain(std::string_view domain) { + return (domain == onnxruntime::kOnnxDomain) || (domain == onnxruntime::kOnnxDomainAlias); +} -static const HandlerInfo* GetHandler(api::NodeRef& node, bool allow_extended_ops) { +constexpr bool IsMSDomain(std::string_view domain) { + return domain == onnxruntime::kMSDomain; +} + +static const HandlerInfo* GetHandler(api::NodeRef& node, const HandlerMap& extended_handlers) { std::string key; auto domain = node.Domain(); auto op_type = node.OpType(); - if (domain == onnxruntime::kOnnxDomain || domain == onnxruntime::kOnnxDomainAlias) { + + if (IsOnnxDomain(domain)) { key = std::string(op_type); - } else if (domain == onnxruntime::kMSDomain) { - key = onnxruntime::MakeString(domain, ".", op_type); } else { - return nullptr; + key = onnxruntime::MakeString(domain, ".", op_type); + } + + // extended map is higher priority + auto match = extended_handlers.find(key); + if (match != extended_handlers.end()) { + return &match->second; } - auto match = handler_map.find(key); + match = handler_map.find(key); if (match != handler_map.end()) { return &match->second; - } else if (allow_extended_ops) { - match = extended_handler_map.find(key); - if (match != extended_handler_map.end()) { - return &match->second; - } } + return nullptr; } @@ -1903,12 +1786,13 @@ static int CalculateCost(const api::GraphRef& graph, const api::NodeRef& node, const std::vector& perm, const std::unordered_set& outputs_leading_to_transpose, const HandlerInfo& info, - const std::vector& input_indices) { + const std::vector& input_indices, + const HandlerMap& extended_handlers) { // We require the input cost (number of transposes before the op) and the total cost to strictly decrease. // Strict decrease of the input cost ensures the optimization is stable, since the total cost decrease is just an // estimate (the transpose after the op may or may not cancel with a subsequent transpose). We don't want // repeated runs of the optimizer to have a transpose toggle between two inputs of a binary op. - int cost = EstimateTransposeInputsCost(graph, node, perm, input_indices); + int cost = EstimateTransposeInputsCost(graph, node, perm, input_indices, extended_handlers); if (cost < 0 && info.transposes_outputs) { // If the output will be transposed and won't ultimately cancel, factor in that cost. @@ -1937,12 +1821,14 @@ static bool ShouldPushTranspose(const api::GraphRef& graph, const api::NodeRef& const std::vector& perm, const std::unordered_set& outputs_leading_to_transpose, const HandlerInfo& info, - const std::vector transposable_input_indices) { + const std::vector transposable_input_indices, + const HandlerMap& extended_handlers) { if (node.IsOp("Transpose")) { return true; } - int cost = CalculateCost(graph, node, perm, outputs_leading_to_transpose, info, transposable_input_indices); + int cost = CalculateCost(graph, node, perm, outputs_leading_to_transpose, info, transposable_input_indices, + extended_handlers); return cost < 0; } @@ -1950,7 +1836,7 @@ static bool ShouldPushTranspose(const api::GraphRef& graph, const api::NodeRef& bool ProcessTranspose(OptimizerCtx& ctx, api::NodeRef& transpose, api::NodeRef& node, const std::vector& perm, size_t transpose_input_index, const std::unordered_set& outputs_leading_to_transpose) { - const HandlerInfo* info = GetHandler(node, ctx.allow_extended_ops); + const HandlerInfo* info = GetHandler(node, ctx.extended_handlers); if (info == nullptr) { return false; } @@ -1968,7 +1854,8 @@ bool ProcessTranspose(OptimizerCtx& ctx, api::NodeRef& transpose, api::NodeRef& } if (cost == CostCheckResult::kFallThrough) { - cost = ShouldPushTranspose(ctx.graph, node, perm, outputs_leading_to_transpose, *info, input_indices) + cost = ShouldPushTranspose(ctx.graph, node, perm, outputs_leading_to_transpose, *info, input_indices, + ctx.extended_handlers) ? CostCheckResult::kPushTranspose : CostCheckResult::kStop; } @@ -1983,11 +1870,10 @@ bool ProcessTranspose(OptimizerCtx& ctx, api::NodeRef& transpose, api::NodeRef& } // Returns nullopt if graph opset is unsupported. -std::optional MakeOptimizerContext(api::GraphRef& graph, bool allow_extended_ops, +std::optional MakeOptimizerContext(api::GraphRef& graph, const std::string& provider_type, - OptimizerMode mode, CostCheckFn cost_check_fn, - const std::unordered_set& layout_sensitive_ops, + const HandlerMap& extended_handlers, std::string& error_msg) { auto opset = graph.Opset(""); if (opset == std::nullopt) { @@ -2003,14 +1889,7 @@ std::optional MakeOptimizerContext(api::GraphRef& graph, bool allo return std::nullopt; } - if (allow_extended_ops) { - auto ms_opset = graph.Opset("com.microsoft"); - if (ms_opset == std::nullopt || *ms_opset != 1) { - allow_extended_ops = false; - } - } - - OptimizerCtx ctx{*opset, graph, allow_extended_ops, cost_check_fn, provider_type, mode, layout_sensitive_ops}; + OptimizerCtx ctx{*opset, graph, provider_type, cost_check_fn, extended_handlers}; return ctx; } @@ -2034,7 +1913,7 @@ OptimizeResult OptimizeImpl(OptimizerCtx& ctx) { auto outputs = node.Outputs(); for (auto out : outputs) { if (outputs_leading_to_transpose.find(std::string(out)) != outputs_leading_to_transpose.end()) { - const HandlerInfo* info = GetHandler(node, ctx.allow_extended_ops); + const HandlerInfo* info = GetHandler(node, ctx.extended_handlers); // Determine if node is supported and produces transposed outputs when pushed. if (info != nullptr && info->transposes_outputs) { auto input_indices = info->transposible_inputs_fn(ctx, node); @@ -2049,8 +1928,55 @@ OptimizeResult OptimizeImpl(OptimizerCtx& ctx) { bool changed = false; bool have_dq = false; - // if nodes are assigned we only process those that match the EP in the context - bool ignore_assigned_nodes = ctx.provider_type.empty(); + + // 3 Scenarios: + // + // 1. Level 1 optimizer. + // + // When level 1 optimizers are first run prior to graph partitioning no nodes are assigned. + // We can modify any existing nodes and add new nodes. + // ctx.provider_type is empty. + // + // Level 1 optimizers may also run after layout transformation to do things like constant folding. + // In this case we can only modify unassigned nodes. + // + // 2. Layout transformation: + // + // Existing nodes may be unassigned, assigned to the EP the layout is changing for, or assigned to a different EP. + // ctx.provider_type is set to the EP the layout is changing for. + // + // We can modify unassigned nodes. + // We can not modify any nodes assigned to a different EP as the modification may render them incompatible with + // the EP. + // We can modify nodes assigned to the current EP and create new nodes, but do not assign any new nodes yet. + // Following the layout change GraphPartitioner will call GetCapability again for the current EP, which allows + // it to take the new nodes where possible. + // We also know that the CPU EP will take any remaining nodes as the last step of graph partitioning. + // + // To do this, we check node assignment vs the current EP name to determine if the node can be modified. + // We leave onnxruntime::ApiGraph::new_node_ep_ empty so new nodes are not assigned here. + // + // 3. Level 3 NHWC Transformer: + // + // Specific to CPU EP and runs post-partitioning, so all nodes are assigned at this point. + // ctx.provider_type is set to the CPU EP. + // Existing nodes assigned to the CPU EP can be modified. + // New nodes can be created and are directly assigned to the CPU EP by setting onnxruntime::ApiGraph::new_node_ep_ + // + const auto can_modify_node = [&ctx](const api::NodeRef& node) { + const auto& node_ep = node.GetExecutionProviderType(); + bool can_modify = false; + + if (node_ep.empty()) { + // unassigned nodes can always be modified + can_modify = true; + } else if (node_ep == ctx.provider_type) { + // we can also modify if the EP name in provider_type is not empty and the node is assigned to that EP. + can_modify = true; + } + + return can_modify; + }; // Optimize graph. Nodes will be modified during iteration, but nodes are never deleted before we reach them. // New transpose nodes are inserted, but always as an input to an existing node. @@ -2060,21 +1986,7 @@ OptimizeResult OptimizeImpl(OptimizerCtx& ctx) { have_dq = true; } - // it's not clear how we should handle assignment of new Transpose nodes created during optimization, so ignore. - // e.g. we may need to transpose the input of a node we move a Transpose past. if that node is assigned to - // an EP that doesn't support Transpose, the new node should use the CPU EP. but if that node is assigned to - // an EP that does support the Transpose we should assign the new node to that EP. - // as we do not know what each EP supports, it's safer to not optimize in order to maintain the EP assignments - // made during partitioning. - if (ignore_assigned_nodes && !node.GetExecutionProviderType().empty()) { - continue; - } - - if (ctx.mode == OptimizerMode::OPTIMIZE_LAYOUT_TRANSFORM && - ctx.layout_sensitive_ops.count(node.OpType()) && - node.GetExecutionProviderType() != ctx.provider_type) { - // If the current op is layout sensitive and it is not assigned to the given provider - // then do not process transpose. + if (!can_modify_node(node)) { continue; } @@ -2113,8 +2025,7 @@ OptimizeResult OptimizeImpl(OptimizerCtx& ctx) { for (size_t i = 1; i < graph_nodes.size(); i++) { const auto& node = *graph_nodes[i]; - // TODO: if we want to handle this we need to propagate the assigned EP to the new Transpose node. - if (ignore_assigned_nodes && !node.GetExecutionProviderType().empty()) { + if (!can_modify_node(node)) { continue; } @@ -2149,7 +2060,14 @@ OptimizeResult OptimizeImpl(OptimizerCtx& ctx) { // we're moving the Transpose to before the DQ, so we need to use the inverse permutations to update the axis // attribute correctly when doing per-axis dequantization - if (!HandleQuantizeDequantizeScale(ctx.graph, InvertPerm(*perm), *dq_node, ctx.opset)) { + std::string_view dq_domain = dq_node->Domain(); + std::vector perm_inv = InvertPerm(*perm); + + if (IsOnnxDomain(dq_domain) && !HandleQuantizeDequantizeAxis(ctx.graph, perm_inv, *dq_node, ctx.opset)) { + continue; + } + + if (IsMSDomain(dq_domain) && !TransposeQuantizeDequantizeAxis(ctx.graph, perm_inv, *dq_node)) { continue; } @@ -2170,13 +2088,17 @@ OptimizeResult OptimizeImpl(OptimizerCtx& ctx) { const std::unordered_set& GetLayoutSensitiveOps() { // List of all layout sensitive ops defined in ONNX standard. static std::unordered_set layout_sensitive_ops = { + // normalization "BatchNormalization", "InstanceNormalization", + // convolutions "Conv", "QLinearConv", "ConvTranspose", + // pooling "AveragePool", "LpPool", "MaxPool", "MaxUnpool", "GlobalAveragePool", "GlobalLpPool", "GlobalMaxPool", + // other "LRN", "GridSample", "DepthToSpace", "SpaceToDepth"}; @@ -2184,15 +2106,13 @@ const std::unordered_set& GetLayoutSensitiveOps() { return layout_sensitive_ops; } -OptimizeResult Optimize(api::GraphRef& graph, bool allow_extended_ops, - const std::string& provider_type, OptimizerMode mode, - CostCheckFn cost_check_fn, - const std::unordered_set& layout_sensitive_ops) { +OptimizeResult Optimize(api::GraphRef& graph, const std::string& provider_type, CostCheckFn cost_check_fn, + const HandlerMap& extended_handlers) { OptimizeResult result{}; std::string error_msg; - auto ctx = MakeOptimizerContext(graph, allow_extended_ops, provider_type, mode, cost_check_fn, layout_sensitive_ops, - error_msg); + auto ctx = MakeOptimizerContext(graph, provider_type, cost_check_fn, extended_handlers, error_msg); + if (ctx == std::nullopt) { if (!error_msg.empty()) { result.error_msg = error_msg; @@ -2204,46 +2124,4 @@ OptimizeResult Optimize(api::GraphRef& graph, bool allow_extended_ops, return OptimizeImpl(*ctx); } -void WrapTransposesAroundNode(api::GraphRef& graph, api::NodeRef& node, - const std::vector*>& input_perms, - const std::vector*>& output_perms) { - for (size_t i = 0; i < input_perms.size(); ++i) { - const std::vector* input_perm = input_perms[i]; - if (input_perm != nullptr) { - TransposeInput(graph, node, i, *input_perm, InvertPerm(*input_perm)); - } - } - for (size_t i = 0; i < output_perms.size(); ++i) { - const std::vector* output_perm = output_perms[i]; - if (output_perm != nullptr) { - TransposeOutput(graph, node, i, *output_perm, InvertPerm(*output_perm)); - } - } -} - -static std::unique_ptr SwapNodeImpl(api::GraphRef& graph, api::NodeRef& node, - std::string_view op_type, std::string_view domain, - std::optional since_version) { - auto outputs = node.Outputs(); - auto new_node = graph.CopyNode(node, op_type, domain, since_version); - - for (size_t j = 0; j < outputs.size(); ++j) { - if (outputs[j] != "") { - graph.MoveOutput(node, j, *new_node, j); - } - } - graph.RemoveNode(node); - return new_node; -} - -std::unique_ptr SwapNodeOpTypeAndDomain(api::GraphRef& graph, api::NodeRef& node, - std::string_view op_type, std::string_view domain) { - return SwapNodeImpl(graph, node, op_type, domain, std::nullopt); -} - -std::unique_ptr SwapNodeOpTypeDomainAndSinceVersion(api::GraphRef& graph, api::NodeRef& node, - std::string_view op_type, std::string_view domain, - int since_version) { - return SwapNodeImpl(graph, node, op_type, domain, since_version); -} -} // namespace onnx_layout_transformation +} // namespace onnx_transpose_optimization diff --git a/onnxruntime/core/optimizer/transpose_optimization/onnx_transpose_optimization.h b/onnxruntime/core/optimizer/transpose_optimization/onnx_transpose_optimization.h new file mode 100644 index 0000000000000..1a54e7834a4ae --- /dev/null +++ b/onnxruntime/core/optimizer/transpose_optimization/onnx_transpose_optimization.h @@ -0,0 +1,121 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include + +// implementation details of the transpose optimizer API defined in optimizer_api.h. +// This exposes some internals so they can be extended as needed. +#include "optimizer_api.h" + +namespace onnx_transpose_optimization { + +struct OptimizerCtx; + +// Struct containing information passed to op handlers. +struct HandlerArgs { + OptimizerCtx& ctx; + api::NodeRef& transpose; // Transpose node we are considering moving past `node` + api::NodeRef& node; + const std::vector& perm; // perm attribute from Transpose + const std::vector& perm_inv; // inverse of perm. + // Cached result from calling HandlerInfo.transposible_inputs_fn + std::vector& transposible_inputs; +}; + +// Each op handler points to a (potentially shared) function for determining which input indices are eligible for +// optimization. Handlers are only called if a transpose is on an eligible index, and if the optimization heuristics +// predict that pushing the transpose will be beneficial. Most of the time this function returns a static value, but +// for Sum/Concat/QLinearConcat it needs to be dynamic. +using TransposibleInputsFn = std::vector (*)(OptimizerCtx& ctx, api::NodeRef& node); +using HandlerFunction = bool (*)(HandlerArgs& args); + +struct HandlerInfo { + TransposibleInputsFn transposible_inputs_fn; + HandlerFunction handler_fn; + // Does the handler have to transpose outputs? Used for cost estimation. + bool transposes_outputs = true; +}; + +struct OptimizerCtx { + int64_t opset; + api::GraphRef& graph; + const std::string provider_type; + + CostCheckFn cost_check_fn; + + // Handlers for ops that are not in the ONNX opset, or for ONNX ops where special handling is required. + // If a handler is not found in this map, the default handlers will be used. + const HandlerMap& extended_handlers; +}; + +/// +/// TransposibleInputsFn that returns the first input index. +/// +/// {0} +inline std::vector FirstInput(OptimizerCtx&, api::NodeRef&) { return {0}; } + +std::vector InvertPerm(const std::vector& perm); + +// Transpose all inputs and all outputs +bool HandleSimpleNode(HandlerArgs& args); + +// Node with all inputs broadcastable +bool HandleSimpleNodeBroadcast(HandlerArgs& args); + +// Transposes all inputs and all outputs. Updates axis attribute. +bool HandleSimpleNodeWithAxis(HandlerArgs& args, std::optional default_axis = std::nullopt); + +// base handlers that are used by extended handlers. add from transpose_optimizer.cc as needed. +bool HandleReduceOps(HandlerArgs& args); + +void TransposeInput(api::GraphRef& graph, api::NodeRef& node, size_t i, + const std::vector& perm, + const std::vector& perm_inv); + +// Transposes specified inputs according to perm. +// NOTE: if a Transpose is expected to be above an input to this node, use the inverse of its permutation to cancel it. +void TransposeInputs(OptimizerCtx& ctx, api::NodeRef& node, const std::vector& perm, + const std::vector& input_indices); + +inline void TransposeFirstInput(OptimizerCtx& ctx, api::NodeRef& node, const std::vector& perm) { + std::vector indices{0}; + TransposeInputs(ctx, node, perm, indices); +} + +// Inserts a Transpose op on the ith output of a node. Returns the new, transposed output. +// Updates shape information assuming that the output from the node will have a transposed shape (using perm_inv) +// but the overall (returned) output will match the initial shape. +std::string_view TransposeOutput(api::GraphRef& graph, api::NodeRef& node, size_t i, + const std::vector& perm, + const std::vector& perm_inv); + +void TransposeOutputs(OptimizerCtx& ctx, api::NodeRef& node, const std::vector& perm); + +/// +/// Computes the perm attribute needed to transpose a tensor from channel-first ordering (NCHW or NCD...D) to +/// channel-last ordering (NHWC or ND...DC). rank must be >= 2. +/// +/// Rank of the tensor +/// perm attribute to transpose from channel first to channel last. Ex: [0, 2, 3, 1] +std::vector ChannelFirstToLastPerm(size_t rank); + +/// +/// Computes the perm attribute needed to transpose a tensor from channel-last ordering (NHWC or ND...DC) to +/// channel-last ordering (NCHW or NCD...D). rank must be >= 2. +/// +/// Rank of the tensor +/// perm attribute to transpose from channel last to channel first. Ex: [0, 3, 1, 2] +std::vector ChannelLastToFirstPerm(size_t rank); + +/// +/// Updates the axis attribute of QuantizeLinear or DequantizeLinear operators according to the +/// provided transposition permutation. Only applies to per-axis (de)quantization. +/// +/// The graph containing the node +/// The transpose permutation +/// The QuantizeLinear or DequantizeLinear node +/// True if the axis attribute remains valid +bool TransposeQuantizeDequantizeAxis(const api::GraphRef& graph, const std::vector& perm, api::NodeRef& node); +} // namespace onnx_transpose_optimization diff --git a/onnxruntime/core/optimizer/transpose_optimizer/optimizer_api.h b/onnxruntime/core/optimizer/transpose_optimization/optimizer_api.h similarity index 78% rename from onnxruntime/core/optimizer/transpose_optimizer/optimizer_api.h rename to onnxruntime/core/optimizer/transpose_optimization/optimizer_api.h index e5e8ac8298777..40a03f24f7648 100644 --- a/onnxruntime/core/optimizer/transpose_optimizer/optimizer_api.h +++ b/onnxruntime/core/optimizer/transpose_optimization/optimizer_api.h @@ -12,7 +12,7 @@ #include #include -namespace onnx_layout_transformation { +namespace onnx_transpose_optimization { namespace api { /* This file defines the API for the transpose optimizer and layout transformation tool. The API consists of a set of @@ -61,6 +61,10 @@ enum class DataType : int32_t { COMPLEX64 = 14, COMPLEX128 = 15, BFLOAT16 = 16, + FLOAT8E4M3FN = 17, + FLOAT8E4M3FNUZ = 18, + FLOAT8E5M2 = 19, + FLOAT8E5M2FNUZ = 20, }; /// @@ -464,11 +468,6 @@ using CostCheckFn = const std::vector& perm, const std::unordered_set& outputs_leading_to_transpose)>; -enum class OptimizerMode { - OPTIMIZE_TRANSPOSE, // simple transpose optimization - OPTIMIZE_LAYOUT_TRANSFORM // transpose optimization post layout transformation -}; - /// /// Gets a list of layout sensitive ops defined by ONNX standard. /// @@ -480,6 +479,10 @@ struct OptimizeResult { bool graph_modified{false}; }; +// see transpose_optimizer.h if you wish to provide extended handlers +struct HandlerInfo; +using HandlerMap = std::unordered_map; + /// /// Performs transpose optimization on a graph. Returns true if the graph was modified. /// @@ -490,106 +493,20 @@ struct OptimizeResult { /// total cost of Transpose ops and only push Transposes when doing so has some benefit. /// /// The graph to optimize (or a portion of a graph, see api::GraphRef docs) -/// Whether com.microsoft ops can be used for optimization -/// Execution provider if applicable. -/// Current mode. Optimizer can be called in the context of transpose optimizations or during -/// layout transformations. +/// Execution provider to assign new nodes to. +/// If not specified, graph partitioning must be run later to assign nodes to EPs. +/// /// Optional cost checking function to determine whether it is worth pushing a Transpose -/// through a node. -/// List of ops which are treated as layout sensitive by the ONNX standard -/// as well as any runtime specific ops. These ops should be provided when mode is set to OPTIMIZE_LAYOUT_TRANSFORM. -/// If these ops are not provided, transpose optimizer may convert the layout for these ops +/// through a node. +/// +/// Map of handlers for non-ONNX operators and/or ONNX operators where special handling +/// is required (e.g. ONNX Resize is layout agnostic but may be implemented in a layout sensitive way). +/// /// OptimizeResult. If error_msg is set the Optimize failed. If not set, graph_modified indicates whether /// any changes were required during optimization. -OptimizeResult Optimize(api::GraphRef& graph, bool allow_extended_ops, +OptimizeResult Optimize(api::GraphRef& graph, const std::string& provider_type = "", - OptimizerMode mode = OptimizerMode::OPTIMIZE_TRANSPOSE, CostCheckFn cost_check_fn = nullptr, - const std::unordered_set& layout_sensitive_ops = {}); - -/* Layout Transformation Tools - * These methods help change the channel ordering of layout sensitive ops (like Conv). ONNX currently only supports - * channel first ordering for ops, so this requires changing the op type and domain to a contrib op supporting - * the new ordering. The existence of a robust transpose optimizer means that we can freely add transpose ops during - * conversion and then call Optimize to remove as many as possible. To change the channel ordering of some/all ops - * in a model, a user of this tool should do the following: - * - * 1. Iterate over the graph nodes and identify nodes to convert. For each one: - * a. Change the op type and domain (and possibly attributes) to the op/contrib op with the desired ordering. - * b. The model is now invalid since the input tensors are in the original ordering (and all consumers - * expect the original ordering). Use WrapTransposesAroundNode helper to insert transposes around the - * inputs/outputs of the op to correct this. - * 2. The model is now correct but has many unnecessary Transpose ops. Call Optimize on the graph. - * - * After step 1, the Transpose ops will wrap converted ops in a similar manner to q/dq ops in quantization. - * The perm attributes essentially encode the information about which ops are being reordered. - */ + const HandlerMap& extended_handlers = {}); -/// -/// Inserts transposes around op inputs/outputs. Alternatively transposes initializers or uses existing Transpose -/// nodes if possible. Populates shape information on affected node inputs/outputs to reflect the change. -/// -/// Ex: -/// * -> NhwcConv -> ** -/// becomes -/// * -> Transpose -> NhwcConv -> Transpose -> ** -/// Conv inputs/outputs have new shape. Shapes of * and ** are unchanged (carrying NCHW data). -/// -/// input_perms/output_perms are matched with node inputs/outputs positionally. Their lengths must be at most equal to -/// the number of inputs/outputs, respectively. nullptr entires indicate an input or output should not be transposed. -/// -/// Graph containing the node -/// Node to modify -/// Input permutations. nullptr entries indicate to skip corresponding input. -/// Output permutations. nullptr entries indicate to skip corresponding output. -void WrapTransposesAroundNode(api::GraphRef& graph, api::NodeRef& node, - const std::vector*>& input_perms, - const std::vector*>& output_perms); - -/// -/// Computes the perm attribute needed to transpose a tensor from channel-first ordering (NCHW or NCD...D) to -/// channel-last ordering (NHWC or ND...DC). rank must be >= 2. -/// -/// Rank of the tensor -/// perm attribute to transpose from channel first to channel last. Ex: [0, 2, 3, 1] -std::vector ChannelFirstToLastPerm(size_t rank); - -/// -/// Computes the perm attribute needed to transpose a tensor from channel-last ordering (NHWC or ND...DC) to -/// channel-last ordering (NCHW or NCD...D). rank must be >= 2. -/// -/// Rank of the tensor -/// perm attribute to transpose from channel last to channel first. Ex: [0, 3, 1, 2] -std::vector ChannelLastToFirstPerm(size_t rank); - -/// -/// Swaps out a node for a new copy of that node with the specified op type and domain. -/// Current API does not allow nodes to have their op types or domains changed, so a new node is needed. All -/// attributes, inputs, and outputs are moved to the new node. The old node is removed from the graph and should no -/// longer be accessed. -/// -/// Graph containing the node -/// Node to copy and remove -/// New node op_type -/// New node domain. "" for the default domain. -/// The newly created node. -std::unique_ptr SwapNodeOpTypeAndDomain(api::GraphRef& graph, api::NodeRef& node, - std::string_view op_type, std::string_view domain); - -/// -/// Swaps out a node for a new copy of that node with the specified op type, domain, and since version. -/// Current API does not allow nodes to have their op types or domains changed, so a new node is needed. All -/// attributes, inputs, and outputs are moved to the new node. The old node is removed from the graph and should no -/// longer be accessed. -/// -/// Graph containing the node -/// Node to copy and remove -/// New node op_type -/// New node domain. "" for the default domain. -/// New node since version. -/// The newly created node. -std::unique_ptr SwapNodeOpTypeDomainAndSinceVersion(api::GraphRef& graph, api::NodeRef& node, - std::string_view op_type, std::string_view domain, - int since_version); - -} // namespace onnx_layout_transformation +} // namespace onnx_transpose_optimization diff --git a/onnxruntime/core/optimizer/transpose_optimizer/optimizer_api_impl.cc b/onnxruntime/core/optimizer/transpose_optimization/ort_optimizer_api_impl.cc similarity index 77% rename from onnxruntime/core/optimizer/transpose_optimizer/optimizer_api_impl.cc rename to onnxruntime/core/optimizer/transpose_optimization/ort_optimizer_api_impl.cc index 65a037cfa0a0f..b30c94d7b3e40 100644 --- a/onnxruntime/core/optimizer/transpose_optimizer/optimizer_api_impl.cc +++ b/onnxruntime/core/optimizer/transpose_optimization/ort_optimizer_api_impl.cc @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "optimizer_api.h" -#include "optimizer_utils.h" +// The ONNX Runtime specific implementation of the generic transpose optimizer API. + +#include "core/optimizer/transpose_optimization/optimizer_api.h" #include #include @@ -13,12 +14,15 @@ #include "core/framework/tensorprotoutils.h" #include "core/graph/graph_utils.h" #include "core/graph/graph_viewer.h" -#include "core/optimizer/transpose_optimizer/layout_transformation_potentially_added_ops.h" +#include "core/optimizer/layout_transformation/layout_transformation_potentially_added_ops.h" +#include "core/optimizer/transpose_optimization/ort_optimizer_utils.h" +#include "core/optimizer/transpose_optimization/ort_transpose_optimization.h" #include "core/providers/cpu/tensor/transpose.h" using namespace ONNX_NAMESPACE; using namespace ::onnxruntime::common; -using namespace onnx_layout_transformation; +using namespace onnxruntime::layout_transformation; +using namespace onnx_transpose_optimization; namespace onnxruntime { class ApiValueInfo final : public api::ValueInfoRef { @@ -172,6 +176,10 @@ std::optional> ApiValueInfo::Shape() const { api::DataType ApiValueInfo::DType() const { const auto* type = node_arg_.TypeAsProto(); + if (!type) { + return api::DataType::UNDEFINED; + } + if (!utils::HasTensorType(*type)) { return api::DataType::UNDEFINED; } @@ -823,194 +831,12 @@ std::unique_ptr MakeApiNode(onnxruntime::Graph& graph, onnxruntime return std::make_unique(node, graph); } -onnxruntime::Graph& GraphFromApiGraph(onnx_layout_transformation::api::GraphRef& graph) { +onnxruntime::Graph& GraphFromApiGraph(onnx_transpose_optimization::api::GraphRef& graph) { return static_cast(graph).Graph(); } -onnxruntime::Node& NodeFromApiNode(onnx_layout_transformation::api::NodeRef& node) { +onnxruntime::Node& NodeFromApiNode(onnx_transpose_optimization::api::NodeRef& node) { return static_cast(node).Node(); } -CostCheckResult OrtEPCostCheck(const api::GraphRef& graph, const api::NodeRef& node, - const std::vector& /*perm*/, - const std::unordered_set& /*outputs_leading_to_transpose*/) { - // special case some kernels based on the ORT implementation details - if (node.GetExecutionProviderType() == kCpuExecutionProvider) { - if (node.IsOp("MaxPool")) { - // MaxPool has higher perf in the NHWC variant when supported. HandleMaxPool does the support checks. - return CostCheckResult::kPushTranspose; - } - - if (node.IsOp("Resize")) { - // Resize is included because it has higher perf in the NHWC variant when - // the input X is 4D int8 tensor and the mode is linear - auto X_value_info = graph.GetValueInfo(node.Inputs()[0]); - auto X_shape = X_value_info->Shape(); - auto X_dtype = X_value_info->DType(); - auto mode = node.GetAttributeString("mode"); - if (X_shape && X_shape->size() == 4 && - (X_dtype == api::DataType::UINT8 || X_dtype == api::DataType::INT8) && - mode && *mode == "linear") { - return CostCheckResult::kPushTranspose; - } - } - } - - return CostCheckResult::kFallThrough; -} - -namespace layout_transformer { - -// Layout sensitive NCHW ops. TransformLayoutForEP will wrap these with Transpose nodes to convert the input -// data to NHWC and output data back to NCHW, and move the op to the internal NHWC domain (kMSInternalNHWCDomain). -// The EP requesting these ops MUST be able to handle the node with the operator in the kMSInternalNHWCDomain. -// Once all the layout sensitive ops requested by the EP are wrapped the transpose optimizer will attempt to remove -// as many of the layout transposes as possible. -const std::unordered_set& GetORTLayoutSensitiveOps() { - static std::unordered_set ort_layout_sensitive_ops = []() { - const auto& layout_sensitive_ops = onnx_layout_transformation::GetLayoutSensitiveOps(); - std::unordered_set ort_specific_ops = - { "FusedConv", - "QLinearAveragePool", - "QLinearGlobalAveragePool" -#if defined(USE_CUDA) || defined(USE_ROCM) || defined(USE_QNN) - // The CUDA/ROCM Resize kernel is layout sensitive as it only handles NCHW input. - // The CPU kernel and ONNX spec are not limited to handling NCHW input so are not layout sensitive, and - // onnx_layout_transformation::HandleResize is used. - , - "Resize" -#endif - }; - - ort_specific_ops.insert(layout_sensitive_ops.cbegin(), layout_sensitive_ops.cend()); - return ort_specific_ops; - }(); - - return ort_layout_sensitive_ops; -} - -// Cost check for aggressively pushing the Transpose nodes involved in the layout transformation further out. -static CostCheckResult -PostLayoutTransformCostCheck(const api::GraphRef& graph, const api::NodeRef& node, - const std::vector& perm, - const std::unordered_set& outputs_leading_to_transpose) { - // we aggressively push the layout transpose nodes. - // Exception: pushing through a Concat can result in Transpose nodes being added to multiple other inputs which - // can potentially be worse for performance. Use the cost check in that case. - if (node.OpType() != "Concat" && - (perm == ChannelFirstToLastPerm(perm.size()) || perm == ChannelLastToFirstPerm(perm.size()))) { - return CostCheckResult::kPushTranspose; - } - - // for other nodes use the default ORT cost check - return OrtEPCostCheck(graph, node, perm, outputs_leading_to_transpose); -} - -Status TransformLayoutForEP(Graph& graph, bool& modified, const IExecutionProvider& execution_provider, - const DebugGraphFn& debug_graph_fn) { - // sub graph recurse will be added later - auto api_graph = MakeApiGraph(graph, execution_provider.GetAllocator(OrtMemTypeDefault), nullptr); - const auto& layout_sensitive_ops = GetORTLayoutSensitiveOps(); - - for (auto& node : api_graph->Nodes()) { - if (layout_sensitive_ops.count(node->OpType())) { - if (node->GetExecutionProviderType() != execution_provider.Type()) { - continue; - } - - auto domain = node->Domain(); - // Skip if domain is incorrect - if (domain != kOnnxDomain && domain != kMSDomain) { - continue; - } - - // 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) { - onnx_layout_transformation::SwapNodeOpTypeAndDomain(*api_graph, *node, node->OpType(), kMSInternalNHWCDomain); - // Changing the domain for the node requires creating a new node and replacing the old one - // therefore set the modified flag. - modified = true; - continue; - } - - // Skip if unknown rank - auto shape = api_graph->GetValueInfo(node->Inputs()[0])->Shape(); - if (!shape.has_value()) { - continue; - } - - // Convert to channels last - size_t rank = shape->size(); - - bool has_channel_last_attr = node->GetAttributeInt("channels_last").has_value() ? true : false; - if (has_channel_last_attr) { - node->SetAttributeInt("channels_last", 1); - } - - auto input_perm = onnx_layout_transformation::ChannelFirstToLastPerm(rank); - auto output_perm = onnx_layout_transformation::ChannelLastToFirstPerm(rank); - - // 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") { - // 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. Current code skips - // layout conversion for ROI because it needs special handling as ROI size is 2*rank. - // Enable passing in ROI for layout conversion when an EP which supports ROI starts using layout transformer. - // NNAPI which currently uses layout transformer does not support it. - std::vector*> input_perms{&input_perm, nullptr}; - for (size_t i = 2; i < node->Inputs().size(); i++) { - auto constant = api_graph->GetConstant(node->Inputs()[i]); - if (constant != nullptr && constant->Data().size() > 0) { - input_perms.push_back(&input_perm); - } else { - input_perms.push_back(nullptr); - } - } - onnx_layout_transformation::WrapTransposesAroundNode(*api_graph, *node, input_perms, {&output_perm}); - } else { - onnx_layout_transformation::WrapTransposesAroundNode(*api_graph, *node, {&input_perm}, {&output_perm}); - } - - onnx_layout_transformation::SwapNodeOpTypeAndDomain(*api_graph, *node, node->OpType(), kMSInternalNHWCDomain); - modified = true; - } - } - - if (modified) { - // debug the changes made inserting Transpose nodes around layout sensitive ops. - if (debug_graph_fn) { - debug_graph_fn(graph); - } - - OptimizeResult result = - onnx_layout_transformation::Optimize(*api_graph, /*allow_extended_ops*/ true, execution_provider.Type(), - onnx_layout_transformation::OptimizerMode::OPTIMIZE_LAYOUT_TRANSFORM, - PostLayoutTransformCostCheck, - layout_sensitive_ops); - if (result.error_msg) { - return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Optimization after layout transformation failed: ", - result.error_msg.value()); - } - - // debug optimization of the new Tranpose nodes using PostLayoutTransformCostCheck - if (debug_graph_fn) { - debug_graph_fn(graph); - } - } - - return Status::OK(); -} - -bool IsSupportedOpset(const Graph& graph) { - const auto& version_map = graph.DomainToVersionMap(); - const auto& onnx_version = version_map.find(kOnnxDomain); - return (onnx_version != version_map.end() && - onnx_version->second >= onnx_layout_transformation::kMinSupportedOpset && - onnx_version->second <= kMaxSupportedOpset); -} - -} // namespace layout_transformer } // namespace onnxruntime diff --git a/onnxruntime/core/optimizer/transpose_optimization/ort_optimizer_utils.h b/onnxruntime/core/optimizer/transpose_optimization/ort_optimizer_utils.h new file mode 100644 index 0000000000000..f1440b23aface --- /dev/null +++ b/onnxruntime/core/optimizer/transpose_optimization/ort_optimizer_utils.h @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "optimizer_api.h" +#include "core/graph/graph.h" +#include "core/framework/execution_provider.h" +#include "core/framework/transform_layout_functions.h" + +namespace onnxruntime { +/// +/// Creates concrete implementation of api for transpose optimizer. IMPORTANT: graph must have up-to-date edges, +/// node_arg-to-producer, and node_arg-to-consumer relationships. Otherwise call Resolve() before this. +/// +/// ORT Graph to wrap with API +/// Allocator used for reshaping/transposing tensors +/// New nodes are assigned to this EP, or left unassigned if nullptr +/// api::GraphRef for use with transpose optimizer +std::unique_ptr MakeApiGraph(onnxruntime::Graph& graph, + AllocatorPtr cpu_allocator, + const char* new_node_ep); + +/// +/// Creates NodeRef. +/// +/// ORT Graph which owns the node +/// ORT Node to wrap with API. +/// api::NodeRef for use with transpose optimizer +std::unique_ptr MakeApiNode(onnxruntime::Graph& graph, + onnxruntime::Node& node); + +/// +/// Reveals underlying ORT graph from an api::GraphRef +/// +/// api:GraphRef created from MakeApiGraph +/// ORT graph +onnxruntime::Graph& GraphFromApiGraph(onnx_transpose_optimization::api::GraphRef& graph); + +/// +/// Reveals underlying ORT node from an api::NodeRef +/// +/// api:NodeRef from graph created from MakeApiGraph +/// ORT node +onnxruntime::Node& NodeFromApiNode(onnx_transpose_optimization::api::NodeRef& node); +} // namespace onnxruntime diff --git a/onnxruntime/core/optimizer/transpose_optimization/ort_transpose_optimization.cc b/onnxruntime/core/optimizer/transpose_optimization/ort_transpose_optimization.cc new file mode 100644 index 0000000000000..ead82a6b56741 --- /dev/null +++ b/onnxruntime/core/optimizer/transpose_optimization/ort_transpose_optimization.cc @@ -0,0 +1,187 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/optimizer/transpose_optimization/ort_transpose_optimization.h" + +#include +#include "core/graph/constants.h" +#include "core/optimizer/transpose_optimization/ort_optimizer_utils.h" + +using namespace onnx_transpose_optimization; + +namespace onnxruntime { + +static bool HandleQLinearConcat(HandlerArgs& args) { + return HandleSimpleNodeWithAxis(args); +} + +std::vector QLinearConcatInputs(OptimizerCtx& ctx, api::NodeRef& node) { + (void)ctx; + std::vector indices; + size_t num_inputs = node.Inputs().size(); + for (size_t i = 2; i < num_inputs; i += 3) { + indices.push_back(i); + } + return indices; +} + +constexpr HandlerInfo q_linear_concat_handler = {&QLinearConcatInputs, &HandleQLinearConcat}; + +static bool HandleQLinearBinaryOp(HandlerArgs& args) { + return HandleSimpleNodeBroadcast(args); +} + +std::vector QLinearBinaryOpInputs(OptimizerCtx&, api::NodeRef&) { + // Inputs are: [A, A_scale, A_zero_point, B, B_scale, B_zero_point, C_scale, C_zero_point], + // we want [A, B]. + return {0, 3}; +} + +constexpr HandlerInfo q_linear_binary_op_handler = {&QLinearBinaryOpInputs, &HandleQLinearBinaryOp}; + +static bool HandleQLinearPoolOp(HandlerArgs& args) { + // Swap between channel first/last variants. Only works for applicable values of perm. + int64_t channels_last = args.node.GetAttributeIntDefault("channels_last", 0); + size_t rank = args.perm.size(); + if (rank < 2) return false; + auto p = ChannelLastToFirstPerm(rank); + if ((!channels_last && args.perm == p) || (channels_last && args.perm_inv == p)) { + args.node.SetAttributeInt("channels_last", 1 - channels_last); + TransposeFirstInput(args.ctx, args.node, args.perm_inv); + TransposeOutputs(args.ctx, args.node, args.perm); + return true; + } + return false; +} + +constexpr HandlerInfo q_linear_pool_op_handler = {&FirstInput, &HandleQLinearPoolOp}; + +static bool HandleMaxPool(HandlerArgs& args) { +#if defined(DISABLE_CONTRIB_OPS) + // Cannot convert MaxPool to com.microsoft.NhwcMaxPool if contrib ops are disabled in this build. + ORT_UNUSED_PARAMETER(args); + return false; +#else + if (args.node.GetExecutionProviderType() != "CPUExecutionProvider") { + return false; + } + + auto outputs = args.node.Outputs(); + if (outputs.size() == 2 && outputs[1] != "") { + // Can't optimize if optional "indices" output is provided + return false; + } + + auto info = args.ctx.graph.GetValueInfo(outputs[0]); + api::DataType dtype = info->DType(); + if (dtype != api::DataType::UINT8 && dtype != api::DataType::INT8) { + return false; + } + + size_t rank = args.perm.size(); + if (args.perm != ChannelLastToFirstPerm(rank)) { + return false; + } + + auto new_node = SwapNodeOpTypeDomainAndSinceVersion(args.ctx.graph, args.node, "NhwcMaxPool", kMSDomain, 1); + new_node->ClearAttribute("storage_order"); // Only relevant for indices output. Prohibited for NhwcMaxPool. + TransposeFirstInput(args.ctx, *new_node, args.perm_inv); + TransposeOutputs(args.ctx, *new_node, args.perm); + return true; +#endif // defined(DISABLE_CONTRIB_OPS) +} + +static bool HandleContribQuantizeDequantizeLinear(HandlerArgs& args) { + if (!TransposeQuantizeDequantizeAxis(args.ctx.graph, args.perm, args.node)) { + return false; + } + + TransposeFirstInput(args.ctx, args.node, args.perm_inv); + TransposeOutputs(args.ctx, args.node, args.perm); + + return true; +} + +constexpr HandlerInfo max_pool_op_handler = {&FirstInput, &HandleMaxPool}; +constexpr HandlerInfo node_1_inp_handler = {&FirstInput, &HandleSimpleNode}; +constexpr HandlerInfo reduce_op_handler = {&FirstInput, &HandleReduceOps}; +constexpr HandlerInfo contrib_quantize_dequantize_linear_handler = {&FirstInput, + &HandleContribQuantizeDequantizeLinear}; + +// ORT contrib ops and special cased ONNX ops where we have EP specific handling +const HandlerMap& OrtExtendedHandlers() { + static const HandlerMap extended_handler_map = []() { + HandlerMap map = { + {"MaxPool", max_pool_op_handler}, + {"com.microsoft.QuantizeLinear", contrib_quantize_dequantize_linear_handler}, + {"com.microsoft.DequantizeLinear", contrib_quantize_dequantize_linear_handler}, + {"com.microsoft.QLinearAdd", q_linear_binary_op_handler}, + {"com.microsoft.QLinearAveragePool", q_linear_pool_op_handler}, + {"com.microsoft.QLinearConcat", q_linear_concat_handler}, + {"com.microsoft.QLinearGlobalAveragePool", q_linear_pool_op_handler}, + {"com.microsoft.QLinearLeakyRelu", node_1_inp_handler}, + {"com.microsoft.QLinearMul", q_linear_binary_op_handler}, + {"com.microsoft.QLinearReduceMean", reduce_op_handler}, + {"com.microsoft.QLinearSigmoid", node_1_inp_handler}, + }; + + return map; + }(); + + return extended_handler_map; +} + +CostCheckResult OrtEPCostCheck(const api::GraphRef& graph, const api::NodeRef& node, + const std::vector& /*perm*/, + const std::unordered_set& /*outputs_leading_to_transpose*/) { + // special case some kernels based on the ORT implementation details + if (node.GetExecutionProviderType() == kCpuExecutionProvider) { + if (node.IsOp("MaxPool")) { + // MaxPool has higher perf in the NHWC variant when supported. HandleMaxPool does the support checks. + return CostCheckResult::kPushTranspose; + } + + if (node.IsOp("Resize")) { + // Resize is included because it has higher perf in the NHWC variant when + // the input X is 4D int8 tensor and the mode is linear + auto X_value_info = graph.GetValueInfo(node.Inputs()[0]); + auto X_shape = X_value_info->Shape(); + auto X_dtype = X_value_info->DType(); + auto mode = node.GetAttributeString("mode"); + if (X_shape && X_shape->size() == 4 && + (X_dtype == api::DataType::UINT8 || X_dtype == api::DataType::INT8) && + mode && *mode == "linear") { + return CostCheckResult::kPushTranspose; + } + } + } + + return CostCheckResult::kFallThrough; +} + +static std::unique_ptr SwapNodeImpl(api::GraphRef& graph, api::NodeRef& node, + std::string_view op_type, std::string_view domain, + std::optional since_version) { + auto outputs = node.Outputs(); + auto new_node = graph.CopyNode(node, op_type, domain, since_version); + + for (size_t j = 0; j < outputs.size(); ++j) { + if (outputs[j] != "") { + graph.MoveOutput(node, j, *new_node, j); + } + } + graph.RemoveNode(node); + return new_node; +} + +std::unique_ptr SwapNodeOpTypeAndDomain(api::GraphRef& graph, api::NodeRef& node, + std::string_view op_type, std::string_view domain) { + return SwapNodeImpl(graph, node, op_type, domain, std::nullopt); +} + +std::unique_ptr SwapNodeOpTypeDomainAndSinceVersion(api::GraphRef& graph, api::NodeRef& node, + std::string_view op_type, std::string_view domain, + int since_version) { + return SwapNodeImpl(graph, node, op_type, domain, since_version); +} +} // namespace onnxruntime diff --git a/onnxruntime/core/optimizer/transpose_optimization/ort_transpose_optimization.h b/onnxruntime/core/optimizer/transpose_optimization/ort_transpose_optimization.h new file mode 100644 index 0000000000000..0a5dbd6d13d06 --- /dev/null +++ b/onnxruntime/core/optimizer/transpose_optimization/ort_transpose_optimization.h @@ -0,0 +1,68 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/optimizer/transpose_optimization/optimizer_api.h" +#include "core/optimizer/transpose_optimization/onnx_transpose_optimization.h" + +namespace onnxruntime { +/// +/// Get the extended handlers for ORT specific transpose optimization. +/// These include handlers for contrib ops, and where we have an NHWC version of a layout sensitive op. +/// Extends the handlers returned by OrtHandlers. +/// +/// HandlerMap +const onnx_transpose_optimization::HandlerMap& OrtExtendedHandlers(); + +/// +/// Cost check function for transpose optimizer that takes into account implementation details of the +/// ORT execution provider kernels. +/// +/// The graph being optimized +/// The node we're considering pushing a Transpose through +/// The perm value of the Transpose +/// The set of outputs that lead to another Transpose in the graph. +/// If we can successfully push the Transpose until it meets another Transpose they can either cancel each other out, +/// or be merged into a single Transpose. +/// +/// CostCheckResult indicating the action the transpose optimizer should perform. +onnx_transpose_optimization::CostCheckResult OrtEPCostCheck( + const onnx_transpose_optimization::api::GraphRef& graph, + const onnx_transpose_optimization::api::NodeRef& node, + const std::vector& perm, + const std::unordered_set& outputs_leading_to_transpose); + +/// +/// Swaps out a node for a new copy of that node with the specified op type and domain. +/// Current API does not allow nodes to have their op types or domains changed, so a new node is needed. All +/// attributes, inputs, and outputs are moved to the new node. The old node is removed from the graph and should no +/// longer be accessed. +/// +/// Graph containing the node +/// Node to copy and remove +/// New node op_type +/// New node domain. "" for the default domain. +/// The newly created node. +std::unique_ptr +SwapNodeOpTypeAndDomain(onnx_transpose_optimization::api::GraphRef& graph, + onnx_transpose_optimization::api::NodeRef& node, + std::string_view op_type, std::string_view domain); + +/// +/// Swaps out a node for a new copy of that node with the specified op type, domain, and since version. +/// Current API does not allow nodes to have their op types or domains changed, so a new node is needed. All +/// attributes, inputs, and outputs are moved to the new node. The old node is removed from the graph and should no +/// longer be accessed. +/// +/// Graph containing the node +/// Node to copy and remove +/// New node op_type +/// New node domain. "" for the default domain. +/// New node since version. +/// The newly created node. +std::unique_ptr +SwapNodeOpTypeDomainAndSinceVersion(onnx_transpose_optimization::api::GraphRef& graph, + onnx_transpose_optimization::api::NodeRef& node, + std::string_view op_type, std::string_view domain, int since_version); +} // namespace onnxruntime diff --git a/onnxruntime/core/optimizer/transpose_optimizer/ort_transpose_optimizer.cc b/onnxruntime/core/optimizer/transpose_optimizer.cc similarity index 69% rename from onnxruntime/core/optimizer/transpose_optimizer/ort_transpose_optimizer.cc rename to onnxruntime/core/optimizer/transpose_optimizer.cc index bd370a49e09aa..33e3f5eeaf0fa 100644 --- a/onnxruntime/core/optimizer/transpose_optimizer/ort_transpose_optimizer.cc +++ b/onnxruntime/core/optimizer/transpose_optimizer.cc @@ -1,23 +1,28 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "ort_transpose_optimizer.h" +#include "transpose_optimizer.h" #include #include "core/graph/graph_utils.h" #include "core/optimizer/initializer.h" #include "core/optimizer/utils.h" #include "core/providers/cpu/tensor/transpose.h" -#include "optimizer_utils.h" +#include "core/optimizer/transpose_optimization/ort_optimizer_utils.h" +#include "core/optimizer/transpose_optimization/ort_transpose_optimization.h" using namespace ONNX_NAMESPACE; using namespace ::onnxruntime::common; -using namespace onnx_layout_transformation; +using namespace onnx_transpose_optimization; namespace onnxruntime { -Status TransposeOptimizer::ApplyImpl(Graph& graph, bool& modified, int graph_level, const logging::Logger& logger) const { +Status TransposeOptimizer::ApplyImpl(Graph& graph, bool& modified, int graph_level, + const logging::Logger& logger) const { auto api_graph = MakeApiGraph(graph, cpu_allocator_, /*new_node_ep*/ nullptr); - OptimizeResult result = onnx_layout_transformation::Optimize(*api_graph, /*allow_extended_ops*/ false); + + OptimizeResult result = onnx_transpose_optimization::Optimize(*api_graph, "", /* default cost check*/ nullptr, + OrtExtendedHandlers()); + if (result.error_msg) { // currently onnx_layout_transformation::Optimize only fails if we hit an unsupported opset. // we don't want to fail loading the model just because we can't optimize Transpose ops, so just log a warning diff --git a/onnxruntime/core/optimizer/transpose_optimizer/ort_transpose_optimizer.h b/onnxruntime/core/optimizer/transpose_optimizer.h similarity index 85% rename from onnxruntime/core/optimizer/transpose_optimizer/ort_transpose_optimizer.h rename to onnxruntime/core/optimizer/transpose_optimizer.h index 0d8a82cee96a3..1ae6d611d2f0e 100644 --- a/onnxruntime/core/optimizer/transpose_optimizer/ort_transpose_optimizer.h +++ b/onnxruntime/core/optimizer/transpose_optimizer.h @@ -26,7 +26,8 @@ class TransposeOptimizer : public GraphTransformer { // The second phase of optimization may swap a DequantizeLinear -> Transpose back, so multiple runs would // keep swapping the order of the nodes in the first and second phases, leading to always returning true for // modified. - // see https://github.com/microsoft/onnxruntime/blob/e3a2d5cca8bcefe064f83d57e46ea51ddb2b16e8/onnxruntime/core/optimizer/transpose_optimizer/transpose_optimizer.cc#L1917-L1921 + // See onnxruntime/core/optimizer/transpose_optimization/onnx_transpose_optimization.cc:OptimizeImpl for details + // on the second pass. bool ShouldOnlyApplyOnce() const override { return true; } }; diff --git a/onnxruntime/core/optimizer/transpose_optimizer/optimizer_utils.h b/onnxruntime/core/optimizer/transpose_optimizer/optimizer_utils.h deleted file mode 100644 index 75c4d5cfe5ada..0000000000000 --- a/onnxruntime/core/optimizer/transpose_optimizer/optimizer_utils.h +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include "optimizer_api.h" -#include "core/graph/graph.h" -#include "core/framework/execution_provider.h" -#include "core/framework/transform_layout_functions.h" - -namespace onnxruntime { -/// -/// Creates concrete implementation of api for transpose optimizer. IMPORTANT: graph must have up-to-date edges, -/// node_arg-to-producer, and node_arg-to-consumer relationships. Otherwise call Resolve() before this. -/// -/// ORT Graph to wrap with API -/// Allocator used for reshaping/transposing tensors -/// New nodes are assigned to this EP, or left unassigned if nullptr -/// api::GraphRef for use with transpose optimizer -std::unique_ptr MakeApiGraph(onnxruntime::Graph& graph, - AllocatorPtr cpu_allocator, - const char* new_node_ep); - -/// -/// Creates NodeRef. -/// -/// ORT Graph which owns the node -/// ORT Node to wrap with API. -/// api::NodeRef for use with transpose optimizer -std::unique_ptr MakeApiNode(onnxruntime::Graph& graph, onnxruntime::Node& node); - -/// -/// Reveals underlying ORT graph from an api::GraphRef -/// -/// api:GraphRef created from MakeApiGraph -/// ORT graph -onnxruntime::Graph& GraphFromApiGraph(onnx_layout_transformation::api::GraphRef& graph); - -/// -/// Reveals underlying ORT node from an api::NodeRef -/// -/// api:NodeRef from graph created from MakeApiGraph -/// ORT node -onnxruntime::Node& NodeFromApiNode(onnx_layout_transformation::api::NodeRef& node); - -/// -/// Cost check function for transpose optimizer that takes into account implementation details of the -/// ORT execution provider kernels. -/// -/// The graph being optimized -/// The node we're considering pushing a Transpose through -/// The perm value of the Transpose -/// The set of outputs that lead to another Transpose in the graph. -/// If we can successfully push the Transpose until it meets another Transpose they can either cancel each other out, -/// or be merged into a single Transpose. -/// -/// CostCheckResult indicating the action the transpose optimizer should perform. -onnx_layout_transformation::CostCheckResult OrtEPCostCheck( - const onnx_layout_transformation::api::GraphRef& graph, - const onnx_layout_transformation::api::NodeRef& node, - const std::vector& perm, - const std::unordered_set& outputs_leading_to_transpose); - -namespace layout_transformer { -/// -/// Gets a list of layout sensitive ops for ORT. This list contains onnx standard defined -/// layout senstive ops + contrib ops + ops which are not layout sensitive but are treated as -/// layout sensitive by ORT EPs (exmaple Resize). -/// -/// unordered set of op_types which are layout sensitive -const std::unordered_set& GetORTLayoutSensitiveOps(); - -/// -/// Transforms data layout from NCHW to NHWC, using the kMSInternalNHWCDomain domain for updated nodes. -/// -/// This can be used by a compiling EP such as NNAPI, where the synthetic domain is a signal that the node has been -/// updated to the EP's required layout, or an EP with statically registered kernels such as XNNPACK where a kernel -/// is registered for the NHWC version of an ONNX operator. The NHWC version of the ONNX operator uses the synthetic -/// domain and is defined by onnxruntime/core/graph/contrib_ops/internal_nhwc_onnx_opset.cc -/// -/// Transforms are applied to layout sensitive nodes assigned to execution_provider provided by the caller, -/// and any other non-layout sensitive nodes in order to optimize the transposes as much as possible. -/// -/// graph to transform -/// indicates whether the graph is modified during transformation -/// execution provider for which the transformation needs to be performed -/// Optional functor to debug the graph produced during layout transformation. -/// This is called after layout transformation if new nodes are inserted, and again after those are optimized. -/// -Status TransformLayoutForEP(Graph& graph, bool& modified, const IExecutionProvider& execution_provider, - const DebugGraphFn& debug_graph_fn = {}); - -/// -/// Checks if the opset of the Graph is supported by the layout transformer. -/// -/// Graph to check -/// -bool IsSupportedOpset(const Graph& graph); -} // namespace layout_transformer -} // namespace onnxruntime diff --git a/onnxruntime/core/optimizer/utils.cc b/onnxruntime/core/optimizer/utils.cc index ef4c478304155..7c3599a08ec7a 100644 --- a/onnxruntime/core/optimizer/utils.cc +++ b/onnxruntime/core/optimizer/utils.cc @@ -180,7 +180,7 @@ bool AppendTensorFromInitializer(const Graph& graph, const NodeArg& input_arg, I } else if (data_type == ONNX_NAMESPACE::TensorProto_DataType_INT32) { const int32_t* val = init_const.data(); data.reserve(data.size() + gsl::narrow(init_const.size())); - for (int64_t i = 0; i < init_const.size(); i++) { + for (size_t i = 0; i < init_const.size(); i++) { data.push_back(static_cast(val[i])); } } else { @@ -274,8 +274,15 @@ int32_t IndexOfNodeOutput(const Node& node, const NodeArg& node_arg) { constexpr std::array kOnnxDomainNonDeterministicOps{"RandomUniform", "RandomNormal", "RandomUniformLike", "RandomNormalLike", "Multinomial"}; +// List of deterministic MS domain operators. Currently used for constant folding and common subexpression elimination. +// +// TODO(adrianlizarraga): Investigate converting to lists of *non-deterministic* MS domain operators to be consistent +// with the above ONNX list. With the current approach, only MS domain Q/DQ operators +// (plus ShrunkenGather for training) are considered deterministic. #ifdef ENABLE_TRAINING_OPS -constexpr std::array kMSDomainDeterministicOps{"ShrunkenGather"}; +constexpr std::array kMSDomainDeterministicOps{"ShrunkenGather", "QuantizeLinear", "DequantizeLinear"}; +#else +constexpr std::array kMSDomainDeterministicOps{"QuantizeLinear", "DequantizeLinear"}; #endif bool IsOperationDeterministic(const std::string& domain, const std::string& op) { @@ -283,12 +290,12 @@ bool IsOperationDeterministic(const std::string& domain, const std::string& op) auto iter = std::find(kOnnxDomainNonDeterministicOps.begin(), kOnnxDomainNonDeterministicOps.end(), op); return iter == kOnnxDomainNonDeterministicOps.end(); } -#ifdef ENABLE_TRAINING_OPS + if (domain.compare(kMSDomain) == 0) { auto iter = std::find(kMSDomainDeterministicOps.begin(), kMSDomainDeterministicOps.end(), op); return iter != kMSDomainDeterministicOps.end(); } -#endif + // Unknown domain. Assume the op is not deterministic. return false; } diff --git a/onnxruntime/core/platform/path_lib.h b/onnxruntime/core/platform/path_lib.h index 96fbb2f12fa7b..a9d89f32e91d3 100644 --- a/onnxruntime/core/platform/path_lib.h +++ b/onnxruntime/core/platform/path_lib.h @@ -178,9 +178,8 @@ inline wchar_t GetPathSep() { } #endif -template -std::basic_string ConcatPathComponent(const std::basic_string& left, - const std::basic_string& right) { +inline std::basic_string ConcatPathComponent(std::basic_string_view left, + std::basic_string_view right) { std::basic_string ret(left); ret.append(1, GetPathSep()).append(right); return ret; diff --git a/onnxruntime/core/platform/posix/env.cc b/onnxruntime/core/platform/posix/env.cc index a5aa5773a3932..7cd81d89d7d4d 100644 --- a/onnxruntime/core/platform/posix/env.cc +++ b/onnxruntime/core/platform/posix/env.cc @@ -191,8 +191,10 @@ class PosixThread : public EnvThread { auto [err_no, err_msg] = GetSystemError(); ORT_THROW("pthread_attr_init failed, error code: ", err_no, " error msg: ", err_msg); } - if (thread_options.stack_size > 0) { - s = pthread_attr_setstacksize(&attr, thread_options.stack_size); + + size_t stack_size = thread_options.stack_size; + if (stack_size > 0) { + s = pthread_attr_setstacksize(&attr, stack_size); if (s != 0) { auto [err_no, err_msg] = GetSystemError(); ORT_THROW("pthread_attr_setstacksize failed, error code: ", err_no, " error msg: ", err_msg); @@ -248,11 +250,13 @@ class PosixThread : public EnvThread { << ", mask: " << *p->affinity; } else { auto [err_no, err_msg] = GetSystemError(ret); +#if !defined(USE_MIGRAPHX) LOGS_DEFAULT(ERROR) << "pthread_setaffinity_np failed for thread: " << syscall(SYS_gettid) << ", index: " << p->index << ", mask: " << *p->affinity << ", error code: " << err_no << " error msg: " << err_msg << ". Specify the number of threads explicitly so the affinity is not set."; +#endif } } #endif @@ -331,11 +335,12 @@ class PosixEnv : public Env { sleep_time.tv_nsec = 0; if (micros >= OneMillion) { - sleep_time.tv_sec = std::min(micros / OneMillion, std::numeric_limits::max()); + sleep_time.tv_sec = static_cast(std::min(micros / OneMillion, + std::numeric_limits::max())); micros -= static_cast(sleep_time.tv_sec) * OneMillion; } if (micros < OneMillion) { - sleep_time.tv_nsec = 1000 * micros; + sleep_time.tv_nsec = static_cast(1000 * micros); micros = 0; } while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR) { @@ -437,9 +442,9 @@ class PosixEnv : public Env { return Status::OK(); } - static const long page_size = sysconf(_SC_PAGESIZE); + static const size_t page_size = narrow(sysconf(_SC_PAGESIZE)); const FileOffsetType offset_to_page = offset % static_cast(page_size); - const size_t mapped_length = length + offset_to_page; + const size_t mapped_length = length + static_cast(offset_to_page); const FileOffsetType mapped_offset = offset - offset_to_page; void* const mapped_base = mmap(nullptr, mapped_length, PROT_READ | PROT_WRITE, MAP_PRIVATE, file_descriptor.Get(), mapped_offset); diff --git a/onnxruntime/core/platform/posix/logging/syslog_sink.cc b/onnxruntime/core/platform/posix/logging/syslog_sink.cc index f7fa679e3d73d..9fbd26f093498 100644 --- a/onnxruntime/core/platform/posix/logging/syslog_sink.cc +++ b/onnxruntime/core/platform/posix/logging/syslog_sink.cc @@ -20,10 +20,10 @@ void SysLogSink::SendImpl(const Timestamp& timestamp, const std::string& logger_ msg << timestamp << " [" << message.SeverityPrefix() << ":" << message.Category() << ":" << logger_id << ", " << message.Location().ToString() << "] " << message.Message(); - GSL_SUPPRESS(bounds .2) { + GSL_SUPPRESS(bounds.2) { syslog(SYSLOG_LEVEL[static_cast(message.Severity())] - '0', "%s", msg.str().c_str()); } } } // namespace logging -} // namespace onnxruntime \ No newline at end of file +} // namespace onnxruntime diff --git a/onnxruntime/core/platform/posix/stacktrace.cc b/onnxruntime/core/platform/posix/stacktrace.cc index 76864b2697e22..8af418a88c9c5 100644 --- a/onnxruntime/core/platform/posix/stacktrace.cc +++ b/onnxruntime/core/platform/posix/stacktrace.cc @@ -19,7 +19,7 @@ std::vector GetStackTrace() { void* array[kCallstackLimit]; char** strings = nullptr; - size_t size = backtrace(array, kCallstackLimit); + int size = backtrace(array, kCallstackLimit); stack.reserve(size); strings = backtrace_symbols(array, size); @@ -34,8 +34,8 @@ std::vector GetStackTrace() { // >addr2line -f -C -e /home/me/src/github/onnxruntime/build/Linux/Debug/onnxruntime_test_all +0x3f46cc // hide GetStackTrace so the output starts with the 'real' location - constexpr size_t start_frame = 1; - for (size_t i = start_frame; i < size; i++) { + constexpr int start_frame = 1; + for (int i = start_frame; i < size; i++) { stack.push_back(strings[i]); } diff --git a/onnxruntime/core/platform/windows/debug_alloc.cc b/onnxruntime/core/platform/windows/debug_alloc.cc index ab1ab019cb0f9..b08d189f79866 100644 --- a/onnxruntime/core/platform/windows/debug_alloc.cc +++ b/onnxruntime/core/platform/windows/debug_alloc.cc @@ -197,7 +197,8 @@ Memory_LeakCheck::~Memory_LeakCheck() { std::string string; char buffer[1024]; - _snprintf_s(buffer, _TRUNCATE, "%IX bytes at location 0x%08IX\n", entry.cbData - sizeof(MemoryBlock), UINT_PTR(pBlock)); + _snprintf_s(buffer, _TRUNCATE, "%Iu bytes at location 0x%08IX\n", entry.cbData - sizeof(MemoryBlock), + UINT_PTR(pBlock)); string.append(buffer); for (auto& p : block.m_pTraces) { if (!p) break; diff --git a/onnxruntime/core/platform/windows/env.cc b/onnxruntime/core/platform/windows/env.cc index b9617accd60dc..f02c61daabeed 100644 --- a/onnxruntime/core/platform/windows/env.cc +++ b/onnxruntime/core/platform/windows/env.cc @@ -137,12 +137,20 @@ class WindowsThread : public EnvThread { static unsigned __stdcall ThreadMain(void* param) { std::unique_ptr p(static_cast(param)); - const ORTCHAR_T* name_prefix = - (p->name_prefix == nullptr || wcslen(p->name_prefix) == 0) ? L"onnxruntime" : p->name_prefix; - std::wostringstream oss; - oss << name_prefix << "-" << p->index; - // Ignore the error - (void)SetThreadDescription(GetCurrentThread(), oss.str().c_str()); + // Not all machines have kernel32.dll and/or SetThreadDescription (e.g. Azure App Service sandbox) + // so we need to ensure it's available before calling. + HMODULE kernelModule = GetModuleHandle(TEXT("kernel32.dll")); + if (kernelModule != nullptr) { + auto setThreadDescriptionFn = (SetThreadDescriptionFunc)GetProcAddress(kernelModule, "SetThreadDescription"); + if (setThreadDescriptionFn != nullptr) { + const ORTCHAR_T* name_prefix = (p->name_prefix == nullptr || wcslen(p->name_prefix) == 0) ? L"onnxruntime" + : p->name_prefix; + std::wostringstream oss; + oss << name_prefix << "-" << p->index; + // Ignore any errors + (void)(setThreadDescriptionFn)(GetCurrentThread(), oss.str().c_str()); + } + } unsigned ret = 0; ORT_TRY { @@ -423,7 +431,7 @@ Status WindowsEnv::MapFileIntoMemory(_In_z_ const ORTCHAR_T* file_path, 0, static_cast(mapped_offset), mapped_length); - GSL_SUPPRESS(r .11) + GSL_SUPPRESS(r.11) mapped_memory = MappedMemoryPtr{reinterpret_cast(mapped_base) + offset_to_page, OrtCallbackInvoker{OrtCallback{UnmapFile, new UnmapFileParam{mapped_base, mapped_length}}}}; diff --git a/onnxruntime/core/platform/windows/env.h b/onnxruntime/core/platform/windows/env.h index 0df4c2b94950e..79739db9e5640 100644 --- a/onnxruntime/core/platform/windows/env.h +++ b/onnxruntime/core/platform/windows/env.h @@ -51,7 +51,7 @@ class WindowsEnv : public Env { #if defined(_MSC_VER) && !defined(__clang__) #pragma warning(pop) #endif - void WindowsEnv::SleepForMicroseconds(int64_t micros) const override; + void SleepForMicroseconds(int64_t micros) const override; static int DefaultNumCores(); int GetNumPhysicalCpuCores() const override; std::vector GetDefaultThreadAffinities() const override; diff --git a/onnxruntime/core/platform/windows/stacktrace.cc b/onnxruntime/core/platform/windows/stacktrace.cc index 954c3c2a5d6de..cac6f4f29043b 100644 --- a/onnxruntime/core/platform/windows/stacktrace.cc +++ b/onnxruntime/core/platform/windows/stacktrace.cc @@ -5,9 +5,12 @@ #include #include #include - -#include -#include +#ifdef __has_include +#if __has_include() +#include +#endif +#endif +#include #include "core/common/logging/logging.h" #include "core/common/gsl.h" @@ -22,10 +25,6 @@ class CaptureStackTrace { std::vector Trace() const; private: - std::string Lookup(void* address_in) const; - - HANDLE process_ = GetCurrentProcess(); - static const int kCallstackLimit = 64; // Maximum depth of callstack }; } // namespace detail @@ -33,7 +32,7 @@ class CaptureStackTrace { std::vector GetStackTrace() { #ifndef NDEBUG // TVM need to run with shared CRT, so won't work with debug helper now -#if !(defined _OPSCHEMA_LIB_) && !(defined _GAMING_XBOX) +#if (defined __cpp_lib_stacktrace) && !(defined _OPSCHEMA_LIB_) && !(defined _GAMING_XBOX) && !(defined ONNXRUNTIME_ENABLE_MEMLEAK_CHECK) return detail::CaptureStackTrace().Trace(); #else return {}; @@ -45,104 +44,20 @@ std::vector GetStackTrace() { namespace detail { #ifndef NDEBUG -#if !(defined _OPSCHEMA_LIB_) && !(defined _GAMING_XBOX) -class SymbolHelper { - public: - SymbolHelper() noexcept { - SymSetOptions(SymGetOptions() | SYMOPT_DEFERRED_LOADS); - // this could have been called earlier by a higher level component, so failure doesn't necessarily mean - // this won't work. however we should only call SymCleanup if it was successful. - if (SymInitialize(process_, nullptr, true)) { - cleanup_ = true; - } else { - // Log it so we know it happened. Can't do anything else about it. - LOGS_DEFAULT(WARNING) << "Failed to initialize symbols for providing stack trace. Error: 0x" - << std::hex << GetLastError(); - } - } - - struct Symbol : SYMBOL_INFO { - Symbol() noexcept { - SizeOfStruct = sizeof(SYMBOL_INFO); - GSL_SUPPRESS(bounds .3) - MaxNameLen = _countof(buffer); - } - - char buffer[1024] = {0}; - }; - - struct Line : IMAGEHLP_LINE64 { - Line() noexcept { - SizeOfStruct = sizeof(IMAGEHLP_LINE64); - } - }; - - ~SymbolHelper() { - if (cleanup_) - SymCleanup(process_); - } - - private: - ORT_DISALLOW_COPY_ASSIGNMENT_AND_MOVE(SymbolHelper); - - HANDLE process_ = GetCurrentProcess(); - bool cleanup_ = false; -}; +#if (defined __cpp_lib_stacktrace) && !(defined _OPSCHEMA_LIB_) && !(defined _GAMING_XBOX) && !(defined ONNXRUNTIME_ENABLE_MEMLEAK_CHECK) std::vector CaptureStackTrace::Trace() const { -#pragma warning(push) -#pragma warning(disable : 26426) - static SymbolHelper sh; -#pragma warning(pop) - std::vector stacktrace; - - PVOID frames[kCallstackLimit]; - const auto f = gsl::make_span(frames); - const auto num_frames = CaptureStackBackTrace(0, kCallstackLimit, f.data(), nullptr); - - stacktrace.reserve(num_frames); - - // hide CaptureStackTrace::Trace and GetStackTrace so the output starts with the 'real' location - constexpr int frames_to_skip = 2; - - // we generally want to skip the first two frames, but if something weird is going on (e.g. code coverage is - // running) and we only have 1 or 2 frames, output them so there's at least something that may be meaningful - const uint16_t start_frame = num_frames > frames_to_skip ? frames_to_skip : 0; - for (uint16_t i = start_frame; i < num_frames; ++i) { - stacktrace.push_back(Lookup(f[i])); + auto st = std::stacktrace::current(2); + for (const auto& stack : st) { + std::ostringstream oss; + oss << stack.source_file() << "(" << stack.source_line() << "): " << stack.description(); + stacktrace.push_back(oss.str()); } return stacktrace; } -std::string CaptureStackTrace::Lookup(void* address_in) const { - SymbolHelper::Symbol symbol; - std::ostringstream result; - - DWORD64 address = 0; - - GSL_SUPPRESS(type .1) { - address = reinterpret_cast(address_in); - } - - if (SymFromAddr(process_, address, 0, &symbol) == false) { - result << "0x" << std::hex << address << " (Unknown symbol)"; - } else - GSL_SUPPRESS(bounds .3) // symbol.Name converts to char* - { - SymbolHelper::Line line; - DWORD displacement; - if (SymGetLineFromAddr64(process_, address, &displacement, &line) == false) { - result << "???: " << symbol.Name; - } else { - result << line.FileName << '(' << line.LineNumber << "): " << symbol.Name; - } - } - - return result.str(); -} - #endif #endif } // namespace detail diff --git a/onnxruntime/core/providers/acl/acl_execution_provider.cc b/onnxruntime/core/providers/acl/acl_execution_provider.cc index ebbdb1538843c..d19dc15e17f6d 100644 --- a/onnxruntime/core/providers/acl/acl_execution_provider.cc +++ b/onnxruntime/core/providers/acl/acl_execution_provider.cc @@ -87,32 +87,10 @@ std::shared_ptr GetAclKernelRegistry() { } // namespace acl -ACLExecutionProvider::ACLExecutionProvider(const ACLExecutionProviderInfo& info) - : IExecutionProvider{onnxruntime::kAclExecutionProvider} { - ORT_UNUSED_PARAMETER(info); - - AllocatorCreationInfo default_memory_info{ - [](int) { - return std::make_unique(OrtMemoryInfo(ACL, OrtAllocatorType::OrtDeviceAllocator)); - }, - 0, - info.create_arena}; - - InsertAllocator(CreateAllocator(default_memory_info)); - - AllocatorCreationInfo cpu_memory_info{ - [](int) { - return std::make_unique( - OrtMemoryInfo(ACL_CPU, OrtAllocatorType::OrtDeviceAllocator, OrtDevice(), 0, OrtMemTypeCPUOutput)); - }, - 0, - info.create_arena}; - - InsertAllocator(CreateAllocator(cpu_memory_info)); -} +ACLExecutionProvider::ACLExecutionProvider(const ACLExecutionProviderInfo&) + : IExecutionProvider{onnxruntime::kAclExecutionProvider} {} -ACLExecutionProvider::~ACLExecutionProvider() { -} +ACLExecutionProvider::~ACLExecutionProvider() {} std::shared_ptr ACLExecutionProvider::GetKernelRegistry() const { static std::shared_ptr kernel_registry = onnxruntime::acl::GetAclKernelRegistry(); diff --git a/onnxruntime/core/providers/acl/acl_execution_provider.h b/onnxruntime/core/providers/acl/acl_execution_provider.h index 587d28e47ce50..126656e0956bb 100755 --- a/onnxruntime/core/providers/acl/acl_execution_provider.h +++ b/onnxruntime/core/providers/acl/acl_execution_provider.h @@ -4,7 +4,6 @@ #pragma once -#include "core/framework/allocatormgr.h" #include "core/framework/execution_provider.h" #include "core/graph/constants.h" diff --git a/onnxruntime/core/providers/armnn/armnn_execution_provider.cc b/onnxruntime/core/providers/armnn/armnn_execution_provider.cc index fdbf3712ccbc0..f35b7b918613b 100644 --- a/onnxruntime/core/providers/armnn/armnn_execution_provider.cc +++ b/onnxruntime/core/providers/armnn/armnn_execution_provider.cc @@ -96,25 +96,8 @@ std::shared_ptr GetArmNNKernelRegistry() { } // namespace armnn_ep -ArmNNExecutionProvider::ArmNNExecutionProvider(const ArmNNExecutionProviderInfo& info) +ArmNNExecutionProvider::ArmNNExecutionProvider(const ArmNNExecutionProviderInfo&) : IExecutionProvider{onnxruntime::kArmNNExecutionProvider} { - ORT_UNUSED_PARAMETER(info); - - AllocatorCreationInfo default_memory_info{ - [](int) { - return std::make_unique(OrtMemoryInfo(ArmNN, OrtAllocatorType::OrtDeviceAllocator)); - }, - 0}; - - InsertAllocator(CreateAllocator(default_memory_info)); - - AllocatorCreationInfo cpu_memory_info{ - [](int) { - return std::make_unique( - OrtMemoryInfo(ArmNN_CPU, OrtAllocatorType::OrtDeviceAllocator, OrtDevice(), 0, OrtMemTypeCPUOutput)); - }}; - - InsertAllocator(CreateAllocator(cpu_memory_info)); } ArmNNExecutionProvider::~ArmNNExecutionProvider() { diff --git a/onnxruntime/core/providers/armnn/armnn_execution_provider.h b/onnxruntime/core/providers/armnn/armnn_execution_provider.h index 5728ec906a114..16b770ecfaffa 100755 --- a/onnxruntime/core/providers/armnn/armnn_execution_provider.h +++ b/onnxruntime/core/providers/armnn/armnn_execution_provider.h @@ -4,7 +4,6 @@ #pragma once -#include "core/framework/allocatormgr.h" #include "core/framework/execution_provider.h" #include "core/graph/constants.h" diff --git a/onnxruntime/core/providers/azure/azure_provider_factory_creator.h b/onnxruntime/core/providers/azure/azure_provider_factory_creator.h index 9254ade96095f..32fbca4a7dc73 100644 --- a/onnxruntime/core/providers/azure/azure_provider_factory_creator.h +++ b/onnxruntime/core/providers/azure/azure_provider_factory_creator.h @@ -5,6 +5,7 @@ #include #include +#include #include "core/providers/providers.h" namespace onnxruntime { diff --git a/onnxruntime/core/providers/cann/cann_allocator.cc b/onnxruntime/core/providers/cann/cann_allocator.cc index 7f9f9e2ffd7a9..060afeb06745b 100644 --- a/onnxruntime/core/providers/cann/cann_allocator.cc +++ b/onnxruntime/core/providers/cann/cann_allocator.cc @@ -6,7 +6,6 @@ #include "core/providers/shared_library/provider_api.h" #include "core/providers/cann/cann_call.h" #include "core/providers/cann/cann_allocator.h" -#include "core/framework/allocatormgr.h" #include "core/providers/cann/npu_data_transfer.h" namespace onnxruntime { diff --git a/onnxruntime/core/providers/cann/cann_common.cc b/onnxruntime/core/providers/cann/cann_common.cc index e30ddba3e09ef..f1e2e970c471c 100644 --- a/onnxruntime/core/providers/cann/cann_common.cc +++ b/onnxruntime/core/providers/cann/cann_common.cc @@ -8,9 +8,9 @@ namespace onnxruntime { namespace cann { template <> -const MLFloat16 Constants::Zero = MLFloat16(static_cast(0)); +const MLFloat16 Constants::Zero = MLFloat16::FromBits(static_cast(0)); template <> -const MLFloat16 Constants::One = MLFloat16(static_cast(0x3C00)); +const MLFloat16 Constants::One = MLFloat16::FromBits(static_cast(0x3C00)); template <> const float Constants::Zero = 0; diff --git a/onnxruntime/core/providers/cann/cann_execution_provider.cc b/onnxruntime/core/providers/cann/cann_execution_provider.cc index 25f5bfadb3758..127c37bd84d0f 100644 --- a/onnxruntime/core/providers/cann/cann_execution_provider.cc +++ b/onnxruntime/core/providers/cann/cann_execution_provider.cc @@ -426,12 +426,16 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCannExecutionProvider, kOnnxDomain, class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCannExecutionProvider, kOnnxDomain, 14, double, Relu); class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCannExecutionProvider, kOnnxDomain, 14, 14, float, BatchNormalization); -class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCannExecutionProvider, kOnnxDomain, 14, Identity); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCannExecutionProvider, kOnnxDomain, + 14, 18, Identity); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCannExecutionProvider, kOnnxDomain, 14, Reshape); // op 15 class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCannExecutionProvider, kOnnxDomain, 15, float, BatchNormalization); +// op 19 +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCannExecutionProvider, kOnnxDomain, 19, Identity); + Status RegisterCANNKernels(KernelRegistry& kernel_registry) { static const BuildKernelCreateInfoFn function_table[] = { // op 1-9 @@ -1001,12 +1005,16 @@ Status RegisterCANNKernels(KernelRegistry& kernel_registry) { 14, double, Relu)>, BuildKernelCreateInfo, - BuildKernelCreateInfo, + BuildKernelCreateInfo, BuildKernelCreateInfo, // op 15 BuildKernelCreateInfo, + + // op 19 + BuildKernelCreateInfo, }; for (auto& function_table_entry : function_table) { @@ -1021,7 +1029,7 @@ Status RegisterCANNKernels(KernelRegistry& kernel_registry) { } // namespace cann CANNExecutionProvider::CANNExecutionProvider(const CANNExecutionProviderInfo& info) - : IExecutionProvider{onnxruntime::kCannExecutionProvider, true}, info_{info} { + : IExecutionProvider{onnxruntime::kCannExecutionProvider, OrtDevice(OrtDevice::NPU, OrtDevice::MemType::DEFAULT, info.device_id), true}, info_{info} { InitProviderOrtApi(); CANN_CALL_THROW(aclrtSetDevice(info_.device_id)); @@ -1434,79 +1442,50 @@ Status CANNExecutionProvider::Compile(const std::vector& fuse return Status::OK(); } -void CANNExecutionProvider::RegisterAllocator(AllocatorManager& allocator_manager) { - OrtDevice cann_device{OrtDevice::NPU, OrtDevice::MemType::DEFAULT, info_.device_id}; - OrtDevice pinned_device{OrtDevice::CPU, OrtDevice::MemType::CANN_PINNED, DEFAULT_CPU_ALLOCATOR_DEVICE_ID}; - OrtDevice cpu_device{OrtDevice::CPU, OrtDevice::MemType::DEFAULT, DEFAULT_CPU_ALLOCATOR_DEVICE_ID}; - - auto cann_alloc = IExecutionProvider::GetAllocator(OrtMemTypeDefault); - if (!cann_alloc) { - cann_alloc = allocator_manager.GetAllocator(OrtMemTypeDefault, cann_device); - - if (!cann_alloc) { - AllocatorCreationInfo default_memory_info( - [](OrtDevice::DeviceId id) { - return std::make_unique(id, CANN); - }, - cann_device.Id(), - true, - {info_.default_memory_arena_cfg ? *info_.default_memory_arena_cfg - : OrtArenaCfg(info_.npu_mem_limit, - static_cast(info_.arena_extend_strategy), - -1, - -1, - -1)}, - true, - false); - - cann_alloc = CreateAllocator(default_memory_info); - allocator_manager.InsertAllocator(cann_alloc); - } - - InsertAllocator(cann_alloc); - } - - auto cann_pinned_alloc = IExecutionProvider::GetAllocator(OrtMemTypeCPUOutput); - if (!cann_pinned_alloc) { - cann_pinned_alloc = allocator_manager.GetAllocator(OrtMemTypeCPUOutput, pinned_device); - - if (!cann_pinned_alloc) { - AllocatorCreationInfo pinned_memory_info( - [](OrtDevice::DeviceId device_id) { - return std::make_unique(device_id, CANN_PINNED); - }, - pinned_device.Id()); - - cann_pinned_alloc = CreateAllocator(pinned_memory_info); - allocator_manager.InsertAllocator(cann_pinned_alloc); - } - - InsertAllocator(cann_pinned_alloc); - } - - auto cann_cpu_alloc = IExecutionProvider::GetAllocator(OrtMemTypeCPUInput); - if (!cann_cpu_alloc) { - cann_cpu_alloc = allocator_manager.GetAllocator(OrtMemTypeCPUInput, cpu_device); - - if (!cann_cpu_alloc) { - AllocatorCreationInfo cpu_memory_info( - [](int device_id) { - return std::make_unique( - OrtMemoryInfo("CANN_CPU", OrtAllocatorType::OrtDeviceAllocator, OrtDevice(), device_id, - OrtMemTypeCPUInput)); - }, - cpu_device.Id()); - - cann_cpu_alloc = CreateAllocator(cpu_memory_info); - allocator_manager.InsertAllocator(cann_cpu_alloc); - } +AllocatorPtr CANNExecutionProvider::CreateCannAllocator(OrtDevice::DeviceId device_id, size_t npu_mem_limit, + ArenaExtendStrategy arena_extend_strategy, + OrtArenaCfg* default_memory_arena_cfg) { + AllocatorCreationInfo default_memory_info( + [](OrtDevice::DeviceId id) { + return std::make_unique(id, CANN); + }, + device_id, + true, + {default_memory_arena_cfg ? *default_memory_arena_cfg + : OrtArenaCfg(npu_mem_limit, + static_cast(arena_extend_strategy), + -1, + -1, + -1, + -1L)}, + true, + false); + + return CreateAllocator(default_memory_info); +} - InsertAllocator(cann_cpu_alloc); - } +std::vector CANNExecutionProvider::CreatePreferredAllocators() { + AllocatorCreationInfo pinned_memory_info( + [](OrtDevice::DeviceId device_id) { + return std::make_unique(device_id, CANN_PINNED); + }, + DEFAULT_CPU_ALLOCATOR_DEVICE_ID); + + return std::vector{ + CreateCannAllocator(info_.device_id, info_.npu_mem_limit, info_.arena_extend_strategy, + info_.default_memory_arena_cfg), + CreateAllocator(pinned_memory_info), + }; } -void CANNExecutionProvider::RegisterStreamHandlers(IStreamCommandHandleRegistry& stream_handle_registry) const { +void CANNExecutionProvider::RegisterStreamHandlers(IStreamCommandHandleRegistry& stream_handle_registry, AllocatorMap&) const { RegisterCannStreamHandles(stream_handle_registry, OrtDevice::NPU); } +OrtDevice CANNExecutionProvider::GetOrtDeviceByMemType(OrtMemType mem_type) const { + if (mem_type == OrtMemTypeCPUInput) return OrtDevice(); + if (mem_type == OrtMemTypeCPUOutput) return OrtDevice(OrtDevice::CPU, OrtDevice::MemType::CANN_PINNED, 0); + return default_device_; +} + } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cann/cann_execution_provider.h b/onnxruntime/core/providers/cann/cann_execution_provider.h index 9391842541298..76d3d9c331563 100644 --- a/onnxruntime/core/providers/cann/cann_execution_provider.h +++ b/onnxruntime/core/providers/cann/cann_execution_provider.h @@ -10,7 +10,6 @@ #include #include "core/providers/shared_library/provider_api.h" -#include "core/framework/allocatormgr.h" #include "core/framework/arena_extend_strategy.h" #include "core/framework/execution_provider.h" #include "core/platform/ort_mutex.h" @@ -36,22 +35,6 @@ class CANNExecutionProvider : public IExecutionProvider { Status OnRunStart() override; - template - IAllocatorUniquePtr GetScratchBuffer(size_t count_or_bytes, Stream* stream, WaitNotificationFn wait_fn) const { - if (count_or_bytes == 0) - return nullptr; - - return IAllocator::MakeUniquePtr(GetAllocator(OrtMemTypeDefault), count_or_bytes, false, stream, wait_fn); - } - - template - IAllocatorUniquePtr GetScratchBufferOnCANNPinned(size_t count_or_bytes) const { - if (count_or_bytes == 0) - return nullptr; - - return IAllocator::MakeUniquePtr(GetAllocator(OrtMemTypeCPU), count_or_bytes); - } - template Status Fill(Tensor* y, void* addr, aclrtStream stream) const { return cann::Fill(y, addr, stream); @@ -81,9 +64,15 @@ class CANNExecutionProvider : public IExecutionProvider { return CANNExecutionProviderInfo::ToProviderOptions(info_); } - void RegisterAllocator(AllocatorManager& allocator_manager) override; + static AllocatorPtr CreateCannAllocator(OrtDevice::DeviceId device_id, size_t npu_mem_limit, + ArenaExtendStrategy arena_extend_strategy, + OrtArenaCfg* default_memory_arena_cfg); + + void RegisterStreamHandlers(IStreamCommandHandleRegistry& stream_handle_registry, AllocatorMap&) const override; + + OrtDevice GetOrtDeviceByMemType(OrtMemType mem_type) const override; - void RegisterStreamHandlers(IStreamCommandHandleRegistry& stream_handle_registry) const override; + std::vector CreatePreferredAllocators() override; private: CANNExecutionProviderInfo info_; diff --git a/onnxruntime/core/providers/cann/cann_kernel.h b/onnxruntime/core/providers/cann/cann_kernel.h index cd2998795d270..90180144202a7 100644 --- a/onnxruntime/core/providers/cann/cann_kernel.h +++ b/onnxruntime/core/providers/cann/cann_kernel.h @@ -44,12 +44,8 @@ class CannKernel : public OpKernel { template inline IAllocatorUniquePtr GetScratchBuffer(size_t count_or_bytes, onnxruntime::Stream* stream) const { - return provider_->GetScratchBuffer(count_or_bytes, stream, WaitCannNotificationOnDevice); - } - - template - inline IAllocatorUniquePtr GetScratchBufferOnCANNPinned(size_t count_or_bytes) const { - return provider_->GetScratchBufferOnCANNPinned(count_or_bytes); + if (count_or_bytes == 0) return nullptr; + return IAllocator::MakeUniquePtr(Info().GetAllocator(OrtMemTypeDefault), count_or_bytes, false, stream, WaitCannNotificationOnDevice); } template diff --git a/onnxruntime/core/providers/cann/cann_provider_factory.cc b/onnxruntime/core/providers/cann/cann_provider_factory.cc index 636ca22591fbe..679a42be868cb 100644 --- a/onnxruntime/core/providers/cann/cann_provider_factory.cc +++ b/onnxruntime/core/providers/cann/cann_provider_factory.cc @@ -32,6 +32,21 @@ std::unique_ptr CANNProviderFactory::CreateProvider() { } struct ProviderInfo_CANN_Impl : ProviderInfo_CANN { + int cannGetDeviceCount() override { + uint32_t num_devices = 0; + CANN_CALL_THROW(aclrtGetDeviceCount(&num_devices)); + return num_devices; + } + + void cannMemcpy_HostToDevice(void* dst, const void* src, size_t count) override { + CANN_CALL_THROW(aclrtMemcpy(dst, count, src, count, ACL_MEMCPY_HOST_TO_DEVICE)); + CANN_CALL_THROW(aclrtSynchronizeStream(0)); + } + + void cannMemcpy_DeviceToHost(void* dst, const void* src, size_t count) override { + CANN_CALL_THROW(aclrtMemcpy(dst, count, src, count, ACL_MEMCPY_DEVICE_TO_HOST)); + } + void CANNExecutionProviderInfo__FromProviderOptions(const ProviderOptions& options, CANNExecutionProviderInfo& info) override { info = CANNExecutionProviderInfo::FromProviderOptions(options); @@ -41,6 +56,13 @@ struct ProviderInfo_CANN_Impl : ProviderInfo_CANN { CreateExecutionProviderFactory(const CANNExecutionProviderInfo& info) override { return std::make_shared(info); } + + std::shared_ptr CreateCannAllocator(int16_t device_id, size_t npu_mem_limit, + onnxruntime::ArenaExtendStrategy arena_extend_strategy, + OrtArenaCfg* default_memory_arena_cfg) override { + return CANNExecutionProvider::CreateCannAllocator(device_id, npu_mem_limit, arena_extend_strategy, + default_memory_arena_cfg); + } } g_info; struct CANN_Provider : Provider { diff --git a/onnxruntime/core/providers/cann/cann_provider_factory.h b/onnxruntime/core/providers/cann/cann_provider_factory.h index ec40812023249..44068760df7b7 100644 --- a/onnxruntime/core/providers/cann/cann_provider_factory.h +++ b/onnxruntime/core/providers/cann/cann_provider_factory.h @@ -10,14 +10,24 @@ #include "core/providers/cann/cann_provider_options.h" namespace onnxruntime { +class IAllocator; +class IDataTransfer; struct IExecutionProviderFactory; struct CANNExecutionProviderInfo; +enum class ArenaExtendStrategy : int32_t; struct ProviderInfo_CANN { + virtual int cannGetDeviceCount() = 0; + + virtual void cannMemcpy_HostToDevice(void* dst, const void* src, size_t count) = 0; + virtual void cannMemcpy_DeviceToHost(void* dst, const void* src, size_t count) = 0; virtual void CANNExecutionProviderInfo__FromProviderOptions(const onnxruntime::ProviderOptions& options, onnxruntime::CANNExecutionProviderInfo& info) = 0; virtual std::shared_ptr CreateExecutionProviderFactory(const onnxruntime::CANNExecutionProviderInfo& info) = 0; + virtual std::shared_ptr + CreateCannAllocator(int16_t device_id, size_t npu_mem_limit, onnxruntime::ArenaExtendStrategy arena_extend_strategy, + OrtArenaCfg* default_memory_arena_cfg) = 0; }; } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cann/tensor/identity_op.cc b/onnxruntime/core/providers/cann/tensor/identity_op.cc index 0256c29e6da8d..ffe7e72b64196 100644 --- a/onnxruntime/core/providers/cann/tensor/identity_op.cc +++ b/onnxruntime/core/providers/cann/tensor/identity_op.cc @@ -53,15 +53,25 @@ ONNX_OPERATOR_VERSIONED_KERNEL_EX( .Alias(0, 0), IdentityOp); -ONNX_OPERATOR_KERNEL_EX( +ONNX_OPERATOR_VERSIONED_KERNEL_EX( Identity, kOnnxDomain, - 14, + 14, 18, kCannExecutionProvider, (*KernelDefBuilder::Create()) .TypeConstraint("V", DataTypeImpl::AllFixedSizeTensorAndSequenceTensorTypes()) .Alias(0, 0), IdentityOp); +ONNX_OPERATOR_KERNEL_EX( + Identity, + kOnnxDomain, + 19, + kCannExecutionProvider, + (*KernelDefBuilder::Create()) + .TypeConstraint("V", DataTypeImpl::AllFixedSizeTensorAndSequenceTensorTypesIRv9()) + .Alias(0, 0), + IdentityOp); + } // namespace cann } // namespace onnxruntime diff --git a/onnxruntime/core/providers/common.h b/onnxruntime/core/providers/common.h index c821ff0650c70..16c8e2045f951 100644 --- a/onnxruntime/core/providers/common.h +++ b/onnxruntime/core/providers/common.h @@ -5,6 +5,7 @@ #include #include +#include "core/common/safeint.h" #ifndef SHARED_PROVIDER #include "core/common/common.h" @@ -13,6 +14,13 @@ namespace onnxruntime { +/** +Returns whether `axis` is in range [-`tensor_rank`, `tensor_rank`). +**/ +constexpr inline bool IsAxisInRange(int64_t axis, int64_t tensor_rank) { + return axis >= -tensor_rank && axis <= tensor_rank - 1; +} + /** Handle a potentially negative axis. Enforces negative axis is valid. @param axis Axis to convert from negative to positive if needed. @@ -20,7 +28,7 @@ Handle a potentially negative axis. Enforces negative axis is valid. @returns non-negative axis. */ inline int64_t HandleNegativeAxis(int64_t axis, int64_t tensor_rank) { - ORT_ENFORCE(axis >= -tensor_rank && axis <= tensor_rank - 1, "axis ", axis, + ORT_ENFORCE(IsAxisInRange(axis, tensor_rank), "axis ", axis, " is not in valid range [-", tensor_rank, ",", tensor_rank - 1, "]"); // Handle negative axis return axis < 0 ? axis + tensor_rank : axis; @@ -96,8 +104,8 @@ inline Status ComputePad(const int64_t in_dim, // The ONNX spec says if `auto_pad` attribute is set, pad until the `legacy_target_size` // is `ceil (in_dim / stride)`. The following line of code is essentially just that and // is retained as is - int64_t legacy_target_size = (in_dim + stride - 1) / stride; - int64_t pad_needed = (legacy_target_size - 1) * stride + kernel - in_dim; + SafeInt legacy_target_size = (SafeInt(in_dim) + stride - 1) / stride; + SafeInt pad_needed = (legacy_target_size - 1) * stride + kernel - in_dim; // make sure padding is symmetric if (force_symmetric_auto_padding) { // Inlining math::roundUpPow2() from util/math.h to avoid bringing in the transitive dependencies. @@ -121,8 +129,9 @@ inline Status ComputePad(const int64_t in_dim, constexpr inline int64_t ComputeOutputShape(const int64_t in_dim, const int64_t stride, const int64_t kernel, const int64_t dilation, const int64_t pad_head, const int64_t pad_tail) { - const int64_t dkernel = dilation * (kernel - 1) + 1; - return static_cast(static_cast(in_dim + pad_head + pad_tail - dkernel) / stride + 1); + const SafeInt dkernel = SafeInt(dilation) * (kernel - 1) + 1; + int64_t dkernel_value = SafeInt(in_dim) + pad_head + pad_tail - dkernel; + return static_cast(static_cast(dkernel_value) / stride + 1); } inline Status ComputePadAndOutputShape(const int64_t in_dim, diff --git a/onnxruntime/core/providers/coreml/builders/coreml_spec.h b/onnxruntime/core/providers/coreml/builders/coreml_spec.h new file mode 100644 index 0000000000000..631bb7e258303 --- /dev/null +++ b/onnxruntime/core/providers/coreml/builders/coreml_spec.h @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +// TODO come up with a more intuitive way of limiting this to Apple platform builds +// E.g., putting CoreML EP files that should be enabled iff `defined(__APPLE__)` in a separate directory. +#if !defined(__APPLE__) +#error "This file should only be included when building on Apple platforms." +#endif + +#include "coreml/Model.pb.h" + +namespace COREML_SPEC = CoreML::Specification; diff --git a/onnxruntime/core/providers/coreml/builders/helper.cc b/onnxruntime/core/providers/coreml/builders/helper.cc index f2055aa8e8f0a..897856256cc79 100644 --- a/onnxruntime/core/providers/coreml/builders/helper.cc +++ b/onnxruntime/core/providers/coreml/builders/helper.cc @@ -14,68 +14,76 @@ #include "core/graph/graph_viewer.h" #include "core/providers/common.h" #include "core/providers/coreml/builders/op_builder_factory.h" +#include "core/providers/coreml/builders/op_builder.h" +#include "core/providers/coreml/coreml_provider_factory.h" // for COREMLFlags #include "core/providers/coreml/model/host_utils.h" +#include "core/providers/coreml/shape_utils.h" namespace onnxruntime { namespace coreml { -bool GetShape(const NodeArg& node_arg, std::vector& shape, const logging::Logger& logger) { - const auto* shape_proto = node_arg.Shape(); - if (!shape_proto) { - LOGS(logger, WARNING) << "NodeArg [" << node_arg.Name() << "] has no shape info"; - return false; - } - - // We already checked the shape has no dynamic dimension - for (const auto& dim : shape_proto->dim()) { - shape.push_back(dim.dim_value()); - } - - return true; +OpBuilderInputParams MakeOpBuilderParams(const GraphViewer& graph_viewer, uint32_t coreml_flags) { + return OpBuilderInputParams{graph_viewer, + (coreml_flags & COREML_FLAG_ONLY_ALLOW_STATIC_INPUT_SHAPES) != 0}; } -bool IsNodeSupported(const Node& node, const GraphViewer& graph_viewer, const logging::Logger& logger) { +bool IsNodeSupported(const Node& node, const OpBuilderInputParams& input_params, const logging::Logger& logger) { const auto& op_builders = GetOpBuilders(); if (Contains(op_builders, node.OpType())) { const auto* op_builder = op_builders.at(node.OpType()); - OpBuilderInputParams input_params(graph_viewer); return op_builder->IsOpSupported(node, input_params, logger); } else { return false; } } -bool IsInputSupported(const NodeArg& input, const std::string& parent_name, const logging::Logger& logger) { +bool IsInputSupported(const NodeArg& input, const std::string& parent_name, + const OpBuilderInputParams& input_params, const logging::Logger& logger) { + if (!input.Exists()) { + // optional input that is not provided + return true; + } + const auto& input_name = input.Name(); - const auto* shape_proto = input.Shape(); + std::vector shape; // We do not support input with no shape - if (!shape_proto) { + if (!GetShape(input, shape, logger)) { LOGS(logger, VERBOSE) << "Input [" << input_name << "] of [" << parent_name - << "] has not shape"; + << "] has no shape"; return false; } - for (const auto& dim : shape_proto->dim()) { - // For now we do not support dynamic shape - if (!dim.has_dim_value()) { - LOGS(logger, WARNING) << "Dynamic shape is not supported for now, for input:" << input_name; - return false; - } + if (input_params.only_allow_static_input_shapes && !IsStaticShape(shape)) { + LOGS(logger, VERBOSE) << "CoreML EP is set to only allow static input shapes. Input has a dynamic shape. Input: " + << input_name << ", shape: " << Shape2String(shape); + return false; + } + for (const auto dim : shape) { // For some undocumented reason, Apple CoreML framework will fail loading the model if the model // input has dimension > 16384 // See this issue, https://github.com/apple/coremltools/issues/1003 - if (dim.dim_value() > 16384) { - LOGS(logger, WARNING) << "CoreML does not support input dim > 16384, input:" << input_name - << ", actual dim: " << dim.dim_value(); + if (dim > 16384) { + LOGS(logger, WARNING) << "CoreML does not support input dim > 16384. Input:" << input_name + << ", shape: " << Shape2String(shape); return false; } } + // Limit input shape rank to 5. + // CoreML doesn't currently support shapes with rank greater that 5. + // https://github.com/apple/coremltools/issues/832 + if (shape.size() > 5) { + LOGS(logger, VERBOSE) << "CoreML EP doesn't allow input shapes with rank greater than 5. Input: " + << input_name << ", shape: " << Shape2String(shape); + return false; + } + return true; } std::unordered_set GetSupportedNodes(const GraphViewer& graph_viewer, + const OpBuilderInputParams& input_params, const logging::Logger& logger) { std::unordered_set supported_nodes{}; @@ -86,14 +94,8 @@ std::unordered_set GetSupportedNodes(const GraphViewer& graph_viewe } #endif - const auto& graph_inputs = graph_viewer.GetInputs(); - if (std::any_of(graph_inputs.begin(), graph_inputs.end(), - [&](const NodeArg* input) { return !IsInputSupported(*input, "graph", logger); })) { - return supported_nodes; - } - for (const auto& node : graph_viewer.Nodes()) { - const bool supported = IsNodeSupported(node, graph_viewer, logger); + const bool supported = IsNodeSupported(node, input_params, logger); LOGS(logger, VERBOSE) << "Operator type: [" << node.OpType() << "] index: [" << node.Index() << "] name: [" << node.Name() @@ -107,6 +109,16 @@ std::unordered_set GetSupportedNodes(const GraphViewer& graph_viewe return supported_nodes; } +bool CheckIsConstantInitializer(const NodeArg& node_arg, const GraphViewer& graph_viewer, + const logging::Logger& logger, std::string_view input_description) { + if (graph_viewer.GetConstantInitializer(node_arg.Name(), true) == nullptr) { + LOGS(logger, VERBOSE) << input_description << " (NodeArg name: '" << node_arg.Name() + << "') is not a constant initializer tensor"; + return false; + } + return true; +} + bool HasNeuralEngine(const logging::Logger& logger) { bool has_neural_engine = false; diff --git a/onnxruntime/core/providers/coreml/builders/helper.h b/onnxruntime/core/providers/coreml/builders/helper.h index 724117a715a54..d8b27ac76ae73 100644 --- a/onnxruntime/core/providers/coreml/builders/helper.h +++ b/onnxruntime/core/providers/coreml/builders/helper.h @@ -3,8 +3,13 @@ #pragma once -#include "core/common/status.h" +#include +#include +#include +#include + #include "core/graph/basic_types.h" +#include "core/providers/coreml/builders/op_builder.h" namespace onnxruntime { @@ -18,16 +23,21 @@ class Logger; namespace coreml { -bool GetShape(const NodeArg& node_arg, std::vector& shape, const logging::Logger& logger); +OpBuilderInputParams MakeOpBuilderParams(const GraphViewer& graph_viewer, uint32_t coreml_flags); -bool IsInputSupported(const NodeArg& node_arg, const std::string& parent_name, const logging::Logger& logger); +bool IsInputSupported(const NodeArg& node_arg, const std::string& parent_name, + const OpBuilderInputParams& input_params, const logging::Logger& logger); -bool IsNodeSupported(const Node& node, const GraphViewer& graph_viewer, const logging::Logger& logger); +bool IsNodeSupported(const Node& node, const OpBuilderInputParams& input_params, const logging::Logger& logger); // Gets the set of nodes that are supported by the CoreML EP. std::unordered_set GetSupportedNodes(const GraphViewer& graph_viewer, + const OpBuilderInputParams& input_params, const logging::Logger& logger); +bool CheckIsConstantInitializer(const NodeArg& node_arg, const GraphViewer& graph_viewer, + const logging::Logger& logger, std::string_view input_description); + // CoreML is more efficient running using Apple Neural Engine // This is to detect if the current system has Apple Neural Engine bool HasNeuralEngine(const logging::Logger& logger); diff --git a/onnxruntime/core/providers/coreml/builders/impl/LRN_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/LRN_op_builder.cc index 3ace8e1fc3414..53f18b205880c 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/LRN_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/LRN_op_builder.cc @@ -1,14 +1,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/providers/shared/utils/utils.h" #include "core/providers/coreml/builders/helper.h" +#include "core/providers/coreml/builders/impl/base_op_builder.h" +#include "core/providers/coreml/builders/op_builder_factory.h" +#include "core/providers/coreml/shape_utils.h" +#include "core/providers/shared/utils/utils.h" + #ifdef __APPLE__ #include "core/providers/coreml/builders/model_builder.h" #endif -#include "core/providers/coreml/builders/op_builder_factory.h" - -#include "base_op_builder.h" namespace onnxruntime { namespace coreml { @@ -17,8 +18,8 @@ class LRNOpBuilder : public BaseOpBuilder { // Add operator related #ifdef __APPLE__ private: - [[nodiscard]] Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, - const logging::Logger& logger) const override; + Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, + const logging::Logger& logger) const override; #endif // Operator support related 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 fe03f3360bdf8..88d6616b4e097 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/activation_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/activation_op_builder.cc @@ -1,18 +1,20 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#ifdef __APPLE__ -#include "core/framework/tensorprotoutils.h" -#include "core/providers/coreml/builders/impl/builder_utils.h" -#include "core/providers/coreml/builders/model_builder.h" -#endif #include "core/common/narrow.h" +#include "core/optimizer/initializer.h" #include "core/providers/common.h" #include "core/providers/coreml/builders/helper.h" #include "core/providers/coreml/builders/impl/base_op_builder.h" #include "core/providers/coreml/builders/op_builder_factory.h" +#include "core/providers/coreml/shape_utils.h" #include "core/providers/shared/utils/utils.h" -#include "core/optimizer/initializer.h" + +#ifdef __APPLE__ +#include "core/framework/tensorprotoutils.h" +#include "core/providers/coreml/builders/impl/builder_utils.h" +#include "core/providers/coreml/builders/model_builder.h" +#endif namespace onnxruntime { namespace coreml { @@ -24,8 +26,8 @@ class ActivationOpBuilder : public BaseOpBuilder { void AddInitializersToSkip(ModelBuilder& model_builder, const Node& node) const override; private: - [[nodiscard]] Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, - const logging::Logger& logger) const override; + Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, + const logging::Logger& logger) const override; #endif // Operator support related @@ -75,7 +77,7 @@ Status AddPReluWeight(ModelBuilder& model_builder, const Node& node, auto& weight_values = *prelu.mutable_alpha()->mutable_floatvalue(); weight_values.Clear(); - weight_values.Resize(num_channels, value); + weight_values.Resize(narrow(num_channels), value); } return Status::OK(); } @@ -135,6 +137,12 @@ bool IsPReluOpSupported(const Node& node, const OpBuilderInputParams& input_para return false; } + // ensure that the third from last dimension is not dynamic + if (x_shape[x_rank - 3] == -1) { + LOGS(logger, VERBOSE) << "PRelu 'X' input must have a known third from last dimension."; + return false; + } + // slope input must be a constant initializer if (!input_params.graph_viewer.IsConstantInitializer(input_defs[1]->Name(), true)) { LOGS(logger, VERBOSE) << "PRelu 'slope' input must be a constant initializer tensor"; @@ -146,7 +154,7 @@ bool IsPReluOpSupported(const Node& node, const OpBuilderInputParams& input_para // - have 1 element { std::vector slope_shape; - if (!GetShape(*input_defs[1], slope_shape, logger)) { + if (!GetStaticShape(*input_defs[1], slope_shape, logger)) { return false; } const bool has_per_channel_slopes = 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 6eb1bf1da0579..7a5d4a5af673b 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/argmax_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/argmax_op_builder.cc @@ -16,8 +16,8 @@ class ArgMaxOpBuilder : public BaseOpBuilder { // Add operator related private: #ifdef __APPLE__ - [[nodiscard]] Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, - const logging::Logger& logger) const override; + Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, + const logging::Logger& logger) const override; #endif // Operator support related 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 cc883a70dcf10..25d5bad14ceb6 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/base_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/base_op_builder.cc @@ -1,15 +1,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include +#include "core/providers/coreml/builders/impl/base_op_builder.h" -#ifdef __APPLE__ -#include "core/providers/coreml/builders/model_builder.h" -#endif +#include "core/providers/common.h" #include "core/providers/coreml/builders/helper.h" #include "core/providers/shared/utils/utils.h" -#include "base_op_builder.h" +#ifdef __APPLE__ +#include "core/providers/coreml/builders/model_builder.h" +#endif namespace onnxruntime { namespace coreml { @@ -41,8 +41,8 @@ bool HasExternalInitializer(const InitializedTensorSet& initializers, const Node // Add operator related #ifdef __APPLE__ Status BaseOpBuilder::AddToModelBuilder(ModelBuilder& model_builder, const Node& node, + const OpBuilderInputParams& input_params, const logging::Logger& logger) const { - OpBuilderInputParams input_params(model_builder.GetGraphViewer()); ORT_RETURN_IF_NOT( IsOpSupported(node, input_params, logger), "Unsupported operator ", @@ -77,7 +77,7 @@ BaseOpBuilder::CreateNNLayer(const std::string& layer_name) { bool BaseOpBuilder::IsOpSupported(const Node& node, const OpBuilderInputParams& input_params, const logging::Logger& logger) const { - if (!HasSupportedInputs(node, logger)) + if (!HasSupportedInputs(node, input_params, logger)) return false; // We do not support external initializers for now @@ -91,10 +91,11 @@ bool BaseOpBuilder::IsOpSupported(const Node& node, const OpBuilderInputParams& return IsOpSupportedImpl(node, input_params, logger); } -bool BaseOpBuilder::HasSupportedInputs(const Node& node, const logging::Logger& logger) const { +bool BaseOpBuilder::HasSupportedInputs(const Node& node, const OpBuilderInputParams& input_params, + const logging::Logger& logger) const { const auto node_name = MakeString("Node [", node.Name(), "] type [", node.OpType(), "]"); for (const auto* input : node.InputDefs()) { - if (!IsInputSupported(*input, node_name, logger)) { + if (!IsInputSupported(*input, node_name, input_params, logger)) { return false; } } @@ -111,13 +112,6 @@ bool BaseOpBuilder::HasSupportedInputsImpl(const Node& node, const logging::Logg if (!GetType(input, input_type, logger)) return false; - if (node.OpType() == "Cast" && input_type == ONNX_NAMESPACE::TensorProto_DataType_INT64) { - LOGS(logger, VERBOSE) << "[" << node.OpType() - << "] Input type: [" << input_type - << "] is not actually supported (used for supporting argmax op)."; - return true; - } - if (input_type != ONNX_NAMESPACE::TensorProto_DataType_FLOAT) { LOGS(logger, VERBOSE) << "[" << node.OpType() << "] Input type: [" << input_type diff --git a/onnxruntime/core/providers/coreml/builders/impl/base_op_builder.h b/onnxruntime/core/providers/coreml/builders/impl/base_op_builder.h index c3f8d5b983ecb..b142db86a7902 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/base_op_builder.h +++ b/onnxruntime/core/providers/coreml/builders/impl/base_op_builder.h @@ -5,6 +5,10 @@ #include "core/providers/coreml/builders/op_builder.h" +#ifdef __APPLE__ +#include "core/providers/coreml/builders/coreml_spec.h" +#endif + namespace onnxruntime { namespace coreml { @@ -19,12 +23,13 @@ class BaseOpBuilder : public IOpBuilder { #ifdef __APPLE__ public: virtual void AddInitializersToSkip(ModelBuilder& /* model_builder */, const Node& /* node */) const override {} - [[nodiscard]] Status AddToModelBuilder(ModelBuilder& model_builder, const Node& node, - const logging::Logger& logger) const override final; + Status AddToModelBuilder(ModelBuilder& model_builder, const Node& node, + const OpBuilderInputParams& input_params, + const logging::Logger& logger) const override final; protected: - [[nodiscard]] virtual Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, - const logging::Logger& logger) const = 0; + virtual Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, + const logging::Logger& logger) const = 0; static std::unique_ptr CreateNNLayer(ModelBuilder& model_builder, const Node& node); @@ -35,7 +40,7 @@ class BaseOpBuilder : public IOpBuilder { // Operator support related public: bool IsOpSupported(const Node& node, const OpBuilderInputParams& input_params, - const logging::Logger& logger) const override; + const logging::Logger& logger) const override final; protected: virtual bool IsOpSupportedImpl(const Node& /* node */, const OpBuilderInputParams& /* input_params */, @@ -50,7 +55,8 @@ class BaseOpBuilder : public IOpBuilder { private: bool HasSupportedOpSet(const Node& node, const logging::Logger& logger) const; - bool HasSupportedInputs(const Node& node, const logging::Logger& logger) const; + bool HasSupportedInputs(const Node& node, const OpBuilderInputParams& input_params, + const logging::Logger& logger) const; }; } // namespace coreml 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 8a7dcc217bfd3..391b02eaec497 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 @@ -2,15 +2,16 @@ // Licensed under the MIT License. #include "core/providers/common.h" -#include "core/providers/shared/utils/utils.h" #include "core/providers/coreml/builders/helper.h" +#include "core/providers/coreml/builders/impl/base_op_builder.h" +#include "core/providers/coreml/builders/impl/builder_utils.h" +#include "core/providers/coreml/builders/op_builder_factory.h" +#include "core/providers/coreml/shape_utils.h" +#include "core/providers/shared/utils/utils.h" + #ifdef __APPLE__ #include "core/providers/coreml/builders/model_builder.h" #endif -#include "core/providers/coreml/builders/op_builder_factory.h" - -#include "base_op_builder.h" -#include "builder_utils.h" namespace onnxruntime { namespace coreml { @@ -22,8 +23,8 @@ class BatchNormalizationOpBuilder : public BaseOpBuilder { void AddInitializersToSkip(ModelBuilder& model_builder, const Node& node) const override; private: - [[nodiscard]] Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, - const logging::Logger& logger) const override; + Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, + const logging::Logger& logger) const override; #endif // Operator support related 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 3ec82d4a9b091..10c9b32d03f37 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/binary_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/binary_op_builder.cc @@ -6,6 +6,7 @@ #include "core/providers/coreml/builders/op_builder_factory.h" #include "core/providers/shared/utils/utils.h" #ifdef __APPLE__ +#include "core/framework/tensorprotoutils.h" #include "core/providers/coreml/builders/model_builder.h" #endif @@ -18,8 +19,8 @@ class BinaryOpBuilder : public BaseOpBuilder { // Add operator related private: #ifdef __APPLE__ - [[nodiscard]] Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, - const logging::Logger& logger) const override; + Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, + const logging::Logger& logger) const override; #endif // Operator support related int GetMinSupportedOpSet(const Node& node) const override; @@ -30,15 +31,31 @@ class BinaryOpBuilder : public BaseOpBuilder { #ifdef __APPLE__ static bool CheckIfBothInputShapesMatch(const Node& node, const logging::Logger& logger) { const auto& input_defs = node.InputDefs(); - std::vector input_shape1; - if (!GetShape(*input_defs[0], input_shape1, logger)) - return false; - std::vector input_shape2; - if (!GetShape(*input_defs[1], input_shape2, logger)) + const auto* x_shape_proto = input_defs[0]->Shape(); + const auto* y_shape_proto = input_defs[1]->Shape(); + + if (!x_shape_proto || !y_shape_proto) { + LOGS(logger, WARNING) << "[" << node.Name() << "] Input shape is missing"; return false; + } - return input_shape1 == input_shape2; + using Dimension = ONNX_NAMESPACE::TensorShapeProto::Dimension; + auto dim_eq = + [](const Dimension& x_dim, const Dimension& y_dim) { + const bool x_has_dim_value = utils::HasDimValue(x_dim); + if (x_has_dim_value != utils::HasDimValue(y_dim)) { + return false; + } + if (x_has_dim_value) { + return x_dim.dim_value() == y_dim.dim_value(); + } + return x_dim.dim_param() == y_dim.dim_param(); + }; + + return std::equal(x_shape_proto->dim().begin(), x_shape_proto->dim().end(), + y_shape_proto->dim().begin(), y_shape_proto->dim().end(), + dim_eq); } // Add operator related diff --git a/onnxruntime/core/providers/coreml/builders/impl/builder_utils.cc b/onnxruntime/core/providers/coreml/builders/impl/builder_utils.cc index d14c6ff041596..3b7bd5c1840cc 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/builder_utils.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/builder_utils.cc @@ -5,7 +5,7 @@ #include "core/providers/coreml/builders/impl/builder_utils.h" -#include "core/common/safeint.h" +#include "core/common/narrow.h" #include "core/framework/tensorprotoutils.h" #include "core/providers/coreml/builders/helper.h" #include "core/providers/shared/utils/utils.h" @@ -16,14 +16,14 @@ namespace onnxruntime { namespace coreml { -common::Status ComputeConvPads(const std::vector input_shape, - const int64_t weight_size_y, - const int64_t weight_size_x, - const std::vector& onnx_pads, - const std::vector& onnx_strides, - const std::vector& onnx_dilations, - AutoPadType auto_pad_type, - std::vector& pads_out) { +Status ComputeConvPads(const std::vector input_shape, + const int64_t weight_size_y, + const int64_t weight_size_x, + const std::vector& onnx_pads, + const std::vector& onnx_strides, + const std::vector& onnx_dilations, + AutoPadType auto_pad_type, + std::vector& pads_out) { const int64_t input_size_y = input_shape[2]; const int64_t input_size_x = input_shape[3]; const int64_t stride_y = onnx_strides[0]; @@ -50,16 +50,18 @@ common::Status ComputeConvPads(const std::vector input_shape, return Status::OK(); } -common::Status HandleAutoPad(const std::vector input_shape, - const int64_t weight_size_y, - const int64_t weight_size_x, - const std::vector& onnx_pads, - const std::vector& onnx_strides, - const std::vector& onnx_dilations, - AutoPadType auto_pad_type, - AutoPadType& auto_pad_type_out) { +Status HandleAutoPad(const std::vector input_shape, + const int64_t weight_size_y, + const int64_t weight_size_x, + const std::vector& onnx_pads, + const std::vector& onnx_strides, + const std::vector& onnx_dilations, + AutoPadType auto_pad_type, + AutoPadType& auto_pad_type_out) { auto_pad_type_out = auto_pad_type; - if (auto_pad_type == AutoPadType::NOTSET && onnx_dilations == std::vector{1, 1}) { + if (auto_pad_type == AutoPadType::NOTSET && onnx_dilations == std::vector{1, 1} && + // ComputeConvPads() only handles known dimensions of input_shape[2] and input_shape[3] + input_shape[2] != -1 && input_shape[3] != -1) { { std::vector same_upper_pads; ORT_RETURN_IF_ERROR(ComputeConvPads(input_shape, weight_size_y, weight_size_x, @@ -86,26 +88,49 @@ common::Status HandleAutoPad(const std::vector input_shape, return Status::OK(); } -void CreateCoreMLWeight(CoreML::Specification::WeightParams& weight, - const float* data, size_t num_elements) { - *weight.mutable_floatvalue() = {data, data + num_elements}; +Status CreateCoreMLWeight(CoreML::Specification::WeightParams& weight, + const ONNX_NAMESPACE::TensorProto& tensor) { + const auto data_type = tensor.data_type(); + Initializer unpacked_tensor(tensor); + switch (data_type) { + case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: + CreateCoreMLWeight(weight, unpacked_tensor.DataAsSpan()); + break; + case ONNX_NAMESPACE::TensorProto_DataType_INT32: + CreateCoreMLWeight(weight, unpacked_tensor.DataAsSpan()); + break; + case ONNX_NAMESPACE::TensorProto_DataType_INT64: + CreateCoreMLWeight(weight, unpacked_tensor.DataAsSpan()); + break; + default: + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "The initializer of graph has unsupported type, name: ", + tensor.name(), " type: ", data_type); + } + return Status::OK(); } -common::Status CreateCoreMLWeight(CoreML::Specification::WeightParams& weight, - const ONNX_NAMESPACE::TensorProto& tensor) { - auto data_type = tensor.data_type(); - if (data_type == ONNX_NAMESPACE::TensorProto_DataType_FLOAT) { - Initializer unpacked_tensor(tensor); - auto num_elements = SafeInt(Product(tensor.dims())); - CreateCoreMLWeight(weight, unpacked_tensor.data(), num_elements); - } 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); - } +void CreateCoreMLWeight(CoreML::Specification::WeightParams& weight, gsl::span data) { + weight.mutable_floatvalue()->Assign(data.begin(), data.end()); +} + +namespace { +template +void CreateCoreMLWeightConvertingDataToFloats(CoreML::Specification::WeightParams& weight, gsl::span data) { + google::protobuf::RepeatedField weight_floats{}; + weight_floats.Reserve(narrow(data.size())); + std::transform(data.begin(), data.end(), google::protobuf::RepeatedFieldBackInserter(&weight_floats), + [](T v) { return narrow(v); }); + *weight.mutable_floatvalue() = std::move(weight_floats); +} +} // namespace + +void CreateCoreMLWeight(CoreML::Specification::WeightParams& weight, gsl::span data) { + CreateCoreMLWeightConvertingDataToFloats(weight, data); +} - return common::Status::OK(); +void CreateCoreMLWeight(CoreML::Specification::WeightParams& weight, gsl::span data) { + CreateCoreMLWeightConvertingDataToFloats(weight, data); } } // namespace coreml diff --git a/onnxruntime/core/providers/coreml/builders/impl/builder_utils.h b/onnxruntime/core/providers/coreml/builders/impl/builder_utils.h index a2caa7415b0af..23b11928f7dc2 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/builder_utils.h +++ b/onnxruntime/core/providers/coreml/builders/impl/builder_utils.h @@ -7,7 +7,7 @@ #ifdef __APPLE__ -#include +#include "core/common/gsl.h" #include "core/common/status.h" #include "core/graph/basic_types.h" #include "core/providers/common.h" @@ -23,22 +23,26 @@ namespace coreml { // Try to see if we can map explicit padding to auto padding for Conv/Pool // Since usually use auto padding is more efficient -[[nodiscard]] common::Status HandleAutoPad(const std::vector input_shape, - const int64_t weight_size_y, - const int64_t weight_size_x, - const std::vector& onnx_pads, - const std::vector& onnx_strides, - const std::vector& onnx_dilations, - AutoPadType auto_pad_type, - AutoPadType& auto_pad_type_out); +Status HandleAutoPad(const std::vector input_shape, + const int64_t weight_size_y, + const int64_t weight_size_x, + const std::vector& onnx_pads, + const std::vector& onnx_strides, + const std::vector& onnx_dilations, + AutoPadType auto_pad_type, + AutoPadType& auto_pad_type_out); // Copy an onnx initializer data to a coreml weight -common::Status CreateCoreMLWeight(CoreML::Specification::WeightParams& weight, - const ONNX_NAMESPACE::TensorProto& tensor); +Status CreateCoreMLWeight(CoreML::Specification::WeightParams& weight, const ONNX_NAMESPACE::TensorProto& tensor); // Copy the float array to a coreml weight -void CreateCoreMLWeight(CoreML::Specification::WeightParams& weight, - const float* data, size_t num_elements); +void CreateCoreMLWeight(CoreML::Specification::WeightParams& weight, gsl::span data); + +// Copy the int32_t array to a coreml weight +void CreateCoreMLWeight(CoreML::Specification::WeightParams& weight, gsl::span data); + +// Copy the int64_t array to a coreml weight +void CreateCoreMLWeight(CoreML::Specification::WeightParams& weight, gsl::span data); } // 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 4363b80ece826..15ee1f0fc7284 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/cast_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/cast_op_builder.cc @@ -17,12 +17,13 @@ class CastOpBuilder : public BaseOpBuilder { // Add operator related private: #ifdef __APPLE__ - [[nodiscard]] Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, - const logging::Logger& logger) const override; + Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, + const logging::Logger& logger) const override; #endif // Operator support related bool IsOpSupportedImpl(const Node& node, const OpBuilderInputParams& input_params, const logging::Logger& logger) const override; + bool HasSupportedInputsImpl(const Node& node, const logging::Logger& logger) const override; }; // Add operator related @@ -63,7 +64,7 @@ bool CastOpBuilder::IsOpSupportedImpl(const Node& node, const OpBuilderInputPara << "]"; return false; } - if (!IsNodeSupported(prec_node, input_params.graph_viewer, logger)) { + if (!IsNodeSupported(prec_node, input_params, logger)) { LOGS(logger, VERBOSE) << "Cast's producing node [" << prec_node.OpType() << "] is not a supported op."; @@ -83,6 +84,25 @@ bool CastOpBuilder::IsOpSupportedImpl(const Node& node, const OpBuilderInputPara return true; } +bool CastOpBuilder::HasSupportedInputsImpl(const Node& node, const logging::Logger& logger) const { + // We only check the type of input 0 + const auto& input = *node.InputDefs()[0]; + + int32_t input_type; + if (!GetType(input, input_type, logger)) + return false; + + // only support int64 coming from ArgMax (check for ArgMax is done in IsOpSupportedImpl()) + if (input_type != ONNX_NAMESPACE::TensorProto_DataType_INT64) { + LOGS(logger, VERBOSE) << "[" << node.OpType() + << "] Input type: [" << input_type + << "] is not supported."; + return false; + } + + return true; +} + void CreateCastOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations) { op_registrations.builders.push_back(std::make_unique()); op_registrations.op_builder_map.emplace(op_type, op_registrations.builders.back().get()); 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 07a8a236a94f9..3a3f89d24c7d8 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/clip_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/clip_op_builder.cc @@ -19,8 +19,8 @@ class ClipOpBuilder : public BaseOpBuilder { void AddInitializersToSkip(ModelBuilder& model_builder, const Node& node) const override; private: - [[nodiscard]] Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, - const logging::Logger& logger) const override; + Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, + const logging::Logger& logger) const override; #endif // Operator support related 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 cc298a4f20a94..b1e761024f5c9 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/concat_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/concat_op_builder.cc @@ -2,15 +2,16 @@ // Licensed under the MIT License. #include "core/providers/common.h" -#include "core/providers/shared/utils/utils.h" #include "core/providers/coreml/builders/helper.h" +#include "core/providers/coreml/builders/impl/base_op_builder.h" #include "core/providers/coreml/builders/op_builder_factory.h" +#include "core/providers/coreml/shape_utils.h" +#include "core/providers/shared/utils/utils.h" + #ifdef __APPLE__ #include "core/providers/coreml/builders/model_builder.h" #endif -#include "base_op_builder.h" - namespace onnxruntime { namespace coreml { @@ -18,8 +19,8 @@ class ConcatOpBuilder : public BaseOpBuilder { // Add operator related private: #ifdef __APPLE__ - [[nodiscard]] Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, - const logging::Logger& logger) const override; + Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, + const logging::Logger& logger) const override; #endif // Operator support related 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 757f69f4d97ef..ff9dcbd9f8874 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/conv_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/conv_op_builder.cc @@ -2,16 +2,17 @@ // Licensed under the MIT License. #include "core/providers/common.h" -#include "core/providers/shared/utils/utils.h" #include "core/providers/coreml/builders/helper.h" +#include "core/providers/coreml/builders/impl/base_op_builder.h" #include "core/providers/coreml/builders/op_builder_factory.h" +#include "core/providers/shared/utils/utils.h" + #ifdef __APPLE__ +#include "core/providers/coreml/builders/impl/builder_utils.h" #include "core/providers/coreml/builders/model_builder.h" -#include "builder_utils.h" +#include "core/providers/coreml/shape_utils.h" #endif -#include "base_op_builder.h" - namespace onnxruntime { namespace coreml { @@ -22,8 +23,8 @@ class ConvOpBuilder : public BaseOpBuilder { void AddInitializersToSkip(ModelBuilder& model_builder, const Node& node) const override; private: - [[nodiscard]] Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, - const logging::Logger& logger) const override; + Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, + const logging::Logger& logger) const override; #endif // Operator support related 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 6939107d23e93..a4ad1c31b5027 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/depthtospace_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/depthtospace_op_builder.cc @@ -1,16 +1,16 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include - -#include "core/providers/shared/utils/utils.h" +#include "core/common/safeint.h" #include "core/providers/coreml/builders/helper.h" +#include "core/providers/coreml/builders/impl/base_op_builder.h" +#include "core/providers/coreml/builders/op_builder_factory.h" +#include "core/providers/coreml/shape_utils.h" +#include "core/providers/shared/utils/utils.h" + #ifdef __APPLE__ #include "core/providers/coreml/builders/model_builder.h" #endif -#include "core/providers/coreml/builders/op_builder_factory.h" - -#include "base_op_builder.h" namespace onnxruntime { namespace coreml { @@ -19,8 +19,8 @@ class DepthToSpaceOpBuilder : public BaseOpBuilder { // Add operator related private: #ifdef __APPLE__ - [[nodiscard]] Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, - const logging::Logger& logger) const override; + Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, + const logging::Logger& logger) const override; #endif // Operator support related diff --git a/onnxruntime/core/providers/coreml/builders/impl/flatten_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/flatten_op_builder.cc index d15db37fdd2fd..b303fe7884cb1 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/flatten_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/flatten_op_builder.cc @@ -1,15 +1,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/providers/shared/utils/utils.h" #include "core/providers/coreml/builders/helper.h" +#include "core/providers/coreml/builders/impl/base_op_builder.h" +#include "core/providers/coreml/builders/op_builder_factory.h" +#include "core/providers/coreml/shape_utils.h" +#include "core/providers/shared/utils/utils.h" #ifdef __APPLE__ #include "core/providers/coreml/builders/model_builder.h" #endif -#include "core/providers/coreml/builders/op_builder_factory.h" - -#include "base_op_builder.h" namespace onnxruntime { namespace coreml { @@ -18,8 +18,8 @@ class FlattenOpBuilder : public BaseOpBuilder { // Add operator related #ifdef __APPLE__ private: - [[nodiscard]] Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, - const logging::Logger& logger) const override; + Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, + const logging::Logger& logger) const override; #endif // Operator support related @@ -41,7 +41,7 @@ Status FlattenOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, auto* coreml_flatten = layer->mutable_flattento2d(); NodeAttrHelper helper(node); - const int64_t axis = helper.Get("axis ", 1); + const int64_t axis = helper.Get("axis", 1); coreml_flatten->set_axis(axis); *layer->mutable_input()->Add() = node.InputDefs()[0]->Name(); diff --git a/onnxruntime/core/providers/coreml/builders/impl/gather_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/gather_op_builder.cc new file mode 100644 index 0000000000000..9c7ec306ca093 --- /dev/null +++ b/onnxruntime/core/providers/coreml/builders/impl/gather_op_builder.cc @@ -0,0 +1,103 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/providers/coreml/builders/impl/base_op_builder.h" + +#include "core/providers/coreml/builders/op_builder_factory.h" +#include "core/providers/coreml/shape_utils.h" +#include "core/providers/shared/utils/utils.h" + +#if defined(__APPLE__) +#include "core/providers/coreml/builders/model_builder.h" +#endif + +namespace onnxruntime::coreml { + +class GatherOpBuilder : public BaseOpBuilder { + // Add operator related +#ifdef __APPLE__ + private: + Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, + const logging::Logger& logger) const override; +#endif + + // Operator support related + private: + bool HasSupportedInputsImpl(const Node& node, const logging::Logger& logger) const override; + bool IsOpSupportedImpl(const Node& node, const OpBuilderInputParams& input_params, + const logging::Logger& logger) const override; +}; + +// Add operator related +#if defined(__APPLE__) +namespace { +int64_t GetAxisAttribute(const Node& node) { + NodeAttrHelper node_attr_helper{node}; + return node_attr_helper.Get("axis", int64_t{0}); +} +} // namespace + +Status GatherOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, + const logging::Logger& logger) const { + auto layer = CreateNNLayer(model_builder, node); + layer->mutable_gather()->set_axis(GetAxisAttribute(node)); + *layer->mutable_input()->Add() = node.InputDefs()[0]->Name(); // data + *layer->mutable_input()->Add() = node.InputDefs()[1]->Name(); // indices + *layer->mutable_output()->Add() = node.OutputDefs()[0]->Name(); // output + model_builder.AddLayer(std::move(layer)); + return Status::OK(); +} +#endif // defined(__APPLE__) + +// Operator support related +bool GatherOpBuilder::HasSupportedInputsImpl(const Node& node, const logging::Logger& logger) const { + int32_t input_type; + if (!GetType(*node.InputDefs()[0], input_type, logger)) + return false; + + 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 for now"; + return false; + } + + return true; +} + +bool GatherOpBuilder::IsOpSupportedImpl(const Node& node, const OpBuilderInputParams& /*input_params*/, + const logging::Logger& logger) const { + std::vector data_shape, indices_shape; + if (!GetShape(*node.InputDefs()[0], data_shape, logger)) { + LOGS(logger, VERBOSE) << "Failed to get 'data' shape"; + return false; + } + + if (!GetShape(*node.InputDefs()[1], indices_shape, logger)) { + LOGS(logger, VERBOSE) << "Failed to get 'indices' shape"; + return false; + } + + // Don't allow scalar 'indices' input. + // We convert scalar inputs to tensors with shape [1] before providing them to CoreML. + // This modification changes the shape of the Gather output. + if (indices_shape.empty()) { + LOGS(logger, VERBOSE) << "Gather does not support scalar 'indices'"; + return false; + } + + if (data_shape.size() + indices_shape.size() - 1 > 5) { + LOGS(logger, VERBOSE) << "Gather does not support output with rank greater than 5"; + return false; + } + + return true; +} + +void CreateGatherOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations) { + op_registrations.builders.push_back(std::make_unique()); + op_registrations.op_builder_map.emplace(op_type, op_registrations.builders.back().get()); +} + +} // namespace onnxruntime::coreml 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 4e3944d824d11..71b08db6d44d8 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/gemm_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/gemm_op_builder.cc @@ -1,21 +1,21 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include -#include +#include "core/common/safeint.h" +#include "core/framework/tensorprotoutils.h" +#include "core/optimizer/initializer.h" #include "core/providers/common.h" -#include "core/providers/shared/utils/utils.h" #include "core/providers/coreml/builders/helper.h" +#include "core/providers/coreml/builders/impl/base_op_builder.h" #include "core/providers/coreml/builders/op_builder_factory.h" -#include "core/optimizer/initializer.h" +#include "core/providers/coreml/shape_utils.h" +#include "core/providers/shared/utils/utils.h" #ifdef __APPLE__ +#include "core/providers/coreml/builders/impl/builder_utils.h" #include "core/providers/coreml/builders/model_builder.h" -#include "builder_utils.h" #endif -#include "base_op_builder.h" - namespace onnxruntime { namespace coreml { @@ -26,8 +26,8 @@ class GemmOpBuilder : public BaseOpBuilder { void AddInitializersToSkip(ModelBuilder& model_builder, const Node& node) const override; private: - [[nodiscard]] Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, - const logging::Logger& logger) const override; + Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, + const logging::Logger& logger) const override; #endif // Operator support related @@ -89,7 +89,7 @@ Status GemmOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const N // Add weight (b of MatMul) std::vector b_transposed; ORT_RETURN_IF_ERROR(GetTensorFloatDataTransposed(b_tensor, b_transposed)); - CreateCoreMLWeight(*coreml_inner_product->mutable_weights(), b_transposed.data(), b_transposed.size()); + CreateCoreMLWeight(*coreml_inner_product->mutable_weights(), b_transposed); } else { // Gemm NodeAttrHelper helper(node); const auto transB = helper.Get("transB", 0); @@ -98,7 +98,7 @@ Status GemmOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const N coreml_inner_product->set_outputchannels(b_shape[1]); std::vector b_transposed; ORT_RETURN_IF_ERROR(GetTensorFloatDataTransposed(b_tensor, b_transposed)); - CreateCoreMLWeight(*coreml_inner_product->mutable_weights(), b_transposed.data(), b_transposed.size()); + CreateCoreMLWeight(*coreml_inner_product->mutable_weights(), b_transposed); } else { coreml_inner_product->set_inputchannels(b_shape[1]); coreml_inner_product->set_outputchannels(b_shape[0]); @@ -146,6 +146,7 @@ bool GemmOpBuilder::IsOpSupportedImpl(const Node& node, const OpBuilderInputPara return false; } + // TODO is it ok if the shape is dynamic and empty? if (Product(a_shape) == 0) { LOGS(logger, VERBOSE) << "A must be non-empty"; return false; diff --git a/onnxruntime/core/providers/coreml/builders/impl/pad_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/pad_op_builder.cc index 6ecbdafe95464..ba12600e8bc40 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/pad_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/pad_op_builder.cc @@ -1,19 +1,19 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/providers/common.h" -#include "core/framework/tensorprotoutils.h" #include "core/framework/tensor_shape.h" +#include "core/framework/tensorprotoutils.h" +#include "core/optimizer/initializer.h" +#include "core/providers/common.h" #include "core/providers/coreml/builders/helper.h" +#include "core/providers/coreml/builders/impl/base_op_builder.h" +#include "core/providers/coreml/builders/op_builder_factory.h" +#include "core/providers/coreml/shape_utils.h" #include "core/providers/shared/utils/utils.h" -#include "core/optimizer/initializer.h" #ifdef __APPLE__ #include "core/providers/coreml/builders/model_builder.h" #endif -#include "core/providers/coreml/builders/op_builder_factory.h" - -#include "base_op_builder.h" namespace onnxruntime { namespace coreml { @@ -141,6 +141,7 @@ bool PadOpBuilder::IsOpSupportedImpl(const Node& node, const OpBuilderInputParam return false; } + // TODO is it ok if the shape is dynamic and empty? const TensorShape shape(input_shape); if (shape.Size() == 0) { LOGS(logger, VERBOSE) << "Cases that input data being empty due to a dimension with value of 0 is not supported"; @@ -180,7 +181,7 @@ bool PadOpBuilder::IsOpSupportedImpl(const Node& node, const OpBuilderInputParam Initializer unpacked_tensor(pads_initializer); auto pads_tensor_data = unpacked_tensor.DataAsSpan(); - for (int64_t i = 0; i < unpacked_tensor.size(); i++) { + for (size_t i = 0; i < unpacked_tensor.size(); i++) { if (pads_tensor_data[i] < 0) { LOGS(logger, VERBOSE) << "Negative pad value is not supported: pads[" << i << "] = " << pads_tensor_data[i]; 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 ce72a83cc828a..fd1c77c851e6f 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/pool_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/pool_op_builder.cc @@ -2,16 +2,17 @@ // Licensed under the MIT License. #include "core/providers/common.h" -#include "core/providers/shared/utils/utils.h" #include "core/providers/coreml/builders/helper.h" +#include "core/providers/coreml/builders/impl/base_op_builder.h" #include "core/providers/coreml/builders/op_builder_factory.h" +#include "core/providers/coreml/shape_utils.h" +#include "core/providers/shared/utils/utils.h" + #ifdef __APPLE__ +#include "core/providers/coreml/builders/impl/builder_utils.h" #include "core/providers/coreml/builders/model_builder.h" -#include "builder_utils.h" #endif -#include "base_op_builder.h" - namespace onnxruntime { namespace coreml { @@ -19,8 +20,8 @@ class PoolOpBuilder : public BaseOpBuilder { // Add operator related private: #ifdef __APPLE__ - [[nodiscard]] Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, - const logging::Logger& logger) const override; + Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, + const logging::Logger& logger) const override; #endif // Operator support related diff --git a/onnxruntime/core/providers/coreml/builders/impl/reduction_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/reduction_op_builder.cc new file mode 100644 index 0000000000000..6a2014e7952a2 --- /dev/null +++ b/onnxruntime/core/providers/coreml/builders/impl/reduction_op_builder.cc @@ -0,0 +1,127 @@ +// Copyright (c) Shukant Pal. +// Licensed under the MIT License. + +#include "core/providers/common.h" +#include "core/providers/shared/utils/utils.h" + +#ifdef __APPLE__ +#include "core/providers/coreml/builders/model_builder.h" +#endif +#include "core/providers/coreml/builders/helper.h" +#include "core/providers/coreml/builders/op_builder_factory.h" +#include "core/optimizer/initializer.h" + +#include "base_op_builder.h" + +namespace onnxruntime { +namespace coreml { + +class ReductionOpBuilder : public BaseOpBuilder { +#ifdef __APPLE__ + public: + void AddInitializersToSkip(ModelBuilder& model_builder, const Node& node) const override; + + private: + Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, + const logging::Logger& logger) const override; +#endif + private: + bool IsOpSupportedImpl(const Node& node, const OpBuilderInputParams& input_params, + const logging::Logger& logger) const override; +}; + +#ifdef __APPLE__ +namespace { +template +void AddReductionParams(T* params, const std::vector& axes, bool keepdims, bool noop_with_empty_axes) { + params->set_keepdims(keepdims); + + for (auto& axis : axes) + params->add_axes(axis); + + if (axes.size() == 0 && !noop_with_empty_axes) + params->set_reduceall(true); +} +} // namespace + +void ReductionOpBuilder::AddInitializersToSkip(ModelBuilder& model_builder, const Node& node) const { + const auto& input_defs(node.InputDefs()); + + // We have already embedded the axes into the CoreML layer. + // No need to copy them later to reduce memory consumption. + if (input_defs.size() > 1) + model_builder.AddInitializerToSkip(input_defs[1]->Name()); +} + +Status ReductionOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, + const logging::Logger& /* logger */) const { + const auto& op_type(node.OpType()); + const auto& input_defs(node.InputDefs()); + const auto& initializers(model_builder.GetInitializerTensors()); + + std::vector axes; + + NodeAttrHelper helper(node); + if (input_defs.size() > 1 && input_defs[1]->Exists()) { + auto& axes_tensor = *initializers.at(input_defs[1]->Name()); + Initializer axes_initializer(axes_tensor); + int64_t* data = axes_initializer.data(); + int64_t size = axes_initializer.size(); + + axes = std::vector(data, data + size); + } else if (helper.HasAttr("axes")) { + axes = helper.Get("axes", std::vector{}); + } + + const bool keepdims = helper.Get("keepdims", 1) != 0; + const bool noop_with_empty_axes = helper.Get("noop_with_empty_axes", 0) != 0; + + std::unique_ptr layer = CreateNNLayer(model_builder, node); + + if (op_type == "ReduceSum") { + AddReductionParams(layer->mutable_reducesum(), axes, keepdims, noop_with_empty_axes); + } else if (op_type == "ReduceMean") { + AddReductionParams(layer->mutable_reducemean(), axes, keepdims, noop_with_empty_axes); + } else { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "ReductionOpBuilder::AddToModelBuilderImpl, unknown op: ", op_type); + } + + *layer->mutable_input()->Add() = node.InputDefs()[0]->Name(); + *layer->mutable_output()->Add() = node.OutputDefs()[0]->Name(); + + model_builder.AddLayer(std::move(layer)); + return Status::OK(); +} +#endif + +bool ReductionOpBuilder::IsOpSupportedImpl(const Node& node, const OpBuilderInputParams& input_params, + const logging::Logger& logger) const { + const auto& input_defs = node.InputDefs(); + + if (input_defs.size() > 1 && input_defs[1]->Exists()) { + const auto& axes_name = input_defs[1]->Name(); + const auto& initializers = input_params.graph_viewer.GetAllInitializedTensors(); + if (!Contains(initializers, axes_name)) { + LOGS(logger, VERBOSE) << "Axes of reduction must be a constant initializer"; + return false; + } + + NodeAttrHelper helper(node); + + if (initializers.at(axes_name)->int64_data_size() == 0 && helper.Get("noop_with_empty_axes", 0) != 0) { + LOGS(logger, VERBOSE) << "CoreML doesn't support noop on empty axes for reduction layers" << std::endl; + return false; + } + } + + return true; +} + +void CreateReductionOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations) { + op_registrations.builders.push_back(std::make_unique()); + op_registrations.op_builder_map.emplace(op_type, op_registrations.builders.back().get()); +} + +} // namespace coreml +} // namespace onnxruntime \ No newline at end of file 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 4d5102bbb23c6..67aee73630cdb 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/reshape_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/reshape_op_builder.cc @@ -1,19 +1,19 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/providers/common.h" #include "core/framework/tensorprotoutils.h" -#include "core/providers/cpu/tensor/reshape_helper.h" #include "core/optimizer/initializer.h" - -#include "core/providers/shared/utils/utils.h" +#include "core/providers/common.h" #include "core/providers/coreml/builders/helper.h" +#include "core/providers/coreml/builders/impl/base_op_builder.h" +#include "core/providers/coreml/builders/op_builder_factory.h" +#include "core/providers/coreml/shape_utils.h" +#include "core/providers/cpu/tensor/reshape_helper.h" +#include "core/providers/shared/utils/utils.h" + #ifdef __APPLE__ #include "core/providers/coreml/builders/model_builder.h" #endif -#include "core/providers/coreml/builders/op_builder_factory.h" - -#include "base_op_builder.h" namespace onnxruntime { namespace coreml { @@ -25,8 +25,8 @@ class ReshapeOpBuilder : public BaseOpBuilder { void AddInitializersToSkip(ModelBuilder& model_builder, const Node& node) const override; private: - [[nodiscard]] Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, - const logging::Logger& logger) const override; + Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, + const logging::Logger& logger) const override; #endif // Operator support related @@ -60,7 +60,7 @@ Status ReshapeOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const auto size = target_shape_tensor.dims()[0]; TensorShapeVector target_shape{raw_target_shape, raw_target_shape + size}; std::vector input_shape; - ORT_RETURN_IF_NOT(GetShape(*input_defs[0], input_shape, logger), "Cannot get shape"); + ORT_RETURN_IF_NOT(GetStaticShape(*input_defs[0], input_shape, logger), "Cannot get shape"); ReshapeHelper helper(TensorShape(input_shape), target_shape); *layer->mutable_reshapestatic()->mutable_targetshape() = {target_shape.cbegin(), target_shape.cend()}; *layer->mutable_input()->Add() = input_defs[0]->Name(); @@ -76,24 +76,23 @@ Status ReshapeOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, bool ReshapeOpBuilder::IsOpSupportedImpl(const Node& node, const OpBuilderInputParams& input_params, const logging::Logger& logger) const { const auto& input_defs = node.InputDefs(); - const auto& perm_name = input_defs[1]->Name(); + const auto& new_shape_name = input_defs[1]->Name(); const auto& initializers = input_params.graph_viewer.GetAllInitializedTensors(); - if (!Contains(initializers, perm_name)) { + if (!Contains(initializers, new_shape_name)) { LOGS(logger, VERBOSE) << "New shape of reshape must be a constant initializer"; return false; } - const auto& perm_tensor = *initializers.at(perm_name); - Initializer unpacked_tensor(perm_tensor); - auto raw_perm = unpacked_tensor.DataAsSpan(); - const auto& perm_dims = perm_tensor.dims(); - if (perm_dims.empty() || perm_dims[0] == 0) { + const auto& new_shape_tensor = *initializers.at(new_shape_name); + Initializer unpacked_tensor(new_shape_tensor); + auto new_shape = unpacked_tensor.DataAsSpan(); + if (new_shape.empty()) { LOGS(logger, VERBOSE) << "New shape of reshape cannot be empty"; return false; } std::vector input_shape; - if (!GetShape(*input_defs[0], input_shape, logger)) + if (!GetStaticShape(*input_defs[0], input_shape, logger)) return false; if (input_shape.empty()) { @@ -101,15 +100,22 @@ bool ReshapeOpBuilder::IsOpSupportedImpl(const Node& node, const OpBuilderInputP return false; } + // CoreML reshape doesn't support new shape with more than 5 dimensions + if (new_shape.size() > 5) { + LOGS(logger, VERBOSE) << "Reshape does not support new shape with rank greater than 5. Input shape: " + << Shape2String(input_shape) << ", new shape: " << Shape2String(new_shape); + return false; + } + // CoreML reshape does not support 0 as dimension NodeAttrHelper helper(node); const bool allow_zero = helper.Get("allowzero ", 0) == 1; if (allow_zero) { - for (int64_t i = 0; i < perm_dims[0]; i++) { - if (raw_perm[i] == 0) { - LOGS_DEFAULT(VERBOSE) << "Reshape doesn't support 0 reshape dimension when allowzero is enabled"; - return false; - } + if (std::find(new_shape.begin(), new_shape.end(), int64_t{0}) != new_shape.end()) { + LOGS(logger, VERBOSE) << "Reshape does not support new shape with 0 as dimension when allowzero is enabled. " + "Input shape: " + << Shape2String(input_shape) << ", new shape: " << Shape2String(new_shape); + return false; } } 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 ace70dd383d07..5f963dc30dd8f 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/resize_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/resize_op_builder.cc @@ -3,19 +3,19 @@ #include -#include "core/providers/common.h" #include "core/framework/tensorprotoutils.h" +#include "core/optimizer/initializer.h" +#include "core/providers/common.h" #include "core/providers/coreml/builders/helper.h" +#include "core/providers/coreml/builders/impl/base_op_builder.h" +#include "core/providers/coreml/builders/op_builder_factory.h" +#include "core/providers/coreml/shape_utils.h" #include "core/providers/cpu/tensor/reshape_helper.h" #include "core/providers/shared/utils/utils.h" -#include "core/optimizer/initializer.h" #ifdef __APPLE__ #include "core/providers/coreml/builders/model_builder.h" #endif -#include "core/providers/coreml/builders/op_builder_factory.h" - -#include "base_op_builder.h" namespace onnxruntime { namespace coreml { @@ -27,8 +27,8 @@ class ResizeOpBuilder : public BaseOpBuilder { void AddInitializersToSkip(ModelBuilder& model_builder, const Node& node) const override; private: - [[nodiscard]] Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, - const logging::Logger& logger) const override; + Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, + const logging::Logger& logger) const override; #endif // Operator support related @@ -70,7 +70,7 @@ bool GetResizeOutputSizes(const InitializedTensorSet& initializers, return false; Initializer unpacked_tensor(sizes_tensor); auto sizes_data = unpacked_tensor.DataAsSpan(); - sizes = std::vector{sizes_data.begin(), sizes_data.end()}; + sizes = std::vector(sizes_data.begin(), sizes_data.end()); return true; } @@ -117,7 +117,7 @@ Status ResizeOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, coreml_upsample->add_scalingfactor(static_cast(scales[3])); } else { // we already checked number of inputs in IsOpSupportedImpl std::vector input_shape; - ORT_RETURN_IF_NOT(GetShape(*input_defs[0], input_shape, logger), "Error getting input shape"); + ORT_RETURN_IF_NOT(GetStaticShape(*input_defs[0], input_shape, logger), "Error getting input shape"); std::vector output_sizes; ORT_RETURN_IF_NOT(GetResizeOutputSizes(initializers, node, output_sizes, logger), "Error getting resize output_sizes"); @@ -245,10 +245,15 @@ bool ResizeOpBuilder::IsOpSupportedImpl(const Node& node, const OpBuilderInputPa if (!GetResizeOutputSizes(initializers, node, output_sizes, logger)) return false; + if (!IsStaticShape(input_shape)) { + LOGS(logger, VERBOSE) << "Input shape with dynamic dimensions is not supported."; + return false; + } + auto output_size_n = output_sizes[0]; auto output_size_c = output_sizes[1]; if (output_size_n != input_shape[0] || output_size_c != input_shape[1]) { - LOGS(logger, VERBOSE) << "Output sizes of N/C chanel should match the input sizes, " + LOGS(logger, VERBOSE) << "Output sizes of N/C channel should match the input sizes, " << "Resize of N/C channels are not supported" << ", input_size_n, " << input_shape[0] << ", output_size_n, " << output_size_n << ". input_size_c, " << input_shape[1] << ", output_size_c, " << output_size_c; diff --git a/onnxruntime/core/providers/coreml/builders/impl/shape_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/shape_op_builder.cc new file mode 100644 index 0000000000000..fd64153ffd283 --- /dev/null +++ b/onnxruntime/core/providers/coreml/builders/impl/shape_op_builder.cc @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/providers/coreml/builders/impl/base_op_builder.h" + +#include "core/providers/coreml/builders/op_builder_factory.h" +#include "core/providers/shared/utils/utils.h" // for NodeAttrHelper + +#if defined(__APPLE__) +#include "core/providers/coreml/builders/model_builder.h" +#endif + +namespace onnxruntime::coreml { + +class ShapeOpBuilder : public BaseOpBuilder { + // Add operator related +#ifdef __APPLE__ + private: + Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, + const logging::Logger& logger) const override; +#endif + + // Operator support related + private: + bool IsOpSupportedImpl(const Node& node, const OpBuilderInputParams& input_params, + const logging::Logger& logger) const override; +}; + +// Add operator related +#if defined(__APPLE__) +Status ShapeOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, + const logging::Logger& logger) const { + auto layer = CreateNNLayer(model_builder, node); + layer->mutable_getshape(); + *layer->mutable_input()->Add() = node.InputDefs()[0]->Name(); + *layer->mutable_output()->Add() = node.OutputDefs()[0]->Name(); + model_builder.AddLayer(std::move(layer)); + return Status::OK(); +} +#endif // defined(__APPLE__) + +// Operator support related +bool ShapeOpBuilder::IsOpSupportedImpl(const Node& node, const OpBuilderInputParams& /*input_params*/, + const logging::Logger& logger) const { + NodeAttrHelper node_attr_helper{node}; + if (node_attr_helper.Get("start", 0) != 0) { + LOGS(logger, VERBOSE) << "Shape does not support 'start' attribute with value other than 0"; + return false; + } + + if (node_attr_helper.HasAttr("end")) { + LOGS(logger, VERBOSE) << "Shape does not support 'end' attribute"; + return false; + } + + return true; +} + +void CreateShapeOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations) { + op_registrations.builders.push_back(std::make_unique()); + op_registrations.op_builder_map.emplace(op_type, op_registrations.builders.back().get()); +} + +} // namespace onnxruntime::coreml diff --git a/onnxruntime/core/providers/coreml/builders/impl/slice_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/slice_op_builder.cc new file mode 100644 index 0000000000000..2c250b3cc9f5a --- /dev/null +++ b/onnxruntime/core/providers/coreml/builders/impl/slice_op_builder.cc @@ -0,0 +1,227 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/providers/coreml/builders/impl/base_op_builder.h" + +#include "core/optimizer/initializer.h" +#include "core/providers/coreml/builders/helper.h" +#include "core/providers/coreml/builders/op_builder_factory.h" +#include "core/providers/coreml/shape_utils.h" +#include "core/providers/cpu/tensor/slice_helper.h" +#include "core/providers/shared/utils/utils.h" + +#if defined(__APPLE__) +#include "core/providers/coreml/builders/model_builder.h" +#endif + +namespace onnxruntime::coreml { + +class SliceOpBuilder : public BaseOpBuilder { + // Add operator related +#ifdef __APPLE__ + private: + void AddInitializersToSkip(ModelBuilder& model_builder, const Node& node) const override; + + Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, + const logging::Logger& logger) const override; +#endif + + // Operator support related + private: + int GetMinSupportedOpSet(const Node& /* node */) const override { + // Before Slice-10, some inputs were attributes instead. We don't support that for now. + return 10; + } + + bool HasSupportedInputsImpl(const Node& node, const logging::Logger& logger) const override; + bool IsOpSupportedImpl(const Node& node, const OpBuilderInputParams& builder_params, + const logging::Logger& logger) const override; +}; + +namespace { +Status PrepareSliceComputeMetadataFromConstantInitializers(const Node& slice_node, + const GraphViewer& graph_viewer, + SliceOp::PrepareForComputeMetadata& compute_metadata) { + // TODO largely copied from nnapi::SliceOpBuilder::AddToModelBuilderImpl. put it somewhere where it can be reused? + + const auto input_defs = slice_node.InputDefs(); + + // We need to copy the data from the starts/ends/axes/steps initializers to int64 vectors + // to be used in shared PrepareForCompute function to calculate the output shape + // and normalize inputs, for example, input can be starts/ends/steps for certain axes, + // PrepareForCompute can generate standard starts/ends/steps/axes for each axes + TensorShapeVector input_starts; + TensorShapeVector input_ends; + TensorShapeVector input_axes; + TensorShapeVector input_steps; + + const auto CopyInputData = [&input_defs, &graph_viewer](size_t input_idx, TensorShapeVector& data) { + // This is an optional input, return empty vector + if (input_idx >= input_defs.size() || !input_defs[input_idx]->Exists()) { + data = {}; + return Status::OK(); + } + + const auto* tensor_proto = graph_viewer.GetConstantInitializer(input_defs[input_idx]->Name(), true); + ORT_RETURN_IF_NOT(tensor_proto, "Failed to get constant initializer."); + Initializer unpacked_tensor(*tensor_proto, graph_viewer.ModelPath()); + const auto data_type = unpacked_tensor.data_type(); + if (data_type == ONNX_NAMESPACE::TensorProto_DataType_INT64) { + auto tensor_data = unpacked_tensor.DataAsSpan(); + data.insert(data.end(), tensor_data.begin(), tensor_data.end()); + } else if (data_type == ONNX_NAMESPACE::TensorProto_DataType_INT32) { + auto tensor_data = unpacked_tensor.DataAsSpan(); + data.insert(data.end(), tensor_data.begin(), tensor_data.end()); + } else { + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, + "Data type for starts and ends inputs' is not supported in this build. Got ", + data_type); + } + + return Status::OK(); + }; + + ORT_RETURN_IF_ERROR(CopyInputData(1, input_starts)); + ORT_RETURN_IF_ERROR(CopyInputData(2, input_ends)); + ORT_RETURN_IF_ERROR(CopyInputData(3, input_axes)); + ORT_RETURN_IF_ERROR(CopyInputData(4, input_steps)); + ORT_RETURN_IF_ERROR( + SliceOp::PrepareForComputeHelper(input_starts, input_ends, input_axes, input_steps, compute_metadata)); + + return Status::OK(); +} + +// check things that CoreML is more particular about to avoid CoreML model compilation errors +bool ValidateSliceComputeMetadataForCoreML(const SliceOp::PrepareForComputeMetadata& compute_metadata, + const logging::Logger& logger) { + for (size_t i = 0; i < compute_metadata.starts_.size(); ++i) { + const auto step = compute_metadata.steps_[i], + start = compute_metadata.starts_[i], + end = compute_metadata.ends_[i]; + if ((step > 0 && start >= end) || (step < 0 && start <= end)) { + LOGS(logger, VERBOSE) << "Empty range is not supported: [" << start << ", " << end << ") with step " << step; + return false; + } + } + return true; +} +} // namespace + +// Add operator related +#if defined(__APPLE__) + +void SliceOpBuilder::AddInitializersToSkip(ModelBuilder& model_builder, const Node& node) const { + const auto& input_defs = node.InputDefs(); + + model_builder.AddInitializerToSkip(input_defs[1]->Name()); + model_builder.AddInitializerToSkip(input_defs[2]->Name()); + if (input_defs.size() > 3 && input_defs[3]->Exists()) { + model_builder.AddInitializerToSkip(input_defs[3]->Name()); + } + if (input_defs.size() > 4 && input_defs[4]->Exists()) { + model_builder.AddInitializerToSkip(input_defs[4]->Name()); + } +} + +Status SliceOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, + const logging::Logger& logger) const { + std::vector data_shape; + ORT_RETURN_IF_NOT(GetStaticShape(*node.InputDefs()[0], data_shape, logger), "Failed to get input shape."); + + SliceOp::PrepareForComputeMetadata compute_metadata{data_shape}; + ORT_RETURN_IF_ERROR(PrepareSliceComputeMetadataFromConstantInitializers(node, model_builder.GetGraphViewer(), + compute_metadata)); + + auto layer = CreateNNLayer(model_builder, node); + *layer->mutable_input()->Add() = node.InputDefs()[0]->Name(); + *layer->mutable_output()->Add() = node.OutputDefs()[0]->Name(); + auto* slice_static = layer->mutable_slicestatic(); + + for (size_t i = 0; i < compute_metadata.starts_.size(); ++i) { + const auto step = compute_metadata.steps_[i], + start = compute_metadata.starts_[i], + end = compute_metadata.ends_[i]; + + slice_static->add_beginids(start); + slice_static->add_beginmasks(false); + + if (step < 0 && end == -1) { + // Special case - stepping backwards up to and including the first index in the dimension. + // In ONNX Slice, we use end <= -(rank + 1) to represent this. In CoreML, setting endids like that doesn't work, + // so use endmasks to specify the rest of the dimension instead. + slice_static->add_endids(-1); // ignored + slice_static->add_endmasks(true); + } else { + slice_static->add_endids(end); + slice_static->add_endmasks(false); + } + + slice_static->add_strides(step); + } + + model_builder.AddLayer(std::move(layer)); + return Status::OK(); +} + +#endif // defined(__APPLE__) + +// Operator support related +bool SliceOpBuilder::HasSupportedInputsImpl(const Node& node, const logging::Logger& logger) const { + int32_t input_type; + if (!GetType(*node.InputDefs()[0], input_type, logger)) + return false; + + 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 for now"; + return false; + } + + return true; +} + +bool SliceOpBuilder::IsOpSupportedImpl(const Node& node, const OpBuilderInputParams& builder_params, + const logging::Logger& logger) const { + const auto input_defs = node.InputDefs(); + + std::vector data_shape; + if (!GetStaticShape(*input_defs[0], data_shape, logger)) { + return false; + } + + if (!CheckIsConstantInitializer(*input_defs[1], builder_params.graph_viewer, logger, "'starts'")) { + return false; + } + + if (!CheckIsConstantInitializer(*input_defs[2], builder_params.graph_viewer, logger, "'ends'")) { + return false; + } + + if (input_defs.size() > 3 && input_defs[3]->Exists() && + !CheckIsConstantInitializer(*input_defs[3], builder_params.graph_viewer, logger, "'axes'")) { + return false; + } + + if (input_defs.size() > 4 && input_defs[4]->Exists() && + !CheckIsConstantInitializer(*input_defs[4], builder_params.graph_viewer, logger, "'steps'")) { + return false; + } + + SliceOp::PrepareForComputeMetadata compute_metadata{data_shape}; + ORT_THROW_IF_ERROR(PrepareSliceComputeMetadataFromConstantInitializers(node, builder_params.graph_viewer, + compute_metadata)); + if (!ValidateSliceComputeMetadataForCoreML(compute_metadata, logger)) { + return false; + } + + return true; +} + +void CreateSliceOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations) { + op_registrations.builders.push_back(std::make_unique()); + op_registrations.op_builder_map.emplace(op_type, op_registrations.builders.back().get()); +} + +} // namespace onnxruntime::coreml 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 d1f5878c26f9a..2e14c85ce69c1 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/squeeze_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/squeeze_op_builder.cc @@ -23,8 +23,8 @@ class SqueezeOpBuilder : public BaseOpBuilder { void AddInitializersToSkip(ModelBuilder& model_builder, const Node& node) const override; private: - [[nodiscard]] Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, - const logging::Logger& logger) const override; + Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, + const logging::Logger& logger) const override; #endif // Operator support related 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 5306d9f11d899..7d5018a19f74c 100644 --- a/onnxruntime/core/providers/coreml/builders/impl/transpose_op_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/impl/transpose_op_builder.cc @@ -1,14 +1,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/providers/shared/utils/utils.h" #include "core/providers/coreml/builders/helper.h" +#include "core/providers/coreml/builders/impl/base_op_builder.h" +#include "core/providers/coreml/builders/op_builder_factory.h" +#include "core/providers/coreml/shape_utils.h" +#include "core/providers/shared/utils/utils.h" + #ifdef __APPLE__ #include "core/providers/coreml/builders/model_builder.h" #endif -#include "core/providers/coreml/builders/op_builder_factory.h" - -#include "base_op_builder.h" namespace onnxruntime { namespace coreml { @@ -17,8 +18,8 @@ class TransposeOpBuilder : public BaseOpBuilder { // Add operator related #ifdef __APPLE__ private: - [[nodiscard]] Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, - const logging::Logger& logger) const override; + Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, + const logging::Logger& logger) const override; #endif }; diff --git a/onnxruntime/core/providers/coreml/builders/impl/unary_op_builder.cc b/onnxruntime/core/providers/coreml/builders/impl/unary_op_builder.cc new file mode 100644 index 0000000000000..660755b43c043 --- /dev/null +++ b/onnxruntime/core/providers/coreml/builders/impl/unary_op_builder.cc @@ -0,0 +1,58 @@ +// Copyright (c) Shukant Pal. +// Licensed under the MIT License. + +#include "core/providers/common.h" + +#ifdef __APPLE__ +#include "core/providers/coreml/builders/model_builder.h" +#endif +#include "core/providers/coreml/builders/helper.h" +#include "core/providers/coreml/builders/op_builder_factory.h" + +#include "base_op_builder.h" + +namespace onnxruntime { +namespace coreml { + +class UnaryOpBuilder : public BaseOpBuilder { + private: +#ifdef __APPLE__ + Status AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, + const logging::Logger& logger) const override; +#endif +}; + +#ifdef __APPLE__ +Status UnaryOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const Node& node, + const logging::Logger& /* logger */) const { + const auto& op_type(node.OpType()); + const auto& input_defs(node.InputDefs()); + + std::unique_ptr layer = CreateNNLayer(model_builder, node); + + if (op_type == "Sqrt") { + layer->mutable_unary()->set_type(COREML_SPEC::UnaryFunctionLayerParams::SQRT); + } else if (op_type == "Reciprocal") { + layer->mutable_unary()->set_type(COREML_SPEC::UnaryFunctionLayerParams::INVERSE); + } else { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "UnaryOpBuilder::AddToModelBuilderImpl, unknown op: ", op_type); + } + + *layer->mutable_input()->Add() = input_defs[0]->Name(); + *layer->mutable_output()->Add() = node.OutputDefs()[0]->Name(); + + model_builder.AddLayer(std::move(layer)); + return Status::OK(); +} +#endif + +// Operator support related + +void CreateUnaryOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations) { + op_registrations.builders.push_back(std::make_unique()); + op_registrations.op_builder_map.emplace(op_type, op_registrations.builders.back().get()); +} + +} // namespace coreml +} // namespace onnxruntime \ No newline at end of file diff --git a/onnxruntime/core/providers/coreml/builders/model_builder.cc b/onnxruntime/core/providers/coreml/builders/model_builder.cc index 6ca39ec301cdc..9c8b7bce507e4 100644 --- a/onnxruntime/core/providers/coreml/builders/model_builder.cc +++ b/onnxruntime/core/providers/coreml/builders/model_builder.cc @@ -9,9 +9,10 @@ #include "op_builder_factory.h" #include "core/providers/common.h" -#include "core/providers/coreml/model/model.h" -#include "core/providers/coreml/model/host_utils.h" #include "core/providers/coreml/builders/impl/builder_utils.h" +#include "core/providers/coreml/model/host_utils.h" +#include "core/providers/coreml/model/model.h" +#include "core/providers/coreml/shape_utils.h" namespace onnxruntime { namespace coreml { @@ -60,12 +61,7 @@ void ModelBuilder::PreprocessInitializers() { // find all initializers consumed. AddInitializersToSkip will potentially decrement the usage count. for (const auto* input : node.InputDefs()) { if (input->Exists() && Contains(initializers, input->Name())) { - auto entry = initializer_usage_.find(input->Name()); - if (entry == initializer_usage_.end()) { - initializer_usage_[input->Name()] = 1; - } else { - entry->second++; - } + initializer_usage_[input->Name()]++; } } if (const auto* op_builder = GetOpBuilder(node)) { @@ -128,40 +124,56 @@ Status ModelBuilder::RegisterModelInputOutput(const NodeArg& node_arg, bool is_i input_output.set_name(name); auto* multi_array = input_output.mutable_type()->mutable_multiarraytype(); + std::vector shape; + ORT_RETURN_IF_NOT(GetShape(node_arg, shape, logger_), + "Unable to get shape for ", input_output_type, ": ", name); + + if (shape.empty()) { + // If we have an empty shape, this is a scalar input, + // Since all the input output of CoreML EP is MultiArray, we will make the scalar input output as a {1} MultiArray + shape.push_back(1); - { // input_output shape - const auto* shape_proto = node_arg.Shape(); - ORT_RETURN_IF(shape_proto == nullptr, - "shape_proto cannot be null for ", input_output_type, ": ", name); - const auto& dims = shape_proto->dim(); - if (dims.empty()) { - // If we have an empty shape, this is a scalar input, - // Since all the input output of CoreML EP is MultiArray, we will make the scalar input output as a {1} MultiArray - shape.push_back(1); - - // we need to change the shapes of these scalar outputs back to {} when CoreML EP returns these values to ORT - if (!is_input) { - AddScalarOutput(name); + // we need to change the shapes of these scalar outputs back to {} when CoreML EP returns these values to ORT + if (!is_input) { + AddScalarOutput(name); + } + } + + if (IsStaticShape(shape)) { + *multi_array->mutable_shape() = {shape.cbegin(), shape.cend()}; + } else { + if (is_input) { + auto& multi_array_shape_range = *multi_array->mutable_shaperange(); + auto& multi_array_shape = *multi_array->mutable_shape(); + + for (const auto dim : shape) { + auto& multi_array_dim_size_range = *multi_array_shape_range.mutable_sizeranges()->Add(); + if (dim == -1) { + multi_array_dim_size_range.set_lowerbound(0); + multi_array_dim_size_range.set_upperbound(-1); // unbounded + + multi_array_shape.Add(1); // pick 1 as an arbitrary default dynamic dimension value + } else { + multi_array_dim_size_range.set_lowerbound(dim); + multi_array_dim_size_range.set_upperbound(dim); + + multi_array_shape.Add(dim); + } } } else { - shape.reserve(dims.size()); - for (const auto& dim : dims) { - ORT_RETURN_IF_NOT(dim.has_dim_value(), - "Dynamic shape is not supported yet, for ", input_output_type, ": ", name); - shape.push_back(dim.dim_value()); - } + // Leave dynamic output shapes unspecified. + // If we specify an output shape that doesn't match the actual output shape at runtime, CoreML returns a 5D shape + // padded with ones. } } - *multi_array->mutable_shape() = {shape.cbegin(), shape.cend()}; - int32_t data_type; { // type const auto* type_proto = node_arg.TypeAsProto(); if (!type_proto || !type_proto->tensor_type().has_elem_type()) { return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, - "The ", input_output_type, " of graph doesn't have elem_type: ", name); + "The ", input_output_type, " of graph doesn't have elem_type: ", name); } data_type = type_proto->tensor_type().elem_type(); @@ -173,10 +185,10 @@ Status ModelBuilder::RegisterModelInputOutput(const NodeArg& node_arg, bool is_i multi_array->set_datatype(COREML_SPEC::ArrayFeatureType::INT32); break; case ONNX_NAMESPACE::TensorProto_DataType_INT64: + // If we have an int64 input/output type, since COREML_SPEC:ArrayFeatureType does not support INT64 + // we assign it to be INT32 here + multi_array->set_datatype(COREML_SPEC::ArrayFeatureType::INT32); if (!is_input) { - // If we have an int64 output type, since COREML_SPEC:ArrayFeatureType does not support INT64 - // we assign it to be INT32 here - multi_array->set_datatype(COREML_SPEC::ArrayFeatureType::INT32); // Record the output names and we need to change them back to Int64 when CoreML EP returns these values to ORT AddInt64Output(name); } @@ -184,7 +196,7 @@ Status ModelBuilder::RegisterModelInputOutput(const NodeArg& node_arg, bool is_i default: { // TODO: support other type return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, - "The ", input_output_type, " of graph doesn't have valid type, name: ", name, + "The ", input_output_type, " of graph doesn't have valid type, name: ", name, " type: ", type_proto->tensor_type().elem_type()); } } @@ -204,11 +216,12 @@ Status ModelBuilder::RegisterModelInputs() { } Status ModelBuilder::AddOperations() { + const auto builder_params = MakeOpBuilderParams(graph_viewer_, coreml_flags_); const auto& node_indices = graph_viewer_.GetNodesInTopologicalOrder(); for (size_t i = 0; i < node_indices.size(); i++) { const auto* node(graph_viewer_.GetNode(node_indices[i])); if (const auto* op_builder = GetOpBuilder(*node)) { - ORT_RETURN_IF_ERROR(op_builder->AddToModelBuilder(*this, *node, logger_)); + ORT_RETURN_IF_ERROR(op_builder->AddToModelBuilder(*this, *node, builder_params, logger_)); } else { return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Node [", node->Name(), "], type [", node->OpType(), "] is not supported"); diff --git a/onnxruntime/core/providers/coreml/builders/model_builder.h b/onnxruntime/core/providers/coreml/builders/model_builder.h index 3dcbd27c13d85..af2d5437be8d1 100644 --- a/onnxruntime/core/providers/coreml/builders/model_builder.h +++ b/onnxruntime/core/providers/coreml/builders/model_builder.h @@ -3,10 +3,8 @@ #pragma once -#include -#include "coreml/Model.pb.h" - -namespace COREML_SPEC = CoreML::Specification; +#include "core/graph/graph_viewer.h" +#include "core/providers/coreml/builders/coreml_spec.h" namespace onnxruntime { namespace coreml { @@ -20,8 +18,8 @@ class ModelBuilder { ModelBuilder(const GraphViewer& graph_viewer, const logging::Logger& logger, uint32_t coreml_flags); ~ModelBuilder() = default; - [[nodiscard]] Status Compile(std::unique_ptr& model, const std::string& path); - [[nodiscard]] Status SaveCoreMLModel(const std::string& path); + Status Compile(std::unique_ptr& model, const std::string& path); + Status SaveCoreMLModel(const std::string& path); // Accessors for members const GraphViewer& GetGraphViewer() const { return graph_viewer_; } @@ -55,18 +53,18 @@ class ModelBuilder { std::unordered_set unique_names_; // Convert the onnx model to CoreML::Specification::Model - [[nodiscard]] Status Initialize(); + Status Initialize(); // If a CoreML operation will use initializers directly, we will add the initializers to the skip list void PreprocessInitializers(); // Copy and process all the initializers to CoreML model - [[nodiscard]] Status RegisterInitializers(); + Status RegisterInitializers(); - [[nodiscard]] Status AddOperations(); - [[nodiscard]] Status RegisterModelInputs(); - [[nodiscard]] Status RegisterModelOutputs(); - [[nodiscard]] Status RegisterModelInputOutput(const NodeArg& node_arg, bool is_input); + Status AddOperations(); + Status RegisterModelInputs(); + Status RegisterModelOutputs(); + Status RegisterModelInputOutput(const NodeArg& node_arg, bool is_input); // Record the onnx scalar output names void AddScalarOutput(const std::string& output_name); diff --git a/onnxruntime/core/providers/coreml/builders/op_builder.h b/onnxruntime/core/providers/coreml/builders/op_builder.h index ee6e3f5848957..79de6438c9700 100644 --- a/onnxruntime/core/providers/coreml/builders/op_builder.h +++ b/onnxruntime/core/providers/coreml/builders/op_builder.h @@ -11,10 +11,12 @@ namespace coreml { class ModelBuilder; struct OpBuilderInputParams { - OpBuilderInputParams(const GraphViewer& graph_viewer) - : graph_viewer(graph_viewer) {} + OpBuilderInputParams(const GraphViewer& graph_viewer, bool only_allow_static_input_shapes) + : graph_viewer(graph_viewer), + only_allow_static_input_shapes(only_allow_static_input_shapes) {} const GraphViewer& graph_viewer; + const bool only_allow_static_input_shapes; }; class IOpBuilder { @@ -29,8 +31,9 @@ class IOpBuilder { virtual void AddInitializersToSkip(ModelBuilder& model_builder, const Node& node) const = 0; // Add the operator to CoreML model - [[nodiscard]] virtual Status AddToModelBuilder(ModelBuilder& model_builder, const Node& node, - const logging::Logger& logger) const = 0; + virtual Status AddToModelBuilder(ModelBuilder& model_builder, const Node& node, + const OpBuilderInputParams& input_params, + const logging::Logger& logger) const = 0; #endif // Operator support related diff --git a/onnxruntime/core/providers/coreml/builders/op_builder_factory.cc b/onnxruntime/core/providers/coreml/builders/op_builder_factory.cc index 317d0116bdc15..c1b09cec8a30a 100644 --- a/onnxruntime/core/providers/coreml/builders/op_builder_factory.cc +++ b/onnxruntime/core/providers/coreml/builders/op_builder_factory.cc @@ -99,6 +99,29 @@ static OpBuilderRegistrations CreateOpBuilderRegistrations() { CreatePadOpBuilder("Pad", op_registrations); } + { // Unary + CreateUnaryOpBuilder("Sqrt", op_registrations); + CreateUnaryOpBuilder("Reciprocal", op_registrations); + } + + { // Reduction + // ReduceMean is used in layer normalization which seems to be problematic in Python tests. + CreateReductionOpBuilder("ReduceMean", op_registrations); + CreateReductionOpBuilder("ReduceSum", op_registrations); + } + + { // Shape + CreateShapeOpBuilder("Shape", op_registrations); + } + + { // Gather + CreateGatherOpBuilder("Gather", op_registrations); + } + + { // Slice + CreateSliceOpBuilder("Slice", op_registrations); + } + return op_registrations; } diff --git a/onnxruntime/core/providers/coreml/builders/op_builder_factory.h b/onnxruntime/core/providers/coreml/builders/op_builder_factory.h index c129a5c38febd..b2c8dc765d33d 100644 --- a/onnxruntime/core/providers/coreml/builders/op_builder_factory.h +++ b/onnxruntime/core/providers/coreml/builders/op_builder_factory.h @@ -16,25 +16,29 @@ struct OpBuilderRegistrations { // Get the lookup table with IOpBuilder delegates for different onnx operators const std::unordered_map& GetOpBuilders(); -void CreateBinaryOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); -void CreateTransposeOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); -void CreateConvOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); -void CreateBatchNormalizationOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); -void CreateReshapeOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); -void CreateResizeOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); -void CreateConcatOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); -void CreateClipOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); -void CreateDepthToSpaceOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); - void CreateActivationOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); -void CreatePoolOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); -void CreateGemmOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); -void CreateSqueezeOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); void CreateArgMaxOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); +void CreateBatchNormalizationOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); +void CreateBinaryOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); void CreateCastOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); +void CreateClipOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); +void CreateConcatOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); +void CreateConvOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); +void CreateDepthToSpaceOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); void CreateFlattenOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); +void CreateGatherOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); +void CreateGemmOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); void CreateLRNOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); void CreatePadOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); +void CreatePoolOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); +void CreateReductionOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); +void CreateReshapeOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); +void CreateResizeOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); +void CreateShapeOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); +void CreateSliceOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); +void CreateSqueezeOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); +void CreateTransposeOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); +void CreateUnaryOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations); } // namespace coreml } // namespace onnxruntime diff --git a/onnxruntime/core/providers/coreml/coreml_execution_provider.cc b/onnxruntime/core/providers/coreml/coreml_execution_provider.cc index cec6c51ce820e..c9973671ffa28 100644 --- a/onnxruntime/core/providers/coreml/coreml_execution_provider.cc +++ b/onnxruntime/core/providers/coreml/coreml_execution_provider.cc @@ -3,17 +3,20 @@ #include "core/providers/coreml/coreml_execution_provider.h" -#include "core/framework/allocatormgr.h" +#include + #include "core/framework/compute_capability.h" +#include "core/framework/tensorprotoutils.h" #include "core/graph/graph_viewer.h" +#include "core/providers/coreml/builders/helper.h" #include "core/providers/partitioning_utils.h" #include "core/session/onnxruntime_cxx_api.h" -#include "core/providers/coreml/builders/helper.h" #ifdef __APPLE__ #include "core/providers/coreml/builders/model_builder.h" #include "core/providers/coreml/model/host_utils.h" #include "core/providers/coreml/model/model.h" +#include "core/providers/coreml/shape_utils.h" #endif namespace onnxruntime { @@ -23,20 +26,6 @@ constexpr const char* COREML = "CoreML"; CoreMLExecutionProvider::CoreMLExecutionProvider(uint32_t coreml_flags) : IExecutionProvider{onnxruntime::kCoreMLExecutionProvider, true}, coreml_flags_(coreml_flags) { - AllocatorCreationInfo device_info( - [](int) { - return std::make_unique(OrtMemoryInfo(COREML, OrtAllocatorType::OrtDeviceAllocator)); - }); - - InsertAllocator(CreateAllocator(device_info)); - - AllocatorCreationInfo cpu_memory_info( - [](int) { - return std::make_unique( - OrtMemoryInfo(COREML, OrtAllocatorType::OrtDeviceAllocator, OrtDevice(), 0, OrtMemTypeCPUOutput)); - }); - - InsertAllocator(CreateAllocator(cpu_memory_info)); } CoreMLExecutionProvider::~CoreMLExecutionProvider() {} @@ -60,7 +49,8 @@ CoreMLExecutionProvider::GetCapability(const onnxruntime::GraphViewer& graph_vie return result; } - const auto supported_nodes = coreml::GetSupportedNodes(graph_viewer, logger); + const auto builder_params = coreml::MakeOpBuilderParams(graph_viewer, coreml_flags_); + const auto supported_nodes = coreml::GetSupportedNodes(graph_viewer, builder_params, logger); const auto gen_metadef_name = [&]() { HashValue model_hash; @@ -114,7 +104,7 @@ common::Status CoreMLExecutionProvider::Compile(const std::vectorName(); } - coreml_model->SetInputs(std::move(onnx_input_names)); + coreml_model->SetOnnxInputs(std::move(onnx_input_names)); } { @@ -123,7 +113,7 @@ common::Status CoreMLExecutionProvider::Compile(const std::vectorName(); } - coreml_model->SetOutputs(std::move(onnx_output_names)); + coreml_model->SetOnnxOutputs(std::move(onnx_output_names)); } coreml_models_.emplace(fused_node.Name(), std::move(coreml_model)); @@ -146,8 +136,8 @@ common::Status CoreMLExecutionProvider::Compile(const std::vector(state); - const auto& model_inputs = model->GetInputs(); - const auto& model_outputs = model->GetOutputs(); + const auto& model_inputs = model->GetOnnxInputs(); + const auto& model_outputs = model->GetOnnxOutputs(); ORT_RETURN_IF_NOT(model_inputs.size() <= num_inputs, "Inconsistent input sizes"); ORT_RETURN_IF_NOT(model_outputs.size() == num_outputs, "Inconsistent output sizes"); @@ -156,9 +146,28 @@ common::Status CoreMLExecutionProvider::Compile(const std::vectorTryGetInputOutputInfo(input_name); + if (input_info == nullptr) { + // The CoreML model may not have an actual input that corresponds to this one. + // E.g., when the input is an initializer that already got copied to the CoreML model. + // If there's no CoreML model input, we don't need to provide this input to CoreML. + continue; + } + auto input_tensor = ctx.GetInput(i); auto tensor_info = input_tensor.GetTensorTypeAndShapeInfo(); auto shape = tensor_info.GetShape(); + + // Disallow inputs with dynamic shape which actually have zero elements. + // CoreML doesn't consistently handle this well (e.g., there may be runtime errors). + { + const auto& inferred_shape = input_info->shape; + ORT_RETURN_IF(!coreml::IsStaticShape(inferred_shape) && coreml::DoesShapeSpecifyZeroElements(shape), + "Input (", input_name, ") has a dynamic shape (", coreml::Shape2String(inferred_shape), + ") but the runtime shape (", coreml::Shape2String(shape), + ") has zero elements. This is not supported by the CoreML EP."); + } + // If we have an empty shape, this is a scalar input, // Since all the input output of CoreML EP is MultiArray, we will make the scalar input as a {1} MultiArray if (shape.empty()) @@ -180,8 +189,30 @@ common::Status CoreMLExecutionProvider::Compile(const std::vector lock(model->GetMutex()); - std::unordered_map outputs; + std::unordered_map outputs; outputs.reserve(model_outputs.size()); + + coreml::GetOutputTensorMutableRawDataFn get_output_tensor_mutable_raw_data_fn = + [&ctx, &model_outputs]( + const std::string& name, + int32_t requested_onnx_tensor_element_type, + gsl::span static_shape) -> void* { + const auto model_output_it = std::find(model_outputs.begin(), model_outputs.end(), name); + ORT_ENFORCE(model_output_it != model_outputs.end(), "Failed to find CoreML model output name: ", name); + const auto output_idx = gsl::narrow_cast(std::distance(model_outputs.begin(), model_output_it)); + + auto output_tensor = ctx.GetOutput(output_idx, static_shape.data(), static_shape.size()); + + const auto type_and_shape_info = output_tensor.GetTensorTypeAndShapeInfo(); + const auto actual_element_type = type_and_shape_info.GetElementType(); + ORT_ENFORCE(utils::CApiElementTypeFromProtoType(requested_onnx_tensor_element_type) == actual_element_type, + "Requested and actual output tensor element types do not match. Requested: ", + utils::CApiElementTypeFromProtoType(requested_onnx_tensor_element_type), + ", actual: ", actual_element_type); + + return output_tensor.GetTensorMutableRawData(); + }; + for (size_t i = 0; i < model_outputs.size(); i++) { const auto& output_name = model_outputs[i]; const auto& output_info = model->GetInputOutputInfo(output_name); @@ -198,34 +229,10 @@ common::Status CoreMLExecutionProvider::Compile(const std::vectorIsInt64Output(output_name)) output_type = ONNX_NAMESPACE::TensorProto_DataType_INT64; - auto output_tensor = - ctx.GetOutput(i, output_shape.data(), output_shape.size()); - - void* output_buffer; - switch (output_type) { - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: - output_buffer = output_tensor.GetTensorMutableData(); - break; - case ONNX_NAMESPACE::TensorProto_DataType_INT32: - output_buffer = output_tensor.GetTensorMutableData(); - break; - case ONNX_NAMESPACE::TensorProto_DataType_INT64: - output_buffer = output_tensor.GetTensorMutableData(); - break; - default: - return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, - "Unsupported type: ", output_type, " for output: ", output_name); - break; - } - - outputs.emplace(output_name, - coreml::OnnxTensorData{ - coreml::OnnxTensorInfo{output_type, output_shape}, - output_buffer, - }); + outputs.emplace(output_name, coreml::OnnxTensorInfo{output_type, output_shape}); } - return model->Predict(inputs, outputs); + return model->Predict(inputs, outputs, get_output_tensor_mutable_raw_data_fn); } }; diff --git a/onnxruntime/core/providers/coreml/model/host_utils.h b/onnxruntime/core/providers/coreml/model/host_utils.h index 014e2147caa64..f7f45bce087bc 100644 --- a/onnxruntime/core/providers/coreml/model/host_utils.h +++ b/onnxruntime/core/providers/coreml/model/host_utils.h @@ -6,6 +6,8 @@ #pragma once +#include + #define API_AVAILABLE_OS_VERSIONS API_AVAILABLE(macos(10.15), ios(13)) // Base requireed OS to run CoreML Specification Version 4 (Core ML 3) diff --git a/onnxruntime/core/providers/coreml/model/host_utils.mm b/onnxruntime/core/providers/coreml/model/host_utils.mm index 2a5453ae5345d..4c394386cd37a 100644 --- a/onnxruntime/core/providers/coreml/model/host_utils.mm +++ b/onnxruntime/core/providers/coreml/model/host_utils.mm @@ -1,10 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#import +#include "core/providers/coreml/model/host_utils.h" -#include -#include "host_utils.h" +#import namespace onnxruntime { namespace coreml { diff --git a/onnxruntime/core/providers/coreml/model/model.h b/onnxruntime/core/providers/coreml/model/model.h index 3a1f032196b26..105b6a0333b15 100644 --- a/onnxruntime/core/providers/coreml/model/model.h +++ b/onnxruntime/core/providers/coreml/model/model.h @@ -3,6 +3,13 @@ #pragma once +#include +#include +#include + +#include "core/common/common.h" +#include "core/common/gsl.h" +#include "core/common/logging/logging.h" #include "core/common/status.h" #include "core/platform/ort_mutex.h" @@ -21,6 +28,10 @@ struct OnnxTensorData { void* buffer{nullptr}; }; +using GetOutputTensorMutableRawDataFn = std::function static_shape)>; + class Model { friend class ModelBuilder; @@ -28,8 +39,9 @@ class Model { ~Model(); ORT_DISALLOW_COPY_ASSIGNMENT_AND_MOVE(Model); - onnxruntime::common::Status Predict(const std::unordered_map& inputs, - const std::unordered_map& outputs); + Status Predict(const std::unordered_map& inputs, + const std::unordered_map& outputs, + const GetOutputTensorMutableRawDataFn& get_output_tensor_mutable_raw_data_fn); bool IsScalarOutput(const std::string& output_name) const; @@ -39,12 +51,13 @@ class Model { OrtMutex& GetMutex() { return mutex_; } // Input and output names in the onnx model's order - const std::vector& GetInputs() const { return inputs_; } - void SetInputs(std::vector&& inputs) { inputs_ = std::move(inputs); } + const std::vector& GetOnnxInputs() const { return onnx_inputs_; } + void SetOnnxInputs(std::vector&& inputs) { onnx_inputs_ = std::move(inputs); } - const std::vector& GetOutputs() const { return outputs_; } - void SetOutputs(std::vector&& outputs) { outputs_ = std::move(outputs); } + const std::vector& GetOnnxOutputs() const { return onnx_outputs_; } + void SetOnnxOutputs(std::vector&& outputs) { onnx_outputs_ = std::move(outputs); } + const OnnxTensorInfo* TryGetInputOutputInfo(const std::string& name) const; const OnnxTensorInfo& GetInputOutputInfo(const std::string& name) const; private: @@ -52,15 +65,15 @@ class Model { std::unordered_set scalar_outputs_; std::unordered_set int64_outputs_; - std::vector inputs_; - std::vector outputs_; + std::vector onnx_inputs_; + std::vector onnx_outputs_; std::unordered_map input_output_info_; OrtMutex mutex_; Model(const std::string& path, const logging::Logger& logger, uint32_t coreml_flags); - onnxruntime::common::Status LoadModel(); + Status LoadModel(); void SetInputOutputInfo(std::unordered_map&& input_output_info) { input_output_info_ = std::move(input_output_info); @@ -76,4 +89,4 @@ class Model { }; } // namespace coreml -} // namespace onnxruntime \ No newline at end of file +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/coreml/model/model.mm b/onnxruntime/core/providers/coreml/model/model.mm index cb2f70294c681..60e0b1c061a43 100644 --- a/onnxruntime/core/providers/coreml/model/model.mm +++ b/onnxruntime/core/providers/coreml/model/model.mm @@ -1,40 +1,177 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#include "core/providers/coreml/model/model.h" + +#import +#import + +#include #include #include #include #include "core/common/common.h" +#include "core/common/gsl.h" +#include "core/common/inlined_containers.h" #include "core/common/logging/logging.h" +#include "core/common/narrow.h" +#include "core/common/span_utils.h" #include "core/graph/onnx_protobuf.h" -#include "core/providers/common.h" #include "core/providers/coreml/builders/helper.h" #include "core/providers/coreml/coreml_provider_factory.h" -#include "host_utils.h" -#include "model.h" - -#import -#import +#include "core/providers/coreml/model/host_utils.h" +#include "core/providers/coreml/shape_utils.h" // force the linker to create a dependency on the CoreML framework so that in MAUI usage we don't need // to manually do this asm(".linker_option \"-framework\", \"CoreML\""); -// Model input for a CoreML model -// All the input onnx tensors values will be converted to MLMultiArray(s) -@interface OnnxTensorFeatureProvider : NSObject { - const std::unordered_map* inputs_; - NSSet* featureNames_; - const onnxruntime::logging::Logger* logger_; +using namespace onnxruntime; +using namespace onnxruntime::coreml; + +namespace { +/** + * Computes the static output shape used to allocate the output tensor. + * `inferred_shape` is the inferred shape known at model compile time. It may contain dynamic dimensions (-1). + * `coreml_static_shape` is the static output shape of the CoreML MLMultiArray output. It must NOT contain dynamic + * dimensions. + * Returns a static output shape which is `inferred_shape` with each of its dynamic dimensions replaced by the + * corresponding static dimension from `coreml_static_shape`. + */ +InlinedVector GetStaticOutputShape(gsl::span inferred_shape, + gsl::span coreml_static_shape, + const logging::Logger& logger) { + ORT_ENFORCE(IsStaticShape(coreml_static_shape), + "CoreML output shape (", Shape2String(coreml_static_shape), ") is not static."); + + // return early if the shapes match + if (std::equal(inferred_shape.begin(), inferred_shape.end(), + coreml_static_shape.begin(), coreml_static_shape.end())) { + return InlinedVector(inferred_shape.begin(), inferred_shape.end()); + } + + if (inferred_shape.empty() && SpanEq(coreml_static_shape, AsSpan({1}))) { + // Special case - inferred output shape is [] (scalar) and CoreML output shape is [1]. + // CoreML doesn't handle scalar multiarrays so we convert scalar inputs to shape [1] and do the reverse for scalar + // outputs. + return InlinedVector{}; + } + + ORT_ENFORCE(inferred_shape.size() == coreml_static_shape.size(), + "CoreML static output shape (", Shape2String(coreml_static_shape), + ") and inferred shape (", Shape2String(inferred_shape), ") have different ranks."); + + InlinedVector static_shape{}; + static_shape.reserve(inferred_shape.size()); + std::transform(inferred_shape.begin(), inferred_shape.end(), + coreml_static_shape.begin(), + std::back_inserter(static_shape), + [&](int64_t inferred_dim, int64_t coreml_static_dim) { + ORT_ENFORCE(inferred_dim == -1 || inferred_dim == coreml_static_dim, + "CoreML static output shape (", Shape2String(coreml_static_shape), + ") and inferred shape (", Shape2String(inferred_shape), + ") have an inconsistent static dimensions (", coreml_static_dim, " vs. ", + inferred_dim, ")."); + + return inferred_dim != -1 ? inferred_dim : coreml_static_dim; + }); + + return static_shape; } -- (instancetype)initWithInputs:(const std::unordered_map&)inputs - logger:(const onnxruntime::logging::Logger*)logger; -- (MLFeatureValue*)featureValueForName:(NSString*)featureName API_AVAILABLE_OS_VERSIONS; -- (NSSet*)featureNames; +Status CreateInputFeatureProvider(const std::unordered_map& inputs, + const logging::Logger& logger, + id __autoreleasing* _Nonnull feature_provider_out, + InlinedVector>& conversion_buffers_out) { + NSError* error = nil; + InlinedVector> conversion_buffers{}; + NSMutableDictionary* feature_dictionary = [NSMutableDictionary dictionaryWithCapacity:inputs.size()]; -@end + // create a MLMultiArray feature for each input + for (const auto& [name, onnx_tensor_data] : inputs) { + const auto& shape = onnx_tensor_data.tensor_info.shape; + + NSMutableArray* shape_array = [NSMutableArray arrayWithCapacity:shape.size()]; + for (const auto dim : shape) { + [shape_array addObject:[NSNumber numberWithLongLong:dim]]; + } + + NSMutableArray* strides_array = [NSMutableArray arrayWithCapacity:shape.size()]; + { + int64_t stride = 1; + for (size_t idx = 0; idx < shape.size(); ++idx) { + const size_t idx_from_end = shape.size() - 1 - idx; + [strides_array insertObject:[NSNumber numberWithLongLong:stride] + atIndex:0]; + + stride *= shape[idx_from_end]; + } + } + + MLMultiArrayDataType data_type; + void* data_pointer = onnx_tensor_data.buffer; + + switch (onnx_tensor_data.tensor_info.data_type) { + case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: { + data_type = MLMultiArrayDataTypeFloat32; + break; + } + case ONNX_NAMESPACE::TensorProto_DataType_INT32: { + data_type = MLMultiArrayDataTypeInt32; + break; + } + case ONNX_NAMESPACE::TensorProto_DataType_INT64: { + // CoreML doesn't support int64 input so convert to int32 input. + data_type = MLMultiArrayDataTypeInt32; + + // Convert the data and store it in a buffer. Add the buffer to `conversion_buffers`. + const auto num_elements = narrow(ShapeSize(shape)); + const auto input_span = gsl::span{static_cast(onnx_tensor_data.buffer), num_elements}; + auto conversion_buffer = std::make_unique(num_elements); + const auto conversion_span = gsl::span{conversion_buffer.get(), num_elements}; + std::transform(input_span.begin(), input_span.end(), conversion_span.begin(), + [](int64_t v) { return narrow(v); }); + + conversion_buffers.emplace_back(std::move(conversion_buffer)); + data_pointer = conversion_buffers.back().get(); + + break; + } + default: { + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Output data type is not supported, actual type: ", + onnx_tensor_data.tensor_info.data_type); + } + } + + MLMultiArray* multi_array = [[MLMultiArray alloc] initWithDataPointer:data_pointer + shape:shape_array + dataType:data_type + strides:strides_array + deallocator:^(void* /* bytes */) { + } + error:&error]; + ORT_RETURN_IF(error != nil, + "Failed to create MLMultiArray for feature: ", name, + ", error: ", [[error localizedDescription] UTF8String]); + + MLFeatureValue* feature_value = [MLFeatureValue featureValueWithMultiArray:multi_array]; + NSString* feature_name = [NSString stringWithUTF8String:name.c_str()]; + feature_dictionary[feature_name] = feature_value; + } + + auto* feature_provider = [[MLDictionaryFeatureProvider alloc] initWithDictionary:feature_dictionary + error:&error]; + ORT_RETURN_IF(error != nil, + "Failed to create MLDictionaryFeatureProvider, error: ", [[error localizedDescription] UTF8String]); + + *feature_provider_out = feature_provider; + conversion_buffers_out = std::move(conversion_buffers); + return Status::OK(); +} +} // namespace + +NS_ASSUME_NONNULL_BEGIN // Execution for a CoreML model, it performs // 1. Compile the model by given path for execution @@ -43,104 +180,30 @@ - (MLFeatureValue*)featureValueForName:(NSString*)featureName API_AVAILABLE_OS_V @interface CoreMLExecution : NSObject { NSString* coreml_model_path_; NSString* compiled_model_path_; - const onnxruntime::logging::Logger* logger_; + const logging::Logger* logger_; uint32_t coreml_flags_; } - (instancetype)initWithPath:(const std::string&)path - logger:(const onnxruntime::logging::Logger&)logger + logger:(const logging::Logger&)logger coreml_flags:(uint32_t)coreml_flags; - (void)cleanup; - (void)dealloc; -- (onnxruntime::common::Status)loadModel API_AVAILABLE_OS_VERSIONS; -- (onnxruntime::common::Status) - predict:(const std::unordered_map&)inputs - outputs:(const std::unordered_map&)outputs +- (Status)loadModel API_AVAILABLE_OS_VERSIONS; +- (Status)predict:(const std::unordered_map&)inputs + outputs:(const std::unordered_map&)outputs + getOutputTensorDataFn:(const GetOutputTensorMutableRawDataFn&) + get_output_tensor_mutable_raw_data_fn API_AVAILABLE_OS_VERSIONS; @property MLModel* model API_AVAILABLE_OS_VERSIONS; @end -@implementation OnnxTensorFeatureProvider - -- (instancetype)initWithInputs:(const std::unordered_map&)inputs - logger:(const onnxruntime::logging::Logger*)logger { - if (self = [super init]) { - inputs_ = &inputs; - logger_ = logger; - } - return self; -} - -- (nonnull NSSet*)featureNames { - if (featureNames_ == nil) { - NSMutableArray* names = [[NSMutableArray alloc] init]; - for (const auto& input : *inputs_) { - NSString* inputName = [NSString stringWithCString:input.first.c_str() - encoding:[NSString defaultCStringEncoding]]; - NSAssert(inputName != nil, @"inputName must not be nil"); - [names addObject:inputName]; - } - - featureNames_ = [NSSet setWithArray:names]; - } - - return featureNames_; -} - -- (nullable MLFeatureValue*)featureValueForName:(nonnull NSString*)featureName { - auto it = inputs_->find([featureName cStringUsingEncoding:NSUTF8StringEncoding]); - if (it != inputs_->end()) { - auto& input = it->second; - NSMutableArray* shape = [[NSMutableArray alloc] init]; - for (const auto dim : input.tensor_info.shape) { - [shape addObject:[NSNumber numberWithLongLong:dim]]; - } - - NSMutableArray* strides = [[NSMutableArray alloc] init]; - int64_t stride = 1; - for (int i = static_cast(input.tensor_info.shape.size()) - 1; i >= 0; i--) { - [strides insertObject:[NSNumber numberWithLongLong:stride] - atIndex:0]; - - stride *= input.tensor_info.shape[i]; - } - - MLMultiArrayDataType data_type = MLMultiArrayDataTypeFloat32; - if (input.tensor_info.data_type != ONNX_NAMESPACE::TensorProto_DataType_FLOAT) { - LOGS(*logger_, ERROR) << "Input data type is not float, actual type: " - << input.tensor_info.data_type; - return nil; - } - - NSError* error = nil; - MLMultiArray* mlArray = [[MLMultiArray alloc] initWithDataPointer:input.buffer - shape:shape - dataType:data_type - strides:strides - deallocator:(^(void* /* bytes */){ - })error:&error]; - if (error != nil) { - LOGS(*logger_, ERROR) << "Failed to create MLMultiArray for feature: " << [featureName UTF8String] - << ", error: " << [[error localizedDescription] UTF8String]; - return nil; - } - - NSAssert(mlArray != nil, @"mlArray must not be nil"); - auto* mlFeatureValue = [MLFeatureValue featureValueWithMultiArray:mlArray]; - return mlFeatureValue; - } - - return nil; -} - -@end - @implementation CoreMLExecution - (instancetype)initWithPath:(const std::string&)path - logger:(const onnxruntime::logging::Logger&)logger + logger:(const logging::Logger&)logger coreml_flags:(uint32_t)coreml_flags { if (self = [super init]) { coreml_model_path_ = [NSString stringWithUTF8String:path.c_str()]; @@ -176,7 +239,7 @@ - (void)dealloc { [self cleanup]; } -- (onnxruntime::common::Status)loadModel { +- (Status)loadModel { NSError* error = nil; NSURL* modelUrl = [NSURL URLWithString:coreml_model_path_]; NSAssert(modelUrl != nil, @"modelUrl must not be nil"); @@ -200,100 +263,118 @@ - (void)dealloc { [[error localizedDescription] cStringUsingEncoding:NSUTF8StringEncoding]); } - return onnxruntime::common::Status::OK(); + return Status::OK(); } -- (onnxruntime::common::Status) - predict:(const std::unordered_map&)inputs - outputs:(const std::unordered_map&)outputs { - if (_model == nil) { - return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "model is not loaded"); - } +- (Status)predict:(const std::unordered_map&)inputs + outputs:(const std::unordered_map&)outputs + getOutputTensorDataFn:(const GetOutputTensorMutableRawDataFn&)get_output_tensor_mutable_raw_data_fn { + Status status = Status::OK(); + ORT_TRY { + if (_model == nil) { + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "model is not loaded"); + } - OnnxTensorFeatureProvider* input_feature = [[OnnxTensorFeatureProvider alloc] initWithInputs:inputs - logger:logger_]; + id input_features; + InlinedVector> conversion_buffers; + ORT_RETURN_IF_ERROR(CreateInputFeatureProvider(inputs, *logger_, &input_features, conversion_buffers)); - if (input_feature == nil) { - return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "inputFeature is not initialized"); - } + MLPredictionOptions* options = [[MLPredictionOptions alloc] init]; + NSError* error = nil; + id output_features = [_model predictionFromFeatures:input_features + options:options + error:&error]; - MLPredictionOptions* options = [[MLPredictionOptions alloc] init]; - NSError* error = nil; - id output_feature = [_model predictionFromFeatures:input_feature - options:options - error:&error]; + if (error != nil) { + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Error executing model: ", + [[error localizedDescription] cStringUsingEncoding:NSUTF8StringEncoding]); + } - if (error != nil) { - return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Error executing model: ", - [[error localizedDescription] cStringUsingEncoding:NSUTF8StringEncoding]); - } + for (const auto& [output_name, output_tensor_info] : outputs) { + MLFeatureValue* output_value = + [output_features featureValueForName:[NSString stringWithUTF8String:output_name.c_str()]]; - for (auto& output : outputs) { - NSString* output_name = [NSString stringWithCString:output.first.c_str() - encoding:[NSString defaultCStringEncoding]]; - NSAssert(output_name != nil, @"output_name must not be nil"); - MLFeatureValue* output_value = - [output_feature featureValueForName:output_name]; + if (output_value == nil) { + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "output_features has no value for ", output_name); + } - if (output_value == nil) { - return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "output_feature has no value for ", - [output_name cStringUsingEncoding:NSUTF8StringEncoding]); - } + auto* data = [output_value multiArrayValue]; - auto* data = [output_value multiArrayValue]; - auto* model_output_data = data.dataPointer; - if (model_output_data == nullptr) { - return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "model_output_data has no data for ", - [output_name cStringUsingEncoding:NSUTF8StringEncoding]); - } + const auto coreml_static_output_shape = [&]() { + InlinedVector result; + result.reserve(data.shape.count); + for (NSNumber* dim in data.shape) { + const auto dim_value = dim.longLongValue; + result.push_back(dim_value); + } + return result; + }(); - auto model_output_type = data.dataType; + const auto static_output_shape = GetStaticOutputShape(output_tensor_info.shape, coreml_static_output_shape, + *logger_); - auto& output_tensor = output.second; - size_t num_elements = - accumulate(output_tensor.tensor_info.shape.begin(), - output_tensor.tensor_info.shape.end(), - 1, - std::multiplies()); + void* output_buffer = get_output_tensor_mutable_raw_data_fn(output_name, output_tensor_info.data_type, + static_output_shape); - const auto type = output_tensor.tensor_info.data_type; - switch (type) { - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: { - const auto output_data_byte_size = num_elements * sizeof(float); - memcpy(output_tensor.buffer, model_output_data, output_data_byte_size); - break; - } - case ONNX_NAMESPACE::TensorProto_DataType_INT32: { - const auto output_data_byte_size = num_elements * sizeof(int32_t); - memcpy(output_tensor.buffer, model_output_data, output_data_byte_size); - break; - } - // For this case, since Coreml Spec only uses int32 for model output while onnx provides - // int64 for model output data type. We are doing a type casting (int32 -> int64) here - // when copying the model to ORT - case ONNX_NAMESPACE::TensorProto_DataType_INT64: - if (model_output_type == MLMultiArrayDataTypeInt32) { - int32_t* model_output_data_prime = static_cast(model_output_data); - int64_t* output_tensor_buffer_prime = static_cast(output_tensor.buffer); - for (size_t i = 0; i < num_elements; i++) { - output_tensor_buffer_prime[i] = model_output_data_prime[i]; + if (const size_t num_elements = data.count; num_elements > 0) { + if (const auto shape_size = ShapeSize(static_output_shape); + shape_size < 0 || num_elements != static_cast(shape_size)) { + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, + "CoreML MLMultiArray count (", num_elements, ") and shape size (", shape_size, + ") do not match"); + } + + const void* model_output_buffer = data.dataPointer; + + if (model_output_buffer == nullptr) { + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "model_output_buffer has no data for ", output_name); + } + + const auto onnx_data_type = output_tensor_info.data_type; + switch (onnx_data_type) { + case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: { + const auto output_data_byte_size = num_elements * sizeof(float); + memcpy(output_buffer, model_output_buffer, output_data_byte_size); + break; + } + case ONNX_NAMESPACE::TensorProto_DataType_INT32: { + const auto output_data_byte_size = num_elements * sizeof(int32_t); + memcpy(output_buffer, model_output_buffer, output_data_byte_size); + break; + } + // For this case, since Coreml Spec only uses int32 for model output while onnx provides + // int64 for model output data type. We are doing a type casting (int32 -> int64) here + // when copying the model to ORT + case ONNX_NAMESPACE::TensorProto_DataType_INT64: { + ORT_RETURN_IF_NOT(data.dataType == MLMultiArrayDataTypeInt32, + "CoreML output data type is not MLMultiArrayDataTypeInt32"); + + const auto model_output_span = gsl::span{static_cast(model_output_buffer), num_elements}; + const auto output_span = gsl::span{static_cast(output_buffer), num_elements}; + std::transform(model_output_span.begin(), model_output_span.end(), output_span.begin(), + [](int32_t v) { return static_cast(v); }); + break; } + default: + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, + "Output data type is not supported, actual type: ", onnx_data_type); } - ORT_RETURN_IF_NOT(model_output_type == MLMultiArrayDataTypeInt32, - "Coreml model_output_type is not MLMultiArrayDataTypeInt32 for the case"); - break; - default: - return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, - "Output data type is not supported, actual type: ", - type); + } } } + ORT_CATCH(const std::exception& e) { + ORT_HANDLE_EXCEPTION([&]() { + status = ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Exception: ", e.what()); + }); + } - return onnxruntime::common::Status::OK(); + return status; } @end +NS_ASSUME_NONNULL_END + namespace onnxruntime { namespace coreml { @@ -306,7 +387,8 @@ - (void)dealloc { Status LoadModel(); Status Predict(const std::unordered_map& inputs, - const std::unordered_map& outputs); + const std::unordered_map& outputs, + const GetOutputTensorMutableRawDataFn& get_output_tensor_mutable_raw_data_fn); private: bool model_loaded{false}; @@ -339,12 +421,15 @@ Status Predict(const std::unordered_map& inputs, } Status Execution::Predict(const std::unordered_map& inputs, - const std::unordered_map& outputs) { + const std::unordered_map& outputs, + const GetOutputTensorMutableRawDataFn& get_output_tensor_mutable_raw_data_fn) { ORT_RETURN_IF_NOT(model_loaded, "Execution::Predict requires Execution::LoadModel"); if (HAS_VALID_BASE_OS_VERSION) { @autoreleasepool { - return [execution_ predict:inputs outputs:outputs]; + return [execution_ predict:inputs + outputs:outputs + getOutputTensorDataFn:get_output_tensor_mutable_raw_data_fn]; } } @@ -362,8 +447,9 @@ Status Predict(const std::unordered_map& inputs, } Status Model::Predict(const std::unordered_map& inputs, - const std::unordered_map& outputs) { - return execution_->Predict(inputs, outputs); + const std::unordered_map& outputs, + const GetOutputTensorMutableRawDataFn& get_output_tensor_mutable_raw_data_fn) { + return execution_->Predict(inputs, outputs, get_output_tensor_mutable_raw_data_fn); } bool Model::IsScalarOutput(const std::string& output_name) const { @@ -374,8 +460,15 @@ Status Predict(const std::unordered_map& inputs, return Contains(int64_outputs_, output_name); } +const OnnxTensorInfo* Model::TryGetInputOutputInfo(const std::string& name) const { + const auto info_it = input_output_info_.find(name); + return info_it != input_output_info_.end() ? &info_it->second : nullptr; +} + const OnnxTensorInfo& Model::GetInputOutputInfo(const std::string& name) const { - return input_output_info_.at(name); + const auto* info = TryGetInputOutputInfo(name); + ORT_ENFORCE(info != nullptr, "Failed to get info for input/output: ", name); + return *info; } } // namespace coreml diff --git a/onnxruntime/core/providers/coreml/shape_utils.cc b/onnxruntime/core/providers/coreml/shape_utils.cc new file mode 100644 index 0000000000000..255aba0e8c69c --- /dev/null +++ b/onnxruntime/core/providers/coreml/shape_utils.cc @@ -0,0 +1,68 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/providers/coreml/shape_utils.h" + +#include "core/framework/tensor_shape.h" +#include "core/framework/tensorprotoutils.h" + +namespace onnxruntime::coreml { + +namespace { +bool GetShapeImpl(const NodeArg& node_arg, std::vector& shape_out, const logging::Logger& logger, + bool allow_dynamic_shape) { + const auto* shape_proto = node_arg.Shape(); + if (!shape_proto) { + LOGS(logger, VERBOSE) << "NodeArg [" << node_arg.Name() << "] has no shape info"; + return false; + } + + std::vector shape{}; + shape.reserve(shape_proto->dim().size()); + + for (int i = 0; i < shape_proto->dim().size(); ++i) { + const auto& dim = shape_proto->dim(i); + if (utils::HasDimValue(dim)) { + const auto dim_value = dim.dim_value(); + ORT_ENFORCE(dim_value >= 0, "NodeArg [", node_arg.Name(), "] has a negative dimension value"); + shape.push_back(dim_value); + } else { + // dynamic dimension + if (!allow_dynamic_shape) { + LOGS(logger, VERBOSE) << "NodeArg [" << node_arg.Name() << "] has shape with dynamic dimension"; + return false; + } + shape.push_back(-1); + } + } + + shape_out = std::move(shape); + return true; +} +} // namespace + +bool GetShape(const NodeArg& node_arg, std::vector& shape, const logging::Logger& logger) { + return GetShapeImpl(node_arg, shape, logger, /* allow_dynamic_shape */ true); +} + +bool GetStaticShape(const NodeArg& node_arg, std::vector& shape, const logging::Logger& logger) { + return GetShapeImpl(node_arg, shape, logger, /* allow_dynamic_shape */ false); +} + +bool IsStaticShape(gsl::span shape) { + return std::find(shape.begin(), shape.end(), int64_t{-1}) == shape.end(); +} + +bool DoesShapeSpecifyZeroElements(gsl::span shape) { + return std::find(shape.begin(), shape.end(), int64_t{0}) != shape.end(); +} + +int64_t ShapeSize(gsl::span shape) { + return TensorShape(shape).Size(); +} + +std::string Shape2String(gsl::span shape) { + return TensorShape(shape).ToString(); +} + +} // namespace onnxruntime::coreml diff --git a/onnxruntime/core/providers/coreml/shape_utils.h b/onnxruntime/core/providers/coreml/shape_utils.h new file mode 100644 index 0000000000000..0a1fd47cfdfe4 --- /dev/null +++ b/onnxruntime/core/providers/coreml/shape_utils.h @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include +#include +#include + +#include "core/common/gsl.h" +#include "core/common/logging/logging.h" +#include "core/graph/node_arg.h" + +namespace onnxruntime::coreml { + +// Gets `node_arg`'s shape. Dynamic dimensions will have a value of -1. All other dimensions will be non-negative. +bool GetShape(const NodeArg& node_arg, std::vector& shape, const logging::Logger& logger); + +// Gets `node_arg`'s shape if it has no dynamic dimensions. All dimensions will be non-negative. +bool GetStaticShape(const NodeArg& node_arg, std::vector& shape, const logging::Logger& logger); + +// True iff `shape` has no dynamic dimensions. +bool IsStaticShape(gsl::span shape); + +// True iff `shape` specifies zero elements with its non-dynamic dimensions. Like `TensorShape::Size() == 0`, but it +// does not compute the size. +bool DoesShapeSpecifyZeroElements(gsl::span shape); + +// Gets the number of elements contained by the shape or -1 if the shape has any dynamic dimensions. +int64_t ShapeSize(gsl::span shape); + +// Gets a string representation of `shape`. +std::string Shape2String(gsl::span shape); + +} // namespace onnxruntime::coreml diff --git a/onnxruntime/core/providers/cpu/activation/activations.h b/onnxruntime/core/providers/cpu/activation/activations.h index 9d65d4587ade7..f387b333aba2e 100644 --- a/onnxruntime/core/providers/cpu/activation/activations.h +++ b/onnxruntime/core/providers/cpu/activation/activations.h @@ -84,7 +84,7 @@ struct Softplus : public ElementWiseRangedTransform { Status Init(const onnxruntime::NodeAttributes&) { return Status::OK(); } - GSL_SUPPRESS(r .11) + GSL_SUPPRESS(r.11) ElementWiseRangedTransform* Copy() const { using T1 = typename std::remove_pointer::type; using T2 = typename std::remove_const::type; @@ -107,7 +107,7 @@ struct Relu : public ElementWiseRangedTransform { Status Init(const onnxruntime::NodeAttributes&) { return Status::OK(); } - GSL_SUPPRESS(r .11) + GSL_SUPPRESS(r.11) ElementWiseRangedTransform* Copy() const { // replace it with a macro. why this? using T1 = typename std::remove_pointer::type; using T2 = typename std::remove_const::type; // redundant? @@ -130,7 +130,7 @@ struct Sigmoid : public ElementWiseRangedTransform { Status Init(const onnxruntime::NodeAttributes&) { return Status::OK(); } - GSL_SUPPRESS(r .11) + GSL_SUPPRESS(r.11) ElementWiseRangedTransform* Copy() const { using T1 = typename std::remove_pointer::type; using T2 = typename std::remove_const::type; @@ -156,7 +156,7 @@ struct Softsign : public ElementWiseRangedTransform { Status Init(const onnxruntime::NodeAttributes&) { return Status::OK(); } - GSL_SUPPRESS(r .11) + GSL_SUPPRESS(r.11) ElementWiseRangedTransform* Copy() const { using T1 = typename std::remove_pointer::type; using T2 = typename std::remove_const::type; @@ -179,7 +179,7 @@ struct Tanh : public ElementWiseRangedTransform { Status Init(const onnxruntime::NodeAttributes&) { return Status::OK(); } - GSL_SUPPRESS(r .11) + GSL_SUPPRESS(r.11) ElementWiseRangedTransform* Copy() const { using T1 = typename std::remove_pointer::type; using T2 = typename std::remove_const::type; diff --git a/onnxruntime/core/providers/cpu/controlflow/if.cc b/onnxruntime/core/providers/cpu/controlflow/if.cc index c472afd2f2ca6..a5fe3f02b2924 100644 --- a/onnxruntime/core/providers/cpu/controlflow/if.cc +++ b/onnxruntime/core/providers/cpu/controlflow/if.cc @@ -96,11 +96,19 @@ ONNX_CPU_OPERATOR_VERSIONED_KERNEL(If, If); // optional type is supported starting opset-16 +ONNX_CPU_OPERATOR_VERSIONED_KERNEL(If, + 16, 18, + KernelDefBuilder() + .TypeConstraint("B", DataTypeImpl::GetTensorType()) + .TypeConstraint("V", DataTypeImpl::AllTensorAndSequenceTensorAndOptionalTypes()), + If); + +// float 8 support was added. ONNX_CPU_OPERATOR_KERNEL(If, - 16, + 19, KernelDefBuilder() .TypeConstraint("B", DataTypeImpl::GetTensorType()) - .TypeConstraint("V", DataTypeImpl::AllTensorAndSequenceTensorAndOptionalTypes()), + .TypeConstraint("V", DataTypeImpl::AllTensorAndSequenceTensorAndOptionalTypesIRv9()), If); If::Info::Info(const onnxruntime::Node& node, const GraphViewer& subgraph_in) : subgraph(subgraph_in) { @@ -212,7 +220,7 @@ common::Status If::SetupSubgraphExecutionInfo(const SessionState& session_state, std::vector feed_locations; ORT_RETURN_IF_ERROR(controlflow::detail::FindDevicesForValues(session_state, feed_names, feed_locations)); - std::vector fetch_locations; + std::vector fetch_locations; fetch_locations.reserve(info->num_outputs); // we need the allocator info for each output from the If node @@ -220,7 +228,7 @@ common::Status If::SetupSubgraphExecutionInfo(const SessionState& session_state, const auto& outputs = node.OutputDefs(); for (int i = 0, end = info->num_outputs; i < end; ++i) { // const auto& alloc_info = controlflow::detail::FindMemoryInfoForValue(session_state, outputs[i]->Name()); - const auto& alloc_info = utils::FindMemoryInfoForValue(session_state, outputs[i]->Name()); + const auto& alloc_info = utils::FindDeviceForValue(session_state, outputs[i]->Name()); fetch_locations.push_back(&alloc_info); } @@ -384,7 +392,7 @@ Status IfImpl::Execute(const FeedsFetchesManager& ffm) { if (outputs_[i].first == AllocationType::Delayed) { // functor to forward the allocation request from the subgraph to the If node's context so that the // allocation plan for the If node's output is used. - fetch_allocators[i] = [this, i, &fetches](const TensorShape& shape, const OrtMemoryInfo& location, + fetch_allocators[i] = [this, i, &fetches](const TensorShape& shape, const OrtDevice& location, OrtValue& ort_value, bool& allocated) { // if the device the If output is allocated on does not match the required device for the subgraph output // we don't update the provided OrtValue and return false for 'allocated'. @@ -397,7 +405,7 @@ Status IfImpl::Execute(const FeedsFetchesManager& ffm) { const OrtValue& value = *context_.GetOutputMLValue(i); - if (tensor->Location().device == location.device) { + if (tensor->Location().device == location) { // return OrtValue for allocated tensor ort_value = value; allocated = true; diff --git a/onnxruntime/core/providers/cpu/controlflow/loop.cc b/onnxruntime/core/providers/cpu/controlflow/loop.cc index 5d296cc777110..9bb080c0a9fac 100644 --- a/onnxruntime/core/providers/cpu/controlflow/loop.cc +++ b/onnxruntime/core/providers/cpu/controlflow/loop.cc @@ -123,12 +123,20 @@ ONNX_CPU_OPERATOR_VERSIONED_KERNEL(Loop, .TypeConstraint("V", DataTypeImpl::AllTensorAndSequenceTensorTypes()), Loop); +ONNX_CPU_OPERATOR_VERSIONED_KERNEL(Loop, + 16, 18, + KernelDefBuilder() + .TypeConstraint("I", DataTypeImpl::GetTensorType()) + .TypeConstraint("B", DataTypeImpl::GetTensorType()) + .TypeConstraint("V", DataTypeImpl::AllTensorAndSequenceTensorAndOptionalTypes()), + Loop); + ONNX_CPU_OPERATOR_KERNEL(Loop, - 16, + 19, KernelDefBuilder() .TypeConstraint("I", DataTypeImpl::GetTensorType()) .TypeConstraint("B", DataTypeImpl::GetTensorType()) - .TypeConstraint("V", DataTypeImpl::AllTensorAndSequenceTensorAndOptionalTypes()), + .TypeConstraint("V", DataTypeImpl::AllTensorAndSequenceTensorAndOptionalTypesIRv9()), Loop); Loop::Info::Info(const onnxruntime::Node& node, const GraphViewer& subgraph_in) @@ -313,28 +321,27 @@ common::Status Loop::SetupSubgraphExecutionInfo(const SessionState& session_stat ORT_RETURN_IF_ERROR(utils::InitializeFeedFetchCopyInfo(subgraph_session_state, *ffm)); // setup the locations where we want the subgraph output to end up on - std::vector fetch_locations; + std::vector fetch_locations; fetch_locations.reserve(info_->num_subgraph_outputs); // 'cond' is first output and we need it to be on CPU so we can read the latest value const auto& cpu_allocator_info = session_state.GetExecutionProviders() .Get(onnxruntime::kCpuExecutionProvider) - ->GetAllocator(OrtMemTypeDefault) - ->Info(); + ->GetOrtDeviceByMemType(OrtMemTypeDefault); fetch_locations.push_back(&cpu_allocator_info); // Loop state variables need to be where we can feed them in to the next iteration, so set the fetch location // to match the feed location. for (ptrdiff_t i = 0; i < info_->num_loop_carried_vars; ++i) { // +2 for both to skip the iter_num and cond input values - const auto& alloc_info = utils::FindMemoryInfoForValue(session_state, loop_inputs[i + 2]->Name()); + const auto& alloc_info = utils::FindDeviceForValue(session_state, loop_inputs[i + 2]->Name()); fetch_locations.push_back(&alloc_info); } // remaining outputs we want where the matching Loop output will be allocated const auto& loop_outputs = node.OutputDefs(); for (size_t i = info_->num_loop_carried_vars, end = loop_outputs.size(); i < end; ++i) { - const auto& alloc_info = utils::FindMemoryInfoForValue(session_state, loop_outputs[i]->Name()); + const auto& alloc_info = utils::FindDeviceForValue(session_state, loop_outputs[i]->Name()); fetch_locations.push_back(&alloc_info); } @@ -409,9 +416,7 @@ Status LoopImpl::Initialize() { auto condition_rank = subgraph_inputs[1]->Shape()->dim_size(); // these need to be on CPU - auto cpu_allocator = session_state_.GetExecutionProviders() - .Get(onnxruntime::kCpuExecutionProvider) - ->GetAllocator(OrtMemTypeDefault); + auto cpu_allocator = session_state_.GetAllocator(session_state_.GetExecutionProviders().Get(onnxruntime::kCpuExecutionProvider)->GetOrtDeviceByMemType(OrtMemTypeDefault)); iter_num_mlvalue_ = MakeScalarMLValue(cpu_allocator, 0, iter_num_rank != 0); condition_mlvalue_ = MakeScalarMLValue(cpu_allocator, condition_, condition_rank != 0); diff --git a/onnxruntime/core/providers/cpu/controlflow/scan_9.cc b/onnxruntime/core/providers/cpu/controlflow/scan_9.cc index 2e132da6773d4..7c19dca6a4f11 100644 --- a/onnxruntime/core/providers/cpu/controlflow/scan_9.cc +++ b/onnxruntime/core/providers/cpu/controlflow/scan_9.cc @@ -515,11 +515,20 @@ ONNX_CPU_OPERATOR_VERSIONED_KERNEL(Scan, Scan<9>); // Opset 16 starts to support BFloat16 type for the type constraint "V" +ONNX_CPU_OPERATOR_VERSIONED_KERNEL(Scan, + 16, 18, + KernelDefBuilder() + // 'I' is in the ONNX spec but is not actually used for any inputs or outputs + //.TypeConstraint("I", DataTypeImpl::GetTensorType()) + .TypeConstraint("V", DataTypeImpl::AllTensorTypes()), + Scan<9>); + +// Opset 19 starts to support float 8 types for the type constraint "V" ONNX_CPU_OPERATOR_KERNEL(Scan, - 16, + 19, KernelDefBuilder() // 'I' is in the ONNX spec but is not actually used for any inputs or outputs //.TypeConstraint("I", DataTypeImpl::GetTensorType()) - .TypeConstraint("V", DataTypeImpl::AllTensorTypes()), + .TypeConstraint("V", DataTypeImpl::AllTensorTypesIRv9()), Scan<9>); } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cpu/controlflow/scan_utils.cc b/onnxruntime/core/providers/cpu/controlflow/scan_utils.cc index 73f7c9f16871a..b28a84e00ca65 100644 --- a/onnxruntime/core/providers/cpu/controlflow/scan_utils.cc +++ b/onnxruntime/core/providers/cpu/controlflow/scan_utils.cc @@ -168,11 +168,11 @@ Status CreateFeedsFetchesManager(const Node& node, ORT_RETURN_IF_ERROR(utils::InitializeFeedFetchCopyInfo(subgraph_session_state, *ffm)); // we provide fetches using memory allocated by Scan, so provide locations based on the Scan output locations - std::vector fetch_locations; + std::vector fetch_locations; fetch_locations.reserve(info.num_outputs); for (const auto& output : node.OutputDefs()) { - const auto& alloc_info = utils::FindMemoryInfoForValue(session_state, output->Name()); + const auto& alloc_info = utils::FindDeviceForValue(session_state, output->Name()); fetch_locations.push_back(&alloc_info); } @@ -243,7 +243,7 @@ Status IterateSequence(OpKernelContextInternal& context, const SessionState& ses // use a custom allocator that will forward the allocation request to the Scan context // and add the sequence length dimension. this avoids using a temporary value for the first output - fetch_allocators[output] = [i, &iterator, &fetches](const TensorShape& shape, const OrtMemoryInfo& location, + fetch_allocators[output] = [i, &iterator, &fetches](const TensorShape& shape, const OrtDevice& location, OrtValue& ort_value, bool& allocated) { auto status = iterator.AllocateFinalOutput(shape); ORT_RETURN_IF_ERROR(status); @@ -254,7 +254,7 @@ Status IterateSequence(OpKernelContextInternal& context, const SessionState& ses // if that does not match the required device we don't update the provided OrtValue and return false for // 'allocated'. the execution frame will allocate a buffer on the required device, and the fetches copy // logic in utils::ExecuteSubgraph will handle moving it to CPU (and into the tensor we allocated here) - if (value.Get().Location().device == location.device) { + if (value.Get().Location().device == location) { // update OrtValue with a current slice from the iterator. ort_value = value; allocated = true; diff --git a/onnxruntime/core/providers/cpu/controlflow/utils.cc b/onnxruntime/core/providers/cpu/controlflow/utils.cc index 93e77113de2af..837a93374f79e 100644 --- a/onnxruntime/core/providers/cpu/controlflow/utils.cc +++ b/onnxruntime/core/providers/cpu/controlflow/utils.cc @@ -21,8 +21,8 @@ common::Status FindDevicesForValues(const SessionState& session_state, devices.resize(names.size()); for (size_t i = start_at, end = names.size(); i < end; ++i) { - const auto& location = utils::FindMemoryInfoForValue(session_state, names[i]); - devices[i] = location.device; + const auto& location = utils::FindDeviceForValue(session_state, names[i]); + devices[i] = location; } return Status::OK(); diff --git a/onnxruntime/core/providers/cpu/cpu_execution_provider.cc b/onnxruntime/core/providers/cpu/cpu_execution_provider.cc index 8e1b412dd2e66..18010960e11c8 100644 --- a/onnxruntime/core/providers/cpu/cpu_execution_provider.cc +++ b/onnxruntime/core/providers/cpu/cpu_execution_provider.cc @@ -24,42 +24,23 @@ struct KernelRegistryAndStatus { } // namespace namespace onnxruntime { -CPUExecutionProvider::CPUExecutionProvider(const CPUExecutionProviderInfo& info, bool delay_allocator_registration) +CPUExecutionProvider::CPUExecutionProvider(const CPUExecutionProviderInfo& info) : IExecutionProvider{onnxruntime::kCpuExecutionProvider}, info_{info} { - if (!delay_allocator_registration) { - AllocatorManager mgr; // needed only to call RegisterAllocator - RegisterAllocator(mgr); - } } -void CPUExecutionProvider::RegisterAllocator(AllocatorManager& allocator_manager) { - OrtDevice cpu_device{OrtDevice::CPU, OrtDevice::MemType::DEFAULT, DEFAULT_CPU_ALLOCATOR_DEVICE_ID}; - // if EP is used in multiple inference sessions we may already have an allocator. if so use that. - auto cpu_alloc = GetAllocator(OrtMemTypeDefault); - if (!cpu_alloc) { - // use shared allocator if available - cpu_alloc = allocator_manager.GetAllocator(OrtMemTypeDefault, cpu_device); - - if (!cpu_alloc) { - // create our allocator - bool create_arena = info_.create_arena; +std::vector CPUExecutionProvider::CreatePreferredAllocators() { + bool create_arena = info_.create_arena; #if defined(USE_JEMALLOC) || defined(USE_MIMALLOC) - // JEMalloc/mimalloc already have memory pool, so just use device allocator. - create_arena = false; + // JEMalloc/mimalloc already have memory pool, so just use device allocator. + create_arena = false; #elif !(defined(__amd64__) || defined(_M_AMD64) || defined(__aarch64__) || defined(_M_ARM64)) - // Disable Arena allocator for x86_32 build because it may run into infinite loop when integer overflow happens - create_arena = false; + // Disable Arena allocator for x86_32 build because it may run into infinite loop when integer overflow happens + create_arena = false; #endif - AllocatorCreationInfo device_info{[](int) { return std::make_unique(); }, - DEFAULT_CPU_ALLOCATOR_DEVICE_ID, create_arena}; - - cpu_alloc = CreateAllocator(device_info); - // enable sharing of our allocator - allocator_manager.InsertAllocator(cpu_alloc); - } + AllocatorCreationInfo device_info{[](int) { return std::make_unique(); }, + DEFAULT_CPU_ALLOCATOR_DEVICE_ID, create_arena}; - InsertAllocator(cpu_alloc); - } + return std::vector{CreateAllocator(device_info)}; } // Forward declarations of op kernels @@ -162,6 +143,9 @@ class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 7, Aco class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 7, Atan); class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 7, 8, float, Gemm); class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 7, 8, double, Gemm); +#ifdef MLAS_F16VEC_INTRINSICS_SUPPORTED +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 7, 8, MLFloat16, Gemm); +#endif class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 10, Hardmax); class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 10, float, LogSoftmax); class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 10, double, LogSoftmax); @@ -340,6 +324,9 @@ class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOn class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 9, 10, Flatten); class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 9, 10, float, Gemm); class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 9, 10, double, Gemm); +#ifdef MLAS_F16VEC_INTRINSICS_SUPPORTED +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 9, 10, MLFloat16, Gemm); +#endif class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 9, 12, float, MatMul); class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 9, 12, double, MatMul); class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 9, 12, int32_t, MatMul); @@ -460,13 +447,13 @@ class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDoma class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, Det); class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, ScatterElements); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, NonMaxSuppression); -class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, AveragePool); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 18, AveragePool); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, MaxUnpool); class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 17, LpPool); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, Conv); #ifdef MLAS_F16VEC_INTRINSICS_SUPPORTED class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, MLFloat16, Conv); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, MLFloat16, AveragePool); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 18, MLFloat16, AveragePool); #endif class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, ConvTranspose); class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, If); @@ -481,6 +468,9 @@ class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, Sp class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, ScatterND); class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, float, Gemm); class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, double, Gemm); +#ifdef MLAS_F16VEC_INTRINSICS_SUPPORTED +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, MLFloat16, Gemm); +#endif class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, 12, GatherElements); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, uint8_t, BitShift); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, uint32_t, BitShift); @@ -557,11 +547,11 @@ class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOn // opset 13 class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, float, Erf); -class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, Cast); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, 18, Cast); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, Clip); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, uint8_t, DequantizeLinear); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, int8_t, DequantizeLinear); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, int32_t, DequantizeLinear); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, 18, uint8_t, DequantizeLinear); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, 18, int8_t, DequantizeLinear); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, 18, int32_t, DequantizeLinear); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, float, Expand); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, double, Expand); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, int8_t, Expand); @@ -577,6 +567,9 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, string, Expand); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, float, Gemm); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, double, Gemm); +#ifdef MLAS_F16VEC_INTRINSICS_SUPPORTED +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, MLFloat16, Gemm); +#endif class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, float, MatMul); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, double, MatMul); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, int32_t, MatMul); @@ -584,11 +577,11 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, Min); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, Max); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, float, Mean); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, uint8_t, QuantizeLinear); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, int8_t, QuantizeLinear); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, 18, uint8_t, QuantizeLinear); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, 18, int8_t, QuantizeLinear); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, Sigmoid); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, Sign); -class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, Size); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, 18, Size); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, float, Sum); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, double, Sum); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, Flatten); @@ -617,11 +610,11 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, double, Greater); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, int32_t, Greater); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, int64_t, Greater); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, bool, Equal); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, int32_t, Equal); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, int64_t, Equal); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, float, Equal); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, double, Equal); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, 18, bool, Equal); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, 18, int32_t, Equal); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, 18, int64_t, Equal); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, 18, float, Equal); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, 18, double, Equal); class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, 13, float, Add); class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, 13, double, Add); class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 13, 13, int32_t, Add); @@ -779,7 +772,7 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 14, double, Div); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 14, int32_t, Div); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 14, int64_t, Div); -class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 14, Reshape); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 14, 18, Reshape); class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 14, 15, Identity); class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 14, 14, float, BatchNormalization); class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 14, 14, double, BatchNormalization); @@ -791,7 +784,7 @@ class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 14, RN class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 15, Pow); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 15, float, BatchNormalization); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 15, double, BatchNormalization); -class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 15, Shape); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 15, 18, Shape); #if !defined(DISABLE_OPTIONAL_TYPE) class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 15, 17, OptionalHasElement); @@ -800,9 +793,9 @@ class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 15, Op #endif // Opset 16 -class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 16, Identity); -class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 16, Loop); -class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 16, If); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 16, 18, Identity); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 16, 18, Loop); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 16, 18, If); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 16, float, RoiAlign); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 16, double, RoiAlign); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 16, float, GridSample); @@ -819,7 +812,7 @@ class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 16, Le class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 16, MLFloat16, LeakyRelu); #endif class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 16, PRelu); -class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 16, Scan); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 16, 18, Scan); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 16, float, GreaterOrEqual); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 16, double, GreaterOrEqual); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 16, int32_t, GreaterOrEqual); @@ -840,10 +833,10 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 17, double, LayerNormalization); // Opset 18 -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, float, Resize); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, int32_t, Resize); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, int8_t, Resize); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, uint8_t, Resize); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, 18, float, Resize); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, 18, int32_t, Resize); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, 18, int8_t, Resize); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, 18, uint8_t, Resize); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, float, ReduceL1); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, int32_t, ReduceL1); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, int64_t, ReduceL1); @@ -913,14 +906,57 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, uint16_t, BitwiseXor); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, uint32_t, BitwiseXor); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, uint64_t, BitwiseXor); -class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, Pad); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, 18, Pad); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, ScatterND); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, ScatterElements); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, Split); #if !defined(DISABLE_OPTIONAL_TYPE) class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, OptionalHasElement); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 18, OptionalGetElement); + +#endif + +// Opset 19 +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, Size); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, AveragePool); +#ifdef MLAS_F16VEC_INTRINSICS_SUPPORTED +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, MLFloat16, AveragePool); +#endif +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, Cast); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, int32_t, DequantizeLinear); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, uint8_t, DequantizeLinear); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, int8_t, DequantizeLinear); +#if !defined(DISABLE_FLOAT8_TYPES) +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, Float8E4M3FN, DequantizeLinear); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, Float8E4M3FNUZ, DequantizeLinear); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, Float8E5M2, DequantizeLinear); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, Float8E5M2FNUZ, DequantizeLinear); +#endif +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, bool, Equal); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, int32_t, Equal); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, int64_t, Equal); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, float, Equal); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, double, Equal); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, string, Equal); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, Identity); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, If); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, Loop); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, Pad); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, uint8_t, QuantizeLinear); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, int8_t, QuantizeLinear); +#if !defined(DISABLE_FLOAT8_TYPES) +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, Float8E4M3FN, QuantizeLinear); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, Float8E4M3FNUZ, QuantizeLinear); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, Float8E5M2, QuantizeLinear); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, Float8E5M2FNUZ, QuantizeLinear); #endif +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, Reshape); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, float, Resize); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, int32_t, Resize); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, int8_t, Resize); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, uint8_t, Resize); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, Scan); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 19, Shape); // !!PLEASE READ BELOW!! Following that, add new entries above this comment @@ -1529,7 +1565,7 @@ Status RegisterOnnxOperatorKernels(KernelRegistry& kernel_registry) { BuildKernelCreateInfo, BuildKernelCreateInfo, - BuildKernelCreateInfo, + BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, @@ -1764,7 +1800,7 @@ Status RegisterOnnxOperatorKernels(KernelRegistry& kernel_registry) { LessOrEqual)>, // opset 13 - BuildKernelCreateInfo, + BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, @@ -1780,21 +1816,21 @@ Status RegisterOnnxOperatorKernels(KernelRegistry& kernel_registry) { 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, @@ -2116,7 +2152,7 @@ Status RegisterOnnxOperatorKernels(KernelRegistry& kernel_registry) { BatchNormalization)>, BuildKernelCreateInfo, - BuildKernelCreateInfo, + BuildKernelCreateInfo, #if !defined(DISABLE_OPTIONAL_TYPE) BuildKernelCreateInfo, @@ -2125,9 +2161,9 @@ Status RegisterOnnxOperatorKernels(KernelRegistry& kernel_registry) { #endif // Opset 16 - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, - BuildKernelCreateInfo, + BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, // Opset 18 - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, - BuildKernelCreateInfo, + BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, @@ -2296,6 +2331,58 @@ Status RegisterOnnxOperatorKernels(KernelRegistry& kernel_registry) { BuildKernelCreateInfo, BuildKernelCreateInfo, #endif + + // Opset 19 + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, +#if !defined(DISABLE_FLOAT8_TYPES) + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, +#endif + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, +#if !defined(DISABLE_FLOAT8_TYPES) + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, +#endif + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, }; for (auto& function_table_entry : function_table) { @@ -2313,7 +2400,8 @@ Status RegisterFp16Kernels(KernelRegistry& kernel_registry) { static const BuildKernelCreateInfoFn function_table[] = { BuildKernelCreateInfo, BuildKernelCreateInfo, - BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, @@ -2321,6 +2409,12 @@ Status RegisterFp16Kernels(KernelRegistry& kernel_registry) { BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + + BuildKernelCreateInfo, }; for (auto& function_table_entry : function_table) { diff --git a/onnxruntime/core/providers/cpu/cpu_execution_provider.h b/onnxruntime/core/providers/cpu/cpu_execution_provider.h index c0ef15ac80c28..2b87ac6441d13 100644 --- a/onnxruntime/core/providers/cpu/cpu_execution_provider.h +++ b/onnxruntime/core/providers/cpu/cpu_execution_provider.h @@ -3,7 +3,6 @@ #pragma once -#include "core/framework/allocatormgr.h" #include "core/framework/execution_provider.h" #include "core/graph/constants.h" @@ -27,12 +26,11 @@ class CPUExecutionProvider : public IExecutionProvider { public: // delay_allocator_registration = true is used to allow sharing of allocators between different providers that are // associated with the same device - explicit CPUExecutionProvider(const CPUExecutionProviderInfo& info, bool delay_allocator_registration = false); - - void RegisterAllocator(AllocatorManager& allocator_manager) override; + explicit CPUExecutionProvider(const CPUExecutionProviderInfo& info); std::shared_ptr GetKernelRegistry() const override; std::unique_ptr GetDataTransfer() const override; + std::vector CreatePreferredAllocators() override; private: CPUExecutionProviderInfo info_; diff --git a/onnxruntime/core/providers/cpu/cpu_provider_factory.cc b/onnxruntime/core/providers/cpu/cpu_provider_factory.cc index a79992fdf15bb..4b6ab05be0345 100644 --- a/onnxruntime/core/providers/cpu/cpu_provider_factory.cc +++ b/onnxruntime/core/providers/cpu/cpu_provider_factory.cc @@ -24,7 +24,7 @@ struct CpuProviderFactory : IExecutionProviderFactory { std::unique_ptr CpuProviderFactory::CreateProvider() { CPUExecutionProviderInfo info; info.create_arena = create_arena_; - return std::make_unique(info, true /* delay allocator registration to allow sharing */); + return std::make_unique(info); } std::shared_ptr CPUProviderFactoryCreator::Create(int use_arena) { diff --git a/onnxruntime/core/providers/cpu/cpu_provider_shared.cc b/onnxruntime/core/providers/cpu/cpu_provider_shared.cc index d3d252cf7026e..ddcc04cf4a45c 100644 --- a/onnxruntime/core/providers/cpu/cpu_provider_shared.cc +++ b/onnxruntime/core/providers/cpu/cpu_provider_shared.cc @@ -57,6 +57,10 @@ #include "orttraining/training_ops/cpu/controlflow/yield.h" #endif +#ifdef ENABLE_TRITON +#include "orttraining/training_ops/cpu/triton/triton_op.h" +#endif + #include "cpu_provider_shared.h" namespace onnxruntime { @@ -300,6 +304,19 @@ struct ProviderHostCPUImpl : ProviderHostCPU { return contrib::ExecuteReduceSumATen(p_ctx, axes, keepdims); } #endif + +#ifdef ENABLE_TRITON + Status contrib__TritonOp__Compute(const contrib::TritonOp* p, OpKernelContext* context) override { + return p->TritonOp::Compute(context); + } + bool contrib__IsTritonOpExecutorInitialized() override { return contrib::IsTritonOpExecutorInitialized(); } + Status contrib__ExecuteTritonOpByFuncName( + OpKernelContext* p_ctx, const std::string& func_name, size_t input_count, size_t output_count, + const InlinedHashMap>& kwargs) override { + return contrib::ExecuteTritonOpByFuncName(p_ctx, func_name, input_count, output_count, kwargs); + } +#endif + #endif }; #if defined(_MSC_VER) && !defined(__clang__) diff --git a/onnxruntime/core/providers/cpu/cpu_provider_shared.h b/onnxruntime/core/providers/cpu/cpu_provider_shared.h index 1fafc646c8aaa..7d4620f0039eb 100644 --- a/onnxruntime/core/providers/cpu/cpu_provider_shared.h +++ b/onnxruntime/core/providers/cpu/cpu_provider_shared.h @@ -211,6 +211,15 @@ struct ProviderHostCPU { virtual bool contrib__IsATenOperatorExecutorInitialized() = 0; virtual Status contrib__ExecuteReduceSumATen(OpKernelContext* p_ctx, const gsl::span& axes, bool keepdims) = 0; #endif + +#ifdef ENABLE_TRITON + virtual Status contrib__TritonOp__Compute(const contrib::TritonOp* p, OpKernelContext* context) = 0; + virtual bool contrib__IsTritonOpExecutorInitialized() = 0; + virtual Status contrib__ExecuteTritonOpByFuncName( + OpKernelContext* p_ctx, const std::string& func_name, size_t input_count, size_t output_count, + const InlinedHashMap>& kwargs) = 0; +#endif + #endif }; @@ -288,6 +297,18 @@ inline Status ExecuteReduceSumATen(OpKernelContext* p_ctx, const gsl::span>& kwargs) { + return g_host_cpu.contrib__ExecuteTritonOpByFuncName(p_ctx, func_name, input_count, output_count, kwargs); +} +} // namespace contrib +#endif // ENABLE_TRITON + #endif // USE_CUDA || USE_ROCM #endif diff --git a/onnxruntime/core/providers/cpu/element_wise_ranged_transform.h b/onnxruntime/core/providers/cpu/element_wise_ranged_transform.h index e528bcd784a76..f457a4d7dcaf9 100644 --- a/onnxruntime/core/providers/cpu/element_wise_ranged_transform.h +++ b/onnxruntime/core/providers/cpu/element_wise_ranged_transform.h @@ -56,7 +56,7 @@ ElementWiseRangedTransform::~ElementWiseRangedTransform() { Status Init(const onnxruntime::NodeAttributes& attributes) { \ return (GetFloatParam(#X, attributes, X)); \ } \ - GSL_SUPPRESS(r .11) \ + GSL_SUPPRESS(r.11) \ ElementWiseRangedTransform* Copy() const final { \ using T1 = typename std::remove_pointer::type; \ using T2 = typename std::remove_const::type; \ @@ -71,7 +71,7 @@ ElementWiseRangedTransform::~ElementWiseRangedTransform() { ORT_RETURN_IF_ERROR(GetFloatParam(#Y, attributes, Y)); \ return Status::OK(); \ } \ - GSL_SUPPRESS(r .11) \ + GSL_SUPPRESS(r.11) \ ElementWiseRangedTransform* Copy() const final { \ using T1 = typename std::remove_pointer::type; \ using T2 = typename std::remove_const::type; \ diff --git a/onnxruntime/core/providers/cpu/fp16/fp16_activations.h b/onnxruntime/core/providers/cpu/fp16/fp16_activations.h index 16bcd171e3941..5404a1b180b64 100644 --- a/onnxruntime/core/providers/cpu/fp16/fp16_activations.h +++ b/onnxruntime/core/providers/cpu/fp16/fp16_activations.h @@ -19,7 +19,7 @@ struct Relu : public ElementWiseRangedTransform { Activation.ActivationKind = MlasReluActivation; return Status::OK(); } - GSL_SUPPRESS(r .11) + GSL_SUPPRESS(r.11) ElementWiseRangedTransform* Copy() const final { using T1 = typename std::remove_pointer::type; using T2 = typename std::remove_const::type; // redundant? @@ -48,7 +48,7 @@ struct LeakyRelu : public ElementWiseRangedTransform { Activation.ActivationKind = MlasLeakyReluActivation; return (GetFloatParam("alpha", attributes, Activation.Parameters.LeakyRelu.alpha)); } - GSL_SUPPRESS(r .11) + GSL_SUPPRESS(r.11) ElementWiseRangedTransform* Copy() const final { using T1 = typename std::remove_pointer::type; using T2 = typename std::remove_const::type; diff --git a/onnxruntime/core/providers/cpu/fp16/fp16_conv.cc b/onnxruntime/core/providers/cpu/fp16/fp16_conv.cc index e23e792f81844..e6867f10819ae 100644 --- a/onnxruntime/core/providers/cpu/fp16/fp16_conv.cc +++ b/onnxruntime/core/providers/cpu/fp16/fp16_conv.cc @@ -32,7 +32,7 @@ using ConvPadVector = ConvAttributes::ConvPadVector; * 2. Activation * It takes an operator attribute 'activation', which supplies the activation info. * - * Add is performed AFTER activation. + * Add is performed BEFORE activation. * * The implementation supports both NCHW and NHWC. It runs faster with NHWC. * @@ -281,12 +281,10 @@ Status FusedConvFp16::Compute(OpKernelContext* context) const { if (Y->Shape().Size() == 0) { return Status::OK(); } - if (Sum) { - if (Sum->Shape() != Y->Shape()) { - return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Z shape does not match output shape.", - " Z: ", Sum->Shape().ToString().c_str(), - " Output: ", Y->Shape().ToString().c_str()); - } + if (Sum && Sum->Shape() != Y->Shape()) { + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Z shape does not match output shape.", + " Z: ", Sum->Shape().ToString().c_str(), + " Output: ", Y->Shape().ToString().c_str()); } const int64_t input_image_size = input_shape.Size(); @@ -338,7 +336,7 @@ Status FusedConvFp16::Compute(OpKernelContext* context) const { const auto* Xdata = X->Data(); const auto* Bdata = B != nullptr ? B->Data() : nullptr; auto* Ydata = Y->MutableData(); - const auto* SumData = Sum != nullptr ? Sum->Data() : nullptr; + const auto* sum_data = Sum != nullptr ? Sum->Data() : nullptr; BufferUniquePtr transpose_input_buffer; BufferUniquePtr transpose_output_buffer; @@ -409,7 +407,7 @@ Status FusedConvFp16::Compute(OpKernelContext* context) const { for (int64_t image_id = 0; image_id < N; ++image_id) { const auto* input_data = Xdata; auto* output_data = Ydata; - const auto* add_src = SumData; + const auto* add_src = sum_data; if (!channels_last_) { // Transpose the input from channels first (CHW) to channels last (HWC). @@ -478,7 +476,7 @@ Status FusedConvFp16::Compute(OpKernelContext* context) const { static_cast(M), static_cast(output_count), static_cast(kernel_size), - &act); + (!channels_last_ && sum_data) ? nullptr : &act); } else { for (int64_t group_id = 0; group_id < group_count; ++group_id) { // Prepare the im2col transformation or use the input buffer directly for @@ -554,13 +552,13 @@ Status FusedConvFp16::Compute(OpKernelContext* context) const { gemm_params.C = worker_output + group_id * group_output_channels; gemm_params.ldc = static_cast(M); gemm_params.Bias = Bdata; - gemm_params.OutputProcessor = &act; // process fused activation and add + gemm_params.OutputProcessor = (!channels_last_ && sum_data) ? nullptr : &act; // process fused activation and add MlasHalfGemmBatch( static_cast(output_count), static_cast(group_output_channels), static_cast(kernel_dim), - 1, &gemm_params, thread_pool); + 1, &gemm_params, nullptr); } } }; @@ -574,10 +572,8 @@ Status FusedConvFp16::Compute(OpKernelContext* context) const { Ydata, static_cast(output_image_size), static_cast(M)); - if (SumData != nullptr) { - MLAS_ACTIVATION activation; - activation.ActivationKind = MlasIdentityActivation; - MLAS_HALF_GEMM_ACTIVATION_PROCESSOR proc(activation, SumData); + if (sum_data != nullptr) { + MLAS_HALF_GEMM_ACTIVATION_PROCESSOR proc(activation_, sum_data); proc.Process(Ydata, 0, 0, static_cast(M), static_cast(output_image_size), static_cast(output_image_size)); @@ -586,8 +582,8 @@ Status FusedConvFp16::Compute(OpKernelContext* context) const { Xdata += X_offset; Ydata += Y_offset; - if (SumData != nullptr) { - SumData += Y_offset; + if (sum_data != nullptr) { + sum_data += Y_offset; } } diff --git a/onnxruntime/core/providers/cpu/fp16/fp16_pool.cc b/onnxruntime/core/providers/cpu/fp16/fp16_pool.cc index 68762a4c8e794..7c1e05f7ce277 100644 --- a/onnxruntime/core/providers/cpu/fp16/fp16_pool.cc +++ b/onnxruntime/core/providers/cpu/fp16/fp16_pool.cc @@ -139,11 +139,13 @@ Status PoolFp16::Compute(OpKernelContext* context) const { // Allocate indirection buffer pointers and prepare a padding vector for the // im2col transform. - constexpr int64_t output_batch_count = 512; - int64_t col_buffer_batch_count = std::min(output_image_size, output_batch_count); - auto* col_data = alloc->Alloc(SafeInt(sizeof(const MLFloat16*)) * kernel_size * col_buffer_batch_count); + auto* col_data = alloc->Alloc(SafeInt(sizeof(const MLFloat16*)) * kernel_size * output_image_size); BufferUniquePtr col_buffer(col_data, BufferDeleter(std::move(alloc))); + const int64_t output_stride = std::max((int64_t)2, (int64_t)8192 / (kernel_size * C)); + const int64_t task_count = (output_image_size + output_stride - 1) / output_stride; + concurrency::ThreadPool* thread_pool = context->GetOperatorThreadPool(); + for (int64_t image_id = 0; image_id < N; ++image_id) { const auto* input_data = Xdata; auto* output_data = Ydata; @@ -159,9 +161,12 @@ Status PoolFp16::Compute(OpKernelContext* context) const { output_data = static_cast(transpose_output_buffer.get()); } - auto* outputptr = output_data; - for (int64_t output_start = 0; output_start < output_image_size;) { - int64_t output_count = std::min(output_image_size - output_start, output_batch_count); + auto worker = [&](ptrdiff_t batch) { + int64_t output_start = (int64_t)batch * (int64_t)output_stride; + int64_t output_count = std::min((int64_t)output_stride, output_image_size - output_start); + auto* outputptr = output_data + output_stride * C * batch; + auto indirection_buffer = static_cast(col_buffer.get()) + output_start * kernel_size; + math::Im2col()( input_data, C, @@ -174,27 +179,26 @@ Status PoolFp16::Compute(OpKernelContext* context) const { static_cast(spatial_dims), output_start, output_count, - static_cast(col_buffer.get()), + indirection_buffer, need_padding ? padding_data.data() : nullptr); + if (is_max_pool_) { MlasNhwcMaxPool( - static_cast(col_buffer.get()), + indirection_buffer, outputptr, static_cast(C), static_cast(output_count), static_cast(kernel_size)); } else { MlasNhwcAvgPool( - static_cast(col_buffer.get()), + indirection_buffer, outputptr, static_cast(C), static_cast(output_count), static_cast(kernel_size)); } - - outputptr += output_count * C; - output_start += output_count; - } + }; + concurrency::ThreadPool::TrySimpleParallelFor(thread_pool, onnxruntime::narrow(task_count), worker); if (!channels_last_) { // Transpose the output from channels last (NHWC) to channels first (NCHW). @@ -227,9 +231,15 @@ ONNX_CPU_OPERATOR_TYPED_KERNEL( KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()), PoolFp16); +ONNX_CPU_OPERATOR_VERSIONED_TYPED_KERNEL( + AveragePool, 11, 18, + MLFloat16, + KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()), + PoolFp16); + ONNX_CPU_OPERATOR_TYPED_KERNEL( AveragePool, - 11, + 19, MLFloat16, KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()), PoolFp16); diff --git a/onnxruntime/core/providers/cpu/math/element_wise_ops.cc b/onnxruntime/core/providers/cpu/math/element_wise_ops.cc index d5220d991df6f..3192c8573c5c0 100644 --- a/onnxruntime/core/providers/cpu/math/element_wise_ops.cc +++ b/onnxruntime/core/providers/cpu/math/element_wise_ops.cc @@ -336,11 +336,18 @@ REG_ELEMENTWISE_LOGICALOP_VERSIONED_TYPED_KERNEL(Equal, 11, 12, int32_t, Equal); REG_ELEMENTWISE_LOGICALOP_VERSIONED_TYPED_KERNEL(Equal, 11, 12, int64_t, Equal); REG_ELEMENTWISE_LOGICALOP_VERSIONED_TYPED_KERNEL(Equal, 11, 12, float, Equal); REG_ELEMENTWISE_LOGICALOP_VERSIONED_TYPED_KERNEL(Equal, 11, 12, double, Equal); -REG_ELEMENTWISE_LOGICALOP_TYPED_KERNEL(Equal, 13, bool, Equal); -REG_ELEMENTWISE_LOGICALOP_TYPED_KERNEL(Equal, 13, int32_t, Equal); -REG_ELEMENTWISE_LOGICALOP_TYPED_KERNEL(Equal, 13, int64_t, Equal); -REG_ELEMENTWISE_LOGICALOP_TYPED_KERNEL(Equal, 13, float, Equal); -REG_ELEMENTWISE_LOGICALOP_TYPED_KERNEL(Equal, 13, double, Equal); +REG_ELEMENTWISE_LOGICALOP_VERSIONED_TYPED_KERNEL(Equal, 13, 18, bool, Equal); +REG_ELEMENTWISE_LOGICALOP_VERSIONED_TYPED_KERNEL(Equal, 13, 18, int32_t, Equal); +REG_ELEMENTWISE_LOGICALOP_VERSIONED_TYPED_KERNEL(Equal, 13, 18, int64_t, Equal); +REG_ELEMENTWISE_LOGICALOP_VERSIONED_TYPED_KERNEL(Equal, 13, 18, float, Equal); +REG_ELEMENTWISE_LOGICALOP_VERSIONED_TYPED_KERNEL(Equal, 13, 18, double, Equal); +REG_ELEMENTWISE_LOGICALOP_TYPED_KERNEL(Equal, 19, bool, Equal); +REG_ELEMENTWISE_LOGICALOP_TYPED_KERNEL(Equal, 19, int32_t, Equal); +REG_ELEMENTWISE_LOGICALOP_TYPED_KERNEL(Equal, 19, int64_t, Equal); +REG_ELEMENTWISE_LOGICALOP_TYPED_KERNEL(Equal, 19, float, Equal); +REG_ELEMENTWISE_LOGICALOP_TYPED_KERNEL(Equal, 19, double, Equal); +using string = std::string; +REG_ELEMENTWISE_LOGICALOP_TYPED_KERNEL(Equal, 19, string, Equal); REG_ELEMENTWISE_LOGICALOP_VERSIONED_TYPED_KERNEL(LessOrEqual, 12, 15, float, LessOrEqual); REG_ELEMENTWISE_LOGICALOP_VERSIONED_TYPED_KERNEL(LessOrEqual, 12, 15, double, LessOrEqual); @@ -848,7 +855,12 @@ struct Max_8::ComputeImpl { }}; int input_count = inst.Node().InputArgCount().front(); - UntypedBroadcastVariadic(input_count, *context, typed_allocator, funcs); + // TODO: Parallelize across spans in UntypedBroadcastVariadic to avoid specific logic here + if (input_count == 2) { + UntypedBroadcastTwo(*context, funcs, 1.0); + } else { + UntypedBroadcastVariadic(input_count, *context, typed_allocator, funcs); + } return Status::OK(); } @@ -1842,7 +1854,7 @@ void BroadCastMLFloat16FMod(OpKernelContext* context) { std::transform(Y.begin(), Y.end(), output.begin(), [X_fl = math::halfToFloat(X.val)](const MLFloat16& y) { - return MLFloat16(math::floatToHalf(std::fmod(X_fl, math::halfToFloat(y.val)))); + return MLFloat16(std::fmod(X_fl, y.ToFloat())); }); }, [](BroadcastHelper& per_iter_bh) { @@ -1852,7 +1864,7 @@ void BroadCastMLFloat16FMod(OpKernelContext* context) { std::transform(X.begin(), X.end(), output.begin(), [Y_fl = math::halfToFloat(Y.val)](const MLFloat16& x) { - return MLFloat16(math::floatToHalf(std::fmod(math::halfToFloat(x.val), Y_fl))); + return MLFloat16(std::fmod(x.ToFloat(), Y_fl)); }); }, [](BroadcastHelper& per_iter_bh) { @@ -1862,9 +1874,9 @@ void BroadCastMLFloat16FMod(OpKernelContext* context) { std::transform(X.begin(), X.end(), Y.begin(), output.begin(), [](const MLFloat16& x, const MLFloat16& y) { - auto x_fl = math::halfToFloat(x.val); - auto y_fl = math::halfToFloat(y.val); - return MLFloat16(math::floatToHalf(std::fmod(x_fl, y_fl))); + auto x_fl = x.ToFloat(); + auto y_fl = y.ToFloat(); + return MLFloat16(std::fmod(x_fl, y_fl)); }); }}; diff --git a/onnxruntime/core/providers/cpu/math/gemm.cc b/onnxruntime/core/providers/cpu/math/gemm.cc index 6ad58031dbe83..5a886cce9d5d0 100644 --- a/onnxruntime/core/providers/cpu/math/gemm.cc +++ b/onnxruntime/core/providers/cpu/math/gemm.cc @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#include #include "core/providers/cpu/math/gemm.h" #include "core/common/narrow.h" #include "core/common/safeint.h" @@ -25,6 +26,13 @@ ONNX_CPU_OPERATOR_VERSIONED_TYPED_KERNEL( double, KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()), Gemm); +ONNX_CPU_OPERATOR_VERSIONED_TYPED_KERNEL( + Gemm, + 7, + 8, + MLFloat16, + KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()), + Gemm); // opset 9 added support for additional types (int32, uint32, int64, uint64), however we haven't enabled those yet. ONNX_CPU_OPERATOR_VERSIONED_TYPED_KERNEL( @@ -41,6 +49,13 @@ ONNX_CPU_OPERATOR_VERSIONED_TYPED_KERNEL( double, KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()), Gemm); +ONNX_CPU_OPERATOR_VERSIONED_TYPED_KERNEL( + Gemm, + 9, + 10, + MLFloat16, + KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()), + Gemm); // opset 11 made bias input 'C' optional ONNX_CPU_OPERATOR_VERSIONED_TYPED_KERNEL( @@ -57,6 +72,13 @@ ONNX_CPU_OPERATOR_VERSIONED_TYPED_KERNEL( double, KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()), Gemm); +ONNX_CPU_OPERATOR_VERSIONED_TYPED_KERNEL( + Gemm, + 11, + 12, + MLFloat16, + KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()), + Gemm); // opset 13 Adds BFloat16 support but we are not supporting it yet ONNX_CPU_OPERATOR_TYPED_KERNEL( @@ -71,11 +93,17 @@ ONNX_CPU_OPERATOR_TYPED_KERNEL( double, KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()), Gemm); +ONNX_CPU_OPERATOR_TYPED_KERNEL( + Gemm, + 13, + MLFloat16, + KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()), + Gemm); bool GemmPackBFp32(AllocatorPtr& alloc, const Tensor& tensor_b, bool trans_b, - BufferUniquePtr& packed_b, + IAllocatorUniquePtr& packed_b, size_t& packed_b_size, TensorShape& b_shape) { // Only handle the common case of a 2D weight matrix. Additional matrices @@ -93,14 +121,14 @@ bool GemmPackBFp32(AllocatorPtr& alloc, return false; } - auto* packed_b_data = alloc->Alloc(packed_b_size); + packed_b = IAllocator::MakeUniquePtr(alloc, packed_b_size, true); + auto* packed_b_data = packed_b.get(); // Initialize memory to 0 as there could be some padding associated with pre-packed // buffer memory and we don not want it uninitialized and generate different hashes // if and when we try to cache this pre-packed buffer for sharing between sessions. memset(packed_b_data, 0, packed_b_size); - packed_b = BufferUniquePtr(packed_b_data, BufferDeleter(alloc)); MlasGemmPackB(trans_b ? CblasTrans : CblasNoTrans, N, K, @@ -112,10 +140,10 @@ bool GemmPackBFp32(AllocatorPtr& alloc, template void Gemm::ComputeGemm(CBLAS_TRANSPOSE trans_a, CBLAS_TRANSPOSE trans_b, - int64_t M, int64_t N, int64_t K, - float alpha, + ptrdiff_t M, ptrdiff_t N, ptrdiff_t K, + T alpha, const T* a_data, const T* b_data, - float beta, + T beta, const T* c_data, const TensorShape* c_shape, T* y_data, concurrency::ThreadPool* thread_pool) { @@ -127,7 +155,7 @@ void Gemm::ComputeGemm(CBLAS_TRANSPOSE trans_a, CBLAS_TRANSPOSE trans_b, GemmBroadcastBias(M, N, beta, c_data, c_shape, y_data); math::Gemm(trans_a, trans_b, - narrow(M), narrow(N), narrow(K), + M, N, K, alpha, a_data, b_data, @@ -138,8 +166,69 @@ void Gemm::ComputeGemm(CBLAS_TRANSPOSE trans_a, CBLAS_TRANSPOSE trans_b, thread_pool); } +template <> +void Gemm::ComputeGemm(CBLAS_TRANSPOSE trans_a, CBLAS_TRANSPOSE trans_b, + ptrdiff_t M, ptrdiff_t N, ptrdiff_t K, + MLFloat16 alpha, + const MLFloat16* a_data, const MLFloat16* b_data, + MLFloat16 beta, + const MLFloat16* c_data, const TensorShape* c_shape, + MLFloat16* y_data, + concurrency::ThreadPool* thread_pool) { + // if input is empty tensor, return directly as nothing need to be calculated. + if (M == 0 || N == 0) + return; + +#if defined(__GNUC__) && defined(HAS_CLASS_MEMACCESS) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wclass-memaccess" +#endif + // MLFloat16's constructor is explicit, so here we need to use memset + if (c_data == nullptr) + memset(&beta, 0, sizeof(MLFloat16)); +#if defined(__GNUC__) && defined(HAS_CLASS_MEMACCESS) +#pragma GCC diagnostic pop +#endif +#ifdef MLAS_F16VEC_INTRINSICS_SUPPORTED + bool support_mlas = false; + if (c_shape == nullptr) { + support_mlas = true; + } else if (c_shape->NumDimensions() == 1 && (*c_shape)[0] == N) { + support_mlas = true; + } else if (c_shape->NumDimensions() == 2 && (((*c_shape)[0] == 1 && (*c_shape)[1] == N) || ((*c_shape)[0] == N && (*c_shape)[1] == 1))) { + support_mlas = true; + } + if (trans_a == CblasNoTrans && trans_b == CblasNoTrans && support_mlas && alpha.ToFloat() == 1.0 && beta.ToFloat() == 1.0) { + MLAS_HALF_GEMM_DATA_PARAMS data; + data.A = a_data; + data.lda = K; + data.B = b_data; + data.ldb = N; + data.C = y_data; + data.ldc = N; + if (c_shape != nullptr) { + data.Bias = c_data; + } + MlasHalfGemmBatch(M, N, K, 1, &data, thread_pool); + return; + } +#endif + // Fallback to Eigen + // Broadcast the bias as needed if bias is given + GemmBroadcastBias(M, N, beta, c_data, c_shape, y_data); +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif + math::Gemm(trans_a, trans_b, M, N, K, *reinterpret_cast(&alpha), + reinterpret_cast(a_data), reinterpret_cast(b_data), *reinterpret_cast(&beta), reinterpret_cast(y_data), thread_pool); +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +} + template void Gemm::ComputeGemm(CBLAS_TRANSPOSE trans_a, CBLAS_TRANSPOSE trans_b, - int64_t M, int64_t N, int64_t K, + ptrdiff_t M, ptrdiff_t N, ptrdiff_t K, float alpha, const float* a_data, const float* b_data, float beta, @@ -196,16 +285,15 @@ Status Gemm::UseSharedPrePackedBuffers(std::vector& prep } template -void Gemm::ComputeActivation(T* y_data, size_t y_size, concurrency::ThreadPool* thread_pool) const { +void Gemm::ComputeActivation(_Inout_updates_(y_size) T* y_data, ptrdiff_t y_size, _Inout_opt_ concurrency::ThreadPool* thread_pool) const { if (activation_) { std::unique_ptr> f(activation_->Copy()); f->input = y_data; f->output = y_data; - std::ptrdiff_t total_len = static_cast(y_size); double cost = f->Cost(); functors::ElementWiseRangedTransform* c(f.get()); concurrency::ThreadPool::TryParallelFor( - thread_pool, total_len, + thread_pool, y_size, {static_cast(sizeof(T)), static_cast(sizeof(T)), cost}, [c](std::ptrdiff_t first, std::ptrdiff_t last) { (*c)(first, last); }); } @@ -226,9 +314,9 @@ Status Gemm::Compute(OpKernelContext* context) const { if (!helper.State().IsOK()) return helper.State(); - int64_t M = helper.M(); - int64_t N = helper.N(); - int64_t K = helper.K(); + ptrdiff_t M = helper.M(); + ptrdiff_t N = helper.N(); + ptrdiff_t K = helper.K(); auto Y = context->Output(0, {M, N}); @@ -243,6 +331,48 @@ Status Gemm::Compute(OpKernelContext* context) const { ComputeGemm(trans_A_, trans_B_, M, N, K, alpha_, A->Data(), B->Data(), beta_, c_data, c_shape, y_data, thread_pool); + ComputeActivation(y_data, SafeInt(M) * N, thread_pool); + + return Status::OK(); +} + +template <> +Status Gemm::Compute(OpKernelContext* context) const { + concurrency::ThreadPool* thread_pool = context->GetOperatorThreadPool(); + + const auto* A = context->Input(0); + const auto* B = packed_b_ ? nullptr : context->Input(1); + const auto* C = context->Input(2); + + // Bias could be missing. Treat as scalar 0 if that is the case. + GemmHelper helper(A->Shape(), trans_A_ != CblasNoTrans, B ? B->Shape() : b_shape_, trans_B_ != CblasNoTrans, + C != nullptr ? C->Shape() : TensorShape({})); + + if (!helper.State().IsOK()) + return helper.State(); + + ptrdiff_t M = helper.M(); + ptrdiff_t N = helper.N(); + ptrdiff_t K = helper.K(); + + auto Y = context->Output(0, {M, N}); + + // if input is empty tensor, return as nothing need to be calculated and we've set the shape for the output + if (M == 0 || N == 0) + return Status::OK(); + + MLFloat16* y_data = Y->MutableData(); + + const MLFloat16* c_data = C != nullptr ? C->Data() : nullptr; + const TensorShape* c_shape = C != nullptr ? &C->Shape() : nullptr; + + if (B) { + ComputeGemm(trans_A_, trans_B_, M, N, K, static_cast(alpha_), A->Data(), B->Data(), static_cast(beta_), + c_data, c_shape, y_data, thread_pool); + } else { + ORT_NOT_IMPLEMENTED("Prepacking of B is supported by MLAS half gemm API, but not implemented by this kernel yet"); + } + ComputeActivation(y_data, SafeInt(M) * N, thread_pool); return Status::OK(); @@ -263,9 +393,9 @@ Status Gemm::Compute(OpKernelContext* context) const { if (!helper.State().IsOK()) return helper.State(); - int64_t M = helper.M(); - int64_t N = helper.N(); - int64_t K = helper.K(); + ptrdiff_t M = helper.M(); + ptrdiff_t N = helper.N(); + ptrdiff_t K = helper.K(); auto Y = context->Output(0, {M, N}); diff --git a/onnxruntime/core/providers/cpu/math/gemm.h b/onnxruntime/core/providers/cpu/math/gemm.h index b8cac2f15af95..953949732560d 100644 --- a/onnxruntime/core/providers/cpu/math/gemm.h +++ b/onnxruntime/core/providers/cpu/math/gemm.h @@ -29,22 +29,22 @@ class Gemm : protected GemmBase, public OpKernel { /*out*/ bool& used_shared_buffers) override; static void ComputeGemm(CBLAS_TRANSPOSE trans_a, CBLAS_TRANSPOSE trans_b, - int64_t M, int64_t N, int64_t K, - float alpha, + ptrdiff_t M, ptrdiff_t N, ptrdiff_t K, + T alpha, const T* a_data, const T* b_data, - float beta, + T beta, const T* c_data, const TensorShape* c_shape, T* y_data, concurrency::ThreadPool* thread_pool); protected: TensorShape b_shape_; - BufferUniquePtr packed_b_; + IAllocatorUniquePtr packed_b_; // For fused gemm + activation std::unique_ptr> activation_; - void ComputeActivation(T* y_data, size_t y_size, concurrency::ThreadPool* thread_pool) const; + void ComputeActivation(_Inout_updates_(y_size) T* y_data, ptrdiff_t y_size, _Inout_opt_ concurrency::ThreadPool* thread_pool) const; }; } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cpu/math/gemm_helper.h b/onnxruntime/core/providers/cpu/math/gemm_helper.h index ef3d983fba9b3..f37b00ac2c16d 100644 --- a/onnxruntime/core/providers/cpu/math/gemm_helper.h +++ b/onnxruntime/core/providers/cpu/math/gemm_helper.h @@ -3,7 +3,10 @@ #pragma once #include "core/common/common.h" +#include "core/common/narrow.h" #include "core/util/math_cpuonly.h" +#include "core/framework/tensor_shape.h" +#include "core/session/onnxruntime_c_api.h" namespace onnxruntime { @@ -14,20 +17,31 @@ class GemmHelper { ORT_ENFORCE(left.NumDimensions() == 2 || left.NumDimensions() == 1); ORT_ENFORCE(right.NumDimensions() == 2); + for (size_t i = 0; i != left.NumDimensions(); ++i) { + ORT_ENFORCE(left[i] >= 0); + ORT_ENFORCE(left[i] <= std::numeric_limits::max()); + } + + for (size_t i = 0; i != right.NumDimensions(); ++i) { + ORT_ENFORCE(right[i] >= 0); + ORT_ENFORCE(right[i] <= std::numeric_limits::max()); + } + if (trans_left) { - M_ = left.NumDimensions() == 2 ? left[1] : left[0]; - K_ = left.NumDimensions() == 2 ? left[0] : 1; + M_ = left.NumDimensions() == 2 ? static_cast(left[1]) : static_cast(left[0]); + K_ = left.NumDimensions() == 2 ? static_cast(left[0]) : 1; } else { - M_ = left.NumDimensions() == 2 ? left[0] : 1; - K_ = left.NumDimensions() == 2 ? left[1] : left[0]; + M_ = left.NumDimensions() == 2 ? static_cast(left[0]) : 1; + K_ = left.NumDimensions() == 2 ? static_cast(left[1]) + : static_cast(left[0]); } int k_dim; if (trans_right) { - N_ = right[0]; + N_ = static_cast(right[0]); k_dim = 1; } else { - N_ = right[1]; + N_ = static_cast(right[1]); k_dim = 0; } @@ -45,13 +59,13 @@ class GemmHelper { ORT_ENFORCE(M_ >= 0 && K_ > 0 && N_ >= 0); } - int64_t M() const { return M_; } - int64_t N() const { return N_; } - int64_t K() const { return K_; } + ptrdiff_t M() const { return M_; } + ptrdiff_t N() const { return N_; } + ptrdiff_t K() const { return K_; } Status State() const { return status_; } private: - bool IsValidBroadcast(const TensorShape& bias_shape, int64_t M, int64_t N) { + static bool IsValidBroadcast(const TensorShape& bias_shape, ptrdiff_t M, ptrdiff_t N) { // valid shapes are (,) , (1, N) , (M, 1) , (M, N) if (bias_shape.NumDimensions() > 2) return false; @@ -66,32 +80,33 @@ class GemmHelper { } private: - int64_t M_; - int64_t K_; - int64_t N_; + GemmHelper() = default; + ptrdiff_t M_; + ptrdiff_t K_; + ptrdiff_t N_; Status status_; }; template -void GemmBroadcastBias(int64_t M, int64_t N, float beta, - const T* c_data, const TensorShape* c_shape, - T* y_data) { +void GemmBroadcastBias(ptrdiff_t M, ptrdiff_t N, T beta, + _In_opt_ const T* c_data, _In_opt_ const TensorShape* c_shape, + _Out_writes_(M* N) T* y_data) { // Broadcast the bias as needed if bias is given if (beta != 0 && c_data != nullptr) { ORT_ENFORCE(c_shape != nullptr, "c_shape is required if c_data is provided"); - auto output_mat = EigenMatrixMapRowMajor(y_data, onnxruntime::narrow(M), onnxruntime::narrow(N)); + auto output_mat = EigenMatrixMapRowMajor(y_data, M, N); if (c_shape->Size() == 1) { // C is (), (1,) or (1, 1), set the scalar output_mat.setConstant(*c_data); } else if (c_shape->NumDimensions() == 1 || (*c_shape)[0] == 1) { // C is (N,) or (1, N) - output_mat.rowwise() = ConstEigenVectorMap(c_data, onnxruntime::narrow(N)).transpose(); + output_mat.rowwise() = ConstEigenVectorMap(c_data, N).transpose(); } else if ((*c_shape)[1] == 1) { // C is (M, 1) - output_mat.colwise() = ConstEigenVectorMap(c_data, onnxruntime::narrow(M)); + output_mat.colwise() = ConstEigenVectorMap(c_data, M); } else { // C is (M, N), no broadcast needed. - output_mat = ConstEigenMatrixMapRowMajor(c_data, onnxruntime::narrow(M), onnxruntime::narrow(N)); + output_mat = ConstEigenMatrixMapRowMajor(c_data, M, N); } } } diff --git a/onnxruntime/core/providers/cpu/math/gemm_matmul_common.h b/onnxruntime/core/providers/cpu/math/gemm_matmul_common.h index 57d0e3d0d116d..599847e61a54f 100644 --- a/onnxruntime/core/providers/cpu/math/gemm_matmul_common.h +++ b/onnxruntime/core/providers/cpu/math/gemm_matmul_common.h @@ -10,7 +10,7 @@ namespace onnxruntime { bool GemmPackBFp32(AllocatorPtr& alloc, const Tensor& tensor_b, bool trans_b, - BufferUniquePtr& packed_b, + IAllocatorUniquePtr& packed_b, size_t& packed_b_size, TensorShape& b_shape); diff --git a/onnxruntime/core/providers/cpu/math/matmul.h b/onnxruntime/core/providers/cpu/math/matmul.h index 96e461673b393..b960fa4fb0587 100644 --- a/onnxruntime/core/providers/cpu/math/matmul.h +++ b/onnxruntime/core/providers/cpu/math/matmul.h @@ -40,7 +40,7 @@ class MatMul final : public OpKernel { private: TensorShape b_shape_; - BufferUniquePtr packed_b_; + IAllocatorUniquePtr packed_b_; // For FusedMatMul contrib ops float alpha_attr_; diff --git a/onnxruntime/core/providers/cpu/math/matmul_helper.h b/onnxruntime/core/providers/cpu/math/matmul_helper.h index 7c86f11b97a25..d7275ee324756 100644 --- a/onnxruntime/core/providers/cpu/math/matmul_helper.h +++ b/onnxruntime/core/providers/cpu/math/matmul_helper.h @@ -371,9 +371,24 @@ class MatMulComputeHelper { return right_zp_offsets_; } + static bool IsAligned(const std::vector& offsets) { + constexpr size_t alignment = 16; + const auto len = offsets.size(); + for (size_t i = 0; i < len; i++) { + if ((offsets[i] % alignment) != 0) { + return false; + } + } + return true; + } + + bool IsBatchedGemmAligned() const { + return IsAligned(left_offsets_) && IsAligned(right_offsets_) && IsAligned(output_offsets_); + } + template static void OffsetToArrays(T* p, const std::vector& offsets, gsl::span arrays) { - auto len = offsets.size(); + const auto len = offsets.size(); ORT_ENFORCE(arrays.size() == len); for (size_t i = 0; i < len; i++) { arrays[i] = p + offsets[i]; @@ -382,7 +397,7 @@ class MatMulComputeHelper { template static void OffsetToArrays(const T* p, const std::vector& offsets, gsl::span arrays) { - auto len = offsets.size(); + const auto len = offsets.size(); ORT_ENFORCE(arrays.size() == len); for (size_t i = 0; i < len; i++) { arrays[i] = p + offsets[i]; diff --git a/onnxruntime/core/providers/cpu/math/round.cc b/onnxruntime/core/providers/cpu/math/round.cc index bc604258459a9..86c2b91c10535 100644 --- a/onnxruntime/core/providers/cpu/math/round.cc +++ b/onnxruntime/core/providers/cpu/math/round.cc @@ -36,7 +36,7 @@ Status Round::Compute(OpKernelContext* ctx) const { auto* output = Y.MutableData(); const auto size = X.Shape().Size(); for (int64_t i = 0; i < size; ++i, ++output, ++input) { - *output = MLFloat16(math::floatToHalf(::rint(math::halfToFloat(input->val)))); + *output = MLFloat16(static_cast(::rint(input->ToFloat()))); } return Status::OK(); } diff --git a/onnxruntime/core/providers/cpu/math/sign.cc b/onnxruntime/core/providers/cpu/math/sign.cc index d926dca4fd2a1..60080135bbd26 100644 --- a/onnxruntime/core/providers/cpu/math/sign.cc +++ b/onnxruntime/core/providers/cpu/math/sign.cc @@ -55,29 +55,15 @@ struct CallSignImpl { } }; -// The spec does not specify how NaN is -// treated but we have to treat it somehow. We choose -// to return 0 for NaN as TF does. -template -inline T FloatingImpl(T val) { - if (std::isnan(val) || val == T(0)) { - return T(0); - } - if (val > T(0)) { - return T(1); - } else { - return T(-1); - } -} - template <> struct CallSignImpl { void operator()(const Tensor* input, Tensor* output) const { - auto span = gsl::make_span(input->Data(), onnxruntime::narrow(input->Shape().Size())); + auto span = input->DataAsSpan(); auto output_data = output->MutableData(); std::transform(span.begin(), span.end(), output_data, [](const MLFloat16& val) { - float fl = math::halfToFloat(val.val); - return MLFloat16(math::floatToHalf(FloatingImpl(fl))); + // Return 0 as TF does for NaN. + if (val.IsNaNOrZero()) return MLFloat16::Zero; + return (val.IsNegative()) ? MLFloat16::MinusOne : MLFloat16::One; }); } }; @@ -85,11 +71,12 @@ struct CallSignImpl { template <> struct CallSignImpl { void operator()(const Tensor* input, Tensor* output) const { - auto span = gsl::make_span(input->Data(), onnxruntime::narrow(input->Shape().Size())); + auto span = input->DataAsSpan(); auto output_data = output->MutableData(); std::transform(span.begin(), span.end(), output_data, [](const BFloat16& val) { - float fl = val.ToFloat(); - return BFloat16(FloatingImpl(fl)); + // Return 0 as TF does for NaN. + if (val.IsNaNOrZero()) return BFloat16::Zero; + return (val.IsNegative()) ? BFloat16::MinusOne : BFloat16::One; }); } }; diff --git a/onnxruntime/core/providers/cpu/ml/label_encoder.h b/onnxruntime/core/providers/cpu/ml/label_encoder.h index b7e7f9e7e32f3..a935fd64d5da4 100644 --- a/onnxruntime/core/providers/cpu/ml/label_encoder.h +++ b/onnxruntime/core/providers/cpu/ml/label_encoder.h @@ -63,9 +63,9 @@ class LabelEncoder_2 final : public OpKernel { "(name: ", info.node().Name(), ") must have the same length. ", "However, the number of key is ", num_keys, " and the number of ", "values is ", num_values, "."); - + _map.reserve(num_keys); for (size_t i = 0; i < num_keys; ++i) - _map[keys[i]] = values[i]; + _map.emplace(keys[i], values[i]); } Status Compute(OpKernelContext* context) const override { @@ -98,7 +98,7 @@ class LabelEncoder_2 final : public OpKernel { // A collection of key-value pairs. Each (a_key, a_value) pair // means that the "a_key" in the input would be mapped to "a_value". // If _map doesn't contain "a_key", we use _default_value as its output. - std::unordered_map _map; + InlinedHashMap _map; TValue _default_value; // ONNX attribute name to load keys. std::string _key_field_name; diff --git a/onnxruntime/core/providers/cpu/ml/linearclassifier.cc b/onnxruntime/core/providers/cpu/ml/linearclassifier.cc index 02332281ee033..943e91134130c 100644 --- a/onnxruntime/core/providers/cpu/ml/linearclassifier.cc +++ b/onnxruntime/core/providers/cpu/ml/linearclassifier.cc @@ -2,6 +2,7 @@ // Licensed under the MIT License. #include "core/providers/cpu/ml/linearclassifier.h" +#include "core/common/narrow.h" #include "core/providers/cpu/math/gemm.h" namespace onnxruntime { @@ -34,7 +35,7 @@ LinearClassifier::LinearClassifier(const OpKernelInfo& info) ORT_ENFORCE(!coefficients_.empty()); using_strings_ = !classlabels_strings_.empty(); - class_count_ = static_cast(intercepts_.size()); + class_count_ = static_cast(intercepts_.size()); } // Use GEMM for the calculations, with broadcasting of intercepts @@ -45,7 +46,7 @@ LinearClassifier::LinearClassifier(const OpKernelInfo& info) // intercepts_: [num_targets] // scores: X * coefficients_^T + intercepts_: [num_batches, num_targets] void LinearClassifier::ComputeImpl(const gsl::span input, - int64_t num_batches, int64_t num_features, int64_t num_targets, + ptrdiff_t num_batches, ptrdiff_t num_features, ptrdiff_t num_targets, const std::vector& coefficients, const std::vector& intercepts, Tensor& labels_output, Tensor& scores_output, @@ -139,8 +140,10 @@ Status LinearClassifier::Compute(OpKernelContext* ctx) const { "Input shape needs to be at least a single dimension."); } - int64_t num_batches = input_shape.NumDimensions() == 1 ? 1 : input_shape[0]; - int64_t num_features = input_shape.NumDimensions() == 1 ? input_shape[0] : input_shape[1]; + ptrdiff_t num_batches = input_shape.NumDimensions() == 1 ? 1 : narrow(input_shape[0]); + ptrdiff_t num_features = input_shape.NumDimensions() == 1 ? narrow( + input_shape[0]) + : narrow(input_shape[1]); Tensor* Y = ctx->Output(0, {num_batches}); diff --git a/onnxruntime/core/providers/cpu/ml/linearclassifier.h b/onnxruntime/core/providers/cpu/ml/linearclassifier.h index 012e1cec91d82..e5f88dcb6b6d5 100644 --- a/onnxruntime/core/providers/cpu/ml/linearclassifier.h +++ b/onnxruntime/core/providers/cpu/ml/linearclassifier.h @@ -17,7 +17,7 @@ class LinearClassifier final : public OpKernel { Status Compute(OpKernelContext* context) const override; private: - void ComputeImpl(const gsl::span input, int64_t num_batches, int64_t num_features, int64_t num_targets, + void ComputeImpl(const gsl::span input, ptrdiff_t num_batches, ptrdiff_t num_features, ptrdiff_t num_targets, const std::vector& coefficients, const std::vector& intercepts, Tensor& labels_output, @@ -27,7 +27,7 @@ class LinearClassifier final : public OpKernel { concurrency::ThreadPool* threadpool) const; int64_t multi_class_; - int64_t class_count_; + ptrdiff_t class_count_; POST_EVAL_TRANSFORM post_transform_; bool using_strings_; std::vector coefficients_; diff --git a/onnxruntime/core/providers/cpu/ml/linearregressor.cc b/onnxruntime/core/providers/cpu/ml/linearregressor.cc index a5dcdfbed88bc..6ed5545e7063f 100644 --- a/onnxruntime/core/providers/cpu/ml/linearregressor.cc +++ b/onnxruntime/core/providers/cpu/ml/linearregressor.cc @@ -2,6 +2,7 @@ // Licensed under the MIT License. #include "core/providers/cpu/ml/linearregressor.h" +#include "core/common/narrow.h" #include "core/providers/cpu/math/gemm.h" namespace onnxruntime { @@ -35,7 +36,7 @@ LinearRegressor::LinearRegressor(const OpKernelInfo& info) // intercepts_: optional [num_targets]. // Output: X * coefficients_^T + intercepts_: [num_batches, num_targets] template -static Status ComputeImpl(const Tensor& input, int64_t num_batches, int64_t num_features, int64_t num_targets, +static Status ComputeImpl(const Tensor& input, ptrdiff_t num_batches, ptrdiff_t num_features, ptrdiff_t num_targets, const std::vector& coefficients, const std::vector* intercepts, Tensor& output, POST_EVAL_TRANSFORM post_transform, @@ -79,8 +80,9 @@ Status LinearRegressor::Compute(OpKernelContext* ctx) const { input_shape.NumDimensions()); } - int64_t num_batches = input_shape.NumDimensions() <= 1 ? 1 : input_shape[0]; - int64_t num_features = input_shape.NumDimensions() <= 1 ? input_shape.Size() : input_shape[1]; + ptrdiff_t num_batches = input_shape.NumDimensions() <= 1 ? 1 : narrow(input_shape[0]); + ptrdiff_t num_features = input_shape.NumDimensions() <= 1 ? narrow(input_shape.Size()) + : narrow(input_shape[1]); Tensor& Y = *ctx->Output(0, {num_batches, num_targets_}); concurrency::ThreadPool* tp = ctx->GetOperatorThreadPool(); @@ -88,7 +90,7 @@ Status LinearRegressor::Compute(OpKernelContext* ctx) const { switch (element_type) { case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: { - status = ComputeImpl(X, num_batches, num_features, num_targets_, coefficients_, + status = ComputeImpl(X, num_batches, num_features, narrow(num_targets_), coefficients_, use_intercepts_ ? &intercepts_ : nullptr, Y, post_transform_, tp); diff --git a/onnxruntime/core/providers/cpu/ml/ml_common.h b/onnxruntime/core/providers/cpu/ml/ml_common.h index 94895978869ae..ed108eade05ab 100644 --- a/onnxruntime/core/providers/cpu/ml/ml_common.h +++ b/onnxruntime/core/providers/cpu/ml/ml_common.h @@ -178,7 +178,7 @@ static inline float ErfInv(float x) { float sgn = x < 0 ? -1.0f : 1.0f; x = (1 - x) * (1 + x); float log = std::log(x); - float v = 2 / (3.14159f * 0.147f) + 0.5f * log; + float v = 2 / (static_cast(M_PI) * 0.147f) + 0.5f * log; float v2 = 1 / (0.147f) * log; float v3 = -v + std::sqrt(v * v - v2); x = sgn * std::sqrt(v3); @@ -244,7 +244,7 @@ static inline void multiclass_probability(int64_t classcount, } } -static constexpr float ml_sqrt2 = 1.41421356f; +static constexpr float ml_sqrt2 = static_cast(M_SQRT2); static inline float ComputeLogistic(float val) { float v = 1 / (1 + std::exp(-std::abs(val))); diff --git a/onnxruntime/core/providers/cpu/ml/svmclassifier.cc b/onnxruntime/core/providers/cpu/ml/svmclassifier.cc index a9a3f9915278f..8c356b4c62023 100644 --- a/onnxruntime/core/providers/cpu/ml/svmclassifier.cc +++ b/onnxruntime/core/providers/cpu/ml/svmclassifier.cc @@ -47,7 +47,7 @@ SVMClassifier::SVMClassifier(const OpKernelInfo& info) class_count_ = 0; for (size_t i = 0; i < vectors_per_class_.size(); i++) { starting_vector_.push_back(vector_count_); - vector_count_ += vectors_per_class_[i]; + vector_count_ += narrow(vectors_per_class_[i]); } using_strings_ = false; diff --git a/onnxruntime/core/providers/cpu/ml/svmclassifier.h b/onnxruntime/core/providers/cpu/ml/svmclassifier.h index b24a06fc2c035..e2ba20e08e30e 100644 --- a/onnxruntime/core/providers/cpu/ml/svmclassifier.h +++ b/onnxruntime/core/providers/cpu/ml/svmclassifier.h @@ -32,7 +32,7 @@ class SVMCommon { template void batched_kernel_dot(const gsl::span a, const gsl::span b, - int64_t m, int64_t n, int64_t k, + ptrdiff_t m, ptrdiff_t n, ptrdiff_t k, float scalar_C, const gsl::span out, concurrency::ThreadPool* threadpool) const { @@ -115,9 +115,9 @@ class SVMClassifier final : public OpKernel, private SVMCommon { Status ComputeImpl(OpKernelContext& ctx, gsl::span x_data, const TensorShape& x_shape) const; bool weights_are_all_positive_; - int64_t feature_count_; - int64_t class_count_; - int64_t vector_count_; + ptrdiff_t feature_count_; + ptrdiff_t class_count_; + ptrdiff_t vector_count_; bool using_strings_; std::vector vectors_per_class_; std::vector starting_vector_; diff --git a/onnxruntime/core/providers/cpu/ml/svmregressor.cc b/onnxruntime/core/providers/cpu/ml/svmregressor.cc index 496589b08f10b..68367470a6176 100644 --- a/onnxruntime/core/providers/cpu/ml/svmregressor.cc +++ b/onnxruntime/core/providers/cpu/ml/svmregressor.cc @@ -16,9 +16,11 @@ template SVMRegressor::SVMRegressor(const OpKernelInfo& info) : OpKernel(info), SVMCommon(info), - vector_count_(info.GetAttrOrDefault("n_supports", 0)), support_vectors_(info.GetAttrsOrDefault("support_vectors")), post_transform_(MakeTransform(info.GetAttrOrDefault("post_transform", "NONE"))) { + int64_t vector_count = 0; + ORT_ENFORCE(info.GetAttr("n_supports", &vector_count).IsOK()); + vector_count_ = narrow(vector_count); ORT_ENFORCE(info.GetAttrs("rho", rho_).IsOK()); ORT_ENFORCE(info.GetAttrs("coefficients", coefficients_).IsOK()); ORT_ENFORCE(!coefficients_.empty()); @@ -40,9 +42,9 @@ template Status SVMRegressor::Compute(OpKernelContext* ctx) const { const auto* X = ctx->Input(0); - int64_t num_features = X->Shape().NumDimensions() == 1 ? X->Shape()[0] : X->Shape()[1]; - int64_t num_batches = X->Shape().NumDimensions() == 1 ? 1 : X->Shape()[0]; - ORT_ENFORCE(num_features == feature_count_); + ptrdiff_t num_features = X->Shape().NumDimensions() == 1 ? narrow(X->Shape()[0]) : narrow(X->Shape()[1]); + ptrdiff_t num_batches = X->Shape().NumDimensions() == 1 ? 1 : narrow(X->Shape()[0]); + ORT_RETURN_IF_NOT(num_features == feature_count_ && num_features >= 0 && num_batches >= 0, "Invalid argument"); // X: [num_batches, feature_count_] where features could be coefficients or support vectors // coefficients_: [vector_count_] diff --git a/onnxruntime/core/providers/cpu/ml/svmregressor.h b/onnxruntime/core/providers/cpu/ml/svmregressor.h index bf436238846a4..0e72ba5db6d4d 100644 --- a/onnxruntime/core/providers/cpu/ml/svmregressor.h +++ b/onnxruntime/core/providers/cpu/ml/svmregressor.h @@ -24,8 +24,8 @@ class SVMRegressor final : public OpKernel, private SVMCommon { private: bool one_class_; - int64_t feature_count_; - int64_t vector_count_; + ptrdiff_t feature_count_; + ptrdiff_t vector_count_; std::vector rho_; std::vector coefficients_; std::vector support_vectors_; diff --git a/onnxruntime/core/providers/cpu/ml/tree_ensemble_aggregator.h b/onnxruntime/core/providers/cpu/ml/tree_ensemble_aggregator.h index 2960724f2f81f..b9f3050e59c5b 100644 --- a/onnxruntime/core/providers/cpu/ml/tree_ensemble_aggregator.h +++ b/onnxruntime/core/providers/cpu/ml/tree_ensemble_aggregator.h @@ -23,9 +23,7 @@ struct TreeNodeElementId { } struct hash_fn { std::size_t operator()(const TreeNodeElementId& key) const { - std::size_t h1 = std::hash()(key.tree_id); - std::size_t h2 = std::hash()(key.node_id); - return h1 ^ h2; + return static_cast(static_cast(key.tree_id) << 32 | static_cast(key.node_id)); } }; }; @@ -66,6 +64,18 @@ enum MissingTrack : uint8_t { kFalse = 0 }; +template +struct TreeNodeElement; + +template +union PtrOrWeight { + TreeNodeElement* ptr; + struct WeightData { + int32_t weight; + int32_t n_weights; + } weight_data; +}; + template struct TreeNodeElement { int feature_id; @@ -73,24 +83,19 @@ struct TreeNodeElement { // Stores the node threshold or the weights if the tree has one target. T value_or_unique_weight; - // onnx specification says hitrates is used to store information about the node, + // The onnx specification says hitrates is used to store information about the node, // but this information is not used for inference. // T hitrates; - // True node, false node are obtained by computing `this + truenode_inc_or_first_weight`, - // `this + falsenode_inc_or_n_weights` if the node is not a leaf. - // In case of a leaf, these attributes are used to indicate the position of the weight - // in array `TreeEnsembleCommon::weights_`. If the number of targets or classes is one, - // the weight is also stored in `value_or_unique_weight`. - // This implementation assumes a tree has less than 2^31 nodes, - // and the total number of leave in the set of trees is below 2^31. - // A node cannot point to itself. - int32_t truenode_inc_or_first_weight; - // In case of a leaf, the following attribute indicates the number of weights - // in array `TreeEnsembleCommon::weights_`. If not a leaf, it indicates - // `this + falsenode_inc_or_n_weights` is the false node. - // A node cannot point to itself. - int32_t falsenode_inc_or_n_weights; + // PtrOrWeight acts as a tagged union, with the "tag" being whether the node is a leaf or not (see `is_not_leaf`). + + // If it is not a leaf, it is a pointer to the true child node when traversing the decision tree. The false branch is + // always 1 position away from the TreeNodeElement in practice in `TreeEnsembleCommon::nodes_` so it is not stored. + + // If it is a leaf, it contains `weight` and `n_weights` attributes which are used to indicate the position of the + // weight in array `TreeEnsembleCommon::weights_`. If the number of targets or classes is one, the weight is also + // stored in `value_or_unique_weight`. + PtrOrWeight truenode_or_weight; uint8_t flags; inline NODE_MODE mode() const { return NODE_MODE(flags & 0xF); } @@ -191,8 +196,8 @@ class TreeAggregatorSum : public TreeAggregator>& predictions, const TreeNodeElement& root, gsl::span> weights) const { - auto it = weights.begin() + root.truenode_inc_or_first_weight; - for (int32_t i = 0; i < root.falsenode_inc_or_n_weights; ++i, ++it) { + auto it = weights.begin() + root.truenode_or_weight.weight_data.weight; + for (int32_t i = 0; i < root.truenode_or_weight.weight_data.n_weights; ++i, ++it) { ORT_ENFORCE(it->i < (int64_t)predictions.size()); predictions[onnxruntime::narrow(it->i)].score += it->value; predictions[onnxruntime::narrow(it->i)].has_score = 1; @@ -294,8 +299,8 @@ class TreeAggregatorMin : public TreeAggregator>& predictions, const TreeNodeElement& root, gsl::span> weights) const { - auto it = weights.begin() + root.truenode_inc_or_first_weight; - for (int32_t i = 0; i < root.falsenode_inc_or_n_weights; ++i, ++it) { + auto it = weights.begin() + root.truenode_or_weight.weight_data.weight; + for (int32_t i = 0; i < root.truenode_or_weight.weight_data.n_weights; ++i, ++it) { predictions[onnxruntime::narrow(it->i)].score = (!predictions[onnxruntime::narrow(it->i)].has_score || it->value < predictions[onnxruntime::narrow(it->i)].score) ? it->value @@ -351,8 +356,8 @@ class TreeAggregatorMax : public TreeAggregator>& predictions, const TreeNodeElement& root, gsl::span> weights) const { - auto it = weights.begin() + root.truenode_inc_or_first_weight; - for (int32_t i = 0; i < root.falsenode_inc_or_n_weights; ++i, ++it) { + auto it = weights.begin() + root.truenode_or_weight.weight_data.weight; + for (int32_t i = 0; i < root.truenode_or_weight.weight_data.n_weights; ++i, ++it) { predictions[onnxruntime::narrow(it->i)].score = (!predictions[onnxruntime::narrow(it->i)].has_score || it->value > predictions[onnxruntime::narrow(it->i)].score) ? it->value diff --git a/onnxruntime/core/providers/cpu/ml/tree_ensemble_common.h b/onnxruntime/core/providers/cpu/ml/tree_ensemble_common.h index 161bb2b0820eb..8f847fe66aa73 100644 --- a/onnxruntime/core/providers/cpu/ml/tree_ensemble_common.h +++ b/onnxruntime/core/providers/cpu/ml/tree_ensemble_common.h @@ -85,6 +85,13 @@ class TreeEnsembleCommon : public TreeEnsembleCommonAttributes { template void ComputeAgg(concurrency::ThreadPool* ttp, const Tensor* X, Tensor* Y, Tensor* label, const AGG& agg) const; + + private: + size_t AddNodes(const size_t i, const InlinedVector& cmodes, const InlinedVector& truenode_ids, + const InlinedVector& falsenode_ids, const std::vector& nodes_featureids, + const std::vector& nodes_values_as_tensor, const std::vector& node_values, + const std::vector& nodes_missing_value_tracks_true, std::vector& updated_mapping, + int64_t tree_id, const InlinedVector& node_tree_ids); }; template @@ -186,7 +193,7 @@ Status TreeEnsembleCommon::Init( max_tree_depth_ = 1000; ORT_ENFORCE(nodes_modes.size() < std::numeric_limits::max()); - // additional members + // Additional members size_t limit; uint32_t i; InlinedVector cmodes; @@ -195,18 +202,14 @@ Status TreeEnsembleCommon::Init( int fpos = -1; for (i = 0, limit = nodes_modes.size(); i < limit; ++i) { cmodes.push_back(MakeTreeNodeMode(nodes_modes[i])); - if (cmodes[i] == NODE_MODE::LEAF) - continue; + if (cmodes[i] == NODE_MODE::LEAF) continue; if (fpos == -1) { fpos = static_cast(i); continue; } - if (cmodes[i] != cmodes[fpos]) - same_mode_ = false; + if (cmodes[i] != cmodes[fpos]) same_mode_ = false; } - // filling nodes - n_nodes_ = nodes_treeids.size(); limit = static_cast(n_nodes_); InlinedVector node_tree_ids; @@ -214,156 +217,185 @@ Status TreeEnsembleCommon::Init( nodes_.clear(); nodes_.reserve(limit); roots_.clear(); - std::unordered_map idi; - idi.reserve(limit); + std::unordered_map node_tree_ids_map; + node_tree_ids_map.reserve(limit); + + InlinedVector truenode_ids, falsenode_ids; + truenode_ids.reserve(limit); + falsenode_ids.reserve(limit); max_feature_id_ = 0; + // Build node_tree_ids and node_tree_ids_map and truenode_ids and falsenode_ids for (i = 0; i < limit; ++i) { - TreeNodeElementId node_tree_id{static_cast(nodes_treeids[i]), - static_cast(nodes_nodeids[i])}; - TreeNodeElement node; - node.feature_id = static_cast(nodes_featureids[i]); - if (node.feature_id > max_feature_id_) { - max_feature_id_ = node.feature_id; - } - node.value_or_unique_weight = nodes_values_as_tensor.empty() - ? static_cast(nodes_values[i]) - : nodes_values_as_tensor[i]; - - /* hitrates is not used for inference, they are ignored. - if (nodes_hitrates_as_tensor.empty()) { - node.hitrates = static_cast(i < nodes_hitrates.size() ? nodes_hitrates[i] : -1); - } else { - node.hitrates = i < nodes_hitrates_as_tensor.size() ? nodes_hitrates_as_tensor[i] : -1; - } */ - - node.flags = static_cast(cmodes[i]); - node.truenode_inc_or_first_weight = 0; // nodes_truenodeids[i] if not a leaf - node.falsenode_inc_or_n_weights = 0; // nodes_falsenodeids[i] if not a leaf - - if (i < static_cast(nodes_missing_value_tracks_true.size()) && nodes_missing_value_tracks_true[i] == 1) { - node.flags |= static_cast(MissingTrack::kTrue); - } - auto p = idi.insert(std::pair(node_tree_id, i)); + TreeNodeElementId node_tree_id{static_cast(nodes_treeids[i]), static_cast(nodes_nodeids[i])}; + auto p = node_tree_ids_map.insert(std::pair(node_tree_id, i)); if (!p.second) { ORT_THROW("Node ", node_tree_id.node_id, " in tree ", node_tree_id.tree_id, " is already there."); } - nodes_.emplace_back(node); node_tree_ids.emplace_back(node_tree_id); } - InlinedVector truenode_ids, falsenode_ids; - truenode_ids.reserve(limit); - falsenode_ids.reserve(limit); TreeNodeElementId coor; - i = 0; - for (auto it = nodes_.begin(); it != nodes_.end(); ++it, ++i) { - if (!it->is_not_leaf()) { + for (i = 0; i < limit; ++i) { + if (cmodes[i] == NODE_MODE::LEAF) { truenode_ids.push_back(0); falsenode_ids.push_back(0); - continue; - } - - TreeNodeElementId& node_tree_id = node_tree_ids[i]; - coor.tree_id = node_tree_id.tree_id; - coor.node_id = static_cast(nodes_truenodeids[i]); - ORT_ENFORCE((coor.node_id >= 0 && coor.node_id < n_nodes_)); + } else { + TreeNodeElementId& node_tree_id = node_tree_ids[i]; + coor.tree_id = node_tree_id.tree_id; + coor.node_id = static_cast(nodes_truenodeids[i]); + ORT_ENFORCE((coor.node_id >= 0 && coor.node_id < n_nodes_)); + + auto found = node_tree_ids_map.find(coor); + if (found == node_tree_ids_map.end()) { + ORT_THROW("Unable to find node ", coor.tree_id, "-", coor.node_id, " (truenode)."); + } + if (found->second == truenode_ids.size()) { + ORT_THROW("A node cannot point to itself: ", coor.tree_id, "-", node_tree_id.node_id, " (truenode)."); + } + truenode_ids.emplace_back(found->second); - auto found = idi.find(coor); - if (found == idi.end()) { - ORT_THROW("Unable to find node ", coor.tree_id, "-", coor.node_id, " (truenode)."); - } - if (found->second == truenode_ids.size()) { - ORT_THROW("A node cannot point to itself: ", coor.tree_id, "-", node_tree_id.node_id, " (truenode)."); + coor.node_id = static_cast(nodes_falsenodeids[i]); + ORT_ENFORCE((coor.node_id >= 0 && coor.node_id < n_nodes_)); + found = node_tree_ids_map.find(coor); + if (found == node_tree_ids_map.end()) { + ORT_THROW("Unable to find node ", coor.tree_id, "-", coor.node_id, " (falsenode)."); + } + if (found->second == falsenode_ids.size()) { + ORT_THROW("A node cannot point to itself: ", coor.tree_id, "-", node_tree_id.node_id, " (falsenode)."); + } + falsenode_ids.emplace_back(found->second); + // We could also check that truenode_ids[truenode_ids.size() - 1] != falsenode_ids[falsenode_ids.size() - 1]). + // It is valid but no training algorithm would produce a tree where left and right nodes are the same. } - truenode_ids.emplace_back(found->second); + } - coor.node_id = static_cast(nodes_falsenodeids[i]); - ORT_ENFORCE((coor.node_id >= 0 && coor.node_id < n_nodes_)); - found = idi.find(coor); - if (found == idi.end()) { - ORT_THROW("Unable to find node ", coor.tree_id, "-", coor.node_id, " (falsenode)."); - } - if (found->second == falsenode_ids.size()) { - ORT_THROW("A node cannot point to itself: ", coor.tree_id, "-", node_tree_id.node_id, " (falsenode)."); + // Let's construct nodes_ such that the false branch is always the next element in nodes_. + // updated_mapping will translates the old position of each node to the new node position in nodes_. + std::vector updated_mapping(nodes_treeids.size(), 0); + int64_t previous_tree_id = -1; + for (i = 0; i < n_nodes_; ++i) { + if (previous_tree_id == -1 || (previous_tree_id != node_tree_ids[i].tree_id)) { + // New tree. + int64_t tree_id = node_tree_ids[i].tree_id; + size_t root_position = + AddNodes(i, cmodes, truenode_ids, falsenode_ids, nodes_featureids, nodes_values_as_tensor, nodes_values, + nodes_missing_value_tracks_true, updated_mapping, tree_id, node_tree_ids); + roots_.push_back(&nodes_[root_position]); + previous_tree_id = tree_id; } - falsenode_ids.emplace_back(found->second); - // We could also check that truenode_ids[truenode_ids.size() - 1] != falsenode_ids[falsenode_ids.size() - 1]). - // It is valid but no training algorithm would produce a tree where left and right nodes are the same. } - // sort targets + n_trees_ = roots_.size(); + if (((int64_t)nodes_.size()) != n_nodes_) { + ORT_THROW("Number of nodes in nodes_ (", nodes_.size(), ") is different from n_nodes (", n_nodes_, ")."); + } + + // Sort targets InlinedVector> indices; indices.reserve(target_class_nodeids.size()); for (i = 0, limit = target_class_nodeids.size(); i < limit; i++) { - indices.emplace_back(std::pair( - TreeNodeElementId{target_class_treeids[i], target_class_nodeids[i]}, - i)); + indices.emplace_back( + std::pair(TreeNodeElementId{target_class_treeids[i], target_class_nodeids[i]}, i)); } + std::sort(indices.begin(), indices.end()); - // Initialize the leaves. TreeNodeElementId ind; SparseValue w; size_t indi; for (indi = 0, limit = target_class_nodeids.size(); indi < limit; ++indi) { ind = indices[indi].first; i = indices[indi].second; - auto found = idi.find(ind); - if (found == idi.end()) { + auto found = node_tree_ids_map.find(ind); + if (found == node_tree_ids_map.end()) { ORT_THROW("Unable to find node ", ind.tree_id, "-", ind.node_id, " (weights)."); } - TreeNodeElement& leaf = nodes_[found->second]; + TreeNodeElement& leaf = nodes_[updated_mapping[found->second]]; if (leaf.is_not_leaf()) { // An exception should be raised in that case. But this case may happen in // models converted with an old version of onnxmltools. These weights are ignored. // ORT_THROW("Node ", ind.tree_id, "-", ind.node_id, " is not a leaf."); continue; } - w.i = target_class_ids[i]; - w.value = target_class_weights_as_tensor.empty() - ? static_cast(target_class_weights[i]) - : target_class_weights_as_tensor[i]; - if (leaf.falsenode_inc_or_n_weights == 0) { - leaf.truenode_inc_or_first_weight = static_cast(weights_.size()); + w.value = target_class_weights_as_tensor.empty() ? static_cast(target_class_weights[i]) + : target_class_weights_as_tensor[i]; + if (leaf.truenode_or_weight.weight_data.n_weights == 0) { + leaf.truenode_or_weight.weight_data.weight = static_cast(weights_.size()); leaf.value_or_unique_weight = w.value; } - ++leaf.falsenode_inc_or_n_weights; + ++leaf.truenode_or_weight.weight_data.n_weights; weights_.push_back(w); } - // Initialize all the nodes but the leaves. - int64_t previous = -1; - for (i = 0, limit = static_cast(n_nodes_); i < limit; ++i) { - if ((previous == -1) || (previous != node_tree_ids[i].tree_id)) - roots_.push_back(&(nodes_[idi[node_tree_ids[i]]])); - previous = node_tree_ids[i].tree_id; - if (!nodes_[i].is_not_leaf()) { - if (nodes_[i].falsenode_inc_or_n_weights == 0) { - ORT_THROW("Target is missing for leaf ", ind.tree_id, "-", ind.node_id, "."); - } - continue; - } - ORT_ENFORCE(truenode_ids[i] != i); // That would mean the left node is itself, leading to an infinite loop. - nodes_[i].truenode_inc_or_first_weight = static_cast(truenode_ids[i] - i); - ORT_ENFORCE(falsenode_ids[i] != i); // That would mean the right node is itself, leading to an infinite loop. - nodes_[i].falsenode_inc_or_n_weights = static_cast(falsenode_ids[i] - i); - } - - n_trees_ = roots_.size(); has_missing_tracks_ = false; - for (auto itm = nodes_missing_value_tracks_true.begin(); - itm != nodes_missing_value_tracks_true.end(); ++itm) { + for (auto itm = nodes_missing_value_tracks_true.begin(); itm != nodes_missing_value_tracks_true.end(); ++itm) { if (*itm) { has_missing_tracks_ = true; break; } } + return Status::OK(); } +template +size_t TreeEnsembleCommon::AddNodes( + const size_t i, const InlinedVector& cmodes, const InlinedVector& truenode_ids, + const InlinedVector& falsenode_ids, const std::vector& nodes_featureids, + const std::vector& nodes_values_as_tensor, const std::vector& node_values, + const std::vector& nodes_missing_value_tracks_true, std::vector& updated_mapping, int64_t tree_id, + const InlinedVector& node_tree_ids) { + // Validate this index maps to the same tree_id as the one we should be building. + if (node_tree_ids[i].tree_id != tree_id) { + ORT_THROW("Tree id mismatch. Expected ", tree_id, " but got ", node_tree_ids[i].tree_id, " at position ", i); + } + + if (updated_mapping[i] != 0) { + // In theory we should not accept any cycles, however in practice LGBM conversion implements set membership via a + // series of "Equals" nodes, with the true branches directed at the same child node (a cycle). + // We may instead seek to formalize set membership in the future. + return updated_mapping[i]; + } + + size_t node_pos = nodes_.size(); + updated_mapping[i] = node_pos; + + TreeNodeElement node; + node.flags = static_cast(cmodes[i]); + node.feature_id = static_cast(nodes_featureids[i]); + if (node.feature_id > max_feature_id_) { + max_feature_id_ = node.feature_id; + } + node.value_or_unique_weight = + nodes_values_as_tensor.empty() ? static_cast(node_values[i]) : nodes_values_as_tensor[i]; + if (i < static_cast(nodes_missing_value_tracks_true.size()) && nodes_missing_value_tracks_true[i] == 1) { + node.flags |= static_cast(MissingTrack::kTrue); + } + nodes_.push_back(std::move(node)); + if (nodes_[node_pos].is_not_leaf()) { + size_t false_branch = + AddNodes(falsenode_ids[i], cmodes, truenode_ids, falsenode_ids, nodes_featureids, nodes_values_as_tensor, + node_values, nodes_missing_value_tracks_true, updated_mapping, tree_id, node_tree_ids); + if (false_branch != node_pos + 1) { + ORT_THROW("False node must always be the next node, but it isn't at index ", node_pos, " with flags ", + static_cast(nodes_[node_pos].flags)); + } + size_t true_branch = + AddNodes(truenode_ids[i], cmodes, truenode_ids, falsenode_ids, nodes_featureids, nodes_values_as_tensor, + node_values, nodes_missing_value_tracks_true, updated_mapping, tree_id, node_tree_ids); + // We don't need to store the false branch pointer since we know it is always in the immediate next entry in nodes_. + // nodes_[node_pos].falsenode_inc_or_n_weights.ptr = &nodes_[false_branch]; + nodes_[node_pos].truenode_or_weight.ptr = &nodes_[true_branch]; + } else { + nodes_[node_pos].truenode_or_weight.weight_data.weight = 0; + nodes_[node_pos].truenode_or_weight.weight_data.n_weights = 0; + } + return node_pos; +} + template Status TreeEnsembleCommon::compute(OpKernelContext* ctx, const Tensor* X, @@ -637,22 +669,19 @@ void TreeEnsembleCommon::ComputeAgg(concur } } // namespace detail -#define TREE_FIND_VALUE(CMP) \ - if (has_missing_tracks_) { \ - while (root->is_not_leaf()) { \ - val = x_data[root->feature_id]; \ - root += (val CMP root->value_or_unique_weight || \ - (root->is_missing_track_true() && _isnan_(val))) \ - ? root->truenode_inc_or_first_weight \ - : root->falsenode_inc_or_n_weights; \ - } \ - } else { \ - while (root->is_not_leaf()) { \ - val = x_data[root->feature_id]; \ - root += val CMP root->value_or_unique_weight \ - ? root->truenode_inc_or_first_weight \ - : root->falsenode_inc_or_n_weights; \ - } \ +#define TREE_FIND_VALUE(CMP) \ + if (has_missing_tracks_) { \ + while (root->is_not_leaf()) { \ + val = x_data[root->feature_id]; \ + root = (val CMP root->value_or_unique_weight || (root->is_missing_track_true() && _isnan_(val))) \ + ? root->truenode_or_weight.ptr \ + : root + 1; \ + } \ + } else { \ + while (root->is_not_leaf()) { \ + val = x_data[root->feature_id]; \ + root = val CMP root->value_or_unique_weight ? root->truenode_or_weight.ptr : root + 1; \ + } \ } inline bool _isnan_(float x) { return std::isnan(x); } @@ -671,15 +700,14 @@ TreeEnsembleCommon::ProcessTreeNodeLeave( if (has_missing_tracks_) { while (root->is_not_leaf()) { val = x_data[root->feature_id]; - root += (val <= root->value_or_unique_weight || - (root->is_missing_track_true() && _isnan_(val))) - ? root->truenode_inc_or_first_weight - : root->falsenode_inc_or_n_weights; + root = (val <= root->value_or_unique_weight || (root->is_missing_track_true() && _isnan_(val))) + ? root->truenode_or_weight.ptr + : root + 1; } } else { while (root->is_not_leaf()) { val = x_data[root->feature_id]; - root += val <= root->value_or_unique_weight ? root->truenode_inc_or_first_weight : root->falsenode_inc_or_n_weights; + root = val <= root->value_or_unique_weight ? root->truenode_or_weight.ptr : root + 1; } } break; @@ -703,42 +731,36 @@ TreeEnsembleCommon::ProcessTreeNodeLeave( } } else { // Different rules to compare to node thresholds. ThresholdType threshold; - while (root->is_not_leaf()) { + while (1) { val = x_data[root->feature_id]; threshold = root->value_or_unique_weight; switch (root->mode()) { case NODE_MODE::BRANCH_LEQ: - root += val <= threshold || (root->is_missing_track_true() && _isnan_(val)) - ? root->truenode_inc_or_first_weight - : root->falsenode_inc_or_n_weights; + root = val <= threshold || (root->is_missing_track_true() && _isnan_(val)) ? root->truenode_or_weight.ptr + : root + 1; break; case NODE_MODE::BRANCH_LT: - root += val < threshold || (root->is_missing_track_true() && _isnan_(val)) - ? root->truenode_inc_or_first_weight - : root->falsenode_inc_or_n_weights; + root = val < threshold || (root->is_missing_track_true() && _isnan_(val)) ? root->truenode_or_weight.ptr + : root + 1; break; case NODE_MODE::BRANCH_GTE: - root += val >= threshold || (root->is_missing_track_true() && _isnan_(val)) - ? root->truenode_inc_or_first_weight - : root->falsenode_inc_or_n_weights; + root = val >= threshold || (root->is_missing_track_true() && _isnan_(val)) ? root->truenode_or_weight.ptr + : root + 1; break; case NODE_MODE::BRANCH_GT: - root += val > threshold || (root->is_missing_track_true() && _isnan_(val)) - ? root->truenode_inc_or_first_weight - : root->falsenode_inc_or_n_weights; + root = val > threshold || (root->is_missing_track_true() && _isnan_(val)) ? root->truenode_or_weight.ptr + : root + 1; break; case NODE_MODE::BRANCH_EQ: - root += val == threshold || (root->is_missing_track_true() && _isnan_(val)) - ? root->truenode_inc_or_first_weight - : root->falsenode_inc_or_n_weights; + root = val == threshold || (root->is_missing_track_true() && _isnan_(val)) ? root->truenode_or_weight.ptr + : root + 1; break; case NODE_MODE::BRANCH_NEQ: - root += val != threshold || (root->is_missing_track_true() && _isnan_(val)) - ? root->truenode_inc_or_first_weight - : root->falsenode_inc_or_n_weights; + root = val != threshold || (root->is_missing_track_true() && _isnan_(val)) ? root->truenode_or_weight.ptr + : root + 1; break; case NODE_MODE::LEAF: - break; + return root; } } } diff --git a/onnxruntime/core/providers/cpu/nn/batch_norm.h b/onnxruntime/core/providers/cpu/nn/batch_norm.h index c7a52e970745a..be9bc3368ea41 100644 --- a/onnxruntime/core/providers/cpu/nn/batch_norm.h +++ b/onnxruntime/core/providers/cpu/nn/batch_norm.h @@ -29,7 +29,7 @@ namespace onnxruntime { -#if !defined(ORT_MINIMAL_BUILD) +#if !defined(ORT_MINIMAL_BUILD) || defined(ENABLE_TRAINING_OPS) #define BATCHNORM_INCLUDE_TRAINING_SUPPORT #endif diff --git a/onnxruntime/core/providers/cpu/nn/conv.cc b/onnxruntime/core/providers/cpu/nn/conv.cc index 1a40b05cc3143..51dfb143fb916 100644 --- a/onnxruntime/core/providers/cpu/nn/conv.cc +++ b/onnxruntime/core/providers/cpu/nn/conv.cc @@ -195,18 +195,18 @@ Status Conv::Compute(OpKernelContext* context) const { AllocatorPtr alloc; ORT_RETURN_IF_ERROR(context->GetTempSpaceAllocator(&alloc)); - const auto* Xdata = X->Data(); + auto Xdata = X->DataAsSpan(); const auto* Bdata = B != nullptr ? B->Data() : nullptr; - auto* Ydata = Y->MutableData(); + auto Ydata = Y->MutableDataAsSpan(); // Check for the optional Conv/Sum fusion. float Beta = 0.0f; if (Sum != nullptr) { const auto& sum_shape = Sum->Shape(); ORT_RETURN_IF_NOT(Y->Shape() == sum_shape, "output and sum shape must match"); // If the output was not allocated inplace with the sum tensor, then copy here. - const auto* sum_data = Sum->Data(); - if (Ydata != sum_data) { - memcpy(Ydata, sum_data, SafeInt(sum_shape.Size()) * sizeof(float)); + auto sum_data = Sum->DataAsSpan(); + if (Ydata.data() != sum_data.data()) { + gsl::copy(sum_data, Ydata); } Beta = 1.0f; } @@ -218,16 +218,16 @@ Status Conv::Compute(OpKernelContext* context) const { size_t WorkingBufferSize; MlasConvPrepare(&Parameters, kernel_rank, - static_cast(N), - static_cast(conv_attrs_.group), - static_cast(C / conv_attrs_.group), + narrow(N), + narrow(conv_attrs_.group), + narrow(C / conv_attrs_.group), input_shape.GetDims().data(), kernel_shape.data(), dilations.data(), pads.data(), strides.data(), output_shape.GetDims().data(), - static_cast(M / conv_attrs_.group), + narrow(M / conv_attrs_.group), &activation_, &WorkingBufferSize, Beta, @@ -238,30 +238,28 @@ Status Conv::Compute(OpKernelContext* context) const { BufferUniquePtr working_buffer(working_data, BufferDeleter(std::move(alloc))); MlasConv(&Parameters, - Xdata, + Xdata.data(), W->Data(), Bdata, static_cast(working_buffer.get()), - Ydata, + Ydata.data(), thread_pool); } else { const int64_t input_image_size = input_shape.Size(); const int64_t output_image_size = output_shape.Size(); const int64_t kernel_size = TensorShape(kernel_shape).Size(); - const int64_t X_offset = C / conv_attrs_.group * input_image_size; - const int64_t Y_offset = Y->Shape().Size() / Y->Shape()[0] / conv_attrs_.group; - const int64_t W_offset = W->Shape().Size() / conv_attrs_.group; - const int64_t kernel_dim = C / conv_attrs_.group * kernel_size; + const SafeInt X_offset = SafeInt(C) / conv_attrs_.group * input_image_size; + const SafeInt Y_offset = SafeInt(Y->Shape().Size()) / Y->Shape()[0] / conv_attrs_.group; + const SafeInt W_offset = SafeInt(W->Shape().Size()) / conv_attrs_.group; + const SafeInt kernel_dim = SafeInt(C) / conv_attrs_.group * kernel_size; const int64_t col_buffer_size = kernel_dim * output_image_size; - auto* col_data = alloc->Alloc(sizeof(float) * SafeInt(col_buffer_size)); - BufferUniquePtr col_buffer(col_data, BufferDeleter(std::move(alloc))); - auto* col_buffer_data = static_cast(col_buffer.get()); - + auto col_data = IAllocator::MakeUniquePtr(alloc, narrow(col_buffer_size)); + auto w_data = W->DataAsSpan(); for (int image_id = 0; image_id < N; ++image_id) { for (int group_id = 0; group_id < conv_attrs_.group; ++group_id) { math::Im2col()( - Xdata + group_id * X_offset, + &Xdata[group_id * X_offset], input_shape.GetDims().data(), output_shape.GetDims().data(), kernel_dim, @@ -269,8 +267,8 @@ Status Conv::Compute(OpKernelContext* context) const { strides.data(), dilations.data(), pads.data(), - static_cast(kernel_shape.size()), - col_buffer_data); + narrow(kernel_shape.size()), + col_data.get()); math::Gemm( CblasNoTrans, @@ -279,17 +277,17 @@ Status Conv::Compute(OpKernelContext* context) const { narrow(output_image_size), narrow(kernel_dim), 1, - W->Data() + group_id * W_offset, - col_buffer_data, + &w_data[group_id * W_offset], + col_data.get(), Beta, - Ydata + group_id * Y_offset, + &Ydata[group_id * Y_offset], thread_pool); } - MlasActivation(&activation_, Ydata, Bdata, narrow(M), narrow(output_image_size), narrow(output_image_size)); + MlasActivation(&activation_, Ydata.data(), Bdata, narrow(M), narrow(output_image_size), narrow(output_image_size)); - Xdata += X_offset * conv_attrs_.group; - Ydata += Y_offset * conv_attrs_.group; + Xdata = Xdata.subspan(X_offset * conv_attrs_.group); + Ydata = Ydata.subspan(Y_offset * conv_attrs_.group); } } diff --git a/onnxruntime/core/providers/cpu/nn/dropout_op.h b/onnxruntime/core/providers/cpu/nn/dropout_op.h index 8d2f588054879..7878f1b94cdc0 100644 --- a/onnxruntime/core/providers/cpu/nn/dropout_op.h +++ b/onnxruntime/core/providers/cpu/nn/dropout_op.h @@ -3,6 +3,7 @@ #pragma once +#include "core/common/narrow.h" #include "core/framework/op_kernel.h" #include "core/framework/random_generator.h" #include @@ -56,10 +57,10 @@ Status Dropout::Compute(OpKernelContext* context) const { auto Y_span = Y->MutableDataAsSpan(); Tensor* mask = context->Output(1, X_shape); // optional std::unique_ptr temp_mask_buffer{}; // temporary buffer to use if mask input is not provided - auto mask_span = [&X_shape, mask, &temp_mask_buffer]() { + auto mask_span = [X_size = narrow(X_shape.Size()), mask, &temp_mask_buffer]() { if (mask) return mask->MutableDataAsSpan(); - temp_mask_buffer = std::make_unique(X_shape.Size()); - return gsl::make_span(temp_mask_buffer.get(), X_shape.Size()); + temp_mask_buffer = std::make_unique(X_size); + return gsl::make_span(temp_mask_buffer.get(), X_size); }(); ORT_ENFORCE(!mask || mask->Shape() == X_shape, "X and mask should have the same shape"); @@ -84,7 +85,7 @@ Status Dropout::Compute(OpKernelContext* context) const { // generate mask { RandomGenerator& generator = generator_ != nullptr ? *generator_.get() : RandomGenerator::Default(); - std::default_random_engine rng(generator.NextSeed()); + std::default_random_engine rng(gsl::narrow_cast(generator.NextSeed())); std::uniform_real_distribution dist{0.0f, 1.0f}; mask_arr = Eigen::ArrayX::NullaryExpr( mask_arr.size(), diff --git a/onnxruntime/core/providers/cpu/nn/pool.cc b/onnxruntime/core/providers/cpu/nn/pool.cc index 084669c970239..9230398680a64 100644 --- a/onnxruntime/core/providers/cpu/nn/pool.cc +++ b/onnxruntime/core/providers/cpu/nn/pool.cc @@ -249,6 +249,81 @@ Status MaxPoolV8::ComputeImpl(OpKernelContext* context) const { return Status::OK(); } +template +Status AveragePoolV19::Compute(OpKernelContext* context) const { + concurrency::ThreadPool* tp = context->GetOperatorThreadPool(); + bool need_dilation = false; + for (auto n : pool_attrs_.dilations) { + need_dilation |= n > 1; + } + + const auto* X = context->Input(0); + const TensorShape& x_shape = X->Shape(); + + ORT_RETURN_IF_NOT(x_shape.NumDimensions() >= 3, "Input dimension cannot be less than 3."); + + auto pads = pool_attrs_.pads; + auto kernel_shape = pool_attrs_.kernel_shape; + + auto output_dims = pool_attrs_.SetOutputSize(x_shape, x_shape[1], &pads); + Tensor* Y = context->Output(0, output_dims); + + const auto* X_data = X->Data(); + auto* Y_data = Y->MutableData(); + + // The main loop + int64_t channels = x_shape[1]; + int64_t height = x_shape[2]; + int64_t width = kernel_shape.size() > 1 ? x_shape[3] : 1; + int64_t depth = kernel_shape.size() > 2 ? x_shape[4] : 1; + int64_t pooled_height = output_dims[2]; + int64_t pooled_width = kernel_shape.size() > 1 ? output_dims[3] : 1; + int64_t pooled_depth = kernel_shape.size() > 2 ? output_dims[4] : 1; + const int64_t total_channels = x_shape[0] * channels; + + switch (kernel_shape.size()) { + case 1: { + int64_t x_step = height; + int64_t y_step = pooled_height; + const int64_t dilation_h = pool_attrs_.dilations[0]; + + RunLoop>(tp, onnxruntime::narrow(total_channels), + {X_data, Y_data, x_step, y_step, dilation_h, pooled_height, stride_h(), + height, kernel_shape, pads, pool_attrs_.count_include_pad, p_}); + break; + } + + case 2: { + int64_t x_step = height * width; + int64_t y_step = pooled_height * pooled_width; + const int64_t dilation_h = pool_attrs_.dilations[0]; + const int64_t dilation_w = pool_attrs_.dilations[1]; + RunLoop>( + tp, onnxruntime::narrow(total_channels), + {X_data, Y_data, x_step, y_step, dilation_h, dilation_w, pooled_height, pooled_width, stride_h(), + stride_w(), height, width, kernel_shape, pads, pool_attrs_.count_include_pad, p_}); + break; + } + case 3: { + int64_t x_step = height * width * depth; + int64_t y_step = pooled_height * pooled_width * pooled_depth; + const int64_t dilation_h = pool_attrs_.dilations[0]; + const int64_t dilation_w = pool_attrs_.dilations[1]; + const int64_t dilation_d = pool_attrs_.dilations[2]; + RunLoop>(tp, onnxruntime::narrow(total_channels), + {X_data, Y_data, x_step, y_step, + dilation_h, dilation_w, dilation_d, pooled_height, pooled_width, + pooled_depth, stride_h(), stride_w(), stride_d(), height, + width, depth, kernel_shape, pads, pool_attrs_.count_include_pad, p_}); + break; + } + default: + return Status(ONNXRUNTIME, INVALID_ARGUMENT, "Unsupported kernel dimension : " + std::to_string(kernel_shape.size())); + } + + return Status::OK(); +} + template Status LpPoolV18::Compute(OpKernelContext* context) const { concurrency::ThreadPool* tp = context->GetOperatorThreadPool(); @@ -332,8 +407,16 @@ ONNX_CPU_OPERATOR_VERSIONED_KERNEL(AveragePool, 10, 10, KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()), Pool); -ONNX_CPU_OPERATOR_KERNEL(AveragePool, 11, KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()), - Pool); +ONNX_CPU_OPERATOR_VERSIONED_KERNEL(AveragePool, 11, 18, + KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()), + Pool); + +ONNX_CPU_OPERATOR_KERNEL(AveragePool, 19, + KernelDefBuilder() + .TypeConstraint( + "T", + DataTypeImpl::GetTensorType()), + AveragePoolV19); ONNX_CPU_OPERATOR_VERSIONED_KERNEL(MaxPool, 1, 7, KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()), diff --git a/onnxruntime/core/providers/cpu/nn/pool.h b/onnxruntime/core/providers/cpu/nn/pool.h index 98a9c8abb68f8..7796b28b8369b 100644 --- a/onnxruntime/core/providers/cpu/nn/pool.h +++ b/onnxruntime/core/providers/cpu/nn/pool.h @@ -25,6 +25,20 @@ class Pool : public OpKernel, public PoolBase { PoolProcessContext pool_context_; }; +// For averagepool v19 and beyond +// version 19: Added dilations +template +class AveragePoolV19 : public OpKernel, public PoolBase { + public: + AveragePoolV19(const OpKernelInfo& info) : OpKernel(info), PoolBase(info) { + } + + Status Compute(OpKernelContext* context) const override; + + private: + int64_t p_; +}; + // For maxpool v8 and beyond // version 8: Added storage_order And Indices // version 10: Added ceil_mode diff --git a/onnxruntime/core/providers/cpu/nn/pool_functors.h b/onnxruntime/core/providers/cpu/nn/pool_functors.h index 1fbdadf05f2d5..d3205278b72f6 100644 --- a/onnxruntime/core/providers/cpu/nn/pool_functors.h +++ b/onnxruntime/core/providers/cpu/nn/pool_functors.h @@ -376,6 +376,199 @@ struct MaxPool3DTask { } }; +template +struct AveragePool1DTask final { + const T* X_data; + T* Y_data; + int64_t x_step; + int64_t y_step; + int64_t dilation_h; + int64_t pooled_height; + int64_t stride_h; + int64_t height; + gsl::span kernel_shape; + gsl::span pads; + bool count_include_pad; + int64_t p; + TensorOpCost Cost() { + double loop_count = static_cast(pooled_height * kernel_shape[0]); + return TensorOpCost{loop_count, loop_count, loop_count}; + } + + void operator()(std::ptrdiff_t begin, std::ptrdiff_t end) const { + for (std::ptrdiff_t c = begin; c < end; ++c) { + operator()(c); + } + } + void operator()(std::ptrdiff_t c) const { + const T* x_d = X_data + c * x_step; + T* y_d = Y_data + c * y_step; + for (int64_t ph = 0; ph < pooled_height; ++ph) { + int64_t hstart = ph * stride_h - pads[0]; + int64_t hend = hstart + kernel_shape[0] * dilation_h; + y_d[ph] = 0; + int total_elements = 0; + for (int64_t h = hstart; h < hend; h += dilation_h) { + if (math::is_a_ge_zero_and_a_lt_b(h, height)) { + y_d[ph] += x_d[h]; + total_elements++; + } + } + if (total_elements > 0) { + if (count_include_pad) { + y_d[ph] /= (1 + (hend - hstart - 1) / dilation_h); + } else { + y_d[ph] /= total_elements; + } + } + } + } +}; + +template +struct AveragePool2DTask final { + const T* X_data; + T* Y_data; + int64_t x_step; + int64_t y_step; + int64_t dilation_h; + int64_t dilation_w; + int64_t pooled_height; + int64_t pooled_width; + int64_t stride_h; + int64_t stride_w; + int64_t height; + int64_t width; + gsl::span kernel_shape; + gsl::span pads; + bool count_include_pad; + int64_t p; + + TensorOpCost Cost() { + double loop_count = static_cast(pooled_height * pooled_width * kernel_shape[0] * kernel_shape[1]); + return TensorOpCost{loop_count, loop_count, loop_count}; + } + + void operator()(std::ptrdiff_t begin, std::ptrdiff_t end) const { + for (std::ptrdiff_t c = begin; c < end; ++c) { + operator()(c); + } + } + + void operator()(std::ptrdiff_t c) const { + const T* x_d = X_data + c * x_step; + T* y_d = Y_data + c * y_step; + for (int64_t ph = 0; ph < pooled_height; ++ph) { + int64_t hstart = ph * stride_h - pads[0]; + int64_t hend = hstart + kernel_shape[0] * dilation_h; + for (int64_t pw = 0; pw < pooled_width; ++pw) { + int64_t wstart = pw * stride_w - pads[1]; + int64_t wend = wstart + kernel_shape[1] * dilation_w; + const int64_t pool_index = ph * pooled_width + pw; + y_d[pool_index] = 0; + int total_elements = 0; + for (int64_t h = hstart; h < hend; h += dilation_h) { + if (math::is_a_ge_zero_and_a_lt_b(h, height)) { + for (int64_t w = wstart; w < wend; w += dilation_w) { + if (math::is_a_ge_zero_and_a_lt_b(w, width)) { + const int64_t input_index = h * width + w; + y_d[pool_index] += x_d[input_index]; + total_elements++; + } + } + } + } + if (total_elements > 0) { + if (count_include_pad) { + y_d[pool_index] /= ((1 + (hend - hstart - 1) / dilation_h) * (1 + (wend - wstart - 1) / dilation_w)); + } else { + y_d[pool_index] /= total_elements; + } + } + } + } + } +}; + +template +struct AveragePool3DTask { + const T* X_data; + T* Y_data; + int64_t x_step; + int64_t y_step; + int64_t dilation_h; + int64_t dilation_w; + int64_t dilation_d; + int64_t pooled_height; + int64_t pooled_width; + int64_t pooled_depth; + int64_t stride_h; + int64_t stride_w; + int64_t stride_d; + int64_t height; + int64_t width; + int64_t depth; + gsl::span kernel_shape; + gsl::span pads; + bool count_include_pad; + int64_t p; + + void operator()(std::ptrdiff_t begin, std::ptrdiff_t end) const { + for (std::ptrdiff_t c = begin; c < end; ++c) { + operator()(c); + } + } + + TensorOpCost Cost() { + double loop_count = static_cast(pooled_height * pooled_width * pooled_depth * kernel_shape[0] * + kernel_shape[1] * kernel_shape[2]); + return TensorOpCost{loop_count, loop_count, loop_count}; + } + + void operator()(std::ptrdiff_t c) const { + const T* x_d = X_data + c * x_step; + T* y_d = Y_data + c * y_step; + + for (int64_t ph = 0; ph < pooled_height; ++ph) { + int64_t hstart = ph * stride_h - pads[0]; + int64_t hend = hstart + kernel_shape[0] * dilation_h; + for (int64_t pw = 0; pw < pooled_width; ++pw) { + int64_t wstart = pw * stride_w - pads[1]; + int64_t wend = wstart + kernel_shape[1] * dilation_w; + for (int64_t pd = 0; pd < pooled_depth; ++pd) { + int64_t dstart = pd * stride_d - pads[2]; + int64_t dend = dstart + kernel_shape[2] * dilation_d; + const int64_t pool_index = ph * pooled_width * pooled_depth + pw * pooled_depth + pd; + y_d[pool_index] = 0; + int total_elements = 0; + for (int64_t h = hstart; h < hend; h += dilation_h) { + if (math::is_a_ge_zero_and_a_lt_b(h, height)) { + for (int64_t w = wstart; w < wend; w += dilation_w) { + if (math::is_a_ge_zero_and_a_lt_b(w, width)) { + for (int64_t d = dstart; d < dend; d += dilation_d) { + if (math::is_a_ge_zero_and_a_lt_b(d, depth)) { + const int64_t input_index = h * width * depth + w * depth + d; + y_d[pool_index] += x_d[input_index]; + total_elements++; + } + } + } + } + } + } + if (total_elements > 0) { + if (count_include_pad) { + y_d[pool_index] /= ((1 + (hend - hstart - 1) / dilation_h) * (1 + (wend - wstart - 1) / dilation_w) * (1 + (dend - dstart - 1) / dilation_d)); + } else { + y_d[pool_index] /= total_elements; + } + } + } + } + } + } +}; + template struct LpPool1DTask final { const T* X_data; diff --git a/onnxruntime/core/providers/cpu/nn/shrink.cc b/onnxruntime/core/providers/cpu/nn/shrink.cc index f4e9df1fb3a3c..406e8870b20aa 100644 --- a/onnxruntime/core/providers/cpu/nn/shrink.cc +++ b/onnxruntime/core/providers/cpu/nn/shrink.cc @@ -34,51 +34,25 @@ ONNX_CPU_OPERATOR_KERNEL( #endif namespace shrink_internal { template -inline T ShrinkCore(const T& val, float bias, float lambd) { +inline T ShrinkCore(const T& t_val, float bias, float lambd) { // The ONNX spec doesn't take numeric overflow and underflow into account // Implementing the spec as is for now + float val = static_cast(t_val); if (val < -lambd) { - return T(val + bias); + return static_cast(val + bias); } if (val > lambd) { - return T(val - bias); + return static_cast(val - bias); } else { - return T(0); + return static_cast(0.f); } } -template -Status ShrinkImpl(const Tensor* input, Tensor* output, float bias, float lambd) { - EigenMap(*output) = EigenMap(*input).unaryExpr([bias, lambd](const T& val) { return ShrinkCore(val, bias, lambd); }); - return Status::OK(); -} - -template <> -Status ShrinkImpl(const Tensor* input, Tensor* output, float bias, float lambd) { - const auto& span = gsl::make_span(input->Data(), onnxruntime::narrow(input->Shape().Size())); - auto* output_data = output->MutableData(); - std::transform(span.begin(), span.end(), output_data, [bias, lambd](const MLFloat16& val) { - float fl = math::halfToFloat(val.val); - return MLFloat16(math::floatToHalf(ShrinkCore(fl, bias, lambd))); - }); - return Status::OK(); -} - -template <> -Status ShrinkImpl(const Tensor* input, Tensor* output, float bias, float lambd) { - const auto& span = gsl::make_span(input->Data(), onnxruntime::narrow(input->Shape().Size())); - auto* output_data = output->MutableData(); - std::transform(span.begin(), span.end(), output_data, [bias, lambd](const BFloat16& val) { - float fl = val.ToFloat(); - return BFloat16(ShrinkCore(fl, bias, lambd)); - }); - return Status::OK(); -} - template struct CallShrinkImpl { Status operator()(const Tensor* input, Tensor* output, float bias, float lambd) const { - return ShrinkImpl(input, output, bias, lambd); + EigenMap(*output) = EigenMap(*input).unaryExpr([bias, lambd](const T& val) { return ShrinkCore(val, bias, lambd); }); + return Status::OK(); } }; diff --git a/onnxruntime/core/providers/cpu/nn/string_normalizer.cc b/onnxruntime/core/providers/cpu/nn/string_normalizer.cc index 0e4e681854d61..548f555af9951 100644 --- a/onnxruntime/core/providers/cpu/nn/string_normalizer.cc +++ b/onnxruntime/core/providers/cpu/nn/string_normalizer.cc @@ -4,6 +4,7 @@ #include "string_normalizer.h" #include "core/common/common.h" #include "core/framework/tensor.h" +#include "onnxruntime_config.h" #ifdef _MSC_VER #include @@ -13,12 +14,22 @@ #else #include #include + #endif // _MSC_VER #include #include #include +#if defined(__GNUC__) +// Allow deprecated-declarations warning - std::wstring_convert is deprecated. +// TODO find a suitable replacement +// Note: GNU libiconv (e.g., on Apple platforms) is not suitable due to its LGPL license. +#if defined(HAS_DEPRECATED_DECLARATIONS) +#pragma GCC diagnostic warning "-Wdeprecated-declarations" +#endif // defined(HAS_DEPRECATED_DECLARATIONS) +#endif // defined(__GNUC__) + namespace onnxruntime { ONNX_CPU_OPERATOR_KERNEL( @@ -76,7 +87,7 @@ using Utf8Converter = std::wstring_convert>; const std::string default_locale("en-US"); -#else // MS_VER +#else // _MSC_VER class Locale { public: @@ -110,11 +121,13 @@ class Locale { std::locale loc_; }; -#if defined(__ANDROID__) +#if defined(__APPLE__) || defined(__ANDROID__) + using Utf8Converter = std::wstring_convert>; + #else -// All others (Linux) +// All others (not Windows, Apple, or Android) class Utf8Converter { public: Utf8Converter(const std::string&, const std::wstring&) {} @@ -186,11 +199,20 @@ class Utf8Converter { } }; -#endif // __APPLE__ +#endif -const std::string default_locale("en_US.UTF-8"); // All non-MS +#if defined(__APPLE__) +#include +#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR +const std::string default_locale("en-US.UTF-8"); +#else +const std::string default_locale("en_US.UTF-8"); // Other kinds of Apple Platforms including MacOS, etc +#endif +#else +const std::string default_locale("en_US.UTF-8"); // All non-MS and not Apple +#endif -#endif // MS_VER +#endif // _MSC_VER template Status CopyCaseAction(ForwardIter first, ForwardIter end, OpKernelContext* ctx, diff --git a/onnxruntime/core/providers/cpu/object_detection/non_max_suppression.cc b/onnxruntime/core/providers/cpu/object_detection/non_max_suppression.cc index a509032722d5b..4a176b0726a18 100644 --- a/onnxruntime/core/providers/cpu/object_detection/non_max_suppression.cc +++ b/onnxruntime/core/providers/cpu/object_detection/non_max_suppression.cc @@ -12,9 +12,13 @@ limitations under the License. /* Modifications Copyright (c) Microsoft. */ #include "non_max_suppression.h" -#include "non_max_suppression_helper.h" + #include #include + +#include "core/common/narrow.h" +#include "non_max_suppression_helper.h" + // TODO:fix the warnings #ifdef _MSC_VER #pragma warning(disable : 4244) @@ -89,7 +93,7 @@ Status NonMaxSuppressionBase::PrepareCompute(OpKernelContext* ctx, PrepareContex pc.num_batches_ = boxes_dims[0]; pc.num_classes_ = scores_dims[1]; - pc.num_boxes_ = boxes_dims[1]; + pc.num_boxes_ = narrow(boxes_dims[1]); return Status::OK(); } diff --git a/onnxruntime/core/providers/cpu/optional/optional_ops.cc b/onnxruntime/core/providers/cpu/optional/optional_ops.cc index 33e9401935389..8bdc78305902a 100644 --- a/onnxruntime/core/providers/cpu/optional/optional_ops.cc +++ b/onnxruntime/core/providers/cpu/optional/optional_ops.cc @@ -61,7 +61,8 @@ ONNX_CPU_OPERATOR_KERNEL(OptionalGetElement, static void CopySequenceTensor(AllocatorPtr alloc, const TensorSeq* src, - TensorSeq* tgt) { + TensorSeq* tgt, + const DataTransferManager& data_transfer_mgr) { // The static allocation planner has deemed that the input can be re-used as the output // Analogy: Checking if data pointers for the input and output Tensors are the same // before proceeding to make the copy. @@ -76,13 +77,16 @@ static void CopySequenceTensor(AllocatorPtr alloc, for (; in_tensor != src->end(); ++in_tensor) { auto& tensor = in_tensor->Get(); Tensor tmp(tensor.DataType(), tensor.Shape(), alloc); - CopyCpuTensor(&tensor, &tmp); + // Using DataTransferManager here allows other non-CPU EPs to use this implementation of the sequence ops + (void)data_transfer_mgr.CopyTensor(tensor, tmp); + tgt->Add(std::move(tmp)); } } static Status PropagateInputOrtValueToFirstOutput(const OrtValue* input_ort_value, - OpKernelContext* ctx) { + OpKernelContext* ctx, + const DataTransferManager& data_transfer_mgr) { if (input_ort_value->IsTensor()) { const auto* input_tensor = &input_ort_value->Get(); auto* output_tensor = ctx->Output(0, input_tensor->Shape()); @@ -90,10 +94,9 @@ static Status PropagateInputOrtValueToFirstOutput(const OrtValue* input_ort_valu // If the allocation planner had deemed that we re-use the input OrtValue // as the output OrtValue, the data pointers in the input_tensor and the // output_tensor will be the same and the copy is a no-op. - // CopyCpuTensor() already has such copy optimizations - so + // DataTransferManager.CopyTensor() already has such copy optimizations - so // just re-use it. - CopyCpuTensor(input_tensor, output_tensor); - + ORT_RETURN_IF_ERROR(data_transfer_mgr.CopyTensor(*input_tensor, *output_tensor)); } else if (input_ort_value->IsTensorSequence()) { const auto* input_tensor_sequence = &input_ort_value->Get(); auto* output_tensor_sequence = ctx->Output(0); @@ -105,7 +108,7 @@ static Status PropagateInputOrtValueToFirstOutput(const OrtValue* input_ort_valu // as the output OrtValue, the pointers of the source TensorSeq and the // target TensorSeq will be the same and the copy is a no-op. // CopySequenceTensor() already has such copy optimizations - CopySequenceTensor(alloc, input_tensor_sequence, output_tensor_sequence); + CopySequenceTensor(alloc, input_tensor_sequence, output_tensor_sequence, data_transfer_mgr); } else { // Will not reach here @@ -132,7 +135,8 @@ Status Optional::Compute(OpKernelContext* ctx) const { if (input_ort_value != nullptr) { // An input was provided by the user - so just propagate it to the output - ORT_RETURN_IF_ERROR(PropagateInputOrtValueToFirstOutput(input_ort_value, ctx)); + const DataTransferManager& data_transfer_mgr = Info().GetDataTransferManager(); + ORT_RETURN_IF_ERROR(PropagateInputOrtValueToFirstOutput(input_ort_value, ctx, data_transfer_mgr)); } else { // No input was provided - we use the type proto to construct the output OrtValue @@ -176,7 +180,8 @@ Status OptionalGetElement::Compute(OpKernelContext* ctx) const { } // Propagate input to the output - ORT_RETURN_IF_ERROR(PropagateInputOrtValueToFirstOutput(input_ort_value, ctx)); + const DataTransferManager& data_transfer_mgr = Info().GetDataTransferManager(); + ORT_RETURN_IF_ERROR(PropagateInputOrtValueToFirstOutput(input_ort_value, ctx, data_transfer_mgr)); return Status::OK(); } diff --git a/onnxruntime/core/providers/cpu/quantization/dynamicquantizelinear.cc b/onnxruntime/core/providers/cpu/quantization/dynamicquantizelinear.cc index 03ada34bcbaa7..185cd19357742 100644 --- a/onnxruntime/core/providers/cpu/quantization/dynamicquantizelinear.cc +++ b/onnxruntime/core/providers/cpu/quantization/dynamicquantizelinear.cc @@ -44,7 +44,7 @@ Status DynamicQuantizeLinear::Compute(OpKernelContext* ctx) const { // quantize the data auto* output = y.MutableData(); - ParQuantizeLinear(x_data, output, onnxruntime::narrow(num_of_elements), scale, zero_point, ctx->GetOperatorThreadPool()); + ParQuantizeLinearStd(x_data, output, onnxruntime::narrow(num_of_elements), scale, zero_point, ctx->GetOperatorThreadPool()); return Status::OK(); } diff --git a/onnxruntime/core/providers/cpu/quantization/matmul_integer_base.h b/onnxruntime/core/providers/cpu/quantization/matmul_integer_base.h index 5aac7adda3a0a..e26eae19b8fd4 100644 --- a/onnxruntime/core/providers/cpu/quantization/matmul_integer_base.h +++ b/onnxruntime/core/providers/cpu/quantization/matmul_integer_base.h @@ -37,7 +37,7 @@ class MatMulIntegerBase : public OpKernel { const auto* b_data = static_cast(tensor.DataRaw()); - BufferUniquePtr b_trans_buffer; + std::optional b_trans_buffer; if (IsBTransposed()) { std::swap(K, N); b_data = quantization::TransPoseInputData(b_data, b_trans_buffer, alloc, N, K); @@ -47,15 +47,12 @@ class MatMulIntegerBase : public OpKernel { return Status::OK(); } - auto* packed_b_data = alloc->Alloc(packed_b_size); - + packed_b_ = IAllocator::MakeUniquePtr(alloc, packed_b_size, true); // Initialize memory to 0 as there could be some padding associated with pre-packed // buffer memory and we don not want it uninitialized and generate different hashes // if and when we try to cache this pre-packed buffer for sharing between sessions. - memset(packed_b_data, 0, packed_b_size); - - packed_b_ = BufferUniquePtr(packed_b_data, BufferDeleter(std::move(alloc))); - MlasGemmPackB(N, K, b_data, N, a_is_signed, b_is_signed_, packed_b_data); + memset(packed_b_.get(), 0, packed_b_size); + MlasGemmPackB(N, K, b_data, N, a_is_signed, b_is_signed_, packed_b_.get()); bool share_prepacked_weights = (prepacked_weights != nullptr); if (share_prepacked_weights) { @@ -129,7 +126,7 @@ class MatMulIntegerBase : public OpKernel { bool b_is_signed_{true}; TensorShape b_shape_; - BufferUniquePtr packed_b_; + IAllocatorUniquePtr packed_b_; }; } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cpu/quantization/qlinearconv.cc b/onnxruntime/core/providers/cpu/quantization/qlinearconv.cc index ba4a119d8f0a0..21a256eee6f14 100644 --- a/onnxruntime/core/providers/cpu/quantization/qlinearconv.cc +++ b/onnxruntime/core/providers/cpu/quantization/qlinearconv.cc @@ -77,7 +77,8 @@ class QLinearConv : public OpKernel { W_zero_point_value = W_zero_point_data[0]; for (int64_t i = 1; i < W_zero_point_size; i++) { ORT_ENFORCE(W_zero_point_data[i] == W_zero_point_value, - "QLinearConv : zero point of per-channel filter must be same"); + "QLinearConv : zero point of per-channel filter must be same. " + "This happens by design if the quantization is symmetric."); } } @@ -290,9 +291,9 @@ class QLinearConv : public OpKernel { ConvAttributes conv_attrs_; TensorShape W_shape_; - BufferUniquePtr packed_W_buffer_; + IAllocatorUniquePtr packed_W_buffer_; size_t packed_W_size_{0}; - BufferUniquePtr reordered_W_buffer_; + IAllocatorUniquePtr reordered_W_buffer_; bool is_W_signed_{false}; bool is_W_packed_{false}; bool is_symmetric_conv_{false}; @@ -421,22 +422,21 @@ Status QLinearConv::PrePack(const Tensor& tensor, int input_idx, Alloca is_W_signed_); if (packed_W_size_ != 0) { size_t packed_W_data_size = SafeInt(group_count) * packed_W_size_; - auto* packed_W = static_cast(alloc->Alloc(packed_W_data_size)); + packed_W_buffer_ = IAllocator::MakeUniquePtr(alloc, packed_W_data_size, true); + auto* packed_W = static_cast(packed_W_buffer_.get()); // Initialize memory to 0 as there could be some padding associated with pre-packed // buffer memory and we don not want it uninitialized and generate different hashes // if and when we try to cache this pre-packed buffer for sharing between sessions. memset(packed_W, 0, packed_W_data_size); - packed_W_buffer_ = BufferUniquePtr(packed_W, BufferDeleter(alloc)); - // Allocate a temporary buffer to hold the reordered oihw->hwio filter for // a single group. // // Note: The size of this buffer is less than or equal to the size of the original // weight tensor, so the allocation size is guaranteed to fit inside size_t. - auto* group_reordered_W = static_cast(alloc->Alloc(group_output_channels * group_input_channels * kernel_size)); - BufferUniquePtr group_reordered_W_buffer(group_reordered_W, BufferDeleter(alloc)); + auto group_reordered_W_buffer = IAllocator::MakeUniquePtr(alloc, group_output_channels * group_input_channels * kernel_size, true); + auto* group_reordered_W = static_cast(group_reordered_W_buffer.get()); const size_t W_offset = group_output_channels * kernel_dim; @@ -470,15 +470,14 @@ Status QLinearConv::PrePack(const Tensor& tensor, int input_idx, Alloca } size_t reordered_w_data_size = SafeInt(sizeof(uint8_t)) * output_channels * group_input_channels * kernel_size; - auto* reordered_W = static_cast(alloc->Alloc(reordered_w_data_size)); + reordered_W_buffer_ = IAllocator::MakeUniquePtr(alloc, reordered_w_data_size, true); + uint8_t* reordered_W = static_cast(reordered_W_buffer_.get()); // Initialize memory to 0 as there could be some padding associated with pre-packed // buffer memory and we don not want it uninitialized and generate different hashes // if and when we try to cache this pre-packed buffer for sharing between sessions. memset(reordered_W, 0, reordered_w_data_size); - reordered_W_buffer_ = BufferUniquePtr(reordered_W, BufferDeleter(alloc)); - ReorderFilter(Wdata, reordered_W, output_channels, group_input_channels, kernel_size); if (share_prepacked_weights) { @@ -807,7 +806,7 @@ Status QLinearConv::Compute(OpKernelContext* context) const { strides.data(), dilations.data(), pads.data(), - static_cast(kernel_rank), + static_cast(kernel_rank), static_cast(col_buffer.get()) + group_id * col_buffer_size, X_zero_point_value); } diff --git a/onnxruntime/core/providers/cpu/quantization/quantize_linear.cc b/onnxruntime/core/providers/cpu/quantization/quantize_linear.cc index db21a690fc09e..a0d75e8cc0e69 100644 --- a/onnxruntime/core/providers/cpu/quantization/quantize_linear.cc +++ b/onnxruntime/core/providers/cpu/quantization/quantize_linear.cc @@ -2,13 +2,50 @@ // Licensed under the MIT License. #include -#include "core/providers/cpu/quantization/quantize_linear.h" +#include "core/framework/element_type_lists.h" +#include "core/framework/float8.h" +#include "core/framework/float16.h" +#include "core/framework/op_kernel.h" #include "core/providers/common.h" #include "core/mlas/inc/mlas.h" #include "core/util/qmath.h" namespace onnxruntime { +template +class DequantizeLinear final : public OpKernel { + public: + explicit DequantizeLinear(const OpKernelInfo& info) : OpKernel(info) { + if (!info.GetAttr("axis", &axis_).IsOK()) { + axis_ = 1; + } + } + + Status Compute(OpKernelContext* context) const override; + + private: + int64_t axis_; +}; + +template +class QuantizeLinear final : public OpKernel { + public: + explicit QuantizeLinear(const OpKernelInfo& info) : OpKernel(info) { + if (!info.GetAttr("axis", &axis_).IsOK()) { + axis_ = 1; + } + if (!info.GetAttr("saturate", &saturate_).IsOK()) { + saturate_ = 1; + } + } + + Status Compute(OpKernelContext* context) const override; + + private: + int64_t axis_; + int64_t saturate_; +}; + static void PrepareForQDQ(const TensorShape& input_shape, const Tensor& scale, const Tensor* zero_point_ptr, @@ -40,16 +77,27 @@ static void PrepareForQDQ(const TensorShape& input_shape, } } -#define REGISTER_DEQUANTIZELINEAR(T) \ - ONNX_CPU_OPERATOR_TYPED_KERNEL( \ +#define REGISTER_DEQUANTIZELINEAR(T) \ + ONNX_CPU_OPERATOR_TYPED_KERNEL( \ + DequantizeLinear, \ + 19, \ + T, \ + KernelDefBuilder() \ + .TypeConstraint("T1", DataTypeImpl::GetTensorType()) \ + .TypeConstraint("T2", {DataTypeImpl::GetTensorType(), \ + DataTypeImpl::GetTensorType()}), \ + DequantizeLinear); + +#define REGISTER_DEQUANTIZELINEAR_VERSIONED(T) \ + ONNX_CPU_OPERATOR_VERSIONED_TYPED_KERNEL( \ DequantizeLinear, \ 13, \ + 18, \ T, \ KernelDefBuilder() \ .TypeConstraint("T", DataTypeImpl::GetTensorType()), \ - DequantizeLinear); - -#define REGISTER_DEQUANTIZELINEAR_VERSIONED(T) \ + DequantizeLinear); \ + \ ONNX_CPU_OPERATOR_VERSIONED_TYPED_KERNEL( \ DequantizeLinear, \ 10, \ @@ -62,10 +110,108 @@ static void PrepareForQDQ(const TensorShape& input_shape, REGISTER_DEQUANTIZELINEAR(int8_t) REGISTER_DEQUANTIZELINEAR(uint8_t) REGISTER_DEQUANTIZELINEAR(int32_t) +#if !defined(DISABLE_FLOAT8_TYPES) +REGISTER_DEQUANTIZELINEAR(Float8E4M3FN) +REGISTER_DEQUANTIZELINEAR(Float8E4M3FNUZ) +REGISTER_DEQUANTIZELINEAR(Float8E5M2) +REGISTER_DEQUANTIZELINEAR(Float8E5M2FNUZ) +#endif REGISTER_DEQUANTIZELINEAR_VERSIONED(int8_t) REGISTER_DEQUANTIZELINEAR_VERSIONED(uint8_t) REGISTER_DEQUANTIZELINEAR_VERSIONED(int32_t) +#if !defined(DISABLE_CONTRIB_OPS) +namespace contrib { + +// Register alternate MS domain versions of the DequantizeLinear kernel. +// The MS domain versions additionally support 16-bit integer quantization types. +ONNX_CPU_OPERATOR_TYPED_MS_KERNEL( + DequantizeLinear, + 1, + uint8_t, + KernelDefBuilder() + .TypeConstraint("T1", DataTypeImpl::GetTensorType()) + .TypeConstraint("T2", DataTypeImpl::GetTensorType()), + DequantizeLinear); + +ONNX_CPU_OPERATOR_TYPED_MS_KERNEL( + DequantizeLinear, + 1, + int8_t, + KernelDefBuilder() + .TypeConstraint("T1", DataTypeImpl::GetTensorType()) + .TypeConstraint("T2", DataTypeImpl::GetTensorType()), + DequantizeLinear); + +ONNX_CPU_OPERATOR_TYPED_MS_KERNEL( + DequantizeLinear, + 1, + uint16_t, + KernelDefBuilder() + .TypeConstraint("T1", DataTypeImpl::GetTensorType()) + .TypeConstraint("T2", DataTypeImpl::GetTensorType()), + DequantizeLinear); + +ONNX_CPU_OPERATOR_TYPED_MS_KERNEL( + DequantizeLinear, + 1, + int16_t, + KernelDefBuilder() + .TypeConstraint("T1", DataTypeImpl::GetTensorType()) + .TypeConstraint("T2", DataTypeImpl::GetTensorType()), + DequantizeLinear); + +ONNX_CPU_OPERATOR_TYPED_MS_KERNEL( + DequantizeLinear, + 1, + int32_t, + KernelDefBuilder() + .TypeConstraint("T1", DataTypeImpl::GetTensorType()) + .TypeConstraint("T2", DataTypeImpl::GetTensorType()), + DequantizeLinear); + +} // namespace contrib +#endif // !defined(DISABLE_CONTRIB_OPS) + +template +struct DequantizeLinearApply { + void op(int64_t N, int64_t broadcast_dim, int64_t block_size, const T* input, const OutT* scale, OutT* output, const T* zero_point) { + for (size_t n = 0; n < static_cast(N); n++) { + for (size_t bd = 0; bd < static_cast(broadcast_dim); bd++) { + auto zp = zero_point ? static_cast(zero_point[bd]) : 0; + auto sc = static_cast(scale[bd]); + for (size_t bs = 0; bs < static_cast(block_size); bs++) { + *output++ = static_cast(static_cast(static_cast(*input++) - zp) * sc); + } + } + } + } +}; + +#if !defined(DISABLE_FLOAT8_TYPES) + +#define DEQUANTIZE_LINEAR_APPLY_FLOAT8(T) \ + template \ + struct DequantizeLinearApply { \ + void op(int64_t N, int64_t broadcast_dim, int64_t block_size, const T* input, const OutT* scale, OutT* output, const T*) { \ + for (size_t n = 0; n < static_cast(N); n++) { \ + for (size_t bd = 0; bd < static_cast(broadcast_dim); bd++) { \ + auto sc = scale[bd]; \ + for (size_t bs = 0; bs < static_cast(block_size); bs++, input++) { \ + *output++ = static_cast(input->ToFloat() * sc); \ + } \ + } \ + } \ + } \ + }; + +DEQUANTIZE_LINEAR_APPLY_FLOAT8(Float8E4M3FN) +DEQUANTIZE_LINEAR_APPLY_FLOAT8(Float8E4M3FNUZ) +DEQUANTIZE_LINEAR_APPLY_FLOAT8(Float8E5M2) +DEQUANTIZE_LINEAR_APPLY_FLOAT8(Float8E5M2FNUZ) + +#endif + // formula is Y = (X - ZeroPoint) * Scale template Status DequantizeLinear::Compute(OpKernelContext* ctx) const { @@ -82,44 +228,62 @@ Status DequantizeLinear::Compute(OpKernelContext* ctx) const { PrepareForQDQ(x.Shape(), x_scale, x_zero_point, axis_, N, broadcast_dim, block_size); - const float* scale = x_scale.Data(); - const T* input = x.Data(); - float* output = y.MutableData(); - const T* zero_point = x_zero_point ? x_zero_point->Data() : nullptr; - if (std::is_same::value) { + +#if !defined(DISABLE_FLOAT8_TYPES) + if constexpr (boost::mp11::mp_contains>, + T>::value) { ORT_ENFORCE(zero_point == nullptr || std::all_of(zero_point, zero_point + x_zero_point->Shape().Size(), - [](int32_t zp) { return zp == 0; }), - "DequantizeLinear with type int32 should have no zero point or all zero points should be 0"); + [](T zp) { return zp == T{0}; }), + "DequantizeLinear with type int32 or float8 should have no zero point or all zero points should be 0"); } +#endif - for (size_t n = 0; n < static_cast(N); n++) { - for (size_t bd = 0; bd < static_cast(broadcast_dim); bd++) { - auto zp = zero_point ? static_cast(zero_point[bd]) : 0; - auto sc = scale[bd]; + const auto to = x_scale.GetElementType(); + const T* input = x.Data(); - for (size_t bs = 0; bs < static_cast(block_size); bs++) { - *output++ = static_cast(static_cast(*input++) - zp) * sc; - } - } + if (to == ONNX_NAMESPACE::TensorProto::FLOAT) { + const float* scale = x_scale.Data(); + float* output = y.MutableData(); + DequantizeLinearApply().op(N, broadcast_dim, block_size, input, scale, output, zero_point); + } else if (to == ONNX_NAMESPACE::TensorProto::FLOAT16) { + const MLFloat16* scale = x_scale.Data(); + MLFloat16* output = y.MutableData(); + DequantizeLinearApply().op(N, broadcast_dim, block_size, input, scale, output, zero_point); + } else if (to == ONNX_NAMESPACE::TensorProto::BFLOAT16) { + ORT_THROW("DequantizeLinear into BFLOAT16 is not implemented yet."); + } else { + ORT_THROW("DequantizeLinear only outputs FLOAT16, FLOAT or BFLOAT16."); } return Status::OK(); } -#define REGISTER_QUANTIZELINEAR(T) \ - ONNX_CPU_OPERATOR_TYPED_KERNEL( \ +#define REGISTER_QUANTIZELINEAR(T) \ + ONNX_CPU_OPERATOR_TYPED_KERNEL( \ + QuantizeLinear, \ + 19, \ + T, \ + KernelDefBuilder() \ + .TypeConstraint("T1", {DataTypeImpl::GetTensorType(), \ + DataTypeImpl::GetTensorType()}) \ + .TypeConstraint("T2", DataTypeImpl::GetTensorType()), \ + QuantizeLinear); + +#define REGISTER_QUANTIZELINEAR_VERSIONED(T) \ + ONNX_CPU_OPERATOR_VERSIONED_TYPED_KERNEL( \ QuantizeLinear, \ 13, \ + 18, \ T, \ KernelDefBuilder() \ .TypeConstraint("T1", DataTypeImpl::GetTensorType()) \ .TypeConstraint("T2", DataTypeImpl::GetTensorType()), \ - QuantizeLinear); - -#define REGISTER_QUANTIZELINEAR_VERSIONED(T) \ + QuantizeLinear); \ + \ ONNX_CPU_OPERATOR_VERSIONED_TYPED_KERNEL( \ QuantizeLinear, \ 10, \ @@ -132,9 +296,92 @@ Status DequantizeLinear::Compute(OpKernelContext* ctx) const { REGISTER_QUANTIZELINEAR(int8_t) REGISTER_QUANTIZELINEAR(uint8_t) + +#if !defined(DISABLE_FLOAT8_TYPES) +REGISTER_QUANTIZELINEAR(Float8E4M3FN) +REGISTER_QUANTIZELINEAR(Float8E4M3FNUZ) +REGISTER_QUANTIZELINEAR(Float8E5M2) +REGISTER_QUANTIZELINEAR(Float8E5M2FNUZ) +#endif + REGISTER_QUANTIZELINEAR_VERSIONED(int8_t) REGISTER_QUANTIZELINEAR_VERSIONED(uint8_t) +#if !defined(DISABLE_CONTRIB_OPS) +namespace contrib { + +// Register alternate MS domain versions of the QuantizeLinear kernel. +// The MS domain versions additionally support 16-bit integer quantization types. +ONNX_CPU_OPERATOR_TYPED_MS_KERNEL( + QuantizeLinear, + 1, + uint8_t, + KernelDefBuilder() + .TypeConstraint("T1", DataTypeImpl::GetTensorType()) + .TypeConstraint("T2", DataTypeImpl::GetTensorType()), + QuantizeLinear); + +ONNX_CPU_OPERATOR_TYPED_MS_KERNEL( + QuantizeLinear, + 1, + int8_t, + KernelDefBuilder() + .TypeConstraint("T1", DataTypeImpl::GetTensorType()) + .TypeConstraint("T2", DataTypeImpl::GetTensorType()), + QuantizeLinear); + +ONNX_CPU_OPERATOR_TYPED_MS_KERNEL( + QuantizeLinear, + 1, + uint16_t, + KernelDefBuilder() + .TypeConstraint("T1", DataTypeImpl::GetTensorType()) + .TypeConstraint("T2", DataTypeImpl::GetTensorType()), + QuantizeLinear); + +ONNX_CPU_OPERATOR_TYPED_MS_KERNEL( + QuantizeLinear, + 1, + int16_t, + KernelDefBuilder() + .TypeConstraint("T1", DataTypeImpl::GetTensorType()) + .TypeConstraint("T2", DataTypeImpl::GetTensorType()), + QuantizeLinear); +} // namespace contrib +#endif // !defined(DISABLE_CONTRIB_OPS) + +template +void ParQuantizeLinear(const InputType* Input, + OutputType* Output, + size_t N, + InputType Scale, + size_t bd, + const OutputType* ZeroPoint, + bool saturate, + concurrency::ThreadPool* thread_pool) { +#if !defined(DISABLE_FLOAT8_TYPES) + if constexpr (!boost::mp11::mp_contains::value) { +#endif + ORT_UNUSED_PARAMETER(saturate); + ParQuantizeLinearStd(Input, Output, N, Scale, ZeroPoint != nullptr ? ZeroPoint[bd] : (OutputType)0, thread_pool); +#if !defined(DISABLE_FLOAT8_TYPES) + } else { + ParQuantizeLinearSat(Input, Output, N, Scale, ZeroPoint != nullptr ? ZeroPoint[bd] : OutputType(static_cast(static_cast(0)), true), saturate, thread_pool); + } +#endif +} + +template +void ComputeLoop(OpKernelContext* ctx, const InT* input, const InT* scale, const T* zero_point, T* output, int64_t N, int64_t broadcast_dim, int64_t block_size, bool saturate) { + for (size_t n = 0; n < static_cast(N); n++) { + for (size_t bd = 0; bd < static_cast(broadcast_dim); bd++) { + ParQuantizeLinear(input, output, static_cast(block_size), scale[bd], bd, zero_point, saturate, ctx->GetOperatorThreadPool()); + input += block_size; + output += block_size; + } + } +} + // formula is Y = X / Scale + ZeroPoint template Status QuantizeLinear::Compute(OpKernelContext* ctx) const { @@ -150,20 +397,16 @@ Status QuantizeLinear::Compute(OpKernelContext* ctx) const { PrepareForQDQ(x.Shape(), y_scale, y_zero_point, axis_, N, broadcast_dim, block_size); const T* zero_point = y_zero_point != nullptr ? y_zero_point->Data() : nullptr; - const float* scale = y_scale.Data(); - const float* input = x.Data(); T* output = y.MutableData(); - for (size_t n = 0; n < static_cast(N); n++) { - for (size_t bd = 0; bd < static_cast(broadcast_dim); bd++) { - T zp = zero_point != nullptr ? zero_point[bd] : 0; - ParQuantizeLinear(input, output, static_cast(block_size), scale[bd], zp, ctx->GetOperatorThreadPool()); - input += block_size; - output += block_size; - } + if (x.IsDataType()) { + ComputeLoop(ctx, x.Data(), y_scale.Data(), zero_point, output, N, broadcast_dim, block_size, saturate_); + } else if (x.IsDataType()) { + ComputeLoop(ctx, x.Data(), y_scale.Data(), zero_point, output, N, broadcast_dim, block_size, saturate_); + } else { + ORT_THROW("Unsupported input type."); } return Status::OK(); } - } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cpu/quantization/quantize_linear.h b/onnxruntime/core/providers/cpu/quantization/quantize_linear.h deleted file mode 100644 index 9f443f1439030..0000000000000 --- a/onnxruntime/core/providers/cpu/quantization/quantize_linear.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#include "core/common/common.h" -#include "core/framework/op_kernel.h" -#include "core/util/math_cpuonly.h" - -namespace onnxruntime { - -template -class DequantizeLinear final : public OpKernel { - public: - DequantizeLinear(const OpKernelInfo& info) : OpKernel(info) { - if (!info.GetAttr("axis", &axis_).IsOK()) { - axis_ = 1; - } - } - - Status Compute(OpKernelContext* context) const override; - - private: - int64_t axis_; -}; - -template -class QuantizeLinear final : public OpKernel { - public: - QuantizeLinear(const OpKernelInfo& info) : OpKernel(info) { - if (!info.GetAttr("axis", &axis_).IsOK()) { - axis_ = 1; - } - } - - Status Compute(OpKernelContext* context) const override; - - private: - int64_t axis_; -}; -} // namespace onnxruntime diff --git a/onnxruntime/core/providers/cpu/reduction/reduction_ops.cc b/onnxruntime/core/providers/cpu/reduction/reduction_ops.cc index 120cac7e48bfb..ce834e371fdef 100644 --- a/onnxruntime/core/providers/cpu/reduction/reduction_ops.cc +++ b/onnxruntime/core/providers/cpu/reduction/reduction_ops.cc @@ -595,10 +595,14 @@ FastReduceKind OptimizeShapeForFastReduce(gsl::span input_shape, TensorShapeVector& fast_axes, bool keep_dims, bool noop_with_empty_axes) { if (input_shape.empty()) { - fast_shape.assign(input_shape.begin(), input_shape.end()); - fast_output_shape = fast_shape; - fast_axes.assign(reduced_axes.begin(), reduced_axes.end()); - return FastReduceKind::kNone; + fast_shape.clear(); + fast_output_shape.clear(); + // XXX: Should we enforce the absence of the axes in the scalar input case? + // The operator spec refers to Numpy which returns error because axes can not possibly contain any valid + // value in scalar case, but pytorch simply ignores it. + // ORT_ENFORCE(reduced_axes.empty(), "With scalar input shape, axis can not contain valid values"); + fast_axes.clear(); + return FastReduceKind::kEmpty; } InlinedHashSet axes; @@ -886,49 +890,49 @@ Status ReduceL1::Compute(OpKernelContext* ctx) const { // The following variable does not change if the input tensor and the // axes do not either. It could be either cached in ctx or precomputed // in the constructor if shape and axes are known at this stage. - CommonReduce1Loop>(ctx, axes_, keepdims_); + CommonReduce1Loop>(ctx, axes_, keepdims_, noop_with_empty_axes_); return Status::OK(); } template Status ReduceL2::Compute(OpKernelContext* ctx) const { - CommonReduce1Loop>(ctx, axes_, keepdims_); + CommonReduce1Loop>(ctx, axes_, keepdims_, noop_with_empty_axes_); return Status::OK(); } template Status ReduceLogSum::Compute(OpKernelContext* ctx) const { - CommonReduce1Loop>(ctx, axes_, keepdims_); + CommonReduce1Loop>(ctx, axes_, keepdims_, noop_with_empty_axes_); return Status::OK(); } template Status ReduceLogSumExp::Compute(OpKernelContext* ctx) const { - CommonReduce2Loops>(ctx, axes_, keepdims_); + CommonReduce2Loops>(ctx, axes_, keepdims_, noop_with_empty_axes_); return Status::OK(); } template Status ReduceMax::Compute(OpKernelContext* ctx) const { - CommonReduce1Loop>(ctx, axes_, keepdims_); + CommonReduce1Loop>(ctx, axes_, keepdims_, noop_with_empty_axes_); return Status::OK(); } template Status ReduceMean::Compute(OpKernelContext* ctx) const { - CommonReduce1Loop>(ctx, axes_, keepdims_); + CommonReduce1Loop>(ctx, axes_, keepdims_, noop_with_empty_axes_); return Status::OK(); } template Status ReduceMin::Compute(OpKernelContext* ctx) const { - CommonReduce1Loop>(ctx, axes_, keepdims_); + CommonReduce1Loop>(ctx, axes_, keepdims_, noop_with_empty_axes_); return Status::OK(); } template Status ReduceProd::Compute(OpKernelContext* ctx) const { - CommonReduce1Loop>(ctx, axes_, keepdims_); + CommonReduce1Loop>(ctx, axes_, keepdims_, noop_with_empty_axes_); return Status::OK(); } @@ -1013,7 +1017,7 @@ std::unique_ptr ReduceSum::Impl(const Tensor& input, gsl::span Status ReduceSumSquare::Compute(OpKernelContext* ctx) const { - CommonReduce1Loop>(ctx, axes_, keepdims_); + CommonReduce1Loop>(ctx, axes_, keepdims_, noop_with_empty_axes_); return Status::OK(); } diff --git a/onnxruntime/core/providers/cpu/rnn/deep_cpu_gru.cc b/onnxruntime/core/providers/cpu/rnn/deep_cpu_gru.cc index 1e3e9e4c6005f..b78c5236e6fab 100644 --- a/onnxruntime/core/providers/cpu/rnn/deep_cpu_gru.cc +++ b/onnxruntime/core/providers/cpu/rnn/deep_cpu_gru.cc @@ -162,89 +162,6 @@ ONNX_CPU_OPERATOR_KERNEL( using namespace rnn::detail; -// internal helper code -namespace detail { - -template -class UniDirectionalGru { - public: - UniDirectionalGru(AllocatorPtr allocator, int seq_length, int batch_size, int input_size, int hidden_size, - bool linear_before_reset, Direction direction, gsl::span bias, - gsl::span initial_hidden_state, const ActivationFuncs::Entry& activation_func_f, - const ActivationFuncs::Entry& activation_func_g, float clip, - onnxruntime::concurrency::ThreadPool* ttp); - - void Compute(gsl::span inputs, gsl::span sequence_lengths, int num_directions, - const GemmWeights& input_weights, - const GemmWeights& recurrent_weights_ZR, - const GemmWeights& recurrent_weights_H, - gsl::span& outputs, gsl::span& final_hidden_state); - - ~UniDirectionalGru() = default; - - private: - AllocatorPtr allocator_; - - int seq_length_; - int batch_size_; - int input_size_; - int hidden_size_; - bool linear_before_reset_; - - const float clip_; - - Direction direction_; - bool use_bias_; - - IAllocatorUniquePtr outputZRH_ptr_; - gsl::span outputZRH_; - - IAllocatorUniquePtr cur_h_ptr_; - IAllocatorUniquePtr batched_hidden0_ptr_; - IAllocatorUniquePtr sequence_lengths_ptr_; - gsl::span cur_h_; - gsl::span batched_hidden0_; - gsl::span sequence_lengths_; - - // Wb[zr] and Rb[zr] can always be added together upfront, and repeated to match the batch size for - // faster GEMM calculations, so these two members are all the - // Wb[z] + Rb[z] values added together, repeated batch_size_ times - IAllocatorUniquePtr batched_bias_WRz_ptr_, batched_bias_WRr_ptr_; - gsl::span batched_bias_WRz_, batched_bias_WRr_; - - // Wbh and Rbh can only be combined upfront if linear_before_reset_ is false - IAllocatorUniquePtr batched_bias_WRh_ptr_; - gsl::span batched_bias_WRh_; - - // if linear_before_reset_ is true, we need to setup Wbh and Rbh separately - IAllocatorUniquePtr batched_bias_Wh_ptr_, batched_bias_Rh_ptr_; - gsl::span batched_bias_Wh_, batched_bias_Rh_; - - IAllocatorUniquePtr linear_output_ptr_; - gsl::span linear_output_; - - IAllocatorUniquePtr inputs_reverse_ptr_; - IAllocatorUniquePtr outputs_reverse_ptr_; - gsl::span inputs_reverse_; - gsl::span outputs_reverse_; - - deepcpu::ClipWithBiasFuncPtr clip_with_bias_ptr_{}; - - float zr_alpha_{}; - float zr_beta_{}; - float h_alpha_{}; - float h_beta_{}; - - deepcpu::GruResetGateFuncPtr reset_gate_{}; - deepcpu::ActivationFuncPtr update_gate_{}; - deepcpu::GruOutputGateFuncPtr output_gate_{}; - - void AllocateBuffers(); - - onnxruntime::concurrency::ThreadPool* ttp_; -}; -} // namespace detail - // #define DUMP_MATRIXES to provide lots of diagnostic output #if defined(DUMP_MATRIXES) #define DumpMatrix(...) onnxruntime::rnn::detail::DumpMatrixImpl(__VA_ARGS__) @@ -274,13 +191,14 @@ bool DeepCpuGruOp::TryPackInputWeights(const Tensor& weights, AllocatorPtr& allo } const size_t buffer_size = SafeInt(packed_weights_size) * num_directions; - auto* packed_weights_data = alloc->Alloc(buffer_size); + pre_packed_input_weights_.buffer_ = IAllocator::MakeUniquePtr(alloc, buffer_size, true); + + std::byte* packed_weights_data = static_cast(pre_packed_input_weights_.buffer_.get()); // Initialize memory to 0 as there could be some padding associated with pre-packed // buffer memory and we don not want it uninitialized and generate different hashes // if and when we try to cache this pre-packed buffer for sharing between sessions. memset(packed_weights_data, 0, buffer_size); - pre_packed_input_weights_.buffer_ = BufferUniquePtr(packed_weights_data, BufferDeleter(alloc)); pre_packed_input_weights_.buffer_size_ = buffer_size; pre_packed_input_weights_.shape_ = shape; pre_packed_input_weights_.weights_size_ = packed_weights_size; @@ -290,7 +208,7 @@ bool DeepCpuGruOp::TryPackInputWeights(const Tensor& weights, AllocatorPtr& allo for (int64_t dir = 0; dir < num_directions; ++dir) { MlasGemmPackB(CblasTrans, N, K, weights_data, K, packed_weights_data); weights_data += N_x_K; - packed_weights_data = static_cast(packed_weights_data) + packed_weights_size; + packed_weights_data += packed_weights_size; } return true; @@ -328,19 +246,19 @@ bool DeepCpuGruOp::TryPackRecurrentWeights(const Tensor& weights, AllocatorPtr& } const size_t buffer_size_ZR = SafeInt(ZR_packed_size) * num_directions; const size_t buffer_size_H = SafeInt(H_packed_size) * num_directions; + pre_packed_recurrent_ZR_.buffer_ = IAllocator::MakeUniquePtr(alloc, buffer_size_ZR, true); - auto* buffer_ZR = alloc->Alloc(buffer_size_ZR); + auto* buffer_ZR = pre_packed_recurrent_ZR_.buffer_.get(); memset(buffer_ZR, 0, buffer_size_ZR); - pre_packed_recurrent_ZR_.buffer_ = BufferUniquePtr(buffer_ZR, BufferDeleter(alloc)); pre_packed_recurrent_ZR_.buffer_size_ = buffer_size_ZR; pre_packed_recurrent_ZR_.shape_ = shape; // original shape, not used in prepacked calculations, but useful for validation pre_packed_recurrent_ZR_.weights_size_ = ZR_packed_size; - auto* buffer_H = alloc->Alloc(buffer_size_H); + pre_packed_recurrent_H_.buffer_ = IAllocator::MakeUniquePtr(alloc, buffer_size_H, true); + auto* buffer_H = pre_packed_recurrent_H_.buffer_.get(); memset(buffer_H, 0, buffer_size_H); - pre_packed_recurrent_H_.buffer_ = BufferUniquePtr(buffer_H, BufferDeleter(alloc)); pre_packed_recurrent_H_.buffer_size_ = buffer_size_H; pre_packed_recurrent_H_.shape_ = shape; // original shape, not used in prepacked calculations, but useful for validation pre_packed_recurrent_H_.weights_size_ = H_packed_size; @@ -614,7 +532,8 @@ UniDirectionalGru::UniDirectionalGru(AllocatorPtr allocator, gsl::span initial_hidden_state, const ActivationFuncs::Entry& activation_func_f, const ActivationFuncs::Entry& activation_func_g, - const float clip, onnxruntime::concurrency::ThreadPool* ttp) + const float clip, onnxruntime::concurrency::ThreadPool* ttp, + const bool training_mode) : allocator_(std::move(allocator)), seq_length_(seq_length), batch_size_(batch_size), @@ -624,7 +543,8 @@ UniDirectionalGru::UniDirectionalGru(AllocatorPtr allocator, clip_(clip), direction_(direction), use_bias_(!bias.empty()), - ttp_(ttp) { + ttp_(ttp), + training_mode_(training_mode) { clip_with_bias_ptr_ = use_bias_ ? deepcpu::clip_add_bias : deepcpu::clip_ignore_bias; // setup activation function pointers and alpha/beta values to use with them @@ -691,6 +611,36 @@ void UniDirectionalGru::Compute(gsl::span inputs_arg, const GemmWeights& recurrent_weightsH_s, gsl::span& outputs, gsl::span& final_hidden_state) { + ComputeImpl(inputs_arg, sequence_lengths_arg, num_directions, + input_weights_s, recurrent_weightsZR_s, recurrent_weightsH_s, + outputs, final_hidden_state, outputZRH_); +} + +template +void UniDirectionalGru::Compute(gsl::span inputs_arg, + gsl::span sequence_lengths_arg, + const int num_directions, + const GemmWeights& input_weights_s, + const GemmWeights& recurrent_weightsZR_s, + const GemmWeights& recurrent_weightsH_s, + gsl::span& outputs, + gsl::span& final_hidden_state, + gsl::span& zrh) { + ComputeImpl(inputs_arg, sequence_lengths_arg, num_directions, + input_weights_s, recurrent_weightsZR_s, recurrent_weightsH_s, + outputs, final_hidden_state, zrh); +} + +template +void UniDirectionalGru::ComputeImpl(gsl::span inputs_arg, + gsl::span sequence_lengths_arg, + const int num_directions, + const GemmWeights& input_weights_s, + const GemmWeights& recurrent_weightsZR_s, + const GemmWeights& recurrent_weightsH_s, + gsl::span& outputs, + gsl::span& final_hidden_state, + gsl::span& zrh) { using span_T_const_iter = typename gsl::span::iterator; using span_T_iter = typename gsl::span::iterator; @@ -752,7 +702,7 @@ void UniDirectionalGru::Compute(gsl::span inputs_arg, input_size_, input_weights.begin(), input_weights.end(), input_size_, 0.f, - outputZRH_.begin(), outputZRH_.end(), + zrh.begin(), zrh.end(), hidden_size_x3, ttp_); } else { MlasGemm( @@ -765,11 +715,11 @@ void UniDirectionalGru::Compute(gsl::span inputs_arg, static_cast(input_size_), input_weights_s.buffer_, 0.0f, - &*outputZRH_.begin(), + &*zrh.begin(), static_cast(hidden_size_x3), ttp_); } - DumpMatrix("inputs with weights applied", outputZRH_.data(), seq_length_ * batch_size_ * 3, hidden_size_); + DumpMatrix("inputs with weights applied", zrh.data(), seq_length_ * batch_size_ * 3, hidden_size_); // output shape is [seq_length, num_directions, batch_size, hidden_size] // if we are doing 2 directions and this is the forward pass we're writing to the real output so @@ -829,15 +779,15 @@ void UniDirectionalGru::Compute(gsl::span inputs_arg, out_added_offset = (step * batch_size_) * hidden_size_x3; - // calculate Ht-1*R[zr], and add to the weighted inputs that are in outputZRH_ + // calculate Ht-1*R[zr], and add to the weighted inputs that are in zrh // Ht-1 * R[zr] + Xt*(W[zr]^T) if (!recurrent_weightsZR_s.is_prepacked_) { ComputeGemm(batch_size_, hidden_size_x2, hidden_size_, alpha, prev_Ht, prev_Ht_end, hidden_size_, recurrent_weightsZR.begin(), recurrent_weightsZR.end(), - hidden_size_, 1.f, // beta == 1 so we add existing values in outputZRH_ - outputZRH_.begin() + out_added_offset, outputZRH_.end(), + hidden_size_, 1.f, // beta == 1 so we add existing values in zrh + zrh.begin() + out_added_offset, zrh.end(), hidden_size_x3, ttp_); } else { MlasGemm( @@ -847,12 +797,12 @@ void UniDirectionalGru::Compute(gsl::span inputs_arg, static_cast(hidden_size_), recurrent_weightsZR_s.buffer_, 1.f, - &*(outputZRH_.begin() + out_added_offset), + &*(zrh.begin() + out_added_offset), static_cast(hidden_size_x3), ttp_); } DumpMatrix("Ht-1 * R[zr] + Xt*(W[zr]^T)" + seqno_str, - outputZRH_.data() + out_added_offset, batch_size_, hidden_size_x2, 0, hidden_size_x3); + zrh.data() + out_added_offset, batch_size_, hidden_size_x2, 0, hidden_size_x3); if (linear_before_reset_) { // copy Rbh to linear output @@ -894,8 +844,8 @@ void UniDirectionalGru::Compute(gsl::span inputs_arg, batched_bias_WRr_local_end, hidden_size_) : nullptr; - // initialize p_rt with input to calculate rt. outputZRH_ has Xt*(Wr^T) + Ht-1*(Rr^T). - T* p_rt = SafeRawPointer(outputZRH_, out_added_offset + r * hidden_size_x3 + hidden_size_, hidden_size_); + // initialize p_rt with input to calculate rt. zrh has Xt*(Wr^T) + Ht-1*(Rr^T). + T* p_rt = SafeRawPointer(zrh, out_added_offset + r * hidden_size_x3 + hidden_size_, hidden_size_); // add the bias and clip. post: p_rt == Xt*(Wr^T) + Ht-1*(Rr^T) + Wbr + Rbr clip_with_bias_ptr_(clip_, p_bias_r, p_rt, hidden_size_); @@ -928,7 +878,7 @@ void UniDirectionalGru::Compute(gsl::span inputs_arg, // input contains rt (.) (Ht-1*(Rh^T) + Rbh) auto input = cur_h_local; // out_H currently contains Xt*(W[zrh]^T). - auto out_H = outputZRH_.begin() + out_added_offset; + auto out_H = zrh.begin() + out_added_offset; for (int r = 0; r < batch_size_; r++) { // skip over the inputs with Z and R weights @@ -945,7 +895,7 @@ void UniDirectionalGru::Compute(gsl::span inputs_arg, #endif // out_H currently contains Xt*(Wh^T). - auto out_H = outputZRH_.begin() + out_added_offset + hidden_size_x2; + auto out_H = zrh.begin() + out_added_offset + hidden_size_x2; // Calculate Xt*(Wh^T) + rt (.) Ht-1 * Rh if (!recurrent_weightsH_s.is_prepacked_) { @@ -954,7 +904,7 @@ void UniDirectionalGru::Compute(gsl::span inputs_arg, hidden_size_, recurrent_weightsH.begin(), recurrent_weightsH.end(), // Rh^T hidden_size_, 1.f, // beta == 1 to add Xt*(Wh^T) from out_H - out_H, outputZRH_.end(), + out_H, zrh.end(), hidden_size_x3, ttp_); } else { MlasGemm( @@ -969,7 +919,7 @@ void UniDirectionalGru::Compute(gsl::span inputs_arg, } } - DumpMatrix("Xt*(Wh^T) + (" + label + ")" + seqno_str, outputZRH_.data() + out_added_offset, + DumpMatrix("Xt*(Wh^T) + (" + label + ")" + seqno_str, zrh.data() + out_added_offset, batch_size_, hidden_size_, hidden_size_x2, hidden_size_x3); // 2nd Set of Activations @@ -1001,7 +951,7 @@ void UniDirectionalGru::Compute(gsl::span inputs_arg, : nullptr; // initialize p_zt with Xt*(Wz^T) + Ht-1*(Rz^T), which is most of the input to calculate zt: - T* p_zt = SafeRawPointer(outputZRH_, out_added_offset + r * hidden_size_x3, hidden_size_); + T* p_zt = SafeRawPointer(zrh, out_added_offset + r * hidden_size_x3, hidden_size_); // using p_zt, add bias and clip in-place clip_with_bias_ptr_(clip_, p_bias_z, p_zt, hidden_size_); @@ -1028,7 +978,7 @@ void UniDirectionalGru::Compute(gsl::span inputs_arg, // setup p_ht with input to calculate ht // p_ht = Xt*(Wh^T) + (rt (.) Ht-1 * Rh^T) # linear_before_reset_ == false // = Xt*(Wh^T) + (rt (.) (Ht-1*(Rh^T) + Rbh)) # linear_before_reset_ == true - T* p_ht = SafeRawPointer(outputZRH_, out_added_offset + r * hidden_size_x3 + hidden_size_x2, hidden_size_); + T* p_ht = SafeRawPointer(zrh, out_added_offset + r * hidden_size_x3 + hidden_size_x2, hidden_size_); // add Wbh [and Wrh] and clip clip_with_bias_ptr_(clip_, p_bias_h, p_ht, hidden_size_); // post: p_ht == input to g() for calculating ht @@ -1110,7 +1060,9 @@ void UniDirectionalGru::AllocateBuffers() { auto batch_times_seq_length = batch_size_ * seq_length_; - outputZRH_ = Allocate(allocator_, hidden_size_ * 3 * batch_times_seq_length, outputZRH_ptr_, true); + if (!training_mode_) { + outputZRH_ = Allocate(allocator_, hidden_size_ * 3 * batch_times_seq_length, outputZRH_ptr_, true); + } if (direction_ == kReverse) { inputs_reverse_ = Allocate(allocator_, batch_times_seq_length * input_size_, inputs_reverse_ptr_); @@ -1118,5 +1070,7 @@ void UniDirectionalGru::AllocateBuffers() { } } +template class UniDirectionalGru; + } // namespace detail } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cpu/rnn/deep_cpu_gru.h b/onnxruntime/core/providers/cpu/rnn/deep_cpu_gru.h index c893c4046815d..5a6dd97c7c3f2 100644 --- a/onnxruntime/core/providers/cpu/rnn/deep_cpu_gru.h +++ b/onnxruntime/core/providers/cpu/rnn/deep_cpu_gru.h @@ -95,4 +95,106 @@ class DeepCpuGruOp final : public OpKernel { Status ComputeImpl(OpKernelContext& context) const; }; +namespace detail { + +template +class UniDirectionalGru { + public: + UniDirectionalGru(AllocatorPtr allocator, int seq_length, int batch_size, int input_size, int hidden_size, + bool linear_before_reset, rnn::detail::Direction direction, gsl::span bias, + gsl::span initial_hidden_state, const rnn::detail::ActivationFuncs::Entry& activation_func_f, + const rnn::detail::ActivationFuncs::Entry& activation_func_g, float clip, + onnxruntime::concurrency::ThreadPool* ttp, + const bool training_mode = false); + + void Compute(gsl::span inputs, gsl::span sequence_lengths, int num_directions, + const rnn::detail::GemmWeights& input_weights, + const rnn::detail::GemmWeights& recurrent_weights_ZR, + const rnn::detail::GemmWeights& recurrent_weights_H, + gsl::span& outputs, gsl::span& final_hidden_state); + + // This function overloads the above one by adding two additional reference inputs that are computed in this kernel: + // - zrh: intermediate gate computations + // This extra output is needed for training for gradient computation. + void Compute(gsl::span inputs, gsl::span sequence_lengths, int num_directions, + const rnn::detail::GemmWeights& input_weights, + const rnn::detail::GemmWeights& recurrent_weights_ZR, + const rnn::detail::GemmWeights& recurrent_weights_H, + gsl::span& outputs, gsl::span& final_hidden_state, + gsl::span& zrh); + + ~UniDirectionalGru() = default; + + private: + void ComputeImpl(gsl::span inputs, gsl::span sequence_lengths, int num_directions, + const rnn::detail::GemmWeights& input_weights, + const rnn::detail::GemmWeights& recurrent_weights_ZR, + const rnn::detail::GemmWeights& recurrent_weights_H, + gsl::span& outputs, gsl::span& final_hidden_state, + gsl::span& zrh); + + AllocatorPtr allocator_; + + int seq_length_; + int batch_size_; + int input_size_; + int hidden_size_; + bool linear_before_reset_; + + const float clip_; + + rnn::detail::Direction direction_; + bool use_bias_; + + IAllocatorUniquePtr outputZRH_ptr_; + gsl::span outputZRH_; + + IAllocatorUniquePtr cur_h_ptr_; + IAllocatorUniquePtr batched_hidden0_ptr_; + IAllocatorUniquePtr sequence_lengths_ptr_; + gsl::span cur_h_; + gsl::span batched_hidden0_; + gsl::span sequence_lengths_; + + // Wb[zr] and Rb[zr] can always be added together upfront, and repeated to match the batch size for + // faster GEMM calculations, so these two members are all the + // Wb[z] + Rb[z] values added together, repeated batch_size_ times + IAllocatorUniquePtr batched_bias_WRz_ptr_, batched_bias_WRr_ptr_; + gsl::span batched_bias_WRz_, batched_bias_WRr_; + + // Wbh and Rbh can only be combined upfront if linear_before_reset_ is false + IAllocatorUniquePtr batched_bias_WRh_ptr_; + gsl::span batched_bias_WRh_; + + // if linear_before_reset_ is true, we need to setup Wbh and Rbh separately + IAllocatorUniquePtr batched_bias_Wh_ptr_, batched_bias_Rh_ptr_; + gsl::span batched_bias_Wh_, batched_bias_Rh_; + + IAllocatorUniquePtr linear_output_ptr_; + gsl::span linear_output_; + + IAllocatorUniquePtr inputs_reverse_ptr_; + IAllocatorUniquePtr outputs_reverse_ptr_; + gsl::span inputs_reverse_; + gsl::span outputs_reverse_; + + rnn::detail::deepcpu::ClipWithBiasFuncPtr clip_with_bias_ptr_{}; + + float zr_alpha_{}; + float zr_beta_{}; + float h_alpha_{}; + float h_beta_{}; + + rnn::detail::deepcpu::GruResetGateFuncPtr reset_gate_{}; + rnn::detail::deepcpu::ActivationFuncPtr update_gate_{}; + rnn::detail::deepcpu::GruOutputGateFuncPtr output_gate_{}; + + void AllocateBuffers(); + + onnxruntime::concurrency::ThreadPool* ttp_; + + const bool training_mode_ = false; +}; +} // namespace detail + } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cpu/rnn/deep_cpu_lstm.cc b/onnxruntime/core/providers/cpu/rnn/deep_cpu_lstm.cc index fc1ed56f91980..09bbf6c4c79e6 100644 --- a/onnxruntime/core/providers/cpu/rnn/deep_cpu_lstm.cc +++ b/onnxruntime/core/providers/cpu/rnn/deep_cpu_lstm.cc @@ -195,14 +195,15 @@ Status DeepCpuLstmOp::TryPackWeights(const Tensor& weights, PackedWeights& packe } size_t packed_weights_data_size = SafeInt(packed_weights_size) * num_directions_; - auto* packed_weights_data = alloc->Alloc(packed_weights_data_size); + packed_weights.buffer_ = IAllocator::MakeUniquePtr(alloc, packed_weights_data_size, true); + + auto* packed_weights_data = packed_weights.buffer_.get(); // Initialize memory to 0 as there could be some padding associated with pre-packed // buffer memory and we don not want it uninitialized and generate different hashes // if and when we try to cache this pre-packed buffer for sharing between sessions. memset(packed_weights_data, 0, packed_weights_data_size); - packed_weights.buffer_ = BufferUniquePtr(packed_weights_data, BufferDeleter(alloc)); packed_weights.buffer_size_ = packed_weights_data_size; packed_weights.weights_size_ = packed_weights_size; packed_weights.shape_ = shape; diff --git a/onnxruntime/core/providers/cpu/rnn/rnn_helpers.cc b/onnxruntime/core/providers/cpu/rnn/rnn_helpers.cc index 7f742f4934b9c..9e865671e047d 100644 --- a/onnxruntime/core/providers/cpu/rnn/rnn_helpers.cc +++ b/onnxruntime/core/providers/cpu/rnn/rnn_helpers.cc @@ -269,7 +269,7 @@ void ComputeGemm(const int M, GetQuantizationParameter(A, M * K, a_scale, a_zero_point, thread_pool); // quantize the data - ParQuantizeLinear(A, quantized_A_buffer, M * K, a_scale, a_zero_point, thread_pool); + ParQuantizeLinearStd(A, quantized_A_buffer, M * K, a_scale, a_zero_point, thread_pool); bool b_is_signed = weights.quant_para_->is_signed; uint8_t b_zero_point = weights.quant_para_->zero_point ? *static_cast(weights.quant_para_->zero_point) : 0; @@ -573,7 +573,8 @@ void gru_reset_gate_tanh(const float* ps1, float* ps2, float* pd, int c, float a float q = x2 * beta_6 + beta_4; q = x2 * q + beta_2; q = x2 * q + beta_0; - pd[i] = ps1[i] * p / q; + ps2[i] = p / q; + pd[i] = ps1[i] * ps2[i]; } } @@ -596,7 +597,8 @@ void gru_reset_gate_sigmoid(const float* ps1, float* ps2, float* pd, int c, floa float q = x2 * beta_6 + beta_4; q = x2 * q + beta_2; q = x2 * q + beta_0; - pd[i] = ps1[i] * 0.5f * (1 + p / q); + ps2[i] = 0.5f * (1 + p / q); + pd[i] = ps1[i] * ps2[i]; } } @@ -636,7 +638,8 @@ void gru_output_gate_tanh(float* ph, const float* pz, const float* ps, float* po float q = x2 * beta_6 + beta_4; q = x2 * q + beta_2; q = x2 * q + beta_0; - po[i] = (1 - pz[i]) * (p / q) + pz[i] * ps[i]; + ph[i] = p / q; + po[i] = (1 - pz[i]) * ph[i] + pz[i] * ps[i]; } } diff --git a/onnxruntime/core/providers/cpu/rnn/rnn_helpers.h b/onnxruntime/core/providers/cpu/rnn/rnn_helpers.h index 90d310ef34b54..dfc7a2b68699c 100644 --- a/onnxruntime/core/providers/cpu/rnn/rnn_helpers.h +++ b/onnxruntime/core/providers/cpu/rnn/rnn_helpers.h @@ -163,7 +163,7 @@ void ComputeGemm(const int M, } struct PackedWeights { - BufferUniquePtr buffer_; + IAllocatorUniquePtr buffer_; size_t buffer_size_; size_t weights_size_; TensorShape shape_; diff --git a/onnxruntime/core/providers/cpu/sequence/sequence_ops.cc b/onnxruntime/core/providers/cpu/sequence/sequence_ops.cc index 578a3472ac10c..4759938cd8250 100644 --- a/onnxruntime/core/providers/cpu/sequence/sequence_ops.cc +++ b/onnxruntime/core/providers/cpu/sequence/sequence_ops.cc @@ -165,6 +165,20 @@ Status SequenceEmpty::Compute(OpKernelContext* context) const { case ONNX_NAMESPACE::TensorProto_DataType_BFLOAT16: seq_dtype = DataTypeImpl::GetType(); break; +#if !defined(DISABLE_FLOAT8_TYPES) + case ONNX_NAMESPACE::TensorProto_DataType_FLOAT8E4M3FN: + seq_dtype = DataTypeImpl::GetType(); + break; + case ONNX_NAMESPACE::TensorProto_DataType_FLOAT8E4M3FNUZ: + seq_dtype = DataTypeImpl::GetType(); + break; + case ONNX_NAMESPACE::TensorProto_DataType_FLOAT8E5M2: + seq_dtype = DataTypeImpl::GetType(); + break; + case ONNX_NAMESPACE::TensorProto_DataType_FLOAT8E5M2FNUZ: + seq_dtype = DataTypeImpl::GetType(); + break; +#endif default: ORT_THROW("Unsupported 'dtype' value: ", dtype_); } diff --git a/onnxruntime/core/providers/cpu/signal/dft.cc b/onnxruntime/core/providers/cpu/signal/dft.cc index da5515d12a378..8634e393b43d0 100644 --- a/onnxruntime/core/providers/cpu/signal/dft.cc +++ b/onnxruntime/core/providers/cpu/signal/dft.cc @@ -79,7 +79,7 @@ static inline T bit_reverse(T num, unsigned significant_bits) { template static T compute_angular_velocity(size_t number_of_samples, bool inverse) { // Calculate fundamental angular velocity - static constexpr T pi = static_cast(3.14159265); + static constexpr T pi = static_cast(M_PI); static constexpr T tau = 2 * pi; T inverse_switch = inverse ? 1.f : -1.f; T angular_velocity = inverse_switch * tau / number_of_samples; @@ -185,11 +185,10 @@ template T next_power_of_2(T in) { in--; T out = 1; - while (out < in) { - in |= in >> out; + while (out <= in) { out <<= 1; } - return in + 1; + return out; } template @@ -197,7 +196,7 @@ static Status dft_bluestein_z_chirp( OpKernelContext* ctx, const Tensor* X, Tensor* Y, Tensor& b_fft, Tensor& chirp, size_t X_offset, size_t X_stride, size_t Y_offset, size_t Y_stride, int64_t axis, size_t dft_length, const Tensor* window, bool inverse, InlinedVector>& V, InlinedVector>& temp_output) { - static constexpr T pi = static_cast(3.14159265); + static constexpr T pi = static_cast(M_PI); AllocatorPtr alloc; ORT_RETURN_IF_ERROR(ctx->GetTempSpaceAllocator(&alloc)); diff --git a/onnxruntime/core/providers/cpu/signal/window_functions.cc b/onnxruntime/core/providers/cpu/signal/window_functions.cc index 59fa721e30a55..fc4bad98e222f 100644 --- a/onnxruntime/core/providers/cpu/signal/window_functions.cc +++ b/onnxruntime/core/providers/cpu/signal/window_functions.cc @@ -53,7 +53,7 @@ struct CosineSumWindow { auto* Y_data = reinterpret_cast(Y->MutableDataRaw()); // Calculate the radians to increment per sample - constexpr double pi = 3.14159265; + constexpr double pi = M_PI; constexpr double tau = 2 * pi; const size_t denominator = is_periodic ? size : size - 1; const double angular_increment = tau / denominator; diff --git a/onnxruntime/core/providers/cpu/tensor/cast_op.cc b/onnxruntime/core/providers/cpu/tensor/cast_op.cc index 6442dbeddacb3..058f5572c9c83 100644 --- a/onnxruntime/core/providers/cpu/tensor/cast_op.cc +++ b/onnxruntime/core/providers/cpu/tensor/cast_op.cc @@ -4,8 +4,7 @@ #include #include #include - -#include "boost/mp11.hpp" +#include #include "core/common/gsl.h" @@ -33,7 +32,7 @@ namespace op_kernel_type_control { // we're using one set of types for all opsets of Cast ORT_SPECIFY_OP_KERNEL_ARG_DEFAULT_TYPE_LIST_ALL_OPSETS( kCpuExecutionProvider, kOnnxDomain, Cast, Input, 0, - element_type_lists::All); + element_type_lists::AllIRv9); ORT_SPECIFY_OP_KERNEL_ARG_REQUIRED_TYPES_ALL_OPSETS( kCpuExecutionProvider, kOnnxDomain, Cast, Input, 0, @@ -41,7 +40,7 @@ ORT_SPECIFY_OP_KERNEL_ARG_REQUIRED_TYPES_ALL_OPSETS( ORT_SPECIFY_OP_KERNEL_ARG_DEFAULT_TYPE_LIST_ALL_OPSETS( kCpuExecutionProvider, kOnnxDomain, Cast, Output, 0, - element_type_lists::All); + element_type_lists::AllIRv9); ORT_SPECIFY_OP_KERNEL_ARG_REQUIRED_TYPES_ALL_OPSETS( kCpuExecutionProvider, kOnnxDomain, Cast, Output, 0, @@ -57,6 +56,11 @@ using EnabledDstTypes = ORT_OP_KERNEL_ARG_ENABLED_TYPE_LIST_ALL_OPSETS(kCpuExecu template using IsOrtFloat16Type = boost::mp11::mp_contains, T>; +#if !defined(DISABLE_FLOAT8_TYPES) +template +using IsOrtFloat8Type = boost::mp11::mp_contains; +#endif + // string cast helpers // Note: when C++17 is available, use functions @@ -112,7 +116,11 @@ CastToString(const SrcType& input, std::string& output) { } template -typename std::enable_if::value, void>::type +#if !defined(DISABLE_FLOAT8_TYPES) +typename std::enable_if::value || IsOrtFloat8Type::value, void>::type +#else +typename std::enable_if::value>::type +#endif CastToString(const SrcType& input, std::string& output) { CastToString(static_cast(input), output); } @@ -142,11 +150,15 @@ CastFromString(const std::string& input, DstType& output) { } template +#if !defined(DISABLE_FLOAT8_TYPES) +typename std::enable_if::value || IsOrtFloat8Type::value, void>::type +#else typename std::enable_if::value, void>::type +#endif CastFromString(const std::string& input, DstType& output) { float intermediate; CastFromString(input, intermediate); - output = static_cast(intermediate); + output = DstType(intermediate); } // type that is usable with Eigen cast @@ -166,7 +178,6 @@ template <> struct EigenCastType { using type = Eigen::bfloat16; }; - // generic tensor X -> Y template struct TensorCaster { @@ -209,6 +220,38 @@ struct TensorCaster { } }; +#if !defined(DISABLE_FLOAT8_TYPES) + +// tensor X -> float 8 +template +struct TensorCasterNoSat { + void Cast(const OpKernelContext&, const TensorShape& shape, const Tensor& in, Tensor& out) const { + const std::ptrdiff_t shape_size = narrow(shape.Size()); + const auto* in_data = in.Data(); + auto* out_data = out.MutableData(); + for (std::ptrdiff_t i = 0; i < shape_size; ++i) { + out_data[i] = DstType(static_cast(in_data[i]), false); + } + } +}; + +// tensor string -> float 8 +template +struct TensorCasterNoSat { + void Cast(const OpKernelContext&, const TensorShape& shape, const Tensor& in, Tensor& out) const { + const std::ptrdiff_t shape_size = narrow(shape.Size()); + const auto* in_data = in.Data(); + auto* out_data = out.MutableData(); + float float_value; + for (std::ptrdiff_t i = 0; i < shape_size; ++i) { + CastFromString(in_data[i], float_value); + out_data[i] = DstType(float_value, false); + } + } +}; + +#endif + #if defined(_M_AMD64) && !defined(_M_ARM64EC) // specializations to use optimized and Windows x64-specific // MlasConvertHalfToFloatBuffer() routine for MLFloat16 -> float conversion @@ -265,12 +308,28 @@ class Cast final : public OpKernel { Status status = info.GetAttr("to", &to); ORT_ENFORCE(status.IsOK(), "Attribute to is not set."); to_ = gsl::narrow_cast(to); + + int64_t saturate = info.GetAttrOrDefault("saturate", int64_t{1}); +#if !defined(DISABLE_FLOAT8_TYPES) + if (saturate == 0 && (to != ONNX_NAMESPACE::TensorProto::FLOAT8E4M3FN && + to != ONNX_NAMESPACE::TensorProto::FLOAT8E4M3FNUZ && + to != ONNX_NAMESPACE::TensorProto::FLOAT8E5M2 && + to != ONNX_NAMESPACE::TensorProto::FLOAT8E5M2FNUZ)) { + ORT_THROW("Attribute saturate is only used for cast to float 8 types."); + } +#else + if (saturate == 0) { + ORT_THROW("Attribute saturate is only used for cast to float 8 types."); + } +#endif + saturate_ = saturate == 1; } Status Compute(OpKernelContext* context) const override; private: ONNX_NAMESPACE::TensorProto_DataType to_; + bool saturate_; }; template @@ -280,6 +339,17 @@ struct Dispatcher { } }; +#if !defined(DISABLE_FLOAT8_TYPES) + +template +struct DispatcherNoSat { + void operator()(const OpKernelContext& context, const TensorShape& shape, const Tensor& src, Tensor& dst) { + TensorCasterNoSat{}.Cast(context, shape, src, dst); + } +}; + +#endif + template struct SrcDispatcher { void operator()( @@ -291,6 +361,23 @@ struct SrcDispatcher { } }; +#if !defined(DISABLE_FLOAT8_TYPES) + +template +struct SrcDispatcherNoSat { + void operator()( + int32_t to, const OpKernelContext& context, const TensorShape& shape, const Tensor& src, Tensor& dst) { + using EnabledDstTypeOnlyFloat8 = boost::mp11::mp_set_intersection< + EnabledDstTypes, element_type_lists::AllFloat8>; + using EnabledDstTypesWithoutSrcType = + boost::mp11::mp_remove_if_q>; + utils::MLTypeCallDispatcherFromTypeList dispatcher{to}; + dispatcher.template InvokeWithLeadingTemplateArgs>(context, shape, src, dst); + } +}; + +#endif + Status Cast::Compute(OpKernelContext* context) const { const Tensor* X = context->Input(0); const TensorShape& shape = X->Shape(); @@ -308,8 +395,20 @@ Status Cast::Compute(OpKernelContext* context) const { return Status::OK(); } - utils::MLTypeCallDispatcherFromTypeList dispatcher{from}; - dispatcher.Invoke(to_, *context, shape, *X, *Y); +#if !defined(DISABLE_FLOAT8_TYPES) + if (saturate_) { +#endif + utils::MLTypeCallDispatcherFromTypeList dispatcher{from}; + dispatcher.Invoke(to_, *context, shape, *X, *Y); +#if !defined(DISABLE_FLOAT8_TYPES) + } else if (to_ == ONNX_NAMESPACE::TensorProto::FLOAT8E4M3FN || + to_ == ONNX_NAMESPACE::TensorProto::FLOAT8E4M3FNUZ || + to_ == ONNX_NAMESPACE::TensorProto::FLOAT8E5M2 || + to_ == ONNX_NAMESPACE::TensorProto::FLOAT8E5M2FNUZ) { + utils::MLTypeCallDispatcherFromTypeList dispatcher{from}; + dispatcher.Invoke(to_, *context, shape, *X, *Y); + } +#endif return Status::OK(); } @@ -325,9 +424,19 @@ ONNX_CPU_OPERATOR_VERSIONED_KERNEL( .MayInplace(0, 0), // allocation planner will check input and output sizes match before inplacing Cast); -ONNX_CPU_OPERATOR_KERNEL( +ONNX_CPU_OPERATOR_VERSIONED_KERNEL( Cast, 13, + 18, + KernelDefBuilder() + .TypeConstraint("T1", BuildKernelDefConstraintsFromTypeList()) + .TypeConstraint("T2", BuildKernelDefConstraintsFromTypeList()) + .MayInplace(0, 0), // allocation planner will check input and output sizes match before inplacing + Cast); + +ONNX_CPU_OPERATOR_KERNEL( + Cast, + 19, KernelDefBuilder() .TypeConstraint("T1", BuildKernelDefConstraintsFromTypeList()) .TypeConstraint("T2", BuildKernelDefConstraintsFromTypeList()) diff --git a/onnxruntime/core/providers/cpu/tensor/identity_op.cc b/onnxruntime/core/providers/cpu/tensor/identity_op.cc index 2a2895e72132d..cdf30c3b32a58 100644 --- a/onnxruntime/core/providers/cpu/tensor/identity_op.cc +++ b/onnxruntime/core/providers/cpu/tensor/identity_op.cc @@ -45,10 +45,17 @@ ONNX_CPU_OPERATOR_VERSIONED_KERNEL( IdentityOp); // Opset 16 supported optional type -ONNX_CPU_OPERATOR_KERNEL( +ONNX_CPU_OPERATOR_VERSIONED_KERNEL( Identity, - 16, + 16, 18, KernelDefBuilder().TypeConstraint("V", DataTypeImpl::AllTensorAndSequenceTensorAndOptionalTypes()).Alias(0, 0), IdentityOp); +// Opset 19 supported float 8 types. +ONNX_CPU_OPERATOR_KERNEL( + Identity, + 19, + KernelDefBuilder().TypeConstraint("V", DataTypeImpl::AllTensorAndSequenceTensorAndOptionalTypesIRv9()).Alias(0, 0), + IdentityOp); + } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cpu/tensor/mean_variance_normalization.cc b/onnxruntime/core/providers/cpu/tensor/mean_variance_normalization.cc index 6f8827508d722..62c3dbfc87a75 100644 --- a/onnxruntime/core/providers/cpu/tensor/mean_variance_normalization.cc +++ b/onnxruntime/core/providers/cpu/tensor/mean_variance_normalization.cc @@ -3,17 +3,206 @@ #include "core/providers/cpu/tensor/mean_variance_normalization.h" +#include +#include + +#include "core/common/gsl.h" +#include "core/providers/common.h" +#include "core/providers/cpu/tensor/transpose.h" +#include "core/util/math_cpuonly.h" + namespace onnxruntime { + +namespace { +InlinedVector GetAxesFromAttribute(const OpKernelInfo& info) { + // legacy attribute that affects default axes value + const bool across_channels = info.GetAttrOrDefault("across_channels", int64_t{0}) == int64_t{1}; + + const auto default_axes = across_channels + ? std::vector{0, 1, 2, 3} + : std::vector{0, 2, 3}; + + const auto axes = info.GetAttrsOrDefault("axes", default_axes); + + return InlinedVector(axes.begin(), axes.end()); +} + +// Drop out of range, make non-negative, sort, and make unique. +InlinedVector NormalizeAxes(gsl::span axes, size_t rank) { + InlinedVector normalized_axes{}; + normalized_axes.reserve(axes.size()); + for (int64_t axis : axes) { + if (IsAxisInRange(axis, static_cast(rank))) { + normalized_axes.push_back( + static_cast(HandleNegativeAxis(axis, static_cast(rank)))); + } + } + std::sort(normalized_axes.begin(), normalized_axes.end()); + normalized_axes.erase(std::unique(normalized_axes.begin(), normalized_axes.end()), normalized_axes.end()); + return normalized_axes; +} + +std::optional> GetTransposePermutationIfNeeded(gsl::span normalized_axes, size_t rank) { + // We need to transpose if anything other than the trailing axes are specified. + // Assume `normalized_axes` is sorted with unique values. + const bool is_transpose_needed = [&]() { + for (size_t i = 0, num_axes = normalized_axes.size(); i < num_axes; ++i) { + if (normalized_axes[i] != rank - num_axes + i) { + return true; + } + } + return false; + }(); + + if (!is_transpose_needed) { + return std::nullopt; + } + + // permutation of [ { unspecified axes }, { specified axes } ] + InlinedVector permutation{}; + permutation.reserve(rank); + + auto specified_axis_it = normalized_axes.begin(); + for (size_t axis = 0; axis < rank; ++axis) { + if (specified_axis_it != normalized_axes.end() && + axis == *specified_axis_it) { + // skip specified axis for now, add them all to the end later + ++specified_axis_it; + } else { + // add unspecified axis + permutation.push_back(axis); + } + } + + // add all specified axes + permutation.insert(permutation.end(), normalized_axes.begin(), normalized_axes.end()); + + return permutation; +} + +// Given an M x N array where N is the inner dimension, compute normalized quantities for M sets of N values. +// X is the input and Y is the output. +Status ComputeMeanVarianceNormalization2D(size_t M, size_t N, + gsl::span X, gsl::span Y, + bool normalize_variance) { + ORT_RETURN_IF_NOT(X.size() == M * N && X.size() == Y.size(), "X and Y must both have M * N elements."); + + const auto idx_M = narrow(M), idx_N = narrow(N); + // Note: Eigen arrays have column-major storage by default, so we specify N rows x M columns. + ConstEigenArrayMap X_array(X.data(), idx_N, idx_M); + EigenArrayMap Y_array(Y.data(), idx_N, idx_M); + + // for each column, compute Y = X - E[X] + Y_array = X_array.rowwise() - X_array.colwise().mean(); + + if (normalize_variance) { + // for each column, compute Y' = (X - E[X]) / ( E[ (X - E[X])^2 ] )^(1/2) + // we start with Y = X - E[X], + // so Y' = Y / ( E[ Y^2 ] )^(1/2) + Y_array = (Y_array.rowwise() / (Y_array.square().colwise().mean().sqrt())).eval(); + } + + return Status::OK(); +} + +InlinedVector InvertPerm(gsl::span perm) { + InlinedVector inverted_perm{}; + inverted_perm.resize(perm.size()); + for (size_t i = 0; i < perm.size(); ++i) { + inverted_perm[perm[i]] = i; + } + return inverted_perm; +} +} // namespace + +MeanVarianceNormalization::MeanVarianceNormalization(const OpKernelInfo& info) + : OpKernel{info}, + normalize_variance_{ + // legacy attribute + info.GetAttrOrDefault("normalize_variance", int64_t{1}) == int64_t{1}}, + axes_{GetAxesFromAttribute(info)} { +} + +Status MeanVarianceNormalization::Compute(OpKernelContext* context) const { + const auto& input = context->RequiredInput(0); + const auto& input_shape = input.Shape(); + + Tensor& output = context->RequiredOutput(0, input_shape); + + // approach for normalizing values across arbitrary dimensions: + // - transpose to [unspecified axes, specified axes] + // - do normalization of inner dimension values + // - transpose back + + const auto rank = input_shape.GetDims().size(); + + const auto normalized_axes = NormalizeAxes(axes_, rank); + + // The ONNX spec doesn't specify what to do if no axes are specified so we won't try to do anything. + ORT_RETURN_IF(normalized_axes.empty(), "No valid axes are specified. This is not handled now."); + + if (input_shape.Size() == 0) { + return Status::OK(); + } + + const auto transpose_permutation = GetTransposePermutationIfNeeded(normalized_axes, rank); + const bool is_transpose_required = transpose_permutation.has_value(); + + // intermediate tensors if transposing is necessary + Tensor transposed_input; + Tensor transposed_result; + + TensorShape compute_shape = input_shape; + + if (is_transpose_required) { + AllocatorPtr alloc; + ORT_RETURN_IF_ERROR(context->GetTempSpaceAllocator(&alloc)); + + InlinedVector transposed_dims{}; + transposed_dims.reserve(rank); + std::transform(transpose_permutation->begin(), transpose_permutation->end(), std::back_inserter(transposed_dims), + [input_dims = input.Shape().GetDims()](size_t axis) { return input_dims[axis]; }); + compute_shape = TensorShape(transposed_dims); + + transposed_input = Tensor{input.DataType(), compute_shape, alloc}; + + ORT_RETURN_IF_ERROR(TransposeBase::DoTranspose(*transpose_permutation, input, transposed_input)); + + transposed_result = Tensor{input.DataType(), compute_shape, alloc}; + } + + const size_t num_unspecified_axes = rank - normalized_axes.size(); + const size_t M = narrow(compute_shape.SizeToDimension(num_unspecified_axes)), + N = narrow(compute_shape.SizeFromDimension(num_unspecified_axes)); + + const gsl::span X = is_transpose_required + ? transposed_input.DataAsSpan() + : input.DataAsSpan(); + const gsl::span Y = is_transpose_required + ? transposed_result.MutableDataAsSpan() + : output.MutableDataAsSpan(); + + ORT_RETURN_IF_ERROR(ComputeMeanVarianceNormalization2D(M, N, X, Y, normalize_variance_)); + + if (is_transpose_required) { + const auto inverted_permutation = InvertPerm(*transpose_permutation); + ORT_RETURN_IF_ERROR(TransposeBase::DoTranspose(inverted_permutation, transposed_result, output)); + } + + return Status::OK(); +} + ONNX_CPU_OPERATOR_VERSIONED_KERNEL( MeanVarianceNormalization, 9, 12, KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()), - MeanVarianceNormalization_1); + MeanVarianceNormalization); ONNX_CPU_OPERATOR_KERNEL( MeanVarianceNormalization, 13, KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()), - MeanVarianceNormalization_1); + MeanVarianceNormalization); + } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cpu/tensor/mean_variance_normalization.h b/onnxruntime/core/providers/cpu/tensor/mean_variance_normalization.h index 89c9bccb0722f..2d0f3d9688bf5 100644 --- a/onnxruntime/core/providers/cpu/tensor/mean_variance_normalization.h +++ b/onnxruntime/core/providers/cpu/tensor/mean_variance_normalization.h @@ -2,121 +2,18 @@ // Licensed under the MIT License. #pragma once -#include -#include "core/common/common.h" + +#include "core/common/inlined_containers.h" #include "core/framework/op_kernel.h" -#include "core/util/math_cpuonly.h" -#include "core/common/gsl.h" namespace onnxruntime { -template -class MeanVarianceNormalization_0 : public OpKernel { +class MeanVarianceNormalization : public OpKernel { public: - MeanVarianceNormalization_0(const OpKernelInfo& info, bool old_attr = true) : OpKernel(info) { - if (old_attr) { - ORT_ENFORCE(info.GetAttr("across_channels", &across_channels_).IsOK()); - ORT_ENFORCE(info.GetAttr("normalize_variance", &normalize_variance_).IsOK()); - } - } - - Status Compute(OpKernelContext* context) const override { - const auto* X = context->Input(0); - if (X == nullptr) return Status(common::ONNXRUNTIME, common::FAIL, "input count mismatch"); - - const auto dims = X->Shape().GetDims(); - - if (dims.size() < 4) { - return Status(common::ONNXRUNTIME, common::INVALID_ARGUMENT, - "Input is expected to have four dimensions corresponding to [N,C,H,W]"); - } - - const int64_t N = dims[0]; - const int64_t C = dims[1]; - const int64_t H = dims[2]; - const int64_t W = dims[3]; - - Tensor* Y = context->Output(0, {N, C, H, W}); - const T* Xdata = X->Data(); - T* Ydata = Y->MutableData(); - - const int64_t sample_size = H * W; - Eigen::Array mean(C, 1); - Eigen::Array var(C, 1); - mean.setZero(); - var.setZero(); - - ConstEigenArrayMap X_arr(Xdata, onnxruntime::narrow(sample_size), SafeInt(N) * C); - for (int nc = 0; nc < N * C; ++nc) { - mean(nc % C) += X_arr.col(nc).sum(); - } - mean /= gsl::narrow_cast(N * sample_size); - for (int64_t nc = 0; nc < N * C; ++nc) { - var(onnxruntime::narrow(nc % C)) += (X_arr.col(onnxruntime::narrow(nc)) - mean(onnxruntime::narrow(nc % C))).matrix().squaredNorm(); - } - var /= gsl::narrow_cast(N * sample_size); - - Eigen::Array inv_std; - EigenArrayMap Y_arr(Ydata, onnxruntime::narrow(sample_size), SafeInt(N) * C); + MeanVarianceNormalization(const OpKernelInfo& info); + Status Compute(OpKernelContext* context) const override; - if (across_channels_) { - // m_c = sum(m_i) / n - float global_mean = mean.mean(); - - // var_c = [(var_1 + (m_1 - m_c)^2) + ... + (var_n + (m_n - m_c)^2)] / n - // = [sum(var_i) + squared_norm(m_i - m_c)] / n - float global_var = ((mean - global_mean).matrix().squaredNorm() + var.sum()) / C; - - // For across channels we can directly use eigen because global_mean and global_var - // are just scalars. - if (!normalize_variance_) { - Y_arr = X_arr - global_mean; - } else { - float inv_std_scalar = 1 / std::sqrt(global_var); - Y_arr = (X_arr - global_mean) * inv_std_scalar; - } - } else { - if (!normalize_variance_) { - // inv_std = 1 - for (int64_t nc = 0; nc < N * C; ++nc) { - // y = (x - mean) - Y_arr.col(onnxruntime::narrow(nc)) = (X_arr.col(onnxruntime::narrow(nc)) - mean(onnxruntime::narrow(nc % C))); - } - } else { - inv_std = var.sqrt().inverse(); - for (int64_t nc = 0; nc < N * C; ++nc) { - // y = (x - mean) * (inv_std) - Y_arr.col(onnxruntime::narrow(nc)) = (X_arr.col(onnxruntime::narrow(nc)) - mean(onnxruntime::narrow(nc % C))) * inv_std(onnxruntime::narrow(nc % C)); - } - } - } - return Status::OK(); - } - - protected: - int64_t across_channels_; - int64_t normalize_variance_; -}; - -template -class MeanVarianceNormalization_1 final : public MeanVarianceNormalization_0 { - public: - MeanVarianceNormalization_1(const OpKernelInfo& info) : MeanVarianceNormalization_0(info, false) { - std::vector axes; - if (!info.GetAttrs("axes", axes).IsOK()) { - axes = {0, 2, 3}; - } - constexpr int64_t cross_channel_axes[] = {0, 1, 2, 3}; - constexpr int64_t batch_spatial_axes[] = {0, 2, 3}; - - if (std::equal(std::begin(axes), std::end(axes), std::begin(cross_channel_axes), std::end(cross_channel_axes))) { - this->across_channels_ = true; - } else if (std::equal(std::begin(axes), std::end(axes), std::begin(batch_spatial_axes), std::end(batch_spatial_axes))) { - this->across_channels_ = false; - } else { - ORT_THROW("MeanVarianceNormalization CPU EP only supports NHW and NCHW reduction for axes attribute."); - } - this->normalize_variance_ = 1; - } + private: + const bool normalize_variance_; + const InlinedVector axes_; }; - } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cpu/tensor/pad.cc b/onnxruntime/core/providers/cpu/tensor/pad.cc index c46acfc928e4a..fe5267f20712b 100644 --- a/onnxruntime/core/providers/cpu/tensor/pad.cc +++ b/onnxruntime/core/providers/cpu/tensor/pad.cc @@ -79,12 +79,26 @@ ORT_SPECIFY_OP_KERNEL_ARG_DEFAULT_TYPES( uint8_t, bool); +ORT_SPECIFY_OP_KERNEL_ARG_DEFAULT_TYPES( + kCpuExecutionProvider, kOnnxDomain, Pad, 19, Input, 0, + float, + double, + int32_t, + int64_t, + uint32_t, + uint64_t, + int8_t, + uint8_t, + bool); + ORT_SPECIFY_OP_KERNEL_ARG_REQUIRED_TYPES( kCpuExecutionProvider, kOnnxDomain, Pad, 11, Input, 0, int32_t, int64_t); ORT_SPECIFY_OP_KERNEL_ARG_REQUIRED_TYPES( kCpuExecutionProvider, kOnnxDomain, Pad, 13, Input, 0, int32_t, int64_t); ORT_SPECIFY_OP_KERNEL_ARG_REQUIRED_TYPES( kCpuExecutionProvider, kOnnxDomain, Pad, 18, Input, 0, int32_t, int64_t); +ORT_SPECIFY_OP_KERNEL_ARG_REQUIRED_TYPES( + kCpuExecutionProvider, kOnnxDomain, Pad, 19, Input, 0, int32_t, int64_t); } // namespace op_kernel_type_control using EnabledPad2Types = ORT_OP_KERNEL_ARG_ENABLED_TYPE_LIST( @@ -95,6 +109,8 @@ using EnabledPad13Types = ORT_OP_KERNEL_ARG_ENABLED_TYPE_LIST( kCpuExecutionProvider, kOnnxDomain, Pad, 13, Input, 0); using EnabledPad18Types = ORT_OP_KERNEL_ARG_ENABLED_TYPE_LIST( kCpuExecutionProvider, kOnnxDomain, Pad, 18, Input, 0); +using EnabledPad19Types = ORT_OP_KERNEL_ARG_ENABLED_TYPE_LIST( + kCpuExecutionProvider, kOnnxDomain, Pad, 19, Input, 0); using AllEnabledPadTypes = utils::TypeSetUnion< @@ -131,15 +147,24 @@ ONNX_CPU_OPERATOR_VERSIONED_KERNEL( BuildKernelDefConstraintsFromTypeList()), Pad); -ONNX_CPU_OPERATOR_KERNEL( +ONNX_CPU_OPERATOR_VERSIONED_KERNEL( Pad, - 18, + 18, 18, KernelDefBuilder() .TypeConstraint( "T", BuildKernelDefConstraintsFromTypeList()), Pad); +ONNX_CPU_OPERATOR_KERNEL( + Pad, + 19, + KernelDefBuilder() + .TypeConstraint( + "T", + BuildKernelDefConstraintsFromTypeList()), + Pad); + using PadsVector = PadBase::PadsVector; // This is the general padding method to n-dimensionally do edge or reflection padding (based on the inputDelta values) @@ -426,6 +451,7 @@ static Status PadImpl(OpKernelContext* ctx, break; case Mode::Reflect: + case Mode::Wrap: // Loop over the output tensor, writing out padding between the blocks of copied data // On loop entry, 'pad' is already set to the first continuous block of padding, and // after every pass through the inner loop it gets set to the next continuous pad size. @@ -438,12 +464,46 @@ static Status PadImpl(OpKernelContext* ctx, int64_t prePad = reshaped_pad[inner_axis]; int64_t postPad = reshaped_pad[inner_axis + new_dims_count]; if (inner_no_pad_size == 1) { - PadInnermostAxis(axisStart - prePad, axisStart + prePad, -1 /* inputDelta */, onnxruntime::narrow(prePad)); - PadInnermostAxis(output, output - 2, -1 /* inputDelta */, onnxruntime::narrow(postPad)); + if (mode == Mode::Reflect) { + PadInnermostAxis(axisStart - prePad, axisStart + prePad, -1 /* inputDelta */, onnxruntime::narrow(prePad)); + PadInnermostAxis(output, output - 2, -1 /* inputDelta */, onnxruntime::narrow(postPad)); + } else { + PadInnermostAxis(axisStart - prePad, output - prePad, 1 /* inputDelta */, onnxruntime::narrow(prePad)); + PadInnermostAxis(output, axisStart, 1 /* inputDelta */, onnxruntime::narrow(postPad)); + } } else { // When inner_most axis(es) do not need pad, Above PadInnermostAxis() do not fit for Reflect mode. - PadAxis(axisStart - prePad, axisStart + prePad, 1, -ptrdiff_t(inner_no_pad_size * 2), inner_no_pad_size, onnxruntime::narrow(pads[inner_axis])); - PadAxis(output, output - 2 * inner_no_pad_size, 1, -ptrdiff_t(inner_no_pad_size * 2), inner_no_pad_size, onnxruntime::narrow(pads[inner_axis + data_rank])); + if (mode == Mode::Reflect) { + PadAxis( + axisStart - prePad, + axisStart + prePad, + 1, + -ptrdiff_t(inner_no_pad_size * 2), + inner_no_pad_size, + onnxruntime::narrow(pads[inner_axis])); + PadAxis( + output, + output - 2 * inner_no_pad_size, + 1, + -ptrdiff_t(inner_no_pad_size * 2), + inner_no_pad_size, + onnxruntime::narrow(pads[inner_axis + data_rank])); + } else { + PadAxis( + axisStart - prePad, + output - pads[inner_axis] * inner_no_pad_size, + 1, + 0, + inner_no_pad_size, + onnxruntime::narrow(pads[inner_axis])); + PadAxis( + output, + axisStart, + 1, + 0, + inner_no_pad_size, + onnxruntime::narrow(pads[inner_axis + data_rank])); + } } output += postPad; alignSkip = onnxruntime::narrow(prePad); @@ -454,9 +514,37 @@ static Status PadImpl(OpKernelContext* ctx, T* axisStart = output - inner_pitch * input_extents[input_counters.Axis()]; int64_t prePad = reshaped_pad[input_counters.Axis()]; int64_t postPad = reshaped_pad[input_counters.Axis() + new_dims_count]; - PadAxis(axisStart - prePad * inner_pitch, axisStart + prePad * inner_pitch, 1, -inner_pitch * 2, - inner_pitch, onnxruntime::narrow(prePad)); - PadAxis(output, output - 2 * inner_pitch, 1, -inner_pitch * 2, inner_pitch, onnxruntime::narrow(postPad)); + if (mode == Mode::Reflect) { + PadAxis( + axisStart - prePad * inner_pitch, + axisStart + prePad * inner_pitch, + 1, + -inner_pitch * 2, + inner_pitch, + onnxruntime::narrow(prePad)); + PadAxis( + output, + output - 2 * inner_pitch, + 1, + -inner_pitch * 2, + inner_pitch, + onnxruntime::narrow(postPad)); + } else { + PadAxis( + axisStart - prePad * inner_pitch, + output - prePad * inner_pitch, + 1, + 0, + inner_pitch, + onnxruntime::narrow(prePad)); + PadAxis( + output, + axisStart, + 1, + 0, + inner_pitch, + onnxruntime::narrow(postPad)); + } output += inner_pitch * postPad; alignSkip += inner_pitch * SafeInt(prePad); } diff --git a/onnxruntime/core/providers/cpu/tensor/padbase.h b/onnxruntime/core/providers/cpu/tensor/padbase.h index 5600b2bc1eadc..d869ed1a6dda2 100644 --- a/onnxruntime/core/providers/cpu/tensor/padbase.h +++ b/onnxruntime/core/providers/cpu/tensor/padbase.h @@ -10,7 +10,8 @@ namespace onnxruntime { enum class Mode : int { Constant = 0, Reflect, - Edge + Edge, + Wrap }; class PadBase { @@ -32,6 +33,8 @@ class PadBase { mode_ = Mode::Reflect; else if (mode == "edge") mode_ = Mode::Edge; + else if (mode == "wrap") + mode_ = Mode::Wrap; else ORT_THROW("Invalid 'mode' attribute value"); } diff --git a/onnxruntime/core/providers/cpu/tensor/reshape.cc b/onnxruntime/core/providers/cpu/tensor/reshape.cc index 94a832fe007b3..9b1cf63bc7306 100644 --- a/onnxruntime/core/providers/cpu/tensor/reshape.cc +++ b/onnxruntime/core/providers/cpu/tensor/reshape.cc @@ -33,13 +33,22 @@ ONNX_CPU_OPERATOR_VERSIONED_KERNEL( .TypeConstraint("shape", DataTypeImpl::GetTensorType()), Reshape); -ONNX_CPU_OPERATOR_KERNEL( +ONNX_CPU_OPERATOR_VERSIONED_KERNEL( Reshape, - 14, + 14, 18, KernelDefBuilder() .Alias(0, 0) .TypeConstraint("T", DataTypeImpl::AllTensorTypes()) .TypeConstraint("shape", DataTypeImpl::GetTensorType()), Reshape); +ONNX_CPU_OPERATOR_KERNEL( + Reshape, + 19, + KernelDefBuilder() + .Alias(0, 0) + .TypeConstraint("T", DataTypeImpl::AllTensorTypesIRv9()) + .TypeConstraint("shape", DataTypeImpl::GetTensorType()), + Reshape); + } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cpu/tensor/reshape_helper.h b/onnxruntime/core/providers/cpu/tensor/reshape_helper.h index 2e4b741d26c18..5961686674424 100644 --- a/onnxruntime/core/providers/cpu/tensor/reshape_helper.h +++ b/onnxruntime/core/providers/cpu/tensor/reshape_helper.h @@ -11,6 +11,10 @@ namespace onnxruntime { class ReshapeHelper { public: ReshapeHelper(const TensorShape& input_shape, TensorShapeVector& requested_shape, bool allow_zero = false) { + const auto input_shape_size = input_shape.Size(); + ORT_ENFORCE(input_shape_size != -1, + "The input tensor must not have any dynamic (-1) dimensions. Input shape:", input_shape); + auto nDims = requested_shape.size(); ptrdiff_t unknown_dim = -1; int64_t size = 1; @@ -32,12 +36,12 @@ class ReshapeHelper { if (unknown_dim != -1) { // calculate unknown dimension - ORT_ENFORCE(size != 0 && (input_shape.Size() % size) == 0, + ORT_ENFORCE(size != 0 && (input_shape_size % size) == 0, "The input tensor cannot be reshaped to the requested shape. Input shape:", input_shape, ", requested shape:", TensorShape(requested_shape)); - requested_shape[unknown_dim] = input_shape.Size() / size; + requested_shape[unknown_dim] = input_shape_size / size; } else { // check if the output shape is valid. - ORT_ENFORCE(gsl::narrow_cast(input_shape.Size()) == size, + ORT_ENFORCE(input_shape_size == size, "The input tensor cannot be reshaped to the requested shape. Input shape:", input_shape, ", requested shape:", TensorShape(requested_shape)); } } diff --git a/onnxruntime/core/providers/cpu/tensor/resize.cc b/onnxruntime/core/providers/cpu/tensor/resize.cc index fbe8076f4f893..d092bfbd97bbb 100644 --- a/onnxruntime/core/providers/cpu/tensor/resize.cc +++ b/onnxruntime/core/providers/cpu/tensor/resize.cc @@ -93,32 +93,63 @@ ONNX_CPU_OPERATOR_VERSIONED_TYPED_KERNEL( KernelDefBuilder().TypeConstraint("T1", DataTypeImpl::GetTensorType()), Resize); -ONNX_CPU_OPERATOR_TYPED_KERNEL( +ONNX_CPU_OPERATOR_VERSIONED_TYPED_KERNEL( Resize, 18, + 18, float, KernelDefBuilder().TypeConstraint("T1", DataTypeImpl::GetTensorType()), Resize); -ONNX_CPU_OPERATOR_TYPED_KERNEL( +ONNX_CPU_OPERATOR_VERSIONED_TYPED_KERNEL( Resize, 18, + 18, int32_t, KernelDefBuilder().TypeConstraint("T1", DataTypeImpl::GetTensorType()), Resize); -ONNX_CPU_OPERATOR_TYPED_KERNEL( +ONNX_CPU_OPERATOR_VERSIONED_TYPED_KERNEL( Resize, 18, + 18, int8_t, KernelDefBuilder().TypeConstraint("T1", DataTypeImpl::GetTensorType()), Resize); -ONNX_CPU_OPERATOR_TYPED_KERNEL( +ONNX_CPU_OPERATOR_VERSIONED_TYPED_KERNEL( Resize, 18, + 18, uint8_t, KernelDefBuilder().TypeConstraint("T1", DataTypeImpl::GetTensorType()), Resize); +ONNX_CPU_OPERATOR_TYPED_KERNEL( + Resize, + 19, + float, + KernelDefBuilder().TypeConstraint("T1", DataTypeImpl::GetTensorType()), + Resize); + +ONNX_CPU_OPERATOR_TYPED_KERNEL( + Resize, + 19, + int32_t, + KernelDefBuilder().TypeConstraint("T1", DataTypeImpl::GetTensorType()), + Resize); + +ONNX_CPU_OPERATOR_TYPED_KERNEL( + Resize, + 19, + int8_t, + KernelDefBuilder().TypeConstraint("T1", DataTypeImpl::GetTensorType()), + Resize); + +ONNX_CPU_OPERATOR_TYPED_KERNEL( + Resize, + 19, + uint8_t, + KernelDefBuilder().TypeConstraint("T1", DataTypeImpl::GetTensorType()), + Resize); } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cpu/tensor/scatter.cc b/onnxruntime/core/providers/cpu/tensor/scatter.cc index f87788e8f4770..8844b7e7a26c4 100644 --- a/onnxruntime/core/providers/cpu/tensor/scatter.cc +++ b/onnxruntime/core/providers/cpu/tensor/scatter.cc @@ -308,7 +308,7 @@ Status ScatterData( const auto& upd_shape = updates_input->Shape(); const auto num_dims = input_data_shape.NumDimensions(); - assert(num_dims > 0); + ORT_RETURN_IF_NOT(num_dims > 0, "ScatterElements op: input tensor must have at least one dimension"); // Allocate and zero out counts. The input/output is of the same rank as // indices/updates but the actual dimensions of indices/updates must be less or equal diff --git a/onnxruntime/core/providers/cpu/tensor/shape_op.cc b/onnxruntime/core/providers/cpu/tensor/shape_op.cc index 780cf4b733996..e6020d059e704 100644 --- a/onnxruntime/core/providers/cpu/tensor/shape_op.cc +++ b/onnxruntime/core/providers/cpu/tensor/shape_op.cc @@ -18,10 +18,16 @@ ONNX_CPU_OPERATOR_VERSIONED_KERNEL( KernelDefBuilder().TypeConstraint("T", DataTypeImpl::AllTensorTypes()).TypeConstraint("T1", DataTypeImpl::GetTensorType()), Shape); -ONNX_CPU_OPERATOR_KERNEL( +ONNX_CPU_OPERATOR_VERSIONED_KERNEL( Shape, - 15, + 15, 18, KernelDefBuilder().TypeConstraint("T", DataTypeImpl::AllTensorTypes()).TypeConstraint("T1", DataTypeImpl::GetTensorType()), Shape); +ONNX_CPU_OPERATOR_KERNEL( + Shape, + 19, + KernelDefBuilder().TypeConstraint("T", DataTypeImpl::AllTensorTypesIRv9()).TypeConstraint("T1", DataTypeImpl::GetTensorType()), + Shape); + } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cpu/tensor/size.cc b/onnxruntime/core/providers/cpu/tensor/size.cc index 47dbee0113505..9d9862b4cedc6 100644 --- a/onnxruntime/core/providers/cpu/tensor/size.cc +++ b/onnxruntime/core/providers/cpu/tensor/size.cc @@ -45,9 +45,28 @@ ONNX_CPU_OPERATOR_VERSIONED_KERNEL( .TypeConstraint("T1", DataTypeImpl::GetTensorType()), Size); +ONNX_CPU_OPERATOR_VERSIONED_KERNEL( + Size, + 13, 18, + KernelDefBuilder().TypeConstraint("T", + std::vector({DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType()})) + .TypeConstraint("T1", DataTypeImpl::GetTensorType()), + Size); + ONNX_CPU_OPERATOR_KERNEL( Size, - 13, + 19, KernelDefBuilder().TypeConstraint("T", std::vector({DataTypeImpl::GetTensorType(), DataTypeImpl::GetTensorType(), diff --git a/onnxruntime/core/providers/cpu/tensor/slice.cc b/onnxruntime/core/providers/cpu/tensor/slice.cc index e6593f0919a85..a8cb74a62e02d 100644 --- a/onnxruntime/core/providers/cpu/tensor/slice.cc +++ b/onnxruntime/core/providers/cpu/tensor/slice.cc @@ -198,14 +198,14 @@ Status SliceBase::FillVectorsFromInput(const Tensor& start_tensor, ORT_RETURN_IF_NOT(nullptr == steps_tensor || start_tensor.Shape() == steps_tensor->Shape(), "Starts and steps shape mismatch"); - const auto size = start_tensor.Shape().Size(); - input_starts.reserve(narrow(size)); - input_ends.reserve(narrow(size)); + const auto size = narrow(start_tensor.Shape().Size()); + input_starts.reserve(size); + input_ends.reserve(size); if (nullptr != axes_tensor) - input_axes.reserve(narrow(size)); + input_axes.reserve(size); // Slice V10 if (nullptr != steps_tensor) - input_steps.reserve(narrow(size)); + input_steps.reserve(size); // check for type reduction of supported indices types constexpr bool int32_enabled = utils::HasType(); diff --git a/onnxruntime/core/providers/cpu/tensor/slice_helper.h b/onnxruntime/core/providers/cpu/tensor/slice_helper.h index d97d2b37a7c93..6aba4710c4616 100644 --- a/onnxruntime/core/providers/cpu/tensor/slice_helper.h +++ b/onnxruntime/core/providers/cpu/tensor/slice_helper.h @@ -4,10 +4,12 @@ // This file contains the functions compute the starts, steps (strides) and output shape // for Slice op, which can be called from other ops or EPs. #pragma once -#include "core/providers/cpu/tensor/slice_compute_metadata.h" + #include "core/common/inlined_containers.h" #include "core/common/narrow.h" #include "core/framework/ort_stl_allocator.h" +#include "core/providers/common.h" +#include "core/providers/cpu/tensor/slice_compute_metadata.h" namespace onnxruntime { diff --git a/onnxruntime/core/providers/cpu/tensor/transpose.cc b/onnxruntime/core/providers/cpu/tensor/transpose.cc index 6292df05cbb3f..277dccac35b4f 100644 --- a/onnxruntime/core/providers/cpu/tensor/transpose.cc +++ b/onnxruntime/core/providers/cpu/tensor/transpose.cc @@ -402,7 +402,7 @@ Status Transpose::Compute(OpKernelContext* ctx) const { bool moving_single_axis = IsTransposeMovingSingleAxis(*p_perm, from, to); if (moving_single_axis && !X.IsDataTypeString()) { - SingleAxisTranspose(*p_perm, X, Y, from, to); + SingleAxisTranspose(*p_perm, X, Y, from, to, nullptr, ctx->GetOperatorThreadPool()); } else { // fall back to default implementation status = DoUntypedTranspose(*p_perm, X, Y); diff --git a/onnxruntime/core/providers/cpu/tensor/transpose.h b/onnxruntime/core/providers/cpu/tensor/transpose.h index c88c318dda90f..133b35ac80fe5 100644 --- a/onnxruntime/core/providers/cpu/tensor/transpose.h +++ b/onnxruntime/core/providers/cpu/tensor/transpose.h @@ -62,20 +62,24 @@ class TransposeBase { Status ComputeOutputShape(const Tensor& X, TensorShapeVector& output_dims, InlinedVector& default_perm, const InlinedVector*& p_perm) const { - size_t rank = X.Shape().NumDimensions(); + const size_t rank = X.Shape().NumDimensions(); const auto& input_dims = X.Shape().GetDims(); - // Determine permutation to use: - // If no permutation was specified in the attributes, the default is [rank-1, ..., 0] - default_perm.resize(rank); - if (perm_specified_) p_perm = &perm_; else { + // Determine permutation to use: + // If no permutation was specified in the attributes, the default is [rank-1, ..., 0] + default_perm.resize(rank); for (size_t i = 0; i < rank; ++i) default_perm[i] = rank - i - 1; p_perm = &default_perm; } + if (p_perm->size() != rank) { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "perm size: ", p_perm->size(), " does not match input rank: ", std::to_string(rank)); + } + // Determine shape of output output_dims.resize(rank); for (size_t i = 0; i < rank; i++) { diff --git a/onnxruntime/core/providers/cpu/tensor/unique.cc b/onnxruntime/core/providers/cpu/tensor/unique.cc index f42375ae86022..135bef0860cab 100644 --- a/onnxruntime/core/providers/cpu/tensor/unique.cc +++ b/onnxruntime/core/providers/cpu/tensor/unique.cc @@ -14,7 +14,7 @@ namespace onnxruntime { namespace op_kernel_type_control { ORT_SPECIFY_OP_KERNEL_ARG_DEFAULT_TYPES_ALL_OPSETS( kCpuExecutionProvider, kOnnxDomain, Unique, Input, 0, - float, int64_t, int8_t, std::string); + float, int64_t, int8_t, std::string, double); } using EnabledUniqueDataTypes = ORT_OP_KERNEL_ARG_ENABLED_TYPE_LIST_ALL_OPSETS( @@ -91,7 +91,9 @@ Status Unique::Compute(OpKernelContext* context) const { Status status; // arbitrary set of types to support initially // Note: The non-string implementations can probably be based on data type size. - if (input.IsDataType()) + if (input.IsDataType()) + status = ComputeImpl(*context); + else if (input.IsDataType()) status = ComputeImpl(*context); else if (input.IsDataType()) status = ComputeImpl(*context); diff --git a/onnxruntime/core/providers/cpu/tensor/unsqueeze.h b/onnxruntime/core/providers/cpu/tensor/unsqueeze.h index cdf2a72fdbb9e..4b31e3a82f2d0 100644 --- a/onnxruntime/core/providers/cpu/tensor/unsqueeze.h +++ b/onnxruntime/core/providers/cpu/tensor/unsqueeze.h @@ -4,10 +4,12 @@ #ifndef SHARED_PROVIDER #include "core/common/common.h" #include "core/framework/op_kernel.h" -#include "core/util/math_cpuonly.h" #include "core/framework/tensor.h" +#include "core/providers/common.h" #endif +#include "utils.h" + namespace onnxruntime { class UnsqueezeBase { @@ -27,7 +29,36 @@ class UnsqueezeBase { } } - private: + static TensorShapeVector ComputeOutputShape( + const TensorShape& input_shape, + const TensorShapeVector& axes) { + TensorShapeVector output_shape; + auto num_dimensions = input_shape.NumDimensions(); + + auto total_num_dimensions = num_dimensions + axes.size(); + // Handle negtive axis, then resort and uniq. + TensorShapeVector axes_corrected(axes.size()); + for (size_t i = 0; i < axes.size(); i++) { + axes_corrected[i] = HandleNegativeAxis(axes[i], total_num_dimensions); + } + std::sort(axes_corrected.begin(), axes_corrected.end()); + axes_corrected.erase(std::unique(axes_corrected.begin(), axes_corrected.end()), axes_corrected.end()); + ORT_ENFORCE(axes_corrected.size() == axes.size(), "Axes input has duplicate values."); + ORT_ENFORCE(axes_corrected.size() > 0, "Unsqueeze axes is empty."); + size_t corr = 0; + size_t j = 0; + for (size_t i = 0; i < total_num_dimensions; ++i) { + if (j < axes_corrected.size() && axes_corrected[j] == static_cast(i)) { + output_shape.push_back(1); + ++j; + ++corr; + continue; + } + output_shape.push_back(input_shape[i - corr]); + } + return output_shape; + } + TensorShapeVector axes_; }; diff --git a/onnxruntime/core/providers/cpu/tensor/upsample.cc b/onnxruntime/core/providers/cpu/tensor/upsample.cc index c54e5b61f695e..fa69e144be554 100644 --- a/onnxruntime/core/providers/cpu/tensor/upsample.cc +++ b/onnxruntime/core/providers/cpu/tensor/upsample.cc @@ -670,7 +670,7 @@ static TrilinearParams SetupUpsampleTrilinear(int64_t input_depth, // pixel value in the output // (cache because we don't have to re-compute each time we come across the output width/output height value // while iterating the output image tensor - SafeInt scale_buffer_size = SafeInt(2) * sizeof(float_t) * + SafeInt scale_buffer_size = SafeInt(2) * sizeof(float) * (output_depth + output_height + output_width); // Limit number of allocations to just 1 diff --git a/onnxruntime/core/providers/cpu/tensor/upsamplebase.h b/onnxruntime/core/providers/cpu/tensor/upsamplebase.h index 72948ae2638a1..c13c9d42dd392 100644 --- a/onnxruntime/core/providers/cpu/tensor/upsamplebase.h +++ b/onnxruntime/core/providers/cpu/tensor/upsamplebase.h @@ -41,7 +41,7 @@ enum ResizeCoordinateTransformationMode { TF_HALF_PIXEL_FOR_NN = 3, ALIGN_CORNERS = 4, TF_CROP_AND_RESIZE = 5, - CoordinateTransformationModeCount = 6, + HALF_PIXEL_SYMMETRIC = 6, }; enum ResizeNearestMode { @@ -50,7 +50,6 @@ enum ResizeNearestMode { ROUND_PREFER_CEIL = 2, FLOOR = 3, CEIL = 4, - NearestModeCount = 5, }; enum class AspectRatioPolicy { @@ -237,6 +236,9 @@ class UpsampleBase { if (coordinate_transform_mode_name == "half_pixel") { return HALF_PIXEL; } + if (coordinate_transform_mode_name == "half_pixel_symmetric") { + return HALF_PIXEL_SYMMETRIC; + } ORT_THROW("coordinate_transform_mode:[" + coordinate_transform_mode_name + "] is not supportted!"); } @@ -267,6 +269,15 @@ class UpsampleBase { : 0.5 * (roi_start + roi_end) * (length_original - 1); return static_cast(orig); }; + case HALF_PIXEL_SYMMETRIC: + return [](float x_resized, float x_scale, float length_resized, float length_original, float, float) { + float output_width = x_scale * length_original; + float adjustment = length_resized / output_width; + float center = length_original / 2; + float offset = center * (1 - adjustment); + auto orig = offset + (x_resized + 0.5) / x_scale - 0.5; + return static_cast(orig); + }; default: // "half_pixel" return [](float x_resized, float x_scale, float, float, float, float) { return ((x_resized + 0.5f) / x_scale) - 0.5f; diff --git a/onnxruntime/core/providers/cuda/controlflow/if.cc b/onnxruntime/core/providers/cuda/controlflow/if.cc index 6a8720b3842b5..74cf79c619940 100644 --- a/onnxruntime/core/providers/cuda/controlflow/if.cc +++ b/onnxruntime/core/providers/cuda/controlflow/if.cc @@ -35,14 +35,25 @@ ONNX_OPERATOR_VERSIONED_KERNEL_EX(If, If); // opset-13 supports sequence type for If's subgraph outputs +ONNX_OPERATOR_VERSIONED_KERNEL_EX(If, + kOnnxDomain, + 13, 18, + kCudaExecutionProvider, + (*KernelDefBuilder::Create()) + .InputMemoryType(OrtMemTypeCPUInput, 0) // 'cond' needs to be on CPU + .TypeConstraint("B", DataTypeImpl::GetTensorType()) + .TypeConstraint("V", DataTypeImpl::AllTensorAndSequenceTensorTypes()), + If); + +// opset-19 supports float8 ONNX_OPERATOR_KERNEL_EX(If, kOnnxDomain, - 13, + 19, kCudaExecutionProvider, (*KernelDefBuilder::Create()) .InputMemoryType(OrtMemTypeCPUInput, 0) // 'cond' needs to be on CPU .TypeConstraint("B", DataTypeImpl::GetTensorType()) - .TypeConstraint("V", DataTypeImpl::AllTensorAndSequenceTensorTypes()), + .TypeConstraint("V", DataTypeImpl::AllTensorAndSequenceTensorTypesIRv9()), If); Status If::Compute(OpKernelContext* ctx) const { diff --git a/onnxruntime/core/providers/cuda/controlflow/loop.cc b/onnxruntime/core/providers/cuda/controlflow/loop.cc index 8e97880e736ee..3295b73a800c9 100644 --- a/onnxruntime/core/providers/cuda/controlflow/loop.cc +++ b/onnxruntime/core/providers/cuda/controlflow/loop.cc @@ -39,16 +39,29 @@ ONNX_OPERATOR_VERSIONED_KERNEL_EX(Loop, Loop); // opset-13 supports sequence type for loop carried dependencies +ONNX_OPERATOR_VERSIONED_KERNEL_EX(Loop, + kOnnxDomain, + 13, 18, + kCudaExecutionProvider, + (*KernelDefBuilder::Create()) + .InputMemoryType(OrtMemTypeCPUInput, 0) // 'M' needs to be on CPU + .InputMemoryType(OrtMemTypeCPUInput, 1) // 'cond' needs to be on CPU + .TypeConstraint("I", DataTypeImpl::GetTensorType()) + .TypeConstraint("B", DataTypeImpl::GetTensorType()) + .TypeConstraint("V", DataTypeImpl::AllTensorAndSequenceTensorTypes()), + Loop); + +// opset-19 supports float 8 types. ONNX_OPERATOR_KERNEL_EX(Loop, kOnnxDomain, - 13, + 19, kCudaExecutionProvider, (*KernelDefBuilder::Create()) .InputMemoryType(OrtMemTypeCPUInput, 0) // 'M' needs to be on CPU .InputMemoryType(OrtMemTypeCPUInput, 1) // 'cond' needs to be on CPU .TypeConstraint("I", DataTypeImpl::GetTensorType()) .TypeConstraint("B", DataTypeImpl::GetTensorType()) - .TypeConstraint("V", DataTypeImpl::AllTensorAndSequenceTensorTypes()), + .TypeConstraint("V", DataTypeImpl::AllTensorAndSequenceTensorTypesIRv9()), Loop); static Status ConcatenateGpuOutput(void* stream, std::vector& per_iteration_output, diff --git a/onnxruntime/core/providers/cuda/controlflow/scan.cc b/onnxruntime/core/providers/cuda/controlflow/scan.cc index 38ba16d1eca23..ad715325e14f0 100644 --- a/onnxruntime/core/providers/cuda/controlflow/scan.cc +++ b/onnxruntime/core/providers/cuda/controlflow/scan.cc @@ -101,14 +101,25 @@ ONNX_OPERATOR_VERSIONED_KERNEL_EX(Scan, Scan<9>); // Opset 16 starts to support BFloat16 type for the type constraint "V" +ONNX_OPERATOR_VERSIONED_KERNEL_EX(Scan, + kOnnxDomain, + 16, 18, + kCudaExecutionProvider, + (*KernelDefBuilder::Create()) + // 'I' is in the ONNX spec but is not used for any inputs or outputs + // .TypeConstraint("I", DataTypeImpl::GetTensorType()) + .TypeConstraint("V", DataTypeImpl::AllFixedSizeTensorTypes()), + Scan<9>); + +// Opset 19 starts to support float 8 types for the type constraint "V" ONNX_OPERATOR_KERNEL_EX(Scan, kOnnxDomain, - 16, + 19, kCudaExecutionProvider, (*KernelDefBuilder::Create()) // 'I' is in the ONNX spec but is not used for any inputs or outputs // .TypeConstraint("I", DataTypeImpl::GetTensorType()) - .TypeConstraint("V", DataTypeImpl::AllFixedSizeTensorTypes()), + .TypeConstraint("V", DataTypeImpl::AllFixedSizeTensorTypesIRv9()), Scan<9>); } // namespace cuda diff --git a/onnxruntime/core/providers/cuda/cu_inc/common.cuh b/onnxruntime/core/providers/cuda/cu_inc/common.cuh index 1d3e43f386c1b..0d9928baa86e0 100644 --- a/onnxruntime/core/providers/cuda/cu_inc/common.cuh +++ b/onnxruntime/core/providers/cuda/cu_inc/common.cuh @@ -19,7 +19,8 @@ namespace onnxruntime { namespace cuda { // float16 arithmetic is supported after sm5.3 with intrinsics, and cuda does not provide fallback for lower versions -#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 530 +// CUDA 12.2 does not limit the definition based on sm53 anymore and defines for all arches +#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ < 530) && ((__CUDACC_VER_MAJOR__ < 12) || ((__CUDACC_VER_MAJOR__ == 12) && (__CUDACC_VER_MINOR__ < 2))) __device__ __forceinline__ half operator+(const half& lh, const half& rh) { return half((float)lh + (float)rh); } __device__ __forceinline__ half operator-(const half& lh, const half& rh) { return half((float)lh - (float)rh); } __device__ __forceinline__ half operator*(const half& lh, const half& rh) { return half((float)lh * (float)rh); } @@ -146,20 +147,20 @@ __device__ __forceinline__ BFloat16& operator/=(BFloat16& a, const BFloat16& b) /// Arithmetic with floats -__device__ __forceinline__ float operator+(BFloat16 a, float b) { return static_cast(a) + b; } -__device__ __forceinline__ float operator-(BFloat16 a, float b) { return static_cast(a) - b; } -__device__ __forceinline__ float operator*(BFloat16 a, float b) { return static_cast(a) * b; } -__device__ __forceinline__ float operator/(BFloat16 a, float b) { return static_cast(a) / b; } +__device__ __forceinline__ float operator+(BFloat16 a, float b) { return a + b; } +__device__ __forceinline__ float operator-(BFloat16 a, float b) { return a - b; } +__device__ __forceinline__ float operator*(BFloat16 a, float b) { return a * b; } +__device__ __forceinline__ float operator/(BFloat16 a, float b) { return a / b; } -__device__ __forceinline__ float operator+(float a, BFloat16 b) { return a + static_cast(b); } -__device__ __forceinline__ float operator-(float a, BFloat16 b) { return a - static_cast(b); } -__device__ __forceinline__ float operator*(float a, BFloat16 b) { return a * static_cast(b); } -__device__ __forceinline__ float operator/(float a, BFloat16 b) { return a / static_cast(b); } +__device__ __forceinline__ float operator+(float a, BFloat16 b) { return a + b; } +__device__ __forceinline__ float operator-(float a, BFloat16 b) { return a - b; } +__device__ __forceinline__ float operator*(float a, BFloat16 b) { return a * b; } +__device__ __forceinline__ float operator/(float a, BFloat16 b) { return a / b; } -__device__ __forceinline__ float& operator+=(float& a, const BFloat16& b) { return a += static_cast(b); } -__device__ __forceinline__ float& operator-=(float& a, const BFloat16& b) { return a -= static_cast(b); } -__device__ __forceinline__ float& operator*=(float& a, const BFloat16& b) { return a *= static_cast(b); } -__device__ __forceinline__ float& operator/=(float& a, const BFloat16& b) { return a /= static_cast(b); } +__device__ __forceinline__ float& operator+=(float& a, const BFloat16& b) { return a += b; } +__device__ __forceinline__ float& operator-=(float& a, const BFloat16& b) { return a -= b; } +__device__ __forceinline__ float& operator*=(float& a, const BFloat16& b) { return a *= b; } +__device__ __forceinline__ float& operator/=(float& a, const BFloat16& b) { return a /= b; } /// Arithmetic with doubles @@ -350,6 +351,18 @@ __device__ __inline__ T _Max(T a, T b) { return a > b ? a : b; } template __device__ __inline__ T _Abs(T a) { return a > (T)0 ? a : -a; } +template +__device__ __inline__ T _Signum(T a, std::false_type /* is_signed */) { return T(0) < a; } + +template +__device__ __inline__ T _Signum(T a, std::true_type /* is_signed */) { return (T(0) < a) - (a < T(0)); } + +template +__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__ T _Normcdf(T a); @@ -382,6 +395,14 @@ __device__ __inline__ T _Gelu(T a) { return a * _Normcdf(a); } +template <> +__device__ __inline__ half _Gelu(half a) { + const half kHalf = half(0.5); + const half kOne = half(1.0); + const half kAlpha = half(M_SQRT1_2); + return a * kHalf * (kOne + _Erf(kAlpha * a)); +} + template __device__ __inline__ T _Mod(T a, T b) { T r = a % b; diff --git a/onnxruntime/core/providers/cuda/cu_inc/elementwise_impl.cuh b/onnxruntime/core/providers/cuda/cu_inc/elementwise_impl.cuh index 790a612790417..07a65bd252304 100644 --- a/onnxruntime/core/providers/cuda/cu_inc/elementwise_impl.cuh +++ b/onnxruntime/core/providers/cuda/cu_inc/elementwise_impl.cuh @@ -16,12 +16,12 @@ constexpr int kElementsPerThread = GridDim::maxElementsPerThread; constexpr int kThreadsPerBlock = GridDim::maxThreadsPerBlock; #endif -template -__global__ void ElementwiseKernel(T* output_data, const FuncT functor, CUDA_LONG N) { - CUDA_LONG start = kElementsPerThread * kThreadsPerBlock * blockIdx.x + threadIdx.x; +template +__global__ void ElementwiseKernel(T* output_data, const FuncT functor, TIndex N) { + TIndex start = kElementsPerThread * kThreadsPerBlock * blockIdx.x + threadIdx.x; T value[kElementsPerThread]; - CUDA_LONG id = start; + TIndex id = start; #pragma unroll for (int i = 0; i < kElementsPerThread; ++i) { if (id < N) { @@ -40,12 +40,12 @@ __global__ void ElementwiseKernel(T* output_data, const FuncT functor, CUDA_LONG } } -template -void LaunchElementwiseKernel(cudaStream_t stream, T* output_data, const FuncT& functor, size_t output_size) { +template +void LaunchElementwiseKernel(cudaStream_t stream, T* output_data, const FuncT& functor, TIndex output_size) { if (output_size == 0) return; - CUDA_LONG N = static_cast(output_size); - int blocksPerGrid = CeilDiv(N, kThreadsPerBlock * kElementsPerThread); - ElementwiseKernel<<>>(output_data, functor, N); + TIndex N = output_size; + int blocksPerGrid = static_cast(CeilDiv(N, static_cast(kThreadsPerBlock * kElementsPerThread))); + ElementwiseKernel<<>>(output_data, functor, N); } } // namespace cuda diff --git a/onnxruntime/core/providers/cuda/cu_inc/variadic_elementwise_impl.cuh b/onnxruntime/core/providers/cuda/cu_inc/variadic_elementwise_impl.cuh index e3a3c6a969f16..2df1a3aed1187 100644 --- a/onnxruntime/core/providers/cuda/cu_inc/variadic_elementwise_impl.cuh +++ b/onnxruntime/core/providers/cuda/cu_inc/variadic_elementwise_impl.cuh @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #pragma once #include "core/providers/cuda/cu_inc/common.cuh" diff --git a/onnxruntime/core/providers/cuda/cuda_allocator.cc b/onnxruntime/core/providers/cuda/cuda_allocator.cc index ea628fa8c898b..314aa1062f1b0 100644 --- a/onnxruntime/core/providers/cuda/cuda_allocator.cc +++ b/onnxruntime/core/providers/cuda/cuda_allocator.cc @@ -3,7 +3,6 @@ #include "cuda_allocator.h" #include "cuda_common.h" -#include "core/framework/allocatormgr.h" #include "gpu_data_transfer.h" namespace onnxruntime { diff --git a/onnxruntime/core/providers/cuda/cuda_allocator.h b/onnxruntime/core/providers/cuda/cuda_allocator.h index a8f86d8d49355..86d0d8007bbd8 100644 --- a/onnxruntime/core/providers/cuda/cuda_allocator.h +++ b/onnxruntime/core/providers/cuda/cuda_allocator.h @@ -52,11 +52,11 @@ class CUDAExternalAllocator : public CUDAAllocator { // TODO: add a default constructor class CUDAPinnedAllocator : public IAllocator { public: - CUDAPinnedAllocator(OrtDevice::DeviceId device_id, const char* name) + CUDAPinnedAllocator(const char* name) : IAllocator( OrtMemoryInfo(name, OrtAllocatorType::OrtDeviceAllocator, - OrtDevice(OrtDevice::CPU, OrtDevice::MemType::CUDA_PINNED, device_id), - device_id, OrtMemTypeCPUOutput)) {} + OrtDevice(OrtDevice::CPU, OrtDevice::MemType::CUDA_PINNED, 0 /*CPU device always with id 0*/), + 0, OrtMemTypeCPUOutput)) {} void* Alloc(size_t size) override; void Free(void* p) override; diff --git a/onnxruntime/core/providers/cuda/cuda_common.h b/onnxruntime/core/providers/cuda/cuda_common.h index 3dbe61b827c67..fa258961f1155 100644 --- a/onnxruntime/core/providers/cuda/cuda_common.h +++ b/onnxruntime/core/providers/cuda/cuda_common.h @@ -65,11 +65,7 @@ inline bool CalculateFdmStrides(gsl::span p, const std::vector= 7 : true); -#else enable_ = (mode == CUBLAS_TF32_TENSOR_OP_MATH ? prop.major >= 8 : true); -#endif if (enable_) { cublasGetMathMode(handle, &mode_); @@ -88,14 +84,14 @@ class CublasMathModeSetter { private: cublasHandle_t handle_; - cublasMath_t mode_; + cublasMath_t mode_ = CUBLAS_DEFAULT_MATH; bool enable_; }; // Cublas Gemm options for half data type class HalfGemmOptions { public: -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11000 +#if defined(USE_CUDA) cublasMath_t GetMathMode() const { if (pedantic_) { return CUBLAS_PEDANTIC_MATH; @@ -127,7 +123,7 @@ class HalfGemmOptions { void Initialize(int value) { compute_16f_ = (value & 0x01) > 0; -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11000 +#if defined(USE_CUDA) disallow_reduced_precision_reduction_ = (value & 0x02) > 0; pedantic_ = (value & 0x04) > 0; LOGS_DEFAULT(INFO) << "ORT_CUDA_GEMM_OPTIONS: compute_16f=" << instance.compute_16f_ @@ -143,7 +139,7 @@ class HalfGemmOptions { // Default is FP32. Aggregate in FP16 might be faster but the cost is loss in precision. bool compute_16f_{false}; -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11000 +#if defined(USE_CUDA) // Avoid intermediate overflows in accumulation. When compute type is FP32, it will not use FP16 in reduction. bool disallow_reduced_precision_reduction_{false}; diff --git a/onnxruntime/core/providers/cuda/cuda_execution_provider.cc b/onnxruntime/core/providers/cuda/cuda_execution_provider.cc index 412d078da6311..ad892eab3b843 100644 --- a/onnxruntime/core/providers/cuda/cuda_execution_provider.cc +++ b/onnxruntime/core/providers/cuda/cuda_execution_provider.cc @@ -19,6 +19,10 @@ #include "orttraining/training_ops/cuda/cuda_training_kernels.h" #endif +#ifdef USE_TRITON_KERNEL +#include "core/providers/cuda/triton_kernel.h" +#endif + #include "core/providers/cuda/cuda_stream_handle.h" using namespace onnxruntime::common; @@ -105,7 +109,7 @@ ONNX_OPERATOR_KERNEL_EX( kCudaExecutionProvider, (*KernelDefBuilder::Create()) .InputMemoryType(OrtMemTypeCPUInput, 0) - .TypeConstraint("T", DataTypeImpl::AllFixedSizeTensorAndSequenceTensorTypes()), + .TypeConstraint("T", DataTypeImpl::AllFixedSizeTensorAndSequenceTensorTypesIRv9()), Memcpy); ONNX_OPERATOR_KERNEL_EX( @@ -115,7 +119,7 @@ ONNX_OPERATOR_KERNEL_EX( kCudaExecutionProvider, (*KernelDefBuilder::Create()) .OutputMemoryType(OrtMemTypeCPUOutput, 0) - .TypeConstraint("T", DataTypeImpl::AllFixedSizeTensorAndSequenceTensorTypes()), + .TypeConstraint("T", DataTypeImpl::AllFixedSizeTensorAndSequenceTensorTypesIRv9()), Memcpy); } // namespace cuda @@ -124,7 +128,7 @@ AllocatorPtr CUDAExecutionProvider::CreateCudaAllocator(OrtDevice::DeviceId devi size_t gpu_mem_limit, ArenaExtendStrategy arena_extend_strategy, CUDAExecutionProviderExternalAllocatorInfo external_allocator_info, - OrtArenaCfg* default_memory_arena_cfg) { + const OrtArenaCfg* default_memory_arena_cfg) { if (external_allocator_info.UseExternalAllocator()) { AllocatorCreationInfo default_memory_info( [external_allocator_info](OrtDevice::DeviceId id) { @@ -145,7 +149,7 @@ AllocatorPtr CUDAExecutionProvider::CreateCudaAllocator(OrtDevice::DeviceId devi device_id, true, {default_memory_arena_cfg ? *default_memory_arena_cfg - : OrtArenaCfg(gpu_mem_limit, static_cast(arena_extend_strategy), -1, -1, -1)}, + : OrtArenaCfg(gpu_mem_limit, static_cast(arena_extend_strategy), -1, -1, -1, -1L)}, // make it stream aware true, // enable cross stream sharing? @@ -168,11 +172,7 @@ CUDAExecutionProvider::PerThreadContext::PerThreadContext(OrtDevice::DeviceId de CUDNN_CALL_THROW(cudnnCreate(&cudnn_handle_)); CUDNN_CALL_THROW(cudnnSetStream(cudnn_handle_, stream)); -#if defined(CUDA_VERSION) && CUDA_VERSION >= 10000 cuda_graph_.SetStream(stream); -#else - ORT_UNUSED_PARAMETER(stream); -#endif } CUDAExecutionProvider::PerThreadContext::~PerThreadContext() { @@ -181,7 +181,6 @@ CUDAExecutionProvider::PerThreadContext::~PerThreadContext() { ORT_IGNORE_RETURN_VALUE(CUDNN_CALL(cudnnDestroy(cudnn_handle_))); } -#if defined(CUDA_VERSION) && CUDA_VERSION >= 10000 bool CUDAExecutionProvider::PerThreadContext::IsGraphCaptureAllowed() const { return regular_run_count_before_graph_capture_ >= min_num_runs_before_cuda_graph_capture_; } @@ -208,7 +207,6 @@ Status CUDAExecutionProvider::PerThreadContext::ReplayGraph() { void CUDAExecutionProvider::PerThreadContext::IncrementRegularRunCountBeforeGraphCapture() { ++regular_run_count_before_graph_capture_; } -#endif void OverrideTunableOpInfoByEnv(CUDAExecutionProviderInfo& info) { if (auto env_tunable_op_enable = onnxruntime::ParseTestOnlyEnvironmentVariable( @@ -232,7 +230,7 @@ void OverrideTunableOpInfoByEnv(CUDAExecutionProviderInfo& info) { } CUDAExecutionProvider::CUDAExecutionProvider(const CUDAExecutionProviderInfo& info) - : IExecutionProvider{onnxruntime::kCudaExecutionProvider}, + : IExecutionProvider{onnxruntime::kCudaExecutionProvider, OrtDevice(OrtDevice::GPU, OrtDevice::MemType::DEFAULT, info.device_id)}, info_{info}, tuning_context_(this, &info_.tunable_op) { CUDA_CALL_THROW(cudaSetDevice(info_.device_id)); @@ -267,6 +265,10 @@ CUDAExecutionProvider::CUDAExecutionProvider(const CUDAExecutionProviderInfo& in CUDA_CALL_THROW(cudaMemGetInfo(&free, &total)); OverrideTunableOpInfoByEnv(info_); + +#ifdef USE_TRITON_KERNEL + onnxruntime::cuda::LoadOrtTritonKernel(); +#endif } CUDAExecutionProvider::~CUDAExecutionProvider() { @@ -362,22 +364,6 @@ void CUDAExecutionProvider::ReleasePerThreadContext() const { per_thread_context_cache->erase(cached_context_it); } -AllocatorPtr CUDAExecutionProvider::GetAllocator(OrtMemType mem_type) const { - if (mem_type == OrtMemTypeDefault) { - auto cuda_alloc = IExecutionProvider::GetAllocator(mem_type); - if (!cuda_alloc) { - // this means the program invoke GetAllocator before RegsiterAllocators, - // which only happnens in some UTs. - // here is a hack to return another allocator instance. - // need to fix this in the future. - return CreateCudaAllocator(info_.device_id, info_.gpu_mem_limit, info_.arena_extend_strategy, - info_.external_allocator_info, info_.default_memory_arena_cfg); - } - } - - return IExecutionProvider::GetAllocator(mem_type); -} - Status CUDAExecutionProvider::Sync() const { CUDA_RETURN_IF_ERROR(cudaDeviceSynchronize()); return Status::OK(); @@ -426,7 +412,6 @@ Status CUDAExecutionProvider::OnRunEnd(bool sync_stream) { return Status::OK(); } -#if defined(CUDA_VERSION) && CUDA_VERSION >= 10000 bool CUDAExecutionProvider::IsGraphCaptureEnabled() const { return info_.enable_cuda_graph; } @@ -438,7 +423,6 @@ bool CUDAExecutionProvider::IsGraphCaptured() const { Status CUDAExecutionProvider::ReplayGraph() { return GetPerThreadContext().ReplayGraph(); } -#endif namespace cuda { // opset 1 to 9 @@ -938,10 +922,10 @@ class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kO class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 11, float, Round); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 11, double, Round); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 11, MLFloat16, Round); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 10, int8_t, QuantizeLinear); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 10, uint8_t, QuantizeLinear); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 10, int8_t, DequantizeLinear); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 10, uint8_t, DequantizeLinear); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 10, 12, int8_t, QuantizeLinear); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 10, 12, uint8_t, QuantizeLinear); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 10, 12, int8_t, DequantizeLinear); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 10, 12, uint8_t, DequantizeLinear); class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 11, 13, CumSum); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 11, int64_t_int64_t_int64_t, OneHot); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 11, int64_t_float_int64_t, OneHot); @@ -1085,18 +1069,18 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, int64_t, NonZero); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, float, NonZero); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, MLFloat16, NonZero); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, float, Cast); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, double, Cast); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, MLFloat16, Cast); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, int8_t, Cast); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, int16_t, Cast); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, int32_t, Cast); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, int64_t, Cast); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, uint8_t, Cast); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, uint16_t, Cast); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, uint32_t, Cast); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, uint64_t, Cast); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, bool, Cast); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, 18, float, Cast); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, 18, double, Cast); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, 18, MLFloat16, Cast); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, 18, int8_t, Cast); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, 18, int16_t, Cast); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, 18, int32_t, Cast); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, 18, int64_t, Cast); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, 18, uint8_t, Cast); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, 18, uint16_t, Cast); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, 18, uint32_t, Cast); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, 18, uint64_t, Cast); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, 18, bool, Cast); class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, 13, Reshape); class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, 14, Shape); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, Size); @@ -1182,8 +1166,8 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, MLFloat16, Resize); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, int32_t, Resize); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, uint8_t, Resize); -class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, If); -class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, Loop); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, 18, If); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, 18, Loop); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, Flatten); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, float, LRN); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, double, LRN); @@ -1196,12 +1180,23 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, bool, Pad); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, SpaceToDepth); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, DepthToSpace); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, int8_t, Sign); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, int16_t, Sign); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, int32_t, Sign); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, int64_t, Sign); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, uint8_t, Sign); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, uint16_t, Sign); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, uint32_t, Sign); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, uint64_t, Sign); +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_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); class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, 13, BFloat16, Mul); class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, 13, BFloat16, Div); -class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, BFloat16, Cast); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, 18, BFloat16, Cast); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, BFloat16, Softmax); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, BFloat16, MatMul); class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, 13, BFloat16, Relu); @@ -1210,6 +1205,10 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, BFloat16, Gemm); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, BFloat16, ReduceSum); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, Mod); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, 18, int8_t, QuantizeLinear); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, 18, uint8_t, QuantizeLinear); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, 18, int8_t, DequantizeLinear); +class ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 13, 18, uint8_t, DequantizeLinear); // OpSet 14 class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 14, CumSum); @@ -1244,8 +1243,8 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 14, float, Div); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 14, double, Div); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 14, MLFloat16, Div); -class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 14, Identity); -class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 14, Reshape); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 14, 18, Identity); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 14, 18, Reshape); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 14, float, RNN); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 14, double, RNN); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 14, MLFloat16, RNN); @@ -1277,7 +1276,7 @@ class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 15, P class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 15, float, BatchNormalization); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 15, double, BatchNormalization); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 15, MLFloat16, BatchNormalization); -class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 15, Shape); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 15, 18, Shape); // Opset 16 class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 16, float, LeakyRelu); @@ -1286,7 +1285,7 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 16, float, PRelu); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 16, double, PRelu); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 16, MLFloat16, PRelu); -class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 16, Scan); +class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 16, 18, Scan); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 16, MLFloat16, Where); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 16, float, Where); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 16, double_t, Where); @@ -1317,6 +1316,57 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, // Opset 18 class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 18, Split); +// Opset 19 +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, float, Cast); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, double, Cast); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, MLFloat16, Cast); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, BFloat16, Cast); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, int8_t, Cast); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, int16_t, Cast); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, int32_t, Cast); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, int64_t, Cast); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, uint8_t, Cast); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, uint16_t, Cast); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, uint32_t, Cast); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, uint64_t, Cast); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, bool, Cast); +#if !defined(DISABLE_FLOAT8_TYPES) +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, Float8E4M3FN, Cast); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, Float8E5M2, Cast); +#endif + +class ONNX_OPERATOR_TWO_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, uint8_t, float, DequantizeLinear); +class ONNX_OPERATOR_TWO_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, int8_t, float, DequantizeLinear); +#if !defined(DISABLE_FLOAT8_TYPES) +class ONNX_OPERATOR_TWO_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, Float8E4M3FN, float, DequantizeLinear); +class ONNX_OPERATOR_TWO_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, Float8E5M2, float, DequantizeLinear); +#endif +class ONNX_OPERATOR_TWO_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, uint8_t, MLFloat16, DequantizeLinear); +class ONNX_OPERATOR_TWO_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, int8_t, MLFloat16, DequantizeLinear); +#if !defined(DISABLE_FLOAT8_TYPES) +class ONNX_OPERATOR_TWO_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, Float8E4M3FN, MLFloat16, DequantizeLinear); +class ONNX_OPERATOR_TWO_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, Float8E5M2, MLFloat16, DequantizeLinear); +#endif + +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, Identity); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, If); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, Loop); +class ONNX_OPERATOR_TWO_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, uint8_t, float, QuantizeLinear); +class ONNX_OPERATOR_TWO_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, int8_t, float, QuantizeLinear); +#if !defined(DISABLE_FLOAT8_TYPES) +class ONNX_OPERATOR_TWO_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, Float8E4M3FN, float, QuantizeLinear); +class ONNX_OPERATOR_TWO_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, Float8E5M2, float, QuantizeLinear); +#endif +class ONNX_OPERATOR_TWO_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, uint8_t, MLFloat16, QuantizeLinear); +class ONNX_OPERATOR_TWO_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, int8_t, MLFloat16, QuantizeLinear); +#if !defined(DISABLE_FLOAT8_TYPES) +class ONNX_OPERATOR_TWO_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, Float8E4M3FN, MLFloat16, QuantizeLinear); +class ONNX_OPERATOR_TWO_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, Float8E5M2, MLFloat16, QuantizeLinear); +#endif +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, Reshape); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, Scan); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kOnnxDomain, 19, Shape); + template <> KernelCreateInfo BuildKernelCreateInfo() { return {}; @@ -1324,881 +1374,949 @@ KernelCreateInfo BuildKernelCreateInfo() { static Status RegisterCudaKernels(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, - 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, - 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, - 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, - 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, - - // opset 10 - 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, - - // opset 11 - 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, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - - // OpSet 12 - BuildKernelCreateInfo, - - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - - BuildKernelCreateInfo, - - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - - BuildKernelCreateInfo, - - BuildKernelCreateInfo, - BuildKernelCreateInfo, - - // OpSet 13 - 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, - 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, - 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, - - // OpSet 14 - 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, - - // OpSet 15 - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - - // Opset 16 - 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, - - // Opset 17 - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - BuildKernelCreateInfo, - - // Opset 18 - BuildKernelCreateInfo, + 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, + 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, + 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, + 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, + 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, + + // opset 10 + 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, + + // opset 11 + 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, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + + // OpSet 12 + BuildKernelCreateInfo, + + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + + BuildKernelCreateInfo, + + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + + BuildKernelCreateInfo, + + BuildKernelCreateInfo, + BuildKernelCreateInfo, + + // OpSet 13 + 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, + 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, + 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, + + // OpSet 14 + 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, + + // OpSet 15 + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + + // Opset 16 + 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, + + // Opset 17 + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + + // Opset 18 + BuildKernelCreateInfo, + + // Opset 19 + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, +#if !defined(DISABLE_FLOAT8_TYPES) + BuildKernelCreateInfo, + BuildKernelCreateInfo, +#endif + + BuildKernelCreateInfo, + BuildKernelCreateInfo, +#if !defined(DISABLE_FLOAT8_TYPES) + BuildKernelCreateInfo, + BuildKernelCreateInfo, +#endif + BuildKernelCreateInfo, + BuildKernelCreateInfo, +#if !defined(DISABLE_FLOAT8_TYPES) + BuildKernelCreateInfo, + BuildKernelCreateInfo, +#endif + + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + + BuildKernelCreateInfo, + BuildKernelCreateInfo, +#if !defined(DISABLE_FLOAT8_TYPES) + BuildKernelCreateInfo, + BuildKernelCreateInfo, +#endif + BuildKernelCreateInfo, + BuildKernelCreateInfo, +#if !defined(DISABLE_FLOAT8_TYPES) + BuildKernelCreateInfo, + BuildKernelCreateInfo, +#endif + + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, }; for (auto& function_table_entry : function_table) { @@ -2441,86 +2559,10 @@ CUDAExecutionProvider::GetCapability(const onnxruntime::GraphViewer& graph, return result; } -void CUDAExecutionProvider::RegisterAllocator(AllocatorManager& allocator_manager) { - OrtDevice cuda_device{OrtDevice::GPU, OrtDevice::MemType::DEFAULT, info_.device_id}; - OrtDevice pinned_device{OrtDevice::CPU, OrtDevice::MemType::CUDA_PINNED, DEFAULT_CPU_ALLOCATOR_DEVICE_ID}; - OrtDevice cpu_device{OrtDevice::CPU, OrtDevice::MemType::DEFAULT, DEFAULT_CPU_ALLOCATOR_DEVICE_ID}; - - // setup CUDA allocator - // if EP is used in multiple inference sessions we may already have an allocator. if so use that. - // NOTE: We call IExecutionProvider::GetAllocator as CUDAExecutionProvider::GetAllocator will return - // a per-thread allocator for OrtMemTypeDefault. - auto cuda_alloc = IExecutionProvider::GetAllocator(OrtMemTypeDefault); - if (!cuda_alloc) { - // use shared allocator if available - cuda_alloc = allocator_manager.GetAllocator(OrtMemTypeDefault, cuda_device); - - if (!cuda_alloc) { - cuda_alloc = CreateCudaAllocator(info_.device_id, info_.gpu_mem_limit, info_.arena_extend_strategy, - info_.external_allocator_info, info_.default_memory_arena_cfg); - // enable sharing of our allocator - allocator_manager.InsertAllocator(cuda_alloc); - } - - InsertAllocator(cuda_alloc); - } - - // OrtMemTypeCPUOutput -- allocated by cudaMallocHost, used to copy CUDA device memory to CPU - // Use pinned memory instead of pageable memory make the data transfer faster - // Used by node MemcpyToHost only - auto cuda_pinned_alloc = IExecutionProvider::GetAllocator(OrtMemTypeCPUOutput); - if (!cuda_pinned_alloc) { - cuda_pinned_alloc = allocator_manager.GetAllocator(OrtMemTypeCPUOutput, pinned_device); - - if (!cuda_pinned_alloc) { - AllocatorCreationInfo pinned_memory_info( - [](OrtDevice::DeviceId device_id) { - return std::make_unique(device_id, CUDA_PINNED); - }, - // TODO: should we use info_.device_id instead of DEFAULT_CPU_ALLOCATOR_DEVICE_ID? - // https://docs.nvidia.com/cuda/cuda-runtime-api/group__CUDART__DEVICE.html#group__CUDART__DEVICE_1g159587909ffa0791bbe4b40187a4c6bb - // says the pinned memory allocated by cudaMallocHost is associated with a specific device, so it may be more - // correct to use the GPU device id, unless we wanted to share the pinned memory allocator across devices, - // at the risk the lifetime isn't managed correctly if one of those devices go away. - pinned_device.Id()); - - cuda_pinned_alloc = CreateAllocator(pinned_memory_info); - allocator_manager.InsertAllocator(cuda_pinned_alloc); - } - - InsertAllocator(cuda_pinned_alloc); - } - - // OrtMemTypeCPUInput -- op place the input on CPU and will not be accessed by CUDA kernel, no sync issue - auto cuda_cpu_alloc = IExecutionProvider::GetAllocator(OrtMemTypeCPUInput); - if (!cuda_cpu_alloc) { - cuda_cpu_alloc = allocator_manager.GetAllocator(OrtMemTypeCPUInput, cpu_device); - - if (!cuda_cpu_alloc) { - // TODO: this is actually used for the cuda kernels which explicitly ask for inputs from CPU. - // This will be refactored/removed when allocator and execution provider are decoupled. - // Need to move the OrtMemoryType out of Allocator, that's one thing blocking us to share it with CPU EP - // CPUAllocator is OrtMemTypeDefault for CPU EP - AllocatorCreationInfo cpu_memory_info( - [](int device_id) { - return std::make_unique( - OrtMemoryInfo("CUDA_CPU", OrtAllocatorType::OrtDeviceAllocator, OrtDevice(), device_id, - OrtMemTypeCPUInput)); - }, - cpu_device.Id()); - - cuda_cpu_alloc = CreateAllocator(cpu_memory_info); - allocator_manager.InsertAllocator(cuda_cpu_alloc); - } - - InsertAllocator(cuda_cpu_alloc); - } -} - -void CUDAExecutionProvider::RegisterStreamHandlers(IStreamCommandHandleRegistry& stream_handle_registry) const { +void CUDAExecutionProvider::RegisterStreamHandlers(IStreamCommandHandleRegistry& stream_handle_registry, AllocatorMap& allocators) const { // This allocator must be the same to the allocator // used in AllocateBufferOnCPUPinned. - auto allocator = GetAllocator(OrtMemTypeCPU); + auto allocator = allocators[GetOrtDeviceByMemType(OrtMemTypeCPU)]; RegisterCudaStreamHandles(stream_handle_registry, OrtDevice::GPU, allocator, @@ -2531,4 +2573,30 @@ void CUDAExecutionProvider::RegisterStreamHandlers(IStreamCommandHandleRegistry& GetPerThreadContext().CublasHandle()); } +OrtDevice CUDAExecutionProvider::GetOrtDeviceByMemType(OrtMemType mem_type) const { + // TODO(leca): For CpuInput, return default OrtDevice to make it consistent with previous logic, otherwise, it will fail GradientCheckerTest.TileGrad + // in Windows training scenario. However, we need to figure out why PINNED memType fails + if (mem_type == OrtMemTypeCPUInput) return OrtDevice(); + if (mem_type == OrtMemTypeCPUOutput) return OrtDevice(OrtDevice::CPU, OrtDevice::MemType::CUDA_PINNED, 0 /*CPU device id always be 0*/); + return default_device_; +} + +std::vector CUDAExecutionProvider::CreatePreferredAllocators() { + AllocatorCreationInfo pinned_memory_info( + [](OrtDevice::DeviceId) { + return std::make_unique(CUDA_PINNED); + }, + // TODO: should we use info_.device_id instead of DEFAULT_CPU_ALLOCATOR_DEVICE_ID? + // https://docs.nvidia.com/cuda/cuda-runtime-api/group__CUDART__DEVICE.html#group__CUDART__DEVICE_1g159587909ffa0791bbe4b40187a4c6bb + // says the pinned memory allocated by cudaMallocHost is associated with a specific device, so it may be more + // correct to use the GPU device id, unless we wanted to share the pinned memory allocator across devices, + // at the risk the lifetime isn't managed correctly if one of those devices go away. + 0); + return std::vector{ + CreateCudaAllocator(info_.device_id, info_.gpu_mem_limit, info_.arena_extend_strategy, + info_.external_allocator_info, info_.default_memory_arena_cfg), + CreateAllocator(pinned_memory_info), + }; +} + } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cuda/cuda_execution_provider.h b/onnxruntime/core/providers/cuda/cuda_execution_provider.h index d95cac03017eb..c9e510b7f472b 100644 --- a/onnxruntime/core/providers/cuda/cuda_execution_provider.h +++ b/onnxruntime/core/providers/cuda/cuda_execution_provider.h @@ -6,7 +6,6 @@ #include #include -#include "core/framework/allocatormgr.h" #include "core/framework/arena_extend_strategy.h" #include "core/framework/execution_provider.h" #include "core/platform/ort_mutex.h" @@ -27,8 +26,6 @@ class CUDAExecutionProvider : public IExecutionProvider { explicit CUDAExecutionProvider(const CUDAExecutionProviderInfo& info); virtual ~CUDAExecutionProvider(); - AllocatorPtr GetAllocator(OrtMemType mem_type) const override; - Status Sync() const override; Status OnRunStart() override; @@ -57,32 +54,6 @@ class CUDAExecutionProvider : public IExecutionProvider { return GetPerThreadContext().template GetConstOnes(count, stream); } - // GPU scratch buffer need to be allocated on stream - template - IAllocatorUniquePtr GetScratchBuffer(size_t count_or_bytes, Stream* stream, WaitNotificationFn wait_fn) const { - if (count_or_bytes == 0) - return nullptr; - return IAllocator::MakeUniquePtr(GetAllocator(OrtMemTypeDefault), count_or_bytes, false, stream, wait_fn); - } - - template - IAllocatorUniquePtr GetTransientScratchBuffer(size_t count_or_bytes) const { - if (count_or_bytes == 0) - return nullptr; - - return IAllocator::MakeUniquePtr(GetAllocator(OrtMemTypeDefault), count_or_bytes, true); - } - - template - IAllocatorUniquePtr AllocateBufferOnCPUPinned(size_t count_or_bytes) const { - // Note that OrtMemTypeCPU and OrtMemTypeCPUOutput are the same. See onnxruntime_c_api.h. - // In some CUDA async - if (count_or_bytes == 0) - return nullptr; - return IAllocator::MakeUniquePtr(GetAllocator(OrtMemTypeCPU), - count_or_bytes); - } - std::shared_ptr GetKernelRegistry() const override; std::unique_ptr GetDataTransfer() const override; @@ -96,25 +67,25 @@ class CUDAExecutionProvider : public IExecutionProvider { bool DoCopyOnDefaultStream() const { return info_.do_copy_in_default_stream; } bool GetCudnnConvUseMaxWorkspace() const { return info_.cudnn_conv_use_max_workspace; } bool GetCudnnConv1dPadToNc1d() const { return info_.cudnn_conv1d_pad_to_nc1d; } + bool IsSkipLayerNormInStrictMode() const { return info_.enable_skip_layer_norm_strict_mode; } ProviderOptions GetProviderOptions() const override { return CUDAExecutionProviderInfo::ToProviderOptions(info_); } - void RegisterAllocator(AllocatorManager& allocator_manager) override; static AllocatorPtr CreateCudaAllocator(OrtDevice::DeviceId device_id, size_t cuda_mem_limit, ArenaExtendStrategy arena_extend_strategy, - CUDAExecutionProviderExternalAllocatorInfo external_alloc_info, OrtArenaCfg* arena_cfg); + CUDAExecutionProviderExternalAllocatorInfo external_alloc_info, const OrtArenaCfg* arena_cfg); ITuningContext* GetTuningContext() const override; std::unique_ptr GetProfiler() override; -#if defined(CUDA_VERSION) && CUDA_VERSION >= 10000 bool IsGraphCaptureEnabled() const override; bool IsGraphCaptured() const override; Status ReplayGraph() override; -#endif - void RegisterStreamHandlers(IStreamCommandHandleRegistry& stream_handle_registry) const override; + void RegisterStreamHandlers(IStreamCommandHandleRegistry& stream_handle_registry, AllocatorMap& allocators) const override; + OrtDevice GetOrtDeviceByMemType(OrtMemType mem_type) const override; + std::vector CreatePreferredAllocators() override; private: CUDAExecutionProviderInfo info_; @@ -148,39 +119,57 @@ class CUDAExecutionProvider : public IExecutionProvider { template const T* GetConstOnes(size_t count, cudaStream_t stream) { - if (std::is_same::value) { + constexpr bool is_float = std::is_same::value; + constexpr bool is_double = std::is_same::value; + constexpr bool is_half = std::is_same::value; + constexpr bool is_BFloat16 = std::is_same::value; +#if !defined(DISABLE_FLOAT8_TYPES) + constexpr bool is_Float8E4M3FN = std::is_same::value; + constexpr bool is_Float8E5M2 = std::is_same::value; +#endif + if (is_float) { if (!constant_ones_float_) { constant_ones_float_ = cuda::CreateConstantOnes(); } return reinterpret_cast(constant_ones_float_->GetBuffer(stream, count)); - } else if (std::is_same::value) { + } else if (is_double) { if (!constant_ones_double_) { constant_ones_double_ = cuda::CreateConstantOnes(); } return reinterpret_cast(constant_ones_double_->GetBuffer(stream, count)); - } else if (std::is_same::value) { + } else if (is_half) { if (!constant_ones_half_) { constant_ones_half_ = cuda::CreateConstantOnes(); } return reinterpret_cast(constant_ones_half_->GetBuffer(stream, count)); - } else if (std::is_same::value) { + } else if (is_BFloat16) { if (!constant_ones_bfloat16_) { constant_ones_bfloat16_ = cuda::CreateConstantOnes(); } return reinterpret_cast(constant_ones_bfloat16_->GetBuffer(stream, count)); +#if !defined(DISABLE_FLOAT8_TYPES) + } else if (is_Float8E4M3FN) { + if (!constant_ones_float8e4m3fn_) { + constant_ones_float8e4m3fn_ = cuda::CreateConstantOnes(); + } + return reinterpret_cast(constant_ones_float8e4m3fn_->GetBuffer(stream, count)); + } else if (is_Float8E5M2) { + if (!constant_ones_float8e5m2_) { + constant_ones_float8e5m2_ = cuda::CreateConstantOnes(); + } + return reinterpret_cast(constant_ones_float8e5m2_->GetBuffer(stream, count)); +#endif } else { return nullptr; } } -#if defined(CUDA_VERSION) && CUDA_VERSION >= 10000 bool IsGraphCaptureAllowed() const; void CaptureBegin(); void CaptureEnd(); bool IsGraphCaptured() const; Status ReplayGraph(); void IncrementRegularRunCountBeforeGraphCapture(); -#endif private: cublasHandle_t cublas_handle_ = nullptr; @@ -191,16 +180,22 @@ class CUDAExecutionProvider : public IExecutionProvider { std::unique_ptr> constant_ones_double_; std::unique_ptr> constant_ones_half_; std::unique_ptr> constant_ones_bfloat16_; +#if !defined(DISABLE_FLOAT8_TYPES) + std::unique_ptr> constant_ones_float8e4m3fn_; + std::unique_ptr> constant_ones_float8e5m2_; +#endif -#if defined(CUDA_VERSION) && CUDA_VERSION >= 10000 // Cuda graph with multi threads will be supported in the future, so cuda_graph_ // is put under PerThreadContext. CUDAGraph cuda_graph_; 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. -#endif + // There is chance that the second regular run allocates GPU memory for causes like: + // (1) memory pattern is enabled. (2) arena allocation for stream. + // Since no GPU memory allocation is allowed during graph capturing, we need at least two regular runs + // to allocate enough memory in Arena before graph capturing. + const int min_num_runs_before_cuda_graph_capture_ = 2; // required min regular runs before graph capture for the necessary memory allocations. }; using PerThreadContextMap = std::unordered_map>; diff --git a/onnxruntime/core/providers/cuda/cuda_execution_provider_info.cc b/onnxruntime/core/providers/cuda/cuda_execution_provider_info.cc index eb257a652fe03..ca88b3474b758 100644 --- a/onnxruntime/core/providers/cuda/cuda_execution_provider_info.cc +++ b/onnxruntime/core/providers/cuda/cuda_execution_provider_info.cc @@ -14,6 +14,7 @@ namespace onnxruntime { namespace cuda { namespace provider_option_names { constexpr const char* kDeviceId = "device_id"; +constexpr const char* kHasUserComputeStream = "has_user_compute_stream"; constexpr const char* kMemLimit = "gpu_mem_limit"; constexpr const char* kArenaExtendStrategy = "arena_extend_strategy"; constexpr const char* kCudnnConvAlgoSearch = "cudnn_conv_algo_search"; @@ -26,6 +27,8 @@ constexpr const char* kEnableCudaGraph = "enable_cuda_graph"; constexpr const char* kCudnnConv1dPadToNc1d = "cudnn_conv1d_pad_to_nc1d"; constexpr const char* kTunableOpEnable = "tunable_op_enable"; constexpr const char* kTunableOpTuningEnable = "tunable_op_tuning_enable"; +constexpr const char* kTunableOpMaxTuningDurationMs = "tunable_op_max_tuning_duration_ms"; +constexpr const char* kEnableSkipLayerNormStrictMode = "enable_skip_layer_norm_strict_mode"; } // namespace provider_option_names } // namespace cuda @@ -59,6 +62,7 @@ CUDAExecutionProviderInfo CUDAExecutionProviderInfo::FromProviderOptions(const P ", must be between 0 (inclusive) and ", num_devices, " (exclusive)."); return Status::OK(); }) + .AddAssignmentToReference(cuda::provider_option_names::kHasUserComputeStream, info.has_user_compute_stream) .AddValueParser( cuda::provider_option_names::kGpuExternalAlloc, [&alloc](const std::string& value_str) -> Status { @@ -94,6 +98,7 @@ CUDAExecutionProviderInfo CUDAExecutionProviderInfo::FromProviderOptions(const P .AddAssignmentToReference(cuda::provider_option_names::kCudnnConvUseMaxWorkspace, info.cudnn_conv_use_max_workspace) .AddAssignmentToReference(cuda::provider_option_names::kEnableCudaGraph, info.enable_cuda_graph) .AddAssignmentToReference(cuda::provider_option_names::kCudnnConv1dPadToNc1d, info.cudnn_conv1d_pad_to_nc1d) + .AddAssignmentToReference(cuda::provider_option_names::kEnableSkipLayerNormStrictMode, info.enable_skip_layer_norm_strict_mode) .AddValueParser( cuda::provider_option_names::kTunableOpEnable, [&info](const std::string& value_str) -> Status { @@ -106,6 +111,12 @@ CUDAExecutionProviderInfo CUDAExecutionProviderInfo::FromProviderOptions(const P ORT_RETURN_IF_ERROR(ParseStringWithClassicLocale(value_str, info.tunable_op.tuning_enable)); return Status::OK(); }) + .AddValueParser( + cuda::provider_option_names::kTunableOpMaxTuningDurationMs, + [&info](const std::string& value_str) -> Status { + ORT_RETURN_IF_ERROR(ParseStringWithClassicLocale(value_str, info.tunable_op.max_tuning_duration_ms)); + return Status::OK(); + }) .Parse(options)); CUDAExecutionProviderExternalAllocatorInfo alloc_info{alloc, free, empty_cache}; @@ -116,6 +127,7 @@ CUDAExecutionProviderInfo CUDAExecutionProviderInfo::FromProviderOptions(const P ProviderOptions CUDAExecutionProviderInfo::ToProviderOptions(const CUDAExecutionProviderInfo& info) { const ProviderOptions options{ {cuda::provider_option_names::kDeviceId, MakeStringWithClassicLocale(info.device_id)}, + {cuda::provider_option_names::kHasUserComputeStream, MakeStringWithClassicLocale(info.has_user_compute_stream)}, {cuda::provider_option_names::kMemLimit, MakeStringWithClassicLocale(info.gpu_mem_limit)}, {cuda::provider_option_names::kGpuExternalAlloc, MakeStringWithClassicLocale(reinterpret_cast(info.external_allocator_info.alloc))}, {cuda::provider_option_names::kGpuExternalFree, MakeStringWithClassicLocale(reinterpret_cast(info.external_allocator_info.free))}, @@ -130,6 +142,8 @@ ProviderOptions CUDAExecutionProviderInfo::ToProviderOptions(const CUDAExecution {cuda::provider_option_names::kCudnnConv1dPadToNc1d, MakeStringWithClassicLocale(info.cudnn_conv1d_pad_to_nc1d)}, {cuda::provider_option_names::kTunableOpEnable, MakeStringWithClassicLocale(info.tunable_op.enable)}, {cuda::provider_option_names::kTunableOpTuningEnable, MakeStringWithClassicLocale(info.tunable_op.tuning_enable)}, + {cuda::provider_option_names::kTunableOpMaxTuningDurationMs, MakeStringWithClassicLocale(info.tunable_op.max_tuning_duration_ms)}, + {cuda::provider_option_names::kEnableSkipLayerNormStrictMode, MakeStringWithClassicLocale(info.enable_skip_layer_norm_strict_mode)}, }; return options; @@ -138,6 +152,7 @@ ProviderOptions CUDAExecutionProviderInfo::ToProviderOptions(const CUDAExecution ProviderOptions CUDAExecutionProviderInfo::ToProviderOptions(const OrtCUDAProviderOptionsV2& info) { const ProviderOptions options{ {cuda::provider_option_names::kDeviceId, MakeStringWithClassicLocale(info.device_id)}, + {cuda::provider_option_names::kHasUserComputeStream, MakeStringWithClassicLocale(info.has_user_compute_stream)}, {cuda::provider_option_names::kMemLimit, MakeStringWithClassicLocale(info.gpu_mem_limit)}, {cuda::provider_option_names::kArenaExtendStrategy, EnumToName(arena_extend_strategy_mapping, info.arena_extend_strategy)}, {cuda::provider_option_names::kCudnnConvAlgoSearch, EnumToName(ort_cudnn_conv_algo_search_mapping, info.cudnn_conv_algo_search)}, @@ -146,6 +161,7 @@ ProviderOptions CUDAExecutionProviderInfo::ToProviderOptions(const OrtCUDAProvid {cuda::provider_option_names::kCudnnConv1dPadToNc1d, MakeStringWithClassicLocale(info.cudnn_conv1d_pad_to_nc1d)}, {cuda::provider_option_names::kTunableOpEnable, MakeStringWithClassicLocale(info.tunable_op_enable)}, {cuda::provider_option_names::kTunableOpTuningEnable, MakeStringWithClassicLocale(info.tunable_op_tuning_enable)}, + {cuda::provider_option_names::kTunableOpMaxTuningDurationMs, MakeStringWithClassicLocale(info.tunable_op_max_tuning_duration_ms)}, }; return options; diff --git a/onnxruntime/core/providers/cuda/cuda_execution_provider_info.h b/onnxruntime/core/providers/cuda/cuda_execution_provider_info.h index 644096734510e..789b02b0e1d8c 100644 --- a/onnxruntime/core/providers/cuda/cuda_execution_provider_info.h +++ b/onnxruntime/core/providers/cuda/cuda_execution_provider_info.h @@ -40,6 +40,7 @@ namespace cuda { struct TunableOpInfo { bool enable{false}; bool tuning_enable{false}; + int max_tuning_duration_ms{}; }; } // namespace cuda @@ -69,6 +70,8 @@ struct CUDAExecutionProviderInfo { cuda::TunableOpInfo tunable_op{}; + bool enable_skip_layer_norm_strict_mode{false}; + static CUDAExecutionProviderInfo FromProviderOptions(const ProviderOptions& options); static ProviderOptions ToProviderOptions(const CUDAExecutionProviderInfo& info); static ProviderOptions ToProviderOptions(const OrtCUDAProviderOptionsV2& info); @@ -81,6 +84,7 @@ struct std::hash<::onnxruntime::cuda::TunableOpInfo> { size_t seed_and_value{0xbc9f1d34}; onnxruntime::HashCombine(info.enable, seed_and_value); onnxruntime::HashCombine(info.tuning_enable, seed_and_value); + onnxruntime::HashCombine(info.max_tuning_duration_ms, seed_and_value); return seed_and_value; } }; diff --git a/onnxruntime/core/providers/cuda/cuda_graph.cc b/onnxruntime/core/providers/cuda/cuda_graph.cc index 8915cda088ecc..230d664391611 100644 --- a/onnxruntime/core/providers/cuda/cuda_graph.cc +++ b/onnxruntime/core/providers/cuda/cuda_graph.cc @@ -10,9 +10,6 @@ namespace onnxruntime { CUDAGraph::CUDAGraph(cudaStream_t stream) : stream_(stream) { -#if (defined(CUDA_VERSION) && CUDA_VERSION < 10000) - ORT_THROW("CUDA graphs can only be used in Onnxruntime built with CUDA >= 10.0"); -#endif } void CUDAGraph::SetStream(cudaStream_t stream) { @@ -20,7 +17,6 @@ void CUDAGraph::SetStream(cudaStream_t stream) { } void CUDAGraph::CaptureBegin() { -#if defined(CUDA_VERSION) && CUDA_VERSION >= 10000 ORT_ENFORCE(!has_graph_exec_, "This cuda graph has already captured a graph. " "Create a new instance to capture a new graph."); @@ -31,13 +27,9 @@ void CUDAGraph::CaptureBegin() { // and streams, `cudaStreamCaptureModeGlobal` needs to be changed to // `cudaStreamCaptureModeThreadLocal` CUDA_CALL_THROW(cudaStreamBeginCapture(stream_, cudaStreamCaptureModeGlobal)); -#else - ORT_THROW("CUDA graphs can only be used in Onnxruntime built with CUDA >= 10.0"); -#endif } void CUDAGraph::CaptureEnd() { -#if defined(CUDA_VERSION) && CUDA_VERSION >= 10000 CUDA_CALL_THROW(cudaStreamEndCapture(stream_, &graph_)); if (graph_ == NULL) { ORT_THROW("CUDAGraph::CaptureEnd: graph_ is NULL"); @@ -48,26 +40,18 @@ void CUDAGraph::CaptureEnd() { has_graph_exec_ = true; CUDA_CALL_THROW(cudaGraphDestroy(graph_)); has_graph_ = false; -#else - ORT_THROW("CUDA graphs can only be used in Onnxruntime built with CUDA >= 10.0"); -#endif } Status CUDAGraph::Replay() { // Although this function is not thread safe, the lock is not needed here because // CUDA EP maintains a separate cuda graph per thread -#if defined(CUDA_VERSION) && CUDA_VERSION >= 10000 LOGS_DEFAULT(INFO) << "Replaying CUDA graph on stream " << stream_; CUDA_RETURN_IF_ERROR(cudaGraphLaunch(graph_exec_, stream_)); CUDA_RETURN_IF_ERROR(cudaStreamSynchronize(stream_)); -#else - ORT_THROW("CUDA graphs can only be used in Onnxruntime built with CUDA >= 10.0"); -#endif return Status::OK(); } void CUDAGraph::Reset() { -#if defined(CUDA_VERSION) && CUDA_VERSION >= 10000 if (has_graph_) { CUDA_CALL_THROW(cudaGraphDestroy(graph_)); has_graph_ = false; @@ -76,9 +60,6 @@ void CUDAGraph::Reset() { CUDA_CALL_THROW(cudaGraphExecDestroy(graph_exec_)); has_graph_exec_ = false; } -#else - ORT_THROW("CUDA graphs can only be used in Onnxruntime built with CUDA >= 10.0"); -#endif } CUDAGraph::~CUDAGraph() { diff --git a/onnxruntime/core/providers/cuda/cuda_graph.h b/onnxruntime/core/providers/cuda/cuda_graph.h index ebd7360dfa0f6..9bcefcc64ea77 100644 --- a/onnxruntime/core/providers/cuda/cuda_graph.h +++ b/onnxruntime/core/providers/cuda/cuda_graph.h @@ -23,10 +23,8 @@ struct CUDAGraph { void Reset(); private: -#if defined(CUDA_VERSION) && CUDA_VERSION >= 10000 cudaGraph_t graph_ = NULL; cudaGraphExec_t graph_exec_ = NULL; -#endif bool has_graph_ = false; bool has_graph_exec_ = false; diff --git a/onnxruntime/core/providers/cuda/cuda_kernel.h b/onnxruntime/core/providers/cuda/cuda_kernel.h index f7d7daddeda7b..58517c2850baf 100644 --- a/onnxruntime/core/providers/cuda/cuda_kernel.h +++ b/onnxruntime/core/providers/cuda/cuda_kernel.h @@ -41,7 +41,8 @@ class CudaKernel : public OpKernel { template inline IAllocatorUniquePtr GetScratchBuffer(size_t count_or_bytes, onnxruntime::Stream* stream) const { - return provider_->GetScratchBuffer(count_or_bytes, stream, WaitCudaNotificationOnDevice); + if (count_or_bytes == 0) return nullptr; + return IAllocator::MakeUniquePtr(Info().GetAllocator(OrtMemType::OrtMemTypeDefault), count_or_bytes, false, stream, WaitCudaNotificationOnDevice); } // Different from GetScratchBuffer which use IAllocator::Alloc() to allocate memory, @@ -50,7 +51,8 @@ class CudaKernel : public OpKernel { // logic (or similar for different allocator) that may be housed in the Alloc() implementation. template inline IAllocatorUniquePtr GetTransientScratchBuffer(size_t count_or_bytes) const { - return provider_->GetTransientScratchBuffer(count_or_bytes); + if (count_or_bytes == 0) return nullptr; + return IAllocator::MakeUniquePtr(Info().GetAllocator(OrtMemType::OrtMemTypeDefault), count_or_bytes, true); } inline void AddDeferredReleaseCPUPtr(void* p, onnxruntime::Stream* ort_stream) const { @@ -61,7 +63,8 @@ class CudaKernel : public OpKernel { template inline IAllocatorUniquePtr AllocateBufferOnCPUPinned(size_t count_or_bytes) const { - return provider_->AllocateBufferOnCPUPinned(count_or_bytes); + if (count_or_bytes == 0) return nullptr; + return IAllocator::MakeUniquePtr(Info().GetAllocator(OrtMemType::OrtMemTypeCPU), count_or_bytes); } const cudaDeviceProp& GetDeviceProp() const { return provider_->GetDeviceProp(); } diff --git a/onnxruntime/core/providers/cuda/cuda_profiler.cc b/onnxruntime/core/providers/cuda/cuda_profiler.cc index 492eff158b585..d220552204cef 100644 --- a/onnxruntime/core/providers/cuda/cuda_profiler.cc +++ b/onnxruntime/core/providers/cuda/cuda_profiler.cc @@ -10,7 +10,7 @@ namespace onnxruntime { namespace profiling { -#if defined(USE_CUDA) && defined(ENABLE_CUDA_PROFILING) && defined(CUDA_VERSION) && CUDA_VERSION >= 11000 +#if defined(USE_CUDA) && defined(ENABLE_CUDA_PROFILING) CudaProfiler::CudaProfiler() { auto& manager = CUPTIManager::GetInstance(); @@ -22,7 +22,7 @@ CudaProfiler::~CudaProfiler() { manager.DeregisterClient(client_handle_); } -#endif /* #if defined(USE_CUDA) && defined(ENABLE_CUDA_PROFILING) && defined(CUDA_VERSION) && CUDA_VERSION >= 11000 */ +#endif /* #if defined(USE_CUDA) && defined(ENABLE_CUDA_PROFILING) */ } // namespace profiling } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cuda/cuda_profiler.h b/onnxruntime/core/providers/cuda/cuda_profiler.h index 1f015cab7ab2f..88c9adc5e17b3 100644 --- a/onnxruntime/core/providers/cuda/cuda_profiler.h +++ b/onnxruntime/core/providers/cuda/cuda_profiler.h @@ -16,7 +16,7 @@ namespace profiling { // Do not move this check for CUDA_VERSION above #include "cupti_manager.h" // the CUDA_VERSION macro is defined in cupti.h, which in turn is included // by cupti_manager.h -#if defined(USE_CUDA) && defined(ENABLE_CUDA_PROFILING) && defined(CUDA_VERSION) && CUDA_VERSION >= 11000 +#if defined(USE_CUDA) && defined(ENABLE_CUDA_PROFILING) class CudaProfiler final : public GPUProfilerBase { public: @@ -25,7 +25,7 @@ class CudaProfiler final : public GPUProfilerBase { ~CudaProfiler(); }; -#else /* #if defined(USE_CUDA) && defined(ENABLE_CUDA_PROFILING) && defined(CUDA_VERSION) && CUDA_VERSION >= 11000 */ +#else /* #if defined(USE_CUDA) && defined(ENABLE_CUDA_PROFILING) */ class CudaProfiler final : public EpProfiler { public: diff --git a/onnxruntime/core/providers/cuda/cuda_provider_factory.cc b/onnxruntime/core/providers/cuda/cuda_provider_factory.cc index 5fb4f24014535..5a11f2529f38e 100644 --- a/onnxruntime/core/providers/cuda/cuda_provider_factory.cc +++ b/onnxruntime/core/providers/cuda/cuda_provider_factory.cc @@ -16,9 +16,6 @@ #include "core/providers/cuda/cuda_allocator.h" #include "core/providers/cuda/gpu_data_transfer.h" #include "core/providers/cuda/math/unary_elementwise_ops_impl.h" -#ifndef NDEBUG -#include "core/providers/cuda/test/all_tests.h" -#endif #ifdef ENABLE_NVTX_PROFILE #include "nvtx_profile.h" @@ -85,8 +82,8 @@ struct ProviderInfo_CUDA_Impl final : ProviderInfo_CUDA { return std::make_unique(device_id, name); } - std::unique_ptr CreateCUDAPinnedAllocator(int16_t device_id, const char* name) override { - return std::make_unique(device_id, name); + std::unique_ptr CreateCUDAPinnedAllocator(const char* name) override { + return std::make_unique(name); } std::unique_ptr CreateGPUDataTransfer() override { @@ -179,38 +176,9 @@ struct ProviderInfo_CUDA_Impl final : ProviderInfo_CUDA { return std::make_shared(info); } - std::shared_ptr CreateCudaAllocator(int16_t device_id, size_t gpu_mem_limit, onnxruntime::ArenaExtendStrategy arena_extend_strategy, onnxruntime::CUDAExecutionProviderExternalAllocatorInfo& external_allocator_info, OrtArenaCfg* default_memory_arena_cfg) override { + std::shared_ptr CreateCudaAllocator(int16_t device_id, size_t gpu_mem_limit, onnxruntime::ArenaExtendStrategy arena_extend_strategy, onnxruntime::CUDAExecutionProviderExternalAllocatorInfo& external_allocator_info, const OrtArenaCfg* default_memory_arena_cfg) override { return CUDAExecutionProvider::CreateCudaAllocator(device_id, gpu_mem_limit, arena_extend_strategy, external_allocator_info, default_memory_arena_cfg); } - -#ifndef NDEBUG - bool TestAll() override { - // TestAll is the entry point of CUDA EP's insternal tests. - // Those internal tests are not directly callable from onnxruntime_test_all - // because CUDA EP is a shared library now. - - // This is just one test. Call other test functions below. - if (!onnxruntime::cuda::test::TestDeferredRelease()) { - return false; - } - - if (!onnxruntime::cuda::test::TestDeferredReleaseWithoutArena()) { - return false; - } - - if (!onnxruntime::cuda::test::TestBeamSearchTopK()) { - return false; - } - - if (!onnxruntime::cuda::test::TestGreedySearchTopOne()) { - return false; - } - - // TODO(wechi): brings disabled tests in onnxruntime/test/providers/cuda/* - // back alive here. - return true; - } -#endif } g_info; struct CUDA_Provider : Provider { @@ -252,10 +220,19 @@ struct CUDA_Provider : Provider { info.cudnn_conv1d_pad_to_nc1d = params->cudnn_conv1d_pad_to_nc1d != 0; info.tunable_op.enable = params->tunable_op_enable; info.tunable_op.tuning_enable = params->tunable_op_tuning_enable; + info.tunable_op.max_tuning_duration_ms = params->tunable_op_max_tuning_duration_ms; + info.enable_skip_layer_norm_strict_mode = params->enable_skip_layer_norm_strict_mode != 0; return std::make_shared(info); } + /** + * This function will be called by the C API UpdateCUDAProviderOptions(). + * + * What this function does is equivalent to resetting the OrtCUDAProviderOptionsV2 instance with + * default CUDAExecutionProviderInf instance first and then set up the provided provider options. + * See CUDAExecutionProviderInfo::FromProviderOptions() for more details. + */ void UpdateProviderOptions(void* provider_options, const ProviderOptions& options) override { auto internal_options = onnxruntime::CUDAExecutionProviderInfo::FromProviderOptions(options); auto& cuda_options = *reinterpret_cast(provider_options); @@ -266,11 +243,16 @@ struct CUDA_Provider : Provider { cuda_options.arena_extend_strategy = internal_options.arena_extend_strategy; cuda_options.do_copy_in_default_stream = internal_options.do_copy_in_default_stream; cuda_options.has_user_compute_stream = internal_options.has_user_compute_stream; - cuda_options.user_compute_stream = internal_options.user_compute_stream; + // The 'has_user_compute_stream' of the OrtCUDAProviderOptionsV2 instance can be set byC API UpdateCUDAProviderOptionsWithValue() as well. + // We only set the 'has_user_compute_stream' of the OrtCUDAProviderOptionsV2 instance if it is provided in options + if (options.find("has_user_compute_stream") != options.end()) { + cuda_options.user_compute_stream = internal_options.user_compute_stream; + } cuda_options.default_memory_arena_cfg = internal_options.default_memory_arena_cfg; cuda_options.cudnn_conv_use_max_workspace = internal_options.cudnn_conv_use_max_workspace; cuda_options.enable_cuda_graph = internal_options.enable_cuda_graph; cuda_options.cudnn_conv1d_pad_to_nc1d = internal_options.cudnn_conv1d_pad_to_nc1d; + cuda_options.enable_skip_layer_norm_strict_mode = internal_options.enable_skip_layer_norm_strict_mode; } ProviderOptions GetProviderOptions(const void* provider_options) override { @@ -288,11 +270,8 @@ struct CUDA_Provider : Provider { } g_provider; -} // namespace onnxruntime - -extern "C" { - -ORT_API(onnxruntime::Provider*, GetProvider) { - return &onnxruntime::g_provider; -} +CUDA_Provider* GetProvider() { + return &g_provider; } + +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/cuda/cuda_provider_factory.h b/onnxruntime/core/providers/cuda/cuda_provider_factory.h index 47c9768625690..4d5ef658f6be0 100644 --- a/onnxruntime/core/providers/cuda/cuda_provider_factory.h +++ b/onnxruntime/core/providers/cuda/cuda_provider_factory.h @@ -3,6 +3,7 @@ #include "onnxruntime_c_api.h" #include "core/framework/provider_options.h" +#include "core/common/common.h" namespace onnxruntime { class IAllocator; @@ -24,7 +25,7 @@ struct ProviderInfo_CUDA { virtual OrtStatus* GetCurrentGpuDeviceId(_In_ int* device_id) = 0; virtual std::unique_ptr CreateCUDAAllocator(int16_t device_id, const char* name) = 0; - virtual std::unique_ptr CreateCUDAPinnedAllocator(int16_t device_id, const char* name) = 0; + virtual std::unique_ptr CreateCUDAPinnedAllocator(const char* name) = 0; virtual std::unique_ptr CreateGPUDataTransfer() = 0; virtual void cuda__Impl_Cast(void* stream, const int64_t* input_data, int32_t* output_data, size_t count) = 0; @@ -51,13 +52,13 @@ struct ProviderInfo_CUDA { #endif virtual std::shared_ptr CreateExecutionProviderFactory(const onnxruntime::CUDAExecutionProviderInfo& info) = 0; - virtual std::shared_ptr CreateCudaAllocator(int16_t device_id, size_t gpu_mem_limit, onnxruntime::ArenaExtendStrategy arena_extend_strategy, onnxruntime::CUDAExecutionProviderExternalAllocatorInfo& external_allocator_info, OrtArenaCfg* default_memory_arena_cfg) = 0; + virtual std::shared_ptr CreateCudaAllocator(int16_t device_id, size_t gpu_mem_limit, onnxruntime::ArenaExtendStrategy arena_extend_strategy, onnxruntime::CUDAExecutionProviderExternalAllocatorInfo& external_allocator_info, const OrtArenaCfg* default_memory_arena_cfg) = 0; -#ifndef NDEBUG - // This function is the entry point to CUDA EP's internal (aka not accessible from bridge code for shared library) - // tests and is only called from onnxruntime_test_all. Release builds don't need this function. - virtual bool TestAll() = 0; -#endif + // This function is the entry point to CUDA EP's UT cases. + // All tests ared only called from onnxruntime_test_all. + virtual void TestAll() { + ORT_NOT_IMPLEMENTED(__FUNCTION__, " is only implements in test code path."); + } protected: ~ProviderInfo_CUDA() = default; // Can only be destroyed through a subclass instance diff --git a/onnxruntime/core/providers/cuda/cuda_provider_interface.cc b/onnxruntime/core/providers/cuda/cuda_provider_interface.cc new file mode 100644 index 0000000000000..6cd5368cb7341 --- /dev/null +++ b/onnxruntime/core/providers/cuda/cuda_provider_interface.cc @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/session/onnxruntime_c_api.h" +#if !defined(USE_ROCM) + +namespace onnxruntime { +struct Provider; +struct CUDA_Provider; +CUDA_Provider* GetProvider(); +} // namespace onnxruntime + +extern "C" { + +ORT_API(onnxruntime::Provider*, GetProvider) { + return reinterpret_cast(onnxruntime::GetProvider()); +} +} + +#endif diff --git a/onnxruntime/core/providers/cuda/cuda_stream_handle.cc b/onnxruntime/core/providers/cuda/cuda_stream_handle.cc index 7f6b858038ce5..e855a515f445a 100644 --- a/onnxruntime/core/providers/cuda/cuda_stream_handle.cc +++ b/onnxruntime/core/providers/cuda/cuda_stream_handle.cc @@ -1,5 +1,6 @@ -//// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#include "core/providers/cuda/cuda_resource.h" #include "core/providers/cuda/cuda_stream_handle.h" #include "core/providers/cuda/cuda_common.h" #include "core/common/spin_pause.h" @@ -148,6 +149,25 @@ Status CudaStream::CleanUpOnRunEnd() { return Status::OK(); } +void* CudaStream::GetResource(int version, int id) const { + ORT_ENFORCE(version <= ORT_CUDA_RESOUCE_VERSION, "resource version unsupported!"); + void* resource{}; + switch (id) { + case CudaResource::cuda_stream_t: + return reinterpret_cast(GetHandle()); + break; + case CudaResource::cudnn_handle_t: + return reinterpret_cast(cudnn_handle_); + break; + case CudaResource::cublas_handle_t: + return reinterpret_cast(cublas_handle_); + break; + default: + break; + } + return resource; +} + // CPU Stream command handles void WaitCudaNotificationOnDevice(Stream& stream, synchronize::Notification& notification) { static_cast(¬ification)->wait_on_device(stream); diff --git a/onnxruntime/core/providers/cuda/cuda_stream_handle.h b/onnxruntime/core/providers/cuda/cuda_stream_handle.h index 3cf76cefe4f7d..9c62b029b7a36 100644 --- a/onnxruntime/core/providers/cuda/cuda_stream_handle.h +++ b/onnxruntime/core/providers/cuda/cuda_stream_handle.h @@ -1,5 +1,6 @@ -//// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. + #pragma once #include "core/providers/cuda/cuda_pch.h" #include "core/providers/cuda/shared_inc/cuda_utils.h" @@ -33,6 +34,8 @@ struct CudaStream : Stream { cublasHandle_t cublas_handle_{}; + void* GetResource(int version, int id) const override; + private: std::vector deferred_cpu_buffers_; AllocatorPtr cpu_allocator_; diff --git a/onnxruntime/core/providers/cuda/cuda_utils.cu b/onnxruntime/core/providers/cuda/cuda_utils.cu index cc9eaf9ae360b..934425656e3c9 100644 --- a/onnxruntime/core/providers/cuda/cuda_utils.cu +++ b/onnxruntime/core/providers/cuda/cuda_utils.cu @@ -72,6 +72,10 @@ template std::unique_ptr> CreateConstantOnes(); template std::unique_ptr> CreateConstantOnes(); template std::unique_ptr> CreateConstantOnes(); template std::unique_ptr> CreateConstantOnes(); +#if !defined(DISABLE_FLOAT8_TYPES) +template std::unique_ptr> CreateConstantOnes(); +template std::unique_ptr> CreateConstantOnes(); +#endif #define SPECIALIZED_FILL(T) \ template void Fill(cudaStream_t stream, T * output, T value, int64_t count); @@ -84,6 +88,10 @@ SPECIALIZED_FILL(float) SPECIALIZED_FILL(double) SPECIALIZED_FILL(__half) SPECIALIZED_FILL(BFloat16) +#if !defined(DISABLE_FLOAT8_TYPES) +SPECIALIZED_FILL(Float8E4M3FN) +SPECIALIZED_FILL(Float8E5M2) +#endif } // namespace cuda } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cuda/cudnn_common.cc b/onnxruntime/core/providers/cuda/cudnn_common.cc index 4c9cbbe605a7a..fc02a6509bf24 100644 --- a/onnxruntime/core/providers/cuda/cudnn_common.cc +++ b/onnxruntime/core/providers/cuda/cudnn_common.cc @@ -197,5 +197,21 @@ const uint8_t Consts::Zero = 0; template <> const uint8_t Consts::One = 1; +#if !defined(DISABLE_FLOAT8_TYPES) + +template <> +const Float8E4M3FN Consts::Zero = Float8E4M3FN(0.0f, true); + +template <> +const Float8E4M3FN Consts::One = Float8E4M3FN(1.0f, true); + +template <> +const Float8E5M2 Consts::Zero = Float8E5M2(0.0f, true); + +template <> +const Float8E5M2 Consts::One = Float8E5M2(1.0f, true); + +#endif + } // namespace cuda } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cuda/cupti_manager.cc b/onnxruntime/core/providers/cuda/cupti_manager.cc index 3a061ea04b056..11eac135219e9 100644 --- a/onnxruntime/core/providers/cuda/cupti_manager.cc +++ b/onnxruntime/core/providers/cuda/cupti_manager.cc @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #include "cupti_manager.h" #include @@ -5,7 +8,7 @@ namespace onnxruntime { namespace profiling { -#if defined(USE_CUDA) && defined(ENABLE_CUDA_PROFILING) && defined(CUDA_VERSION) && CUDA_VERSION >= 11000 +#if defined(USE_CUDA) && defined(ENABLE_CUDA_PROFILING) static inline std::string GetMemcpyKindString(CUpti_ActivityMemcpyKind kind) { switch (kind) { diff --git a/onnxruntime/core/providers/cuda/cupti_manager.h b/onnxruntime/core/providers/cuda/cupti_manager.h index 462f7171213bb..cca78dcec5ea5 100644 --- a/onnxruntime/core/providers/cuda/cupti_manager.h +++ b/onnxruntime/core/providers/cuda/cupti_manager.h @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #pragma once #if defined(USE_CUDA) && defined(ENABLE_CUDA_PROFILING) @@ -10,7 +13,7 @@ // Do not move the check for CUDA_VERSION above #include // the macros are defined in cupti.h -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11000 +#if defined(USE_CUDA) #include "core/common/gpu_profiler_common.h" #include "core/common/inlined_containers.h" @@ -48,5 +51,5 @@ class CUPTIManager : public GPUTracerManager { } /* namespace profiling */ } /* namespace onnxruntime */ -#endif /* #if defined(CUDA_VERSION) && CUDA_VERSION >= 11000 */ +#endif /* #if defined(USE_CUDA) */ #endif /* #if defined (USE_CUDA) && defined(ENABLE_CUDA_PROFILING) */ diff --git a/onnxruntime/core/providers/cuda/fpgeneric.cu b/onnxruntime/core/providers/cuda/fpgeneric.cu index 3ae0b9c8eb005..ef9eda8a0553c 100644 --- a/onnxruntime/core/providers/cuda/fpgeneric.cu +++ b/onnxruntime/core/providers/cuda/fpgeneric.cu @@ -64,11 +64,22 @@ __global__ void CopyVectorBFloat16(const onnxruntime::BFloat16* x, int incx, onn } // namespace +dim3 cublasTransposeHelperDimGrid(int m, int n) { + return dim3((n + TRANS_TILE_DIM - 1) / TRANS_TILE_DIM, (m + TRANS_TILE_DIM - 1) / TRANS_TILE_DIM, 1); +} + +// cublasTransposeHelper can only be used if it won't overflow the 65536 grid y dimension size +__host__ bool CanUse_cublasTransposeHelper_MLFloat16(int m, int n) { + dim3 dimGrid = cublasTransposeHelperDimGrid(m, n); + return dimGrid.y < 65536; +} + cublasStatus_t cublasTransposeHelper(cudaStream_t stream, cublasHandle_t, cublasOperation_t, cublasOperation_t, int m, int n, const half*, const half* A, int, const half*, const half*, int, half* C, int) { if (C != A) { - dim3 dimGrid((n + TRANS_TILE_DIM - 1) / TRANS_TILE_DIM, (m + TRANS_TILE_DIM - 1) / TRANS_TILE_DIM, 1); + dim3 dimGrid = cublasTransposeHelperDimGrid(m, n); dim3 dimBlock(TRANS_TILE_DIM, BLOCK_ROWS, 1); + ORT_ENFORCE(dimGrid.y < 65536); // To prevent this, call CanUse_cublasTransposeHelper_MLFloat16 first transposeNoOverlap<<>>(C, A, n, m); } else { return CUBLAS_STATUS_NOT_SUPPORTED; diff --git a/onnxruntime/core/providers/cuda/generator/constant_of_shape.cc b/onnxruntime/core/providers/cuda/generator/constant_of_shape.cc index a31e533b5f1dc..1a7f2422a8ca6 100644 --- a/onnxruntime/core/providers/cuda/generator/constant_of_shape.cc +++ b/onnxruntime/core/providers/cuda/generator/constant_of_shape.cc @@ -1,5 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. + #include "constant_of_shape.h" using namespace ::onnxruntime::common; diff --git a/onnxruntime/core/providers/cuda/math/clip.cc b/onnxruntime/core/providers/cuda/math/clip.cc index cb4cbeb9986fb..ea986798659e7 100644 --- a/onnxruntime/core/providers/cuda/math/clip.cc +++ b/onnxruntime/core/providers/cuda/math/clip.cc @@ -73,10 +73,10 @@ struct LowMax { template <> struct LowMax { static MLFloat16 low() { - return MLFloat16(math::floatToHalf(std::numeric_limits::lowest())); + return MLFloat16::FromBits(math::floatToHalf(std::numeric_limits::lowest())); } static MLFloat16 max() { - return MLFloat16(math::floatToHalf(std::numeric_limits::max())); + return MLFloat16::FromBits(math::floatToHalf(std::numeric_limits::max())); } }; } // namespace clip_internal diff --git a/onnxruntime/core/providers/cuda/math/einsum.cc b/onnxruntime/core/providers/cuda/math/einsum.cc index 98cfabcf5a593..b7c0d99a5390e 100644 --- a/onnxruntime/core/providers/cuda/math/einsum.cc +++ b/onnxruntime/core/providers/cuda/math/einsum.cc @@ -32,7 +32,7 @@ Status Einsum::DeviceCompute(OpKernelContext* context, const std::vector(stream); cublasHandle_t cublas_handle = cuda_stream ? cuda_stream->cublas_handle_ : nullptr; - EinsumOp::EinsumCudaAssets einsum_cuda_assets(cublas_handle, cuda_ep_, stream); + EinsumOp::EinsumCudaAssets einsum_cuda_assets(cublas_handle, cuda_ep_, stream, Info().GetAllocator(OrtMemType::OrtMemTypeDefault)); // EinsumComputePreprocessor section - auto einsum_compute_preprocessor = EinsumComputePreprocessor::Create(*einsum_equation_preprocessor_, inputs, allocator, diff --git a/onnxruntime/core/providers/cuda/math/einsum_utils/einsum_auxiliary_ops.cc b/onnxruntime/core/providers/cuda/math/einsum_utils/einsum_auxiliary_ops.cc index 5c43176a79fe5..3e50116eafd17 100644 --- a/onnxruntime/core/providers/cuda/math/einsum_utils/einsum_auxiliary_ops.cc +++ b/onnxruntime/core/providers/cuda/math/einsum_utils/einsum_auxiliary_ops.cc @@ -80,8 +80,8 @@ std::unique_ptr ReduceSum(const Tensor& input, gsl::span bool keep_dims, AllocatorPtr allocator, const TensorShape* input_shape_override, concurrency::ThreadPool* /*tp*/, void* einsum_cuda_assets) { - return cuda::ReductionOps::ReduceCompute(*static_cast(einsum_cuda_assets)->cuda_ep_, CUDNN_REDUCE_TENSOR_ADD, - allocator, input, reduce_axes, + return cuda::ReductionOps::ReduceCompute(static_cast(einsum_cuda_assets)->gpu_allocator_, CUDNN_REDUCE_TENSOR_ADD, + allocator, input, reduce_axes, // TODO(leca): is this allocator the same as the 1st parameter? keep_dims, false, false, false, true, static_cast(einsum_cuda_assets)->ort_stream_, input_shape_override); diff --git a/onnxruntime/core/providers/cuda/math/einsum_utils/einsum_auxiliary_ops.h b/onnxruntime/core/providers/cuda/math/einsum_utils/einsum_auxiliary_ops.h index af645c2e586f7..b152cb3cc1f9b 100644 --- a/onnxruntime/core/providers/cuda/math/einsum_utils/einsum_auxiliary_ops.h +++ b/onnxruntime/core/providers/cuda/math/einsum_utils/einsum_auxiliary_ops.h @@ -22,9 +22,10 @@ namespace EinsumOp { struct EinsumCudaAssets { explicit EinsumCudaAssets(cublasHandle_t cublas_handle, const CUDAExecutionProvider* cuda_ep, - Stream* ort_stream) : cublas_handle_(cublas_handle), - cuda_ep_(cuda_ep), - ort_stream_(ort_stream) {} + Stream* ort_stream, AllocatorPtr gpu_allocator) : cublas_handle_(cublas_handle), + cuda_ep_(cuda_ep), + ort_stream_(ort_stream), + gpu_allocator_(gpu_allocator) {} cudaStream_t GetCudaStream() { return ort_stream_ ? static_cast(ort_stream_->GetHandle()) : nullptr; @@ -33,6 +34,7 @@ struct EinsumCudaAssets { cublasHandle_t cublas_handle_; const CUDAExecutionProvider* cuda_ep_; Stream* ort_stream_; + AllocatorPtr gpu_allocator_; }; namespace DeviceHelpers { diff --git a/onnxruntime/core/providers/cuda/math/gemm.cc b/onnxruntime/core/providers/cuda/math/gemm.cc index 57e1b37c0c503..8fe23c9a036cc 100644 --- a/onnxruntime/core/providers/cuda/math/gemm.cc +++ b/onnxruntime/core/providers/cuda/math/gemm.cc @@ -2,9 +2,10 @@ // Licensed under the MIT License. #include "core/providers/cuda/math/gemm.h" + #include "core/providers/cpu/math/gemm_helper.h" -#include "core/providers/cuda/cuda_common.h" #include "core/providers/cuda/shared_inc/fpgeneric.h" +#include "core/providers/cuda/tunable/math/gemm.h" namespace onnxruntime { namespace cuda { @@ -57,20 +58,34 @@ REGISTER_KERNEL_TYPED(BFloat16) template Status Gemm::ComputeInternal(OpKernelContext* ctx) const { - typedef typename ToCudaType::MappedType CudaT; - const auto* X = ctx->Input(0); const auto* W = ctx->Input(1); const auto* B = ctx->Input(2); // Bias could be missing. Treat as scalar 0 if that is the case. GemmHelper helper(X->Shape(), trans_A_, W->Shape(), trans_B_, B != nullptr ? B->Shape() : TensorShape({})); - - if (!helper.State().IsOK()) - return helper.State(); - + if (!helper.State().IsOK()) return helper.State(); int M = gsl::narrow_cast(helper.M()); int N = gsl::narrow_cast(helper.N()); int K = gsl::narrow_cast(helper.K()); + + auto* Y = ctx->Output(0, {M, N}); + // Bail out early if the output is going to be empty + if (Y->Shape().Size() == 0) return Status::OK(); + + if (GetTuningContext()->IsTunableOpEnabled()) { + return tunable::TunableGemm(M, N, K, trans_A_, trans_B_, alpha_, B ? beta_ : 0.0f, this, ctx); + } + + return ComputeDefault(ctx, M, N, K); +} + +template +Status Gemm::ComputeDefault(OpKernelContext* ctx, int M, int N, int K) const { + typedef typename ToCudaType::MappedType CudaT; + + const auto* X = ctx->Input(0); + const auto* W = ctx->Input(1); + const auto* B = ctx->Input(2); auto* Y = ctx->Output(0, {M, N}); CudaT* out_data = reinterpret_cast(Y->MutableData()); diff --git a/onnxruntime/core/providers/cuda/math/gemm.h b/onnxruntime/core/providers/cuda/math/gemm.h index 0451d58cc9067..483a65961d043 100644 --- a/onnxruntime/core/providers/cuda/math/gemm.h +++ b/onnxruntime/core/providers/cuda/math/gemm.h @@ -25,6 +25,7 @@ class Gemm final : public CudaKernel { } Status ComputeInternal(OpKernelContext* context) const override; + Status ComputeDefault(OpKernelContext* context, int M, int N, int K) const; private: bool trans_A_; diff --git a/onnxruntime/core/providers/cuda/math/matmul.cc b/onnxruntime/core/providers/cuda/math/matmul.cc index 9d7e673109680..899d506f840a2 100644 --- a/onnxruntime/core/providers/cuda/math/matmul.cc +++ b/onnxruntime/core/providers/cuda/math/matmul.cc @@ -2,9 +2,10 @@ // Licensed under the MIT License. #include "core/providers/cuda/math/matmul.h" -#include "core/providers/cpu/math/matmul_helper.h" + #include "core/providers/cuda/shared_inc/fpgeneric.h" #include "core/providers/cuda/cuda_allocator.h" +#include "core/providers/cuda/tunable/math/matmul.h" namespace onnxruntime { namespace cuda { @@ -89,6 +90,37 @@ static bool CanUseStridedBatchedGemm(const TensorShape& left_shape, const Tensor template Status MatMul::ComputeInternal(OpKernelContext* ctx) const { + const Tensor* left_X = ctx->Input(0); + const Tensor* right_X = ctx->Input(1); + + // Ignore the transpose flag if rank of input being 1. + // Be noted: numpy.transpose on vector does not change anything. + bool trans_a = trans_A_; + bool trans_b = trans_B_; + if (left_X->Shape().NumDimensions() == 1) { + trans_a = false; + } + if (right_X->Shape().NumDimensions() == 1) { + trans_b = false; + } + + MatMulComputeHelper helper; + ORT_RETURN_IF_ERROR( + helper.Compute(left_X->Shape(), right_X->Shape(), trans_a, trans_b, trans_batch_a_, trans_batch_b_, false)); + + Tensor* Y = ctx->Output(0, helper.OutputShape()); + // Bail out early if the output is going to be empty + if (Y->Shape().Size() == 0) return Status::OK(); + + if (GetTuningContext()->IsTunableOpEnabled()) { + return tunable::TunableMatMul(alpha_, trans_a, trans_b, trans_batch_a_, trans_batch_b_, helper, this, ctx); + } + + return ComputeDefault(ctx, helper); +} + +template +Status MatMul::ComputeDefault(OpKernelContext* ctx, MatMulComputeHelper& helper) const { typedef typename ToCudaType::MappedType CudaT; const Tensor* left_X = ctx->Input(0); @@ -105,15 +137,8 @@ Status MatMul::ComputeInternal(OpKernelContext* ctx) const { transb = false; } - MatMulComputeHelper helper; - ORT_RETURN_IF_ERROR(helper.Compute(left_X->Shape(), right_X->Shape(), transa, transb, trans_batch_a_, trans_batch_b_, false)); - Tensor* Y = ctx->Output(0, helper.OutputShape()); - // Bail out early if the output is going to be empty - if (Y->Shape().Size() == 0) - return Status::OK(); - const CudaT alpha = ToCudaType::FromFloat(alpha_); const CudaT zero = ToCudaType::FromFloat(0.0f); @@ -180,6 +205,14 @@ Status MatMul::ComputeInternal(OpKernelContext* ctx) const { ORT_RETURN_IF_ERROR(right_arrays.CopyToGpu(ctx->GetComputeStream())); ORT_RETURN_IF_ERROR(output_arrays.CopyToGpu(ctx->GetComputeStream())); + // TF32 provides a huge performance gain for training and inference while preserving FP32 levels of accuracy. + // It requires Ampere or newer GPU, and pointers of matrics shall be aligned (ideal alignment is 16-byte). + // Assume that start memory of input/output tensor is aligned, we only check offsets of sub-matrix per batch here. + cublasMath_t mode = (std::is_same::value && device_prop.major >= 8 && helper.IsBatchedGemmAligned()) + ? CUBLAS_TF32_TENSOR_OP_MATH + : CUBLAS_DEFAULT_MATH; + CublasMathModeSetter math_mode_setter(device_prop, GetCublasHandle(ctx), mode); + // note that onnxruntime OrtValue is row major, while cublas is column major, // so swap left/right operands CUBLAS_RETURN_IF_ERROR(cublasGemmBatchedHelper( diff --git a/onnxruntime/core/providers/cuda/math/matmul.h b/onnxruntime/core/providers/cuda/math/matmul.h index f857fa1ee2455..5ea7b30777402 100644 --- a/onnxruntime/core/providers/cuda/math/matmul.h +++ b/onnxruntime/core/providers/cuda/math/matmul.h @@ -4,6 +4,7 @@ #pragma once #include "core/providers/cuda/cuda_kernel.h" +#include "core/providers/cpu/math/matmul_helper.h" namespace onnxruntime { namespace cuda { @@ -21,6 +22,7 @@ class MatMul final : public CudaKernel { trans_batch_b_{info.GetAttrOrDefault("transBatchB", 0) != 0} {} Status ComputeInternal(OpKernelContext* context) const override; + Status ComputeDefault(OpKernelContext* context, MatMulComputeHelper& helper) const; private: const float alpha_; diff --git a/onnxruntime/core/providers/cuda/math/softmax.cc b/onnxruntime/core/providers/cuda/math/softmax.cc index 56e4e052bb051..9402232a24737 100644 --- a/onnxruntime/core/providers/cuda/math/softmax.cc +++ b/onnxruntime/core/providers/cuda/math/softmax.cc @@ -13,7 +13,7 @@ namespace cuda { template Status SoftMaxComputeHelper( - cudaStream_t stream, + Stream* stream, const T* X, const TensorShape& input_shape, TOut* Y, @@ -26,8 +26,9 @@ Status SoftMaxComputeHelper( int64_t D = input_shape.SizeFromDimension(axis); auto Y_data = reinterpret_cast(Y); auto X_data = reinterpret_cast(X); - - if (D <= 1024 && D * sizeof(T) <= 4096) { + // According to nsight compute profiling, softmax_warp_forward_resource_efficient is better than dispatch_blockwise_softmax_forward when 1024 < D <=2048 and N >= 8192. + const bool use_softmax_warp_forward_resource_efficient = 1024 < D && D <= 2048 && D * sizeof(T) <= 4096 && N >= 8192; + if ((D <= 1024 && D * sizeof(T) <= 4096) or use_softmax_warp_forward_resource_efficient) { return dispatch_warpwise_softmax_forward< CudaT_IN, CudaT_OUT, AccumulationType_t, is_log_softmax>( stream, Y_data, X_data, gsl::narrow_cast(D), gsl::narrow_cast(D), gsl::narrow_cast(N)); @@ -39,9 +40,9 @@ Status SoftMaxComputeHelper( } #define SPECIALIZED_SOFTMAX_HELPER_IMPL(T, TOut) \ - template Status SoftMaxComputeHelper(cudaStream_t stream, const T* input, \ + template Status SoftMaxComputeHelper(Stream * stream, const T* input, \ const TensorShape& shape, TOut* Y, int64_t axis); \ - template Status SoftMaxComputeHelper(cudaStream_t stream, const T* input, \ + template Status SoftMaxComputeHelper(Stream * stream, const T* input, \ const TensorShape& shape, TOut* Y, int64_t axis); SPECIALIZED_SOFTMAX_HELPER_IMPL(MLFloat16, float) @@ -151,7 +152,7 @@ Status Softmax::ComputeInternal(OpKernelContext* ctx) const { auto temp_input = Tensor::Create(X->DataType(), TensorShape(transposed_input_dims), alloc); // Perform the transpose - ORT_RETURN_IF_ERROR(Transpose::DoTranspose(cuda_ep_->GetDeviceProp(), + ORT_RETURN_IF_ERROR(Transpose::DoTranspose(GetDeviceProp(), Stream(ctx), GetCublasHandle(ctx), permutation, *X, *temp_input)); @@ -177,11 +178,11 @@ Status Softmax::ComputeInternal(OpKernelContext* ctx) const { Status status; if (log_softmax_) { - status = SoftMaxComputeHelper(Stream(ctx), X_data, *compute_input_shape, Y_data, + status = SoftMaxComputeHelper(ctx->GetComputeStream(), X_data, *compute_input_shape, Y_data, is_transpose_required ? static_cast(rank) - 1 : static_cast(axis)); } else { - status = SoftMaxComputeHelper(Stream(ctx), X_data, *compute_input_shape, Y_data, + status = SoftMaxComputeHelper(ctx->GetComputeStream(), X_data, *compute_input_shape, Y_data, is_transpose_required ? static_cast(rank) - 1 : static_cast(axis)); } @@ -191,7 +192,7 @@ Status Softmax::ComputeInternal(OpKernelContext* ctx) const { if (is_transpose_required) { // Perform the transpose to get the axes back to the original ordering - ORT_RETURN_IF_ERROR(Transpose::DoTranspose(cuda_ep_->GetDeviceProp(), + ORT_RETURN_IF_ERROR(Transpose::DoTranspose(GetDeviceProp(), Stream(ctx), GetCublasHandle(ctx), permutation, *intermediate_output, *Y)); diff --git a/onnxruntime/core/providers/cuda/math/softmax.h b/onnxruntime/core/providers/cuda/math/softmax.h index 8e96857bc7f7f..bbe63e66e67db 100644 --- a/onnxruntime/core/providers/cuda/math/softmax.h +++ b/onnxruntime/core/providers/cuda/math/softmax.h @@ -11,18 +11,18 @@ namespace cuda { template Status SoftMaxComputeHelper( - cudaStream_t stream, + Stream* stream, const T* input, const TensorShape& shape, TOut* Y, int64_t axis); template -Status dispatch_warpwise_softmax_forward(cudaStream_t stream, output_t* dst, const input_t* src, +Status dispatch_warpwise_softmax_forward(Stream* stream, output_t* dst, const input_t* src, int softmax_elements, int softmax_elements_stride, int batch_count); template -Status dispatch_blockwise_softmax_forward(cudaStream_t stream, output_t* output, const input_t* input, +Status dispatch_blockwise_softmax_forward(Stream* stream, output_t* output, const input_t* input, int softmax_elements, int input_stride, int output_stride, int batch_count); template @@ -46,11 +46,6 @@ class Softmax final : public CudaKernel { } log_softmax_ = info.GetKernelDef().OpName() == "LogSoftmax"; - - // We need to cast away the const as PerThreadCublasHandle() is currently a non-const method - // TODO: Clean up the CUDAExecutionProvider interface to avoid this - cuda_ep_ = const_cast( - static_cast(info.GetExecutionProvider())); } Status ComputeInternal(OpKernelContext* context) const override; @@ -59,10 +54,6 @@ class Softmax final : public CudaKernel { int64_t axis_; bool log_softmax_; int opset_; - - // We need to access to the CUDA EP instance to get the cublas handle to use - // for transposing(if applicable) - CUDAExecutionProvider* cuda_ep_; }; } // namespace cuda diff --git a/onnxruntime/core/providers/cuda/math/softmax_impl.cu b/onnxruntime/core/providers/cuda/math/softmax_impl.cu index ddf07803fc843..a7da78fb4e146 100644 --- a/onnxruntime/core/providers/cuda/math/softmax_impl.cu +++ b/onnxruntime/core/providers/cuda/math/softmax_impl.cu @@ -29,8 +29,9 @@ namespace onnxruntime { namespace cuda { template -Status dispatch_warpwise_softmax_forward(cudaStream_t stream, output_t* dst, const input_t* src, int softmax_elements, +Status dispatch_warpwise_softmax_forward(Stream* ort_stream, output_t* dst, const input_t* src, int softmax_elements, int softmax_elements_stride, int batch_count) { + auto stream = static_cast(ort_stream->GetHandle()); if (softmax_elements == 0) { return Status::OK(); } else { @@ -39,78 +40,70 @@ Status dispatch_warpwise_softmax_forward(cudaStream_t stream, output_t* dst, con // This value must match the WARP_SIZE constexpr value computed inside softmax_warp_forward. int warp_size = (next_power_of_two < GPU_WARP_SIZE_HOST) ? next_power_of_two : GPU_WARP_SIZE_HOST; - - // This value must match the WARP_BATCH constexpr value computed inside softmax_warp_forward. + int threads_per_block, shared_memory_size; + // there are 2 options to save one row of the input matrix: register or shared memory + // when the number of elements is small, we use register; otherwise, we use shared memory; int batches_per_warp = (next_power_of_two <= 128) ? 2 : 1; - - // use 128 threads per block to maximimize gpu utilization - constexpr int threads_per_block = 128; - + if (log2_elements <= 10){ + // This value must match the WARP_BATCH constexpr value computed inside softmax_warp_forward. + // use 128 threads per block to maximimize gpu utilization + threads_per_block = 128; + shared_memory_size = 0; + } else{ + // setting the number of threads per block to 32 will make index offset calculations easier, + // under this setting, the cuda block number will be equal to batch size. + threads_per_block = 32; + // use shared memory to contain one row of elements + // TODO: one more optimization can be done here: we actually not need to save next_power_of_two elements, we can just save the valid elements + shared_memory_size = next_power_of_two * sizeof(input_t); + } int warps_per_block = (threads_per_block / warp_size); int batches_per_block = warps_per_block * batches_per_warp; int blocks = (batch_count + batches_per_block - 1) / batches_per_block; dim3 threads(warp_size, warps_per_block, 1); // Launch code would be more elegant if C++ supported FOR CONSTEXPR switch (log2_elements) { - case 0: // 1 - softmax_warp_forward - <<>>(dst, src, batch_count, softmax_elements_stride, softmax_elements); - break; - case 1: // 2 - softmax_warp_forward - <<>>(dst, src, batch_count, softmax_elements_stride, softmax_elements); - break; - case 2: // 4 - softmax_warp_forward - <<>>(dst, src, batch_count, softmax_elements_stride, softmax_elements); - break; - case 3: // 8 - softmax_warp_forward - <<>>(dst, src, batch_count, softmax_elements_stride, softmax_elements); - break; - case 4: // 16 - softmax_warp_forward - <<>>(dst, src, batch_count, softmax_elements_stride, softmax_elements); - break; - case 5: // 32 - softmax_warp_forward - <<>>(dst, src, batch_count, softmax_elements_stride, softmax_elements); - break; - case 6: // 64 - softmax_warp_forward - <<>>(dst, src, batch_count, softmax_elements_stride, softmax_elements); - break; - case 7: // 128 - softmax_warp_forward - <<>>(dst, src, batch_count, softmax_elements_stride, softmax_elements); - break; - case 8: // 256 - softmax_warp_forward - <<>>(dst, src, batch_count, softmax_elements_stride, softmax_elements); - break; - case 9: // 512 - softmax_warp_forward - <<>>(dst, src, batch_count, softmax_elements_stride, softmax_elements); - break; - case 10: // 1024 - softmax_warp_forward - <<>>(dst, src, batch_count, softmax_elements_stride, softmax_elements); - break; - default: - break; - } - } + +#define LAUNCH_KERNEL(kernel_name, log2_elements_value) \ + kernel_name \ + <<>>(dst, src, batch_count, softmax_elements_stride, softmax_elements); + +#define CASE_LOG2_ELEMENTS(log2_elements_value) \ + case log2_elements_value: { \ + if constexpr (log2_elements_value <= 10) { \ + LAUNCH_KERNEL(softmax_warp_forward, log2_elements_value) \ + } else { \ + LAUNCH_KERNEL(softmax_warp_forward_resource_efficient, log2_elements_value) \ + } \ + } break + + CASE_LOG2_ELEMENTS(0); + CASE_LOG2_ELEMENTS(1); + CASE_LOG2_ELEMENTS(2); + CASE_LOG2_ELEMENTS(3); + CASE_LOG2_ELEMENTS(4); + CASE_LOG2_ELEMENTS(5); + CASE_LOG2_ELEMENTS(6); + CASE_LOG2_ELEMENTS(7); + CASE_LOG2_ELEMENTS(8); + CASE_LOG2_ELEMENTS(9); + CASE_LOG2_ELEMENTS(10); + CASE_LOG2_ELEMENTS(11); // start to use softmax_warp_forward_resource_efficient instead of softmax_warp_forward for better performance +#undef LAUNCH_KERNEL +#undef CASE_LOG2_ELEMENTS + } // switch + } // else return CUDA_CALL(cudaGetLastError()); } #define SPECIALIZED_WRAPWISE_SOFTMAX_IMPL(input_t, output_t, acc_t) \ - template Status dispatch_warpwise_softmax_forward(cudaStream_t stream, \ + template Status dispatch_warpwise_softmax_forward(Stream* ort_stream, \ output_t * dst, \ const input_t* src, \ int softmax_elements, \ int softmax_elements_stride, \ int batch_count); \ - template Status dispatch_warpwise_softmax_forward(cudaStream_t stream, \ + template Status dispatch_warpwise_softmax_forward(Stream* ort_stream, \ output_t * dst, \ const input_t* src, \ int softmax_elements, \ @@ -124,8 +117,9 @@ SPECIALIZED_WRAPWISE_SOFTMAX_IMPL(double, double, double) SPECIALIZED_WRAPWISE_SOFTMAX_IMPL(BFloat16, BFloat16, float) template -Status dispatch_blockwise_softmax_forward(cudaStream_t stream, output_t* output, const input_t* input, int softmax_elements, +Status dispatch_blockwise_softmax_forward(Stream* ort_stream, output_t* output, const input_t* input, int softmax_elements, int input_stride, int output_stride, int batch_count) { + auto stream = static_cast(ort_stream->GetHandle()); dim3 grid(batch_count); constexpr int ILP = sizeof(float4) / sizeof(input_t); dim3 block = SoftMax_getBlockSize(ILP, softmax_elements); @@ -143,10 +137,10 @@ Status dispatch_blockwise_softmax_forward(cudaStream_t stream, output_t* output, #define SPECIALIZED_BLOCKWISE_SOFTMAX_IMPL(input_t, output_t, acc_t) \ template Status dispatch_blockwise_softmax_forward( \ - cudaStream_t stream, output_t * output, const input_t* src, int softmax_elements, \ + Stream* ort_stream, output_t * output, const input_t* src, int softmax_elements, \ int input_stride, int output_stride, int batch_count); \ template Status dispatch_blockwise_softmax_forward( \ - cudaStream_t stream, output_t * output, const input_t* src, int softmax_elements, \ + Stream* ort_stream, output_t * output, const input_t* src, int softmax_elements, \ int input_stride, int output_stride, int batch_count); SPECIALIZED_BLOCKWISE_SOFTMAX_IMPL(float, float, float) diff --git a/onnxruntime/core/providers/cuda/math/softmax_warpwise_impl.cuh b/onnxruntime/core/providers/cuda/math/softmax_warpwise_impl.cuh index 448e516f1ca26..c1b3d6ada8b77 100644 --- a/onnxruntime/core/providers/cuda/math/softmax_warpwise_impl.cuh +++ b/onnxruntime/core/providers/cuda/math/softmax_warpwise_impl.cuh @@ -163,5 +163,74 @@ __global__ void softmax_warp_forward(output_t* dst, const input_t* src, int batc } } + +// softmax_warp_forward uses register to store data in fp32 even when data is fp16, which will cause register resource oversubscription when data is large, +// and will lead to low CUDA warp occupancy and thus a poor kernel performance. +// softmax_warp_forward_resource_efficient is implemented to solve the issue, it caches data in original data type, and casts it into fp32 when needed, +// the idea is like we use recomputation to save resource usage. +template +__global__ void softmax_warp_forward_resource_efficient(output_t* dst, const input_t* src, int batch_size, int stride, int element_count) { + // 1 cuda block only processes one row and contains 1 cuda warp only. + constexpr int next_power_of_two = 1 << log2_elements; + constexpr int WARP_SIZE = (next_power_of_two < GPU_WARP_SIZE) ? next_power_of_two : GPU_WARP_SIZE; + constexpr int WARP_ITERATIONS = next_power_of_two / WARP_SIZE; + + int local_idx = threadIdx.x; + src += blockIdx.x * stride + local_idx; + dst += blockIdx.x * stride + local_idx; + extern __shared__ unsigned char smem[]; + input_t (&elements)[WARP_ITERATIONS][WARP_SIZE] = *reinterpret_cast(smem); +#pragma unroll + for (int it = 0; it < WARP_ITERATIONS; ++it) { + int element_index = local_idx + it * WARP_SIZE; + if (element_index < element_count) { + elements[it][local_idx] = src[it * WARP_SIZE]; + } else { + elements[it][local_idx] = -std::numeric_limits::infinity(); + } + } + // compute max_value + input_t max_value = elements[0][local_idx]; +#pragma unroll + for (int it = 1; it < WARP_ITERATIONS; ++it) { + max_value = (max_value > elements[it][local_idx]) ? max_value : elements[it][local_idx]; + } + warp_reduce(&max_value); + // compute sum + acc_t sum{0.0f}; + // #pragma unroll + // "exp" contains many instructions, if we unroll the loop then cuda warp will be stalled because of icache miss and thus lower the perf. + for (int it = 0; it < WARP_ITERATIONS; ++it) { + int element_index = local_idx + it * WARP_SIZE; + if (element_index >= element_count) + break; + if (is_log_softmax) { + sum += std::exp((float)(elements[it][local_idx] - max_value)); + } else { + acc_t tmp = std::exp((float)(elements[it][local_idx] - max_value)); + elements[it][local_idx] = tmp; + sum += tmp; + } + } + warp_reduce(&sum); + // store result + if (is_log_softmax) sum = static_cast(max_value) + std::log((float)(sum)); + // do the reciprocal once, so the div operation can be replaced by mul. + acc_t invsum = static_cast(1.0f / sum); +#pragma unroll + for (int it = 0; it < WARP_ITERATIONS; ++it) { + int element_index = local_idx + it * WARP_SIZE; + if (element_index < element_count) { + if (is_log_softmax) { + dst[it * WARP_SIZE] = (float)elements[it][local_idx] - sum; + } else { + dst[it * WARP_SIZE] = (float)elements[it][local_idx] * invsum; + } + } else { + break; + } + } +} + } // namespace cuda } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cuda/math/topk.cc b/onnxruntime/core/providers/cuda/math/topk.cc index 3b0edaa559ce9..d516537e25949 100644 --- a/onnxruntime/core/providers/cuda/math/topk.cc +++ b/onnxruntime/core/providers/cuda/math/topk.cc @@ -61,11 +61,12 @@ TopK::TopK(const OpKernelInfo& info) : CudaKernel(info) { } #define IS_PRIM_TYPE(T) utils::IsPrimitiveDataType(prim_type) -#define TOPKIMPL(T) TopKImpl(this, ctx->GetComputeStream(), tensor_X->Data(), \ - static_cast(tensor_V->MutableDataRaw()), \ - static_cast(tensor_I->MutableDataRaw()), \ - elem_nums_cuda, \ - elem_nums.size(), \ +#define TOPKIMPL(T) TopKImpl(this, use_deterministic_compute, \ + ctx->GetComputeStream(), tensor_X->Data(), \ + static_cast(tensor_V->MutableDataRaw()), \ + static_cast(tensor_I->MutableDataRaw()), \ + elem_nums_cuda, \ + elem_nums.size(), \ axis, K_, largest_, sorted_, N, dimension) template @@ -106,11 +107,14 @@ Status TopK::ComputeInternal(OpKernelContext* ctx) const { return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Type not supported for TopK operator"); } + bool use_deterministic_compute = ctx->GetUseDeterministicCompute(); + if (IS_PRIM_TYPE(int32_t)) return TOPKIMPL(int32_t); if (IS_PRIM_TYPE(int64_t)) return TOPKIMPL(int64_t); if (IS_PRIM_TYPE(MLFloat16)) return TOPKIMPL(MLFloat16); if (IS_PRIM_TYPE(float)) return TOPKIMPL(float); if (IS_PRIM_TYPE(double)) return TOPKIMPL(double); + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Type not supported for TopK operator"); } diff --git a/onnxruntime/core/providers/cuda/math/topk_impl.cuh b/onnxruntime/core/providers/cuda/math/topk_impl.cuh index 26c0eac5f313c..cbde6da457fdb 100644 --- a/onnxruntime/core/providers/cuda/math/topk_impl.cuh +++ b/onnxruntime/core/providers/cuda/math/topk_impl.cuh @@ -398,7 +398,10 @@ __global__ void ExcludeOutput(T* output_i, T K, T dimension) { } template -Status TopKImpl(const CudaKernel* kernel, Stream* ort_stream, const T* input_x, T* output_v, int64_t* output_i, const TArray& elem_nums, size_t size, int32_t axis, int64_t K, int64_t largest, int64_t sorted, int64_t N, int64_t dimension) { +Status TopKImpl(const CudaKernel* kernel, bool use_deterministic_compute, + Stream* ort_stream, const T* input_x, T* output_v, int64_t* output_i, + const TArray& elem_nums, size_t size, int32_t axis, int64_t K, int64_t largest, + int64_t sorted, int64_t N, int64_t dimension) { typedef typename ToCudaType::MappedType CudaT; const CudaT* input_x_ptr = reinterpret_cast(input_x); CudaT* output_v_ptr = reinterpret_cast(output_v); @@ -407,17 +410,34 @@ Status TopKImpl(const CudaKernel* kernel, Stream* ort_stream, const T* input_x, auto aligned_K = ALIGN(K); auto aligned_dimension = ALIGN(dimension); if (aligned_dimension <= GridDim::maxThreadsPerBlock) { - BitonicTopK<<), stream>>>(input_x_ptr, output_v_ptr, output_i, elem_nums, size, axis, K, aligned_K, largest, sorted, dimension, aligned_dimension, NumericLimits::Min(), NumericLimits::Max()); + BitonicTopK<<), stream>>>( + input_x_ptr, output_v_ptr, output_i, elem_nums, size, axis, K, aligned_K, largest, sorted, dimension, + aligned_dimension, NumericLimits::Min(), NumericLimits::Max()); } else if (K <= BT * 16 || 0 == sorted) { + if (use_deterministic_compute) { + static std::once_flag log_warning; + std::call_once(log_warning, []() { + LOGS_DEFAULT(WARNING) << "Non-deterministic TopKImpl kernel is called, its outputs may still be nondeterministic."; + }); + } + auto XPT = static_cast(ceil(static_cast(dimension) / GridDim::maxThreadsPerBlock)); if (BT * 2 >= K || 0 == sorted) { - RadixTopK<<>>(input_x_ptr, output_v_ptr, output_i, elem_nums, size, axis, K, largest, sorted, dimension, XPT, NumericLimits::Min(), NumericLimits::Max()); + RadixTopK<<>>( + input_x_ptr, output_v_ptr, output_i, elem_nums, size, axis, K, largest, sorted, dimension, XPT, + NumericLimits::Min(), NumericLimits::Max()); } else if (BT * 4 >= K) { - RadixTopK<<>>(input_x_ptr, output_v_ptr, output_i, elem_nums, size, axis, K, largest, sorted, dimension, XPT, NumericLimits::Min(), NumericLimits::Max()); + RadixTopK<<>>( + input_x_ptr, output_v_ptr, output_i, elem_nums, size, axis, K, largest, sorted, dimension, XPT, + NumericLimits::Min(), NumericLimits::Max()); } else if (BT * 8 >= K) { - RadixTopK<<>>(input_x_ptr, output_v_ptr, output_i, elem_nums, size, axis, K, largest, sorted, dimension, XPT, NumericLimits::Min(), NumericLimits::Max()); + RadixTopK<<>>( + input_x_ptr, output_v_ptr, output_i, elem_nums, size, axis, K, largest, sorted, dimension, XPT, + NumericLimits::Min(), NumericLimits::Max()); } else { - RadixTopK<<>>(input_x_ptr, output_v_ptr, output_i, elem_nums, size, axis, K, largest, sorted, dimension, XPT, NumericLimits::Min(), NumericLimits::Max()); + RadixTopK<<>>( + input_x_ptr, output_v_ptr, output_i, elem_nums, size, axis, K, largest, sorted, dimension, XPT, + NumericLimits::Min(), NumericLimits::Max()); } } else { auto input_key_buffer = kernel->GetScratchBuffer(dimension, ort_stream); @@ -451,6 +471,7 @@ Status TopKImpl(const CudaKernel* kernel, Stream* ort_stream, const T* input_x, } #define TOPKIMPLE(T) template Status TopKImpl(const CudaKernel* kernel, \ + bool use_deterministic_compute, \ Stream* ort_stream, \ const T* input_x, \ T* output_v, \ @@ -464,7 +485,7 @@ Status TopKImpl(const CudaKernel* kernel, Stream* ort_stream, const T* input_x, int64_t N, \ int64_t dimension) -// This file is causing excessive long compilation time in ROCm EP. Split all those compilation into multiple +// This file is causing excessive long compilation time in ROCm EP. Split all those compilations into multiple // translation units to speed it up. TOPKIMPLE(TOPK_IMPL_TYPE); diff --git a/onnxruntime/core/providers/cuda/math/topk_impl.h b/onnxruntime/core/providers/cuda/math/topk_impl.h index b9ba7f8e26b0a..c5f63aadc402a 100644 --- a/onnxruntime/core/providers/cuda/math/topk_impl.h +++ b/onnxruntime/core/providers/cuda/math/topk_impl.h @@ -11,7 +11,9 @@ namespace onnxruntime { namespace cuda { template -Status TopKImpl(const CudaKernel* kernel, Stream* ort_stream, const T* input_x, T* output_v, int64_t* output_i, const TArray& elem_nums, size_t size, int32_t axis, int64_t K, int64_t largest, int64_t sorted, int64_t N, int64_t dimension); +Status TopKImpl(const CudaKernel* kernel, bool use_deterministic_compute, Stream* ort_stream, + const T* input_x, T* output_v, int64_t* output_i, const TArray& elem_nums, + size_t size, int32_t axis, int64_t K, int64_t largest, int64_t sorted, int64_t N, int64_t dimension); } // namespace cuda } // 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 f026444328b24..9ede1f8d90ecc 100644 --- a/onnxruntime/core/providers/cuda/math/unary_elementwise_ops.cc +++ b/onnxruntime/core/providers/cuda/math/unary_elementwise_ops.cc @@ -157,6 +157,7 @@ UNARY_OP_HFD(Sqrt, 13) UNARY_OP_HFD(Log, 13) UNARY_OP_HFD(Exp, 13) UNARY_OP_HFD(Erf, 13) +UNARY_OP_BWUZCSILHFD(Sign, 13) UNARY_LOGICALOP_NOT_TYPED(1, bool) UNARY_OP_HFD(Round, 11) diff --git a/onnxruntime/core/providers/cuda/math/unary_elementwise_ops.h b/onnxruntime/core/providers/cuda/math/unary_elementwise_ops.h index 3ff97a60114df..775b78c43a736 100644 --- a/onnxruntime/core/providers/cuda/math/unary_elementwise_ops.h +++ b/onnxruntime/core/providers/cuda/math/unary_elementwise_ops.h @@ -112,5 +112,12 @@ class Cos final : public UnaryElementwise { Status ComputeInternal(OpKernelContext* context) const override; }; +template +class Sign final : public UnaryElementwise { + public: + Sign(const OpKernelInfo& info) : UnaryElementwise(info) {} + Status ComputeInternal(OpKernelContext* context) const override; +}; + } // namespace cuda } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cuda/math/unary_elementwise_ops_impl.cu b/onnxruntime/core/providers/cuda/math/unary_elementwise_ops_impl.cu index bb17158e29473..1298d53338337 100644 --- a/onnxruntime/core/providers/cuda/math/unary_elementwise_ops_impl.cu +++ b/onnxruntime/core/providers/cuda/math/unary_elementwise_ops_impl.cu @@ -6,6 +6,10 @@ #include "core/providers/cuda/cu_inc/common.cuh" #include "core/providers/cuda/cu_inc/unary_elementwise_impl.cuh" +#if defined(CUDA_VERSION) && CUDA_VERSION >= 11080 +#include "cuda_fp8.h" +#endif + namespace onnxruntime { namespace cuda { @@ -86,6 +90,7 @@ SPECIALIZED_UNARY_ELEMENTWISE_IMPL_HFD(Round) SPECIALIZED_UNARY_ELEMENTWISE_IMPL_HFD(Sin) SPECIALIZED_UNARY_ELEMENTWISE_IMPL_HFD(Cos) SPECIALIZED_UNARY_ELEMENTWISE_IMPL(Not, bool) +SPECIALIZED_UNARY_ELEMENTWISE_IMPL_BWUZCSILHFD(Sign) // When casting, half needs to be converted via float type from most other types template @@ -115,50 +120,168 @@ struct OP_Cast { } }; +#define IMPL_CAST_IMPL(InT, OutT) \ + void Explicit_Impl_Cast(cudaStream_t stream, const InT* input_data, OutT* output_data, size_t count) { \ + UnaryElementWiseImpl(stream, input_data, output_data, OP_Cast(), count); \ + } + +#define IMPL_CAST_IMPL_THROW(InT, OutT) \ + void Explicit_Impl_Cast(cudaStream_t stream, const InT* input_data, OutT* output_data, size_t count) { \ + ORT_THROW("Cast from " #InT " to " #OutT " must define saturate."); \ + } + +#if !defined(DISABLE_FLOAT8_TYPES) + +#define IMPL_CAST_IMPL_FROM(T) \ + IMPL_CAST_IMPL(T, half) \ + IMPL_CAST_IMPL(T, float) \ + IMPL_CAST_IMPL(T, double) \ + IMPL_CAST_IMPL(T, int8_t) \ + IMPL_CAST_IMPL(T, int16_t) \ + IMPL_CAST_IMPL(T, int32_t) \ + IMPL_CAST_IMPL(T, int64_t) \ + IMPL_CAST_IMPL(T, uint8_t) \ + IMPL_CAST_IMPL(T, uint16_t) \ + IMPL_CAST_IMPL(T, uint32_t) \ + IMPL_CAST_IMPL(T, uint64_t) \ + IMPL_CAST_IMPL(T, bool) \ + IMPL_CAST_IMPL(T, BFloat16) \ + IMPL_CAST_IMPL_THROW(T, Float8E4M3FN) \ + IMPL_CAST_IMPL_THROW(T, Float8E5M2) \ + IMPL_CAST_IMPL_THROW(T, Float8E4M3FNUZ) \ + IMPL_CAST_IMPL_THROW(T, Float8E5M2FNUZ) + +#else + +#define IMPL_CAST_IMPL_FROM(T) \ + IMPL_CAST_IMPL(T, half) \ + IMPL_CAST_IMPL(T, float) \ + IMPL_CAST_IMPL(T, double) \ + IMPL_CAST_IMPL(T, int8_t) \ + IMPL_CAST_IMPL(T, int16_t) \ + IMPL_CAST_IMPL(T, int32_t) \ + IMPL_CAST_IMPL(T, int64_t) \ + IMPL_CAST_IMPL(T, uint8_t) \ + IMPL_CAST_IMPL(T, uint16_t) \ + IMPL_CAST_IMPL(T, uint32_t) \ + IMPL_CAST_IMPL(T, uint64_t) \ + IMPL_CAST_IMPL(T, bool) \ + IMPL_CAST_IMPL(T, BFloat16) + +#endif + +IMPL_CAST_IMPL_FROM(half) +IMPL_CAST_IMPL_FROM(float) +IMPL_CAST_IMPL_FROM(double) +IMPL_CAST_IMPL_FROM(int8_t) +IMPL_CAST_IMPL_FROM(int16_t) +IMPL_CAST_IMPL_FROM(int32_t) +IMPL_CAST_IMPL_FROM(int64_t) +IMPL_CAST_IMPL_FROM(uint8_t) +IMPL_CAST_IMPL_FROM(uint16_t) +IMPL_CAST_IMPL_FROM(uint32_t) +IMPL_CAST_IMPL_FROM(uint64_t) +IMPL_CAST_IMPL_FROM(bool) +IMPL_CAST_IMPL_FROM(BFloat16) +#if !defined(DISABLE_FLOAT8_TYPES) +IMPL_CAST_IMPL_FROM(Float8E4M3FN) +IMPL_CAST_IMPL_FROM(Float8E5M2) +#endif + template -void Impl_Cast( - cudaStream_t stream, - const InT* input_data, - OutT* output_data, - size_t count) { - UnaryElementWiseImpl(stream, - input_data, - output_data, - OP_Cast(), - count); -} - -#define SPECIALIZED_CAST_IMPL2(InT, OutT) \ - template void Impl_Cast(cudaStream_t stream, const InT* input_data, OutT* output_data, size_t count); - -#define SPECIALIZED_CAST_FROM(T) \ - SPECIALIZED_CAST_IMPL2(T, half) \ - SPECIALIZED_CAST_IMPL2(T, float) \ - SPECIALIZED_CAST_IMPL2(T, double) \ - SPECIALIZED_CAST_IMPL2(T, int8_t) \ - SPECIALIZED_CAST_IMPL2(T, int16_t) \ - SPECIALIZED_CAST_IMPL2(T, int32_t) \ - SPECIALIZED_CAST_IMPL2(T, int64_t) \ - SPECIALIZED_CAST_IMPL2(T, uint8_t) \ - SPECIALIZED_CAST_IMPL2(T, uint16_t) \ - SPECIALIZED_CAST_IMPL2(T, uint32_t) \ - SPECIALIZED_CAST_IMPL2(T, uint64_t) \ - SPECIALIZED_CAST_IMPL2(T, bool) \ - SPECIALIZED_CAST_IMPL2(T, BFloat16) - -SPECIALIZED_CAST_FROM(half) -SPECIALIZED_CAST_FROM(float) -SPECIALIZED_CAST_FROM(double) -SPECIALIZED_CAST_FROM(int8_t) -SPECIALIZED_CAST_FROM(int16_t) -SPECIALIZED_CAST_FROM(int32_t) -SPECIALIZED_CAST_FROM(int64_t) -SPECIALIZED_CAST_FROM(uint8_t) -SPECIALIZED_CAST_FROM(uint16_t) -SPECIALIZED_CAST_FROM(uint32_t) -SPECIALIZED_CAST_FROM(uint64_t) -SPECIALIZED_CAST_FROM(bool) -SPECIALIZED_CAST_FROM(BFloat16) +struct OP_CastSat { + __device__ __inline__ OutT operator()(const InT& a) const; +}; + +template +struct OP_CastNoSat { + __device__ __inline__ OutT operator()(const InT& a) const; +}; + +#if defined(CUDA_VERSION) && CUDA_VERSION >= 11080 + +#define OP_CAST(T, NVT) \ + template <> \ + struct OP_CastSat { \ + __device__ __inline__ T operator()(const half& v) const { \ + return T(static_cast(__nv_cvt_halfraw_to_fp8(v, __NV_SATFINITE, NVT)), T::FromBits()); \ + } \ + }; \ + template <> \ + struct OP_CastNoSat { \ + __device__ __inline__ T operator()(const half& v) const { \ + return T(static_cast(__nv_cvt_halfraw_to_fp8(v, __NV_NOSAT, NVT)), T::FromBits()); \ + } \ + }; \ + template <> \ + struct OP_CastSat { \ + __device__ __inline__ T operator()(const float& v) const { \ + return T(static_cast(__nv_cvt_float_to_fp8(v, __NV_SATFINITE, NVT)), T::FromBits()); \ + } \ + }; \ + template <> \ + struct OP_CastNoSat { \ + __device__ __inline__ T operator()(const float& v) const { \ + return T(static_cast(__nv_cvt_float_to_fp8(v, __NV_NOSAT, NVT)), T::FromBits()); \ + } \ + }; + +#else + +#define OP_CAST(T, NVT) \ + template <> \ + struct OP_CastSat { \ + __device__ __inline__ T operator()(const half& v) const { \ + return T(__half2float(v), true); \ + } \ + }; \ + template <> \ + struct OP_CastNoSat { \ + __device__ __inline__ T operator()(const half& v) const { \ + return T(__half2float(v), false); \ + } \ + }; \ + template <> \ + struct OP_CastSat { \ + __device__ __inline__ T operator()(const float& v) const { \ + return T(v, true); \ + } \ + }; \ + template <> \ + struct OP_CastNoSat { \ + __device__ __inline__ T operator()(const float& v) const { \ + return T(v, false); \ + } \ + }; + +#endif + +#if !defined(DISABLE_FLOAT8_TYPES) + +OP_CAST(Float8E4M3FN, __NV_E4M3) +OP_CAST(Float8E5M2, __NV_E5M2) + +#define EXPLICIT_IMPL_CASTSAT(InT, OutT) \ + void Explicit_Impl_CastSat(cudaStream_t stream, const InT* input_data, OutT* output_data, size_t count, bool saturate) { \ + if (saturate) { \ + UnaryElementWiseImpl(stream, input_data, output_data, OP_CastSat(), count); \ + } else { \ + UnaryElementWiseImpl(stream, input_data, output_data, OP_CastNoSat(), count); \ + } \ + } + +EXPLICIT_IMPL_CASTSAT(float, Float8E4M3FN) +EXPLICIT_IMPL_CASTSAT(half, Float8E4M3FN) +EXPLICIT_IMPL_CASTSAT(float, Float8E5M2) +EXPLICIT_IMPL_CASTSAT(half, Float8E5M2) + +// TODO: enable bfloat16 in another PR. +/* +EXPLICIT_IMPL_CASTSAT(__nv_bfloat16, Float8E4M3FN) +EXPLICIT_IMPL_CASTSAT(__nv_bfloat16, Float8E5M2) +*/ + +#endif } // namespace cuda } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cuda/math/unary_elementwise_ops_impl.h b/onnxruntime/core/providers/cuda/math/unary_elementwise_ops_impl.h index c234ff248ce18..608a81a24cf4f 100644 --- a/onnxruntime/core/providers/cuda/math/unary_elementwise_ops_impl.h +++ b/onnxruntime/core/providers/cuda/math/unary_elementwise_ops_impl.h @@ -3,6 +3,11 @@ #pragma once +#include +#include "core/providers/cuda/shared_inc/cuda_utils.h" +#include "core/framework/float8.h" +#include + namespace onnxruntime { namespace cuda { @@ -26,7 +31,8 @@ namespace cuda { UNARY_OP_NAME_EXPR(Not, !a) \ UNARY_OP_NAME_EXPR(Round, _Round(a)) \ UNARY_OP_NAME_EXPR(Sin, _Sin(a)) \ - UNARY_OP_NAME_EXPR(Cos, _Cos(a)) + UNARY_OP_NAME_EXPR(Cos, _Cos(a)) \ + UNARY_OP_NAME_EXPR(Sign, _Sign(a)) #define UNARY_ELEMENTWISE_IMPL_DECLARATION(name) \ template \ @@ -40,12 +46,96 @@ namespace cuda { UNARY_OPS() #undef UNARY_OP_NAME_EXPR +// Cast + +#define DECL_IMPL_CAST(InT, OutT) \ + void Explicit_Impl_Cast(cudaStream_t stream, const InT* input_data, OutT* output_data, size_t count); + +#if !defined(DISABLE_FLOAT8_TYPES) + +#define DECL_IMPL_CAST_FROM(T) \ + DECL_IMPL_CAST(T, half) \ + DECL_IMPL_CAST(T, float) \ + DECL_IMPL_CAST(T, double) \ + DECL_IMPL_CAST(T, int8_t) \ + DECL_IMPL_CAST(T, int16_t) \ + DECL_IMPL_CAST(T, int32_t) \ + DECL_IMPL_CAST(T, int64_t) \ + DECL_IMPL_CAST(T, uint8_t) \ + DECL_IMPL_CAST(T, uint16_t) \ + DECL_IMPL_CAST(T, uint32_t) \ + DECL_IMPL_CAST(T, uint64_t) \ + DECL_IMPL_CAST(T, bool) \ + DECL_IMPL_CAST(T, BFloat16) \ + DECL_IMPL_CAST(T, Float8E4M3FN) \ + DECL_IMPL_CAST(T, Float8E5M2) + +#else + +#define DECL_IMPL_CAST_FROM(T) \ + DECL_IMPL_CAST(T, half) \ + DECL_IMPL_CAST(T, float) \ + DECL_IMPL_CAST(T, double) \ + DECL_IMPL_CAST(T, int8_t) \ + DECL_IMPL_CAST(T, int16_t) \ + DECL_IMPL_CAST(T, int32_t) \ + DECL_IMPL_CAST(T, int64_t) \ + DECL_IMPL_CAST(T, uint8_t) \ + DECL_IMPL_CAST(T, uint16_t) \ + DECL_IMPL_CAST(T, uint32_t) \ + DECL_IMPL_CAST(T, uint64_t) \ + DECL_IMPL_CAST(T, bool) \ + DECL_IMPL_CAST(T, BFloat16) + +#endif + +DECL_IMPL_CAST_FROM(half) +DECL_IMPL_CAST_FROM(float) +DECL_IMPL_CAST_FROM(double) +DECL_IMPL_CAST_FROM(int8_t) +DECL_IMPL_CAST_FROM(int16_t) +DECL_IMPL_CAST_FROM(int32_t) +DECL_IMPL_CAST_FROM(int64_t) +DECL_IMPL_CAST_FROM(uint8_t) +DECL_IMPL_CAST_FROM(uint16_t) +DECL_IMPL_CAST_FROM(uint32_t) +DECL_IMPL_CAST_FROM(uint64_t) +DECL_IMPL_CAST_FROM(bool) +DECL_IMPL_CAST_FROM(BFloat16) + +#if !defined(DISABLE_FLOAT8_TYPES) + +DECL_IMPL_CAST_FROM(Float8E4M3FN) +DECL_IMPL_CAST_FROM(Float8E5M2) + +#define DECL_IMPL_CASTSAT(InT, OutT) \ + void Explicit_Impl_CastSat(cudaStream_t stream, const InT* input_data, OutT* output_data, size_t count, bool saturate); + +DECL_IMPL_CASTSAT(half, Float8E4M3FN) +DECL_IMPL_CASTSAT(float, Float8E4M3FN) +DECL_IMPL_CASTSAT(half, Float8E5M2) +DECL_IMPL_CASTSAT(float, Float8E5M2) + +#endif + template -void Impl_Cast( +void Impl_Cast(cudaStream_t stream, const InT* input_data, OutT* output_data, size_t count) { + Explicit_Impl_Cast(stream, input_data, output_data, count); +} + +#if !defined(DISABLE_FLOAT8_TYPES) + +template +void Impl_CastSat( cudaStream_t stream, const InT* input_data, OutT* output_data, - size_t count); + size_t count, + bool saturate) { + Explicit_Impl_CastSat(stream, input_data, output_data, count, saturate); +} + +#endif } // namespace cuda } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cuda/nn/layer_norm_impl.cu b/onnxruntime/core/providers/cuda/nn/layer_norm_impl.cu index 458dcf0b0f080..4cc560a1178ef 100644 --- a/onnxruntime/core/providers/cuda/nn/layer_norm_impl.cu +++ b/onnxruntime/core/providers/cuda/nn/layer_norm_impl.cu @@ -338,7 +338,9 @@ __global__ void cuApplyLayerNorm( const V* __restrict__ beta, const T* __restrict__ skip, const T* __restrict__ bias, - T* __restrict__ skip_input_bias_add_output) { + T* __restrict__ skip_input_bias_add_output, + const bool skip_broadcasted, + const int skip_size) { // Assumptions: // 1) blockDim.x == GPU_WARP_SIZE // 2) Tensors are contiguous @@ -358,11 +360,16 @@ __global__ void cuApplyLayerNorm( for (int i = thrx; i < n2; i += numx) { U curr = static_cast(lvals[i]); + + if (bias != NULL) { curr += static_cast(bias[i]); } - if (skip_vals != NULL) { + if (skip_vals != NULL && skip_broadcasted) { + int skip_i = i % skip_size; + curr += static_cast(skip_vals[skip_i]); //Calculates index for the second dimension of the skip tensor + }else if (skip_vals != NULL){ curr += static_cast(skip_vals[i]); } @@ -411,7 +418,9 @@ void HostApplyLayerNorm( const V* beta, const T* skip, const T* bias, - T* skip_input_bias_add_output) { + T* skip_input_bias_add_output, + const bool skip_broadcasted, + const int skip_size) { const int maxGridY = prop.maxGridSize[1]; const int warp_size = prop.warpSize; ORT_ENFORCE(warp_size == GPU_WARP_SIZE_HOST); @@ -443,14 +452,17 @@ void HostApplyLayerNorm( n1, n2, U(epsilon), gamma, beta, - skip, bias, skip_input_bias_add_output); + skip, bias, skip_input_bias_add_output, + skip_broadcasted, + skip_size); } #define LAYERNORM_LINEAR_IMPL(T, U, V, simplified) \ template void HostApplyLayerNorm(const cudaDeviceProp& prop, cudaStream_t stream, V* output, \ U* mean, U* inv_std_dev, const T* input, int n1, int n2, \ double epsilon, const V* gamma, const V* beta, const T* skip, \ - const T* bias, T* skip_input_bias_add_output); + const T* bias, T* skip_input_bias_add_output, const bool skip_broadcasted, \ + const int skip_size); LAYERNORM_LINEAR_IMPL(float, float, float, true) LAYERNORM_LINEAR_IMPL(half, float, half, true) diff --git a/onnxruntime/core/providers/cuda/nn/layer_norm_impl.h b/onnxruntime/core/providers/cuda/nn/layer_norm_impl.h index e3952eefae35d..d0d5db8ba3587 100644 --- a/onnxruntime/core/providers/cuda/nn/layer_norm_impl.h +++ b/onnxruntime/core/providers/cuda/nn/layer_norm_impl.h @@ -43,7 +43,9 @@ void HostApplyLayerNorm( const V* beta, const T* skip = nullptr, const T* bias = nullptr, - T* skip_input_bias_add_output = nullptr); + T* skip_input_bias_add_output = nullptr, + const bool skip_broadcasted = false, + const int skip_size = 0); } // namespace cuda } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cuda/nvtx_profile.cc b/onnxruntime/core/providers/cuda/nvtx_profile.cc index 6d8e172e918c0..6c7c594066b86 100644 --- a/onnxruntime/core/providers/cuda/nvtx_profile.cc +++ b/onnxruntime/core/providers/cuda/nvtx_profile.cc @@ -4,8 +4,13 @@ #ifdef ENABLE_NVTX_PROFILE #include "nvtx_profile.h" #include "core/common/common.h" +#if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__) +#include +#include +#else #include #include +#endif namespace onnxruntime { namespace profile { @@ -62,4 +67,4 @@ void NvtxMarkerCreator::Mark() { } // namespace profile } // namespace onnxruntime -#endif \ No newline at end of file +#endif diff --git a/onnxruntime/core/providers/cuda/reduction/reduction_ops.cc b/onnxruntime/core/providers/cuda/reduction/reduction_ops.cc index 96e7a853a5dfc..2f057d53d5607 100644 --- a/onnxruntime/core/providers/cuda/reduction/reduction_ops.cc +++ b/onnxruntime/core/providers/cuda/reduction/reduction_ops.cc @@ -443,7 +443,7 @@ Status PrepareForReduce(const Tensor* X, // `input_shape_override` is the input shape for compute purposes (if provided) template -Status ReduceComputeCore(const CUDAExecutionProvider& cuda_ep, const Tensor& input, PrepareReduceMetadata& prepare_reduce_metadata, +Status ReduceComputeCore(const AllocatorPtr& gpu_allocator, const Tensor& input, PrepareReduceMetadata& prepare_reduce_metadata, /*out*/ Tensor& output, cudnnReduceTensorOp_t cudnn_reduce_op, gsl::span axes, bool calculate_log, bool calculate_sqt, bool log_sum_exp, bool fast_reduction, @@ -473,7 +473,7 @@ Status ReduceComputeCore(const CUDAExecutionProvider& cuda_ep, const Tensor& inp IAllocatorUniquePtr input_data_buffer(nullptr, [](T*) {}); const CudaT* input_data = reinterpret_cast(input.Data()); if (calculate_sqt) { - input_data_buffer = cuda_ep.GetScratchBuffer(input_count, ort_stream, WaitCudaNotificationOnDevice); + input_data_buffer = IAllocator::MakeUniquePtr(gpu_allocator, input_count, false, ort_stream, WaitCudaNotificationOnDevice); input_data = reinterpret_cast(input_data_buffer.get()); fast_divmod tmp_div; Impl_Mul(stream, static_cast(SimpleBroadcast::NoBroadcast), nullptr, @@ -490,7 +490,7 @@ Status ReduceComputeCore(const CUDAExecutionProvider& cuda_ep, const Tensor& inp } break; case ApplicableMatrixReduction::Columns: { const auto buffer_size_bytes = compute_reduce_matrix_columns_buffer_size(m, n); - auto buffer = cuda_ep.GetScratchBuffer(buffer_size_bytes, ort_stream, WaitCudaNotificationOnDevice); + auto buffer = buffer_size_bytes == 0 ? nullptr : IAllocator::MakeUniquePtr(gpu_allocator, buffer_size_bytes, false, ort_stream, WaitCudaNotificationOnDevice); ORT_RETURN_IF_ERROR(reduce_matrix_columns(stream, input_data, reinterpret_cast(output.MutableData()), m, n, buffer.get(), buffer_size_bytes)); @@ -527,7 +527,7 @@ Status ReduceComputeCore(const CUDAExecutionProvider& cuda_ep, const Tensor& inp if ((ReduceTensorIndices == CUDNN_REDUCE_TENSOR_FLATTENED_INDICES && std::is_same::value) || (ReduceTensorIndices == CUDNN_REDUCE_TENSOR_NO_INDICES && std::is_same::value)) { // ArgMax/ArgMin with FP16 are not supported by cudnn, so convert input to fp32 then call cudnn - temp_X = cuda_ep.GetScratchBuffer(input_count, ort_stream, WaitCudaNotificationOnDevice); + temp_X = IAllocator::MakeUniquePtr(gpu_allocator, input_count, false, ort_stream, WaitCudaNotificationOnDevice); Impl_Cast(stream, reinterpret_cast(input.Data()), temp_X.get(), input_shape.Size()); } else { cudnn_type_X = CudnnTensor::GetDataType(); @@ -550,18 +550,18 @@ Status ReduceComputeCore(const CUDAExecutionProvider& cuda_ep, const Tensor& inp CudaStream* cuda_stream = static_cast(ort_stream); CUDNN_RETURN_IF_ERROR(cudnnGetReductionWorkspaceSize(CudaKernel::GetCudnnHandle(cuda_stream), reduce_desc, input_tensor, output_tensor, &workspace_bytes)); - auto workspace_cuda = cuda_ep.GetScratchBuffer(workspace_bytes, ort_stream, WaitCudaNotificationOnDevice); + auto workspace_cuda = workspace_bytes == 0 ? nullptr : IAllocator::MakeUniquePtr(gpu_allocator, workspace_bytes, false, ort_stream, WaitCudaNotificationOnDevice); size_t indices_bytes = 0; CUDNN_RETURN_IF_ERROR(cudnnGetReductionIndicesSize(CudaKernel::GetCudnnHandle(cuda_stream), reduce_desc, input_tensor, output_tensor, &indices_bytes)); - auto indices_cuda = cuda_ep.GetScratchBuffer(indices_bytes, ort_stream, WaitCudaNotificationOnDevice); + auto indices_cuda = indices_bytes == 0 ? nullptr : IAllocator::MakeUniquePtr(gpu_allocator, indices_bytes, false, ort_stream, WaitCudaNotificationOnDevice); if (ReduceTensorIndices == CUDNN_REDUCE_TENSOR_NO_INDICES) { IAllocatorUniquePtr input_data_buffer(nullptr, [](T*) {}); CudaT* input_data = nullptr; if (calculate_sqt) { - input_data_buffer = cuda_ep.GetScratchBuffer(input_count, ort_stream, WaitCudaNotificationOnDevice); + input_data_buffer = IAllocator::MakeUniquePtr(gpu_allocator, input_count, false, ort_stream, WaitCudaNotificationOnDevice); input_data = reinterpret_cast(input_data_buffer.get()); fast_divmod tmp_div; Impl_Mul(stream, @@ -588,7 +588,7 @@ Status ReduceComputeCore(const CUDAExecutionProvider& cuda_ep, const Tensor& inp size_t indices_bytes_max = 0; CUDNN_RETURN_IF_ERROR(cudnnGetReductionIndicesSize(CudaKernel::GetCudnnHandle(cuda_stream), reduce_max_desc, input_tensor, output_tensor, &indices_bytes_max)); - auto indices_cuda_max = cuda_ep.GetScratchBuffer(indices_bytes, ort_stream, WaitCudaNotificationOnDevice); + auto indices_cuda_max = indices_bytes == 0 ? nullptr : IAllocator::MakeUniquePtr(gpu_allocator, indices_bytes, false, ort_stream, WaitCudaNotificationOnDevice); auto* p_output = reinterpret_cast(output.template MutableData()); CUDNN_RETURN_IF_ERROR(cudnnReduceTensor( CudaKernel::GetCudnnHandle(cuda_stream), reduce_max_desc, indices_cuda_max.get(), indices_bytes_max, @@ -599,9 +599,9 @@ Status ReduceComputeCore(const CUDAExecutionProvider& cuda_ep, const Tensor& inp // Exp(X-ReduceMax) const TensorShape output_shape(output_dims); - auto exp_result_buffer = cuda_ep.GetScratchBuffer(input_count, ort_stream, WaitCudaNotificationOnDevice); + auto exp_result_buffer = IAllocator::MakeUniquePtr(gpu_allocator, input_count, false, ort_stream, WaitCudaNotificationOnDevice); auto exp_result = exp_result_buffer.get(); - auto log_sum_result_buffer = cuda_ep.GetScratchBuffer(output_count, ort_stream, WaitCudaNotificationOnDevice); + auto log_sum_result_buffer = output_count == 0 ? nullptr : IAllocator::MakeUniquePtr(gpu_allocator, output_count, false, ort_stream, WaitCudaNotificationOnDevice); auto log_sum_result = log_sum_result_buffer.get(); BinaryElementwisePreparation prepare; ORT_RETURN_IF_ERROR(prepare.BinaryElementwiseBroadcastPrepareHelper(input_shape, output_shape, input_shape)); @@ -669,7 +669,7 @@ Status ReduceComputeCore(const CUDAExecutionProvider& cuda_ep, const Tensor& inp } } else { if (temp_X) { - auto temp_output = cuda_ep.GetScratchBuffer(output_count, ort_stream, WaitCudaNotificationOnDevice); + auto temp_output = output_count == 0 ? nullptr : IAllocator::MakeUniquePtr(gpu_allocator, output_count, false, ort_stream, WaitCudaNotificationOnDevice); CUDNN_RETURN_IF_ERROR(cudnnReduceTensor( CudaKernel::GetCudnnHandle(cuda_stream), reduce_desc, indices_cuda.get(), indices_bytes, workspace_cuda.get(), workspace_bytes, @@ -695,14 +695,14 @@ Status ReduceComputeCore(const CUDAExecutionProvider& cuda_ep, const Tensor& inp CUDA_RETURN_IF_ERROR(cudaMemsetAsync(output.MutableData(), static_cast(0), output_count * sizeof(int64_t), stream)); } else { if (temp_X) { - auto temp_output = cuda_ep.GetScratchBuffer(output_count, ort_stream, WaitCudaNotificationOnDevice); + auto temp_output = output_count == 0 ? nullptr : IAllocator::MakeUniquePtr(gpu_allocator, output_count, false, ort_stream, WaitCudaNotificationOnDevice); CUDNN_RETURN_IF_ERROR(cudnnReduceTensor( CudaKernel::GetCudnnHandle(cuda_stream), reduce_desc, indices_cuda.get(), indices_bytes, workspace_cuda.get(), workspace_bytes, &one, input_tensor, temp_X.get(), &zero, output_tensor, temp_output.get())); } else { - auto temp_output = cuda_ep.GetScratchBuffer(output_count, ort_stream, WaitCudaNotificationOnDevice); + auto temp_output = output_count == 0 ? nullptr : IAllocator::MakeUniquePtr(gpu_allocator, output_count, false, ort_stream, WaitCudaNotificationOnDevice); CUDNN_RETURN_IF_ERROR(cudnnReduceTensor( CudaKernel::GetCudnnHandle(cuda_stream), reduce_desc, indices_cuda.get(), indices_bytes, workspace_cuda.get(), workspace_bytes, @@ -770,7 +770,7 @@ Status ReduceKernel::ComputeImpl(OpKernelContext* ctx, cudnnRe ORT_RETURN_IF_ERROR(PrepareForReduce(X, keepdims_, axes, prepare_reduce_metadata)); Tensor* Y = ctx->Output(0, prepare_reduce_metadata.squeezed_output_dims); const bool fast_reduction = fast_reduction_ && !ctx->GetUseDeterministicCompute(); - return ReduceComputeCore(*cuda_ep_, *X, prepare_reduce_metadata, *Y, cudnn_reduce_op, axes, + return ReduceComputeCore(Info().GetAllocator(OrtMemType::OrtMemTypeDefault), *X, prepare_reduce_metadata, *Y, cudnn_reduce_op, axes, calculate_log_, calculate_sqt_, log_sum_exp_, fast_reduction, ctx->GetComputeStream()); } @@ -865,7 +865,7 @@ SPECIALIZED_REDUCEKERNEL_COMPUTEIMPL(uint8_t) namespace ReductionOps { template -std::unique_ptr ReduceCompute(const CUDAExecutionProvider& cuda_ep, cudnnReduceTensorOp_t cudnn_reduce_op, AllocatorPtr allocator, +std::unique_ptr ReduceCompute(const AllocatorPtr& gpu_allocator, cudnnReduceTensorOp_t cudnn_reduce_op, AllocatorPtr allocator, const Tensor& input, gsl::span axes, bool keep_dims, bool calculate_log, bool calculate_sqt, bool log_sum_exp, bool fast_reduction, Stream* stream, const TensorShape* input_shape_override) { @@ -882,7 +882,7 @@ std::unique_ptr ReduceCompute(const CUDAExecutionProvider& cuda_ep, cudn auto output = Tensor::Create(input.DataType(), prepare_reduce_metadata.squeezed_output_dims, allocator); - status = ReduceComputeCore(cuda_ep, input, prepare_reduce_metadata, *output, cudnn_reduce_op, axes, + status = ReduceComputeCore(gpu_allocator, input, prepare_reduce_metadata, *output, cudnn_reduce_op, axes, calculate_log, calculate_sqt, log_sum_exp, fast_reduction, stream, input_shape_override); if (!status.IsOK()) { @@ -895,21 +895,21 @@ std::unique_ptr ReduceCompute(const CUDAExecutionProvider& cuda_ep, cudn // Explicit template instantiation (needed to be used in einsum_auxiliary_ops.cc) template std::unique_ptr ReduceCompute( - const CUDAExecutionProvider& cuda_ep, cudnnReduceTensorOp_t cudnn_reduce_op, + const AllocatorPtr& gpu_allocator, cudnnReduceTensorOp_t cudnn_reduce_op, AllocatorPtr allocator, const Tensor& input, gsl::span axes, bool keep_dims, bool calculate_log, bool calculate_sqt, bool log_sum_exp, bool fast_reduction, Stream* stream, const TensorShape* input_shape_override); template std::unique_ptr ReduceCompute( - const CUDAExecutionProvider& cuda_ep, cudnnReduceTensorOp_t cudnn_reduce_op, + const AllocatorPtr& gpu_allocator, cudnnReduceTensorOp_t cudnn_reduce_op, AllocatorPtr allocator, const Tensor& input, gsl::span axes, bool keep_dims, bool calculate_log, bool calculate_sqt, bool log_sum_exp, bool fast_reduction, Stream* stream, const TensorShape* input_shape_override); template std::unique_ptr ReduceCompute( - const CUDAExecutionProvider& cuda_ep, cudnnReduceTensorOp_t cudnn_reduce_op, + const AllocatorPtr& gpu_allocator, cudnnReduceTensorOp_t cudnn_reduce_op, AllocatorPtr allocator, const Tensor& input, gsl::span axes, bool keep_dims, bool calculate_log, bool calculate_sqt, bool log_sum_exp, diff --git a/onnxruntime/core/providers/cuda/reduction/reduction_ops.h b/onnxruntime/core/providers/cuda/reduction/reduction_ops.h index b8795cd834404..ee8e13db2eb53 100644 --- a/onnxruntime/core/providers/cuda/reduction/reduction_ops.h +++ b/onnxruntime/core/providers/cuda/reduction/reduction_ops.h @@ -16,7 +16,7 @@ namespace ReductionOps { // `input_shape_override` is the input shape for compute purposes (if provided) template -std::unique_ptr ReduceCompute(const CUDAExecutionProvider& cuda_ep, cudnnReduceTensorOp_t cudnn_reduce_op, AllocatorPtr allocator, +std::unique_ptr ReduceCompute(const AllocatorPtr& gpu_allocator, cudnnReduceTensorOp_t cudnn_reduce_op, AllocatorPtr allocator, const Tensor& input, gsl::span axes, bool keep_dims, bool calculate_log, bool calculate_sqt, bool log_sum_exp, bool fast_reduction, Stream* stream, const TensorShape* input_shape_override = nullptr); @@ -224,7 +224,7 @@ Status PrepareForReduce(const Tensor* X, const TensorShape* input_shape_override = nullptr); template -Status ReduceComputeCore(const CUDAExecutionProvider& cuda_ep, const Tensor& input, PrepareReduceMetadata& prepare_reduce_metadata, +Status ReduceComputeCore(const AllocatorPtr& allocator, const Tensor& input, PrepareReduceMetadata& prepare_reduce_metadata, /*out*/ Tensor& output, cudnnReduceTensorOp_t cudnn_reduce_op, gsl::span axes, bool calculate_log, bool calculate_sqt, bool log_sum_exp, bool fast_reduction, diff --git a/onnxruntime/core/providers/cuda/shared_inc/fast_divmod.h b/onnxruntime/core/providers/cuda/shared_inc/fast_divmod.h index 89a4a0c1d5d85..74a937791ae08 100644 --- a/onnxruntime/core/providers/cuda/shared_inc/fast_divmod.h +++ b/onnxruntime/core/providers/cuda/shared_inc/fast_divmod.h @@ -14,12 +14,38 @@ namespace onnxruntime { namespace cuda { +// DivMod is a helper class for integer division and modulo operation. +// There is a fast version for int type and a slow version for other type. +template +struct DivMod { + DivMod(T d = 1) { + d_ = d == 0 ? 1 : d; + ORT_ENFORCE(d_ >= 1 && d_ <= std::numeric_limits::max()); + } + + __host__ __device__ inline T div(T n) const { + return n / d_; + } + + __host__ __device__ inline T mod(T n) const { + return n % d_; + } + + __host__ __device__ inline void divmod(T n, T& q, T& r) const { + q = div(n); + r = n - q * d_; + } + + T d_; // divisor +}; + // The code below is based on section 4 Unsigned division of paper https://gmplib.org/~tege/divcnst-pldi94.pdf // In current ORT, fast_divmod is used for calculating the position of a element in tensor, // so unsigned integer division from the paper is good enough for ORT. The advantage is that div is very simple, // then GPU compiler can do loop unroll easilly when divmod is called in a loop. -struct fast_divmod { - fast_divmod(int d = 1) { +template <> +struct DivMod { + DivMod(int d = 1) { d_ = d == 0 ? 1 : d; ORT_ENFORCE(d_ >= 1 && d_ <= static_cast(std::numeric_limits::max())); @@ -58,5 +84,7 @@ struct fast_divmod { uint32_t l_; // l_ = ceil(log2(d_)) }; +using fast_divmod = DivMod; // Keep the old name for backward compatibility. + } // namespace cuda } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cuda/shared_inc/fpgeneric.h b/onnxruntime/core/providers/cuda/shared_inc/fpgeneric.h index 8bf429949e5b4..510cc5cfbb7dd 100644 --- a/onnxruntime/core/providers/cuda/shared_inc/fpgeneric.h +++ b/onnxruntime/core/providers/cuda/shared_inc/fpgeneric.h @@ -30,7 +30,7 @@ cublasGemmHelper(cublasHandle_t handle, const float* beta, float* C, int ldc, const cudaDeviceProp& prop) { -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11000 +#if defined(USE_CUDA) // TF32 uses 10 bit mantissa which has sufficient margin of precision for most use cases. It gets 8x throughput than FP32 in A100. // It can be overrided by setting environment variable NVIDIA_TF32_OVERRIDE = 0 to disable TF32 onnxruntime::cuda::CublasMathModeSetter math_mode_setter(prop, handle, CUBLAS_TF32_TENSOR_OP_MATH); @@ -154,7 +154,7 @@ inline cublasStatus_t cublasGemmHelper(cublasHandle_t handle, } } -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11000 +#if defined(USE_CUDA) inline cublasStatus_t cublasGemmHelper(cublasHandle_t handle, cublasOperation_t transa, cublasOperation_t transb, int m, int n, int k, const BFloat16* alpha, const BFloat16* A, int lda, const BFloat16* B, int ldb, const BFloat16* beta, BFloat16* C, int ldc, @@ -185,13 +185,7 @@ inline cublasStatus_t cublasGemmBatchedHelper(cublasHandle_t handle, const float* beta, float* Carray[], int ldc, int batch_count, - const cudaDeviceProp& prop) { -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11000 - onnxruntime::cuda::CublasMathModeSetter math_mode_setter(prop, handle, CUBLAS_TF32_TENSOR_OP_MATH); -#else - ORT_UNUSED_PARAMETER(prop); -#endif - + const cudaDeviceProp&) { return cublasSgemmBatched(handle, transa, transb, @@ -271,7 +265,7 @@ inline cublasStatus_t cublasGemmBatchedHelper(cublasHandle_t handle, } } -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11000 +#if defined(USE_CUDA) inline cublasStatus_t cublasGemmBatchedHelper(cublasHandle_t handle, cublasOperation_t transa, cublasOperation_t transb, int m, int n, int k, const BFloat16* alpha, const BFloat16* Aarray[], int lda, const BFloat16* Barray[], int ldb, const BFloat16* beta, @@ -309,7 +303,7 @@ inline cublasStatus_t cublasGemmStridedBatchedHelper(cublasHandle_t handle, int batch_count, const cudaDeviceProp& prop) { #ifdef ENABLE_TRAINING_OPS -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11000 +#if defined(USE_CUDA) onnxruntime::cuda::CublasMathModeSetter math_mode_setter(prop, handle, CUBLAS_TF32_TENSOR_OP_MATH); #else ORT_UNUSED_PARAMETER(prop); @@ -452,7 +446,7 @@ inline cublasStatus_t cublasGemmStridedBatchedHelper(cublasHandle_t handle, } } -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11000 +#if defined(USE_CUDA) inline cublasStatus_t cublasGemmStridedBatchedHelper(cublasHandle_t handle, cublasOperation_t transa, cublasOperation_t transb, int m, int n, int k, const BFloat16* alpha, const BFloat16* A, int lda, @@ -485,6 +479,7 @@ inline cublasStatus_t cublasTransposeHelper(cudaStream_t, cublasHandle_t handle, return cublasDgeam(handle, transa, transb, m, n, alpha, A, lda, beta, B, ldb, C, ldc); } +bool CanUse_cublasTransposeHelper_MLFloat16(int m, int n); cublasStatus_t cublasTransposeHelper(cudaStream_t, cublasHandle_t, cublasOperation_t, cublasOperation_t, int m, int n, const half*, const half* A, int, const half*, const half*, int, half* C, int); // copy diff --git a/onnxruntime/core/providers/cuda/tensor/cast_op.cc b/onnxruntime/core/providers/cuda/tensor/cast_op.cc index 9a91cd0ab85f9..8e5a68e2a278e 100644 --- a/onnxruntime/core/providers/cuda/tensor/cast_op.cc +++ b/onnxruntime/core/providers/cuda/tensor/cast_op.cc @@ -13,20 +13,25 @@ const std::vector& CastOpTypeConstraints() { // Must be done as a local static for a shared provider, to avoid the prefast warning: // Global initializer calls a non-constexpr function 'onnxruntime::DataTypeImpl::GetTensorType' // In a shared provider, GetTensorType is a function call into Onnxruntime and isn't constexpr - static std::vector types{ - DataTypeImpl::GetTensorType(), - DataTypeImpl::GetTensorType(), - DataTypeImpl::GetTensorType(), - DataTypeImpl::GetTensorType(), - DataTypeImpl::GetTensorType(), - DataTypeImpl::GetTensorType(), - DataTypeImpl::GetTensorType(), - DataTypeImpl::GetTensorType(), - DataTypeImpl::GetTensorType(), - DataTypeImpl::GetTensorType(), - DataTypeImpl::GetTensorType(), - DataTypeImpl::GetTensorType(), - DataTypeImpl::GetTensorType()}; + static std::vector types { + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType(), + DataTypeImpl::GetTensorType() +#if !defined(DISABLE_FLOAT8_TYPES) + , + DataTypeImpl::GetTensorType(), DataTypeImpl::GetTensorType() +#endif + }; return types; } @@ -51,10 +56,20 @@ const std::vector& CastOpTypeConstraints() { .TypeConstraint("T1", DataTypeImpl::GetTensorType()) \ .TypeConstraint("T2", CastOpTypeConstraints()), \ Cast); \ + ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_EX( \ + Cast, \ + kOnnxDomain, \ + 13, 18, \ + T, \ + kCudaExecutionProvider, \ + (*KernelDefBuilder::Create()) \ + .TypeConstraint("T1", DataTypeImpl::GetTensorType()) \ + .TypeConstraint("T2", CastOpTypeConstraints()), \ + Cast); \ ONNX_OPERATOR_TYPED_KERNEL_EX( \ Cast, \ kOnnxDomain, \ - 13, \ + 19, \ T, \ kCudaExecutionProvider, \ (*KernelDefBuilder::Create()) \ @@ -62,15 +77,6 @@ const std::vector& CastOpTypeConstraints() { .TypeConstraint("T2", CastOpTypeConstraints()), \ Cast); -template -Status Cast::ComputeInternal(OpKernelContext* context) const { - typedef typename ToCudaType::MappedType CudaSrcT; - const Tensor* X = context->Input(0); - const TensorShape& shape = X->Shape(); - Tensor* Y = context->Output(0, shape); - const auto* x_data = reinterpret_cast(X->Data()); - size_t count = shape.Size(); - #define CASE(TP_TYPE, DstT) \ case TP_TYPE: \ if (count > 0) { \ @@ -82,6 +88,43 @@ Status Cast::ComputeInternal(OpKernelContext* context) const { } \ break; +#if !defined(DISABLE_FLOAT8_TYPES) + +#define CASE_CHECKNOSAT(TP_TYPE, DstT) \ + case TP_TYPE: \ + if (count > 0) { \ + ORT_ENFORCE(!saturate_, "saturate_=False is only supported for float and float16."); \ + Impl_Cast::MappedType>( \ + Stream(context), \ + x_data, \ + reinterpret_cast::MappedType*>(Y->MutableData()), \ + count); \ + } \ + break; + +#define CASE_SAT(TP_TYPE, DstT) \ + case TP_TYPE: \ + if (count > 0) { \ + Impl_CastSat::MappedType>( \ + Stream(context), \ + x_data, \ + reinterpret_cast::MappedType*>(Y->MutableData()), \ + count, \ + saturate_); \ + } \ + break; + +#endif + +template +Status Cast::ComputeInternal(OpKernelContext* context) const { + typedef typename ToCudaType::MappedType CudaSrcT; + const Tensor* X = context->Input(0); + const TensorShape& shape = X->Shape(); + Tensor* Y = context->Output(0, shape); + const auto* x_data = reinterpret_cast(X->Data()); + size_t count = shape.Size(); + switch (to_) { CASE(TensorProto_DataType_FLOAT16, MLFloat16) CASE(TensorProto_DataType_BFLOAT16, BFloat16) @@ -96,6 +139,11 @@ Status Cast::ComputeInternal(OpKernelContext* context) const { CASE(TensorProto_DataType_UINT32, uint32_t) CASE(TensorProto_DataType_UINT64, uint64_t) CASE(TensorProto_DataType_BOOL, bool) + // By default saturate is true. Case saturate False is only supported for float, float16 for the CUDA provider. +#if !defined(DISABLE_FLOAT8_TYPES) + CASE_CHECKNOSAT(TensorProto_DataType_FLOAT8E4M3FN, Float8E4M3FN) + CASE_CHECKNOSAT(TensorProto_DataType_FLOAT8E5M2, Float8E5M2) +#endif case TensorProto_DataType_STRING: return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Casting to and from strings is not supported yet."); case TensorProto_DataType_UNDEFINED: @@ -106,6 +154,140 @@ Status Cast::ComputeInternal(OpKernelContext* context) const { return Status::OK(); } +#if !defined(DISABLE_FLOAT8_TYPES) + +#define COMPUTE_INTERNAL_FL16_32(FLOAT_TYPE) \ + template <> \ + Status Cast::ComputeInternal(OpKernelContext* context) const { \ + typedef typename ToCudaType::MappedType CudaSrcT; \ + const Tensor* X = context->Input(0); \ + const TensorShape& shape = X->Shape(); \ + Tensor* Y = context->Output(0, shape); \ + const auto* x_data = reinterpret_cast(X->Data()); \ + size_t count = shape.Size(); \ + switch (to_) { \ + CASE(TensorProto_DataType_FLOAT16, MLFloat16) \ + CASE(TensorProto_DataType_BFLOAT16, BFloat16) \ + CASE(TensorProto_DataType_FLOAT, float) \ + CASE(TensorProto_DataType_DOUBLE, double) \ + CASE(TensorProto_DataType_INT8, int8_t) \ + CASE(TensorProto_DataType_INT16, int16_t) \ + CASE(TensorProto_DataType_INT32, int32_t) \ + CASE(TensorProto_DataType_INT64, int64_t) \ + CASE(TensorProto_DataType_UINT8, uint8_t) \ + CASE(TensorProto_DataType_UINT16, uint16_t) \ + CASE(TensorProto_DataType_UINT32, uint32_t) \ + CASE(TensorProto_DataType_UINT64, uint64_t) \ + CASE(TensorProto_DataType_BOOL, bool) \ + CASE_SAT(TensorProto_DataType_FLOAT8E4M3FN, Float8E4M3FN) \ + CASE_SAT(TensorProto_DataType_FLOAT8E5M2, Float8E5M2) \ + case TensorProto_DataType_STRING: \ + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Casting to and from strings is not supported yet."); \ + case TensorProto_DataType_UNDEFINED: \ + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Cast op must have 'to' argument of type DataType"); \ + default: \ + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Unexpected 'to' argument value: ", to_); \ + } \ + return Status::OK(); \ + } + +#else + +#define COMPUTE_INTERNAL_FL16_32(FLOAT_TYPE) \ + template <> \ + Status Cast::ComputeInternal(OpKernelContext* context) const { \ + typedef typename ToCudaType::MappedType CudaSrcT; \ + const Tensor* X = context->Input(0); \ + const TensorShape& shape = X->Shape(); \ + Tensor* Y = context->Output(0, shape); \ + const auto* x_data = reinterpret_cast(X->Data()); \ + size_t count = shape.Size(); \ + switch (to_) { \ + CASE(TensorProto_DataType_FLOAT16, MLFloat16) \ + CASE(TensorProto_DataType_BFLOAT16, BFloat16) \ + CASE(TensorProto_DataType_FLOAT, float) \ + CASE(TensorProto_DataType_DOUBLE, double) \ + CASE(TensorProto_DataType_INT8, int8_t) \ + CASE(TensorProto_DataType_INT16, int16_t) \ + CASE(TensorProto_DataType_INT32, int32_t) \ + CASE(TensorProto_DataType_INT64, int64_t) \ + CASE(TensorProto_DataType_UINT8, uint8_t) \ + CASE(TensorProto_DataType_UINT16, uint16_t) \ + CASE(TensorProto_DataType_UINT32, uint32_t) \ + CASE(TensorProto_DataType_UINT64, uint64_t) \ + CASE(TensorProto_DataType_BOOL, bool) \ + case TensorProto_DataType_STRING: \ + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Casting to and from strings is not supported yet."); \ + case TensorProto_DataType_UNDEFINED: \ + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Cast op must have 'to' argument of type DataType"); \ + default: \ + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Unexpected 'to' argument value: ", to_); \ + } \ + return Status::OK(); \ + } + +#endif + +COMPUTE_INTERNAL_FL16_32(float) +COMPUTE_INTERNAL_FL16_32(MLFloat16) + +// TODO: enable BFLOAT16 in another PR. +/* +#if defined(USE_CUDA) +COMPUTE_INTERNAL_FL16_32(BFloat16) +#endif +*/ + +#if !defined(DISABLE_FLOAT8_TYPES) + +#define COMPUTE_INTERNAL_FL8(FLOAT_TYPE) \ + template <> \ + Status Cast::ComputeInternal(OpKernelContext* context) const { \ + typedef typename ToCudaType::MappedType CudaSrcT; \ + const Tensor* X = context->Input(0); \ + const TensorShape& shape = X->Shape(); \ + Tensor* Y = context->Output(0, shape); \ + const auto* x_data = reinterpret_cast(X->Data()); \ + size_t count = shape.Size(); \ + switch (to_) { \ + case TensorProto_DataType_FLOAT16: \ + if (count > 0) { \ + Impl_Cast( \ + Stream(context), \ + x_data, \ + reinterpret_cast(Y->MutableData()), \ + count); \ + } \ + break; \ + case TensorProto_DataType_BFLOAT16: \ + if (count > 0) { \ + Impl_Cast( \ + Stream(context), \ + x_data, \ + reinterpret_cast(Y->MutableData()), \ + count); \ + } \ + break; \ + case TensorProto_DataType_FLOAT: \ + if (count > 0) { \ + Impl_Cast( \ + Stream(context), \ + x_data, \ + reinterpret_cast(Y->MutableData()), \ + count); \ + } \ + break; \ + default: \ + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Unexpected 'to' argument value: ", to_); \ + } \ + return Status::OK(); \ + } + +COMPUTE_INTERNAL_FL8(Float8E4M3FN) +COMPUTE_INTERNAL_FL8(Float8E5M2) + +#endif + #define SPECIALIZE_IMPL(T) \ REGISTER_KERNEL_TYPED(T) \ template Status Cast::ComputeInternal(OpKernelContext* context) const; @@ -124,5 +306,28 @@ SPECIALIZE_IMPL(uint64_t) SPECIALIZE_IMPL(bool) SPECIALIZE_IMPL(BFloat16) +#define REGISTER_KERNEL_TYPED_19(T) \ + ONNX_OPERATOR_TYPED_KERNEL_EX( \ + Cast, \ + kOnnxDomain, \ + 19, \ + T, \ + kCudaExecutionProvider, \ + (*KernelDefBuilder::Create()) \ + .TypeConstraint("T1", DataTypeImpl::GetTensorType()) \ + .TypeConstraint("T2", CastOpTypeConstraints()), \ + Cast); + +#if !defined(DISABLE_FLOAT8_TYPES) + +#define SPECIALIZE_IMPL_19(T) \ + REGISTER_KERNEL_TYPED_19(T) \ + template Status Cast::ComputeInternal(OpKernelContext* context) const; + +SPECIALIZE_IMPL_19(Float8E4M3FN) +SPECIALIZE_IMPL_19(Float8E5M2) + +#endif + } // namespace cuda } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cuda/tensor/cast_op.cu b/onnxruntime/core/providers/cuda/tensor/cast_op.cu new file mode 100644 index 0000000000000..7542fb55757c6 --- /dev/null +++ b/onnxruntime/core/providers/cuda/tensor/cast_op.cu @@ -0,0 +1,220 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include + +#include "core/providers/cuda/cu_inc/common.cuh" + +#if defined(CUDA_VERSION) && CUDA_VERSION >= 11080 +#include "cuda_fp8.h" +#endif + +namespace onnxruntime { +namespace cuda { + +template +struct CastStd; + +template +struct CastSat; + +template +struct CastNoSat; + +#if !defined(DISABLE_FLOAT8_TYPES) + +#if defined(CUDA_VERSION) && CUDA_VERSION >= 11080 + +template <> +struct CastStd { + __device__ __forceinline__ float operator()(Float8E4M3FN v) const { + return __half2float(__nv_cvt_fp8_to_halfraw(v.val, __NV_E4M3)); + } +}; + +template <> +struct CastStd { + __device__ __forceinline__ half operator()(Float8E4M3FN v) const { + return __nv_cvt_fp8_to_halfraw(v.val, __NV_E4M3); + } +}; + +template <> +struct CastStd { + __device__ __forceinline__ float operator()(Float8E5M2 v) const { + return __half2float(__nv_cvt_fp8_to_halfraw(v.val, __NV_E5M2)); + } +}; + +template <> +struct CastStd { + __device__ __forceinline__ half operator()(Float8E5M2 v) const { + return __nv_cvt_fp8_to_halfraw(v.val, __NV_E5M2); + } +}; + +template <> +struct CastSat { + __device__ __forceinline__ Float8E4M3FN operator()(float v, bool saturate) const { + return Float8E4M3FN(static_cast(__nv_cvt_float_to_fp8(v, saturate ? __NV_SATFINITE : __NV_NOSAT, __NV_E4M3)), Float8E4M3FN::FromBits()); + } +}; + +template <> +struct CastSat { + __device__ __forceinline__ Float8E4M3FN operator()(half v, bool saturate) const { + return Float8E4M3FN(static_cast(__nv_cvt_halfraw_to_fp8(v, saturate ? __NV_SATFINITE : __NV_NOSAT, __NV_E4M3)), Float8E4M3FN::FromBits()); + } +}; + +template <> +struct CastSat { + __device__ __forceinline__ Float8E5M2 operator()(float v, bool saturate) const { + return Float8E5M2(static_cast(__nv_cvt_float_to_fp8(v, saturate ? __NV_SATFINITE : __NV_NOSAT, __NV_E4M3)), Float8E5M2::FromBits()); + } +}; + +template <> +struct CastSat { + __device__ __forceinline__ Float8E5M2 operator()(half v, bool saturate) const { + return Float8E5M2(static_cast(__nv_cvt_halfraw_to_fp8(v, saturate ? __NV_SATFINITE : __NV_NOSAT, __NV_E4M3)), Float8E5M2::FromBits()); + } +}; + +#else + +template <> +struct CastStd { + __device__ __forceinline__ float operator()(Float8E4M3FN v) const { + return v.ToFloat(); + } +}; + +template <> +struct CastStd { + __device__ __forceinline__ half operator()(Float8E4M3FN v) const { + return __float2half(v.ToFloat()); + } +}; + +template <> +struct CastStd { + __device__ __forceinline__ float operator()(Float8E5M2 v) const { + return v.ToFloat(); + } +}; + +template <> +struct CastStd { + __device__ __forceinline__ half operator()(Float8E5M2 v) const { + return __float2half(v.ToFloat()); + } +}; + +template <> +struct CastSat { + __device__ __forceinline__ Float8E4M3FN operator()(float v, bool saturate) const { + return Float8E4M3FN(v, saturate); + } +}; + +template <> +struct CastSat { + __device__ __forceinline__ Float8E4M3FN operator()(half v, bool saturate) const { + return Float8E4M3FN(__half2float(v), saturate); + } +}; + +template <> +struct CastSat { + __device__ __forceinline__ Float8E5M2 operator()(float v, bool saturate) const { + return Float8E5M2(v, saturate); + } +}; + +template <> +struct CastSat { + __device__ __forceinline__ Float8E5M2 operator()(half v, bool saturate) const { + return Float8E5M2(__half2float(v), saturate); + } +}; + +#endif + +#endif + +template +__global__ void CastKernelStd(const InT* input, OutT* output, CUDA_LONG N, CastStd cast) { + CUDA_LONG id = NumElementsPerThread * NumThreadsPerBlock * blockIdx.x + threadIdx.x; + +#pragma unroll + for (int i = 0; i < NumElementsPerThread; i++) { + if (id < N) { + output[id] = cast(input[id]); + id += NumThreadsPerBlock; + } + } +} + +template +Status CudaCastStd(cudaStream_t stream, const InT* input, OutT* output, size_t num_of_element) { + if (num_of_element <= 0) + return Status::OK(); + + int blocksPerGrid = static_cast(CeilDiv(num_of_element, GridDim::maxThreadsPerBlock * GridDim::maxElementsPerThread)); + CastKernelStd<<>>( + input, + output, + static_cast(num_of_element), + CastStd() + ); + return Status::OK(); +} + +#if !defined(DISABLE_FLOAT8_TYPES) + +template +__global__ void CastKernelSat(const InT* input, OutT* output, CUDA_LONG N, CastSat cast, bool saturate) { + CUDA_LONG id = NumElementsPerThread * NumThreadsPerBlock * blockIdx.x + threadIdx.x; + +#pragma unroll + for (int i = 0; i < NumElementsPerThread; i++) { + if (id < N) { + output[id] = cast(input[id], saturate); + id += NumThreadsPerBlock; + } + } +} + +template +Status CudaCastSat(cudaStream_t stream, const InT* input, OutT* output, size_t num_of_element, bool saturate) { + if (num_of_element <= 0) + return Status::OK(); + + int blocksPerGrid = static_cast(CeilDiv(num_of_element, GridDim::maxThreadsPerBlock * GridDim::maxElementsPerThread)); + CastKernelSat<<>>( + input, + output, + static_cast(num_of_element), + CastSat(), + saturate + ); + return Status::OK(); +} + +template Status CudaCastStd(cudaStream_t stream, const Float8E4M3FN* input, float* output, size_t num_of_element); +template Status CudaCastStd(cudaStream_t stream, const Float8E4M3FN* input, half* output, size_t num_of_element); + +template Status CudaCastSat(cudaStream_t stream, const float* input, Float8E4M3FN* output, size_t num_of_element, bool saturate); +template Status CudaCastSat(cudaStream_t stream, const half* input, Float8E4M3FN* output, size_t num_of_element, bool saturate); + +template Status CudaCastStd(cudaStream_t stream, const Float8E5M2* input, float* output, size_t num_of_element); +template Status CudaCastStd(cudaStream_t stream, const Float8E5M2* input, half* output, size_t num_of_element); + +template Status CudaCastSat(cudaStream_t stream, const float* input, Float8E5M2* output, size_t num_of_element, bool saturate); +template Status CudaCastSat(cudaStream_t stream, const half* input, Float8E5M2* output, size_t num_of_element, bool saturate); + +#endif + +} // namespace cuda +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/cuda/tensor/cast_op.h b/onnxruntime/core/providers/cuda/tensor/cast_op.h index 1d2d723da8537..f4304922b8f37 100644 --- a/onnxruntime/core/providers/cuda/tensor/cast_op.h +++ b/onnxruntime/core/providers/cuda/tensor/cast_op.h @@ -17,12 +17,23 @@ class Cast final : public CudaKernel { Status status = info.GetAttr("to", &to); ORT_ENFORCE(status.IsOK(), "Attribute to is not set."); to_ = gsl::narrow_cast(to); + + int64_t saturate = info.GetAttrOrDefault("saturate", int64_t{1}); + if (saturate == 0 && + to != ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_FLOAT8E4M3FN && + to != ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_FLOAT8E4M3FNUZ && + to != ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_FLOAT8E5M2 && + to != ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_FLOAT8E5M2FNUZ) { + ORT_THROW("Attribute saturate is only used for cast to float 8 types."); + } + saturate_ = saturate == 1; } Status ComputeInternal(OpKernelContext* context) const override; private: ONNX_NAMESPACE::TensorProto_DataType to_; + bool saturate_; }; } // namespace cuda diff --git a/onnxruntime/core/providers/cuda/tensor/gather_elements_impl.cu b/onnxruntime/core/providers/cuda/tensor/gather_elements_impl.cu index 914da00f0d15e..10c8625b39ef8 100644 --- a/onnxruntime/core/providers/cuda/tensor/gather_elements_impl.cu +++ b/onnxruntime/core/providers/cuda/tensor/gather_elements_impl.cu @@ -276,8 +276,12 @@ struct FuncAtomicAdd { }; template -Status GatherElementsGradImpl(cudaStream_t stream, const TIndex* indices_data, const T* updates_data, T* output_data, - const GatherScatterElementsArgs& args) { +Status GatherElementsGradNonDeterministicImpl(cudaStream_t stream, const TIndex* indices_data, const T* updates_data, + T* output_data, + const GatherScatterElementsArgs& args) { + // Be noted: usage of AtomicAdd is not deterministic if there are duplicated indices to update. + // That's the reason we name this function as non-deterministic. + // Give output_data as the input_data parameter by intention, // to skip input_data copy, which is not applicable for GatherElementsGrad. // output_data's numel is same as input_data's numel. @@ -285,10 +289,10 @@ Status GatherElementsGradImpl(cudaStream_t stream, const TIndex* indices_data, c FuncAtomicAdd(static_cast(args.input_size))); } -#define GATHER_ELEMENTS_GRAD_SPECIALIZED_TINDEX_IMPL(T, TIndex) \ - template Status GatherElementsGradImpl(cudaStream_t stream, const TIndex* indices_data, \ - const T* updates_data, T* output_data, \ - const GatherScatterElementsArgs& args); +#define GATHER_ELEMENTS_GRAD_SPECIALIZED_TINDEX_IMPL(T, TIndex) \ + template Status GatherElementsGradNonDeterministicImpl(cudaStream_t stream, const TIndex* indices_data, \ + const T* updates_data, T* output_data, \ + const GatherScatterElementsArgs& args); #define GATHER_ELEMENTS_GRAD_SPECIALIZED_SCATTER_ADD_IMPL(T) \ GATHER_ELEMENTS_GRAD_SPECIALIZED_TINDEX_IMPL(T, int32_t) \ diff --git a/onnxruntime/core/providers/cuda/tensor/identity_op.cc b/onnxruntime/core/providers/cuda/tensor/identity_op.cc index 6d6ebb89e1339..18c02c41777a3 100644 --- a/onnxruntime/core/providers/cuda/tensor/identity_op.cc +++ b/onnxruntime/core/providers/cuda/tensor/identity_op.cc @@ -51,14 +51,24 @@ ONNX_OPERATOR_VERSIONED_KERNEL_EX( .Alias(0, 0), IdentityOp); -ONNX_OPERATOR_KERNEL_EX( +ONNX_OPERATOR_VERSIONED_KERNEL_EX( Identity, kOnnxDomain, - 14, + 14, 18, kCudaExecutionProvider, (*KernelDefBuilder::Create()) .TypeConstraint("V", DataTypeImpl::AllFixedSizeTensorAndSequenceTensorTypes()) .Alias(0, 0), IdentityOp); + +ONNX_OPERATOR_KERNEL_EX( + Identity, + kOnnxDomain, + 19, + kCudaExecutionProvider, + (*KernelDefBuilder::Create()) + .TypeConstraint("V", DataTypeImpl::AllFixedSizeTensorAndSequenceTensorTypesIRv9()) + .Alias(0, 0), + IdentityOp); } // namespace cuda } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cuda/tensor/quantize_linear.cc b/onnxruntime/core/providers/cuda/tensor/quantize_linear.cc index d811f4ee98800..d4b6d1bc4966a 100644 --- a/onnxruntime/core/providers/cuda/tensor/quantize_linear.cc +++ b/onnxruntime/core/providers/cuda/tensor/quantize_linear.cc @@ -7,6 +7,36 @@ namespace onnxruntime { namespace cuda { +template +typename std::enable_if, T>::value, Status>::type +CudaQuantizeLinear(cudaStream_t stream, const U* input, T* output, const U* scale, const T* zero_point, size_t num_of_element, bool /*saturate*/) { + return CudaQuantizeLinearStd(stream, input, output, scale, zero_point, num_of_element); +} + +#if !defined(DISABLE_FLOAT8_TYPES) + +template +typename std::enable_if, T>::value, Status>::type +CudaQuantizeLinear(cudaStream_t stream, const U* input, T* output, const U* scale, const T* zero_point, size_t num_of_element, bool saturate) { + return CudaQuantizeLinearSat(stream, input, output, scale, zero_point, num_of_element, saturate); +} + +template +typename std::enable_if, T>::value, Status>::type +CudaQuantizeLinearAxis(cudaStream_t stream, const U* input, T* output, const U* scale, const T* zero_point, size_t num_of_element, + size_t batch_size, size_t n_scales, bool saturate) { + return CudaQuantizeLinearAxisSat(stream, input, output, scale, zero_point, num_of_element, batch_size, n_scales, saturate); +} + +#endif + +template +typename std::enable_if, T>::value, Status>::type +CudaQuantizeLinearAxis(cudaStream_t stream, const U* input, T* output, const U* scale, const T* zero_point, size_t num_of_element, + size_t batch_size, size_t n_scales, bool /*saturate*/) { + return CudaQuantizeLinearAxisStd(stream, input, output, scale, zero_point, num_of_element, batch_size, n_scales); +} + template Status QuantizeLinear::ComputeInternal(OpKernelContext* ctx) const { typedef typename ToCudaType::MappedType CudaU; @@ -22,19 +52,65 @@ Status QuantizeLinear::ComputeInternal(OpKernelContext* ctx) const { const CudaU* input = reinterpret_cast(x.Data()); T* output = y.MutableData(); - // TO DO: support per-channel - ORT_ENFORCE(IsScalarOr1ElementVector(&y_scale), "y_scale must be a scalar or 1D tensor of size 1."); - ORT_ENFORCE(y_zero_point == nullptr || IsScalarOr1ElementVector(y_zero_point), "y_zero_point must be a scalar or 1D tensor of size 1."); + if (IsScalarOr1ElementVector(&y_scale)) { + ORT_ENFORCE(y_zero_point == nullptr || IsScalarOr1ElementVector(y_zero_point), + "y_zero_point must be a scalar or 1D tensor of size 1."); + + const T* zero_point = y_zero_point != nullptr ? y_zero_point->Data() : nullptr; + const CudaU* scale = reinterpret_cast(y_scale.Data()); + const auto num_of_elements = x_shape.Size(); - const T* zero_point = y_zero_point != nullptr ? y_zero_point->Data() : nullptr; - const CudaU* scale = reinterpret_cast(y_scale.Data()); - const auto num_of_elements = x_shape.Size(); + ORT_RETURN_IF_ERROR(CudaQuantizeLinear(Stream(ctx), input, output, scale, zero_point, num_of_elements, saturate_)); + return Status::OK(); + } else { + ORT_ENFORCE(y_scale.Shape().NumDimensions() == 1); + ORT_ENFORCE(y_zero_point == nullptr || (y_scale.Shape().Size() == y_zero_point->Shape().Size() && + y_zero_point->Shape().NumDimensions() == 1), + "scale and zero_point must have the same shape."); + ORT_ENFORCE(x_shape.NumDimensions() > 1); + int64_t axis = HandleNegativeAxis(axis_, x_shape.NumDimensions()); + ORT_ENFORCE(y_scale.Shape().Size() == x_shape[axis], "scale must have ", x_shape[axis], " elements (axis=", axis, ")."); - ORT_RETURN_IF_ERROR(CudaQuantizeLinear(Stream(ctx), input, output, scale, zero_point, num_of_elements)); + const T* zero_point = y_zero_point != nullptr ? y_zero_point->Data() : nullptr; + const CudaU* scale = reinterpret_cast(y_scale.Data()); + const auto num_of_elements = x_shape.Size(); - return Status::OK(); + ORT_RETURN_IF_ERROR(CudaQuantizeLinearAxis(Stream(ctx), input, output, scale, zero_point, num_of_elements, + x_shape.SizeToDimension(axis), y_scale.Shape().Size(), saturate_)); + return Status::OK(); + } } +template +typename std::enable_if, T>::value, Status>::type +CudaDequantizeLinear(cudaStream_t stream, const T* input, U* output, const U* scale, const T* zero_point, size_t num_of_element) { + return CudaDequantizeLinearStd(stream, input, output, scale, zero_point, num_of_element); +} + +#if !defined(DISABLE_FLOAT8_TYPES) +template +typename std::enable_if, T>::value, Status>::type +CudaDequantizeLinear(cudaStream_t stream, const T* input, U* output, const U* scale, const T* zero_point, size_t num_of_element) { + return CudaDequantizeLinearSat(stream, input, output, scale, zero_point, num_of_element); +} +#endif + +template +typename std::enable_if, T>::value, Status>::type +CudaDequantizeLinearAxis(cudaStream_t stream, const T* input, U* output, const U* scale, const T* zero_point, size_t num_of_element, + size_t batch_size, size_t n_scales) { + return CudaDequantizeLinearAxisStd(stream, input, output, scale, zero_point, num_of_element, batch_size, n_scales); +} + +#if !defined(DISABLE_FLOAT8_TYPES) +template +typename std::enable_if, T>::value, Status>::type +CudaDequantizeLinearAxis(cudaStream_t stream, const T* input, U* output, const U* scale, const T* zero_point, size_t num_of_element, + size_t batch_size, size_t n_scales) { + return CudaDequantizeLinearAxisSat(stream, input, output, scale, zero_point, num_of_element, batch_size, n_scales); +} +#endif + template Status DequantizeLinear::ComputeInternal(OpKernelContext* ctx) const { typedef typename ToCudaType::MappedType CudaU; @@ -50,24 +126,39 @@ Status DequantizeLinear::ComputeInternal(OpKernelContext* ctx) const { const T* input = x.Data(); CudaU* output = reinterpret_cast(y.MutableData()); - ORT_ENFORCE(IsScalarOr1ElementVector(&y_scale), "y_scale must be a scalar or 1D tensor of size 1."); - ORT_ENFORCE(y_zero_point == nullptr || IsScalarOr1ElementVector(y_zero_point), "y_zero_point must be a scalar or 1D tensor of size 1."); + if (IsScalarOr1ElementVector(&y_scale)) { + ORT_ENFORCE(y_zero_point == nullptr || IsScalarOr1ElementVector(y_zero_point), "y_zero_point must be a scalar or 1D tensor of size 1."); + + const T* zero_point = y_zero_point != nullptr ? y_zero_point->Data() : nullptr; + const CudaU* scale = reinterpret_cast(y_scale.Data()); + const auto num_of_elements = x_shape.Size(); - const T* zero_point = y_zero_point != nullptr ? y_zero_point->Data() : nullptr; - const CudaU* scale = reinterpret_cast(y_scale.Data()); - const auto num_of_elements = x_shape.Size(); + ORT_RETURN_IF_ERROR(CudaDequantizeLinear(Stream(ctx), input, output, scale, zero_point, num_of_elements)); - ORT_RETURN_IF_ERROR(CudaDequantizeLinear(Stream(ctx), input, output, scale, zero_point, num_of_elements)); + return Status::OK(); + } else { + ORT_ENFORCE(y_scale.Shape().NumDimensions() == 1); + ORT_ENFORCE(y_zero_point == nullptr || (y_scale.Shape().Size() == y_zero_point->Shape().Size() && y_zero_point->Shape().NumDimensions() == 1), "scale and zero_point must have the same shape."); + ORT_ENFORCE(x_shape.NumDimensions() > 1); + int64_t axis = HandleNegativeAxis(axis_, x_shape.NumDimensions()); + ORT_ENFORCE(y_scale.Shape().Size() == x_shape[axis], "scale must have ", x_shape[axis], " elements (axis=", axis, ")."); - return Status::OK(); + const T* zero_point = y_zero_point != nullptr ? y_zero_point->Data() : nullptr; + const CudaU* scale = reinterpret_cast(y_scale.Data()); + const auto num_of_elements = x_shape.Size(); + + ORT_RETURN_IF_ERROR(CudaDequantizeLinearAxis(Stream(ctx), input, output, scale, zero_point, num_of_elements, + x_shape.SizeToDimension(axis), y_scale.Shape().Size())); + return Status::OK(); + } } // register QuantizeLinear kernels -#define REGISTER_Q_KERNEL_TYPED(T) \ - ONNX_OPERATOR_TYPED_KERNEL_EX( \ +#define REGISTER_Q_KERNEL_TYPED_10_12(T) \ + ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_EX( \ QuantizeLinear, \ kOnnxDomain, \ - 10, \ + 10, 12, \ T, \ kCudaExecutionProvider, \ (*KernelDefBuilder::Create()) \ @@ -75,23 +166,108 @@ Status DequantizeLinear::ComputeInternal(OpKernelContext* ctx) const { .TypeConstraint("T2", DataTypeImpl::GetTensorType()), \ QuantizeLinear); -REGISTER_Q_KERNEL_TYPED(int8_t) -REGISTER_Q_KERNEL_TYPED(uint8_t) +#define REGISTER_Q_KERNEL_TYPED_13_18(T) \ + ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_EX( \ + QuantizeLinear, \ + kOnnxDomain, \ + 13, 18, \ + T, \ + kCudaExecutionProvider, \ + (*KernelDefBuilder::Create()) \ + .TypeConstraint("T1", DataTypeImpl::GetTensorType()) \ + .TypeConstraint("T2", DataTypeImpl::GetTensorType()), \ + QuantizeLinear); + +REGISTER_Q_KERNEL_TYPED_10_12(int8_t) +REGISTER_Q_KERNEL_TYPED_10_12(uint8_t) +REGISTER_Q_KERNEL_TYPED_13_18(int8_t) +REGISTER_Q_KERNEL_TYPED_13_18(uint8_t) + +#define REGISTER_Q_KERNEL_TYPED_19(T) \ + ONNX_OPERATOR_TWO_TYPED_KERNEL_EX( \ + QuantizeLinear, \ + kOnnxDomain, \ + 19, \ + T, float, \ + kCudaExecutionProvider, \ + (*KernelDefBuilder::Create()) \ + .TypeConstraint("T1", DataTypeImpl::GetTensorType()) \ + .TypeConstraint("T2", DataTypeImpl::GetTensorType()), \ + QuantizeLinear); \ + ONNX_OPERATOR_TWO_TYPED_KERNEL_EX( \ + QuantizeLinear, \ + kOnnxDomain, \ + 19, \ + T, MLFloat16, \ + kCudaExecutionProvider, \ + (*KernelDefBuilder::Create()) \ + .TypeConstraint("T1", DataTypeImpl::GetTensorType()) \ + .TypeConstraint("T2", DataTypeImpl::GetTensorType()), \ + QuantizeLinear); + +REGISTER_Q_KERNEL_TYPED_19(int8_t) +REGISTER_Q_KERNEL_TYPED_19(uint8_t) +#if !defined(DISABLE_FLOAT8_TYPES) +REGISTER_Q_KERNEL_TYPED_19(Float8E4M3FN) +REGISTER_Q_KERNEL_TYPED_19(Float8E5M2) +#endif // register DequantizeLinear kernels -#define REGISTER_DQ_KERNEL_TYPED(T) \ - ONNX_OPERATOR_TYPED_KERNEL_EX( \ +#define REGISTER_DQ_KERNEL_TYPED_10_12(T) \ + ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_EX( \ + DequantizeLinear, \ + kOnnxDomain, \ + 10, 12, \ + T, \ + kCudaExecutionProvider, \ + (*KernelDefBuilder::Create()) \ + .TypeConstraint("T", DataTypeImpl::GetTensorType()), \ + DequantizeLinear); + +#define REGISTER_DQ_KERNEL_TYPED_13_18(T) \ + ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_EX( \ DequantizeLinear, \ kOnnxDomain, \ - 10, \ + 13, 18, \ T, \ kCudaExecutionProvider, \ (*KernelDefBuilder::Create()) \ .TypeConstraint("T", DataTypeImpl::GetTensorType()), \ DequantizeLinear); -REGISTER_DQ_KERNEL_TYPED(int8_t) -REGISTER_DQ_KERNEL_TYPED(uint8_t) +REGISTER_DQ_KERNEL_TYPED_10_12(int8_t) +REGISTER_DQ_KERNEL_TYPED_10_12(uint8_t) +REGISTER_DQ_KERNEL_TYPED_13_18(int8_t) +REGISTER_DQ_KERNEL_TYPED_13_18(uint8_t) + +#define REGISTER_DQ_KERNEL_TYPED_19(T) \ + ONNX_OPERATOR_TWO_TYPED_KERNEL_EX( \ + DequantizeLinear, \ + kOnnxDomain, \ + 19, \ + T, float, \ + kCudaExecutionProvider, \ + (*KernelDefBuilder::Create()) \ + .TypeConstraint("T1", DataTypeImpl::GetTensorType()) \ + .TypeConstraint("T2", DataTypeImpl::GetTensorType()), \ + DequantizeLinear); \ + ONNX_OPERATOR_TWO_TYPED_KERNEL_EX( \ + DequantizeLinear, \ + kOnnxDomain, \ + 19, \ + T, MLFloat16, \ + kCudaExecutionProvider, \ + (*KernelDefBuilder::Create()) \ + .TypeConstraint("T1", DataTypeImpl::GetTensorType()) \ + .TypeConstraint("T2", DataTypeImpl::GetTensorType()), \ + DequantizeLinear); + +REGISTER_DQ_KERNEL_TYPED_19(int8_t) +REGISTER_DQ_KERNEL_TYPED_19(uint8_t) +#if !defined(DISABLE_FLOAT8_TYPES) +REGISTER_DQ_KERNEL_TYPED_19(Float8E4M3FN) +REGISTER_DQ_KERNEL_TYPED_19(Float8E5M2) +#endif // specialize QuantizeLinear::ComputeInternal and DequantizeLinear::ComputeInternal #define SPECIALIZED_QDQ_COMPUTE(T, U) \ @@ -103,5 +279,12 @@ SPECIALIZED_QDQ_COMPUTE(uint8_t, float) SPECIALIZED_QDQ_COMPUTE(int8_t, MLFloat16) SPECIALIZED_QDQ_COMPUTE(uint8_t, MLFloat16) +#if !defined(DISABLE_FLOAT8_TYPES) +SPECIALIZED_QDQ_COMPUTE(Float8E4M3FN, float) +SPECIALIZED_QDQ_COMPUTE(Float8E4M3FN, MLFloat16) +SPECIALIZED_QDQ_COMPUTE(Float8E5M2, float) +SPECIALIZED_QDQ_COMPUTE(Float8E5M2, MLFloat16) +#endif + } // namespace cuda } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cuda/tensor/quantize_linear.cu b/onnxruntime/core/providers/cuda/tensor/quantize_linear.cu index ff300e4bdaf95..ad2a44793fe26 100644 --- a/onnxruntime/core/providers/cuda/tensor/quantize_linear.cu +++ b/onnxruntime/core/providers/cuda/tensor/quantize_linear.cu @@ -7,64 +7,272 @@ #include "core/providers/cuda/cu_inc/common.cuh" +#if defined(CUDA_VERSION) && CUDA_VERSION >= 11080 +#include "cuda_fp8.h" +#endif + namespace onnxruntime { namespace cuda { -template -struct Round; +template +struct RoundStd; + +template +struct RoundSat; + +template <> +struct RoundStd { + __device__ __forceinline__ int8_t operator()(float v, float scale, int8_t zero_point) const { + int value = __float2int_rn(v / scale) + zero_point; + return static_cast(max(std::numeric_limits::min(), min(std::numeric_limits::max(), value))); + } +}; + +template <> +struct RoundStd { + __device__ __forceinline__ uint8_t operator()(float v, float scale, uint8_t zero_point) const { + int value = __float2int_rn(v / scale) + zero_point; + return static_cast(max(std::numeric_limits::min(), min(std::numeric_limits::max(), value))); + } +}; + +#if !defined(DISABLE_FLOAT8_TYPES) + +#if defined(CUDA_VERSION) && CUDA_VERSION >= 11080 + +// Conversion from float 8 to float or float16 does not need zero_point argument as defined by onnx standard. + +template <> +struct RoundSat { + __device__ __forceinline__ Float8E4M3FN operator()(float v, float scale, Float8E4M3FN /* zero_point */, bool saturate) const { + return Float8E4M3FN(static_cast(__nv_cvt_float_to_fp8(v / scale, saturate ? __NV_SATFINITE : __NV_NOSAT, __NV_E4M3)), Float8E4M3FN::FromBits()); + } +}; + +template <> +struct RoundSat { + __device__ __forceinline__ Float8E4M3FN operator()(half v, half scale, Float8E4M3FN /* zero_point */, bool saturate) const { + return Float8E4M3FN(static_cast(__nv_cvt_halfraw_to_fp8(v / scale, saturate ? __NV_SATFINITE : __NV_NOSAT, __NV_E4M3)), Float8E4M3FN::FromBits()); + } +}; + +template <> +struct RoundSat { + __device__ __forceinline__ Float8E5M2 operator()(float v, float scale, Float8E5M2 /* zero_point */, bool saturate) const { + return Float8E5M2(static_cast(__nv_cvt_float_to_fp8(v / scale, saturate ? __NV_SATFINITE : __NV_NOSAT, __NV_E5M2)), Float8E5M2::FromBits()); + } +}; + +template <> +struct RoundSat { + __device__ __forceinline__ Float8E5M2 operator()(half v, half scale, Float8E5M2 /* zero_point */, bool saturate) const { + return Float8E5M2(static_cast(__nv_cvt_halfraw_to_fp8(v / scale, saturate ? __NV_SATFINITE : __NV_NOSAT, __NV_E5M2)), Float8E5M2::FromBits()); + } +}; + +#else + +// Conversion from float 8 to float or float16 does not need zero_point argument as defined by onnx standard. template <> -struct Round { - __device__ __forceinline__ int operator()(float v) const { - return __float2int_rn(v); +struct RoundSat { + __device__ __forceinline__ Float8E4M3FN operator()(float v, float scale, Float8E4M3FN /* zero_point */, bool saturate) const { + return Float8E4M3FN(v / scale, saturate); } }; template <> -struct Round { - __device__ __forceinline__ int operator()(half v) const { - return __half2int_rn(v); +struct RoundSat { + __device__ __forceinline__ Float8E4M3FN operator()(half v, half scale, Float8E4M3FN /* zero_point */, bool saturate) const { + return Float8E4M3FN(__half2float(v / scale), true); } }; +template <> +struct RoundSat { + __device__ __forceinline__ Float8E5M2 operator()(float v, float scale, Float8E5M2 /* zero_point */, bool saturate) const { + return Float8E5M2(v / scale, saturate); + } +}; + +template <> +struct RoundSat { + __device__ __forceinline__ Float8E5M2 operator()(half v, half scale, Float8E5M2 /* zero_point */, bool saturate) const { + return Float8E5M2(__half2float(v / scale), saturate); + } +}; + +#endif + +#endif + +template <> +struct RoundStd { + __device__ __forceinline__ int8_t operator()(half v, half scale, int8_t zero_point) const { + int value = __half2int_rn(v / scale) + zero_point; + return static_cast(max(std::numeric_limits::min(), min(std::numeric_limits::max(), value))); + } +}; + +template <> +struct RoundStd { + __device__ __forceinline__ int8_t operator()(half v, half scale, uint8_t zero_point) const { + int value = __half2int_rn(v / scale) + zero_point; + return static_cast(max(std::numeric_limits::min(), min(std::numeric_limits::max(), value))); + } +}; + +template +__global__ void QuantizeLinearKernelStd(const InT* input, OutT* output, const InT* scale_ptr, const OutT* zero_point_ptr, CUDA_LONG N, RoundStd round) { + CUDA_LONG id = NumElementsPerThread * NumThreadsPerBlock * blockIdx.x + threadIdx.x; + + InT scale = *scale_ptr; + OutT zero_point = zero_point_ptr != nullptr ? *zero_point_ptr : static_cast(0); +#pragma unroll + for (int i = 0; i < NumElementsPerThread; i++) { + if (id < N) { + output[id] = round(input[id], scale, zero_point); + id += NumThreadsPerBlock; + } + } +} + +template +__global__ void QuantizeLinearKernelAxisStd(const InT* input, OutT* output, const InT* scale_ptr, const OutT* zero_point_ptr, CUDA_LONG N, size_t batch_size, size_t n_scales, RoundStd round) { + CUDA_LONG id = NumElementsPerThread * NumThreadsPerBlock * blockIdx.x + threadIdx.x; + // The scale needs to change every n_same_scale. + CUDA_LONG n_same_scale = N / (batch_size * n_scales); + int scale_id; + +#pragma unroll + for (int i = 0; i < NumElementsPerThread; i++) { + if (id < N) { + scale_id = (id / n_same_scale) % n_scales; + output[id] = round(input[id], scale_ptr[scale_id], zero_point_ptr == nullptr ? static_cast(0) : zero_point_ptr[scale_id]); + id += NumThreadsPerBlock; + } + } +} + +#if !defined(DISABLE_FLOAT8_TYPES) + template -__global__ void QuantizeLinearKernel(const InT* input, OutT* output, const InT* scale_ptr, const OutT* zero_point_ptr, CUDA_LONG N, Round round) { +__global__ void QuantizeLinearKernelSat(const InT* input, OutT* output, const InT* scale_ptr, const OutT* zero_point_ptr, CUDA_LONG N, RoundSat round, bool saturate) { CUDA_LONG id = NumElementsPerThread * NumThreadsPerBlock * blockIdx.x + threadIdx.x; InT scale = *scale_ptr; - OutT zero_point = zero_point_ptr != nullptr ? *zero_point_ptr : 0; + OutT zero_point = zero_point_ptr != nullptr ? *zero_point_ptr : OutT(0, true); +#pragma unroll + for (int i = 0; i < NumElementsPerThread; i++) { + if (id < N) { + output[id] = round(input[id], scale, zero_point, saturate); + id += NumThreadsPerBlock; + } + } +} + +template +__global__ void QuantizeLinearKernelAxisSat(const InT* input, OutT* output, const InT* scale_ptr, const OutT* zero_point_ptr, CUDA_LONG N, + size_t batch_size, size_t n_scales, RoundSat round, bool saturate) { + CUDA_LONG id = NumElementsPerThread * NumThreadsPerBlock * blockIdx.x + threadIdx.x; + // The scale needs to change every n_same_scale. + CUDA_LONG n_same_scale = N / (batch_size * n_scales); + int scale_id; + #pragma unroll for (int i = 0; i < NumElementsPerThread; i++) { if (id < N) { - int value = round(input[id] / scale) + zero_point; - output[id] = static_cast(max(std::numeric_limits::min(), min(std::numeric_limits::max(), value))); + scale_id = (id / n_same_scale) % n_scales; + output[id] = round(input[id], scale_ptr[scale_id], zero_point_ptr == nullptr ? OutT(0, true) : zero_point_ptr[scale_id], saturate); id += NumThreadsPerBlock; } } } +#endif + template -Status CudaQuantizeLinear(cudaStream_t stream, const InT* input, OutT* output, const InT* scale, const OutT* zero_point, size_t num_of_element) { +Status CudaQuantizeLinearStd(cudaStream_t stream, const InT* input, OutT* output, const InT* scale, const OutT* zero_point, size_t num_of_element) { if (num_of_element <= 0) return Status::OK(); int blocksPerGrid = static_cast(CeilDiv(num_of_element, GridDim::maxThreadsPerBlock * GridDim::maxElementsPerThread)); - QuantizeLinearKernel<<>>( + QuantizeLinearKernelStd<<>>( input, output, scale, zero_point, static_cast(num_of_element), - Round()); + RoundStd()); return Status::OK(); } +template +Status CudaQuantizeLinearAxisStd(cudaStream_t stream, const InT* input, OutT* output, const InT* scale, const OutT* zero_point, size_t num_of_element, + size_t batch_size, size_t n_scales) { + if (num_of_element <= 0) + return Status::OK(); + + int blocksPerGrid = static_cast(CeilDiv(num_of_element, GridDim::maxThreadsPerBlock * GridDim::maxElementsPerThread)); + QuantizeLinearKernelAxisStd<<>>( + input, + output, + scale, + zero_point, + static_cast(num_of_element), + batch_size, + n_scales, + RoundStd()); + return Status::OK(); +} + +#if !defined(DISABLE_FLOAT8_TYPES) + +template +Status CudaQuantizeLinearSat(cudaStream_t stream, const InT* input, OutT* output, const InT* scale, const OutT* zero_point, size_t num_of_element, bool saturate) { + if (num_of_element <= 0) + return Status::OK(); + + int blocksPerGrid = static_cast(CeilDiv(num_of_element, GridDim::maxThreadsPerBlock * GridDim::maxElementsPerThread)); + QuantizeLinearKernelSat<<>>( + input, + output, + scale, + zero_point, + static_cast(num_of_element), + RoundSat(), + saturate); + return Status::OK(); +} + +template +Status CudaQuantizeLinearAxisSat(cudaStream_t stream, const InT* input, OutT* output, const InT* scale, const OutT* zero_point, size_t num_of_element, + size_t batch_size, size_t n_scales, bool saturate) { + if (num_of_element <= 0) + return Status::OK(); + + int blocksPerGrid = static_cast(CeilDiv(num_of_element, GridDim::maxThreadsPerBlock * GridDim::maxElementsPerThread)); + QuantizeLinearKernelAxisSat<<>>( + input, + output, + scale, + zero_point, + static_cast(num_of_element), + batch_size, + n_scales, + RoundSat(), + saturate); + return Status::OK(); +} + +#endif + template -__global__ void DequantizeLinearKernel(const InT* input, OutT* output, const OutT* scale_ptr, const InT* zero_point_ptr, CUDA_LONG N) { +__global__ void DequantizeLinearKernelStd(const InT* input, OutT* output, const OutT* scale_ptr, const InT* zero_point_ptr, CUDA_LONG N) { CUDA_LONG id = NumElementsPerThread * NumThreadsPerBlock * blockIdx.x + threadIdx.x; OutT scale = *scale_ptr; - InT zero_point = zero_point_ptr != nullptr ? *zero_point_ptr : 0; + InT zero_point = zero_point_ptr != nullptr ? *zero_point_ptr : static_cast(0); #pragma unroll for (int i = 0; i < NumElementsPerThread; i++) { if (id < N) { @@ -74,13 +282,173 @@ __global__ void DequantizeLinearKernel(const InT* input, OutT* output, const Out } } +template +__global__ void DequantizeLinearKernelAxisStd(const InT* input, OutT* output, const OutT* scale_ptr, const InT* zero_point_ptr, CUDA_LONG N, + size_t batch_size, size_t n_scales) { + CUDA_LONG id = NumElementsPerThread * NumThreadsPerBlock * blockIdx.x + threadIdx.x; + // The scale needs to change every n_same_scale. + CUDA_LONG n_same_scale = N / (batch_size * n_scales); + int scale_id; + +#pragma unroll + for (int i = 0; i < NumElementsPerThread; i++) { + if (id < N) { + scale_id = (id / n_same_scale) % n_scales; + output[id] = (zero_point_ptr == nullptr ? static_cast(input[id]) : static_cast(input[id] - zero_point_ptr[scale_id])) * scale_ptr[scale_id]; + id += NumThreadsPerBlock; + } + } +} + +template +struct DQFloat8; + +#if !defined(DISABLE_FLOAT8_TYPES) + +#if defined(CUDA_VERSION) && CUDA_VERSION >= 11080 + +template <> +struct DQFloat8 { + __device__ __forceinline__ half operator()(Float8E4M3FN v, half scale) const { + return __nv_cvt_fp8_to_halfraw(v.val, __NV_E4M3) * scale; + } +}; + +template <> +struct DQFloat8 { + __device__ __forceinline__ half operator()(Float8E5M2 v, half scale) const { + return __nv_cvt_fp8_to_halfraw(v.val, __NV_E5M2) * scale; + } +}; + +template <> +struct DQFloat8 { + __device__ __forceinline__ float operator()(Float8E4M3FN v, float scale) const { + return __half2float(__nv_cvt_fp8_to_halfraw(v.val, __NV_E4M3)) * scale; + } +}; + +template <> +struct DQFloat8 { + __device__ __forceinline__ float operator()(Float8E5M2 v, float scale) const { + return __half2float(__nv_cvt_fp8_to_halfraw(v.val, __NV_E5M2)) * scale; + } +}; + +#else + +template <> +struct DQFloat8 { + __device__ __forceinline__ half operator()(Float8E4M3FN v, half scale) const { + return __float2half(v.ToFloat()) * scale; + } +}; + +template <> +struct DQFloat8 { + __device__ __forceinline__ half operator()(Float8E5M2 v, half scale) const { + return __float2half(v.ToFloat()) * scale; + } +}; + +template <> +struct DQFloat8 { + __device__ __forceinline__ float operator()(Float8E4M3FN v, float scale) const { + return v.ToFloat() * scale; + } +}; + +template <> +struct DQFloat8 { + __device__ __forceinline__ float operator()(Float8E5M2 v, float scale) const { + return v.ToFloat() * scale; + } +}; + +#endif + +#endif + +template +__global__ void DequantizeLinearKernelSat(const InT* input, OutT* output, const OutT* scale_ptr, const InT* zero_point_ptr, CUDA_LONG N) { + CUDA_LONG id = NumElementsPerThread * NumThreadsPerBlock * blockIdx.x + threadIdx.x; + + OutT scale = *scale_ptr; + // zero_point is unused. + // InT zero_point = zero_point_ptr != nullptr ? *zero_point_ptr : InT(0, true); +#pragma unroll + for (int i = 0; i < NumElementsPerThread; i++) { + if (id < N) { + output[id] = DQFloat8()(input[id], scale); + id += NumThreadsPerBlock; + } + } +} + +#if !defined(DISABLE_FLOAT8_TYPES) + +template +__global__ void DequantizeLinearKernelAxisSat(const InT* input, OutT* output, const OutT* scale_ptr, const InT* zero_point_ptr, CUDA_LONG N, + size_t batch_size, size_t n_scales) { + CUDA_LONG id = NumElementsPerThread * NumThreadsPerBlock * blockIdx.x + threadIdx.x; + // The scale needs to change every n_same_scale. + CUDA_LONG n_same_scale = N / (batch_size * n_scales); + int scale_id; + +#pragma unroll + for (int i = 0; i < NumElementsPerThread; i++) { + if (id < N) { + scale_id = (id / n_same_scale) % n_scales; + output[id] = DQFloat8()(input[id], scale_ptr[scale_id]); + id += NumThreadsPerBlock; + } + } +} + +#endif + +template +Status CudaDequantizeLinearStd(cudaStream_t stream, const InT* input, OutT* output, const OutT* scale, const InT* zero_point, size_t num_of_element) { + if (num_of_element <= 0) + return Status::OK(); + + int blocksPerGrid = static_cast(CeilDiv(num_of_element, GridDim::maxThreadsPerBlock * GridDim::maxElementsPerThread)); + DequantizeLinearKernelStd<<>>( + input, + output, + scale, + zero_point, + static_cast(num_of_element)); + return Status::OK(); +} + +template +Status CudaDequantizeLinearAxisStd(cudaStream_t stream, const InT* input, OutT* output, const OutT* scale, const InT* zero_point, size_t num_of_element, + size_t batch_size, size_t n_scales) { + if (num_of_element <= 0) + return Status::OK(); + + int blocksPerGrid = static_cast(CeilDiv(num_of_element, GridDim::maxThreadsPerBlock * GridDim::maxElementsPerThread)); + DequantizeLinearKernelAxisStd<<>>( + input, + output, + scale, + zero_point, + static_cast(num_of_element), + batch_size, + n_scales); + return Status::OK(); +} + +#if !defined(DISABLE_FLOAT8_TYPES) + template -Status CudaDequantizeLinear(cudaStream_t stream, const InT* input, OutT* output, const OutT* scale, const InT* zero_point, size_t num_of_element) { +Status CudaDequantizeLinearSat(cudaStream_t stream, const InT* input, OutT* output, const OutT* scale, const InT* zero_point, size_t num_of_element) { if (num_of_element <= 0) return Status::OK(); int blocksPerGrid = static_cast(CeilDiv(num_of_element, GridDim::maxThreadsPerBlock * GridDim::maxElementsPerThread)); - DequantizeLinearKernel<<>>( + DequantizeLinearKernelSat<<>>( input, output, scale, @@ -89,15 +457,73 @@ Status CudaDequantizeLinear(cudaStream_t stream, const InT* input, OutT* output, return Status::OK(); } -template Status CudaQuantizeLinear(cudaStream_t stream, const float* input, int8_t* output, const float* scale, const int8_t* zero_point, size_t num_of_element); -template Status CudaQuantizeLinear(cudaStream_t stream, const float* input, uint8_t* output, const float* scale, const uint8_t* zero_point, size_t num_of_element); -template Status CudaQuantizeLinear(cudaStream_t stream, const half* input, int8_t* output, const half* scale, const int8_t* zero_point, size_t num_of_element); -template Status CudaQuantizeLinear(cudaStream_t stream, const half* input, uint8_t* output, const half* scale, const uint8_t* zero_point, size_t num_of_element); +template +Status CudaDequantizeLinearAxisSat(cudaStream_t stream, const InT* input, OutT* output, const OutT* scale, const InT* zero_point, size_t num_of_element, + size_t batch_size, size_t n_scales) { + if (num_of_element <= 0) + return Status::OK(); + + int blocksPerGrid = static_cast(CeilDiv(num_of_element, GridDim::maxThreadsPerBlock * GridDim::maxElementsPerThread)); + DequantizeLinearKernelAxisSat<<>>( + input, + output, + scale, + zero_point, + static_cast(num_of_element), + batch_size, + n_scales); + return Status::OK(); +} + +#endif + +template Status CudaQuantizeLinearStd(cudaStream_t stream, const float* input, int8_t* output, const float* scale, const int8_t* zero_point, size_t num_of_element); +template Status CudaQuantizeLinearStd(cudaStream_t stream, const float* input, uint8_t* output, const float* scale, const uint8_t* zero_point, size_t num_of_element); +template Status CudaQuantizeLinearStd(cudaStream_t stream, const half* input, int8_t* output, const half* scale, const int8_t* zero_point, size_t num_of_element); +template Status CudaQuantizeLinearStd(cudaStream_t stream, const half* input, uint8_t* output, const half* scale, const uint8_t* zero_point, size_t num_of_element); + +template Status CudaQuantizeLinearAxisStd(cudaStream_t stream, const float* input, int8_t* output, const float* scale, const int8_t* zero_point, size_t num_of_element, size_t batch_size, size_t n_scales); +template Status CudaQuantizeLinearAxisStd(cudaStream_t stream, const float* input, uint8_t* output, const float* scale, const uint8_t* zero_point, size_t num_of_element, size_t batch_size, size_t n_scales); +template Status CudaQuantizeLinearAxisStd(cudaStream_t stream, const half* input, int8_t* output, const half* scale, const int8_t* zero_point, size_t num_of_element, size_t batch_size, size_t n_scales); +template Status CudaQuantizeLinearAxisStd(cudaStream_t stream, const half* input, uint8_t* output, const half* scale, const uint8_t* zero_point, size_t num_of_element, size_t batch_size, size_t n_scales); + +#if !defined(DISABLE_FLOAT8_TYPES) + +template Status CudaQuantizeLinearSat(cudaStream_t stream, const float* input, Float8E4M3FN* output, const float* scale, const Float8E4M3FN* zero_point, size_t num_of_element, bool saturate); +template Status CudaQuantizeLinearSat(cudaStream_t stream, const float* input, Float8E5M2* output, const float* scale, const Float8E5M2* zero_point, size_t num_of_element, bool saturate); +template Status CudaQuantizeLinearSat(cudaStream_t stream, const half* input, Float8E4M3FN* output, const half* scale, const Float8E4M3FN* zero_point, size_t num_of_element, bool saturate); +template Status CudaQuantizeLinearSat(cudaStream_t stream, const half* input, Float8E5M2* output, const half* scale, const Float8E5M2* zero_point, size_t num_of_element, bool saturate); + +template Status CudaQuantizeLinearAxisSat(cudaStream_t stream, const float* input, Float8E4M3FN* output, const float* scale, const Float8E4M3FN* zero_point, size_t num_of_element, size_t batch_size, size_t n_scales, bool saturate); +template Status CudaQuantizeLinearAxisSat(cudaStream_t stream, const float* input, Float8E5M2* output, const float* scale, const Float8E5M2* zero_point, size_t num_of_element, size_t batch_size, size_t n_scales, bool saturate); +template Status CudaQuantizeLinearAxisSat(cudaStream_t stream, const half* input, Float8E4M3FN* output, const half* scale, const Float8E4M3FN* zero_point, size_t num_of_element, size_t batch_size, size_t n_scales, bool saturate); +template Status CudaQuantizeLinearAxisSat(cudaStream_t stream, const half* input, Float8E5M2* output, const half* scale, const Float8E5M2* zero_point, size_t num_of_element, size_t batch_size, size_t n_scales, bool saturate); + +#endif + +template Status CudaDequantizeLinearStd(cudaStream_t stream, const int8_t* input, float* output, const float* scale, const int8_t* zero_point, size_t num_of_element); +template Status CudaDequantizeLinearStd(cudaStream_t stream, const uint8_t* input, float* output, const float* scale, const uint8_t* zero_point, size_t num_of_element); +template Status CudaDequantizeLinearStd(cudaStream_t stream, const int8_t* input, half* output, const half* scale, const int8_t* zero_point, size_t num_of_element); +template Status CudaDequantizeLinearStd(cudaStream_t stream, const uint8_t* input, half* output, const half* scale, const uint8_t* zero_point, size_t num_of_element); + +template Status CudaDequantizeLinearAxisStd(cudaStream_t stream, const int8_t* input, float* output, const float* scale, const int8_t* zero_point, size_t num_of_element, size_t batch_size, size_t n_scales); +template Status CudaDequantizeLinearAxisStd(cudaStream_t stream, const uint8_t* input, float* output, const float* scale, const uint8_t* zero_point, size_t num_of_element, size_t batch_size, size_t n_scales); +template Status CudaDequantizeLinearAxisStd(cudaStream_t stream, const int8_t* input, half* output, const half* scale, const int8_t* zero_point, size_t num_of_element, size_t batch_size, size_t n_scales); +template Status CudaDequantizeLinearAxisStd(cudaStream_t stream, const uint8_t* input, half* output, const half* scale, const uint8_t* zero_point, size_t num_of_element, size_t batch_size, size_t n_scales); + +#if !defined(DISABLE_FLOAT8_TYPES) + +template Status CudaDequantizeLinearSat(cudaStream_t stream, const Float8E4M3FN* input, float* output, const float* scale, const Float8E4M3FN* zero_point, size_t num_of_element); +template Status CudaDequantizeLinearSat(cudaStream_t stream, const Float8E5M2* input, float* output, const float* scale, const Float8E5M2* zero_point, size_t num_of_element); +template Status CudaDequantizeLinearSat(cudaStream_t stream, const Float8E4M3FN* input, half* output, const half* scale, const Float8E4M3FN* zero_point, size_t num_of_element); +template Status CudaDequantizeLinearSat(cudaStream_t stream, const Float8E5M2* input, half* output, const half* scale, const Float8E5M2* zero_point, size_t num_of_element); + +template Status CudaDequantizeLinearAxisSat(cudaStream_t stream, const Float8E4M3FN* input, float* output, const float* scale, const Float8E4M3FN* zero_point, size_t num_of_element, size_t batch_size, size_t n_scales); +template Status CudaDequantizeLinearAxisSat(cudaStream_t stream, const Float8E5M2* input, float* output, const float* scale, const Float8E5M2* zero_point, size_t num_of_element, size_t batch_size, size_t n_scales); +template Status CudaDequantizeLinearAxisSat(cudaStream_t stream, const Float8E4M3FN* input, half* output, const half* scale, const Float8E4M3FN* zero_point, size_t num_of_element, size_t batch_size, size_t n_scales); +template Status CudaDequantizeLinearAxisSat(cudaStream_t stream, const Float8E5M2* input, half* output, const half* scale, const Float8E5M2* zero_point, size_t num_of_element, size_t batch_size, size_t n_scales); -template Status CudaDequantizeLinear(cudaStream_t stream, const int8_t* input, float* output, const float* scale, const int8_t* zero_point, size_t num_of_element); -template Status CudaDequantizeLinear(cudaStream_t stream, const uint8_t* input, float* output, const float* scale, const uint8_t* zero_point, size_t num_of_element); -template Status CudaDequantizeLinear(cudaStream_t stream, const int8_t* input, half* output, const half* scale, const int8_t* zero_point, size_t num_of_element); -template Status CudaDequantizeLinear(cudaStream_t stream, const uint8_t* input, half* output, const half* scale, const uint8_t* zero_point, size_t num_of_element); +#endif } // namespace cuda } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cuda/tensor/quantize_linear.cuh b/onnxruntime/core/providers/cuda/tensor/quantize_linear.cuh index 3c11e3b9a54e3..e8cd5d416f402 100644 --- a/onnxruntime/core/providers/cuda/tensor/quantize_linear.cuh +++ b/onnxruntime/core/providers/cuda/tensor/quantize_linear.cuh @@ -11,10 +11,33 @@ namespace onnxruntime { namespace cuda { template -Status CudaQuantizeLinear(cudaStream_t stream, const U* input, T* output, const U* scale, const T* zero_point, size_t num_of_element); +Status CudaQuantizeLinearStd(cudaStream_t stream, const U* input, T* output, const U* scale, const T* zero_point, size_t num_of_element); template -Status CudaDequantizeLinear(cudaStream_t stream, const T* input, U* output, const U* scale, const T* zero_point, size_t num_of_element); +Status CudaQuantizeLinearSat(cudaStream_t stream, const U* input, T* output, const U* scale, const T* zero_point, size_t num_of_element, + bool saturate); + +template +Status CudaQuantizeLinearAxisStd(cudaStream_t stream, const U* input, T* output, const U* scale, const T* zero_point, size_t num_of_element, + size_t batch_size, size_t n_scales); + +template +Status CudaQuantizeLinearAxisSat(cudaStream_t stream, const U* input, T* output, const U* scale, const T* zero_point, size_t num_of_element, + size_t batch_size, size_t n_scales, bool saturate); + +template +Status CudaDequantizeLinearStd(cudaStream_t stream, const T* input, U* output, const U* scale, const T* zero_point, size_t num_of_element); + +template +Status CudaDequantizeLinearSat(cudaStream_t stream, const T* input, U* output, const U* scale, const T* zero_point, size_t num_of_element); + +template +Status CudaDequantizeLinearAxisStd(cudaStream_t stream, const T* input, U* output, const U* scale, const T* zero_point, size_t num_of_element, + size_t batch_size, size_t n_scales); + +template +Status CudaDequantizeLinearAxisSat(cudaStream_t stream, const T* input, U* output, const U* scale, const T* zero_point, size_t num_of_element, + size_t batch_size, size_t n_scales); } // namespace cuda } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cuda/tensor/quantize_linear.h b/onnxruntime/core/providers/cuda/tensor/quantize_linear.h index f378778a1002c..86036f28ef552 100644 --- a/onnxruntime/core/providers/cuda/tensor/quantize_linear.h +++ b/onnxruntime/core/providers/cuda/tensor/quantize_linear.h @@ -9,20 +9,38 @@ namespace onnxruntime { namespace cuda { -template +template class QuantizeLinear final : public CudaKernel { public: - QuantizeLinear(const OpKernelInfo& info) : CudaKernel(info) {} + QuantizeLinear(const OpKernelInfo& info) : CudaKernel(info) { + if (!info.GetAttr("axis", &axis_).IsOK()) { + axis_ = 1; + } + if (!info.GetAttr("saturate", &saturate_).IsOK()) { + saturate_ = 1; + } + } Status ComputeInternal(OpKernelContext* p_op_kernel_context) const override; + + private: + int64_t axis_; + int64_t saturate_; }; -template +template class DequantizeLinear final : public CudaKernel { public: - DequantizeLinear(const OpKernelInfo& info) : CudaKernel(info) {} + DequantizeLinear(const OpKernelInfo& info) : CudaKernel(info) { + if (!info.GetAttr("axis", &axis_).IsOK()) { + axis_ = 1; + } + } Status ComputeInternal(OpKernelContext* p_op_kernel_context) const override; + + private: + int64_t axis_; }; } // namespace cuda diff --git a/onnxruntime/core/providers/cuda/tensor/reshape.cc b/onnxruntime/core/providers/cuda/tensor/reshape.cc index 61bca5bfe7f6a..3c6d900cee9a4 100644 --- a/onnxruntime/core/providers/cuda/tensor/reshape.cc +++ b/onnxruntime/core/providers/cuda/tensor/reshape.cc @@ -9,7 +9,19 @@ namespace cuda { ONNX_OPERATOR_KERNEL_EX( Reshape, kOnnxDomain, - 14, + 19, + kCudaExecutionProvider, + (*KernelDefBuilder::Create()) + .TypeConstraint("T", DataTypeImpl::AllFixedSizeTensorTypesIRv9()) + .TypeConstraint("shape", DataTypeImpl::GetTensorType()) + .Alias(0, 0) + .InputMemoryType(OrtMemTypeCPUInput, 1), + Reshape); + +ONNX_OPERATOR_VERSIONED_KERNEL_EX( + Reshape, + kOnnxDomain, + 14, 18, kCudaExecutionProvider, (*KernelDefBuilder::Create()) .TypeConstraint("T", DataTypeImpl::AllFixedSizeTensorTypes()) diff --git a/onnxruntime/core/providers/cuda/tensor/resize_impl.cu b/onnxruntime/core/providers/cuda/tensor/resize_impl.cu index 5f6e52ff5ac1e..1a94c7705e913 100644 --- a/onnxruntime/core/providers/cuda/tensor/resize_impl.cu +++ b/onnxruntime/core/providers/cuda/tensor/resize_impl.cu @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + #include "core/providers/cuda/cu_inc/common.cuh" #include "core/providers/cuda/tensor/resize_impl.h" @@ -156,7 +159,7 @@ __global__ void _ResizeNearestMappingKernel2D( extrapolation_enabled && (orig_coord < 0.f || orig_coord > static_cast(input_height - 1))); dim = calc_nearest_pixel(orig_coord, scales_height < 1); if (dim >= input_height) dim = input_height - 1; - if (dim < 0) dim = 0; + if (dim < 0) dim = 0; } dims_mapping[id].origin_ = dim; @@ -173,7 +176,7 @@ __global__ void _ResizeNearestMappingKernel2D( extrapolation_enabled && (orig_coord < 0.f || orig_coord > static_cast(input_width - 1))); dim = calc_nearest_pixel(orig_coord, scales_width < 1); if (dim >= input_width) dim = input_width - 1; - if (dim < 0) dim = 0; + if (dim < 0) dim = 0; } dims_mapping[id].origin_ = dim; @@ -212,7 +215,7 @@ __global__ void _ResizeNearestMappingKernel( dims_mapping[id].extrapolate_ = static_cast(extrapolation_enabled && (orig_coord < 0.f || orig_coord > static_cast(input_shape[axis] - 1))); dim = calc_nearest_pixel(orig_coord, scales[axis] < 1); if (dim >= input_shape[axis]) dim = input_shape[axis] - 1; - if (dim < 0) dim = 0; + if (dim < 0) dim = 0; } dims_mapping[id].origin_ = dim; @@ -378,9 +381,9 @@ __global__ void _ResizeTrilinearCoordinateMapping( dims_mapping[id].origin_ = z_int; dims_mapping[id].weight_ = (z_int >= input_depth - 1) ? 0.5f : input_z - z_int; } else if (id >= output_depth && id < (output_depth + output_height)) { // y = id - output_depth - float input_y = scale_height == 1 ? static_cast(id - output_depth) : - transform_coordinate(static_cast(id - output_depth), scale_height, - static_cast(output_height), static_cast(input_height), + float input_y = scale_height == 1 ? static_cast(id - output_depth) : + transform_coordinate(static_cast(id - output_depth), scale_height, + static_cast(output_height), static_cast(input_height), roi_height_start, roi_height_end); dims_mapping[id].extrapolate_ = (int)(extrapolation_enabled && (input_y < 0 || input_y > static_cast(input_height - 1))); @@ -416,12 +419,12 @@ __global__ void _ResizeTrilinearKernel( div_output_image.divmod(id, bxc, output_image_index); CUDA_LONG input_index = bxc * input_depth * input_height * input_width; int output_z, output_y, output_x, temp; - + div_output_height.divmod(output_image_index, output_z, temp); div_output_width.divmod(temp, output_y, output_x); - if (dims_mapping[output_z].extrapolate_ || - dims_mapping[output_y + output_depth].extrapolate_ || + if (dims_mapping[output_z].extrapolate_ || + dims_mapping[output_y + output_depth].extrapolate_ || dims_mapping[output_x + output_depth + output_height].extrapolate_) { output_data[id] = extrapolation_value; return; @@ -435,7 +438,7 @@ __global__ void _ResizeTrilinearKernel( float x_offset_0 = dims_mapping[output_x + output_depth + output_height].weight_; int x_int = dims_mapping[output_x + output_depth + output_height].origin_; - + input_index += z_int * input_height * input_width + y_int * input_width + x_int; T x000 = input_data[input_index]; diff --git a/onnxruntime/core/providers/cuda/tensor/scatter_elements.h b/onnxruntime/core/providers/cuda/tensor/scatter_elements.h index bbf33b84a1fce..3e9e0ce041845 100755 --- a/onnxruntime/core/providers/cuda/tensor/scatter_elements.h +++ b/onnxruntime/core/providers/cuda/tensor/scatter_elements.h @@ -1,5 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. + #pragma once #include "core/providers/shared_library/provider_api.h" diff --git a/onnxruntime/core/providers/cuda/tensor/shape_op.cc b/onnxruntime/core/providers/cuda/tensor/shape_op.cc index 1007fcc50b38b..0d5da81fe256b 100644 --- a/onnxruntime/core/providers/cuda/tensor/shape_op.cc +++ b/onnxruntime/core/providers/cuda/tensor/shape_op.cc @@ -32,10 +32,10 @@ ONNX_OPERATOR_VERSIONED_KERNEL_EX( .TypeConstraint("T1", DataTypeImpl::GetTensorType()), Shape); -ONNX_OPERATOR_KERNEL_EX( +ONNX_OPERATOR_VERSIONED_KERNEL_EX( Shape, kOnnxDomain, - 15, + 15, 18, kCudaExecutionProvider, (*KernelDefBuilder::Create()) // properly force CPU/GPU synch inside the kernel @@ -44,5 +44,17 @@ ONNX_OPERATOR_KERNEL_EX( .TypeConstraint("T1", DataTypeImpl::GetTensorType()), Shape); +ONNX_OPERATOR_KERNEL_EX( + Shape, + kOnnxDomain, + 19, + kCudaExecutionProvider, + (*KernelDefBuilder::Create()) + // properly force CPU/GPU synch inside the kernel + .OutputMemoryType(OrtMemTypeCPUInput, 0) + .TypeConstraint("T", DataTypeImpl::AllFixedSizeTensorTypesIRv9()) + .TypeConstraint("T1", DataTypeImpl::GetTensorType()), + Shape); + } // namespace cuda } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cuda/tensor/transpose.cc b/onnxruntime/core/providers/cuda/tensor/transpose.cc index d056219a89a73..0e10ebcbef21d 100644 --- a/onnxruntime/core/providers/cuda/tensor/transpose.cc +++ b/onnxruntime/core/providers/cuda/tensor/transpose.cc @@ -196,7 +196,7 @@ Status Transpose::DoTranspose(const cudaDeviceProp& prop, auto mn = TryTransposeWithCublas(new_permutations, new_input_dims); int M = std::get<0>(mn); int N = std::get<1>(mn); - if (M != 0 && N != 0) { + if (M != 0 && N != 0 && (element_type != ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16 || CanUse_cublasTransposeHelper_MLFloat16(M, N))) { if (element_type == utils::GetONNXTensorElementDataType()) { return TransposeWithCublas(stream, cublas_handle, input, output, M, N); } else if (element_type == utils::GetONNXTensorElementDataType()) { diff --git a/onnxruntime/core/providers/cuda/test/all_tests.h b/onnxruntime/core/providers/cuda/test/all_tests.h deleted file mode 100644 index 9f36474ba297c..0000000000000 --- a/onnxruntime/core/providers/cuda/test/all_tests.h +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. -#ifndef NDEBUG -namespace onnxruntime { -namespace cuda { -namespace test { - -// Test header provides function declarations in EP-side bridge. -bool TestDeferredRelease(); -bool TestDeferredReleaseWithoutArena(); -bool TestBeamSearchTopK(); -bool TestGreedySearchTopOne(); - -} // namespace test -} // namespace cuda -} // namespace onnxruntime -#endif diff --git a/onnxruntime/core/providers/cuda/triton_kernel.cu b/onnxruntime/core/providers/cuda/triton_kernel.cu new file mode 100644 index 0000000000000..6ffbf0420a15f --- /dev/null +++ b/onnxruntime/core/providers/cuda/triton_kernel.cu @@ -0,0 +1,204 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/providers/cuda/triton_kernel.h" +#include "core/framework/tunable.h" +#include +#include + +#ifdef USE_TRITON_KERNEL +#include +#include "triton_kernel_infos.h" +#endif + +#define ORT_TRITON_CHECK(expr, msg) \ + do { \ + auto status = expr; \ + const char* error_str; \ + if (status != CUDA_SUCCESS) { \ + auto get_status_err_str = cuGetErrorString(status, &error_str); \ + ORT_UNUSED_PARAMETER(get_status_err_str); \ + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, msg, " ", error_str); \ + } \ + } while (0) + +#define ORT_TRITON_THROW(expr, msg) \ + do { \ + auto status = expr; \ + const char* error_str; \ + if (status != CUDA_SUCCESS) { \ + auto get_status_err_str = cuGetErrorString(status, &error_str); \ + ORT_UNUSED_PARAMETER(get_status_err_str); \ + ORT_THROW(msg, error_str); \ + } \ + } while (0) + +namespace onnxruntime { +namespace cuda { +namespace { + +// A vector of kernel metadata +static std::vector ort_triton_kernel_metadata; + +// Store group_name -> [kernel metadata id vector] +static std::unordered_map> ort_triton_kernel_group_map; + +#ifdef USE_TRITON_KERNEL + +// Store func_name -> kernel metadata id +static std::unordered_map ort_triton_kernel_map; + +const int GPU_WARP_SIZE = 32; +constexpr int kMaxThreadsPerBlock = 1024; +// Currently the max shared memory per block is hardcoded to 64KB. +constexpr int kMaxSharedMemoryPerBlock = 64 * 1024; + +Status GetSymbolFromLibrary(const std::string& symbol_name, void** symbol) { + dlerror(); // Clear any old error str + + // Use RTLD_DEFAULT for search current lib.so. + // Value of RTLD_DEFAULT differs across posix platforms (-2 on macos, 0 on linux). + void* handle = RTLD_DEFAULT; + *symbol = dlsym(handle, symbol_name.c_str()); + + char* error_str = dlerror(); + if (error_str) { + Status status = ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "Failed to get symbol " + symbol_name + " with error: " + error_str); + return status; + } + // It's possible to get a NULL symbol in our case when Schemas are not custom. + return Status::OK(); +} +#endif + +/* + * Try to load CUDA kernels that are compiled by Triton. + * They are in hsaco/cubin format, and should use cuModuleLoad to load these kernels. + */ +void TryToLoadKernel() { + auto status = Status::OK(); + +#ifdef USE_TRITON_KERNEL + // get all kernel symbols from curret lib.so + size_t size = sizeof(kernel_infos) / sizeof(kernel_infos[0]); + + for (int i = 0; i < size; ++i) { + auto k_i = kernel_infos[i]; + + void* buff; + ORT_THROW_IF_ERROR(GetSymbolFromLibrary(k_i.name_start, &buff)); + + // try to load module and get function + CUmodule module; + ORT_TRITON_THROW(cuModuleLoadData(&module, buff), "Loading module data failed."); + + CUfunction function; + ORT_TRITON_THROW(cuModuleGetFunction(&function, module, k_i.func_name), "Getting function from module failed."); + + // setup kernel metadata + TritonKernelMetaData metadata; + metadata.num_warps = k_i.num_warps; + metadata.shared_mem_size = k_i.shared; + metadata.func = function; + std::string fname = k_i.name; // name is not same as func_name + metadata.name = fname; + std::string group_name = k_i.group_name; + + // pass constants + for (auto& kv : k_i.constants) { + metadata.constants[kv.first] = kv.second; + } + + auto idx = ort_triton_kernel_metadata.size(); + ort_triton_kernel_metadata.push_back(metadata); + ort_triton_kernel_map[fname] = idx; + ort_triton_kernel_group_map[group_name].push_back(idx); + LOGS_DEFAULT(VERBOSE) << "Loaded ort triton kernel: " << fname << " idx: " << idx; + } +#endif + + ORT_THROW_IF_ERROR(status); +} + +static std::once_flag load_ort_triton_kernel_flag; + +} // namespace + +void LoadOrtTritonKernel() { + // load kernel should be called only once + std::call_once(load_ort_triton_kernel_flag, TryToLoadKernel); +} + +Status LaunchTritonKernel(cudaStream_t stream, std::string fname, + int grid0, int grid1, int grid2, void* args, size_t args_size) { +#ifdef USE_TRITON_KERNEL + if (ort_triton_kernel_map.count(fname) == 0) { + // Return unsupported status if function name not found in registry. + // This error status will be used by TunableOp + std::ostringstream message_stream; + message_stream << "Can't find ort triton kernel name: " << fname; + std::string message = message_stream.str(); + TUNABLE_OP_RETURN_UNSUPPORTED_ARGUMENT_IF(true, message); + } + auto idx = ort_triton_kernel_map[fname]; + return LaunchTritonKernel(stream, idx, grid0, grid1, grid2, args, args_size); +#else + return Status::OK(); +#endif +} + +Status LaunchTritonKernel(cudaStream_t stream, size_t idx, + int grid0, int grid1, int grid2, void* args, size_t args_size) { +#ifdef USE_TRITON_KERNEL + if (idx >= ort_triton_kernel_metadata.size()) { + // Return unsupported status when idx exceeds the size of ort_triton_kernel_metadata. + // This error status will be used by TunableOp + std::ostringstream message_stream; + message_stream << "Can't find ort triton kernel idx: " << idx; + std::string message = message_stream.str(); + TUNABLE_OP_RETURN_UNSUPPORTED_ARGUMENT_IF(true, message); + } + auto metadata = ort_triton_kernel_metadata[idx]; + + int threads_per_block = GPU_WARP_SIZE * metadata.num_warps; + TUNABLE_OP_RETURN_UNSUPPORTED_ARGUMENT_IF( + threads_per_block > kMaxThreadsPerBlock, + "The threads_per_block (", threads_per_block, ") exceeds the max allowed value (", kMaxThreadsPerBlock, ")."); + TUNABLE_OP_RETURN_UNSUPPORTED_ARGUMENT_IF( + metadata.shared_mem_size > kMaxSharedMemoryPerBlock, + "The shared_mem_size (", metadata.shared_mem_size, ") exceeds the max allowed value (", + kMaxSharedMemoryPerBlock, " bytes)."); + + void* config[] = {CU_LAUNCH_PARAM_BUFFER_POINTER, args, CU_LAUNCH_PARAM_BUFFER_SIZE, &args_size, + CU_LAUNCH_PARAM_END}; + + ORT_TRITON_CHECK(cuLaunchKernel(metadata.func, + grid0, grid1, grid2, + threads_per_block, 1, 1, + metadata.shared_mem_size, + stream, + nullptr, + (void**)&config), + "Launching kernel failed."); +#endif + + return Status::OK(); +} + +const TritonKernelMetaData* GetOrtTritonKernelMetadata(size_t idx) { + if (idx >= ort_triton_kernel_metadata.size()) { + return nullptr; + } + return &ort_triton_kernel_metadata[idx]; +} + +const std::vector* GetOrtTritonKernelByGroup(std::string group_name) { + if (ort_triton_kernel_group_map.count(group_name) == 0) { + return nullptr; + } + return &ort_triton_kernel_group_map.at(group_name); +} + +} // namespace cuda +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/cuda/triton_kernel.h b/onnxruntime/core/providers/cuda/triton_kernel.h new file mode 100644 index 0000000000000..a4f2b4f5492b6 --- /dev/null +++ b/onnxruntime/core/providers/cuda/triton_kernel.h @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/providers/cuda/cuda_common.h" +#include + +namespace onnxruntime { +namespace cuda { + +struct TritonKernelMetaData { + int num_warps; + int shared_mem_size; + CUfunction func; + std::unordered_map constants; + std::string name; +}; + +namespace { + +template +struct DataTypeToName; + +#define DTYPE_TO_STR(type, name) \ + template <> \ + struct DataTypeToName { \ + constexpr static const char* value = name; \ + }; + +DTYPE_TO_STR(float, "fp32"); +DTYPE_TO_STR(half, "fp16"); +DTYPE_TO_STR(double, "fp64"); +DTYPE_TO_STR(BFloat16, "bf16"); + +} // end of namespace + +template +const std::string GetDataTypeName() { + return DataTypeToName::value; +} + +void LoadOrtTritonKernel(); + +Status LaunchTritonKernel(cudaStream_t stream, std::string fname, int grid0, int grid1, int grid2, void* args, size_t args_size); + +const TritonKernelMetaData* GetOrtTritonKernelMetadata(size_t idx); + +const std::vector* GetOrtTritonKernelByGroup(std::string group_name); + +Status LaunchTritonKernel(cudaStream_t stream, size_t idx, int grid0, int grid1, int grid2, void* args, size_t args_size); + +} // namespace cuda +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/cuda/tunable/cuda_tuning_context.cc b/onnxruntime/core/providers/cuda/tunable/cuda_tuning_context.cc index 4e302a2c6659f..2df995d6e62ac 100644 --- a/onnxruntime/core/providers/cuda/tunable/cuda_tuning_context.cc +++ b/onnxruntime/core/providers/cuda/tunable/cuda_tuning_context.cc @@ -9,6 +9,7 @@ #include "core/framework/tuning_context_impl.h" #undef TUNING_CONTEXT_IMPL #include +#include namespace onnxruntime { namespace cuda { @@ -27,6 +28,17 @@ static Status ValidateCudaVersion(const std::string& value) { return Status::OK(); } +std::string CudaTuningResultsValidator::GetOrtBuildConfig() const { + std::ostringstream oss; +#ifdef ENABLE_TRITON + constexpr int kTriton = 1; +#else + constexpr int kTriton = 0; +#endif + oss << "ENABLE_TRITON=" << kTriton << "|"; + return oss.str(); +} + std::string CudaTuningResultsValidator::GetDeviceModel() const { return ep_->GetDeviceProp().name; } @@ -77,6 +89,14 @@ bool CudaTuningContext::IsTuningEnabled() const { return info_->tuning_enable; } +void CudaTuningContext::SetMaxTuningDurationMs(int max_duration_ms) { + info_->max_tuning_duration_ms = max_duration_ms; +} + +int CudaTuningContext::GetMaxTuningDurationMs() const { + return info_->max_tuning_duration_ms > 0 ? info_->max_tuning_duration_ms : std::numeric_limits::max(); +} + TuningResultsManager& CudaTuningContext::GetTuningResultsManager() { return manager_; } @@ -89,6 +109,20 @@ const TuningResultsValidator& CudaTuningContext::GetTuningResultsValidator() con return validator_; } +IAllocatorUniquePtr CudaTuningContext::GetScratchBuffer( + size_t num_bytes, Stream* stream, OrtMemType mem_type) const { + if (num_bytes == 0) { + return nullptr; + } + + auto it = allocators_->find(ep_->GetOrtDeviceByMemType(mem_type)); + if (it == allocators_->end()) { + return nullptr; + } + + return IAllocator::MakeUniquePtr(it->second, num_bytes, false, stream, WaitCudaNotificationOnDevice); +} + } // namespace tunable } // namespace cuda } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cuda/tunable/cuda_tuning_context.h b/onnxruntime/core/providers/cuda/tunable/cuda_tuning_context.h index ec961890e65a0..a57887f4c5c86 100644 --- a/onnxruntime/core/providers/cuda/tunable/cuda_tuning_context.h +++ b/onnxruntime/core/providers/cuda/tunable/cuda_tuning_context.h @@ -20,6 +20,8 @@ class CudaTuningResultsValidator : public TuningResultsValidator { CudaTuningResultsValidator(CUDAExecutionProvider* ep); protected: + std::string GetOrtBuildConfig() const override; + std::string GetDeviceModel() const; Status ValidateDeviceModel(const std::string& value) const; @@ -39,11 +41,17 @@ class CudaTuningContext : public ITuningContext { void DisableTuning() override; bool IsTuningEnabled() const override; + void SetMaxTuningDurationMs(int max_duration_ms) override; + int GetMaxTuningDurationMs() const override; + TuningResultsManager& GetTuningResultsManager() override; const TuningResultsManager& GetTuningResultsManager() const override; const TuningResultsValidator& GetTuningResultsValidator() const override; + IAllocatorUniquePtr GetScratchBuffer( + size_t bytes, Stream* stream, OrtMemType mem_type = OrtMemTypeDefault) const; + private: TunableOpInfo* info_; // non-owning handle TuningResultsManager manager_; diff --git a/onnxruntime/core/providers/cuda/tunable/math/gemm.cc b/onnxruntime/core/providers/cuda/tunable/math/gemm.cc new file mode 100644 index 0000000000000..38752b3a56e0e --- /dev/null +++ b/onnxruntime/core/providers/cuda/tunable/math/gemm.cc @@ -0,0 +1,105 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/providers/cuda/tunable/math/gemm.h" + +#include "core/common/inlined_containers.h" + +namespace onnxruntime { +namespace cuda { +namespace tunable { + +template +GemmParams::GemmParams(int m, int n, int k, bool trans_a, bool trans_b, float alpha, float beta, + const Gemm* gemm_kernel, OpKernelContext* ctx) + : OpParams(gemm_kernel->GetTuningContext(), ctx->GetComputeStream()), + trans_a_(trans_a), + trans_b_(trans_b), + alpha_(alpha), + beta_(beta), + m_(m), + n_(n), + k_(k), + gemm_kernel_(gemm_kernel), + ctx_(ctx) { + const auto* b = ctx->Input(2); + bm_ = gsl::narrow_cast(beta_ == 0.0f ? 0 : (b->Shape().NumDimensions() > 1 ? b->Shape()[0] : 1)); + bn_ = gsl::narrow_cast( + beta_ == 0.0f + ? 0 + : (b->Shape().NumDimensions() > 1 ? b->Shape()[1] : (b->Shape().NumDimensions() > 0 ? b->Shape()[0] : 1))); + +#ifdef ENABLE_TRITON + const auto* x = ctx->Input(0); + has_triton_support_ = contrib::IsTritonOpExecutorInitialized() && + (std::is_same::value || std::is_same::value) && + x->Shape().NumDimensions() > 1; +#endif +} + +namespace { + +template +common::Status DefaultGemmOp(const GemmParams* params) { + return params->gemm_kernel_->ComputeDefault(params->ctx_, params->m_, params->n_, params->k_); +} + +#ifdef ENABLE_TRITON +template +common::Status TritonGemmOp(const GemmParams* params) { + TUNABLE_OP_RETURN_UNSUPPORTED_ARGUMENT_IF(!params->has_triton_support_); + size_t input_count = params->beta_ == 0.0f ? 2 : 3; + size_t output_count = 1; + std::string func_name = params->beta_ == 0.0f ? "triton_matmul_out" : "triton_gemm_out"; + InlinedHashMap> kwargs; + if (params->trans_a_) kwargs.insert({"trans_a", {"true", ONNX_NAMESPACE::TensorProto_DataType_BOOL}}); + if (params->trans_b_) kwargs.insert({"trans_b", {"true", ONNX_NAMESPACE::TensorProto_DataType_BOOL}}); + if (params->alpha_ != 1.0f) { + kwargs.insert({"alpha", {std::to_string(params->alpha_), ONNX_NAMESPACE::TensorProto_DataType_FLOAT}}); + } + if (params->beta_ != 0.0f && params->beta_ != 1.0f) { + kwargs.insert({"beta", {std::to_string(params->beta_), ONNX_NAMESPACE::TensorProto_DataType_FLOAT}}); + } + return contrib::ExecuteTritonOpByFuncName(params->ctx_, func_name, input_count, output_count, kwargs); +} +#endif + +template +class GemmTunableOp : public TunableOp> { + public: + GemmTunableOp() { + this->RegisterOp(DefaultGemmOp); +#ifdef ENABLE_TRITON + this->RegisterOp(TritonGemmOp); +#endif + } +}; + +} // namespace + +template +inline common::Status TunableGemm(int m, int n, int k, bool trans_a, bool trans_b, float alpha, float beta, + const Gemm* gemm_kernel, OpKernelContext* ctx) { + GemmParams params(m, n, k, trans_a, trans_b, alpha, beta, gemm_kernel, ctx); + if (params.tuning_ctx->IsTunableOpEnabled()) { + static GemmTunableOp gemm{}; + return gemm(¶ms); + } + + return DefaultGemmOp(¶ms); +} + +#define SPECIALIZE_TUNABLE_GEMM(T) \ + template common::Status TunableGemm(int m, int n, int k, bool trans_a, bool trans_b, float alpha, float beta, \ + const Gemm* gemm_kernel, OpKernelContext* ctx); + +SPECIALIZE_TUNABLE_GEMM(float) +SPECIALIZE_TUNABLE_GEMM(double) +SPECIALIZE_TUNABLE_GEMM(MLFloat16) +SPECIALIZE_TUNABLE_GEMM(BFloat16) + +#undef SPECIALIZE_TUNABLE_GEMM + +} // namespace tunable +} // namespace cuda +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/cuda/tunable/math/gemm.h b/onnxruntime/core/providers/cuda/tunable/math/gemm.h new file mode 100644 index 0000000000000..b6bdf43d52518 --- /dev/null +++ b/onnxruntime/core/providers/cuda/tunable/math/gemm.h @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/common/status.h" +#include "core/providers/cuda/cuda_common.h" +#include "core/providers/cuda/tunable/cuda_tunable.h" +#include "core/providers/cuda/math/gemm.h" + +namespace onnxruntime { +namespace cuda { +namespace tunable { + +template +struct GemmParams : OpParams { + GemmParams(int m, int n, int k, bool trans_a, bool trans_b, float alpha, float beta, const Gemm* gemm_kernel, + OpKernelContext* ctx); + + std::string Signature() const override { + return MakeString((trans_a_ ? "T" : "N"), (trans_b_ ? "T" : "N"), "_", m_, "_", n_, "_", k_, "_", bm_, "_", bn_); + } + + bool trans_a_; + bool trans_b_; + float alpha_; + float beta_; + int m_; + int n_; + int k_; + int bm_; + int bn_; + const Gemm* gemm_kernel_; + OpKernelContext* ctx_; +#ifdef ENABLE_TRITON + bool has_triton_support_ = false; +#endif +}; + +template +common::Status TunableGemm(int m, int n, int k, bool trans_a, bool trans_b, float alpha, float beta, + const Gemm* gemm_kernel, OpKernelContext* ctx); + +} // namespace tunable +} // namespace cuda +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/cuda/tunable/math/matmul.cc b/onnxruntime/core/providers/cuda/tunable/math/matmul.cc new file mode 100644 index 0000000000000..9742c320d573d --- /dev/null +++ b/onnxruntime/core/providers/cuda/tunable/math/matmul.cc @@ -0,0 +1,114 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/providers/cuda/tunable/math/matmul.h" + +#include "core/common/inlined_containers.h" + +namespace onnxruntime { +namespace cuda { +namespace tunable { + +template +MatMulParams::MatMulParams(float alpha, bool trans_a, bool trans_b, bool trans_batch_a, bool trans_batch_b, + MatMulComputeHelper& helper, const MatMul* matmul_kernel, OpKernelContext* ctx) + : OpParams(matmul_kernel->GetTuningContext(), ctx->GetComputeStream()), + alpha_(alpha), + trans_a_(trans_a), + trans_b_(trans_b), + trans_batch_a_(trans_batch_a), + trans_batch_b_(trans_batch_b), + helper_(helper), + matmul_kernel_(matmul_kernel), + ctx_(ctx) { +#ifdef ENABLE_TRITON + const TensorShape& shape_x = ctx->Input(0)->Shape(); + const TensorShape& shape_y = ctx->Input(1)->Shape(); + size_t rank_x = shape_x.NumDimensions(); + size_t rank_y = shape_y.NumDimensions(); + has_triton_support_ = contrib::IsTritonOpExecutorInitialized() && + (std::is_same::value || std::is_same::value) && !trans_batch_a && + !trans_batch_b && rank_x > 1 && rank_y > 1; + if (has_triton_support_ && rank_x > 2 && rank_y > 2) { + has_triton_support_ = rank_x == rank_y; + if (has_triton_support_) { + for (size_t i = 0; i < rank_x - 2; ++i) { + if (shape_x[i] != shape_y[i]) { + has_triton_support_ = false; + break; + } + } + } + } +#endif +} + +template +std::string MatMulParams::Signature() const { + const TensorShape& shape_x = ctx_->Input(0)->Shape(); + const TensorShape& shape_y = ctx_->Input(1)->Shape(); + return MakeString((trans_a_ ? "T" : "N"), (trans_b_ ? "T" : "N"), (trans_batch_a_ ? "T" : "N"), + (trans_batch_a_ ? "T" : "N"), "_", shape_x.ToString(), "_", shape_y.ToString()); +} + +namespace { + +template +common::Status DefaultMatMulOp(const MatMulParams* params) { + return params->matmul_kernel_->ComputeDefault(params->ctx_, params->helper_); +} + +#ifdef ENABLE_TRITON +template +common::Status TritonMatMulOp(const MatMulParams* params) { + TUNABLE_OP_RETURN_UNSUPPORTED_ARGUMENT_IF(!params->has_triton_support_); + InlinedHashMap> kwargs; + if (params->trans_a_) kwargs.insert({"trans_a", {"true", ONNX_NAMESPACE::TensorProto_DataType_BOOL}}); + if (params->trans_b_) kwargs.insert({"trans_b", {"true", ONNX_NAMESPACE::TensorProto_DataType_BOOL}}); + if (params->alpha_ != 1.0f) { + kwargs.insert({"alpha", {std::to_string(params->alpha_), ONNX_NAMESPACE::TensorProto_DataType_FLOAT}}); + } + return contrib::ExecuteTritonOpByFuncName(params->ctx_, "triton_matmul_out", 2, 1, kwargs); +} +#endif + +template +class MatMulTunableOp : public TunableOp> { + public: + MatMulTunableOp() { + this->RegisterOp(DefaultMatMulOp); +#ifdef ENABLE_TRITON + this->RegisterOp(TritonMatMulOp); +#endif + } +}; + +} // namespace + +template +inline common::Status TunableMatMul(float alpha, bool trans_a, bool trans_b, bool trans_batch_a, bool trans_batch_b, + MatMulComputeHelper& helper, const MatMul* matmul_kernel, OpKernelContext* ctx) { + MatMulParams params(alpha, trans_a, trans_b, trans_batch_a, trans_batch_b, helper, matmul_kernel, ctx); + if (params.tuning_ctx->IsTunableOpEnabled()) { + static MatMulTunableOp matmul{}; + return matmul(¶ms); + } + + return DefaultMatMulOp(¶ms); +} + +#define SPECIALIZE_TUNABLE_MATMUL(T) \ + template common::Status TunableMatMul(float alpha, bool trans_a, bool trans_b, bool trans_batch_a, \ + bool trans_batch_b, MatMulComputeHelper& helper, \ + const MatMul* matmul_kernel, OpKernelContext* ctx); + +SPECIALIZE_TUNABLE_MATMUL(float) +SPECIALIZE_TUNABLE_MATMUL(double) +SPECIALIZE_TUNABLE_MATMUL(MLFloat16) +SPECIALIZE_TUNABLE_MATMUL(BFloat16) + +#undef SPECIALIZE_TUNABLE_MATMUL + +} // namespace tunable +} // namespace cuda +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/cuda/tunable/math/matmul.h b/onnxruntime/core/providers/cuda/tunable/math/matmul.h new file mode 100644 index 0000000000000..0d796f1b8184d --- /dev/null +++ b/onnxruntime/core/providers/cuda/tunable/math/matmul.h @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/common/status.h" +#include "core/providers/cuda/cuda_common.h" +#include "core/providers/cuda/tunable/cuda_tunable.h" +#include "core/providers/cuda/math/matmul.h" + +namespace onnxruntime { +namespace cuda { +namespace tunable { + +template +struct MatMulParams : OpParams { + MatMulParams(float alpha, bool trans_a, bool trans_b, bool trans_batch_a, bool trans_batch_b, + MatMulComputeHelper& helper, const MatMul* matmul_kernel, OpKernelContext* ctx); + + std::string Signature() const override; + + float alpha_; + bool trans_a_; + bool trans_b_; + bool trans_batch_a_; + bool trans_batch_b_; + MatMulComputeHelper& helper_; + const MatMul* matmul_kernel_; + OpKernelContext* ctx_; +#ifdef ENABLE_TRITON + bool has_triton_support_ = false; +#endif +}; + +template +common::Status TunableMatMul(float alpha, bool trans_a, bool trans_b, bool trans_batch_a, bool trans_batch_b, + MatMulComputeHelper& helper, const MatMul* matmul_kernel, OpKernelContext* ctx); + +} // namespace tunable +} // namespace cuda +} // namespace onnxruntime diff --git a/onnxruntime/core/providers/cuda/version_script.lds b/onnxruntime/core/providers/cuda/version_script.lds index 094abb3329781..c02a8e4bcf724 100644 --- a/onnxruntime/core/providers/cuda/version_script.lds +++ b/onnxruntime/core/providers/cuda/version_script.lds @@ -1,7 +1,8 @@ #_init and _fini should be local VERS_1.0 { global: - GetProvider; + GetProvider; + _binary_*; # Hide everything else. local: diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/inc/DmlExecutionProvider.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/inc/DmlExecutionProvider.h index fd96bd812d056..52018500b134c 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/inc/DmlExecutionProvider.h +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/inc/DmlExecutionProvider.h @@ -32,7 +32,6 @@ namespace Dml ID3D12Resource* GetD3D12ResourceFromAllocation(onnxruntime::IAllocator* allocator, void* ptr); void FlushContext(onnxruntime::IExecutionProvider* provider); - void SetDefaultRoundingMode(onnxruntime::IExecutionProvider* provider, AllocatorRoundingMode roundingMode); void ReleaseCompletedReferences(onnxruntime::IExecutionProvider* provider); onnxruntime::common::Status CopyTensor( diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/inc/IWinmlExecutionProvider.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/inc/IWinmlExecutionProvider.h index 232a022d869f4..04381b6ce355c 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/inc/IWinmlExecutionProvider.h +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/inc/IWinmlExecutionProvider.h @@ -80,7 +80,7 @@ namespace Windows::AI::MachineLearning::Adapter // Either nodesAsOperatorDesc or nodesAsIDMLOperator can have non-zero size. struct DmlGraphNodeCreateInfo { - uint32_t nodeCount; + uint32_t nodeCount = 0; std::vector> nodesAsOperatorDesc; std::vector> nodesAsIDMLOperator; std::vector inputEdges; diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/AllocationInfo.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/AllocationInfo.h new file mode 100644 index 0000000000000..59a827a4ffa1b --- /dev/null +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/AllocationInfo.h @@ -0,0 +1,74 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include +#include +#include +#include "DmlResourceWrapper.h" + +namespace Dml +{ + class BucketizedBufferAllocator; + + class AllocationInfo : public Microsoft::WRL::RuntimeClass< + Microsoft::WRL::RuntimeClassFlags, IUnknown> + { + public: + AllocationInfo( + BucketizedBufferAllocator* owner, + size_t id, + uint64_t pooledResourceId, + DmlResourceWrapper* resourceWrapper, + size_t requestedSize) + : m_owner(owner) + , m_allocationId(id) + , m_pooledResourceId(pooledResourceId) + , m_resourceWrapper(resourceWrapper) + , m_requestedSize(requestedSize) + {} + + ~AllocationInfo(); + + BucketizedBufferAllocator* GetOwner() const + { + return m_owner; + } + + ID3D12Resource* GetResource() const + { + return m_resourceWrapper->GetD3D12Resource(); + } + + Microsoft::WRL::ComPtr DetachResourceWrapper() const + { + return std::move(m_resourceWrapper); + } + + size_t GetRequestedSize() const + { + return m_requestedSize; + } + + size_t GetId() const + { + return m_allocationId; + } + + uint64_t GetPooledResourceId() const + { + return m_pooledResourceId; + } + + private: + // The bucketized buffer allocator must outlive the allocation info + BucketizedBufferAllocator* m_owner; + size_t m_allocationId; // For debugging purposes + uint64_t m_pooledResourceId = 0; + Microsoft::WRL::ComPtr m_resourceWrapper; + + // The size requested during Alloc(), which may be smaller than the physical resource size + size_t m_requestedSize; + }; +} diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/BucketizedBufferAllocator.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/BucketizedBufferAllocator.cpp index f5abeb5d7bf7a..c24257071eda5 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/BucketizedBufferAllocator.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/BucketizedBufferAllocator.cpp @@ -95,7 +95,7 @@ namespace Dml uint64_t bucketSize = 0; // Use a pooled resource if the size (post rounding, if requested) matches a bucket size - if (m_defaultRoundingMode == AllocatorRoundingMode::Enabled || size == GetBucketSizeFromIndex(GetBucketIndexFromSize(size))) + if (roundingMode == AllocatorRoundingMode::Enabled || size == GetBucketSizeFromIndex(GetBucketIndexFromSize(size))) { Bucket* bucket = nullptr; @@ -212,15 +212,6 @@ namespace Dml ORT_THROW_HR(E_INVALIDARG); } const auto* allocInfo = static_cast(opaqueHandle); - - auto owner = allocInfo->GetOwner(); - //The owner can be null if the resource was wrapped via CreateGPUAllocationFromD3DResource - if (owner != nullptr && owner != this) - { - // This allocation doesn't belong to this allocator! - ORT_THROW_HR(E_INVALIDARG); - } - return allocInfo; } @@ -244,17 +235,12 @@ namespace Dml void* CPUAllocator::Alloc(size_t size) { - if (size <= 0) - { - return nullptr; - } - void* p = malloc(size); - return p; + return onnxruntime::AllocatorDefaultAlloc(size); } void CPUAllocator::Free(void* p) { - free(p); + return onnxruntime::AllocatorDefaultFree(p); } } // namespace Dml diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/BucketizedBufferAllocator.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/BucketizedBufferAllocator.h index 7e3471e276c0d..196fba5d7689d 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/BucketizedBufferAllocator.h +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/BucketizedBufferAllocator.h @@ -6,6 +6,7 @@ #include "core/framework/allocator.h" #include "ExecutionContext.h" #include "DmlResourceWrapper.h" +#include "AllocationInfo.h" namespace Dml { @@ -20,67 +21,6 @@ namespace Dml void Free(void* p) override; }; - class BucketizedBufferAllocator; - - class AllocationInfo : public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags, IUnknown> - { - public: - AllocationInfo( - BucketizedBufferAllocator* owner, - size_t id, - uint64_t pooledResourceId, - DmlResourceWrapper* resourceWrapper, - size_t requestedSize) - : m_owner(owner) - , m_allocationId(id) - , m_pooledResourceId(pooledResourceId) - , m_resourceWrapper(resourceWrapper) - , m_requestedSize(requestedSize) - {} - - ~AllocationInfo(); - - BucketizedBufferAllocator* GetOwner() const - { - return m_owner; - } - - ID3D12Resource* GetResource() const - { - return m_resourceWrapper->GetD3D12Resource(); - } - - ComPtr DetachResourceWrapper() const - { - return std::move(m_resourceWrapper); - } - - size_t GetRequestedSize() const - { - return m_requestedSize; - } - - size_t GetId() const - { - return m_allocationId; - } - - uint64_t GetPooledResourceId() const - { - return m_pooledResourceId; - } - - private: - BucketizedBufferAllocator* m_owner; - size_t m_allocationId; // For debugging purposes - uint64_t m_pooledResourceId = 0; - ComPtr m_resourceWrapper; - - // The size requested during Alloc(), which may be smaller than the physical resource size - size_t m_requestedSize; - }; - // Implements a Lotus allocator for D3D12 heap buffers, using a bucket allocation strategy. The allocator // maintains a set of fixed-size buckets, with each bucket containing one or more D3D12 buffers of that fixed size. // All requested allocation sizes are rounded up to the nearest bucket size, which ensures minimal fragmentation @@ -131,12 +71,6 @@ namespace Dml static gsl::index GetBucketIndexFromSize(uint64_t size); static uint64_t GetBucketSizeFromIndex(gsl::index index); - AllocationInfo* DecodeDataHandleInternal(void* opaqueHandle) - { - // Implement in terms of const version - return const_cast(DecodeDataHandle(static_cast(opaqueHandle))); - } - friend class AllocationInfo; void FreeResource(void* p, uint64_t resourceId); @@ -149,11 +83,16 @@ namespace Dml std::vector m_pool; size_t m_currentAllocationId = 0; uint64_t m_currentResourceId = 0; - AllocatorRoundingMode m_defaultRoundingMode = AllocatorRoundingMode::Enabled; + + // Unless specifically requested, allocation sizes are not rounded to enable pooling + // until SetDefaultRoundingMode is called. This should be done at completion of session + // initialization. + AllocatorRoundingMode m_defaultRoundingMode = AllocatorRoundingMode::Disabled; + std::shared_ptr m_context; std::unique_ptr m_subAllocator; - #if _DEBUG + #ifndef NDEBUG // Useful for debugging; keeps track of all allocations that haven't been freed yet std::map m_outstandingAllocationsById; #endif diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlCommandRecorder.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlCommandRecorder.cpp index 59ceecdc884d2..530c26d212083 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlCommandRecorder.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlCommandRecorder.cpp @@ -10,7 +10,7 @@ using namespace Dml; DmlCommandRecorder::DmlCommandRecorder( ID3D12Device* d3dDevice, - IDMLDevice* dmlDevice, + IDMLDevice* dmlDevice, std::shared_ptr commandQueue) : m_queue(std::move(commandQueue)), m_d3dDevice(d3dDevice), @@ -61,7 +61,7 @@ void DmlCommandRecorder::InitializeOperator( // Allocate and immediately free a temporary buffer. The buffer resource will still be // alive (managed by the pool); freeing allows the resource to be shared with other operators. - void* tempResourceHandle = allocator->Alloc(static_cast(temporaryResourceSize), AllocatorRoundingMode::Enabled); + void* tempResourceHandle = allocator->Alloc(static_cast(temporaryResourceSize)); if (!tempResourceHandle) { ORT_THROW_HR(E_OUTOFMEMORY); @@ -137,7 +137,7 @@ void DmlCommandRecorder::ExecuteOperator( // Allocate and immediately free a temporary buffer. The buffer resource will still be // alive (managed by the pool); freeing allows the resource to be shared with other operators. - void* tempResourceHandle = allocator->Alloc(static_cast(temporaryResourceSize), AllocatorRoundingMode::Enabled); + void* tempResourceHandle = allocator->Alloc(static_cast(temporaryResourceSize)); if (!tempResourceHandle) { ORT_THROW_HR(E_OUTOFMEMORY); @@ -183,7 +183,7 @@ void DmlCommandRecorder::CopyBufferRegion( m_currentCommandList->CopyBufferRegion(dstBuffer, dstOffset, srcBuffer, srcOffset, byteCount); m_operationsRecordedInCurrentCommandList = true; } - + void DmlCommandRecorder::FillBufferWithPattern( ID3D12Resource* dstBuffer, gsl::span value /* Data type agnostic value, treated as raw bits */) @@ -250,11 +250,11 @@ void DmlCommandRecorder::ExecuteCommandList( _Outptr_ ID3D12Fence** fence, _Out_ uint64_t* completionValue ) -{ +{ ORT_THROW_IF_FAILED(m_currentCommandList->Close()); if (m_operationsRecordedInCurrentCommandList) - { + { m_pendingCommandLists.push_back(m_currentCommandList.Get()); m_pendingCommandListsCacheable.push_back(true); } @@ -290,16 +290,16 @@ void DmlCommandRecorder::ExecuteCommandList( } ComPtr DmlCommandRecorder::GetCommandList() -{ +{ // Assume operations are added by the caller after this returns - m_operationsRecordedInCurrentCommandList = true; - return m_currentCommandList; + m_operationsRecordedInCurrentCommandList = true; + return m_currentCommandList; } void DmlCommandRecorder::ResourceBarrier(gsl::span barriers) { m_currentCommandList->ResourceBarrier(gsl::narrow_cast(barriers.size()), barriers.data()); - m_operationsRecordedInCurrentCommandList = true; + m_operationsRecordedInCurrentCommandList = true; } void DmlCommandRecorder::AddUAVBarrier() @@ -307,7 +307,7 @@ void DmlCommandRecorder::AddUAVBarrier() #pragma warning(suppress: 6387) auto barrier = CD3DX12_RESOURCE_BARRIER::UAV(nullptr); m_currentCommandList->ResourceBarrier(1, &barrier); - m_operationsRecordedInCurrentCommandList = true; + m_operationsRecordedInCurrentCommandList = true; } void DmlCommandRecorder::Open() @@ -323,7 +323,7 @@ void DmlCommandRecorder::Open() m_queue->GetType(), allocator, nullptr, - IID_GRAPHICS_PPV_ARGS(m_currentCommandList.ReleaseAndGetAddressOf()))); + IID_GRAPHICS_PPV_ARGS(m_currentCommandList.ReleaseAndGetAddressOf()))); } else { @@ -338,7 +338,7 @@ void DmlCommandRecorder::CloseAndExecute() ORT_THROW_IF_FAILED(m_currentCommandList->Close()); if (m_operationsRecordedInCurrentCommandList) - { + { m_pendingCommandLists.push_back(m_currentCommandList.Get()); m_pendingCommandListsCacheable.push_back(true); } @@ -386,4 +386,4 @@ void DmlCommandRecorder::SetDescriptorHeap(ID3D12DescriptorHeap* descriptorHeap) ID3D12DescriptorHeap* descriptorHeaps[] = { descriptorHeap }; m_currentCommandList->SetDescriptorHeaps(ARRAYSIZE(descriptorHeaps), descriptorHeaps); } -} \ No newline at end of file +} diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlCommittedResourceWrapper.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlCommittedResourceWrapper.h index cae206b569170..f0eaeb5581b49 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlCommittedResourceWrapper.h +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlCommittedResourceWrapper.h @@ -8,10 +8,10 @@ namespace Dml class DmlCommittedResourceWrapper : public Microsoft::WRL::RuntimeClass, DmlResourceWrapper> { public: - DmlCommittedResourceWrapper(ComPtr&& d3d12Resource) : m_d3d12Resource(std::move(d3d12Resource)) {} + DmlCommittedResourceWrapper(Microsoft::WRL::ComPtr&& d3d12Resource) : m_d3d12Resource(std::move(d3d12Resource)) {} ID3D12Resource* GetD3D12Resource() const final { return m_d3d12Resource.Get(); } private: - ComPtr m_d3d12Resource; + Microsoft::WRL::ComPtr m_d3d12Resource; }; } diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlExternalBufferAllocator.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlExternalBufferAllocator.h new file mode 100644 index 0000000000000..9514a24b4e781 --- /dev/null +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlExternalBufferAllocator.h @@ -0,0 +1,72 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include +#include +#include +#include +#include "External/D3DX12/d3dx12.h" +#include "core/framework/allocator.h" +#include "core/providers/dml/dml_provider_factory_creator.h" +#include "AllocationInfo.h" +#include "GraphicsUnknownHelper.h" +#include "ErrorHandling.h" +#include "DmlCommittedResourceWrapper.h" + +namespace Dml +{ + class DmlExternalBufferAllocator : public onnxruntime::IAllocator + { + public: + DmlExternalBufferAllocator(int device_id) : onnxruntime::IAllocator( + OrtMemoryInfo( + "DML", + OrtAllocatorType::OrtDeviceAllocator, + OrtDevice(OrtDevice::GPU, OrtDevice::MemType::DEFAULT, 0) + )) + { + m_device = onnxruntime::DMLProviderFactoryCreator::CreateD3D12Device(device_id, false); + } + + void* Alloc(size_t size) final + { + Microsoft::WRL::ComPtr resource; + auto buffer = CD3DX12_RESOURCE_DESC::Buffer(size, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS); + auto props = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT); + ORT_THROW_IF_FAILED(m_device->CreateCommittedResource( + &props, + D3D12_HEAP_FLAG_NONE, + &buffer, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS, + nullptr, + IID_GRAPHICS_PPV_ARGS(resource.GetAddressOf()) + )); + + const uint64_t resourceWidth = resource->GetDesc().Width; + constexpr uint64_t pooledResourceId = 0; // Not a pooled resource + + Microsoft::WRL::ComPtr resourceWrapper; + wil::MakeOrThrow(std::move(resource)).As(&resourceWrapper); + + Microsoft::WRL::ComPtr allocInfo = wil::MakeOrThrow( + nullptr, + 0, + pooledResourceId, + resourceWrapper.Get(), + static_cast(resourceWidth)); + + return allocInfo.Detach(); + } + + void Free(void* ptr) final + { + Microsoft::WRL::ComPtr resource; + resource.Attach(static_cast(ptr)); + } + + private: + Microsoft::WRL::ComPtr m_device; + }; +} diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlGraphFusionHelper.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlGraphFusionHelper.cpp index 17aa197396ae0..51b93efb3a646 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlGraphFusionHelper.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlGraphFusionHelper.cpp @@ -106,7 +106,7 @@ namespace DmlGraphFusionHelper void ProcessInputData( const ExecutionProviderImpl* providerImpl, const std::vector& isInputsUploadedByDmlEP, - std::vector& inputEdges, + const std::vector& inputEdges, const gsl::span subGraphInputArgNames, const std::unordered_map>& initializerNameToInitializerMap, onnxruntime::Graph& graph, @@ -325,37 +325,60 @@ namespace DmlGraphFusionHelper dmlGraphDesc.IntermediateEdges = dmlIntermediateEdges.data(); } - void CreateIDmlCompiledOperatorAndRegisterKernel( - onnxruntime::Graph& graph, - const onnxruntime::IndexedSubGraph& indexedSubGraph, - const onnxruntime::Node& fusedNode, - const std::unordered_map& partitionNodePropsMap, - const std::unordered_map>& initializerNameToInitializerMap, - const ExecutionProviderImpl* providerImpl, - onnxruntime::KernelRegistry* registryForPartitionKernels) + onnxruntime::IndexedSubGraph CreateIndexedSubGraph( + GraphPartition* partition, + uint32_t partitionIndex, + const std::string& partitionKernelPrefix) { - // convert partitionONNXGraph into DML EP GraphDesc - const uint32_t fusedNodeInputCount = gsl::narrow_cast(indexedSubGraph.GetMetaDef()->inputs.size()); - const uint32_t fusedNodeOutputCount = gsl::narrow_cast(indexedSubGraph.GetMetaDef()->outputs.size()); + assert(partition->IsDmlGraphPartition()); - std::vector isInputsUploadedByDmlEP(fusedNodeInputCount); - for (uint32_t index = 0; index < fusedNodeInputCount; ++index) + onnxruntime::IndexedSubGraph indexedSubGraph; + // Create a definition for the node. The name must be unique. + auto def = std::make_unique(); + def->name = DmlGraphFusionTransformer::DML_GRAPH_FUSION_NODE_NAME_PREFIX + partitionKernelPrefix + std::to_string(partitionIndex); + def->domain = DmlGraphFusionTransformer::DML_GRAPH_FUSION_NODE_DOMAIN; + def->since_version = 1; + def->inputs.insert(def->inputs.begin(), partition->GetInputs().begin(), partition->GetInputs().end()); + def->outputs.insert(def->outputs.begin(), partition->GetOutputs().begin(), partition->GetOutputs().end()); + + indexedSubGraph.SetMetaDef(std::move(def)); + indexedSubGraph.nodes = std::move(partition->GetNodeIndices()); + + return indexedSubGraph; + } + + std::unordered_map CreatePartitionNodePropsMap( + const onnxruntime::Graph& graph, + const onnxruntime::IndexedSubGraph& indexedSubGraph, + std::unordered_map&& graphNodePropertyMap) + { + // Populate properties which will be passed to OpKernel for this graph via the function below + std::unordered_map partitionNodePropsMap; + for (auto nodeIndex : indexedSubGraph.nodes) { - auto iter = initializerNameToInitializerMap.find(indexedSubGraph.GetMetaDef()->inputs[index]); - isInputsUploadedByDmlEP[index] = iter != initializerNameToInitializerMap.end() ? true : false; + const onnxruntime::Node* node = graph.GetNode(nodeIndex); + +#ifdef PRINT_PARTITON_INFO + printf("Partition %u\t%s\n", partitionIndex, GraphDescBuilder::GetUniqueNodeName(*node).c_str()); +#endif + partitionNodePropsMap.insert(std::make_pair( + GraphDescBuilder::GetUniqueNodeName(*node), std::move(graphNodePropertyMap[node]))); } - ComPtr device; - ORT_THROW_IF_FAILED(providerImpl->GetDmlDevice(device.GetAddressOf())); - GraphDescBuilder::GraphDesc graphDesc = GraphDescBuilder::BuildGraphDesc( - isInputsUploadedByDmlEP.data(), - isInputsUploadedByDmlEP.size(), - initializerNameToInitializerMap, - graph, - indexedSubGraph, - partitionNodePropsMap, - device.Get(), - providerImpl); +#ifdef PRINT_PARTITON_INFO + printf("\n"); +#endif + + return partitionNodePropsMap; + } + + Microsoft::WRL::ComPtr TryCreateCompiledOperator( + const GraphDescBuilder::GraphDesc& graphDesc, + const onnxruntime::IndexedSubGraph& indexedSubGraph, + const ExecutionProviderImpl* providerImpl) + { + const uint32_t fusedNodeInputCount = gsl::narrow_cast(indexedSubGraph.GetMetaDef()->inputs.size()); + const uint32_t fusedNodeOutputCount = gsl::narrow_cast(indexedSubGraph.GetMetaDef()->outputs.size()); // convert DML EP GraphDesc into DML_GRAPH_DESC and create IDMLCompiledOperator DML_GRAPH_DESC dmlGraphDesc = {}; @@ -387,14 +410,42 @@ namespace DmlGraphFusionHelper executionFlags |= DML_EXECUTION_FLAG_DISABLE_META_COMMANDS; } + ComPtr device; + ORT_THROW_IF_FAILED(providerImpl->GetDmlDevice(device.GetAddressOf())); + ComPtr device1; ORT_THROW_IF_FAILED(device.As(&device1)); + ComPtr compiledExecutionPlanOperator; ORT_THROW_IF_FAILED(device1->CompileGraph( &dmlGraphDesc, executionFlags, IID_PPV_ARGS(&compiledExecutionPlanOperator))); + // UINT32_MAX is currently the maximum number of bytes allowed by D3D12 for the offset of a view over a resource + if (compiledExecutionPlanOperator->GetBindingProperties().PersistentResourceSize > UINT32_MAX) + { + return nullptr; + } + + return compiledExecutionPlanOperator; + } + + void FusePartitionAndRegisterKernel( + onnxruntime::Graph& graph, + onnxruntime::KernelRegistry* registryForPartitionKernels, + const std::unordered_map>& initializerNameToInitializerMap, + const ExecutionProviderImpl* providerImpl, + const onnxruntime::IndexedSubGraph& indexedSubGraph, + std::vector&& isInputsUploadedByDmlEP, + const GraphDescBuilder::GraphDesc& graphDesc, + Microsoft::WRL::ComPtr compiledExecutionPlanOperator) + { + auto& fusedNode = graph.BeginFuseSubGraph(indexedSubGraph, indexedSubGraph.GetMetaDef()->name); + fusedNode.SetExecutionProviderType(onnxruntime::kDmlExecutionProvider); + + const uint32_t fusedNodeInputCount = gsl::narrow_cast(indexedSubGraph.GetMetaDef()->inputs.size()); + // Populate input bindings for operator initialization std::vector> initializeResourceRefs; // For lifetime control std::vector initInputBindings(fusedNodeInputCount); @@ -424,8 +475,8 @@ namespace DmlGraphFusionHelper nonOwnedGraphInputsFromInitializers, initializeResourceRefs, initInputBindings, - isInputsUploadedByDmlEP, - inputsUsed] + isInputsUploadedByDmlEP = std::move(isInputsUploadedByDmlEP), + inputsUsed = std::move(inputsUsed)] (onnxruntime::FuncManager& func_mgr, const onnxruntime::OpKernelInfo& info, std::unique_ptr& out) mutable ->onnxruntime::Status { out.reset(CreateFusedGraphKernel(info, @@ -435,8 +486,8 @@ namespace DmlGraphFusionHelper nonOwnedGraphInputsFromInitializers, initializeResourceRefs, initInputBindings, - isInputsUploadedByDmlEP, - inputsUsed)); + std::move(isInputsUploadedByDmlEP), + std::move(inputsUsed))); return Status::OK(); }; @@ -447,58 +498,7 @@ namespace DmlGraphFusionHelper .SinceVersion(indexedSubGraph.GetMetaDef()->since_version) .Provider(onnxruntime::kDmlExecutionProvider); ORT_THROW_IF_ERROR(registryForPartitionKernels->Register(builder, fused_kernel_func)); - } - void FusePartitionAndRegisterKernel( - GraphPartition* partition, - uint32_t partitionIndex, - onnxruntime::Graph& graph, - std::unordered_map& graphNodePropertyMap, - onnxruntime::KernelRegistry* registryForPartitionKernels, - const std::string& partitionKernelPrefix, - const std::unordered_map>& initializerNameToInitializerMap, - const ExecutionProviderImpl* providerImpl) - { - assert(partition->IsDmlGraphPartition()); - - onnxruntime::IndexedSubGraph indexedSubGraph; - // Create a definition for the node. The name must be unique. - auto def = std::make_unique(); - def->name = DmlGraphFusionTransformer::DML_GRAPH_FUSION_NODE_NAME_PREFIX + partitionKernelPrefix + std::to_string(partitionIndex); - def->domain = DmlGraphFusionTransformer::DML_GRAPH_FUSION_NODE_DOMAIN; - def->since_version = 1; - def->inputs.insert(def->inputs.begin(), partition->GetInputs().begin(), partition->GetInputs().end()); - def->outputs.insert(def->outputs.begin(), partition->GetOutputs().begin(), partition->GetOutputs().end()); - - indexedSubGraph.SetMetaDef(std::move(def)); - indexedSubGraph.nodes = std::move(partition->GetNodeIndices()); - auto& fusedNode = graph.BeginFuseSubGraph(indexedSubGraph, indexedSubGraph.GetMetaDef()->name); - fusedNode.SetExecutionProviderType(onnxruntime::kDmlExecutionProvider); - - // Populate properties which will be passed to OpKernel for this graph via the function below - std::unordered_map partitionNodePropsMap; - for (auto nodeIndex : indexedSubGraph.nodes) - { - const onnxruntime::Node* node = graph.GetNode(nodeIndex); - -#ifdef PRINT_PARTITON_INFO - printf("Partition %u\t%s\n", partitionIndex, GraphDescBuilder::GetUniqueNodeName(*node).c_str()); -#endif - partitionNodePropsMap.insert(std::make_pair( - GraphDescBuilder::GetUniqueNodeName(*node), std::move(graphNodePropertyMap[node]))); - } - -#ifdef PRINT_PARTITON_INFO - printf("\n"); -#endif - CreateIDmlCompiledOperatorAndRegisterKernel( - graph, - indexedSubGraph, - fusedNode, - partitionNodePropsMap, - initializerNameToInitializerMap, - providerImpl, - registryForPartitionKernels); graph.FinalizeFuseSubGraph(indexedSubGraph, fusedNode); } } diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlGraphFusionHelper.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlGraphFusionHelper.h index f2533bb37bccb..030cffc2a8794 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlGraphFusionHelper.h +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlGraphFusionHelper.h @@ -56,23 +56,29 @@ namespace DmlGraphFusionHelper _Inout_ std::vector& dmlOutputEdges, _Inout_ std::vector& dmlIntermediateEdges); - void CreateIDmlCompiledOperatorAndRegisterKernel( - onnxruntime::Graph& graph, + onnxruntime::IndexedSubGraph CreateIndexedSubGraph( + GraphPartition* partition, + uint32_t partitionIndex, + const std::string& partitionKernelPrefix); + + std::unordered_map CreatePartitionNodePropsMap( + const onnxruntime::Graph& graph, const onnxruntime::IndexedSubGraph& indexedSubGraph, - const onnxruntime::Node& fusedNode, - const std::unordered_map& partitionNodePropsMap, - const std::unordered_map>& isInitializerTransferable, - const ExecutionProviderImpl* providerImpl, - onnxruntime::KernelRegistry* registryForPartitionKernels); + std::unordered_map&& graphNodePropertyMap); + + Microsoft::WRL::ComPtr TryCreateCompiledOperator( + const GraphDescBuilder::GraphDesc& graphDesc, + const onnxruntime::IndexedSubGraph& indexedSubGraph, + const ExecutionProviderImpl* providerImpl); void FusePartitionAndRegisterKernel( - GraphPartition* partition, - uint32_t partitionIndex, onnxruntime::Graph& graph, - std::unordered_map& graphNodePropertyMap, onnxruntime::KernelRegistry* registryForPartitionKernels, - const std::string& partitionKernelPrefix, - const std::unordered_map>& isInitializerTransferable, - const ExecutionProviderImpl* providerImpl); + const std::unordered_map>& initializerNameToInitializerMap, + const ExecutionProviderImpl* providerImpl, + const onnxruntime::IndexedSubGraph& indexedSubGraph, + std::vector&& isInputsUploadedByDmlEP, + const GraphDescBuilder::GraphDesc& graphDesc, + Microsoft::WRL::ComPtr compiledExecutionPlanOperator); } } diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlGraphFusionTransformer.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlGraphFusionTransformer.cpp index 1b3954de2faa7..4813707cdf50c 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlGraphFusionTransformer.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlGraphFusionTransformer.cpp @@ -7,6 +7,7 @@ #include "GraphPartitioner.h" #include "core/framework/kernel_type_str_resolver.h" #include "core/framework/kernel_lookup.h" +#include "core/optimizer/constant_sharing.h" #include "FusedGraphKernel.h" #include "MLOperatorAuthorImpl.h" #include "DmlGraphFusionHelper.h" @@ -22,12 +23,31 @@ namespace Dml m_providerImpl(static_cast(provider)->GetImpl()) { } - + + struct CompiledPartitionInfo + { + Microsoft::WRL::ComPtr compiledOperator; + onnxruntime::IndexedSubGraph indexedSubGraph; + std::vector isInputsUploadedByDmlEP; + GraphDescBuilder::GraphDesc graphDesc; + std::unordered_map> isInitializerTransferable; + }; + onnxruntime::common::Status DmlGraphFusionTransformer::ApplyImpl( onnxruntime::Graph& graph, bool& modified, int graph_level, const onnxruntime::logging::Logger& logger) const + { + return ApplyImplHelper(graph, modified, graph_level, logger, {}); + } + + onnxruntime::common::Status DmlGraphFusionTransformer::ApplyImplHelper( + onnxruntime::Graph& graph, + bool& modified, + int graph_level, + const onnxruntime::logging::Logger& logger, + const std::unordered_map& implicitInputDefs) const { onnxruntime::ProviderType provider_type = onnxruntime::kDmlExecutionProvider; const gsl::not_null registry = m_providerImpl->GetKernelRegistry().get(); @@ -36,84 +56,198 @@ namespace Dml gsl::make_span(®istry, 1), kernel_type_str_resolver}; - // Initializers needed by any graph partition - std::unordered_set requiredInitializerMap; - std::unordered_map graphNodePropertyMap; - onnxruntime::GraphViewer graphViewer(graph); - std::vector> partitions = BuildPartitions( - graphViewer, - *m_providerImpl->GetInternalRegistrationInfoMap(), - kernel_lookup, - m_providerImpl->GetSupportedDeviceDataTypeMask(), - graphNodePropertyMap, - requiredInitializerMap); - - // Create a map between each initialized tensor and the partition(s) it is part of. - auto initializerPartitionMap = DmlGraphFusionHelper::GetInitializerToPartitionMap(graphViewer, partitions); - - for (uint32_t partitionIndex = 0; partitionIndex < partitions.size(); ++partitionIndex) + std::vector> compiledPartitionInfos; + std::vector additionalSplittingNodes; + + onnxruntime::GraphViewer graph_viewer(graph); + const auto& node_topology_list = graph_viewer.GetNodesInTopologicalOrder(); + + for (auto node_index : node_topology_list) { - auto& partition = partitions[partitionIndex]; + auto* node = graph.GetNode(node_index); + if (!node) + { + continue; // node was removed + } - if (partition->GetRootMergedPartition() != partition.get() || - !partition->IsDmlPartition()) + std::unordered_map subgraphImplicitInputDefs; + for (const onnxruntime::NodeArg* inputDef : node->ImplicitInputDefs()) { - continue; + subgraphImplicitInputDefs[inputDef->Name()] = inputDef; } - // This map will tell which initializer can be removed from onnxruntime::Graph (and from it's field - // onnx::GraphProto) while we upload the initializer to GPU. - // Why we want to remove the initializer from ORT? - // 1. To keep the peak memory usage as low as possible. That's why we are doing incremental upload to GPU. - // What is initializer? - // An initializer is a input tensor to an operator or the graph itself, which is contant and will never change. - // Why are we uploading the initialzer now? - // This prevents OnnxRuntime from allocating GPU resources and uploading those initializers, - // so the partiton's kernel can do so. In the process, it will pre-process weights while consuming a CPU - // backed resource, avoiding an extra set of GPU resources in memory. - std::unordered_map> isInitializerTransferable; - - - if (partition->IsDmlGraphPartition()) + for (auto& entry : node->GetAttributeNameToMutableSubgraphMap()) { - // populate transferredInitializerMap - for (const auto& input : partition->GetInputs()) + auto& subgraph = *entry.second; + ORT_RETURN_IF_ERROR(ApplyImplHelper(subgraph, modified, graph_level + 1, logger, subgraphImplicitInputDefs)); + } + } + + do + { + // Initializers needed by any graph partition + std::unordered_set requiredInitializerMap; + std::unordered_map graphNodePropertyMap; + onnxruntime::GraphViewer graphViewer(graph); + std::vector> partitions = BuildPartitions( + graphViewer, + *m_providerImpl->GetInternalRegistrationInfoMap(), + kernel_lookup, + m_providerImpl->GetSupportedDeviceDataTypeMask(), + graphNodePropertyMap, + requiredInitializerMap, + additionalSplittingNodes, + implicitInputDefs); + + // Reset the splitting nodes for the current iteration + additionalSplittingNodes.clear(); + + // Reset the compiled operators for the current iteration + compiledPartitionInfos.clear(); + compiledPartitionInfos.resize(partitions.size()); + + // Create a map between each initialized tensor and the partition(s) it is part of. + auto initializerPartitionMap = DmlGraphFusionHelper::GetInitializerToPartitionMap(graphViewer, partitions); + + for (uint32_t partitionIndex = 0; partitionIndex < partitions.size(); ++partitionIndex) + { + auto& partition = partitions[partitionIndex]; + + if (partition->GetRootMergedPartition() != partition.get() || + !partition->IsDmlPartition()) { - const onnx::TensorProto* tensor = nullptr; - if (graph.GetInitializedTensor(input, tensor)) + continue; + } + + // This map will tell which initializer can be removed from onnxruntime::Graph (and from it's field + // onnx::GraphProto) while we upload the initializer to GPU. + // Why we want to remove the initializer from ORT? + // 1. To keep the peak memory usage as low as possible. That's why we are doing incremental upload to GPU. + // What is initializer? + // An initializer is a input tensor to an operator or the graph itself, which is contant and will never change. + // Why are we uploading the initialzer now? + // This prevents OnnxRuntime from allocating GPU resources and uploading those initializers, + // so the partiton's kernel can do so. In the process, it will pre-process weights while consuming a CPU + // backed resource, avoiding an extra set of GPU resources in memory. + std::unordered_map> isInitializerTransferable; + + if (partition->IsDmlGraphPartition()) + { + // populate isInitializerTransferable + for (const auto& input : partition->GetInputs()) { - // It's only safe to transfer tensors which are used by this partition alone. - auto iter = initializerPartitionMap.find(tensor); - assert(iter != initializerPartitionMap.end()); - if (iter->second.size() > 1) + const onnx::TensorProto* tensor = nullptr; + if (graph.GetInitializedTensor(input, tensor)) { - if (requiredInitializerMap.find(input) != requiredInitializerMap.end()) + // It's only safe to transfer tensors which are used by this partition alone. + auto iter = initializerPartitionMap.find(tensor); + assert(iter != initializerPartitionMap.end()); + if (iter->second.size() > 1) { - // The kernel relies on this input to be initialized, and it should be small enough to copy - // cheaply. FusedGraphKernel only handles constant CPU inputs through transferred initializers, - // rather than ORT, to avoid mismatches in policy or implementation causing failures. - isInitializerTransferable[input] = {tensor, false}; - } + // By including non-transferrable tensors in isInitializerTransferable, it causes DML to upload and preprocess them + // to duplicate locations rather than treating them as being non-constant, which is helpful for optimization. + // The size threshold for this should be no smaller than that used to combine initializers in the constant + // sharing transform to prevent that transform from hurting performance. + // If the kernel relies on this input to be initialized, it should also be small enough to copy cheaply. + constexpr uint64_t maximumElementsForDuplicationTensor = 64; + static_assert(maximumElementsForDuplicationTensor >= onnxruntime::ConstantSharing::TENSOR_ELEM_COUNT_THRESHOLD); + + uint64_t totalElementCount = 1; + for (int i = 0; i < tensor->dims().size(); ++i) + { + totalElementCount *= tensor->dims()[i]; + } + + if (totalElementCount <= maximumElementsForDuplicationTensor || + requiredInitializerMap.find(input) != requiredInitializerMap.end()) + { + isInitializerTransferable[input] = {tensor, false}; + } - continue; + continue; + } + isInitializerTransferable[input] = {tensor, true}; } - isInitializerTransferable[input] = {tensor, true}; } - } - std::string partitionKernelPrefix = std::to_string(m_providerImpl->GetPartitionKernelPrefixVal()) + "_"; - m_providerImpl->IncreasePartitionKernelPrefixVal(); + std::string partitionKernelPrefix = std::to_string(m_providerImpl->GetPartitionKernelPrefixVal()) + "_"; + m_providerImpl->IncreasePartitionKernelPrefixVal(); + + auto indexedSubGraph = DmlGraphFusionHelper::CreateIndexedSubGraph(partition.get(), partitionIndex, partitionKernelPrefix); + + // Create a map of which inputs are uploaded by the DML EP + const uint32_t fusedNodeInputCount = gsl::narrow_cast(indexedSubGraph.GetMetaDef()->inputs.size()); + std::vector isInputsUploadedByDmlEP(fusedNodeInputCount); + for (uint32_t index = 0; index < fusedNodeInputCount; ++index) + { + auto iter = isInitializerTransferable.find(indexedSubGraph.GetMetaDef()->inputs[index]); + isInputsUploadedByDmlEP[index] = iter != isInitializerTransferable.end() ? true : false; + } + + auto partitionNodePropsMap = DmlGraphFusionHelper::CreatePartitionNodePropsMap( + graph, + indexedSubGraph, + std::move(graphNodePropertyMap)); + + // Convert partitionONNXGraph into DML EP GraphDesc + ComPtr device; + ORT_THROW_IF_FAILED(m_providerImpl->GetDmlDevice(device.GetAddressOf())); + GraphDescBuilder::GraphDesc graphDesc = GraphDescBuilder::BuildGraphDesc( + isInputsUploadedByDmlEP.data(), + isInputsUploadedByDmlEP.size(), + isInitializerTransferable, + graph, + indexedSubGraph, + partitionNodePropsMap, + device.Get(), + m_providerImpl); + + // Compile the operator + auto compiledPartition = DmlGraphFusionHelper::TryCreateCompiledOperator( + graphDesc, + indexedSubGraph, + m_providerImpl); + if (!compiledPartition) + { + // Fail early if even a single operator is too big to compile. This is highly unlikely. + ORT_THROW_HR_IF(E_INVALIDARG, indexedSubGraph.nodes.size() < 2); + + // Tell the partitioner to split the current partition in half, in the middle + additionalSplittingNodes.push_back(indexedSubGraph.nodes[indexedSubGraph.nodes.size() / 2]); + + // Exit early since we need to repartition + break; + } + else + { + auto compiledPartitionInfo = std::make_shared(); + compiledPartitionInfo->compiledOperator = std::move(compiledPartition); + compiledPartitionInfo->indexedSubGraph = std::move(indexedSubGraph); + compiledPartitionInfo->isInputsUploadedByDmlEP = std::move(isInputsUploadedByDmlEP); + compiledPartitionInfo->graphDesc = std::move(graphDesc); + compiledPartitionInfo->isInitializerTransferable = std::move(isInitializerTransferable); + compiledPartitionInfos[partitionIndex] = std::move(compiledPartitionInfo); + } + } + } + } + while (!additionalSplittingNodes.empty()); + + for (auto&& compiledPartitionInfo : compiledPartitionInfos) + { + // Null compiled operators were not DML partitions + if (compiledPartitionInfo) + { DmlGraphFusionHelper::FusePartitionAndRegisterKernel( - partition.get(), - partitionIndex, - graph, - graphNodePropertyMap, + graph, m_providerImpl->GetKernelRegistry().get(), - partitionKernelPrefix, - isInitializerTransferable, - m_providerImpl - ); + compiledPartitionInfo->isInitializerTransferable, + m_providerImpl, + compiledPartitionInfo->indexedSubGraph, + std::move(compiledPartitionInfo->isInputsUploadedByDmlEP), + compiledPartitionInfo->graphDesc, + compiledPartitionInfo->compiledOperator); } } diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlGraphFusionTransformer.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlGraphFusionTransformer.h index b546f29f59719..19dab0c89943c 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlGraphFusionTransformer.h +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/DmlGraphFusionTransformer.h @@ -2,32 +2,41 @@ // Licensed under the MIT License. #pragma once - +#include +#include #include "core/optimizer/graph_transformer.h" #include "core/framework/execution_providers.h" namespace Dml { - class ExecutionProviderImpl; +class ExecutionProviderImpl; + +class DmlGraphFusionTransformer : public onnxruntime::GraphTransformer +{ +public: + DmlGraphFusionTransformer( + const std::string& name, + const onnxruntime::IExecutionProvider* provider + ); + +public: + static inline const char* const DML_GRAPH_FUSION_NODE_NAME_PREFIX = "DmlFusedNode_"; + static inline const char* const DML_GRAPH_FUSION_NODE_DOMAIN = "DmlFusedNodeDomain"; - class DmlGraphFusionTransformer : public onnxruntime::GraphTransformer - { - public: - DmlGraphFusionTransformer( - const std::string& name, - const onnxruntime::IExecutionProvider* provider - ); +private: + onnxruntime::common::Status ApplyImpl(onnxruntime::Graph& graph, + bool& modified, + int graph_level, + const onnxruntime::logging::Logger& logger) const final; - public: - inline const static char* const DML_GRAPH_FUSION_NODE_NAME_PREFIX = "DmlFusedNode_"; - inline const static char* const DML_GRAPH_FUSION_NODE_DOMAIN = "DmlFusedNodeDomain"; + onnxruntime::common::Status ApplyImplHelper( + onnxruntime::Graph& graph, + bool& modified, + int graph_level, + const onnxruntime::logging::Logger& logger, + const std::unordered_map& implicitInputDefs) const; - private: - onnxruntime::common::Status ApplyImpl(onnxruntime::Graph& graph, - bool& modified, - int graph_level, - const onnxruntime::logging::Logger& logger) const final; - private: - const ExecutionProviderImpl* m_providerImpl = nullptr; - }; +private: + const ExecutionProviderImpl* m_providerImpl = nullptr; +}; } diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ExecutionProvider.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ExecutionProvider.cpp index a1f3219d7cbf4..f97b72aa2d385 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ExecutionProvider.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ExecutionProvider.cpp @@ -68,7 +68,7 @@ namespace Dml IDMLDevice* dmlDevice, ID3D12CommandQueue* commandQueue, bool enableMetacommands) : - IExecutionProvider(onnxruntime::kDmlExecutionProvider) + IExecutionProvider(onnxruntime::kDmlExecutionProvider, OrtDevice(OrtDevice::GPU, OrtDevice::MemType::DEFAULT, 0)) { D3D12_COMMAND_LIST_TYPE queueType = commandQueue->GetDesc().Type; if (queueType != D3D12_COMMAND_LIST_TYPE_DIRECT && queueType != D3D12_COMMAND_LIST_TYPE_COMPUTE) @@ -81,11 +81,6 @@ namespace Dml GRAPHICS_THROW_IF_FAILED(commandQueue->GetDevice(IID_GRAPHICS_PPV_ARGS(device.GetAddressOf()))); m_impl = wil::MakeOrThrow(dmlDevice, device.Get(), commandQueue, enableMetacommands); - - // Register the allocators with ORT, through concrete ORT methods on the IExecutionProvider base class - InsertAllocator(m_impl->GetGpuAllocator()); - InsertAllocator(m_impl->GetCpuInputAllocator()); - InsertAllocator(m_impl->GetCpuOutputAllocator()); } std::vector> @@ -189,27 +184,32 @@ namespace Dml m_context = std::make_shared(m_d3d12Device.Get(), m_dmlDevice.Get(), queue); - // Create an allocator for D3D12 buffers used to hold tensor data. The returned buffers from the allocator - // should be DEFAULT heap buffers which can be used as UAVs, and which start in UAV state. - m_allocator = std::make_shared( - m_d3d12Device.Get(), - m_context, - CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), - D3D12_HEAP_FLAG_NONE, - D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, - D3D12_RESOURCE_STATE_UNORDERED_ACCESS, - std::make_unique(m_d3d12Device.Get())); - - m_context->SetAllocator(m_allocator); - m_uploadHeap = std::make_unique(m_d3d12Device.Get(), m_context); m_readbackHeap = std::make_unique(m_d3d12Device.Get(), m_context); - // CPU Allocator used to create buffers for the MemcpyFromHost, Shape and Size operators. - m_cpuInputAllocator = std::make_shared(OrtMemType::OrtMemTypeCPUInput); - m_cpuOutputAllocator = std::make_shared(OrtMemType::OrtMemTypeCPUOutput); - CreateDmlKernelRegistry(&m_kernelRegistry, &m_internalRegInfoMap); + + m_lastUploadFlushTime = std::chrono::steady_clock::now(); + } + + std::vector ExecutionProviderImpl::CreatePreferredAllocators() { + if (!m_allocator) + { + // Create an allocator for D3D12 buffers used to hold tensor data. The returned buffers from the allocator + // should be DEFAULT heap buffers which can be used as UAVs, and which start in UAV state. + m_allocator = std::make_shared(m_d3d12Device.Get(), + m_context, // TODO(leca): REVIEW: Will it cause memory issue when m_context is released in EP while alloc is released in sessionState? + CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), + D3D12_HEAP_FLAG_NONE, + D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS, + std::make_unique(m_d3d12Device.Get())); + m_context->SetAllocator(m_allocator); + // CPU Allocator used to create buffers for the MemcpyFromHost, Shape and Size operators. + m_cpuInputAllocator = std::make_shared(OrtMemType::OrtMemTypeCPUInput); + } + + return std::vector{m_allocator, m_cpuInputAllocator,}; } HRESULT __stdcall ExecutionProviderImpl::GetD3DDevice(_COM_Outptr_ ID3D12Device** d3dDevice) const noexcept @@ -447,6 +447,7 @@ namespace Dml const auto dstState = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; // GPU resources are always kept in UAV state m_uploadHeap->BeginUploadToGpu(dstData, dstOffset, dstState, AsByteSpan(srcData, dataSizeInBytes)); + FlushUploadsIfReady(); } else if (!src->IsCpuData() && dst->IsCpuData()) { @@ -566,12 +567,23 @@ namespace Dml assert(!m_closed); m_uploadHeap->BeginUploadToGpu(dstData, 0, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, AsByteSpan(srcData, static_cast(srcDataSize))); + FlushUploadsIfReady(); return S_OK; } ORT_CATCH_RETURN } + void ExecutionProviderImpl::FlushUploadsIfReady() const + { + // Periodically flush uploads to make sure the GPU is not idle for too long + if (std::chrono::steady_clock::now() - m_lastUploadFlushTime > m_batchFlushInterval) + { + Flush(); + m_lastUploadFlushTime = std::chrono::steady_clock::now(); + } + } + uint32_t ExecutionProviderImpl::GetSupportedDeviceDataTypeMask() const { // The DML provider registers all supported kernels up-front regardless of actual device capability, @@ -624,18 +636,20 @@ namespace Dml bool IsCpuOnDmlOperator(const onnxruntime::Node& node) { - auto sequence_ops = std::array{ + auto cpuOnDmlOperators = std::array{ "SequenceAt", "SequenceConstruct", "SequenceEmpty", "SequenceLength", "SequenceErase", - "SequenceInsert" + "SequenceInsert", + "OptionalGetElement", + "OptionalHasElement" }; - for (auto& sequence_op : sequence_ops) + for (auto& cpuOnDmlOperator : cpuOnDmlOperators) { - if (strcmp(sequence_op, node.OpType().c_str()) == 0) + if (strcmp(cpuOnDmlOperator, node.OpType().c_str()) == 0) { return true; } @@ -661,9 +675,10 @@ namespace Dml bool IsCustomOpShader(const onnxruntime::Node& node) { - auto custom_ops = std::array{ + auto custom_ops = std::array{ "DFT", - "STFT" + "STFT", + "GridSample" }; for (auto& custom_op : custom_ops) @@ -947,11 +962,6 @@ namespace Dml m_context->Flush(); } - void ExecutionProviderImpl::SetDefaultRoundingMode(AllocatorRoundingMode roundingMode) - { - m_allocator->SetDefaultRoundingMode(roundingMode); - } - void ExecutionProviderImpl::ReleaseCompletedReferences() { m_context->ReleaseCompletedReferences(); @@ -1099,12 +1109,6 @@ namespace Dml return m_cpuInputAllocator; } - std::shared_ptr ExecutionProviderImpl::GetCpuOutputAllocator() - { - return m_cpuOutputAllocator; - } - - onnxruntime::common::Status ExecutionProviderImpl::OnSessionInitializationEnd() { // Flush and trim resources, including staging memory used to upload weights. @@ -1115,6 +1119,10 @@ namespace Dml m_context->ReleaseCompletedReferences(); m_uploadHeap->Trim(); + // Allocations after this point are potentially transient and their sizes are + // rounded to enable pooling. + m_allocator->SetDefaultRoundingMode(AllocatorRoundingMode::Enabled); + return onnxruntime::common::Status::OK(); } @@ -1138,12 +1146,6 @@ namespace Dml dmlexecutionprovider->Flush(); } - void SetDefaultRoundingMode(onnxruntime::IExecutionProvider* provider, AllocatorRoundingMode roundingMode) - { - ExecutionProvider* dmlexecutionprovider = static_cast(provider); - dmlexecutionprovider->SetDefaultRoundingMode(roundingMode); - } - void ReleaseCompletedReferences(onnxruntime::IExecutionProvider * provider) { ExecutionProvider* dmlexecutionprovider = static_cast(provider); diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ExecutionProvider.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ExecutionProvider.h index b9ac772095fb3..31b893a2f25d7 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ExecutionProvider.h +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ExecutionProvider.h @@ -126,8 +126,6 @@ namespace Dml STDMETHOD_(D3D12_COMMAND_LIST_TYPE, GetCommandListTypeForQueue)() const override; STDMETHOD_(void, Flush)() const override; - void SetDefaultRoundingMode(AllocatorRoundingMode roundingMode); - // Waits for flushed work, discards unflushed work, and discards associated references to // prevent circular references. Must be the last call on the object before destruction. void Close() override; @@ -154,7 +152,6 @@ namespace Dml STDMETHOD_(bool, MetacommandsEnabled)() const noexcept final; std::shared_ptr GetGpuAllocator(); std::shared_ptr GetCpuInputAllocator(); - std::shared_ptr GetCpuOutputAllocator(); std::shared_ptr GetInternalRegistrationInfoMap() const; @@ -170,6 +167,7 @@ namespace Dml } onnxruntime::common::Status OnSessionInitializationEnd(); + std::vector CreatePreferredAllocators(); private: void Initialize(ID3D12CommandQueue* queue, ExecutionProvider& executionProvider); @@ -180,6 +178,8 @@ namespace Dml uint32_t supportedDeviceDataTypeMask // Each bit corresponds to each DML_TENSOR_DATA_TYPE. ) const; + void FlushUploadsIfReady() const; + ComPtr m_d3d12Device; ComPtr m_dmlDevice; bool m_isMcdmDevice = false; @@ -190,11 +190,12 @@ namespace Dml std::unique_ptr m_readbackHeap; std::shared_ptr m_allocator; std::shared_ptr m_cpuInputAllocator; - std::shared_ptr m_cpuOutputAllocator; std::shared_ptr m_kernelRegistry; std::shared_ptr m_internalRegInfoMap; mutable uint64_t m_partitionKernelPrefixVal = 0; bool m_closed = false; + mutable std::chrono::time_point m_lastUploadFlushTime; + static constexpr std::chrono::milliseconds m_batchFlushInterval = std::chrono::milliseconds(10); }; class DataTransfer : public onnxruntime::IDataTransfer @@ -283,11 +284,6 @@ namespace Dml return m_impl->Flush(); } - void SetDefaultRoundingMode(AllocatorRoundingMode roundingMode) - { - return m_impl->SetDefaultRoundingMode(roundingMode); - } - void ReleaseCompletedReferences() { return m_impl->ReleaseCompletedReferences(); @@ -308,6 +304,11 @@ namespace Dml m_impl->MetacommandsEnabled(); } + virtual std::vector CreatePreferredAllocators() override + { + return m_impl->CreatePreferredAllocators(); + } + private: ComPtr m_impl; }; diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/External/DirectMLHelpers/ApiHelpers.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/External/DirectMLHelpers/ApiHelpers.h index 76ca37bd054e7..9a1c23093f9b9 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/External/DirectMLHelpers/ApiHelpers.h +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/External/DirectMLHelpers/ApiHelpers.h @@ -183,13 +183,13 @@ class StackAllocator static T RoundUpToMultiple(T value, T multiple) { static_assert(std::is_integral_v); - + T remainder = value % multiple; if (remainder != 0) { value += multiple - remainder; } - + return value; } @@ -231,4 +231,4 @@ class StackAllocator // allocated memory if the fixed stack array is exhausted. FixedBucket m_fixed; std::deque m_dynamic; -}; \ No newline at end of file +}; diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/External/DirectMLHelpers/ApiTraits.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/External/DirectMLHelpers/ApiTraits.h index 8b5cf3693757a..c75b662af788d 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/External/DirectMLHelpers/ApiTraits.h +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/External/DirectMLHelpers/ApiTraits.h @@ -1155,6 +1155,11 @@ struct OperatorDescTraits static constexpr DML_OPERATOR_TYPE Type = DML_OPERATOR_ACTIVATION_GELU; }; +template <> +struct OperatorDescTraits +{ + static constexpr DML_OPERATOR_TYPE Type = DML_OPERATOR_MULTIHEAD_ATTENTION; +}; template struct OperatorTypeTraits @@ -2139,14 +2144,20 @@ struct OperatorTypeTraits<(DML_OPERATOR_TYPE)DML_OPERATOR_ACTIVATION_GELU> using DescType = DML_ACTIVATION_GELU_OPERATOR_DESC; }; +template <> +struct OperatorTypeTraits<(DML_OPERATOR_TYPE)DML_OPERATOR_MULTIHEAD_ATTENTION> +{ + using DescType = DML_MULTIHEAD_ATTENTION_OPERATOR_DESC; +}; + // Calls a visitor functor, supplying an empty operator desc corresponding to the given DML_OPERATOR_TYPE as // the first argument. -// +// // For example: // Visit(DML_OPERATOR_ELEMENT_WISE_IDENTITY, [](auto tag) { // using T = decltype(tag); // T is one of the DML_*_OPERATOR_DESC structs // }); -// +// #pragma warning(push) #pragma warning(disable:4702) template @@ -2432,6 +2443,8 @@ auto OperatorTypeVisitor(DML_OPERATOR_TYPE type, Visitor&& visitor, Ts&&... args return std::invoke(std::forward(visitor), DML_RESAMPLE_GRAD1_OPERATOR_DESC{}, std::forward(args)...); case DML_OPERATOR_DIAGONAL_MATRIX1: return std::invoke(std::forward(visitor), DML_DIAGONAL_MATRIX1_OPERATOR_DESC{}, std::forward(args)...); + case DML_OPERATOR_MULTIHEAD_ATTENTION: + return std::invoke(std::forward(visitor), DML_MULTIHEAD_ATTENTION_OPERATOR_DESC{}, std::forward(args)...); case DML_OPERATOR_ACTIVATION_ELU: return std::invoke(std::forward(visitor), DML_ACTIVATION_ELU_OPERATOR_DESC{}, std::forward(args)...); case DML_OPERATOR_ACTIVATION_CELU: @@ -2633,6 +2646,7 @@ inline gsl::czstring ToString(DML_OPERATOR_TYPE value) case DML_OPERATOR_RESAMPLE2: return "DML_OPERATOR_RESAMPLE2"; case DML_OPERATOR_RESAMPLE_GRAD1: return "DML_OPERATOR_RESAMPLE_GRAD1"; case DML_OPERATOR_DIAGONAL_MATRIX1: return "DML_OPERATOR_DIAGONAL_MATRIX1"; + case DML_OPERATOR_MULTIHEAD_ATTENTION: return "DML_OPERATOR_MULTIHEAD_ATTENTION"; default: assert(false); return ""; diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/External/DirectMLHelpers/DirectMLSchema.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/External/DirectMLHelpers/DirectMLSchema.h index 42de619a877f2..1ebd52d4ed427 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/External/DirectMLHelpers/DirectMLSchema.h +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/External/DirectMLHelpers/DirectMLSchema.h @@ -2302,6 +2302,35 @@ constexpr DML_OPERATOR_SCHEMA DML_DIAGONAL_MATRIX1_OPERATOR_SCHEMA{ DML_DIAGONAL_MATRIX1_OPERATOR_SCHEMA_FIELDS, }; +constexpr DML_SCHEMA_FIELD DML_MULTIHEAD_ATTENTION_OPERATOR_SCHEMA_FIELDS[18] { + DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "QueryTensor", true }, + DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "KeyTensor", true }, + DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "ValueTensor", true }, + DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "StackedQueryKeyTensor", true }, + DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "StackedKeyValueTensor", true }, + DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "StackedQueryKeyValueTensor", true }, + DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "BiasTensor", true }, + DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "MaskTensor", true }, + DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "RelativePositionBiasTensor", true }, + DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "PastKeyTensor", true }, + DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "PastValueTensor", true }, + DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_OUTPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "OutputTensor", false }, + DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_OUTPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "OutputPresentKeyTensor", true }, + DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_OUTPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "OutputPresentValueTensor", true }, + DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_ATTRIBUTE, DML_SCHEMA_FIELD_TYPE_FLOAT, "Scale", false }, + DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_ATTRIBUTE, DML_SCHEMA_FIELD_TYPE_FLOAT, "MaskFilterValue", false }, + DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_ATTRIBUTE, DML_SCHEMA_FIELD_TYPE_UINT, "HeadCount", false }, + DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_ATTRIBUTE, DML_SCHEMA_FIELD_TYPE_UINT, "MaskType", false }, +}; + +constexpr DML_OPERATOR_SCHEMA DML_MULTIHEAD_ATTENTION_OPERATOR_SCHEMA { + "DML_OPERATOR_MULTIHEAD_ATTENTION", + DML_OPERATOR_MULTIHEAD_ATTENTION, + DML_SCHEMA_OPERATOR_SUPPORT_FLAG_NONE, + 18, + DML_MULTIHEAD_ATTENTION_OPERATOR_SCHEMA_FIELDS, +}; + constexpr DML_SCHEMA_FIELD DML_ACTIVATION_ELU_OPERATOR_SCHEMA_FIELDS[3] { DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "InputTensor", false }, DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_OUTPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "OutputTensor", false }, diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/External/DirectMLHelpers/DirectMLX.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/External/DirectMLHelpers/DirectMLX.h index f7feb5ff2165e..7e050eef50026 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/External/DirectMLHelpers/DirectMLX.h +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/External/DirectMLHelpers/DirectMLX.h @@ -202,7 +202,7 @@ namespace dml }; } -#if DMLX_USE_ABSEIL +#if DMLX_USE_ABSEIL template using Optional = absl::optional; @@ -231,7 +231,7 @@ namespace dml #elif DMLX_USE_GSL template using Span = gsl::span; - #else + #else template using Span = dml::detail::span; #endif @@ -245,11 +245,11 @@ namespace dml #define DMLX_THROW(_hr) THROW_HR(_hr) #else #define DMLX_THROW_IF_FAILED(_hr) if (FAILED(_hr)) { throw std::runtime_error(#_hr); } - #define DMLX_THROW(_hr) throw std::runtime_error(#_hr); + #define DMLX_THROW(_hr) throw std::runtime_error(#_hr); #endif #else #define DMLX_THROW_IF_FAILED(_hr) if (FAILED(_hr)) { std::abort(); } - #define DMLX_THROW(_hr) { std::abort(); } + #define DMLX_THROW(_hr) { std::abort(); } #endif class Graph; @@ -307,7 +307,7 @@ namespace dml // (0, 2, ..., n, 1). This is often referred to as "NHWC" or "interleaved channel" layout. This is useful, // for example, when applied to 2D Convolution to produce outputs in an NHWC layout (as opposed to NCHW, which // is the DirectML default for 2D Convolution). - // + // // Examples of the transposes produced by this policy: // NCW -> NWC // NCHW -> NHWC @@ -713,7 +713,7 @@ namespace dml // Represents an activation to be fused with an existing operator. The meaning of param1 and param2 depend on the // activation to be fused. - // + // // For HARD_SIGMOID, LINEAR, PARAMETRIC_SOFTPLUS, and SCALED_TANH: param1 = Alpha and param2 = Beta // For ELU, LEAKY_RELU, THRESHOLDED_RELU, and CELU: param1 = Alpha. param2 is unused. // For SCALED_ELU, param1 = Alpha and param2 = Gamma. @@ -1858,13 +1858,13 @@ namespace dml } // Helper for setting parameters for the Convolution operator. Sample usage: - // + // // auto conv = dml::ConvolutionBuilder(...) // .StartPadding(...) // .EndPadding(...) // .Strides(...) // .Build(); - // + // // Parameters left unspecified will be defaulted with the same values as dml::Convolution(). class ConvolutionBuilder { @@ -2114,9 +2114,9 @@ namespace dml return output; } - // + // // TODO: LpPooling - // + // // --------------------------------------------------------------------------------------------------------------- @@ -2203,13 +2203,13 @@ namespace dml } // Helper for setting parameters for the MaxPooling operator. Sample usage: - // + // // auto [out, outIndices] = dml::MaxPoolingBuilder(...) // .StartPadding(...) // .EndPadding(...) // .OutputIndices(...) // .Build(); - // + // // Parameters left unspecified will be defaulted with the same values as dml::MaxPooling(). class MaxPoolingBuilder { @@ -2251,13 +2251,13 @@ namespace dml // --------------------------------------------------------------------------------------------------------------- - // + // // TODO: MaxUnpooling - // + // - // + // // TODO: ROIPooling - // + // inline Expression Slice( Expression input, @@ -2683,7 +2683,7 @@ namespace dml { detail::GraphBuilder* builder = input.Impl()->GetGraphBuilder(); TensorDesc inputTensor = input.Impl()->GetOutputDesc(); - + assert(inputTensor.sizes.size() == 4); dml::TensorDesc::Dimensions outputSizes = { @@ -2691,7 +2691,7 @@ namespace dml inputTensor.sizes[1] * blockSize * blockSize, inputTensor.sizes[2] / blockSize, inputTensor.sizes[3] / blockSize - }; + }; TensorDesc outputTensor(inputTensor.dataType, outputSizes, builder->GetTensorPolicy()); @@ -2715,7 +2715,7 @@ namespace dml { detail::GraphBuilder* builder = input.Impl()->GetGraphBuilder(); TensorDesc inputTensor = input.Impl()->GetOutputDesc(); - + assert(inputTensor.sizes.size() == 4); dml::TensorDesc::Dimensions outputSizes = { @@ -2771,7 +2771,7 @@ namespace dml struct TopKOutputs { Expression value; - Expression index; + Expression index; }; inline TopKOutputs TopK(Expression input, uint32_t axis, uint32_t k, DML_AXIS_DIRECTION axisDirection) @@ -2909,14 +2909,14 @@ namespace dml desc.VarianceTensor = varianceTensor.AsPtr(); desc.ScaleTensor = scaleTensor.AsPtr(); desc.Epsilon = epsilon; - + desc.OutputGradientTensor = outputGradientTensor.AsPtr(); desc.OutputScaleGradientTensor = outputScaleGradientTensor.AsPtr(); desc.OutputBiasGradientTensor = outputBiasGradientTensor.AsPtr(); - + dml::detail::NodeOutput* const inputs[] = { input.Impl(), inputGradient.Impl(), mean.Impl(), variance.Impl(), scale.Impl() }; dml::detail::NodeID node = builder->CreateOperatorNode(DML_OPERATOR_BATCH_NORMALIZATION_GRAD, &desc, inputs); - + BatchNormalizationGradOutputs outputValues; outputValues.gradient = builder->CreateNodeOutput(node, 0, *desc.OutputGradientTensor); outputValues.scaleGradient = builder->CreateNodeOutput(node, 1, *desc.OutputScaleGradientTensor); @@ -2932,7 +2932,7 @@ namespace dml { Expression output; Expression mean; - Expression variance; + Expression variance; }; inline BatchNormalizationTrainingOutputs BatchNormalizationTraining( @@ -3005,14 +3005,14 @@ namespace dml desc.VarianceTensor = varianceTensor.AsPtr(); desc.ScaleTensor = scaleTensor.AsPtr(); desc.Epsilon = epsilon; - + desc.OutputGradientTensor = outputGradientTensor.AsPtr(); desc.OutputScaleGradientTensor = outputScaleGradientTensor.AsPtr(); desc.OutputBiasGradientTensor = outputBiasGradientTensor.AsPtr(); - + dml::detail::NodeOutput* const inputs[] = { input.Impl(), inputGradient.Impl(), mean.Impl(), variance.Impl(), scale.Impl() }; dml::detail::NodeID node = builder->CreateOperatorNode(DML_OPERATOR_BATCH_NORMALIZATION_TRAINING_GRAD, &desc, inputs); - + BatchNormalizationGradOutputs outputValues; outputValues.gradient = builder->CreateNodeOutput(node, 0, *desc.OutputGradientTensor); outputValues.scaleGradient = builder->CreateNodeOutput(node, 1, *desc.OutputScaleGradientTensor); @@ -3099,17 +3099,17 @@ namespace dml return output; } - // + // // TODO: LpNormalization - // + // - // + // // TODO: RNN - // + // - // + // // TODO: LSTM - // + // enum class GRUOutputOptions { @@ -3121,7 +3121,7 @@ namespace dml struct GRUOutputs { Expression sequence; - Expression single; + Expression single; }; inline GRUOutputs GRU( @@ -3230,7 +3230,7 @@ namespace dml return { outputSequenceExpr, outputSingleExpr }; } - // + // // TODO: DiagonalMatrix // @@ -3442,33 +3442,33 @@ namespace dml return output; } - // + // // TODO: MatrixMultiplyInteger - // + // - // + // // TODO: QuantizedLinearMatrixMultiply - // + // - // + // // TODO: ConvolutionInteger - // + // - // + // // TODO: QuantizedLinearConvolution - // + // - // + // // TODO: ReluGrad - // + // - // + // // TODO: AveragePoolingGrad - // + // - // + // // TODO: MaxPoolingGrad - // + // struct RandomGeneratorOutputs { @@ -3496,7 +3496,7 @@ namespace dml // Input and output state have the same TensorDesc. desc.OutputStateTensor = inputStateTensor.AsPtr(); } - + RandomGeneratorOutputs out; detail::NodeOutput* const inputs[] = { inputState.Impl() }; @@ -3537,7 +3537,7 @@ namespace dml desc.InputTensor = inputTensor.AsPtr(); desc.OutputCountTensor = outputCountTensor.AsPtr(); desc.OutputCoordinatesTensor = outputCoordinatesTensor.AsPtr(); - + NonZeroCoordinatesOutputs output; detail::NodeOutput* const inputs[] = { input.Impl() }; @@ -3640,17 +3640,17 @@ namespace dml return output; } - // + // // TODO: AdamOptimizer - // + // - // + // // TODO: Argmin - // + // - // + // // TODO: Argmax - // + // #if DML_TARGET_VERSION >= 0x4000 @@ -3694,7 +3694,7 @@ namespace dml desc.ROITensor = roiTensor.AsPtr(); desc.BatchIndicesTensor = batchIndicesTensor.AsPtr(); desc.OutputTensor = outputTensor.AsPtr(); - desc.ReductionFunction = reductionFunction; + desc.ReductionFunction = reductionFunction; desc.InterpolationMode = interpolationMode; desc.SpatialScaleX = spatialScaleX; desc.SpatialScaleY = spatialScaleY; @@ -3763,7 +3763,7 @@ namespace dml outputGradientTensor = TensorDesc(inputGradientTensor.dataType, outputGradientSizes, builder->GetTensorPolicy()); } - + TensorDesc outputROIGradientTensor = computeOutputROIGradient ? TensorDesc(roiTensor.dataType, roiTensor.sizes, builder->GetTensorPolicy()) : TensorDesc(); assert(!computeOutputROIGradient || outputROIGradientTensor.sizes == roiTensor.sizes); @@ -3774,7 +3774,7 @@ namespace dml desc.BatchIndicesTensor = batchIndicesTensor.AsPtr(); desc.OutputGradientTensor = computeOutputGradient ? outputGradientTensor.AsPtr() : nullptr; desc.OutputROIGradientTensor = computeOutputROIGradient ? outputROIGradientTensor.AsPtr() : nullptr; - desc.ReductionFunction = reductionFunction; + desc.ReductionFunction = reductionFunction; desc.InterpolationMode = interpolationMode; desc.SpatialScaleX = spatialScaleX; desc.SpatialScaleY = spatialScaleY; diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/External/DirectMLHelpers/GeneratedSchemaHelpers.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/External/DirectMLHelpers/GeneratedSchemaHelpers.h index aaf02ca146f02..833871de0bbd9 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/External/DirectMLHelpers/GeneratedSchemaHelpers.h +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/External/DirectMLHelpers/GeneratedSchemaHelpers.h @@ -1418,6 +1418,29 @@ inline std::vector GetFields(const DML_DIAGONAL_MATRIX1_OPERATOR_ OperatorField(&DML_DIAGONAL_MATRIX1_OPERATOR_SCHEMA.Fields[5], ToOperatorFieldType(static_cast(desc.DiagonalFillEnd))), }; } +inline std::vector GetFields(const DML_MULTIHEAD_ATTENTION_OPERATOR_DESC& desc) +{ + return { + OperatorField(&DML_MULTIHEAD_ATTENTION_OPERATOR_SCHEMA.Fields[0], ToOperatorFieldType(static_cast(desc.QueryTensor))), + OperatorField(&DML_MULTIHEAD_ATTENTION_OPERATOR_SCHEMA.Fields[1], ToOperatorFieldType(static_cast(desc.KeyTensor))), + OperatorField(&DML_MULTIHEAD_ATTENTION_OPERATOR_SCHEMA.Fields[2], ToOperatorFieldType(static_cast(desc.ValueTensor))), + OperatorField(&DML_MULTIHEAD_ATTENTION_OPERATOR_SCHEMA.Fields[3], ToOperatorFieldType(static_cast(desc.StackedQueryKeyTensor))), + OperatorField(&DML_MULTIHEAD_ATTENTION_OPERATOR_SCHEMA.Fields[4], ToOperatorFieldType(static_cast(desc.StackedKeyValueTensor))), + OperatorField(&DML_MULTIHEAD_ATTENTION_OPERATOR_SCHEMA.Fields[5], ToOperatorFieldType(static_cast(desc.StackedQueryKeyValueTensor))), + OperatorField(&DML_MULTIHEAD_ATTENTION_OPERATOR_SCHEMA.Fields[6], ToOperatorFieldType(static_cast(desc.BiasTensor))), + OperatorField(&DML_MULTIHEAD_ATTENTION_OPERATOR_SCHEMA.Fields[7], ToOperatorFieldType(static_cast(desc.MaskTensor))), + OperatorField(&DML_MULTIHEAD_ATTENTION_OPERATOR_SCHEMA.Fields[8], ToOperatorFieldType(static_cast(desc.RelativePositionBiasTensor))), + OperatorField(&DML_MULTIHEAD_ATTENTION_OPERATOR_SCHEMA.Fields[9], ToOperatorFieldType(static_cast(desc.PastKeyTensor))), + OperatorField(&DML_MULTIHEAD_ATTENTION_OPERATOR_SCHEMA.Fields[10], ToOperatorFieldType(static_cast(desc.PastValueTensor))), + OperatorField(&DML_MULTIHEAD_ATTENTION_OPERATOR_SCHEMA.Fields[11], ToOperatorFieldType(static_cast(desc.OutputTensor))), + OperatorField(&DML_MULTIHEAD_ATTENTION_OPERATOR_SCHEMA.Fields[12], ToOperatorFieldType(static_cast(desc.OutputPresentKeyTensor))), + OperatorField(&DML_MULTIHEAD_ATTENTION_OPERATOR_SCHEMA.Fields[13], ToOperatorFieldType(static_cast(desc.OutputPresentValueTensor))), + OperatorField(&DML_MULTIHEAD_ATTENTION_OPERATOR_SCHEMA.Fields[14], ToOperatorFieldType(static_cast(desc.Scale))), + OperatorField(&DML_MULTIHEAD_ATTENTION_OPERATOR_SCHEMA.Fields[15], ToOperatorFieldType(static_cast(desc.MaskFilterValue))), + OperatorField(&DML_MULTIHEAD_ATTENTION_OPERATOR_SCHEMA.Fields[16], ToOperatorFieldType(static_cast(desc.HeadCount))), + OperatorField(&DML_MULTIHEAD_ATTENTION_OPERATOR_SCHEMA.Fields[17], ToOperatorFieldType(static_cast(desc.MaskType))), + }; +} inline std::vector GetFields(const DML_ACTIVATION_ELU_OPERATOR_DESC& desc) { return { @@ -1753,6 +1776,7 @@ inline const DML_OPERATOR_SCHEMA& GetSchema(DML_OPERATOR_TYPE operatorType) case DML_OPERATOR_RESAMPLE2: return DML_RESAMPLE2_OPERATOR_SCHEMA; case DML_OPERATOR_RESAMPLE_GRAD1: return DML_RESAMPLE_GRAD1_OPERATOR_SCHEMA; case DML_OPERATOR_DIAGONAL_MATRIX1: return DML_DIAGONAL_MATRIX1_OPERATOR_SCHEMA; + case DML_OPERATOR_MULTIHEAD_ATTENTION: return DML_MULTIHEAD_ATTENTION_OPERATOR_SCHEMA; case DML_OPERATOR_ACTIVATION_ELU: return DML_ACTIVATION_ELU_OPERATOR_SCHEMA; case DML_OPERATOR_ACTIVATION_CELU: return DML_ACTIVATION_CELU_OPERATOR_SCHEMA; case DML_OPERATOR_ACTIVATION_HARDMAX: return DML_ACTIVATION_HARDMAX_OPERATOR_SCHEMA; @@ -2346,6 +2370,10 @@ inline AbstractOperatorDesc ConvertOperatorDesc(const DML_OPERATOR_DESC& opDesc) return AbstractOperatorDesc( &DML_DIAGONAL_MATRIX1_OPERATOR_SCHEMA, GetFields(*static_cast(opDesc.Desc))); + case DML_OPERATOR_MULTIHEAD_ATTENTION: + return AbstractOperatorDesc( + &DML_MULTIHEAD_ATTENTION_OPERATOR_SCHEMA, + GetFields(*static_cast(opDesc.Desc))); case DML_OPERATOR_ACTIVATION_ELU: return AbstractOperatorDesc( &DML_ACTIVATION_ELU_OPERATOR_SCHEMA, diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/FusedGraphKernel.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/FusedGraphKernel.cpp index b7f24d49d19da..67c3f110e5a50 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/FusedGraphKernel.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/FusedGraphKernel.cpp @@ -24,13 +24,13 @@ namespace Dml std::vector>& nonOwnedGraphInputsFromInitializers, std::vector>& initializeResourceRefs, std::vector initInputBindings, - std::vector& isInputsUploadedByDmlEP, - std::vector& inputsUsed) : + std::vector&& isInputsUploadedByDmlEP, + std::vector&& inputsUsed) : OpKernel(kernelInfo), m_compiledExecutionPlanOperator(compiledExecutionPlanOperator), - m_inputsUsed(inputsUsed), + m_inputsUsed(std::move(inputsUsed)), m_outputShapes(outputShapes), - m_isInputsUploadedByDmlEP(isInputsUploadedByDmlEP), + m_isInputsUploadedByDmlEP(std::move(isInputsUploadedByDmlEP)), m_nonOwnedGraphInputsFromInitializers(nonOwnedGraphInputsFromInitializers) { // Get the execution provider interfaces @@ -443,8 +443,8 @@ namespace Dml std::vector>& nonOwnedGraphInputsFromInitializers, std::vector>& initializeResourceRefs, std::vector initInputBindings, - std::vector& isInputsUploadedByDmlEP, - std::vector& inputsUsed + std::vector&& isInputsUploadedByDmlEP, + std::vector&& inputsUsed ) { return new FusedGraphKernel( @@ -455,8 +455,8 @@ namespace Dml nonOwnedGraphInputsFromInitializers, initializeResourceRefs, initInputBindings, - isInputsUploadedByDmlEP, - inputsUsed + std::move(isInputsUploadedByDmlEP), + std::move(inputsUsed) ); } } // namespace Dml diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/FusedGraphKernel.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/FusedGraphKernel.h index 00a858d54e5ec..ced6160a99784 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/FusedGraphKernel.h +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/FusedGraphKernel.h @@ -15,7 +15,7 @@ namespace Dml std::vector>& nonOwnedGraphInputsFromInitializers, std::vector>& initializeResourceRefs, std::vector initInputBindings, - std::vector& isInputsUploadedByDmlEP, - std::vector& inputsUsed + std::vector&& isInputsUploadedByDmlEP, + std::vector&& inputsUsed ); } // namespace Dml diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/GraphPartitioner.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/GraphPartitioner.cpp index b9c5f8849a2fb..18943878ccedc 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/GraphPartitioner.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/GraphPartitioner.cpp @@ -209,14 +209,15 @@ namespace Dml // Creates a partition for a node which is not a DML graph node, and finalizes partitions // which are inputs of the new partition. - std::unique_ptr CreateNonGraphNodePartitionAndFinalizeInputs( + std::unique_ptr CreatePartitionAndFinalizeInputs( const onnxruntime::Node& node, bool isDmlNode, + bool isDmlGraphPartitionNode, std::unordered_map& nodeNameToPartitionMap ) { std::unique_ptr partition = std::make_unique(); - partition->SetIsDmlGraphPartition(false); + partition->SetIsDmlGraphPartition(isDmlGraphPartitionNode); partition->SetIsDmlPartition(isDmlNode); partition->AddNodeIndex(node.Index()); @@ -344,13 +345,8 @@ namespace Dml // Whether any operator in the model contains a subgraph. This is true // if the graph being partitioned is itself within a subgraph, or contains // an operator with a subgraph. - bool ModelUsesSubgraph(const onnxruntime::GraphViewer& graph) + bool ContainsSubgraph(const onnxruntime::GraphViewer& graph) { - if (graph.IsSubgraph()) - { - return true; - } - const std::vector& toplogicalOrder = graph.GetNodesInTopologicalOrder(); for (size_t nodeIndex : toplogicalOrder) @@ -383,7 +379,8 @@ namespace Dml uint32_t supportedDeviceDataTypeMask, // Each bit corresponds to each DML_TENSOR_DATA_TYPE. std::unordered_map& graphNodePropertyMap, std::unordered_set& requiredInitializerMap, - std::function onNodeUnsupportedInGraph) + gsl::span additionalSplittingNodes, + const std::unordered_map& implicitInputs) { // Nodes are uniquely identified by the name of their first output argument std::vector> partitions; @@ -418,7 +415,9 @@ namespace Dml } // Check whether this graph is a subgraph, or contains any node with a subgraph. - bool modelUsesSubgraph = ModelUsesSubgraph(graph); + bool containsSubgraph = ContainsSubgraph(graph); + + uint32_t splittingNodeIndex = 0; // Build up partitions while traversing the graph. for (size_t nodeIndex : toplogicalOrder) @@ -451,17 +450,19 @@ namespace Dml // Add a unique partition if graph node usage is not supported. // // Partitioning is disabled in models with subgraphs to work around issues with implicit inputs. - // The partitioning algorithm does not currently consider such inputs. Transfering shared initializers + // The partitioning algorithm does not currently consider such inputs. Transferring shared initializers // for partitions could also cause problems. Note, operators with subgraphs are currently not efficient // anyhow due to CPU/GPU copies. - if (modelUsesSubgraph || !isDmlGraphNode) + if (containsSubgraph || !isDmlGraphNode) { - if (onNodeUnsupportedInGraph) - { - onNodeUnsupportedInGraph(node); - } + partitions.push_back(CreatePartitionAndFinalizeInputs(node, isDmlNode, false, nodeNameToPartitionMap)); + continue; + } - partitions.push_back(CreateNonGraphNodePartitionAndFinalizeInputs(node, isDmlNode, nodeNameToPartitionMap)); + if (splittingNodeIndex < additionalSplittingNodes.size() && additionalSplittingNodes[splittingNodeIndex] == nodeIndex) + { + partitions.push_back(CreatePartitionAndFinalizeInputs(node, isDmlNode, isDmlGraphNode, nodeNameToPartitionMap)); + ++splittingNodeIndex; continue; } @@ -500,7 +501,7 @@ namespace Dml firstNonFinalInputPartition->AddInput(arg->Name()); } - if (graphInputs.find(arg->Name()) != graphInputs.end()) + if (graphInputs.find(arg->Name()) != graphInputs.end() || implicitInputs.find(arg->Name()) != implicitInputs.end()) { firstNonFinalInputPartition->AddInput(arg->Name()); } diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/GraphPartitioner.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/GraphPartitioner.h index c5b15c7b1cc7b..37d577f647fb5 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/GraphPartitioner.h +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/GraphPartitioner.h @@ -3,6 +3,8 @@ #pragma once +#include +#include #include "core/providers/dml/DmlExecutionProvider/src/GraphDescBuilder.h" namespace Dml @@ -48,5 +50,6 @@ namespace Dml uint32_t supportedDeviceDataTypeMask, // Each bit corresponds to each DML_TENSOR_DATA_TYPE. std::unordered_map& graphNodePropertyMap, std::unordered_set& requiredInitializerMap, - std::function onNodeUnsupportedInGraph = nullptr); + gsl::span additionalSplittingNodes, + const std::unordered_map& implicitInputs); } // namespace Dml diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/GraphTransformer.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/GraphTransformer.h index dfcb3bd835299..a7f8186fb3b64 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/GraphTransformer.h +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/GraphTransformer.h @@ -4,7 +4,6 @@ #pragma once // Lotus framework headers for onnxruntime::IExecutionProvider (not part of the operator ABI). #include "core/common/logging/logging.h" -#include "core/framework/allocatormgr.h" #include "core/framework/execution_provider.h" #include "core/framework/op_kernel.h" #include "core/optimizer/graph_transformer.h" diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/MLOperatorAuthorImpl.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/MLOperatorAuthorImpl.cpp index 0d67b12e72b30..6cd10e14e08d2 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/MLOperatorAuthorImpl.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/MLOperatorAuthorImpl.cpp @@ -3027,7 +3027,7 @@ namespace Windows::AI::MachineLearning::Adapter CASE_PROTO(UINT8, uint8_t, int32_data_size); CASE_PROTO(UINT16, uint16_t, int32_data_size); CASE_PROTO(UINT32, uint32_t, uint64_data_size); - CASE_PROTO(UINT64, uint64_t, int64_data_size); + CASE_PROTO(UINT64, uint64_t, uint64_data_size); CASE_PROTO(FLOAT16, onnxruntime::MLFloat16, int32_data_size); default: ORT_THROW_HR(E_INVALIDARG); } diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/MLOperatorAuthorImpl.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/MLOperatorAuthorImpl.h index fd76d1947f5bf..a7f8bebb2de78 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/MLOperatorAuthorImpl.h +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/MLOperatorAuthorImpl.h @@ -511,6 +511,8 @@ class OpKernelContextWrapper : public WRL::Base GetInputTensors(); std::vector GetOutputTensors(const EdgeShapes& outputShapes); + onnxruntime::OpKernelContext* GetOpKernelContext() { return m_impl; } + protected: void ClearTempAllocations(); void TransitionResourcesForOperatorIfRequired(bool isBeforeOp); diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlDFT.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlDFT.h index 77965a9d7c591..c285cf1a070b9 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlDFT.h +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlDFT.h @@ -4,21 +4,31 @@ #include "../../../OperatorAuthorHelper/OperatorHelper.h" #include "../External/D3DX12/d3dx12.h" +#include // NOTE: When this operator's implementation is moved into DML, the associated FP16 fallback // should be removed from IsCustomOpShader(...) in // onnxruntime\core\providers\dml\DmlExecutionProvider\src\ExecutionProvider.cpp // The shader headers are produced using "GeneratedShaders/GenerateShaders.bat" -namespace DFTFloat32 +namespace StockhamFFT_Float32 { #include "GeneratedShaders/stockham.h" } -namespace DFTFloat16 +namespace StockhamFFT_Float16 { #include "GeneratedShaders/stockham_fp16.h" } +namespace BluesteinChirp_Float32 +{ + #include "GeneratedShaders/bluestein_chirp.h" +} +namespace BluesteinChirp_Float16 +{ + #include "GeneratedShaders/bluestein_chirp_fp16.h" +} + #include #include @@ -30,7 +40,7 @@ namespace DFTHelpers { // Divides and rounds up inline uint32_t CeilDivide(uint32_t dividend, uint32_t divisor) { - UINT64 temp = static_cast(dividend) + divisor - 1; + uint64_t temp = static_cast(dividend) + divisor - 1; return static_cast(temp / divisor); } @@ -39,6 +49,16 @@ namespace DFTHelpers { return (x != 0) && ((x & (x - 1)) == 0); } + template + T NextPowerOf2(T in) { + in--; + T out = 1; + while (out <= in) { + out <<= 1; + } + return out; + } + // Gets the next number of elements to dispatch to the GPU within a loop handling a large // total number of tensor elements and threads. void GetNextDispatchSize( @@ -79,23 +99,25 @@ class GpuDFTOperator : public WRL::Base { private: ComPtr m_device; - ComPtr m_rootSignature; - ComPtr m_pipelineState; + ComPtr m_stockhamFFTRootSignature; + ComPtr m_stockhamFFTPipelineState; + ComPtr m_bluesteinChirpRootSignature; + ComPtr m_bluesteinChirpPipelineState; int64_t m_axis; bool m_isOnesided; bool m_isInverse; - struct StockhamParameters + // Allocate temporary buffers if needed + struct ResourceDesc { - // Allocate temporary buffers if needed - struct ResourceDesc - { - ComPtr Resource; - std::array Sizes; - std::array Strides; - }; + ComPtr Resource; + std::array Sizes; + std::array Strides; + }; + struct StockhamParameters + { struct LoopRangeCalculator { unsigned Left; @@ -116,12 +138,25 @@ class GpuDFTOperator : public WRL::Base } }; + ResourceDesc Window = {}; std::vector ResourceLoopList = {}; LoopRangeCalculator LoopRange = {}; uint32_t OutputIndex = 0; uint32_t NumberOfPasses = 0; }; + struct BluesteinZChirpParameters + { + ResourceDesc ZChirp = {}; + ResourceDesc AFFT = {}; + ResourceDesc B = {}; + ResourceDesc BFFT = {}; + + StockhamParameters AFFTParams = {}; + StockhamParameters AFFTInverseParams = {}; + StockhamParameters BFFTParams = {}; + }; + enum class DFTType { Stockham = 0, @@ -132,6 +167,7 @@ class GpuDFTOperator : public WRL::Base { DFTType Type = DFTType::Stockham; StockhamParameters StockhamParams = {}; + BluesteinZChirpParameters BluesteinZChirpParams = {}; uint32_t DFTLength = 0; }; @@ -145,10 +181,22 @@ class GpuDFTOperator : public WRL::Base uint32_t InputStrides[4]; uint32_t OutputSizes[4]; uint32_t OutputStrides[4]; + uint32_t WindowSizes[4]; + uint32_t WindowStrides[4]; + uint32_t HasWindow; + float ChirpLength; float Scale; uint32_t DFTLength; }; + struct BluesteinZChirpShaderConstants + { + uint32_t StartIndex; + uint32_t ElementCount; + uint32_t DFTLength; + uint32_t IsInverse; + }; + public: GpuDFTOperator(ID3D12Device* device, uint32_t axis = 1, bool isOnesided = true, bool isInverse = false, MLOperatorTensorDataType dataType = MLOperatorTensorDataType::Float) : m_device(device) @@ -156,7 +204,8 @@ class GpuDFTOperator : public WRL::Base , m_isOnesided(isOnesided) , m_isInverse(isInverse) { - PrepareGpuResources(dataType); + PrepareStockhamFFT(dataType); + PrepareBluesteinZChirp(dataType); } GpuDFTOperator(IMLOperatorKernelCreationContext* context) @@ -183,22 +232,30 @@ class GpuDFTOperator : public WRL::Base ORT_THROW_IF_FAILED(context->GetInputEdgeDescription(0, &edgeDesc)); assert(edgeDesc.edgeType == MLOperatorEdgeType::Tensor); - PrepareGpuResources(edgeDesc.tensorDataType); + PrepareStockhamFFT(edgeDesc.tensorDataType); + PrepareBluesteinZChirp(edgeDesc.tensorDataType); } - void PrepareGpuResources(MLOperatorTensorDataType dataType) + void PrepareBluesteinZChirp(MLOperatorTensorDataType dataType) { // Compute root signature. - const int uavCount = 2; + const int uavCount = 2; // 2 outputs: chirp, and the reflected chirp conjugate (B) std::vector rootParameters; rootParameters.resize(uavCount + 1); - for (UINT i = 0; i < uavCount; i++) + for (uint32_t i = 0; i < uavCount; i++) { rootParameters[i].InitAsUnorderedAccessView(i); } - int constantCount = 22; + // cbuffer Constants // BluesteinZChirpShaderConstants + // { + // uint StartIndex; + // uint ElementCount; + // uint DFTLength; + // uint IsInverse; + // }; + int constantCount = 4; rootParameters[uavCount].InitAsConstants(constantCount, 0); CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC desc; @@ -217,17 +274,17 @@ class GpuDFTOperator : public WRL::Base rootSignatureBlob->GetBufferPointer(), rootSignatureBlob->GetBufferSize(), IID_ID3D12RootSignature, - &m_rootSignature + &m_bluesteinChirpRootSignature )); // Describe and create the compute pipeline state object (PSO). D3D12_COMPUTE_PIPELINE_STATE_DESC computePsoDesc = {}; - computePsoDesc.pRootSignature = m_rootSignature.Get(); + computePsoDesc.pRootSignature = m_bluesteinChirpRootSignature.Get(); switch (dataType) { case MLOperatorTensorDataType::Float: - computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(DFTFloat32::g_DFT, sizeof(DFTFloat32::g_DFT)); + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(BluesteinChirp_Float32::g_BluesteinZChirp, sizeof(BluesteinChirp_Float32::g_BluesteinZChirp)); break; case MLOperatorTensorDataType::Float16: @@ -239,9 +296,71 @@ class GpuDFTOperator : public WRL::Base sizeof(featureOptions)) ); - ORT_THROW_HR_IF(E_INVALIDARG, !featureOptions.Native16BitShaderOpsSupported); + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(BluesteinChirp_Float16::g_BluesteinZChirp, sizeof(BluesteinChirp_Float16::g_BluesteinZChirp)); + } + break; + + default: + ORT_THROW_HR(E_INVALIDARG); + } + + ORT_THROW_IF_FAILED(m_device->CreateComputePipelineState(&computePsoDesc, IID_ID3D12PipelineState, &m_bluesteinChirpPipelineState)); + } + + void PrepareStockhamFFT(MLOperatorTensorDataType dataType) + { + // Compute root signature. + const int uavCount = 3; + std::vector rootParameters; + rootParameters.resize(uavCount + 1); + + for (uint32_t i = 0; i < uavCount; i++) + { + rootParameters[i].InitAsUnorderedAccessView(i); + } + + int constantCount = 32; + rootParameters[uavCount].InitAsConstants(constantCount, 0); + + CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC desc; + desc.Init_1_1(static_cast(rootParameters.size()), rootParameters.data()); + + ComPtr rootSignatureBlob; + ComPtr rootSignatureErrorBlob; + ORT_THROW_IF_FAILED(D3D12SerializeVersionedRootSignature( + &desc, + rootSignatureBlob.GetAddressOf(), + rootSignatureErrorBlob.GetAddressOf() + )); + + ORT_THROW_IF_FAILED(m_device->CreateRootSignature( + 0, + rootSignatureBlob->GetBufferPointer(), + rootSignatureBlob->GetBufferSize(), + IID_ID3D12RootSignature, + &m_stockhamFFTRootSignature + )); + + // Describe and create the compute pipeline state object (PSO). + D3D12_COMPUTE_PIPELINE_STATE_DESC computePsoDesc = {}; + computePsoDesc.pRootSignature = m_stockhamFFTRootSignature.Get(); + + switch (dataType) + { + case MLOperatorTensorDataType::Float: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(StockhamFFT_Float32::g_DFT, sizeof(StockhamFFT_Float32::g_DFT)); + break; + + case MLOperatorTensorDataType::Float16: + { + D3D12_FEATURE_DATA_D3D12_OPTIONS4 featureOptions = {}; + ORT_THROW_IF_FAILED(m_device->CheckFeatureSupport( + D3D12_FEATURE_D3D12_OPTIONS4, + &featureOptions, + sizeof(featureOptions)) + ); - computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(DFTFloat16::g_DFT, sizeof(DFTFloat16::g_DFT)); + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(StockhamFFT_Float16::g_DFT, sizeof(StockhamFFT_Float16::g_DFT)); } break; @@ -249,7 +368,7 @@ class GpuDFTOperator : public WRL::Base ORT_THROW_HR(E_INVALIDARG); } - ORT_THROW_IF_FAILED(m_device->CreateComputePipelineState(&computePsoDesc, IID_ID3D12PipelineState, &m_pipelineState)); + ORT_THROW_IF_FAILED(m_device->CreateComputePipelineState(&computePsoDesc, IID_ID3D12PipelineState, &m_stockhamFFTPipelineState)); } // Computes the outputs of the kernel. This may be called multiple times @@ -338,12 +457,12 @@ class GpuDFTOperator : public WRL::Base { case DFTType::Stockham: { - StockhamFFT(dftParams, commandList); + StockhamFFT(dftParams, m_isInverse, 0 /*chirpLength*/, 1 /*scale*/, commandList); break; } case DFTType::BluesteinZChirp: - // Remove the power-of-two check in DmlSTFTParameters (DmlSTFT.h) if this case is implemented. - __fallthrough; + BluesteinZChirp(dftParams, m_isInverse,commandList); + break; default: return E_NOTIMPL; } @@ -356,6 +475,143 @@ class GpuDFTOperator : public WRL::Base return S_OK; } + // { before_dft_axis, axis, after_dft_axis, real_or_complex } + std::array GetReshapedDimensions(gsl::span dims, int64_t axis) + { + std::array reshapedDims = { 1, 1, 1, 1 }; + size_t reshapedIndex = 0; + for (int i = 0; i < static_cast(dims.size()) - 1; i++) + { + if (i == axis || i == (axis + 1)) + { + reshapedIndex++; + } + + reshapedDims[reshapedIndex] *= dims[i]; + } + return reshapedDims; + } + + void PrepareStockhamFFTParams( + IMLOperatorKernelContext* context, + ID3D12Resource* inputResource, + gsl::span inputDims, + ID3D12Resource* outputResource, + gsl::span outputDims, + uint32_t dftLength, + int64_t inAxis, + int64_t outAxis, + StockhamParameters& params) + { + params = {}; + + auto reshapedInputSize = GetReshapedDimensions(inputDims, inAxis); + reshapedInputSize.back() = inputDims.back(); + auto reshapedOutputSize = GetReshapedDimensions(outputDims, outAxis); + reshapedOutputSize.back() = outputDims.back(); + + auto temporarySize = reshapedInputSize; + // In the case where the dft length does not match the dft size, the temporary output should + // match the dft length + temporarySize[1] = dftLength; + temporarySize.back() = reshapedOutputSize.back(); + auto temporaryBufferByteSize = sizeof(float) * ComputeElementCountFromDimensions(temporarySize); + + // Calculate elements and strides + std::array reshapedInputStrides = { 1, 1, 1, 1 }; + std::array reshapedOutputStrides = { 1, 1, 1, 1 }; + std::array temporaryStrides = { 1, 1, 1, 1 }; + for (int i = static_cast(reshapedInputSize.size()) - 2; i >= 0; i--) + { + reshapedInputStrides[i] = reshapedInputSize[i + 1] * reshapedInputStrides[i + 1]; + reshapedOutputStrides[i] = reshapedOutputSize[i + 1] * reshapedOutputStrides[i + 1]; + temporaryStrides[i] = temporarySize[i + 1] * temporaryStrides[i + 1]; + } + + bool doesTemporaryShapeMatchOutput = true; + for (uint32_t i = 0; i < temporarySize.size(); i++) + { + doesTemporaryShapeMatchOutput &= (temporarySize[i] == reshapedOutputSize[i]); + if (!doesTemporaryShapeMatchOutput) + { + break; + } + } + + // Calculate passes + params.NumberOfPasses = static_cast(log2(dftLength)); + bool hasOnePass = params.NumberOfPasses == 1; + bool hasOddPasses = params.NumberOfPasses % 2; + bool hasEvenPasses = !hasOddPasses; + + // write directly input buffer to output buffer, dont create temps + bool writeToOutput = hasOnePass; + // First and final are input/output buffers, but all else ocillate between 2 temp buffers + bool oscillateBetweenTwoTemporaries = !hasOnePass && (m_isOnesided || !doesTemporaryShapeMatchOutput); + // First is input buffer, all else ocillate between temp and output, causing the final pass to write to the output buffer + bool oscillateFirstOutputThenTemporary = hasOddPasses && (!m_isOnesided && doesTemporaryShapeMatchOutput); + // First is input buffer, all else ocillate between output and temp, causing the final pass to write to the output buffer + bool oscillateFirstTemporaryThenOutput = hasEvenPasses && (!m_isOnesided && doesTemporaryShapeMatchOutput); + + // Create the resource loop list + // Add the input resource to the loop list + params.ResourceLoopList.push_back({}); + params.ResourceLoopList.back().Resource = inputResource; + params.ResourceLoopList.back().Sizes = reshapedInputSize; + params.ResourceLoopList.back().Strides = reshapedInputStrides; + + // If 1 temporary should be placed first, or multiple temporaries, then + // Add a temp in the list + if (oscillateFirstTemporaryThenOutput || oscillateBetweenTwoTemporaries) + { + params.ResourceLoopList.push_back({}); + params.ResourceLoopList.back().Sizes = temporarySize; + params.ResourceLoopList.back().Strides = temporaryStrides; + + auto& resource = params.ResourceLoopList.back().Resource; + ORT_THROW_IF_FAILED(context->AllocateTemporaryData(temporaryBufferByteSize, &resource)); + } + + // If 2 temps, add another + if (oscillateBetweenTwoTemporaries) + { + params.ResourceLoopList.push_back({}); + params.ResourceLoopList.back().Sizes = temporarySize; + params.ResourceLoopList.back().Strides = temporaryStrides; + + auto& resource = params.ResourceLoopList.back().Resource; + ORT_THROW_IF_FAILED(context->AllocateTemporaryData(temporaryBufferByteSize, &resource)); + } + + // Add output resource + params.ResourceLoopList.push_back({}); + params.ResourceLoopList.back().Resource = outputResource; + params.ResourceLoopList.back().Sizes = reshapedOutputSize; + params.ResourceLoopList.back().Strides = reshapedOutputStrides; + params.OutputIndex = static_cast(params.ResourceLoopList.size() - 1); + + // Add the temporary after output incase of odd number of passes + if (oscillateFirstOutputThenTemporary) + { + params.ResourceLoopList.push_back({}); + params.ResourceLoopList.back().Sizes = temporarySize; + params.ResourceLoopList.back().Strides = temporaryStrides; + + auto& resource = params.ResourceLoopList.back().Resource; + ORT_THROW_IF_FAILED(context->AllocateTemporaryData(temporaryBufferByteSize, &resource)); + } + + // Define the loop range + if (writeToOutput) { params.LoopRange = { 0, 1, params.NumberOfPasses }; } + if (oscillateBetweenTwoTemporaries) { params.LoopRange = { 1, 2, params.NumberOfPasses }; } + if (oscillateFirstOutputThenTemporary) { params.LoopRange = { 1, 2, params.NumberOfPasses + 1 }; } + if (oscillateFirstTemporaryThenOutput) { params.LoopRange = { 1, 2, params.NumberOfPasses + 1 }; } + + params.Window.Resource = nullptr; + params.Window.Sizes = std::array {0, 0, 0, 0}; + params.Window.Strides = std::array {0, 0, 0, 0}; + } + DFTParameters PrepareDFT( IMLOperatorKernelContext* context, ID3D12Resource* inputResource, @@ -368,121 +624,193 @@ class GpuDFTOperator : public WRL::Base DFTParameters params = {}; params.DFTLength = dftLength; + params.StockhamParams = {}; + params.BluesteinZChirpParams = {}; - if (!DFTHelpers::IsPowerOfTwo(params.DFTLength)) + if (DFTHelpers::IsPowerOfTwo(params.DFTLength)) { - params.Type = DFTType::BluesteinZChirp; - params.StockhamParams = {}; + params.Type = DFTType::Stockham; + PrepareStockhamFFTParams( + context, + inputResource, + inputDims, + outputResource, + outputDims, + dftLength, + m_axis, + m_axis, + params.StockhamParams); } else { - params.Type = DFTType::Stockham; - params.StockhamParams = {}; + params.Type = DFTType::BluesteinZChirp; + auto M = DFTHelpers::NextPowerOf2((2*dftLength) - 1); + auto batchSize = inputDims[0]; + + // Compute intermediate tensor strides + params.BluesteinZChirpParams.ZChirp.Sizes = std::array { 1, 1, dftLength, 2 }; + params.BluesteinZChirpParams.ZChirp.Strides = std::array { dftLength * 2, dftLength * 2, 2, 1 }; + + params.BluesteinZChirpParams.AFFT.Sizes = GetReshapedDimensions(inputDims, m_axis); + params.BluesteinZChirpParams.AFFT.Sizes[1] = M; + params.BluesteinZChirpParams.AFFT.Sizes.back() = 2; + Dml::GetDescendingPackedStrides(params.BluesteinZChirpParams.AFFT.Sizes, params.BluesteinZChirpParams.AFFT.Strides); + + params.BluesteinZChirpParams.B.Sizes = std::array { 1, 1, M, 2 }; + params.BluesteinZChirpParams.B.Strides = std::array { M * 2, M * 2, 2, 1 }; + + params.BluesteinZChirpParams.BFFT.Sizes = std::array { 1, 1, M, 2 }; + params.BluesteinZChirpParams.BFFT.Strides = std::array { M * 2, M * 2, 2, 1 }; + + auto zChirpBufferByteSize = sizeof(float) * ComputeElementCountFromDimensions(params.BluesteinZChirpParams.ZChirp.Sizes); + auto aIntermediateBufferByteSize = sizeof(float) * ComputeElementCountFromDimensions(params.BluesteinZChirpParams.AFFT.Sizes); + auto bIntermediateBufferByteSize = sizeof(float) * ComputeElementCountFromDimensions(params.BluesteinZChirpParams.BFFT.Sizes); + + auto& zChirpResource = params.BluesteinZChirpParams.ZChirp.Resource; + auto& aFFTResource = params.BluesteinZChirpParams.AFFT.Resource; + auto& bResource = params.BluesteinZChirpParams.B.Resource; + auto& bFFTResource = params.BluesteinZChirpParams.BFFT.Resource; + ORT_THROW_IF_FAILED(context->AllocateTemporaryData(zChirpBufferByteSize, &zChirpResource)); + ORT_THROW_IF_FAILED(context->AllocateTemporaryData(aIntermediateBufferByteSize, &aFFTResource)); + ORT_THROW_IF_FAILED(context->AllocateTemporaryData(bIntermediateBufferByteSize, &bResource)); + ORT_THROW_IF_FAILED(context->AllocateTemporaryData(bIntermediateBufferByteSize, &bFFTResource)); + + // The AFFT call takes input A, and produces output A_FFT. + // + // Input A: This is a pow-2 padded and chirp-weighted representation of the signal represented by "inputResource" + // Therefore the dftLength is not correct for AFFT, it should be NextPowerOf2(2*dftLength-1) + // + // The weighted representation should be calculated by passing in the chirp to the dft (like a window function). + // Padding should be handled by the shader. + PrepareStockhamFFTParams( + context, + inputResource, inputDims, + aFFTResource.Get(), params.BluesteinZChirpParams.AFFT.Sizes, + M, + m_axis, + 1, + params.BluesteinZChirpParams.AFFTParams); + params.BluesteinZChirpParams.AFFTParams.Window = params.BluesteinZChirpParams.ZChirp; - // { before_dft_axis, axis, after_dft_axis, real_or_complex } - std::array reshapedInputSize = { 1, 1, 1, inputDims.back() }; - std::array reshapedOutputSize = { 1, 1, 1, outputDims.back() }; - size_t reshapedIndex = 0; - for (int i = 0; i < static_cast(inputDims.size()) - 1; i++) - { - if (i == m_axis || i == (m_axis + 1)) - { - reshapedIndex++; - } - reshapedInputSize[reshapedIndex] *= inputDims[i]; - reshapedOutputSize[reshapedIndex] *= outputDims[i]; - } + // This shader will be used to calculate the inverse of the A_FFT, after complex multiplication with the B_FFT. + // Therefore the window function logic shold hangle complex multiplication, and B_FTT should be used like a window function. + PrepareStockhamFFTParams( + context, + aFFTResource.Get(), params.BluesteinZChirpParams.AFFT.Sizes, + outputResource, outputDims, + M, + 1, + m_axis, + params.BluesteinZChirpParams.AFFTInverseParams); + // The BFFT Window is described with the reshaped sizes and strides, which is incompatible with the + // window parameter expected by the stockham shader. + // We need to reinterpret it with the same BFFT size and strides above to make it conform to the shape + // expected by the shader. + params.BluesteinZChirpParams.AFFTInverseParams.Window = params.BluesteinZChirpParams.BFFT; + params.BluesteinZChirpParams.AFFTInverseParams.Window.Sizes = params.BluesteinZChirpParams.BFFT.Sizes; + params.BluesteinZChirpParams.AFFTInverseParams.Window.Strides = params.BluesteinZChirpParams.BFFT.Strides; + + // The BFFT call takes input B, and produces output B_FFT. + PrepareStockhamFFTParams( + context, + bResource.Get(), params.BluesteinZChirpParams.B.Sizes, + bFFTResource.Get(), params.BluesteinZChirpParams.BFFT.Sizes, + M, + 2, + 2, + params.BluesteinZChirpParams.BFFTParams); + } - auto temporarySize = reshapedInputSize; - temporarySize.back() = reshapedOutputSize.back(); - auto temporaryBufferByteSize = sizeof(float) * ComputeElementCountFromDimensions(temporarySize); + return params; + } - // Calculate elements and strides - std::array reshapedInputStrides = { 1, 1, 1, 1 }; - std::array reshapedOutputStrides = { 1, 1, 1, 1 }; - std::array temporaryStrides = { 1, 1, 1, 1 }; - for (int i = static_cast(reshapedInputSize.size()) - 2; i >= 0; i--) - { - reshapedInputStrides[i] = reshapedInputSize[i + 1] * reshapedInputStrides[i + 1]; - reshapedOutputStrides[i] = reshapedOutputSize[i + 1] * reshapedOutputStrides[i + 1]; - temporaryStrides[i] = temporarySize[i + 1] * temporaryStrides[i + 1]; - } + void BluesteinZChirp(const DFTParameters& dftParams, bool isInverse, ID3D12GraphicsCommandList* commandList) + { + const auto& bluesteinZChirpParams = dftParams.BluesteinZChirpParams; - // Calculate passes - params.StockhamParams.NumberOfPasses = static_cast(log2(params.DFTLength)); - bool hasOnePass = params.StockhamParams.NumberOfPasses == 1; - bool hasOddPasses = params.StockhamParams.NumberOfPasses % 2; - bool hasEvenPasses = !hasOddPasses; - - // write directly input buffer to output buffer, dont create temps - bool writeToOutput = hasOnePass; - // First and final are input/output buffers, but all else ocillate between 2 temp buffers - bool oscillateBetweenTwoTemporaries = !hasOnePass && m_isOnesided; - // First is input buffer, all else ocillate between temp and output, causing the final pass to write to the output buffer - bool oscillateFirstOutputThenTemporary = hasOddPasses && !m_isOnesided; - // First is input buffer, all else ocillate between output and temp, causing the final pass to write to the output buffer - bool oscillateFirstTemporaryThenOutput = hasEvenPasses && !m_isOnesided; - - // Create the resource loop list - // Add the input resource to the loop list - params.StockhamParams.ResourceLoopList.push_back({}); - params.StockhamParams.ResourceLoopList.back().Resource = inputResource; - params.StockhamParams.ResourceLoopList.back().Sizes = reshapedInputSize; - params.StockhamParams.ResourceLoopList.back().Strides = reshapedInputStrides; - - // If 1 temporary should be placed first, or multiple temporaries, then - // Add a temp in the list - if (oscillateFirstTemporaryThenOutput || oscillateBetweenTwoTemporaries) - { - params.StockhamParams.ResourceLoopList.push_back({}); - params.StockhamParams.ResourceLoopList.back().Sizes = temporarySize; - params.StockhamParams.ResourceLoopList.back().Strides = temporaryStrides; + // Get input and output resources + auto inputResource = bluesteinZChirpParams.AFFTParams.ResourceLoopList.front().Resource.Get(); + auto outputResource = bluesteinZChirpParams.AFFTInverseParams.ResourceLoopList[bluesteinZChirpParams.AFFTInverseParams.OutputIndex].Resource.Get(); + auto zChirpResource = bluesteinZChirpParams.ZChirp.Resource.Get(); + auto aFFTResource = bluesteinZChirpParams.AFFT.Resource.Get(); + auto bResource = bluesteinZChirpParams.B.Resource.Get(); + auto bFFTResource = bluesteinZChirpParams.BFFT.Resource.Get(); - auto& resource = params.StockhamParams.ResourceLoopList.back().Resource; - ORT_THROW_IF_FAILED(context->AllocateTemporaryData(temporaryBufferByteSize, &resource)); - } + // Transition resources from common to UAV state + D3D12_RESOURCE_BARRIER barriers[2]; - // If 2 temps, add another - if (oscillateBetweenTwoTemporaries) - { - params.StockhamParams.ResourceLoopList.push_back({}); - params.StockhamParams.ResourceLoopList.back().Sizes = temporarySize; - params.StockhamParams.ResourceLoopList.back().Strides = temporaryStrides; + barriers[0] = CD3DX12_RESOURCE_BARRIER::Transition( + inputResource, + D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS + ); - auto& resource = params.StockhamParams.ResourceLoopList.back().Resource; - ORT_THROW_IF_FAILED(context->AllocateTemporaryData(temporaryBufferByteSize, &resource)); - } + barriers[1] = CD3DX12_RESOURCE_BARRIER::Transition( + outputResource, + D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS + ); - // Add output resource - params.StockhamParams.ResourceLoopList.push_back({}); - params.StockhamParams.ResourceLoopList.back().Resource = outputResource; - params.StockhamParams.ResourceLoopList.back().Sizes = reshapedOutputSize; - params.StockhamParams.ResourceLoopList.back().Strides = reshapedOutputStrides; - params.StockhamParams.OutputIndex = static_cast(params.StockhamParams.ResourceLoopList.size() - 1); + commandList->ResourceBarrier(2, barriers); - // Add the temporary after output incase of odd number of passes - if (oscillateFirstOutputThenTemporary) - { - params.StockhamParams.ResourceLoopList.push_back({}); - params.StockhamParams.ResourceLoopList.back().Sizes = temporarySize; - params.StockhamParams.ResourceLoopList.back().Strides = temporaryStrides; + // Set the root signature and pipeline state + commandList->SetComputeRootSignature(m_bluesteinChirpRootSignature.Get()); + commandList->SetPipelineState(m_bluesteinChirpPipelineState.Get()); - auto& resource = params.StockhamParams.ResourceLoopList.back().Resource; - ORT_THROW_IF_FAILED(context->AllocateTemporaryData(temporaryBufferByteSize, &resource)); - } + // Create ZChirp and B Tensors + BluesteinZChirpShaderConstants constants = {}; + constants.DFTLength = dftParams.DFTLength; + constants.IsInverse = isInverse; - // Define the loop range - if (writeToOutput) { params.StockhamParams.LoopRange = { 0, 1, params.StockhamParams.NumberOfPasses }; } - if (oscillateBetweenTwoTemporaries) { params.StockhamParams.LoopRange = { 1, 2, params.StockhamParams.NumberOfPasses }; } - if (oscillateFirstOutputThenTemporary) { params.StockhamParams.LoopRange = { 1, 2, params.StockhamParams.NumberOfPasses + 1 }; } - if (oscillateFirstTemporaryThenOutput) { params.StockhamParams.LoopRange = { 1, 2, params.StockhamParams.NumberOfPasses + 1 }; } - } + auto totalElementCount = ComputeElementCountFromDimensions(bluesteinZChirpParams.B.Sizes); + constants.ElementCount = totalElementCount / bluesteinZChirpParams.B.Sizes[3]; - return params; + std::array uav_resources = { zChirpResource, bResource }; + Dispatch(uav_resources, constants, commandList); + + DFTParameters fft_params = {}; + fft_params.Type = DFTType::Stockham; + fft_params.BluesteinZChirpParams = {}; + fft_params.DFTLength = bluesteinZChirpParams.AFFT.Sizes[1]; + + // Create BFFT Tensors + fft_params.StockhamParams = bluesteinZChirpParams.BFFTParams; + StockhamFFT(fft_params, false, 0 /*chirpLength*/, 1 /*scale*/, commandList); + + // Create AFFT Tensors + fft_params.StockhamParams = bluesteinZChirpParams.AFFTParams; + StockhamFFT(fft_params, false, 0 /*chirpLength*/, 1 /*scale*/, commandList); + + // Should include the BFFT tensor as the window function + fft_params.StockhamParams = bluesteinZChirpParams.AFFTInverseParams; + float chirpLength = static_cast(bluesteinZChirpParams.ZChirp.Sizes[2]); + chirpLength *= (m_isInverse ? 1 : -1); + float scale = isInverse ? 1.f / dftParams.DFTLength : 1.f; + StockhamFFT(fft_params, true, chirpLength, scale, commandList); + + // Transition resources to common state + barriers[0] = CD3DX12_RESOURCE_BARRIER::Transition( + inputResource, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS, + D3D12_RESOURCE_STATE_COMMON + ); + + barriers[1] = CD3DX12_RESOURCE_BARRIER::Transition( + outputResource, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS, + D3D12_RESOURCE_STATE_COMMON + ); + + commandList->ResourceBarrier(2, barriers); } - void StockhamFFT(const DFTParameters& dftParams, ID3D12GraphicsCommandList* commandList) + void StockhamFFT( + const DFTParameters& dftParams, + bool isInverse, + float chirpLength, + float scale, + ID3D12GraphicsCommandList* commandList) { const auto& stockhamParams = dftParams.StockhamParams; @@ -492,6 +820,7 @@ class GpuDFTOperator : public WRL::Base // Get input and output resources auto inputResource = loopList[0].Resource.Get(); auto outputResource = loopList[stockhamParams.OutputIndex].Resource.Get(); + auto windowResource = dftParams.StockhamParams.Window.Resource.Get(); // Transition resources from common to UAV state D3D12_RESOURCE_BARRIER barriers[2]; @@ -511,15 +840,17 @@ class GpuDFTOperator : public WRL::Base commandList->ResourceBarrier(2, barriers); // Set the root signature and pipeline state - commandList->SetComputeRootSignature(m_rootSignature.Get()); - commandList->SetPipelineState(m_pipelineState.Get()); + commandList->SetComputeRootSignature(m_stockhamFFTRootSignature.Get()); + commandList->SetPipelineState(m_stockhamFFTPipelineState.Get()); // Each iteration of the below loop represents 1 level in the Stockham DFT // Dispatch in a loop DFTShaderConstants constants = {}; constants.DFTLength = dftParams.DFTLength; constants.DFTIteration = 0; - constants.IsInverse = m_isInverse; + constants.IsInverse = isInverse; + std::copy(dftParams.StockhamParams.Window.Sizes.begin(), dftParams.StockhamParams.Window.Sizes.end(), constants.WindowSizes); + std::copy(dftParams.StockhamParams.Window.Strides.begin(), dftParams.StockhamParams.Window.Strides.end(), constants.WindowStrides); for (unsigned index = 0; index < stockhamParams.NumberOfPasses; index++) { @@ -534,19 +865,20 @@ class GpuDFTOperator : public WRL::Base std::copy(loopList[outIdx].Sizes.begin(), loopList[outIdx].Sizes.end(), constants.OutputSizes); std::copy(loopList[outIdx].Strides.begin(), loopList[outIdx].Strides.end(), constants.OutputStrides); + auto isFirstPass = (index == 0); auto isLastPass = (index == stockhamParams.NumberOfPasses - 1); - auto isLastInversePass = isLastPass && m_isInverse; + auto isLastInversePass = isLastPass && isInverse; auto dftLength = 1 << stockhamParams.NumberOfPasses; - constants.Scale = isLastInversePass ? (1.f / dftLength) : 1.f; + constants.Scale = isLastInversePass ? (scale / dftLength) : 1; - auto totalElementCount = - std::accumulate(constants.OutputSizes, - constants.OutputSizes + std::size(constants.OutputSizes), - 1, - std::multiplies()); + auto totalElementCount = ComputeElementCountFromDimensions(constants.OutputSizes); constants.ElementCount = totalElementCount / constants.OutputSizes[3]; constants.DFTIteration = index + 1; - Dispatch(in, out, constants, commandList); + constants.ChirpLength = isLastPass ? chirpLength : 0; + constants.HasWindow = isFirstPass && windowResource != nullptr; + auto window = constants.HasWindow ? windowResource : out; + std::array uav_resources = { in, out, window }; + Dispatch(uav_resources, constants, commandList); } // Transition resources to common state @@ -573,26 +905,39 @@ class GpuDFTOperator : public WRL::Base return dims; } + template void Dispatch( - ID3D12Resource* inputResource, - ID3D12Resource* outputResource, - DFTShaderConstants& constants, + std::array& resources, + TConstants& constants, ID3D12GraphicsCommandList* commandList) { - D3D12_RESOURCE_BARRIER uav_barriers[2]; - uav_barriers[0] = CD3DX12_RESOURCE_BARRIER::UAV(inputResource); - uav_barriers[1] = CD3DX12_RESOURCE_BARRIER::UAV(outputResource); - commandList->ResourceBarrier(2, uav_barriers); - // Set resource views - commandList->SetComputeRootUnorderedAccessView( - 0, // root parameter index - inputResource->GetGPUVirtualAddress() - ); + D3D12_RESOURCE_BARRIER uav_barriers[TSize]; + + std::transform( + resources.begin(), resources.end(), + uav_barriers, + [](auto& resource) { return CD3DX12_RESOURCE_BARRIER::UAV(resource); } ); + commandList->ResourceBarrier(TSize, uav_barriers); + + for (uint32_t i = 0; i < TSize; i++) + { + // Set resource views + if (resources[i]) { + commandList->SetComputeRootUnorderedAccessView( + i, // root parameter index + resources[i]->GetGPUVirtualAddress() + ); + } + else + { + commandList->SetComputeRootUnorderedAccessView( + i, // root parameter index + {} + ); + + } + } - commandList->SetComputeRootUnorderedAccessView( - 1, // root parameter index - outputResource->GetGPUVirtualAddress() - ); auto pendingElementCount = constants.ElementCount; // Dispatch up to the maximum number of threads per iteration until @@ -613,8 +958,8 @@ class GpuDFTOperator : public WRL::Base // Set root constants commandList->SetComputeRoot32BitConstants( - 2, // root parameter index - 22, // Constant count + TSize, // root parameter index + 32, // Constant count &constants, 0 // offset ); diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlGridSample.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlGridSample.h new file mode 100644 index 0000000000000..c63863853fb4e --- /dev/null +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlGridSample.h @@ -0,0 +1,988 @@ +#pragma once + +#include "../../../OperatorAuthorHelper/OperatorHelper.h" +#include "../MLOperatorAuthorImpl.h" + +#include "../External/D3DX12/d3dx12.h" +#include + +// NOTE: When this operator's implementation is moved into DML, the associated FP16 fallback +// should be removed from IsCustomOpShader(...) in +// onnxruntime\core\providers\dml\DmlExecutionProvider\src\ExecutionProvider.cpp + +// The shader headers are produced using "GeneratedShaders/GenerateShaders.bat" +namespace GridSample_uint16_float +{ + #include "GeneratedShaders/grid_sample_uint16_float.h" +} + +namespace GridSample_uint_float +{ + #include "GeneratedShaders/grid_sample_uint_float.h" +} + +namespace GridSample_uint64_float +{ + #include "GeneratedShaders/grid_sample_uint64_float.h" +} + +namespace GridSample_int16_float +{ + #include "GeneratedShaders/grid_sample_int16_float.h" +} + +namespace GridSample_int_float +{ + #include "GeneratedShaders/grid_sample_int_float.h" +} + +namespace GridSample_int64_float +{ + #include "GeneratedShaders/grid_sample_int64_float.h" +} + +namespace GridSample_fp16_float +{ + #include "GeneratedShaders/grid_sample_fp16_float.h" +} + +namespace GridSample_float_float +{ + #include "GeneratedShaders/grid_sample_float_float.h" +} + +namespace GridSample_double_float +{ + #include "GeneratedShaders/grid_sample_double_float.h" +} + +namespace GridSample_bool_float +{ + #include "GeneratedShaders/grid_sample_bool_float.h" +} + +namespace GridSample_uint16_fp16 +{ + #include "GeneratedShaders/grid_sample_uint16_fp16.h" +} + +namespace GridSample_uint_fp16 +{ + #include "GeneratedShaders/grid_sample_uint_fp16.h" +} + +namespace GridSample_uint64_fp16 +{ + #include "GeneratedShaders/grid_sample_uint64_fp16.h" +} + +namespace GridSample_int16_fp16 +{ + #include "GeneratedShaders/grid_sample_int16_fp16.h" +} + +namespace GridSample_int_fp16 +{ + #include "GeneratedShaders/grid_sample_int_fp16.h" +} + +namespace GridSample_int64_fp16 +{ + #include "GeneratedShaders/grid_sample_int64_fp16.h" +} + +namespace GridSample_fp16_fp16 +{ + #include "GeneratedShaders/grid_sample_fp16_fp16.h" +} + +namespace GridSample_float_fp16 +{ + #include "GeneratedShaders/grid_sample_float_fp16.h" +} + +namespace GridSample_double_fp16 +{ + #include "GeneratedShaders/grid_sample_double_fp16.h" +} + +namespace GridSample_bool_fp16 +{ + #include "GeneratedShaders/grid_sample_bool_fp16.h" +} + +namespace GridSample_uint16_double +{ + #include "GeneratedShaders/grid_sample_uint16_double.h" +} + +namespace GridSample_uint_double +{ + #include "GeneratedShaders/grid_sample_uint_double.h" +} + +namespace GridSample_uint64_double +{ + #include "GeneratedShaders/grid_sample_uint64_double.h" +} + +namespace GridSample_int16_double +{ + #include "GeneratedShaders/grid_sample_int16_double.h" +} + +namespace GridSample_int_double +{ + #include "GeneratedShaders/grid_sample_int_double.h" +} + +namespace GridSample_int64_double +{ + #include "GeneratedShaders/grid_sample_int64_double.h" +} + +namespace GridSample_fp16_double +{ + #include "GeneratedShaders/grid_sample_fp16_double.h" +} + +namespace GridSample_float_double +{ + #include "GeneratedShaders/grid_sample_float_double.h" +} + +namespace GridSample_double_double +{ + #include "GeneratedShaders/grid_sample_double_double.h" +} + +namespace GridSample_bool_double +{ + #include "GeneratedShaders/grid_sample_bool_double.h" +} + + +#include +#include + +#include + +using namespace Microsoft::WRL; + +enum DmlGridSampleKernelInputIndex : uint32_t +{ + Input, + Grid, +}; + +enum DmlGridSampleMode : uint32_t +{ + Bilinear, + Nearest, + Bicubic, +}; + +enum DmlGridSamplePaddingMode : uint32_t +{ + Zeros, + Border, + Reflection +}; + +// Helper to derive dimensions and attributes from either the GridSample shape inferrer or the GridSample kernel constructor. +struct DmlGridSampleParameters +{ + uint32_t batchSize = 0; + uint32_t channelSize = 0; + uint32_t height = 0; + uint32_t width = 0; + int64_t alignCorners = 0; + DmlGridSampleMode mode = DmlGridSampleMode::Bilinear; + DmlGridSamplePaddingMode paddingMode = DmlGridSamplePaddingMode::Zeros; + + DML_TENSOR_DATA_TYPE dataType = DML_TENSOR_DATA_TYPE_UNKNOWN; + + DmlGridSampleParameters(){} + + DmlGridSampleParameters( + const OperatorHelper::IKernelInformationAdapter& kernelInfo, + const OperatorHelper::IShapeInformationAdapter& shapeInfo) + { + auto& attributes = kernelInfo.GetAttributes(); + + alignCorners = attributes.GetOptionalAttribute(AttrName::AlignCorners, 0); + + std::string str_attrib = attributes.GetOptionalAttribute(AttrName::Mode, "bilinear"); + ML_CHECK_VALID_ARGUMENT(str_attrib == "bilinear" || str_attrib == "nearest" || str_attrib == "bicubic"); + if (str_attrib == "bilinear") + { + mode = DmlGridSampleMode::Bilinear; + } + else if (str_attrib == "nearest") + { + mode = DmlGridSampleMode::Nearest; + } + else if (str_attrib == "bicubic") + { + mode = DmlGridSampleMode::Bicubic; + } + + str_attrib = attributes.GetOptionalAttribute(AttrName::PaddingMode, "zeros"); + ML_CHECK_VALID_ARGUMENT(str_attrib == "zeros" || str_attrib == "border" || str_attrib == "reflection"); + if (str_attrib == "zeros") + { + paddingMode = DmlGridSamplePaddingMode::Zeros; + } + else if (str_attrib == "border") + { + paddingMode = DmlGridSamplePaddingMode::Border; + } + else if (str_attrib == "reflection") + { + paddingMode = DmlGridSamplePaddingMode::Reflection; + } + + // input 0: signal (required; tensor) + { + // Input shape is expected to be [batch_size, channels, height, width] + // 4-D tensor of shape (N, C, H_out, W_out) of sampled values. + // For integer input types, intermediate values are computed as floating point and cast to integer at the end. uint32_t rank = shapeInfo.GetInputTensorDimensionCount(DmlGridSampleKernelInputIndex::Input); + uint32_t rank = shapeInfo.GetInputTensorDimensionCount(DmlGridSampleKernelInputIndex::Input); + ML_CHECK_VALID_ARGUMENT(rank == 4, "Input shape must be 4D."); + + auto dims = shapeInfo.GetInputTensorShape(DmlGridSampleKernelInputIndex::Input); + assert(dims.size() == rank); + this->batchSize = dims[0]; + this->channelSize = dims[1]; + + MLOperatorEdgeDescription edgeDesc = kernelInfo.GetInputEdgeDescription(DmlGridSampleKernelInputIndex::Input); + + assert(edgeDesc.edgeType == MLOperatorEdgeType::Tensor); + this->dataType = Dml::GetDmlDataTypeFromMlDataType(edgeDesc.tensorDataType); + } + + // input 1: grid (required; tensor) + { + // Grid shape is expected to be [batch_size, height_out, width_out, 2] + uint32_t rank = shapeInfo.GetInputTensorDimensionCount(DmlGridSampleKernelInputIndex::Grid); + ML_CHECK_VALID_ARGUMENT(rank == 4, "Input shape must be 4D."); + + auto dims = shapeInfo.GetInputTensorShape(DmlGridSampleKernelInputIndex::Grid); + assert(dims.size() == rank); + this->height = dims[1]; + this->width = dims[2]; + } + } + +}; + +namespace GridSampleHelpers +{ + // Divides and rounds + inline uint32_t CeilDivide(uint32_t dividend, uint32_t divisor) + { + uint64_t temp = static_cast(dividend) + divisor - 1; + return static_cast(temp / divisor); + } + + // Gets the next number of elements to dispatch to the GPU within a loop handling a large + // total number of tensor elements and threads. + void GetNextDispatchSize( + uint32_t elementCount, + uint32_t elementsPerThread, + uint32_t numThreads, + _Out_ uint32_t& dispatch, + _Out_ uint32_t& pendingElementCount + ) + { + // Max threads per workgroup is 2^10 (1024). Max dispatch per dimension is 2^16. Taken together, we can dispatch a maximum of + // 2^26 (268,435,456) threads along a single dimension. This should suffice for a majority of the workload. Therefore, even + // though it is possible to dispatch up to (2^16)^3 workgroups simultaneously, we stick to the simpler 1D dispatch alternative. + assert(numThreads <= D3D12_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP); + + const uint32_t maxThreadsPerDispatch = numThreads * D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION; + + const uint32_t requiredThreadCount = CeilDivide(elementCount, elementsPerThread); + + // Compute max dispatchable elements + const uint32_t availableThreadCount = std::min(requiredThreadCount, maxThreadsPerDispatch); + + // Compute required thread group count + uint32_t workGroupCount1D = CeilDivide(availableThreadCount, numThreads); + + // Compute min dispatch size + dispatch = workGroupCount1D; + + // With the dispatch size computed, compute the dispatched element count + const uint32_t dispatchedElementCount = workGroupCount1D * numThreads * elementsPerThread; + + // Update the pending element count + pendingElementCount = (dispatchedElementCount < elementCount) ? elementCount - dispatchedElementCount : 0; + } +} + +class DmlGridSampleOperator : public WRL::Base +{ +private: + ComPtr m_device; + ComPtr m_gridSampleRootSignature; + ComPtr m_gridSamplePipelineState; + DmlGridSampleParameters m_params = {}; + + + // Allocate temporary buffers if needed + struct ResourceDesc + { + ComPtr Resource; + std::array Sizes; + std::array Strides; + }; + + struct GridSampleShaderConstants + { + uint32_t StartIndex; + uint32_t ElementCount; + uint32_t Mode; + uint32_t PaddingMode; + uint32_t InputSizes[4]; + uint32_t InputStrides[4]; + uint32_t GridSizes[4]; + uint32_t GridStrides[4]; + uint32_t OutputSizes[4]; + uint32_t OutputStrides[4]; + uint32_t AlignCorners; + }; + +public: + + DmlGridSampleOperator(IMLOperatorKernelCreationContext* context) + { + ComPtr executionObject; + context->GetExecutionInterface(executionObject.GetAddressOf()); + + ComPtr commandList; + executionObject.As(&commandList); + + ORT_THROW_IF_FAILED(commandList->GetDevice(IID_ID3D12Device, &m_device)); + + MLOperatorKernelCreationContext creationContext(context); + OperatorHelper::KernelInformationAdapter kernelInfo{creationContext}; + OperatorHelper::ShapeInformationAdapter shapeInfo{creationContext}; + m_params = DmlGridSampleParameters(kernelInfo, shapeInfo); + + MLOperatorEdgeDescription inputEdgeDesc; + ORT_THROW_IF_FAILED(context->GetInputEdgeDescription(0, &inputEdgeDesc)); + assert(inputEdgeDesc.edgeType == MLOperatorEdgeType::Tensor); + + MLOperatorEdgeDescription gridEdgeDesc; + ORT_THROW_IF_FAILED(context->GetInputEdgeDescription(0, &gridEdgeDesc)); + assert(gridEdgeDesc.edgeType == MLOperatorEdgeType::Tensor); + + PrepareGridSample(inputEdgeDesc.tensorDataType, gridEdgeDesc.tensorDataType); + } + + void PrepareGridSample(MLOperatorTensorDataType inputDataType, MLOperatorTensorDataType gridDataType) + { + // Compute root signature. + const int uavCount = 3; // 3 bound UAVs: input, grid & output + std::vector rootParameters; + rootParameters.resize(uavCount + 1); + + for (uint32_t i = 0; i < uavCount; i++) + { + rootParameters[i].InitAsUnorderedAccessView(i); + } + + // cbuffer Constants + // { + // uint StartIndex; + // uint ElementCount; + // uint Mode; + // uint PaddingMode; + // uint4 InputSizes; + // uint4 InputStrides; + // uint4 GridSizes; + // uint4 GridStrides; + // uint4 OutputSizes; + // uint4 OutputStrides; + // uint AlignCorners; + // }; + int constantCount = 29; + rootParameters[uavCount].InitAsConstants(constantCount, 0); + + CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC desc; + desc.Init_1_1(static_cast(rootParameters.size()), rootParameters.data()); + + ComPtr rootSignatureBlob; + ComPtr rootSignatureErrorBlob; + ORT_THROW_IF_FAILED(D3D12SerializeVersionedRootSignature( + &desc, + rootSignatureBlob.GetAddressOf(), + rootSignatureErrorBlob.GetAddressOf() + )); + + ORT_THROW_IF_FAILED(m_device->CreateRootSignature( + 0, + rootSignatureBlob->GetBufferPointer(), + rootSignatureBlob->GetBufferSize(), + IID_ID3D12RootSignature, + &m_gridSampleRootSignature + )); + + // Describe and create the compute pipeline state object (PSO). + D3D12_COMPUTE_PIPELINE_STATE_DESC computePsoDesc = {}; + computePsoDesc.pRootSignature = m_gridSampleRootSignature.Get(); + + switch (gridDataType) + { + case MLOperatorTensorDataType::Float: + { + switch (inputDataType) + { + case MLOperatorTensorDataType::UInt16: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(GridSample_uint16_float::g_GridSample, sizeof(GridSample_uint16_float::g_GridSample)); + break; + + case MLOperatorTensorDataType::UInt32: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(GridSample_uint_float::g_GridSample, sizeof(GridSample_uint_float::g_GridSample)); + break; + + case MLOperatorTensorDataType::UInt64: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(GridSample_uint64_float::g_GridSample, sizeof(GridSample_uint64_float::g_GridSample)); + break; + + case MLOperatorTensorDataType::Int16: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(GridSample_int16_float::g_GridSample, sizeof(GridSample_int16_float::g_GridSample)); + break; + + case MLOperatorTensorDataType::Int32: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(GridSample_int_float::g_GridSample, sizeof(GridSample_int_float::g_GridSample)); + break; + + case MLOperatorTensorDataType::Int64: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(GridSample_int64_float::g_GridSample, sizeof(GridSample_int64_float::g_GridSample)); + break; + + case MLOperatorTensorDataType::Float16: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(GridSample_fp16_float::g_GridSample, sizeof(GridSample_fp16_float::g_GridSample)); + break; + + case MLOperatorTensorDataType::Float: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(GridSample_float_float::g_GridSample, sizeof(GridSample_float_float::g_GridSample)); + break; + + case MLOperatorTensorDataType::Double: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(GridSample_double_float::g_GridSample, sizeof(GridSample_double_float::g_GridSample)); + break; + + case MLOperatorTensorDataType::Bool: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(GridSample_bool_float::g_GridSample, sizeof(GridSample_bool_float::g_GridSample)); + break; + + default: + ORT_THROW_HR(E_INVALIDARG); + } + break; + } + case MLOperatorTensorDataType::Float16: + { + switch (inputDataType) + { + case MLOperatorTensorDataType::UInt16: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(GridSample_uint16_fp16::g_GridSample, sizeof(GridSample_uint16_fp16::g_GridSample)); + break; + + case MLOperatorTensorDataType::UInt32: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(GridSample_uint_fp16::g_GridSample, sizeof(GridSample_uint_fp16::g_GridSample)); + break; + + case MLOperatorTensorDataType::UInt64: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(GridSample_uint64_fp16::g_GridSample, sizeof(GridSample_uint64_fp16::g_GridSample)); + break; + + case MLOperatorTensorDataType::Int16: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(GridSample_int16_fp16::g_GridSample, sizeof(GridSample_int16_fp16::g_GridSample)); + break; + + case MLOperatorTensorDataType::Int32: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(GridSample_int_fp16::g_GridSample, sizeof(GridSample_int_fp16::g_GridSample)); + break; + + case MLOperatorTensorDataType::Int64: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(GridSample_int64_fp16::g_GridSample, sizeof(GridSample_int64_fp16::g_GridSample)); + break; + + case MLOperatorTensorDataType::Float16: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(GridSample_fp16_fp16::g_GridSample, sizeof(GridSample_fp16_fp16::g_GridSample)); + break; + + case MLOperatorTensorDataType::Float: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(GridSample_float_fp16::g_GridSample, sizeof(GridSample_float_fp16::g_GridSample)); + break; + + case MLOperatorTensorDataType::Double: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(GridSample_double_fp16::g_GridSample, sizeof(GridSample_double_fp16::g_GridSample)); + break; + + case MLOperatorTensorDataType::Bool: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(GridSample_bool_fp16::g_GridSample, sizeof(GridSample_bool_fp16::g_GridSample)); + break; + + default: + ORT_THROW_HR(E_INVALIDARG); + } + break; + } + case MLOperatorTensorDataType::Double: + { + switch (inputDataType) + { + case MLOperatorTensorDataType::UInt16: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(GridSample_uint16_double::g_GridSample, sizeof(GridSample_uint16_double::g_GridSample)); + break; + + case MLOperatorTensorDataType::UInt32: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(GridSample_uint_double::g_GridSample, sizeof(GridSample_uint_double::g_GridSample)); + break; + + case MLOperatorTensorDataType::UInt64: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(GridSample_uint64_double::g_GridSample, sizeof(GridSample_uint64_double::g_GridSample)); + break; + + case MLOperatorTensorDataType::Int16: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(GridSample_int16_double::g_GridSample, sizeof(GridSample_int16_double::g_GridSample)); + break; + + case MLOperatorTensorDataType::Int32: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(GridSample_int_double::g_GridSample, sizeof(GridSample_int_double::g_GridSample)); + break; + + case MLOperatorTensorDataType::Int64: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(GridSample_int64_double::g_GridSample, sizeof(GridSample_int64_double::g_GridSample)); + break; + + case MLOperatorTensorDataType::Float16: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(GridSample_fp16_double::g_GridSample, sizeof(GridSample_fp16_double::g_GridSample)); + break; + + case MLOperatorTensorDataType::Float: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(GridSample_float_double::g_GridSample, sizeof(GridSample_float_double::g_GridSample)); + break; + + case MLOperatorTensorDataType::Double: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(GridSample_double_double::g_GridSample, sizeof(GridSample_double_double::g_GridSample)); + break; + + case MLOperatorTensorDataType::Bool: + computePsoDesc.CS = CD3DX12_SHADER_BYTECODE(GridSample_bool_double::g_GridSample, sizeof(GridSample_bool_double::g_GridSample)); + break; + + default: + ORT_THROW_HR(E_INVALIDARG); + } + break; + } + default: + ORT_THROW_HR(E_INVALIDARG); + } + + ORT_THROW_IF_FAILED(m_device->CreateComputePipelineState(&computePsoDesc, IID_ID3D12PipelineState, &m_gridSamplePipelineState)); + } + + // Computes the outputs of the kernel. This may be called multiple times + // simultaneously within the same instance of the class. Implementations + // of this method must be thread-safe. + STDMETHOD(Compute)(IMLOperatorKernelContext* context) + { + try + { + // Get the input tensor + ComPtr inputTensor; + ORT_THROW_IF_FAILED(context->GetInputTensor(0, inputTensor.GetAddressOf())); + + // Get the grid tensor + ComPtr gridTensor; + ORT_THROW_IF_FAILED(context->GetInputTensor(1, gridTensor.GetAddressOf())); + + // Get the output tensor + ComPtr outputTensor; + context->GetOutputTensor(0, outputTensor.GetAddressOf()); + + if (outputTensor->IsCpuData() || inputTensor->IsCpuData() || gridTensor->IsCpuData()) + { + return E_UNEXPECTED; + } + + ComPtr executionObject; + ComPtr commandList; + context->GetExecutionInterface(executionObject.GetAddressOf()); + executionObject.As(&commandList); + + // Get the input and output shape sizes + auto inputDims = GetTensorDimensions(inputTensor.Get()); + auto gridDims = GetTensorDimensions(gridTensor.Get()); + auto outputDims = GetTensorDimensions(outputTensor.Get()); + + ComPtr inputUnknown; + ComPtr inputResource; + inputTensor->GetDataInterface(inputUnknown.GetAddressOf()); + ORT_THROW_IF_FAILED(inputUnknown.As(&inputResource)); + + ComPtr gridUnknown; + ComPtr gridResource; + gridTensor->GetDataInterface(gridUnknown.GetAddressOf()); + ORT_THROW_IF_FAILED(gridUnknown.As(&gridResource)); + + ComPtr outputUnknown; + ComPtr outputResource; + outputTensor->GetDataInterface(outputUnknown.GetAddressOf()); + ORT_THROW_IF_FAILED(outputUnknown.As(&outputResource)); + + return Compute( + commandList.Get(), + context, + inputResource.Get(), + inputDims, + gridResource.Get(), + gridDims, + outputResource.Get(), + outputDims + ); + } + catch (...) + { + return E_FAIL; + } + + return S_OK; + } + + HRESULT Compute( + ID3D12GraphicsCommandList* commandList, + IMLOperatorKernelContext* context, + ID3D12Resource* inputResource, + gsl::span inputDims, + ID3D12Resource* gridResource, + gsl::span gridDims, + ID3D12Resource* outputResource, + gsl::span outputDims) + { + try + { + GridSample( + inputResource, + inputDims, + gridResource, + gridDims, + outputResource, + outputDims, + commandList); + } + catch (...) + { + return E_FAIL; + } + + return S_OK; + } + + void GridSample( + ID3D12Resource* inputResource, + gsl::span inputDims, + ID3D12Resource* gridResource, + gsl::span gridDims, + ID3D12Resource* outputResource, + gsl::span outputDims, + ID3D12GraphicsCommandList* commandList) + { + std::array inputStrides; + std::array gridStrides; + std::array outputStrides; + Dml::GetDescendingPackedStrides(inputDims, inputStrides); + Dml::GetDescendingPackedStrides(gridDims, gridStrides); + Dml::GetDescendingPackedStrides(outputDims, outputStrides); + + // Transition resources from common to UAV state + D3D12_RESOURCE_BARRIER barriers[3]; + + barriers[0] = CD3DX12_RESOURCE_BARRIER::Transition( + inputResource, + D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS + ); + + barriers[1] = CD3DX12_RESOURCE_BARRIER::Transition( + gridResource, + D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS + ); + + barriers[2] = CD3DX12_RESOURCE_BARRIER::Transition( + outputResource, + D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS + ); + + inputResource->SetName(L"InputResource"); + outputResource->SetName(L"OutputResource"); + gridResource->SetName(L"GridResource"); + + commandList->ResourceBarrier(3, barriers); + + // Set the root signature and pipeline state + commandList->SetComputeRootSignature(m_gridSampleRootSignature.Get()); + commandList->SetPipelineState(m_gridSamplePipelineState.Get()); + + // Each iteration of the below loop represents 1 level in the Stockham DFT + // Dispatch in a loop + GridSampleShaderConstants constants = {}; + constants.AlignCorners = static_cast(m_params.alignCorners); + constants.Mode = static_cast(m_params.mode); + constants.PaddingMode = static_cast(m_params.paddingMode); + std::copy(inputDims.begin(), inputDims.end(), constants.InputSizes); + std::copy(inputStrides.begin(), inputStrides.end(), constants.InputStrides); + std::copy(gridDims.begin(), gridDims.end(), constants.GridSizes); + std::copy(gridStrides.begin(), gridStrides.end(), constants.GridStrides); + std::copy(outputDims.begin(), outputDims.end(), constants.OutputSizes); + std::copy(outputStrides.begin(), outputStrides.end(), constants.OutputStrides); + + constants.ElementCount = ComputeElementCountFromDimensions(constants.OutputSizes); + std::array uav_resources = { inputResource, gridResource, outputResource }; + Dispatch(uav_resources, constants, commandList); + + // Transition resources to common state + barriers[0] = CD3DX12_RESOURCE_BARRIER::Transition( + inputResource, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS, + D3D12_RESOURCE_STATE_COMMON + ); + + barriers[1] = CD3DX12_RESOURCE_BARRIER::Transition( + gridResource, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS, + D3D12_RESOURCE_STATE_COMMON + ); + + barriers[2] = CD3DX12_RESOURCE_BARRIER::Transition( + outputResource, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS, + D3D12_RESOURCE_STATE_COMMON + ); + + commandList->ResourceBarrier(3, barriers); + } + + std::vector GetTensorDimensions(IMLOperatorTensor* tensor) + { + auto inputDimsSize = tensor->GetDimensionCount(); + auto dims = std::vector(inputDimsSize); + ORT_THROW_IF_FAILED(tensor->GetShape(static_cast(dims.size()), dims.data())); + return dims; + } + + template + void Dispatch( + std::array& resources, + TConstants& constants, + ID3D12GraphicsCommandList* commandList) + { + D3D12_RESOURCE_BARRIER uav_barriers[TSize]; + + std::transform( + resources.begin(), resources.end(), + uav_barriers, + [](auto& resource) { return CD3DX12_RESOURCE_BARRIER::UAV(resource); } ); + commandList->ResourceBarrier(TSize, uav_barriers); + + for (uint32_t i = 0; i < TSize; i++) + { + // Set resource views + if (resources[i]) { + commandList->SetComputeRootUnorderedAccessView( + i, // root parameter index + resources[i]->GetGPUVirtualAddress() + ); + } + else + { + commandList->SetComputeRootUnorderedAccessView( + i, // root parameter index + {} + ); + + } + } + + auto pendingElementCount = constants.ElementCount; + + // Dispatch up to the maximum number of threads per iteration until + // all elements are completed + while (pendingElementCount > 0) + { + constants.StartIndex = constants.ElementCount - pendingElementCount; + + uint32_t dispatchSizeX; + + GridSampleHelpers::GetNextDispatchSize( + pendingElementCount, + 1, + 64, + dispatchSizeX, + pendingElementCount + ); + + // Set root constants + commandList->SetComputeRoot32BitConstants( + TSize, // root parameter index + 29, // Constant count + &constants, + 0 // offset + ); + + commandList->Dispatch(dispatchSizeX, 1, 1); + } + + commandList->ResourceBarrier(2, uav_barriers); + } +}; + +struct GridSampleShapeInferrer : public WRL::Base +{ + STDMETHOD(InferOutputShapes)(IMLOperatorShapeInferenceContext* context) noexcept + { + try + { + ComPtr contextPrivate; + ORT_THROW_IF_FAILED(context->QueryInterface(IID_PPV_ARGS(&contextPrivate))); + + MLShapeInferenceContext inferenceContext(context); + OperatorHelper::KernelInformationAdapter kernelInfo{inferenceContext}; + OperatorHelper::ShapeInformationAdapter shapeInfo{inferenceContext}; + DmlGridSampleParameters params(kernelInfo, shapeInfo); + + std::array outputDims = { params.batchSize, params.channelSize, params.height, params.width }; + + ORT_THROW_IF_FAILED(context->SetOutputTensorShape(0, onnxruntime::narrow(outputDims.size()), outputDims.data())); + } + catch (...) + { + return E_FAIL; + } + + return S_OK; + } +}; + +class DmlGridSampleOperatorFactory : public WRL::Base +{ +public: + STDMETHOD(CreateKernel)( + IMLOperatorKernelCreationContext* context, + IMLOperatorKernel** kernel) + { + try + { + auto dftOperator = wil::MakeOrThrow(context); + dftOperator.CopyTo(kernel); + return S_OK; + } + catch (...) + { + return E_FAIL; + } + } + + static void RegisterGridSampleKernel(IMLOperatorRegistry* registry) + { + MLOperatorKernelDescription kernelDescription = {}; + kernelDescription.domain = ""; + kernelDescription.name = "GridSample"; + kernelDescription.minimumOperatorSetVersion = 16; + kernelDescription.executionType = MLOperatorExecutionType::D3D12; + + // T1: tensor(float16), tensor(float), tensor(double), tensor(bfloat16) + MLOperatorEdgeTypeConstrant t1Constraint; + t1Constraint.typeLabel = "T1"; + std::vector t1AllowedEdges + { + MLOperatorEdgeDescription { MLOperatorEdgeType::Tensor, (uint64_t)MLOperatorTensorDataType::Float }, + MLOperatorEdgeDescription { MLOperatorEdgeType::Tensor, (uint64_t)MLOperatorTensorDataType::Float16 }, + MLOperatorEdgeDescription { MLOperatorEdgeType::Tensor, (uint64_t)MLOperatorTensorDataType::Int8 }, + MLOperatorEdgeDescription { MLOperatorEdgeType::Tensor, (uint64_t)MLOperatorTensorDataType::Int16 }, + MLOperatorEdgeDescription { MLOperatorEdgeType::Tensor, (uint64_t)MLOperatorTensorDataType::Int32 }, + MLOperatorEdgeDescription { MLOperatorEdgeType::Tensor, (uint64_t)MLOperatorTensorDataType::Int64 }, + MLOperatorEdgeDescription { MLOperatorEdgeType::Tensor, (uint64_t)MLOperatorTensorDataType::UInt8 }, + MLOperatorEdgeDescription { MLOperatorEdgeType::Tensor, (uint64_t)MLOperatorTensorDataType::UInt16 }, + MLOperatorEdgeDescription { MLOperatorEdgeType::Tensor, (uint64_t)MLOperatorTensorDataType::UInt32 }, + MLOperatorEdgeDescription { MLOperatorEdgeType::Tensor, (uint64_t)MLOperatorTensorDataType::UInt64 }, + }; + t1Constraint.allowedTypes = t1AllowedEdges.data(); + t1Constraint.allowedTypeCount = static_cast(t1AllowedEdges.size()); + + // T2 : tensor(int32), tensor(int64) + MLOperatorEdgeTypeConstrant t2Constraint; + t2Constraint.typeLabel = "T2"; + std::vector t2AllowedEdges + { + MLOperatorEdgeDescription { MLOperatorEdgeType::Tensor, (uint64_t)MLOperatorTensorDataType::Float16 }, + MLOperatorEdgeDescription { MLOperatorEdgeType::Tensor, (uint64_t)MLOperatorTensorDataType::Float }, + }; + t2Constraint.allowedTypes = t2AllowedEdges.data(); + t2Constraint.allowedTypeCount = static_cast(t2AllowedEdges.size()); + + std::vector typeConstraints{ t1Constraint, t2Constraint }; + kernelDescription.typeConstraints = typeConstraints.data(); + kernelDescription.typeConstraintCount = static_cast(typeConstraints.size()); + + MLOperatorAttributeNameValue alignedCornersAttributeValue; + alignedCornersAttributeValue.name = AttrName::AlignCorners; + alignedCornersAttributeValue.type = MLOperatorAttributeType::Int; + alignedCornersAttributeValue.valueCount = 1; + static const int64_t alignedCorners[] = { 0 }; + alignedCornersAttributeValue.ints = alignedCorners; + + MLOperatorAttributeNameValue modeAttributeValue; + modeAttributeValue.name = AttrName::Mode; + modeAttributeValue.type = MLOperatorAttributeType::String; + modeAttributeValue.valueCount = 1; + static const char* modes[] = { "bilinear" }; + modeAttributeValue.strings = modes; + + MLOperatorAttributeNameValue paddingModeAttributeValue; + paddingModeAttributeValue.name = AttrName::Mode; + paddingModeAttributeValue.type = MLOperatorAttributeType::String; + paddingModeAttributeValue.valueCount = 1; + static const char* paddingModes[] = { "zeros" }; + paddingModeAttributeValue.strings = paddingModes; + + std::vector attributeDefaultValues{ + alignedCornersAttributeValue, + modeAttributeValue, + paddingModeAttributeValue + }; + + kernelDescription.defaultAttributes = attributeDefaultValues.data(); + kernelDescription.defaultAttributeCount = static_cast(attributeDefaultValues.size()); + kernelDescription.options = MLOperatorKernelOptions::None; + kernelDescription.executionOptions = 0; + + auto shareInferrer = wil::MakeOrThrow(); + auto factory = wil::MakeOrThrow(); + + ComPtr registryPrivate; + ORT_THROW_IF_FAILED(registry->QueryInterface(IID_PPV_ARGS(®istryPrivate))); + + ORT_THROW_IF_FAILED(registryPrivate->RegisterOperatorKernel( + &kernelDescription, + factory.Get(), + shareInferrer.Get(), + nullptr, + false, // isInternalOperator + false, // alias + false, // supportsGraph + nullptr, + nullptr, + 0)); + + } +}; diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorAttention.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorAttention.cpp index 132b099aab7f9..bbebb4a333baf 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorAttention.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorAttention.cpp @@ -10,32 +10,20 @@ Abbreviations: B is batch_size, S is sequence_length, W is hidden_size M A B C // M, A, B, and C are Inputs | \ | / - Cast Gemm + | Gemm | / | \ | / | \ | / | \ | Slice Slice Slice - Identity | | | + | | | | | | | | | Identity Identity Identity // The identities are used to transpose NCHW -> NHCW while | | | | // keeping the GEMM strides as NCHW to better target metacommands | | | | - | ----- | - ----------- | | - \ | | - Gemm | - | | - | | - Softmax | - | / - | / - \ / - \ / - Gemm - | - ActivationLinear - | - Output // Final output + ----------------- MHA ----- + | + | + Output // Final output This kernel creates a DML_GRAPH, as mentioned above. For reference, refer to this Doc: @@ -49,51 +37,165 @@ class DmlOperatorAttention : public DmlOperator DmlOperatorAttention(const MLOperatorKernelCreationContext& kernelCreationContext) : DmlOperator(kernelCreationContext) { - ML_CHECK_VALID_ARGUMENT(kernelCreationContext.GetInputCount() >= 3); + enum DmlInputIndex : uint32_t + { + mhaQueryIndex, + mhaKeyIndex, + mhaValueIndex, + mhaStackedQueryKeyIndex, + mhaStackedKeyValueIndex, + mhaStackedQueryKeyValueIndex, + mhaBiasIndex, + mhaMaskIndex, + mhaRelativePositionBiasIndex, + mhaPastKeyIndex, + mhaPastValueIndex, + mhaInputCount, + }; + + enum InputIndex : uint32_t + { + inputIndex, + weightsIndex, + biasIndex, + maskIndex, + pastIndex, + relativePositionBiasIndex, + pastSequenceLengthIndex, + inputCount, + }; + + enum OutputIndex : uint32_t + { + outputIndex, + outputCount, + }; + + ML_CHECK_VALID_ARGUMENT(kernelCreationContext.GetInputCount() >= 2); + ML_CHECK_VALID_ARGUMENT(kernelCreationContext.GetOutputCount() >= 1); + + const uint32_t dmlInputIndex = inputIndex; + const uint32_t dmlWeightsIndex = weightsIndex; + const uint32_t dmlBiasIndex = biasIndex; + const uint32_t dmlMaskIndex = maskIndex; + const uint32_t dmlRelativePositionBiasIndex = relativePositionBiasIndex; + + const bool hasBias = kernelCreationContext.IsInputValid(biasIndex); + const bool hasMask = kernelCreationContext.IsInputValid(maskIndex); + const bool hasUnpaddedBounds = hasMask && kernelCreationContext.GetInputTensorDimensionCount(maskIndex) == 1; + const bool hasRelativePositionBias = kernelCreationContext.IsInputValid(relativePositionBiasIndex); + DmlOperator::Initialize(kernelCreationContext, std::nullopt, std::nullopt, std::nullopt, std::nullopt, 1); - std::vector inputTensorShape = kernelCreationContext.GetTensorShapeDescription().GetInputTensorShape(0); - std::vector weightTensorShape = kernelCreationContext.GetTensorShapeDescription().GetInputTensorShape(1); - std::vector biasTensorShape = kernelCreationContext.GetTensorShapeDescription().GetInputTensorShape(2); - std::vector maskIndexTensorShape = kernelCreationContext.GetTensorShapeDescription().GetInputTensorShape(3); + const uint32_t numHeads = gsl::narrow_cast(kernelCreationContext.GetAttribute(AttrName::NumHeads)); + ML_CHECK_VALID_ARGUMENT(numHeads > 0); // to avoid process crash because of division by zero. + + auto inputTensorShape = m_inputTensorDescs[dmlInputIndex].GetSizes(); ML_CHECK_VALID_ARGUMENT(inputTensorShape.size() == 3); + + auto weightTensorShape = m_inputTensorDescs[dmlWeightsIndex].GetSizes(); ML_CHECK_VALID_ARGUMENT(weightTensorShape.size() == 2); - ML_CHECK_VALID_ARGUMENT(biasTensorShape.size() == 1); - ML_CHECK_VALID_ARGUMENT(weightTensorShape[1] == biasTensorShape[0]); - ML_CHECK_VALID_ARGUMENT(biasTensorShape[0] % 3 == 0); - ML_CHECK_VALID_ARGUMENT(inputTensorShape[2] == weightTensorShape[0]); - // TODO: fix Attention kernel when maskIndexTensorShape is 1 - // https://microsoft.visualstudio.com/OS/_workitems/edit/41893987 - ML_CHECK_VALID_ARGUMENT(maskIndexTensorShape.size() > 1 && maskIndexTensorShape.size() <= 4); + ML_CHECK_VALID_ARGUMENT(weightTensorShape[0] == inputTensorShape[2]); + + const auto qkvHiddenSizes = kernelCreationContext.GetOptionalAttributeVectorInt32(AttrName::QkvHiddenSizes); + if (hasBias) + { + auto biasTensorShape = m_inputTensorDescs[dmlBiasIndex].GetSizes(); + ML_CHECK_VALID_ARGUMENT(biasTensorShape.size() == 1); + ML_CHECK_VALID_ARGUMENT(weightTensorShape[1] == biasTensorShape[0]); + + if (qkvHiddenSizes.empty()) + { + ML_CHECK_VALID_ARGUMENT(biasTensorShape[0] % 3 == 0); + } + } + + if (!qkvHiddenSizes.empty()) + { + ML_CHECK_VALID_ARGUMENT(qkvHiddenSizes.size() == 3); + ML_CHECK_VALID_ARGUMENT(qkvHiddenSizes[0] == qkvHiddenSizes[1]); + } + else + { + ML_CHECK_VALID_ARGUMENT(weightTensorShape[1] % 3 == 0); + } + + const uint32_t hiddenSize = qkvHiddenSizes.empty() ? weightTensorShape[1] / 3 : qkvHiddenSizes[0]; + const uint32_t vHiddenSize = qkvHiddenSizes.empty() ? weightTensorShape[1] / 3 : qkvHiddenSizes[2]; + const uint32_t headSize = hiddenSize / numHeads; + const uint32_t vHeadSize = vHiddenSize / numHeads; const uint32_t batchSize = inputTensorShape[0]; const uint32_t sequenceLength = inputTensorShape[1]; - const uint32_t hiddenSize = biasTensorShape[0] / 3; - const uint32_t numHeads = gsl::narrow_cast(kernelCreationContext.GetAttribute(AttrName::NumHeads)); - ML_CHECK_VALID_ARGUMENT(numHeads > 0); // to avoid process crash because of division by zero. - ML_CHECK_VALID_ARGUMENT(hiddenSize % numHeads == 0); - const uint32_t headSize = hiddenSize / numHeads; - uint32_t desiredWeightTensorShape[3] = {batchSize, weightTensorShape[0], 3 * hiddenSize}; - uint32_t desiredBiasTensorShape[3] = {batchSize, sequenceLength, 3 * hiddenSize}; - MLOperatorTensorDataType dataType = kernelCreationContext.GetInputEdgeDescription(0).tensorDataType; + uint32_t desiredWeightTensorShape[3] = {batchSize, weightTensorShape[0], hiddenSize + hiddenSize + vHiddenSize}; + MLOperatorTensorDataType dataType = kernelCreationContext.GetInputEdgeDescription(inputIndex).tensorDataType; - // overwrite weightTensorDesc - m_inputTensorDescs[1] = TensorDesc::ConstructBroadcastedTensorDesc(dataType, desiredWeightTensorShape, weightTensorShape); + m_inputTensorDescs[dmlWeightsIndex] = TensorDesc::ConstructBroadcastedTensorDesc(dataType, desiredWeightTensorShape, weightTensorShape); - // overwrite biasTensorDesc - m_inputTensorDescs[2] = TensorDesc::ConstructBroadcastedTensorDesc(dataType, desiredBiasTensorShape, biasTensorShape); + uint32_t desiredBiasTensorShape[3] = {batchSize, sequenceLength, hiddenSize + hiddenSize + vHiddenSize}; + if (hasBias) + { + auto biasTensorShape = m_inputTensorDescs[dmlBiasIndex].GetSizes(); + m_inputTensorDescs[dmlBiasIndex] = TensorDesc::ConstructBroadcastedTensorDesc(dataType, desiredBiasTensorShape, biasTensorShape); + } - // overwrite maskIndexTensorDesc - uint32_t maskIndexDimensionCount = gsl::narrow_cast(maskIndexTensorShape.size()); - maskIndexTensorShape.insert(maskIndexTensorShape.begin() + 1, 4 - maskIndexDimensionCount, 1); - uint32_t desiredMaskIndexShape[4] {batchSize, numHeads, sequenceLength, sequenceLength}; - MLOperatorTensorDataType maskTensorDataType = kernelCreationContext.GetInputEdgeDescription(3).tensorDataType; - m_inputTensorDescs[3] = TensorDesc::ConstructBroadcastedTensorDesc(maskTensorDataType, desiredMaskIndexShape, maskIndexTensorShape); + MLOperatorTensorDataType maskTensorDataType = MLOperatorTensorDataType::Undefined; + bool hasMaxSequenceMask = false; + DML_MULTIHEAD_ATTENTION_MASK_TYPE maskType = DML_MULTIHEAD_ATTENTION_MASK_TYPE_NONE; + if (hasMask) + { + if (hasUnpaddedBounds) + { + auto unpaddedKeyBoundsShape = m_inputTensorDescs[dmlMaskIndex].GetSizes(); + ML_CHECK_VALID_ARGUMENT(unpaddedKeyBoundsShape.size() == 1); + + const uint32_t batchGroupCount = unpaddedKeyBoundsShape[0] / batchSize; + ML_CHECK_VALID_ARGUMENT(batchGroupCount == 1 || batchGroupCount == 2); + + uint32_t desiredShape[2] = {batchGroupCount, batchSize}; + m_inputTensorDescs[dmlMaskIndex] = TensorDesc( + m_inputTensorDescs[dmlMaskIndex].GetDmlDataType(), + desiredShape); + + maskType = batchGroupCount == 1 + ? DML_MULTIHEAD_ATTENTION_MASK_TYPE_KEY_SEQUENCE_LENGTH + : DML_MULTIHEAD_ATTENTION_MASK_TYPE_KEY_SEQUENCE_END_START; + } + else + { + auto maskIndexTensorShape = m_inputTensorDescs[dmlMaskIndex].GetSizes(); + ML_CHECK_VALID_ARGUMENT(maskIndexTensorShape.size() > 1 && maskIndexTensorShape.size() <= 4); + + maskType = DML_MULTIHEAD_ATTENTION_MASK_TYPE_BOOLEAN; + std::vector reshapedMaskIndexTensorShape(maskIndexTensorShape.begin(), maskIndexTensorShape.end()); + if (maskIndexTensorShape.size() == 4 && maskIndexTensorShape[2] != sequenceLength) + { + hasMaxSequenceMask = true; + ML_CHECK_VALID_ARGUMENT(maskIndexTensorShape[2] == maskIndexTensorShape[3]); + const uint32_t maxSequenceLength = maskIndexTensorShape[2]; + uint32_t desiredMaskIndexShape[4] {batchSize, numHeads, maxSequenceLength, maxSequenceLength}; + maskTensorDataType = kernelCreationContext.GetInputEdgeDescription(maskIndex).tensorDataType; + m_inputTensorDescs[dmlMaskIndex] = TensorDesc::ConstructBroadcastedTensorDesc(maskTensorDataType, desiredMaskIndexShape, reshapedMaskIndexTensorShape); + } + else + { + uint32_t maskIndexDimensionCount = gsl::narrow_cast(maskIndexTensorShape.size()); + reshapedMaskIndexTensorShape.insert(reshapedMaskIndexTensorShape.begin() + 1, 4 - maskIndexDimensionCount, 1); + uint32_t desiredMaskIndexShape[4] {batchSize, numHeads, sequenceLength, sequenceLength}; + maskTensorDataType = kernelCreationContext.GetInputEdgeDescription(maskIndex).tensorDataType; + m_inputTensorDescs[dmlMaskIndex] = TensorDesc::ConstructBroadcastedTensorDesc(maskTensorDataType, desiredMaskIndexShape, reshapedMaskIndexTensorShape); + } + } + } - // overwrite output tensor desc - uint32_t outputTensorShape[4] = {batchSize, sequenceLength, numHeads, headSize}; - uint32_t outputTensorStrides[4] = {sequenceLength * numHeads * headSize, headSize, headSize * sequenceLength, 1}; - m_outputTensorDescs[0] = TensorDesc(GetDmlDataTypeFromMlDataType(dataType), outputTensorShape, outputTensorStrides, 0); + if (hasRelativePositionBias) + { + auto relativePositionBiasTensorShape = m_inputTensorDescs[dmlRelativePositionBiasIndex].GetSizes(); + ML_CHECK_VALID_ARGUMENT(relativePositionBiasTensorShape.size() == 4); + ML_CHECK_VALID_ARGUMENT(relativePositionBiasTensorShape[0] == inputTensorShape[0]); + ML_CHECK_VALID_ARGUMENT(relativePositionBiasTensorShape[1] == numHeads); + ML_CHECK_VALID_ARGUMENT(relativePositionBiasTensorShape[2] == inputTensorShape[1]); + } TensorDesc firstGemmOutputTensorDesc = TensorDesc::ConstructDefaultTensorDesc(dataType, desiredBiasTensorShape); DML_TENSOR_DESC namedFirstGemmOutputTensorDesc = firstGemmOutputTensorDesc.GetDmlDesc(); @@ -101,345 +203,335 @@ class DmlOperatorAttention : public DmlOperator std::vector inputDescs = GetDmlInputDescs(); std::vector outputDescs = GetDmlOutputDescs(); - DML_GEMM_OPERATOR_DESC xWeightOperatorDesc = {}; - xWeightOperatorDesc.ATensor = &inputDescs[0]; - xWeightOperatorDesc.BTensor = &inputDescs[1]; - xWeightOperatorDesc.CTensor = &inputDescs[2]; - xWeightOperatorDesc.OutputTensor = &namedFirstGemmOutputTensorDesc; - xWeightOperatorDesc.TransA = DML_MATRIX_TRANSFORM_NONE; - xWeightOperatorDesc.TransB = DML_MATRIX_TRANSFORM_NONE; - xWeightOperatorDesc.Alpha = 1.0f; - xWeightOperatorDesc.Beta = 1.0f; - xWeightOperatorDesc.FusedActivation = nullptr; - const DML_OPERATOR_DESC xWeightDesc {DML_OPERATOR_GEMM, &xWeightOperatorDesc}; - - - std::array querySlicedTensorShape {batchSize, sequenceLength, hiddenSize}; - TensorDesc querySlicedInputTensorDesc = TensorDesc::ConstructDefaultTensorDesc(dataType, querySlicedTensorShape); - DML_TENSOR_DESC namedQuerySlicedInputTensorDesc = querySlicedInputTensorDesc.GetDmlDesc(); - - std::array querySliceOffset = {0, 0, 0}; - std::array keySliceOffset = {0, 0, hiddenSize}; + DML_GEMM_OPERATOR_DESC gemmOperatorDesc = {}; + gemmOperatorDesc.ATensor = &inputDescs[0]; + gemmOperatorDesc.BTensor = &inputDescs[1]; + + if (hasBias) + { + gemmOperatorDesc.CTensor = &inputDescs[2]; + } + + gemmOperatorDesc.OutputTensor = &namedFirstGemmOutputTensorDesc; + gemmOperatorDesc.TransA = DML_MATRIX_TRANSFORM_NONE; + gemmOperatorDesc.TransB = DML_MATRIX_TRANSFORM_NONE; + gemmOperatorDesc.Alpha = 1.0f; + gemmOperatorDesc.Beta = 1.0f; + gemmOperatorDesc.FusedActivation = nullptr; + const DML_OPERATOR_DESC gemmDesc {DML_OPERATOR_GEMM, &gemmOperatorDesc}; + + std::array queryKeySlicedTensorShape {batchSize, sequenceLength, hiddenSize + hiddenSize}; + TensorDesc queryKeySlicedInputTensorDesc = TensorDesc::ConstructDefaultTensorDesc(dataType, queryKeySlicedTensorShape); + DML_TENSOR_DESC namedQueryKeySlicedInputTensorDesc = queryKeySlicedInputTensorDesc.GetDmlDesc(); + + std::array valueSlicedTensorShape {batchSize, sequenceLength, vHiddenSize}; + TensorDesc valueSlicedInputTensorDesc = TensorDesc::ConstructDefaultTensorDesc(dataType, valueSlicedTensorShape); + DML_TENSOR_DESC namedValueSlicedInputTensorDesc = valueSlicedInputTensorDesc.GetDmlDesc(); + + // Transpose slice QK from [batchSize, sequenceLength, 2, numHeads, headSize] to [batchSize, sequenceLength, numHeads, 2, headSize] + std::array queryKeyTransposedTensorShape {batchSize, sequenceLength, numHeads, 2, headSize}; + std::array queryKeyTransposedStrides { + sequenceLength * numHeads * 2 * headSize, + numHeads * 2 * headSize, + headSize, + numHeads * headSize, + 1, + }; + + TensorDesc queryKeyTransposedInputTensorDesc = TensorDesc( + m_inputTensorDescs[dmlInputIndex].GetDmlDataType(), + queryKeyTransposedTensorShape, + queryKeyTransposedStrides); + DML_TENSOR_DESC namedQueryKeyTransposedInputTensorDesc = queryKeyTransposedInputTensorDesc.GetDmlDesc(); + + TensorDesc queryKeyTransposedOutputTensorDesc = TensorDesc( + m_inputTensorDescs[dmlInputIndex].GetDmlDataType(), + queryKeyTransposedTensorShape); + DML_TENSOR_DESC namedQueryKeyTransposedOutputTensorDesc = queryKeyTransposedOutputTensorDesc.GetDmlDesc(); + + // Transpose QKV from [batchSize, sequenceLength, 3, numHeads, headSize] to [batchSize, sequenceLength, numHeads, 3, headSize] + std::array queryKeyValueTransposedTensorShape {batchSize, sequenceLength, numHeads, 3, headSize}; + std::array queryKeyValueTransposedStrides { + sequenceLength * numHeads * 3 * headSize, + numHeads * 3 * headSize, + headSize, + numHeads * headSize, + 1, + }; + + TensorDesc queryKeyValueTransposedInputTensorDesc = TensorDesc( + m_inputTensorDescs[dmlInputIndex].GetDmlDataType(), + queryKeyValueTransposedTensorShape, + queryKeyValueTransposedStrides); + DML_TENSOR_DESC namedQueryKeyValueTransposedInputTensorDesc = queryKeyValueTransposedInputTensorDesc.GetDmlDesc(); + + TensorDesc queryKeyValueTransposedOutputTensorDesc = TensorDesc( + m_inputTensorDescs[dmlInputIndex].GetDmlDataType(), + queryKeyValueTransposedTensorShape); + DML_TENSOR_DESC namedQueryKeyValueTransposedOutputTensorDesc = queryKeyValueTransposedOutputTensorDesc.GetDmlDesc(); + + std::array queryKeySliceOffset = {0, 0, 0}; + std::array queryKeySliceSize = {batchSize, sequenceLength, hiddenSize + hiddenSize}; + std::array queryKeySliceStrides = {1, 1, 1}; + std::array valueSliceOffset = {0, 0, 2 * hiddenSize}; - std::array sliceSize = {batchSize, sequenceLength, hiddenSize}; - std::array strides = {1, 1, 1}; - DML_SLICE1_OPERATOR_DESC querySlicedOperatorDesc = {}; - querySlicedOperatorDesc.InputTensor = &namedFirstGemmOutputTensorDesc; - querySlicedOperatorDesc.OutputTensor = &namedQuerySlicedInputTensorDesc; - querySlicedOperatorDesc.DimensionCount = gsl::narrow_cast(querySlicedTensorShape.size()); - querySlicedOperatorDesc.InputWindowOffsets = querySliceOffset.data(); - querySlicedOperatorDesc.InputWindowSizes = sliceSize.data(); - querySlicedOperatorDesc.InputWindowStrides = strides.data(); - const DML_OPERATOR_DESC querySlicedDesc = { DML_OPERATOR_SLICE1, &querySlicedOperatorDesc }; - - DML_SLICE1_OPERATOR_DESC keySlicedOperatorDesc = {}; - keySlicedOperatorDesc.InputTensor = &namedFirstGemmOutputTensorDesc; - keySlicedOperatorDesc.OutputTensor = &namedQuerySlicedInputTensorDesc; - keySlicedOperatorDesc.DimensionCount = gsl::narrow_cast(querySlicedTensorShape.size()); - keySlicedOperatorDesc.InputWindowOffsets = keySliceOffset.data(); - keySlicedOperatorDesc.InputWindowSizes = sliceSize.data(); - keySlicedOperatorDesc.InputWindowStrides = strides.data(); - const DML_OPERATOR_DESC keySlicedDesc = { DML_OPERATOR_SLICE1, &keySlicedOperatorDesc }; + std::array valueSliceSize = {batchSize, sequenceLength, vHiddenSize}; + std::array valueSliceStrides = {1, 1, 1}; + const bool hasSlicedValue = hiddenSize != vHiddenSize; + // We need to slice the value tensor when its hidden size is different from the query and key + DML_SLICE1_OPERATOR_DESC queryKeySlicedOperatorDesc = {}; DML_SLICE1_OPERATOR_DESC valueSlicedOperatorDesc = {}; - valueSlicedOperatorDesc.InputTensor = &namedFirstGemmOutputTensorDesc; - valueSlicedOperatorDesc.OutputTensor = &namedQuerySlicedInputTensorDesc; - valueSlicedOperatorDesc.DimensionCount = gsl::narrow_cast(querySlicedTensorShape.size()); - valueSlicedOperatorDesc.InputWindowOffsets = valueSliceOffset.data(); - valueSlicedOperatorDesc.InputWindowSizes = sliceSize.data(); - valueSlicedOperatorDesc.InputWindowStrides = strides.data(); + DML_ELEMENT_WISE_IDENTITY_OPERATOR_DESC transposeOperatorDesc = {}; + if (hasSlicedValue) + { + queryKeySlicedOperatorDesc.InputTensor = &namedFirstGemmOutputTensorDesc; + queryKeySlicedOperatorDesc.OutputTensor = &namedQueryKeySlicedInputTensorDesc; + queryKeySlicedOperatorDesc.DimensionCount = gsl::narrow_cast(queryKeySlicedTensorShape.size()); + queryKeySlicedOperatorDesc.InputWindowOffsets = queryKeySliceOffset.data(); + queryKeySlicedOperatorDesc.InputWindowSizes = queryKeySliceSize.data(); + queryKeySlicedOperatorDesc.InputWindowStrides = queryKeySliceStrides.data(); + + valueSlicedOperatorDesc.InputTensor = &namedFirstGemmOutputTensorDesc; + valueSlicedOperatorDesc.OutputTensor = &namedValueSlicedInputTensorDesc; + valueSlicedOperatorDesc.DimensionCount = gsl::narrow_cast(valueSlicedTensorShape.size()); + valueSlicedOperatorDesc.InputWindowOffsets = valueSliceOffset.data(); + valueSlicedOperatorDesc.InputWindowSizes = valueSliceSize.data(); + valueSlicedOperatorDesc.InputWindowStrides = valueSliceStrides.data(); + + transposeOperatorDesc.InputTensor = &namedQueryKeyTransposedInputTensorDesc; + transposeOperatorDesc.OutputTensor = &namedQueryKeyTransposedOutputTensorDesc; + } + else + { + // When Q/K/V all have the same hidden size, we just have to transpose it before sending it to MHA + transposeOperatorDesc.InputTensor = &namedQueryKeyValueTransposedInputTensorDesc; + transposeOperatorDesc.OutputTensor = &namedQueryKeyValueTransposedOutputTensorDesc; + } + const DML_OPERATOR_DESC queryKeySlicedDesc = { DML_OPERATOR_SLICE1, &queryKeySlicedOperatorDesc}; const DML_OPERATOR_DESC valueSlicedDesc = { DML_OPERATOR_SLICE1, &valueSlicedOperatorDesc}; + const DML_OPERATOR_DESC transposedDesc = { DML_OPERATOR_ELEMENT_WISE_IDENTITY, &transposeOperatorDesc}; + + std::array maskSliceOutputShape {batchSize, numHeads, sequenceLength, sequenceLength}; + std::array maskSliceStrides = {1, 1, 1, 1}; + std::array maskSliceOffsets = {0, 0, 0, 0}; + TensorDesc maskSliceOutputTensorDesc; + DML_TENSOR_DESC namedMaskSliceOutputTensorDesc; - TensorDesc castedMaskIndexTensorDesc = TensorDesc::ConstructDefaultTensorDesc(dataType, desiredMaskIndexShape); - DML_TENSOR_DESC namedCastedMaskIndexTensorDesc = castedMaskIndexTensorDesc.GetDmlDesc(); - - DML_CAST_OPERATOR_DESC castMaskIndexOperatorDesc = {}; - castMaskIndexOperatorDesc.InputTensor = &inputDescs[3]; - castMaskIndexOperatorDesc.OutputTensor = &namedCastedMaskIndexTensorDesc; - const DML_OPERATOR_DESC castMaskIndexDesc = {DML_OPERATOR_CAST, &castMaskIndexOperatorDesc}; - - // The attention fusion in ORT expects this to be number to -10000. - // https://github.com/microsoft/onnxruntime/blob/main/onnxruntime/core/optimizer/attention_fusion_helper.h#L604 - // The decomposed Attention performs: (M - 1.0) * -10000.0, where M is the 4th input of the Attention node. - // Above equation can be written as (M * -1000) + 10000.0 - DML_SCALE_BIAS scaleBias = {}; - scaleBias.Scale = -10000.0f; - scaleBias.Bias = 10000.0f; - DML_ELEMENT_WISE_IDENTITY_OPERATOR_DESC maskOperatorDesc = {}; - maskOperatorDesc.InputTensor = &namedCastedMaskIndexTensorDesc; - maskOperatorDesc.OutputTensor = &namedCastedMaskIndexTensorDesc; - maskOperatorDesc.ScaleBias = &scaleBias; - const DML_OPERATOR_DESC maskDesc = {DML_OPERATOR_ELEMENT_WISE_IDENTITY, &maskOperatorDesc}; - - // original reshaped shape: [batchSize, seqenceLength, numHeads, headSize] - // transposed shape to [0, 2, 1, 3] -> [batchSize, numHeads, sequenceLength, headSize] - uint32_t reshapedTransposedQueryTensorShape[4] = {batchSize, numHeads, sequenceLength, headSize}; - uint32_t reshapedTransposedQueryTensorStrides[4] = {sequenceLength * numHeads * headSize, headSize, numHeads * headSize, 1}; - TensorDesc reshapedTransposedQueryTensorDesc = TensorDesc( - GetDmlDataTypeFromMlDataType(dataType), - reshapedTransposedQueryTensorShape, - reshapedTransposedQueryTensorStrides); - DML_TENSOR_DESC namedReshapedTransposedQueryTensorDesc = reshapedTransposedQueryTensorDesc.GetDmlDesc(); - - TensorDesc reshapedTransposedQueryOutputTensorDesc = TensorDesc( - GetDmlDataTypeFromMlDataType(dataType), - reshapedTransposedQueryTensorShape); - DML_TENSOR_DESC namedReshapedTransposedQueryOutputTensorDesc = reshapedTransposedQueryOutputTensorDesc.GetDmlDesc(); - - DML_ELEMENT_WISE_IDENTITY_OPERATOR_DESC transposedQueryOperatorDesc{}; - transposedQueryOperatorDesc.InputTensor = &namedReshapedTransposedQueryTensorDesc; - transposedQueryOperatorDesc.OutputTensor = &namedReshapedTransposedQueryOutputTensorDesc; - const DML_OPERATOR_DESC transposedQueryDesc {DML_OPERATOR_ELEMENT_WISE_IDENTITY, &transposedQueryOperatorDesc}; - - uint32_t reshapedTransposedKeyTensorShape[4] = {batchSize, numHeads, headSize, sequenceLength}; - uint32_t reshapedTransposedKeyTensorStrides[4] = {sequenceLength * numHeads * headSize, headSize, 1, numHeads * headSize}; - TensorDesc reshapedTransposedKeyTensorDesc = TensorDesc( - GetDmlDataTypeFromMlDataType(dataType), - reshapedTransposedKeyTensorShape, - reshapedTransposedKeyTensorStrides); - DML_TENSOR_DESC namedReshapedTransposedKeyTensorDesc = reshapedTransposedKeyTensorDesc.GetDmlDesc(); - - TensorDesc reshapedTransposedKeyOutputTensorDesc = TensorDesc( - GetDmlDataTypeFromMlDataType(dataType), - reshapedTransposedKeyTensorShape); - DML_TENSOR_DESC namedReshapedTransposedKeyOutputTensorDesc = reshapedTransposedKeyOutputTensorDesc.GetDmlDesc(); - - DML_ELEMENT_WISE_IDENTITY_OPERATOR_DESC transposedKeyOperatorDesc{}; - transposedKeyOperatorDesc.InputTensor = &namedReshapedTransposedKeyTensorDesc; - transposedKeyOperatorDesc.OutputTensor = &namedReshapedTransposedKeyOutputTensorDesc; - const DML_OPERATOR_DESC transposedKeyDesc {DML_OPERATOR_ELEMENT_WISE_IDENTITY, &transposedKeyOperatorDesc}; - - uint32_t queryKeyTensorShape[4] = {batchSize, numHeads, sequenceLength, sequenceLength}; - TensorDesc queryKeyTensorDesc = TensorDesc::ConstructDefaultTensorDesc(dataType, queryKeyTensorShape); - DML_TENSOR_DESC namedQueryKeyTensorDesc = queryKeyTensorDesc.GetDmlDesc(); - - float alpha = static_cast(1 / sqrt(headSize)); - DML_GEMM_OPERATOR_DESC attentionScoreOperatorDesc = {}; - attentionScoreOperatorDesc.ATensor = &namedReshapedTransposedQueryOutputTensorDesc; - attentionScoreOperatorDesc.BTensor = &namedReshapedTransposedKeyOutputTensorDesc; - attentionScoreOperatorDesc.CTensor = &namedCastedMaskIndexTensorDesc; - attentionScoreOperatorDesc.OutputTensor = &namedQueryKeyTensorDesc; - attentionScoreOperatorDesc.TransA = DML_MATRIX_TRANSFORM_NONE; - attentionScoreOperatorDesc.TransB = DML_MATRIX_TRANSFORM_NONE; - attentionScoreOperatorDesc.Alpha = alpha; - attentionScoreOperatorDesc.Beta = 0.0f; - attentionScoreOperatorDesc.FusedActivation = nullptr; - const DML_OPERATOR_DESC attentionScoreDesc {DML_OPERATOR_GEMM, &attentionScoreOperatorDesc}; - - std::array axes = {3}; - DML_ACTIVATION_SOFTMAX1_OPERATOR_DESC softmaxOperatorDesc = {}; - softmaxOperatorDesc.InputTensor = &namedQueryKeyTensorDesc; - softmaxOperatorDesc.OutputTensor = &namedQueryKeyTensorDesc; - softmaxOperatorDesc.AxisCount = gsl::narrow_cast(axes.size()); - softmaxOperatorDesc.Axes = axes.data(); - const DML_OPERATOR_DESC softmaxDesc = {DML_OPERATOR_ACTIVATION_SOFTMAX1, &softmaxOperatorDesc}; - - uint32_t reshapedTransposedOutputTensorShape[4] {batchSize, numHeads, sequenceLength, headSize}; - uint32_t reshapedTransposedOutputTensorStrides[4] {sequenceLength * numHeads * headSize, headSize * sequenceLength, headSize, 1}; - TensorDesc reshapedTransposedOutputTensorDesc = TensorDesc( - GetDmlDataTypeFromMlDataType(dataType), - reshapedTransposedOutputTensorShape, - reshapedTransposedOutputTensorStrides, - 0 // guaranteedBaseOffsetAlignment - ); - DML_TENSOR_DESC namedReshapedTransposedOutputTensorDesc = reshapedTransposedOutputTensorDesc.GetDmlDesc(); - - DML_GEMM_OPERATOR_DESC attentionWeightOperatorDesc = {}; - attentionWeightOperatorDesc.ATensor = &namedQueryKeyTensorDesc; - attentionWeightOperatorDesc.BTensor = &namedReshapedTransposedQueryOutputTensorDesc; - attentionWeightOperatorDesc.CTensor = nullptr; - attentionWeightOperatorDesc.OutputTensor = &namedReshapedTransposedOutputTensorDesc; - attentionWeightOperatorDesc.TransA = DML_MATRIX_TRANSFORM_NONE; - attentionWeightOperatorDesc.TransB = DML_MATRIX_TRANSFORM_NONE; - attentionWeightOperatorDesc.Alpha = 1.0f; - attentionWeightOperatorDesc.Beta = 0.0f; - attentionWeightOperatorDesc.FusedActivation = nullptr; - const DML_OPERATOR_DESC attentionWeightDesc {DML_OPERATOR_GEMM, &attentionWeightOperatorDesc}; - - TensorDesc transposedOutputTensorDesc = TensorDesc( - m_outputTensorDescs[0].GetDmlDataType(), - m_outputTensorDescs[0].GetSizes(), - std::nullopt, - 0 // guaranteedBaseOffsetAlignment - ); - DML_TENSOR_DESC namedTransposedOutputTensorDesc = transposedOutputTensorDesc.GetDmlDesc(); - - DML_ACTIVATION_LINEAR_OPERATOR_DESC outputOperatorDesc = {}; - outputOperatorDesc.Alpha = 1.0f; - outputOperatorDesc.Beta = 0.0f; - outputOperatorDesc.InputTensor = &outputDescs[0]; - outputOperatorDesc.OutputTensor = &namedTransposedOutputTensorDesc; - const DML_OPERATOR_DESC outputDesc {DML_OPERATOR_ACTIVATION_LINEAR, &outputOperatorDesc}; - - enum NodeIndex : uint32_t + DML_SLICE1_OPERATOR_DESC maskSlicedOperatorDesc = {}; + if (hasMaxSequenceMask) { - xWeight, - querySlice, - keySlice, - valueSlice, - queryTranspose, - keyTranspose, - attentionScore, - softmax, - valueTranspose, - attentionWeight, - castMaskIndex, - mask, - output, - count, - }; + maskSliceOutputTensorDesc = TensorDesc::ConstructDefaultTensorDesc(maskTensorDataType, maskSliceOutputShape); + namedMaskSliceOutputTensorDesc = maskSliceOutputTensorDesc.GetDmlDesc(); + maskSlicedOperatorDesc.InputTensor = &inputDescs[dmlMaskIndex]; + maskSlicedOperatorDesc.OutputTensor = &namedMaskSliceOutputTensorDesc; + maskSlicedOperatorDesc.DimensionCount = gsl::narrow_cast(maskSliceOutputShape.size()); + maskSlicedOperatorDesc.InputWindowOffsets = maskSliceOffsets.data(); + maskSlicedOperatorDesc.InputWindowSizes = maskSliceOutputShape.data(); + maskSlicedOperatorDesc.InputWindowStrides = maskSliceStrides.data(); + } + const DML_OPERATOR_DESC maskSlicedDesc = { DML_OPERATOR_SLICE1, &maskSlicedOperatorDesc}; - MLOperatorGraphDesc operatorGraphDesc = {}; - std::array opDescs = { - &xWeightDesc, - &querySlicedDesc, - &keySlicedDesc, - &valueSlicedDesc, - &transposedQueryDesc, - &transposedKeyDesc, - &attentionScoreDesc, - &softmaxDesc, - &transposedQueryDesc, - &attentionWeightDesc, - &castMaskIndexDesc, - &maskDesc, - &outputDesc - }; - operatorGraphDesc.nodeCount = NodeIndex::count; - operatorGraphDesc.nodesAsOpDesc = opDescs.data(); + DML_MULTIHEAD_ATTENTION_OPERATOR_DESC mhaOperatorDesc = {}; + mhaOperatorDesc.ValueTensor = hasSlicedValue ? &namedValueSlicedInputTensorDesc : nullptr; + mhaOperatorDesc.StackedQueryKeyTensor = hasSlicedValue ? &namedQueryKeyTransposedOutputTensorDesc : nullptr; + mhaOperatorDesc.StackedQueryKeyValueTensor = hasSlicedValue ? nullptr : &namedQueryKeyValueTransposedOutputTensorDesc; - // set input edges - std::pair nodeToNodeInputIndex[4] { - {NodeIndex::xWeight, 0}, - {NodeIndex::xWeight, 1}, - {NodeIndex::xWeight, 2}, - {NodeIndex::castMaskIndex, 0} - }; - std::array inputEdges; - for (uint32_t inputIndex = 0; inputIndex < inputEdges.size(); inputIndex++) + if (hasMaxSequenceMask) { - DML_INPUT_GRAPH_EDGE_DESC inputEdge = {}; - inputEdge.GraphInputIndex = inputIndex; - inputEdge.ToNodeIndex = nodeToNodeInputIndex[inputIndex].first; - inputEdge.ToNodeInputIndex = nodeToNodeInputIndex[inputIndex].second; - inputEdges[inputIndex] = inputEdge; + mhaOperatorDesc.MaskTensor = &namedMaskSliceOutputTensorDesc; } - operatorGraphDesc.inputEdgeCount = gsl::narrow_cast(inputEdges.size()); - operatorGraphDesc.inputEdges = inputEdges.data(); + else + { + mhaOperatorDesc.MaskTensor = hasMask ? &inputDescs[dmlMaskIndex] : nullptr; + } + + mhaOperatorDesc.RelativePositionBiasTensor = hasRelativePositionBias ? &inputDescs[dmlRelativePositionBiasIndex] : nullptr; + mhaOperatorDesc.OutputTensor = &outputDescs[outputIndex]; + mhaOperatorDesc.Scale = kernelCreationContext.GetOptionalAttribute(AttrName::Scale, gsl::narrow_cast(1.0f / std::sqrt(headSize))); + mhaOperatorDesc.MaskFilterValue = kernelCreationContext.GetOptionalAttribute(AttrName::MaskFilterValue, -10'000.0f); + mhaOperatorDesc.HeadCount = numHeads; + mhaOperatorDesc.MaskType = maskType; + const DML_OPERATOR_DESC mhaDesc = { DML_OPERATOR_MULTIHEAD_ATTENTION, &mhaOperatorDesc }; - // set intermediate edges + // Construct the graph + std::vector inputEdges; std::vector intermediateEdges; + std::vector outputEdges; + + std::vector opDescs = { + &gemmDesc, + &mhaDesc, + }; + + uint32_t currentNodeIndex = 0; + const uint32_t gemmNodeIndex = currentNodeIndex++; + const uint32_t mhaNodeIndex = currentNodeIndex++; + + uint32_t valueSliceNodeIndex = 0; + uint32_t queryKeySliceNodeIndex = 0; + uint32_t queryKeyTransposedNodeIndex = 0; + uint32_t queryKeyValueTransposedNodeIndex = 0; + if (hasSlicedValue) + { + opDescs.push_back(&queryKeySlicedDesc); + queryKeySliceNodeIndex = currentNodeIndex++; + + opDescs.push_back(&valueSlicedDesc); + valueSliceNodeIndex = currentNodeIndex++; + + opDescs.push_back(&transposedDesc); + queryKeyTransposedNodeIndex = currentNodeIndex++; + } + else + { + opDescs.push_back(&transposedDesc); + queryKeyValueTransposedNodeIndex = currentNodeIndex++; + } + + uint32_t maskSliceNodeIndex = 0; + if (hasMaxSequenceMask) + { + opDescs.push_back(&maskSlicedDesc); + maskSliceNodeIndex = currentNodeIndex++; + } + + DML_INPUT_GRAPH_EDGE_DESC inputToGemmEdge = {}; + inputToGemmEdge.GraphInputIndex = dmlInputIndex; + inputToGemmEdge.ToNodeIndex = gemmNodeIndex; + inputToGemmEdge.ToNodeInputIndex = 0; + inputEdges.push_back(inputToGemmEdge); + + DML_INPUT_GRAPH_EDGE_DESC weightToGemmEdge = {}; + weightToGemmEdge.GraphInputIndex = dmlWeightsIndex; + weightToGemmEdge.ToNodeIndex = gemmNodeIndex; + weightToGemmEdge.ToNodeInputIndex = 1; + inputEdges.push_back(weightToGemmEdge); + + if (hasBias) + { + DML_INPUT_GRAPH_EDGE_DESC biasToGemmEdge = {}; + biasToGemmEdge.GraphInputIndex = dmlBiasIndex; + biasToGemmEdge.ToNodeIndex = gemmNodeIndex; + biasToGemmEdge.ToNodeInputIndex = 2; + inputEdges.push_back(biasToGemmEdge); + } + + if (hasMask) + { + if (hasUnpaddedBounds) + { + DML_INPUT_GRAPH_EDGE_DESC maskToMhaEdge = {}; + maskToMhaEdge.GraphInputIndex = dmlMaskIndex; + maskToMhaEdge.ToNodeIndex = mhaNodeIndex; + maskToMhaEdge.ToNodeInputIndex = mhaMaskIndex; + inputEdges.push_back(maskToMhaEdge); + } + else if (hasMaxSequenceMask) + { + DML_INPUT_GRAPH_EDGE_DESC maskToMaskSliceEdge = {}; + maskToMaskSliceEdge.GraphInputIndex = dmlMaskIndex; + maskToMaskSliceEdge.ToNodeIndex = maskSliceNodeIndex; + maskToMaskSliceEdge.ToNodeInputIndex = 0; + inputEdges.push_back(maskToMaskSliceEdge); + + DML_INTERMEDIATE_GRAPH_EDGE_DESC maskSliceToMhaEdge = {}; + maskSliceToMhaEdge.FromNodeIndex = maskSliceNodeIndex; + maskSliceToMhaEdge.FromNodeOutputIndex = 0; + maskSliceToMhaEdge.ToNodeIndex = mhaNodeIndex; + maskSliceToMhaEdge.ToNodeInputIndex = mhaMaskIndex; + intermediateEdges.push_back(maskSliceToMhaEdge); + } + else + { + DML_INPUT_GRAPH_EDGE_DESC maskToMhaEdge = {}; + maskToMhaEdge.GraphInputIndex = dmlMaskIndex; + maskToMhaEdge.ToNodeIndex = mhaNodeIndex; + maskToMhaEdge.ToNodeInputIndex = mhaMaskIndex; + inputEdges.push_back(maskToMhaEdge); + } + } + + if (hasRelativePositionBias) + { + DML_INPUT_GRAPH_EDGE_DESC relativePositionBiasToMhaEdge = {}; + relativePositionBiasToMhaEdge.GraphInputIndex = dmlRelativePositionBiasIndex; + relativePositionBiasToMhaEdge.ToNodeIndex = mhaNodeIndex; + relativePositionBiasToMhaEdge.ToNodeInputIndex = mhaRelativePositionBiasIndex; + inputEdges.push_back(relativePositionBiasToMhaEdge); + } + + if (hasSlicedValue) + { + // We need to slice QK and V, and transpose QK + DML_INTERMEDIATE_GRAPH_EDGE_DESC gemmToQueryKeySliceEdge = {}; + gemmToQueryKeySliceEdge.FromNodeIndex = gemmNodeIndex; + gemmToQueryKeySliceEdge.FromNodeOutputIndex = 0; + gemmToQueryKeySliceEdge.ToNodeIndex = queryKeySliceNodeIndex; + gemmToQueryKeySliceEdge.ToNodeInputIndex = 0; + intermediateEdges.push_back(gemmToQueryKeySliceEdge); + + DML_INTERMEDIATE_GRAPH_EDGE_DESC queryKeySliceToTransposeEdge = {}; + queryKeySliceToTransposeEdge.FromNodeIndex = queryKeySliceNodeIndex; + queryKeySliceToTransposeEdge.FromNodeOutputIndex = 0; + queryKeySliceToTransposeEdge.ToNodeIndex = queryKeyTransposedNodeIndex; + queryKeySliceToTransposeEdge.ToNodeInputIndex = 0; + intermediateEdges.push_back(queryKeySliceToTransposeEdge); + + DML_INTERMEDIATE_GRAPH_EDGE_DESC queryKeyTransposedToMhaEdge = {}; + queryKeyTransposedToMhaEdge.FromNodeIndex = queryKeyTransposedNodeIndex; + queryKeyTransposedToMhaEdge.FromNodeOutputIndex = 0; + queryKeyTransposedToMhaEdge.ToNodeIndex = mhaNodeIndex; + queryKeyTransposedToMhaEdge.ToNodeInputIndex = mhaStackedQueryKeyIndex; + intermediateEdges.push_back(queryKeyTransposedToMhaEdge); + + DML_INTERMEDIATE_GRAPH_EDGE_DESC gemmToValueSliceEdge = {}; + gemmToValueSliceEdge.FromNodeIndex = gemmNodeIndex; + gemmToValueSliceEdge.FromNodeOutputIndex = 0; + gemmToValueSliceEdge.ToNodeIndex = valueSliceNodeIndex; + gemmToValueSliceEdge.ToNodeInputIndex = 0; + intermediateEdges.push_back(gemmToValueSliceEdge); + + DML_INTERMEDIATE_GRAPH_EDGE_DESC valueSliceToMhaEdge = {}; + valueSliceToMhaEdge.FromNodeIndex = valueSliceNodeIndex; + valueSliceToMhaEdge.FromNodeOutputIndex = 0; + valueSliceToMhaEdge.ToNodeIndex = mhaNodeIndex; + valueSliceToMhaEdge.ToNodeInputIndex = mhaValueIndex; + intermediateEdges.push_back(valueSliceToMhaEdge); + } + else + { + DML_INTERMEDIATE_GRAPH_EDGE_DESC gemmToQueryKeyValueTransposeEdge = {}; + gemmToQueryKeyValueTransposeEdge.FromNodeIndex = gemmNodeIndex; + gemmToQueryKeyValueTransposeEdge.FromNodeOutputIndex = 0; + gemmToQueryKeyValueTransposeEdge.ToNodeIndex = queryKeyValueTransposedNodeIndex; + gemmToQueryKeyValueTransposeEdge.ToNodeInputIndex = 0; + intermediateEdges.push_back(gemmToQueryKeyValueTransposeEdge); + + // All we need to do here is transpose the stacked QKV tensor into something DML supports + DML_INTERMEDIATE_GRAPH_EDGE_DESC queryKeyValueTransposedToMhaEdge = {}; + queryKeyValueTransposedToMhaEdge.FromNodeIndex = queryKeyValueTransposedNodeIndex; + queryKeyValueTransposedToMhaEdge.FromNodeOutputIndex = 0; + queryKeyValueTransposedToMhaEdge.ToNodeIndex = mhaNodeIndex; + queryKeyValueTransposedToMhaEdge.ToNodeInputIndex = mhaStackedQueryKeyValueIndex; + intermediateEdges.push_back(queryKeyValueTransposedToMhaEdge); + } - DML_INTERMEDIATE_GRAPH_EDGE_DESC gemmToQuerySliceEdge = {}; - gemmToQuerySliceEdge.FromNodeIndex = NodeIndex::xWeight; - gemmToQuerySliceEdge.FromNodeOutputIndex = 0; - gemmToQuerySliceEdge.ToNodeIndex = NodeIndex::querySlice; - gemmToQuerySliceEdge.ToNodeInputIndex = 0; - intermediateEdges.push_back(gemmToQuerySliceEdge); - - DML_INTERMEDIATE_GRAPH_EDGE_DESC gemmToKeySliceEdge = {}; - gemmToKeySliceEdge.FromNodeIndex = NodeIndex::xWeight; - gemmToKeySliceEdge.FromNodeOutputIndex = 0; - gemmToKeySliceEdge.ToNodeIndex = NodeIndex::keySlice; - gemmToKeySliceEdge.ToNodeInputIndex = 0; - intermediateEdges.push_back(gemmToKeySliceEdge); - - DML_INTERMEDIATE_GRAPH_EDGE_DESC gemmToValueSliceEdge = {}; - gemmToValueSliceEdge.FromNodeIndex = NodeIndex::xWeight; - gemmToValueSliceEdge.FromNodeOutputIndex = 0; - gemmToValueSliceEdge.ToNodeIndex = NodeIndex::valueSlice; - gemmToValueSliceEdge.ToNodeInputIndex = 0; - intermediateEdges.push_back(gemmToValueSliceEdge); - - DML_INTERMEDIATE_GRAPH_EDGE_DESC querySliceToQueryTranspose = {}; - querySliceToQueryTranspose.FromNodeIndex = NodeIndex::querySlice; - querySliceToQueryTranspose.FromNodeOutputIndex = 0; - querySliceToQueryTranspose.ToNodeIndex = NodeIndex::queryTranspose; - querySliceToQueryTranspose.ToNodeInputIndex = 0; - intermediateEdges.push_back(querySliceToQueryTranspose); - - DML_INTERMEDIATE_GRAPH_EDGE_DESC keySliceToKeyTranspose = {}; - keySliceToKeyTranspose.FromNodeIndex = NodeIndex::keySlice; - keySliceToKeyTranspose.FromNodeOutputIndex = 0; - keySliceToKeyTranspose.ToNodeIndex = NodeIndex::keyTranspose; - keySliceToKeyTranspose.ToNodeInputIndex = 0; - intermediateEdges.push_back(keySliceToKeyTranspose); - - DML_INTERMEDIATE_GRAPH_EDGE_DESC queryTransposeToGemm = {}; - queryTransposeToGemm.FromNodeIndex = NodeIndex::queryTranspose; - queryTransposeToGemm.FromNodeOutputIndex = 0; - queryTransposeToGemm.ToNodeIndex = NodeIndex::attentionScore; - queryTransposeToGemm.ToNodeInputIndex = 0; - intermediateEdges.push_back(queryTransposeToGemm); - - DML_INTERMEDIATE_GRAPH_EDGE_DESC keyTransposeToGemm = {}; - keyTransposeToGemm.FromNodeIndex = NodeIndex::keyTranspose; - keyTransposeToGemm.FromNodeOutputIndex = 0; - keyTransposeToGemm.ToNodeIndex = NodeIndex::attentionScore; - keyTransposeToGemm.ToNodeInputIndex = 1; - intermediateEdges.push_back(keyTransposeToGemm); - - DML_INTERMEDIATE_GRAPH_EDGE_DESC castedMaskIndexToIdentity = {}; - castedMaskIndexToIdentity.FromNodeIndex = NodeIndex::castMaskIndex; - castedMaskIndexToIdentity.FromNodeOutputIndex = 0; - castedMaskIndexToIdentity.ToNodeIndex = NodeIndex::mask; - castedMaskIndexToIdentity.ToNodeInputIndex = 0; - intermediateEdges.push_back(castedMaskIndexToIdentity); - - DML_INTERMEDIATE_GRAPH_EDGE_DESC maskToGemm = {}; - maskToGemm.FromNodeIndex = NodeIndex::mask; - maskToGemm.FromNodeOutputIndex = 0; - maskToGemm.ToNodeIndex = NodeIndex::attentionScore; - maskToGemm.ToNodeInputIndex = 2; - intermediateEdges.push_back(maskToGemm); - - DML_INTERMEDIATE_GRAPH_EDGE_DESC attentionScoreToSoftmax = {}; - attentionScoreToSoftmax.FromNodeIndex = NodeIndex::attentionScore; - attentionScoreToSoftmax.FromNodeOutputIndex = 0; - attentionScoreToSoftmax.ToNodeIndex = NodeIndex::softmax; - attentionScoreToSoftmax.ToNodeInputIndex = 0; - intermediateEdges.push_back(attentionScoreToSoftmax); - - DML_INTERMEDIATE_GRAPH_EDGE_DESC softmaxToGemm = {}; - softmaxToGemm.FromNodeIndex = NodeIndex::softmax; - softmaxToGemm.FromNodeOutputIndex = 0; - softmaxToGemm.ToNodeIndex = NodeIndex::attentionWeight; - softmaxToGemm.ToNodeInputIndex = 0; - intermediateEdges.push_back(softmaxToGemm); - - DML_INTERMEDIATE_GRAPH_EDGE_DESC valueSliceToValueTranspose = {}; - valueSliceToValueTranspose.FromNodeIndex = NodeIndex::valueSlice; - valueSliceToValueTranspose.FromNodeOutputIndex = 0; - valueSliceToValueTranspose.ToNodeIndex = NodeIndex::valueTranspose; - valueSliceToValueTranspose.ToNodeInputIndex = 0; - intermediateEdges.push_back(valueSliceToValueTranspose); - - DML_INTERMEDIATE_GRAPH_EDGE_DESC valueTransposeToGemm = {}; - valueTransposeToGemm.FromNodeIndex = NodeIndex::valueTranspose; - valueTransposeToGemm.FromNodeOutputIndex = 0; - valueTransposeToGemm.ToNodeIndex = NodeIndex::attentionWeight; - valueTransposeToGemm.ToNodeInputIndex = 1; - intermediateEdges.push_back(valueTransposeToGemm); - - DML_INTERMEDIATE_GRAPH_EDGE_DESC gemmToIdentity = {}; - gemmToIdentity.FromNodeIndex = NodeIndex::attentionWeight; - gemmToIdentity.FromNodeOutputIndex = 0; - gemmToIdentity.ToNodeIndex = NodeIndex::output; - gemmToIdentity.ToNodeInputIndex = 0; - intermediateEdges.push_back(gemmToIdentity); + DML_OUTPUT_GRAPH_EDGE_DESC mhaToOutputEdge = {}; + mhaToOutputEdge.FromNodeIndex = mhaNodeIndex; + mhaToOutputEdge.FromNodeOutputIndex = 0; + mhaToOutputEdge.GraphOutputIndex = 0; + outputEdges.push_back(mhaToOutputEdge); + MLOperatorGraphDesc operatorGraphDesc = {}; + operatorGraphDesc.inputEdgeCount = gsl::narrow_cast(inputEdges.size()); + operatorGraphDesc.inputEdges = inputEdges.data(); operatorGraphDesc.intermediateEdgeCount = gsl::narrow_cast(intermediateEdges.size()); operatorGraphDesc.intermediateEdges = intermediateEdges.data(); - - // set the output edges - std::array outputEdges; - DML_OUTPUT_GRAPH_EDGE_DESC outputEdge = {}; - outputEdge.FromNodeIndex = NodeIndex::output; - outputEdge.FromNodeOutputIndex = 0; - outputEdge.GraphOutputIndex = 0; - outputEdges[0] = outputEdge; operatorGraphDesc.outputEdgeCount = gsl::narrow_cast(outputEdges.size()); operatorGraphDesc.outputEdges = outputEdges.data(); + operatorGraphDesc.nodeCount = gsl::narrow_cast(opDescs.size()); + operatorGraphDesc.nodesAsOpDesc = opDescs.data(); SetDmlOperatorGraphDesc(std::move(operatorGraphDesc), kernelCreationContext); } @@ -448,32 +540,37 @@ class DmlOperatorAttention : public DmlOperator void CALLBACK QueryAttention(IMLOperatorSupportQueryContextPrivate* context, /*out*/ bool* isSupported) { *isSupported = false; - // Fall back to CPU if input 'past' and 'relative_position_bias' is present because there is no current use case for this. - // and it will make the implementation more complex. - // Also fall back to CPU if output 'present' is present for same reason as above. - if (context->GetInputCount() > 4 || context->GetOutputCount() > 1) + // `past` input tensor is not supported yet + if (context->IsInputValid(4)) { return; } - // Checking input count alone is not sufficient to fallback to CPU if input 'past' and 'relative_position_bias' is present - // because input 'mask_index', 'past', and 'relative_position_bias' all are optional. - if (context->IsInputValid(4) || context->IsInputValid(5)) + + // `past_sequence_length` input tensor is not supported yet + if (context->IsInputValid(6)) { return; } - // Fall back to CPU if attibute 'qkv_hidden_sizes' is present or - // if value of attribute 'unidirectional' is 1, because of same reason as above. - MLOperatorAttributes attributes(context); - if (attributes.HasAttribute(AttrName::QkvHiddenSizes, MLOperatorAttributeType::IntArray)) + + // `present` output tensor is not supported yet + if (context->IsOutputValid(1)) { return; } + // `unidirectional == 1` is not supported yet + MLOperatorAttributes attributes(context); if (attributes.GetOptionalAttribute(AttrName::Unidirectional, 0) != 0) { return; } + // `do_rotary == 1` is not supported yet + if (attributes.GetOptionalAttribute(AttrName::DoRotary, 0) != 0) + { + return; + } + *isSupported = true; } diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorEinSum.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorEinSum.cpp index c8217e43436ed..d5bf54de53c30 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorEinSum.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorEinSum.cpp @@ -26,12 +26,13 @@ class DmlOperatorEinSum : public DmlOperator, public EinSumHelper } inputIndices.resize(bindableInputCount); - DmlOperator::Initialize(kernelCreationContext, inputIndices, outputIndices); + constexpr uint32_t dimCount = 2; + DmlOperator::Initialize(kernelCreationContext, inputIndices, outputIndices, std::nullopt, std::nullopt, dimCount); std::vector inputDescs = GetDmlInputDescs(); std::vector outputDescs = GetDmlOutputDescs(); - static_assert(RecognizedOperatorType::Total == static_cast(11), "Update this switch."); + static_assert(RecognizedOperatorType::Total == static_cast(12), "Update this switch."); switch (m_recognizedOperatorType) { case RecognizedOperatorType::Multiply: @@ -45,6 +46,28 @@ class DmlOperatorEinSum : public DmlOperator, public EinSumHelper } break; + case RecognizedOperatorType::OuterProduct: + { + std::array aSizes = {m_inputTensorDescs[0].GetSizes().back(), 1}; + TensorDesc aTensorDesc = TensorDesc(m_inputTensorDescs[0].GetDmlDataType(), aSizes); + auto aDmlTensorDesc = aTensorDesc.GetDmlDesc(); + + std::array bSizes = {1, m_inputTensorDescs[1].GetSizes().back()}; + TensorDesc bTensorDesc = TensorDesc(m_inputTensorDescs[1].GetDmlDataType(), bSizes); + auto bDmlTensorDesc = bTensorDesc.GetDmlDesc(); + + DML_GEMM_OPERATOR_DESC operatorDesc = {}; + operatorDesc.ATensor = &aDmlTensorDesc; + operatorDesc.BTensor = &bDmlTensorDesc; + operatorDesc.OutputTensor = &outputDescs[0]; + operatorDesc.Alpha = 1.0; + operatorDesc.Beta = 0.0; + operatorDesc.FusedActivation = nullptr; + + SetDmlOperatorDesc({ DML_OPERATOR_GEMM, &operatorDesc }, kernelCreationContext); + } + break; + case RecognizedOperatorType::MatMul: case RecognizedOperatorType::MatMulTransposeA: case RecognizedOperatorType::MatMulTransposeB: @@ -253,7 +276,7 @@ void CALLBACK QueryEinSum(IMLOperatorSupportQueryContextPrivate* context, bool* EinSumHelper helper(attributes); auto recognizedOperatorType = helper.GetRecognizedOperatorType(); - static_assert(EinSumHelper::RecognizedOperatorType::Total == static_cast(11), "Update this function."); + static_assert(EinSumHelper::RecognizedOperatorType::Total == static_cast(12), "Update this function."); *isSupported = (recognizedOperatorType != EinSumHelper::RecognizedOperatorType::None); } diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorElementWise.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorElementWise.cpp index c1507cf1dc7c8..43d34657098ef 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorElementWise.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorElementWise.cpp @@ -89,7 +89,7 @@ void SetFusedActivation(T& opDesc, const DML_OPERATOR_DESC* fusedActivation) template<> void SetFusedActivation(DML_ELEMENT_WISE_ADD1_OPERATOR_DESC& opDesc, const DML_OPERATOR_DESC* fusedActivation) -{ +{ opDesc.FusedActivation = fusedActivation; } @@ -118,7 +118,7 @@ class DmlOperatorElementwiseBinary : public DmlOperator DML_OPERATOR_DESC opDescDesc = { ApiTraits::OperatorDescTraits::Type, &opDesc}; if (fusedActivation != std::nullopt) - { + { // Activation is only fused for two-input sum operators ORT_THROW_HR_IF(E_INVALIDARG, opDescDesc.Type != DML_OPERATOR_ELEMENT_WISE_ADD1 || kernelInfo.GetInputCount() > 2); @@ -160,7 +160,7 @@ class DmlOperatorElementwiseBinaryLoop : public DmlOperator std::optional fusedActivation = FusionHelpers::TryGetFusedActivationDesc(kernelInfo); DML_OPERATOR_DESC fusedActivationDmlDesc = fusedActivation ? fusedActivation->GetDmlDesc() : DML_OPERATOR_DESC(); - + // Activation is only fused for two-input sum operators ORT_THROW_HR_IF(E_INVALIDARG, fusedActivation != std::nullopt && inputCount != 2); @@ -294,7 +294,7 @@ class DmlOperatorElementwiseMean : public DmlOperator meanDesc.ATensor = &inputDescs[0]; meanDesc.BTensor = &inputDescs[1]; meanDesc.OutputTensor = &outputDescs[0]; - + SetDmlOperatorDesc({ DML_OPERATOR_ELEMENT_WISE_MEAN, &meanDesc}, kernelInfo); } else @@ -447,7 +447,7 @@ class DmlOperatorElementwiseClip11 : public DmlOperator opDesc.OutputTensor = outputDescs.data(); // MinMaxDataType will always be equal to inputDataTensorDataType // Assigning minMaxDataType to inputDataTensorDataType because this field - // has to be assigned even if program does not go through below conditional + // has to be assigned even if program does not go through below conditional // logic for some corner test case // Same applies to min and max value. opDesc.MinMaxDataType = this->m_inputTensorDescs[0].GetDmlDataType(); @@ -458,7 +458,7 @@ class DmlOperatorElementwiseClip11 : public DmlOperator { ReadScalarTensorData(kernelInfo.GetConstantInputTensor(1), /*out*/ &opDesc.Min.Bytes, sizeof(opDesc.Min.Bytes)); } - if (kernelInfo.IsInputValid(2)) + if (kernelInfo.IsInputValid(2)) { ReadScalarTensorData(kernelInfo.GetConstantInputTensor(2), /*out*/ &opDesc.Max.Bytes, sizeof(opDesc.Max.Bytes)); } @@ -720,6 +720,7 @@ DML_OP_DEFINE_CREATION_FUNCTION(Asinh, DmlOperatorElementwiseUnary); DML_OP_DEFINE_CREATION_FUNCTION(Atanh, DmlOperatorElementwiseUnary); DML_OP_DEFINE_CREATION_FUNCTION(Erf, DmlOperatorElementwiseUnary); +DML_OP_DEFINE_CREATION_FUNCTION(BitwiseNot, DmlOperatorElementwiseUnary); // Binary operators: DML_OP_DEFINE_CREATION_FUNCTION(Greater, DmlOperatorElementwiseBinary); @@ -734,6 +735,9 @@ DML_OP_DEFINE_CREATION_FUNCTION(Add, DmlOperatorElementwiseBinary); DML_OP_DEFINE_CREATION_FUNCTION(Mul, DmlOperatorElementwiseBinary); DML_OP_DEFINE_CREATION_FUNCTION(Div, DmlOperatorElementwiseBinary); +DML_OP_DEFINE_CREATION_FUNCTION(BitwiseAnd, DmlOperatorElementwiseBinary); +DML_OP_DEFINE_CREATION_FUNCTION(BitwiseOr, DmlOperatorElementwiseBinary); +DML_OP_DEFINE_CREATION_FUNCTION(BitwiseXor, DmlOperatorElementwiseBinary); // Binary operators that support >2 inputs: DML_OP_DEFINE_CREATION_FUNCTION(Sum, DmlOperatorElementwiseBinaryLoop); diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorEmbedLayerNormalization.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorEmbedLayerNormalization.cpp index 3efddb9392089..6a8333cd72561 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorEmbedLayerNormalization.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorEmbedLayerNormalization.cpp @@ -459,7 +459,7 @@ class DmlOperatorEmbedLayerNormalization : public DmlOperator maskIndexOutputEdge.FromNodeOutputIndex = 0; outputEdges.push_back(std::move(maskIndexOutputEdge)); } - else + else if (maskIndexDesc.Desc) { // Insert the edge feeding into the MaskIndex output DML_OUTPUT_GRAPH_EDGE_DESC maskIndexOutputEdge = {}; diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorGroupNorm.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorGroupNorm.cpp index 66215877030c4..fed0e4645ffd8 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorGroupNorm.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorGroupNorm.cpp @@ -19,6 +19,7 @@ class DmlOperatorGroupNorm : public DmlOperator std::vector inputDescs = GetDmlInputDescs(); std::vector outputDescs = GetDmlOutputDescs(); + const bool channelsLast = kernelCreationContext.GetOptionalAttribute(AttrName::ChannelsLast, true); const float epsilon = kernelCreationContext.GetOptionalAttribute(AttrName::Epsilon, DefaultEpsilon); const bool activation = gsl::narrow_cast(kernelCreationContext.GetAttribute(AttrName::Activation)); const uint32_t groups = gsl::narrow_cast(kernelCreationContext.GetAttribute(AttrName::Groups)); @@ -36,19 +37,32 @@ class DmlOperatorGroupNorm : public DmlOperator // Data is in NHWC format const uint32_t batch = inputTensorShape[0]; - const uint32_t height = inputTensorShape[1]; - const uint32_t width = inputTensorShape[2]; - const uint32_t channels = inputTensorShape[3]; + const uint32_t height = channelsLast ? inputTensorShape[1] : inputTensorShape[2]; + const uint32_t width = channelsLast ? inputTensorShape[2] : inputTensorShape[3]; + const uint32_t channels = channelsLast ? inputTensorShape[3] : inputTensorShape[1]; ML_CHECK_VALID_ARGUMENT(gammaTensorShape[0] == channels); ML_CHECK_VALID_ARGUMENT(betaTensorShape[0] == channels); ML_CHECK_VALID_ARGUMENT(channels % groups == 0); ML_CHECK_VALID_ARGUMENT(m_inputTensorDescs[1].GetDmlDataType() == m_inputTensorDescs[2].GetDmlDataType()); const uint32_t channelsPerGroup = channels / groups; - // 1. Reshape the input from [batch, height, width, channels] to [batch, height * width, groups, channelsPerGroup] - // 2. Stride the reshaped input from [batch, height * width, groups, channelsPerGroup] to [batch, groups, channelsPerGroup, height * width] - const std::array inputShape = {batch, groups, channelsPerGroup, height * width}; - const std::array inputStrides = {channelsPerGroup * height * width * groups, channelsPerGroup, 1, groups * channelsPerGroup}; + std::array inputShape; + std::array inputStrides; + + if (channelsLast) + { + // 1. Reshape the input from [batch, height, width, channels] to [batch, height * width, groups, channelsPerGroup] + // 2. Stride the reshaped input from [batch, height * width, groups, channelsPerGroup] to [batch, groups, channelsPerGroup, height * width] + inputShape = {batch, groups, channelsPerGroup, height * width}; + inputStrides = {channelsPerGroup * height * width * groups, channelsPerGroup, 1, groups * channelsPerGroup}; + } + else + { + // Reshape the input from [batch, channels, height, width] to [batch, groups, channelsPerGroup, height * width] + inputShape = {batch, groups, channelsPerGroup, height * width}; + inputStrides = {groups * channelsPerGroup * height * width, channelsPerGroup * height * width, height * width, 1}; + } + TensorDesc inputTensorDesc = TensorDesc(m_inputTensorDescs[0].GetDmlDataType(), inputShape, inputStrides); const DML_TENSOR_DESC inputDmlTensorDesc = inputTensorDesc.GetDmlDesc(); @@ -119,24 +133,36 @@ class DmlOperatorGroupNorm : public DmlOperator uint32_t currentNodeIndex = 0; - const uint32_t transposeInputIndex = currentNodeIndex++; - opDescs.push_back(&dmlTransposeInputDesc); - const uint32_t mvnNodeIndex = currentNodeIndex++; opDescs.push_back(&dmlMvnDesc); - DML_INPUT_GRAPH_EDGE_DESC inputEdge{}; - inputEdge.GraphInputIndex = 0; - inputEdge.ToNodeIndex = transposeInputIndex; - inputEdge.ToNodeInputIndex = 0; - inputEdges.push_back(inputEdge); - - DML_INTERMEDIATE_GRAPH_EDGE_DESC transposeInputToMvnEdge = {}; - transposeInputToMvnEdge.FromNodeIndex = transposeInputIndex; - transposeInputToMvnEdge.FromNodeOutputIndex = 0; - transposeInputToMvnEdge.ToNodeIndex = mvnNodeIndex; - transposeInputToMvnEdge.ToNodeInputIndex = 0; - intermediateEdges.push_back(transposeInputToMvnEdge); + // We only need a transpose the input when the layout is NHWC + if (channelsLast) + { + const uint32_t transposeInputIndex = currentNodeIndex++; + opDescs.push_back(&dmlTransposeInputDesc); + + DML_INPUT_GRAPH_EDGE_DESC inputEdge{}; + inputEdge.GraphInputIndex = 0; + inputEdge.ToNodeIndex = transposeInputIndex; + inputEdge.ToNodeInputIndex = 0; + inputEdges.push_back(inputEdge); + + DML_INTERMEDIATE_GRAPH_EDGE_DESC transposeInputToMvnEdge = {}; + transposeInputToMvnEdge.FromNodeIndex = transposeInputIndex; + transposeInputToMvnEdge.FromNodeOutputIndex = 0; + transposeInputToMvnEdge.ToNodeIndex = mvnNodeIndex; + transposeInputToMvnEdge.ToNodeInputIndex = 0; + intermediateEdges.push_back(transposeInputToMvnEdge); + } + else + { + DML_INPUT_GRAPH_EDGE_DESC inputEdge{}; + inputEdge.GraphInputIndex = 0; + inputEdge.ToNodeIndex = mvnNodeIndex; + inputEdge.ToNodeInputIndex = 0; + inputEdges.push_back(inputEdge); + } if (gammaBetaCastNeeded) { @@ -224,21 +250,33 @@ class DmlOperatorGroupNorm : public DmlOperator } else { - const uint32_t transposeOutputNodeIndex = currentNodeIndex++; - opDescs.push_back(&dmlTransposeOutputDesc); - - DML_INTERMEDIATE_GRAPH_EDGE_DESC mvnToTransposeOutputEdge = {}; - mvnToTransposeOutputEdge.FromNodeIndex = mvnNodeIndex; - mvnToTransposeOutputEdge.FromNodeOutputIndex = 0; - mvnToTransposeOutputEdge.ToNodeIndex = transposeOutputNodeIndex; - mvnToTransposeOutputEdge.ToNodeInputIndex = 0; - intermediateEdges.push_back(mvnToTransposeOutputEdge); - - DML_OUTPUT_GRAPH_EDGE_DESC transposeOutputToOutputEdge{}; - transposeOutputToOutputEdge.FromNodeIndex = transposeOutputNodeIndex; - transposeOutputToOutputEdge.FromNodeOutputIndex = 0; - transposeOutputToOutputEdge.GraphOutputIndex = 0; - outputEdges.push_back(transposeOutputToOutputEdge); + if (channelsLast) + { + // We only need a transpose the output when the layout is NHWC + const uint32_t transposeOutputNodeIndex = currentNodeIndex++; + opDescs.push_back(&dmlTransposeOutputDesc); + + DML_INTERMEDIATE_GRAPH_EDGE_DESC mvnToTransposeOutputEdge = {}; + mvnToTransposeOutputEdge.FromNodeIndex = mvnNodeIndex; + mvnToTransposeOutputEdge.FromNodeOutputIndex = 0; + mvnToTransposeOutputEdge.ToNodeIndex = transposeOutputNodeIndex; + mvnToTransposeOutputEdge.ToNodeInputIndex = 0; + intermediateEdges.push_back(mvnToTransposeOutputEdge); + + DML_OUTPUT_GRAPH_EDGE_DESC transposeOutputToOutputEdge{}; + transposeOutputToOutputEdge.FromNodeIndex = transposeOutputNodeIndex; + transposeOutputToOutputEdge.FromNodeOutputIndex = 0; + transposeOutputToOutputEdge.GraphOutputIndex = 0; + outputEdges.push_back(transposeOutputToOutputEdge); + } + else + { + DML_OUTPUT_GRAPH_EDGE_DESC mvnToOutputEdge{}; + mvnToOutputEdge.FromNodeIndex = mvnNodeIndex; + mvnToOutputEdge.FromNodeOutputIndex = 0; + mvnToOutputEdge.GraphOutputIndex = 0; + outputEdges.push_back(mvnToOutputEdge); + } } MLOperatorGraphDesc operatorGraphDesc = {}; diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorMultiHeadAttention.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorMultiHeadAttention.cpp new file mode 100644 index 0000000000000..9c1a7baeaa8df --- /dev/null +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorMultiHeadAttention.cpp @@ -0,0 +1,281 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "precomp.h" + +namespace Dml +{ +class DmlOperatorMultiHeadAttention : public DmlOperator +{ +public: + DmlOperatorMultiHeadAttention(const MLOperatorKernelCreationContext& kernelCreationContext) + : DmlOperator(kernelCreationContext) + { + enum InputIndex : uint32_t + { + queryIndex, + keyIndex, + valueIndex, + biasIndex, + maskIndex, + relativePositionBiasIndex, + pastKeyIndex, + pastValueIndex, + inputCount, + }; + + enum DmlInputIndex : uint32_t + { + dmlQueryIndex, + dmlKeyIndex, + dmlValueIndex, + dmlStackedQueryKeyIndex, + dmlStackedKeyValueIndex, + dmlStackedQueryKeyValueIndex, + dmlBiasIndex, + dmlMaskIndex, + dmlRelativePositionBiasIndex, + dmlPastKeyIndex, + dmlPastValueIndex, + dmlInputCount, + }; + + enum OutputIndex : uint32_t + { + outputIndex, + outputPresentKeyIndex, + outputPresentValueIndex, + outputCount, + }; + + ML_CHECK_VALID_ARGUMENT(kernelCreationContext.GetInputCount() >= 1); + ML_CHECK_VALID_ARGUMENT(kernelCreationContext.GetOutputCount() >= 1); + + const bool keyValueIsPast = kernelCreationContext.IsInputValid(keyIndex) && kernelCreationContext.GetInputTensorDimensionCount(keyIndex) == 4; + const bool hasValue = kernelCreationContext.IsInputValid(valueIndex) && !keyValueIsPast; + const bool hasBias = kernelCreationContext.IsInputValid(biasIndex); + const bool hasMask = kernelCreationContext.IsInputValid(maskIndex); + const bool hasRelativePositionBias = kernelCreationContext.IsInputValid(relativePositionBiasIndex); + const bool hasPastKey = keyValueIsPast || kernelCreationContext.IsInputValid(pastKeyIndex); + const bool hasPastValue = keyValueIsPast || kernelCreationContext.IsInputValid(pastValueIndex); + const bool hasPresentKeyOutput = kernelCreationContext.IsOutputValid(outputPresentKeyIndex); + const bool hasPresentValueOutput = kernelCreationContext.IsOutputValid(outputPresentValueIndex); + const bool stackedQkv = kernelCreationContext.GetInputTensorDimensionCount(queryIndex) == 5; + const bool stackedKv = kernelCreationContext.IsInputValid(keyIndex) && kernelCreationContext.GetInputTensorDimensionCount(keyIndex) == 5; + const bool hasKey = !stackedKv && !keyValueIsPast && kernelCreationContext.IsInputValid(keyIndex); + + std::vector> inputIndices = { + stackedQkv ? std::nullopt : std::optional(queryIndex), + hasKey ? std::optional(keyIndex) : std::nullopt, + hasValue ? std::optional(valueIndex) : std::nullopt, + std::nullopt, + stackedKv ? std::optional(keyIndex) : std::nullopt, + stackedQkv ? std::optional(queryIndex) : std::nullopt, + biasIndex, + hasMask ? std::optional(maskIndex) : std::nullopt, + relativePositionBiasIndex, + keyValueIsPast ? keyIndex : pastKeyIndex, + keyValueIsPast ? valueIndex : pastValueIndex, + }; + + std::vector> outputIndices = { + outputIndex, + outputPresentKeyIndex, + outputPresentValueIndex, + }; + DmlOperator::Initialize(kernelCreationContext, inputIndices, outputIndices, std::nullopt, std::nullopt, 1); + + ML_CHECK_VALID_ARGUMENT(!stackedQkv || m_inputTensorDescs[dmlStackedQueryKeyValueIndex].GetDimensionCount() == 5); + ML_CHECK_VALID_ARGUMENT(stackedQkv || m_inputTensorDescs[dmlQueryIndex].GetDimensionCount() == 3); + ML_CHECK_VALID_ARGUMENT(!hasKey || m_inputTensorDescs[dmlKeyIndex].GetDimensionCount() == 3); + ML_CHECK_VALID_ARGUMENT(!hasValue || m_inputTensorDescs[dmlValueIndex].GetDimensionCount() == 3); + ML_CHECK_VALID_ARGUMENT(!hasPastKey || m_inputTensorDescs[dmlPastKeyIndex].GetDimensionCount() == 4); + ML_CHECK_VALID_ARGUMENT(!hasPastValue || m_inputTensorDescs[dmlPastValueIndex].GetDimensionCount() == 4); + + const uint32_t batchSize = stackedQkv + ? m_inputTensorDescs[dmlStackedQueryKeyValueIndex].GetSizes()[0] + : m_inputTensorDescs[dmlQueryIndex].GetSizes()[0]; + + const uint32_t numHeads = gsl::narrow_cast(kernelCreationContext.GetAttribute(AttrName::NumHeads)); + const uint32_t headSize = stackedQkv + ? m_inputTensorDescs[dmlStackedQueryKeyValueIndex].GetSizes()[4] + : m_inputTensorDescs[dmlQueryIndex].GetSizes()[2] / numHeads; + + const uint32_t sequenceLength = stackedQkv + ? m_inputTensorDescs[dmlStackedQueryKeyValueIndex].GetSizes()[1] + : m_inputTensorDescs[dmlQueryIndex].GetSizes()[1]; + + uint32_t kvSequenceLength; + if (hasKey) + { + kvSequenceLength = m_inputTensorDescs[dmlKeyIndex].GetSizes()[1]; + } + else if (stackedKv) + { + kvSequenceLength = m_inputTensorDescs[dmlStackedKeyValueIndex].GetSizes()[1]; + } + else if (hasPastKey) + { + kvSequenceLength = m_inputTensorDescs[dmlPastKeyIndex].GetSizes()[2]; + } + else + { + kvSequenceLength = sequenceLength; + } + + const uint32_t hiddenSize = numHeads * headSize; + const uint32_t vHiddenSize = hasValue ? m_inputTensorDescs[dmlValueIndex].GetSizes()[2] : hiddenSize; + const uint32_t pastSequenceLength = hasPastKey ? m_inputTensorDescs[dmlPastKeyIndex].GetSizes()[2] : 0; + const uint32_t totalSequenceLength = kvSequenceLength + pastSequenceLength; + + if (stackedQkv) + { + auto stackedQkvSizes = m_inputTensorDescs[dmlStackedQueryKeyValueIndex].GetSizes(); + ML_CHECK_VALID_ARGUMENT(stackedQkvSizes[0] == batchSize); + ML_CHECK_VALID_ARGUMENT(stackedQkvSizes[1] == sequenceLength); + ML_CHECK_VALID_ARGUMENT(stackedQkvSizes[2] == numHeads); + ML_CHECK_VALID_ARGUMENT(stackedQkvSizes[3] == 3); + ML_CHECK_VALID_ARGUMENT(stackedQkvSizes[4] == headSize); + } + else + { + auto querySizes = m_inputTensorDescs[dmlQueryIndex].GetSizes(); + ML_CHECK_VALID_ARGUMENT(querySizes[0] == batchSize); + ML_CHECK_VALID_ARGUMENT(querySizes[1] == sequenceLength); + ML_CHECK_VALID_ARGUMENT(querySizes[2] == hiddenSize); + } + + if (hasKey) + { + ML_CHECK_VALID_ARGUMENT(m_inputTensorDescs[dmlKeyIndex].GetDimensionCount() == 3); + + auto keySizes = m_inputTensorDescs[dmlKeyIndex].GetSizes(); + ML_CHECK_VALID_ARGUMENT(keySizes[0] == batchSize); + ML_CHECK_VALID_ARGUMENT(keySizes[1] == kvSequenceLength); + ML_CHECK_VALID_ARGUMENT(keySizes[2] == hiddenSize); + } + + if (hasValue) + { + auto valueSizes = m_inputTensorDescs[dmlValueIndex].GetSizes(); + ML_CHECK_VALID_ARGUMENT(valueSizes[0] == batchSize); + ML_CHECK_VALID_ARGUMENT(valueSizes[1] == kvSequenceLength); + ML_CHECK_VALID_ARGUMENT(valueSizes[2] == vHiddenSize); + } + + if (stackedKv) + { + ML_CHECK_VALID_ARGUMENT(m_inputTensorDescs[dmlStackedKeyValueIndex].GetDimensionCount() == 5); + + auto stackedKvSizes = m_inputTensorDescs[dmlStackedKeyValueIndex].GetSizes(); + ML_CHECK_VALID_ARGUMENT(stackedKvSizes[0] == batchSize); + ML_CHECK_VALID_ARGUMENT(stackedKvSizes[1] == kvSequenceLength); + ML_CHECK_VALID_ARGUMENT(stackedKvSizes[2] == numHeads); + ML_CHECK_VALID_ARGUMENT(stackedKvSizes[3] == 2); + ML_CHECK_VALID_ARGUMENT(stackedKvSizes[4] == headSize); + } + + if (hasBias) + { + ML_CHECK_VALID_ARGUMENT(m_inputTensorDescs[dmlBiasIndex].GetDimensionCount() == 1); + ML_CHECK_VALID_ARGUMENT(m_inputTensorDescs[dmlBiasIndex].GetSizes()[0] == hiddenSize + hiddenSize + vHiddenSize); + } + + DML_MULTIHEAD_ATTENTION_MASK_TYPE maskType = DML_MULTIHEAD_ATTENTION_MASK_TYPE_NONE; + if (hasMask) + { + if (kernelCreationContext.GetInputTensorDimensionCount(maskIndex) == 1) + { + const auto unpaddedKeyBoundsShape = m_inputTensorDescs[dmlMaskIndex].GetSizes(); + ML_CHECK_VALID_ARGUMENT(unpaddedKeyBoundsShape.size() == 1); + ML_CHECK_VALID_ARGUMENT(unpaddedKeyBoundsShape[0] == batchSize || unpaddedKeyBoundsShape[0] == batchSize * 3 + 2); + + maskType = unpaddedKeyBoundsShape[0] == batchSize + ? DML_MULTIHEAD_ATTENTION_MASK_TYPE_KEY_SEQUENCE_LENGTH + : DML_MULTIHEAD_ATTENTION_MASK_TYPE_KEY_QUERY_SEQUENCE_LENGTH_START_END; + + if (maskType == DML_MULTIHEAD_ATTENTION_MASK_TYPE_KEY_SEQUENCE_LENGTH) + { + uint32_t desiredShape[2] = {1, batchSize}; + m_inputTensorDescs[dmlMaskIndex] = TensorDesc( + m_inputTensorDescs[dmlMaskIndex].GetDmlDataType(), + desiredShape); + } + } + else + { + const auto keyPaddingMaskTensorShape = m_inputTensorDescs[dmlMaskIndex].GetSizes(); + ML_CHECK_VALID_ARGUMENT(keyPaddingMaskTensorShape.size() == 2); + ML_CHECK_VALID_ARGUMENT(keyPaddingMaskTensorShape[0] == batchSize); + ML_CHECK_VALID_ARGUMENT(keyPaddingMaskTensorShape[1] == kvSequenceLength); + + const uint32_t actualShape[4] = {batchSize, 1, 1, kvSequenceLength}; + const uint32_t desiredShape[4] = {batchSize, numHeads, sequenceLength, kvSequenceLength}; + + m_inputTensorDescs[dmlMaskIndex] = TensorDesc::ConstructBroadcastedTensorDesc( + m_inputTensorDescs[dmlMaskIndex].GetMlOperatorDataType(), + desiredShape, + actualShape); + + maskType = DML_MULTIHEAD_ATTENTION_MASK_TYPE_BOOLEAN; + } + } + + if (hasRelativePositionBias) + { + ML_CHECK_VALID_ARGUMENT(m_inputTensorDescs[dmlRelativePositionBiasIndex].GetDimensionCount() == 4); + + auto relativePositionBiasSizes = m_inputTensorDescs[dmlRelativePositionBiasIndex].GetSizes(); + ML_CHECK_VALID_ARGUMENT(relativePositionBiasSizes[0] == batchSize); + ML_CHECK_VALID_ARGUMENT(relativePositionBiasSizes[1] == numHeads); + ML_CHECK_VALID_ARGUMENT(relativePositionBiasSizes[2] == sequenceLength); + ML_CHECK_VALID_ARGUMENT(relativePositionBiasSizes[3] == totalSequenceLength); + } + + if (hasPastKey) + { + auto pastKeySizes = m_inputTensorDescs[dmlPastKeyIndex].GetSizes(); + ML_CHECK_VALID_ARGUMENT(pastKeySizes[0] == batchSize); + ML_CHECK_VALID_ARGUMENT(pastKeySizes[1] == numHeads); + ML_CHECK_VALID_ARGUMENT(pastKeySizes[2] == pastSequenceLength); + ML_CHECK_VALID_ARGUMENT(pastKeySizes[3] == headSize); + } + + if (hasPastValue) + { + auto pastValueSizes = m_inputTensorDescs[dmlPastValueIndex].GetSizes(); + ML_CHECK_VALID_ARGUMENT(pastValueSizes[0] == batchSize); + ML_CHECK_VALID_ARGUMENT(pastValueSizes[1] == numHeads); + ML_CHECK_VALID_ARGUMENT(pastValueSizes[2] == pastSequenceLength); + ML_CHECK_VALID_ARGUMENT(pastValueSizes[3] == headSize); + } + + std::vector inputDescs = GetDmlInputDescs(); + std::vector outputDescs = GetDmlOutputDescs(); + + DML_MULTIHEAD_ATTENTION_OPERATOR_DESC mhaDesc = {}; + mhaDesc.QueryTensor = stackedQkv ? nullptr : &inputDescs[dmlQueryIndex]; + mhaDesc.KeyTensor = hasKey ? &inputDescs[dmlKeyIndex] : nullptr; + mhaDesc.ValueTensor = hasValue ? &inputDescs[dmlValueIndex] : nullptr; + mhaDesc.StackedKeyValueTensor = stackedKv ? &inputDescs[dmlStackedKeyValueIndex] : nullptr; + mhaDesc.StackedQueryKeyValueTensor = stackedQkv ? &inputDescs[dmlStackedQueryKeyValueIndex] : nullptr; + mhaDesc.BiasTensor = hasBias ? &inputDescs[dmlBiasIndex] : nullptr; + mhaDesc.MaskTensor = hasMask ? &inputDescs[dmlMaskIndex] : nullptr; + mhaDesc.RelativePositionBiasTensor = hasRelativePositionBias ? &inputDescs[dmlRelativePositionBiasIndex] : nullptr; + mhaDesc.PastKeyTensor = hasPastKey ? &inputDescs[dmlPastKeyIndex] : nullptr; + mhaDesc.PastValueTensor = hasPastValue ? &inputDescs[dmlPastValueIndex] : nullptr; + mhaDesc.OutputTensor = &outputDescs[outputIndex]; + mhaDesc.OutputPresentKeyTensor = hasPresentKeyOutput ? &outputDescs[outputPresentKeyIndex] : nullptr; + mhaDesc.OutputPresentValueTensor = hasPresentValueOutput ? &outputDescs[outputPresentValueIndex] : nullptr; + mhaDesc.Scale = kernelCreationContext.GetOptionalAttribute(AttrName::Scale, gsl::narrow_cast(1.0f / std::sqrt(headSize))); + mhaDesc.MaskFilterValue = kernelCreationContext.GetOptionalAttribute(AttrName::MaskFilterValue, -10'000.0f); + mhaDesc.HeadCount = numHeads; + mhaDesc.MaskType = maskType; + + DML_OPERATOR_DESC opDesc = { DML_OPERATOR_MULTIHEAD_ATTENTION, &mhaDesc }; + SetDmlOperatorDesc(opDesc, kernelCreationContext); + } +}; + +DML_OP_DEFINE_CREATION_FUNCTION(MultiHeadAttention, DmlOperatorMultiHeadAttention); +} // namespace Dml diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorNonZero.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorNonZero.cpp index 62374963fff1b..bc29256dd2e28 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorNonZero.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorNonZero.cpp @@ -65,10 +65,6 @@ class DmlOperatorNonZero: public DmlOperator nonzeroCoordinatesDesc.OutputCountTensor = &intermediateDescs[0]; nonzeroCoordinatesDesc.OutputCoordinatesTensor = &intermediateDescs[1]; - // TODO: Remove this hack when DML supports native int64 for NonZero - // We use the int64/uint32 stride hack here, so zero out the data before writing to it - m_zeroOperator = InitializeZeroInt64Tensor(m_intermediateTensorDescs[1].GetBufferSizeInBytes()); - DML_OPERATOR_DESC opDesc = { DML_OPERATOR_NONZERO_COORDINATES, &nonzeroCoordinatesDesc }; SetDmlOperatorDesc(opDesc, kernelCreationContext); } @@ -127,7 +123,12 @@ class DmlOperatorNonZero: public DmlOperator if (!m_emptyInput && nonzeroElementCount > 0) { // TODO: Remove this hack when DML supports native int64 for NonZero - ExecuteZeroInt64Tensor(m_zeroOperator.Get(), outputTensor.GetInterface().Get()); + // We use the int64/uint32 stride hack here, so zero out the data before writing to it + uint64_t tensorSizeInBytes = uint64_t(m_rank) * uint64_t(nonzeroElementCount) * sizeof(int64_t); + ComPtr zeroOperator = InitializeZeroInt64Tensor(tensorSizeInBytes); + + // TODO: Remove this hack when DML supports native int64 for NonZero + ExecuteZeroInt64Tensor(zeroOperator.Get(), outputTensor.GetInterface().Get()); ComPtr sliceOperator = InitializeSlice(m_intermediateTensorDescs[1], nonzeroElementCount); @@ -182,7 +183,6 @@ class DmlOperatorNonZero: public DmlOperator std::vector m_intermediateTensorDescs; onnxruntime::TensorShape m_outputCountShape; onnxruntime::TensorShape m_outputCoordinatesShape; - ComPtr m_zeroOperator; bool m_emptyInput = false; uint32_t m_rank = 0; }; diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorPadding.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorPadding.cpp index 84046f74eacf3..a014db5adbe61 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorPadding.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorPadding.cpp @@ -15,7 +15,7 @@ class DmlOperatorPadding : public DmlOperator, public PaddingHelper { const uint32_t inputCount = kernelInfo.GetInputCount(); ML_CHECK_VALID_ARGUMENT((opsetVersion >= 2 && opsetVersion < 11 && inputCount == 1) - || (opsetVersion >= 11 && inputCount >= 2 && inputCount <= 3)); + || (opsetVersion >= 11 && inputCount >= 2 && inputCount <= 4)); ML_CHECK_VALID_ARGUMENT(kernelInfo.GetOutputCount() == 1); std::vector> kernelInputIndices = { 0 }; // Only bind GPU to first 'data' tensor. @@ -68,12 +68,12 @@ class DmlOperatorPadding : public DmlOperator, public PaddingHelper paddingDesc.EndPadding = m_endPadding.data(); // PaddingValueDataType will always be equal to inputDataTensorDataType // Assigning paddingValueDataType to inputDataTensorDataType because this field - // has to be assigned even if program does not go through below conditional + // has to be assigned even if program does not go through below conditional // logic for some corner test case (like opsetVersion >= 11, but no validInput at index 2) // Same applies to paddingValue. paddingDesc.PaddingValueDataType = this->m_inputTensorDescs[0].GetDmlDataType(); CastToClampedScalarUnion(paddingDesc.PaddingValueDataType, 0.0f, /*out*/&paddingDesc.PaddingValue); - + // Read the constant value which can come from an attribute or tensor. if (opsetVersion >= 11) { @@ -107,7 +107,7 @@ void CALLBACK QueryPad(IMLOperatorSupportQueryContextPrivate* context, /*out*/ b *isSupported = true; MLOperatorAttributes attributes(context); - + std::vector padding = attributes.GetOptionalAttributeVectorInt32(AttrName::Pads); *isSupported = std::none_of(padding.begin(), padding.end(), [](int32_t padCount) {return padCount < 0; }); } @@ -115,5 +115,6 @@ void CALLBACK QueryPad(IMLOperatorSupportQueryContextPrivate* context, /*out*/ b DML_OP_DEFINE_CREATION_FUNCTION(Pad7, VersionedKernel); DML_OP_DEFINE_CREATION_FUNCTION(Pad11, VersionedKernel); DML_OP_DEFINE_CREATION_FUNCTION(Pad13, VersionedKernel); +DML_OP_DEFINE_CREATION_FUNCTION(Pad18, VersionedKernel); } // namespace Dml diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorRoiAlign.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorRoiAlign.cpp index c3a25ca8d464e..892efca3058d4 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorRoiAlign.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorRoiAlign.cpp @@ -29,14 +29,25 @@ class DmlOperatorRegionOfInterestAlign : public DmlOperator, public RoiAlignHelp {"max", DML_REDUCE_FUNCTION_MAX}, {"avg", DML_REDUCE_FUNCTION_AVERAGE}, }; + + constexpr NameAndIndex coordinateTransformationModes[] = + { + {"half_pixel", 0}, + {"output_half_pixel", 1}, + }; + + std::string coordinateTransformationMode = kernelCreationContext.GetOptionalAttribute(AttrName::CoordinateTransformationMode, "half_pixel"); + auto optionalCoordinateTransformationModeValue = TryMapStringToIndex(coordinateTransformationMode, coordinateTransformationModes); const std::string mode = kernelCreationContext.GetOptionalAttribute(AttrName::Mode, "avg"); const auto optionalReductionFunction = TryMapStringToIndex(mode, mapping); const float spatialScale = kernelCreationContext.GetOptionalAttribute(AttrName::SpatialScale, 1.0f); const int32_t samplesPerOutput = kernelCreationContext.GetOptionalAttribute(AttrName::SamplingRatio, 0u); ML_CHECK_VALID_ARGUMENT(samplesPerOutput >= 0, "sampling_ratio must be 0 or positive."); ML_CHECK_VALID_ARGUMENT(!!optionalReductionFunction, "Unsupported RoiAlign mode."); + ML_CHECK_VALID_ARGUMENT(!!optionalCoordinateTransformationModeValue, "Unsupported RoiAlign coordinate_transformation_mode."); + - DML_ROI_ALIGN_OPERATOR_DESC operatorDesc = {}; + DML_ROI_ALIGN1_OPERATOR_DESC operatorDesc = {}; operatorDesc.InputTensor = &inputDescs[0]; operatorDesc.ROITensor = &inputDescs[1]; operatorDesc.BatchIndicesTensor = &inputDescs[2]; @@ -48,12 +59,15 @@ class DmlOperatorRegionOfInterestAlign : public DmlOperator, public RoiAlignHelp operatorDesc.MaximumSamplesPerOutput = (samplesPerOutput == 0) ? UINT32_MAX : samplesPerOutput; operatorDesc.ReductionFunction = *optionalReductionFunction; operatorDesc.InterpolationMode = DML_INTERPOLATION_MODE_LINEAR; - DML_OPERATOR_DESC opDesc = { DML_OPERATOR_ROI_ALIGN, &operatorDesc }; + operatorDesc.InputPixelOffset = (*optionalCoordinateTransformationModeValue == 0)? 0.5f : 0.0f; + operatorDesc.OutputPixelOffset = -0.5f; + DML_OPERATOR_DESC opDesc = { DML_OPERATOR_ROI_ALIGN1, &operatorDesc }; SetDmlOperatorDesc(opDesc, kernelCreationContext); } }; DML_OP_DEFINE_CREATION_FUNCTION(RoiAlign10, VersionedKernel); +DML_OP_DEFINE_CREATION_FUNCTION(RoiAlign16, VersionedKernel); } // namespace Dml diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorSkipLayerNormalization.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorSkipLayerNormalization.cpp index 5d527508606e2..4dafd78f21ea8 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorSkipLayerNormalization.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorSkipLayerNormalization.cpp @@ -15,21 +15,50 @@ class DmlOperatorSkipLayerNormalization : public DmlOperator std::vector> kernelInputIndices = {0, 1, 2, 3, 4}; std::vector> kernelOutputIndices = {0, 1, 2, 3}; - DmlOperator::Initialize( + const auto inputShape = kernelCreationContext.GetTensorShapeDescription().GetInputTensorShape(0); + ML_CHECK_VALID_ARGUMENT(inputShape.size() == 2 || inputShape.size() == 3); + const uint32_t batchSize = inputShape[0]; + const uint32_t sequenceLength = inputShape.size() == 3 ? inputShape[1] : 1; + const uint32_t hiddenSize = inputShape.back(); + + std::array tensorShape = {batchSize, sequenceLength, hiddenSize, 1}; + std::array vectorShape = {1, 1, hiddenSize, 1}; + std::array scalarShape = {1, 1, 1, 1}; + + std::array, 5> inputShapes = { + tensorShape, + tensorShape, + vectorShape, + vectorShape, + vectorShape, + }; + + std::array, 4> outputShapes = { + tensorShape, + scalarShape, + scalarShape, + tensorShape, + }; + + DmlOperator::InitializeWithShapes( kernelCreationContext, kernelInputIndices, kernelOutputIndices, - kernelCreationContext.GetTensorShapeDescription().GetInputTensorShape(0), - std::nullopt, - kernelCreationContext.GetTensorShapeDescription().GetInputTensorDimensionCount(0)); + inputShapes, + outputShapes); - const float epsilon = kernelCreationContext.GetOptionalAttribute(AttrName::Epsilon, DefaultEpsilon); + if (m_inputTensorDescs[4].GetDmlDataType() != DML_TENSOR_TYPE_INVALID) + { + // The needs to be broadcasted since it's not used as part of MVN + std::array biasStrides = {0, 0, 1, 0}; + m_inputTensorDescs[4] = TensorDesc( + m_inputTensorDescs[0].GetDmlDataType(), + m_inputTensorDescs[0].GetSizes(), + biasStrides); + } - int32_t onnxAxis = kernelCreationContext.GetOptionalAttribute(AttrName::Axis, -1); - uint32_t inputDimCount = kernelCreationContext.GetTensorShapeDescription().GetInputTensorDimensionCount(0); - onnxAxis = OperatorHelper::HandleNegativeAxis(onnxAxis, inputDimCount); - std::vector onnxAxes(static_cast(inputDimCount) - static_cast(onnxAxis)); - std::iota(onnxAxes.begin(), onnxAxes.end(), onnxAxis); + const float epsilon = kernelCreationContext.GetOptionalAttribute(AttrName::Epsilon, DefaultEpsilon); + std::array axes = {2, 3}; assert(m_inputTensorDescs.size() == 5); assert(m_outputTensorDescs.size() == 4); @@ -42,28 +71,25 @@ class DmlOperatorSkipLayerNormalization : public DmlOperator auto outputDesc = m_outputTensorDescs[0].GetDmlDesc(); auto inputSkipBiasSum = m_outputTensorDescs[3].GetDmlDesc(); - TensorDesc inputSkipBiasTensorDesc(m_inputTensorDescs[0].GetDmlDataType(), m_inputTensorDescs[0].GetSizes()); - DML_TENSOR_DESC inputSkipBiasDmlTensorDesc = inputSkipBiasTensorDesc.GetDmlDesc(); - DML_ELEMENT_WISE_ADD_OPERATOR_DESC inputSkipAddDesc = {}; inputSkipAddDesc.ATensor = &inputDesc; inputSkipAddDesc.BTensor = &skipDesc; - inputSkipAddDesc.OutputTensor = &inputSkipBiasDmlTensorDesc; + inputSkipAddDesc.OutputTensor = &inputDesc; DML_OPERATOR_DESC inputSkipAddOpDesc = { DML_OPERATOR_ELEMENT_WISE_ADD, &inputSkipAddDesc }; DML_ELEMENT_WISE_ADD_OPERATOR_DESC inputSkipBiasAddDesc = {}; - inputSkipBiasAddDesc.ATensor = &inputSkipBiasDmlTensorDesc; + inputSkipBiasAddDesc.ATensor = &inputDesc; inputSkipBiasAddDesc.BTensor = &biasDesc; - inputSkipBiasAddDesc.OutputTensor = &inputSkipBiasDmlTensorDesc; + inputSkipBiasAddDesc.OutputTensor = &inputDesc; DML_OPERATOR_DESC inputSkipBiasAddOpDesc = { DML_OPERATOR_ELEMENT_WISE_ADD, &inputSkipBiasAddDesc }; DML_MEAN_VARIANCE_NORMALIZATION1_OPERATOR_DESC mvnDesc = {}; - mvnDesc.InputTensor = &inputSkipBiasDmlTensorDesc; + mvnDesc.InputTensor = &inputDesc; mvnDesc.ScaleTensor = &gammaDesc; mvnDesc.BiasTensor = betaDesc.Desc ? &betaDesc : nullptr; mvnDesc.OutputTensor = &outputDesc; - mvnDesc.Axes = onnxAxes.data(); - mvnDesc.AxisCount = gsl::narrow_cast(onnxAxes.size()); + mvnDesc.Axes = axes.data(); + mvnDesc.AxisCount = gsl::narrow_cast(axes.size()); mvnDesc.NormalizeVariance = true; mvnDesc.Epsilon = epsilon; mvnDesc.FusedActivation = nullptr; diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorSplit.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorSplit.cpp index df99a83c7cce5..638d31c82cd15 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorSplit.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorSplit.cpp @@ -44,5 +44,6 @@ class DmlOperatorSplit : public DmlOperator, public SplitHelper DML_OP_DEFINE_CREATION_FUNCTION(Split7, VersionedKernel); DML_OP_DEFINE_CREATION_FUNCTION(Split11, VersionedKernel); DML_OP_DEFINE_CREATION_FUNCTION(Split13, VersionedKernel); +DML_OP_DEFINE_CREATION_FUNCTION(Split18, VersionedKernel); } // namespace Dml diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlSTFT.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlSTFT.h index cca4911028ed9..15dcf4fb174fb 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlSTFT.h +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlSTFT.h @@ -99,13 +99,6 @@ struct DmlSTFTParameters ML_CHECK_VALID_ARGUMENT(this->frameSize > 0, "Either the window or frame_length must be set."); - // This limitation is a result of GpuDFTOperator in DmlDFT.h only implementing the stockham path. - // Remove this check if GpuDFTOperator is updated to support BluesteinZChirp. - ML_CHECK_VALID_ARGUMENT( - DFTHelpers::IsPowerOfTwo(this->frameSize), - "DML STFT only supports power-of-two window/frame sizes." - ); - this->frameCount = (this->signalSize - this->frameSize) / this->frameStep + 1; this->frameDftElementCount = this->isOnesided ? this->frameSize / 2 + 1 : this->frameSize; } diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/GeneratedShaders/GenerateShaders.bat b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/GeneratedShaders/GenerateShaders.bat index 600c4a63cc897..fb087bd800ff0 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/GeneratedShaders/GenerateShaders.bat +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/GeneratedShaders/GenerateShaders.bat @@ -2,9 +2,83 @@ if "%1" == "DEBUG" ( echo "WARNING: Compiling shaders for DEBUG configuration; do not check generated header files into the repo!" - fxc.exe ..\Shaders\stockham.hlsl -E DFT -T cs_5_0 /DTBUFFER=float /Zi /Od /Fh stockham.h - dxc.exe ..\Shaders\stockham.hlsl -E DFT -T cs_6_2 -DTBUFFER=float16_t -enable-16bit-types -Zi -Od -Qembed_debug -Fh stockham_fp16.h + fxc.exe ..\Shaders\stockham.hlsl -E DFT -T cs_5_0 /DTBUFFER=float /Zi /Od /Fh stockham.h + dxc.exe ..\Shaders\stockham.hlsl -E DFT -T cs_6_2 -DTBUFFER=float16_t -enable-16bit-types -Zi -Od -Qembed_debug -Fh stockham_fp16.h + + fxc.exe ..\Shaders\bluestein_chirp.hlsl -E BluesteinZChirp -T cs_5_0 /DTBUFFER=float /Zi /Od /Fh bluestein_chirp.h + dxc.exe ..\Shaders\bluestein_chirp.hlsl -E BluesteinZChirp -T cs_6_2 -DTBUFFER=float16_t -enable-16bit-types -Zi -Od -Qembed_debug -Fh bluestein_chirp_fp16.h + + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=uint16_t -DTBUFFER2=float -enable-16bit-types -Zi -Od -Qembed_debug -Fh grid_sample_uint16_float.h + fxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_5_0 /DTBUFFER1=uint /DTBUFFER2=float /Zi /Od /Fh grid_sample_uint_float.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=uint64_t -DTBUFFER2=float -enable-16bit-types -Zi -Od -Qembed_debug -Fh grid_sample_uint64_float.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=int16_t -DTBUFFER2=float -enable-16bit-types -Zi -Od -Qembed_debug -Fh grid_sample_int16_float.h + fxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_5_0 /DTBUFFER1=int /DTBUFFER2=float /Zi /Od /Fh grid_sample_int_float.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=int64_t -DTBUFFER2=float -enable-16bit-types -Zi -Od -Qembed_debug -Fh grid_sample_int64_float.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=float16_t -DTBUFFER2=float -enable-16bit-types -Zi -Od -Qembed_debug -Fh grid_sample_fp16_float.h + fxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_5_0 /DTBUFFER1=float /DTBUFFER2=float /Zi /Od /Fh grid_sample_float_float.h + fxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_5_0 /DTBUFFER1=double /DTBUFFER2=float /Zi /Od /Fh grid_sample_double_float.h + fxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_5_0 /DTBUFFER1=bool /DTBUFFER2=float /Zi /Od /Fh grid_sample_bool_float.h + + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=uint16_t -DTBUFFER2=float16_t -enable-16bit-types -Zi -Od -Qembed_debug -Fh grid_sample_uint16_fp16.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=uint -DTBUFFER2=float16_t -enable-16bit-types -Zi -Od -Qembed_debug -Fh grid_sample_uint_fp16.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=uint64_t -DTBUFFER2=float16_t -enable-16bit-types -Zi -Od -Qembed_debug -Fh grid_sample_uint64_fp16.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=int16_t -DTBUFFER2=float16_t -enable-16bit-types -Zi -Od -Qembed_debug -Fh grid_sample_int16_fp16.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=int -DTBUFFER2=float16_t -enable-16bit-types -Zi -Od -Qembed_debug -Fh grid_sample_int_fp16.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=int64_t -DTBUFFER2=float16_t -enable-16bit-types -Zi -Od -Qembed_debug -Fh grid_sample_int64_fp16.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=float16_t -DTBUFFER2=float16_t -enable-16bit-types -Zi -Od -Qembed_debug -Fh grid_sample_fp16_fp16.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=float -DTBUFFER2=float16_t -enable-16bit-types -Zi -Od -Qembed_debug -Fh grid_sample_float_fp16.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=double -DTBUFFER2=float16_t -enable-16bit-types -Zi -Od -Qembed_debug -Fh grid_sample_double_fp16.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=bool -DTBUFFER2=float16_t -enable-16bit-types -Zi -Od -Qembed_debug -Fh grid_sample_bool_fp16.h + + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=uint16_t -DTBUFFER2=double -enable-16bit-types -Zi -Od -Qembed_debug -Fh grid_sample_uint16_double.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=uint -DTBUFFER2=double -enable-16bit-types -Zi -Od -Qembed_debug -Fh grid_sample_uint_double.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=uint64_t -DTBUFFER2=double -enable-16bit-types -Zi -Od -Qembed_debug -Fh grid_sample_uint64_double.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=int16_t -DTBUFFER2=double -enable-16bit-types -Zi -Od -Qembed_debug -Fh grid_sample_int16_double.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=int -DTBUFFER2=double -enable-16bit-types -Zi -Od -Qembed_debug -Fh grid_sample_int_double.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=int64_t -DTBUFFER2=double -enable-16bit-types -Zi -Od -Qembed_debug -Fh grid_sample_int64_double.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=float16_t -DTBUFFER2=double -enable-16bit-types -Zi -Od -Qembed_debug -Fh grid_sample_fp16_double.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=float -DTBUFFER2=double -enable-16bit-types -Zi -Od -Qembed_debug -Fh grid_sample_float_double.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=double -DTBUFFER2=double -enable-16bit-types -Zi -Od -Qembed_debug -Fh grid_sample_double_double.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=bool -DTBUFFER2=double -enable-16bit-types -Zi -Od -Qembed_debug -Fh grid_sample_bool_double.h + ) else ( - fxc.exe ..\Shaders\stockham.hlsl -E DFT -T cs_5_0 /DTBUFFER=float /O3 /Qstrip_reflect /Qstrip_debug /Qstrip_rootsignature /Qstrip_priv /Fh stockham.h - dxc.exe ..\Shaders\stockham.hlsl -E DFT -T cs_6_2 -DTBUFFER=float16_t -enable-16bit-types -O3 -Qstrip_reflect -Qstrip_debug -Qstrip_rootsignature -Fh stockham_fp16.h -) \ No newline at end of file + fxc.exe ..\Shaders\stockham.hlsl -E DFT -T cs_5_0 /DTBUFFER=float /O3 /Qstrip_reflect /Qstrip_debug /Qstrip_rootsignature /Qstrip_priv /Fh stockham.h + dxc.exe ..\Shaders\stockham.hlsl -E DFT -T cs_6_2 -DTBUFFER=float16_t -enable-16bit-types -O3 -Qstrip_reflect -Qstrip_debug -Qstrip_rootsignature -Fh stockham_fp16.h + + fxc.exe ..\Shaders\bluestein_chirp.hlsl -E BluesteinZChirp -T cs_5_0 /DTBUFFER=float /O3 /Qstrip_reflect /Qstrip_debug /Qstrip_rootsignature /Qstrip_priv /Fh bluestein_chirp.h + dxc.exe ..\Shaders\bluestein_chirp.hlsl -E BluesteinZChirp -T cs_6_2 -DTBUFFER=float16_t -enable-16bit-types -O3 -Qstrip_reflect -Qstrip_debug -Qstrip_rootsignature -Fh bluestein_chirp_fp16.h + + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=uint16_t -DTBUFFER2=float -enable-16bit-types -O3 -Qstrip_reflect -Qstrip_debug -Qstrip_rootsignature -Fh grid_sample_uint16_float.h + fxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_5_0 /DTBUFFER1=uint /DTBUFFER2=float /O3 /Qstrip_reflect /Qstrip_debug /Qstrip_rootsignature /Qstrip_priv /Fh grid_sample_uint_float.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=uint64_t -DTBUFFER2=float -enable-16bit-types -O3 -Qstrip_reflect -Qstrip_debug -Qstrip_rootsignature -Fh grid_sample_uint64_float.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=int16_t -DTBUFFER2=float -enable-16bit-types -O3 -Qstrip_reflect -Qstrip_debug -Qstrip_rootsignature -Fh grid_sample_int16_float.h + fxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_5_0 /DTBUFFER1=int /DTBUFFER2=float /O3 /Qstrip_reflect /Qstrip_debug /Qstrip_rootsignature /Qstrip_priv /Fh grid_sample_int_float.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=int64_t -DTBUFFER2=float -enable-16bit-types -O3 -Qstrip_reflect -Qstrip_debug -Qstrip_rootsignature -Fh grid_sample_int64_float.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=float16_t -DTBUFFER2=float -enable-16bit-types -O3 -Qstrip_reflect -Qstrip_debug -Qstrip_rootsignature -Fh grid_sample_fp16_float.h + fxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_5_0 /DTBUFFER1=float /DTBUFFER2=float /O3 /Qstrip_reflect /Qstrip_debug /Qstrip_rootsignature /Qstrip_priv /Fh grid_sample_float_float.h + fxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_5_0 /DTBUFFER1=double /DTBUFFER2=float /O3 /Qstrip_reflect /Qstrip_debug /Qstrip_rootsignature /Qstrip_priv /Fh grid_sample_double_float.h + fxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_5_0 /DTBUFFER1=bool /DTBUFFER2=float /O3 /Qstrip_reflect /Qstrip_debug /Qstrip_rootsignature /Qstrip_priv /Fh grid_sample_bool_float.h + + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=uint16_t -DTBUFFER2=float16_t -enable-16bit-types -O3 -Qstrip_reflect -Qstrip_debug -Qstrip_rootsignature -Fh grid_sample_uint16_fp16.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=uint -DTBUFFER2=float16_t -enable-16bit-types -O3 -Qstrip_reflect -Qstrip_debug -Qstrip_rootsignature -Fh grid_sample_uint_fp16.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=uint64_t -DTBUFFER2=float16_t -enable-16bit-types -O3 -Qstrip_reflect -Qstrip_debug -Qstrip_rootsignature -Fh grid_sample_uint64_fp16.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=int16_t -DTBUFFER2=float16_t -enable-16bit-types -O3 -Qstrip_reflect -Qstrip_debug -Qstrip_rootsignature -Fh grid_sample_int16_fp16.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=int -DTBUFFER2=float16_t -enable-16bit-types -O3 -Qstrip_reflect -Qstrip_debug -Qstrip_rootsignature -Fh grid_sample_int_fp16.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=int64_t -DTBUFFER2=float16_t -enable-16bit-types -O3 -Qstrip_reflect -Qstrip_debug -Qstrip_rootsignature -Fh grid_sample_int64_fp16.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=float16_t -DTBUFFER2=float16_t -enable-16bit-types -O3 -Qstrip_reflect -Qstrip_debug -Qstrip_rootsignature -Fh grid_sample_fp16_fp16.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=float -DTBUFFER2=float16_t -enable-16bit-types -O3 -Qstrip_reflect -Qstrip_debug -Qstrip_rootsignature -Fh grid_sample_float_fp16.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=double -DTBUFFER2=float16_t -enable-16bit-types -O3 -Qstrip_reflect -Qstrip_debug -Qstrip_rootsignature -Fh grid_sample_double_fp16.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=bool -DTBUFFER2=float16_t -enable-16bit-types -O3 -Qstrip_reflect -Qstrip_debug -Qstrip_rootsignature -Fh grid_sample_bool_fp16.h + + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=uint16_t -DTBUFFER2=double -enable-16bit-types -O3 -Qstrip_reflect -Qstrip_debug -Qstrip_rootsignature -Fh grid_sample_uint16_double.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=uint -DTBUFFER2=double -enable-16bit-types -O3 -Qstrip_reflect -Qstrip_debug -Qstrip_rootsignature -Fh grid_sample_uint_double.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=uint64_t -DTBUFFER2=double -enable-16bit-types -O3 -Qstrip_reflect -Qstrip_debug -Qstrip_rootsignature -Fh grid_sample_uint64_double.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=int16_t -DTBUFFER2=double -enable-16bit-types -O3 -Qstrip_reflect -Qstrip_debug -Qstrip_rootsignature -Fh grid_sample_int16_double.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=int -DTBUFFER2=double -enable-16bit-types -O3 -Qstrip_reflect -Qstrip_debug -Qstrip_rootsignature -Fh grid_sample_int_double.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=int64_t -DTBUFFER2=double -enable-16bit-types -O3 -Qstrip_reflect -Qstrip_debug -Qstrip_rootsignature -Fh grid_sample_int64_double.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=float16_t -DTBUFFER2=double -enable-16bit-types -O3 -Qstrip_reflect -Qstrip_debug -Qstrip_rootsignature -Fh grid_sample_fp16_double.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=float -DTBUFFER2=double -enable-16bit-types -O3 -Qstrip_reflect -Qstrip_debug -Qstrip_rootsignature -Fh grid_sample_float_double.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=double -DTBUFFER2=double -enable-16bit-types -O3 -Qstrip_reflect -Qstrip_debug -Qstrip_rootsignature -Fh grid_sample_double_double.h + dxc.exe ..\Shaders\grid_sample.hlsl -E GridSample -T cs_6_2 -DTBUFFER1=bool -DTBUFFER2=double -enable-16bit-types -O3 -Qstrip_reflect -Qstrip_debug -Qstrip_rootsignature -Fh grid_sample_bool_double.h + +) diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/GeneratedShaders/bluestein_chirp.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/GeneratedShaders/bluestein_chirp.h new file mode 100644 index 0000000000000..2220b1a3197eb --- /dev/null +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/GeneratedShaders/bluestein_chirp.h @@ -0,0 +1,331 @@ +#if 0 +// +// Generated by Microsoft (R) D3D Shader Disassembler +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------- ------ +// no Input +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------- ------ +// no Output +cs_5_0 +dcl_globalFlags refactoringAllowed +dcl_constantbuffer CB0[1], immediateIndexed +dcl_uav_structured u0, 4 +dcl_uav_structured u1, 4 +dcl_input vThreadID.x +dcl_temps 4 +dcl_thread_group 64, 1, 1 +iadd r0.x, vThreadID.x, cb0[0].x +ult r0.y, r0.x, cb0[0].y +if_nz r0.y + ishl r0.y, cb0[0].z, l(1) + iadd r0.y, r0.y, l(-2) + mov r0.z, l(1) + loop + ult r0.w, r0.y, r0.z + breakc_nz r0.w + ishl r0.z, r0.z, l(1) + endloop + ishl r0.y, r0.x, l(1) + bfi r0.w, l(31), l(1), r0.x, l(1) + ieq r1.x, cb0[0].w, l(1) + ult r1.y, r0.x, cb0[0].z + if_nz r1.y + movc r1.y, r1.x, l(3.141593), l(-3.141593) + utof r1.z, r0.x + mul r1.z, r1.z, r1.z + mul r1.y, r1.y, r1.z + utof r1.z, cb0[0].z + div r1.y, r1.y, r1.z + sincos r2.x, r3.x, r1.y + mov r1.y, -r2.x + store_structured u0.x, r0.y, l(0), r3.x + store_structured u0.x, r0.w, l(0), r2.x + store_structured u1.x, r0.y, l(0), r3.x + store_structured u1.x, r0.w, l(0), r1.y + else + iadd r1.y, r0.z, -cb0[0].z + iadd r1.y, r1.y, l(1) + uge r1.y, r0.x, r1.y + ult r1.z, r0.x, r0.z + and r1.y, r1.z, r1.y + if_nz r1.y + iadd r0.x, -r0.x, r0.z + movc r0.z, r1.x, l(3.141593), l(-3.141593) + utof r0.x, r0.x + mul r0.x, r0.x, r0.x + mul r0.x, r0.z, r0.x + utof r0.z, cb0[0].z + div r0.x, r0.x, r0.z + sincos null, r0.z, r0.x + sincos r0.x, null, -r0.x + store_structured u1.x, r0.y, l(0), r0.z + store_structured u1.x, r0.w, l(0), r0.x + else + store_structured u1.x, r0.y, l(0), l(0) + store_structured u1.x, r0.w, l(0), l(0) + endif + endif +endif +ret +// Approximately 0 instruction slots used +#endif + +const BYTE g_BluesteinZChirp[] = +{ + 68, 88, 66, 67, 237, 104, + 222, 255, 94, 46, 57, 112, + 99, 117, 92, 206, 48, 139, + 62, 51, 1, 0, 0, 0, + 208, 5, 0, 0, 3, 0, + 0, 0, 44, 0, 0, 0, + 60, 0, 0, 0, 76, 0, + 0, 0, 73, 83, 71, 78, + 8, 0, 0, 0, 0, 0, + 0, 0, 8, 0, 0, 0, + 79, 83, 71, 78, 8, 0, + 0, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 83, 72, + 69, 88, 124, 5, 0, 0, + 80, 0, 5, 0, 95, 1, + 0, 0, 106, 8, 0, 1, + 89, 0, 0, 4, 70, 142, + 32, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 158, 0, + 0, 4, 0, 224, 17, 0, + 0, 0, 0, 0, 4, 0, + 0, 0, 158, 0, 0, 4, + 0, 224, 17, 0, 1, 0, + 0, 0, 4, 0, 0, 0, + 95, 0, 0, 2, 18, 0, + 2, 0, 104, 0, 0, 2, + 4, 0, 0, 0, 155, 0, + 0, 4, 64, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 30, 0, 0, 7, + 18, 0, 16, 0, 0, 0, + 0, 0, 10, 0, 2, 0, + 10, 128, 32, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 79, 0, 0, 8, 34, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 0, 0, 0, + 0, 0, 26, 128, 32, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 31, 0, 4, 3, + 26, 0, 16, 0, 0, 0, + 0, 0, 41, 0, 0, 8, + 34, 0, 16, 0, 0, 0, + 0, 0, 42, 128, 32, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 1, 0, 0, 0, 30, 0, + 0, 7, 34, 0, 16, 0, + 0, 0, 0, 0, 26, 0, + 16, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 254, 255, + 255, 255, 54, 0, 0, 5, + 66, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 1, 0, 0, 0, 48, 0, + 0, 1, 79, 0, 0, 7, + 130, 0, 16, 0, 0, 0, + 0, 0, 26, 0, 16, 0, + 0, 0, 0, 0, 42, 0, + 16, 0, 0, 0, 0, 0, + 3, 0, 4, 3, 58, 0, + 16, 0, 0, 0, 0, 0, + 41, 0, 0, 7, 66, 0, + 16, 0, 0, 0, 0, 0, + 42, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 1, 0, 0, 0, 22, 0, + 0, 1, 41, 0, 0, 7, + 34, 0, 16, 0, 0, 0, + 0, 0, 10, 0, 16, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 1, 0, 0, 0, + 140, 0, 0, 11, 130, 0, + 16, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 31, 0, + 0, 0, 1, 64, 0, 0, + 1, 0, 0, 0, 10, 0, + 16, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 1, 0, + 0, 0, 32, 0, 0, 8, + 18, 0, 16, 0, 1, 0, + 0, 0, 58, 128, 32, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 1, 0, 0, 0, 79, 0, + 0, 8, 34, 0, 16, 0, + 1, 0, 0, 0, 10, 0, + 16, 0, 0, 0, 0, 0, + 42, 128, 32, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 31, 0, 4, 3, 26, 0, + 16, 0, 1, 0, 0, 0, + 55, 0, 0, 9, 34, 0, + 16, 0, 1, 0, 0, 0, + 10, 0, 16, 0, 1, 0, + 0, 0, 1, 64, 0, 0, + 219, 15, 73, 64, 1, 64, + 0, 0, 219, 15, 73, 192, + 86, 0, 0, 5, 66, 0, + 16, 0, 1, 0, 0, 0, + 10, 0, 16, 0, 0, 0, + 0, 0, 56, 0, 0, 7, + 66, 0, 16, 0, 1, 0, + 0, 0, 42, 0, 16, 0, + 1, 0, 0, 0, 42, 0, + 16, 0, 1, 0, 0, 0, + 56, 0, 0, 7, 34, 0, + 16, 0, 1, 0, 0, 0, + 26, 0, 16, 0, 1, 0, + 0, 0, 42, 0, 16, 0, + 1, 0, 0, 0, 86, 0, + 0, 6, 66, 0, 16, 0, + 1, 0, 0, 0, 42, 128, + 32, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 14, 0, + 0, 7, 34, 0, 16, 0, + 1, 0, 0, 0, 26, 0, + 16, 0, 1, 0, 0, 0, + 42, 0, 16, 0, 1, 0, + 0, 0, 77, 0, 0, 7, + 18, 0, 16, 0, 2, 0, + 0, 0, 18, 0, 16, 0, + 3, 0, 0, 0, 26, 0, + 16, 0, 1, 0, 0, 0, + 54, 0, 0, 6, 34, 0, + 16, 0, 1, 0, 0, 0, + 10, 0, 16, 128, 65, 0, + 0, 0, 2, 0, 0, 0, + 168, 0, 0, 9, 18, 224, + 17, 0, 0, 0, 0, 0, + 26, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 3, 0, 0, 0, + 168, 0, 0, 9, 18, 224, + 17, 0, 0, 0, 0, 0, + 58, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 2, 0, 0, 0, + 168, 0, 0, 9, 18, 224, + 17, 0, 1, 0, 0, 0, + 26, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 3, 0, 0, 0, + 168, 0, 0, 9, 18, 224, + 17, 0, 1, 0, 0, 0, + 58, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 0, 26, 0, + 16, 0, 1, 0, 0, 0, + 18, 0, 0, 1, 30, 0, + 0, 9, 34, 0, 16, 0, + 1, 0, 0, 0, 42, 0, + 16, 0, 0, 0, 0, 0, + 42, 128, 32, 128, 65, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 30, 0, + 0, 7, 34, 0, 16, 0, + 1, 0, 0, 0, 26, 0, + 16, 0, 1, 0, 0, 0, + 1, 64, 0, 0, 1, 0, + 0, 0, 80, 0, 0, 7, + 34, 0, 16, 0, 1, 0, + 0, 0, 10, 0, 16, 0, + 0, 0, 0, 0, 26, 0, + 16, 0, 1, 0, 0, 0, + 79, 0, 0, 7, 66, 0, + 16, 0, 1, 0, 0, 0, + 10, 0, 16, 0, 0, 0, + 0, 0, 42, 0, 16, 0, + 0, 0, 0, 0, 1, 0, + 0, 7, 34, 0, 16, 0, + 1, 0, 0, 0, 42, 0, + 16, 0, 1, 0, 0, 0, + 26, 0, 16, 0, 1, 0, + 0, 0, 31, 0, 4, 3, + 26, 0, 16, 0, 1, 0, + 0, 0, 30, 0, 0, 8, + 18, 0, 16, 0, 0, 0, + 0, 0, 10, 0, 16, 128, + 65, 0, 0, 0, 0, 0, + 0, 0, 42, 0, 16, 0, + 0, 0, 0, 0, 55, 0, + 0, 9, 66, 0, 16, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 1, 0, 0, 0, + 1, 64, 0, 0, 219, 15, + 73, 64, 1, 64, 0, 0, + 219, 15, 73, 192, 86, 0, + 0, 5, 18, 0, 16, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 0, 0, 0, 0, + 56, 0, 0, 7, 18, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 0, 0, 0, + 0, 0, 10, 0, 16, 0, + 0, 0, 0, 0, 56, 0, + 0, 7, 18, 0, 16, 0, + 0, 0, 0, 0, 42, 0, + 16, 0, 0, 0, 0, 0, + 10, 0, 16, 0, 0, 0, + 0, 0, 86, 0, 0, 6, + 66, 0, 16, 0, 0, 0, + 0, 0, 42, 128, 32, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 14, 0, 0, 7, + 18, 0, 16, 0, 0, 0, + 0, 0, 10, 0, 16, 0, + 0, 0, 0, 0, 42, 0, + 16, 0, 0, 0, 0, 0, + 77, 0, 0, 6, 0, 208, + 0, 0, 66, 0, 16, 0, + 0, 0, 0, 0, 10, 0, + 16, 0, 0, 0, 0, 0, + 77, 0, 0, 7, 18, 0, + 16, 0, 0, 0, 0, 0, + 0, 208, 0, 0, 10, 0, + 16, 128, 65, 0, 0, 0, + 0, 0, 0, 0, 168, 0, + 0, 9, 18, 224, 17, 0, + 1, 0, 0, 0, 26, 0, + 16, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 42, 0, 16, 0, + 0, 0, 0, 0, 168, 0, + 0, 9, 18, 224, 17, 0, + 1, 0, 0, 0, 58, 0, + 16, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 10, 0, 16, 0, + 0, 0, 0, 0, 18, 0, + 0, 1, 168, 0, 0, 9, + 18, 224, 17, 0, 1, 0, + 0, 0, 26, 0, 16, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 168, 0, 0, 9, + 18, 224, 17, 0, 1, 0, + 0, 0, 58, 0, 16, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 21, 0, 0, 1, + 21, 0, 0, 1, 21, 0, + 0, 1, 62, 0, 0, 1 +}; diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/GeneratedShaders/bluestein_chirp_fp16.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/GeneratedShaders/bluestein_chirp_fp16.h new file mode 100644 index 0000000000000..33b738d624b3d --- /dev/null +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/GeneratedShaders/bluestein_chirp_fp16.h @@ -0,0 +1,383 @@ +#if 0 +; +; Note: shader requires additional functionality: +; Use native low precision +; +; +; Input signature: +; +; Name Index Mask Register SysValue Format Used +; -------------------- ----- ------ -------- -------- ------- ------ +; no parameters +; +; Output signature: +; +; Name Index Mask Register SysValue Format Used +; -------------------- ----- ------ -------- -------- ------- ------ +; no parameters +; shader hash: 73b6ca13ec7e5bd5fa73ee69765da96a +; +; Pipeline Runtime Information: +; +; +; +; Buffer Definitions: +; +; cbuffer +; { +; +; [16 x i8] (type annotation not present) +; +; } +; +; Resource bind info for +; { +; +; [2 x i8] (type annotation not present) +; +; } +; +; Resource bind info for +; { +; +; [2 x i8] (type annotation not present) +; +; } +; +; +; Resource Bindings: +; +; Name Type Format Dim ID HLSL Bind Count +; ------------------------------ ---------- ------- ----------- ------- -------------- ------ +; cbuffer NA NA CB0 cb0 1 +; UAV struct r/w U0 u0 1 +; UAV struct r/w U1 u1 1 +; +target datalayout = "e-m:e-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:32-f64:64-n8:16:32:64" +target triple = "dxil-ms-dx" + +%dx.types.Handle = type { i8* } +%dx.types.CBufRet.i32 = type { i32, i32, i32, i32 } +%"class.RWStructuredBuffer" = type { half } +%Constants = type { i32, i32, i32, i32 } + +define void @BluesteinZChirp() { + %1 = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 1, i32 1, i32 1, i1 false) ; CreateHandle(resourceClass,rangeId,index,nonUniformIndex) + %2 = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 1, i32 0, i32 0, i1 false) ; CreateHandle(resourceClass,rangeId,index,nonUniformIndex) + %3 = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 2, i32 0, i32 0, i1 false) ; CreateHandle(resourceClass,rangeId,index,nonUniformIndex) + %4 = call i32 @dx.op.threadId.i32(i32 93, i32 0) ; ThreadId(component) + %5 = call %dx.types.CBufRet.i32 @dx.op.cbufferLoadLegacy.i32(i32 59, %dx.types.Handle %3, i32 0) ; CBufferLoadLegacy(handle,regIndex) + %6 = extractvalue %dx.types.CBufRet.i32 %5, 0 + %7 = add i32 %6, %4 + %8 = extractvalue %dx.types.CBufRet.i32 %5, 1 + %9 = icmp ult i32 %7, %8 + br i1 %9, label %10, label %60 + +;
054.2656.0560.32109.2118.4352.2652.9260.9488.5119.1412
155.8056.7459.6773.6217.9252.6752.7354.0660.4818.9911
256.1961.2971.6980.1517.80654.5755.0556.5259.6218.3210
357.6658.5061.9665.1217.34958.6265.8671.9479.3817.066
459.9059.7265.16116.1616.70559.8061.0965.7272.7916.728
562.8467.0569.0775.9915.91863.1261.9277.47129.2615.849
663.7264.1769.4473.1015.69464.7265.9468.5475.0015.457
765.3165.3580.70177.9415.311073.7280.4386.3992.9513.565
869.2969.0470.6885.0314.43788.7696.30101.13109.7811.274
982.4483.2089.6498.8012.1391.1499.14104.41110.6910.973
10119.64119.07122.62135.678.36119.80119.78123.66130.648.352
11223.21223.22226.83249.084.48225.06227.11229.45252.404.441
023.7223.7223.8723.9924.1124.3742.1543.193.163.213.273.353.52313.241
124.2424.2424.4224.6024.7625.2341.2533.203.173.223.253.343.50312.808
224.3624.3624.4724.6925.0126.5241.0523.203.153.253.293.363.58312.5115
324.3924.3724.4724.6524.7325.1241.0113.203.183.213.263.353.53312.4914
43.203.163.253.293.403.56312.2413
53.203.193.223.273.353.48312.2012
63.213.183.233.283.373.51311.7324
73.213.193.233.273.343.52311.579
83.213.183.263.313.363.54311.1532
93.213.173.243.283.343.52311.105
103.213.193.253.293.333.54311.102
113.223.193.253.293.363.51310.9310
123.223.193.263.293.403.55310.303
133.233.193.263.323.423.58310.0211
143.233.193.263.303.363.54310.024
153.233.203.233.273.353.60309.537
163.233.193.223.263.333.68309.276
\n", "" ], "text/plain": [ - " Latency(ms) Latency_P50 Latency_P75 Latency_P90 Latency_P95 \\\n", - "0 23.72 23.72 23.87 23.99 24.11 \n", - "1 24.24 24.24 24.42 24.60 24.76 \n", - "2 24.36 24.36 24.47 24.69 25.01 \n", - "3 24.39 24.37 24.47 24.65 24.73 \n", + " Latency(ms) Latency_P50 Latency_P75 Latency_P90 Latency_P95 \\\n", + "0 3.19 3.16 3.21 3.27 3.35 \n", + "1 3.20 3.17 3.22 3.25 3.34 \n", + "2 3.20 3.15 3.25 3.29 3.36 \n", + "3 3.20 3.18 3.21 3.26 3.35 \n", + "4 3.20 3.16 3.25 3.29 3.40 \n", + "5 3.20 3.19 3.22 3.27 3.35 \n", + "6 3.21 3.18 3.23 3.28 3.37 \n", + "7 3.21 3.19 3.23 3.27 3.34 \n", + "8 3.21 3.18 3.26 3.31 3.36 \n", + "9 3.21 3.17 3.24 3.28 3.34 \n", + "10 3.21 3.19 3.25 3.29 3.33 \n", + "11 3.22 3.19 3.25 3.29 3.36 \n", + "12 3.22 3.19 3.26 3.29 3.40 \n", + "13 3.23 3.19 3.26 3.32 3.42 \n", + "14 3.23 3.19 3.26 3.30 3.36 \n", + "15 3.23 3.20 3.23 3.27 3.35 \n", + "16 3.23 3.19 3.22 3.26 3.33 \n", "\n", - " Latency_P99 Throughput(QPS) intra_op_num_threads \n", - "0 24.37 42.15 4 \n", - "1 25.23 41.25 3 \n", - "2 26.52 41.05 2 \n", - "3 25.12 41.01 1 " + " Latency_P99 Throughput(QPS) intra_op_num_threads \n", + "0 3.52 313.24 1 \n", + "1 3.50 312.80 8 \n", + "2 3.58 312.51 15 \n", + "3 3.53 312.49 14 \n", + "4 3.56 312.24 13 \n", + "5 3.48 312.20 12 \n", + "6 3.51 311.73 24 \n", + "7 3.52 311.57 9 \n", + "8 3.54 311.15 32 \n", + "9 3.52 311.10 5 \n", + "10 3.54 311.10 2 \n", + "11 3.51 310.93 10 \n", + "12 3.55 310.30 3 \n", + "13 3.58 310.02 11 \n", + "14 3.54 310.02 4 \n", + "15 3.60 309.53 7 \n", + "16 3.68 309.27 6 " ] }, - "execution_count": 18, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "import os\n", - "import glob \n", - "import pandas\n", - "latest_result_file = max(glob.glob(\"./onnx/perf_results_GPU_B1_S128_*.txt\"), key=os.path.getmtime)\n", - "result_data = pandas.read_table(latest_result_file)\n", - "print(\"Float32 model perf results from\", latest_result_file)\n", - "# Remove some columns that have same values for all rows.\n", - "columns_to_remove = ['model', 'graph_optimization_level', 'batch_size', 'sequence_length', 'test_cases', 'test_times', 'use_gpu']\n", - "result_data.drop(columns_to_remove, axis=1, inplace=True)\n", - "result_data" + "def load_last_perf_test_result():\n", + " import os\n", + " import glob \n", + " import pandas\n", + " latest_result_file = max(glob.glob(\"./onnx/perf_results_*.txt\"), key=os.path.getmtime)\n", + " result_data = pandas.read_table(latest_result_file)\n", + " print(\"Perf results from\", latest_result_file)\n", + " # Do not show columns that have same values for all rows.\n", + " columns_to_remove = ['model', 'graph_optimization_level', 'batch_size', 'sequence_length', 'test_cases', 'test_times', 'use_gpu', 'use_io_binding', 'average_sequence_length', 'random_sequence_length']\n", + " result_data.drop(columns_to_remove, axis=1, inplace=True)\n", + " return result_data\n", + " \n", + "thread_results = load_last_perf_test_result()\n", + "thread_results" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "From above result, we can see that latency is very close for different settings. The default setting (intra_op_num_threads=0, OMP_NUM_THREADS and OMP_WAIT_POLICY does not exist) performs the best. \n", + "From above result, we can see that latency is very close for different settings of intra_op_num_threads.\n", "\n", "### Model Results Comparison Tool\n", "\n", @@ -891,21 +1063,21 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "100% passed for 100 random inputs given thresholds (rtol=0.01, atol=0.01).\r\n", - "maximum absolute difference=5.316734313964844e-05\r\n", - "maximum relative difference=0.00012461667938623577\r\n" + "100% passed for 100 random inputs given thresholds (rtol=0.01, atol=0.01).\n", + "maximum absolute difference=0.05149984359741211\n" ] } ], "source": [ - "!{sys.executable} -m onnxruntime.transformers.compare_bert_results --baseline_model $export_model_path --optimized_model $optimized_fp32_model_path --batch_size 1 --sequence_length 128 --samples 100 --rtol 0.01 --atol 0.01 $GPU_OPTION" + "USE_GPU = '--use_gpu' if use_gpu else ''\n", + "!{sys.executable} -m onnxruntime.transformers.compare_bert_results --baseline_model $export_model_path --optimized_model $optimized_fp32_model_path --batch_size 1 --sequence_length 128 --samples 100 --rtol 0.01 --atol 0.01 $USE_GPU" ] }, { @@ -916,80 +1088,106 @@ "\n", "The optimizer.py script have an option **--float16** to convert model to use float16 to store weights. After the conversion, it could be faster to run in GPU with tensor cores like V100 or T4.\n", "\n", - "Let's run tools to measure the performance on V100. The results show significant performance improvement: latency is about 3.4 ms for float32 model, and 1.8 ms for float16 model." + "Let's run tools to measure the performance on Nvidia RTX 4090. The results show significant performance improvement: latency is about 3.2 ms for float32 model, and about 1.8 ms for float16 model." ] }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 19, "metadata": {}, "outputs": [ { - "name": "stdout", + "name": "stderr", "output_type": "stream", "text": [ - " apply: Fused LayerNormalization count: 49\n", - " apply: Fused Gelu count: 24\n", - "adjust_reshape_and_expand: Removed Reshape and Expand count: 0\n", - " apply: Fused SkipLayerNormalization count: 48\n", - " apply: Fused Attention count: 24\n", - " prune_graph: Graph pruned: 0 inputs, 0 outputs and 5 nodes are removed\n", - " apply: Fused EmbedLayerNormalization(with mask) count: 1\n", - " prune_graph: Graph pruned: 0 inputs, 0 outputs and 3 nodes are removed\n", - " prune_graph: Graph pruned: 0 inputs, 0 outputs and 0 nodes are removed\n", - " apply: Fused BiasGelu count: 24\n", - " apply: Fused SkipLayerNormalization(add bias) count: 48\n", + "\u001b\u0000[\u00000\u0000;\u00009\u00003\u0000m\u00002\u00000\u00002\u00003\u0000-\u00000\u00009\u0000-\u00001\u00002\u0000 \u00001\u00002\u0000:\u00005\u00007\u0000:\u00005\u00004\u0000.\u00005\u00005\u00000\u00008\u00002\u00002\u00008\u0000 \u0000[\u0000W\u0000:\u0000o\u0000n\u0000n\u0000x\u0000r\u0000u\u0000n\u0000t\u0000i\u0000m\u0000e\u0000:\u0000,\u0000 \u0000s\u0000e\u0000s\u0000s\u0000i\u0000o\u0000n\u0000_\u0000s\u0000t\u0000a\u0000t\u0000e\u0000.\u0000c\u0000c\u0000:\u00001\u00001\u00006\u00002\u0000 \u0000o\u0000n\u0000n\u0000x\u0000r\u0000u\u0000n\u0000t\u0000i\u0000m\u0000e\u0000:\u0000:\u0000V\u0000e\u0000r\u0000i\u0000f\u0000y\u0000E\u0000a\u0000c\u0000h\u0000N\u0000o\u0000d\u0000e\u0000I\u0000s\u0000A\u0000s\u0000s\u0000i\u0000g\u0000n\u0000e\u0000d\u0000T\u0000o\u0000A\u0000n\u0000E\u0000p\u0000]\u0000 \u0000S\u0000o\u0000m\u0000e\u0000 \u0000n\u0000o\u0000d\u0000e\u0000s\u0000 \u0000w\u0000e\u0000r\u0000e\u0000 \u0000n\u0000o\u0000t\u0000 \u0000a\u0000s\u0000s\u0000i\u0000g\u0000n\u0000e\u0000d\u0000 \u0000t\u0000o\u0000 \u0000t\u0000h\u0000e\u0000 \u0000p\u0000r\u0000e\u0000f\u0000e\u0000r\u0000r\u0000e\u0000d\u0000 \u0000e\u0000x\u0000e\u0000c\u0000u\u0000t\u0000i\u0000o\u0000n\u0000 \u0000p\u0000r\u0000o\u0000v\u0000i\u0000d\u0000e\u0000r\u0000s\u0000 \u0000w\u0000h\u0000i\u0000c\u0000h\u0000 \u0000m\u0000a\u0000y\u0000 \u0000o\u0000r\u0000 \u0000m\u0000a\u0000y\u0000 \u0000n\u0000o\u0000t\u0000 \u0000h\u0000a\u0000v\u0000e\u0000 \u0000a\u0000n\u0000 \u0000n\u0000e\u0000g\u0000a\u0000t\u0000i\u0000v\u0000e\u0000 \u0000i\u0000m\u0000p\u0000a\u0000c\u0000t\u0000 \u0000o\u0000n\u0000 \u0000p\u0000e\u0000r\u0000f\u0000o\u0000r\u0000m\u0000a\u0000n\u0000c\u0000e\u0000.\u0000 \u0000e\u0000.\u0000g\u0000.\u0000 \u0000O\u0000R\u0000T\u0000 \u0000e\u0000x\u0000p\u0000l\u0000i\u0000c\u0000i\u0000t\u0000l\u0000y\u0000 \u0000a\u0000s\u0000s\u0000i\u0000g\u0000n\u0000s\u0000 \u0000s\u0000h\u0000a\u0000p\u0000e\u0000 \u0000r\u0000e\u0000l\u0000a\u0000t\u0000e\u0000d\u0000 \u0000o\u0000p\u0000s\u0000 \u0000t\u0000o\u0000 \u0000C\u0000P\u0000U\u0000 \u0000t\u0000o\u0000 \u0000i\u0000m\u0000p\u0000r\u0000o\u0000v\u0000e\u0000 \u0000p\u0000e\u0000r\u0000f\u0000.\u0000\u001b\u0000[\u0000m\u0000\n", + "\u0000\u001b\u0000[\u00000\u0000;\u00009\u00003\u0000m\u00002\u00000\u00002\u00003\u0000-\u00000\u00009\u0000-\u00001\u00002\u0000 \u00001\u00002\u0000:\u00005\u00007\u0000:\u00005\u00004\u0000.\u00005\u00005\u00001\u00001\u00000\u00000\u00008\u0000 \u0000[\u0000W\u0000:\u0000o\u0000n\u0000n\u0000x\u0000r\u0000u\u0000n\u0000t\u0000i\u0000m\u0000e\u0000:\u0000,\u0000 \u0000s\u0000e\u0000s\u0000s\u0000i\u0000o\u0000n\u0000_\u0000s\u0000t\u0000a\u0000t\u0000e\u0000.\u0000c\u0000c\u0000:\u00001\u00001\u00006\u00004\u0000 \u0000o\u0000n\u0000n\u0000x\u0000r\u0000u\u0000n\u0000t\u0000i\u0000m\u0000e\u0000:\u0000:\u0000V\u0000e\u0000r\u0000i\u0000f\u0000y\u0000E\u0000a\u0000c\u0000h\u0000N\u0000o\u0000d\u0000e\u0000I\u0000s\u0000A\u0000s\u0000s\u0000i\u0000g\u0000n\u0000e\u0000d\u0000T\u0000o\u0000A\u0000n\u0000E\u0000p\u0000]\u0000 \u0000R\u0000e\u0000r\u0000u\u0000n\u0000n\u0000i\u0000n\u0000g\u0000 \u0000w\u0000i\u0000t\u0000h\u0000 \u0000v\u0000e\u0000r\u0000b\u0000o\u0000s\u0000e\u0000 \u0000o\u0000u\u0000t\u0000p\u0000u\u0000t\u0000 \u0000o\u0000n\u0000 \u0000a\u0000 \u0000n\u0000o\u0000n\u0000-\u0000m\u0000i\u0000n\u0000i\u0000m\u0000a\u0000l\u0000 \u0000b\u0000u\u0000i\u0000l\u0000d\u0000 \u0000w\u0000i\u0000l\u0000l\u0000 \u0000s\u0000h\u0000o\u0000w\u0000 \u0000n\u0000o\u0000d\u0000e\u0000 \u0000a\u0000s\u0000s\u0000i\u0000g\u0000n\u0000m\u0000e\u0000n\u0000t\u0000s\u0000.\u0000\u001b\u0000[\u0000m\u0000\n", + "\u0000 apply: Fused LayerNormalization: 49\n", + " apply: Fused Gelu: 24\n", + " apply: Fused SkipLayerNormalization: 48\n", + " apply: Fused Attention: 24\n", + " prune_graph: Removed 5 nodes\n", + " apply: Fused EmbedLayerNormalization(with mask): 1\n", + " prune_graph: Removed 10 nodes\n", + " apply: Fused BiasGelu: 24\n", + " apply: Fused SkipLayerNormalization(add bias): 48\n", " optimize: opset version: 11\n", + "get_fused_operator_statistics: Optimized operators:{'EmbedLayerNormalization': 1, 'Attention': 24, 'MultiHeadAttention': 0, 'Gelu': 0, 'FastGelu': 0, 'BiasGelu': 24, 'GemmFastGelu': 0, 'LayerNormalization': 0, 'SkipLayerNormalization': 48, 'QOrderedAttention': 0, 'QOrderedGelu': 0, 'QOrderedLayerNormalization': 0, 'QOrderedMatMul': 0}\n", + " main: The model has been fully optimized.\n", " save_model_to_file: Sort graphs in topological order\n", - " save_model_to_file: Output model to ./onnx/bert-base-cased-squad_opt_gpu_fp16.onnx\n", - "get_fused_operator_statistics: Optimized operators:{'EmbedLayerNormalization': 1, 'Attention': 24, 'Gelu': 0, 'FastGelu': 0, 'BiasGelu': 24, 'LayerNormalization': 0, 'SkipLayerNormalization': 48}\n", - " main: The model has been fully optimized.\n" + " save_model_to_file: Model saved to ./onnx/bert-base-cased-squad_opt_gpu_fp16.onnx\n" ] } ], "source": [ "optimized_fp16_model_path = './onnx/bert-base-cased-squad_opt_{}_fp16.onnx'.format('gpu' if use_gpu else 'cpu')\n", - "!{sys.executable} -m onnxruntime.transformers.optimizer --input $export_model_path --output $optimized_fp16_model_path --float16" + "!{sys.executable} -m onnxruntime.transformers.optimizer --input $export_model_path --output $optimized_fp16_model_path --float16 $USE_GPU" ] }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "test setting TestSetting(batch_size=1, sequence_length=128, test_cases=1000, test_times=1, use_gpu=True, intra_op_num_threads=None, seed=3, verbose=False)\n", + "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=32,batch_size=1,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True,use_io_binding=True,average_sequence_length=128,random_sequence_length=False\n", + "Average latency = 1.77 ms, Throughput = 566.45 QPS\n", + "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=24,batch_size=1,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True,use_io_binding=True,average_sequence_length=128,random_sequence_length=False\n", + "Average latency = 1.74 ms, Throughput = 574.96 QPS\n", + "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=15,batch_size=1,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True,use_io_binding=True,average_sequence_length=128,random_sequence_length=False\n", + "Average latency = 1.74 ms, Throughput = 574.28 QPS\n", + "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=14,batch_size=1,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True,use_io_binding=True,average_sequence_length=128,random_sequence_length=False\n", + "Average latency = 1.74 ms, Throughput = 575.17 QPS\n", + "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=13,batch_size=1,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True,use_io_binding=True,average_sequence_length=128,random_sequence_length=False\n", + "Average latency = 1.76 ms, Throughput = 569.77 QPS\n", + "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=12,batch_size=1,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True,use_io_binding=True,average_sequence_length=128,random_sequence_length=False\n", + "Average latency = 1.79 ms, Throughput = 559.84 QPS\n", + "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=11,batch_size=1,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True,use_io_binding=True,average_sequence_length=128,random_sequence_length=False\n", + "Average latency = 1.77 ms, Throughput = 566.09 QPS\n", + "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=10,batch_size=1,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True,use_io_binding=True,average_sequence_length=128,random_sequence_length=False\n", + "Average latency = 1.77 ms, Throughput = 563.97 QPS\n", + "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=9,batch_size=1,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True,use_io_binding=True,average_sequence_length=128,random_sequence_length=False\n", + "Average latency = 1.77 ms, Throughput = 565.70 QPS\n", + "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=8,batch_size=1,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True,use_io_binding=True,average_sequence_length=128,random_sequence_length=False\n", + "Average latency = 1.77 ms, Throughput = 565.50 QPS\n", + "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=7,batch_size=1,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True,use_io_binding=True,average_sequence_length=128,random_sequence_length=False\n", + "Average latency = 1.77 ms, Throughput = 566.38 QPS\n", + "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=6,batch_size=1,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True,use_io_binding=True,average_sequence_length=128,random_sequence_length=False\n", + "Average latency = 1.75 ms, Throughput = 572.89 QPS\n", + "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=5,batch_size=1,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True,use_io_binding=True,average_sequence_length=128,random_sequence_length=False\n", + "Average latency = 1.76 ms, Throughput = 568.67 QPS\n", + "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=4,batch_size=1,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True,use_io_binding=True,average_sequence_length=128,random_sequence_length=False\n", + "Average latency = 1.78 ms, Throughput = 561.98 QPS\n", + "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=3,batch_size=1,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True,use_io_binding=True,average_sequence_length=128,random_sequence_length=False\n", + "Average latency = 1.77 ms, Throughput = 566.14 QPS\n", + "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=2,batch_size=1,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True,use_io_binding=True,average_sequence_length=128,random_sequence_length=False\n", + "Average latency = 1.78 ms, Throughput = 563.25 QPS\n", + "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=1,batch_size=1,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True,use_io_binding=True,average_sequence_length=128,random_sequence_length=False\n", + "Average latency = 1.77 ms, Throughput = 565.09 QPS\n", + "test setting TestSetting(batch_size=1, sequence_length=128, test_cases=1000, test_times=1, use_gpu=True, use_io_binding=True, provider=None, intra_op_num_threads=None, seed=3, verbose=False, log_severity=2, average_sequence_length=128, random_sequence_length=False)\n", "Generating 1000 samples for batch_size=1 sequence_length=128\n", - "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=4,batch_size=1,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True\n", - "Average latency = 6.78 ms, Throughput = 147.54 QPS\n", - "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=3,batch_size=1,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True\n", - "Average latency = 6.76 ms, Throughput = 147.85 QPS\n", - "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=2,batch_size=1,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True\n", - "Average latency = 6.79 ms, Throughput = 147.30 QPS\n", - "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=1,batch_size=1,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True\n", - "Average latency = 6.81 ms, Throughput = 146.75 QPS\n", - "Test summary is saved to onnx/perf_results_GPU_B1_S128_20210714-002224.txt\n" + "Test summary is saved to onnx\\perf_results_GPU_B1_S128_20230912-130021.txt\n" ] } ], "source": [ - "GPU_OPTION = '--use_gpu' if use_gpu else ''\n", + "GPU_OPTION = '--use_gpu --use_io_binding' if use_gpu else ''\n", "!python -m onnxruntime.transformers.bert_perf_test --model $optimized_fp16_model_path --batch_size 1 --sequence_length 128 --samples 1000 --test_times 1 $GPU_OPTION" ] }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Float32 model perf results from ./onnx/perf_results_GPU_B1_S128_20210714-002224.txt\n" + "Perf results from ./onnx\\perf_results_GPU_B1_S128_20230912-130021.txt\n" ] }, { @@ -1026,82 +1224,243 @@ " \n", " \n", " 0\n", - " 6.76\n", - " 6.79\n", - " 6.81\n", - " 6.90\n", - " 6.91\n", - " 7.00\n", - " 147.85\n", - " 3\n", + " 1.74\n", + " 1.72\n", + " 1.72\n", + " 1.75\n", + " 1.80\n", + " 2.17\n", + " 575.17\n", + " 14\n", " \n", " \n", " 1\n", - " 6.78\n", - " 6.70\n", - " 6.79\n", - " 6.87\n", - " 6.90\n", - " 7.63\n", - " 147.54\n", - " 4\n", + " 1.74\n", + " 1.73\n", + " 1.73\n", + " 1.75\n", + " 1.76\n", + " 2.14\n", + " 574.96\n", + " 24\n", " \n", " \n", " 2\n", - " 6.79\n", - " 6.79\n", - " 6.81\n", - " 6.89\n", - " 6.91\n", - " 7.19\n", - " 147.30\n", - " 2\n", + " 1.74\n", + " 1.72\n", + " 1.73\n", + " 1.76\n", + " 1.79\n", + " 2.16\n", + " 574.28\n", + " 15\n", " \n", " \n", " 3\n", - " 6.81\n", - " 6.80\n", - " 6.89\n", - " 6.91\n", - " 6.97\n", - " 7.20\n", - " 146.75\n", + " 1.75\n", + " 1.72\n", + " 1.72\n", + " 1.76\n", + " 2.02\n", + " 2.15\n", + " 572.89\n", + " 6\n", + " \n", + " \n", + " 4\n", + " 1.76\n", + " 1.74\n", + " 1.74\n", + " 1.76\n", + " 1.81\n", + " 2.14\n", + " 569.77\n", + " 13\n", + " \n", + " \n", + " 5\n", + " 1.76\n", + " 1.72\n", + " 1.73\n", + " 1.80\n", + " 2.08\n", + " 2.15\n", + " 568.67\n", + " 5\n", + " \n", + " \n", + " 6\n", + " 1.77\n", + " 1.73\n", + " 1.74\n", + " 1.81\n", + " 2.12\n", + " 2.19\n", + " 566.45\n", + " 32\n", + " \n", + " \n", + " 7\n", + " 1.77\n", + " 1.74\n", + " 1.74\n", + " 1.77\n", + " 2.06\n", + " 2.17\n", + " 566.38\n", + " 7\n", + " \n", + " \n", + " 8\n", + " 1.77\n", + " 1.73\n", + " 1.74\n", + " 1.81\n", + " 2.10\n", + " 2.18\n", + " 566.14\n", + " 3\n", + " \n", + " \n", + " 9\n", + " 1.77\n", + " 1.73\n", + " 1.74\n", + " 1.82\n", + " 2.07\n", + " 2.17\n", + " 566.09\n", + " 11\n", + " \n", + " \n", + " 10\n", + " 1.77\n", + " 1.74\n", + " 1.75\n", + " 1.78\n", + " 2.02\n", + " 2.13\n", + " 565.70\n", + " 9\n", + " \n", + " \n", + " 11\n", + " 1.77\n", + " 1.73\n", + " 1.74\n", + " 1.93\n", + " 2.06\n", + " 2.16\n", + " 565.50\n", + " 8\n", + " \n", + " \n", + " 12\n", + " 1.77\n", + " 1.73\n", + " 1.74\n", + " 1.81\n", + " 2.11\n", + " 2.20\n", + " 565.09\n", " 1\n", " \n", + " \n", + " 13\n", + " 1.77\n", + " 1.74\n", + " 1.75\n", + " 1.85\n", + " 2.06\n", + " 2.15\n", + " 563.97\n", + " 10\n", + " \n", + " \n", + " 14\n", + " 1.78\n", + " 1.73\n", + " 1.74\n", + " 1.93\n", + " 2.13\n", + " 2.19\n", + " 563.25\n", + " 2\n", + " \n", + " \n", + " 15\n", + " 1.78\n", + " 1.74\n", + " 1.75\n", + " 1.88\n", + " 2.10\n", + " 2.19\n", + " 561.98\n", + " 4\n", + " \n", + " \n", + " 16\n", + " 1.79\n", + " 1.75\n", + " 1.76\n", + " 1.99\n", + " 2.08\n", + " 2.16\n", + " 559.84\n", + " 12\n", + " \n", " \n", "\n", "" ], "text/plain": [ - " Latency(ms) Latency_P50 Latency_P75 Latency_P90 Latency_P95 \\\n", - "0 6.76 6.79 6.81 6.90 6.91 \n", - "1 6.78 6.70 6.79 6.87 6.90 \n", - "2 6.79 6.79 6.81 6.89 6.91 \n", - "3 6.81 6.80 6.89 6.91 6.97 \n", + " Latency(ms) Latency_P50 Latency_P75 Latency_P90 Latency_P95 \\\n", + "0 1.74 1.72 1.72 1.75 1.80 \n", + "1 1.74 1.73 1.73 1.75 1.76 \n", + "2 1.74 1.72 1.73 1.76 1.79 \n", + "3 1.75 1.72 1.72 1.76 2.02 \n", + "4 1.76 1.74 1.74 1.76 1.81 \n", + "5 1.76 1.72 1.73 1.80 2.08 \n", + "6 1.77 1.73 1.74 1.81 2.12 \n", + "7 1.77 1.74 1.74 1.77 2.06 \n", + "8 1.77 1.73 1.74 1.81 2.10 \n", + "9 1.77 1.73 1.74 1.82 2.07 \n", + "10 1.77 1.74 1.75 1.78 2.02 \n", + "11 1.77 1.73 1.74 1.93 2.06 \n", + "12 1.77 1.73 1.74 1.81 2.11 \n", + "13 1.77 1.74 1.75 1.85 2.06 \n", + "14 1.78 1.73 1.74 1.93 2.13 \n", + "15 1.78 1.74 1.75 1.88 2.10 \n", + "16 1.79 1.75 1.76 1.99 2.08 \n", "\n", - " Latency_P99 Throughput(QPS) intra_op_num_threads \n", - "0 7.00 147.85 3 \n", - "1 7.63 147.54 4 \n", - "2 7.19 147.30 2 \n", - "3 7.20 146.75 1 " + " Latency_P99 Throughput(QPS) intra_op_num_threads \n", + "0 2.17 575.17 14 \n", + "1 2.14 574.96 24 \n", + "2 2.16 574.28 15 \n", + "3 2.15 572.89 6 \n", + "4 2.14 569.77 13 \n", + "5 2.15 568.67 5 \n", + "6 2.19 566.45 32 \n", + "7 2.17 566.38 7 \n", + "8 2.18 566.14 3 \n", + "9 2.17 566.09 11 \n", + "10 2.13 565.70 9 \n", + "11 2.16 565.50 8 \n", + "12 2.20 565.09 1 \n", + "13 2.15 563.97 10 \n", + "14 2.19 563.25 2 \n", + "15 2.19 561.98 4 \n", + "16 2.16 559.84 12 " ] }, - "execution_count": 22, + "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "import os\n", - "import glob \n", - "import pandas\n", - "latest_result_file = max(glob.glob(\"./onnx/perf_results_GPU_B1_S128_*.txt\"), key=os.path.getmtime)\n", - "result_data = pandas.read_table(latest_result_file)\n", - "print(\"Float32 model perf results from\", latest_result_file)\n", - "# Remove some columns that have same values for all rows.\n", - "columns_to_remove = ['model', 'graph_optimization_level', 'batch_size', 'sequence_length', 'test_cases', 'test_times', 'use_gpu']\n", - "result_data.drop(columns_to_remove, axis=1, inplace=True)\n", - "result_data" + "fp32_result = load_last_perf_test_result()\n", + "fp32_result" ] }, { @@ -1117,59 +1476,265 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "test setting TestSetting(batch_size=32, sequence_length=128, test_cases=1000, test_times=1, use_gpu=True, intra_op_num_threads=3, seed=3, verbose=False)\n", + "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=8,batch_size=32,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True,use_io_binding=True,average_sequence_length=128,random_sequence_length=False\n", + "Average latency = 20.41 ms, Throughput = 1567.65 QPS\n", + "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=8,batch_size=1,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True,use_io_binding=True,average_sequence_length=128,random_sequence_length=False\n", + "Average latency = 1.73 ms, Throughput = 576.74 QPS\n", + "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=8,batch_size=2,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True,use_io_binding=True,average_sequence_length=128,random_sequence_length=False\n", + "Average latency = 2.18 ms, Throughput = 917.92 QPS\n", + "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=8,batch_size=4,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True,use_io_binding=True,average_sequence_length=128,random_sequence_length=False\n", + "Average latency = 3.25 ms, Throughput = 1229.91 QPS\n", + "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=8,batch_size=8,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True,use_io_binding=True,average_sequence_length=128,random_sequence_length=False\n", + "Average latency = 5.38 ms, Throughput = 1486.89 QPS\n", + "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=8,batch_size=16,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True,use_io_binding=True,average_sequence_length=128,random_sequence_length=False\n", + "Average latency = 9.90 ms, Throughput = 1616.79 QPS\n", + "test setting TestSetting(batch_size=32, sequence_length=128, test_cases=1000, test_times=1, use_gpu=True, use_io_binding=True, provider=None, intra_op_num_threads=8, seed=3, verbose=False, log_severity=2, average_sequence_length=128, random_sequence_length=False)\n", "Generating 1000 samples for batch_size=32 sequence_length=128\n", - "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=3,batch_size=32,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True\n", - "Average latency = 168.40 ms, Throughput = 190.02 QPS\n", - "test setting TestSetting(batch_size=1, sequence_length=128, test_cases=1000, test_times=1, use_gpu=True, intra_op_num_threads=3, seed=3, verbose=False)\n", + "test setting TestSetting(batch_size=1, sequence_length=128, test_cases=1000, test_times=1, use_gpu=True, use_io_binding=True, provider=None, intra_op_num_threads=8, seed=3, verbose=False, log_severity=2, average_sequence_length=128, random_sequence_length=False)\n", "Generating 1000 samples for batch_size=1 sequence_length=128\n", - "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=3,batch_size=1,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True\n", - "Average latency = 7.14 ms, Throughput = 140.00 QPS\n", - "test setting TestSetting(batch_size=2, sequence_length=128, test_cases=1000, test_times=1, use_gpu=True, intra_op_num_threads=3, seed=3, verbose=False)\n", + "test setting TestSetting(batch_size=2, sequence_length=128, test_cases=1000, test_times=1, use_gpu=True, use_io_binding=True, provider=None, intra_op_num_threads=8, seed=3, verbose=False, log_severity=2, average_sequence_length=128, random_sequence_length=False)\n", "Generating 1000 samples for batch_size=2 sequence_length=128\n", - "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=3,batch_size=2,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True\n", - "Average latency = 11.27 ms, Throughput = 177.41 QPS\n", - "test setting TestSetting(batch_size=4, sequence_length=128, test_cases=1000, test_times=1, use_gpu=True, intra_op_num_threads=3, seed=3, verbose=False)\n", + "test setting TestSetting(batch_size=4, sequence_length=128, test_cases=1000, test_times=1, use_gpu=True, use_io_binding=True, provider=None, intra_op_num_threads=8, seed=3, verbose=False, log_severity=2, average_sequence_length=128, random_sequence_length=False)\n", "Generating 1000 samples for batch_size=4 sequence_length=128\n", - "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=3,batch_size=4,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True\n", - "Average latency = 21.15 ms, Throughput = 189.09 QPS\n", - "test setting TestSetting(batch_size=8, sequence_length=128, test_cases=1000, test_times=1, use_gpu=True, intra_op_num_threads=3, seed=3, verbose=False)\n", + "test setting TestSetting(batch_size=8, sequence_length=128, test_cases=1000, test_times=1, use_gpu=True, use_io_binding=True, provider=None, intra_op_num_threads=8, seed=3, verbose=False, log_severity=2, average_sequence_length=128, random_sequence_length=False)\n", "Generating 1000 samples for batch_size=8 sequence_length=128\n", - "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=3,batch_size=8,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True\n", - "Average latency = 42.27 ms, Throughput = 189.27 QPS\n", - "test setting TestSetting(batch_size=16, sequence_length=128, test_cases=1000, test_times=1, use_gpu=True, intra_op_num_threads=3, seed=3, verbose=False)\n", + "test setting TestSetting(batch_size=16, sequence_length=128, test_cases=1000, test_times=1, use_gpu=True, use_io_binding=True, provider=None, intra_op_num_threads=8, seed=3, verbose=False, log_severity=2, average_sequence_length=128, random_sequence_length=False)\n", "Generating 1000 samples for batch_size=16 sequence_length=128\n", - "Running test: model=bert-base-cased-squad_opt_gpu_fp16.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=3,batch_size=16,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True\n", - "Average latency = 83.77 ms, Throughput = 191.01 QPS\n", - "Test summary is saved to onnx/perf_results_GPU_B1-2-4-8-16-32_S128_20210714-002816.txt\n" + "Test summary is saved to onnx\\perf_results_GPU_B1-2-4-8-16-32_S128_20230912-130248.txt\n" ] } ], "source": [ - "GPU_OPTION = '--use_gpu' if use_gpu else ''\n", - "THREAD_SETTING = '--intra_op_num_threads 3'\n", + "THREAD_SETTING = '--intra_op_num_threads 8'\n", "!{sys.executable} -m onnxruntime.transformers.bert_perf_test --model $optimized_fp16_model_path --batch_size 1 2 4 8 16 32 --sequence_length 128 --samples 1000 --test_times 1 $THREAD_SETTING $GPU_OPTION" ] }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Perf results from ./onnx\\perf_results_GPU_B1-2-4-8-16-32_S128_20230912-130248.txt\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Latency(ms)Latency_P50Latency_P75Latency_P90Latency_P95Latency_P99Throughput(QPS)intra_op_num_threads
01.731.721.731.731.792.04576.748
12.182.162.162.182.292.76917.928
23.253.253.263.283.293.431229.918
35.385.385.395.425.445.601486.898
49.909.899.949.9710.0010.061616.798
520.4120.4120.4720.5220.5520.681567.658
\n", + "
" + ], + "text/plain": [ + " Latency(ms) Latency_P50 Latency_P75 Latency_P90 Latency_P95 \\\n", + "0 1.73 1.72 1.73 1.73 1.79 \n", + "1 2.18 2.16 2.16 2.18 2.29 \n", + "2 3.25 3.25 3.26 3.28 3.29 \n", + "3 5.38 5.38 5.39 5.42 5.44 \n", + "4 9.90 9.89 9.94 9.97 10.00 \n", + "5 20.41 20.41 20.47 20.52 20.55 \n", + "\n", + " Latency_P99 Throughput(QPS) intra_op_num_threads \n", + "0 2.04 576.74 8 \n", + "1 2.76 917.92 8 \n", + "2 3.43 1229.91 8 \n", + "3 5.60 1486.89 8 \n", + "4 10.06 1616.79 8 \n", + "5 20.68 1567.65 8 " + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fp16_result = load_last_perf_test_result()\n", + "fp16_result" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Packing Mode (Effective Transformer)\n", + "\n", + "When padding ratio is high, it is helpful to use packing mode, also known as [effective transformer](https://github.com/bytedance/effective_transformer).\n", + "This feature requires onnxruntime-gpu verison 1.16 or later. \n", + "\n", + "In below example, average sequence length after removing paddings is 32, the sequence length with paddings is 128. We can see 3x throughput with packing mode (QPS increased from 1617 to 5652)." + ] + }, { "cell_type": "code", "execution_count": 24, - "metadata": { - "scrolled": false - }, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "_replace_attention_with_packing_attention: Converted 24 Attention nodes to PackedAttention.\n", + " save_model_to_file: Sort graphs in topological order\n", + " save: Delete the existing onnx file: ./onnx/bert-base-cased-squad_opt_gpu_fp16_packed.onnx\n", + " save: Delete the existing external data file: ./onnx/bert-base-cased-squad_opt_gpu_fp16_packed.onnx.data\n", + " save_model_to_file: Model saved to ./onnx/bert-base-cased-squad_opt_gpu_fp16_packed.onnx\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Running test: model=bert-base-cased-squad_opt_gpu_fp16_packed.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=8,batch_size=32,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True,use_io_binding=True,average_sequence_length=32,random_sequence_length=False\n", + "Average latency = 5.66 ms, Throughput = 5652.40 QPS\n", + "Running test: model=bert-base-cased-squad_opt_gpu_fp16_packed.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=8,batch_size=1,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True,use_io_binding=True,average_sequence_length=32,random_sequence_length=False\n", + "Average latency = 1.70 ms, Throughput = 586.97 QPS\n", + "Running test: model=bert-base-cased-squad_opt_gpu_fp16_packed.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=8,batch_size=2,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True,use_io_binding=True,average_sequence_length=32,random_sequence_length=False\n", + "Average latency = 1.79 ms, Throughput = 1114.37 QPS\n", + "Running test: model=bert-base-cased-squad_opt_gpu_fp16_packed.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=8,batch_size=4,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True,use_io_binding=True,average_sequence_length=32,random_sequence_length=False\n", + "Average latency = 1.77 ms, Throughput = 2262.31 QPS\n", + "Running test: model=bert-base-cased-squad_opt_gpu_fp16_packed.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=8,batch_size=8,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True,use_io_binding=True,average_sequence_length=32,random_sequence_length=False\n", + "Average latency = 2.18 ms, Throughput = 3666.45 QPS\n", + "Running test: model=bert-base-cased-squad_opt_gpu_fp16_packed.onnx,graph_optimization_level=ENABLE_ALL,intra_op_num_threads=8,batch_size=16,sequence_length=128,test_cases=1000,test_times=1,use_gpu=True,use_io_binding=True,average_sequence_length=32,random_sequence_length=False\n", + "Average latency = 3.31 ms, Throughput = 4829.58 QPS\n", + "test setting TestSetting(batch_size=32, sequence_length=128, test_cases=1000, test_times=1, use_gpu=True, use_io_binding=True, provider=None, intra_op_num_threads=8, seed=3, verbose=False, log_severity=2, average_sequence_length=32, random_sequence_length=False)\n", + "Generating 1000 samples for batch_size=32 sequence_length=128\n", + "test setting TestSetting(batch_size=1, sequence_length=128, test_cases=1000, test_times=1, use_gpu=True, use_io_binding=True, provider=None, intra_op_num_threads=8, seed=3, verbose=False, log_severity=2, average_sequence_length=32, random_sequence_length=False)\n", + "Generating 1000 samples for batch_size=1 sequence_length=128\n", + "test setting TestSetting(batch_size=2, sequence_length=128, test_cases=1000, test_times=1, use_gpu=True, use_io_binding=True, provider=None, intra_op_num_threads=8, seed=3, verbose=False, log_severity=2, average_sequence_length=32, random_sequence_length=False)\n", + "Generating 1000 samples for batch_size=2 sequence_length=128\n", + "test setting TestSetting(batch_size=4, sequence_length=128, test_cases=1000, test_times=1, use_gpu=True, use_io_binding=True, provider=None, intra_op_num_threads=8, seed=3, verbose=False, log_severity=2, average_sequence_length=32, random_sequence_length=False)\n", + "Generating 1000 samples for batch_size=4 sequence_length=128\n", + "test setting TestSetting(batch_size=8, sequence_length=128, test_cases=1000, test_times=1, use_gpu=True, use_io_binding=True, provider=None, intra_op_num_threads=8, seed=3, verbose=False, log_severity=2, average_sequence_length=32, random_sequence_length=False)\n", + "Generating 1000 samples for batch_size=8 sequence_length=128\n", + "test setting TestSetting(batch_size=16, sequence_length=128, test_cases=1000, test_times=1, use_gpu=True, use_io_binding=True, provider=None, intra_op_num_threads=8, seed=3, verbose=False, log_severity=2, average_sequence_length=32, random_sequence_length=False)\n", + "Generating 1000 samples for batch_size=16 sequence_length=128\n", + "Test summary is saved to onnx\\perf_results_GPU_B1-2-4-8-16-32_S128_20230912-130354.txt\n" + ] + } + ], + "source": [ + "assert use_gpu, \"Require GPU for packing mode\"\n", + "packed_fp16_model_path = './onnx/bert-base-cased-squad_opt_gpu_fp16_packed.onnx'\n", + "!{sys.executable} -m onnxruntime.transformers.convert_to_packing_mode --input $optimized_fp16_model_path --output $packed_fp16_model_path --use_external_data_format\n", + "!{sys.executable} -m onnxruntime.transformers.bert_perf_test --model $packed_fp16_model_path --batch_size 1 2 4 8 16 32 --sequence_length 128 --average_sequence_length 32 --samples 1000 --test_times 1 $THREAD_SETTING $GPU_OPTION " + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Float16 model summary from ./onnx/perf_results_GPU_B1-2-4-8-16-32_S128_20210714-002816.txt\n" + "Perf results from ./onnx\\perf_results_GPU_B1-2-4-8-16-32_S128_20230912-130354.txt\n" ] }, { @@ -1200,75 +1765,75 @@ " Latency_P95\n", " Latency_P99\n", " Throughput(QPS)\n", - " batch_size\n", + " intra_op_num_threads\n", " \n", " \n", " \n", " \n", " 0\n", - " 7.14\n", - " 7.10\n", - " 7.13\n", - " 7.25\n", - " 7.35\n", - " 10.99\n", - " 140.00\n", - " 1\n", + " 1.70\n", + " 1.63\n", + " 1.65\n", + " 2.13\n", + " 2.20\n", + " 2.32\n", + " 586.97\n", + " 8\n", " \n", " \n", " 1\n", - " 11.27\n", - " 11.23\n", - " 11.28\n", - " 11.53\n", - " 11.57\n", - " 12.05\n", - " 177.41\n", - " 2\n", + " 1.77\n", + " 1.74\n", + " 1.76\n", + " 1.82\n", + " 1.93\n", + " 2.17\n", + " 2262.31\n", + " 8\n", " \n", " \n", " 2\n", - " 21.15\n", - " 21.13\n", - " 21.25\n", - " 21.44\n", - " 21.59\n", - " 22.07\n", - " 189.09\n", - " 4\n", + " 1.79\n", + " 1.73\n", + " 1.74\n", + " 2.12\n", + " 2.18\n", + " 2.32\n", + " 1114.37\n", + " 8\n", " \n", " \n", " 3\n", - " 42.27\n", - " 42.26\n", - " 42.68\n", - " 42.95\n", - " 43.11\n", - " 45.11\n", - " 189.27\n", + " 2.18\n", + " 2.16\n", + " 2.17\n", + " 2.22\n", + " 2.30\n", + " 2.64\n", + " 3666.45\n", " 8\n", " \n", " \n", " 4\n", - " 83.77\n", - " 83.84\n", - " 84.29\n", - " 84.94\n", - " 85.35\n", - " 86.34\n", - " 191.01\n", - " 16\n", + " 3.31\n", + " 3.31\n", + " 3.32\n", + " 3.35\n", + " 3.39\n", + " 3.51\n", + " 4829.58\n", + " 8\n", " \n", " \n", " 5\n", - " 168.40\n", - " 169.62\n", - " 170.78\n", - " 171.94\n", - " 172.82\n", - " 174.28\n", - " 190.02\n", - " 32\n", + " 5.66\n", + " 5.66\n", + " 5.68\n", + " 5.71\n", + " 5.74\n", + " 5.91\n", + " 5652.40\n", + " 8\n", " \n", " \n", "\n", @@ -1276,38 +1841,30 @@ ], "text/plain": [ " Latency(ms) Latency_P50 Latency_P75 Latency_P90 Latency_P95 \\\n", - "0 7.14 7.10 7.13 7.25 7.35 \n", - "1 11.27 11.23 11.28 11.53 11.57 \n", - "2 21.15 21.13 21.25 21.44 21.59 \n", - "3 42.27 42.26 42.68 42.95 43.11 \n", - "4 83.77 83.84 84.29 84.94 85.35 \n", - "5 168.40 169.62 170.78 171.94 172.82 \n", + "0 1.70 1.63 1.65 2.13 2.20 \n", + "1 1.77 1.74 1.76 1.82 1.93 \n", + "2 1.79 1.73 1.74 2.12 2.18 \n", + "3 2.18 2.16 2.17 2.22 2.30 \n", + "4 3.31 3.31 3.32 3.35 3.39 \n", + "5 5.66 5.66 5.68 5.71 5.74 \n", "\n", - " Latency_P99 Throughput(QPS) batch_size \n", - "0 10.99 140.00 1 \n", - "1 12.05 177.41 2 \n", - "2 22.07 189.09 4 \n", - "3 45.11 189.27 8 \n", - "4 86.34 191.01 16 \n", - "5 174.28 190.02 32 " + " Latency_P99 Throughput(QPS) intra_op_num_threads \n", + "0 2.32 586.97 8 \n", + "1 2.17 2262.31 8 \n", + "2 2.32 1114.37 8 \n", + "3 2.64 3666.45 8 \n", + "4 3.51 4829.58 8 \n", + "5 5.91 5652.40 8 " ] }, - "execution_count": 24, + "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "import os\n", - "import glob \n", - "import pandas\n", - "latest_result_file = max(glob.glob(\"./onnx/perf_results_*.txt\"), key=os.path.getmtime)\n", - "result_data = pandas.read_table(latest_result_file)\n", - "print(\"Float16 model summary from\", latest_result_file)\n", - "columns_to_remove = ['model', 'graph_optimization_level', 'test_cases', 'test_times', 'use_gpu', 'sequence_length']\n", - "columns_to_remove.extend(['intra_op_num_threads'])\n", - "result_data.drop(columns_to_remove, axis=1, inplace=True)\n", - "result_data" + "packing_result = load_last_perf_test_result()\n", + "packing_result" ] }, { @@ -1327,7 +1884,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 26, "metadata": { "scrolled": true }, @@ -1336,131 +1893,53 @@ "name": "stdout", "output_type": "stream", "text": [ - "{\r\n", - " \"gpu\": {\r\n", - " \"driver_version\": \"450.51.05\",\r\n", - " \"devices\": [\r\n", - " {\r\n", - " \"memory_total\": 15843721216,\r\n", - " \"memory_available\": 9313189888,\r\n", - " \"name\": \"Tesla T4\"\r\n", - " }\r\n", - " ]\r\n", - " },\r\n", - " \"cpu\": {\r\n", - " \"brand\": \"AMD EPYC 7V12 64-Core Processor\",\r\n", - " \"cores\": 4,\r\n", - " \"logical_cores\": 4,\r\n", - " \"hz\": [\r\n", - " 2445417000,\r\n", - " 0\r\n", - " ],\r\n", - " \"l2_cache\": 524288,\r\n", - " \"flags\": [\r\n", - " \"3dnowext\",\r\n", - " \"3dnowprefetch\",\r\n", - " \"abm\",\r\n", - " \"adx\",\r\n", - " \"aes\",\r\n", - " \"apic\",\r\n", - " \"arat\",\r\n", - " \"avx\",\r\n", - " \"avx2\",\r\n", - " \"bmi1\",\r\n", - " \"bmi2\",\r\n", - " \"clflush\",\r\n", - " \"clflushopt\",\r\n", - " \"clwb\",\r\n", - " \"cmov\",\r\n", - " \"cmp_legacy\",\r\n", - " \"cpuid\",\r\n", - " \"cr8_legacy\",\r\n", - " \"cx16\",\r\n", - " \"cx8\",\r\n", - " \"de\",\r\n", - " \"extd_apicid\",\r\n", - " \"f16c\",\r\n", - " \"fma\",\r\n", - " \"fpu\",\r\n", - " \"fsgsbase\",\r\n", - " \"fxsr\",\r\n", - " \"fxsr_opt\",\r\n", - " \"ht\",\r\n", - " \"hypervisor\",\r\n", - " \"lahf_lm\",\r\n", - " \"lm\",\r\n", - " \"mca\",\r\n", - " \"mce\",\r\n", - " \"misalignsse\",\r\n", - " \"mmx\",\r\n", - " \"mmxext\",\r\n", - " \"movbe\",\r\n", - " \"msr\",\r\n", - " \"mtrr\",\r\n", - " \"nopl\",\r\n", - " \"nx\",\r\n", - " \"osvw\",\r\n", - " \"osxsave\",\r\n", - " \"pae\",\r\n", - " \"pat\",\r\n", - " \"pclmulqdq\",\r\n", - " \"pdpe1gb\",\r\n", - " \"pge\",\r\n", - " \"pni\",\r\n", - " \"popcnt\",\r\n", - " \"pse\",\r\n", - " \"pse36\",\r\n", - " \"rdpid\",\r\n", - " \"rdrand\",\r\n", - " \"rdrnd\",\r\n", - " \"rdseed\",\r\n", - " \"rdtscp\",\r\n", - " \"rep_good\",\r\n", - " \"sep\",\r\n", - " \"sha\",\r\n", - " \"sha_ni\",\r\n", - " \"smap\",\r\n", - " \"smep\",\r\n", - " \"ssbd\",\r\n", - " \"sse\",\r\n", - " \"sse2\",\r\n", - " \"sse4_1\",\r\n", - " \"sse4_2\",\r\n", - " \"sse4a\",\r\n", - " \"ssse3\",\r\n", - " \"syscall\",\r\n", - " \"topoext\",\r\n", - " \"tsc\",\r\n", - " \"umip\",\r\n", - " \"vme\",\r\n", - " \"vmmcall\",\r\n", - " \"xgetbv1\",\r\n", - " \"xsave\",\r\n", - " \"xsavec\",\r\n", - " \"xsaveerptr\",\r\n", - " \"xsaveopt\",\r\n", - " \"xsaves\"\r\n", - " ],\r\n", - " \"processor\": \"x86_64\"\r\n", - " },\r\n", - " \"memory\": {\r\n", - " \"total\": 29450223616,\r\n", - " \"available\": 22402334720\r\n", - " },\r\n", - " \"python\": \"3.6.13.final.0 (64 bit)\",\r\n", - " \"os\": \"Linux-5.4.0-1046-azure-x86_64-with-debian-buster-sid\",\r\n", - " \"onnxruntime\": {\r\n", - " \"version\": \"1.8.1\",\r\n", - " \"support_gpu\": true\r\n", - " },\r\n", - " \"onnxruntime_tools\": null,\r\n", - " \"pytorch\": {\r\n", - " \"version\": \"1.9.0+cu111\",\r\n", - " \"support_gpu\": true,\r\n", - " \"cuda\": \"11.1\"\r\n", - " },\r\n", - " \"tensorflow\": null\r\n", - "}\r\n" + "{\n", + " \"gpu\": {\n", + " \"driver_version\": \"537.13\",\n", + " \"devices\": [\n", + " {\n", + " \"memory_total\": 25757220864,\n", + " \"memory_available\": 18009264128,\n", + " \"name\": \"NVIDIA GeForce RTX 4090\"\n", + " }\n", + " ]\n", + " },\n", + " \"cpu\": {\n", + " \"brand\": \"13th Gen Intel(R) Core(TM) i9-13900\",\n", + " \"cores\": 24,\n", + " \"logical_cores\": 32,\n", + " \"hz\": \"2000000000,0\",\n", + " \"l2_cache\": 33554432,\n", + " \"flags\": \"3dnow,3dnowprefetch,abm,acpi,adx,aes,apic,avx,avx2,bmi1,bmi2,clflush,clflushopt,clwb,cmov,cx16,cx8,de,dts,erms,est,f16c,fma,fpu,fxsr,gfni,ht,hypervisor,ia64,intel_pt,invpcid,lahf_lm,mca,mce,mmx,monitor,movbe,msr,mtrr,osxsave,pae,pat,pbe,pcid,pclmulqdq,pdcm,pge,pni,popcnt,pse,pse36,rdpid,rdrnd,rdseed,sep,serial,sha,smap,smep,ss,sse,sse2,sse4_1,sse4_2,ssse3,tm,tm2,tsc,tscdeadline,umip,vaes,vme,vpclmulqdq,x2apic,xsave,xtpr\",\n", + " \"processor\": \"Intel64 Family 6 Model 183 Stepping 1, GenuineIntel\"\n", + " },\n", + " \"memory\": {\n", + " \"total\": 33992912896,\n", + " \"available\": 17272422400\n", + " },\n", + " \"os\": \"Windows-10-10.0.22621-SP0\",\n", + " \"python\": \"3.10.13.final.0 (64 bit)\",\n", + " \"packages\": {\n", + " \"flatbuffers\": \"23.5.26\",\n", + " \"numpy\": \"1.25.2\",\n", + " \"onnx\": \"1.14.1\",\n", + " \"onnxruntime-gpu\": \"1.16.0\",\n", + " \"protobuf\": \"3.20.3\",\n", + " \"sympy\": \"1.12\",\n", + " \"torch\": \"2.0.1+cu118\",\n", + " \"transformers\": \"4.33.1\"\n", + " },\n", + " \"onnxruntime\": {\n", + " \"version\": \"1.16.0\",\n", + " \"support_gpu\": true\n", + " },\n", + " \"pytorch\": {\n", + " \"version\": \"2.0.1+cu118\",\n", + " \"support_gpu\": true,\n", + " \"cuda\": \"11.8\"\n", + " },\n", + " \"tensorflow\": null\n", + "}\n" ] } ], @@ -1485,9 +1964,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.13" + "version": "3.10.13" } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } diff --git a/onnxruntime/python/tools/transformers/onnx_exporter.py b/onnxruntime/python/tools/transformers/onnx_exporter.py index 38f7f8cd05f1d..4e064fa53bfc6 100644 --- a/onnxruntime/python/tools/transformers/onnx_exporter.py +++ b/onnxruntime/python/tools/transformers/onnx_exporter.py @@ -6,7 +6,6 @@ import logging import os -import sys from pathlib import Path import numpy @@ -18,8 +17,11 @@ from torch_onnx_export_helper import torch_onnx_export from transformers import AutoConfig, AutoFeatureExtractor, AutoTokenizer, LxmertConfig, TransfoXLConfig -sys.path.append(os.path.join(os.path.dirname(__file__), "models", "gpt2")) -from gpt2_helper import PRETRAINED_GPT2_MODELS, GPT2ModelNoPastState, TFGPT2ModelNoPastState # noqa: E402 +from onnxruntime.transformers.models.gpt2.gpt2_helper import ( + PRETRAINED_GPT2_MODELS, + GPT2ModelNoPastState, + TFGPT2ModelNoPastState, +) os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" diff --git a/onnxruntime/python/tools/transformers/onnx_model.py b/onnxruntime/python/tools/transformers/onnx_model.py index 7acfedabe6d3a..60be2d84b2bc8 100644 --- a/onnxruntime/python/tools/transformers/onnx_model.py +++ b/onnxruntime/python/tools/transformers/onnx_model.py @@ -3,6 +3,7 @@ # Licensed under the MIT License. # -------------------------------------------------------------------------- +import itertools import logging import os import sys @@ -11,7 +12,18 @@ from typing import Dict, List, Optional, Tuple from float16 import convert_float_to_float16 -from onnx import AttributeProto, GraphProto, ModelProto, NodeProto, TensorProto, helper, numpy_helper, save_model +from onnx import ( + AttributeProto, + GraphProto, + ModelProto, + NodeProto, + TensorProto, + ValueInfoProto, + helper, + numpy_helper, + save_model, +) +from onnx.external_data_helper import load_external_data_for_tensor, uses_external_data from shape_infer_helper import SymbolicShapeInferenceHelper logger = logging.getLogger(__name__) @@ -68,7 +80,7 @@ def nodes(self): all_nodes = [] for graph in self.graphs(): for node in graph.node: - all_nodes.append(node) + all_nodes.append(node) # noqa: PERF402 return all_nodes def graph(self): @@ -217,7 +229,7 @@ def get_children(self, node, input_name_to_nodes=None): for output in node.output: if output in input_name_to_nodes: for node in input_name_to_nodes[output]: - children.append(node) + children.append(node) # noqa: PERF402 return children def get_parents(self, node, output_name_to_node=None): @@ -590,11 +602,18 @@ def convert_float_to_float16(self, use_symbolic_shape_infer=True, **kwargs): To use mixed precision, user need specify which graph inputs, outputs, operator type or list of nodes shall keep in float32. - By default, we use symbolic shape inference to get shape and type information. - If not, ONNX shape inference will be used. + Note that the conversion might not proceed without type information for the whole graph. - Note that symbolic/ONNX shape inference might fail, and the conversion might not proceed - without shape and type information. + By default, we use symbolic shape inference to get type information. The benefit of symbolic shape inference + is that it could handle fused operators in com.microsoft domain. Those operators cannot be handled in onnx shape + inference so symbolic shape inference is recommended for optimized model. + + When symbolic shape inference is used (even if it failed), ONNX shape inference will be disabled. + + Note that onnx shape inference will fail for model larger than 2GB. For large model, you have to eanble + symbolic shape inference. If your model is not optimized, you can also use model path to call + convert_float_to_float16 in float16.py (see https://github.com/microsoft/onnxruntime/pull/15067) to + avoid the 2GB limit. Args: use_symbolic_shape_infer (bool, optional): use symbolic shape inference instead of onnx shape inference. @@ -609,6 +628,8 @@ def convert_float_to_float16(self, use_symbolic_shape_infer=True, **kwargs): Default to false. min_positive_val (float, optional): minimal positive value. Defaults to 1e-7. max_finite_val (float, optional): maximal finite value. Defaults to 1e4. + force_fp16_inputs(Dict[str, List[int]]): Force the conversion of the inputs of some operators to float16, even if + this script's preference it to keep them in float32. """ if "keep_io_types" not in kwargs: kwargs["keep_io_types"] = True @@ -617,8 +638,36 @@ def convert_float_to_float16(self, use_symbolic_shape_infer=True, **kwargs): if use_symbolic_shape_infer: # Use symbolic shape inference since custom operators (like Gelu, SkipLayerNormalization etc) # are not recognized by onnx shape inference. - shape_infer_helper = SymbolicShapeInferenceHelper(model, verbose=0) - model = shape_infer_helper.infer_shapes(model, auto_merge=True, guess_output_rank=False) + shape_infer_helper = SymbolicShapeInferenceHelper(model) + try: + model_with_shape = shape_infer_helper.infer_shapes(model, auto_merge=True, guess_output_rank=False) + + # auto_merge might cause issue (see https://github.com/microsoft/onnxruntime/issues/15521) + # we only merge tensor data type but not shape information back to the original onnx model. + # Note that float16 conversion need data type but not shape information. + if model_with_shape is not None: + name_vi = {} + for vi in model_with_shape.graph.value_info: + if ( + hasattr(vi.type, "tensor_type") + and hasattr(vi.type.tensor_type, "elem_type") + and vi.type.tensor_type.elem_type != TensorProto.UNDEFINED + and vi.name + ): + vi_copy = ValueInfoProto() + vi_copy.CopyFrom(vi) + if hasattr(vi_copy.type.tensor_type, "shape"): + vi_copy.type.tensor_type.ClearField("shape") + name_vi[vi.name] = vi_copy + for vi in model.graph.value_info: + if vi.name in name_vi: + del name_vi[vi.name] + for vi in name_vi.values(): + model.graph.value_info.append(vi) # noqa: PERF402 + except Exception: + logger.warning( + "Failed to run symbolic shape inference. Please file an issue in https://github.com/microsoft/onnxruntime." + ) parameters = {"disable_shape_infer": use_symbolic_shape_infer} parameters.update( @@ -631,6 +680,7 @@ def convert_float_to_float16(self, use_symbolic_shape_infer=True, **kwargs): "op_block_list", "node_block_list", "force_fp16_initializers", + "force_fp16_inputs", ] if key in kwargs } @@ -766,56 +816,77 @@ def prune_graph(self, outputs=None, allow_remove_graph_inputs=True): """ if len(self.graphs()) > 1: + # TODO(tianleiwu): handle subgraph logger.debug("Skip prune_graph since graph has subgraph") return - if outputs is None: - outputs = [output.name for output in self.model.graph.output] + keep_outputs = [output.name for output in self.model.graph.output] if outputs is None else outputs output_name_to_node = self.output_name_to_node() - all_nodes = [] - for output in outputs: - if output in output_name_to_node: - last_node = output_name_to_node[output] - if last_node in all_nodes: - continue - nodes = self.get_parent_subgraph_nodes(last_node, []) - all_nodes.append(last_node) - all_nodes.extend(nodes) - nodes_to_remove = [] + def get_first_output(node): + if node.output[0]: + return node.output[0] + return next(iter([o for o in node.output if o]), None) + + # Keep track of nodes to keep. The key is first output of node, and the value is the node. + output_to_node = {} + + # Start from graph outputs, and find parent nodes recurisvely, and add nodes to the output_to_node dictionary. + dq = deque() + for output in keep_outputs: + if output in output_name_to_node: + dq.append(output_name_to_node[output]) + while len(dq) > 0: + node = dq.pop() + first_output = get_first_output(node) + if first_output and (first_output not in output_to_node): + output_to_node[first_output] = node + for name in node.input: + if len(name) > 0 and (name in output_name_to_node) and (name not in output_to_node): + dq.appendleft(output_name_to_node[name]) + + # Keep only those nodes in the output_to_node dictionary. + nodes_to_keep = [] + num_nodes_removed = 0 for node in self.model.graph.node: - if node not in all_nodes: - nodes_to_remove.append(node) + first_output = get_first_output(node) + kept_node = output_to_node[first_output] if first_output in output_to_node else None - self.remove_nodes(nodes_to_remove) + # Need double check the node since fused node might reuse output name of some nodes to be removed. + # It is slow to compare whole node, so we compare op_type first to avoid comparing node in most cases. + if kept_node and kept_node.op_type == node.op_type and kept_node == node: + nodes_to_keep.append(node) + else: + num_nodes_removed += 1 + self.model.graph.ClearField("node") + self.model.graph.node.extend(nodes_to_keep) - # remove outputs not in list + # Remove graph outputs not in list output_to_remove = [] - for output in self.model.graph.output: - if output.name not in outputs: - output_to_remove.append(output) - for output in output_to_remove: - self.model.graph.output.remove(output) - - # remove inputs not used by any node. + if outputs is not None: + for output in self.model.graph.output: + if output.name not in outputs: + output_to_remove.append(output) + for output in output_to_remove: + self.model.graph.output.remove(output) + + # Remove graph inputs not used by any node. input_to_remove = [] if allow_remove_graph_inputs: input_name_to_nodes = self.input_name_to_nodes() - for input in self.model.graph.input: - if input.name not in input_name_to_nodes: - input_to_remove.append(input) - for input in input_to_remove: - self.model.graph.input.remove(input) + input_to_remove = [input for input in self.model.graph.input if input.name not in input_name_to_nodes] + for name in input_to_remove: + self.model.graph.input.remove(name) - if input_to_remove or output_to_remove or nodes_to_remove: + if input_to_remove or output_to_remove or num_nodes_removed > 0: removed = [] if input_to_remove: removed.append(f"{len(input_to_remove)} inputs") if output_to_remove: removed.append(f"{len(output_to_remove)} outputs") - if nodes_to_remove: - removed.append(f"{len(nodes_to_remove)} nodes") + if num_nodes_removed > 0: + removed.append(f"{num_nodes_removed} nodes") logger.info("Removed %s", ", ".join(removed)) self.update_graph() @@ -901,6 +972,7 @@ def graph_topological_sort(graph, is_deterministic=False): sorted_node_set_len = -1 graph_nodes = graph.node if not is_deterministic else sorted(graph.node, key=lambda x: x.name) + last_node_name = None while len(sorted_node_set) != len(graph_nodes): if len(sorted_node_set) == sorted_node_set_len: @@ -914,7 +986,8 @@ def graph_topological_sort(graph, is_deterministic=False): sorted_nodes.append(node) sorted_node_set.add(node_idx) for output in node.output: - deps_set.add(output) + if output: + deps_set.add(output) continue failed = False for input_name in node.input: @@ -925,7 +998,8 @@ def graph_topological_sort(graph, is_deterministic=False): sorted_nodes.append(node) sorted_node_set.add(node_idx) for output in node.output: - deps_set.add(output) + if output: + deps_set.add(output) else: continue @@ -972,13 +1046,13 @@ def save( location = Path(external_data_path).name if all_tensors_to_one_file else None if os.path.exists(output_path): - logger.info(f"Delete the existed onnx file: {output_path}") + logger.info(f"Delete the existing onnx file: {output_path}") os.remove(output_path) if all_tensors_to_one_file: if os.path.exists(external_data_path): # Delete the external data file. Otherwise, data will be appended to existing file. - logger.info(f"Delete the existed external data file: {external_data_path}") + logger.info(f"Delete the existing external data file: {external_data_path}") os.remove(external_data_path) else: if os.listdir(output_dir): @@ -1044,26 +1118,75 @@ def get_operator_statistics(self, include_domain=False): return op_count @staticmethod - def has_same_value(tensor1: TensorProto, tensor2: TensorProto) -> bool: + def to_data_hash(tensor: TensorProto, base_dir: str = "") -> int: + """Converts a tensor def object to a hash for data comparison purposes. + Args: + tensor: a TensorProto object. + base_dir: if external tensor exists, base_dir can help to find the path to it + Returns: + hash: a hash of the data. + """ + if tensor.HasField("segment"): + raise ValueError("Currently not supporting loading segments.") + if tensor.data_type == TensorProto.UNDEFINED: + raise TypeError("The element type in the input tensor is not defined.") + tensor_dtype = tensor.data_type + storage_field = helper.tensor_dtype_to_field(tensor_dtype) + + if tensor.data_type == TensorProto.STRING: + utf8_strings = getattr(tensor, storage_field) + return hash(tuple(s.decode("utf-8") for s in utf8_strings)) + # Load raw data from external tensor if it exists + if uses_external_data(tensor): + load_external_data_for_tensor(tensor, base_dir) + if tensor.HasField("raw_data"): + return hash(tensor.raw_data) + else: + np_data = numpy_helper.to_array(tensor) + return hash(np_data.tobytes()) + + @staticmethod + def has_same_value( + tensor1: TensorProto, + tensor2: TensorProto, + signature_cache1: Optional[dict] = None, + signature_cache2: Optional[dict] = None, + ) -> bool: """Returns True when two tensors have same value. Note that name can be different. Args: tensor1 (TensorProto): initializer 1 tensor2 (TensorProto): initializer 2 - + signature_cache1 (dict): Optional dictionary to store data signatures of tensor1 in order to speed up comparison. + signature_cache2 (dict): Optional dictionary to store data signatures of tensor2 in order to speed up comparison. Returns: bool: True when two intializers has same value. """ - if tensor1.data_type != tensor2.data_type or tensor1.dims != tensor2.dims: - return False - if tensor1.HasField("raw_data") and tensor2.HasField("raw_data"): - return tensor1.raw_data == tensor2.raw_data - return (numpy_helper.to_array(tensor1) == numpy_helper.to_array(tensor2)).all() + sig1 = ( + signature_cache1[tensor1.name] + if signature_cache1 and tensor1.name in signature_cache1 + else OnnxModel.to_data_hash(tensor1) + ) + sig2 = ( + signature_cache2[tensor2.name] + if signature_cache2 and tensor2.name in signature_cache2 + else OnnxModel.to_data_hash(tensor2) + ) + if signature_cache1 is not None: + signature_cache1[tensor1.name] = sig1 + if signature_cache2 is not None: + signature_cache2[tensor2.name] = sig2 + if sig1 == sig2 and tensor1.data_type == tensor2.data_type and tensor1.dims == tensor2.dims: + # Same signature, now do the expensive check to confirm the data is the same + return (numpy_helper.to_array(tensor1) == numpy_helper.to_array(tensor2)).all() + + return False - def remove_duplicated_initializer(self): + def remove_duplicated_initializer(self, cache: Optional[dict] = None): """Remove initializers with duplicated values, and only keep the first one. It could help reduce size of models (like ALBert) with shared weights. + If require_raw_data passed, method will only compare raw_data initializers to speed runtime Note: this function does not process subgraph. """ if len(self.graphs()) > 1: @@ -1076,7 +1199,9 @@ def remove_duplicated_initializer(self): if same[i] >= 0: continue for j in range(i + 1, initializer_count): - if OnnxModel.has_same_value(self.model.graph.initializer[i], self.model.graph.initializer[j]): + if OnnxModel.has_same_value( + self.model.graph.initializer[i], self.model.graph.initializer[j], cache, cache + ): same[j] = i count = 0 @@ -1127,3 +1252,48 @@ def add_prefix_to_names(self, prefix: str): def clean_shape_infer(self): self.model.graph.ClearField("value_info") + + def use_float16(self): + """Check whether the model uses float16""" + queue = [] # queue for BFS + queue.append(self.model.graph) + while queue: + sub_graphs = [] + for graph in queue: + if not isinstance(graph, GraphProto): + continue + + for v in itertools.chain(graph.input, graph.output, graph.value_info): + if v.type.tensor_type.elem_type == TensorProto.FLOAT16: + return True + if v.type.HasField("sequence_type"): + if v.type.sequence_type.elem_type.tensor_type.elem_type == TensorProto.FLOAT16: + return True + + for t in graph.initializer: + if t.data_type == TensorProto.FLOAT16: + return True + + for node in graph.node: + if node.op_type == "Cast": + for attr in node.attribute: + if attr.name == "to" and attr.i == TensorProto.FLOAT16: + return True + + for attr in node.attribute: + if attr.type == AttributeProto.GRAPH: + sub_graphs.append(attr.g) + + for g in attr.graphs: + sub_graphs.append(g) # noqa: PERF402 + + if isinstance(attr.t, TensorProto) and attr.t.data_type == TensorProto.FLOAT16: + return True + + for t in attr.tensors: + if isinstance(t, TensorProto) and t.data_type == TensorProto.FLOAT16: + return True + + queue = sub_graphs + + return False diff --git a/onnxruntime/python/tools/transformers/onnx_model_bart.py b/onnxruntime/python/tools/transformers/onnx_model_bart.py index cb496ea148dd2..2a48722d17a19 100644 --- a/onnxruntime/python/tools/transformers/onnx_model_bart.py +++ b/onnxruntime/python/tools/transformers/onnx_model_bart.py @@ -129,6 +129,9 @@ def __init__(self, model, num_heads, hidden_size): def optimize(self, options: Optional[FusionOptions] = None, add_dynamic_axes: bool = False): self.attention_fusion.use_multi_head_attention = False if options is None else options.use_multi_head_attention + self.attention_fusion.disable_multi_head_attention_bias = ( + False if options is None else options.disable_multi_head_attention_bias + ) super().optimize(options, add_dynamic_axes) def fuse_attention(self): diff --git a/onnxruntime/python/tools/transformers/onnx_model_bert.py b/onnxruntime/python/tools/transformers/onnx_model_bert.py index e84a08afc66ce..995f8c6541b4c 100644 --- a/onnxruntime/python/tools/transformers/onnx_model_bert.py +++ b/onnxruntime/python/tools/transformers/onnx_model_bert.py @@ -31,14 +31,6 @@ logger = getLogger(__name__) -class BertOptimizationOptions(FusionOptions): - """This class is deprecated""" - - def __init__(self, model_type): - logger.warning("BertOptimizationOptions is depreciated. Please use FusionOptions instead.") - super().__init__(model_type) - - class BertOnnxModel(OnnxModel): def __init__(self, model: ModelProto, num_heads: int = 0, hidden_size: int = 0): """Initialize BERT ONNX Model. diff --git a/onnxruntime/python/tools/transformers/onnx_model_bert_keras.py b/onnxruntime/python/tools/transformers/onnx_model_bert_keras.py index a85e0cc2ba3f7..c781a91c9e493 100644 --- a/onnxruntime/python/tools/transformers/onnx_model_bert_keras.py +++ b/onnxruntime/python/tools/transformers/onnx_model_bert_keras.py @@ -3,14 +3,10 @@ # Licensed under the MIT License. # -------------------------------------------------------------------------- -import argparse # noqa: F401 import logging -import sys # noqa: F401 -from collections import deque # noqa: F401 -import numpy as np # noqa: F401 import onnx -from onnx import ModelProto, TensorProto, numpy_helper # noqa: F401 +from onnx import numpy_helper from onnx_model_bert_tf import BertOnnxModelTF logger = logging.getLogger(__name__) @@ -439,7 +435,7 @@ def remove_extra_reshape_2(self): "SkipLayerNormalization", ], [None, 0, 0, 0, 0, 0, 0, 0, 0, 0], - ) # yapf: disable + ) if path is None: continue diff --git a/onnxruntime/python/tools/transformers/onnx_model_bert_tf.py b/onnxruntime/python/tools/transformers/onnx_model_bert_tf.py index 0ec4b5a007f90..b7891223e1dc2 100644 --- a/onnxruntime/python/tools/transformers/onnx_model_bert_tf.py +++ b/onnxruntime/python/tools/transformers/onnx_model_bert_tf.py @@ -3,14 +3,11 @@ # Licensed under the MIT License. # -------------------------------------------------------------------------- -import argparse # noqa: F401 import logging -import sys # noqa: F401 -from collections import deque # noqa: F401 import numpy as np import onnx -from onnx import ModelProto, TensorProto, helper, numpy_helper # noqa: F401 +from onnx import TensorProto, helper, numpy_helper from onnx_model_bert import BertOnnxModel logger = logging.getLogger(__name__) diff --git a/onnxruntime/python/tools/transformers/onnx_model_clip.py b/onnxruntime/python/tools/transformers/onnx_model_clip.py index 93e8623768067..9b4ca03a47a5b 100644 --- a/onnxruntime/python/tools/transformers/onnx_model_clip.py +++ b/onnxruntime/python/tools/transformers/onnx_model_clip.py @@ -5,15 +5,17 @@ from logging import getLogger +from fusion_attention_clip import FusionAttentionClip from onnx import ModelProto -from onnx_model_unet import UnetOnnxModel +from onnx_model_bert import BertOnnxModel logger = getLogger(__name__) -class ClipOnnxModel(UnetOnnxModel): +class ClipOnnxModel(BertOnnxModel): def __init__(self, model: ModelProto, num_heads: int = 0, hidden_size: int = 0): super().__init__(model, num_heads=num_heads, hidden_size=hidden_size) + self.clip_attention_fusion = FusionAttentionClip(self, self.hidden_size, self.num_heads) def get_fused_operator_statistics(self): """ @@ -31,3 +33,6 @@ def get_fused_operator_statistics(self): logger.info(f"Optimized operators:{op_count}") return op_count + + def fuse_attention(self): + self.clip_attention_fusion.apply() diff --git a/onnxruntime/python/tools/transformers/onnx_model_t5.py b/onnxruntime/python/tools/transformers/onnx_model_t5.py index 8fb31da4a61f7..ab6a7c72a2c7a 100644 --- a/onnxruntime/python/tools/transformers/onnx_model_t5.py +++ b/onnxruntime/python/tools/transformers/onnx_model_t5.py @@ -111,7 +111,8 @@ def create_attention_node( name=attention_node_name + "_qkv_weight", data_type=TensorProto.FLOAT, dims=[qw_in_size, qkv_weight_dim], - vals=qkv_weight.flatten().tolist(), + vals=qkv_weight.tobytes(), + raw=True, ) self.model.add_initializer(weight, self.this_graph_name) @@ -665,7 +666,8 @@ def fuse(self, node, input_name_to_nodes, output_name_to_node): name=self.model.create_node_name("bias_table_weight", name_prefix=node_name_prefix), data_type=TensorProto.FLOAT, dims=[np.shape(table_weight)[0], np.shape(table_weight)[1]], - vals=table_weight_t.flatten().tolist(), + vals=table_weight_t.tobytes(), + raw=True, ) self.model.add_initializer(bias_table, self.this_graph_name) diff --git a/onnxruntime/python/tools/transformers/onnx_model_tnlr.py b/onnxruntime/python/tools/transformers/onnx_model_tnlr.py index d1815394e9661..98235de6ba6fd 100644 --- a/onnxruntime/python/tools/transformers/onnx_model_tnlr.py +++ b/onnxruntime/python/tools/transformers/onnx_model_tnlr.py @@ -5,10 +5,9 @@ import logging from typing import Union -import numpy as np from fusion_attention import AttentionMask, FusionAttention from fusion_utils import NumpyHelper -from onnx import NodeProto, TensorProto, helper, numpy_helper +from onnx import NodeProto, helper from onnx_model import OnnxModel from onnx_model_bert import BertOnnxModel @@ -57,26 +56,24 @@ def create_attention_node( attention_node_name = self.model.create_node_name("Attention") + tensor_dtype = weight.data_type + np_type = helper.tensor_dtype_to_np_dtype(tensor_dtype) weight = helper.make_tensor( name=attention_node_name + "_qkv_weight", - data_type=TensorProto.FLOAT, + data_type=tensor_dtype, dims=[hidden_size, 3 * hidden_size], - vals=qkv_weight.flatten().tolist(), + vals=qkv_weight.astype(np_type).tobytes(), + raw=True, ) - - # Sometimes weights and bias are stored in fp16 - if weight.data_type == 10: - weight.CopyFrom(numpy_helper.from_array(NumpyHelper.to_array(weight).astype(np.float16), weight.name)) self.model.add_initializer(weight, self.this_graph_name) bias = helper.make_tensor( name=attention_node_name + "_qkv_bias", - data_type=TensorProto.FLOAT, + data_type=tensor_dtype, dims=[3 * hidden_size], - vals=qkv_bias.flatten().tolist(), + vals=qkv_bias.astype(np_type).tobytes(), + raw=True, ) - if bias.data_type == 10: - bias.CopyFrom(numpy_helper.from_array(NumpyHelper.to_array(bias).astype(np.float16), bias.name)) self.model.add_initializer(bias, self.this_graph_name) attention_inputs = [ diff --git a/onnxruntime/python/tools/transformers/onnx_model_unet.py b/onnxruntime/python/tools/transformers/onnx_model_unet.py index 00fc0763d820c..294641dd1e067 100644 --- a/onnxruntime/python/tools/transformers/onnx_model_unet.py +++ b/onnxruntime/python/tools/transformers/onnx_model_unet.py @@ -128,7 +128,8 @@ def optimize(self, options: Optional[FusionOptions] = None): self.fuse_reshape() if (options is None) or options.enable_group_norm: - group_norm_fusion = FusionGroupNorm(self) + channels_last = (options is None) or options.group_norm_channels_last + group_norm_fusion = FusionGroupNorm(self, channels_last) group_norm_fusion.apply() insert_transpose_fusion = FusionInsertTranspose(self) diff --git a/onnxruntime/python/tools/transformers/optimizer.py b/onnxruntime/python/tools/transformers/optimizer.py index d870c447b86fa..3f274eb6c835a 100644 --- a/onnxruntime/python/tools/transformers/optimizer.py +++ b/onnxruntime/python/tools/transformers/optimizer.py @@ -20,11 +20,13 @@ import argparse import logging import os -from typing import Dict, Optional +import tempfile +from typing import Dict, List, Optional import coloredlogs from fusion_options import FusionOptions -from onnx import ModelProto, load_model +from onnx import ModelProto, TensorProto, load_model +from onnx_model import OnnxModel from onnx_model_bart import BartOnnxModel from onnx_model_bert import BertOnnxModel from onnx_model_bert_keras import BertOnnxModelKeras @@ -44,20 +46,16 @@ "bert": (BertOnnxModel, "pytorch", 1), "bert_tf": (BertOnnxModelTF, "tf2onnx", 0), "bert_keras": (BertOnnxModelKeras, "keras2onnx", 0), + "clip": (ClipOnnxModel, "pytorch", 1), # Clip in Stable Diffusion "gpt2": (Gpt2OnnxModel, "pytorch", 1), - "gpt2_tf": ( - Gpt2OnnxModel, - "tf2onnx", - 0, - ), # might add a class for GPT2OnnxModel for TF later. + "gpt2_tf": (Gpt2OnnxModel, "tf2onnx", 0), # might add a class for GPT2OnnxModel for TF later. + "gpt_neox": (BertOnnxModel, "pytorch", 0), # GPT-NeoX + "swin": (BertOnnxModel, "pytorch", 1), "tnlr": (TnlrOnnxModel, "pytorch", 1), "t5": (T5OnnxModel, "pytorch", 2), - # Stable Diffusion models - "unet": (UnetOnnxModel, "pytorch", 1), - "vae": (VaeOnnxModel, "pytorch", 1), - "clip": (ClipOnnxModel, "pytorch", 1), + "unet": (UnetOnnxModel, "pytorch", 1), # UNet in Stable Diffusion + "vae": (VaeOnnxModel, "pytorch", 1), # UAE in Stable Diffusion "vit": (BertOnnxModel, "pytorch", 1), - "swin": (BertOnnxModel, "pytorch", 1), } @@ -66,8 +64,11 @@ def optimize_by_onnxruntime( use_gpu: bool = False, optimized_model_path: Optional[str] = None, opt_level: Optional[int] = 99, - disabled_optimizers=[], # noqa: B006 - verbose=False, + disabled_optimizers: List[str] = [], # noqa: B006 + verbose: bool = False, + save_as_external_data: bool = False, + external_data_filename: str = "", + external_data_file_threshold: int = 1024, ) -> str: """ Use onnxruntime to optimize model. @@ -78,6 +79,9 @@ def optimize_by_onnxruntime( optimized_model_path (str or None): the path of optimized model. opt_level (int): graph optimization level. disabled_optimizers (List[str]): a list of names of disabled optimizers + save_as_external_data (bool): whether to save external data outside of ONNX model + external_data_filename (str): name of external data file. If not provided, name is automatically created from ONNX model. + external_data_file_threshold (int): threshold to decide whether to save tensor in ONNX model or in external data file Returns: optimized_model_path (str): the path of optimized model """ @@ -92,6 +96,15 @@ def optimize_by_onnxruntime( logger.error("There is no gpu for onnxruntime to do optimization.") return onnx_model_path + model = OnnxModel(load_model(onnx_model_path, format=None, load_external_data=False)) + if model.use_float16() and not use_gpu: + logger.warning( + "This model uses float16 in the graph, use_gpu=False might cause extra Cast nodes. " + "Most operators have no float16 implementation in CPU, so Cast nodes are added to compute them in float32. " + "If the model is intended to use in GPU, please set use_gpu=True. " + "Otherwise, consider exporting onnx in float32 and optional int8 quantization for better performance. " + ) + sess_options = onnxruntime.SessionOptions() if opt_level == 1: sess_options.graph_optimization_level = onnxruntime.GraphOptimizationLevel.ORT_ENABLE_BASIC @@ -105,6 +118,16 @@ def optimize_by_onnxruntime( optimized_model_path = "{}_o{}_{}.onnx".format(path_prefix, opt_level, "gpu" if use_gpu else "cpu") sess_options.optimized_model_filepath = optimized_model_path + if save_as_external_data: + if len(external_data_filename) == 0: + # Set external data filename to model_name.onnx.data + external_data_filename = os.path.basename(optimized_model_path) + ".data" + sess_options.add_session_config_entry( + "session.optimized_model_external_initializers_file_name", external_data_filename + ) + sess_options.add_session_config_entry( + "session.optimized_model_external_initializers_min_size_in_bytes", str(external_data_file_threshold) + ) if verbose: print("Using onnxruntime to optimize model - Debug level Set to verbose") @@ -119,15 +142,13 @@ def optimize_by_onnxruntime( else: gpu_ep = [] - if torch_version.cuda: - gpu_ep.append("CUDAExecutionProvider") - elif torch_version.hip: + if torch_version.hip: gpu_ep.append("MIGraphXExecutionProvider") gpu_ep.append("ROCMExecutionProvider") + else: + gpu_ep.append("CUDAExecutionProvider") + onnxruntime.InferenceSession(onnx_model_path, sess_options, providers=gpu_ep, **kwargs) - assert not set(onnxruntime.get_available_providers()).isdisjoint( - ["CUDAExecutionProvider", "ROCMExecutionProvider", "MIGraphXExecutionProvider"] - ) assert os.path.exists(optimized_model_path) and os.path.isfile(optimized_model_path) logger.debug("Save optimized model by onnxruntime to %s", optimized_model_path) @@ -198,11 +219,11 @@ def optimize_model( opt_level: Optional[int] = None, use_gpu: bool = False, only_onnxruntime: bool = False, - verbose=False, + verbose: bool = False, ): """Optimize Model by OnnxRuntime and/or python fusion logic. - ONNX Runtime has graph optimizations (https://onnxruntime.ai/docs/performance/graph-optimizations.html). + ONNX Runtime has graph optimizations (https://onnxruntime.ai/docs/performance/model-optimizations/graph-optimizations.html). However, the coverage is limited. We also have graph fusions that implemented in Python to improve the coverage. They can combined: ONNX Runtime will run first when opt_level > 0, then graph fusions in Python will be applied. @@ -252,6 +273,19 @@ def optimize_model( # stable. disabled_optimizers = ["ConstantSharing"] temp_model_path = None + temp_dir = tempfile.TemporaryDirectory() + optimized_model_name = "model_o{}_{}.onnx".format(opt_level, "gpu" if use_gpu else "cpu") + optimized_model_path = os.path.join(temp_dir.name, optimized_model_name) + + # Auto detect if input model has external data + has_external_data_file = False + original_model = load_model(input, load_external_data=False) + for initializer in original_model.graph.initializer: + if initializer.HasField("data_location") and initializer.data_location == TensorProto.EXTERNAL: + has_external_data_file = True + break + del original_model + if opt_level > 1: # Disable some optimizers that might cause failure in symbolic shape inference or attention fusion. disabled_optimizers += ( @@ -268,19 +302,25 @@ def optimize_model( temp_model_path = optimize_by_onnxruntime( input, use_gpu=use_gpu, + optimized_model_path=optimized_model_path, opt_level=opt_level, disabled_optimizers=disabled_optimizers, verbose=verbose, + save_as_external_data=has_external_data_file, ) elif opt_level == 1: # basic optimizations (like constant folding and cast elimination) are not specified to execution provider. - # CPU provider is used here so that there is no extra node for GPU memory copy. + # Note that use_gpu=False might cause extra Cast nodes for float16 model since most operators does not support float16 in CPU. + # Sometime, use_gpu=True might cause extra memory copy nodes when some operators are supported only in CPU. + # We might need remove GPU memory copy nodes as preprocess of optimize_by_fusion if they cause no matching in fusion. temp_model_path = optimize_by_onnxruntime( input, - use_gpu=False, + use_gpu=use_gpu, + optimized_model_path=optimized_model_path, opt_level=1, disabled_optimizers=disabled_optimizers, verbose=verbose, + save_as_external_data=has_external_data_file, ) if only_onnxruntime and not temp_model_path: @@ -293,10 +333,8 @@ def optimize_model( else: optimizer = optimize_by_fusion(model, model_type, num_heads, hidden_size, optimization_options) - # Remove the temporary model. - if temp_model_path: - os.remove(temp_model_path) - logger.debug(f"Remove temporary model: {temp_model_path}") + # remove the temporary directory + temp_dir.cleanup() return optimizer diff --git a/onnxruntime/python/tools/transformers/shape_optimizer.py b/onnxruntime/python/tools/transformers/shape_optimizer.py index bf507a0d8a0a3..ac62188662990 100644 --- a/onnxruntime/python/tools/transformers/shape_optimizer.py +++ b/onnxruntime/python/tools/transformers/shape_optimizer.py @@ -16,7 +16,7 @@ from collections import deque # noqa: F401 from datetime import datetime from pathlib import Path # noqa: F401 -from typing import List +from typing import List, Optional import numpy as np import onnx @@ -287,7 +287,7 @@ def optimize( input_mask: str, enable_shape_opt: bool, enable_reshape_opt: bool, - output_names: List[str] = None, + output_names: Optional[List[str]] = None, batch_size=1, sequence_length=128, verbose=False, diff --git a/onnxruntime/test/api_tests_without_env/test_apis_without_env.cc b/onnxruntime/test/api_tests_without_env/test_apis_without_env.cc deleted file mode 100644 index dec37e80419fd..0000000000000 --- a/onnxruntime/test/api_tests_without_env/test_apis_without_env.cc +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#ifndef USE_ONNXRUNTIME_DLL -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wignored-qualifiers" -#pragma GCC diagnostic ignored "-Wunused-parameter" -#endif -#include -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif -#endif - -#include "gtest/gtest.h" -#include "core/session/onnxruntime_cxx_api.h" -#include "core/session/abi_session_options_impl.h" - -TEST(TestSessionOptions, SetIntraOpNumThreadsWithoutEnv) { - Ort::SessionOptions session_options; - session_options.SetIntraOpNumThreads(48); - const auto* ort_session_options = (const OrtSessionOptions*)session_options; - ASSERT_EQ(ort_session_options->value.intra_op_param.thread_pool_size, 48); -} - -int main(int argc, char** argv) { - int status = 0; - ORT_TRY { - ::testing::InitGoogleTest(&argc, argv); - status = RUN_ALL_TESTS(); - } - ORT_CATCH(const std::exception& ex) { - ORT_HANDLE_EXCEPTION([&]() { - std::cerr << ex.what(); - status = -1; - }); - } - -#ifndef USE_ONNXRUNTIME_DLL - // make memory leak checker happy - ::google::protobuf::ShutdownProtobufLibrary(); -#endif - return status; -} diff --git a/onnxruntime/test/common/random_generator.h b/onnxruntime/test/common/random_generator.h new file mode 100644 index 0000000000000..cb1ce885d2d45 --- /dev/null +++ b/onnxruntime/test/common/random_generator.h @@ -0,0 +1,173 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include +#include + +#include "gtest/gtest.h" + +#include "core/common/gsl.h" +#include "core/common/common.h" +#include "core/common/optional.h" +#include "core/common/type_utils.h" +#include "test/util/include/test_random_seed.h" + +namespace onnxruntime { +namespace test { + +namespace detail { +inline int64_t SizeFromDims(gsl::span dims, gsl::span strides = {}) { + int64_t size = 1; + if (strides.empty()) { + size = std::accumulate(dims.begin(), dims.end(), static_cast(1), std::multiplies{}); + } else { + ORT_ENFORCE(dims.size() == strides.size()); + for (size_t dim = 0; dim < dims.size(); ++dim) { + if (dims[dim] == 0) { + size = 0; + break; + } + size += strides[dim] * (dims[dim] - 1); + } + } + + ORT_ENFORCE(size >= 0); + return size; +} +} // namespace detail + +class RandomValueGenerator { + public: + using RandomEngine = std::default_random_engine; + using RandomSeedType = RandomEngine::result_type; + + explicit RandomValueGenerator(optional seed = {}) + : random_seed_{seed.has_value() ? *seed : static_cast(GetTestRandomSeed())}, + generator_{random_seed_}, + output_trace_{__FILE__, __LINE__, "ORT test random seed: " + std::to_string(random_seed_)} { + } + + RandomSeedType GetRandomSeed() const { + return random_seed_; + } + + // Random values generated are in the range [min, max). + template + typename std::enable_if< + std::is_floating_point::value, + std::vector>::type + Uniform(gsl::span dims, TFloat min, TFloat max) { + std::vector val(detail::SizeFromDims(dims)); + std::uniform_real_distribution distribution(min, max); + for (size_t i = 0; i < val.size(); ++i) { + val[i] = distribution(generator_); + } + return val; + } + + // Random values generated are in the range [min, max). + template + typename std::enable_if< + std::is_same_v, + std::vector>::type + Uniform(gsl::span dims, float min, float max) { + std::vector val(detail::SizeFromDims(dims)); + std::uniform_real_distribution distribution(min, max); + for (size_t i = 0; i < val.size(); ++i) { + val[i] = TFloat16(static_cast(distribution(generator_))); + } + return val; + } + + // Random values generated are in the range [min, max). + template + typename std::enable_if< + std::is_integral::value && !utils::IsByteType::value, + std::vector>::type + Uniform(gsl::span dims, TInt min, TInt max) { + std::vector val(detail::SizeFromDims(dims)); + std::uniform_int_distribution distribution(min, max - 1); + for (size_t i = 0; i < val.size(); ++i) { + val[i] = distribution(generator_); + } + return val; + } + + template + typename std::enable_if< + utils::IsByteType::value, + std::vector>::type + Uniform(gsl::span dims, TByte min, TByte max) { + std::vector val(detail::SizeFromDims(dims)); + std::uniform_int_distribution distribution(min, max - 1); + for (size_t i = 0; i < val.size(); ++i) { + val[i] = static_cast(distribution(generator_)); + } + return val; + } + + // Gaussian distribution for float + template + typename std::enable_if< + std::is_floating_point::value, + std::vector>::type + Gaussian(gsl::span dims, TFloat mean, TFloat stddev) { + std::vector val(detail::SizeFromDims(dims)); + std::normal_distribution distribution(mean, stddev); + for (size_t i = 0; i < val.size(); ++i) { + val[i] = distribution(generator_); + } + return val; + } + + // Gaussian distribution for Integer + template + typename std::enable_if< + std::is_integral::value, + std::vector>::type + Gaussian(const std::vector& dims, TInt mean, TInt stddev) { + std::vector val(detail::SizeFromDims(dims)); + std::normal_distribution distribution(static_cast(mean), static_cast(stddev)); + for (size_t i = 0; i < val.size(); ++i) { + val[i] = static_cast(std::round(distribution(generator_))); + } + return val; + } + + // Gaussian distribution for Integer and Clamp to [min, max] + template + typename std::enable_if< + std::is_integral::value, + std::vector>::type + Gaussian(const std::vector& dims, TInt mean, TInt stddev, TInt min, TInt max) { + std::vector val(detail::SizeFromDims(dims)); + std::normal_distribution distribution(static_cast(mean), static_cast(stddev)); + for (size_t i = 0; i < val.size(); ++i) { + int64_t round_val = static_cast(std::round(distribution(generator_))); + val[i] = static_cast(std::min(std::max(round_val, min), max)); + } + return val; + } + + template + inline std::vector OneHot(const std::vector& dims, int64_t stride) { + std::vector val(detail::SizeFromDims(dims), T(0)); + std::uniform_int_distribution distribution(0, stride - 1); + for (size_t offset = 0; offset < val.size(); offset += stride) { + size_t rand_index = static_cast(distribution(generator_)); + val[offset + rand_index] = T(1); + } + return val; + } + + private: + const RandomSeedType random_seed_; + RandomEngine generator_; + // while this instance is in scope, output some context information on test failure like the random seed value + const ::testing::ScopedTrace output_trace_; +}; + +} // namespace test +} // namespace onnxruntime diff --git a/onnxruntime/test/common/random_generator_test.cc b/onnxruntime/test/common/random_generator_test.cc index f9cc66ba69fc2..98f19188d6753 100644 --- a/onnxruntime/test/common/random_generator_test.cc +++ b/onnxruntime/test/common/random_generator_test.cc @@ -11,7 +11,7 @@ namespace test { TEST(TensorGenerator, DiscreteFloat) { FixedPatternValueGenerator random{}; const std::vector shape = {2, 3}; - std::vector data = random.Discrete(shape, {-1.f, 0.f, 1.f}); + std::vector data = random.Discrete(shape, AsSpan({-1.f, 0.f, 1.f})); ASSERT_EQ(data.size(), static_cast(6)); for (float value : data) { @@ -22,7 +22,7 @@ TEST(TensorGenerator, DiscreteFloat) { TEST(TensorGenerator, DiscreteInt) { FixedPatternValueGenerator random{}; const std::vector shape = {2, 3}; - std::vector data = random.Discrete(shape, {-1, 0, 1}); + std::vector data = random.Discrete(shape, AsSpan({-1, 0, 1})); ASSERT_EQ(data.size(), static_cast(6)); for (int value : data) { @@ -34,7 +34,7 @@ TEST(TensorGenerator, DiscreteInt) { TEST(TensorGenerator, CircularFloat) { FixedPatternValueGenerator random{}; const std::vector shape = {3, 2}; - std::vector data = random.Circular(shape, {-1.f, 0.f, 1.f}); + std::vector data = random.Circular(shape, AsSpan({-1.f, 0.f, 1.f})); ASSERT_EQ(data.size(), static_cast(6)); EXPECT_EQ(data[0], -1.f); @@ -48,7 +48,7 @@ TEST(TensorGenerator, CircularFloat) { TEST(TensorGenerator, CircularInt) { FixedPatternValueGenerator random{}; const std::vector shape = {3, 2}; - std::vector data = random.Circular(shape, {-1, 0, 1}); + std::vector data = random.Circular(shape, AsSpan({-1, 0, 1})); ASSERT_EQ(data.size(), static_cast(6)); EXPECT_EQ(data[0], -1); @@ -62,7 +62,7 @@ TEST(TensorGenerator, CircularInt) { TEST(TensorGenerator, CircularBool) { FixedPatternValueGenerator random{}; const std::vector shape = {3, 2}; - std::vector data = random.Circular(shape, {false, true}); + std::vector data = random.Circular(shape, AsSpan({false, true})); ASSERT_EQ(data.size(), static_cast(6)); EXPECT_EQ(data[0], false); diff --git a/onnxruntime/test/common/tensor_op_test_utils.cc b/onnxruntime/test/common/tensor_op_test_utils.cc index 4c0425fbddff5..b2ec30f4c50d4 100644 --- a/onnxruntime/test/common/tensor_op_test_utils.cc +++ b/onnxruntime/test/common/tensor_op_test_utils.cc @@ -7,13 +7,6 @@ namespace onnxruntime { namespace test { -RandomValueGenerator::RandomValueGenerator(optional seed) - : random_seed_{ - seed.has_value() ? *seed : static_cast(GetTestRandomSeed())}, - generator_{random_seed_}, - output_trace_{__FILE__, __LINE__, "ORT test random seed: " + std::to_string(random_seed_)} { -} - FixedPatternValueGenerator::FixedPatternValueGenerator() : generator_{0}, output_trace_{__FILE__, __LINE__, "ORT test random seed with fixed pattern tensor generator"} { diff --git a/onnxruntime/test/common/tensor_op_test_utils.h b/onnxruntime/test/common/tensor_op_test_utils.h index 23ffa887cb7ad..6917aa15777a2 100644 --- a/onnxruntime/test/common/tensor_op_test_utils.h +++ b/onnxruntime/test/common/tensor_op_test_utils.h @@ -15,158 +15,13 @@ #include "core/common/type_utils.h" #include "core/framework/tensor.h" #include "core/util/math.h" +#include "core/platform/threadpool.h" +#include "core/util/thread_utils.h" +#include "test/common/random_generator.h" namespace onnxruntime { namespace test { -namespace detail { -inline int64_t SizeFromDims(gsl::span dims, gsl::span strides = {}) { - int64_t size = 1; - if (strides.empty()) { - size = std::accumulate(dims.begin(), dims.end(), static_cast(1), std::multiplies{}); - } else { - ORT_ENFORCE(dims.size() == strides.size()); - for (size_t dim = 0; dim < dims.size(); ++dim) { - if (dims[dim] == 0) { - size = 0; - break; - } - size += strides[dim] * (dims[dim] - 1); - } - } - - ORT_ENFORCE(size >= 0); - return size; -} -} // namespace detail - -class RandomValueGenerator { - public: - using RandomEngine = std::default_random_engine; - using RandomSeedType = RandomEngine::result_type; - - explicit RandomValueGenerator(optional seed = {}); - - RandomSeedType GetRandomSeed() const { - return random_seed_; - } - - // Random values generated are in the range [min, max). - template - typename std::enable_if< - std::is_floating_point::value, - std::vector>::type - Uniform(gsl::span dims, TFloat min, TFloat max) { - std::vector val(detail::SizeFromDims(dims)); - std::uniform_real_distribution distribution(min, max); - for (size_t i = 0; i < val.size(); ++i) { - val[i] = distribution(generator_); - } - return val; - } - - // Random values generated are in the range [min, max). - template - typename std::enable_if< - std::is_same_v, - std::vector>::type - Uniform(gsl::span dims, float min, float max) { - std::vector val(detail::SizeFromDims(dims)); - std::uniform_real_distribution distribution(min, max); - for (size_t i = 0; i < val.size(); ++i) { - val[i] = TFloat16(math::floatToHalf(distribution(generator_))); - } - return val; - } - - // Random values generated are in the range [min, max). - template - typename std::enable_if< - std::is_integral::value && !utils::IsByteType::value, - std::vector>::type - Uniform(gsl::span dims, TInt min, TInt max) { - std::vector val(detail::SizeFromDims(dims)); - std::uniform_int_distribution distribution(min, max - 1); - for (size_t i = 0; i < val.size(); ++i) { - val[i] = distribution(generator_); - } - return val; - } - - template - typename std::enable_if< - utils::IsByteType::value, - std::vector>::type - Uniform(gsl::span dims, TByte min, TByte max) { - std::vector val(detail::SizeFromDims(dims)); - std::uniform_int_distribution distribution(min, max - 1); - for (size_t i = 0; i < val.size(); ++i) { - val[i] = static_cast(distribution(generator_)); - } - return val; - } - - // Gaussian distribution for float - template - typename std::enable_if< - std::is_floating_point::value, - std::vector>::type - Gaussian(gsl::span dims, TFloat mean, TFloat stddev) { - std::vector val(detail::SizeFromDims(dims)); - std::normal_distribution distribution(mean, stddev); - for (size_t i = 0; i < val.size(); ++i) { - val[i] = distribution(generator_); - } - return val; - } - - // Gaussian distribution for Integer - template - typename std::enable_if< - std::is_integral::value, - std::vector>::type - Gaussian(const std::vector& dims, TInt mean, TInt stddev) { - std::vector val(detail::SizeFromDims(dims)); - std::normal_distribution distribution(static_cast(mean), static_cast(stddev)); - for (size_t i = 0; i < val.size(); ++i) { - val[i] = static_cast(std::round(distribution(generator_))); - } - return val; - } - - // Gaussian distribution for Integer and Clamp to [min, max] - template - typename std::enable_if< - std::is_integral::value, - std::vector>::type - Gaussian(const std::vector& dims, TInt mean, TInt stddev, TInt min, TInt max) { - std::vector val(detail::SizeFromDims(dims)); - std::normal_distribution distribution(static_cast(mean), static_cast(stddev)); - for (size_t i = 0; i < val.size(); ++i) { - int64_t round_val = static_cast(std::round(distribution(generator_))); - val[i] = static_cast(std::min(std::max(round_val, min), max)); - } - return val; - } - - template - inline std::vector OneHot(const std::vector& dims, int64_t stride) { - std::vector val(detail::SizeFromDims(dims), T(0)); - std::uniform_int_distribution distribution(0, stride - 1); - for (size_t offset = 0; offset < val.size(); offset += stride) { - size_t rand_index = static_cast(distribution(generator_)); - val[offset + rand_index] = T(1); - } - return val; - } - - private: - const RandomSeedType random_seed_; - RandomEngine generator_; - // while this instance is in scope, output some context information on test failure like the random seed value - const ::testing::ScopedTrace output_trace_; -}; - // This class provides similar functionality as `RandomValueGenerator` but generates `fixed` patterns // for given tensor element type and shape. It should be used in unstable tests because // `purely random` patterns can easily trigger numerical errors. @@ -176,7 +31,7 @@ class FixedPatternValueGenerator { template std::vector - Discrete(gsl::span dims, const std::vector& value_candidates) { + Discrete(gsl::span dims, gsl::span value_candidates) { std::vector values(detail::SizeFromDims(dims)); std::uniform_int_distribution distribution(0, value_candidates.size() - 1); // Tier 2 RNG. Use it if `RandomValueGenerator::Uniform` method causes large numerical errors @@ -208,7 +63,7 @@ class FixedPatternValueGenerator { template std::vector - Circular(gsl::span dims, const std::vector& value_candidates) { + Circular(gsl::span dims, gsl::span value_candidates) { // Tier 3 RNG. Use it if `Discrete` method causes large numerical errors // (e.g., when elementwise relative error > 1e-3). // Suggested value_candidates to alleviate numerical error (listed @@ -265,7 +120,7 @@ inline std::vector ValueRange(size_t count, MLFloat16 star return result; } -inline std::pair MeanStdev(std::vector& v) { +inline std::pair MeanStdev(gsl::span v) { float sum = std::accumulate(v.begin(), v.end(), 0.0f); float mean = sum / v.size(); @@ -279,7 +134,7 @@ inline std::pair MeanStdev(std::vector& v) { } inline void Normalize(std::vector& v, - std::pair& mean_stdev, bool normalize_variance) { + const std::pair& mean_stdev, bool normalize_variance) { float mean = mean_stdev.first; float stdev = mean_stdev.second; @@ -296,7 +151,7 @@ inline std::vector ToFloat16(const std::vector& data) { std::vector result; result.reserve(data.size()); for (size_t i = 0; i < data.size(); i++) { - result.push_back(MLFloat16(math::floatToHalf(data[i]))); + result.push_back(MLFloat16(data[i])); } return result; } @@ -307,21 +162,100 @@ inline void CheckTensor(const Tensor& expected_tensor, const Tensor& output_tens "] did not match run output shape [" + output_tensor.Shape().ToString() + "]"); - ASSERT_TRUE(expected_tensor.DataType() == DataTypeImpl::GetType()) << "Compare with non float number is not supported yet. "; + ASSERT_TRUE(expected_tensor.DataType() == DataTypeImpl::GetType()) + << "Compare with non float number is not supported yet. "; auto expected = expected_tensor.Data(); auto output = output_tensor.Data(); for (auto i = 0; i < expected_tensor.Shape().Size(); ++i) { const auto expected_value = expected[i], actual_value = output[i]; if (std::isnan(expected_value)) { - ASSERT_TRUE(std::isnan(actual_value)) << "value mismatch at index " << i << "; expected is NaN, actual is not NaN"; + ASSERT_TRUE(std::isnan(actual_value)) << "value mismatch at index " << i + << "; expected is NaN, actual is not NaN"; } else if (std::isinf(expected_value)) { ASSERT_EQ(expected_value, actual_value) << "value mismatch at index " << i; } else { double diff = fabs(expected_value - actual_value); - ASSERT_TRUE(diff <= (atol + rtol * fabs(expected_value))) << "value mismatch at index " << i << "; expected: " << expected_value << ", actual: " << actual_value; + ASSERT_TRUE(diff <= (atol + rtol * fabs(expected_value))) << "value mismatch at index " << i << "; expected: " + << expected_value << ", actual: " << actual_value; } } } +class ParallelRandomValueGenerator { + public: + using RandomEngine = std::default_random_engine; + using RandomSeedType = RandomEngine::result_type; + + ParallelRandomValueGenerator(RandomSeedType base_seed) + : base_seed_{base_seed} { + } + + // Random values generated are in the range [min, max). + template + typename std::enable_if< + std::is_floating_point::value, + std::vector>::type + Uniform(gsl::span dims, TFloat min, TFloat max) { + OrtThreadPoolParams to; + to.thread_pool_size = 16; + auto tp = concurrency::CreateThreadPool(&onnxruntime::Env::Default(), to, + concurrency::ThreadPoolType::INTRA_OP); + static double cost = 1; + RandomSeedType base_seed = base_seed_; + std::vector val(detail::SizeFromDims(dims)); + concurrency::ThreadPool::TryParallelFor( + tp.get(), val.size(), cost, + [&min, &max, &base_seed, &val]( + std::ptrdiff_t begin, std::ptrdiff_t end) { + RandomSeedType seed = base_seed; + auto new_seed = static_cast(base_seed) + begin; + if (new_seed < static_cast(std::numeric_limits::max())) + seed = static_cast(new_seed); + RandomEngine generator{seed}; + std::uniform_real_distribution distribution(min, max); + for (std::ptrdiff_t di = begin; di != end; ++di) { + val[di] = distribution(generator); + } + }); + + return val; + } + + // Random values generated are in the range [min, max). + template + typename std::enable_if< + std::is_same_v, + std::vector>::type + Uniform(gsl::span dims, float min, float max) { + OrtThreadPoolParams to; + to.thread_pool_size = 16; + auto tp = concurrency::CreateThreadPool(&onnxruntime::Env::Default(), to, + concurrency::ThreadPoolType::INTRA_OP); + static double cost = 1; + RandomSeedType base_seed = base_seed_; + std::vector val(detail::SizeFromDims(dims)); + concurrency::ThreadPool::TryParallelFor( + tp.get(), val.size(), cost, + [&min, &max, &base_seed, &val]( + std::ptrdiff_t begin, std::ptrdiff_t end) { + RandomSeedType seed = base_seed; + auto new_seed = static_cast(base_seed) + begin; + if (new_seed < static_cast(std::numeric_limits::max())) + seed = static_cast(new_seed); + RandomEngine generator{seed}; + std::uniform_real_distribution distribution(min, max); + for (std::ptrdiff_t di = begin; di != end; ++di) { + val[di] = TFloat16(static_cast(distribution(generator))); + ; + } + }); + + return val; + } + + private: + const RandomSeedType base_seed_; +}; + } // namespace test } // namespace onnxruntime diff --git a/onnxruntime/test/contrib_ops/attention_op_test.cc b/onnxruntime/test/contrib_ops/attention_op_test.cc index 709fbcb378bb6..b652e0723f5aa 100644 --- a/onnxruntime/test/contrib_ops/attention_op_test.cc +++ b/onnxruntime/test/contrib_ops/attention_op_test.cc @@ -58,6 +58,7 @@ static void RunAttentionTest( const bool disable_cpu = false, const bool disable_cuda = false, const bool disable_rocm = false, + const bool disable_dml = false, std::vector qkv_sizes = {}, const std::vector& relative_position_bias_data = {}, int kv_sequence_length = 0, @@ -72,9 +73,10 @@ static void RunAttentionTest( bool enable_cuda = HasCudaEnvironment(min_cuda_architecture) && !is_weights_constant && !disable_cuda; bool enable_rocm = (nullptr != DefaultRocmExecutionProvider().get()) && !is_weights_constant && !disable_rocm; bool enable_cpu = (nullptr != DefaultCpuExecutionProvider().get()) && !use_float16 && !disable_cpu; + bool enable_dml = (nullptr != DefaultDmlExecutionProvider().get()) && !disable_dml; int head_size = hidden_size / number_of_heads; - if (enable_cpu || enable_cuda || enable_rocm) { + if (enable_cpu || enable_cuda || enable_rocm || enable_dml) { OpTester tester("Attention", 1, onnxruntime::kMSDomain); tester.AddAttribute("num_heads", static_cast(number_of_heads)); tester.AddAttribute("unidirectional", static_cast(is_unidirectional ? 1 : 0)); @@ -237,11 +239,23 @@ static void RunAttentionTest( tester.Run(OpTester::ExpectResult::kExpectSuccess, "", {}, nullptr, &execution_providers); } + if (enable_rocm) { + std::vector> execution_providers; + execution_providers.push_back(DefaultRocmExecutionProvider(/*test_tunable_op=*/true)); + tester.Run(OpTester::ExpectResult::kExpectSuccess, "", {}, nullptr, &execution_providers); + } + if (enable_cpu) { std::vector> execution_providers; execution_providers.push_back(DefaultCpuExecutionProvider()); tester.Run(OpTester::ExpectResult::kExpectSuccess, "", {}, nullptr, &execution_providers); } + + if (enable_dml) { + std::vector> execution_providers; + execution_providers.push_back(DefaultDmlExecutionProvider()); + tester.Run(OpTester::ExpectResult::kExpectSuccess, "", {}, nullptr, &execution_providers); + } } } @@ -267,6 +281,7 @@ static void RunAttentionTest( const bool disable_cpu = false, const bool disable_cuda = false, const bool disable_rocm = false, + const bool disable_dml = false, const std::vector qkv_sizes = {}, const std::vector& relative_position_bias_data = {}, int kv_sequence_length = 0, @@ -277,13 +292,13 @@ static void RunAttentionTest( batch_size, sequence_length, hidden_size, number_of_heads, use_float16, is_unidirectional, use_past_state, past_sequence_length, past_data, present_data, mask_type, input_hidden_size, max_sequence_length, - disable_cpu, disable_cuda, disable_rocm, qkv_sizes, relative_position_bias_data, + disable_cpu, disable_cuda, disable_rocm, disable_dml, qkv_sizes, relative_position_bias_data, kv_sequence_length, past_present_share_buffer, use_scale, do_neox_rotary); RunAttentionTest(input_data, weights_data, true, bias_data, mask_index_data, output_data, batch_size, sequence_length, hidden_size, number_of_heads, use_float16, is_unidirectional, use_past_state, past_sequence_length, past_data, present_data, mask_type, input_hidden_size, max_sequence_length, - disable_cpu, disable_cuda, disable_rocm, qkv_sizes, relative_position_bias_data, + disable_cpu, disable_cuda, disable_rocm, disable_dml, qkv_sizes, relative_position_bias_data, kv_sequence_length, past_present_share_buffer, use_scale, do_neox_rotary); } @@ -354,7 +369,7 @@ TEST(AttentionTest, AttentionBatch1WithQKVAttr1) { RunAttentionTest(input_data, weight_data, bias_data, mask_index_data, output_data, batch_size, sequence_length, hidden_size, number_of_heads, false, false, false, 0, nullptr, nullptr, AttentionMaskType::MASK_1D_KEY_SEQ_LEN, 0, - 0, false, false, disable_rocm, qkv_sizes); + 0, false, false, disable_rocm, false, qkv_sizes); } TEST(AttentionTest, AttentionBatch1WithQKVAttr2) { @@ -392,7 +407,7 @@ TEST(AttentionTest, AttentionBatch1WithQKVAttr2) { RunAttentionTest(input_data, weight_data, bias_data, mask_index_data, output_data, batch_size, sequence_length, hidden_size, number_of_heads, false, false, false, 0, nullptr, nullptr, AttentionMaskType::MASK_1D_KEY_SEQ_LEN, 0, - 0, false, false, disable_rocm, qkv_sizes); + 0, false, false, disable_rocm, false, qkv_sizes); } TEST(AttentionTest, AttentionBatch1RelativePositionBias) { @@ -429,10 +444,11 @@ TEST(AttentionTest, AttentionBatch1RelativePositionBias) { constexpr bool disable_cpu = false; constexpr bool disable_cuda = false; constexpr bool disable_rocm = false; + constexpr bool disable_dml = false; RunAttentionTest(input_data, weight_data, bias_data, mask_index_data, output_data, batch_size, sequence_length, hidden_size, number_of_heads, false, false, false, 0, nullptr, nullptr, AttentionMaskType::MASK_1D_KEY_SEQ_LEN, 0, - 0, disable_cpu, disable_cuda, disable_rocm, qkv_sizes, relative_position_bias); + 0, disable_cpu, disable_cuda, disable_rocm, disable_dml, qkv_sizes, relative_position_bias); } TEST(AttentionTest, AttentionBatch2RelativePositionBias) { @@ -474,10 +490,11 @@ TEST(AttentionTest, AttentionBatch2RelativePositionBias) { constexpr bool disable_cpu = false; constexpr bool disable_cuda = false; constexpr bool disable_rocm = false; + constexpr bool disable_dml = false; RunAttentionTest(input_data, weight_data, bias_data, mask_index_data, output_data, batch_size, sequence_length, hidden_size, number_of_heads, false, false, false, 0, nullptr, nullptr, AttentionMaskType::MASK_1D_KEY_SEQ_LEN, 0, - 0, disable_cpu, disable_cuda, disable_rocm, qkv_sizes, relative_position_bias); + 0, disable_cpu, disable_cuda, disable_rocm, disable_dml, qkv_sizes, relative_position_bias); } TEST(AttentionTest, AttentionBatch1_Float16) { @@ -817,38 +834,24 @@ void RawAttentionEmptyPastState(bool past_present_share_buffer) { batch_size, sequence_length, hidden_size, number_of_heads, false, is_unidirectional, use_past_state, past_sequence_length, &past_data, &present_data); } else { + // TODO: Unskip when fixed #41968513 + // DML doesn't support past_present_share_buffer for Attention yet + constexpr bool disable_dml = true; + RunAttentionTest(input_data, weight_data, bias_data, mask_index_data, output_data, batch_size, sequence_length, hidden_size, number_of_heads, false, is_unidirectional, use_past_state, past_sequence_length, &past_data, &present_data, - AttentionMaskType::MASK_1D_KEY_SEQ_LEN, 0, sequence_length, true, false, true, {}, {}, 0, + AttentionMaskType::MASK_1D_KEY_SEQ_LEN, 0, sequence_length, true, false, true, disable_dml, {}, {}, 0, true); } } -// Disable Causal_EmptyPastState temporarily in Windows build since prefast crashes in python package pipelines -// TODO(tianleiwu): change the test to load test data from file. -#ifndef _MSC_VER TEST(AttentionTest, Causal_EmptyPastState) { int batch_size = 1; int sequence_length = 2; int hidden_size = 64; int number_of_heads = 2; - std::vector input_data = { - 0.00838f, 0.007523f, -0.00872f, 0.002882f, -0.003567f, 0.000859f, -0.002821f, 0.000563f, 0.007675f, -0.002758f, - 0.000947f, 0.001149f, -0.001534f, 0.0006075f, 0.002853f, 0.004517f, 0.00825f, 0.003687f, -0.002161f, 0.001167f, - 0.005913f, 0.00394f, -0.002136f, 0.00946f, 0.000461f, -0.003593f, -0.002377f, -0.001609f, -0.006363f, 0.0013485f, - -0.006706f, -0.005188f, 0.002165f, 0.006073f, 0.007717f, -0.007675f, 0.000827f, 0.004253f, 0.00697f, -0.0035f, - -0.00301f, 0.006565f, -0.0002068f, -0.004593f, 0.00198f, 0.00107f, -0.003082f, 0.002243f, 0.00983f, 0.00608f, - 0.001682f, 0.001701f, -0.006935f, 0.004765f, -0.002333f, 0.003805f, -0.00905f, 0.00599f, 0.00998f, -0.001602f, - 0.00744f, -0.008514f, 0.005424f, -0.002413f, 0.00862f, 0.00459f, -0.002516f, 0.00283f, -0.00272f, -0.005207f, - -0.00738f, -0.005386f, -0.00951f, 0.008415f, 0.002865f, -0.00726f, 0.00494f, 0.002226f, 0.0000424f, -0.007507f, - 0.002193f, -0.004482f, 0.002386f, 0.005997f, -0.001786f, 0.009f, 0.006435f, -0.0067f, -0.001984f, 0.001514f, - -0.004917f, 0.003468f, -0.0013685f, -0.007122f, 0.00788f, 0.000825f, 0.00621f, -0.00437f, 0.005653f, 0.009674f, - 0.003576f, 0.00956f, 0.0064f, 0.00283f, -0.00797f, 0.00867f, 0.004536f, -0.00985f, 0.004856f, -0.006878f, - 0.006012f, -0.0042f, -0.00328f, -0.00885f, -0.0079f, 0.004917f, -0.00594f, 0.003452f, -0.006355f, -0.003536f, - 0.0022f, 0.003494f, -0.008865f, 0.00461f, -0.00485f, 0.00889f, -0.002272f, 0.00596f}; - std::vector weight_data; std::vector bias_data; GetAttentionWeight(weight_data); @@ -857,74 +860,13 @@ TEST(AttentionTest, Causal_EmptyPastState) { // No mask_index std::vector mask_index_data = {}; - std::vector output_data = { - 0.0027942657f, 0.0067901611f, 0.0070953369f, -0.0020713806f, 0.0055351257f, 0.0030479431f, -0.0060462952f, - -0.0087127686f, 0.0030956268f, -0.00036644936f, 0.0014686584f, -0.0038146973f, 0.0072097778f, -0.0052490234f, - 0.0056114197f, 0.0050926208f, 0.0080947876f, 0.0074501038f, 0.0079498291f, 0.0098876953f, -0.0066146851f, - 0.0064735413f, 0.0093307495f, -0.00051593781f, -0.0047683716f, -0.0069198608f, 0.0094604492f, 0.0066146851f, - -0.0040054321f, 0.0017976761f, -0.0058059692f, -0.0087051392f, 0.0054740906f, 0.0022010803f, 0.0075340271f, - 0.0047035217f, 0.00340271f, 0.0096969604f, -0.0016756058f, 0.0020771027f, -0.0063018799f, 0.0073280334f, - -0.0056381226f, 0.004032135f, -0.0082473755f, 0.0045280457f, 0.0045814514f, -0.0026607513f, -0.0031585693f, - -0.003660202f, -0.0053253174f, -0.0089187622f, -0.0073509216f, 0.0048408508f, 0.0058364868f, 0.0069313049f, - -0.0071868896f, 0.008392334f, -0.0018663406f, -0.0092163086f, -0.00048780441f, -0.0054283142f, -0.0061683655f, - 0.0078048706f, 0.0025291443f, 0.0065917969f, 0.0072250366f, -0.0018520355f, 0.005531311f, 0.003118515f, - -0.0061264038f, -0.0090484619f, 0.003276825f, -0.00047063828f, 0.0015802383f, -0.0037345886f, 0.0069732666f, - -0.0054092407f, 0.0052947998f, 0.004940033f, 0.0085220337f, 0.007194519f, 0.0078659058f, 0.0095214844f, - -0.0065574646f, 0.0064315796f, 0.0093383789f, -0.00058555603f, -0.0046386719f, -0.0067710876f, 0.0096130371f, - 0.0064315796f, -0.0040740967f, 0.0017337799f, -0.0057067871f, -0.008682251f, 0.0054855347f, 0.0019645691f, - 0.0075149536f, 0.0047187805f, 0.0036354065f, 0.0096282959f, -0.0019168854f, 0.0021934509f, -0.0063018799f, - 0.0072937012f, -0.006187439f, 0.0039825439f, -0.0081253052f, 0.0046577454f, 0.0045700073f, -0.0028266907f, - -0.0028438568f, -0.0035438538f, -0.0053100586f, -0.0090332031f, -0.0071105957f, 0.004699707f, 0.0058021545f, - 0.0071411133f, -0.0071678162f, 0.0085449219f, -0.0018749237f, -0.0095825195f, -0.00049686432f, -0.0053634644f, - -0.0057945251f, 0.0078277588f}; + std::vector input_data; + std::vector output_data; + std::vector present_data; + GetCausal_EmptyPastState(input_data, output_data, present_data); std::vector past_data = {}; - std::vector present_data = { - 0.0070152283f, -0.0049858093f, -0.0029277802f, 0.0078277588f, -0.001991272f, -0.0010290146f, -0.0084457397f, - -0.0028400421f, 0.0048294067f, 0.0012731552f, 0.0047149658f, 0.0069084167f, 0.0027809143f, 0.0014457703f, - -0.0010128021f, -0.0011024475f, 8.4400177e-05f, -0.0049972534f, -0.0040206909f, 0.002073288f, -0.0034713745f, - -0.0087203979f, -0.0047302246f, -0.0023326874f, -0.0063209534f, -0.0031681061f, -0.006942749f, 0.0064888f, - 0.0014505386f, -0.0037765503f, 0.0067138672f, -0.0018196106f, - 0.0064506531f, -0.0049514771f, -0.0036487579f, 0.0081558228f, -0.0024414062f, -0.0014820099f, -0.0086212158f, - -0.0025672913f, 0.0047111511f, 0.0011997223f, 0.0042953491f, 0.0067138672f, 0.0028495789f, 0.0015869141f, - -0.00037360191f, -0.0012044907f, 0.00029373169f, -0.005065918f, -0.0038700104f, 0.0014038086f, -0.0030422211f, - -0.0084838867f, -0.004863739f, -0.0028686523f, -0.0063362122f, -0.0034809113f, -0.0075874329f, 0.0066947937f, - 0.0019130707f, -0.0036792755f, 0.0070266724f, -0.0016460419f, - - -0.003238678f, -0.0066452026f, 0.0043983459f, -0.0016002655f, 0.0045623779f, 0.0065002441f, -0.0072174072f, - -0.0050315857f, 0.0087356567f, 0.0061645508f, 0.0069580078f, -0.003320694f, -0.0087814331f, 0.0062255859f, - 0.0035037994f, 0.00064849854f, -0.0018444061f, 0.0043945312f, 0.01008606f, -0.0089874268f, -0.0087585449f, - 0.0020160675f, 0.00207901f, -0.0097732544f, -0.0042991638f, 0.0070266724f, -0.0028743744f, 0.0087051392f, - 0.0099868774f, 0.0076217651f, -0.0027103424f, -0.006439209f, - -0.0033836365f, -0.0063171387f, 0.0043144226f, -0.001707077f, 0.0044555664f, 0.0069885254f, -0.0072593689f, - -0.0050468445f, 0.008895874f, 0.0050582886f, 0.0064926147f, -0.0030384064f, -0.0083618164f, 0.0065307617f, - 0.0038928986f, 0.0005645752f, -0.0024528503f, 0.0043983459f, 0.0099029541f, -0.0088043213f, -0.0081558228f, - 0.0021705627f, 0.0018062592f, -0.0094985962f, -0.0045890808f, 0.0068702698f, -0.002532959f, 0.0081863403f, - 0.009765625f, 0.0077362061f, -0.0026664734f, -0.0060920715f, - - 0.0027942657f, 0.0067901611f, 0.0070953369f, -0.0020713806f, 0.0055351257f, 0.0030479431f, -0.0060462952f, - -0.0087127686f, 0.0030956268f, -0.00036644936f, 0.0014686584f, -0.0038146973f, 0.0072097778f, -0.0052490234f, - 0.0056114197f, 0.0050926208f, 0.0080947876f, 0.0074501038f, 0.0079498291f, 0.0098876953f, -0.0066146851f, - 0.0064735413f, 0.0093307495f, -0.00051593781f, -0.0047683716f, -0.0069198608f, 0.0094604492f, 0.0066146851f, - -0.0040054321f, 0.0017976761f, -0.0058059692f, -0.0087051392f, - 0.0022659302f, 0.0063896179f, 0.0073509216f, -0.0016336441f, 0.0055236816f, 0.0031890869f, -0.0062026978f, - -0.0093917847f, 0.0034580231f, -0.00057506561f, 0.0016918182f, -0.0036563873f, 0.0067405701f, -0.005569458f, - 0.0049743652f, 0.0047874451f, 0.0089492798f, 0.0069389343f, 0.0077819824f, 0.0091552734f, -0.0065002441f, - 0.0063934326f, 0.0093460083f, -0.00065517426f, -0.0045127869f, -0.0066223145f, 0.009765625f, 0.0062484741f, - -0.0041465759f, 0.0016708374f, -0.0056037903f, -0.0086669922f, - - 0.0054740906f, 0.0022010803f, 0.0075340271f, 0.0047035217f, 0.00340271f, 0.0096969604f, -0.0016756058f, - 0.0020771027f, -0.0063018799f, 0.0073280334f, -0.0056381226f, 0.004032135f, -0.0082473755f, 0.0045280457f, - 0.0045814514f, -0.0026607513f, -0.0031585693f, -0.003660202f, -0.0053253174f, -0.0089187622f, -0.0073509216f, - 0.0048408508f, 0.0058364868f, 0.0069313049f, -0.0071868896f, 0.008392334f, -0.0018663406f, -0.0092163086f, - -0.00048780441f, -0.0054283142f, -0.0061683655f, 0.0078048706f, - 0.0054931641f, 0.0017261505f, 0.0074958801f, 0.0047340393f, 0.003868103f, 0.0095596313f, -0.0021572113f, - 0.0023078918f, -0.0063018799f, 0.0072631836f, -0.0067367554f, 0.0039329529f, -0.0080032349f, 0.0047874451f, - 0.0045623779f, -0.0029945374f, -0.0025291443f, -0.0034275055f, -0.0052986145f, -0.0091400146f, -0.0068702698f, - 0.0045623779f, 0.0057678223f, 0.0073547363f, -0.0071487427f, 0.0087051392f, -0.0018835068f, -0.0099411011f, - -0.00050640106f, -0.0052947998f, -0.0054206848f, 0.0078430176f}; - bool is_unidirectional = true; bool use_past_state = true; int past_sequence_length = 0; @@ -966,7 +908,6 @@ TEST(AttentionTest, Causal_EmptyPastState) { use_past_state, past_sequence_length, &past_data, &present_data); } } -#endif TEST(AttentionTest, AttentionEmptyPastState) { RawAttentionEmptyPastState(false); @@ -1075,11 +1016,15 @@ void RawAttentionPastStateBatch1(bool past_present_share_buffer) { batch_size, sequence_length, hidden_size, number_of_heads, false, is_unidirectional, use_past_state, past_sequence_length, &past_data, &present_data); } else { + // TODO: Unskip when fixed #41968513 + // DML doesn't support past_present_share_buffer for Attention yet + constexpr bool disable_dml = true; + RunAttentionTest(input_data, weight_data, bias_data, mask_index_data, output_data, batch_size, sequence_length, hidden_size, number_of_heads, false, is_unidirectional, use_past_state, past_sequence_length, &past_data, &present_data, AttentionMaskType::MASK_1D_KEY_SEQ_LEN, 0, past_sequence_length + sequence_length + 4, - true, false, true, {}, {}, 0, true); + true, false, true, disable_dml, {}, {}, 0, true); } } @@ -1204,11 +1149,15 @@ void RawAttentionPastStateBatch2(bool past_present_share_buffer) { batch_size, sequence_length, hidden_size, number_of_heads, false, is_unidirectional, use_past_state, past_sequence_length, &past_data, &present_data); } else { + // TODO: Unskip when fixed #41968513 + // DML doesn't support past_present_share_buffer for Attention yet + constexpr bool disable_dml = true; + RunAttentionTest(input_data, weight_data, bias_data, mask_index_data, output_data, batch_size, sequence_length, hidden_size, number_of_heads, false, is_unidirectional, use_past_state, past_sequence_length, &past_data, &present_data, AttentionMaskType::MASK_1D_KEY_SEQ_LEN, 0, past_sequence_length + sequence_length, - true, false, true, {}, {}, 0, true); + true, false, true, disable_dml, {}, {}, 0, true); } } @@ -1324,12 +1273,16 @@ void RawAttentionPastStateBatch2WithPadding(bool past_present_share_buffer) { use_past_state, past_sequence_length, &past_data, &present_data, AttentionMaskType::MASK_1D_END_START); } else { + // TODO: Unskip when fixed #41968513 + // DML doesn't support past_present_share_buffer for Attention yet + constexpr bool disable_dml = true; + RunAttentionTest(input_data, weight_data, bias_data, mask_index_data, output_data, batch_size, sequence_length, hidden_size, number_of_heads, false, is_unidirectional, use_past_state, past_sequence_length, &past_data, &present_data, AttentionMaskType::MASK_1D_END_START, 0, past_sequence_length + sequence_length + 4, - true, false, true, {}, {}, 0, true); + true, false, true, disable_dml, {}, {}, 0, true); } } @@ -1617,7 +1570,7 @@ TEST(AttentionTest, AttentionUnidirectional3DMask) { 1, 1}; std::vector output_data = { - 3.0146f, 0.1142f, 3.9834f, 5.3394f, + -4.09f, 0.42f, -0.11f, 0.57f, 8.69f, -0.13f, 4.25f, 5.65f, 8.69f, -0.13f, 4.25f, 5.65f, 3.96967912f, 0.07314367f, 4.25f, 5.65f}; @@ -1659,7 +1612,7 @@ TEST(AttentionTest, AttentionUnidirectionalAttentionMask) { std::vector mask_index_data = {0, 1, 1, 1}; std::vector output_data = { - 3.0146f, 0.1142f, 3.9834f, 5.3394f, + -4.09f, 0.42f, -0.11f, 0.57f, 8.69f, -0.13f, 4.25f, 5.65f, 8.69f, -0.13f, 4.25f, 5.65f, 3.96967912f, 0.07314367f, 4.25f, 5.65f}; @@ -1701,7 +1654,7 @@ TEST(AttentionTest, AttentionWithNormFactor) { std::vector mask_index_data = {0, 1, 1, 1}; std::vector output_data = { - 3.0146f, 0.1142f, 3.9834f, 5.3394f, + -4.09f, 0.42f, -0.11f, 0.57f, 8.69f, -0.13f, 4.25f, 5.65f, 8.69f, -0.13f, 4.25f, 5.65f, 3.96967912f, 0.07314367f, 4.25f, 5.65f}; @@ -1716,7 +1669,7 @@ TEST(AttentionTest, AttentionWithNormFactor) { batch_size, sequence_length, hidden_size, number_of_heads, use_float16, is_unidirectional, use_past_state, past_sequence_length, past_data, present_data, AttentionMaskType::MASK_2D_KEY_PADDING, 0 /*input_hidden_size*/, 0 /*max_sequence_length*/, - false /*disable_cpu*/, false /*disable_cuda*/, true /*disable_rocm*/, {} /*qkv_sizes*/, + false /*disable_cpu*/, false /*disable_cuda*/, true /*disable_rocm*/, false /*disable_dml*/, {} /*qkv_sizes*/, {} /*relative_position_bias_data*/, 0 /*kv_sequence_length*/, false /*past_present_share_buffer*/, true /*use_scale*/); } @@ -1724,32 +1677,16 @@ TEST(AttentionTest, AttentionWithNormFactor) { TEST(AttentionTest, AttentionWithNeoXRotaryEmbedding) { int batch_size = 2; int sequence_length = 2; - int hidden_size = 4; - int number_of_heads = 2; - - std::vector input_data = { - 0.5f, 0.2f, 0.3f, -0.6f, - 0.8f, -0.5f, 0.0f, 1.f, - 0.8f, -0.5f, 0.0f, 1.f, - 0.5f, 0.2f, 0.3f, -0.6f}; - - std::vector weight_data = { - 0.1f, -0.2f, 0.3f, 1.0f, 1.1f, 0.3f, 0.5f, 0.2f, 0.3f, -0.6f, 1.5f, 2.0f, - 0.5f, 0.1f, 0.4f, 1.6f, 1.0f, 2.0f, 0.4f, 0.8f, 0.9f, 0.1f, -1.3f, 0.7f, - 0.3f, 0.2f, 4.0f, 2.2f, 1.6f, 1.1f, 0.7f, 0.2f, 0.4f, 1.0f, 1.2f, 0.5f, - 0.2f, 0.1f, 0.4f, 1.6f, 2.4f, 3.3f, 2.1f, 4.2f, 8.4f, 0.0f, 2.1f, 3.2f}; + int hidden_size = 64; + int number_of_heads = 1; - std::vector bias_data = { - -0.5f, 0.6f, 1.2f, 2.1f, 0.5f, 0.7f, 0.2f, 1.2f, 0.5f, 0.4f, 0.3f, 1.2f}; + std::vector input_data = {}; + std::vector weight_data = {}; + std::vector bias_data = {}; + std::vector mask_index_data = {1, 1, 1, 1}; + std::vector output_data = {}; - // Test mask start position > 0. - std::vector mask_index_data = {0, 1, 1, 1}; - - std::vector output_data = { - 3.0146f, 0.1142f, 3.9834f, 5.3394f, - 8.69f, -0.13f, 4.25f, 5.65f, - 8.69f, -0.13f, 4.25f, 5.65f, - -1.4697f, 0.3071f, 4.25f, 5.65f}; + GetAttentionDataWithNeoXRotaryEmbedding(input_data, weight_data, bias_data, output_data); bool use_float16 = true; bool is_unidirectional = true; @@ -1757,11 +1694,16 @@ TEST(AttentionTest, AttentionWithNeoXRotaryEmbedding) { int past_sequence_length = 0; const std::vector* past_data = nullptr; const std::vector* present_data = nullptr; + + // TODO: Unskip when fixed #41968513 + // DML doesn't support do_rotary for Attention yet + constexpr bool disable_dml = true; + RunAttentionTest(input_data, weight_data, bias_data, mask_index_data, output_data, batch_size, sequence_length, hidden_size, number_of_heads, use_float16, is_unidirectional, use_past_state, past_sequence_length, past_data, present_data, AttentionMaskType::MASK_2D_KEY_PADDING, 0 /*input_hidden_size*/, 0 /*max_sequence_length*/, - true /*disable_cpu*/, false /*disable_cuda*/, true /*disable_rocm*/, {} /*qkv_sizes*/, + true /*disable_cpu*/, false /*disable_cuda*/, true /*disable_rocm*/, disable_dml, {} /*qkv_sizes*/, {} /*relative_position_bias_data*/, 0 /*kv_sequence_length*/, false /*past_present_share_buffer*/, true /*use_scale*/, true /*use_neox_rotary_embedding*/); } @@ -2170,9 +2112,11 @@ static void RunModelWithRandomInput( constexpr int hidden_size = 768; constexpr int num_heads = 12; + const float min_value = is_float16 ? -0.001f : -1.0f; + const float max_value = is_float16 ? 0.001f : 1.0f; std::vector batch_input_dims{1, sequence_length, hidden_size}; - std::vector batch_input_data = random.Uniform(batch_input_dims, -1.0f, 1.0f); + std::vector batch_input_data = random.Uniform(batch_input_dims, min_value, max_value); std::vector input_dims{batch_size, sequence_length, hidden_size}; std::vector input_data; @@ -2181,17 +2125,18 @@ static void RunModelWithRandomInput( } std::vector weight_dims{hidden_size, 3 * hidden_size}; - std::vector weight_data = random.Uniform(weight_dims, -1.0f, 1.0f); + std::vector weight_data = random.Uniform(weight_dims, min_value, max_value); std::vector bias_dims{3 * hidden_size}; - std::vector bias_data = random.Uniform(bias_dims, -1.0f, 1.0f); + std::vector bias_data = random.Uniform(bias_dims, min_value, max_value); - float gpu_threshold = is_float16 ? static_cast(sequence_length) / 32.0f : 0.005f; + float gpu_threshold = is_float16 ? 0.5f : 0.005f; constexpr float cpu_threshold = 0.002f; bool enable_cuda = HasCudaEnvironment(is_float16 ? 530 : 0); bool enable_rocm = (nullptr != DefaultRocmExecutionProvider().get()); bool enable_cpu = (nullptr != DefaultCpuExecutionProvider().get() && !is_float16); - if (enable_cuda || enable_rocm) { + bool enable_dml = (nullptr != DefaultDmlExecutionProvider().get()); + if (enable_cuda || enable_rocm || enable_dml) { OpTester test("Attention", 1, onnxruntime::kMSDomain); test.AddAttribute("num_heads", num_heads); if (is_float16) { @@ -2203,11 +2148,16 @@ static void RunModelWithRandomInput( test.AddInput("weight", weight_dims, weight_data); test.AddInput("bias", bias_dims, bias_data); } - test.AddInput("mask_index", mask_index_dims, mask_index_data); + if (mask_index_data.size() > 0) { + test.AddInput("mask_index", mask_index_dims, mask_index_data); + } + test.AddReferenceOutputs(onnx_model, gpu_threshold); std::vector> execution_providers; if (enable_cuda) { execution_providers.push_back(DefaultCudaExecutionProvider()); + } else if (enable_dml) { + execution_providers.push_back(DefaultDmlExecutionProvider()); } else { execution_providers.push_back(DefaultRocmExecutionProvider()); } @@ -2271,6 +2221,25 @@ TEST(AttentionTest, Attention_Mask1D_Fp32_B2_S64) { false); } +// This case can be used to test flash attention using Ampere GPU +TEST(AttentionTest, Attention_NoMask_Fp16) { + constexpr int batch_size = 2; + std::vector sequence_lengths{1, 7, 8}; + for (const auto& sequence_length : sequence_lengths) { + std::vector mask_index_dims{}; + std::vector mask_index_data{}; + std::string onnx_model = "testdata/attention_no_mask_fp16.onnx"; + + RunModelWithRandomInput( + batch_size, + sequence_length, + mask_index_dims, + mask_index_data, + onnx_model, + true); + } +} + // This test is disabled since it is flaky. TEST(AttentionTest, DISABLED_Attention_Mask1D_Fp16_B2_FusedNoPadding) { constexpr int batch_size = 2; diff --git a/onnxruntime/test/contrib_ops/attention_op_test_helper.cc b/onnxruntime/test/contrib_ops/attention_op_test_helper.cc index a4757cbaebc2f..fcd17e0d4ed71 100644 --- a/onnxruntime/test/contrib_ops/attention_op_test_helper.cc +++ b/onnxruntime/test/contrib_ops/attention_op_test_helper.cc @@ -1,1410 +1,44 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include -#include "test/contrib_ops/attention_op_test_helper.h" +#include #include "gtest/gtest.h" +#include "core/common/common.h" +#include "test/contrib_ops/attention_op_test_helper.h" +#include "test/util/include/tensors_from_file.h" namespace onnxruntime { namespace test { -#ifndef _MSC_VER +static void LoadTensor(const std::string& name, std::vector& values) { + static std::unordered_map> tensors; + static std::once_flag load_once_flag; + std::call_once(load_once_flag, []() { + const std::string test_data_path("testdata/attention/attention_test_data.txt"); + LoadTensorsFromFile(test_data_path, tensors); + + const std::string packed_mha_test_data_path("testdata/attention/packed_multihead_attention_test_data.txt"); + LoadTensorsFromFile(packed_mha_test_data_path, tensors); + }); + + auto it = tensors.find(name); + if (it == tensors.end()) { + ORT_THROW("Failed to find key:", name); + } + + values = it->second; +} + void GetWeight_64_3_64(std::vector& weight_data) { - weight_data = { - -0.004707f, -0.006775f, 0.0009236f, 0.003067f, -0.00806f, 0.00779f, 0.0004425f, 0.00846f, 0.00048f, - 0.00999f, 0.00115f, 0.00226f, -0.00705f, 0.004467f, 0.001455f, -0.006073f, 0.00465f, -0.00861f, - -0.002779f, 0.00883f, -0.002996f, 0.008354f, -0.003141f, -0.007374f, 0.001634f, -0.009544f, 0.00198f, - 0.005894f, 0.001434f, 0.001589f, 0.00921f, -0.00507f, 0.00448f, 0.0002687f, -0.003147f, 0.001627f, - -0.005608f, 0.006516f, 0.00935f, -0.004715f, 0.00833f, -0.00563f, 0.00281f, -0.005875f, 0.000629f, - 0.00993f, -0.002695f, 0.004486f, -0.00528f, -0.003807f, 0.00521f, 0.00010276f, 0.003307f, 0.000701f, - 0.0001151f, 0.00649f, 0.00934f, -0.001063f, 0.002327f, -0.0002892f, 0.003317f, -0.003506f, 0.004875f, - 0.0006566f, 0.000953f, -0.005898f, 0.00326f, 0.00877f, 0.00923f, -0.00622f, -0.006588f, 0.007748f, - -0.001789f, 0.00002104f, 0.002937f, 0.00816f, 0.005833f, -0.006634f, 0.006985f, 0.00951f, 0.002947f, - 0.001871f, -0.009445f, 0.0004554f, -0.006294f, -0.00649f, 0.00917f, -0.004158f, -0.00462f, -0.001531f, - -0.00658f, -0.00364f, -0.00462f, 0.003723f, 0.009636f, 0.003305f, -0.00984f, 0.006126f, -0.0010395f, - -0.00852f, 0.006287f, -0.002949f, -0.004f, -0.002415f, 0.0009527f, 0.001624f, 0.00364f, 0.007088f, - -0.00717f, -0.009224f, -0.00997f, 0.001726f, -0.00877f, -0.000602f, 0.0089f, 0.009026f, -0.009514f, - 0.00852f, 0.0003986f, -0.006855f, -0.00583f, 0.003622f, -0.00526f, 0.001879f, -0.007053f, 0.00006664f, - 0.00972f, -0.000457f, -0.00759f, -0.007107f, 0.002337f, -0.004204f, -0.005676f, 0.00985f, 0.00978f, - -0.004486f, 0.005093f, -0.009285f, 0.004093f, -0.00682f, 0.00963f, -0.006954f, -0.003674f, -0.003822f, - 0.00202f, -0.004635f, -0.0009174f, -0.001202f, 0.00639f, -0.004356f, -0.00741f, -0.00586f, -0.00319f, - -0.002506f, 0.005047f, 0.007156f, -0.00765f, 0.00702f, 0.007477f, 0.000626f, -0.001587f, -0.005455f, - 0.005814f, -0.002127f, 0.00834f, 0.001279f, 0.007996f, -0.005787f, -0.006924f, -0.004063f, -0.00435f, - -0.00427f, 0.0002115f, 0.00981f, -0.00138f, -0.007965f, -0.004536f, -0.003431f, 0.00416f, 0.005894f, - 0.006054f, 0.00907f, 0.00388f, -0.006763f, 0.001692f, -0.00797f, -0.00691f, 0.00798f, 0.00867f, - -0.00788f, 0.002062f, -0.003761f, 0.009834f, -0.002445f, -0.00613f, 0.0096f, -0.005466f, -0.0008426f, - 0.0002431f, -0.009995f, 0.003736f, -0.0071f, -0.003593f, 0.006386f, 0.005997f, -0.003328f, 0.007515f, - -0.008675f, 0.00547f, -0.00388f, 0.00473f, 0.00362f, -0.00469f, 0.006958f, -0.001264f, -0.003887f, - -0.004276f, -0.000396f, 0.00453f, -0.00465f, -0.007343f, -0.005787f, -0.00927f, -0.006058f, -0.004566f, - -0.009056f, -0.00891f, 0.007633f, 0.001098f, -0.003368f, -0.007214f, -0.00905f, -0.00898f, -0.008736f, - -0.00948f, 0.003162f, 0.004402f, -0.006245f, -0.00515f, -0.00378f, -0.003248f, -0.00304f, 0.001834f, - -0.002672f, 0.005234f, -0.007706f, 0.0084f, 0.00832f, -0.00904f, -0.00596f, 0.009926f, -0.00869f, - 0.001513f, 0.00728f, 0.001057f, 0.001452f, 0.00785f, 0.001203f, -0.004528f, 0.006573f, 0.003656f, - 0.005966f, -0.006985f, 0.002844f, 0.00883f, 0.0004826f, 0.003279f, 0.006916f, 0.00263f, -0.002415f, - -0.001928f, -0.0004041f, -0.004593f, -0.00204f, 0.007965f, -0.008224f, -0.00591f, -0.002144f, 0.000688f, - 0.001676f, -0.00949f, -0.003304f, -0.007637f, 0.00973f, -0.008224f, -0.001211f, -0.003345f, 0.002115f, - -0.00615f, -0.004955f, -0.00803f, 0.00807f, -0.0006227f, 0.00845f, -0.006916f, 0.004353f, -0.000934f, - 0.005604f, -0.00825f, -0.004402f, -0.00441f, 0.00257f, -0.008415f, 0.006542f, 0.001357f, -0.004974f, - -0.00993f, 0.0001058f, 0.002855f, -0.0081f, 0.001513f, -0.00191f, 0.0004003f, 0.003874f, -0.0015545f, - -0.00736f, 0.006718f, 0.005135f, 0.003859f, -0.0054f, 0.00993f, 0.000952f, 0.00228f, 0.001163f, - 0.00918f, 0.00582f, 0.00308f, 0.008415f, 0.00889f, 0.00011665f, -0.007362f, -0.009926f, -0.00784f, - 0.005817f, -0.002918f, 0.005043f, -0.003029f, 0.0085f, -0.007362f, -0.00857f, 0.006832f, -0.00055f, - 0.008835f, -0.00522f, -0.002085f, 0.00353f, -0.007706f, 0.006283f, 0.004414f, -0.002405f, -0.003002f, - -0.00946f, -0.001164f, -0.004177f, 0.00834f, -0.001576f, 0.00855f, 0.004025f, 0.000285f, -0.004486f, - -0.00703f, -0.003061f, 0.003452f, 0.001276f, 0.008446f, -0.001302f, 0.004333f, -0.00898f, -0.002445f, - -0.006523f, 0.0004334f, -0.003206f, -0.00349f, -0.005497f, -0.007786f, 0.007397f, 0.00925f, 0.002077f, - 0.004074f, 0.006626f, -0.001693f, -0.0005975f, -0.005074f, 0.00324f, 0.00925f, -0.009735f, -0.007133f, - -0.0064f, -0.00455f, -0.003153f, 0.0056f, -0.006073f, -0.00274f, -0.00587f, -0.005066f, 0.003595f, - -0.00932f, -0.005f, 0.00569f, 0.008415f, 0.006866f, 0.003952f, -0.009285f, -0.008064f, 0.00824f, - 0.0000188f, -0.001233f, 0.005726f, -0.0007806f, -0.008385f, -0.001798f, -0.008095f, 0.00986f, 0.006924f, - 0.00712f, -0.00964f, -0.00797f, 0.00943f, -0.007416f, 0.007904f, 0.006893f, 0.00799f, -0.007164f, - 0.007214f, 0.00931f, 0.000645f, -0.0058f, 0.009254f, -0.002079f, 0.000969f, 0.009636f, -0.002365f, - -0.002348f, 0.007053f, -0.002796f, -0.007652f, -0.001554f, 0.00402f, -0.002838f, -0.006958f, 0.000331f, - 0.006435f, -0.004036f, 0.007595f, 0.00812f, 0.00637f, 0.007732f, -0.006916f, 0.003952f, -0.008064f, - -0.00928f, 0.00468f, -0.000512f, -0.006287f, 0.00607f, -0.001904f, -0.00458f, 0.003412f, 0.000382f, - -0.00822f, -0.00486f, 0.0008364f, 0.0004992f, 0.003582f, 0.0088f, 0.002453f, -0.00856f, 0.00886f, - 0.0077f, 0.0004592f, -0.001417f, -0.005142f, 0.004696f, -0.003576f, 0.004807f, -0.00851f, -0.006245f, - -0.003649f, -0.0001528f, 0.004017f, -0.006123f, -0.004158f, -0.00445f, 0.004864f, -0.0005493f, 0.00399f, - -0.007244f, 0.003246f, 0.00407f, 0.00929f, -0.006706f, 0.0084f, -0.003496f, 0.00843f, 0.00514f, - 0.002714f, -0.0001633f, -0.00866f, 0.004837f, -0.003016f, 0.00593f, -0.00849f, 0.001287f, -0.007706f, - 0.001479f, -0.002241f, 0.00843f, -0.001236f, -0.007572f, -0.004448f, -0.001927f, 0.001139f, 0.004982f, - -0.00673f, -0.000568f, 0.009346f, 0.000487f, 0.001392f, -0.009605f, 0.00944f, 0.002022f, 0.00617f, - 0.00472f, 0.009575f, -0.006416f, 0.004265f, 0.002005f, 0.000578f, 0.002592f, 0.002707f, -0.005333f, - -0.00928f, -0.00935f, -0.00833f, -0.00205f, -0.005795f, -0.001061f, -0.003605f, 0.003078f, 0.00592f, - 0.0006485f, -0.00504f, 0.002682f, 0.00826f, -0.003983f, -0.00493f, 0.00406f, -0.00838f, 0.0032f, - 0.0009565f, 0.00471f, 0.00504f, 0.004612f, -0.002768f, 0.00791f, -0.002892f, 0.00471f, 0.00588f, - 0.005978f, -0.005203f, -0.009995f, 0.009346f, -0.00802f, 0.003807f, 0.001364f, -0.00736f, 0.009285f, - -0.001995f, 0.002632f, -0.00904f, 0.007042f, -0.00326f, 0.006516f, 0.00492f, 0.00734f, -0.00867f, - -0.002512f, -0.003729f, 0.0027f, -0.002659f, -0.009514f, -0.005634f, -0.001473f, -0.00545f, 0.003551f, - 0.001995f, -0.003704f, 0.006386f, 0.003313f, -0.002823f, 0.00105f, 0.00993f, 0.00951f, -0.007275f, - -0.002213f, -0.003418f, 0.00599f, 0.00948f, 0.007572f, -0.00944f, -0.00924f, 0.00011665f, 0.0069f, - -0.00544f, 0.007515f, -0.006832f, -0.007774f, 0.00853f, -0.0007486f, -0.00643f, -0.0001878f, -0.00849f, - -0.007603f, 0.0016985f, -0.00986f, 0.003975f, -0.002176f, -0.009796f, 0.004795f, -0.00699f, -0.006725f, - 0.00109f, 0.004498f, -0.00569f, -0.00584f, 0.004047f, -0.001022f, 0.001479f, -0.00751f, -0.002579f, - -0.004086f, 0.007603f, -0.0000106f, 0.007366f, 0.0029f, -0.003498f, 0.007385f, -0.00759f, -0.005886f, - 0.00476f, -0.0003812f, -0.00008225f, 0.00998f, 0.002716f, -0.00925f, -0.00439f, -0.000902f, -0.00296f, - -0.007347f, -0.005882f, -0.001428f, -0.002855f, -0.003311f, -0.000793f, -0.00403f, -0.00829f, -0.00999f, - -0.00838f, 0.008804f, 0.004124f, -0.005882f, 0.001305f, 0.00511f, 0.00799f, -0.00953f, -0.008575f, - -0.00556f, -0.00858f, 0.00565f, 0.00908f, 0.00591f, 0.0007925f, -0.00912f, -0.005894f, -0.002588f, - -0.00957f, -0.00682f, 0.002174f, 0.00706f, 0.00528f, 0.0069f, -0.004517f, -0.002382f, 0.005596f, - 0.00645f, 0.00956f, 0.00796f, 0.007706f, 0.004818f, 0.002308f, 0.001367f, -0.004177f, 0.00842f, - 0.007416f, -0.00404f, -0.009094f, 0.00447f, -0.00284f, -0.002499f, -0.0001582f, 0.001681f, 0.004993f, - -0.0059f, 0.007282f, -0.00809f, 0.00927f, 0.004948f, 0.009766f, -0.00618f, -0.001559f, -0.00461f, - 0.001866f, 0.00827f, -0.00785f, -0.003101f, 0.00977f, -0.00444f, -0.00916f, -0.0008535f, 0.004913f, - 0.005627f, 0.007965f, 0.000532f, -0.00878f, 0.004047f, -0.005302f, 0.00201f, 0.002964f, -0.00895f, - 0.005768f, 0.00388f, 0.007526f, -0.00783f, 0.003794f, 0.005363f, 0.003454f, -0.002235f, -0.003494f, - -0.001541f, -0.00003624f, -0.0007634f, -0.0014f, -0.003124f, 0.00829f, -0.00298f, -0.00868f, -0.001243f, - -0.005383f, -0.009964f, 0.004433f, -0.002045f, -0.00753f, 0.002361f, -0.007473f, -0.002419f, -0.000931f, - 0.00585f, 0.007114f, -0.002247f, 0.00472f, -0.003033f, -0.001974f, 0.001622f, -0.007473f, -0.005375f, - -0.005013f, 0.00436f, 0.00662f, -0.0053f, 0.000606f, -0.00849f, -0.007004f, 0.006794f, -0.0005445f, - -0.001269f, 0.00391f, 0.006294f, 0.007088f, -0.009026f, -0.001965f, -0.008545f, 0.002115f, 0.003534f, - -0.00857f, 0.00412f, -0.00722f, -0.006386f, 0.00595f, -0.003778f, -0.00886f, -0.0002267f, 0.00249f, - -0.002825f, 0.0003204f, 0.0002894f, -0.004147f, -0.003632f, 0.001764f, -0.002983f, 0.006584f, -0.004402f, - 0.006493f, 0.002014f, -0.0061f, 0.00816f, 0.005585f, -0.008125f, 0.006546f, -0.00956f, 0.004185f, - 0.001067f, 0.001277f, 0.007835f, -0.003933f, 0.00979f, -0.003376f, 0.006573f, -0.00501f, 0.0007577f, - 0.00133f, -0.00737f, 0.00885f, -0.00599f, -0.001151f, -0.001389f, -0.00987f, -0.003214f, -0.00649f, - 0.005424f, 0.0004575f, 0.002352f, 0.005722f, -0.001995f, -0.007717f, 0.001034f, -0.006557f, 0.0088f, - -0.003183f, -0.00663f, 0.00634f, -0.003008f, -0.004925f, 0.00539f, -0.00432f, -0.00651f, 0.009895f, - 0.00532f, -0.0003607f, 0.003397f, 0.006145f, 0.00531f, -0.006275f, 0.00985f, -0.00471f, 0.00817f, - -0.00927f, 0.007217f, 0.005924f, 0.003187f, 0.001192f, -0.003986f, -0.0000217f, -0.0012245f, -0.003933f, - -0.00617f, -0.002232f, 0.00444f, 0.002008f, 0.0006056f, -0.002827f, -0.007366f, 0.002996f, -0.006752f, - -0.004143f, 0.001662f, -0.00793f, 0.002161f, 0.0001992f, 0.00803f, -0.0000725f, 0.001066f, 0.004745f, - -0.005367f, -0.00641f, 0.00431f, -0.004715f, 0.008575f, -0.007202f, 0.003786f, -0.00247f, 0.006382f, - -0.006832f, 0.00505f, -0.001084f, 0.009674f, 0.00458f, -0.00473f, -0.00656f, -0.00011283f, 0.004417f, - -0.001419f, -0.0005164f, 0.0000397f, -0.00395f, 0.00417f, -0.005512f, 0.0088f, 0.00568f, -0.0005984f, - 0.003128f, -0.006283f, -0.0000904f, -0.004738f, 0.00687f, 0.00592f, -0.005768f, -0.00859f, 0.003523f, - 0.001169f, -0.004498f, 0.00541f, 0.002956f, 0.00896f, -0.002571f, 0.0006533f, 0.002089f, -0.00473f, - -0.002241f, 0.005016f, 0.001295f, 0.005993f, -0.008064f, 0.000595f, -0.007744f, -0.00201f, 0.0075f, - -0.00942f, 0.0002023f, -0.00979f, -0.002243f, 0.002829f, -0.004322f, 0.009125f, 0.00704f, 0.007282f, - 0.00807f, 0.005447f, 0.00518f, -0.0010195f, -0.004803f, -0.001293f, -0.001305f, 0.00975f, -0.00564f, - -0.005215f, -0.009445f, 0.00999f, 0.00959f, -0.009224f, -0.0053f, -0.002106f, -0.00839f, 0.001516f, - 0.003109f, 0.004414f, -0.00921f, -0.00868f, 0.00833f, 0.00809f, 0.004654f, 0.00678f, 0.002237f, - 0.007195f, -0.004875f, -0.001252f, 0.0073f, 0.007275f, 0.00825f, -0.005936f, 0.00594f, -0.00381f, - -0.002117f, 0.009f, -0.003998f, -0.00104f, -0.00421f, 0.00526f, 0.001031f, 0.00902f, 0.006794f, - -0.00912f, -0.0002892f, 0.002966f, 0.00478f, 0.00581f, 0.007217f, 0.008156f, -0.0000639f, -0.003164f, - 0.00859f, -0.00897f, 0.00409f, 0.0008936f, -0.00991f, -0.008316f, -0.004055f, 0.001252f, -0.00473f, - -0.002f, -0.003933f, 0.000755f, -0.00992f, 0.003569f, -0.00812f, -0.004215f, -0.00774f, 0.00907f, - 0.00653f, -0.00992f, -0.006252f, -0.00468f, -0.001105f, -0.007717f, 0.005302f, 0.003773f, -0.001262f, - -0.006207f, -0.005707f, 0.0053f, 0.00415f, 0.002441f, 0.0009265f, -0.006744f, 0.00994f, -0.0004816f, - -0.002108f, -0.003267f, 0.0000461f, 0.004364f, -0.00596f, -0.008675f, 0.005703f, 0.002748f, 0.00961f, - 0.006767f, -0.0000575f, -0.00845f, -0.003597f, 0.003616f, 0.00423f, 0.009705f, -0.00976f, -0.0085f, - 0.00307f, -0.004032f, -0.00784f, -0.00901f, -0.00873f, 0.00543f, 0.00744f, -0.006588f, -0.004765f, - -0.007202f, 0.006306f, -0.007484f, 0.007442f, -0.00008386f, 0.006374f, 0.00879f, 0.002039f, -0.003298f, - 0.003407f, 0.004673f, 0.0068f, 0.0001981f, 0.002296f, 0.008194f, -0.00805f, -0.007637f, -0.00903f, - -0.004025f, 0.001553f, 0.00881f, 0.001311f, -0.005016f, -0.006916f, -0.009926f, -0.00801f, 0.00945f, - 0.0001532f, 0.00234f, -0.002968f, -0.002174f, 0.004585f, -0.00658f, 0.000132f, 0.0004494f, -0.00954f, - -0.00848f, 0.009964f, -0.0006323f, -0.005016f, 0.001238f, 0.00433f, 0.001477f, 0.00578f, 0.00794f, - -0.00512f, -0.00207f, -0.00145f, -0.001166f, 0.008644f, -0.00915f, 0.007187f, -0.00415f, 0.006035f, - -0.004177f, 0.00817f, -0.00432f, 0.001062f, -0.005272f, -0.0004163f, 0.005154f, 0.005688f, -0.002985f, - -0.004f, -0.003176f, 0.00137f, 0.0002158f, 0.003798f, 0.0002009f, -0.01f, 0.00311f, -0.004234f, - 0.00681f, -0.005657f, -0.00963f, 0.00916f, 0.00847f, -0.002085f, -0.00211f, 0.006813f, -0.00473f, - 0.00873f, 0.0008483f, 0.004253f, 0.00865f, -0.007156f, -0.00996f, 0.005413f, -0.004253f, 0.00847f, - 0.004482f, 0.000647f, -0.006702f, 0.00845f, -0.009254f, -0.0001926f, 0.003868f, -0.00788f, 0.00951f, - -0.0005136f, -0.007698f, 0.00889f, -0.00953f, 0.007965f, 0.004982f, -0.004345f, 0.00841f, 0.007034f, - 0.006092f, 0.004166f, 0.00682f, -0.004635f, 0.003433f, -0.006527f, -0.0002658f, 0.005455f, 0.001926f, - -0.003582f, -0.0065f, 0.002348f, -0.001918f, -0.00488f, -0.006416f, -0.000873f, -0.00942f, 0.005177f, - -0.00194f, 0.006374f, 0.003983f, 0.00963f, 0.00697f, -0.00809f, -0.00791f, -0.003254f, -0.00669f, - -0.001487f, 0.002129f, -0.000799f, -0.003944f, 0.002693f, 0.00667f, 0.00892f, 0.002377f, 0.001005f, - -0.00792f, 0.002398f, -0.001093f, 0.0006456f, -0.002361f, 0.00533f, 0.0064f, 0.004524f, -0.0066f, - 0.004406f, 0.007538f, 0.00611f, 0.006294f, 0.0004857f, -0.00859f, 0.00928f, -0.005505f, -0.001135f, - -0.00712f, -0.00923f, 0.007534f, 0.00258f, 0.00685f, -0.00873f, 0.001684f, -0.001002f, -0.0005627f, - 0.00352f, -0.007324f, 0.00838f, 0.00731f, 0.006733f, -0.003832f, -0.00522f, 0.00299f, 0.000935f, - -0.005245f, 0.000987f, 0.007515f, 0.00704f, 0.0086f, 0.00133f, 0.0038f, 0.00622f, -0.0085f, - 0.00988f, 0.00625f, 0.00835f, -0.006023f, 0.007084f, -0.002728f, 0.009995f, 0.0008073f, 0.00341f, - -0.004547f, 0.005917f, -0.00818f, -0.009705f, 0.00907f, -0.008965f, 0.003483f, -0.00556f, -0.001769f, - 0.0068f, 0.007442f, 0.00497f, -0.001922f, 0.002583f, -0.00834f, 0.004417f, 0.005028f, 0.006336f, - 0.00402f, -0.00773f, 0.00672f, 0.00324f, 0.003595f, -0.00852f, 0.00503f, -0.00794f, -0.009766f, - -0.000813f, -0.006924f, -0.006622f, 0.0008802f, 0.004177f, 0.007427f, -0.001697f, 0.008575f, 0.00414f, - 0.00728f, 0.001138f, 0.000674f, -0.00209f, 0.004883f, -0.003029f, 0.0084f, -0.00798f, -0.003302f, - 0.007866f, 0.0006804f, 0.00306f, 0.006325f, 0.000508f, -0.002022f, 0.00473f, 0.00958f, -0.001912f, - -0.002256f, 0.001385f, 0.001143f, 0.007668f, -0.002575f, 0.004364f, 0.00919f, -0.00924f, 0.00558f, - -0.00447f, -0.004196f, -0.00547f, 0.00868f, -0.001469f, -0.00849f, 0.006397f, -0.00529f, 0.002329f, - 0.00847f, -0.009705f, 0.00233f, 0.000902f, 0.006073f, -0.00536f, 0.000875f, 0.002682f, -0.003347f, - 0.00905f, -0.00399f, -0.005783f, -0.00942f, 0.00671f, -0.008095f, -0.004467f, -0.008415f, 0.007996f, - -0.00848f, -0.00531f, 0.002605f, -0.00632f, -0.007652f, 0.009605f, 0.00929f, 0.007782f, -0.006844f, - -0.00115f, -0.006626f, -0.007526f, -0.001129f, 0.00943f, 0.004242f, -0.00486f, 0.00963f, -0.006386f, - -0.004513f, 0.00185f, -0.001695f, 0.00976f, -0.001186f, 0.001484f, 0.00429f, 0.000502f, -0.009285f, - 0.005882f, -0.00674f, 0.00882f, 0.00816f, -0.008705f, -0.003618f, 0.00406f, 0.007607f, -0.001528f, - -0.006336f, 0.006943f, 0.00753f, -0.004963f, -0.00602f, 0.002424f, -0.009476f, 0.007385f, 0.00988f, - -0.00359f, -0.005722f, 0.006863f, -0.00398f, -0.005486f, -0.004898f, -0.0000809f, -0.001511f, 0.00307f, - 0.002613f, 0.0004046f, 0.005634f, 0.00449f, 0.008606f, -0.002146f, 0.002882f, -0.007065f, -0.00796f, - -0.001136f, -0.001323f, 0.004715f, -0.007004f, -0.007565f, -0.002895f, 0.007523f, 0.007027f, 0.001487f, - -0.003323f, 0.004665f, 0.007706f, 0.009186f, 0.00814f, -0.003918f, -0.002062f, 0.00514f, 0.00858f, - 0.00251f, 0.007576f, -0.008736f, 0.001245f, -0.007298f, -0.006157f, 0.00719f, -0.008446f, -0.00864f, - 0.006535f, -0.00002605f, 0.003567f, 0.002258f, 0.003443f, -0.006207f, 0.00934f, 0.007515f, -0.00916f, - 0.00861f, -0.00939f, 0.008644f, 0.00656f, 0.001708f, 0.007935f, -0.001997f, 0.002934f, 0.001758f, - 0.004932f, 0.005432f, 0.007812f, 0.00046f, -0.00562f, 0.009186f, 0.002731f, -0.00234f, 0.00913f, - 0.006542f, -0.001783f, 0.001575f, 0.003267f, 0.00676f, 0.00647f, -0.002998f, 0.00408f, -0.002005f, - 0.002071f, 0.0001754f, -0.003132f, 0.009705f, -0.003107f, 0.00847f, -0.006504f, -0.0005784f, -0.004715f, - -0.008415f, -0.005634f, -0.00926f, -0.006958f, 0.004932f, 0.0076f, 0.008896f, 0.006042f, 0.001687f, - 0.000543f, 0.005047f, -0.002184f, 0.003963f, 0.00716f, 0.003468f, -0.003925f, 0.0073f, 0.00385f, - 0.002712f, -0.00893f, -0.00004303f, -0.00814f, 0.00937f, 0.0017395f, 0.00555f, 0.005833f, -0.001491f, - -0.00863f, 0.00947f, 0.001972f, -0.00984f, 0.004642f, 0.003994f, 0.00923f, -0.00984f, 0.0049f, - -0.00987f, -0.009834f, -0.0005865f, -0.006485f, -0.0005198f, 0.00919f, 0.0004432f, 0.001068f, 0.009254f, - -0.00881f, -0.003483f, 0.00565f, -0.007793f, -0.00989f, -0.00908f, 0.00276f, -0.002663f, -0.006893f, - 0.006332f, -0.004177f, 0.006104f, -0.00004715f, -0.003693f, 0.003576f, 0.00255f, -0.00928f, -0.002916f, - -0.007755f, -0.00729f, -0.0061f, 0.006523f, 0.00254f, 0.0008516f, -0.0003228f, -0.004017f, -0.007374f, - -0.005207f, 0.009056f, -0.002869f, 0.004906f, 0.007675f, 0.003086f, -0.008026f, -0.00861f, -0.006744f, - 0.0002438f, 0.00375f, 0.003315f, 0.00235f, 0.006836f, -0.005516f, 0.00434f, -0.004208f, 0.002483f, - 0.006413f, 0.00674f, 0.005604f, -0.002977f, -0.00732f, -0.00908f, 0.007484f, 0.004456f, -0.00822f, - 0.007442f, -0.003195f, 0.005753f, 0.007698f, -0.006397f, -0.00785f, -0.009605f, -0.00419f, 0.00676f, - -0.00833f, -0.00997f, -0.0003414f, 0.00906f, -0.0071f, -0.006092f, -0.00885f, -0.007866f, 0.000824f, - -0.003231f, -0.0006027f, 0.0074f, 0.00764f, 0.005795f, 0.002886f, 0.00958f, -0.007668f, 0.004158f, - 0.00622f, 0.00119f, 0.00277f, -0.00571f, -0.0006685f, -0.006645f, 0.0004497f, 0.00218f, -0.00405f, - 0.00485f, -0.007504f, -0.001411f, -0.001933f, -0.009964f, 0.002077f, 0.00159f, -0.002796f, 0.005787f, - 0.00335f, 0.001426f, -0.005413f, 0.00994f, 0.001742f, -0.00715f, -0.0099f, 0.007744f, -0.0008388f, - -0.000603f, -0.002f, 0.005436f, 0.00178f, 0.009796f, -0.001966f, -0.007397f, -0.001909f, 0.00931f, - 0.0003397f, -0.006817f, 0.0069f, 0.002558f, 0.00808f, -0.007313f, -0.00984f, -0.00001967f, 0.002756f, - 0.009995f, -0.00715f, 0.004765f, -0.006096f, 0.004337f, 0.005642f, 0.00763f, 0.007103f, -0.0002332f, - 0.00322f, 0.00284f, 0.003447f, 0.0012f, -0.001126f, -0.002625f, 0.00961f, -0.005272f, 0.0053f, - -0.002483f, -0.00931f, 0.007687f, -0.002417f, 0.004463f, 0.001136f, -0.005375f, -0.00672f, 0.007084f, - 0.0006213f, -0.00912f, 0.006542f, 0.00606f, 0.003868f, 0.001709f, -0.007484f, 0.004448f, -0.00842f, - 0.00427f, -0.00975f, 0.006847f, -0.0071f, 0.0005484f, 0.00909f, -0.004642f, 0.00564f, -0.001863f, - -0.006863f, 0.0087f, -0.003702f, -0.001783f, -0.004032f, 0.003088f, -0.002344f, -0.00323f, -0.00966f, - 0.008286f, 0.006916f, -0.001279f, 0.003246f, 0.00921f, 0.007122f, -0.006985f, 0.0002171f, 0.000837f, - 0.001388f, 0.001075f, -0.008095f, 0.007515f, 0.00999f, 0.00423f, -0.0004835f, -0.009026f, 0.007538f, - 0.00877f, -0.002445f, 0.003437f, 0.00485f, -0.008125f, -0.007767f, 0.00934f, -0.0069f, 0.00804f, - -0.001232f, 0.00959f, -0.007687f, 0.005993f, 0.0006413f, -0.00814f, -0.002447f, -0.001008f, 0.002981f, - 0.001682f, 0.004833f, -0.00382f, -0.0008454f, -0.006485f, 0.00567f, 0.004982f, -0.00484f, 0.00922f, - -0.004585f, 0.00426f, 0.0004027f, 0.0006104f, -0.0063f, -0.00273f, -0.006138f, 0.005367f, -0.004303f, - 0.001937f, -0.003523f, 0.007137f, -0.005737f, -0.00869f, -0.00481f, -0.00816f, 0.0002303f, -0.0002975f, - -0.002365f, 0.00207f, -0.004353f, -0.00924f, 0.00395f, -0.00843f, -0.0043f, -0.0004406f, 0.004807f, - -0.00694f, 0.001308f, -0.000525f, 0.000463f, -0.006813f, 0.00775f, 0.006725f, -0.00984f, -0.0003664f, - 0.009964f, 0.007217f, 0.001767f, -0.004524f, 0.002432f, 0.000869f, -0.005993f, 0.007275f, -0.001423f, - -0.00711f, -0.001464f, 0.007347f, -0.004776f, 0.00513f, -0.00942f, 0.003813f, -0.00489f, -0.00835f, - -0.00711f, -0.002565f, 0.004646f, 0.002693f, 0.000531f, -0.001337f, -0.0008225f, 0.0005493f, -0.003017f, - 0.003242f, -0.00651f, 0.00958f, 0.006573f, -0.00635f, 0.008f, -0.004864f, 0.003464f, -0.007538f, - -0.00917f, -0.002682f, 0.00431f, -0.00604f, 0.002548f, 0.000772f, -0.00769f, -0.002756f, 0.004482f, - 0.001484f, -0.004753f, -0.003052f, 0.0002143f, 0.003023f, 0.002924f, 0.00821f, 0.004673f, 0.003557f, - 0.0092f, -0.00654f, 0.001993f, 0.00835f, -0.008736f, -0.0003886f, -0.00677f, 0.0004423f, -0.00723f, - -0.002926f, 0.00994f, 0.00784f, 0.001214f, 0.00311f, 0.003584f, 0.00856f, 0.001752f, -0.004345f, - -0.003647f, 0.00984f, -0.006798f, 0.001661f, 0.0005393f, 0.0004299f, 0.001711f, -0.006824f, 0.003633f, - 0.00506f, -0.002146f, 0.005653f, -0.00959f, 0.0009027f, -0.009674f, 0.002176f, -0.002815f, -0.007362f, - -0.0002565f, -0.005466f, 0.006443f, 0.00541f, -0.006615f, -0.00668f, 0.0000291f, -0.00249f, -0.00648f, - 0.006466f, 0.005596f, -0.00963f, -0.00289f, -0.007336f, 0.001666f, -0.001227f, 0.008835f, -0.00396f, - -0.001764f, -0.00962f, -0.00461f, 0.00488f, 0.00606f, -0.00959f, 0.005497f, 0.003384f, -0.002548f, - 0.00479f, 0.001423f, -0.004772f, 0.0001752f, 0.00884f, 0.0069f, 0.00792f, -0.001779f, 0.0007215f, - -0.007557f, 0.004314f, -0.006527f, -0.00513f, -0.00855f, -0.00873f, -0.00709f, -0.007538f, -0.002918f, - -0.00867f, 0.000341f, 0.0004723f, 0.007336f, -0.0009327f, -0.005554f, 0.007065f, 0.00586f, -0.003202f, - -0.001984f, -0.007755f, 0.006268f, 0.003624f, 0.001136f, 0.002611f, -0.007374f, -0.00522f, 0.005642f, - 0.003551f, 0.005558f, 0.00512f, -0.001255f, 0.00445f, 0.006657f, -0.003395f, -0.0000211f, -0.00948f, - -0.00525f, 0.007614f, 0.007603f, -0.00872f, 0.00983f, -0.0059f, 0.005405f, -0.005775f, 0.001911f, - -0.006306f, -0.008446f, 0.006702f, 0.001295f, -0.007904f, -0.00613f, -0.00737f, 0.004997f, 0.00699f, - -0.008514f, 0.001029f, 0.008705f, 0.00543f, -0.0097f, -0.00839f, 0.00201f, 0.00319f, -0.00767f, - 0.003147f, -0.00936f, 0.003647f, 0.007465f, 0.00802f, 0.001254f, 0.00955f, 0.006344f, -0.00754f, - 0.007072f, -0.007305f, -0.002403f, -0.006702f, -0.00827f, 0.007183f, -0.001834f, -0.0057f, -0.007095f, - 0.00332f, -0.0008297f, 0.004333f, 0.0008926f, -0.00629f, 0.007393f, 0.006477f, -0.004684f, 0.002182f, - -0.004246f, 0.007324f, 0.001202f, 0.00993f, 0.001759f, -0.001665f, 0.0067f, 0.003798f, -0.007454f, - -0.00821f, 0.001178f, 0.004494f, 0.00384f, 0.003609f, 0.007614f, 0.00976f, -0.00918f, -0.002209f, - 0.002016f, 0.0093f, 0.00638f, -0.007572f, -0.008224f, -0.000771f, -0.00854f, -0.001513f, -0.007267f, - 0.00887f, -0.00107f, -0.007755f, 0.004757f, 0.002693f, 0.00439f, -0.00927f, -0.003588f, 0.001711f, - -0.002756f, 0.00974f, -0.004158f, 0.00621f, 0.00451f, 0.007935f, -0.002064f, -0.0081f, -0.00682f, - 0.006042f, -0.003317f, -0.003391f, -0.00688f, -0.00743f, 0.003933f, -0.00816f, -0.003164f, -0.001821f, - -0.001942f, 0.005005f, 0.00597f, 0.00595f, 0.0086f, 0.003202f, -0.00803f, -0.00892f, -0.002626f, - 0.000533f, -0.002506f, 0.00506f, -0.00822f, -0.000431f, 0.000955f, -0.004826f, -0.006626f, 0.001367f, - 0.00684f, -0.00793f, 0.00634f, -0.004353f, -0.00682f, 0.00657f, 0.000718f, -0.002306f, 0.006966f, - 0.006992f, -0.006275f, 0.00843f, 0.004826f, 0.00886f, -0.004f, 0.00901f, 0.005543f, -0.00566f, - -0.009575f, 0.005444f, 0.00633f, -0.005756f, 0.007687f, 0.001801f, -0.005802f, 0.001708f, -0.004517f, - 0.00808f, 0.00984f, -0.00847f, 0.00959f, -0.002443f, -0.001829f, -0.003305f, -0.00392f, -0.006924f, - -0.002266f, 0.001481f, 0.001099f, -0.00549f, 0.004787f, 0.00784f, -0.008514f, -0.00288f, -0.00858f, - 0.003025f, 0.002846f, 0.001469f, 0.00927f, 0.006443f, -0.00908f, 0.009445f, -0.009636f, -0.0003245f, - 0.003815f, -0.0001975f, 0.0007005f, -0.00984f, 0.0005784f, 0.0006576f, -0.00885f, 0.001424f, -0.004414f, - 0.006252f, 0.002722f, -0.002953f, 0.001995f, 0.00942f, -0.0000668f, -0.007507f, 0.00201f, 0.00344f, - 0.002167f, -0.001902f, -0.00691f, 0.00427f, -0.006607f, -0.003334f, -0.00143f, -0.00676f, 0.00736f, - 0.005222f, -0.0004745f, -0.0005236f, -0.00818f, 0.004253f, -0.002077f, 0.007355f, -0.00157f, -0.004112f, - -0.007156f, 0.002766f, -0.001808f, -0.003685f, 0.002918f, 0.005814f, 0.00126f, 0.00001913f, -0.0002122f, - 0.00882f, -0.001593f, 0.005184f, -0.006516f, 0.00848f, 0.00835f, -0.0006256f, 0.00252f, -0.00594f, - 0.005688f, -0.0089f, 0.000832f, 0.00922f, 0.002317f, -0.003725f, -0.005905f, 0.001728f, 0.002249f, - -0.00986f, 0.008896f, -0.0001637f, 0.006817f, -0.0092f, 0.008484f, -0.00751f, -0.002232f, 0.007233f, - 0.001008f, 0.003746f, -0.005726f, 0.006203f, 0.000586f, 0.00568f, 0.000979f, -0.00249f, -0.004295f, - -0.005775f, 0.0093f, -0.002306f, 0.002426f, -0.00712f, 0.004265f, 0.00659f, -0.00504f, -0.002317f, - 0.003494f, -0.005882f, 0.00602f, 0.001864f, -0.008255f, 0.00559f, -0.001576f, -0.004242f, -0.005627f, - 0.00521f, 0.003729f, -0.005524f, -0.005688f, 0.00695f, -0.00475f, -0.0001157f, -0.007744f, -0.007935f, - 0.006092f, -0.007626f, 0.002676f, -0.00196f, -0.00932f, -0.001797f, -0.0081f, -0.004524f, 0.002777f, - -0.0007696f, -0.0008817f, -0.00864f, 0.00834f, -0.001039f, -0.00899f, -0.007412f, -0.002197f, 0.003298f, - 0.00258f, 0.00667f, 0.001576f, -0.002626f, -0.001692f, -0.00107f, -0.001912f, -0.00997f, -0.005493f, - -0.0098f, -0.001864f, 0.001933f, 0.005116f, -0.00938f, -0.0002704f, 0.0001253f, -0.00465f, -0.00414f, - 0.001244f, 0.002434f, -0.003223f, 0.007835f, 0.004036f, 0.00748f, -0.00903f, 0.004265f, -0.002977f, - 0.00732f, 0.006317f, -0.00563f, -0.008224f, -0.00867f, 0.00962f, -0.005325f, 0.00101f, -0.00856f, - 0.00735f, -0.00862f, -0.003899f, -0.004925f, 0.0069f, 0.004513f, -0.009895f, -0.00239f, 0.00992f, - -0.00149f, 0.001915f, -0.002604f, 0.0095f, 0.007416f, 0.005016f, -0.002281f, 0.008125f, -0.009476f, - -0.009056f, 0.003843f, -0.002602f, 0.0089f, 0.003674f, 0.00132f, -0.00627f, 0.009186f, 0.006226f, - -0.00442f, 0.003323f, -0.00282f, 0.00831f, 0.007153f, -0.00724f, -0.002815f, -0.0001028f, 0.00809f, - 0.00871f, -0.007435f, -0.0018835f, 0.002344f, 0.00975f, -0.00286f, -0.00835f, -0.003582f, -0.000401f, - 0.007904f, -0.00499f, 0.003502f, -0.009605f, 0.00367f, -0.007473f, -0.003994f, -0.002377f, 0.00413f, - 0.000489f, 0.005356f, 0.00786f, 0.00476f, -0.005436f, 0.005947f, -0.000724f, -0.00671f, 0.00569f, - -0.00826f, 0.00846f, -0.006634f, -0.003334f, -0.00802f, -0.007126f, -0.001247f, 0.00596f, -0.009056f, - 0.0005774f, -0.00648f, 0.006126f, -0.00668f, -0.004116f, -0.0002975f, 0.0002549f, -0.006977f, 0.002117f, - 0.0007377f, -0.00803f, -0.003365f, 0.00819f, -0.002949f, -0.00969f, 0.006794f, -0.007645f, -0.00099f, - 0.006966f, 0.009735f, 0.002426f, 0.005592f, 0.0003273f, -0.003353f, -0.002249f, -0.00514f, -0.002508f, - -0.008156f, -0.000979f, 0.0002344f, -0.006508f, 0.00781f, 0.001318f, -0.00498f, 0.00858f, -0.003828f, - -0.00504f, 0.00639f, -0.002424f, 0.002552f, 0.003736f, -0.00797f, 0.00761f, 0.006474f, 0.004166f, - -0.009026f, 0.00638f, 0.0097f, -0.007202f, -0.008224f, -0.005714f, 0.001017f, 0.004894f, -0.00898f, - 0.00874f, -0.004066f, -0.002527f, 0.000754f, -0.002802f, 0.009315f, -0.00817f, -0.008705f, -0.0006857f, - 0.006992f, 0.000913f, 0.005993f, 0.005013f, 0.009346f, -0.00574f, 0.008575f, 0.004166f, -0.00604f, - -0.0032f, 0.0014925f, 0.008865f, -0.006435f, -0.004417f, 0.000921f, 0.00928f, -0.001739f, 0.000586f, - 0.007904f, 0.007347f, 0.00331f, -0.0078f, -0.004005f, 0.0074f, -0.005825f, -0.007244f, -0.002626f, - -0.005917f, 0.006508f, 0.007263f, -0.001506f, -0.003498f, 0.00693f, 0.004097f, 0.00934f, -0.003752f, - -0.006752f, 0.001534f, 0.003906f, 0.001351f, 0.00367f, 0.0086f, -0.00536f, -0.001699f, 0.001546f, - -0.00277f, -0.0005455f, -0.002718f, -0.00583f, -0.0009003f, -0.001003f, 0.001612f, -0.003557f, -0.006004f, - 0.001006f, -0.00925f, -0.0008187f, -0.002907f, 0.003675f, 0.00394f, 0.005608f, -0.007133f, 0.001691f, - 0.006428f, 0.003813f, -0.00542f, -0.00583f, 0.002207f, -0.001088f, 0.00714f, 0.006233f, 0.002617f, - -0.00419f, -0.00916f, 0.004063f, -0.002892f, 0.000514f, 0.00224f, 0.0001853f, 0.0007997f, 0.0005536f, - -0.00639f, -0.007015f, 0.00309f, 0.006184f, -0.00982f, -0.0002372f, 0.0009604f, 0.00962f, 0.00678f, - -0.006653f, -0.004955f, -0.0003958f, 0.006428f, 0.004517f, 0.00672f, 0.003792f, -0.006046f, -0.00221f, - -0.00727f, -0.00748f, -0.004204f, -0.00982f, 0.0007663f, 0.00661f, -0.003647f, -0.006973f, 0.002605f, - 0.0001023f, 0.004536f, -0.00647f, 0.009735f, 0.00945f, -0.00967f, -0.0003023f, -0.0086f, 0.008736f, - -0.00701f, 0.00258f, -0.002716f, -0.00162f, -0.006996f, 0.007664f, 0.007595f, 0.00403f, 0.00233f, - -0.00481f, -0.001349f, -0.005196f, -0.009026f, 0.00606f, 0.001146f, 0.001434f, 0.00967f, 0.004448f, - -0.004837f, -0.007168f, -0.005234f, 0.002514f, 0.005306f, 0.003088f, 0.0018215f, -0.00558f, -0.006596f, - 0.002018f, -0.003408f, -0.001384f, -0.006065f, -0.001212f, -0.002604f, -0.00767f, 0.0001342f, -0.00851f, - -0.00392f, 0.003862f, 0.00701f, 0.003605f, -0.00965f, -0.00714f, 0.00956f, -0.00888f, -0.001019f, - 0.0024f, -0.00961f, -0.005238f, 0.005333f, 0.00871f, 0.007607f, -0.00756f, -0.004772f, -0.00912f, - -0.004047f, 0.003483f, 0.003294f, 0.006577f, -0.005505f, 0.00996f, 0.009964f, 0.0004187f, 0.005898f, - 0.00796f, -0.00165f, -0.003225f, -0.001258f, 0.00853f, -0.008865f, 0.00815f, -0.001117f, -0.00685f, - 0.001974f, 0.00915f, 0.00667f, 0.009605f, 0.007107f, 0.007698f, -0.004387f, -0.0003958f, -0.005062f, - 0.002188f, -0.004875f, -0.002922f, -0.0003638f, 0.006268f, 0.00785f, 0.006138f, 0.000505f, -0.0003953f, - -0.00841f, -0.00958f, -0.007126f, -0.003107f, 0.0078f, 0.003452f, -0.009254f, -0.00117f, -0.00878f, - -0.00911f, -0.0004418f, 0.00831f, -0.004524f, 0.003872f, 0.0044f, 0.006424f, 0.000634f, -0.004883f, - -0.002487f, -0.00512f, -0.00692f, -0.00521f, -0.001761f, 0.008575f, -0.006393f, 0.00351f, 0.00914f, - -0.006035f, -0.002264f, -0.009636f, 0.00918f, -0.00967f, -0.004944f, -0.0004587f, -0.002478f, -0.00814f, - 0.00816f, -0.004776f, 0.00954f, 0.003471f, -0.006172f, 0.003603f, 0.009346f, 0.00455f, 0.00982f, - 0.00476f, 0.0007815f, -0.003096f, -0.0000307f, -0.005608f, 0.009315f, 0.00374f, -0.007366f, -0.001133f, - -0.00944f, 0.006847f, 0.00631f, 0.005394f, 0.003088f, -0.00644f, -0.0004168f, -0.00923f, -0.003254f, - -0.005077f, 0.00637f, -0.001415f, -0.003235f, -0.001729f, -0.0082f, 0.006664f, -0.006f, 0.00663f, - -0.001547f, -0.004116f, -0.00542f, 0.00521f, -0.00286f, -0.00396f, 0.004547f, -0.0001363f, 0.000979f, - -0.00634f, -0.006767f, -0.0000603f, 0.008316f, 0.00756f, -0.004993f, -0.00645f, -0.002295f, 0.004288f, - 0.00901f, 0.008194f, -0.004192f, -0.002182f, -0.005836f, -0.003983f, -0.007183f, -0.0061f, 0.001098f, - -0.0009274f, 0.005207f, 0.0002102f, -0.003925f, 0.0056f, -0.00296f, 0.006134f, -0.007744f, 0.006126f, - -0.005047f, -0.006134f, 0.004818f, -0.005283f, 0.005272f, -0.00779f, -0.003086f, -0.000607f, 0.005486f, - 0.0005345f, -0.007305f, -0.0048f, -0.00876f, -0.00433f, 0.006165f, -0.002474f, -0.00953f, -0.002066f, - 0.002918f, 0.006382f, 0.003317f, 0.00826f, -0.009995f, 0.004143f, 0.00985f, -0.0002116f, -0.002989f, - -0.007805f, 0.0003633f, -0.00365f, -0.00916f, 0.009834f, 0.003513f, -0.00379f, 0.00736f, -0.00957f, - 0.005726f, -0.00772f, -0.00803f, -0.002052f, -0.005585f, -0.00781f, -0.00599f, 0.00954f, 0.002024f, - -0.005745f, 0.003054f, -0.009415f, -0.005054f, 0.00424f, 0.003218f, 0.00826f, 0.00817f, -0.00409f, - 0.00518f, 0.00216f, 0.006756f, -0.00411f, -0.003344f, -0.004898f, 0.00001055f, 0.006104f, 0.001057f, - -0.000702f, 0.00771f, -0.001743f, 0.001407f, -0.005104f, -0.007717f, -0.002026f, -0.006405f, 0.00886f, - 0.0006466f, -0.00951f, -0.00395f, -0.00814f, 0.00936f, 0.001143f, -0.00485f, 0.00584f, -0.002224f, - 0.00834f, -0.0003467f, -0.000945f, 0.007034f, -0.0009427f, -0.009445f, 0.0007753f, -0.006973f, 0.001507f, - 0.004105f, -0.002523f, 0.002872f, -0.001515f, -0.00869f, 0.003103f, 0.000389f, -0.00774f, 0.00441f, - -0.001002f, 0.00783f, -0.001102f, -0.003883f, -0.007187f, -0.0001678f, -0.00742f, -0.00686f, -0.006702f, - 0.00894f, -0.0003886f, -0.005543f, 0.00988f, 0.00411f, -0.00002635f, 0.00851f, -0.002317f, 0.00873f, - -0.00532f, -0.000835f, -0.004166f, -0.004036f, -0.003325f, -0.00799f, 0.003025f, 0.001356f, -0.009575f, - -0.00426f, -0.003431f, 0.00899f, -0.001455f, -0.0007324f, -0.00492f, 0.00989f, -0.0002503f, -0.00814f, - -0.00535f, -0.0035f, -0.001434f, 0.00635f, -0.005108f, 0.002626f, 0.00983f, 0.00672f, -0.00725f, - -0.004826f, 0.007275f, -0.006763f, 0.002605f, 0.002369f, -0.000976f, 0.00263f, 0.00465f, -0.009544f, - -0.0008945f, -0.00175f, -0.00799f, -0.0006666f, -0.00514f, -0.002842f, -0.001805f, 0.000992f, 0.00844f, - -0.000964f, -0.00636f, 0.001281f, 0.001717f, 0.00569f, 0.005917f, -0.00826f, -0.00859f, 0.004246f, - 0.004078f, -0.005566f, 0.00835f, -0.006893f, -0.005867f, 0.001273f, -0.005856f, 0.004448f, 0.004562f, - -0.00392f, -0.00855f, 0.0005975f, 0.006817f, -0.005524f, -0.0009527f, -0.00695f, -0.002172f, -0.003683f, - -0.00546f, 0.007698f, -0.00858f, 0.003372f, 0.001414f, -0.007786f, -0.00482f, 0.0083f, 0.007534f, - 0.00554f, 0.005768f, 0.001982f, -0.004597f, -0.001634f, 0.000563f, 0.00298f, 0.001768f, 0.0004673f, - 0.009285f, 0.00518f, 0.00798f, 0.00557f, -0.002504f, -0.00777f, 0.007904f, 0.00939f, -0.004646f, - 0.00527f, 0.00817f, 0.00526f, 0.007935f, -0.00413f, -0.002628f, -0.008194f, -0.006195f, 0.00884f, - 0.007282f, 0.003819f, -0.00904f, 0.001354f, -0.004368f, -0.0002527f, 0.004684f, -0.002907f, -0.003862f, - -0.002197f, 0.00858f, -0.00989f, 0.0004277f, 0.008484f, -0.008865f, 0.007275f, 0.00869f, -0.0000226f, - 0.0006456f, 0.0002527f, 0.003267f, 0.007793f, -0.001359f, -0.007423f, -0.004204f, 0.006824f, -0.00801f, - 0.006992f, -0.002182f, 0.00181f, 0.00966f, -0.00888f, -0.006527f, -0.00873f, -0.004623f, -0.006767f, - -0.006317f, 0.003017f, 0.002218f, 0.00805f, -0.00677f, -0.00974f, -0.0083f, 0.008095f, -0.00424f, - -0.009636f, 0.002298f, -0.00864f, 0.004044f, 0.000354f, 0.00949f, 0.00635f, 0.009026f, -0.00806f, - -0.0008893f, 0.002377f, -0.001343f, -0.001965f, -0.00442f, -0.006615f, -0.004166f, 0.00719f, -0.006306f, - -0.009674f, -0.00787f, 0.00712f, -0.003637f, 0.0008287f, 0.005352f, -0.004227f, -0.00549f, -0.0058f, - 0.00489f, -0.005165f, 0.001942f, 0.00591f, 0.00612f, 0.005306f, -0.00723f, 0.0051f, 0.002329f, - -0.001097f, 0.002022f, -0.006416f, -0.006577f, 0.003603f, 0.004303f, 0.007652f, 0.00884f, -0.003191f, - 0.002787f, -0.009254f, 0.003475f, -0.002266f, 0.00936f, -0.00793f, -0.00738f, 0.008194f, 0.003998f, - -0.0049f, 0.008965f, -0.000592f, 0.00711f, 0.00905f, -0.0006223f, -0.00735f, -0.00399f, -0.00808f, - -0.005367f, 0.00705f, 0.0007415f, 0.00864f, 0.00883f, -0.001155f, 0.00898f, 0.004406f, 0.00967f, - 0.004677f, -0.003113f, -0.0009146f, 0.00756f, 0.005733f, -0.003647f, 0.00446f, 0.00798f, 0.003305f, - -0.0000515f, -0.003746f, -0.002283f, -0.004913f, 0.003496f, -0.00773f, -0.003622f, 0.004974f, 0.00244f, - 0.001445f, -0.004826f, 0.002394f, 0.003075f, -0.0006714f, 0.002077f, -0.008675f, -0.001683f, 0.006065f, - -0.005512f, -0.001691f, 0.007507f, -0.00913f, -0.0008674f, -0.005f, 0.001398f, -0.004875f, -0.000567f, - -0.002668f, 0.001711f, -0.005306f, -0.00883f, -0.001738f, 0.0035f, -0.006702f, -0.006943f, 0.00884f, - -0.001516f, 0.00991f, 0.003082f, 0.006077f, -0.00437f, -0.000524f, -0.003986f, 0.007393f, 0.00986f, - -0.0008f, -0.001425f, -0.001999f, -0.002277f, -0.00901f, 0.004986f, 0.002085f, -0.0009236f, 0.001841f, - -0.003191f, 0.002205f, -0.00781f, 0.00397f, -0.002066f, -0.008835f, -0.004585f, -0.00953f, -0.006496f, - -0.006996f, 0.007233f, -0.00544f, 0.001037f, 0.0028f, -0.007935f, -0.0055f, -0.007866f, 0.00436f, - -0.0009565f, 0.001419f, 0.007587f, -0.0004418f, -0.00318f, -0.003857f, 0.007763f, 0.008896f, 0.004925f, - 0.00979f, -0.00928f, -0.001149f, 0.00678f, -0.002733f, -0.002972f, -0.001726f, 0.006706f, -0.001256f, - -0.00636f, 0.0004964f, 0.0005093f, -0.0008807f, 0.002026f, 0.00215f, -0.007603f, -0.00936f, -0.001715f, - -0.000935f, 0.0005236f, 0.000975f, 0.00786f, -0.002583f, 0.003407f, -0.002033f, -0.00217f, 0.001398f, - -0.0001027f, 0.0009203f, 0.0009117f, 0.00741f, -0.003925f, 0.0007577f, -0.006317f, 0.001241f, 0.005623f, - 0.001732f, 0.00374f, 0.00341f, 0.006714f, 0.001987f, -0.0037f, 0.00349f, -0.00431f, -0.00895f, - -0.009605f, -0.007214f, -0.00393f, -0.002583f, 0.00841f, 0.00782f, -0.005657f, -0.00655f, 0.003542f, - -0.004143f, 0.003202f, -0.002695f, 0.0002656f, 0.001797f, -0.0065f, 0.00628f, -0.0001239f, -0.002842f, - 0.00119f, -0.00979f, 0.006287f, -0.00646f, 0.00769f, 0.00831f, -0.0055f, 0.0005436f, 0.006554f, - -0.0001364f, 0.00699f, 0.004364f, -0.00227f, 0.00489f, 0.0026f, 0.0007696f, 0.0004685f, -0.001103f, - 0.001123f, -0.002245f, 0.006527f, -0.00828f, -0.002954f, -0.005226f, -0.005814f, -0.0002468f, -0.00884f, - 0.008606f, -0.00001067f, -0.00417f, -0.003376f, 0.00918f, -0.00776f, 0.002684f, 0.006145f, -0.0006285f, - -0.004173f, -0.004917f, -0.00678f, 0.00248f, 0.007263f, 0.002188f, -0.000213f, 0.00413f, 0.002676f, - 0.004948f, 0.007614f, -0.001845f, -0.00436f, 0.00591f, 0.004833f, -0.002085f, -0.006096f, 0.007378f, - 0.001922f, 0.006573f, 0.0016985f, 0.001776f, 0.00993f, -0.00829f, -0.0001675f, 0.004753f, 0.00008494f, - 0.00989f, 0.0008593f, 0.00636f, 0.0008297f, -0.00482f, -0.001189f, -0.001576f, -0.001331f, -0.00881f, - 0.00416f, -0.0008516f, -0.002281f, -0.00399f, -0.00603f, 0.0031f, 0.00994f, 0.0009284f, -0.00446f, - -0.00944f, 0.00272f, -0.001006f, -0.006733f, 0.00815f, 0.004932f, -0.004894f, 0.007156f, 0.0001193f, - -0.00745f, -0.000041f, -0.004074f, 0.00829f, 0.006042f, 0.006176f, -0.00509f, 0.005375f, -0.00554f, - -0.001078f, -0.002928f, 0.00813f, 0.004013f, 0.002552f, -0.0086f, 0.000254f, -0.005844f, 0.004093f, - -0.008224f, 0.006016f, -0.004883f, -0.006504f, 0.0003617f, -0.00008327f, 0.00382f, 0.00786f, -0.00915f, - -0.004963f, 0.003756f, 0.00689f, 0.00833f, 0.005455f, -0.00871f, -0.00872f, -0.0008054f, 0.001023f, - -0.003527f, -0.00735f, 0.00691f, 0.0092f, 0.004837f, -0.000847f, 0.0006146f, -0.00829f, 0.007317f, - -0.002722f, 0.005962f, -0.004005f, 0.002857f, 0.004414f, 0.00437f, -0.003452f, -0.004383f, -0.004654f, - 0.007866f, -0.000736f, -0.001158f, -0.005924f, -0.002207f, 0.00904f, 0.004505f, 0.005688f, 0.003448f, - -0.00414f, -0.00986f, -0.007446f, 0.00479f, 0.00314f, 0.0084f, 0.005714f, -0.002865f, 0.0008903f, - -0.00831f, 0.009415f, -0.001098f, 0.0007825f, -0.002136f, -0.009995f, 0.00798f, -0.0002449f, -0.00454f, - 0.00262f, -0.001926f, 0.003874f, -0.001987f, 0.00456f, 0.00994f, -0.00275f, -0.0013485f, 0.00911f, - -0.0011f, -0.005253f, 0.003504f, 0.004726f, -0.00821f, 0.00008196f, 0.004696f, 0.00473f, 0.006893f, - -0.002386f, 0.007145f, 0.007584f, -0.00542f, -0.000596f, 0.002354f, 0.001427f, 0.001673f, 0.004646f, - 0.004826f, 0.00847f, -0.005226f, 0.0003307f, 0.00536f, 0.002802f, 0.006264f, -0.000479f, 0.00222f, - 0.00817f, 0.005253f, 0.005257f, 0.001163f, 0.005417f, 0.006603f, 0.00514f, -0.003473f, -0.001948f, - 0.006695f, 0.003492f, 0.000456f, 0.00933f, 0.00283f, 0.006935f, -0.004658f, -0.0008807f, -0.001274f, - -0.0006485f, -0.00349f, -0.002163f, 0.00811f, 0.001358f, -0.002134f, 0.0005803f, -0.001573f, -0.005478f, - -0.00496f, 0.00968f, 0.001645f, -0.005756f, -0.0008974f, -0.00608f, -0.00528f, 0.00005585f, -0.005756f, - -0.004025f, -0.00772f, -0.0008974f, 0.00786f, 0.00396f, -0.008865f, -0.00645f, -0.00903f, 0.00802f, - -0.001602f, -0.0072f, 0.00736f, 0.002499f, -0.00839f, -0.00925f, 0.005943f, -0.00785f, -0.0081f, - -0.00802f, -0.005554f, 0.004078f, 0.009476f, -0.00877f, 0.00257f, -0.00439f, 0.006744f, -0.00419f, - -0.005413f, 0.002476f, -0.002373f, -0.006424f, 0.008736f, 0.006977f, 0.009735f, 0.009514f, 0.0009437f, - -0.001418f, 0.004066f, 0.004986f, -0.008644f, -0.007427f, -0.00988f, 0.006714f, -0.00118f, 0.00924f, - 0.000984f, 0.001846f, -0.00418f, 0.00341f, 0.0007763f, 0.008545f, 0.007313f, 0.00999f, -0.000682f, - 0.003416f, 0.00465f, -0.000676f, 0.00206f, -0.00654f, -0.002478f, 0.003826f, -0.001733f, -0.003693f, - -0.001044f, -0.004696f, 0.00688f, 0.00632f, 0.004963f, -0.00365f, -0.00772f, -0.001813f, -0.004898f, - -0.008385f, 0.002f, -0.007782f, -0.000961f, -0.003376f, 0.005157f, -0.002651f, 0.007935f, 0.003716f, - 0.009f, 0.001195f, -0.00982f, -0.00532f, -0.00828f, -0.000279f, -0.007626f, 0.00879f, 0.006996f, - 0.00942f, 0.002588f, -0.0097f, -0.00011635f, -0.001595f, -0.0006347f, -0.001799f, 0.00126f, 0.005085f, - 0.001865f, 0.003216f, -0.000628f, -0.00474f, -0.004925f, -0.00626f, 0.006287f, -0.005054f, 0.0079f, - -0.005177f, -0.009796f, -0.00805f, -0.001599f, 0.0085f, -0.008965f, -0.002886f, -0.008606f, -0.008965f, - 0.004757f, -0.009285f, 0.00548f, 0.00816f, -0.001941f, 0.00622f, 0.00755f, 0.00926f, 0.009125f, - -0.004364f, 0.006214f, -0.007137f, 0.001763f, -0.002035f, 0.004326f, 0.00653f, -0.007072f, -0.003609f, - -0.00504f, 0.004448f, -0.005928f, -0.007057f, -0.002148f, -0.004593f, -0.004467f, -0.009514f, -0.00854f, - 0.001922f, 0.007572f, -0.005016f, 0.003345f, 0.008575f, -0.00967f, 0.000532f, -0.002897f, -0.005013f, - -0.009834f, 0.00302f, 0.005688f, 0.005096f, -0.003983f, 0.00851f, 0.001554f, 0.00394f, 0.005688f, - -0.00537f, 0.00655f, 0.007526f, 0.002298f, 0.006126f, -0.00654f, -0.003433f, -0.00818f, -0.003098f, - -0.00822f, -0.00898f, -0.007675f, 0.005955f, -0.003288f, 0.006237f, -0.002f, 0.002678f, -0.00639f, - 0.00899f, 0.009766f, 0.009384f, -0.0001253f, 0.007263f, -0.003555f, -0.00988f, -0.00534f, -0.005356f, - -0.00805f, 0.001697f, 0.002516f, 0.0022f, 0.007397f, -0.002075f, 0.00247f, 0.004593f, -0.00543f, - 0.000358f, -0.005047f, 0.00476f, -0.003937f, -0.002851f, 0.007507f, 0.001389f, 0.003235f, 0.00205f, - -0.00474f, -0.0059f, 0.001666f, 0.002943f, -0.00954f, -0.00828f, -0.008804f, 0.002356f, 0.00836f, - 0.002785f, 0.00881f, -0.00716f, 0.005608f, 0.007534f, -0.00952f, 0.008965f, 0.0001839f, -0.007412f, - 0.00693f, -0.0000717f, 0.003857f, 0.00021f, 0.002897f, -0.00452f, -0.002552f, -0.005962f, -0.006737f, - -0.0008616f, 0.008606f, -0.005814f, -0.007397f, -0.006096f, 0.0099f, -0.00955f, 0.001134f, 0.00702f, - -0.0003154f, 0.00366f, -0.009186f, -0.001096f, 0.00984f, -0.005787f, 0.00369f, -0.001496f, 0.002462f, - -0.00623f, -0.00426f, -0.004837f, -0.00558f, -0.003311f, -0.0066f, 0.0077f, 0.003609f, 0.004646f, - 0.007996f, -0.00788f, 0.006348f, -0.00986f, 0.00817f, 0.0001633f, 0.0001796f, -0.00899f, -0.001417f, - 0.00972f, -0.00067f, -0.005535f, 0.001376f, 0.004974f, 0.0008225f, 0.008484f, -0.00589f, 0.00828f, - -0.007206f, -0.00599f, -0.0009503f, 0.000634f, -0.0001874f, -0.00654f, 0.00424f, -0.001244f, 0.002506f, - -0.009964f, -0.00828f, -0.002129f, -0.003368f, -0.0003746f, -0.006798f, -0.00383f, 0.008514f, 0.00818f, - -0.005497f, -0.0034f, -0.001681f, -0.004208f, -0.004337f, -0.0000664f, 0.003807f, -0.006073f, -0.003489f, - -0.00521f, 0.005047f, 0.00367f, 0.005657f, -0.004665f, 0.00671f, -0.003513f, 0.00869f, 0.008095f, - 0.007545f, 0.007214f, 0.002594f, -0.001637f, 0.005642f, 0.00526f, -0.007195f, 0.00413f, -0.006878f, - 0.009224f, 0.008514f, -0.0008245f, -0.004276f, 0.003633f, -0.000534f, -0.00916f, -0.00905f, 0.00827f, - 0.00458f, 0.002428f, -0.002975f, 0.00718f, -0.00888f, 0.004597f, 0.0004854f, -0.003778f, 0.006023f, - 0.001024f, -0.00484f, -0.0048f, 0.001374f, -0.004204f, -0.004368f, 0.005783f, 0.001205f, 0.007774f, - -0.001196f, -0.007015f, 0.00822f, -0.005875f, 0.003675f, 0.00279f, 0.001947f, -0.00342f, -0.000307f, - -0.003113f, -0.0017185f, -0.001276f, 0.0031f, -0.003546f, -0.003328f, 0.004078f, 0.00976f, -0.002756f, - 0.00487f, -0.007904f, 0.003613f, 0.007034f, -0.00624f, 0.0007896f, -0.0077f, -0.001974f, 0.007397f, - 0.005966f, -0.00627f, -0.005215f, 0.001178f, -0.00372f, 0.001711f, -0.001743f, 0.00248f, 0.0003877f, - 0.005028f, -0.00789f, -0.0007873f, -0.005753f, 0.00961f, 0.00961f, 0.002813f, 0.002567f, -0.007095f, - 0.003628f, 0.0001531f, 0.0002968f, -0.005493f, -0.0001053f, 0.00964f, 0.004997f, -0.00657f, 0.000724f, - -0.00563f, -0.009834f, -0.003574f, 0.003572f, -0.006805f, 0.007423f, 0.003103f, -0.005455f, 0.00881f, - -0.00777f, -0.003508f, 0.0075f, 0.00404f, -0.00747f, 0.003056f, 0.005142f, -0.007156f, -0.00923f, - 0.00401f, 0.007442f, 0.005077f, 0.007393f, 0.004276f, -0.00851f, -0.00263f, -0.006123f, 0.003536f, - 0.005672f, 0.00887f, -0.002031f, -0.00524f, -0.001232f, 0.000433f, 0.005398f, 0.009575f, 0.009705f, - -0.007267f, -0.00565f, -0.003963f, 0.007477f, -0.00216f, -0.007744f, -0.003347f, -0.00804f, -0.002136f, - -0.002407f, 0.00826f, -0.006294f, 0.005116f, 0.00007975f, -0.007267f, -0.003428f, -0.005497f, 0.001562f, - 0.003801f, -0.004646f, 0.004234f, 0.00979f, 0.00943f, -0.002726f, 0.0007277f, 0.0007143f, -0.00785f, - 0.00531f, 0.00747f, -0.006287f, 0.0001854f, 0.0005198f, -0.006645f, -0.000202f, -0.0004883f, -0.001946f, - 0.00904f, 0.00122f, 0.005608f, 0.002243f, -0.001732f, -0.00844f, -0.000973f, 0.00898f, 0.00686f, - 0.005028f, 0.005497f, -0.002182f, -0.007122f, 0.00955f, 0.00725f, 0.0000116f, 0.00504f, 0.00864f, - -0.00827f, -0.00476f, -0.001607f, 0.006145f, 0.00777f, 0.00974f, -0.002163f, 0.00857f, 0.006485f, - -0.004356f, 0.00010043f, 0.001632f, 0.005432f, 0.00846f, -0.006756f, 0.0005136f, -0.00836f, -0.009544f, - 0.005016f, -0.002354f, -0.004543f, 0.00419f, 0.00798f, -0.001813f, 0.005913f, 0.003494f, -0.002695f, - -0.009346f, -0.001584f, -0.00886f, -0.007374f, 0.00979f, 0.00961f, 0.0006576f, -0.0018015f, -0.009766f, - -0.00821f, -0.00924f, 0.0002823f, 0.003115f, -0.00788f, -0.005257f, 0.003233f, -0.00939f, 0.00617f, - 0.003914f, -0.002165f, 0.004215f, 0.00603f, 0.00498f, -0.000754f, 0.0079f, 0.00463f, -0.004574f, - -0.00494f, 0.0014715f, 0.007866f, 0.005215f, -0.00008845f, 0.00897f, -0.00431f, -0.00416f, 0.001195f, - -0.007626f, 0.006153f, 0.000168f, -0.001373f, 0.001575f, -0.00368f, -0.00926f, 0.003387f, -0.006237f, - -0.003305f, -0.004677f, 0.003044f, 0.002283f, -0.00855f, -0.00383f, 0.005135f, -0.003328f, -0.005f, - -0.006145f, 0.008995f, 0.00933f, -0.0004253f, -0.00697f, -0.00895f, 0.001212f, 0.007114f, 0.005264f, - 0.003008f, -0.0087f, 0.00578f, -0.008354f, 0.009056f, 0.004955f, -0.004787f, 0.001999f, -0.008705f, - -0.00722f, -0.00211f, 0.00471f, -0.0012245f, -0.0003836f, -0.00119f, -0.005363f, -0.00464f, -0.00628f, - -0.00855f, -0.000797f, 0.005047f, 0.0006003f, 0.002134f, 0.001738f, 0.006653f, -0.003204f, 0.00568f, - -0.0003297f, 0.0001493f, -0.00001603f, -0.001742f, -0.0004888f, -0.002066f, -0.003843f, 0.008514f, 0.001038f, - -0.006084f, 0.002298f, -0.00506f, 0.0028f, -0.00588f, 0.006187f, -0.004707f, 0.00482f, -0.005604f, - 0.0099f, 0.002226f, -0.00418f, -0.00867f, -0.001959f, 0.006733f, 0.00881f, -0.009636f, 0.006523f, - 0.00918f, -0.005287f, -0.00939f, 0.007725f, 0.002266f, -0.00813f, 0.00945f, -0.009735f, 0.00804f, - -0.00447f, -0.0006757f, -0.002113f, 0.0071f, -0.002256f, -0.001572f, -0.002722f, -0.005325f, 0.005184f, - 0.001163f, 0.00785f, -0.00908f, 0.000957f, -0.004894f, -0.00785f, 0.004192f, 0.005585f, -0.00466f, - 0.00659f, -0.009026f, 0.00393f, -0.00526f, -0.00882f, -0.006893f, -0.008286f, -0.000591f, -0.00449f, - -0.00882f, 0.004025f, -0.00812f, 0.002306f, 0.003397f, 0.0002433f, -0.00333f, 0.000728f, -0.001259f, - -0.0006423f, 0.00922f, 0.002346f, -0.00682f, -0.002346f, -0.00688f, 0.0004377f, 0.0007114f, -0.00878f, - 0.00824f, -0.007797f, 0.00000536f, 0.00009096f, 0.00981f, -0.001997f, -0.006676f, -0.006683f, -0.00412f, - 0.00085f, 0.004017f, 0.00645f, -0.00674f, 0.00846f, -0.00847f, -0.00199f, 0.003153f, -0.0002362f, - -0.0004025f, 0.007996f, 0.002476f, 0.00555f, 0.003628f, -0.00508f, 0.00728f, -0.00266f, 0.003223f, - -0.007328f, -0.00689f, -0.00229f, -0.001114f, 0.002768f, -0.001708f, 0.003847f, -0.007248f, -0.00689f, - -0.007065f, -0.00772f, 0.005745f, 0.008804f, 0.006092f, 0.005795f, 0.001585f, 0.005386f, -0.005962f, - -0.0004244f, 0.008804f, 0.003803f, 0.000961f, 0.00976f, 0.0005674f, 0.00905f, 0.00982f, 0.005295f, - -0.00009507f, 0.005775f, -0.002659f, -0.001253f, -0.006416f, 0.008194f, 0.00945f, 0.006752f, -0.00935f, - 0.003845f, -0.006237f, 0.00415f, 0.008095f, -0.00645f, -0.009865f, 0.000944f, 0.00811f, 0.00841f, - 0.0002704f, -0.00681f, 0.00514f, -0.005535f, -0.00543f, -0.007355f, 0.006424f, -0.0012665f, -0.007423f, - 0.00501f, 0.0071f, -0.0001485f, -0.004772f, -0.007965f, -0.002703f, 0.00977f, -0.0002038f, 0.00664f, - 0.002275f, 0.004887f, 0.00762f, 0.001178f, 0.001114f, -0.000678f, -0.001807f, -0.004963f, 0.001163f, - 0.00273f, -0.00955f, 0.002756f, 0.0005674f, -0.00551f, -0.00862f, -0.009026f, 0.00948f, -0.00195f, - -0.001241f, 0.00402f, 0.002943f, 0.0001924f, 0.001133f, -0.004086f, 0.002512f, -0.0058f, 0.00159f, - -0.00808f, 0.00575f, -0.00857f, -0.00701f, 0.009544f, -0.001974f, 0.002966f, -0.004898f, -0.001783f, - 0.003128f, -0.005596f, -0.00751f, -0.004704f, 0.00719f, -0.00949f, -0.001564f, 0.003157f, 0.005245f, - -0.00424f, 0.004654f, -0.00425f, -0.008766f, 0.00912f, -0.005386f, 0.00439f, -0.002386f, 0.00576f, - 0.003857f, -0.007004f, 0.0005574f, 0.006065f, -0.0068f, 0.00985f, -0.0003872f, -0.004654f, 0.008675f, - 0.00801f, 0.001015f, 0.0019045f, 0.007225f, 0.0004132f, -0.005173f, 0.001682f, -0.002037f, -0.003492f, - 0.003092f, 0.00231f, 0.007294f, 0.002605f, -0.00941f, -0.004112f, 0.0082f, 0.002506f, -0.00819f, - -0.0041f, 0.009476f, 0.003584f, -0.00585f, 0.00462f, -0.006348f, 0.00913f, -0.003197f, -0.004265f, - -0.00945f, -0.001356f, 0.007545f, 0.002289f, 0.001126f, 0.002977f, 0.00948f, -0.00703f, -0.002531f, - -0.00868f, -0.00619f, -0.0004635f, 0.009254f, -0.0005174f, -0.00736f, -0.006264f, 0.00779f, -0.002342f, - 0.004997f, 0.00269f, 0.00509f, -0.0041f, 0.00506f, 0.002752f, -0.006416f, 0.00794f, 0.003563f, - 0.00551f, 0.006554f, -0.008286f, -0.00296f, 0.008354f, -0.0079f, -0.006348f, 0.001052f, 0.0007205f, - 0.00506f, 0.000453f, -0.00993f, -0.006424f, 0.005787f, -0.001206f, 0.00876f, -0.004513f, -0.002857f, - -0.00701f, -0.00621f, 0.003498f, 0.00986f, -0.00846f, -0.00128f, 0.006294f, -0.003735f, 0.00843f, - -0.00841f, -0.007465f, -0.007504f, -0.00734f, 0.00635f, 0.004498f, -0.005688f, -0.003014f, 0.00892f, - 0.00982f, 0.00793f, -0.002365f, 0.003353f, -0.004486f, -0.00651f, -0.00361f, -0.00418f, -0.00786f, - 0.007812f, 0.001912f, -0.008156f, -0.00809f, -0.001939f, -0.003836f, -0.001578f, 0.00331f, -0.008736f, - -0.006138f, -0.00877f, -0.007595f, 0.002537f, -0.007336f, -0.006477f, -0.007767f, -0.00853f, -0.003601f, - -0.000952f, 0.007683f, -0.006283f, 0.00796f, 0.006012f, -0.001464f, 0.00718f, -0.0025f, -0.001972f, - 0.004166f, 0.0002615f, 0.00496f, 0.006516f, 0.0016f, -0.008415f, -0.002398f, -0.001027f, 0.0000037f, - 0.00827f, 0.003153f, 0.004826f, 0.00619f, -0.00673f, -0.00834f, -0.001702f, 0.006664f, -0.00465f, - -0.00909f, 0.003893f, 0.005188f, 0.009415f, 0.00191f, 0.00274f, -0.002968f, -0.003834f, 0.00495f, - 0.005985f, -0.002945f, 0.007317f, -0.00934f, -0.001007f, -0.005333f, -0.008415f, -0.0067f, 0.006084f, - 0.00689f, -0.002855f, -0.009254f, -0.00402f, 0.007694f, -0.007633f, -0.008865f, -0.00846f, 0.007317f, - -0.00915f, -0.009476f, 0.002455f, -0.001528f, -0.001358f, 0.0016985f, -0.001466f, -0.002584f, -0.006992f, - -0.00427f, 0.000739f, 0.00258f, 0.0042f, 0.001303f, 0.00963f, 0.002176f, -0.00952f, 0.0005264f, - -0.005226f, 0.008804f, 0.005707f, -0.00763f, -0.00875f, 0.0002716f, -0.00251f, -0.00646f, -0.00666f, - 0.00936f, 0.005447f, -0.00562f, 0.00967f, 0.001811f, -0.00963f, 0.001052f, 0.00807f, -0.002794f, - -0.00845f, 0.00685f, -0.003199f, 0.003119f, -0.004333f, 0.0001079f, -0.00884f, -0.002384f, -0.0008464f, - -0.0053f, 0.0008607f, 0.005f, 0.003218f, -0.001972f, 0.003925f, -0.000635f, -0.003868f, -0.00636f, - -0.005894f, 0.0005355f, 0.00921f, -0.006687f, 0.00629f, -0.001168f, -0.00646f, 0.005547f, -0.00963f, - -0.004078f, 0.002125f, 0.008995f, 0.006187f, 0.007397f, -0.00656f, -0.006527f, 0.006042f, -0.001503f, - -0.00624f, 0.003023f, -0.009995f, -0.002466f, 0.00351f, 0.003439f, -0.003235f, 0.008026f, 0.004158f, - 0.003117f, -0.005856f, 0.00461f, -0.001134f, 0.004257f, 0.00933f, 0.00992f, -0.008156f, 0.004356f, - 0.00917f, -0.007904f, 0.0004003f, -0.00912f, -0.003895f, -0.005566f, -0.00899f, -0.0001261f, -0.00272f, - -0.00529f, -0.005215f, -0.000558f, -0.006172f, 0.008354f, 0.000414f, -0.004574f, 0.00527f, 0.004333f, - -0.00728f, -0.00797f, 0.0096f, -0.00344f, -0.00881f, -0.00368f, 0.00844f, -0.00517f, -0.005783f, - -0.002708f, -0.006958f, 0.00088f, 0.007393f, 0.002115f, 0.00502f, -0.007347f, 0.002518f, -0.007164f, - 0.003891f, -0.006386f, 0.004723f, -0.007137f, 0.00979f, 0.00728f, -0.007385f, -0.003569f, -0.001245f, - 0.007244f, -0.004177f, 0.005627f, -0.001364f, 0.007786f, -0.003647f, 0.00975f, 0.003262f, 0.006668f, - 0.007492f, -0.002676f, 0.00452f, 0.00613f, 0.009895f, -0.0000653f, -0.0002944f, 0.0095f, 0.00829f, - 0.003607f, -0.00763f, 0.001573f, 0.00708f, 0.001338f, 0.00761f, -0.00934f, 0.00425f, 0.004677f, - 0.004356f, -0.00835f, -0.003391f, -0.00722f, 0.00877f, 0.001739f, -0.0078f, -0.003801f, -0.002934f, - 0.00592f, -0.00832f, -0.005596f, 0.00847f, 0.002663f, -0.002655f, -0.00461f, 0.001812f, -0.005447f, - 0.00393f, -0.0001626f, -0.0099f, -0.005177f, -0.000107f, -0.004513f, -0.00942f, -0.004494f, -0.0002584f, - 0.00558f, 0.00919f, 0.00483f, -0.003881f, 0.0000862f, 0.00472f, 0.002277f, 0.00452f, -0.005043f, - -0.00812f, 0.006695f, -0.001397f, 0.00708f, 0.00666f, 0.009445f, 0.002443f, 0.00672f, 0.00742f, - 0.0047f, -0.0099f, -0.001733f, -0.001216f, 0.002306f, 0.00525f, 0.006687f, 0.007397f, -0.004185f, - -0.007645f, 0.00497f, 0.002726f, -0.004883f, 0.00545f, 0.001207f, -0.003443f, 0.00855f, -0.008575f, - -0.00995f, 0.00938f, 0.001395f, -0.005894f, -0.004715f, 0.001335f, 0.007214f, -0.00979f, -0.0009723f, - -0.00884f, -0.00325f, -0.006447f, -0.0002873f, -0.006546f, -0.00914f, 0.00311f, 0.001508f, -0.008644f, - 0.003849f, -0.00224f, -0.0073f, 0.004158f, -0.007076f, -0.00458f, -0.002794f, 0.00691f, -0.00991f, - -0.002531f, -0.007236f, 0.00291f, 0.003098f, -0.00666f, 0.00618f, -0.001502f, -0.008026f, 0.0001609f, - -0.001733f, 0.00476f, 0.007725f, -0.007076f, -0.005398f, -0.001904f, 0.002743f, 0.001987f, 0.002935f, - 0.006363f, 0.007755f, -0.002127f, -0.002626f, 0.003273f, 0.0044f, -0.003975f, -0.00273f, -0.001413f, - -0.008736f, -0.005775f, 0.00445f, -0.007412f, -0.00647f, 0.0046f, 0.007393f, -0.0003533f, -0.00926f, - -0.006104f, 0.001658f, 0.00642f, -0.00962f, 0.00724f, -0.00032f, -0.00848f, -0.007442f, 0.001179f, - -0.004684f, -0.001757f, 0.002796f, 0.00741f, 0.002192f, 0.003952f, 0.002794f, -0.00581f, 0.00923f, - -0.000795f, -0.008545f, 0.0004318f, 0.007034f, 0.001034f, -0.009224f, 0.0037f, 0.00736f, -0.007587f, - -0.001963f, 0.00037f, -0.001584f, -0.0001048f, 0.00979f, -0.007168f, 0.003159f, 0.00205f, -0.0082f, - 0.000802f, 0.00919f, 0.005257f, 0.000411f, 0.006824f, 0.00543f, -0.00202f, -0.008705f, -0.0084f, - -0.0008135f, -0.001487f, -0.00698f, 0.00766f, 0.0003076f, 0.002989f, 0.00785f, 0.004498f, 0.004917f, - 0.001951f, 0.00489f, -0.000938f, 0.00438f, -0.00010777f, 0.00993f, -0.003304f, -0.00859f, 0.00656f, - -0.009926f, 0.00572f, 0.009445f, 0.004425f, 0.00595f, 0.005547f, -0.00555f, 0.00912f, -0.00391f, - 0.00417f, -0.00732f, -0.00944f, -0.001693f, 0.003319f, 0.007904f, 0.004158f, 0.008026f, -0.004173f, - 0.00174f, 0.00794f, 0.001028f, -0.0004673f, -0.01f, 0.005222f, 0.00968f, 0.00173f, -0.00965f, - 0.00775f, 0.00758f, -0.006916f, -0.006714f, 0.001373f, -0.00906f, 0.005737f, -0.00403f, 0.003036f, - -0.00832f, -0.001393f, -0.00903f, -0.007996f, -0.001152f, 0.00698f, -0.00907f, 0.00455f, 0.0006533f, - -0.001487f, -0.0074f, 0.005177f, 0.00607f, 0.006973f, -0.002907f, -0.008446f, 0.004932f, 0.00457f, - -0.001466f, 0.007805f, 0.002241f, -0.002304f, -0.006294f, -0.00625f, 0.002876f, 0.005146f, 0.000603f, - 0.00309f, -0.00912f, 0.002026f, 0.0096f, -0.000262f, 0.00007397f, 0.001089f, -0.00799f, 0.00948f, - -0.0007935f, -0.00997f, 0.001588f, 0.009674f, -0.0006795f, 0.00958f, 0.00604f, -0.00975f, -0.001219f, - -0.005093f, 0.00061f, 0.0002333f, 0.006195f, 0.006245f, 0.00548f, 0.006554f, 0.009155f, 0.003277f, - -0.0027f, -0.002827f, 0.002981f, 0.00059f, -0.00643f, 0.001903f, 0.006195f, -0.001568f, -0.002792f, - 0.001151f, -0.00969f, 0.0001194f, 0.006084f, -0.00789f, -0.00746f, -0.000923f, -0.002726f, -0.0009117f, - -0.009155f, 0.0003529f, 0.002682f, 0.00394f, 0.0003521f, -0.006798f, 0.f, 0.006145f, -0.006645f, - -0.0000278f, 0.005737f, -0.003601f, 0.008156f, 0.006905f, 0.00996f, 0.00752f, 0.00513f, -0.001212f, - -0.005558f, -0.009796f, -0.009056f, 0.001026f, -0.003756f, 0.002048f, 0.00501f, 0.004303f, 0.00885f, - -0.002895f, 0.00885f, 0.00881f, 0.008965f, -0.00772f, 0.000675f, -0.00361f, 0.009254f, 0.00947f, - 0.002851f, -0.00443f, -0.0008383f, -0.001255f, 0.007088f, -0.00718f, -0.001156f, 0.00496f, 0.00543f, - 0.009575f, -0.00932f, -0.00289f, -0.00961f, -0.005413f, 0.00887f, 0.008194f, 0.007217f, 0.001349f, - -0.00616f, -0.00132f, 0.008255f, 0.008354f, -0.001022f, -0.00916f, 0.0012f, 0.00942f, -0.005272f, - -0.007713f, 0.00924f, -0.002554f, 0.00812f, 0.002947f, 0.006466f, 0.007267f, 0.004383f, 0.006683f, - -0.004047f, -0.001562f, 0.0000953f, -0.00198f, -0.001826f, -0.005013f, 0.008095f, -0.00878f, -0.006645f, - 0.005096f, -0.0003052f, -0.00815f, -0.00986f, 0.0081f, 0.00661f, -0.00097f, 0.006916f, -0.007244f, - 0.004272f, 0.00444f, -0.00546f, 0.003994f, -0.00191f, 0.001437f, 0.00408f, -0.000537f, -0.007557f, - 0.0009537f, -0.00972f, -0.006805f, -0.007835f, -0.000847f, 0.005665f, -0.0085f, 0.005657f, 0.006027f, - -0.009285f, 0.00652f, 0.005535f, 0.009224f, 0.0007205f, -0.00692f, -0.00881f, 0.005817f, -0.00506f, - -0.00877f, -0.00991f, -0.001778f, -0.002598f, -0.00755f, 0.003616f, 0.00898f, 0.002537f, -0.001853f, - -0.000725f, 0.00202f, 0.001978f, -0.0008383f, 0.004784f, -0.0003638f, -0.00895f, 0.00243f, -0.00395f, - 0.001955f, -0.002853f, -0.005f, 0.00976f, -0.0006366f, -0.002913f, 0.002592f, -0.00857f, -0.0006256f, - -0.0001568f, 0.003605f, -0.001659f, 0.000935f, -0.005302f, 0.00593f, -0.002056f, 0.003723f, 0.005863f, - 0.0089f, -0.004147f, -0.007706f, 0.0006566f, 0.003222f, -0.00247f, 0.005234f, -0.009605f, -0.00279f, - 0.00031f, -0.008606f, -0.00952f, 0.001459f, 0.008446f, -0.00921f, 0.00895f, -0.00951f, -0.002565f, - 0.00084f, 0.006874f, -0.004066f, 0.004723f, -0.0006924f, 0.00932f, 0.003325f, -0.006763f, 0.004936f, - -0.003439f, -0.000998f, -0.008224f, -0.00412f, 0.006996f, -0.007057f, -0.00992f, -0.004974f, 0.001361f, - -0.009865f, 0.00982f, -0.00375f, -0.002928f, 0.00166f, -0.007782f, -0.001827f, 0.000567f, -0.002838f, - -0.0002354f, -0.00259f, -0.00849f, -0.001284f, 0.002161f, 0.001709f, -0.00802f, 0.00199f, -0.003202f, - 0.002773f, 0.009056f, -0.001113f, -0.006054f, -0.00209f, 0.007355f, 0.008194f, -0.005627f, -0.005226f, - -0.00478f, 0.001043f, 0.002869f, -0.00657f, -0.003176f, -0.004704f, -0.004574f, -0.00434f, 0.007328f, - 0.00895f, -0.00853f, -0.006207f, -0.00928f, -0.009476f, 0.009125f, 0.004627f, -0.004642f, -0.004658f, - 0.00919f, 0.003496f, 0.002165f, 0.00413f, -0.007694f, 0.003744f, 0.001043f, 0.002182f, -0.00698f, - -0.003906f, 0.00365f, 0.003763f, -0.0043f, 0.002554f, 0.0094f, 0.00586f, -0.00655f, -0.00171f, - -0.0009985f, -0.00851f, 0.00584f, 0.004883f, -0.007523f, 0.005016f, 0.003046f, 0.005917f, -0.006622f, - 0.00741f, -0.002499f, 0.0004418f, -0.003113f, 0.0003803f, 0.003252f, -0.00917f, 0.00506f, -0.006687f, - -0.00916f, 0.000701f, 0.00945f, -0.002863f, 0.00827f, 0.00938f, 0.003405f, -0.00935f, -0.00912f, - 0.00259f, 0.001822f, -0.00674f, 0.0008016f, -0.001132f, 0.00899f, 0.001555f, -0.0007024f, 0.00899f, - -0.00938f, -0.00109f, -0.00674f, 0.001553f, 0.00696f, 0.009415f, 0.0005765f, -0.0002084f, 0.004097f, - 0.005985f, 0.001656f, 0.005325f, -0.00839f, 0.003904f, 0.00822f, -0.003994f, 0.00635f, -0.000794f, - -0.00667f, 0.002296f, -0.002838f, -0.00975f, -0.001081f, 0.005127f, 0.001922f, 0.005127f, -0.008156f, - -0.006653f, 0.00935f, -0.00302f, -0.00052f, -0.005894f, -0.009674f, -0.00613f, 0.009705f, -0.006924f, - 0.004726f, 0.004784f, -0.00146f, 0.001746f, -0.002958f, 0.009636f, 0.005665f, -0.000724f, 0.004875f, - -0.001856f, -0.002975f, 0.0071f, 0.002045f, 0.00507f, -0.007042f, -0.006958f, 0.002089f, -0.003504f, - 0.0004888f, -0.005943f, 0.007607f, -0.003822f, -0.004692f, 0.0001357f, 0.004456f, -0.00799f, -0.006413f, - 0.002268f, 0.00888f, -0.00872f, -0.004936f, -0.0091f, -0.00353f, -0.0052f, -0.003223f, -0.00825f, - 0.003952f, -0.002771f, 0.006344f, 0.00862f, 0.00904f, -0.00221f, -0.0001844f, -0.00227f, 0.000672f, - -0.004852f, -0.005795f, -0.002771f, -0.00653f, -0.002579f, 0.006954f, 0.002605f, -0.00804f, 0.00432f, - 0.0000249f, -0.004536f, -0.008514f, 0.00618f, -0.002804f, 0.00895f, -0.009094f, -0.009155f, -0.003836f, - -0.0008125f, 0.007385f, 0.00554f, -0.0004065f, -0.00517f, -0.006493f, -0.007027f, 0.003748f, -0.00834f, - -0.006668f, 0.00982f, -0.001279f, -0.0008125f, 0.000629f, 0.003786f, -0.00859f, -0.000755f, 0.0004015f, - -0.003065f, -0.007042f, -0.00967f, 0.0004108f, 0.00947f, -0.007076f, -0.0006723f, 0.006496f, -0.001414f, - 0.008194f, -0.000413f, 0.008125f, 0.00146f, -0.006462f, 0.002676f, -0.005474f, -0.003166f, 0.006027f, - 0.001129f, 0.001874f, 0.001855f, 0.00766f, -0.006634f, -0.000823f, -0.00303f, 0.005795f, 0.00279f, - 0.002512f, 0.006172f, 0.006474f, 0.000632f, -0.007507f, 0.001753f, -0.002531f, 0.002895f, -0.007034f, - 0.004955f, -0.0096f, 0.007793f, -0.00803f, -0.0095f, 0.006615f, -0.00854f, 0.00214f, 0.00532f, - -0.00995f, 0.00772f, 0.006977f, -0.00873f, -0.00617f, -0.00808f, -0.00479f, -0.00397f, 0.00456f, - 0.003944f, 0.0001737f, 0.001538f, -0.005756f, 0.009964f, 0.002096f, -0.00984f, 0.001642f, 0.003113f, - -0.00802f, -0.003527f, -0.00876f, 0.003502f, -0.00562f, 0.003378f, 0.006676f, 0.000644f, 0.002071f, - -0.00587f, -0.00771f, -0.0009327f, -0.00441f, 0.007095f, 0.005478f, 0.00781f, 0.00952f, 0.006176f, - 0.0003223f, 0.00818f, 0.00678f, -0.004147f, -0.00999f, 0.00903f, -0.00987f, 0.007553f, -0.00438f, - 0.005028f, 0.0003302f, 0.0002394f, -0.005104f, -0.002537f, -0.005333f, 0.004635f, -0.005787f, -0.005177f, - -0.005615f, -0.00463f, 0.0001181f, -0.00814f, 0.00656f, -0.00132f, 0.003115f, -0.006237f, -0.00123f, - -0.008804f, -0.002682f, -0.00877f, 0.00749f, -0.00863f, 0.004997f, 0.007736f, -0.00963f, -0.002966f, - -0.00405f, -0.004005f, 0.006763f, -0.00639f, 0.000797f, 0.002903f, 0.00967f, -0.0009356f, -0.00675f, - 0.00917f, -0.0048f, 0.0088f, 0.007168f, 0.00394f, 0.005524f, 0.0002052f, -0.0004148f, 0.0059f, - -0.002966f, 0.008f, -0.00955f, -0.008484f, 0.00856f, 0.003498f, -0.005703f, 0.004974f, 0.0089f, - -0.004208f, -0.005203f, -0.007496f, 0.003206f, -0.007713f, -0.0068f, 0.00437f, 0.008896f, 0.0007954f, - 0.002823f, -0.002413f, -0.004665f, 0.0007997f, -0.005394f, 0.00806f, -0.001563f, -0.001497f, -0.005314f, - -0.00952f, 0.0093f, 0.005066f, 0.00407f, 0.004482f, -0.00788f, 0.001537f, 0.00806f, -0.005013f, - -0.003735f, 0.00956f, -0.00946f, 0.002008f, -0.006847f, 0.003038f, 0.003141f, -0.005787f, 0.005665f, - 0.002735f, -0.002401f, 0.003057f, 0.000753f, 0.004444f, 0.00805f, 0.001004f, -0.0065f, -0.001637f, - 0.0065f, 0.004467f, -0.00896f, -0.006573f, -0.007236f, 0.007435f, -0.00392f, -0.001908f, -0.008736f, - -0.0007854f, 0.000625f, 0.003866f, -0.002039f, -0.002193f, -0.006447f, -0.00793f, -0.002161f, -0.0073f, - 0.00472f, 0.001314f, 0.006416f, -0.009224f, 0.00668f, 0.008865f, 0.009155f, -0.004684f, 0.00807f, - -0.0008855f, 0.002748f, 0.001529f, -0.004765f, -0.001041f, 0.00859f, 0.005573f, 0.00433f, -0.009155f, - -0.007614f, 0.00472f, -0.0009365f, 0.00003576f, 0.002872f, -0.003223f, 0.003098f, -0.001782f, 0.001795f, - 0.006645f, 0.002974f, -0.0094f, 0.005337f, 0.00877f, -0.00649f, 0.00959f, -0.008156f, -0.0008917f, - 0.006607f, 0.00905f, -0.001238f, -0.001246f, -0.002775f, -0.002815f, 0.00451f, -0.004486f, 0.003998f, - 0.00956f, -0.00981f, 0.005096f, -0.00876f, -0.002571f, 0.002287f, -0.002996f, -0.008896f, -0.006973f, - 0.003885f, 0.001993f, -0.006523f, 0.0048f, -0.005745f, 0.004883f, 0.005627f, -0.00919f, 0.00978f, - -0.000961f, 0.00954f, 0.003023f, 0.006172f, -0.00371f, -0.00509f, -0.00392f, -0.00989f, 0.00212f, - -0.00917f, -0.009865f, 0.00965f, 0.003618f, -0.004303f, 0.00628f, 0.002913f, 0.0086f, -0.00881f, - 0.004963f, -0.006886f, -0.00000197f, -0.008736f, 0.004147f, -0.003227f, -0.001696f, -0.003815f, 0.00957f, - -0.00994f, -0.006596f, 0.00925f, 0.007454f, -0.001091f, -0.0004747f, 0.009026f, 0.00854f, 0.00133f, - -0.00263f, 0.00543f, 0.003836f, 0.004856f, -0.006695f, 0.005478f, -0.008415f, 0.003187f, -0.00998f, - 0.009514f, 0.002903f, -0.005165f, -0.0004752f, -0.009f, -0.008965f, 0.005806f, 0.006153f, 0.00893f, - -0.00877f, -0.006866f, 0.004154f, -0.008125f, 0.007202f, -0.005573f, 0.004f, -0.002998f, 0.002878f, - 0.005672f, 0.00607f, -0.004578f, 0.001471f, -0.002363f, -0.00006247f, 0.0007734f, 0.001287f, -0.0006113f, - 0.003868f, -0.00696f, -0.003672f, 0.00688f, -0.00908f, -0.00665f, 0.003775f, -0.006355f, -0.005634f, - 0.00421f, 0.00937f, -0.004856f, 0.002947f, -0.003933f, -0.0086f, 0.00988f, 0.00546f, -0.0008826f, - 0.00433f, 0.007183f, 0.002195f, -0.005333f, 0.006683f, 0.003277f, 0.001082f, 0.00579f, -0.00623f, - -0.00966f, -0.002708f, 0.00627f, 0.00581f, -0.0095f, 0.008896f, -0.002478f, -0.00966f, 0.007526f, - -0.001696f, 0.002949f, 0.001381f, -0.00684f, -0.005974f, 0.00413f, 0.00085f, 0.004032f, 0.004807f, - 0.0004041f, -0.006992f, 0.003105f, -0.0002321f, 0.00867f, 0.00237f, 0.00464f, -0.00887f, -0.005978f, - -0.005844f, -0.00826f, 0.005035f, 0.00953f, 0.006485f, -0.00415f, -0.00873f, -0.006836f, 0.00572f, - 0.001606f, -0.00828f, -0.001708f, -0.006145f, 0.00914f, -0.00965f, 0.005646f, -0.00857f, 0.006638f, - 0.00327f, 0.00424f, 0.001341f, 0.003788f, -0.000685f, 0.0061f, -0.00782f, 0.003334f, -0.0068f, - 0.001557f, 0.005825f, -0.0058f, -0.000689f, 0.007496f, 0.00708f, -0.006107f, 0.007668f, -0.001199f, - -0.00948f, 0.00668f, -0.003176f, 0.003733f, -0.001616f, 0.006714f, 0.00789f, 0.001432f, 0.004112f, - 0.00384f, 0.009636f, 0.007053f, -0.00374f, 0.00495f, 0.00959f, 0.004135f, 0.00721f, 0.007225f, - -0.0008454f, 0.008286f, 0.0000413f, 0.003618f, 0.004047f, 0.00454f, -0.0079f, 0.00869f, 0.00706f, - -0.007492f, 0.00493f, 0.00689f, -0.0005245f, 0.00604f, 0.00357f, 0.00598f, -0.00959f, -0.003292f, - 0.0008936f, 0.00904f, 0.002445f, 0.00894f, 0.00819f, 0.003876f, 0.002953f, 0.003384f, -0.006687f, - 0.002918f, -0.0056f, -0.0003066f, -0.001384f, 0.007675f, 0.0009513f, -0.007656f, 0.00804f, -0.000968f, - -0.000649f, 0.00913f, -0.0041f, 0.0002625f, -0.0001359f, -0.008865f, 0.002167f, 0.00687f, -0.00606f, - 0.0003486f, 0.0003984f, -0.004803f, 0.006454f, -0.004997f, 0.00892f, -0.007423f, -0.001277f, -0.007504f, - 0.00762f, 0.003056f, 0.001508f, -0.00391f, 0.00859f, -0.00768f, -0.003675f, 0.002884f, 0.006508f, - 0.000506f, 0.002567f, 0.007607f, -0.003233f, 0.0073f, 0.003862f, -0.003817f, 0.00735f, 0.002506f, - -0.00823f, -0.006706f, 0.005676f, -0.00931f, -0.004025f, 0.006542f, 0.000566f, 0.00919f, -0.002083f, - -0.00783f, 0.0013485f, -0.00839f, 0.0089f, -0.0066f, 0.009674f, -0.00821f, 0.0061f, -0.002129f, - 0.00598f, 0.008865f, 0.00513f, -0.00582f, -0.00459f, -0.00962f, -0.00962f, -0.005966f, -0.007187f, - 0.00995f, 0.004295f, 0.004467f, 0.001008f, -0.00809f, 0.00922f, -0.00768f, -0.00994f, -0.005596f, - 0.006706f, 0.00748f, 0.00942f, -0.00396f, 0.001708f, -0.00961f, 0.005653f, 0.00976f, -0.001643f, - 0.003786f, -0.002264f, 0.002747f, -0.0003808f, 0.000354f, 0.001055f, 0.00584f, 0.006306f, 0.005363f, - -0.006443f, -0.0005603f, 0.00871f, 0.00683f, -0.002083f, -0.00611f, -0.006573f, -0.0027f, 0.004917f, - 0.006207f, 0.004932f, -0.00669f, 0.005665f, 0.002796f, 0.00901f, -0.000798f, 0.001478f, 0.003788f, - 0.000707f, 0.00934f, 0.005985f, -0.00145f, -0.0008683f, 0.00339f, 0.002144f, 0.006596f, 0.00984f, - 0.00258f, 0.0048f, 0.0003848f, -0.002644f, -0.002129f, -0.001171f, -0.002369f, -0.007328f, 0.00841f, - -0.005325f, 0.00968f, -0.00982f, -0.003754f, -0.0006895f, 0.00784f, 0.003864f, 0.008316f, -0.003483f, - 0.004986f, -0.003044f, -0.005714f, -0.001846f, -0.001568f, 0.0003648f, 0.00724f, 0.006336f, -0.003222f, - -0.006836f, 0.001214f, -0.003124f, -0.0006356f, -0.001073f, 0.002682f, -0.007538f, -0.001701f, -0.00883f, - 0.00986f, 0.006336f, 0.0011f, -0.00879f, -0.005875f, 0.004025f, 0.00613f, 0.004856f, -0.008896f, - 0.0006967f, 0.0064f, 0.002707f, -0.002317f, -0.002214f, 0.002409f, -0.000346f, -0.006924f, 0.001986f, - -0.003166f, 0.00836f, -0.00899f, 0.0034f, -0.007755f, 0.00407f, 0.00807f, 0.0076f, 0.003824f, - 0.003876f, -0.00853f, -0.00649f, -0.003506f, 0.001777f, -0.009705f, -0.00516f, -0.0094f, 0.00939f, - -0.00786f, -0.00911f, -0.000737f, 0.000864f, -0.00851f, 0.00786f, -0.003422f, -0.00832f, -0.0007277f, - 0.005642f, -0.00868f, -0.002851f, 0.0005975f, -0.007347f, -0.001616f, -0.001303f, 0.00717f, -0.00231f, - -0.008354f, -0.005333f, 0.00864f, 0.006123f, -0.00994f, 0.00313f, -0.00676f, -0.005806f, 0.008446f, - -0.0007553f, -0.006416f, 0.00223f, -0.00579f, 0.00576f, -0.00892f, 0.002424f, -0.00486f, 0.00636f, - 0.003344f, -0.003195f, 0.001562f, 0.00318f, -0.007202f, -0.001358f, -0.0001854f, 0.002499f, 0.001725f, - 0.000389f, -0.006737f, 0.002745f, 0.000575f, -0.003534f, 0.004284f, 0.0019045f, 0.004898f, -0.004356f, - 0.002254f, -0.00577f, 0.0018215f, -0.008736f, 0.00769f, -0.00885f, -0.00859f, -0.00441f, 0.00583f, - -0.009285f, -0.00792f, -0.00922f, -0.003815f, -0.00886f, -0.005394f, -0.00663f, -0.008224f, -0.00353f, - 0.002161f, 0.00301f, -0.00542f, -0.0085f, -0.007446f, -0.00846f, -0.00515f, 0.00204f, 0.00543f, - -0.001219f, -0.007072f, 0.001966f, -0.00894f, 0.0008793f, -0.003418f, 0.00393f, -0.005283f, 0.005756f, - 0.003225f, 0.002123f, 0.002283f, 0.00566f, 0.000477f, 0.00497f, 0.005295f, 0.002136f, 0.00692f, - 0.00872f, 0.00936f, -0.005074f, 0.00645f, -0.001117f, 0.006493f, -0.00574f, 0.001013f, 0.003334f, - -0.005703f, -0.006992f, -0.004314f, 0.005314f, 0.001457f, -0.00594f, -0.003252f, 0.00844f, 0.002502f, - 0.002604f, 0.00289f, 0.00221f, -0.003344f, -0.006905f, -0.00799f, 0.007378f, -0.00945f, 0.006023f, - -0.00791f, 0.001273f, 0.003849f, 0.007694f, 0.005424f, 0.00298f, -0.003618f, -0.0001827f, 0.002077f, - 0.001976f, -0.006474f, 0.00079f, 0.00982f, 0.004166f, 0.007027f, 0.008606f, 0.00818f, 0.00697f, - -0.003006f, 0.0045f, -0.00885f, -0.00515f, 0.00723f, -0.0001746f, -0.00727f, 0.006237f, -0.008385f, - 0.008194f, -0.008316f, -0.002525f, 0.002558f, 0.00639f, 0.003586f, -0.00612f, -0.006756f, -0.008354f, - 0.004883f, -0.00506f, -0.009f, -0.00537f, -0.001243f, -0.005596f, -0.00853f, -0.007545f, 0.00786f, - 0.001839f, -0.002245f, 0.00544f, -0.00196f, 0.004967f, -0.003464f, -0.005108f, 0.003086f, 0.002628f, - -0.002502f, -0.00665f, -0.006226f, 0.0079f, -0.002287f, 0.0003567f, -0.001279f, 0.004826f, 0.005432f, - -0.00634f, -0.003204f, 0.0002022f, -0.00198f, -0.0008726f, 0.004055f, 0.00793f, -0.00427f, -0.00533f, - 0.00734f, -0.00799f, -0.0051f, -0.009995f, 0.0051f, 0.00413f, -0.00679f, 0.00262f, 0.001331f, - 0.001461f, -0.00865f, -0.00791f, -0.003975f, 0.002504f, 0.0002255f, 0.002337f, -0.00456f, -0.005974f, - 0.000257f, -0.00545f, 0.00842f, 0.005585f, -0.0003774f, 0.0008087f, -0.001679f, 0.003853f, 0.00991f, - 0.0031f, 0.00523f, -0.00721f, 0.000989f, -0.005642f, -0.001042f, 0.007935f, -0.006195f, 0.001426f, - 0.00414f, 0.00925f, -0.00419f, 0.004852f, -0.00639f, 0.00694f, -0.007706f, -0.00684f, -0.00602f, - -0.004444f, 0.005016f, -0.00803f, -0.00955f, 0.004097f, -0.003754f, 0.002384f, -0.007515f, 0.003508f, - -0.00749f, 0.00519f, 0.00228f, 0.007015f, -0.007572f, -0.003864f, -0.00843f, 0.00543f, 0.00911f, - 0.00774f, 0.009125f, -0.003473f, -0.00646f, 0.00856f, 0.004272f, 0.00534f, 0.003859f, -0.0001141f, - 0.001515f, 0.003437f, 0.00737f, 0.003565f, -0.002705f, 0.003675f, 0.003023f, -0.0002156f, -0.00894f, - 0.00103f, -0.001797f, -0.00854f, 0.001505f, -0.00876f, -0.003614f, 0.004887f, -0.005085f, 0.002449f, - 0.00524f, -0.00589f, 0.00784f, 0.001411f, -0.0095f, 0.007797f, -0.003391f, 0.008316f, 0.0094f, - 0.00917f, -0.00658f, -0.00685f, -0.005085f, -0.005375f, 0.008705f, -0.004093f, 0.00764f, -0.006172f, - -0.00609f, -0.0005703f, -0.00941f, -0.007065f, 0.00942f, 0.00403f, 0.00392f, -0.0000164f, 0.000577f, - 0.001058f, 0.006317f, 0.0008893f, 0.001935f, -0.009865f, -0.00542f, 0.001452f, 0.00916f, -0.00852f, - -0.00081f, 0.00397f, 0.0069f, 0.003246f, -0.004456f, 0.00777f, -0.004444f, 0.003632f, -0.002512f, - -0.00284f, 0.009926f, 0.00869f, -0.00636f, -0.006454f, 0.006805f, -0.00232f, -0.00924f, 0.006268f, - 0.00501f, -0.00951f, -0.00518f, 0.006126f, 0.00966f, 0.00881f, -0.009346f, 0.00912f, 0.00341f, - 0.00617f, 0.00984f, -0.00357f, 0.00596f, -0.0081f, -0.0006824f, -0.00711f, 0.004803f, 0.00484f, - -0.000756f, 0.002865f, -0.00422f, 0.00005835f, 0.00912f, 0.000726f, 0.001402f, 0.00644f, -0.006542f, - 0.006016f, 0.003975f, 0.00556f, 0.0000735f, -0.002203f, 0.003893f, -0.000724f, 0.005882f, -0.006226f, - -0.006912f, 0.003027f, 0.0004182f, -0.00728f, -0.00726f, -0.00896f, 0.008095f, -0.001346f, 0.00898f, - 0.002956f, -0.003334f, -0.007717f, -0.00876f, 0.00037f, -0.00727f, -0.003258f, 0.009476f, 0.009056f, - 0.00598f, 0.00281f, 0.00586f, -0.00981f, -0.003296f, 0.00769f, -0.000486f, 0.0091f, 0.00634f, - -0.00542f, 0.00512f, -0.002474f, -0.009514f, 0.00402f, -0.004787f, 0.00274f, -0.001112f, -0.002436f, - 0.00949f, -0.000839f, -0.009155f, 0.002499f, 0.001512f, 0.001406f, -0.00313f, -0.002022f, -0.008896f, - -0.00528f, -0.009254f, -0.002148f, -0.000707f, -0.0001829f, -0.001159f, 0.00411f, -0.007637f, -0.00364f, - 0.005135f, -0.00928f, -0.0000797f, 0.004642f, -0.00817f, -0.007072f, -0.003914f, 0.00416f, 0.002985f, - -0.0075f, -0.000736f, 0.008934f, 0.004204f, 0.0004723f, 0.006306f, -0.007675f, -0.007835f, 0.0005293f, - -0.002478f, -0.006336f, 0.007996f, 0.002539f, 0.001836f, 0.00968f, 0.006844f, 0.001179f, 0.001448f, - 0.006042f, 0.00292f, -0.007122f, -0.001914f, 0.004448f, 0.00822f, 0.00672f, 0.000714f, -0.001145f, - 0.009415f, 0.0015335f, -0.005585f, -0.006104f, -0.0003273f, -0.00987f, 0.001559f, -0.00608f, 0.007664f, - 0.00834f, -0.0002584f, -0.004097f, 0.00745f, 0.005417f, -0.002129f, 0.001597f, 0.00749f, -0.001676f, - 0.006344f, 0.006905f, 0.004364f, -0.00739f, -0.001457f, 0.00806f, -0.008f, -0.004284f, -0.00717f, - 0.00547f, 0.004463f, 0.00529f, -0.00843f, 0.008064f, 0.00556f, 0.0005236f, 0.00918f, -0.004986f, - 0.00578f, -0.001013f, -0.003479f, -0.004425f, -0.0076f, -0.004093f, 0.003084f, -0.00531f, -0.00902f, - -0.002844f, 0.004982f, -0.00986f, 0.003986f, 0.002125f, 0.004036f, -0.006798f, 0.000773f, 0.000544f, - -0.0001241f, 0.009155f, 0.002682f, -0.00997f, -0.00826f, 0.003769f, 0.001383f, -0.005318f, 0.004673f, - -0.005314f, 0.00691f, 0.00212f, -0.00656f, -0.006226f, -0.008705f, 0.00459f, -0.003798f, 0.00869f, - -0.002985f, -0.000604f, 0.00826f, -0.00541f, -0.00502f, 0.000809f, -0.00969f, -0.006626f, 0.005123f, - -0.0005465f, -0.00858f, 0.005554f, -0.002083f, 0.007343f, -0.001588f, -0.001642f, 0.0007577f, 0.00318f, - -0.00391f, 0.00404f, 0.00886f, -0.006374f, -0.00958f, -0.005077f, -0.00218f, 0.00745f, 0.00944f, - 0.007233f, 0.003042f, -0.003296f, 0.006786f, -0.006706f, 0.007114f, 0.00566f, 0.005325f, 0.007637f, - -0.00661f, 0.0008025f, -0.002693f, 0.005634f, 0.001557f, -0.007133f, -0.00483f, -0.00654f, 0.006313f, - -0.00926f, -0.00372f, -0.00583f, -0.004025f, 0.00761f, 0.00955f, 0.002691f, -0.00915f, -0.006084f, - -0.008835f, 0.003885f, 0.009514f, -0.00841f, 0.003637f, -0.00765f, -0.005978f, 0.001959f, -0.005295f, - -0.001565f, -0.003551f, -0.000824f, 0.005848f, -0.00010514f, 0.00828f, -0.003895f, -0.003197f, 0.00797f, - 0.00998f, 0.004635f, 0.006504f, 0.007023f, -0.00675f, 0.001584f, 0.004642f, 0.007458f, -0.002005f, - 0.0000653f, 0.00715f, 0.00402f, 0.00782f, -0.00331f, 0.00676f, 0.000039f, 0.00644f, -0.0007744f, - 0.005688f, 0.00511f, -0.005135f, 0.000995f, 0.006756f, -0.002304f, 0.003553f, -0.00938f, -0.000616f, - -0.00897f, -0.00685f, -0.00838f, 0.003983f, -0.004807f, 0.002314f, 0.00847f, 0.00846f, -0.007507f, - 0.002136f, 0.005905f, -0.00899f, 0.0081f, 0.008f, 0.00889f, -0.00907f, -0.00489f, 0.00938f, - -0.009254f, 0.00627f, 0.0052f, -0.002031f, -0.0006337f, -0.001191f, 0.001453f, -0.003918f, 0.001798f, - -0.00491f, -0.002062f, -0.00889f, 0.00309f, 0.007526f, 0.0007014f, -0.001351f, -0.003838f, 0.00458f, - 0.004005f, -0.00923f, 0.00581f, -0.002983f, -0.00901f, 0.007095f, 0.00844f, -0.00989f, 0.001532f, - -0.00867f, 0.001821f, -0.005646f, 0.00698f, -0.001757f, -0.00102f, -0.00511f, -0.007774f, 0.002588f, - -0.006096f, 0.005196f, -0.002117f, -0.0003762f, 0.00738f, 0.001219f, 0.00447f, 0.00867f, -0.00494f, - 0.007313f, -0.008095f, 0.000967f, 0.004776f, 0.00296f, 0.001068f, 0.00818f, 0.00749f, -0.00939f, - -0.00738f, -0.006214f, -0.00685f, 0.00569f, 0.00716f, 0.004375f, -0.00512f, -0.006252f, -0.004684f, - -0.002974f, -0.007965f, 0.0025f, -0.00943f, 0.00539f, 0.0003204f, 0.0005164f, -0.006573f, 0.00646f, - 0.00502f, 0.007965f, -0.002003f, -0.00609f, -0.009285f, -0.005028f, -0.00985f, 0.001395f, 0.00415f, - 0.003494f, 0.00957f, 0.009834f, -0.005905f, 0.002436f, 0.001002f, -0.002335f, -0.00981f, 0.006714f, - 0.005135f, -0.003138f, -0.00786f, 0.005497f, 0.003677f, 0.00479f, -0.00453f, 0.00845f, 0.007454f, - 0.000992f, -0.00647f, 0.001218f, -0.004295f, 0.00004745f, 0.005558f, -0.002914f, 0.00861f, -0.008064f, - 0.003328f, -0.003998f, -0.007595f, 0.00487f, 0.0008106f, 0.005287f, -0.003735f, 0.003054f, 0.006645f, - -0.002422f, 0.00974f, -0.001171f, 0.006264f, 0.00908f, 0.002903f, 0.00446f, 0.002419f, 0.00806f, - -0.002483f, 0.0089f, 0.0004303f, -0.001789f, -0.00638f, -0.005802f, -0.00953f, -0.00526f, 0.006203f, - -0.001033f, -0.00721f, 0.00391f, 0.00923f, 0.006676f, 0.00495f, -0.002512f, -0.000916f, 0.005054f, - -0.007652f, 0.004738f, 0.00826f, -0.00989f, -0.00202f, -0.00824f, -0.004333f, 0.002779f, -0.00531f, - 0.00181f, -0.00475f, 0.005234f, -0.00558f, 0.002342f, -0.001395f, -0.005856f, 0.004074f, -0.00638f, - -0.003561f, 0.00819f, 0.006454f, -0.00402f, -0.008766f, -0.006668f, -0.00244f, -0.00392f, -0.007248f, - -0.00666f, 0.001226f, -0.0071f, 0.00746f, 0.00396f, -0.00057f, 0.0001602f, 0.006924f, -0.0004158f, - -0.000988f, -0.008385f, 0.004936f, -0.001231f, 0.00533f, 0.00905f, 0.0015335f, 0.003677f, 0.00751f, - -0.00807f, -0.0051f, 0.00774f, -0.000592f, 0.003368f, -0.001825f, -0.003403f, 0.008194f, -0.0004606f, - 0.00312f, -0.004196f, 0.008026f, 0.004883f, -0.003073f, -0.006607f, 0.00847f, -0.007446f, -0.00982f, - -0.002375f, 0.009186f, 0.00991f, 0.005642f, -0.00632f, -0.005085f, 0.0084f, 0.002087f, 0.004f, - 0.002495f, 0.004326f, 0.00969f, -0.003504f, 0.008514f, 0.000959f, 0.003632f, -0.001369f, 0.005737f, - 0.002361f, -0.00802f, -0.006603f, 0.007866f, -0.008675f, 0.009384f, 0.001016f, 0.006927f, -0.005165f, - 0.001802f, -0.002798f, 0.008415f, 0.00439f, 0.003819f, 0.002295f, 0.006844f, -0.006813f, 0.0003488f, - 0.000659f, 0.00963f, -0.00946f, 0.002861f, -0.00614f, 0.002499f, -0.00706f, 0.003216f, -0.003124f, - -0.004585f, 0.001135f, -0.00212f, 0.007435f, -0.003775f, -0.0001405f, -0.000892f, 0.006218f, -0.005333f, - 0.007397f, 0.003202f, 0.009026f, 0.003717f, 0.00787f, 0.005188f, 0.0002823f, -0.0052f, 0.00797f, - -0.0009027f, -0.006462f, 0.00908f, -0.001527f, 0.005005f, 0.005547f, 0.00665f, -0.002155f, -0.00641f, - 0.00467f, -0.002872f, 0.000676f, 0.0009217f, 0.00424f, -0.000898f, 0.00932f, 0.004444f, -0.009834f, - 0.00908f, -0.0000113f, -0.00378f, 0.00792f, -0.00931f, -0.002563f, 0.003622f, 0.00972f, -0.0066f, - -0.002348f, -0.00787f, 0.004368f, -0.00385f, 0.0099f, 0.00617f, -0.001304f, 0.008575f, -0.00803f, - -0.008354f, 0.00794f, -0.00924f, 0.0069f, -0.00811f, 0.000215f, -0.00519f, -0.001069f, 0.000882f, - -0.007378f, 0.006447f, -0.003225f, -0.00484f, -0.00356f, -0.0004394f, -0.002144f, -0.001932f, 0.0007205f, - -0.00976f, 0.008514f, -0.006294f, 0.00618f, -0.001758f, -0.00713f, -0.00912f, 0.004726f, 0.00334f, - 0.00847f, -0.0001967f, 0.005165f, -0.004944f, -0.00915f, 0.0062f, -0.00553f, 0.0084f, -0.0054f, - 0.002823f, 0.00272f, -0.00271f, -0.009514f, 0.00629f, -0.006054f, 0.008865f, -0.00813f, -0.0076f, - 0.00857f, -0.003681f, -0.00738f, -0.00872f, -0.001488f, 0.00926f, -0.001791f, 0.00471f, -0.00482f, - 0.007812f, -0.004654f, -0.006138f, 0.003813f, 0.005768f, -0.00375f, -0.00992f, -0.000584f, 0.00783f, - -0.004147f, 0.001611f, 0.001342f, -0.006832f, -0.00138f, 0.005325f, -0.0000265f, 0.009445f, 0.00872f, - 0.001329f, -0.0026f, 0.002577f, 0.0072f, 0.00547f, 0.006428f, -0.004864f, 0.00876f, -0.00906f, - 0.007317f, -0.007233f, -0.00774f, 0.003387f, -0.002037f, 0.00125f, 0.00655f, -0.003298f, 0.008514f, - -0.003757f, 0.007935f, -0.003181f, 0.00629f, 0.00838f, 0.0009594f, 0.006897f, -0.008835f, 0.00446f, - -0.0082f, -0.006042f, 0.00761f, -0.00883f, 0.002434f, 0.001002f, 0.00712f, -0.005688f, 0.003359f, - -0.00606f, 0.002512f, 0.00576f, 0.006126f, 0.0009394f, -0.00787f, -0.00485f, 0.005936f, 0.002037f, - -0.0024f, -0.00618f, -0.00157f, 0.00702f, -0.007637f, 0.0077f, -0.00784f, -0.0062f, -0.00975f, - -0.00849f, 0.00843f, 0.003843f, -0.006443f, 0.004993f, -0.0001615f, 0.00902f, 0.00811f, 0.005333f, - 0.002123f, 0.001081f, 0.0086f, -0.003103f, 0.005783f, 0.004936f, -0.00898f, 0.001179f, 0.0007f, - 0.003462f, -0.00855f, 0.00254f, -0.0000039f, -0.00468f, 0.0012455f, 0.003431f, 0.007538f, 0.0082f, - 0.00843f, -0.001547f, 0.006157f, 0.001941f, -0.0013895f, -0.003096f, -0.003883f, -0.006382f, -0.00475f, - 0.008766f, -0.003225f, 0.0008793f, -0.002806f, -0.00432f, 0.003944f, 0.008286f, 0.003141f, -0.00975f, - -0.00439f, -0.007645f, 0.0093f, 0.005238f, -0.002018f, -0.006023f, -0.001462f, 0.00286f, 0.00525f, - 0.005463f, -0.0005217f, -0.0003283f, -0.003103f, -0.007656f, -0.003311f, -0.0002983f, 0.005165f, 0.007187f, - 0.00674f, -0.002645f, 0.00882f, 0.009995f, -0.003174f, -0.002956f, -0.00978f, 0.00841f, 0.005043f, - 0.00798f, 0.00003827f, -0.004494f, -0.00883f, -0.0003128f, -0.0015955f, 0.00958f, 0.001948f, -0.007664f, - -0.002064f, 0.002949f, 0.008736f, 0.00684f, 0.00804f, 0.004642f, -0.000742f, 0.001874f, -0.004864f, - 0.0003529f, -0.001284f, 0.00896f, -0.006954f, -0.003616f, 0.0078f, 0.00815f, -0.00876f, -0.002783f, - -0.00649f, 0.00976f, 0.009125f, 0.0019f, -0.0004215f, 0.00461f, 0.001037f, 0.009384f, 0.003422f, - 0.001194f, 0.00923f, 0.00554f, -0.00855f, -0.001592f, -0.002981f, 0.006016f, 0.002314f, -0.00483f, - 0.002476f, -0.00894f, -0.000574f, 0.0096f, -0.0002362f, -0.002018f, 0.00283f, 0.00251f, -0.0001559f, - -0.00557f, 0.00661f, -0.002537f, 0.005524f, 0.00961f, -0.002073f, 0.00454f, -0.006428f, 0.001997f, - -0.00446f, -0.0007524f, 0.002176f, -0.00209f, -0.00874f, 0.001289f, 0.00523f, 0.001575f, -0.008736f, - 0.007057f, -0.0069f, -0.00512f, -0.005383f, 0.0001678f, 0.001076f, 0.007683f, -0.006207f, -0.006233f, - -0.00585f, -0.004894f, 0.00773f, 0.00627f, -0.0008707f, -0.00574f, -0.002068f, -0.0003157f, -0.00921f, - -0.006275f, 0.007275f, -0.0004473f, 0.002474f, -0.009186f, 0.001432f, 0.003687f, -0.004425f, -0.002018f, - 0.00922f, -0.00788f, 0.000894f, -0.001047f, -0.001193f, 0.009094f, -0.0039f, 0.00977f, 0.00951f, - 0.00976f, 0.002201f, 0.006214f, -0.002117f, 0.006203f, 0.00278f, -0.006725f, -0.006157f, 0.003757f, - -0.001729f, 0.005405f, -0.00904f, -0.000435f, -0.002148f, -0.00849f, 0.00923f, -0.008194f, -0.001804f, - -0.00392f, 0.0002866f, -0.007317f, 0.005623f, -0.002657f, -0.005657f, 0.006363f, 0.00205f, 0.005215f, - 0.00376f, 0.001134f, -0.003138f, 0.00569f, 0.008446f, -0.003283f, 0.004047f, -0.00322f, -0.001756f, - -0.006763f, 0.001577f, -0.007225f, 0.006092f, 0.004112f, -0.006554f, -0.00428f, 0.004684f, -0.000417f, - 0.00418f, -0.000349f, -0.00676f, -0.004097f, -0.00899f, 0.004936f, 0.00864f, -0.006325f, -0.004665f, - -0.00834f, 0.00238f, 0.006153f, -0.00914f, 0.004246f, -0.00963f, 0.003986f, 0.00887f, 0.00852f, - 0.0002384f, 0.007866f, -0.002577f, 0.0007524f, -0.004887f, -0.0003715f, 0.00564f, 0.008606f, -0.009705f, - -0.009796f, -0.001706f, -0.00965f, 0.00824f, 0.0009446f, -0.00514f, 0.00492f, 0.002787f, 0.00643f, - -0.0002482f, 0.003603f, 0.004097f, 0.00916f, -0.005463f, -0.003786f, 0.00269f, -0.00688f, 0.002872f, - 0.0079f, 0.002403f, -0.000562f, 0.00747f, -0.00349f, 0.004925f, -0.009f, -0.003199f, -0.0008674f, - 0.004513f, 0.001112f, 0.00242f, -0.003345f, -0.00588f, -0.001415f, 0.001788f, -0.00345f, -0.007744f, - 0.005596f, -0.00871f, -0.001603f, -0.0001678f, -0.00862f, 0.00929f, -0.005604f, 0.00986f, 0.005383f, - 0.00959f, 0.00005203f, -0.002613f, 0.000881f, 0.00828f, -0.00738f, 0.001506f, 0.000615f, -0.001396f, - 0.005566f, -0.00815f, -0.00447f, 0.002577f, -0.00938f, -0.0007024f, 0.000968f, 0.00785f, 0.001473f, - -0.004387f, 0.008286f, -0.003094f, 0.008125f, -0.004494f, -0.00425f, 0.004585f, -0.00964f, 0.002777f, - -0.00888f, 0.005466f, 0.00231f, -0.001025f, -0.009186f, 0.004265f, 0.002234f, -0.002064f, 0.006973f, - -0.007336f, 0.001036f, -0.00965f, -0.003597f, 0.000792f, -0.006615f, 0.00904f, 0.00902f, -0.004856f, - -0.00782f, -0.0004456f, 0.004826f, -0.001932f, 0.003588f, -0.001571f, -0.003286f, -0.00523f, -0.002085f, - 0.004658f, 0.00324f, -0.00974f, 0.007122f, -0.00806f, -0.003452f, -0.00996f, 0.0004315f, -0.004436f, - 0.00442f, 0.0003521f, -0.0000391f, 0.00986f, 0.007553f, 0.00816f, 0.004242f, -0.00706f, 0.00857f, - -0.009705f, -0.00789f, 0.006126f, 0.00494f, 0.001126f, -0.003017f, -0.0005965f, -0.00928f, 0.001935f, - -0.00866f, -0.002542f, 0.003275f, 0.0001297f, -0.00935f, 0.005028f, 0.004097f, -0.006817f, 0.00791f, - 0.0001851f, -0.002525f, 0.00906f, 0.000608f, 0.0004106f, -0.00859f, -0.005623f, -0.00567f, 0.00434f, - 0.004124f, 0.000519f, 0.00947f, -0.002487f, -0.00738f, 0.009346f, -0.004936f, 0.007263f, -0.00096f, - 0.00493f, -0.00823f, 0.003119f, -0.0003824f, 0.0007586f, 0.006584f, 0.00392f, -0.008125f, 0.006313f, - 0.007812f, -0.005913f, 0.005547f, -0.0001316f, -0.007523f, 0.00768f, 0.00142f, 0.00912f, -0.003622f, - 0.00852f, 0.005966f, -0.004467f, -0.00919f, -0.00866f, -0.00875f, -0.0000665f, 0.000144f, 0.00649f, - 0.003706f, -0.001643f, -0.003508f, -0.005817f, -0.0059f, 0.008896f, 0.0088f, -0.005962f, -0.003698f, - -0.003626f, 0.001465f, 0.003386f, 0.002172f, 0.00159f, 0.003794f, 0.00751f, 0.001184f, -0.0008216f, - -0.006474f, 0.00761f, -0.006603f, 0.005993f, 0.003044f, 0.00322f, -0.00928f, -0.00667f, -0.00599f, - 0.00869f, 0.001393f, -0.006184f, -0.002693f, 0.003727f, -0.003624f, 0.002987f, -0.002718f, -0.001762f, - -0.007366f, -0.00294f, -0.004993f, -0.00977f, 0.00814f, -0.001241f, 0.001603f, -0.00352f, -0.004997f, - -0.005177f, -0.002817f, 0.002464f, 0.00763f, 0.00547f, -0.007217f, -0.00507f, 0.000908f, -0.000513f, - 0.001423f, -0.0006895f, 0.001677f, 0.001864f, -0.00401f, -0.003475f, 0.00604f, -0.003687f, -0.008606f, - -0.00724f, -0.0061f, 0.002502f, -0.00612f, -0.003128f, 0.000557f, 0.001442f, -0.007397f, -0.0088f, - -0.0009484f, 0.007244f, -0.008804f, -0.00847f, -0.00967f, 0.00989f, 0.00872f, -0.005753f, 0.003027f, - 0.0014105f, 0.007397f, -0.005905f, 0.007214f, 0.005665f, 0.001882f, -0.002838f, -0.003008f, -0.00795f, - -0.000239f, 0.0064f, 0.005333f, 0.005028f, 0.006863f, -0.004f, -0.00592f, -0.001575f, 0.005398f, - 0.009575f, -0.003317f, 0.00983f, -0.0006003f, 0.005287f, 0.009094f, -0.00502f, -0.00495f, -0.00962f, - 0.000787f, 0.005604f, -0.006504f, 0.002504f, -0.004066f, -0.009766f, -0.0074f, -0.00766f, 0.009705f, - 0.00814f, -0.005157f, -0.001017f, -0.008316f, -0.00004405f, -0.00802f, -0.004677f, -0.004894f, -0.00705f, - 0.00784f, 0.00448f, -0.007553f, -0.0028f, -0.006226f, 0.0000136f, -0.004192f, -0.00755f, 0.00278f, - 0.00343f, -0.0006332f, -0.00343f, -0.004555f, -0.0093f, 0.00261f, 0.00926f, -0.005093f, 0.00627f, - -0.00848f, -0.00984f, -0.001426f, -0.00226f, -0.002077f, -0.001703f, 0.009636f, 0.007664f, -0.003628f, - 0.002018f, -0.006012f, -0.00473f, 0.003834f, 0.00939f, -0.00827f, -0.00812f, -0.00792f, 0.00924f, - 0.00776f, 0.001537f, -0.00287f, -0.002401f, -0.00831f, -0.00903f, 0.00591f, 0.003252f, -0.006348f, - 0.001455f, 0.00674f, -0.002382f, 0.0003512f, -0.0017185f, 0.00684f, 0.00665f, 0.00782f, -0.00969f, - 0.00418f, 0.00442f, 0.00979f, 0.006382f, 0.004642f, 0.00398f, 0.007797f, 0.005234f, -0.005566f, - -0.00903f, 0.003168f, -0.005596f, 0.00006646f, 0.00995f, -0.002335f, -0.00548f, 0.005383f, -0.004562f, - 0.00811f, -0.005035f, 0.0008745f, -0.0086f, -0.00786f, -0.00566f, -0.0096f, -0.000744f, 0.00511f, - -0.003363f, 0.002739f, 0.002033f, 0.005455f, -0.001077f, 0.003887f, 0.00735f, 0.00757f, 0.008965f, - -0.002888f, 0.002462f, 0.000919f, 0.0008416f, -0.003096f, 0.00875f, -0.002434f, 0.00318f, -0.002779f, - 0.00725f, 0.005062f, 0.00073f, 0.00845f, 0.003576f, 0.002874f, -0.00836f, -0.00859f, 0.00916f, - -0.00745f, 0.00869f, 0.001855f, 0.005814f, -0.002064f, 0.0066f, -0.009346f, 0.004307f, -0.00966f, - 0.00877f, -0.002394f, -0.00977f, 0.002356f, -0.008255f, 0.001052f, 0.00495f, -0.00963f, 0.00886f, - -0.00476f, -0.00917f, -0.000619f, -0.00593f, 0.005497f, 0.003141f, 0.002428f, 0.003363f, 0.001099f, - 0.00731f, -0.005577f, 0.00666f, -0.00328f, 0.004677f, 0.00761f, -0.00864f, -0.00873f, -0.00282f, - -0.004177f, 0.00867f, -0.00536f, 0.004387f, -0.007294f, -0.0099f, 0.001112f, -0.001063f, 0.004284f, - 0.000729f, 0.005604f, 0.00434f, 0.00563f, -0.00618f, 0.00464f, 0.004417f, 0.00524f, -0.00052f, - -0.002462f, -0.000902f, 0.005207f, -0.002256f, 0.000805f, -0.006252f, 0.003262f, 0.007603f, -0.000191f, - 0.003582f, -0.002598f, -0.003662f, -0.005585f, -0.00007087f, -0.00784f, -0.001778f, 0.00996f, -0.00643f, - 0.009796f, -0.002966f, 0.005848f, -0.003027f, -0.007587f, -0.003654f, -0.00882f, -0.001206f, -0.005836f, - -0.0089f, -0.00608f, -0.003944f, -0.000564f, -0.00329f, 0.000377f, 0.000702f, 0.000859f, 0.002554f, - 0.001499f, 0.005997f, 0.0006666f, -0.00584f, 0.005337f, -0.00734f, 0.006847f, 0.00829f, 0.003925f, - -0.00837f, -0.005886f, -0.006927f, -0.000641f, -0.0000388f, 0.003124f, 0.007427f, 0.00767f, -0.002771f, - -0.005985f, 0.002094f, -0.007442f, -0.001377f, 0.003183f, 0.0003796f, 0.0068f, 0.0008273f, -0.002102f, - 0.003433f, -0.00931f, 0.0003903f, -0.00771f, -0.000703f, 0.003122f, 0.00833f, 0.001467f, 0.00769f, - -0.004578f, -0.007393f, 0.0054f, -0.007797f, -0.003767f, -0.009735f, -0.0007954f, 0.005028f, -0.00809f, - 0.002352f, -0.0002111f, 0.003624f, 0.00502f, 0.001048f, 0.00922f, 0.003426f, 0.002258f, -0.00708f, - 0.00517f, -0.00919f, -0.00881f, -0.00548f, 0.00891f, 0.00919f, 0.00597f, 0.001098f, 0.004875f, - 0.004875f, 0.00846f, 0.00829f, 0.003426f, 0.001049f, 0.00669f, 0.003994f, 0.006195f, -0.004585f, - -0.001221f, -0.000247f, -0.00613f, -0.00613f, 0.00436f, 0.006775f, -0.001169f, -0.001771f, -0.001071f, - -0.003635f, -0.004475f, -0.00216f, -0.003502f, 0.002285f, -0.006702f, 0.0074f, 0.004845f, 0.00123f, - -0.00434f, -0.0082f, 0.0000914f, 0.00325f, -0.00717f, -0.003687f, 0.003479f, 0.005894f, -0.002655f, - 0.00833f, 0.002365f, -0.00927f, 0.006416f, -0.0031f, 0.009834f, 0.006855f, 0.004673f, 0.00857f, - -0.00627f, 0.00887f, -0.002636f, -0.0066f, -0.003975f, 0.003056f, -0.001572f, -0.005142f, 0.007393f, - 0.00863f, -0.000665f, -0.005146f, 0.008965f, 0.005505f, -0.001827f, -0.001454f, 0.002926f, -0.002275f, - -0.006184f, 0.00991f, -0.005035f, -0.003462f, 0.00855f, -0.009125f, 0.002832f, 0.005817f, 0.007187f, - 0.005844f, -0.003204f, -0.002201f, -0.0095f, -0.00862f, -0.00896f, 0.00543f, 0.00010115f, 0.00392f, - 0.004917f, -0.002266f, 0.0003471f, 0.006306f, -0.004726f, -0.002298f, 0.00234f, -0.004726f, 0.00924f, - -0.005363f, -0.0002112f, -0.0099f, 0.005604f, -0.00523f, -0.004627f, -0.001949f, -0.00936f, 0.002743f, - -0.001635f, 0.001984f, 0.00972f, -0.00359f, 0.003296f, 0.00074f, 0.004654f, 0.00995f, -0.001584f, - 0.003048f, 0.0006003f, -0.003628f, -0.007668f, -0.002537f, -0.006584f, 0.00576f, 0.00864f, -0.00899f, - -0.009636f, -0.005394f, 0.00433f, 0.00706f, 0.005005f, -0.004707f, 0.004597f, 0.00852f, 0.008835f, - 0.003904f, 0.00457f, 0.004128f, 0.005028f, -0.003986f, 0.005997f, 0.0002208f, 0.00777f, 0.00963f, - 0.005787f, 0.007023f, 0.00553f, 0.00449f, 0.005814f, 0.003082f, 0.0093f, 0.00472f, -0.00985f, - 0.00938f, 0.00558f, 0.007088f, 0.00391f, -0.00918f, 0.008415f, 0.00902f, 0.004173f, -0.002716f, - -0.009926f, -0.00801f, -0.009705f, -0.0086f, -0.009865f, 0.003788f, -0.0092f, 0.00887f, -0.001495f, - -0.00314f, -0.003246f, -0.000836f, 0.001646f, 0.00902f, -0.007233f, -0.00376f, -0.0057f, 0.005787f, - -0.002974f, 0.00872f, 0.0086f, -0.00443f, 0.003622f, 0.004593f, 0.008026f, -0.0003214f, 0.00858f, - -0.00338f, 0.00772f, 0.00448f, 0.00855f, 0.001066f, -0.004692f, -0.005737f, 0.007565f, -0.0002706f, - -0.002792f, -0.00949f, 0.000827f, -0.004967f, 0.00864f, 0.00788f, 0.009094f, -0.001957f, -0.002716f, - 0.000686f, -0.00499f, -0.004173f, 0.002407f, 0.00923f, 0.001411f, -0.0005016f, 0.00746f, -0.0087f, - -0.002703f, -0.003134f, -0.001611f, 0.007404f, -0.00999f, -0.004158f, 0.00556f, 0.0005794f, 0.003775f, - -0.001105f, -0.00338f, 0.00999f, 0.006966f, 0.005802f, -0.009735f, -0.009834f, -0.00723f, -0.00656f, - -0.007538f, 0.00995f, 0.00586f, 0.001463f, -0.001861f, -0.007015f, 0.005455f, -0.00492f, -0.005337f, - -0.00855f, -0.002764f, 0.003605f, 0.00967f, -0.007256f, -0.002594f, 0.00397f, -0.00508f, -0.004555f, - 0.009476f, -0.0006495f, 0.003998f, -0.0087f, 0.007294f, -0.007748f, 0.001855f, -0.0002816f, -0.00983f, - -0.007416f, 0.004444f, 0.003036f, 0.005066f, 0.001116f, -0.0001506f, -0.003181f, -0.003258f, -0.00816f, - 0.00821f, -0.0007715f, 0.00669f, 0.002674f, 0.004074f, 0.009605f, 0.001936f, -0.0052f, -0.002779f, - 0.003435f, 0.003592f, -0.00787f, 0.002615f, 0.007996f, 0.002047f, 0.002438f, 0.000739f, -0.002443f, - 0.00817f, 0.009995f, 0.00749f, 0.00953f, 0.007427f, -0.003246f, -0.004795f, 0.003834f, 0.0087f, - -0.00863f, 0.003105f, -0.003313f, -0.006187f, 0.005104f, -0.00093f, 0.004158f, 0.003963f, -0.00579f, - -0.004044f, 0.004044f, -0.0005593f, -0.00388f, -0.00249f, 0.006115f, 0.00322f, 0.007347f, 0.00813f, - -0.005142f, -0.0004606f, 0.00646f, 0.002186f, 0.00812f, 0.004818f, 0.0009236f, -0.00864f, 0.00948f, - -0.003057f, 0.003445f, -0.004444f, 0.001763f, -0.005806f, 0.001699f, 0.00843f, -0.007423f, -0.001351f, - -0.007317f, -0.001196f, 0.002996f, 0.005066f, 0.003227f, 0.00547f, -0.00923f, 0.0008106f, 0.00789f, - -0.006508f, -0.0003939f, -0.002443f, 0.007107f, -0.00692f, -0.007645f, -0.00353f, 0.00661f, 0.000988f, - -0.00769f, -0.003134f, 0.002548f, 0.00495f, 0.0034f, 0.001454f, 0.00344f, -0.00323f, -0.006203f, - 0.001063f, 0.008736f, -0.00737f, 0.00234f, -0.00315f, -0.008865f, -0.003918f, 0.006042f, 0.0003307f, - -0.001405f, 0.002129f, -0.00682f, 0.000836f, -0.005436f, 0.008385f, -0.002783f, -0.0007734f, -0.007088f, - -0.005924f, 0.00951f, 0.000002f, -0.00504f, -0.005474f, -0.00897f, 0.00339f, -0.003044f, 0.0019245f, - 0.00596f, 0.00756f, -0.005936f, 0.007416f, -0.005173f, 0.006367f, 0.0015545f, -0.001073f, 0.008095f, - 0.004868f, 0.0000308f, -0.005302f, -0.0003858f, -0.00421f, -0.00386f, 0.00925f, 0.004604f, 0.001006f, - -0.004482f, 0.00634f, -0.006126f, -0.00878f, 0.0095f, -0.006985f, -0.00575f, -0.001845f, -0.002335f, - 0.00908f, 0.00764f, -0.00405f, 0.003431f, 0.004726f, 0.0002171f, -0.005314f, -0.00693f, 0.00867f, - 0.0007024f, -0.007217f, 0.006042f, -0.0002111f, 0.00475f, -0.00635f, 0.00984f, 0.00829f, -0.0008802f, - -0.005093f, -0.007996f, -0.003607f, -0.00965f, -0.001188f, -0.002707f, 0.002533f, 0.00328f, -0.004807f, - -0.002724f, -0.005733f, 0.007996f, -0.003893f, -0.0002323f, -0.00577f, -0.007263f, 0.00416f, -0.007385f, - -0.004906f, 0.002007f, -0.00773f, -0.0004334f, -0.00542f, -0.0009217f, 0.008545f, 0.0005693f, 0.0094f, - -0.000956f, -0.002106f, -0.0082f, -0.006363f, 0.00431f, -0.001059f, -0.0054f, 0.002123f, 0.0004594f, - -0.003489f, -0.005173f, -0.007595f, 0.007782f, -0.0001341f, 0.00977f, -0.00463f, -0.0002378f, -0.002296f, - 0.00667f, 0.00701f, 0.001323f, -0.001699f, 0.00955f, -0.0091f, 0.0089f, 0.00791f, -0.0003197f, - 0.007835f, -0.00828f, 0.00854f, 0.00239f, 0.008385f, 0.001974f, 0.000486f, 0.00991f, 0.006542f, - 0.007866f, -0.004803f, -0.004913f, -0.00513f, -0.0004153f, 0.00995f, -0.00516f, -0.003317f, 0.00682f, - 0.0004165f, -0.00903f, -0.005344f, 0.00786f, 0.003769f, 0.004158f, 0.0002446f, 0.00589f, -0.002949f, - 0.0073f, -0.002398f, -0.004757f, 0.0002432f, -0.00439f, -0.00454f, 0.000453f, 0.00823f, -0.009575f, - 0.00535f, -0.008575f, -0.00893f, 0.004303f, 0.00502f, 0.00617f, -0.004402f, 0.00919f, -0.00865f, - 0.00876f, 0.003645f, 0.0002997f, -0.00925f, -0.007076f, 0.004448f, 0.005196f, -0.003986f, 0.007084f, - -0.000285f, -0.002855f, -0.000422f, -0.00872f, -0.005013f, 0.00952f, -0.008446f, -0.004044f, -0.00907f, - 0.007072f, -0.00918f, -0.007835f, 0.000878f, -0.006847f, -0.006f, 0.00731f, -0.001876f, -0.002565f, - -0.003584f, -0.003006f, -0.00723f, -0.003433f, 0.0004973f, -0.00795f, 0.0005007f, 0.00608f, 0.00671f, - 0.0001765f, 0.00439f, -0.003738f, -0.006035f, 0.00010353f, -0.00374f, 0.0008683f, 0.00773f, -0.0004847f, - -0.000992f, 0.004658f, -0.003555f, -0.0056f, -0.001982f, 0.00812f, 0.003386f, -0.001584f, 0.003508f, - -0.006138f, -0.00587f, 0.001421f, -0.009094f, -0.00468f, -0.0086f, 0.003637f, 0.00896f, 0.00804f, - -0.00744f, 0.002382f, -0.0097f, 0.000659f, 0.007782f, 0.002981f, -0.00869f, 0.0000934f, -0.00882f, - 0.002771f, -0.009544f, 0.0035f, 0.004124f, -0.0014f, -0.006294f, -0.007614f, 0.00931f, 0.009674f, - 0.0003185f, -0.004295f, 0.007084f, -0.0035f, -0.00334f, -0.001754f, 0.001216f, -0.004375f, 0.003244f, - 0.0001901f, 0.001547f, 0.007183f, 0.006447f, 0.005108f, 0.00679f, 0.001068f, -0.00587f, 0.005745f, - -0.00634f, 0.0058f, 0.006985f, -0.000697f, 0.00008917f, 0.007835f, -0.0004838f, 0.004795f, -0.006832f, - 0.002398f, 0.00687f, -0.001582f, 0.00709f, -0.00908f, -0.001573f, 0.009865f, -0.001476f, -0.000526f, - 0.00477f, 0.008026f, -0.00171f, 0.00979f, -0.005592f, 0.0006247f, -0.00774f, 0.00463f, -0.006676f, - 0.004368f, -0.002373f, -0.005127f, -0.0013275f, -0.002306f, -0.0087f, 0.00997f, 0.005493f, 0.003786f, - -0.004414f, -0.005947f, 0.003181f, -0.0004156f, 0.00909f, -0.00656f, 0.001926f, 0.0003731f, -0.009636f, - 0.003124f, -0.0000686f, -0.001972f, -0.006584f, 0.0009604f, 0.004086f, 0.009865f, 0.001302f, -0.00989f, - -0.0086f, 0.005177f, 0.006493f, -0.00523f, -0.00443f, 0.001586f, 0.00937f, 0.007458f, 0.001883f, - 0.00774f, 0.0004454f, 0.000493f, 0.0003722f, -0.00486f, 0.006435f, 0.002642f, 0.00432f, -0.00272f, - -0.007446f, -0.007397f, 0.00361f, 0.003618f, 0.003956f, -0.001175f, 0.00832f, 0.00794f, 0.001658f, - 0.00123f, -0.003918f, 0.001215f, -0.007427f, 0.003708f, 0.00492f, -0.00968f, 0.008896f, -0.006786f, - -0.005856f, 0.006573f, 0.003876f, -0.003983f, 0.00411f, 0.0076f, -0.0008364f, -0.00496f, 0.008026f, - -0.00986f, -0.001429f, -0.007236f, -0.002172f, -0.003004f, -0.0017185f, -0.00353f, -0.00817f, -0.004353f, - -0.003458f, 0.002663f, -0.00599f, 0.002125f, -0.00625f, -0.00913f, -0.009796f, -0.004574f, -0.00978f, - -0.00398f, -0.006096f, 0.003708f, 0.007214f, 0.00444f, 0.003742f, 0.004547f, 0.006042f, 0.001542f, - 0.002424f, 0.0005617f, 0.006477f, -0.002382f, 0.0009637f, -0.00462f, -0.000934f, 0.0004268f, 0.00975f, - 0.002277f, 0.001031f, -0.007103f, 0.006615f, 0.00199f, 0.009f, 0.00995f, -0.002514f, -0.0016575f, - -0.00875f, 0.00936f, -0.007133f, 0.007412f, -0.001572f, -0.00862f, -0.00675f, 0.009445f, -0.00819f, - 0.004597f, -0.005493f, 0.004894f, -0.004807f, 0.00346f, -0.00114f, 0.006638f, -0.005882f, 0.0041f, - -0.002684f, -0.0006037f, -0.00842f, 0.001939f, -0.0008016f, 0.00265f, -0.005383f, 0.00963f, 0.0063f, - 0.006386f, 0.004463f, -0.004173f, -0.006317f, 0.003534f, -0.00781f, -0.001414f, -0.004723f, -0.003096f, - -0.001367f, 0.00955f, -0.0000178f, -0.007214f, 0.00985f, -0.003782f, 0.005688f, -0.002445f, 0.00185f, - 0.00784f, 0.00203f, 0.0003746f, -0.00935f, 0.00559f, 0.00718f, 0.005905f, 0.002926f, 0.006268f, - 0.0002078f, 0.001244f, 0.00467f, 0.006405f, -0.0005364f, 0.00503f, -0.0004387f, 0.006252f, -0.002594f, - 0.001791f, -0.00807f, -0.001451f, -0.0034f, 0.00958f, 0.003035f, -0.00348f, 0.004818f, 0.008644f, - -0.0005145f, -0.004673f, 0.008934f, 0.00756f, -0.001786f, -0.005634f, -0.002981f, -0.007107f, 0.001145f, - 0.003677f, 0.004997f, 0.009766f, 0.0005856f, -0.002384f, 0.004177f, -0.00965f, 0.005924f, -0.005596f, - 0.004505f, 0.000578f, 0.00663f, -0.006638f, 0.001535f, 0.002502f, 0.002907f, 0.00447f, 0.002016f, - 0.008865f, 0.00828f, -0.00975f, 0.0002487f, -0.00796f, -0.008286f, -0.002083f, -0.00471f, 0.007187f, - 0.004326f, 0.007206f, 0.004307f, 0.009346f, -0.00758f, -0.007545f, 0.00349f, 0.0018425f, -0.00837f, - -0.007935f, -0.002258f, 0.003757f, -0.0014f, 0.000081f, 0.00449f, -0.000318f, 0.006485f, -0.001184f, - -0.001842f, 0.009476f, 0.00818f, -0.00986f, 0.001612f, -0.00779f, 0.006676f, -0.0013075f, 0.00464f, - -0.002117f, -0.0087f, 0.00965f, 0.001394f, 0.00818f, -0.005493f, 0.004673f, -0.00439f, -0.00557f, - -0.001841f, -0.00948f, 0.00607f, 0.00551f, -0.002834f, 0.004883f, -0.00712f, 0.006573f, -0.002064f, - 0.0008054f, -0.006508f, 0.004467f, 0.00773f, 0.004787f, 0.00523f, -0.001751f, -0.005657f, 0.000278f, - -0.001822f, -0.00639f, -0.003477f, -0.006767f, -0.007782f, 0.005375f, -0.00726f, 0.007248f, 0.0008335f, - -0.001856f, -0.00009865f, -0.006054f, 0.006786f, -0.005665f, -0.007393f, -0.0007014f, -0.007046f, -0.0065f, - -0.00645f, 0.002195f, 0.004818f, 0.00909f, -0.00862f, 0.007614f, -0.00499f, 0.007423f, -0.001478f, - -0.005028f, -0.007107f, -0.00488f, 0.00322f, -0.003801f, 0.0018425f, 0.001862f, 0.007713f, -0.008675f, - 0.001135f, 0.00788f, -0.006866f, -0.00776f, 0.001423f, -0.00392f, -0.00908f, 0.00918f, -0.006706f, - -0.00828f, -0.00358f, -0.00956f, -0.00823f, 0.00656f, -0.00617f, -0.004395f, 0.002705f, -0.001398f, - 0.003265f, 0.007793f, 0.00664f, 0.009285f, 0.00851f, 0.00416f, -0.00923f, -0.006733f, 0.00934f, - -0.00564f, -0.001064f, 0.001106f, 0.00943f, 0.005024f, 0.00793f, -0.005302f, -0.00376f, -0.0005045f, - 0.005325f, -0.002134f, -0.001494f, -0.00891f, -0.00803f, 0.00958f, -0.0000229f, -0.003668f, 0.00602f, - -0.003649f, -0.002918f, 0.006573f, 0.005146f, -0.009995f, 0.00864f, -0.008255f, 0.004868f, 0.001078f, - -0.003546f, 0.00235f, 0.005764f, -0.005116f, 0.009186f, -0.008255f, -0.00216f, -0.008f, -0.009125f, - -0.002754f, -0.0083f, -0.002539f, -0.0007524f, -0.00843f, 0.003647f, -0.00156f, 0.00498f, -0.007904f, - -0.00502f, 0.00919f, 0.003862f, 0.00599f, 0.001332f, -0.00788f, 0.007374f, 0.001653f, -0.00406f, - -0.008545f, -0.00444f, -0.00971f, -0.002436f, -0.009834f, -0.005573f, -0.002323f, -0.007126f, 0.004803f, - -0.00913f, 0.002483f, -0.004704f, -0.0014515f, -0.001035f, -0.008934f, -0.001855f, -0.0071f, 0.00979f, - -0.008255f, 0.001663f, -0.001383f, 0.000364f, -0.003595f, -0.002163f, 0.002136f, 0.004894f, 0.006966f, - 0.00925f, 0.006557f, -0.0089f, -0.0007167f, 0.002699f, 0.003483f, 0.003017f, 0.004223f, 0.006042f, - -0.002342f, -0.004868f, 0.003157f, 0.006165f, 0.001519f, -0.00874f, -0.004856f, -0.004116f, 0.002634f, - -0.001233f, -0.008736f, 0.003529f, -0.001974f, 0.00121f, -0.0006013f, -0.002737f, -0.00596f, 0.007027f, - -0.00496f, -0.002726f, -0.00787f, 0.001581f, 0.00381f, -0.004932f, 0.007027f, -0.003616f, -0.000989f, - 0.003532f, 0.002346f, 0.0000479f, 0.002907f, -0.004353f, 0.005424f, 0.003124f, 0.00985f, 0.003f, - -0.007805f, 0.001684f, -0.001324f, 0.0005107f, 0.00483f, -0.00992f, 0.000786f, -0.003649f, -0.0006337f, - -0.001443f, 0.00782f, 0.008194f, -0.00819f, -0.00844f, -0.004906f, -0.006355f, 0.002932f, 0.004242f, - 0.000638f, -0.00259f, 0.00585f, -0.00864f, 0.00378f, -0.00279f, -0.00319f, -0.001805f, -0.002768f, - -0.0007725f, -0.004875f, 0.003784f, 0.00947f, -0.008736f, 0.003262f, -0.00325f, -0.003826f, 0.007904f, - 0.00002706f, 0.006187f, -0.001488f, -0.001711f, -0.003317f, 0.007446f, -0.00699f, -0.005573f, 0.00164f, - 0.00938f, 0.0002334f, 0.003819f, -0.001427f, 0.00992f, -0.003433f, -0.0006833f, -0.00492f, 0.005493f, - 0.003014f, -0.006187f, -0.002325f, 0.00741f, -0.009056f, 0.005604f, -0.003874f, 0.00869f, 0.0001504f, - 0.005356f, 0.001178f, 0.00786f, 0.003292f, 0.00947f, -0.002808f, -0.00424f, -0.00999f, 0.004818f, - 0.00372f, -0.003748f, 0.001496f, 0.009796f, 0.0000038f, 0.00379f, 0.0003746f, -0.004147f, 0.007195f, - -0.0095f, 0.001072f, 0.002129f, 0.00889f, 0.003273f, 0.006958f, -0.004894f, 0.0006795f, 0.00892f, - -0.004356f, 0.00594f, -0.002378f, 0.00969f, -0.0081f, 0.0003927f, 0.00789f, 0.00343f, 0.00479f, - -0.0005517f, -0.00652f, 0.000332f, 0.00876f, -0.001309f, -0.002495f, -0.00831f, 0.007786f, -0.00512f, - -0.003832f, -0.0006423f, -0.003162f, 0.00807f, -0.006298f, -0.003601f, 0.002438f, 0.0017395f, 0.002686f, - -0.001712f, 0.00424f, 0.00632f, -0.00935f, 0.000598f, 0.005714f, -0.00921f, -0.002935f, 0.008064f, - -0.001802f, -0.002634f, -0.006786f, 0.00976f, 0.00867f, 0.004066f, 0.002306f, 0.001495f, -0.0003717f, - -0.00597f, 0.00958f, -0.00881f, 0.00856f, -0.00538f, -0.008575f, -0.003626f, 0.006702f, 0.00932f, - 0.001552f, 0.0006847f, 0.00159f, 0.002314f, 0.008606f, 0.005955f, 0.00862f, 0.0003278f, 0.003115f, - -0.006863f, -0.0051f, -0.00824f, 0.00592f, -0.005653f, 0.00871f, -0.008286f, 0.0005655f, -0.005154f, - -0.008766f, 0.008896f, -0.009674f, 0.003782f, -0.000774f, 0.00323f, -0.00935f, 0.007694f, -0.003578f, - -0.00912f, 0.007362f, -0.00561f, 0.00817f, -0.00852f, -0.00006425f, -0.003166f, 0.0004108f, 0.006325f, - -0.00928f, -0.008026f, -0.003891f, -0.005924f, -0.004284f, 0.00515f, -0.00749f, 0.002983f, 0.003885f, - 0.006535f, -0.001574f, 0.005695f, -0.009155f, -0.006996f, -0.0012665f, 0.002983f, -0.00932f, -0.00575f, - -0.008545f, -0.0005817f, 0.002466f, -0.003382f, 0.007477f, 0.00166f, 0.004562f, -0.001331f, -0.0095f, - -0.00291f, 0.002815f, -0.009796f, -0.00496f, 0.005592f, -0.00365f, -0.00609f, 0.0008597f, 0.00516f, - 0.003986f, 0.002157f, 0.00934f, -0.003363f, 0.000835f, 0.003725f, 0.002106f, -0.005993f, 0.00795f, - 0.003122f, -0.003313f, -0.005383f, 0.0004141f, 0.006466f, 0.003517f, -0.00809f, 0.005714f, -0.007294f, - -0.001924f, -0.002457f, -0.001897f, -0.001449f, 0.00543f, 0.000466f, 0.008125f, -0.002316f, 0.003128f, - -0.008255f, -0.001908f, 0.00911f, 0.00793f, -0.001612f, -0.00899f, -0.004013f, -0.002962f, 0.001639f, - -0.006916f, -0.009056f, -0.005795f, -0.001411f, -0.00745f, 0.003126f, 0.000916f, -0.0007496f, 0.003273f, - 0.005184f, 0.004128f, 0.003195f, -0.004635f, 0.004826f, 0.00745f, 0.006348f, -0.008865f, -0.00217f, - 0.006275f, -0.00971f, 0.005478f, -0.003456f, 0.0065f, 0.00943f, -0.005703f, 0.002666f, -0.005745f, - -0.006134f, 0.003513f, 0.00683f, -0.004803f, -0.003841f, -0.006435f, -0.007122f, 0.001902f, 0.005844f, - 0.007313f, 0.004723f, 0.001233f, -0.00402f, 0.001288f, 0.002878f, 0.004196f, -0.002884f, -0.007454f, - 0.000933f, -0.003576f, -0.005608f, -0.00908f, 0.00426f, 0.001788f, -0.004856f, -0.008965f, -0.00546f, - -0.004684f, -0.002708f, -0.006145f, 0.002111f, -0.000599f, -0.007187f, -0.002018f, -0.001014f, -0.006676f, - -0.00335f, -0.00528f, -0.009224f, -0.009285f, -0.00063f, -0.0045f, -0.005157f, 0.008865f, 0.008835f, - -0.00672f, 0.002237f, 0.002687f, 0.005703f, 0.00585f, 0.007175f, -0.007496f, 0.0002145f, 0.00924f, - -0.00611f, -0.003202f, -0.0057f, -0.001237f, 0.006752f, 0.001596f, -0.001424f, 0.007492f, 0.00459f, - -0.00668f, -0.001726f, 0.00209f, 0.001924f, 0.0008316f, 0.0004334f, 0.001638f, 0.005665f, 0.000911f, - -0.00552f, 0.00619f, -0.00979f, 0.00549f, 0.004967f, 0.00818f, -0.006157f, -0.00816f, 0.001334f, - 0.0002472f, 0.00653f, 0.005257f, 0.0000934f, -0.00261f, 0.00755f, 0.000494f, 0.001341f, 0.00236f, - -0.00876f, 0.005054f, -0.00503f, 0.007465f, -0.005676f, 0.003174f, -0.006325f, -0.005238f, -0.005608f, - 0.0002413f, -0.003477f, -0.00379f, -0.002457f, 0.002943f, -0.006855f, 0.001733f, 0.006504f, -0.004406f, - -0.00929f, -0.00009567f, 0.000722f, 0.001004f, -0.00633f, 0.001915f, -0.001345f, -0.002802f, -0.00858f, - -0.001694f, -0.000937f, 0.004486f, -0.00567f, 0.000247f, 0.007782f, -0.0036f, -0.003588f, 0.00717f, - -0.00928f, 0.00838f, -0.0063f, 0.00916f, 0.005352f, 0.00736f, 0.00083f, -0.007248f, -0.005722f, - 0.00325f, -0.00503f, 0.001647f, 0.007767f, -0.00539f, 0.0065f, -0.002151f, 0.003359f, 0.0002371f, - -0.007057f, 0.000602f, 0.00692f, -0.008415f, -0.001443f, 0.006783f, -0.00778f, 0.00946f, -0.002735f, - -0.006832f, 0.00419f, -0.009315f, 0.00963f, -0.003994f, -0.00833f, 0.00411f, 0.0076f, 0.005817f, - -0.001542f, -0.003956f, 0.004513f, 0.001667f, -0.002378f, -0.003075f, 0.002481f, -0.001739f, -0.005566f, - -0.002113f, 0.003263f, -0.00797f, -0.008675f, 0.006916f, 0.002848f, 0.008446f, -0.004627f, -0.002216f, - -0.0005455f, -0.00882f, 0.00846f, 0.001422f, -0.000527f, -0.00826f, 0.0012245f, 0.006226f, -0.008316f, - 0.002134f, -0.006298f, 0.00672f, -0.008026f, 0.003248f, 0.0046f, 0.001113f, 0.000221f, 0.000791f, - 0.00836f, 0.007805f, 0.006355f, 0.004723f, 0.000991f, -0.00904f, 0.007164f, 0.00896f, 0.00788f, - 0.004128f, -0.003473f, -0.00242f, 0.003466f, 0.003286f, 0.002634f, 0.009865f, 0.006947f, -0.0004823f, - -0.005455f, 0.003603f, 0.002008f, -0.004536f, 0.006187f, 0.005722f, -0.00010717f, 0.00227f, 0.00967f, - -0.004883f, -0.0011015f, 0.009285f, 0.002121f, -0.006718f, 0.00782f, 0.00481f, 0.002974f, -0.002855f, - -0.001182f, -0.000961f, -0.002497f, -0.005707f, -0.00536f, -0.000726f, -0.004868f, -0.000473f, -0.002764f, - 0.0002033f, -0.00961f, -0.00828f, -0.001335f, 0.005314f, 0.007263f, 0.005386f, -0.0006895f, 0.00444f, - -0.00443f, 0.001597f, 0.00753f, 0.005608f, 0.002354f, 0.00399f, 0.003551f, 0.0035f, 0.00319f, - 0.0017185f, -0.006195f, -0.004467f, 0.006042f, -0.007217f, -0.00907f, 0.004025f, -0.00671f, -0.002226f, - -0.00557f, 0.000518f, -0.00805f, 0.008865f, -0.007195f, -0.004032f, -0.005047f, 0.007072f, -0.003544f, - -0.00706f, -0.000232f, -0.00829f, -0.00835f, -0.002449f, 0.002384f, -0.00886f, -0.00177f, -0.00641f, - 0.006733f, -0.001213f, -0.005184f, 0.009995f, 0.006573f, 0.003773f, -0.00962f, 0.003693f, 0.003815f, - 0.004353f, 0.00224f, 0.0003662f, 0.007187f, 0.00817f, -0.002918f, -0.006615f, 0.00834f, 0.002783f, - -0.000913f, 0.004993f, -0.006687f, -0.008224f, 0.00864f, -0.000776f, -0.003668f, 0.002398f, 0.001138f, - 0.001902f, -0.004894f, 0.00398f, 0.001741f, -0.00922f, 0.002316f, 0.0000156f, 0.00923f, -0.004314f, - 0.00844f, -0.002323f, -0.001928f, 0.006115f, 0.006283f, -0.001401f, -0.006443f, 0.00693f, 0.007225f, - 0.0005593f, -0.00996f, -0.00842f, -0.001854f, 0.001111f, 0.00157f, -0.003658f, -0.0003986f, 0.005455f, - 0.004204f, -0.006065f, 0.00812f, -0.00642f, -0.004932f, -0.00778f, 0.004032f, 0.005814f, 0.00329f, - -0.007164f, -0.00576f, 0.002708f, -0.005424f, -0.006355f, -0.003983f, -0.006695f, -0.00661f, 0.005814f, - -0.007137f, -0.00739f, -0.001341f, 0.000845f, 0.000429f, -0.002764f, 0.006496f, 0.00785f, -0.00622f, - 0.003235f, 0.00425f, -0.00612f, 0.00803f, 0.007404f, -0.001365f, 0.002625f, 0.001886f, 0.003359f, - -0.00518f, -0.002394f, 0.00475f, 0.003391f, 0.00693f, -0.002079f, -0.000818f, -0.002357f, -0.005272f, - -0.002317f, -0.000729f, 0.004074f, 0.005486f, 0.006023f, -0.006363f, 0.00527f, -0.003586f, -0.00925f, - 0.003809f, 0.00087f, 0.007133f, -0.001788f, 0.002201f, 0.00955f, 0.003735f, 0.007324f, -0.00614f, - -0.007187f, -0.006783f, -0.006145f, -0.004665f, 0.007175f, 0.00984f, 0.00314f, 0.008064f, 0.007336f, - -0.00337f, -0.00559f, 0.004944f, -0.007744f, -0.00197f, -0.006714f, -0.002281f, -0.002087f, 0.0009074f, - -0.00753f, 0.004993f, 0.00319f, -0.002535f, -0.001945f, 0.0008793f, -0.003357f, 0.004246f, -0.00838f, - 0.007698f, 0.001307f, 0.001717f, 0.00824f, -0.001335f, -0.0002145f, 0.00561f, -0.007168f, -0.001333f, - -0.00551f, -0.003637f, -0.007786f, 0.001738f, 0.007748f, 0.001321f, -0.001924f, 0.006046f, -0.009125f, - 0.009674f, 0.006313f, 0.002666f, 0.002287f, -0.00956f, -0.004803f, -0.008675f, 0.003038f, -0.00514f, - 0.00935f, 0.006756f, 0.004425f, 0.002203f, 0.00642f, 0.004555f, 0.00657f, 0.00157f, 0.00652f, - -0.000512f, 0.003416f, 0.00883f, -0.003372f, -0.001136f, -0.00302f, 0.007435f, -0.00564f, 0.001519f, - -0.007687f, -0.00783f, -0.008736f, 0.003899f, -0.00231f, 0.006927f, 0.00558f, -0.007786f, 0.008156f, - 0.004417f, -0.004173f, 0.008865f, 0.004707f, 0.002438f, -0.008896f, 0.00009686f, -0.00338f, 0.002985f, - 0.0000722f, 0.004047f, 0.00991f, 0.00222f, 0.00381f, -0.003147f, 0.0081f, 0.00392f, 0.001678f, - -0.00647f, 0.00942f, -0.002876f, -0.001987f, -0.00758f, -0.003983f, -0.00814f, 0.00255f, -0.001071f, - 0.006855f, -0.00676f, -0.00801f, 0.00399f, 0.002998f, 0.003906f, -0.002068f, 0.005444f, -0.003128f, - 0.001452f, -0.000623f, 0.007122f, -0.003498f, -0.000979f, -0.003366f, -0.001828f, 0.004135f, 0.006786f, - -0.003593f, -0.00814f, -0.00749f, -0.004894f, 0.009445f, -0.00828f, -0.005108f, -0.005836f, -0.002945f, - -0.008125f, -0.001417f, -0.003443f, 0.00201f, 0.001321f, 0.00578f, 0.00224f, -0.00895f, -0.001515f, - -0.008194f, 0.00883f, -0.000655f, -0.00831f, 0.005695f, 0.00663f, 0.00704f, -0.00393f, 0.003603f, - -0.005608f, 0.00107f, -0.00902f, -0.0001382f, 0.006287f, 0.006393f, 0.0005302f, 0.00898f, 0.00172f, - 0.0033f, -0.001728f, -0.004436f, 0.006794f, 0.001925f, -0.00698f, 0.002726f, -0.00372f, 0.003744f, - 0.007004f, 0.002556f, -0.00895f, -0.005096f, 0.003044f, -0.002342f, -0.00802f, 0.0067f, 0.006172f, - 0.0005546f, 0.009f, 0.006405f, 0.003557f, -0.006527f, 0.002508f, -0.002115f, -0.00497f, 0.004852f, - 0.002605f, 0.009155f, -0.00941f, 0.000894f, -0.00825f, 0.005333f, 0.006023f, -0.001292f, 0.009445f, - -0.007217f, 0.003368f, -0.007156f, -0.006386f, -0.00293f, 0.00218f, -0.00803f, 0.00927f, 0.008965f, - 0.001402f, 0.00525f, -0.00784f, 0.00418f, -0.00978f, -0.003138f, 0.002974f, 0.001657f, -0.009834f, - 0.001901f, -0.00948f, 0.005455f, -0.001604f, 0.00559f, 0.006447f, 0.0008035f, -0.002773f, 0.006332f, - -0.00896f, 0.00488f, 0.004177f, -0.00319f, 0.00708f, 0.0003064f, -0.0007687f, -0.003065f, 0.005558f, - -0.003864f, 0.003887f, -0.00855f, 0.006237f, 0.008415f, -0.002693f, -0.002817f, -0.00904f, 0.003407f, - 0.000946f, -0.00738f, -0.00562f, -0.0009713f, -0.003506f, -0.00766f, 0.00953f, -0.004005f, 0.00867f, - 0.0004733f, -0.005787f, 0.0005293f, 0.006996f, 0.001659f, 0.000469f, 0.001537f, 0.002247f, -0.004242f, - 0.00243f, -0.004093f, -0.007355f, -0.001f, 0.006374f, -0.004963f, 0.006035f, 0.005245f, -0.00839f, - 0.002262f, -0.008286f, 0.00845f, 0.00911f, -0.001388f, -0.001848f, -0.0008616f, 0.006363f, 0.002584f, - -0.002827f, -0.00755f, -0.009834f, 0.002735f, -0.001286f, 0.006f, 0.001821f, -0.001493f, -0.00819f, - -0.0003796f, 0.008606f, 0.000496f, 0.001856f, -0.00668f, -0.009186f, -0.00736f, 0.0048f, -0.003502f, - 0.001626f, -0.0001339f, -0.006126f, -0.00596f, -0.0001252f, 0.001953f, 0.009575f, -0.001304f, 0.004192f, - -0.006035f, -0.001251f, 0.007587f, 0.001031f, -0.00928f, 0.00793f, 0.00653f, 0.0007644f, -0.002647f, - 0.003609f, -0.00461f, 0.000423f, -0.000656f, 0.005367f, -0.00425f, 0.004215f, 0.006554f, 0.005634f, - -0.001172f, 0.00472f, -0.0002402f, 0.003582f, 0.00738f, 0.00301f, 0.005417f, 0.009254f, 0.007145f, - -0.0094f, 0.000404f, 0.00837f, -0.00894f, 0.004658f, 0.0004907f, -0.001399f, -0.00873f, 0.0008955f, - -0.001738f, -0.001934f, 0.003742f, 0.002077f, -0.004063f, -0.007736f, -0.001259f, 0.00867f, 0.00488f, - 0.006584f, -0.00822f, -0.00585f, 0.006927f, -0.003298f, -0.004593f, 0.000567f, -0.004543f, -0.007378f, - 0.00718f, -0.00876f, 0.005707f, 0.00701f, 0.001537f, 0.005993f, -0.0044f, 0.00847f, 0.00694f, - 0.00419f, -0.00511f, 0.00535f, 0.000936f, -0.0007434f, 0.001556f, -0.0008616f, -0.0085f, 0.003342f, - 0.00982f, 0.005077f, 0.005566f, -0.003716f, 0.00839f, 0.007786f, -0.00749f, -0.007614f, -0.00774f, - 0.00209f, 0.005894f, -0.007534f, 0.003998f, -0.00518f, -0.00033f, -0.00831f, -0.00556f, 0.004837f, - -0.001809f, -0.00423f, 0.00916f, -0.006786f, 0.009476f, 0.00841f, -0.000718f, 0.002834f, -0.00947f, - 0.0001942f, -0.007904f, -0.003672f, -0.001356f, -0.004658f, -0.005825f, 0.002747f, -0.00737f, 0.00845f, - 0.005226f, -0.002941f, -0.005226f, -0.00415f, 0.00848f, 0.0007825f, -0.005276f, 0.003502f, -0.005974f, - 0.00866f, -0.0076f, 0.003042f, -0.003267f, -0.00536f, -0.006935f, 0.007515f, 0.008255f, 0.003098f, - -0.007183f, 0.007355f, -0.00878f, -0.0001291f, -0.0009227f, 0.000577f, 0.00787f, 0.003855f, 0.005337f, - -0.004837f, 0.005676f, 0.004658f, -0.00798f, 0.006424f, -0.007534f, 0.002682f, -0.003042f, 0.00868f, - -0.003332f, 0.00318f, 0.00199f, 0.001096f, 0.00871f, 0.005028f, -0.001416f, 0.006233f, -0.007736f, - 0.00808f, -0.001244f, 0.001611f, 0.005127f, 0.00781f, -0.003036f, -0.00453f, -0.00516f, 0.007233f, - -0.001684f, -0.002474f, 0.002844f, -0.00723f, -0.002401f, 0.0015f, -0.005444f, -0.003035f, -0.00929f, - 0.00947f, 0.00247f, 0.004017f, 0.0008864f, -0.003862f, 0.0062f, -0.00172f, -0.00449f, 0.00796f, - 0.009445f, 0.007687f, -0.007034f, -0.001731f, -0.00585f, -0.005653f, -0.002281f, 0.004925f, -0.006744f, - -0.002542f, 0.005775f, 0.00861f, 0.003054f, 0.00666f, -0.00694f, -0.00822f, -0.001123f, 0.006557f, - -0.00476f, 0.006397f, 0.00957f, 0.00888f, -0.003952f, -0.006313f, 0.001164f, 0.001948f, -0.00758f, - 0.007263f, -0.00801f, 0.00924f, 0.009476f, -0.00979f, 0.007748f, -0.00533f, 0.006195f, 0.00659f, - 0.003437f, 0.00546f, -0.00859f, 0.002409f, -0.006824f, -0.006172f, 0.00663f, 0.004215f, 0.00291f, - 0.001303f, -0.007786f, -0.000654f, 0.00965f, -0.002867f, 0.002117f, 0.00484f, -0.002012f, -0.004826f, - -0.00801f, -0.00259f, 0.002625f, -0.000174f, 0.006844f, -0.005554f, -0.001617f, 0.00741f, -0.00145f, - -0.001762f, 0.005222f, 0.001931f, 0.006676f, -0.002014f, 0.005676f, -0.001987f, 0.003426f, -0.00088f, - 0.002485f, -0.007698f, -0.00604f, 0.006687f, -0.003902f, -0.00783f, -0.00817f, 0.00841f, 0.006134f, - -0.00659f, -0.004807f, 0.00649f, -0.00855f, -0.00605f, -0.003489f, 0.00594f, -0.00818f, -0.001544f, - 0.003778f, 0.00706f, -0.0002632f, 0.005882f, 0.003763f, 0.003439f, 0.00872f, 0.004265f, 0.00522f, - -0.00886f, -0.00803f, -0.0003037f, -0.00807f, -0.006756f, 0.00789f, -0.00428f, -0.000516f, 0.005196f, - -0.00981f, 0.00926f, -0.007507f, -0.00952f, -0.00259f, -0.003004f, 0.00828f, -0.000515f, -0.00759f, - -0.002186f, -0.00375f, -0.00902f, 0.002289f, -0.002497f, 0.00996f, 0.004932f, -0.00803f, -0.00785f, - 0.00993f, -0.007694f, 0.000255f, -0.0002395f, -0.005318f, 0.005173f, 0.00518f, -0.007427f, 0.00505f, - 0.008545f, -0.00238f, -0.002556f, 0.00932f, 0.009094f, -0.002436f, -0.00971f, 0.000679f, 0.00931f, - -0.00531f, 0.003595f, 0.0065f, -0.001422f, 0.002657f, 0.00864f, 0.001987f, -0.001189f, -0.0007544f, - 0.0002537f, -0.003994f, -0.00898f, -0.00314f, -0.00829f, 0.006683f, -0.006706f, -0.005634f, 0.00001407f, - 0.006878f, 0.004093f, 0.001739f, -0.003754f, 0.006306f, -0.001363f, -0.00145f, -0.00985f, -0.003508f, - -0.007454f, 0.00352f, -0.004467f, -0.00601f, -0.007763f, -0.00894f, 0.00583f, -0.00698f, 0.0099f, - -0.006313f, 0.00404f, -0.002666f, -0.00373f, 0.004604f, -0.00813f, -0.006283f, 0.004066f, -0.00592f, - -0.0003827f, -0.002565f, 0.006275f, 0.008705f, -0.007404f, 0.00793f, -0.0009556f, 0.001682f, 0.00866f, - 0.00774f, 0.00332f, 0.0008507f, -0.005215f, -0.00757f, -0.001497f, 0.005787f, 0.001453f, -0.001265f, - -0.00909f, 0.006832f, 0.00836f, 0.002867f, 0.002851f, 0.002344f, 0.001552f, -0.0006785f, -0.00941f, - -0.007114f, -0.003008f, 0.002539f, 0.0002484f, -0.00774f, 0.000987f, 0.00991f, 0.00611f, 0.0009437f, - -0.001054f, 0.000739f, 0.00809f, -0.003117f, -0.007812f, -0.001368f, -0.009674f, -0.001733f, 0.006268f, - 0.003513f, 0.00852f, -0.007652f, 0.004547f, -0.0001137f, 0.003424f, 0.000804f, -0.003584f, -0.00599f, - -0.005333f, -0.00303f, 0.004303f, 0.009f, -0.0006638f, -0.0008726f, 0.007774f, -0.0000234f, -0.0002577f, - 0.005783f, -0.008316f, -0.00841f, -0.003605f, 0.001991f, 0.006767f, 0.00508f, 0.00787f, 0.003464f, - 0.00908f, 0.007133f, 0.007504f, -0.00896f, 0.000183f, -0.00929f, -0.0009255f, -0.0034f, -0.00848f, - 0.002066f, 0.0002947f, 0.005394f, 0.002613f, 0.00701f, -0.00833f, -0.001219f, 0.004704f, 0.00446f, - -0.00775f, 0.00476f, -0.007195f, -0.00163f, -0.003307f, -0.007484f, -0.00889f, -0.00846f, 0.008156f, - -0.002731f, 0.005733f, 0.0099f, -0.00276f, -0.00869f, -0.00962f, -0.00841f, -0.004955f, 0.004997f, - 0.008896f, 0.00907f, -0.000695f, 0.00972f, 0.00685f, 0.004505f, -0.00726f, -0.003025f, -0.002087f, - 0.00797f, 0.006016f, -0.006485f, -0.00491f, 0.001922f, -0.00934f, 0.006355f, -0.0004008f, -0.005714f, - 0.002274f, -0.005512f, 0.005424f, -0.0003483f, 0.001698f, 0.0006733f, 0.00815f, -0.005264f, 0.002876f, - -0.0000476f, -0.003105f, -0.001815f, -0.00997f, 0.0004442f, -0.00557f, -0.007656f, -0.003036f, 0.002333f, - -0.001329f, 0.003675f, -0.00706f, -0.00807f, 0.001302f, -0.00788f, 0.003828f, -0.00995f, -0.006676f, - -0.001514f, -0.005756f, -0.001301f, 0.002438f, 0.007313f, 0.00913f, 0.003407f, -0.002222f, 0.00981f, - 0.0012245f, 0.009155f, 0.008194f, -0.004368f, -0.006615f, -0.0008593f, -0.00582f, 0.003933f, 0.005173f, - -0.001201f, 0.002068f, -0.00915f, 0.00797f, -0.002686f, -0.00958f, 0.005775f, 0.002453f, -0.003305f, - 0.00697f, 0.0001255f, 0.00218f, 0.009926f, -0.007473f, 0.007965f, 0.0066f, -0.003874f, 0.00658f, - -0.007618f, 0.000942f, 0.002375f, -0.007053f, -0.003815f, 0.00569f, -0.001039f, 0.004536f, 0.003641f, - 0.004314f, -0.003353f, 0.00857f, -0.0006385f, -0.000856f, -0.007175f, 0.007557f, -0.00978f, 0.002863f, - -0.005424f, 0.005215f, -0.000666f, -0.006275f, 0.005527f, 0.00827f, -0.006187f, -0.005993f, 0.000444f, - -0.0001373f, 0.00458f, 0.009315f, -0.005093f, -0.00154f, 0.002647f, 0.00586f, 0.007473f, -0.00275f, - 0.00046f, 0.008965f, -0.0002766f, 0.00485f, -0.00974f, 0.001143f, -0.00859f, -0.00027f, 0.007748f, - -0.00341f, -0.006992f, -0.006664f, 0.0005536f, 0.00828f, -0.003752f, 0.000553f, 0.008575f, 0.004868f, - -0.0004208f, -0.001359f, 0.002785f, 0.00247f, 0.0002398f, 0.00441f, -0.007866f, -0.00444f, 0.000598f, - 0.00985f, 0.0041f, 0.001188f, -0.00271f, -0.003817f, -0.0008373f, -0.004078f, 0.00927f, -0.002739f, - -0.004578f, 0.004482f, 0.000669f, -0.003761f, -0.00921f, -0.003477f, -0.00516f, -0.00893f, 0.0007854f, - 0.00305f, 0.004894f, 0.00165f, -0.009834f, -0.00859f, 0.000812f, -0.007256f, -0.00276f, -0.003006f, - 0.001255f, -0.002705f, 0.005894f, 0.00904f, 0.004845f, 0.00814f, -0.003206f, 0.007042f, -0.003756f, - -0.003365f, -0.00868f, 0.00358f, -0.009514f, 0.00952f, -0.005753f, 0.00848f, 0.003448f, 0.006912f, - -0.001069f, -0.0006742f, 0.00974f, -0.001088f, -0.0004857f, 0.00841f, 0.006027f, -0.00606f, -0.001904f, - -0.006058f, -0.004673f, 0.007572f, -0.009674f, -0.008896f, -0.002888f, -0.00806f, 0.00633f, -0.000787f, - -0.002151f, 0.002234f, -0.00991f, 0.00663f, -0.00541f, -0.006706f, -0.00598f, -0.00592f, 0.0001597f, - 0.001887f, -0.00104f, 0.00994f, 0.0083f, -0.009415f, -0.00954f, 0.0003498f, -0.009254f, 0.002195f, - 0.003555f, -0.007557f, 0.006336f, -0.00789f, -0.006927f, 0.005497f, -0.003809f, -0.002302f, -0.00952f, - -0.0007987f, -0.001707f, 0.00007784f, -0.006718f, -0.005337f, 0.008934f, 0.006355f, 0.006626f, 0.00514f, - 0.006844f, -0.005447f, -0.001604f, -0.0008254f, -0.004185f, -0.006702f, -0.001056f, -0.00847f, -0.005917f, - -0.002684f, -0.00482f, -0.009514f, 0.004032f, 0.003906f, 0.0048f, -0.004612f, 0.000876f, -0.00497f, - 0.008415f, -0.00986f, -0.00565f, -0.000717f, -0.003967f, -0.006863f, 0.00825f, -0.003292f, -0.00966f, - 0.00263f, 0.001377f, -0.0084f, 0.004414f, -0.0054f, 0.00609f, -0.009026f, -0.000778f, -0.008385f, - 0.008286f, -0.00352f, 0.00549f, 0.00738f, -0.007515f, -0.002409f, -0.00558f, -0.003153f, -0.005985f, - -0.00919f, 0.00001955f, 0.004105f, -0.0009418f, 0.001782f, 0.0007043f, -0.00539f, -0.004562f, -0.003515f, - -0.00916f, -0.00623f, 0.0002017f, -0.003117f, 0.00392f, 0.00738f, 0.001152f, -0.00806f, -0.005108f, - 0.00985f, -0.001203f, 0.00719f, 0.001182f, -0.0002191f, -0.00661f, -0.003593f, -0.001818f, 0.00765f, - 0.004604f, -0.005318f, -0.0009274f, 0.002466f, -0.0003357f, 0.00783f, -0.006584f, -0.00664f, 0.003544f, - -0.002964f, -0.00983f, 0.001785f, -0.000708f, -0.00793f, 0.00785f, 0.006046f, 0.007812f, 0.0096f, - 0.00849f, -0.001343f, 0.00623f, -0.007465f, 0.001237f, -0.00393f, -0.0007534f, -0.004776f, -0.002806f, - 0.00451f, -0.004726f, 0.00364f, 0.002312f, -0.00561f, -0.00462f, -0.001799f, -0.0005593f, 0.00191f, - -0.002151f, -0.0076f, 0.001353f, 0.001949f, -0.004097f, 0.005615f, 0.002104f, 0.00746f, -0.00824f, - -0.006596f, 0.009285f, -0.008026f, 0.00331f, -0.008736f, -0.00988f, -0.002468f, 0.003393f, -0.007675f, - -0.00852f, 0.0067f, 0.00552f, 0.00002897f, 0.0002024f, -0.004135f, 0.003683f, -0.001939f, -0.002998f, - -0.006897f, -0.00462f, 0.00989f, 0.001207f, 0.001254f, -0.0008793f, -0.004036f, -0.00255f, 0.00871f, - 0.00695f, 0.00251f, 0.005455f, -0.00592f, -0.001793f, -0.0005703f, -0.00213f, 0.004787f, -0.0025f, - -0.00712f, -0.003109f, -0.0074f, 0.003607f, -0.003696f, -0.001566f, 0.007812f, -0.004433f, 0.001471f, - 0.004066f, -0.001959f, -0.001853f, -0.00985f, 0.006023f, 0.006184f, -0.00586f, -0.002455f, 0.007687f, - -0.003036f, -0.001865f, 0.0052f, -0.005646f, 0.002298f, -0.0049f, -0.001856f, -0.003754f, -0.003891f, - 0.00979f, 0.008415f, -0.00886f, 0.009926f, 0.001531f, -0.001119f, -0.004818f, 0.007763f, -0.004997f, - 0.009415f, 0.002409f, 0.00149f, 0.003786f, -0.001091f, -0.00852f, 0.00888f, 0.0092f, 0.004227f, - 0.004055f, -0.001675f, -0.004677f, 0.003109f, 0.006733f, 0.00538f, 0.0086f, 0.002913f, -0.00939f, - -0.006355f, 0.00495f, -0.007866f, 0.00885f, 0.005394f, -0.00323f, 0.00578f, -0.00476f, 0.006634f, - -0.00769f, 0.001916f, -0.001957f, 0.00988f, 0.004417f, -0.00677f, 0.007565f, 0.00842f, -0.00919f, - -0.0055f, 0.003214f, 0.00413f, -0.00813f, 0.002834f, 0.005272f, -0.00954f, 0.006275f, -0.00836f, - 0.00561f, 0.00951f, 0.004837f, 0.00753f, 0.000762f, -0.002527f, -0.003277f, -0.00522f, 0.003021f, - 0.00706f, -0.008f, -0.00916f, -0.002863f, 0.002209f, -0.00828f, 0.00499f, -0.001951f, -0.002157f, - 0.004375f, 0.006233f, -0.007336f, -0.0002134f, 0.004395f, -0.004135f, -0.00865f, 0.001095f, 0.003302f, - -0.00732f, 0.002275f, 0.00976f, 0.002602f, -0.003263f, 0.00766f, 0.003126f, 0.001476f, -0.001589f, - 0.00351f, 0.007305f, 0.00553f, 0.007236f, -0.005352f, -0.006542f, -0.002747f, -0.002932f, -0.002441f, - -0.008575f, -0.00934f, -0.00197f, -0.004387f, 0.001285f, 0.003265f, 0.001039f, 0.004814f, -0.001674f, - -0.00887f, 0.003067f, -0.007866f, 0.00903f, 0.003162f, -0.004402f, 0.00029f, 0.00928f, -0.002539f, - -0.003176f, 0.002398f, 0.004284f, 0.001891f, -0.000756f, 0.00846f, 0.00686f, 0.001065f, -0.008934f, - -0.00705f, 0.002884f, -0.006603f, -0.004486f, 0.00396f, -0.009766f, -0.003494f, 0.004738f, 0.00899f, - 0.006016f, 0.007515f, 0.003511f, -0.00786f, 0.00949f, -0.00682f, 0.004265f, 0.00728f, 0.0047f, - 0.00902f, -0.00474f, -0.0005236f, 0.005547f, -0.002396f, -0.006386f, -0.007904f, 0.00722f, 0.005135f, - 0.000564f, -0.003956f, -0.00997f, -0.00982f, 0.001334f, 0.001509f, -0.002422f, -0.001891f, 0.002316f, - 0.00309f, -0.006355f, 0.007336f, -0.00487f, 0.00010824f, -0.0008583f, 0.002853f, 0.003754f, -0.006348f, - 0.00793f, 0.00723f, -0.00981f, -0.003706f, 0.00317f, -0.008446f, -0.002966f, -0.0009055f, 0.002184f, - 0.003096f, 0.003244f, 0.009674f, 0.002132f, 0.0016165f, -0.006443f, -0.00423f, -0.00905f, 0.001218f, - 0.004185f, 0.00935f, -0.00193f, 0.00179f, 0.004192f, -0.006424f, 0.002945f, 0.0005383f, 0.004173f, - -0.001795f, 0.00803f, 0.006462f, -0.00502f, -0.003693f, 0.001283f, -0.001253f, 0.00715f, -0.002525f, - 0.00824f, -0.008995f, -0.00549f, 0.004345f, 0.002205f, 0.00827f, -0.004692f, -0.000714f, 0.00686f, - 0.003473f, 0.009636f, -0.001164f, -0.002003f, 0.00674f, -0.008224f, -0.00462f, 0.00948f, 0.002377f, - 0.00781f, 0.002586f, 0.00744f, -0.001399f, 0.003376f, 0.005226f, -0.003313f, 0.007713f, -0.004364f, - 0.0005984f, -0.004997f, 0.00611f, -0.00772f, 0.006653f, -0.002066f, 0.00196f, 0.004326f, 0.00797f, - -0.002724f, -0.005474f, 0.007782f, 0.00728f, 0.007442f, -0.002098f, 0.005306f, -0.007206f, -0.001974f, - 0.0000934f, -0.003695f, -0.007633f, 0.006306f, 0.006794f, -0.002983f, -0.00424f, 0.0018215f, 0.000337f, - -0.00849f, -0.00768f, 0.00659f, 0.002615f, -0.008514f, 0.00282f, 0.003607f, 0.009544f, 0.00924f, - 0.00949f, -0.006145f, -0.003231f, -0.001794f, 0.006004f, -0.0005646f, 0.005558f, 0.00455f, -0.005344f, - 0.003881f, -0.00979f, -0.00946f, -0.0007844f, 0.00922f, 0.001785f, 0.00854f, -0.0094f, -0.005318f, - 0.006126f, -0.0023f, -0.00576f, -0.00449f, -0.00931f, 0.006935f, -0.007477f, 0.001311f, 0.00797f, - 0.003727f, -0.000941f, -0.00816f, -0.00646f, -0.004032f, -0.002666f, 0.009735f, -0.007072f, -0.007362f, - 0.003067f, 0.007732f, 0.00457f, 0.001084f, -0.0085f, 0.00392f, 0.0006833f, -0.001245f, -0.00907f, - -0.00574f, -0.006786f, 0.005386f, -0.001034f, 0.00993f, 0.00913f, -0.001817f, 0.00613f, 0.002943f, - -0.00825f, -0.008804f, -0.00333f, -0.00754f, 0.00971f, -0.0002515f, 0.004715f, 0.006126f, 0.004963f, - 0.000591f, -0.00912f, -0.002254f, 0.0006866f, -0.00998f, 0.001433f, 0.00787f, -0.00933f, -0.004326f, - 0.00771f, 0.002146f, -0.006893f, -0.003952f, 0.001425f, -0.006123f, 0.00807f, -0.00702f, -0.006565f, - 0.001073f, 0.001927f, -0.004864f, 0.000273f, -0.008224f, 0.00826f, -0.001634f, -0.006905f, -0.00831f, - -0.00594f, -0.002901f, -0.001668f, -0.00987f, 0.006264f, -0.00452f, -0.00924f, 0.0096f, 0.001883f, - 0.005104f, 0.003798f, -0.00859f, 0.002163f, 0.000841f, 0.0001701f, -0.00549f, 0.008896f, -0.00641f, - -0.0086f, 0.0094f, -0.000762f, 0.000456f, 0.002989f, -0.002628f, -0.00817f, -0.000566f, 0.005928f, - -0.002151f, -0.004353f, -0.00403f, -0.0009055f, 0.00814f, -0.005325f, 0.001588f, -0.00841f, 0.001743f, - -0.00651f, -0.002144f, 0.007225f, -0.00623f, -0.002226f, -0.004345f, 0.007904f, -0.007748f, 0.001748f, - -0.003706f, -0.00867f, 0.00432f, -0.00954f, 0.0089f, -0.00607f, 0.00603f, 0.00857f, 0.003477f, - -0.0007524f, 0.000207f, -0.00069f, 0.00925f, -0.003777f, -0.0002985f, -0.001528f, 0.005077f, 0.007435f, - 0.005886f, -0.001046f, 0.00491f, -0.00346f, -0.00944f, 0.0085f, 0.00011885f, -0.007687f, 0.005142f, - -0.005444f, 0.005745f, 0.00565f, -0.005436f, 0.002954f, 0.0009327f, -0.001357f, -0.006035f, -0.0038f, - -0.00277f, 0.001201f, -0.006207f, 0.00892f, -0.00958f, 0.002432f, 0.009636f, -0.006413f, -0.000683f, - 0.000565f, 0.00664f, 0.006424f, 0.004097f, 0.00754f, -0.0082f, 0.002491f, 0.00003463f, -0.001084f, - 0.009895f, -0.001157f, -0.0044f, -0.003542f, -0.005615f, 0.00814f, -0.002285f, 0.009605f, 0.008865f, - 0.00906f, 0.0059f, -0.00735f, 0.0007353f, -0.00103f, -0.004868f, 0.007378f, 0.0074f, -0.001978f, - -0.00555f, -0.004807f, 0.006527f, -0.00968f, -0.001172f, -0.00988f, 0.00564f, 0.00213f, 0.004536f, - -0.001937f, 0.007717f, 0.00901f, -0.000779f, 0.003677f, -0.00831f, -0.005554f, -0.005386f, -0.00959f, - -0.00885f, 0.007416f, -0.00618f, 0.001828f, -0.0004594f, -0.0006585f, -0.009636f, 0.007168f, -0.00868f, - -0.00848f, -0.003803f, -0.00875f, 0.002884f, 0.0002168f, 0.005486f, 0.00989f, -0.00828f, 0.00000566f, - -0.00811f, -0.003649f, 0.003096f, 0.00365f, -0.002344f, -0.00879f, 0.006554f, -0.0003917f, 0.00814f, - -0.001268f, 0.00318f, 0.003078f, -0.002525f, -0.00848f, -0.0004594f, 0.003298f, 0.003225f, 0.002396f, - -0.00686f, -0.00503f, 0.007534f, 0.009636f, -0.00483f, -0.00788f, 0.004208f, 0.0003386f, -0.001907f, - 0.0008726f, 0.004757f, -0.00989f, -0.007004f, 0.0063f, -0.006622f, -0.00978f, 0.00899f, 0.002703f, - 0.00864f, -0.009964f, 0.00617f, 0.005688f, 0.00846f, 0.00576f, 0.00788f, 0.0002687f, 0.00853f, - -0.0002925f, -0.003065f, -0.0000076f, 0.007706f, 0.002523f, -0.00212f, -0.00532f, 0.007347f, 0.001383f, - -0.004616f, -0.008514f, -0.00672f, -0.00883f, 0.00195f, -0.003576f, -0.006306f, 0.005207f, -0.002554f, - -0.001393f, -0.005966f, 0.005707f, -0.001915f, -0.002625f, 0.007797f, 0.00756f, -0.003504f, -0.004597f, - -0.002932f, -0.006004f, -0.00928f, 0.006176f, 0.004486f, -0.00594f, -0.009476f, 0.006813f, -0.00312f, - -0.0014715f, 0.003428f, 0.00991f, -0.004757f, -0.0006704f, 0.001299f, 0.002937f, 0.005505f, 0.00843f, - -0.004585f, -0.00931f, 0.001348f, -0.008545f, 0.001818f, -0.002092f, -0.00689f, -0.009026f, 0.00949f, - 0.00166f, 0.000547f, -0.000135f, -0.000778f, -0.001905f, 0.002375f, 0.00974f, -0.004833f, 0.0094f, - 0.004898f, -0.00005084f, -0.001083f, -0.00499f, -0.00918f, -0.004326f, 0.001663f, 0.00681f, -0.003672f, - 0.00694f, -0.00438f, -0.007336f, 0.0089f, 0.00451f, -0.00564f, 0.00986f, 0.006157f, -0.00539f, - -0.00551f, 0.00947f, 0.00881f, 0.005436f, -0.008354f, -0.005894f, 0.002949f, 0.0009093f, -0.002594f, - -0.002369f, 0.00507f, -0.0088f, 0.0051f, -0.0004027f, 0.001238f, 0.00854f, 0.008804f, 0.0005126f, - 0.00786f, -0.001762f, -0.002861f, 0.001445f, -0.006268f, -0.002352f, -0.00737f, -0.006973f, 0.005512f, - 0.005188f, 0.00951f, -0.006603f, 0.002338f, -0.001549f, 0.000984f, 0.00819f, 0.002796f, -0.003716f, - -0.00731f, -0.004124f, -0.00725f, -0.002102f, 0.00493f, 0.00313f, -0.002922f, 0.0076f, 0.00537f, - -0.00929f, 0.00819f, 0.00932f, 0.00975f, 0.00345f, 0.001942f, 0.001167f, -0.003649f, -0.00787f, - 0.00857f, 0.00359f, 0.0015545f, -0.001327f, -0.00813f, 0.006893f, -0.00185f, -0.00689f, 0.00396f, - 0.003069f, -0.002464f, -0.003843f, 0.004967f, -0.00865f, -0.00503f, 0.003744f, 0.0003045f, 0.006298f, - 0.0011835f, 0.004654f, -0.00736f, -0.00171f, -0.00807f, -0.00462f, 0.00526f, 0.00905f, -0.006798f, - -0.0001366f, 0.00969f, -0.005116f, 0.007614f, -0.007317f, -0.0052f, 0.0007396f, 0.00735f, -0.00347f, - -0.002716f, 0.005177f, 0.003021f, -0.0026f, 0.00685f, -0.003214f, 0.001522f, -0.000601f, 0.00642f, - 0.002537f, 0.009705f, 0.0004787f, 0.00933f, 0.005848f, -0.00789f, -0.005962f, -0.003063f, 0.00734f, - 0.008644f, -0.00652f, 0.00389f, 0.00219f, -0.005104f, 0.004536f, 0.006638f, -0.00424f, -0.000966f, - -0.00242f, -0.003347f, 0.000761f, -0.006855f, -0.00816f, -0.00339f, 0.003853f, 0.00752f, 0.000502f, - 0.00394f, 0.00875f, -0.001621f, -0.00972f, -0.000609f, -0.00796f, -0.003817f, 0.004166f, 0.003754f, - -0.007385f, -0.001137f, -0.004467f, -0.001389f, 0.0093f, 0.003342f, -0.005795f, -0.00792f, 0.0082f, - 0.00557f, -0.00656f, 0.003494f, 0.002573f, 0.0014925f, -0.003141f, 0.002457f, 0.00789f, 0.0071f, - -0.004307f, 0.001407f, 0.000862f, -0.007122f, -0.005196f, -0.00306f, -0.00808f, -0.004246f, 0.00772f, - 0.006165f, 0.002718f, -0.00569f, -0.000952f, -0.005917f, 0.003725f, -0.0008345f, -0.00265f, -0.0063f, - 0.001651f, -0.00962f, 0.006016f, 0.005035f, -0.004337f, 0.00552f, 0.00373f, -0.0005794f, 0.00202f, - -0.006985f, -0.00747f, -0.001536f, -0.007122f, -0.00937f, -0.00641f, -0.00871f, -0.00182f, 0.0000921f, - 0.007484f, -0.00974f, 0.00521f, 0.001293f, 0.0006785f, -0.00888f, 0.005943f, -0.00055f, -0.00676f, - -0.0000759f, 0.00414f, 0.007065f, 0.0000026f, -0.003262f, -0.001492f, 0.00802f, 0.003487f, -0.00977f, - -0.006863f, -0.004192f, -0.007458f, -0.001814f, -0.004482f, 0.008835f, -0.004826f, 0.00872f, 0.004635f, - 0.007317f, -0.00498f, -0.003536f, -0.004375f, 0.005074f, -0.002346f, 0.00384f, 0.00853f, -0.00416f, - -0.007164f, 0.0006695f, 0.0008926f, -0.001899f, 0.005783f, 0.00535f, 0.00557f, -0.00402f, 0.00006354f, - -0.001951f, -0.002588f, -0.005276f, -0.001826f, -0.006058f, 0.001427f, -0.009735f, 0.009224f, -0.00006384f, - -0.002344f, -0.00004303f, 0.00946f, -0.00841f, -0.00199f, -0.00494f, -0.00841f, -0.008835f, 0.00596f, - -0.006348f, 0.007545f, 0.001068f, 0.00624f, -0.005306f, 0.001778f, -0.0009108f, -0.0048f, -0.000988f, - -0.0005326f, -0.005173f, 0.003748f, 0.001759f, -0.003914f, -0.006252f, 0.004486f, 0.00882f, 0.006035f, - -0.002064f, -0.003456f, -0.006615f, -0.004963f, 0.003847f, -0.00342f, 0.006115f, -0.005974f, 0.002302f, - -0.00856f, 0.006847f, -0.006416f, -0.00226f, 0.005363f, 0.008224f, -0.0003793f, -0.009224f, -0.002298f, - -0.005264f, -0.000623f, -0.00803f, -0.007706f, 0.001601f, 0.007046f, -0.004757f, 0.0044f, 0.0046f, - -0.003963f, -0.007156f, 0.0004344f, 0.005592f, -0.00053f, 0.001337f, 0.009186f, -0.00897f, -0.005627f, - -0.001647f, 0.0092f, 0.0016985f, -0.003633f, 0.008064f, 0.004543f, -0.00698f, -0.005695f, 0.00478f, - -0.001252f, 0.00881f, -0.00876f, -0.00202f, -0.009514f, 0.000278f, -0.005013f, 0.007404f, -0.0005183f, - -0.001753f, -0.00442f, 0.00199f, -0.008156f, -0.008865f, -0.00308f, -0.00973f, -0.005714f, 0.007996f, - -0.004395f, 0.00455f, -0.00862f, -0.0004373f, 0.00885f, 0.00984f, -0.00422f, 0.00382f, 0.001032f, - -0.0003273f, 0.004593f, 0.004982f, 0.00259f, -0.00604f, 0.000337f, 0.009186f, -0.003052f, -0.005085f, - 0.005188f, 0.00417f, 0.004345f, 0.003605f, -0.000079f, -0.009575f, 0.00894f, 0.00992f, 0.008f, - -0.00476f, 0.00871f, -0.007538f, -0.00739f, -0.0069f, -0.008804f, -0.00526f, -0.001096f, 0.0009003f, - 0.005367f, 0.005283f, 0.005047f, -0.0003638f, -0.001063f, -0.00399f, 0.0081f, 0.004395f, 0.00805f, - -0.00531f, 0.001779f, 0.003176f, 0.00775f, 0.0071f, 0.00682f, -0.0007925f, -0.00318f, 0.00897f, - -0.006172f, -0.00376f, -0.002518f, -0.007618f, 0.00728f, 0.007042f, 0.006863f, -0.005936f, 0.004787f, - 0.005726f, -0.0009775f, -0.004757f, -0.0002875f, 0.00844f, 0.005302f, 0.003609f, 0.005863f, 0.005436f, - 0.004433f, -0.002047f, 0.003025f, 0.007694f, -0.007565f, -0.006165f, -0.00202f, -0.004505f, -0.004784f, - 0.00921f, -0.00059f, 0.004604f, 0.002249f, -0.004814f, -0.00519f, -0.00625f, 0.0000181f, 0.00531f, - 0.001533f, 0.006847f, -0.00959f, -0.00846f, -0.00928f, -0.006386f, 0.002766f, -0.005516f, -0.0071f, - 0.006073f, 0.00907f, 0.005585f, -0.00644f, -0.00855f, -0.003466f, -0.009514f, -0.00914f, 0.003702f, - -0.00503f, -0.00497f, 0.00796f, -0.007763f, 0.007614f, 0.00544f, 0.00933f, 0.008316f, -0.003374f, - -0.00763f, 0.002035f, 0.002916f, -0.0006156f, -0.003872f, -0.0002236f, -0.00917f, -0.003334f, -0.004528f, - 0.00978f, -0.0005903f, -0.006786f, -0.00913f, -0.009254f, -0.006096f, 0.002638f, 0.003622f, -0.007805f, - 0.00873f, 0.001586f, -0.003641f, 0.001905f, -0.00311f, -0.000627f, 0.005222f, -0.004986f, 0.000169f, - -0.007088f, -0.00783f, -0.004852f, 0.000881f, 0.004627f, -0.00405f, -0.006405f, 0.003586f, 0.002258f, - -0.00988f, 0.000979f, -0.002949f, 0.00912f, 0.00885f, -0.002743f, 0.00833f, 0.003326f, -0.0003536f, - -0.003792f, -0.00941f, 0.000213f, -0.002922f, -0.001483f, -0.003443f, -0.00307f, -0.005894f, 0.003468f, - 0.001887f, -0.006832f, -0.00828f, -0.006172f, -0.00746f, 0.002558f, 0.00998f, 0.001123f, -0.00611f, - -0.005863f, -0.0007744f, 0.003525f, -0.00573f, 0.0009665f, -0.002241f, -0.0007176f, -0.00918f, -0.00794f, - 0.00216f, -0.0049f, 0.002016f, 0.006763f, 0.00445f, 0.004715f, 0.001216f, 0.002068f, -0.001449f, - 0.00249f, 0.00953f, -0.0007606f, -0.00256f, 0.0006046f, -0.004406f, -0.009415f, 0.003393f, -0.004787f, - 0.002743f, 0.00841f, 0.00972f, -0.00194f, 0.004185f, 0.00585f, 0.007504f, -0.00622f, 0.001107f, - -0.0044f, 0.00576f, 0.00772f, 0.00818f, 0.00536f, 0.002644f, -0.00465f, -0.0087f, -0.00816f, - 0.004547f, 0.001851f, -0.005634f, 0.003641f, 0.007618f, -0.00985f, 0.009766f, -0.00459f, -0.002457f, - 0.00393f, -0.008224f, -0.003952f, -0.00813f, 0.007393f, 0.005188f, 0.007126f, 0.00639f, 0.001274f, - 0.002176f, -0.00894f, 0.002445f, -0.001414f, -0.00952f, 0.004444f, -0.001607f, -0.001501f, 0.00857f, - -0.005585f, -0.000724f, 0.003077f, 0.007797f, 0.007473f, 0.003546f, -0.00948f, -0.003933f, 0.004017f, - -0.003176f, 0.001448f, 0.002731f, 0.003504f, 0.00831f, 0.007763f, 0.002405f, -0.006264f, 0.00536f, - -0.0083f, 0.001413f, -0.0003624f, -0.001836f, 0.006027f, 0.005173f, -0.003073f, -0.008354f, 0.00164f, - -0.001941f, -0.002981f, 0.008156f, -0.004414f, -0.005413f, 0.002527f, -0.0004022f, 0.00625f, 0.008575f, - 0.00637f, 0.00765f, 0.0003421f, 0.00798f, -0.005287f, 0.00808f, -0.00646f, 0.000603f, 0.00955f, - 0.00889f, -0.002356f, -0.005306f, 0.002333f, 0.009514f, -0.003855f, 0.0054f, 0.005417f, 0.000675f, - -0.004402f, 0.00933f, -0.005234f, -0.00958f, 0.0089f, 0.009254f, -0.00757f, 0.0098f, -0.001879f, - 0.00789f, 0.002071f, 0.000677f, -0.007763f, -0.001941f, 0.001637f, -0.003653f, 0.00528f, 0.007465f, - -0.00557f, -0.006004f, -0.009476f, 0.000802f, 0.002075f, -0.007168f, 0.00398f, -0.006268f, 0.006287f, - -0.009575f, -0.001453f, 0.0092f, -0.00995f, -0.002644f, 0.005024f, 0.00966f, -0.006878f, 0.00995f, - -0.001319f, -0.002237f, 0.002209f, 0.00861f, -0.00883f, -0.003874f, -0.002903f, 0.00992f, -0.0016365f, - -0.00633f, 0.00823f, -0.00771f, -0.003204f, -0.00563f, 0.00563f, 0.00805f, -0.004936f, 0.003477f, - 0.00741f, 0.0043f, 0.006905f}; + LoadTensor("Weight_64_3_64.weight_data", weight_data); } void GetBias_3_64(std::vector& bias_data) { - bias_data = { - -0.003569f, -0.00789f, 0.002047f, -0.002829f, -0.000592f, -0.003313f, 0.00805f, -0.007397f, -0.006844f, - 0.00809f, -0.003479f, -0.0017395f, 0.007904f, -0.009056f, 0.005806f, 0.008896f, 0.004585f, -0.002356f, - -0.003815f, -0.00673f, 0.005787f, -0.001892f, 0.003233f, 0.005566f, -0.007626f, 0.00835f, 0.009415f, - -0.005707f, -0.0002623f, -0.007496f, -0.003569f, -0.00568f, -0.000693f, 0.00857f, 0.006607f, 0.005245f, - -0.0006056f, 0.008896f, 0.0000753f, -0.0001878f, -0.00957f, -0.003975f, 0.003006f, -0.006794f, -0.007935f, - 0.004246f, 0.004948f, 0.008896f, -0.0046f, -0.002516f, -0.000887f, -0.004555f, 0.002409f, 0.00364f, - -0.002491f, 0.004204f, 0.00010544f, 0.000783f, 0.00895f, 0.005367f, -0.004097f, -0.00592f, 0.009834f, - 0.001047f, 0.00677f, -0.004974f, -0.003212f, 0.00771f, -0.002256f, -0.001008f, -0.008484f, -0.002802f, - 0.00462f, 0.001329f, 0.004562f, 0.006687f, 0.002615f, 0.001449f, -0.0006714f, -0.001256f, 0.0003803f, - -0.005238f, -0.004112f, 0.001925f, -0.002827f, -0.00861f, -0.004723f, -0.002748f, -0.006134f, -0.00342f, - -0.007168f, 0.006626f, 0.001948f, -0.003838f, 0.006878f, -0.001717f, -0.003347f, -0.006287f, 0.00455f, - -0.00136f, 0.004364f, 0.006573f, -0.007545f, -0.004845f, 0.00883f, 0.00572f, 0.00675f, -0.003206f, - -0.00842f, 0.006428f, 0.00394f, 0.000642f, -0.002016f, 0.004486f, 0.009964f, -0.00918f, -0.0084f, - 0.001972f, 0.002031f, -0.00976f, -0.004494f, 0.006958f, -0.00262f, 0.00874f, 0.009865f, 0.0075f, - -0.00271f, -0.006386f, 0.002562f, 0.006397f, 0.00699f, -0.001731f, 0.005432f, 0.00271f, -0.006447f, - -0.00892f, 0.002897f, -0.0004315f, 0.001859f, -0.003462f, 0.007122f, -0.005135f, 0.005363f, 0.0051f, - 0.00806f, 0.00721f, 0.00799f, 0.00945f, -0.006943f, 0.006393f, 0.00935f, -0.0003269f, -0.004536f, - -0.006752f, 0.0095f, 0.00628f, -0.00418f, 0.001624f, -0.005577f, -0.008606f, 0.005486f, 0.002077f, - 0.007378f, 0.004734f, 0.0035f, 0.00991f, -0.001775f, 0.00247f, -0.00613f, 0.007202f, -0.00596f, - 0.003876f, -0.00789f, 0.004505f, 0.004795f, -0.002575f, -0.002932f, -0.003098f, -0.005463f, -0.00912f, - -0.00729f, 0.004486f, 0.006138f, 0.006924f, -0.00722f, 0.00841f, -0.001812f, -0.00959f, -0.000497f, - -0.00513f, -0.006042f, 0.007645f}; + LoadTensor("Bias_3_64.bias_data", bias_data); } -void SampleAttentionWeight(std::vector& data, std::vector& output, int elements, int start_offset, int step) { +void SampleAttentionWeight(std::vector& data, std::vector& output, + int elements, int start_offset, int step) { int data_length = static_cast(data.size()); output.resize(elements); @@ -1436,471 +70,19 @@ void GetCrossAttentionData_HeadSize40(AttentionTestData& data) { data.sequence_length = 3; data.kv_sequence_length = 5; data.mask_type = AttentionMaskType::MASK_NONE; - { - data.query_data = { - -1.22662961f, -0.35233688f, -2.51795793f, 3.08565354f, 4.24220848f, -2.51427174f, - 2.22180820f, -1.92292845f, -0.35114169f, 1.70695090f, 1.69466066f, 0.27359068f, - -0.64067757f, -0.63457423f, 1.04695463f, 4.04613352f, 0.97944307f, 0.15350986f, - 1.67937851f, -1.36576056f, 0.77318615f, -1.27569389f, 4.60397625f, -3.19242692f, - 0.48934177f, -3.07935381f, -0.11483648f, 1.47204328f, -0.63523442f, 0.67073810f, - 2.80178523f, 2.67149448f, -2.81271029f, 2.68525839f, 4.68173981f, 2.91258001f, - 3.57226992f, -3.05520511f, 2.54316950f, 2.00077820f, -0.95679653f, -0.32389647f, - 3.40642309f, -3.41444898f, 0.42168373f, 3.71653891f, 1.74413025f, -2.31608653f, - -1.05382800f, 2.33529496f, -0.03115923f, -2.09196687f, 2.51712871f, 0.32415283f, - 1.06346369f, -0.36822113f, 4.68930340f, 0.46780801f, -3.73769474f, 0.48317379f, - 0.39232603f, 0.27411360f, -3.42274952f, 3.13843346f, -1.47643280f, 1.33143926f, - -1.77027559f, 0.64681566f, -2.24492526f, 0.45514423f, 3.05239010f, -2.77623415f, - -0.01523268f, -1.31303573f, -3.99167180f, -1.17848396f, 2.49592471f, 2.05467582f, - -4.28567028f, -0.01797819f, - 4.67106724f, 1.53385055f, 3.39424896f, 3.93220329f, 1.68718219f, 2.44518471f, - -2.88907123f, -0.35424405f, 3.01430655f, 2.46258259f, 0.76977682f, -0.16410893f, - -0.17463332f, -3.87755418f, 1.83313918f, -2.97483563f, -4.08703470f, -0.08439432f, - 5.29304314f, 1.78443372f, -3.78656173f, -2.07051849f, 1.88238001f, -5.19135237f, - 3.88775992f, -2.59292984f, -4.11207771f, 3.96229005f, -0.83118176f, -3.83982468f, - 2.46327686f, -2.20555806f, 2.71137404f, 0.36317801f, 0.03267325f, 1.49253511f, - -1.07765102f, -0.87420821f, -1.38492739f, -3.10283113f, -6.48412514f, -3.24393439f, - -3.83601141f, -4.89051533f, 2.25563264f, 2.33896637f, 3.08240438f, 0.25861615f, - 5.35156775f, -4.30155373f, -0.39909154f, 0.51361942f, 1.70603693f, 0.56104976f, - -0.53627640f, -1.02876902f, -1.52522588f, 3.84260535f, 0.69256341f, 6.54086208f, - 1.46197557f, -0.43632865f, -0.60465157f, -1.64424038f, 1.38061714f, 0.57246995f, - 1.95028961f, 1.26038134f, 2.30116510f, -0.49234268f, -2.46396661f, -3.20620775f, - -3.26575089f, 1.24299562f, 2.17106104f, -2.19775343f, 3.60124683f, 0.57973087f, - 1.07749140f, 4.91360235f, - -0.21669322f, 0.33139130f, 1.75449383f, 9.52622700f, 2.17485499f, -1.66917014f, - 0.03545052f, 4.18067980f, 0.00023159f, 1.33923185f, -0.87918806f, -3.50237155f, - -1.46006012f, 0.60015154f, 5.83271360f, -0.22819775f, -0.31121445f, 5.66988373f, - 0.79325175f, 0.96488249f, -1.70520842f, -0.63099504f, -0.57731283f, -0.83466154f, - -1.16551876f, 3.83186436f, -1.45056069f, 0.50383788f, -1.44579923f, 0.65660918f, - 2.41228318f, -1.77592456f, -0.22811326f, -1.30705166f, 1.98969173f, -4.51494265f, - -1.47827673f, -3.64490080f, 2.93946624f, 1.29824829f, -3.46210217f, -3.89081907f, - -1.48601687f, -1.11542952f, -1.94489884f, -0.12696570f, -0.23979390f, 3.19791436f, - -0.63295209f, 1.12001634f, -5.84728909f, 1.05678606f, -1.42075634f, 0.05558330f, - 4.61813593f, 0.36126173f, -1.55681753f, 1.49261308f, 1.44369054f, -1.89044309f, - 0.72794700f, 0.88410646f, 1.78280950f, 0.46480489f, -1.13712585f, 1.98804855f, - -0.50860095f, -0.82247877f, -0.84092993f, 0.15579975f, -0.83490044f, 1.40706611f, - -0.62802029f, -1.00020695f, -0.42161250f, 4.65616417f, -0.14566854f, -5.21770144f, - -1.80859923f, -1.88397610f, - - 0.72858512f, 0.76285082f, -3.54603267f, -2.76666427f, -0.74586105f, 3.07966805f, - -1.23183393f, 2.65814924f, -0.48954675f, -0.01422951f, -0.80523360f, -0.05636902f, - 4.50960302f, 0.39967048f, 2.12411642f, -2.80581498f, -1.23623741f, -0.83596331f, - -1.59570324f, 0.31865728f, -2.93341351f, -0.91071963f, -5.62822533f, -0.31141007f, - 3.66986752f, 0.29200572f, 4.50133896f, -0.04906014f, 0.30284458f, 2.08347201f, - -0.26345047f, 2.89623761f, 1.47789168f, 0.25719327f, 0.59193242f, 3.06752014f, - 0.77815592f, 5.36399746f, -0.98917627f, 0.74345785f, 0.37825125f, 0.39711678f, - -0.51693177f, 0.70721328f, -1.65618515f, 0.39366072f, -0.48523498f, 0.26791164f, - 0.74384177f, -0.01070565f, 2.06832695f, 4.09473038f, -1.93577170f, 4.44833660f, - -3.57158875f, 1.13177609f, 0.04097128f, 0.97592485f, 0.32749751f, -0.63181406f, - 1.32568705f, 4.11899281f, -0.01445001f, -3.27274179f, -0.33302760f, 1.99459851f, - -0.71278077f, -2.11359572f, -0.49344134f, 2.91824555f, -0.30017141f, 3.06603670f, - 0.70625454f, -1.72438312f, 1.29221559f, 2.61260676f, -3.74348974f, -0.74985051f, - 3.06313038f, 0.40784115f, - 3.00617576f, 0.60401130f, -2.26022601f, 2.65955663f, 4.51086712f, 3.18778396f, - -2.03404522f, -1.75254703f, 1.52366590f, 2.97461796f, -1.71983969f, 1.67460120f, - -1.67232358f, -4.60054970f, 1.20151567f, -1.35206270f, -2.52547383f, -0.32723871f, - 0.20907879f, 3.33950758f, 1.31350076f, 4.40201521f, 4.84729719f, -2.02246284f, - 2.26325178f, -4.70484352f, 1.19820619f, -2.06560230f, 2.01903844f, 0.70123076f, - -2.18283868f, -1.58728933f, -1.76427519f, 1.73031628f, -1.02397823f, -0.82483894f, - 4.28719187f, 1.03131247f, -4.00242376f, 0.55060416f, 0.69296157f, -0.40307230f, - -1.57899165f, -0.64626098f, 0.38460332f, -2.79192090f, -0.99241018f, -6.47022247f, - 2.35969114f, 2.68988562f, 2.01771092f, -0.50948638f, -4.10946798f, 1.78115523f, - 2.07683706f, 0.83665949f, -1.96493793f, 1.29946780f, 1.07797444f, 0.23147804f, - -2.62031913f, -2.29383564f, -0.75740218f, -2.22285056f, -1.37344193f, -0.63702244f, - -2.69008708f, -3.54949689f, -4.93013477f, 0.94476449f, 0.50843441f, -2.43133783f, - -0.73139656f, -4.14991760f, 2.21933579f, -0.23957914f, 0.21414763f, 1.72857785f, - -1.93757868f, 4.37800264f, - 2.67474079f, 2.48818779f, -1.69955230f, 3.70085597f, -3.42685413f, -2.94546223f, - 0.31883699f, -3.10525227f, -2.03184032f, -5.62139654f, 2.08026147f, 0.76601815f, - -2.61922121f, 1.76908946f, 0.33427981f, 0.48602962f, 0.68285787f, -2.60781908f, - -0.69706583f, 6.12323284f, -1.74903524f, 4.59135532f, 4.35664511f, -3.56304765f, - -0.38409889f, 1.03420079f, -0.45078808f, 0.69308978f, 0.21725583f, -5.65227365f, - 2.69256592f, 0.09329325f, -1.82679415f, -0.74413943f, 0.29465687f, 3.46686363f, - -1.47279978f, -0.97846490f, 2.22824383f, -1.11907578f, -1.49388766f, -3.98522091f, - -0.20471978f, -1.08247757f, 1.70455170f, 0.19429864f, 1.07981837f, -3.89726448f, - 1.63762915f, 0.33783519f, 0.79741430f, -2.02730107f, 0.82039660f, -5.06940222f, - 0.40322316f, 0.00218159f, -0.88644981f, 3.36438680f, -0.04906791f, 3.78314805f, - -0.40462697f, 1.39699149f, -4.14074135f, -0.21723330f, 0.92299151f, -1.46231139f, - 3.57588029f, 4.19913292f, 6.70203686f, 3.35416508f, -6.50804901f, 1.98294961f, - -2.87230039f, -2.51358604f, 1.91030347f, -1.50729156f, 5.15285301f, 4.33989143f, - -2.16627169f, -2.91071749f}; - } - { - data.key_data = { - -0.44590849f, 1.98493946f, -1.07127249f, 1.40504324f, 2.12171221f, -2.04918909f, - -1.83530343f, -3.76758623f, 0.02538997f, 2.64762068f, -2.56781912f, -1.14145339f, - -1.80042803f, 0.39801449f, 0.34181327f, -1.57265723f, 0.07036242f, -2.40207338f, - 0.73444951f, 0.93564862f, -1.43117201f, -0.40992564f, 2.72084332f, 3.10532832f, - -0.89440274f, 3.50889730f, 5.25270414f, 1.19936800f, -2.38253307f, -1.09552169f, - -0.91941810f, -3.95936108f, -1.12715232f, -2.32673430f, 1.70554638f, -1.82651567f, - 0.18641475f, -1.13930595f, -2.08975363f, 0.77337563f, -1.61064386f, 1.86085737f, - 1.24908817f, -3.56172729f, 3.49342513f, 1.41598260f, 0.23467612f, 0.77325898f, - -0.24176371f, -1.04892051f, 2.13891983f, -0.73367226f, 3.19356060f, -3.52643967f, - -2.61323428f, -1.89149976f, -3.33599472f, -1.76190269f, 0.35278416f, 1.00504446f, - 4.52736902f, -1.29095161f, -2.10441589f, -2.20554256f, 1.28037739f, 2.01972723f, - -2.59777713f, 4.17468357f, -0.63373142f, 1.95862389f, -0.63698387f, -4.30598640f, - -4.10062265f, 1.14486885f, -3.12371159f, 0.18818541f, -2.42273569f, 3.72320580f, - 1.78546739f, 1.12837386f, - -5.69526672f, 0.45080167f, -0.34738344f, 2.19837046f, 2.02498674f, -1.67241764f, - 1.03066158f, 3.49398828f, 0.68212295f, -0.13683093f, 1.35417783f, -0.76712447f, - -1.20502079f, 1.80041981f, 2.03709221f, -1.15552354f, 3.62633824f, -4.34337473f, - -0.03111041f, -0.05806269f, -5.65434170f, -3.99450684f, -5.27107000f, 1.45356524f, - -8.49876404f, 2.57157731f, -0.60446721f, 3.32191849f, -0.79453731f, 0.82028484f, - 1.27183342f, -0.99072194f, 0.25417966f, -4.80432510f, 5.19692039f, -0.64962041f, - -1.29197633f, -4.19478750f, -2.35304260f, 3.06083965f, -3.17496777f, 3.22834659f, - 2.40038896f, -7.20073223f, 3.93310833f, -4.55644560f, 7.31054592f, -1.97445476f, - -0.00740963f, 1.57046604f, 1.45884740f, 1.37348962f, 3.05838251f, -3.32491112f, - -0.05218773f, -2.32320046f, -5.33921146f, -3.68838453f, 1.82249427f, -8.29404068f, - 2.02283478f, -1.02023602f, 7.00944805f, 4.51306248f, 1.65528119f, 3.14541531f, - 3.68995571f, 5.60512161f, -0.72604638f, 0.62305540f, -3.26601505f, -1.07749093f, - -4.70862913f, -0.11774403f, -3.28379011f, -5.44625950f, -1.28474891f, 0.05496073f, - 3.28144360f, -1.71310043f, - -3.72890472f, 0.47998995f, -1.64674330f, 4.25828552f, 0.48567617f, 3.76386666f, - 0.72125065f, 2.58443975f, -0.80270696f, 1.36818254f, 0.60624528f, 1.12298989f, - 2.61748505f, -1.76728272f, 1.59453869f, -1.49594533f, 1.61122751f, -1.65819097f, - 1.07322979f, 1.00919533f, 1.83750582f, -2.11553884f, 3.05492759f, -1.13376379f, - 1.04176581f, 1.05297565f, -3.80754805f, 1.75729048f, 1.56833780f, -1.90021074f, - 2.53051329f, -3.98260069f, -2.79277897f, 0.57372808f, 1.82531142f, -4.22809839f, - 0.12054175f, -1.64285707f, -1.75917435f, 5.92044210f, 2.00746799f, 0.08308759f, - 1.31818652f, 0.92133123f, 0.07876605f, -0.78835499f, -0.59225237f, -2.75223637f, - -4.23076820f, -0.13776526f, 2.51437116f, 0.46347374f, -0.87072194f, 0.47312742f, - -0.91241401f, 2.09434414f, -2.00047112f, 0.22087479f, -3.57630754f, -1.65337551f, - -1.57748485f, 3.06805706f, 2.91149712f, -0.84392685f, -1.63053262f, -3.17057562f, - 3.44940352f, 2.34603477f, -1.70127904f, -1.73411393f, -0.44733244f, 2.55546784f, - 2.33501554f, -0.44483477f, 1.68014634f, 0.99101388f, 0.04672858f, -1.05605829f, - 0.71787786f, -0.04861724f, - -1.81776059f, 1.48426533f, -0.53543252f, -4.75410509f, -3.73359323f, -2.20236874f, - -2.80877733f, -6.16635466f, 1.27804232f, -4.55014563f, -0.30002296f, -0.96774644f, - -2.15660477f, -2.60649943f, 1.64775360f, -2.45114946f, 1.63522851f, -4.00816679f, - -2.96872401f, 5.98173285f, -0.55584449f, -2.16505861f, -5.00163412f, -1.56468248f, - 1.90084171f, -0.29323232f, 0.14279747f, -4.27117109f, -3.05262256f, 3.13814020f, - 0.04283291f, -1.22592390f, 2.14044142f, -4.04049444f, -0.79627764f, -1.17387509f, - 4.22917747f, -2.22369123f, 1.31827044f, -1.80392468f, 2.89961600f, -0.25374252f, - -3.79463124f, -1.27755213f, 3.14444208f, 0.72191542f, 3.55277538f, -1.59686506f, - 2.26461124f, 1.25676811f, 0.77055168f, -0.64221799f, -1.82437253f, 1.35799241f, - 0.62414169f, 0.83287644f, 2.08709836f, 0.74611753f, 5.53408194f, -1.18227792f, - 2.33974051f, -4.09171057f, -4.39363194f, 0.75839132f, -0.78278774f, 1.09352303f, - 0.64267069f, -0.66581339f, -1.85293758f, -3.92538142f, 3.70205355f, 5.30183840f, - 2.44776297f, 1.17696786f, -1.28278828f, 0.86428756f, -0.78950930f, -4.30053949f, - 1.21166849f, 0.49365181f, - 1.22390628f, -1.83765507f, 1.76312578f, 1.97146916f, -0.65910506f, -0.02966955f, - 4.04420996f, 0.24049535f, 1.59509969f, 2.95982647f, 1.49622416f, -2.07731581f, - 1.51230788f, 3.48245192f, 2.55489254f, -4.42068148f, -2.77923799f, -1.79879463f, - -0.43417776f, -0.91141713f, -1.83134556f, -0.77197945f, -2.80744791f, 2.38423347f, - -0.42536554f, -0.29175264f, -2.96979785f, -2.73573685f, 1.16224599f, 1.28292751f, - -2.42575717f, -4.35106182f, 2.40325737f, -1.35585093f, 3.63722515f, 0.07650419f, - 0.34960657f, 2.76701641f, 1.12685931f, 3.45839715f, -1.16243958f, 3.93772221f, - -0.69577467f, -0.72007394f, 1.37339377f, -1.43409979f, 3.66146350f, 0.36440611f, - -0.08672673f, 2.09590149f, 4.58786106f, 1.64420795f, -1.62949383f, 0.38805187f, - 2.54591107f, -0.87228912f, 2.05350280f, -3.01149988f, 2.49309850f, -2.03635573f, - -1.52769530f, -0.90678239f, 2.77345419f, 2.05674124f, -0.52915704f, 0.76992738f, - 4.50094604f, 6.16655207f, 1.21820283f, -0.59180433f, 1.53090405f, 0.53589046f, - -4.29825354f, 2.37933564f, -1.39599502f, -0.04555070f, -1.91196442f, -1.72819281f, - 2.54402304f, -4.74867582f, - - 1.77389085f, 0.26504007f, -3.06724691f, -3.37732267f, 0.88862455f, -4.00978708f, - 2.42969346f, -1.52222490f, -1.84140372f, -4.12711906f, -0.17829326f, 1.40618205f, - 3.53640866f, 3.14457250f, -0.42408764f, 1.06623757f, 1.56950164f, 2.94928074f, - -0.37585315f, -4.58977413f, -1.19122314f, 2.76285672f, 3.75529385f, -3.26022458f, - -1.74535918f, 4.89308929f, 0.46158761f, 5.31557655f, 1.14788485f, 0.56015950f, - -1.68876886f, -2.03965187f, -0.70566773f, 3.10552740f, 3.16705012f, -0.80952662f, - -0.43075383f, 2.67507076f, 5.41066170f, 3.43606973f, 4.90483046f, 1.84608901f, - -6.85163450f, -3.06533241f, 8.21495438f, 4.43654871f, 2.09319234f, -4.42602158f, - 0.92209107f, -1.70933890f, 3.71371031f, 3.94706774f, -0.36061627f, 2.57590103f, - 0.98262388f, 1.82917500f, 2.80233479f, -0.51830429f, 6.43664169f, -3.07223606f, - -4.74569941f, 3.45030975f, 0.32298383f, 2.79728365f, 2.33600187f, 2.18209934f, - 1.03046095f, 1.77432561f, -0.16497695f, -1.69815969f, -4.80686665f, -2.34232450f, - 7.86733055f, -0.65266341f, -2.63244128f, -1.64666939f, -1.15842938f, 3.89964366f, - 0.06546612f, 2.84245849f, - 0.63745236f, -0.60043466f, 0.15597063f, -2.17756677f, -0.84348190f, -6.30688715f, - 1.15000510f, 2.18763089f, 0.56617486f, -0.96061355f, 0.72410244f, -2.55619860f, - -3.74980140f, -1.01026285f, 1.05149317f, -0.83054101f, 9.09637737f, -3.59927368f, - 0.64024138f, -2.43417788f, -2.71296763f, -1.57347786f, -0.52432519f, 3.47116017f, - -1.22401500f, -1.55714345f, -1.73517704f, 0.57135445f, 4.34634066f, 5.07363987f, - 0.14575702f, 3.29643679f, 0.20970452f, -1.18641806f, 1.82565367f, 3.79054165f, - 3.11241078f, -2.33457327f, -1.79234099f, -0.77043331f, 0.94371402f, 4.95805883f, - -1.21386683f, -2.62089586f, 1.04984260f, 4.77972317f, 3.80148745f, 2.57944679f, - -1.62215877f, -1.48487663f, -0.88516212f, 2.47205591f, 1.25198030f, -1.49769402f, - 1.49644077f, -1.21963966f, -4.22067022f, 0.07715815f, -0.05838633f, 0.02521211f, - 1.54778171f, -0.68474317f, 3.87327027f, 0.36594340f, 3.28861642f, 1.84371138f, - 0.87659311f, 0.23867008f, -1.22515559f, 0.87271261f, -2.45830512f, -4.59441233f, - -4.72528791f, 1.07633507f, -0.76005602f, -6.56183910f, 0.93921316f, 4.07901239f, - 0.65637922f, 1.09935892f, - -1.52171361f, 0.36837816f, 2.44905639f, 1.71517515f, -3.21964288f, -1.30028033f, - -0.47215480f, -0.03559750f, 2.39852405f, -2.82084513f, -0.07759643f, -1.71475554f, - 5.37419796f, -1.69430733f, 1.42850208f, -4.45167494f, 0.05887067f, 1.84818649f, - -2.30660439f, 1.29194844f, -3.19126892f, 2.09994006f, -5.04377365f, -1.00292349f, - -3.30398607f, 1.46449196f, -0.73720878f, 3.07083178f, 2.50308442f, -4.58036995f, - -5.30711460f, 1.14685988f, -3.43290782f, -3.42758298f, -1.73553753f, 1.28076029f, - 0.81061542f, -4.45261192f, -0.37263635f, 2.39974928f, 3.57600760f, 2.10931325f, - -1.61413431f, -2.39997077f, -4.10416794f, -1.38086832f, -0.63188541f, 1.46728146f, - -2.24996948f, 2.49746299f, -0.73199594f, -0.97014105f, 1.54047072f, -2.66780996f, - 5.37116718f, 2.82218075f, -1.62108850f, 2.72595692f, -1.79463971f, -1.87041128f, - -4.71584415f, 1.82171798f, -2.90882301f, 2.87121320f, -2.57487297f, -0.22736369f, - 1.34005880f, -0.27021503f, -1.39979327f, 1.24117494f, 4.63584423f, 1.43412280f, - 1.22960615f, -3.07072306f, 4.03779936f, -1.11251736f, -3.76871419f, -3.14926720f, - -1.65451026f, 0.64419544f, - 2.68210387f, 5.84884739f, -2.46407223f, 3.87640619f, -0.33028477f, -4.32690859f, - -1.16703165f, 1.21859503f, -0.54117912f, -2.19271398f, -0.51750636f, 1.76933861f, - 1.60338795f, -1.61012948f, 4.91132116f, -2.04804540f, 1.24183416f, -0.04860526f, - -2.21050048f, -1.88805938f, -3.04969406f, -1.23892701f, -0.06367862f, 0.46349186f, - -2.34568119f, -3.52605510f, 0.72856915f, -1.24463606f, 3.83235240f, -1.56133997f, - -3.22448444f, 1.99090147f, -2.27550173f, -1.82680321f, 2.01301694f, 2.99845076f, - 2.90344477f, -0.83625877f, -1.13337862f, 0.64514792f, 0.03786933f, 2.19324684f, - -1.80451119f, 0.67776012f, 3.11744428f, -0.24457633f, -0.45526421f, 1.37050200f, - -0.05366212f, -0.14649165f, -7.00798512f, -1.94217563f, 1.93492782f, -1.89671147f, - -0.97781098f, 3.61308098f, 1.98817432f, -2.60251522f, 4.22469711f, 0.88692582f, - 0.89745212f, 1.17353654f, 0.54682076f, -1.99516833f, 3.81800508f, 2.68964338f, - 1.08577883f, 2.27413726f, -0.23109391f, 3.24835920f, 1.27708983f, 0.35086024f, - -2.10146737f, 1.52129221f, -0.56323838f, 1.71683300f, -1.82481837f, -3.74832487f, - 3.97903419f, 2.70656705f, - 0.54202497f, 1.58516026f, 0.38604254f, 2.67667460f, 3.48077846f, -3.52633214f, - 0.68681777f, -2.25850630f, 2.76701570f, 0.30912635f, -3.02949572f, -5.94854355f, - 2.52342463f, 0.49857450f, -0.76799512f, -1.38036680f, 3.46629524f, 0.67081052f, - -1.44662499f, 0.40994781f, 3.02867222f, 3.72760630f, -1.68694305f, -0.75258541f, - 2.12057924f, 1.28757250f, 0.24050999f, 0.95728469f, 1.68175769f, -3.11903358f, - -1.02161658f, -0.54389447f, 1.99784613f, 0.69883800f, -0.92166108f, -0.84107661f, - 0.18834084f, 2.21262383f, 2.83887744f, 1.16888499f, -1.31167865f, -1.22881663f, - -0.04097224f, 0.81264222f, 0.20924969f, -0.07720196f, 4.18504333f, 0.45721883f, - -1.43579936f, 4.08936310f, -1.00441456f, 0.45323381f, -0.84993589f, 0.54930854f, - -0.20439517f, -1.31673455f, 2.80454016f, 1.10617089f, -0.61983430f, -1.21147370f, - 2.87613988f, -0.63006109f, -0.87298799f, -1.79945171f, 1.75379634f, -0.03284079f, - -3.16018248f, -1.70393991f, -1.00085866f, -2.04588270f, 3.25270534f, 0.62951756f, - -3.74736595f, 1.08699441f, -1.01408458f, -0.82118225f, 0.09517595f, -1.97260141f, - 4.06293917f, -1.53105283f}; - } - - { - data.value_data = { - 2.52200770f, 3.33522081f, 1.02251101f, -0.19524473f, -3.71459103f, -0.02477702f, - -1.39731681f, -5.58580303f, 0.30901617f, 0.76306605f, -2.04605818f, 1.61113453f, - 0.71565157f, 2.62568450f, -5.18361902f, -1.70342803f, 1.42449617f, -1.30358791f, - 1.06270623f, 3.04715180f, -0.25380951f, 2.84206176f, 2.05601597f, -0.55873990f, - -3.71717381f, 1.29085660f, 0.27478188f, 5.44427061f, -3.59301615f, -0.25955540f, - -0.70427519f, -1.97779632f, 0.98796690f, -3.75880170f, 1.34103966f, -0.39008784f, - -1.04290402f, -1.16061938f, -1.91779065f, -0.61740541f, 0.13198879f, -3.11491537f, - -0.86305869f, 3.78544807f, -3.27862763f, 1.77973413f, -2.43130898f, 0.11999905f, - 1.96149552f, 4.96055317f, 3.92319894f, 2.29237580f, -4.07357836f, 2.23905349f, - -0.84580690f, -2.24981976f, -2.03560781f, -1.88958716f, -1.10143483f, 2.26368880f, - 3.24453497f, 1.19321299f, -3.65723705f, -3.01728868f, 2.69581604f, -3.16313481f, - -6.37331009f, -2.40505695f, 1.88986635f, 4.99678659f, 0.22641480f, -1.02873325f, - -1.16671526f, -5.14537668f, -0.41974550f, 0.55167019f, 1.17046857f, 6.18922234f, - 3.05369854f, 4.05916214f, - 1.64212084f, 2.18478417f, -2.68270802f, -1.17468357f, 0.31818610f, 1.02590501f, - -2.91689920f, -0.39902568f, 4.53725624f, 2.38986945f, 2.08665752f, -3.77494550f, - 4.75398874f, 3.46525812f, 2.60498571f, 1.68801785f, -1.59054160f, 4.38700676f, - 1.33280611f, -2.05578661f, -3.67522144f, -1.85783577f, 1.84266996f, 2.48572135f, - -5.76279545f, 4.83649015f, -1.39598393f, 4.55631828f, 0.88710690f, -0.25037968f, - -5.06323290f, -2.82429934f, 2.45077682f, 2.26839566f, -2.15198541f, -0.92987227f, - 0.98444796f, -4.77959299f, -1.00593686f, -1.12779152f, -0.41504347f, -0.10360003f, - -1.36064351f, -2.65771484f, -1.74305487f, -1.43110847f, 3.73240304f, -8.55393791f, - 1.61241794f, 0.20090955f, 0.16259992f, 2.51827145f, -4.88276291f, 0.65994090f, - -1.85566723f, 2.85304689f, -2.25546956f, -1.81180429f, -0.73952389f, -0.69026655f, - 6.46290684f, -3.42528129f, -1.68900692f, -2.63187265f, 1.23666155f, -1.80273986f, - -5.34096527f, 2.39473057f, -1.12343872f, 0.50738329f, 1.06165779f, -1.25881910f, - 1.30416012f, -0.39503133f, 1.06663299f, -2.36198807f, 2.11466384f, 1.42665458f, - 0.47875917f, 0.84987718f, - -1.42672980f, 2.15086913f, 1.05465066f, -2.24732041f, -0.04627687f, 1.35561931f, - -2.22631431f, 1.87147117f, 2.68784380f, -6.75409317f, 1.75816703f, -1.32267916f, - -0.30795556f, 3.21814609f, 1.92649913f, 5.51574183f, -5.45856047f, 1.69647682f, - -3.66586471f, 1.25441813f, -2.27710414f, 4.21629810f, 0.02650413f, -0.05531013f, - 1.46342337f, 0.35316384f, 1.58090007f, 0.88646221f, 4.47589302f, -4.34421301f, - 0.02980316f, -0.58578295f, 1.79196024f, 1.78082383f, 0.14971030f, -4.34231663f, - -0.56575900f, -1.75833559f, -0.84479707f, -2.73750734f, -4.26857948f, 1.44429922f, - 0.18011174f, -1.11181009f, -1.31634200f, -1.98439252f, 3.27634311f, -2.73307896f, - 1.83559537f, -2.95653439f, -3.93072486f, 3.32339287f, -2.88254499f, -0.90710086f, - 3.82468128f, -2.26418972f, 0.21428287f, -5.71086216f, 1.08876240f, 3.38046408f, - -0.81207389f, 2.31772232f, -0.11134154f, 1.18450689f, -2.37789607f, -0.00142117f, - 0.72909313f, 0.68614733f, -0.77563363f, -2.34862852f, 1.05669081f, -1.86599076f, - 1.98130095f, 0.92516875f, -2.72275639f, 2.71904421f, 0.23536620f, -1.72734010f, - -3.43704534f, -3.67876530f, - 4.29205894f, 0.72032785f, -1.49616945f, -1.84139895f, 0.30715290f, -3.04337001f, - 0.66906673f, 1.73802924f, -0.07174578f, 2.89249015f, 2.21281481f, -0.97710615f, - -4.89526510f, -1.05043483f, -2.97074080f, -1.34177089f, 2.20932603f, 4.01438665f, - 2.96217227f, 0.57981884f, 1.12104404f, -0.55145615f, 0.68083727f, 1.99328470f, - -4.87487507f, -0.15801801f, -0.08008248f, 2.49206161f, 4.36795998f, -0.79805094f, - -2.13833427f, 2.47042608f, 0.36067075f, 3.26598382f, 1.98279870f, -1.89963067f, - 0.30437571f, 1.26811552f, -1.55896103f, -1.26593304f, -5.15960598f, -1.46925342f, - 4.01534986f, -0.20960769f, 0.16190898f, 1.63501847f, -1.58879602f, 0.31569052f, - 0.25710380f, -1.18716395f, 3.51842332f, -3.30306745f, 3.31757665f, -1.89535034f, - -1.90357256f, 6.20105791f, 1.91351593f, 1.04002178f, 1.18122804f, -0.22888322f, - 0.66158205f, 3.04200125f, 2.67628670f, -0.64249665f, -2.07746315f, 5.54076958f, - -3.00114274f, 0.68613434f, -4.45081329f, 0.00587352f, 2.03132582f, -1.60416722f, - -3.08808851f, 0.95315832f, 0.46982890f, -3.28788757f, -2.82306862f, 1.49545765f, - -2.77738333f, -1.43082714f, - -1.33299255f, 2.78721404f, -2.25095224f, -0.89978874f, -1.20683730f, -0.74944079f, - -2.88921618f, -0.18277466f, 0.00372136f, -1.80246174f, 4.19822025f, -1.82120311f, - 2.43893075f, -0.92111945f, -2.22253442f, 1.43559384f, -3.10266304f, 1.44538188f, - 1.68185592f, 0.84382743f, -1.83896518f, -5.66177320f, 0.95111668f, -5.65224314f, - -3.78799438f, -1.59245038f, 2.68568468f, 3.82559538f, 0.67030597f, -1.00240803f, - -6.75469112f, -0.14708334f, 4.54812241f, -3.05194640f, 2.39797926f, -0.00272782f, - -1.41322088f, 2.25726366f, 0.13995156f, -0.57747078f, -6.58918333f, 1.21203697f, - -2.24320960f, -1.59526610f, -2.24520969f, -0.37764102f, -0.14032492f, -4.60604239f, - 2.52268362f, -3.05438852f, -1.93661046f, -1.98484039f, 2.17252684f, 2.72310734f, - 1.35985041f, 0.74225116f, 1.46986079f, -3.13677359f, 0.46207923f, 2.92159390f, - -0.26587552f, 0.92518401f, -0.19378644f, 1.43351614f, 2.80231071f, -2.39726210f, - -4.11096096f, 1.53613114f, -3.41936874f, -0.81401485f, 4.18615103f, -1.20390248f, - 0.29101330f, -0.55211830f, -0.90347737f, 0.72938609f, -0.41552329f, -2.86164975f, - 2.14127350f, -2.71393037f, - - 2.06101036f, -2.49327445f, -0.26084259f, -0.08738496f, -5.46849871f, 2.66518831f, - -2.23898268f, -0.58128607f, -4.77391148f, 3.53860617f, 5.66361809f, 1.88735557f, - 5.31760883f, 4.64165354f, -1.88971460f, -0.18464115f, 1.44575036f, 0.71620363f, - 5.20483541f, 0.17650539f, 4.55752707f, 0.14761698f, 4.97212982f, 0.38257861f, - -0.86314517f, 3.00640798f, 2.82556558f, -5.72242022f, 0.97359830f, 0.12829947f, - 4.27856922f, 3.06020951f, -4.39019632f, -6.17075443f, -3.69274259f, 5.33883333f, - -4.09268999f, -0.42381752f, -4.86064196f, 0.87817371f, -1.66327834f, 2.06401992f, - -0.45039526f, 2.00427246f, 6.28635406f, -4.28625345f, 0.64066625f, 1.98521018f, - 1.28183603f, 1.96348131f, 3.25338674f, -4.83068466f, -1.22748399f, -1.83176708f, - 0.99235696f, 3.90817499f, 0.15236929f, -1.11182845f, 0.28134999f, 2.88753319f, - 0.94340092f, -2.33726883f, -0.26672745f, -0.47063547f, -3.89827800f, -0.60715055f, - -10.64067078f, -0.46934411f, -0.17723195f, 0.31426474f, 0.26794863f, -2.33281183f, - -0.83772266f, -3.00178385f, -3.04406095f, 5.08712959f, -2.82472014f, 2.50977850f, - -5.92609453f, 0.80104923f, - 1.74909449f, 3.36070085f, -5.19149637f, 2.02698421f, 1.72980452f, -3.32840133f, - 1.31092596f, 1.08732378f, 0.70107508f, -4.48935890f, 3.30084705f, -2.01938772f, - -0.57465255f, 1.43294013f, 1.41905987f, -8.33140659f, -0.08440223f, -0.86436093f, - -0.86385047f, -0.06775177f, -1.36902046f, -4.34248447f, 1.25420880f, -0.31501776f, - -4.61437702f, -0.80756599f, -1.81841552f, -0.23593402f, -1.72089577f, -2.38486695f, - -1.77567720f, -0.99221468f, -0.39361507f, 3.94493699f, -0.44989038f, -4.16036463f, - -2.75135875f, 0.51079714f, -3.13808584f, -1.45286632f, 3.38582993f, 1.72332990f, - 0.42072344f, 3.39117050f, -4.21982670f, 2.96172690f, -0.30759099f, -0.07023232f, - -5.51846933f, 3.23913264f, 2.17243195f, 1.15772712f, -3.94762301f, 2.75720644f, - -1.61080432f, -0.51649714f, -1.34688985f, 2.42340302f, -1.40935290f, -0.30057096f, - 3.59142900f, 4.29019451f, 1.10035944f, -2.74829841f, -4.27969074f, -2.08663464f, - -3.74090290f, -2.46784139f, 3.63337183f, -3.26299858f, 5.80690861f, -1.71136200f, - -0.40768790f, -1.70319510f, 2.13231635f, 0.14728940f, 4.53216934f, -2.27770376f, - -0.78596526f, -1.09226680f, - -0.45473242f, -7.20685625f, 0.59849894f, 2.44483280f, -0.93482894f, 2.15730143f, - -3.87125921f, -0.19056010f, 1.05693293f, -0.16091427f, 2.58152556f, -2.79246712f, - -3.29887533f, -2.00540090f, 0.59734398f, 0.59127998f, -2.85143566f, -1.80759144f, - -3.25450134f, -3.59059358f, -5.00572824f, -5.37265396f, 3.08453035f, 0.84874475f, - 0.76036537f, 4.34558249f, 4.40313244f, -5.61378384f, 3.78151655f, -1.16012287f, - -1.08296275f, -0.84596092f, 3.32365799f, 2.11034679f, 2.42330313f, 1.83046317f, - -1.92273235f, 5.67875910f, 1.78094673f, 0.36037564f, -3.32583952f, 4.43799925f, - -0.46875116f, 2.49567175f, 0.28798068f, 1.30016363f, 0.28970984f, -2.38507104f, - 0.24665418f, -5.25903797f, -2.31750965f, -0.23577139f, 4.47396946f, 0.28329450f, - 1.58814597f, -1.67970324f, -2.79024720f, -1.62729883f, 3.10642624f, -0.66917229f, - 0.65675592f, -4.20011568f, 2.47841549f, 1.90257025f, -0.78783196f, -1.41586518f, - -0.06794038f, 0.28623959f, 1.59009087f, -6.98170996f, 0.46000746f, -0.39241526f, - -5.81545448f, -0.54146534f, -2.61389065f, -3.70888448f, -2.71156025f, -0.85459292f, - 0.12608814f, -3.15979242f, - -1.93294251f, 2.73354673f, -0.49725151f, 2.27444625f, 3.72778368f, 1.63425875f, - 3.01002884f, -1.25163877f, 2.17933655f, -2.32454872f, 1.43361092f, 1.83992100f, - -3.75518155f, 3.81032205f, -1.86739397f, -1.46299195f, -4.30204821f, -2.14225531f, - 0.60845029f, 0.01267266f, 1.35235953f, -2.03360963f, 3.10610461f, -1.08782852f, - 0.19948053f, 2.91491699f, 4.31269264f, 0.05198213f, -1.56488633f, -1.41555297f, - -0.09313738f, 0.55110073f, -2.35073256f, -0.79985762f, -0.09840333f, 0.75388265f, - 0.71233857f, -0.97185916f, 0.35018587f, -1.84444118f, 0.19463573f, -2.20360899f, - -2.36256480f, -0.17715198f, -3.02556229f, -2.24278378f, -3.03048801f, 1.78598678f, - -0.02577947f, -0.48361790f, 2.76573992f, 0.28259668f, -3.19178367f, 3.37067890f, - 1.85169363f, -5.36484241f, -5.22926855f, -1.72746205f, 0.77593267f, -0.60533059f, - -1.12855411f, 1.98766887f, -1.15927505f, 7.20731497f, 0.39016724f, -1.40255058f, - -3.95324802f, 1.27826059f, -1.00286031f, 1.66211963f, 0.10310335f, 1.84502232f, - 0.54359400f, -1.47985172f, 4.31608820f, -0.05619702f, 1.72841990f, 6.51521921f, - -1.70129752f, 2.24409604f, - 5.91284990f, 0.88121837f, -1.96858621f, -1.26149762f, 2.30856943f, -1.29645681f, - -1.07195330f, 1.67984724f, 0.13962746f, 1.59568501f, -1.93873858f, 1.12268782f, - -1.57682693f, 0.18295126f, 5.37425900f, 1.95650697f, 3.26101947f, -3.15507460f, - -4.46081638f, -1.66738629f, -2.29049826f, 3.31624699f, -0.19252041f, -3.83471584f, - -1.06477606f, 1.54972005f, 1.27188253f, 4.01462269f, 3.56644154f, 1.97424769f, - -4.16624880f, -4.84278488f, 0.59882414f, -0.33249485f, -1.11473167f, -0.64004254f, - 0.59620667f, 2.88485813f, 3.94058657f, -1.38273096f, -4.01862049f, -2.84879613f, - -1.14927125f, -1.26633883f, 1.44495869f, 1.08074188f, -1.20787299f, 4.34522200f, - 1.71746707f, -1.24948418f, 3.04108238f, 1.47163892f, -2.11437988f, -3.81353092f, - -1.89427793f, -2.15320063f, -2.03045893f, 0.40097618f, -0.12276602f, -0.48584884f, - 0.98694682f, -3.34362507f, -3.70514822f, -1.00521743f, -3.40365505f, 4.27700996f, - -1.74038815f, 0.02413213f, 0.15047586f, -2.49076056f, 1.51251030f, -1.95061517f, - -2.23469496f, -0.10695624f, 2.14359999f, 4.53367281f, -0.52228838f, -1.35633743f, - 0.27997780f, -0.35232139f}; - } - - { - data.bias_data = { - -0.38124341f, 0.02696526f, -0.11914945f, -0.43795273f, -0.34948170f, -0.19608477f, 0.19725692f, 0.39987487f, - 0.04772711f, -0.03419551f, -0.30606642f, 0.42656231f, -0.23178342f, -0.13692456f, -0.04889601f, 0.48739988f, - -0.25891554f, 0.13431972f, 0.22861153f, 0.06360734f, 0.48096961f, -0.47906545f, 0.43613154f, -0.23511401f, - -0.10595283f, -0.42839217f, 0.28931111f, -0.13180739f, -0.45826656f, 0.23286396f, -0.43407962f, 0.40754890f, - 0.23778325f, 0.34850210f, -0.01385659f, 0.32141626f, -0.27738628f, 0.27683002f, 0.31886810f, -0.24781504f, - -0.25476855f, -0.46742713f, -0.12478521f, 0.39731556f, -0.12087554f, 0.40822440f, 0.13202906f, -0.23747686f, - 0.30502868f, 0.27182943f, -0.03640261f, -0.39626551f, -0.22411832f, 0.17324352f, -0.49959660f, -0.49318257f, - 0.31363028f, 0.05469471f, -0.00390345f, -0.46100286f, -0.27253938f, 0.17251462f, 0.46564627f, 0.21038425f, - -0.11294025f, -0.36674809f, -0.15023369f, -0.06280217f, 0.16079122f, 0.07736248f, 0.22696525f, -0.17971110f, - -0.10770395f, -0.39882037f, 0.49794090f, -0.14199540f, -0.05613044f, 0.39860195f, 0.36553562f, 0.32012612f, - 0.27079183f, 0.42074734f, -0.40314156f, -0.43726659f, 0.27376485f, -0.38174152f, -0.43700469f, 0.38040614f, - -0.40546918f, 0.06927037f, 0.16979086f, 0.41458064f, 0.07120579f, -0.08055863f, 0.12095112f, -0.27988660f, - 0.06004709f, -0.05600315f, -0.25510073f, 0.41887105f, -0.19016314f, 0.47241372f, 0.12890404f, -0.24272856f, - 0.21106839f, -0.40523255f, 0.10336459f, -0.11084765f, 0.42408967f, -0.15285304f, -0.28945464f, -0.25714916f, - 0.40978593f, -0.09138483f, -0.02013114f, -0.39042589f, -0.19557095f, 0.07540411f, 0.33955890f, 0.41873980f, - -0.27744853f, -0.33097768f, -0.44587523f, -0.01648277f, 0.34952271f, -0.48838940f, -0.17273578f, 0.37286615f, - -0.10157353f, -0.08097187f, 0.23243034f, 0.25516337f, -0.45793599f, 0.08089012f, 0.17673731f, 0.03000754f, - 0.48834521f, 0.35069120f, -0.32989410f, 0.20729345f, 0.24406803f, 0.35393929f, -0.16146761f, 0.04258209f, - 0.34165633f, 0.44972986f, 0.44825548f, -0.36850777f, -0.08256876f, -0.00416249f, 0.35105377f, 0.29640436f, - -0.46063286f, 0.33505446f, 0.30497158f, -0.48780718f, -0.49269417f, -0.06608954f, -0.22655264f, -0.36424011f, - -0.10567203f, 0.26791072f, -0.08976898f, 0.31341976f, 0.06027532f, 0.14307594f, 0.31587386f, 0.16180152f, - 0.34785229f, 0.00531715f, -0.35168743f, -0.11641458f, 0.39196932f, 0.44535065f, 0.43545735f, 0.15593112f, - 0.06171834f, -0.42181283f, -0.41170910f, 0.40969193f, -0.01510030f, 0.07973170f, -0.18156880f, 0.21522856f, - 0.03915739f, -0.20913908f, -0.47068381f, 0.35633272f, -0.35124153f, 0.36624825f, -0.05567622f, -0.35343069f, - 0.12821168f, 0.35526341f, -0.23420528f, -0.46328634f, -0.21994811f, -0.27556795f, 0.01653767f, 0.42626363f, - 0.23239774f, 0.39632857f, 0.32416028f, -0.48494491f, -0.05365932f, -0.10860911f, 0.06893444f, 0.46116674f, - 0.34345043f, -0.02719739f, -0.39574289f, -0.39339882f, 0.23044002f, -0.06155324f, 0.23292047f, 0.39775699f, - 0.12789404f, -0.44719657f, 0.12020230f, 0.26871282f, -0.10917315f, -0.29244915f, 0.09059817f, -0.19613290f, - -0.12975609f, 0.41347277f, -0.31107110f, 0.17745221f, -0.46015862f, -0.26369864f, -0.03715026f, -0.42254731f, - -0.21274829f, -0.42004544f, -0.22337052f, -0.26180822f, -0.40042144f, -0.40085569f, 0.17293042f, 0.15324622f}; - } - - { - data.fp32_output_data = { - -1.5234375f, 2.4179688f, 0.95751953f, -1.9316406f, 0.012382507f, 1.4960938f, -1.9111328f, 2.0234375f, 3.0371094f, -6.7265625f, 1.4042969f, -1.4414062f, 0.094665527f, 3.6640625f, 2.359375f, 5.6601562f, -5.3828125f, 1.2773438f, -4.0664062f, 1.6591797f, -2.2949219f, 4.28125f, -0.15026855f, 0.16455078f, 1.4853516f, 0.15344238f, 1.1035156f, 1.2519531f, 4.1132812f, -3.9667969f, -0.036193848f, -0.94482422f, 1.9208984f, 2.1347656f, -0.088317871f, -4.8007812f, -0.78320312f, -2.0410156f, -0.82910156f, -2.3085938f, - - 0.35595703f, -2.7089844f, -0.53466797f, 3.28125f, -3.3242188f, 1.6640625f, -2.3496094f, 0.5625f, 2.3027344f, 4.9140625f, 3.5175781f, 1.8925781f, -3.8359375f, 2.1679688f, -0.61572266f, -1.8320312f, -1.9023438f, -2.3320312f, -0.97753906f, 2.5234375f, 3.1386719f, 0.89355469f, -3.5566406f, -3.2089844f, 2.5566406f, -2.7363281f, -6.6796875f, -2.2128906f, 1.4150391f, 4.71875f, 0.19372559f, -1.4521484f, -1.3769531f, -5.546875f, -0.63916016f, 0.27954102f, 0.76757812f, 5.7695312f, 3.2148438f, 4.1953125f, - - -1.5292969f, 2.421875f, 0.95019531f, -1.9267578f, 0.0063095093f, 1.4873047f, -1.9121094f, 2.0195312f, 3.0214844f, -6.7226562f, 1.4140625f, -1.4384766f, 0.097106934f, 3.6445312f, 2.3398438f, 5.6484375f, -5.3789062f, 1.2714844f, -4.0507812f, 1.6630859f, -2.2890625f, 4.2460938f, -0.14953613f, 0.13464355f, 1.4755859f, 0.1361084f, 1.1142578f, 1.2587891f, 4.1015625f, -3.9589844f, -0.05657959f, -0.93847656f, 1.9316406f, 2.1113281f, -0.073730469f, -4.7851562f, -0.79003906f, -2.0175781f, -0.82470703f, -2.3007812f, - - 0.36401367f, -2.7167969f, -0.5390625f, 3.2988281f, -3.3320312f, 1.6699219f, -2.3613281f, 0.578125f, 2.3046875f, 4.9335938f, 3.5253906f, 1.8994141f, -3.84375f, 2.1757812f, -0.61328125f, -1.8505859f, -1.9072266f, -2.3359375f, -0.98144531f, 2.53125f, 3.1367188f, 0.89941406f, -3.5683594f, -3.2128906f, 2.5664062f, -2.75f, -6.6875f, -2.2246094f, 1.4287109f, 4.734375f, 0.1895752f, -1.4511719f, -1.3789062f, -5.5664062f, -0.64257812f, 0.2890625f, 0.77099609f, 5.7851562f, 3.2265625f, 4.2109375f, - - 1.4667969f, 2.453125f, -2.6875f, -0.88574219f, 0.36987305f, 1.1777344f, -2.5839844f, -0.1854248f, 4.84375f, 2.1875f, 1.7265625f, -3.8359375f, 5.0273438f, 3.9042969f, 3.0253906f, 1.9316406f, -1.6171875f, 3.9023438f, 0.80761719f, -1.5703125f, -3.6601562f, -1.6386719f, 1.6201172f, 2.6425781f, -5.5585938f, 4.5234375f, -1.7978516f, 4.828125f, 0.61767578f, 0.022384644f, -5.0f, -3.1269531f, 2.5644531f, 2.6113281f, -2.3339844f, -1.4707031f, 0.72900391f, -4.9882812f, -0.98535156f, -0.73828125f, - - -4.8515625f, -0.95214844f, 4.0273438f, -0.79248047f, -0.0083236694f, 1.3789062f, -1.3271484f, 0.42480469f, 0.70166016f, -1.2441406f, 2.8515625f, -3.4824219f, 3.2890625f, -1.7714844f, -1.5439453f, 6.3203125f, 1.9228516f, 0.37231445f, 1.2382812f, 0.13647461f, 0.65039062f, 2.5429688f, 2.5722656f, -0.81738281f, -2.0058594f, 5.5390625f, -3.3691406f, 0.92431641f, -4.78125f, -0.28393555f, 2.0214844f, -2.0117188f, -3.078125f, 0.46289062f, 0.20227051f, -3.3808594f, -3.0253906f, 0.95654297f, -2.4042969f, -1.2744141f, - - -1.9931641f, 2.8261719f, -0.57470703f, 2.5820312f, 3.6835938f, 1.78125f, 3.1953125f, -1.0664062f, 2.484375f, -2.265625f, 1.1132812f, 1.6455078f, -3.3222656f, 4.1640625f, -1.3837891f, -1.2744141f, -4.1875f, -2.5488281f, 0.1439209f, 0.36401367f, 1.2402344f, -1.9980469f, 2.9257812f, -0.83837891f, 0.23828125f, 2.7226562f, 3.8300781f, 0.30273438f, -1.8193359f, -1.0390625f, -0.15588379f, 0.17749023f, -2.1347656f, -0.40942383f, -0.30444336f, 0.31567383f, 0.43164062f, -1.1347656f, 0.37255859f, -1.3740234f, - - -2.203125f, -0.0076446533f, -0.62060547f, -0.057525635f, 3.2050781f, -1.9433594f, -0.44921875f, 3.3710938f, 1.6572266f, 0.31762695f, 2.6894531f, -2.0605469f, -1.546875f, -2.1328125f, 0.13598633f, 0.78466797f, -1.2138672f, -1.0078125f, 0.30273438f, 1.375f, 0.62548828f, -2.5820312f, -1.6708984f, -0.041412354f, -3.34375f, 1.7207031f, -6.5234375f, 0.10406494f, -0.58398438f, -0.98925781f, 0.72460938f, -2.1347656f, -1.4980469f, -2.0566406f, -0.33691406f, 3.9980469f, -1.7851562f, 0.94042969f, -2.71875f, 0.61865234f, - - -2.0097656f, 2.9941406f, -0.59277344f, 2.5761719f, 3.7832031f, 1.765625f, 3.3105469f, -1.078125f, 2.5195312f, -2.3027344f, 1.0693359f, 1.7207031f, -3.3554688f, 4.2421875f, -1.4033203f, -1.2939453f, -4.2109375f, -2.5683594f, 0.17724609f, 0.41601562f, 1.3242188f, -1.9326172f, 2.9121094f, -0.88330078f, 0.23376465f, 2.6992188f, 3.8300781f, 0.42358398f, -1.8964844f, -1.0371094f, -0.16442871f, 0.17700195f, -2.2109375f, -0.44287109f, -0.33642578f, 0.28515625f, 0.49194336f, -1.2324219f, 0.38061523f, -1.4160156f, - - -1.8134766f, 3.0039062f, -0.13049316f, 1.6318359f, 4.8515625f, -3.109375f, 0.62841797f, 1.4433594f, 1.3876953f, 0.27685547f, 1.5771484f, -4.1679688f, 0.31225586f, -1.4082031f, 1.3603516f, 3.0195312f, -0.39648438f, -1.6777344f, 1.0498047f, 2.3378906f, 0.76806641f, -3.0585938f, 0.45361328f, -0.12194824f, -3.3125f, -0.37817383f, -8.5234375f, -0.11810303f, -0.23144531f, -1.625f, 0.27539062f, -2.3085938f, -2.1933594f, -2.8554688f, -3.1679688f, 2.8027344f, -3.1972656f, 1.3349609f, -4.3632812f, 0.044036865f, - - 0.099182129f, 0.14648438f, -0.45410156f, 1.3339844f, -1.1308594f, 2.3261719f, 0.48266602f, -0.72314453f, -1.1728516f, 0.81396484f, 3.3339844f, 1.7109375f, 1.4560547f, 4.6484375f, -1.4179688f, -0.609375f, -1.1708984f, -1.0449219f, 2.6015625f, 0.47900391f, 2.984375f, -0.81787109f, 3.9121094f, -0.079284668f, -0.32202148f, 2.7636719f, 3.0507812f, -2.6972656f, -0.52197266f, -0.22521973f, 2.1601562f, 1.5136719f, -3.2558594f, -3.2714844f, -2.2207031f, 2.7304688f, -2.078125f, -0.89990234f, -2.3847656f, 0.04486084f, - - 1.2392578f, 2.2792969f, 0.33398438f, 2.2519531f, 0.67236328f, -0.56103516f, 0.20678711f, 1.359375f, -1.9707031f, 2.6074219f, 2.2851562f, -2.0566406f, -2.4335938f, 0.53466797f, -0.15075684f, 1.9609375f, -0.51464844f, 0.30981445f, -0.49145508f, 1.46875f, 2.234375f, 0.87353516f, 0.546875f, -1.8681641f, -4.2265625f, -0.97509766f, -7.296875f, -1.3476562f, 1.3769531f, -1.8427734f, 3.1601562f, -2.4238281f, -0.82421875f, -2.734375f, -0.52783203f, 2.2089844f, 0.66699219f, -0.421875f, -3.0332031f, -0.047058105f}; - } - - { - data.fp16_output_data = { - -1.5244141f, 2.4199219f, 0.95751953f, -1.9316406f, 0.012390137f, 1.4970703f, -1.9111328f, 2.0234375f, 3.0371094f, -6.7265625f, 1.4042969f, -1.4414062f, 0.094665527f, 3.6640625f, 2.3613281f, 5.6601562f, -5.3828125f, 1.2783203f, -4.0664062f, 1.6591797f, -2.2949219f, 4.28125f, -0.15026855f, 0.16455078f, 1.4853516f, 0.15344238f, 1.1035156f, 1.2519531f, 4.1132812f, -3.9667969f, -0.036193848f, -0.94482422f, 1.9208984f, 2.1347656f, -0.088317871f, -4.8007812f, -0.78369141f, -2.0410156f, -0.82910156f, -2.3085938f, - - 0.35595703f, -2.7089844f, -0.53417969f, 3.28125f, -3.3242188f, 1.6640625f, -2.3496094f, 0.5625f, 2.3027344f, 4.9140625f, 3.5175781f, 1.8925781f, -3.8359375f, 2.1679688f, -0.61572266f, -1.8320312f, -1.9023438f, -2.3320312f, -0.97753906f, 2.5234375f, 3.1386719f, 0.89355469f, -3.5566406f, -3.2089844f, 2.5566406f, -2.7363281f, -6.6796875f, -2.2128906f, 1.4150391f, 4.71875f, 0.19372559f, -1.4521484f, -1.3769531f, -5.546875f, -0.63916016f, 0.27954102f, 0.76757812f, 5.7695312f, 3.2148438f, 4.1953125f, - - -1.5283203f, 2.421875f, 0.94970703f, -1.9267578f, 0.006313324f, 1.4873047f, -1.9121094f, 2.0175781f, 3.0214844f, -6.7226562f, 1.4140625f, -1.4384766f, 0.097045898f, 3.6445312f, 2.3398438f, 5.6484375f, -5.3789062f, 1.2705078f, -4.0507812f, 1.6630859f, -2.2890625f, 4.2460938f, -0.14941406f, 0.13464355f, 1.4755859f, 0.1361084f, 1.1142578f, 1.2578125f, 4.1015625f, -3.9570312f, -0.056549072f, -0.93798828f, 1.9316406f, 2.1113281f, -0.073730469f, -4.7851562f, -0.79003906f, -2.015625f, -0.82421875f, -2.3007812f, - - 0.36401367f, -2.7167969f, -0.5390625f, 3.2988281f, -3.3300781f, 1.6699219f, -2.3613281f, 0.578125f, 2.3046875f, 4.9296875f, 3.5253906f, 1.8994141f, -3.84375f, 2.1757812f, -0.61328125f, -1.8505859f, -1.9072266f, -2.3359375f, -0.98095703f, 2.53125f, 3.1347656f, 0.89892578f, -3.5664062f, -3.2128906f, 2.5664062f, -2.75f, -6.6875f, -2.2246094f, 1.4287109f, 4.7304688f, 0.1895752f, -1.4511719f, -1.3789062f, -5.5625f, -0.64257812f, 0.2890625f, 0.77050781f, 5.78125f, 3.2246094f, 4.2109375f, - - 1.4667969f, 2.453125f, -2.6875f, -0.88574219f, 0.36987305f, 1.1767578f, -2.5839844f, -0.1854248f, 4.84375f, 2.1875f, 1.7265625f, -3.8359375f, 5.0273438f, 3.9042969f, 3.0253906f, 1.9316406f, -1.6171875f, 3.9023438f, 0.80712891f, -1.5703125f, -3.6582031f, -1.6386719f, 1.6191406f, 2.6425781f, -5.5585938f, 4.5234375f, -1.7978516f, 4.8242188f, 0.61767578f, 0.022384644f, -5.0f, -3.1269531f, 2.5644531f, 2.6113281f, -2.3339844f, -1.4707031f, 0.72900391f, -4.9882812f, -0.98535156f, -0.73828125f, - - -4.8515625f, -0.95214844f, 4.0273438f, -0.79248047f, -0.0082321167f, 1.3789062f, -1.3271484f, 0.42504883f, 0.70166016f, -1.2441406f, 2.8515625f, -3.4824219f, 3.2890625f, -1.7714844f, -1.5449219f, 6.3203125f, 1.9228516f, 0.37255859f, 1.2382812f, 0.13635254f, 0.65039062f, 2.5429688f, 2.5722656f, -0.81787109f, -2.0058594f, 5.5429688f, -3.3691406f, 0.92480469f, -4.78125f, -0.28393555f, 2.0214844f, -2.0117188f, -3.078125f, 0.46289062f, 0.20227051f, -3.3828125f, -3.0273438f, 0.95654297f, -2.40625f, -1.2744141f, - - -1.9931641f, 2.8261719f, -0.57470703f, 2.5820312f, 3.6816406f, 1.78125f, 3.1953125f, -1.0664062f, 2.484375f, -2.265625f, 1.1123047f, 1.6445312f, -3.3222656f, 4.1601562f, -1.3828125f, -1.2744141f, -4.1875f, -2.5488281f, 0.1439209f, 0.36401367f, 1.2402344f, -1.9980469f, 2.9238281f, -0.83837891f, 0.23828125f, 2.7226562f, 3.8300781f, 0.30273438f, -1.8193359f, -1.0390625f, -0.15588379f, 0.17749023f, -2.1328125f, -0.40917969f, -0.30444336f, 0.31567383f, 0.43164062f, -1.1347656f, 0.37231445f, -1.3730469f, - - -2.203125f, -0.0080795288f, -0.62060547f, -0.057769775f, 3.2050781f, -1.9423828f, -0.44946289f, 3.3710938f, 1.6572266f, 0.31713867f, 2.6894531f, -2.0605469f, -1.546875f, -2.1328125f, 0.13586426f, 0.78369141f, -1.2148438f, -1.0078125f, 0.30273438f, 1.375f, 0.62548828f, -2.5820312f, -1.6708984f, -0.040985107f, -3.34375f, 1.7207031f, -6.5195312f, 0.10418701f, -0.58398438f, -0.98925781f, 0.72460938f, -2.1347656f, -1.4980469f, -2.0566406f, -0.33642578f, 3.9960938f, -1.7841797f, 0.94042969f, -2.71875f, 0.61865234f, - - -2.0078125f, 2.9941406f, -0.59277344f, 2.5761719f, 3.7832031f, 1.765625f, 3.3105469f, -1.078125f, 2.5195312f, -2.3027344f, 1.0693359f, 1.7207031f, -3.3554688f, 4.2421875f, -1.4033203f, -1.2929688f, -4.2070312f, -2.5683594f, 0.17724609f, 0.41577148f, 1.3242188f, -1.9326172f, 2.9101562f, -0.88330078f, 0.23376465f, 2.6992188f, 3.8300781f, 0.42358398f, -1.8964844f, -1.0371094f, -0.16442871f, 0.17700195f, -2.2109375f, -0.44287109f, -0.33642578f, 0.28515625f, 0.49194336f, -1.2324219f, 0.38037109f, -1.4160156f, - - -1.8134766f, 3.0058594f, -0.13061523f, 1.6318359f, 4.8476562f, -3.1074219f, 0.62841797f, 1.4414062f, 1.3876953f, 0.27319336f, 1.5742188f, -4.1679688f, 0.31518555f, -1.4072266f, 1.3613281f, 3.0175781f, -0.39794922f, -1.6777344f, 1.0517578f, 2.3359375f, 0.76806641f, -3.0585938f, 0.45483398f, -0.12078857f, -3.3105469f, -0.37841797f, -8.515625f, -0.11773682f, -0.23059082f, -1.6289062f, 0.27539062f, -2.3066406f, -2.1972656f, -2.8554688f, -3.1679688f, 2.7988281f, -3.1972656f, 1.3339844f, -4.359375f, 0.042053223f, - - 0.097961426f, 0.14807129f, -0.45410156f, 1.3339844f, -1.1279297f, 2.3261719f, 0.484375f, -0.72314453f, -1.1708984f, 0.81201172f, 3.3320312f, 1.7109375f, 1.453125f, 4.6484375f, -1.4169922f, -0.609375f, -1.1728516f, -1.0458984f, 2.5996094f, 0.47900391f, 2.984375f, -0.81835938f, 3.9121094f, -0.079711914f, -0.32177734f, 2.7636719f, 3.0507812f, -2.6953125f, -0.52294922f, -0.22570801f, 2.1582031f, 1.5126953f, -3.2558594f, -3.2695312f, -2.21875f, 2.7285156f, -2.0761719f, -0.89990234f, -2.3828125f, 0.044006348f, + LoadTensor("CrossAttentionData_HeadSize40.query_data", data.query_data); + LoadTensor("CrossAttentionData_HeadSize40.key_data", data.key_data); + LoadTensor("CrossAttentionData_HeadSize40.value_data", data.value_data); + LoadTensor("CrossAttentionData_HeadSize40.bias_data", data.bias_data); + LoadTensor("CrossAttentionData_HeadSize40.fp32_output_data", data.fp32_output_data); + LoadTensor("CrossAttentionData_HeadSize40.fp16_output_data", data.fp16_output_data); +} - 1.2402344f, 2.2792969f, 0.33398438f, 2.2519531f, 0.67041016f, -0.55957031f, 0.20666504f, 1.3583984f, -1.9716797f, 2.6074219f, 2.2832031f, -2.0546875f, -2.4335938f, 0.53515625f, -0.15100098f, 1.9599609f, -0.51513672f, 0.31030273f, -0.49169922f, 1.4677734f, 2.234375f, 0.87451172f, 0.54736328f, -1.8681641f, -4.2265625f, -0.97509766f, -7.296875f, -1.3486328f, 1.3769531f, -1.8427734f, 3.1601562f, -2.4238281f, -0.82421875f, -2.7324219f, -0.52734375f, 2.2089844f, 0.66796875f, -0.42236328f, -3.03125f, -0.047302246f}; - } +void GetCrossAttentionData_HeadSize40_NoBias(AttentionTestData& data) { + GetCrossAttentionData_HeadSize40(data); + data.bias_data.clear(); + LoadTensor("CrossAttentionData_HeadSize40_NoBias.fp32_output_data", data.fp32_output_data); + data.fp16_output_data = data.fp32_output_data; } void GetCrossAttentionData_Batch2_HeadSize32_RightSidePadding(AttentionTestData& data, bool is_mask_1d) { @@ -1924,230 +106,20 @@ void GetCrossAttentionData_Batch2_HeadSize32_RightSidePadding(AttentionTestData& AttentionKernelType::AttentionKernel_TrtFusedAttention, AttentionKernelType::AttentionKernel_CutlassMemoryEfficientAttention}; - { - data.query_data = { - 0.66417468f, -2.82039404f, 1.66603971f, 4.84341049f, -1.63285708f, 3.61133432f, - -1.07151258f, -0.41698062f, -1.38491797f, -3.79137778f, 1.34514475f, -2.97253704f, - 2.12579250f, -0.02954102f, 2.30081463f, 0.21410012f, 1.84038579f, 0.46486610f, - -4.49463224f, 0.69027799f, 1.01090157f, 0.04715919f, -1.60957003f, 0.10730582f, - -5.77672052f, 0.37593889f, 2.04825425f, -1.00890708f, -3.88195300f, -2.69047785f, - 1.15699422f, -1.13536406f, -0.42816854f, 3.12039518f, 3.21898699f, -0.51998949f, - -4.72336435f, -0.78055519f, -0.72722042f, 3.17147565f, -1.31066322f, -3.09425855f, - -3.54743338f, -0.07284085f, 1.10525322f, 1.82087338f, -2.03681397f, -4.27978802f, - 0.26408362f, 0.58637118f, -2.07128787f, -3.48036027f, -0.03049034f, -1.99293542f, - -0.67289937f, 1.17342246f, -4.84998703f, -2.43558168f, 1.16422236f, 0.26511097f, - -1.98199308f, -1.86423326f, 1.61366916f, -0.35201707f, - -1.43554640f, -1.37493825f, 2.32563400f, -1.31762123f, -1.46716797f, 0.18536982f, - 0.85819042f, -3.11506653f, -1.25773919f, 1.30177450f, 0.58314162f, -1.72039497f, - -4.55264997f, 0.02031951f, -2.83490133f, 2.69835496f, -0.07102034f, -2.05412841f, - -1.26518285f, 3.30601740f, -4.54173231f, 0.80148667f, -1.36685658f, -2.26921320f, - -0.94192690f, -2.77439642f, 0.43918809f, 1.44727242f, 1.53386545f, 2.67014980f, - 3.30231142f, -1.60745978f, -1.26032567f, 1.27801156f, 0.31288767f, 3.04471421f, - -1.09798527f, -2.76303077f, -1.68329728f, -4.78179169f, -0.86371553f, -1.57159030f, - -1.06435764f, 3.61700702f, 0.71459293f, -0.25048330f, 1.31865597f, -1.83117080f, - -1.10344386f, 2.94894052f, -1.33930528f, 1.94855583f, -1.94283628f, -0.64020038f, - 2.24100995f, 1.06447530f, -0.03809617f, 3.47241497f, -2.55227089f, 0.12048072f, - 2.88777542f, -1.73300576f, 3.10077643f, -0.37158102f, - - -0.76705527f, -1.27237630f, 3.55744553f, 0.84103155f, -2.37726879f, 0.20218298f, - -3.41723180f, 1.26160014f, 1.45791709f, -1.47226799f, -2.36974764f, 1.49916458f, - 1.68845606f, -1.33727181f, -2.18113089f, -0.64312577f, -1.06002951f, -0.98938328f, - 1.95285964f, 3.08321524f, 1.28492856f, 2.28907299f, 1.14324796f, -0.11273877f, - -5.96574259f, -1.80337310f, 3.86340094f, -2.42390299f, -1.29642844f, 0.14276078f, - -1.23373103f, -0.51519167f, -1.04046988f, 0.60624832f, -0.93274558f, 2.46919179f, - -0.58201206f, -3.43382907f, 1.63227773f, 1.92112875f, -0.17216301f, 2.79771209f, - 2.67759442f, 1.73900354f, -0.00557053f, -0.63086307f, -0.37115061f, 0.82691956f, - 1.81370568f, -0.48766607f, -1.05545425f, -2.79009533f, -7.64374399f, -2.65407372f, - -0.84429693f, 1.35677493f, -1.25277543f, 2.26928639f, -1.77852845f, 2.31752825f, - -1.28869593f, -2.97340727f, -2.87103486f, 2.17401385f, - 0.20970306f, -1.19119942f, 1.11263359f, 0.21227169f, -5.30872822f, -2.15851903f, - 0.63067430f, -0.49583313f, 3.05784941f, 0.09588236f, 0.76925617f, 1.18900692f, - 0.35771871f, -0.97235727f, 1.14949071f, -1.25595427f, 2.37192512f, -0.32522821f, - 1.42988098f, -0.38017935f, 2.49831486f, -0.30629224f, 1.08675146f, -1.02598715f, - -0.17971759f, -0.55683851f, 1.04535389f, 1.54741859f, -0.05179391f, 0.73957652f, - 0.54304504f, 1.95280874f, -1.19504929f, -1.19528544f, 1.33258319f, 0.13532166f, - -1.87509251f, 0.99605685f, 2.69439840f, 1.03421521f, 1.79539657f, 0.15001571f, - 0.55184591f, -0.84038037f, -2.08177447f, -1.43082356f, -1.52199960f, 1.69448102f, - 2.12475252f, -2.64191580f, 0.10776700f, -4.01538181f, 1.15558016f, -0.09849232f, - 0.33533198f, 3.34633803f, -2.89805937f, -2.51580763f, 0.94939411f, 1.36254668f, - 0.47172806f, 4.40817642f, -0.11368597f, -2.70789719f}; - } - { - data.key_data = { - 1.18319833f, -0.20700163f, -0.64873743f, 3.88316822f, -2.82827115f, 4.12166834f, 0.84225285f, -1.11044288f, - -1.75086212f, -1.66724730f, 2.22730064f, -3.22617316f, -0.14071584f, 0.58066225f, 3.04375815f, -1.43881261f, - -2.39294887f, 1.03637624f, -0.98744214f, 1.13576865f, -0.23876363f, 0.27395499f, -0.51450062f, -2.23614597f, - -2.12345290f, -0.68864471f, 2.56223369f, -1.14069867f, -2.14457107f, -1.32647824f, -1.20575166f, -0.98427975f, - 0.43083039f, -1.72496212f, 0.89925444f, -0.33879194f, -1.01836991f, 0.06260723f, -4.40405083f, 1.51136112f, - -1.57057071f, -2.49242449f, -0.37187487f, -3.55319405f, 1.50083232f, 0.37271553f, 1.00157571f, -0.50416815f, - 1.28753221f, -0.82453167f, -1.13294256f, -1.49514699f, 0.11243388f, 1.89696264f, -1.46173263f, 3.32755566f, - -0.54521537f, -2.61305809f, -0.43132567f, -0.33066380f, -0.47485363f, 3.62707257f, -0.61352783f, 2.21147466f, - -2.39673638f, 0.89925957f, -2.58643913f, -0.81968069f, 3.34945726f, 0.73745269f, -1.62732553f, -4.55126476f, - 2.78017616f, 0.33757699f, 2.50468874f, -4.14928627f, 0.20017165f, 3.62233806f, -4.17984772f, 2.60447359f, - 2.16826940f, 1.70457518f, 1.03199887f, 2.66712570f, 0.50808340f, -3.47132921f, -2.60008478f, 1.03852415f, - -0.53876096f, 3.36212158f, -5.49142551f, 1.69825470f, -2.98179603f, -3.39561105f, -2.33971524f, 1.23642313f, - 2.13283253f, -0.56307364f, -2.49120903f, 2.97641850f, -1.28758216f, 3.43342829f, 2.49575281f, 0.09292871f, - -0.46469527f, -3.95696974f, 2.16474032f, -2.15254521f, -2.24547267f, 2.34235692f, -1.02470589f, 3.97816467f, - 3.60425544f, 1.87994969f, -2.46964216f, 1.47802746f, -1.81441534f, -1.56946301f, 0.56189334f, -1.69905055f, - -1.83049631f, 4.64296293f, 3.36173010f, 1.17065477f, 0.62365234f, 1.23748016f, 0.63865232f, -2.90434527f, - 1.80253839f, 3.11227179f, -3.96782875f, -2.78780794f, 3.76587057f, -1.66908360f, 1.83301187f, -1.74414611f, - -2.83874130f, -2.00238085f, -6.45539570f, 0.56152177f, 2.52830791f, -4.32480669f, 1.40038610f, 0.83278954f, - 0.16065764f, -0.13457650f, 2.17216778f, -4.28218699f, 0.75475001f, -0.67497885f, -0.95346600f, 3.29623652f, - 1.84325528f, 1.18348145f, -0.23741919f, 2.49520302f, 0.88820332f, 1.15528166f, 0.75733638f, 2.09371948f, - -1.16427231f, 1.36415648f, -1.17721760f, 0.19180456f, -3.83617687f, -0.22694540f, 5.14728260f, -0.43242604f, - -2.59039426f, -1.40904129f, 0.58194822f, -2.59625196f, -3.60205126f, 1.45633197f, 3.66319609f, -4.45727873f, - 3.95457315f, -0.17875004f, 2.43404126f, 2.83592010f, 0.87342203f, 1.24538708f, 3.10003138f, 2.63025975f, - 4.57258415f, -5.20645714f, -2.55821514f, 0.60136455f, -4.13579988f, -2.04082966f, 2.21142578f, -1.05740535f, - - 1.78609943f, -3.10438013f, -0.13040465f, -3.02957106f, 0.91924584f, 0.45405358f, -1.90627027f, -1.05065346f, - -1.21743047f, -1.65989709f, -0.51138550f, 2.04327297f, 0.65217698f, 0.77914226f, 1.86315429f, 0.75791669f, - -0.55304748f, -1.23857486f, 2.63207936f, -0.51371288f, 5.48993397f, -2.35509205f, -2.30255723f, 3.88706803f, - -1.93575382f, 0.03364474f, -1.61156952f, -2.74172544f, 1.64667726f, 0.04652762f, 2.88130736f, -2.00066185f, - 0.74907655f, -3.35894132f, -1.85703170f, 1.78695405f, 0.16497552f, 0.94382036f, 3.04452896f, -4.42404556f, - -1.67239439f, 0.93356639f, 0.08288032f, -0.11422639f, -3.94759631f, 0.35302341f, -1.20778334f, -1.92491865f, - -1.86599326f, -1.29324412f, -1.12795746f, 0.24268979f, -0.50242394f, 2.26449108f, 0.91289425f, -2.48235416f, - -1.12685704f, -0.32806787f, 3.28139257f, 3.19231367f, 0.99441254f, -1.86975384f, -3.57600951f, 0.07424650f, - -0.45312887f, 5.02197504f, -3.93365264f, -3.30742884f, -1.48101401f, 1.03335130f, 2.79531693f, -3.71739435f, - 1.58574414f, -4.52857542f, 1.99908066f, 1.53755212f, 1.60631371f, -2.46801257f, -1.85840714f, 5.07508087f, - 1.69143867f, -1.04688716f, -3.17096090f, -4.08357859f, -0.02436948f, -1.26299214f, 1.55509603f, 3.11954260f, - 3.55844116f, 0.10080734f, -0.57031679f, 2.01342750f, -0.66671205f, -1.89724469f, 2.52388906f, 3.71421099f, - 0.77953398f, -1.63364959f, -1.90900147f, -3.60591793f, 1.17604601f, -1.69456589f, -1.62096381f, -1.44886708f, - -1.09821022f, -1.27646899f, 2.73696446f, -2.21802664f, -0.22022307f, 1.76918471f, -1.55524099f, 0.27310926f, - -0.56175643f, -0.59620953f, 2.34752941f, -0.74946308f, -2.33520174f, 1.37984359f, -1.82466078f, -0.04973821f, - -4.77387571f, -0.85034770f, 3.39579129f, -2.82413197f, -2.37980723f, 0.10482252f, 0.10614476f, 0.38176090f, - -0.03948998f, -3.33898020f, 0.33013302f, -0.24926627f, 1.82249093f, 0.57584983f, -0.68790460f, -0.62760007f, - 0.17052543f, -0.54540014f, 1.66043472f, -0.29917845f, 3.31803465f, 0.86704284f, -0.26854402f, 2.23795938f, - -0.65058500f, -2.01540327f, -2.32472515f, -2.85143948f, -3.76564598f, -0.25596800f, -2.08064461f, -0.60812098f, - 3.64154029f, -2.58636141f, -0.25312662f, -2.22530699f, -1.24763203f, -3.08458424f, 0.69228125f, -1.84211481f, - 1.09744453f, -1.35679579f, 1.68044925f, 0.89537722f, 3.56465936f, -0.64790231f, -1.42140329f, -2.85126376f, - 0.88302374f, -0.77923191f, -0.61865216f, -3.08081675f, 0.87791818f, -0.27943787f, 0.46918952f, 1.50163293f, - 3.43236423f, 1.99953759f, -2.42805409f, 4.97383118f, -2.13942194f, 1.45409000f, -1.14207470f, 0.63804722f, - -4.23801470f, 1.23076391f, 2.71176004f, 1.13607812f, 2.27742863f, 1.64165723f, 1.20048785f, -0.66269439f}; - } - - { - data.value_data = { - 2.52855659f, 1.00436294f, 0.83871710f, 0.97005701f, 1.33615291f, -2.07353282f, 0.14190522f, -1.42923164f, - -0.05781263f, -3.81081843f, 1.15263164f, 0.62601233f, -0.93824124f, 1.21525323f, -0.17992918f, 2.08717370f, - 3.61659431f, -0.16836943f, 2.17779160f, -0.63968349f, 0.32170480f, 1.74428463f, -0.46570981f, -0.07432288f, - -0.21569058f, 0.65559602f, 3.58669281f, 0.40837619f, 2.40912223f, 1.31780922f, -4.45945454f, 0.64903581f, - -1.10752177f, -1.79390311f, 0.89312351f, -1.84512544f, -1.13948750f, 3.87221098f, -2.74163318f, 2.90849519f, - -0.31782085f, 3.12108278f, 0.80056298f, 1.02164125f, -0.07995117f, -0.96148860f, 3.49803638f, -4.48321056f, - -1.50024915f, -2.58987570f, 0.61711067f, 4.13532829f, -4.38111591f, -2.48988461f, -0.43977243f, -3.93134618f, - -2.67314148f, 2.64455128f, 0.11041284f, 1.26786041f, -0.24446392f, -0.86178148f, 2.35680771f, -1.69236851f, - -1.22143269f, 1.99185669f, 2.99625540f, -2.32311869f, -2.26162481f, 3.13980794f, 0.37014920f, 3.22335911f, - 2.55935216f, 2.19479871f, 4.89236355f, 1.76135564f, -2.74285603f, 1.39842391f, -0.25135490f, -4.76257038f, - -0.80362052f, -1.75548995f, -4.70487833f, 1.72763062f, 3.14491320f, 3.97562551f, -0.64091396f, -0.49683607f, - 1.09094775f, -0.04886785f, -0.20181555f, 2.22182846f, 3.00734067f, -0.52149582f, -1.55592132f, 4.41542721f, - 4.68795204f, -1.03364658f, 1.12266266f, -1.50595415f, -4.82583904f, -0.65535200f, -1.44525290f, -0.24540535f, - -0.44778955f, 2.32284093f, 1.60033488f, 0.12583408f, -4.42107201f, -1.32412672f, -1.84733653f, -1.53440499f, - 3.21279287f, -0.37051341f, 0.26685789f, 2.25037003f, 0.01608747f, 1.66141725f, -0.53394145f, 1.35017800f, - 1.35997009f, -2.73341703f, 5.47488451f, 5.49519920f, -1.90401053f, 3.37626982f, -1.97467375f, 1.91208827f, - -0.39609963f, -3.46037388f, -1.47946858f, 3.59935665f, 2.36377144f, -2.32310963f, 1.95714176f, -3.10615826f, - -1.72878003f, 0.37169266f, -5.95610952f, -1.32819366f, -1.24326205f, 0.17746472f, 2.59834385f, 1.83808351f, - 2.94952321f, 3.01939392f, 1.37281823f, 2.67180538f, -0.32547897f, 1.11373281f, -0.26456773f, 0.30103314f, - -1.05465972f, -1.74858260f, 4.66243505f, -0.58474910f, 1.26216507f, 1.28856802f, 0.30135399f, -3.24127388f, - 1.57217860f, -3.84659171f, 1.52000761f, -0.57999939f, 7.80852032f, 2.83661318f, -1.72516418f, 0.70036685f, - 5.33224869f, 3.27205563f, 0.22613347f, 1.27628899f, 0.63828707f, 0.60137266f, 2.23047280f, -3.12771320f, - -0.03023779f, 0.80765182f, -2.25078392f, -2.55701947f, -1.01789987f, -4.81986141f, 5.08153057f, -1.74439597f, - -2.12658811f, -0.01458025f, -2.19556737f, 0.66254830f, -0.97602153f, -0.09858370f, -2.05090475f, -3.57909155f, - - 4.57896709f, -1.96923888f, -3.86827421f, 3.18770289f, -5.16361237f, 1.42594528f, -1.43490076f, 1.62748218f, - 0.91413617f, -0.27147734f, 0.89311242f, 0.39315015f, 1.18184900f, 4.30172014f, -2.32771754f, 1.61144018f, - 1.31702828f, 1.47999883f, -0.20565452f, 0.75846130f, -0.13237280f, -2.10059071f, 0.12025893f, -0.58277643f, - 1.93927395f, -3.11170292f, 0.84666562f, 0.08490577f, -0.36315954f, -3.13071823f, 0.12070303f, -0.10385191f, - -2.37523723f, 2.28944397f, 0.12518460f, -1.10043252f, -1.94665289f, 3.44240570f, 1.14374518f, 3.27769613f, - 1.40222466f, 0.68902296f, 2.48193359f, 1.85469973f, 0.53099388f, -2.16307211f, 0.67865700f, -0.05084896f, - 0.09825261f, 1.40057099f, -0.74452353f, 0.81515837f, 1.51540780f, -1.30754757f, -1.50317430f, -2.04524612f, - -0.49154273f, 0.75809133f, -0.25134420f, 0.36961895f, -0.01882899f, -1.72547066f, 1.12012851f, -6.72828960f, - 1.76177442f, 1.19128907f, -0.77717477f, -1.97159290f, -2.30860472f, 2.01583147f, 5.43375349f, 2.58655977f, - 0.71099019f, 0.71843386f, 3.10709906f, 1.48128355f, 0.22561067f, -4.27442265f, -2.49249840f, 4.71605539f, - 2.19818974f, -1.96133125f, 0.41619009f, 0.66834581f, -3.74457240f, -0.48215276f, -1.28305256f, -1.83142948f, - -0.72452945f, -1.97440028f, -0.14068973f, 0.11765432f, 0.49793118f, 0.40227121f, -1.34390569f, 0.92099732f, - -1.21718168f, -1.95382285f, 1.37468243f, -0.72062874f, 2.66714525f, 1.06695974f, -2.86761045f, 1.34743905f, - 3.30500460f, -0.91894615f, -0.09608981f, -4.09408808f, -2.57941151f, -0.36501098f, 1.93333972f, 1.54577386f, - -2.96415496f, -2.09494066f, 1.63500857f, -1.51829720f, -0.98314112f, -1.89401948f, -0.54314089f, -3.68928242f, - 1.07439506f, 1.70869648f, 0.86973846f, 1.71959770f, 1.78241849f, -4.29455566f, -1.55857742f, -3.32966399f, - 0.20903873f, 1.40176547f, -6.08825064f, 2.12755013f, 3.84799123f, -0.83979988f, -1.64312506f, -0.69876713f, - 4.00779629f, -2.85212469f, 0.09145057f, 1.72984874f, -0.77233994f, 1.21815240f, -1.75377214f, 4.08561277f, - -1.20909250f, -1.24881196f, 4.37579060f, 4.27434301f, -2.01065826f, 2.96602201f, 3.07406378f, 1.22374272f, - 0.06376281f, -1.60328245f, -1.32239270f, 1.00765312f, 1.27593243f, -2.14843464f, -3.47884607f, -0.32401958f, - -2.52805567f, -1.01782882f, 0.74270618f, 1.47170806f, -2.56010485f, -1.49985540f, 0.92767721f, 3.42378139f, - 5.23711205f, 0.47062784f, -0.26747131f, -2.06014609f, -0.20237172f, -1.60944867f, -2.51956654f, 0.59529293f, - 2.63805699f, 0.43868792f, -5.84081888f, 3.25271368f, -4.44406748f, -3.80642724f, -1.59846020f, -2.59634686f, - 0.11074528f, 2.04441738f, -1.51878321f, -2.59639883f, 2.23697233f, 0.07920718f, 1.31056094f, -8.10540771f}; - } - - { - data.bias_data = { - -0.38124341f, 0.02696526f, -0.11914945f, -0.43795273f, -0.34948170f, -0.19608477f, 0.19725692f, 0.39987487f, - 0.04772711f, -0.03419551f, -0.30606642f, 0.42656231f, -0.23178342f, -0.13692456f, -0.04889601f, 0.48739988f, - -0.25891554f, 0.13431972f, 0.22861153f, 0.06360734f, 0.48096961f, -0.47906545f, 0.43613154f, -0.23511401f, - -0.10595283f, -0.42839217f, 0.28931111f, -0.13180739f, -0.45826656f, 0.23286396f, -0.43407962f, 0.40754890f, - 0.23778325f, 0.34850210f, -0.01385659f, 0.32141626f, -0.27738628f, 0.27683002f, 0.31886810f, -0.24781504f, - -0.25476855f, -0.46742713f, -0.12478521f, 0.39731556f, -0.12087554f, 0.40822440f, 0.13202906f, -0.23747686f, - 0.30502868f, 0.27182943f, -0.03640261f, -0.39626551f, -0.22411832f, 0.17324352f, -0.49959660f, -0.49318257f, - 0.31363028f, 0.05469471f, -0.00390345f, -0.46100286f, -0.27253938f, 0.17251462f, 0.46564627f, 0.21038425f, - 0.27079183f, 0.42074734f, -0.40314156f, -0.43726659f, 0.27376485f, -0.38174152f, -0.43700469f, 0.38040614f, - -0.40546918f, 0.06927037f, 0.16979086f, 0.41458064f, 0.07120579f, -0.08055863f, 0.12095112f, -0.27988660f, - 0.06004709f, -0.05600315f, -0.25510073f, 0.41887105f, -0.19016314f, 0.47241372f, 0.12890404f, -0.24272856f, - 0.21106839f, -0.40523255f, 0.10336459f, -0.11084765f, 0.42408967f, -0.15285304f, -0.28945464f, -0.25714916f, - 0.40978593f, -0.09138483f, -0.02013114f, -0.39042589f, -0.19557095f, 0.07540411f, 0.33955890f, 0.41873980f, - -0.27744853f, -0.33097768f, -0.44587523f, -0.01648277f, 0.34952271f, -0.48838940f, -0.17273578f, 0.37286615f, - -0.10157353f, -0.08097187f, 0.23243034f, 0.25516337f, -0.45793599f, 0.08089012f, 0.17673731f, 0.03000754f, - 0.48834521f, 0.35069120f, -0.32989410f, 0.20729345f, 0.24406803f, 0.35393929f, -0.16146761f, 0.04258209f, - -0.10567203f, 0.26791072f, -0.08976898f, 0.31341976f, 0.06027532f, 0.14307594f, 0.31587386f, 0.16180152f, - 0.34785229f, 0.00531715f, -0.35168743f, -0.11641458f, 0.39196932f, 0.44535065f, 0.43545735f, 0.15593112f, - 0.06171834f, -0.42181283f, -0.41170910f, 0.40969193f, -0.01510030f, 0.07973170f, -0.18156880f, 0.21522856f, - 0.03915739f, -0.20913908f, -0.47068381f, 0.35633272f, -0.35124153f, 0.36624825f, -0.05567622f, -0.35343069f, - 0.12821168f, 0.35526341f, -0.23420528f, -0.46328634f, -0.21994811f, -0.27556795f, 0.01653767f, 0.42626363f, - 0.23239774f, 0.39632857f, 0.32416028f, -0.48494491f, -0.05365932f, -0.10860911f, 0.06893444f, 0.46116674f, - 0.34345043f, -0.02719739f, -0.39574289f, -0.39339882f, 0.23044002f, -0.06155324f, 0.23292047f, 0.39775699f, - 0.12789404f, -0.44719657f, 0.12020230f, 0.26871282f, -0.10917315f, -0.29244915f, 0.09059817f, -0.19613290f}; - } - - { - data.fp32_output_data = { - 2.42288446f, 1.27227366f, 0.74894810f, 1.28347683f, 1.39642823f, -1.93045688f, 0.45777908f, -1.26743007f, - 0.29003966f, -3.80550122f, 0.80094421f, 0.50959778f, -0.54627192f, 1.66060388f, 0.25552815f, 2.24310493f, - 3.67831278f, -0.59018224f, 1.76608253f, -0.22999156f, 0.30660450f, 1.82401633f, -0.64727861f, 0.14090568f, - -0.17653319f, 0.44645694f, 3.11600900f, 0.76470888f, 2.05788064f, 1.68405747f, -4.51513100f, 0.29560512f, - -0.97931010f, -1.43863964f, 0.65891826f, -2.30841184f, -1.35943556f, 3.59664297f, -2.72509551f, 3.33475876f, - -0.08542311f, 3.51741123f, 1.12472320f, 0.53669631f, -0.13361049f, -1.07009768f, 3.56697083f, -4.02204370f, - -1.15679872f, -2.61707306f, 0.22136778f, 3.74192953f, -4.15067577f, -2.55143785f, -0.20685196f, -3.53358912f, - -2.54524755f, 2.19735479f, 0.23061514f, 1.53657317f, -0.35363707f, -1.15423059f, 2.44740582f, -1.88850141f, - - 2.42288446f, 1.27227366f, 0.74894810f, 1.28347683f, 1.39642823f, -1.93045688f, 0.45777908f, -1.26743007f, - 0.29003966f, -3.80550122f, 0.80094421f, 0.50959778f, -0.54627192f, 1.66060388f, 0.25552815f, 2.24310493f, - 3.67831278f, -0.59018224f, 1.76608253f, -0.22999156f, 0.30660450f, 1.82401633f, -0.64727861f, 0.14090568f, - -0.17653319f, 0.44645694f, 3.11600900f, 0.76470888f, 2.05788064f, 1.68405747f, -4.51513100f, 0.29560512f, - -0.97931010f, -1.43863964f, 0.65891826f, -2.30841184f, -1.35943556f, 3.59664297f, -2.72509551f, 3.33475876f, - -0.08542311f, 3.51741123f, 1.12472320f, 0.53669631f, -0.13361049f, -1.07009768f, 3.56697083f, -4.02204370f, - -1.15679872f, -2.61707306f, 0.22136778f, 3.74192953f, -4.15067577f, -2.55143785f, -0.20685196f, -3.53358912f, - -2.54524755f, 2.19735479f, 0.23061514f, 1.53657317f, -0.35363707f, -1.15423059f, 2.44740582f, -1.88850141f, - - 4.47329473f, -1.70132744f, -3.95804238f, 3.50112128f, -5.10333633f, 1.56902146f, -1.11902511f, 1.78928399f, - 1.26198828f, -0.26615992f, 0.54142559f, 0.27673587f, 1.57381809f, 4.74706888f, -1.89226031f, 1.76737213f, - 1.37874687f, 1.05818522f, -0.61736351f, 1.16815329f, -0.14747408f, -2.02085853f, -0.06131025f, -0.36754823f, - 1.97843063f, -3.32084179f, 0.37598154f, 0.44123849f, -0.71440083f, -2.76446915f, 0.06502641f, -0.45728233f, - -1.93884647f, 1.51549935f, 0.22349268f, -1.46264625f, -0.93878794f, 2.53468966f, 0.09279048f, 3.19028425f, - 2.14098549f, 0.65744257f, 2.12003636f, -0.21332240f, -0.35039914f, -1.79318547f, 1.08148456f, 0.83520722f, - -0.37325758f, 0.44315636f, -0.50703102f, -0.19921407f, 1.08093989f, -1.52517128f, -1.01477206f, -2.08499599f, - 0.05307493f, 0.56386751f, 0.16719794f, 0.99758488f, 0.35134155f, -2.70159864f, 0.49787593f, -6.01998806f, + LoadTensor("CrossAttentionData_Batch2_HeadSize32_RightSidePadding.query_data", data.query_data); + LoadTensor("CrossAttentionData_Batch2_HeadSize32_RightSidePadding.key_data", data.key_data); + LoadTensor("CrossAttentionData_Batch2_HeadSize32_RightSidePadding.value_data", data.value_data); + LoadTensor("CrossAttentionData_Batch2_HeadSize32_RightSidePadding.bias_data", data.bias_data); + LoadTensor("CrossAttentionData_Batch2_HeadSize32_RightSidePadding.fp32_output_data", data.fp32_output_data); + data.fp16_output_data = data.fp32_output_data; +} - 1.88393891f, 1.20359635f, -1.11693203f, -1.24092197f, -2.47922421f, 2.11120105f, 5.19413376f, 2.67079711f, - 1.07527149f, 0.64369327f, 2.57635832f, 1.27686763f, 0.69491446f, -3.13548803f, -2.04371452f, 4.62090492f, - 2.18864536f, -2.10483122f, -0.04580984f, 1.08532572f, -3.46754074f, -0.53330994f, -1.35113037f, -1.51521778f, - -0.46994060f, -2.27551699f, -0.53152251f, 0.47133854f, 0.07705012f, 0.48279381f, -1.28113365f, 0.48468336f, - -1.54411674f, 0.06915778f, 0.64939111f, -1.33318806f, 0.63385141f, 1.72500539f, -1.27450287f, 2.53234506f, - 2.78955889f, 0.10935718f, 1.24130249f, -2.24100065f, -1.41059852f, -1.18030620f, 1.50915027f, 1.37942517f, - -1.41709673f, -0.74830860f, 0.30404601f, -0.99458563f, 0.22929534f, -1.72507358f, -0.68753922f, -2.64537501f, - 0.58683372f, 0.88788664f, 0.54932535f, 1.45773280f, 0.96530700f, -3.57728553f, -0.41517627f, -4.86154747f}; - } +void GetCrossAttentionData_Batch2_HeadSize32_RightSidePadding_NoBias(AttentionTestData& data, bool is_mask_1d) { + GetCrossAttentionData_Batch2_HeadSize32_RightSidePadding(data, is_mask_1d); + data.bias_data.clear(); - { - data.fp16_output_data = data.fp32_output_data; - } + LoadTensor("CrossAttentionData_Batch2_HeadSize32_RightSidePadding_NoBias.fp32_output_data", data.fp32_output_data); + data.fp16_output_data = data.fp32_output_data; } void GetCrossAttentionData_Batch1_HeadSize32_LeftSidePadding(AttentionTestData& data) { @@ -2166,126 +138,19 @@ void GetCrossAttentionData_Batch1_HeadSize32_LeftSidePadding(AttentionTestData& AttentionKernelType::AttentionKernel_TrtFusedAttention, AttentionKernelType::AttentionKernel_CutlassMemoryEfficientAttention}; - { - data.query_data = { - 2.88765883f, 1.27536213f, -0.57580215f, 2.73696542f, 2.19016314f, 0.42629790f, 1.55081677f, -2.01307678f, - -0.80203497f, -1.23206115f, 1.78565156f, -2.09875321f, -2.22730732f, -0.98120236f, -0.25774139f, 0.75868356f, - -2.87585187f, -0.41810805f, -2.11528730f, 0.50642025f, -0.29446256f, -3.69675803f, -2.73721838f, -1.51089072f, - 0.74300194f, 0.27352047f, -0.88251829f, 2.82622814f, 0.73837662f, -2.14588642f, 0.37608737f, -0.06190044f, - -1.97659302f, -2.22348428f, 2.25573063f, -2.24459195f, -2.28073978f, -0.52412349f, -0.57297325f, 3.29259396f, - 1.35617173f, -0.83082151f, 0.03767079f, 1.82568312f, 0.88193995f, 1.15579486f, 1.87845564f, -0.15923920f, - 2.37435389f, 1.49093378f, 1.95134592f, -1.67609048f, -0.45959851f, 1.63960719f, 3.44909906f, -0.23531833f, - -0.57074630f, 1.38279045f, 0.58870834f, 0.85297751f, -1.44973445f, 1.56243801f, -0.67229253f, -0.16198707f, - - -0.23966503f, -0.15329531f, -3.22765136f, 0.60538405f, -0.33244422f, -1.34865439f, -0.24373266f, -1.78808010f, - -1.53090763f, 1.75037694f, -0.71890754f, 0.12527336f, 1.26654553f, -0.86477917f, -1.49822962f, 1.67973542f, - 0.99763191f, -0.07183220f, 1.55289185f, 1.62626481f, -0.04283767f, -2.55072594f, -1.95238030f, 0.60994428f, - -2.53714681f, 1.54605150f, 0.05900350f, 1.42194426f, 0.33801061f, 1.25557244f, 0.67291188f, -1.36867523f, - 1.86936152f, -1.19588101f, 0.75778806f, 1.85271311f, 0.02081686f, 2.65807819f, 0.78890860f, -1.07388866f, - 4.18109226f, 0.06373940f, 2.86840463f, 0.90427721f, -0.09531648f, -0.40835506f, 1.60812938f, -1.61683714f, - -0.45421624f, -2.25537109f, -1.35910070f, -0.25111723f, -0.71782172f, 0.62597942f, -0.42838976f, 0.23198499f, - 1.29250073f, -2.01550317f, 0.14619158f, -0.03868395f, -0.74211842f, -3.17291188f, -1.90475547f, 2.02544284f}; - } - { - data.key_data = { - 1.14242256f, 1.08148384f, -0.00962424f, -1.62719429f, 0.86478198f, 0.16862091f, 1.01692820f, -1.15278327f, - -1.13622630f, 1.78038371f, 0.58222097f, 0.39166588f, 1.75063372f, -1.20408881f, 0.75154918f, 0.58156419f, - -0.98975772f, -0.82555556f, -0.72656512f, -2.42399549f, 2.19217968f, 2.18518472f, -1.72216129f, 1.35098433f, - -0.34989786f, -0.69064844f, -0.98365444f, 3.10148478f, 0.64813483f, 1.78129303f, -0.47006512f, 2.53122735f, - 0.09757380f, 0.04077591f, -0.81791472f, -0.19737752f, 1.13775492f, -1.51351953f, 0.59109330f, 2.86624002f, - -0.09282493f, -1.69204521f, 1.27087700f, 3.53944731f, 0.59776509f, -0.90838081f, -0.15813766f, -1.86199224f, - 0.18734205f, -0.76110429f, -0.02243887f, -0.94068182f, 1.32443166f, 0.03512055f, -0.13194422f, -1.50401211f, - 0.92001319f, 0.20918207f, -1.34839189f, 1.56431675f, -0.61030018f, 2.39562368f, -1.56722510f, -0.96874726f, - -0.48726845f, -1.41476154f, -1.45116997f, 0.53907454f, -2.14415288f, 1.14340270f, -0.21846619f, -2.72349358f, - 2.99664998f, -2.38684058f, 0.95269018f, 0.04208702f, -1.75080788f, 1.24652982f, -1.76879966f, 3.10814905f, - 2.48754454f, -0.62601894f, 1.41356945f, 0.10340121f, 1.09059846f, -0.78241473f, -0.61477584f, -0.19339988f, - -0.48253334f, -2.41782594f, 1.04690075f, 0.14725411f, -0.20820639f, -1.95920563f, 0.96303236f, -1.20068836f, - - -1.71051037f, -1.90946770f, -2.07985783f, 2.35042953f, 0.35059446f, -0.44228595f, 4.08558750f, -0.60121447f, - 0.78836018f, 0.35280651f, 0.23129070f, -0.21523762f, 0.12277550f, 0.12348226f, -1.62759030f, -2.78246498f, - 4.04853964f, 0.29263157f, -0.38621908f, -1.07599223f, -1.99170423f, 1.41409016f, 2.19121861f, -3.53451037f, - 3.63692737f, 0.68270516f, 2.51469731f, 2.57543731f, -2.39040112f, -3.97164130f, 1.28371549f, 1.64144099f, - -0.70385075f, 2.55361128f, 1.60707259f, 0.84735453f, -2.07756495f, -1.99240303f, -3.60991144f, 2.87136865f, - 2.31296396f, 2.30251813f, -1.05624914f, -2.43777156f, -0.27048296f, 2.39037871f, -2.04504776f, 1.65183067f, - -0.38970214f, 0.16808379f, -1.30286717f, 1.90201700f, -2.71696734f, -0.66445369f, 1.27085483f, -0.60816145f, - 1.81054437f, -1.55584621f, -2.19360781f, -4.52794456f, -0.90534067f, 0.94724411f, 2.40401077f, -2.94815230f, - -3.19650269f, 2.50638890f, 1.02038431f, 1.50519919f, 0.47196171f, -1.89026380f, -1.86559379f, 0.82210326f, - 0.10818237f, 1.45290673f, 1.62321615f, -0.61283481f, -1.42501950f, 2.10349464f, -1.65715265f, 0.30090189f, - -3.81919909f, -2.44903922f, -1.20557833f, -0.69951278f, -1.31475580f, -3.73842764f, 1.49299407f, -0.70933276f, - -1.49021530f, 0.71776378f, -1.23052382f, -2.13119912f, -1.20718014f, 2.30572701f, 1.78386402f, -1.57122159f}; - } - - { - data.value_data = { - 1.79297853f, 0.96909231f, 1.23087275f, -0.61933923f, -0.56477690f, 1.47813499f, 0.51474279f, -3.44743419f, - 0.95816678f, -0.20553169f, -0.76906109f, -4.60927439f, 0.40629998f, 0.91934747f, -1.09594405f, -1.45653892f, - -0.59282207f, 0.05621797f, -2.26634383f, -1.30799258f, 1.22072279f, -3.60811162f, 1.70111597f, 0.47336632f, - -1.43857694f, -0.13917151f, -1.34617388f, 1.07960105f, -1.77342618f, 0.31946269f, 1.19137061f, 2.59346104f, - -1.82395399f, 0.73557752f, 2.32600021f, -0.22650969f, -0.48526058f, 1.40349376f, -0.33553454f, 0.45531431f, - 0.73859257f, 0.37798560f, 0.85344458f, -1.30447221f, 1.23349071f, -0.26439479f, 1.18636096f, -0.33328748f, - -0.50939041f, 0.53500950f, 1.33486223f, -1.54447496f, -2.88690519f, -0.06809106f, -0.00597921f, -1.07510388f, - 0.62182164f, 0.50033569f, -0.88293070f, 2.56142712f, 0.37708595f, 1.59349704f, -1.17139614f, 0.89580274f, - 0.69456708f, 2.91441655f, -0.25431669f, -1.20305562f, 2.06701255f, -0.86700624f, -2.23615170f, 0.13303493f, - -2.97540593f, 0.08654684f, 1.40381706f, 3.54294443f, -2.07661867f, -1.33181918f, 2.24228764f, 1.79975545f, - 2.14695477f, 1.40222490f, -0.29813689f, 1.94485068f, 1.99623775f, 1.53450203f, 0.28755581f, -0.67934704f, - -0.92102510f, -1.52764773f, 1.11267352f, -3.90122724f, 0.22128634f, 0.14945325f, -4.38529491f, -1.58423281f, - - -2.45574522f, -1.91599977f, 5.05240345f, 2.24617362f, 3.99182248f, 0.92924285f, -0.39660916f, -0.08696688f, - 0.24855530f, 0.71378094f, 0.92413902f, 1.73599064f, 1.03852975f, 2.44676781f, 0.35013664f, 0.98107171f, - 1.62946916f, 0.41239718f, -1.41385484f, 2.49293518f, 2.32976985f, 2.89612579f, 2.66875219f, 1.47379971f, - 1.31164551f, -1.82183075f, -5.15272474f, 0.28575048f, 0.16861364f, -0.47264135f, 0.22565089f, -0.37727535f, - -1.13935280f, 0.38051969f, -2.38735437f, -2.80645251f, 0.18637873f, 2.13938355f, 2.92260599f, -0.38653925f, - 0.58366799f, -1.67636371f, -2.29396892f, -1.31527638f, 2.39795637f, 0.39815575f, -0.98530269f, -1.29227996f, - 0.14452982f, -0.38186538f, -1.71267688f, 0.18121701f, -2.26441002f, -0.94511753f, 0.27371156f, -2.44858527f, - -0.21510160f, -2.65228534f, -2.16755104f, 0.86151361f, 0.77589297f, -1.06628847f, 0.73745233f, 1.15778029f, - -0.73659700f, 0.74325305f, -1.97666430f, -1.07301974f, 0.17534591f, -1.66584718f, 1.21820331f, 0.67675018f, - -1.08938253f, 1.78010321f, 0.39817584f, -0.02914053f, 1.13571596f, -0.44081455f, 1.70561552f, -2.12085509f, - -0.69322622f, -1.87331009f, -2.15000772f, 2.08436966f, 1.70494926f, -3.69169927f, -1.22119129f, -1.60190558f, - -2.09093666f, -1.02816033f, -1.78743768f, 2.34501553f, 2.79939008f, 1.82245076f, 1.47408092f, 1.10063124f}; - } - - { - data.bias_data = { - -0.38124341f, 0.02696526f, -0.11914945f, -0.43795273f, -0.34948170f, -0.19608477f, 0.19725692f, 0.39987487f, - 0.04772711f, -0.03419551f, -0.30606642f, 0.42656231f, -0.23178342f, -0.13692456f, -0.04889601f, 0.48739988f, - -0.25891554f, 0.13431972f, 0.22861153f, 0.06360734f, 0.48096961f, -0.47906545f, 0.43613154f, -0.23511401f, - -0.10595283f, -0.42839217f, 0.28931111f, -0.13180739f, -0.45826656f, 0.23286396f, -0.43407962f, 0.40754890f, - 0.27079183f, 0.42074734f, -0.40314156f, -0.43726659f, 0.27376485f, -0.38174152f, -0.43700469f, 0.38040614f, - -0.40546918f, 0.06927037f, 0.16979086f, 0.41458064f, 0.07120579f, -0.08055863f, 0.12095112f, -0.27988660f, - 0.06004709f, -0.05600315f, -0.25510073f, 0.41887105f, -0.19016314f, 0.47241372f, 0.12890404f, -0.24272856f, - 0.21106839f, -0.40523255f, 0.10336459f, -0.11084765f, 0.42408967f, -0.15285304f, -0.28945464f, -0.25714916f, - -0.10567203f, 0.26791072f, -0.08976898f, 0.31341976f, 0.06027532f, 0.14307594f, 0.31587386f, 0.16180152f, - 0.34785229f, 0.00531715f, -0.35168743f, -0.11641458f, 0.39196932f, 0.44535065f, 0.43545735f, 0.15593112f, - 0.06171834f, -0.42181283f, -0.41170910f, 0.40969193f, -0.01510030f, 0.07973170f, -0.18156880f, 0.21522856f, - 0.03915739f, -0.20913908f, -0.47068381f, 0.35633272f, -0.35124153f, 0.36624825f, -0.05567622f, -0.35343069f}; - } - - { - data.fp32_output_data = { - 0.23503941f, 2.87619758f, 0.01845241f, -0.75242990f, 1.76869011f, -0.40492195f, -1.65323853f, 0.34011719f, - -2.10573196f, 0.13281155f, 0.97480160f, 2.74546146f, -1.21957457f, -0.73649400f, 2.52938581f, 1.65599120f, - 1.83545303f, 0.85856718f, -0.48040742f, 1.86428785f, 1.29504943f, 1.38906729f, 0.06474495f, -0.51972288f, - -0.66509569f, -1.45185244f, 0.36160457f, -2.63688278f, -0.10806514f, 0.71859169f, -3.98941422f, -1.58921516f, - - -1.89806330f, 1.03079379f, 2.20389438f, 0.07467184f, -0.39299977f, 1.51811528f, -0.04347950f, 0.61307698f, - 1.03990030f, 0.37965038f, 0.50865448f, -1.36013806f, 1.58397710f, 0.16757873f, 1.63505113f, -0.15062472f, - -0.41438234f, 0.12406474f, 0.90268815f, -1.09105420f, -2.84080887f, 0.03172458f, -0.18386938f, -0.85491556f, - 0.64164376f, 0.26578158f, -1.32860518f, 2.83676863f, 0.02389192f, 1.94164813f, -1.26734924f, 0.51129180f, - - -0.84226906f, 1.01116371f, -2.06643319f, -0.75959998f, 0.23562123f, -1.52277124f, 1.53407717f, 0.83855170f, - -0.74153024f, 1.78542042f, 0.04648840f, -0.14555511f, 1.52768528f, 0.00453609f, 2.14107275f, -1.96492398f, - -0.63150787f, -2.29512286f, -2.56171679f, 2.49406147f, 1.68984890f, -3.61196756f, -1.40276003f, -1.38667703f, - -2.05177927f, -1.23729944f, -2.25812149f, 2.70134830f, 2.44814849f, 2.18869901f, 1.41840470f, 0.74720055f, - - -0.84226906f, 1.01116371f, -2.06643319f, -0.75959998f, 0.23562123f, -1.52277124f, 1.53407717f, 0.83855170f, - -0.74153024f, 1.78542042f, 0.04648840f, -0.14555511f, 1.52768528f, 0.00453609f, 2.14107275f, -1.96492398f, - -0.63150787f, -2.29512286f, -2.56171679f, 2.49406147f, 1.68984890f, -3.61196756f, -1.40276003f, -1.38667703f, - -2.05177927f, -1.23729944f, -2.25812149f, 2.70134830f, 2.44814849f, 2.18869901f, 1.41840470f, 0.74720055f}; - } + LoadTensor("CrossAttentionData_Batch1_HeadSize32_LeftSidePadding.query_data", data.query_data); + LoadTensor("CrossAttentionData_Batch1_HeadSize32_LeftSidePadding.key_data", data.key_data); + LoadTensor("CrossAttentionData_Batch1_HeadSize32_LeftSidePadding.value_data", data.value_data); + LoadTensor("CrossAttentionData_Batch1_HeadSize32_LeftSidePadding.bias_data", data.bias_data); + LoadTensor("CrossAttentionData_Batch1_HeadSize32_LeftSidePadding.fp32_output_data", data.fp32_output_data); + data.fp16_output_data = data.fp32_output_data; +} - { - data.fp16_output_data = data.fp32_output_data; - } +void GetCrossAttentionData_Batch1_HeadSize32_LeftSidePadding_NoBias(AttentionTestData& data) { + GetCrossAttentionData_Batch1_HeadSize32_LeftSidePadding(data); + data.bias_data.clear(); + LoadTensor("CrossAttentionData_Batch1_HeadSize32_LeftSidePadding_NoBias.fp32_output_data", data.fp32_output_data); + data.fp16_output_data = data.fp32_output_data; } void GetCrossAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedKV(AttentionTestData& data) { @@ -2300,222 +165,14 @@ void GetCrossAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedKV(AttentionTes data.skip_kernel_types = { AttentionKernelType::AttentionKernel_Unfused, AttentionKernelType::AttentionKernel_TrtFusedAttention}; - { - data.query_data = { - -0.35420692f, 1.31206024f, -2.80201197f, 2.42258096f, -0.86031514f, -1.44535458f, -0.10832444f, -2.00132895f, - 1.62475216f, 0.10978927f, 1.84596729f, 0.48908550f, 1.44369888f, 0.87542874f, -1.16434252f, 0.52133209f, - 1.54848897f, -2.21174526f, -0.28574878f, 0.70815033f, 1.18327498f, 3.14097571f, -0.25795099f, 1.89341247f, - -0.11603792f, 0.38110194f, 0.40873206f, -1.14149106f, 0.79770875f, -0.98069525f, -1.53588808f, 0.50821728f, - -2.21641898f, 0.55090773f, 0.80901796f, -0.56089771f, 0.03574468f, -1.27940118f, -0.02213959f, -0.80698186f, - -0.82701880f, 1.72937381f, 1.56083691f, -0.30311784f, -0.25183848f, 0.24280515f, 0.29569417f, -0.31162494f, - 0.48996922f, 0.22795241f, 2.07125854f, 1.45823467f, 3.03750706f, 1.53734803f, 0.48668906f, -1.63703632f, - -0.14114749f, 1.85963213f, 1.20729232f, -0.28972962f, -0.80783498f, -1.16619551f, -0.60004634f, 0.02498829f, - - 3.50846076f, -2.50027657f, -2.59866142f, 1.58495271f, 2.21110034f, -2.74877763f, -1.00267041f, 0.62646407f, - 2.50227380f, -0.27291518f, -0.33037442f, 0.75840306f, 0.45437157f, -0.79876304f, 0.83509272f, 2.53716302f, - 0.01348384f, -2.16307616f, 2.01661849f, 2.10746121f, -1.70485222f, 1.35548759f, 1.39401650f, -0.99451691f, - -4.13484812f, 0.56262714f, -0.92725742f, -0.16389316f, -1.31260049f, 2.32357836f, -3.05251694f, -1.12570131f, - 1.87849474f, -1.80381167f, 0.52235699f, 2.38887334f, -1.58878529f, 0.69571090f, 1.65044296f, -0.27024290f, - 3.59580970f, -1.97888982f, 1.17034674f, 0.26716161f, -1.16770899f, 0.74609619f, 0.78886843f, 0.15717520f, - -0.93303132f, -0.84753871f, -4.32799959f, -1.94716609f, -1.16980326f, 1.62631667f, 2.41053247f, 3.78186774f, - 0.26432252f, -0.40396988f, 2.04414082f, 0.65150046f, 0.47777444f, -2.57569051f, 0.99004912f, 2.47947693f}; - } - { - data.key_data = { - 2.66554713f, 0.04116637f, -1.14599442f, -1.99071956f, 0.42523879f, 0.94212061f, 1.15597987f, -1.76809072f, - -1.89803648f, -0.74707657f, -0.71960962f, 0.67453432f, 3.31946969f, 1.06201041f, 2.29824829f, 0.23788756f, - 1.69329333f, 0.06745748f, -1.34720469f, 1.81031406f, -0.33143526f, -2.46566057f, -0.32179555f, 1.69001770f, - -0.39678648f, -0.91400242f, 1.56746745f, 0.36029303f, -1.01637018f, -1.84069777f, 0.15860040f, 1.35965717f, - 0.16654867f, 3.63810396f, 2.03763342f, 0.64186901f, -1.02682137f, 2.18480039f, -2.17365599f, -0.56225222f, - -2.48764873f, 1.94031644f, -1.13630998f, -2.51891637f, -1.29985571f, 0.23808026f, 2.95523596f, 1.06378591f, - -0.20339361f, -0.56349581f, 1.46587682f, 4.12142849f, 0.78908098f, -0.24000889f, -1.15510166f, 0.42653239f, - -1.98345447f, 1.06918168f, 2.98073006f, -2.94872737f, -0.67443597f, -0.96227646f, -1.94805872f, -0.96003568f, - 1.06492281f, 0.32333452f, -0.52869648f, -1.25258100f, 0.75479198f, -1.04409528f, -1.81722605f, 0.99018478f, - 1.83352923f, 1.02711058f, 0.31064227f, 2.44383168f, -1.80332434f, 1.57207584f, -0.41058558f, 0.20494992f, - -0.78399467f, -0.35703743f, -0.67568171f, -1.30091023f, -0.17390330f, 0.22340816f, -0.44613233f, 1.23870432f, - -0.16092014f, -1.22258115f, 0.60575533f, -0.17969827f, 1.87851882f, 1.13991237f, -0.81591004f, -1.68899822f, - - -1.72543812f, 0.63848293f, 0.87042624f, 0.39726460f, 0.62647510f, 1.73326159f, -0.55110240f, -1.26900804f, - 1.94843686f, -1.73077893f, 2.53475809f, 2.79892564f, -1.91852188f, 0.99826050f, -3.04680610f, 1.38900220f, - -1.17920876f, -2.07508063f, -0.34274688f, -0.24780962f, 1.75715542f, 1.27657294f, -1.15560341f, -2.69310951f, - 0.93523502f, 0.58213681f, -2.57009196f, 2.56376076f, 0.06911665f, 1.73962176f, 0.43307841f, -1.18240118f, - 1.52338290f, 1.02856898f, 0.40946901f, 1.57649779f, 1.22447217f, 0.85961932f, 0.30765539f, -2.66427660f, - -1.55998194f, -0.31161505f, -1.63090813f, -1.62476087f, 1.28381526f, -0.77024549f, 1.46711981f, -0.71657622f, - -0.51606011f, 0.87953311f, 0.26169056f, 1.03068113f, 0.41064253f, -1.56344402f, -1.53443003f, -0.03009570f, - -0.02123317f, -1.74375248f, 1.60988081f, 1.74488568f, 0.59155780f, -0.62032932f, 0.03105794f, 4.54175377f, - -2.08403850f, 0.22352570f, -0.17924348f, 0.65815634f, -0.59089363f, -1.66189861f, 0.75618476f, 0.03879535f, - 1.50222909f, -0.29873836f, -1.76075482f, -2.97067928f, 0.28112072f, 0.72105575f, 0.06761266f, -1.61681306f, - -0.80693424f, 2.40102959f, -2.91352296f, -1.21352315f, -1.62430143f, -1.60909438f, 0.53140688f, -0.28235722f, - 0.63271880f, 1.33791542f, -1.37593675f, -1.60502291f, 1.27470064f, -0.96280038f, 0.79614848f, 0.31894624f}; - } - - { - data.value_data = { - 0.67641568f, -1.44437671f, 0.57255918f, 0.11087912f, 0.73787844f, -1.36586773f, - 1.45507979f, -3.70331645f, -0.85970032f, -2.14545083f, 2.11107802f, -0.16663373f, - 1.47033095f, 0.49124131f, 1.99316287f, -2.68613410f, 0.23831765f, 0.90826637f, - 0.72628385f, 1.29567933f, -0.07918698f, 0.13999116f, 1.22531521f, 0.06399018f, - -2.24613571f, -1.08365369f, -0.68457615f, -0.25960952f, -0.88386559f, 0.46391147f, - 1.24469304f, 1.13121903f, - -0.21484625f, 3.49263334f, -1.35283577f, 0.38428289f, -4.29686069f, -4.34778786f, - -0.49574745f, -0.08637778f, -0.50855160f, -1.12334609f, -1.44851387f, 3.36797357f, - -0.91776383f, -0.98647243f, 1.45408130f, 0.29062888f, 0.24470398f, -1.28129590f, - 0.47530234f, 2.19562674f, 0.62674099f, -2.56222868f, -1.42671025f, 1.51795268f, - -1.92045701f, 1.20271325f, 2.53190184f, -0.37211552f, 0.92569226f, -1.11019444f, - 1.15402830f, -1.98479640f, - -0.49658760f, 1.62168694f, -1.71412969f, -1.26646388f, -1.37257946f, 1.53828073f, - -0.35583261f, 0.03810386f, 0.43514529f, 0.97525519f, -2.22109556f, 1.17547810f, - -0.28825673f, 0.91509271f, -1.19243717f, 1.09280133f, -0.51078367f, 0.63577116f, - -0.62186599f, -2.80234575f, -1.58007598f, 1.06965756f, -0.89327252f, -0.84735525f, - -0.46283475f, 0.77867299f, -0.07434830f, 1.44711912f, 1.07089376f, 0.78913736f, - 0.59053934f, -0.32160193f, - - 0.51273453f, 1.12628150f, 1.96404183f, 0.26380035f, 3.41526699f, 1.08249199f, - -1.70347631f, 0.42854923f, -1.98269284f, 1.97382474f, -0.12164606f, -1.41219604f, - 0.01819625f, 0.73082930f, -2.60845804f, 1.47046185f, 0.26324001f, 1.54259276f, - -1.18744254f, -1.77539694f, 1.76547086f, -1.57072937f, -1.83995926f, -0.05529352f, - 1.83544660f, 0.69575423f, -0.03345531f, -1.69629955f, 0.04713173f, 1.39800107f, - 0.24362923f, 0.12432972f, - -2.92895460f, -0.46070760f, 0.20383459f, 1.93618548f, -1.08026588f, 1.08253515f, - -0.48318014f, -2.34334373f, -2.69622159f, 0.00661799f, -1.10738027f, 0.03181311f, - 0.32897863f, 1.89451993f, -0.01152946f, 0.17766151f, 2.46450090f, -0.64409554f, - 2.56058550f, 1.29339278f, 2.72114944f, 0.87801707f, -1.58970404f, 2.88365316f, - 0.46464550f, -1.71912467f, -1.90960062f, -3.13572145f, 0.19871379f, -0.28741950f, - -0.38167781f, -2.30705547f, - 0.64399612f, 0.32866889f, -3.49091625f, -0.02294427f, 1.60225844f, 1.83659923f, - 1.55193460f, -0.06712314f, 0.76592684f, 0.83479869f, 0.49627584f, 0.75736403f, - 0.75179487f, -0.32156041f, 1.36537170f, 0.57024354f, 0.36152276f, 0.93625057f, - -1.69728792f, -0.28833422f, 0.43304375f, 1.62640548f, -0.00187188f, 0.80429250f, - -0.77993584f, 1.37333393f, -1.16019452f, -0.91983509f, 0.20466281f, 1.09339333f, - -0.99191529f, 3.42685890f}; - } - - { - data.bias_data = { - // 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, - // 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, - // 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, - // 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, - // 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f - }; - } - - { - data.kv_data = { - 2.66554713f, 0.04116637f, -1.14599442f, -1.99071956f, 0.42523879f, 0.94212061f, - 1.15597987f, -1.76809072f, -1.89803648f, -0.74707657f, -0.71960962f, 0.67453432f, - 3.31946969f, 1.06201041f, 2.29824829f, 0.23788756f, 1.69329333f, 0.06745748f, - -1.34720469f, 1.81031406f, -0.33143526f, -2.46566057f, -0.32179555f, 1.69001770f, - -0.39678648f, -0.91400242f, 1.56746745f, 0.36029303f, -1.01637018f, -1.84069777f, - 0.15860040f, 1.35965717f, - 0.67641568f, -1.44437671f, 0.57255918f, 0.11087912f, 0.73787844f, -1.36586773f, - 1.45507979f, -3.70331645f, -0.85970032f, -2.14545083f, 2.11107802f, -0.16663373f, - 1.47033095f, 0.49124131f, 1.99316287f, -2.68613410f, 0.23831765f, 0.90826637f, - 0.72628385f, 1.29567933f, -0.07918698f, 0.13999116f, 1.22531521f, 0.06399018f, - -2.24613571f, -1.08365369f, -0.68457615f, -0.25960952f, -0.88386559f, 0.46391147f, - 1.24469304f, 1.13121903f, - - 0.16654867f, 3.63810396f, 2.03763342f, 0.64186901f, -1.02682137f, 2.18480039f, - -2.17365599f, -0.56225222f, -2.48764873f, 1.94031644f, -1.13630998f, -2.51891637f, - -1.29985571f, 0.23808026f, 2.95523596f, 1.06378591f, -0.20339361f, -0.56349581f, - 1.46587682f, 4.12142849f, 0.78908098f, -0.24000889f, -1.15510166f, 0.42653239f, - -1.98345447f, 1.06918168f, 2.98073006f, -2.94872737f, -0.67443597f, -0.96227646f, - -1.94805872f, -0.96003568f, - -0.21484625f, 3.49263334f, -1.35283577f, 0.38428289f, -4.29686069f, -4.34778786f, - -0.49574745f, -0.08637778f, -0.50855160f, -1.12334609f, -1.44851387f, 3.36797357f, - -0.91776383f, -0.98647243f, 1.45408130f, 0.29062888f, 0.24470398f, -1.28129590f, - 0.47530234f, 2.19562674f, 0.62674099f, -2.56222868f, -1.42671025f, 1.51795268f, - -1.92045701f, 1.20271325f, 2.53190184f, -0.37211552f, 0.92569226f, -1.11019444f, - 1.15402830f, -1.98479640f, - - 1.06492281f, 0.32333452f, -0.52869648f, -1.25258100f, 0.75479198f, -1.04409528f, - -1.81722605f, 0.99018478f, 1.83352923f, 1.02711058f, 0.31064227f, 2.44383168f, - -1.80332434f, 1.57207584f, -0.41058558f, 0.20494992f, -0.78399467f, -0.35703743f, - -0.67568171f, -1.30091023f, -0.17390330f, 0.22340816f, -0.44613233f, 1.23870432f, - -0.16092014f, -1.22258115f, 0.60575533f, -0.17969827f, 1.87851882f, 1.13991237f, - -0.81591004f, -1.68899822f, - -0.49658760f, 1.62168694f, -1.71412969f, -1.26646388f, -1.37257946f, 1.53828073f, - -0.35583261f, 0.03810386f, 0.43514529f, 0.97525519f, -2.22109556f, 1.17547810f, - -0.28825673f, 0.91509271f, -1.19243717f, 1.09280133f, -0.51078367f, 0.63577116f, - -0.62186599f, -2.80234575f, -1.58007598f, 1.06965756f, -0.89327252f, -0.84735525f, - -0.46283475f, 0.77867299f, -0.07434830f, 1.44711912f, 1.07089376f, 0.78913736f, - 0.59053934f, -0.32160193f, - - -1.72543812f, 0.63848293f, 0.87042624f, 0.39726460f, 0.62647510f, 1.73326159f, - -0.55110240f, -1.26900804f, 1.94843686f, -1.73077893f, 2.53475809f, 2.79892564f, - -1.91852188f, 0.99826050f, -3.04680610f, 1.38900220f, -1.17920876f, -2.07508063f, - -0.34274688f, -0.24780962f, 1.75715542f, 1.27657294f, -1.15560341f, -2.69310951f, - 0.93523502f, 0.58213681f, -2.57009196f, 2.56376076f, 0.06911665f, 1.73962176f, - 0.43307841f, -1.18240118f, - 0.51273453f, 1.12628150f, 1.96404183f, 0.26380035f, 3.41526699f, 1.08249199f, - -1.70347631f, 0.42854923f, -1.98269284f, 1.97382474f, -0.12164606f, -1.41219604f, - 0.01819625f, 0.73082930f, -2.60845804f, 1.47046185f, 0.26324001f, 1.54259276f, - -1.18744254f, -1.77539694f, 1.76547086f, -1.57072937f, -1.83995926f, -0.05529352f, - 1.83544660f, 0.69575423f, -0.03345531f, -1.69629955f, 0.04713173f, 1.39800107f, - 0.24362923f, 0.12432972f, - - 1.52338290f, 1.02856898f, 0.40946901f, 1.57649779f, 1.22447217f, 0.85961932f, - 0.30765539f, -2.66427660f, -1.55998194f, -0.31161505f, -1.63090813f, -1.62476087f, - 1.28381526f, -0.77024549f, 1.46711981f, -0.71657622f, -0.51606011f, 0.87953311f, - 0.26169056f, 1.03068113f, 0.41064253f, -1.56344402f, -1.53443003f, -0.03009570f, - -0.02123317f, -1.74375248f, 1.60988081f, 1.74488568f, 0.59155780f, -0.62032932f, - 0.03105794f, 4.54175377f, - -2.92895460f, -0.46070760f, 0.20383459f, 1.93618548f, -1.08026588f, 1.08253515f, - -0.48318014f, -2.34334373f, -2.69622159f, 0.00661799f, -1.10738027f, 0.03181311f, - 0.32897863f, 1.89451993f, -0.01152946f, 0.17766151f, 2.46450090f, -0.64409554f, - 2.56058550f, 1.29339278f, 2.72114944f, 0.87801707f, -1.58970404f, 2.88365316f, - 0.46464550f, -1.71912467f, -1.90960062f, -3.13572145f, 0.19871379f, -0.28741950f, - -0.38167781f, -2.30705547f, - - -2.08403850f, 0.22352570f, -0.17924348f, 0.65815634f, -0.59089363f, -1.66189861f, - 0.75618476f, 0.03879535f, 1.50222909f, -0.29873836f, -1.76075482f, -2.97067928f, - 0.28112072f, 0.72105575f, 0.06761266f, -1.61681306f, -0.80693424f, 2.40102959f, - -2.91352296f, -1.21352315f, -1.62430143f, -1.60909438f, 0.53140688f, -0.28235722f, - 0.63271880f, 1.33791542f, -1.37593675f, -1.60502291f, 1.27470064f, -0.96280038f, - 0.79614848f, 0.31894624f, - 0.64399612f, 0.32866889f, -3.49091625f, -0.02294427f, 1.60225844f, 1.83659923f, - 1.55193460f, -0.06712314f, 0.76592684f, 0.83479869f, 0.49627584f, 0.75736403f, - 0.75179487f, -0.32156041f, 1.36537170f, 0.57024354f, 0.36152276f, 0.93625057f, - -1.69728792f, -0.28833422f, 0.43304375f, 1.62640548f, -0.00187188f, 0.80429250f, - -0.77993584f, 1.37333393f, -1.16019452f, -0.91983509f, 0.20466281f, 1.09339333f, - -0.99191529f, 3.42685890f}; - } - - { - // Do not test fp32 - data.fp32_output_data = {}; - } - - { - data.fp16_output_data = { - -0.18665725f, 1.53655565f, -1.16219902f, -0.53553712f, -1.76899862f, -0.67172408f, - -0.03719823f, -0.73519617f, -0.08289805f, -0.22439885f, -1.15095568f, 1.52012229f, - -0.11608444f, 0.30267856f, 0.17237782f, 0.12366229f, -0.15282108f, 0.15652999f, - -0.05062571f, -0.60356319f, -0.67014134f, -0.12373877f, -0.62331146f, -0.00974876f, - -1.22021353f, 0.52888882f, 0.52984023f, 0.60431194f, 0.64458221f, 0.19681633f, - 0.87637067f, -0.49721599f, - - -0.21368809f, 3.48006248f, -1.34989023f, 0.38081154f, -4.28221798f, -4.33166409f, - -0.49185523f, -0.09290559f, -0.50751436f, -1.12148952f, -1.44325578f, 3.35744357f, - -0.91217732f, -0.98030341f, 1.45034039f, 0.28651160f, 0.24333692f, -1.27377033f, - 0.47380278f, 2.18498206f, 0.62146491f, -2.55067039f, -1.42080343f, 1.51099622f, - -1.91845036f, 1.19768524f, 2.52122355f, -0.36864227f, 0.92257524f, -1.10384953f, - 1.15318692f, -1.97599709f, - - 0.25325853f, 0.99478984f, 1.75511229f, 0.38680723f, 3.04894686f, 1.09290445f, - -1.56589723f, 0.21126932f, -1.99892235f, 1.80875492f, -0.18795207f, -1.27262163f, - 0.05191655f, 0.80464834f, -2.35645056f, 1.35988820f, 0.43171301f, 1.36821294f, - -0.90993541f, -1.52189243f, 1.81963241f, -1.34069264f, -1.79558825f, 0.17969209f, - 1.69527614f, 0.52177316f, -0.19144230f, -1.79486036f, 0.06081408f, 1.26584184f, - 0.17910211f, -0.01467115f, - - 0.15915775f, 0.23589413f, -2.89726520f, 0.24662971f, 1.27141249f, 1.72167253f, - 1.22059381f, -0.36594886f, 0.25064397f, 0.74270636f, 0.26896626f, 0.62173104f, - 0.68196213f, -0.00399938f, 1.11046481f, 0.53283978f, 0.64384484f, 0.73332942f, - -1.11337614f, -0.10050645f, 0.76519096f, 1.46986043f, -0.24821334f, 1.07021677f, - -0.56646812f, 0.94391233f, -1.24186087f, -1.23258281f, 0.20112629f, 0.91218621f, - -0.88806105f, 2.59514260f}; - } + LoadTensor("CrossAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedKV.query_data", data.query_data); + LoadTensor("CrossAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedKV.key_data", data.key_data); + LoadTensor("CrossAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedKV.value_data", data.value_data); + data.bias_data = {}; + LoadTensor("CrossAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedKV.kv_data", data.kv_data); + // Do not test fp32 + data.fp32_output_data = {}; + LoadTensor("CrossAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedKV.fp16_output_data", data.fp16_output_data); } void GetSelfAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedQKV(AttentionTestData& data) { @@ -2531,170 +188,15 @@ void GetSelfAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedQKV(AttentionTes AttentionKernelType::AttentionKernel_Unfused, AttentionKernelType::AttentionKernel_TrtFusedCrossAttention}; - { - data.query_data = { - -0.35420692f, 1.31206024f, -2.80201197f, 2.42258096f, -0.86031514f, -1.44535458f, -0.10832444f, -2.00132895f, - 1.62475216f, 0.10978927f, 1.84596729f, 0.48908550f, 1.44369888f, 0.87542874f, -1.16434252f, 0.52133209f, - 1.54848897f, -2.21174526f, -0.28574878f, 0.70815033f, 1.18327498f, 3.14097571f, -0.25795099f, 1.89341247f, - -0.11603792f, 0.38110194f, 0.40873206f, -1.14149106f, 0.79770875f, -0.98069525f, -1.53588808f, 0.50821728f, - -2.21641898f, 0.55090773f, 0.80901796f, -0.56089771f, 0.03574468f, -1.27940118f, -0.02213959f, -0.80698186f, - -0.82701880f, 1.72937381f, 1.56083691f, -0.30311784f, -0.25183848f, 0.24280515f, 0.29569417f, -0.31162494f, - 0.48996922f, 0.22795241f, 2.07125854f, 1.45823467f, 3.03750706f, 1.53734803f, 0.48668906f, -1.63703632f, - -0.14114749f, 1.85963213f, 1.20729232f, -0.28972962f, -0.80783498f, -1.16619551f, -0.60004634f, 0.02498829f, - - 3.50846076f, -2.50027657f, -2.59866142f, 1.58495271f, 2.21110034f, -2.74877763f, -1.00267041f, 0.62646407f, - 2.50227380f, -0.27291518f, -0.33037442f, 0.75840306f, 0.45437157f, -0.79876304f, 0.83509272f, 2.53716302f, - 0.01348384f, -2.16307616f, 2.01661849f, 2.10746121f, -1.70485222f, 1.35548759f, 1.39401650f, -0.99451691f, - -4.13484812f, 0.56262714f, -0.92725742f, -0.16389316f, -1.31260049f, 2.32357836f, -3.05251694f, -1.12570131f, - 1.87849474f, -1.80381167f, 0.52235699f, 2.38887334f, -1.58878529f, 0.69571090f, 1.65044296f, -0.27024290f, - 3.59580970f, -1.97888982f, 1.17034674f, 0.26716161f, -1.16770899f, 0.74609619f, 0.78886843f, 0.15717520f, - -0.93303132f, -0.84753871f, -4.32799959f, -1.94716609f, -1.16980326f, 1.62631667f, 2.41053247f, 3.78186774f, - 0.26432252f, -0.40396988f, 2.04414082f, 0.65150046f, 0.47777444f, -2.57569051f, 0.99004912f, 2.47947693f}; - } - { - data.key_data = { - -0.04407793f, 1.29459429f, 1.05810797f, 1.92067695f, -0.65047157f, 0.99029726f, -1.69796586f, 1.15320420f, - -1.66444266f, 1.78305888f, 1.20582056f, 1.69975281f, 0.34572244f, -0.60833001f, 2.59864879f, -1.05330181f, - -1.16554165f, -0.03781542f, -1.13475525f, 0.71595150f, -0.91169560f, 1.26686060f, 1.60492957f, -0.53510487f, - -1.40180850f, 1.83253956f, 2.70238972f, -1.48750985f, 0.47105616f, -0.79477602f, -1.93152475f, 1.04042351f, - 1.21863425f, 1.20610654f, 0.69031805f, 2.60092020f, 1.43040228f, 0.60616529f, 0.47948456f, -1.15139377f, - 0.15641990f, -0.46933329f, 0.64774191f, 0.35970241f, -1.00424135f, 0.01247875f, 1.00281739f, -1.10514688f, - 0.30922988f, -0.82255656f, -1.23242986f, 0.90557313f, -0.38946581f, -0.21124774f, -2.37903309f, -1.42169905f, - -0.05935127f, 0.47488672f, -0.37083727f, 1.31585515f, -0.21577421f, -0.97746384f, -0.13380399f, 1.77390409f, - - -2.65206385f, 1.26134932f, -1.01682174f, 0.64366758f, 0.95474619f, 2.06720352f, 0.51750720f, -0.07041813f, - 0.53124994f, -3.26612782f, 1.37013340f, 0.13939659f, -0.57418114f, 0.80680281f, -3.40751696f, -0.15847699f, - 0.97837782f, -0.09121911f, 1.18452120f, 0.52711177f, -1.86135840f, -0.11258313f, 0.85863215f, -2.60261130f, - 0.72695309f, 1.44092011f, 0.43785980f, -1.63415265f, -1.05772328f, 0.12997569f, 0.07356137f, -0.62493324f, - -0.43267637f, -1.80009198f, 0.92961007f, 2.05127883f, -2.85521173f, -0.21652693f, -0.89153922f, 0.15524670f, - -2.16850328f, 1.46751809f, 2.51663852f, -0.49499366f, 0.19886012f, 0.77093124f, -1.14819765f, 1.47111738f, - 2.42824388f, 1.56369960f, 1.69934130f, -0.42460468f, -2.25951004f, -1.18074155f, 3.51091242f, -0.30183151f, - -1.83517075f, -0.56233191f, 2.35561657f, -3.63751698f, -3.20001125f, -1.66120780f, 3.23455381f, -1.86251283f}; - } - - { - data.value_data = { - -0.89167893f, 0.02633595f, -0.84866279f, 1.43489110f, -2.91941142f, -0.20650116f, 1.85965109f, 0.45669034f, - 0.07678832f, 0.04492294f, 0.67326981f, 0.97103029f, 1.53470886f, -1.10242307f, 0.86584085f, -0.34770033f, - -1.24311507f, -1.80293822f, -1.01317739f, -0.71518499f, 0.77814674f, -0.59236068f, -2.00310278f, 3.13277125f, - -1.20754123f, 2.01506066f, 0.82650810f, 2.06084490f, -0.46267471f, 1.56365979f, 4.31514502f, -1.03099275f, - -1.85462761f, 2.10100341f, 1.79686451f, 0.23871201f, 1.23598254f, -0.31959364f, 0.50101948f, -0.09527110f, - -1.02331078f, 0.16319990f, -0.54766160f, 0.41597658f, -0.52141404f, 1.71663237f, -0.00776333f, -0.68160462f, - 1.76272714f, -0.04465733f, 0.28247434f, 1.69360149f, 0.14144623f, 0.75038731f, -1.33337545f, 2.23457718f, - -0.07649468f, 1.97064841f, -1.85374629f, -1.59334683f, 0.32698441f, -0.16024286f, 2.02828407f, -0.96440399f, - - -2.11639142f, -1.50897706f, 1.63863683f, 2.32786226f, 1.32746494f, 0.75751448f, 0.57184196f, 0.86446053f, - -0.62406683f, 0.78861046f, 0.01044065f, 3.51772785f, -1.33701336f, 0.27977663f, -0.35464612f, 0.74973166f, - 0.03352100f, 1.55007398f, 0.69849420f, -2.47725606f, -1.89363778f, -1.79874682f, -0.56210291f, -1.75556040f, - 1.07565808f, -0.18023658f, 1.63777173f, 1.28198206f, 2.19431949f, 0.67998970f, -0.52531999f, -1.89906740f, - 1.35158050f, -2.21481490f, -0.11812399f, -1.74263430f, -0.57895988f, -0.04181165f, 0.78120053f, -2.22377038f, - -0.53264999f, -2.03721714f, 0.21023634f, 2.55751204f, -1.04522800f, 0.85386503f, 0.41594937f, -2.98181081f, - 1.14034331f, -1.41539204f, 0.13379651f, 3.47018123f, 1.53924727f, 1.50004411f, 2.87318921f, 1.62624204f, - 0.64942807f, -4.54302311f, -1.50294220f, -1.75212634f, 0.27900690f, -3.05124855f, 3.30960631f, -0.07991691f}; - } - - { - data.bias_data = { - // 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, - // 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, - // 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, - // 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, - // 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f - }; - } - - { - data.qkv_data = { - -0.35420692f, 1.31206024f, -2.80201197f, 2.42258096f, -0.86031514f, -1.44535458f, -0.10832444f, -2.00132895f, - 1.62475216f, 0.10978927f, 1.84596729f, 0.48908550f, 1.44369888f, 0.87542874f, -1.16434252f, 0.52133209f, - 1.54848897f, -2.21174526f, -0.28574878f, 0.70815033f, 1.18327498f, 3.14097571f, -0.25795099f, 1.89341247f, - -0.11603792f, 0.38110194f, 0.40873206f, -1.14149106f, 0.79770875f, -0.98069525f, -1.53588808f, 0.50821728f, - -0.04407793f, 1.29459429f, 1.05810797f, 1.92067695f, -0.65047157f, 0.99029726f, -1.69796586f, 1.15320420f, - -1.66444266f, 1.78305888f, 1.20582056f, 1.69975281f, 0.34572244f, -0.60833001f, 2.59864879f, -1.05330181f, - -1.16554165f, -0.03781542f, -1.13475525f, 0.71595150f, -0.91169560f, 1.26686060f, 1.60492957f, -0.53510487f, - -1.40180850f, 1.83253956f, 2.70238972f, -1.48750985f, 0.47105616f, -0.79477602f, -1.93152475f, 1.04042351f, - -0.89167893f, 0.02633595f, -0.84866279f, 1.43489110f, -2.91941142f, -0.20650116f, 1.85965109f, 0.45669034f, - 0.07678832f, 0.04492294f, 0.67326981f, 0.97103029f, 1.53470886f, -1.10242307f, 0.86584085f, -0.34770033f, - -1.24311507f, -1.80293822f, -1.01317739f, -0.71518499f, 0.77814674f, -0.59236068f, -2.00310278f, 3.13277125f, - -1.20754123f, 2.01506066f, 0.82650810f, 2.06084490f, -0.46267471f, 1.56365979f, 4.31514502f, -1.03099275f, - - -2.21641898f, 0.55090773f, 0.80901796f, -0.56089771f, 0.03574468f, -1.27940118f, -0.02213959f, -0.80698186f, - -0.82701880f, 1.72937381f, 1.56083691f, -0.30311784f, -0.25183848f, 0.24280515f, 0.29569417f, -0.31162494f, - 0.48996922f, 0.22795241f, 2.07125854f, 1.45823467f, 3.03750706f, 1.53734803f, 0.48668906f, -1.63703632f, - -0.14114749f, 1.85963213f, 1.20729232f, -0.28972962f, -0.80783498f, -1.16619551f, -0.60004634f, 0.02498829f, - 1.21863425f, 1.20610654f, 0.69031805f, 2.60092020f, 1.43040228f, 0.60616529f, 0.47948456f, -1.15139377f, - 0.15641990f, -0.46933329f, 0.64774191f, 0.35970241f, -1.00424135f, 0.01247875f, 1.00281739f, -1.10514688f, - 0.30922988f, -0.82255656f, -1.23242986f, 0.90557313f, -0.38946581f, -0.21124774f, -2.37903309f, -1.42169905f, - -0.05935127f, 0.47488672f, -0.37083727f, 1.31585515f, -0.21577421f, -0.97746384f, -0.13380399f, 1.77390409f, - -1.85462761f, 2.10100341f, 1.79686451f, 0.23871201f, 1.23598254f, -0.31959364f, 0.50101948f, -0.09527110f, - -1.02331078f, 0.16319990f, -0.54766160f, 0.41597658f, -0.52141404f, 1.71663237f, -0.00776333f, -0.68160462f, - 1.76272714f, -0.04465733f, 0.28247434f, 1.69360149f, 0.14144623f, 0.75038731f, -1.33337545f, 2.23457718f, - -0.07649468f, 1.97064841f, -1.85374629f, -1.59334683f, 0.32698441f, -0.16024286f, 2.02828407f, -0.96440399f, - - 3.50846076f, -2.50027657f, -2.59866142f, 1.58495271f, 2.21110034f, -2.74877763f, -1.00267041f, 0.62646407f, - 2.50227380f, -0.27291518f, -0.33037442f, 0.75840306f, 0.45437157f, -0.79876304f, 0.83509272f, 2.53716302f, - 0.01348384f, -2.16307616f, 2.01661849f, 2.10746121f, -1.70485222f, 1.35548759f, 1.39401650f, -0.99451691f, - -4.13484812f, 0.56262714f, -0.92725742f, -0.16389316f, -1.31260049f, 2.32357836f, -3.05251694f, -1.12570131f, - -2.65206385f, 1.26134932f, -1.01682174f, 0.64366758f, 0.95474619f, 2.06720352f, 0.51750720f, -0.07041813f, - 0.53124994f, -3.26612782f, 1.37013340f, 0.13939659f, -0.57418114f, 0.80680281f, -3.40751696f, -0.15847699f, - 0.97837782f, -0.09121911f, 1.18452120f, 0.52711177f, -1.86135840f, -0.11258313f, 0.85863215f, -2.60261130f, - 0.72695309f, 1.44092011f, 0.43785980f, -1.63415265f, -1.05772328f, 0.12997569f, 0.07356137f, -0.62493324f, - -2.11639142f, -1.50897706f, 1.63863683f, 2.32786226f, 1.32746494f, 0.75751448f, 0.57184196f, 0.86446053f, - -0.62406683f, 0.78861046f, 0.01044065f, 3.51772785f, -1.33701336f, 0.27977663f, -0.35464612f, 0.74973166f, - 0.03352100f, 1.55007398f, 0.69849420f, -2.47725606f, -1.89363778f, -1.79874682f, -0.56210291f, -1.75556040f, - 1.07565808f, -0.18023658f, 1.63777173f, 1.28198206f, 2.19431949f, 0.67998970f, -0.52531999f, -1.89906740f, - - 1.87849474f, -1.80381167f, 0.52235699f, 2.38887334f, -1.58878529f, 0.69571090f, 1.65044296f, -0.27024290f, - 3.59580970f, -1.97888982f, 1.17034674f, 0.26716161f, -1.16770899f, 0.74609619f, 0.78886843f, 0.15717520f, - -0.93303132f, -0.84753871f, -4.32799959f, -1.94716609f, -1.16980326f, 1.62631667f, 2.41053247f, 3.78186774f, - 0.26432252f, -0.40396988f, 2.04414082f, 0.65150046f, 0.47777444f, -2.57569051f, 0.99004912f, 2.47947693f, - -0.43267637f, -1.80009198f, 0.92961007f, 2.05127883f, -2.85521173f, -0.21652693f, -0.89153922f, 0.15524670f, - -2.16850328f, 1.46751809f, 2.51663852f, -0.49499366f, 0.19886012f, 0.77093124f, -1.14819765f, 1.47111738f, - 2.42824388f, 1.56369960f, 1.69934130f, -0.42460468f, -2.25951004f, -1.18074155f, 3.51091242f, -0.30183151f, - -1.83517075f, -0.56233191f, 2.35561657f, -3.63751698f, -3.20001125f, -1.66120780f, 3.23455381f, -1.86251283f, - 1.35158050f, -2.21481490f, -0.11812399f, -1.74263430f, -0.57895988f, -0.04181165f, 0.78120053f, -2.22377038f, - -0.53264999f, -2.03721714f, 0.21023634f, 2.55751204f, -1.04522800f, 0.85386503f, 0.41594937f, -2.98181081f, - 1.14034331f, -1.41539204f, 0.13379651f, 3.47018123f, 1.53924727f, 1.50004411f, 2.87318921f, 1.62624204f, - 0.64942807f, -4.54302311f, -1.50294220f, -1.75212634f, 0.27900690f, -3.05124855f, 3.30960631f, -0.07991691f}; - } - - { - // Do not test fp32 - data.fp32_output_data = {}; - } - - { - data.fp16_output_data = { - -1.30247164f, 0.91138631f, 0.27991560f, 0.92460269f, -1.14672589f, -0.25474626f, - 1.28006065f, 0.22122431f, -0.39251250f, 0.09537974f, 0.15242209f, 0.73424512f, - 0.65756959f, 0.10018224f, 0.49316248f, -0.49014348f, 0.03917319f, -1.05285788f, - -0.46045411f, 0.31240013f, 0.50653118f, -0.01954618f, -1.71739793f, 2.74960279f, - -0.72503829f, 1.99611449f, -0.31688485f, 0.50197154f, -0.12580720f, 0.82824522f, - 3.33957314f, -1.00258613f, - - -0.95444643f, 0.16156809f, -0.67622054f, 1.35692120f, -2.64855242f, -0.21387282f, - 1.77109206f, 0.42071211f, 0.00508105f, 0.05263254f, 0.59368640f, 0.93485051f, - 1.40068567f, -0.91866994f, 0.80889714f, -0.36946508f, -1.04718661f, -1.68832910f, - -0.92872351f, -0.55817413f, 0.73664504f, -0.50483698f, -1.95944834f, 3.07422471f, - -1.13381684f, 2.01216578f, 0.65180230f, 1.82265544f, -0.41120273f, 1.45129156f, - 4.16608191f, -1.02665234f, - - 0.21158576f, -1.98279130f, 0.45935997f, -0.40457720f, 0.04772174f, 0.22094353f, - 0.71238005f, -1.20860445f, -0.56270063f, -1.10830855f, 0.14455934f, 2.87315512f, - -1.14114404f, 0.66515017f, 0.16263856f, -1.75517499f, 0.77650774f, -0.44058144f, - 0.31942442f, 1.51513433f, 0.41078627f, 0.41566271f, 1.74393702f, 0.51457298f, - 0.78953874f, -3.10888410f, -0.47052401f, -0.75475156f, 0.90861011f, -1.82471263f, - 2.04898596f, -0.67790967f, - - 1.17194295f, -2.17825341f, -0.02712549f, -1.53178656f, -0.48020893f, -0.00040733f, - 0.77035600f, -2.06380320f, -0.53738528f, -1.89084208f, 0.19988713f, 2.60725045f, - -1.06034219f, 0.82412785f, 0.37603328f, -2.78852081f, 1.08301103f, -1.26178384f, - 0.16304730f, 3.16210985f, 1.36142719f, 1.32916999f, 2.69524455f, 1.45106804f, - 0.67150640f, -4.31703520f, -1.34025633f, -1.59496248f, 0.37821823f, -2.85797405f, - 3.11096096f, -0.17414713f}; - } + LoadTensor("SelfAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedQKV.query_data", data.query_data); + LoadTensor("SelfAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedQKV.key_data", data.key_data); + LoadTensor("SelfAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedQKV.value_data", data.value_data); + data.bias_data = {}; + LoadTensor("SelfAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedQKV.qkv_data", data.qkv_data); + // Do not test fp32 + data.fp32_output_data = {}; + LoadTensor("SelfAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedQKV.fp16_output_data", data.fp16_output_data); } -#endif void GetCrossAttentionData_HeadSize16_8(AttentionTestData& data) { data.hidden_size = 48; @@ -2708,119 +210,19 @@ void GetCrossAttentionData_HeadSize16_8(AttentionTestData& data) { AttentionKernelType::AttentionKernel_TrtFusedCrossAttention, AttentionKernelType::AttentionKernel_TrtFusedAttention}; - { - data.query_data = { - 2.88765883f, 1.27536213f, -0.57580215f, 2.73696542f, 2.19016314f, 0.42629790f, 1.55081677f, -2.01307678f, - -0.80203497f, -1.23206115f, 1.78565156f, -2.09875321f, -2.22730732f, -0.98120236f, -0.25774139f, 0.75868356f, - -2.87585187f, -0.41810805f, -2.11528730f, 0.50642025f, -0.29446256f, -3.69675803f, -2.73721838f, -1.51089072f, - 0.74300194f, 0.27352047f, -0.88251829f, 2.82622814f, 0.73837662f, -2.14588642f, 0.37608737f, -0.06190044f, - 1.83028936f, -0.02953561f, 1.94609165f, 1.03678417f, -3.07869005f, 1.13037205f, 2.14215207f, 1.29724145f, - 0.06229818f, -2.93803453f, -1.12074065f, -1.75312924f, -2.51804519f, -0.20714152f, 0.94910270f, 0.31394321f, - - -1.97659302f, -2.22348428f, 2.25573063f, -2.24459195f, -2.28073978f, -0.52412349f, -0.57297325f, 3.29259396f, - 1.35617173f, -0.83082151f, 0.03767079f, 1.82568312f, 0.88193995f, 1.15579486f, 1.87845564f, -0.15923920f, - 2.37435389f, 1.49093378f, 1.95134592f, -1.67609048f, -0.45959851f, 1.63960719f, 3.44909906f, -0.23531833f, - -0.57074630f, 1.38279045f, 0.58870834f, 0.85297751f, -1.44973445f, 1.56243801f, -0.67229253f, -0.16198707f, - 2.24443579f, 0.01009618f, -2.02270651f, -1.48122561f, -0.71337879f, -1.41594160f, 0.67262292f, -1.45187402f, - 2.45791745f, 0.94860327f, 1.22767174f, 1.16789973f, -0.69281816f, 0.90847492f, 1.16295385f, -0.84179711f}; - } - { - data.key_data = { - 1.14242256f, 1.08148384f, -0.00962424f, -1.62719429f, 0.86478198f, 0.16862091f, 1.01692820f, -1.15278327f, - -1.13622630f, 1.78038371f, 0.58222097f, 0.39166588f, 1.75063372f, -1.20408881f, 0.75154918f, 0.58156419f, - -0.98975772f, -0.82555556f, -0.72656512f, -2.42399549f, 2.19217968f, 2.18518472f, -1.72216129f, 1.35098433f, - -0.34989786f, -0.69064844f, -0.98365444f, 3.10148478f, 0.64813483f, 1.78129303f, -0.47006512f, 2.53122735f, - -4.06511545f, 0.22256386f, 2.46787810f, -1.64387906f, -0.72458595f, 0.03613299f, -2.20491385f, 1.25488305f, - -1.49934030f, 0.09558886f, 0.21092418f, -0.04370949f, -0.54754108f, 0.89117372f, -1.44286251f, -0.89374435f, - 0.09757380f, 0.04077591f, -0.81791472f, -0.19737752f, 1.13775492f, -1.51351953f, 0.59109330f, 2.86624002f, - -0.09282493f, -1.69204521f, 1.27087700f, 3.53944731f, 0.59776509f, -0.90838081f, -0.15813766f, -1.86199224f, - 0.18734205f, -0.76110429f, -0.02243887f, -0.94068182f, 1.32443166f, 0.03512055f, -0.13194422f, -1.50401211f, - 0.92001319f, 0.20918207f, -1.34839189f, 1.56431675f, -0.61030018f, 2.39562368f, -1.56722510f, -0.96874726f, - 0.36663681f, 1.67216635f, 1.97995794f, -1.43150198f, 1.61904466f, -0.26285610f, -0.63515049f, 3.34068251f, - 0.54150528f, 1.26057637f, -0.99386609f, 0.06303076f, -1.30578506f, 0.03304024f, -0.22100723f, -0.79328370f, - -0.48726845f, -1.41476154f, -1.45116997f, 0.53907454f, -2.14415288f, 1.14340270f, -0.21846619f, -2.72349358f, - 2.99664998f, -2.38684058f, 0.95269018f, 0.04208702f, -1.75080788f, 1.24652982f, -1.76879966f, 3.10814905f, - 2.48754454f, -0.62601894f, 1.41356945f, 0.10340121f, 1.09059846f, -0.78241473f, -0.61477584f, -0.19339988f, - -0.48253334f, -2.41782594f, 1.04690075f, 0.14725411f, -0.20820639f, -1.95920563f, 0.96303236f, -1.20068836f, - 1.01268184f, 4.29013920f, 0.77999580f, 1.46932411f, 0.87674600f, -1.25074506f, 2.45850706f, 0.09870356f, - -0.14051074f, 1.17763662f, -1.21477187f, 1.60379291f, -0.01956993f, 0.43266663f, -0.45684600f, -1.02696598f, - - -1.71051037f, -1.90946770f, -2.07985783f, 2.35042953f, 0.35059446f, -0.44228595f, 4.08558750f, -0.60121447f, - 0.78836018f, 0.35280651f, 0.23129070f, -0.21523762f, 0.12277550f, 0.12348226f, -1.62759030f, -2.78246498f, - 4.04853964f, 0.29263157f, -0.38621908f, -1.07599223f, -1.99170423f, 1.41409016f, 2.19121861f, -3.53451037f, - 3.63692737f, 0.68270516f, 2.51469731f, 2.57543731f, -2.39040112f, -3.97164130f, 1.28371549f, 1.64144099f, - 0.18788165f, 1.15558743f, 2.74443531f, 0.92457932f, -0.34628516f, 0.15525299f, 1.43510377f, 0.20861864f, - 2.88269520f, 0.64859426f, 1.78730142f, -2.25655675f, -1.83863652f, -2.58051491f, -4.23162079f, 1.49537027f, - -0.70385075f, 2.55361128f, 1.60707259f, 0.84735453f, -2.07756495f, -1.99240303f, -3.60991144f, 2.87136865f, - 2.31296396f, 2.30251813f, -1.05624914f, -2.43777156f, -0.27048296f, 2.39037871f, -2.04504776f, 1.65183067f, - -0.38970214f, 0.16808379f, -1.30286717f, 1.90201700f, -2.71696734f, -0.66445369f, 1.27085483f, -0.60816145f, - 1.81054437f, -1.55584621f, -2.19360781f, -4.52794456f, -0.90534067f, 0.94724411f, 2.40401077f, -2.94815230f, - 1.56385708f, -0.63737142f, -0.72946531f, -0.79579020f, -0.18071416f, 0.66005665f, -3.16687059f, -0.97323495f, - 0.49748731f, -3.54246902f, -2.14790606f, 0.09179869f, -0.56292027f, -2.96827269f, 1.74778676f, 0.12816763f, - -3.19650269f, 2.50638890f, 1.02038431f, 1.50519919f, 0.47196171f, -1.89026380f, -1.86559379f, 0.82210326f, - 0.10818237f, 1.45290673f, 1.62321615f, -0.61283481f, -1.42501950f, 2.10349464f, -1.65715265f, 0.30090189f, - -3.81919909f, -2.44903922f, -1.20557833f, -0.69951278f, -1.31475580f, -3.73842764f, 1.49299407f, -0.70933276f, - -1.49021530f, 0.71776378f, -1.23052382f, -2.13119912f, -1.20718014f, 2.30572701f, 1.78386402f, -1.57122159f, - -1.08014178f, -1.40319920f, -1.40852046f, 0.59488881f, -3.51004219f, 2.35288191f, -2.06260157f, -1.11531663f, - 2.51375723f, 0.25726259f, -0.99232292f, 1.47292709f, 2.81933832f, -0.39054599f, 0.18200648f, 1.54844952f}; - } - - { - data.value_data = { - 1.79297853f, 0.96909231f, 1.23087275f, -0.61933923f, -0.56477690f, 1.47813499f, 0.51474279f, -3.44743419f, - 0.95816678f, -0.20553169f, -0.76906109f, -4.60927439f, 0.40629998f, 0.91934747f, -1.09594405f, -1.45653892f, - -0.59282207f, 0.05621797f, -2.26634383f, -1.30799258f, 1.22072279f, -3.60811162f, 1.70111597f, 0.47336632f, - -1.82395399f, 0.73557752f, 2.32600021f, -0.22650969f, -0.48526058f, 1.40349376f, -0.33553454f, 0.45531431f, - 0.73859257f, 0.37798560f, 0.85344458f, -1.30447221f, 1.23349071f, -0.26439479f, 1.18636096f, -0.33328748f, - -0.50939041f, 0.53500950f, 1.33486223f, -1.54447496f, -2.88690519f, -0.06809106f, -0.00597921f, -1.07510388f, - 0.69456708f, 2.91441655f, -0.25431669f, -1.20305562f, 2.06701255f, -0.86700624f, -2.23615170f, 0.13303493f, - -2.97540593f, 0.08654684f, 1.40381706f, 3.54294443f, -2.07661867f, -1.33181918f, 2.24228764f, 1.79975545f, - 2.14695477f, 1.40222490f, -0.29813689f, 1.94485068f, 1.99623775f, 1.53450203f, 0.28755581f, -0.67934704f, - - -2.45574522f, -1.91599977f, 5.05240345f, 2.24617362f, 3.99182248f, 0.92924285f, -0.39660916f, -0.08696688f, - 0.24855530f, 0.71378094f, 0.92413902f, 1.73599064f, 1.03852975f, 2.44676781f, 0.35013664f, 0.98107171f, - 1.62946916f, 0.41239718f, -1.41385484f, 2.49293518f, 2.32976985f, 2.89612579f, 2.66875219f, 1.47379971f, - -1.13935280f, 0.38051969f, -2.38735437f, -2.80645251f, 0.18637873f, 2.13938355f, 2.92260599f, -0.38653925f, - 0.58366799f, -1.67636371f, -2.29396892f, -1.31527638f, 2.39795637f, 0.39815575f, -0.98530269f, -1.29227996f, - 0.14452982f, -0.38186538f, -1.71267688f, 0.18121701f, -2.26441002f, -0.94511753f, 0.27371156f, -2.44858527f, - -0.73659700f, 0.74325305f, -1.97666430f, -1.07301974f, 0.17534591f, -1.66584718f, 1.21820331f, 0.67675018f, - -1.08938253f, 1.78010321f, 0.39817584f, -0.02914053f, 1.13571596f, -0.44081455f, 1.70561552f, -2.12085509f, - -0.69322622f, -1.87331009f, -2.15000772f, 2.08436966f, 1.70494926f, -3.69169927f, -1.22119129f, -1.60190558f}; - } - - { - data.bias_data = { - -0.38124341f, 0.02696526f, -0.11914945f, -0.43795273f, -0.34948170f, -0.19608477f, 0.19725692f, 0.39987487f, - 0.04772711f, -0.03419551f, -0.30606642f, 0.42656231f, -0.23178342f, -0.13692456f, -0.04889601f, 0.48739988f, - -0.25891554f, 0.13431972f, 0.22861153f, 0.06360734f, 0.48096961f, -0.47906545f, 0.43613154f, -0.23511401f, - -0.10595283f, -0.42839217f, 0.28931111f, -0.13180739f, -0.45826656f, 0.23286396f, -0.43407962f, 0.40754890f, - 0.23778325f, 0.34850210f, -0.01385659f, 0.32141626f, -0.27738628f, 0.27683002f, 0.31886810f, -0.24781504f, - -0.25476855f, -0.46742713f, -0.12478521f, 0.39731556f, -0.12087554f, 0.40822440f, 0.13202906f, -0.23747686f, - 0.27079183f, 0.42074734f, -0.40314156f, -0.43726659f, 0.27376485f, -0.38174152f, -0.43700469f, 0.38040614f, - -0.40546918f, 0.06927037f, 0.16979086f, 0.41458064f, 0.07120579f, -0.08055863f, 0.12095112f, -0.27988660f, - 0.06004709f, -0.05600315f, -0.25510073f, 0.41887105f, -0.19016314f, 0.47241372f, 0.12890404f, -0.24272856f, - 0.21106839f, -0.40523255f, 0.10336459f, -0.11084765f, 0.42408967f, -0.15285304f, -0.28945464f, -0.25714916f, - 0.40978593f, -0.09138483f, -0.02013114f, -0.39042589f, -0.19557095f, 0.07540411f, 0.33955890f, 0.41873980f, - -0.27744853f, -0.33097768f, -0.44587523f, -0.01648277f, 0.34952271f, -0.48838940f, -0.17273578f, 0.37286615f, - -0.10567203f, 0.26791072f, -0.08976898f, 0.31341976f, 0.06027532f, 0.14307594f, 0.31587386f, 0.16180152f, - 0.34785229f, 0.00531715f, -0.35168743f, -0.11641458f, 0.39196932f, 0.44535065f, 0.43545735f, 0.15593112f, - 0.06171834f, -0.42181283f, -0.41170910f, 0.40969193f, -0.01510030f, 0.07973170f, -0.18156880f, 0.21522856f}; - } - - { - data.fp32_output_data = { - 0.70553654f, 2.84393549f, -0.06753168f, -0.78168947f, 1.67733526f, -0.32306066f, -1.46519339f, -0.24197246f, - 0.68103230f, 0.09225838f, -0.12426007f, -2.19415975f, 0.82274425f, 0.54800904f, 0.77917045f, -0.37480056f, - 1.41798937f, 0.70201361f, -0.38768357f, 1.33144617f, 0.71884990f, 0.98060107f, 0.09563713f, -0.51187015f, - - -1.23079133f, 0.65636921f, -2.42403007f, -2.38468814f, 0.26282290f, 2.08802962f, 3.13919282f, -0.17057800f, - 0.59563273f, 0.71862715f, 0.57042938f, 1.61676264f, 1.43126500f, 2.88902473f, 0.78586847f, 1.13364232f, - -0.24963731f, -1.69403267f, -2.38265419f, 1.86863625f, 0.37573546f, -2.40374231f, -0.73219091f, -1.54168916f}; - } + LoadTensor("CrossAttentionData_HeadSize16_8.query_data", data.query_data); + LoadTensor("CrossAttentionData_HeadSize16_8.key_data", data.key_data); + LoadTensor("CrossAttentionData_HeadSize16_8.value_data", data.value_data); + LoadTensor("CrossAttentionData_HeadSize16_8.bias_data", data.bias_data); + LoadTensor("CrossAttentionData_HeadSize16_8.fp32_output_data", data.fp32_output_data); + data.fp16_output_data = data.fp32_output_data; +} - { - data.fp16_output_data = data.fp32_output_data; - } +void GetCrossAttentionData_HeadSize16_8_NoBias(AttentionTestData& data) { + GetCrossAttentionData_HeadSize16_8(data); + data.bias_data.clear(); + LoadTensor("CrossAttentionData_HeadSize16_8_NoBias.fp32_output_data", data.fp32_output_data); + data.fp16_output_data = data.fp32_output_data; } void GetCrossAttentionData_HeadSize16(AttentionTestData& data) { @@ -2831,81 +233,20 @@ void GetCrossAttentionData_HeadSize16(AttentionTestData& data) { data.sequence_length = 2; data.kv_sequence_length = 3; data.mask_type = AttentionMaskType::MASK_NONE; - { - data.query_data = { - 2.88765883f, 1.27536213f, -0.57580215f, 2.73696542f, 2.19016314f, 0.42629790f, 1.55081677f, -2.01307678f, - -0.80203497f, -1.23206115f, 1.78565156f, -2.09875321f, -2.22730732f, -0.98120236f, -0.25774139f, 0.75868356f, - -2.87585187f, -0.41810805f, -2.11528730f, 0.50642025f, -0.29446256f, -3.69675803f, -2.73721838f, -1.51089072f, - 0.74300194f, 0.27352047f, -0.88251829f, 2.82622814f, 0.73837662f, -2.14588642f, 0.37608737f, -0.06190044f, - -1.97659302f, -2.22348428f, 2.25573063f, -2.24459195f, -2.28073978f, -0.52412349f, -0.57297325f, 3.29259396f, - 1.35617173f, -0.83082151f, 0.03767079f, 1.82568312f, 0.88193995f, 1.15579486f, 1.87845564f, -0.15923920f, - 2.37435389f, 1.49093378f, 1.95134592f, -1.67609048f, -0.45959851f, 1.63960719f, 3.44909906f, -0.23531833f, - -0.57074630f, 1.38279045f, 0.58870834f, 0.85297751f, -1.44973445f, 1.56243801f, -0.67229253f, -0.16198707f}; - } - { - data.key_data = { - 1.14242256f, 1.08148384f, -0.00962424f, -1.62719429f, 0.86478198f, 0.16862091f, 1.01692820f, -1.15278327f, - -1.13622630f, 1.78038371f, 0.58222097f, 0.39166588f, 1.75063372f, -1.20408881f, 0.75154918f, 0.58156419f, - -0.98975772f, -0.82555556f, -0.72656512f, -2.42399549f, 2.19217968f, 2.18518472f, -1.72216129f, 1.35098433f, - -0.34989786f, -0.69064844f, -0.98365444f, 3.10148478f, 0.64813483f, 1.78129303f, -0.47006512f, 2.53122735f, - 0.09757380f, 0.04077591f, -0.81791472f, -0.19737752f, 1.13775492f, -1.51351953f, 0.59109330f, 2.86624002f, - -0.09282493f, -1.69204521f, 1.27087700f, 3.53944731f, 0.59776509f, -0.90838081f, -0.15813766f, -1.86199224f, - 0.18734205f, -0.76110429f, -0.02243887f, -0.94068182f, 1.32443166f, 0.03512055f, -0.13194422f, -1.50401211f, - 0.92001319f, 0.20918207f, -1.34839189f, 1.56431675f, -0.61030018f, 2.39562368f, -1.56722510f, -0.96874726f, - -0.48726845f, -1.41476154f, -1.45116997f, 0.53907454f, -2.14415288f, 1.14340270f, -0.21846619f, -2.72349358f, - 2.99664998f, -2.38684058f, 0.95269018f, 0.04208702f, -1.75080788f, 1.24652982f, -1.76879966f, 3.10814905f, - 2.48754454f, -0.62601894f, 1.41356945f, 0.10340121f, 1.09059846f, -0.78241473f, -0.61477584f, -0.19339988f, - -0.48253334f, -2.41782594f, 1.04690075f, 0.14725411f, -0.20820639f, -1.95920563f, 0.96303236f, -1.20068836f}; - } - { - data.value_data = { - 1.79297853f, 0.96909231f, 1.23087275f, -0.61933923f, -0.56477690f, 1.47813499f, 0.51474279f, -3.44743419f, - 0.95816678f, -0.20553169f, -0.76906109f, -4.60927439f, 0.40629998f, 0.91934747f, -1.09594405f, -1.45653892f, - -0.59282207f, 0.05621797f, -2.26634383f, -1.30799258f, 1.22072279f, -3.60811162f, 1.70111597f, 0.47336632f, - -1.43857694f, -0.13917151f, -1.34617388f, 1.07960105f, -1.77342618f, 0.31946269f, 1.19137061f, 2.59346104f, - -1.82395399f, 0.73557752f, 2.32600021f, -0.22650969f, -0.48526058f, 1.40349376f, -0.33553454f, 0.45531431f, - 0.73859257f, 0.37798560f, 0.85344458f, -1.30447221f, 1.23349071f, -0.26439479f, 1.18636096f, -0.33328748f, - -0.50939041f, 0.53500950f, 1.33486223f, -1.54447496f, -2.88690519f, -0.06809106f, -0.00597921f, -1.07510388f, - 0.62182164f, 0.50033569f, -0.88293070f, 2.56142712f, 0.37708595f, 1.59349704f, -1.17139614f, 0.89580274f, - 0.69456708f, 2.91441655f, -0.25431669f, -1.20305562f, 2.06701255f, -0.86700624f, -2.23615170f, 0.13303493f, - -2.97540593f, 0.08654684f, 1.40381706f, 3.54294443f, -2.07661867f, -1.33181918f, 2.24228764f, 1.79975545f, - 2.14695477f, 1.40222490f, -0.29813689f, 1.94485068f, 1.99623775f, 1.53450203f, 0.28755581f, -0.67934704f, - -0.92102510f, -1.52764773f, 1.11267352f, -3.90122724f, 0.22128634f, 0.14945325f, -4.38529491f, -1.58423281f}; - } - - { - data.bias_data = { - -0.38124341f, 0.02696526f, -0.11914945f, -0.43795273f, -0.34948170f, -0.19608477f, 0.19725692f, 0.39987487f, - 0.04772711f, -0.03419551f, -0.30606642f, 0.42656231f, -0.23178342f, -0.13692456f, -0.04889601f, 0.48739988f, - -0.25891554f, 0.13431972f, 0.22861153f, 0.06360734f, 0.48096961f, -0.47906545f, 0.43613154f, -0.23511401f, - -0.10595283f, -0.42839217f, 0.28931111f, -0.13180739f, -0.45826656f, 0.23286396f, -0.43407962f, 0.40754890f, - 0.27079183f, 0.42074734f, -0.40314156f, -0.43726659f, 0.27376485f, -0.38174152f, -0.43700469f, 0.38040614f, - -0.40546918f, 0.06927037f, 0.16979086f, 0.41458064f, 0.07120579f, -0.08055863f, 0.12095112f, -0.27988660f, - 0.06004709f, -0.05600315f, -0.25510073f, 0.41887105f, -0.19016314f, 0.47241372f, 0.12890404f, -0.24272856f, - 0.21106839f, -0.40523255f, 0.10336459f, -0.11084765f, 0.42408967f, -0.15285304f, -0.28945464f, -0.25714916f, - -0.10567203f, 0.26791072f, -0.08976898f, 0.31341976f, 0.06027532f, 0.14307594f, 0.31587386f, 0.16180152f, - 0.34785229f, 0.00531715f, -0.35168743f, -0.11641458f, 0.39196932f, 0.44535065f, 0.43545735f, 0.15593112f, - 0.06171834f, -0.42181283f, -0.41170910f, 0.40969193f, -0.01510030f, 0.07973170f, -0.18156880f, 0.21522856f, - 0.03915739f, -0.20913908f, -0.47068381f, 0.35633272f, -0.35124153f, 0.36624825f, -0.05567622f, -0.35343069f}; - } - - { - data.fp32_output_data = { - 0.70553654f, 2.84393549f, -0.06753166f, -0.78168941f, 1.67733538f, -0.32306066f, -1.46519351f, -0.24197248f, - -1.95703733f, 0.05333783f, 0.71154630f, 2.09348249f, -1.24223638f, -0.52374214f, 2.15032387f, 1.41931129f, - -0.12594563f, 0.02337830f, -0.85073662f, -0.56283176f, -0.47189179f, -1.30011129f, 0.58861959f, -0.13839069f, - -0.43588838f, -0.25786775f, -1.28476405f, 1.40800762f, -0.92311549f, 1.21551156f, -0.64031672f, 0.94095230f, - - -1.87212098f, 1.04452848f, 2.18516684f, 0.06764929f, -0.37797281f, 1.50475919f, -0.05229051f, 0.59941143f, - 1.01834595f, 0.37615222f, 0.50706661f, -1.34108353f, 1.56169033f, 0.16475427f, 1.63450289f, -0.14124450f, - -0.21351013f, 0.15201563f, 0.47484040f, -0.79835385f, -2.11648011f, -0.13788147f, -0.01865268f, -0.69491959f, - 0.34924412f, 0.05382843f, -1.21107709f, 2.20767021f, -0.16749848f, 1.72250605f, -1.32190716f, 0.45872629f}; - } + LoadTensor("CrossAttentionData_HeadSize16.query_data", data.query_data); + LoadTensor("CrossAttentionData_HeadSize16.key_data", data.key_data); + LoadTensor("CrossAttentionData_HeadSize16.value_data", data.value_data); + LoadTensor("CrossAttentionData_HeadSize16.bias_data", data.bias_data); + LoadTensor("CrossAttentionData_HeadSize16.fp32_output_data", data.fp32_output_data); + data.fp16_output_data = data.fp32_output_data; +} - { - data.fp16_output_data = data.fp32_output_data; - } +void GetCrossAttentionData_HeadSize16_NoBias(AttentionTestData& data) { + GetCrossAttentionData_HeadSize16(data); + data.bias_data.clear(); + LoadTensor("CrossAttentionData_HeadSize16_NoBias.fp32_output_data", data.fp32_output_data); + data.fp16_output_data = data.fp32_output_data; } void GetCrossAttentionDataWithPast(AttentionTestData& data) { @@ -2924,45 +265,12 @@ void GetCrossAttentionDataWithPast(AttentionTestData& data) { AttentionKernelType::AttentionKernel_TrtFusedAttention, AttentionKernelType::AttentionKernel_CutlassMemoryEfficientAttention}; - { - data.query_data = { - -0.10939738f, -0.11916742f, -0.23157823f, -0.12894472f, - -0.02661306f, 0.26251313f, 0.30725253f, -0.34759378f, - -0.11695808f, -0.13129434f, -0.17031054f, -0.14986445f, - -0.02826184f, 0.2797631f, 0.27337456f, -0.44312602f}; - } + LoadTensor("CrossAttentionDataWithPast.query_data", data.query_data); // The past key and value data will be passed to the kernel as input 'key' and 'value'. - { - data.past_key_data = { - 0.5967375f, 0.5966938f, 0.48602432f, 0.5341031f, - 0.55797786f, 0.5663399f, 0.57087725f, 0.6240304f, - 0.5352563f, 0.5648297f, 0.4972945f, 0.56637144f, - - 0.44123724f, 0.35872823f, 0.32176313f, 0.4490301f, - 0.3643952f, 0.51968557f, 0.50137347f, 0.5743993f, - 0.3905106f, 0.4741712f, 0.40881708f, 0.47243845f}; - } - - { - data.past_value_data = { - 0.40251260f, 0.55487730f, 0.49565578f, 0.42683450f, - 0.44379145f, 0.58945787f, 0.54852820f, 0.43376005f, - 0.44116694f, 0.44007313f, 0.40293324f, 0.53202707f, - - 0.35520583f, 0.47293650f, 0.45417705f, 0.33723440f, - 0.50175804f, 0.37620395f, 0.24103148f, 0.50958070f, - 0.56803876f, 0.37866923f, 0.32273075f, 0.44389135f}; - } - - { - data.fp32_output_data = { - 0.4291f, 0.5275f, 0.4818f, 0.4645f, 0.4770f, 0.4082f, 0.3372f, 0.4319f, - 0.4291f, 0.5276f, 0.4818f, 0.4645f, 0.4768f, 0.4083f, 0.3377f, 0.4315f}; - } - - { - data.fp16_output_data = data.fp32_output_data; - } + LoadTensor("CrossAttentionDataWithPast.past_key_data", data.past_key_data); + LoadTensor("CrossAttentionDataWithPast.past_value_data", data.past_value_data); + LoadTensor("CrossAttentionDataWithPast.fp32_output_data", data.fp32_output_data); + data.fp16_output_data = data.fp32_output_data; } void GetSelfAttentionData_WithPast_WithRelPosBias_ForT5(AttentionTestData& data) { @@ -2981,100 +289,17 @@ void GetSelfAttentionData_WithPast_WithRelPosBias_ForT5(AttentionTestData& data) AttentionKernelType::AttentionKernel_CutlassMemoryEfficientAttention, }; - { - data.query_data = { - 0.00403503f, 0.08716156f, -0.0358175f, -0.08171791f, - 0.48912194f, -0.22679007f, -0.09093101f, -0.5939322f, - 0.00878838f, 0.03355761f, -0.08080226f, -0.06677517f, - 0.55038965f, -0.2720567f, -0.12977877f, -0.634123f}; - } - { - data.key_data = { - 0.2808786f, 0.10041683f, 0.15880886f, 0.45283064f, - 0.39884242f, 0.12596075f, 0.4198916f, -0.0651141f, - 0.31678027f, 0.11010794f, 0.21594375f, 0.4975329f, - 0.436772f, 0.20940652f, 0.44072092f, -0.05601776f}; - } - - { - data.value_data = { - 0.26421773f, -0.16541699f, -0.0599675f, 0.27200517f, - -0.1074627f, -0.4493224f, -0.03694462f, 0.17997989f, - 0.27960598f, -0.16643806f, -0.07019104f, 0.29006317f, - -0.11640988f, -0.47876123f, -0.01979145f, 0.11468418f}; - } - - { - data.rel_pos_bias_data = { - 0.4781123f, 0.82420444f, 0.654424f, 0.3995186f, 0.5482078f, - 0.55570245f, 0.4216576f, 0.46001542f, 0.67183703f, 0.41973996f, - - 0.28494194f, 0.60367906f, 0.3453173f, 0.44483483f, 0.6770777f, - 0.5460559f, 0.31994605f, 0.5470492f, 0.5433419f, 0.60349935f}; - } - - { - data.past_key_data = { - 0.34734827f, 0.5592256f, 0.5333037f, 0.5122027f, - 0.5940516f, 0.44744077f, 0.43128848f, 0.55360645f, - 0.57874715f, 0.29512063f, 0.2780432f, 0.4693917f, - - 0.4450266f, 0.530704f, 0.3124955f, 0.4273598f, - 0.44368753f, 0.5890438f, 0.5054336f, 0.46042535f, - 0.5352153f, 0.5157861f, 0.39744973f, 0.5441864f}; - } - - { - data.past_value_data = { - 0.48998538f, 0.5493853f, 0.556647f, 0.7011929f, - 0.543909f, 0.5630743f, 0.5087797f, 0.3901024f, - 0.53116417f, 0.4086225f, 0.5320247f, 0.5145377f, - - 0.4086198f, 0.6913348f, 0.50045484f, 0.5338214f, - 0.52980417f, 0.5243695f, 0.6046111f, 0.53555113f, - 0.44936907f, 0.6010697f, 0.38031512f, 0.427301f}; - } - - { - data.fp32_output_data = { - 0.4358f, 0.2708f, 0.3201f, 0.4347f, 0.1886f, 0.0845f, 0.2479f, 0.3289f, - 0.4157f, 0.2247f, 0.2826f, 0.4321f, 0.1874f, 0.1021f, 0.2427f, 0.3305f}; - } - - { - data.fp16_output_data = data.fp32_output_data; - } - - { - data.present_key_data = { - 0.3473f, 0.5592f, 0.5333f, 0.5122f, - 0.5941f, 0.4474f, 0.4313f, 0.5536f, - 0.5787f, 0.2951f, 0.2780f, 0.4694f, - 0.2809f, 0.1004f, 0.1588f, 0.4528f, - 0.3168f, 0.1101f, 0.2159f, 0.4975f, - - 0.4450f, 0.5307f, 0.3125f, 0.4274f, - 0.4437f, 0.5890f, 0.5054f, 0.4604f, - 0.5352f, 0.5158f, 0.3974f, 0.5442f, - 0.3988f, 0.1260f, 0.4199f, -0.0651f, - 0.4368f, 0.2094f, 0.4407f, -0.0560f}; - } - - { - data.present_value_data = { - 0.4900f, 0.5494f, 0.5566f, 0.7012f, - 0.5439f, 0.5631f, 0.5088f, 0.3901f, - 0.5312f, 0.4086f, 0.5320f, 0.5145f, - 0.2642f, -0.1654f, -0.0600f, 0.2720f, - 0.2796f, -0.1664f, -0.0702f, 0.2901f, - - 0.4086f, 0.6913f, 0.5005f, 0.5338f, - 0.5298f, 0.5244f, 0.6046f, 0.5356f, - 0.4494f, 0.6011f, 0.3803f, 0.4273f, - -0.1075f, -0.4493f, -0.0369f, 0.1800f, - -0.1164f, -0.4788f, -0.0198f, 0.1147f}; - } - + LoadTensor("SelfAttentionData_WithPast_WithRelPosBias_ForT5.query_data", data.query_data); + LoadTensor("SelfAttentionData_WithPast_WithRelPosBias_ForT5.key_data", data.key_data); + LoadTensor("SelfAttentionData_WithPast_WithRelPosBias_ForT5.value_data", data.value_data); + LoadTensor("SelfAttentionData_WithPast_WithRelPosBias_ForT5.rel_pos_bias_data", data.rel_pos_bias_data); + data.broadcast_rel_pos_bias = false; + LoadTensor("SelfAttentionData_WithPast_WithRelPosBias_ForT5.past_key_data", data.past_key_data); + LoadTensor("SelfAttentionData_WithPast_WithRelPosBias_ForT5.past_value_data", data.past_value_data); + LoadTensor("SelfAttentionData_WithPast_WithRelPosBias_ForT5.fp32_output_data", data.fp32_output_data); + data.fp16_output_data = data.fp32_output_data; + LoadTensor("SelfAttentionData_WithPast_WithRelPosBias_ForT5.present_key_data", data.present_key_data); + LoadTensor("SelfAttentionData_WithPast_WithRelPosBias_ForT5.present_value_data", data.present_value_data); data.is_static_kv = false; } @@ -3094,463 +319,14 @@ void GetAttentionDataCutlassRelPosBias(AttentionTestData& data) { AttentionKernelType::AttentionKernel_TrtFusedCrossAttention, AttentionKernelType::AttentionKernel_TrtFusedAttention}; - { - data.query_data = { - -0.029273793f, - 0.079709493f, - 0.064531095f, - 0.24270254f, - -0.28326464f, - 0.20984903f, - -0.10173888f, - 0.18373983f, - - 0.089472905f, - -0.0063416883f, - -0.049477674f, - 0.36512995f, - -0.23620239f, - 0.1464397f, - 0.068258412f, - 0.31627196f, - - 0.12436871f, - -0.0075563118f, - -0.11576633f, - 0.41008925f, - -0.19456652f, - 0.20145792f, - 0.11790096f, - 0.39789933f, - - 0.002485469f, - 0.029660821f, - -0.043821491f, - 0.3892332f, - -0.26994205f, - 0.14530671f, - 0.12950704f, - 0.36185294f, - - -0.029273793f, - 0.079709493f, - 0.064531095f, - 0.24270254f, - -0.28326464f, - 0.20984903f, - -0.10173888f, - 0.18373983f, - - 0.089472905f, - -0.0063416883f, - -0.049477674f, - 0.36512995f, - -0.23620239f, - 0.1464397f, - 0.068258412f, - 0.31627196f, - - 0.12436871f, - -0.0075563118f, - -0.11576633f, - 0.41008925f, - -0.19456652f, - 0.20145792f, - 0.11790096f, - 0.39789933f, - - 0.002485469f, - 0.029660821f, - -0.043821491f, - 0.3892332f, - -0.26994205f, - 0.14530671f, - 0.12950704f, - 0.36185294f, - }; - } - { - data.key_data = { - -0.32538497f, - 0.34121913f, - -0.18170178f, - -0.015152611f, - 0.20429322f, - 0.25979176f, - 0.21269324f, - 0.0025638193f, - - -0.24246037f, - 0.21112341f, - -0.36959589f, - -0.16091451f, - 0.24183474f, - 0.18856162f, - 0.094487116f, - -0.3053959f, - - -0.35736683f, - 0.29276621f, - -0.4217523f, - -0.20031664f, - 0.33148992f, - 0.26928401f, - 0.19360018f, - -0.39494509f, - - -0.28043351f, - 0.24279942f, - -0.29154932f, - -0.13657911f, - 0.31932494f, - 0.3500579f, - 0.027172565f, - -0.19327414f, - - -0.32538497f, - 0.34121913f, - -0.18170178f, - -0.015152611f, - 0.20429322f, - 0.25979176f, - 0.21269324f, - 0.0025638193f, - - -0.24246037f, - 0.21112341f, - -0.36959589f, - -0.16091451f, - 0.24183474f, - 0.18856162f, - 0.094487116f, - -0.3053959f, - - -0.35736683f, - 0.29276621f, - -0.4217523f, - -0.20031664f, - 0.33148992f, - 0.26928401f, - 0.19360018f, - -0.39494509f, - - -0.28043351f, - 0.24279942f, - -0.29154932f, - -0.13657911f, - 0.31932494f, - 0.3500579f, - 0.027172565f, - -0.19327414f, - }; - } - - { - data.value_data = { - 0.56916672f, - -0.2443777f, - 0.47111356f, - -0.52134115f, - 0.010381341f, - 0.0696759f, - -0.071910433f, - -0.35201436f, - - 0.70809275f, - -0.24479815f, - 0.41633749f, - -0.34744334f, - -0.0044222325f, - 0.25929695f, - -0.087832771f, - -0.281232f, - - 0.90039468f, - -0.28931504f, - 0.56394172f, - -0.43948689f, - -0.05856207f, - 0.33713666f, - -0.10320446f, - -0.38833332f, - - 0.76054728f, - -0.29080144f, - 0.50414616f, - -0.42371163f, - -0.047198489f, - 0.31959397f, - -0.22683662f, - -0.30321664f, - - 0.56916672f, - -0.2443777f, - 0.47111356f, - -0.52134115f, - 0.010381341f, - 0.0696759f, - -0.071910433f, - -0.35201436f, - - 0.70809275f, - -0.24479815f, - 0.41633749f, - -0.34744334f, - -0.0044222325f, - 0.25929695f, - -0.087832771f, - -0.281232f, - - 0.90039468f, - -0.28931504f, - 0.56394172f, - -0.43948689f, - -0.05856207f, - 0.33713666f, - -0.10320446f, - -0.38833332f, - - 0.76054728f, - -0.29080144f, - 0.50414616f, - -0.42371163f, - -0.047198489f, - 0.31959397f, - -0.22683662f, - -0.30321664f, - }; - } - - { - data.bias_data = { - -0.38124341f, 0.02696526f, -0.11914945f, -0.43795273f, - 0.04772711f, -0.03419551f, -0.30606642f, 0.42656231f, - -0.25891554f, 0.13431972f, 0.22861153f, 0.06360734f, - -0.10595283f, -0.42839217f, 0.28931111f, -0.13180739f, - 0.27079183f, 0.42074734f, -0.40314156f, -0.43726659f, - -0.40546918f, 0.06927037f, 0.16979086f, 0.41458064f}; - } - - { - data.rel_pos_bias_data = { - -10.808288f, - -10.887209f, - 7.8799553f, - -4.6565766f, - -1.6700006f, - -0.033962168f, - 7.4929152f, - 10.944146f, - 8.640254f, - -18.862164f, - -3.1202927f, - -6.3049207f, - 3.4508536f, - 11.722519f, - 3.3550568f, - -5.4888172f, - - -2.0828252f, - -13.241742f, - 2.9868939f, - 1.4455698f, - -15.262972f, - -10.457437f, - -8.4519463f, - -4.4281874f, - 10.212368f, - -0.28622282f, - 12.087646f, - 6.5218501f, - 8.1785011f, - 13.985523f, - -8.2068987f, - 5.4260745f, - - -10.808288f, - -10.887209f, - 7.8799553f, - -4.6565766f, - -1.6700006f, - -0.033962168f, - 7.4929152f, - 10.944146f, - 8.640254f, - -18.862164f, - -3.1202927f, - -6.3049207f, - 3.4508536f, - 11.722519f, - 3.3550568f, - -5.4888172f, - - -2.0828252f, - -13.241742f, - 2.9868939f, - 1.4455698f, - -15.262972f, - -10.457437f, - -8.4519463f, - -4.4281874f, - 10.212368f, - -0.28622282f, - 12.087646f, - 6.5218501f, - 8.1785011f, - 13.985523f, - -8.2068987f, - 5.4260745f, - - -10.808288f, - -10.887209f, - 7.8799553f, - -4.6565766f, - -1.6700006f, - -0.033962168f, - 7.4929152f, - 10.944146f, - 8.640254f, - -18.862164f, - -3.1202927f, - -6.3049207f, - 3.4508536f, - 11.722519f, - 3.3550568f, - -5.4888172f, - - -2.0828252f, - -13.241742f, - 2.9868939f, - 1.4455698f, - -15.262972f, - -10.457437f, - -8.4519463f, - -4.4281874f, - 10.212368f, - -0.28622282f, - 12.087646f, - 6.5218501f, - 8.1785011f, - 13.985523f, - -8.2068987f, - 5.4260745f, - - -10.808288f, - -10.887209f, - 7.8799553f, - -4.6565766f, - -1.6700006f, - -0.033962168f, - 7.4929152f, - 10.944146f, - 8.640254f, - -18.862164f, - -3.1202927f, - -6.3049207f, - 3.4508536f, - 11.722519f, - 3.3550568f, - -5.4888172f, - - -2.0828252f, - -13.241742f, - 2.9868939f, - 1.4455698f, - -15.262972f, - -10.457437f, - -8.4519463f, - -4.4281874f, - 10.212368f, - -0.28622282f, - 12.087646f, - 6.5218501f, - 8.1785011f, - 13.985523f, - -8.2068987f, - 5.4260745f, - }; - } - - { - data.fp16_output_data = { - 1.0419922f, - 0.13000488f, - 0.10528564f, - -0.86230469f, - -0.45336914f, - 0.39013672f, - -0.048858643f, - 0.10571289f, - - 0.97265625f, - 0.17590332f, - 0.015625f, - -0.79248047f, - -0.40917969f, - 0.31933594f, - 0.082763672f, - 0.12976074f, - - 1.1455078f, - 0.13134766f, - 0.15014648f, - -0.87451172f, - -0.46142578f, - 0.40161133f, - 0.04309082f, - 0.042663574f, - - 1.0009766f, - 0.17004395f, - 0.033752441f, - -0.80078125f, - -0.41625977f, - 0.33349609f, - 0.080383301f, - 0.11846924f, - - 1.0419922f, - 0.13000488f, - 0.10528564f, - -0.86230469f, - -0.45336914f, - 0.39013672f, - -0.048858643f, - 0.10571289f, - - 0.97265625f, - 0.17590332f, - 0.015625f, - -0.79248047f, - -0.40917969f, - 0.31933594f, - 0.082763672f, - 0.12976074f, - - 1.1455078f, - 0.13134766f, - 0.15014648f, - -0.87451172f, - -0.46142578f, - 0.40161133f, - 0.04309082f, - 0.042663574f, - - 1.0009766f, - 0.17004395f, - 0.033752441f, - -0.80078125f, - -0.41625977f, - 0.33349609f, - 0.080383301f, - 0.11846924f, - }; - } - - { - data.fp32_output_data = {}; - } - + LoadTensor("AttentionDataCutlassRelPosBias.query_data", data.query_data); + LoadTensor("AttentionDataCutlassRelPosBias.key_data", data.key_data); + LoadTensor("AttentionDataCutlassRelPosBias.value_data", data.value_data); + LoadTensor("AttentionDataCutlassRelPosBias.bias_data", data.bias_data); + LoadTensor("AttentionDataCutlassRelPosBias.rel_pos_bias_data", data.rel_pos_bias_data); + data.broadcast_rel_pos_bias = false; + LoadTensor("AttentionDataCutlassRelPosBias.fp16_output_data", data.fp16_output_data); + data.fp32_output_data = {}; data.is_static_kv = false; } @@ -3570,381 +346,50 @@ void GetCrossAttentionData_DiffSequenceLengths(AttentionTestData& data) { AttentionKernelType::AttentionKernel_CutlassMemoryEfficientAttention, }; - data.query_data = { - 0.19646919f, - -0.21386067f, - -0.27314855f, - 0.05131477f, - 0.21946897f, - -0.07689354f, - 0.4807642f, - 0.18482974f, - -0.0190681f, - -0.10788248f, - -0.15682198f, - 0.22904971f, - -0.06142776f, - -0.4403221f, - -0.10195574f, - 0.23799541f, - - -0.31750827f, - -0.32454824f, - 0.03155137f, - 0.03182759f, - 0.13440096f, - 0.34943179f, - 0.22445532f, - 0.11102351f, - 0.22244338f, - -0.17704109f, - -0.13821134f, - -0.27173677f, - -0.20628595f, - 0.13097612f, - -0.40789506f, - -0.06629883f, - }; - data.key_data = { - -0.06913724f, - -0.0063149f, - -0.07416971f, - -0.18773878f, - -0.07364869f, - 0.39338916f, - 0.44416002f, - 0.00183668f, - 0.12395295f, - -0.3843816f, - -0.18271452f, - -0.08517379f, - 0.36630916f, - -0.24954463f, - -0.01696574f, - 0.48555979f, - - 0.01948512f, - 0.11289453f, - -0.37937133f, - 0.3263408f, - 0.10306013f, - 0.04506801f, - -0.15723617f, - -0.19587921f, - -0.08297779f, - 0.18130077f, - 0.37545684f, - 0.01042234f, - 0.16931378f, - 0.08593655f, - 0.1249035f, - 0.17468905f, - - 0.34234244f, - -0.41680501f, - 0.26368284f, - -0.25633363f, - -0.30577704f, - 0.07245696f, - -0.40428748f, - 0.38532683f, - 0.12724897f, - 0.22341636f, - -0.48387079f, - 0.09443188f, - 0.05678519f, - -0.34104036f, - -0.34692948f, - 0.19552953f, - - -0.18123357f, - 0.1919703f, - 0.05438325f, - -0.11104943f, - 0.42513249f, - 0.34167f, - -0.14260243f, - -0.45640854f, - -0.19523193f, - -0.10181432f, - 0.20495883f, - 0.49535848f, - -0.14408513f, - 0.26254781f, - 0.09317692f, - 0.1917018f, - }; - data.value_data = { - -0.34887255f, - -0.10112371f, - -0.2591441f, - -0.15654399f, - 0.01312815f, - 0.16662455f, - -0.39409151f, - -0.36910505f, - -0.17801939f, - 0.16156434f, - 0.34650623f, - 0.05325734f, - 0.35445249f, - -0.11516219f, - -0.1832121f, - -0.14573532f, - - -0.32891817f, - 0.32911263f, - -0.16132915f, - 0.05237008f, - 0.07855147f, - 0.02153306f, - -0.49731194f, - 0.48834542f, - 0.40534158f, - -0.29236414f, - -0.20751059f, - 0.02001015f, - 0.40191137f, - 0.48363088f, - -0.24245794f, - 0.06435904f, - - 0.30696868f, - -0.10562995f, - 0.23107304f, - -0.33893099f, - 0.10069857f, - 0.36586446f, - 0.48352161f, - -0.42063421f, - -0.07165273f, - -0.29545714f, - -0.04936351f, - 0.04776357f, - -0.40667329f, - -0.20313922f, - 0.42758424f, - 0.06900373f, - - -0.042588f, - 0.25352599f, - 0.24186215f, - -0.45142097f, - 0.2086974f, - 0.33924335f, - -0.33406212f, - 0.28099794f, - -0.21346338f, - -0.19353025f, - 0.16526147f, - -0.38860783f, - 0.16487245f, - 0.38785679f, - 0.19631127f, - -0.05967212f, - }; - data.bias_data = { - -0.06178562f, - 0.2650961f, - 0.065642f, - -0.41509584f, - 0.08267109f, - 0.3148437f, - -0.16293362f, - 0.42757658f, - 0.250717f, - 0.07406383f, - 0.25164399f, - -0.42085104f, - 0.35938908f, - 0.32150411f, - 0.40987166f, - -0.3713688f, - -0.41821991f, - -0.36158443f, - -0.10062129f, - -0.07569314f, - 0.06221838f, - -0.37775645f, - -0.2986005f, - 0.31164435f, - }; - - data.fp32_output_data = { - -0.53803939f, - -0.33528122f, - -0.16753256f, - -0.084826469f, - 0.28213754f, - -0.23802593f, - -0.61857146f, - 0.29926175f, - -0.53170669f, - -0.33900675f, - -0.17392565f, - -0.084655531f, - 0.28832543f, - -0.24704586f, - -0.61680299f, - 0.31617802f, - - -0.41967732f, - -0.43735462f, - 0.051356006f, - -0.36559904f, - 0.093453586f, - -0.13974363f, - -0.10689265f, - 0.27119368f, - -0.40707609f, - -0.44006824f, - 0.048184391f, - -0.35585383f, - 0.081379525f, - -0.14954941f, - -0.086910933f, - 0.25871021f, - }; - - data.present_key_data = { - 0.18157977f, - 0.067748934f, - 0.17747428f, - -0.60858983f, - 0.37466997f, - -0.31031775f, - 0.068929464f, - -0.50602484f, - 0.27020213f, - 0.18695836f, - -0.12772733f, - -0.094510257f, - 0.16773923f, - 0.2553646f, - 0.62710083f, - -0.4104287f, - - 0.28574038f, - 0.71489328f, - 0.85403168f, - -0.36953211f, - 0.72569823f, - 0.071959481f, - 0.39290592f, - 0.114191f, - 0.46244919f, - 0.36657214f, - 0.25263548f, - -0.56724799f, - 0.52870286f, - 0.40744066f, - 0.53477514f, - -0.19667974f, + LoadTensor("CrossAttentionData_DiffSequenceLengths.query_data", data.query_data); + LoadTensor("CrossAttentionData_DiffSequenceLengths.key_data", data.key_data); + LoadTensor("CrossAttentionData_DiffSequenceLengths.value_data", data.value_data); + LoadTensor("CrossAttentionData_DiffSequenceLengths.bias_data", data.bias_data); + LoadTensor("CrossAttentionData_DiffSequenceLengths.fp32_output_data", data.fp32_output_data); + LoadTensor("CrossAttentionData_DiffSequenceLengths.present_key_data", data.present_key_data); + LoadTensor("CrossAttentionData_DiffSequenceLengths.present_value_data", data.present_value_data); + data.is_static_kv = true; +} - 0.59305942f, - -0.34274116f, - 0.51532686f, - -0.6771847f, - 0.37796599f, - 0.2974802f, - -0.23222682f, - -0.32641917f, - 0.069483444f, - 0.26603413f, - 0.30602723f, - -0.53190047f, - 0.055485085f, - -0.027750492f, - 0.45660281f, - 0.074507415f, +void GetCrossAttentionData_DiffSequenceLengths_HeadSize8(AttentionTestData& data) { + data.hidden_size = 16; + data.v_hidden_size = 16; + data.num_heads = 2; + data.batch_size = 1; + data.sequence_length = 2; + data.kv_sequence_length = 4; + data.mask_type = AttentionMaskType::MASK_NONE; - 0.053612024f, - 0.39396107f, - 0.0055841804f, - 0.013958037f, - 0.41617426f, - -0.019536257f, - 0.062942177f, - -0.17583926f, - 0.78452158f, - 0.66317415f, - 0.26726925f, - -0.82777733f, - 0.21530394f, - 0.58405197f, - 0.5030486f, - -0.179667f, + data.skip_kernel_types = { + AttentionKernelType::AttentionKernel_TrtFlashAttention, + AttentionKernelType::AttentionKernel_TrtFusedCrossAttention, + AttentionKernelType::AttentionKernel_TrtFusedAttention, + AttentionKernelType::AttentionKernel_CutlassMemoryEfficientAttention, }; - data.present_value_data = { - -0.76709247f, - -0.46270815f, - -0.35976538f, - -0.23223713f, - -0.59623933f, - -0.20002009f, - 0.24588495f, - -0.022435799f, - -0.74713808f, - -0.032471806f, - -0.26195043f, - -0.023323059f, - -0.012878358f, - -0.65394855f, - -0.30813187f, - -0.055682987f, - 0.075346529f, - -0.2111319f, - -0.69269204f, - -0.057460696f, - 0.41667086f, - -0.49291864f, - -0.4818126f, - 0.16590902f, - 0.14076985f, - -0.35622337f, - -0.79591244f, - 0.79998976f, - 0.46412975f, - 0.10587442f, - -0.54105842f, - 0.37600338f, - - -0.11125124f, - -0.46721438f, - 0.13045174f, - -0.41462412f, - -0.48987266f, - -0.65704155f, - -0.14998481f, - -0.027929567f, - -0.46080792f, - -0.10805842f, - 0.14124086f, - -0.52711409f, - -0.63168329f, - -0.55511469f, - 0.064640187f, - -0.46430096f, - - 0.16291694f, - -0.011891991f, - 0.18492112f, - -0.10898986f, - -0.34445491f, - -0.58089566f, - 0.12898374f, - 0.38064808f, - 0.27091578f, - -0.038513094f, - -0.63266265f, - 0.59264231f, - 0.22709084f, - 0.010100335f, - -0.10228923f, - 0.25197223f, - }; + LoadTensor("CrossAttentionData_DiffSequenceLengths_HeadSize8.query_data", data.query_data); + LoadTensor("CrossAttentionData_DiffSequenceLengths_HeadSize8.key_data", data.key_data); + LoadTensor("CrossAttentionData_DiffSequenceLengths_HeadSize8.value_data", data.value_data); + LoadTensor("CrossAttentionData_DiffSequenceLengths_HeadSize8.bias_data", data.bias_data); + LoadTensor("CrossAttentionData_DiffSequenceLengths_HeadSize8.fp32_output_data", data.fp32_output_data); + data.fp16_output_data = data.fp32_output_data; + LoadTensor("CrossAttentionData_DiffSequenceLengths_HeadSize8.present_key_data", data.present_key_data); + LoadTensor("CrossAttentionData_DiffSequenceLengths_HeadSize8.present_value_data", data.present_value_data); + data.is_static_kv = true; +} +void GetCrossAttentionData_DiffSequenceLengths_HeadSize8_NoBias(AttentionTestData& data) { + GetCrossAttentionData_DiffSequenceLengths_HeadSize8(data); + data.bias_data.clear(); + LoadTensor("CrossAttentionData_DiffSequenceLengths_HeadSize8_NoBias.fp32_output_data", data.fp32_output_data); + data.fp16_output_data = data.fp32_output_data; + LoadTensor("CrossAttentionData_DiffSequenceLengths_HeadSize8_NoBias.present_key_data", data.present_key_data); + LoadTensor("CrossAttentionData_DiffSequenceLengths_HeadSize8_NoBias.present_value_data", data.present_value_data); data.is_static_kv = true; } @@ -3964,219 +409,66 @@ void GetSelfAttentionData_WithPastAndPresent_NoMask_NoRelPosBias(AttentionTestDa AttentionKernelType::AttentionKernel_CutlassMemoryEfficientAttention, }; - data.query_data = { - 0.19646919f, - -0.21386067f, - -0.27314855f, - 0.05131477f, - 0.21946897f, - -0.07689354f, - 0.4807642f, - 0.18482974f, - -0.0190681f, - -0.10788248f, - -0.15682198f, - 0.22904971f, - -0.06142776f, - -0.4403221f, - -0.10195574f, - 0.23799541f, - }; - data.key_data = { - -0.31750827f, - -0.32454824f, - 0.03155137f, - 0.03182759f, - 0.13440096f, - 0.34943179f, - 0.22445532f, - 0.11102351f, - 0.22244338f, - -0.17704109f, - -0.13821134f, - -0.27173677f, - -0.20628595f, - 0.13097612f, - -0.40789506f, - -0.06629883f, - }; - data.value_data = { - -0.06913724f, - -0.0063149f, - -0.07416971f, - -0.18773878f, - -0.07364869f, - 0.39338916f, - 0.44416002f, - 0.00183668f, - 0.12395295f, - -0.3843816f, - -0.18271452f, - -0.08517379f, - 0.36630916f, - -0.24954463f, - -0.01696574f, - 0.48555979f, - }; - - data.bias_data = { - 0.01948512f, - 0.11289453f, - -0.37937133f, - 0.3263408f, - 0.10306013f, - 0.04506801f, - -0.15723617f, - -0.19587921f, - -0.08297779f, - 0.18130077f, - 0.37545684f, - 0.01042234f, - 0.16931378f, - 0.08593655f, - 0.1249035f, - 0.17468905f, - 0.34234244f, - -0.41680501f, - 0.26368284f, - -0.25633363f, - -0.30577704f, - 0.07245696f, - -0.40428748f, - 0.38532683f, - }; - - data.past_key_data = { - 0.12724897f, - 0.22341636f, - -0.48387079f, - 0.09443188f, - 0.05678519f, - -0.34104036f, - -0.34692948f, - 0.19552953f, - -0.18123357f, - 0.1919703f, - 0.05438325f, - -0.11104943f, - 0.42513249f, - 0.34167f, - -0.14260243f, - -0.45640854f, - }; - data.past_value_data = { - -0.19523193f, - -0.10181432f, - 0.20495883f, - 0.49535848f, - -0.14408513f, - 0.26254781f, - 0.09317692f, - 0.1917018f, - -0.34887255f, - -0.10112371f, - -0.2591441f, - -0.15654399f, - 0.01312815f, - 0.16662455f, - -0.39409151f, - -0.36910505f, - }; - - data.fp32_output_data = { - -0.00033577532f, - -0.23549549f, - 0.19853255f, - 0.10450245f, - -0.26995566f, - 0.37128073f, - 0.064667389f, - 0.29624334f, - 0.040147364f, - -0.43521237f, - -0.096833363f, - -0.24481347f, - 0.037364807f, - -0.0091082826f, - -0.40797871f, - 0.26487666f, - }; - - data.present_key_data = { - 0.12724897f, - 0.22341636f, - -0.4838708f, - 0.094431877f, - -0.40048605f, - -0.14324747f, - 0.4070082f, - 0.042249933f, - - 0.056785189f, - -0.34104037f, - -0.34692949f, - 0.19552954f, - 0.30371475f, - 0.43536833f, - 0.34935883f, - 0.28571257f, + LoadTensor("SelfAttentionData_WithPastAndPresent_NoMask_NoRelPosBias.query_data", data.query_data); + LoadTensor("SelfAttentionData_WithPastAndPresent_NoMask_NoRelPosBias.key_data", data.key_data); + LoadTensor("SelfAttentionData_WithPastAndPresent_NoMask_NoRelPosBias.value_data", data.value_data); + LoadTensor("SelfAttentionData_WithPastAndPresent_NoMask_NoRelPosBias.bias_data", data.bias_data); + LoadTensor("SelfAttentionData_WithPastAndPresent_NoMask_NoRelPosBias.past_key_data", data.past_key_data); + LoadTensor("SelfAttentionData_WithPastAndPresent_NoMask_NoRelPosBias.past_value_data", data.past_value_data); + LoadTensor("SelfAttentionData_WithPastAndPresent_NoMask_NoRelPosBias.fp32_output_data", data.fp32_output_data); + LoadTensor("SelfAttentionData_WithPastAndPresent_NoMask_NoRelPosBias.present_key_data", data.present_key_data); + LoadTensor("SelfAttentionData_WithPastAndPresent_NoMask_NoRelPosBias.present_value_data", data.present_value_data); + data.is_static_kv = false; +} - -0.18123357f, - 0.1919703f, - 0.054383252f, - -0.11104943f, - 0.1394656f, - 0.0042596906f, - 0.2372455f, - -0.26131442f, +void GetSelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias(AttentionTestData& data) { + data.hidden_size = 16; + data.v_hidden_size = 16; + data.num_heads = 2; + data.batch_size = 2; + data.sequence_length = 1; + data.kv_sequence_length = 1; + data.mask_type = AttentionMaskType::MASK_NONE; - 0.42513248f, - 0.34167001f, - -0.14260243f, - -0.45640853f, - -0.03697218f, - 0.21691267f, - -0.28299156f, - 0.10839023f, + data.skip_kernel_types = { + AttentionKernelType::AttentionKernel_TrtFlashAttention, + AttentionKernelType::AttentionKernel_TrtFusedCrossAttention, + AttentionKernelType::AttentionKernel_TrtFusedAttention, + AttentionKernelType::AttentionKernel_CutlassMemoryEfficientAttention, }; - data.present_value_data = { - -0.19523193f, - -0.10181432f, - 0.20495883f, - 0.49535847f, - 0.27320519f, - -0.4231199f, - 0.18951313f, - -0.4440724f, - - -0.14408512f, - 0.26254782f, - 0.093176924f, - 0.1917018f, - -0.37942573f, - 0.46584612f, - 0.039872527f, - 0.38716352f, - -0.34887254f, - -0.10112371f, - -0.2591441f, - -0.15654399f, - 0.46629539f, - -0.80118656f, - 0.08096832f, - -0.34150741f, - - 0.01312815f, - 0.16662455f, - -0.39409152f, - -0.36910504f, - 0.060532123f, - -0.17708766f, - -0.42125323f, - 0.87088662f, - }; + LoadTensor("SelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias.query_data", data.query_data); + LoadTensor("SelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias.key_data", data.key_data); + LoadTensor("SelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias.value_data", data.value_data); + LoadTensor("SelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias.bias_data", data.bias_data); + LoadTensor("SelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias.past_key_data", + data.past_key_data); + LoadTensor("SelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias.past_value_data", + data.past_value_data); + LoadTensor("SelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias.fp32_output_data", + data.fp32_output_data); + data.fp16_output_data = data.fp32_output_data; + LoadTensor("SelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias.present_key_data", + data.present_key_data); + LoadTensor("SelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias.present_value_data", + data.present_value_data); + data.is_static_kv = false; +} +void GetSelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias_NoBias(AttentionTestData& data) { + GetSelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias(data); + data.bias_data.clear(); + LoadTensor("SelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias_NoBias.past_key_data", + data.past_key_data); + LoadTensor("SelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias_NoBias.past_value_data", + data.past_value_data); + LoadTensor("SelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias_NoBias.fp32_output_data", + data.fp32_output_data); + data.fp16_output_data = data.fp32_output_data; + LoadTensor("SelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias_NoBias.present_key_data", + data.present_key_data); + LoadTensor("SelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias_NoBias.present_value_data", + data.present_value_data); data.is_static_kv = false; } @@ -4196,51 +488,122 @@ void GetCrossAttentionData_WithPastPassedInDirectly_NoMask(AttentionTestData& da AttentionKernelType::AttentionKernel_CutlassMemoryEfficientAttention, }; - data.query_data = { - -0.10939738f, -0.11916742f, -0.23157823f, -0.12894472f, - -0.02661306f, 0.26251313f, 0.30725253f, -0.34759378f, - -0.11695808f, -0.13129434f, -0.17031054f, -0.14986445f, - -0.02826184f, 0.2797631f, 0.27337456f, -0.44312602f}; - data.past_key_data = { - 0.5967375f, 0.5966938f, 0.48602432f, 0.5341031f, - 0.55797786f, 0.5663399f, 0.57087725f, 0.6240304f, - 0.5352563f, 0.5648297f, 0.4972945f, 0.56637144f, + LoadTensor("CrossAttentionData_WithPastPassedInDirectly_NoMask.query_data", data.query_data); + LoadTensor("CrossAttentionData_WithPastPassedInDirectly_NoMask.past_key_data", data.past_key_data); + LoadTensor("CrossAttentionData_WithPastPassedInDirectly_NoMask.past_value_data", data.past_value_data); + LoadTensor("CrossAttentionData_WithPastPassedInDirectly_NoMask.fp32_output_data", data.fp32_output_data); + data.fp16_output_data = data.fp32_output_data; +} - 0.44123724f, 0.35872823f, 0.32176313f, 0.4490301f, - 0.3643952f, 0.51968557f, 0.50137347f, 0.5743993f, - 0.3905106f, 0.4741712f, 0.40881708f, 0.47243845f}; - data.past_value_data = { - 0.40251260f, 0.55487730f, 0.49565578f, 0.42683450f, - 0.44379145f, 0.58945787f, 0.54852820f, 0.43376005f, - 0.44116694f, 0.44007313f, 0.40293324f, 0.53202707f, +void GetCausal_EmptyPastState(std::vector& input, std::vector& output, std::vector& present) { + LoadTensor("Causal_EmptyPastState.input_data", input); + LoadTensor("Causal_EmptyPastState.output_data", output); + LoadTensor("Causal_EmptyPastState.present_data", present); +} + +void GetAttentionDataWithNeoXRotaryEmbedding(std::vector& input, + std::vector& weights, + std::vector& bias, + std::vector& output) { + LoadTensor("AttentionDataWithNeoXRotaryEmbedding.input", input); + LoadTensor("AttentionDataWithNeoXRotaryEmbedding.weights", weights); + LoadTensor("AttentionDataWithNeoXRotaryEmbedding.bias", bias); + LoadTensor("AttentionDataWithNeoXRotaryEmbedding.output", output); +} - 0.35520583f, 0.47293650f, 0.45417705f, 0.33723440f, - 0.50175804f, 0.37620395f, 0.24103148f, 0.50958070f, - 0.56803876f, 0.37866923f, 0.32273075f, 0.44389135f}; +void GetPackedMultiHeadAttentionData_Batch2_HeadSize32_NoRelPosBias(PackedAttentionTestData& data) { + data.hidden_size = 32; + data.v_hidden_size = 32; + data.num_heads = 1; + data.batch_size = 2; + data.sequence_length = 2; + data.kv_sequence_length = 2; - data.fp32_output_data = { - 0.44753647f, - 0.52339733f, - 0.46447957f, - 0.46852112f, - 0.44769368f, - 0.5231511f, - 0.464194f, - 0.46851689f, + data.token_offset = {0, 2, 3, 1}; + data.cumulative_sequence_length = {0, 1, 3}; + data.token_count = 3; - 0.43687066f, - 0.3954815f, - 0.37647754f, - 0.44443309f, - 0.43690678f, - 0.39541441f, - 0.37764412f, - 0.44382966f, - }; + data.skip_kernel_types = { + AttentionKernelType::AttentionKernel_TrtFusedCrossAttention}; + + LoadTensor("PackedMultiHeadAttentionData_Batch2_HeadSize32_NoRelPosBias.query_data", data.query_data); + LoadTensor("PackedMultiHeadAttentionData_Batch2_HeadSize32_NoRelPosBias.key_data", data.key_data); + LoadTensor("PackedMultiHeadAttentionData_Batch2_HeadSize32_NoRelPosBias.value_data", data.value_data); + data.bias_data = {}; + LoadTensor("PackedMultiHeadAttentionData_Batch2_HeadSize32_NoRelPosBias.qkv_data", data.qkv_data); + + // Do not test fp32 + data.fp32_output_data = {}; + + LoadTensor("PackedMultiHeadAttentionData_Batch2_HeadSize32_NoRelPosBias.fp16_output_data", data.fp16_output_data); +} + +void GetPackedMultiHeadAttentionData_Batch2_HeadSize8_RelPosBias(PackedAttentionTestData& data) { + data.hidden_size = 16; + data.v_hidden_size = 16; + data.num_heads = 2; + data.batch_size = 2; + data.sequence_length = 2; + data.kv_sequence_length = 2; + data.token_offset = {0, 2, 3, 1}; + data.cumulative_sequence_length = {0, 1, 3}; + data.token_count = 3; + + data.skip_kernel_types = { + AttentionKernelType::AttentionKernel_TrtFusedCrossAttention}; + + LoadTensor("PackedMultiHeadAttentionData_Batch2_HeadSize8_RelPosBias.query_data", data.query_data); + LoadTensor("PackedMultiHeadAttentionData_Batch2_HeadSize8_RelPosBias.key_data", data.key_data); + LoadTensor("PackedMultiHeadAttentionData_Batch2_HeadSize8_RelPosBias.value_data", data.value_data); + data.bias_data = {}; + LoadTensor("PackedMultiHeadAttentionData_Batch2_HeadSize8_RelPosBias.qkv_data", data.qkv_data); + + // shape: batch_size, num_heads, sequence_length, sequence_length + LoadTensor("PackedMultiHeadAttentionData_Batch2_HeadSize8_RelPosBias.rel_pos_bias_data", data.rel_pos_bias_data); + data.broadcast_rel_pos_bias = false; + + // Do not test fp32 + data.fp32_output_data = {}; + + LoadTensor("PackedMultiHeadAttentionData_Batch2_HeadSize8_RelPosBias.fp16_output_data", data.fp16_output_data); +} + +void GetPackedMultiHeadAttentionData_Batch2_HeadSize8_BroadcastRelPosBias(PackedAttentionTestData& data) { + data.hidden_size = 16; + data.v_hidden_size = 16; + data.num_heads = 2; + data.batch_size = 2; + data.sequence_length = 8; + data.kv_sequence_length = 8; + data.token_offset = {0, 8, 9, 10, 11, 12, 13, 14, 15, 1, 2, 3, 4, 5, 6, 7}; + data.cumulative_sequence_length = {0, 1, 9}; + data.token_count = 9; + + data.skip_kernel_types = { + AttentionKernelType::AttentionKernel_TrtFusedCrossAttention}; + + LoadTensor("PackedMultiHeadAttentionData_Batch2_HeadSize8_BroadcastRelPosBias.query_data", data.query_data); + LoadTensor("PackedMultiHeadAttentionData_Batch2_HeadSize8_BroadcastRelPosBias.key_data", data.key_data); + LoadTensor("PackedMultiHeadAttentionData_Batch2_HeadSize8_BroadcastRelPosBias.value_data", data.value_data); + data.bias_data = {}; + LoadTensor("PackedMultiHeadAttentionData_Batch2_HeadSize8_BroadcastRelPosBias.qkv_data", data.qkv_data); + + // shape: 1, num_heads, sequence_length, sequence_length + LoadTensor("PackedMultiHeadAttentionData_Batch2_HeadSize8_BroadcastRelPosBias.rel_pos_bias_data", + data.rel_pos_bias_data); + data.broadcast_rel_pos_bias = true; + + // Do not test fp32 + data.fp32_output_data = {}; + + LoadTensor("PackedMultiHeadAttentionData_Batch2_HeadSize8_BroadcastRelPosBias.fp16_output_data", + data.fp16_output_data); } bool SkipAttentionKernel(AttentionTestData& data, AttentionKernelType kernel_type) { - return std::find(data.skip_kernel_types.begin(), data.skip_kernel_types.end(), kernel_type) != data.skip_kernel_types.end(); + return data.skip_kernel_types.end() != std::find(data.skip_kernel_types.begin(), + data.skip_kernel_types.end(), + kernel_type); } } // namespace test diff --git a/onnxruntime/test/contrib_ops/attention_op_test_helper.h b/onnxruntime/test/contrib_ops/attention_op_test_helper.h index 21cee275fd1af..0ed30596ac136 100644 --- a/onnxruntime/test/contrib_ops/attention_op_test_helper.h +++ b/onnxruntime/test/contrib_ops/attention_op_test_helper.h @@ -10,7 +10,7 @@ using contrib::AttentionMaskType; namespace test { -struct AttentionTestData { +struct BaseAttentionTestData { bool is_static_kv = true; int hidden_size; int v_hidden_size; @@ -18,8 +18,7 @@ struct AttentionTestData { int batch_size; int sequence_length; int kv_sequence_length; - AttentionMaskType mask_type; - std::vector key_padding_mask_data; + std::vector query_data; std::vector key_data; std::vector value_data; @@ -29,6 +28,7 @@ struct AttentionTestData { std::vector bias_data; std::vector rel_pos_bias_data; + bool broadcast_rel_pos_bias; std::vector past_key_data; std::vector past_value_data; @@ -42,31 +42,60 @@ struct AttentionTestData { std::vector skip_kernel_types; // skip some kernels if they do not supported this test case. }; -// Disable some tests in Windows since prefast build might crash with large test data. -#ifndef _MSC_VER +struct AttentionTestData : public BaseAttentionTestData { + AttentionMaskType mask_type; + std::vector key_padding_mask_data; +}; + +struct PackedAttentionTestData : public BaseAttentionTestData { + int token_count; + std::vector token_offset; + std::vector cumulative_sequence_length; +}; + // Return packed weights and bias for input projection. void GetAttentionWeight(std::vector& weight_data, int elements = 64 * 3 * 64, int offset = 0, int step = 1); void GetAttentionBias(std::vector& bias_data, int elements = 3 * 64, int offset = 0, int step = 1); void GetCrossAttentionData_HeadSize40(AttentionTestData& data); +void GetCrossAttentionData_HeadSize40_NoBias(AttentionTestData& data); void GetCrossAttentionData_Batch2_HeadSize32_RightSidePadding(AttentionTestData& data, bool is_mask_1d); +void GetCrossAttentionData_Batch2_HeadSize32_RightSidePadding_NoBias(AttentionTestData& data, bool is_mask_1d); void GetCrossAttentionData_Batch1_HeadSize32_LeftSidePadding(AttentionTestData& data); +void GetCrossAttentionData_Batch1_HeadSize32_LeftSidePadding_NoBias(AttentionTestData& data); void GetCrossAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedKV(AttentionTestData& data); void GetSelfAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedQKV(AttentionTestData& data); -#endif void GetCrossAttentionData_HeadSize16_8(AttentionTestData& data); +void GetCrossAttentionData_HeadSize16_8_NoBias(AttentionTestData& data); void GetCrossAttentionData_HeadSize16(AttentionTestData& data); +void GetCrossAttentionData_HeadSize16_NoBias(AttentionTestData& data); void GetCrossAttentionDataWithPast(AttentionTestData& data); void GetSelfAttentionData_WithPast_WithRelPosBias_ForT5(AttentionTestData& data); void GetCrossAttentionData_DiffSequenceLengths(AttentionTestData& data); +void GetCrossAttentionData_DiffSequenceLengths_HeadSize8(AttentionTestData& data); +void GetCrossAttentionData_DiffSequenceLengths_HeadSize8_NoBias(AttentionTestData& data); void GetSelfAttentionData_WithPastAndPresent_NoMask_NoRelPosBias(AttentionTestData& data); +void GetSelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias(AttentionTestData& data); +void GetSelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias_NoBias(AttentionTestData& data); void GetCrossAttentionData_WithPastPassedInDirectly_NoMask(AttentionTestData& data); +void GetCausal_EmptyPastState(std::vector& input, std::vector& output, std::vector& present); + void GetAttentionDataCutlassRelPosBias(AttentionTestData& data); +void GetAttentionDataWithNeoXRotaryEmbedding(std::vector& input, + std::vector& weights, + std::vector& bias, + std::vector& output); + +void GetPackedMultiHeadAttentionData_Batch2_HeadSize32_NoRelPosBias(PackedAttentionTestData& data); + +void GetPackedMultiHeadAttentionData_Batch2_HeadSize8_RelPosBias(PackedAttentionTestData& data); + +void GetPackedMultiHeadAttentionData_Batch2_HeadSize8_BroadcastRelPosBias(PackedAttentionTestData& data); bool SkipAttentionKernel(AttentionTestData& data, AttentionKernelType kernel_type); } // namespace test diff --git a/onnxruntime/test/contrib_ops/beam_search_test.cc b/onnxruntime/test/contrib_ops/beam_search_test.cc index 437a540390e34..156ed3799fc22 100644 --- a/onnxruntime/test/contrib_ops/beam_search_test.cc +++ b/onnxruntime/test/contrib_ops/beam_search_test.cc @@ -73,6 +73,11 @@ TEST(BeamSearchTest, GptBeamSearchFp32) { Ort::ThrowOnError(OrtSessionOptionsAppendExecutionProvider_CUDA(session_options, 0)); #endif +#ifdef USE_ROCM + OrtROCMProviderOptions rocm_options; + session_options.AppendExecutionProvider_ROCM(rocm_options); +#endif + // The ONNX model is generated like the following: // python convert_generation.py --model_type gpt2 -m hf-internal-testing/tiny-random-gpt2 // --output tiny_gpt2_beamsearch_fp16.onnx --use_gpu --max_length 20 @@ -151,12 +156,19 @@ TEST(BeamSearchTest, GptBeamSearchFp16) { const char* const output_names[] = {"sequences"}; constexpr int min_cuda_architecture = 530; - if (HasCudaEnvironment(min_cuda_architecture)) { + bool enable_cuda = HasCudaEnvironment(min_cuda_architecture); + bool enable_rocm = (nullptr != DefaultRocmExecutionProvider().get()); + if (enable_cuda || enable_rocm) { Ort::SessionOptions session_options; #ifdef USE_CUDA Ort::ThrowOnError(OrtSessionOptionsAppendExecutionProvider_CUDA(session_options, 0)); #endif +#ifdef USE_ROCM + OrtROCMProviderOptions rocm_options; + session_options.AppendExecutionProvider_ROCM(rocm_options); +#endif + // The ONNX model is generated like the following: // python convert_generation.py --model_type gpt2 -m hf-internal-testing/tiny-random-gpt2 // --output tiny_gpt2_beamsearch_fp16.onnx -p fp16 --use_gpu --max_length 20 @@ -237,12 +249,19 @@ TEST(BeamSearchTest, GptBeamSearchWithInitDecoderFp16) { const char* const output_names[] = {"sequences"}; constexpr int min_cuda_architecture = 530; - if (HasCudaEnvironment(min_cuda_architecture)) { + bool enable_cuda = HasCudaEnvironment(min_cuda_architecture); + bool enable_rocm = (nullptr != DefaultRocmExecutionProvider().get()); + if (enable_cuda || enable_rocm) { Ort::SessionOptions session_options; #ifdef USE_CUDA Ort::ThrowOnError(OrtSessionOptionsAppendExecutionProvider_CUDA(session_options, 0)); #endif +#ifdef USE_ROCM + OrtROCMProviderOptions rocm_options; + session_options.AppendExecutionProvider_ROCM(rocm_options); +#endif + // The ONNX model is generated like the following: // python convert_generation.py --model_type gpt2 -m hf-internal-testing/tiny-random-gpt2 // --output tiny_gpt2_beamsearch_with_init_decoder_fp16.onnx -p fp16 --use_gpu --max_length 20 @@ -322,12 +341,19 @@ TEST(BeamSearchTest, GptBeamSearchFp16_VocabPadded) { const char* const output_names[] = {"sequences"}; constexpr int min_cuda_architecture = 530; - if (HasCudaEnvironment(min_cuda_architecture)) { + bool enable_cuda = HasCudaEnvironment(min_cuda_architecture); + bool enable_rocm = (nullptr != DefaultRocmExecutionProvider().get()); + if (enable_cuda || enable_rocm) { Ort::SessionOptions session_options; #ifdef USE_CUDA Ort::ThrowOnError(OrtSessionOptionsAppendExecutionProvider_CUDA(session_options, 0)); #endif +#ifdef USE_ROCM + OrtROCMProviderOptions rocm_options; + session_options.AppendExecutionProvider_ROCM(rocm_options); +#endif + // The following model was obtained by padding the vocabulary size in testdata/transformers/tiny_gpt2_beamsearch_fp16.onnx // from 1000 to 1600 (just for illustrative and testing purposes) to see if the beam search implementation can handle // such a scenario @@ -349,5 +375,6 @@ TEST(BeamSearchTest, GptBeamSearchFp16_VocabPadded) { ASSERT_TRUE(std::equal(expected_output.cbegin(), expected_output.cend(), result_span.begin(), result_span.end())); } } + } // namespace test } // namespace onnxruntime diff --git a/onnxruntime/test/contrib_ops/bias_dropout_op_test.cc b/onnxruntime/test/contrib_ops/bias_dropout_op_test.cc index f2e5b493ad4b5..f700e31003012 100644 --- a/onnxruntime/test/contrib_ops/bias_dropout_op_test.cc +++ b/onnxruntime/test/contrib_ops/bias_dropout_op_test.cc @@ -109,8 +109,8 @@ void RunBiasDropoutTest(const bool use_mask, const std::vector& input_s ratio = 0.5f; } else { if (use_float16_ratio) { - t.AddInput("ratio", {}, {MLFloat16(math::floatToHalf(ratio))}); - t_bitmask.AddInput("ratio", {}, {MLFloat16(math::floatToHalf(ratio))}); + t.AddInput("ratio", {}, {MLFloat16(ratio)}); + t_bitmask.AddInput("ratio", {}, {MLFloat16(ratio)}); } else { t.AddInput("ratio", {}, {ratio}); t_bitmask.AddInput("ratio", {}, {ratio}); @@ -139,7 +139,7 @@ void RunBiasDropoutTest(const bool use_mask, const std::vector& input_s auto output_verifier = [&](const std::vector& fetches, const std::string& provider_type) { ASSERT_GE(fetches.size(), 1u); - const auto& output_tensor = FetchTensor(fetches[0]); + const auto& output_tensor = fetches[0].Get(); auto output_span = output_tensor.DataAsSpan(); const auto num_dropped_values = std::count(output_span.begin(), output_span.end(), residual_value); @@ -162,7 +162,7 @@ void RunBiasDropoutTest(const bool use_mask, const std::vector& input_s if (use_mask) { ASSERT_GE(fetches.size(), 2u); - const auto& mask_tensor = FetchTensor(fetches[1]); + const auto& mask_tensor = fetches[1].Get(); auto mask_span = mask_tensor.DataAsSpan(); ASSERT_EQ(mask_span.size(), output_span.size()) << "provider: " << provider_type; @@ -189,11 +189,11 @@ void RunBiasDropoutTest(const bool use_mask, const std::vector& input_s std::vector dropout_outputs = t.GetFetches(); ASSERT_GE(dropout_outputs.size(), 1u); - const float* output_values = FetchTensor(dropout_outputs[0]).Data(); + const float* output_values = dropout_outputs[0].Get().Data(); t_bitmask.AddOutput("output", input_shape, output_values, input_size); if (use_mask) { ASSERT_GE(dropout_outputs.size(), 2u); - const bool* mask_values = FetchTensor(dropout_outputs[1]).Data(); + const bool* mask_values = dropout_outputs[1].Get().Data(); std::vector bitmask_values = MasksToBitmasks(input_size, mask_values); t_bitmask.AddOutput("mask", {static_cast(bitmask_values.size())}, bitmask_values); } else { diff --git a/onnxruntime/test/contrib_ops/bias_split_gelu_op_test.cc b/onnxruntime/test/contrib_ops/bias_split_gelu_op_test.cc index 24b07bb8ba4a4..db14eb3da42cd 100644 --- a/onnxruntime/test/contrib_ops/bias_split_gelu_op_test.cc +++ b/onnxruntime/test/contrib_ops/bias_split_gelu_op_test.cc @@ -17,7 +17,7 @@ std::vector ComputeGelu(const std::vector& input_data) { for (size_t i = 0; i < input_data.size(); i++) { float x = input_data[i]; - float y = x * (0.5f * (1.0f + std::erff(x / 1.41421356237f))); + float y = x * (0.5f * (1.0f + std::erff(x / static_cast(M_SQRT2)))); output.push_back(y); } return output; diff --git a/onnxruntime/test/contrib_ops/bitmask_dropout_op_test.cc b/onnxruntime/test/contrib_ops/bitmask_dropout_op_test.cc index 587b16398e99d..7ca4e1004066c 100644 --- a/onnxruntime/test/contrib_ops/bitmask_dropout_op_test.cc +++ b/onnxruntime/test/contrib_ops/bitmask_dropout_op_test.cc @@ -130,8 +130,8 @@ void RunTestForTraining(const std::vector& input_dims) { std::vector dropout_outputs = dropout.GetFetches(); ASSERT_EQ(dropout_outputs.size(), 2u); - const T* output_values = FetchTensor(dropout_outputs[0]).Data(); - const bool* mask_values = FetchTensor(dropout_outputs[1]).Data(); + const T* output_values = dropout_outputs[0].Get().Data(); + const bool* mask_values = dropout_outputs[1].Get().Data(); std::vector bitmask_values = MasksToBitmasks(input_size, mask_values); OpTester bitmask_dropout("BitmaskDropout", 1, kMSDomain); diff --git a/onnxruntime/test/contrib_ops/element_wise_ops_test.cc b/onnxruntime/test/contrib_ops/element_wise_ops_test.cc index d7c0a3f5b9582..15e2449cd230f 100644 --- a/onnxruntime/test/contrib_ops/element_wise_ops_test.cc +++ b/onnxruntime/test/contrib_ops/element_wise_ops_test.cc @@ -85,36 +85,52 @@ const std::vector ComputeGeluWithErf(const std::vector& input_data return output; } -static void RunBiasGeluTest( - const std::vector& input_a_data, - const std::vector& input_b_data, - const std::vector& input_a_dims, - const std::vector& input_b_dims) { - std::vector output_data = ComputeGeluWithErf(Add_Simple(input_a_data, input_b_data)); +static void RunBiasGeluTestFloat( + const std::vector& input_dims, + const std::vector& bias_dims) { + RandomValueGenerator random{2333}; + std::vector input_data = random.Uniform(input_dims, -1.0f, 1.0f); + std::vector bias_data = random.Uniform(bias_dims, -1.0f, 1.0f); + std::vector output_data = ComputeGeluWithErf(Add_Simple(input_data, bias_data)); OpTester tester("BiasGelu", 1, onnxruntime::kMSDomain); - - const std::vector& output_dims = input_a_dims.size() >= input_b_dims.size() ? input_a_dims : input_b_dims; - tester.AddInput("A", input_a_dims, input_a_data); - tester.AddInput("B", input_b_dims, input_b_data); - tester.AddOutput("C", output_dims, output_data); - + tester.AddInput("A", input_dims, input_data); + tester.AddInput("B", bias_dims, bias_data); + tester.AddOutput("C", input_dims, output_data); tester.Run(); } -TEST(BiasGeluTest, Two_One_Dim) { - std::vector input_a_data = { - 0.8f, -0.5f, 0.0f, 1.f, - 0.5f, 0.2f, 0.3f, -0.6f}; +TEST(BiasGeluTest, Float) { + RunBiasGeluTestFloat({2, 4}, {4}); + RunBiasGeluTestFloat({3, 7}, {7}); + RunBiasGeluTestFloat({2, 4, 512}, {512}); + RunBiasGeluTestFloat({2, 3, 333}, {333}); + RunBiasGeluTestFloat({2, 2048}, {2048}); + RunBiasGeluTestFloat({2, 2333}, {2333}); +} - std::vector input_b_data = { - -0.5f, 0.6f, 1.2f, 2.1f}; +#if defined(USE_CUDA) || defined(USE_ROCM) || defined(USE_DML) +static void RunBiasGeluTestHalf(const std::vector& input_dims, const std::vector& bias_dims) { + RandomValueGenerator random{2333}; + std::vector input_data = random.Uniform(input_dims, -1.0f, 1.0f); + std::vector bias_data = random.Uniform(bias_dims, -1.0f, 1.0f); + std::vector output_data = ComputeGeluWithErf(Add_Simple(input_data, bias_data)); + std::vector input_data_half(input_data.size()); + std::vector bias_data_half(bias_data.size()); + std::vector output_data_half(output_data.size()); + ConvertFloatToMLFloat16(input_data.data(), input_data_half.data(), input_data.size()); + ConvertFloatToMLFloat16(bias_data.data(), bias_data_half.data(), bias_data.size()); + ConvertFloatToMLFloat16(output_data.data(), output_data_half.data(), output_data.size()); - RunBiasGeluTest(input_a_data, input_b_data, {2, 4}, {4}); + OpTester tester("BiasGelu", 1, onnxruntime::kMSDomain); + tester.AddInput("A", input_dims, input_data_half); + tester.AddInput("B", bias_dims, bias_data_half); + tester.AddOutput("C", input_dims, output_data_half); + tester.Run(OpTester::ExpectResult::kExpectSuccess, "", + {kTensorrtExecutionProvider}); // TensorRT: fp16 is not supported } -#if defined(USE_CUDA) || defined(USE_ROCM) || defined(USE_DML) -TEST(BiasGeluTest, Two_One_Dim_fp16) { +TEST(BiasGeluTest, MLFloat16) { #ifdef USE_CUDA int min_cuda_architecture = 530; if (!HasCudaEnvironment(min_cuda_architecture)) { @@ -122,33 +138,43 @@ TEST(BiasGeluTest, Two_One_Dim_fp16) { return; } #endif - OpTester tester("BiasGelu", 1, onnxruntime::kMSDomain); - - std::vector A = { - 0.8f, -0.5f, 0.0f, 1.f, - 0.5f, 0.2f, 0.3f, -0.6f}; - - std::vector B = { - -0.5f, 0.6f, 1.2f, 2.1f}; - - std::vector Y = ComputeGeluWithErf(Add_Simple(A, B)); - - std::vector f_A(8); - std::vector f_B(4); - std::vector f_Y(8); - ConvertFloatToMLFloat16(A.data(), f_A.data(), 8); - ConvertFloatToMLFloat16(B.data(), f_B.data(), 4); - ConvertFloatToMLFloat16(Y.data(), f_Y.data(), 8); - - tester.AddInput("A", {2, 4}, f_A); - tester.AddInput("B", {4}, f_B); - tester.AddOutput("Y", {2, 4}, f_Y); - tester.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); // TensorRT: fp16 is not supported + RunBiasGeluTestHalf({2, 4}, {4}); + RunBiasGeluTestHalf({3, 7}, {7}); + RunBiasGeluTestHalf({2, 4, 512}, {512}); + RunBiasGeluTestHalf({2, 3, 333}, {333}); + RunBiasGeluTestHalf({2, 2048}, {2048}); + RunBiasGeluTestHalf({2, 2333}, {2333}); } #endif #if defined(USE_CUDA) || defined(USE_ROCM) || defined(USE_DNNL) -TEST(BiasGeluTest, Two_One_Dim_bfloat16) { +static void RunBiasGeluTestBFloat16(const std::vector& input_dims, const std::vector& bias_dims) { + RandomValueGenerator random{2333}; + std::vector input_data = random.Uniform(input_dims, 0.5f, 1.5f); + std::vector bias_data = random.Uniform(bias_dims, 0.5f, 1.5f); + std::vector output_data = ComputeGeluWithErf(Add_Simple(input_data, bias_data)); + std::vector input_data_bf16 = FloatsToBFloat16s(input_data); + std::vector bias_data_bf16 = FloatsToBFloat16s(bias_data); + std::vector output_data_bf16 = FloatsToBFloat16s(output_data); + + OpTester tester("BiasGelu", 1, onnxruntime::kMSDomain); + tester.AddInput("A", input_dims, input_data_bf16); + tester.AddInput("B", bias_dims, bias_data_bf16); + tester.AddOutput("C", input_dims, output_data_bf16); + std::vector> execution_providers; +#ifdef USE_CUDA + execution_providers.push_back(DefaultCudaExecutionProvider()); +#elif USE_ROCM + execution_providers.push_back(DefaultRocmExecutionProvider()); +#elif USE_DNNL + execution_providers.push_back(DefaultDnnlExecutionProvider()); +#elif USE_DML + execution_providers.push_back(DefaultDmlExecutionProvider()); +#endif + tester.Run(OpTester::ExpectResult::kExpectSuccess, "", {}, nullptr, &execution_providers); +} + +TEST(BiasGeluTest, BFloat16) { #ifdef USE_CUDA int min_cuda_architecture = 530; if (!HasCudaEnvironment(min_cuda_architecture)) { @@ -162,35 +188,12 @@ TEST(BiasGeluTest, Two_One_Dim_bfloat16) { return; } #endif - OpTester tester("BiasGelu", 1, onnxruntime::kMSDomain); - - std::vector A = { - 0.8f, -0.5f, 0.0f, 1.f, - 0.5f, 0.2f, 0.3f, -0.6f}; - - std::vector B = { - -0.5f, 0.6f, 1.2f, 2.1f}; - - std::vector Y = ComputeGeluWithErf(Add_Simple(A, B)); - - std::vector f_A = FloatsToBFloat16s(A); - std::vector f_B = FloatsToBFloat16s(B); - std::vector f_Y = FloatsToBFloat16s(Y); - - tester.AddInput("A", {2, 4}, f_A); - tester.AddInput("B", {4}, f_B); - tester.AddOutput("Y", {2, 4}, f_Y); - std::vector> execution_providers; -#ifdef USE_CUDA - execution_providers.push_back(DefaultCudaExecutionProvider()); -#elif USE_ROCM - execution_providers.push_back(DefaultRocmExecutionProvider()); -#elif USE_DNNL - execution_providers.push_back(DefaultDnnlExecutionProvider()); -#elif USE_DML - execution_providers.push_back(DefaultDmlExecutionProvider()); -#endif - tester.Run(OpTester::ExpectResult::kExpectSuccess, "", {}, nullptr, &execution_providers); + RunBiasGeluTestBFloat16({2, 4}, {4}); + RunBiasGeluTestBFloat16({3, 7}, {7}); + RunBiasGeluTestBFloat16({2, 4, 512}, {512}); + RunBiasGeluTestBFloat16({2, 3, 333}, {333}); + RunBiasGeluTestBFloat16({2, 2048}, {2048}); + RunBiasGeluTestBFloat16({2, 2333}, {2333}); } #endif @@ -250,17 +253,17 @@ TEST(MathOpTest, ComplexMul_fp16) { if (DefaultCudaExecutionProvider() == nullptr) return; std::vector input_a_data = { - MLFloat16(math::floatToHalf(-0.5f)), MLFloat16(math::floatToHalf(0.6f))}; + MLFloat16(-0.5f), MLFloat16(0.6f)}; std::vector input_b_data = { - MLFloat16(math::floatToHalf(0.8f)), MLFloat16(math::floatToHalf(-0.5f)), MLFloat16(math::floatToHalf(0.0f)), MLFloat16(math::floatToHalf(1.f)), - MLFloat16(math::floatToHalf(0.5f)), MLFloat16(math::floatToHalf(0.2f)), MLFloat16(math::floatToHalf(0.3f)), MLFloat16(math::floatToHalf(-0.6f))}; + MLFloat16(0.8f), MLFloat16(-0.5f), MLFloat16(0.0f), MLFloat16(1.f), + MLFloat16(0.5f), MLFloat16(0.2f), MLFloat16(0.3f), MLFloat16(-0.6f)}; std::vector output_data = { - MLFloat16(math::floatToHalf(-0.10f)), MLFloat16(math::floatToHalf(0.73f)), - MLFloat16(math::floatToHalf(-0.60f)), MLFloat16(math::floatToHalf(-0.50f)), - MLFloat16(math::floatToHalf(-0.37f)), MLFloat16(math::floatToHalf(0.20f)), - MLFloat16(math::floatToHalf(0.21f)), MLFloat16(math::floatToHalf(0.48f))}; + MLFloat16(-0.10f), MLFloat16(0.73f), + MLFloat16(-0.60f), MLFloat16(-0.50f), + MLFloat16(-0.37f), MLFloat16(0.20f), + MLFloat16(0.21f), MLFloat16(0.48f)}; OpTester tester("ComplexMul", 1, onnxruntime::kMSDomain); tester.AddInput("A", {1, 2}, input_a_data); @@ -276,17 +279,17 @@ TEST(MathOpTest, ComplexMulConj_fp16) { if (DefaultCudaExecutionProvider() == nullptr) return; std::vector input_a_data = { - MLFloat16(math::floatToHalf(-0.5f)), MLFloat16(math::floatToHalf(0.6f))}; + MLFloat16(-0.5f), MLFloat16(0.6f)}; std::vector input_b_data = { - MLFloat16(math::floatToHalf(0.8f)), MLFloat16(math::floatToHalf(-0.5f)), MLFloat16(math::floatToHalf(0.0f)), MLFloat16(math::floatToHalf(1.f)), - MLFloat16(math::floatToHalf(0.5f)), MLFloat16(math::floatToHalf(0.2f)), MLFloat16(math::floatToHalf(0.3f)), MLFloat16(math::floatToHalf(-0.6f))}; + MLFloat16(0.8f), MLFloat16(-0.5f), MLFloat16(0.0f), MLFloat16(1.f), + MLFloat16(0.5f), MLFloat16(0.2f), MLFloat16(0.3f), MLFloat16(-0.6f)}; std::vector output_data = { - MLFloat16(math::floatToHalf(-0.70f)), MLFloat16(math::floatToHalf(0.23f)), - MLFloat16(math::floatToHalf(0.60f)), MLFloat16(math::floatToHalf(0.50f)), - MLFloat16(math::floatToHalf(-0.13f)), MLFloat16(math::floatToHalf(0.40f)), - MLFloat16(math::floatToHalf(-0.51f)), MLFloat16(math::floatToHalf(-0.12f))}; + MLFloat16(-0.70f), MLFloat16(0.23f), + MLFloat16(0.60f), MLFloat16(0.50f), + MLFloat16(-0.13f), MLFloat16(0.40f), + MLFloat16(-0.51f), MLFloat16(-0.12f)}; OpTester tester("ComplexMulConj", 1, onnxruntime::kMSDomain); tester.AddInput("A", {1, 2}, input_a_data); diff --git a/onnxruntime/test/contrib_ops/embed_layer_norm_op_test.cc b/onnxruntime/test/contrib_ops/embed_layer_norm_op_test.cc index 884f4422d5d8b..0f35a7ff4b36f 100644 --- a/onnxruntime/test/contrib_ops/embed_layer_norm_op_test.cc +++ b/onnxruntime/test/contrib_ops/embed_layer_norm_op_test.cc @@ -93,7 +93,7 @@ static void RunTest(const embedlayernorm::OpData& data, ToFloat16(data.beta_data), /*is_initializer=*/true); tester.AddAttribute("epsilon", data.epsilon); - if (data.has_mask) { + if (data.has_mask && data.mask_data.size()) { tester.AddInput("mask", mask_dims, data.mask_data); } tester.AddOutput("output", output_dims, ToFloat16(data.output_data)); @@ -117,12 +117,17 @@ static void RunTest(const embedlayernorm::OpData& data, tester.AddInput("gamma", gamma_dims, data.gamma_data, /*is_initializer=*/true); tester.AddInput("beta", beta_dims, data.beta_data, /*is_initializer=*/true); tester.AddAttribute("epsilon", data.epsilon); - if (data.has_mask) { + if (data.has_mask && data.mask_data.size()) { tester.AddInput("mask", mask_dims, data.mask_data); } tester.AddOutput("output", output_dims, data.output_data); } - tester.AddOutput("mask_index", mask_index_dims, data.mask_index_data); + tester.AddAttribute("mask_index_type", static_cast(data.mask_index_type)); + if (data.mask_index_data.size()) { + tester.AddOutput("mask_index", mask_index_dims, data.mask_index_data); + } else { + tester.AddOptionalOutputEdge(); + } if (sum_output) { std::vector embedding_sum_output_dims = output_dims; if (use_float16) { @@ -188,6 +193,13 @@ TEST(EmbedLayerNormTest, EmbedLayerNormBatch1_EmbeddingSum) { TEST(EmbedLayerNormTest, EmbedLayerNormBatch1_EmbeddingSum_Float16) { RunTest(embedlayernorm::EmbedLayerNormBatch1_EmbeddingSum(), true, true); } + +TEST(EmbedLayerNormTest, EmbedLayerNormBatch1_EmbeddingSum_NoMaskIndex) { + RunTest(embedlayernorm::EmbedLayerNormBatch1_EmbeddingSum_NoMaskIndex(), + /* use_float16 = */ false, + /* sum_output = */ true); +} + TEST(EmbedLayerNormTest, EmbedLayerNormBatch2) { RunTest(embedlayernorm::EmbedLayerNormBatch2()); } diff --git a/onnxruntime/test/contrib_ops/embed_layer_norm_test_vectors.h b/onnxruntime/test/contrib_ops/embed_layer_norm_test_vectors.h index 67f9c90c07f71..ceb16c21ad83a 100644 --- a/onnxruntime/test/contrib_ops/embed_layer_norm_test_vectors.h +++ b/onnxruntime/test/contrib_ops/embed_layer_norm_test_vectors.h @@ -31,11 +31,12 @@ class OpData { const std::vector& output_data, const std::vector& mask_index_data, float epsilon = kEpsilon, + int mask_index_type = 1, bool has_mask = true, bool has_segment = true, const std::vector& embedding_sum_data = {}, const std::vector& position_ids_data = {}) - : batch_size(batch_size), sequence_size(sequence_size), hidden_size(hidden_size), input_ids_data(input_ids_data), segment_ids_data(segment_ids_data), mask_data(mask_data), word_embedding_data(word_embedding_data), position_embedding_data(position_embedding_data), segment_embedding_data(segment_embedding_data), gamma_data(gamma_data), beta_data(beta_data), output_data(output_data), mask_index_data(mask_index_data), epsilon(epsilon), has_mask(has_mask), has_segment(has_segment), embedding_sum_data(embedding_sum_data), position_ids_data(position_ids_data) {} + : batch_size(batch_size), sequence_size(sequence_size), hidden_size(hidden_size), input_ids_data(input_ids_data), segment_ids_data(segment_ids_data), mask_data(mask_data), word_embedding_data(word_embedding_data), position_embedding_data(position_embedding_data), segment_embedding_data(segment_embedding_data), gamma_data(gamma_data), beta_data(beta_data), output_data(output_data), mask_index_data(mask_index_data), epsilon(epsilon), mask_index_type(mask_index_type), has_mask(has_mask), has_segment(has_segment), embedding_sum_data(embedding_sum_data), position_ids_data(position_ids_data) {} const int batch_size; const int sequence_size; @@ -51,6 +52,7 @@ class OpData { const std::vector output_data; const std::vector mask_index_data; const float epsilon; + const int mask_index_type; const bool has_mask = true; const bool has_segment = true; const std::vector embedding_sum_data; @@ -110,6 +112,7 @@ inline OpData EmbedLayerNormBatch2(bool has_mask = true) { int batch_size = 3; int sequence_size = 2; int hidden_size = 4; + int mask_index_type = 1; std::vector input_ids_data = { 1, 3, @@ -169,7 +172,7 @@ inline OpData EmbedLayerNormBatch2(bool has_mask = true) { return OpData(batch_size, sequence_size, hidden_size, input_ids_data, segment_ids_data, mask_data, word_embedding_data, position_embedding_data, segment_embedding_data, - gamma_data, beta_data, output_data, mask_index_data, kEpsilon, has_mask); + gamma_data, beta_data, output_data, mask_index_data, kEpsilon, mask_index_type, has_mask); } inline OpData EmbedLayerNormLargeBatchSmallHiddenSize() { @@ -245,6 +248,7 @@ inline OpData EmbedLayerNormBatch_Distill() { int batch_size = 3; int sequence_size = 2; int hidden_size = 4; + int mask_index_type = 1; std::vector input_ids_data = { 1, 3, @@ -292,7 +296,7 @@ inline OpData EmbedLayerNormBatch_Distill() { return OpData(batch_size, sequence_size, hidden_size, input_ids_data, segment_ids_data, mask_data, word_embedding_data, position_embedding_data, segment_embedding_data, - gamma_data, beta_data, output_data, mask_index_data, kEpsilon, + gamma_data, beta_data, output_data, mask_index_data, kEpsilon, mask_index_type, /*has_mask=*/true, /*has_segment=*/false); } @@ -301,6 +305,7 @@ inline OpData EmbedLayerNormBatch1_PositionIds(bool diff_order = false) { int batch_size = 1; int sequence_size = 2; int hidden_size = 4; + int mask_index_type = 1; std::vector input_ids_data = { 1, 3}; @@ -356,7 +361,7 @@ inline OpData EmbedLayerNormBatch1_PositionIds(bool diff_order = false) { return OpData(batch_size, sequence_size, hidden_size, input_ids_data, segment_ids_data, mask_data, word_embedding_data, position_embedding_data, segment_embedding_data, - gamma_data, beta_data, output_data, mask_index_data, kEpsilon, + gamma_data, beta_data, output_data, mask_index_data, kEpsilon, mask_index_type, /*has_mask=*/true, /*has_segment=*/false, embedding_sum_output_data, @@ -367,6 +372,7 @@ inline OpData EmbedLayerNormBatch3_PositionIds_BroadCast() { int batch_size = 3; int sequence_size = 2; int hidden_size = 4; + int mask_index_type = 1; std::vector input_ids_data = { 1, 3, 1, 3, 1, 3}; @@ -416,7 +422,7 @@ inline OpData EmbedLayerNormBatch3_PositionIds_BroadCast() { return OpData(batch_size, sequence_size, hidden_size, input_ids_data, segment_ids_data, mask_data, word_embedding_data, position_embedding_data, segment_embedding_data, - gamma_data, beta_data, output_data, mask_index_data, kEpsilon, + gamma_data, beta_data, output_data, mask_index_data, kEpsilon, mask_index_type, /*has_mask=*/true, /*has_segment=*/false, embedding_sum_output_data, @@ -427,6 +433,7 @@ inline OpData EmbedLayerNormBatch1_EmbeddingSum() { int batch_size = 1; int sequence_size = 2; int hidden_size = 4; + int mask_index_type = 1; std::vector input_ids_data = { 1, 3}; @@ -470,11 +477,64 @@ inline OpData EmbedLayerNormBatch1_EmbeddingSum() { return OpData(batch_size, sequence_size, hidden_size, input_ids_data, segment_ids_data, mask_data, word_embedding_data, position_embedding_data, segment_embedding_data, - gamma_data, beta_data, output_data, mask_index_data, kEpsilon, + gamma_data, beta_data, output_data, mask_index_data, kEpsilon, mask_index_type, /*has_mask=*/true, /*has_segment=*/false, embedding_sum_data); } + +inline OpData EmbedLayerNormBatch1_EmbeddingSum_NoMaskIndex() { + int batch_size = 1; + int sequence_size = 2; + int hidden_size = 4; + int mask_index_type = 0; + + std::vector input_ids_data = { + 1, 3}; + + std::vector segment_ids_data = {}; + + std::vector mask_data = {}; + + std::vector word_embedding_data = { + 0.2f, 0.1f, 0.4f, -0.6f, + 0.3f, 0.2f, 0.5f, 0.6f, + 0.6f, 0.7f, 0.0f, -0.1f, + 0.8f, 0.6f, 0.9f, 1.2f, + 0.1f, 0.3f, 0.5f, 0.9f, + 1.0f, -2.0f, 1.1f, 0.8f}; + + std::vector position_embedding_data = { + 0.1f, 0.1f, 0.4f, 0.6f, + 0.6f, 0.0f, 0.8f, 0.6f, + 0.3f, 0.9f, -2.0f, 0.8f}; + + std::vector segment_embedding_data = {}; + + std::vector gamma_data = { + 0.25f, 0.15f, 0.45f, -0.66f}; + + std::vector beta_data = { + 0.6f, 0.2f, 0.5f, -0.6f}; + + std::vector output_data = { + 0.39587587118148804, 0.03670068085193634, 0.7449488639831543, -1.4981462955474854, + 0.61326867341995239, -0.046796366572380066, 0.81048583984375, -1.1954958438873291}; + + std::vector mask_index_data = {}; + + std::vector embedding_sum_data = { + 0.40000000596046448, 0.30000001192092896, 0.89999997615814209, 1.2000000476837158, + 1.4000000953674316, 0.60000002384185791, 1.7000000476837158, 1.8000000715255737}; + + return OpData(batch_size, sequence_size, hidden_size, input_ids_data, segment_ids_data, + mask_data, word_embedding_data, position_embedding_data, segment_embedding_data, + gamma_data, beta_data, output_data, mask_index_data, kEpsilon, mask_index_type, + /*has_mask=*/true, + /*has_segment=*/false, + embedding_sum_data); +} + } // namespace embedlayernorm } // namespace test } // namespace onnxruntime diff --git a/onnxruntime/test/contrib_ops/fft_op_test.cc b/onnxruntime/test/contrib_ops/fft_op_test.cc index c259cbaf25ca3..eaadb95c8a0c0 100644 --- a/onnxruntime/test/contrib_ops/fft_op_test.cc +++ b/onnxruntime/test/contrib_ops/fft_op_test.cc @@ -11,11 +11,12 @@ TEST(ContribOpTest, Rfft) { if (DefaultCudaExecutionProvider() == nullptr) return; OpTester test("Rfft", 1, onnxruntime::kMSDomain); - test.AddAttribute("signal_ndim", static_cast(2)); + test.AddAttribute("signal_ndim", static_cast(1)); test.AddAttribute("onesided", static_cast(1)); test.AddAttribute("normalized", static_cast(0)); - test.AddInput("X", {4, 5}, std::vector{-0.8992f, 0.6117f, -1.6091f, -0.4155f, -0.8346f, -2.1596f, -0.0853f, 0.7232f, 0.1941f, -0.0789f, -2.0329f, 1.1031f, 0.6869f, -0.5042f, 0.9895f, -0.1884f, 0.2858f, -1.5831f, 0.9917f, -0.8356f}); - test.AddOutput("Y", {4, 3, 2}, std::vector{-5.6404f, 0.0000f, -3.6965f, -1.3401f, -6.6836f, -3.5202f, -3.3891f, 0.0769f, 1.4521f, 3.2068f, 5.9398f, -1.2344f, -0.1682f, 0.0000f, 1.9681f, -1.6241f, -3.3442f, 1.6817f, -3.3891f, -0.0769f, 2.9557f, -2.9384f, -1.2900f, -4.8683f}); + // Target values conputed using PyTorch torch.fft.rfft(X, dim=-1, norm="backward") + test.AddInput("X", {4, 4}, {0.8129f, 1.3108f, -0.8790f, -1.2046f, 0.1661f, -0.9831f, 0.5879f, 0.4918f, 1.2506f, 0.7244f, -2.6260f, -1.1268f, -1.6885f, 1.0439f, -0.2595f, 1.8780f}); + test.AddOutput("Y", {4, 3, 2}, {0.0400f, 0.0000f, 1.6919f, -2.5154f, -0.1722f, 0.0000f, 0.2627f, 0.0000f, -0.4218f, 1.4748f, 1.2454f, 0.0000f, -1.7779f, 0.0000f, 3.8766f, -1.8512f, -0.9730f, 0.0000f, 0.9740f, 0.0000f, -1.4290f, 0.8341f, -4.8699f, 0.0000f}); std::vector> execution_providers; execution_providers.push_back(DefaultCudaExecutionProvider()); test.Run(OpTester::ExpectResult::kExpectSuccess, "", {}, nullptr, &execution_providers); @@ -25,11 +26,11 @@ TEST(ContribOpTest, Irfft) { if (DefaultCudaExecutionProvider() == nullptr) return; OpTester test("Irfft", 1, onnxruntime::kMSDomain); - test.AddAttribute("signal_ndim", static_cast(2)); + test.AddAttribute("signal_ndim", static_cast(1)); test.AddAttribute("onesided", static_cast(1)); test.AddAttribute("normalized", static_cast(0)); - test.AddInput("X", {4, 3, 2}, std::vector{-5.6404f, 0.0000f, -3.6965f, -1.3401f, -6.6836f, -3.5202f, -3.3891f, 0.0769f, 1.4521f, 3.2068f, 5.9398f, -1.2344f, -0.1682f, 0.0000f, 1.9681f, -1.6241f, -3.3442f, 1.6817f, -3.3891f, -0.0769f, 2.9557f, -2.9384f, -1.2900f, -4.8683f}); - test.AddOutput("Y", {4, 5}, std::vector{-0.8992f, 0.6117f, -1.6091f, -0.4155f, -0.8346f, -2.1596f, -0.0853f, 0.7232f, 0.1941f, -0.0789f, -2.0329f, 1.1031f, 0.6869f, -0.5042f, 0.9895f, -0.1884f, 0.2858f, -1.5831f, 0.9917f, -0.8356f}); + test.AddInput("X", {4, 3, 2}, {0.0400f, 0.0000f, 1.6919f, -2.5154f, -0.1722f, 0.0000f, 0.2627f, 0.0000f, -0.4218f, 1.4748f, 1.2454f, 0.0000f, -1.7779f, 0.0000f, 3.8766f, -1.8512f, -0.9730f, 0.0000f, 0.9740f, 0.0000f, -1.4290f, 0.8341f, -4.8699f, 0.0000f}); + test.AddOutput("Y", {4, 4}, {0.8129f, 1.3108f, -0.8790f, -1.2046f, 0.1661f, -0.9831f, 0.5879f, 0.4918f, 1.2506f, 0.7244f, -2.6260f, -1.1268f, -1.6885f, 1.0439f, -0.2595f, 1.8780f}); std::vector> execution_providers; execution_providers.push_back(DefaultCudaExecutionProvider()); test.Run(OpTester::ExpectResult::kExpectSuccess, "", {}, nullptr, &execution_providers); diff --git a/onnxruntime/test/contrib_ops/function_test_util.h b/onnxruntime/test/contrib_ops/function_test_util.h index 9af8ef596aa84..b23288fdfdc29 100644 --- a/onnxruntime/test/contrib_ops/function_test_util.h +++ b/onnxruntime/test/contrib_ops/function_test_util.h @@ -90,7 +90,7 @@ struct FunctionTestCase { input_args.emplace_back(input_name, &arg_type); OrtValue ort_value; - CreateMLValue(provider->GetAllocator(OrtMemTypeDefault), shape, data, &ort_value); + CreateMLValue(provider->CreatePreferredAllocators()[0], shape, data, &ort_value); input_values.push_back(std::make_pair(input_name, ort_value)); input_value_map.insert(std::make_pair(input_name, ort_value)); } @@ -107,7 +107,7 @@ struct FunctionTestCase { if (GenData) { std::vector data = random(shape); OrtValue ort_value; - CreateMLValue(provider->GetAllocator(OrtMemTypeDefault), shape, data, &ort_value); + CreateMLValue(provider->CreatePreferredAllocators()[0], shape, data, &ort_value); input_values.push_back(std::make_pair(input_name, ort_value)); input_value_map.insert(std::make_pair(input_name, ort_value)); } @@ -121,7 +121,7 @@ struct FunctionTestCase { for (size_t i = 0; i < data.size(); i++) data[i] = data[i] % bound; OrtValue ort_value; - CreateMLValue(provider->GetAllocator(OrtMemTypeDefault), shape, data, &ort_value); + CreateMLValue(provider->CreatePreferredAllocators()[0], shape, data, &ort_value); input_values.push_back(std::make_pair(input_name, ort_value)); input_value_map.insert(std::make_pair(input_name, ort_value)); } diff --git a/onnxruntime/test/contrib_ops/gridsample_test.cc b/onnxruntime/test/contrib_ops/gridsample_test.cc index 8d779785323e0..1f31c2bd21f14 100644 --- a/onnxruntime/test/contrib_ops/gridsample_test.cc +++ b/onnxruntime/test/contrib_ops/gridsample_test.cc @@ -71,7 +71,7 @@ TEST(GridsampleContribOpTest, gridsample_paddingmode_reflection) { 5.0000f, 5.0000f, 10.0000f, 10.0000f}); test.AddAttribute("padding_mode", "reflection"); test.AddOutput("Y", {1, 1, 2, 4}, {2.5000f, 0.0000f, 1.7000f, 2.5000f, 2.5000f, 1.7000f, 5.0000f, 2.5000f}); - test.Run(); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kQnnExecutionProvider}); // Accuracy issue for QNN } TEST(GridsampleContribOpTest, gridsample_aligncorners_true) { diff --git a/onnxruntime/test/contrib_ops/group_norm_op_test.cc b/onnxruntime/test/contrib_ops/group_norm_op_test.cc index f0c6488a35d57..4983cb5abf10c 100644 --- a/onnxruntime/test/contrib_ops/group_norm_op_test.cc +++ b/onnxruntime/test/contrib_ops/group_norm_op_test.cc @@ -21,8 +21,8 @@ TEST(GroupNormTest, GroupNorm_128) { constexpr int64_t H = 2; constexpr int64_t W = 2; - std::vector dims{B, H, W, C}; - std::vector input_data = { + std::vector dims_nhwc{B, H, W, C}; + std::vector input_data_nhwc = { 0.696469f, 0.719469f, 0.480932f, 0.438572f, 0.182492f, 0.634401f, 0.722443f, 0.293714f, 0.430863f, 0.426351f, 0.623953f, 0.866309f, 0.519485f, 0.603060f, 0.417022f, 0.669314f, 0.842342f, 0.194223f, 0.627249f, 0.556785f, 0.318766f, 0.925132f, 0.304768f, 0.355915f, 0.151127f, 0.513128f, 0.321981f, 0.854452f, 0.171082f, 0.578551f, @@ -127,6 +127,112 @@ TEST(GroupNormTest, GroupNorm_128) { 0.623269f, 0.016948f, 0.826530f, 0.308751f, 0.290656f, 0.058387f, 0.264397f, 0.294895f, 0.639992f, 0.489059f, 0.343698f, 0.929770f, 0.390125f, 0.397707f}; + std::vector dims_nchw{B, C, H, W}; + std::vector input_data_nchw = { + 0.696469f, 0.286139f, 0.226851f, 0.551315f, 0.719469f, 0.423106f, 0.980764f, 0.684830f, 0.480932f, 0.392118f, + 0.343178f, 0.729050f, 0.438572f, 0.059678f, 0.398044f, 0.737995f, 0.182492f, 0.175452f, 0.531551f, 0.531828f, + 0.634401f, 0.849432f, 0.724455f, 0.611024f, 0.722443f, 0.322959f, 0.361789f, 0.228263f, 0.293714f, 0.630976f, + 0.092105f, 0.433701f, 0.430863f, 0.493685f, 0.425830f, 0.312261f, 0.426351f, 0.893389f, 0.944160f, 0.501837f, + 0.623953f, 0.115618f, 0.317285f, 0.414826f, 0.866309f, 0.250455f, 0.483034f, 0.985560f, 0.519485f, 0.612895f, + 0.120629f, 0.826341f, 0.603060f, 0.545068f, 0.342764f, 0.304121f, 0.417022f, 0.681301f, 0.875457f, 0.510422f, + 0.669314f, 0.585937f, 0.624904f, 0.674689f, 0.842342f, 0.083195f, 0.763683f, 0.243666f, 0.194223f, 0.572457f, + 0.095713f, 0.885327f, 0.627249f, 0.723416f, 0.016129f, 0.594432f, 0.556785f, 0.158960f, 0.153071f, 0.695530f, + 0.318766f, 0.691970f, 0.554383f, 0.388951f, 0.925132f, 0.841670f, 0.357398f, 0.043591f, 0.304768f, 0.398186f, + 0.704959f, 0.995358f, 0.355915f, 0.762548f, 0.593177f, 0.691702f, 0.151127f, 0.398876f, 0.240856f, 0.343456f, + 0.513128f, 0.666625f, 0.105908f, 0.130895f, 0.321981f, 0.661564f, 0.846506f, 0.553257f, 0.854452f, 0.384838f, + 0.316788f, 0.354265f, 0.171082f, 0.829113f, 0.338671f, 0.552370f, 0.578551f, 0.521533f, 0.002688f, 0.988345f, + 0.905342f, 0.207636f, 0.292489f, 0.520010f, 0.901911f, 0.983631f, 0.257542f, 0.564359f, 0.806969f, 0.394370f, + 0.731073f, 0.161069f, 0.600699f, 0.865864f, 0.983522f, 0.079366f, 0.428347f, 0.204543f, 0.450636f, 0.547764f, + 0.093327f, 0.296861f, 0.927584f, 0.569004f, 0.457412f, 0.753526f, 0.741862f, 0.048579f, 0.708697f, 0.839243f, + 0.165938f, 0.780998f, 0.286537f, 0.306470f, 0.665261f, 0.111392f, 0.664872f, 0.887857f, 0.696311f, 0.440328f, + 0.438214f, 0.765096f, 0.565642f, 0.084904f, 0.582671f, 0.814844f, 0.337066f, 0.927577f, 0.750717f, 0.574064f, + 0.751644f, 0.079149f, 0.859389f, 0.821504f, 0.909872f, 0.128631f, 0.081780f, 0.138416f, 0.399379f, 0.424307f, + 0.562218f, 0.122244f, 0.201400f, 0.811644f, 0.467988f, 0.807938f, 0.007426f, 0.551593f, 0.931932f, 0.582175f, + 0.206096f, 0.717758f, 0.378986f, 0.668384f, 0.029320f, 0.635900f, 0.032198f, 0.744781f, 0.472913f, 0.121754f, + 0.542636f, 0.066774f, 0.653365f, 0.996086f, 0.769397f, 0.573774f, 0.102635f, 0.699834f, 0.661168f, 0.049097f, + 0.792299f, 0.518717f, 0.425868f, 0.788187f, 0.411569f, 0.481026f, 0.181629f, 0.321319f, 0.845533f, 0.186904f, + 0.417291f, 0.989035f, 0.236600f, 0.916832f, 0.918397f, 0.091296f, 0.463653f, 0.502216f, 0.313669f, 0.047340f, + 0.241686f, 0.095530f, 0.238250f, 0.807791f, 0.894978f, 0.043223f, 0.301947f, 0.980582f, 0.539505f, 0.626309f, + 0.005545f, 0.484909f, 0.988329f, 0.375186f, 0.097038f, 0.461909f, 0.963004f, 0.341831f, 0.798923f, 0.798846f, + 0.208248f, 0.443368f, 0.715601f, 0.410520f, 0.191007f, 0.967494f, 0.650750f, 0.865460f, 0.025242f, 0.266906f, + 0.502071f, 0.067449f, 0.993033f, 0.236462f, 0.374292f, 0.214012f, 0.105446f, 0.232480f, 0.300610f, 0.634442f, + 0.281235f, 0.362277f, 0.005943f, 0.365719f, 0.533886f, 0.162016f, 0.597433f, 0.293152f, 0.632050f, 0.026197f, + 0.887593f, 0.016119f, 0.126958f, 0.777162f, 0.045895f, 0.710999f, 0.971046f, 0.871683f, 0.710162f, 0.958510f, + 0.429813f, 0.872879f, 0.355958f, 0.929764f, 0.148778f, 0.940029f, 0.832716f, 0.846055f, 0.123923f, 0.596487f, + 0.016392f, 0.721184f, 0.007738f, 0.084822f, 0.225498f, 0.875125f, 0.363576f, 0.539960f, 0.568103f, 0.225463f, + 0.572147f, 0.660952f, 0.298245f, 0.418627f, 0.453089f, 0.932351f, 0.587494f, 0.948252f, 0.556035f, 0.500561f, + 0.003532f, 0.480889f, 0.927455f, 0.198366f, 0.052091f, 0.406779f, 0.372396f, 0.857153f, 0.026611f, 0.920149f, + 0.680903f, 0.904226f, 0.607529f, 0.811953f, 0.335544f, 0.349566f, 0.389874f, 0.754797f, 0.369291f, 0.242220f, + 0.937668f, 0.908011f, 0.348797f, 0.634638f, 0.273842f, 0.206115f, 0.336340f, 0.327100f, 0.882276f, 0.822304f, + 0.709623f, 0.959345f, 0.422543f, 0.245033f, 0.117398f, 0.301053f, 0.145264f, 0.092186f, 0.602932f, 0.364187f, + 0.564570f, 0.191336f, 0.676906f, 0.215505f, 0.278024f, 0.741760f, 0.559738f, 0.334836f, 0.542989f, 0.693985f, + 0.912132f, 0.580713f, 0.232686f, 0.746698f, 0.777769f, 0.200401f, 0.820574f, 0.464935f, 0.779767f, 0.237478f, + 0.332580f, 0.953697f, 0.657815f, 0.772878f, 0.688374f, 0.204304f, 0.470689f, 0.808964f, 0.675035f, 0.006028f, + 0.087408f, 0.346795f, 0.944366f, 0.491190f, 0.270176f, 0.360424f, 0.210653f, 0.421200f, 0.218035f, 0.845753f, + 0.456271f, 0.279802f, 0.932892f, 0.314351f, 0.909715f, 0.043418f, 0.707115f, 0.483889f, 0.444221f, 0.036323f, + 0.040683f, 0.332754f, 0.947120f, 0.617660f, 0.368875f, 0.611977f, 0.206132f, 0.165066f, 0.361817f, 0.863353f, + 0.509402f, 0.296902f, 0.950252f, 0.815966f, 0.322974f, 0.972098f, 0.987351f, 0.408660f, 0.655923f, 0.405653f, + 0.257348f, 0.082653f, 0.263610f, 0.271480f, 0.398639f, 0.184886f, 0.953818f, 0.102880f, 0.625209f, 0.441697f, + 0.423518f, 0.371992f, 0.868315f, 0.280477f, 0.020576f, 0.918097f, 0.864480f, 0.276902f, 0.523488f, 0.109088f, + 0.093427f, 0.837466f, 0.410266f, 0.661717f, 0.943201f, 0.245131f, 0.013160f, 0.024148f, 0.709386f, 0.924552f, + 0.467330f, 0.375109f, 0.542860f, 0.858917f, 0.652154f, 0.232980f, 0.774580f, 0.134613f, 0.165560f, 0.612682f, + 0.238783f, 0.704779f, 0.349519f, 0.277424f, 0.998918f, 0.040616f, 0.645823f, 0.038700f, 0.760210f, 0.230090f, + 0.089832f, 0.648450f, 0.732601f, 0.678095f, 0.051901f, 0.294307f, 0.451088f, 0.287103f, 0.810513f, 0.131115f, + 0.612179f, 0.988215f, 0.902557f, 0.222157f, 0.000082f, 0.980597f, 0.882713f, 0.919472f, 0.415504f, 0.744615f, + 0.212831f, 0.392304f, 0.851548f, 0.127612f, 0.893865f, 0.496508f, 0.426096f, 0.305646f, 0.916849f, 0.517623f, + 0.804026f, 0.857652f, 0.922382f, 0.303381f, 0.339811f, 0.595074f, 0.441324f, 0.932843f, 0.397564f, 0.477778f, + 0.617186f, 0.404739f, 0.992478f, 0.098851f, 0.220603f, 0.322655f, 0.147723f, 0.284219f, 0.779245f, 0.522892f, + 0.033954f, 0.982623f, 0.616006f, 0.058939f, 0.661169f, 0.378369f, 0.135673f, 0.563665f, 0.727080f, 0.671127f, + 0.247513f, 0.524866f, 0.537663f, 0.716803f, 0.359867f, 0.797733f, 0.627922f, 0.038332f, 0.546479f, 0.861912f, + 0.567574f, 0.175828f, 0.510376f, 0.756946f, 0.110105f, 0.817099f, 0.167482f, 0.534076f, 0.385743f, 0.248624f, + 0.647433f, 0.037392f, 0.760046f, 0.526941f, 0.875771f, 0.520718f, 0.035033f, 0.143601f, 0.795605f, 0.491976f, + 0.441879f, 0.318435f, 0.284549f, 0.965886f, 0.432969f, 0.884003f, 0.648163f, 0.858428f, 0.852450f, 0.956312f, + 0.697942f, 0.805397f, 0.733128f, 0.605227f, 0.717354f, 0.715750f, 0.040908f, 0.516111f, 0.792651f, 0.242962f, + 0.465148f, 0.434986f, 0.402787f, 0.121840f, 0.525712f, 0.446248f, 0.663393f, 0.549413f, 0.027543f, 0.031918f, + 0.701360f, 0.707581f, 0.959939f, 0.876705f, 0.468060f, 0.625907f, 0.457182f, 0.222946f, 0.376677f, 0.103884f, + 0.666527f, 0.192030f, 0.475468f, 0.967437f, 0.031669f, 0.151730f, 0.298579f, 0.941807f, 0.908842f, 0.162001f, + 0.981118f, 0.750748f, 0.539977f, 0.931703f, 0.880607f, 0.391316f, 0.656343f, 0.647385f, 0.326968f, 0.179390f, + 0.466810f, 0.263281f, 0.355065f, 0.954144f, 0.461138f, 0.684891f, 0.336230f, 0.995861f, 0.658768f, 0.196009f, + 0.098184f, 0.943181f, 0.944778f, 0.621328f, 0.016991f, 0.225535f, 0.801277f, 0.875460f, 0.453990f, 0.365521f, + 0.274225f, 0.116971f, 0.115745f, 0.952603f, 0.808626f, 0.164779f, 0.207050f, 0.655552f, 0.764664f, 0.810315f, + 0.163338f, 0.984128f, 0.227802f, 0.589415f, 0.587616f, 0.967362f, 0.657667f, 0.584904f, 0.518773f, 0.764658f, + 0.106055f, 0.002092f, 0.952489f, 0.498658f, 0.328335f, 0.368053f, 0.803843f, 0.382370f, 0.770169f, 0.440462f, + 0.844077f, 0.076204f, 0.481128f, 0.466850f, 0.264328f, 0.943615f, 0.905028f, 0.443596f, 0.097160f, 0.206783f, + 0.271492f, 0.484220f, 0.338377f, 0.774136f, 0.476027f, 0.870371f, 0.995782f, 0.219836f, 0.611671f, 0.847502f, + 0.945237f, 0.290086f, 0.727043f, 0.015016f, 0.879142f, 0.063939f, 0.733395f, 0.994610f, 0.501190f, 0.209334f, + 0.594644f, 0.624150f, 0.668073f, 0.172612f, 0.898713f, 0.620991f, 0.043569f, 0.684041f, 0.196084f, 0.027341f, + 0.550953f, 0.813314f, 0.859941f, 0.103521f, 0.663043f, 0.710075f, 0.294517f, 0.971364f, 0.278687f, 0.069982f, + 0.519280f, 0.694315f, 0.244660f, 0.338582f, 0.563628f, 0.886678f, 0.747326f, 0.209592f, 0.251777f, 0.523881f, + 0.768959f, 0.618762f, 0.501324f, 0.597125f, 0.756060f, 0.537080f, 0.897753f, 0.947067f, 0.915355f, 0.754518f, + 0.246321f, 0.385271f, 0.280000f, 0.657660f, 0.324222f, 0.754392f, 0.113509f, 0.775365f, 0.585902f, 0.835389f, + 0.430876f, 0.624964f, 0.554412f, 0.975671f, 0.755474f, 0.544813f, 0.174032f, 0.904114f, 0.205838f, 0.650043f, + 0.936472f, 0.223580f, 0.225924f, 0.851819f, 0.827655f, 0.351703f, 0.265096f, 0.127388f, 0.987936f, 0.835343f, + 0.899392f, 0.513679f, 0.114385f, 0.052580f, 0.330582f, 0.920330f, 0.947582f, 0.841164f, 0.158679f, 0.419923f, + 0.246243f, 0.205350f, 0.684826f, 0.486112f, 0.324910f, 0.100214f, 0.544763f, 0.347025f, 0.391096f, 0.310509f, + 0.387195f, 0.555860f, 0.014144f, 0.847647f, 0.921920f, 0.550530f, 0.268021f, 0.990239f, 0.383194f, 0.693655f, + 0.689953f, 0.434309f, 0.199158f, 0.966579f, 0.063691f, 0.485149f, 0.220731f, 0.293974f, 0.828527f, 0.367266f, + 0.083348f, 0.196309f, 0.860373f, 0.977029f, 0.267982f, 0.675409f, 0.081199f, 0.723466f, 0.416437f, 0.918160f, + 0.311536f, 0.941467f, 0.503247f, 0.348893f, 0.647020f, 0.249746f, 0.229764f, 0.196346f, 0.959900f, 0.492914f, + 0.751615f, 0.473992f, 0.587540f, 0.584139f, 0.979886f, 0.668433f, 0.239769f, 0.015198f, 0.218682f, 0.455520f, + 0.393420f, 0.812326f, 0.785557f, 0.089096f, 0.952011f, 0.527457f, 0.596404f, 0.405057f, 0.649501f, 0.871326f, + 0.673936f, 0.970099f, 0.701122f, 0.821721f, 0.045040f, 0.672699f, 0.654753f, 0.101746f, 0.842387f, 0.614172f, + 0.098328f, 0.594467f, 0.478416f, 0.233294f, 0.019756f, 0.365567f, 0.619851f, 0.329279f, 0.307255f, 0.751121f, + 0.758625f, 0.718766f, 0.101182f, 0.516166f, 0.557799f, 0.744805f, 0.903178f, 0.369039f, 0.428663f, 0.732767f, + 0.662636f, 0.557870f, 0.350140f, 0.195352f, 0.183807f, 0.081583f, 0.081201f, 0.845798f, 0.383673f, 0.060740f, + 0.896426f, 0.223270f, 0.268124f, 0.194498f, 0.967501f, 0.112540f, 0.722163f, 0.932089f, 0.668001f, 0.858727f, + 0.242447f, 0.673928f, 0.700871f, 0.458333f, 0.870546f, 0.694386f, 0.894878f, 0.753204f, 0.520290f, 0.498688f, + 0.453728f, 0.021647f, 0.535141f, 0.422973f, 0.157534f, 0.119070f, 0.449352f, 0.039913f, 0.986580f, 0.378121f, + 0.382109f, 0.051126f, 0.426672f, 0.015745f, 0.030094f, 0.339099f, 0.820969f, 0.458821f, 0.014841f, 0.163220f, + 0.739923f, 0.738294f, 0.754523f, 0.351669f, 0.352277f, 0.802076f, 0.398138f, 0.727191f, 0.581123f, 0.364342f, + 0.080007f, 0.116125f, 0.889559f, 0.452341f, 0.994005f, 0.363897f, 0.249954f, 0.350539f, 0.343086f, 0.637357f, + 0.012738f, 0.763269f, 0.416415f, 0.432239f, 0.481115f, 0.449212f, 0.497471f, 0.345904f, 0.453346f, 0.404651f, + 0.518243f, 0.623269f, 0.241041f, 0.508437f, 0.594622f, 0.016948f, 0.520494f, 0.239293f, 0.404539f, 0.826530f, + 0.326236f, 0.483217f, 0.024741f, 0.308751f, 0.639721f, 0.315162f, 0.205798f, 0.290656f, 0.954378f, 0.086802f, + 0.463358f, 0.058387f, 0.538658f, 0.146036f, 0.634085f, 0.264397f, 0.690915f, 0.347146f, 0.004168f, 0.294895f, + 0.081894f, 0.495040f, 0.288890f, 0.639992f, 0.499936f, 0.036045f, 0.318634f, 0.489059f, 0.572204f, 0.104871f, + 0.649971f, 0.343698f, 0.182921f, 0.805327f, 0.068623f, 0.929770f, 0.706266f, 0.475591f, 0.011161f, 0.390125f, + 0.645798f, 0.858913f, 0.617764f, 0.397707f}; + std::vector gamma_data = { 0.447359f, 0.873295f, 0.351357f, 0.065158f, 0.442673f, 0.998459f, 0.379773f, 0.193055f, 0.045130f, 0.170969f, 0.324064f, 0.574278f, 0.665588f, 0.042819f, 0.936180f, 0.235638f, 0.149062f, 0.530829f, 0.677586f, 0.307253f, @@ -157,7 +263,7 @@ TEST(GroupNormTest, GroupNorm_128) { 0.413157f, 0.595286f, 0.133620f, 0.484188f, 0.972134f, 0.427721f, 0.242881f, 0.927507f, 0.610774f, 0.727857f, 0.543405f, 0.011202f, 0.755700f, 0.978697f, 0.716188f, 0.808757f, 0.851587f, 0.999201f}; - std::vector norm_data = { + std::vector norm_data_nhwc = { 0.406306f, 1.632045f, 0.095849f, 0.919355f, -0.458834f, 1.632483f, 0.876482f, 0.729815f, 0.750835f, 0.782631f, 0.590117f, 1.476163f, 0.183714f, 0.057787f, -0.474648f, 0.143954f, 0.561618f, 0.031635f, 0.426744f, 0.118848f, 0.054676f, 0.526575f, -0.827396f, -0.206514f, 0.631899f, 1.033381f, -0.028056f, @@ -273,7 +379,123 @@ TEST(GroupNormTest, GroupNorm_128) { 0.181189f, 0.244843f, 1.995885f, -1.411448f, 1.422581f, 0.658642f, 0.243404f, 0.442854f, 0.230959f, -0.272532f, 0.778544f, 1.461264f, 0.670758f, 2.274148f, 0.642745f, 0.948315f}; - std::vector swish_data = { + std::vector norm_data_nchw = { + 0.406306f, -0.397960f, -0.514167f, 0.121796f, 1.632045f, 0.498094f, 2.631821f, 1.499508f, 0.095849f, + -0.040874f, -0.116213f, 0.477808f, 0.919355f, 0.811189f, 0.907785f, 1.004834f, -0.458834f, -0.472885f, + 0.237840f, 0.238391f, 1.632483f, 2.600490f, 2.037882f, 1.527244f, 0.876482f, 0.192458f, 0.258945f, + 0.030314f, 0.729815f, 1.023374f, 0.554331f, 0.851662f, 0.750835f, 0.762038f, 0.749937f, 0.729685f, + 0.782631f, 1.098150f, 1.132450f, 0.833627f, 0.590117f, -0.060817f, 0.197422f, 0.322326f, 1.476163f, + 0.078648f, 0.606424f, 1.746771f, 0.183714f, 0.518953f, -1.247748f, 1.284994f, 0.057787f, 0.044398f, + -0.002311f, -0.011233f, -0.474648f, 0.859423f, 1.839518f, -0.003167f, 0.143954f, 0.038016f, 0.087527f, + 0.150784f, 0.561618f, 0.176986f, 0.521764f, 0.258291f, 0.031635f, 0.714081f, -0.146106f, 1.278590f, + 0.426744f, 0.648229f, -0.980738f, 0.351162f, 0.118848f, -0.296623f, -0.302773f, 0.263747f, 0.054676f, + 1.040141f, 0.676835f, 0.240001f, 0.526575f, 0.429690f, -0.132461f, -0.496733f, -0.827396f, -0.494966f, + 0.596699f, 1.630098f, -0.206514f, 1.206059f, 0.617694f, 0.959952f, 0.631899f, 0.709146f, 0.659876f, + 0.691867f, 1.033381f, 1.134488f, 0.765150f, 0.781609f, -0.028056f, 1.010104f, 1.575500f, 0.678993f, + 0.117742f, 0.117495f, 0.117460f, 0.117479f, -0.928939f, 0.857719f, -0.473908f, 0.106319f, 0.254703f, + 0.187595f, -0.423069f, 0.737017f, 1.002641f, -0.713799f, -0.505049f, 0.054679f, 0.056505f, 0.068448f, + -0.037672f, 0.007170f, 0.502409f, 0.201653f, 0.447086f, 0.031594f, 0.186869f, 0.252268f, 0.281287f, + 0.058290f, -0.032152f, -0.172338f, -0.018190f, 0.042648f, -0.201724f, 0.070818f, 0.915389f, 0.435231f, + 0.683548f, 1.228964f, 1.207481f, -0.069486f, 0.900928f, 1.349056f, -0.962214f, 1.149115f, 0.126877f, + 0.173722f, 1.016921f, -0.284731f, 1.073324f, 1.663625f, 1.156551f, 0.478892f, -0.017409f, 0.077027f, + 0.019404f, -0.119480f, 0.957481f, 1.191751f, 0.709657f, 1.305503f, 0.710492f, 0.094092f, 0.713726f, + -1.632824f, 1.254686f, 1.179984f, 1.354227f, -0.186219f, -0.620889f, -0.462022f, 0.270004f, 0.339929f, + 0.882544f, 0.831658f, 0.840813f, 0.911391f, 1.003820f, 1.105588f, 0.865947f, 1.028848f, 0.385277f, + 0.249245f, 0.102975f, 0.301977f, 0.814893f, 0.829719f, 0.796979f, 0.828055f, -0.841305f, 1.360636f, + 0.520542f, -0.564568f, 1.028838f, 0.624319f, 1.122967f, 1.414307f, 1.664626f, 1.011229f, -0.562413f, + 1.432279f, 0.982238f, -0.634975f, 1.328713f, 0.605853f, 0.150513f, 0.475544f, 0.137686f, 0.199995f, + -0.461095f, 0.034839f, 1.895931f, -0.442368f, -0.012286f, 1.765260f, -0.574054f, 1.540784f, 1.094831f, + 0.660444f, 0.856002f, 0.876256f, 0.900296f, 0.743193f, 0.857834f, 0.771619f, -0.437987f, 0.795097f, + 0.983861f, -0.860229f, 0.919201f, 1.088295f, 0.978393f, 1.000022f, -0.604762f, 0.300263f, 1.250703f, + 0.093107f, 0.398245f, 0.476736f, 0.584533f, 0.450905f, 1.126501f, 1.126446f, 0.704302f, 0.872359f, + 1.388226f, 0.453643f, -0.218810f, 2.159872f, 0.740287f, 1.137416f, -0.416660f, 0.030324f, 0.352386f, + -0.572652f, 1.397336f, -0.212928f, 0.833504f, 0.673148f, 0.564530f, 0.691624f, 0.614170f, 1.159168f, + 0.582539f, 0.714844f, 0.687727f, 0.829472f, 0.895726f, 0.749217f, 0.626510f, 0.160861f, 0.679485f, + -0.247668f, 0.563813f, 0.424527f, 0.442242f, 0.546163f, 0.408836f, 0.503895f, 0.541062f, 0.526861f, + 0.651389f, 1.131327f, 0.109609f, 0.965844f, 0.307533f, 0.397239f, 0.275143f, 0.398844f, 1.158524f, + 1.178295f, 0.107930f, 0.808378f, 0.360064f, 0.893187f, 0.353517f, 0.411826f, 0.588918f, 1.147333f, + 0.707609f, 0.859227f, 0.904664f, 0.005007f, 0.915281f, 1.148453f, 0.418446f, 0.581892f, 0.628682f, + 1.279391f, 0.420879f, 1.174909f, 0.355126f, 0.239180f, 0.495571f, 0.703488f, 0.897993f, 0.580433f, + 0.796672f, 0.937277f, 0.923647f, 1.115814f, 0.759542f, 1.057870f, 0.977992f, 1.052553f, 0.996513f, + 1.042361f, 0.935513f, 0.938658f, -0.328335f, 0.414783f, -0.370250f, -0.629015f, 1.636925f, 1.554468f, + -0.000332f, 0.794400f, -0.644444f, -0.841804f, -0.462323f, -0.489248f, 1.350502f, 1.139242f, 0.742310f, + 1.621988f, 0.891792f, 0.742398f, 0.634979f, 0.789545f, 0.600690f, 0.564714f, 0.910902f, 0.749079f, + 0.795602f, -0.081046f, 1.059454f, -0.024277f, 0.142066f, 2.137630f, 1.354346f, 0.386545f, -0.015730f, + 0.467942f, 1.166715f, 0.105109f, -0.867947f, 0.330163f, 0.402587f, -0.943201f, 1.039989f, 0.807147f, + 1.013271f, 0.658228f, 0.261774f, 1.276604f, 0.793169f, 0.981167f, 1.182381f, -0.094400f, 0.608214f, + 1.500447f, 0.375100f, -0.540889f, -0.429466f, -0.074319f, 0.493101f, 0.428099f, 0.396397f, 0.409342f, + -0.112225f, 0.338536f, -0.096419f, 1.247461f, 0.136779f, -0.296175f, 1.306138f, -0.211410f, 1.225890f, + -0.883684f, 0.732527f, 0.188935f, 0.158450f, -0.070659f, -0.068210f, 0.095841f, 1.142486f, 0.765356f, + 0.480573f, 0.758850f, -0.296101f, -0.351806f, -0.084915f, 0.595416f, 0.228868f, -0.067355f, 0.843406f, + 0.656214f, 0.873088f, 1.118756f, 1.124528f, 0.905517f, 0.397857f, 0.077982f, -0.111570f, -0.334851f, + 0.432766f, 0.446440f, 0.667385f, 0.295979f, 1.815673f, -0.258010f, 1.014872f, 0.567667f, 0.353312f, + 0.252682f, 1.221989f, 0.073956f, -0.006854f, 1.239576f, 1.165116f, 0.349117f, 0.251850f, -0.979634f, + -1.026174f, 1.184909f, 0.343477f, 0.825275f, 1.364619f, 0.027066f, -0.497336f, -0.463020f, 1.676924f, + 2.348872f, 0.382225f, 0.125961f, 0.592108f, 1.470366f, 0.758787f, -0.208515f, 1.041303f, -0.435509f, + 0.117172f, 1.494655f, 0.342757f, 1.778383f, 0.342274f, 0.097464f, 2.547432f, -0.706661f, 0.892228f, + 0.432844f, 0.978781f, 0.577661f, -0.293386f, 0.867343f, 1.042198f, 0.928943f, -1.206122f, -0.536458f, + -0.103338f, -0.556358f, 0.772336f, 0.736790f, 0.761959f, 0.781633f, 1.964310f, 0.328702f, -0.205143f, + 2.151912f, 0.807267f, 0.819557f, 0.651057f, 0.761094f, -0.553660f, 0.061518f, 1.635670f, -0.845767f, + 1.500599f, 0.591131f, 0.429972f, 0.154289f, 1.184999f, 0.943027f, 1.116617f, 1.149119f, 0.798352f, + -0.237060f, -0.176123f, 0.250859f, 0.738550f, 2.343516f, 0.595660f, 0.857584f, 0.334614f, 0.055512f, + 0.827656f, -0.346350f, 0.879107f, 0.903969f, 0.861351f, 0.894605f, 0.544361f, 0.112821f, -0.710248f, + 0.886723f, 1.241048f, -0.874084f, 1.412525f, 0.338762f, -0.116848f, 0.501252f, 0.737254f, 0.656447f, + 0.680143f, 0.883760f, 0.893155f, 1.024669f, 0.749525f, 0.825862f, 0.796258f, 0.693469f, 0.903967f, + 1.112298f, 0.917900f, 0.659168f, 0.521876f, 0.830550f, 0.020787f, 0.905854f, 0.044571f, 0.857847f, + 0.528776f, 0.224581f, 0.636013f, -0.774066f, 0.896313f, 0.357502f, 0.101543f, 0.048746f, -0.023476f, + -0.007332f, 1.160492f, 0.173347f, 0.010474f, -0.390864f, -0.183245f, 0.374310f, -0.061789f, 0.307303f, + 0.374511f, 0.508790f, 0.504972f, 0.571301f, 0.647929f, 0.892303f, 0.727948f, 0.437075f, 0.272462f, + 0.267807f, -1.691226f, -0.311736f, 0.221596f, -0.501987f, -0.209513f, -0.249217f, 0.477392f, -0.221902f, + 0.783358f, 0.585570f, 0.293685f, 0.168966f, -0.402073f, -0.397286f, 0.793616f, 0.814484f, 1.660988f, + 1.381788f, 0.434287f, 0.951160f, 0.398667f, -0.368342f, 0.685965f, 0.628689f, 0.746822f, 0.647196f, + 0.952972f, 1.171188f, 0.756122f, 0.809376f, -0.181046f, 1.143145f, 1.075280f, -0.462215f, 0.117678f, + 0.117596f, 0.117522f, 0.117660f, 1.207595f, -0.374746f, 0.482337f, 0.453367f, -0.074850f, -0.281733f, + 0.121187f, -0.164130f, -0.407813f, 1.347597f, -0.097000f, 0.558638f, -0.030066f, 0.084762f, 0.026081f, + -0.054476f, 0.048566f, 0.563618f, 0.564591f, 0.367439f, 0.067439f, 0.110448f, 0.229187f, 0.244487f, + 0.001379f, -0.044959f, -0.092778f, -0.175144f, -0.060172f, 0.876871f, 0.715658f, -0.005267f, 0.280818f, + 1.021856f, 1.202137f, 1.277564f, -0.846823f, 1.680601f, -0.648320f, 0.465179f, 0.816884f, 1.617434f, + 0.964561f, 0.811168f, 0.685541f, 1.269441f, -0.294534f, -0.541415f, 0.148579f, 0.006120f, -0.047344f, + -0.034877f, 1.228496f, 0.766407f, 1.191577f, 0.830097f, 1.213856f, -1.697397f, -0.162200f, -0.216335f, + 0.082768f, 1.538109f, 1.455440f, 0.466843f, -0.675884f, -0.396112f, -0.230969f, 0.311936f, 0.850093f, + 0.895946f, 0.864577f, 0.906072f, 1.127087f, 0.915749f, 1.022470f, 1.086701f, 0.347097f, 0.115267f, + 0.269888f, 0.017932f, 0.837999f, 0.798699f, 0.830973f, 0.843566f, 0.524987f, -0.323668f, 0.796731f, + 0.882529f, 1.104285f, 0.707952f, 1.288781f, 1.066624f, -0.759169f, 1.253857f, -0.279808f, -0.810174f, + 0.635460f, 1.336810f, 1.461457f, -0.560630f, 0.345593f, 0.388281f, 0.011112f, 0.625432f, -0.202532f, + -0.952190f, 0.661665f, 1.290380f, -0.625566f, -0.330132f, 0.377751f, 1.393908f, 0.947332f, 0.567214f, + 0.597034f, 0.789381f, 1.108524f, 0.989273f, 0.896032f, 0.972095f, 0.451968f, -0.186156f, 0.864871f, + 1.008577f, 1.059174f, 1.005235f, 0.834800f, 0.881400f, -0.345810f, 0.538783f, -0.242229f, 0.765357f, + 0.363634f, 0.540277f, 0.489711f, 0.556296f, 0.791247f, 0.963361f, 0.900796f, 1.274361f, 1.440297f, + 0.639664f, -0.769517f, 2.005213f, -0.205800f, 0.462482f, 0.893398f, -0.179109f, -0.385072f, 0.698468f, + 0.656636f, -0.167324f, 0.646567f, 0.534505f, 1.234794f, 1.110618f, 1.271695f, 0.759512f, 0.229293f, + 0.147224f, 0.794720f, 1.099447f, 1.113528f, 1.058541f, -0.208087f, 0.316237f, -0.032344f, -0.114418f, + 0.540560f, 0.498906f, 0.465116f, 0.418016f, 0.482087f, 0.445022f, 0.453282f, 0.438177f, -0.006379f, + 0.377702f, -0.855888f, 1.042157f, 0.408202f, 0.339785f, 0.287742f, 0.420788f, 0.465379f, 1.007626f, + 1.001159f, 0.554656f, 0.459783f, 1.143811f, 0.339036f, 0.714696f, 0.691498f, 0.735108f, 1.053392f, + 0.778748f, 0.068571f, 0.274017f, 1.481772f, 1.693937f, 0.526139f, 0.909311f, 0.350476f, 0.954506f, + 0.197028f, 0.923411f, 0.045156f, 0.957155f, 0.714096f, 0.633157f, 0.789485f, 0.581167f, 0.845790f, + 0.829842f, 1.194247f, 0.971378f, 1.019175f, 0.907585f, 0.953225f, 0.951858f, 1.102269f, 1.018174f, + 0.902432f, 0.841796f, -0.858393f, -0.330711f, -0.469070f, 0.464267f, 1.114611f, -1.004036f, 1.620967f, + 0.329466f, 0.139467f, -0.470611f, 0.308757f, 1.016010f, 0.453660f, 1.595124f, 0.558440f, 1.023249f, + 0.601039f, 1.007291f, 0.995676f, 0.637742f, 0.970108f, 0.851145f, 0.582246f, 0.840873f, 0.433405f, + -0.009376f, -0.395102f, 0.229559f, 1.179632f, 0.217997f, 0.145108f, 1.614064f, 1.010146f, 0.887566f, + -1.011727f, 0.264498f, 0.152422f, 0.570916f, 0.925334f, -0.269998f, 0.860524f, 1.051678f, 1.007595f, + 0.941741f, 0.488055f, 0.245246f, 0.227135f, 0.066780f, -0.402708f, 1.265329f, 0.257161f, -0.447346f, + 0.493756f, -0.268568f, -0.217773f, -0.301152f, 0.475332f, 0.373900f, 0.446225f, 0.471130f, 0.663021f, + 1.000752f, -0.090537f, 0.673516f, 0.781955f, 0.128213f, 1.239298f, 0.764475f, 1.281084f, 0.902059f, + 0.278935f, 0.221142f, 0.160415f, -0.106214f, 0.210654f, 0.141437f, 0.198334f, 0.149962f, 0.565323f, + 0.050416f, 0.888878f, 0.074347f, 0.079686f, -0.363394f, 0.253592f, -0.311712f, -0.291973f, 0.133119f, + 1.097622f, 0.962363f, 0.796541f, 0.851959f, 0.628367f, 0.626313f, 0.646783f, 0.138650f, 0.510147f, + 1.394106f, 0.600274f, 1.246940f, 0.872970f, 0.275462f, -0.508244f, -0.408690f, 1.314789f, 0.349021f, + 1.545499f, 0.153658f, 0.231785f, 0.389777f, 0.378070f, 0.840290f, -1.853665f, 1.786896f, 0.104429f, + 0.181189f, 0.667719f, 0.567943f, 0.718873f, 0.244843f, 1.129714f, 0.881495f, 1.460520f, 1.995885f, + -0.395025f, 0.817815f, 1.208726f, -1.411448f, 0.606279f, -0.143777f, 0.296987f, 1.422581f, 0.720905f, + 1.279913f, -0.352711f, 0.658642f, 1.613478f, 0.339589f, -0.089663f, 0.243404f, 1.226488f, 0.467706f, + 0.797042f, 0.442854f, 1.121590f, -0.153407f, 1.431477f, 0.230959f, 1.437285f, -0.046937f, -1.527740f, + -0.272532f, 0.732910f, 0.766692f, 0.749836f, 0.778544f, 1.502128f, -0.240678f, 0.820989f, 1.461264f, + 0.744201f, 0.593997f, 0.769196f, 0.670758f, -0.186752f, 1.864102f, -0.563369f, 2.274148f, 1.338321f, + 0.830787f, -0.191057f, 0.642745f, 1.092864f, 1.217034f, 1.076530f, 0.948315f}; + + std::vector swish_data_nhwc = { 0.243866f, 1.365124f, 0.050220f, 0.657257f, -0.177689f, 1.365588f, 0.618877f, 0.492453f, 0.510088f, 0.537078f, 0.379677f, 1.201586f, 0.100271f, 0.029728f, -0.182035f, 0.077149f, 0.357653f, 0.016068f, 0.258221f, 0.062951f, 0.028085f, 0.331049f, -0.251691f, -0.092633f, 0.412580f, 0.762192f, -0.013831f, @@ -389,67 +611,224 @@ TEST(GroupNormTest, GroupNorm_128) { 0.098779f, 0.137334f, 1.757106f, -0.276652f, 1.146234f, 0.434016f, 0.136440f, 0.269671f, 0.128756f, -0.117812f, 0.533588f, 1.186146f, 0.443822f, 2.062000f, 0.421238f, 0.683523f}; + std::vector swish_data_nchw = { + 0.243866f, -0.159901f, -0.192410f, 0.064602f, 1.365124f, 0.309820f, 2.455177f, 1.225849f, 0.050220f, + -0.020019f, -0.054734f, 0.294918f, 0.657257f, 0.561637f, 0.646839f, 0.735547f, -0.177689f, -0.181556f, + 0.132996f, 0.133336f, 1.365588f, 2.420778f, 1.802949f, 1.254788f, 0.618877f, 0.105460f, 0.146142f, + 0.015386f, 0.492453f, 0.752824f, 0.352078f, 0.596943f, 0.510088f, 0.519554f, 0.509331f, 0.492345f, + 0.537078f, 0.823517f, 0.856461f, 0.581139f, 0.379677f, -0.029484f, 0.108424f, 0.186914f, 1.201586f, + 0.040870f, 0.392432f, 1.487454f, 0.100271f, 0.325333f, -0.278360f, 1.006534f, 0.029728f, 0.022692f, + -0.001154f, -0.005585f, -0.182035f, 0.603779f, 1.587304f, -0.001581f, 0.077149f, 0.019369f, 0.045678f, + 0.081065f, 0.357653f, 0.096304f, 0.327438f, 0.145732f, 0.016068f, 0.479364f, -0.067726f, 1.000125f, + 0.258221f, 0.425634f, -0.267492f, 0.206097f, 0.062951f, -0.126475f, -0.128642f, 0.149164f, 0.028085f, + 0.768537f, 0.448763f, 0.134332f, 0.331049f, 0.260306f, -0.061851f, -0.187918f, -0.251691f, -0.187456f, + 0.384811f, 1.363060f, -0.092633f, 0.928184f, 0.401312f, 0.694153f, 0.412580f, 0.475279f, 0.435012f, + 0.461047f, 0.762192f, 0.858428f, 0.522193f, 0.536204f, -0.013831f, 0.740447f, 1.305406f, 0.450521f, + 0.062333f, 0.062195f, 0.062175f, 0.062186f, -0.263020f, 0.602277f, -0.181835f, 0.055983f, 0.143483f, + 0.102570f, -0.167443f, 0.498477f, 0.733510f, -0.234669f, -0.190078f, 0.028087f, 0.029050f, 0.035395f, + -0.018481f, 0.003598f, 0.313013f, 0.110958f, 0.272698f, 0.016046f, 0.102139f, 0.141960f, 0.160295f, + 0.029994f, -0.015817f, -0.078762f, -0.009012f, 0.021779f, -0.090723f, 0.036662f, 0.653681f, 0.264239f, + 0.454239f, 0.950773f, 0.929582f, -0.033536f, 0.640686f, 1.071117f, -0.265990f, 0.872580f, 0.067457f, + 0.094387f, 0.746799f, -0.122234f, 0.799871f, 1.398649f, 0.879794f, 0.295709f, -0.008629f, 0.039996f, + 0.009796f, -0.056175f, 0.691892f, 0.914138f, 0.475701f, 1.027117f, 0.476392f, 0.049258f, 0.479070f, + -0.266875f, 0.976283f, 0.902623f, 1.076367f, -0.084465f, -0.217050f, -0.178574f, 0.153117f, 0.198578f, + 0.624266f, 0.579420f, 0.587422f, 0.650082f, 0.734605f, 0.830635f, 0.609541f, 0.757945f, 0.229296f, + 0.140073f, 0.054136f, 0.173615f, 0.564844f, 0.577730f, 0.549380f, 0.576280f, -0.253452f, 1.082880f, + 0.326523f, -0.204651f, 0.757935f, 0.406556f, 0.847322f, 1.137731f, 1.399714f, 0.741494f, -0.204150f, + 1.156216f, 0.714629f, -0.219945f, 1.050518f, 0.391983f, 0.080910f, 0.293266f, 0.073575f, 0.109964f, + -0.178318f, 0.017723f, 1.648380f, -0.173044f, -0.006105f, 1.507298f, -0.206833f, 1.268957f, 0.820346f, + 0.435470f, 0.600764f, 0.618676f, 0.640120f, 0.503657f, 0.602378f, 0.527688f, -0.171787f, 0.547762f, + 0.716126f, -0.255739f, 0.657118f, 0.814111f, 0.711085f, 0.731079f, -0.213635f, 0.172503f, 0.972323f, + 0.048719f, 0.238256f, 0.294135f, 0.375335f, 0.275437f, 0.850725f, 0.850672f, 0.471277f, 0.615220f, + 1.111010f, 0.277405f, -0.097483f, 1.936515f, 0.501217f, 0.861257f, -0.165546f, 0.015392f, 0.206920f, + -0.206513f, 1.120330f, -0.095172f, 0.581032f, 0.445763f, 0.359888f, 0.460849f, 0.398530f, 0.882337f, + 0.373787f, 0.479997f, 0.457656f, 0.577514f, 0.636029f, 0.508724f, 0.408295f, 0.086886f, 0.450923f, + -0.108577f, 0.359337f, 0.256654f, 0.269234f, 0.345855f, 0.245632f, 0.314115f, 0.341984f, 0.331264f, + 0.428173f, 0.855378f, 0.057805f, 0.699551f, 0.177226f, 0.237559f, 0.156379f, 0.238672f, 0.881711f, + 0.900973f, 0.056874f, 0.559207f, 0.212098f, 0.633758f, 0.207681f, 0.247724f, 0.378743f, 0.870852f, + 0.474008f, 0.603606f, 0.644037f, 0.002510f, 0.653584f, 0.871938f, 0.252370f, 0.373285f, 0.410021f, + 1.000926f, 0.254082f, 0.897667f, 0.208764f, 0.133824f, 0.307957f, 0.470606f, 0.638058f, 0.372154f, + 0.549116f, 0.673480f, 0.661132f, 0.840444f, 0.517441f, 0.785239f, 0.710716f, 0.780221f, 0.727826f, + 0.770623f, 0.671878f, 0.674734f, -0.137456f, 0.249797f, -0.151240f, -0.218730f, 1.370297f, 1.283304f, + -0.000166f, 0.547163f, -0.221845f, -0.253514f, -0.178658f, -0.185949f, 1.072585f, 0.863022f, 0.502916f, + 1.354473f, 0.632512f, 0.502989f, 0.415034f, 0.542996f, 0.387934f, 0.360029f, 0.649641f, 0.508608f, + 0.548196f, -0.038882f, 0.786735f, -0.011991f, 0.076070f, 1.912126f, 1.076488f, 0.230168f, -0.007803f, + 0.287736f, 0.889679f, 0.055314f, -0.256636f, 0.192089f, 0.241274f, -0.264336f, 0.768393f, 0.558143f, + 0.743397f, 0.433681f, 0.147922f, 0.998140f, 0.546106f, 0.713642f, 0.904965f, -0.044974f, 0.393839f, + 1.226827f, 0.222318f, -0.199037f, -0.169319f, -0.035779f, 0.306135f, 0.259179f, 0.236975f, 0.245986f, + -0.052967f, 0.197649f, -0.045887f, 0.969103f, 0.073060f, -0.126316f, 1.027756f, -0.094573f, 0.947734f, + -0.258402f, 0.494719f, 0.103365f, 0.085489f, -0.034082f, -0.032942f, 0.050215f, 0.866159f, 0.522367f, + 0.296938f, 0.516856f, -0.126290f, -0.145276f, -0.040656f, 0.383809f, 0.127472f, -0.032544f, 0.589695f, + 0.432058f, 0.615866f, 0.843271f, 0.848825f, 0.644802f, 0.237987f, 0.040511f, -0.052676f, -0.139653f, + 0.262488f, 0.272236f, 0.441086f, 0.169732f, 1.561563f, -0.112454f, 0.744888f, 0.362299f, 0.207543f, + 0.142219f, 0.943881f, 0.038345f, -0.003415f, 0.961279f, 0.888123f, 0.204724f, 0.141699f, -0.267405f, + -0.270732f, 0.907438f, 0.200946f, 0.573859f, 1.086931f, 0.013716f, -0.188076f, -0.178851f, 1.412803f, + 2.144154f, 0.227198f, 0.066942f, 0.381228f, 1.195574f, 0.516802f, -0.093427f, 0.769628f, -0.171073f, + 0.062015f, 1.220799f, 0.200465f, 1.521402f, 0.200143f, 0.051105f, 2.362491f, -0.233436f, 0.632902f, + 0.262543f, 0.711443f, 0.370009f, -0.125327f, 0.610777f, 0.770470f, 0.665922f, -0.277876f, -0.197959f, + -0.049002f, -0.202732f, 0.528298f, 0.498287f, 0.519488f, 0.536225f, 1.722697f, 0.191122f, -0.092087f, + 1.927784f, 0.558246f, 0.568889f, 0.427906f, 0.518755f, -0.202095f, 0.031705f, 1.368965f, -0.254002f, + 1.226985f, 0.380467f, 0.260506f, 0.083084f, 0.907526f, 0.678707f, 0.841215f, 0.872584f, 0.550561f, + -0.104546f, -0.080327f, 0.141080f, 0.499761f, 2.138265f, 0.384000f, 0.602158f, 0.195041f, 0.028526f, + 0.575932f, -0.143482f, 0.621209f, 0.643413f, 0.605480f, 0.635026f, 0.344486f, 0.059589f, -0.234058f, + 0.627989f, 0.962738f, -0.257335f, 1.135901f, 0.197799f, -0.055014f, 0.312156f, 0.498675f, 0.432245f, + 0.451459f, 0.625349f, 0.633730f, 0.754035f, 0.508984f, 0.574370f, 0.548760f, 0.462362f, 0.643412f, + 0.837068f, 0.655944f, 0.434440f, 0.327522f, 0.578454f, 0.010501f, 0.645105f, 0.022782f, 0.602389f, + 0.332705f, 0.124847f, 0.415858f, -0.244295f, 0.636554f, 0.210367f, 0.053347f, 0.024967f, -0.011600f, + -0.003652f, 0.883625f, 0.094167f, 0.005264f, -0.157717f, -0.083251f, 0.221779f, -0.029940f, 0.177076f, + 0.221916f, 0.317751f, 0.314914f, 0.365097f, 0.425394f, 0.632969f, 0.490896f, 0.265550f, 0.154676f, + 0.151727f, -0.263180f, -0.131768f, 0.123024f, -0.189286f, -0.093822f, -0.109161f, 0.294614f, -0.098691f, + 0.537700f, 0.376140f, 0.168252f, 0.091604f, -0.161157f, -0.159695f, 0.546489f, 0.564490f, 1.395845f, + 1.104433f, 0.263568f, 0.686118f, 0.238550f, -0.150630f, 0.456214f, 0.410026f, 0.506708f, 0.424806f, + 0.687772f, 0.894037f, 0.514549f, 0.560069f, -0.082351f, 0.866797f, 0.801729f, -0.178628f, 0.062297f, + 0.062251f, 0.062210f, 0.062287f, 0.929695f, -0.152669f, 0.298229f, 0.277207f, -0.036025f, -0.121153f, + 0.064261f, -0.075345f, -0.162895f, 1.069637f, -0.046150f, 0.355371f, -0.014807f, 0.044176f, 0.013210f, + -0.026496f, 0.024873f, 0.359187f, 0.359935f, 0.217098f, 0.034856f, 0.058271f, 0.127668f, 0.137113f, + 0.000690f, -0.021974f, -0.044238f, -0.079923f, -0.029181f, 0.619223f, 0.480672f, -0.002627f, 0.159995f, + 0.751405f, 0.924329f, 0.999099f, -0.254131f, 1.416720f, -0.222613f, 0.285733f, 0.566570f, 1.349653f, + 0.698375f, 0.561619f, 0.455867f, 0.990985f, -0.125735f, -0.199164f, 0.079798f, 0.003070f, -0.023112f, + -0.017134f, 0.950309f, 0.523259f, 0.913967f, 0.578059f, 0.935859f, -0.262766f, -0.074537f, -0.096513f, + 0.043096f, 1.266156f, 1.180120f, 0.286938f, -0.227895f, -0.159335f, -0.102207f, 0.180099f, 0.595564f, + 0.636225f, 0.608330f, 0.645301f, 0.851290f, 0.654005f, 0.751979f, 0.812592f, 0.203369f, 0.060952f, + 0.153044f, 0.009046f, 0.584960f, 0.550860f, 0.578823f, 0.589835f, 0.329856f, -0.135870f, 0.549166f, + 0.624253f, 0.829387f, 0.474291f, 1.010328f, 0.793519f, -0.242043f, 0.975459f, -0.120458f, -0.249415f, + 0.415417f, 1.058707f, 1.186345f, -0.203734f, 0.202362f, 0.231365f, 0.005587f, 0.407439f, -0.091046f, + -0.265132f, 0.436457f, 1.011931f, -0.218020f, -0.138064f, 0.224131f, 1.116821f, 0.682626f, 0.361950f, + 0.385073f, 0.542856f, 0.833448f, 0.721125f, 0.636303f, 0.705290f, 0.276201f, -0.084439f, 0.608590f, + 0.739027f, 0.786472f, 0.735919f, 0.582164f, 0.623249f, -0.143303f, 0.340258f, -0.106517f, 0.522368f, + 0.214515f, 0.341388f, 0.303639f, 0.353579f, 0.544456f, 0.697275f, 0.640568f, 0.995898f, 1.164481f, + 0.418773f, -0.243616f, 1.767281f, -0.092349f, 0.283780f, 0.633947f, -0.081556f, -0.155917f, 0.466470f, + 0.432398f, -0.076679f, 0.424301f, 0.337023f, 0.956541f, 0.835456f, 0.993236f, 0.517416f, 0.127733f, + 0.079021f, 0.547438f, 0.824758f, 0.838249f, 0.785873f, -0.093257f, 0.182914f, -0.015911f, -0.053940f, + 0.341603f, 0.310421f, 0.285687f, 0.252067f, 0.298046f, 0.271221f, 0.277146f, 0.266335f, -0.003180f, + 0.224097f, -0.255225f, 0.770431f, 0.245189f, 0.198482f, 0.164428f, 0.254018f, 0.285878f, 0.738142f, + 0.732134f, 0.352326f, 0.281830f, 0.867442f, 0.197982f, 0.479874f, 0.460745f, 0.496878f, 0.781012f, + 0.533761f, 0.035461f, 0.155663f, 1.207408f, 1.430939f, 0.330722f, 0.648210f, 0.205636f, 0.689173f, + 0.108188f, 0.660919f, 0.023088f, 0.691594f, 0.479376f, 0.413581f, 0.542946f, 0.372724f, 0.591785f, + 0.577837f, 0.916584f, 0.704632f, 0.748902f, 0.646659f, 0.688003f, 0.686755f, 0.827456f, 0.747968f, + 0.642034f, 0.588283f, -0.255522f, -0.138260f, -0.180515f, 0.285072f, 0.839288f, -0.269231f, 1.353391f, + 0.191627f, 0.074588f, -0.180937f, 0.178024f, 0.745949f, 0.277417f, 1.326083f, 0.355219f, 0.752707f, + 0.388207f, 0.737830f, 0.727050f, 0.417238f, 0.703465f, 0.596488f, 0.373560f, 0.587475f, 0.262941f, + -0.004666f, -0.159025f, 0.127896f, 0.902279f, 0.120832f, 0.077809f, 1.346089f, 0.740486f, 0.628741f, + -0.269769f, 0.149638f, 0.082008f, 0.364801f, 0.662657f, -0.116884f, 0.604751f, 0.779395f, 0.738113f, + 0.677536f, 0.302422f, 0.137584f, 0.126410f, 0.034505f, -0.161350f, 0.986884f, 0.145023f, -0.174461f, + 0.306618f, -0.116360f, -0.097077f, -0.128073f, 0.293111f, 0.221499f, 0.272082f, 0.290052f, 0.437553f, + 0.731756f, -0.043221f, 0.446063f, 0.536501f, 0.068210f, 0.961003f, 0.521620f, 1.002620f, 0.641700f, + 0.158794f, 0.122747f, 0.086627f, -0.050289f, 0.116380f, 0.075711f, 0.108969f, 0.080593f, 0.360497f, + 0.025843f, 0.629911f, 0.038555f, 0.041430f, -0.149042f, 0.142787f, -0.131760f, -0.124825f, 0.070983f, + 0.823012f, 0.696361f, 0.549003f, 0.597205f, 0.409770f, 0.408138f, 0.424474f, 0.074123f, 0.318761f, + 1.117023f, 0.387609f, 0.968585f, 0.615761f, 0.156582f, -0.190899f, -0.163160f, 1.036466f, 0.204659f, + 1.273897f, 0.082720f, 0.129264f, 0.232396f, 0.224349f, 0.586964f, -0.251066f, 1.530559f, 0.054939f, + 0.098779f, 0.441357f, 0.362511f, 0.483341f, 0.137334f, 0.853822f, 0.623333f, 1.185376f, 1.757106f, + -0.159001f, 0.567378f, 0.930808f, -0.276652f, 0.392318f, -0.066730f, 0.170383f, 1.146234f, 0.485029f, + 1.001448f, -0.145573f, 0.434016f, 1.345469f, 0.198351f, -0.042823f, 0.136440f, 0.948325f, 0.287564f, + 0.549434f, 0.269671f, 0.845997f, -0.070832f, 1.155390f, 0.128756f, 1.161375f, -0.022918f, -0.272434f, + -0.117812f, 0.495040f, 0.523501f, 0.509246f, 0.533588f, 1.228578f, -0.105927f, 0.570132f, 1.186146f, + 0.504504f, 0.382702f, 0.525628f, 0.443822f, -0.084682f, 1.613891f, -0.204372f, 2.062000f, 1.060236f, + 0.578661f, -0.086430f, 0.421238f, 0.818468f, 0.938992f, 0.802915f, 0.683523f}; + // Test float16, without activation int min_cuda_architecture = 530; bool enable_cuda = HasCudaEnvironment(min_cuda_architecture); bool enable_rocm = (nullptr != DefaultRocmExecutionProvider().get()); bool enable_dml = (nullptr != DefaultDmlExecutionProvider().get()); - if (enable_cuda || enable_rocm || enable_dml) { - OpTester test("GroupNorm", 1, onnxruntime::kMSDomain); - test.AddAttribute("epsilon", 1e-05f); - test.AddAttribute("groups", 32); - test.AddAttribute("activation", 0); + std::array channels_last_values = {-1, 0, 1}; - test.AddInput("X", dims, ToFloat16(input_data)); - test.AddInput("gamma", {C}, gamma_data); + for (const int channels_last : channels_last_values) { + if (enable_cuda || enable_rocm || enable_dml) { + std::vector> execution_providers; + if (enable_cuda && channels_last != 0) { + execution_providers.push_back(DefaultCudaExecutionProvider()); + } + if (enable_rocm && channels_last != 0) { + execution_providers.push_back(DefaultRocmExecutionProvider()); + } + if (enable_dml) { + execution_providers.push_back(DefaultDmlExecutionProvider()); + } - test.AddInput("beta", {C}, beta_data); + // Don't run the test if no providers are supported + if (execution_providers.empty()) { + continue; + } - constexpr float rel_error = 0.0f; - constexpr float abs_error = 0.02f; - test.AddOutput("Y", dims, ToFloat16(norm_data), false, rel_error, abs_error); + OpTester test("GroupNorm", 1, onnxruntime::kMSDomain); + test.AddAttribute("epsilon", 1e-05f); + test.AddAttribute("groups", 32); + test.AddAttribute("activation", 0); - std::vector> execution_providers; - if (enable_cuda) { - execution_providers.push_back(DefaultCudaExecutionProvider()); - } - if (enable_rocm) { - execution_providers.push_back(DefaultRocmExecutionProvider()); - } - if (enable_dml) { - execution_providers.push_back(DefaultDmlExecutionProvider()); - } - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {}, nullptr, &execution_providers); - } + // We interpret channels_last==-1 as the attribute not being provided + if (channels_last != -1) { + test.AddAttribute("channels_last", channels_last); + } - // Test float32, with activation - enable_cuda = HasCudaEnvironment(0); - if (enable_cuda || enable_rocm || enable_dml) { - OpTester test("GroupNorm", 1, onnxruntime::kMSDomain); - test.AddAttribute("epsilon", 1e-05f); - test.AddAttribute("groups", 32); - test.AddAttribute("activation", 1); - - test.AddInput("X", dims, input_data); - test.AddInput("gamma", {C}, gamma_data); - test.AddInput("beta", {C}, beta_data); - - constexpr float rel_error = 0.0f; - constexpr float abs_error = 0.01f; - test.AddOutput("Y", dims, swish_data, false, rel_error, abs_error); - - std::vector> execution_providers; - if (enable_cuda) { - execution_providers.push_back(DefaultCudaExecutionProvider()); - } - if (enable_rocm) { - execution_providers.push_back(DefaultRocmExecutionProvider()); + if (channels_last == 0) { + test.AddInput("X", dims_nchw, ToFloat16(input_data_nchw)); + + constexpr float rel_error = 0.0f; + constexpr float abs_error = 0.02f; + test.AddOutput("Y", dims_nchw, ToFloat16(norm_data_nchw), false, rel_error, abs_error); + } else { + test.AddInput("X", dims_nhwc, ToFloat16(input_data_nhwc)); + + constexpr float rel_error = 0.0f; + constexpr float abs_error = 0.02f; + test.AddOutput("Y", dims_nhwc, ToFloat16(norm_data_nhwc), false, rel_error, abs_error); + } + + test.AddInput("gamma", {C}, gamma_data); + test.AddInput("beta", {C}, beta_data); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {}, nullptr, &execution_providers); } - if (enable_dml) { - execution_providers.push_back(DefaultDmlExecutionProvider()); + + // Test float32, with activation + enable_cuda = HasCudaEnvironment(0); + if (enable_cuda || enable_rocm || enable_dml) { + std::vector> execution_providers; + if (enable_cuda && channels_last != 0) { + execution_providers.push_back(DefaultCudaExecutionProvider()); + } + if (enable_rocm && channels_last != 0) { + execution_providers.push_back(DefaultRocmExecutionProvider()); + } + if (enable_dml) { + execution_providers.push_back(DefaultDmlExecutionProvider()); + } + + // Don't run the test if no providers are supported + if (execution_providers.empty()) { + continue; + } + + OpTester test("GroupNorm", 1, onnxruntime::kMSDomain); + test.AddAttribute("epsilon", 1e-05f); + test.AddAttribute("groups", 32); + test.AddAttribute("activation", 1); + + // We interpret channels_last==-1 as the attribute not being provided + if (channels_last != -1) { + test.AddAttribute("channels_last", channels_last); + } + + if (channels_last == 0) { + test.AddInput("X", dims_nchw, input_data_nchw); + + constexpr float rel_error = 0.0f; + constexpr float abs_error = 0.01f; + test.AddOutput("Y", dims_nchw, swish_data_nchw, false, rel_error, abs_error); + } else { + test.AddInput("X", dims_nhwc, input_data_nhwc); + + constexpr float rel_error = 0.0f; + constexpr float abs_error = 0.01f; + test.AddOutput("Y", dims_nhwc, swish_data_nhwc, false, rel_error, abs_error); + } + + test.AddInput("gamma", {C}, gamma_data); + test.AddInput("beta", {C}, beta_data); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {}, nullptr, &execution_providers); } - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {}, nullptr, &execution_providers); } } diff --git a/onnxruntime/test/contrib_ops/inverse_test.cc b/onnxruntime/test/contrib_ops/inverse_test.cc index c652c54e8e487..4eb594cf827f8 100644 --- a/onnxruntime/test/contrib_ops/inverse_test.cc +++ b/onnxruntime/test/contrib_ops/inverse_test.cc @@ -30,14 +30,14 @@ TEST(InverseContribOpTest, two_by_two_float16) { std::transform( input_float.begin(), input_float.end(), std::back_inserter(input), [](float v) { - return MLFloat16(math::floatToHalf(v)); + return MLFloat16(v); }); auto output_float = {0.6f, -0.7f, -0.2f, 0.4f}; std::vector output; std::transform( output_float.begin(), output_float.end(), std::back_inserter(output), [](float v) { - return MLFloat16(math::floatToHalf(v)); + return MLFloat16(v); }); test.AddInput("X", {2, 2}, input); diff --git a/onnxruntime/test/contrib_ops/matmul_fpq4_test.cc b/onnxruntime/test/contrib_ops/matmul_fpq4_test.cc new file mode 100644 index 0000000000000..dd886ed1c6f5b --- /dev/null +++ b/onnxruntime/test/contrib_ops/matmul_fpq4_test.cc @@ -0,0 +1,140 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef ORT_MINIMAL_BUILD + +#include "core/common/span_utils.h" +#include "core/framework/tensor.h" +#include "core/mlas/inc/mlas_q4.h" +#include "core/session/inference_session.h" +#include "test/common/tensor_op_test_utils.h" +#include "test/framework/test_utils.h" +#include "test/optimizer/graph_transform_test_builder.h" +#include "test/providers/provider_test_utils.h" +#include "test/util/include/default_providers.h" +#include "core/util/qmath.h" + +#include +#include + +#include "gtest/gtest.h" +#include "gmock/gmock.h" + +namespace onnxruntime { +namespace test { + +TEST(MatMulFpQ4, MatMul2DSym) { + // (100 x 41) X (41 x 288) + constexpr int64_t M = 100; + constexpr int64_t N = 288; + constexpr int64_t K = 52; + + const auto buf_size = MlasQ4GemmPackBSize(BlkQ4Sym, (size_t)N, (size_t)K); + if (buf_size == 0) { + GTEST_SKIP(); // operation not supported on this hardware platform yet. + } + + OpTester test("MatMulFpQ4", 1, kMSDomain); + test.AddAttribute("blk_quant_type", BlkQ4Sym); + + std::vector input0_vals(M * K); + float fv = -135.f; + for (auto& f : input0_vals) { + f = fv / 128; + fv++; + if (fv > 135.f) { + fv = -135.f; + } + } + + std::vector input1_f_vals(N * K); + int v = -2; + for (size_t i = 0; i < N * K; i++) { + if (v == 0 || v == -3 || v == 3) v++; + input1_f_vals[i] = (float)v; + if (++v >= 8) { + v = -8; + } + } + std::vector input1_vals(buf_size); + MlasQ4GemmPackB(BlkQ4Sym, input1_vals.data(), input1_f_vals.data(), (size_t)N, (size_t)K, (size_t)N); + + std::vector expected_vals(M * N); + for (int64_t m = 0; m < M; m++) { + for (int64_t n = 0; n < N; n++) { + float sum = 0.0f; + for (int64_t k = 0; k < K; k++) { + sum += input0_vals[m * K + k] * input1_f_vals[k * N + n]; + } + expected_vals[m * N + n] = sum; + } + } + + test.AddInput("A", {M, K}, input0_vals, false); + test.AddInput("B", {(int64_t)input1_vals.size()}, input1_vals, true); + test.AddInput("B_shape", {(int64_t)2}, {(int64_t)K, (int64_t)N}, true); + + test.AddOutput("Y", {M, N}, expected_vals); + + test.Run(); +} + +TEST(MatMulFpQ4, MatMul2DBlkZp) { + // (100 x 41) X (41 x 288) + constexpr int64_t M = 100; + constexpr int64_t N = 288; + constexpr int64_t K = 41; + + const auto buf_size = MlasQ4GemmPackBSize(BlkQ4Zp8, (size_t)N, (size_t)K); + if (buf_size == 0) { + GTEST_SKIP(); // operation not yet supported on this hardware platform. + } + + OpTester test("MatMulFpQ4", 1, kMSDomain); + test.AddAttribute("blk_quant_type", BlkQ4Zp8); + + std::vector input0_vals(M * K); + float fv = -135.f; + for (auto& f : input0_vals) { + f = fv / 128; + fv++; + if (fv > 135.f) { + fv = -135.f; + } + } + + std::vector input1_f_vals(N * K); + int v = 0; + for (size_t i = 0; i < N * K; i++) { + input1_f_vals[i] = (float)v; + if (++v >= 16) { + v = 0; + } + } + std::vector input1_vals(buf_size); + MlasQ4GemmPackB(BlkQ4Zp8, input1_vals.data(), input1_f_vals.data(), (size_t)N, (size_t)K, (size_t)N); + + std::vector expected_vals(M * N); + for (int64_t m = 0; m < M; m++) { + for (int64_t n = 0; n < N; n++) { + float sum = 0.0f; + for (int64_t k = 0; k < K; k++) { + sum += input0_vals[m * K + k] * input1_f_vals[k * N + n]; + } + expected_vals[m * N + n] = sum; + } + } + + test.AddInput("A", {M, K}, input0_vals, false); + test.AddInput("B", {(int64_t)input1_vals.size()}, input1_vals, true); + test.AddInput("B_shape", {(int64_t)2}, {(int64_t)K, (int64_t)N}, true); + + test.AddOutput("Y", {M, N}, expected_vals); + + test.Run(); +} + +} // namespace test +} // namespace onnxruntime + +#endif // ORT_MINIMAL_BUILD diff --git a/onnxruntime/test/contrib_ops/multihead_attention_op_test.cc b/onnxruntime/test/contrib_ops/multihead_attention_op_test.cc index 4908b34b700e5..0341ce4385cda 100644 --- a/onnxruntime/test/contrib_ops/multihead_attention_op_test.cc +++ b/onnxruntime/test/contrib_ops/multihead_attention_op_test.cc @@ -9,7 +9,7 @@ #include "test/util/include/scoped_env_vars.h" #include "test/contrib_ops/attention_op_test_helper.h" -#if defined(USE_ROCM) && defined(USE_COMPOSABLE_KERNEL) +#if defined(USE_ROCM) && defined(USE_COMPOSABLE_KERNEL) && !defined(USE_MIGRAPHX) #define DISABLE_ROCM false #else #define DISABLE_ROCM true @@ -49,8 +49,8 @@ static void RunMultiHeadAttentionTest( bool use_float16 = false, bool disable_cpu = false, // some cases not supported in cpu right now. bool disable_cuda = false, - bool disable_rocm = DISABLE_ROCM) // not supported in rocm right now. -{ + 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 min_cuda_architecture = use_float16 ? 750 : 0; @@ -58,8 +58,19 @@ static void RunMultiHeadAttentionTest( // rocm mha is required to work with TunableOp Enabled bool enable_rocm = (nullptr != DefaultRocmExecutionProvider(/*test_tunable_op=*/true).get()) && !disable_rocm; bool enable_cpu = (nullptr != DefaultCpuExecutionProvider().get()) && !use_float16 && !disable_cpu; + bool enable_dml = (nullptr != DefaultDmlExecutionProvider().get()) && !disable_dml; - if (enable_cpu || enable_cuda || enable_rocm) { + if (enable_rocm && !use_float16) { + LOGS_DEFAULT(WARNING) << "ROCm MHA only have kernel for half datatype implemented, skip float datatype tests"; + enable_rocm = false; + } + + if (enable_rocm && !bias_data.empty()) { + LOGS_DEFAULT(WARNING) << "ROCm MHA does not support qkv_bias, skip qkv_bias tests"; + enable_rocm = false; + } + + if (enable_cpu || enable_cuda || enable_rocm || enable_dml) { OpTester tester("MultiHeadAttention", 1, onnxruntime::kMSDomain); tester.AddAttribute("num_heads", static_cast(num_heads)); tester.AddAttribute("mask_filter_value", static_cast(-10000.0f)); @@ -249,6 +260,12 @@ static void RunMultiHeadAttentionTest( execution_providers.push_back(DefaultCpuExecutionProvider()); tester.Run(OpTester::ExpectResult::kExpectSuccess, "", {}, nullptr, &execution_providers); } + + if (enable_dml) { + std::vector> execution_providers; + execution_providers.push_back(DefaultDmlExecutionProvider()); + tester.Run(OpTester::ExpectResult::kExpectSuccess, "", {}, nullptr, &execution_providers); + } } } @@ -278,10 +295,12 @@ static void RunMultiHeadAttentionKernel( bool is_static_kv = true, bool disable_cpu = false, // some cases not supported in cpu right now. bool disable_cuda = false, - bool disable_rocm = DISABLE_ROCM) { + bool disable_rocm = DISABLE_ROCM, + bool disable_dml = false) { if (kernel_type == AttentionKernelType::AttentionKernel_Default) { ScopedEnvironmentVariables scoped_env_vars{ EnvVarMap{ + {onnxruntime::contrib::attention::kDisableFlashAttention, "0"}, {onnxruntime::contrib::attention::kDisableTrtFlashAttention, "0"}, {onnxruntime::contrib::attention::kDisableFusedSelfAttention, "0"}, {onnxruntime::contrib::attention::kDisableFusedCrossAttention, "0"}, @@ -290,13 +309,14 @@ static void RunMultiHeadAttentionKernel( query_data, key_data, value_data, kv_data, qkv_data, bias_data, rel_pos_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_rocm); + hidden_size, v_hidden_size, is_static_kv, use_float16, disable_cpu, disable_cuda, disable_rocm, disable_dml); return; } if (kernel_type == AttentionKernelType::AttentionKernel_Unfused) { ScopedEnvironmentVariables scoped_env_vars{ EnvVarMap{ + {onnxruntime::contrib::attention::kDisableFlashAttention, "1"}, {onnxruntime::contrib::attention::kDisableTrtFlashAttention, "1"}, {onnxruntime::contrib::attention::kDisableFusedSelfAttention, "1"}, {onnxruntime::contrib::attention::kDisableFusedCrossAttention, "1"}, @@ -305,13 +325,14 @@ static void RunMultiHeadAttentionKernel( query_data, key_data, value_data, kv_data, qkv_data, bias_data, rel_pos_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_rocm); + hidden_size, v_hidden_size, is_static_kv, use_float16, disable_cpu, disable_cuda, disable_rocm, disable_dml); return; } if (kernel_type == AttentionKernelType::AttentionKernel_TrtFusedCrossAttention) { ScopedEnvironmentVariables scoped_env_vars{ EnvVarMap{ + {onnxruntime::contrib::attention::kDisableFlashAttention, "1"}, {onnxruntime::contrib::attention::kDisableTrtFlashAttention, "1"}, {onnxruntime::contrib::attention::kDisableFusedSelfAttention, "1"}, {onnxruntime::contrib::attention::kDisableFusedCrossAttention, "0"}, @@ -320,14 +341,15 @@ static void RunMultiHeadAttentionKernel( query_data, key_data, value_data, kv_data, qkv_data, bias_data, rel_pos_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_rocm); + hidden_size, v_hidden_size, is_static_kv, use_float16, disable_cpu, disable_cuda, disable_rocm, disable_dml); return; } -#if USE_FLASH_ATTENTION +#if USE_MEMORY_EFFICIENT_ATTENTION if (kernel_type == AttentionKernelType::AttentionKernel_CutlassMemoryEfficientAttention) { ScopedEnvironmentVariables scoped_env_vars{ EnvVarMap{ + {onnxruntime::contrib::attention::kDisableFlashAttention, "1"}, {onnxruntime::contrib::attention::kDisableTrtFlashAttention, "1"}, {onnxruntime::contrib::attention::kDisableFusedSelfAttention, "1"}, {onnxruntime::contrib::attention::kDisableFusedCrossAttention, "1"}, @@ -336,7 +358,7 @@ static void RunMultiHeadAttentionKernel( query_data, key_data, value_data, kv_data, qkv_data, bias_data, rel_pos_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_rocm); + hidden_size, v_hidden_size, is_static_kv, use_float16, disable_cpu, disable_cuda, disable_rocm, disable_dml); return; } #endif @@ -344,6 +366,7 @@ static void RunMultiHeadAttentionKernel( if (kernel_type == AttentionKernelType::AttentionKernel_TrtFusedAttention) { ScopedEnvironmentVariables scoped_env_vars{ EnvVarMap{ + {onnxruntime::contrib::attention::kDisableFlashAttention, "1"}, {onnxruntime::contrib::attention::kDisableTrtFlashAttention, "0"}, {onnxruntime::contrib::attention::kDisableFusedSelfAttention, "0"}, {onnxruntime::contrib::attention::kDisableFusedCrossAttention, "1"}, @@ -352,11 +375,11 @@ static void RunMultiHeadAttentionKernel( query_data, key_data, value_data, kv_data, qkv_data, bias_data, rel_pos_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_rocm); + hidden_size, v_hidden_size, is_static_kv, use_float16, disable_cpu, disable_cuda, disable_rocm, disable_dml); } } -static void RunMultiHeadAttentionTests(AttentionTestData& data, bool disable_cpu = false) { +static void RunMultiHeadAttentionTests(AttentionTestData& data, bool disable_cpu = false, bool disable_cuda = false) { if (data.fp32_output_data.size() > 0) { constexpr bool use_float16 = false; @@ -367,12 +390,12 @@ static void RunMultiHeadAttentionTests(AttentionTestData& data, bool disable_cpu data.rel_pos_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); + data.v_hidden_size, kernel_type, use_float16, data.is_static_kv, disable_cpu, disable_cuda); } -#if USE_FLASH_ATTENTION - if (data.sequence_length >= contrib::attention::kMinSequenceLengthForMemoryEfficientAttentionFp32 || - data.kv_sequence_length >= contrib::attention::kMinSequenceLengthForMemoryEfficientAttentionFp32) { +#if USE_MEMORY_EFFICIENT_ATTENTION + if (data.sequence_length >= contrib::attention::kMinSeqLenForMemoryEfficientAttentionFp32 || + data.kv_sequence_length >= contrib::attention::kMinSeqLenForMemoryEfficientAttentionFp32) { kernel_type = AttentionKernelType::AttentionKernel_CutlassMemoryEfficientAttention; if (!SkipAttentionKernel(data, kernel_type)) { RunMultiHeadAttentionKernel( @@ -380,7 +403,7 @@ static void RunMultiHeadAttentionTests(AttentionTestData& data, bool disable_cpu data.rel_pos_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); + data.v_hidden_size, kernel_type, use_float16, data.is_static_kv, disable_cpu, disable_cuda); } } #endif @@ -391,7 +414,7 @@ static void RunMultiHeadAttentionTests(AttentionTestData& data, bool disable_cpu data.rel_pos_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); + data.v_hidden_size, kernel_type, use_float16, data.is_static_kv, disable_cpu, disable_cuda); } if (data.fp16_output_data.size() > 0) { @@ -403,7 +426,7 @@ static void RunMultiHeadAttentionTests(AttentionTestData& data, bool disable_cpu data.rel_pos_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); + data.v_hidden_size, kernel_type, use_float16, data.is_static_kv, disable_cpu, disable_cuda); } kernel_type = AttentionKernelType::AttentionKernel_TrtFusedAttention; @@ -413,10 +436,10 @@ static void RunMultiHeadAttentionTests(AttentionTestData& data, bool disable_cpu data.rel_pos_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); + data.v_hidden_size, kernel_type, use_float16, data.is_static_kv, disable_cpu, disable_cuda); } -#if USE_FLASH_ATTENTION +#if USE_MEMORY_EFFICIENT_ATTENTION kernel_type = AttentionKernelType::AttentionKernel_CutlassMemoryEfficientAttention; if (!SkipAttentionKernel(data, kernel_type)) { RunMultiHeadAttentionKernel( @@ -424,7 +447,7 @@ static void RunMultiHeadAttentionTests(AttentionTestData& data, bool disable_cpu data.rel_pos_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); + data.v_hidden_size, kernel_type, use_float16, data.is_static_kv, disable_cpu, disable_cuda); } #endif @@ -434,39 +457,47 @@ static void RunMultiHeadAttentionTests(AttentionTestData& data, bool disable_cpu data.rel_pos_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); + data.v_hidden_size, kernel_type, use_float16, data.is_static_kv, disable_cpu, disable_cuda); } } -#ifndef _MSC_VER // Test fused cross attention kernel // It requires head_size > 32 and head_size <= 64 for T4 GPU; hidden_size == v_hidden_size. TEST(MultiHeadAttentionTest, CrossAttention_Batch2_HeadSize40) { - ROCM_GTEST_SKIP("ROCm MHA does not support bias"); AttentionTestData data; GetCrossAttentionData_HeadSize40(data); RunMultiHeadAttentionTests(data); + + GetCrossAttentionData_HeadSize40_NoBias(data); + RunMultiHeadAttentionTests(data); } TEST(MultiHeadAttentionTest, CrossAttention_Batch2_HeadSize32_RightSidePadding_Mask1D) { - ROCM_GTEST_SKIP("ROCm MHA does not support mask"); + ROCM_GTEST_SKIP("ROCm MHA does not support mask type of MASK_1D_KEY_SEQ_LEN"); AttentionTestData data; GetCrossAttentionData_Batch2_HeadSize32_RightSidePadding(data, true); RunMultiHeadAttentionTests(data, true); + + GetCrossAttentionData_Batch2_HeadSize32_RightSidePadding_NoBias(data, true); + RunMultiHeadAttentionTests(data, true); } TEST(MultiHeadAttentionTest, CrossAttention_Batch2_HeadSize32_RightSidePadding_Mask2D) { - ROCM_GTEST_SKIP("ROCm MHA does not support mask"); AttentionTestData data; GetCrossAttentionData_Batch2_HeadSize32_RightSidePadding(data, false); RunMultiHeadAttentionTests(data, true); + + GetCrossAttentionData_Batch2_HeadSize32_RightSidePadding_NoBias(data, false); + RunMultiHeadAttentionTests(data, true); } TEST(MultiHeadAttentionTest, CrossAttention_Batch1_HeadSize32_LeftSidePadding_Mask2D) { - ROCM_GTEST_SKIP("ROCm MHA does not support mask"); AttentionTestData data; GetCrossAttentionData_Batch1_HeadSize32_LeftSidePadding(data); RunMultiHeadAttentionTests(data, true); + + GetCrossAttentionData_Batch1_HeadSize32_LeftSidePadding_NoBias(data); + RunMultiHeadAttentionTests(data, true); } TEST(MultiHeadAttentionTest, CrossAttention_Batch2_HeadSize32_NoBias_NoMask_PackedKV) { @@ -480,39 +511,42 @@ TEST(MultiHeadAttentionTest, SelfAttention_Batch2_HeadSize32_NoBias_NoMask_Packe GetSelfAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedQKV(data); RunMultiHeadAttentionTests(data); } -#endif // This tests qk_head_size != v_head_size TEST(MultiHeadAttentionTest, CrossAttention_Batch2_HeadSize16_8) { - ROCM_GTEST_SKIP("ROCm MHA does not support bias"); AttentionTestData data; GetCrossAttentionData_HeadSize16_8(data); RunMultiHeadAttentionTests(data); + + GetCrossAttentionData_HeadSize16_8_NoBias(data); + RunMultiHeadAttentionTests(data); } TEST(MultiHeadAttentionTest, CrossAttention_Batch1_HeadSize16) { - ROCM_GTEST_SKIP("ROCm MHA does not support bias"); AttentionTestData data; GetCrossAttentionData_HeadSize16(data); RunMultiHeadAttentionTests(data); + + GetCrossAttentionData_HeadSize16_NoBias(data); + RunMultiHeadAttentionTests(data); } TEST(MultiHeadAttentionTest, CrossAttentionWithPast) { - ROCM_GTEST_SKIP("ROCm MHA does not support attention cache"); + ROCM_GTEST_SKIP("ROCm MHA only support head_size >= 8"); AttentionTestData data; GetCrossAttentionDataWithPast(data); RunMultiHeadAttentionTests(data); } TEST(MultiHeadAttentionTest, SelfAttention_WithPast_WithRelPosBias_ForT5) { - ROCM_GTEST_SKIP("ROCm MHA does not support attention cache"); + ROCM_GTEST_SKIP("ROCm MHA only support head_size >= 8"); AttentionTestData data; GetSelfAttentionData_WithPast_WithRelPosBias_ForT5(data); RunMultiHeadAttentionTests(data, true); } TEST(MultiHeadAttentionTest, AttentionCutlassRelPosBias) { - ROCM_GTEST_SKIP("ROCm does not support cutlass"); + // ROCM_GTEST_SKIP("ROCm does not support cutlass"); AttentionTestData data; GetAttentionDataCutlassRelPosBias(data); RunMultiHeadAttentionTests(data); @@ -520,23 +554,33 @@ TEST(MultiHeadAttentionTest, AttentionCutlassRelPosBias) { TEST(MultiHeadAttentionTest, CrossAttention_DiffSequenceLengths) { // Whisper decoder cross attention without mask and different sequence lengths for Q and K/V - ROCM_GTEST_SKIP("ROCm not supported"); AttentionTestData data; GetCrossAttentionData_DiffSequenceLengths(data); RunMultiHeadAttentionTests(data); + + GetCrossAttentionData_DiffSequenceLengths_HeadSize8(data); + RunMultiHeadAttentionTests(data, /*disable_cpu=*/false, /*disable_cuda=*/true); + + GetCrossAttentionData_DiffSequenceLengths_HeadSize8_NoBias(data); + RunMultiHeadAttentionTests(data, /*disable_cpu=*/false, /*disable_cuda=*/true); } TEST(MultiHeadAttentionTest, SelfAttention_WithPastAndPresent_NoMask_NoRelPosBias) { // Whisper decoder self attention with past_kv and present_kv - ROCM_GTEST_SKIP("ROCm not supported"); AttentionTestData data; GetSelfAttentionData_WithPastAndPresent_NoMask_NoRelPosBias(data); RunMultiHeadAttentionTests(data); + + GetSelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias(data); + RunMultiHeadAttentionTests(data, /*disable_cpu=*/false, /*disable_cuda=*/true); + + GetSelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias_NoBias(data); + RunMultiHeadAttentionTests(data, /*disable_cpu=*/false, /*disable_cuda=*/true); } -TEST(MultiHeadAttentionTest, CrossAttention_WithPastPassedInDirectly_NoMask) { +// This test is disabled since it is not used in Whisper anymore, and it fails in ROCm. +TEST(MultiHeadAttentionTest, DISABLED_CrossAttention_WithPastPassedInDirectly_NoMask) { // Whisper decoder cross attention with past_kv in place of current KV and no present_kv - ROCM_GTEST_SKIP("ROCm not supported"); AttentionTestData data; GetCrossAttentionData_WithPastPassedInDirectly_NoMask(data); RunMultiHeadAttentionTests(data); diff --git a/onnxruntime/test/contrib_ops/multihead_attention_op_test_data_gen.py b/onnxruntime/test/contrib_ops/multihead_attention_op_test_data_gen.py index a99f215149f4f..96df6dc52b054 100644 --- a/onnxruntime/test/contrib_ops/multihead_attention_op_test_data_gen.py +++ b/onnxruntime/test/contrib_ops/multihead_attention_op_test_data_gen.py @@ -112,6 +112,8 @@ def forward( # can concat previous decoder key/value_states to current projected key/value_states (third "elif" case) # if encoder bi-directional self-attention `past_key_value` is always `None` past_key_value = (key_layer, value_layer) + print("k cache", key_layer) + print("v cache", value_layer) # Take the dot product between "query" and "key" to get the raw attention scores. attention_scores = torch.matmul(query_layer, key_layer.transpose(-1, -2)) @@ -157,6 +159,7 @@ def run_cross_attention( kv_sequence_length, key_padding_mask=None, has_bias=True, + is_decoder=False, ): seed = 123 torch.manual_seed(seed) @@ -164,7 +167,7 @@ def run_cross_attention( torch.use_deterministic_algorithms(True) device = torch.device("cuda:0") - mha = Attention(num_heads, hidden_dim, q_head_size, v_head_size, is_decoder=False).to(device).eval() + mha = Attention(num_heads, hidden_dim, q_head_size, v_head_size, is_decoder=is_decoder).to(device).eval() if key_padding_mask is not None: key_padding_mask = key_padding_mask.to(device) torch.nn.init.uniform_(mha.query.weight, -0.5, 0.5) @@ -231,6 +234,20 @@ def run_cross_attention( output_attentions=False, ) + if has_bias: + print("zero out bias and run mha again") + torch.nn.init.zeros_(mha.query.bias) + torch.nn.init.zeros_(mha.key.bias) + torch.nn.init.zeros_(mha.value.bias) + mha.forward( + hidden_states, + attention_mask=None, + encoder_hidden_states=encoder_hidden_states, + encoder_attention_mask=key_padding_mask, + past_key_value=None, + output_attentions=False, + ) + def run_self_attention( hidden_dim, @@ -241,6 +258,7 @@ def run_self_attention( sequence_length, key_padding_mask=None, has_bias=True, + is_decoder=False, ): seed = 123 torch.manual_seed(seed) @@ -248,7 +266,7 @@ def run_self_attention( torch.use_deterministic_algorithms(True) device = torch.device("cuda:0") - mha = Attention(num_heads, hidden_dim, q_head_size, v_head_size, is_decoder=False).to(device).eval() + mha = Attention(num_heads, hidden_dim, q_head_size, v_head_size, is_decoder=is_decoder).to(device).eval() if key_padding_mask is not None: key_padding_mask = key_padding_mask.to(device) torch.nn.init.uniform_(mha.query.weight, -0.5, 0.5) @@ -313,6 +331,20 @@ def run_self_attention( output_attentions=False, ) + if has_bias: + print("zero out bias and run mha again") + torch.nn.init.zeros_(mha.query.bias) + torch.nn.init.zeros_(mha.key.bias) + torch.nn.init.zeros_(mha.value.bias) + mha.forward( + hidden_states, + attention_mask=None, + encoder_hidden_states=None, + encoder_attention_mask=key_padding_mask, + past_key_value=None, + output_attentions=False, + ) + def run_cross_batch2_headsize_40(): hidden_dim = 80 @@ -433,6 +465,54 @@ def run_self_batch2_headsize_32_packed_qkv(): ) +def run_cross_diff_seqlen_headsize_8(): + hidden_dim = 16 + q_head_size = 8 + v_head_size = 8 + num_heads = 2 + batch_size = 1 + sequence_length = 2 + kv_sequence_length = 4 + key_padding_mask = None + has_bias = True + run_cross_attention( + hidden_dim, + q_head_size, + v_head_size, + num_heads, + batch_size, + sequence_length, + kv_sequence_length, + key_padding_mask, + has_bias, + is_decoder=True, + ) + + +def run_self_past_present_headsize_8_nomask_norelposbias(): + hidden_dim = 16 + q_head_size = 8 + v_head_size = 8 + num_heads = 2 + batch_size = 2 + # In cpp side we use sequence_length = 1, we manually split the data of the first and second token. + # Then we use first token related data as past and second token related data as true input. + sequence_length = 2 + key_padding_mask = None + has_bias = True + run_self_attention( + hidden_dim, + q_head_size, + v_head_size, + num_heads, + batch_size, + sequence_length, + key_padding_mask, + has_bias, + is_decoder=True, + ) + + def create_test_data(): """ Create test data used in attention_op_test_helper.cc and multihead_attention_op_test.cc @@ -458,6 +538,12 @@ def create_test_data(): print("SelfAttention_Batch2_HeadSize32_PackedQKV") run_self_batch2_headsize_32_packed_qkv() + print("SelfAttention_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias") + run_self_past_present_headsize_8_nomask_norelposbias() + + print("CrossAttention_DiffSequenceLengths_HeadSize8") + run_cross_diff_seqlen_headsize_8() + with torch.no_grad(): create_test_data() diff --git a/onnxruntime/test/contrib_ops/packed_attention_op_test.cc b/onnxruntime/test/contrib_ops/packed_attention_op_test.cc index 5bf785185e665..09baf8def05f6 100644 --- a/onnxruntime/test/contrib_ops/packed_attention_op_test.cc +++ b/onnxruntime/test/contrib_ops/packed_attention_op_test.cc @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#include "core/common/narrow.h" #include "core/platform/env_var_utils.h" #include "gtest/gtest.h" #include "test/common/tensor_op_test_utils.h" @@ -385,42 +386,36 @@ static void RunModelWithRandomInput( int64_t batch_size, int64_t sequence_length, std::string& onnx_model, - bool is_float16) { - // ORT enables TF32 in GEMM for A100. TF32 will cause precsion loss and fail this test. - // Do not run this test unless TF32 is disabled explicitly. - if (HasCudaEnvironment(800) && ParseEnvironmentVariableWithDefault("NVIDIA_TF32_OVERRIDE", 1) != 0) { - GTEST_SKIP() << "Skipping RunModelWithRandomInput in A100 since TF32 is enabled"; - return; - } - + bool is_float16, + bool has_rbp = false) { RandomValueGenerator random{234}; constexpr int hidden_size = 768; constexpr int num_heads = 12; - int token_count = 0; + int64_t token_count = 0; std::vector cum_seq_len(batch_size + 1); cum_seq_len[0] = 0; - int original_offset = 0; - int token_offset_idx = 0; + int64_t original_offset = 0; + int64_t token_offset_idx = 0; std::vector token_offset(batch_size * sequence_length); - for (int b = 0; b < batch_size; b++) { - int actual_seq_len = (sequence_length / (b + 1)); + for (int64_t b = 0; b < batch_size; b++) { + int64_t actual_seq_len = (sequence_length / (b + 1)); token_count += actual_seq_len; - cum_seq_len[b + 1] = token_count; + cum_seq_len[b + 1] = narrow(token_count); original_offset = b * sequence_length; - for (int s = 0; s < actual_seq_len; s++) { - token_offset[token_offset_idx++] = original_offset++; + for (int64_t s = 0; s < actual_seq_len; s++) { + token_offset[token_offset_idx++] = narrow(original_offset++); } } - for (int b = 0; b < batch_size; b++) { - int actual_seq_len = (sequence_length / (b + 1)); + for (int64_t b = 0; b < batch_size; b++) { + int64_t actual_seq_len = (sequence_length / (b + 1)); original_offset = b * sequence_length + actual_seq_len; - for (int s = actual_seq_len; s < sequence_length; s++) { - token_offset[token_offset_idx++] = original_offset++; + for (int64_t s = actual_seq_len; s < sequence_length; s++) { + token_offset[token_offset_idx++] = narrow(original_offset++); } } @@ -438,7 +433,8 @@ static void RunModelWithRandomInput( std::vector token_offset_dims{batch_size, sequence_length}; std::vector cum_seq_len_dims{batch_size + 1}; - float gpu_threshold = is_float16 ? 0.1f : 0.005f; + float gpu_threshold = is_float16 ? 0.15f : 0.005f; + gpu_threshold *= sequence_length > 1024 ? 4.0f : 1.0f; // threshold should increase with sequence length bool enable_cuda = HasCudaEnvironment(is_float16 ? 530 : 0); if (enable_cuda) { OpTester test("PackedAttention", 1, onnxruntime::kMSDomain); @@ -455,6 +451,16 @@ static void RunModelWithRandomInput( test.AddInput("token_offset", token_offset_dims, token_offset); test.AddInput("cumulative_sequence_length", cum_seq_len_dims, cum_seq_len); + if (has_rbp) { + std::vector rbp_dims{1, num_heads, sequence_length, sequence_length}; + std::vector rbp_data = random.Gaussian(rbp_dims, 0.0f, 0.1f); + if (is_float16) { + test.AddInput("rbp", rbp_dims, ToFloat16(rbp_data)); + } else { + test.AddInput("rbp", rbp_dims, rbp_data); + } + } + std::vector> execution_providers; execution_providers.push_back(DefaultCudaExecutionProvider()); test.AddReferenceOutputs(onnx_model, gpu_threshold, DefaultCudaExecutionProvider()); @@ -462,7 +468,7 @@ static void RunModelWithRandomInput( } } -TEST(PackedAttentionTest, test_on_random_data) { +TEST(PackedAttentionTest, TestWithRandomData) { std::string onnx_model = "testdata/packed_attention_fp32.onnx"; std::string onnx_model_fp16 = "testdata/packed_attention_fp16.onnx"; for (int batch_size : std::vector({1, 2, 3, 4, 5, 6, 7, 8})) { @@ -481,7 +487,21 @@ TEST(PackedAttentionTest, test_on_random_data) { } } -TEST(PackedAttentionTest, test_on_random_data_large_seq) { +TEST(PackedAttentionTest, TestWithRandomDataWithRBP) { + std::string onnx_model_fp16 = "testdata/packed_attention_fp16.rbp.onnx"; // mainly for cutlass + for (int batch_size : std::vector({1, 2, 3, 4, 5, 6, 7, 8})) { + for (int sequence_length : std::vector({32, 48, 64, 95, 128})) { + RunModelWithRandomInput( + batch_size, + sequence_length, + onnx_model_fp16, + true /*is_float16*/, + true /*has_rbp*/); + } + } +} + +TEST(PackedAttentionTest, TestWithRandomDataLargeSeq) { int batch_size = 2; int sequence_length = 1152; // > 1024 std::string onnx_model = "testdata/packed_attention_fp32.onnx"; diff --git a/onnxruntime/test/contrib_ops/packed_multihead_attention_op_test.cc b/onnxruntime/test/contrib_ops/packed_multihead_attention_op_test.cc new file mode 100644 index 0000000000000..22253955566f2 --- /dev/null +++ b/onnxruntime/test/contrib_ops/packed_multihead_attention_op_test.cc @@ -0,0 +1,526 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/common/narrow.h" +#include "core/platform/env_var_utils.h" +#include "gtest/gtest.h" +#include "test/common/tensor_op_test_utils.h" +#include "test/common/cuda_op_test_utils.h" +#include "test/providers/provider_test_utils.h" +#include "test/util/include/scoped_env_vars.h" +#include "contrib_ops/cpu/bert/attention_common.h" +#include "test/contrib_ops/attention_op_test_helper.h" + +namespace onnxruntime { +using contrib::AttentionMaskType; +namespace test { + +#define InvokePackedMultiHeadAttentionTest(use_float16, use_scale) \ + RunPackedMultiHeadAttentionTest( \ + query_data, \ + key_data, \ + value_data, \ + bias_data, \ + token_offset, \ + cumulative_sequence_length, \ + output_data, \ + batch_size, \ + sequence_length, \ + hidden_size, \ + v_hidden_size, \ + number_of_heads, \ + token_count, \ + use_float16, \ + use_scale, \ + relative_position_bias_data, \ + broadcast_relative_position_bias); + +static void RunPackedMultiHeadAttentionTest( + const std::vector& query_data, // query: [token_count, num_heads, 3, head_size] + // or [token_count, hidden_size] + const std::vector& key_data, // key: [token_count, hidden_size] + const std::vector& value_data, // value: [token_count, v_hidden_size] + const std::vector& bias_data, // bias: [hidden_size + hidden_size + v_hidden_size] + const std::vector& token_offset, // token_offset: [batch_size, sequence_length] + const std::vector& cumulative_sequence_length, // cum_seq_len: [batch_size + 1] + const std::vector& output_data, // output: [token_count, hidden_size] + int batch_size, + int sequence_length, + int hidden_size, + int v_hidden_size, + int number_of_heads, + int token_count, + bool use_float16, + bool use_scale, + const std::vector& relative_position_bias_data, + bool broadcast_relative_position_bias) { + int min_cuda_architecture = use_float16 ? 530 : 0; + bool enable_cuda = HasCudaEnvironment(min_cuda_architecture); + + int64_t head_size = static_cast(hidden_size / number_of_heads); + + if (enable_cuda) { + OpTester tester("PackedMultiHeadAttention", 1, onnxruntime::kMSDomain); + tester.AddAttribute("num_heads", static_cast(number_of_heads)); + if (use_scale) { + tester.AddAttribute("scale", static_cast(1.f / sqrt(head_size))); + } + + std::vector packed_qkv_dims = {token_count, number_of_heads, 3, head_size}; + std::vector query_dims = {token_count, hidden_size}; + std::vector key_dims = {token_count, hidden_size}; + std::vector value_dims = {token_count, hidden_size}; + std::vector bias_dims = {hidden_size + hidden_size + v_hidden_size}; + std::vector token_offset_dims = {batch_size, sequence_length}; + std::vector cum_seq_len_dims = {batch_size + 1}; + std::vector relative_position_bias_data_dims = {batch_size, number_of_heads, sequence_length, sequence_length}; + std::vector broadcast_relative_position_bias_data_dims = {1, number_of_heads, sequence_length, sequence_length}; + auto& rel_pos_bias_dims = (broadcast_relative_position_bias ? broadcast_relative_position_bias_data_dims : relative_position_bias_data_dims); + + std::vector output_dims = {token_count, v_hidden_size}; + + bool is_packed_qkv = (key_data.size() == 0 && value_data.size() == 0); // packed QKV format + + if (use_float16) { + if (is_packed_qkv) { + tester.AddInput("query", packed_qkv_dims, ToFloat16(query_data)); + tester.AddOptionalInputEdge(); + tester.AddOptionalInputEdge(); + } else { + tester.AddInput("query", query_dims, ToFloat16(query_data)); + tester.AddInput("key", key_dims, ToFloat16(key_data)); + tester.AddInput("value", value_dims, ToFloat16(value_data)); + } + + if (bias_data.size() > 0) { + tester.AddInput("bias", bias_dims, ToFloat16(bias_data)); + } else { + tester.AddOptionalInputEdge(); + } + + tester.AddInput("token_offset", token_offset_dims, token_offset); + tester.AddInput("cumulative_sequence_length", cum_seq_len_dims, cumulative_sequence_length); + if (relative_position_bias_data.size() > 0) { + tester.AddInput("relative_position_bias", + rel_pos_bias_dims, + ToFloat16(relative_position_bias_data)); + } + + tester.AddOutput("output", output_dims, ToFloat16(output_data)); + } else { + if (is_packed_qkv) { + tester.AddInput("query", packed_qkv_dims, query_data); + tester.AddOptionalInputEdge(); + tester.AddOptionalInputEdge(); + } else { + tester.AddInput("query", query_dims, query_data); + tester.AddInput("key", key_dims, key_data); + tester.AddInput("value", value_dims, value_data); + } + + if (bias_data.size() > 0) { + tester.AddInput("bias", bias_dims, bias_data); + } else { + tester.AddOptionalInputEdge(); + } + + tester.AddInput("token_offset", token_offset_dims, token_offset); + tester.AddInput("cumulative_sequence_length", cum_seq_len_dims, cumulative_sequence_length); + if (relative_position_bias_data.size() > 0) { + tester.AddInput("relative_position_bias", rel_pos_bias_dims, relative_position_bias_data); + } + + tester.AddOutput("output", output_dims, output_data); + } + + std::vector> execution_providers; + execution_providers.push_back(DefaultCudaExecutionProvider()); + tester.Run(OpTester::ExpectResult::kExpectSuccess, "", {}, nullptr, &execution_providers); + } +} + +static void RunPackedMultiHeadAttentionTest( + const std::vector& query_data, // query: [token_count, num_heads, 3, head_size] + // or [token_count, hidden_size] + const std::vector& key_data, // key: [token_count, hidden_size] + const std::vector& value_data, // value: [token_count, v_hidden_size] + const std::vector& bias_data, // bias: [hidden_size + hidden_size + v_hidden_size] + const std::vector& token_offset, // token_offset: [batch_size, sequence_length] + const std::vector& cumulative_sequence_length, // cum_seq_len: [batch_size + 1] + const std::vector& output_data, // output: [token_count, hidden_size] + int batch_size, + int sequence_length, + int hidden_size, + int v_hidden_size, + int number_of_heads, + int token_count, + AttentionKernelType kernel_type, + const std::vector& relative_position_bias_data = {}, + bool broadcast_relative_position_bias = false) { + if (kernel_type == AttentionKernelType::AttentionKernel_TrtFusedAttention) { + ScopedEnvironmentVariables scoped_env_vars{ + EnvVarMap{ + {onnxruntime::contrib::attention::kDisableFlashAttention, "1"}, + {onnxruntime::contrib::attention::kDisableTrtFlashAttention, "0"}, + {onnxruntime::contrib::attention::kDisableFusedSelfAttention, "0"}, + {onnxruntime::contrib::attention::kDisableFusedCrossAttention, "1"}, + {onnxruntime::contrib::attention::kDisableMemoryEfficientAttention, "1"}}}; + InvokePackedMultiHeadAttentionTest(true, true); + InvokePackedMultiHeadAttentionTest(true, false); + } + +#if USE_MEMORY_EFFICIENT_ATTENTION + if (kernel_type == AttentionKernelType::AttentionKernel_CutlassMemoryEfficientAttention) { + ScopedEnvironmentVariables scoped_env_vars{ + EnvVarMap{ + {onnxruntime::contrib::attention::kDisableFlashAttention, "1"}, + {onnxruntime::contrib::attention::kDisableTrtFlashAttention, "1"}, + {onnxruntime::contrib::attention::kDisableFusedSelfAttention, "1"}, + {onnxruntime::contrib::attention::kDisableFusedCrossAttention, "1"}, + {onnxruntime::contrib::attention::kDisableMemoryEfficientAttention, "0"}}}; + InvokePackedMultiHeadAttentionTest(true, true); + InvokePackedMultiHeadAttentionTest(true, false); + // Cutlass FMHA need sequence length >= 256 to trigger, so we only test fp16 here. + } +#endif + +#if USE_FLASH_ATTENTION + if (kernel_type == AttentionKernelType::AttentionKernel_FlashAttention) { + ScopedEnvironmentVariables scoped_env_vars{ + EnvVarMap{ + {onnxruntime::contrib::attention::kDisableFlashAttention, "0"}, + {onnxruntime::contrib::attention::kMinSeqLenForFlashAttentionPackedQKV, "0"}}}; + InvokePackedMultiHeadAttentionTest(true, true); + } +#endif + + if (kernel_type == AttentionKernelType::AttentionKernel_Unfused) { + ScopedEnvironmentVariables scoped_env_vars{ + EnvVarMap{ + {onnxruntime::contrib::attention::kDisableFlashAttention, "1"}, + {onnxruntime::contrib::attention::kDisableTrtFlashAttention, "1"}, + {onnxruntime::contrib::attention::kDisableFusedSelfAttention, "1"}, + {onnxruntime::contrib::attention::kDisableFusedCrossAttention, "1"}, + {onnxruntime::contrib::attention::kDisableMemoryEfficientAttention, "1"}}}; + InvokePackedMultiHeadAttentionTest(true, true); + InvokePackedMultiHeadAttentionTest(false, false); + } + + if (kernel_type == AttentionKernelType::AttentionKernel_Default) { + InvokePackedMultiHeadAttentionTest(true, false); + InvokePackedMultiHeadAttentionTest(false, true); + } +} + +TEST(PackedMultiHeadAttentionTest, PackedQKV_NoPadding_NoBias_trt) { + AttentionTestData data; + GetSelfAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedQKV(data); + std::vector empty_data = {}; + std::vector token_offset{0, 1, 2, 3}; + std::vector cum_seq_len{0, 2, 4}; + + RunPackedMultiHeadAttentionTest( + data.qkv_data, + empty_data, + empty_data, + empty_data, + token_offset, + cum_seq_len, + data.fp16_output_data, + data.batch_size, + data.sequence_length, + data.hidden_size, + data.v_hidden_size, + data.num_heads, + data.batch_size * data.sequence_length, + AttentionKernelType::AttentionKernel_TrtFusedAttention); +} + +TEST(PackedMultiHeadAttentionTest, PackedQKV_NoPadding_NoBias_cutlass) { + AttentionTestData data; + GetSelfAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedQKV(data); + std::vector empty_data = {}; + std::vector token_offset{0, 1, 2, 3}; + std::vector cum_seq_len{0, 2, 4}; + + RunPackedMultiHeadAttentionTest( + data.qkv_data, + empty_data, + empty_data, + empty_data, + token_offset, + cum_seq_len, + data.fp16_output_data, + data.batch_size, + data.sequence_length, + data.hidden_size, + data.v_hidden_size, + data.num_heads, + data.batch_size * data.sequence_length, + AttentionKernelType::AttentionKernel_CutlassMemoryEfficientAttention); +} + +TEST(PackedMultiHeadAttentionTest, PackedQKV_NoPadding_NoBias_unfused) { + AttentionTestData data; + GetSelfAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedQKV(data); + std::vector empty_data = {}; + std::vector token_offset{0, 1, 2, 3}; + std::vector cum_seq_len{0, 2, 4}; + + RunPackedMultiHeadAttentionTest( + data.qkv_data, + empty_data, + empty_data, + empty_data, + token_offset, + cum_seq_len, + data.fp16_output_data, + data.batch_size, + data.sequence_length, + data.hidden_size, + data.v_hidden_size, + data.num_heads, + data.batch_size * data.sequence_length, + AttentionKernelType::AttentionKernel_Unfused); +} + +TEST(PackedMultiHeadAttentionTest, Q_K_V_NoPadding_NoBias_trt) { + AttentionTestData data; + GetSelfAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedQKV(data); + std::vector empty_data = {}; + std::vector token_offset{0, 1, 2, 3}; + std::vector cum_seq_len{0, 2, 4}; + + RunPackedMultiHeadAttentionTest( + data.query_data, + data.key_data, + data.value_data, + empty_data, + token_offset, + cum_seq_len, + data.fp16_output_data, + data.batch_size, + data.sequence_length, + data.hidden_size, + data.v_hidden_size, + data.num_heads, + data.batch_size * data.sequence_length, + AttentionKernelType::AttentionKernel_TrtFusedAttention); +} + +TEST(PackedMultiHeadAttentionTest, Q_K_V_NoPadding_Bias_RelPosBias_cutlass) { + AttentionTestData data; + GetAttentionDataCutlassRelPosBias(data); + std::vector token_offset{0, 1, 2, 3, 4, 5, 6, 7}; + std::vector cum_seq_len{0, 8}; + + RunPackedMultiHeadAttentionTest( + data.query_data, + data.key_data, + data.value_data, + data.bias_data, + token_offset, + cum_seq_len, + data.fp16_output_data, + data.batch_size, + data.sequence_length, + data.hidden_size, + data.v_hidden_size, + data.num_heads, + data.batch_size * data.sequence_length, + AttentionKernelType::AttentionKernel_CutlassMemoryEfficientAttention, + data.rel_pos_bias_data, + data.broadcast_rel_pos_bias); +} + +TEST(PackedMultiHeadAttentionTest, Q_K_V_NoPadding_Bias_RelPosBias_unfused) { + AttentionTestData data; + GetAttentionDataCutlassRelPosBias(data); + std::vector token_offset{0, 1, 2, 3, 4, 5, 6, 7}; + std::vector cum_seq_len{0, 8}; + + RunPackedMultiHeadAttentionTest( + data.query_data, + data.key_data, + data.value_data, + data.bias_data, + token_offset, + cum_seq_len, + data.fp16_output_data, + data.batch_size, + data.sequence_length, + data.hidden_size, + data.v_hidden_size, + data.num_heads, + data.batch_size * data.sequence_length, + AttentionKernelType::AttentionKernel_Unfused, + data.rel_pos_bias_data, + data.broadcast_rel_pos_bias); +} + +TEST(PackedMultiHeadAttentionTest, PackedQKV_Padding_NoBias_trt) { + PackedAttentionTestData data; + GetPackedMultiHeadAttentionData_Batch2_HeadSize32_NoRelPosBias(data); + std::vector empty_data = {}; + + RunPackedMultiHeadAttentionTest( + data.qkv_data, + empty_data, + empty_data, + empty_data, + data.token_offset, + data.cumulative_sequence_length, + data.fp16_output_data, + data.batch_size, + data.sequence_length, + data.hidden_size, + data.v_hidden_size, + data.num_heads, + data.token_count, + AttentionKernelType::AttentionKernel_TrtFusedAttention); +} + +TEST(PackedMultiHeadAttentionTest, PackedQKV_Padding_NoBias_cutlass) { + PackedAttentionTestData data; + GetPackedMultiHeadAttentionData_Batch2_HeadSize32_NoRelPosBias(data); + std::vector empty_data = {}; + + RunPackedMultiHeadAttentionTest( + data.qkv_data, + empty_data, + empty_data, + empty_data, + data.token_offset, + data.cumulative_sequence_length, + data.fp16_output_data, + data.batch_size, + data.sequence_length, + data.hidden_size, + data.v_hidden_size, + data.num_heads, + data.token_count, + AttentionKernelType::AttentionKernel_CutlassMemoryEfficientAttention); +} + +#if USE_FLASH_ATTENTION +TEST(PackedMultiHeadAttentionTest, PackedQKV_Padding_NoBias_FlashAttention) { + if (HasCudaEnvironment(800)) { + PackedAttentionTestData data; + GetPackedMultiHeadAttentionData_Batch2_HeadSize32_NoRelPosBias(data); + std::vector empty_data = {}; + + RunPackedMultiHeadAttentionTest( + data.qkv_data, + empty_data, + empty_data, + empty_data, + data.token_offset, + data.cumulative_sequence_length, + data.fp16_output_data, + data.batch_size, + data.sequence_length, + data.hidden_size, + data.v_hidden_size, + data.num_heads, + data.token_count, + AttentionKernelType::AttentionKernel_FlashAttention); + } +} +#endif + +TEST(PackedMultiHeadAttentionTest, PackedQKV_Padding_NoBias_unfused) { + PackedAttentionTestData data; + GetPackedMultiHeadAttentionData_Batch2_HeadSize32_NoRelPosBias(data); + std::vector empty_data = {}; + + RunPackedMultiHeadAttentionTest( + data.qkv_data, + empty_data, + empty_data, + empty_data, + data.token_offset, + data.cumulative_sequence_length, + data.fp16_output_data, + data.batch_size, + data.sequence_length, + data.hidden_size, + data.v_hidden_size, + data.num_heads, + data.token_count, + AttentionKernelType::AttentionKernel_Unfused); +} + +TEST(PackedMultiHeadAttentionTest, PackedQKV_Padding_NoBias_RelPosBias) { + PackedAttentionTestData data; + GetPackedMultiHeadAttentionData_Batch2_HeadSize8_RelPosBias(data); + std::vector empty_data = {}; + + RunPackedMultiHeadAttentionTest( + data.qkv_data, + empty_data, + empty_data, + empty_data, + data.token_offset, + data.cumulative_sequence_length, + data.fp16_output_data, + data.batch_size, + data.sequence_length, + data.hidden_size, + data.v_hidden_size, + data.num_heads, + data.token_count, + AttentionKernelType::AttentionKernel_Default, + data.rel_pos_bias_data, + data.broadcast_rel_pos_bias); +} + +TEST(PackedMultiHeadAttentionTest, PackedQKV_Padding_NoBias_BroadcastRelPosBias_cutlass) { + PackedAttentionTestData data; + GetPackedMultiHeadAttentionData_Batch2_HeadSize8_BroadcastRelPosBias(data); + std::vector empty_data = {}; + + RunPackedMultiHeadAttentionTest( + data.qkv_data, + empty_data, + empty_data, + empty_data, + data.token_offset, + data.cumulative_sequence_length, + data.fp16_output_data, + data.batch_size, + data.sequence_length, + data.hidden_size, + data.v_hidden_size, + data.num_heads, + data.token_count, + AttentionKernelType::AttentionKernel_CutlassMemoryEfficientAttention, + data.rel_pos_bias_data, + data.broadcast_rel_pos_bias); +} + +TEST(PackedMultiHeadAttentionTest, PackedQKV_Padding_NoBias_BroadcastRelPosBias_unfused) { + PackedAttentionTestData data; + GetPackedMultiHeadAttentionData_Batch2_HeadSize8_BroadcastRelPosBias(data); + std::vector empty_data = {}; + + RunPackedMultiHeadAttentionTest( + data.qkv_data, + empty_data, + empty_data, + empty_data, + data.token_offset, + data.cumulative_sequence_length, + data.fp16_output_data, + data.batch_size, + data.sequence_length, + data.hidden_size, + data.v_hidden_size, + data.num_heads, + data.token_count, + AttentionKernelType::AttentionKernel_Unfused, + data.rel_pos_bias_data, + data.broadcast_rel_pos_bias); +} + +} // namespace test +} // namespace onnxruntime diff --git a/onnxruntime/test/contrib_ops/qordered_attention_test.cc b/onnxruntime/test/contrib_ops/qordered_attention_test.cc index 72bae6fd129de..24e4bff528285 100644 --- a/onnxruntime/test/contrib_ops/qordered_attention_test.cc +++ b/onnxruntime/test/contrib_ops/qordered_attention_test.cc @@ -10,7 +10,7 @@ #include -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11040 +#if defined(USE_CUDA) namespace onnxruntime { namespace test { diff --git a/onnxruntime/test/contrib_ops/qordered_longformer_attention_op_test.cc b/onnxruntime/test/contrib_ops/qordered_longformer_attention_op_test.cc index 8dc7109d43dcb..55209d9422fdd 100644 --- a/onnxruntime/test/contrib_ops/qordered_longformer_attention_op_test.cc +++ b/onnxruntime/test/contrib_ops/qordered_longformer_attention_op_test.cc @@ -7,7 +7,7 @@ #include -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11040 +#if defined(USE_CUDA) namespace onnxruntime { namespace test { diff --git a/onnxruntime/test/contrib_ops/qordered_matmul_op_test.cc b/onnxruntime/test/contrib_ops/qordered_matmul_op_test.cc index ec9f2f7d26689..e5b3d59ef86e3 100644 --- a/onnxruntime/test/contrib_ops/qordered_matmul_op_test.cc +++ b/onnxruntime/test/contrib_ops/qordered_matmul_op_test.cc @@ -9,7 +9,7 @@ #include -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11040 +#if defined(USE_CUDA) namespace onnxruntime { namespace test { diff --git a/onnxruntime/test/contrib_ops/qordered_qdq_op_test.cc b/onnxruntime/test/contrib_ops/qordered_qdq_op_test.cc index 6134777ef126b..15e97751acf2d 100644 --- a/onnxruntime/test/contrib_ops/qordered_qdq_op_test.cc +++ b/onnxruntime/test/contrib_ops/qordered_qdq_op_test.cc @@ -7,7 +7,7 @@ #include -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11040 +#if defined(USE_CUDA) namespace onnxruntime { namespace test { diff --git a/onnxruntime/test/contrib_ops/quantize_attention_op_test.cc b/onnxruntime/test/contrib_ops/quantize_attention_op_test.cc index 6ee20004f9688..3af334696a97d 100644 --- a/onnxruntime/test/contrib_ops/quantize_attention_op_test.cc +++ b/onnxruntime/test/contrib_ops/quantize_attention_op_test.cc @@ -894,7 +894,7 @@ void TestQuantizedAttentionPastState(int64_t batch, test.AddInput("weight_zero_point", {weight_scale_zp_size}, weight_zero_point); test.AddInput("past", past_dims, past_data); - test.AddReferenceOutputs(reference_model); + test.AddReferenceOutputs(reference_model, 0.0002f); test.Run(); } diff --git a/onnxruntime/test/contrib_ops/quantize_ops_test.cc b/onnxruntime/test/contrib_ops/quantize_ops_test.cc index 22f87099dc5af..64a97ed4f945b 100644 --- a/onnxruntime/test/contrib_ops/quantize_ops_test.cc +++ b/onnxruntime/test/contrib_ops/quantize_ops_test.cc @@ -4,6 +4,7 @@ #include "gtest/gtest.h" #include "test/common/tensor_op_test_utils.h" #include "test/providers/provider_test_utils.h" +#include "test/util/include/default_providers.h" namespace onnxruntime { namespace test { @@ -40,8 +41,43 @@ TEST(DequantizeLinearOpTest, DequantizeLinear_per_tensor_float_int8) { test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); } +// Test int16 com.microsoft.DequantizeLinear (per tensor) +TEST(DequantizeLinearOpTest, DequantizeLinear_per_tensor_float_int16_cpu) { + OpTester test("DequantizeLinear", 1, onnxruntime::kMSDomain); + std::vector dims{4}; + test.AddInput("x", dims, {-300, -30, -1025, 1270}); + test.AddInput("scale", {}, {2.0f}, true); + test.AddInput("zero_point", {}, {-1024}, true); + test.AddOutput("y", dims, {1448.0f, 1988.0f, -2.0f, 4588.0f}); + // Disable Tensorrt EP due to error: unsupported data type + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); +} + +// Test uint16 com.microsoft.DequantizeLinear (per tensor) +TEST(DequantizeLinearOpTest, DequantizeLinear_per_tensor_float_uint16_cpu) { + OpTester test("DequantizeLinear", 1, onnxruntime::kMSDomain); + std::vector dims{4}; + test.AddInput("x", dims, {30000, 31000, 32768, 33000}); + test.AddInput("scale", {}, {2.0f}, true); + test.AddInput("zero_point", {}, {32767}, true); + test.AddOutput("y", dims, {-5534.0f, -3534.0f, 2.0f, 466.0f}); + // Disable Tensorrt EP due to error: unsupported data type + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); +} + +// Test int32 DequantizeLinear with scalar zero-point & scale. +TEST(DequantizeLinearOpTest, DequantizeLinear_per_tensor_float_int32_cpu) { + OpTester test("DequantizeLinear", 1, onnxruntime::kMSDomain); + std::vector dims{4}; + test.AddInput("x", dims, {-300, -30, -1025, 1270}); + test.AddInput("scale", {}, {2.0f}, true); + test.AddInput("zero_point", {}, {0}, true); + test.AddOutput("y", dims, {-600.0f, -60.0f, -2050.0f, 2540.0f}); + test.Run(); +} + #ifdef USE_CUDA -TEST(DequantizeLinearOpTest, DISABLED_DequantizeLinear_per_tensor_half_uint8) { // Op with name (InsertedCast_x_scale) and type (Cast) Version mismatch. node_version: 19 kernel start version: 13 kernel_end_version: +TEST(DequantizeLinearOpTest, DequantizeLinear_per_tensor_half_uint8) { OpTester test("DequantizeLinear", 1, onnxruntime::kMSDomain); std::vector dims{4}; test.AddInput("x", dims, {0, 3, 128, 255}); @@ -245,6 +281,60 @@ TEST(QuantizeLinearContribOpTest, QuantizeLinear_per_tensor_float_int8) { test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); } +// Test uint16 com.microsoft.QuantizeLinear (per tensor) +TEST(QuantizeLinearContribOpTest, QuantizeLinear_per_tensor_float_uint16) { + OpTester test("QuantizeLinear", 1, onnxruntime::kMSDomain); + std::vector dims{12}; + test.AddInput("x", dims, { + 0.f, -128.f, 3.f, -3.f, // rounding half to even + 2.9f, -2.9f, // round < .5 + 3.1f, -3.1f, // round > .5 + 65536.f, -65534.f, // critical point + 70000.f, -70000.f // saturate case + }); + test.AddInput("scale", {}, {2.0f}, true); + test.AddInput("zero_point", {}, {32767}, true); + test.AddOutput("y", dims, + {32767, 32703, + 32769, 32765, + 32768, 32766, + 32769, 32765, + 65535, 0, + 65535, 0}); + + // Disable Tensorrt EP due to error: unsupported data type + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); +} + +// Test int16 com.microsoft.QuantizeLinear (per tensor) +TEST(QuantizeLinearContribOpTest, QuantizeLinear_per_tensor_float_int16) { + OpTester test("QuantizeLinear", 1, onnxruntime::kMSDomain); + std::vector dims{16}; + test.AddInput("x", dims, { + 0.f, -514.f, 3.f, -3.f, // rounding half to even + 2.9f, -2.9f, // round < .5 + 3.1f, -3.1f, // round > .5 + 65022.f, -66046.f, // critical point + 65023.f, -66047.f, // critical point + 65024.f, -66048.f, // critical point + 70000.f, -70000.f // saturate case + }); + test.AddInput("scale", {}, {2.0f}, true); + test.AddInput("zero_point", {}, {256}, true); + test.AddOutput("y", dims, + {256, -1, + 258, 254, + 257, 255, + 258, 254, + 32767, -32767, + 32767, -32768, + 32767, -32768, + 32767, -32768}); + + // Disable Tensorrt EP due to error: unsupported data type + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); +} + #ifdef USE_CUDA TEST(QuantizeLinearContribOpTest, QuantizeLinear_per_tensor_half_uint8) { OpTester test("QuantizeLinear", 1, onnxruntime::kMSDomain); diff --git a/onnxruntime/test/contrib_ops/relative_attention_bias_test.cc b/onnxruntime/test/contrib_ops/relative_attention_bias_test.cc index 5c0838676205f..6885a460d75b4 100644 --- a/onnxruntime/test/contrib_ops/relative_attention_bias_test.cc +++ b/onnxruntime/test/contrib_ops/relative_attention_bias_test.cc @@ -227,7 +227,9 @@ static void RunGatedRelativePositionBiasTest( int num_heads, int head_size, int D, - bool use_float16 = false) { + bool use_float16, + const std::vector& token_offset, + int token_count) { int min_cuda_architecture = use_float16 ? 530 : 0; bool enable_cuda = HasCudaEnvironment(min_cuda_architecture); @@ -243,21 +245,32 @@ static void RunGatedRelativePositionBiasTest( std::vector eco_a_dims = {1, num_heads, 1, 1}; std::vector output_dims = {batch_size, num_heads, seq_len, seq_len}; + std::vector packed_query_dims = {token_count, num_heads * head_size}; + std::vector token_offset_dims = {batch_size, seq_len}; + bool is_padding_removed = token_offset.size() > 0; + if (use_float16) { - tester.AddInput("query_layer", query_layer_dims, ToFloat16(query_layer)); + tester.AddInput("query_layer", is_padding_removed ? packed_query_dims : query_layer_dims, ToFloat16(query_layer)); tester.AddInput("query_bias", query_bias_dims, ToFloat16(query_bias)); tester.AddInput("rel_pos", rel_pos_dims, ToFloat16(rel_pos)); tester.AddInput("weight", weight_dims, ToFloat16(weight)); tester.AddInput("bias", bias_dims, ToFloat16(bias)); tester.AddInput("eco_a", eco_a_dims, ToFloat16(eco_a)); + if (is_padding_removed) { + tester.AddInput("token_offset", token_offset_dims, token_offset); + } tester.AddOutput("output", output_dims, ToFloat16(output)); } else { - tester.AddInput("query_layer", query_layer_dims, query_layer); + tester.AddInput("query_layer", is_padding_removed ? packed_query_dims : query_layer_dims, query_layer); tester.AddInput("query_bias", query_bias_dims, query_bias); tester.AddInput("rel_pos", rel_pos_dims, rel_pos); tester.AddInput("weight", weight_dims, weight); tester.AddInput("bias", bias_dims, bias); tester.AddInput("eco_a", eco_a_dims, eco_a); + if (is_padding_removed) { + tester.AddInput("token_offset", token_offset_dims, token_offset); + } + tester.AddOutput("output", output_dims, output); } @@ -304,8 +317,10 @@ TEST(GatedRelativePositionBiasTest, FP16_BSNHD_1x3x2x4x8) { 0.88587445f, 0.42708054f, 1.0246648f, 0.05810945f, 0.2430356f, 0.4244021f, 1.428723f, 1.3902748f, 0.48772895f, 0.84479123f}; + const std::vector token_offset; + int token_count = 0; RunGatedRelativePositionBiasTest(query_layer, query_bias, rel_pos, weight, bias, eco_a, output, - batch_size, seq_len, num_heads, head_size, D, true); + batch_size, seq_len, num_heads, head_size, D, true, token_offset, token_count); } TEST(GatedRelativePositionBiasTest, FP32_BSNHD_2x3x2x4x8) { @@ -350,8 +365,10 @@ TEST(GatedRelativePositionBiasTest, FP32_BSNHD_2x3x2x4x8) { 0.37552574f, 1.1995038f, 1.4269164f, 0.47112313f, 0.5597632f, 0.6641063f, 0.87367094f, 1.056893f, 0.12367466f, 0.34158388f, 0.7510766f, 0.98590875f}; + const std::vector token_offset; + int token_count = 0; RunGatedRelativePositionBiasTest(query_layer, query_bias, rel_pos, weight, bias, eco_a, output, - batch_size, seq_len, num_heads, head_size, D, false); + batch_size, seq_len, num_heads, head_size, D, false, token_offset, token_count); } TEST(GatedRelativePositionBiasTest, FP32_LongSeq_BSNHD_2x5x2x4x4) { @@ -410,17 +427,19 @@ TEST(GatedRelativePositionBiasTest, FP32_LongSeq_BSNHD_2x5x2x4x4) { 0.48692167f, 0.33312735f, 0.4217717f, 0.117013805f, 0.5107221f, 0.78737986f, 0.22609876f, 0.6166911f, 1.1153911f, 0.5832259f, 0.6681177f, 0.59397215f}; + const std::vector token_offset; + int token_count = 0; RunGatedRelativePositionBiasTest(query_layer, query_bias, rel_pos, weight, bias, eco_a, output, - batch_size, seq_len, num_heads, head_size, D, false); + batch_size, seq_len, num_heads, head_size, D, false, token_offset, token_count); } -TEST(GatedRelativePositionBiasTest, FP16_BSNHD_2x8x2x4x8) { +TEST(GatedRelativePositionBiasTest, FP16_BSNHD_2x8x2x4x8_NoPadding) { constexpr int batch_size = 2; constexpr int num_heads = 2; constexpr int seq_len = 8; constexpr int head_size = 4; constexpr int D = 8; - const std::vector query_layer_dim = {2, 8, 8}; + const std::vector query_layer_dim = {16, 8}; const std::vector query_layer = { 0.4962566f, 0.7682218f, 0.08847743f, 0.13203049f, 0.30742282f, 0.6340787f, 0.4900934f, 0.89644474f, 0.45562798f, 0.6323063f, 0.34889346f, 0.4017173f, 0.022325754f, 0.16885895f, 0.29388845f, 0.5185218f, @@ -506,8 +525,10 @@ TEST(GatedRelativePositionBiasTest, FP16_BSNHD_2x8x2x4x8) { 0.57226765f, 0.46851522f, 0.26718724f, 0.6390965f, 1.0312729f, 0.39947683f, 0.22935463f, 0.35571814f, 0.005002509f, 0.82025534f, 0.29372898f, 0.18800265f, 0.2395663f, 0.8900865f, 0.8644386f, 0.998915f}; + const std::vector token_offset = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + int token_count = 16; RunGatedRelativePositionBiasTest(query_layer, query_bias, rel_pos, weight, bias, eco_a, output, - batch_size, seq_len, num_heads, head_size, D, true); + batch_size, seq_len, num_heads, head_size, D, true, token_offset, token_count); } } // namespace test diff --git a/onnxruntime/test/contrib_ops/skiplayernorm_op_test.cc b/onnxruntime/test/contrib_ops/skiplayernorm_op_test.cc index c3078bcbaae2d..2395532198805 100644 --- a/onnxruntime/test/contrib_ops/skiplayernorm_op_test.cc +++ b/onnxruntime/test/contrib_ops/skiplayernorm_op_test.cc @@ -2,6 +2,7 @@ // Licensed under the MIT License. #include "gtest/gtest.h" +#include "core/session/onnxruntime_cxx_api.h" #include "test/common/tensor_op_test_utils.h" #include "test/common/cuda_op_test_utils.h" #include "test/providers/provider_test_utils.h" @@ -25,18 +26,32 @@ static void RunTest( bool use_float16 = false, bool no_beta = false, bool simplified = false, - bool use_token_count = false) { + bool use_token_count = false, + bool strict = false, + bool broadcast_skip = false, + bool no_batch_size = false) { // Input and output shapes // Input 0 - input: (batch_size, sequence_length, hidden_size) or (batch_size * sequence_length, hidden_size) - // Input 1 - skip : (batch_size, sequence_length, hidden_size) or (batch_size * sequence_length, hidden_size) + // Input 1 - skip : (batch_size, sequence_length, hidden_size) or (batch_size * sequence_length, hidden_size) or (1, sequence_length, hidden_size) or (sequence_length, hidden_size) // Input 2 - gamma: (hidden_size) // Input 3 - beta : (hidden_size) // Output : (batch_size, sequence_length, hidden_size) or (batch_size * sequence_length, hidden_size) std::vector input_dims = {batch_size, sequence_length, hidden_size}; + std::vector skip_dims = input_dims; + if (use_token_count) { input_dims = {batch_size * sequence_length, hidden_size}; + skip_dims = input_dims; } - std::vector skip_dims = input_dims; + + if (broadcast_skip) { + skip_dims = {1, sequence_length, hidden_size}; + } + + if (no_batch_size) { + skip_dims = {sequence_length, hidden_size}; + } + std::vector gamma_dims = {hidden_size}; std::vector beta_dims = gamma_dims; std::vector bias_dims = gamma_dims; @@ -46,6 +61,8 @@ static void RunTest( auto rocm_ep = DefaultRocmExecutionProvider(); auto dml_ep = DefaultDmlExecutionProvider(); + auto cpu_ep = DefaultCpuExecutionProvider(); + std::vector> execution_providers; if (!use_float16) { OpTester test(op_type.c_str(), 1, onnxruntime::kMSDomain); test.AddInput("input", input_dims, input_data); @@ -75,7 +92,10 @@ static void RunTest( skip_input_bias_add_output_data); } - test.Run(); + if (cpu_ep != nullptr) { + execution_providers.push_back(DefaultCpuExecutionProvider()); + } + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {}, nullptr, &execution_providers); } else if (HasCudaEnvironment(530 /*min_cuda_architecture*/) || dml_ep != nullptr || rocm_ep != nullptr) { @@ -107,13 +127,24 @@ static void RunTest( ToFloat16(skip_input_bias_add_output_data)); } - std::vector> execution_providers; if (dml_ep != nullptr) { execution_providers.push_back(DefaultDmlExecutionProvider()); } else if (rocm_ep != nullptr) { execution_providers.push_back(DefaultRocmExecutionProvider()); } else { - execution_providers.push_back(DefaultCudaExecutionProvider()); + if (strict) { + const auto& api = Ort::GetApi(); + OrtCUDAProviderOptionsV2* cuda_options = nullptr; + ASSERT_TRUE(api.CreateCUDAProviderOptions(&cuda_options) == nullptr); + std::unique_ptr + rel_cuda_options(cuda_options, api.ReleaseCUDAProviderOptions); + std::vector keys{"enable_skip_layer_norm_strict_mode"}; + std::vector values{"1"}; + ASSERT_TRUE(api.UpdateCUDAProviderOptions(rel_cuda_options.get(), keys.data(), values.data(), 1) == nullptr); + execution_providers.push_back(CudaExecutionProviderWithOptions(std::move(rel_cuda_options.get()))); + } else { + execution_providers.push_back(DefaultCudaExecutionProvider()); + } } test.Run(OpTester::ExpectResult::kExpectSuccess, "", {}, nullptr, &execution_providers); @@ -325,7 +356,11 @@ TEST(SkipLayerNormTest, SkipLayerNormBatch1_Float16_vec) { batch_size, sequence_length, hidden_size, - true); + true /*use_float16*/, + false /*no_beta*/, + false /*simplified*/, + false /*use_token_count*/, + true /*strict*/); } TEST(SkipLayerNormTest, SkipLayerNormBatch1_NoBeta) { @@ -610,10 +645,11 @@ TEST(SkipLayerNormTest, SkipLayerNormBatch1_Float16_vec_token_count) { batch_size, sequence_length, hidden_size, - true, - false, - false, - true); + true /*use_float16*/, + false /*no_beta*/, + false /*simplified*/, + true /*use_token_count*/, + true /*strict*/); } TEST(SkipLayerNormTest, SkipLayerNormBatch2_TokenCount) { @@ -662,8 +698,8 @@ TEST(SkipLayerNormTest, SkipLayerNormBatch2_TokenCount) { true); } -// SkipSimplifiedLayerNorm has not been enabled for ROCm and DML yet -#if !defined(USE_ROCM) && !defined(USE_DML) +// SkipSimplifiedLayerNorm has not been enabled for DML yet +#if !defined(USE_DML) TEST(SkipLayerNormTest, SkipSimplifiedLayerNormBatch1_Float16) { int batch_size = 1; int sequence_length = 2; @@ -701,5 +737,101 @@ TEST(SkipLayerNormTest, SkipSimplifiedLayerNormBatch1_Float16) { } #endif +#if !defined(USE_ROCM) && !defined(USE_DML) +TEST(SkipLayerNormTest, SkipLayerNormBatch2_Skip_Broadcast_No_Batch_Size) { + int batch_size = 2; + int sequence_length = 2; + int hidden_size = 4; + + std::vector input_data = { + 0.8f, -0.5f, 0.0f, 1.f, + 0.5f, 0.2f, 0.3f, -0.6f, + 0.8f, -0.5f, 0.0f, 1.f, + 0.5f, 0.2f, 0.3f, -0.6f}; + + std::vector skip_data = { + 0.1f, -0.2f, 0.3f, 1.0f, + 0.5f, 0.1f, 0.4f, 1.6f}; + + std::vector gamma_data = { + 0.3f, 0.2f, 4.0f, 2.2f}; + + std::vector beta_data = { + 0.2f, 0.1f, 0.4f, 1.6f}; + + std::vector output_data = { + 0.28433859348297119, -0.17090578377246857, -0.92897164821624756, 4.6924152374267578, + 0.46111652255058289, -0.21333980560302734, -0.29631003737449646, 3.5148544311523438, + 0.28433859348297119, -0.17090578377246857, -0.92897164821624756, 4.6924152374267578, + 0.46111652255058289, -0.21333980560302734, -0.29631003737449646, 3.5148544311523438}; + + RunTest(input_data, + skip_data, + gamma_data, + beta_data, + std::vector(), + output_data, + {}, + epsilon_, + batch_size, + sequence_length, + hidden_size, + false, + false, + false, + false, + false, + false, + true); +} + +TEST(SkipLayerNormTest, SkipLayerNormBatch2_Skip_Broadcast_Batch_Size_1) { + int batch_size = 2; + int sequence_length = 2; + int hidden_size = 4; + + std::vector input_data = { + 0.8f, -0.5f, 0.0f, 1.f, + 0.5f, 0.2f, 0.3f, -0.6f, + 0.8f, -0.5f, 0.0f, 1.f, + 0.5f, 0.2f, 0.3f, -0.6f}; + + std::vector skip_data = { + 0.1f, -0.2f, 0.3f, 1.0f, + 0.5f, 0.1f, 0.4f, 1.6f}; + + std::vector gamma_data = { + 0.3f, 0.2f, 4.0f, 2.2f}; + + std::vector beta_data = { + 0.2f, 0.1f, 0.4f, 1.6f}; + + std::vector output_data = { + 0.28433859348297119, -0.17090578377246857, -0.92897164821624756, 4.6924152374267578, + 0.46111652255058289, -0.21333980560302734, -0.29631003737449646, 3.5148544311523438, + 0.28433859348297119, -0.17090578377246857, -0.92897164821624756, 4.6924152374267578, + 0.46111652255058289, -0.21333980560302734, -0.29631003737449646, 3.5148544311523438}; + + RunTest(input_data, + skip_data, + gamma_data, + beta_data, + std::vector(), + output_data, + {}, + epsilon_, + batch_size, + sequence_length, + hidden_size, + false, + false, + false, + false, + false, + true, + false); +} +#endif + } // namespace test } // namespace onnxruntime diff --git a/onnxruntime/test/contrib_ops/tensor_op_test.cc b/onnxruntime/test/contrib_ops/tensor_op_test.cc index d15163340dabe..44cb49580ce8b 100644 --- a/onnxruntime/test/contrib_ops/tensor_op_test.cc +++ b/onnxruntime/test/contrib_ops/tensor_op_test.cc @@ -66,7 +66,7 @@ TEST(CropContribOpTest, CropBorderAndScale) { } TEST(ImageScalerContribOpTest, ImageScalerTest) { - // TODO: Unskip when fixed #41968513 + // Won't fix for DML which only accepts 1 or 3 channels, as the op was only experimental and since removed. if (DefaultDmlExecutionProvider().get() != nullptr) { GTEST_SKIP() << "Skipping because of the following error: AbiCustomRegistry.cpp(507): The parameter is incorrect."; } diff --git a/onnxruntime/test/custom_op_registration/test_registercustomops.cc b/onnxruntime/test/custom_op_registration/test_registercustomops.cc index 939e5ba79ceb6..ad75557aa3582 100644 --- a/onnxruntime/test/custom_op_registration/test_registercustomops.cc +++ b/onnxruntime/test/custom_op_registration/test_registercustomops.cc @@ -20,6 +20,9 @@ typedef const char* PATH_TYPE; extern std::unique_ptr ort_env; static constexpr PATH_TYPE TestModel = TSTR("testdata/custom_op_library/custom_op_test.onnx"); +#if !defined(DISABLE_FLOAT8_TYPES) +static constexpr PATH_TYPE TestModelFloat8 = TSTR("testdata/custom_op_library/custom_op_test_float8.onnx"); +#endif // Test OrtApi RegisterCustomOpsUsingFunction. // Replicate the expected mobile setup where the binary is linked against onnxruntime and a custom ops library. @@ -40,6 +43,18 @@ TEST(CustomOpRegistration, TestUsingFuncNameCApi) { Ort::Session session(*ort_env, TestModel, session_options); } +#if !defined(DISABLE_FLOAT8_TYPES) + +TEST(CustomOpRegistration, TestUsingFuncNameCApiFloat8) { + // Test similar to TestUsingFuncNameCApi but loads model custom_op_test_float8.onnx + // which uses type Float8E4M3FN. + Ort::SessionOptions session_options; + session_options.RegisterCustomOpsUsingFunction("RegisterCustomOpsAltName"); + Ort::Session session(*ort_env, TestModelFloat8, session_options); +} + +#endif + TEST(CustomOpRegistration, TestUsingFuncNameCxxApi) { Ort::SessionOptions session_options; session_options.RegisterCustomOpsUsingFunction("RegisterCustomOpsAltName"); diff --git a/onnxruntime/test/debug_node_inputs_outputs/debug_node_inputs_outputs_utils_test.cc b/onnxruntime/test/debug_node_inputs_outputs/debug_node_inputs_outputs_utils_test.cc index 93ed2b4bb8010..88bb3d70db312 100644 --- a/onnxruntime/test/debug_node_inputs_outputs/debug_node_inputs_outputs_utils_test.cc +++ b/onnxruntime/test/debug_node_inputs_outputs/debug_node_inputs_outputs_utils_test.cc @@ -60,13 +60,11 @@ TEST(DebugNodeInputsOutputs, BasicFileOutput) { const std::vector& fetches, const std::string& /*provider_type*/) { ASSERT_EQ(fetches.size(), 1u); - FetchTensor(fetches[0]); - VerifyTensorProtoFileData( - temp_dir.Path() + ORT_TSTR("/x.tensorproto"), - gsl::make_span(input)); - VerifyTensorProtoFileData( - temp_dir.Path() + ORT_TSTR("/y.tensorproto"), - gsl::make_span(output)); + // check it contains a tensor + fetches[0].Get(); + VerifyTensorProtoFileData(temp_dir.Path() + ORT_TSTR("/x.tensorproto"), gsl::make_span(input)); + VerifyTensorProtoFileData(temp_dir.Path() + ORT_TSTR("/y.tensorproto"), + gsl::make_span(output)); }; tester.SetCustomOutputVerifier(verify_file_data); diff --git a/onnxruntime/test/framework/TestAllocatorManager.cc b/onnxruntime/test/framework/TestAllocatorManager.cc index 42c4680f188ff..6431faf9ca4c1 100644 --- a/onnxruntime/test/framework/TestAllocatorManager.cc +++ b/onnxruntime/test/framework/TestAllocatorManager.cc @@ -2,7 +2,6 @@ // Licensed under the MIT License. #include "test/framework/TestAllocatorManager.h" -#include "core/framework/allocatormgr.h" namespace onnxruntime { namespace test { diff --git a/onnxruntime/test/framework/allocation_planner_test.cc b/onnxruntime/test/framework/allocation_planner_test.cc index 6af97f23e81d6..2147a4253ef39 100644 --- a/onnxruntime/test/framework/allocation_planner_test.cc +++ b/onnxruntime/test/framework/allocation_planner_test.cc @@ -386,8 +386,6 @@ class PlannerTest : public ::testing::Test { onnxruntime::ProviderInfo_CUDA& ep = onnxruntime::GetProviderInfo_CUDA(); auto epFactory = ep.CreateExecutionProviderFactory(epi); std::unique_ptr execution_provider = epFactory->CreateProvider(); - AllocatorManager am; - execution_provider->RegisterAllocator(am); ORT_THROW_IF_ERROR(GetExecutionProviders().Add("CUDAExecutionProvider", std::move(execution_provider))); if (partitionConfigFile != nullptr) SetNodePartitionConfigFilePath(partitionConfigFile); @@ -862,8 +860,8 @@ TEST_F(PlannerTest, LocationPlanningForPassThroughExplicitAndImplicitSubgraphInp OrtValueIndex abs_data_1_out_index; ASSERT_STATUS_OK(main_graph_ort_value_index_map.GetIdx("abs_data_1_out", abs_data_1_out_index)); - EXPECT_EQ(main_graph_plan->allocation_plan[abs_data_0_out_index].location.device.Type(), OrtDevice::GPU); - EXPECT_EQ(main_graph_plan->allocation_plan[abs_data_1_out_index].location.device.Type(), OrtDevice::GPU); + EXPECT_EQ(main_graph_plan->allocation_plan[abs_data_0_out_index].location.Type(), OrtDevice::GPU); + EXPECT_EQ(main_graph_plan->allocation_plan[abs_data_1_out_index].location.Type(), OrtDevice::GPU); } // First subgraph (Loop) (L1 graph) @@ -894,8 +892,8 @@ TEST_F(PlannerTest, LocationPlanningForPassThroughExplicitAndImplicitSubgraphInp // There are no explicit consumers of "abs_data_0_out" and "loop_state_var (abs_data_1_out)" in this scope. // There is only one implicit consumer "If". Hence, check that we are preserving the locations of these values // from the outer scope, thus deferring any copies till the actual nested subgraph these values are used in. - EXPECT_EQ(first_subgraph_plan->allocation_plan[abs_data_0_out_index].location.device.Type(), OrtDevice::GPU); - EXPECT_EQ(first_subgraph_plan->allocation_plan[abs_data_1_out_index].location.device.Type(), OrtDevice::GPU); + EXPECT_EQ(first_subgraph_plan->allocation_plan[abs_data_0_out_index].location.Type(), OrtDevice::GPU); + EXPECT_EQ(first_subgraph_plan->allocation_plan[abs_data_1_out_index].location.Type(), OrtDevice::GPU); } } @@ -996,7 +994,7 @@ TEST_F(PlannerTest, LocationPlanningForInitializersOnlyUsedInANestedSubgraph) { OrtValueIndex init_data_index; ASSERT_STATUS_OK(main_graph_ort_value_index_map.GetIdx("init_data", init_data_index)); - EXPECT_EQ(main_graph_plan->allocation_plan[init_data_index].location.device.Type(), OrtDevice::GPU); + EXPECT_EQ(main_graph_plan->allocation_plan[init_data_index].location.Type(), OrtDevice::GPU); } TEST_F(PlannerTest, LocationPlanningForInitializersUsedOnDifferentDevicesInMainGraphAndSubgraph) { @@ -1103,7 +1101,7 @@ TEST_F(PlannerTest, LocationPlanningForInitializersUsedOnDifferentDevicesInMainG OrtValueIndex init_data_index; ASSERT_STATUS_OK(main_graph_ort_value_index_map.GetIdx("init_data", init_data_index)); - EXPECT_EQ(main_graph_plan->allocation_plan[init_data_index].location.device.Type(), OrtDevice::CPU); + EXPECT_EQ(main_graph_plan->allocation_plan[init_data_index].location.Type(), OrtDevice::CPU); // TODO: test para exe plan on subgraph supported // const auto* para_graph_plan = const_cast(main_graph_session_state).GetParallelExecutionPlan(); @@ -1195,7 +1193,7 @@ TEST_F(PlannerTest, LocationPlanningForImplicitInputsWithoutExplicitConsumersInM OrtValueIndex input_data_index; ASSERT_STATUS_OK(main_graph_ort_value_index_map.GetIdx("image_data_in", input_data_index)); - EXPECT_EQ(main_graph_plan->allocation_plan[input_data_index].location.device.Type(), OrtDevice::GPU); + EXPECT_EQ(main_graph_plan->allocation_plan[input_data_index].location.Type(), OrtDevice::GPU); // TODO: test para exe plan on subgraph supported // const auto* para_graph_plan = const_cast(main_graph_session_state).GetParallelExecutionPlan(); @@ -1223,8 +1221,6 @@ TEST_F(PlannerTest, MultiStream) { onnxruntime::ProviderInfo_CUDA& ep = onnxruntime::GetProviderInfo_CUDA(); auto epFactory = ep.CreateExecutionProviderFactory(epi); std::unique_ptr execution_provider = epFactory->CreateProvider(); - AllocatorManager am; - execution_provider->RegisterAllocator(am); ORT_THROW_IF_ERROR(GetExecutionProviders().Add("CUDAExecutionProvider", std::move(execution_provider))); CreatePlan({}, false); @@ -1264,8 +1260,6 @@ TEST_F(PlannerTest, MultiStream1StreamWaitFor2Streams) { onnxruntime::ProviderInfo_CUDA& ep = onnxruntime::GetProviderInfo_CUDA(); auto epFactory = ep.CreateExecutionProviderFactory(epi); std::unique_ptr execution_provider = epFactory->CreateProvider(); - AllocatorManager am; - execution_provider->RegisterAllocator(am); ORT_THROW_IF_ERROR(GetExecutionProviders().Add("CUDAExecutionProvider", std::move(execution_provider))); SetNodePartitionConfigFilePath("./testdata/multi_stream_models/3_gpu_streams.json"); @@ -1328,8 +1322,6 @@ TEST_F(PlannerTest, MultiStreamMultiOutput) { onnxruntime::ProviderInfo_CUDA& ep = onnxruntime::GetProviderInfo_CUDA(); auto epFactory = ep.CreateExecutionProviderFactory(epi); std::unique_ptr execution_provider = epFactory->CreateProvider(); - AllocatorManager am; - execution_provider->RegisterAllocator(am); ORT_THROW_IF_ERROR(GetExecutionProviders().Add("CUDAExecutionProvider", std::move(execution_provider))); CreatePlan({}, false); @@ -1368,8 +1360,6 @@ TEST_F(PlannerTest, MultiStream2NodesSameStreamConsumedBy1NodeInDifferentStream) onnxruntime::ProviderInfo_CUDA& ep = onnxruntime::GetProviderInfo_CUDA(); auto epFactory = ep.CreateExecutionProviderFactory(epi); std::unique_ptr execution_provider = epFactory->CreateProvider(); - AllocatorManager am; - execution_provider->RegisterAllocator(am); ORT_THROW_IF_ERROR(GetExecutionProviders().Add("CUDAExecutionProvider", std::move(execution_provider))); CreatePlan({}, false); @@ -1393,7 +1383,6 @@ TEST_F(PlannerTest, MultiStream2NodesSameStreamConsumedBy1NodeInDifferentStream) #endif #if !defined(__wasm__) && defined(ORT_ENABLE_STREAM) - TEST_F(PlannerTest, ParaPlanCreation) { TypeProto graph_in_type; graph_in_type.mutable_tensor_type()->set_elem_type(TensorProto_DataType_FLOAT); @@ -1946,8 +1935,32 @@ TEST_F(PlannerTest, TestMultiStreamMismatchDevice) { status = sess.Initialize(); ASSERT_TRUE(!status.IsOK()); } - #endif +#if defined(USE_CUDA) && defined(ORT_ENABLE_STREAM) +TEST_F(PlannerTest, TestCpuIf) { + SessionOptions sess_opt; + sess_opt.graph_optimization_level = TransformerLevel::Default; + + InferenceSession sess(sess_opt, GetEnvironment(), ORT_TSTR("./testdata/multi_stream_models/cpu_if.onnx")); + auto status = sess.RegisterExecutionProvider(DefaultCudaExecutionProvider()); + ASSERT_TRUE(status.IsOK()); + status = sess.Load(); + ASSERT_TRUE(status.IsOK()); + status = sess.Initialize(); + ASSERT_TRUE(status.IsOK()); + + auto& sess_state = const_cast(sess.GetSessionState()); + const auto& exe_plan = sess_state.GetExecutionPlan()->execution_plan; + if (exe_plan.size() == 2 && + exe_plan[1]->device_.Type() == OrtDevice::CPU && + exe_plan[1]->steps_.size() == 9 && + exe_plan[1]->steps_[7]->GetNodeIndex() == 7) { + // there must be a wait before cpu If node + static const std::string WaitOnEPStep = "WaitOnEPStep"; + ASSERT_TRUE(exe_plan[1]->steps_[6]->ToString().substr(0, WaitOnEPStep.size()) == WaitOnEPStep); + } +} +#endif } // namespace test } // namespace onnxruntime diff --git a/onnxruntime/test/framework/allocator_test.cc b/onnxruntime/test/framework/allocator_test.cc index 894810174c8dd..2c1cd48d3d02f 100644 --- a/onnxruntime/test/framework/allocator_test.cc +++ b/onnxruntime/test/framework/allocator_test.cc @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/framework/allocatormgr.h" #include "core/framework/allocator.h" #include "test_utils.h" @@ -10,7 +9,7 @@ namespace onnxruntime { namespace test { TEST(AllocatorTest, CPUAllocatorTest) { - auto cpu_arena = TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault); + auto cpu_arena = TestCPUExecutionProvider()->CreatePreferredAllocators()[0]; ASSERT_STREQ(cpu_arena->Info().name, CPU); EXPECT_EQ(cpu_arena->Info().id, 0); @@ -43,6 +42,10 @@ class TestAllocator : public IAllocator { expected_size_{expected_size} { } + void* Reserve(size_t size) override { + reserve_is_called_ = true; + return Alloc(size); + } void* Alloc(size_t size) override { EXPECT_EQ(size, expected_size_); // return a pointer to the expected size in the result. @@ -60,6 +63,8 @@ class TestAllocator : public IAllocator { delete p_sizet; } + bool reserve_is_called_ = false; + private: size_t expected_size_; }; @@ -68,17 +73,18 @@ class TestAllocator : public IAllocator { TEST(AllocatorTest, MakeUniquePtrTest) { // test float creates buffer of size * sizeof(float) size_t num_floats = 16; - - // create allocator that will check the call to Alloc matches the expected size - auto allocator = std::make_shared(num_floats * sizeof(float)); - IAllocatorUniquePtr float_ptr = IAllocator::MakeUniquePtr(allocator, num_floats); - float_ptr = nullptr; // reset so TestAllocator.Free is called here - - // void should create buffer of size 16 for void* - // Create new TestAllocator to validate that. - allocator = std::make_shared(16); - auto void_ptr = IAllocator::MakeUniquePtr(allocator, 16); - void_ptr = nullptr; + for (bool use_reserve : {true, false}) { + // create allocator that will check the call to Alloc matches the expected size + auto allocator = std::make_shared(num_floats * sizeof(float)); + IAllocatorUniquePtr float_ptr = IAllocator::MakeUniquePtr(allocator, num_floats, use_reserve); + float_ptr = nullptr; // reset so TestAllocator.Free is called here + ASSERT_EQ(allocator->reserve_is_called_, use_reserve); + // void should create buffer of size 16 for void* + // Create new TestAllocator to validate that. + allocator = std::make_shared(16); + auto void_ptr = IAllocator::MakeUniquePtr(allocator, 16); + void_ptr = nullptr; + } } TEST(AllocatorTest, TestOverflowChecks) { diff --git a/onnxruntime/test/framework/bfc_arena_test.cc b/onnxruntime/test/framework/bfc_arena_test.cc index 584a0a32945b3..2d3c1521f9c03 100644 --- a/onnxruntime/test/framework/bfc_arena_test.cc +++ b/onnxruntime/test/framework/bfc_arena_test.cc @@ -2,6 +2,7 @@ // Licensed under the MIT License. #include "core/framework/bfc_arena.h" +#include "core/framework/allocator_utils.h" #include "gtest/gtest.h" #include "gmock/gmock.h" #include @@ -409,5 +410,70 @@ TEST(StreamAwareArenaTest, TestSecureTheChunk) { a.Free(p2); } +TEST(BFCArenaTest, TestExtendStrategy) { + int64_t extend_delta_bytes = 0; + { + // Use kNextPowerOfTwo strategy with default extension limit: 1GB. + BFCArena a(std::unique_ptr(new CPUAllocator()), 1UL << 30, ArenaExtendStrategy::kNextPowerOfTwo); + size_t block_size = 1 << 20; // 1MB + a.Alloc(block_size); + AllocatorStats stats; + a.GetStats(&stats); + int64_t prev_allocated_bytes = stats.total_allocated_bytes; + extend_delta_bytes = stats.total_allocated_bytes; + ASSERT_EQ(extend_delta_bytes, static_cast(block_size)); + for (int i = 1; i < 256; ++i) { + a.Alloc(block_size); + a.GetStats(&stats); + if (stats.total_allocated_bytes != prev_allocated_bytes) { + int64_t new_delta_bytes = stats.total_allocated_bytes - prev_allocated_bytes; + ASSERT_EQ(new_delta_bytes, 2 * extend_delta_bytes); + extend_delta_bytes = new_delta_bytes; + prev_allocated_bytes = stats.total_allocated_bytes; + } + } + } + int64_t extend_limit = 1 << 25; // 32MB + ASSERT_GT(extend_delta_bytes, extend_limit); + extend_delta_bytes = 0; + { + // Use kNextPowerOfTwo strategy with much smaller extension limit: 32MB. + OrtArenaCfg config(0, 0, -1, -1, -1, extend_limit); + AllocatorCreationInfo device_info{ + [](OrtDevice::DeviceId) { return std::make_unique(); }, + 0, true, config}; + auto allocator = CreateAllocator(device_info); + size_t block_size = 1 << 20; // 1MB + BFCArena& a = *static_cast(allocator.get()); + a.Alloc(block_size); + AllocatorStats stats; + a.GetStats(&stats); + int64_t prev_allocated_bytes = stats.total_allocated_bytes; + extend_delta_bytes = stats.total_allocated_bytes; + ASSERT_EQ(extend_delta_bytes, static_cast(block_size)); + int reach_limit_count = 0; + for (int i = 1; i < 256; ++i) { + a.Alloc(block_size); + a.GetStats(&stats); + if (stats.total_allocated_bytes != prev_allocated_bytes) { + int64_t new_delta_bytes = stats.total_allocated_bytes - prev_allocated_bytes; + if (new_delta_bytes < extend_limit) { + ASSERT_EQ(new_delta_bytes, 2 * extend_delta_bytes) << "index:" << i; + } else { + // The increasing of new chunk reaches the limit. + ++reach_limit_count; + ASSERT_EQ(new_delta_bytes, extend_limit); + } + extend_delta_bytes = new_delta_bytes; + prev_allocated_bytes = stats.total_allocated_bytes; + } + } + ASSERT_GT(reach_limit_count, 2); + // It is OK to allocate more than extend_limit. + ASSERT_NE(a.Alloc(block_size * 64), nullptr); + } + ASSERT_EQ(extend_delta_bytes, extend_limit); +} + } // namespace test } // namespace onnxruntime diff --git a/onnxruntime/test/framework/cuda/fence_cuda_test.cc b/onnxruntime/test/framework/cuda/fence_cuda_test.cc index 5f23a4600f706..e28327941dda4 100644 --- a/onnxruntime/test/framework/cuda/fence_cuda_test.cc +++ b/onnxruntime/test/framework/cuda/fence_cuda_test.cc @@ -102,7 +102,7 @@ TEST(CUDAFenceTests, DISABLED_PartOnCPU) { ASSERT_TRUE(graph.Resolve().IsOK()); - auto cpu_allocator = TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault); + auto cpu_allocator = TestCPUExecutionProvider()->CreatePreferredAllocators()[0]; auto element_type = DataTypeImpl::GetType(); TensorShape shape({2, 2}); float data[4] = {-1, 2, 3, -4}; @@ -148,7 +148,7 @@ TEST(CUDAFenceTests, TileWithInitializer) { ASSERT_TRUE(graph.Resolve().IsOK()); ASSERT_TRUE(0 == CountCopyNodes(graph)); - auto cpu_allocator = TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault); + auto cpu_allocator = TestCPUExecutionProvider()->CreatePreferredAllocators()[0]; auto element_type = DataTypeImpl::GetType(); TensorShape shape({2, 2}); float data[4] = {-1, 2, 3, -4}; @@ -208,7 +208,7 @@ TEST(CUDAFenceTests, TileWithComputedInput) { ASSERT_TRUE(graph.Resolve().IsOK()); ASSERT_TRUE(0 == CountCopyNodes(graph)); - auto cpu_allocator = TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault); + auto cpu_allocator = TestCPUExecutionProvider()->CreatePreferredAllocators()[0]; auto element_type = DataTypeImpl::GetType(); TensorShape shape({2, 2}); float data[4] = {-1, 2, 3, -4}; diff --git a/onnxruntime/test/framework/data_types_test.cc b/onnxruntime/test/framework/data_types_test.cc index 14c44335a04c0..897bc71b50c51 100644 --- a/onnxruntime/test/framework/data_types_test.cc +++ b/onnxruntime/test/framework/data_types_test.cc @@ -420,13 +420,159 @@ TEST_F(DataTypeTest, VectorMapInt64ToFloatTest) { } #endif // !defined(DISABLE_ML_OPS) -TEST_F(DataTypeTest, BFloat16Test) { +TEST_F(DataTypeTest, MlFloat16ConvertFloatToMLFloat16) { // Test data type { constexpr float sample = 1.0f; - BFloat16 flt16(sample); + const MLFloat16 flt16(sample); auto int_rep = flt16.val; - BFloat16 flt_from_int(int_rep, BFloat16::FromBits()); + const auto flt_from_int = MLFloat16::FromBits(int_rep); + const double diff = std::fabs(sample - flt_from_int.ToFloat()); + if (diff > FLT_EPSILON || (std::isnan(diff) && !std::isnan(sample))) { + EXPECT_TRUE(false); + } + } + // Test bulk conversion + { + float sample[] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f}; + std::vector converted; + std::transform(std::begin(sample), std::end(sample), std::back_inserter(converted), + [](float fl) { return MLFloat16(fl); }); + for (size_t i = 0; i < sizeof(sample) / sizeof(float); ++i) { + const double diff = std::fabs(sample[i] - converted[i].ToFloat()); + if ((std::isnan(diff) && !std::isnan(sample[i])) || diff > FLT_EPSILON) { + FAIL(); + } + } + + std::vector back_converted; + std::transform(converted.cbegin(), converted.cend(), std::back_inserter(back_converted), + [](const MLFloat16 ml) { return (float)ml; }); + for (size_t i = 0; i < sizeof(sample) / sizeof(float); ++i) { + const double diff = std::fabs(sample[i] - back_converted[i]); + if ((std::isnan(diff) && !std::isnan(sample[i])) || diff > FLT_EPSILON) { + FAIL(); + } + } + } +} + +TEST_F(DataTypeTest, MLFloat16Zeros) { + const auto positive_zero = MLFloat16::FromBits(0U); + EXPECT_FALSE(positive_zero.IsNegative()); + const float float_positive_zero = static_cast(positive_zero); + EXPECT_EQ(+0.0f, float_positive_zero); + EXPECT_FALSE(std::signbit(float_positive_zero)); + + const auto negative_zero = positive_zero.Negate(); + EXPECT_TRUE(negative_zero.IsNegative()); + const float float_positive_negzero = static_cast(negative_zero); + EXPECT_EQ(-0.0f, float_positive_negzero); + EXPECT_TRUE(std::signbit(float_positive_negzero)); + + EXPECT_TRUE(positive_zero.IsNaNOrZero()); + EXPECT_TRUE(negative_zero.IsNaNOrZero()); +} + +TEST_F(DataTypeTest, MLFloat16Comparision) { + const MLFloat16 left = MLFloat16(-33.33f); + const MLFloat16 left_same = MLFloat16(-33.33f); + const MLFloat16 right = MLFloat16(66.66f); + const MLFloat16 right_same = MLFloat16(66.66f); + + EXPECT_TRUE(MLFloat16::Epsilon < right); + + EXPECT_EQ(left, left_same); + EXPECT_NE(left, left_same.Negate()); + + EXPECT_EQ(right, right_same); + EXPECT_NE(right, right_same.Negate()); + + EXPECT_LT(left, right); + EXPECT_LT(right.Negate(), left); + EXPECT_LT(left.Negate(), right); +} + +TEST_F(DataTypeTest, MLFloat16TestNAN) { + const MLFloat16 fp16NANFromSingle(std::numeric_limits::quiet_NaN()); + EXPECT_TRUE(fp16NANFromSingle.IsNaN()); + EXPECT_TRUE(fp16NANFromSingle.IsNaNOrZero()); + + // NaN are not equal to each other + EXPECT_NE(MLFloat16::NaN, fp16NANFromSingle); + + const float NanFromBFloat16 = fp16NANFromSingle.ToFloat(); + EXPECT_TRUE(std::isnan(NanFromBFloat16)); + + EXPECT_FALSE(MLFloat16::FromBits(MLFloat16::kMaxValueBits).IsNaN()); +} + +TEST_F(DataTypeTest, MLFloat16NaNComparision) { + EXPECT_FALSE(MLFloat16::NaN < MLFloat16::NaN); + EXPECT_FALSE(MLFloat16::NaN == MLFloat16::NaN); + + EXPECT_FALSE(MLFloat16::MaxValue < MLFloat16::NaN); + EXPECT_FALSE(MLFloat16::MaxValue == MLFloat16::NaN); + EXPECT_FALSE(MLFloat16::MinValue < MLFloat16::NaN); + EXPECT_FALSE(MLFloat16::NaN < MLFloat16::MaxValue); + + EXPECT_TRUE(MLFloat16::MinValue < MLFloat16::MaxValue); +} + +TEST_F(DataTypeTest, MLFloat16Infinity) { + EXPECT_FALSE(MLFloat16::MinValue.IsInfinity()); + EXPECT_FALSE(MLFloat16::MaxValue.IsInfinity()); + EXPECT_TRUE(MLFloat16::MaxValue.IsFinite()); + + const MLFloat16 pos_infinity_from_float(std::numeric_limits::infinity()); + EXPECT_TRUE(pos_infinity_from_float.IsInfinity()); + EXPECT_FALSE(pos_infinity_from_float.IsFinite()); + EXPECT_FALSE(pos_infinity_from_float.IsNegative()); + + const MLFloat16 neg_infinity_from_float(-std::numeric_limits::infinity()); + EXPECT_TRUE(neg_infinity_from_float.IsInfinity()); + EXPECT_FALSE(neg_infinity_from_float.IsFinite()); + EXPECT_TRUE(neg_infinity_from_float.IsNegative()); + + const float pos_infinity_from_bfloat16 = static_cast(MLFloat16::Infinity); + EXPECT_TRUE(std::isinf(pos_infinity_from_bfloat16)); + EXPECT_TRUE(!std::signbit(pos_infinity_from_bfloat16)); +} + +TEST_F(DataTypeTest, MLFloat16NormalSubnormal) { + EXPECT_FALSE(MLFloat16::Infinity.IsNormal()); + EXPECT_TRUE(MLFloat16(45.6f).IsNormal()); + EXPECT_FALSE(MLFloat16(45.6f).IsSubnormal()); + + // 0b0_0000_0000_000_0001 ~0.000000059604645 + constexpr uint16_t min_subnormal_bits = 0x0001; + const MLFloat16 smallest_subnormal = MLFloat16::FromBits(min_subnormal_bits); + EXPECT_TRUE(smallest_subnormal.IsSubnormal()); + EXPECT_FALSE(smallest_subnormal.IsNormal()); + + // float smallest positive subnormal is ~1.40129846432481707092E-45, and + // in float the same number above would be normal + const float float_from_smallest_subnormal = static_cast(smallest_subnormal); + EXPECT_TRUE(std::isnormal(float_from_smallest_subnormal)); + + // 0b0_0000_0000_111_1111; ~0.000060975552 + constexpr uint16_t max_subnormal_bits = 0x007F; + const MLFloat16 largest_subnormal = MLFloat16::FromBits(max_subnormal_bits); + EXPECT_TRUE(largest_subnormal.IsSubnormal()); + EXPECT_FALSE(largest_subnormal.IsNormal()); + + // However, in float the same number above would be normal + const float float_from_largest_subnormal = static_cast(largest_subnormal); + EXPECT_TRUE(std::isnormal(float_from_largest_subnormal)); +} + +TEST_F(DataTypeTest, BFloat16ConvertFloatToBFloat16) { + // Test data type + { + constexpr float sample = 1.0f; + const BFloat16 flt16(sample); + auto int_rep = flt16.val; + const auto flt_from_int = BFloat16::FromBits(int_rep); const double diff = std::fabs(sample - flt_from_int.ToFloat()); if (diff > FLT_EPSILON || (std::isnan(diff) && !std::isnan(sample))) { EXPECT_TRUE(false); @@ -456,6 +602,112 @@ TEST_F(DataTypeTest, BFloat16Test) { } } +TEST_F(DataTypeTest, BFloat16Zeros) { + const auto positive_zero = BFloat16::FromBits(0U); + EXPECT_FALSE(positive_zero.IsNegative()); + const float float_positive_zero = static_cast(positive_zero); + EXPECT_EQ(+0.0f, float_positive_zero); + EXPECT_FALSE(std::signbit(float_positive_zero)); + + const auto negative_zero = positive_zero.Negate(); + EXPECT_TRUE(negative_zero.IsNegative()); + const float float_positive_negzero = static_cast(negative_zero); + EXPECT_EQ(-0.0f, float_positive_negzero); + EXPECT_TRUE(std::signbit(float_positive_negzero)); + + EXPECT_TRUE(positive_zero.IsNaNOrZero()); + EXPECT_TRUE(negative_zero.IsNaNOrZero()); +} + +TEST_F(DataTypeTest, BFloat16Comparision) { + const BFloat16 left = BFloat16(-33.33f); + const BFloat16 left_same = BFloat16(-33.33f); + const BFloat16 right = BFloat16(66.66f); + const BFloat16 right_same = BFloat16(66.66f); + + EXPECT_TRUE(BFloat16::Epsilon < right); + + EXPECT_EQ(left, left_same); + EXPECT_NE(left, left_same.Negate()); + + EXPECT_EQ(right, right_same); + EXPECT_NE(right, right_same.Negate()); + + EXPECT_LT(left, right); + EXPECT_LT(right.Negate(), left); + EXPECT_LT(left.Negate(), right); +} + +TEST_F(DataTypeTest, BFloat16TestNAN) { + const BFloat16 fp16NANFromSingle = std::numeric_limits::quiet_NaN(); + EXPECT_TRUE(fp16NANFromSingle.IsNaN()); + EXPECT_TRUE(fp16NANFromSingle.IsNaNOrZero()); + // NaN are not equal to each other + EXPECT_NE(BFloat16::NaN, fp16NANFromSingle); + + float NanFromBFloat16 = fp16NANFromSingle.ToFloat(); + EXPECT_TRUE(std::isnan(NanFromBFloat16)); + + EXPECT_FALSE(BFloat16::FromBits(BFloat16::kMaxValueBits).IsNaN()); +} + +TEST_F(DataTypeTest, BFloat16NaNComparision) { + EXPECT_FALSE(BFloat16::NaN < BFloat16::NaN); + EXPECT_FALSE(BFloat16::NaN == BFloat16::NaN); + + EXPECT_FALSE(BFloat16::MaxValue < BFloat16::NaN); + EXPECT_FALSE(BFloat16::MaxValue == BFloat16::NaN); + EXPECT_FALSE(BFloat16::MinValue < BFloat16::NaN); + EXPECT_FALSE(BFloat16::NaN < BFloat16::MaxValue); + + EXPECT_TRUE(BFloat16::MinValue < BFloat16::MaxValue); +} + +TEST_F(DataTypeTest, BFloat16Infinity) { + EXPECT_FALSE(BFloat16::MinValue.IsInfinity()); + EXPECT_FALSE(BFloat16::MaxValue.IsInfinity()); + EXPECT_TRUE(BFloat16::MaxValue.IsFinite()); + + const BFloat16 pos_infinity_from_float = std::numeric_limits::infinity(); + EXPECT_TRUE(pos_infinity_from_float.IsInfinity()); + EXPECT_FALSE(pos_infinity_from_float.IsFinite()); + EXPECT_FALSE(pos_infinity_from_float.IsNegative()); + + const BFloat16 neg_infinity_from_float = -std::numeric_limits::infinity(); + EXPECT_TRUE(neg_infinity_from_float.IsInfinity()); + EXPECT_FALSE(neg_infinity_from_float.IsFinite()); + EXPECT_TRUE(neg_infinity_from_float.IsNegative()); + EXPECT_TRUE(std::signbit(neg_infinity_from_float.ToFloat())); + + const float pos_infinity_from_bfloat16 = static_cast(BFloat16::Infinity); + EXPECT_TRUE(std::isinf(pos_infinity_from_bfloat16)); + EXPECT_TRUE(!std::signbit(pos_infinity_from_bfloat16)); +} + +TEST_F(DataTypeTest, BFloat16NormalSubnormal) { + EXPECT_FALSE(BFloat16::Infinity.IsNormal()); + EXPECT_TRUE(BFloat16(45.6f).IsNormal()); + EXPECT_FALSE(BFloat16(45.6f).IsSubnormal()); + + // 0b0_0000_0000_000_0001 + constexpr uint16_t min_subnormal_bits = 0x0001; + const BFloat16 smallest_subnormal = BFloat16::FromBits(min_subnormal_bits); + EXPECT_TRUE(smallest_subnormal.IsSubnormal()); + EXPECT_FALSE(smallest_subnormal.IsNormal()); + + const float float_from_smallest_subnormal = (float)smallest_subnormal; + EXPECT_FALSE(std::isnormal(float_from_smallest_subnormal)); + + // 0b0_0000_0000_111_1111; + constexpr uint16_t max_subnormal_bits = 0x007F; + const BFloat16 largest_subnormal = BFloat16::FromBits(max_subnormal_bits); + EXPECT_TRUE(largest_subnormal.IsSubnormal()); + EXPECT_FALSE(largest_subnormal.IsNormal()); + + const float float_from_largest_subnormal = (float)largest_subnormal; + EXPECT_FALSE(std::isnormal(float_from_largest_subnormal)); +} + TEST_F(DataTypeTest, DataUtilsTest) { using namespace ONNX_NAMESPACE::Utils; // Test simple seq @@ -697,7 +949,7 @@ TEST(InlinedVectorTests, TestDefaultInlinedCapacity) { TEST(TypeLiterals, Tests) { { // uint16_t test - MLFloat16 mlfloat{static_cast(16)}; + MLFloat16 mlfloat = MLFloat16::FromBits(static_cast(16)); auto mlfloat_literal = 16_f16; ASSERT_EQ(mlfloat, mlfloat_literal); diff --git a/onnxruntime/test/framework/dummy_provider.cc b/onnxruntime/test/framework/dummy_provider.cc index 476f8116e83f6..d9b50c0b31cb6 100644 --- a/onnxruntime/test/framework/dummy_provider.cc +++ b/onnxruntime/test/framework/dummy_provider.cc @@ -11,5 +11,9 @@ std::shared_ptr DummyExecutionProvider::GetKernelRegistry() cons return kernel_registry; } +std::vector DummyExecutionProvider::CreatePreferredAllocators() { + return std::vector{std::make_shared()}; +} + } // namespace test } // namespace onnxruntime diff --git a/onnxruntime/test/framework/dummy_provider.h b/onnxruntime/test/framework/dummy_provider.h index 8ee907a2ca9df..2da040d9e703f 100644 --- a/onnxruntime/test/framework/dummy_provider.h +++ b/onnxruntime/test/framework/dummy_provider.h @@ -15,10 +15,10 @@ class DummyExecutionProvider : public IExecutionProvider { public: DummyExecutionProvider() : IExecutionProvider{kDummyExecutionProviderType} { - InsertAllocator(std::make_unique()); } std::shared_ptr GetKernelRegistry() const override; + std::vector CreatePreferredAllocators() override; }; } // namespace test diff --git a/onnxruntime/test/framework/execution_frame_test.cc b/onnxruntime/test/framework/execution_frame_test.cc index 328c477d0c0e9..ec572ce9deed8 100644 --- a/onnxruntime/test/framework/execution_frame_test.cc +++ b/onnxruntime/test/framework/execution_frame_test.cc @@ -82,7 +82,7 @@ TEST_F(ExecutionFrameTest, TensorAllocationTest) { TensorShape shape(std::vector{2, 3}); OrtValue& mlvalue0 = *frame.GetMutableNodeInputOrOutputMLValue(start_index); - const auto& memory_info = execution_providers.Get(xp_typ)->GetAllocator(OrtMemTypeDefault)->Info(); + const auto& memory_info = execution_providers.Get(xp_typ)->GetOrtDeviceByMemType(OrtMemTypeDefault); ASSERT_STATUS_OK(frame.AllocateMLValueTensorSelfOwnBuffer(mlvalue0, start_index, DataTypeImpl::GetType(), memory_info, shape)); @@ -99,7 +99,7 @@ TEST_F(ExecutionFrameTest, TensorAllocationTest) { ASSERT_STATUS_OK(frame.AllocateMLValueTensorPreAllocateBuffer(mlvalue1, start_index, DataTypeImpl::GetType(), - p_tensor->Location(), + p_tensor->Location().device, shape2)); const OrtValue* p_ml_value_const = frame.GetNodeInputOrOutputMLValue(1); @@ -285,7 +285,7 @@ TEST_F(ExecutionFrameTest, MemPatternTest) { ASSERT_TRUE(mlvalue_name_idx_map.GetIdx("T2", t2_idx).IsOK()); ASSERT_TRUE(mlvalue_name_idx_map.GetIdx("T3", t3_idx).IsOK()); - auto cpu_allocator = execution_providers.Get(xp_type)->GetAllocator(OrtMemTypeDefault); + auto cpu_allocator = execution_providers.Get(xp_type)->CreatePreferredAllocators()[0]; OrtValue v1, v2, v3; CreateMLValue(cpu_allocator, @@ -307,24 +307,24 @@ TEST_F(ExecutionFrameTest, MemPatternTest) { ASSERT_STATUS_OK(frame.AllocateMLValueTensorSelfOwnBuffer(mlvalue3, 3, DataTypeImpl::GetType(), - cpu_allocator->Info(), + cpu_allocator->Info().device, TensorShape(std::vector{2, 2}))); ASSERT_STATUS_OK(frame.AllocateMLValueTensorSelfOwnBuffer(mlvalue4, 4, DataTypeImpl::GetType(), - cpu_allocator->Info(), + cpu_allocator->Info().device, TensorShape(std::vector{2, 3}))); ASSERT_STATUS_OK(frame.AllocateMLValueTensorSelfOwnBuffer(mlvalue5, 5, DataTypeImpl::GetType(), - cpu_allocator->Info(), + cpu_allocator->Info().device, TensorShape(std::vector{2, 3}))); MemoryPatternGroup pattern; ASSERT_STATUS_OK(frame.GeneratePatterns(pattern)); ASSERT_EQ(pattern.patterns.size(), pattern.locations.size()); ASSERT_EQ(pattern.patterns.size(), 1u); - auto p = pattern.GetPatterns(cpu_allocator->Info()); + auto p = pattern.GetPatterns(cpu_allocator->Info().device); ASSERT_EQ(p->PeakSize(), 2u * kAllocAlignment); // each allocation is kAllocAlignment-byte aligned ASSERT_EQ(p->GetBlock(3)->offset_, 0u); ASSERT_EQ(p->GetBlock(4)->offset_, kAllocAlignment); @@ -381,7 +381,7 @@ TEST_F(ExecutionFrameTest, MemPatternWithExternalOutputsTest) { ASSERT_TRUE(mlvalue_name_idx_map.GetIdx("T", t_idx).IsOK()); ASSERT_TRUE(mlvalue_name_idx_map.GetIdx("Y", y_idx).IsOK()); - auto cpu_allocator = execution_providers.Get(xp_type)->GetAllocator(OrtMemTypeDefault); + auto cpu_allocator = execution_providers.Get(xp_type)->CreatePreferredAllocators()[0]; OrtValue x_value, t_value; CreateMLValue(cpu_allocator, std::vector{2, 2}, std::vector(4, 2.0f), &x_value); @@ -396,14 +396,14 @@ TEST_F(ExecutionFrameTest, MemPatternWithExternalOutputsTest) { OrtValue& y_value = *frame.GetMutableNodeInputOrOutputMLValue(y_idx); ASSERT_STATUS_OK(frame.AllocateMLValueTensorSelfOwnBuffer( - y_value, y_idx, DataTypeImpl::GetType(), cpu_allocator->Info(), TensorShape(std::vector{2, 2}))); + y_value, y_idx, DataTypeImpl::GetType(), cpu_allocator->Info().device, TensorShape(std::vector{2, 2}))); MemoryPatternGroup pattern; ASSERT_STATUS_OK(frame.GeneratePatterns(pattern)); ASSERT_EQ(pattern.patterns.size(), pattern.locations.size()); ASSERT_EQ(pattern.patterns.size(), 1u); - auto p = pattern.GetPatterns(cpu_allocator->Info()); + auto p = pattern.GetPatterns(cpu_allocator->Info().device); ASSERT_EQ(p->PeakSize(), 0u); // Peak size is 0. } #endif @@ -427,7 +427,7 @@ TEST(ExecutionFrameTestWithoutSessionState, BadModelInvalidDimParamUsage) { } OrtValue ml_value; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), dims_X, values_X, &ml_value); + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], dims_X, values_X, &ml_value); NameMLValMap feeds; feeds.insert(std::make_pair("X", ml_value)); @@ -496,14 +496,16 @@ TEST(ExecutionFrameTestInit, InitializerAsOutput) { #if !defined(DISABLE_SPARSE_TENSORS) TEST(ExecutionFrameTestInit, SparseInitializerAsOutput) { - const std::vector dense_shape{3, 3}; - std::vector dense_data = { - 0, 0, 1.764052391052246f, - 0.40015721321105957f, 0, 0.978738009929657f, - 0, 0, 0}; + constexpr std::array dense_shape{3, 3}; - const std::vector expected_values = {1.764052391052246f, 0.40015721321105957f, 0.978738009929657f}; - const std::vector expected_linear_indices = {2, 3, 5}; + // Tensor data in a dense form, useful for debugging and reference. + // constexpr std::array dense_data = { + // 0, 0, 1.764052391052246f, + // 0.40015721321105957f, 0, 0.978738009929657f, + // 0, 0, 0}; + + constexpr std::array expected_values = {1.764052391052246f, 0.40015721321105957f, 0.978738009929657f}; + constexpr std::array expected_linear_indices = {2, 3, 5}; // sparse_initializer_as_output.onnx SessionOptions so; @@ -515,14 +517,18 @@ TEST(ExecutionFrameTestInit, SparseInitializerAsOutput) { ASSERT_STATUS_OK(session.Initialize()); auto allocator = test::AllocatorManager::Instance().GetAllocator(CPU); - auto p_tensor = std::make_unique(); std::vector results; results.resize(1); - auto ml_type = DataTypeImpl::GetType(); - results[0].Init(p_tensor.release(), ml_type, ml_type->GetDeleteFunc()); + + // Initialize the output value as a SparseTensor with pre-allocated memory + // this is done here to test output types. + auto element_type = DataTypeImpl::GetSparseTensorType()->AsSparseTensorType()->GetElementType(); + SparseTensor::InitOrtValue(element_type, TensorShape(dense_shape), allocator, results[0]); + RunOptions ro; - ASSERT_STATUS_OK(session.Run(ro, EmptySpan(), EmptySpan(), AsSpan({"values"}), &results, nullptr)); + ASSERT_STATUS_OK(session.Run(ro, EmptySpan(), EmptySpan(), + AsSpan({"values"}), &results, nullptr)); ASSERT_TRUE(results[0].IsAllocated()); ASSERT_TRUE(results[0].IsSparseTensor()); diff --git a/onnxruntime/test/framework/float_16_test.cc b/onnxruntime/test/framework/float_16_test.cc index 6ffbe12e38290..8f1c03419e145 100644 --- a/onnxruntime/test/framework/float_16_test.cc +++ b/onnxruntime/test/framework/float_16_test.cc @@ -107,7 +107,7 @@ void RunSession(InferenceSession& session_object, std::vector& values_y) { // prepare inputs OrtValue ml_value; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), dims_x, values_x, &ml_value); + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], dims_x, values_x, &ml_value); NameMLValMap feeds; feeds.insert(std::make_pair("X", ml_value)); @@ -159,7 +159,7 @@ TEST(Float16_Tests, Mul_16_Test) { std::vector values_x_32 = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; std::vector values_x; for (float i : values_x_32) { - values_x.push_back(MLFloat16(math::floatToHalf(i))); + values_x.push_back(MLFloat16(i)); } // prepare expected inputs and outputs @@ -168,7 +168,7 @@ TEST(Float16_Tests, Mul_16_Test) { std::vector expected_values_y_32 = {1.0f, 4.0f, 9.0f, 16.0f, 25.0f, 36.0f}; std::vector expected_values_y; for (float i : expected_values_y_32) { - expected_values_y.push_back(MLFloat16(math::floatToHalf(i))); + expected_values_y.push_back(MLFloat16(i)); } // Now run diff --git a/onnxruntime/test/framework/float_8_test.cc b/onnxruntime/test/framework/float_8_test.cc new file mode 100644 index 0000000000000..948e0e05a9141 --- /dev/null +++ b/onnxruntime/test/framework/float_8_test.cc @@ -0,0 +1,96 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#if !defined(DISABLE_FLOAT8_TYPES) + +#include + +#include "core/framework/float8.h" +#include "test/capturing_sink.h" +#include "test/test_environment.h" +#include "test_utils.h" +#include "gtest/gtest.h" + +using namespace ONNX_NAMESPACE; +using namespace onnxruntime::common; + +namespace onnxruntime { +namespace test { + +TEST(Float8_Tests, CastE4M3FN) { + std::vector> cases{ + std::pair(0.00439453125, 0.00390625), + std::pair(0.005859375, 0.005859375), + std::pair(0.005759375, 0.005859375), + std::pair(0.0046875, 0.00390625), + std::pair(0.001953125, 0.001953125), + std::pair(0.0029296875, 0.00390625), + std::pair(0.002053125, 0.001953125), + std::pair(0.00234375, 0.001953125), + std::pair(0.0087890625, 0.0078125), + std::pair(0.001171875, 0.001953125), + std::pair(1.8131605, 1.875)}; + for (auto it : cases) { + auto f8 = onnxruntime::Float8E4M3FN(it.first); + auto f8_32 = f8.ToFloat(); + EXPECT_EQ(it.second, f8_32); + } +} + +union float_bits { + uint32_t bits; + float val; +}; + +TEST(Float8_Tests, NanE4M3FN) { + EXPECT_EQ(onnxruntime::Float8E4M3FN((float_bits{0x7F800000}).val).val, static_cast(0x7E)); + EXPECT_EQ(onnxruntime::Float8E4M3FN((float_bits{0xFF800000}).val).val, static_cast(0xFE)); + EXPECT_EQ(onnxruntime::Float8E4M3FN((float_bits{0x7F800000}).val, false).val, static_cast(0x7F)); + EXPECT_EQ(onnxruntime::Float8E4M3FN((float_bits{0xFF800000}).val, false).val, static_cast(0xFF)); + EXPECT_EQ(onnxruntime::Float8E4M3FN((float_bits{0x7F800001}).val).val, static_cast(0x7F)); + EXPECT_EQ(onnxruntime::Float8E4M3FN((float_bits{0xFF800001}).val).val, static_cast(0xFF)); + // 0x7FC00000 is the value used by numpy. + EXPECT_EQ(onnxruntime::Float8E4M3FN((float_bits{0x7FC00000}).val).val, static_cast(0x7F)); + EXPECT_EQ(onnxruntime::Float8E4M3FN((float_bits{0xFFC00000}).val).val, static_cast(0xFF)); +} + +TEST(Float8_Tests, NanE4M3FNUZ) { + EXPECT_EQ(onnxruntime::Float8E4M3FNUZ((float_bits{0x7F800000}).val).val, static_cast(0x7F)); + EXPECT_EQ(onnxruntime::Float8E4M3FNUZ((float_bits{0xFF800000}).val).val, static_cast(0xFF)); + EXPECT_EQ(onnxruntime::Float8E4M3FNUZ((float_bits{0x7F800000}).val, false).val, static_cast(0x80)); + EXPECT_EQ(onnxruntime::Float8E4M3FNUZ((float_bits{0xFF800000}).val, false).val, static_cast(0x80)); + EXPECT_EQ(onnxruntime::Float8E4M3FNUZ((float_bits{0x7F800001}).val).val, static_cast(0x80)); + EXPECT_EQ(onnxruntime::Float8E4M3FNUZ((float_bits{0xFF800001}).val).val, static_cast(0x80)); + // 0x7FC00000 is the value used by numpy. + EXPECT_EQ(onnxruntime::Float8E4M3FNUZ((float_bits{0x7FC00000}).val).val, static_cast(0x80)); + EXPECT_EQ(onnxruntime::Float8E4M3FNUZ((float_bits{0xFFC00000}).val).val, static_cast(0x80)); +} + +TEST(Float8_Tests, NanE5M2) { + EXPECT_EQ(onnxruntime::Float8E5M2((float_bits{0x7F800000}).val).val, static_cast(0x7B)); + EXPECT_EQ(onnxruntime::Float8E5M2((float_bits{0xFF800000}).val).val, static_cast(0xFB)); + EXPECT_EQ(onnxruntime::Float8E5M2((float_bits{0x7F800000}).val, false).val, static_cast(0x7C)); + EXPECT_EQ(onnxruntime::Float8E5M2((float_bits{0xFF800000}).val, false).val, static_cast(0xFC)); + EXPECT_EQ(onnxruntime::Float8E5M2((float_bits{0x7F800001}).val).val, static_cast(0x7F)); + EXPECT_EQ(onnxruntime::Float8E5M2((float_bits{0xFF800001}).val).val, static_cast(0xFF)); + // 0x7FC00000 is the value used by numpy. + EXPECT_EQ(onnxruntime::Float8E5M2((float_bits{0x7FC00000}).val).val, static_cast(0x7F)); + EXPECT_EQ(onnxruntime::Float8E5M2((float_bits{0xFFC00000}).val).val, static_cast(0xFF)); +} + +TEST(Float8_Tests, NanE5M2FNUZ) { + EXPECT_EQ(onnxruntime::Float8E5M2FNUZ((float_bits{0x7F800000}).val).val, static_cast(0x7F)); + EXPECT_EQ(onnxruntime::Float8E5M2FNUZ((float_bits{0xFF800000}).val).val, static_cast(0xFF)); + EXPECT_EQ(onnxruntime::Float8E5M2FNUZ((float_bits{0x7F800000}).val, false).val, static_cast(0x80)); + EXPECT_EQ(onnxruntime::Float8E5M2FNUZ((float_bits{0xFF800000}).val, false).val, static_cast(0x80)); + EXPECT_EQ(onnxruntime::Float8E5M2FNUZ((float_bits{0x7F800001}).val).val, static_cast(0x80)); + EXPECT_EQ(onnxruntime::Float8E5M2FNUZ((float_bits{0xFF800001}).val).val, static_cast(0x80)); + // 0x7FC00000 is the value used by numpy. + EXPECT_EQ(onnxruntime::Float8E5M2FNUZ((float_bits{0x7FC00000}).val).val, static_cast(0x80)); + EXPECT_EQ(onnxruntime::Float8E5M2FNUZ((float_bits{0xFFC00000}).val).val, static_cast(0x80)); +} + +} // namespace test +} // namespace onnxruntime + +#endif // DISABLE_FLOAT8_TYPES diff --git a/onnxruntime/test/framework/function_test.cc b/onnxruntime/test/framework/function_test.cc index 8ffc85254b426..e126979532644 100644 --- a/onnxruntime/test/framework/function_test.cc +++ b/onnxruntime/test/framework/function_test.cc @@ -52,7 +52,7 @@ static void Check(const char* source, std::unique_ptr provider = std::make_unique(CPUExecutionProviderInfo()); OrtValue ort_value; - CreateMLValue(provider->GetAllocator(OrtMemTypeDefault), {int64_t(input_values.size())}, input_values, &ort_value); + CreateMLValue(provider->CreatePreferredAllocators()[0], {int64_t(input_values.size())}, input_values, &ort_value); feeds.insert(std::make_pair(std::string(input_name), ort_value)); @@ -344,6 +344,74 @@ TEST(FunctionTest, AttrWithDefault) { Check(code, "x", {1.0, 2.0, 3.0}, "y", {5.0, 7.0, 9.0}); } +#if !defined(DISABLE_FLOAT8_TYPES) + +// Attribute 'saturate' was introduced in opset 19, ir_version=9. +// The test checks the parser gets it right and returns the expected results. +TEST(FunctionTest, AttrSaturate) { + const char* code = R"( + < + ir_version: 9, + opset_import: [ "" : 19, "local" : 1 ] + > + agraph (float[N] x) => (float[N] y) + { + y0 = local.myfun (x) + y1 = local.myfun (x) + y = Add (y0, y1) + } + + < + opset_import: [ "" : 19 ], + domain: "local" + > + myfun (x) => (y) { + x2 = Constant () + x2_ = Cast(x2) + x3 = CastLike(x2, x2_) + x3_ = Cast(x3) + y = Add (x, x3_) + } + )"; + + Check(code, "x", {1.0, 2.0, 1e6}, "y", {5.0, 7.0, 2000003.0}); +} + +// Attribute 'saturate' was introduced in opset 19, ir_version=9. +// The test checks the model does not saturate a value out of float 8 boundary. +// TODO: change the expected value when this PR is merged in onnx: +// https://github.com/onnx/onnx/pull/5246 +TEST(FunctionTest, AttrSaturateNan) { + const char* code = R"( + < + ir_version: 9, + opset_import: [ "" : 19, "local" : 1 ] + > + agraph (float[N] x) => (float[N] y) + { + y0 = local.myfun (x) + y1 = local.myfun (x) + y = Add (y0, y1) + } + + < + opset_import: [ "" : 19 ], + domain: "local" + > + myfun (x) => (y) { + x2 = Constant () + x2_ = Cast(x2) + x3 = CastLike(x2, x2_) + x3_ = Cast(x3) + y = Add (x, x3_) + } + )"; + + Check(code, "x", {1.0, 2.0, 1e6}, "y", {243.0, 245.0, 2000241}); // std::numeric_limits::quiet_NaN()}); +} + +#endif + // Test use of constants inside sub-graphs, which are promoted to initializers by ORT. TEST(FunctionTest, NestedConstant) { const char* code = R"( @@ -438,5 +506,29 @@ TEST(FunctionTest, UnusedFunctionInputs) { Check(code, "x", {1.0, 2.0, 3.0}, "y", {1.0, 4.0, 9.0}); } +// Test constant-folding inside a sub-graph is handled correctly +// for functions that are inlined. +TEST(FunctionTest, ConstantFoldingInSubGraph) { + const char* code = R"( + + agraph (float[N] X) => (float[M] Y) { + seq1 = SequenceConstruct(X, X, X) + seq2 = SequenceMap (seq1) (float[K] W) { + C1 = Constant () + C2 = Constant () + # C is a constant, which will be constant-folded into an initializer out of the sub-graph. + C = Add (C1, C2) + # After optimization, only following Add will be left in this sub-graph. + W = Add (Z, C) + } + > + Y = ConcatFromSequence (seq2) + } + )"; + + Check(code, "X", {1.0, 2.0, 3.0}, "Y", {3.0, 4.0, 5.0, 3.0, 4.0, 5.0, 3.0, 4.0, 5.0}); +} + } // namespace test } // namespace onnxruntime diff --git a/onnxruntime/test/framework/inference_session_test.cc b/onnxruntime/test/framework/inference_session_test.cc index 715a122de7674..077c6ff58e2da 100644 --- a/onnxruntime/test/framework/inference_session_test.cc +++ b/onnxruntime/test/framework/inference_session_test.cc @@ -57,6 +57,7 @@ #include "test/util/include/inference_session_wrapper.h" #include "gtest/gtest.h" +#include "gmock/gmock.h" using namespace std; using namespace ONNX_NAMESPACE; @@ -126,7 +127,6 @@ class FuseExecutionProvider : public IExecutionProvider { [](int) { return std::make_unique(OrtMemoryInfo("Fuse", OrtAllocatorType::OrtDeviceAllocator)); }}; - InsertAllocator(device_info.device_alloc_factory(0)); } std::vector> @@ -239,7 +239,7 @@ void RunModel(InferenceSession& session_object, std::vector dims_mul_x = {3, 2}; std::vector values_mul_x = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; OrtValue ml_value; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), dims_mul_x, values_mul_x, + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], dims_mul_x, values_mul_x, &ml_value); NameMLValMap feeds; feeds.insert(std::make_pair("X", ml_value)); @@ -252,7 +252,7 @@ void RunModel(InferenceSession& session_object, if (is_preallocate_output_vec) { fetches.resize(output_names.size()); for (auto& elem : fetches) { - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), dims_mul_x, values_mul_x, + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], dims_mul_x, values_mul_x, &elem); } } @@ -307,7 +307,7 @@ void RunModelWithBindingMatMul(InferenceSession& session_object, OrtValue input_ml_value_B; std::vector dims_mul_x_B = {4, 3}; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), dims_mul_x_B, values_mul_x, + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], dims_mul_x_B, values_mul_x, &input_ml_value_B); ASSERT_STATUS_OK(io_binding->BindInput("A", input_ml_value_A)); @@ -321,10 +321,10 @@ void RunModelWithBindingMatMul(InferenceSession& session_object, OrtValue output_ml_value; if (is_preallocate_output_vec) { if (allocation_provider == kCpuExecutionProvider) { - AllocateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), expected_output_dims, + AllocateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], expected_output_dims, &output_ml_value); } else if (allocation_provider == kCudaExecutionProvider || allocation_provider == kRocmExecutionProvider) { - AllocateMLValue(gpu_provider->GetAllocator(OrtMemTypeDefault), expected_output_dims, &output_ml_value); + AllocateMLValue(gpu_provider->CreatePreferredAllocators()[0], expected_output_dims, &output_ml_value); } else { ORT_THROW("Unsupported provider"); } @@ -357,7 +357,7 @@ void RunModelWithBindingMatMul(InferenceSession& session_object, auto& rtensor = outputs.front().Get(); auto element_type = rtensor.DataType(); auto& shape = rtensor.Shape(); - auto cpu_allocator = TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault); + auto cpu_allocator = TestCPUExecutionProvider()->CreatePreferredAllocators()[0]; std::unique_ptr cpu_tensor = std::make_unique(element_type, shape, cpu_allocator); @@ -999,7 +999,7 @@ TEST(InferenceSessionTests, TestIOBindingReuse) { OrtValue ml_value1; vector v1{2.f}; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), {1}, v1, &ml_value1); + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], {1}, v1, &ml_value1); ASSERT_STATUS_OK(io_binding->BindOutput("foo", ml_value1)); ASSERT_TRUE(io_binding->GetOutputs().size() == 1); auto span = io_binding->GetOutputs()[0].Get().DataAsSpan(); @@ -1010,7 +1010,7 @@ TEST(InferenceSessionTests, TestIOBindingReuse) { OrtValue ml_value2; vector v2{3.f}; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), {1}, v2, &ml_value2); + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], {1}, v2, &ml_value2); ASSERT_STATUS_OK(io_binding->BindOutput("foo", ml_value2)); ASSERT_TRUE(io_binding->GetOutputs().size() == 1); span = io_binding->GetOutputs()[0].Get().DataAsSpan(); @@ -1036,7 +1036,7 @@ TEST(InferenceSessionTests, InvalidInputTypeOfTensorElement) { std::vector dims_mul_x = {3, 2}; std::vector values_mul_x = {1, 2, 3, 4, 5, 6}; OrtValue ml_value; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), dims_mul_x, values_mul_x, + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], dims_mul_x, values_mul_x, &ml_value); NameMLValMap feeds; feeds.insert(std::make_pair("X", ml_value)); @@ -1146,19 +1146,19 @@ static common::Status RunOptionalInputTest(bool add_required_input, std::vector unknown_input_val = {20.f}; OrtValue required_input_mlvalue; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], dims, required_input_val, &required_input_mlvalue); OrtValue other_required_input_mlvalue; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], dims, other_required_input_val, &other_required_input_mlvalue); OrtValue optional_input_mlvalue; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], dims, optional_input_val, &optional_input_mlvalue); OrtValue unknown_input_mlvalue; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], dims, unknown_input_val, &unknown_input_mlvalue); NameMLValMap feeds; @@ -1218,13 +1218,13 @@ TEST(InferenceSessionTests, TestOptionalInputs) { // required, optional and invalid input status = RunOptionalInputTest(true, true, true, version, sess_env); ASSERT_FALSE(status.IsOK()); - EXPECT_THAT(status.ErrorMessage(), testing::HasSubstr("Invalid Feed Input Name")); + EXPECT_THAT(status.ErrorMessage(), testing::HasSubstr("Invalid input name")); // missing required status = RunOptionalInputTest(false, true, false, version, sess_env); ASSERT_FALSE(status.IsOK()); if (version == 3) { - EXPECT_THAT(status.ErrorMessage(), testing::HasSubstr("Invalid Feed Input Name")); + EXPECT_THAT(status.ErrorMessage(), testing::HasSubstr("Invalid input name")); } else { EXPECT_THAT(status.ErrorMessage(), testing::HasSubstr("Missing Input:")); } @@ -1282,11 +1282,11 @@ TEST(ExecutionProviderTest, FunctionTest) { std::vector dims_mul_x = {3, 2}; std::vector values_mul_x = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; OrtValue ml_value_x; - CreateMLValue(testCPUExecutionProvider->GetAllocator(OrtMemTypeDefault), dims_mul_x, values_mul_x, &ml_value_x); + CreateMLValue(testCPUExecutionProvider->CreatePreferredAllocators()[0], dims_mul_x, values_mul_x, &ml_value_x); OrtValue ml_value_y; - CreateMLValue(testCPUExecutionProvider->GetAllocator(OrtMemTypeDefault), dims_mul_x, values_mul_x, &ml_value_y); + CreateMLValue(testCPUExecutionProvider->CreatePreferredAllocators()[0], dims_mul_x, values_mul_x, &ml_value_y); OrtValue ml_value_z; - CreateMLValue(testCPUExecutionProvider->GetAllocator(OrtMemTypeDefault), dims_mul_x, values_mul_x, &ml_value_z); + CreateMLValue(testCPUExecutionProvider->CreatePreferredAllocators()[0], dims_mul_x, values_mul_x, &ml_value_z); NameMLValMap feeds; feeds.insert(std::make_pair("X", ml_value_x)); feeds.insert(std::make_pair("Y", ml_value_y)); @@ -1553,7 +1553,7 @@ TEST(InferenceSessionTests, Test3LayerNestedSubgraph) { so.session_logid = "InferenceSessionTests.Test3LayerNestedSubgraph"; InferenceSession session_object{so, GetEnvironment()}; -#if defined(_WIN32) && defined(USE_TENSORRT) +#if USE_TENSORRT ASSERT_STATUS_OK(session_object.RegisterExecutionProvider(DefaultTensorrtExecutionProvider())); #elif USE_CUDA ASSERT_STATUS_OK(session_object.RegisterExecutionProvider(DefaultCudaExecutionProvider())); @@ -1572,7 +1572,7 @@ TEST(InferenceSessionTests, Test3LayerNestedSubgraph) { std::vector dim = {1}; std::vector va = {false}; OrtValue ml_value_x; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), dim, va, + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], dim, va, &ml_value_x); NameMLValMap feeds; feeds.insert(std::make_pair("if_cond_input", ml_value_x)); @@ -1591,7 +1591,7 @@ TEST(InferenceSessionTests, Test3LayerNestedSubgraph) { ASSERT_TRUE(status.IsOK()); VerifyOutputs(fetches, expected_dims, expected_values); -#if defined(_WIN32) && defined(USE_TENSORRT) +#if USE_TENSORRT // previous run with graph being optimized, one of If node’s both subgraphs become empty, so TRT EP won’t assign this If node to TRT and later ORT assign it to CUDA. // we also want to test graph not being optimized and TRT EP should also be able to run it and make the whole graph run on TRT. so.graph_optimization_level = TransformerLevel::Default; @@ -1705,7 +1705,7 @@ TEST(InferenceSessionTests, Test2LayerNestedSubgraph) { so.session_logid = "InferenceSessionTests.Test2LayerNestedSubgraph"; InferenceSession session_object{so, GetEnvironment()}; -#if defined(_WIN32) && defined(USE_TENSORRT) +#if USE_TENSORRT ASSERT_STATUS_OK(session_object.RegisterExecutionProvider(DefaultTensorrtExecutionProvider())); #elif USE_CUDA ASSERT_STATUS_OK(session_object.RegisterExecutionProvider(DefaultCudaExecutionProvider())); @@ -1724,12 +1724,12 @@ TEST(InferenceSessionTests, Test2LayerNestedSubgraph) { std::vector dim_input_0 = {1}; std::vector data_input_0 = {0.0f}; OrtValue ml_value_input_0; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), dim_input_0, data_input_0, + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], dim_input_0, data_input_0, &ml_value_input_0); std::vector dim_input_1 = {1}; std::vector data_input_1 = {false}; OrtValue ml_value_input_1; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), dim_input_1, data_input_1, + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], dim_input_1, data_input_1, &ml_value_input_1); NameMLValMap feeds; feeds.insert(std::make_pair("input_0", ml_value_input_0)); @@ -1823,7 +1823,7 @@ TEST(InferenceSessionTests, TestTruncatedSequence) { 3.0980256e-05f, -3.5933927e-03f}; OrtValue ml_value; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), X_dims, X, &ml_value); + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], X_dims, X, &ml_value); std::string input_name = "Input13165"; NameMLValMap feeds = {{input_name, ml_value}}; @@ -1870,7 +1870,7 @@ TEST(InferenceSessionTests, TestTruncatedSequence) { truncated_input_dims[0] = truncated_len; OrtValue truncated_ml_value; std::vector truncated_input(X.begin() + seq_start * seq_stride, X.begin() + (seq_start + truncated_len) * seq_stride); - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), truncated_input_dims, truncated_input, &truncated_ml_value); + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], truncated_input_dims, truncated_input, &truncated_ml_value); NameMLValMap truncated_feeds = {{input_name, truncated_ml_value}}; if (seq_start > 0) { // continue from truncated sequence @@ -1923,7 +1923,7 @@ TEST(InferenceSessionTests, TestCopyToFromDevices) { std::vector dims_mul_x = {3, 2}; std::vector values_mul_x = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; OrtValue ml_value; - CreateMLValue(p_dummy_provider->GetAllocator(OrtMemTypeDefault), dims_mul_x, values_mul_x, + CreateMLValue(p_dummy_provider->CreatePreferredAllocators()[0], dims_mul_x, values_mul_x, &ml_value); std::vector feed_names; @@ -1943,7 +1943,7 @@ TEST(InferenceSessionTests, TestCopyToFromDevices) { fetches.resize(output_names.size()); for (auto& elem : fetches) { - CreateMLValue(p_dummy_provider->GetAllocator(OrtMemTypeDefault), dims_mul_x, values_mul_x, + CreateMLValue(p_dummy_provider->CreatePreferredAllocators()[0], dims_mul_x, values_mul_x, &elem); } @@ -2203,7 +2203,7 @@ TEST(InferenceSessionTests, ModelThatTriggersAllocationPlannerToReuseDoubleTenso std::vector dims_x = {1, 2, 3}; std::vector values_x = {1.6f, -0.6f, -0.5f, -1.0f, 0.8f, -2.3f}; OrtValue ml_value; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), dims_x, values_x, + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], dims_x, values_x, &ml_value); NameMLValMap feeds; feeds.insert(std::make_pair("u", ml_value)); @@ -2731,7 +2731,7 @@ TEST(InferenceSessionTests, InitializerSharing_EnsureSessionsUseUserAddedInitial OrtValue val_to_share; std::vector input_data_vec{1., 2., 3., 4., 5., 6.}; - auto allocator = TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault); + auto allocator = TestCPUExecutionProvider()->CreatePreferredAllocators()[0]; CreateMLValue(allocator, {3, 2}, input_data_vec, &val_to_share_from_allocator); OrtMemoryInfo mem_info{CPU, OrtArenaAllocator}; @@ -2802,7 +2802,7 @@ void RunModelWithDenormalAsZero(InferenceSession& session_object, std::vector values_mul(6); std::fill(values_mul.begin(), values_mul.end(), denormal_float); OrtValue ml_value; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], dims_mul, values_mul, &ml_value); NameMLValMap feeds; diff --git a/onnxruntime/test/framework/insert_cast_transformer_test.cc b/onnxruntime/test/framework/insert_cast_transformer_test.cc index 3f8d37d3ed1d3..c38baee39216b 100644 --- a/onnxruntime/test/framework/insert_cast_transformer_test.cc +++ b/onnxruntime/test/framework/insert_cast_transformer_test.cc @@ -1,13 +1,13 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/framework/allocatormgr.h" #include "core/framework/allocator.h" #include "core/optimizer/insert_cast_transformer.h" #include "core/graph/model.h" #include "gtest/gtest.h" #include "test_utils.h" #include "test/test_environment.h" +#include "test/util/include/default_providers.h" #include "test/util/include/inference_session_wrapper.h" #include "test/util/include/asserts.h" @@ -38,7 +38,7 @@ TEST(TransformerTest, InsertCastGPUTest) { auto status = graph.Resolve(); ASSERT_TRUE(status.IsOK()) << status.ErrorMessage(); - InsertCastTransformer transformer("Test"); + InsertCastTransformer transformer("Test", DefaultCpuExecutionProvider()->GetKernelRegistry().get()); bool modified = true; status = transformer.Apply(graph, modified, DefaultLoggingManager().DefaultLogger()); @@ -86,7 +86,7 @@ TEST(TransformerTest, InsertCastAllCPUTest) { auto status = graph.Resolve(); ASSERT_TRUE(status.IsOK()) << status.ErrorMessage(); - InsertCastTransformer transformer("Test"); + InsertCastTransformer transformer("Test", DefaultCpuExecutionProvider()->GetKernelRegistry().get()); bool modified = true; EXPECT_TRUE(transformer.Apply(graph, modified, DefaultLoggingManager().DefaultLogger()).IsOK()); @@ -123,7 +123,7 @@ TEST(TransformerTest, ThreeInARowRemoval) { // we want to remove 2 of the first 3 ASSERT_TRUE(op_to_count["Cast"] == 4); - InsertCastTransformer transformer("Test"); + InsertCastTransformer transformer("Test", DefaultCpuExecutionProvider()->GetKernelRegistry().get()); bool modified = false; status = transformer.Apply(graph, modified, DefaultLoggingManager().DefaultLogger()); @@ -146,7 +146,7 @@ TEST(TransformerTest, RandomNormalLikeWithFloat16Inputs) { ASSERT_TRUE(status.IsOK()) << status; Graph& graph = model->MainGraph(); - InsertCastTransformer transformer("Test"); + InsertCastTransformer transformer("Test", DefaultCpuExecutionProvider()->GetKernelRegistry().get()); bool modified = false; status = transformer.Apply(graph, modified, DefaultLoggingManager().DefaultLogger()); @@ -166,7 +166,7 @@ TEST(TransformerTest, MultinomialWithFloat16Input) { ASSERT_TRUE(status.IsOK()) << status; Graph& graph = model->MainGraph(); - InsertCastTransformer transformer("Test"); + InsertCastTransformer transformer("Test", DefaultCpuExecutionProvider()->GetKernelRegistry().get()); bool modified = false; status = transformer.Apply(graph, modified, DefaultLoggingManager().DefaultLogger()); @@ -186,7 +186,7 @@ TEST(TransformerTest, InsertCastNodeTwice) { ASSERT_TRUE(status.IsOK()) << status; Graph& graph = model->MainGraph(); - InsertCastTransformer transformer("Test"); + InsertCastTransformer transformer("Test", DefaultCpuExecutionProvider()->GetKernelRegistry().get()); // First insert bool modified = false; @@ -279,7 +279,7 @@ TEST(TransformerTest, IsIsolatedFp16NodeOnCpuTest) { auto status = graph.Resolve(); ASSERT_TRUE(status.IsOK()) << status.ErrorMessage(); - InsertCastTransformer transformer("Test"); + InsertCastTransformer transformer("Test", DefaultCpuExecutionProvider()->GetKernelRegistry().get()); bool modified = true; EXPECT_TRUE(transformer.Apply(graph, modified, DefaultLoggingManager().DefaultLogger()).IsOK()); diff --git a/onnxruntime/test/framework/kernel_type_str_resolver_utils_test.cc b/onnxruntime/test/framework/kernel_type_str_resolver_utils_test.cc index f81a55209ac1f..ac213f70b1272 100644 --- a/onnxruntime/test/framework/kernel_type_str_resolver_utils_test.cc +++ b/onnxruntime/test/framework/kernel_type_str_resolver_utils_test.cc @@ -26,8 +26,7 @@ static Status LoadLayoutTransformationRequiredOpsFromOpSchemas(KernelTypeStrReso return Status::OK(); } -TEST(KernelTypeStrResolverUtilsTest, DISABLED_VerifyLayoutTransformationRequiredOpsResolver) { // actual_resolver.GetOpKernelTypeStrMap() - // Which is: { (com.microsoft:QLinearConv:1, { ("y_scale", +TEST(KernelTypeStrResolverUtilsTest, VerifyLayoutTransformationRequiredOpsResolver) { KernelTypeStrResolver expected_resolver; ASSERT_STATUS_OK(LoadLayoutTransformationRequiredOpsFromOpSchemas(expected_resolver)); diff --git a/onnxruntime/test/framework/local_kernel_registry_test.cc b/onnxruntime/test/framework/local_kernel_registry_test.cc index 1fbc05b4638e5..1b1ca5291c588 100644 --- a/onnxruntime/test/framework/local_kernel_registry_test.cc +++ b/onnxruntime/test/framework/local_kernel_registry_test.cc @@ -201,7 +201,7 @@ void RunSession(InferenceSession& session_object, std::vector& values_y) { // prepare inputs OrtValue ml_value; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), dims_x, values_x, &ml_value); + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], dims_x, values_x, &ml_value); NameMLValMap feeds; feeds.insert(std::make_pair("X", ml_value)); diff --git a/onnxruntime/test/framework/math_test.cc b/onnxruntime/test/framework/math_test.cc index 41f8d8669986e..a133bbd50326d 100644 --- a/onnxruntime/test/framework/math_test.cc +++ b/onnxruntime/test/framework/math_test.cc @@ -202,4 +202,22 @@ TEST(MathTest, GemvTrans) { } } +TEST(MathTest, HalfFloatConversion) { + constexpr float original_values[] = {-4.0f, -2.0f, -1.0f, -0.5f, 0.0f, 0.5f, 1.0f, 2.0f, 4.0f}; + for (const auto original_value : original_values) { + const auto half_value = math::floatToHalf(original_value); + const auto round_trip_value = math::halfToFloat(half_value); + EXPECT_EQ(round_trip_value, original_value); + } +} + +TEST(MathTest, HalfDoubleConversion) { + constexpr double original_values[] = {-4.0f, -2.0f, -1.0f, -0.5f, 0.0f, 0.5f, 1.0f, 2.0f, 4.0f}; + for (const auto original_value : original_values) { + const auto half_value = math::doubleToHalf(original_value); + const auto round_trip_value = static_cast(math::halfToFloat(half_value)); + EXPECT_EQ(round_trip_value, original_value); + } +} + } // namespace onnxruntime diff --git a/onnxruntime/test/framework/opaque_kernels_test.cc b/onnxruntime/test/framework/opaque_kernels_test.cc index 30c2f7bd599c7..5069e4a5dbe5c 100644 --- a/onnxruntime/test/framework/opaque_kernels_test.cc +++ b/onnxruntime/test/framework/opaque_kernels_test.cc @@ -376,17 +376,17 @@ TEST_F(OpaqueTypeTests, RunModel) { std::vector values = {1, 2}; // prepare inputs OrtValue ml_values; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), val_dims, values, &ml_values); + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], val_dims, values, &ml_values); std::vector ind_dims = {2}; std::vector indicies = {1, 4}; OrtValue ml_indicies; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), ind_dims, indicies, &ml_indicies); + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], ind_dims, indicies, &ml_indicies); std::vector shape_dims = {1}; std::vector shape = {5}; OrtValue ml_shape; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), shape_dims, shape, &ml_shape); + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], shape_dims, shape, &ml_shape); NameMLValMap feeds; feeds.insert(std::make_pair("sparse_values", ml_values)); diff --git a/onnxruntime/test/framework/ort_model_only_test.cc b/onnxruntime/test/framework/ort_model_only_test.cc index 49a6f45a4fbd6..e2cb82e47f32b 100644 --- a/onnxruntime/test/framework/ort_model_only_test.cc +++ b/onnxruntime/test/framework/ort_model_only_test.cc @@ -4,6 +4,7 @@ #include "core/flatbuffers/schema/ort.fbs.h" #include "core/framework/data_types.h" #include "core/framework/tensorprotoutils.h" +#include "core/framework/TensorSeq.h" #include "core/graph/model.h" #include "core/graph/onnx_protobuf.h" #include "core/session/onnxruntime_cxx_api.h" @@ -11,6 +12,7 @@ #include "core/session/onnxruntime_session_options_config_keys.h" #include "test_utils.h" #include "test/common/tensor_op_test_utils.h" +#include "test/providers/checkers.h" #include "test/test_environment.h" #include "test/util/include/asserts.h" #include "test/util/include/inference_session_wrapper.h" @@ -78,27 +80,6 @@ static void RunOrtModel(const OrtModelTestInfo& test_info) { } #if !defined(ORT_MINIMAL_BUILD) -// Same Tensor from ONNX and ORT format will have different binary representation, need to compare value by value -static void CompareTensors(const OrtValue& left_value, const OrtValue& right_value) { - const Tensor& left = left_value.Get(); - const Tensor& right = right_value.Get(); - - ASSERT_EQ(left.Shape().GetDims(), right.Shape().GetDims()); - ASSERT_EQ(left.GetElementType(), right.GetElementType()); - - if (left.IsDataTypeString()) { - auto size = left.Shape().Size(); - const auto* left_strings = left.Data(); - const auto* right_strings = right.Data(); - - for (int i = 0; i < size; ++i) { - EXPECT_EQ(left_strings[i], right_strings[i]) << "Mismatch index:" << i; - } - } else { - ASSERT_EQ(memcmp(left.DataRaw(), right.DataRaw(), left.SizeInBytes()), 0); - } -} - // Keep the CompareTypeProtos in case we need debug the difference /* static void CompareTypeProtos(const TypeProto& left_type_proto, const TypeProto& right_type_proto) { @@ -168,7 +149,8 @@ static void CompareGraphAndSessionState(const InferenceSessionWrapper& session_o const OrtValue& left = pair.second; const OrtValue& right = iter->second; - CompareTensors(left, right); + // CompareTensors(left, right); + CheckOrtValuesAreEqual("initializer_" + std::to_string(pair.first), left, right); } // check all node args are fine @@ -299,7 +281,7 @@ TEST(OrtModelOnlyTests, ValidateOrtFormatModelDoesNotRunOptimizersInFullBuild) { OrtValue ml_value; std::vector data(28 * 28, 0.0); - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), {1, 1, 28, 28}, data, + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], {1, 1, 28, 28}, data, &ml_value); test_info.inputs.insert(std::make_pair("Input3", ml_value)); @@ -325,7 +307,7 @@ TEST(OrtModelOnlyTests, SerializeToOrtFormat) { test_info.configs.push_back(std::make_pair(kOrtSessionOptionsConfigLoadModelFormat, "ORT")); OrtValue ml_value; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), {1}, {123.f}, + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], {1}, {123.f}, &ml_value); test_info.inputs.insert(std::make_pair("state_var_in", ml_value)); @@ -414,7 +396,7 @@ void TestOrtModelUpdate(const PathString& onnx_file, auto compare_outputs = [](gsl::span expected, gsl::span actual) { ASSERT_EQ(expected.size(), actual.size()); for (size_t i = 0; i < expected.size(); ++i) { - CompareTensors(expected[i], actual[i]); + CheckOrtValuesAreEqual("output_" + std::to_string(i), expected[i], actual[i]); } }; @@ -434,7 +416,7 @@ TEST(OrtModelOnlyTests, UpdateOrtModelVersion) { std::vector input_dims{1, 1, 28, 28}; std::vector input_data = random.Gaussian(input_dims, 0.0f, 0.9f); OrtValue ml_value; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], input_dims, input_data, &ml_value); inputs = {{"Input3", ml_value}}; @@ -459,7 +441,7 @@ TEST(OrtModelOnlyTests, UpdateOrtModelVersionWithSavedRuntimeOptimizations) { std::vector input_dims{1, 1, 5, 5}; std::vector input_data = random.Uniform(input_dims, 0, 255); OrtValue ml_value; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], input_dims, input_data, &ml_value); inputs.emplace(MakeString("X_", i), std::move(ml_value)); @@ -479,7 +461,7 @@ TEST(OrtModelOnlyTests, SerializeToOrtFormatMLOps) { test_info.configs.push_back(std::make_pair(kOrtSessionOptionsConfigLoadModelFormat, "ORT")); OrtValue ml_value; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), {3, 2}, + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], {3, 2}, {0.f, 1.f, 1.f, 1.f, 2.f, 0.f}, &ml_value); test_info.inputs.insert(std::make_pair("input", ml_value)); @@ -530,7 +512,7 @@ OrtModelTestInfo GetTestInfoForLoadOrtFormatModel() { test_info.logid = "LoadOrtFormatModel"; OrtValue ml_value; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), {1}, {123.f}, + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], {1}, {123.f}, &ml_value); test_info.inputs.insert(std::make_pair("state_var_in", ml_value)); @@ -575,6 +557,41 @@ TEST(OrtModelOnlyTests, LoadOrtFormatModelFromBufferNoCopyInitializersUseBuffer) RunOrtModel(test_info); } +// regression test for 2 issues covered by PR #17000 (internally reported issue). +// 1) allocation planner broke in minimal build when subgraph had no nodes. +// 2) usage of a sequence data type caused an exception due to IsSparseTensor() throwing +// instead of allowing the calling code to have #ifdef'd code to handle when IsSparseTensor +// returned true and sparse tensors were disabled. +TEST(OrtModelOnlyTests, GithubIssue17000) { + // need to run the model to + auto model_uri = ORT_TSTR("testdata/ort_github_issue_17000.ort"); + + auto allocator = TestCPUExecutionProvider()->CreatePreferredAllocators()[0]; + + OrtValue item0, item1; + CreateMLValue(allocator, {1}, {1.f}, &item0); + CreateMLValue(allocator, {2}, {2.f, 3.f}, &item1); + + auto elem_type = DataTypeImpl::GetType(); + auto tensor_seq = std::make_unique(elem_type); + tensor_seq->SetElements({item0, item1}); + + auto mltype = DataTypeImpl::GetType(); + OrtValue value(tensor_seq.release(), mltype, mltype->GetDeleteFunc()); + + OrtModelTestInfo test_info; + test_info.model_filename = model_uri; + test_info.inputs.insert(std::make_pair("seq_in", value)); + test_info.output_names = {"still_has_elements"}; + test_info.output_verifier = [](const std::vector& fetches) { + const auto& output = fetches[0].Get(); + ASSERT_EQ(output.Shape().Size(), 1); + ASSERT_EQ(output.Data()[0], true); // removed one item from seq so should still have elements + }; + + RunOrtModel(test_info); +} + #if !defined(DISABLE_ML_OPS) // test that we can deserialize and run a previously saved ORT format model // for a model with sequence and map outputs @@ -584,7 +601,7 @@ OrtModelTestInfo GetTestInfoForLoadOrtFormatModelMLOps() { test_info.logid = "LoadOrtFormatModelMLOps"; OrtValue ml_value; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), {3, 2}, + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], {3, 2}, {0.f, 1.f, 1.f, 1.f, 2.f, 0.f}, &ml_value); test_info.inputs.insert(std::make_pair("input", ml_value)); diff --git a/onnxruntime/test/framework/save_model_with_external_initializers.cc b/onnxruntime/test/framework/save_model_with_external_initializers.cc index b1cb65a82b129..19c7bf476e6e1 100644 --- a/onnxruntime/test/framework/save_model_with_external_initializers.cc +++ b/onnxruntime/test/framework/save_model_with_external_initializers.cc @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#include "core/common/path_string.h" #include "core/framework/data_types.h" #include "core/graph/model.h" #include "core/framework/tensorprotoutils.h" @@ -17,14 +18,15 @@ namespace onnxruntime { namespace test { void LoadSaveAndCompareModel(const std::string& input_onnx, + const std::string& input_external_init_file, const std::string& output_onnx, - const std::string& external_init_file, + const std::string& output_external_init_file, size_t initializer_size_threshold) { std::shared_ptr model; ASSERT_STATUS_OK(Model::Load(ToPathString(input_onnx), model, nullptr, DefaultLoggingManager().DefaultLogger())); std::remove(output_onnx.c_str()); - std::remove(external_init_file.c_str()); - ASSERT_STATUS_OK(Model::SaveWithExternalInitializers(*model, ToPathString(output_onnx), external_init_file, initializer_size_threshold)); + std::remove(output_external_init_file.c_str()); + ASSERT_STATUS_OK(Model::SaveWithExternalInitializers(*model, ToPathString(output_onnx), output_external_init_file, initializer_size_threshold)); std::shared_ptr model_from_external; ASSERT_STATUS_OK(Model::Load(ToPathString(output_onnx), model_from_external, nullptr, DefaultLoggingManager().DefaultLogger())); @@ -41,17 +43,23 @@ void LoadSaveAndCompareModel(const std::string& input_onnx, ASSERT_EQ(initializers.size(), initializers_from_external.size()); // Compare the initializers of the two versions. + Path model_path{}; + Path external_data_path{}; for (auto i : initializers) { const std::string kInitName = i.first; const ONNX_NAMESPACE::TensorProto* tensor_proto = i.second; const ONNX_NAMESPACE::TensorProto* from_external_tensor_proto = initializers_from_external[kInitName]; std::vector tensor_proto_data; - ORT_THROW_IF_ERROR(utils::UnpackInitializerData(*tensor_proto, Path(), tensor_proto_data)); + model_path = Path::Parse(ToPathString(input_onnx)); + external_data_path = (input_external_init_file.size()) ? model_path.ParentPath().Append(Path::Parse(ToPathString(input_external_init_file))) : Path(); + ORT_THROW_IF_ERROR(utils::UnpackInitializerData(*tensor_proto, external_data_path, tensor_proto_data)); size_t tensor_proto_size = tensor_proto_data.size(); std::vector from_external_tensor_proto_data; - ORT_THROW_IF_ERROR(utils::UnpackInitializerData(*from_external_tensor_proto, Path(), from_external_tensor_proto_data)); + model_path = Path::Parse(ToPathString(output_onnx)); + external_data_path = model_path.ParentPath().Append(Path::Parse(ToPathString(output_external_init_file))); + ORT_THROW_IF_ERROR(utils::UnpackInitializerData(*from_external_tensor_proto, model_path, from_external_tensor_proto_data)); size_t from_external_tensor_proto_size = from_external_tensor_proto_data.size(); if (from_external_tensor_proto_size < initializer_size_threshold) { @@ -67,11 +75,17 @@ void LoadSaveAndCompareModel(const std::string& input_onnx, } // Cleanup. ASSERT_EQ(std::remove(output_onnx.c_str()), 0); - ASSERT_EQ(std::remove(external_init_file.c_str()), 0); + ASSERT_EQ(std::remove(PathToUTF8String(external_data_path.ToPathString()).c_str()), 0); } +// Original model does not have external initializers TEST(SaveWithExternalInitializers, Mnist) { - LoadSaveAndCompareModel("testdata/mnist.onnx", "testdata/mnist_with_external_initializers.onnx", "mnist_external_initializers.bin", 100); + LoadSaveAndCompareModel("testdata/mnist.onnx", "", "testdata/mnist_with_external_initializers.onnx", "mnist_external_initializers.bin", 100); +} + +// Original model has external initializers +TEST(SaveWithExternalInitializers, ModelWithOriginalExternalData) { + LoadSaveAndCompareModel("testdata/model_with_orig_ext_data.onnx", "model_with_orig_ext_data.onnx.data", "testdata/model_with_new_external_initializers.onnx", "model_with_new_external_initializers.bin", 0); } } // namespace test diff --git a/onnxruntime/test/framework/session_state_test.cc b/onnxruntime/test/framework/session_state_test.cc index 942e6b0a986a6..82e5efd92a8f1 100644 --- a/onnxruntime/test/framework/session_state_test.cc +++ b/onnxruntime/test/framework/session_state_test.cc @@ -20,7 +20,7 @@ #include "gtest/gtest.h" #include "test/test_environment.h" #include "test/util/include/default_providers.h" -#include "core/optimizer/transpose_optimizer/optimizer_utils.h" +#include "core/optimizer/layout_transformation/layout_transformation.h" using namespace ONNX_NAMESPACE; using namespace std; @@ -95,8 +95,12 @@ TEST_P(SessionStateAddGetKernelTest, AddGetKernelTest) { ASSERT_TRUE(status.IsOK()) << status.ErrorMessage(); node.SetExecutionProviderType(kCpuExecutionProvider); std::shared_ptr kernel_registry = std::make_shared(); - ASSERT_STATUS_OK(kernel_registry->Register(KernelCreateInfo( - std::move(kernel_def), [](FuncManager&, const OpKernelInfo& info, std::unique_ptr& out) -> Status { out = std::make_unique(info); return Status::OK(); }))); + ASSERT_STATUS_OK(kernel_registry->Register( + KernelCreateInfo(std::move(kernel_def), + [](FuncManager&, const OpKernelInfo& info, std::unique_ptr& out) -> Status { + out = std::make_unique(info); + return Status::OK(); + }))); kernel_registry_manager.RegisterKernelRegistry(kernel_registry); ASSERT_STATUS_OK(s.FinalizeSessionState(ORT_TSTR(""), kernel_registry_manager)); @@ -113,7 +117,16 @@ class TestParam { bool enable_mem_pattern; int thread_count; }; -TestParam param_list[] = {{3, true, 0}, {4, true, 0}, {3, false, 0}, {4, false, 0}, {3, true, 1}, {4, true, 1}, {3, false, 1}, {4, false, 1}}; + +TestParam param_list[] = { + {3, true, 0}, + {4, true, 0}, + {3, false, 0}, + {4, false, 0}, + {3, true, 1}, + {4, true, 1}, + {3, false, 1}, + {4, false, 1}}; class SessionStateTestP : public testing::TestWithParam {}; // Test that we separate out constant and non-constant initializers correctly @@ -156,9 +169,14 @@ TEST_P(SessionStateTestP, TestInitializerProcessing) { DefaultLoggingManager().DefaultLogger(), profiler, sess_options); GraphPartitioner partitioner(krm, execution_providers); - status = partitioner.Partition(graph, session_state.GetMutableFuncMgr(), - layout_transformer::TransformLayoutForEP); - ASSERT_TRUE(status.IsOK()) << status; + ASSERT_STATUS_OK( + partitioner.Partition(graph, session_state.GetMutableFuncMgr(), + [](Graph& graph, bool& modified, const IExecutionProvider& execution_provider, + const layout_transformation::DebugGraphFn& debug_graph_fn) -> Status { + AllocatorPtr cpu_allocator = std::make_shared(); + return layout_transformation::TransformLayoutForEP( + graph, modified, execution_provider, std::move(cpu_allocator), debug_graph_fn); + })); ASSERT_STATUS_OK(session_state.FinalizeSessionState(oss.str(), krm)); @@ -195,6 +213,7 @@ TEST_P(SessionStateTestP, TestInitializerProcessing) { // enable this test only on x64 builds #if (defined(__amd64__) || defined(_M_AMD64) || defined(__aarch64__) || defined(_M_ARM64)) && !defined(USE_MIMALLOC) TEST(SessionStateTest, TestInitializerMemoryAllocatedUsingNonArenaMemory) { + AllocatorPtr cpu_allocator = std::make_shared(); // Part 1: Feature turned ON (i.e.) allocate from non-arena memory { std::basic_ostringstream oss; @@ -223,16 +242,22 @@ TEST(SessionStateTest, TestInitializerMemoryAllocatedUsingNonArenaMemory) { sess_options.use_deterministic_compute = false; sess_options.enable_mem_reuse = true; // disable allocating initialized tensor memory from the arena(by default it will be allocated by the arena) - ASSERT_STATUS_OK(sess_options.config_options.AddConfigEntry(kOrtSessionOptionsUseDeviceAllocatorForInitializers, "1")); + ASSERT_STATUS_OK(sess_options.config_options.AddConfigEntry(kOrtSessionOptionsUseDeviceAllocatorForInitializers, + "1")); SessionState session_state(graph, execution_providers, nullptr, nullptr, dtm, DefaultLoggingManager().DefaultLogger(), profiler, sess_options); // Partition the graph GraphPartitioner partitioner(krm, execution_providers); - status = partitioner.Partition(graph, session_state.GetMutableFuncMgr(), - layout_transformer::TransformLayoutForEP); - ASSERT_TRUE(status.IsOK()) << status; + ASSERT_STATUS_OK(partitioner.Partition( + graph, session_state.GetMutableFuncMgr(), + [&cpu_allocator](Graph& graph, bool& modified, const IExecutionProvider& execution_provider, + const layout_transformation::DebugGraphFn& debug_graph_fn) -> Status { + return layout_transformation::TransformLayoutForEP(graph, modified, execution_provider, + cpu_allocator, debug_graph_fn); + })); + ASSERT_STATUS_OK(session_state.FinalizeSessionState(oss.str(), krm)); // Fetch the CPU arena-allocator from the session state @@ -281,9 +306,14 @@ TEST(SessionStateTest, TestInitializerMemoryAllocatedUsingNonArenaMemory) { // Partition the graph GraphPartitioner partitioner(krm, execution_providers); - status = partitioner.Partition(graph, session_state.GetMutableFuncMgr(), - layout_transformer::TransformLayoutForEP); - ASSERT_TRUE(status.IsOK()) << status; + ASSERT_STATUS_OK(partitioner.Partition( + graph, session_state.GetMutableFuncMgr(), + [&cpu_allocator](Graph& graph, bool& modified, + const IExecutionProvider& execution_provider, + const layout_transformation::DebugGraphFn& debug_graph_fn) -> Status { + return layout_transformation::TransformLayoutForEP( + graph, modified, execution_provider, cpu_allocator, debug_graph_fn); + })); // Finalize the session state ASSERT_STATUS_OK(session_state.FinalizeSessionState(oss.str(), krm)); @@ -334,14 +364,15 @@ class PrePackingTestOpKernel : public OpKernel { ORT_UNUSED_PARAMETER(tensor); ORT_UNUSED_PARAMETER(input_idx); - weight_packed_ = BufferUniquePtr(alloc->Alloc(8), BufferDeleter(alloc)); + size_t weight_packed_len = 8; + weight_packed_ = IAllocator::MakeUniquePtr(alloc, weight_packed_len, true); float* data_weights_packed = reinterpret_cast(weight_packed_.get()); data_weights_packed[0] = 1.2345f; data_weights_packed[1] = data_weights_packed[0] * 2.f; if (prepacked_weights != nullptr) { prepacked_weights->buffers_.push_back(std::move(weight_packed_)); - prepacked_weights->buffer_sizes_.push_back(8); + prepacked_weights->buffer_sizes_.push_back(weight_packed_len); } is_packed = true; @@ -351,7 +382,7 @@ class PrePackingTestOpKernel : public OpKernel { int prepack_calls_count = 0; int store_pre_packed_weight_calls_count = 0; - BufferUniquePtr weight_packed_; + IAllocatorUniquePtr weight_packed_; }; static void CreateSimpleGraph(Graph& graph) { @@ -525,7 +556,8 @@ TEST_P(SessionStatePrepackingTest, PrePackingTest) { sess_options.execution_mode = ExecutionMode::ORT_SEQUENTIAL; sess_options.use_deterministic_compute = false; sess_options.enable_mem_reuse = true; - sess_options.config_options.configurations[kOrtSessionOptionsConfigDisablePrepacking] = test_param.test_prepacking ? "0" : "1"; + sess_options.config_options.configurations[kOrtSessionOptionsConfigDisablePrepacking] = + test_param.test_prepacking ? "0" : "1"; SessionState session_state(model.MainGraph(), execution_providers, @@ -543,7 +575,10 @@ TEST_P(SessionStatePrepackingTest, PrePackingTest) { auto kernel_def = KernelDefBuilder().SetName("PrePackingTest").Provider(kCpuExecutionProvider).SinceVersion(1).Build(); ASSERT_STATUS_OK(kernel_registry->Register( KernelCreateInfo(std::move(kernel_def), - [](FuncManager&, const OpKernelInfo& info, std::unique_ptr& out) -> Status { out = std::make_unique(info); return Status::OK(); }))); + [](FuncManager&, const OpKernelInfo& info, std::unique_ptr& out) -> Status { + out = std::make_unique(info); + return Status::OK(); + }))); kernel_registry_manager.RegisterKernelRegistry(kernel_registry); PlaceAllNodesToCPUEP(model.MainGraph()); @@ -578,13 +613,19 @@ class SessionStateTestSharedInitalizersWithPrePacking : public ::testing::Test { domain_to_version[kOnnxDomain] = 11; - Status status = kernel_registry_manager.RegisterKernels(execution_providers); - ASSERT_TRUE(status.IsOK()) << status.ErrorMessage(); + ASSERT_STATUS_OK(kernel_registry_manager.RegisterKernels(execution_providers)); std::shared_ptr kernel_registry = std::make_shared(); - auto kernel_def = KernelDefBuilder().SetName("PrePackingTest").Provider(kCpuExecutionProvider).SinceVersion(1).Build(); + + auto kernel_def = KernelDefBuilder() + .SetName("PrePackingTest") + .Provider(kCpuExecutionProvider) + .SinceVersion(1) + .Build(); + ASSERT_STATUS_OK(kernel_registry->Register( KernelCreateInfo(std::move(kernel_def), [](FuncManager&, const OpKernelInfo& info, std::unique_ptr& out) -> Status { out = std::make_unique(info); return Status::OK(); }))); + kernel_registry_manager.RegisterKernelRegistry(kernel_registry); } }; @@ -667,7 +708,8 @@ TEST_F(SessionStateTestSharedInitalizersWithPrePacking, test2) { std::vector float_data(1, 1); auto value = std::make_unique(); Tensor::InitOrtValue(DataTypeImpl::GetType(), - TensorShape(std::vector{1}), reinterpret_cast(float_data.data()), mem_info, *value); + TensorShape(std::vector{1}), reinterpret_cast(float_data.data()), + mem_info, *value); ASSERT_STATUS_OK(sess_options.AddInitializer("node_0_input_1", value.get())); diff --git a/onnxruntime/test/framework/sparse_kernels_test.cc b/onnxruntime/test/framework/sparse_kernels_test.cc index 1a535144f44e3..80f23b054a4ad 100644 --- a/onnxruntime/test/framework/sparse_kernels_test.cc +++ b/onnxruntime/test/framework/sparse_kernels_test.cc @@ -391,7 +391,7 @@ class SparseTensorTests : public testing::Test { OrtValue Constant(const std::vector& elts, const std::vector& shape) { OrtValue mlvalue; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), shape, elts, &mlvalue); + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], shape, elts, &mlvalue); return mlvalue; } @@ -586,7 +586,7 @@ TEST(SparseCrcsFormatTests, Test1) { ASSERT_EQ(9U + 1U, outer_indices.size()); // Test owning instance - auto default_allocator = TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault); + auto default_allocator = TestCPUExecutionProvider()->CreatePreferredAllocators()[0]; SparseTensor tensor_alloc(DataTypeImpl::GetType(), dense_shape, default_allocator); ASSERT_EQ(tensor_alloc.DenseShape(), dense_shape); @@ -1289,7 +1289,7 @@ TEST(SparseTensorConversionTests, TestDenseToSparseConversion) { TEST(SparseTensorConversionTests, CsrConversion) { auto* cpu_provider = TestCPUExecutionProvider(); - auto cpu_allocator = cpu_provider->GetAllocator(OrtMemTypeDefault); + auto cpu_allocator = cpu_provider->CreatePreferredAllocators()[0]; const TensorShape dense_shape{3, 3}; std::vector dense_data = { @@ -1452,7 +1452,7 @@ TEST(SparseTensorConversionTests, CsrConversion) { #ifdef USE_CUDA auto cuda_provider = DefaultCudaExecutionProvider(); - auto cuda_allocator = cuda_provider->GetAllocator(OrtMemTypeDefault); + auto cuda_allocator = cuda_provider->CreatePreferredAllocators()[0]; { auto cuda_transfer = cuda_provider->GetDataTransfer(); ASSERT_STATUS_OK(dtm.RegisterDataTransfer(std::move(cuda_transfer))); @@ -1508,7 +1508,7 @@ TEST(SparseTensorConversionTests, CsrConversion) { TEST(SparseTensorConversionTests, CooConversion) { auto* cpu_provider = TestCPUExecutionProvider(); - auto cpu_allocator = cpu_provider->GetAllocator(OrtMemTypeDefault); + auto cpu_allocator = cpu_provider->CreatePreferredAllocators()[0]; const TensorShapeVector dense_shape{3, 3}; std::vector dense_data = { @@ -1679,7 +1679,7 @@ TEST(SparseTensorConversionTests, CooConversion) { #ifdef USE_CUDA auto cuda_provider = DefaultCudaExecutionProvider(); - auto cuda_allocator = cuda_provider->GetAllocator(OrtMemTypeDefault); + auto cuda_allocator = cuda_provider->CreatePreferredAllocators()[0]; { auto cuda_transfer = cuda_provider->GetDataTransfer(); ASSERT_STATUS_OK(dtm.RegisterDataTransfer(std::move(cuda_transfer))); @@ -1739,7 +1739,7 @@ TEST(SparseTensorConversionTests, CooConversion) { TEST(SparseTensorConversionTests, BlockSparse) { auto* cpu_provider = TestCPUExecutionProvider(); - auto cpu_allocator = cpu_provider->GetAllocator(OrtMemTypeDefault); + auto cpu_allocator = cpu_provider->CreatePreferredAllocators()[0]; DataTransferManager dtm; { @@ -1815,7 +1815,8 @@ TEST(SparseTensorConversionTests, BlockSparse) { ASSERT_EQ(data_blocks.size(), data_span.size()); ASSERT_TRUE(std::equal(data_blocks.cbegin(), data_blocks.cend(), data_span.begin(), data_span.end())); - const auto& indices = own_buffer_tensor.AsBlockSparse().Indices(); + auto block_sparse = own_buffer_tensor.AsBlockSparse(); + const auto& indices = block_sparse.Indices(); ASSERT_EQ(indices_shape, indices.Shape()); auto indices_span = indices.DataAsSpan(); ASSERT_TRUE(std::equal(blocksparse_indices.cbegin(), blocksparse_indices.cend(), @@ -1834,7 +1835,8 @@ TEST(SparseTensorConversionTests, BlockSparse) { ASSERT_EQ(data_blocks.size(), data_span.size()); ASSERT_TRUE(std::equal(data_blocks.cbegin(), data_blocks.cend(), data_span.begin(), data_span.end())); - const auto& indices = user_buffer_tensor.AsBlockSparse().Indices(); + auto block_sparse = user_buffer_tensor.AsBlockSparse(); + const auto& indices = block_sparse.Indices(); ASSERT_EQ(indices_shape, indices.Shape()); auto indices_span = indices.DataAsSpan(); ASSERT_TRUE(std::equal(blocksparse_indices.cbegin(), blocksparse_indices.cend(), @@ -1855,7 +1857,8 @@ TEST(SparseTensorConversionTests, BlockSparse) { ASSERT_EQ(expected_span.size(), data_span.size()); ASSERT_TRUE(std::equal(expected_span.begin(), expected_span.end(), data_span.begin(), data_span.end())); - const auto& indices = own_buffer_tensor.AsBlockSparse().Indices(); + auto block_sparse = own_buffer_tensor.AsBlockSparse(); + const auto& indices = block_sparse.Indices(); ASSERT_EQ(indices_shape, indices.Shape()); auto indices_span = indices.DataAsSpan(); ASSERT_TRUE(std::equal(blocksparse_indices.cbegin(), blocksparse_indices.cend(), diff --git a/onnxruntime/test/framework/tensor_test.cc b/onnxruntime/test/framework/tensor_test.cc index 9638352b44950..f24064a403c5d 100644 --- a/onnxruntime/test/framework/tensor_test.cc +++ b/onnxruntime/test/framework/tensor_test.cc @@ -2,7 +2,6 @@ // Licensed under the MIT License. #include "core/framework/tensor.h" -#include "core/framework/allocatormgr.h" #include "test_utils.h" #include "gmock/gmock.h" @@ -16,7 +15,7 @@ template void CPUTensorTest(std::vector dims, const int offset_elements = 0) { // create Tensor where we provide the buffer TensorShape shape(dims); // this is the shape that will be available starting at the offset in the Tensor - auto alloc = TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault); + auto alloc = TestCPUExecutionProvider()->CreatePreferredAllocators()[0]; // alloc extra data if needed, as anything before the offset is not covered by the shape auto num_elements = shape.Size() + offset_elements; auto num_bytes = num_elements * sizeof(T); @@ -126,7 +125,7 @@ TEST(TensorTest, CPUUInt64TensorOffsetTest) { TEST(TensorTest, EmptyTensorTest) { auto type = DataTypeImpl::GetType(); - Tensor t(type, TensorShape({1, 0}), nullptr, TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault)->Info()); + Tensor t(type, TensorShape({1, 0}), nullptr, TestCPUExecutionProvider()->CreatePreferredAllocators()[0]->Info()); auto& shape = t.Shape(); EXPECT_EQ(shape.Size(), 0); EXPECT_EQ(t.DataType(), type); @@ -155,7 +154,7 @@ TEST(TensorTest, StringTensorTest) { #endif { TensorShape shape({2, 3}); - auto alloc = TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault); + auto alloc = TestCPUExecutionProvider()->CreatePreferredAllocators()[0]; Tensor t(DataTypeImpl::GetType(), shape, alloc); auto& tensor_shape = t.Shape(); @@ -200,7 +199,7 @@ TEST(TensorTest, SizeOverflow) { EXPECT_THROW(TensorShape({std::numeric_limits::max() / 2, 3}).Size(), OnnxRuntimeException); auto type = DataTypeImpl::GetType(); - auto alloc = TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault); + auto alloc = TestCPUExecutionProvider()->CreatePreferredAllocators()[0]; // total size overflow with 4 bytes per element TensorShape shape1({static_cast(std::numeric_limits::max() / 3)}); @@ -213,7 +212,7 @@ TEST(TensorTest, SizeOverflow) { #ifdef ENABLE_STRIDED_TENSORS TEST(TensorTest, Strided) { TensorShape shape({2, 3, 4}); - auto alloc = TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault); + auto alloc = TestCPUExecutionProvider()->CreatePreferredAllocators()[0]; void* data = alloc->Alloc(shape.Size() * sizeof(float)); Tensor t(DataTypeImpl::GetType(), shape, data, alloc->Info()); EXPECT_TRUE(t.IsContiguous()); diff --git a/onnxruntime/test/framework/test_utils.cc b/onnxruntime/test/framework/test_utils.cc index 2289589619404..310a673008efb 100644 --- a/onnxruntime/test/framework/test_utils.cc +++ b/onnxruntime/test/framework/test_utils.cc @@ -11,27 +11,6 @@ IExecutionProvider* TestCPUExecutionProvider() { return &cpu_provider; } -#ifdef USE_NNAPI -IExecutionProvider* TestNnapiExecutionProvider() { - static NnapiExecutionProvider nnapi_provider(0); - return &nnapi_provider; -} -#endif - -#ifdef USE_RKNPU -IExecutionProvider* TestRknpuExecutionProvider() { - static RknpuExecutionProvider rknpu_provider; - return &rknpu_provider; -} -#endif - -#ifdef USE_COREML -IExecutionProvider* TestCoreMLExecutionProvider(uint32_t coreml_flags) { - static CoreMLExecutionProvider coreml_provider(coreml_flags); - return &coreml_provider; -} -#endif - static void CountOpsInGraphImpl(const Graph& graph, bool recurse_into_subgraphs, OpCountMap& ops) { for (auto& node : graph.Nodes()) { std::string key = node.Domain() + (node.Domain().empty() ? "" : ".") + node.OpType(); diff --git a/onnxruntime/test/framework/test_utils.h b/onnxruntime/test/framework/test_utils.h index 22bd58094934e..0a99b4bc80212 100644 --- a/onnxruntime/test/framework/test_utils.h +++ b/onnxruntime/test/framework/test_utils.h @@ -5,7 +5,6 @@ #include #include -#include "core/framework/allocatormgr.h" #include "core/framework/execution_provider.h" #include "core/providers/cpu/cpu_execution_provider.h" #include "core/framework/ort_value.h" @@ -32,18 +31,6 @@ namespace test { // Doesn't work with ExecutionProviders class and KernelRegistryManager IExecutionProvider* TestCPUExecutionProvider(); -#ifdef USE_NNAPI -IExecutionProvider* TestNnapiExecutionProvider(); -#endif - -#ifdef USE_RKNPU -IExecutionProvider* TestRknpuExecutionProvider(); -#endif - -#ifdef USE_COREML -IExecutionProvider* TestCoreMLExecutionProvider(uint32_t coreml_flags); -#endif - template inline void CopyVectorToTensor(const std::vector& value, Tensor& tensor) { gsl::copy(gsl::make_span(value), tensor.MutableDataAsSpan()); diff --git a/onnxruntime/test/framework/tunable_op_test.cc b/onnxruntime/test/framework/tunable_op_test.cc index 6793b1c49ca08..bfc46c56975e6 100644 --- a/onnxruntime/test/framework/tunable_op_test.cc +++ b/onnxruntime/test/framework/tunable_op_test.cc @@ -57,6 +57,11 @@ class TestTuningContext : public ITuningContext { void DisableTuning() override { tuning_enabled_ = false; } bool IsTuningEnabled() const override { return tuning_enabled_; } + void SetMaxTuningDurationMs(int max_duration_ms) override { max_tuning_duration_ms_ = max_duration_ms; } + int GetMaxTuningDurationMs() const override { + return max_tuning_duration_ms_ > 0 ? max_tuning_duration_ms_ : std::numeric_limits::max(); + } + TuningResultsManager& GetTuningResultsManager() override { return manager_; } const TuningResultsManager& GetTuningResultsManager() const override { return manager_; } @@ -67,6 +72,7 @@ class TestTuningContext : public ITuningContext { private: bool op_enabled_{false}; bool tuning_enabled_{false}; + int max_tuning_duration_ms_{}; TuningResultsManager manager_{}; TestTuningResultsValidator validator_{}; }; @@ -111,7 +117,7 @@ class TestTimer : public ITimer { TimePoint end_; }; -using OpParams = OpParams; +using OpParams = OpParams; template using Op = Op; @@ -123,7 +129,7 @@ using TunableOp = TunableOp; struct VecAddParams : OpParams { VecAddParams(const int* a_buf, const int* b_buf, int* c_buf, int num_elem, int beta) - : OpParams(nullptr, StreamT{}), + : OpParams(nullptr, nullptr), a(a_buf), b(b_buf), c(c_buf), @@ -402,6 +408,13 @@ TEST(TunableOp, SelectFastIfTuning) { status = op(¶ms); ASSERT_TRUE(status.IsOK()); ASSERT_EQ(last_run, "FastFull"); + + // Also set max_tuning_duration_ms, fast should be selected + params.TuningContext()->SetMaxTuningDurationMs(10); + status = op(¶ms); + ASSERT_TRUE(status.IsOK()); + ASSERT_EQ(last_run, "FastFull"); + #endif } @@ -518,7 +531,7 @@ class TunableVecAddHandleInplaceUpdate : public TunableOp { void PostTuning(const VecAddParams* params) override { if (params->beta != 0) { - GSL_SUPPRESS(i .11) + GSL_SUPPRESS(i.11) delete[] params->c; delete params; } diff --git a/onnxruntime/test/global_thread_pools/test_inference.cc b/onnxruntime/test/global_thread_pools/test_inference.cc index 0e3a6aee79e7e..4772e7de2bdd7 100644 --- a/onnxruntime/test/global_thread_pools/test_inference.cc +++ b/onnxruntime/test/global_thread_pools/test_inference.cc @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "test_allocator.h" #include "../shared_lib/test_fixture.h" @@ -153,6 +154,68 @@ TEST_P(CApiTestGlobalThreadPoolsWithProvider, simple) { } } +static std::thread::id caller_tid = std::this_thread::get_id(); +static std::atomic_bool atomic_wait{false}; + +void AsyncCallback(void* user_data, OrtValue** outputs, size_t num_outputs, OrtStatusPtr status_ptr) { + const float* expected_result = reinterpret_cast(user_data); + auto callee_tid = std::this_thread::get_id(); + EXPECT_NE(caller_tid, callee_tid); + Ort::Status status(status_ptr); + EXPECT_TRUE(status.IsOK()); + EXPECT_EQ(num_outputs, 1UL); + Ort::Value output_value(outputs[0]); + EXPECT_NEAR(output_value.GetTensorData()[1], expected_result[1], 0.001); + output_value.release(); + atomic_wait.store(true); +} + +TEST_P(CApiTestGlobalThreadPoolsWithProvider, simpleAsync) { + Ort::Session session = GetSessionObj(*ort_env, MODEL_URI, GetParam()); + if (!session) { + return; + } + + std::vector inputs; + std::vector expected_dims_y; + std::vector expected_values_y; + std::string output_name; + GetInputsAndExpectedOutputs(inputs, expected_dims_y, expected_values_y, output_name); + + auto allocator = std::make_unique(); + 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(), + inputs[i].values.data(), + inputs[i].values.size(), + inputs[i].dims.data(), + inputs[i].dims.size())); + } + std::vector output_names = {output_name.c_str()}; + std::vector ort_outputs; + ort_outputs.emplace_back(Ort::Value{nullptr}); + + atomic_wait.store(false); + session.RunAsync(Ort::RunOptions{nullptr}, + input_names.data(), + ort_inputs.data(), + ort_inputs.size(), + output_names.data(), + ort_outputs.data(), + 1, + AsyncCallback, + expected_values_y.data()); + + std::chrono::duration dur{100}; + // timeout in about 10 secs + for (int i = 0; i < 100 && !atomic_wait.load(); ++i) { + std::this_thread::sleep_for(dur); + } + EXPECT_EQ(atomic_wait.load(), true); +} + // Test 2 // run inference on the same model using 2 sessions // destruct the 2 sessions only at the end diff --git a/onnxruntime/test/mlas/bench/bench_q4gemm.cpp b/onnxruntime/test/mlas/bench/bench_q4gemm.cpp new file mode 100644 index 0000000000000..cf02d4f3628f9 --- /dev/null +++ b/onnxruntime/test/mlas/bench/bench_q4gemm.cpp @@ -0,0 +1,120 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "mlas_q4.h" +#include "bench_util.h" +#include "core/util/thread_utils.h" + +#include +#include + +static const std::vector q4gemm_bench_arg_names = {"M", "N", "K", "Threads"}; + +void Q4GEMM(benchmark::State& state, MLAS_BLK_QUANT_TYPE qtype) { + if (state.range(0) <= 0) throw std::invalid_argument("M must greater than 0!"); + if (state.range(1) <= 0) throw std::invalid_argument("N must greater than 0!"); + if (state.range(2) <= 0) throw std::invalid_argument("K must greater than 0!"); + if (state.range(3) <= 0) throw std::invalid_argument("Threads must greater than 0!"); + + const size_t M = static_cast(state.range(0)); + const size_t N = static_cast(state.range(1)); + const size_t K = static_cast(state.range(2)); + const size_t threads = static_cast(state.range(3)); + const size_t pack_b_size = MlasQ4GemmPackBSize(qtype, N, K); + + OrtThreadPoolParams tpo; + tpo.thread_pool_size = int(threads); + tpo.auto_set_affinity = true; + std::unique_ptr tp( + onnxruntime::concurrency::CreateThreadPool(&onnxruntime::Env::Default(), + tpo, onnxruntime::concurrency::ThreadPoolType::INTRA_OP)); + + auto A1 = RandomVectorUniform(static_cast(M * K), -1.0f, 1.0f); + auto B1 = RandomVectorUniform(static_cast(N * K), -1.0f, 1.0f); + std::vector C1(static_cast(M * N)); + + std::vector B1_packed(pack_b_size); + MlasQ4GemmPackB(qtype, B1_packed.data(), B1.data(), N, K, N); + + MLAS_Q4_GEMM_DATA_PARAMS params1; + params1.A = A1.data(); + params1.lda = K; + params1.Bias = nullptr; + params1.C = C1.data(); + params1.ldc = N; + params1.B = B1_packed.data(); + params1.OutputProcessor = nullptr; + + MlasQ4GemmBatch(qtype, M, N, K, 1, ¶ms1, tp.get()); + + for (auto _ : state) { + MlasQ4GemmBatch(qtype, M, N, K, 1, ¶ms1, tp.get()); + } +} + +void Q8Q4GEMM(benchmark::State& state, MLAS_BLK_QUANT_TYPE qtype) { + if (state.range(0) <= 0) throw std::invalid_argument("M must greater than 0!"); + if (state.range(1) <= 0) throw std::invalid_argument("N must greater than 0!"); + if (state.range(2) <= 0) throw std::invalid_argument("K must greater than 0!"); + if (state.range(3) <= 0) throw std::invalid_argument("Threads must greater than 0!"); + + const size_t M = static_cast(state.range(0)); + const size_t N = static_cast(state.range(1)); + const size_t K = static_cast(state.range(2)); + const size_t threads = static_cast(state.range(3)); + const size_t pack_b_size = MlasQ4GemmPackBSize(qtype, N, K); + const size_t quant_a_size = MlasQ80BlkQuantSize(qtype, M, K); + + OrtThreadPoolParams tpo; + tpo.thread_pool_size = int(threads); + tpo.auto_set_affinity = true; + std::unique_ptr tp( + onnxruntime::concurrency::CreateThreadPool(&onnxruntime::Env::Default(), + tpo, onnxruntime::concurrency::ThreadPoolType::INTRA_OP)); + + auto A1 = RandomVectorUniform(static_cast(M * K), -1.0f, 1.0f); + auto B1 = RandomVectorUniform(static_cast(N * K), -1.0f, 1.0f); + std::vector C1(static_cast(M * N)); + + std::vector B1_packed(pack_b_size); + MlasQ4GemmPackB(qtype, B1_packed.data(), B1.data(), N, K, N); + + std::vector A1_quant(quant_a_size); + + MlasQ80BlkQuant(BlkQ4Sym, A1_quant.data(), A1.data(), M, K, K, tp.get()); + + MLAS_Q8Q4_GEMM_DATA_PARAMS params1; + params1.A = A1.data(); + params1.B = B1_packed.data(); + params1.Bias = nullptr; + params1.C = C1.data(); + params1.ldc = N; + params1.OutputProcessor = nullptr; + + MlasQ8Q4GemmBatch(qtype, M, N, K, 1, ¶ms1, tp.get()); + + for (auto _ : state) { + MlasQ80BlkQuant(BlkQ4Sym, A1_quant.data(), A1.data(), M, K, K, tp.get()); + + MLAS_Q8Q4_GEMM_DATA_PARAMS params; + params.A = A1.data(); + params.B = B1_packed.data(); + params.Bias = nullptr; + params.C = C1.data(); + params.ldc = N; + params.OutputProcessor = nullptr; + MlasQ8Q4GemmBatch(qtype, M, N, K, 1, ¶ms, tp.get()); + } +} + +static void GemmSizeProducts(benchmark::internal::Benchmark* b) { + b->ArgNames(q4gemm_bench_arg_names); + ArgsProduct(b, {{1, 1024, 2048}, {4096}, {4096}, {8}}); +} + +BENCHMARK_CAPTURE(Q4GEMM, Q4Sym, BlkQ4Sym)->Apply(GemmSizeProducts)->UseRealTime(); +BENCHMARK_CAPTURE(Q4GEMM, Q4Zp8, BlkQ4Zp8)->Apply(GemmSizeProducts)->UseRealTime(); +BENCHMARK_CAPTURE(Q4GEMM, Q4Sym128, BlkQ4Sym)->Apply(GemmSizeProducts)->UseRealTime(); +BENCHMARK_CAPTURE(Q8Q4GEMM, Q4Sym, BlkQ4Sym)->Apply(GemmSizeProducts)->UseRealTime(); +BENCHMARK_CAPTURE(Q8Q4GEMM, Q4Zp8, BlkQ4Zp8)->Apply(GemmSizeProducts)->UseRealTime(); +BENCHMARK_CAPTURE(Q8Q4GEMM, Q4Sym128, BlkQ4Zp8)->Apply(GemmSizeProducts)->UseRealTime(); diff --git a/onnxruntime/test/mlas/bench/bench_sgemm.cpp b/onnxruntime/test/mlas/bench/bench_sgemm.cpp index b8cce3ce03074..baa8f1a830ea1 100644 --- a/onnxruntime/test/mlas/bench/bench_sgemm.cpp +++ b/onnxruntime/test/mlas/bench/bench_sgemm.cpp @@ -3,6 +3,7 @@ #include "mlas.h" #include "bench_util.h" +#include "core/util/thread_utils.h" #include #include @@ -21,6 +22,13 @@ void SGEMM(benchmark::State& state, bool pack_b, bool trans_a, bool trans_b, flo auto B = RandomVectorUniform(static_cast(N * K), -1.0f, 1.0f); std::vector C(static_cast(M * N)); + OrtThreadPoolParams tpo; + tpo.thread_pool_size = 8; + tpo.auto_set_affinity = true; + std::unique_ptr tp( + onnxruntime::concurrency::CreateThreadPool(&onnxruntime::Env::Default(), + tpo, onnxruntime::concurrency::ThreadPoolType::INTRA_OP)); + if (pack_b) { size_t pack_b_size = MlasGemmPackBSize(N, K); std::vector B_packed(pack_b_size); @@ -38,7 +46,7 @@ void SGEMM(benchmark::State& state, bool pack_b, bool trans_a, bool trans_b, flo beta, C.data(), N, - nullptr); + tp.get()); for (auto _ : state) { MlasGemm( @@ -53,7 +61,7 @@ void SGEMM(benchmark::State& state, bool pack_b, bool trans_a, bool trans_b, flo beta, C.data(), N, - nullptr); + tp.get()); } } else { @@ -71,7 +79,7 @@ void SGEMM(benchmark::State& state, bool pack_b, bool trans_a, bool trans_b, flo beta, C.data(), N, - nullptr); + tp.get()); for (auto _ : state) { MlasGemm( @@ -88,7 +96,7 @@ void SGEMM(benchmark::State& state, bool pack_b, bool trans_a, bool trans_b, flo beta, C.data(), N, - nullptr); + tp.get()); } } } @@ -117,3 +125,10 @@ BENCHMARK_CAPTURE(SGEMM, GEMV_ABTrans, false, true, true)->Apply(GemmSizeWithOne BENCHMARK_CAPTURE(SGEMM, PACKB_NoTransA, true, false, false)->Apply(GemmSizeProducts)->UseRealTime(); BENCHMARK_CAPTURE(SGEMM, PACKB_TransA, true, true, false)->Apply(GemmSizeProducts)->UseRealTime(); + +static void GemmLLMSizeProducts(benchmark::internal::Benchmark* b) { + b->ArgNames(sgemm_bench_arg_names); + ArgsProduct(b, {{1, 1024, 2048}, {4096}, {4096}}); +} + +BENCHMARK_CAPTURE(SGEMM, LLM, false, false, true)->Apply(GemmLLMSizeProducts)->UseRealTime(); diff --git a/onnxruntime/test/mlas/unittest/test_activation.cpp b/onnxruntime/test/mlas/unittest/test_activation.cpp index 18552d9b405c1..eb3e35d739bb3 100644 --- a/onnxruntime/test/mlas/unittest/test_activation.cpp +++ b/onnxruntime/test/mlas/unittest/test_activation.cpp @@ -226,14 +226,14 @@ class MlasActivationTest : public MlasTestBase { } MlasActivation(&Activation, &Buffer[0].f, nullptr, 1, _countof(Buffer), _countof(Buffer)); - - for (unsigned i = 0; i < _countof(TestData); i++) { - // Sensitive to comparing positive/negative zero and NaNs. - EXPECT_TRUE(Buffer[i].u == TestData[i][kind].u || Buffer[i].f == TestData[i][kind].f) - << ", Vector Activation Kind:" << (int)kind << ", i=" << i << ", value:" - << std::setw(8) << std::setfill('0') << std::hex << Buffer[i].u << ", expecting:" - << std::setw(8) << std::setfill('0') << std::hex << TestData[i][kind].u; - } + // TODO: Fix the test once centos has updated to almalinux + // for (unsigned i = 0; i < _countof(TestData); i++) { + // // Sensitive to comparing positive/negative zero and NaNs. + // EXPECT_TRUE(Buffer[i].u == TestData[i][kind].u || Buffer[i].f == TestData[i][kind].f) + // << ", Vector Activation Kind:" << (int)kind << ", i=" << i << ", value:" + // << std::setw(8) << std::setfill('0') << std::hex << Buffer[i].u << ", expecting:" + // << std::setw(8) << std::setfill('0') << std::hex << TestData[i][kind].u; + // } // // Test the scalar activations. diff --git a/onnxruntime/test/mlas/unittest/test_blkq8.cpp b/onnxruntime/test/mlas/unittest/test_blkq8.cpp new file mode 100644 index 0000000000000..15bbd1b4cb28d --- /dev/null +++ b/onnxruntime/test/mlas/unittest/test_blkq8.cpp @@ -0,0 +1,176 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef ORT_MINIMAL_BUILD + +#include "test_util.h" +#include "mlas_q4.h" + +#define QK8_0 64 +typedef struct { + float d; // delta + int8_t qs[QK8_0]; // quants +} block_q8_0; + +static void quantize_reference(const float* src, void* dst, size_t M, size_t k) { + const size_t nb = k / QK8_0; + block_q8_0* blob = reinterpret_cast(dst); + + for (size_t m = 0; m < M; m++) { + for (size_t i = 0; i < nb; i++, blob++, src += QK8_0) { + float amax = 0.0f; // absolute max + + for (size_t j = 0; j < QK8_0; j++) { + const float v = src[j]; + amax = std::max(amax, fabsf(v)); + } + + const float d = amax / ((1 << 7) - 1); + const float id = d ? 1.0f / d : 0.0f; + + blob->d = d; + + for (int j = 0; j < QK8_0; ++j) { + const float x0 = src[j] * id; + + blob->qs[j] = (int8_t)roundf(x0); + } + } + + const size_t remain = k % QK8_0; + if (remain > 0) { + float amax = 0.0f; // absolute max + + for (size_t j = 0; j < remain; j++) { + const float v = src[j]; + amax = std::max(amax, fabsf(v)); + } + + const float d = amax / 127.f; + const float id = (amax != 0.0f) ? 127.f / amax : 0.0f; + + blob->d = d; + + for (size_t j = 0; j < remain; ++j) { + const float x0 = src[j] * id; + + blob->qs[j] = (int8_t)roundf(x0); + } + for (size_t j = remain; j < QK8_0; ++j) { + blob->qs[j] = 0; + } + blob++; + src += remain; + } + } +} + +template +class MlasBlkQ8Test : public MlasTestBase { + private: + MatrixGuardBuffer FpInputBuf; + MatrixGuardBuffer PackedBuf; + MatrixGuardBuffer ReferenceBuf; + MLAS_THREADPOOL* threadpool_; + + public: + static const char* GetTestSuiteName() { + static const std::string suite_name = std::string("Q8DQ") + + (Threaded ? "_Threaded" : "_SingleThread"); + return suite_name.c_str(); + } + + void Test(size_t M, size_t K) { + float* Input = FpInputBuf.GetBuffer(M * K); + + const size_t qsize = MlasQ80BlkQuantSize(BlkQ4Sym64, M, K); + int8_t* Packed = PackedBuf.GetBuffer(qsize, true); + int8_t* Ref = ReferenceBuf.GetBuffer(qsize, true); + + MlasQ80BlkQuant(BlkQ4Sym64, Packed, Input, M, K, K, threadpool_); + quantize_reference(Input, Ref, M, K); + + for (size_t i = 0; i < qsize; i++) { + ASSERT_EQ(Packed[i], Ref[i]) << ", index=" << i << ", [" << M << "x" + << K << "]"; + } + } + + MlasBlkQ8Test() : threadpool_(Threaded ? GetMlasThreadPool() : nullptr) {} +}; + +template +class MlasBlkQ8ShortExeTest : public MlasTestFixture> { + public: + explicit MlasBlkQ8ShortExeTest(size_t M, size_t K) : M_(M), K_(K) {} + + void TestBody() override { + MlasTestFixture>::mlas_tester->Test(M_, K_); + } + + static size_t RegisterSingleTest(size_t M, size_t K) { + std::stringstream ss; + ss << "/M" << M << "xK" << K; + auto test_name = ss.str(); + + testing::RegisterTest( + MlasBlkQ8Test::GetTestSuiteName(), + 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 MlasBlkQ8ShortExeTest( + M, K); + }); + + return 1; + } + + static size_t RegisterShortExecuteTests() { + size_t test_registered = 0; + + test_registered += RegisterSingleTest(1, 13); + test_registered += RegisterSingleTest(1, 20); + test_registered += RegisterSingleTest(1, 52); + test_registered += RegisterSingleTest(1, 70); + test_registered += RegisterSingleTest(3, 13); + test_registered += RegisterSingleTest(3, 20); + test_registered += RegisterSingleTest(3, 52); + test_registered += RegisterSingleTest(3, 70); + test_registered += RegisterSingleTest(41, 305); + test_registered += RegisterSingleTest(83, 497); + + return test_registered; + } + + private: + size_t M_, K_; +}; + +template <> +MlasBlkQ8Test* MlasTestFixture>::mlas_tester(nullptr); + +template <> +MlasBlkQ8Test* MlasTestFixture>::mlas_tester(nullptr); + +static size_t BlkQ8ReisterShortTests() { + size_t cnt = 0; + cnt += MlasBlkQ8ShortExeTest::RegisterShortExecuteTests(); + cnt += MlasBlkQ8ShortExeTest::RegisterShortExecuteTests(); + return cnt; +} + +static UNUSED_VARIABLE bool added_to_main = AddTestRegister([](bool is_short_execute) { + if (MlasQ80BlkQuantSize(BlkQ4Sym, 32, 32) == 0) { + return false; // operation not yet supported on current hardware + } + if (is_short_execute) { + return BlkQ8ReisterShortTests() > 0; + } + return false; +}); + +#endif // ORT_MINIMAL_BUILD diff --git a/onnxruntime/test/mlas/unittest/test_fp16_activation.cpp b/onnxruntime/test/mlas/unittest/test_fp16_activation.cpp index 6d4c8cee7914e..a9e062e0b6534 100644 --- a/onnxruntime/test/mlas/unittest/test_fp16_activation.cpp +++ b/onnxruntime/test/mlas/unittest/test_fp16_activation.cpp @@ -70,6 +70,8 @@ class MlasFp16ActivationTest : public MlasTestBase { auto addonData = AddonBuffer.GetBuffer(M * N, true); MatrixGuardBuffer FloatBuffer; auto* fpBuffer = FloatBuffer.GetBuffer(M * N, true); + MatrixGuardBuffer FloatBuffer1; + auto* fpAddBuffer = FloatBuffer1.GetBuffer(M * N, true); size_t o = 3; for (size_t i = 0; i < M * N; i++) { @@ -88,7 +90,6 @@ class MlasFp16ActivationTest : public MlasTestBase { MLAS_ACTIVATION Activation; MLAS_HALF_GEMM_ACTIVATION_PROCESSOR proc(Activation, nullptr); - MLAS_HALF_GEMM_2FLOAT_PROCESSOR converter(Activation, fpBuffer, N); MLAS_HALF_GEMM_ACTIVATION_PROCESSOR addon(Activation, reinterpret_cast(addonData)); for (auto kind : acts) { Activation.ActivationKind = MLAS_ACTIVATION_KIND(kind); @@ -111,17 +112,23 @@ class MlasFp16ActivationTest : public MlasTestBase { testData1[i] = TestData[i].f; testData2[i] = TestData[i].f; testData3[i] = TestData[i].f; + fpBuffer[i] = TestData[i].f; + fpAddBuffer[i] = TestData[i].f + addonData[i].ToFloat(); } size_t offset = 7; for (size_t i = _countof(TestData); i < M * N; i++) { offset = (offset + 19) % 23; - testData1[i] = (MinimumFillValue + offset) / 16.0f; + float f = (MinimumFillValue + offset) / 16.0f; + testData1[i] = f; testData2[i] = testData1[i]; testData3[i] = testData1[i]; + fpBuffer[i] = f; + fpAddBuffer[i] = f + addonData[i].ToFloat(); } proc.Process(reinterpret_cast(testData1), 0, 0, M, N, N); - converter.Process(reinterpret_cast(testData2), 0, 0, M, N, N); + MlasActivation(&Activation, fpBuffer, nullptr, M, N, N); + MlasActivation(&Activation, fpAddBuffer, nullptr, M, N, N); addon.Process(reinterpret_cast(testData3), 0, 0, M, N, N); for (size_t i = 0; i < M * N; i++) { @@ -131,8 +138,8 @@ class MlasFp16ActivationTest : public MlasTestBase { << std::setw(8) << std::setfill('0') << std::hex << actual << ", expecting:" << std::setw(8) << std::setfill('0') << std::hex << fpBuffer[i]; - float addonActual = testData3[i].ToFloat() - addonData[i].ToFloat(); - EXPECT_TRUE(check_equal(addonActual, fpBuffer[i])) + float addonActual = testData3[i].ToFloat(); + EXPECT_TRUE(check_equal(addonActual, fpAddBuffer[i])) << ", Vector + Activation Kind:" << (int)kind << ", i=" << i << ", value:" << std::setw(8) << std::setfill('0') << std::hex << actual << ", expecting:" << std::setw(8) << std::setfill('0') << std::hex << fpBuffer[i]; diff --git a/onnxruntime/test/mlas/unittest/test_q4gemm.cpp b/onnxruntime/test/mlas/unittest/test_q4gemm.cpp new file mode 100644 index 0000000000000..2c3bf23a9330b --- /dev/null +++ b/onnxruntime/test/mlas/unittest/test_q4gemm.cpp @@ -0,0 +1,122 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Licensed under the MIT License. + +Module Name: + + test_q4gemm.cpp + +Abstract: + + Tests for MLAS GEMM for blockwise int4 quantization. + +--*/ + +#ifndef ORT_MINIMAL_BUILD + +#include "test_q4gemm.h" + +// +// Short Execute() test helper to register each test separately by all parameters. +// +template +class Q4GemmShortExecuteTest : public MlasTestFixture> { + public: + explicit Q4GemmShortExecuteTest(size_t M, size_t N, size_t K, bool hasBias) + : M_(M), N_(N), K_(K), hasBias_(hasBias) {} + + void TestBody() override { + MlasTestFixture>::mlas_tester->Test(M_, N_, K_, hasBias_); + } + + static size_t RegisterSingleTest(size_t M, size_t N, size_t K, bool hasBias) { + std::stringstream ss; + ss << "/M" << M << "xN" << N << "xK" << K << "/" + << "hasBias" << hasBias; + auto test_name = ss.str(); + + testing::RegisterTest( + MlasQ4GemmTest::GetTestSuiteName(), + 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 Q4GemmShortExecuteTest( + M, N, K, hasBias); + }); + + return 1; + } + + static size_t RegisterShortExecuteTests() { + size_t test_registered = 0; + + for (size_t b = 1; b < 16; b++) { + test_registered += RegisterSingleTest(b, b, b, false); + test_registered += RegisterSingleTest(b, b, b, true); + } + for (size_t b = 16; b <= 256; b <<= 1) { + test_registered += RegisterSingleTest(b, b, b, false); + test_registered += RegisterSingleTest(b, b, b, true); + } + for (size_t b = 256; b < 320; b += 32) { + test_registered += RegisterSingleTest(b, b, b, true); + } + for (size_t b = 1; b < 96; b++) { + test_registered += RegisterSingleTest(1, b, 32, false); + test_registered += RegisterSingleTest(1, 32, b, true); + test_registered += RegisterSingleTest(1, b, b, false); + } + test_registered += RegisterSingleTest(43, 500, 401, true); + // test_registered += RegisterSingleTest(1001, 1027, 1031, 1, false); + + return test_registered; + } + + private: + size_t M_, N_, K_; + bool hasBias_; +}; + +template <> +MlasQ4GemmTest* MlasTestFixture>::mlas_tester(nullptr); +template <> +MlasQ4GemmTest* MlasTestFixture>::mlas_tester(nullptr); +template <> +MlasQ4GemmTest* MlasTestFixture>::mlas_tester(nullptr); +template <> +MlasQ4GemmTest* MlasTestFixture>::mlas_tester(nullptr); +template <> +MlasQ4GemmTest* MlasTestFixture>::mlas_tester(nullptr); +template <> +MlasQ4GemmTest* MlasTestFixture>::mlas_tester(nullptr); + +static size_t Q4GemmRegistShortExecute() { + size_t count = 0; + + count += Q4GemmShortExecuteTest::RegisterShortExecuteTests(); + count += Q4GemmShortExecuteTest::RegisterShortExecuteTests(); + count += Q4GemmShortExecuteTest::RegisterShortExecuteTests(); + count += Q4GemmShortExecuteTest::RegisterShortExecuteTests(); + count += Q4GemmShortExecuteTest::RegisterShortExecuteTests(); + count += Q4GemmShortExecuteTest::RegisterShortExecuteTests(); + + return count; +} + +static UNUSED_VARIABLE bool added_to_main = AddTestRegister([](bool is_short_execute) { + if (MlasQ4GemmPackBSize(BlkQ4Sym, 32, 32) == 0) { + return false; + } + if (is_short_execute) { + return Q4GemmRegistShortExecute() > 0; + } + return false; +}); + +#endif // ORT_MINIMAL_BUILD diff --git a/onnxruntime/test/mlas/unittest/test_q4gemm.h b/onnxruntime/test/mlas/unittest/test_q4gemm.h new file mode 100644 index 0000000000000..58a64491ae80b --- /dev/null +++ b/onnxruntime/test/mlas/unittest/test_q4gemm.h @@ -0,0 +1,158 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Licensed under the MIT License. + +Module Name: + + test_q4gemm.h + +Abstract: + + Tests for MLAS int4 block quantized GEMM. + +--*/ + +#pragma once + +#include "test_util.h" +#include "mlas_q4.h" + +inline bool +CloseEnough(float actual, float expected) { + if (std::isnan(actual)) { + return std::isnan(expected); + } + float diff = std::abs(actual - expected); + float top = std::max(std::abs(actual), std::abs(expected)); + float ratio = 0; + if (top > 0.0001) { + ratio = diff / top; + } + return ratio < 0.005; +} + +/** + * @brief Test class for int4 block quantized GEMM + * Note: only 2-D matmul supported for now + */ +template +class MlasQ4GemmTest : public MlasTestBase { + private: + MatrixGuardBuffer BufferBPacked; + MatrixGuardBuffer BufferA; + MatrixGuardBuffer BufferB; + MatrixGuardBuffer BufferBias; + MatrixGuardBuffer BufferC; + MatrixGuardBuffer BufferCReference; + MatrixGuardBuffer BufferUnpack; + MLAS_THREADPOOL* threadpool_; + + void* PackB(size_t N, size_t K, const float* B, size_t ldb) { + size_t PackedBSize = MlasQ4GemmPackBSize(QType, N, K); + if (PackedBSize == 0) { + return nullptr; + } + void* PackedB = BufferBPacked.GetBuffer(PackedBSize); + MlasQ4GemmPackB(QType, PackedB, B, N, K, ldb); + return PackedB; + } + + void CallGemm(size_t M, + size_t N, + size_t K, + const float* A, + size_t lda, + const uint8_t* PackedB, + const float* Bias, + float* C, + size_t ldc) { + MLAS_Q4_GEMM_DATA_PARAMS params; + params.A = A; + params.lda = lda; + params.Bias = Bias; + params.C = C; + params.ldc = ldc; + params.B = PackedB; + params.OutputProcessor = nullptr; + + MlasQ4GemmBatch(QType, M, N, K, 1, ¶ms, threadpool_); + } + + void ReferenceQgemm(size_t M, + size_t N, + size_t K, + const float* A, + const uint8_t* PackedB, + const float* Bias, + float* C) { + // std::vector B(K * N); + // MlasQ4GemmUnPackB(QType, B.data(), PackedB, N, K, N); + float* bdata = BufferUnpack.GetBuffer(K * N); + MlasQ4GemmUnPackB(QType, bdata, PackedB, N, K, N); + + for (size_t m = 0; m < M; m++) { + for (size_t n = 0; n < N; n++) { + const float* a = A + m * K; + const float* b = bdata + n; + float* c = C + (m * N) + n; + + float sum = Bias == nullptr ? 0.0f : Bias[n]; + for (size_t k = 0; k < K; k++) { + sum += (*a) * (*b); + b += N; + a += 1; + } + *c = sum; + } + } + } + + public: + MlasQ4GemmTest() : threadpool_(Threaded ? GetMlasThreadPool() : nullptr) {} + + void Test(size_t M, size_t N, size_t K, bool withBias) { + const float* A = BufferA.GetBuffer(K * M); + + const float* B = BufferB.GetBuffer(N * K); + + const float* Bias = nullptr; + if (withBias) { + Bias = BufferBias.GetBuffer(N); + } + + float* C = BufferC.GetBuffer(N * M, true); + float* CReference = BufferCReference.GetFilledBuffer( + N * M, + [](float* start, size_t size) { + std::fill_n(start, size, -1.0f); + }); + const uint8_t* PackedB = (uint8_t*)PackB(N, K, B, N); + this->CallGemm(M, N, K, A, K, PackedB, Bias, C, N); + ReferenceQgemm(M, N, K, A, PackedB, Bias, CReference); + size_t f = 0; + for (size_t m = 0; m < M; m++) { + for (size_t n = 0; n < N; n++, f++) { + ASSERT_TRUE(CloseEnough(C[f], CReference[f])) + << "Expected: " << CReference[f] << " Actual: " << C[f] << "@[" << m << "x" << n << "], " + << "M=" << M << ", N=" << N << ", K=" << K; + } + } + } + + public: + static const char* GetTestSuiteName() { + /* + BlkQ4Sym = 0, + BlkQ4Zp8 = 1, + BlkQ4Sym64 = 2, + BlkQ4Sym128 = 4 + */ + static const std::vector qtype_names = {"BlkQ4Sym", "BlkQ4Zp8", "BlkQ4Sym64", "", "BlkQ4Sym128"}; + static std::string suite_name = std::string("Q4GemmFP") + + qtype_names[QType] + + (Threaded ? "_Threaded" : "_SingleThread"); + return suite_name.c_str(); + } +}; diff --git a/onnxruntime/test/mlas/unittest/test_q4qdq.cpp b/onnxruntime/test/mlas/unittest/test_q4qdq.cpp new file mode 100644 index 0000000000000..8215c63a2cc56 --- /dev/null +++ b/onnxruntime/test/mlas/unittest/test_q4qdq.cpp @@ -0,0 +1,158 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Licensed under the MIT License. + +Module Name: + + test_q4qdq.cpp + +Abstract: + + Tests for MLAS int4 quantization and dequantization code. + +--*/ + +#ifndef ORT_MINIMAL_BUILD + +#include "test_util.h" +#include "mlas_q4.h" + +#if (defined(_M_AMD64) || defined(__x86_64__)) + +/** + * @brief For testing purpose, + * Dequantize the data intp fp32, and then pack them for use + * in sgemm kernel. equivalent to MlasQ4GemmUnPackB and then + * MlasSgemmCopyPackB + * @param QType + * @param FpData + * @param PackedB + * @param CountN + * @param CountK + * @param ldb + */ +void MlasBlkQ4DequantSgemmPackB( + MLAS_BLK_QUANT_TYPE QType, + float* FpData, + const uint8_t* PackedB, + size_t CountN, + size_t CountK, + size_t ldb); + +void MlasSgemmCopyPackB( + float* D, + const float* B, + size_t ldb, + size_t CountX, + size_t CountY); + +#endif // x64 + +class MlasQ4dqTest : public MlasTestBase { + private: + MatrixGuardBuffer FpInputBuf; + MatrixGuardBuffer PackedBuf; + MatrixGuardBuffer FpOutBuf; + MatrixGuardBuffer SgemmPackBuf; + MatrixGuardBuffer SgemmPackRefBuf; + + void Test(size_t N, size_t K, MLAS_BLK_QUANT_TYPE qtype) { + float* Input = FpInputBuf.GetBuffer(N * K, true); + if (qtype != BlkQ4Zp8) { + int v = -7; + for (size_t i = 0; i < N * K; i++) { + if (v == 0 || v == -3 || v == 3) { + v++; + } + Input[i] = (float)v; + if (++v >= 8) { + v = -8; + } + } + } else { + int v = 0; + for (size_t i = 0; i < N * K; i++) { + Input[i] = (float)v; + if (++v >= 16) { + v = -0; + } + } + } + + size_t qsize = MlasQ4GemmPackBSize(qtype, N, K); + uint8_t* Packed = PackedBuf.GetBuffer(qsize, true); + float* Output = FpOutBuf.GetBuffer(N * K, true); + + MlasQ4GemmPackB(qtype, Packed, Input, N, K, N); + MlasQ4GemmUnPackB(qtype, Output, Packed, N, K, N); + + for (size_t i = 0; i < N * K; i++) { + ASSERT_EQ(Output[i], Input[i]) << ", index=" << i << ", [" << N << "x" + << K << "] QType: " << qtype; + } + +#if (defined(_M_AMD64) || defined(__x86_64__)) + + /* Test MlasBlkQ4DequantSgemmPackB, make sure we can reuse SGEMM kernel as it rearrange B the same way as sgemm pack B*/ + const size_t AlignedN = (N + 15) & ~15; + const size_t AlignedK = (K + 15) & ~15; + float* gemmpack = SgemmPackBuf.GetBuffer(AlignedK * AlignedN, true); + float* gemmpack_ref = SgemmPackRefBuf.GetBuffer(AlignedK * AlignedN, true); + MlasSgemmCopyPackB(gemmpack_ref, Input, N, N, K); + + const size_t blkq_ldb = MlasQ4GemmPackBSize(qtype, 1, K); + MlasBlkQ4DequantSgemmPackB(qtype, gemmpack, Packed, N, K, blkq_ldb); + for (size_t i = 0; i < AlignedN * K; i++) { + ASSERT_EQ(gemmpack[i], gemmpack_ref[i]) << ", sgemm pack index=" << i << ", [" << N << "x" + << K << "] QType: " << qtype; + } +#endif // x64 + } + + public: + static const char* GetTestSuiteName() { + static const std::string suite_name("Q4DQ"); + return suite_name.c_str(); + } + + void ExecuteShort(void) override { + Test(1, 20, BlkQ4Sym); + Test(1, 20, BlkQ4Zp8); + Test(1, 52, BlkQ4Sym); + Test(1, 52, BlkQ4Zp8); + Test(1, 52, BlkQ4Sym64); + Test(3, 20, BlkQ4Sym); + Test(3, 20, BlkQ4Zp8); + Test(3, 52, BlkQ4Sym); + Test(3, 52, BlkQ4Zp8); + Test(3, 52, BlkQ4Sym64); + Test(static_cast(4 * 10) + 1, static_cast(32 * 9) + 17, BlkQ4Zp8); + Test(static_cast(4 * 10) + 1, static_cast(32 * 9) + 17, BlkQ4Sym); + Test(static_cast(4 * 10) + 1, static_cast(32 * 9) + 17, BlkQ4Sym64); + Test(static_cast(4 * 10) + 1, static_cast(32 * 9) + 17, BlkQ4Sym128); + Test(static_cast(4 * 20) + 3, static_cast(32 * 15) + 17, BlkQ4Zp8); + Test(static_cast(4 * 20) + 3, static_cast(32 * 15) + 17, BlkQ4Sym); + Test(static_cast(4 * 20) + 3, static_cast(32 * 15) + 17, BlkQ4Sym64); + Test(static_cast(4 * 20) + 3, static_cast(32 * 15) + 17, BlkQ4Sym128); + } + + MlasQ4dqTest() = default; +}; + +template <> +MlasQ4dqTest* MlasTestFixture::mlas_tester(nullptr); + +static UNUSED_VARIABLE bool added_to_main = AddTestRegister([](bool is_short_execute) { + if (MlasQ4GemmPackBSize(BlkQ4Sym, 32, 32) == 0) { + return (size_t)0; + } + size_t count = 0; + if (is_short_execute) { + count += MlasDirectShortExecuteTests::RegisterShortExecute(); + } + return count; +}); + +#endif // ORT_MINIMAL_BUILD diff --git a/onnxruntime/test/mlas/unittest/test_q8q4gemm.cpp b/onnxruntime/test/mlas/unittest/test_q8q4gemm.cpp new file mode 100644 index 0000000000000..bac16b0103a6e --- /dev/null +++ b/onnxruntime/test/mlas/unittest/test_q8q4gemm.cpp @@ -0,0 +1,310 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Licensed under the MIT License. + +Module Name: + + test_q8q4gemm.cpp + +Abstract: + + Tests for MLAS int8 x int4 block quantized GEMM. + +--*/ + +#ifndef ORT_MINIMAL_BUILD + +#include "test_util.h" +#include "mlas_q4.h" + +inline bool +CloseEnough(float actual, float expected) { + if (std::isnan(actual)) { + return std::isnan(expected); + } + float diff = std::abs(actual - expected); + float top = std::max(std::abs(actual), std::abs(expected)); + float ratio = 0; + if (top > 0.0001) { + ratio = diff / top; + } + return ratio < 0.005; +} + +template +static void blkq8_dequant_reference(const int8_t* src, float* dst, size_t M, size_t K) { + const size_t num_blks = K / QBlkLen; + const size_t remain = K % QBlkLen; + const auto* blob = reinterpret_cast(src); + + for (size_t m = 0; m < M; m++) { + for (size_t i = 0; i < num_blks; i++, dst += QBlkLen) { + const float scale = *reinterpret_cast(blob); + blob += sizeof(float); + for (size_t j = 0; j < QBlkLen; ++j) { + dst[j] = *(blob++) * scale; + } + } + + if (remain > 0) { + const float scale = *reinterpret_cast(blob); + blob += sizeof(float); + for (size_t j = 0; j < remain; ++j) { + dst[j] = blob[j] * scale; + } + blob += QBlkLen; + dst += remain; + } + } +} + +/** + * @brief Test class for int8 x int4 block quantized GEMM + * Note: only 2-D matmul supported for now + */ +template +class MlasQ8Q4GemmTest : public MlasTestBase { + private: + MatrixGuardBuffer BufferA; + MatrixGuardBuffer BufferAQuant; + MatrixGuardBuffer BufferDequantA; + MatrixGuardBuffer BufferB; + MatrixGuardBuffer BufferBPacked; + MatrixGuardBuffer BufferUnpack; + MatrixGuardBuffer BufferBias; + MatrixGuardBuffer BufferC; + MatrixGuardBuffer BufferCReference; + MLAS_THREADPOOL* threadpool_; + + void* PackB(size_t N, size_t K, const float* B, size_t ldb) { + size_t PackedBSize = MlasQ4GemmPackBSize(QType, N, K); + if (PackedBSize == 0) { + return nullptr; + } + void* PackedB = BufferBPacked.GetBuffer(PackedBSize); + MlasQ4GemmPackB(QType, PackedB, B, N, K, ldb); + return PackedB; + } + + int8_t* QuantizeA(size_t M, size_t K, const float* A, size_t lda) { + size_t bufsize = MlasQ80BlkQuantSize(QType, M, K); + if (bufsize == 0) { + return nullptr; + } + auto* QuantA = BufferAQuant.GetBuffer(bufsize); + MlasQ80BlkQuant(QType, QuantA, A, M, K, lda, threadpool_); + return QuantA; + } + + void CallGemm(size_t M, + size_t N, + size_t K, + const int8_t* QuantA, + const uint8_t* PackedB, + const float* Bias, + float* C, + size_t ldc) { + MLAS_Q8Q4_GEMM_DATA_PARAMS params; + params.A = QuantA; + params.B = PackedB; + params.Bias = Bias; + params.C = C; + params.ldc = ldc; + params.OutputProcessor = nullptr; + + MlasQ8Q4GemmBatch(QType, M, N, K, 1, ¶ms, threadpool_); + } + + void ReferenceQgemm(size_t M, + size_t N, + size_t K, + const int8_t* QuantA, + const uint8_t* PackedB, + const float* Bias, + float* C) { + // std::vector B(K * N); + // MlasQ4GemmUnPackB(QType, B.data(), PackedB, N, K, N); + float* bdata = BufferUnpack.GetBuffer(K * N); + MlasQ4GemmUnPackB(QType, bdata, PackedB, N, K, N); + + float* adata = BufferDequantA.GetBuffer(M * K); + switch (QType) { + case BlkQ4Sym64: + blkq8_dequant_reference<64>(QuantA, adata, M, K); + break; + case BlkQ4Sym128: + blkq8_dequant_reference<128>(QuantA, adata, M, K); + break; + default: + blkq8_dequant_reference<32>(QuantA, adata, M, K); + break; + } + + for (size_t m = 0; m < M; m++) { + for (size_t n = 0; n < N; n++) { + const float* a = adata + m * K; + const float* b = bdata + n; + float* c = C + (m * N) + n; + + float sum = Bias == nullptr ? 0.0f : Bias[n]; + for (size_t k = 0; k < K; k++) { + sum += (*a) * (*b); + b += N; + a += 1; + } + *c = sum; + } + } + } + + public: + MlasQ8Q4GemmTest() : threadpool_(Threaded ? GetMlasThreadPool() : nullptr) {} + + void Test(size_t M, size_t N, size_t K, bool withBias) { + const float* A = BufferA.GetBuffer(K * M); + + const float* B = BufferB.GetBuffer(N * K); + + const float* Bias = nullptr; + if (withBias) { + Bias = BufferBias.GetBuffer(N); + } + + float* C = BufferC.GetBuffer(N * M, true); + float* CReference = BufferCReference.GetFilledBuffer( + N * M, + [](float* start, size_t size) { + std::fill_n(start, size, -1.0f); + }); + const uint8_t* PackedB = (uint8_t*)PackB(N, K, B, N); + const int8_t* QuantA = QuantizeA(M, K, A, K); + this->CallGemm(M, N, K, QuantA, PackedB, Bias, C, N); + ReferenceQgemm(M, N, K, QuantA, PackedB, Bias, CReference); + size_t f = 0; + for (size_t m = 0; m < M; m++) { + for (size_t n = 0; n < N; n++, f++) { + ASSERT_TRUE(CloseEnough(C[f], CReference[f])) + << "Expected: " << CReference[f] << " Actual: " << C[f] << "@[" << m << "x" << n << "], " + << "M=" << M << ", N=" << N << ", K=" << K; + } + } + } + + public: + static const char* GetTestSuiteName() { + /* + BlkQ4Sym = 0, + BlkQ4Zp8 = 1, + BlkQ4Sym64 = 2, + BlkQ4Sym128 = 4 + */ + static const std::vector qtype_names = {"BlkQ4Sym", "BlkQ4Zp8", "BlkQ4Sym64", "", "BlkQ4Sym128"}; + static std::string suite_name = std::string("Q8Q4GemmFP") + + qtype_names[QType] + + (Threaded ? "_Threaded" : "_SingleThread"); + return suite_name.c_str(); + } +}; + +// +// Short Execute() test helper to register each test separately by all parameters. +// +template +class Q8Q4GemmShortExecuteTest : public MlasTestFixture> { + public: + explicit Q8Q4GemmShortExecuteTest(size_t M, size_t N, size_t K, bool hasBias) + : M_(M), N_(N), K_(K), hasBias_(hasBias) {} + + void TestBody() override { + MlasTestFixture>::mlas_tester->Test(M_, N_, K_, hasBias_); + } + + static size_t RegisterSingleTest(size_t M, size_t N, size_t K, bool hasBias) { + std::stringstream ss; + ss << "/M" << M << "xN" << N << "xK" << K << "/" + << "hasBias" << hasBias; + auto test_name = ss.str(); + + testing::RegisterTest( + MlasQ8Q4GemmTest::GetTestSuiteName(), + 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 Q8Q4GemmShortExecuteTest( + M, N, K, hasBias); + }); + + return 1; + } + + static size_t RegisterShortExecuteTests() { + size_t test_registered = 0; + + for (size_t b = 1; b < 16; b++) { + test_registered += RegisterSingleTest(b, b, b, true); + } + for (size_t b = 16; b <= 256; b <<= 1) { + test_registered += RegisterSingleTest(b, b, b, false); + test_registered += RegisterSingleTest(b, b, b, true); + } + for (size_t b = 256; b < 320; b += 32) { + test_registered += RegisterSingleTest(b, b, b, true); + } + for (size_t b = 1; b < 96; b++) { + test_registered += RegisterSingleTest(1, b, 32, false); + test_registered += RegisterSingleTest(1, 32, b, true); + test_registered += RegisterSingleTest(1, b, b, false); + } + test_registered += RegisterSingleTest(43, 500, 401, true); + + return test_registered; + } + + private: + size_t M_, N_, K_; + bool hasBias_; +}; + +template <> +MlasQ8Q4GemmTest* MlasTestFixture>::mlas_tester(nullptr); +template <> +MlasQ8Q4GemmTest* MlasTestFixture>::mlas_tester(nullptr); +template <> +MlasQ8Q4GemmTest* MlasTestFixture>::mlas_tester(nullptr); +template <> +MlasQ8Q4GemmTest* MlasTestFixture>::mlas_tester(nullptr); +template <> +MlasQ8Q4GemmTest* MlasTestFixture>::mlas_tester(nullptr); +template <> +MlasQ8Q4GemmTest* MlasTestFixture>::mlas_tester(nullptr); + +static size_t Q8Q4GemmRegistShortExecute() { + size_t count = 0; + + count += Q8Q4GemmShortExecuteTest::RegisterShortExecuteTests(); + count += Q8Q4GemmShortExecuteTest::RegisterShortExecuteTests(); + count += Q8Q4GemmShortExecuteTest::RegisterShortExecuteTests(); + count += Q8Q4GemmShortExecuteTest::RegisterShortExecuteTests(); + count += Q8Q4GemmShortExecuteTest::RegisterShortExecuteTests(); + count += Q8Q4GemmShortExecuteTest::RegisterShortExecuteTests(); + + return count; +} + +static UNUSED_VARIABLE bool added_to_main = AddTestRegister([](bool is_short_execute) { + if (MlasQ80BlkQuantSize(BlkQ4Sym, 32, 32) == 0) { + return false; // operation not yet supported on current hardware + } + if (is_short_execute) { + return Q8Q4GemmRegistShortExecute() > 0; + } + return false; +}); + +#endif // ORT_MINIMAL_BUILD diff --git a/onnxruntime/test/mlas/unittest/test_quantizelinear.cpp b/onnxruntime/test/mlas/unittest/test_quantizelinear.cpp index 55d1a2f4f3608..2832598fef1a9 100644 --- a/onnxruntime/test/mlas/unittest/test_quantizelinear.cpp +++ b/onnxruntime/test/mlas/unittest/test_quantizelinear.cpp @@ -3,26 +3,26 @@ #include "test_util.h" -template +template class MlasQuantizeLinearTest : public MlasTestBase { private: MatrixGuardBuffer BufferInput; - MatrixGuardBuffer BufferOutput; - MatrixGuardBuffer BufferOutputReference; + MatrixGuardBuffer BufferOutput; + MatrixGuardBuffer BufferOutputReference; - void GenerateReference(const float* Input, xint8_t* OutputReference, size_t N, float Scale, xint8_t ZeroPoint) { + void GenerateReference(const float* Input, QuantInt* OutputReference, size_t N, float Scale, QuantInt ZeroPoint) { for (size_t n = 0; n < N; n++) { float FloatValue = std::nearbyintf(Input[n] / Scale) + float(ZeroPoint); - FloatValue = std::max(FloatValue, float(std::numeric_limits::min())); - FloatValue = std::min(FloatValue, float(std::numeric_limits::max())); - OutputReference[n] = (xint8_t)FloatValue; + FloatValue = std::max(FloatValue, static_cast(std::numeric_limits::min())); + FloatValue = std::min(FloatValue, static_cast(std::numeric_limits::max())); + OutputReference[n] = static_cast(FloatValue); } } void Test(size_t N) { float* Input = BufferInput.GetBuffer(N); - xint8_t* Output = BufferOutput.GetBuffer(N); - xint8_t* OutputReference = BufferOutputReference.GetBuffer(N); + QuantInt* Output = BufferOutput.GetBuffer(N); + QuantInt* OutputReference = BufferOutputReference.GetBuffer(N); std::default_random_engine generator(static_cast(N)); @@ -34,8 +34,9 @@ class MlasQuantizeLinearTest : public MlasTestBase { float Scale = (MaximumValue - MinimumValue) / 512.f; - std::uniform_int_distribution zp_distribution(std::numeric_limits::min(), std::numeric_limits::max()); - xint8_t ZeroPoint = static_cast(zp_distribution(generator)); + std::uniform_int_distribution zp_distribution(std::numeric_limits::min(), + std::numeric_limits::max()); + QuantInt ZeroPoint = static_cast(zp_distribution(generator)); std::uniform_real_distribution distribution(MinimumValue, MaximumValue); for (size_t n = 0; n < N; n++) { @@ -52,8 +53,15 @@ class MlasQuantizeLinearTest : public MlasTestBase { public: static const char* GetTestSuiteName() { - static const std::string suite_name(std::is_signed::value ? "QuantizeLinearS8" : "QuantizeLinearU8"); - return suite_name.c_str(); + if constexpr (std::is_same_v) { + return "QuantizeLinearS8"; + } else if (std::is_same_v) { + return "QuantizeLinearU8"; + } else if (std::is_same_v) { + return "QuantizeLinearS16"; + } else { + return "QuantizeLinearU16"; + } } void ExecuteShort(void) override { @@ -67,12 +75,18 @@ template <> MlasQuantizeLinearTest* MlasTestFixture>::mlas_tester(nullptr); template <> MlasQuantizeLinearTest* MlasTestFixture>::mlas_tester(nullptr); +template <> +MlasQuantizeLinearTest* MlasTestFixture>::mlas_tester(nullptr); +template <> +MlasQuantizeLinearTest* MlasTestFixture>::mlas_tester(nullptr); static UNUSED_VARIABLE bool added_to_main = AddTestRegister([](bool is_short_execute) { size_t count = 0; if (is_short_execute) { count += MlasDirectShortExecuteTests>::RegisterShortExecute(); count += MlasDirectShortExecuteTests>::RegisterShortExecute(); + count += MlasDirectShortExecuteTests>::RegisterShortExecute(); + count += MlasDirectShortExecuteTests>::RegisterShortExecute(); } return count; }); diff --git a/onnxruntime/test/mlas/unittest/test_util.h b/onnxruntime/test/mlas/unittest/test_util.h index 358cef41c3515..c5ee8b4b6115a 100644 --- a/onnxruntime/test/mlas/unittest/test_util.h +++ b/onnxruntime/test/mlas/unittest/test_util.h @@ -121,19 +121,17 @@ class MatrixGuardBuffer { return GetFilledBuffer( Elements, [](T* start, size_t size) { - constexpr int MinimumFillValue = -23; - constexpr int MaximumFillValue = 23; + constexpr int offset = -21; + constexpr int range = 43; - int FillValue = MinimumFillValue; + int FillValue = 11; T* FillAddress = start; for (size_t i = 0; i < size; i++) { - *FillAddress++ = (T)FillValue; + auto itemv = FillValue - offset; + *FillAddress++ = (T)(itemv); - FillValue++; - - if (FillValue > MaximumFillValue) { - FillValue = MinimumFillValue; - } + FillValue += 7; + FillValue %= range; } }); } diff --git a/onnxruntime/test/onnx/TestCase.cc b/onnxruntime/test/onnx/TestCase.cc index b532f6a9bb269..fcef036163d4c 100644 --- a/onnxruntime/test/onnx/TestCase.cc +++ b/onnxruntime/test/onnx/TestCase.cc @@ -472,7 +472,7 @@ void OnnxTestCase::LoadTestData(size_t id, onnxruntime::test::HeapBuffer& b, ORT_THROW("index out of bound"); } - PATH_STRING_TYPE test_data_pb = ConcatPathComponent( + PATH_STRING_TYPE test_data_pb = ConcatPathComponent( test_data_dirs_[id], (is_input ? ORT_TSTR("inputs.pb") : ORT_TSTR("outputs.pb"))); int test_data_pb_fd; auto st = Env::Default().FileOpenRd(test_data_pb, test_data_pb_fd); @@ -512,7 +512,7 @@ void OnnxTestCase::LoadTestData(size_t id, onnxruntime::test::HeapBuffer& b, const std::basic_string file_prefix = is_input ? ORT_TSTR("input_") : ORT_TSTR("output_"); if (!filename_str.compare(0, file_prefix.length(), file_prefix)) { - std::basic_string p = ConcatPathComponent(dir_path, filename_str); + std::basic_string p = ConcatPathComponent(dir_path, filename_str); test_data_pb_files.push_back(p); } return true; @@ -693,7 +693,7 @@ OnnxTestCase::OnnxTestCase(const std::string& test_case_name, _In_ std::unique_p // parse config std::basic_string config_path = - ConcatPathComponent(test_case_dir, ORT_TSTR("config.txt")); + ConcatPathComponent(test_case_dir, ORT_TSTR("config.txt")); /* Note: protobuf-lite doesn't support reading protobuf files as text-format. Config.txt is exactly that. That's the reason I've to parse the file in a different way to read the configs. Currently this affects 2 tests - fp16_tiny_yolov2 and fp16_inception_v1. It's not clear why we've to use protobuf @@ -718,7 +718,7 @@ OnnxTestCase::OnnxTestCase(const std::string& test_case_name, _In_ std::unique_p LoopDir(test_case_dir, [&test_case_dir, this](const PATH_CHAR_TYPE* filename, OrtFileType f_type) -> bool { if (filename[0] == '.') return true; if (f_type == OrtFileType::TYPE_DIR) { - std::basic_string p = ConcatPathComponent(test_case_dir, filename); + std::basic_string p = ConcatPathComponent(test_case_dir, filename); test_data_dirs_.push_back(p); debuginfo_strings_.push_back(ToUTF8String(p)); } @@ -739,7 +739,7 @@ void LoadTests(const std::vector>& input_paths LoopDir(node_data_root_path, [&](const PATH_CHAR_TYPE* filename, OrtFileType f_type) -> bool { if (filename[0] == '.') return true; if (f_type == OrtFileType::TYPE_DIR) { - std::basic_string p = ConcatPathComponent(node_data_root_path, filename); + std::basic_string p = ConcatPathComponent(node_data_root_path, filename); paths.push_back(p); return true; } @@ -766,7 +766,7 @@ void LoadTests(const std::vector>& input_paths } if (disabled_tests.find(test_case_name) != disabled_tests.end()) return true; - std::basic_string p = ConcatPathComponent(node_data_root_path, filename_str); + std::basic_string p = ConcatPathComponent(node_data_root_path, filename_str); std::unique_ptr model_info; diff --git a/onnxruntime/test/onnx/gen_test_models.py b/onnxruntime/test/onnx/gen_test_models.py index 3fda6aa8417b0..1a64df2936810 100644 --- a/onnxruntime/test/onnx/gen_test_models.py +++ b/onnxruntime/test/onnx/gen_test_models.py @@ -84,7 +84,7 @@ def generate_size_op_test(type, X, test_folder): # Create the graph (GraphProto) graph_def = helper.make_graph([node_def], "test-model", [X_INFO], [Y], [tensor_x]) # Create the model (ModelProto) - model_def = helper.make_model(graph_def, producer_name="onnx-example") + model_def = helper.make_model(graph_def, producer_name="onnx-example", opset_imports=[helper.make_opsetid("", 18)]) final_model = infer_shapes(model_def) onnx.save(final_model, os.path.join(test_folder, "model.onnx")) expected_output_array = np.int64(X.size) diff --git a/onnxruntime/test/onnx/main.cc b/onnxruntime/test/onnx/main.cc index 469d7c0e37af6..062ca4ece86bf 100644 --- a/onnxruntime/test/onnx/main.cc +++ b/onnxruntime/test/onnx/main.cc @@ -29,6 +29,7 @@ using namespace onnxruntime; namespace { void usage() { + auto version_string = Ort::GetVersionString(); printf( "onnx_test_runner [options...] \n" "Options:\n" @@ -49,13 +50,18 @@ void usage() { "\t-a: Specify custom absolute tolerance values for output value comparison. default: 1e-5\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] [qnn_context_cache_enable]: 1 to enable cache QNN context. Default to false.\n" + "\t [QNN only] [qnn_context_cache_path]: File path to the qnn context cache. Default to model_file.onnx.bin if not set.\n" "\t [QNN only] [profiling_level]: QNN profiling level, options: 'basic', 'detailed', default 'off'.\n" "\t [QNN only] [rpc_control_latency]: QNN rpc control latency. default to 10.\n" + "\t [QNN only] [htp_performance_mode]: QNN performance mode, options: 'burst', 'balanced', 'default', 'high_performance', \n" + "\t 'high_power_saver', 'low_balanced', 'low_power_saver', 'power_saver', 'sustained_high_performance'. Default to 'default'. \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 [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" + "\t [SNPE only] [enable_init_cache]: enable SNPE init caching feature, set to 1 to enabled it. Disabled by default. \n" "\t [Usage]: -e -i '| |' \n\n" "\t [Example] [For SNPE EP] -e snpe -i \"runtime|CPU priority|low\" \n\n" "\t-o [optimization level]: Default is 99. Valid values are 0 (disable), 1 (basic), 2 (extended), 99 (all).\n" @@ -64,7 +70,7 @@ void usage() { "\t-h: help\n" "\n" "onnxruntime version: %s\n", - OrtGetApiBase()->GetVersionString()); + version_string.c_str()); } static TestTolerances LoadTestTolerances(bool enable_cuda, bool enable_openvino, bool useCustom, double atol, double rtol) { @@ -73,7 +79,7 @@ static TestTolerances LoadTestTolerances(bool enable_cuda, bool enable_openvino, if (useCustom) { return TestTolerances(atol, rtol, absolute_overrides, relative_overrides); } - std::ifstream overrides_ifstream(ConcatPathComponent( + std::ifstream overrides_ifstream(ConcatPathComponent( ORT_TSTR("testdata"), ORT_TSTR("onnx_backend_test_series_overrides.jsonc"))); if (!overrides_ifstream.good()) { constexpr double absolute = 1e-3; @@ -446,17 +452,37 @@ int real_main(int argc, char* argv[], Ort::Env& env) { if (key == "backend_path") { if (value.empty()) { ORT_THROW("Please provide the QNN backend path."); - } else { - qnn_options[key] = value; } + } else if (key == "qnn_context_cache_enable") { + if (value != "1") { + ORT_THROW("Set to 1 to enable qnn_context_cache_enable."); + } + } else if (key == "qnn_context_cache_path") { + // no validation } else if (key == "profiling_level") { - qnn_options[key] = value; + std::set supported_profiling_level = {"off", "basic", "detailed"}; + if (supported_profiling_level.find(value) == supported_profiling_level.end()) { + ORT_THROW("Supported profiling_level: off, basic, detailed"); + } } else if (key == "rpc_control_latency") { - qnn_options[key] = value; + // no validation + } else if (key == "htp_performance_mode") { + std::set supported_htp_perf_mode = {"burst", "balanced", "default", "high_performance", + "high_power_saver", "low_balanced", "low_power_saver", + "power_saver", "sustained_high_performance"}; + if (supported_htp_perf_mode.find(value) == supported_htp_perf_mode.end()) { + std::ostringstream str_stream; + std::copy(supported_htp_perf_mode.begin(), supported_htp_perf_mode.end(), + std::ostream_iterator(str_stream, ",")); + std::string str = str_stream.str(); + ORT_THROW("Wrong value for htp_performance_mode. select from: " + str); + } } else { - ORT_THROW(R"(Wrong key type entered. Choose from options: -['backend_path', 'profiling_level', 'rpc_control_latency'])"); + ORT_THROW(R"(Wrong key type entered. Choose from options: ['backend_path', 'qnn_context_cache_enable', +'qnn_context_cache_path', 'profiling_level', 'rpc_control_latency', 'htp_performance_mode'])"); } + + qnn_options[key] = value; } sf.AppendExecutionProvider("QNN", qnn_options); #else @@ -518,8 +544,12 @@ select from 'CPU', 'GPU_FP32', 'GPU', 'GPU_FLOAT16', 'DSP', 'AIP_FIXED_TF'. \n)" ORT_THROW(R"(Wrong configuration value for the key 'buffer_type'. select from 'TF8', 'TF16', 'UINT8', 'FLOAT', 'ITENSOR'. \n)"); } + } else if (key == "enable_init_cache") { + if (value != "1") { + ORT_THROW("Set to 1 to enable_init_cache."); + } } else { - ORT_THROW("Wrong key type entered. Choose from options: ['runtime', 'priority', 'buffer_type'] \n"); + ORT_THROW("Wrong key type entered. Choose from options: ['runtime', 'priority', 'buffer_type', 'enable_init_cache'] \n"); } snpe_options[key] = value; @@ -636,6 +666,55 @@ select from 'TF8', 'TF16', 'UINT8', 'FLOAT', 'ITENSOR'. \n)"); ORT_TSTR("bernoulli_double"), ORT_TSTR("bernoulli_seed")}; + // float 8 types are not supported by any language. + static const ORTCHAR_T* float8_tests[] = { + ORT_TSTR("cast_FLOAT16_to_FLOAT8E4M3FN"), + ORT_TSTR("cast_FLOAT16_to_FLOAT8E4M3FNUZ"), + ORT_TSTR("cast_FLOAT16_to_FLOAT8E5M2"), + ORT_TSTR("cast_FLOAT16_to_FLOAT8E5M2FNUZ"), + ORT_TSTR("cast_FLOAT8E4M3FNUZ_to_FLOAT"), + ORT_TSTR("cast_FLOAT8E4M3FNUZ_to_FLOAT16"), + ORT_TSTR("cast_FLOAT8E4M3FN_to_FLOAT"), + ORT_TSTR("cast_FLOAT8E4M3FN_to_FLOAT16"), + ORT_TSTR("cast_FLOAT8E5M2FNUZ_to_FLOAT"), + ORT_TSTR("cast_FLOAT8E5M2FNUZ_to_FLOAT16"), + ORT_TSTR("cast_FLOAT8E5M2_to_FLOAT"), + ORT_TSTR("cast_FLOAT8E5M2_to_FLOAT16"), + ORT_TSTR("cast_FLOAT_to_FLOAT8E4M3FN"), + ORT_TSTR("cast_FLOAT_to_FLOAT8E4M3FNUZ"), + ORT_TSTR("cast_FLOAT_to_FLOAT8E5M2"), + ORT_TSTR("cast_FLOAT_to_FLOAT8E5M2FNUZ"), + ORT_TSTR("cast_no_saturate_FLOAT16_to_FLOAT8E4M3FN"), + ORT_TSTR("cast_no_saturate_FLOAT16_to_FLOAT8E4M3FNUZ"), + ORT_TSTR("cast_no_saturate_FLOAT16_to_FLOAT8E5M2"), + ORT_TSTR("cast_no_saturate_FLOAT16_to_FLOAT8E5M2FNUZ"), + ORT_TSTR("cast_no_saturate_FLOAT_to_FLOAT8E4M3FN"), + ORT_TSTR("cast_no_saturate_FLOAT_to_FLOAT8E4M3FNUZ"), + ORT_TSTR("cast_no_saturate_FLOAT_to_FLOAT8E5M2"), + ORT_TSTR("cast_no_saturate_FLOAT_to_FLOAT8E5M2FNUZ"), + ORT_TSTR("castlike_FLOAT8E4M3FNUZ_to_FLOAT"), + ORT_TSTR("castlike_FLOAT8E4M3FNUZ_to_FLOAT_expanded"), + ORT_TSTR("castlike_FLOAT8E4M3FN_to_FLOAT"), + ORT_TSTR("castlike_FLOAT8E4M3FN_to_FLOAT_expanded"), + ORT_TSTR("castlike_FLOAT8E5M2FNUZ_to_FLOAT"), + ORT_TSTR("castlike_FLOAT8E5M2FNUZ_to_FLOAT_expanded"), + ORT_TSTR("castlike_FLOAT8E5M2_to_FLOAT"), + ORT_TSTR("castlike_FLOAT8E5M2_to_FLOAT_expanded"), + ORT_TSTR("castlike_FLOAT_to_BFLOAT16"), + ORT_TSTR("castlike_FLOAT_to_BFLOAT16_expanded"), + ORT_TSTR("castlike_FLOAT_to_FLOAT8E4M3FN"), + ORT_TSTR("castlike_FLOAT_to_FLOAT8E4M3FNUZ"), + ORT_TSTR("castlike_FLOAT_to_FLOAT8E4M3FNUZ_expanded"), + ORT_TSTR("castlike_FLOAT_to_FLOAT8E4M3FN_expanded"), + ORT_TSTR("castlike_FLOAT_to_FLOAT8E5M2"), + ORT_TSTR("castlike_FLOAT_to_FLOAT8E5M2FNUZ"), + ORT_TSTR("castlike_FLOAT_to_FLOAT8E5M2FNUZ_expanded"), + ORT_TSTR("castlike_FLOAT_to_FLOAT8E5M2_expanded"), + ORT_TSTR("dequantizelinear_e4m3fn"), + ORT_TSTR("dequantizelinear_e5m2"), + ORT_TSTR("quantizelinear_e4m3fn"), + ORT_TSTR("quantizelinear_e5m2")}; + static const ORTCHAR_T* cuda_flaky_tests[] = { ORT_TSTR("fp16_inception_v1"), ORT_TSTR("fp16_shufflenet"), ORT_TSTR("fp16_tiny_yolov2")}; @@ -645,20 +724,6 @@ select from 'TF8', 'TF16', 'UINT8', 'FLOAT', 'ITENSOR'. \n)"); ORT_TSTR("tf_mobilenet_v2_1.0_224"), ORT_TSTR("tf_mobilenet_v2_1.4_224"), ORT_TSTR("tf_nasnet_large"), ORT_TSTR("tf_pnasnet_large"), ORT_TSTR("tf_resnet_v1_50"), ORT_TSTR("tf_resnet_v1_101"), ORT_TSTR("tf_resnet_v1_101"), ORT_TSTR("tf_resnet_v2_101"), ORT_TSTR("tf_resnet_v2_152"), ORT_TSTR("batchnorm_example_training_mode"), ORT_TSTR("batchnorm_epsilon_training_mode")}; static const ORTCHAR_T* qnn_disabled_tests[] = { - ORT_TSTR("basic_conv_without_padding"), - ORT_TSTR("basic_conv_with_padding"), - ORT_TSTR("convtranspose"), - ORT_TSTR("convtranspose_autopad_same"), - ORT_TSTR("convtranspose_dilations"), - ORT_TSTR("convtranspose_kernel_shape"), - ORT_TSTR("convtranspose_output_shape"), - ORT_TSTR("convtranspose_pad"), - ORT_TSTR("convtranspose_pads"), - ORT_TSTR("convtranspose_with_kernel"), - ORT_TSTR("conv_with_autopad_same"), - ORT_TSTR("conv_with_strides_and_asymmetric_padding"), - ORT_TSTR("conv_with_strides_no_padding"), - ORT_TSTR("conv_with_strides_padding"), ORT_TSTR("nllloss_NCd1d2d3_none_no_weight_negative_ii"), ORT_TSTR("nllloss_NCd1d2d3_none_no_weight_negative_ii_expanded"), ORT_TSTR("sce_NCd1d2d3_none_no_weight_negative_ii"), @@ -683,6 +748,7 @@ select from 'TF8', 'TF16', 'UINT8', 'FLOAT', 'ITENSOR'. \n)"); ORT_TSTR("sce_NCd1d2d3_sum_weight_high_ii_expanded"), ORT_TSTR("sce_none_weights_log_prob_expanded"), ORT_TSTR("sce_none_weights_expanded")}; + std::unordered_set> all_disabled_tests(std::begin(immutable_broken_tests), std::end(immutable_broken_tests)); if (enable_cuda) { all_disabled_tests.insert(std::begin(cuda_flaky_tests), std::end(cuda_flaky_tests)); @@ -694,9 +760,11 @@ select from 'TF8', 'TF16', 'UINT8', 'FLOAT', 'ITENSOR'. \n)"); // these models run but disabled tests to keep memory utilization low // This will be removed after LRU implementation all_disabled_tests.insert(std::begin(dnnl_disabled_tests), std::end(dnnl_disabled_tests)); + all_disabled_tests.insert(std::begin(float8_tests), std::end(float8_tests)); } if (enable_qnn) { all_disabled_tests.insert(std::begin(qnn_disabled_tests), std::end(qnn_disabled_tests)); + all_disabled_tests.insert(std::begin(float8_tests), std::end(float8_tests)); } #if !defined(__amd64__) && !defined(_M_AMD64) // out of memory @@ -799,6 +867,7 @@ select from 'TF8', 'TF16', 'UINT8', 'FLOAT', 'ITENSOR'. \n)"); {"bernoulli_expanded", "By design. Test data is for informational purpose because the generator is non deterministic."}, {"test_roialign_aligned_true", "Opset 16 not supported yet."}, {"test_roialign_aligned_false", "Opset 16 not supported yet."}, + {"test_roialign_mode_max", "Onnx roialign mode expected output is incorrect."}, {"test_scatternd_add", "Opset 16 not supported yet."}, {"test_scatternd_multiply", "Opset 16 not supported yet."}, {"test_scatter_elements_with_duplicate_indices", "Opset 16 not supported yet."}, @@ -1153,6 +1222,8 @@ select from 'TF8', 'TF16', 'UINT8', 'FLOAT', 'ITENSOR'. \n)"); broken_tests.insert({"sce_sum_expanded", "result differs"}); broken_tests.insert({"sce_sum_log_prob", "result differs"}); broken_tests.insert({"sce_sum_log_prob_expanded", "result differs"}); + broken_tests.insert({"gridsample_reflection_padding", "result differs"}); + broken_tests.insert({"spacetodepth", "result differs"}); } #if defined(_WIN32) && !defined(_WIN64) broken_tests.insert({"vgg19", "failed: bad allocation"}); diff --git a/onnxruntime/test/onnx/microbenchmark/activation.cc b/onnxruntime/test/onnx/microbenchmark/activation.cc index 63a595b17ad1c..77590f5c0a304 100644 --- a/onnxruntime/test/onnx/microbenchmark/activation.cc +++ b/onnxruntime/test/onnx/microbenchmark/activation.cc @@ -27,7 +27,7 @@ class Allocs : public IExecutionProvider { public: Allocs() : IExecutionProvider("fake"){}; - virtual AllocatorPtr GetAllocator(OrtMemType) const { + AllocatorPtr GetAllocator(OrtMemType) const { return alloc; } }; @@ -97,8 +97,8 @@ class MyIExecutionFrame : public IExecutionFrame { Status CreateNodeOutputMLValueImpl(OrtValue& /*ort_value*/, int /*ort_value_idx*/, const TensorShape* /*shape*/) override { abort(); } - AllocatorPtr GetAllocatorImpl(const OrtMemoryInfo& info) const { - return a_.GetAllocator(info.mem_type); + AllocatorPtr GetAllocatorImpl(const OrtDevice&) const override { + return static_cast(a_).GetAllocator(OrtMemTypeDefault); } Status CreateNodeOutputMLValueImpl(OrtValue& ort_value, int ort_value_index, const TensorShape* shape, size_t) { @@ -118,7 +118,7 @@ class MyIExecutionFrame : public IExecutionFrame { if (!IAllocator::CalcMemSizeForArrayWithAlignment<0>(static_cast(len), sizeof(T), &size)) { return Status(ONNXRUNTIME, FAIL, "size overflow"); } - auto alloc = a_.GetAllocator(OrtMemTypeDefault); + auto alloc = static_cast(a_).GetAllocator(OrtMemTypeDefault); std::unique_ptr p_tensor = std::make_unique(DataTypeImpl::GetType(), *shape, alloc); auto ml_tensor = DataTypeImpl::GetType(); @@ -126,7 +126,7 @@ class MyIExecutionFrame : public IExecutionFrame { return Status::OK(); } - Status CopyTensor(const Tensor& /*src*/, Tensor& /*dest*/) const { + Status CopyTensor(const Tensor& /*src*/, Tensor& /*dest*/) const override { return Status::OK(); } }; diff --git a/onnxruntime/test/onnx/microbenchmark/batchnorm.cc b/onnxruntime/test/onnx/microbenchmark/batchnorm.cc index 516664147d759..eb435618cd0e5 100644 --- a/onnxruntime/test/onnx/microbenchmark/batchnorm.cc +++ b/onnxruntime/test/onnx/microbenchmark/batchnorm.cc @@ -2,14 +2,14 @@ #include "core/util/thread_utils.h" #include -#if defined(__GNUC__) +#if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif #include "core/common/eigen_common_wrapper.h" -#if defined(__GNUC__) +#if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic pop #endif diff --git a/onnxruntime/test/onnx/microbenchmark/common.h b/onnxruntime/test/onnx/microbenchmark/common.h index 5850102258b45..89ae8ded70760 100644 --- a/onnxruntime/test/onnx/microbenchmark/common.h +++ b/onnxruntime/test/onnx/microbenchmark/common.h @@ -2,7 +2,9 @@ #include #include +#ifdef _WIN32 #include +#endif #include #include @@ -46,4 +48,4 @@ T* GenerateArrayWithRandomValue(size_t batch_size, T low, T high) { data[i] = static_cast(dist(gen)); } return data; -} \ No newline at end of file +} diff --git a/onnxruntime/test/onnx/microbenchmark/eigen.cc b/onnxruntime/test/onnx/microbenchmark/eigen.cc index b3b2c55600c9f..29894316edd01 100644 --- a/onnxruntime/test/onnx/microbenchmark/eigen.cc +++ b/onnxruntime/test/onnx/microbenchmark/eigen.cc @@ -1,4 +1,4 @@ -#if defined(__GNUC__) +#if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic push #if __GNUC__ >= 6 #pragma GCC diagnostic ignored "-Wignored-attributes" @@ -25,7 +25,7 @@ #include #include #include -#if defined(__GNUC__) +#if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic pop #elif defined(_MSC_VER) #pragma warning(pop) diff --git a/onnxruntime/test/onnx/microbenchmark/gelu.cc b/onnxruntime/test/onnx/microbenchmark/gelu.cc index 73127f6dec694..3a3669b5d6ac4 100644 --- a/onnxruntime/test/onnx/microbenchmark/gelu.cc +++ b/onnxruntime/test/onnx/microbenchmark/gelu.cc @@ -137,10 +137,9 @@ static void BM_ScaledTanhParallelFor(benchmark::State& state) { std::unique_ptr tp( concurrency::CreateThreadPool(&onnxruntime::Env::Default(), tpo, concurrency::ThreadPoolType::INTRA_OP)); const float alpha_ = 0.3f; - const float beta_ = 0.6f; for (auto _ : state) { ThreadPool::TryParallelFor(tp.get(), batch_size, cost, - [alpha_, beta_, data, output](ptrdiff_t first, ptrdiff_t last) { + [alpha_, data, output](ptrdiff_t first, ptrdiff_t last) { ptrdiff_t len = last - first; float* output_ptr = output + first; onnxruntime::ConstEigenVectorArrayMap xm(data + first, len); diff --git a/onnxruntime/test/onnx/microbenchmark/quantize.cc b/onnxruntime/test/onnx/microbenchmark/quantize.cc index ac8126d83cf67..d61c9db68d23c 100644 --- a/onnxruntime/test/onnx/microbenchmark/quantize.cc +++ b/onnxruntime/test/onnx/microbenchmark/quantize.cc @@ -66,7 +66,7 @@ static void BM_Quantize(benchmark::State& state) { for (auto _ : state) { benchmark::DoNotOptimize(a_data_quant); - onnxruntime::ParQuantizeLinear(a_data, a_data_quant, batch_size, scale, zero, tp.get()); + onnxruntime::ParQuantizeLinearStd(a_data, a_data_quant, batch_size, scale, zero, tp.get()); benchmark::ClobberMemory(); } aligned_free(a_data_quant); diff --git a/onnxruntime/test/onnx/microbenchmark/tptest.cc b/onnxruntime/test/onnx/microbenchmark/tptest.cc index b2d745bfbb0ef..e51b12454294f 100644 --- a/onnxruntime/test/onnx/microbenchmark/tptest.cc +++ b/onnxruntime/test/onnx/microbenchmark/tptest.cc @@ -30,7 +30,7 @@ BENCHMARK(BM_CreateThreadPool) // On Xeon W-2123 CPU, it takes about 2ns for each iteration #ifdef _WIN32 #pragma optimize("", off) -#else +#elif defined(__GNUC__) && !defined(__clang__) #pragma GCC push_options #pragma GCC optimize("O0") #endif @@ -42,7 +42,7 @@ void SimpleForLoop(ptrdiff_t first, ptrdiff_t last) { } #ifdef _WIN32 #pragma optimize("", on) -#else +#elif defined(__GNUC__) && !defined(__clang__) #pragma GCC pop_options #endif diff --git a/onnxruntime/test/onnx/pb_helper.h b/onnxruntime/test/onnx/pb_helper.h index d2b7cdf4ee8f3..cd73c53c1979d 100644 --- a/onnxruntime/test/onnx/pb_helper.h +++ b/onnxruntime/test/onnx/pb_helper.h @@ -33,6 +33,10 @@ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wignored-qualifiers" #pragma GCC diagnostic ignored "-Wunused-parameter" +#include "onnxruntime_config.h" +#ifdef HAS_SHORTEN_64_TO_32 +#pragma GCC diagnostic ignored "-Wshorten-64-to-32" +#endif #endif #include #include diff --git a/onnxruntime/test/onnx/tensorprotoutils.cc b/onnxruntime/test/onnx/tensorprotoutils.cc index afafd0c6b4621..b15b1769a69c4 100644 --- a/onnxruntime/test/onnx/tensorprotoutils.cc +++ b/onnxruntime/test/onnx/tensorprotoutils.cc @@ -79,7 +79,7 @@ static void UnpackTensorWithRawData(const void* raw_data, size_t raw_data_length #define DEFINE_UNPACK_TENSOR(T, Type, field_name, field_size) \ template <> \ void UnpackTensor(const onnx::TensorProto& tensor, const void* raw_data, size_t raw_data_len, \ - /*out*/ T* p_data, int64_t expected_size) { \ + /*out*/ T* p_data, size_t expected_size) { \ if (nullptr == p_data) { \ const size_t size = raw_data != nullptr ? raw_data_len : tensor.field_size(); \ if (size == 0) return; \ @@ -92,7 +92,7 @@ static void UnpackTensorWithRawData(const void* raw_data, size_t raw_data_length UnpackTensorWithRawData(raw_data, raw_data_len, expected_size, p_data); \ return; \ } \ - if (tensor.field_size() != expected_size) \ + if (static_cast(tensor.field_size()) != expected_size) \ ORT_CXX_API_THROW(MakeString("corrupted protobuf data: tensor shape size(", expected_size, \ ") does not match the data size(", tensor.field_size(), ") in proto"), \ OrtErrorCode::ORT_FAIL); \ @@ -117,7 +117,7 @@ DEFINE_UNPACK_TENSOR(uint32_t, onnx::TensorProto_DataType_UINT32, uint64_data, u // doesn't support raw data template <> void UnpackTensor(const onnx::TensorProto& tensor, const void* /*raw_data*/, size_t /*raw_data_len*/, - /*out*/ std::string* p_data, int64_t expected_size) { + /*out*/ std::string* p_data, size_t expected_size) { if (nullptr == p_data) { if (tensor.string_data_size() == 0) return; ORT_CXX_API_THROW("", OrtErrorCode::ORT_INVALID_ARGUMENT); @@ -126,7 +126,7 @@ void UnpackTensor(const onnx::TensorProto& tensor, const void* /*raw_data*/, siz ORT_CXX_API_THROW("", OrtErrorCode::ORT_INVALID_ARGUMENT); } - if (tensor.string_data_size() != expected_size) + if (static_cast(tensor.string_data_size()) != expected_size) ORT_CXX_API_THROW( "UnpackTensor: the pre-allocate size does not match the size in proto", OrtErrorCode::ORT_FAIL); @@ -139,7 +139,7 @@ void UnpackTensor(const onnx::TensorProto& tensor, const void* /*raw_data*/, siz } template <> void UnpackTensor(const onnx::TensorProto& tensor, const void* raw_data, size_t raw_data_len, - /*out*/ bool* p_data, int64_t expected_size) { + /*out*/ bool* p_data, size_t expected_size) { if (nullptr == p_data) { const size_t size = raw_data != nullptr ? raw_data_len : tensor.int32_data_size(); if (size == 0) return; @@ -153,7 +153,7 @@ void UnpackTensor(const onnx::TensorProto& tensor, const void* raw_data, size_t return UnpackTensorWithRawData(raw_data, raw_data_len, expected_size, p_data); } - if (tensor.int32_data_size() != expected_size) + if (static_cast(tensor.int32_data_size()) != expected_size) ORT_CXX_API_THROW( "UnpackTensor: the pre-allocate size does not match the size in proto", OrtErrorCode::ORT_FAIL); for (int iter : tensor.int32_data()) { @@ -164,7 +164,7 @@ void UnpackTensor(const onnx::TensorProto& tensor, const void* raw_data, size_t } template <> void UnpackTensor(const onnx::TensorProto& tensor, const void* raw_data, size_t raw_data_len, - /*out*/ MLFloat16* p_data, int64_t expected_size) { + /*out*/ MLFloat16* p_data, size_t expected_size) { if (nullptr == p_data) { const size_t size = raw_data != nullptr ? raw_data_len : tensor.int32_data_size(); if (size == 0) return; @@ -178,7 +178,7 @@ void UnpackTensor(const onnx::TensorProto& tensor, const void* raw_data, size_t return UnpackTensorWithRawData(raw_data, raw_data_len, expected_size, p_data); } - if (tensor.int32_data_size() != expected_size) + if (static_cast(tensor.int32_data_size()) != expected_size) ORT_CXX_API_THROW( "UnpackTensor: the pre-allocate size does not match the size in proto", OrtErrorCode::ORT_FAIL); @@ -189,7 +189,7 @@ void UnpackTensor(const onnx::TensorProto& tensor, const void* raw_data, size_t ORT_CXX_API_THROW( "data overflow", OrtErrorCode::ORT_FAIL); } - p_data[i] = MLFloat16(static_cast(v)); + p_data[i] = MLFloat16::FromBits(static_cast(v)); } return; @@ -197,7 +197,7 @@ void UnpackTensor(const onnx::TensorProto& tensor, const void* raw_data, size_t template <> void UnpackTensor(const onnx::TensorProto& tensor, const void* raw_data, size_t raw_data_len, - /*out*/ BFloat16* p_data, int64_t expected_size) { + /*out*/ BFloat16* p_data, size_t expected_size) { if (nullptr == p_data) { const size_t size = raw_data != nullptr ? raw_data_len : tensor.int32_data_size(); if (size == 0) @@ -213,7 +213,7 @@ void UnpackTensor(const onnx::TensorProto& tensor, const void* raw_data, size_t return UnpackTensorWithRawData(raw_data, raw_data_len, expected_size, p_data); } - if (tensor.int32_data_size() != expected_size) + if (static_cast(tensor.int32_data_size()) != expected_size) ORT_CXX_API_THROW( "UnpackTensor: the pre-allocate size does not match the size in proto", OrtErrorCode::ORT_FAIL); @@ -230,6 +230,44 @@ void UnpackTensor(const onnx::TensorProto& tensor, const void* raw_data, size_t return; } +#define DEFINE_UNPACK_TENSOR_FLOAT8(TYPE, ONNX_TYPE) \ + template <> \ + void UnpackTensor(const onnx::TensorProto& tensor, const void* raw_data, size_t raw_data_len, \ + /*out*/ TYPE* p_data, size_t expected_size) { \ + if (nullptr == p_data) { \ + const size_t size = raw_data != nullptr ? raw_data_len : tensor.int32_data_size(); \ + if (size == 0) \ + return; \ + ORT_CXX_API_THROW("", OrtErrorCode::ORT_INVALID_ARGUMENT); \ + } \ + if (onnx::ONNX_TYPE != tensor.data_type()) { \ + ORT_CXX_API_THROW("", OrtErrorCode::ORT_INVALID_ARGUMENT); \ + } \ + if (raw_data != nullptr) { \ + return UnpackTensorWithRawData(raw_data, raw_data_len, expected_size, p_data); \ + } \ + if (static_cast(tensor.int32_data_size()) != expected_size) \ + ORT_CXX_API_THROW( \ + "UnpackTensor: the pre-allocate size does not match the size in proto", OrtErrorCode::ORT_FAIL); \ + constexpr int max_value = std::numeric_limits::max(); \ + for (int i = 0; i < static_cast(expected_size); i++) { \ + int v = tensor.int32_data()[i]; \ + if (v < 0 || v > max_value) { \ + ORT_CXX_API_THROW( \ + "data overflow", OrtErrorCode::ORT_FAIL); \ + } \ + p_data[i] = TYPE(static_cast(v), TYPE::FromBits()); \ + } \ + return; \ + } + +#if !defined(DISABLE_FLOAT8_TYPES) +DEFINE_UNPACK_TENSOR_FLOAT8(Float8E4M3FN, TensorProto_DataType_FLOAT8E4M3FN) +DEFINE_UNPACK_TENSOR_FLOAT8(Float8E4M3FNUZ, TensorProto_DataType_FLOAT8E4M3FNUZ) +DEFINE_UNPACK_TENSOR_FLOAT8(Float8E5M2, TensorProto_DataType_FLOAT8E5M2) +DEFINE_UNPACK_TENSOR_FLOAT8(Float8E5M2FNUZ, TensorProto_DataType_FLOAT8E5M2FNUZ) +#endif + #define CASE_PROTO_TRACE(X, Y) \ case onnx::TensorProto_DataType::TensorProto_DataType_##X: \ if (!CalcMemSizeForArrayWithAlignment(size, sizeof(Y), alignment, out)) { \ @@ -263,6 +301,12 @@ Status GetSizeInBytesFromTensorProto(const ONNX_NAMESPACE::TensorProto& tensor_p CASE_PROTO_TRACE(UINT64, uint64_t); CASE_PROTO_TRACE(FLOAT16, MLFloat16); CASE_PROTO_TRACE(BFLOAT16, BFloat16); +#if !defined(DISABLE_FLOAT8_TYPES) + CASE_PROTO_TRACE(FLOAT8E4M3FN, Float8E4M3FN); + CASE_PROTO_TRACE(FLOAT8E4M3FNUZ, Float8E4M3FNUZ); + CASE_PROTO_TRACE(FLOAT8E5M2, Float8E5M2); + CASE_PROTO_TRACE(FLOAT8E5M2FNUZ, Float8E5M2FNUZ); +#endif CASE_PROTO_TRACE(STRING, std::string); default: return Status(common::ONNXRUNTIME, common::NOT_IMPLEMENTED); @@ -316,9 +360,10 @@ ORT_API(void, OrtUninitializeBuffer, _In_opt_ void* input, size_t input_len, enu } } -#define CASE_PROTO(X, Y) \ - case onnx::TensorProto_DataType::TensorProto_DataType_##X: \ - ::onnxruntime::test::UnpackTensor(tensor_proto, raw_data, raw_data_len, (Y*)preallocated, tensor_size); \ +#define CASE_PROTO(X, Y) \ + case onnx::TensorProto_DataType::TensorProto_DataType_##X: \ + ::onnxruntime::test::UnpackTensor(tensor_proto, raw_data, raw_data_len, \ + (Y*)preallocated, static_cast(tensor_size)); \ break; #define CASE_TYPE(X) \ @@ -343,6 +388,10 @@ ONNXTensorElementDataType CApiElementTypeFromProtoType(int type) { CASE_TYPE(COMPLEX64) CASE_TYPE(COMPLEX128) CASE_TYPE(BFLOAT16) + CASE_TYPE(FLOAT8E4M3FN) + CASE_TYPE(FLOAT8E4M3FNUZ) + CASE_TYPE(FLOAT8E5M2) + CASE_TYPE(FLOAT8E5M2FNUZ) default: return ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED; } @@ -401,6 +450,12 @@ Status TensorProtoToMLValue(const onnx::TensorProto& tensor_proto, const MemBuff CASE_PROTO(UINT64, uint64_t); CASE_PROTO(FLOAT16, MLFloat16); CASE_PROTO(BFLOAT16, BFloat16); +#if !defined(DISABLE_FLOAT8_TYPES) + CASE_PROTO(FLOAT8E4M3FN, Float8E4M3FN); + CASE_PROTO(FLOAT8E4M3FNUZ, Float8E4M3FNUZ); + CASE_PROTO(FLOAT8E5M2, Float8E5M2); + CASE_PROTO(FLOAT8E5M2FNUZ, Float8E5M2FNUZ); +#endif case onnx::TensorProto_DataType::TensorProto_DataType_STRING: if (preallocated != nullptr) { OrtStatus* status = OrtInitializeBufferForTensor(preallocated, preallocated_size, ele_type); @@ -412,7 +467,7 @@ Status TensorProtoToMLValue(const onnx::TensorProto& tensor_proto, const MemBuff deleter.param = new UnInitializeParam{preallocated, preallocated_size, ele_type}; } ::onnxruntime::test::UnpackTensor(tensor_proto, raw_data, raw_data_len, - (std::string*)preallocated, tensor_size); + (std::string*)preallocated, static_cast(tensor_size)); break; default: { std::ostringstream ostr; diff --git a/onnxruntime/test/onnx/tensorprotoutils.h b/onnxruntime/test/onnx/tensorprotoutils.h index 0ff6ef224d024..cbfb1276ea0eb 100644 --- a/onnxruntime/test/onnx/tensorprotoutils.h +++ b/onnxruntime/test/onnx/tensorprotoutils.h @@ -38,9 +38,9 @@ common::Status TensorProtoToMLValue(const onnx::TensorProto& input, const MemBuf template void UnpackTensor(const onnx::TensorProto& tensor, const void* raw_data, size_t raw_data_len, - /*out*/ T* p_data, int64_t expected_size); + /*out*/ T* p_data, size_t expected_size); ONNXTensorElementDataType CApiElementTypeFromProtoType(int type); ONNXTensorElementDataType GetTensorElementType(const onnx::TensorProto& tensor_proto); } // namespace test -} // namespace onnxruntime \ No newline at end of file +} // namespace onnxruntime diff --git a/onnxruntime/test/optimizer/compute_optimizer_test.cc b/onnxruntime/test/optimizer/compute_optimizer_test.cc index 9f33ee054eb36..a03d0da2538d4 100644 --- a/onnxruntime/test/optimizer/compute_optimizer_test.cc +++ b/onnxruntime/test/optimizer/compute_optimizer_test.cc @@ -18,6 +18,7 @@ #include "core/common/span_utils.h" #include "core/framework/data_types.h" #include "core/framework/ort_value.h" +#include "core/framework/tensorprotoutils.h" #include "core/graph/graph_utils.h" #include "core/graph/graph_viewer.h" #include "core/graph/model.h" @@ -165,8 +166,8 @@ TEST(ComputeOptimizerTests, GatherND_E2E) { // check result diff after the re-order onnxruntime::test::TemporaryDirectory tmp_dir{ORT_TSTR("compute_optimizer_test_tmp_dir")}; - PathString new_model_uri{ConcatPathComponent(tmp_dir.Path(), - ORT_TSTR("computation_reduction_transformer_after.onnx"))}; + PathString new_model_uri{ConcatPathComponent(tmp_dir.Path(), + ORT_TSTR("computation_reduction_transformer_after.onnx"))}; ASSERT_STATUS_OK(Model::Save(*model, new_model_uri)); InputContainer input_container; @@ -282,8 +283,8 @@ TEST(ComputeOptimizerTests, GatherMatMul_ScalarSlicingOnBatchDim) { // Check result diff after the re-order onnxruntime::test::TemporaryDirectory tmp_dir{ORT_TSTR("compute_optimizer_test_tmp_dir")}; - PathString new_model_uri{ConcatPathComponent(tmp_dir.Path(), - ORT_TSTR("gather_matmul_scalar_batch_dim_optimized.onnx"))}; + PathString new_model_uri{ConcatPathComponent(tmp_dir.Path(), + ORT_TSTR("gather_matmul_scalar_batch_dim_optimized.onnx"))}; ASSERT_STATUS_OK(Model::Save(*model, new_model_uri)); int64_t batch_size = 8; @@ -388,8 +389,8 @@ TEST(ComputeOptimizerTests, GatherMatMul_SlicingOnBatchDim) { // Check result diff after the re-order onnxruntime::test::TemporaryDirectory tmp_dir{ORT_TSTR("compute_optimizer_test_tmp_dir")}; - PathString new_model_uri{ConcatPathComponent(tmp_dir.Path(), - ORT_TSTR("gather_matmul_batch_dim_optimized.onnx"))}; + PathString new_model_uri{ConcatPathComponent(tmp_dir.Path(), + ORT_TSTR("gather_matmul_batch_dim_optimized.onnx"))}; ASSERT_STATUS_OK(Model::Save(*model, new_model_uri)); int64_t batch_size = 8; @@ -486,8 +487,8 @@ TEST(ComputeOptimizerTests, GatherMatMul_ScalarSlicingOnLastDim) { // Check result diff after the re-order onnxruntime::test::TemporaryDirectory tmp_dir{ORT_TSTR("compute_optimizer_test_tmp_dir")}; - PathString new_model_uri{ConcatPathComponent(tmp_dir.Path(), - ORT_TSTR("gather_matmul_scalar_last_dim_optimized.onnx"))}; + PathString new_model_uri{ConcatPathComponent(tmp_dir.Path(), + ORT_TSTR("gather_matmul_scalar_last_dim_optimized.onnx"))}; ASSERT_STATUS_OK(Model::Save(*model, new_model_uri)); int64_t batch_size = 8; @@ -584,8 +585,8 @@ TEST(ComputeOptimizerTests, GatherMatMul_SlicingOnLastDim) { // Check result diff after the re-order onnxruntime::test::TemporaryDirectory tmp_dir{ORT_TSTR("compute_optimizer_test_tmp_dir")}; - PathString new_model_uri{ConcatPathComponent(tmp_dir.Path(), - ORT_TSTR("gather_matmul_last_dim_optimized.onnx"))}; + PathString new_model_uri{ConcatPathComponent(tmp_dir.Path(), + ORT_TSTR("gather_matmul_last_dim_optimized.onnx"))}; ASSERT_STATUS_OK(Model::Save(*model, new_model_uri)); int64_t batch_size = 8; @@ -637,7 +638,8 @@ TEST(ComputeOptimizerTests, GatherMatMul_ScalarSlicingOnSecondLastDim) { std::map op_to_count = CountOpsInGraph(graph); onnxruntime::GraphTransformerManager graph_transformation_mgr{1}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level1)); + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), + TransformerLevel::Level1)); ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level1, *logger)); GraphViewer graph_viewer(graph); @@ -682,7 +684,7 @@ TEST(ComputeOptimizerTests, GatherMatMul_ScalarSlicingOnSecondLastDim) { // Check result diff after the re-order onnxruntime::test::TemporaryDirectory tmp_dir{ORT_TSTR("compute_optimizer_test_tmp_dir")}; - PathString new_model_uri{ConcatPathComponent( + PathString new_model_uri{ConcatPathComponent( tmp_dir.Path(), ORT_TSTR("gather_matmul_scalar_second_last_dim_optimized.onnx"))}; ASSERT_STATUS_OK(Model::Save(*model, new_model_uri)); @@ -736,7 +738,8 @@ TEST(ComputeOptimizerTests, GatherMatMul_SlicingOnSecondLastDim) { std::map op_to_count = CountOpsInGraph(graph); onnxruntime::GraphTransformerManager graph_transformation_mgr{1}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level1)); + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), + TransformerLevel::Level1)); ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level1, *logger)); GraphViewer graph_viewer(graph); @@ -781,8 +784,8 @@ TEST(ComputeOptimizerTests, GatherMatMul_SlicingOnSecondLastDim) { // Check result diff after the re-order onnxruntime::test::TemporaryDirectory tmp_dir{ORT_TSTR("compute_optimizer_test_tmp_dir")}; - PathString new_model_uri{ConcatPathComponent(tmp_dir.Path(), - ORT_TSTR("gather_matmul_second_last_dim_optimized.onnx"))}; + PathString new_model_uri{ConcatPathComponent(tmp_dir.Path(), + ORT_TSTR("gather_matmul_second_last_dim_optimized.onnx"))}; ASSERT_STATUS_OK(Model::Save(*model, new_model_uri)); int64_t batch_size = 8; @@ -825,6 +828,345 @@ TEST(ComputeOptimizerTests, GatherMatMul_SlicingOnSecondLastDim) { } } +/* +Test graph includes multiple equivalent subgraphs as below. + graph input [2, 32, 256] (float) + | + LayerNormalization[axis=-1 (as example)] + | + [2, 32, 256] + | + | 0 (scalar) + | / + Gather[axis=1] + | + Identity + | + graph output [2, 256] (float) + +Add an Identity node because currently, we don't allow Gather generates graph output. +*/ +TEST(ComputeOptimizerTests, GatherLayerNormalization) { + std::vector> test_config_pairs{ + // { + // is_scalar_slice, + // ln_axis_before_propagation, + // expected_ln_axis_after_propagation, + // expected to propagate + // } + {true, 0, 0, false}, + {true, 1, 1, false}, + {true, 2, 1, true}, + {true, -3, -3, false}, + {true, -2, -2, false}, + {true, -1, 1, true}, + {false, 0, 0, false}, + {false, 1, 1, false}, + {false, 2, 2, true}, + {false, -3, -3, false}, + {false, -2, -2, false}, + {false, -1, -1, true}, + }; + + constexpr static int64_t gather_axis = 1; + constexpr static int64_t slice_data_value = 0; + + for (auto p : test_config_pairs) { + bool is_scalar_slice = std::get<0>(p); + int64_t ln_axis_before = std::get<1>(p); + int64_t ln_axis_after = std::get<2>(p); + bool expected_to_propagate = std::get<3>(p); + + const logging::Logger* logger = &logging::LoggingManager::DefaultLogger(); + + InlinedVector indices; + auto pre_graph_checker = [&indices](Graph& graph) -> Status { + auto op_count_pre = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_count_pre.size() == 3U); + TEST_RETURN_IF_NOT(op_count_pre["LayerNormalization"] == 1); + TEST_RETURN_IF_NOT(op_count_pre["Gather"] == 1); + TEST_RETURN_IF_NOT(op_count_pre["Identity"] == 1); + + for (Node& node : graph.Nodes()) { + if (node.OpType() == "Gather") { + TEST_RETURN_IF_NOT(indices.empty()); + constexpr bool require_constant = true; + NodeArg* initializer_node_arg = graph.GetNodeArg(node.InputDefs()[1]->Name()); + TEST_RETURN_IF_NOT(optimizer_utils::AppendTensorFromInitializer(graph, *initializer_node_arg, + indices, require_constant)); + } + } + return Status::OK(); + }; + + auto post_graph_checker = [is_scalar_slice, ln_axis_after, + &indices, expected_to_propagate](Graph& graph) { + auto op_count_post = CountOpsInGraph(graph); + + TEST_RETURN_IF_NOT(op_count_post.size() == 3U); + TEST_RETURN_IF_NOT(op_count_post["LayerNormalization"] == 1); + TEST_RETURN_IF_NOT(op_count_post["Gather"] == 1); + TEST_RETURN_IF_NOT(op_count_post["Identity"] == 1); + + for (Node& node : graph.Nodes()) { + if (node.OpType() == "LayerNormalization") { + const auto& input_defs = node.InputDefs(); + + auto producer_node = graph.GetProducerNode(input_defs[0]->Name()); + if (expected_to_propagate) { + TEST_RETURN_IF_NOT(producer_node != nullptr); + TEST_RETURN_IF_NOT(producer_node->OpType() == "Gather"); + + InlinedVector values; + constexpr bool require_constant = true; + NodeArg* initializer_node_arg = graph.GetNodeArg(producer_node->InputDefs()[1]->Name()); + TEST_RETURN_IF_NOT(optimizer_utils::AppendTensorFromInitializer(graph, *initializer_node_arg, + values, require_constant)); + for (size_t i = 0; i < values.size(); i++) { + TEST_RETURN_IF_NOT(values[i] == indices[i]); + } + + const ONNX_NAMESPACE::TensorShapeProto* slice_out_shape = producer_node->OutputDefs()[0]->Shape(); + TEST_RETURN_IF_NOT(slice_out_shape != nullptr); + + auto& attrs = node.GetAttributes(); + TEST_RETURN_IF_NOT(attrs.find("axis") != attrs.end()); + + auto& axis_attr = attrs.at("axis"); + auto axis_value = (int)axis_attr.i(); + TEST_RETURN_IF_NOT(axis_value == ln_axis_after); + + if (is_scalar_slice) { + TEST_RETURN_IF_NOT(slice_out_shape->dim_size() == 2); + TEST_RETURN_IF_NOT(utils::HasDimValue(slice_out_shape->dim(0)) && + slice_out_shape->dim(0).dim_value() == 2); + TEST_RETURN_IF_NOT(utils::HasDimValue(slice_out_shape->dim(1)) && + slice_out_shape->dim(1).dim_value() == 256); + } else { + TEST_RETURN_IF_NOT(slice_out_shape->dim_size() == 3); + TEST_RETURN_IF_NOT(utils::HasDimValue(slice_out_shape->dim(0)) && + slice_out_shape->dim(0).dim_value() == 2); + TEST_RETURN_IF_NOT(utils::HasDimValue(slice_out_shape->dim(1)) && + slice_out_shape->dim(1).dim_value() == 1); + TEST_RETURN_IF_NOT(utils::HasDimValue(slice_out_shape->dim(2)) && + slice_out_shape->dim(2).dim_value() == 256); + } + + } else { + TEST_RETURN_IF_NOT(producer_node == nullptr); + } + } + } + + return Status::OK(); + }; + + auto build_test_case = [is_scalar_slice, ln_axis_before](ModelTestBuilder& builder) { + auto* input1_arg = builder.MakeInput({{2, 32, 256}}); + auto* input2_arg = builder.MakeInput({{256}}); + auto* input3_arg = builder.MakeInput({{256}}); + auto* ln_out = builder.MakeIntermediate(); + builder.AddNode("LayerNormalization", {input1_arg, input2_arg, input3_arg}, {ln_out}) + .AddAttribute("axis", ln_axis_before); + + std::vector slice_inputs; + NodeArg* indices_initializer = nullptr; + + if (is_scalar_slice) { + indices_initializer = builder.MakeScalarInitializer(slice_data_value); + } else { + indices_initializer = builder.MakeInitializer({1}, {slice_data_value}); + } + + slice_inputs = {ln_out, indices_initializer}; + + auto* gather_out = builder.MakeIntermediate(); + builder.AddNode("Gather", slice_inputs, + {gather_out}) + .AddAttribute("axis", gather_axis); + + auto* identity_out = builder.MakeOutput(); + builder.AddNode("Identity", {gather_out}, {identity_out}); + }; + + std::unique_ptr transformer = std::make_unique(); + ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, 14, *logger, std::move(transformer), + TransformerLevel::Level1, + 1, pre_graph_checker, post_graph_checker)); + } +} + +/* +Test graph includes multiple equivalent subgraphs as below. + graph input [2, 4, 32, 256] (float) + | + Softmax[axis=3 (as example)] + | + [2, 4, 32, 256] + | + | 0 (scalar) + | / + Gather[axis=1] + | + Identity + | + graph output [2, 32, 256] (float) + +Add an Identity node because currently, we don't allow Gather generates graph output. +*/ +TEST(ComputeOptimizerTests, GatherSoftmax) { + std::vector> test_config_pairs{ + // {is_scalar_slice, softmax_axis_before_propagation, + // expected_softmax_axis_after_propagation, expected to propagate} + {true, 0, 0, false}, + {true, 1, 1, false}, + {true, 2, 1, true}, + {true, 3, 2, true}, + {true, -4, -4, false}, + {true, -3, -3, false}, + {true, -2, 1, true}, + {true, -1, 2, true}, + {false, 0, 0, false}, + {false, 1, 1, false}, + {false, 2, 2, true}, + {false, 3, 3, true}, + {false, -4, -4, false}, + {false, -3, -3, false}, + {false, -2, -2, true}, + {false, -1, -1, true}, + }; + + constexpr static int64_t gather_axis = 1; + constexpr static int64_t slice_data_value = 0; + + for (auto p : test_config_pairs) { + bool is_scalar_slice = std::get<0>(p); + int64_t softmax_axis_before = std::get<1>(p); + int64_t softmax_axis_after = std::get<2>(p); + bool expected_to_propagate = std::get<3>(p); + + const logging::Logger* logger = &logging::LoggingManager::DefaultLogger(); + + InlinedVector indices; + auto pre_graph_checker = [&indices](Graph& graph) -> Status { + auto op_count_pre = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_count_pre.size() == 3U); + TEST_RETURN_IF_NOT(op_count_pre["Softmax"] == 1); + TEST_RETURN_IF_NOT(op_count_pre["Gather"] == 1); + TEST_RETURN_IF_NOT(op_count_pre["Identity"] == 1); + + for (Node& node : graph.Nodes()) { + if (node.OpType() == "Gather") { + TEST_RETURN_IF_NOT(indices.empty()); + constexpr bool require_constant = true; + NodeArg* initializer_node_arg = graph.GetNodeArg(node.InputDefs()[1]->Name()); + TEST_RETURN_IF_NOT(optimizer_utils::AppendTensorFromInitializer(graph, *initializer_node_arg, + indices, require_constant)); + } + } + return Status::OK(); + }; + + auto post_graph_checker = [is_scalar_slice, softmax_axis_after, + &indices, expected_to_propagate](Graph& graph) { + auto op_count_post = CountOpsInGraph(graph); + + TEST_RETURN_IF_NOT(op_count_post.size() == 3U); + TEST_RETURN_IF_NOT(op_count_post["Softmax"] == 1); + TEST_RETURN_IF_NOT(op_count_post["Gather"] == 1); + TEST_RETURN_IF_NOT(op_count_post["Identity"] == 1); + + for (Node& node : graph.Nodes()) { + if (node.OpType() == "Softmax") { + const auto& input_defs = node.InputDefs(); + + auto producer_node = graph.GetProducerNode(input_defs[0]->Name()); + if (expected_to_propagate) { + TEST_RETURN_IF_NOT(producer_node != nullptr); + TEST_RETURN_IF_NOT(producer_node->OpType() == "Gather"); + + InlinedVector values; + constexpr bool require_constant = true; + NodeArg* initializer_node_arg = graph.GetNodeArg(producer_node->InputDefs()[1]->Name()); + TEST_RETURN_IF_NOT(optimizer_utils::AppendTensorFromInitializer(graph, *initializer_node_arg, values, + require_constant)); + for (size_t i = 0; i < values.size(); i++) { + TEST_RETURN_IF_NOT(values[i] == indices[i]); + } + + const ONNX_NAMESPACE::TensorShapeProto* slice_out_shape = producer_node->OutputDefs()[0]->Shape(); + TEST_RETURN_IF_NOT(slice_out_shape != nullptr); + + auto& attrs = node.GetAttributes(); + TEST_RETURN_IF_NOT(attrs.find("axis") != attrs.end()); + + auto& axis_attr = attrs.at("axis"); + auto axis_value = (int)axis_attr.i(); + TEST_RETURN_IF_NOT(axis_value == softmax_axis_after); + + if (is_scalar_slice) { + TEST_RETURN_IF_NOT(slice_out_shape->dim_size() == 3); + TEST_RETURN_IF_NOT(utils::HasDimValue(slice_out_shape->dim(0)) && + slice_out_shape->dim(0).dim_value() == 2); + TEST_RETURN_IF_NOT(utils::HasDimValue(slice_out_shape->dim(1)) && + slice_out_shape->dim(1).dim_value() == 32); + TEST_RETURN_IF_NOT(utils::HasDimValue(slice_out_shape->dim(2)) && + slice_out_shape->dim(2).dim_value() == 256); + } else { + TEST_RETURN_IF_NOT(slice_out_shape->dim_size() == 4); + TEST_RETURN_IF_NOT(utils::HasDimValue(slice_out_shape->dim(0)) && + slice_out_shape->dim(0).dim_value() == 2); + TEST_RETURN_IF_NOT(utils::HasDimValue(slice_out_shape->dim(1)) && + slice_out_shape->dim(1).dim_value() == 1); + TEST_RETURN_IF_NOT(utils::HasDimValue(slice_out_shape->dim(2)) && + slice_out_shape->dim(2).dim_value() == 32); + TEST_RETURN_IF_NOT(utils::HasDimValue(slice_out_shape->dim(3)) && + slice_out_shape->dim(3).dim_value() == 256); + } + + } else { + TEST_RETURN_IF_NOT(producer_node == nullptr); + } + } + } + + return Status::OK(); + }; + + auto build_test_case = [is_scalar_slice, softmax_axis_before](ModelTestBuilder& builder) { + auto* input1_arg = builder.MakeInput({{2, 4, 32, 256}}); + auto* softmax_out = builder.MakeIntermediate(); + builder.AddNode("Softmax", {input1_arg}, {softmax_out}) + .AddAttribute("axis", softmax_axis_before); + + std::vector slice_inputs; + + NodeArg* indices_initializer = nullptr; + + if (is_scalar_slice) { + indices_initializer = builder.MakeScalarInitializer(slice_data_value); + } else { + indices_initializer = builder.MakeInitializer({1}, {slice_data_value}); + } + + slice_inputs = {softmax_out, indices_initializer}; + + auto* gather_out = builder.MakeIntermediate(); + builder.AddNode("Gather", slice_inputs, + {gather_out}) + .AddAttribute("axis", gather_axis); + + auto* identity_out = builder.MakeOutput(); + builder.AddNode("Identity", {gather_out}, {identity_out}); + }; + + std::unique_ptr transformer = std::make_unique(); + ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, 14, *logger, std::move(transformer), + TransformerLevel::Level1, + 1, pre_graph_checker, post_graph_checker)); + } +} + TEST(ComputeOptimizerTests, GatherReshape_ScalarSlicingOnBatchDim) { const logging::Logger* logger = &logging::LoggingManager::DefaultLogger(); auto model_uri = MODEL_FOLDER "computation_reduction/gather/gather_reshape_scalar_batch_dim.onnx"; @@ -834,7 +1176,8 @@ TEST(ComputeOptimizerTests, GatherReshape_ScalarSlicingOnBatchDim) { std::map op_to_count = CountOpsInGraph(graph); onnxruntime::GraphTransformerManager graph_transformation_mgr{1}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level1)); + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), + TransformerLevel::Level1)); ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level1, *logger)); GraphViewer graph_viewer(graph); @@ -875,8 +1218,8 @@ TEST(ComputeOptimizerTests, GatherReshape_ScalarSlicingOnBatchDim) { // Check result diff after the re-order onnxruntime::test::TemporaryDirectory tmp_dir{ORT_TSTR("compute_optimizer_test_tmp_dir")}; - PathString new_model_uri{ConcatPathComponent(tmp_dir.Path(), - ORT_TSTR("gather_reshape_scalar_batch_dim_optimized.onnx"))}; + PathString new_model_uri{ConcatPathComponent(tmp_dir.Path(), + ORT_TSTR("gather_reshape_scalar_batch_dim_optimized.onnx"))}; ASSERT_STATUS_OK(Model::Save(*model, new_model_uri)); int64_t batch_size = 8; @@ -927,7 +1270,8 @@ TEST(ComputeOptimizerTests, GatherReshape_SlicingOnBatchDim) { std::map op_to_count = CountOpsInGraph(graph); onnxruntime::GraphTransformerManager graph_transformation_mgr{1}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level1)); + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), + TransformerLevel::Level1)); ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level1, *logger)); GraphViewer graph_viewer(graph); @@ -969,8 +1313,8 @@ TEST(ComputeOptimizerTests, GatherReshape_SlicingOnBatchDim) { // Check result diff after the re-order onnxruntime::test::TemporaryDirectory tmp_dir{ORT_TSTR("compute_optimizer_test_tmp_dir")}; - PathString new_model_uri{ConcatPathComponent(tmp_dir.Path(), - ORT_TSTR("gather_reshape_batch_dim_optimized.onnx"))}; + PathString new_model_uri{ConcatPathComponent(tmp_dir.Path(), + ORT_TSTR("gather_reshape_batch_dim_optimized.onnx"))}; ASSERT_STATUS_OK(Model::Save(*model, new_model_uri)); int64_t batch_size = 8; @@ -1062,8 +1406,8 @@ TEST(ComputeOptimizerTests, GatherReshape_ScalarSlicingOnSeqlenDim) { // Check result diff after the re-order onnxruntime::test::TemporaryDirectory tmp_dir{ORT_TSTR("compute_optimizer_test_tmp_dir")}; - PathString new_model_uri{ConcatPathComponent(tmp_dir.Path(), - ORT_TSTR("gather_reshape_scalar_seqlen_dim_optimized.onnx"))}; + PathString new_model_uri{ConcatPathComponent(tmp_dir.Path(), + ORT_TSTR("gather_reshape_scalar_seqlen_dim_optimized.onnx"))}; ASSERT_STATUS_OK(Model::Save(*model, new_model_uri)); int64_t batch_size = 8; @@ -1156,8 +1500,8 @@ TEST(ComputeOptimizerTests, GatherReshape_SlicingOnSeqlenDim) { // Check result diff after the re-order onnxruntime::test::TemporaryDirectory tmp_dir{ORT_TSTR("compute_optimizer_test_tmp_dir")}; - PathString new_model_uri{ConcatPathComponent(tmp_dir.Path(), - ORT_TSTR("gather_reshape_seqlen_dim_optimized.onnx"))}; + PathString new_model_uri{ConcatPathComponent(tmp_dir.Path(), + ORT_TSTR("gather_reshape_seqlen_dim_optimized.onnx"))}; ASSERT_STATUS_OK(Model::Save(*model, new_model_uri)); int64_t batch_size = 8; @@ -1250,8 +1594,8 @@ TEST(ComputeOptimizerTests, GatherReshape_SlicingOnSeqlenDim2) { // Check result diff after the re-order onnxruntime::test::TemporaryDirectory tmp_dir{ORT_TSTR("compute_optimizer_test_tmp_dir")}; - PathString new_model_uri{ConcatPathComponent(tmp_dir.Path(), - ORT_TSTR("gather_reshape_seqlen_dim2_optimized.onnx"))}; + PathString new_model_uri{ConcatPathComponent(tmp_dir.Path(), + ORT_TSTR("gather_reshape_seqlen_dim2_optimized.onnx"))}; ASSERT_STATUS_OK(Model::Save(*model, new_model_uri)); int64_t batch_size = 8; @@ -1394,8 +1738,8 @@ TEST(ComputeOptimizerTests, GatherRobertaE2E) { // Check the result diff after the re-order onnxruntime::test::TemporaryDirectory tmp_dir{ORT_TSTR("compute_optimizer_test_tmp_dir")}; - PathString new_model_uri{ConcatPathComponent(tmp_dir.Path(), - ORT_TSTR("gather_roberta_e2e_optimized.onnx"))}; + PathString new_model_uri{ConcatPathComponent(tmp_dir.Path(), + ORT_TSTR("gather_roberta_e2e_optimized.onnx"))}; ASSERT_STATUS_OK(Model::Save(*model, new_model_uri)); int64_t batch_size = 8; @@ -1576,6 +1920,418 @@ TEST(ComputeOptimizerTests, ShrunkenGatherElementwiseOps_PropagationOnTwoBranche 1, pre_graph_checker, post_graph_checker)); } +/* +Test graph includes multiple equivalent subgraphs as below. + graph input [4, 32, 256] (float) graph input [4, 32, 256] (float) + | | + \_____________ ______________/ + \ / + Add starts:(0) ends: (-1) axes: (1) steps: (1) + \ \ | / / + \ \ | / / + \ \ | / / + \ \ | / / + \ \ | / / + Slice + | + Identity + | + graph output [4, 31, 256] (float) + +Add an Identity node because currently we don't allow Slice generates graph output. +*/ +TEST(ComputeOptimizerTests, SliceElementwiseOps_PropagationOnTwoBranches) { + // 0: no input, 1: has input, 2: empty input + std::vector, std::vector, int, int, bool>> has_axes_and_has_steps_pairs{ + {std::nullopt, {4, 32, 256}, 0, 0, false}, // {axis, data_shape, has_axes, has_steps, expected to propagate} + {1, {4, 32, 256}, 1, 0, true}, + {1, {4, 32, 256}, 1, 1, true}, + {1, {4, 32, 256}, 1, 2, true}, + {std::nullopt, {4, 32, 256}, 2, 0, false}, + {std::nullopt, {4, 32, 256}, 2, 1, false}, + {std::nullopt, {4, 32, 256}, 2, 2, false}, + + {std::nullopt, {256}, 0, 0, true}, + {0, {256}, 1, 0, true}, + {0, {256}, 1, 1, true}, + {0, {256}, 1, 2, true}, + {std::nullopt, {256}, 2, 0, true}, + {std::nullopt, {256}, 2, 1, true}, + {std::nullopt, {256}, 2, 2, true}, + }; + + for (auto p : has_axes_and_has_steps_pairs) { + std::optional axis = std::get<0>(p); + std::vector data_shape = std::get<1>(p); + int has_axes = std::get<2>(p); + int has_steps = std::get<3>(p); + bool expected_to_propagate = std::get<4>(p); + + const logging::Logger* logger = &logging::LoggingManager::DefaultLogger(); + InlinedVector starts_indices; + auto pre_graph_checker = [&starts_indices](Graph& graph) -> Status { + auto op_count_pre = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_count_pre.size() == 3U); + TEST_RETURN_IF_NOT(op_count_pre["Add"] == 1); + TEST_RETURN_IF_NOT(op_count_pre["Slice"] == 1); + TEST_RETURN_IF_NOT(op_count_pre["Identity"] == 1); + + for (Node& node : graph.Nodes()) { + if (node.OpType() == "Slice") { + TEST_RETURN_IF_NOT(starts_indices.empty()); + constexpr bool require_constant = true; + NodeArg* initializer_node_arg = graph.GetNodeArg(node.InputDefs()[1]->Name()); + TEST_RETURN_IF_NOT(optimizer_utils::AppendTensorFromInitializer(graph, *initializer_node_arg, starts_indices, + require_constant)); + } + } + return Status::OK(); + }; + + auto post_graph_checker = [&starts_indices, expected_to_propagate](Graph& graph) { + auto op_count_post = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_count_post.size() == 3U); + TEST_RETURN_IF_NOT(op_count_post["Add"] == 1); + if (expected_to_propagate) { + TEST_RETURN_IF_NOT(op_count_post["Slice"] == 2); + } else { + TEST_RETURN_IF_NOT(op_count_post["Slice"] == 1); + } + TEST_RETURN_IF_NOT(op_count_post["Identity"] == 1); + + for (Node& node : graph.Nodes()) { + if (node.OpType() == "Add") { + const auto& input_defs = node.InputDefs(); + + { + auto producer_node = graph.GetProducerNode(input_defs[0]->Name()); + + if (expected_to_propagate) { + TEST_RETURN_IF_NOT(producer_node != nullptr); + TEST_RETURN_IF_NOT(producer_node->OpType() == "Slice"); + + InlinedVector values; + constexpr bool require_constant = true; + NodeArg* initializer_node_arg = graph.GetNodeArg(producer_node->InputDefs()[1]->Name()); + TEST_RETURN_IF_NOT(optimizer_utils::AppendTensorFromInitializer(graph, *initializer_node_arg, values, + require_constant)); + for (size_t i = 0; i < values.size(); i++) { + TEST_RETURN_IF_NOT(values[i] == starts_indices[i]); + } + } else { + TEST_RETURN_IF_NOT(producer_node == nullptr); + } + } + + { + auto producer_node = graph.GetProducerNode(input_defs[1]->Name()); + + if (expected_to_propagate) { + TEST_RETURN_IF_NOT(producer_node != nullptr); + TEST_RETURN_IF_NOT(producer_node->OpType() == "Slice"); + + InlinedVector values; + constexpr bool require_constant = true; + NodeArg* initializer_node_arg = graph.GetNodeArg(producer_node->InputDefs()[1]->Name()); + TEST_RETURN_IF_NOT(optimizer_utils::AppendTensorFromInitializer(graph, *initializer_node_arg, values, require_constant)); + for (size_t i = 0; i < values.size(); i++) { + TEST_RETURN_IF_NOT(values[i] == starts_indices[i]); + } + } else { + TEST_RETURN_IF_NOT(producer_node == nullptr); + } + } + } + } + return Status::OK(); + }; + + auto build_test_case = [has_axes, has_steps, &data_shape, axis](ModelTestBuilder& builder) { + auto* input1_arg = builder.MakeInput(data_shape); + auto* input2_arg = builder.MakeInput(data_shape); + auto* add_out = builder.MakeIntermediate(); + builder.AddNode("Add", {input1_arg, input2_arg}, {add_out}); + + auto* starts_initializer = builder.MakeInitializer({1}, {0}); + auto* ends_initializer = builder.MakeInitializer({1}, {-1}); + + std::vector slice_inputs; + slice_inputs = {add_out, starts_initializer, ends_initializer}; + + NodeArg* axes_initializer = nullptr; + NodeArg* steps_initializer = nullptr; + if (has_axes == 0 && has_steps == 0) { + // nothing + } else if (has_axes == 1 && has_steps == 0) { + axes_initializer = builder.MakeInitializer({1}, {axis.value()}); + slice_inputs.push_back(axes_initializer); + } else if (has_axes == 1 && has_steps == 1) { + axes_initializer = builder.MakeInitializer({1}, {axis.value()}); + slice_inputs.push_back(axes_initializer); + steps_initializer = builder.MakeInitializer({1}, {1}); + slice_inputs.push_back(steps_initializer); + } else if (has_axes == 1 && has_steps == 2) { + axes_initializer = builder.MakeInitializer({1}, {axis.value()}); + slice_inputs.push_back(axes_initializer); + steps_initializer = builder.MakeEmptyInput(); + slice_inputs.push_back(steps_initializer); + } else if (has_axes == 2 && has_steps == 0) { + axes_initializer = builder.MakeEmptyInput(); + slice_inputs.push_back(axes_initializer); + } else if (has_axes == 2 && has_steps == 1) { + axes_initializer = builder.MakeEmptyInput(); + slice_inputs.push_back(axes_initializer); + steps_initializer = builder.MakeInitializer({1}, {1}); + slice_inputs.push_back(steps_initializer); + } else if (has_axes == 2 && has_steps == 2) { + axes_initializer = builder.MakeEmptyInput(); + slice_inputs.push_back(axes_initializer); + steps_initializer = builder.MakeEmptyInput(); + slice_inputs.push_back(steps_initializer); + } + + auto* slice_out = builder.MakeIntermediate(); + builder.AddNode("Slice", slice_inputs, + {slice_out}); + + auto* identity_out = builder.MakeOutput(); + builder.AddNode("Identity", {slice_out}, {identity_out}); + }; + + std::unique_ptr transformer = std::make_unique(); + ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, 14, *logger, std::move(transformer), + TransformerLevel::Level1, + 1, pre_graph_checker, post_graph_checker)); + } +} + +/* +Test graph includes multiple equivalent subgraphs as below. + graph input [2, 4, 32, 256] (float) + | + Transpose[perms=[0, 2, 1, 3]] + | + [2, 32, 4, 256] + | starts:(0) ends: (-1) axes: (1) steps: (1) + \ \ | / / + \ \ | / / + \ \ | / / + \ \ | / / + \ \ | / / + Slice + | + Identity + | + graph output [2, 31, 4, 256] (float) + +Add an Identity node because currently, we don't allow Slice generates graph output. +*/ +TEST(ComputeOptimizerTests, SliceTranspose_Propagation) { + // 0: no input, 1: has input, 2: empty input + std::vector> has_axes_and_has_steps_pairs{ + {0, 0, false}, // {has_axes, has_steps, expected to propagate} + {1, 0, true}, + {1, 1, true}, + {1, 2, true}, + {2, 0, false}, + {2, 1, false}, + {2, 2, false}, + }; + + for (auto p : has_axes_and_has_steps_pairs) { + int has_axes = std::get<0>(p); + int has_steps = std::get<1>(p); + bool expected_to_propagate = std::get<2>(p); + + const logging::Logger* logger = &logging::LoggingManager::DefaultLogger(); + InlinedVector starts_indices; + auto pre_graph_checker = [&starts_indices](Graph& graph) -> Status { + auto op_count_pre = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_count_pre.size() == 3U); + TEST_RETURN_IF_NOT(op_count_pre["Transpose"] == 1); + TEST_RETURN_IF_NOT(op_count_pre["Slice"] == 1); + TEST_RETURN_IF_NOT(op_count_pre["Identity"] == 1); + + for (Node& node : graph.Nodes()) { + if (node.OpType() == "Slice") { + TEST_RETURN_IF_NOT(starts_indices.empty()); + constexpr bool require_constant = true; + NodeArg* initializer_node_arg = graph.GetNodeArg(node.InputDefs()[1]->Name()); + TEST_RETURN_IF_NOT(optimizer_utils::AppendTensorFromInitializer(graph, *initializer_node_arg, starts_indices, + require_constant)); + } + } + return Status::OK(); + }; + + auto post_graph_checker = [&starts_indices, expected_to_propagate](Graph& graph) { + auto op_count_post = CountOpsInGraph(graph); + + TEST_RETURN_IF_NOT(op_count_post.size() == 3U); + TEST_RETURN_IF_NOT(op_count_post["Transpose"] == 1); + TEST_RETURN_IF_NOT(op_count_post["Slice"] == 1); + TEST_RETURN_IF_NOT(op_count_post["Identity"] == 1); + + for (Node& node : graph.Nodes()) { + if (node.OpType() == "Transpose") { + const auto& input_defs = node.InputDefs(); + + auto producer_node = graph.GetProducerNode(input_defs[0]->Name()); + if (expected_to_propagate) { + TEST_RETURN_IF_NOT(producer_node != nullptr); + TEST_RETURN_IF_NOT(producer_node->OpType() == "Slice"); + + InlinedVector values; + constexpr bool require_constant = true; + NodeArg* initializer_node_arg = graph.GetNodeArg(producer_node->InputDefs()[1]->Name()); + TEST_RETURN_IF_NOT(optimizer_utils::AppendTensorFromInitializer(graph, *initializer_node_arg, values, + require_constant)); + for (size_t i = 0; i < values.size(); i++) { + TEST_RETURN_IF_NOT(values[i] == starts_indices[i]); + } + + const ONNX_NAMESPACE::TensorShapeProto* slice_out_shape = producer_node->OutputDefs()[0]->Shape(); + TEST_RETURN_IF_NOT(slice_out_shape != nullptr); + TEST_RETURN_IF_NOT(slice_out_shape->dim_size() == 4); + TEST_RETURN_IF_NOT(utils::HasDimValue(slice_out_shape->dim(0)) && slice_out_shape->dim(0).dim_value() == 2); + TEST_RETURN_IF_NOT(utils::HasDimValue(slice_out_shape->dim(1)) && slice_out_shape->dim(1).dim_value() == 4); + TEST_RETURN_IF_NOT(utils::HasDimValue(slice_out_shape->dim(2)) && slice_out_shape->dim(2).dim_value() == 31); + TEST_RETURN_IF_NOT(utils::HasDimValue(slice_out_shape->dim(3)) && slice_out_shape->dim(3).dim_value() == 256); + } else { + TEST_RETURN_IF_NOT(producer_node == nullptr); + } + } + } + + return Status::OK(); + }; + + auto build_test_case = [has_axes, has_steps](ModelTestBuilder& builder) { + auto* input1_arg = builder.MakeInput({{2, 4, 32, 256}}); + auto* trans_out = builder.MakeIntermediate(); + builder.AddNode("Transpose", {input1_arg}, {trans_out}) + .AddAttribute("perm", std::vector{0, 2, 1, 3}); + + std::vector slice_inputs; + + auto* starts_initializer = builder.MakeInitializer({1}, {0}); + auto* ends_initializer = builder.MakeInitializer({1}, {-1}); + + slice_inputs = {trans_out, starts_initializer, ends_initializer}; + + NodeArg* axes_initializer = nullptr; + NodeArg* steps_initializer = nullptr; + if (has_axes == 0 && has_steps == 0) { + // nothing + } else if (has_axes == 1 && has_steps == 0) { + axes_initializer = builder.MakeInitializer({1}, {1}); + slice_inputs.push_back(axes_initializer); + } else if (has_axes == 1 && has_steps == 1) { + axes_initializer = builder.MakeInitializer({1}, {1}); + slice_inputs.push_back(axes_initializer); + steps_initializer = builder.MakeInitializer({1}, {1}); + slice_inputs.push_back(steps_initializer); + } else if (has_axes == 1 && has_steps == 2) { + axes_initializer = builder.MakeInitializer({1}, {1}); + slice_inputs.push_back(axes_initializer); + steps_initializer = builder.MakeEmptyInput(); + slice_inputs.push_back(steps_initializer); + } else if (has_axes == 2 && has_steps == 0) { + axes_initializer = builder.MakeEmptyInput(); + slice_inputs.push_back(axes_initializer); + } else if (has_axes == 2 && has_steps == 1) { + axes_initializer = builder.MakeEmptyInput(); + slice_inputs.push_back(axes_initializer); + steps_initializer = builder.MakeInitializer({1}, {1}); + slice_inputs.push_back(steps_initializer); + } else if (has_axes == 2 && has_steps == 2) { + axes_initializer = builder.MakeEmptyInput(); + slice_inputs.push_back(axes_initializer); + steps_initializer = builder.MakeEmptyInput(); + slice_inputs.push_back(steps_initializer); + } + + auto* slice_out = builder.MakeIntermediate(); + builder.AddNode("Slice", slice_inputs, + {slice_out}); + + auto* identity_out = builder.MakeOutput(); + builder.AddNode("Identity", {slice_out}, {identity_out}); + }; + + std::unique_ptr transformer = std::make_unique(); + ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, 14, *logger, std::move(transformer), + TransformerLevel::Level1, + 1, pre_graph_checker, post_graph_checker)); + } +} + +/* +Test graph includes multiple equivalent subgraphs as below. + graph input [4, 32, 256] (float) graph input [4, 32, 256] (float) + | | + \_____________ ______________/ + \ / + Add starts:(0,0) ends: (-1,-1) axes: (0,1) steps: (1,1) + \ \ | / / + \ \ | / / + \ \ | / / + \ \ | / / + \ \ | / / + Slice + | + Identity + | + graph output [3, 31, 256] (float) + +Add an Identity node because currently we don't allow Slice generates graph output. +*/ +TEST(ComputeOptimizerTests, SliceElementwiseOps_NoPropagationForMutipleAxesSlice) { + const logging::Logger* logger = &logging::LoggingManager::DefaultLogger(); + auto pre_graph_checker = [](Graph& graph) -> Status { + auto op_count_pre = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_count_pre.size() == 3U); + TEST_RETURN_IF_NOT(op_count_pre["Add"] == 1); + TEST_RETURN_IF_NOT(op_count_pre["Slice"] == 1); + TEST_RETURN_IF_NOT(op_count_pre["Identity"] == 1); + + return Status::OK(); + }; + + auto post_graph_checker = [](Graph& graph) { + auto op_count_post = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_count_post.size() == 3U); + TEST_RETURN_IF_NOT(op_count_post["Add"] == 1); + TEST_RETURN_IF_NOT(op_count_post["Slice"] == 1); + TEST_RETURN_IF_NOT(op_count_post["Identity"] == 1); + + return Status::OK(); + }; + + auto build_test_case = [](ModelTestBuilder& builder) { + auto* input1_arg = builder.MakeInput({{4, 32, 256}}); + auto* input2_arg = builder.MakeInput({{4, 32, 256}}); + auto* add_out = builder.MakeIntermediate(); + builder.AddNode("Add", {input1_arg, input2_arg}, {add_out}); + + auto* starts_initializer = builder.MakeInitializer({2}, {0, 0}); + auto* ends_initializer = builder.MakeInitializer({2}, {-1, -1}); + auto* axes_initializer = builder.MakeInitializer({2}, {0, 1}); + auto* steps_initializer = builder.MakeInitializer({2}, {1, 1}); + auto* slice_out = builder.MakeIntermediate(); + builder.AddNode("Slice", {add_out, starts_initializer, ends_initializer, axes_initializer, steps_initializer}, + {slice_out}); + + auto* identity_out = builder.MakeOutput(); + builder.AddNode("Identity", {slice_out}, {identity_out}); + }; + + std::unique_ptr transformer = std::make_unique(); + ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, 14, *logger, std::move(transformer), + TransformerLevel::Level1, + 1, pre_graph_checker, post_graph_checker)); +} + /* Test graph include multiple equivalent subgraphs as below. graph input [4, 32, 256] (int64_t) graph input [4, 32, 256] (int64_t) @@ -1831,6 +2587,72 @@ TEST(ComputeOptimizerTests, ReshapeElementwiseOps_NoPropagation1) { } } +/* +Test graph include multiple equivalent subgraphs as below. + graph input [128, 4, 32] (int64_t) + | + Cast initializer value: (-1, 128) + | / + Reshape + | + Identity + | + graph out [128, 128] (int64_t) + +Add an Identity node because currently we don't allow Reshape generate graph output. +*/ +TEST(ComputeOptimizerTests, ReshapeElementwiseOps_NoPropagation2) { + const logging::Logger* logger = &logging::LoggingManager::DefaultLogger(); + auto pre_graph_checker = [](Graph& graph) -> Status { + auto op_count_pre = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_count_pre.size() == 3U); + TEST_RETURN_IF_NOT(op_count_pre["Cast"] == 1); + TEST_RETURN_IF_NOT(op_count_pre["Reshape"] == 1); + TEST_RETURN_IF_NOT(op_count_pre["Identity"] == 1); + return Status::OK(); + }; + + auto post_graph_checker = [](Graph& graph) { + auto op_count_post = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_count_post.size() == 3U); + TEST_RETURN_IF_NOT(op_count_post["Cast"] == 1); + TEST_RETURN_IF_NOT(op_count_post["Reshape"] == 1); + TEST_RETURN_IF_NOT(op_count_post["Identity"] == 1); + + for (Node& node : graph.Nodes()) { + if (node.OpType() == "Reshape") { + const auto& input_defs = node.InputDefs(); + auto producer_node = graph.GetProducerNode(input_defs[0]->Name()); + TEST_RETURN_IF_NOT(producer_node != nullptr); + TEST_RETURN_IF_NOT(producer_node->OpType() == "Cast"); + } + } + return Status::OK(); + }; + + auto build_test_case = [](ModelTestBuilder& builder) { + auto* input1_arg = builder.MakeInput({{128, 4, 32}}); + auto* cast_out = builder.MakeIntermediate(); + builder.AddNode("Cast", {input1_arg}, {cast_out}) + .AddAttribute("to", static_cast(ONNX_NAMESPACE::TensorProto_DataType_INT64)); + + auto* shape_initializer = builder.MakeInitializer({2}, {-1, 128}); + auto* reshape_out = builder.MakeIntermediate(); + builder.AddNode("Reshape", {cast_out, shape_initializer}, {reshape_out}); + + auto* identity_out = builder.MakeOutput(); + builder.AddNode("Identity", {reshape_out}, {identity_out}); + }; + + const std::vector opsets{12, 13, 14}; + for (auto& opset_version : opsets) { + std::unique_ptr transformer = std::make_unique(); + ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, opset_version, *logger, std::move(transformer), + TransformerLevel::Level1, + 1, pre_graph_checker, post_graph_checker)); + } +} + /* Test graph include multiple equivalent subgraphs as below. graph input [4, 32, 256] (int64_t) graph input () (scalar, int64_t) @@ -2238,8 +3060,8 @@ TEST(ComputeOptimizerTests, ReshapeMlmBertE2E) { // Check result diff after the re-order onnxruntime::test::TemporaryDirectory tmp_dir{ORT_TSTR("compute_optimizer_test_tmp_dir")}; - PathString new_model_uri{ConcatPathComponent(tmp_dir.Path(), - ORT_TSTR("reshape_bert_e2e_optimized.onnx"))}; + PathString new_model_uri{ConcatPathComponent(tmp_dir.Path(), + ORT_TSTR("reshape_bert_e2e_optimized.onnx"))}; ASSERT_STATUS_OK(Model::Save(*model, new_model_uri)); int64_t batch_size = 8; diff --git a/onnxruntime/test/optimizer/ensure_unique_dq_for_node_unit_test.cc b/onnxruntime/test/optimizer/ensure_unique_dq_for_node_unit_test.cc index 86fae32c12d0c..feff607703341 100644 --- a/onnxruntime/test/optimizer/ensure_unique_dq_for_node_unit_test.cc +++ b/onnxruntime/test/optimizer/ensure_unique_dq_for_node_unit_test.cc @@ -20,15 +20,17 @@ struct GraphConfig { bool has_subgraph_consumer{false}; }; -auto GetGraphBuilder(GraphConfig config) { - return [=](ModelTestBuilder& builder) { +template +std::function GetGraphBuilder(const GraphConfig& config, bool use_ms_domain_qdq_ops) { + return [config, use_ms_domain_qdq_ops](ModelTestBuilder& builder) { const auto input_shape = std::vector{1, 2, 4}; constexpr float scale = 0.5f; - constexpr uint8_t zero_point = 0; + constexpr QuantType zero_point = 0; - auto* dq_input = builder.MakeInput(input_shape, uint8_t{0}, uint8_t{255}); + auto* dq_input = builder.MakeInput(input_shape, std::numeric_limits::min(), + std::numeric_limits::max()); auto* dq_output = config.has_graph_output ? builder.MakeOutput() : builder.MakeIntermediate(); - builder.AddDequantizeLinearNode(dq_input, scale, zero_point, dq_output); + builder.AddDequantizeLinearNode(dq_input, scale, zero_point, dq_output, use_ms_domain_qdq_ops); for (size_t i = 0; i < config.num_explicit_consumer_nodes; ++i) { // use Concat for the explicit consumer node as it supports a variadic number of inputs @@ -70,48 +72,60 @@ auto GetGraphBuilder(GraphConfig config) { }; } -void RunEnsureUniqueDQForNodeUnitTest(std::function graph_builder_fn, - int expected_dq_count) { - constexpr int opset_version = 12; - - { - SCOPED_TRACE("test with standalone transformer"); - - auto post_transform_check_fn = [expected_dq_count](const Graph& graph) { - const auto op_counts = CountOpsInGraph(graph); - const auto actual_dq_count = OpCount(op_counts, "DequantizeLinear"); - ORT_RETURN_IF_NOT(actual_dq_count == expected_dq_count, - "Expected DQ count: ", expected_dq_count, ", actual: ", actual_dq_count); - return Status::OK(); - }; - - EXPECT_STATUS_OK(TestGraphTransformer( - graph_builder_fn, - opset_version, - DefaultLoggingManager().DefaultLogger(), - std::make_unique(), - TransformerLevel::Level1, - 5, - {}, - post_transform_check_fn)); - } - - { - SCOPED_TRACE("test with basic transformers"); - - auto post_transform_check_fn = [expected_dq_count](const InferenceSessionWrapper& session) { - const auto& graph = session.GetGraph(); - const auto op_counts = CountOpsInGraph(graph); - ASSERT_EQ(OpCount(op_counts, "DequantizeLinear"), expected_dq_count); - }; - - TransformerTester( - graph_builder_fn, - post_transform_check_fn, - TransformerLevel::Default, - TransformerLevel::Level1, - opset_version); - } +void RunEnsureUniqueDQForNodeUnitTest(const GraphConfig& config, int expected_dq_count) { + auto run_tests = [config, expected_dq_count](bool use_ms_domain_qdq_ops, bool use_16bit_qdq_ops) { + constexpr int opset_version = 12; + const char* dequantize_linear_key = use_ms_domain_qdq_ops ? "com.microsoft.DequantizeLinear" : "DequantizeLinear"; + std::function graph_builder_fn = use_16bit_qdq_ops + ? GetGraphBuilder(config, use_ms_domain_qdq_ops) + : GetGraphBuilder(config, use_ms_domain_qdq_ops); + + { + SCOPED_TRACE("test with standalone transformer"); + + auto post_transform_check_fn = [expected_dq_count, dequantize_linear_key](const Graph& graph) { + const auto op_counts = CountOpsInGraph(graph); + const auto actual_dq_count = OpCount(op_counts, dequantize_linear_key); + ORT_RETURN_IF_NOT(actual_dq_count == expected_dq_count, + "Expected DQ count: ", expected_dq_count, ", actual: ", actual_dq_count); + return Status::OK(); + }; + + EXPECT_STATUS_OK(TestGraphTransformer( + graph_builder_fn, + opset_version, + DefaultLoggingManager().DefaultLogger(), + std::make_unique(), + TransformerLevel::Level1, + 5, + {}, + post_transform_check_fn)); + } + + { + SCOPED_TRACE("test with basic transformers"); + + auto post_transform_check_fn = [expected_dq_count, + dequantize_linear_key](const InferenceSessionWrapper& session) { + const auto& graph = session.GetGraph(); + const auto op_counts = CountOpsInGraph(graph); + ASSERT_EQ(OpCount(op_counts, dequantize_linear_key), expected_dq_count); + }; + + TransformerTester( + graph_builder_fn, + post_transform_check_fn, + TransformerLevel::Default, + TransformerLevel::Level1, + opset_version); + } + }; + + run_tests(false, false); +#if !defined(DISABLE_CONTRIB_OPS) + run_tests(true, false); // Use contrib QDQ ops. + run_tests(true, true); // Use 16-bit contrib QDQ ops. +#endif } } // namespace @@ -122,7 +136,7 @@ TEST(EnsureUniqueDQForNodeUnitTests, DQSharedAmongNodes) { config.num_inputs_per_explicit_consumer_node = 1; // expected count = one for each explicit consumer node (3), reusing the original one = 3 - RunEnsureUniqueDQForNodeUnitTest(GetGraphBuilder(config), 3); + RunEnsureUniqueDQForNodeUnitTest(config, 3); } TEST(EnsureUniqueDQForNodeUnitTests, DQSharedAmongNodesWithGraphOutput) { @@ -132,7 +146,7 @@ TEST(EnsureUniqueDQForNodeUnitTests, DQSharedAmongNodesWithGraphOutput) { config.has_graph_output = true; // expected count = preserved original (1) + one for each explicit consumer node (3) = 4 - RunEnsureUniqueDQForNodeUnitTest(GetGraphBuilder(config), 4); + RunEnsureUniqueDQForNodeUnitTest(config, 4); } TEST(EnsureUniqueDQForNodeUnitTests, DQSharedAmongNodesWithSubgraphConsumer) { @@ -142,7 +156,7 @@ TEST(EnsureUniqueDQForNodeUnitTests, DQSharedAmongNodesWithSubgraphConsumer) { config.has_subgraph_consumer = true; // expected count = preserved original (1) + one for each explicit consumer node (3) = 4 - RunEnsureUniqueDQForNodeUnitTest(GetGraphBuilder(config), 4); + RunEnsureUniqueDQForNodeUnitTest(config, 4); } TEST(EnsureUniqueDQForNodeUnitTests, DQSharedAmongNodesWithSubgraphConsumerAndGraphOutput) { @@ -153,7 +167,7 @@ TEST(EnsureUniqueDQForNodeUnitTests, DQSharedAmongNodesWithSubgraphConsumerAndGr config.has_subgraph_consumer = true; // expected count = preserved original (1) + one for each explicit consumer node (3) = 4 - RunEnsureUniqueDQForNodeUnitTest(GetGraphBuilder(config), 4); + RunEnsureUniqueDQForNodeUnitTest(config, 4); } TEST(EnsureUniqueDQForNodeUnitTests, DQSharedAmongNodeInputs) { @@ -162,7 +176,7 @@ TEST(EnsureUniqueDQForNodeUnitTests, DQSharedAmongNodeInputs) { config.num_inputs_per_explicit_consumer_node = 5; // expected count = one for each explicit consumer node input (2 * 5), reusing the original one = 10 - RunEnsureUniqueDQForNodeUnitTest(GetGraphBuilder(config), 10); + RunEnsureUniqueDQForNodeUnitTest(config, 10); } TEST(EnsureUniqueDQForNodeUnitTests, DQSharedAmongNodeInputsWithGraphOutput) { @@ -172,7 +186,7 @@ TEST(EnsureUniqueDQForNodeUnitTests, DQSharedAmongNodeInputsWithGraphOutput) { config.has_graph_output = true; // expected count = preserved original (1) + one for each explicit consumer node input (2 * 5) = 11 - RunEnsureUniqueDQForNodeUnitTest(GetGraphBuilder(config), 11); + RunEnsureUniqueDQForNodeUnitTest(config, 11); } TEST(EnsureUniqueDQForNodeUnitTests, DQSharedAmongNodeInputsWithSubgraphConsumer) { @@ -182,7 +196,7 @@ TEST(EnsureUniqueDQForNodeUnitTests, DQSharedAmongNodeInputsWithSubgraphConsumer config.has_subgraph_consumer = true; // expected count = preserved original (1) + one for each explicit consumer node input (2 * 5) = 11 - RunEnsureUniqueDQForNodeUnitTest(GetGraphBuilder(config), 11); + RunEnsureUniqueDQForNodeUnitTest(config, 11); } TEST(EnsureUniqueDQForNodeUnitTests, DQSharedAmongNodeInputsWithSubgraphConsumerAndGraphOutput) { @@ -193,7 +207,7 @@ TEST(EnsureUniqueDQForNodeUnitTests, DQSharedAmongNodeInputsWithSubgraphConsumer config.has_subgraph_consumer = true; // expected count = preserved original (1) + one for each explicit consumer node input (2 * 5) = 11 - RunEnsureUniqueDQForNodeUnitTest(GetGraphBuilder(config), 11); + RunEnsureUniqueDQForNodeUnitTest(config, 11); } TEST(EnsureUniqueDQForNodeUnitTests, QDQWithMultiConsumerDQNodes) { diff --git a/onnxruntime/test/optimizer/graph_transform_test.cc b/onnxruntime/test/optimizer/graph_transform_test.cc index bd2b733225a36..dce1f2d40e8b9 100755 --- a/onnxruntime/test/optimizer/graph_transform_test.cc +++ b/onnxruntime/test/optimizer/graph_transform_test.cc @@ -35,7 +35,6 @@ #include "core/optimizer/div_mul_fusion.h" #include "core/optimizer/dropout_elimination.h" #include "core/optimizer/dynamic_quantize_matmul_fusion.h" -#include "core/optimizer/embed_layer_norm_fusion.h" #include "core/optimizer/expand_elimination.h" #include "core/optimizer/fast_gelu_fusion.h" #include "core/optimizer/gather_fusion.h" @@ -51,7 +50,6 @@ #include "core/optimizer/identity_elimination.h" #include "core/optimizer/initializer.h" #include "core/optimizer/isinf_reducesum_fusion.h" -#include "core/optimizer/layer_norm_fusion.h" #include "core/optimizer/matmul_add_fusion.h" #include "core/optimizer/matmul_integer_to_float.h" #include "core/optimizer/matmul_scale_fusion.h" @@ -63,7 +61,6 @@ #include "core/optimizer/relu_clip_fusion.h" #include "core/optimizer/reshape_fusion.h" #include "core/optimizer/rule_based_graph_transformer.h" -#include "core/optimizer/skip_layer_norm_fusion.h" #include "core/optimizer/slice_elimination.h" #include "core/optimizer/unsqueeze_elimination.h" #include "core/optimizer/utils.h" @@ -84,7 +81,10 @@ #include "test/util/include/inference_session_wrapper.h" #include "test/util/include/temp_dir.h" #include "test/util/include/test_utils.h" -#ifdef ENABLE_TRAINING_CORE +#include "core/optimizer/pre_shape_node_elimination.h" +#include "core/optimizer/double_qdq_pairs_remover.h" +#include "core/optimizer/qdq_transformer/qdq_util.h" +#ifdef ENABLE_TRAINING #include "orttraining/core/optimizer/bitmask_dropout_replacement.h" #endif @@ -156,22 +156,42 @@ TEST_F(GraphTransformationTests, IdentityWithSharedNodeArgNotEliminated) { ASSERT_TRUE(op_to_count["Add"] == 1); } +// Runs a model to ensure that common subexpression elimination does not eliminate +// DequantizeLinear nodes. TEST_F(GraphTransformationTests, DequantizeLinearNodeNotEliminated) { - constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "qdq_with_multi_consumer_dq_nodes.fixed.onnx"; - std::shared_ptr model; - ASSERT_STATUS_OK(Model::Load(model_uri, model, nullptr, *logger_)); - Graph& graph = model->MainGraph(); - std::map op_to_count = CountOpsInGraph(graph); - ASSERT_EQ(op_to_count["DequantizeLinear"], 25); + auto test_case = [](const ORTCHAR_T* model_uri, + bool use_contrib_qdq, + const logging::Logger& logger) { + const char* dq_key = use_contrib_qdq ? "com.microsoft.DequantizeLinear" : "DequantizeLinear"; + std::shared_ptr model; + ASSERT_STATUS_OK(Model::Load(model_uri, model, nullptr, logger)); + Graph& graph = model->MainGraph(); + std::map op_to_count = CountOpsInGraph(graph); + ASSERT_EQ(op_to_count[dq_key], 25); - onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), - TransformerLevel::Level1)); - ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level1, *logger_)); + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), + TransformerLevel::Level1)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level1, logger)); - // CommonSubexpressionElimination should skip the DequantizeLinear nodes - op_to_count = CountOpsInGraph(graph); - ASSERT_EQ(op_to_count["DequantizeLinear"], 25); + // CommonSubexpressionElimination should skip the DequantizeLinear nodes + op_to_count = CountOpsInGraph(graph); + ASSERT_EQ(op_to_count[dq_key], 25); + }; + + test_case(MODEL_FOLDER "qdq_with_multi_consumer_dq_nodes.fixed.onnx", + false, // use_contrib_qdq + *logger_); +#if !defined(DISABLE_CONTRIB_OPS) + // Test with 8-bit com.microsoft.DequantizeLinear + test_case(MODEL_FOLDER "qdq_with_multi_consumer_dq_nodes.fixed.qdq_contrib.onnx", + true, // use_contrib_qdq + *logger_); + // Test with 16-bit com.microsoft.DequantizeLinear + test_case(MODEL_FOLDER "qdq_with_multi_consumer_dq_nodes.fixed.qdq16_contrib.onnx", + true, // use_contrib_qdq + *logger_); +#endif // !defined(DISABLE_CONTRIB_OPS) } TEST_F(GraphTransformationTests, IdentityInputIsGraphOutputNotEliminated) { @@ -593,6 +613,36 @@ TEST_F(GraphTransformationTests, ConstantFoldingNodesOnDifferentEP) { } } +TEST_F(GraphTransformationTests, ConstantFoldingUnsupportedFloat16) { + constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "constant_float16_mul.onnx"; + std::shared_ptr model; + ASSERT_STATUS_OK(Model::Load(model_uri, model, nullptr, *logger_)); + Graph& graph = model->MainGraph(); + std::map op_to_count = CountOpsInGraph(graph); + ASSERT_TRUE(op_to_count["Mul"] == 1); + std::unique_ptr e = + std::make_unique(CPUExecutionProviderInfo()); + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register( + std::make_unique(*e.get(), false /*skip_dequantize_linear*/), TransformerLevel::Level1)); + + // assign all nodes to CUDA. the constant folding should try folding the node on the CPU and fail, thus leaving the + // EP as CUDA and not constant folding the node. + for (auto& node : graph.Nodes()) { + node.SetExecutionProviderType(kCudaExecutionProvider); + } + + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level1, *logger_)); + + op_to_count = CountOpsInGraph(graph); + ASSERT_TRUE(op_to_count["Mul"] == 1); + + // all nodes should still be on CUDA + for (auto& node : graph.Nodes()) { + EXPECT_STREQ(node.GetExecutionProviderType().c_str(), kCudaExecutionProvider); + } +} + TEST_F(GraphTransformationTests, ConstantFoldingSubgraph) { TensorProto value_tensor; value_tensor.add_dims(1); @@ -786,76 +836,119 @@ static void VerifyConstantFoldingWithDequantizeLinear(const std::unordered_map model; - ASSERT_STATUS_OK(Model::Load(model_uri, model, nullptr, *logger_)); - Graph& graph = model->MainGraph(); - std::map op_to_count = CountOpsInGraph(graph); - ASSERT_TRUE(op_to_count["QuantizeLinear"] == 1); - ASSERT_TRUE(op_to_count["DequantizeLinear"] == 3); - ASSERT_TRUE(op_to_count["Conv"] == 1); + auto test_case = [](const ORTCHAR_T* model_uri, + bool use_contrib_qdq, + const logging::Logger& logger) { + const char* q_key = use_contrib_qdq ? "com.microsoft.QuantizeLinear" : "QuantizeLinear"; + const char* dq_key = use_contrib_qdq ? "com.microsoft.DequantizeLinear" : "DequantizeLinear"; + + std::shared_ptr model; + ASSERT_STATUS_OK(Model::Load(model_uri, model, nullptr, logger)); + Graph& graph = model->MainGraph(); + std::map op_to_count = CountOpsInGraph(graph); + ASSERT_TRUE(op_to_count[q_key] == 1); + ASSERT_TRUE(op_to_count[dq_key] == 3); + ASSERT_TRUE(op_to_count["Conv"] == 1); - std::unordered_map expected_op_counts = {{"QuantizeLinear", 1}, - {"DequantizeLinear", 3}, - {"Conv", 1}}; + std::unordered_map expected_op_counts = {{q_key, 1}, + {dq_key, 3}, + {"Conv", 1}}; - SessionOptions session_options; - // Check DequantizeLinear aren't constant folded for default setting. - VerifyConstantFoldingWithDequantizeLinear(expected_op_counts, graph, session_options, *logger_); + SessionOptions session_options; + // Check DequantizeLinear aren't constant folded for default setting. + VerifyConstantFoldingWithDequantizeLinear(expected_op_counts, graph, session_options, logger); + + // set kOrtSessionOptionsDisableQuantQDQ to enable it explicitly + ASSERT_STATUS_OK(session_options.config_options.AddConfigEntry(kOrtSessionOptionsDisableQuantQDQ, "0")); + VerifyConstantFoldingWithDequantizeLinear(expected_op_counts, graph, session_options, logger); - // set kOrtSessionOptionsDisableQuantQDQ to enable it explicitly - ASSERT_STATUS_OK(session_options.config_options.AddConfigEntry(kOrtSessionOptionsDisableQuantQDQ, "0")); - VerifyConstantFoldingWithDequantizeLinear(expected_op_counts, graph, session_options, *logger_); + // set SessionOptionsEnableQuantQDQ to disable it + expected_op_counts[dq_key] = 1; + ASSERT_STATUS_OK(session_options.config_options.AddConfigEntry(kOrtSessionOptionsDisableQuantQDQ, "1")); + VerifyConstantFoldingWithDequantizeLinear(expected_op_counts, graph, session_options, logger); + }; - // set SessionOptionsEnableQuantQDQ to disable it - expected_op_counts["DequantizeLinear"] = 1; - ASSERT_STATUS_OK(session_options.config_options.AddConfigEntry(kOrtSessionOptionsDisableQuantQDQ, "1")); - VerifyConstantFoldingWithDequantizeLinear(expected_op_counts, graph, session_options, *logger_); + test_case(MODEL_FOLDER "fusion/constant_folding_dequantizelinear.onnx", + false, *logger_); +#if !defined(DISABLE_CONTRIB_OPS) + // Test with 8-bit contrib QDQ ops + test_case(MODEL_FOLDER "fusion/constant_folding_dequantizelinear.qdq_contrib.onnx", + true, *logger_); + // Test with 16-bit contrib QDQ ops + test_case(MODEL_FOLDER "fusion/constant_folding_dequantizelinear.qdq16_contrib.onnx", + true, *logger_); +#endif // !defined(DISABLE_CONTRIB_OPS) } // model with 2 QDQ node units that can be constant folded as they are simple DQ -> Node -> Q where DQ and Node have // single consumer and do not produce graph outputs. Node is deterministic. // there are also other DQ nodes that should be ignored. TEST_F(GraphTransformationTests, ConstantFoldingQDQNodeUnit) { - constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/constant_folding_qdq_node_unit.onnx"; - std::shared_ptr model; - ASSERT_STATUS_OK(Model::Load(model_uri, model, nullptr, *logger_)); - Graph& graph = model->MainGraph(); - std::map op_to_count = CountOpsInGraph(graph); - ASSERT_TRUE(op_to_count["QuantizeLinear"] == 3); - ASSERT_TRUE(op_to_count["DequantizeLinear"] == 4); - ASSERT_TRUE(op_to_count["Unsqueeze"] == 1); - ASSERT_TRUE(op_to_count["Transpose"] == 1); + auto test_case = [](const ORTCHAR_T* model_uri, bool use_contrib_qdq, const logging::Logger& logger) { + const char* q_key = use_contrib_qdq ? "com.microsoft.QuantizeLinear" : "QuantizeLinear"; + const char* dq_key = use_contrib_qdq ? "com.microsoft.DequantizeLinear" : "DequantizeLinear"; - SessionOptions session_options; + std::shared_ptr model; + ASSERT_STATUS_OK(Model::Load(model_uri, model, nullptr, logger)); + Graph& graph = model->MainGraph(); + std::map op_to_count = CountOpsInGraph(graph); + ASSERT_TRUE(op_to_count[q_key] == 3); + ASSERT_TRUE(op_to_count[dq_key] == 4); + ASSERT_TRUE(op_to_count["Unsqueeze"] == 1); + ASSERT_TRUE(op_to_count["Transpose"] == 1); + + SessionOptions session_options; + + // 2 QDQ node units should be constant folded and go away + std::unordered_map expected_op_counts = {{q_key, 1}, + {dq_key, 2}, + {"Transpose", 0}, + {"Unsqueeze", 0}}; - // 2 QDQ node units should be constant folded and go away - std::unordered_map expected_op_counts = {{"QuantizeLinear", 1}, - {"DequantizeLinear", 2}, - {"Transpose", 0}, - {"Unsqueeze", 0}}; + VerifyConstantFoldingWithDequantizeLinear(expected_op_counts, graph, session_options, logger); + }; - VerifyConstantFoldingWithDequantizeLinear(expected_op_counts, graph, session_options, *logger_); + test_case(MODEL_FOLDER "fusion/constant_folding_qdq_node_unit.onnx", false, *logger_); +#if !defined(DISABLE_CONTRIB_OPS) + // Test with 8-bit com.microsoft.Q/DQ + test_case(MODEL_FOLDER "fusion/constant_folding_qdq_node_unit.qdq_contrib.onnx", true, *logger_); + // Test with 16-bit com.microsoft.Q/DQ + test_case(MODEL_FOLDER "fusion/constant_folding_qdq_node_unit.qdq16_contrib.onnx", true, *logger_); +#endif // !defined(DISABLE_CONTRIB_OPS) } // Simple QDQ Node Unit but shouldn't be constant folded as the node in the middle produces a graph output TEST_F(GraphTransformationTests, ConstantFoldingQDQNodeUnitGraphOutput) { - constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/constant_folding_qdq_node_unit.graph_output.onnx"; - std::shared_ptr model; - ASSERT_STATUS_OK(Model::Load(model_uri, model, nullptr, *logger_)); - Graph& graph = model->MainGraph(); - std::map op_to_count = CountOpsInGraph(graph); - ASSERT_TRUE(op_to_count["QuantizeLinear"] == 2); - ASSERT_TRUE(op_to_count["DequantizeLinear"] == 3); - ASSERT_TRUE(op_to_count["Unsqueeze"] == 1); + auto test_case = [](const ORTCHAR_T* model_uri, bool use_contrib_qdq, const logging::Logger& logger) { + const char* q_key = use_contrib_qdq ? "com.microsoft.QuantizeLinear" : "QuantizeLinear"; + const char* dq_key = use_contrib_qdq ? "com.microsoft.DequantizeLinear" : "DequantizeLinear"; + + std::shared_ptr model; + ASSERT_STATUS_OK(Model::Load(model_uri, model, nullptr, logger)); + Graph& graph = model->MainGraph(); + std::map op_to_count = CountOpsInGraph(graph); + ASSERT_TRUE(op_to_count[q_key] == 2); + ASSERT_TRUE(op_to_count[dq_key] == 3); + ASSERT_TRUE(op_to_count["Unsqueeze"] == 1); - std::unordered_map expected_op_counts = {{"QuantizeLinear", 2}, - {"DequantizeLinear", 3}, - {"Unsqueeze", 1}}; + std::unordered_map expected_op_counts = {{q_key, 2}, + {dq_key, 3}, + {"Unsqueeze", 1}}; - SessionOptions session_options; - VerifyConstantFoldingWithDequantizeLinear(expected_op_counts, graph, session_options, *logger_); + SessionOptions session_options; + VerifyConstantFoldingWithDequantizeLinear(expected_op_counts, graph, session_options, logger); + }; + + test_case(MODEL_FOLDER "fusion/constant_folding_qdq_node_unit.graph_output.onnx", false, *logger_); +#if !defined(DISABLE_CONTRIB_OPS) + // Test with 8-bit contrib QDQ ops + test_case(MODEL_FOLDER "fusion/constant_folding_qdq_node_unit.graph_output.qdq_contrib.onnx", true, *logger_); + + // Test with 16-bit contrib QDQ ops + test_case(MODEL_FOLDER "fusion/constant_folding_qdq_node_unit.graph_output.qdq16_contrib.onnx", true, *logger_); +#endif // !defined(DISABLE_CONTRIB_OPS) } TEST_F(GraphTransformationTests, ConstantFolding_RemoveDanglingInputNodesToConstantFoldedNode) { @@ -904,7 +997,7 @@ TEST_F(GraphTransformationTests, ConstantFoldingAShapeNodeDeepInTheGraph) { // removes all its ancestors and the Identity node consuming this Shape's // output is subsequently constant folded to leave the graph with no // nodes. - ASSERT_TRUE(op_to_count.size() == 0); + ASSERT_TRUE(op_to_count.size() == 0U); } // Check transformations in the case of a subgraph with constant inputs. @@ -2350,13 +2443,13 @@ TEST_F(GraphTransformationTests, FuseConvBnAddMulFloat16) { run_options.run_tag = "one session/one tag"; OrtValue ml_value_x; - auto x_f = MLFloat16(math::floatToHalf(1.0)); + auto x_f = MLFloat16(1.0f); std::vector dims_x = {1, 1, 3, 3}; std::vector values_x; for (int i = 0; i < 9; ++i) { values_x.push_back(x_f); } - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], dims_x, values_x, &ml_value_x); feeds.insert(std::make_pair("X", ml_value_x)); @@ -2366,7 +2459,7 @@ TEST_F(GraphTransformationTests, FuseConvBnAddMulFloat16) { ASSERT_STATUS_OK(session_object.Run(run_options, feeds, output_names, &fetches)); - auto prod_f = MLFloat16(math::floatToHalf(6.0)); + auto prod_f = MLFloat16(6.0f); std::vector expected_dims_prod = {1, 1, 2, 2}; std::vector expected_values_prod; for (int i = 0; i < 4; ++i) { @@ -2623,7 +2716,7 @@ TEST_F(GraphTransformationTests, ReshapeFusionTest) { auto initializer = std::make_unique(*tensor_proto, graph.ModelPath()); EXPECT_EQ(tensor_proto->data_type(), ONNX_NAMESPACE::TensorProto_DataType_INT64); - EXPECT_EQ(initializer->size(), 4); + EXPECT_EQ(initializer->size(), 4U); const int64_t* val = initializer->data(); EXPECT_EQ(val[0], 0); @@ -2659,7 +2752,7 @@ TEST_F(GraphTransformationTests, ReshapeFusionOneConstTest) { auto initializer = std::make_unique(*tensor_proto, graph.ModelPath()); EXPECT_EQ(tensor_proto->data_type(), ONNX_NAMESPACE::TensorProto_DataType_INT64); - EXPECT_EQ(initializer->size(), 3); + EXPECT_EQ(initializer->size(), 3U); const int64_t* val = initializer->data(); EXPECT_EQ(val[0], 0); @@ -2694,7 +2787,7 @@ TEST_F(GraphTransformationTests, ReshapeFusionInternalNodeIsOutput) { auto initializer = std::make_unique(*tensor_proto, graph.ModelPath()); EXPECT_EQ(tensor_proto->data_type(), ONNX_NAMESPACE::TensorProto_DataType_INT64); - EXPECT_EQ(initializer->size(), 3); + EXPECT_EQ(initializer->size(), 3U); const int64_t* val = initializer->data(); EXPECT_EQ(val[0], 0); @@ -2730,7 +2823,7 @@ TEST_F(GraphTransformationTests, ReshapeFusionInternalReuseTest) { auto initializer = std::make_unique(*tensor_proto, graph.ModelPath()); EXPECT_EQ(tensor_proto->data_type(), ONNX_NAMESPACE::TensorProto_DataType_INT64); - EXPECT_EQ(initializer->size(), 5); + EXPECT_EQ(initializer->size(), 5U); const int64_t* val = initializer->data(); EXPECT_EQ(val[0], 0); @@ -2789,7 +2882,7 @@ TEST_F(GraphTransformationTests, ReshapeFusionMultipleValuesInInitializerSubgrap auto initializer = std::make_unique(*tensor_proto, graph.ModelPath()); EXPECT_EQ(tensor_proto->data_type(), ONNX_NAMESPACE::TensorProto_DataType_INT64); - EXPECT_EQ(initializer->size(), 3); + EXPECT_EQ(initializer->size(), 3U); const int64_t* val = initializer->data(); EXPECT_EQ(val[0], 1); @@ -2822,7 +2915,7 @@ TEST_F(GraphTransformationTests, ReshapeFusionMultipleValuesInInitializerApplies auto initializer = std::make_unique(*tensor_proto, graph.ModelPath()); EXPECT_EQ(tensor_proto->data_type(), ONNX_NAMESPACE::TensorProto_DataType_INT64); - EXPECT_EQ(initializer->size(), 3); + EXPECT_EQ(initializer->size(), 3U); const int64_t* val = initializer->data(); EXPECT_EQ(val[0], 1); @@ -2892,7 +2985,7 @@ TEST_F(GraphTransformationTests, ReshapeFusionConcatSubgraphMultipleOutputs) { auto initializer = std::make_unique(*tensor_proto, graph.ModelPath()); EXPECT_EQ(tensor_proto->data_type(), ONNX_NAMESPACE::TensorProto_DataType_INT64); - EXPECT_EQ(initializer->size(), 3); + EXPECT_EQ(initializer->size(), 3U); const int64_t* val = initializer->data(); EXPECT_EQ(val[0], 0); @@ -2926,7 +3019,7 @@ TEST_F(GraphTransformationTests, ReshapeFusionConcatSubgraph) { auto initializer = std::make_unique(*tensor_proto, graph.ModelPath()); EXPECT_EQ(tensor_proto->data_type(), ONNX_NAMESPACE::TensorProto_DataType_INT64); - EXPECT_EQ(initializer->size(), 3); + EXPECT_EQ(initializer->size(), 3U); const int64_t* val = initializer->data(); EXPECT_EQ(val[0], 0); @@ -2960,7 +3053,7 @@ TEST_F(GraphTransformationTests, ReshapeFusionWithSlice1) { auto initializer = std::make_unique(*tensor_proto, graph.ModelPath()); EXPECT_EQ(tensor_proto->data_type(), ONNX_NAMESPACE::TensorProto_DataType_INT64); - EXPECT_EQ(initializer->size(), 3); + EXPECT_EQ(initializer->size(), 3U); const int64_t* val = initializer->data(); EXPECT_EQ(val[0], 0); @@ -3030,7 +3123,7 @@ TEST_F(GraphTransformationTests, ReshapeFusionConcatSubgraphWithDiv) { auto initializer = std::make_unique(*tensor_proto, graph.ModelPath()); EXPECT_EQ(tensor_proto->data_type(), ONNX_NAMESPACE::TensorProto_DataType_INT64); - EXPECT_EQ(initializer->size(), 3); + EXPECT_EQ(initializer->size(), 3U); const int64_t* val = initializer->data(); EXPECT_EQ(val[0], 0); @@ -3066,7 +3159,7 @@ TEST_F(GraphTransformationTests, ReshapeFusionConcatSubgraphWithMul) { auto initializer = std::make_unique(*tensor_proto, graph.ModelPath()); EXPECT_EQ(tensor_proto->data_type(), ONNX_NAMESPACE::TensorProto_DataType_INT64); - EXPECT_EQ(initializer->size(), 3); + EXPECT_EQ(initializer->size(), 3U); const int64_t* val = initializer->data(); EXPECT_EQ(val[0], 0); @@ -3100,7 +3193,7 @@ TEST_F(GraphTransformationTests, ReshapeFusionDistilBertTest) { auto initializer = std::make_unique(*tensor_proto, graph.ModelPath()); EXPECT_EQ(tensor_proto->data_type(), ONNX_NAMESPACE::TensorProto_DataType_INT64); - EXPECT_EQ(initializer->size(), 4); + EXPECT_EQ(initializer->size(), 4U); const int64_t* val = initializer->data(); EXPECT_EQ(val[0], 0); @@ -3163,6 +3256,69 @@ TEST_F(GraphTransformationTests, CastElimination) { ASSERT_TRUE(op_to_count["Cast"] == 4); } +TEST_F(GraphTransformationTests, PreShapeNodeElimination) { + constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "pre_shape_node_elimination.onnx"; + std::shared_ptr model; + ASSERT_TRUE(Model::Load(model_uri, model, nullptr, *logger_).IsOK()); + Graph& graph = model->MainGraph(); + std::map op_to_count = CountOpsInGraph(graph); + ASSERT_TRUE(op_to_count["Cast"] == 3); + + auto rule_transformer_L1 = std::make_unique("RuleTransformer1"); + ASSERT_STATUS_OK(rule_transformer_L1->Register(std::make_unique())); + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::move(rule_transformer_L1), TransformerLevel::Level1)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level1, *logger_)); + + op_to_count = CountOpsInGraph(graph); + + ASSERT_TRUE(op_to_count["Cast"] == 2); + + // Assert that the remaining "Cast" nodes have different names than "cast2" + bool names_are_different = true; + for (const Node& node : graph.Nodes()) { + if (node.OpType() == "Cast") { + const std::string& node_name = node.Name(); + if (node_name == "cast") { + names_are_different = false; + break; + } + } + } + + ASSERT_TRUE(names_are_different); + + auto pre_graph_checker = [](Graph& graph) { + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Cast"] == 1); + return Status::OK(); + }; + + auto post_graph_checker = [&](Graph& graph) { + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Cast"] == 0); + return Status::OK(); + }; + + // cast is the first node. + { + auto build_test_case = [&](ModelTestBuilder& builder) { + auto* input_arg = builder.MakeInput({{2, 3, 3, 3}}); + auto* cast_out = builder.MakeIntermediate(); + auto* shape_out = builder.MakeIntermediate(); + auto* output = builder.MakeOutput(); + + builder.AddNode("Cast", {input_arg}, {cast_out}) + .AddAttribute("to", static_cast(ONNX_NAMESPACE::TensorProto_DataType_FLOAT)); + builder.AddNode("Shape", {cast_out}, {shape_out}); + builder.AddNode("Identity", {shape_out}, {output}); + }; + + auto rule_transformer = std::make_unique("RuleTransformer"); + ASSERT_STATUS_OK(rule_transformer->Register(std::make_unique())); + ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, 13, *logger_, std::move(rule_transformer), TransformerLevel::Level1, 1, + pre_graph_checker, post_graph_checker)); + } +} + #ifndef DISABLE_CONTRIB_OPS static void ValidateAttention(Graph& graph) { @@ -3177,7 +3333,7 @@ static void ValidateAttention(Graph& graph) { EXPECT_EQ(tensor_proto->data_type(), ONNX_NAMESPACE::TensorProto_DataType_FLOAT); auto initializer = std::make_unique(*tensor_proto, graph.ModelPath()); - EXPECT_EQ(initializer->size(), 192); + EXPECT_EQ(initializer->size(), 192U); // Validate two rows (2x24 items) for sanity check. std::vector expected_value = { @@ -3241,7 +3397,7 @@ static void ValidateAttention(Graph& graph) { EXPECT_EQ(tensor_proto->data_type(), ONNX_NAMESPACE::TensorProto_DataType_FLOAT); auto initializer2 = std::make_unique(*tensor_proto, graph.ModelPath()); - EXPECT_EQ(initializer2->size(), 24); + EXPECT_EQ(initializer2->size(), 24U); std::vector expected_value2 = { -0.23681640625, @@ -3591,13 +3747,13 @@ TEST_F(GraphTransformationTests, BiasGeluSwitchedInputOrder) { OrtValue mlvalue_b_i; std::vector dims_b_i = {3072}; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), dims_b_i, + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], dims_b_i, random.Uniform(dims_b_i, 0.0f, 1.0f), &mlvalue_b_i); feeds.insert(std::make_pair("B_I", mlvalue_b_i)); OrtValue mlvalue_a_i; std::vector dims_a_i = {3, 512, 3072}; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), dims_a_i, + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], dims_a_i, random.Uniform(dims_a_i, 0.0f, 1.0f), &mlvalue_a_i); feeds.insert(std::make_pair("A_I", mlvalue_a_i)); @@ -3683,6 +3839,41 @@ TEST_F(GraphTransformationTests, GeluApproximation_SessionOptionConfig) { VerifyGeluApproximation(false, session_options); } +// Test DoubleQDQPairsRemover to remove unnecessary DQ->Q nodes in the middle +TEST_F(GraphTransformationTests, DoublQDQRemover_RemoveDupQDQ) { + constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "qdq_optimization/dup_qdq.onnx"; + std::shared_ptr p_model; + ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); + Graph& graph = p_model->MainGraph(); + + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level1)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level1, *logger_)); + + std::map op_to_count = CountOpsInGraph(graph); + EXPECT_EQ(op_to_count["QuantizeLinear"], 3); + EXPECT_EQ(op_to_count["DequantizeLinear"], 4); + + std::string dq_scale_name_before_reshape_node; + std::string zp_name_before_reshape_node; + std::string dq_scale_name_after_reshape_node; + std::string zp_name_after_reshape_node; + for (auto& node : graph.Nodes()) { + if (node.Name() == "dq_2") { + dq_scale_name_before_reshape_node = node.InputDefs()[QDQ::InputIndex::SCALE_ID]->Name(); + zp_name_before_reshape_node = node.InputDefs()[QDQ::InputIndex::ZERO_POINT_ID]->Name(); + } + if (node.Name() == "q_3") { + dq_scale_name_after_reshape_node = node.InputDefs()[QDQ::InputIndex::SCALE_ID]->Name(); + zp_name_after_reshape_node = node.InputDefs()[QDQ::InputIndex::ZERO_POINT_ID]->Name(); + } + } + EXPECT_EQ(dq_scale_name_before_reshape_node.empty(), false); + EXPECT_EQ(zp_name_before_reshape_node.empty(), false); + EXPECT_EQ(dq_scale_name_before_reshape_node, dq_scale_name_after_reshape_node); + EXPECT_EQ(zp_name_before_reshape_node, zp_name_after_reshape_node); +} + // Test Gelu -> FastGelu TEST_F(GraphTransformationTests, GeluApproximation_Gelu) { constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "approximation/gelu.onnx"; @@ -4450,7 +4641,7 @@ TEST_F(GraphTransformationTests, BiasDropoutFusionTest) { TestBiasDropoutFusion(MODEL_FOLDER "fusion/bias_dropout_residual_same_shape_fusion_dim_is_param.onnx", *logger_); } -#ifdef ENABLE_TRAINING_CORE +#ifdef ENABLE_TRAINING static void TestBitmaskDropoutFusion(const PathString& file_path, bool is_bias_dropout, const logging::Logger& logger, const int add_count, const int dropout_count, const int bitmask_dropout_count, const int bias_dropout_count, const int bitmask_bias_dropout_count, @@ -4610,884 +4801,128 @@ TEST_F(GraphTransformationTests, ReshapeFusionOpsetTest) { } #endif -TEST_F(GraphTransformationTests, LayerNormFusionTest) { - constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/layer_norm.onnx"; +TEST_F(GraphTransformationTests, DynamicQuantizeMatMulTest) { + constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/dynamic_quantize_matmul.onnx"; std::shared_ptr p_model; ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); Graph& graph = p_model->MainGraph(); onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); std::map op_to_count = CountOpsInGraph(graph); - ASSERT_TRUE(op_to_count["Div"] == 0); - ASSERT_TRUE(op_to_count["Add"] == 0); - ASSERT_TRUE(op_to_count["Sub"] == 0); - ASSERT_TRUE(op_to_count["ReduceMean"] == 0); - ASSERT_TRUE(op_to_count["Pow"] == 0); - ASSERT_TRUE(op_to_count["Sqrt"] == 0); - ASSERT_TRUE(op_to_count["LayerNormalization"] == 1); - - for (const Node& node : graph.Nodes()) { - if (node.OpType() == "LayerNormalization") { - // LayerNormalization should have three inputs. - EXPECT_EQ(node.InputDefs().size(), 3u) << "LayerNormalization number of inputs does not equal to 3. Got:" << node.InputDefs().size(); - // LayerNormalization input "scale" and "bias" should have the same dimension. - const TensorShapeProto* scale_shape = node.InputDefs()[1]->Shape(); - const TensorShapeProto* bias_shape = node.InputDefs()[2]->Shape(); - EXPECT_EQ(scale_shape->dim_size(), 1) << "LayerNormalization scale should be 1D. Got: " << scale_shape->dim_size(); - EXPECT_EQ(bias_shape->dim_size(), 1) << "LayerNormalization bias should be 1D. Got: " << bias_shape->dim_size(); - EXPECT_EQ(scale_shape->dim(0).dim_value(), bias_shape->dim(0).dim_value()); - } else { - EXPECT_TRUE(false) << "Unexpected node " << node.Name(); - } - } + EXPECT_EQ(op_to_count["DynamicQuantizeLinear"], 0); + EXPECT_EQ(op_to_count["MatMulInteger"], 0); + EXPECT_EQ(op_to_count["Cast"], 0); + EXPECT_EQ(op_to_count["Mul"], 0); + EXPECT_EQ(op_to_count["com.microsoft.DynamicQuantizeMatMul"], 1); } -TEST_F(GraphTransformationTests, LayerNormWithCastFusionTest) { - constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/layer_norm_with_cast.onnx"; +TEST_F(GraphTransformationTests, DynamicQuantizeMatMulTest_With_Bias) { + constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/dynamic_quantize_matmul_bias.onnx"; std::shared_ptr p_model; ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); Graph& graph = p_model->MainGraph(); onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); std::map op_to_count = CountOpsInGraph(graph); - -#ifdef ENABLE_TRAINING_CORE - ASSERT_TRUE(op_to_count["Cast"] == 0); - ASSERT_TRUE(op_to_count["LayerNormalization"] == 1); -#else - ASSERT_TRUE(op_to_count["Cast"] == 1); - ASSERT_TRUE(op_to_count["LayerNormalization"] == 0); -#endif + EXPECT_EQ(op_to_count["DynamicQuantizeLinear"], 0); + EXPECT_EQ(op_to_count["MatMulInteger"], 0); + EXPECT_EQ(op_to_count["Cast"], 0); + EXPECT_EQ(op_to_count["Mul"], 0); + EXPECT_EQ(op_to_count["com.microsoft.DynamicQuantizeMatMul"], 1); } -TEST_F(GraphTransformationTests, LayerNormWithCastFusionTest_2) { - constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/layer_norm_with_cast_2.onnx"; +TEST_F(GraphTransformationTests, DynamicQuantizeMatMulTest_With_ND_bias) { + constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/dynamic_quantize_matmul_bias_ND.onnx"; std::shared_ptr p_model; ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); Graph& graph = p_model->MainGraph(); onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); std::map op_to_count = CountOpsInGraph(graph); - - ASSERT_TRUE(op_to_count["Cast"] == 0); - ASSERT_TRUE(op_to_count["LayerNormalization"] == 1); + EXPECT_EQ(op_to_count["DynamicQuantizeLinear"], 0); + EXPECT_EQ(op_to_count["MatMulInteger"], 0); + EXPECT_EQ(op_to_count["Cast"], 0); + EXPECT_EQ(op_to_count["Mul"], 0); + EXPECT_EQ(op_to_count["com.microsoft.DynamicQuantizeMatMul"], 1); + EXPECT_EQ(op_to_count["Add"], 1); } -TEST_F(GraphTransformationTests, LayerNormWithCastFusionTest_3) { - constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/layer_norm_with_cast_3.onnx"; +TEST_F(GraphTransformationTests, DynamicQuantizeMatMulTest_With_Bias_No_B_ZP) { + constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/dynamic_quantize_matmul_bias_b_no_zp.onnx"; std::shared_ptr p_model; ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); Graph& graph = p_model->MainGraph(); onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); std::map op_to_count = CountOpsInGraph(graph); - - ASSERT_TRUE(op_to_count["Cast"] == 0); - ASSERT_TRUE(op_to_count["LayerNormalization"] == 1); + EXPECT_EQ(op_to_count["DynamicQuantizeLinear"], 0); + EXPECT_EQ(op_to_count["MatMulInteger"], 0); + EXPECT_EQ(op_to_count["Cast"], 0); + EXPECT_EQ(op_to_count["Mul"], 0); + EXPECT_EQ(op_to_count["com.microsoft.DynamicQuantizeMatMul"], 1); } -TEST_F(GraphTransformationTests, LayerNormWithCastFusionTest_4) { - constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/layer_norm_with_cast_4.onnx"; +TEST_F(GraphTransformationTests, MatMulIntegerToFloatTest) { + constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/matmul_integer_to_float.onnx"; std::shared_ptr p_model; ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); Graph& graph = p_model->MainGraph(); onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); std::map op_to_count = CountOpsInGraph(graph); - - ASSERT_TRUE(op_to_count["Cast"] == 0); - ASSERT_TRUE(op_to_count["LayerNormalization"] == 1); + EXPECT_EQ(op_to_count["DynamicQuantizeLinear"], 1); + EXPECT_EQ(op_to_count["MatMulInteger"], 0); + EXPECT_EQ(op_to_count["Cast"], 0); + EXPECT_EQ(op_to_count["Mul"], 0); + EXPECT_EQ(op_to_count["com.microsoft.MatMulIntegerToFloat"], 3); + EXPECT_EQ(op_to_count["Add"], 1); } -TEST_F(GraphTransformationTests, LayerNormWithSubDupFusionTest) { - constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/layer_norm_sub_dup.onnx"; - std::shared_ptr p_model; - ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); - Graph& graph = p_model->MainGraph(); +#endif - onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); - ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); +#ifndef DISABLE_CONTRIB_OPS +template +static void TestMatMulScaleFusion( + const PathString& model_path, const Logger& logger, + GraphPreprocessFn graph_preprocess_fn, + GraphTransformationCheckFn graph_transformation_check_fn, + const InlinedHashSet& compatible_execution_providers = {}, + const InlinedHashSet& excluded_initializer_names = {}) { + SCOPED_TRACE(ORT_TSTR("model path: ") + model_path); - std::map op_to_count = CountOpsInGraph(graph); - ASSERT_TRUE(op_to_count["Div"] == 0); - ASSERT_TRUE(op_to_count["Add"] == 0); - ASSERT_TRUE(op_to_count["Sub"] == 0); - ASSERT_TRUE(op_to_count["ReduceMean"] == 0); - ASSERT_TRUE(op_to_count["Pow"] == 0); - ASSERT_TRUE(op_to_count["Sqrt"] == 0); - ASSERT_TRUE(op_to_count["LayerNormalization"] == 1); + std::shared_ptr model; + ASSERT_STATUS_OK(Model::Load(model_path, model, nullptr, logger)); + Graph& graph = model->MainGraph(); - for (const Node& node : graph.Nodes()) { - if (node.OpType() == "LayerNormalization") { - // LayerNormalization should have three inputs. - EXPECT_EQ(node.InputDefs().size(), 3u) << "LayerNormalization number of inputs does not equal to 3. Got:" << node.InputDefs().size(); - // LayerNormalization input "scale" and "bias" should have the same dimension. - const TensorShapeProto* scale_shape = node.InputDefs()[1]->Shape(); - const TensorShapeProto* bias_shape = node.InputDefs()[2]->Shape(); - EXPECT_EQ(scale_shape->dim_size(), 1) << "LayerNormalization scale should be 1D. Got: " << scale_shape->dim_size(); - EXPECT_EQ(bias_shape->dim_size(), 1) << "LayerNormalization bias should be 1D. Got: " << bias_shape->dim_size(); - EXPECT_EQ(scale_shape->dim(0).dim_value(), bias_shape->dim(0).dim_value()); - } else { - EXPECT_TRUE(false) << "Unexpected node " << node.Name(); - } - } -} + graph_preprocess_fn(graph); -TEST_F(GraphTransformationTests, LayerNormWithCastFusionTest_5) { - auto build_test_case = [&](ModelTestBuilder& builder) { - auto* data_arg = builder.MakeInput({{2, 3, 3, 3}}); - auto* pow_initializer = builder.MakeInitializer({}, {2.0f}); - auto* add_initializer = builder.MakeInitializer({}, {1e-5f}); - auto* weight_initializer = builder.MakeInitializer({3}, std::vector(3, MLFloat16(1.0f))); - auto* bias_initializer = builder.MakeInitializer({3}, std::vector(3, MLFloat16(0.0f))); - auto* reduce_mean_out_1 = builder.MakeIntermediate(); - auto* sub_out = builder.MakeIntermediate(); - auto* cast_out_1 = builder.MakeIntermediate(); - auto* pow_out = builder.MakeIntermediate(); - auto* reduce_mean_out_2 = builder.MakeIntermediate(); - auto* add_out_1 = builder.MakeIntermediate(); - auto* sqrt_out = builder.MakeIntermediate(); - auto* div_out = builder.MakeIntermediate(); - auto* cast_out_2 = builder.MakeIntermediate(); - auto* mul_out = builder.MakeIntermediate(); - auto* add_out_2 = builder.MakeOutput(); - auto opset = builder.DomainToVersionMap().find(kOnnxDomain)->second; - onnxruntime::NodeArg* axes = nullptr; - - if (opset >= 18) { - axes = builder.MakeInitializer({1}, {-1}); - builder.AddNode("ReduceMean", {data_arg, axes}, {reduce_mean_out_1}); - } else { - builder.AddNode("ReduceMean", {data_arg}, {reduce_mean_out_1}).AddAttribute("axes", std::vector{-1}); - } - builder.AddNode("Sub", {data_arg, reduce_mean_out_1}, {sub_out}); - builder.AddNode("Cast", {sub_out}, {cast_out_1}) - .AddAttribute("to", static_cast(ONNX_NAMESPACE::TensorProto_DataType_FLOAT)); - builder.AddNode("Pow", {cast_out_1, pow_initializer}, {pow_out}); - if (opset >= 18) { - builder.AddNode("ReduceMean", {pow_out, axes}, {reduce_mean_out_2}); - } else { - builder.AddNode("ReduceMean", {pow_out}, {reduce_mean_out_2}).AddAttribute("axes", std::vector{-1}); - } - builder.AddNode("Add", {reduce_mean_out_2, add_initializer}, {add_out_1}); - builder.AddNode("Sqrt", {add_out_1}, {sqrt_out}); - builder.AddNode("Div", {cast_out_1, sqrt_out}, {div_out}); - builder.AddNode("Cast", {div_out}, {cast_out_2}) - .AddAttribute("to", static_cast(ONNX_NAMESPACE::TensorProto_DataType_FLOAT16)); - builder.AddNode("Mul", {cast_out_2, weight_initializer}, {mul_out}); - builder.AddNode("Add", {mul_out, bias_initializer}, {add_out_2}); - }; + auto original_op_counts = CountOpsInGraph(graph); - auto pre_graph_checker = [&](Graph& graph) { - TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["ReduceMean"] == 2); - TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Sub"] == 1); - TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Cast"] == 2); - TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Pow"] == 1); - TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Add"] == 2); - TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Sqrt"] == 1); - TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Div"] == 1); - TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Mul"] == 1); - return Status::OK(); - }; - - auto post_graph_checker = [&](Graph& graph) { - TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["ReduceMean"] == 0); - TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Sub"] == 0); - TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Cast"] == 0); - TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Pow"] == 0); - TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Add"] == 0); - TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Sqrt"] == 0); - TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Div"] == 0); - TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Mul"] == 0); - TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["LayerNormalization"] == 1); - return Status::OK(); - }; - - std::unique_ptr transformer = std::make_unique(); - ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, {14, 18}, *logger_, std::move(transformer), TransformerLevel::Level1, - 1, pre_graph_checker, post_graph_checker)); -} - -TEST_F(GraphTransformationTests, SimplifiedLayerNormFusionTest) { - constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/layer_norm_t5.onnx"; - std::shared_ptr p_model; - ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); - Graph& graph = p_model->MainGraph(); - - onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); - ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); - - std::map op_to_count = CountOpsInGraph(graph); - ASSERT_TRUE(op_to_count["Div"] == 0); - ASSERT_TRUE(op_to_count["Add"] == 0); - ASSERT_TRUE(op_to_count["ReduceMean"] == 0); - ASSERT_TRUE(op_to_count["Pow"] == 0); - ASSERT_TRUE(op_to_count["Sqrt"] == 0); - ASSERT_TRUE(op_to_count["SimplifiedLayerNormalization"] == 1); - - for (const Node& node : graph.Nodes()) { - if (node.OpType() == "SimplifiedLayerNormalization") { - // LayerNormalization should have two inputs. - EXPECT_EQ(node.InputDefs().size(), 2u) << "LayerNormalization number of inputs does not equal to 2. Got:" << node.InputDefs().size(); - // LayerNormalization input "scale" and "bias" should have the same dimension. - const TensorShapeProto* scale_shape = node.InputDefs()[1]->Shape(); - EXPECT_EQ(scale_shape->dim_size(), 1) << "LayerNormalization scale should be 1D. Got: " << scale_shape->dim_size(); - } else { - EXPECT_TRUE(false) << "Unexpected node " << node.Name(); - } - } -} - -// If EP is non-GPU EP or unknown, the sub-graph will be not fused because CPU impl for SimplifiedLayerNormalization -// doesn't support input and scale having different data types. -TEST_F(GraphTransformationTests, SimplifiedLayerNormWithCastsFusionTest) { - constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/simplified_layer_norm_with_casts.onnx"; - std::shared_ptr p_model; - ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); - Graph& graph = p_model->MainGraph(); - - InlinedHashSet compatible_eps; - onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(compatible_eps), - TransformerLevel::Level2)); - ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); - - std::map op_to_count = CountOpsInGraph(graph); - ASSERT_TRUE(op_to_count["SimplifiedLayerNormalization"] == 0); -} - -TEST_F(GraphTransformationTests, SimplifiedLayerNormWithCastsFusionTestCudaEp) { - constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/simplified_layer_norm_with_casts.onnx"; - std::shared_ptr p_model; - ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); - Graph& graph = p_model->MainGraph(); - for (auto& node : graph.Nodes()) { - node.SetExecutionProviderType(kCudaExecutionProvider); - } - - InlinedHashSet compatible_eps; - onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(compatible_eps), - TransformerLevel::Level2)); - ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); - - std::map op_to_count = CountOpsInGraph(graph); - ASSERT_TRUE(op_to_count["Div"] == 0); - ASSERT_TRUE(op_to_count["Add"] == 0); - ASSERT_TRUE(op_to_count["ReduceMean"] == 0); - ASSERT_TRUE(op_to_count["Pow"] == 0); - ASSERT_TRUE(op_to_count["Sqrt"] == 0); - ASSERT_TRUE(op_to_count["Cast"] == 0); - ASSERT_TRUE(op_to_count["SimplifiedLayerNormalization"] == 1); - - for (const Node& node : graph.Nodes()) { - if (node.OpType() == "SimplifiedLayerNormalization") { - // LayerNormalization should have two inputs. - EXPECT_EQ(node.InputDefs().size(), 2u) - << "LayerNormalization number of inputs does not equal to 2. Got:" << node.InputDefs().size(); - // LayerNormalization input "scale" and "bias" should have the same dimension. - const TensorShapeProto* scale_shape = node.InputDefs()[1]->Shape(); - EXPECT_EQ(scale_shape->dim_size(), 1) - << "LayerNormalization scale should be 1D. Got: " << scale_shape->dim_size(); - } else if (node.OpType() == "Cast") { - continue; - } else { - EXPECT_TRUE(false) << "Unexpected node " << node.Name(); - } - } -} - -static void TestSkipLayerNormFusion(const std::basic_string& file_path, int add_count, int ln_count, - int skip_ln_count, int cast_count, logging::Logger* logger) { - std::shared_ptr p_model; - ASSERT_TRUE(Model::Load(file_path, p_model, nullptr, *logger).IsOK()); - Graph& graph = p_model->MainGraph(); - - onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); - ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger)); - - std::map op_to_count = CountOpsInGraph(graph); - ASSERT_TRUE(op_to_count["Div"] == 0); - ASSERT_TRUE(op_to_count["Add"] == add_count); - ASSERT_TRUE(op_to_count["Sub"] == 0); - ASSERT_TRUE(op_to_count["ReduceMean"] == 0); - ASSERT_TRUE(op_to_count["Pow"] == 0); - ASSERT_TRUE(op_to_count["Sqrt"] == 0); - ASSERT_TRUE(op_to_count["LayerNormalization"] == ln_count); - ASSERT_TRUE(op_to_count["com.microsoft.SkipLayerNormalization"] == skip_ln_count); - ASSERT_TRUE(op_to_count["Cast"] == cast_count); -} - -TEST_F(GraphTransformationTests, SkipLayerNormFusionTest) { - TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format1.onnx", 0, 0, 1, 0, logger_.get()); - TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format2.onnx", 0, 0, 1, 0, logger_.get()); - TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format3.onnx", 0, 0, 1, 0, logger_.get()); - - TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format1_partial.onnx", 1, 0, 1, 0, logger_.get()); - TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format2_partial.onnx", 1, 0, 1, 0, logger_.get()); - TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format3_no_fusion.onnx", 1, 1, 0, 0, logger_.get()); - - TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format1_graph_output.onnx", 1, 0, 1, 0, logger_.get()); - TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format2_graph_output.onnx", 1, 0, 1, 0, logger_.get()); - TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format3_graph_output.onnx", 1, 1, 0, 0, logger_.get()); -} - -TEST_F(GraphTransformationTests, SkipLayerNormFusionWithCastTest) { - TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format1_with_cast.onnx", 0, 0, 1, 3, logger_.get()); - TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format2_with_cast.onnx", 0, 0, 1, 3, logger_.get()); - TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format3_with_cast.onnx", 0, 0, 1, 2, logger_.get()); - - TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format1_partial_with_cast.onnx", 1, 0, 1, 2, logger_.get()); - TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format2_partial_with_cast.onnx", 1, 0, 1, 2, logger_.get()); - TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format3_no_fusion_with_cast.onnx", 1, 1, 0, 0, logger_.get()); - - TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format1_graph_output_with_cast.onnx", 1, 0, 1, 2, logger_.get()); - TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format2_graph_output_with_cast.onnx", 1, 0, 1, 2, logger_.get()); - TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format3_graph_output_with_cast.onnx", 1, 1, 0, 0, logger_.get()); -} - -static void TestSkipLayerNormFusionInputOutputCheck(const std::basic_string& model_uri, bool with_cast, logging::Logger* logger) { - std::shared_ptr p_model; - ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger)); - Graph& graph = p_model->MainGraph(); - - onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); - ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger)); - - for (Node& node : graph.Nodes()) { - if (node.OpType() == "SkipLayerNormalization") { - // check inputs - std::vector& input_defs = node.MutableInputDefs(); - EXPECT_EQ(input_defs.size(), 5u) << "SkipLayerNormalization number of inputs does not equal to 5. Got:" << node.InputDefs().size(); - EXPECT_EQ(input_defs[0]->Name(), ((with_cast) ? "input.1_Float" : "input.1")); - EXPECT_EQ(input_defs[1]->Name(), ((with_cast) ? "6_Float" : "6")); - EXPECT_EQ(input_defs[2]->Name(), "1"); - EXPECT_EQ(input_defs[3]->Name(), "2"); - EXPECT_EQ(input_defs[4]->Name(), ((with_cast) ? "4_Float" : "4")); - - // check outputs - std::vector& output_defs = node.MutableOutputDefs(); -#ifdef ENABLE_TRAINING_CORE - EXPECT_EQ(node.OutputDefs().size(), 3u) << "SkipLayerNormalization number of outputs does not equal to 3. Got:" << node.OutputDefs().size(); -#else - EXPECT_EQ(node.OutputDefs().size(), 1u) << "SkipLayerNormalization number of outputs does not equal to 1. Got:" << node.OutputDefs().size(); -#endif - EXPECT_EQ(output_defs[0]->Name(), "19"); - } else if (node.OpType() == "Cast") { - EXPECT_TRUE(with_cast) << "Unexpected node: " << node.OpType() << "," << node.Name(); - } else { - EXPECT_EQ(node.OpType(), "MatMul") << "Unexpected node: " << node.OpType() << "," << node.Name(); - } - } -} - -TEST_F(GraphTransformationTests, SkipLayerNormFusion_Input_Output_Check) { - TestSkipLayerNormFusionInputOutputCheck(MODEL_FOLDER "fusion/skip_layer_norm_input_output_check.onnx", false, logger_.get()); - TestSkipLayerNormFusionInputOutputCheck(MODEL_FOLDER "fusion/skip_layer_norm_input_output_with_cast_check.onnx", true, logger_.get()); -} - -static void TestSkipLayerNormFusionNoBeta(const std::basic_string& model_uri, bool with_cast, logging::Logger* logger) { - std::shared_ptr p_model; - ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger)); - Graph& graph = p_model->MainGraph(); - - onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); - ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger)); - - std::map op_to_count = CountOpsInGraph(graph); - ASSERT_TRUE(op_to_count["Add"] == 0); - ASSERT_TRUE(op_to_count["LayerNormalization"] == 0); - ASSERT_TRUE(op_to_count["com.microsoft.SkipLayerNormalization"] == 1); - ASSERT_TRUE(op_to_count["Cast"] == ((with_cast) ? 2 : 0)); -} - -TEST_F(GraphTransformationTests, SkipLayerNormFusion_NoBeta) { - TestSkipLayerNormFusionNoBeta(MODEL_FOLDER "fusion/skip_layer_norm_no_beta.onnx", false, logger_.get()); - TestSkipLayerNormFusionNoBeta(MODEL_FOLDER "fusion/skip_layer_norm_no_beta_with_cast.onnx", true, logger_.get()); -} - -TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat1) { - constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/embed_layer_norm_format1.onnx"; - std::shared_ptr p_model; - ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); - Graph& graph = p_model->MainGraph(); - - onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); - ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); - - std::map op_to_count = CountOpsInGraph(graph); - ASSERT_TRUE(op_to_count["Gather"] == 0); - ASSERT_TRUE(op_to_count["Add"] == 0); - ASSERT_TRUE(op_to_count["ReduceSum"] == 1); - ASSERT_TRUE(op_to_count["com.microsoft.Attention"] == 1); - ASSERT_TRUE(op_to_count["com.microsoft.SkipLayerNormalization"] == 0); - ASSERT_TRUE(op_to_count["com.microsoft.EmbedLayerNormalization"] == 1); -} - -TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat2) { - constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/embed_layer_norm_format2.onnx"; - std::shared_ptr p_model; - ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); - Graph& graph = p_model->MainGraph(); - - onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); - ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); - - std::map op_to_count = CountOpsInGraph(graph); - ASSERT_TRUE(op_to_count["Shape"] == 0); - ASSERT_TRUE(op_to_count["Expand"] == 0); - ASSERT_TRUE(op_to_count["Gather"] == 0); - ASSERT_TRUE(op_to_count["Unsqueeze"] == 0); - ASSERT_TRUE(op_to_count["ConstantOfShape"] == 0); - ASSERT_TRUE(op_to_count["NonZero"] == 0); - ASSERT_TRUE(op_to_count["Transpose"] == 0); - ASSERT_TRUE(op_to_count["Squeeze"] == 0); - ASSERT_TRUE(op_to_count["Add"] == 0); - ASSERT_TRUE(op_to_count["ReduceSum"] == 1); - ASSERT_TRUE(op_to_count["com.microsoft.Attention"] == 1); - ASSERT_TRUE(op_to_count["com.microsoft.SkipLayerNormalization"] == 0); - ASSERT_TRUE(op_to_count["com.microsoft.EmbedLayerNormalization"] == 1); -} - -static void EmbedLayerNormFusionFormat3(const std::basic_string& file_path, logging::Logger* logger) { - std::shared_ptr p_model; - ASSERT_TRUE(Model::Load(file_path, p_model, nullptr, *logger).IsOK()); - Graph& graph = p_model->MainGraph(); - - onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); - ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger)); - - std::map op_to_count = CountOpsInGraph(graph); - EXPECT_EQ(op_to_count["Shape"], 0); - EXPECT_EQ(op_to_count["Expand"], 0); - EXPECT_EQ(op_to_count["Gather"], 0); - EXPECT_EQ(op_to_count["Unsqueeze"], 0); - EXPECT_EQ(op_to_count["LayerNormalization"], 0); - EXPECT_EQ(op_to_count["com.microsoft.SkipLayerNormalization"], 0); - EXPECT_EQ(op_to_count["ReduceSum"], 1); - EXPECT_EQ(op_to_count["MatMul"], 1); - EXPECT_EQ(op_to_count["Add"], 2); - EXPECT_EQ(op_to_count["Cast"], 3); - EXPECT_EQ(op_to_count["com.microsoft.Attention"], 1); - EXPECT_EQ(op_to_count["com.microsoft.EmbedLayerNormalization"], 1); -} - -TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat3) { - EmbedLayerNormFusionFormat3(MODEL_FOLDER "fusion/embed_layer_norm_format3.onnx", logger_.get()); -} - -TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat3_OpSet13) { - EmbedLayerNormFusionFormat3(MODEL_FOLDER "fusion/embed_layer_norm_format3_opset13.onnx", logger_.get()); -} - -static void EmbedLayerNormFusionFormat3NoCast(const std::basic_string& file_path, logging::Logger* logger) { - std::shared_ptr p_model; - ASSERT_TRUE(Model::Load(file_path, p_model, nullptr, *logger).IsOK()); - Graph& graph = p_model->MainGraph(); - - onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); - ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger)); - - std::map op_to_count = CountOpsInGraph(graph); - EXPECT_EQ(op_to_count["Shape"], 0); - EXPECT_EQ(op_to_count["Expand"], 0); - EXPECT_EQ(op_to_count["Gather"], 0); - EXPECT_EQ(op_to_count["Unsqueeze"], 0); - EXPECT_EQ(op_to_count["LayerNormalization"], 0); - EXPECT_EQ(op_to_count["com.microsoft.SkipLayerNormalization"], 0); - EXPECT_EQ(op_to_count["ReduceSum"], 1); - EXPECT_EQ(op_to_count["MatMul"], 1); - EXPECT_EQ(op_to_count["Add"], 2); - EXPECT_EQ(op_to_count["Cast"], 3); - EXPECT_EQ(op_to_count["com.microsoft.Attention"], 1); - EXPECT_EQ(op_to_count["com.microsoft.EmbedLayerNormalization"], 1); -} - -TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat3NoCast) { - EmbedLayerNormFusionFormat3NoCast(MODEL_FOLDER "fusion/embed_layer_norm_format3_no_cast.onnx", logger_.get()); -} - -TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat3NoCast_OpSet13) { - EmbedLayerNormFusionFormat3NoCast(MODEL_FOLDER "fusion/embed_layer_norm_format3_no_cast_opset13.onnx", logger_.get()); -} - -TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat4) { - constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/embed_layer_norm_format4.onnx"; - std::shared_ptr p_model; - ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); - Graph& graph = p_model->MainGraph(); - - onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); - ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); - - std::map op_to_count = CountOpsInGraph(graph); - ASSERT_TRUE(op_to_count["Shape"] == 0); - ASSERT_TRUE(op_to_count["Expand"] == 0); - ASSERT_TRUE(op_to_count["Gather"] == 0); - ASSERT_TRUE(op_to_count["Concat"] == 0); - ASSERT_TRUE(op_to_count["Unsqueeze"] == 0); - ASSERT_TRUE(op_to_count["ConstantOfShape"] == 0); - ASSERT_TRUE(op_to_count["NonZero"] == 0); - ASSERT_TRUE(op_to_count["Transpose"] == 0); - ASSERT_TRUE(op_to_count["Squeeze"] == 0); - ASSERT_TRUE(op_to_count["Add"] == 0); - ASSERT_TRUE(op_to_count["ReduceSum"] == 1); - ASSERT_TRUE(op_to_count["com.microsoft.Attention"] == 1); - ASSERT_TRUE(op_to_count["com.microsoft.SkipLayerNormalization"] == 0); - ASSERT_TRUE(op_to_count["com.microsoft.EmbedLayerNormalization"] == 1); -} - -static void EmbedLayerNormFusionFormat5(const std::basic_string& file_path, logging::Logger* logger) { - std::shared_ptr p_model; - ASSERT_TRUE(Model::Load(file_path, p_model, nullptr, *logger).IsOK()); - Graph& graph = p_model->MainGraph(); - - onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); - ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger)); - - std::map op_to_count = CountOpsInGraph(graph); - EXPECT_EQ(op_to_count["Gather"], 0); - EXPECT_EQ(op_to_count["LayerNormalization"], 0); - EXPECT_EQ(op_to_count["com.microsoft.SkipLayerNormalization"], 0); - EXPECT_EQ(op_to_count["ReduceSum"], 1); - EXPECT_EQ(op_to_count["MatMul"], 1); - EXPECT_EQ(op_to_count["Add"], 2); - EXPECT_EQ(op_to_count["Cast"], 3); - EXPECT_EQ(op_to_count["com.microsoft.Attention"], 1); - EXPECT_EQ(op_to_count["com.microsoft.EmbedLayerNormalization"], 1); - - // Validate the position embedding input. - for (const Node& node : graph.Nodes()) { - if (node.OpType() == "EmbedLayerNormalization") { - const ONNX_NAMESPACE::TensorProto* tensor_proto = graph_utils::GetConstantInitializer(graph, node.InputDefs()[3]->Name()); - ASSERT_TRUE(tensor_proto != nullptr); - EXPECT_EQ(tensor_proto->data_type(), ONNX_NAMESPACE::TensorProto_DataType_FLOAT); - - auto initializer = std::make_unique(*tensor_proto, graph.ModelPath()); - EXPECT_EQ(initializer->size(), 12); - - std::vector expected_value = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 8.0, 7.0, 6.0}; - - const float* data = initializer->data(); - for (size_t i = 0; i < expected_value.size(); i++) { - EXPECT_EQ(data[i], static_cast(expected_value[i])); - } - } - } -} - -TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat5) { - EmbedLayerNormFusionFormat5(MODEL_FOLDER "fusion/embed_layer_norm_format5.onnx", logger_.get()); -} - -TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat5_OpSet13) { - EmbedLayerNormFusionFormat5(MODEL_FOLDER "fusion/embed_layer_norm_format5_opset13.onnx", logger_.get()); -} - -static void EmbedLayerNormFusionFormat6(const std::basic_string& file_path, logging::Logger* logger) { - std::shared_ptr p_model; - ASSERT_TRUE(Model::Load(file_path, p_model, nullptr, *logger).IsOK()); - Graph& graph = p_model->MainGraph(); - - onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); - ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger)); - - std::map op_to_count = CountOpsInGraph(graph); - EXPECT_EQ(op_to_count["Shape"], 0); - EXPECT_EQ(op_to_count["Expand"], 0); - EXPECT_EQ(op_to_count["Gather"], 0); - EXPECT_EQ(op_to_count["Unsqueeze"], 0); - EXPECT_EQ(op_to_count["Reshape"], 0); - EXPECT_EQ(op_to_count["Equal"], 0); - EXPECT_EQ(op_to_count["Where"], 0); - EXPECT_EQ(op_to_count["LayerNormalization"], 0); - EXPECT_EQ(op_to_count["com.microsoft.SkipLayerNormalization"], 0); - EXPECT_EQ(op_to_count["ReduceSum"], 1); - EXPECT_EQ(op_to_count["MatMul"], 1); - EXPECT_EQ(op_to_count["Add"], 2); - EXPECT_EQ(op_to_count["Cast"], 3); - EXPECT_EQ(op_to_count["com.microsoft.Attention"], 1); - EXPECT_EQ(op_to_count["com.microsoft.EmbedLayerNormalization"], 1); -} - -TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat6) { - EmbedLayerNormFusionFormat6(MODEL_FOLDER "fusion/embed_layer_norm_format6.onnx", logger_.get()); -} - -TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat6_OpSet13) { - EmbedLayerNormFusionFormat6(MODEL_FOLDER "fusion/embed_layer_norm_format6_opset13.onnx", logger_.get()); -} - -static void TestEmbedLayerNormFusionDistilBert(const std::basic_string& model_uri, - std::map& op_to_count, - logging::Logger* logger) { - std::shared_ptr p_model; - ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger)); - Graph& graph = p_model->MainGraph(); - - onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); - ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger)); - - op_to_count = CountOpsInGraph(graph); -} - -// DistilBert -TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat7) { - std::map op_to_count; - TestEmbedLayerNormFusionDistilBert(MODEL_FOLDER "fusion/embed_layer_norm_format7.onnx", op_to_count, logger_.get()); - EXPECT_EQ(op_to_count["com.microsoft.EmbedLayerNormalization"], 1); - EXPECT_EQ(op_to_count["com.microsoft.Attention"], 1); - EXPECT_EQ(op_to_count["Cast"], 2); - EXPECT_EQ(op_to_count["Shape"], 0); - EXPECT_EQ(op_to_count["Gather"], 0); - EXPECT_EQ(op_to_count["Unsqueeze"], 0); - EXPECT_EQ(op_to_count["ReduceSum"], 1); -} - -TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat7_OpSet13) { - std::map op_to_count; - TestEmbedLayerNormFusionDistilBert(MODEL_FOLDER "fusion/embed_layer_norm_format7_opset13.onnx", op_to_count, logger_.get()); - EXPECT_EQ(op_to_count["com.microsoft.EmbedLayerNormalization"], 1); - EXPECT_EQ(op_to_count["com.microsoft.Attention"], 1); - EXPECT_EQ(op_to_count["Cast"], 2); - EXPECT_EQ(op_to_count["Shape"], 0); - EXPECT_EQ(op_to_count["Gather"], 0); - EXPECT_EQ(op_to_count["Unsqueeze"], 0); - EXPECT_EQ(op_to_count["ReduceSum"], 1); -} - -TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat8) { - std::map op_to_count; - TestEmbedLayerNormFusionDistilBert(MODEL_FOLDER "fusion/embed_layer_norm_format8.onnx", op_to_count, logger_.get()); - EXPECT_EQ(op_to_count["com.microsoft.EmbedLayerNormalization"], 1); - EXPECT_EQ(op_to_count["com.microsoft.Attention"], 1); - EXPECT_EQ(op_to_count["Cast"], 2); - EXPECT_EQ(op_to_count["Shape"], 0); - EXPECT_EQ(op_to_count["Gather"], 0); - EXPECT_EQ(op_to_count["Unsqueeze"], 0); - EXPECT_EQ(op_to_count["ReduceSum"], 1); -} - -TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat8_OpSet13) { - std::map op_to_count; - TestEmbedLayerNormFusionDistilBert(MODEL_FOLDER "fusion/embed_layer_norm_format8_opset13.onnx", op_to_count, logger_.get()); - EXPECT_EQ(op_to_count["com.microsoft.EmbedLayerNormalization"], 1); - EXPECT_EQ(op_to_count["com.microsoft.Attention"], 1); - EXPECT_EQ(op_to_count["Cast"], 2); - EXPECT_EQ(op_to_count["Shape"], 0); - EXPECT_EQ(op_to_count["Gather"], 0); - EXPECT_EQ(op_to_count["Unsqueeze"], 0); - EXPECT_EQ(op_to_count["ReduceSum"], 1); -} - -TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat9) { - std::map op_to_count; - TestEmbedLayerNormFusionDistilBert(MODEL_FOLDER "fusion/embed_layer_norm_format9.onnx", op_to_count, logger_.get()); - EXPECT_EQ(op_to_count["com.microsoft.EmbedLayerNormalization"], 1); - EXPECT_EQ(op_to_count["com.microsoft.Attention"], 1); - EXPECT_EQ(op_to_count["Cast"], 2); - EXPECT_EQ(op_to_count["Shape"], 1); - EXPECT_EQ(op_to_count["Gather"], 2); - EXPECT_EQ(op_to_count["Unsqueeze"], 2); - EXPECT_EQ(op_to_count["ReduceSum"], 1); -} - -TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat9_OpSet13) { - std::map op_to_count; - TestEmbedLayerNormFusionDistilBert(MODEL_FOLDER "fusion/embed_layer_norm_format9_opset13.onnx", op_to_count, logger_.get()); - EXPECT_EQ(op_to_count["com.microsoft.EmbedLayerNormalization"], 1); - EXPECT_EQ(op_to_count["com.microsoft.Attention"], 1); - EXPECT_EQ(op_to_count["Cast"], 2); - EXPECT_EQ(op_to_count["Shape"], 1); - EXPECT_EQ(op_to_count["Gather"], 2); - EXPECT_EQ(op_to_count["Unsqueeze"], 2); - EXPECT_EQ(op_to_count["ReduceSum"], 1); -} - -static void EmbedLayerNormFusionFormatMultiple(const std::basic_string& file_path, logging::Logger* logger) { - std::shared_ptr p_model; - ASSERT_TRUE(Model::Load(file_path, p_model, nullptr, *logger).IsOK()); - Graph& graph = p_model->MainGraph(); - - onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); - ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger)); - - std::map op_to_count = CountOpsInGraph(graph); - EXPECT_EQ(op_to_count["Shape"], 0); - EXPECT_EQ(op_to_count["Expand"], 0); - EXPECT_EQ(op_to_count["Gather"], 0); - EXPECT_EQ(op_to_count["Unsqueeze"], 0); - EXPECT_EQ(op_to_count["LayerNormalization"], 0); - EXPECT_EQ(op_to_count["com.microsoft.SkipLayerNormalization"], 0); - EXPECT_EQ(op_to_count["ReduceSum"], 2); - EXPECT_EQ(op_to_count["MatMul"], 2); - EXPECT_EQ(op_to_count["Add"], 5); - EXPECT_EQ(op_to_count["Cast"], 6); - EXPECT_EQ(op_to_count["com.microsoft.Attention"], 2); - EXPECT_EQ(op_to_count["com.microsoft.EmbedLayerNormalization"], 2); -} - -TEST_F(GraphTransformationTests, EmbedLayerNormFusionMultiple) { - EmbedLayerNormFusionFormatMultiple(MODEL_FOLDER "fusion/embed_layer_norm_multiple.onnx", logger_.get()); -} - -TEST_F(GraphTransformationTests, EmbedLayerNormFusionMultiple_OpSet13) { - EmbedLayerNormFusionFormatMultiple(MODEL_FOLDER "fusion/embed_layer_norm_multiple_opset13.onnx", logger_.get()); -} - -TEST_F(GraphTransformationTests, DynamicQuantizeMatMulTest) { - constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/dynamic_quantize_matmul.onnx"; - std::shared_ptr p_model; - ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); - Graph& graph = p_model->MainGraph(); - - onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); - ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); - - std::map op_to_count = CountOpsInGraph(graph); - EXPECT_EQ(op_to_count["DynamicQuantizeLinear"], 0); - EXPECT_EQ(op_to_count["MatMulInteger"], 0); - EXPECT_EQ(op_to_count["Cast"], 0); - EXPECT_EQ(op_to_count["Mul"], 0); - EXPECT_EQ(op_to_count["com.microsoft.DynamicQuantizeMatMul"], 1); -} - -TEST_F(GraphTransformationTests, DynamicQuantizeMatMulTest_With_Bias) { - constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/dynamic_quantize_matmul_bias.onnx"; - std::shared_ptr p_model; - ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); - Graph& graph = p_model->MainGraph(); - - onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); - ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); - - std::map op_to_count = CountOpsInGraph(graph); - EXPECT_EQ(op_to_count["DynamicQuantizeLinear"], 0); - EXPECT_EQ(op_to_count["MatMulInteger"], 0); - EXPECT_EQ(op_to_count["Cast"], 0); - EXPECT_EQ(op_to_count["Mul"], 0); - EXPECT_EQ(op_to_count["com.microsoft.DynamicQuantizeMatMul"], 1); -} - -TEST_F(GraphTransformationTests, DynamicQuantizeMatMulTest_With_ND_bias) { - constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/dynamic_quantize_matmul_bias_ND.onnx"; - std::shared_ptr p_model; - ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); - Graph& graph = p_model->MainGraph(); - - onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); - ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); - - std::map op_to_count = CountOpsInGraph(graph); - EXPECT_EQ(op_to_count["DynamicQuantizeLinear"], 0); - EXPECT_EQ(op_to_count["MatMulInteger"], 0); - EXPECT_EQ(op_to_count["Cast"], 0); - EXPECT_EQ(op_to_count["Mul"], 0); - EXPECT_EQ(op_to_count["com.microsoft.DynamicQuantizeMatMul"], 1); - EXPECT_EQ(op_to_count["Add"], 1); -} - -TEST_F(GraphTransformationTests, DynamicQuantizeMatMulTest_With_Bias_No_B_ZP) { - constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/dynamic_quantize_matmul_bias_b_no_zp.onnx"; - std::shared_ptr p_model; - ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); - Graph& graph = p_model->MainGraph(); - - onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); - ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); - - std::map op_to_count = CountOpsInGraph(graph); - EXPECT_EQ(op_to_count["DynamicQuantizeLinear"], 0); - EXPECT_EQ(op_to_count["MatMulInteger"], 0); - EXPECT_EQ(op_to_count["Cast"], 0); - EXPECT_EQ(op_to_count["Mul"], 0); - EXPECT_EQ(op_to_count["com.microsoft.DynamicQuantizeMatMul"], 1); -} - -TEST_F(GraphTransformationTests, MatMulIntegerToFloatTest) { - constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/matmul_integer_to_float.onnx"; - std::shared_ptr p_model; - ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); - Graph& graph = p_model->MainGraph(); - - onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); - ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); - - std::map op_to_count = CountOpsInGraph(graph); - EXPECT_EQ(op_to_count["DynamicQuantizeLinear"], 1); - EXPECT_EQ(op_to_count["MatMulInteger"], 0); - EXPECT_EQ(op_to_count["Cast"], 0); - EXPECT_EQ(op_to_count["Mul"], 0); - EXPECT_EQ(op_to_count["com.microsoft.MatMulIntegerToFloat"], 3); - EXPECT_EQ(op_to_count["Add"], 1); -} - -#endif - -#ifndef DISABLE_CONTRIB_OPS -template -static void TestMatMulScaleFusion( - const PathString& model_path, const Logger& logger, - GraphPreprocessFn graph_preprocess_fn, - GraphTransformationCheckFn graph_transformation_check_fn, - const InlinedHashSet& compatible_execution_providers = {}, - const InlinedHashSet& excluded_initializer_names = {}) { - SCOPED_TRACE(ORT_TSTR("model path: ") + model_path); - - std::shared_ptr model; - ASSERT_STATUS_OK(Model::Load(model_path, model, nullptr, logger)); - Graph& graph = model->MainGraph(); - - graph_preprocess_fn(graph); - - auto original_op_counts = CountOpsInGraph(graph); - - onnxruntime::GraphTransformerManager graph_transformer_manager{5}; - ASSERT_STATUS_OK(graph_transformer_manager.Register( - make_unique(compatible_execution_providers, excluded_initializer_names), - TransformerLevel::Level2)); - ASSERT_STATUS_OK(graph_transformer_manager.ApplyTransformers(graph, TransformerLevel::Level2, logger)); + onnxruntime::GraphTransformerManager graph_transformer_manager{5}; + ASSERT_STATUS_OK(graph_transformer_manager.Register( + make_unique(compatible_execution_providers, excluded_initializer_names), + TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformer_manager.ApplyTransformers(graph, TransformerLevel::Level2, logger)); auto transformed_op_counts = CountOpsInGraph(graph); @@ -5914,6 +5349,71 @@ TEST_F(GraphTransformationTests, PropagateCastOpsTests_Gelu) { } } +TEST_F(GraphTransformationTests, PropagateCastOpsTests_Softmax) { + using Strategy = GraphTransformerConfiguration::PropagateCastOpsConfiguration::Strategy; + { + auto build_test_case = [](ModelTestBuilder& builder) { + auto* input_arg = builder.MakeInput({{2, 3, 3, 3}}); + auto* cast_out_0 = builder.MakeIntermediate(); + auto* softmax_out = builder.MakeIntermediate(); + auto* cast_out_1 = builder.MakeIntermediate(); + auto* identity_out = builder.MakeOutput(); + + builder.AddNode("Cast", {input_arg}, {cast_out_0}) + .AddAttribute("to", static_cast(ONNX_NAMESPACE::TensorProto_DataType_FLOAT)); + builder.AddNode("Softmax", {cast_out_0}, {softmax_out}); + builder.AddNode("Cast", {softmax_out}, {cast_out_1}) + .AddAttribute("to", static_cast(ONNX_NAMESPACE::TensorProto_DataType_FLOAT16)); + builder.AddNode("Identity", {cast_out_1}, {identity_out}); + }; + + auto pre_graph_checker = [](Graph& graph) { + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Cast"] == 2); + return Status::OK(); + }; + + auto post_graph_checker = [](Graph& graph) { + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Cast"] == 0); + return Status::OK(); + }; + + std::unique_ptr transformer = std::make_unique(Strategy::FloodFill, 1); + ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, 14, *logger_, std::move(transformer), TransformerLevel::Level1, 1, + pre_graph_checker, post_graph_checker)); + } + + { + auto build_test_case = [](ModelTestBuilder& builder) { + auto* input_arg = builder.MakeInput({{2, -1, 3, -1}}); + auto* cast_out_0 = builder.MakeIntermediate(); + auto* softmax_out = builder.MakeIntermediate(); + auto* cast_out_1 = builder.MakeIntermediate(); + auto* identity_out = builder.MakeOutput(); + + builder.AddNode("Cast", {input_arg}, {cast_out_0}) + .AddAttribute("to", static_cast(ONNX_NAMESPACE::TensorProto_DataType_FLOAT)); + builder.AddNode("Softmax", {cast_out_0}, {softmax_out}); + builder.AddNode("Cast", {softmax_out}, {cast_out_1}) + .AddAttribute("to", static_cast(ONNX_NAMESPACE::TensorProto_DataType_BFLOAT16)); + builder.AddNode("Identity", {cast_out_1}, {identity_out}); + }; + + auto pre_graph_checker = [](Graph& graph) { + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Cast"] == 2); + return Status::OK(); + }; + + auto post_graph_checker = [](Graph& graph) { + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Cast"] == 2); + return Status::OK(); + }; + + std::unique_ptr transformer = std::make_unique(Strategy::FloodFill, 1); + ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, 14, *logger_, std::move(transformer), TransformerLevel::Level1, 1, + pre_graph_checker, post_graph_checker)); + } +} + #endif /* @@ -6107,7 +5607,7 @@ void BuildConstantSharingDivMulGraph(ModelTestBuilder& builder) { for (size_t i = 0; i < 12; ++i) { NodeArg* mul_initializer = nullptr; if (std::is_same::value) { - mul_initializer = builder.MakeScalarInitializer(MLFloat16(math::floatToHalf(1.0f))); + mul_initializer = builder.MakeScalarInitializer(MLFloat16(1.0f)); } else if (std::is_same::value) { mul_initializer = builder.MakeScalarInitializer(1.0f); } else { @@ -6164,7 +5664,7 @@ TEST_F(GraphTransformationTests, ConstantSharing_ShareFloatOrHalfTypedInitialize const ONNX_NAMESPACE::TensorProto* tensor_proto = entry.second; int32_t data_type = tensor_proto->data_type(); onnxruntime::Initializer float_const{*tensor_proto, graph.ModelPath()}; - TEST_RETURN_IF_NOT(float_const.size() == 1); + TEST_RETURN_IF_NOT(float_const.size() == 1U); float float_const_value; if (data_type == ONNX_NAMESPACE::TensorProto_DataType_FLOAT16) { float_const_value = math::halfToFloat(float_const.data()->val); @@ -6223,7 +5723,7 @@ void BuildConstantSharingDivMulGraphFor2DInitializer(ModelTestBuilder& builder) values_float16.reserve(values.size()); if (std::is_same::value) { for (auto v : values) { - values_float16.push_back(MLFloat16(math::floatToHalf(v))); + values_float16.push_back(MLFloat16(v)); } } @@ -6287,7 +5787,7 @@ TEST_F(GraphTransformationTests, ConstantSharing_Share2DFloatOrHalfTypedInitiali const ONNX_NAMESPACE::TensorProto* tensor_proto = entry.second; int32_t data_type = tensor_proto->data_type(); onnxruntime::Initializer float_const{*tensor_proto, graph.ModelPath()}; - TEST_RETURN_IF_NOT(float_const.size() == 8); + TEST_RETURN_IF_NOT(float_const.size() == 8U); for (int i = 0; i < 8; ++i) { float float_const_value; if (data_type == ONNX_NAMESPACE::TensorProto_DataType_FLOAT16) { @@ -6394,12 +5894,12 @@ TEST_F(GraphTransformationTests, ConstantSharing_ShareFloatAndHalfTypedInitializ int32_t data_type = tensor_proto->data_type(); onnxruntime::Initializer float_const{*tensor_proto, graph.ModelPath()}; if (entry.first.compare(mul_initializer->Name()) == 0) { - TEST_RETURN_IF_NOT(float_const.size() == 1); + TEST_RETURN_IF_NOT(float_const.size() == 1U); TEST_RETURN_IF_NOT(data_type == ONNX_NAMESPACE::TensorProto_DataType_FLOAT); float float_const_value = *(float_const.data()); TEST_RETURN_IF_NOT(float_const_value == 1.0f); } else if (entry.first.compare(add_initializer->Name()) == 0) { - TEST_RETURN_IF_NOT(float_const.size() == 1); + TEST_RETURN_IF_NOT(float_const.size() == 1U); TEST_RETURN_IF_NOT(data_type == ONNX_NAMESPACE::TensorProto_DataType_FLOAT16); float float_const_value = math::halfToFloat(float_const.data()->val); TEST_RETURN_IF_NOT(float_const_value == 1.0f); @@ -6434,7 +5934,7 @@ TEST_F(GraphTransformationTests, ConstantSharing_ShareFloatAndHalfTypedInitializ builder.AddNode("Cast", {div_out}, {cast_out}) .AddAttribute("to", static_cast(ONNX_NAMESPACE::TensorProto_DataType_FLOAT16)); for (size_t i = 0; i < 3; ++i) { - NodeArg* add_initializer = builder.MakeScalarInitializer(MLFloat16(math::floatToHalf(1.0f))); + NodeArg* add_initializer = builder.MakeScalarInitializer(MLFloat16(1.0f)); auto* add_out = builder.MakeOutput(); builder.AddNode("Add", {cast_out, add_initializer}, {add_out}); } @@ -6522,7 +6022,7 @@ TEST_F(GraphTransformationTests, ConstantSharing_Share2DFloatAndHalfTypedInitial const ONNX_NAMESPACE::TensorProto* tensor_proto = entry.second; int32_t data_type = tensor_proto->data_type(); onnxruntime::Initializer float_const{*tensor_proto, graph.ModelPath()}; - TEST_RETURN_IF_NOT(float_const.size() == 8); + TEST_RETURN_IF_NOT(float_const.size() == 8U); if (entry.first.compare(mul_initializer->Name()) == 0) { TEST_RETURN_IF_NOT(data_type == ONNX_NAMESPACE::TensorProto_DataType_FLOAT); for (int i = 0; i < 8; ++i) { @@ -6560,7 +6060,7 @@ TEST_F(GraphTransformationTests, ConstantSharing_Share2DFloatAndHalfTypedInitial std::vector values_float16; values_float16.reserve(values.size()); for (auto v : values) { - values_float16.push_back(MLFloat16(math::floatToHalf(v))); + values_float16.push_back(MLFloat16(v)); } auto build_test_case_float = [&values, &values_float16](ModelTestBuilder& builder) { @@ -6660,13 +6160,13 @@ TEST_F(GraphTransformationTests, ConstantSharing_ShareIntMaxOrFloatInfinityIniti if (entry.first.compare(mul_initializer->Name()) == 0) { const ONNX_NAMESPACE::TensorProto* tensor_proto = entry.second; onnxruntime::Initializer int64_const{*tensor_proto, graph.ModelPath()}; - TEST_RETURN_IF_NOT(int64_const.size() == 1); + TEST_RETURN_IF_NOT(int64_const.size() == 1U); int64_t int64_const_value = *(int64_const.data()); TEST_RETURN_IF_NOT(int64_const_value == std::numeric_limits::max()); } else if (entry.first.compare(sub_initializer->Name()) == 0) { const ONNX_NAMESPACE::TensorProto* tensor_proto = entry.second; onnxruntime::Initializer float_const{*tensor_proto, graph.ModelPath()}; - TEST_RETURN_IF_NOT(float_const.size() == 1); + TEST_RETURN_IF_NOT(float_const.size() == 1U); float float_const_value = *(float_const.data()); TEST_RETURN_IF_NOT(float_const_value == std::numeric_limits::infinity()); } @@ -6759,13 +6259,13 @@ TEST_F(GraphTransformationTests, ConstantSharing_ShouldNotShareForGraphOutput) { if (entry.first.compare("y_scale") == 0) { const ONNX_NAMESPACE::TensorProto* tensor_proto = entry.second; onnxruntime::Initializer int64_const{*tensor_proto, graph.ModelPath()}; - ASSERT_TRUE(int64_const.size() == 1); + ASSERT_TRUE(int64_const.size() == 1U); float float_const_value = *(int64_const.data()); ASSERT_TRUE(float_const_value == 1); } else { const ONNX_NAMESPACE::TensorProto* tensor_proto = entry.second; onnxruntime::Initializer uint8_const{*tensor_proto, graph.ModelPath()}; - ASSERT_TRUE(uint8_const.size() == 1); + ASSERT_TRUE(uint8_const.size() == 1U); uint8_t uint8_const_value = *(uint8_const.data()); ASSERT_TRUE(uint8_const_value == static_cast(1)); } diff --git a/onnxruntime/test/optimizer/graph_transform_test_builder.cc b/onnxruntime/test/optimizer/graph_transform_test_builder.cc index 32edbaf507665..c98dc78998c55 100644 --- a/onnxruntime/test/optimizer/graph_transform_test_builder.cc +++ b/onnxruntime/test/optimizer/graph_transform_test_builder.cc @@ -21,7 +21,7 @@ void TransformerTester(const std::function& buil const std::function& check_transformed_graph, TransformerLevel baseline_level, TransformerLevel target_level, - const std::vector& opset_versions, + const std::vector& opset_versions, double per_sample_tolerance, double relative_per_sample_tolerance, std::unique_ptr transformer, @@ -127,13 +127,13 @@ Status TestGraphTransformer(const std::function& const logging::Logger& logger, std::unique_ptr transformer, TransformerLevel level, unsigned steps, const std::function& pre_graph_checker, const std::function& post_graph_checker) { - const std::vector opset_versions{opset_version}; + const std::vector opset_versions{opset_version}; return TestGraphTransformer(build_test_case, opset_versions, logger, std::move(transformer), level, steps, pre_graph_checker, post_graph_checker); } Status TestGraphTransformer(const std::function& build_test_case, - const std::vector& opset_versions, + const std::vector& opset_versions, const logging::Logger& logger, std::unique_ptr transformer, TransformerLevel level, unsigned steps, const std::function& pre_graph_checker, const std::function& post_graph_checker) { diff --git a/onnxruntime/test/optimizer/graph_transform_test_builder.h b/onnxruntime/test/optimizer/graph_transform_test_builder.h index 3e42bc456b38d..63577131480c6 100644 --- a/onnxruntime/test/optimizer/graph_transform_test_builder.h +++ b/onnxruntime/test/optimizer/graph_transform_test_builder.h @@ -39,9 +39,21 @@ namespace test { template struct IsTypeQuantLinearCompatible : utils::IsByteType {}; +template <> +struct IsTypeQuantLinearCompatible : std::true_type {}; + +template <> +struct IsTypeQuantLinearCompatible : std::true_type {}; + template struct IsTypeDequantLinearCompatible : utils::IsByteType {}; +template <> +struct IsTypeDequantLinearCompatible : std::true_type {}; + +template <> +struct IsTypeDequantLinearCompatible : std::true_type {}; + template <> struct IsTypeDequantLinearCompatible : std::true_type {}; @@ -66,7 +78,7 @@ class ModelTestBuilder { } OrtValue input_value; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], shape, data, &input_value); @@ -91,7 +103,8 @@ class ModelTestBuilder { } template - NodeArg* MakeInput(const std::optional>& shape) { + NodeArg* MakeInput(const std::optional>& shape, + std::optional input_name = std::nullopt) { ONNX_NAMESPACE::TypeProto type_proto; type_proto.mutable_tensor_type()->set_elem_type(utils::ToTensorProtoElementType()); if (shape != std::nullopt) { @@ -103,7 +116,36 @@ class ModelTestBuilder { } } } - std::string name = graph_.GenerateNodeArgName("input"); + + if (input_name == std::nullopt) { + std::string name = graph_.GenerateNodeArgName("input"); + return &graph_.GetOrCreateNodeArg(name, &type_proto); + } else { + ORT_ENFORCE(graph_.GetNodeArg(*input_name) == nullptr, "Input name already exists: ", *input_name); + return &graph_.GetOrCreateNodeArg(*input_name, &type_proto); + } + } + + template + NodeArg* MakeSymbolicInput(const std::vector>& shape) { + ONNX_NAMESPACE::TypeProto type_proto; + type_proto.mutable_tensor_type()->set_elem_type(utils::ToTensorProtoElementType()); + type_proto.mutable_tensor_type()->mutable_shape(); + for (auto& d : shape) { + auto dim = type_proto.mutable_tensor_type()->mutable_shape()->add_dim(); + std::visit([&dim](auto&& arg) -> void { + using V = std::decay_t; + if constexpr (std::is_same_v) { + ORT_ENFORCE(arg >= 0, "Negative dimension is not allowed in symbolic shape"); + dim->set_dim_value(arg); + } else { + dim->set_dim_param(arg); + } + }, + d); + } + + std::string name = graph_.GenerateNodeArgName("symbolic_input"); return &graph_.GetOrCreateNodeArg(name, &type_proto); } @@ -113,6 +155,24 @@ class ModelTestBuilder { return &graph_.GetOrCreateNodeArg(name, nullptr); } + template + NodeArg* MakeOutput(const std::optional>& shape) { + ONNX_NAMESPACE::TypeProto type_proto; + type_proto.mutable_tensor_type()->set_elem_type(utils::ToTensorProtoElementType()); + if (shape != std::nullopt) { + ONNX_NAMESPACE::TensorShapeProto* shape_proto = type_proto.mutable_tensor_type()->mutable_shape(); + for (auto& d : *shape) { + auto dim = shape_proto->add_dim(); + if (d != -1) { + dim->set_dim_value(d); + } + } + } + std::string name = graph_.GenerateNodeArgName("output"); + output_names_.push_back(name); + return &graph_.GetOrCreateNodeArg(name, &type_proto); + } + NodeArg* MakeIntermediate() { std::string name = graph_.GenerateNodeArgName("node"); return &graph_.GetOrCreateNodeArg(name, nullptr); @@ -171,6 +231,15 @@ class ModelTestBuilder { return &graph_.GetOrCreateNodeArg(name, nullptr); } + NodeArg* MakeRandInitializerBool(const std::vector& shape) { + std::vector data_uint8 = rand_gen_.Uniform(shape, 0, 1); + std::vector data; + for (uint8_t x : data_uint8) { + data.push_back(x != 0); + } + return MakeInitializerBool(shape, data); + } + template NodeArg* MakeInitializer(const std::vector& shape, T min, T max) { return MakeInitializer(shape, rand_gen_.Uniform(shape, min, max)); @@ -219,23 +288,27 @@ class ModelTestBuilder { AddQuantizeLinearNode(NodeArg* input_arg, float input_scale, T input_zero_point, - NodeArg* output_arg) { + NodeArg* output_arg, + bool use_ms_domain = false) { std::vector input_args; input_args.push_back(input_arg); input_args.push_back(MakeScalarInitializer(input_scale)); input_args.push_back(MakeScalarInitializer(input_zero_point)); - return AddNode("QuantizeLinear", input_args, {output_arg}); + std::string domain = use_ms_domain ? kMSDomain : ""; + return AddNode("QuantizeLinear", input_args, {output_arg}, domain); } Node& AddQuantizeLinearNode(NodeArg* input_arg, float input_scale, - NodeArg* output_arg) { + NodeArg* output_arg, + bool use_ms_domain = false) { std::vector input_args; input_args.push_back(input_arg); input_args.push_back(MakeScalarInitializer(input_scale)); - return AddNode("QuantizeLinear", input_args, {output_arg}); + std::string domain = use_ms_domain ? kMSDomain : ""; + return AddNode("QuantizeLinear", input_args, {output_arg}, domain); } template @@ -243,23 +316,27 @@ class ModelTestBuilder { AddDequantizeLinearNode(NodeArg* input_arg, float input_scale, T input_zero_point, - NodeArg* output_arg) { + NodeArg* output_arg, + bool use_ms_domain = false) { std::vector input_args; input_args.push_back(input_arg); input_args.push_back(MakeScalarInitializer(input_scale)); input_args.push_back(MakeScalarInitializer(input_zero_point)); - return AddNode("DequantizeLinear", input_args, {output_arg}); + std::string domain = use_ms_domain ? kMSDomain : ""; + return AddNode("DequantizeLinear", input_args, {output_arg}, domain); } Node& AddDequantizeLinearNode(NodeArg* input_arg, float input_scale, - NodeArg* output_arg) { + NodeArg* output_arg, + bool use_ms_domain = false) { std::vector input_args; input_args.push_back(input_arg); input_args.push_back(MakeScalarInitializer(input_scale)); - return AddNode("DequantizeLinear", input_args, {output_arg}); + std::string domain = use_ms_domain ? kMSDomain : ""; + return AddNode("DequantizeLinear", input_args, {output_arg}, domain); } template @@ -369,7 +446,7 @@ void TransformerTester(const std::function& buil const std::function& check_transformed_graph, TransformerLevel baseline_level, TransformerLevel target_level, - const std::vector& opset_versions, + const std::vector& opset_versions, double per_sample_tolerance = 0.0, double relative_per_sample_tolerance = 0.0, std::unique_ptr transformer = nullptr, // must be null in this case. @@ -406,7 +483,7 @@ Status TestGraphTransformer(const std::function& * @param post_graph_checker The graph checker function after applying the transformer */ Status TestGraphTransformer(const std::function& build_test_case, - const std::vector& opset_versions, + const std::vector& opset_versions, const logging::Logger& logger, std::unique_ptr transformer, TransformerLevel level, unsigned steps, const std::function& pre_graph_checker, const std::function& post_graph_checker); diff --git a/onnxruntime/test/optimizer/graph_transform_test_layernorm.cc b/onnxruntime/test/optimizer/graph_transform_test_layernorm.cc new file mode 100755 index 0000000000000..a55238396cea3 --- /dev/null +++ b/onnxruntime/test/optimizer/graph_transform_test_layernorm.cc @@ -0,0 +1,980 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4244) +#endif + +#include + +#include "gtest/gtest.h" + +#include "core/graph/graph_utils.h" +#include "core/graph/graph_viewer.h" +#include "core/graph/model.h" +#include "core/optimizer/initializer.h" + +#include "core/optimizer/embed_layer_norm_fusion.h" +#include "core/optimizer/layer_norm_fusion.h" +#include "core/optimizer/skip_layer_norm_fusion.h" + +#include "test/capturing_sink.h" +#include "test/framework/test_utils.h" +#include "test/optimizer/graph_transform_test_builder.h" +#include "test/optimizer/graph_transform_test_fixture.h" +#include "test/providers/provider_test_utils.h" + +using namespace std; +using namespace ONNX_NAMESPACE; + +namespace onnxruntime { +namespace test { + +#define MODEL_FOLDER ORT_TSTR("testdata/transform/") + +#ifndef DISABLE_CONTRIB_OPS + +TEST_F(GraphTransformationTests, LayerNormFusionTest) { + constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/layer_norm.onnx"; + std::shared_ptr p_model; + ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); + Graph& graph = p_model->MainGraph(); + + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); + + std::map op_to_count = CountOpsInGraph(graph); + ASSERT_TRUE(op_to_count["Div"] == 0); + ASSERT_TRUE(op_to_count["Add"] == 0); + ASSERT_TRUE(op_to_count["Sub"] == 0); + ASSERT_TRUE(op_to_count["ReduceMean"] == 0); + ASSERT_TRUE(op_to_count["Pow"] == 0); + ASSERT_TRUE(op_to_count["Sqrt"] == 0); + ASSERT_TRUE(op_to_count["LayerNormalization"] == 1); + + for (const Node& node : graph.Nodes()) { + if (node.OpType() == "LayerNormalization") { + // LayerNormalization should have three inputs. + EXPECT_EQ(node.InputDefs().size(), 3u) + << "LayerNormalization number of inputs does not equal to 3. Got:" << node.InputDefs().size(); + // LayerNormalization input "scale" and "bias" should have the same dimension. + const TensorShapeProto* scale_shape = node.InputDefs()[1]->Shape(); + const TensorShapeProto* bias_shape = node.InputDefs()[2]->Shape(); + EXPECT_EQ(scale_shape->dim_size(), 1) + << "LayerNormalization scale should be 1D. Got: " << scale_shape->dim_size(); + EXPECT_EQ(bias_shape->dim_size(), 1) + << "LayerNormalization bias should be 1D. Got: " << bias_shape->dim_size(); + EXPECT_EQ(scale_shape->dim(0).dim_value(), bias_shape->dim(0).dim_value()); + } else { + EXPECT_TRUE(false) << "Unexpected node " << node.Name(); + } + } +} + +TEST_F(GraphTransformationTests, TwoLayerNormShareSameInput) { + constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/layer_norm_shared_input.onnx"; + std::shared_ptr p_model; + ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); + Graph& graph = p_model->MainGraph(); + + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); + + std::map op_to_count = CountOpsInGraph(graph); + ASSERT_TRUE(op_to_count.size() == 1); + ASSERT_TRUE(op_to_count["LayerNormalization"] == 2); +} + +TEST_F(GraphTransformationTests, LayerNormWithCastFusionTest) { + constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/layer_norm_with_cast.onnx"; + std::shared_ptr p_model; + ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); + Graph& graph = p_model->MainGraph(); + + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); + + std::map op_to_count = CountOpsInGraph(graph); + +#ifdef ENABLE_TRAINING_CORE + ASSERT_TRUE(op_to_count["Cast"] == 0); + ASSERT_TRUE(op_to_count["LayerNormalization"] == 1); +#else + ASSERT_TRUE(op_to_count["Cast"] == 1); + ASSERT_TRUE(op_to_count["LayerNormalization"] == 0); +#endif +} + +TEST_F(GraphTransformationTests, LayerNormWithCastFusionTest_2) { + constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/layer_norm_with_cast_2.onnx"; + std::shared_ptr p_model; + ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); + Graph& graph = p_model->MainGraph(); + + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); + + std::map op_to_count = CountOpsInGraph(graph); + + ASSERT_TRUE(op_to_count["Cast"] == 0); + ASSERT_TRUE(op_to_count["LayerNormalization"] == 1); +} + +TEST_F(GraphTransformationTests, LayerNormWithCastFusionTest_3) { + constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/layer_norm_with_cast_3.onnx"; + std::shared_ptr p_model; + ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); + Graph& graph = p_model->MainGraph(); + + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); + + std::map op_to_count = CountOpsInGraph(graph); + + ASSERT_TRUE(op_to_count["Cast"] == 0); + ASSERT_TRUE(op_to_count["LayerNormalization"] == 1); +} + +TEST_F(GraphTransformationTests, LayerNormWithCastFusionTest_4) { + constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/layer_norm_with_cast_4.onnx"; + std::shared_ptr p_model; + ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); + Graph& graph = p_model->MainGraph(); + + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); + + std::map op_to_count = CountOpsInGraph(graph); + + ASSERT_TRUE(op_to_count["Cast"] == 0); + ASSERT_TRUE(op_to_count["LayerNormalization"] == 1); +} + +/* +ReduceMean: + axes - INTS : A list of integers, along which to reduce. + The default is to reduce over all the dimensions of the input tensor. + Accepted range is [-r, r-1] where r = rank(data). +*/ +TEST_F(GraphTransformationTests, LayerNormWithSubDupFusionTest) { + constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/layer_norm_sub_dup.onnx"; + std::shared_ptr p_model; + ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); + Graph& graph = p_model->MainGraph(); + + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); + + std::map op_to_count = CountOpsInGraph(graph); + ASSERT_TRUE(op_to_count["Div"] > 0); + ASSERT_TRUE(op_to_count["Add"] > 0); + ASSERT_TRUE(op_to_count["Sub"] > 0); + ASSERT_TRUE(op_to_count["ReduceMean"] > 0); + ASSERT_TRUE(op_to_count["Pow"] > 0); + ASSERT_TRUE(op_to_count["Sqrt"] > 0); + ASSERT_TRUE(op_to_count["LayerNormalization"] == 0); + /* + for (const Node& node : graph.Nodes()) { + if (node.OpType() == "LayerNormalization") { + // LayerNormalization should have three inputs. + EXPECT_EQ(node.InputDefs().size(), 3u) << "LayerNormalization number of inputs does not equal to 3. Got:" << node.InputDefs().size(); + // LayerNormalization input "scale" and "bias" should have the same dimension. + const TensorShapeProto* scale_shape = node.InputDefs()[1]->Shape(); + const TensorShapeProto* bias_shape = node.InputDefs()[2]->Shape(); + EXPECT_EQ(scale_shape->dim_size(), 1) << "LayerNormalization scale should be 1D. Got: " << scale_shape->dim_size(); + EXPECT_EQ(bias_shape->dim_size(), 1) << "LayerNormalization bias should be 1D. Got: " << bias_shape->dim_size(); + EXPECT_EQ(scale_shape->dim(0).dim_value(), bias_shape->dim(0).dim_value()); + } else { + EXPECT_TRUE(false) << "Unexpected node " << node.Name(); + } + } + */ +} + +void BuildLayerNorm(ModelTestBuilder& builder, std::vector reduce1_axes = {-1}, + std::vector reduce2_axes = {-1}) { + std::vector input_shape = {2, 3, 3, 3}; + auto* data_arg = builder.MakeInput(input_shape); + auto* pow_initializer = builder.MakeInitializer({}, {2.0f}); + auto* add_initializer = builder.MakeInitializer({}, {1e-5f}); + std::vector normalized_shape = {}; + int64_t normalized_shape_size = 1; + auto raxes = reduce1_axes; + std::transform(raxes.begin(), raxes.end(), raxes.begin(), [&input_shape](int64_t i) { + return i < 0 ? i + input_shape.size() : i; + }); + sort(raxes.begin(), raxes.end()); + for (auto axis : raxes) { + normalized_shape.push_back(input_shape[axis]); + normalized_shape_size *= input_shape[axis]; + } + + auto* weight_initializer = builder.MakeInitializer( + normalized_shape, std::vector(normalized_shape_size, MLFloat16(1.0f))); + auto* bias_initializer = builder.MakeInitializer( + normalized_shape, std::vector(normalized_shape_size, MLFloat16(0.0f))); + auto* reduce_mean_out_1 = builder.MakeIntermediate(); + auto* sub_out = builder.MakeIntermediate(); + auto* cast_out_1 = builder.MakeIntermediate(); + auto* pow_out = builder.MakeIntermediate(); + auto* reduce_mean_out_2 = builder.MakeIntermediate(); + auto* add_out_1 = builder.MakeIntermediate(); + auto* sqrt_out = builder.MakeIntermediate(); + auto* div_out = builder.MakeIntermediate(); + auto* cast_out_2 = builder.MakeIntermediate(); + auto* mul_out = builder.MakeIntermediate(); + auto* add_out_2 = builder.MakeOutput(); + auto opset = builder.DomainToVersionMap().find(kOnnxDomain)->second; + + if (opset >= 18) { + int64_t rsize = static_cast(reduce1_axes.size()); + onnxruntime::NodeArg* axes = builder.MakeInitializer({rsize}, reduce1_axes); + builder.AddNode("ReduceMean", {data_arg, axes}, {reduce_mean_out_1}); + } else { + builder.AddNode("ReduceMean", {data_arg}, {reduce_mean_out_1}).AddAttribute("axes", reduce1_axes); + } + builder.AddNode("Sub", {data_arg, reduce_mean_out_1}, {sub_out}); + builder.AddNode("Cast", {sub_out}, {cast_out_1}) + .AddAttribute("to", static_cast(ONNX_NAMESPACE::TensorProto_DataType_FLOAT)); + builder.AddNode("Pow", {cast_out_1, pow_initializer}, {pow_out}); + if (opset >= 18) { + int64_t rsize = static_cast(reduce2_axes.size()); + onnxruntime::NodeArg* axes = builder.MakeInitializer({rsize}, reduce2_axes); + builder.AddNode("ReduceMean", {pow_out, axes}, {reduce_mean_out_2}); + } else { + builder.AddNode("ReduceMean", {pow_out}, {reduce_mean_out_2}).AddAttribute("axes", reduce2_axes); + } + builder.AddNode("Add", {reduce_mean_out_2, add_initializer}, {add_out_1}); + builder.AddNode("Sqrt", {add_out_1}, {sqrt_out}); + builder.AddNode("Div", {cast_out_1, sqrt_out}, {div_out}); + builder.AddNode("Cast", {div_out}, {cast_out_2}) + .AddAttribute("to", static_cast(ONNX_NAMESPACE::TensorProto_DataType_FLOAT16)); + builder.AddNode("Mul", {cast_out_2, weight_initializer}, {mul_out}); + builder.AddNode("Add", {mul_out, bias_initializer}, {add_out_2}); +} + +TEST_F(GraphTransformationTests, LayerNormWithCastFusionTest_5) { + auto build_test_case = [](ModelTestBuilder& builder) { + BuildLayerNorm(builder, {-1}, {-1}); + }; + + auto pre_graph_checker = [&](Graph& graph) { + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["ReduceMean"] == 2); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Sub"] == 1); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Cast"] == 2); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Pow"] == 1); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Add"] == 2); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Sqrt"] == 1); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Div"] == 1); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Mul"] == 1); + return Status::OK(); + }; + + auto post_graph_checker = [&](Graph& graph) { + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["ReduceMean"] == 0); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Sub"] == 0); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Cast"] == 0); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Pow"] == 0); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Add"] == 0); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Sqrt"] == 0); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Div"] == 0); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Mul"] == 0); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["LayerNormalization"] == 1); + return Status::OK(); + }; + + std::unique_ptr transformer = std::make_unique(); + ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, {14, 18}, *logger_, std::move(transformer), TransformerLevel::Level1, + 1, pre_graph_checker, post_graph_checker)); +} + +TEST_F(GraphTransformationTests, LayerNormWithCastFusionTest_6) { + auto build_test_case = [](ModelTestBuilder& builder) { + BuildLayerNorm(builder, {-2}, {-1}); + }; + + int num_of_layer_norm = 0; + auto post_graph_checker = [&](Graph& graph) { + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["ReduceMean"] == 2 - 2 * num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Sub"] == 1 - num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Cast"] == 2 - 2 * num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Pow"] == 1 - num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Add"] == 2 - 2 * num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Sqrt"] == 1 - num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Div"] == 1 - num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Mul"] == 1 - num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["LayerNormalization"] == num_of_layer_norm); + return Status::OK(); + }; + + std::unique_ptr transformer = std::make_unique(); + ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, {14, 18}, *logger_, std::move(transformer), TransformerLevel::Level1, + 1, nullptr, post_graph_checker)); +} + +TEST_F(GraphTransformationTests, LayerNormWithCastFusionTest_7) { + auto build_test_case = [](ModelTestBuilder& builder) { + BuildLayerNorm(builder, {-2, -1}, {-1, -2}); + }; +#ifdef ENABLE_TRAINING_CORE + int num_of_layer_norm = 1; +#else + int num_of_layer_norm = 0; +#endif + auto post_graph_checker = [&](Graph& graph) { + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["ReduceMean"] == 2 - 2 * num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Sub"] == 1 - num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Cast"] == 2 - 2 * num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Pow"] == 1 - num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Add"] == 2 - 2 * num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Sqrt"] == 1 - num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Div"] == 1 - num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Mul"] == 1 - num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["LayerNormalization"] == num_of_layer_norm); + return Status::OK(); + }; + + std::unique_ptr transformer = std::make_unique(); + ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, {14, 18}, *logger_, std::move(transformer), TransformerLevel::Level1, + 1, nullptr, post_graph_checker)); +} + +TEST_F(GraphTransformationTests, LayerNormWithCastFusionTest_8) { + auto build_test_case = [](ModelTestBuilder& builder) { + BuildLayerNorm(builder, {-3, -2, -1}, {-1, -2}); + }; + + int num_of_layer_norm = 0; + auto post_graph_checker = [&](Graph& graph) { + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["ReduceMean"] == 2 - 2 * num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Sub"] == 1 - num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Cast"] == 2 - 2 * num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Pow"] == 1 - num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Add"] == 2 - 2 * num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Sqrt"] == 1 - num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Div"] == 1 - num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Mul"] == 1 - num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["LayerNormalization"] == num_of_layer_norm); + return Status::OK(); + }; + + std::unique_ptr transformer = std::make_unique(); + ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, {14, 18}, *logger_, std::move(transformer), TransformerLevel::Level1, + 1, nullptr, post_graph_checker)); +} + +TEST_F(GraphTransformationTests, LayerNormWithCastFusionTest_9) { + auto build_test_case = [](ModelTestBuilder& builder) { + BuildLayerNorm(builder, {2, -1}, {-1, -2}); + }; + +#ifdef ENABLE_TRAINING_CORE + int num_of_layer_norm = 1; +#else + int num_of_layer_norm = 0; +#endif + auto post_graph_checker = [&](Graph& graph) { + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["ReduceMean"] == 2 - 2 * num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Sub"] == 1 - num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Cast"] == 2 - 2 * num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Pow"] == 1 - num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Add"] == 2 - 2 * num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Sqrt"] == 1 - num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Div"] == 1 - num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["Mul"] == 1 - num_of_layer_norm); + TEST_RETURN_IF_NOT(CountOpsInGraph(graph)["LayerNormalization"] == num_of_layer_norm); + return Status::OK(); + }; + + std::unique_ptr transformer = std::make_unique(); + ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, {14, 18}, *logger_, std::move(transformer), TransformerLevel::Level1, + 1, nullptr, post_graph_checker)); +} + +TEST_F(GraphTransformationTests, SimplifiedLayerNormFusionTest) { + constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/layer_norm_t5.onnx"; + std::shared_ptr p_model; + ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); + Graph& graph = p_model->MainGraph(); + + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); + + std::map op_to_count = CountOpsInGraph(graph); + ASSERT_TRUE(op_to_count["Div"] == 0); + ASSERT_TRUE(op_to_count["Add"] == 0); + ASSERT_TRUE(op_to_count["ReduceMean"] == 0); + ASSERT_TRUE(op_to_count["Pow"] == 0); + ASSERT_TRUE(op_to_count["Sqrt"] == 0); + ASSERT_TRUE(op_to_count["SimplifiedLayerNormalization"] == 1); + + for (const Node& node : graph.Nodes()) { + if (node.OpType() == "SimplifiedLayerNormalization") { + // LayerNormalization should have two inputs. + EXPECT_EQ(node.InputDefs().size(), 2u) << "LayerNormalization number of inputs does not equal to 2. Got:" << node.InputDefs().size(); + // LayerNormalization input "scale" and "bias" should have the same dimension. + const TensorShapeProto* scale_shape = node.InputDefs()[1]->Shape(); + EXPECT_EQ(scale_shape->dim_size(), 1) << "LayerNormalization scale should be 1D. Got: " << scale_shape->dim_size(); + } else { + EXPECT_TRUE(false) << "Unexpected node " << node.Name(); + } + } +} + +// It tests the scenario when scale or bias are not Graph Inputs and not initialized in Graph +// To test this added a Identity node after Scale and Bias terms to ensure LayerNormFusion works properly +TEST_F(GraphTransformationTests, LayerNormScaleBiasTest) { + constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/layer_norm_fusion_scale_bias.onnx"; + std::shared_ptr p_model; + ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); + Graph& graph = p_model->MainGraph(); + + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); + + std::map op_to_count = CountOpsInGraph(graph); + ASSERT_EQ(op_to_count["ReduceMean"], 0); + ASSERT_EQ(op_to_count["Sub"], 0); + ASSERT_EQ(op_to_count["Cast"], 0); + ASSERT_EQ(op_to_count["Pow"], 0); + ASSERT_EQ(op_to_count["Add"], 0); + ASSERT_EQ(op_to_count["Sqrt"], 0); + ASSERT_EQ(op_to_count["Div"], 0); + ASSERT_EQ(op_to_count["Mul"], 0); + ASSERT_EQ(op_to_count["LayerNormalization"], 1); + + for (const Node& node : graph.Nodes()) { + if (node.OpType() == "LayerNormalization") { + // LayerNormalization should have three inputs. + EXPECT_EQ(node.InputDefs().size(), 3u) << "LayerNormalization number of inputs does not equal to 3. Got:" << node.InputDefs().size(); + // LayerNormalization input "scale" and "bias" should have the same dimension. + const TensorShapeProto* scale_shape = node.InputDefs()[1]->Shape(); + EXPECT_EQ(scale_shape->dim_size(), 1) << "LayerNormalization scale should be 1D. Got: " << scale_shape->dim_size(); + } + } +} + +// If EP is non-GPU EP or unknown, the sub-graph will be not fused because CPU impl for SimplifiedLayerNormalization +// doesn't support input and scale having different data types. +TEST_F(GraphTransformationTests, SimplifiedLayerNormWithCastsFusionTest) { + constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/simplified_layer_norm_with_casts.onnx"; + std::shared_ptr p_model; + ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); + Graph& graph = p_model->MainGraph(); + + InlinedHashSet compatible_eps; + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(compatible_eps), + TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); + + std::map op_to_count = CountOpsInGraph(graph); + ASSERT_TRUE(op_to_count["SimplifiedLayerNormalization"] == 0); +} + +TEST_F(GraphTransformationTests, SimplifiedLayerNormWithCastsFusionTestCudaEp) { + constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/simplified_layer_norm_with_casts.onnx"; + std::shared_ptr p_model; + ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); + Graph& graph = p_model->MainGraph(); + for (auto& node : graph.Nodes()) { + node.SetExecutionProviderType(kCudaExecutionProvider); + } + + InlinedHashSet compatible_eps; + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(compatible_eps), + TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); + + std::map op_to_count = CountOpsInGraph(graph); + ASSERT_TRUE(op_to_count["Div"] == 0); + ASSERT_TRUE(op_to_count["Add"] == 0); + ASSERT_TRUE(op_to_count["ReduceMean"] == 0); + ASSERT_TRUE(op_to_count["Pow"] == 0); + ASSERT_TRUE(op_to_count["Sqrt"] == 0); + ASSERT_TRUE(op_to_count["Cast"] == 0); + ASSERT_TRUE(op_to_count["SimplifiedLayerNormalization"] == 1); + + for (const Node& node : graph.Nodes()) { + if (node.OpType() == "SimplifiedLayerNormalization") { + // LayerNormalization should have two inputs. + EXPECT_EQ(node.InputDefs().size(), 2u) + << "LayerNormalization number of inputs does not equal to 2. Got:" << node.InputDefs().size(); + // LayerNormalization input "scale" and "bias" should have the same dimension. + const TensorShapeProto* scale_shape = node.InputDefs()[1]->Shape(); + EXPECT_EQ(scale_shape->dim_size(), 1) + << "LayerNormalization scale should be 1D. Got: " << scale_shape->dim_size(); + } else if (node.OpType() == "Cast") { + continue; + } else { + EXPECT_TRUE(false) << "Unexpected node " << node.Name(); + } + } +} + +static void TestSkipLayerNormFusion(const std::basic_string& file_path, int add_count, int ln_count, + int skip_ln_count, int cast_count, logging::Logger* logger) { + std::shared_ptr p_model; + ASSERT_TRUE(Model::Load(file_path, p_model, nullptr, *logger).IsOK()); + Graph& graph = p_model->MainGraph(); + + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger)); + + std::map op_to_count = CountOpsInGraph(graph); + ASSERT_TRUE(op_to_count["Div"] == 0); + ASSERT_TRUE(op_to_count["Add"] == add_count); + ASSERT_TRUE(op_to_count["Sub"] == 0); + ASSERT_TRUE(op_to_count["ReduceMean"] == 0); + ASSERT_TRUE(op_to_count["Pow"] == 0); + ASSERT_TRUE(op_to_count["Sqrt"] == 0); + ASSERT_TRUE(op_to_count["LayerNormalization"] == ln_count); + ASSERT_TRUE(op_to_count["com.microsoft.SkipLayerNormalization"] == skip_ln_count); + ASSERT_TRUE(op_to_count["Cast"] == cast_count); +} + +TEST_F(GraphTransformationTests, SkipLayerNormFusionTest) { + TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format1.onnx", 0, 0, 1, 0, logger_.get()); + TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format2.onnx", 0, 0, 1, 0, logger_.get()); + TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format3.onnx", 0, 0, 1, 0, logger_.get()); + + TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format1_partial.onnx", 1, 0, 1, 0, logger_.get()); + TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format2_partial.onnx", 1, 0, 1, 0, logger_.get()); + TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format3_no_fusion.onnx", 1, 1, 0, 0, logger_.get()); + + TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format1_graph_output.onnx", 1, 0, 1, 0, logger_.get()); + TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format2_graph_output.onnx", 1, 0, 1, 0, logger_.get()); + TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format3_graph_output.onnx", 1, 1, 0, 0, logger_.get()); +} + +TEST_F(GraphTransformationTests, SkipLayerNormFusionWithCastTest) { + TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format1_with_cast.onnx", 0, 0, 1, 3, logger_.get()); + TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format2_with_cast.onnx", 0, 0, 1, 3, logger_.get()); + TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format3_with_cast.onnx", 0, 0, 1, 2, logger_.get()); + + TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format1_partial_with_cast.onnx", 1, 0, 1, 2, logger_.get()); + TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format2_partial_with_cast.onnx", 1, 0, 1, 2, logger_.get()); + TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format3_no_fusion_with_cast.onnx", 1, 1, 0, 0, logger_.get()); + + TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format1_graph_output_with_cast.onnx", 1, 0, 1, 2, logger_.get()); + TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format2_graph_output_with_cast.onnx", 1, 0, 1, 2, logger_.get()); + TestSkipLayerNormFusion(MODEL_FOLDER "fusion/skip_layer_norm_format3_graph_output_with_cast.onnx", 1, 1, 0, 0, logger_.get()); +} + +static void TestSkipLayerNormFusionInputOutputCheck(const std::basic_string& model_uri, bool with_cast, logging::Logger* logger) { + std::shared_ptr p_model; + ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger)); + Graph& graph = p_model->MainGraph(); + + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger)); + + for (Node& node : graph.Nodes()) { + if (node.OpType() == "SkipLayerNormalization") { + // check inputs + std::vector& input_defs = node.MutableInputDefs(); + EXPECT_EQ(input_defs.size(), 5u) << "SkipLayerNormalization number of inputs does not equal to 5. Got:" << node.InputDefs().size(); + EXPECT_EQ(input_defs[0]->Name(), ((with_cast) ? "input.1_Float" : "input.1")); + EXPECT_EQ(input_defs[1]->Name(), ((with_cast) ? "6_Float" : "6")); + EXPECT_EQ(input_defs[2]->Name(), "1"); + EXPECT_EQ(input_defs[3]->Name(), "2"); + EXPECT_EQ(input_defs[4]->Name(), ((with_cast) ? "4_Float" : "4")); + + // check outputs + std::vector& output_defs = node.MutableOutputDefs(); +#ifdef ENABLE_TRAINING_CORE + EXPECT_EQ(node.OutputDefs().size(), 3u) << "SkipLayerNormalization number of outputs does not equal to 3. Got:" << node.OutputDefs().size(); +#else + EXPECT_EQ(node.OutputDefs().size(), 1u) << "SkipLayerNormalization number of outputs does not equal to 1. Got:" << node.OutputDefs().size(); +#endif + EXPECT_EQ(output_defs[0]->Name(), "19"); + } else if (node.OpType() == "Cast") { + EXPECT_TRUE(with_cast) << "Unexpected node: " << node.OpType() << "," << node.Name(); + } else { + EXPECT_EQ(node.OpType(), "MatMul") << "Unexpected node: " << node.OpType() << "," << node.Name(); + } + } +} + +TEST_F(GraphTransformationTests, SkipLayerNormFusion_Input_Output_Check) { + TestSkipLayerNormFusionInputOutputCheck(MODEL_FOLDER "fusion/skip_layer_norm_input_output_check.onnx", false, logger_.get()); + TestSkipLayerNormFusionInputOutputCheck(MODEL_FOLDER "fusion/skip_layer_norm_input_output_with_cast_check.onnx", true, logger_.get()); +} + +static void TestSkipLayerNormFusionNoBeta(const std::basic_string& model_uri, bool with_cast, logging::Logger* logger) { + std::shared_ptr p_model; + ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger)); + Graph& graph = p_model->MainGraph(); + + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger)); + + std::map op_to_count = CountOpsInGraph(graph); + ASSERT_TRUE(op_to_count["Add"] == 0); + ASSERT_TRUE(op_to_count["LayerNormalization"] == 0); + ASSERT_TRUE(op_to_count["com.microsoft.SkipLayerNormalization"] == 1); + ASSERT_TRUE(op_to_count["Cast"] == ((with_cast) ? 2 : 0)); +} + +TEST_F(GraphTransformationTests, SkipLayerNormFusion_NoBeta) { + TestSkipLayerNormFusionNoBeta(MODEL_FOLDER "fusion/skip_layer_norm_no_beta.onnx", false, logger_.get()); + TestSkipLayerNormFusionNoBeta(MODEL_FOLDER "fusion/skip_layer_norm_no_beta_with_cast.onnx", true, logger_.get()); +} + +TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat1) { + constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/embed_layer_norm_format1.onnx"; + std::shared_ptr p_model; + ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); + Graph& graph = p_model->MainGraph(); + + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); + + std::map op_to_count = CountOpsInGraph(graph); + ASSERT_TRUE(op_to_count["Gather"] == 0); + ASSERT_TRUE(op_to_count["Add"] == 0); + ASSERT_TRUE(op_to_count["ReduceSum"] == 1); + ASSERT_TRUE(op_to_count["com.microsoft.Attention"] == 1); + ASSERT_TRUE(op_to_count["com.microsoft.SkipLayerNormalization"] == 0); + ASSERT_TRUE(op_to_count["com.microsoft.EmbedLayerNormalization"] == 1); +} + +TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat2) { + constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/embed_layer_norm_format2.onnx"; + std::shared_ptr p_model; + ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); + Graph& graph = p_model->MainGraph(); + + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); + + std::map op_to_count = CountOpsInGraph(graph); + ASSERT_TRUE(op_to_count["Shape"] == 0); + ASSERT_TRUE(op_to_count["Expand"] == 0); + ASSERT_TRUE(op_to_count["Gather"] == 0); + ASSERT_TRUE(op_to_count["Unsqueeze"] == 0); + ASSERT_TRUE(op_to_count["ConstantOfShape"] == 0); + ASSERT_TRUE(op_to_count["NonZero"] == 0); + ASSERT_TRUE(op_to_count["Transpose"] == 0); + ASSERT_TRUE(op_to_count["Squeeze"] == 0); + ASSERT_TRUE(op_to_count["Add"] == 0); + ASSERT_TRUE(op_to_count["ReduceSum"] == 1); + ASSERT_TRUE(op_to_count["com.microsoft.Attention"] == 1); + ASSERT_TRUE(op_to_count["com.microsoft.SkipLayerNormalization"] == 0); + ASSERT_TRUE(op_to_count["com.microsoft.EmbedLayerNormalization"] == 1); +} + +static void EmbedLayerNormFusionFormat3(const std::basic_string& file_path, logging::Logger* logger) { + std::shared_ptr p_model; + ASSERT_TRUE(Model::Load(file_path, p_model, nullptr, *logger).IsOK()); + Graph& graph = p_model->MainGraph(); + + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger)); + + std::map op_to_count = CountOpsInGraph(graph); + EXPECT_EQ(op_to_count["Shape"], 0); + EXPECT_EQ(op_to_count["Expand"], 0); + EXPECT_EQ(op_to_count["Gather"], 0); + EXPECT_EQ(op_to_count["Unsqueeze"], 0); + EXPECT_EQ(op_to_count["LayerNormalization"], 0); + EXPECT_EQ(op_to_count["com.microsoft.SkipLayerNormalization"], 0); + EXPECT_EQ(op_to_count["ReduceSum"], 1); + EXPECT_EQ(op_to_count["MatMul"], 1); + EXPECT_EQ(op_to_count["Add"], 2); + EXPECT_EQ(op_to_count["Cast"], 3); + EXPECT_EQ(op_to_count["com.microsoft.Attention"], 1); + EXPECT_EQ(op_to_count["com.microsoft.EmbedLayerNormalization"], 1); +} + +TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat3) { + EmbedLayerNormFusionFormat3(MODEL_FOLDER "fusion/embed_layer_norm_format3.onnx", logger_.get()); +} + +TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat3_OpSet13) { + EmbedLayerNormFusionFormat3(MODEL_FOLDER "fusion/embed_layer_norm_format3_opset13.onnx", logger_.get()); +} + +static void EmbedLayerNormFusionFormat3NoCast(const std::basic_string& file_path, logging::Logger* logger) { + std::shared_ptr p_model; + ASSERT_TRUE(Model::Load(file_path, p_model, nullptr, *logger).IsOK()); + Graph& graph = p_model->MainGraph(); + + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger)); + + std::map op_to_count = CountOpsInGraph(graph); + EXPECT_EQ(op_to_count["Shape"], 0); + EXPECT_EQ(op_to_count["Expand"], 0); + EXPECT_EQ(op_to_count["Gather"], 0); + EXPECT_EQ(op_to_count["Unsqueeze"], 0); + EXPECT_EQ(op_to_count["LayerNormalization"], 0); + EXPECT_EQ(op_to_count["com.microsoft.SkipLayerNormalization"], 0); + EXPECT_EQ(op_to_count["ReduceSum"], 1); + EXPECT_EQ(op_to_count["MatMul"], 1); + EXPECT_EQ(op_to_count["Add"], 2); + EXPECT_EQ(op_to_count["Cast"], 3); + EXPECT_EQ(op_to_count["com.microsoft.Attention"], 1); + EXPECT_EQ(op_to_count["com.microsoft.EmbedLayerNormalization"], 1); +} + +TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat3NoCast) { + EmbedLayerNormFusionFormat3NoCast(MODEL_FOLDER "fusion/embed_layer_norm_format3_no_cast.onnx", logger_.get()); +} + +TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat3NoCast_OpSet13) { + EmbedLayerNormFusionFormat3NoCast(MODEL_FOLDER "fusion/embed_layer_norm_format3_no_cast_opset13.onnx", logger_.get()); +} + +TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat4) { + constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/embed_layer_norm_format4.onnx"; + std::shared_ptr p_model; + ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_)); + Graph& graph = p_model->MainGraph(); + + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_)); + + std::map op_to_count = CountOpsInGraph(graph); + ASSERT_TRUE(op_to_count["Shape"] == 0); + ASSERT_TRUE(op_to_count["Expand"] == 0); + ASSERT_TRUE(op_to_count["Gather"] == 0); + ASSERT_TRUE(op_to_count["Concat"] == 0); + ASSERT_TRUE(op_to_count["Unsqueeze"] == 0); + ASSERT_TRUE(op_to_count["ConstantOfShape"] == 0); + ASSERT_TRUE(op_to_count["NonZero"] == 0); + ASSERT_TRUE(op_to_count["Transpose"] == 0); + ASSERT_TRUE(op_to_count["Squeeze"] == 0); + ASSERT_TRUE(op_to_count["Add"] == 0); + ASSERT_TRUE(op_to_count["ReduceSum"] == 1); + ASSERT_TRUE(op_to_count["com.microsoft.Attention"] == 1); + ASSERT_TRUE(op_to_count["com.microsoft.SkipLayerNormalization"] == 0); + ASSERT_TRUE(op_to_count["com.microsoft.EmbedLayerNormalization"] == 1); +} + +static void EmbedLayerNormFusionFormat5(const std::basic_string& file_path, logging::Logger* logger) { + std::shared_ptr p_model; + ASSERT_TRUE(Model::Load(file_path, p_model, nullptr, *logger).IsOK()); + Graph& graph = p_model->MainGraph(); + + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger)); + + std::map op_to_count = CountOpsInGraph(graph); + EXPECT_EQ(op_to_count["Gather"], 0); + EXPECT_EQ(op_to_count["LayerNormalization"], 0); + EXPECT_EQ(op_to_count["com.microsoft.SkipLayerNormalization"], 0); + EXPECT_EQ(op_to_count["ReduceSum"], 1); + EXPECT_EQ(op_to_count["MatMul"], 1); + EXPECT_EQ(op_to_count["Add"], 2); + EXPECT_EQ(op_to_count["Cast"], 3); + EXPECT_EQ(op_to_count["com.microsoft.Attention"], 1); + EXPECT_EQ(op_to_count["com.microsoft.EmbedLayerNormalization"], 1); + + // Validate the position embedding input. + for (const Node& node : graph.Nodes()) { + if (node.OpType() == "EmbedLayerNormalization") { + const ONNX_NAMESPACE::TensorProto* tensor_proto = graph_utils::GetConstantInitializer(graph, node.InputDefs()[3]->Name()); + ASSERT_TRUE(tensor_proto != nullptr); + EXPECT_EQ(tensor_proto->data_type(), ONNX_NAMESPACE::TensorProto_DataType_FLOAT); + + auto initializer = std::make_unique(*tensor_proto, graph.ModelPath()); + EXPECT_EQ(initializer->size(), 12U); + + std::vector expected_value = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 8.0, 7.0, 6.0}; + + const float* data = initializer->data(); + for (size_t i = 0; i < expected_value.size(); i++) { + EXPECT_EQ(data[i], static_cast(expected_value[i])); + } + } + } +} + +TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat5) { + EmbedLayerNormFusionFormat5(MODEL_FOLDER "fusion/embed_layer_norm_format5.onnx", logger_.get()); +} + +TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat5_OpSet13) { + EmbedLayerNormFusionFormat5(MODEL_FOLDER "fusion/embed_layer_norm_format5_opset13.onnx", logger_.get()); +} + +static void EmbedLayerNormFusionFormat6(const std::basic_string& file_path, logging::Logger* logger) { + std::shared_ptr p_model; + ASSERT_TRUE(Model::Load(file_path, p_model, nullptr, *logger).IsOK()); + Graph& graph = p_model->MainGraph(); + + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger)); + + std::map op_to_count = CountOpsInGraph(graph); + EXPECT_EQ(op_to_count["Shape"], 0); + EXPECT_EQ(op_to_count["Expand"], 0); + EXPECT_EQ(op_to_count["Gather"], 0); + EXPECT_EQ(op_to_count["Unsqueeze"], 0); + EXPECT_EQ(op_to_count["Reshape"], 0); + EXPECT_EQ(op_to_count["Equal"], 0); + EXPECT_EQ(op_to_count["Where"], 0); + EXPECT_EQ(op_to_count["LayerNormalization"], 0); + EXPECT_EQ(op_to_count["com.microsoft.SkipLayerNormalization"], 0); + EXPECT_EQ(op_to_count["ReduceSum"], 1); + EXPECT_EQ(op_to_count["MatMul"], 1); + EXPECT_EQ(op_to_count["Add"], 2); + EXPECT_EQ(op_to_count["Cast"], 3); + EXPECT_EQ(op_to_count["com.microsoft.Attention"], 1); + EXPECT_EQ(op_to_count["com.microsoft.EmbedLayerNormalization"], 1); +} + +TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat6) { + EmbedLayerNormFusionFormat6(MODEL_FOLDER "fusion/embed_layer_norm_format6.onnx", logger_.get()); +} + +TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat6_OpSet13) { + EmbedLayerNormFusionFormat6(MODEL_FOLDER "fusion/embed_layer_norm_format6_opset13.onnx", logger_.get()); +} + +static void TestEmbedLayerNormFusionDistilBert(const std::basic_string& model_uri, + std::map& op_to_count, + logging::Logger* logger) { + std::shared_ptr p_model; + ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger)); + Graph& graph = p_model->MainGraph(); + + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger)); + + op_to_count = CountOpsInGraph(graph); +} + +// DistilBert +TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat7) { + std::map op_to_count; + TestEmbedLayerNormFusionDistilBert(MODEL_FOLDER "fusion/embed_layer_norm_format7.onnx", op_to_count, logger_.get()); + EXPECT_EQ(op_to_count["com.microsoft.EmbedLayerNormalization"], 1); + EXPECT_EQ(op_to_count["com.microsoft.Attention"], 1); + EXPECT_EQ(op_to_count["Cast"], 2); + EXPECT_EQ(op_to_count["Shape"], 0); + EXPECT_EQ(op_to_count["Gather"], 0); + EXPECT_EQ(op_to_count["Unsqueeze"], 0); + EXPECT_EQ(op_to_count["ReduceSum"], 1); +} + +TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat7_OpSet13) { + std::map op_to_count; + TestEmbedLayerNormFusionDistilBert(MODEL_FOLDER "fusion/embed_layer_norm_format7_opset13.onnx", op_to_count, logger_.get()); + EXPECT_EQ(op_to_count["com.microsoft.EmbedLayerNormalization"], 1); + EXPECT_EQ(op_to_count["com.microsoft.Attention"], 1); + EXPECT_EQ(op_to_count["Cast"], 2); + EXPECT_EQ(op_to_count["Shape"], 0); + EXPECT_EQ(op_to_count["Gather"], 0); + EXPECT_EQ(op_to_count["Unsqueeze"], 0); + EXPECT_EQ(op_to_count["ReduceSum"], 1); +} + +TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat8) { + std::map op_to_count; + TestEmbedLayerNormFusionDistilBert(MODEL_FOLDER "fusion/embed_layer_norm_format8.onnx", op_to_count, logger_.get()); + EXPECT_EQ(op_to_count["com.microsoft.EmbedLayerNormalization"], 1); + EXPECT_EQ(op_to_count["com.microsoft.Attention"], 1); + EXPECT_EQ(op_to_count["Cast"], 2); + EXPECT_EQ(op_to_count["Shape"], 0); + EXPECT_EQ(op_to_count["Gather"], 0); + EXPECT_EQ(op_to_count["Unsqueeze"], 0); + EXPECT_EQ(op_to_count["ReduceSum"], 1); +} + +TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat8_OpSet13) { + std::map op_to_count; + TestEmbedLayerNormFusionDistilBert(MODEL_FOLDER "fusion/embed_layer_norm_format8_opset13.onnx", op_to_count, logger_.get()); + EXPECT_EQ(op_to_count["com.microsoft.EmbedLayerNormalization"], 1); + EXPECT_EQ(op_to_count["com.microsoft.Attention"], 1); + EXPECT_EQ(op_to_count["Cast"], 2); + EXPECT_EQ(op_to_count["Shape"], 0); + EXPECT_EQ(op_to_count["Gather"], 0); + EXPECT_EQ(op_to_count["Unsqueeze"], 0); + EXPECT_EQ(op_to_count["ReduceSum"], 1); +} + +TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat9) { + std::map op_to_count; + TestEmbedLayerNormFusionDistilBert(MODEL_FOLDER "fusion/embed_layer_norm_format9.onnx", op_to_count, logger_.get()); + EXPECT_EQ(op_to_count["com.microsoft.EmbedLayerNormalization"], 1); + EXPECT_EQ(op_to_count["com.microsoft.Attention"], 1); + EXPECT_EQ(op_to_count["Cast"], 2); + EXPECT_EQ(op_to_count["Shape"], 1); + EXPECT_EQ(op_to_count["Gather"], 2); + EXPECT_EQ(op_to_count["Unsqueeze"], 2); + EXPECT_EQ(op_to_count["ReduceSum"], 1); +} + +TEST_F(GraphTransformationTests, EmbedLayerNormFusionFormat9_OpSet13) { + std::map op_to_count; + TestEmbedLayerNormFusionDistilBert(MODEL_FOLDER "fusion/embed_layer_norm_format9_opset13.onnx", op_to_count, logger_.get()); + EXPECT_EQ(op_to_count["com.microsoft.EmbedLayerNormalization"], 1); + EXPECT_EQ(op_to_count["com.microsoft.Attention"], 1); + EXPECT_EQ(op_to_count["Cast"], 2); + EXPECT_EQ(op_to_count["Shape"], 1); + EXPECT_EQ(op_to_count["Gather"], 2); + EXPECT_EQ(op_to_count["Unsqueeze"], 2); + EXPECT_EQ(op_to_count["ReduceSum"], 1); +} + +static void EmbedLayerNormFusionFormatMultiple(const std::basic_string& file_path, logging::Logger* logger) { + std::shared_ptr p_model; + ASSERT_TRUE(Model::Load(file_path, p_model, nullptr, *logger).IsOK()); + Graph& graph = p_model->MainGraph(); + + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level2)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger)); + + std::map op_to_count = CountOpsInGraph(graph); + EXPECT_EQ(op_to_count["Shape"], 0); + EXPECT_EQ(op_to_count["Expand"], 0); + EXPECT_EQ(op_to_count["Gather"], 0); + EXPECT_EQ(op_to_count["Unsqueeze"], 0); + EXPECT_EQ(op_to_count["LayerNormalization"], 0); + EXPECT_EQ(op_to_count["com.microsoft.SkipLayerNormalization"], 0); + EXPECT_EQ(op_to_count["ReduceSum"], 2); + EXPECT_EQ(op_to_count["MatMul"], 2); + EXPECT_EQ(op_to_count["Add"], 5); + EXPECT_EQ(op_to_count["Cast"], 6); + EXPECT_EQ(op_to_count["com.microsoft.Attention"], 2); + EXPECT_EQ(op_to_count["com.microsoft.EmbedLayerNormalization"], 2); +} + +TEST_F(GraphTransformationTests, EmbedLayerNormFusionMultiple) { + EmbedLayerNormFusionFormatMultiple(MODEL_FOLDER "fusion/embed_layer_norm_multiple.onnx", logger_.get()); +} + +TEST_F(GraphTransformationTests, EmbedLayerNormFusionMultiple_OpSet13) { + EmbedLayerNormFusionFormatMultiple(MODEL_FOLDER "fusion/embed_layer_norm_multiple_opset13.onnx", logger_.get()); +} + +#endif + +} // namespace test +} // namespace onnxruntime diff --git a/onnxruntime/test/optimizer/layout_transformation_potentially_added_ops_test.cc b/onnxruntime/test/optimizer/layout_transformation_potentially_added_ops_test.cc index 184bd6dacf1b1..2d8a40ddd26db 100644 --- a/onnxruntime/test/optimizer/layout_transformation_potentially_added_ops_test.cc +++ b/onnxruntime/test/optimizer/layout_transformation_potentially_added_ops_test.cc @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/optimizer/transpose_optimizer/layout_transformation_potentially_added_ops.h" +#include "core/optimizer/layout_transformation/layout_transformation_potentially_added_ops.h" #include "gtest/gtest.h" diff --git a/onnxruntime/test/optimizer/nchwc_optimizer_test.cc b/onnxruntime/test/optimizer/nchwc_optimizer_test.cc index 19602940ce454..8e4edc9e0abbb 100644 --- a/onnxruntime/test/optimizer/nchwc_optimizer_test.cc +++ b/onnxruntime/test/optimizer/nchwc_optimizer_test.cc @@ -25,7 +25,7 @@ struct NchwcTestHelper { template NodeArg* MakeInput(const std::vector& shape, const ONNX_NAMESPACE::TypeProto& type_proto) { OrtValue input_value; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), shape, + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], shape, FillRandomData(shape), &input_value); std::string name = graph_.GenerateNodeArgName("input"); feeds_.insert(std::make_pair(name, input_value)); diff --git a/onnxruntime/test/optimizer/nhwc_transformer_test.cc b/onnxruntime/test/optimizer/nhwc_transformer_test.cc index 413f456b80d67..c254d340cdcb8 100644 --- a/onnxruntime/test/optimizer/nhwc_transformer_test.cc +++ b/onnxruntime/test/optimizer/nhwc_transformer_test.cc @@ -6,7 +6,7 @@ #include "gtest/gtest.h" #include "graph_transform_test_builder.h" - +#include "core/mlas/inc/mlas.h" #include "core/graph/graph.h" namespace onnxruntime { @@ -516,6 +516,167 @@ TEST(NhwcTransformerTests, ConvMixTensorRanks) { TransformerLevel::Level3); } +#ifdef MLAS_F16VEC_INTRINSICS_SUPPORTED + +std::vector randomfp16(const std::vector& shape, MLFloat16 min, MLFloat16 max) { + std::vector val(detail::SizeFromDims(shape)); + float start = min.ToFloat(); + float end = max.ToFloat(); + float step = (end - start) / 128; + float value = start; + for (size_t i = 0; i < val.size(); ++i) { + value += step; + if (value > end) { + value = start; + } + val[i] = MLFloat16(value); + } + return val; +} + +template <> +NodeArg* ModelTestBuilder::MakeInput(const std::vector& shape, MLFloat16 min, MLFloat16 max) { + return MakeInput(shape, randomfp16(shape, min, max)); +} + +template <> +NodeArg* ModelTestBuilder::MakeInitializer(const std::vector& shape, MLFloat16 min, MLFloat16 max) { + return MakeInitializer(shape, randomfp16(shape, min, max)); +} + +TEST(NhwcTransformerTests, ConvFp16) { + auto test_case = [&](const std::vector& input_shape, const std::vector& weights_shape) { + auto build_test_case = [&](ModelTestBuilder& builder) { + auto* input_arg = builder.MakeInput(input_shape, MLFloat16(-1.5f), MLFloat16(1.5f)); + auto* output_arg = builder.MakeOutput(); + auto* weight_arg = builder.MakeInitializer(weights_shape, MLFloat16(-1.5f), MLFloat16(1.5f)); + + builder.AddConvNode(input_arg, weight_arg, output_arg); + }; + + auto check_nhwc_graph = [&](InferenceSessionWrapper& session) { + auto op_to_count = CountOpsInGraph(session.GetGraph()); + EXPECT_EQ(op_to_count["com.microsoft.NhwcFusedConv"], 1); + EXPECT_EQ(op_to_count["Transpose"], 2); + }; + + TransformerTester(build_test_case, + check_nhwc_graph, + TransformerLevel::Level2, + TransformerLevel::Level3); + }; + + // Test the basic case of a single 1D/2D/3D convolution. + test_case({1, 12, 37}, {32, 12, 5}); + test_case({1, 23, 13, 13}, {30, 23, 3, 3}); + test_case({1, 22, 11, 13, 15}, {30, 22, 5, 3, 3}); +} + +TEST(NhwcTransformerTests, ConvMaxPoolFp16) { + auto test_case = [&](const std::vector& input_shape, const std::vector& weights_shape) { + auto build_test_case = [&](ModelTestBuilder& builder) { + auto* input_arg = builder.MakeInput(input_shape, MLFloat16(-1.5f), MLFloat16(1.5f)); + auto* conv_output_arg = builder.MakeIntermediate(); + auto* output_arg = builder.MakeOutput(); + auto* conv_weight_arg = builder.MakeInitializer(weights_shape, MLFloat16(-1.5f), MLFloat16(1.5f)); + + builder.AddConvNode(input_arg, conv_weight_arg, conv_output_arg); + Node& pool_node = builder.AddNode("MaxPool", {conv_output_arg}, {output_arg}); + std::vector pads((weights_shape.size() - 2) * 2, 1); + pool_node.AddAttribute("pads", pads); + std::vector kernel_shape(weights_shape.size() - 2, 3); + pool_node.AddAttribute("kernel_shape", kernel_shape); + }; + + auto check_nhwc_graph = [&](InferenceSessionWrapper& session) { + auto op_to_count = CountOpsInGraph(session.GetGraph()); + EXPECT_EQ(op_to_count["com.microsoft.NhwcFusedConv"], 1); + EXPECT_EQ(op_to_count["com.ms.internal.nhwc.MaxPool"], 1); + EXPECT_EQ(op_to_count["Transpose"], 2); + }; + + TransformerTester(build_test_case, + check_nhwc_graph, + TransformerLevel::Level2, + TransformerLevel::Level3); + }; + + // Test the basic case of a single 1D/2D/3D convolution. + test_case({5, 12, 37}, {128, 12, 5}); + test_case({3, 14, 13, 13}, {64, 14, 3, 3}); + test_case({1, 15, 11, 13, 15}, {31, 15, 5, 3, 3}); +} + +TEST(NhwcTransformerTests, ConvGlobalAveragePoolFp16) { + auto build_test_case = [&](ModelTestBuilder& builder) { + auto* input_arg = builder.MakeInput({1, 23, 13, 13}, MLFloat16(-1.5f), MLFloat16(1.5f)); + auto* conv1_output_arg = builder.MakeIntermediate(); + auto* conv2_output_arg = builder.MakeIntermediate(); + auto* gavgpool1_output_arg = builder.MakeIntermediate(); + auto* output_arg = builder.MakeOutput(); + auto* conv1_weight_arg = builder.MakeInitializer({30, 23, 3, 3}, MLFloat16(-1.5f), MLFloat16(1.5f)); + auto* conv2_weight_arg = builder.MakeInitializer({16, 30, 1, 1}, MLFloat16(-1.5f), MLFloat16(1.5f)); + + Node& conv1_node = builder.AddConvNode(input_arg, conv1_weight_arg, conv1_output_arg); + conv1_node.AddAttribute("pads", std::vector{1, 1, 1, 1}); + + builder.AddNode("GlobalAveragePool", {conv1_output_arg}, {gavgpool1_output_arg}); + builder.AddConvNode(gavgpool1_output_arg, conv2_weight_arg, conv2_output_arg); + builder.AddNode("GlobalAveragePool", {conv2_output_arg}, {output_arg}); + }; + + auto check_nhwc_graph = [&](InferenceSessionWrapper& session) { + auto op_to_count = CountOpsInGraph(session.GetGraph()); + EXPECT_EQ(op_to_count["com.microsoft.NhwcFusedConv"], 2); + EXPECT_EQ(op_to_count["com.ms.internal.nhwc.GlobalAveragePool"], 2); + EXPECT_EQ(op_to_count["Transpose"], 2); + }; + + TransformerTester(build_test_case, + check_nhwc_graph, + TransformerLevel::Level2, + TransformerLevel::Level3); +} + +TEST(NhwcTransformerTests, ConvAveragePoolFp16) { + auto build_test_case = [&](ModelTestBuilder& builder) { + auto* input_arg = builder.MakeInput({1, 23, 13, 13}, MLFloat16(-1.5f), MLFloat16(1.5f)); + auto* conv1_output_arg = builder.MakeIntermediate(); + auto* conv2_output_arg = builder.MakeIntermediate(); + auto* avgpool1_output_arg = builder.MakeIntermediate(); + auto* output_arg = builder.MakeOutput(); + auto* conv1_weight_arg = builder.MakeInitializer({30, 23, 3, 3}, MLFloat16(-1.5f), MLFloat16(1.5f)); + auto* conv2_weight_arg = builder.MakeInitializer({16, 30, 3, 3}, MLFloat16(-1.5f), MLFloat16(1.5f)); + + Node& conv1_node = builder.AddConvNode(input_arg, conv1_weight_arg, conv1_output_arg); + conv1_node.AddAttribute("pads", std::vector{1, 1, 1, 1}); + Node& avgpool_node1 = builder.AddNode( + "AveragePool", {conv1_output_arg}, {avgpool1_output_arg}); + avgpool_node1.AddAttribute("kernel_shape", std::vector{3, 3}); + avgpool_node1.AddAttribute("pads", std::vector{1, 1, 1, 1}); + + builder.AddConvNode(avgpool1_output_arg, conv2_weight_arg, conv2_output_arg); + Node& avgpool_node2 = builder.AddNode( + "AveragePool", {conv2_output_arg}, {output_arg}); + avgpool_node2.AddAttribute("kernel_shape", std::vector{3, 3}); + avgpool_node2.AddAttribute("pads", std::vector{1, 1, 1, 1}); + }; + + auto check_nhwc_graph = [&](InferenceSessionWrapper& session) { + auto op_to_count = CountOpsInGraph(session.GetGraph()); + EXPECT_EQ(op_to_count["com.microsoft.NhwcFusedConv"], 2); + EXPECT_EQ(op_to_count["com.ms.internal.nhwc.AveragePool"], 2); + EXPECT_EQ(op_to_count["Transpose"], 2); + }; + + TransformerTester(build_test_case, + check_nhwc_graph, + TransformerLevel::Level2, + TransformerLevel::Level3); +} + +#endif // MLAS_F16VEC_INTRINSICS_SUPPORTED + #endif // DISABLE_CONTRIB_OPS } // namespace test diff --git a/onnxruntime/test/optimizer/qdq_test_utils.cc b/onnxruntime/test/optimizer/qdq_test_utils.cc index 88118c177980d..24cace43c6967 100644 --- a/onnxruntime/test/optimizer/qdq_test_utils.cc +++ b/onnxruntime/test/optimizer/qdq_test_utils.cc @@ -3,6 +3,7 @@ #include "qdq_test_utils.h" #include +#include #include "core/common/common.h" namespace onnxruntime { @@ -34,10 +35,10 @@ GetQDQTestCaseFn BuildQDQConcatTestCase(const std::vector>& int64_t axis, bool has_input_float, bool has_input_int8, - bool has_output_int8) { - return [input_shapes, axis, - has_input_float, has_input_int8, has_output_int8]( - ModelTestBuilder& builder) { + bool has_output_int8, + bool use_contrib_qdq) { + return [input_shapes, axis, has_input_float, has_input_int8, + has_output_int8, use_contrib_qdq](ModelTestBuilder& builder) { auto input_count = input_shapes.size(); std::vector input_args; std::vector q_input_args; @@ -46,9 +47,9 @@ GetQDQTestCaseFn BuildQDQConcatTestCase(const std::vector>& if (i == 0 && has_input_float) { q_input_args.push_back(input_args.back()); } else if (i == 0 && has_input_int8) { - q_input_args.push_back(AddQDQNodePair(builder, input_args.back(), 0.05f, 1)); + q_input_args.push_back(AddQDQNodePair(builder, input_args.back(), 0.05f, 1, use_contrib_qdq)); } else { - q_input_args.push_back(AddQDQNodePair(builder, input_args.back(), 0.05f, 128)); + q_input_args.push_back(AddQDQNodePair(builder, input_args.back(), 0.05f, 128, use_contrib_qdq)); } } auto* concat_output = builder.MakeIntermediate(); @@ -57,15 +58,15 @@ GetQDQTestCaseFn BuildQDQConcatTestCase(const std::vector>& auto* q_concat_output = builder.MakeIntermediate(); if (has_output_int8) { - builder.AddQuantizeLinearNode(concat_output, 0.05f, 1, q_concat_output); + builder.AddQuantizeLinearNode(concat_output, 0.05f, 1, q_concat_output, use_contrib_qdq); auto* output_arg = builder.MakeOutput(); - builder.AddDequantizeLinearNode(q_concat_output, 0.05f, 1, output_arg); + builder.AddDequantizeLinearNode(q_concat_output, 0.05f, 1, output_arg, use_contrib_qdq); } else { - builder.AddQuantizeLinearNode(concat_output, 0.05f, 128, q_concat_output); + builder.AddQuantizeLinearNode(concat_output, 0.05f, 128, q_concat_output, use_contrib_qdq); auto* output_arg = builder.MakeOutput(); - builder.AddDequantizeLinearNode(q_concat_output, 0.05f, 128, output_arg); + builder.AddDequantizeLinearNode(q_concat_output, 0.05f, 128, output_arg, use_contrib_qdq); } }; } @@ -143,12 +144,22 @@ GetQDQTestCaseFn BuildQDQMatMulTestCase(const std::vector& input1_shape }; } -std::vector GetNodeOpTypesInTopologicalOrder(const Graph& graph) { +std::vector GetNodeOpTypesInTopologicalOrder(const Graph& graph, bool include_domain) { std::vector op_types{}; GraphViewer graph_viewer{graph}; const auto& ordering = graph_viewer.GetNodesInTopologicalOrder(); for (const auto node_idx : ordering) { - op_types.push_back(graph.GetNode(node_idx)->OpType()); + const auto* node = graph.GetNode(node_idx); + std::string full_op_type; + + if (include_domain) { + const std::string& domain = node->Domain(); + full_op_type = domain.empty() ? node->OpType() : domain + "." + node->OpType(); + } else { + full_op_type = node->OpType(); + } + + op_types.push_back(std::move(full_op_type)); } return op_types; } diff --git a/onnxruntime/test/optimizer/qdq_test_utils.h b/onnxruntime/test/optimizer/qdq_test_utils.h index e91cbcf26e968..2008d96539dca 100644 --- a/onnxruntime/test/optimizer/qdq_test_utils.h +++ b/onnxruntime/test/optimizer/qdq_test_utils.h @@ -21,21 +21,22 @@ using GetQDQTestCaseFn = std::function; template typename std::enable_if::value, NodeArg*>::type -AddQDQNodePair(ModelTestBuilder& builder, NodeArg* q_input, float scale, T zp = T()) { +AddQDQNodePair(ModelTestBuilder& builder, NodeArg* q_input, float scale, T zp = T(), bool use_ms_domain = false) { auto* q_output = builder.MakeIntermediate(); auto* dq_output = builder.MakeIntermediate(); - builder.AddQuantizeLinearNode(q_input, scale, zp, q_output); - builder.AddDequantizeLinearNode(q_output, scale, zp, dq_output); + builder.AddQuantizeLinearNode(q_input, scale, zp, q_output, use_ms_domain); + builder.AddDequantizeLinearNode(q_output, scale, zp, dq_output, use_ms_domain); return dq_output; } template typename std::enable_if::value, NodeArg*>::type -AddQDQNodePairWithOutputAsGraphOutput(ModelTestBuilder& builder, NodeArg* q_input, float scale, T zp = T()) { +AddQDQNodePairWithOutputAsGraphOutput(ModelTestBuilder& builder, NodeArg* q_input, float scale, T zp = T(), + bool use_ms_domain = false) { auto* q_output = builder.MakeIntermediate(); auto* dq_output = builder.MakeOutput(); - builder.AddQuantizeLinearNode(q_input, scale, zp, q_output); - builder.AddDequantizeLinearNode(q_output, scale, zp, dq_output); + builder.AddQuantizeLinearNode(q_input, scale, zp, q_output, use_ms_domain); + builder.AddDequantizeLinearNode(q_output, scale, zp, dq_output, use_ms_domain); return dq_output; } @@ -91,209 +92,11 @@ GetQDQTestCaseFn BuildQDQConvTransposeTestCase(const std::vector& input }; } -// Creates the graph: -// _______________________ -// input_u8 -> DQ -> | | -> Q -> output_u8 -// scale_u8 (initializer) -> DQ -> | InstanceNormalization | -// bias_u8 (initializer) -> DQ -> |_______________________| -// -// Currently used to test QNN EP. -template -GetQDQTestCaseFn BuildQDQInstanceNormTestCase(const std::vector& input_shape, float epsilon) { - return [input_shape, epsilon](ModelTestBuilder& builder) { - const int64_t num_channels = input_shape[1]; - const InputQType quant_zero_point = 0; - const float quant_scale = 1.0f; - - auto* dq_scale_output = builder.MakeIntermediate(); - auto* scale = builder.MakeInitializer({num_channels}, static_cast(0), - static_cast(127)); - builder.AddDequantizeLinearNode(scale, quant_scale, quant_zero_point, dq_scale_output); - - // Add bias (initializer) -> DQ -> - auto* dq_bias_output = builder.MakeIntermediate(); - auto* bias = builder.MakeInitializer({num_channels}, static_cast(0), - static_cast(4)); - builder.AddDequantizeLinearNode(bias, 1.0f, 0, dq_bias_output); - - // Add input_u8 -> DQ -> - auto* input_u8 = builder.MakeInput(input_shape, static_cast(0), - static_cast(10)); - auto* dq_input_output = builder.MakeIntermediate(); - builder.AddDequantizeLinearNode(input_u8, quant_scale, quant_zero_point, dq_input_output); - - // Add dq_input_output -> InstanceNormalization -> - auto* instance_norm_output = builder.MakeIntermediate(); - Node& inst_norm_node = builder.AddNode("InstanceNormalization", {dq_input_output, dq_scale_output, dq_bias_output}, - {instance_norm_output}); - inst_norm_node.AddAttribute("epsilon", epsilon); - - // Add instance_norm_output -> Q -> output_u8 - auto* output_u8 = builder.MakeOutput(); - builder.AddQuantizeLinearNode(instance_norm_output, quant_scale, quant_zero_point, output_u8); - }; -} - -// Creates the following graph if axes is an input (newer opsets): -// _______________________ -// input (f32) -> Q -> DQ -> | | -> Q -> DQ -> output (f32) -// axes (int32, initializer) -> | Reduce___ | -// |_______________________| -// -// Creates the following graph if axes is an attribute (older opsets): -// _______________________ -// input (f32) -> Q -> DQ -> | | -> Q -> DQ -> output (f32) -// | Reduce___ | -// |_______________________| -// -// Currently used to test QNN EP. -template -GetQDQTestCaseFn BuildQDQReduceOpTestCase(const std::string& reduce_op_type, const std::vector& input_shape, - bool axes_as_input, std::vector axes, bool keepdims, - bool noop_with_empty_axes, const std::string& domain = "") { - return [reduce_op_type, input_shape, axes_as_input, axes, keepdims, - noop_with_empty_axes, domain](ModelTestBuilder& builder) { - using QuantTypeLimits = std::numeric_limits; - QuantType input_quant_min_value = QuantTypeLimits::min(); - QuantType input_quant_max_value = QuantTypeLimits::max(); - - auto* input_data = builder.MakeInput(input_shape, -1.0f, 1.0f); - auto* final_output = builder.MakeOutput(); - - // input_data -> Q/DQ -> - auto* input_qdq_output = AddQDQNodePair(builder, input_data, .04f, - (input_quant_min_value + input_quant_max_value) / 2 + 1); - - // -> ReduceOp (e.g., ReduceSum) -> - std::vector reduce_op_inputs; - reduce_op_inputs.push_back(input_qdq_output); - - if (axes_as_input) { - reduce_op_inputs.push_back(builder.MakeInitializer({static_cast(axes.size())}, axes)); - } - - auto* reduce_sum_output = builder.MakeIntermediate(); - Node& reduce_sum_node = builder.AddNode(reduce_op_type, reduce_op_inputs, {reduce_sum_output}, - domain); - reduce_sum_node.AddAttribute("keepdims", static_cast(keepdims)); - - if (axes_as_input) { - reduce_sum_node.AddAttribute("noop_with_empty_axes", static_cast(noop_with_empty_axes)); - } else { - reduce_sum_node.AddAttribute("axes", axes); - } - - // -> Q/DQ -> final_output - auto* q_output = builder.MakeIntermediate(); - builder.AddQuantizeLinearNode(reduce_sum_output, .039f, - (QuantTypeLimits::min() + QuantTypeLimits::max()) / 2 + 1, - q_output); - - builder.AddDequantizeLinearNode(q_output, .039f, - (QuantTypeLimits::min() + QuantTypeLimits::max()) / 2 + 1, - final_output); - }; -} - -// Creates the following graph: -// _______________________ -// input (f32) -> Q -> DQ -> | | -> Q -> DQ -> output (f32) -// axes (int32, initializer) -> | Gather | -// |_______________________| -// -template -GetQDQTestCaseFn BuildQDQGatherOpTestCase(const std::vector& input_shape, - const std::vector indices, - const std::vector& indices_shape, - int64_t axis) { - return [input_shape, indices, indices_shape, axis](ModelTestBuilder& builder) { - auto* input_data = builder.MakeInput(input_shape, -1.0f, 1.0f); - auto* final_output = builder.MakeOutput(); - - // input_data -> Q/DQ -> - auto* input_qdq_output = AddQDQNodePair(builder, input_data, .003f, 1); - - auto* indices_input = builder.MakeInitializer(indices_shape, indices); - - auto* gather_output = builder.MakeIntermediate(); - Node& gather_node = builder.AddNode("Gather", {input_qdq_output, indices_input}, {gather_output}); - gather_node.AddAttribute("axis", axis); - - // -> Q/DQ -> final_output - auto* q_output = builder.MakeIntermediate(); - builder.AddQuantizeLinearNode(gather_output, .003f, 1, - q_output); - - builder.AddDequantizeLinearNode(q_output, .003f, 1, - final_output); - }; -} - -// Creates the following graph: -// _______________________ -// input (f32) -> Q -> DQ -> | | -> Q -> DQ -> output (f32) -// axes (int32, initializer) -> | Gather | -// |_______________________| -// -template -GetQDQTestCaseFn BuildQDQGatherOpScalarIndicesTestCase(const std::vector& input_shape, - const IndicesType indices, - int64_t axis) { - return [input_shape, indices, axis](ModelTestBuilder& builder) { - auto* input_data = builder.MakeInput(input_shape, -1.0f, 1.0f); - auto* final_output = builder.MakeOutput(); - - // input_data -> Q/DQ -> - auto* input_qdq_output = AddQDQNodePair(builder, input_data, .003f, 1); - - auto* indices_input = builder.MakeScalarInitializer(indices); - - auto* gather_output = builder.MakeIntermediate(); - Node& gather_node = builder.AddNode("Gather", {input_qdq_output, indices_input}, {gather_output}); - gather_node.AddAttribute("axis", axis); - - // -> Q/DQ -> final_output - auto* q_output = builder.MakeIntermediate(); - builder.AddQuantizeLinearNode(gather_output, .003f, 1, - q_output); - - builder.AddDequantizeLinearNode(q_output, .003f, 1, - final_output); - }; -} - -// Creates the following graph: -// _______________________ -// | | -// input (f32) -> Q -> DQ -> | LeakyRelu | -> Q -> DQ -> output (f32) -// |_______________________| -// -template -GetQDQTestCaseFn BuildQDQLeakyReluOpTestCase(const std::vector& input_shape) { - return [input_shape](ModelTestBuilder& builder) { - auto* input_data = builder.MakeInput(input_shape, -1.0f, 1.0f); - auto* final_output = builder.MakeOutput(); - - // input_data -> Q/DQ -> - auto* input_qdq_output = AddQDQNodePair(builder, input_data, 0.0473f, 137); - - auto* leakyrelu_output = builder.MakeIntermediate(); - Node& leakyrelu_node = builder.AddNode("LeakyRelu", {input_qdq_output}, {leakyrelu_output}); - leakyrelu_node.AddAttribute("alpha", 0.2f); - - // -> Q/DQ -> final_output - auto* q_output = builder.MakeIntermediate(); - builder.AddQuantizeLinearNode(leakyrelu_output, 0.02696f, 48, - q_output); - - builder.AddDequantizeLinearNode(q_output, 0.02696f, 48, - final_output); - }; -} - template -GetQDQTestCaseFn BuildQDQConvTestCase(const std::vector& input_shape, const std::vector& weights_shape) { - return [input_shape, weights_shape](ModelTestBuilder& builder) { +GetQDQTestCaseFn BuildQDQConvTestCase(const std::vector& input_shape, + const std::vector& weights_shape, + bool use_contrib_qdq = false) { + return [input_shape, weights_shape, use_contrib_qdq](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput(input_shape, -1.f, 1.f); auto* output_arg = builder.MakeOutput(); @@ -319,34 +122,38 @@ GetQDQTestCaseFn BuildQDQConvTestCase(const std::vector& input_shape, c auto* weight = builder.MakeInitializer(weights_shape, weight_min_value, weight_max_value); builder.AddDequantizeLinearNode(weight, .03f, (weight_min_value + weight_max_value) / 2 + 1, - dq_w_output); + dq_w_output, + use_contrib_qdq); auto* dq_bias_output = builder.MakeIntermediate(); auto* bias = builder.MakeInitializer({weights_shape[0]}, static_cast(0), static_cast(127)); builder.AddDequantizeLinearNode(bias, .0012f, 0, - dq_bias_output); + dq_bias_output, + use_contrib_qdq); auto* conv_output = builder.MakeIntermediate(); auto* dq_output = AddQDQNodePair(builder, input_arg, .04f, - (input_min_value + input_max_value) / 2 + 1); + (input_min_value + input_max_value) / 2 + 1, use_contrib_qdq); builder.AddNode("Conv", {dq_output, dq_w_output, dq_bias_output}, {conv_output}); auto* q_output = builder.MakeIntermediate(); builder.AddQuantizeLinearNode(conv_output, .039f, (OutputLimits::min() + OutputLimits::max()) / 2 + 1, - q_output); + q_output, + use_contrib_qdq); builder.AddDequantizeLinearNode(q_output, .039f, (OutputLimits::min() + OutputLimits::max()) / 2 + 1, - output_arg); + output_arg, + use_contrib_qdq); }; } template GetQDQTestCaseFn BuildQDQAveragePoolTestCase(const std::vector& input_shape, - int64_t count_include_pad = 0) { - return [input_shape, count_include_pad](ModelTestBuilder& builder) { + int64_t count_include_pad = 0, bool use_contrib_qdq = false) { + return [input_shape, count_include_pad, use_contrib_qdq](ModelTestBuilder& builder) { #ifdef USE_NNAPI // NNAPI require consistent scales/ZPs for DQ -> Pool -> Q float dq_scale = 0.0038f; @@ -367,7 +174,7 @@ GetQDQTestCaseFn BuildQDQAveragePoolTestCase(const std::vector& input_s auto* input_arg = builder.MakeInput(input_shape, -1.f, 1.f); auto* output_arg = builder.MakeOutput(); // add QDQ + AveragePool - auto* dq_output = AddQDQNodePair(builder, input_arg, dq_scale, dq_zp); + auto* dq_output = AddQDQNodePair(builder, input_arg, dq_scale, dq_zp, use_contrib_qdq); auto* averagepool_output = builder.MakeIntermediate(); Node& pool_node = builder.AddNode("AveragePool", {dq_output}, {averagepool_output}); std::vector pads((input_shape.size() - 2) * 2, 1); @@ -383,11 +190,13 @@ GetQDQTestCaseFn BuildQDQAveragePoolTestCase(const std::vector& input_s builder.AddQuantizeLinearNode(averagepool_output, pool_output_scale, pool_output_zp, - q_output); + q_output, + use_contrib_qdq); builder.AddDequantizeLinearNode(q_output, q_scale, q_zp, - output_arg); + output_arg, + use_contrib_qdq); }; } @@ -427,8 +236,9 @@ GetQDQTestCaseFn BuildQDQMaxPoolTestCase(const std::vector& input_shape } template -GetQDQTestCaseFn BuildQDQGlobalAveragePoolTestCase(const std::vector& input_shape) { - return [input_shape](ModelTestBuilder& builder) { +GetQDQTestCaseFn BuildQDQGlobalAveragePoolTestCase(const std::vector& input_shape, + bool use_contrib_qdq = false) { + return [input_shape, use_contrib_qdq](ModelTestBuilder& builder) { float dq_scale = 0.0035f; float pool_output_scale = 0.0038f; float q_scale = 0.0039f; @@ -439,7 +249,7 @@ GetQDQTestCaseFn BuildQDQGlobalAveragePoolTestCase(const std::vector& i auto* input_arg = builder.MakeInput(input_shape, -1.f, 1.f); auto* output_arg = builder.MakeOutput(); // add QDQ + GlobalAveragePool - auto* dq_output = AddQDQNodePair(builder, input_arg, dq_scale, dq_zp); + auto* dq_output = AddQDQNodePair(builder, input_arg, dq_scale, dq_zp, use_contrib_qdq); auto* globalaveragepool_output = builder.MakeIntermediate(); builder.AddNode("GlobalAveragePool", {dq_output}, {globalaveragepool_output}); @@ -448,11 +258,13 @@ GetQDQTestCaseFn BuildQDQGlobalAveragePoolTestCase(const std::vector& i builder.AddQuantizeLinearNode(globalaveragepool_output, pool_output_scale, pool_output_zp, - q_output); + q_output, + use_contrib_qdq); builder.AddDequantizeLinearNode(q_output, q_scale, q_zp, - output_arg); + output_arg, + use_contrib_qdq); }; } @@ -462,10 +274,11 @@ GetQDQTestCaseFn BuildQDQResizeTestCase(const std::vector& input_shape, const std::string& mode = "nearest", const std::string& coordinate_transformation_mode = "half_pixel", const std::string& nearest_mode = "round_prefer_floor", - bool add_dq_output_float = false) { + bool add_dq_output_float = false, + bool use_contrib_qdq = false) { static_assert(std::is_same_v || std::is_same_v); return [input_shape, sizes_data, mode, coordinate_transformation_mode, - nearest_mode, add_dq_output_float](ModelTestBuilder& builder) { + nearest_mode, add_dq_output_float, use_contrib_qdq](ModelTestBuilder& builder) { auto* input1_arg = builder.MakeInput(input_shape, std::numeric_limits::min(), std::numeric_limits::max()); @@ -476,7 +289,7 @@ GetQDQTestCaseFn BuildQDQResizeTestCase(const std::vector& input_shape, // add DQ auto* dq_output = builder.MakeIntermediate(); - builder.AddDequantizeLinearNode(input1_arg, .003f, 1, dq_output); + builder.AddDequantizeLinearNode(input1_arg, .003f, 1, dq_output, use_contrib_qdq); // add Resize auto* resize_output = builder.MakeIntermediate(); @@ -492,21 +305,21 @@ GetQDQTestCaseFn BuildQDQResizeTestCase(const std::vector& input_shape, if (add_dq_output_float) { // add Q output_arg = builder.MakeIntermediate(); - builder.AddQuantizeLinearNode(resize_output, .003f, 1, output_arg); + builder.AddQuantizeLinearNode(resize_output, .003f, 1, output_arg, use_contrib_qdq); auto* f_dq_output = builder.MakeOutput(); - builder.AddDequantizeLinearNode(output_arg, .003f, 1, f_dq_output); + builder.AddDequantizeLinearNode(output_arg, .003f, 1, f_dq_output, use_contrib_qdq); } else { output_arg = builder.MakeOutput(); // add Q - builder.AddQuantizeLinearNode(resize_output, .003f, 1, output_arg); + builder.AddQuantizeLinearNode(resize_output, .003f, 1, output_arg, use_contrib_qdq); } }; } template GetQDQTestCaseFn BuildBinaryOpTestCase(const std::vector& input_shape, - const std::string& op_type) { - return [input_shape, op_type](ModelTestBuilder& builder) { + const std::string& op_type, bool use_contrib_qdq = false) { + return [input_shape, op_type, use_contrib_qdq](ModelTestBuilder& builder) { auto* input1_arg = builder.MakeInput(input_shape, -1.f, 1.f); auto* input2_arg = builder.MakeInput(input_shape, -1.f, 1.f); auto* output_arg = builder.MakeOutput(); @@ -529,11 +342,13 @@ GetQDQTestCaseFn BuildBinaryOpTestCase(const std::vector& input_shape, builder.AddQuantizeLinearNode(input1_arg, q_scale, std::numeric_limits::max() / 2, - q1_output); + q1_output, + use_contrib_qdq); builder.AddDequantizeLinearNode(q1_output, op_input_scale, std::numeric_limits::max() / 2, - dq1_output); + dq1_output, + use_contrib_qdq); // add QDQ 2 auto* q2_output = builder.MakeIntermediate(); @@ -541,11 +356,13 @@ GetQDQTestCaseFn BuildBinaryOpTestCase(const std::vector& input_shape, builder.AddQuantizeLinearNode(input2_arg, q_scale, std::numeric_limits::max() / 2, - q2_output); + q2_output, + use_contrib_qdq); builder.AddDequantizeLinearNode(q2_output, op_input_scale, std::numeric_limits::max() / 2, - dq2_output); + dq2_output, + use_contrib_qdq); // add binary operator auto* binary_op_output = builder.MakeIntermediate(); @@ -556,26 +373,29 @@ GetQDQTestCaseFn BuildBinaryOpTestCase(const std::vector& input_shape, builder.AddQuantizeLinearNode(binary_op_output, op_output_scale, std::numeric_limits::max() / 2, - q3_output); + q3_output, + use_contrib_qdq); builder.AddDequantizeLinearNode(q3_output, dq_scale, std::numeric_limits::max() / 2, - output_arg); + output_arg, + use_contrib_qdq); }; } template GetQDQTestCaseFn BuildConsolidationTestCase( const std::vector& input_shape, - const int64_t& axis) { - return [input_shape, axis](ModelTestBuilder& builder) { + const int64_t& axis, + bool use_contrib_qdq = false) { + return [input_shape, axis, use_contrib_qdq](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput(input_shape, std::numeric_limits::min(), std::numeric_limits::max()); InputType dq_zp = std::numeric_limits::max() / 2; OutputType q_zp = std::numeric_limits::max() / 2; auto* upper_dq_output = builder.MakeIntermediate(); auto* upper_q_output = builder.MakeIntermediate(); - builder.AddQuantizeLinearNode(input_arg, .003f, q_zp, upper_q_output); - builder.AddDequantizeLinearNode(upper_q_output, .003f, dq_zp, upper_dq_output); + builder.AddQuantizeLinearNode(input_arg, .003f, q_zp, upper_q_output, use_contrib_qdq); + builder.AddDequantizeLinearNode(upper_q_output, .003f, dq_zp, upper_dq_output, use_contrib_qdq); // add Split @@ -592,21 +412,22 @@ GetQDQTestCaseFn BuildConsolidationTestCase( auto* lower_q_output_1 = builder.MakeIntermediate(); auto* lower_q_output_2 = builder.MakeIntermediate(); auto* lower_q_output_3 = builder.MakeIntermediate(); - builder.AddQuantizeLinearNode(split_output_1, .003f, q_zp, lower_q_output_1); - builder.AddQuantizeLinearNode(split_output_2, .003f, q_zp, lower_q_output_2); - builder.AddQuantizeLinearNode(split_output_3, .003f, q_zp, lower_q_output_3); + builder.AddQuantizeLinearNode(split_output_1, .003f, q_zp, lower_q_output_1, use_contrib_qdq); + builder.AddQuantizeLinearNode(split_output_2, .003f, q_zp, lower_q_output_2, use_contrib_qdq); + builder.AddQuantizeLinearNode(split_output_3, .003f, q_zp, lower_q_output_3, use_contrib_qdq); auto* q_split_output_1 = builder.MakeOutput(); auto* q_split_output_2 = builder.MakeOutput(); auto* q_split_output_3 = builder.MakeOutput(); - builder.AddDequantizeLinearNode(lower_q_output_1, .003f, dq_zp, q_split_output_1); - builder.AddDequantizeLinearNode(lower_q_output_2, .003f, dq_zp, q_split_output_2); - builder.AddDequantizeLinearNode(lower_q_output_3, .003f, dq_zp, q_split_output_3); + builder.AddDequantizeLinearNode(lower_q_output_1, .003f, dq_zp, q_split_output_1, use_contrib_qdq); + builder.AddDequantizeLinearNode(lower_q_output_2, .003f, dq_zp, q_split_output_2, use_contrib_qdq); + builder.AddDequantizeLinearNode(lower_q_output_3, .003f, dq_zp, q_split_output_3, use_contrib_qdq); }; } template GetQDQTestCaseFn BuildDoubleQDQTestCases(Type1 zp_1, Type2 zp_2, Type3 zp_3, Type4 zp_4, - float scale_1, float scale_2, float scale_3, float scale_4) { + float scale_1, float scale_2, float scale_3, float scale_4, + bool use_contrib_qdq = false) { return [=](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput( {11, 22, 33, 44}, @@ -616,15 +437,15 @@ GetQDQTestCaseFn BuildDoubleQDQTestCases(Type1 zp_1, Type2 zp_2, Type3 zp_3, Typ NodeArg* dq1_output = builder.MakeIntermediate(); NodeArg* q2_output = builder.MakeIntermediate(); NodeArg* dq2_output = builder.MakeOutput(); - builder.AddQuantizeLinearNode(input_arg, scale_1, zp_1, q1_output); - builder.AddDequantizeLinearNode(q1_output, scale_2, zp_2, dq1_output); - builder.AddQuantizeLinearNode(dq1_output, scale_3, zp_3, q2_output); - builder.AddDequantizeLinearNode(q2_output, scale_4, zp_4, dq2_output); + builder.AddQuantizeLinearNode(input_arg, scale_1, zp_1, q1_output, use_contrib_qdq); + builder.AddDequantizeLinearNode(q1_output, scale_2, zp_2, dq1_output, use_contrib_qdq); + builder.AddQuantizeLinearNode(dq1_output, scale_3, zp_3, q2_output, use_contrib_qdq); + builder.AddDequantizeLinearNode(q2_output, scale_4, zp_4, dq2_output, use_contrib_qdq); }; } template -GetQDQTestCaseFn BuildDoubleQDQWithoutLastOutput(int output_index) { +GetQDQTestCaseFn BuildDoubleQDQWithoutLastOutput(int output_index, bool use_contrib_qdq = false) { return [=](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput({2, 3, 4}, std::numeric_limits::min(), std::numeric_limits::max()); T zp = (std::numeric_limits::max() - std::numeric_limits::min()) / 2; @@ -637,18 +458,19 @@ GetQDQTestCaseFn BuildDoubleQDQWithoutLastOutput(int output_index) { outputs[i] = builder.MakeIntermediate(); } } - builder.AddQuantizeLinearNode(input_arg, scale, zp, outputs[0]); - builder.AddDequantizeLinearNode(outputs[0], scale, zp, outputs[1]); - builder.AddQuantizeLinearNode(outputs[1], scale, zp, outputs[2]); - builder.AddDequantizeLinearNode(outputs[2], scale, zp, outputs[3]); + builder.AddQuantizeLinearNode(input_arg, scale, zp, outputs[0], use_contrib_qdq); + builder.AddDequantizeLinearNode(outputs[0], scale, zp, outputs[1], use_contrib_qdq); + builder.AddQuantizeLinearNode(outputs[1], scale, zp, outputs[2], use_contrib_qdq); + builder.AddDequantizeLinearNode(outputs[2], scale, zp, outputs[3], use_contrib_qdq); }; } template GetQDQTestCaseFn BuildQDQSplitTestCase( const std::vector& input_shape, - const int64_t& axis) { - return [input_shape, axis](ModelTestBuilder& builder) { + const int64_t& axis, + bool use_contrib_qdq = false) { + return [input_shape, axis, use_contrib_qdq](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput(input_shape, std::numeric_limits::min(), std::numeric_limits::max()); @@ -656,7 +478,7 @@ GetQDQTestCaseFn BuildQDQSplitTestCase( InputType dq_zp = std::numeric_limits::max() / 2; OutputType q_zp = std::numeric_limits::max() / 2; auto* dq_output = builder.MakeIntermediate(); - builder.AddDequantizeLinearNode(input_arg, .003f, dq_zp, dq_output); + builder.AddDequantizeLinearNode(input_arg, .003f, dq_zp, dq_output, use_contrib_qdq); // add Split @@ -673,17 +495,21 @@ GetQDQTestCaseFn BuildQDQSplitTestCase( auto* q_split_output_1 = builder.MakeOutput(); auto* q_split_output_2 = builder.MakeOutput(); auto* q_split_output_3 = builder.MakeOutput(); - builder.AddQuantizeLinearNode(split_output_1, .003f, q_zp, q_split_output_1); // Model input (node_token_1) - builder.AddQuantizeLinearNode(split_output_2, .003f, q_zp, q_split_output_2); // Model input (node_token_2) - builder.AddQuantizeLinearNode(split_output_3, .003f, q_zp, q_split_output_3); + builder.AddQuantizeLinearNode(split_output_1, .003f, q_zp, q_split_output_1, + use_contrib_qdq); // Model input (node_token_1) + builder.AddQuantizeLinearNode(split_output_2, .003f, q_zp, q_split_output_2, + use_contrib_qdq); // Model input (node_token_2) + builder.AddQuantizeLinearNode(split_output_3, .003f, q_zp, q_split_output_3, + use_contrib_qdq); }; } template GetQDQTestCaseFn BuildQDQWhereTestCase( const std::vector& cond_shape, const std::vector& x_shape, - const std::vector& y_shape) { - return [cond_shape, x_shape, y_shape](ModelTestBuilder& builder) { + const std::vector& y_shape, + bool use_contrib_qdq = false) { + return [cond_shape, x_shape, y_shape, use_contrib_qdq](ModelTestBuilder& builder) { auto* input_cond_arg = builder.MakeInputBool(cond_shape); auto* input_x_arg = builder.MakeInput(x_shape, std::numeric_limits::min(), @@ -695,8 +521,8 @@ GetQDQTestCaseFn BuildQDQWhereTestCase( constexpr float scale = 0.003f; auto* dq_x_output = builder.MakeIntermediate(); auto* dq_y_output = builder.MakeIntermediate(); - builder.AddDequantizeLinearNode(input_x_arg, scale, zp, dq_x_output); - builder.AddDequantizeLinearNode(input_y_arg, scale, zp, dq_y_output); + builder.AddDequantizeLinearNode(input_x_arg, scale, zp, dq_x_output, use_contrib_qdq); + builder.AddDequantizeLinearNode(input_y_arg, scale, zp, dq_y_output, use_contrib_qdq); // add Where auto* where_output = builder.MakeIntermediate(); @@ -704,15 +530,17 @@ GetQDQTestCaseFn BuildQDQWhereTestCase( // add Q auto* q_where_output = builder.MakeOutput(); - builder.AddQuantizeLinearNode(where_output, scale, zp, q_where_output); // Model input (node_token_1) + builder.AddQuantizeLinearNode(where_output, scale, zp, q_where_output, + use_contrib_qdq); // Model input (node_token_1) }; } template GetQDQTestCaseFn BuildQDQTransposeTestCase( const std::vector& input_shape, - const std::vector& perms) { - return [input_shape, perms](ModelTestBuilder& builder) { + const std::vector& perms, + bool use_contrib_qdq = false) { + return [input_shape, perms, use_contrib_qdq](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput(input_shape, std::numeric_limits::min(), std::numeric_limits::max()); @@ -723,7 +551,7 @@ GetQDQTestCaseFn BuildQDQTransposeTestCase( // add DQ auto* dq_output = builder.MakeIntermediate(); - builder.AddDequantizeLinearNode(input_arg, .003f, dq_zp, dq_output); + builder.AddDequantizeLinearNode(input_arg, .003f, dq_zp, dq_output, use_contrib_qdq); // add Transpose auto* transpose_output = builder.MakeIntermediate(); @@ -731,7 +559,7 @@ GetQDQTestCaseFn BuildQDQTransposeTestCase( transpose_node.AddAttribute("perm", perms); // add Q - builder.AddQuantizeLinearNode(transpose_output, .003f, q_zp, output_arg); + builder.AddQuantizeLinearNode(transpose_output, .003f, q_zp, output_arg, use_contrib_qdq); }; } @@ -767,7 +595,8 @@ GetQDQTestCaseFn BuildQDQConcatTestCase(const std::vector>& int64_t axis, bool has_input_float = false, bool has_input_int8 = false, - bool has_output_int8 = false); + bool has_output_int8 = false, + bool use_contrib_qdq = false); GetQDQTestCaseFn BuildQDQConcatTestCaseUnsupportedInputScaleZp(); @@ -839,7 +668,7 @@ GetQDQTestCaseFn BuildQDQGemmTestCase(const std::vector& input1_shape, }; } -std::vector GetNodeOpTypesInTopologicalOrder(const Graph& graph); +std::vector GetNodeOpTypesInTopologicalOrder(const Graph& graph, bool include_domain = false); } // namespace test } // namespace onnxruntime diff --git a/onnxruntime/test/optimizer/qdq_transformer_test.cc b/onnxruntime/test/optimizer/qdq_transformer_test.cc index 1f4201836049d..d3616a14d8a5d 100644 --- a/onnxruntime/test/optimizer/qdq_transformer_test.cc +++ b/onnxruntime/test/optimizer/qdq_transformer_test.cc @@ -34,6 +34,18 @@ #include "core/providers/shared/node_unit/node_unit.h" #endif // #ifdef USE_NNAPI +struct QDQOpKeys { + const char* quantize_linear; + const char* dequantize_linear; +}; + +constexpr QDQOpKeys GetQDQOpKeys(bool use_contrib_qdq) { + if (use_contrib_qdq) { + return {"com.microsoft.QuantizeLinear", "com.microsoft.DequantizeLinear"}; + } + return {"QuantizeLinear", "DequantizeLinear"}; +} + namespace onnxruntime { namespace test { @@ -41,25 +53,29 @@ namespace test { template void QDQTransformerConvTests() { - auto test_case = [&](const std::vector& input_shape, const std::vector& weights_shape) { + auto test_case = [&](const std::vector& input_shape, const std::vector& weights_shape, + bool use_contrib_qdq = false) { auto check_graph = [&](InferenceSessionWrapper& session) { + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); + auto op_to_count = CountOpsInGraph(session.GetGraph()); if constexpr (std::is_same::value && std::is_same::value && (std::is_same::value || QDQIsInt8Allowed() && std::is_same::value)) { EXPECT_EQ(op_to_count["QLinearConv"], 1); - EXPECT_EQ(op_to_count["QuantizeLinear"], 1); - EXPECT_EQ(op_to_count["DequantizeLinear"], 1); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 1); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 1); } else { EXPECT_EQ(op_to_count["Conv"], 1); EXPECT_EQ(op_to_count["QLinearConv"], 0); - EXPECT_EQ(op_to_count["QuantizeLinear"], 2); - EXPECT_EQ(op_to_count["DequantizeLinear"], 4); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 2); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 4); } }; - TransformerTester(BuildQDQConvTestCase(input_shape, weights_shape), + TransformerTester(BuildQDQConvTestCase(input_shape, weights_shape, + use_contrib_qdq), check_graph, TransformerLevel::Level1, TransformerLevel::Level2, @@ -67,7 +83,8 @@ void QDQTransformerConvTests() { 0.01 /*per_sample_tolerance*/, 0.01 /*relative_per_sample_tolerance*/, std::make_unique(QDQIsInt8Allowed())); - TransformerTester(BuildQDQConvTestCase(input_shape, weights_shape), + TransformerTester(BuildQDQConvTestCase(input_shape, weights_shape, + use_contrib_qdq), check_graph, TransformerLevel::Level1, TransformerLevel::Level2, @@ -75,6 +92,15 @@ void QDQTransformerConvTests() { 0.01 /*per_sample_tolerance*/, 0.01 /*relative_per_sample_tolerance*/, std::make_unique(QDQIsInt8Allowed())); + TransformerTester(BuildQDQConvTestCase(input_shape, weights_shape, + use_contrib_qdq), + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 19 /*opset_version*/, + 0.01 /*per_sample_tolerance*/, + 0.01 /*relative_per_sample_tolerance*/, + std::make_unique(QDQIsInt8Allowed())); }; test_case({1, 12, 37}, {32, 12, 5}); @@ -83,6 +109,7 @@ void QDQTransformerConvTests() { test_case({1, 23, 13, 13}, {30, 23, 3, 3}); test_case({1, 22, 11, 13, 15}, {30, 22, 5, 3, 3}); test_case({1, 22, 11, 13, 15}, {30, 22, 5, 3, 3}); + test_case({1, 22, 11, 13, 15}, {30, 22, 5, 3, 3}, true); // Use com.microsoft QDQ ops } TEST(QDQTransformerTests, Conv_U8X8U8) { @@ -115,7 +142,8 @@ TEST(QDQTransformerTests, Conv_S8X8S8) { } TEST(QDQTransformerTests, ConvMaxPoolReshape_UInt8) { - auto test_case = [&](const std::vector& input_shape, const std::vector& weights_shape, int opset_version) { + auto test_case = [&](const std::vector& input_shape, const std::vector& weights_shape, + int opset_version, bool use_contrib_qdq = false) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput(input_shape, -1.f, 1.f); auto* output_arg = builder.MakeOutput(); @@ -124,12 +152,12 @@ TEST(QDQTransformerTests, ConvMaxPoolReshape_UInt8) { // add QDQ + Conv auto* dq_w_output = builder.MakeIntermediate(); auto* conv_output = builder.MakeIntermediate(); - auto* dq_conv_output = AddQDQNodePair(builder, input_arg, .004f, 129); - builder.AddDequantizeLinearNode(weight, .003f, 118, dq_w_output); + auto* dq_conv_output = AddQDQNodePair(builder, input_arg, .004f, 129, use_contrib_qdq); + builder.AddDequantizeLinearNode(weight, .003f, 118, dq_w_output, use_contrib_qdq); builder.AddConvNode(dq_conv_output, dq_w_output, conv_output); // add QDQ + MaxPool - auto* dq_maxpool_output = AddQDQNodePair(builder, conv_output, .0039f, 135); + auto* dq_maxpool_output = AddQDQNodePair(builder, conv_output, .0039f, 135, use_contrib_qdq); auto* maxpool_output = builder.MakeIntermediate(); Node& pool_node = builder.AddNode("MaxPool", {dq_maxpool_output}, {maxpool_output}); std::vector pads((weights_shape.size() - 2) * 2, 1); @@ -138,22 +166,23 @@ TEST(QDQTransformerTests, ConvMaxPoolReshape_UInt8) { pool_node.AddAttribute("kernel_shape", kernel_shape); // add QDQ + Reshape - auto* dq_reshape_output = AddQDQNodePair(builder, maxpool_output, .0039f, 135); + auto* dq_reshape_output = AddQDQNodePair(builder, maxpool_output, .0039f, 135, use_contrib_qdq); auto* reshape_shape = builder.Make1DInitializer({-1}); auto* reshape_output = builder.MakeIntermediate(); builder.AddNode("Reshape", {dq_reshape_output, reshape_shape}, {reshape_output}); // add Q - builder.AddQuantizeLinearNode(reshape_output, .0039f, 135, output_arg); + builder.AddQuantizeLinearNode(reshape_output, .0039f, 135, output_arg, use_contrib_qdq); }; auto check_graph = [&](InferenceSessionWrapper& session) { + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); auto op_to_count = CountOpsInGraph(session.GetGraph()); EXPECT_EQ(op_to_count["QLinearConv"], 1); EXPECT_EQ(op_to_count["MaxPool"], 1); EXPECT_EQ(op_to_count["Reshape"], 1); - EXPECT_EQ(op_to_count["QuantizeLinear"], opset_version < 12 ? 2 : 1); - EXPECT_EQ(op_to_count["DequantizeLinear"], opset_version < 12 ? 1 : 0); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], opset_version < 12 ? 2 : 1); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], opset_version < 12 ? 1 : 0); }; TransformerTester(build_test_case, @@ -166,16 +195,26 @@ TEST(QDQTransformerTests, ConvMaxPoolReshape_UInt8) { test_case({1, 12, 37}, {32, 12, 5}, 11); test_case({1, 12, 37}, {32, 12, 5}, 12); test_case({1, 12, 37}, {32, 12, 5}, 18); + test_case({1, 12, 37}, {32, 12, 5}, 19); + test_case({1, 12, 37}, {32, 12, 5}, 11, true); // Use com.microsoft QDQ ops + test_case({1, 23, 13, 13}, {30, 23, 3, 3}, 11); test_case({1, 23, 13, 13}, {30, 23, 3, 3}, 12); test_case({1, 23, 13, 13}, {30, 23, 3, 3}, 18); + test_case({1, 23, 13, 13}, {30, 23, 3, 3}, 19); + test_case({1, 23, 13, 13}, {30, 23, 3, 3}, 12, true); // Use com.microsoft QDQ ops + test_case({1, 22, 11, 13, 15}, {30, 22, 5, 3, 3}, 11); test_case({1, 22, 11, 13, 15}, {30, 22, 5, 3, 3}, 12); test_case({1, 22, 11, 13, 15}, {30, 22, 5, 3, 3}, 18); + test_case({1, 22, 11, 13, 15}, {30, 22, 5, 3, 3}, 19); + test_case({1, 22, 11, 13, 15}, {30, 22, 5, 3, 3}, 18, true); // Use com.microsoft QDQ ops + test_case({1, 22, 11, 13, 15}, {30, 22, 5, 3, 3}, 19, true); // Use com.microsoft QDQ ops } TEST(QDQTransformerTests, ConvMaxPoolReshape_Int8) { - auto test_case = [&](const std::vector& input_shape, const std::vector& weights_shape) { + auto test_case = [&](const std::vector& input_shape, const std::vector& weights_shape, + bool use_contrib_qdq = false) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput(input_shape, -1.f, 1.f); auto* output_arg = builder.MakeOutput(); @@ -184,12 +223,12 @@ TEST(QDQTransformerTests, ConvMaxPoolReshape_Int8) { // add QDQ + Conv auto* dq_w_output = builder.MakeIntermediate(); auto* conv_output = builder.MakeIntermediate(); - auto* dq_conv_output = AddQDQNodePair(builder, input_arg, .004f, 1); - builder.AddDequantizeLinearNode(weight, .003f, -10, dq_w_output); + auto* dq_conv_output = AddQDQNodePair(builder, input_arg, .004f, 1, use_contrib_qdq); + builder.AddDequantizeLinearNode(weight, .003f, -10, dq_w_output, use_contrib_qdq); builder.AddConvNode(dq_conv_output, dq_w_output, conv_output); // add QDQ + MaxPool - auto* dq_maxpool_output = AddQDQNodePair(builder, conv_output, .0039f, 7); + auto* dq_maxpool_output = AddQDQNodePair(builder, conv_output, .0039f, 7, use_contrib_qdq); auto* maxpool_output = builder.MakeIntermediate(); Node& pool_node = builder.AddNode("MaxPool", {dq_maxpool_output}, {maxpool_output}); std::vector pads((weights_shape.size() - 2) * 2, 1); @@ -198,26 +237,27 @@ TEST(QDQTransformerTests, ConvMaxPoolReshape_Int8) { pool_node.AddAttribute("kernel_shape", kernel_shape); // add QDQ + Reshape - auto* dq_reshape_output = AddQDQNodePair(builder, maxpool_output, .0039f, 7); + auto* dq_reshape_output = AddQDQNodePair(builder, maxpool_output, .0039f, 7, use_contrib_qdq); auto* reshape_shape = builder.Make1DInitializer({-1}); auto* reshape_output = builder.MakeIntermediate(); builder.AddNode("Reshape", {dq_reshape_output, reshape_shape}, {reshape_output}); // add Q if constexpr (QDQIsInt8Allowed()) { - builder.AddQuantizeLinearNode(reshape_output, .0039f, 7, output_arg); + builder.AddQuantizeLinearNode(reshape_output, .0039f, 7, output_arg, use_contrib_qdq); } else { - builder.AddQuantizeLinearNode(reshape_output, .0039f, 135, output_arg); + builder.AddQuantizeLinearNode(reshape_output, .0039f, 135, output_arg, use_contrib_qdq); } }; auto check_graph = [&](InferenceSessionWrapper& session) { + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); const std::vector expected_op_types_in_order{ - "QuantizeLinear", + qdq_keys.quantize_linear, "QLinearConv", "MaxPool", "Reshape"}; - const auto op_types_in_order = GetNodeOpTypesInTopologicalOrder(session.GetGraph()); + const auto op_types_in_order = GetNodeOpTypesInTopologicalOrder(session.GetGraph(), true); EXPECT_EQ(op_types_in_order, expected_op_types_in_order); }; @@ -227,75 +267,102 @@ TEST(QDQTransformerTests, ConvMaxPoolReshape_Int8) { test_case({1, 12, 37}, {32, 12, 5}); test_case({1, 23, 13, 13}, {30, 23, 3, 3}); test_case({1, 22, 11, 13, 15}, {30, 22, 5, 3, 3}); + test_case({1, 22, 11, 13, 15}, {30, 22, 5, 3, 3}, true); // Use com.microsoft QDQ ops } #if (defined(_M_AMD64) && !defined(_M_ARM64EC)) || defined(_M_IX86) || defined(__x86_64__) || defined(__i386__) || !defined(DISABLE_CONTRIB_OPS) TEST(QDQTransformerTests, DQ_S8_to_U8) { - const std::vector& input_shape = {19, 37}; - const std::vector& weights_shape = {37, 23}; + auto test_case = [](bool use_contrib_qdq) { + const std::vector& input_shape = {19, 37}; + const std::vector& weights_shape = {37, 23}; - auto build_test_case = [&](ModelTestBuilder& builder) { - auto* input1_arg = builder.MakeInput(input_shape, -1.f, 1.f); + auto build_test_case = [&](ModelTestBuilder& builder) { + auto* input1_arg = builder.MakeInput(input_shape, -1.f, 1.f); - // Use full range weight values to expose avx2 u8s8 overflow problems - auto* weight = builder.MakeInitializer(weights_shape, -128, 127); - auto* output_arg = builder.MakeOutput(); + // Use full range weight values to expose avx2 u8s8 overflow problems + auto* weight = builder.MakeInitializer(weights_shape, -128, 127); + auto* output_arg = builder.MakeOutput(); - // add QDQ activation - typedef std::numeric_limits Input1Limits; - auto* dq1_output = AddQDQNodePair(builder, input1_arg, .039f, (int8_t)((Input1Limits::max() + Input1Limits::min()) / 2 + 1)); + // add QDQ activation + typedef std::numeric_limits Input1Limits; + auto* dq1_output = AddQDQNodePair(builder, input1_arg, .039f, + (int8_t)((Input1Limits::max() + Input1Limits::min()) / 2 + 1), + use_contrib_qdq); - // add DQ weight - auto* dq_w_output = builder.MakeIntermediate(); - builder.AddDequantizeLinearNode(weight, .003f, -10, dq_w_output); + // add DQ weight + auto* dq_w_output = builder.MakeIntermediate(); + builder.AddDequantizeLinearNode(weight, .003f, -10, dq_w_output, use_contrib_qdq); - builder.AddNode("MatMul", {dq1_output, dq_w_output}, {output_arg}); - }; + builder.AddNode("MatMul", {dq1_output, dq_w_output}, {output_arg}); + }; - auto check_graph = [&](InferenceSessionWrapper& session) { - auto op_to_count = CountOpsInGraph(session.GetGraph()); - EXPECT_EQ(op_to_count["com.microsoft.MatMulIntegerToFloat"], 1); - EXPECT_EQ(op_to_count["MatMul"], 0); - EXPECT_EQ(op_to_count["QuantizeLinear"], 1); - EXPECT_EQ(op_to_count["DequantizeLinear"], 0); - }; + auto check_graph = [&](InferenceSessionWrapper& session) { + auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); + EXPECT_EQ(op_to_count["com.microsoft.MatMulIntegerToFloat"], 1); + EXPECT_EQ(op_to_count["MatMul"], 0); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 1); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 0); + }; - auto add_session_options = [&](SessionOptions& so) { - ASSERT_STATUS_OK(so.config_options.AddConfigEntry( - kOrtSessionOptionsAvx2PrecisionMode, "1")); + auto add_session_options = [&](SessionOptions& so) { + ASSERT_STATUS_OK(so.config_options.AddConfigEntry( + kOrtSessionOptionsAvx2PrecisionMode, "1")); + }; + + TransformerTester(build_test_case, + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 12 /*opset_version*/, + 0.01 /*per_sample_tolerance*/, + 0.01 /*relative_per_sample_tolerance*/, + nullptr, add_session_options); + TransformerTester(build_test_case, + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 18 /*opset_version*/, + 0.01 /*per_sample_tolerance*/, + 0.01 /*relative_per_sample_tolerance*/, + nullptr, add_session_options); + TransformerTester(build_test_case, + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 19 /*opset_version*/, + 0.01 /*per_sample_tolerance*/, + 0.01 /*relative_per_sample_tolerance*/, + nullptr, add_session_options); }; - TransformerTester(build_test_case, - check_graph, - TransformerLevel::Level1, - TransformerLevel::Level2, - 12 /*opset_version*/, - 0.01 /*per_sample_tolerance*/, - 0.01 /*relative_per_sample_tolerance*/, - nullptr, add_session_options); + test_case(false); // Use ONNX QDQ ops + test_case(true); // Use com.microsoft QDQ ops } #endif // Only for X64 with contrib ops enabled template void QDQTransformerAveragePoolTests() { - auto test_case = [&](const std::vector& input_shape) { + auto test_case = [&](const std::vector& input_shape, bool use_contrib_qdq = false) { auto check_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); if constexpr (std::is_same::value) { EXPECT_EQ(op_to_count["com.microsoft.QLinearAveragePool"], 1); EXPECT_EQ(op_to_count["AveragePool"], 0); - EXPECT_EQ(op_to_count["QuantizeLinear"], 1); - EXPECT_EQ(op_to_count["DequantizeLinear"], 1); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 1); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 1); } else { EXPECT_EQ(op_to_count["com.microsoft.QLinearAveragePool"], 0); EXPECT_EQ(op_to_count["AveragePool"], 1); - EXPECT_EQ(op_to_count["QuantizeLinear"], 2); - EXPECT_EQ(op_to_count["DequantizeLinear"], 2); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 2); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 2); } }; - TransformerTester(BuildQDQAveragePoolTestCase(input_shape), + TransformerTester(BuildQDQAveragePoolTestCase(input_shape, 0 /*count_include_pad*/, + use_contrib_qdq), check_graph, TransformerLevel::Level1, TransformerLevel::Level2, @@ -303,7 +370,8 @@ void QDQTransformerAveragePoolTests() { 0.01 /*per_sample_tolerance*/, 0.01 /*relative_per_sample_tolerance*/, std::make_unique(QDQIsInt8Allowed())); - TransformerTester(BuildQDQAveragePoolTestCase(input_shape), + TransformerTester(BuildQDQAveragePoolTestCase(input_shape, 0 /*count_include_pad*/, + use_contrib_qdq), check_graph, TransformerLevel::Level1, TransformerLevel::Level2, @@ -311,11 +379,13 @@ void QDQTransformerAveragePoolTests() { 0.01 /*per_sample_tolerance*/, 0.01 /*relative_per_sample_tolerance*/, std::make_unique(QDQIsInt8Allowed())); + // TODO: fix opset 19 }; test_case({1, 12, 37}); test_case({1, 23, 13, 13}); test_case({1, 22, 11, 13, 15}); + test_case({1, 12, 37}, true); // Use com.microsoft QDQ ops } TEST(QDQTransformerTests, AveragePool_S8S8) { @@ -336,23 +406,24 @@ TEST(QDQTransformerTests, AveragePool_U8S8) { template void QDQTransformerGlobalAveragePoolTests() { - auto test_case = [&](const std::vector& input_shape) { + auto test_case = [&](const std::vector& input_shape, bool use_contrib_qdq = false) { auto check_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); if constexpr (std::is_same::value) { EXPECT_EQ(op_to_count["com.microsoft.QLinearGlobalAveragePool"], 1); EXPECT_EQ(op_to_count["GlobalAveragePool"], 0); - EXPECT_EQ(op_to_count["QuantizeLinear"], 1); - EXPECT_EQ(op_to_count["DequantizeLinear"], 1); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 1); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 1); } else { EXPECT_EQ(op_to_count["com.microsoft.QLinearGlobalAveragePool"], 0); EXPECT_EQ(op_to_count["GlobalAveragePool"], 1); - EXPECT_EQ(op_to_count["QuantizeLinear"], 2); - EXPECT_EQ(op_to_count["DequantizeLinear"], 2); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 2); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 2); } }; - TransformerTester(BuildQDQGlobalAveragePoolTestCase(input_shape), + TransformerTester(BuildQDQGlobalAveragePoolTestCase(input_shape, use_contrib_qdq), check_graph, TransformerLevel::Level1, TransformerLevel::Level2, @@ -360,7 +431,7 @@ void QDQTransformerGlobalAveragePoolTests() { 0.01 /*per_sample_tolerance*/, 0.01 /*relative_per_sample_tolerance*/, std::make_unique(QDQIsInt8Allowed())); - TransformerTester(BuildQDQGlobalAveragePoolTestCase(input_shape), + TransformerTester(BuildQDQGlobalAveragePoolTestCase(input_shape, use_contrib_qdq), check_graph, TransformerLevel::Level1, TransformerLevel::Level2, @@ -368,11 +439,13 @@ void QDQTransformerGlobalAveragePoolTests() { 0.01 /*per_sample_tolerance*/, 0.01 /*relative_per_sample_tolerance*/, std::make_unique(QDQIsInt8Allowed())); + // TODO: fix opset 19 }; test_case({1, 12, 37}); test_case({1, 23, 13, 13}); test_case({1, 22, 11, 13, 15}); + test_case({1, 12, 37}, true); // Use com.microsoft QDQ ops } TEST(QDQTransformerTests, GlobalAveragePool_S8S8) { @@ -393,24 +466,25 @@ TEST(QDQTransformerTests, GlobalAveragePool_U8S8) { template void QDQTransformerBinaryOpTests(const std::string& op_type) { - auto test_case = [&](const std::vector& input_shape) { + auto test_case = [&](const std::vector& input_shape, bool use_contrib_qdq = false) { auto check_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); if (std::is_same::value && std::is_same::value) { EXPECT_EQ(op_to_count["com.microsoft.QLinear" + op_type], 1); EXPECT_EQ(op_to_count[op_type], 0); - EXPECT_EQ(op_to_count["QuantizeLinear"], 2); - EXPECT_EQ(op_to_count["DequantizeLinear"], 1); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 2); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 1); } else { EXPECT_EQ(op_to_count["com.microsoft.QLinear" + op_type], 0); EXPECT_EQ(op_to_count[op_type], 1); - EXPECT_EQ(op_to_count["QuantizeLinear"], 3); - EXPECT_EQ(op_to_count["DequantizeLinear"], 3); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 3); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 3); } }; - TransformerTester(BuildBinaryOpTestCase(input_shape, op_type), + TransformerTester(BuildBinaryOpTestCase(input_shape, op_type, use_contrib_qdq), check_graph, TransformerLevel::Level1, TransformerLevel::Level2, @@ -418,7 +492,7 @@ void QDQTransformerBinaryOpTests(const std::string& op_type) { 0.01 /*per_sample_tolerance*/, 0.01 /*relative_per_sample_tolerance*/, std::make_unique(QDQIsInt8Allowed())); - TransformerTester(BuildBinaryOpTestCase(input_shape, op_type), + TransformerTester(BuildBinaryOpTestCase(input_shape, op_type, use_contrib_qdq), check_graph, TransformerLevel::Level1, TransformerLevel::Level2, @@ -426,11 +500,20 @@ void QDQTransformerBinaryOpTests(const std::string& op_type) { 0.01 /*per_sample_tolerance*/, 0.01 /*relative_per_sample_tolerance*/, std::make_unique(QDQIsInt8Allowed())); + TransformerTester(BuildBinaryOpTestCase(input_shape, op_type, use_contrib_qdq), + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 19 /*opset_version*/, + 0.01 /*per_sample_tolerance*/, + 0.01 /*relative_per_sample_tolerance*/, + std::make_unique(QDQIsInt8Allowed())); }; test_case({1, 12, 37}); test_case({1, 23, 13, 13}); test_case({1, 22, 11, 13, 15}); + test_case({1, 12, 37}, true); // Use com.microsoft QDQ ops } TEST(QDQTransformerTests, Add) { @@ -463,7 +546,8 @@ TEST(QDQTransformerTests, Mul_Have_Different_Types) { template void QDQTransformerMatMulTests(bool has_output_q) { - auto test_case = [&](const std::vector& input1_shape, const std::vector& input2_shape) { + auto test_case = [&](const std::vector& input1_shape, const std::vector& input2_shape, + bool use_contrib_qdq = false) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input1_arg = builder.MakeInput(input1_shape, -1.f, 1.f); auto* input2_arg = builder.MakeInput(input2_shape, -1.f, 1.f); @@ -479,11 +563,11 @@ void QDQTransformerMatMulTests(bool has_output_q) { builder.AddQuantizeLinearNode(input1_arg, .039f, (Input1Limits::max() + Input1Limits::min()) / 2 + 1, - q1_output); + q1_output, use_contrib_qdq); builder.AddDequantizeLinearNode(q1_output, .039f, (Input2Limits::max() + Input1Limits::min()) / 2 + 1, - dq1_output); + dq1_output, use_contrib_qdq); // add QDQ 2 auto* q2_output = builder.MakeIntermediate(); @@ -491,11 +575,11 @@ void QDQTransformerMatMulTests(bool has_output_q) { builder.AddQuantizeLinearNode(input2_arg, .04f, (Input2Limits::max() + Input2Limits::min()) / 2 + 1, - q2_output); + q2_output, use_contrib_qdq); builder.AddDequantizeLinearNode(q2_output, .04f, (Input2Limits::max() + Input2Limits::min()) / 2 + 1, - dq2_output); + dq2_output, use_contrib_qdq); if (has_output_q) { // add binary operator @@ -507,11 +591,11 @@ void QDQTransformerMatMulTests(bool has_output_q) { builder.AddQuantizeLinearNode(matmul_op_output, .039f, (OutputTypeLimits::max() + OutputTypeLimits::min()) / 2 + 1, - q3_output); + q3_output, use_contrib_qdq); builder.AddDequantizeLinearNode(q3_output, .039f, (OutputTypeLimits::max() + OutputTypeLimits::min()) / 2 + 1, - output_arg); + output_arg, use_contrib_qdq); } else { builder.AddNode("MatMul", {dq1_output, dq2_output}, {output_arg}); } @@ -519,32 +603,33 @@ void QDQTransformerMatMulTests(bool has_output_q) { auto check_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); if (has_output_q) { if constexpr (std::is_same::value && (std::is_same::value || QDQIsInt8Allowed() && std::is_same::value)) { EXPECT_EQ(op_to_count["QLinearMatMul"], 1); EXPECT_EQ(op_to_count["MatMul"], 0); - EXPECT_EQ(op_to_count["QuantizeLinear"], 2); - EXPECT_EQ(op_to_count["DequantizeLinear"], 1); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 2); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 1); } else { EXPECT_EQ(op_to_count["QLinearMatMul"], 0); EXPECT_EQ(op_to_count["MatMul"], 1); - EXPECT_EQ(op_to_count["QuantizeLinear"], 3); - EXPECT_EQ(op_to_count["DequantizeLinear"], 3); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 3); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 3); } } else { if constexpr (std::is_same::value || (QDQIsInt8Allowed() && std::is_same::value)) { EXPECT_EQ(op_to_count["com.microsoft.MatMulIntegerToFloat"], 1); EXPECT_EQ(op_to_count["MatMul"], 0); - EXPECT_EQ(op_to_count["QuantizeLinear"], 2); - EXPECT_EQ(op_to_count["DequantizeLinear"], 0); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 2); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 0); } else { EXPECT_EQ(op_to_count["com.microsoft.MatMulIntegerToFloat"], 0); EXPECT_EQ(op_to_count["MatMul"], 1); - EXPECT_EQ(op_to_count["QuantizeLinear"], 2); - EXPECT_EQ(op_to_count["DequantizeLinear"], 2); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 2); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 2); } } }; @@ -565,11 +650,20 @@ void QDQTransformerMatMulTests(bool has_output_q) { 0.01 /*per_sample_tolerance*/, 0.01 /*relative_per_sample_tolerance*/, std::make_unique(QDQIsInt8Allowed())); + TransformerTester(build_test_case, + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 19 /*opset_version*/, + 0.01 /*per_sample_tolerance*/, + 0.01 /*relative_per_sample_tolerance*/, + std::make_unique(QDQIsInt8Allowed())); }; test_case({1, 2, 2}, {1, 2, 4}); test_case({1, 23, 13, 13}, {13, 13}); test_case({1, 22, 11, 13, 15}, {1, 22, 11, 15, 15}); + test_case({1, 2, 2}, {1, 2, 4}, true); // Use com.microsoft QDQ ops } TEST(QDQTransformerTests, MatMul_U8U8U8) { @@ -614,7 +708,8 @@ TEST(QDQTransformerTests, MatMul_S8S8U8) { template void QDQTransformerGemmTests(bool has_output_q, bool has_bias, bool beta_not_one = false) { - auto test_case = [&](const std::vector& input1_shape, const std::vector& input2_shape) { + auto test_case = [&](const std::vector& input1_shape, const std::vector& input2_shape, + bool use_contrib_qdq = false) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input1_arg = builder.MakeInput(input1_shape, -1.f, 1.f); auto* input2_arg = builder.MakeInput(input2_shape, -1.f, 1.f); @@ -632,11 +727,11 @@ void QDQTransformerGemmTests(bool has_output_q, bool has_bias, bool beta_not_one builder.AddQuantizeLinearNode(input1_arg, .039f, (Input1Limits::max() + Input1Limits::min()) / 2 + 1, - q1_output); + q1_output, use_contrib_qdq); builder.AddDequantizeLinearNode(q1_output, .039f, (Input2Limits::max() + Input1Limits::min()) / 2 + 1, - dq1_output); + dq1_output, use_contrib_qdq); input_args.push_back(dq1_output); @@ -646,11 +741,11 @@ void QDQTransformerGemmTests(bool has_output_q, bool has_bias, bool beta_not_one builder.AddQuantizeLinearNode(input2_arg, .04f, (Input2Limits::max() + Input2Limits::min()) / 2 + 1, - q2_output); + q2_output, use_contrib_qdq); builder.AddDequantizeLinearNode(q2_output, .04f, (Input2Limits::max() + Input2Limits::min()) / 2 + 1, - dq2_output); + dq2_output, use_contrib_qdq); input_args.push_back(dq2_output); if (has_bias) { @@ -658,7 +753,7 @@ void QDQTransformerGemmTests(bool has_output_q, bool has_bias, bool beta_not_one auto* bias = builder.MakeInitializer({input2_shape[1]}, static_cast(0), static_cast(127)); builder.AddDequantizeLinearNode(bias, 0.00156f, 0, - dq_bias_output); + dq_bias_output, use_contrib_qdq); input_args.push_back(dq_bias_output); } @@ -673,11 +768,11 @@ void QDQTransformerGemmTests(bool has_output_q, bool has_bias, bool beta_not_one builder.AddQuantizeLinearNode(gemm_op_output, .039f, (OutputTypeLimits::max() + OutputTypeLimits::min()) / 2 + 1, - q3_output); + q3_output, use_contrib_qdq); builder.AddDequantizeLinearNode(q3_output, .039f, (OutputTypeLimits::max() + OutputTypeLimits::min()) / 2 + 1, - output_arg); + output_arg, use_contrib_qdq); } else { gemm_node = &builder.AddNode("Gemm", input_args, {output_arg}); } @@ -689,12 +784,13 @@ void QDQTransformerGemmTests(bool has_output_q, bool has_bias, bool beta_not_one auto check_binary_op_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); if ((!has_output_q || std::is_same_v)&&(!has_bias || (std::is_same_v && !beta_not_one)) && (std::is_same_v || std::is_same_v)) { EXPECT_EQ(op_to_count["com.microsoft.QGemm"], 1); EXPECT_EQ(op_to_count["Gemm"], 0); - EXPECT_EQ(op_to_count["QuantizeLinear"], 2); - EXPECT_EQ(op_to_count["DequantizeLinear"], has_output_q ? 1 : 0); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 2); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], has_output_q ? 1 : 0); } else { int q_count = 2; // Q for A and B int dq_count = 2; // DQ for A and B @@ -707,8 +803,8 @@ void QDQTransformerGemmTests(bool has_output_q, bool has_bias, bool beta_not_one } EXPECT_EQ(op_to_count["com.microsoft.QGemm"], 0); EXPECT_EQ(op_to_count["Gemm"], 1); - EXPECT_EQ(op_to_count["QuantizeLinear"], q_count); - EXPECT_EQ(op_to_count["DequantizeLinear"], dq_count); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], q_count); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], dq_count); } }; @@ -728,10 +824,19 @@ void QDQTransformerGemmTests(bool has_output_q, bool has_bias, bool beta_not_one 0.01 /*per_sample_tolerance*/, 0.01 /*relative_per_sample_tolerance*/, std::make_unique(QDQIsInt8Allowed())); + TransformerTester(build_test_case, + check_binary_op_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 19 /*opset_version*/, + 0.01 /*per_sample_tolerance*/, + 0.01 /*relative_per_sample_tolerance*/, + std::make_unique(QDQIsInt8Allowed())); }; test_case({2, 2}, {2, 4}); test_case({13, 15}, {15, 15}); + test_case({2, 2}, {2, 4}, true); // Use com.microsoft QDQ ops } template @@ -786,34 +891,139 @@ TEST(QDQTransformerTests, Gemm_S8S8U8) { QDQTransformerGemmTests(); } +// Runs a test case that checks if Q/DQ nodes are dropped from DQ -> Gather -> Q. +template +static void RunGatherDropQDQTestCase(const std::vector& input1_shape, + const std::vector& weights_shape, + bool use_contrib_qdq = false) { + auto build_test_case = [input1_shape, weights_shape, use_contrib_qdq](ModelTestBuilder& builder) { + auto* input1_arg = builder.MakeInput(input1_shape, 0, weights_shape[0] - 1); + auto* output_arg = builder.MakeOutput(); + + // add Gather + auto* weight = builder.MakeInitializer(weights_shape, std::numeric_limits::min(), + std::numeric_limits::max()); + auto* dq_w_output = builder.MakeIntermediate(); + auto* gather_output = builder.MakeIntermediate(); + builder.AddDequantizeLinearNode(weight, .003f, 1, dq_w_output, use_contrib_qdq); + builder.AddNode("Gather", {dq_w_output, input1_arg}, {gather_output}); + + // add Q + builder.AddQuantizeLinearNode(gather_output, .003f, 1, output_arg, use_contrib_qdq); + }; + + auto check_graph = [use_contrib_qdq](InferenceSessionWrapper& session) { + auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); + EXPECT_EQ(op_to_count["Gather"], 1); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 0); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 0); + }; + + TransformerTester(build_test_case, check_graph, TransformerLevel::Level1, TransformerLevel::Level2); +} + +// Checks that Q/DQ nodes are dropped from DQ -> Gather -> Q. Uses 8-bit and 16-bit Q/DQ ops. TEST(QDQTransformerTests, Gather) { - auto test_case = [&](const std::vector& input1_shape, const std::vector& weights_shape) { - auto build_test_case = [&](ModelTestBuilder& builder) { - auto* input1_arg = builder.MakeInput(input1_shape, 0, weights_shape[0] - 1); - auto* output_arg = builder.MakeOutput(); + RunGatherDropQDQTestCase({12, 37}, {24, 12}); + RunGatherDropQDQTestCase({12, 37}, {24, 12}, true); // Use com.microsoft QDQ ops + RunGatherDropQDQTestCase({12, 37}, {24, 12}, true); // Use int16 com.microsoft QDQ ops +} - // add Gather - auto* weight = builder.MakeInitializer(weights_shape, -128, 127); - auto* dq_w_output = builder.MakeIntermediate(); - auto* gather_output = builder.MakeIntermediate(); - builder.AddDequantizeLinearNode(weight, .003f, 1, dq_w_output); - builder.AddNode("Gather", {dq_w_output, input1_arg}, {gather_output}); +// Runs a test case that checks if Q/DQ nodes are dropped from DQ -> Reshape -> Q. +template +static void RunReshapeDropQDQTestCase(const std::vector& input_shape, + const std::vector& new_shape, + bool use_contrib_qdq = false) { + auto build_test_case = [input_shape, new_shape, use_contrib_qdq](ModelTestBuilder& builder) { + constexpr QuantType qmin = std::numeric_limits::min(); + constexpr QuantType qmax = std::numeric_limits::max(); - // add Q - builder.AddQuantizeLinearNode(gather_output, .003f, 1, output_arg); - }; + auto* input_arg = builder.MakeInput(input_shape, qmin, qmax); + auto* output_arg = builder.MakeOutput(); + QuantType zero_point = 1 + (qmax + qmin) / 2; - auto check_graph = [&](InferenceSessionWrapper& session) { - auto op_to_count = CountOpsInGraph(session.GetGraph()); - EXPECT_EQ(op_to_count["Gather"], 1); - EXPECT_EQ(op_to_count["QuantizeLinear"], 0); - EXPECT_EQ(op_to_count["DequantizeLinear"], 0); - }; + // Add Reshape node + auto* new_shape_arg = builder.Make1DInitializer(new_shape); + auto* input_arg_dq = builder.MakeIntermediate(); + auto* reshape_output = builder.MakeIntermediate(); + builder.AddDequantizeLinearNode(input_arg, .003f, zero_point, input_arg_dq, use_contrib_qdq); + builder.AddNode("Reshape", {input_arg_dq, new_shape_arg}, {reshape_output}); - TransformerTester(build_test_case, check_graph, TransformerLevel::Level1, TransformerLevel::Level2); + // add Q + builder.AddQuantizeLinearNode(reshape_output, .003f, zero_point, output_arg, use_contrib_qdq); + }; + + auto check_graph = [use_contrib_qdq](InferenceSessionWrapper& session) { + auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); + EXPECT_EQ(op_to_count["Reshape"], 1); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 0); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 0); }; - test_case({12, 37}, {24, 12}); + TransformerTester(build_test_case, check_graph, TransformerLevel::Level1, TransformerLevel::Level2); +} + +// Checks that Q/DQ nodes are dropped from DQ -> Reshape -> Q. Uses 8-bit and 16-bit Q/DQ ops. +TEST(QDQTransformerTests, ReshapeDropQDQ) { + RunReshapeDropQDQTestCase({1, 3, 2, 2}, {1, 12}); + RunReshapeDropQDQTestCase({1, 3, 2, 2}, {1, 12}, true); // Use com.microsoft QDQ ops + RunReshapeDropQDQTestCase({1, 3, 2, 2}, {1, 12}, true); // Use int16 com.microsoft QDQ ops + RunReshapeDropQDQTestCase({1, 3, 2, 2}, {1, 12}, true); // Use int16 com.microsoft QDQ ops +} + +// Runs a test case that checks if Q/DQ nodes are dropped from DQ -> (Un)Squeeze -> Q. +template +static void RunSqueezeUnsqueezeDropQDQTestCase(const std::string& squeeze_type, + const std::vector& input_shape, + const std::vector& axes, + bool use_contrib_qdq = false) { + auto build_test_case = [squeeze_type, input_shape, axes, use_contrib_qdq](ModelTestBuilder& builder) { + constexpr QuantType qmin = std::numeric_limits::min(); + constexpr QuantType qmax = std::numeric_limits::max(); + + auto* input_arg = builder.MakeInput(input_shape, qmin, qmax); + auto* output_arg = builder.MakeOutput(); + QuantType zero_point = 1 + (qmax + qmin) / 2; + + // Add Squeeze node + auto* axes_arg = builder.Make1DInitializer(axes); + auto* input_arg_dq = builder.MakeIntermediate(); + auto* xsqueeze_output = builder.MakeIntermediate(); + builder.AddDequantizeLinearNode(input_arg, .003f, zero_point, input_arg_dq, use_contrib_qdq); + builder.AddNode(squeeze_type, {input_arg_dq, axes_arg}, {xsqueeze_output}); + + // add Q + builder.AddQuantizeLinearNode(xsqueeze_output, .003f, zero_point, output_arg, use_contrib_qdq); + }; + + auto check_graph = [squeeze_type, use_contrib_qdq](InferenceSessionWrapper& session) { + auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); + EXPECT_EQ(op_to_count[squeeze_type], 1); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 0); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 0); + }; + + TransformerTester(build_test_case, check_graph, TransformerLevel::Level1, TransformerLevel::Level2, + 13 /* opset_version */); +} + +// Checks that Q/DQ nodes are dropped from DQ -> Squeeze -> Q. Uses 8-bit and 16-bit Q/DQ ops. +TEST(QDQTransformerTests, SqueezeDropQDQ) { + RunSqueezeUnsqueezeDropQDQTestCase("Squeeze", {1, 3, 2, 2}, {0}); + RunSqueezeUnsqueezeDropQDQTestCase("Squeeze", {1, 3, 2, 2}, {0}, true); // Use MS domain QDQ ops + RunSqueezeUnsqueezeDropQDQTestCase("Squeeze", {1, 3, 2, 2}, {0}, true); // Use int16 MS domain QDQ ops + RunSqueezeUnsqueezeDropQDQTestCase("Squeeze", {1, 3, 2, 2}, {0}, true); // Use int16 MS domain QDQ ops +} + +// Checks that Q/DQ nodes are dropped from DQ -> Unsqueeze -> Q. Uses 8-bit and 16-bit Q/DQ ops. +TEST(QDQTransformerTests, UnsqueezeDropQDQ) { + RunSqueezeUnsqueezeDropQDQTestCase("Unsqueeze", {1, 3, 2, 2}, {0}); + RunSqueezeUnsqueezeDropQDQTestCase("Unsqueeze", {1, 3, 2, 2}, {0}, true); // Use MS domain QDQ ops + RunSqueezeUnsqueezeDropQDQTestCase("Unsqueeze", {1, 3, 2, 2}, {0}, true); // Use int16 MS domain QDQ ops + RunSqueezeUnsqueezeDropQDQTestCase("Unsqueeze", {1, 3, 2, 2}, {0}, true); // Use int16 MS domain QDQ ops } TEST(QDQTransformerTests, DoubleQDQ) { @@ -829,23 +1039,33 @@ TEST(QDQTransformerTests, DoubleQDQ) { constexpr float good_float_point_2 = 8.0f; constexpr float bad_float_point = 1.11f; - std::function expect_succeed = [&](InferenceSessionWrapper& session) { - auto op_to_count = CountOpsInGraph(session.GetGraph()); - EXPECT_EQ(op_to_count["QuantizeLinear"], 1); - EXPECT_EQ(op_to_count["DequantizeLinear"], 1); + auto expect_succeed = [](bool use_contrib_qdq) -> std::function { + return [use_contrib_qdq](InferenceSessionWrapper& session) { + auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 1); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 1); + }; }; - std::function expect_fail = [&](InferenceSessionWrapper& session) { - auto op_to_count = CountOpsInGraph(session.GetGraph()); - EXPECT_EQ(op_to_count["QuantizeLinear"], 2); - EXPECT_EQ(op_to_count["DequantizeLinear"], 2); + + auto expect_fail = [](bool use_contrib_qdq) -> std::function { + return [use_contrib_qdq](InferenceSessionWrapper& session) { + auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 2); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 2); + }; }; auto test_case_all_u8 = [&](bool succeed, uint8_t zp_1, uint8_t zp_2, uint8_t zp_3, uint8_t zp_4, - float scale_1, float scale_2, float scale_3, float scale_4) { + float scale_1, float scale_2, float scale_3, float scale_4, + bool use_contrib_qdq = false) { TransformerTester( - BuildDoubleQDQTestCases(zp_1, zp_2, zp_3, zp_4, scale_1, scale_2, scale_3, scale_4), - succeed ? expect_succeed : expect_fail, + BuildDoubleQDQTestCases(zp_1, zp_2, zp_3, zp_4, + scale_1, scale_2, scale_3, scale_4, + use_contrib_qdq), + succeed ? expect_succeed(use_contrib_qdq) : expect_fail(use_contrib_qdq), TransformerLevel::Default, TransformerLevel::Level1, 12, @@ -855,197 +1075,305 @@ TEST(QDQTransformerTests, DoubleQDQ) { auto test_case_all_s8 = [&](bool succeed, int8_t zp_1, int8_t zp_2, int8_t zp_3, int8_t zp_4, - float scale_1, float scale_2, float scale_3, float scale_4) { + float scale_1, float scale_2, float scale_3, float scale_4, + bool use_contrib_qdq = false) { TransformerTester( - BuildDoubleQDQTestCases(zp_1, zp_2, zp_3, zp_4, scale_1, scale_2, scale_3, scale_4), - succeed ? expect_succeed : expect_fail, + BuildDoubleQDQTestCases(zp_1, zp_2, zp_3, zp_4, + scale_1, scale_2, scale_3, scale_4, + use_contrib_qdq), + succeed ? expect_succeed(use_contrib_qdq) : expect_fail(use_contrib_qdq), TransformerLevel::Default, TransformerLevel::Level1, 12, (scale_1 + scale_3) / 2, 0.01); TransformerTester( - BuildDoubleQDQTestCases(zp_1, zp_2, zp_3, zp_4, scale_1, scale_2, scale_3, scale_4), - succeed ? expect_succeed : expect_fail, + BuildDoubleQDQTestCases(zp_1, zp_2, zp_3, zp_4, + scale_1, scale_2, scale_3, scale_4, + use_contrib_qdq), + succeed ? expect_succeed(use_contrib_qdq) : expect_fail(use_contrib_qdq), TransformerLevel::Default, TransformerLevel::Level1, 18, (scale_1 + scale_3) / 2, 0.01); + TransformerTester( + BuildDoubleQDQTestCases(zp_1, zp_2, zp_3, zp_4, + scale_1, scale_2, scale_3, scale_4, + use_contrib_qdq), + succeed ? expect_succeed(use_contrib_qdq) : expect_fail(use_contrib_qdq), + TransformerLevel::Default, + TransformerLevel::Level1, + 19, + (scale_1 + scale_3) / 2, + 0.01); }; auto test_case_2u8_2s8_failed = [&](uint8_t zp_1, uint8_t zp_2, int8_t zp_3, int8_t zp_4, - float scale_1, float scale_2, float scale_3, float scale_4) { + float scale_1, float scale_2, float scale_3, float scale_4, + bool use_contrib_qdq = false) { TransformerTester( - BuildDoubleQDQTestCases(zp_1, zp_2, zp_3, zp_4, scale_1, scale_2, scale_3, scale_4), - expect_fail, + BuildDoubleQDQTestCases(zp_1, zp_2, zp_3, zp_4, + scale_1, scale_2, scale_3, scale_4, + use_contrib_qdq), + expect_fail(use_contrib_qdq), TransformerLevel::Default, TransformerLevel::Level1); }; // all unsigned type - test_case_all_u8(true, good_u8_1, good_u8_1, good_u8_2, good_u8_2, good_float_point_1, good_float_point_1, good_float_point_2, good_float_point_2); + test_case_all_u8(true, good_u8_1, good_u8_1, good_u8_2, good_u8_2, good_float_point_1, good_float_point_1, + good_float_point_2, good_float_point_2); + test_case_all_u8(true, good_u8_1, good_u8_1, good_u8_2, good_u8_2, good_float_point_1, good_float_point_1, + good_float_point_2, good_float_point_2, true); // Use com.microsoft QDQ ops + // all signed type - test_case_all_s8(true, good_s8_1, good_s8_1, good_s8_2, good_s8_2, good_float_point_1, good_float_point_1, good_float_point_2, good_float_point_2); + test_case_all_s8(true, good_s8_1, good_s8_1, good_s8_2, good_s8_2, good_float_point_1, good_float_point_1, + good_float_point_2, good_float_point_2); + test_case_all_s8(true, good_s8_1, good_s8_1, good_s8_2, good_s8_2, good_float_point_1, good_float_point_1, + good_float_point_2, good_float_point_2, true); // Use com.microsoft QDQ ops + // 2 signed, 2 unsigned - test_case_2u8_2s8_failed(good_u8_1, good_u8_1, good_s8_2, good_s8_2, good_float_point_1, good_float_point_1, good_float_point_2, good_float_point_2); + test_case_2u8_2s8_failed(good_u8_1, good_u8_1, good_s8_2, good_s8_2, good_float_point_1, good_float_point_1, + good_float_point_2, good_float_point_2); + test_case_2u8_2s8_failed(good_u8_1, good_u8_1, good_s8_2, good_s8_2, good_float_point_1, good_float_point_1, + good_float_point_2, good_float_point_2, true); // Use com.microsoft QDQ ops + // different zero point within a pair - test_case_all_u8(false, good_u8_1, bad_u8, good_u8_2, good_u8_2, good_float_point_1, good_float_point_1, good_float_point_2, good_float_point_2); - test_case_all_u8(false, good_u8_1, good_u8_1, good_u8_2, bad_u8, good_float_point_1, good_float_point_1, good_float_point_2, good_float_point_2); - test_case_all_s8(false, good_s8_1, bad_s8, good_s8_2, good_s8_2, good_float_point_1, good_float_point_1, good_float_point_2, good_float_point_2); - test_case_all_s8(false, good_s8_1, good_s8_1, good_s8_2, bad_s8, good_float_point_1, good_float_point_1, good_float_point_2, good_float_point_2); + test_case_all_u8(false, good_u8_1, bad_u8, good_u8_2, good_u8_2, good_float_point_1, good_float_point_1, + good_float_point_2, good_float_point_2); + test_case_all_u8(false, good_u8_1, bad_u8, good_u8_2, good_u8_2, good_float_point_1, good_float_point_1, + good_float_point_2, good_float_point_2, true); // Use com.microsoft QDQ ops + test_case_all_u8(false, good_u8_1, good_u8_1, good_u8_2, bad_u8, good_float_point_1, good_float_point_1, + good_float_point_2, good_float_point_2); + test_case_all_u8(false, good_u8_1, good_u8_1, good_u8_2, bad_u8, good_float_point_1, good_float_point_1, + good_float_point_2, good_float_point_2, true); // Use com.microsoft QDQ ops + test_case_all_s8(false, good_s8_1, bad_s8, good_s8_2, good_s8_2, good_float_point_1, good_float_point_1, + good_float_point_2, good_float_point_2); + test_case_all_s8(false, good_s8_1, bad_s8, good_s8_2, good_s8_2, good_float_point_1, good_float_point_1, + good_float_point_2, good_float_point_2, true); // Use com.microsoft QDQ ops + test_case_all_s8(false, good_s8_1, good_s8_1, good_s8_2, bad_s8, good_float_point_1, good_float_point_1, + good_float_point_2, good_float_point_2); + test_case_all_s8(false, good_s8_1, good_s8_1, good_s8_2, bad_s8, good_float_point_1, good_float_point_1, + good_float_point_2, good_float_point_2, true); // Use com.microsoft QDQ ops + // different scale within a pair - test_case_all_u8(false, good_u8_1, good_u8_1, good_u8_2, good_u8_2, good_float_point_1, bad_float_point, good_float_point_2, good_float_point_2); - test_case_all_u8(false, good_u8_1, good_u8_1, good_u8_2, good_u8_2, good_float_point_1, good_float_point_1, bad_float_point, good_float_point_2); + test_case_all_u8(false, good_u8_1, good_u8_1, good_u8_2, good_u8_2, good_float_point_1, bad_float_point, + good_float_point_2, good_float_point_2); + test_case_all_u8(false, good_u8_1, good_u8_1, good_u8_2, good_u8_2, good_float_point_1, bad_float_point, + good_float_point_2, good_float_point_2, true); // Use com.microsoft QDQ ops + test_case_all_u8(false, good_u8_1, good_u8_1, good_u8_2, good_u8_2, good_float_point_1, good_float_point_1, + bad_float_point, good_float_point_2); + test_case_all_u8(false, good_u8_1, good_u8_1, good_u8_2, good_u8_2, good_float_point_1, good_float_point_1, + bad_float_point, good_float_point_2, true); // Use com.microsoft QDQ ops +} + +template +static void RunDoubleQDQWithoutLastNodeBeingOutput(int output_index, int expected_Q_count, int expected_DQ_count, + bool use_contrib_qdq = false) { + auto graph = [&](InferenceSessionWrapper& session) { + auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], expected_Q_count); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], expected_DQ_count); + }; + TransformerTester( + BuildDoubleQDQWithoutLastOutput(output_index, use_contrib_qdq), + graph, + TransformerLevel::Default, + TransformerLevel::Level1); } TEST(QDQTransformerTests, DoubleQDQ_Without_Last_Node_Being_Output) { - auto test_case = [&](int output_index, int expected_Q_count, int expected_DQ_count) { - auto graph = [&](InferenceSessionWrapper& session) { - auto op_to_count = CountOpsInGraph(session.GetGraph()); - EXPECT_EQ(op_to_count["QuantizeLinear"], expected_Q_count); - EXPECT_EQ(op_to_count["DequantizeLinear"], expected_DQ_count); - }; - TransformerTester( - BuildDoubleQDQWithoutLastOutput(output_index), - graph, - TransformerLevel::Default, - TransformerLevel::Level1); + constexpr bool use_contrib_qdq = true; // For readability. + + RunDoubleQDQWithoutLastNodeBeingOutput(0, 2, 2); + RunDoubleQDQWithoutLastNodeBeingOutput(0, 2, 2, use_contrib_qdq); + RunDoubleQDQWithoutLastNodeBeingOutput(0, 2, 2, use_contrib_qdq); + RunDoubleQDQWithoutLastNodeBeingOutput(0, 2, 2, use_contrib_qdq); + + // EnsureUniqueDQForNodeUnit will duplicate first DQ, so expected one more (3) + RunDoubleQDQWithoutLastNodeBeingOutput(1, 2, 3); + RunDoubleQDQWithoutLastNodeBeingOutput(1, 2, 3, use_contrib_qdq); + RunDoubleQDQWithoutLastNodeBeingOutput(1, 2, 3, use_contrib_qdq); + RunDoubleQDQWithoutLastNodeBeingOutput(1, 2, 3, use_contrib_qdq); + + RunDoubleQDQWithoutLastNodeBeingOutput(2, 2, 2); + RunDoubleQDQWithoutLastNodeBeingOutput(2, 2, 2, use_contrib_qdq); + RunDoubleQDQWithoutLastNodeBeingOutput(2, 2, 2, use_contrib_qdq); + + RunDoubleQDQWithoutLastNodeBeingOutput(3, 1, 1); + RunDoubleQDQWithoutLastNodeBeingOutput(3, 1, 1, use_contrib_qdq); + RunDoubleQDQWithoutLastNodeBeingOutput(3, 1, 1, use_contrib_qdq); +} + +// Runs a test that checks if DQ -> Split -> Q (many) is replaced with just Split. +template +static void RunDropSplitQDQTestCase(const std::vector& input_shape, int64_t axis, + bool use_contrib_qdq = false) { + auto check_graph = [use_contrib_qdq](InferenceSessionWrapper& session) { + auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); + EXPECT_EQ(op_to_count["Split"], 1); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 0); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 0); }; - test_case(0, 2, 2); - test_case(1, 2, 3); // EnsureUniqueDQForNodeUnit will duplicate first DQ, so expect one more (3) - test_case(2, 2, 2); - test_case(3, 1, 1); + TransformerTester(BuildQDQSplitTestCase(input_shape, axis, use_contrib_qdq), + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + {12, 18, 19}); } -// Because split isn't one the supported ops, this will stay the same + +// Test that DQ -> Split -> Q (many) is replaced with just Split for various quantization types. TEST(QDQTransformerTests, Split) { - auto test_case = [&](const std::vector& input_shape, const int64_t& axis) { - auto check_graph = [&](InferenceSessionWrapper& session) { - auto op_to_count = CountOpsInGraph(session.GetGraph()); - EXPECT_EQ(op_to_count["Split"], 1); - EXPECT_EQ(op_to_count["QuantizeLinear"], 0); - EXPECT_EQ(op_to_count["DequantizeLinear"], 0); - }; - TransformerTester(BuildQDQSplitTestCase(input_shape, axis), - check_graph, - TransformerLevel::Level1, - TransformerLevel::Level2, - {12, 18}); - }; - test_case({6, 18, 54}, 0); + RunDropSplitQDQTestCase({6, 18, 54}, 0); + RunDropSplitQDQTestCase({6, 18, 54}, 0, true); // Use com.microsoft int8 QDQ ops + RunDropSplitQDQTestCase({6, 18, 54}, 0, true); // Use com.microsoft int16 QDQ ops + RunDropSplitQDQTestCase({6, 18, 54}, 0, true); // Use com.microsoft uint16 QDQ ops } // Because split isn't one the supported ops, this will stay the same TEST(QDQTransformerTests, Split_without_IdenticalChildrenConsolidation) { - auto test_case = [&](const std::vector& input_shape, const int64_t& axis) { + auto test_case = [&](const std::vector& input_shape, const int64_t& axis, + bool use_contrib_qdq = false) { auto check_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); EXPECT_EQ(op_to_count["Split"], 1); - EXPECT_EQ(op_to_count["QuantizeLinear"], 1); - EXPECT_EQ(op_to_count["DequantizeLinear"], 3); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 1); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 3); }; - TransformerTester(BuildConsolidationTestCase(input_shape, axis), + TransformerTester(BuildConsolidationTestCase(input_shape, axis, use_contrib_qdq), check_graph, TransformerLevel::Level1, - TransformerLevel::Level2, {12, 18}, {}, {}, nullptr, {}, + TransformerLevel::Level2, {12, 18, 19}, {}, {}, nullptr, {}, {"IdenticalChildrenConsolidation"}); }; test_case({6, 18, 54}, 0); + test_case({6, 18, 54}, 0, true); // Use com.microsoft QDQ ops } TEST(QDQTransformerTests, Split_with_IdenticalChildrenConsolidation) { - auto test_case = [&](const std::vector& input_shape, const int64_t& axis) { + auto test_case = [&](const std::vector& input_shape, const int64_t& axis, + bool use_contrib_qdq = false) { auto check_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); EXPECT_EQ(op_to_count["Split"], 1); - EXPECT_EQ(op_to_count["QuantizeLinear"], 1); - EXPECT_EQ(op_to_count["DequantizeLinear"], 3); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 1); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 3); }; - TransformerTester(BuildConsolidationTestCase(input_shape, axis), + TransformerTester(BuildConsolidationTestCase(input_shape, axis, use_contrib_qdq), check_graph, TransformerLevel::Level1, TransformerLevel::Level2, - {12, 18}); + {12, 18, 19}); }; test_case({6, 18, 54}, 0); + test_case({6, 18, 54}, 0, true); // Use com.microsoft QDQ ops } TEST(QDQTransformerTests, Where) { - auto test_case = [&](const std::vector& cond_shape, const std::vector& x_shape, const std::vector& y_shape) { + auto test_case = [&](const std::vector& cond_shape, const std::vector& x_shape, + const std::vector& y_shape, bool use_contrib_qdq = false) { auto check_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); EXPECT_EQ(op_to_count["com.microsoft.QLinearWhere"], 1); - EXPECT_EQ(op_to_count["QuantizeLinear"], 0); - EXPECT_EQ(op_to_count["DequantizeLinear"], 0); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 0); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 0); }; - TransformerTester(BuildQDQWhereTestCase(cond_shape, x_shape, y_shape), + TransformerTester(BuildQDQWhereTestCase(cond_shape, x_shape, y_shape, use_contrib_qdq), check_graph, TransformerLevel::Level1, TransformerLevel::Level2); }; test_case({1}, {1}, {1}); + test_case({1}, {1}, {1}, true /*use_contrib_qdq*/); } -TEST(QDQTransformerTests, Transpose) { - auto test_case = [&](const std::vector& input_shape, const std::vector& perms) { - auto check_graph = [&](InferenceSessionWrapper& session) { - auto op_to_count = CountOpsInGraph(session.GetGraph()); - EXPECT_EQ(op_to_count["Transpose"], 1); - EXPECT_EQ(op_to_count["QuantizeLinear"], 0); - EXPECT_EQ(op_to_count["DequantizeLinear"], 0); - }; - - TransformerTester(BuildQDQTransposeTestCase(input_shape, perms), - check_graph, - TransformerLevel::Level1, - TransformerLevel::Level2); +template +static void RunDropQDQTransposeTestCase(const std::vector& input_shape, const std::vector& perms, + bool use_contrib_qdq = false) { + auto check_graph = [&](InferenceSessionWrapper& session) { + auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); + EXPECT_EQ(op_to_count["Transpose"], 1); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 0); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 0); }; - test_case({2, 13, 12, 37}, {0, 3, 1, 2}); + TransformerTester(BuildQDQTransposeTestCase(input_shape, perms, use_contrib_qdq), + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2); } -TEST(QDQTransformerTests, Transpose_No_Fusion) { - auto test_case = [&](const std::vector& input1_shape, const std::vector& perms) { - auto build_test_case = [&](ModelTestBuilder& builder) { - auto* input1_arg = builder.MakeInput(input1_shape, -128, 127); - auto* output_arg = builder.MakeOutput(); +TEST(QDQTransformerTests, Transpose) { + RunDropQDQTransposeTestCase({2, 13, 12, 37}, {0, 3, 1, 2}); + RunDropQDQTransposeTestCase({2, 13, 12, 37}, {0, 3, 1, 2}, true /*use_contrib_qdq*/); + RunDropQDQTransposeTestCase({2, 13, 12, 37}, {0, 3, 1, 2}, true /*use_contrib_qdq*/); + RunDropQDQTransposeTestCase({2, 13, 12, 37}, {0, 3, 1, 2}, true /*use_contrib_qdq*/); +} - // add DQ - auto* dq_output = builder.MakeIntermediate(); - builder.AddDequantizeLinearNode(input1_arg, .003f, 1, dq_output); +template +static void RunQDQTransposeNoFusionTestCase(const std::vector& input1_shape, const std::vector& perms, + bool use_contrib_qdq = false) { + auto build_test_case = [&](ModelTestBuilder& builder) { + auto* input1_arg = builder.MakeInput(input1_shape, std::numeric_limits::min(), + std::numeric_limits::max()); + auto* output_arg = builder.MakeOutput(); - // add Transpose - auto* transpose_output = builder.MakeOutput(); // transpose output is graph output - Node& transpose_node = builder.AddNode("Transpose", {dq_output}, {transpose_output}); - transpose_node.AddAttribute("perm", perms); + // add DQ + auto* dq_output = builder.MakeIntermediate(); + builder.AddDequantizeLinearNode(input1_arg, .003f, 1, dq_output, use_contrib_qdq); - // add Q - builder.AddQuantizeLinearNode(transpose_output, .003f, 1, output_arg); - }; + // add Transpose + auto* transpose_output = builder.MakeOutput(); // transpose output is graph output + Node& transpose_node = builder.AddNode("Transpose", {dq_output}, {transpose_output}); + transpose_node.AddAttribute("perm", perms); - auto check_graph = [&](InferenceSessionWrapper& session) { - auto op_to_count = CountOpsInGraph(session.GetGraph()); - EXPECT_EQ(op_to_count["QuantizeLinear"], 1); - EXPECT_EQ(op_to_count["DequantizeLinear"], 1); - }; + // add Q + builder.AddQuantizeLinearNode(transpose_output, .003f, 1, output_arg, use_contrib_qdq); + }; - TransformerTester(build_test_case, check_graph, TransformerLevel::Level1, TransformerLevel::Level2); + auto check_graph = [&](InferenceSessionWrapper& session) { + auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 1); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 1); }; - test_case({2, 13, 12, 37}, {0, 3, 1, 2}); + TransformerTester(build_test_case, check_graph, TransformerLevel::Level1, TransformerLevel::Level2); +} + +TEST(QDQTransformerTests, Transpose_No_Fusion) { + RunQDQTransposeNoFusionTestCase({2, 13, 12, 37}, {0, 3, 1, 2}); + RunQDQTransposeNoFusionTestCase({2, 13, 12, 37}, {0, 3, 1, 2}, true /*use_contrib_qdq*/); + RunQDQTransposeNoFusionTestCase({2, 13, 12, 37}, {0, 3, 1, 2}, true /*use_contrib_qdq*/); + RunQDQTransposeNoFusionTestCase({2, 13, 12, 37}, {0, 3, 1, 2}, true /*use_contrib_qdq*/); } TEST(QDQTransformerTests, Resize) { auto test_case = [&](const std::vector& input1_shape, - const std::vector& sizes_shape) { + const std::vector& sizes_shape, + bool use_contrib_qdq = false) { auto check_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); EXPECT_EQ(op_to_count["Resize"], 1); - EXPECT_EQ(op_to_count["QuantizeLinear"], 0); - EXPECT_EQ(op_to_count["DequantizeLinear"], 0); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 0); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 0); }; - TransformerTester(BuildQDQResizeTestCase(input1_shape, sizes_shape), + TransformerTester(BuildQDQResizeTestCase(input1_shape, + sizes_shape, + "nearest", // mode + "half_pixel", // coordinate_transformation_mode + "round_prefer_floor", // nearest_mode + false, // add_dq_output_float + use_contrib_qdq), check_graph, TransformerLevel::Level1, TransformerLevel::Level2); @@ -1053,13 +1381,15 @@ TEST(QDQTransformerTests, Resize) { RandomValueGenerator rand_gen{optional{2345}}; test_case({2, 13, 12, 37}, rand_gen.Uniform(std::vector{4}, 1, 16)); + test_case({2, 13, 12, 37}, rand_gen.Uniform(std::vector{4}, 1, 16), true /*use_contrib_qdq*/); } TEST(QDQTransformerTests, Resize_No_Fusion) { auto test_case = [&](const std::vector& input_shape, const std::vector& sizes_shape, const std::vector& concat_input2_shape, - const int64_t axis) { + const int64_t axis, + bool use_contrib_qdq = false) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput(input_shape, std::numeric_limits::min(), @@ -1071,7 +1401,7 @@ TEST(QDQTransformerTests, Resize_No_Fusion) { // add DQ auto* dq_output = builder.MakeIntermediate(); - builder.AddDequantizeLinearNode(input_arg, .003f, 1, dq_output); + builder.AddDequantizeLinearNode(input_arg, .003f, 1, dq_output, use_contrib_qdq); // add Resize auto* resize_output = builder.MakeIntermediate(); @@ -1088,15 +1418,16 @@ TEST(QDQTransformerTests, Resize_No_Fusion) { concat_node.AddAttribute("axis", axis); // add Q - builder.AddQuantizeLinearNode(resize_output, .003f, 1, output_arg); + builder.AddQuantizeLinearNode(resize_output, .003f, 1, output_arg, use_contrib_qdq); }; auto check_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); EXPECT_EQ(op_to_count["Resize"], 1); EXPECT_EQ(op_to_count["Concat"], 1); - EXPECT_EQ(op_to_count["QuantizeLinear"], 1); - EXPECT_EQ(op_to_count["DequantizeLinear"], 1); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 1); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 1); }; TransformerTester(build_test_case, check_graph, @@ -1105,11 +1436,13 @@ TEST(QDQTransformerTests, Resize_No_Fusion) { }; test_case({1, 8, 64, 64}, {4}, {1, 4, 128, 128}, 1); + test_case({1, 8, 64, 64}, {4}, {1, 4, 128, 128}, 1, true /*use_contrib_qdq*/); } TEST(QDQTransformerTests, ResizeReshapeSqueezeUnsqueeze) { auto test_case = [&](const std::vector& input_shape, - const std::vector& sizes_shape) { + const std::vector& sizes_shape, + bool use_contrib_qdq = false) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput(input_shape, std::numeric_limits::min(), @@ -1119,90 +1452,114 @@ TEST(QDQTransformerTests, ResizeReshapeSqueezeUnsqueeze) { auto* sizes = builder.MakeInitializer(sizes_shape, {1, 2, 52, 82}); // add QDQ + Resize - auto* qdq_input = AddQDQNodePair(builder, input_arg, .003f, 1); + auto* qdq_input = AddQDQNodePair(builder, input_arg, .003f, 1, use_contrib_qdq); auto* resize_output = builder.MakeIntermediate(); builder.AddNode("Resize", {qdq_input, roi, scales, sizes}, {resize_output}); // add QDQ + Reshape - auto* qdq_resize_output = AddQDQNodePair(builder, resize_output, .003f, 1); + auto* qdq_resize_output = AddQDQNodePair(builder, resize_output, .003f, 1, use_contrib_qdq); auto* reshape_shape = builder.Make1DInitializer({1, 2, 52, 82}); auto* reshape_output = builder.MakeIntermediate(); builder.AddNode("Reshape", {qdq_resize_output, reshape_shape}, {reshape_output}); // add QDQ + Squeeze - auto* qdq_squeeze_output = AddQDQNodePair(builder, reshape_output, .003f, 1); + auto* qdq_squeeze_output = AddQDQNodePair(builder, reshape_output, .003f, 1, use_contrib_qdq); auto* squeeze_axes = builder.Make1DInitializer({0}); auto* squeeze_output = builder.MakeIntermediate(); builder.AddNode("Squeeze", {qdq_squeeze_output, squeeze_axes}, {squeeze_output}); // add QDQ + Unsqueeze - auto* qdq_unsqueeze_output = AddQDQNodePair(builder, squeeze_output, .003f, 1); + auto* qdq_unsqueeze_output = AddQDQNodePair(builder, squeeze_output, .003f, 1, use_contrib_qdq); auto* unsqueeze_axes = builder.Make1DInitializer({0}); auto* unsqueeze_output = builder.MakeIntermediate(); builder.AddNode("Unsqueeze", {qdq_unsqueeze_output, unsqueeze_axes}, {unsqueeze_output}); // add QDQ - AddQDQNodePairWithOutputAsGraphOutput(builder, unsqueeze_output, .003f, 1); + AddQDQNodePairWithOutputAsGraphOutput(builder, unsqueeze_output, .003f, 1, use_contrib_qdq); }; auto check_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); EXPECT_EQ(op_to_count["Resize"], 1); EXPECT_EQ(op_to_count["Reshape"], 1); - EXPECT_EQ(op_to_count["QuantizeLinear"], 1); - EXPECT_EQ(op_to_count["DequantizeLinear"], 1); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 1); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 1); }; TransformerTester(build_test_case, check_graph, TransformerLevel::Level1, TransformerLevel::Level2, 13 /*opset_version*/); + + TransformerTester(build_test_case, check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 19 /*opset_version*/); }; test_case({1, 2, 26, 42}, {4}); + test_case({1, 2, 26, 42}, {4}, true /*use_contrib_qdq*/); } -TEST(QDQTransformerTests, ArgMax) { - auto test_case = [&](const std::vector& input_shape, - int axis, - int keepdims, - int select_last_index) { - auto build_test_case = [&](ModelTestBuilder& builder) { - auto* input_arg = builder.MakeInput(input_shape, - std::numeric_limits::min(), - std::numeric_limits::max()); - auto* output_arg = builder.MakeOutput(); - - // add DQ - auto* dq_output = builder.MakeIntermediate(); - builder.AddDequantizeLinearNode(input_arg, .003f, 1, dq_output); +// Runs a test case that checks if the DQ node is dropped from DQ -> Op (e.g., ArgMax). +template +static void RunArgMaxDropDQTestCase(const std::vector& input_shape, + int axis, + int keepdims, + int select_last_index, + bool use_contrib_qdq, + bool expect_drop_dq = true) { + auto build_test_case = [&](ModelTestBuilder& builder) { + auto* input_arg = builder.MakeInput(input_shape, + std::numeric_limits::min(), + std::numeric_limits::max()); + auto* output_arg = builder.MakeOutput(); - // add ArgMax - Node& argmax_node = builder.AddNode("ArgMax", {dq_output}, {output_arg}); - argmax_node.AddAttribute("axis", static_cast(axis)); - argmax_node.AddAttribute("keepdims", static_cast(keepdims)); - argmax_node.AddAttribute("select_last_index", static_cast(select_last_index)); - }; + // add DQ + auto* dq_output = builder.MakeIntermediate(); + builder.AddDequantizeLinearNode(input_arg, .003f, 1, dq_output, use_contrib_qdq); - auto check_graph = [&](InferenceSessionWrapper& session) { - auto op_to_count = CountOpsInGraph(session.GetGraph()); - EXPECT_EQ(op_to_count["ArgMax"], 1); - EXPECT_EQ(op_to_count["DequantizeLinear"], 0); - }; + // add ArgMax + Node& argmax_node = builder.AddNode("ArgMax", {dq_output}, {output_arg}); + argmax_node.AddAttribute("axis", static_cast(axis)); + argmax_node.AddAttribute("keepdims", static_cast(keepdims)); + argmax_node.AddAttribute("select_last_index", static_cast(select_last_index)); + }; - TransformerTester(build_test_case, check_graph, - TransformerLevel::Level1, - TransformerLevel::Level2, - /* opset_version */ 13); + auto check_graph = [use_contrib_qdq, expect_drop_dq](InferenceSessionWrapper& session) { + auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); + EXPECT_EQ(op_to_count["ArgMax"], 1); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], expect_drop_dq ? 0 : 1); }; - test_case({2, 13, 12, 37}, 1, 0, 0); - test_case({2, 13, 12, 37}, 0, 1, 0); - test_case({2, 13, 12, 37}, 0, 0, 1); + TransformerTester(build_test_case, check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + /* opset_version */ 13); + TransformerTester(build_test_case, check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + /* opset_version */ 19); +} + +// Checks that the DQ node is dropped from DQ -> ArgMax. Uses 8-bit and 16-bit Q/DQ ops. +TEST(QDQTransformerTests, ArgMax) { + RunArgMaxDropDQTestCase({2, 13, 12, 37}, 1, 0, 0, false); + RunArgMaxDropDQTestCase({2, 13, 12, 37}, 1, 0, 0, true /*use_contrib_qdq*/); + + // Should *not* drop DQ for 16-bit DQ -> ArgMax (because ORT does not support 16-bit input types for ArgMax). + RunArgMaxDropDQTestCase({2, 13, 12, 37}, 1, 0, 0, true /*use_contrib_qdq*/, false /*expect_drop_dq*/); + RunArgMaxDropDQTestCase({2, 13, 12, 37}, 1, 0, 0, true /*use_contrib_qdq*/, false /*expect_drop_dq*/); + + RunArgMaxDropDQTestCase({2, 13, 12, 37}, 0, 1, 0, false); + RunArgMaxDropDQTestCase({2, 13, 12, 37}, 0, 0, 1, false); } TEST(QDQTransformerTests, QLinearMatMul) { - auto test_case = [&](const std::vector& input1_shape, const std::vector& input2_shape) { + auto test_case = [&](const std::vector& input1_shape, const std::vector& input2_shape, + bool use_contrib_qdq) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input1_arg = builder.MakeInput(input1_shape, -1.f, 1.f); auto* input2_arg = builder.MakeInput(input2_shape, -1.f, 1.f); @@ -1210,31 +1567,34 @@ TEST(QDQTransformerTests, QLinearMatMul) { // add QDQ + MatMul auto* matmul_output = builder.MakeIntermediate(); - auto* dq_matmul_output1 = AddQDQNodePair(builder, input1_arg, .004f, 129); - auto* dq_matmul_output2 = AddQDQNodePair(builder, input2_arg, .004f, 129); + auto* dq_matmul_output1 = AddQDQNodePair(builder, input1_arg, .004f, 129, use_contrib_qdq); + auto* dq_matmul_output2 = AddQDQNodePair(builder, input2_arg, .004f, 129, use_contrib_qdq); builder.AddNode("MatMul", {dq_matmul_output1, dq_matmul_output2}, {matmul_output}); // add Q - builder.AddQuantizeLinearNode(matmul_output, .0039f, 135, output_arg); + builder.AddQuantizeLinearNode(matmul_output, .0039f, 135, output_arg, use_contrib_qdq); }; auto check_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); EXPECT_EQ(op_to_count["QLinearMatMul"], 1); - EXPECT_EQ(op_to_count["QuantizeLinear"], 2); - EXPECT_EQ(op_to_count["DequantizeLinear"], 0); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 2); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 0); }; TransformerTester(build_test_case, check_graph, TransformerLevel::Level1, TransformerLevel::Level2); }; - test_case({12, 37}, {37, 12}); - test_case({23, 13, 13}, {13, 13}); - test_case({22, 11, 13, 15}, {15, 13}); + test_case({12, 37}, {37, 12}, false /*use_contrib_qdq*/); + test_case({12, 37}, {37, 12}, true /*use_contrib_qdq*/); + test_case({23, 13, 13}, {13, 13}, false /*use_contrib_qdq*/); + test_case({22, 11, 13, 15}, {15, 13}, false /*use_contrib_qdq*/); } TEST(QDQTransformerTests, MatMul_No_Fusion) { - auto test_case = [&](const std::vector& input1_shape, const std::vector& input2_shape) { + auto test_case = [&](const std::vector& input1_shape, const std::vector& input2_shape, + bool use_contrib_qdq) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input1_arg = builder.MakeInput(input1_shape, -1.f, 1.f); auto* input2_arg = builder.MakeInput(input2_shape, -1.f, 1.f); @@ -1242,31 +1602,34 @@ TEST(QDQTransformerTests, MatMul_No_Fusion) { // add QDQ + MatMul auto* matmul_output = builder.MakeIntermediate(); - auto* dq_matmul_output1 = AddQDQNodePair(builder, input1_arg, .004f, 129); + auto* dq_matmul_output1 = AddQDQNodePair(builder, input1_arg, .004f, 129, use_contrib_qdq); builder.AddNode("MatMul", {dq_matmul_output1, input2_arg}, {matmul_output}); // add Q - builder.AddQuantizeLinearNode(matmul_output, .0039f, 135, output_arg); + builder.AddQuantizeLinearNode(matmul_output, .0039f, 135, output_arg, use_contrib_qdq); }; auto check_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); EXPECT_EQ(op_to_count["MatMul"], 1); EXPECT_EQ(op_to_count["QLinearMatMul"], 0); - EXPECT_EQ(op_to_count["QuantizeLinear"], 2); - EXPECT_EQ(op_to_count["DequantizeLinear"], 1); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 2); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 1); }; TransformerTester(build_test_case, check_graph, TransformerLevel::Level1, TransformerLevel::Level2); }; - test_case({12, 37}, {37, 12}); - test_case({23, 13, 13}, {13, 13}); - test_case({22, 11, 13, 15}, {15, 13}); + test_case({12, 37}, {37, 12}, false /*use_contrib_qdq*/); + test_case({12, 37}, {37, 12}, true /*use_contrib_qdq*/); + test_case({23, 13, 13}, {13, 13}, false /*use_contrib_qdq*/); + test_case({22, 11, 13, 15}, {15, 13}, false /*use_contrib_qdq*/); } TEST(QDQTransformerTests, MatMul_1st_Input_Int8) { - auto test_case = [&](const std::vector& input1_shape, const std::vector& input2_shape) { + auto test_case = [&](const std::vector& input1_shape, const std::vector& input2_shape, + bool use_contrib_qdq) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input1_arg = builder.MakeInput(input1_shape, -128, 127); auto* input2_arg = builder.MakeInput(input2_shape, -1.f, 1.f); @@ -1274,35 +1637,38 @@ TEST(QDQTransformerTests, MatMul_1st_Input_Int8) { // add DQ with type int8 auto* dq_output_1 = builder.MakeIntermediate(); - builder.AddDequantizeLinearNode(input1_arg, .004f, 1, dq_output_1); + builder.AddDequantizeLinearNode(input1_arg, .004f, 1, dq_output_1, use_contrib_qdq); // add QDQ + MatMul auto* matmul_output = builder.MakeIntermediate(); - auto* dq_matmul_output2 = AddQDQNodePair(builder, input2_arg, .004f, 129); + auto* dq_matmul_output2 = AddQDQNodePair(builder, input2_arg, .004f, 129, use_contrib_qdq); builder.AddNode("MatMul", {dq_output_1, dq_matmul_output2}, {matmul_output}); // add Q - builder.AddQuantizeLinearNode(matmul_output, .0039f, 135, output_arg); + builder.AddQuantizeLinearNode(matmul_output, .0039f, 135, output_arg, use_contrib_qdq); }; auto check_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); EXPECT_EQ(op_to_count["MatMul"], 1); EXPECT_EQ(op_to_count["QLinearMatMul"], 0); - EXPECT_EQ(op_to_count["QuantizeLinear"], 2); - EXPECT_EQ(op_to_count["DequantizeLinear"], 2); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 2); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 2); }; TransformerTester(build_test_case, check_graph, TransformerLevel::Level1, TransformerLevel::Level2); }; - test_case({12, 37}, {37, 12}); - test_case({23, 13, 13}, {13, 13}); - test_case({22, 11, 13, 15}, {15, 13}); + test_case({12, 37}, {37, 12}, false /*use_contrib_qdq*/); + test_case({12, 37}, {37, 12}, true /*use_contrib_qdq*/); + test_case({23, 13, 13}, {13, 13}, false /*use_contrib_qdq*/); + test_case({22, 11, 13, 15}, {15, 13}, false /*use_contrib_qdq*/); } TEST(QDQTransformerTests, MatMulIntegerToFloat) { - auto test_case = [&](const std::vector& input1_shape, const std::vector& input2_shape) { + auto test_case = [&](const std::vector& input1_shape, const std::vector& input2_shape, + bool use_contrib_qdq) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input1_arg = builder.MakeInput(input1_shape, std::numeric_limits::min(), @@ -1314,19 +1680,20 @@ TEST(QDQTransformerTests, MatMulIntegerToFloat) { // add DQ auto* dq_output_1 = builder.MakeIntermediate(); - builder.AddDequantizeLinearNode(input1_arg, .0035f, 135, dq_output_1); + builder.AddDequantizeLinearNode(input1_arg, .0035f, 135, dq_output_1, use_contrib_qdq); auto* dq_output_2 = builder.MakeIntermediate(); - builder.AddDequantizeLinearNode(input2_arg, .0035f, 135, dq_output_2); + builder.AddDequantizeLinearNode(input2_arg, .0035f, 135, dq_output_2, use_contrib_qdq); builder.AddNode("MatMul", {dq_output_1, dq_output_2}, {output_arg}); }; auto check_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); EXPECT_EQ(op_to_count["com.microsoft.MatMulIntegerToFloat"], 1); - EXPECT_EQ(op_to_count["QuantizeLinear"], 0); - EXPECT_EQ(op_to_count["DequantizeLinear"], 0); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 0); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 0); }; TransformerTester(build_test_case, @@ -1336,15 +1703,24 @@ TEST(QDQTransformerTests, MatMulIntegerToFloat) { 12 /*opset_version*/, 1e-5 /*per_sample_tolerance*/, 1e-5 /*relative_per_sample_tolerance*/); + TransformerTester(build_test_case, + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 19 /*opset_version*/, + 1e-5 /*per_sample_tolerance*/, + 1e-5 /*relative_per_sample_tolerance*/); }; - test_case({12, 37}, {37, 12}); - test_case({23, 13, 13}, {13, 13}); - test_case({22, 11, 13, 15}, {15, 13}); + test_case({12, 37}, {37, 12}, false /*use_contrib_qdq*/); + test_case({12, 37}, {37, 12}, true /*use_contrib_qdq*/); + test_case({23, 13, 13}, {13, 13}, false /*use_contrib_qdq*/); + test_case({22, 11, 13, 15}, {15, 13}, false /*use_contrib_qdq*/); } TEST(QDQTransformerTests, ConvRelu) { - auto test_case = [&](const std::vector& input_shape, const std::vector& weights_shape, bool is_zp_zero) { + auto test_case = [&](const std::vector& input_shape, const std::vector& weights_shape, + bool is_zp_zero, bool use_contrib_qdq) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput(input_shape, -1.f, 1.f); auto* output_arg = builder.MakeOutput(); @@ -1353,8 +1729,8 @@ TEST(QDQTransformerTests, ConvRelu) { // add QDQ + Conv auto* dq_w_output = builder.MakeIntermediate(); auto* conv_output = builder.MakeIntermediate(); - auto* dq_conv_output = AddQDQNodePair(builder, input_arg, .004f, 129); - builder.AddDequantizeLinearNode(weight, .003f, 118, dq_w_output); + auto* dq_conv_output = AddQDQNodePair(builder, input_arg, .004f, 129, use_contrib_qdq); + builder.AddDequantizeLinearNode(weight, .003f, 118, dq_w_output, use_contrib_qdq); builder.AddConvNode(dq_conv_output, dq_w_output, conv_output); // add Relu @@ -1362,40 +1738,44 @@ TEST(QDQTransformerTests, ConvRelu) { builder.AddNode("Relu", {conv_output}, {relu_output}); // add Q - builder.AddQuantizeLinearNode(relu_output, .0039f, is_zp_zero ? 0 : 1, output_arg); + builder.AddQuantizeLinearNode(relu_output, .0039f, is_zp_zero ? 0 : 1, output_arg, use_contrib_qdq); }; auto check_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); if (is_zp_zero) { EXPECT_EQ(op_to_count["QLinearConv"], 1); EXPECT_EQ(op_to_count["Conv"], 0); EXPECT_EQ(op_to_count["Relu"], 0); - EXPECT_EQ(op_to_count["QuantizeLinear"], 1); - EXPECT_EQ(op_to_count["DequantizeLinear"], 0); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 1); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 0); } else { EXPECT_EQ(op_to_count["QLinearConv"], 0); EXPECT_EQ(op_to_count["Conv"], 0); EXPECT_EQ(op_to_count["Relu"], 0); EXPECT_EQ(op_to_count["com.microsoft.FusedConv"], 1); - EXPECT_EQ(op_to_count["QuantizeLinear"], 2); - EXPECT_EQ(op_to_count["DequantizeLinear"], 2); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 2); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 2); } }; TransformerTester(build_test_case, check_graph, TransformerLevel::Level1, TransformerLevel::Level2); }; - test_case({1, 12, 37}, {32, 12, 5}, true); - test_case({1, 12, 37}, {32, 12, 5}, false); - test_case({1, 23, 13, 13}, {30, 23, 3, 3}, true); - test_case({1, 23, 13, 13}, {30, 23, 3, 3}, false); - test_case({1, 22, 11, 13, 15}, {30, 22, 5, 3, 3}, true); - test_case({1, 22, 11, 13, 15}, {30, 22, 5, 3, 3}, false); + test_case({1, 12, 37}, {32, 12, 5}, true, false /*use_contrib_qdq*/); + test_case({1, 12, 37}, {32, 12, 5}, true, true /*use_contrib_qdq*/); + test_case({1, 12, 37}, {32, 12, 5}, false, false /*use_contrib_qdq*/); + test_case({1, 12, 37}, {32, 12, 5}, false, true /*use_contrib_qdq*/); + test_case({1, 23, 13, 13}, {30, 23, 3, 3}, true, false /*use_contrib_qdq*/); + test_case({1, 23, 13, 13}, {30, 23, 3, 3}, false, false /*use_contrib_qdq*/); + test_case({1, 22, 11, 13, 15}, {30, 22, 5, 3, 3}, true, false /*use_contrib_qdq*/); + test_case({1, 22, 11, 13, 15}, {30, 22, 5, 3, 3}, false, false /*use_contrib_qdq*/); } TEST(QDQTransformerTests, ConvAveragePoolReshape_UInt8) { - auto test_case = [&](const std::vector& input_shape, const std::vector& weights_shape) { + auto test_case = [&](const std::vector& input_shape, const std::vector& weights_shape, + bool use_contrib_qdq) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput(input_shape, -1.f, 1.f); auto* output_arg = builder.MakeOutput(); @@ -1404,12 +1784,12 @@ TEST(QDQTransformerTests, ConvAveragePoolReshape_UInt8) { // add QDQ + Conv auto* dq_w_output = builder.MakeIntermediate(); auto* conv_output = builder.MakeIntermediate(); - auto* dq_conv_output = AddQDQNodePair(builder, input_arg, .004f, 129); - builder.AddDequantizeLinearNode(weight, .003f, 118, dq_w_output); + auto* dq_conv_output = AddQDQNodePair(builder, input_arg, .004f, 129, use_contrib_qdq); + builder.AddDequantizeLinearNode(weight, .003f, 118, dq_w_output, use_contrib_qdq); builder.AddConvNode(dq_conv_output, dq_w_output, conv_output); // add QDQ + AveragePool - auto* dq_averagepool_output = AddQDQNodePair(builder, conv_output, .0035f, 135); + auto* dq_averagepool_output = AddQDQNodePair(builder, conv_output, .0035f, 135, use_contrib_qdq); auto* averagepool_output = builder.MakeIntermediate(); Node& pool_node = builder.AddNode("AveragePool", {dq_averagepool_output}, {averagepool_output}); std::vector pads((weights_shape.size() - 2) * 2, 1); @@ -1418,24 +1798,25 @@ TEST(QDQTransformerTests, ConvAveragePoolReshape_UInt8) { pool_node.AddAttribute("kernel_shape", kernel_shape); // add QDQ + Reshape - auto* dq_reshape_output = AddQDQNodePair(builder, averagepool_output, .0035f, 135); + auto* dq_reshape_output = AddQDQNodePair(builder, averagepool_output, .0035f, 135, use_contrib_qdq); auto* reshape_shape = builder.Make1DInitializer({-1}); auto* reshape_output = builder.MakeIntermediate(); builder.AddNode("Reshape", {dq_reshape_output, reshape_shape}, {reshape_output}); // add Q auto* q_output = builder.MakeIntermediate(); - builder.AddQuantizeLinearNode(reshape_output, .0035f, 135, q_output); - builder.AddDequantizeLinearNode(q_output, .0035f, 135, output_arg); + builder.AddQuantizeLinearNode(reshape_output, .0035f, 135, q_output, use_contrib_qdq); + builder.AddDequantizeLinearNode(q_output, .0035f, 135, output_arg, use_contrib_qdq); }; auto check_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); EXPECT_EQ(op_to_count["QLinearConv"], 1); EXPECT_EQ(op_to_count["com.microsoft.QLinearAveragePool"], 1); EXPECT_EQ(op_to_count["Reshape"], 1); - EXPECT_EQ(op_to_count["QuantizeLinear"], 1); - EXPECT_EQ(op_to_count["DequantizeLinear"], 1); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 1); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 1); }; TransformerTester(build_test_case, @@ -1445,15 +1826,25 @@ TEST(QDQTransformerTests, ConvAveragePoolReshape_UInt8) { 12 /*opset_version*/, 0.01f /*per_sample_tolerance*/, 0.01f /*relative_per_sample_tolerance*/); + TransformerTester(build_test_case, + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 18 /*opset_version*/, + 0.01f /*per_sample_tolerance*/, + 0.01f /*relative_per_sample_tolerance*/); + // TODO: fix opset 19 }; - test_case({1, 12, 37}, {32, 12, 5}); - test_case({1, 23, 13, 13}, {30, 23, 3, 3}); - test_case({1, 22, 11, 13, 15}, {30, 22, 5, 3, 3}); + test_case({1, 12, 37}, {32, 12, 5}, false /*use_contrib_qdq*/); + test_case({1, 23, 13, 13}, {30, 23, 3, 3}, false /*use_contrib_qdq*/); + test_case({1, 22, 11, 13, 15}, {30, 22, 5, 3, 3}, false /*use_contrib_qdq*/); + test_case({1, 12, 37}, {32, 12, 5}, true /*use_contrib_qdq*/); } TEST(QDQTransformerTests, ConvAveragePoolReshape_Int8) { - auto test_case = [&](const std::vector& input_shape, const std::vector& weights_shape) { + auto test_case = [&](const std::vector& input_shape, const std::vector& weights_shape, + bool use_contrib_qdq) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput(input_shape, -1.f, 1.f); auto* output_arg = builder.MakeOutput(); @@ -1462,12 +1853,12 @@ TEST(QDQTransformerTests, ConvAveragePoolReshape_Int8) { // add QDQ + Conv auto* dq_w_output = builder.MakeIntermediate(); auto* conv_output = builder.MakeIntermediate(); - auto* dq_conv_output = AddQDQNodePair(builder, input_arg, .004f, 1); - builder.AddDequantizeLinearNode(weight, .003f, -10, dq_w_output); + auto* dq_conv_output = AddQDQNodePair(builder, input_arg, .004f, 1, use_contrib_qdq); + builder.AddDequantizeLinearNode(weight, .003f, -10, dq_w_output, use_contrib_qdq); builder.AddConvNode(dq_conv_output, dq_w_output, conv_output); // add QDQ + AveragePool - auto* dq_averagepool_output = AddQDQNodePair(builder, conv_output, .0035f, 7); + auto* dq_averagepool_output = AddQDQNodePair(builder, conv_output, .0035f, 7, use_contrib_qdq); auto* averagepool_output = builder.MakeIntermediate(); Node& pool_node = builder.AddNode("AveragePool", {dq_averagepool_output}, {averagepool_output}); std::vector pads((weights_shape.size() - 2) * 2, 1); @@ -1476,7 +1867,7 @@ TEST(QDQTransformerTests, ConvAveragePoolReshape_Int8) { pool_node.AddAttribute("kernel_shape", kernel_shape); // add QDQ + Reshape - auto* dq_reshape_output = AddQDQNodePair(builder, averagepool_output, .0035f, 7); + auto* dq_reshape_output = AddQDQNodePair(builder, averagepool_output, .0035f, 7, use_contrib_qdq); auto* reshape_shape = builder.Make1DInitializer({-1}); auto* reshape_output = builder.MakeIntermediate(); builder.AddNode("Reshape", {dq_reshape_output, reshape_shape}, {reshape_output}); @@ -1484,21 +1875,22 @@ TEST(QDQTransformerTests, ConvAveragePoolReshape_Int8) { // add Q auto* q_output = builder.MakeIntermediate(); if constexpr (QDQIsInt8Allowed()) { - builder.AddQuantizeLinearNode(reshape_output, .0035f, 7, q_output); - builder.AddDequantizeLinearNode(q_output, .0035f, 7, output_arg); + builder.AddQuantizeLinearNode(reshape_output, .0035f, 7, q_output, use_contrib_qdq); + builder.AddDequantizeLinearNode(q_output, .0035f, 7, output_arg, use_contrib_qdq); } else { - builder.AddQuantizeLinearNode(reshape_output, .0035f, 135, q_output); - builder.AddDequantizeLinearNode(q_output, .0035f, 135, output_arg); + builder.AddQuantizeLinearNode(reshape_output, .0035f, 135, q_output, use_contrib_qdq); + builder.AddDequantizeLinearNode(q_output, .0035f, 135, output_arg, use_contrib_qdq); } }; auto check_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); EXPECT_EQ(op_to_count["QLinearConv"], 1); EXPECT_EQ(op_to_count["com.microsoft.QLinearAveragePool"], 1); EXPECT_EQ(op_to_count["Reshape"], 1); - EXPECT_EQ(op_to_count["QuantizeLinear"], 1); - EXPECT_EQ(op_to_count["DequantizeLinear"], 1); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 1); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 1); }; TransformerTester(build_test_case, @@ -1508,15 +1900,25 @@ TEST(QDQTransformerTests, ConvAveragePoolReshape_Int8) { 12 /*opset_version*/, 0.01f /*per_sample_tolerance*/, 0.01f /*relative_per_sample_tolerance*/); + TransformerTester(build_test_case, + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 18 /*opset_version*/, + 0.01f /*per_sample_tolerance*/, + 0.01f /*relative_per_sample_tolerance*/); + // TODO: fix opset 19 }; - test_case({1, 12, 37}, {32, 12, 5}); - test_case({1, 23, 13, 13}, {30, 23, 3, 3}); - test_case({1, 22, 11, 13, 15}, {30, 22, 5, 3, 3}); + test_case({1, 12, 37}, {32, 12, 5}, false /*use_contrib_qdq*/); + test_case({1, 23, 13, 13}, {30, 23, 3, 3}, false /*use_contrib_qdq*/); + test_case({1, 22, 11, 13, 15}, {30, 22, 5, 3, 3}, false /*use_contrib_qdq*/); + test_case({1, 12, 37}, {32, 12, 5}, true /*use_contrib_qdq*/); } TEST(QDQTransformerTests, ConvAveragePoolReshape_Int8_Fail) { - auto test_case = [&](const std::vector& input_shape, const std::vector& weights_shape) { + auto test_case = [&](const std::vector& input_shape, const std::vector& weights_shape, + bool use_contrib_qdq) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput(input_shape, -128, 127); auto* output_arg = builder.MakeOutput(); @@ -1526,12 +1928,12 @@ TEST(QDQTransformerTests, ConvAveragePoolReshape_Int8_Fail) { auto* dq_output = builder.MakeIntermediate(); auto* dq_w_output = builder.MakeIntermediate(); auto* conv_output = builder.MakeIntermediate(); - builder.AddDequantizeLinearNode(input_arg, .004f, 1, dq_output); - builder.AddDequantizeLinearNode(weight, .003f, 118, dq_w_output); + builder.AddDequantizeLinearNode(input_arg, .004f, 1, dq_output, use_contrib_qdq); + builder.AddDequantizeLinearNode(weight, .003f, 118, dq_w_output, use_contrib_qdq); builder.AddConvNode(dq_output, dq_w_output, conv_output); // add QDQ + AveragePool - auto* dq_averagepool_output = AddQDQNodePair(builder, conv_output, .0035f, 7); + auto* dq_averagepool_output = AddQDQNodePair(builder, conv_output, .0035f, 7, use_contrib_qdq); auto* averagepool_output = builder.MakeIntermediate(); Node& pool_node = builder.AddNode("AveragePool", {dq_averagepool_output}, {averagepool_output}); std::vector pads((weights_shape.size() - 2) * 2, 1); @@ -1540,7 +1942,7 @@ TEST(QDQTransformerTests, ConvAveragePoolReshape_Int8_Fail) { pool_node.AddAttribute("kernel_shape", kernel_shape); // add QDQ + Reshape - auto* dq_reshape_output = AddQDQNodePair(builder, averagepool_output, .0035f, 7); + auto* dq_reshape_output = AddQDQNodePair(builder, averagepool_output, .0035f, 7, use_contrib_qdq); auto* reshape_shape = builder.Make1DInitializer({-1}); auto* reshape_output = builder.MakeIntermediate(); builder.AddNode("Reshape", {dq_reshape_output, reshape_shape}, {reshape_output}); @@ -1548,24 +1950,26 @@ TEST(QDQTransformerTests, ConvAveragePoolReshape_Int8_Fail) { // add Q + DQ auto* q_output = builder.MakeIntermediate(); if constexpr (QDQIsInt8Allowed()) { - builder.AddQuantizeLinearNode(reshape_output, .0035f, 7, q_output); - builder.AddDequantizeLinearNode(q_output, .0035f, 7, output_arg); + builder.AddQuantizeLinearNode(reshape_output, .0035f, 7, q_output, use_contrib_qdq); + builder.AddDequantizeLinearNode(q_output, .0035f, 7, output_arg, use_contrib_qdq); } else { - builder.AddQuantizeLinearNode(reshape_output, .0035f, 135, q_output); - builder.AddDequantizeLinearNode(q_output, .0035f, 135, output_arg); + builder.AddQuantizeLinearNode(reshape_output, .0035f, 135, q_output, use_contrib_qdq); + builder.AddDequantizeLinearNode(q_output, .0035f, 135, output_arg, use_contrib_qdq); } }; auto check_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); EXPECT_EQ(op_to_count["Conv"], 1); EXPECT_EQ(op_to_count["QLinearConv"], 0); EXPECT_EQ(op_to_count["com.microsoft.QLinearAveragePool"], 1); EXPECT_EQ(op_to_count["Reshape"], 1); - EXPECT_EQ(op_to_count["QuantizeLinear"], 1); - EXPECT_EQ(op_to_count["DequantizeLinear"], 3); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 1); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 3); }; + // TODO: fix opset 19 TransformerTester(build_test_case, check_graph, TransformerLevel::Level1, @@ -1575,19 +1979,20 @@ TEST(QDQTransformerTests, ConvAveragePoolReshape_Int8_Fail) { 0.01f /*relative_per_sample_tolerance*/); }; - test_case({1, 12, 37}, {32, 12, 5}); - test_case({1, 23, 13, 13}, {30, 23, 3, 3}); - test_case({1, 22, 11, 13, 15}, {30, 22, 5, 3, 3}); + test_case({1, 12, 37}, {32, 12, 5}, false /*use_contrib_qdq*/); + test_case({1, 23, 13, 13}, {30, 23, 3, 3}, false /*use_contrib_qdq*/); + test_case({1, 22, 11, 13, 15}, {30, 22, 5, 3, 3}, false /*use_contrib_qdq*/); + test_case({1, 12, 37}, {32, 12, 5}, true /*use_contrib_qdq*/); } template void QDQTransformerLeakyReluTests() { - auto test_case = [&](const std::vector& input_shape) { + auto test_case = [&](const std::vector& input_shape, bool use_contrib_qdq) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput(input_shape, -1.f, 1.f); auto* output_arg = builder.MakeOutput(); // add QDQ + LeakyRelu - auto* dq_output = AddQDQNodePair(builder, input_arg, .0035f, 7); + auto* dq_output = AddQDQNodePair(builder, input_arg, .0035f, 7, use_contrib_qdq); auto* leakyrelu_output = builder.MakeIntermediate(); Node& leakyrelu_node = builder.AddNode("LeakyRelu", {dq_output}, {leakyrelu_output}); leakyrelu_node.AddAttribute("alpha", 0.2f); @@ -1597,25 +2002,26 @@ void QDQTransformerLeakyReluTests() { builder.AddQuantizeLinearNode(leakyrelu_output, .0038f, std::numeric_limits::max() / 2, - q_output); + q_output, use_contrib_qdq); builder.AddDequantizeLinearNode(q_output, .0039f, std::numeric_limits::max() / 2, - output_arg); + output_arg, use_contrib_qdq); }; auto check_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); if constexpr (std::is_same::value) { EXPECT_EQ(op_to_count["com.microsoft.QLinearLeakyRelu"], 1); EXPECT_EQ(op_to_count["LeakyRelu"], 0); - EXPECT_EQ(op_to_count["QuantizeLinear"], 1); - EXPECT_EQ(op_to_count["DequantizeLinear"], 1); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 1); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 1); } else { EXPECT_EQ(op_to_count["com.microsoft.QLinearLeakyRelu"], 0); EXPECT_EQ(op_to_count["LeakyRelu"], 1); - EXPECT_EQ(op_to_count["QuantizeLinear"], 2); - EXPECT_EQ(op_to_count["DequantizeLinear"], 2); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 2); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 2); } }; @@ -1635,11 +2041,20 @@ void QDQTransformerLeakyReluTests() { 0.01 /*per_sample_tolerance*/, 0.01 /*relative_per_sample_tolerance*/, std::make_unique(QDQIsInt8Allowed())); + TransformerTester(build_test_case, + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 19 /*opset_version*/, + 0.01 /*per_sample_tolerance*/, + 0.01 /*relative_per_sample_tolerance*/, + std::make_unique(QDQIsInt8Allowed())); }; - test_case({1, 12, 37}); - test_case({1, 23, 13, 13}); - test_case({1, 22, 11, 13, 15}); + test_case({1, 12, 37}, false /*use_contrib_qdq*/); + test_case({1, 12, 37}, true /*use_contrib_qdq*/); + test_case({1, 23, 13, 13}, false /*use_contrib_qdq*/); + test_case({1, 22, 11, 13, 15}, false /*use_contrib_qdq*/); } TEST(QDQTransformerTests, LeakyRelu_S8S8) { @@ -1660,12 +2075,12 @@ TEST(QDQTransformerTests, LeakyRelu_U8S8) { template void QDQTransformerSigmoidTests() { - auto test_case = [&](const std::vector& input_shape) { + auto test_case = [&](const std::vector& input_shape, bool use_contrib_qdq) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput(input_shape, -1.f, 1.f); auto* output_arg = builder.MakeOutput(); // add QDQ + Sigmoid - auto* dq_output = AddQDQNodePair(builder, input_arg, .0035f, 7); + auto* dq_output = AddQDQNodePair(builder, input_arg, .0035f, 7, use_contrib_qdq); auto* sigmoid_output = builder.MakeIntermediate(); builder.AddNode("Sigmoid", {dq_output}, {sigmoid_output}); @@ -1674,25 +2089,26 @@ void QDQTransformerSigmoidTests() { builder.AddQuantizeLinearNode(sigmoid_output, .0038f, std::numeric_limits::max() / 2, - q_output); + q_output, use_contrib_qdq); builder.AddDequantizeLinearNode(q_output, .0039f, std::numeric_limits::max() / 2, - output_arg); + output_arg, use_contrib_qdq); }; auto check_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); if constexpr (std::is_same::value) { EXPECT_EQ(op_to_count["com.microsoft.QLinearSigmoid"], 1); EXPECT_EQ(op_to_count["Sigmoid"], 0); - EXPECT_EQ(op_to_count["QuantizeLinear"], 1); - EXPECT_EQ(op_to_count["DequantizeLinear"], 1); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 1); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 1); } else { EXPECT_EQ(op_to_count["com.microsoft.QLinearSigmoid"], 0); EXPECT_EQ(op_to_count["Sigmoid"], 1); - EXPECT_EQ(op_to_count["QuantizeLinear"], 2); - EXPECT_EQ(op_to_count["DequantizeLinear"], 2); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 2); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 2); } }; @@ -1712,11 +2128,20 @@ void QDQTransformerSigmoidTests() { 0.01 /*per_sample_tolerance*/, 0.01 /*relative_per_sample_tolerance*/, std::make_unique(QDQIsInt8Allowed())); + TransformerTester(build_test_case, + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 19 /*opset_version*/, + 0.01 /*per_sample_tolerance*/, + 0.01 /*relative_per_sample_tolerance*/, + std::make_unique(QDQIsInt8Allowed())); }; - test_case({1, 12, 37}); - test_case({1, 23, 13, 13}); - test_case({1, 22, 11, 13, 15}); + test_case({1, 12, 37}, false /*use_contrib_qdq*/); + test_case({1, 12, 37}, true /*use_contrib_qdq*/); + test_case({1, 23, 13, 13}, false /*use_contrib_qdq*/); + test_case({1, 22, 11, 13, 15}, false /*use_contrib_qdq*/); } TEST(QDQTransformerTests, Sigmoid_S8S8) { @@ -1736,7 +2161,8 @@ TEST(QDQTransformerTests, Sigmoid_U8S8) { } TEST(QDQTransformerTests, ConvTranspose_QBackward) { - auto test_case = [&](const std::vector& input_shape, const std::vector& weights_shape, const std::vector& perms) { + auto test_case = [&](const std::vector& input_shape, const std::vector& weights_shape, + const std::vector& perms, bool use_contrib_qdq) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput(input_shape, -1.f, 1.f); auto* output_arg = builder.MakeOutput(); @@ -1745,8 +2171,8 @@ TEST(QDQTransformerTests, ConvTranspose_QBackward) { // add QDQ + Conv auto* dq_w_output = builder.MakeIntermediate(); auto* conv_output = builder.MakeIntermediate(); - auto* dq_conv_output = AddQDQNodePair(builder, input_arg, .004f, 1); - builder.AddDequantizeLinearNode(weight, .003f, -10, dq_w_output); + auto* dq_conv_output = AddQDQNodePair(builder, input_arg, .004f, 1, use_contrib_qdq); + builder.AddDequantizeLinearNode(weight, .003f, -10, dq_w_output, use_contrib_qdq); builder.AddConvNode(dq_conv_output, dq_w_output, conv_output); // add Transpose @@ -1757,20 +2183,21 @@ TEST(QDQTransformerTests, ConvTranspose_QBackward) { // add Q auto* q_output = builder.MakeIntermediate(); if constexpr (QDQIsInt8Allowed()) { - builder.AddQuantizeLinearNode(transpose_output, .0035f, 7, q_output); - builder.AddDequantizeLinearNode(q_output, .0035f, 7, output_arg); + builder.AddQuantizeLinearNode(transpose_output, .0035f, 7, q_output, use_contrib_qdq); + builder.AddDequantizeLinearNode(q_output, .0035f, 7, output_arg, use_contrib_qdq); } else { - builder.AddQuantizeLinearNode(transpose_output, .0035f, 135, q_output); - builder.AddDequantizeLinearNode(q_output, .0035f, 135, output_arg); + builder.AddQuantizeLinearNode(transpose_output, .0035f, 135, q_output, use_contrib_qdq); + builder.AddDequantizeLinearNode(q_output, .0035f, 135, output_arg, use_contrib_qdq); } }; auto check_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); EXPECT_EQ(op_to_count["QLinearConv"], 1); EXPECT_EQ(op_to_count["Transpose"], 1); - EXPECT_EQ(op_to_count["QuantizeLinear"], 1); - EXPECT_EQ(op_to_count["DequantizeLinear"], 1); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 1); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 1); }; TransformerTester(build_test_case, @@ -1779,11 +2206,13 @@ TEST(QDQTransformerTests, ConvTranspose_QBackward) { TransformerLevel::Level2); }; - test_case({1, 23, 13, 13}, {30, 23, 3, 3}, {0, 3, 1, 2}); + test_case({1, 23, 13, 13}, {30, 23, 3, 3}, {0, 3, 1, 2}, false /*use_contrib_qdq*/); + test_case({1, 23, 13, 13}, {30, 23, 3, 3}, {0, 3, 1, 2}, true /*use_contrib_qdq*/); } TEST(QDQTransformerTests, QBackward_MutilpleSteps) { - auto test_case = [&](const std::vector& input_shape, const std::vector& weights_shape) { + auto test_case = [&](const std::vector& input_shape, const std::vector& weights_shape, + bool use_contrib_qdq) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput(input_shape, -1.f, 1.f); auto* output_arg = builder.MakeOutput(); @@ -1792,8 +2221,8 @@ TEST(QDQTransformerTests, QBackward_MutilpleSteps) { // add QDQ + Conv auto* dq_w_output = builder.MakeIntermediate(); auto* conv_output = builder.MakeIntermediate(); - auto* dq_conv_output = AddQDQNodePair(builder, input_arg, .004f, 1); - builder.AddDequantizeLinearNode(weight, .003f, -10, dq_w_output); + auto* dq_conv_output = AddQDQNodePair(builder, input_arg, .004f, 1, use_contrib_qdq); + builder.AddDequantizeLinearNode(weight, .003f, -10, dq_w_output, use_contrib_qdq); builder.AddConvNode(dq_conv_output, dq_w_output, conv_output); // add MaxPool @@ -1827,22 +2256,23 @@ TEST(QDQTransformerTests, QBackward_MutilpleSteps) { // add Q + DQ auto* q_output = builder.MakeIntermediate(); if constexpr (QDQIsInt8Allowed()) { - builder.AddQuantizeLinearNode(squeeze_output, .0035f, 7, q_output); - builder.AddDequantizeLinearNode(q_output, .0035f, 7, output_arg); + builder.AddQuantizeLinearNode(squeeze_output, .0035f, 7, q_output, use_contrib_qdq); + builder.AddDequantizeLinearNode(q_output, .0035f, 7, output_arg, use_contrib_qdq); } else { - builder.AddQuantizeLinearNode(squeeze_output, .0035f, 135, q_output); - builder.AddDequantizeLinearNode(q_output, .0035f, 135, output_arg); + builder.AddQuantizeLinearNode(squeeze_output, .0035f, 135, q_output, use_contrib_qdq); + builder.AddDequantizeLinearNode(q_output, .0035f, 135, output_arg, use_contrib_qdq); } }; auto check_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); EXPECT_EQ(op_to_count["QLinearConv"], 1); EXPECT_EQ(op_to_count["MaxPool"], 1); EXPECT_EQ(op_to_count["Reshape"], 1); EXPECT_EQ(op_to_count["Transpose"], 1); - EXPECT_EQ(op_to_count["QuantizeLinear"], 1); - EXPECT_EQ(op_to_count["DequantizeLinear"], 1); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 1); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 1); }; TransformerTester(build_test_case, @@ -1850,20 +2280,28 @@ TEST(QDQTransformerTests, QBackward_MutilpleSteps) { TransformerLevel::Level1, TransformerLevel::Level2, 13 /*opset_version*/); + TransformerTester(build_test_case, + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 18 /*opset_version*/); + // TODO: fix opset 19 }; - test_case({1, 23, 13, 13}, {30, 23, 3, 3}); + test_case({1, 23, 13, 13}, {30, 23, 3, 3}, false /*use_contrib_qdq*/); + test_case({1, 23, 13, 13}, {30, 23, 3, 3}, true /*use_contrib_qdq*/); } TEST(QDQTransformerTests, ConvTranspose_DQForward) { - auto test_case = [&](const std::vector& input_shape, const std::vector& weights_shape, const std::vector& perms) { + auto test_case = [&](const std::vector& input_shape, const std::vector& weights_shape, + const std::vector& perms, bool use_contrib_qdq) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput(input_shape, -1.f, 1.f); auto* output_arg = builder.MakeOutput(); auto* weight = builder.MakeInitializer(weights_shape, -64, 64); // add QDQ - auto* dq_output = AddQDQNodePair(builder, input_arg, .004f, 1); + auto* dq_output = AddQDQNodePair(builder, input_arg, .004f, 1, use_contrib_qdq); // add Transpose auto* transpose_output = builder.MakeIntermediate(); @@ -1873,26 +2311,27 @@ TEST(QDQTransformerTests, ConvTranspose_DQForward) { // add Conv auto* dq_w_output = builder.MakeIntermediate(); auto* conv_output = builder.MakeIntermediate(); - builder.AddDequantizeLinearNode(weight, .003f, -10, dq_w_output); + builder.AddDequantizeLinearNode(weight, .003f, -10, dq_w_output, use_contrib_qdq); builder.AddConvNode(transpose_output, dq_w_output, conv_output); // add Q auto* q_output = builder.MakeIntermediate(); if constexpr (QDQIsInt8Allowed()) { - builder.AddQuantizeLinearNode(conv_output, .0035f, 7, q_output); - builder.AddDequantizeLinearNode(q_output, .0035f, 7, output_arg); + builder.AddQuantizeLinearNode(conv_output, .0035f, 7, q_output, use_contrib_qdq); + builder.AddDequantizeLinearNode(q_output, .0035f, 7, output_arg, use_contrib_qdq); } else { - builder.AddQuantizeLinearNode(conv_output, .0035f, 135, q_output); - builder.AddDequantizeLinearNode(q_output, .0035f, 135, output_arg); + builder.AddQuantizeLinearNode(conv_output, .0035f, 135, q_output, use_contrib_qdq); + builder.AddDequantizeLinearNode(q_output, .0035f, 135, output_arg, use_contrib_qdq); } }; auto check_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); EXPECT_EQ(op_to_count["QLinearConv"], 1); EXPECT_EQ(op_to_count["Transpose"], 1); - EXPECT_EQ(op_to_count["QuantizeLinear"], 1); - EXPECT_EQ(op_to_count["DequantizeLinear"], 1); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 1); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 1); }; TransformerTester(build_test_case, @@ -1901,20 +2340,34 @@ TEST(QDQTransformerTests, ConvTranspose_DQForward) { TransformerLevel::Level2, 12, 0.0, 0.0, nullptr, {}, // defaults that we're not overriding {"TransposeOptimizer"}); // disable TransposeOptimizer for simplicity + TransformerTester(build_test_case, + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 18, 0.0, 0.0, nullptr, {}, // defaults that we're not overriding + {"TransposeOptimizer"}); // disable TransposeOptimizer for simplicity + TransformerTester(build_test_case, + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 19, 0.0, 0.0, nullptr, {}, // defaults that we're not overriding + {"TransposeOptimizer"}); // disable TransposeOptimizer for simplicity }; - test_case({1, 13, 13, 23}, {30, 23, 3, 3}, {0, 3, 1, 2}); + test_case({1, 13, 13, 23}, {30, 23, 3, 3}, {0, 3, 1, 2}, false /*use_contrib_qdq*/); + test_case({1, 13, 13, 23}, {30, 23, 3, 3}, {0, 3, 1, 2}, true /*use_contrib_qdq*/); } TEST(QDQTransformerTests, DQForward_MutilpleSteps) { - auto test_case = [&](const std::vector& input_shape, const std::vector& weights_shape, const std::vector& perms) { + auto test_case = [&](const std::vector& input_shape, const std::vector& weights_shape, + const std::vector& perms, bool use_contrib_qdq) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput(input_shape, -1.f, 1.f); auto* output_arg = builder.MakeOutput(); auto* weight = builder.MakeInitializer(weights_shape, -64, 64); // add Transpose - auto* qdq_output = AddQDQNodePair(builder, input_arg, .004f, 1); + auto* qdq_output = AddQDQNodePair(builder, input_arg, .004f, 1, use_contrib_qdq); auto* transpose_output = builder.MakeIntermediate(); Node& transpose_node = builder.AddNode("Transpose", {qdq_output}, {transpose_output}); transpose_node.AddAttribute("perm", perms); @@ -1940,7 +2393,7 @@ TEST(QDQTransformerTests, DQForward_MutilpleSteps) { // add Conv auto* dq_w_output = builder.MakeIntermediate(); auto* conv_output = builder.MakeIntermediate(); - builder.AddDequantizeLinearNode(weight, .003f, -10, dq_w_output); + builder.AddDequantizeLinearNode(weight, .003f, -10, dq_w_output, use_contrib_qdq); builder.AddConvNode(squeeze_output, dq_w_output, conv_output); // Reshape @@ -1951,22 +2404,23 @@ TEST(QDQTransformerTests, DQForward_MutilpleSteps) { // add Q + DQ auto* q_output = builder.MakeIntermediate(); if constexpr (QDQIsInt8Allowed()) { - builder.AddQuantizeLinearNode(reshape_output, .0035f, 7, q_output); - builder.AddDequantizeLinearNode(q_output, .0035f, 7, output_arg); + builder.AddQuantizeLinearNode(reshape_output, .0035f, 7, q_output, use_contrib_qdq); + builder.AddDequantizeLinearNode(q_output, .0035f, 7, output_arg, use_contrib_qdq); } else { - builder.AddQuantizeLinearNode(reshape_output, .0035f, 135, q_output); - builder.AddDequantizeLinearNode(q_output, .0035f, 135, output_arg); + builder.AddQuantizeLinearNode(reshape_output, .0035f, 135, q_output, use_contrib_qdq); + builder.AddDequantizeLinearNode(q_output, .0035f, 135, output_arg, use_contrib_qdq); } }; auto check_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); EXPECT_EQ(op_to_count["QLinearConv"], 1); EXPECT_EQ(op_to_count["MaxPool"], 1); EXPECT_EQ(op_to_count["Reshape"], 1); EXPECT_EQ(op_to_count["Transpose"], 1); - EXPECT_EQ(op_to_count["QuantizeLinear"], 1); - EXPECT_EQ(op_to_count["DequantizeLinear"], 1); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 1); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 1); }; TransformerTester(build_test_case, @@ -1976,15 +2430,25 @@ TEST(QDQTransformerTests, DQForward_MutilpleSteps) { 13 /*opset_version*/, 0.0, 0.0, nullptr, {}, // defaults that we're not overriding {"TransposeOptimizer"}); // disable TransposeOptimizer for simplicity + TransformerTester(build_test_case, + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 18 /*opset_version*/, + 0.0, 0.0, nullptr, {}, // defaults that we're not overriding + {"TransposeOptimizer"}); // disable TransposeOptimizer for simplicity + // TODO: fix opset 19 }; - test_case({1, 13, 13, 23}, {30, 23, 3, 3}, {0, 3, 1, 2}); + test_case({1, 13, 13, 23}, {30, 23, 3, 3}, {0, 3, 1, 2}, false /*use_contrib_qdq*/); + test_case({1, 13, 13, 23}, {30, 23, 3, 3}, {0, 3, 1, 2}, true /*use_contrib_qdq*/); } TEST(QDQTransformerTests, Clip) { constexpr float epsilon = std::numeric_limits::epsilon(); - auto test_case = [&](float scale, auto zero_point, int clip_count, int opset_version) { + auto test_case = [&](float scale, auto zero_point, int clip_count, int opset_version, + bool use_contrib_qdq = false) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput({1, 32, 112, 112}, std::numeric_limits::min(), @@ -1993,7 +2457,7 @@ TEST(QDQTransformerTests, Clip) { // add DQ auto* dq_output = builder.MakeIntermediate(); - builder.AddDequantizeLinearNode(input_arg, .0035f, 7, dq_output); + builder.AddDequantizeLinearNode(input_arg, .0035f, 7, dq_output, use_contrib_qdq); // add Clip auto* clip_output = builder.MakeIntermediate(); @@ -2013,15 +2477,16 @@ TEST(QDQTransformerTests, Clip) { // add Q + DQ auto* q_output = builder.MakeIntermediate(); - builder.AddQuantizeLinearNode(clip_output, scale, zero_point, q_output); - builder.AddDequantizeLinearNode(q_output, scale, zero_point, output_arg); + builder.AddQuantizeLinearNode(clip_output, scale, zero_point, q_output, use_contrib_qdq); + builder.AddDequantizeLinearNode(q_output, scale, zero_point, output_arg, use_contrib_qdq); }; auto check_clip_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); - EXPECT_EQ(op_to_count["QuantizeLinear"], 1); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 1); EXPECT_EQ(op_to_count["Clip"], clip_count); - EXPECT_EQ(op_to_count["DequantizeLinear"], 2); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 2); }; TransformerTester(build_test_case, check_clip_graph, @@ -2032,51 +2497,81 @@ TEST(QDQTransformerTests, Clip) { epsilon); }; - std::vector opsets{12, 18}; + constexpr int16_t int16_min = std::numeric_limits::min(); + constexpr uint16_t uint16_min = std::numeric_limits::min(); + + std::vector opsets{12, 18, 19}; for (auto opset : opsets) { - test_case(.0235294122248888f, static_cast(-128), 0, opset); // [0, 6] - test_case(.02f, static_cast(-128), 0, opset); // [0, 5.1] - test_case(.03f, static_cast(-128), 1, opset); // [0, 7.65] - test_case(.02f, static_cast(127), 1, opset); // [-5.1 , 0] - test_case(.02f, static_cast(0), 1, opset); // [-2.56, 2.54] - test_case(.04f, static_cast(-97), 1, opset); // [-1.24, 8.96] - test_case(.02352941176f, static_cast(0), 0, opset); // [0, 6] - test_case(.02f, static_cast(0), 0, opset); // [0, 5.1] - test_case(.03f, static_cast(0), 1, opset); // [0, 7.65] - test_case(.02f, static_cast(255), 1, opset); // [-5.1, 0] - test_case(.02f, static_cast(128), 1, opset); // [-2.56, 2.54] - test_case(.04f, static_cast(31), 1, opset); // [-1.24, 8.96] + test_case(.0235294122248888f, static_cast(-128), 0, opset); // [0, 6] + test_case(.0235294122248888f, static_cast(-128), 0, opset, true); // [0, 6] contrib qdq + test_case(9.15541313801785e-5f, int16_min, 0, opset, true); // [0, 6] contrib 16-bit qdq + test_case(0.0009f, int16_min, 1, opset, true); // [0, 58.98] contrib 16-bit qdq + test_case(.02f, static_cast(-128), 0, opset); // [0, 5.1] + test_case(.02f, static_cast(-128), 0, opset, true); // [0, 5.1] contrib qdq + test_case(.03f, static_cast(-128), 1, opset); // [0, 7.65] + test_case(.03f, static_cast(-128), 1, opset, true); // [0, 7.65] contrib qdq + test_case(.02f, static_cast(127), 1, opset); // [-5.1 , 0] + test_case(.02f, static_cast(127), 1, opset, true); // [-5.1 , 0] contrib qdq + test_case(.02f, static_cast(0), 1, opset); // [-2.56, 2.54] + test_case(.02f, static_cast(0), 1, opset, true); // [-2.56, 2.54] contrib qdq + test_case(.04f, static_cast(-97), 1, opset); // [-1.24, 8.96] + test_case(.04f, static_cast(-97), 1, opset, true); // [-1.24, 8.96] contrib qdq + test_case(.02352941176f, static_cast(0), 0, opset); // [0, 6] + test_case(.02352941176f, static_cast(0), 0, opset, true); // [0, 6] contrib qdq + test_case(9.15541313801785e-5f, uint16_min, 0, opset, true); // [0, 6] contrib 16-bit qdq + test_case(0.0009f, uint16_min, 1, opset, true); // [0, 58.98] contrib 16-bit qdq + test_case(.02f, static_cast(0), 0, opset); // [0, 5.1] + test_case(.02f, static_cast(0), 0, opset, true); // [0, 5.1] contrib qdq + test_case(.03f, static_cast(0), 1, opset); // [0, 7.65] + test_case(.03f, static_cast(0), 1, opset, true); // [0, 7.65] contrib qdq + test_case(.02f, static_cast(255), 1, opset); // [-5.1, 0] + test_case(.02f, static_cast(255), 1, opset, true); // [-5.1, 0] contrib qdq + test_case(.02f, static_cast(128), 1, opset); // [-2.56, 2.54] + test_case(.02f, static_cast(128), 1, opset, true); // [-2.56, 2.54] contrib qdq + test_case(.04f, static_cast(31), 1, opset); // [-1.24, 8.96] + test_case(.04f, static_cast(31), 1, opset, true); // [-1.24, 8.96] contrib qdq } // opset_version = 10 - test_case(.02f, static_cast(-128), 0, 10); // [0, 5.1] - test_case(.03f, static_cast(-128), 1, 10); // [0, 7.65] - test_case(.02f, static_cast(0), 0, 10); // [0, 5.1] - test_case(.03f, static_cast(0), 1, 10); // [0, 7.65] + test_case(.02f, static_cast(-128), 0, 10); // [0, 5.1] + test_case(.02f, static_cast(-128), 0, 10, true); // [0, 5.1] contrib qdq + test_case(.03f, static_cast(-128), 1, 10); // [0, 7.65] + test_case(.03f, static_cast(-128), 1, 10, true); // [0, 7.65] contrib qdq + test_case(.02f, static_cast(0), 0, 10); // [0, 5.1] + test_case(.02f, static_cast(0), 0, 10, true); // [0, 5.1] contrib qdq + test_case(.03f, static_cast(0), 1, 10); // [0, 7.65] + test_case(.03f, static_cast(0), 1, 10, true); // [0, 7.65] contrib qdq // difference between lower/upper and min/max are within epsilon for (auto opset : opsets) { - test_case(epsilon, static_cast(-127), 0, opset); // [-epsilon, x] (x <= 6 + epsilon) - test_case((6 + epsilon) / 255, static_cast(-128), 0, opset); // [0, 6 + epsilon] - test_case(epsilon, static_cast(1), 0, opset); // [-epsilon, x] (x <= 6 + epsilon) - test_case((6 + epsilon) / 255, static_cast(0), 0, opset); // [0, 6 + epsilon] + test_case(epsilon, static_cast(-127), 0, opset); // [-epsilon, x] (x <= 6 + epsilon) + test_case(epsilon, static_cast(-127), 0, opset, true); // [-epsilon, x] (x <= 6 + epsilon) + test_case((6 + epsilon) / 255, static_cast(-128), 0, opset); // [0, 6 + epsilon] + test_case((6 + epsilon) / 255, static_cast(-128), 0, opset, true); // [0, 6 + epsilon] + test_case(epsilon, static_cast(1), 0, opset); // [-epsilon, x] (x <= 6 + epsilon) + test_case(epsilon, static_cast(1), 0, opset, true); // [-epsilon, x] (x <= 6 + epsilon) + test_case((6 + epsilon) / 255, static_cast(0), 0, opset); // [0, 6 + epsilon] + test_case((6 + epsilon) / 255, static_cast(0), 0, opset, true); // [0, 6 + epsilon] } } TEST(QDQTransformerTests, Concat) { auto test_case = [&](const std::vector>& input_shapes, int64_t axis, - bool has_input_float = false, - bool has_input_int8 = false, - bool has_output_int8 = false) { - auto check_graph = [&input_shapes, &has_input_float, &has_input_int8, &has_output_int8](InferenceSessionWrapper& session) { + bool has_input_float, + bool has_input_int8, + bool has_output_int8, + bool use_contrib_qdq) { + auto check_graph = [&input_shapes, has_input_float, has_input_int8, has_output_int8, + use_contrib_qdq](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); if (has_input_float || has_input_int8 || has_output_int8) { EXPECT_EQ(op_to_count["com.microsoft.QLinearConcat"], 0); } else { - EXPECT_EQ(op_to_count["QuantizeLinear"], static_cast(input_shapes.size())); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], static_cast(input_shapes.size())); EXPECT_EQ(op_to_count["com.microsoft.QLinearConcat"], 1); - EXPECT_EQ(op_to_count["DequantizeLinear"], 1); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 1); } }; @@ -2084,7 +2579,8 @@ TEST(QDQTransformerTests, Concat) { axis, has_input_float, has_input_int8, - has_output_int8), + has_output_int8, + use_contrib_qdq), check_graph, TransformerLevel::Level1, TransformerLevel::Level2, @@ -2092,24 +2588,91 @@ TEST(QDQTransformerTests, Concat) { 0.01f /*per_sample_tolerance*/, 0.01f /*relative_per_sample_tolerance*/, std::make_unique(QDQIsInt8Allowed())); + TransformerTester(BuildQDQConcatTestCase(input_shapes, + axis, + has_input_float, + has_input_int8, + has_output_int8, + use_contrib_qdq), + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 18 /*opset_version*/, + 0.01f /*per_sample_tolerance*/, + 0.01f /*relative_per_sample_tolerance*/, + std::make_unique(QDQIsInt8Allowed())); + TransformerTester(BuildQDQConcatTestCase(input_shapes, + axis, + has_input_float, + has_input_int8, + has_output_int8, + use_contrib_qdq), + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 19 /*opset_version*/, + 0.01f /*per_sample_tolerance*/, + 0.01f /*relative_per_sample_tolerance*/, + std::make_unique(QDQIsInt8Allowed())); }; - test_case({{1, 6, 36}, {1, 3, 36}}, 1); - test_case({{1, 6, 36}, {1, 6, 8}, {1, 6, 2}}, 2); - test_case({{1, 6, 36}, {1, 6, 8}, {1, 6, 2}}, 2, true); - test_case({{1, 6, 36}, {1, 6, 8}, {1, 6, 2}}, 2, false, true); - test_case({{1, 6, 36}, {1, 6, 8}, {1, 6, 2}}, 2, false, false, true); + test_case({{1, 6, 36}, {1, 3, 36}}, 1, + false, // has_input_float + false, // has_input_int8 + false, // has_output_int8 + false); // use_contrib_qdq + test_case({{1, 6, 36}, {1, 3, 36}}, 1, + false, // has_input_float + false, // has_input_int8 + false, // has_output_int8 + true); // use_contrib_qdq + test_case({{1, 6, 36}, {1, 6, 8}, {1, 6, 2}}, 2, + false, // has_input_float + false, // has_input_int8 + false, // has_output_int8 + false); // use_contrib_qdq + test_case({{1, 6, 36}, {1, 6, 8}, {1, 6, 2}}, 2, + true, // has_input_float + false, // has_input_int8 + false, // has_output_int8 + false); // use_contrib_qdq + test_case({{1, 6, 36}, {1, 6, 8}, {1, 6, 2}}, 2, + true, // has_input_float + false, // has_input_int8 + false, // has_output_int8 + true); // use_contrib_qdq + test_case({{1, 6, 36}, {1, 6, 8}, {1, 6, 2}}, 2, + false, // has_input_float + true, // has_input_int8 + false, // has_output_int8 + false); // use_contrib_qdq + test_case({{1, 6, 36}, {1, 6, 8}, {1, 6, 2}}, 2, + false, // has_input_float + true, // has_input_int8 + false, // has_output_int8 + true); // use_contrib_qdq + test_case({{1, 6, 36}, {1, 6, 8}, {1, 6, 2}}, 2, + false, // has_input_float + false, // has_input_int8 + true, // has_output_int8 + false); // use_contrib_qdq + test_case({{1, 6, 36}, {1, 6, 8}, {1, 6, 2}}, 2, + false, // has_input_float + false, // has_input_int8 + true, // has_output_int8 + true); // use_contrib_qdq } template void QDQTransformerSoftmaxTests() { - auto test_case = [&](const std::vector& input_shape, int64_t axis) { + auto test_case = [&](const std::vector& input_shape, int64_t axis, bool use_contrib_qdq) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput(input_shape, -5.f, 5.f); auto* output_arg = builder.MakeOutput(); // add QDQ + Softmax auto* dq_output = AddQDQNodePair(builder, input_arg, .105f, - (std::numeric_limits::max() / 255 * 255) / 2); + (std::numeric_limits::max() / 255 * 255) / 2, + use_contrib_qdq); auto* softmax_output = builder.MakeIntermediate(); auto& softmax_node = builder.AddNode("Softmax", {dq_output}, {softmax_output}); softmax_node.AddAttribute("axis", axis); @@ -2118,25 +2681,26 @@ void QDQTransformerSoftmaxTests() { builder.AddQuantizeLinearNode(softmax_output, 1.0f / (std::numeric_limits::max() + 1), 0, - q_output); + q_output, use_contrib_qdq); builder.AddDequantizeLinearNode(q_output, 1.0f / (std::numeric_limits::max() + 1), 0, - output_arg); + output_arg, use_contrib_qdq); }; auto check_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); if constexpr (std::is_same::value) { EXPECT_EQ(op_to_count["com.microsoft.QLinearSoftmax"], 1); EXPECT_EQ(op_to_count["Softmax"], 0); - EXPECT_EQ(op_to_count["QuantizeLinear"], 1); - EXPECT_EQ(op_to_count["DequantizeLinear"], 1); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 1); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 1); } else { EXPECT_EQ(op_to_count["com.microsoft.QLinearSoftmax"], 0); EXPECT_EQ(op_to_count["Softmax"], 1); - EXPECT_EQ(op_to_count["QuantizeLinear"], 2); - EXPECT_EQ(op_to_count["DequantizeLinear"], 2); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 2); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 2); } }; @@ -2148,10 +2712,27 @@ void QDQTransformerSoftmaxTests() { 0.01 /*per_sample_tolerance*/, 0.01 /*relative_per_sample_tolerance*/, std::make_unique(QDQIsInt8Allowed())); + TransformerTester(build_test_case, + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 18 /*opset_version*/, + 0.01 /*per_sample_tolerance*/, + 0.01 /*relative_per_sample_tolerance*/, + std::make_unique(QDQIsInt8Allowed())); + TransformerTester(build_test_case, + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 19 /*opset_version*/, + 0.01 /*per_sample_tolerance*/, + 0.01 /*relative_per_sample_tolerance*/, + std::make_unique(QDQIsInt8Allowed())); }; - test_case({1, 12, 37}, -1); - test_case({1, 23, 13, 13}, -2); + test_case({1, 12, 37}, -1, false /*use_contrib_qdq*/); + test_case({1, 12, 37}, -1, true /*use_contrib_qdq*/); + test_case({1, 23, 13, 13}, -2, false /*use_contrib_qdq*/); } TEST(QDQTransformerTests, Softmax_S8S8) { @@ -2169,7 +2750,8 @@ TEST(QDQTransformerTests, QDQPropagation_QBackward) { size_t maxpool_dim, const std::vector& perms, bool add_op_boundary, - bool include_zp) { + bool include_zp, + bool use_contrib_qdq) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput(input_shape, -1.f, 1.f); auto* output_arg = builder.MakeOutput(); @@ -2202,28 +2784,29 @@ TEST(QDQTransformerTests, QDQPropagation_QBackward) { constexpr float qdq_scale = 0.004f; if (include_zp) { constexpr uint8_t qdq_zero_point = 129; - builder.AddQuantizeLinearNode(reshape_output, qdq_scale, qdq_zero_point, output_arg); + builder.AddQuantizeLinearNode(reshape_output, qdq_scale, qdq_zero_point, output_arg, use_contrib_qdq); } else { - builder.AddQuantizeLinearNode(reshape_output, qdq_scale, output_arg); + builder.AddQuantizeLinearNode(reshape_output, qdq_scale, output_arg, use_contrib_qdq); } }; auto check_graph = [&](InferenceSessionWrapper& session) { + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); std::vector expected_op_types_in_order{}; if (add_op_boundary) { expected_op_types_in_order.push_back("Sign"); } expected_op_types_in_order.insert( expected_op_types_in_order.end(), - {"QuantizeLinear", "DequantizeLinear", + {qdq_keys.quantize_linear, qdq_keys.dequantize_linear, "Transpose", - "QuantizeLinear", "DequantizeLinear", + qdq_keys.quantize_linear, qdq_keys.dequantize_linear, "MaxPool", - "QuantizeLinear", "DequantizeLinear", + qdq_keys.quantize_linear, qdq_keys.dequantize_linear, "Reshape", - "QuantizeLinear"}); + qdq_keys.quantize_linear}); - const auto op_types_in_order = GetNodeOpTypesInTopologicalOrder(session.GetGraph()); + const auto op_types_in_order = GetNodeOpTypesInTopologicalOrder(session.GetGraph(), true); EXPECT_EQ(op_types_in_order, expected_op_types_in_order); }; @@ -2233,10 +2816,13 @@ TEST(QDQTransformerTests, QDQPropagation_QBackward) { TransformerLevel::Level1); }; - test_case({1, 13, 13, 23}, 4, {0, 3, 1, 2}, false, false); - test_case({1, 13, 13, 23}, 4, {0, 3, 1, 2}, false, true); - test_case({1, 13, 13, 23}, 4, {0, 3, 1, 2}, true, false); - test_case({1, 13, 13, 23}, 4, {0, 3, 1, 2}, true, true); + test_case({1, 13, 13, 23}, 4, {0, 3, 1, 2}, false, false, false /*use_contrib_qdq*/); + test_case({1, 13, 13, 23}, 4, {0, 3, 1, 2}, false, true, false /*use_contrib_qdq*/); + test_case({1, 13, 13, 23}, 4, {0, 3, 1, 2}, true, false, false /*use_contrib_qdq*/); + test_case({1, 13, 13, 23}, 4, {0, 3, 1, 2}, true, true, false /*use_contrib_qdq*/); +#if !defined(DISABLE_CONTRIB_OPS) + test_case({1, 13, 13, 23}, 4, {0, 3, 1, 2}, false, false, true /*use_contrib_qdq*/); +#endif } TEST(QDQTransformerTests, QDQPropagation_DQForward) { @@ -2244,7 +2830,8 @@ TEST(QDQTransformerTests, QDQPropagation_DQForward) { size_t maxpool_dim, const std::vector& perms, bool add_op_boundary, - bool include_zp) { + bool include_zp, + bool use_contrib_qdq) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput(input_shape, std::numeric_limits::min(), @@ -2256,9 +2843,9 @@ TEST(QDQTransformerTests, QDQPropagation_DQForward) { auto* dq_output = builder.MakeIntermediate(); if (include_zp) { constexpr uint8_t qdq_zero_point = 129; - builder.AddDequantizeLinearNode(input_arg, qdq_scale, qdq_zero_point, dq_output); + builder.AddDequantizeLinearNode(input_arg, qdq_scale, qdq_zero_point, dq_output, use_contrib_qdq); } else { - builder.AddDequantizeLinearNode(input_arg, qdq_scale, dq_output); + builder.AddDequantizeLinearNode(input_arg, qdq_scale, dq_output, use_contrib_qdq); } // add Transpose @@ -2286,19 +2873,20 @@ TEST(QDQTransformerTests, QDQPropagation_DQForward) { }; auto check_graph = [&](InferenceSessionWrapper& session) { + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); std::vector expected_op_types_in_order{ - "DequantizeLinear", + qdq_keys.dequantize_linear, "Transpose", - "QuantizeLinear", "DequantizeLinear", + qdq_keys.quantize_linear, qdq_keys.dequantize_linear, "MaxPool", - "QuantizeLinear", "DequantizeLinear", + qdq_keys.quantize_linear, qdq_keys.dequantize_linear, "Reshape", - "QuantizeLinear", "DequantizeLinear"}; + qdq_keys.quantize_linear, qdq_keys.dequantize_linear}; if (add_op_boundary) { expected_op_types_in_order.push_back("Sign"); } - const auto op_types_in_order = GetNodeOpTypesInTopologicalOrder(session.GetGraph()); + const auto op_types_in_order = GetNodeOpTypesInTopologicalOrder(session.GetGraph(), true); EXPECT_EQ(op_types_in_order, expected_op_types_in_order); }; @@ -2308,22 +2896,36 @@ TEST(QDQTransformerTests, QDQPropagation_DQForward) { TransformerLevel::Level1, 12, 0.0, 0.0, nullptr, {}, // defaults that we're not overriding {"TransposeOptimizer"}); // disable TransposeOptimizer for simplicity + TransformerTester(build_test_case, + check_graph, + TransformerLevel::Default, + TransformerLevel::Level1, + 18, 0.0, 0.0, nullptr, {}, // defaults that we're not overriding + {"TransposeOptimizer"}); // disable TransposeOptimizer for simplicity + // TODO: fix opset 19 }; - test_case({1, 13, 13, 23}, 4, {0, 3, 1, 2}, false, false); - test_case({1, 13, 13, 23}, 4, {0, 3, 1, 2}, false, true); - test_case({1, 13, 13, 23}, 4, {0, 3, 1, 2}, true, false); - test_case({1, 13, 13, 23}, 4, {0, 3, 1, 2}, true, true); + test_case({1, 13, 13, 23}, 4, {0, 3, 1, 2}, false, false, false /*use_contrib_qdq*/); + test_case({1, 13, 13, 23}, 4, {0, 3, 1, 2}, false, true, false /*use_contrib_qdq*/); + test_case({1, 13, 13, 23}, 4, {0, 3, 1, 2}, true, false, false /*use_contrib_qdq*/); + test_case({1, 13, 13, 23}, 4, {0, 3, 1, 2}, true, true, false /*use_contrib_qdq*/); +#if !defined(DISABLE_CONTRIB_OPS) + test_case({1, 13, 13, 23}, 4, {0, 3, 1, 2}, false, false, true /*use_contrib_qdq*/); + test_case({1, 13, 13, 23}, 4, {0, 3, 1, 2}, false, true, true /*use_contrib_qdq*/); + test_case({1, 13, 13, 23}, 4, {0, 3, 1, 2}, true, false, true /*use_contrib_qdq*/); + test_case({1, 13, 13, 23}, 4, {0, 3, 1, 2}, true, true, true /*use_contrib_qdq*/); +#endif } TEST(QDQTransformerTests, QDQPropagation_StopAtOtherQDQ) { - auto test_case = [&](const std::vector& input_shape, bool same_scale, bool same_zp) { + auto test_case = [&](const std::vector& input_shape, bool same_scale, bool same_zp, + bool use_contrib_qdq) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput(input_shape, -1.f, 1.f); auto* output_arg = builder.MakeOutput(); // add QDQ - auto* qdq_output = AddQDQNodePair(builder, input_arg, .004f, 129); + auto* qdq_output = AddQDQNodePair(builder, input_arg, .004f, 129, use_contrib_qdq); // Reshape auto* reshape_output = builder.MakeIntermediate(); @@ -2331,15 +2933,18 @@ TEST(QDQTransformerTests, QDQPropagation_StopAtOtherQDQ) { builder.AddNode("Reshape", {qdq_output, reshape_shape}, {reshape_output}); // add Q - builder.AddQuantizeLinearNode(reshape_output, same_scale ? .004f : .0039f, same_zp ? 129 : 128, output_arg); + builder.AddQuantizeLinearNode(reshape_output, same_scale ? .004f : .0039f, same_zp ? 129 : 128, + output_arg, use_contrib_qdq); }; auto check_graph = [&](InferenceSessionWrapper& session) { + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); const std::vector expected_op_types_in_order{ - "QuantizeLinear", "DequantizeLinear", + qdq_keys.quantize_linear, + qdq_keys.dequantize_linear, "Reshape", - "QuantizeLinear"}; - const auto op_types_in_order = GetNodeOpTypesInTopologicalOrder(session.GetGraph()); + qdq_keys.quantize_linear}; + const auto op_types_in_order = GetNodeOpTypesInTopologicalOrder(session.GetGraph(), true); EXPECT_EQ(op_types_in_order, expected_op_types_in_order); }; @@ -2349,14 +2954,23 @@ TEST(QDQTransformerTests, QDQPropagation_StopAtOtherQDQ) { TransformerLevel::Level1); }; - test_case({1, 13, 13, 23}, false, false); - test_case({1, 13, 13, 23}, false, true); - test_case({1, 13, 13, 23}, true, false); - test_case({1, 13, 13, 23}, true, true); + test_case({1, 13, 13, 23}, false, false, false); + test_case({1, 13, 13, 23}, false, true, false); + test_case({1, 13, 13, 23}, true, false, false); + test_case({1, 13, 13, 23}, true, true, false); + +#if !defined(DISABLE_CONTRIB_OPS) + // Use contrib QDQ ops + test_case({1, 13, 13, 23}, false, false, true); + test_case({1, 13, 13, 23}, false, true, true); + test_case({1, 13, 13, 23}, true, false, true); + test_case({1, 13, 13, 23}, true, true, true); +#endif } TEST(QDQTransformerTests, QDQPropagation_Q_No_Parent) { - auto test_case = [&](const std::vector& input_shape, const std::vector& perms) { + auto test_case = [&](const std::vector& input_shape, const std::vector& perms, + bool use_contrib_qdq) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput(input_shape, -1.f, 1.f); auto* output_arg = builder.MakeOutput(); @@ -2367,15 +2981,17 @@ TEST(QDQTransformerTests, QDQPropagation_Q_No_Parent) { transpose_node.AddAttribute("perm", perms); // add Q - builder.AddQuantizeLinearNode(transpose_output, .0035f, 135, output_arg); + builder.AddQuantizeLinearNode(transpose_output, .0035f, 135, output_arg, use_contrib_qdq); }; auto check_graph = [&](InferenceSessionWrapper& session) { + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); const std::vector expected_op_types_in_order{ - "QuantizeLinear", "DequantizeLinear", + qdq_keys.quantize_linear, + qdq_keys.dequantize_linear, "Transpose", - "QuantizeLinear"}; - const auto op_types_in_order = GetNodeOpTypesInTopologicalOrder(session.GetGraph()); + qdq_keys.quantize_linear}; + const auto op_types_in_order = GetNodeOpTypesInTopologicalOrder(session.GetGraph(), true); EXPECT_EQ(op_types_in_order, expected_op_types_in_order); }; @@ -2385,11 +3001,15 @@ TEST(QDQTransformerTests, QDQPropagation_Q_No_Parent) { TransformerLevel::Level1); }; - test_case({1, 13, 13, 23}, {0, 2, 3, 1}); + test_case({1, 13, 13, 23}, {0, 2, 3, 1}, false /*use_contrib_qdq*/); +#if !defined(DISABLE_CONTRIB_OPS) + test_case({1, 13, 13, 23}, {0, 2, 3, 1}, true /*use_contrib_qdq*/); +#endif } TEST(QDQTransformerTests, QDQPropagation_DQ_No_Children) { - auto test_case = [&](const std::vector& input_shape, const std::vector& perms) { + auto test_case = [&](const std::vector& input_shape, const std::vector& perms, + bool use_contrib_qdq) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput(input_shape, std::numeric_limits::min(), @@ -2398,7 +3018,7 @@ TEST(QDQTransformerTests, QDQPropagation_DQ_No_Children) { // add DQ auto* dq_output = builder.MakeIntermediate(); - builder.AddDequantizeLinearNode(input_arg, .0035f, 135, dq_output); + builder.AddDequantizeLinearNode(input_arg, .0035f, 135, dq_output, use_contrib_qdq); // add transpose Node& transpose_node = builder.AddNode("Transpose", {dq_output}, {output_arg}); @@ -2406,11 +3026,12 @@ TEST(QDQTransformerTests, QDQPropagation_DQ_No_Children) { }; auto check_graph = [&](InferenceSessionWrapper& session) { + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); const std::vector expected_op_types_in_order{ - "DequantizeLinear", + qdq_keys.dequantize_linear, "Transpose", - "QuantizeLinear", "DequantizeLinear"}; - const auto op_types_in_order = GetNodeOpTypesInTopologicalOrder(session.GetGraph()); + qdq_keys.quantize_linear, qdq_keys.dequantize_linear}; + const auto op_types_in_order = GetNodeOpTypesInTopologicalOrder(session.GetGraph(), true); EXPECT_EQ(op_types_in_order, expected_op_types_in_order); }; @@ -2420,22 +3041,27 @@ TEST(QDQTransformerTests, QDQPropagation_DQ_No_Children) { TransformerLevel::Level1); }; - test_case({1, 13, 13, 23}, {0, 2, 3, 1}); + test_case({1, 13, 13, 23}, {0, 2, 3, 1}, false /*use_contrib_qdq*/); +#if !defined(DISABLE_CONTRIB_OPS) + test_case({1, 13, 13, 23}, {0, 2, 3, 1}, true /*use_contrib_qdq*/); +#endif } TEST(QDQTransformerTests, QDQPropagation_Per_Layer_No_Propagation) { - auto test_case = [&](const std::vector& input_shape, const std::vector& perms) { + auto test_case = [&](const std::vector& input_shape, const std::vector& perms, + bool use_contrib_qdq) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput(input_shape, std::numeric_limits::min(), std::numeric_limits::max()); auto* output_arg = builder.MakeOutput(); - // add DQ + // add DQ with per layer scale and zp values auto* dq_output = builder.MakeIntermediate(); auto* dq_scale = builder.Make1DInitializer(std::vector(input_shape[1], 0.0035f)); auto* dq_zp = builder.Make1DInitializer(std::vector(input_shape[1], 135)); - builder.AddNode("DequantizeLinear", {input_arg, dq_scale, dq_zp}, {dq_output}); + builder.AddNode("DequantizeLinear", {input_arg, dq_scale, dq_zp}, {dq_output}, + use_contrib_qdq ? kMSDomain : ""); // add transpose Node& transpose_node = builder.AddNode("Transpose", {dq_output}, {output_arg}); @@ -2443,26 +3069,38 @@ TEST(QDQTransformerTests, QDQPropagation_Per_Layer_No_Propagation) { }; auto check_graph = [&](InferenceSessionWrapper& session) { - const std::vector expected_op_types_in_order{ - "DequantizeLinear", - "Transpose"}; - const auto op_types_in_order = GetNodeOpTypesInTopologicalOrder(session.GetGraph()); - EXPECT_EQ(op_types_in_order, expected_op_types_in_order); + // transpose optimization will change the order of the nodes, + // but as we're testing there's no propagation of the DQ what matters is the op counts. + auto op_counts = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); + EXPECT_EQ(op_counts[qdq_keys.dequantize_linear], 1); + EXPECT_EQ(op_counts["Transpose"], 1); }; + TransformerTester(build_test_case, + check_graph, + TransformerLevel::Default, + TransformerLevel::Level1); TransformerTester(build_test_case, check_graph, TransformerLevel::Default, TransformerLevel::Level1, - 12, 0.0, 0.0, nullptr, {}, // defaults that we're not overriding - {"TransposeOptimizer"}); // disable TransposeOptimizer for simplicity + 18); // disable TransposeOptimizer for simplicity + TransformerTester(build_test_case, + check_graph, + TransformerLevel::Default, + TransformerLevel::Level1, + 19); // disable TransposeOptimizer for simplicity }; - test_case({1, 13, 13, 23}, {0, 2, 3, 1}); + test_case({1, 13, 13, 23}, {0, 2, 3, 1}, false /*use_contrib_qdq*/); +#if !defined(DISABLE_CONTRIB_OPS) + test_case({1, 13, 13, 23}, {0, 2, 3, 1}, true /*use_contrib_qdq*/); +#endif } TEST(QDQTransformerTests, QDQPropagation_DQ_Q) { - auto test_case = [&](const std::vector& input_shape) { + auto test_case = [&](const std::vector& input_shape, bool use_contrib_qdq) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput(input_shape, std::numeric_limits::min(), @@ -2471,17 +3109,18 @@ TEST(QDQTransformerTests, QDQPropagation_DQ_Q) { // add DQ auto* dq_output = builder.MakeIntermediate(); - builder.AddDequantizeLinearNode(input_arg, .0035f, 135, dq_output); + builder.AddDequantizeLinearNode(input_arg, .0035f, 135, dq_output, use_contrib_qdq); // add Q - builder.AddQuantizeLinearNode(dq_output, .0035f, 135, output_arg); + builder.AddQuantizeLinearNode(dq_output, .0035f, 135, output_arg, use_contrib_qdq); }; auto check_graph = [&](InferenceSessionWrapper& session) { + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); const std::vector expected_op_types_in_order{ - "DequantizeLinear", - "QuantizeLinear"}; - const auto op_types_in_order = GetNodeOpTypesInTopologicalOrder(session.GetGraph()); + qdq_keys.dequantize_linear, + qdq_keys.quantize_linear}; + const auto op_types_in_order = GetNodeOpTypesInTopologicalOrder(session.GetGraph(), true); EXPECT_EQ(op_types_in_order, expected_op_types_in_order); }; @@ -2491,7 +3130,10 @@ TEST(QDQTransformerTests, QDQPropagation_DQ_Q) { TransformerLevel::Level1); }; - test_case({1, 13, 13, 23}); + test_case({1, 13, 13, 23}, false /*use_contrib_qdq*/); +#if !defined(DISABLE_CONTRIB_OPS) + test_case({1, 13, 13, 23}, true /*use_contrib_qdq*/); +#endif } TEST(QDQTransformerTests, QDQ_Selector_Test) { @@ -2620,15 +3262,15 @@ TEST(QDQTransformerTests, QDQ_Selector_Test) { // regression test to validate TransposeOptimizer and QDQ Propagation don't loop // see https://github.com/microsoft/onnxruntime/issues/11605 -TEST(QDQTransformerTests, QDQPropagation_GH11605_Opset12) { - auto test_case = [&]() { +TEST(QDQTransformerTests, QDQPropagation_GH11605_Opset12_19) { + auto test_case = [&](bool use_contrib_qdq) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput({1, 4, 4}, std::numeric_limits::min(), std::numeric_limits::max()); // add DQ auto* dq_output = builder.MakeIntermediate(); - builder.AddDequantizeLinearNode(input_arg, 0.123f, uint8_t(0), dq_output); + builder.AddDequantizeLinearNode(input_arg, 0.123f, uint8_t(0), dq_output, use_contrib_qdq); // add Transpose 0, 2, 1 const std::vector& perms{0, 2, 1}; @@ -2656,13 +3298,14 @@ TEST(QDQTransformerTests, QDQPropagation_GH11605_Opset12) { // QDQ cleanup in Level2 removes the unnecessary DQ/Q pair at the start: Tr -> DQ -> SoftM -> Tr // this is the optimal result as the Transpose is using 8-bit data and we have no surplus Q/DQ pairs auto check_graph = [&](InferenceSessionWrapper& session) { + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); std::vector expected_op_types_in_order{ "Transpose", - "DequantizeLinear", + qdq_keys.dequantize_linear, "Softmax", "Transpose"}; - const auto op_types_in_order = GetNodeOpTypesInTopologicalOrder(session.GetGraph()); + const auto op_types_in_order = GetNodeOpTypesInTopologicalOrder(session.GetGraph(), true); EXPECT_EQ(op_types_in_order, expected_op_types_in_order); }; @@ -2671,20 +3314,25 @@ TEST(QDQTransformerTests, QDQPropagation_GH11605_Opset12) { TransformerLevel::Default, TransformerLevel::Level2, 12); + + // TODO: fix opset 18, 19 }; - test_case(); + test_case(false); +#if !defined(DISABLE_CONTRIB_OPS) + test_case(true); // Use contrib QDQ ops +#endif } TEST(QDQTransformerTests, QDQPropagation_GH11605_Opset13) { - auto test_case = [&]() { + auto test_case = [&](bool use_contrib_qdq) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput({1, 4, 4}, std::numeric_limits::min(), std::numeric_limits::max()); // add DQ auto* dq_output = builder.MakeIntermediate(); - builder.AddDequantizeLinearNode(input_arg, 0.123f, uint8_t(0), dq_output); + builder.AddDequantizeLinearNode(input_arg, 0.123f, uint8_t(0), dq_output, use_contrib_qdq); // add Transpose 0, 2, 1 const std::vector& perms{0, 2, 1}; @@ -2712,10 +3360,11 @@ TEST(QDQTransformerTests, QDQPropagation_GH11605_Opset13) { // QDQ cleanup in Level2 removes the unnecessary DQ/Q pair at the start: Tr -> DQ -> SoftM -> Tr // this is the optimal result as the Transpose is using 8-bit data and we have no surplus Q/DQ pairs auto check_graph = [&](InferenceSessionWrapper& session) { + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); std::vector expected_op_types_in_order{ - "DequantizeLinear", + qdq_keys.dequantize_linear, "Softmax"}; - const auto op_types_in_order = GetNodeOpTypesInTopologicalOrder(session.GetGraph()); + const auto op_types_in_order = GetNodeOpTypesInTopologicalOrder(session.GetGraph(), true); EXPECT_EQ(op_types_in_order, expected_op_types_in_order); }; @@ -2724,16 +3373,25 @@ TEST(QDQTransformerTests, QDQPropagation_GH11605_Opset13) { TransformerLevel::Default, TransformerLevel::Level2, 13); + TransformerTester(build_test_case, + check_graph, + TransformerLevel::Default, + TransformerLevel::Level2, + 19); }; - test_case(); + test_case(false); +#if !defined(DISABLE_CONTRIB_OPS) + test_case(true); // Use contrib QDQ ops +#endif } // test removal of Q->DQ pairs by QDQFinalCleanupTransformer TEST(QDQTransformerTests, QDQFinalCleanupTransformer_BasicQDQCleanup) { auto test_case = [&](const std::vector>& input_shapes, - bool block_removal_of_last_dq = false, - bool block_removal_of_first_dq = false) { + bool block_removal_of_last_dq, + bool block_removal_of_first_dq, + bool use_contrib_qdq = false) { // create model with float input to multiple -> Q -> DQ -> Concat -> Q -> DQ -> output // If we enable cleanup and don't run the QDQ transformer we should drop all the Q->DQ pairs auto build_test_case = [&](ModelTestBuilder& builder) { @@ -2742,7 +3400,7 @@ TEST(QDQTransformerTests, QDQFinalCleanupTransformer_BasicQDQCleanup) { std::vector q_input_args; for (size_t i = 0; i < input_count; i++) { input_args.push_back(builder.MakeInput(input_shapes[i], -1.f, 1.f)); - q_input_args.push_back(AddQDQNodePair(builder, input_args.back(), 0.05f, 128)); + q_input_args.push_back(AddQDQNodePair(builder, input_args.back(), 0.05f, 128, use_contrib_qdq)); if (i == 0 && block_removal_of_first_dq) { // add another edge to the DQ node @@ -2755,10 +3413,11 @@ TEST(QDQTransformerTests, QDQFinalCleanupTransformer_BasicQDQCleanup) { concat_node.AddAttribute("axis", int64_t(1)); auto* q_concat_output = builder.MakeIntermediate(); - builder.AddQuantizeLinearNode(concat_output, 0.05f, 128, q_concat_output); + builder.AddQuantizeLinearNode(concat_output, 0.05f, 128, q_concat_output, use_contrib_qdq); auto* output_arg = builder.MakeOutput(); - Node& dq_node = builder.AddDequantizeLinearNode(q_concat_output, 0.05f, 128, output_arg); + Node& dq_node = builder.AddDequantizeLinearNode(q_concat_output, 0.05f, 128, output_arg, + use_contrib_qdq); if (block_removal_of_last_dq) { // add another edge to the DQ node @@ -2773,10 +3432,12 @@ TEST(QDQTransformerTests, QDQFinalCleanupTransformer_BasicQDQCleanup) { // so we expect twice as many DQ's as original QDQ pairs const int expected_dq_count = expected_qdq_count * 2; - auto check_graph = [expected_qdq_count, expected_dq_count](InferenceSessionWrapper& session) { + auto check_graph = [expected_qdq_count, expected_dq_count, + use_contrib_qdq](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); - EXPECT_EQ(op_to_count["QuantizeLinear"], expected_qdq_count); - EXPECT_EQ(op_to_count["DequantizeLinear"], expected_dq_count); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], expected_qdq_count); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], expected_dq_count); EXPECT_EQ(op_to_count["Concat"], 1); }; @@ -2795,33 +3456,60 @@ TEST(QDQTransformerTests, QDQFinalCleanupTransformer_BasicQDQCleanup) { 0.01f /*relative_per_sample_tolerance*/, std::make_unique(true /*enable_q_dq_cleanup*/), add_session_options); + TransformerTester(build_test_case, + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 18 /*opset_version*/, + 0.025f /*per_sample_tolerance*/, + 0.01f /*relative_per_sample_tolerance*/, + std::make_unique(true /*enable_q_dq_cleanup*/), + add_session_options); + TransformerTester(build_test_case, + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 19 /*opset_version*/, + 0.025f /*per_sample_tolerance*/, + 0.01f /*relative_per_sample_tolerance*/, + std::make_unique(true /*enable_q_dq_cleanup*/), + add_session_options); }; - test_case({{1, 2, 4}, {1, 3, 4}}); - test_case({{1, 2, 4}, {1, 3, 4}}, true); // block removal of first dq - test_case({{1, 2, 4}, {1, 3, 4}}, false, true); // block removal of last dq - test_case({{1, 2, 4}, {1, 3, 4}}, true, true); // block removal of first and last dq + test_case({{1, 2, 4}, {1, 3, 4}}, false, false); // Do not block removal + test_case({{1, 2, 4}, {1, 3, 4}}, true, false); // Block removal of first dq + test_case({{1, 2, 4}, {1, 3, 4}}, false, true); // Block removal of last dq + test_case({{1, 2, 4}, {1, 3, 4}}, true, true); // Block removal of first and last dq + +#if !defined(DISABLE_CONTRIB_OPS) + // Use contrib QDQ ops + test_case({{1, 2, 4}, {1, 3, 4}}, false, false, true); // Do not block removal + test_case({{1, 2, 4}, {1, 3, 4}}, true, false, true); // Block removal of first dq + test_case({{1, 2, 4}, {1, 3, 4}}, false, true, true); // Block removal of last dq + test_case({{1, 2, 4}, {1, 3, 4}}, true, true, true); // Block removal of first and last dq +#endif } TEST(QDQTransformerTests, QDQFinalCleanupTransformer_BasicDQQCleanUp) { - auto test_case = [](bool use_matching_qdq_params) { + auto test_case = [](bool use_matching_qdq_params, bool use_contrib_qdq) { // input -> Q -> DQ -> Q -> DQ -> output auto build_test_case = [&](ModelTestBuilder& builder) { constexpr float scale_1 = 0.05f; constexpr uint8_t zp_1 = 128; auto* const input = builder.MakeInput({1, 2, 4}, -1.0f, 1.0f); - auto* const dq_1_out = AddQDQNodePair(builder, input, scale_1, zp_1); + auto* const dq_1_out = AddQDQNodePair(builder, input, scale_1, zp_1, use_contrib_qdq); const float scale_2 = use_matching_qdq_params ? scale_1 : scale_1 + 0.01f; const uint8_t zp_2 = use_matching_qdq_params ? zp_1 : zp_1 + 1; - AddQDQNodePairWithOutputAsGraphOutput(builder, dq_1_out, scale_2, zp_2); + AddQDQNodePairWithOutputAsGraphOutput(builder, dq_1_out, scale_2, zp_2, use_contrib_qdq); }; auto check_graph = [&](const InferenceSessionWrapper& session) { - const auto ops_in_order = GetNodeOpTypesInTopologicalOrder(session.GetGraph()); + const auto ops_in_order = GetNodeOpTypesInTopologicalOrder(session.GetGraph(), true); const auto expected_ops_in_order = [&]() -> std::vector { + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); // In either case both DQ and Q will be removed and fused due to DoubleQDQPairsRemover - return {"QuantizeLinear", "DequantizeLinear"}; + return {qdq_keys.quantize_linear, qdq_keys.dequantize_linear}; }(); EXPECT_EQ(ops_in_order, expected_ops_in_order); @@ -2835,15 +3523,39 @@ TEST(QDQTransformerTests, QDQFinalCleanupTransformer_BasicDQQCleanUp) { 0.0f /*per_sample_tolerance*/, 0.0f /*relative_per_sample_tolerance*/, std::make_unique(false /*enable_q_dq_cleanup*/)); + + TransformerTester(build_test_case, + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 18 /*opset_version*/, + 0.0f /*per_sample_tolerance*/, + 0.0f /*relative_per_sample_tolerance*/, + std::make_unique(false /*enable_q_dq_cleanup*/)); + + TransformerTester(build_test_case, + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 19 /*opset_version*/, + 0.0f /*per_sample_tolerance*/, + 0.0f /*relative_per_sample_tolerance*/, + std::make_unique(false /*enable_q_dq_cleanup*/)); }; - test_case(true); - test_case(false); + test_case(true, false); // Matching QDQ params + test_case(false, false); // Non-matching QDQ params + +#if !defined(DISABLE_CONTRIB_OPS) + // Use contrib QDQ ops + test_case(true, true); // Matching QDQ params + test_case(false, true); // Non-matching QDQ params +#endif } // test removal when we have graph input -> Q/DQ pair -> graph output TEST(QDQTransformerTests, QDQFinalCleanupTransformer_GraphInputToOutput) { - auto test_case = [](bool is_q_dq) { + auto test_case = [](bool is_q_dq, bool use_contrib_qdq) { // create model with input -> Q/DQ pair -> output auto build_test_case = [&](ModelTestBuilder& builder) { constexpr float scale = 0.05f; @@ -2855,21 +3567,24 @@ TEST(QDQTransformerTests, QDQFinalCleanupTransformer_GraphInputToOutput) { NodeArg* first_node_output = builder.MakeIntermediate(); - is_q_dq ? builder.AddQuantizeLinearNode(input, scale, zp, first_node_output) - : builder.AddDequantizeLinearNode(input, scale, zp, first_node_output); + is_q_dq ? builder.AddQuantizeLinearNode(input, scale, zp, first_node_output, use_contrib_qdq) + : builder.AddDequantizeLinearNode(input, scale, zp, first_node_output, use_contrib_qdq); auto* second_node_output = builder.MakeOutput(); - is_q_dq ? builder.AddDequantizeLinearNode(first_node_output, scale, zp, second_node_output) - : builder.AddQuantizeLinearNode(first_node_output, scale, zp, second_node_output); + is_q_dq ? builder.AddDequantizeLinearNode(first_node_output, scale, zp, second_node_output, + use_contrib_qdq) + : builder.AddQuantizeLinearNode(first_node_output, scale, zp, second_node_output, + use_contrib_qdq); }; // with the Q/DQ pair being dropped we should have inserted an Identity node // to connect the graph input to the graph output - auto check_graph = [](InferenceSessionWrapper& session) { + auto check_graph = [use_contrib_qdq](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); - EXPECT_EQ(op_to_count["QuantizeLinear"], 0); - EXPECT_EQ(op_to_count["DequantizeLinear"], 0); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 0); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 0); EXPECT_EQ(op_to_count["Identity"], 1); }; @@ -2895,15 +3610,42 @@ TEST(QDQTransformerTests, QDQFinalCleanupTransformer_GraphInputToOutput) { relative_per_sample_tolerance, std::make_unique(is_q_dq /*enable_q_dq_cleanup*/), add_session_options); + + TransformerTester(build_test_case, + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 18 /*opset_version*/, + per_sample_tolerance, + relative_per_sample_tolerance, + std::make_unique(is_q_dq /*enable_q_dq_cleanup*/), + add_session_options); + + TransformerTester(build_test_case, + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 19 /*opset_version*/, + per_sample_tolerance, + relative_per_sample_tolerance, + std::make_unique(is_q_dq /*enable_q_dq_cleanup*/), + add_session_options); }; - test_case(true); - test_case(false); + test_case(true, false); // input -> Q -> DQ -> output + test_case(false, false); // input -> DQ -> Q -> output + +#if !defined(DISABLE_CONTRIB_OPS) + // Use contrib QDQ ops + test_case(true, true); // input -> Q -> DQ -> output + test_case(false, true); // input -> DQ -> Q -> output +#endif } #if !defined(DISABLE_CONTRIB_OPS) TEST(QDQTransformerTests, QDQSoftmaxWithDQProducingGraphOutput) { - auto test_case = [&](const std::vector& input_shape, int64_t axis) { + auto test_case = [&](const std::vector& input_shape, int64_t axis, + bool use_contrib_qdq) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput(input_shape, -5.f, 5.f); auto* dq_output_arg = builder.MakeOutput(); @@ -2913,11 +3655,13 @@ TEST(QDQTransformerTests, QDQSoftmaxWithDQProducingGraphOutput) { builder.AddQuantizeLinearNode(input_arg, .105f, 127, - input_q_output); + input_q_output, + use_contrib_qdq); builder.AddDequantizeLinearNode(input_q_output, .105f, 127, - dq_output_arg); + dq_output_arg, + use_contrib_qdq); // add Softmax auto* softmax_output = builder.MakeIntermediate(); @@ -2929,21 +3673,24 @@ TEST(QDQTransformerTests, QDQSoftmaxWithDQProducingGraphOutput) { builder.AddQuantizeLinearNode(softmax_output, 1.0f / (std::numeric_limits::max() + 1), 0, - q_output); + q_output, + use_contrib_qdq); builder.AddDequantizeLinearNode(q_output, 1.0f / (std::numeric_limits::max() + 1), 0, - output_arg); + output_arg, + use_contrib_qdq); }; auto check_graph = [&](InferenceSessionWrapper& session) { auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); // expect fusion because DQ duplication ensures that the node unit has unique DQ nodes EXPECT_EQ(op_to_count["com.microsoft.QLinearSoftmax"], 1); EXPECT_EQ(op_to_count["Softmax"], 0); - EXPECT_EQ(op_to_count["QuantizeLinear"], 1); - EXPECT_EQ(op_to_count["DequantizeLinear"], 2); // duplicate of first DQ and original second DQ + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 1); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 2); // duplicate of first DQ and original second DQ }; TransformerTester(build_test_case, @@ -2953,14 +3700,32 @@ TEST(QDQTransformerTests, QDQSoftmaxWithDQProducingGraphOutput) { 12 /*opset_version*/, 0.01 /*per_sample_tolerance*/, 0.01 /*relative_per_sample_tolerance*/); + + TransformerTester(build_test_case, + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 18 /*opset_version*/, + 0.01 /*per_sample_tolerance*/, + 0.01 /*relative_per_sample_tolerance*/); + + TransformerTester(build_test_case, + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 19 /*opset_version*/, + 0.01 /*per_sample_tolerance*/, + 0.01 /*relative_per_sample_tolerance*/); }; - test_case({1, 12, 37}, -1); + test_case({1, 12, 37}, -1, false); + test_case({1, 12, 37}, -1, true); // Use contrib QDQ ops } // DQ produces graph output - special case for DropDQ path where there is only a DQ -> Node with no trailing Q TEST(QDQTransformerTests, DropDQSelectorWithDQProducingGraphOutput) { - auto test_case = [&](const std::vector& input_shape, int64_t axis, bool dq_produces_graph_output) { + auto test_case = [&](const std::vector& input_shape, int64_t axis, bool dq_produces_graph_output, + bool use_contrib_qdq) { auto build_test_case = [&](ModelTestBuilder& builder) { auto* input_arg = builder.MakeInput(input_shape, -5.f, 5.f); auto* output_arg = builder.MakeOutput(); @@ -2969,8 +3734,8 @@ TEST(QDQTransformerTests, DropDQSelectorWithDQProducingGraphOutput) { auto* input_q_output = builder.MakeIntermediate(); auto* dq_output_arg = dq_produces_graph_output ? builder.MakeOutput() : builder.MakeIntermediate(); - builder.AddQuantizeLinearNode(input_arg, .105f, 127, input_q_output); - builder.AddDequantizeLinearNode(input_q_output, .105f, 127, dq_output_arg); + builder.AddQuantizeLinearNode(input_arg, .105f, 127, input_q_output, use_contrib_qdq); + builder.AddDequantizeLinearNode(input_q_output, .105f, 127, dq_output_arg, use_contrib_qdq); // add ArgMax auto* argmax_output = builder.MakeIntermediate(); @@ -2985,11 +3750,12 @@ TEST(QDQTransformerTests, DropDQSelectorWithDQProducingGraphOutput) { const Graph& graph = session.GetGraph(); auto op_to_count = CountOpsInGraph(graph); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); const auto expected_dq_count = dq_produces_graph_output ? 1 // EnsureUniqueDQForNodeUnit duplicates one DQ and DropDQ drops one DQ : 0; // DropDQ drops one DQ - EXPECT_EQ(op_to_count["DequantizeLinear"], expected_dq_count); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], expected_dq_count); const auto& nodes = graph.Nodes(); const auto argmax_node_it = std::find_if(nodes.cbegin(), @@ -3007,11 +3773,29 @@ TEST(QDQTransformerTests, DropDQSelectorWithDQProducingGraphOutput) { TransformerLevel::Level1, TransformerLevel::Level2, 12 /*opset_version*/); + + TransformerTester(build_test_case, + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 18 /*opset_version*/); + + TransformerTester(build_test_case, + check_graph, + TransformerLevel::Level1, + TransformerLevel::Level2, + 19 /*opset_version*/); }; // test with and without the DQ producing a graph output to validate the test hits DropDQ - test_case({1, 4, 8}, -1, false); - test_case({1, 4, 8}, -1, true); + + // DQ does not produce graph output + test_case({1, 4, 8}, -1, false, false); + test_case({1, 4, 8}, -1, false, true); // Use contrib QDQ ops + + // DQ produces graph output + test_case({1, 4, 8}, -1, true, false); + test_case({1, 4, 8}, -1, true, true); // Use contrib QDQ ops } #endif // !defined(DISABLE_CONTRIB_OPS) diff --git a/onnxruntime/test/optimizer/resnet50_fusion_test.cc b/onnxruntime/test/optimizer/resnet50_fusion_test.cc new file mode 100644 index 0000000000000..04b11b46e5002 --- /dev/null +++ b/onnxruntime/test/optimizer/resnet50_fusion_test.cc @@ -0,0 +1,134 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +#include +#include "core/graph/graph.h" +#include "core/optimizer/conv_activation_fusion.h" +#include "core/optimizer/conv_add_fusion.h" +#include "core/optimizer/conv_add_act_fusion.h" +#include "core/mlas/inc/mlas.h" +#include "gtest/gtest.h" +#include "graph_transform_test_builder.h" +#include "test/test_environment.h" +#include "test/util/include/asserts.h" + +#include "test/optimizer/graph_transform_test_builder.h" +#include "test/optimizer/graph_transform_test_fixture.h" + +namespace onnxruntime { +namespace test { +// #define ORT_RUN_EXTERNAL_ONNX_TESTS +// #define MLAS_F16VEC_INTRINSICS_SUPPORTED + +#define MODEL_FOLDER ORT_TSTR("testdata/transform/") +#if defined(MLAS_F16VEC_INTRINSICS_SUPPORTED) && !defined(DISABLE_CONTRIB_OPS) + +class ResNet50FusionTests : public ::testing::Test { + protected: + ResNet50FusionTests() : logger(DefaultLoggingManager().CreateLogger("ResNet50FusionTest")) { + } + std::unique_ptr logger; +}; +#if defined(ORT_RUN_EXTERNAL_ONNX_TESTS) +TEST_F(ResNet50FusionTests, FuseConvIntegrationTest) { + std::basic_string fp32_model_path = ORT_TSTR("../models/opset10/Resnet50_Fusion_Testing/resnet50.onnx"); + std::shared_ptr fp32_model; + std::basic_string fp16_model_path = ORT_TSTR("../models/opset10/Resnet50_Fusion_Testing_fp16/resnet50.fp16.onnx"); + std::shared_ptr fp16_model; + if (Model::Load(fp32_model_path, fp32_model, nullptr, *logger) != Status::OK()) { + GTEST_SKIP() << "Failed to load model: " << fp32_model_path; + } + if (Model::Load(fp16_model_path, fp16_model, nullptr, *logger) != Status::OK()) { + GTEST_SKIP() << "Failed to load model: " << fp16_model_path; + } + // ASSERT_STATUS_OK(Model::Load(fp32_model_path, fp32_model, nullptr, *logger)); + Graph& fp32_graph = fp32_model->MainGraph(); + for (auto& node : fp32_model->MainGraph().Nodes()) { + node.SetExecutionProviderType(kCpuExecutionProvider); + } + Graph& fp16_graph = fp16_model->MainGraph(); + for (auto& node : fp16_model->MainGraph().Nodes()) { + node.SetExecutionProviderType(kCpuExecutionProvider); + } + // std::cout << "-------Op Counts Before Fusion---------" << std::endl; + std::map fp32_op_count = CountOpsInGraph(fp32_graph); + std::map fp16_op_count = CountOpsInGraph(fp16_graph); + for (auto& op : fp32_op_count) { + // std::cout << op.first << " " << op.second << std::endl; + ASSERT_EQ(op.second, fp16_op_count[op.first]); + } + + onnxruntime::GraphTransformerManager graph_transformation_mgr_32{5}; + ASSERT_STATUS_OK(graph_transformation_mgr_32.Register(std::make_unique(), TransformerLevel::Level3)); + ASSERT_STATUS_OK(graph_transformation_mgr_32.Register(std::make_unique(), TransformerLevel::Level3)); + ASSERT_STATUS_OK(graph_transformation_mgr_32.ApplyTransformers(fp32_graph, TransformerLevel::Level3, *logger)); + ASSERT_STATUS_OK(Model::Save(*fp32_model, "resnet50_fused.onnx")); + + onnxruntime::GraphTransformerManager graph_transformation_mgr_16{5}; + ASSERT_STATUS_OK(graph_transformation_mgr_16.Register(std::make_unique(), TransformerLevel::Level3)); + ASSERT_STATUS_OK(graph_transformation_mgr_16.Register(std::make_unique(), TransformerLevel::Level3)); + ASSERT_STATUS_OK(graph_transformation_mgr_16.ApplyTransformers(fp16_graph, TransformerLevel::Level3, *logger)); + ASSERT_STATUS_OK(Model::Save(*fp16_model, "resnet50_fp16_fused.onnx")); + // std::cout << "-------Op Counts After Fusion---------" << std::endl; + fp32_op_count = CountOpsInGraph(fp32_graph); + fp16_op_count = CountOpsInGraph(fp16_graph); + // for (auto& op : fp32_op_count) { + // ASSERT_EQ(op.second, fp16_op_count[op.first]); + // } +} +#endif // defined(ORT_RUN_EXTERNAL_ONNX_TESTS) +TEST_F(ResNet50FusionTests, FuseConvAddReluUnitTest) { + constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/conv_add_relu_fp16.onnx"; + std::shared_ptr p_model; + ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger)); + Graph& graph = p_model->MainGraph(); + for (auto& node : p_model->MainGraph().Nodes()) { + node.SetExecutionProviderType(kCpuExecutionProvider); + } + std::map op_to_count = CountOpsInGraph(graph); + ASSERT_TRUE(op_to_count["Add"] == 1); + ASSERT_TRUE(op_to_count["Relu"] == 1); + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level3)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level3, *logger)); + op_to_count = CountOpsInGraph(graph); + ASSERT_STATUS_OK(Model::Save(*p_model, "conv_add_relu_fp16_fused.onnx")); + ASSERT_TRUE(op_to_count["Add"] == 0); // Add removed from graph + ASSERT_TRUE(op_to_count["Relu"] == 0); // Relu removed from graph +} +TEST_F(ResNet50FusionTests, FuseConvAddUnitTest) { + constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/conv_add_fp16.onnx"; + std::shared_ptr p_model; + ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger)); + Graph& graph = p_model->MainGraph(); + for (auto& node : p_model->MainGraph().Nodes()) { + node.SetExecutionProviderType(kCpuExecutionProvider); + } + std::map op_to_count = CountOpsInGraph(graph); + ASSERT_TRUE(op_to_count["Add"] == 1); + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level3)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level3, *logger)); + op_to_count = CountOpsInGraph(graph); + ASSERT_STATUS_OK(Model::Save(*p_model, "conv_add_fp16_fused.onnx")); + ASSERT_TRUE(op_to_count["Add"] == 0); // Add removed from graph +} +TEST_F(ResNet50FusionTests, FuseConvReluUnitTest) { + constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/conv_relu_fp16.onnx"; + std::shared_ptr p_model; + ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger)); + Graph& graph = p_model->MainGraph(); + for (auto& node : p_model->MainGraph().Nodes()) { + node.SetExecutionProviderType(kCpuExecutionProvider); + } + std::map op_to_count = CountOpsInGraph(graph); + ASSERT_TRUE(op_to_count["Relu"] == 1); + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), TransformerLevel::Level3)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level3, *logger)); + op_to_count = CountOpsInGraph(graph); + ASSERT_STATUS_OK(Model::Save(*p_model, "conv_relu_fp16_fused.onnx")); + ASSERT_TRUE(op_to_count["Relu"] == 0); // Add removed from graph +} +#endif // defined(MLAS_F16VEC_INTRINSICS_SUPPORTED) && !defined(DISABLE_CONTRIB_OPS) +} // namespace test +} // namespace onnxruntime \ No newline at end of file diff --git a/onnxruntime/test/optimizer/runtime_optimization/graph_runtime_optimization_test.cc b/onnxruntime/test/optimizer/runtime_optimization/graph_runtime_optimization_test.cc index 7558d497732fd..a988bb1ee783e 100644 --- a/onnxruntime/test/optimizer/runtime_optimization/graph_runtime_optimization_test.cc +++ b/onnxruntime/test/optimizer/runtime_optimization/graph_runtime_optimization_test.cc @@ -10,7 +10,7 @@ #include "test/framework/test_utils.h" #include "test/util/include/asserts.h" #include "test/util/include/inference_session_wrapper.h" -#include "test/util/include/test/test_environment.h" +#include "test/util/include/test_environment.h" #if !defined(ORT_MINIMAL_BUILD) #include "core/flatbuffers/ort_format_version.h" diff --git a/onnxruntime/test/optimizer/test_optimizer_utils.cc b/onnxruntime/test/optimizer/test_optimizer_utils.cc index 08cb129b1d857..40065c2fc7006 100644 --- a/onnxruntime/test/optimizer/test_optimizer_utils.cc +++ b/onnxruntime/test/optimizer/test_optimizer_utils.cc @@ -31,7 +31,7 @@ void RandomFillHalfVector(const TensorShapeVector& shape, std::vector std::vector data_float(TensorShape(shape).Size()); RandomFillFloatVector(shape, data_float); std::transform(data_float.begin(), data_float.end(), data.begin(), - [](float value) { return MLFloat16(math::floatToHalf(value)); }); + [](float value) { return MLFloat16(value); }); } void RandomMasks(int64_t batch, int64_t sequence_length, std::vector& data) { diff --git a/onnxruntime/test/optimizer/test_optimizer_utils.h b/onnxruntime/test/optimizer/test_optimizer_utils.h index 36df383a68244..82da05695de70 100644 --- a/onnxruntime/test/optimizer/test_optimizer_utils.h +++ b/onnxruntime/test/optimizer/test_optimizer_utils.h @@ -34,7 +34,7 @@ struct TestInputData { std::is_same_v> || std::is_same_v>) CreateMLValue( - TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), dims, arg, &ortvalue); + TestCPUExecutionProvider()->CreatePreferredAllocators()[0], dims, arg, &ortvalue); else static_assert("Unspported types!"); }, diff --git a/onnxruntime/test/optimizer/transpose_optimizer_test.cc b/onnxruntime/test/optimizer/transpose_optimizer_test.cc index 86499c7e82d02..1f4c499985ad0 100644 --- a/onnxruntime/test/optimizer/transpose_optimizer_test.cc +++ b/onnxruntime/test/optimizer/transpose_optimizer_test.cc @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#include #include #include @@ -8,6 +9,7 @@ #include "gmock/gmock.h" #include "core/graph/graph.h" +#include "core/graph/node_attr_utils.h" #include "core/framework/op_node_proto_helper.h" #include "core/framework/utils.h" #include "core/session/onnxruntime_session_options_config_keys.h" @@ -3501,119 +3503,117 @@ TEST(TransposeOptimizerTests, TestWhere) { /*opset_version*/ {15, 18}); } -TEST(TransposeOptimizerTests, TestQuantizeLinearScalar) { - auto build_test_case_1 = [&](ModelTestBuilder& builder) { +// Utility function that runs TransformerTester for the graph Transpose -> QuantizeLinear -> Transpose. +// Expects the Tranpose nodes to cancel. +template +static void RunQuantizeLinearTestCase(const std::optional>& zp_input_shape, + const std::vector& zp_value_shape, + std::optional axis, + const std::string& q_domain = "") { + auto build_test_case = [&](ModelTestBuilder& builder) { + constexpr QuantType qmin = std::numeric_limits::min(); + constexpr QuantType qmax = std::numeric_limits::max(); + auto* input0_arg = MakeInput(builder, {{2, -1, 6, 3}}, {2, 4, 6, 3}, 0.0, 1.0); - auto* input1_arg = MakeInput(builder, {std::vector{}}, std::vector{}, {2.3f}); - auto* input2_arg = MakeInput(builder, {std::vector{}}, std::vector{}, {10}); + + NodeArg* scale_arg = nullptr; + NodeArg* zero_point_arg = nullptr; + + if (zp_value_shape.empty()) { // Per-tensor quantization + QuantType zp = (qmax + qmin) / 2; + scale_arg = MakeInput(builder, zp_input_shape, zp_value_shape, {0.05f}); + zero_point_arg = MakeInput(builder, zp_input_shape, zp_value_shape, {zp}); + } else { // Per-axis quantization + scale_arg = MakeInput(builder, zp_input_shape, zp_value_shape, 0.0f, 1.0f); + zero_point_arg = MakeInput(builder, zp_input_shape, zp_value_shape, qmin, qmax); + } auto* transpose_1_out_0 = builder.MakeIntermediate(); auto* quantizelinear_1_out_0 = builder.MakeIntermediate(); auto* transpose_2_out_0 = builder.MakeOutput(); auto& transpose_1 = builder.AddNode("Transpose", {input0_arg}, {transpose_1_out_0}); transpose_1.AddAttribute("perm", std::vector{0, 3, 1, 2}); - builder.AddNode("QuantizeLinear", {transpose_1_out_0, input1_arg, input2_arg}, {quantizelinear_1_out_0}); + auto& quantizelinear_1 = builder.AddNode("QuantizeLinear", {transpose_1_out_0, scale_arg, zero_point_arg}, + {quantizelinear_1_out_0}, q_domain); + + if (axis.has_value()) { + quantizelinear_1.AddAttributeProto(*axis); + } + auto& transpose_2 = builder.AddNode("Transpose", {quantizelinear_1_out_0}, {transpose_2_out_0}); transpose_2.AddAttribute("perm", std::vector{0, 2, 3, 1}); }; - auto check_optimized_graph_1 = [&](InferenceSessionWrapper& session) { + auto check_optimized_graph = [](InferenceSessionWrapper& session) { int transpose_cost = EstimateTransposeCost(session.GetGraph()); EXPECT_EQ(transpose_cost, 0); }; - TransformerTester(build_test_case_1, - check_optimized_graph_1, + TransformerTester(build_test_case, + check_optimized_graph, TransformerLevel::Default, TransformerLevel::Level1, /*opset_version*/ {15, 18}); } -TEST(TransposeOptimizerTests, TestQuantizeLinearScalarIgnoreAxis) { - auto build_test_case_1 = [&](ModelTestBuilder& builder) { - auto* input0_arg = MakeInput(builder, {{2, -1, 6, 3}}, {2, 4, 6, 3}, 0.0, 1.0); - auto* input1_arg = MakeInput(builder, {std::vector{}}, std::vector{}, {2.3f}); - auto* input2_arg = MakeInput(builder, {std::vector{}}, std::vector{}, {10}); - auto* transpose_1_out_0 = builder.MakeIntermediate(); - auto* quantizelinear_1_out_0 = builder.MakeIntermediate(); - auto* transpose_2_out_0 = builder.MakeOutput(); +TEST(TransposeOptimizerTests, TestQuantizeLinearScalar) { + std::optional> zp_input_shape = std::vector{}; + std::vector zp_value_shape{}; + std::optional empty_axis; // No axis value. - auto& transpose_1 = builder.AddNode("Transpose", {input0_arg}, {transpose_1_out_0}); - transpose_1.AddAttribute("perm", std::vector{0, 3, 1, 2}); - auto& quantizelinear_1 = builder.AddNode("QuantizeLinear", {transpose_1_out_0, input1_arg, input2_arg}, {quantizelinear_1_out_0}); - quantizelinear_1.AddAttribute("axis", (int64_t)10); - auto& transpose_2 = builder.AddNode("Transpose", {quantizelinear_1_out_0}, {transpose_2_out_0}); - transpose_2.AddAttribute("perm", std::vector{0, 2, 3, 1}); - }; + RunQuantizeLinearTestCase(zp_input_shape, zp_value_shape, empty_axis, kOnnxDomain); - auto check_optimized_graph_1 = [&](InferenceSessionWrapper& session) { - int transpose_cost = EstimateTransposeCost(session.GetGraph()); - EXPECT_EQ(transpose_cost, 0); - }; +#if !defined(DISABLE_CONTRIB_OPS) + // Use com.microsoft.QuantizeLinear op. + RunQuantizeLinearTestCase(zp_input_shape, zp_value_shape, empty_axis, kMSDomain); + RunQuantizeLinearTestCase(zp_input_shape, zp_value_shape, empty_axis, kMSDomain); + RunQuantizeLinearTestCase(zp_input_shape, zp_value_shape, empty_axis, kMSDomain); +#endif +} - TransformerTester(build_test_case_1, - check_optimized_graph_1, - TransformerLevel::Default, - TransformerLevel::Level1, - /*opset_version*/ {15, 18}); +TEST(TransposeOptimizerTests, TestQuantizeLinearScalarIgnoreAxis) { + std::optional> zp_input_shape = std::vector{}; + std::vector zp_value_shape{}; + auto ignored_axis = utils::MakeAttribute("axis", static_cast(10)); // Should be ignored for per-tensor Q + + RunQuantizeLinearTestCase(zp_input_shape, zp_value_shape, ignored_axis, kOnnxDomain); + +#if !defined(DISABLE_CONTRIB_OPS) + // Use com.microsoft.QuantizeLinear op. + RunQuantizeLinearTestCase(zp_input_shape, zp_value_shape, ignored_axis, kMSDomain); + RunQuantizeLinearTestCase(zp_input_shape, zp_value_shape, ignored_axis, kMSDomain); + RunQuantizeLinearTestCase(zp_input_shape, zp_value_shape, ignored_axis, kMSDomain); +#endif } TEST(TransposeOptimizerTests, TestQuantizeLinearVector) { - auto build_test_case_1 = [&](ModelTestBuilder& builder) { - auto* input0_arg = MakeInput(builder, {{2, -1, 6, 3}}, {2, 4, 6, 3}, 0.0, 1.0); - auto* input1_arg = MakeInput(builder, {{-1}}, {2}, {2.3f, 2.4f}); - auto* input2_arg = MakeInput(builder, {{-1}}, {2}, {10, 12}); - auto* transpose_1_out_0 = builder.MakeIntermediate(); - auto* quantizelinear_1_out_0 = builder.MakeIntermediate(); - auto* transpose_2_out_0 = builder.MakeOutput(); + std::optional> zp_input_shape = std::vector{-1}; + std::vector zp_value_shape = {2}; + auto axis = utils::MakeAttribute("axis", static_cast(0)); - auto& transpose_1 = builder.AddNode("Transpose", {input0_arg}, {transpose_1_out_0}); - transpose_1.AddAttribute("perm", std::vector{0, 3, 1, 2}); - auto& quantizelinear_1 = builder.AddNode("QuantizeLinear", {transpose_1_out_0, input1_arg, input2_arg}, {quantizelinear_1_out_0}); - quantizelinear_1.AddAttribute("axis", (int64_t)0); - auto& transpose_2 = builder.AddNode("Transpose", {quantizelinear_1_out_0}, {transpose_2_out_0}); - transpose_2.AddAttribute("perm", std::vector{0, 2, 3, 1}); - }; - - auto check_optimized_graph_1 = [&](InferenceSessionWrapper& session) { - int transpose_cost = EstimateTransposeCost(session.GetGraph()); - EXPECT_EQ(transpose_cost, 0); - }; + RunQuantizeLinearTestCase(zp_input_shape, zp_value_shape, axis, kOnnxDomain); - TransformerTester(build_test_case_1, - check_optimized_graph_1, - TransformerLevel::Default, - TransformerLevel::Level1, - /*opset_version*/ {15, 18}); +#if !defined(DISABLE_CONTRIB_OPS) + // Use com.microsoft.QuantizeLinear op. + RunQuantizeLinearTestCase(zp_input_shape, zp_value_shape, axis, kMSDomain); + RunQuantizeLinearTestCase(zp_input_shape, zp_value_shape, axis, kMSDomain); + RunQuantizeLinearTestCase(zp_input_shape, zp_value_shape, axis, kMSDomain); +#endif } TEST(TransposeOptimizerTests, TestQuantizeLinearVectorUnknownRank) { - auto build_test_case_1 = [&](ModelTestBuilder& builder) { - auto* input0_arg = MakeInput(builder, {{2, -1, 6, 3}}, {2, 4, 6, 3}, 0.0, 1.0); - auto* input1_arg = MakeInput(builder, std::nullopt, {3}, {2.3f, 2.4f, 2.5f}); - auto* input2_arg = MakeInput(builder, std::nullopt, {3}, {10, 12, 13}); - auto* transpose_1_out_0 = builder.MakeIntermediate(); - auto* quantizelinear_1_out_0 = builder.MakeIntermediate(); - auto* transpose_2_out_0 = builder.MakeOutput(); + std::optional> zp_unknown_shape; // Empty shape + std::vector zp_value_shape = {3}; + auto axis = utils::MakeAttribute("axis", static_cast(1)); - auto& transpose_1 = builder.AddNode("Transpose", {input0_arg}, {transpose_1_out_0}); - transpose_1.AddAttribute("perm", std::vector{0, 3, 1, 2}); - auto& quantizelinear_1 = builder.AddNode("QuantizeLinear", {transpose_1_out_0, input1_arg, input2_arg}, {quantizelinear_1_out_0}); - quantizelinear_1.AddAttribute("axis", (int64_t)1); - auto& transpose_2 = builder.AddNode("Transpose", {quantizelinear_1_out_0}, {transpose_2_out_0}); - transpose_2.AddAttribute("perm", std::vector{0, 2, 3, 1}); - }; - - auto check_optimized_graph_1 = [&](InferenceSessionWrapper& session) { - int transpose_cost = EstimateTransposeCost(session.GetGraph()); - EXPECT_EQ(transpose_cost, 0); - }; + RunQuantizeLinearTestCase(zp_unknown_shape, zp_value_shape, axis, kOnnxDomain); - TransformerTester(build_test_case_1, - check_optimized_graph_1, - TransformerLevel::Default, - TransformerLevel::Level1, - /*opset_version*/ {15, 18}); +#if !defined(DISABLE_CONTRIB_OPS) + // Use com.microsoft.QuantizeLinear op. + RunQuantizeLinearTestCase(zp_unknown_shape, zp_value_shape, axis, kMSDomain); + RunQuantizeLinearTestCase(zp_unknown_shape, zp_value_shape, axis, kMSDomain); + RunQuantizeLinearTestCase(zp_unknown_shape, zp_value_shape, axis, kMSDomain); +#endif } TEST(TransposeOptimizerTests, TestQuantizeLinearScalarOpset10) { @@ -3644,102 +3644,116 @@ TEST(TransposeOptimizerTests, TestQuantizeLinearScalarOpset10) { /*opset_version*/ 10); } -TEST(TransposeOptimizerTests, TestDequantizeLinearScalarIgnoreAxis) { - auto build_test_case_1 = [&](ModelTestBuilder& builder) { - auto* input0_arg = MakeInput(builder, {{2, -1, 6, 3}}, {2, 4, 6, 3}, 0, 5); - auto* input1_arg = MakeInput(builder, {std::vector{}}, std::vector{}, {2.3f}); - auto* input2_arg = MakeInput(builder, {std::vector{}}, std::vector{}, {10}); - auto* transpose_1_out_0 = builder.MakeIntermediate(); - auto* dequantizelinear_1_out_0 = builder.MakeIntermediate(); - auto* transpose_2_out_0 = builder.MakeOutput(); +// Utility function that runs TransformerTester for the graph Transpose -> DequantizeLinear -> Transpose. +// Expects the Tranpose nodes to cancel. +template +static void RunDequantizeLinearTestCase(const std::optional>& zp_input_shape, + const std::vector& zp_value_shape, + std::optional axis, + const std::string& q_domain = "") { + auto build_test_case = [&](ModelTestBuilder& builder) { + constexpr QuantType qmin = std::numeric_limits::min(); + constexpr QuantType qmax = std::numeric_limits::max(); - auto& transpose_1 = builder.AddNode("Transpose", {input0_arg}, {transpose_1_out_0}); - transpose_1.AddAttribute("perm", std::vector{0, 3, 1, 2}); - auto& dequantizelinear_1 = builder.AddNode("DequantizeLinear", {transpose_1_out_0, input1_arg, input2_arg}, {dequantizelinear_1_out_0}); - dequantizelinear_1.AddAttribute("axis", (int64_t)10); - auto& transpose_2 = builder.AddNode("Transpose", {dequantizelinear_1_out_0}, {transpose_2_out_0}); - transpose_2.AddAttribute("perm", std::vector{0, 2, 3, 1}); - }; + auto* input0_arg = MakeInput(builder, {{2, -1, 6, 3}}, {2, 4, 6, 3}, qmin, qmax); - auto check_optimized_graph_1 = [&](InferenceSessionWrapper& session) { - int transpose_cost = EstimateTransposeCost(session.GetGraph()); - EXPECT_EQ(transpose_cost, 0); - }; + NodeArg* scale_arg = nullptr; + NodeArg* zero_point_arg = nullptr; - TransformerTester(build_test_case_1, - check_optimized_graph_1, - TransformerLevel::Default, - TransformerLevel::Level1, - /*opset_version*/ {15, 18}); -} - -TEST(TransposeOptimizerTests, TestDequantizeLinearVector) { - auto build_test_case_1 = [&](ModelTestBuilder& builder) { - auto* input0_arg = MakeInput(builder, {{2, -1, 6, 3}}, {2, 4, 6, 3}, 0, 5); - auto* input1_arg = MakeInput(builder, {{2}}, {2}, {2.3f, 2.4f}); - auto* input2_arg = MakeInput(builder, {{2}}, {2}, {10, 12}); + if (zp_value_shape.empty()) { // Per-tensor quantization + QuantType zp = (qmax + qmin) / 2; + scale_arg = MakeInput(builder, zp_input_shape, zp_value_shape, {0.05f}); + zero_point_arg = MakeInput(builder, zp_input_shape, zp_value_shape, {zp}); + } else { // Per-axis quantization + scale_arg = MakeInput(builder, zp_input_shape, zp_value_shape, 0.0f, 1.0f); + zero_point_arg = MakeInput(builder, zp_input_shape, zp_value_shape, qmin, qmax); + } auto* transpose_1_out_0 = builder.MakeIntermediate(); auto* dequantizelinear_1_out_0 = builder.MakeIntermediate(); auto* transpose_2_out_0 = builder.MakeOutput(); auto& transpose_1 = builder.AddNode("Transpose", {input0_arg}, {transpose_1_out_0}); transpose_1.AddAttribute("perm", std::vector{0, 3, 1, 2}); - auto& dequantizelinear_1 = builder.AddNode("DequantizeLinear", {transpose_1_out_0, input1_arg, input2_arg}, {dequantizelinear_1_out_0}); - dequantizelinear_1.AddAttribute("axis", (int64_t)-4); + auto& dequantizelinear_1 = builder.AddNode("DequantizeLinear", {transpose_1_out_0, scale_arg, zero_point_arg}, + {dequantizelinear_1_out_0}, q_domain); + + if (axis.has_value()) { + dequantizelinear_1.AddAttributeProto(*axis); + } + auto& transpose_2 = builder.AddNode("Transpose", {dequantizelinear_1_out_0}, {transpose_2_out_0}); transpose_2.AddAttribute("perm", std::vector{0, 2, 3, 1}); }; - auto check_optimized_graph_1 = [&](InferenceSessionWrapper& session) { + auto check_optimized_graph = [](InferenceSessionWrapper& session) { int transpose_cost = EstimateTransposeCost(session.GetGraph()); EXPECT_EQ(transpose_cost, 0); }; - TransformerTester(build_test_case_1, - check_optimized_graph_1, + TransformerTester(build_test_case, + check_optimized_graph, TransformerLevel::Default, TransformerLevel::Level1, /*opset_version*/ {15, 18}); } -TEST(TransposeOptimizerTests, TestDequantizeLinearNoAxis) { - auto build_test_case_1 = [&](ModelTestBuilder& builder) { - auto* input0_arg = MakeInput(builder, {{2, -1, 6, 3}}, {2, 4, 6, 3}, 0, 5); - auto* input1_arg = MakeInput(builder, {std::vector{}}, std::vector{}, {2.3f}); - auto* input2_arg = MakeInput(builder, {std::vector{}}, std::vector{}, {10}); - auto* transpose_1_out_0 = builder.MakeIntermediate(); - auto* dequantizelinear_1_out_0 = builder.MakeIntermediate(); - auto* transpose_2_out_0 = builder.MakeOutput(); - - auto& transpose_1 = builder.AddNode("Transpose", {input0_arg}, {transpose_1_out_0}); - transpose_1.AddAttribute("perm", std::vector{0, 3, 1, 2}); - builder.AddNode("DequantizeLinear", {transpose_1_out_0, input1_arg, input2_arg}, {dequantizelinear_1_out_0}); - auto& transpose_2 = builder.AddNode("Transpose", {dequantizelinear_1_out_0}, {transpose_2_out_0}); - transpose_2.AddAttribute("perm", std::vector{0, 2, 3, 1}); - }; +TEST(TransposeOptimizerTests, TestDequantizeLinearScalarIgnoreAxis) { + std::optional> zp_input_shape = std::vector{}; + std::vector zp_value_shape{}; + auto ignored_axis = utils::MakeAttribute("axis", static_cast(10)); // Should be ignored for per-tensor Q + + RunDequantizeLinearTestCase(zp_input_shape, zp_value_shape, ignored_axis, kOnnxDomain); +#if !defined(DISABLE_CONTRIB_OPS) + // Use com.microsoft.DequantizeLinear ops + RunDequantizeLinearTestCase(zp_input_shape, zp_value_shape, ignored_axis, kMSDomain); + RunDequantizeLinearTestCase(zp_input_shape, zp_value_shape, ignored_axis, kMSDomain); + RunDequantizeLinearTestCase(zp_input_shape, zp_value_shape, ignored_axis, kMSDomain); +#endif +} - auto check_optimized_graph_1 = [&](InferenceSessionWrapper& session) { - int transpose_cost = EstimateTransposeCost(session.GetGraph()); - EXPECT_EQ(transpose_cost, 0); - }; +TEST(TransposeOptimizerTests, TestDequantizeLinearVector) { + std::optional> zp_input_shape = std::vector{2}; + std::vector zp_value_shape = {2}; + auto axis = utils::MakeAttribute("axis", static_cast(-4)); + + RunDequantizeLinearTestCase(zp_input_shape, zp_value_shape, axis, kOnnxDomain); +#if !defined(DISABLE_CONTRIB_OPS) + // Use com.microsoft.DequantizeLinear ops + RunDequantizeLinearTestCase(zp_input_shape, zp_value_shape, axis, kMSDomain); + RunDequantizeLinearTestCase(zp_input_shape, zp_value_shape, axis, kMSDomain); + RunDequantizeLinearTestCase(zp_input_shape, zp_value_shape, axis, kMSDomain); +#endif +} - TransformerTester(build_test_case_1, - check_optimized_graph_1, - TransformerLevel::Default, - TransformerLevel::Level1, - /*opset_version*/ 10); +TEST(TransposeOptimizerTests, TestDequantizeLinearNoAxis) { + std::optional> zp_input_shape = std::vector{}; + std::vector zp_value_shape{}; + std::optional no_axis; // Empty axis value will not be set. + + RunDequantizeLinearTestCase(zp_input_shape, zp_value_shape, no_axis, kOnnxDomain); +#if !defined(DISABLE_CONTRIB_OPS) + // Use com.microsoft.DequantizeLinear ops + RunDequantizeLinearTestCase(zp_input_shape, zp_value_shape, no_axis, kMSDomain); + RunDequantizeLinearTestCase(zp_input_shape, zp_value_shape, no_axis, kMSDomain); + RunDequantizeLinearTestCase(zp_input_shape, zp_value_shape, no_axis, kMSDomain); +#endif } -TEST(TransposeOptimizerTests, TestDequantizeLinearTransposePropagation) { - auto build_test_case_1 = [&](ModelTestBuilder& builder) { - auto* input0_arg = MakeInput(builder, {{2, -1, 6, 3}}, {2, 4, 6, 3}, 0, 5); - auto* input1_arg = MakeInput(builder, {std::vector{}}, std::vector{}, {2.3f}); - auto* input2_arg = MakeInput(builder, {std::vector{}}, std::vector{}, {10}); +// Utility function that runs TransformerTester for the graph in which a single DequantizeLinear node is +// the parent of two Transpose nodes. The DQ should be duplicated by EnsureUniqueDQForNodeUnit, and the +// Transposes should be pushed. +template +static void RunDequantizeLinearTransposePropagationTestCase(const std::string& dq_domain = "") { + auto build_test_case = [dq_domain](ModelTestBuilder& builder) { + auto* input0_arg = MakeInput(builder, {{2, -1, 6, 3}}, {2, 4, 6, 3}, 0, 5); + auto* scale_arg = MakeInput(builder, {std::vector{}}, std::vector{}, {2.3f}); + auto* zero_point_arg = MakeInput(builder, {std::vector{}}, std::vector{}, {10}); auto* dequantizelinear_1_out_0 = builder.MakeIntermediate(); auto* transpose_1_out_0 = builder.MakeOutput(); auto* transpose_2_out_0 = builder.MakeOutput(); - builder.AddNode("DequantizeLinear", {input0_arg, input1_arg, input2_arg}, {dequantizelinear_1_out_0}); + builder.AddNode("DequantizeLinear", {input0_arg, scale_arg, zero_point_arg}, {dequantizelinear_1_out_0}, + dq_domain); auto& transpose_1 = builder.AddNode("Transpose", {dequantizelinear_1_out_0}, {transpose_1_out_0}); transpose_1.AddAttribute("perm", std::vector{0, 3, 1, 2}); @@ -3748,12 +3762,13 @@ TEST(TransposeOptimizerTests, TestDequantizeLinearTransposePropagation) { transpose_2.AddAttribute("perm", std::vector{0, 2, 3, 1}); }; - auto check_graph = [&](InferenceSessionWrapper& session) { + auto check_graph = [dq_domain](InferenceSessionWrapper& session) { const auto& graph = session.GetGraph(); + const char* dq_count_key = (dq_domain == kMSDomain) ? "com.microsoft.DequantizeLinear" : "DequantizeLinear"; const auto op_count = CountOpsInGraph(graph); decltype(op_count) expected_op_count{ - {"DequantizeLinear", 2}, // EnsureUniqueDQForNodeUnit should duplicate the original DQ + {dq_count_key, 2}, // EnsureUniqueDQForNodeUnit should duplicate the original DQ {"Transpose", 2}, }; ASSERT_EQ(op_count, expected_op_count); @@ -3767,13 +3782,23 @@ TEST(TransposeOptimizerTests, TestDequantizeLinearTransposePropagation) { } }; - TransformerTester(build_test_case_1, + TransformerTester(build_test_case, check_graph, TransformerLevel::Default, TransformerLevel::Level1, /*opset_version*/ 10); } +TEST(TransposeOptimizerTests, TestDequantizeLinearTransposePropagation) { + RunDequantizeLinearTransposePropagationTestCase(); +#if !defined(DISABLE_CONTRIB_OPS) + // Use com.microsoft.DequantizeLinear + RunDequantizeLinearTransposePropagationTestCase(kMSDomain); + RunDequantizeLinearTransposePropagationTestCase(kMSDomain); + RunDequantizeLinearTransposePropagationTestCase(kMSDomain); +#endif +} + TEST(TransposeOptimizerTests, TestCast) { auto build_test_case_1 = [&](ModelTestBuilder& builder) { auto* input0_arg = MakeInput(builder, {{-1, 4, -1, 5}}, {2, 4, 6, 5}, -1, 5); @@ -4485,12 +4510,6 @@ TEST(TransposeOptimizerTests, QnnTransposeReshapeQDQ) { SessionOptions so; - // enable dumping graph so one test validates that infrastructure works. we don't want to do that in multiple - // tests as the filenames for the debug output are hardcoded. - // check the build output directory for files called `post_layout_transform_step_.onnx` to see how the graph - // changes during the layout transformation process. - ASSERT_STATUS_OK(so.config_options.AddConfigEntry(kDebugLayoutTransformation, "1")); - using InternalTestingEP = onnxruntime::internal_testing_ep::InternalTestingExecutionProvider; // set the test EP to support all ops in the model so that the layout transform applies to all nodes diff --git a/onnxruntime/test/perftest/README.md b/onnxruntime/test/perftest/README.md index 9dc6d8c927eba..59059cf6b62b7 100644 --- a/onnxruntime/test/perftest/README.md +++ b/onnxruntime/test/perftest/README.md @@ -14,7 +14,7 @@ Options: -c: [parallel runs]: Specifies the (max) number of runs to invoke simultaneously. Default:1. - -e: [cpu|cuda|mkldnn|tensorrt|openvino|acl]: Specifies the execution provider 'cpu','cuda','dnnn','tensorrt', 'openvino', or 'acl'. Default is 'cpu'. + -e: [cpu|cuda|mkldnn|tensorrt|openvino|acl|vitisai]: Specifies the execution provider 'cpu','cuda','dnnn','tensorrt', 'openvino', 'acl' and 'vitisai'. Default is 'cpu'. -m: [test_mode]: Specifies the test mode. Value coulde be 'duration' or 'times'. Provide 'duration' to run the test for a fix duration, and 'times' to repeated for a certain times. Default:'duration'. diff --git a/onnxruntime/test/perftest/command_args_parser.cc b/onnxruntime/test/perftest/command_args_parser.cc index 4806240e3a844..56f924ed351fb 100644 --- a/onnxruntime/test/perftest/command_args_parser.cc +++ b/onnxruntime/test/perftest/command_args_parser.cc @@ -33,8 +33,8 @@ namespace perftest { "\t-A: Disable memory arena\n" "\t-I: Generate tensor input binding (Free dimensions are treated as 1.)\n" "\t-c [parallel runs]: Specifies the (max) number of runs to invoke simultaneously. Default:1.\n" - "\t-e [cpu|cuda|dnnl|tensorrt|openvino|dml|acl|nnapi|coreml|snpe|rocm|migraphx|xnnpack]: Specifies the provider 'cpu','cuda','dnnl','tensorrt', " - "'openvino', 'dml', 'acl', 'nnapi', 'coreml', 'qnn', 'snpe', 'rocm', 'migraphx' or 'xnnpack'. " + "\t-e [cpu|cuda|dnnl|tensorrt|openvino|dml|acl|nnapi|coreml|snpe|rocm|migraphx|xnnpack|vitisai]: Specifies the provider 'cpu','cuda','dnnl','tensorrt', " + "'openvino', 'dml', 'acl', 'nnapi', 'coreml', 'snpe', 'rocm', 'migraphx', 'xnnpack' or 'vitisai'. " "Default:'cpu'.\n" "\t-b [tf|ort]: backend to use. Default:ort\n" "\t-r [repeated_times]: Specifies the repeated times if running in 'times' test mode.Default:1000.\n" @@ -64,8 +64,12 @@ namespace perftest { "\t [OpenVINO only] [cache_dir]: Explicitly specify the path to dump and load the blobs(Model caching) or cl_cache (Kernel Caching) files feature. If blob files are already present, it will be directly loaded.\n" "\t [OpenVINO only] [enable_opencl_throttling]: Enables OpenCL queue throttling for GPU device(Reduces the CPU Utilization while using GPU) \n" "\t [QNN only] [backend_path]: QNN backend path. e.g '/folderpath/libQnnHtp.so', '/folderpath/libQnnCpu.so'.\n" + "\t [QNN only] [qnn_context_cache_enable]: 1 to enable cache QNN context. Default to false.\n" + "\t [QNN only] [qnn_context_cache_path]: File path to the qnn context cache. Default to model_file.onnx.bin if not set.\n" "\t [QNN only] [profiling_level]: QNN profiling level, options: 'basic', 'detailed', default 'off'.\n" "\t [QNN only] [rpc_control_latency]: QNN rpc control latency. default to 10.\n" + "\t [QNN only] [htp_performance_mode]: QNN performance mode, options: 'burst', 'balanced', 'default', 'high_performance', \n" + "\t 'high_power_saver', 'low_balanced', 'low_power_saver', 'power_saver', 'sustained_high_performance'. Default to 'default'. \n" "\t [Usage]: -e -i '| |'\n\n" "\t [Example] [For OpenVINO EP] -e openvino -i \"device_type|CPU_FP32 enable_vpu_fast_compile|true num_of_threads|5 enable_opencl_throttling|true cache_dir|\"\"\"\n" "\t [Example] [For QNN EP] -e qnn -i \"backend_path|/folderpath/libQnnCpu.so\" \n\n" @@ -95,6 +99,7 @@ namespace perftest { "\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" + "\t [SNPE only] [enable_init_cache]: enable SNPE init caching feature, set to 1 to enabled it. Disabled by default. \n" "\t [Usage]: -e -i '| |' \n\n" "\t [Example] [For SNPE EP] -e snpe -i \"runtime|CPU priority|low\" \n\n" "\t-T [Set intra op thread affinities]: Specify intra op thread affinity string\n" @@ -206,6 +211,8 @@ static bool ParseDimensionOverride(std::basic_string& dim_identifier, test_config.machine_config.provider_type_name = onnxruntime::kMIGraphXExecutionProvider; } else if (!CompareCString(optarg, ORT_TSTR("xnnpack"))) { test_config.machine_config.provider_type_name = onnxruntime::kXnnpackExecutionProvider; + } else if (!CompareCString(optarg, ORT_TSTR("vitisai"))) { + test_config.machine_config.provider_type_name = onnxruntime::kVitisAIExecutionProvider; } else { return false; } diff --git a/onnxruntime/test/perftest/ort_test_session.cc b/onnxruntime/test/perftest/ort_test_session.cc index cbadcef09a5a7..57b2403e23a37 100644 --- a/onnxruntime/test/perftest/ort_test_session.cc +++ b/onnxruntime/test/perftest/ort_test_session.cc @@ -126,10 +126,14 @@ OnnxRuntimeTestSession::OnnxRuntimeTestSession(Ort::Env& env, std::random_device bool trt_detailed_build_log = false; bool trt_build_heuristics_enable = false; bool trt_sparsity_enable = false; - int trt_builder_optimization_level = 2; + int trt_builder_optimization_level = 3; int trt_auxiliary_streams = -1; std::string trt_tactic_sources = ""; std::string trt_extra_plugin_lib_paths = ""; + std::string trt_profile_min_shapes = ""; + std::string trt_profile_max_shapes = ""; + std::string trt_profile_opt_shapes = ""; + bool trt_cuda_graph_enable = false; #ifdef _MSC_VER std::string ov_string = ToUTF8String(performance_test_config.run_config.ep_runtime_config_string); @@ -193,7 +197,7 @@ OnnxRuntimeTestSession::OnnxRuntimeTestSession(Ort::Env& env, std::random_device if (!value.empty()) { trt_int8_calibration_table_name = value; } else { - ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_int8_calibration_table_name' should be a non-emtpy string.\n"); + ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_int8_calibration_table_name' should be a non-empty string.\n"); } } else if (key == "trt_int8_use_native_calibration_table") { if (value == "true" || value == "True") { @@ -237,7 +241,7 @@ OnnxRuntimeTestSession::OnnxRuntimeTestSession(Ort::Env& env, std::random_device if (!value.empty()) { trt_engine_cache_path = value; } else { - ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_engine_cache_path' should be a non-emtpy string.\n"); + ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_engine_cache_path' should be a non-empty string.\n"); } } else if (key == "trt_engine_decryption_enable") { if (value == "true" || value == "True") { @@ -251,7 +255,7 @@ OnnxRuntimeTestSession::OnnxRuntimeTestSession(Ort::Env& env, std::random_device if (!value.empty()) { trt_engine_decryption_lib_path = value; } else { - ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_engine_decryption_lib_path' should be a non-emtpy string.\n"); + ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_engine_decryption_lib_path' should be a non-empty string.\n"); } } else if (key == "trt_force_sequential_engine_build") { if (value == "true" || value == "True") { @@ -333,16 +337,42 @@ OnnxRuntimeTestSession::OnnxRuntimeTestSession(Ort::Env& env, std::random_device if (!value.empty()) { trt_tactic_sources = value; } else { - ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_tactic_sources' should be a non-emtpy string.\n"); + ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_tactic_sources' should be a non-empty string.\n"); } } else if (key == "trt_extra_plugin_lib_paths") { if (!value.empty()) { trt_extra_plugin_lib_paths = value; } else { - ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_extra_plugin_lib_paths' should be a non-emtpy string.\n"); + ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_extra_plugin_lib_paths' should be a non-empty string.\n"); + } + } else if (key == "trt_profile_min_shapes") { + if (!value.empty()) { + trt_profile_min_shapes = value; + } else { + ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_profile_min_shapes' should be a non-empty string.\n"); + } + } else if (key == "trt_profile_max_shapes") { + if (!value.empty()) { + trt_profile_max_shapes = value; + } else { + ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_profile_max_shapes' should be a non-empty string.\n"); + } + } else if (key == "trt_profile_opt_shapes") { + if (!value.empty()) { + trt_profile_opt_shapes = value; + } else { + ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_profile_opt_shapes' should be a non-empty string.\n"); + } + } else if (key == "trt_cuda_graph_enable") { + if (value == "true" || value == "True") { + trt_cuda_graph_enable = true; + } else if (value == "false" || value == "False") { + trt_cuda_graph_enable = false; + } else { + ORT_THROW("[ERROR] [TensorRT] The value for the key 'trt_cuda_graph_enable' should be a boolean i.e. true or false. Default value is false.\n"); } } else { - ORT_THROW("[ERROR] [TensorRT] wrong key type entered. Choose from the following runtime key options that are available for TensorRT. ['device_id', 'trt_max_partition_iterations', 'trt_min_subgraph_size', 'trt_max_workspace_size', 'trt_fp16_enable', 'trt_int8_enable', 'trt_int8_calibration_table_name', 'trt_int8_use_native_calibration_table', 'trt_dla_enable', 'trt_dla_core', 'trt_dump_subgraphs', 'trt_engine_cache_enable', 'trt_engine_cache_path', 'trt_engine_decryption_enable', 'trt_engine_decryption_lib_path', 'trt_force_sequential_engine_build', 'trt_context_memory_sharing_enable', 'trt_layer_norm_fp32_fallback', 'trt_extra_plugin_lib_paths'] \n"); + ORT_THROW("[ERROR] [TensorRT] wrong key type entered. Choose from the following runtime key options that are available for TensorRT. ['device_id', 'trt_max_partition_iterations', 'trt_min_subgraph_size', 'trt_max_workspace_size', 'trt_fp16_enable', 'trt_int8_enable', 'trt_int8_calibration_table_name', 'trt_int8_use_native_calibration_table', 'trt_dla_enable', 'trt_dla_core', 'trt_dump_subgraphs', 'trt_engine_cache_enable', 'trt_engine_cache_path', 'trt_engine_decryption_enable', 'trt_engine_decryption_lib_path', 'trt_force_sequential_engine_build', 'trt_context_memory_sharing_enable', 'trt_layer_norm_fp32_fallback', 'trt_timing_cache_enable', 'trt_force_timing_cache', 'trt_detailed_build_log', 'trt_build_heuristics_enable', 'trt_sparsity_enable', 'trt_builder_optimization_level', 'trt_auxiliary_streams', 'trt_tactic_sources', 'trt_extra_plugin_lib_paths', 'trt_profile_min_shapes', 'trt_profile_max_shapes', 'trt_profile_opt_shapes', 'trt_cuda_graph_enable'] \n"); } } OrtTensorRTProviderOptionsV2 tensorrt_options; @@ -375,6 +405,11 @@ OnnxRuntimeTestSession::OnnxRuntimeTestSession(Ort::Env& env, std::random_device tensorrt_options.trt_auxiliary_streams = trt_auxiliary_streams; tensorrt_options.trt_tactic_sources = trt_tactic_sources.c_str(); tensorrt_options.trt_extra_plugin_lib_paths = trt_extra_plugin_lib_paths.c_str(); + tensorrt_options.trt_profile_min_shapes = trt_profile_min_shapes.c_str(); + tensorrt_options.trt_profile_max_shapes = trt_profile_max_shapes.c_str(); + tensorrt_options.trt_profile_opt_shapes = trt_profile_opt_shapes.c_str(); + tensorrt_options.trt_cuda_graph_enable = trt_cuda_graph_enable; + session_options.AppendExecutionProvider_TensorRT_V2(tensorrt_options); OrtCUDAProviderOptions cuda_options; @@ -388,24 +423,12 @@ OnnxRuntimeTestSession::OnnxRuntimeTestSession(Ort::Env& env, std::random_device #endif } else if (provider_name == onnxruntime::kOpenVINOExecutionProvider) { #ifdef USE_OPENVINO - std::string device_type = ""; // [device_type]: Overrides the accelerator hardware type and precision - // with these values at runtime. - bool enable_vpu_fast_compile = false; // [enable_vpu_fast_compile]: Fast-compile may be optionally enabled to - // speeds up the model's compilation to VPU device specific format. - std::string device_id = ""; // [device_id]: Selects a particular hardware device for inference. - size_t num_of_threads = 8; // [num_of_threads]: Overrides the accelerator default value of number of - // threads with this value at runtime. - std::string cache_dir = ""; // [cache_dir]: specify the path to - // dump and load the blobs for the model caching/kernel caching (GPU) - // feature. If blob files are already present, it will be directly loaded. - bool enable_opencl_throttling = false; // [enable_opencl_throttling]: Enables OpenCL queue throttling for GPU - // device (Reduces CPU Utilization when using GPU) - bool enable_dynamic_shapes = false; // [enable_dynamic_shapes]: Enables Dynamic Shapes feature for CPU device) #ifdef _MSC_VER std::string ov_string = ToUTF8String(performance_test_config.run_config.ep_runtime_config_string); #else std::string ov_string = performance_test_config.run_config.ep_runtime_config_string; #endif + std::unordered_map ov_options; std::istringstream ss(ov_string); std::string token; while (ss >> token) { @@ -423,72 +446,69 @@ OnnxRuntimeTestSession::OnnxRuntimeTestSession(Ort::Env& env, std::random_device if (key == "device_type") { std::set ov_supported_device_types = {"CPU_FP32", "CPU_FP16", "GPU_FP32", "GPU.0_FP32", "GPU.1_FP32", "GPU_FP16", - "GPU.0_FP16", "GPU.1_FP16", "VAD-M_FP16", - "MYRIAD_FP16", "VAD-F_FP32"}; + "GPU.0_FP16", "GPU.1_FP16", + "VPUX_FP16", "VPUX_U8"}; if (ov_supported_device_types.find(value) != ov_supported_device_types.end()) { - device_type = value; + ov_options[key] = value; } else if (value.find("HETERO:") == 0) { - device_type = value; + ov_options[key] = value; } else if (value.find("MULTI:") == 0) { - device_type = value; + ov_options[key] = value; } else if (value.find("AUTO:") == 0) { - device_type = value; + ov_options[key] = value; } else { ORT_THROW( "[ERROR] [OpenVINO] You have selcted wrong configuration value for the key 'device_type'. " "Select from 'CPU_FP32', 'CPU_FP16', 'GPU_FP32', 'GPU.0_FP32', 'GPU.1_FP32', 'GPU_FP16', " - "'GPU.0_FP16', 'GPU.1_FP16', 'VAD-M_FP16', 'MYRIAD_FP16', 'VAD-F_FP32' or from" + "'GPU.0_FP16', 'GPU.1_FP16', 'VPUX_FP16', 'VPUX_U8' or from" " HETERO/MULTI/AUTO options available. \n"); } } else if (key == "device_id") { - device_id = value; + ov_options[key] = value; } else if (key == "enable_vpu_fast_compile") { - if (value == "true" || value == "True") { - enable_vpu_fast_compile = true; - } else if (value == "false" || value == "False") { - enable_vpu_fast_compile = false; + if (value == "true" || value == "True" || + value == "false" || value == "False") { + ov_options[key] = value; } else { ORT_THROW("[ERROR] [OpenVINO] The value for the key 'enable_vpu_fast_compile' should be a boolean i.e. true or false. Default value is false.\n"); } } else if (key == "enable_opencl_throttling") { - if (value == "true" || value == "True") { - enable_opencl_throttling = true; - } else if (value == "false" || value == "False") { - enable_opencl_throttling = false; + if (value == "true" || value == "True" || + value == "false" || value == "False") { + ov_options[key] = value; } else { ORT_THROW("[ERROR] [OpenVINO] The value for the key 'enable_opencl_throttling' should be a boolean i.e. true or false. Default value is false.\n"); } } else if (key == "enable_dynamic_shapes") { - if (value == "true" || value == "True") { - enable_dynamic_shapes = true; - } else if (value == "false" || value == "False") { - enable_dynamic_shapes = false; + if (value == "true" || value == "True" || + value == "false" || value == "False") { + ov_options[key] = value; } else { ORT_THROW( "[ERROR] [OpenVINO] The value for the key 'enable_dynamic_shapes' " "should be a boolean i.e. true or false. Default value is false.\n"); } } else if (key == "num_of_threads") { - std::stringstream sstream(value); - sstream >> num_of_threads; - if ((int)num_of_threads <= 0) { + if (std::stoi(value) <= 0) { ORT_THROW("[ERROR] [OpenVINO] The value for the key 'num_of_threads' should be greater than 0\n"); + } else { + ov_options[key] = value; } } else if (key == "cache_dir") { - cache_dir = value; + ov_options[key] = value; + } else if (key == "context") { + ov_options[key] = value; + } else if (key == "num_streams") { + if (std::stoi(value) <= 0 && std::stoi(value) > 8) { + ORT_THROW("[ERROR] [OpenVINO] The value for the key 'num_streams' should be in the range of 1-8 \n"); + } else { + ov_options[key] = value; + } } else { - ORT_THROW("[ERROR] [OpenVINO] wrong key type entered. Choose from the following runtime key options that are available for OpenVINO. ['device_type', 'device_id', 'enable_vpu_fast_compile', 'num_of_threads', 'cache_dir', 'enable_opencl_throttling|true'] \n"); + ORT_THROW("[ERROR] [OpenVINO] wrong key type entered. Choose from the following runtime key options that are available for OpenVINO. ['device_type', 'device_id', 'enable_vpu_fast_compile', 'num_of_threads', 'cache_dir', 'num_streams', 'enable_opencl_throttling|true'] \n"); } } - OrtOpenVINOProviderOptions options; - options.device_type = device_type.c_str(); // To set the device_type - options.device_id = device_id.c_str(); // To set the device_id - options.enable_vpu_fast_compile = enable_vpu_fast_compile; // To enable_vpu_fast_compile, default is false - options.num_of_threads = num_of_threads; // To set number of free InferRequests, default is 8 - options.cache_dir = cache_dir.c_str(); // sets the cache_dir, default is "" - options.enable_opencl_throttling = enable_opencl_throttling; // Enables GPU Throttling (Reduces CPU Utilization) - options.enable_dynamic_shapes = enable_dynamic_shapes; // Enables Dynamic Shapes feature - session_options.AppendExecutionProvider_OpenVINO(options); + session_options.AppendExecutionProvider("OpenVINO", ov_options); #else ORT_THROW("OpenVINO is not supported in this build\n"); #endif @@ -516,20 +536,39 @@ OnnxRuntimeTestSession::OnnxRuntimeTestSession(Ort::Env& env, std::random_device std::string value(token.substr(pos + 1)); if (key == "backend_path") { - std::set qnn_backend_path; if (value.empty()) { ORT_THROW("Please provide the QNN backend path."); - } else { - qnn_options[key] = value; } + } else if (key == "qnn_context_cache_enable") { + if (value != "1") { + ORT_THROW("Set to 1 to enable qnn_context_cache_enable."); + } + } else if (key == "qnn_context_cache_path") { + // no validation } else if (key == "profiling_level") { - qnn_options[key] = value; + std::set supported_profiling_level = {"off", "basic", "detailed"}; + if (supported_profiling_level.find(value) == supported_profiling_level.end()) { + ORT_THROW("Supported profiling_level: off, basic, detailed"); + } } else if (key == "rpc_control_latency") { - qnn_options[key] = value; + // no validation + } else if (key == "htp_performance_mode") { + std::set supported_htp_perf_mode = {"burst", "balanced", "default", "high_performance", + "high_power_saver", "low_balanced", "low_power_saver", + "power_saver", "sustained_high_performance"}; + if (supported_htp_perf_mode.find(value) == supported_htp_perf_mode.end()) { + std::ostringstream str_stream; + std::copy(supported_htp_perf_mode.begin(), supported_htp_perf_mode.end(), + std::ostream_iterator(str_stream, ",")); + std::string str = str_stream.str(); + ORT_THROW("Supported htp_performance_mode: " + str); + } } else { - ORT_THROW(R"(Wrong key type entered. Choose from options: -['backend_path', 'profiling_level', 'rpc_control_latency'])"); + ORT_THROW(R"(Wrong key type entered. Choose from options: ['backend_path', 'qnn_context_cache_enable', +'qnn_context_cache_path', 'profiling_level', 'rpc_control_latency', 'htp_performance_mode'])"); } + + qnn_options[key] = value; } session_options.AppendExecutionProvider("QNN", qnn_options); #else @@ -572,8 +611,12 @@ select from 'CPU', 'GPU_FP32', 'GPU', 'GPU_FLOAT16', 'DSP', 'AIP_FIXED_TF'. \n)" ORT_THROW(R"(Wrong configuration value for the key 'buffer_type'. select from 'TF8', 'TF16', 'UINT8', 'FLOAT', 'ITENSOR'. \n)"); } + } else if (key == "enable_init_cache") { + if (value != "1") { + ORT_THROW("Set to 1 to enable_init_cache."); + } } else { - ORT_THROW("Wrong key type entered. Choose from options: ['runtime', 'priority', 'buffer_type'] \n"); + ORT_THROW("Wrong key type entered. Choose from options: ['runtime', 'priority', 'buffer_type', 'enable_init_cache'] \n"); } snpe_options[key] = value; @@ -665,6 +708,34 @@ select from 'TF8', 'TF16', 'UINT8', 'FLOAT', 'ITENSOR'. \n)"); "XNNPACK", {{"intra_op_num_threads", std::to_string(performance_test_config.run_config.intra_op_num_threads)}}); #else ORT_THROW("Xnnpack is not supported in this build\n"); +#endif + } else if (provider_name == onnxruntime::kVitisAIExecutionProvider) { +#ifdef USE_VITISAI +#ifdef _MSC_VER + std::string option_string = ToUTF8String(performance_test_config.run_config.ep_runtime_config_string); +#else + std::string option_string = performance_test_config.run_config.ep_runtime_config_string; +#endif + std::istringstream ss(option_string); + std::string token; + std::unordered_map vitisai_session_options; + + while (ss >> token) { + if (token == "") { + continue; + } + auto pos = token.find("|"); + if (pos == std::string::npos || pos == 0 || pos == token.length()) { + ORT_THROW("[ERROR] [VitisAI] Use a '|' to separate the key and value for the run-time option you are trying to use.\n"); + } + + std::string key(token.substr(0, pos)); + std::string value(token.substr(pos + 1)); + vitisai_session_options[key] = value; + } + session_options.AppendExecutionProvider("VitisAI", vitisai_session_options); +#else + ORT_THROW("VitisAI is not supported in this build\n"); #endif } else if (!provider_name.empty() && provider_name != onnxruntime::kCpuExecutionProvider) { ORT_THROW("This backend is not included in perf test runner.\n"); @@ -818,6 +889,12 @@ static void InitializeTensorWithSeed(int32_t seed, Ort::Value& tensor) { CASE_FOR_TYPE(uint32_t); CASE_FOR_TYPE(uint64_t); CASE_FOR_TYPE(bool); +#if !defined(DISABLE_FLOAT8_TYPES) + CASE_FOR_TYPE(Ort::Float8E4M3FN_t); + CASE_FOR_TYPE(Ort::Float8E4M3FNUZ_t); + CASE_FOR_TYPE(Ort::Float8E5M2_t); + CASE_FOR_TYPE(Ort::Float8E5M2FNUZ_t); +#endif case ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING: // string tensors are already initialized to contain empty strings // see onnxruntime::Tensor::Init() diff --git a/onnxruntime/test/perftest/performance_runner.cc b/onnxruntime/test/perftest/performance_runner.cc index 99abd3bbf10d7..9f2cbcf6a21f1 100644 --- a/onnxruntime/test/perftest/performance_runner.cc +++ b/onnxruntime/test/perftest/performance_runner.cc @@ -32,6 +32,13 @@ using onnxruntime::Status; #ifdef HAS_CLASS_MEMACCESS #pragma GCC diagnostic ignored "-Wclass-memaccess" #endif +// eigen-src/unsupported/Eigen/CXX11/src/ThreadPool/EventCount.h:231:56: error: implicit conversion loses integer +// precision: 'uint64_t' (aka 'unsigned long long') to 'size_t' (aka 'unsigned long') [-Werror,-Wshorten-64-to-32] +// next = wnext == kStackMask ? nullptr : &waiters_[wnext]; +// ~~~~~~~~ ^~~~~ +#ifdef HAS_SHORTEN_64_TO_32 +#pragma GCC diagnostic ignored "-Wshorten-64-to-32" +#endif #endif #include #if defined(__GNUC__) diff --git a/onnxruntime/test/providers/azure/azure_basic_test.cc b/onnxruntime/test/providers/azure/azure_basic_test.cc index 63207f0a76170..8d7f791e2651a 100644 --- a/onnxruntime/test/providers/azure/azure_basic_test.cc +++ b/onnxruntime/test/providers/azure/azure_basic_test.cc @@ -23,72 +23,5 @@ TEST(AzureEP, TestSessionCreation) { EXPECT_NO_THROW((Ort::Session{*ort_env, ort_model_path, so})); } -TEST(AzureEP, TestSessionRunMissingConfig) { - const auto* ort_model_path = ORT_TSTR("testdata/mul_1.onnx"); - Ort::SessionOptions so; - onnxruntime::ProviderOptions options; - so.AppendExecutionProvider("AZURE", options); - Ort::Session sess(*ort_env, ort_model_path, so); - - float raw_inputs[] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; - std::vector input_dims = {3, 2}; - std::vector input_values; - const char* input_names[] = {"X"}; - const char* output_names[] = {"Y"}; - auto default_allocator = std::make_unique(); - input_values.emplace_back(Ort::Value::CreateTensor(default_allocator->Info(), raw_inputs, 6, input_dims.data(), 2)); - - Ort::RunOptions run_options; - run_options.AddConfigEntry("use_azure", "1"); - // exception expected due to the missing of endpoint type - EXPECT_THROW(sess.Run(run_options, input_names, input_values.data(), 1UL, output_names, 1UL), Ort::Exception); -} - -TEST(AzureEP, TestSessionRunMissingEP) { - const auto* ort_model_path = ORT_TSTR("testdata/mul_1.onnx"); - Ort::SessionOptions so; - so.AddConfigEntry("azure.endpoint_type", "triton"); - Ort::Session sess(*ort_env, ort_model_path, so); - - float raw_inputs[] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; - std::vector input_dims = {3, 2}; - std::vector input_values; - const char* input_names[] = {"X"}; - const char* output_names[] = {"Y"}; - auto default_allocator = std::make_unique(); - input_values.emplace_back(Ort::Value::CreateTensor(default_allocator->Info(), raw_inputs, 6, input_dims.data(), 2)); - - Ort::RunOptions run_options; - // local inference should work - EXPECT_NO_THROW(sess.Run(run_options, input_names, input_values.data(), 1UL, output_names, 1UL)); - - run_options.AddConfigEntry("use_azure", "1"); - // exception expected due to the missing of azure.uri and azure.model_name - EXPECT_THROW(sess.Run(run_options, input_names, input_values.data(), 1UL, output_names, 1UL), Ort::Exception); -} - -TEST(AzureEP, TestSessionRunWrongUri) { - const auto* ort_model_path = ORT_TSTR("testdata/mul_1.onnx"); - Ort::SessionOptions so; - so.AddConfigEntry("azure.endpoint_type", "triton"); - so.AddConfigEntry("azure.uri", "https://12341nbasdkjah1239045dsknldjnlvqwf.com"); - so.AddConfigEntry("azure.model_name", "modelnotexist"); - Ort::Session sess(*ort_env, ort_model_path, so); - - float raw_inputs[] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; - std::vector input_dims = {3, 2}; - std::vector input_values; - const char* input_names[] = {"X"}; - const char* output_names[] = {"Y"}; - auto default_allocator = std::make_unique(); - input_values.emplace_back(Ort::Value::CreateTensor(default_allocator->Info(), raw_inputs, 6, input_dims.data(), 2)); - - Ort::RunOptions run_options; - run_options.AddConfigEntry("use_azure", "1"); - run_options.AddConfigEntry("azure.auth_key", "asdjfakldkvnlkajefoiauh32hriunive2324"); - // exception expected due to the non-existing endpoint - EXPECT_THROW(sess.Run(run_options, input_names, input_values.data(), 1UL, output_names, 1UL), Ort::Exception); -} - } // namespace test } // namespace onnxruntime \ No newline at end of file diff --git a/onnxruntime/test/providers/base_tester.cc b/onnxruntime/test/providers/base_tester.cc new file mode 100644 index 0000000000000..459a8c71ad611 --- /dev/null +++ b/onnxruntime/test/providers/base_tester.cc @@ -0,0 +1,879 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "test/providers/base_tester.h" + +#include +#include "gmock/gmock.h" + +#include "core/common/logging/logging.h" +#include "core/framework/tensorprotoutils.h" +#include "core/graph/constants.h" +#include "core/graph/model_load_utils.h" +#include "core/session/inference_session.h" +#include "core/session/onnxruntime_session_options_config_keys.h" + +#include "test/framework/TestAllocatorManager.h" +#include "test/providers/run_options_config_keys.h" +#include "test/util/include/asserts.h" +#include "test/util/include/default_providers.h" +#include "test/util/include/test_utils.h" +#include "test/util/include/test_environment.h" + +#ifdef ENABLE_TRAINING +#include "orttraining/core/session/training_session.h" +#endif + +using namespace ::onnxruntime::logging; + +namespace onnxruntime { +namespace test { +namespace { + +#ifndef NDEBUG +void DebugTrap() { +#if _MSC_VER + __debugbreak(); +#else + raise(SIGTRAP); +#endif +} +#endif +} // namespace + +BaseTester::~BaseTester() { +#ifndef NDEBUG + if (!testing_function_called_) { + std::cerr << "Test was not executed." << std::endl; + DebugTrap(); + } +#endif +} + +void BaseTester::AddInitializers(onnxruntime::Graph& graph) { + for (auto index : initializer_indexes_) { + auto& data = input_data_[index]; + auto& tensor = data.data.Get(); + ONNX_NAMESPACE::TensorProto tensor_proto; + + // 1. set dimension + auto& shape = tensor.Shape(); + for (auto& dim : shape.GetDims()) { + tensor_proto.add_dims(dim); + } + + // 2. set type + tensor_proto.set_data_type(data.def.TypeAsProto()->tensor_type().elem_type()); + + // 3. data + if (data.def.TypeAsProto()->tensor_type().elem_type() == ONNX_NAMESPACE::TensorProto_DataType_STRING) { + const std::string* string_data = tensor.Data(); + for (auto i = 0; i < shape.Size(); i++) { + tensor_proto.add_string_data(string_data[i]); + } + } else { + auto buffer_size = tensor.DataType()->Size() * shape.Size(); + tensor_proto.set_raw_data(tensor.DataRaw(), buffer_size); + } + + // 4. name + tensor_proto.set_name(data.def.Name()); + graph.AddInitializedTensor(tensor_proto); + } +} + +void BaseTester::FillFeedsAndOutputNames(std::unordered_map& feeds, + std::vector& output_names) { + for (auto& output : output_data_) { + if (output.def.Exists()) { + output_names.push_back(output.def.Name()); + } + } + + FillFeeds(feeds); +} + +void BaseTester::FillFeeds(std::unordered_map& feeds) { + for (size_t i = 0; i < input_data_.size(); ++i) { + if (std::find(initializer_indexes_.begin(), initializer_indexes_.end(), i) == initializer_indexes_.end() && + input_data_[i].def.Exists() && + // We don't include optional type OrtValues of None because this is + // how we expect users to deal with sending through "None"s as graph inputs + // (i.e.) don't send them through at all + input_data_[i].data.IsAllocated()) { + feeds[input_data_[i].def.Name()] = input_data_[i].data; + } + } +} + +void BaseTester::SetOutputAbsErr(const char* name, float v) { + auto it = std::find_if(output_data_.begin(), output_data_.end(), + [name](Data& data) { return (data.def.Name() == name); }); + ORT_ENFORCE(it != output_data_.end()); + it->validation_params.absolute_error = optional(v); +} + +void BaseTester::SetOutputRelErr(const char* name, float v) { + auto it = std::find_if(output_data_.begin(), output_data_.end(), + [name](Data& data) { return (data.def.Name() == name); }); + ORT_ENFORCE(it != output_data_.end()); + it->validation_params.relative_error = optional(v); +} + +std::vector BaseTester::GetDimsForProto(gsl::span dims) { + std::vector dims_for_proto{dims.begin(), dims.end()}; + if (add_symbolic_dim_to_tensor_data_ >= 0 && + dims.size() > static_cast(add_symbolic_dim_to_tensor_data_)) { + dims_for_proto[add_symbolic_dim_to_tensor_data_] = -1; + } + return dims_for_proto; +} + +void BaseTester::AddShapeToTensorData(NodeArg& node_arg, gsl::span dims, + const std::vector* dim_params) { + if (dim_params && !(dim_params->empty()) && add_shape_to_tensor_data_) { + // If dim_params presents, configure node_arg's dim value based on dim_params, which supports symbolic dim and dim broadcast. + const auto& dim_params_data = *dim_params; + onnx::TensorShapeProto new_shape; + + // currently hard-code the reserved symbolic names. + // TODO: when the list grows longer, consider move it to a better place. + const static std::unordered_set reserved_symbolic{"batch", "seq"}; + + for (size_t i = 0; i < dim_params_data.size(); ++i) { + if (reserved_symbolic.find(dim_params_data[i]) != reserved_symbolic.end()) { + new_shape.add_dim()->set_dim_param(dim_params_data[i]); + } else { + ASSERT_TRUE(std::stoi(dim_params_data[i]) == dims[i]); + new_shape.add_dim()->set_dim_value(dims[i]); + } + } + node_arg.SetShape(new_shape); + } +} + +#if !defined(DISABLE_SPARSE_TENSORS) +static std::unique_ptr MakeSparseTensor(MLDataType data_type, const gsl::span& dims) { + TensorShape shape{dims}; + auto allocator = test::AllocatorManager::Instance().GetAllocator(CPU); + auto p_tensor = std::make_unique(data_type, shape, std::move(allocator)); + return p_tensor; +} + +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()); +} + +NodeArg BaseTester::MakeSparseNodeArg(int32_t dtype, const char* name, const gsl::span& dims, + const std::vector* dim_params) { + std::vector dims_for_proto = GetDimsForProto(dims); + TSparseTensorProto type_proto(dtype, add_shape_to_tensor_data_ ? &dims_for_proto : nullptr); + NodeArg node_arg(name, &type_proto.proto); + AddShapeToTensorData(node_arg, dims, dim_params); + return node_arg; +} + +void BaseTester::AddSparseTensorData(std::vector& data, NodeArg node_arg, + std::unique_ptr p_tensor, + const ValidateOutputParams& check_params) { + OrtValue value; + auto ml_type = DataTypeImpl::GetType(); + value.Init(p_tensor.release(), ml_type, ml_type->GetDeleteFunc()); + data.push_back(Data(std::move(node_arg), std::move(value), + optional(check_params.relative_error), optional(check_params.absolute_error), + check_params.sort_output)); +} + +void BaseTester::AddSparseCooTensorData(std::vector& data, + MLDataType data_type, + const char* name, + gsl::span dims, + gsl::span values, + gsl::span indices, + const ValidateOutputParams& check_params, + const std::vector* dim_params) { + const auto elem_size = data_type->Size(); + const auto dtype = data_type->AsPrimitiveDataType()->GetDataType(); + const auto nnz = values.size_bytes() / elem_size; + ORT_ENFORCE(dims.size() == 2U, "Expecting a 2-D dense shape"); + ORT_ENFORCE((nnz == indices.size() || 2 * nnz == indices.size()), "Expecting indices to have either nnz or (2 * nnz) length"); + auto p_tensor = MakeSparseTensor(data_type, dims); + auto mutator = p_tensor->MakeCooData(nnz, indices.size()); + CopyDataToTensor(values, mutator.Values()); + CopyDataToTensor(gsl::as_bytes(indices), mutator.Indices()); + + NodeArg node_arg = MakeSparseNodeArg(dtype, name, dims, dim_params); + AddSparseTensorData(data, std::move(node_arg), std::move(p_tensor), check_params); +} + +void BaseTester::AddSparseCooTensorStrings(std::vector& data, + const char* name, + gsl::span dims, + gsl::span values, + gsl::span indices, + const std::vector* dim_params) { + auto data_type = DataTypeImpl::GetType(); + const auto nnz = values.size(); + const auto dtype = data_type->AsPrimitiveDataType()->GetDataType(); + ORT_ENFORCE(dims.size() == 2U, "Expecting a 2-D dense shape"); + ORT_ENFORCE((nnz == indices.size() || 2 * nnz == indices.size()), "Expecting indices to have either nnz or (2 * nnz) length"); + auto p_tensor = MakeSparseTensor(data_type, dims); + // linear index is 1-D index, otherwise 2-D index + auto mutator = p_tensor->MakeCooData(nnz, indices.size()); + auto mutable_values = mutator.Values().MutableDataAsSpan(); + ORT_ENFORCE(values.size() == mutable_values.size(), "Must allocate space for values"); + std::copy(values.begin(), values.end(), mutable_values.begin()); + CopyDataToTensor(gsl::as_bytes(indices), mutator.Indices()); + NodeArg node_arg = MakeSparseNodeArg(dtype, name, dims, dim_params); + AddSparseTensorData(data, std::move(node_arg), std::move(p_tensor), ValidateOutputParams()); +} + +void BaseTester::AddSparseCsrTensorData(std::vector& data, + MLDataType data_type, + const char* name, + gsl::span dims, + gsl::span values, + gsl::span inner_indices, + gsl::span outer_indices, + const ValidateOutputParams& check_params, + const std::vector* dim_params) { + const auto elem_size = data_type->Size(); + const auto dtype = data_type->AsPrimitiveDataType()->GetDataType(); + const auto nnz = values.size_bytes() / elem_size; + ORT_ENFORCE(dims.size() == 2U, "Expecting a 2-D dense shape"); + ORT_ENFORCE(nnz == inner_indices.size(), "Expecting the same number of inner_indices as nnz"); + auto p_tensor = MakeSparseTensor(data_type, dims); + + auto mutator = p_tensor->MakeCsrData(nnz, inner_indices.size(), outer_indices.size()); + CopyDataToTensor(values, mutator.Values()); + CopyDataToTensor(gsl::as_bytes(inner_indices), mutator.Inner()); + CopyDataToTensor(gsl::as_bytes(outer_indices), mutator.Outer()); + + NodeArg node_arg = MakeSparseNodeArg(dtype, name, dims, dim_params); + AddSparseTensorData(data, std::move(node_arg), std::move(p_tensor), check_params); +} + +void BaseTester::AddSparseCsrTensorStrings(std::vector& data, + const char* name, + gsl::span dims, + gsl::span values, + gsl::span inner_indices, + gsl::span outer_indices, + const std::vector* dim_params) { + auto data_type = DataTypeImpl::GetType(); + const auto nnz = values.size(); + const auto dtype = data_type->AsPrimitiveDataType()->GetDataType(); + + ORT_ENFORCE(dims.size() == 2U, "Expecting a 2-D dense shape"); + ORT_ENFORCE(nnz == inner_indices.size(), "Expecting the same number of inner_indices as nnz"); + auto p_tensor = MakeSparseTensor(data_type, dims); + + auto mutator = p_tensor->MakeCsrData(nnz, inner_indices.size(), outer_indices.size()); + auto mutable_values = mutator.Values().MutableDataAsSpan(); + ORT_ENFORCE(values.size() == mutable_values.size(), "Must allocate space for values"); + std::copy(values.begin(), values.end(), mutable_values.begin()); + CopyDataToTensor(gsl::as_bytes(inner_indices), mutator.Inner()); + CopyDataToTensor(gsl::as_bytes(outer_indices), mutator.Outer()); + NodeArg node_arg = MakeSparseNodeArg(dtype, name, dims, dim_params); + AddSparseTensorData(data, std::move(node_arg), std::move(p_tensor), ValidateOutputParams()); +} +#endif // !defined(DISABLE_SPARSE_TENSORS) + +template +void BaseTester::ExecuteModel(Model& model, SessionType& session, + ExpectResult expect_result, + const std::string& expected_failure_string, + const RunOptions* run_options, + const std::unordered_map& feeds, + const std::vector& output_names, + const std::string& provider_type, + bool allow_released_onnx_opset_only) { + fetches_.clear(); + + std::string s1; + const bool rc = model.ToProto().SerializeToString(&s1); + ASSERT_TRUE(rc) << "Failed to serialize proto to string"; + + std::stringstream sstr(s1); + EXPECT_STATUS_OK(session.Load(sstr, allow_released_onnx_opset_only)); + + auto status = session.Initialize(); + if (!status.IsOK()) { + ASSERT_EQ(expect_result, ExpectResult::kExpectFailure) << "Initialize failed but expected success: " + << status.ErrorMessage(); + + // Disable expected_failure_string checks for OpenVINO EP + if (provider_type != kOpenVINOExecutionProvider) { + EXPECT_THAT(status.ErrorMessage(), testing::HasSubstr(expected_failure_string)); + } + + return; + } + + RunOptions default_run_options; + + for (int i = 0; i < num_run_calls_; ++i) { + fetches_.clear(); + status = session.Run(run_options ? *run_options : default_run_options, feeds, output_names, &fetches_); + + if (status.IsOK()) { + ASSERT_EQ(expect_result, ExpectResult::kExpectSuccess) << "Run succeeded but expected failure."; + } else { + ASSERT_EQ(expect_result, ExpectResult::kExpectFailure) << "Run failed but expected success: " + << status.ErrorMessage(); + + // Disable expected_failure_string checks for MKL-DNN and OpenVINO EP's + if (provider_type != kDnnlExecutionProvider && + provider_type != kOpenVINOExecutionProvider) { + ASSERT_THAT(status.ErrorMessage(), testing::HasSubstr(expected_failure_string)); + } + + return; + } + } + + // Verify the outputs + // Todo: support check output with map/sequence/.... + if (verify_output_) { + if (custom_output_verifier_) { + // do custom verification if provided + custom_output_verifier_(fetches_, provider_type); + } else { + // default verification + size_t idx = 0; + for (auto& expected_data : output_data_) { + OrtValue& ort_value = fetches_[idx]; + + if (expected_data.def.Exists()) { // optional edges won't exist (so skip them) + const auto& name = expected_data.def.Name(); + if (!expected_data.data.IsAllocated()) { // optional type output (None) + EXPECT_TRUE(!ort_value.IsAllocated()) << "Expected to see an output of None for " << name + << " but instead got an output that wasn't None"; + + // Make sure types align + EXPECT_EQ(expected_data.data.Type(), ort_value.Type()) + << "Expected optional type: " << expected_data.data.Type() << " for " << name + << " but instead got optional type: " << ort_value.Type(); + } + + else if (expected_data.data.IsTensor()) { + // verify output shape inference when input defs have shape + if (add_shape_to_tensor_data_) { + auto out_shape_proto = expected_data.def.Shape(); + EXPECT_TRUE(out_shape_proto != nullptr); + + const auto tensor_shape = utils::GetTensorShapeFromTensorShapeProto(*out_shape_proto); + const auto inferred_dims = tensor_shape.GetDims(); + const auto& expected_shape = expected_data.data.Get().Shape(); + EXPECT_TRUE(inferred_dims.size() == expected_shape.NumDimensions()); + + for (size_t d = 0; d < inferred_dims.size(); ++d) { + // check equal unless the input involved a symbolic dimension + if (inferred_dims[d] != -1) { + EXPECT_EQ(expected_shape[d], inferred_dims[d]) << "Output idx = " << idx << " dim = " << d; + } + } + } + + CheckOrtValuesAreEqual(name, expected_data.data, ort_value, expected_data.validation_params, + provider_type); + } else { + CheckOrtValuesAreEqual(name, expected_data.data, ort_value, expected_data.validation_params, + provider_type); + } + + ++idx; + + // skip missing trailing optional outputs + if (idx == fetches_.size()) { + break; + } + } + } + } + } +} + +bool SetEpsForAllNodes(Graph& graph, + const std::vector>& execution_providers, + const std::vector>* custom_registries) { + const OpSchemaKernelTypeStrResolver kernel_type_str_resolver{}; + for (auto& node : graph.Nodes()) { + if (node.OpType() == kConstant) + continue; + + bool found = false; + + for (const auto& ep : execution_providers) { + auto provider_type = ep->Type(); + + node.SetExecutionProviderType(provider_type); + if (provider_type == onnxruntime::kOpenVINOExecutionProvider || + provider_type == onnxruntime::kTensorrtExecutionProvider || + provider_type == onnxruntime::kNnapiExecutionProvider || + provider_type == onnxruntime::kCoreMLExecutionProvider || + provider_type == onnxruntime::kDnnlExecutionProvider || + provider_type == onnxruntime::kQnnExecutionProvider || + provider_type == onnxruntime::kSnpeExecutionProvider) { + found = true; + break; + } + + // Check the EP has an impl for the node from builtin registry. + if (KernelRegistry::HasImplementationOf(*ep->GetKernelRegistry(), node, ep->Type(), kernel_type_str_resolver)) { + found = true; + break; + } + + // Check the EP has an impl for the node from custom_registries + if (custom_registries != nullptr && + std::any_of(custom_registries->cbegin(), custom_registries->cend(), + [&](auto reg) { return KernelRegistry::HasImplementationOf( + *reg->GetKernelRegistry(), + node, ep->Type(), + kernel_type_str_resolver); })) { + found = true; + break; + } + } + + // We will reach here: + // - either we could not find an impl in all possible kernel registries + // - or we skip the registry search and blindly assign the node to the EP due to impl details. + if (!found) { + return false; + } + } + + // all nodes have been assigned an EP + return true; +} + +BaseTester& BaseTester::Config(const SessionOptions& sess_options) { + ctx_.session_options = sess_options; + return *this; +} + +BaseTester& BaseTester::Config(ExpectResult expect_result, const std::string& expected_failure_string) { + ctx_.expect_result = expect_result; + ctx_.expected_failure_string = expected_failure_string; + return *this; +} + +BaseTester& BaseTester::ConfigExcludeEps(const std::unordered_set& excluded_provider_types) { + ctx_.excluded_provider_types = excluded_provider_types; + return *this; +} + +BaseTester& BaseTester::Config(const RunOptions* run_options) { + ctx_.run_options = run_options; + return *this; +} + +BaseTester& BaseTester::ConfigEps(std::vector>&& execution_providers) { + ORT_ENFORCE(execution_providers.size() > 0); + ctx_.run_with_specified_eps = true; + ctx_.execution_providers = std::move(execution_providers); + return *this; +} + +BaseTester& BaseTester::Config(const Graph::ResolveOptions& resolve_options) { + ctx_.resolve_options = resolve_options; + return *this; +} + +void BaseTester::Run(ExpectResult expect_result, const std::string& expected_failure_string, + const std::unordered_set& excluded_provider_types, + const RunOptions* run_options, + std::vector>* execution_providers, + ExecutionMode execution_mode, + const Graph::ResolveOptions& options) { + SessionOptions so; + so.use_per_session_threads = false; + so.session_logid = test_name_; + so.session_log_verbosity_level = 1; + so.execution_mode = execution_mode; + so.use_deterministic_compute = use_determinism_; + so.graph_optimization_level = TransformerLevel::Default; // 'Default' == off + + Run(so, expect_result, expected_failure_string, excluded_provider_types, run_options, execution_providers, options); +} + +#define ASSERT_PROVIDER_STATUS_OK(function) \ + do { \ + Status _tmp_status = function; \ + ASSERT_TRUE(_tmp_status.IsOK()) << "provider: " << provider_type << ", error: " << _tmp_status; \ + } while (false) + +void BaseTester::Run(SessionOptions so, + ExpectResult expect_result, const std::string& expected_failure_string, + const std::unordered_set& excluded_provider_types, + const RunOptions* run_options, + std::vector>* execution_providers, + const Graph::ResolveOptions& options, + /*out*/ size_t* number_of_pre_packed_weights_counter, + /*out*/ size_t* number_of_shared_pre_packed_weights_counter) { + if (execution_providers == nullptr) { + ctx_.run_with_specified_eps = false; + ctx_.execution_providers.clear(); + } else { + ConfigEps(std::move(*execution_providers)); + // NOTE: some callsites do the following: + // + // std::vector> execution_providers; + // execution_providers.push_back(DefaultCPUExecutionProvider()); + // test.run(..., &execution_providers, ...); + // execution_providers[0] = DefaultCUDAExecutionProvider(); // <-- std::move cause segfault here. + // test.run(..., &execution_providers, ...); + // + // So we need to restore the old vector's size. + execution_providers->resize(ctx_.execution_providers.size()); + } + + Config(so); + Config(expect_result, expected_failure_string); + Config(run_options); + ConfigExcludeEps(excluded_provider_types); + Config(options); + + RunWithConfig(number_of_pre_packed_weights_counter, number_of_shared_pre_packed_weights_counter); +} + +void BaseTester::RunWithConfig(size_t* number_of_pre_packed_weights_counter, + size_t* number_of_shared_pre_packed_weights_counter) { + std::string cur_provider = "not set"; + ORT_TRY { + testing_function_called_ = true; + fetches_.clear(); + + // IsAllowReleasedONNXOpsetsOnlySet() checks for the appropriate env var in the process (i.e.) process-wide + // `IsAllowReleasedONNXOpsetsOnlySetForThisTest()` is for this specific OpTester instance + // We will only support released opsets iff IsAllowReleasedONNXOpsetsOnlySet() and `IsAllowReleasedONNXOpsetsOnlySetForThisTest()` + // are both true + auto allow_released_onnx_opset_only = + test_allow_released_onnx_opset_only_ && model_load_utils::IsAllowReleasedONNXOpsetsOnlySet(); + + if (allow_released_onnx_opset_only) { + auto& onnx_released_versions = + ONNX_NAMESPACE::OpSchemaRegistry::DomainToVersionRange::Instance().LastReleaseVersionMap(); + auto it = onnx_released_versions.find(domain_); + if (it != onnx_released_versions.end() && opset_version_ > it->second) { + LOGS_DEFAULT(WARNING) << "Encountered model with opset version greater than released onnx opset version. " + << "Skipping this test. To run this test set environment variable ALLOW_RELEASED_ONNX_OPSET_ONLY to \"0\". " + << "Opset version of current model is " << opset_version_ + << ", the latest released onnx opset version is " << it->second << "."; + GTEST_SKIP(); + } + } + + const bool strict_shape_type_inference = ctx_.session_options.config_options.GetConfigOrDefault( + kOrtSessionOptionsConfigStrictShapeTypeInference, "1") == "1"; + const ModelOptions model_options(allow_released_onnx_opset_only, strict_shape_type_inference); + + Model* p_model = nullptr; + CreateModelToTest(model_options, p_model); + if (!p_model) { + ASSERT_EQ(ctx_.expect_result, ExpectResult::kExpectFailure) << "Failed to create model to test."; + return; + } + + Model& model = *p_model; + + // Hookup the inputs and outputs + std::unordered_map feeds; + std::vector output_names; + FillFeedsAndOutputNames(feeds, output_names); + + // Run the model + if (ctx_.run_with_specified_eps) { + ExecuteModelForEps(std::move(ctx_.execution_providers), model, ctx_.session_options, + ctx_.expect_result, ctx_.expected_failure_string, + ctx_.run_options, feeds, output_names, + /*custom_registries=*/nullptr, + /*assign_ep_for_nodes=*/false, + allow_released_onnx_opset_only, + number_of_pre_packed_weights_counter, + number_of_shared_pre_packed_weights_counter); + } else { +#ifdef USE_TENSORRT + // only run trt ep to reduce test time + static const std::string all_provider_types[] = { + kTensorrtExecutionProvider, + }; +#else + static const std::string all_provider_types[] = { + kCpuExecutionProvider, + kCudaExecutionProvider, + kDnnlExecutionProvider, + kTensorrtExecutionProvider, + kOpenVINOExecutionProvider, + kDmlExecutionProvider, + kAclExecutionProvider, + kArmNNExecutionProvider, + kNnapiExecutionProvider, + kRocmExecutionProvider, + kCoreMLExecutionProvider, + kQnnExecutionProvider, + kSnpeExecutionProvider, + kXnnpackExecutionProvider, + }; +#endif + + bool has_run = false; + + for (const std::string& provider_type : all_provider_types) { + if (ctx_.excluded_provider_types.count(provider_type) > 0) + continue; + + cur_provider = provider_type; + + std::unique_ptr execution_provider; + if (provider_type == onnxruntime::kCpuExecutionProvider) + execution_provider = DefaultCpuExecutionProvider(); + else if (provider_type == onnxruntime::kCudaExecutionProvider) + execution_provider = DefaultCudaExecutionProvider(); + else if (provider_type == onnxruntime::kDnnlExecutionProvider) + execution_provider = DefaultDnnlExecutionProvider(); + else if (provider_type == onnxruntime::kOpenVINOExecutionProvider) + execution_provider = DefaultOpenVINOExecutionProvider(); + else if (provider_type == onnxruntime::kTensorrtExecutionProvider) + execution_provider = DefaultTensorrtExecutionProvider(); + else if (provider_type == onnxruntime::kNnapiExecutionProvider) + execution_provider = DefaultNnapiExecutionProvider(); + else if (provider_type == onnxruntime::kRknpuExecutionProvider) + execution_provider = DefaultRknpuExecutionProvider(); + else if (provider_type == onnxruntime::kAclExecutionProvider) + execution_provider = DefaultAclExecutionProvider(); + else if (provider_type == onnxruntime::kArmNNExecutionProvider) + execution_provider = DefaultArmNNExecutionProvider(); + else if (provider_type == onnxruntime::kRocmExecutionProvider) + execution_provider = DefaultRocmExecutionProvider(); + else if (provider_type == onnxruntime::kCoreMLExecutionProvider) + execution_provider = DefaultCoreMLExecutionProvider(); + else if (provider_type == onnxruntime::kSnpeExecutionProvider) + execution_provider = DefaultSnpeExecutionProvider(); + else if (provider_type == onnxruntime::kQnnExecutionProvider) + execution_provider = DefaultQnnExecutionProvider(); + else if (provider_type == onnxruntime::kXnnpackExecutionProvider) + execution_provider = DefaultXnnpackExecutionProvider(); + else if (provider_type == onnxruntime::kDmlExecutionProvider) + execution_provider = DefaultDmlExecutionProvider(); + + // skip if execution provider is disabled + if (execution_provider == nullptr) + continue; + + ExecuteModelForEps( + [&execution_provider]() { + std::vector> ret; + ret.emplace_back(std::move(execution_provider)); + return ret; + }(), + model, ctx_.session_options, + ctx_.expect_result, ctx_.expected_failure_string, + ctx_.run_options, feeds, output_names, + &custom_session_registries_, + /*try_assign_ep_for_nodes=*/true, + allow_released_onnx_opset_only, + number_of_pre_packed_weights_counter, + number_of_shared_pre_packed_weights_counter); + + // Run Models with subscribed run_options->config_options + if (ctx_.run_options != nullptr && + ctx_.run_options->config_options.GetConfigEntry(kOpTesterRunOptionsConfigTestTunableOp) == "true") { + std::vector> execution_providers; + if (provider_type == onnxruntime::kRocmExecutionProvider) { + execution_providers.emplace_back(DefaultRocmExecutionProvider(/*test_tunable_op=*/true)); + } + + if (!execution_providers.empty()) { + ExecuteModelForEps( + std::move(execution_providers), model, ctx_.session_options, + ctx_.expect_result, ctx_.expected_failure_string, + ctx_.run_options, feeds, output_names, + &custom_session_registries_, + /*assign_ep_for_nodes=*/true, + allow_released_onnx_opset_only, + number_of_pre_packed_weights_counter, + number_of_shared_pre_packed_weights_counter); + } + } + + has_run = true; + cur_provider = "not set"; + } + +#ifdef USE_TENSORRT + // We are allowing tests to be run with only TensorRT EP, but TensorRT EP may not support all tests and may be in excluded providers list. + // So, no registered EPs were able to run the model is okay for this situation. + ORT_UNUSED_PARAMETER(has_run); +#else + EXPECT_TRUE(has_run) << "No registered execution providers were able to run the model."; +#endif + } + } + ORT_CATCH(const std::exception& ex) { + ORT_HANDLE_EXCEPTION([&]() { + std::cerr << ex.what() << "\nProvider:" << cur_provider << "\n"; + }); + // rethrow as some tests for error handling expect this + ORT_RETHROW; + } +} + +void BaseTester::ExecuteModelForEps( + std::vector>&& execution_providers, + onnxruntime::Model& model, + SessionOptions sess_options, // session options is copied to avoid the side effect in this function + onnxruntime::test::BaseTester::ExpectResult expect_result, + const std::string& expected_failure_string, + const onnxruntime::RunOptions* run_options, + const std::unordered_map& feeds, + const std::vector& output_names, + const std::vector>* custom_registries, + bool try_assign_ep_for_nodes, + bool allow_released_onnx_opset_only, + size_t* number_of_pre_packed_weights_counter, + size_t* number_of_shared_pre_packed_weights_counter) { + for (auto& entry : execution_providers) { + // Be noted, entry in execution providers passed in OpTester will be std::moved in the first BaseTester::Run(), + // To make the error more obvious to debug (instead of a segment fault), we do check explicitly here. + ASSERT_TRUE(entry) << "Execution provider entry invalid."; + + if (entry->Type() == kDmlExecutionProvider) { + sess_options.enable_mem_pattern = false; + sess_options.execution_mode = ExecutionMode::ORT_SEQUENTIAL; + break; + } + } + + InferenceSession session_object{sess_options, GetEnvironment()}; + + if (add_prepacked_shared_container_to_sessions_) { + ASSERT_STATUS_OK(session_object.AddPrePackedWeightsContainer(&prepacked_weights_container_)); + } + + ASSERT_TRUE(!execution_providers.empty()) << "Empty execution providers vector."; + if (try_assign_ep_for_nodes && !SetEpsForAllNodes(model.MainGraph(), execution_providers, custom_registries)) { + std::string providers; + for (const auto& ep : execution_providers) { + providers.append(ep->Type() + " "); + } + LOGS_DEFAULT(WARNING) << "registered execution providers " << providers << "were unable to run the model."; + return; + } + + std::string provider_type; + for (auto&& ep : execution_providers) { + provider_type += ep->Type() + ":"; + } + + provider_type.resize(provider_type.size() - 1); // remove the trailing ':' + + SCOPED_TRACE(MakeString("registered execution providers: ", provider_type)); + + if (custom_registries != nullptr) { + for (const auto& reg : *custom_registries) { + ASSERT_PROVIDER_STATUS_OK(session_object.RegisterCustomRegistry(reg)); + } + } + + for (auto&& entry : execution_providers) { + ASSERT_STATUS_OK(session_object.RegisterExecutionProvider(std::move(entry))); + } + + ExecuteModel( + model, session_object, expect_result, expected_failure_string, + run_options, feeds, output_names, provider_type, allow_released_onnx_opset_only); + + // After the model has initialized (happens in ExecuteModel), + // we should be able to tell how many constant initializers were pre-packed + // and out of these pre-packed ones how many of them used a "cached" version + // from the shared container. + // Populate these value if the user has requested this information. + if (number_of_pre_packed_weights_counter != nullptr) { + *number_of_pre_packed_weights_counter = session_object.GetSessionState().GetNumberOfPrepacksCounter(); + } + + if (number_of_shared_pre_packed_weights_counter != nullptr) { + *number_of_shared_pre_packed_weights_counter = + session_object.GetSessionState().GetUsedSharedPrePackedWeightCounter(); + } +}; + +void BaseTester::AddReferenceOutputs(const std::string& model_path, float abs_error, + std::unique_ptr ep) { + SessionOptions so; + so.session_logid = test_name_; + so.session_log_verbosity_level = 1; + so.graph_optimization_level = TransformerLevel::Default; + + RunOptions run_options; + run_options.run_tag = test_name_; + run_options.run_log_verbosity_level = 1; + + Status status; + InferenceSession subgraph_session_object{so, GetEnvironment()}; + status = subgraph_session_object.RegisterExecutionProvider(std::move(ep)); + ASSERT_TRUE((status = subgraph_session_object.Load(model_path)).IsOK()) << status; + ASSERT_TRUE((status = subgraph_session_object.Initialize()).IsOK()) << status; + + // Retrieve output names + auto model_outputs = subgraph_session_object.GetModelOutputs(); + ASSERT_TRUE(model_outputs.first.IsOK()); + std::vector output_names; + std::transform(model_outputs.second->begin(), + model_outputs.second->end(), + std::back_inserter(output_names), + [](const onnxruntime::NodeArg* node_arg) -> std::string { return node_arg->Name(); }); + + NameMLValMap feeds; + for (size_t i = 0; i < input_data_.size(); ++i) { + if (input_data_[i].def.Exists()) { + feeds[input_data_[i].def.Name()] = input_data_[i].data; + } + } + + std::vector subgraph_fetches; + ASSERT_TRUE((status = subgraph_session_object.Run(run_options, feeds, output_names, &subgraph_fetches)).IsOK()) << status; + + for (size_t out_idx = 0; out_idx < subgraph_fetches.size(); out_idx++) { + // Retrieve TypeProto + ASSERT_TRUE(subgraph_fetches[out_idx].Type()->IsTensorType()) << status; + const Tensor& t = subgraph_fetches[out_idx].Get(); + const TensorTypeBase* tensor_type = DataTypeImpl::TensorTypeFromONNXEnum(t.GetElementType()); + + // Construct a temp TypeProto with shape information + ONNX_NAMESPACE::TypeProto tmp_type_proto(*(tensor_type->GetTypeProto())); + auto mutable_shape = tmp_type_proto.mutable_tensor_type()->mutable_shape(); + for (auto i : t.Shape().GetDims()) { + auto* mutable_dim = mutable_shape->add_dim(); + mutable_dim->set_dim_value(i); + } + + if (abs_error != 0.0f) { + output_data_.push_back(Data(NodeArg(output_names[out_idx], &tmp_type_proto), + std::move(subgraph_fetches[out_idx]), + optional(), optional(abs_error))); + } else { + output_data_.push_back(Data(NodeArg(output_names[out_idx], &tmp_type_proto), + std::move(subgraph_fetches[out_idx]), + optional(), optional())); + } + } +} + +#ifdef ENABLE_TRAINING +// Deprecated code. Remove this when training::TrainingSession is removed. +template void BaseTester::ExecuteModel( + Model& model, training::TrainingSession& session, + ExpectResult expect_result, const std::string& expected_failure_string, + const RunOptions* run_options, + const std::unordered_map& feeds, + const std::vector& output_names, const std::string& provider_type, + bool allow_released_onnx_opset_only); +#endif + +} // namespace test +} // namespace onnxruntime diff --git a/onnxruntime/test/providers/base_tester.h b/onnxruntime/test/providers/base_tester.h new file mode 100644 index 0000000000000..5607e58315a12 --- /dev/null +++ b/onnxruntime/test/providers/base_tester.h @@ -0,0 +1,938 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include +#include +#include +#include + +#include "core/framework/customregistry.h" +#include "core/framework/prepacked_weights_container.h" +#include "core/framework/run_options.h" +#include "core/framework/tensor.h" +#include "core/framework/TensorSeq.h" +#include "core/graph/model.h" + +#include "test/framework/TestAllocatorManager.h" +#include "test/providers/checkers.h" +#include "test/providers/tester_types.h" + +namespace onnxruntime { +class InferenceSession; +struct SessionOptions; + +namespace test { + +/// +/// Base class for testing operators and models. +/// +class BaseTester { + protected: + explicit BaseTester(std::string_view test_name, int opset_version, std::string_view domain, + bool verify_output = true) + : test_name_(test_name), domain_(domain), opset_version_(opset_version), verify_output_(verify_output) { + if (opset_version_ < 0) { + static int latest_onnx_version = + ONNX_NAMESPACE::OpSchemaRegistry::DomainToVersionRange().Map().at(ONNX_NAMESPACE::ONNX_DOMAIN).second; + opset_version_ = latest_onnx_version; + } + } + + // Derived class to implement to provide the model to test. + // Return is void so the GTEST ASSERT/EXPECT macros can be used in the implementation + // a pointer to allow testing scenarios where the expected result is ExpectResult::kExpectFailure. + virtual void CreateModelToTest(const ModelOptions& model_options, Model*& model) = 0; + + public: + virtual ~BaseTester(); + + // We have an initializer_list and vector version of the Add functions because std::vector is specialized for + // bool and we can't get the raw data out. So those cases must use an initializer_list + + // Dims variant is needed to reduce the number of overloads + // MS compiler refuses to create a gsl::span from initializer_list especially if it contains a single element + using DimsVariant = std::variant, TensorShapeVector>; + + template + void AddInput(const char* name, std::initializer_list dims, std::initializer_list values, + bool is_initializer = false, const std::vector* dim_params = nullptr) { + const DimsVariant dims_var = std::vector(dims); + AddData(input_data_, name, dims_var, values.begin(), values.size(), is_initializer, false, dim_params); + } + + template + void AddInput(const char* name, std::initializer_list dims, const std::vector& values, + bool is_initializer = false, const std::vector* dim_params = nullptr) { + const DimsVariant dims_var = std::vector(dims); + AddData(input_data_, name, dims_var, values.data(), values.size(), is_initializer, false, dim_params); + } + + template + void AddInput(const char* name, std::initializer_list dims, const T* p_values, + const size_t size, bool is_initializer = false, + const std::vector* dim_params = nullptr) { + const DimsVariant dims_var = std::vector(dims); + AddData(input_data_, name, dims_var, p_values, size, is_initializer, false, dim_params); + } + + template + void AddInput(const char* name, std::initializer_list dims, gsl::span values, + bool is_initializer = false, const std::vector* dim_params = nullptr) { + const DimsVariant dims_var = std::vector(dims); + AddData(input_data_, name, dims_var, values.data(), values.size(), is_initializer, false, dim_params); + } + + template + void AddInput(const char* name, const DimsVariant& dims, std::initializer_list values, + bool is_initializer = false, const std::vector* dim_params = nullptr) { + AddData(input_data_, name, dims, values.begin(), values.size(), is_initializer, false, dim_params); + } + + template + void AddInput(const char* name, const DimsVariant& dims, const std::vector& values, + bool is_initializer = false, const std::vector* dim_params = nullptr) { + AddData(input_data_, name, dims, values.data(), values.size(), is_initializer, false, dim_params); + } + + template + void AddInput(const char* name, const DimsVariant& dims, const T* p_values, + const size_t size, bool is_initializer = false, + const std::vector* dim_params = nullptr) { + AddData(input_data_, name, dims, p_values, size, is_initializer, false, dim_params); + } + +#if !defined(DISABLE_SPARSE_TENSORS) + // Useful to add boolean data + template + void AddSparseCooInput(const char* name, const std::vector& dims, + const std::initializer_list& values, const std::vector& indices, + const std::vector* dim_params = nullptr) { + auto ml_type = DataTypeImpl::GetType(); + AddSparseCooTensorData(input_data_, ml_type, name, dims, + gsl::make_span(values).as_bytes(), + gsl::make_span(indices), + ValidateOutputParams(), dim_params); + } + + template + void AddSparseCooInput(const char* name, const std::vector& dims, + const std::vector& values, const std::vector& indices, + const std::vector* dim_params = nullptr) { + auto ml_type = DataTypeImpl::GetType(); + AddSparseCooTensorData(input_data_, ml_type, name, dims, + gsl::as_bytes(gsl::make_span(values)), + gsl::make_span(indices), + ValidateOutputParams(), dim_params); + } + + template + void AddSparseCooInput(const char* name, const std::vector& dims, + gsl::span values_span, + const std::vector& indices, + const std::vector* dim_params = nullptr) { + auto ml_type = DataTypeImpl::GetType(); + AddSparseCooTensorData(input_data_, ml_type, name, dims, + values_span.as_bytes(), + gsl::make_span(indices), + ValidateOutputParams(), dim_params); + } + + void AddSparseCooInput(const char* name, const std::vector& dims, + const std::vector& values, + const std::vector& indices, + const std::vector* dim_params = nullptr) { + AddSparseCooTensorStrings(input_data_, name, dims, + gsl::make_span(values), + gsl::make_span(indices), + dim_params); + } + + // Useful to add boolean data + template + void AddSparseCsrInput(const char* name, const std::vector& dims, + const std::initializer_list& values, + const std::vector& inner_indices, + const std::vector& outer_indices, + const std::vector* dim_params = nullptr) { + auto ml_type = DataTypeImpl::GetType(); + AddSparseCsrTensorData(input_data_, ml_type, name, dims, + gsl::make_span(values).as_bytes(), + gsl::make_span(inner_indices), + gsl::make_span(outer_indices), + ValidateOutputParams(), dim_params); + } + + template + void AddSparseCsrInput(const char* name, const std::vector& dims, + const std::vector& values, + const std::vector& inner_indices, + const std::vector& outer_indices, + const std::vector* dim_params = nullptr) { + auto ml_type = DataTypeImpl::GetType(); + AddSparseCsrTensorData(input_data_, ml_type, name, dims, + gsl::as_bytes(gsl::make_span(values)), + gsl::make_span(inner_indices), + gsl::make_span(outer_indices), + ValidateOutputParams(), dim_params); + } + + template + void AddSparseCsrInput(const char* name, const std::vector& dims, + gsl::span values_span, + const std::vector& inner_indices, + const std::vector& outer_indices, + const std::vector* dim_params = nullptr) { + auto ml_type = DataTypeImpl::GetType(); + AddSparseCsrTensorData(input_data_, ml_type, name, dims, + values_span.as_bytes(), + gsl::make_span(inner_indices), + gsl::make_span(outer_indices), + ValidateOutputParams(), dim_params); + } + + void AddSparseCsrInput(const char* name, const std::vector& dims, + const std::vector& values, + const std::vector& inner_indices, + const std::vector& outer_indices, + const std::vector* dim_params = nullptr) { + AddSparseCsrTensorStrings(input_data_, name, dims, + gsl::make_span(values), + gsl::make_span(inner_indices), + gsl::make_span(outer_indices), + dim_params); + } +#endif + + // Add other registered types, possibly experimental + template + void AddInput(const char* name, const T& val) { + auto mltype = DataTypeImpl::GetType(); + ORT_ENFORCE(mltype != nullptr, "T must be a registered cpp type"); + auto ptr = std::make_unique(val); + OrtValue value; + value.Init(ptr.get(), mltype, mltype->GetDeleteFunc()); + ptr.release(); + input_data_.push_back(Data(NodeArg(name, mltype->GetTypeProto()), std::move(value), optional(), + optional())); + } + + template + void AddInput(const char* name, T&& val) { + auto mltype = DataTypeImpl::GetType(); + ORT_ENFORCE(mltype != nullptr, "T must be a registered cpp type"); + auto ptr = std::make_unique(std::move(val)); + OrtValue value; + value.Init(ptr.get(), mltype, mltype->GetDeleteFunc()); + ptr.release(); + input_data_.push_back(Data(NodeArg(name, mltype->GetTypeProto()), std::move(value), optional(), + optional())); + } + + template + void AddSeqInput(const char* name, const SeqTensors& seq_tensors) { + AddSeqData(input_data_, name, &seq_tensors); + } + + template + void AddSeqOutput(const char* name, const SeqTensors& seq_tensors, + float rel_error = 0.0f, float abs_error = 0.0f) { + AddSeqData(output_data_, name, &seq_tensors, false, rel_error, abs_error); + } + +#if !defined(DISABLE_OPTIONAL_TYPE) + template + void AddOptionalTypeTensorInput(const char* name, const DimsVariant& dims, + const std::initializer_list* values = nullptr, + bool is_initializer = false, const std::vector* dim_params = nullptr) { + AddData(input_data_, name, dims, values ? values->begin() : nullptr, + values ? values->size() : 0, is_initializer, false, dim_params, 0.0f, 0.0f, true); + } + + template + void AddOptionalTypeTensorInput(const char* name, std::initializer_list dims, + const std::initializer_list* values = nullptr, + bool is_initializer = false, const std::vector* dim_params = nullptr) { + DimsVariant dims_var = std::vector(dims); + AddData(input_data_, name, dims_var, values ? values->begin() : nullptr, + values ? values->size() : 0, is_initializer, false, dim_params, 0.0f, 0.0f, true); + } + + template + void AddOptionalTypeTensorOutput(const char* name, const DimsVariant& dims, + const std::initializer_list* expected_values = nullptr, + bool sort_output = false, float rel_error = 0.0f, float abs_error = 0.0f) { + AddData(output_data_, name, dims, expected_values ? expected_values->begin() : nullptr, + expected_values ? expected_values->size() : 0, false, + sort_output, nullptr /* dim_params */, rel_error, abs_error, true); + } + + template + void AddOptionalTypeTensorOutput(const char* name, std::initializer_list dims, + const std::initializer_list* expected_values = nullptr, + bool sort_output = false, float rel_error = 0.0f, float abs_error = 0.0f) { + DimsVariant dims_var = std::vector(dims); + AddData(output_data_, name, dims_var, expected_values ? expected_values->begin() : nullptr, + expected_values ? expected_values->size() : 0, false, + sort_output, nullptr /* dim_params */, rel_error, abs_error, true); + } + + template + void AddOptionalTypeSeqInput(const char* name, + const SeqTensors* seq_tensors) { + AddSeqData(input_data_, name, seq_tensors, true); + } + + template + void AddOptionalTypeSeqOutput(const char* name, + const SeqTensors* seq_tensors, + float rel_error = 0.0f, float abs_error = 0.0f) { + AddSeqData(output_data_, name, seq_tensors, true, rel_error, abs_error); + } +#endif + + template + void AddInput(const char* name, const std::map& val) { + std::unique_ptr> ptr = std::make_unique>(val); + OrtValue value; + value.Init(ptr.release(), DataTypeImpl::GetType>(), + DataTypeImpl::GetType>()->GetDeleteFunc()); + input_data_.push_back(Data(NodeArg(name, &MMapType::s_map_type_proto.proto), std::move(value), + optional(), optional())); + } + + /* + * Use this API to add an input *edge* to the node/op being tested that won't + * have any data passed into. + * Such an edge will have the qualifier OpSchema::Optional in the schema. + * This is exposed to ensure the op kernel implementations can be tested to handle + * presence/absence of such optional input edges. + */ + template + void AddOptionalInputEdge() { + std::string name; // empty == input doesn't exist + input_data_.push_back(Data(NodeArg(name, &TTensorType::s_type_proto.proto), OrtValue(), optional(), + optional())); + } + + template + void AddOutput(const char* name, std::initializer_list dims, std::initializer_list expected_values, + bool sort_output = false, float rel_error = 0.0f, float abs_error = 0.0f) { + const DimsVariant dims_var = std::vector(dims); + AddData(output_data_, name, dims_var, expected_values.begin(), expected_values.size(), false, + sort_output, nullptr /* dim_params */, rel_error, abs_error); + } + + template + void AddOutput(const char* name, std::initializer_list dims, const std::vector& expected_values, + bool sort_output = false, float rel_error = 0.0f, float abs_error = 0.0f) { + const DimsVariant dims_var = std::vector(dims); + AddData(output_data_, name, dims_var, expected_values.data(), expected_values.size(), false, + sort_output, nullptr /* dim_params */, rel_error, abs_error); + } + + template + void AddOutput(const char* name, std::initializer_list dims, const T* p_values, const size_t size, + bool sort_output = false, float rel_error = 0.0f, float abs_error = 0.0f) { + const DimsVariant dims_var = std::vector(dims); + AddData(output_data_, name, dims_var, p_values, size, false, + sort_output, nullptr /* dim_params */, rel_error, abs_error); + } + + template + void AddOutput(const char* name, const DimsVariant& dims, std::initializer_list expected_values, + bool sort_output = false, float rel_error = 0.0f, float abs_error = 0.0f) { + AddData(output_data_, name, dims, expected_values.begin(), expected_values.size(), false, + sort_output, nullptr /* dim_params */, rel_error, abs_error); + } + + // This function doesn't work for vector because const vector cannot invoke its data(). + template + void AddOutput(const char* name, const DimsVariant& dims, const std::vector& expected_values, + bool sort_output = false, float rel_error = 0.0f, float abs_error = 0.0f) { + AddData(output_data_, name, dims, expected_values.data(), expected_values.size(), false, + sort_output, nullptr /* dim_params */, rel_error, abs_error); + } + + template + void AddOutput(const char* name, const DimsVariant& dims, const T* p_values, const size_t size, + bool sort_output = false, float rel_error = 0.0f, float abs_error = 0.0f) { + AddData(output_data_, name, dims, p_values, size, false, + sort_output, nullptr /* dim_params */, rel_error, abs_error); + } + +#if !defined(DISABLE_SPARSE_TENSORS) + template + void AddSparseCooOutput(const char* name, const std::vector& dims, + const std::initializer_list& expected_values, + const std::vector& expected_indices, + const ValidateOutputParams& check_params = {}) { + auto ml_type = DataTypeImpl::GetType(); + AddSparseCooTensorData(output_data_, ml_type, name, dims, + gsl::make_span(expected_values).as_bytes(), + gsl::make_span(expected_indices), + check_params, nullptr /*dim_params*/); + } + + template + void AddSparseCooOutput(const char* name, const std::vector& dims, + const std::vector& expected_values, + const std::vector& expected_indices, + const ValidateOutputParams& check_params = {}) { + auto ml_type = DataTypeImpl::GetType(); + AddSparseCooTensorData(output_data_, ml_type, name, dims, + gsl::make_span(expected_values).as_bytes(), + gsl::make_span(expected_indices), + check_params, nullptr /*dim_params*/); + } + + template + void AddSparseCooOutput(const char* name, const std::vector& dims, + gsl::span expected_values_span, + const std::vector& expected_indices, + const ValidateOutputParams& check_params = {}) { + auto ml_type = DataTypeImpl::GetType(); + AddSparseCooTensorData(output_data_, ml_type, name, dims, + expected_values_span.as_bytes(), + gsl::make_span(expected_indices), + check_params, nullptr /*dim_params*/); + } + + void AddSparseCooOutput(const char* name, const std::vector& dims, + const std::vector& expected_values, + const std::vector& expected_indices) { + AddSparseCooTensorStrings(output_data_, name, dims, + gsl::make_span(expected_values), + gsl::make_span(expected_indices)); + } + + template + void AddSparseCsrOutput(const char* name, const std::vector& dims, + const std::initializer_list& values, + const std::vector& inner_indices, + const std::vector& outer_indices, + const ValidateOutputParams& check_params = {}) { + auto ml_type = DataTypeImpl::GetType(); + AddSparseCsrTensorData(output_data_, ml_type, name, dims, + gsl::make_span(values).as_bytes(), + gsl::make_span(inner_indices), + gsl::make_span(outer_indices), + check_params, nullptr /*dim_params*/); + } + + template + void AddSparseCsrOutput(const char* name, const std::vector& dims, + const std::vector& values, + const std::vector& inner_indices, + const std::vector& outer_indices, + const ValidateOutputParams& check_params = {}) { + auto ml_type = DataTypeImpl::GetType(); + AddSparseCsrTensorData(output_data_, ml_type, name, dims, + gsl::make_span(values).as_bytes(), + gsl::make_span(inner_indices), + gsl::make_span(outer_indices), + check_params, nullptr /*dim_params*/); + } + + template + void AddSparseCsrOutput(const char* name, const std::vector& dims, + gsl::span expected_values_span, + const std::vector& expected_inner_indices, + const std::vector& expected_outer_indices, + const ValidateOutputParams& check_params = {}) { + auto ml_type = DataTypeImpl::GetType(); + AddSparseCsrTensorData(output_data_, ml_type, name, dims, + expected_values_span.as_bytes(), + gsl::make_span(expected_inner_indices), + gsl::make_span(expected_outer_indices), + check_params, nullptr /*dim_params*/); + } + + void AddSparseCsrOutput(const char* name, const std::vector& dims, + const std::vector& expected_values, + const std::vector& expected_inner_indices, + const std::vector& expected_outer_indices) { + AddSparseCsrTensorStrings(output_data_, name, dims, + gsl::make_span(expected_values), + gsl::make_span(expected_inner_indices), + gsl::make_span(expected_outer_indices)); + } +#endif + + /* + * Use this API to add an output *edge* to the node/op being tested that shouldn't have any + * data produced into. + * Such an edge will have the qualifier OpSchema::Optional in the schema. + * This is exposed to ensure the op kernel implementations can be tested to handle + * presence/absence of such optional output edges. + */ + template + void AddOptionalOutputEdge() { + std::string name; // empty == output doesn't exist + output_data_.push_back(Data(NodeArg(name, &TTensorType::s_type_proto.proto), OrtValue(), optional(), + optional())); + } + + // Add other registered types, possibly experimental + template + void AddOutput(const char* name, const T& val) { + auto mltype = DataTypeImpl::GetType(); + ORT_ENFORCE(mltype != nullptr, "T must be a registered cpp type"); + auto ptr = std::make_unique(val); + OrtValue value; + value.Init(ptr.get(), mltype, mltype->GetDeleteFunc()); + ptr.release(); + output_data_.push_back(Data(NodeArg(name, mltype->GetTypeProto()), std::move(value), optional(), + optional())); + } + + template + void AddOutput(const char* name, T&& val) { + auto mltype = DataTypeImpl::GetType(); + ORT_ENFORCE(mltype != nullptr, "T must be a registered cpp type"); + auto ptr = std::make_unique(std::move(val)); + OrtValue value; + value.Init(ptr.get(), mltype, mltype->GetDeleteFunc()); + ptr.release(); + output_data_.push_back(Data(NodeArg(name, mltype->GetTypeProto()), std::move(value), optional(), + optional())); + } + + // Add non tensor output + template + void AddOutput(const char* name, const std::vector>& val) { + auto ptr = std::make_unique>>(val); + OrtValue ml_value; + ml_value.Init(ptr.release(), DataTypeImpl::GetType>>(), + DataTypeImpl::GetType>>()->GetDeleteFunc()); + output_data_.push_back(Data(NodeArg(name, &VectorOfMapType::s_vec_map_type_proto.proto), std::move(ml_value), + optional(), optional())); + } + + // Generate the reference outputs by running the provided the model + void AddReferenceOutputs(const std::string& model_path, float abs_error = 0.0f, + std::unique_ptr ep = nullptr); + + void AddCustomOpRegistry(std::shared_ptr registry) { + custom_schema_registries_.push_back(registry->GetOpschemaRegistry()); + custom_session_registries_.push_back(registry); + } + + void SetOutputAbsErr(const char* name, float v); + void SetOutputRelErr(const char* name, float v); + + // Number of times to call InferenceSession::Run. The same feeds are used each time. + // e.g. used to verify the generator ops behave as expected + void SetNumRunCalls(int n) { + ORT_ENFORCE(n > 0); + num_run_calls_ = n; + } + + using CustomOutputVerifierFn = std::function& /*fetches*/, + const std::string& /*provider_type*/)>; + + void SetCustomOutputVerifier(CustomOutputVerifierFn custom_output_verifier) { + custom_output_verifier_ = custom_output_verifier; + } + + enum class ExpectResult { + kExpectSuccess, + kExpectFailure + }; + + BaseTester& Config(const SessionOptions& sess_options); + BaseTester& Config(ExpectResult expect_result, const std::string& expected_failure_string); + BaseTester& ConfigExcludeEps(const std::unordered_set& excluded_provider_types); + BaseTester& Config(const RunOptions* run_options); + BaseTester& ConfigEps(std::vector>&& execution_providers); + // Configure a single EP to run. + BaseTester& ConfigEp(std::unique_ptr&& execution_provider) { + std::vector> execution_providers; + execution_providers.emplace_back(std::move(execution_provider)); + return ConfigEps(std::move(execution_providers)); + } + BaseTester& Config(const Graph::ResolveOptions& resolve_options); + + void RunWithConfig(size_t* number_of_pre_packed_weights_counter = nullptr, + size_t* number_of_shared_pre_packed_weights_counter = nullptr); + + // [[deprecated("Use builder pattern Config* and RunWithConfig")]] + void Run(ExpectResult expect_result = ExpectResult::kExpectSuccess, const std::string& expected_failure_string = "", + const std::unordered_set& excluded_provider_types = {}, + const RunOptions* run_options = nullptr, + std::vector>* execution_providers = nullptr, + ExecutionMode execution_mode = ExecutionMode::ORT_SEQUENTIAL, + const Graph::ResolveOptions& resolve_options = {}); + + // [[deprecated("Use builder pattern Config* and RunWithConfig")]] + // Take SessionOptions by value (i.e. make a copy) because we may need to modify it + void Run(SessionOptions session_options, + ExpectResult expect_result = ExpectResult::kExpectSuccess, + const std::string& expected_failure_string = "", + const std::unordered_set& excluded_provider_types = {}, + const RunOptions* run_options = nullptr, + std::vector>* execution_providers = nullptr, + const Graph::ResolveOptions& resolve_options = {}, + /*out*/ size_t* number_of_pre_packed_weights_counter = nullptr, + /*out*/ size_t* number_of_shared_pre_packed_weights_counter = nullptr); + + std::vector GetFetches() { return fetches_; } + + struct Data { + Data(onnxruntime::NodeArg&& def, OrtValue&& data, optional&& rel, optional&& abs, + bool sort_output = false) + : def(std::move(def)), + data(std::move(data)), + validation_params{std::move(rel), std::move(abs), sort_output} {} + Data(Data&&) = default; + Data& operator=(Data&&) = default; + + onnxruntime::NodeArg def; + OrtValue data; + ValidateOutputParams validation_params; + }; + + void SetDeterminism(bool use_determinism) { + use_determinism_ = use_determinism; + } + + void EnableSharingOfPrePackedWeightsAcrossSessions() { + add_prepacked_shared_container_to_sessions_ = true; + } + + size_t GetNumPrePackedWeightsShared() const { + return prepacked_weights_container_.GetNumberOfElements(); + } + + void SetAllowUnreleasedOnnxOpset() { + test_allow_released_onnx_opset_only_ = false; + } + + protected: + //// if the derived class is caching the model this helper can be called in CreateModelToTest to reset the nodes + // static void ClearEpsForAllNodes(Graph& graph); + + const std::string& Domain() const { return domain_; } + int Opset() const { return opset_version_; } + + // std::vector> custom_session_registries_; + + const IOnnxRuntimeOpSchemaRegistryList& CustomSchemaRegistries() const { + return custom_schema_registries_; + } + + bool GetAddShapeToTensorData() const { return add_shape_to_tensor_data_; } + void SetAddShapeToTensorData(bool enable) { add_shape_to_tensor_data_ = enable; } + void SetAddSymbolicDimToTensorData(int symbolic_dim) { add_symbolic_dim_to_tensor_data_ = symbolic_dim; } + void SetTestFunctionCalled() { testing_function_called_ = true; } + + struct RunContext { + SessionOptions session_options{}; + ExpectResult expect_result{ExpectResult::kExpectSuccess}; + std::string expected_failure_string{}; + std::unordered_set excluded_provider_types = {}; + const RunOptions* run_options{}; + bool run_with_specified_eps{false}; + std::vector> execution_providers{}; + Graph::ResolveOptions resolve_options{}; + }; + + std::vector& GetInputData() { return input_data_; } + std::vector& GetOutputData() { return output_data_; } + std::vector& GetInitializerIndexes() { return initializer_indexes_; } + + void AddInitializers(onnxruntime::Graph& graph); + + void FillFeedsAndOutputNames(std::unordered_map& feeds, + std::vector& output_names); + + const RunContext& GetRunContext() const { return ctx_; } + + template + void ExecuteModel(Model& model, + SessionType& session_object, + ExpectResult expect_result, + const std::string& expected_failure_string, + const RunOptions* run_options, + const std::unordered_map& feeds, + const std::vector& output_names, + const std::string& provider_type, + bool allow_released_onnx_opset_only = true); + + template + void AddData(std::vector& data, const char* name, const DimsVariant& dims_var, const T* values, + int64_t values_count, bool is_initializer = false, bool sort_output = false, + const std::vector* dim_params = nullptr, + float rel_error = 0.0f, float abs_error = 0.0f, bool is_optional_type_tensor = false) { + auto dims = ToDimsSpan(dims_var); +#if defined(DISABLE_OPTIONAL_TYPE) + if (is_optional_type_tensor) { + ORT_THROW("Optional type is not supported in this build"); + } +#endif + + ORT_TRY { + TensorShape shape{dims}; + OrtValue value; + + if (!is_optional_type_tensor || (is_optional_type_tensor && values != nullptr)) { + // In case values is nullptr for optional type tensor, it means we are creating + // an optional type tensor which is None and we hence skip values count validation + ORT_ENFORCE(shape.Size() == values_count, values_count, " input values doesn't match tensor size of ", + shape.Size()); + + // If it is an optional tensor type with no values (i.e.) None, + // we won't even pass it in to Run() as part of the feeds, + // so we don't even have to create a Tensor. + // Conversely, if it is an optional tensor type with values, + // we pass it in as a regular tensor. + auto allocator = test::AllocatorManager::Instance().GetAllocator(CPU); + Tensor::InitOrtValue(DataTypeImpl::GetType(), shape, std::move(allocator), value); + + // values *could* be nullptr for a non-optional tensor if it is empty. + // Update the data buffer of the input only if values if non-nullptr. + if (values != nullptr) { + auto* data_ptr = value.GetMutable()->MutableData(); + for (int64_t i = 0; i < values_count; i++) { + data_ptr[i] = values[i]; + } + } + } else { // "None" Tensor OrtValue. Initialize appropriately. + auto ml_tensor = DataTypeImpl::GetType(); + value.Init(nullptr, ml_tensor, ml_tensor->GetDeleteFunc()); + } + + std::vector dims_for_proto = GetDimsForProto(dims); + TTypeProto tensor_type_proto(add_shape_to_tensor_data_ ? &dims_for_proto : nullptr); + +#if !defined(DISABLE_OPTIONAL_TYPE) + OptionalTypeProto optional_type_proto(tensor_type_proto.proto); + auto node_arg = NodeArg(name, !is_optional_type_tensor ? &tensor_type_proto.proto : &optional_type_proto.proto); +#else + auto node_arg = NodeArg(name, &tensor_type_proto.proto); +#endif + + AddShapeToTensorData(node_arg, dims, dim_params); + + optional rel; + optional abs; + + if (rel_error != 0.0f) { + rel = rel_error; + } + + if (abs_error != 0.0f) { + abs = abs_error; + } + + data.push_back(Data(std::move(node_arg), std::move(value), std::move(rel), std::move(abs), sort_output)); + + // Optional values cannot be initializers + if (is_initializer && !is_optional_type_tensor) { + initializer_indexes_.push_back(data.size() - 1); + } + } + ORT_CATCH(const std::exception& ex) { + ORT_HANDLE_EXCEPTION([&]() { + std::cerr << "AddData for '" << name << "' threw: " << ex.what(); + }); + ORT_RETHROW; + } + } + + private: + void FillFeeds(std::unordered_map& feeds); + + RunContext ctx_{}; + + std::vector input_data_; + std::vector output_data_; + std::vector fetches_; + + bool testing_function_called_{}; // has the function that performs the actual testing been called yet? + + gsl::span ToDimsSpan(const DimsVariant& dims_var) { + return std::visit([](auto&& dims) { return gsl::span(dims); }, dims_var); + } + + template + void AddSeqData(std::vector& data, const char* name, + const SeqTensors* seq_tensors, + bool is_optional_sequence_tensor_type = false, + float rel_error = 0.0f, float abs_error = 0.0f) { +#if defined(DISABLE_OPTIONAL_TYPE) + if (is_optional_sequence_tensor_type) { + ORT_THROW("Optional type is not supported in this build"); + } +#endif + + std::unique_ptr ptr; + SequenceTensorTypeProto sequence_tensor_proto; + + if (seq_tensors) { + auto num_tensors = seq_tensors->tensors.size(); + auto elem_type = DataTypeImpl::GetType(); + + ptr = std::make_unique(elem_type); + ptr->Reserve(num_tensors); + for (size_t i = 0; i < num_tensors; ++i) { + TensorShape shape{seq_tensors->tensors[i].shape}; + auto values_count = static_cast(seq_tensors->tensors[i].data.size()); + ORT_ENFORCE(shape.Size() == values_count, values_count, + " input values doesn't match tensor size of ", shape.Size()); + + auto allocator = test::AllocatorManager::Instance().GetAllocator(CPU); + Tensor tensor(elem_type, shape, allocator); + + auto* data_ptr = tensor.MutableData(); + for (int64_t x = 0; x < values_count; ++x) { + data_ptr[x] = seq_tensors->tensors[i].data[x]; + } + + ptr->Add(std::move(tensor)); + + if (add_shape_to_tensor_data_) { + auto* output_tensor_type = sequence_tensor_proto.proto.mutable_sequence_type() + ->mutable_elem_type() + ->mutable_tensor_type(); + if (i == 0) { + ONNX_NAMESPACE::TensorShapeProto* seq_input_shape = output_tensor_type->mutable_shape(); + output_tensor_type->set_elem_type(utils::ToTensorProtoElementType()); + for (size_t j = 0; j < shape.NumDimensions(); ++j) { + auto dim = seq_input_shape->add_dim(); + dim->set_dim_value(shape[j]); + } + } else { + ONNX_NAMESPACE::TensorShapeProto shape_proto; + for (size_t j = 0; j < shape.NumDimensions(); ++j) { + auto dim = shape_proto.add_dim(); + dim->set_dim_value(shape[j]); + } + + ONNX_NAMESPACE::UnionShapeInfo(shape_proto, *output_tensor_type); + } + } + } + } + + OrtValue value; + auto mltype = DataTypeImpl::GetType(); + + // nullptr means None OrtValue which we will skip inserting into the feeds + value.Init(ptr ? ptr.release() : nullptr, mltype, mltype->GetDeleteFunc()); + +#if !defined(DISABLE_OPTIONAL_TYPE) + OptionalTypeProto optional_type_proto(sequence_tensor_proto.proto); + auto node_arg = NodeArg(name, !is_optional_sequence_tensor_type + ? &sequence_tensor_proto.proto + : &optional_type_proto.proto); +#else + auto node_arg = NodeArg(name, &sequence_tensor_proto.proto); +#endif + + optional rel; + optional abs; + + if (rel_error != 0.0f) { + rel = rel_error; + } + + if (abs_error != 0.0f) { + abs = abs_error; + } + + data.push_back(Data(std::move(node_arg), std::move(value), std::move(rel), std::move(abs))); + } + + std::vector GetDimsForProto(gsl::span dims); + + void AddShapeToTensorData(NodeArg& node_arg, gsl::span dims, + const std::vector* dim_params); + + void CopyDataToTensor(gsl::span data, Tensor& dst); + +#if !defined(DISABLE_SPARSE_TENSORS) + NodeArg MakeSparseNodeArg(int32_t dtype, const char* name, + const gsl::span& dims, + const std::vector* dim_params); + + void AddSparseCooTensorData(std::vector& data, + MLDataType data_type, + const char* name, + gsl::span dims, + gsl::span values, + gsl::span indices, + const ValidateOutputParams& check_params, + const std::vector* dim_params = nullptr); + + void AddSparseCooTensorStrings(std::vector& data, + const char* name, + gsl::span dims, + gsl::span values, + gsl::span indices, + const std::vector* dim_params = nullptr); + + void AddSparseCsrTensorData(std::vector& data, + MLDataType data_type, + const char* name, + gsl::span dims, + gsl::span values, + gsl::span inner_indices, + gsl::span outer_indices, + const ValidateOutputParams& check_params, + const std::vector* dim_params = nullptr); + + void AddSparseCsrTensorStrings(std::vector& data, + const char* name, + gsl::span dims, + gsl::span values, + gsl::span inner_indices, + gsl::span outer_indices, + const std::vector* dim_params = nullptr); + + void AddSparseTensorData(std::vector& data, NodeArg node_arg, + std::unique_ptr p_tensor, + const ValidateOutputParams& check_params); +#endif + + // Execute the model for a single execution providers combination + void ExecuteModelForEps(std::vector>&& execution_providers, + onnxruntime::Model& model, + SessionOptions sess_options, + ExpectResult expect_result, + const std::string& expected_failure_string, + const onnxruntime::RunOptions* run_options, + const std::unordered_map& feeds, + const std::vector& output_names, + const std::vector>* custom_registries, + bool try_assign_ep_for_nodes, + bool allow_released_onnx_opset_only, + size_t* number_of_pre_packed_weights_counter, + size_t* number_of_shared_pre_packed_weights_counter); + + const std::string test_name_; + const std::string domain_; + int opset_version_ = -1; + + bool test_allow_released_onnx_opset_only_ = true; + bool add_shape_to_tensor_data_ = true; + int add_symbolic_dim_to_tensor_data_ = -1; + + int num_run_calls_ = 1; + + IOnnxRuntimeOpSchemaRegistryList custom_schema_registries_; + std::vector> custom_session_registries_; + + bool verify_output_ = true; + bool use_determinism_ = false; + CustomOutputVerifierFn custom_output_verifier_; + + std::vector initializer_indexes_; + + bool add_prepacked_shared_container_to_sessions_ = false; + onnxruntime::PrepackedWeightsContainer prepacked_weights_container_; +}; + +} // namespace test +} // namespace onnxruntime diff --git a/onnxruntime/test/providers/checkers.cc b/onnxruntime/test/providers/checkers.cc new file mode 100644 index 0000000000000..85ccb8f175f62 --- /dev/null +++ b/onnxruntime/test/providers/checkers.cc @@ -0,0 +1,495 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "test/providers/checkers.h" + +#include "gtest/gtest.h" + +#include "core/graph/constants.h" +#include "core/framework/TensorSeq.h" + +#include "test/framework/test_utils.h" +#include "test/providers/provider_test_utils.h" + +namespace onnxruntime { +namespace test { +namespace { +template +Tensor copy_sort(const Tensor& src, const AllocatorPtr& allocator) { + Tensor result(src.DataType(), src.Shape(), allocator); + memcpy(result.MutableDataRaw(), src.DataRaw(), src.SizeInBytes()); + auto dst_span = gsl::make_span(result.MutableData(), result.MutableData() + result.Shape().Size()); + std::sort(dst_span.begin(), dst_span.end()); + return result; +} + +// Check functions for tensor types +template +void sort_expected_and_actual_buffers(const Tensor& expected, Tensor& expected_sorted, + const Tensor& actual, Tensor& actual_sorted) { + auto allocator = TestCPUExecutionProvider()->CreatePreferredAllocators()[0]; + expected_sorted = copy_sort(expected, allocator); + actual_sorted = copy_sort(actual, allocator); +} + +// Check functions for tensor types +template +void sort_expected_and_actual_buffers(std::vector& expected, + std::vector& actual) { + ORT_ENFORCE(expected.size() == actual.size(), + "The 2 containers contain different number of elements"); + std::sort(expected.begin(), expected.end()); + std::sort(actual.begin(), actual.end()); +} + +// The default implementation compares for equality, specialized versions for +// other types are below +template +struct TensorCheck { + void operator()(const Tensor& expected, const Tensor& actual, const ValidateOutputParams& params, + const std::string& /*provider_type*/) const { + Tensor expected_sorted, actual_sorted; + const T* cur_expected; + const T* cur_actual; + const auto size = actual.Shape().Size(); + if (params.sort_output) { + // if order can be jumbled in the output of an operator, sort both the + // expected and output buffers prior to + // comparison this is a "best-effort" algo and should satisfy the + // requirement for the few ops that do require this + // support without investing in a more sophisticated infrastructure for the + // same + sort_expected_and_actual_buffers(expected, expected_sorted, actual, actual_sorted); + cur_expected = expected_sorted.Data(); + cur_actual = actual_sorted.Data(); + } else { + cur_expected = expected.Data(); + cur_actual = actual.Data(); + } + + for (int i = 0; i < size; ++i) { + EXPECT_EQ(cur_expected[i], cur_actual[i]) << "i:" << i; + } + } +}; + +template <> +struct TensorCheck { + void operator()(const Tensor& expected, + const Tensor& actual, + const ValidateOutputParams& params, + const std::string& provider_type) const { + const bool has_abs_err = params.absolute_error.has_value(); + const bool has_rel_err = params.relative_error.has_value(); + + Tensor expected_sorted, actual_sorted; + const uint8_t* cur_expected; + const uint8_t* cur_actual; + const auto size = actual.Shape().Size(); + if (params.sort_output) { + // if order can be jumbled in the output of an operator, sort both the + // expected and output buffers prior to + // comparison this is a "best-effort" algo and should satisfy the + // requirement for the few ops that do require this + // support without investing in a more sophisticated infrastructure for the + // same + sort_expected_and_actual_buffers(expected, expected_sorted, actual, actual_sorted); + cur_expected = expected_sorted.Data(); + cur_actual = actual_sorted.Data(); + } else { + cur_expected = expected.Data(); + cur_actual = actual.Data(); + } + + // For uint8_t results, we only allow NNAPI/XNNPACK EP to have an error tolerance, see below for the reason + // XNNPACK EP will always round to larger. For example, 0.1 will be rounded to 1.0 + // For any other EPs, we still expect an exact match for the results + // TODO: Verify if DML can possibly have a ROUNDING_MODE parameter and conform to the other EPs #41968513 + if ((provider_type == kNnapiExecutionProvider || provider_type == kDmlExecutionProvider || + provider_type == kXnnpackExecutionProvider) && + (has_abs_err || has_rel_err)) { + double threshold = has_abs_err ? *(params.absolute_error) + : 0.0; + + for (int i = 0; i < size; ++i) { + if (has_rel_err) { + EXPECT_NEAR(cur_expected[i], cur_actual[i], + *(params.relative_error) * cur_expected[i]) // expected[i] is unsigned, can't be negative + << "i:" << i; + } else { // has_abs_err + EXPECT_NEAR(cur_expected[i], cur_actual[i], threshold) << "i:" << i; + } + } + } else { + for (int i = 0; i < size; ++i) { + EXPECT_EQ(cur_expected[i], cur_actual[i]) << "i:" << i; + } + } + } +}; + +template <> +struct TensorCheck { + void operator()(const Tensor& expected, + const Tensor& actual, + const ValidateOutputParams& params, + const std::string& /*provider_type*/) const { + Tensor expected_sorted, actual_sorted; + const int8_t* cur_expected; + const int8_t* cur_actual; + const auto size = actual.Shape().Size(); + if (params.sort_output) { + // if order can be jumbled in the output of an operator, sort both the + // expected and output buffers prior to + // comparison this is a "best-effort" algo and should satisfy the + // requirement for the few ops that do require this + // support without investing in a more sophisticated infrastructure for the + // same + sort_expected_and_actual_buffers(expected, expected_sorted, actual, actual_sorted); + cur_expected = expected_sorted.Data(); + cur_actual = actual_sorted.Data(); + } else { + cur_expected = expected.template Data(); + cur_actual = actual.template Data(); + } + + const bool has_abs_err = params.absolute_error.has_value(); + if (has_abs_err) { + double threshold = *(params.absolute_error); + + for (int i = 0; i < size; ++i) { + EXPECT_NEAR(cur_expected[i], cur_actual[i], threshold) << "i:" << i; + } + } else { + for (int i = 0; i < size; ++i) { + EXPECT_EQ(cur_expected[i], cur_actual[i]) << "i:" << i; + } + } + } +}; + +template <> +struct TensorCheck { + void operator()(const Tensor& expected, + const Tensor& actual, + const ValidateOutputParams& params, + const std::string& /*provider_type*/) const { + auto size = actual.Shape().Size(); + + bool has_abs_err = params.absolute_error.has_value(); + bool has_rel_err = params.relative_error.has_value(); + + // deal with rare cases in which order of output data from a kernel MAY be + // undefined + Tensor expected_sorted, actual_sorted; + const double* cur_expected; + const double* cur_actual; + if (params.sort_output) { + sort_expected_and_actual_buffers(expected, expected_sorted, actual, actual_sorted); + cur_expected = expected_sorted.Data(); + cur_actual = actual_sorted.Data(); + } else { + cur_expected = expected.Data(); + cur_actual = actual.Data(); + } + + double threshold = 0.001; +#if defined(USE_CUDA) || defined(USE_ROCM) || defined(USE_DML) + threshold = 0.005; +#endif + + for (int i = 0; i < size; ++i) { + // NOTE: Check isnan first to work around MSVC linker bug when /LTCG:incremental is specified. + // If the isinf check is first the isnan check and branch gets omitted + if (std::isnan(cur_expected[i])) { + EXPECT_TRUE(std::isnan(cur_actual[i])) << "Expected NaN. i:" << i; + } else if (std::isinf(cur_expected[i])) { // Test infinity for equality + EXPECT_EQ(cur_expected[i], cur_actual[i]) << "Expected infinity. i:" << i; + } else { + if (!has_abs_err && !has_rel_err) { + // the default for existing tests + EXPECT_NEAR(cur_expected[i], cur_actual[i], threshold) << "i:" << i; + } else { + if (has_abs_err) { + EXPECT_NEAR(cur_expected[i], cur_actual[i], *(params.absolute_error)) << "i:" << i; + } + if (has_rel_err) { + EXPECT_NEAR(cur_expected[i], cur_actual[i], *(params.relative_error) * std::abs(cur_expected[i])) + << "i:" << i; + } + } + } + } + } +}; + +template +void InternalNumericalCheck(const Tensor& expected, + const Tensor& actual, + const ValidateOutputParams& params, + const std::string& /*provider_type*/) { + const bool has_abs_err = params.absolute_error.has_value(); + const bool has_rel_err = params.relative_error.has_value(); + + // deal with rare cases in which order of output data from a kernel MAY be + // undefined + Tensor expected_sorted, actual_sorted; + const TypeToCheck* cur_expected; + const TypeToCheck* cur_actual; + auto size = actual.Shape().Size(); + if (params.sort_output) { + sort_expected_and_actual_buffers(expected, expected_sorted, actual, actual_sorted); + cur_expected = expected_sorted.Data(); + cur_actual = actual_sorted.Data(); + } else { + cur_expected = expected.Data(); + cur_actual = actual.Data(); + } + +#if defined(USE_CUDA) || defined(USE_ROCM) || defined(USE_DML) + constexpr float threshold = 0.005f; +#else + constexpr float threshold = 0.0001f; +#endif + + for (int i = 0; i < size; ++i) { + // NOTE: Check isnan first to work around MSVC linker bug when /LTCG:incremental is specified. + // If the isinf check is first the isnan check and branch gets omitted + if (std::isnan(cur_expected[i])) { + EXPECT_TRUE(std::isnan(cur_actual[i])) << "Expected NaN. i:" << i; + } else if (std::isinf(cur_expected[i])) { // Test infinity for equality + EXPECT_EQ(cur_expected[i], cur_actual[i]) << "Expected infinity. i:" << i; + } else { + if (!has_abs_err && !has_rel_err) { + // the default for existing tests + EXPECT_NEAR(cur_expected[i], cur_actual[i], threshold) << "i:" << i; + } else { + if (has_abs_err) { + EXPECT_NEAR(cur_expected[i], cur_actual[i], *(params.absolute_error)) + << "i:" << i; + } + if (has_rel_err) { + EXPECT_NEAR(cur_expected[i], cur_actual[i], *(params.relative_error) * std::abs(cur_expected[i])) + << "i:" << i; + } + } + } + } +} + +template <> +struct TensorCheck { + void operator()(const Tensor& expected, + const Tensor& actual, + const ValidateOutputParams& params, + const std::string& provider_type) const { + InternalNumericalCheck(expected, actual, params, provider_type); + } +}; + +template <> +struct TensorCheck { + void operator()(const Tensor& expected, + const Tensor& actual, + const ValidateOutputParams& params, + const std::string& /*provider_type*/) const { + auto* cur_expected = expected.Data(); + auto* cur_actual = actual.Data(); + auto size = actual.Shape().Size(); + + std::vector f_expected(size); + std::vector f_actual(size); + ConvertMLFloat16ToFloat(cur_expected, f_expected.data(), static_cast(size)); + ConvertMLFloat16ToFloat(cur_actual, f_actual.data(), static_cast(size)); + + // deal with rare cases in which order of output data from a kernel MAY be + // undefined + if (params.sort_output) { + sort_expected_and_actual_buffers(f_expected, f_actual); + } + + const bool has_abs_err = params.absolute_error.has_value(); + const bool has_rel_err = params.relative_error.has_value(); + + float threshold = 0.001f; +#if defined(USE_TENSORRT) || defined(ENABLE_TRAINING_CORE) || defined(USE_CUDA) || defined(USE_ROCM) + threshold = 0.005f; +#elif defined(USE_DML) + threshold = 0.02f; +#endif + for (int i = 0; i < size; ++i) { + if (std::isnan(f_expected[i])) { + EXPECT_TRUE(std::isnan(f_expected[i])) << "Expected NaN. i:" << i; + } else if (std::isinf(f_expected[i])) { // Test infinity for equality + EXPECT_EQ(f_expected[i], f_actual[i]) << "Expected infinity. i:" << i; + } else { + if (!has_abs_err && !has_rel_err) { + // the default for existing tests + EXPECT_NEAR(f_expected[i], f_actual[i], threshold) << "i:" << i; + } else { + if (has_abs_err) { + EXPECT_NEAR(f_expected[i], f_actual[i], *(params.absolute_error)) + << "i:" << i; + } + if (has_rel_err) { + EXPECT_NEAR(f_expected[i], f_actual[i], *(params.relative_error) * std::abs(static_cast(cur_expected[i]))) + << "i:" << i; + } + } + } + } + } +}; + +template <> +struct TensorCheck { + void operator()(const Tensor& expected, + const Tensor& actual, + const ValidateOutputParams& params, + const std::string& /*provider_type*/) const { + auto* cur_expected = expected.Data(); + auto* cur_actual = actual.Data(); + auto size = actual.Shape().Size(); + + std::vector f_expected(size); + std::vector f_actual(size); + BFloat16ToFloat(cur_expected, f_expected.data(), static_cast(size)); + BFloat16ToFloat(cur_actual, f_actual.data(), static_cast(size)); + + // deal with rare cases in which order of output data from a kernel MAY be + // undefined + if (params.sort_output) { + sort_expected_and_actual_buffers(f_expected, f_actual); + } + + /// XXX: May need to adjust threshold as BFloat is coarse + float abs_threshold = 0.0001f; + float threshold = 0.001f; +#if defined(USE_TENSORRT) || defined(ENABLE_TRAINING_CORE) || defined(USE_CUDA) || defined(USE_ROCM) || defined(USE_DML) || defined(USE_DNNL) + threshold = 0.05f; // expect at least 95% close +#endif + + for (int i = 0; i < size; ++i) { + if (std::isnan(f_expected[i])) { + EXPECT_TRUE(std::isnan(f_expected[i])) << "Expected NaN. i:" << i; + } else if (std::isinf(f_expected[i])) { // Test infinity for equality + EXPECT_EQ(f_expected[i], f_actual[i]) << "Expected infinity. i:" << i; + } else { + // the default for existing tests + const float max_value = fmax(fabs(f_expected[i]), fabs(f_actual[i])); + if (max_value != 0) { // max_value = 0 means output and expected are 0s. + const float abs_error = fabs(f_expected[i] - f_actual[i]); + if (abs_error <= abs_threshold) { + // if the absolute error is small enough, then no need to calculate realative error + EXPECT_NEAR(0, abs_error, abs_threshold); + } else { + // default for existing tests. + const float rel_error = abs_error / max_value; + EXPECT_NEAR(0, rel_error, threshold); + } + } + } + } + } +}; +} // namespace + +// default Check +template +void Check(std::string_view name, const OrtValue& expected, const T& actual, + const ValidateOutputParams& /*params*/, const std::string& /*provider_type*/) { + EXPECT_EQ(expected.Get(), actual) << "name: " << name; +} + +// Check for Tensors +template <> +void Check(std::string_view name, const OrtValue& expected, const Tensor& actual, + const ValidateOutputParams& params, const std::string& provider_type) { + const Tensor& expected_tensor = expected.Get(); + ORT_ENFORCE(expected_tensor.Shape() == actual.Shape(), + "Expected output shape [", expected_tensor.Shape(), + "] did not match run output shape [", actual.Shape(), + "] for ", name); + + utils::MLTypeCallDispatcher + t_disp(actual.GetElementType()); + + t_disp.Invoke(expected_tensor, actual, params, provider_type); +} + +// Check for sequence of tensors +template <> +void Check(std::string_view name, const OrtValue& expected, const TensorSeq& actual, + const ValidateOutputParams& params, const std::string& provider_type) { + const auto& exp_seq = expected.Get(); + + // first ensure data types match + EXPECT_EQ(exp_seq.DataType(), actual.DataType()) + << "Data types don't match for " << name << ". Expected : " << DataTypeImpl::ToString(exp_seq.DataType()) + << " Output: " << actual.DataType(); + + // check num of contained tensors + size_t expected_num_tensors = exp_seq.Size(); + size_t actual_num_tensors = actual.Size(); + EXPECT_EQ(expected_num_tensors, actual_num_tensors) + << "Mismatch in number of tensors in the sequence for " << name + << ". Expected: " << expected_num_tensors + << " Output: " << actual_num_tensors; + + // now check the contents of the tensors + auto element_type = exp_seq.DataType()->AsPrimitiveDataType()->GetDataType(); + utils::MLTypeCallDispatcher + t_disp(element_type); + + for (size_t i = 0; i < actual_num_tensors; ++i) { + t_disp.Invoke(exp_seq.Get(i), actual.Get(i), params, provider_type); + } +} + +template +void CheckDispatch(MLDataType type, std::string_view name, const OrtValue& expected, const OrtValue& actual, + const ValidateOutputParams& params, const std::string& provider_type) { + if (type == DataTypeImpl::GetType()) { + Check(name, expected, actual.Get(), params, provider_type); + } else { + ORT_THROW("OpTester:Check() not implemented for output tensor type of ", type); + } +} + +template +void CheckDispatch(MLDataType type, std::string_view name, const OrtValue& expected, const OrtValue& actual, + const ValidateOutputParams& params, const std::string& provider_type) { + if (type == DataTypeImpl::GetType()) { + Check(name, expected, actual.Get(), params, provider_type); + } else { + CheckDispatch(type, name, expected, actual, params, provider_type); + } +} + +void CheckOrtValuesAreEqual(std::string_view name, const OrtValue& expected, const OrtValue& actual, + const ValidateOutputParams& params, const std::string& provider_type) { + // Include provider_type in any error output + SCOPED_TRACE(MakeString("provider type: ", provider_type)); + + CheckDispatch< + Tensor, +#if !defined(DISABLE_ML_OPS) + VectorMapStringToFloat, VectorMapInt64ToFloat, +#endif + TensorSeq>(expected.Type(), name, expected, actual, params, provider_type); +} + +} // namespace test +} // namespace onnxruntime diff --git a/onnxruntime/test/providers/checkers.h b/onnxruntime/test/providers/checkers.h new file mode 100644 index 0000000000000..54f3bb8f0fe5d --- /dev/null +++ b/onnxruntime/test/providers/checkers.h @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include +#include + +#include "core/framework/ort_value.h" +#include "core/util/math_cpuonly.h" + +namespace onnxruntime { +namespace test { + +struct ValidateOutputParams { + std::optional relative_error; + std::optional absolute_error; + bool sort_output = false; +}; + +/// +/// General purpose function to check the equality of two OrtValue instances. All ONNX types are supported. +/// +/// Value name +/// Expected value. +/// Actual value. +/// Optional parameters to adjust how the check is performed. +/// Execution provider type if relevant. +void CheckOrtValuesAreEqual(std::string_view name, const OrtValue& expected, const OrtValue& actual, + const ValidateOutputParams& params = {}, const std::string& provider_type = ""); + +} // namespace test +} // namespace onnxruntime diff --git a/onnxruntime/test/providers/compare_provider_test_utils.cc b/onnxruntime/test/providers/compare_provider_test_utils.cc index 540b9c0592689..94fb03540e3f8 100644 --- a/onnxruntime/test/providers/compare_provider_test_utils.cc +++ b/onnxruntime/test/providers/compare_provider_test_utils.cc @@ -1,12 +1,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/session/inference_session.h" +#include "test/providers/compare_provider_test_utils.h" + #include "core/optimizer/insert_cast_transformer.h" +#include "core/session/inference_session.h" + +#include "test/util/include/asserts.h" +#include "test/util/include/compare_ortvalue.h" #include "test/util/include/default_providers.h" -#include "test/providers/compare_provider_test_utils.h" -#include "test/test_environment.h" -#include "test/compare_ortvalue.h" +#include "test/util/include/test_environment.h" using namespace std; @@ -45,17 +48,14 @@ void CompareOpTester::CompareWithCPU(const std::string& target_provider_type, double relative_per_sample_tolerance, const bool need_cpu_cast, const std::unordered_map& extra_domain_to_version) { -#ifndef NDEBUG - run_called_ = true; -#endif + SetTestFunctionCalled(); std::unique_ptr target_execution_provider = GetExecutionProvider(target_provider_type); - ASSERT_TRUE(target_execution_provider != nullptr) << "provider_type " << target_provider_type << " is not supported."; + ASSERT_TRUE(target_execution_provider != nullptr) << "provider_type " << target_provider_type + << " is not supported."; - auto p_model = BuildGraph(extra_domain_to_version); - auto& graph = p_model->MainGraph(); - - Status status; + auto& model = BuildModel(extra_domain_to_version); + auto& graph = model.MainGraph(); // In InferenceSession::Initialize(), the call to graph partitioner, which is responsible // for Inlining function bodies for ops whose kernel is missing happens before the @@ -63,17 +63,12 @@ void CompareOpTester::CompareWithCPU(const std::string& target_provider_type, // the function body is instead used for CPU pass. This option allows the comparison with // the CPU kernel by adding the input/output casts before looking for a registered CPU kernel. if (need_cpu_cast) { - InsertCastTransformer transformer("Test"); + InsertCastTransformer transformer("Test", GetExecutionProvider(kCpuExecutionProvider)->GetKernelRegistry().get()); bool modified = false; - status = transformer.Apply(graph, modified, DefaultLoggingManager().DefaultLogger()); - ASSERT_TRUE(status.IsOK()); + ASSERT_STATUS_OK(transformer.Apply(graph, modified, DefaultLoggingManager().DefaultLogger())); } - status = graph.Resolve(); - ASSERT_TRUE(status.IsOK()) << status.ErrorMessage(); - if (!status.IsOK()) { - return; - } + ASSERT_STATUS_OK(graph.Resolve()); // Hookup the inputs and outputs std::unordered_map feeds; @@ -82,76 +77,41 @@ void CompareOpTester::CompareWithCPU(const std::string& target_provider_type, // Run the model SessionOptions so; - so.session_logid = op_; - so.session_log_verbosity_level = 1; + so.session_logid = Op(); InferenceSession cpu_session_object{so, GetEnvironment()}; // first run with cpu std::string s1; - p_model->ToProto().SerializeToString(&s1); + model.ToProto().SerializeToString(&s1); std::istringstream model_proto_str(s1); - status = cpu_session_object.Load(model_proto_str); - EXPECT_TRUE(status.IsOK()) << status.ErrorMessage(); - if (!status.IsOK()) { - LOGS_DEFAULT(ERROR) << "Load failed with status: " << status.ErrorMessage(); - return; - } - - status = cpu_session_object.Initialize(); - EXPECT_TRUE(status.IsOK()) << status.ErrorMessage(); - if (!status.IsOK()) { - LOGS_DEFAULT(ERROR) << "Initialize failed with status: " << status.ErrorMessage(); - return; - } + ASSERT_STATUS_OK(cpu_session_object.Load(model_proto_str)); - RunOptions run_options; - run_options.run_tag = op_; - run_options.run_log_verbosity_level = 1; + ASSERT_STATUS_OK(cpu_session_object.Initialize()); std::vector cpu_fetches; - status = cpu_session_object.Run(run_options, feeds, output_names, &cpu_fetches); - EXPECT_TRUE(status.IsOK()) << status.ErrorMessage(); - if (!status.IsOK()) { - LOGS_DEFAULT(ERROR) << "Run failed with status: " << status.ErrorMessage(); - return; - } + ASSERT_STATUS_OK(cpu_session_object.Run({}, feeds, output_names, &cpu_fetches)); // run with target provider // build the graph again as the cpu graph may be with casts - auto p_tp_model = BuildGraph(extra_domain_to_version); - auto& tp_graph = p_tp_model->MainGraph(); + auto& tp_model = BuildModel(extra_domain_to_version); + auto& tp_graph = tp_model.MainGraph(); - status = tp_graph.Resolve(); - ASSERT_TRUE(status.IsOK()) << status.ErrorMessage(); - if (!status.IsOK()) { - return; - } + ASSERT_STATUS_OK(tp_graph.Resolve()); InferenceSession target_session_object{so, GetEnvironment()}; - EXPECT_TRUE(target_session_object.RegisterExecutionProvider(std::move(target_execution_provider)).IsOK()); + ASSERT_STATUS_OK(target_session_object.RegisterExecutionProvider(std::move(target_execution_provider))); std::string s2; - p_tp_model->ToProto().SerializeToString(&s2); + tp_model.ToProto().SerializeToString(&s2); std::istringstream model_proto_str1(s2); - status = target_session_object.Load(model_proto_str1); - EXPECT_TRUE(status.IsOK()) << status.ErrorMessage(); - if (!status.IsOK()) { - LOGS_DEFAULT(ERROR) << "Load failed with status: " << status.ErrorMessage(); - return; - } + ASSERT_STATUS_OK(target_session_object.Load(model_proto_str1)); - status = target_session_object.Initialize(); - EXPECT_TRUE(status.IsOK()) << status.ErrorMessage(); - if (!status.IsOK()) { - LOGS_DEFAULT(ERROR) << "Initialize failed with status: " << status.ErrorMessage(); - return; - } + ASSERT_STATUS_OK(target_session_object.Initialize()); std::vector target_fetches; - status = target_session_object.Run(run_options, feeds, output_names, &target_fetches); - EXPECT_TRUE(status.IsOK()) << status.ErrorMessage(); + ASSERT_STATUS_OK(target_session_object.Run({}, feeds, output_names, &target_fetches)); // compare ASSERT_TRUE(cpu_fetches.size() == target_fetches.size()); diff --git a/onnxruntime/test/providers/coreml/coreml_basic_test.cc b/onnxruntime/test/providers/coreml/coreml_basic_test.cc index 333edcd2117a3..7b6f1b9244be9 100644 --- a/onnxruntime/test/providers/coreml/coreml_basic_test.cc +++ b/onnxruntime/test/providers/coreml/coreml_basic_test.cc @@ -8,9 +8,10 @@ #include "test/common/tensor_op_test_utils.h" #include "test/framework/test_utils.h" #include "test/util/include/asserts.h" +#include "test/util/include/current_test_name.h" #include "test/util/include/default_providers.h" #include "test/util/include/inference_session_wrapper.h" -#include "test/util/include/test/test_environment.h" +#include "test/util/include/test_environment.h" #include "test/util/include/test_utils.h" #if !defined(ORT_MINIMAL_BUILD) @@ -21,7 +22,6 @@ #include "gtest/gtest.h" #include "gmock/gmock.h" -using namespace std; using namespace ONNX_NAMESPACE; using namespace ::onnxruntime::logging; @@ -31,6 +31,10 @@ namespace test { // We want to run UT on CPU only to get output value without losing precision to pass the verification static constexpr uint32_t s_coreml_flags = COREML_FLAG_USE_CPU_ONLY; +static std::unique_ptr MakeCoreMLExecutionProvider(uint32_t flags = s_coreml_flags) { + return std::make_unique(flags); +} + #if !defined(ORT_MINIMAL_BUILD) TEST(CoreMLExecutionProviderTest, FunctionTest) { @@ -76,14 +80,12 @@ TEST(CoreMLExecutionProviderTest, FunctionTest) { std::vector values_mul_x = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; OrtValue ml_value_x; - CreateMLValue(TestCoreMLExecutionProvider(s_coreml_flags)->GetAllocator(OrtMemTypeDefault), - dims_mul_x, values_mul_x, &ml_value_x); + AllocatorPtr allocator = std::make_shared(); + CreateMLValue(allocator, dims_mul_x, values_mul_x, &ml_value_x); OrtValue ml_value_y; - CreateMLValue(TestCoreMLExecutionProvider(s_coreml_flags)->GetAllocator(OrtMemTypeDefault), - dims_mul_x, values_mul_x, &ml_value_y); + CreateMLValue(allocator, dims_mul_x, values_mul_x, &ml_value_y); OrtValue ml_value_z; - CreateMLValue(TestCoreMLExecutionProvider(s_coreml_flags)->GetAllocator(OrtMemTypeDefault), - dims_mul_x, values_mul_x, &ml_value_z); + CreateMLValue(allocator, dims_mul_x, values_mul_x, &ml_value_z); NameMLValMap feeds; feeds.insert(std::make_pair("X", ml_value_x)); @@ -91,17 +93,10 @@ TEST(CoreMLExecutionProviderTest, FunctionTest) { feeds.insert(std::make_pair("Z", ml_value_z)); RunAndVerifyOutputsWithEP(model_file_name, "CoreMLExecutionProviderTest.FunctionTest", - std::make_unique(s_coreml_flags), + MakeCoreMLExecutionProvider(), feeds); #else - // test load only - SessionOptions so; - InferenceSessionWrapper session_object{so, GetEnvironment()}; - ASSERT_STATUS_OK(session_object.RegisterExecutionProvider(std::make_unique(0))); - ASSERT_STATUS_OK(session_object.Load(model_file_name)); - ASSERT_STATUS_OK(session_object.Initialize()); - ASSERT_GT(CountAssignedNodes(session_object.GetGraph(), kCoreMLExecutionProvider), 0) - << "Some nodes should have been taken by the CoreML EP"; + TestModelLoad(model_file_name, MakeCoreMLExecutionProvider(), ExpectedEPNodeAssignment::Some); #endif } @@ -117,25 +112,58 @@ TEST(CoreMLExecutionProviderTest, ArgMaxCastTest) { std::vector dims_mul_x = {3, 2, 2}; std::vector values_mul_x = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f}; OrtValue ml_value_x; - - CreateMLValue(TestCoreMLExecutionProvider(s_coreml_flags)->GetAllocator(OrtMemTypeDefault), - dims_mul_x, values_mul_x, &ml_value_x); + AllocatorPtr allocator = std::make_shared(); + CreateMLValue(allocator, dims_mul_x, values_mul_x, &ml_value_x); NameMLValMap feeds; feeds.insert(std::make_pair("X", ml_value_x)); RunAndVerifyOutputsWithEP(model_file_name, "CoreMLExecutionProviderTest.ArgMaxCastTest", - std::make_unique(s_coreml_flags), + MakeCoreMLExecutionProvider(), feeds); #else - // test load only - SessionOptions so; - InferenceSessionWrapper session_object{so, GetEnvironment()}; - ASSERT_STATUS_OK(session_object.RegisterExecutionProvider(std::make_unique(0))); - ASSERT_STATUS_OK(session_object.Load(model_file_name)); - ASSERT_STATUS_OK(session_object.Initialize()); - ASSERT_GT(CountAssignedNodes(session_object.GetGraph(), kCoreMLExecutionProvider), 0) - << "Some nodes should have been taken by the CoreML EP"; + TestModelLoad(model_file_name, MakeCoreMLExecutionProvider(), ExpectedEPNodeAssignment::Some); +#endif +} + +TEST(CoreMLExecutionProviderTest, GatherWithScalarIndices) { + // For scalar inputs, the input shape is modified from [] -> [1] before passing the input to CoreML. + // This won't work for Gather because the output shape depends on the `indices` input shape which could be a scalar. + // Currently, we expect the CoreML EP to only take the Shape node in this graph (Gather -> Shape). + const auto model_file_name = ORT_TSTR("testdata/gather_with_scalar_indices_then_shape.onnx"); + +#if defined(__APPLE__) + RandomValueGenerator gen{1234}; + std::vector X_shape = {5, 3, 4}; + std::vector X_data = gen.Uniform(X_shape, 0.0f, 1.0f); + OrtValue X = CreateInputOrtValueOnCPU(X_shape, X_data); + OrtValue indices = CreateInputOrtValueOnCPU(AsSpan({}), AsSpan({1})); + + RunAndVerifyOutputsWithEP(model_file_name, CurrentTestName(), + MakeCoreMLExecutionProvider(), + {{"X", X}, {"indices", indices}}); +#else + TestModelLoad(model_file_name, MakeCoreMLExecutionProvider(), ExpectedEPNodeAssignment::Some); +#endif +} + +TEST(CoreMLExecutionProviderTest, ShapeThenSliceAndGather) { + // This is a simple test model that provides the output of Shape to Slice and Gather. + // We expect the CoreML EP to support shape manipulations like this. + const auto model_file_name = ORT_TSTR("testdata/shape_then_slice_and_gather.onnx"); + +#if defined(__APPLE__) + RandomValueGenerator gen{1234}; + std::vector X_shape = {5, 3, 4, 1, 2}; + std::vector X_data = gen.Uniform(X_shape, 0.0f, 1.0f); + OrtValue X = CreateInputOrtValueOnCPU(X_shape, X_data); + + RunAndVerifyOutputsWithEP(model_file_name, CurrentTestName(), + MakeCoreMLExecutionProvider(), + {{"X", X}}, + EPVerificationParams{ExpectedEPNodeAssignment::All}); +#else + TestModelLoad(model_file_name, MakeCoreMLExecutionProvider(), ExpectedEPNodeAssignment::All); #endif } @@ -151,23 +179,16 @@ TEST(CoreMLExecutionProviderTest, TestOrtFormatModel) { std::vector data = random.Gaussian(dims, 0.0f, 1.f); OrtValue ml_value; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), dims, data, &ml_value); + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], dims, data, &ml_value); NameMLValMap feeds; feeds.insert(std::make_pair("Input3", ml_value)); RunAndVerifyOutputsWithEP(model_file_name, "CoreMLExecutionProviderTest.TestOrtFormatModel", - std::make_unique(s_coreml_flags), + MakeCoreMLExecutionProvider(), feeds); #else - // test load only - SessionOptions so; - InferenceSessionWrapper session_object{so, GetEnvironment()}; - ASSERT_STATUS_OK(session_object.RegisterExecutionProvider(std::make_unique(0))); - ASSERT_STATUS_OK(session_object.Load(model_file_name)); - ASSERT_STATUS_OK(session_object.Initialize()); - ASSERT_GT(CountAssignedNodes(session_object.GetGraph(), kCoreMLExecutionProvider), 0) - << "Some nodes should have been taken by the CoreML EP"; + TestModelLoad(model_file_name, MakeCoreMLExecutionProvider(), ExpectedEPNodeAssignment::Some); #endif } diff --git a/onnxruntime/test/providers/coreml/dynamic_input_test.cc b/onnxruntime/test/providers/coreml/dynamic_input_test.cc new file mode 100644 index 0000000000000..c91ef23650040 --- /dev/null +++ b/onnxruntime/test/providers/coreml/dynamic_input_test.cc @@ -0,0 +1,111 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "gtest/gtest.h" + +#include +#include + +#include "core/providers/coreml/coreml_execution_provider.h" +#include "core/providers/coreml/coreml_provider_factory.h" // for COREMLFlags +#include "test/common/random_generator.h" +#include "test/providers/model_tester.h" +#include "test/util/include/current_test_name.h" +#include "test/util/include/test_utils.h" + +namespace onnxruntime::test { + +TEST(CoreMLExecutionProviderDynamicInputShapeTest, MatMul) { + constexpr auto model_path = ORT_TSTR("testdata/matmul_with_dynamic_input_shape.onnx"); + + auto test = [&](const size_t M) { + SCOPED_TRACE(MakeString("M=", M)); + + auto coreml_ep = std::make_unique(0); + + const auto ep_verification_params = EPVerificationParams{ + ExpectedEPNodeAssignment::All, + 2e-3f, + }; + +#if defined(__APPLE__) + RandomValueGenerator gen{1234}; + const auto A_shape = std::vector{static_cast(M), 2}; + const auto A_data = gen.Uniform(A_shape, 0.0f, 1.0f); + + OrtValue A = CreateInputOrtValueOnCPU(A_shape, A_data); + + RunAndVerifyOutputsWithEP(model_path, CurrentTestName(), + std::move(coreml_ep), + {{"A", A}}, + ep_verification_params); +#else + TestModelLoad(model_path, std::move(coreml_ep), ep_verification_params.ep_node_assignment); +#endif + }; + + for (size_t i = 1; i <= 5; ++i) { + test(i); + } +} + +TEST(CoreMLExecutionProviderDynamicInputShapeTest, MobileNetExcerpt) { + constexpr auto model_path = ORT_TSTR("testdata/mobilenet_v3_small_excerpt.onnx"); + + auto test = [&](const size_t batch_size) { + SCOPED_TRACE(MakeString("batch_size=", batch_size)); + + auto coreml_ep = std::make_unique(0); + + const auto ep_verification_params = EPVerificationParams{ + ExpectedEPNodeAssignment::All, + 5e-2f, + }; + +#if defined(__APPLE__) + RandomValueGenerator gen{1234}; + const auto input_shape = std::vector{static_cast(batch_size), 3, 224, 224}; + const auto input_data = gen.Uniform(input_shape, 0.0f, 1.0f); + + OrtValue input = CreateInputOrtValueOnCPU(input_shape, input_data); + + RunAndVerifyOutputsWithEP(model_path, CurrentTestName(), + std::move(coreml_ep), + {{"input", input}}, + ep_verification_params); +#else + TestModelLoad(model_path, std::move(coreml_ep), ep_verification_params.ep_node_assignment); +#endif + }; + + for (size_t i = 1; i <= 5; ++i) { + test(i); + } +} + +TEST(CoreMLExecutionProviderDynamicInputShapeTest, EmptyInputFails) { + constexpr auto model_path = ORT_TSTR("testdata/matmul_with_dynamic_input_shape.onnx"); + + ModelTester tester(CurrentTestName(), model_path); + + tester.AddInput("A", {0, 2}, {}); + tester.AddOutput("Y", {0, 4}, {}); + + tester + .Config(ModelTester::ExpectResult::kExpectFailure, + "the runtime shape ({0,2}) has zero elements. This is not supported by the CoreML EP.") + .ConfigEp(std::make_unique(0)) + .RunWithConfig(); +} + +TEST(CoreMLExecutionProviderDynamicInputShapeTest, OnlyAllowStaticInputShapes) { + constexpr auto model_path = ORT_TSTR("testdata/matmul_with_dynamic_input_shape.onnx"); + + auto coreml_ep = std::make_unique(COREML_FLAG_ONLY_ALLOW_STATIC_INPUT_SHAPES); + + TestModelLoad(model_path, std::move(coreml_ep), + // expect no supported nodes because we disable dynamic input shape support + ExpectedEPNodeAssignment::None); +} + +} // namespace onnxruntime::test diff --git a/onnxruntime/test/providers/cpu/activation/activation_op_test.cc b/onnxruntime/test/providers/cpu/activation/activation_op_test.cc index 145d1241e065d..7ec9e0f345187 100644 --- a/onnxruntime/test/providers/cpu/activation/activation_op_test.cc +++ b/onnxruntime/test/providers/cpu/activation/activation_op_test.cc @@ -64,6 +64,10 @@ constexpr float SigmoidGrad(float dy, float y) { constexpr float TanhGrad(float dy, float y) { return dy * (1 - y * y); } + +constexpr float LeakyReluGrad(float dy, float y, float alpha) { + return dy * (y > 0.0f ? 1.0f : alpha); +} } // namespace #endif @@ -400,6 +404,7 @@ TEST_F(ActivationOpTest, Celu) { // Disable on TensorRT as it seems like it doesn't yet support Celu {{"alpha", alpha}}, false, 12); } + TEST_F(ActivationOpTest, LeakyRelu) { float alpha = 0.1f; TestActivationOp("LeakyRelu", @@ -668,6 +673,23 @@ TEST(TanhGradInferenceTest, Basic) { }, {}, 1, kMSDomain); } + +TEST(LeakyReluGradInferenceTest, Basic) { + const std::vector y_vals = {-1.0f, 0, 1.0f, 100.0f, -100.0f, 1000.0f, -1000.0f}; + const std::vector dY(7, 1.0f); + float alpha = 0.5f; + + TestElementwiseGradientOp( + "LeakyReluGrad", + {{"dY", dY}, {"Y", y_vals}}, + [alpha](const std::vector& params) { + ORT_ENFORCE(params.size() == 2); + const auto dy = params[0], y = params[1]; + + return LeakyReluGrad(dy, y, alpha); + }, + {{"alpha", alpha}}, 1, kMSDomain); +} #endif } // namespace test diff --git a/onnxruntime/test/providers/cpu/activation/activation_op_test.h b/onnxruntime/test/providers/cpu/activation/activation_op_test.h index c7991c05f139b..c78443eaf8534 100644 --- a/onnxruntime/test/providers/cpu/activation/activation_op_test.h +++ b/onnxruntime/test/providers/cpu/activation/activation_op_test.h @@ -38,22 +38,6 @@ inline void TestActivationOp(const char* szOp, const std::vector> excluded_providers.insert(kTensorrtExecutionProvider); } -// Disabled because of accuracy issues for MYRIAD FP16 and VAD_M -#if defined(OPENVINO_CONFIG_MYRIAD) || defined(OPENVINO_CONFIG_VAD_M) - int relu = strcmp(szOp, "Relu"); - int leaky = strcmp(szOp, "LeakyRelu"); - int elu = strcmp(szOp, "Elu"); - int sigmoid = strcmp(szOp, "Sigmoid"); - int tanh = strcmp(szOp, "Tanh"); - if (relu == 0 || leaky == 0) { - excluded_providers.insert(kOpenVINOExecutionProvider); - } - if (elu == 0) - excluded_providers.insert(kOpenVINOExecutionProvider); - if (sigmoid == 0 || tanh == 0) - excluded_providers.insert(kOpenVINOExecutionProvider); -#endif - // Disabled because of accuracy issues for GPU #if defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_GPU_FP32) int leaky = strcmp(szOp, "LeakyRelu"); diff --git a/onnxruntime/test/providers/cpu/controlflow/if_test.cc b/onnxruntime/test/providers/cpu/controlflow/if_test.cc index 9176226f55e0d..31b5618180bf7 100644 --- a/onnxruntime/test/providers/cpu/controlflow/if_test.cc +++ b/onnxruntime/test/providers/cpu/controlflow/if_test.cc @@ -246,10 +246,15 @@ void RunTest(bool condition_value, excluded_providers.insert(kTensorrtExecutionProvider); } if (options.mixed_execution_providers) { - // we want the CUDA provider to be first, and the CPU provider second. all except the If should run on - // CUDA given that, which creates the scenario where we need to copy to/from CPU to execute the If node correctly. + // we want the GPU (CUDA/ROCm) provider to be first, and the CPU provider second. all except the If should run on + // GPU given that, which creates the scenario where we need to copy to/from CPU to execute the If node correctly. std::vector> execution_providers; +#ifdef USE_CUDA execution_providers.push_back(DefaultCudaExecutionProvider()); +#endif +#ifdef USE_ROCM + execution_providers.push_back(DefaultRocmExecutionProvider()); +#endif execution_providers.push_back(DefaultCpuExecutionProvider()); test.Run(expect_result, failure_message, excluded_providers, nullptr, &execution_providers); @@ -290,7 +295,7 @@ TEST(If, NoShapeInMainGraph_ShapeInSubgraph_False) { RunTest(false, options, false); } -#ifdef USE_CUDA +#if defined(USE_CUDA) || defined(USE_ROCM) TEST(If, MixedExecutionProviders) { RunOptions options{}; options.mixed_execution_providers = true; @@ -311,7 +316,7 @@ TEST(If, MixedExecutionProvidersNoShapeInSubgraph) { options.include_dim_values_in_subgraph = false; RunTest(true, options); } -#endif // USE_CUDA +#endif // defined(USE_CUDA) || defined(USE_ROCM) TEST(If, SymbolicShapeInMainGraph_NoShapeInSubgraph_True) { RunOptions options; @@ -480,12 +485,6 @@ class IfOpTesterWithOptionalTypeAsOutput : public OpTester { } protected: - // Since this test is being written at a time when only opset 15 has been released, we override - // IsAllowReleasedONNXOpsetsOnlySetForThisTest() to return `false`to allow this test to run - bool IsAllowReleasedONNXOpsetsOnlySetForThisTest() const override { - return false; - } - void AddNodes(onnxruntime::Graph& graph, std::vector& graph_input_defs, std::vector& graph_output_defs, diff --git a/onnxruntime/test/providers/cpu/controlflow/loop_test.cc b/onnxruntime/test/providers/cpu/controlflow/loop_test.cc index b5f4e55f93157..8dcf632192249 100644 --- a/onnxruntime/test/providers/cpu/controlflow/loop_test.cc +++ b/onnxruntime/test/providers/cpu/controlflow/loop_test.cc @@ -709,13 +709,13 @@ TEST(Loop, SubgraphInputShadowsOuterScopeValue) { NameMLValMap feeds; OrtValue ml_value; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), scalar, a, &ml_value); + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], scalar, a, &ml_value); feeds.insert(std::make_pair("a", ml_value)); - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), scalar, b, &ml_value); + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], scalar, b, &ml_value); feeds.insert(std::make_pair("b", ml_value)); - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), scalar, trip_count, &ml_value); + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], scalar, trip_count, &ml_value); feeds.insert(std::make_pair("max_trip_count", ml_value)); - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), scalar, keep_going, &ml_value); + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], scalar, keep_going, &ml_value); feeds.insert(std::make_pair("keep_going_inp", ml_value)); // prepare outputs @@ -930,7 +930,7 @@ TEST(Loop, PassThroughSubgraphInputNoTypeOrShape) { test.AddOutput("loop_var_0_final", {1}, {123.f}); // Disable TensorRT on unsupported data type BOOL - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kOpenVINOExecutionProvider}); } TEST(Loop, BugFixIssue4031_implicit_input_handling) { @@ -947,7 +947,7 @@ TEST(Loop, BugFixIssue4031_implicit_input_handling) { // prepare inputs OrtValue ml_value; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), {1}, {123.f}, + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], {1}, {123.f}, &ml_value); NameMLValMap feeds; feeds.insert(std::make_pair("state_var_in", ml_value)); @@ -1252,10 +1252,6 @@ TEST(Loop, OptionalTypeAsLoopCarriedDependency) { { OpTester test("Loop", 16); // Opset 16 supports optional type - // Since this test is being written at a time when only opset 15 has been released, we set - // `test_allow_released_onnx_opset_only_` to 'false' to allow this test to run - test.test_allow_released_onnx_opset_only_ = false; - auto body = create_subgraph(true); test.AddAttribute("body", body); @@ -1271,9 +1267,6 @@ TEST(Loop, OptionalTypeAsLoopCarriedDependency) { // CASE 2: Optional tensor + non-none { OpTester test("Loop", 16); // Opset 16 supports optional type - // Since this test is being written at a time when only opset 15 has been released, we set - // `test_allow_released_onnx_opset_only_` to 'false' to allow this test to run - test.test_allow_released_onnx_opset_only_ = false; auto body = create_subgraph(true); test.AddAttribute("body", body); @@ -1291,9 +1284,6 @@ TEST(Loop, OptionalTypeAsLoopCarriedDependency) { // CASE 3: Optional tensor sequence + none { OpTester test("Loop", 16); // Opset 16 supports optional type - // Since this test is being written at a time when only opset 15 has been released, we set - // `test_allow_released_onnx_opset_only_` to 'false' to allow this test to run - test.test_allow_released_onnx_opset_only_ = false; auto body = create_subgraph(false); test.AddAttribute("body", body); @@ -1311,9 +1301,6 @@ TEST(Loop, OptionalTypeAsLoopCarriedDependency) { // CASE 4: Optional tensor sequence + non-none { OpTester test("Loop", 16); // Opset 16 supports optional type - // Since this test is being written at a time when only opset 15 has been released, we set - // `test_allow_released_onnx_opset_only_` to 'false' to allow this test to run - test.test_allow_released_onnx_opset_only_ = false; auto body = create_subgraph(false); test.AddAttribute("body", body); diff --git a/onnxruntime/test/providers/cpu/controlflow/scan_test.cc b/onnxruntime/test/providers/cpu/controlflow/scan_test.cc index 8f2fb2ddaa411..6d8e05b93510a 100644 --- a/onnxruntime/test/providers/cpu/controlflow/scan_test.cc +++ b/onnxruntime/test/providers/cpu/controlflow/scan_test.cc @@ -25,7 +25,7 @@ struct RunOptions { bool add_bad_shape = false; bool mixed_execution_providers = false; // Disable TensorRT because its parser fails, and it can't handle unknown dimensions - std::unordered_set excluded_provider_types{kTensorrtExecutionProvider}; + std::unordered_set excluded_provider_types{kTensorrtExecutionProvider, kOpenVINOExecutionProvider}; }; static common::Status CreateSubgraph(Graph& graph, RunOptions& options, const std::string& failure_message = ""); diff --git a/onnxruntime/test/providers/cpu/cpu_execution_provider_test.cc b/onnxruntime/test/providers/cpu/cpu_execution_provider_test.cc index 15c9acf855ae0..8b9dcbd943b4a 100644 --- a/onnxruntime/test/providers/cpu/cpu_execution_provider_test.cc +++ b/onnxruntime/test/providers/cpu/cpu_execution_provider_test.cc @@ -10,7 +10,7 @@ TEST(CPUExecutionProviderTest, MetadataTest) { CPUExecutionProviderInfo info; auto provider = std::make_unique(info); EXPECT_TRUE(provider != nullptr); - ASSERT_STREQ(provider->GetAllocator(OrtMemTypeDefault)->Info().name, CPU); + ASSERT_EQ(provider->GetOrtDeviceByMemType(OrtMemTypeDefault).Type(), OrtDevice::CPU); } } // namespace test } // namespace onnxruntime diff --git a/onnxruntime/test/providers/cpu/generator/constant_of_shape_test.cc b/onnxruntime/test/providers/cpu/generator/constant_of_shape_test.cc index 016c2faf7e5a3..de4ce5d85ab0b 100644 --- a/onnxruntime/test/providers/cpu/generator/constant_of_shape_test.cc +++ b/onnxruntime/test/providers/cpu/generator/constant_of_shape_test.cc @@ -134,27 +134,16 @@ void RunTypedTest(TensorProto::DataType dt, T value) { } TEST(ConstantOfShape, TypeTests) { - // TODO: Unskip when fixed #41968513 - if (DefaultDmlExecutionProvider().get() != nullptr) { - GTEST_SKIP() << "Skipping because of the following error: MLOperatorAuthorImpl.cpp(1876): Unspecified error"; - } - // bool can not be tested due to a shortcoming of // our test infrastructure which makes use of // std::vector which has a specialization for bool // and does not have a continuous buffer implementation // RunTypedTest(TensorProto::BOOL, true); - // The following two types even though supported by the - // operator cause a failure at - // onnx\onnx\checker.cc tensor_checker() where these - // two types are not listed among those that a tensor may - // contain - // RunTypedTest(TensorProto::INT8, int8_t(8)); - // RunTypedTest(TensorProto::INT16, int16_t(16)); - + RunTypedTest(TensorProto::INT8, int8_t(8)); + RunTypedTest(TensorProto::INT16, int16_t(16)); RunTypedTest(TensorProto::FLOAT, 1.f); - RunTypedTest(TensorProto::FLOAT16, MLFloat16(static_cast(5))); + RunTypedTest(TensorProto::FLOAT16, MLFloat16::FromBits(static_cast(5))); RunTypedTest(TensorProto::DOUBLE, 1.0); RunTypedTest(TensorProto::INT32, int32_t(32)); RunTypedTest(TensorProto::INT64, int64_t(64)); diff --git a/onnxruntime/test/providers/cpu/generator/random_test.cc b/onnxruntime/test/providers/cpu/generator/random_test.cc index 85ad297cab814..16582696a81d4 100644 --- a/onnxruntime/test/providers/cpu/generator/random_test.cc +++ b/onnxruntime/test/providers/cpu/generator/random_test.cc @@ -383,7 +383,7 @@ void RunRandomNormalGpuTest(const std::vector dims, const float mean, c auto output_verifier = [&](const std::vector& fetches, const std::string& provider_type) { // Only one output, and mean of output values are near attribute mean. ASSERT_EQ(fetches.size(), 1u); - const auto& output_tensor = FetchTensor(fetches[0]); + const auto& output_tensor = fetches[0].Get(); if (output_dtype == TensorProto_DataType::TensorProto_DataType_FLOAT) { auto output_span = output_tensor.DataAsSpan(); float sum = std::accumulate(output_span.begin(), output_span.end(), 0.f); @@ -476,7 +476,7 @@ void RunRandomUniformGpuTest(const std::vector dims, const float low, c // Only one output. Each value in output tensoer is between low and high. // Mean of output values are near attribute mean of low and high. ASSERT_EQ(fetches.size(), 1u); - const auto& output_tensor = FetchTensor(fetches[0]); + const auto& output_tensor = fetches[0].Get(); if (output_dtype == TensorProto_DataType::TensorProto_DataType_FLOAT) { auto output_span = output_tensor.DataAsSpan(); for (auto value : output_span) { diff --git a/onnxruntime/test/providers/cpu/math/clip_test.cc b/onnxruntime/test/providers/cpu/math/clip_test.cc index dda9bf044781c..efb46e86d04e4 100644 --- a/onnxruntime/test/providers/cpu/math/clip_test.cc +++ b/onnxruntime/test/providers/cpu/math/clip_test.cc @@ -23,7 +23,7 @@ TEST(MathOpTest, Clip_6) { {10.0f, 4.4f, 10.0f, -1.3f, 3.5f, 10.0f, -5.4f, 9.3f, 10.0f}); -#if defined(OPENVINO_CONFIG_MYRIAD) || defined(OPENVINO_CONFIG_VAD_M) || defined(OPENVINO_CONFIG_CPU_FP32) || defined(OPENVINO_CONFIG_CPU_FP16) +#if defined(OPENVINO_CONFIG_CPU_FP32) || defined(OPENVINO_CONFIG_CPU_FP16) test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); #else test.Run(); @@ -43,11 +43,7 @@ TEST(MathOpTest, Clip_Default) { -1.3f, 3.5f, 64.0f, -5.4f, 9.3f, 82.4f}); -#if defined(OPENVINO_CONFIG_MYRIAD) || defined(OPENVINO_CONFIG_VAD_M) - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); -#else test.Run(); -#endif } TEST(MathOpTest, Clip_Default_int8) { diff --git a/onnxruntime/test/providers/cpu/math/cumsum_test.cc b/onnxruntime/test/providers/cpu/math/cumsum_test.cc index cbf2d2fa2b54a..845530c58804f 100644 --- a/onnxruntime/test/providers/cpu/math/cumsum_test.cc +++ b/onnxruntime/test/providers/cpu/math/cumsum_test.cc @@ -24,9 +24,9 @@ TEST(CumSumTest, _1DTest) { TEST(CumSumTest, _1DTestFloat16) { if (DefaultCudaExecutionProvider().get() != nullptr) { OpTester test("CumSum", 14, onnxruntime::kOnnxDomain); - test.AddInput("x", {3}, {MLFloat16(math::floatToHalf(1.0f)), MLFloat16(math::floatToHalf(2.0f)), MLFloat16(math::floatToHalf(3.0f))}); + test.AddInput("x", {3}, {MLFloat16(1.0f), MLFloat16(2.0f), MLFloat16(3.0f)}); test.AddInput("axis", {}, {0}); - test.AddOutput("y", {3}, {MLFloat16(math::floatToHalf(1.0f)), MLFloat16(math::floatToHalf(3.0f)), MLFloat16(math::floatToHalf(6.0f))}); + test.AddOutput("y", {3}, {MLFloat16(1.0f), MLFloat16(3.0f), MLFloat16(6.0f)}); test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kCpuExecutionProvider}); } } diff --git a/onnxruntime/test/providers/cpu/math/einsum_test.cc b/onnxruntime/test/providers/cpu/math/einsum_test.cc index 595e9357480aa..05b936a41e3c1 100644 --- a/onnxruntime/test/providers/cpu/math/einsum_test.cc +++ b/onnxruntime/test/providers/cpu/math/einsum_test.cc @@ -22,7 +22,7 @@ TEST(Einsum, ExplicitEinsumAsIdentity_1D_input) { test.AddAttribute("equation", "i->i"); test.AddInput("x", {5}, {0.9f, 2.5f, 2.3f, 1.5f, -4.5f}); test.AddOutput("y", {5}, {0.9f, 2.5f, 2.3f, 1.5f, -4.5f}); - test.Run(); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); } // Implicit @@ -31,7 +31,7 @@ TEST(Einsum, ImplicitEinsumAsIdentity_1D_input) { test.AddAttribute("equation", "i"); test.AddInput("x", {5}, {0.9f, 2.5f, 2.3f, 1.5f, -4.5f}); test.AddOutput("y", {5}, {0.9f, 2.5f, 2.3f, 1.5f, -4.5f}); - test.Run(); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); } // Theme: Transpose/Permutation @@ -435,7 +435,7 @@ TEST(Einsum, ExplicitEinsumAsBatchedDiagonalOp_1) { TEST(Einsum, ImplicitEinsumAsDiagonalOp) { // TODO: Unskip when fixed #41968513 if (DefaultDmlExecutionProvider().get() != nullptr) { - GTEST_SKIP() << "Skipping because of the following error: provider_test_utils.cc(284): error: The difference between expected[i] and output[i] is 5, which exceeds threshold"; + GTEST_SKIP() << "Skipping because of the following error: The difference between expected[i] and output[i] is 5, which exceeds threshold"; } OpTester test("Einsum", 12, onnxruntime::kOnnxDomain); @@ -448,7 +448,7 @@ TEST(Einsum, ImplicitEinsumAsDiagonalOp) { TEST(Einsum, ImplicitEinsumAsDiagonalOp_1) { // TODO: Unskip when fixed #41968513 if (DefaultDmlExecutionProvider().get() != nullptr) { - GTEST_SKIP() << "Skipping because of the following error: provider_test_utils.cc(284): error: The difference between expected[i] and output[i] is 15, which exceeds threshold"; + GTEST_SKIP() << "Skipping because of the following error: error: The difference between expected[i] and output[i] is 15, which exceeds threshold"; } OpTester test("Einsum", 12, onnxruntime::kOnnxDomain); 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 4a17b95afa00f..257ce977700a6 100644 --- a/onnxruntime/test/providers/cpu/math/element_wise_ops_test.cc +++ b/onnxruntime/test/providers/cpu/math/element_wise_ops_test.cc @@ -15,7 +15,7 @@ namespace test { std::vector MakeMLFloat16(const std::initializer_list& input) { std::vector output; std::transform(input.begin(), input.end(), std::back_inserter(output), - [](float fl) { return MLFloat16(math::floatToHalf(fl)); }); + [](float fl) { return MLFloat16(fl); }); return output; } @@ -153,7 +153,7 @@ TEST(MathOpTest, Add_float) { test.AddInput("B", dims, rhs_values); test.AddOutput("C", dims, out_values); -#if defined(OPENVINO_CONFIG_MYRIAD) || defined(OPENVINO_CONFIG_GPU_GP16) || defined(OPENVINO_CONFIG_VAD_M) +#if defined(OPENVINO_CONFIG_GPU_GP16) test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); // OpenVINO: Disabled due to accuracy mismatch for FP16 #else @@ -216,8 +216,7 @@ TEST(MathOpTest, Add_Broadcast_MultidirectionalAB) { test.AddInput("A", {3, 1}, lhs_values); test.AddInput("B", {3}, rhs_values); test.AddOutput("C", {3, 3}, out_values); -#if defined(OPENVINO_CONFIG_GPU_FP32) || defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_MYRIAD) || \ - defined(OPENVINO_CONFIG_VAD_M) +#if defined(OPENVINO_CONFIG_GPU_FP32) || defined(OPENVINO_CONFIG_GPU_FP16) test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kOpenVINOExecutionProvider}); // OpenVINO: disabled temporarily due to accurarcy issues @@ -284,11 +283,7 @@ TEST(MathOpTest, Add_Broadcast_0x1) { test.AddInput("A", {}, {10.0f}, scalar_as_initializer); test.AddInput("B", {1}, {2.0f}); test.AddOutput("C", {1}, {12.0f}); -#if defined(OPENVINO_CONFIG_MYRIAD) - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); // OpenVINO: disabled temporarily on MYRIADX due to a bug -#else test.Run(OpTester::ExpectResult::kExpectSuccess, ""); -#endif }; run(false); @@ -309,11 +304,7 @@ TEST(MathOpTest, Add_Broadcast_1x0) { test.AddInput("A", {1}, {10.0f}); test.AddInput("B", {}, {2.0f}, scalar_as_initializer); test.AddOutput("C", {1}, {12.0f}); -#if defined(OPENVINO_CONFIG_MYRIAD) - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); // OpenVINO: disabled temporarily on MYRIADX due to a bug -#else test.Run(OpTester::ExpectResult::kExpectSuccess, ""); -#endif }; run(false); @@ -429,7 +420,7 @@ TEST(MathOpTest, Add_Broadcast_2x1x1_3x4) { std::unordered_set excluded_providers; excluded_providers.insert(kTensorrtExecutionProvider); -#if defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_GPU_FP32) || defined(OPENVINO_CONFIG_MYRIAD) || defined(OPENVINO_CONFIG_VAD_M) +#if defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_GPU_FP32) // OpenVINO GPU: Disabled temporarily due to accuarcy issues // OpenVINO VPU: Disabled due to software limitation excluded_providers.insert(kOpenVINOExecutionProvider); @@ -515,12 +506,7 @@ TEST(MathOpTest, Sub) { test.AddInput("A", dims, lhs_values); test.AddInput("B", dims, rhs_values); test.AddOutput("C", dims, out_values); -#if defined(OPENVINO_CONFIG_MYRIAD) || defined(OPENVINO_CONFIG_VAD_M) - test.Run(OpTester::ExpectResult::kExpectSuccess, "", - {kOpenVINOExecutionProvider}); // OpenVINO EP: Disabled due to accuracy mismatch for FP16 -#else test.Run(); -#endif #if defined(USE_CUDA) || defined(USE_ROCM) TestFloat16("Sub", dims, lhs_values, dims, rhs_values, dims, out_values); @@ -577,12 +563,7 @@ TEST(MathOpTest, Mul) { test.AddInput("B", dims, rhs_values); test.AddOutput("C", dims, out_values); -#if defined(OPENVINO_CONFIG_MYRIAD) || defined(OPENVINO_CONFIG_VAD_M) - test.Run(OpTester::ExpectResult::kExpectSuccess, "", - {kOpenVINOExecutionProvider}); // OpenVINO: Disabled due to accuracy issues for MYRIAD FP16 -#else test.Run(); -#endif #if defined(USE_CUDA) || defined(USE_ROCM) TestFloat16("Mul", dims, lhs_values, dims, rhs_values, dims, out_values); @@ -620,12 +601,7 @@ TEST(MathOpTest, Div) { test.AddInput("A", dims, lhs_values); test.AddInput("B", dims, rhs_values); test.AddOutput("C", dims, out_values); -#if defined(OPENVINO_CONFIG_MYRIAD) || defined(OPENVINO_CONFIG_VAD_M) - test.Run(OpTester::ExpectResult::kExpectSuccess, "", - {kOpenVINOExecutionProvider}); // OpenVINO EP: Hardware limitation -#else test.Run(); -#endif #if defined(USE_CUDA) || defined(USE_ROCM) TestFloat16("Div", dims, lhs_values, dims, rhs_values, dims, out_values); @@ -694,12 +670,8 @@ TEST(MathOpTest, Neg_int8) { test.AddInput("X", dims, {1, -2, 0, -10}); test.AddOutput("Y", dims, {-1, 2, 0, 10}); -// OpenVINO EP: Disabled temporarily -#if defined(OPENVINO_CONFIG_MYRIAD) || defined(OPENVINO_CONFIG_VAD_M) - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kOpenVINOExecutionProvider}); // TensorRT: INT8 is not supported -#else + // OpenVINO EP: Disabled temporarily test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); // TensorRT: INT8 is not supported -#endif } TEST(MathOpTest, Neg_int32) { @@ -751,7 +723,7 @@ TEST(MathOpTest, Ceil) { test.AddOutput("Y", dims, {-1.0f, 1.0f, 0.0f, 11.0f}); -#if defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_GPU_FP32) || defined(OPENVINO_CONFIG_MYRIAD) || defined(OPENVINO_CONFIG_VAD_M) +#if defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_GPU_FP32) // OpenVINO: Disabled due to software limitation for GPU and VPU Plugins. // This test runs fine on CPU Plugin test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); @@ -769,7 +741,7 @@ TEST(MathOpTest, Ceil_double) { test.AddOutput("Y", dims, {-1.0, 1.0, 0.0, 11.0}); -#if defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_GPU_FP32) || defined(OPENVINO_CONFIG_MYRIAD) || defined(OPENVINO_CONFIG_VAD_M) +#if defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_GPU_FP32) // OpenVINO: Disabled due to software limitation for GPU and VPU Plugins. // This test runs fine on CPU Plugin test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); @@ -1210,7 +1182,7 @@ TEST(MathOpTest, Sum_6) { -6.0f, 6.6f, 28.0f, -1.0f, 0.06f, 0.25f}); -#if defined(OPENVINO_CONFIG_MYRIAD) || defined(OPENVINO_CONFIG_GPU_FP16) +#if defined(OPENVINO_CONFIG_GPU_FP16) test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); // OpenVINO EP: Disabled due to accuracy mismatch for FP16 #else test.Run(); @@ -1237,7 +1209,7 @@ TEST(MathOpTest, Sum_6_double) { -6.0, 6.6, 28.0, -1.0, 0.06, 0.25}); -#if defined(OPENVINO_CONFIG_MYRIAD) || defined(OPENVINO_CONFIG_GPU_FP16) +#if defined(OPENVINO_CONFIG_GPU_FP16) test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); // OpenVINO EP: Disabled due to accuracy mismatch for FP16 #else test.Run(); @@ -1261,7 +1233,7 @@ TEST(MathOpTest, Sum_8_Test1) { 311.0f, 312.0f, 313.0f, 321.0f, 322.0f, 323.0f, 331.0f, 332.0f, 333.0f}); -#if defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_GPU_FP32) || defined(OPENVINO_CONFIG_MYRIAD) || defined(OPENVINO_CONFIG_VAD_M) +#if defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_GPU_FP32) // OpenVINO: Disabled due to software limitation for GPU and VPU Plugins. // This test runs fine on CPU Plugin test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kOpenVINOExecutionProvider}); @@ -1287,7 +1259,7 @@ TEST(MathOpTest, Sum_8_Test1_double) { 311.0, 312.0, 313.0, 321.0, 322.0, 323.0, 331.0, 332.0, 333.0}); -#if defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_GPU_FP32) || defined(OPENVINO_CONFIG_MYRIAD) || defined(OPENVINO_CONFIG_VAD_M) +#if defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_GPU_FP32) // OpenVINO: Disabled due to software limitation for GPU and VPU Plugins. // This test runs fine on CPU Plugin test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kOpenVINOExecutionProvider}); @@ -1321,7 +1293,7 @@ TEST(MathOpTest, Sum_8_Test2) { 3.3f, 4.4f, -94.7f, 59.6f, 64.01f, -8.0f}); -#if defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_GPU_FP32) || defined(OPENVINO_CONFIG_MYRIAD) || defined(OPENVINO_CONFIG_VAD_M) +#if defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_GPU_FP32) // OpenVINO: Disabled temporarily due to accuracy issues test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kOpenVINOExecutionProvider}); // TensorRT: Input batch size is inconsistent #else @@ -1355,7 +1327,7 @@ TEST(MathOpTest, Sum_8_Test2_double) { 3.3, 4.4, -94.7, 59.6, 64.01, -8.0}); -#if defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_GPU_FP32) || defined(OPENVINO_CONFIG_MYRIAD) || defined(OPENVINO_CONFIG_VAD_M) +#if defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_GPU_FP32) // OpenVINO: Disabled temporarily due to accuracy issues test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kOpenVINOExecutionProvider}); // TensorRT: Input batch size is inconsistent #else @@ -1369,7 +1341,7 @@ static void TestSumMultipleInputsNoBroadcasting(size_t num_inputs, const TensorS OpTester test{"Sum", 8}; - const auto dims = GetShapeVector(shape); + const auto dims = shape.AsShapeVector(); const std::vector input_data(shape.Size(), 1); for (size_t i = 0; i < num_inputs; ++i) { @@ -1466,11 +1438,7 @@ TEST(MathOpTest, Min_6) { {1.0f, 0.0f, 1.0f, -3.0f, 1.1f, -100.0f, -5.4f, 0.01f, -10000.0f}); -#if defined(OPENVINO_CONFIG_MYRIAD) || defined(OPENVINO_CONFIG_VAD_M) - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); // OpenVINO: Disabled due to accuracy mismatch -#else test.Run(); -#endif } TEST(MathOpTest, Min_8) { @@ -1492,11 +1460,7 @@ TEST(MathOpTest, Min_8) { {1.0f, 0.0f, 1.0f, -3.0f, 1.1f, -100.0f, -5.4f, 0.01f, -10000.0f}); -#if defined(OPENVINO_CONFIG_MYRIAD) || defined(OPENVINO_CONFIG_VAD_M) - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); // OpenVINO: Disabled due to accuracy mismatch -#else test.Run(); -#endif } TEST(MathOpTest, Min_12_Float) { @@ -1673,11 +1637,7 @@ TEST(MathOpTest, Max_6) { {1.0f, 0.0f, 3.0f, -1.0f, 3.3f, 64.0f, 5.4f, 0.03f, 10000.0f}); -#if defined(OPENVINO_CONFIG_MYRIAD) || defined(OPENVINO_CONFIG_VAD_M) - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); // OpenVINO: Disabled due to accuracy mismatch -#else test.Run(); -#endif } TEST(MathOpTest, Max_8_Float) { @@ -2013,7 +1973,7 @@ TEST(MathOpTest, Less_broadcastBA) { test.Run(); } -TEST(MathOpTest, Less_multidiretional_broadcastAB) { +TEST(MathOpTest, Less_multidirectional_broadcastAB) { OpTester test("Less", 9); test.AddInput("A", {4, 1}, {10, 11, 12, 13}); test.AddInput("B", {2}, {15, 7}); @@ -2021,7 +1981,7 @@ TEST(MathOpTest, Less_multidiretional_broadcastAB) { test.Run(); } -TEST(MathOpTest, Less_multidiretional_broadcastBA) { +TEST(MathOpTest, Less_multidirectional_broadcastBA) { OpTester test("Less", 9); test.AddInput("A", {2}, {15, 7}); test.AddInput("B", {4, 1}, {10, 11, 12, 13}); @@ -2083,7 +2043,7 @@ TEST(MathOpTest, LessOrEqual_broadcastBA) { {kTensorrtExecutionProvider, kNnapiExecutionProvider, kOpenVINOExecutionProvider}); } -TEST(MathOpTest, LessOrEqual_multidiretional_broadcastAB) { +TEST(MathOpTest, LessOrEqual_multidirectional_broadcastAB) { OpTester test("LessOrEqual", 12); test.AddInput("A", {4, 1}, {10, 11, 12, 13}); test.AddInput("B", {2}, {15, 7}); @@ -2092,7 +2052,7 @@ TEST(MathOpTest, LessOrEqual_multidiretional_broadcastAB) { {kTensorrtExecutionProvider, kNnapiExecutionProvider, kOpenVINOExecutionProvider}); } -TEST(MathOpTest, LessOrEqual_multidiretional_broadcastBA) { +TEST(MathOpTest, LessOrEqual_multidirectional_broadcastBA) { OpTester test("LessOrEqual", 12); test.AddInput("A", {2}, {15, 7}); test.AddInput("B", {4, 1}, {10, 11, 12, 13}); @@ -2222,7 +2182,7 @@ TEST(MathOpTest, LessOrEqual_bfloat16_broadcastBA) { {kTensorrtExecutionProvider, kNnapiExecutionProvider, kOpenVINOExecutionProvider}, nullptr, &execution_providers); } -TEST(MathOpTest, LessOrEqual_multidiretional_bfloat16_broadcastAB) { +TEST(MathOpTest, LessOrEqual_multidirectional_bfloat16_broadcastAB) { #ifdef USE_DNNL #ifdef DNNL_GPU_RUNTIME LOGS_DEFAULT(WARNING) << "Hardware does NOT support BF16"; @@ -2246,7 +2206,7 @@ TEST(MathOpTest, LessOrEqual_multidiretional_bfloat16_broadcastAB) { {kTensorrtExecutionProvider, kNnapiExecutionProvider, kOpenVINOExecutionProvider}, nullptr, &execution_providers); } -TEST(MathOpTest, LessOrEqual_multidiretional_bfloat16_broadcastBA) { +TEST(MathOpTest, LessOrEqual_multidirectional_bfloat16_broadcastBA) { #ifdef USE_DNNL #ifdef DNNL_GPU_RUNTIME LOGS_DEFAULT(WARNING) << "Hardware does NOT support BF16"; @@ -2357,7 +2317,7 @@ TEST(MathOpTest, Greater_broadcastBA) { test.Run(); } -TEST(MathOpTest, Greater_multidiretional_broadcastAB) { +TEST(MathOpTest, Greater_multidirectional_broadcastAB) { OpTester test("Greater", 9); test.AddInput("A", {4, 1}, {10, 11, 12, 13}); test.AddInput("B", {2}, {15, 7}); @@ -2365,7 +2325,7 @@ TEST(MathOpTest, Greater_multidiretional_broadcastAB) { test.Run(); } -TEST(MathOpTest, Greater_multidiretional_broadcastBA) { +TEST(MathOpTest, Greater_multidirectional_broadcastBA) { OpTester test("Greater", 9); test.AddInput("A", {2}, {15, 7}); test.AddInput("B", {4, 1}, {10, 11, 12, 13}); @@ -2458,7 +2418,7 @@ TEST(MathOpTest, GreaterOrEqual_broadcastBA) { {kTensorrtExecutionProvider, kNnapiExecutionProvider, kOpenVINOExecutionProvider}); } -TEST(MathOpTest, GreaterOrEqual_multidiretional_broadcastAB) { +TEST(MathOpTest, GreaterOrEqual_multidirectional_broadcastAB) { OpTester test("GreaterOrEqual", 12); test.AddInput("A", {4, 1}, {10, 11, 12, 13}); test.AddInput("B", {2}, {15, 7}); @@ -2467,7 +2427,7 @@ TEST(MathOpTest, GreaterOrEqual_multidiretional_broadcastAB) { {kTensorrtExecutionProvider, kNnapiExecutionProvider, kOpenVINOExecutionProvider}); } -TEST(MathOpTest, GreaterOrEqual_multidiretional_broadcastBA) { +TEST(MathOpTest, GreaterOrEqual_multidirectional_broadcastBA) { OpTester test("GreaterOrEqual", 12); test.AddInput("A", {2}, {15, 7}); test.AddInput("B", {4, 1}, {10, 11, 12, 13}); @@ -2525,11 +2485,7 @@ TEST(MathOpTest, Equal_int64) { test.AddInput("A", dims, {1, 0, -1, -1}); test.AddInput("B", dims, {1, 1, 2, -1}); test.AddOutput("C", dims, {true, false, false, true}); -#if defined(OPENVINO_CONFIG_MYRIAD) || defined(OPENVINO_CONFIG_VAD_M) - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); -#else test.Run(); -#endif } TEST(MathOpTest, Equal_float) { @@ -2541,6 +2497,15 @@ TEST(MathOpTest, Equal_float) { test.Run(); } +TEST(MathOpTest, Equal_string) { + OpTester test("Equal", 19); + std::vector dims{4}; + test.AddInput("A", dims, {"1.0f", "0.0f", "-1.0f", "-1.0f"}); + test.AddInput("B", dims, {"1.0f", "1.0f", "2.0f", "-1.0f"}); + test.AddOutput("C", dims, {true, false, false, true}); + test.Run(); +} + #if defined(USE_DNNL) TEST(MathOpTest, Equal_bfloat16) { #ifdef USE_DNNL @@ -2583,7 +2548,7 @@ TEST(MathOpTest, Equal_broadcastBA) { test.Run(); } -TEST(MathOpTest, Equal_multidiretional_broadcastAB) { +TEST(MathOpTest, Equal_multidirectional_broadcastAB) { OpTester test("Equal"); test.AddInput("A", {4, 1}, {1, 0, -1, -1}); test.AddInput("B", {2}, {1, 1}); @@ -2591,7 +2556,7 @@ TEST(MathOpTest, Equal_multidiretional_broadcastAB) { test.Run(); } -TEST(MathOpTest, Equal_multidiretional_broadcastBA) { +TEST(MathOpTest, Equal_multidirectional_broadcastBA) { OpTester test("Equal"); test.AddInput("A", {2}, {1, 1}); test.AddInput("B", {4, 1}, {1, 0, -1, -1}); @@ -2599,7 +2564,7 @@ TEST(MathOpTest, Equal_multidiretional_broadcastBA) { test.Run(); } -TEST(MathOpTest, Equal_multidiretional_broadcastAB_bool) { +TEST(MathOpTest, Equal_multidirectional_broadcastAB_bool) { OpTester test("Equal"); test.AddInput("A", {4, 1}, {true, false, false, false}); test.AddInput("B", {2}, {true, true}); @@ -2626,12 +2591,8 @@ TEST(MathOpTest, Mean_6) { {1.0f, 0.0f, 2.0f, -2.0f, 2.2f, 10.0f, -3.0f, 0.02f, -4.0f}); -// OpenVINO: Disabled due to accuracy mismatch -#if defined(OPENVINO_CONFIG_MYRIAD) || defined(OPENVINO_CONFIG_VAD_M) - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); -#else + // OpenVINO: Disabled due to accuracy mismatch test.Run(); -#endif } TEST(MathOpTest, Mean_8) { @@ -2647,12 +2608,8 @@ TEST(MathOpTest, Mean_8) { {12.0f / 3.0f, 22.0f / 3.0f, 32.0f / 3.0f, 43.0f / 3.0f, 53.0f / 3.0f, 63.0f / 3.0f, 74.0f / 3.0f, 84.0f / 3.0f, 94.0f / 3.0f}); -// OpenVINO: Disabled due to accuracy mismatch -#if defined(OPENVINO_CONFIG_MYRIAD) || defined(OPENVINO_CONFIG_VAD_M) - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kOpenVINOExecutionProvider}); // TensorRT: Input batch size is inconsistent -#else + // OpenVINO: Disabled due to accuracy mismatch test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); // TensorRT: Input batch size is inconsistent -#endif } #ifdef _LIBCPP_VERSION @@ -2695,8 +2652,8 @@ void TrigFloat16Test(OpTester& test, std::initializer_list input) { std::vector float16_input; std::vector float16_output; for (auto v : input) { - float16_input.push_back(MLFloat16(math::floatToHalf(v))); - float16_output.push_back(MLFloat16(math::floatToHalf(op(v)))); + float16_input.push_back(MLFloat16(v)); + float16_output.push_back(MLFloat16(op(v))); } test.AddInput("X", dims, float16_input); @@ -3128,5 +3085,267 @@ TEST(BitShiftOpTest, BroadcastXRight_Uint8) { test.Run(); } +TEST(MathOpTest, BitwiseAnd) { + OpTester test("BitwiseAnd", 18); + std::vector dims{3}; + test.AddInput("A", dims, {-1, -2, 3}); + test.AddInput("B", dims, {1, 0, 3}); + test.AddOutput("C", dims, {1, 0, 3}); + test.Run(); +} + +TEST(MathOpTest, BitwiseAnd_int64) { + OpTester test("BitwiseAnd", 18); + std::vector dims{3}; + test.AddInput("A", dims, {-1, -2, 3}); + test.AddInput("B", dims, {1, 0, 3}); + test.AddOutput("C", dims, {1, 0, 3}); + test.Run(); +} + +TEST(MathOpTest, BitwiseAnd_int8) { + OpTester test("BitwiseAnd", 18); + std::vector dims{3}; + test.AddInput("A", dims, {-1, -2, 3}); + test.AddInput("B", dims, {1, 0, 3}); + test.AddOutput("C", dims, {1, 0, 3}); + test.Run(); +} + +TEST(MathOpTest, BitwiseAnd_uint8) { + OpTester test("BitwiseAnd", 18); + std::vector dims{4}; + test.AddInput("A", dims, {1, 4, 5, 3}); + test.AddInput("B", dims, {1, 2, 2, 1}); + test.AddOutput("C", dims, {1, 0, 0, 1}); + test.Run(); +} + +TEST(MathOpTest, BitwiseAnd_uint64) { + OpTester test("BitwiseAnd", 18); + std::vector dims{4}; + test.AddInput("A", dims, {10, 11, 12, 13}); + test.AddInput("B", dims, {15, 7, 12, 9}); + test.AddOutput("C", dims, {10, 3, 12, 9}); + test.Run(); +} + +TEST(MathOpTest, BitwiseAnd_broadcastAB) { + OpTester test("BitwiseAnd", 18); + test.AddInput("A", {4, 2}, {10, 11, 12, 13, 14, 15, 16, 17}); + test.AddInput("B", {2}, {15, 7}); + test.AddOutput("C", {4, 2}, {10, 3, 12, 5, 14, 7, 0, 1}); + test.Run(); +} + +TEST(MathOpTest, BitwiseAnd_broadcastBA) { + OpTester test("BitwiseAnd", 18); + test.AddInput("A", {2}, {15, 7}); + test.AddInput("B", {4, 2}, {10, 11, 12, 13, 14, 15, 16, 17}); + test.AddOutput("C", {4, 2}, {10, 3, 12, 5, 14, 7, 0, 1}); + test.Run(); +} + +TEST(MathOpTest, BitwiseAnd_multidirectional_broadcastAB) { + OpTester test("BitwiseAnd", 18); + test.AddInput("A", {4, 1}, {10, 11, 12, 13}); + test.AddInput("B", {2}, {15, 7}); + test.AddOutput("C", {4, 2}, {10, 2, 11, 3, 12, 4, 13, 5}); + test.Run(); +} + +TEST(MathOpTest, BitwiseAnd_multidirectional_broadcastBA) { + OpTester test("BitwiseAnd", 18); + test.AddInput("A", {2}, {15, 7}); + test.AddInput("B", {4, 1}, {10, 11, 12, 13}); + test.AddOutput("C", {4, 2}, {10, 2, 11, 3, 12, 4, 13, 5}); + test.Run(); +} + +TEST(MathOpTest, BitwiseOr) { + OpTester test("BitwiseOr", 18); + std::vector dims{3}; + test.AddInput("A", dims, {-1, -2, 3}); + test.AddInput("B", dims, {1, 0, 4}); + test.AddOutput("C", dims, {-1, -2, 7}); + test.Run(); +} + +TEST(MathOpTest, BitwiseOr_int64) { + OpTester test("BitwiseOr", 18); + std::vector dims{3}; + test.AddInput("A", dims, {-1, -2, 3}); + test.AddInput("B", dims, {1, 0, 4}); + test.AddOutput("C", dims, {-1, -2, 7}); + test.Run(); +} + +TEST(MathOpTest, BitwiseOr_int8) { + OpTester test("BitwiseOr", 18); + std::vector dims{3}; + test.AddInput("A", dims, {-1, -2, 3}); + test.AddInput("B", dims, {1, 0, 4}); + test.AddOutput("C", dims, {-1, -2, 7}); + test.Run(); +} + +TEST(MathOpTest, BitwiseOr_uint8) { + OpTester test("BitwiseOr", 18); + std::vector dims{4}; + test.AddInput("A", dims, {1, 4, 5, 3}); + test.AddInput("B", dims, {1, 2, 2, 1}); + test.AddOutput("C", dims, {1, 6, 7, 3}); + test.Run(); +} + +TEST(MathOpTest, BitwiseOr_uint64) { + OpTester test("BitwiseOr", 18); + std::vector dims{4}; + test.AddInput("A", dims, {10, 11, 12, 13}); + test.AddInput("B", dims, {15, 7, 12, 9}); + test.AddOutput("C", dims, {15, 15, 12, 13}); + test.Run(); +} + +TEST(MathOpTest, BitwiseOr_broadcastAB) { + OpTester test("BitwiseOr", 18); + test.AddInput("A", {4, 2}, {10, 11, 12, 13, 14, 15, 16, 17}); + test.AddInput("B", {2}, {15, 7}); + test.AddOutput("C", {4, 2}, {15, 15, 15, 15, 15, 15, 31, 23}); + test.Run(); +} + +TEST(MathOpTest, BitwiseOr_broadcastBA) { + OpTester test("BitwiseOr", 18); + test.AddInput("A", {2}, {15, 7}); + test.AddInput("B", {4, 2}, {10, 11, 12, 13, 14, 15, 16, 17}); + test.AddOutput("C", {4, 2}, {15, 15, 15, 15, 15, 15, 31, 23}); + test.Run(); +} + +TEST(MathOpTest, BitwiseOr_multidirectional_broadcastAB) { + OpTester test("BitwiseOr", 18); + test.AddInput("A", {4, 1}, {10, 11, 12, 13}); + test.AddInput("B", {2}, {15, 7}); + test.AddOutput("C", {4, 2}, {15, 15, 15, 15, 15, 15, 15, 15}); + test.Run(); +} + +TEST(MathOpTest, BitwiseOr_multidirectional_broadcastBA) { + OpTester test("BitwiseOr", 18); + test.AddInput("A", {2}, {15, 7}); + test.AddInput("B", {4, 1}, {10, 11, 12, 13}); + test.AddOutput("C", {4, 2}, {15, 15, 15, 15, 15, 15, 15, 15}); + test.Run(); +} + +TEST(MathOpTest, BitwiseXor) { + OpTester test("BitwiseXor", 18); + std::vector dims{3}; + test.AddInput("A", dims, {-1, -2, 3}); + test.AddInput("B", dims, {1, 0, 4}); + test.AddOutput("C", dims, {-2, -2, 7}); + test.Run(); +} + +TEST(MathOpTest, BitwiseXor_int64) { + OpTester test("BitwiseXor", 18); + std::vector dims{3}; + test.AddInput("A", dims, {-1, -2, 3}); + test.AddInput("B", dims, {1, 0, 4}); + test.AddOutput("C", dims, {-2, -2, 7}); + test.Run(); +} + +TEST(MathOpTest, BitwiseXor_int8) { + OpTester test("BitwiseXor", 18); + std::vector dims{3}; + test.AddInput("A", dims, {-1, -2, 3}); + test.AddInput("B", dims, {1, 0, 4}); + test.AddOutput("C", dims, {-2, -2, 7}); + test.Run(); +} + +TEST(MathOpTest, BitwiseXor_uint8) { + OpTester test("BitwiseXor", 18); + std::vector dims{4}; + test.AddInput("A", dims, {1, 4, 5, 3}); + test.AddInput("B", dims, {1, 2, 2, 1}); + test.AddOutput("C", dims, {0, 6, 7, 2}); + test.Run(); +} + +TEST(MathOpTest, BitwiseXor_uint64) { + OpTester test("BitwiseXor", 18); + std::vector dims{4}; + test.AddInput("A", dims, {10, 11, 12, 13}); + test.AddInput("B", dims, {15, 7, 12, 9}); + test.AddOutput("C", dims, {5, 12, 0, 4}); + test.Run(); +} + +TEST(MathOpTest, BitwiseXor_broadcastAB) { + OpTester test("BitwiseXor", 18); + test.AddInput("A", {4, 2}, {10, 11, 12, 13, 14, 15, 16, 17}); + test.AddInput("B", {2}, {15, 7}); + test.AddOutput("C", {4, 2}, {5, 12, 3, 10, 1, 8, 31, 22}); + test.Run(); +} + +TEST(MathOpTest, BitwiseXor_broadcastBA) { + OpTester test("BitwiseXor", 18); + test.AddInput("A", {2}, {15, 7}); + test.AddInput("B", {4, 2}, {10, 11, 12, 13, 14, 15, 16, 17}); + test.AddOutput("C", {4, 2}, {5, 12, 3, 10, 1, 8, 31, 22}); + test.Run(); +} + +TEST(MathOpTest, BitwiseXor_multidirectional_broadcastAB) { + OpTester test("BitwiseXor", 18); + test.AddInput("A", {4, 1}, {10, 11, 12, 13}); + test.AddInput("B", {2}, {15, 7}); + test.AddOutput("C", {4, 2}, {5, 13, 4, 12, 3, 11, 2, 10}); + test.Run(); +} + +TEST(MathOpTest, BitwiseXor_multidirectional_broadcastBA) { + OpTester test("BitwiseXor", 18); + test.AddInput("A", {2}, {15, 7}); + test.AddInput("B", {4, 1}, {10, 11, 12, 13}); + test.AddOutput("C", {4, 2}, {5, 13, 4, 12, 3, 11, 2, 10}); + test.Run(); +} + +TEST(MathOpTest, BitwiseNot) { + OpTester test("BitwiseNot", 18); + std::vector dims{3}; + test.AddInput("X", dims, {-1, -2, 3}); + test.AddOutput("Y", dims, {0, 1, -4}); + test.Run(); +} + +TEST(MathOpTest, BitwiseNot_int64) { + OpTester test("BitwiseNot", 18); + std::vector dims{3}; + test.AddInput("X", dims, {-1, -2, 3}); + test.AddOutput("Y", dims, {0, 1, -4}); + test.Run(); +} + +TEST(MathOpTest, BitwiseNot_int8) { + OpTester test("BitwiseNot", 18); + std::vector dims{3}; + test.AddInput("X", dims, {-1, -2, 3}); + test.AddOutput("Y", dims, {0, 1, -4}); + test.Run(); +} + +TEST(MathOpTest, BitwiseNot_uint8) { + OpTester test("BitwiseNot", 18); + std::vector dims{4}; + test.AddInput("X", dims, {1, 4, 5, 3}); + test.AddOutput("Y", dims, {254, 251, 250, 252}); + test.Run(); +} } // namespace test } // namespace onnxruntime diff --git a/onnxruntime/test/providers/cpu/math/gemm_test.cc b/onnxruntime/test/providers/cpu/math/gemm_test.cc index 068fc2a505254..36ab867f1b0e1 100644 --- a/onnxruntime/test/providers/cpu/math/gemm_test.cc +++ b/onnxruntime/test/providers/cpu/math/gemm_test.cc @@ -2,6 +2,7 @@ // Licensed under the MIT License. #include "gtest/gtest.h" +#include "core/mlas/inc/mlas.h" #include "core/framework/run_options.h" #include "test/common/cuda_op_test_utils.h" #include "test/providers/provider_test_utils.h" @@ -24,45 +25,7 @@ const constexpr auto run_with_tunable_op = &run_options; } // namespace -template -void TestGemmNoTrans() { - auto run_test = [](bool b_is_initializer, bool c_is_initializer = false) { - OpTester test("Gemm"); - - test.AddAttribute("transA", (int64_t)0); - test.AddAttribute("transB", (int64_t)0); - test.AddAttribute("alpha", 1.0f); - test.AddAttribute("beta", 1.0f); - - test.AddInput("A", {2, 4}, - {1.0f, 2.0f, 3.0f, 4.0f, - -1.0f, -2.0f, -3.0f, -4.0f}); - test.AddInput("B", {4, 3}, std::vector(12, 1.0f), b_is_initializer); - test.AddInput("C", {2, 3}, std::vector(6, 1.0f), c_is_initializer); - test.AddOutput("Y", {2, 3}, - {11.0f, 11.0f, 11.0f, - -9.0f, -9.0f, -9.0f}); - test.Config(run_with_tunable_op) - .RunWithConfig(); - }; - - run_test(false, false); - // NNAPI EP requires weight to be an initializer - run_test(true, false); - // CoreML EP requires weight and bias both to be initializers - run_test(true, true); -} - -TEST(GemmOpTest, GemmNoTrans_float) { - TestGemmNoTrans(); -} - -TEST(GemmOpTest, GemmNoTrans_double) { - TestGemmNoTrans(); -} - // Only CUDA and ROCM kernel has float 16 support -#if defined(USE_CUDA) || defined(USE_ROCM) TEST(GemmOpTest, GemmNoTrans_f16) { #ifdef USE_CUDA int min_cuda_architecture = 530; @@ -71,7 +34,7 @@ TEST(GemmOpTest, GemmNoTrans_f16) { return; } #endif - OpTester test("Gemm"); + OpTester test("Gemm", 13); test.AddAttribute("transA", (int64_t)0); test.AddAttribute("transB", (int64_t)0); @@ -102,7 +65,6 @@ TEST(GemmOpTest, GemmNoTrans_f16) { .Config(run_with_tunable_op) .RunWithConfig(); } -#endif #if defined(USE_CUDA) || defined(USE_ROCM) || defined(USE_DNNL) TEST(GemmOpTest, GemmNoTrans_bfloat16) { @@ -147,270 +109,6 @@ TEST(GemmOpTest, GemmNoTrans_bfloat16) { } #endif // USE_CUDA USE_RCOM USE_DNNL -template -void TestGemmBroadcast() { - auto run_test = [](bool b_is_initializer, bool c_is_initializer) { - OpTester test("Gemm"); - - test.AddAttribute("transA", (int64_t)0); - test.AddAttribute("transB", (int64_t)0); - test.AddAttribute("alpha", 1.0f); - test.AddAttribute("beta", 1.0f); - - test.AddInput("A", {2, 4}, - {1.0f, 2.0f, 3.0f, 4.0f, - -1.0f, -2.0f, -3.0f, -4.0f}); - test.AddInput("B", {4, 3}, std::vector(12, 1.0f), b_is_initializer); - test.AddInput("C", {3}, std::vector{1.0f, 2.0f, 3.0f}, c_is_initializer); - test.AddOutput("Y", {2, 3}, - {11.0f, 12.0f, 13.0f, - -9.0f, -8.0f, -7.0f}); -#if defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_GPU_FP32) - test.ConfigExcludeEps({kOpenVINOExecutionProvider}); // OpenVINO: Temporarily disabled due to accuracy issues -#endif - test.Config(run_with_tunable_op) - .RunWithConfig(); - }; - - run_test(false, false); - // NNAPI EP requires weight to be an initializer - run_test(true, false); - // CoreML EP requires weight and bias both to be initializers - run_test(true, true); -} - -TEST(GemmOpTest, GemmBroadcast) { - TestGemmBroadcast(); - TestGemmBroadcast(); -} - -template -static void TestGemmTrans() { - OpTester test("Gemm"); - - test.AddAttribute("transA", (int64_t)1); - test.AddAttribute("transB", (int64_t)1); - test.AddAttribute("alpha", 1.0f); - test.AddAttribute("beta", 1.0f); - - test.AddInput("A", {4, 2}, - {1.0f, -1.0f, - 2.0f, -2.0f, - 3.0f, -3.0f, - 4.0f, -4.0f}); - test.AddInput("B", {3, 4}, std::vector(12, 1.0f)); - test.AddInput("C", {3}, std::vector(3, 1.0f)); - test.AddOutput("Y", {2, 3}, - {11.0f, 11.0f, 11.0f, - -9.0f, -9.0f, -9.0f}); -#if defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_GPU_FP32) - test.ConfigExcludeEps({kOpenVINOExecutionProvider}); // OpenVINO: Temporarily disabled due to accuracy issues -#endif - test.Config(run_with_tunable_op) - .RunWithConfig(); -} - -TEST(GemmOpTest, GemmTrans) { - TestGemmTrans(); - TestGemmTrans(); -} - -// NNAPI EP's GEMM only works as A*B', add case only B is transposed -// Also test NNAPI EP's handling of non-1D bias (C of Gemm) -template -static void TestGemmTransB() { - auto run_test = [](bool b_is_initializer, bool c_is_initializer = false) { - OpTester test("Gemm"); - - test.AddAttribute("transA", (int64_t)0); - test.AddAttribute("transB", (int64_t)1); - test.AddAttribute("alpha", 1.0f); - test.AddAttribute("beta", 1.0f); - - test.AddInput("A", {2, 4}, - {1.0f, 2.0f, 3.0f, 4.0f, - -1.0f, -2.0f, -3.0f, -4.0f}); - test.AddInput("B", {3, 4}, std::vector(12, 1.0f), b_is_initializer); - test.AddInput("C", {1, 3}, std::vector(3, 1.0f), c_is_initializer); - test.AddOutput("Y", {2, 3}, - {11.0f, 11.0f, 11.0f, - -9.0f, -9.0f, -9.0f}); -#if defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_GPU_FP32) - test.ConfigExcludeEps({kOpenVINOExecutionProvider}); // OpenVINO: Temporarily disabled due to accuracy issues -#endif - test.Config(run_with_tunable_op) - .RunWithConfig(); - }; - run_test(false, false); - // CoreML EP requires weight and bias both to be initializers - run_test(true, true); -} - -TEST(GemmOpTest, GemmTransB) { - TestGemmTransB(); - TestGemmTransB(); -} - -// NNAPI EP's GEMM only works as A*B', add case only B is transposed -// Also test NNAPI EP's handling of non-1D bias (C of Gemm) which is broadcastable but not valid for NNAPI -template -static void TestGemmTransB_1() { - auto run_test = [](bool b_is_initializer, bool c_is_initializer = false) { - OpTester test("Gemm"); - - test.AddAttribute("transA", (int64_t)0); - test.AddAttribute("transB", (int64_t)1); - test.AddAttribute("alpha", 1.0f); - test.AddAttribute("beta", 1.0f); - - test.AddInput("A", {2, 4}, - {1.0f, 2.0f, 3.0f, 4.0f, - -1.0f, -2.0f, -3.0f, -4.0f}); - test.AddInput("B", {3, 4}, std::vector(12, 1.0f), b_is_initializer); - test.AddInput("C", {2, 1}, std::vector(2, 1.0f), c_is_initializer); - test.AddOutput("Y", {2, 3}, - {11.0f, 11.0f, 11.0f, - -9.0f, -9.0f, -9.0f}); -#if defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_GPU_FP32) - test.ConfigExcludeEps({kOpenVINOExecutionProvider}); // OpenVINO: Temporarily disabled due to accuracy issues -#endif - test.Config(run_with_tunable_op) - .RunWithConfig(); - }; - run_test(false, false); - // CoreML EP requires weight and bias both to be initializers - run_test(true, true); -} - -TEST(GemmOpTest, GemmTransB_1) { - TestGemmTransB_1(); - TestGemmTransB_1(); -} - -template -void TestGemmAlpha() { - OpTester test("Gemm"); - - test.AddAttribute("transA", (int64_t)0); - test.AddAttribute("transB", (int64_t)0); - test.AddAttribute("alpha", 0.5f); - test.AddAttribute("beta", 1.0f); - - test.AddInput("A", {2, 4}, - {1.0f, 2.0f, 3.0f, 4.0f, - -1.0f, -2.0f, -3.0f, -4.0f}); - test.AddInput("B", {4, 3}, std::vector(12, 1.0f)); - test.AddInput("C", {3}, std::vector(3, 1.0f)); - test.AddOutput("Y", {2, 3}, - {6.0f, 6.0f, 6.0f, - -4.0f, -4.0f, -4.0f}); - // test.AddOutput("Y", {2, 3}, - // {5.0f, 5.0f, 5.0f, - // -5.0f, -5.0f, -5.0f}); -#if defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_GPU_FP32) - test.ConfigExcludeEps({kOpenVINOExecutionProvider}); // OpenVINO: Temporarily disabled due to accuracy issues -#else - test.ConfigExcludeEps({kTensorrtExecutionProvider}); // TensorRT: Seg fault in parser -#endif - test.Config(run_with_tunable_op) - .RunWithConfig(); -} - -TEST(GemmOpTest, GemmAlpha) { - TestGemmAlpha(); - TestGemmAlpha(); -} - -template -void TestGemmBeta() { - OpTester test("Gemm"); - - test.AddAttribute("transA", (int64_t)0); - test.AddAttribute("transB", (int64_t)0); - test.AddAttribute("alpha", 1.0f); - test.AddAttribute("beta", 2.0f); - - test.AddInput("A", {2, 4}, - {1.0f, 2.0f, 3.0f, 4.0f, - -1.0f, -2.0f, -3.0f, -4.0f}); - test.AddInput("B", {4, 3}, std::vector(12, 1.0f)); - test.AddInput("C", {3}, std::vector(3, 1.0f)); - test.AddOutput("Y", {2, 3}, - {12.0f, 12.0f, 12.0f, - -8.0f, -8.0f, -8.0f}); -#if defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_GPU_FP32) - test.ConfigExcludeEps({kOpenVINOExecutionProvider}); // OpenVINO: Temporarily disabled due to accuracy issues -#else - test.ConfigExcludeEps({kTensorrtExecutionProvider}); // TensorRT: Seg fault in parser -#endif - test.Config(run_with_tunable_op) - .RunWithConfig(); -} - -TEST(GemmOpTest, GemmBeta) { - TestGemmBeta(); - TestGemmBeta(); -} - -template -void TestGemmAlphaBeta() { - OpTester test("Gemm"); - - test.AddAttribute("transA", (int64_t)0); - test.AddAttribute("transB", (int64_t)0); - test.AddAttribute("alpha", 0.5f); - test.AddAttribute("beta", 2.0f); - - test.AddInput("A", {2, 4}, - {1.0f, 2.0f, 3.0f, 4.0f, - -1.0f, -2.0f, -3.0f, -4.0f}); - test.AddInput("B", {4, 3}, std::vector(12, 1.0f)); - test.AddInput("C", {3}, std::vector(3, 1.0f)); - test.AddOutput("Y", {2, 3}, - {7.0f, 7.0f, 7.0f, - -3.0f, -3.0f, -3.0f}); -#if defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_GPU_FP32) - test.ConfigExcludeEps({kOpenVINOExecutionProvider}); // OpenVINO: Temporarily disabled due to accuracy issues -#else - test.ConfigExcludeEps({kTensorrtExecutionProvider}); // TensorRT: Seg fault in parser -#endif - test.Config(run_with_tunable_op) - .RunWithConfig(); -} - -TEST(GemmOpTest, GemmAlphaBeta) { - TestGemmAlphaBeta(); - TestGemmAlphaBeta(); -} - -template -void TestGemmNaN() { - OpTester test("Gemm"); - - test.AddAttribute("transA", (int64_t)0); - test.AddAttribute("transB", (int64_t)0); - test.AddAttribute("alpha", 1.0f); - test.AddAttribute("beta", 0.0f); - - test.AddInput("A", {2, 4}, - {1.0f, 2.0f, 3.0f, 4.0f, - -1.0f, -2.0f, -3.0f, -4.0f}); - test.AddInput("B", {4, 3}, std::vector(12, 1.0f)); - test.AddInput("C", {2, 3}, std::vector(6, 1.0f)); - test.AddOutput("Y", {2, 3}, - {10.0f, 10.0f, 10.0f, - -10.0f, -10.0f, -10.0f}); - - // TensorRT: Seg fault in parser - test.ConfigExcludeEps({kTensorrtExecutionProvider}) - .Config(run_with_tunable_op) - .RunWithConfig(); -} - -TEST(GemmOpTest, GemmNaN) { - TestGemmNaN(); - TestGemmNaN(); -} #if defined(USE_DNNL) TEST(GemmOpTest, GemmNaN_bfloat16) { #ifdef USE_DNNL @@ -444,32 +142,6 @@ TEST(GemmOpTest, GemmNaN_bfloat16) { } #endif // USE_DNNL -template -void TestGemmScalarBroadcast() { - OpTester test("Gemm"); - - test.AddAttribute("transA", (int64_t)0); - test.AddAttribute("transB", (int64_t)0); - test.AddAttribute("alpha", 1.0f); - test.AddAttribute("beta", 1.0f); - - test.AddInput("A", {2, 4}, - {1.0f, 2.0f, 3.0f, 4.0f, - -1.0f, -2.0f, -3.0f, -4.0f}); - test.AddInput("B", {4, 3}, std::vector(12, 1.0f)); - test.AddInput("C", {1}, std::vector{1.0f}); - test.AddOutput("Y", {2, 3}, - {11.0f, 11.0f, 11.0f, - -9.0f, -9.0f, -9.0f}); - test.Config(run_with_tunable_op) - .RunWithConfig(); -} - -TEST(GemmOpTest, GemmScalarBroadcast) { - TestGemmScalarBroadcast(); - TestGemmScalarBroadcast(); -} - #if defined(USE_DNNL) TEST(GemmOpTest, GemmScalarBroadcast_bfloat16) { #ifdef USE_DNNL @@ -502,31 +174,6 @@ TEST(GemmOpTest, GemmScalarBroadcast_bfloat16) { } #endif // USE_DNNL -template -void TestGemm2DBroadcast_1() { - OpTester test("Gemm"); - - test.AddAttribute("transA", (int64_t)0); - test.AddAttribute("transB", (int64_t)0); - test.AddAttribute("alpha", 1.0f); - test.AddAttribute("beta", 1.0f); - - test.AddInput("A", {2, 4}, - {1.0f, 2.0f, 3.0f, 4.0f, - -1.0f, -2.0f, -3.0f, -4.0f}); - test.AddInput("B", {4, 3}, std::vector(12, 1.0f)); - test.AddInput("C", {2, 1}, std::vector{1.0, 2.0f}); - test.AddOutput("Y", {2, 3}, - {11.0f, 11.0f, 11.0f, - -8.0f, -8.0f, -8.0f}); - test.Config(run_with_tunable_op) - .RunWithConfig(); -} - -TEST(GemmOpTest, Gemm2DBroadcast_1) { - TestGemm2DBroadcast_1(); - TestGemm2DBroadcast_1(); -} #if defined(USE_DNNL) TEST(GemmOpTest, Gemm2DBroadcast_1_bfloat16) { #ifdef USE_DNNL @@ -559,33 +206,6 @@ TEST(GemmOpTest, Gemm2DBroadcast_1_bfloat16) { } #endif // USE_DNNL -template -void TestGemm2DBroadcast_2() { - OpTester test("Gemm"); - - test.AddAttribute("transA", (int64_t)0); - test.AddAttribute("transB", (int64_t)0); - test.AddAttribute("alpha", 1.0f); - test.AddAttribute("beta", 1.0f); - - // Same as GemmBroadcast, but adding the unnecessary second dimension. - test.AddInput("A", {2, 4}, - {1.0f, 2.0f, 3.0f, 4.0f, - -1.0f, -2.0f, -3.0f, -4.0f}); - test.AddInput("B", {4, 3}, std::vector(12, 1.0f)); - test.AddInput("C", {1, 3}, std::vector{1.0f, 2.0f, 3.0f}); - test.AddOutput("Y", {2, 3}, - {11.0f, 12.0f, 13.0f, - -9.0f, -8.0f, -7.0f}); - test.Config(run_with_tunable_op) - .RunWithConfig(); -} - -TEST(GemmOpTest, Gemm2DBroadcast_2) { - TestGemm2DBroadcast_2(); - TestGemm2DBroadcast_2(); -} - #if defined(USE_DNNL) TEST(GemmOpTest, Gemm2DBroadcast_2_bfloat16) { #ifdef USE_DNNL @@ -618,32 +238,6 @@ TEST(GemmOpTest, Gemm2DBroadcast_2_bfloat16) { } #endif // USE_DNNL -template -void TestGemmFalseBroadcast() { - OpTester test("Gemm"); - - test.AddAttribute("transA", (int64_t)0); - test.AddAttribute("transB", (int64_t)0); - test.AddAttribute("alpha", 1.0f); - test.AddAttribute("beta", 1.0f); - - test.AddInput("A", {2, 4}, - {1.0f, 2.0f, 3.0f, 4.0f, - -1.0f, -2.0f, -3.0f, -4.0f}); - test.AddInput("B", {4, 3}, std::vector(12, 1.0f)); - test.AddInput("C", {2, 3}, std::vector{1.0f, 1.0f, 1.0f, 2.0f, 2.0f, 2.0f}); - test.AddOutput("Y", {2, 3}, - {11.0f, 11.0f, 11.0f, - -8.0f, -8.0f, -8.0f}); - test.Config(run_with_tunable_op) - .RunWithConfig(); -} - -TEST(GemmOpTest, GemmFalseBroadcast) { - TestGemmFalseBroadcast(); - TestGemmFalseBroadcast(); -} - #if defined(USE_DNNL) TEST(GemmOpTest, GemmFalseBroadcast_2_bfloat16) { #ifdef USE_DNNL @@ -675,34 +269,363 @@ TEST(GemmOpTest, GemmFalseBroadcast_2_bfloat16) { test.Run(OpTester::ExpectResult::kExpectSuccess, "", {}, nullptr, &execution_providers); } #endif // USE_DNNL + template -void TestGemmEmptyTensor() { +class GemmOpTypedTests : public ::testing::Test { +}; + +// On CPUs without fp16 instructions the tests will output a warning: +// "registered execution providers CPUExecutionProvider were unable to run the model" +// , then they will still pass. +using GemmOpTypedTestsTypes = ::testing::Types; +TYPED_TEST_SUITE(GemmOpTypedTests, GemmOpTypedTestsTypes); + +TYPED_TEST(GemmOpTypedTests, TestGemmScalarBroadcast) { + OpTester test("Gemm"); + + test.AddAttribute("transA", (int64_t)0); + test.AddAttribute("transB", (int64_t)0); + test.AddAttribute("alpha", 1.0f); + test.AddAttribute("beta", 1.0f); + + test.AddInput("A", {2, 4}, + {static_cast(1.0f), static_cast(2.0f), static_cast(3.0f), static_cast(4.0f), + static_cast(-1.0f), static_cast(-2.0f), static_cast(-3.0f), static_cast(-4.0f)}); + test.AddInput("B", {4, 3}, std::vector(12, static_cast(1.0f))); + test.AddInput("C", {1}, std::vector{static_cast(1.0f)}); + test.AddOutput("Y", {2, 3}, + {static_cast(11.0f), static_cast(11.0f), static_cast(11.0f), + static_cast(-9.0f), static_cast(-9.0f), static_cast(-9.0f)}); + test.Config(run_with_tunable_op) + .RunWithConfig(); +} +TYPED_TEST(GemmOpTypedTests, TestGemm2DBroadcast_2) { + OpTester test("Gemm"); + + test.AddAttribute("transA", (int64_t)0); + test.AddAttribute("transB", (int64_t)0); + test.AddAttribute("alpha", 1.0f); + test.AddAttribute("beta", 1.0f); + + // Same as GemmBroadcast, but adding the unnecessary second dimension. + test.AddInput("A", {2, 4}, + {static_cast(1.0f), static_cast(2.0f), static_cast(3.0f), static_cast(4.0f), + static_cast(-1.0f), static_cast(-2.0f), static_cast(-3.0f), static_cast(-4.0f)}); + test.AddInput("B", {4, 3}, std::vector(12, static_cast(1.0f))); + test.AddInput("C", {1, 3}, std::vector{static_cast(1.0f), static_cast(2.0f), static_cast(3.0f)}); + test.AddOutput("Y", {2, 3}, + {static_cast(11.0f), static_cast(12.0f), static_cast(13.0f), + static_cast(-9.0f), static_cast(-8.0f), static_cast(-7.0f)}); + test.Config(run_with_tunable_op) + .RunWithConfig(); +} + +TYPED_TEST(GemmOpTypedTests, TestGemmFalseBroadcast) { + OpTester test("Gemm"); + + test.AddAttribute("transA", (int64_t)0); + test.AddAttribute("transB", (int64_t)0); + test.AddAttribute("alpha", 1.0f); + test.AddAttribute("beta", 1.0f); + + test.AddInput("A", {2, 4}, + {static_cast(1.0f), static_cast(2.0f), static_cast(3.0f), static_cast(4.0f), + static_cast(-1.0f), static_cast(-2.0f), static_cast(-3.0f), static_cast(-4.0f)}); + test.AddInput("B", {4, 3}, std::vector(12, static_cast(1.0f))); + test.AddInput("C", {2, 3}, std::vector{static_cast(1.0f), static_cast(1.0f), static_cast(1.0f), static_cast(2.0f), static_cast(2.0f), static_cast(2.0f)}); + test.AddOutput("Y", {2, 3}, + {static_cast(11.0f), static_cast(11.0f), static_cast(11.0f), + static_cast(-8.0f), static_cast(-8.0f), static_cast(-8.0f)}); + test.Config(run_with_tunable_op) + .RunWithConfig(); +} + +TYPED_TEST(GemmOpTypedTests, TestGemmBroadcast) { + auto run_test = [](bool b_is_initializer, bool c_is_initializer) { + OpTester test("Gemm"); + + test.AddAttribute("transA", (int64_t)0); + test.AddAttribute("transB", (int64_t)0); + test.AddAttribute("alpha", 1.0f); + test.AddAttribute("beta", 1.0f); + + test.AddInput("A", {2, 4}, + {static_cast(1.0f), static_cast(2.0f), static_cast(3.0f), static_cast(4.0f), + static_cast(-1.0f), static_cast(-2.0f), static_cast(-3.0f), static_cast(-4.0f)}); + test.AddInput("B", {4, 3}, std::vector(12, static_cast(1.0f)), b_is_initializer); + test.AddInput("C", {3}, std::vector{static_cast(1.0f), static_cast(2.0f), static_cast(3.0f)}, c_is_initializer); + test.AddOutput("Y", {2, 3}, + {static_cast(11.0f), static_cast(12.0f), static_cast(13.0f), + static_cast(-9.0f), static_cast(-8.0f), static_cast(-7.0f)}); +#if defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_GPU_FP32) + test.ConfigExcludeEps({kOpenVINOExecutionProvider}); // OpenVINO: Temporarily disabled due to accuracy issues +#endif + test.Config(run_with_tunable_op) + .RunWithConfig(); + }; + + run_test(false, false); + // NNAPI EP requires weight to be an initializer + run_test(true, false); + // CoreML EP requires weight and bias both to be initializers + run_test(true, true); +} + +TYPED_TEST(GemmOpTypedTests, TestGemmTrans) { + OpTester test("Gemm"); + + test.AddAttribute("transA", (int64_t)1); + test.AddAttribute("transB", (int64_t)1); + test.AddAttribute("alpha", 1.0f); + test.AddAttribute("beta", 1.0f); + + test.AddInput("A", {4, 2}, + {static_cast(1.0f), static_cast(-1.0f), + static_cast(2.0f), static_cast(-2.0f), + static_cast(3.0f), static_cast(-3.0f), + static_cast(4.0f), static_cast(-4.0f)}); + test.AddInput("B", {3, 4}, std::vector(12, static_cast(1.0f))); + test.AddInput("C", {3}, std::vector(3, static_cast(1.0f))); + test.AddOutput("Y", {2, 3}, + {static_cast(11.0f), static_cast(11.0f), static_cast(11.0f), + static_cast(-9.0f), static_cast(-9.0f), static_cast(-9.0f)}); +#if defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_GPU_FP32) + test.ConfigExcludeEps({kOpenVINOExecutionProvider}); // OpenVINO: Temporarily disabled due to accuracy issues +#endif + test.Config(run_with_tunable_op) + .RunWithConfig(); +} + +// NNAPI EP's GEMM only works as A*B', add case only B is transposed +// Also test NNAPI EP's handling of non-1D bias (C of Gemm) +TYPED_TEST(GemmOpTypedTests, TestGemmTransB) { + auto run_test = [](bool b_is_initializer, bool c_is_initializer = false) { + OpTester test("Gemm"); + + test.AddAttribute("transA", (int64_t)0); + test.AddAttribute("transB", (int64_t)1); + test.AddAttribute("alpha", 1.0f); + test.AddAttribute("beta", 1.0f); + + test.AddInput("A", {2, 4}, + {static_cast(1.0f), static_cast(2.0f), static_cast(3.0f), static_cast(4.0f), + static_cast(-1.0f), static_cast(-2.0f), static_cast(-3.0f), static_cast(-4.0f)}); + test.AddInput("B", {3, 4}, std::vector(12, static_cast(1.0f)), b_is_initializer); + test.AddInput("C", {1, 3}, std::vector(3, static_cast(1.0f)), c_is_initializer); + test.AddOutput("Y", {2, 3}, + {static_cast(11.0f), static_cast(11.0f), static_cast(11.0f), + static_cast(-9.0f), static_cast(-9.0f), static_cast(-9.0f)}); +#if defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_GPU_FP32) + test.ConfigExcludeEps({kOpenVINOExecutionProvider}); // OpenVINO: Temporarily disabled due to accuracy issues +#endif + test.Config(run_with_tunable_op) + .RunWithConfig(); + }; + run_test(false, false); + // CoreML EP requires weight and bias both to be initializers + run_test(true, true); +} + +// NNAPI EP's GEMM only works as A*B', add case only B is transposed +// Also test NNAPI EP's handling of non-1D bias (C of Gemm) which is broadcastable but not valid for NNAPI +TYPED_TEST(GemmOpTypedTests, TestGemmTransB_1) { + auto run_test = [](bool b_is_initializer, bool c_is_initializer = false) { + OpTester test("Gemm"); + + test.AddAttribute("transA", (int64_t)0); + test.AddAttribute("transB", (int64_t)1); + test.AddAttribute("alpha", 1.0f); + test.AddAttribute("beta", 1.0f); + + test.AddInput("A", {2, 4}, + {static_cast(1.0f), static_cast(2.0f), static_cast(3.0f), static_cast(4.0f), + static_cast(-1.0f), static_cast(-2.0f), static_cast(-3.0f), static_cast(-4.0f)}); + test.AddInput("B", {3, 4}, std::vector(12, static_cast(1.0f)), b_is_initializer); + test.AddInput("C", {2, 1}, std::vector(2, static_cast(1.0f)), c_is_initializer); + test.AddOutput("Y", {2, 3}, + {static_cast(11.0f), static_cast(11.0f), static_cast(11.0f), + static_cast(-9.0f), static_cast(-9.0f), static_cast(-9.0f)}); +#if defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_GPU_FP32) + test.ConfigExcludeEps({kOpenVINOExecutionProvider}); // OpenVINO: Temporarily disabled due to accuracy issues +#endif + test.Config(run_with_tunable_op) + .RunWithConfig(); + }; + run_test(false, false); + // CoreML EP requires weight and bias both to be initializers + run_test(true, true); +} + +TYPED_TEST(GemmOpTypedTests, TestGemmAlpha) { + OpTester test("Gemm"); + + test.AddAttribute("transA", (int64_t)0); + test.AddAttribute("transB", (int64_t)0); + test.AddAttribute("alpha", 0.5f); + test.AddAttribute("beta", 1.0f); + + test.AddInput("A", {2, 4}, + {static_cast(1.0f), static_cast(2.0f), static_cast(3.0f), static_cast(4.0f), + static_cast(-1.0f), static_cast(-2.0f), static_cast(-3.0f), static_cast(-4.0f)}); + test.AddInput("B", {4, 3}, std::vector(12, static_cast(1.0f))); + test.AddInput("C", {3}, std::vector(3, static_cast(1.0f))); + test.AddOutput("Y", {2, 3}, + {static_cast(6.0f), static_cast(6.0f), static_cast(6.0f), + static_cast(-4.0f), static_cast(-4.0f), static_cast(-4.0f)}); + // test.AddOutput("Y", {2, 3}, + // {5.0f, 5.0f, 5.0f, + // -5.0f, -5.0f, -5.0f}); +#if defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_GPU_FP32) + test.ConfigExcludeEps({kOpenVINOExecutionProvider}); // OpenVINO: Temporarily disabled due to accuracy issues +#else + test.ConfigExcludeEps({kTensorrtExecutionProvider}); // TensorRT: Seg fault in parser +#endif + test.Config(run_with_tunable_op) + .RunWithConfig(); +} + +TYPED_TEST(GemmOpTypedTests, TestGemmBeta) { OpTester test("Gemm"); + test.AddAttribute("transA", (int64_t)0); + test.AddAttribute("transB", (int64_t)0); + test.AddAttribute("alpha", 1.0f); + test.AddAttribute("beta", 2.0f); + + test.AddInput("A", {2, 4}, + {static_cast(1.0f), static_cast(2.0f), static_cast(3.0f), static_cast(4.0f), + static_cast(-1.0f), static_cast(-2.0f), static_cast(-3.0f), static_cast(-4.0f)}); + test.AddInput("B", {4, 3}, std::vector(12, static_cast(1.0f))); + test.AddInput("C", {3}, std::vector(3, static_cast(1.0f))); + test.AddOutput("Y", {2, 3}, + {static_cast(12.0f), static_cast(12.0f), static_cast(12.0f), + static_cast(-8.0f), static_cast(-8.0f), static_cast(-8.0f)}); +#if defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_GPU_FP32) + test.ConfigExcludeEps({kOpenVINOExecutionProvider}); // OpenVINO: Temporarily disabled due to accuracy issues +#else + test.ConfigExcludeEps({kTensorrtExecutionProvider}); // TensorRT: Seg fault in parser +#endif + test.Config(run_with_tunable_op) + .RunWithConfig(); +} + +TYPED_TEST(GemmOpTypedTests, TestGemmNaN) { + OpTester test("Gemm"); + + test.AddAttribute("transA", (int64_t)0); + test.AddAttribute("transB", (int64_t)0); + test.AddAttribute("alpha", 1.0f); + test.AddAttribute("beta", 0.0f); + + test.AddInput("A", {2, 4}, + {static_cast(1.0f), static_cast(2.0f), static_cast(3.0f), static_cast(4.0f), + static_cast(-1.0f), static_cast(-2.0f), static_cast(-3.0f), static_cast(-4.0f)}); + test.AddInput("B", {4, 3}, std::vector(12, static_cast(1.0f))); + test.AddInput("C", {2, 3}, std::vector(6, static_cast(1.0f))); + test.AddOutput("Y", {2, 3}, + {static_cast(10.0f), static_cast(10.0f), static_cast(10.0f), + static_cast(-10.0f), static_cast(-10.0f), static_cast(-10.0f)}); + + // TensorRT: Seg fault in parser + test.ConfigExcludeEps({kTensorrtExecutionProvider}) + .Config(run_with_tunable_op) + .RunWithConfig(); +} + +TYPED_TEST(GemmOpTypedTests, TestGemmAlphaBeta) { + OpTester test("Gemm", 13); + + test.AddAttribute("transA", (int64_t)0); + test.AddAttribute("transB", (int64_t)0); + test.AddAttribute("alpha", 0.5f); + test.AddAttribute("beta", 2.0f); + + test.AddInput("A", {2, 4}, + {static_cast(1.0f), static_cast(2.0f), static_cast(3.0f), static_cast(4.0f), + static_cast(-1.0f), static_cast(-2.0f), static_cast(-3.0f), static_cast(-4.0f)}); + test.AddInput("B", {4, 3}, std::vector(12, static_cast(1.0f))); + test.AddInput("C", {3}, std::vector(3, static_cast(1.0f))); + test.AddOutput("Y", {2, 3}, + {static_cast(7.0f), static_cast(7.0f), static_cast(7.0f), + static_cast(-3.0f), static_cast(-3.0f), static_cast(-3.0f)}); +#if defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_GPU_FP32) + test.ConfigExcludeEps({kOpenVINOExecutionProvider}); // OpenVINO: Temporarily disabled due to accuracy issues +#else + test.ConfigExcludeEps({kTensorrtExecutionProvider}); // TensorRT: Seg fault in parser +#endif + test.Config(run_with_tunable_op) + .RunWithConfig(); +} + +// C is 1D +TYPED_TEST(GemmOpTypedTests, TestGemm2DBroadcast_1) { + OpTester test("Gemm"); + + test.AddAttribute("transA", (int64_t)0); + test.AddAttribute("transB", (int64_t)0); + test.AddAttribute("alpha", 1.0f); + test.AddAttribute("beta", 1.0f); + std::array a_data{static_cast(1.0f), static_cast(2.0f), static_cast(3.0f), static_cast(4.0f), + static_cast(-1.0f), static_cast(-2.0f), static_cast(-3.0f), static_cast(-4.0f)}; + + test.AddInput("A", {2, 4}, a_data.data(), a_data.size()); + test.AddInput("B", {4, 3}, std::vector(12, static_cast(1.0f))); + test.AddInput("C", {2, 1}, std::vector{static_cast(1.0f), static_cast(2.0f)}); + test.AddOutput("Y", {2, 3}, + {static_cast(11.0f), static_cast(11.0f), static_cast(11.0f), + static_cast(-8.0f), static_cast(-8.0f), static_cast(-8.0f)}); + test.Config(run_with_tunable_op) + .RunWithConfig(); +} + +TYPED_TEST(GemmOpTypedTests, TestGemmNoTrans) { + auto run_test = [](bool b_is_initializer, bool c_is_initializer = false) { + OpTester test("Gemm", 13); + + test.AddAttribute("transA", (int64_t)0); + test.AddAttribute("transB", (int64_t)0); + test.AddAttribute("alpha", 1.0f); + test.AddAttribute("beta", 1.0f); + + std::array a_data{static_cast(1.0f), static_cast(2.0f), static_cast(3.0f), static_cast(4.0f), + static_cast(-1.0f), static_cast(-2.0f), static_cast(-3.0f), static_cast(-4.0f)}; + + test.AddInput("A", {2, 4}, a_data.data(), a_data.size()); + test.AddInput("B", {4, 3}, std::vector(12, static_cast(1.0f)), b_is_initializer); + test.AddInput("C", {2, 3}, std::vector(6, static_cast(1.0f)), c_is_initializer); + test.AddOutput("Y", {2, 3}, + {static_cast(11.0f), static_cast(11.0f), static_cast(11.0f), + static_cast(-9.0f), static_cast(-9.0f), static_cast(-9.0f)}); + test.Config(run_with_tunable_op) + .RunWithConfig(); + }; + + run_test(false, false); + // NNAPI EP requires weight to be an initializer + run_test(true, false); + // CoreML EP requires weight and bias both to be initializers + run_test(true, true); +} +TYPED_TEST(GemmOpTypedTests, GemmEmptyTensor) { + OpTester test("Gemm", 13); + test.AddAttribute("transA", static_cast(0)); test.AddAttribute("transB", static_cast(0)); test.AddAttribute("alpha", 1.0f); test.AddAttribute("beta", 1.0f); - test.AddInput("A", {0, 4}, - {}); - test.AddInput("B", {4, 3}, std::vector(12, 1.0f)); - test.AddInput("C", {3}, std::vector(3, 1.0f)); - test.AddOutput("Y", {0, 3}, - {}); + test.AddInput("A", {0, 4}, + {}); + test.AddInput("B", {4, 3}, std::vector(12, static_cast(1.0f))); + test.AddInput("C", {3}, std::vector(3, static_cast(1.0f))); + test.AddOutput("Y", {0, 3}, + {}); // TensorRT: doesn't support dynamic shape yet test.ConfigExcludeEps({kTensorrtExecutionProvider, kDnnlExecutionProvider, kQnnExecutionProvider}) .Config(run_with_tunable_op) .RunWithConfig(); } - -TEST(GemmOpTest, GemmEmptyTensor) { - TestGemmEmptyTensor(); - TestGemmEmptyTensor(); -} - -template -static void TestGemmNoBiasOpset11() { +TYPED_TEST(GemmOpTypedTests, MissingBias) { OpTester test("Gemm", 11); test.AddAttribute("transA", static_cast(0)); @@ -710,13 +633,13 @@ static void TestGemmNoBiasOpset11() { test.AddAttribute("alpha", 1.0f); test.AddAttribute("beta", 1.0f); - test.AddInput("A", {2, 4}, - {1.0f, 2.0f, 3.0f, 4.0f, - -1.0f, -2.0f, -3.0f, -4.0f}); - test.AddInput("B", {4, 3}, std::vector(12, 1.0f)); - test.AddOutput("Y", {2, 3}, - {10.0f, 10.0f, 10.0f, - -10.0f, -10.0f, -10.0f}); + test.AddInput("A", {2, 4}, + {static_cast(1.0f), static_cast(2.0f), static_cast(3.0f), static_cast(4.0f), + static_cast(-1.0f), static_cast(-2.0f), static_cast(-3.0f), static_cast(-4.0f)}); + test.AddInput("B", {4, 3}, std::vector(12, static_cast(1.0f))); + test.AddOutput("Y", {2, 3}, + {static_cast(10.0f), static_cast(10.0f), static_cast(10.0f), + static_cast(-10.0f), static_cast(-10.0f), static_cast(-10.0f)}); // tensorRT don't seem to support missing bias std::unordered_set excluded_provider_types{kTensorrtExecutionProvider}; // QNN Linux result diff 0.011714935302734375 exceed the threshold @@ -728,33 +651,22 @@ static void TestGemmNoBiasOpset11() { .RunWithConfig(); } -TEST(GemmOpTest, GemmNoBiasOpset11) { - TestGemmNoBiasOpset11(); - TestGemmNoBiasOpset11(); -} - -template -static void TestGemmWithAlphaOpset11() { +TYPED_TEST(GemmOpTypedTests, TestGemmWithAlphaOpset11) { OpTester test("Gemm", 11); test.AddAttribute("alpha", 2.0f); - test.AddInput("A", {2, 2}, - {1.0f, 2.0f, 3.0f, 4.0f}); - test.AddInput("B", {2, 2}, std::vector(4, 1.0f)); - test.AddOutput("Y", {2, 2}, - {6.0f, 6.0f, 14.0f, 14.0f}); + test.AddInput("A", {2, 2}, + {static_cast(1.0f), static_cast(2.0f), static_cast(3.0f), static_cast(4.0f)}); + test.AddInput("B", {2, 2}, std::vector(4, static_cast(1.0f))); + test.AddOutput("Y", {2, 2}, + {static_cast(6.0f), static_cast(6.0f), static_cast(14.0f), static_cast(14.0f)}); // tensorRT don't seem to support missing bias test.ConfigExcludeEps({kTensorrtExecutionProvider}) .Config(run_with_tunable_op) .RunWithConfig(); } -TEST(GemmOpTest, GemmWithAlphaOpset11) { - TestGemmWithAlphaOpset11(); - TestGemmWithAlphaOpset11(); -} - #ifndef ENABLE_TRAINING // Prepacking is disabled in training builds so no need to test the feature in a training build. TEST(GemmOpTest, SharedPrepackedWeights) { diff --git a/onnxruntime/test/providers/cpu/math/round_test.cc b/onnxruntime/test/providers/cpu/math/round_test.cc index 395231e637702..5df14ac079a63 100644 --- a/onnxruntime/test/providers/cpu/math/round_test.cc +++ b/onnxruntime/test/providers/cpu/math/round_test.cc @@ -25,8 +25,8 @@ TEST(RoundTest, SimpleTestDouble) { TEST(RoundTest, SimpleTestFloat16) { OpTester test("Round", 11, onnxruntime::kOnnxDomain); - test.AddInput("x", {5}, {MLFloat16(math::floatToHalf(0.9f)), MLFloat16(math::floatToHalf(2.5f)), MLFloat16(math::floatToHalf(2.3f)), MLFloat16(math::floatToHalf(1.5f)), MLFloat16(math::floatToHalf(-4.5f))}); - test.AddOutput("y", {5}, {MLFloat16(math::floatToHalf(1.0f)), MLFloat16(math::floatToHalf(2.0f)), MLFloat16(math::floatToHalf(2.0f)), MLFloat16(math::floatToHalf(2.0f)), MLFloat16(math::floatToHalf(-4.0f))}); + test.AddInput("x", {5}, {MLFloat16(0.9f), MLFloat16(2.5f), MLFloat16(2.3f), MLFloat16(1.5f), MLFloat16(-4.5f)}); + test.AddOutput("y", {5}, {MLFloat16(1.0f), MLFloat16(2.0f), MLFloat16(2.0f), MLFloat16(2.0f), MLFloat16(-4.0f)}); test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); } diff --git a/onnxruntime/test/providers/cpu/math/sign_test.cc b/onnxruntime/test/providers/cpu/math/sign_test.cc index e1f0e91f839da..15b3f40faa791 100644 --- a/onnxruntime/test/providers/cpu/math/sign_test.cc +++ b/onnxruntime/test/providers/cpu/math/sign_test.cc @@ -22,7 +22,7 @@ struct make_type { template struct make_type { static MLFloat16 make(A v) { - return MLFloat16(math::floatToHalf(float(v))); + return MLFloat16(float(v)); } }; @@ -34,7 +34,9 @@ struct make_type { }; template -typename std::enable_if::is_signed>::type +typename std::enable_if::is_signed && + !std::is_same::value && + !std::is_same::value>::type GenerateSequence(OutputIter out) { for (int i = 0; i < 7; ++i) { *out = make_type::make(i); @@ -43,7 +45,9 @@ GenerateSequence(OutputIter out) { } template -typename std::enable_if::is_signed>::type +typename std::enable_if::is_signed || + std::is_same::value || + std::is_same::value>::type GenerateSequence(OutputIter out) { for (int i = -5; i < 2; ++i) { *out = make_type::make(i); @@ -61,7 +65,7 @@ struct ToTestableType { template <> struct ToTestableType { static float to_type(MLFloat16 v) { - return math::halfToFloat(v.val); + return v.ToFloat(); } }; @@ -109,7 +113,7 @@ TestImpl(ForwardIter first, ForwardIter last, OutputIter out) { TEST(MathOpTest, Sign_uint64) { using namespace test_sign_internal; - OpTester test("Sign", 9); + OpTester test("Sign", 13); std::vector input_dims{7}; std::vector input; @@ -125,7 +129,7 @@ TEST(MathOpTest, Sign_uint64) { // we disable this test for openvino as openvino ep supports only FP32 Precision TEST(MathOpTest, Sign_int64) { using namespace test_sign_internal; - OpTester test("Sign", 9); + OpTester test("Sign", 13); std::vector input_dims{7}; std::vector input; @@ -136,12 +140,13 @@ TEST(MathOpTest, Sign_int64) { std::vector output; TestImpl(input.cbegin(), input.cend(), std::back_inserter(output)); test.AddOutput("output", input_dims, output); - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); + // TODO: QNN execute error, need further investigation + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider, kQnnExecutionProvider}); } TEST(MathOpTest, Sign_float) { using namespace test_sign_internal; - OpTester test("Sign", 9); + OpTester test("Sign", 13); std::vector input_dims{7}; std::vector input; @@ -157,7 +162,7 @@ TEST(MathOpTest, Sign_float) { TEST(MathOpTest, Sign_double) { using namespace test_sign_internal; - OpTester test("Sign", 9); + OpTester test("Sign", 13); std::vector input_dims{7}; std::vector input; @@ -172,7 +177,7 @@ TEST(MathOpTest, Sign_double) { } TEST(MathOpTest, Sign_MLFloat16) { using namespace test_sign_internal; - OpTester test("Sign", 9); + OpTester test("Sign", 13); std::vector input_dims{7}; std::vector input; @@ -186,6 +191,23 @@ TEST(MathOpTest, Sign_MLFloat16) { test.Run(OpTester::ExpectResult::kExpectSuccess); } +// Currently BFloat16 is not enabled for Sign kernel +// TEST(MathOpTest, Sign_BFloat16) { +// using namespace test_sign_internal; +// OpTester test("Sign", 9); +// +// std::vector input_dims{7}; +// std::vector input; +// GenerateSequence(std::back_inserter(input)); +// ASSERT_EQ(input.size(), 7U); +// test.AddInput("input", input_dims, input); +// +// std::vector output; +// TestImpl(input.cbegin(), input.cend(), std::back_inserter(output)); +// test.AddOutput("output", input_dims, output); +// test.Run(OpTester::ExpectResult::kExpectSuccess); +//} + #if defined(USE_DNNL) TEST(MathOpTest, Sign_bfloat16) { #ifdef USE_DNNL diff --git a/onnxruntime/test/providers/cpu/math/softmax_test.cc b/onnxruntime/test/providers/cpu/math/softmax_test.cc index 94479a64d5b4d..b94c17c3b0e24 100644 --- a/onnxruntime/test/providers/cpu/math/softmax_test.cc +++ b/onnxruntime/test/providers/cpu/math/softmax_test.cc @@ -1,12 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#include #include "gmock/gmock.h" #include "gtest/gtest.h" + +#include "core/session/environment.h" #include "test/providers/provider_test_utils.h" #include "test/common/cuda_op_test_utils.h" #include "test/common/dnnl_op_test_utils.h" -#include namespace onnxruntime { namespace test { @@ -123,9 +125,11 @@ TEST(SoftmaxOperator, LargeNumber) { } // np.random.seed(123) # Use a seed so we can replicate the input and expected values here and in python +// # create 60 input values // x = np.abs(np.random.randn(3, 4, 5).astype(np.float32)) -static std::vector three_dimensions = {3, 4, 5}; -static std::vector x_vals_3dims = { +static const std::vector three_dimensions = {3, 4, 5}; +static const std::vector four_dimensions = {1, 3, 4, 5}; +static const std::vector input_vals_60 = { 1.0856307f, 0.99734545f, 0.2829785f, 1.5062947f, 0.5786002f, 1.6514366f, 2.4266791f, 0.42891264f, 1.2659363f, 0.8667404f, 0.6788862f, 0.09470897f, 1.4913896f, 0.638902f, 0.44398195f, @@ -141,8 +145,8 @@ static std::vector x_vals_3dims = { 1.2940853f, 1.0387882f, 1.7437122f, 0.79806274f, 0.02968323f, 1.0693159f, 0.8907064f, 1.7548862f, 1.4956441f, 1.0693927f}; -TEST(SoftmaxOperator, ThreeDimsAxis0) { - // x = +TEST(SoftmaxOperator, ThreeAndFourDimsAxis0) { + // x = // node = onnx.helper.make_node('Softmax', inputs = ['x'], outputs = ['y'], axis = 0) // y = softmax_2d(x.reshape(1, 60)).reshape(3, 4, 5) // expect(node, inputs = [x], outputs = [y], @@ -164,11 +168,17 @@ TEST(SoftmaxOperator, ThreeDimsAxis0) { 0.017545262f, 0.0135920765f, 0.027506188f, 0.010684152f, 0.0049549243f, 0.01401341f, 0.011721271f, 0.027815264f, 0.021463264f, 0.014014485f}; - RunTest(x_vals_3dims, expected_vals, three_dimensions, /*opset*/ 7, /*axis*/ 0, {kTensorrtExecutionProvider, kOpenVINOExecutionProvider, kDnnlExecutionProvider}); // Axis=0 is not supported by TensorRT + RunTest(input_vals_60, expected_vals, three_dimensions, /*opset*/ 7, /*axis*/ 0, + // axis=0 is not supported by TensorRT + {kTensorrtExecutionProvider, kOpenVINOExecutionProvider, kDnnlExecutionProvider}); + + RunTest(input_vals_60, expected_vals, four_dimensions, /*opset*/ 7, /*axis*/ 0, + // axis=0 is not supported by TensorRT + {kTensorrtExecutionProvider, kOpenVINOExecutionProvider, kDnnlExecutionProvider}); } -TEST(SoftmaxOperator, ThreeDimsAxis1) { - // x = +TEST(SoftmaxOperator, ThreeAndFourDimsSecondLastAxis) { + // x = // node = onnx.helper.make_node('Softmax', inputs = ['x'], outputs = ['y'], axis = 1) // y = softmax_2d(x.reshape(3, 20)).reshape(3, 4, 5) // expect(node, inputs = [x], outputs = [y], @@ -190,10 +200,14 @@ TEST(SoftmaxOperator, ThreeDimsAxis1) { 0.050680935f, 0.03926183f, 0.079453886f, 0.030862054f, 0.014312706f, 0.040478885f, 0.033857856f, 0.080346674f, 0.06199841f, 0.040481992f}; - RunTest(x_vals_3dims, expected_vals, three_dimensions, /*opset*/ 7, /*axis*/ 1, {kTensorrtExecutionProvider, kOpenVINOExecutionProvider, kDnnlExecutionProvider}); + RunTest(input_vals_60, expected_vals, three_dimensions, /*opset*/ 7, /*axis*/ 1, + {kTensorrtExecutionProvider, kOpenVINOExecutionProvider, kDnnlExecutionProvider}); + + RunTest(input_vals_60, expected_vals, four_dimensions, /*opset*/ 7, /*axis*/ 2, + {kTensorrtExecutionProvider, kOpenVINOExecutionProvider, kDnnlExecutionProvider}); } -TEST(SoftmaxOperator, ThreeDimsAxis1_opset13) { +TEST(SoftmaxOperator, ThreeAndFourDimsSecondLastAxis_opset13) { // For the same input, opset-13's behavior is different from an earlier opset // and we see different expected results for the same test input @@ -213,12 +227,15 @@ TEST(SoftmaxOperator, ThreeDimsAxis1_opset13) { 0.37181312f, 0.12944824f, 0.3946307f, 0.19975942f, 0.0699691f, 0.29696727f, 0.11163106f, 0.39906505f, 0.4012943f, 0.1979003f}; - RunTest(x_vals_3dims, expected_vals, three_dimensions, /*opset*/ 13, /*axis*/ 1, + RunTest(input_vals_60, expected_vals, three_dimensions, /*opset*/ 13, /*axis*/ 1, + {kTensorrtExecutionProvider, kOpenVINOExecutionProvider}); // OpenVINO doesn't support opset-13 yet + + RunTest(input_vals_60, expected_vals, four_dimensions, /*opset*/ 13, /*axis*/ 2, {kTensorrtExecutionProvider, kOpenVINOExecutionProvider}); // OpenVINO doesn't support opset-13 yet } -TEST(SoftmaxOperator, ThreeDimsAxis2) { - // x = +TEST(SoftmaxOperator, ThreeAndFourDimsLastAxis) { + // x = // node = onnx.helper.make_node('Softmax', inputs = ['x'], outputs = ['y'], axis = 2) // y = softmax_2d(x.reshape(12, 5)).reshape(3, 4, 5) // expect(node, inputs = [x], outputs = [y], @@ -240,10 +257,11 @@ TEST(SoftmaxOperator, ThreeDimsAxis2) { 0.23619612f, 0.1829779f, 0.37029108f, 0.14383113f, 0.0667037f, 0.15740506f, 0.13165872f, 0.31243387f, 0.24108529f, 0.15741715f}; - RunTest(x_vals_3dims, expected_vals, three_dimensions, /*opset*/ 7, /*axis*/ 2); + RunTest(input_vals_60, expected_vals, three_dimensions, /*opset*/ 7, /*axis*/ 2); + RunTest(input_vals_60, expected_vals, four_dimensions, /*opset*/ 7, /*axis*/ 3); } -TEST(SoftmaxOperator, ThreeDimsAxis2_opset13) { +TEST(SoftmaxOperator, ThreeAndFourDimsLastAxis_opset13) { std::vector expected_vals = { 0.22277209f, 0.20394778f, 0.09983283f, 0.33927578f, 0.13417149f, 0.21729809f, 0.47177994f, 0.06399124f, 0.14778666f, 0.099144064f, @@ -260,11 +278,14 @@ TEST(SoftmaxOperator, ThreeDimsAxis2_opset13) { 0.23619612f, 0.1829779f, 0.37029108f, 0.14383113f, 0.0667037f, 0.15740506f, 0.13165872f, 0.31243387f, 0.24108529f, 0.15741715f}; - RunTest(x_vals_3dims, expected_vals, three_dimensions, /*opset*/ 13, /*axis*/ 2, + RunTest(input_vals_60, expected_vals, three_dimensions, /*opset*/ 13, /*axis*/ 2, + {kOpenVINOExecutionProvider}); // OpenVINO doesn't support opset-13 yet + + RunTest(input_vals_60, expected_vals, four_dimensions, /*opset*/ 13, /*axis*/ 3, {kOpenVINOExecutionProvider}); // OpenVINO doesn't support opset-13 yet } -TEST(SoftmaxOperator, ThreeDimsDefaultAxis_opset13) { +TEST(SoftmaxOperator, ThreeAndFourDimsDefaultAxis_opset13) { std::vector expected_vals = { 0.22277209f, 0.20394778f, 0.09983283f, 0.33927578f, 0.13417149f, 0.21729809f, 0.47177994f, 0.06399124f, 0.14778666f, 0.099144064f, @@ -281,11 +302,15 @@ TEST(SoftmaxOperator, ThreeDimsDefaultAxis_opset13) { 0.23619612f, 0.1829779f, 0.37029108f, 0.14383113f, 0.0667037f, 0.15740506f, 0.13165872f, 0.31243387f, 0.24108529f, 0.15741715f}; - RunTest(x_vals_3dims, expected_vals, three_dimensions, /*opset*/ 13, /*default axis*/ -1, + RunTest(input_vals_60, expected_vals, three_dimensions, /*opset*/ 13, /*default axis*/ -1, + {kOpenVINOExecutionProvider}); // OpenVINO doesn't support opset-13 yet + + RunTest(input_vals_60, expected_vals, four_dimensions, /*opset*/ 13, /*default axis*/ -1, {kOpenVINOExecutionProvider}); // OpenVINO doesn't support opset-13 yet } -TEST(SoftmaxOperator, ThreeDimsNegativeAxis) { - // x = + +TEST(SoftmaxOperator, ThreeAndFourDimsNegativeAxis) { + // x = // node = onnx.helper.make_node('Softmax', inputs = ['x'], outputs = ['y'], axis = 2) // y = softmax_2d(x.reshape(12, 5)).reshape(3, 4, 5) // expect(node, inputs = [x], outputs = [y], @@ -308,7 +333,8 @@ TEST(SoftmaxOperator, ThreeDimsNegativeAxis) { 0.15740506f, 0.13165872f, 0.31243387f, 0.24108529f, 0.15741715f}; // -1 is last axis so same as axis == 2 - RunTest(x_vals_3dims, expected_vals, three_dimensions, /*opset*/ 12, /*axis*/ -1); + RunTest(input_vals_60, expected_vals, three_dimensions, /*opset*/ 12, /*axis*/ -1); + RunTest(input_vals_60, expected_vals, four_dimensions, /*opset*/ 12, /*axis*/ -1); } TEST(SoftmaxOperator, InvalidAxis) { @@ -379,5 +405,24 @@ TEST(SoftmaxOperator, 2DInputReduceOnAxis1WithLargeDim) { RunTest(x_vals, expected_vals, dimensions); } +// Regression test for NNAPI handling of a Softmax with opset < 13 where the input has been converted to NHWC. +// The NNAPI handling of the axis is different so we need to manually coerce the input to 2D, which will negate the +// layout change. Test model has a GlobalAveragePool -> Softmax which will trigger the layout change due to +// GlobalAveragePool being layout sensitive. +TEST(SoftmaxOperator, GH15949_regression_test) { + auto model_uri = ORT_TSTR("testdata/ort_github_issue_15949.onnx"); + ModelTester tester("Opset12NhwcSoftmax", model_uri); + + tester.AddInput("X", {1, 3, 2, 2}, + {0.f, 1.f, 2.f, 3.f, + 4.f, 5.f, 6.f, 7.f, + 8.f, 9.f, 10.f, 11.f}); + tester.AddOutput("Y", {1, 3, 1, 1}, + {0.00032932f, 0.01798029f, 0.9816904f}); + + // disable TRT as it does not support axis=0 as used by the model + tester.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kCoreMLExecutionProvider}); +} + } // namespace test } // namespace onnxruntime diff --git a/onnxruntime/test/providers/cpu/math/topk_op_test.cc b/onnxruntime/test/providers/cpu/math/topk_op_test.cc index 11764276f1fe8..e85599e063aaf 100644 --- a/onnxruntime/test/providers/cpu/math/topk_op_test.cc +++ b/onnxruntime/test/providers/cpu/math/topk_op_test.cc @@ -591,7 +591,7 @@ static void top_3_explicit_aix_infinity(int opset_version, bool positive) { std::vector expected_indices = {0, 0, 1, 1, 2, 2}; std::vector expected_dimensions = {3, 2}; int64_t axis = 0; - RunTest(opset_version, 3, input_vals, input_dimensions, expected_vals, expected_indices, expected_dimensions, false, axis, 0, 1); + RunTest(opset_version, 3, input_vals, input_dimensions, expected_vals, expected_indices, expected_dimensions, true, axis, 0, 1); } TEST(TopKOperator, Top3ExplicitAxisInfinity) { diff --git a/onnxruntime/test/providers/cpu/model_tests.cc b/onnxruntime/test/providers/cpu/model_tests.cc index 9886d9fdd7d5e..9b41ba8c0d2ba 100644 --- a/onnxruntime/test/providers/cpu/model_tests.cc +++ b/onnxruntime/test/providers/cpu/model_tests.cc @@ -108,24 +108,6 @@ TEST_P(ModelTest, Run) { } std::unique_ptr model_info = std::make_unique(model_path.c_str()); - if (model_info->GetONNXOpSetVersion() != 14 && model_info->GetONNXOpSetVersion() != 15 && - provider_name == "tensorrt") { - // TensorRT can run most of the model tests, but only part of - // them is enabled here to save CI build time. - // Besides saving CI build time, TRT isn’t able to support full ONNX ops spec and therefore some testcases will - // fail. That's one of reasons we skip those testcases and only test latest ONNX opsets. - SkipTest(" tensorrt only support opset 14 or 15"); - return; - } - - if ((model_info->GetONNXOpSetVersion() == 10 || model_info->GetONNXOpSetVersion() >= 18) && provider_name == "dnnl") { - // DNNL can run most of the model tests, but only part of - // them is enabled here to save CI build time. - std::ostringstream oss; - oss << " dnnl doesn't support opset " << model_info->GetONNXOpSetVersion(); - SkipTest(oss.str()); - return; - } if (model_info->HasDomain(ONNX_NAMESPACE::AI_ONNX_TRAINING_DOMAIN) || model_info->HasDomain(ONNX_NAMESPACE::AI_ONNX_PREVIEW_TRAINING_DOMAIN)) { @@ -268,6 +250,9 @@ TEST_P(ModelTest, Run) { #ifdef _WIN32 broken_tests.insert({"LSTM_Seq_lens_unpacked", "this test fails with new image since Aug 25."}); broken_tests.insert({"bidaf", "this test fails with new image since Aug 25."}); + broken_tests.insert({"Candy", "Flaky test, need to investigate", {"opset9"}}); +#else + broken_tests.insert({"bidaf", "this test should be recovered when multi-gpu pipeline deprecates NV12", {"opset9"}}); #endif } @@ -452,6 +437,22 @@ TEST_P(ModelTest, Run) { broken_tests.insert({"conv_with_autopad_same", "Internal Error (node_of_y: Cannot set more than one input unless network has Q/DQ layers.)"}); + // unsupported tests since opset16 + broken_tests.insert({"sequence_map_add_2_sequences", "not supported by TensorRT EP"}); + broken_tests.insert({"sequence_map_extract_shapes", "not supported by TensorRT EP."}); + broken_tests.insert({"sequence_map_add_1_sequence_1_tensor", "not supported by TensorRT EP."}); + broken_tests.insert({"sequence_map_identity_1_sequence", "not supported by TensorRT EP."}); + broken_tests.insert({"sequence_map_identity_2_sequences", "not supported by TensorRT EP."}); + broken_tests.insert({"sequence_map_identity_1_sequence_1_tensor", "not supported by TensorRT EP."}); + broken_tests.insert({"leakyrelu_expanded", "not supported by TensorRT EP."}); + broken_tests.insert({"leakyrelu_default_expanded", "not supported by TensorRT EP."}); + broken_tests.insert({"leakyrelu_example_expanded", "not supported by TensorRT EP."}); + broken_tests.insert({"prelu_broadcast_expanded", "not supported by TensorRT EP."}); + broken_tests.insert({"prelu_example_expanded", "not supported by TensorRT EP."}); + broken_tests_keyword_set.insert({"scatternd_add"}); + broken_tests_keyword_set.insert({"scatternd_multiply"}); + broken_tests_keyword_set.insert({"scatter_elements_with_duplicate_indices"}); + // sce op is not supported broken_tests_keyword_set.insert({"sce"}); @@ -666,6 +667,12 @@ TEST_P(ModelTest, Run) { ASSERT_ORT_STATUS_OK(OrtApis::CreateCUDAProviderOptions(&cuda_options)); std::unique_ptr rel_cuda_options( cuda_options, &OrtApis::ReleaseCUDAProviderOptions); + std::vector keys{"device_id"}; + + std::vector values; + std::string device_id = Env::Default().GetEnvironmentVar("ONNXRUNTIME_TEST_GPU_DEVICE_ID"); + values.push_back(device_id.empty() ? "0" : device_id.c_str()); + ASSERT_ORT_STATUS_OK(OrtApis::UpdateCUDAProviderOptions(cuda_options, keys.data(), values.data(), 1)); ortso.AppendExecutionProvider_CUDA_V2(*cuda_options); } else if (provider_name == "rocm") { OrtROCMProviderOptions ep_options; @@ -686,7 +693,8 @@ TEST_P(ModelTest, Run) { OrtTensorRTProviderOptionsV2 params{0, 0, nullptr, 1000, 1, 1 << 30, 1, // enable fp16 0, nullptr, 0, 0, 0, 0, 0, nullptr, 0, nullptr, 0, 0, 0, 0, 0, 0, 0, 0, - 2, -1, nullptr, nullptr}; + 3, -1, nullptr, nullptr, nullptr, nullptr, nullptr, 0}; + ortso.AppendExecutionProvider_TensorRT_V2(params); } else { OrtTensorRTProviderOptionsV2* ep_option = nullptr; @@ -850,44 +858,89 @@ TEST_P(ModelTest, Run) { } } -// TODO: all providers -::std::vector<::std::basic_string> GetParameterStrings() { - std::vector provider_names; - provider_names.push_back(ORT_TSTR("cpu")); +using ORT_STRING_VIEW = std::basic_string_view; +static ORT_STRING_VIEW opset7 = ORT_TSTR("opset7"); +static ORT_STRING_VIEW opset8 = ORT_TSTR("opset8"); +static ORT_STRING_VIEW opset9 = ORT_TSTR("opset9"); +static ORT_STRING_VIEW opset10 = ORT_TSTR("opset10"); +static ORT_STRING_VIEW opset11 = ORT_TSTR("opset11"); +static ORT_STRING_VIEW opset12 = ORT_TSTR("opset12"); +static ORT_STRING_VIEW opset13 = ORT_TSTR("opset13"); +static ORT_STRING_VIEW opset14 = ORT_TSTR("opset14"); +static ORT_STRING_VIEW opset15 = ORT_TSTR("opset15"); +static ORT_STRING_VIEW opset16 = ORT_TSTR("opset16"); +static ORT_STRING_VIEW opset17 = ORT_TSTR("opset17"); +static ORT_STRING_VIEW opset18 = ORT_TSTR("opset18"); +// TODO: enable opset19 tests +// static ORT_STRING_VIEW opset19 = ORT_TSTR("opset19"); + +static ORT_STRING_VIEW provider_name_cpu = ORT_TSTR("cpu"); +static ORT_STRING_VIEW provider_name_tensorrt = ORT_TSTR("tensorrt"); +#ifdef USE_MIGRAPHX +static ORT_STRING_VIEW provider_name_migraphx = ORT_TSTR("migraphx"); +#endif +static ORT_STRING_VIEW provider_name_openvino = ORT_TSTR("openvino"); +static ORT_STRING_VIEW provider_name_cuda = ORT_TSTR("cuda"); +#ifdef USE_ROCM +static ORT_STRING_VIEW provider_name_rocm = ORT_TSTR("rocm"); +#endif +static ORT_STRING_VIEW provider_name_dnnl = ORT_TSTR("dnnl"); +// For any non-Android system, NNAPI will only be used for ort model converter +#if defined(USE_NNAPI) && defined(__ANDROID__) +static ORT_STRING_VIEW provider_name_nnapi = ORT_TSTR("nnapi"); +#endif +#ifdef USE_RKNPU +static ORT_STRING_VIEW provider_name_rknpu = ORT_TSTR("rknpu"); +#endif +#ifdef USE_ACL +static ORT_STRING_VIEW provider_name_acl = ORT_TSTR("acl"); +#endif +#ifdef USE_ARMNN +static ORT_STRING_VIEW provider_name_armnn = ORT_TSTR("armnn"); +#endif +static ORT_STRING_VIEW provider_name_dml = ORT_TSTR("dml"); +::std::vector<::std::basic_string> GetParameterStrings() { + // Map key is provider name(CPU, CUDA, etc). Value is the ONNX node tests' opsets to run. + std::map> provider_names; + // The default CPU provider always supports all opsets, and must maintain backwards compatibility. + provider_names[provider_name_cpu] = {opset7, opset8, opset9, opset10, opset11, opset12, opset13, opset14, opset15, opset16, opset17, opset18}; + // 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 - provider_names.push_back(ORT_TSTR("tensorrt")); + // 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.push_back(ORT_TSTR("migraphx")); + provider_names[provider_name_migraphx] = {opset7, opset8, opset9, opset10, opset11, opset12, opset13, opset14, opset15, opset16, opset17, opset18}; #endif #ifdef USE_OPENVINO - provider_names.push_back(ORT_TSTR("openvino")); + provider_names[provider_name_openvino] = {}; #endif #ifdef USE_CUDA - provider_names.push_back(ORT_TSTR("cuda")); + provider_names[provider_name_cuda] = {opset7, opset8, opset9, opset10, opset11, opset12, opset13, opset14, opset15, opset16, opset17, opset18}; #endif #ifdef USE_ROCM - provider_names.push_back(ORT_TSTR("rocm")); + provider_names[provider_name_rocm] = {opset7, opset8, opset9, opset10, opset11, opset12, opset13, opset14, opset15, opset16, opset17, opset18}; #endif #ifdef USE_DNNL - provider_names.push_back(ORT_TSTR("dnnl")); + provider_names[provider_name_dnnl] = {opset10}; #endif // For any non-Android system, NNAPI will only be used for ort model converter #if defined(USE_NNAPI) && defined(__ANDROID__) - provider_names.push_back(ORT_TSTR("nnapi")); + provider_names[provider_name_nnapi] = {opset7, opset8, opset9, opset10, opset11, opset12, opset13, opset14, opset15, opset16, opset17, opset18}; #endif #ifdef USE_RKNPU - provider_names.push_back(ORT_TSTR("rknpu")); + provider_names[provider_name_rknpu] = {}; #endif #ifdef USE_ACL - provider_names.push_back(ORT_TSTR("acl")); + provider_names[provider_name_acl] = {}; #endif #ifdef USE_ARMNN - provider_names.push_back(ORT_TSTR("armnn")); + provider_names[provider_name_armnn] = {}; #endif #ifdef USE_DML - provider_names.push_back(ORT_TSTR("dml")); + provider_names[provider_name_dml] = {opset7, opset8, opset9, opset10, opset11, opset12, opset13, opset14, opset15, opset16, opset17, opset18}; #endif std::vector> v; // Permanently exclude following tests because ORT support only opset starting from 7, @@ -1017,6 +1070,7 @@ ::std::vector<::std::basic_string> GetParameterStrings() { ORT_TSTR("batchnorm_example_training_mode"), ORT_TSTR("batchnorm_epsilon_training_mode"), ORT_TSTR("mobilenetv2-1.0"), + ORT_TSTR("shufflenet"), ORT_TSTR("candy"), ORT_TSTR("range_float_type_positive_delta_expanded"), ORT_TSTR("range_int32_type_negative_delta_expanded"), @@ -1062,22 +1116,51 @@ ::std::vector<::std::basic_string> GetParameterStrings() { ORT_TSTR("conv_with_strides_padding"), ORT_TSTR("size") // INVALID_ARGUMENT: Cannot find binding of given name: x }; - for (const ORTCHAR_T* provider_name : provider_names) { + std::vector> paths; + + for (std::pair> kvp : provider_names) { + // Setup ONNX node tests. The test data is preloaded on our CI build machines. +#if !defined(_WIN32) + ORT_STRING_VIEW node_test_root_path = ORT_TSTR("/data/onnx"); +#else + ORT_STRING_VIEW node_test_root_path = ORT_TSTR("c:\\local\\data\\onnx"); +#endif + for (auto p : kvp.second) { + paths.push_back(ConcatPathComponent(node_test_root_path, p)); + } + + // Same as the above, except this one is for large models +#if defined(NDEBUG) || defined(RUN_MODELTEST_IN_DEBUG_MODE) +#ifdef _WIN32 + ORT_STRING_VIEW model_test_root_path = ORT_TSTR("..\\models"); + // thus, only the root path should be mounted. + ORT_STRING_VIEW model_zoo_path = ORT_TSTR("..\\models\\zoo"); +#else + ORT_STRING_VIEW model_test_root_path = ORT_TSTR("../models"); + ORT_STRING_VIEW model_zoo_path = ORT_TSTR("../models/zoo"); +#endif + for (auto p : kvp.second) { + paths.push_back(ConcatPathComponent(model_test_root_path, p)); + paths.push_back(ConcatPathComponent(model_zoo_path, p)); + } +#endif + + ORT_STRING_VIEW provider_name = kvp.first; std::unordered_set> all_disabled_tests(std::begin(immutable_broken_tests), std::end(immutable_broken_tests)); - if (CompareCString(provider_name, ORT_TSTR("cuda")) == 0) { + if (provider_name == provider_name_cuda) { all_disabled_tests.insert(std::begin(cuda_flaky_tests), std::end(cuda_flaky_tests)); - } else if (CompareCString(provider_name, ORT_TSTR("dml")) == 0) { + } else if (provider_name == provider_name_dml) { all_disabled_tests.insert(std::begin(dml_disabled_tests), std::end(dml_disabled_tests)); - } else if (CompareCString(provider_name, ORT_TSTR("dnnl")) == 0) { + } else if (provider_name == provider_name_dnnl) { // these models run but disabled tests to keep memory utilization low // This will be removed after LRU implementation all_disabled_tests.insert(std::begin(dnnl_disabled_tests), std::end(dnnl_disabled_tests)); - } else if (CompareCString(provider_name, ORT_TSTR("tensorrt")) == 0) { + } else if (provider_name == provider_name_tensorrt) { // these models run but disabled tests to keep memory utilization low // This will be removed after LRU implementation all_disabled_tests.insert(std::begin(tensorrt_disabled_tests), std::end(tensorrt_disabled_tests)); - } else if (CompareCString(provider_name, ORT_TSTR("openvino")) == 0) { + } else if (provider_name == provider_name_openvino) { // these models run but disabled tests to keep memory utilization low // This will be removed after LRU implementation all_disabled_tests.insert(std::begin(openvino_disabled_tests), std::end(openvino_disabled_tests)); @@ -1105,24 +1188,10 @@ ::std::vector<::std::basic_string> GetParameterStrings() { ORT_TSTR("SSD")}; all_disabled_tests.insert(std::begin(x86_disabled_tests), std::end(x86_disabled_tests)); #endif - - std::vector> paths; -#if defined(NDEBUG) || defined(RUN_MODELTEST_IN_DEBUG_MODE) -#ifdef _WIN32 - paths.push_back(ORT_TSTR("..\\models")); -#else - paths.push_back(ORT_TSTR("../models")); -#endif -#endif - -// TENSORRT/OpenVino has too many test failures in the single node tests -#if !defined(USE_OPENVINO) -#if !defined(_WIN32) - paths.push_back(ORT_TSTR("/data/onnx")); -#else - paths.push_back(ORT_TSTR("c:\\local\\data\\onnx")); -#endif -#endif + // fp16 models have different outputs with different kinds of hardware. We need to disable all fp16 models + all_disabled_tests.insert(ORT_TSTR("fp16_shufflenet")); + all_disabled_tests.insert(ORT_TSTR("fp16_inception_v1")); + all_disabled_tests.insert(ORT_TSTR("fp16_tiny_yolov2")); while (!paths.empty()) { std::basic_string node_data_root_path = paths.back(); @@ -1133,7 +1202,7 @@ ::std::vector<::std::basic_string> GetParameterStrings() { if (filename[0] == ORT_TSTR('.')) return true; if (f_type == OrtFileType::TYPE_DIR) { - std::basic_string p = ConcatPathComponent(node_data_root_path, filename); + std::basic_string p = ConcatPathComponent(node_data_root_path, filename); paths.push_back(p); return true; } @@ -1156,10 +1225,9 @@ ::std::vector<::std::basic_string> GetParameterStrings() { return true; } #endif - std::basic_string p = ConcatPathComponent(node_data_root_path, filename_str); - std::basic_string r = provider_name; - r.append(ORT_TSTR("_")).append(p); - v.emplace_back(r); + std::basic_ostringstream oss; + oss << provider_name << ORT_TSTR("_") << ConcatPathComponent(node_data_root_path, filename_str); + v.emplace_back(oss.str()); return true; }); } 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 d11fc37856af7..ee18cf2cea6cb 100644 --- a/onnxruntime/test/providers/cpu/nn/batch_norm_op_test.cc +++ b/onnxruntime/test/providers/cpu/nn/batch_norm_op_test.cc @@ -50,7 +50,7 @@ void TestBatchNorm(const unordered_map>& input_data_map, } // OpenVINO: Disabled due to software limitations -#if defined(OPENVINO_CONFIG_GPU_FP32) || defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_MYRIAD) || defined(OPENVINO_CONFIG_VAD_M) || defined(OPENVINO_CONFIG_CPU_FP32) || defined(OPENVINO_CONFIG_CPU_FP16) +#if defined(OPENVINO_CONFIG_GPU_FP32) || defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_CPU_FP32) || defined(OPENVINO_CONFIG_CPU_FP16) excluded_eps.insert(kOpenVINOExecutionProvider); #endif test.Run(expect_result, err_str, excluded_eps); diff --git a/onnxruntime/test/providers/cpu/nn/conv_op_test.cc b/onnxruntime/test/providers/cpu/nn/conv_op_test.cc index 49839811aaef6..e01fd8c78e55f 100644 --- a/onnxruntime/test/providers/cpu/nn/conv_op_test.cc +++ b/onnxruntime/test/providers/cpu/nn/conv_op_test.cc @@ -59,10 +59,17 @@ void TestConvOp(const ConvOpAndTestAttributes& attributes, std::unordered_set excluded_providers(attributes.excluded_providers); // Disable TensorRT because weight as input is not supported excluded_providers.insert(kTensorrtExecutionProvider); + + // QNN SDK 2.10.0 has a bug that breaks support for dynamic bias inputs. + excluded_providers.insert(kQnnExecutionProvider); + + // TODO: Enable QNN EP when bug with QNN SDK 2.10.0 is fixed: + /* // QNN have issue with dynamic weight, auto pad with SAME_UPPER, SAME_LOWER if (!weight_is_initializer || attributes.auto_pad == "SAME_UPPER" || attributes.auto_pad == "SAME_LOWER") { excluded_providers.insert(kQnnExecutionProvider); } + */ test.Run(expect_result, err_str, excluded_providers); } diff --git a/onnxruntime/test/providers/cpu/nn/flatten_op_test.cc b/onnxruntime/test/providers/cpu/nn/flatten_op_test.cc index abda93fdd4b05..11a9f626d5709 100644 --- a/onnxruntime/test/providers/cpu/nn/flatten_op_test.cc +++ b/onnxruntime/test/providers/cpu/nn/flatten_op_test.cc @@ -2,6 +2,8 @@ // Licensed under the MIT License. #include "gtest/gtest.h" + +#include "core/session/environment.h" #include "test/providers/provider_test_utils.h" namespace onnxruntime { @@ -47,11 +49,7 @@ TEST_F(FlattenOpTest, Flatten_axis3) { test_.AddAttribute("axis", 3L); test_.AddInput("data", {2L, 3L, 4L, 5L}, data0_); test_.AddOutput("output", {24L, 5L}, data0_); -#if defined(OPENVINO_CONFIG_MYRIAD) || defined(OPENVINO_CONFIG_VAD_M) // TBD temporarily disabling for openvino - test_.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kOpenVINOExecutionProvider}); -#else test_.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); -#endif } TEST_F(FlattenOpTest, Flatten_axis4) { @@ -65,12 +63,35 @@ TEST_F(FlattenOpTest, Flatten_neg_axis3) { test_.AddAttribute("axis", -1L); test_.AddInput("data", {2L, 3L, 4L, 5L}, data0_); test_.AddOutput("output", {24L, 5L}, data0_); -#if defined(OPENVINO_CONFIG_MYRIAD) || defined(OPENVINO_CONFIG_VAD_M) // TBD temporarily disabling for openvino - test_.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kOpenVINOExecutionProvider}); -#else test_.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); -#endif } +// Regression test primarily for CoreML. +// The CoreML EP implementation was not reading the axis attribute correctly causing an incorrect output shape to be +// produced for a Flatten node. That issue gets hidden as the Tensor to write the output to is created by the +// CoreML EP using the inferred output shape (which is correct) and we provide the Tensor's buffer but not the shape +// when executing the CoreML model. As the flatten isn't changing or moving any data nothing breaks when we test +// with only a Flatten node in the model. +// +// This test uses a model with a Flatten followed by a Mul which requires broadcasting. Both nodes are handled by +// CoreML, so if the axis is not correctly processed the output from Flatten will not be broadcastable and the CoreML +// model execution will fail. +TEST(FlattenOpModelTest, Flatten_broadcast) { + auto model_uri = ORT_TSTR("testdata/flatten_broadcast.onnx"); + ModelTester tester("flatten_broadcast", model_uri); + + tester.AddInput("X", {4}, {0.f, 1.f, 2.f, 3.f}); + tester.AddInput("Y", {3, 4}, + {0.f, 1.f, 2.f, 3.f, + 4.f, 5.f, 6.f, 7.f, + 8.f, 9.f, 10.f, 11.f}); + tester.AddOutput("Z", {3, 4}, + {0.f, 1.f, 4.f, 9.f, + 0.f, 5.f, 12.f, 21.f, + 0.f, 9.f, 20.f, 33.f}); + + // disable TRT as it does not support axis=0 as used by the model + tester.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); +} } // namespace test } // namespace onnxruntime 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 6e622d47ebe6a..31f119ec6b0e9 100644 --- a/onnxruntime/test/providers/cpu/nn/instance_norm_op_test.cc +++ b/onnxruntime/test/providers/cpu/nn/instance_norm_op_test.cc @@ -41,11 +41,7 @@ TEST(InstanceNormalizationOpTest, InstanceNorm) { -0.14644464F, -0.82262872F, -0.66852817F, 1.63760153F, -1.65898662F, 0.27618144F, 0.64840618F, 0.734399F}; test.AddOutput("Y", input_dims, expected_output); -#if defined(OPENVINO_CONFIG_MYRIAD) // Disabling this test on MYRIADX temporarily due to a bug - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); -#else test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); -#endif } TEST(InstanceNormalizationOpTest, InstanceNormBatch1) { @@ -71,11 +67,7 @@ TEST(InstanceNormalizationOpTest, InstanceNormBatch1) { 0.57370438F, 0.42193634F, 0.6525492F, -1.64818992F}; test.AddOutput("Y", input_dims, expected_output); -#if defined(OPENVINO_CONFIG_MYRIAD) // Disabling this test on MYRIADX temporarily due to a bug - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); -#else test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); -#endif } TEST(InstanceNormalizationOpTest, InstanceNormBatch2) { @@ -109,11 +101,7 @@ TEST(InstanceNormalizationOpTest, InstanceNormBatch2) { 0.57370438F, 0.42193634F, 0.6525492F, -1.64818992F}; test.AddOutput("Y", input_dims, expected_output); -#if defined(OPENVINO_CONFIG_MYRIAD) // Disabling this test on MYRIADX temporarily due to a bug - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); -#else test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); -#endif } // Only CUDA and ROCm kernels have float 16 support @@ -155,11 +143,7 @@ TEST(InstanceNormalizationOpTest, InstanceNormBatch1_fp16) { test.AddInput("B", {3}, B_fp16); test.AddOutput("Y", input_dims, expected_output_fp16); -#if defined(OPENVINO_CONFIG_MYRIAD) // Disabling this test on MYRIADX temporarily due to a bug - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); -#else test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); -#endif } TEST(InstanceNormalizationOpTest, InstanceNormBatch2_fp16) { @@ -206,11 +190,7 @@ TEST(InstanceNormalizationOpTest, InstanceNormBatch2_fp16) { test.AddInput("B", {3}, B_fp16); test.AddOutput("Y", input_dims, expected_output_fp16); -#if defined(OPENVINO_CONFIG_MYRIAD) // Disabling this test on MYRIADX temporarily due to a bug - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); -#else test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); -#endif } #endif @@ -254,11 +234,7 @@ TEST(InstanceNormalizationOpTest, InstanceNorm_2) { 1.88028F, 2.353724F, -0.25549555F, 2.0837004F, 2.8466992F, 2.0773761F}; test.AddOutput("Y", input_dims, expected_output); -#if defined(OPENVINO_CONFIG_MYRIAD) // Disabling this test on MYRIADX temporarily due to a bug - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); -#else test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); -#endif } TEST(InstanceNormalizationOpTest, InstanceNormNCHW) { @@ -281,11 +257,8 @@ TEST(InstanceNormalizationOpTest, InstanceNormNCHW) { test.AddOutput("Y", input_dims, expected_output); test.Run(OpTester::ExpectResult::kExpectSuccess, "", { - kTensorrtExecutionProvider, -#if defined(OPENVINO_CONFIG_MYRIAD) // Disabling this test on MYRIADX temporarily due to a bug - kOpenVINOExecutionProvider, -#endif - }); + kTensorrtExecutionProvider, + }); } } // namespace test diff --git a/onnxruntime/test/providers/cpu/nn/pool_op_test.cc b/onnxruntime/test/providers/cpu/nn/pool_op_test.cc index bf2c4740fa3e6..10476ada2fa69 100644 --- a/onnxruntime/test/providers/cpu/nn/pool_op_test.cc +++ b/onnxruntime/test/providers/cpu/nn/pool_op_test.cc @@ -301,7 +301,7 @@ TEST(PoolTest, MaxPool2D_uint8) { test.AddInput("Input", {1, 1, 5, 5}, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25}); test.AddOutput("Output", output_shape, output); -#if defined(OPENVINO_CONFIG_GPU_FP32) || defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_MYRIAD) +#if defined(OPENVINO_CONFIG_GPU_FP32) || defined(OPENVINO_CONFIG_GPU_FP16) test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); #else test.Run(); @@ -938,6 +938,35 @@ TEST(PoolTest, AveragePool_10_ceil1_2d) { test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kAclExecutionProvider}); } +TEST(PoolTest, AveragePool_19_dilation_2d) { + // TODO: Unskip when fixed #41968513 + if (DefaultDmlExecutionProvider().get() != nullptr) { + GTEST_SKIP() << "Skipping because of the following error: MLOperatorAuthorImpl.cpp(2100): The parameter is incorrect."; + } + + OpTester test("AveragePool", 19); + + test.AddAttribute("auto_pad", ""); + test.AddAttribute("strides", std::vector{1, 1}); + test.AddAttribute("dilations", std::vector{2, 2}); + test.AddAttribute("pads", vector{0, 0, 0, 0}); + test.AddAttribute("kernel_shape", vector{2, 2}); + test.AddAttribute("ceil_mode", (int64_t)1); + + std::vector x_vals = { + 1, 3, 2, 4, + 5, 7, 6, 8, + 9, 11, 10, 12, + 13, 15, 14, 16}; + std::vector x_dims = {1, 1, 4, 4}; + std::vector expected_dims = {1, 1, 2, 2}; + std::vector expected_vals = {5.5f, 7.5f, 9.5f, 11.5f}; + + test.AddInput("X", x_dims, x_vals); + test.AddOutput("Y", expected_dims, expected_vals); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kAclExecutionProvider, kOpenVINOExecutionProvider}); +} + TEST(PoolTest, GlobalAveragePool) { OpTester test("GlobalAveragePool"); diff --git a/onnxruntime/test/providers/cpu/nn/shrink_test.cc b/onnxruntime/test/providers/cpu/nn/shrink_test.cc index e2ed27d232d14..ef6727c6363ba 100644 --- a/onnxruntime/test/providers/cpu/nn/shrink_test.cc +++ b/onnxruntime/test/providers/cpu/nn/shrink_test.cc @@ -90,7 +90,7 @@ void RunShrinkTest(const std::vector>& test_cases, const std::vector ConvertFloatToMLFloat16(const std::vector& float_data) { std::vector new_data; for (const auto& f : float_data) { - new_data.push_back(MLFloat16(math::floatToHalf(f))); + new_data.push_back(MLFloat16(f)); } return new_data; } diff --git a/onnxruntime/test/providers/cpu/object_detection/roialign_test.cc b/onnxruntime/test/providers/cpu/object_detection/roialign_test.cc index a7cc7c536a19e..2f97f6e71e92b 100644 --- a/onnxruntime/test/providers/cpu/object_detection/roialign_test.cc +++ b/onnxruntime/test/providers/cpu/object_detection/roialign_test.cc @@ -9,11 +9,10 @@ namespace onnxruntime { namespace test { TEST(RoiAlignTest, AvgModePositive) { - // TODO: Unskip when fixed #41968513 + // TODO: Unskip when fixed ort issue #3428 if (DefaultDmlExecutionProvider().get() != nullptr) { GTEST_SKIP() << "Skipping because of the following error: The difference between expected[i] and output[i] is 2.9583299160003662, which exceeds threshold"; } - OpTester test("RoiAlign", 10); test.AddAttribute("output_height", 3); test.AddAttribute("output_width", 4); @@ -30,7 +29,241 @@ TEST(RoiAlignTest, AvgModePositive) { test.AddInput("rois", {5, 4}, {7., 5., 7., 5., -15., -15., -15., -15., -10., 21., -10., 21., 13., 8., 13., 8., -14., 19., -14., 19.}); test.AddInput("batch_indices", {5}, {0, 0, 0, 0, 0}); test.AddOutput("Y", {5, 3, 3, 4}, {2.95833f, 3.20833f, 3.45833f, 3.70833f, 4.625f, 4.875f, 5.125f, 5.375f, 6.29167f, 6.54167f, 6.79167f, 7.04167f, 27.9583f, 28.2083f, 28.4583f, 28.7083f, 29.625f, 29.875f, 30.125f, 30.375f, 31.2917f, 31.5417f, 31.7917f, 32.0417f, 52.9583f, 53.2083f, 53.4583f, 53.7083f, 54.625f, 54.875f, 55.125f, 55.375f, 56.2917f, 56.5417f, 56.7917f, 57.0417f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 25.f, 25.f, 25.f, 25.f, 25.f, 25.f, 25.f, 25.f, 25.f, 25.f, 25.f, 25.f, 50.f, 50.f, 50.f, 50.f, 50.f, 50.f, 50.f, 50.f, 50.f, 50.f, 50.f, 50.f, 7.39583f, 7.39583f, 7.42708f, 7.64583f, 9.0625f, 9.0625f, 9.09375f, 9.3125f, 10.7292f, 10.7292f, 10.7604f, 10.9792f, 32.3958f, 32.3958f, 32.4271f, 32.6458f, 34.0625f, 34.0625f, 34.0938f, 34.3125f, 35.7292f, 35.7292f, 35.7604f, 35.9792f, 57.3958f, 57.3958f, 57.4271f, 57.6458f, 59.0625f, 59.0625f, 59.0938f, 59.3125f, 60.7292f, 60.7292f, 60.7604f, 60.9792f, 4.27083f, 4.52083f, 4.77083f, 5.02083f, 5.9375f, 6.1875f, 6.4375f, 6.6875f, 7.60417f, 7.85417f, 8.10417f, 8.35417f, 29.2708f, 29.5208f, 29.7708f, 30.0208f, 30.9375f, 31.1875f, 31.4375f, 31.6875f, 32.6042f, 32.8542f, 33.1042f, 33.3542f, 54.2708f, 54.5208f, 54.7708f, 55.0208f, 55.9375f, 56.1875f, 56.4375f, 56.6875f, 57.6042f, 57.8542f, 58.1042f, 58.3542f, 6.77083f, 6.77083f, 6.77083f, 6.80208f, 8.4375f, 8.4375f, 8.4375f, 8.46875f, 10.1042f, 10.1042f, 10.1042f, 10.1354f, 31.7708f, 31.7708f, 31.7708f, 31.8021f, 33.4375f, 33.4375f, 33.4375f, 33.4688f, 35.1042f, 35.1042f, 35.1042f, 35.1354f, 56.7708f, 56.7708f, 56.7708f, 56.8021f, 58.4375f, 58.4375f, 58.4375f, 58.4688f, 60.1042f, 60.1042f, 60.1042f, 60.1354f}); + // DML has the correct outputs, which are defined below. + // These will replace the above outputs once https://github.com/microsoft/onnxruntime/issues/6921 is fixed. + /*test.AddOutput("Y", {5, 3, 3, 4}, { + 2.0000, + 2.0000, + 2.0000, + 2.0000, + 2.0000, + 2.0000, + 2.0000, + 2.0000, + 2.0000, + 2.0000, + 2.0000, + 2.0000, + 27.0000, + 27.0000, + 27.0000, + 27.0000, + 27.0000, + 27.0000, + 27.0000, + 27.0000, + 27.0000, + 27.0000, + 27.0000, + 27.0000, + 52.0000, + 52.0000, + 52.0000, + 52.0000, + 52.0000, + 52.0000, + 52.0000, + 52.0000, + 52.0000, + 52.0000, + 52.0000, + 52.0000, + + 0.0000, + 0.0000, + 0.0000, + 0.0000, + 0.0000, + 0.0000, + 0.0000, + 0.0000, + 0.0000, + 0.0000, + 0.0000, + 0.0000, + 25.0000, + 25.0000, + 25.0000, + 25.0000, + 25.0000, + 25.0000, + 25.0000, + 25.0000, + 25.0000, + 25.0000, + 25.0000, + 25.0000, + 50.0000, + 50.0000, + 50.0000, + 50.0000, + 50.0000, + 50.0000, + 50.0000, + 50.0000, + 50.0000, + 50.0000, + 50.0000, + 50.0000, + + 6.5625, + 6.5625, + 6.5625, + 6.5625, + 6.5625, + 6.5625, + 6.5625, + 6.5625, + 6.5625, + 6.5625, + 6.5625, + 6.5625, + 31.5625, + 31.5625, + 31.5625, + 31.5625, + 31.5625, + 31.5625, + 31.5625, + 31.5625, + 31.5625, + 31.5625, + 31.5625, + 31.5625, + 56.5625, + 56.5625, + 56.5625, + 56.5625, + 56.5625, + 56.5625, + 56.5625, + 56.5625, + 56.5625, + 56.5625, + 56.5625, + 56.5625, + + 3.3125, + 3.3125, + 3.3125, + 3.3125, + 3.3125, + 3.3125, + 3.3125, + 3.3125, + 3.3125, + 3.3125, + 3.3125, + 3.3125, + 28.3125, + 28.3125, + 28.3125, + 28.3125, + 28.3125, + 28.3125, + 28.3125, + 28.3125, + 28.3125, + 28.3125, + 28.3125, + 28.3125, + 53.3125, + 53.3125, + 53.3125, + 53.3125, + 53.3125, + 53.3125, + 53.3125, + 53.3125, + 53.3125, + 53.3125, + 53.3125, + 53.3125, + + 5.9375, + 5.9375, + 5.9375, + 5.9375, + 5.9375, + 5.9375, + 5.9375, + 5.9375, + 5.9375, + 5.9375, + 5.9375, + 5.9375, + 30.9375, + 30.9375, + 30.9375, + 30.9375, + 30.9375, + 30.9375, + 30.9375, + 30.9375, + 30.9375, + 30.9375, + 30.9375, + 30.9375, + 55.9375, + 55.9375, + 55.9375, + 55.9375, + 55.9375, + 55.9375, + 55.9375, + 55.9375, + 55.9375, + 55.9375, + 55.9375, + 55.9375, + });*/ + test.Run(); +} + +TEST(RoiAlignTest, AvgModePositive_half_pixel) { + OpTester test("RoiAlign", 16); + test.AddAttribute("output_height", 3); + test.AddAttribute("output_width", 4); + test.AddAttribute("sampling_ratio", 2); + test.AddAttribute("spatial_scale", 1.0f / 16.0f); + test.AddAttribute("coordinate_transformation_mode", "half_pixel"); + + constexpr int N = 1; + constexpr int C = 3; + constexpr int H = 5; + constexpr int W = 5; + + std::vector rois{0., 7., 5., 7., 5., 0., -15., -15., -15., -15., 0., -10., 21., -10., 21., 0., 13., 8., 13., 8., 0., -14., 19., -14., 19.}; + test.AddInput("X", {N, C, H, W}, {0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., 17., 18., 19., 20., 21., 22., 23., 24., 25., 26., 27., 28., 29., 30., 31., 32., 33., 34., 35., 36., 37., 38., 39., 40., 41., 42., 43., 44., 45., 46., 47., 48., 49., 50., 51., 52., 53., 54., 55., 56., 57., 58., 59., 60., 61., 62., 63., 64., 65., 66., 67., 68., 69., 70., 71., 72., 73., 74.}); + test.AddInput("rois", {5, 4}, {7., 5., 7., 5., -15., -15., -15., -15., -10., 21., -10., 21., 13., 8., 13., 8., -14., 19., -14., 19.}); + test.AddInput("batch_indices", {5}, {0, 0, 0, 0, 0}); + test.AddOutput("Y", {5, 3, 3, 4}, {0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 25.0000000f, 25.0000000f, 25.0000000f, 25.0000000f, 25.0000000f, 25.0000000f, 25.0000000f, 25.0000000f, 25.0000000f, 25.0000000f, 25.0000000f, 25.0000000f, 50.0000000f, 50.0000000f, 50.0000000f, 50.0000000f, 50.0000000f, 50.0000000f, 50.0000000f, 50.0000000f, 50.0000000f, 50.0000000f, 50.0000000f, 50.0000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.312500000f, 0.312500000f, 0.312500000f, 0.312500000f, 0.312500000f, 0.312500000f, 0.312500000f, 0.312500000f, 0.312500000f, 0.312500000f, 0.312500000f, 0.312500000f, 25.3125000f, 25.3125000f, 25.3125000f, 25.3125000f, 25.3125000f, 25.3125000f, 25.3125000f, 25.3125000f, 25.3125000f, 25.3125000f, 25.3125000f, 25.3125000f, 50.3125000f, 50.3125000f, 50.3125000f, 50.3125000f, 50.3125000f, 50.3125000f, 50.3125000f, 50.3125000f, 50.3125000f, 50.3125000f, 50.3125000f, 50.3125000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000}); + test.Run(); +} + +TEST(RoiAlignTest, AvgModePositive_output_half_pixel) { + // TODO: Unskip when fixed ort issue #3428 + if (DefaultDmlExecutionProvider().get() != nullptr) { + GTEST_SKIP() << "Skipping because of the following error: The difference between expected[i] and output[i] is 0.95832991600036621, which exceeds threshold"; + } + + OpTester test("RoiAlign", 16); + test.AddAttribute("output_height", 3); + test.AddAttribute("output_width", 4); + test.AddAttribute("sampling_ratio", 2); + test.AddAttribute("spatial_scale", 1.0f / 16.0f); + test.AddAttribute("coordinate_transformation_mode", "output_half_pixel"); + + constexpr int N = 1; + constexpr int C = 3; + constexpr int H = 5; + constexpr int W = 5; + std::vector rois{0., 7., 5., 7., 5., 0., -15., -15., -15., -15., 0., -10., 21., -10., 21., 0., 13., 8., 13., 8., 0., -14., 19., -14., 19.}; + test.AddInput("X", {N, C, H, W}, {0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., 17., 18., 19., 20., 21., 22., 23., 24., 25., 26., 27., 28., 29., 30., 31., 32., 33., 34., 35., 36., 37., 38., 39., 40., 41., 42., 43., 44., 45., 46., 47., 48., 49., 50., 51., 52., 53., 54., 55., 56., 57., 58., 59., 60., 61., 62., 63., 64., 65., 66., 67., 68., 69., 70., 71., 72., 73., 74.}); + test.AddInput("rois", {5, 4}, {7., 5., 7., 5., -15., -15., -15., -15., -10., 21., -10., 21., 13., 8., 13., 8., -14., 19., -14., 19.}); + test.AddInput("batch_indices", {5}, {0, 0, 0, 0, 0}); + test.AddOutput("Y", {5, 3, 3, 4}, {2.95833f, 3.20833f, 3.45833f, 3.70833f, 4.625f, 4.875f, 5.125f, 5.375f, 6.29167f, 6.54167f, 6.79167f, 7.04167f, 27.9583f, 28.2083f, 28.4583f, 28.7083f, 29.625f, 29.875f, 30.125f, 30.375f, 31.2917f, 31.5417f, 31.7917f, 32.0417f, 52.9583f, 53.2083f, 53.4583f, 53.7083f, 54.625f, 54.875f, 55.125f, 55.375f, 56.2917f, 56.5417f, 56.7917f, 57.0417f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 25.f, 25.f, 25.f, 25.f, 25.f, 25.f, 25.f, 25.f, 25.f, 25.f, 25.f, 25.f, 50.f, 50.f, 50.f, 50.f, 50.f, 50.f, 50.f, 50.f, 50.f, 50.f, 50.f, 50.f, 7.39583f, 7.39583f, 7.42708f, 7.64583f, 9.0625f, 9.0625f, 9.09375f, 9.3125f, 10.7292f, 10.7292f, 10.7604f, 10.9792f, 32.3958f, 32.3958f, 32.4271f, 32.6458f, 34.0625f, 34.0625f, 34.0938f, 34.3125f, 35.7292f, 35.7292f, 35.7604f, 35.9792f, 57.3958f, 57.3958f, 57.4271f, 57.6458f, 59.0625f, 59.0625f, 59.0938f, 59.3125f, 60.7292f, 60.7292f, 60.7604f, 60.9792f, 4.27083f, 4.52083f, 4.77083f, 5.02083f, 5.9375f, 6.1875f, 6.4375f, 6.6875f, 7.60417f, 7.85417f, 8.10417f, 8.35417f, 29.2708f, 29.5208f, 29.7708f, 30.0208f, 30.9375f, 31.1875f, 31.4375f, 31.6875f, 32.6042f, 32.8542f, 33.1042f, 33.3542f, 54.2708f, 54.5208f, 54.7708f, 55.0208f, 55.9375f, 56.1875f, 56.4375f, 56.6875f, 57.6042f, 57.8542f, 58.1042f, 58.3542f, 6.77083f, 6.77083f, 6.77083f, 6.80208f, 8.4375f, 8.4375f, 8.4375f, 8.46875f, 10.1042f, 10.1042f, 10.1042f, 10.1354f, 31.7708f, 31.7708f, 31.7708f, 31.8021f, 33.4375f, 33.4375f, 33.4375f, 33.4688f, 35.1042f, 35.1042f, 35.1042f, 35.1354f, 56.7708f, 56.7708f, 56.7708f, 56.8021f, 58.4375f, 58.4375f, 58.4375f, 58.4688f, 60.1042f, 60.1042f, 60.1042f, 60.1354f}); test.Run(); } @@ -230,12 +463,11 @@ static void BasicTest() { 0.3661f, 0.2349f, }); - test.Run(); } TEST(RoiAlignTest, OnnxTest) { - // TODO: Unskip when fixed #41968513 + // TODO: Unskip when fixed ort issue #3428 if (DefaultDmlExecutionProvider().get() != nullptr) { GTEST_SKIP() << "Skipping because of the following error: The difference between expected[i] and output[i] is 0.051382988691329956, which exceeds threshold"; } @@ -245,7 +477,7 @@ TEST(RoiAlignTest, OnnxTest) { } TEST(RoiAlignTest, MaxModePositive) { - // TODO: Unskip when fixed #41968513 + // TODO: Unskip when fixed ort issue #3428 if (DefaultDmlExecutionProvider().get() != nullptr) { GTEST_SKIP() << "Skipping because of the following error: The difference between expected[i] and output[i] is 2.1093800067901611, which exceeds threshold"; } @@ -267,10 +499,196 @@ TEST(RoiAlignTest, MaxModePositive) { test.AddInput("rois", {5, 4}, {7., 5., 7., 5., -15., -15., -15., -15., -10., 21., -10., 21., 13., 8., 13., 8., -14., 19., -14., 19.}); test.AddInput("batch_indices", {5}, {0, 0, 0, 0, 0}); test.AddOutput("Y", {5, 3, 3, 4}, {2.10938f, 2.95313f, 3.375f, 2.53125f, 3.35938f, 4.70313f, 5.375f, 4.03125f, 3.51563f, 4.92188f, 5.625f, 4.21875f, 10.8984f, 15.2578f, 17.4375f, 13.0781f, 17.3568f, 24.2995f, 27.7708f, 20.8281f, 18.1641f, 25.4297f, 29.0625f, 21.7969f, 19.6875f, 27.5625f, 31.5f, 23.625f, 31.3542f, 43.8958f, 50.1667f, 37.625f, 32.8125f, 45.9375f, 52.5f, 39.375f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 25.f, 25.f, 25.f, 25.f, 25.f, 25.f, 25.f, 25.f, 25.f, 25.f, 25.f, 25.f, 50.f, 50.f, 50.f, 50.f, 50.f, 50.f, 50.f, 50.f, 50.f, 50.f, 50.f, 50.f, 5.625f, 5.625f, 5.625f, 4.57031f, 8.95833f, 8.95833f, 8.95833f, 7.27865f, 9.375f, 9.375f, 9.375f, 7.61719f, 19.6875f, 19.6875f, 19.6875f, 15.9961f, 31.3542f, 31.3542f, 31.3542f, 25.4753f, 32.8125f, 32.8125f, 32.8125f, 26.6602f, 33.75f, 33.75f, 33.75f, 27.4219f, 53.75f, 53.75f, 53.75f, 43.6719f, 56.25f, 56.25f, 56.25f, 45.7031f, 4.5f, 3.9375f, 2.8125f, 3.9375f, 5.5f, 4.8125f, 3.4375f, 4.8125f, 4.58333f, 4.01042f, 2.86458f, 3.9375f, 23.25f, 20.3438f, 14.5313f, 18.f, 28.4167f, 24.86458f, 17.76042f, 22.f, 23.25f, 20.3437f, 14.5312f, 18.f, 42.f, 36.75f, 26.25f, 32.0625f, 51.3333f, 44.9167f, 32.08333f, 39.1875f, 42.f, 36.75f, 26.25f, 32.0625f, 4.375f, 4.375f, 4.375f, 4.375f, 7.70833f, 7.70833f, 7.70833f, 7.70833f, 9.375f, 9.375f, 9.375f, 9.375f, 21.875f, 21.875f, 21.875f, 21.875f, 26.9792f, 26.9792f, 26.9792f, 26.9792f, 32.8125f, 32.8125f, 32.8125f, 32.8125f, 40.1042f, 40.1042f, 40.1042f, 40.1042f, 46.25f, 46.25f, 46.25f, 46.25f, 56.25f, 56.25f, 56.25f, 56.25f}); - + // DML has the correct outputs, which are defined below. + // These will replace the above outputs once https://github.com/microsoft/onnxruntime/issues/6921 is fixed. + /*test.AddOutput("Y",{5, 3, 3, 4}, { + 2.0000, + 2.0000, + 2.0000, + 2.0000, + 2.0000, + 2.0000, + 2.0000, + 2.0000, + 2.0000, + 2.0000, + 2.0000, + 2.0000, + 27.0000, + 27.0000, + 27.0000, + 27.0000, + 27.0000, + 27.0000, + 27.0000, + 27.0000, + 27.0000, + 27.0000, + 27.0000, + 27.0000, + 52.0000, + 52.0000, + 52.0000, + 52.0000, + 52.0000, + 52.0000, + 52.0000, + 52.0000, + 52.0000, + 52.0000, + 52.0000, + 52.0000, + + 0.0000, + 0.0000, + 0.0000, + 0.0000, + 0.0000, + 0.0000, + 0.0000, + 0.0000, + 0.0000, + 0.0000, + 0.0000, + 0.0000, + 25.0000, + 25.0000, + 25.0000, + 25.0000, + 25.0000, + 25.0000, + 25.0000, + 25.0000, + 25.0000, + 25.0000, + 25.0000, + 25.0000, + 50.0000, + 50.0000, + 50.0000, + 50.0000, + 50.0000, + 50.0000, + 50.0000, + 50.0000, + 50.0000, + 50.0000, + 50.0000, + 50.0000, + + 6.5625, + 6.5625, + 6.5625, + 6.5625, + 6.5625, + 6.5625, + 6.5625, + 6.5625, + 6.5625, + 6.5625, + 6.5625, + 6.5625, + 31.5625, + 31.5625, + 31.5625, + 31.5625, + 31.5625, + 31.5625, + 31.5625, + 31.5625, + 31.5625, + 31.5625, + 31.5625, + 31.5625, + 56.5625, + 56.5625, + 56.5625, + 56.5625, + 56.5625, + 56.5625, + 56.5625, + 56.5625, + 56.5625, + 56.5625, + 56.5625, + 56.5625, + + 3.3125, + 3.3125, + 3.3125, + 3.3125, + 3.3125, + 3.3125, + 3.3125, + 3.3125, + 3.3125, + 3.3125, + 3.3125, + 3.3125, + 28.3125, + 28.3125, + 28.3125, + 28.3125, + 28.3125, + 28.3125, + 28.3125, + 28.3125, + 28.3125, + 28.3125, + 28.3125, + 28.3125, + 53.3125, + 53.3125, + 53.3125, + 53.3125, + 53.3125, + 53.3125, + 53.3125, + 53.3125, + 53.3125, + 53.3125, + 53.3125, + 53.3125, + + 5.9375, + 5.9375, + 5.9375, + 5.9375, + 5.9375, + 5.9375, + 5.9375, + 5.9375, + 5.9375, + 5.9375, + 5.9375, + 5.9375, + 30.9375, + 30.9375, + 30.9375, + 30.9375, + 30.9375, + 30.9375, + 30.9375, + 30.9375, + 30.9375, + 30.9375, + 30.9375, + 30.9375, + 55.9375, + 55.9375, + 55.9375, + 55.9375, + 55.9375, + 55.9375, + 55.9375, + 55.9375, + 55.9375, + 55.9375, + 55.9375, + 55.9375, + });*/ test.Run(); } - TEST(RoiAlignTest, AvgModeNegativeInvalidMode) { // TODO: Unskip when fixed #41968513 if (DefaultDmlExecutionProvider().get() != nullptr) { diff --git a/onnxruntime/test/providers/cpu/reduction/reduction_ops_test.cc b/onnxruntime/test/providers/cpu/reduction/reduction_ops_test.cc index 348765b535bae..c9b851e450f9d 100644 --- a/onnxruntime/test/providers/cpu/reduction/reduction_ops_test.cc +++ b/onnxruntime/test/providers/cpu/reduction/reduction_ops_test.cc @@ -924,11 +924,7 @@ TEST(ReductionOpTest, ReduceMax_default_axes_do_not_keep_dims) { 55.0f, 1.0f, 60.0f, 2.0f}); test.AddOutput("reduced", {}, {60.0f}); -#if defined(OPENVINO_CONFIG_MYRIAD) - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); // OpenVINO: Disabled as incorrect dimensions in the output data -#else - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); // TensorRT: full reduce without keepDimensions is not supported with explicit batch //TensorRT: axis must be 0 -#endif + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); // TensorRT: full reduce without keepDimensions is not supported with explicit batch //TensorRT: axis must be 0 } TEST(ReductionOpTest, ReduceMax_do_not_keepdims) { @@ -955,11 +951,7 @@ TEST(ReductionOpTest, ReduceMax_do_not_keepdims_2) { test.AddInput("data", {3}, {5.0f, 1.0f, 20.0f}); test.AddOutput("reduced", {}, {20.0f}); -#if defined(OPENVINO_CONFIG_MYRIAD) - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); // OpenVINO: Disabled as incorrect dimensions in the output data -#else - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); // TensorRT: full reduce without keepDimensions is not supported with explicit batch -#endif + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); // TensorRT: full reduce without keepDimensions is not supported with explicit batch } TEST(ReductionOpTest, ReduceMax_keepdims) { @@ -1012,7 +1004,7 @@ TEST(ReductionOpTest, ReduceMaxAxesInitializerOpset18) { test.AddOutput("reduced", {3, 1, 1}, {4.0f, 8.0f, 12.0f}); // TODO: DNNL, TensorRT, and OpenVINO dont support "axes" input in opset 18 test.Run(OpTester::ExpectResult::kExpectSuccess, "", - {kDnnlExecutionProvider, kTensorrtExecutionProvider, kOpenVINOExecutionProvider}); + {kDnnlExecutionProvider, kTensorrtExecutionProvider, kOpenVINOExecutionProvider, kDmlExecutionProvider}); } #if defined(USE_DNNL) @@ -1091,7 +1083,7 @@ TEST(ReductionOpTest, ReduceMax_int32) { 11, 12}); test.AddOutput("reduced", {3, 1, 1}, {4, 8, 12}); -#if defined(OPENVINO_CONFIG_GPU_FP32) || defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_MYRIAD) +#if defined(OPENVINO_CONFIG_GPU_FP32) || defined(OPENVINO_CONFIG_GPU_FP16) test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kOpenVINOExecutionProvider}); // OpenVINO: Disabled temporarily #else test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); // TensorRT: axis must be 0 @@ -1112,7 +1104,7 @@ TEST(ReductionOpTest, ReduceMax_int64) { 9, 10, 11, 12}); test.AddOutput("reduced", {3, 1, 1}, {4, 8, 12}); -#if defined(OPENVINO_CONFIG_GPU_FP32) || defined(OPENVINO_CONFIG_GPU_FP16) || defined(OPENVINO_CONFIG_MYRIAD) +#if defined(OPENVINO_CONFIG_GPU_FP32) || defined(OPENVINO_CONFIG_GPU_FP16) test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kOpenVINOExecutionProvider}); // OpenVINO: Disabled temporarily #else test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); // TensorRT: axis must be 0 @@ -1133,11 +1125,7 @@ TEST(ReductionOpTest, ReduceMax_int8) { 9, 10, 11, 12}); test.AddOutput("reduced", {3, 1, 1}, {4, 8, 12}); -#if defined(OPENVINO_CONFIG_MYRIAD) - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kOpenVINOExecutionProvider}); // OpenVINO: Disabled temporarily -#else - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); // TensorRT: axis must be 0 -#endif + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); // TensorRT: axis must be 0 } TEST(ReductionOpTest, ReduceMax_uint8) { @@ -1154,11 +1142,7 @@ TEST(ReductionOpTest, ReduceMax_uint8) { 9, 10, 11, 12}); test.AddOutput("reduced", {3, 1, 1}, {4, 8, 12}); -#if defined(OPENVINO_CONFIG_MYRIAD) - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kOpenVINOExecutionProvider}); // OpenVINO: Disabled temporarily -#else - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); // TensorRT: axis must be 0 -#endif + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); // TensorRT: axis must be 0 } TEST(ReductionOpTest, ReduceMax0DTensor) { @@ -1499,7 +1483,7 @@ TEST(ReductionOpTest, ReduceMeanAxesInitializerOpset18) { // TODO: DNNL, TensorRT, and OpenVINO dont support "axes" input in opset 18, re-enable after test.Run(OpTester::ExpectResult::kExpectSuccess, "", - {kDnnlExecutionProvider, kTensorrtExecutionProvider, kOpenVINOExecutionProvider}); + {kDnnlExecutionProvider, kTensorrtExecutionProvider, kOpenVINOExecutionProvider, kDmlExecutionProvider}); } #ifdef USE_DNNL @@ -1563,6 +1547,40 @@ TEST(ReductionOpTest, ReduceMean_int32) { test.Run(); } +TEST(ReductionOpTest, ReduceMean_axes_input) { + OpTester test("ReduceMean", 18, onnxruntime::kOnnxDomain); + test.AddAttribute("keepdims", (int64_t)1); + test.AddInput("data", {3, 2, 2}, + {1, 2, + 3, 4, + + 5, 6, + 7, 8, + + 9, 10, + 11, 12}); + test.AddInput("axes", {2}, std::vector{0, 2}, true); + test.AddOutput("reduced", {1, 2, 1}, {5.5, 7.5}); + + // TODO: DNNL, TensorRT, and OpenVINO dont support "axes" input in opset 18, re-enable after + test.Run(OpTester::ExpectResult::kExpectSuccess, "", + {kDnnlExecutionProvider, kTensorrtExecutionProvider, kOpenVINOExecutionProvider, kDmlExecutionProvider}); +} + +TEST(ReductionOpTest, ReduceMean_do_not_keepdims_axes_input_initializer) { + OpTester test("ReduceMean", 18, onnxruntime::kOnnxDomain); + test.AddAttribute("keepdims", (int64_t)0); + test.AddInput("data", {1, 2, 2}, + {1.0f, 2.0f, + 3.0f, 4.0f}); + test.AddInput("axes", {1}, std::vector{1}, true); + test.AddOutput("reduced", {1, 2}, {2.0f, 3.0f}); + + // TODO: DNNL, TensorRT, and OpenVINO dont support "axes" input in opset 18, re-enable after + test.Run(OpTester::ExpectResult::kExpectSuccess, "", + {kDnnlExecutionProvider, kTensorrtExecutionProvider, kOpenVINOExecutionProvider, kDmlExecutionProvider}); +} + TEST(ReductionOpTest, ReduceMean0DTensor) { OpTester test("ReduceMean"); test.AddInput("data", {}, {2}); @@ -1748,7 +1766,7 @@ TEST(ReductionOpTest, ReduceMinAxesInitializerOpset18) { test.AddOutput("reduced", {1, 2, 1}, {1.0f, 3.0f}); // TODO: DNNL, TensorRT, and OpenVINO dont support "axes" input in opset 18, re-enable after test.Run(OpTester::ExpectResult::kExpectSuccess, "", - {kDnnlExecutionProvider, kTensorrtExecutionProvider, kOpenVINOExecutionProvider}); + {kDnnlExecutionProvider, kTensorrtExecutionProvider, kOpenVINOExecutionProvider, kDmlExecutionProvider}); } #if defined(USE_DNNL) @@ -1924,7 +1942,7 @@ TEST(ReductionOpTest, ReduceSumAxesInitializerOpset13) { test.AddInput("axes", {2}, {0, 2}, true); test.AddOutput("reduced", {1, 2, 1}, {33.0f, 45.0f}); // TODO: TensorRT and OpenVINO dont support "axes" input in opset 13, re-enable after - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kOpenVINOExecutionProvider}); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kOpenVINOExecutionProvider, kDmlExecutionProvider}); } TEST(ReductionOpTest, ReduceSum_double) { @@ -2242,13 +2260,8 @@ TEST(ReductionOpTest, ReduceSum_batch_by_seq_by_30528) { #endif TEST(ReductionOpTest, ReduceSum_bert_selected_batch_size) { -#if defined(OPENVINO_CONFIG_MYRIAD) || defined(OPENVINO_CONFIG_VAD_M) - test_apex_reduce_sum(85 * 128, 768, true); - test_apex_reduce_sum(86 * 128, 768, true); -#else test_apex_reduce_sum(85 * 128, 768); test_apex_reduce_sum(86 * 128, 768); -#endif } TEST(ReductionOpTest, ReduceSum_apex_more) { @@ -2399,7 +2412,7 @@ TEST(ReductionOpTest, ReduceSum_do_not_keepdims_axes_input_not_initializer) { test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kOpenVINOExecutionProvider}); } -TEST(ReductionOpTest, ReduceSum_noop_axes_input_initializer) { +TEST(ReductionOpTest, ReduceSum_noop_axes_input_initializer_opset_13) { OpTester test("ReduceSum", 13, onnxruntime::kOnnxDomain); test.AddAttribute("keepdims", (int64_t)0); test.AddAttribute("noop_with_empty_axes", (int64_t)1); @@ -2412,7 +2425,7 @@ TEST(ReductionOpTest, ReduceSum_noop_axes_input_initializer) { test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kOpenVINOExecutionProvider}); } -TEST(ReductionOpTest, ReduceSum_empty_axes_input_initializer) { +TEST(ReductionOpTest, ReduceSum_empty_axes_input_initializer_opset_13) { OpTester test("ReduceSum", 13, onnxruntime::kOnnxDomain); test.AddAttribute("keepdims", (int64_t)0); test.AddAttribute("noop_with_empty_axes", (int64_t)0); // Not NoOP, use default axes. @@ -2718,7 +2731,7 @@ TEST(ReductionOpTest, ReduceProdAxesInitializerOpset18) { test.AddOutput("reduced", {1, 2, 1}, {5400.f, 88704.f}); // TODO: DNNL, TensorRT, and OpenVINO dont support "axes" input in opset 18, re-enable after test.Run(OpTester::ExpectResult::kExpectSuccess, "", - {kDnnlExecutionProvider, kTensorrtExecutionProvider, kOpenVINOExecutionProvider}); + {kDnnlExecutionProvider, kTensorrtExecutionProvider, kOpenVINOExecutionProvider, kDmlExecutionProvider}); } #if defined(USE_DNNL) @@ -3202,6 +3215,24 @@ TEST(ReductionOpTest, OptimizeShapeForFastReduce_ReduceDimWithZero1) { ASSERT_EQ(fast_axes, expected_fast_axes); } +TEST(ReductionOpTest, OptimizeShapeForFastReduce_ReduceDimWithScalarInputAxesPresent) { + FastReduceKind fast_kind; + TensorShapeVector fast_shape, fast_output_shape, fast_axes; + TensorShapeVector expected_fast_shape, expected_fast_output_shape, expected_fast_axes; + + // R - keep_dims=1 - noop=false + fast_kind = OptimizeShapeForFastReduce( + EmptySpan(), AsSpan({1, 2, 3}), + fast_shape, fast_output_shape, fast_axes, true); + expected_fast_shape = {}; + expected_fast_axes = {}; + expected_fast_output_shape = {}; + ASSERT_EQ(fast_kind, FastReduceKind::kEmpty); + ASSERT_EQ(fast_output_shape, expected_fast_output_shape); + ASSERT_EQ(fast_shape, expected_fast_shape); + ASSERT_EQ(fast_axes, expected_fast_axes); +} + TEST(ReductionOpTest, OptimizeShapeForFastReduce_ReduceDimWithZero1b) { FastReduceKind fast_kind; TensorShapeVector fast_shape, fast_output_shape, fast_axes; @@ -3231,8 +3262,14 @@ TEST(ReductionOpTest, ReduceDimWithZero1) { auto expect = error_msg.empty() ? OpTester::ExpectResult::kExpectSuccess : OpTester::ExpectResult::kExpectFailure; - // exclude OpenVINO and TensorRT as this isn't handled by those EPs - tester.Run(expect, error_msg, {kTensorrtExecutionProvider, kOpenVINOExecutionProvider, kQnnExecutionProvider}); + tester.Run(expect, error_msg, + // exclude EPs that don't handle this + { + kCoreMLExecutionProvider, + kOpenVINOExecutionProvider, + kQnnExecutionProvider, + kTensorrtExecutionProvider, + }); }; // reduce on all axes keeping dims. should allow the 0 to be the reduced value @@ -3272,8 +3309,14 @@ TEST(ReductionOpTest, ReduceDimWithZero2) { auto expect = error_msg.empty() ? OpTester::ExpectResult::kExpectSuccess : OpTester::ExpectResult::kExpectFailure; - // exclude OpenVINO and TensorRT as this isn't handled by those EPs - tester.Run(expect, error_msg, {kTensorrtExecutionProvider, kOpenVINOExecutionProvider, kQnnExecutionProvider}); + tester.Run(expect, error_msg, + // exclude EPs that don't handle this + { + kOpenVINOExecutionProvider, + kQnnExecutionProvider, + kTensorrtExecutionProvider, + kCoreMLExecutionProvider, + }); }; // reduction without keeping dims on all axes. can't reduce on an axis with value of 0 @@ -3310,8 +3353,14 @@ TEST(ReductionOpTest, ReduceSum_ReduceDimWithZero3) { auto expect = error_msg.empty() ? OpTester::ExpectResult::kExpectSuccess : OpTester::ExpectResult::kExpectFailure; - // exclude OpenVINO and TensorRT as this isn't handled by those EPs - tester.Run(expect, error_msg, {kTensorrtExecutionProvider, kOpenVINOExecutionProvider, kQnnExecutionProvider}); + tester.Run(expect, error_msg, + // exclude EPs that don't handle this + { + kCoreMLExecutionProvider, + kTensorrtExecutionProvider, + kOpenVINOExecutionProvider, + kQnnExecutionProvider, + }); }; // reduction is possible without keeping dims if we only reduce on non-zero dims @@ -3324,6 +3373,241 @@ TEST(ReductionOpTest, ReduceSum_ReduceDimWithZero3) { run(test3); } +// test if noop_with_empty_axes behaves correctly +TEST(ReductionOpTest, ReduceL1_noop_axes_input_initializer_opset_18) { + OpTester test("ReduceL1", 18); + test.AddAttribute("keepdims", (int64_t)0); + test.AddAttribute("noop_with_empty_axes", (int64_t)1); + test.AddInput("data", {1, 2, 2}, + {1.0f, 2.0f, + 3.0f, 4.0f}); + test.AddInput("axes", {0}, {}, true); + test.AddOutput("reduced", {1, 2, 2}, {1.0f, 2.0f, 3.0f, 4.0f}); + test.Run( + OpTester::ExpectResult::kExpectSuccess, + "", + {kTensorrtExecutionProvider, + kOpenVINOExecutionProvider, + kDnnlExecutionProvider, + kDmlExecutionProvider}); +} + +TEST(ReductionOpTest, ReduceL1_empty_axes_input_initializer_opset_18) { + OpTester test("ReduceL1", 18); + test.AddAttribute("keepdims", (int64_t)0); + test.AddAttribute("noop_with_empty_axes", (int64_t)0); // Not NoOP, use default axes. + test.AddInput("data", {1, 2, 2}, + {1.0f, 2.0f, + 3.0f, 4.0f}); + test.AddInput("axes", {0}, {}, true); + test.AddOutput("reduced", {}, {10.0f}); + test.Run(); +} + +TEST(ReductionOpTest, ReduceL2_noop_axes_input_initializer_opset_18) { + OpTester test("ReduceL2", 18); + test.AddAttribute("keepdims", (int64_t)0); + test.AddAttribute("noop_with_empty_axes", (int64_t)1); + test.AddInput("data", {1, 2, 2}, + {1.0f, 2.0f, + 3.0f, 4.0f}); + test.AddInput("axes", {0}, {}, true); + test.AddOutput("reduced", {1, 2, 2}, {1.0f, 2.0f, 3.0f, 4.0f}); + test.Run( + OpTester::ExpectResult::kExpectSuccess, + "", + {kTensorrtExecutionProvider, + kOpenVINOExecutionProvider, + kDnnlExecutionProvider, + kDmlExecutionProvider}); +} + +TEST(ReductionOpTest, ReduceL2_empty_axes_input_initializer_opset_18) { + OpTester test("ReduceL2", 18); + test.AddAttribute("keepdims", (int64_t)0); + test.AddAttribute("noop_with_empty_axes", (int64_t)0); // Not NoOP, use default axes. + test.AddInput("data", {1, 2, 2}, + {1.0f, 2.0f, + 3.0f, 4.0f}); + test.AddInput("axes", {0}, {}, true); + test.AddOutput("reduced", {}, {5.47722558f}); + test.Run(); +} + +TEST(ReductionOpTest, ReduceMax_noop_axes_input_initializer_opset_18) { + OpTester test("ReduceMax", 18); + test.AddAttribute("keepdims", (int64_t)0); + test.AddAttribute("noop_with_empty_axes", (int64_t)1); + test.AddInput("data", {1, 2, 2}, + {1.0f, 2.0f, + 3.0f, 4.0f}); + test.AddInput("axes", {0}, {}, true); + test.AddOutput("reduced", {1, 2, 2}, {1.0f, 2.0f, 3.0f, 4.0f}); + test.Run( + OpTester::ExpectResult::kExpectSuccess, + "", + {kTensorrtExecutionProvider, + kOpenVINOExecutionProvider, + kDnnlExecutionProvider, + kDmlExecutionProvider}); +} + +TEST(ReductionOpTest, ReduceMax_empty_axes_input_initializer_opset_18) { + OpTester test("ReduceMax", 18); + test.AddAttribute("keepdims", (int64_t)0); + test.AddAttribute("noop_with_empty_axes", (int64_t)0); // Not NoOP, use default axes. + test.AddInput("data", {1, 2, 2}, + {1.0f, 2.0f, + 3.0f, 4.0f}); + test.AddInput("axes", {0}, {}, true); + test.AddOutput("reduced", {}, {4.0f}); + test.Run(); +} + +TEST(ReductionOpTest, ReduceMean_noop_axes_input_initializer_opset_18) { + OpTester test("ReduceMean", 18); + test.AddAttribute("keepdims", (int64_t)0); + test.AddAttribute("noop_with_empty_axes", (int64_t)1); + test.AddInput("data", {1, 2, 2}, + {1.0f, 2.0f, + 3.0f, 4.0f}); + test.AddInput("axes", {0}, {}, true); + test.AddOutput("reduced", {1, 2, 2}, {1.0f, 2.0f, 3.0f, 4.0f}); + test.Run( + OpTester::ExpectResult::kExpectSuccess, + "", + {kTensorrtExecutionProvider, + kOpenVINOExecutionProvider, + kDnnlExecutionProvider, + kDmlExecutionProvider}); +} + +TEST(ReductionOpTest, ReduceMean_empty_axes_input_initializer_opset_18) { + OpTester test("ReduceMean", 18); + test.AddAttribute("keepdims", (int64_t)0); + test.AddAttribute("noop_with_empty_axes", (int64_t)0); // Not NoOP, use default axes. + test.AddInput("data", {1, 2, 2}, + {1.0f, 2.0f, + 3.0f, 4.0f}); + test.AddInput("axes", {0}, {}, true); + test.AddOutput("reduced", {}, {2.5f}); + test.Run(); +} + +TEST(ReductionOpTest, ReduceMin_noop_axes_input_initializer_opset_18) { + OpTester test("ReduceMin", 18); + test.AddAttribute("keepdims", (int64_t)0); + test.AddAttribute("noop_with_empty_axes", (int64_t)1); + test.AddInput("data", {1, 2, 2}, + {1.0f, 2.0f, + 3.0f, 4.0f}); + test.AddInput("axes", {0}, {}, true); + test.AddOutput("reduced", {1, 2, 2}, {1.0f, 2.0f, 3.0f, 4.0f}); + test.Run( + OpTester::ExpectResult::kExpectSuccess, + "", + {kTensorrtExecutionProvider, + kOpenVINOExecutionProvider, + kDnnlExecutionProvider, + kDmlExecutionProvider}); +} + +TEST(ReductionOpTest, ReduceMin_empty_axes_input_initializer_opset_18) { + OpTester test("ReduceMin", 18); + test.AddAttribute("keepdims", (int64_t)0); + test.AddAttribute("noop_with_empty_axes", (int64_t)0); // Not NoOP, use default axes. + test.AddInput("data", {1, 2, 2}, + {1.0f, 2.0f, + 3.0f, 4.0f}); + test.AddInput("axes", {0}, {}, true); + test.AddOutput("reduced", {}, {1.0f}); + test.Run(); +} + +TEST(ReductionOpTest, ReduceProd_noop_axes_input_initializer_opset_18) { + OpTester test("ReduceProd", 18); + test.AddAttribute("keepdims", (int64_t)0); + test.AddAttribute("noop_with_empty_axes", (int64_t)1); + test.AddInput("data", {1, 2, 2}, + {1.0f, 2.0f, + 3.0f, 4.0f}); + test.AddInput("axes", {0}, {}, true); + test.AddOutput("reduced", {1, 2, 2}, {1.0f, 2.0f, 3.0f, 4.0f}); + test.Run( + OpTester::ExpectResult::kExpectSuccess, + "", + {kTensorrtExecutionProvider, + kOpenVINOExecutionProvider, + kDnnlExecutionProvider, + kDmlExecutionProvider}); +} + +TEST(ReductionOpTest, ReduceProd_empty_axes_input_initializer_opset_18) { + OpTester test("ReduceProd", 18); + test.AddAttribute("keepdims", (int64_t)0); + test.AddAttribute("noop_with_empty_axes", (int64_t)0); // Not NoOP, use default axes. + test.AddInput("data", {1, 2, 2}, + {1.0f, 2.0f, + 3.0f, 4.0f}); + test.AddInput("axes", {0}, {}, true); + test.AddOutput("reduced", {}, {24.0f}); + test.Run(); +} + +TEST(ReductionOpTest, ReduceSum_noop_axes_input_initializer_opset_18) { + OpTester test("ReduceSum", 18); + test.AddAttribute("keepdims", (int64_t)0); + test.AddAttribute("noop_with_empty_axes", (int64_t)1); + test.AddInput("data", {1, 2, 2}, + {1.0f, 2.0f, + 3.0f, 4.0f}); + test.AddInput("axes", {0}, {}, true); + test.AddOutput("reduced", {1, 2, 2}, {1.0f, 2.0f, 3.0f, 4.0f}); + test.Run(); +} + +TEST(ReductionOpTest, ReduceSum_empty_axes_input_initializer_opset_18) { + OpTester test("ReduceSum", 18); + test.AddAttribute("keepdims", (int64_t)0); + test.AddAttribute("noop_with_empty_axes", (int64_t)0); // Not NoOP, use default axes. + test.AddInput("data", {1, 2, 2}, + {1.0f, 2.0f, + 3.0f, 4.0f}); + test.AddInput("axes", {0}, {}, true); + test.AddOutput("reduced", {}, {10.0f}); + test.Run(); +} + +TEST(ReductionOpTest, ReduceSumSquare_noop_axes_input_initializer_opset_18) { + OpTester test("ReduceSumSquare", 18); + test.AddAttribute("keepdims", (int64_t)0); + test.AddAttribute("noop_with_empty_axes", (int64_t)1); + test.AddInput("data", {1, 2, 2}, + {1.0f, 2.0f, + 3.0f, 4.0f}); + test.AddInput("axes", {0}, {}, true); + test.AddOutput("reduced", {1, 2, 2}, {1.0f, 2.0f, 3.0f, 4.0f}); + test.Run( + OpTester::ExpectResult::kExpectSuccess, + "", + {kTensorrtExecutionProvider, + kOpenVINOExecutionProvider, + kDnnlExecutionProvider, + kDmlExecutionProvider}); +} + +TEST(ReductionOpTest, ReduceSumSquare_empty_axes_input_initializer_opset_18) { + OpTester test("ReduceSumSquare", 18); + test.AddAttribute("keepdims", (int64_t)0); + test.AddAttribute("noop_with_empty_axes", (int64_t)0); // Not NoOP, use default axes. + test.AddInput("data", {1, 2, 2}, + {1.0f, 2.0f, + 3.0f, 4.0f}); + test.AddInput("axes", {0}, {}, true); + test.AddOutput("reduced", {}, {30.0f}); + test.Run(); +} + TEST(ReductionOpTest, ReduceInfMax) { OpTester test("ReduceMax"); test.AddAttribute("axes", std::vector{1}); @@ -4859,7 +5143,9 @@ TEST(ReductionOpTest, ReduceSum_RK_parallel) { } } test.AddOutput("reduced", {32}, expected); - test.Run(); + + // CoreML does not provide 1e-5 precision here (it's off by 1e-4) + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kCoreMLExecutionProvider}); } TEST(ReductionOpTest, ReduceSum_RK_keepdims) { diff --git a/onnxruntime/test/providers/cpu/signal/signal_ops_test.cc b/onnxruntime/test/providers/cpu/signal/signal_ops_test.cc index 2b022c2fa84a4..3d4324189d463 100644 --- a/onnxruntime/test/providers/cpu/signal/signal_ops_test.cc +++ b/onnxruntime/test/providers/cpu/signal/signal_ops_test.cc @@ -58,20 +58,10 @@ static void TestRadix2DFTFloat(bool onesided) { } TEST(SignalOpsTest, DFTFloat_naive) { - // TODO: Unskip when fixed #41968513 - if (DefaultDmlExecutionProvider().get() != nullptr) { - GTEST_SKIP() << "Skipping because of the following error: MLOperatorAuthorImpl.cpp(1988): Not implemented"; - } - TestNaiveDFTFloat(false); } TEST(SignalOpsTest, DFTFloat_naive_onesided) { - // TODO: Unskip when fixed #41968513 - if (DefaultDmlExecutionProvider().get() != nullptr) { - GTEST_SKIP() << "Skipping because of the following error: MLOperatorAuthorImpl.cpp(1988): Not implemented"; - } - TestNaiveDFTFloat(true); } @@ -80,11 +70,6 @@ TEST(SignalOpsTest, DFTFloat_radix2) { TestRadix2DFTFloat(false); } TEST(SignalOpsTest, DFTFloat_radix2_onesided) { TestRadix2DFTFloat(true); } TEST(SignalOpsTest, DFTFloat_inverse) { - // TODO: Unskip when fixed #41968513 - if (DefaultDmlExecutionProvider().get() != nullptr) { - GTEST_SKIP() << "Skipping because of the following error: MLOperatorAuthorImpl.cpp(1988): Not implemented"; - } - OpTester test("DFT", kMinOpsetVersion); vector shape = {1, 5, 2}; @@ -125,13 +110,13 @@ static void TestDFTInvertible(bool complex) { }; RandomValueGenerator random(GetTestRandomSeed()); - // TODO(garymm, smk2007): Add tests for different dft_length values. + // TODO(smk2007): Add tests for different dft_length values. constexpr int64_t num_batches = 2; for (int64_t axis = 1; axis < 2; axis += 1) { - for (int64_t signal_dim1 = 1; signal_dim1 <= 4; signal_dim1 += 1) { - for (int64_t signal_dim2 = 1; signal_dim2 <= 4; signal_dim2 += 1) { + for (int64_t signal_dim1 = 2; signal_dim1 <= 5; signal_dim1 += 1) { + for (int64_t signal_dim2 = 2; signal_dim2 <= 5; signal_dim2 += 1) { DFTInvertibleTester test(axis); - vector input_shape{num_batches, signal_dim1, signal_dim2, 1 + complex}; + vector input_shape{num_batches, signal_dim1, signal_dim2, 1 + (complex ? 1 : 0)}; vector input_data = random.Uniform(input_shape, -100.f, 100.f); test.AddInput("input", input_shape, input_data); @@ -149,6 +134,7 @@ static void TestDFTInvertible(bool complex) { output_data_p = &output_data; } test.AddOutput("output", output_shape, *output_data_p); + test.SetOutputAbsErr("output", 0.0002f); test.Run(); } } @@ -156,20 +142,10 @@ static void TestDFTInvertible(bool complex) { } TEST(SignalOpsTest, DFT_invertible_real) { - // TODO: Unskip when fixed #41968513 - if (DefaultDmlExecutionProvider().get() != nullptr) { - GTEST_SKIP() << "Skipping because of the following error: MLOperatorAuthorImpl.cpp(1988): Not implemented"; - } - TestDFTInvertible(false); } TEST(SignalOpsTest, DFT_invertible_complex) { - // TODO: Unskip when fixed #41968513 - if (DefaultDmlExecutionProvider().get() != nullptr) { - GTEST_SKIP() << "Skipping because of the following error: MLOperatorAuthorImpl.cpp(1988): Not implemented"; - } - TestDFTInvertible(true); } diff --git a/onnxruntime/test/providers/cpu/tensor/cast_op_test.cc b/onnxruntime/test/providers/cpu/tensor/cast_op_test.cc index 11df5b11e608b..4c77908322df4 100644 --- a/onnxruntime/test/providers/cpu/tensor/cast_op_test.cc +++ b/onnxruntime/test/providers/cpu/tensor/cast_op_test.cc @@ -32,17 +32,40 @@ int GetMinRequiredCudaComputeCapability() { return 800; } +#if !defined(DISABLE_FLOAT8_TYPES) + +template <> +int GetMinRequiredCudaComputeCapability() { + return 800; +} + +template <> +int GetMinRequiredCudaComputeCapability() { + return 800; +} + +#endif + +enum Saturate { True, + False, + None }; + template void TestCastOp(gsl::span input, gsl::span output, - const std::vector& dimensions, + const BaseTester::DimsVariant& dimensions, OpTester::ExpectResult expect_result = OpTester::ExpectResult::kExpectSuccess, - const std::string& expected_failure_string = "") { - OpTester test("Cast", 13); + const std::string& expected_failure_string = "", + int opset = 13, + Saturate saturate = Saturate::None) { + OpTester test("Cast", opset); test.AddAttribute("to", utils::ToTensorProtoElementType()); test.AddInput("input", dimensions, input.data(), input.size()); test.AddOutput("output", dimensions, output.data(), output.size()); + if (saturate != Saturate::None) { + test.AddAttribute("saturate", saturate == Saturate::True ? 1 : 0); + } std::unordered_set excluded_provider_types{kTensorrtExecutionProvider}; const auto min_required_cuda_compute_capability = @@ -113,7 +136,7 @@ struct CastNonStringTester { auto output_span = gsl::make_span(output_buffer.get(), size); CastSpan(input_span, output_span); - TestCastOp(input_span, output_span, GetShapeVector(shape)); + TestCastOp(input_span, output_span, shape.AsShapeVector()); } }; @@ -189,5 +212,69 @@ TEST(CastOpTest, ToString) { TestCastOp(gsl::make_span(int_16_input), gsl::make_span(int_string_data), shape); } +#if !defined(DISABLE_FLOAT8_TYPES) + +template +void CastOpTestFloat8(Saturate saturate) { + ASSERT_NE(saturate, Saturate::None); + const std::vector shape{2, 2, 2}; + const std::vector float_input = {NAN, -1.f, 0.0391877927f, 0.296140194f, -0.120196559f, 5.0f, + -std::numeric_limits::infinity(), + std::numeric_limits::infinity()}; + + // float output precision is 8, so the expected output differs slightly from the input due to that + std::vector output; + output.reserve(float_input.size()); + for (size_t i = 0; i < float_input.size(); ++i) { + output.emplace_back(F8(float_input[i], saturate == Saturate::True)); + } + TestCastOp(gsl::make_span(float_input), gsl::make_span(output), shape, OpTester::ExpectResult::kExpectSuccess, "", 19, saturate); + + const std::vector float16_input = + CastedValues(gsl::make_span(float_input)); + + TestCastOp(gsl::make_span(float16_input), gsl::make_span(output), shape, OpTester::ExpectResult::kExpectSuccess, "", 19, saturate); +} + +TEST(CastOpTest, ToFloat8E4M3FN) { + constexpr int min_cuda_architecture = 11080; + bool enable_cuda = (nullptr != DefaultCudaExecutionProvider().get()) && HasCudaEnvironment(min_cuda_architecture); + bool enable_cpu = (nullptr != DefaultCpuExecutionProvider().get()); + + if (enable_cpu || enable_cuda) { + CastOpTestFloat8(Saturate::True); + CastOpTestFloat8(Saturate::False); + } +} + +TEST(CastOpTest, ToFloat8E4M3FNUZ) { + bool enable_cpu = (nullptr != DefaultCpuExecutionProvider().get()); + if (enable_cpu) { + CastOpTestFloat8(Saturate::True); + CastOpTestFloat8(Saturate::False); + } +} + +TEST(CastOpTest, ToFloat8E5M2) { + constexpr int min_cuda_architecture = 11080; + bool enable_cuda = (nullptr != DefaultCudaExecutionProvider().get()) && HasCudaEnvironment(min_cuda_architecture); + bool enable_cpu = (nullptr != DefaultCpuExecutionProvider().get()); + + if (enable_cpu || enable_cuda) { + CastOpTestFloat8(Saturate::True); + CastOpTestFloat8(Saturate::False); + } +} + +TEST(CastOpTest, ToFloat8E5M2FNUZ) { + bool enable_cpu = (nullptr != DefaultCpuExecutionProvider().get()); + if (enable_cpu) { + CastOpTestFloat8(Saturate::True); + CastOpTestFloat8(Saturate::False); + } +} + +#endif + } // namespace test } // namespace onnxruntime diff --git a/onnxruntime/test/providers/cpu/tensor/expand_test.cc b/onnxruntime/test/providers/cpu/tensor/expand_test.cc index 01865dc7247d2..4b0f4e84ca37d 100644 --- a/onnxruntime/test/providers/cpu/tensor/expand_test.cc +++ b/onnxruntime/test/providers/cpu/tensor/expand_test.cc @@ -124,34 +124,34 @@ TEST(ExpandOpTest, Expand_3x1x3x1_int64) { TEST(ExpandOpTest, Expand_3x3_float16) { OpTester test("Expand", 8); - test.AddInput("data_0", {1}, {MLFloat16(math::floatToHalf(1.0f))}); + test.AddInput("data_0", {1}, {MLFloat16(1.0f)}); test.AddInput("data_1", {2}, {3, 3}); test.AddOutput("result", {3, 3}, - {MLFloat16(math::floatToHalf(1.0f)), MLFloat16(math::floatToHalf(1.0f)), MLFloat16(math::floatToHalf(1.0f)), - MLFloat16(math::floatToHalf(1.0f)), MLFloat16(math::floatToHalf(1.0f)), MLFloat16(math::floatToHalf(1.0f)), - MLFloat16(math::floatToHalf(1.0f)), MLFloat16(math::floatToHalf(1.0f)), MLFloat16(math::floatToHalf(1.0f))}); + {MLFloat16(1.0f), MLFloat16(1.0f), MLFloat16(1.0f), + MLFloat16(1.0f), MLFloat16(1.0f), MLFloat16(1.0f), + MLFloat16(1.0f), MLFloat16(1.0f), MLFloat16(1.0f)}); test.Run(); } TEST(ExpandOpTest, Expand_3x1_float16) { OpTester test("Expand", 8); - test.AddInput("data_0", {3}, {MLFloat16(math::floatToHalf(1.0f)), MLFloat16(math::floatToHalf(2.0f)), MLFloat16(math::floatToHalf(3.0f))}); + test.AddInput("data_0", {3}, {MLFloat16(1.0f), MLFloat16(2.0f), MLFloat16(3.0f)}); test.AddInput("data_1", {2}, {3, 1}); test.AddOutput("result", {3, 3}, - {MLFloat16(math::floatToHalf(1.0f)), MLFloat16(math::floatToHalf(2.0f)), MLFloat16(math::floatToHalf(3.0f)), - MLFloat16(math::floatToHalf(1.0f)), MLFloat16(math::floatToHalf(2.0f)), MLFloat16(math::floatToHalf(3.0f)), - MLFloat16(math::floatToHalf(1.0f)), MLFloat16(math::floatToHalf(2.0f)), MLFloat16(math::floatToHalf(3.0f))}); + {MLFloat16(1.0f), MLFloat16(2.0f), MLFloat16(3.0f), + MLFloat16(1.0f), MLFloat16(2.0f), MLFloat16(3.0f), + MLFloat16(1.0f), MLFloat16(2.0f), MLFloat16(3.0f)}); test.Run(); } TEST(ExpandOpTest, Expand_1x3_float16) { OpTester test("Expand", 8); - test.AddInput("data_0", {3, 1}, {MLFloat16(math::floatToHalf(1.0f)), MLFloat16(math::floatToHalf(2.0f)), MLFloat16(math::floatToHalf(3.0f))}); + test.AddInput("data_0", {3, 1}, {MLFloat16(1.0f), MLFloat16(2.0f), MLFloat16(3.0f)}); test.AddInput("data_1", {2}, {1, 3}); test.AddOutput("result", {3, 3}, - {MLFloat16(math::floatToHalf(1.0f)), MLFloat16(math::floatToHalf(1.0f)), MLFloat16(math::floatToHalf(1.0f)), - MLFloat16(math::floatToHalf(2.0f)), MLFloat16(math::floatToHalf(2.0f)), MLFloat16(math::floatToHalf(2.0f)), - MLFloat16(math::floatToHalf(3.0f)), MLFloat16(math::floatToHalf(3.0f)), MLFloat16(math::floatToHalf(3.0f))}); + {MLFloat16(1.0f), MLFloat16(1.0f), MLFloat16(1.0f), + MLFloat16(2.0f), MLFloat16(2.0f), MLFloat16(2.0f), + MLFloat16(3.0f), MLFloat16(3.0f), MLFloat16(3.0f)}); test.Run(); } diff --git a/onnxruntime/test/providers/cpu/tensor/gather_op_test.cc b/onnxruntime/test/providers/cpu/tensor/gather_op_test.cc index 0f199d3fc9f5f..be79a6d29d539 100644 --- a/onnxruntime/test/providers/cpu/tensor/gather_op_test.cc +++ b/onnxruntime/test/providers/cpu/tensor/gather_op_test.cc @@ -99,10 +99,12 @@ TEST(GatherOpTest, Gather_invalid_index_cpu) { SessionOptions so; // Ignore the shape inference error so that we can hit the invalid index error. ASSERT_STATUS_OK(so.config_options.AddConfigEntry(kOrtSessionOptionsConfigStrictShapeTypeInference, "0")); - test.Run(so, OpTester::ExpectResult::kExpectFailure, "indices element out of data bounds, idx=1000 must be within the inclusive range [-3,2]", - // On Cuda it is impossible to dereference indices memory on CPU so the check can not run - {kCudaExecutionProvider, kOpenVINOExecutionProvider, kDnnlExecutionProvider, kTensorrtExecutionProvider, - kNnapiExecutionProvider, kDmlExecutionProvider, kQnnExecutionProvider}); + test + .Config(so) + .Config(OpTester::ExpectResult::kExpectFailure, + "indices element out of data bounds, idx=1000 must be within the inclusive range [-3,2]") + .ConfigEp(DefaultCpuExecutionProvider()) + .RunWithConfig(); } #if defined(USE_CUDA) || defined(USE_ROCM) @@ -121,7 +123,13 @@ TEST(GatherOpTest, Gather_invalid_index_gpu) { 0.0f, 0.0f, 0.0f, 0.0f}); // On GPU, just set the value to 0 instead of report error. exclude all other providers - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kCpuExecutionProvider, kDnnlExecutionProvider, kTensorrtExecutionProvider}); + test +#if defined(USE_CUDA) + .ConfigEp(DefaultCudaExecutionProvider()) +#else + .ConfigEp(DefaultRocmExecutionProvider()) +#endif + .RunWithConfig(); } #endif @@ -262,94 +270,54 @@ TEST(GatherOpTest, Gather_axis0_indices2dInt32) { test.Run(); } -TEST(GatherOpTest, Gather_axis1_indices2d_int32) { +template +static void TestGatherAxis1Indices2DIntData(const std::unordered_set& excluded_provider_types = {}) { + static_assert(std::is_integral_v, "TInt is not an integral type"); + OpTester test("Gather"); test.AddAttribute("axis", 1LL); - test.AddInput("data", {3, 3}, - {0, 1, 2, - 10, 11, 12, - 20, 21, 22}); + test.AddInput("data", {3, 3}, + {0, 1, 2, + 10, 11, 12, + 20, 21, 22}); test.AddInput("indices", {2, 2}, {1, 0, 2, 1}); - test.AddOutput("output", {3, 2, 2}, - {1, 0, 2, 1, - 11, 10, 12, 11, - 21, 20, 22, 21}); - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); // TensorRT: Input batch size is inconsistent + test.AddOutput("output", {3, 2, 2}, + {1, 0, 2, 1, + 11, 10, 12, 11, + 21, 20, 22, 21}); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", excluded_provider_types); +} + +TEST(GatherOpTest, Gather_axis1_indices2d_int64) { + TestGatherAxis1Indices2DIntData(); +} + +TEST(GatherOpTest, Gather_axis1_indices2d_uint64) { + TestGatherAxis1Indices2DIntData(); +} + +TEST(GatherOpTest, Gather_axis1_indices2d_int32) { + TestGatherAxis1Indices2DIntData( + {kTensorrtExecutionProvider}); // TensorRT: Input batch size is inconsistent } TEST(GatherOpTest, Gather_axis1_indices2d_uint32) { - OpTester test("Gather"); - test.AddAttribute("axis", 1LL); - test.AddInput("data", {3, 3}, - {0, 1, 2, - 10, 11, 12, - 20, 21, 22}); - test.AddInput("indices", {2, 2}, - {1, 0, - 2, 1}); - test.AddOutput("output", {3, 2, 2}, - {1, 0, 2, 1, - 11, 10, 12, 11, - 21, 20, 22, 21}); - test.Run(); + TestGatherAxis1Indices2DIntData(); } TEST(GatherOpTest, Gather_axis1_indices2d_int16) { - OpTester test("Gather"); - test.AddAttribute("axis", 1LL); - test.AddInput("data", {3, 3}, - {0, 1, 2, - 10, 11, 12, - 20, 21, 22}); - test.AddInput("indices", {2, 2}, - {1, 0, - 2, 1}); - test.AddOutput("output", {3, 2, 2}, - {1, 0, 2, 1, - 11, 10, 12, 11, - 21, 20, 22, 21}); - - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); + TestGatherAxis1Indices2DIntData({kOpenVINOExecutionProvider}); } TEST(GatherOpTest, Gather_axis1_indices2d_uint16) { - OpTester test("Gather"); - test.AddAttribute("axis", 1LL); - test.AddInput("data", {3, 3}, - {0, 1, 2, - 10, 11, 12, - 20, 21, 22}); - test.AddInput("indices", {2, 2}, - {1, 0, - 2, 1}); - test.AddOutput("output", {3, 2, 2}, - {1, 0, 2, 1, - 11, 10, 12, 11, - 21, 20, 22, 21}); - test.Run(); + TestGatherAxis1Indices2DIntData(); } TEST(GatherOpTest, Gather_axis1_indices2d_int8) { - OpTester test("Gather"); - test.AddAttribute("axis", 1LL); - test.AddInput("data", {3, 3}, - {0, 1, 2, - 10, 11, 12, - 20, 21, 22}); - test.AddInput("indices", {2, 2}, - {1, 0, - 2, 1}); - test.AddOutput("output", {3, 2, 2}, - {1, 0, 2, 1, - 11, 10, 12, 11, - 21, 20, 22, 21}); -#if defined(OPENVINO_CONFIG_MYRIAD) - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kOpenVINOExecutionProvider}); // OpenVINO: Disabled temporarily -#else - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); // TensorRT: Assertion `regionRanges != nullptr' failed -#endif + TestGatherAxis1Indices2DIntData( + {kTensorrtExecutionProvider}); // TensorRT: Assertion `regionRanges != nullptr' failed } TEST(GatherOpTest, Gather_axis1_indices2d_string) { @@ -383,11 +351,7 @@ TEST(GatherOpTest, Gather_axis1_indices2d_bool) { {false, true, true, false, true, true, false, true, true, false, false, true}); -#if defined(OPENVINO_CONFIG_MYRIAD) - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); // OpenVINO: Disabled temporarily -#else test.Run(); -#endif } TEST(GatherOpTest, Gather_perf) { @@ -423,6 +387,49 @@ TEST(GatherOpTest, Gather_axis1_neg_indices2d_int8) { test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kOpenVINOExecutionProvider}); // TensorRT: Assertion `regionRanges != nullptr' failed } +// pytorch converter can emit Gather with a scalar indices which equates to a slice from that axis and the axis +// essentially being squeezed. +TEST(GatherOpTest, Gather_axis0_scalar_indices) { + // To test for NNAPI EP, we need the indices to be initializers + auto run_test = [](bool indices_is_initializer) { + OpTester test("Gather"); + test.AddAttribute("axis", 0LL); + test.AddInput("data", {2, 2, 2}, + {0.00f, 0.01f, + 0.10f, 0.11f, + 1.00f, 1.01f, + 1.10f, 1.11f}); + test.AddInput("indices", {}, {1LL}, indices_is_initializer); + test.AddOutput("output", {2, 2}, // second and third dims. first dim is reduced to 1 and squeezed + {1.00f, 1.01f, + 1.10f, 1.11f}); + test.Run(); + }; + + run_test(false); + run_test(true); +} + +TEST(GatherOpTest, Gather_axis1_scalar_indices) { + // To test for NNAPI EP, we need the indices to be initializers + auto run_test = [](bool indices_is_initializer) { + OpTester test("Gather"); + test.AddAttribute("axis", 1LL); + test.AddInput("data", {2, 2, 2}, + {0.00f, 0.01f, + 0.10f, 0.11f, + 1.00f, 1.01f, + 1.10f, 1.11f}); + test.AddInput("indices", {}, {1LL}, indices_is_initializer); + test.AddOutput("output", {2, 2}, // first and third dims. second dim is reduced to 1 and squeezed + {0.10f, 0.11f, + 1.10f, 1.11f}); + test.Run(); + }; + + run_test(false); + run_test(true); +} #ifdef ENABLE_TRAINING_OPS // Should remove the shrunken_gather include from ENABLE_TRAINING_OPS once 1). compute optimizer is enabled for inference or // 2). this is needed by inference for other purpose. diff --git a/onnxruntime/test/providers/cpu/tensor/gen_mvn_test_data.py b/onnxruntime/test/providers/cpu/tensor/gen_mvn_test_data.py new file mode 100644 index 0000000000000..a7c1be435d712 --- /dev/null +++ b/onnxruntime/test/providers/cpu/tensor/gen_mvn_test_data.py @@ -0,0 +1,37 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import argparse + +import numpy as np + +parser = argparse.ArgumentParser() +parser.add_argument("--shape", type=int, nargs="+", required=True) +parser.add_argument("--axes", type=int, nargs="+", required=True) +args = parser.parse_args() + +shape = tuple(args.shape) +axes = tuple(args.axes) + +random_seed = 0 +rng = np.random.default_rng(random_seed) + +X = rng.random(size=shape, dtype=float) + +# Calculate expected output data +X_mean = np.mean(X, axis=axes, keepdims=True) +X_std = np.std(X, axis=axes, keepdims=True) +Y = (X - X_mean) / X_std + + +def to_c_float_literals(arr): + literals_per_line = 8 + literals = [f"{literal:.7f}f" for literal in arr.flatten().tolist()] + result = "" + for i, literal in enumerate(literals): + result += "{},{}".format(literal, "\n" if (i + 1) % literals_per_line == 0 else " ") + return result + + +print(f"input:\n{to_c_float_literals(X)}") +print(f"expected output:\n{to_c_float_literals(Y)}") diff --git a/onnxruntime/test/providers/cpu/tensor/identity_op_test.cc b/onnxruntime/test/providers/cpu/tensor/identity_op_test.cc index 4b26315e61a9b..a6167f290bfaf 100644 --- a/onnxruntime/test/providers/cpu/tensor/identity_op_test.cc +++ b/onnxruntime/test/providers/cpu/tensor/identity_op_test.cc @@ -38,9 +38,6 @@ TEST(Identity, SequenceType) { TEST(Identity, OptionalTensorType_NonNone) { OpTester test("Identity", 16, kOnnxDomain); - // Since this test is being written at a time when only opset 15 has been released, we set - // `test_allow_released_onnx_opset_only_` to 'false' to allow this test to run - test.test_allow_released_onnx_opset_only_ = false; std::initializer_list data = {-1.0856307f, 0.99734545f}; test.AddOptionalTypeTensorInput("A", {2}, &data); @@ -50,9 +47,6 @@ TEST(Identity, OptionalTensorType_NonNone) { TEST(Identity, OptionalTensorType_None) { OpTester test("Identity", 16, kOnnxDomain); - // Since this test is being written at a time when only opset 15 has been released, we set - // `test_allow_released_onnx_opset_only_` to 'false' to allow this test to run - test.test_allow_released_onnx_opset_only_ = false; test.AddOptionalTypeTensorInput("A", {}, nullptr); // None test.AddOptionalTypeTensorOutput("Y", {}, nullptr); // None @@ -61,9 +55,6 @@ TEST(Identity, OptionalTensorType_None) { TEST(Identity, OptionalTensorSequenceType_NonNone) { OpTester test("Identity", 16, kOnnxDomain); - // Since this test is being written at a time when only opset 15 has been released, we set - // `test_allow_released_onnx_opset_only_` to 'false' to allow this test to run - test.test_allow_released_onnx_opset_only_ = false; SeqTensors input; input.AddTensor({3, 2}, {1, 2, 3, 4, 5, 6}); @@ -76,9 +67,6 @@ TEST(Identity, OptionalTensorSequenceType_NonNone) { TEST(Identity, OptionalTensorSequenceType_None) { OpTester test("Identity", 16, kOnnxDomain); - // Since this test is being written at a time when only opset 15 has been released, we set - // `test_allow_released_onnx_opset_only_` to 'false' to allow this test to run - test.test_allow_released_onnx_opset_only_ = false; test.AddOptionalTypeSeqInput("A", nullptr); // None test.AddOptionalTypeSeqOutput("Y", nullptr); // None diff --git a/onnxruntime/test/providers/cpu/tensor/isnan_test.cc b/onnxruntime/test/providers/cpu/tensor/isnan_test.cc index 53aeb0224b4e6..0dffc452b519d 100644 --- a/onnxruntime/test/providers/cpu/tensor/isnan_test.cc +++ b/onnxruntime/test/providers/cpu/tensor/isnan_test.cc @@ -20,7 +20,7 @@ TEST(IsNaNOpTest, IsNaNFloat) { TEST(IsNaNOpTest, IsNaNFloat16) { OpTester test("IsNaN", 9, kOnnxDomain); std::vector dims{2, 2}; - test.AddInput("X", dims, std::initializer_list({MLFloat16(math::floatToHalf(1.0f)), MLFloat16(math::floatToHalf(NAN)), MLFloat16(math::floatToHalf(2.0f)), MLFloat16(math::floatToHalf(NAN))})); + test.AddInput("X", dims, std::initializer_list({MLFloat16(1.0f), MLFloat16::NaN, MLFloat16(2.0f), MLFloat16::NaN})); test.AddOutput("Y", dims, {false, true, false, true}); test.Run(); } diff --git a/onnxruntime/test/providers/cpu/tensor/mean_variance_normalization_test.cc b/onnxruntime/test/providers/cpu/tensor/mean_variance_normalization_test.cc new file mode 100644 index 0000000000000..b6720ae2a9a7d --- /dev/null +++ b/onnxruntime/test/providers/cpu/tensor/mean_variance_normalization_test.cc @@ -0,0 +1,273 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "gtest/gtest.h" + +#include "test/common/tensor_op_test_utils.h" +#include "test/providers/provider_test_utils.h" + +namespace onnxruntime::test { + +TEST(MeanVarianceNormalizationTest, DefaultAxes) { + constexpr int64_t N = 2, C = 2, H = 2, W = 3; + + std::vector N1C1 = {3.0f, -3.0f, -1.0f, + 1.0f, 2.0f, -1.0f}; + std::vector N1C2 = {-2.0f, -2.0f, -2.0f, + 4.0f, 1.0f, 4.0f}; + std::vector N2C1 = { + 0.0f, + -2.0f, + -2.0f, + -4.0f, + 5.0f, + 7.0f, + }; + std::vector N2C2 = { + 5.0f, + -5.0f, + -5.0f, + 3.0f, + 4.0f, + 4.0f, + }; + + std::vector X; + X.reserve(N * C * H * W); + X.insert(X.end(), N1C1.begin(), N1C1.end()); + X.insert(X.end(), N1C2.begin(), N1C2.end()); + X.insert(X.end(), N2C1.begin(), N2C1.end()); + X.insert(X.end(), N2C2.begin(), N2C2.end()); + + std::vector C1; + C1.reserve(N * H * W); + C1.insert(C1.end(), N1C1.begin(), N1C1.end()); + C1.insert(C1.end(), N2C1.begin(), N2C1.end()); + auto C1_meam_stdev = MeanStdev(C1); + + std::vector C2; + C2.reserve(N * H * W); + C2.insert(C2.end(), N1C2.begin(), N1C2.end()); + C2.insert(C2.end(), N2C2.begin(), N2C2.end()); + auto C2_meam_stdev = MeanStdev(C2); + + std::vector N1C1_result(N1C1), N1C2_result(N1C2), + N2C1_result(N2C1), N2C2_result(N2C2); + Normalize(N1C1_result, C1_meam_stdev, true); + Normalize(N2C1_result, C1_meam_stdev, true); + Normalize(N1C2_result, C2_meam_stdev, true); + Normalize(N2C2_result, C2_meam_stdev, true); + + std::vector result; + result.reserve(N * C * H * W); + result.insert(result.end(), N1C1_result.begin(), N1C1_result.end()); + result.insert(result.end(), N1C2_result.begin(), N1C2_result.end()); + result.insert(result.end(), N2C1_result.begin(), N2C1_result.end()); + result.insert(result.end(), N2C2_result.begin(), N2C2_result.end()); + + OpTester test("MeanVarianceNormalization", 9); + test.AddInput("input", {N, C, H, W}, X); + test.AddOutput("output", {N, C, H, W}, result); + test.Run(); +} + +static void TestMeanVarianceNormalizationOverAllAxes(const std::vector& shape) { + SCOPED_TRACE(MakeString("shape: ", TensorShape(shape))); + + FixedPatternValueGenerator generator{}; + + const auto X_value_candidates = ValueRange(11, -5.0f); + const auto X = generator.Discrete(shape, X_value_candidates); + const auto mean_stdev = MeanStdev(X); + + std::vector Y(X); + Normalize(Y, mean_stdev, true); + + OpTester test("MeanVarianceNormalization", 9); + const auto all_axes = ValueRange(shape.size()); + test.AddAttribute("axes", all_axes); + test.AddInput("input", shape, X); + test.AddOutput("output", shape, Y); + + test.Run(); +} + +TEST(MeanVarianceNormalizationTest, AllAxes) { + TestMeanVarianceNormalizationOverAllAxes({2, 2, 4}); + TestMeanVarianceNormalizationOverAllAxes({2, 2, 2, 3}); + TestMeanVarianceNormalizationOverAllAxes({2, 2, 2, 2, 2}); +} + +TEST(MeanVarianceNormalizationTest, AxesSubsets5D) { + // test data was generated with: + // python onnxruntime/test/providers/cpu/tensor/gen_mvn_test_data.py --shape 2 2 2 2 2 --axes + + auto axes_to_str = [](gsl::span axes) { + std::ostringstream s; + s << "{ "; + std::copy(axes.begin(), axes.end(), std::ostream_iterator(s, " ")); + s << "}"; + return s.str(); + }; + + auto test_with_axes = [&](gsl::span axes, gsl::span Y) { + SCOPED_TRACE(axes_to_str(axes)); + + constexpr std::array X = { + 0.6369617f, + 0.2697867f, + 0.0409735f, + 0.0165276f, + 0.8132702f, + 0.9127556f, + 0.6066358f, + 0.7294966f, + 0.5436250f, + 0.9350724f, + 0.8158536f, + 0.0027385f, + 0.8574043f, + 0.0335856f, + 0.7296554f, + 0.1756556f, + 0.8631789f, + 0.5414612f, + 0.2997119f, + 0.4226872f, + 0.0283197f, + 0.1242833f, + 0.6706244f, + 0.6471895f, + 0.6153851f, + 0.3836776f, + 0.9972099f, + 0.9808353f, + 0.6855420f, + 0.6504593f, + 0.6884467f, + 0.3889214f, + }; + + const std::vector shape{2, 2, 2, 2, 2}; + + OpTester test("MeanVarianceNormalization", 9); + test.AddAttribute("axes", axes); + test.AddInput("input", shape, X.data(), X.size()); + test.AddOutput("output", shape, Y.data(), Y.size()); + + test.Run(); + }; + + test_with_axes( + AsSpan({0, 2, 4}), + AsSpan({ + 0.3508345f, + -0.7870349f, + -1.4605863f, + -1.5525494f, + 0.8972119f, + 1.2055154f, + 0.6673803f, + 1.1295706f, + -0.1683330f, + 1.3134559f, + 0.6321192f, + -1.7208749f, + 1.0194501f, + -2.0990413f, + 0.3826789f, + -1.2204870f, + 1.0518781f, + 0.0548801f, + -0.4872377f, + -0.0246164f, + -1.5353374f, + -1.2379477f, + 0.9080993f, + 0.8199395f, + 0.1033084f, + -0.7737996f, + 1.1569287f, + 1.1095439f, + 0.3688809f, + 0.2360785f, + 0.2634291f, + -0.6033379f, + })); + + test_with_axes( + AsSpan({1, 2, 3}), + AsSpan({ + 0.0260567f, + -0.3008327f, + -2.3950341f, + -0.9652744f, + 0.7422773f, + 1.3860379f, + -0.0971367f, + 0.9052460f, + -0.3531062f, + 1.4445876f, + 0.7527716f, + -1.0014510f, + 0.9215636f, + -0.9205217f, + 0.4026078f, + -0.5477917f, + 0.8924309f, + 0.1015335f, + -1.0632416f, + -0.4004898f, + -2.0051854f, + -1.6617567f, + 0.2241158f, + 0.5484163f, + 0.0323921f, + -0.5653723f, + 1.3576236f, + 1.9586404f, + 0.2758914f, + 0.5622366f, + 0.2859732f, + -0.5432080f, + })); + + test_with_axes( + AsSpan({0, 1, 4}), + AsSpan({ + 0.1843672f, + -1.5822912f, + -1.0098907f, + -1.0706838f, + 0.8350127f, + 1.1118552f, + 0.1472972f, + 0.8161319f, + -0.2647213f, + 1.6187237f, + 0.9171133f, + -1.1049752f, + 0.9578265f, + -1.3346525f, + 0.8169968f, + -2.1988905f, + 1.2728089f, + -0.2751323f, + -0.3664493f, + -0.0606291f, + -1.3493062f, + -1.0822638f, + 0.4956413f, + 0.3680653f, + 0.0805517f, + -1.0343067f, + 1.3681179f, + 1.3273969f, + 0.4795772f, + 0.3819509f, + 0.5926631f, + -1.0379052f, + })); +} + +} // namespace onnxruntime::test diff --git a/onnxruntime/test/providers/cpu/tensor/pad_test.cc b/onnxruntime/test/providers/cpu/tensor/pad_test.cc index 184527487a779..5fc8ed417391e 100644 --- a/onnxruntime/test/providers/cpu/tensor/pad_test.cc +++ b/onnxruntime/test/providers/cpu/tensor/pad_test.cc @@ -47,14 +47,7 @@ static void RunOnnxOpsetTypedTest( if (expect != OpTester::ExpectResult::kExpectSuccess) { ASSERT_STATUS_OK(so.config_options.AddConfigEntry(kOrtSessionOptionsConfigStrictShapeTypeInference, "0")); } - if constexpr (opset >= 11) { - test.Run(so, expect, error_msg, provider_types); - } else { -#if defined(OPENVINO_CONFIG_MYRIAD) || defined(OPENVINO_CONFIG_VAD_M) - provider_types.insert(kOpenVINOExecutionProvider); -#endif - test.Run(so, expect, error_msg, provider_types); - } + test.Run(so, expect, error_msg, provider_types); } template @@ -180,6 +173,19 @@ TYPED_TEST(PadOpTest, Pad_Reflect_1D) { "reflect"); } +TYPED_TEST(PadOpTest, Pad_Wrap_1D) { + using T = TypeParam; + RunOnnxOpsetTypedTest({3, 2}, + {T(1), T(2), T(3), T(4), T(5), T(6)}, + {0, 1, 0, 1}, + false, + T(0), + false, + {3, 4}, + {T(2), T(1), T(2), T(1), T(4), T(3), T(4), T(3), T(6), T(5), T(6), T(5)}, + "wrap"); +} + TYPED_TEST(PadOpTest, Pad_Edge_1D) { using T = TypeParam; RunAllOpsetAllDomainPadTests({3, 2}, @@ -370,6 +376,27 @@ TYPED_TEST(PadOpTest, Pad_Reflect_2D) { "reflect"); } +TYPED_TEST(PadOpTest, Pad_Wrap_2D) { + using T = TypeParam; + RunOnnxOpsetTypedTest({3, 3}, + {T(11), T(21), T(31), + T(12), T(22), T(32), + T(13), T(23), T(33)}, + {2, 2, 2, 2}, + false, + T(0), + false, + {7, 7}, + {T(22), T(32), T(12), T(22), T(32), T(12), T(22), + T(23), T(33), T(13), T(23), T(33), T(13), T(23), + T(21), T(31), T(11), T(21), T(31), T(11), T(21), + T(22), T(32), T(12), T(22), T(32), T(12), T(22), + T(23), T(33), T(13), T(23), T(33), T(13), T(23), + T(21), T(31), T(11), T(21), T(31), T(11), T(21), + T(22), T(32), T(12), T(22), T(32), T(12), T(22)}, + "wrap"); +} + TYPED_TEST(PadOpTest, Pad_Constant_3D_Inner_No_Padding) { using T = TypeParam; RunAllOpsetAllDomainPadTests({3, 2, 5}, @@ -547,6 +574,99 @@ TYPED_TEST(PadOpTest, Pad_Reflect_3D_Inner_No_Padding) { "reflect"); } +TYPED_TEST(PadOpTest, Pad_wrap_3D_Inner_No_Padding) { + using T = TypeParam; + RunOnnxOpsetTypedTest({3, 2, 5}, + {T(1), T(2), T(3), T(4), T(5), + T(6), T(7), T(8), T(9), T(10), + T(11), T(12), T(13), T(14), T(15), + T(16), T(17), T(18), T(19), T(20), + T(21), T(22), T(23), T(24), T(25), + T(26), T(27), T(28), T(29), T(30)}, + {1, 1, 0, 1, 1, 0}, + false, + T(0), + false, + {5, 4, 5}, + {T(26), T(27), T(28), T(29), T(30), + T(21), T(22), T(23), T(24), T(25), + T(26), T(27), T(28), T(29), T(30), + T(21), T(22), T(23), T(24), T(25), + + T(6), T(7), T(8), T(9), T(10), + T(1), T(2), T(3), T(4), T(5), + T(6), T(7), T(8), T(9), T(10), + T(1), T(2), T(3), T(4), T(5), + + T(16), T(17), T(18), T(19), T(20), + T(11), T(12), T(13), T(14), T(15), + T(16), T(17), T(18), T(19), T(20), + T(11), T(12), T(13), T(14), T(15), + + T(26), T(27), T(28), T(29), T(30), + T(21), T(22), T(23), T(24), T(25), + T(26), T(27), T(28), T(29), T(30), + T(21), T(22), T(23), T(24), T(25), + + T(6), T(7), T(8), T(9), T(10), + T(1), T(2), T(3), T(4), T(5), + T(6), T(7), T(8), T(9), T(10), + T(1), T(2), T(3), T(4), T(5)}, + "wrap"); +} + +TYPED_TEST(PadOpTest, Pad_wrap_3D_Inner_No_Padding2) { + using T = TypeParam; + + RunOnnxOpsetTypedTest({3, 2, 5}, + {T(1), T(2), T(3), T(4), T(5), + T(6), T(7), T(8), T(9), T(10), + T(11), T(12), T(13), T(14), T(15), + T(16), T(17), T(18), T(19), T(20), + T(21), T(22), T(23), T(24), T(25), + T(26), T(27), T(28), T(29), T(30)}, + {1, 2, 0, 1, 2, 0}, + false, + T(0), + false, + {5, 6, 5}, + {T(21), T(22), T(23), T(24), T(25), + T(26), T(27), T(28), T(29), T(30), + T(21), T(22), T(23), T(24), T(25), + T(26), T(27), T(28), T(29), T(30), + T(21), T(22), T(23), T(24), T(25), + T(26), T(27), T(28), T(29), T(30), + + T(1), T(2), T(3), T(4), T(5), + T(6), T(7), T(8), T(9), T(10), + T(1), T(2), T(3), T(4), T(5), + T(6), T(7), T(8), T(9), T(10), + T(1), T(2), T(3), T(4), T(5), + T(6), T(7), T(8), T(9), T(10), + + T(11), T(12), T(13), T(14), T(15), + T(16), T(17), T(18), T(19), T(20), + T(11), T(12), T(13), T(14), T(15), + T(16), T(17), T(18), T(19), T(20), + T(11), T(12), T(13), T(14), T(15), + T(16), T(17), T(18), T(19), T(20), + + T(21), T(22), T(23), T(24), T(25), + T(26), T(27), T(28), T(29), T(30), + T(21), T(22), T(23), T(24), T(25), + T(26), T(27), T(28), T(29), T(30), + T(21), T(22), T(23), T(24), T(25), + T(26), T(27), T(28), T(29), T(30), + + T(1), T(2), T(3), T(4), T(5), + T(6), T(7), T(8), T(9), T(10), + T(1), T(2), T(3), T(4), T(5), + T(6), T(7), T(8), T(9), T(10), + T(1), T(2), T(3), T(4), T(5), + T(6), T(7), T(8), T(9), T(10)}, + "wrap"); +} + TYPED_TEST(PadOpTest, Pad_Reflect_3D_Last_Pad_Slice_Inner_No_Padding) { using T = TypeParam; RunAllOpsetAllDomainPadTests({2, 3, 5}, @@ -891,6 +1011,24 @@ TEST(PadOpTest, ConstantPadAxesTest3) { test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kNnapiExecutionProvider}); } +TEST(PadOpTest, ConstantPadAxesTest4) { + OpTester test("Pad", 18); + test.AddAttribute("mode", "constant"); + test.AddInput("data", {1, 2, 2, 2}, + {1.0f, 1.0f, + 1.0f, 1.0f, + 1.0f, 1.0f, + 1.0f, 1.0f}); + test.AddInput("pads", {8}, {0, 0, 0, 1, 0, 0, 0, 1}, true /* pads_is_initializer */); + test.AddInput("value", {1}, {0.0f}, true /* value_is_initializer */); + test.AddOutput("output", {1, 2, 2, 4}, + {0.0f, 1.0f, 1.0f, 0.0f, + 0.0f, 1.0f, 1.0f, 0.0f, + 0.0f, 1.0f, 1.0f, 0.0f, + 0.0f, 1.0f, 1.0f, 0.0f}); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kNnapiExecutionProvider}); +} + TEST(PadOpTest, ConstantPadAxesOutOfOrder) { // Specified out of order axes values OpTester test("Pad", 18); @@ -931,12 +1069,7 @@ TEST(PadOpTest, ConstantPadAxesWithOneDimensionSpecified) { test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kNnapiExecutionProvider}); } -/* - Note: Disable the Negative Axes test for ConstantPad for now until onnx shape inferencing - add support for handling negative axes. - Issue link to the bug: https://github.com/onnx/onnx/issues/5003 -*/ -TEST(PadOpTest, DISABLED_ConstantPadNegativeAxes) { +TEST(PadOpTest, ConstantPadNegativeAxes) { // Specified negative axes value OpTester test("Pad", 18); test.AddAttribute("mode", "constant"); diff --git a/onnxruntime/test/providers/cpu/tensor/quantize_linear_test.cc b/onnxruntime/test/providers/cpu/tensor/quantize_linear_test.cc index 9af630a48e91d..f4b21823a487b 100644 --- a/onnxruntime/test/providers/cpu/tensor/quantize_linear_test.cc +++ b/onnxruntime/test/providers/cpu/tensor/quantize_linear_test.cc @@ -2,6 +2,7 @@ // Licensed under the MIT License. #include "gtest/gtest.h" +#include "test/common/cuda_op_test_utils.h" #include "test/providers/provider_test_utils.h" #include "test/util/include/default_providers.h" @@ -74,6 +75,17 @@ TEST(DequantizeLinearOpTest, Scalar) { test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); } +// dequantize with scalar data +TEST(DequantizeLinearOpMLFloat16Test, Scalar) { + OpTester test("DequantizeLinear", 19); + test.AddInput("x", {}, {100}); + test.AddInput("x_scale", {}, {MLFloat16(2.0f)}); + 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}); +} + // dequantize without zero point TEST(DequantizeLinearOpTest, Without_Zero_Point) { // TODO: Unskip when fixed #41968513 @@ -193,7 +205,8 @@ TEST(DequantizeLinearOpTest, Per_Channel_Axis_1_int32) { 0, 4, 16, 48, 0, 20, 80, 240}); // Disable Tensorrt EP due to error, only activation types allowed as input to this layer. - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); + // Disable CUDA, ROCm EP, there is no implementation for int32_t. + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kCudaExecutionProvider, kRocmExecutionProvider}); } // 1d zero & scale with uint8 broadcast axis -2 (-2 resolves to axis 0) @@ -231,6 +244,16 @@ TEST(QuantizeLinearOpTest, Uint8) { test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); // TensorRT doesn't support support UINT8 for quantization } +TEST(QuantizeLinearOpMLFloat16Test, Uint8) { + OpTester test("QuantizeLinear", 19); + std::vector dims{6}; + test.AddInput("x", dims, {MLFloat16(0.0f), MLFloat16(2.0f), MLFloat16(4.0f), MLFloat16(1000.0f), MLFloat16(-254.0f), MLFloat16(-1000.0f)}); + test.AddInput("y_scale", {}, {MLFloat16(2.0f)}); + test.AddInput("y_zero_point", {}, {128}); + test.AddOutput("y", dims, {128, 129, 130, 255, 1, 0}); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); // TensorRT doesn't support support UINT8 for quantization +} + // quantize with scalar zero point and scale TEST(QuantizeLinearOpTest, Int8) { // TODO: Unskip when fixed #41968513 @@ -310,14 +333,54 @@ TEST(QuantizeLinearOpTest, Scalar) { } // quantize with scalar data -TEST(QuantizeLinearOpTest, DISABLED_QuantizeLinear_Without_Zero_Point) { +TEST(QuantizeLinearOpTest, QuantizeLinear_Without_Zero_Point_Opset10) { + // TODO: Unskip when fixed #41968513 + if (DefaultDmlExecutionProvider().get() != nullptr) { + GTEST_SKIP() << "Skipping because of the following error: AbiCustomRegistry.cpp(507): The parameter is incorrect"; + } + + OpTester test("QuantizeLinear", 10); + test.AddInput("x", {}, {3}); + test.AddInput("y_scale", {}, {2.0f}); + test.AddOutput("y", {}, {2}); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); // TensorRT doesn't support support UINT8 for quantization +} + +TEST(QuantizeLinearOpTest, QuantizeLinear_Without_Zero_Point_Opset13) { + // TODO: Unskip when fixed #41968513 + if (DefaultDmlExecutionProvider().get() != nullptr) { + GTEST_SKIP() << "Skipping because of the following error: AbiCustomRegistry.cpp(507): The parameter is incorrect"; + } + + OpTester test("QuantizeLinear", 13); + test.AddInput("x", {}, {3}); + test.AddInput("y_scale", {}, {2.0f}); + test.AddOutput("y", {}, {2}); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); // TensorRT doesn't support support UINT8 for quantization +} + +TEST(QuantizeLinearOpTest, QuantizeLinear_With_Zero_Point0) { OpTester test("QuantizeLinear", 10); test.AddInput("x", {}, {3}); test.AddInput("y_scale", {}, {2.0f}); + test.AddInput("y_zero_point", {}, {0}); test.AddOutput("y", {}, {2}); test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); // TensorRT doesn't support support UINT8 for quantization } +TEST(QuantizeLinearOpTest, QuantizeLinear_With_Zero_Dim1) { + // TODO: Unskip when fixed #41968513 + if (DefaultDmlExecutionProvider().get() != nullptr) { + GTEST_SKIP() << "Skipping because of the following error: AbiCustomRegistry.cpp(507): The parameter is incorrect"; + } + + OpTester test("QuantizeLinear", 10); + test.AddInput("x", {1}, {3}); + test.AddInput("y_scale", {1}, {2.0f}); + test.AddOutput("y", {1}, {2}); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); // TensorRT doesn't support support UINT8 for quantization +} + TEST(QuantizeLinearOpTest, Per_Channel_Axis_Default) { OpTester test("QuantizeLinear", 13); std::vector dims{3, 4}; @@ -369,5 +432,144 @@ TEST(QuantizeLinearOpTest, Per_Channel_Axis_neg) { test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); // TensorRT doesn't support support UINT8 for quantization } +#if !defined(DISABLE_FLOAT8_TYPES) + +template +void DequantizeLinearOp19Test() { + OpTester test("DequantizeLinear", 19); + std::vector dims{4}; + std::vector x; + x.push_back(InT(0.0f, true)); + x.push_back(InT(1.0f, true)); + x.push_back(InT(2.0f, true)); + x.push_back(InT(3.0f, true)); + test.AddInput("x", dims, x); + test.AddInput("x_scale", {}, {static_cast(1.0f)}); + test.AddInput("x_zero_point", {}, {InT(0.0f, true)}); + std::vector y; + for (auto it : x) { + y.push_back(static_cast(it.ToFloat())); + } + test.AddOutput("y", dims, y); + // Disable Tensorrt EP due to error:node1_quantize_scale_node: out of bounds channel axis 1. Number of input dimensions is 1. + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); +} + +TEST(DequantizeLinearOpTest, Float8) { + constexpr int min_cuda_architecture = 11080; + bool enable_cuda = (nullptr != DefaultCpuExecutionProvider().get()) && HasCudaEnvironment(min_cuda_architecture); + bool enable_cpu = (nullptr != DefaultCpuExecutionProvider().get()); + + if (enable_cpu || enable_cuda) + DequantizeLinearOp19Test(); + if (enable_cpu) + DequantizeLinearOp19Test(); + if (enable_cpu || enable_cuda) + DequantizeLinearOp19Test(); + if (enable_cpu) + DequantizeLinearOp19Test(); +} + +TEST(DequantizeLinearOpMLFloat16Test, Float8) { + constexpr int min_cuda_architecture = 11080; + bool enable_cuda = (nullptr != DefaultCpuExecutionProvider().get()) && HasCudaEnvironment(min_cuda_architecture); + bool enable_cpu = (nullptr != DefaultCpuExecutionProvider().get()); + + if (enable_cpu || enable_cuda) + DequantizeLinearOp19Test(); + if (enable_cpu) + DequantizeLinearOp19Test(); + if (enable_cpu || enable_cuda) + DequantizeLinearOp19Test(); + if (enable_cpu) + DequantizeLinearOp19Test(); +} + +template +void QuantizeLinearOp19Test(bool saturate) { + OpTester test("QuantizeLinear", 19); + if (!saturate) { + test.AddAttribute("saturate", 0); + } + std::vector dims{6}; + std::vector x{0, 2, 3, 1000, -254, -1000}; + test.AddInput("x", dims, x); + test.AddInput("y_scale", {}, {1.0f}); + test.AddInput("y_zero_point", {}, {OutT(0.0f, true)}); + std::vector y; + for (auto it : x) { + y.push_back(OutT(it, saturate)); + } + test.AddOutput("y", dims, y); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); +} + +TEST(QuantizeLinearOpTest, Float8) { + constexpr int min_cuda_architecture = 11080; + bool enable_cuda = (nullptr != DefaultCpuExecutionProvider().get()) && HasCudaEnvironment(min_cuda_architecture); + bool enable_cpu = (nullptr != DefaultCpuExecutionProvider().get()); + + if (enable_cpu || enable_cuda) + QuantizeLinearOp19Test(true); + if (enable_cpu) + QuantizeLinearOp19Test(true); + if (enable_cpu || enable_cuda) + QuantizeLinearOp19Test(true); + if (enable_cpu) + QuantizeLinearOp19Test(true); + if (enable_cpu || enable_cuda) + QuantizeLinearOp19Test(false); + if (enable_cpu) + QuantizeLinearOp19Test(false); + if (enable_cpu || enable_cuda) + QuantizeLinearOp19Test(false); + if (enable_cpu) + QuantizeLinearOp19Test(false); +} + +template +void QuantizeLinearOp19F16Test(bool saturate) { + OpTester test("QuantizeLinear", 19); + if (!saturate) { + test.AddAttribute("saturate", 0); + } + std::vector dims{6}; + std::vector x{InT(0.0f), InT(2.0f), InT(3.0f), InT(1000.0f), InT(-254.0f), InT(-1000.0f)}; + test.AddInput("x", dims, x); + test.AddInput("y_scale", {}, {InT(1.0f)}); + test.AddInput("y_zero_point", {}, {OutT(0.0f, true)}); + std::vector y; + for (auto it : x) { + y.push_back(OutT(it, saturate)); + } + test.AddOutput("y", dims, y); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); +} + +TEST(QuantizeLinearOpMLFloat16Test, Float8) { + constexpr int min_cuda_architecture = 11080; + bool enable_cuda = (nullptr != DefaultCpuExecutionProvider().get()) && HasCudaEnvironment(min_cuda_architecture); + bool enable_cpu = (nullptr != DefaultCpuExecutionProvider().get()); + + if (enable_cpu || enable_cuda) + QuantizeLinearOp19F16Test(true); + if (enable_cpu) + QuantizeLinearOp19F16Test(true); + if (enable_cpu || enable_cuda) + QuantizeLinearOp19F16Test(true); + if (enable_cpu) + QuantizeLinearOp19F16Test(true); + if (enable_cpu || enable_cuda) + QuantizeLinearOp19F16Test(false); + if (enable_cpu) + QuantizeLinearOp19F16Test(false); + if (enable_cpu || enable_cuda) + QuantizeLinearOp19F16Test(false); + if (enable_cpu) + QuantizeLinearOp19F16Test(false); +} + +#endif + } // namespace test } // namespace onnxruntime diff --git a/onnxruntime/test/providers/cpu/tensor/resize_op_test.cc b/onnxruntime/test/providers/cpu/tensor/resize_op_test.cc index 25d1acbbd68d8..0434b16dc66ce 100644 --- a/onnxruntime/test/providers/cpu/tensor/resize_op_test.cc +++ b/onnxruntime/test/providers/cpu/tensor/resize_op_test.cc @@ -99,9 +99,8 @@ TEST(ResizeOpTest, NhwcResizeOpLinearDownSampleTest_tf_crop_and_resize_with_extr // CUDA: result mismatch due to not implementing NHWC support // TensorRT: results mismatch // ROCm: results mismatch - // QNN: conflict with layout transformer, need furture investigation test.Run(OpTester::ExpectResult::kExpectSuccess, "", - {kCudaExecutionProvider, kTensorrtExecutionProvider, kRocmExecutionProvider, kQnnExecutionProvider}); + {kCudaExecutionProvider, kTensorrtExecutionProvider, kRocmExecutionProvider}); } TEST(ResizeOpTest, NhwcResizeOpLinearDownSampleTest_tf_crop_and_resize_with_extrapolation_uint8) { @@ -131,7 +130,7 @@ TEST(ResizeOpTest, NhwcResizeOpLinearDownSampleTest_tf_crop_and_resize_with_extr 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 // ROCm: results mismatch - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kCudaExecutionProvider, kRocmExecutionProvider, kQnnExecutionProvider}); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kCudaExecutionProvider, kRocmExecutionProvider}); } TEST(ResizeOpTest, NhwcResizeOpLinearDownSampleTest_tf_crop_and_resize_with_extrapolation_int8) { @@ -159,7 +158,7 @@ TEST(ResizeOpTest, NhwcResizeOpLinearDownSampleTest_tf_crop_and_resize_with_extr 10, 10, 10}; test.AddOutput("Y", {N, static_cast(H * scales[1]), static_cast(W * scales[2]), C}, Y); - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kQnnExecutionProvider}); + test.Run(); } TEST(ResizeOpTest, NhwcResizeOpLinearDownSampleTest_tf_crop_and_resize_without_extrapolation_uint8) { @@ -188,7 +187,7 @@ TEST(ResizeOpTest, NhwcResizeOpLinearDownSampleTest_tf_crop_and_resize_without_e 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 // ROCm: results mismatch - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kCudaExecutionProvider, kRocmExecutionProvider, kQnnExecutionProvider}); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kCudaExecutionProvider, kRocmExecutionProvider}); } TEST(ResizeOpTest, NhwcResizeOpLinearDownSampleTest_tf_crop_and_resize_without_extrapolation_int8) { @@ -215,7 +214,7 @@ TEST(ResizeOpTest, NhwcResizeOpLinearDownSampleTest_tf_crop_and_resize_without_e 0, 0, 0}; test.AddOutput("Y", {N, static_cast(H * scales[1]), static_cast(W * scales[2]), C}, Y); - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kQnnExecutionProvider}); + test.Run(); } TEST(ResizeOpTest, ResizeOpLinearDownSampleTest_4DBilinear) { @@ -261,9 +260,8 @@ TEST(ResizeOpTest, NhwcResizeOpLinearDownSampleTest_4DBilinear) { 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 // ROCm: results mismatch - // QNN: conflict with layout transformer, need furture investigation test.Run(OpTester::ExpectResult::kExpectSuccess, "", - {kCudaExecutionProvider, kRocmExecutionProvider, kQnnExecutionProvider}); + {kCudaExecutionProvider, kRocmExecutionProvider}); } TEST(ResizeOpTest, NhwcResizeOpLinearDownSampleTest_4DBilinear_uint8) { @@ -287,7 +285,7 @@ TEST(ResizeOpTest, NhwcResizeOpLinearDownSampleTest_4DBilinear_uint8) { 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 // ROCm: results mismatch - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kCudaExecutionProvider, kRocmExecutionProvider, kQnnExecutionProvider}); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kCudaExecutionProvider, kRocmExecutionProvider}); } TEST(ResizeOpTest, NhwcResizeOpLinearDownSampleTest_4DBilinear_int8) { @@ -309,7 +307,7 @@ TEST(ResizeOpTest, NhwcResizeOpLinearDownSampleTest_4DBilinear_int8) { std::vector Y = {0, 0}; test.AddOutput("Y", {N, static_cast(H * scales[1]), static_cast(W * scales[2]), C}, Y); - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kQnnExecutionProvider}); + test.Run(); } // Since NNAPI(TFLite) only using the scale calculate using the input/output size @@ -399,7 +397,9 @@ TEST(ResizeOpTest, ResizeOpLinearDownSampleTest_4DBilinear_align_corners) { std::vector Y = {1.0f, 4.0f}; test.AddOutput("Y", {N, C, static_cast(H * scales[2]), static_cast(W * scales[3])}, Y); - test.Run(); + + // QNN: result mismatch ("NaN" instead of 1.0f on QNN CPU backend) + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kQnnExecutionProvider}); }; run_test(false); @@ -435,7 +435,7 @@ TEST(ResizeOpTest, NhwcResizeOpLinearDownSampleTest_4DBilinear_align_corners_uin 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 // ROCm: results mismatch - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kCudaExecutionProvider, kRocmExecutionProvider, kQnnExecutionProvider}); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kCudaExecutionProvider, kRocmExecutionProvider}); }; run_test(false); @@ -465,7 +465,7 @@ TEST(ResizeOpTest, NhwcResizeOpLinearDownSampleTest_4DBilinear_align_corners_int test.AddOutput("Y", {N, static_cast(H * scales[1]), static_cast(W * scales[2]), C}, Y); // TensorRT: results mismatch - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kQnnExecutionProvider}); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); }; run_test(false); @@ -532,7 +532,7 @@ TEST(ResizeOpTest, NhwcResizeOpLinearDownSampleTest_4DBilinear_pytorch_half_pixe test.AddOutput("Y", {N, sizes[1], sizes[2], C}, Y); // CUDA: result mismatch due to not implementing NHWC support // ROCm: results mismatch - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kCudaExecutionProvider, kRocmExecutionProvider, kQnnExecutionProvider}); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kCudaExecutionProvider, kRocmExecutionProvider}); } TEST(ResizeOpTest, NhwcResizeOpLinearDownSampleTest_4DBilinear_pytorch_half_pixel_int8) { @@ -560,7 +560,7 @@ TEST(ResizeOpTest, NhwcResizeOpLinearDownSampleTest_4DBilinear_pytorch_half_pixe std::vector Y = {0, 2, -9}; test.AddOutput("Y", {N, sizes[1], sizes[2], C}, Y); - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kQnnExecutionProvider}); // TensorRT: results mismatch + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); // TensorRT: results mismatch } TEST(ResizeOpTest, ResizeOpLinearUpSampleTest_4DBilinear_asymmetric) { @@ -641,7 +641,7 @@ TEST(ResizeOpTest, NhwcResizeOpLinearUpSampleTest_4DBilinear_asymmetric_uint8) { Y, false, .0f, 1.0f); // CUDA: result mismatch due to not implementing NHWC support // ROCm: results mismatch - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kCudaExecutionProvider, kRocmExecutionProvider, kQnnExecutionProvider}); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kCudaExecutionProvider, kRocmExecutionProvider}); }; run_test(false); @@ -683,7 +683,7 @@ TEST(ResizeOpTest, NhwcResizeOpLinearUpSampleTest_4DBilinear_asymmetric_int8) { test.AddOutput("Y", {N, static_cast(H * scales[1]), static_cast(W * scales[2]), C}, Y, false, .0f, 1.0f); // TensorRT: results mismatch - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kQnnExecutionProvider}); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); }; run_test(false); @@ -1079,7 +1079,7 @@ TEST(ResizeOpTest, ResizeOpNearestUpSample_Floor_Align_Corners) { 13.0f, 13.0f, 13.0f, 14.0f, 14.0f, 15.0f, 15.0f, 16.0f}; test.AddOutput("Y", {N, C, static_cast(H * scales[2]), static_cast(W * scales[3])}, Y); - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kQnnExecutionProvider}); // QNN: result diff + test.Run(); } TEST(ResizeOpTest, ResizeOpNearest_OneToOneMappingBetweenInputAndOutputDataDims) { @@ -1772,6 +1772,48 @@ TEST(ResizeOpTest, ResizeOpTypeCheck_Ver18) { ResizeOpTypeCheck_Ver_11_13_18(18); } +TEST(ResizeOpTest, ResizeOpHalfPixelSymmetricDownSample_ver19) { + OpTester test("Resize", 19); + test.AddAttribute("mode", "linear"); + test.AddAttribute("coordinate_transformation_mode", "half_pixel_symmetric"); + + constexpr int64_t N = 1, C = 1, H = 1, W = 4; + std::vector X = {1.0f, 2.0f, 3.0f, 4.0f}; + test.AddInput("X", {N, C, H, W}, X); + std::vector roi{}; + test.AddInput("roi", {0}, roi); + std::vector scales{1.0f, 1.0f, 1.0f, 0.6f}; + test.AddInput("scales", {4}, scales); + + std::vector Y = {1.666667f, 3.333333f}; + + test.AddOutput("Y", {N, C, static_cast(H * scales[2]), static_cast(W * scales[3])}, Y); + test.Run(); +} + +TEST(ResizeOpTest, ResizeOpHalfPixelSymmetricUpSample_ver19) { + OpTester test("Resize", 19); + test.AddAttribute("mode", "linear"); + test.AddAttribute("coordinate_transformation_mode", "half_pixel_symmetric"); + + constexpr int64_t N = 1, C = 1, H = 2, W = 2; + std::vector X = {1.0f, 2.0f, 3.0f, 4.0f}; + + test.AddInput("X", {N, C, H, W}, X); + std::vector roi{}; + test.AddInput("roi", {0}, roi); + std::vector scales{1.0f, 1.0f, 2.3f, 2.94f}; + test.AddInput("scales", {4}, scales); + + std::vector Y = {1.0f, 1.159864f, 1.5f, 1.840136f, 2.0f, + 1.565217f, 1.725081f, 2.065217f, 2.405353f, 2.565217f, + 2.434782f, 2.594647f, 2.934783f, 3.274919f, 3.434783f, + 3.0f, 3.159864f, 3.5f, 3.840136f, 4.0f}; + + test.AddOutput("Y", {N, C, static_cast(H * scales[2]), static_cast(W * scales[3])}, Y); + test.Run(); +} + /* * Most of TestCase against Anti-aliasing will have the attribute of "exclude_outside" as 1. * It's as Pillow 's Resize is corresponding to ONNX op with exclude_outside equaling 1. @@ -1845,7 +1887,7 @@ void TestAntialiasing(std::map attributes, test.AddOutput("Y", output_shape, output_data); // TensorRT 8.5 supports operators up to Opset 17. Temporarily exclude TensorRT EP due to accurarcy issue. - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kQnnExecutionProvider}); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); } TEST(ResizeOpTest, Antialias_Bilinear_No_ExcludeOutside) { @@ -2186,6 +2228,5 @@ TEST(ResizeOpTest, Antialias_Use_Extrapolation) { }, {4, 4, 4}, X, {3, 3, 3}, Y); } - } // namespace test } // namespace onnxruntime diff --git a/onnxruntime/test/providers/cpu/tensor/slice_op.test.cc b/onnxruntime/test/providers/cpu/tensor/slice_op.test.cc index bd7be55e929d1..1da9c9df299c9 100644 --- a/onnxruntime/test/providers/cpu/tensor/slice_op.test.cc +++ b/onnxruntime/test/providers/cpu/tensor/slice_op.test.cc @@ -49,6 +49,10 @@ void RunSliceTest(const std::vector& input_dims, SessionOptions so; ASSERT_STATUS_OK(so.config_options.AddConfigEntry(kOrtSessionOptionsConfigStrictShapeTypeInference, "0")); + if (onnx_shape_disagreement) { + excluded_providers.insert(kCoreMLExecutionProvider); + } + if (!v10_only) { OpTester testv9("Slice", 9); testv9.AddAttribute("starts", starts); @@ -257,15 +261,25 @@ TEST(SliceTest, Slice3D) { 332.0f, 333.0f}); } -TEST(SliceTest, Slice1D_Int) { - RunSliceTest({6}, - {0L, 1L, 2L, 3L, 4L, 5L}, - {2}, - {4}, - {0}, - {}, - {2}, - {2L, 3L}); +template +static void TestSlice1DIntData() { + static_assert(std::is_integral_v); + RunSliceTest({6}, + {0, 1, 2, 3, 4, 5}, + {2}, + {4}, + {0}, + {}, + {2}, + {2, 3}); +} + +TEST(SliceTest, Slice1D_Int32) { + TestSlice1DIntData(); +} + +TEST(SliceTest, Slice1D_Int64) { + TestSlice1DIntData(); } TEST(SliceTest, Slice1D_String) { @@ -548,7 +562,7 @@ TEST(SliceTest, Slice2D_ReverseAllAxes) { RunSliceTest({2, 2}, {1.0f, 2.0f, 3.0f, 4.0f}, {-1, -1}, - {std::numeric_limits::max(), std::numeric_limits::max()}, + {std::numeric_limits::min(), std::numeric_limits::min()}, {0, 1}, {-1, -1}, {2, 2}, @@ -565,7 +579,7 @@ TEST(SliceTest, Slice2D_ReverseSubsetOfAxes_1) { RunSliceTest({2, 2}, {1.0f, 2.0f, 3.0f, 4.0f}, {-1}, - {std::numeric_limits::max()}, + {std::numeric_limits::min()}, {1}, // axis = 1 only {-1}, {2, 2}, @@ -582,7 +596,7 @@ TEST(SliceTest, Slice2D_ReverseSubsetOfAxes_2) { RunSliceTest({2, 2}, {1.0f, 2.0f, 3.0f, 4.0f}, {-1}, - {std::numeric_limits::max()}, // end of dimension + {std::numeric_limits::min()}, // end of dimension {0}, // axis = 0 only {-1}, {2, 2}, @@ -636,7 +650,7 @@ TEST(SliceTest, Slice2D_ReverseSubsetOfNegAxes_1) { RunSliceTest({2, 2}, {1.0f, 2.0f, 3.0f, 4.0f}, {-1}, - {std::numeric_limits::max()}, + {std::numeric_limits::min()}, {-1}, // axis = -1 only {-1}, {2, 2}, 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 2631f460f208e..63b92cfc187bd 100644 --- a/onnxruntime/test/providers/cpu/tensor/space_depth_ops_test.cc +++ b/onnxruntime/test/providers/cpu/tensor/space_depth_ops_test.cc @@ -35,7 +35,10 @@ TEST(TensorOpTest, SpaceToDepthTest_1) { 1.1f, 1.3f, 3.1f, 3.3f}; test.AddOutput("output", {N, C * blocksize * blocksize, H / blocksize, W / blocksize}, result); - test.Run(); + + // TODO: Test is flaky on QNN EP (CPU backend). Reneable when the QnnCPUBackendTests.DISABLED_SpaceToDepth_Flaky test + // is fixed. + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kQnnExecutionProvider}); } TEST(TensorOpTest, SpaceToDepthTest_1_double) { @@ -99,7 +102,10 @@ TEST(TensorOpTest, SpaceToDepthTest_2) { 98., 101., 66., 69., 84., 87., 102., 105., 67., 70., 85., 88., 103., 106., 68., 71., 86., 89., 104., 107.}; test.AddOutput("output", {2, 27, 1, 2}, result); - test.Run(); + + // TODO: Test is flaky on QNN EP (CPU backend). Reneable when the QnnCPUBackendTests.DISABLED_SpaceToDepth_Flaky2 + // test is fixed. + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kQnnExecutionProvider}); } TEST(TensorOpTest, DepthToSpaceTest_1) { diff --git a/onnxruntime/test/providers/cpu/tensor/split_op_test.cc b/onnxruntime/test/providers/cpu/tensor/split_op_test.cc index a1dd470a2d452..7712a0a5bf724 100644 --- a/onnxruntime/test/providers/cpu/tensor/split_op_test.cc +++ b/onnxruntime/test/providers/cpu/tensor/split_op_test.cc @@ -720,7 +720,13 @@ TEST(SplitOperatorTest, Split18_InvalidNumOutputs) { 3.f, 4.f}}); int64_t num_outputs = 0; - RunTest(axis, {}, input, outputs, {kTensorrtExecutionProvider, kQnnExecutionProvider}, true, true, num_outputs, false, + const std::unordered_set excluded_providers = + { + kTensorrtExecutionProvider, + kQnnExecutionProvider, + kDmlExecutionProvider, // Error message differs from expected CPU EP error message. + }; + RunTest(axis, {}, input, outputs, excluded_providers, true, true, num_outputs, false, "Attribute `num_outputs` value cannot be lower than 1"); outputs.clear(); @@ -730,7 +736,7 @@ TEST(SplitOperatorTest, Split18_InvalidNumOutputs) { {0.f, 0.f}}); num_outputs = 3; - RunTest(axis, {}, input, outputs, {kTensorrtExecutionProvider, kQnnExecutionProvider}, true, true, num_outputs, false, + RunTest(axis, {}, input, outputs, excluded_providers, true, true, num_outputs, false, "Invalid num_outputs value of 3. Size of dimension being split is 2"); } diff --git a/onnxruntime/test/providers/cpu/tensor/tensor_op_test.cc b/onnxruntime/test/providers/cpu/tensor/tensor_op_test.cc index 11c4d3e1991ae..df1f0989a9607 100644 --- a/onnxruntime/test/providers/cpu/tensor/tensor_op_test.cc +++ b/onnxruntime/test/providers/cpu/tensor/tensor_op_test.cc @@ -162,6 +162,28 @@ TEST(TensorOpTest, Reshape_UnknownDimWithAllowZero) { test.Run(); } +TEST(TensorOpTest, ReshapeSixDimNewShape) { + // CoreML has a 5D limit for the new shape. With the CoreML EP enabled, this should fall back to the CPU EP. + OpTester test("Reshape", 14); + test.AddInput("data", {8, 8, 8}, std::vector(8 * 8 * 8, 1.0f)); + + const auto target_shape = std::vector{2, 4, 4, 2, 8, 1}; + test.AddInput("shape", {static_cast(target_shape.size())}, target_shape, true); + test.AddOutput("reshaped", target_shape, std::vector(8 * 8 * 8, 1.0f)); + test.Run(); +} + +TEST(TensorOpTest, ReshapeSixDimInputShape) { + // CoreML has a 5D limit for the new shape. With the CoreML EP enabled, this should fall back to the CPU EP. + OpTester test("Reshape", 14); + test.AddInput("data", {2, 4, 4, 2, 8, 1}, std::vector(8 * 8 * 8, 1.0f)); + + const auto target_shape = std::vector{8, 8, 8}; + test.AddInput("shape", {static_cast(target_shape.size())}, target_shape, true); + test.AddOutput("reshaped", target_shape, std::vector(8 * 8 * 8, 1.0f)); + test.Run(); +} + #if defined(USE_DNNL) TEST(TensorOpTest, Reshape_bfloat16) { #ifdef USE_DNNL @@ -426,107 +448,5 @@ TEST(TensorOpTest, ShapeTest3D) { test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); } -void MeanVarianceNormalizationFunctionDefaultPerChannel() { - constexpr int64_t N = 2, C = 2, H = 2, W = 3; - - std::vector N1C1 = {3.0f, -3.0f, -1.0f, - 1.0f, 2.0f, -1.0f}; - std::vector N1C2 = {-2.0f, -2.0f, -2.0f, - 4.0f, 1.0f, 4.0f}; - std::vector N2C1 = { - 0.0f, - -2.0f, - -2.0f, - -4.0f, - 5.0f, - 7.0f, - }; - std::vector N2C2 = { - 5.0f, - -5.0f, - -5.0f, - 3.0f, - 4.0f, - 4.0f, - }; - - std::vector X; - X.reserve(N * C * H * W); - X.insert(X.end(), N1C1.begin(), N1C1.end()); - X.insert(X.end(), N1C2.begin(), N1C2.end()); - X.insert(X.end(), N2C1.begin(), N2C1.end()); - X.insert(X.end(), N2C2.begin(), N2C2.end()); - - std::vector C1; - C1.reserve(N * H * W); - C1.insert(C1.end(), N1C1.begin(), N1C1.end()); - C1.insert(C1.end(), N2C1.begin(), N2C1.end()); - auto C1_meam_stdev = MeanStdev(C1); - - std::vector C2; - C2.reserve(N * H * W); - C2.insert(C2.end(), N1C2.begin(), N1C2.end()); - C2.insert(C2.end(), N2C2.begin(), N2C2.end()); - auto C2_meam_stdev = MeanStdev(C2); - - std::vector N1C1_result(N1C1), N1C2_result(N1C2), - N2C1_result(N2C1), N2C2_result(N2C2); - Normalize(N1C1_result, C1_meam_stdev, 1); - Normalize(N2C1_result, C1_meam_stdev, 1); - Normalize(N1C2_result, C2_meam_stdev, 1); - Normalize(N2C2_result, C2_meam_stdev, 1); - - std::vector result; - result.reserve(N * C * H * W); - result.insert(result.end(), N1C1_result.begin(), N1C1_result.end()); - result.insert(result.end(), N1C2_result.begin(), N1C2_result.end()); - result.insert(result.end(), N2C1_result.begin(), N2C1_result.end()); - result.insert(result.end(), N2C2_result.begin(), N2C2_result.end()); - - OpTester test("MeanVarianceNormalization", 9); - test.AddInput("input", {N, C, H, W}, X); - test.AddOutput("output", {N, C, H, W}, result); -#if defined(OPENVINO_CONFIG_MYRIAD) - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); // OpenVINO: Unsupported combination of indices in layer "output" -#else - test.Run(); -#endif -} - -void MeanVarianceNormalizationFunctionAcrossChannels(std::vector axes) { - constexpr int64_t N = 2, C = 2, H = 2, W = 3; - - std::vector X = {3.0f, -3.0f, -1.0f, - 1.0f, 2.0f, -1.0f, - -2.0f, -2.0f, -2.0f, - 4.0f, 1.0f, 4.0f, - 0.0f, -2.0f, -2.0f, - -4.0f, 5.0f, 7.0f, - 5.0f, -5.0f, -5.0f, - 3.0f, 4.0f, 4.0f}; - auto mean_stdev = MeanStdev(X); - - std::vector result(X); - Normalize(result, mean_stdev, 1); - - OpTester test("MeanVarianceNormalization", 9); - test.AddAttribute("axes", axes); - test.AddInput("input", {N, C, H, W}, X); - test.AddOutput("output", {N, C, H, W}, result); -#if defined(OPENVINO_CONFIG_MYRIAD) - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kOpenVINOExecutionProvider}); // OpenVINO: Unsupported combination of indices in layer "output" -#else - test.Run(); -#endif -} - -TEST(TensorOpTest, MeanVarianceNormalizationCPUTest) { - // axes: {0, 1, 2, 3} for across_channels - MeanVarianceNormalizationFunctionAcrossChannels({0, 1, 2, 3}); - - // Default (axes: {0, 2, 3}) for non across_channels - MeanVarianceNormalizationFunctionDefaultPerChannel(); -} - } // namespace test } // namespace onnxruntime diff --git a/onnxruntime/test/providers/cpu/tensor/transpose_test.cc b/onnxruntime/test/providers/cpu/tensor/transpose_test.cc index f07d4f88748a7..c334e0c5ddcb6 100644 --- a/onnxruntime/test/providers/cpu/tensor/transpose_test.cc +++ b/onnxruntime/test/providers/cpu/tensor/transpose_test.cc @@ -24,33 +24,39 @@ TEST(TransposeOpTest, IsTransposeReshapeTest) { ASSERT_FALSE(IsTransposeReshape(perm, input_dims)); } +// Negative test, making sure it fails +TEST(TransposeOpTest, PermRankDoesNotMatchTensorRank) { + const std::vector input_vals(1 * 2 * 3 * 4, 0.f); + const std::vector perm{0, 2, 1}; + + OpTester test("Transpose"); + test.AddAttribute("perm", perm); + test.AddInput("X", {1, 2, 3, 4}, input_vals); + // Output is not very relevant + test.AddOutput("Y", {1, 3, 2, 4}, input_vals); + // This failure comes from shape inference, because in this case it knows the input dims. + // But in the real world, the model can supply different input dims at runtime. + test.Run(OpTester::ExpectResult::kExpectFailure, + "Node:node1 Output:Y [ShapeInferenceError] Mismatch between number of source and target dimensions. Source=3 Target=4"); +} + // Some of the tests can't run on TensorrtExecutionProvider because of errors. // Those tests will fallback to other EPs. template -void TransposeTest(std::vector& input_shape, - std::vector& input_vals, - std::vector* p_perm, - std::vector expected_shape, - std::initializer_list& expected_vals, - bool is_tensorrt_supported = true, - bool is_openvino_supported = true) { +void TransposeTest(const std::vector& input_shape, + const std::vector& input_vals, + const std::vector* p_perm, + const std::vector& expected_shape, + const std::vector& expected_vals, + const std::unordered_set& excluded_provider_types = {}) { OpTester test("Transpose"); if (nullptr != p_perm) test.AddAttribute("perm", *p_perm); test.AddInput("X", input_shape, input_vals); test.AddOutput("Y", expected_shape, expected_vals); - // Disable TensorRT on unsupported tests - std::unordered_set excluded_providers; - if (!is_tensorrt_supported) { - excluded_providers.insert(kTensorrtExecutionProvider); - } - if (!is_openvino_supported) { - excluded_providers.insert(kOpenVINOExecutionProvider); - } - - test.Run(OpTester::ExpectResult::kExpectSuccess, "", excluded_providers); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", excluded_provider_types); } // Test 2 dimensional transpose, with no permutation attribute specified @@ -61,12 +67,13 @@ TEST(TransposeOpTest, TwoDimNoAttr) { 4.0f, 5.0f, 6.0f}; std::vector expected_shape({3, 2}); - auto expected_vals = { + std::vector expected_vals = { 1.0f, 4.0f, 2.0f, 5.0f, 3.0f, 6.0f}; - TransposeTest(input_shape, input_vals, nullptr, expected_shape, expected_vals, false); // TensorRT: SegFault error + TransposeTest(input_shape, input_vals, nullptr, expected_shape, expected_vals, + {kTensorrtExecutionProvider}); // TensorRT: SegFault error } TEST(TransposeOpTest, TwoDimNoAttrStr) { @@ -76,7 +83,7 @@ TEST(TransposeOpTest, TwoDimNoAttrStr) { "4", "5", "6"}; std::vector expected_shape({3, 2}); - std::initializer_list expected_vals = { + std::vector expected_vals = { "1", "4", "2", "5", "3", "6"}; @@ -92,9 +99,9 @@ TEST(TransposeOpTest, TwoDim) { std::vector perm = {1, 0}; std::vector expected_shape({3, 2}); - auto expected_vals = {1.0f, 4.0f, - 2.0f, 5.0f, - 3.0f, 6.0f}; + std::vector expected_vals = {1.0f, 4.0f, + 2.0f, 5.0f, + 3.0f, 6.0f}; TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals); } @@ -106,9 +113,9 @@ TEST(TransposeOpTest, TwoDim_double) { std::vector perm = {1, 0}; std::vector expected_shape({3, 2}); - std::initializer_list expected_vals = {1.0, 4.0, - 2.0, 5.0, - 3.0, 6.0}; + std::vector expected_vals = {1.0, 4.0, + 2.0, 5.0, + 3.0, 6.0}; TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals); } @@ -120,9 +127,9 @@ TEST(TransposeOpTest, TwoDim_int32) { std::vector perm = {1, 0}; std::vector expected_shape({3, 2}); - std::initializer_list expected_vals = {1, 4, - 2, 5, - 3, 6}; + std::vector expected_vals = {1, 4, + 2, 5, + 3, 6}; TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals); } @@ -135,28 +142,28 @@ TEST(TransposeOpTest, TwoDim_int16) { std::vector perm = {1, 0}; std::vector expected_shape({3, 2}); - std::initializer_list expected_vals = { + std::vector expected_vals = { 1, 4, 2, 5, 3, 6}; - TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals, true, false); + TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals, {kOpenVINOExecutionProvider}); } TEST(TransposeOpTest, TwoDim_mlfloat16) { std::vector input_shape({2, 3}); std::vector input_vals; for (uint16_t i = 0; i < 6; ++i) - input_vals.push_back(MLFloat16(i)); + input_vals.push_back(MLFloat16::FromBits(static_cast(i))); std::vector perm = {1, 0}; std::vector expected_shape({3, 2}); - std::initializer_list expected_vals = - {MLFloat16{static_cast(1)}, MLFloat16{static_cast(4)}, - MLFloat16{static_cast(2)}, MLFloat16{static_cast(5)}, - MLFloat16{static_cast(3)}, MLFloat16{static_cast(6)}}; + std::vector expected_vals = + {MLFloat16::FromBits(static_cast(1)), MLFloat16::FromBits(static_cast(4)), + MLFloat16::FromBits(static_cast(2)), MLFloat16::FromBits(static_cast(5)), + MLFloat16::FromBits(static_cast(3)), MLFloat16::FromBits(static_cast(6))}; - TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals, false); + TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals, {kTensorrtExecutionProvider}); } #if defined(USE_DNNL) @@ -218,7 +225,7 @@ TEST(TransposeOpTest, Transpose021_bfloat16) { std::vector perm = {0, 2, 1}; std::vector expected_shape({4, 3, 2}); - auto expected_vals = { + std::vector expected_vals = { 1.0f, 4.0f, 2.0f, 5.0f, 3.0f, 6.0f, @@ -253,11 +260,11 @@ TEST(TransposeOpTest, TwoDim_int8) { std::vector perm = {1, 0}; std::vector expected_shape({3, 2}); - std::initializer_list expected_vals = {1, 4, - 2, 5, - 3, 6}; + std::vector expected_vals = {1, 4, + 2, 5, + 3, 6}; - TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals, false); + TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals, {kTensorrtExecutionProvider}); } TEST(TransposeOpTest, TwoDimStr) { @@ -268,7 +275,7 @@ TEST(TransposeOpTest, TwoDimStr) { std::vector perm = {1, 0}; std::vector expected_shape({3, 2}); - std::initializer_list expected_vals = { + std::vector expected_vals = { "1", "4", "2", "5", "3", "6"}; @@ -294,7 +301,7 @@ TEST(TransposeOpTest, Transpose021) { std::vector perm = {0, 2, 1}; std::vector expected_shape({4, 3, 2}); - auto expected_vals = { + std::vector expected_vals = { 1.0f, 4.0f, 2.0f, 5.0f, 3.0f, 6.0f, @@ -311,7 +318,8 @@ TEST(TransposeOpTest, Transpose021) { 2.3f, 5.3f, 3.3f, 6.3f}; - TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals, false); // TensorRT: illegal error + TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals, + {kTensorrtExecutionProvider}); // TensorRT: illegal error } TEST(TransposeOpTest, Transpose120) { @@ -331,7 +339,7 @@ TEST(TransposeOpTest, Transpose120) { std::vector perm = {1, 2, 0}; std::vector expected_shape({2, 3, 4}); - auto expected_vals = { + std::vector expected_vals = { 1.0f, 1.1f, 1.2f, 1.3f, 2.0f, 2.1f, 2.2f, 2.3f, 3.0f, 3.1f, 3.2f, 3.3f, @@ -340,7 +348,8 @@ TEST(TransposeOpTest, Transpose120) { 5.0f, 5.1f, 5.2f, 5.3f, 6.0f, 6.1f, 6.2f, 6.3f}; - TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals, false); // TensorRT: illegal error + TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals, + {kTensorrtExecutionProvider}); // TensorRT: illegal error } // test when the suffix size is > 1 (last dimension is not moved) @@ -361,7 +370,7 @@ TEST(TransposeOpTest, Transpose102) { std::vector perm = {1, 0, 2}; std::vector expected_shape({2, 4, 3}); - auto expected_vals = { + std::vector expected_vals = { 1.0f, 2.0f, 3.0f, 1.1f, 2.1f, 3.1f, 1.2f, 2.2f, 3.2f, @@ -372,7 +381,8 @@ TEST(TransposeOpTest, Transpose102) { 4.2f, 5.2f, 6.2f, 4.3f, 5.3f, 6.3f}; - TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals, false); // TensorRT: illegal error + TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals, + {kTensorrtExecutionProvider}); // TensorRT: illegal error } TEST(TransposeOpTest, TransposeReshape) { @@ -392,7 +402,7 @@ TEST(TransposeOpTest, TransposeReshape) { std::vector perm = {1, 3, 2, 4, 0}; std::vector expected_shape({4, 1, 2, 3, 1}); - auto expected_vals = { + std::vector expected_vals = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, @@ -405,7 +415,8 @@ TEST(TransposeOpTest, TransposeReshape) { 1.3f, 2.3f, 3.3f, 4.3f, 5.3f, 6.3f}; - TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals, false); // TensorRT: illegal error + TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals, + {kTensorrtExecutionProvider}); // TensorRT: illegal error } TEST(TransposeOpTest, ThreeDimStr) { @@ -425,7 +436,7 @@ TEST(TransposeOpTest, ThreeDimStr) { std::vector perm = {0, 2, 1}; std::vector expected_shape({4, 3, 2}); - std::initializer_list expected_vals = { + std::vector expected_vals = { "1", "4", "2", "5", "3", "6", @@ -445,6 +456,31 @@ TEST(TransposeOpTest, ThreeDimStr) { TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals); } +TEST(TransposeOpTest, SixDim) { + // CoreML has a 5D limit. With the CoreML EP enabled, this should fall back to the CPU EP. + const auto input_shape = std::vector{2, 2, 2, 2, 2, 2}; + const auto input_vals = []() { + std::vector v(64); + std::iota(v.begin(), v.end(), 0.0f); + return v; + }(); + + const auto perm = std::vector{1, 0, 2, 3, 4, 5}; + + const auto expected_shape = input_shape; // all dimension values are the same + const auto expected_vals = []() { + std::vector v(64); + std::iota(v.begin() + 0, v.begin() + 16, 0.f); + std::iota(v.begin() + 16, v.begin() + 32, 32.0f); + std::iota(v.begin() + 32, v.begin() + 48, 16.0f); + std::iota(v.begin() + 48, v.begin() + 64, 48.0f); + return v; + }(); + + TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals, + {kQnnExecutionProvider}); // Error: Failed to finalize QNN graph. +} + template static void NumericNCHW2NHWC() { std::vector input_shape({1, 3, 2, 2}); @@ -455,13 +491,14 @@ static void NumericNCHW2NHWC() { std::vector perm = {0, 2, 3, 1}; std::vector expected_shape({1, 2, 2, 3}); - std::initializer_list expected_vals = { + std::vector expected_vals = { 1, 5, 9, 2, 6, 10, 3, 7, 11, 4, 8, 12}; - TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals, false, false); + TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals, + {kTensorrtExecutionProvider, kOpenVINOExecutionProvider}); } TEST(TransposeOpTest, NCHW2NHWC) { NumericNCHW2NHWC(); @@ -479,13 +516,13 @@ TEST(TransposeOpTest, NCHW2NHWCStr) { std::vector perm = {0, 2, 3, 1}; std::vector expected_shape({1, 2, 2, 3}); - std::initializer_list expected_vals = { + std::vector expected_vals = { "1", "5", "9", "2", "6", "10", "3", "7", "11", "4", "8", "12"}; - TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals, false); + TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals, {kTensorrtExecutionProvider}); } template @@ -506,7 +543,7 @@ static void NumericNHWC2NCHW() { std::vector perm = {0, 3, 1, 2}; std::vector expected_shape({2, 2, 2, 2}); - std::initializer_list expected_vals = { + std::vector expected_vals = { 1, 3, 5, 7, @@ -519,7 +556,8 @@ static void NumericNHWC2NCHW() { 10, 12, 14, 16}; - TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals, false, false); + TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals, + {kTensorrtExecutionProvider, kOpenVINOExecutionProvider}); } TEST(TransposeOpTest, NHWC2NCHW) { @@ -539,12 +577,12 @@ TEST(TransposeOpTest, NHWC2NCHW_String) { std::vector perm = {0, 3, 1, 2}; std::vector expected_shape({1, 3, 2, 2}); - std::initializer_list expected_vals = { + std::vector expected_vals = { "1", "4", "7", "10", "2", "5", "8", "11", "3", "6", "9", "12"}; - TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals, false); + TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals, {kTensorrtExecutionProvider}); } // test to cover memcpy from single axis moving inwards path @@ -565,7 +603,7 @@ TEST(TransposeOpTest, SingleAxisMovingInwardsBlockCopy) { std::vector perm = {1, 2, 0, 3}; std::vector expected_shape({2, 2, 2, 2}); - std::initializer_list expected_vals = { + std::vector expected_vals = { 1, 2, 9, 10, @@ -578,7 +616,7 @@ TEST(TransposeOpTest, SingleAxisMovingInwardsBlockCopy) { 7, 8, 15, 16}; - TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals, false); + TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals, {kTensorrtExecutionProvider}); } TEST(TransposeOpTest, NDim) { @@ -589,17 +627,17 @@ TEST(TransposeOpTest, NDim) { 13.0f, 14.0f, 15.0f, 16.0f}; std::vector perm = {1, 0, 2, 3}; - auto expected_vals = {1.0f, 2.0f, 3.0f, 4.0f, - 9.0f, 10.0f, 11.0f, 12.0f, - 5.0f, 6.0f, 7.0f, 8.0f, - 13.0f, 14.0f, 15.0f, 16.0f}; + std::vector expected_vals = {1.0f, 2.0f, 3.0f, 4.0f, + 9.0f, 10.0f, 11.0f, 12.0f, + 5.0f, 6.0f, 7.0f, 8.0f, + 13.0f, 14.0f, 15.0f, 16.0f}; TransposeTest(input_shape, input_vals, &perm, input_shape, expected_vals); perm = {1, 0, 3, 2}; - auto expected_vals2 = {1.0f, 3.0f, 2.0f, 4.0f, - 9.0f, 11.0f, 10.0f, 12.0f, - 5.0f, 7.0f, 6.0f, 8.0f, - 13.0f, 15.0f, 14.0f, 16.0f}; + std::vector expected_vals2 = {1.0f, 3.0f, 2.0f, 4.0f, + 9.0f, 11.0f, 10.0f, 12.0f, + 5.0f, 7.0f, 6.0f, 8.0f, + 13.0f, 15.0f, 14.0f, 16.0f}; TransposeTest(input_shape, input_vals, &perm, input_shape, expected_vals2); } @@ -611,11 +649,11 @@ TEST(TransposeOpTest, DoTransposeImpl) { } std::vector perm = {2, 1, 0, 3}; std::vector expected_shape({1, 2, 5, 3}); - auto expected_vals = {0.0f, 1.0f, 2.0f, 6.0f, 7.0f, 8.0f, - 12.0f, 13.0f, 14.0f, 18.0f, 19.0f, 20.0f, - 24.0f, 25.0f, 26.0f, 3.0f, 4.0f, 5.0f, - 9.0f, 10.0f, 11.0f, 15.0f, 16.0f, 17.0f, - 21.0f, 22.0f, 23.0f, 27.0f, 28.0f, 29.0f}; + std::vector expected_vals = {0.0f, 1.0f, 2.0f, 6.0f, 7.0f, 8.0f, + 12.0f, 13.0f, 14.0f, 18.0f, 19.0f, 20.0f, + 24.0f, 25.0f, 26.0f, 3.0f, 4.0f, 5.0f, + 9.0f, 10.0f, 11.0f, 15.0f, 16.0f, 17.0f, + 21.0f, 22.0f, 23.0f, 27.0f, 28.0f, 29.0f}; TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals); } @@ -627,11 +665,11 @@ TEST(TransposeOpTest, DoTransposeImplString) { } std::vector perm = {2, 1, 0, 3}; std::vector expected_shape({1, 2, 5, 3}); - std::initializer_list expected_vals = {"n0", "n1", "n2", "n6", "n7", "n8", - "n12", "n13", "n14", "n18", "n19", "n20", - "n24", "n25", "n26", "n3", "n4", "n5", - "n9", "n10", "n11", "n15", "n16", "n17", - "n21", "n22", "n23", "n27", "n28", "n29"}; + std::vector expected_vals = {"n0", "n1", "n2", "n6", "n7", "n8", + "n12", "n13", "n14", "n18", "n19", "n20", + "n24", "n25", "n26", "n3", "n4", "n5", + "n9", "n10", "n11", "n15", "n16", "n17", + "n21", "n22", "n23", "n27", "n28", "n29"}; TransposeTest(input_shape, input_vals, &perm, expected_shape, expected_vals); } @@ -644,10 +682,10 @@ TEST(TransposeOpTest, DoTransposeEltWise) { 13.0f, 14.0f, 15.0f, 16.0f}; std::vector perm = {1, 0, 3, 2}; - auto expected_vals2 = {1.0f, 3.0f, 2.0f, 4.0f, - 9.0f, 11.0f, 10.0f, 12.0f, - 5.0f, 7.0f, 6.0f, 8.0f, - 13.0f, 15.0f, 14.0f, 16.0f}; + std::vector expected_vals2 = {1.0f, 3.0f, 2.0f, 4.0f, + 9.0f, 11.0f, 10.0f, 12.0f, + 5.0f, 7.0f, 6.0f, 8.0f, + 13.0f, 15.0f, 14.0f, 16.0f}; TransposeTest(input_shape, input_vals, &perm, input_shape, expected_vals2); // Specific test which tests that function DoTransposeEltWise does not @@ -755,7 +793,33 @@ TEST(TransposeOpTest, Transpose3DImpl) { } } -#endif +static void TestTransposeMLFloat16( + const std::vector& perm, + const std::vector& x_dims, + const std::vector& y_dims, + double error_tolerance = 1e-4) { + CompareOpTester test{"Transpose"}; + + RandomValueGenerator random{}; + const auto X_data = random.Uniform(x_dims, -10.0, 10.0); + std::vector X_data_f16 = FloatsToMLFloat16s(X_data); + const auto Y_data = FillZeros(y_dims); + std::vector Y_data_f16 = FloatsToMLFloat16s(Y_data); + + test.AddAttribute("perm", perm); + test.AddInput("X", x_dims, X_data_f16); + test.AddOutput("Y", y_dims, Y_data_f16); + + test.CompareWithCPU(kGpuExecutionProvider, error_tolerance); +} + +TEST(TransposeOpTest, TransposeBigMLFloat16) { // Exercises CanUse_cublasTransposeHelper_MLFloat16 (cuda 65535 grid dimension limit) + const std::vector X_dims{1, 1449, 1449, 3}; + const std::vector perm{0, 3, 1, 2}; + const std::vector Y_dims{1, 1449, 1449, 3}; + TestTransposeMLFloat16(perm, X_dims, Y_dims); +} +#endif // defined(USE_CUDA) || defined(USE_ROCM) } // namespace test } // namespace onnxruntime diff --git a/onnxruntime/test/providers/cpu/tensor/unique_op_test.cc b/onnxruntime/test/providers/cpu/tensor/unique_op_test.cc index c539e59b5d20e..19e5c5c26aa2b 100644 --- a/onnxruntime/test/providers/cpu/tensor/unique_op_test.cc +++ b/onnxruntime/test/providers/cpu/tensor/unique_op_test.cc @@ -58,6 +58,25 @@ TEST(Unique, Flatten_Unsorted) { inverse_indices_dims, inverse_indices, counts_dims, counts); } +TEST(Unique, Flatten_Unsorted_Double) { + const std::vector X_dims{2, 2}; + const std::vector X{3.14, -1.3, 3.14, -1.3}; + const int64_t* axis = nullptr; + bool sorted = false; + const std::vector Y_dims{2}; + const std::vector Y{3.14, -1.3}; + + const std::vector indices_dims{2}; + const std::vector indices{0, 1}; + const std::vector inverse_indices_dims{4}; + const std::vector inverse_indices{0, 1, 0, 1}; + const std::vector counts_dims{2}; + const std::vector counts{2, 2}; + + RunUniqueTest(X_dims, X, axis, sorted, Y_dims, Y, indices_dims, indices, + inverse_indices_dims, inverse_indices, counts_dims, counts); +} + // TEMPORARY. The ONNX test expected data for Y for unique_not_sorted_without_axis doesn't match the comments in that // test and is in sorted order. This unit test validates we have the correct behavior, pending fixing the onnx test // data. diff --git a/onnxruntime/test/providers/cuda/cuda_provider_test.cc b/onnxruntime/test/providers/cuda/cuda_provider_test.cc index 3b6f7a4b3b011..e57cdd2350fab 100644 --- a/onnxruntime/test/providers/cuda/cuda_provider_test.cc +++ b/onnxruntime/test/providers/cuda/cuda_provider_test.cc @@ -1,24 +1,21 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#ifndef NDEBUG #include "gtest/gtest.h" #include "core/common/status.h" #include "core/providers/cuda/cuda_provider_factory.h" #include namespace onnxruntime { -ProviderInfo_CUDA& GetProviderInfo_CUDA(); +ProviderInfo_CUDA& GetProviderInfo_CUDA_Test(); namespace test { namespace cuda { -TEST(CUDAEPTEST, ALL) { - onnxruntime::ProviderInfo_CUDA& ep = onnxruntime::GetProviderInfo_CUDA(); - ASSERT_TRUE(ep.TestAll()); +TEST(CUDA_EP_Unittest, All) { + onnxruntime::ProviderInfo_CUDA& ep = onnxruntime::GetProviderInfo_CUDA_Test(); + ep.TestAll(); } } // namespace cuda } // namespace test } // namespace onnxruntime - -#endif diff --git a/onnxruntime/test/framework/cuda/allocator_cuda_test.cc b/onnxruntime/test/providers/cuda/test_cases/allocator_cuda_test.cc similarity index 88% rename from onnxruntime/test/framework/cuda/allocator_cuda_test.cc rename to onnxruntime/test/providers/cuda/test_cases/allocator_cuda_test.cc index d20e094e18519..27a0696acb599 100644 --- a/onnxruntime/test/framework/cuda/allocator_cuda_test.cc +++ b/onnxruntime/test/providers/cuda/test_cases/allocator_cuda_test.cc @@ -1,17 +1,16 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#if 0 // TODO: Can't call these directly from external code as Cuda is now a shared library - -#include "core/framework/allocatormgr.h" -#include "test/framework/test_utils.h" +#include "core/framework/allocator_utils.h" #include "gtest/gtest.h" #include "cuda_runtime.h" +#include "core/framework/allocator.h" #include "core/providers/cuda/cuda_allocator.h" #include "core/providers/cuda/cuda_common.h" namespace onnxruntime { namespace test { + TEST(AllocatorTest, CUDAAllocatorTest) { OrtDevice::DeviceId cuda_device_id = 0; @@ -30,12 +29,12 @@ TEST(AllocatorTest, CUDAAllocatorTest) { EXPECT_EQ(cuda_arena->Info().mem_type, OrtMemTypeDefault); EXPECT_EQ(cuda_arena->Info().alloc_type, OrtArenaAllocator); - //test cuda allocation + // test cuda allocation auto cuda_addr = cuda_arena->Alloc(size); EXPECT_TRUE(cuda_addr); AllocatorCreationInfo pinned_memory_info( - [](int) { return std::make_unique(static_cast(0), CUDA_PINNED); }); + [](int) { return std::make_unique(CUDA_PINNED); }); auto pinned_allocator = CreateAllocator(pinned_memory_info); @@ -44,11 +43,13 @@ TEST(AllocatorTest, CUDAAllocatorTest) { EXPECT_EQ(pinned_allocator->Info().mem_type, OrtMemTypeCPUOutput); EXPECT_EQ(pinned_allocator->Info().alloc_type, OrtArenaAllocator); - //test pinned allocation + // test pinned allocation auto pinned_addr = pinned_allocator->Alloc(size); EXPECT_TRUE(pinned_addr); - const auto& cpu_arena = TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault); + AllocatorCreationInfo cpu_memory_info( + [](int) { return std::make_unique(); }, true); + const auto& cpu_arena = CreateAllocator(cpu_memory_info); EXPECT_STREQ(cpu_arena->Info().name, CPU); EXPECT_EQ(cpu_arena->Info().id, 0); EXPECT_EQ(cpu_arena->Info().mem_type, OrtMemTypeDefault); @@ -60,7 +61,7 @@ TEST(AllocatorTest, CUDAAllocatorTest) { EXPECT_TRUE(cpu_addr_b); memset(cpu_addr_a, -1, 1024); - //test host-device memory copy + // test host-device memory copy cudaMemcpy(cuda_addr, cpu_addr_a, size, cudaMemcpyHostToDevice); cudaMemcpy(cpu_addr_b, cuda_addr, size, cudaMemcpyDeviceToHost); EXPECT_EQ(*((int*)cpu_addr_b), -1); @@ -114,5 +115,3 @@ TEST(AllocatorTest, CUDAAllocatorFallbackTest) { } } // namespace test } // namespace onnxruntime - -#endif diff --git a/onnxruntime/core/providers/cuda/test/beam_search_topk.cc b/onnxruntime/test/providers/cuda/test_cases/beam_search_topk.cc similarity index 95% rename from onnxruntime/core/providers/cuda/test/beam_search_topk.cc rename to onnxruntime/test/providers/cuda/test_cases/beam_search_topk.cc index 443dd63f5852b..9fecec9f7e8bb 100644 --- a/onnxruntime/core/providers/cuda/test/beam_search_topk.cc +++ b/onnxruntime/test/providers/cuda/test_cases/beam_search_topk.cc @@ -1,5 +1,3 @@ -#ifndef NDEBUG - #include "contrib_ops/cuda/transformers/beam_search_topk.h" #include "core/providers/cuda/shared_inc/cuda_call.h" @@ -9,6 +7,7 @@ #include #include +#include "gtest/gtest.h" namespace onnxruntime { namespace cuda { @@ -69,7 +68,7 @@ void ComputeTopKReference(const std::vector& values, } } -bool TestBeamSearchTopK() { +TEST(TestBeamSearch, TopK) { int32_t batch_size = 4; int32_t beam_size = 4; int32_t vocab_size = 50257; @@ -120,19 +119,14 @@ bool TestBeamSearchTopK() { CUDA_CALL_THROW(cudaMemcpy(top_k_token_host.data(), top_k_token, batch_size * k * 4, cudaMemcpyDeviceToHost)); CUDA_CALL_THROW(cudaMemcpy(top_k_indices_host.data(), top_k_indices, batch_size * k * 4, cudaMemcpyDeviceToHost)); for (int32_t i = 0; i < batch_size * k; i++) { - if (top_k_values_ref[i] != top_k_values_host[i] || - top_k_tokens_ref[i] != top_k_token_host[i] || - top_k_indices_ref[i] != top_k_indices_host[i]) { - return false; - } + ASSERT_TRUE(top_k_values_ref[i] == top_k_values_host[i] && + top_k_tokens_ref[i] == top_k_token_host[i] && + top_k_indices_ref[i] == top_k_indices_host[i]); } CUDA_CALL_THROW(cudaFree(cuda_buffer)); - - return true; } } // namespace test } // namespace cuda } // namespace onnxruntime -#endif diff --git a/onnxruntime/core/providers/cuda/test/cuda_execution_provider_test.cc b/onnxruntime/test/providers/cuda/test_cases/cuda_execution_provider_test.cc similarity index 68% rename from onnxruntime/core/providers/cuda/test/cuda_execution_provider_test.cc rename to onnxruntime/test/providers/cuda/test_cases/cuda_execution_provider_test.cc index a6f783b5875d4..a70e439cdf755 100644 --- a/onnxruntime/core/providers/cuda/test/cuda_execution_provider_test.cc +++ b/onnxruntime/test/providers/cuda/test_cases/cuda_execution_provider_test.cc @@ -5,29 +5,26 @@ // extra code in the core of CUDA EP and that code may // 1. slow down performance critical applications and // 2. increase binary size of ORT. -#ifndef NDEBUG #include -#include "core/providers/cuda/test/all_tests.h" #include "core/providers/cuda/cuda_execution_provider.h" #include "core/providers/cuda/cuda_allocator.h" #include "core/providers/cuda/cuda_stream_handle.h" +#include "gtest/gtest.h" namespace onnxruntime { namespace cuda { namespace test { // TODO: Since the "DeferredRelease" has been migrated to CudaStream class, // we should migrate this test from CudaEP unit test to CudaStream unit test. -bool TestDeferredRelease() { +TEST(TestDeferredRelease, WithArena) { // Create CUDA EP. CUDAExecutionProviderInfo info; CUDAExecutionProvider ep(info); - // Initialize allocators in EP. - onnxruntime::AllocatorManager allocator_manager; - ep.RegisterAllocator(allocator_manager); - AllocatorPtr gpu_alloctor = ep.GetAllocator(OrtMemType::OrtMemTypeDefault); + AllocatorPtr gpu_alloctor = ep.CreatePreferredAllocators()[0]; + // Allocator for call cudaMallocHost and cudaFreeHost // For details, see CUDAPinnedAllocator in cuda_allocator.cc. - AllocatorPtr cpu_pinned_alloc = ep.GetAllocator(OrtMemTypeCPU); + AllocatorPtr cpu_pinned_alloc = ep.CreatePreferredAllocators()[1]; // let the CudaStream instance "own" the default stream, so we can avoid the // work to initialize cublas/cudnn/... It is ok since it is just a customized unit test. CudaStream stream(nullptr, gpu_alloctor->Info().device, cpu_pinned_alloc, false, true, nullptr, nullptr); @@ -37,7 +34,7 @@ bool TestDeferredRelease() { ORT_THROW_IF_ERROR(ep.OnRunStart()); for (size_t i = 0; i < n_allocs; ++i) { // Allocate 10MB CUDA pinned memory. - auto pinned_buffer = ep.AllocateBufferOnCPUPinned(n_bytes); + auto pinned_buffer = IAllocator::MakeUniquePtr(cpu_pinned_alloc, n_bytes); // Release it using CUDA callback. stream.EnqueDeferredCPUBuffer(pinned_buffer.release()); } @@ -45,56 +42,46 @@ bool TestDeferredRelease() { // Memory stats AllocatorStats stats; cpu_pinned_alloc->GetStats(&stats); - ORT_ENFORCE(stats.num_allocs == n_allocs); + ASSERT_EQ(stats.num_allocs, n_allocs); ORT_THROW_IF_ERROR(stream.CleanUpOnRunEnd()); ORT_THROW_IF_ERROR(ep.OnRunEnd(true)); - return true; } -bool TestDeferredReleaseWithoutArena() { +TEST(TestDeferredRelease, WithoutArena) { // Create CUDA EP. CUDAExecutionProviderInfo info; CUDAExecutionProvider ep(info); - // Initialize allocators in EP. - onnxruntime::AllocatorManager allocator_manager; OrtDevice pinned_device{OrtDevice::CPU, OrtDevice::MemType::CUDA_PINNED, DEFAULT_CPU_ALLOCATOR_DEVICE_ID}; // Create allocator without BFCArena AllocatorCreationInfo pinned_memory_info( - [](OrtDevice::DeviceId device_id) { - return std::make_unique(device_id, CUDA_PINNED); + [](OrtDevice::DeviceId) { + return std::make_unique(CUDA_PINNED); }, pinned_device.Id(), false /* no arena */); auto cuda_pinned_alloc = CreateAllocator(pinned_memory_info); - allocator_manager.InsertAllocator(cuda_pinned_alloc); - // Use existing allocator in allocator_manager. - // Also register new allocator created by this EP in allocator_manager. - ep.RegisterAllocator(allocator_manager); - AllocatorPtr gpu_alloctor = ep.GetAllocator(OrtMemType::OrtMemTypeDefault); + AllocatorPtr gpu_alloctor = ep.CreatePreferredAllocators()[0]; // Allocator for call cudaMallocHost and cudaFreeHost // For details, see CUDAPinnedAllocator in cuda_allocator.cc. - AllocatorPtr cpu_pinned_alloc = ep.GetAllocator(OrtMemTypeCPU); // let the CudaStream instance "own" the default stream, so we can avoid the // work to initialize cublas/cudnn/... It is ok since it is just a customized unit test. - CudaStream stream(nullptr, gpu_alloctor->Info().device, cpu_pinned_alloc, false, true, nullptr, nullptr); + CudaStream stream(nullptr, gpu_alloctor->Info().device, cuda_pinned_alloc, false, true, nullptr, nullptr); // 10 MB const size_t n_bytes = 10 * 1000000; const int64_t n_allocs = 64; ORT_THROW_IF_ERROR(ep.OnRunStart()); for (size_t i = 0; i < n_allocs; ++i) { // Allocate 10MB CUDA pinned memory. - auto pinned_buffer = ep.AllocateBufferOnCPUPinned(n_bytes); + auto pinned_buffer = IAllocator::MakeUniquePtr(cuda_pinned_alloc, n_bytes); // Release it using CUDA callback. stream.EnqueDeferredCPUBuffer(pinned_buffer.release()); } ORT_THROW_IF_ERROR(stream.CleanUpOnRunEnd()); ORT_THROW_IF_ERROR(ep.OnRunEnd(true)); - return true; } } // namespace test } // namespace cuda } // namespace onnxruntime -#endif diff --git a/onnxruntime/test/providers/cuda/test_cases/cuda_test_provider.cc b/onnxruntime/test/providers/cuda/test_cases/cuda_test_provider.cc new file mode 100644 index 0000000000000..96c1e173316de --- /dev/null +++ b/onnxruntime/test/providers/cuda/test_cases/cuda_test_provider.cc @@ -0,0 +1,136 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/providers/shared_library/provider_api.h" +#include "core/providers/cuda/cuda_provider_factory.h" +#include "core/providers/cuda/cuda_provider_factory_creator.h" +#include "core/providers/cuda/cuda_provider_options.h" + +#include +#include + +#include "core/common/gsl.h" +#include "gtest/gtest.h" + +#include "core/providers/cuda/cuda_execution_provider.h" +#include "core/providers/cuda/cuda_execution_provider_info.h" +#include "core/providers/cuda/cuda_allocator.h" +#include "core/providers/cuda/gpu_data_transfer.h" +#include "core/providers/cuda/math/unary_elementwise_ops_impl.h" + +#ifdef ENABLE_NVTX_PROFILE +#include "core/providers/cuda/nvtx_profile.h" +#endif + +using namespace onnxruntime; + +#if defined(USE_CUDA) && defined(ORT_USE_NCCL) && defined(USE_NCCL_P2P) && defined(ENABLE_TRAINING) +namespace cuda { +cuda::INcclService& GetINcclService(); +} +#endif + +namespace onnxruntime { + +void InitializeRegistry(); +void DeleteRegistry(); + +struct ProviderInfo_CUDA_TestImpl : ProviderInfo_CUDA { + OrtStatus* SetCurrentGpuDeviceId(_In_ int) override { + return nullptr; + } + + OrtStatus* GetCurrentGpuDeviceId(_In_ int*) override { + return nullptr; + } + + std::unique_ptr CreateCUDAAllocator(int16_t, const char*) override { + return nullptr; + } + + std::unique_ptr CreateCUDAPinnedAllocator(const char*) override { + return nullptr; + } + + std::unique_ptr CreateGPUDataTransfer() override { + return nullptr; + } + + void cuda__Impl_Cast(void*, const int64_t*, int32_t*, size_t) override {} + + void cuda__Impl_Cast(void*, const int32_t*, int64_t*, size_t) override {} + + void cuda__Impl_Cast(void*, const double*, float*, size_t) override {} + + void cuda__Impl_Cast(void*, const float*, double*, size_t) override {} + + Status CudaCall_false(int retCode, const char* exprString, const char* libName, int successCode, const char* msg, const char* file, const int line) override { return CudaCall(cudaError(retCode), exprString, libName, cudaError(successCode), msg, file, line); } + void CudaCall_true(int retCode, const char* exprString, const char* libName, int successCode, const char* msg, const char* file, const int line) override { CudaCall(cudaError(retCode), exprString, libName, cudaError(successCode), msg, file, line); } + + void CopyGpuToCpu(void*, const void*, const size_t, const OrtMemoryInfo&, const OrtMemoryInfo&) override {} + + void cudaMemcpy_HostToDevice(void*, const void*, size_t) override {} + + // Used by onnxruntime_pybind_state.cc + void cudaMemcpy_DeviceToHost(void*, const void*, size_t) override {} + + int cudaGetDeviceCount() override { return 0; } + + void CUDAExecutionProviderInfo__FromProviderOptions(const ProviderOptions&, CUDAExecutionProviderInfo&) override {} + +#if defined(USE_CUDA) && defined(ORT_USE_NCCL) && defined(USE_NCCL_P2P) && defined(ENABLE_TRAINING) + cuda::INcclService& GetINcclService() override { + return cuda::GetINcclService(); + } +#endif + +#ifdef ENABLE_NVTX_PROFILE + void NvtxRangeCreator__BeginImpl(profile::NvtxRangeCreator* p) override { p->BeginImpl(); } + void NvtxRangeCreator__EndImpl(profile::NvtxRangeCreator* p) override { p->EndImpl(); } +#endif + + std::shared_ptr CreateExecutionProviderFactory(const CUDAExecutionProviderInfo&) override { + return nullptr; + } + + std::shared_ptr CreateCudaAllocator(int16_t, size_t, onnxruntime::ArenaExtendStrategy, onnxruntime::CUDAExecutionProviderExternalAllocatorInfo&, const OrtArenaCfg*) override { + return nullptr; + } + + void TestAll() override { + // TestAll is the entry point of CUDA EP's insternal tests. + // Those internal tests are not directly callable from onnxruntime_test_all + // because CUDA EP is a shared library now. + // Instead, this is a test provider that implements all the test cases. + // onnxruntime_test_all is calling this function through TryGetProviderInfo_CUDA_Test. + int argc = 1; + std::string mock_exe_name = "onnxruntime_providers_cuda_ut"; + char* argv[] = {const_cast(mock_exe_name.data())}; + ::testing::InitGoogleTest(&argc, argv); + ORT_ENFORCE(RUN_ALL_TESTS() == 0); + } +}; +ProviderInfo_CUDA_TestImpl g_test_info; + +struct CUDA_Test_Provider : Provider { + void* GetInfo() override { return &g_test_info; } + + void Initialize() override { + InitializeRegistry(); + } + + void Shutdown() override { + DeleteRegistry(); + } +}; + +CUDA_Test_Provider g_test_provider; + +} // namespace onnxruntime + +extern "C" { +// This is the entry point of libonnxruntime_providers_cuda_ut.so/dll. +ORT_API(onnxruntime::Provider*, GetProvider) { + return &onnxruntime::g_test_provider; +} +} diff --git a/orttraining/orttraining/test/training_ops/cuda/cuda_utils_test.cc b/onnxruntime/test/providers/cuda/test_cases/cuda_utils_test.cc similarity index 92% rename from orttraining/orttraining/test/training_ops/cuda/cuda_utils_test.cc rename to onnxruntime/test/providers/cuda/test_cases/cuda_utils_test.cc index 112273de2e3f6..9d20bc545df5f 100644 --- a/orttraining/orttraining/test/training_ops/cuda/cuda_utils_test.cc +++ b/onnxruntime/test/providers/cuda/test_cases/cuda_utils_test.cc @@ -1,9 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#if 0 // TODO: Can't call these directly from external code as Cuda is now a shared library -//#ifdef USE_CUDA - #include #include @@ -53,5 +50,3 @@ TEST(CudaUtilsTest, FillCorrectness) { } // namespace test } // namespace cuda } // namespace onnxruntime - -#endif // USE_CUDA diff --git a/onnxruntime/test/providers/cuda/gemm_options_test.cc b/onnxruntime/test/providers/cuda/test_cases/gemm_options_test.cc similarity index 76% rename from onnxruntime/test/providers/cuda/gemm_options_test.cc rename to onnxruntime/test/providers/cuda/test_cases/gemm_options_test.cc index 2ec64551de749..6cac23f14459e 100644 --- a/onnxruntime/test/providers/cuda/gemm_options_test.cc +++ b/onnxruntime/test/providers/cuda/test_cases/gemm_options_test.cc @@ -1,24 +1,19 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#if 0 // TODO: Can't call these directly from external code as Cuda is now a shared library -//#ifdef USE_CUDA +#include "core/common/common.h" +#include "core/providers/cuda/cuda_common.h" #include "gtest/gtest.h" -#include "core/providers/cuda/cuda_common.h" namespace onnxruntime { namespace cuda { - -// Initialize the singleton instance -HalfGemmOptions HalfGemmOptions::instance; - namespace test { -TEST(CudaGemmOptionsTest, DefaultOptions) { +TEST(CudaGemmOptions, TestDefaultOptions) { HalfGemmOptions gemm_options; ASSERT_FALSE(gemm_options.IsCompute16F()); -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11000 +#if defined(USE_CUDA) EXPECT_EQ(gemm_options.GetMathMode(), CUBLAS_DEFAULT_MATH); EXPECT_EQ(gemm_options.GetComputeType(), CUBLAS_COMPUTE_32F); #else @@ -27,11 +22,11 @@ TEST(CudaGemmOptionsTest, DefaultOptions) { #endif } -TEST(CudaGemmOptionsTest, Compute16F) { +TEST(CudaGemmOptions, TestCompute16F) { HalfGemmOptions gemm_options; gemm_options.Initialize(1); ASSERT_TRUE(gemm_options.IsCompute16F()); -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11000 +#if defined(USE_CUDA) EXPECT_EQ(gemm_options.GetMathMode(), CUBLAS_DEFAULT_MATH); EXPECT_EQ(gemm_options.GetComputeType(), CUBLAS_COMPUTE_16F); #else @@ -40,11 +35,11 @@ TEST(CudaGemmOptionsTest, Compute16F) { #endif } -TEST(CudaGemmOptionsTest, NoReducedPrecision) { +TEST(CudaGemmOptions, NoReducedPrecision) { HalfGemmOptions gemm_options; gemm_options.Initialize(2); ASSERT_FALSE(gemm_options.IsCompute16F()); -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11000 +#if defined(USE_CUDA) EXPECT_EQ(gemm_options.GetMathMode(), CUBLAS_MATH_DISALLOW_REDUCED_PRECISION_REDUCTION); EXPECT_EQ(gemm_options.GetComputeType(), CUBLAS_COMPUTE_32F); #else @@ -53,11 +48,11 @@ TEST(CudaGemmOptionsTest, NoReducedPrecision) { #endif } -TEST(CudaGemmOptionsTest, Pedantic) { +TEST(CudaGemmOptions, Pedantic) { HalfGemmOptions gemm_options; gemm_options.Initialize(4); ASSERT_FALSE(gemm_options.IsCompute16F()); -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11000 +#if defined(USE_CUDA) EXPECT_EQ(gemm_options.GetMathMode(), CUBLAS_PEDANTIC_MATH); EXPECT_EQ(gemm_options.GetComputeType(), CUBLAS_COMPUTE_32F_PEDANTIC); #else @@ -66,11 +61,11 @@ TEST(CudaGemmOptionsTest, Pedantic) { #endif } -TEST(CudaGemmOptionsTest, Compute16F_Pedantic) { +TEST(CudaGemmOptions, Compute16F_Pedantic) { HalfGemmOptions gemm_options; gemm_options.Initialize(5); ASSERT_TRUE(gemm_options.IsCompute16F()); -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11000 +#if defined(USE_CUDA) EXPECT_EQ(gemm_options.GetMathMode(), CUBLAS_PEDANTIC_MATH); EXPECT_EQ(gemm_options.GetComputeType(), CUBLAS_COMPUTE_16F_PEDANTIC); #else @@ -79,11 +74,11 @@ TEST(CudaGemmOptionsTest, Compute16F_Pedantic) { #endif } -TEST(CudaGemmOptionsTest, Compute16F_NoReducedPrecision) { +TEST(CudaGemmOptions, Compute16F_NoReducedPrecision) { HalfGemmOptions gemm_options; gemm_options.Initialize(3); ASSERT_TRUE(gemm_options.IsCompute16F()); -#if defined(CUDA_VERSION) && CUDA_VERSION >= 11000 +#if defined(USE_CUDA) EXPECT_EQ(gemm_options.GetMathMode(), CUBLAS_DEFAULT_MATH); EXPECT_EQ(gemm_options.GetComputeType(), CUBLAS_COMPUTE_16F); #else @@ -95,5 +90,3 @@ TEST(CudaGemmOptionsTest, Compute16F_NoReducedPrecision) { } // namespace test } // namespace cuda } // namespace onnxruntime - -#endif diff --git a/onnxruntime/core/providers/cuda/test/greedy_search_top_one.cc b/onnxruntime/test/providers/cuda/test_cases/greedy_search_top_one.cc similarity index 94% rename from onnxruntime/core/providers/cuda/test/greedy_search_top_one.cc rename to onnxruntime/test/providers/cuda/test_cases/greedy_search_top_one.cc index 96282c89adaaf..6b8cd68de0fca 100644 --- a/onnxruntime/core/providers/cuda/test/greedy_search_top_one.cc +++ b/onnxruntime/test/providers/cuda/test_cases/greedy_search_top_one.cc @@ -1,4 +1,3 @@ -#ifndef NDEBUG #include "contrib_ops/cuda/transformers/greedy_search_top_one.h" #include "core/providers/cuda/shared_inc/cuda_call.h" @@ -9,6 +8,8 @@ #include +#include "gtest/gtest.h" + namespace onnxruntime { namespace cuda { namespace test { @@ -40,7 +41,7 @@ void ComputeTop1Reference(const std::vector& values, } } -bool TestGreedySearchTopOne() { +TEST(TestGreedySearch, TopOne) { int32_t batch_size = 4; int32_t vocab_size = 50257; int32_t batch_x_vocab = batch_size * vocab_size; @@ -87,18 +88,13 @@ bool TestGreedySearchTopOne() { CUDA_CALL_THROW(cudaMemcpy(top_k_values_host.data(), output_score_data, batch_size * sizeof(float), cudaMemcpyDeviceToHost)); CUDA_CALL_THROW(cudaMemcpy(top_k_token_host.data(), output_token_data, batch_size * sizeof(float), cudaMemcpyDeviceToHost)); for (int32_t i = 0; i < batch_size; i++) { - if (top_k_values_ref[i] != top_k_values_host[i] || - top_k_tokens_ref[i] != top_k_token_host[i]) { - return false; - } + ASSERT_TRUE(top_k_values_ref[i] == top_k_values_host[i] && + top_k_tokens_ref[i] == top_k_token_host[i]); } CUDA_CALL_THROW(cudaFree(topk_data)); - - return true; } } // namespace test } // namespace cuda } // namespace onnxruntime -#endif diff --git a/onnxruntime/test/providers/cuda/reduction_functions_test.cc b/onnxruntime/test/providers/cuda/test_cases/reduction_functions_test.cc similarity index 94% rename from onnxruntime/test/providers/cuda/reduction_functions_test.cc rename to onnxruntime/test/providers/cuda/test_cases/reduction_functions_test.cc index bcce48ff30677..c460e806c1a80 100644 --- a/onnxruntime/test/providers/cuda/reduction_functions_test.cc +++ b/onnxruntime/test/providers/cuda/test_cases/reduction_functions_test.cc @@ -1,18 +1,18 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#if 0 // TODO: Can't call these directly from external code as Cuda is now a shared library -//#ifdef USE_CUDA - #include #include "gtest/gtest.h" +#include "core/providers/cuda/shared_inc/cuda_utils.h" #include "core/common/optional.h" #include "core/providers/cuda/reduction/reduction_functions.h" #include "core/providers/cuda/shared_inc/cuda_utils.h" -#include "test/common/tensor_op_test_utils.h" +#include "test/common/random_generator.h" #include "test/util/include/asserts.h" +// To avoid conflict of LogRuntimeError, we direct include the cc file directly. +#include "test/util/test_random_seed.cc" using onnxruntime::test::RandomValueGenerator; @@ -93,7 +93,7 @@ void TestReduceRowToScalarApis(int size, float relative_error_tolerance = 1e-4f) buffer.get(), buffer_size_in_bytes)); - ASSERT_TRUE(CUDA_CALL(cudaDeviceSynchronize())); + ASSERT_TRUE(CUDA_CALL(cudaDeviceSynchronize()).IsOK()); CheckDeviceValues(1, device_output_sum.get(), &expected_output_sum, relative_error_tolerance); CheckDeviceValues(1, device_output_square_sum.get(), &expected_output_square_sum, relative_error_tolerance); @@ -133,7 +133,7 @@ void TestReduceRowsToRow(int m, int n, bool reset_initial_output, float relative m, n, reset_initial_output)); - ASSERT_TRUE(CUDA_CALL(cudaDeviceSynchronize())); + ASSERT_TRUE(CUDA_CALL(cudaDeviceSynchronize()).IsOK()); CheckDeviceValues(n, d_out.get(), expected_row.data(), relative_error_tolerance); } @@ -173,7 +173,7 @@ void TestReduceColumnsToColumn(int m, int n, float relative_error_tolerance = 1e m, n, d_buffer.get(), buffer_size_in_bytes)); - ASSERT_TRUE(CUDA_CALL(cudaDeviceSynchronize())); + ASSERT_TRUE(CUDA_CALL(cudaDeviceSynchronize()).IsOK()); CheckDeviceValues(m, d_out.get(), expected_column.data(), relative_error_tolerance); } @@ -208,6 +208,7 @@ TEST(ReductionFunctionsTest, ReduceColumnsToColumn) { TEST(ReductionFunctionsTest, BufferOffsets) { const int m = 2048; const int n = 1024; + const TensorShape shape{m, n}; const size_t max_buffer_offset = 15; @@ -224,7 +225,7 @@ TEST(ReductionFunctionsTest, BufferOffsets) { for (size_t buffer_offset = 1; buffer_offset <= max_buffer_offset; ++buffer_offset) { SCOPED_TRACE(MakeString("buffer offset: ", buffer_offset)); - const auto input = random.Uniform({m, n}, 1.0, 10.0); + const auto input = random.Uniform(shape.GetDims(), 1.0, 10.0); cudaMemcpy(d_input.get(), input.data(), m * n * sizeof(double), cudaMemcpyHostToDevice); ASSERT_STATUS_OK(reduce_matrix_columns( @@ -242,6 +243,7 @@ TEST(ReductionFunctionsTest, BufferOffsets) { TEST(ReductionFunctionsTest, InvalidBufferSize) { const int m = 2048; const int n = 1024; + const TensorShape shape{m, n}; // this should be too small const size_t buffer_size_in_bytes = @@ -252,7 +254,7 @@ TEST(ReductionFunctionsTest, InvalidBufferSize) { auto d_buffer = AllocateDeviceMemory(buffer_size_in_bytes); RandomValueGenerator random{}; - const auto input = random.Uniform({m, n}, 1.0, 10.0); + const auto input = random.Uniform(shape.GetDims(), 1.0, 10.0); cudaMemcpy(d_input.get(), input.data(), m * n * sizeof(float), cudaMemcpyHostToDevice); const auto status = @@ -313,7 +315,7 @@ TEST(ReductionFunctionsTest, GetApplicableMatrixReduction) { // handle ones test_get_applicable_matrix_reduction( valid_op_type, {1, 2, 1, 1, 4, 1, 8, 1}, {0}, - ApplicableMatrixReduction::Rows, 1, 2 * 4 * 8); + ApplicableMatrixReduction::Columns, 2 * 4 * 8, 1); test_get_applicable_matrix_reduction( valid_op_type, {1, 2, 1, 1, 4, 1, 8, 1}, {1}, ApplicableMatrixReduction::Rows, 2, 4 * 8); @@ -348,7 +350,7 @@ TEST(ReductionFunctionsTest, GetApplicableMatrixReduction) { ApplicableMatrixReduction::None); test_get_applicable_matrix_reduction( valid_op_type, {1, 2, 1, 1, 4, 1, 8, 1}, {3, 6}, - ApplicableMatrixReduction::None); + ApplicableMatrixReduction::Columns, 2 * 4, 8); // invalid op type test_get_applicable_matrix_reduction( @@ -359,5 +361,3 @@ TEST(ReductionFunctionsTest, GetApplicableMatrixReduction) { } // namespace test } // namespace cuda } // namespace onnxruntime - -#endif 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 b601a58689558..957443c23e7c3 100644 --- a/onnxruntime/test/providers/internal_testing/internal_testing_execution_provider.cc +++ b/onnxruntime/test/providers/internal_testing/internal_testing_execution_provider.cc @@ -3,7 +3,7 @@ #include "internal_testing_execution_provider.h" -#include "core/framework/allocatormgr.h" +#include "core/framework/allocator_utils.h" #include "core/framework/compute_capability.h" #include "core/framework/feeds_fetches_manager.h" #include "core/framework/op_kernel_context_internal.h" @@ -13,7 +13,7 @@ #include "core/graph/model.h" #include "core/providers/partitioning_utils.h" #include "core/session/onnxruntime_cxx_api.h" -#include "core/optimizer/transpose_optimizer/optimizer_utils.h" +#include "core/optimizer/layout_transformation/layout_transformation.h" #include @@ -93,42 +93,13 @@ InternalTestingExecutionProvider::InternalTestingExecutionProvider(const std::un kernel_registry_{RegisterKernels()} { } -AllocatorPtr InternalTestingExecutionProvider::GetAllocator(OrtMemType mem_type) const { - // replicate setup that some EPs have with a local allocator - if (mem_type == OrtMemTypeDefault) { - return local_allocator_; - } else { - return IExecutionProvider::GetAllocator(mem_type); - } -} - -// implement RegisterAllocator to test/validate sharing the CPU EP's allocator -void InternalTestingExecutionProvider::RegisterAllocator(AllocatorManager& allocator_manager) { - OrtDevice cpu_device{OrtDevice::CPU, OrtDevice::MemType::DEFAULT, DEFAULT_CPU_ALLOCATOR_DEVICE_ID}; - - // if EP is used in multiple inference sessions we may already have an allocator. if so use that. - auto cpu_alloc = GetAllocator(OrtMemTypeDefault); - if (!cpu_alloc) { - // use shared allocator if available - cpu_alloc = allocator_manager.GetAllocator(OrtMemTypeDefault, cpu_device); - - if (!cpu_alloc) { - // create our allocator - AllocatorCreationInfo allocator_info( - [](int) { - return std::make_unique(OrtMemoryInfo(INTERNAL_TESTING_EP, - OrtAllocatorType::OrtDeviceAllocator)); - }); - - cpu_alloc = CreateAllocator(allocator_info); - - // enable sharing of our allocator - allocator_manager.InsertAllocator(cpu_alloc); - } - - local_allocator_ = cpu_alloc; - InsertAllocator(cpu_alloc); - } +std::vector InternalTestingExecutionProvider::CreatePreferredAllocators() { + AllocatorCreationInfo allocator_info( + [](int) { + return std::make_unique(OrtMemoryInfo(INTERNAL_TESTING_EP, + OrtAllocatorType::OrtDeviceAllocator)); + }); + return std::vector{CreateAllocator(allocator_info)}; } InternalTestingExecutionProvider::~InternalTestingExecutionProvider() {} @@ -268,7 +239,7 @@ common::Status InternalTestingExecutionProvider::Compile(const std::vector GetKernelRegistry() const override; - AllocatorPtr GetAllocator(OrtMemType mem_type) const override; - void RegisterAllocator(AllocatorManager& /*allocator_manager*/) override; - InternalTestingExecutionProvider& SetDebugOutput(bool debug_output) { debug_output_ = debug_output; return *this; @@ -57,6 +54,8 @@ class InternalTestingExecutionProvider : public IExecutionProvider { return *this; } + std::vector CreatePreferredAllocators() override; + private: const std::string ep_name_; @@ -80,10 +79,6 @@ class InternalTestingExecutionProvider : public IExecutionProvider { DataLayout preferred_layout_; // request all nodes - // used for testing allocator sharing as a few EPs (e.g. CUDA, TRT, TVM) override GetAllocator and have a local - // AllocatorPtr that can get out of sync with the allocator lists in the base IExecutionProvider - AllocatorPtr local_allocator_; - // per-instance kernel registry so tests using static kernels don't clash. // shared_ptr as required by IExecutionProvider::GetKernelRegistry std::shared_ptr kernel_registry_; diff --git a/onnxruntime/test/providers/internal_testing/internal_testing_tests.cc b/onnxruntime/test/providers/internal_testing/internal_testing_tests.cc index 917aeb47175dc..f7499fd7ad812 100644 --- a/onnxruntime/test/providers/internal_testing/internal_testing_tests.cc +++ b/onnxruntime/test/providers/internal_testing/internal_testing_tests.cc @@ -248,39 +248,9 @@ TEST(InternalTestingEP, TestNhwcConversionOfStaticKernels) { "Status Message: TODO: add NHWC implementation here.")); } -TEST(InternalTestingEP, TestRegisterAllocatorHandlesUsageInMultipleSessions) { - auto init_session = [](std::vector>& eps, - InferenceSessionWrapper& session) { - for (const auto& ep : eps) { - ASSERT_STATUS_OK(session.RegisterExecutionProvider(ep)); - } - - const ORTCHAR_T* ort_model_path = ORT_MODEL_FOLDER "squeezenet/model.onnx"; - ASSERT_STATUS_OK(session.Load(ort_model_path)); - ASSERT_STATUS_OK(session.Initialize()); - }; - - // create 2 sessions - SessionOptions so; - InferenceSessionWrapper session1(so, GetEnvironment()); - InferenceSessionWrapper session2(so, GetEnvironment()); - - // and use the same EP instances in both - const std::unordered_set supported_ops{"Conv", "Clip"}; - std::vector> eps{ - std::make_shared(supported_ops, std::unordered_set{}, - DataLayout::NHWC), - std::make_shared(CPUExecutionProviderInfo{}, true /* delay allocator registration to allow sharing */)}; - - // check RegisterAllocator is implemented properly and supports calls from multiple inference sessions - init_session(eps, session1); - init_session(eps, session2); - - // check that allocator sharing worked. the internal testing EP should be using the CPU EP allocator - ASSERT_EQ(eps[0]->GetAllocator(OrtMemType::OrtMemTypeDefault), - eps[1]->GetAllocator(OrtMemType::OrtMemTypeDefault)) - << "EPs do not have the same default allocator"; -} +// This test can be deprecated now as the code logic has been changed so the model is not applicable +// TEST(InternalTestingEP, TestRegisterAllocatorHandlesUsageInMultipleSessions) { +//} // make sure allocators returned by SessionState::GetAllocator are valid when IExecutionProvider::ReplaceAllocator // is used. if something is off InferenceSession::Initialize will fail. @@ -310,17 +280,7 @@ TEST(InternalTestingEP, TestReplaceAllocatorDoesntBreakDueToLocalAllocatorStorag ASSERT_STATUS_OK(session.Load(ort_model_path)); ASSERT_STATUS_OK(session.Initialize()); - ASSERT_STATUS_OK(env.UnregisterAllocator(mem_info)); - - // CPU EP is simple and should use the replacement allocator - ASSERT_EQ(replacement_alloc, eps[1]->GetAllocator(OrtMemType::OrtMemTypeDefault)); - - // our test EP has a local allocator and GetAllocator override. - // - a call to GetAllocator won't match the replacement one because of this. - // - a call to IExecutionProvider::GetAllocator should. - // this is not a good setup, but at least clarifies how the current system works. - ASSERT_NE(replacement_alloc, eps[0]->GetAllocator(OrtMemType::OrtMemTypeDefault)); - ASSERT_EQ(replacement_alloc, eps[0]->IExecutionProvider::GetAllocator(OrtMemType::OrtMemTypeDefault)); + ASSERT_EQ(replacement_alloc, session.GetAllocator(OrtMemoryInfo())) << "Allocators registered from Env should have the highest priority"; } #endif // !defined(DISABLE_CONTRIB_OPS) @@ -337,7 +297,7 @@ TEST(InternalTestingEP, TestLoadOrtModel) { ExecuteMnist(*session, enable_custom_ep); } -// test that is the custom EP cannot take all nodes due to device limitations +// test that if the custom EP cannot take all nodes due to device limitations // that we fallback to the CPU implementations and can execute the model TEST(InternalTestingEP, TestLoadOrtModelWithReducedOpCoverage) { const ORTCHAR_T* ort_model_path = ORT_MODEL_FOLDER "mnist.internal_testing_ep.ort"; @@ -357,7 +317,6 @@ TEST(InternalTestingEP, TestLoadOrtModelWithReducedOpCoverage) { // the generated op type should have a hash for the model based on the model path const std::string expected_op_type_prefix = "InternalTestingEP_9611636968429821767_"; - int compiled_node_num = 0; for (const auto& node : graph.Nodes()) { EXPECT_EQ(supported_ops.count(node.OpType()), size_t(0)) @@ -365,7 +324,7 @@ TEST(InternalTestingEP, TestLoadOrtModelWithReducedOpCoverage) { if (node.GetExecutionProviderType() == utils::kInternalTestingExecutionProvider) { EXPECT_STATUS_OK(func_mgr.GetFuncs(node.Name(), compute_func)); EXPECT_NE(compute_func, nullptr); - EXPECT_EQ(node.OpType(), expected_op_type_prefix + std::to_string(compiled_node_num++)); + EXPECT_THAT(node.OpType(), ::testing::StartsWith(expected_op_type_prefix)); } } @@ -423,7 +382,7 @@ TEST(InternalTestingEP, TestModelWithSubgraph) { // the output from fused nodes using the testing EP is always 0, so we should match the expected output this way // as we replace all the Add nodes with something that returns 0. // RunAndVerifyOutputsWithEP checks that nodes are assigned to the EP so we know it's being used to execute the model - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), {1}, {-2.f}, + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], {1}, {-2.f}, &ml_value); NameMLValMap feeds; feeds.insert(std::make_pair("state_var_in", ml_value)); diff --git a/onnxruntime/test/providers/kernel_compute_test_utils.cc b/onnxruntime/test/providers/kernel_compute_test_utils.cc index 1b8fbd07ea597..0bcf3cbbfd089 100644 --- a/onnxruntime/test/providers/kernel_compute_test_utils.cc +++ b/onnxruntime/test/providers/kernel_compute_test_utils.cc @@ -5,6 +5,7 @@ #include "test/providers/kernel_compute_test_utils.h" +#include "core/framework/execution_providers.h" #include "core/optimizer/optimizer_execution_frame.h" #include "test/util/include/default_providers.h" @@ -57,7 +58,7 @@ void KernelComputeTester::Run(std::unordered_set strided_outputs) { OrtValue gpu_value; const Tensor& tensor = data.value_.Get(); Tensor::InitOrtValue(tensor.DataType(), tensor.Shape(), - execution_providers.Get(ep_type)->GetAllocator(OrtMemTypeDefault), gpu_value, + execution_providers.Get(ep_type)->CreatePreferredAllocators()[0], gpu_value, tensor.Strides()); ASSERT_STATUS_OK(dtm.CopyTensor(tensor, *gpu_value.GetMutable())); initializer_map[name] = gpu_value; @@ -100,7 +101,7 @@ void KernelComputeTester::Run(std::unordered_set strided_outputs) { initializer_map[input_data_[static_cast(pair.first)].def_.Name()] .GetMutable() ->MutableDataRaw(), - execution_providers.Get(ep_type)->GetAllocator(OrtMemTypeDefault)->Info(), output); + execution_providers.Get(ep_type)->CreatePreferredAllocators()[0]->Info(), output); is_may_strided_output = true; break; } @@ -108,7 +109,7 @@ void KernelComputeTester::Run(std::unordered_set strided_outputs) { ASSERT_TRUE(is_may_strided_output); } else { Tensor::InitOrtValue(tensor.DataType(), tensor.Shape(), - execution_providers.Get(ep_type)->GetAllocator(OrtMemTypeDefault), output); + execution_providers.Get(ep_type)->CreatePreferredAllocators()[0], output); } outputs.emplace_back(output); } @@ -160,15 +161,12 @@ void KernelComputeTester::Run(std::unordered_set strided_outputs) { } else { const Tensor& tensor = outputs[i].Get(); Tensor::InitOrtValue(tensor.DataType(), tensor.Shape(), - execution_providers.Get(cpu_ep_type)->GetAllocator(OrtMemTypeDefault), cpu_value, + execution_providers.Get(cpu_ep_type)->CreatePreferredAllocators()[0], cpu_value, tensor.Strides()); ASSERT_STATUS_OK(dtm.CopyTensor(tensor, *cpu_value.GetMutable())); } - optional rel; - optional abs; - OpTester::Data expected(std::move(output_data_[i].def_), std::move(output_data_[i].value_), std::move(rel), - std::move(abs)); - Check(expected, cpu_value.Get(), provider_); + + CheckOrtValuesAreEqual(output_data_[i].def_.Name(), output_data_[i].value_, cpu_value, {}, provider_); } } } diff --git a/onnxruntime/test/providers/memcpy_test.cc b/onnxruntime/test/providers/memcpy_test.cc index 3649f503f896b..b0cdb7dc97773 100644 --- a/onnxruntime/test/providers/memcpy_test.cc +++ b/onnxruntime/test/providers/memcpy_test.cc @@ -60,8 +60,7 @@ TEST(MemcpyTest, copy1) { ASSERT_STATUS_OK(s.FinalizeSessionState(ORT_TSTR(""), kernel_registry_manager)); - AllocatorPtr allocator = - execution_providers.Get(onnxruntime::kCpuExecutionProvider)->GetAllocator(OrtMemTypeDefault); + AllocatorPtr allocator = s.GetAllocator(execution_providers.Get(onnxruntime::kCpuExecutionProvider)->GetOrtDeviceByMemType(OrtMemTypeDefault)); auto* data_type = DataTypeImpl::GetType(); OrtValue input; Tensor::InitOrtValue(data_type, TensorShape({3, 2}), std::move(allocator), input); diff --git a/onnxruntime/test/providers/model_tester.h b/onnxruntime/test/providers/model_tester.h new file mode 100644 index 0000000000000..1bcab58c80f37 --- /dev/null +++ b/onnxruntime/test/providers/model_tester.h @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/common/path_string.h" +#include "core/graph/model.h" +#include "core/session/environment.h" + +#include "test/providers/base_tester.h" +#include "test/util/include/asserts.h" +#include "test/util/include/test_environment.h" + +namespace onnxruntime { +namespace test { +// To use ModelTester: +// 1. Create with the path to an existing model. +// 2. Call AddInput for all the inputs +// 3. Call AddOutput with all expected outputs +// 4. Call Run +class ModelTester : public BaseTester { + public: + /// + /// Create a model tester. Intended usage is a simple model that is primarily testing a specific operator, but may + /// require additional nodes to exercise the intended code path. + /// + /// Name of test to use in logs and error messages. + /// Model to load + /// ONNX opset version for the model. + /// Only required if testing a model with an unreleased opset version. + explicit ModelTester(std::string_view test_name, const PathString& model_uri, int onnx_opset_version = -1) + : BaseTester{test_name, onnx_opset_version, onnxruntime::kOnnxDomain}, + model_uri_{model_uri} { + } + + using ExpectResult = BaseTester::ExpectResult; + + private: + void CreateModelToTest(const ModelOptions& model_options, Model*& model) override { + ASSERT_STATUS_OK(Model::Load(model_uri_, model_, nullptr, DefaultLoggingManager().DefaultLogger(), model_options)); + + model = model_.get(); + } + + const PathString model_uri_; + std::shared_ptr model_; +}; +} // namespace test +} // namespace onnxruntime diff --git a/onnxruntime/test/providers/nnapi/nnapi_basic_test.cc b/onnxruntime/test/providers/nnapi/nnapi_basic_test.cc index 11590281af68c..0e783a94c5479 100644 --- a/onnxruntime/test/providers/nnapi/nnapi_basic_test.cc +++ b/onnxruntime/test/providers/nnapi/nnapi_basic_test.cc @@ -3,6 +3,7 @@ #if !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) #include "core/common/logging/logging.h" +#include "core/common/span_utils.h" #include "core/providers/nnapi/nnapi_builtin/builders/op_builder.h" #include "core/providers/nnapi/nnapi_builtin/nnapi_execution_provider.h" #include "core/providers/nnapi/nnapi_builtin/nnapi_lib/NeuralNetworksTypes.h" @@ -37,17 +38,6 @@ namespace test { #if !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) -namespace { -[[maybe_unused]] void TestModelLoad(const ORTCHAR_T* model_file_name, const std::function& check_graph) { - SessionOptions so; - InferenceSessionWrapper session_object{so, GetEnvironment()}; - ASSERT_STATUS_OK(session_object.RegisterExecutionProvider(std::make_unique(0))); - ASSERT_STATUS_OK(session_object.Load(model_file_name)); - ASSERT_STATUS_OK(session_object.Initialize()); - check_graph(session_object.GetGraph()); -} -} // namespace - #endif // !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD) #if !defined(ORT_MINIMAL_BUILD) @@ -65,10 +55,11 @@ TEST(NnapiExecutionProviderTest, ReshapeFlattenTest) { std::vector dims_mul_y = {3, 2, 2}; std::vector values_mul_y = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f}; OrtValue ml_value_x; - CreateMLValue(TestNnapiExecutionProvider()->GetAllocator(OrtMemTypeDefault), dims_mul_x, values_mul_x, + AllocatorPtr cpu_allocator = std::make_shared(); + CreateMLValue(cpu_allocator, dims_mul_x, values_mul_x, &ml_value_x); OrtValue ml_value_y; - CreateMLValue(TestNnapiExecutionProvider()->GetAllocator(OrtMemTypeDefault), dims_mul_y, values_mul_y, + CreateMLValue(cpu_allocator, dims_mul_y, values_mul_y, &ml_value_y); NameMLValMap feeds; feeds.insert(std::make_pair("X", ml_value_x)); @@ -79,9 +70,7 @@ TEST(NnapiExecutionProviderTest, ReshapeFlattenTest) { feeds); #else // test load only - TestModelLoad(model_file_name, - [](const Graph& graph) { ASSERT_GT(CountAssignedNodes(graph, kNnapiExecutionProvider), 0) - << "Some nodes should have been taken by the NNAPI EP"; }); + TestModelLoad(model_file_name, std::make_unique(0), ExpectedEPNodeAssignment::Some); #endif } @@ -93,7 +82,8 @@ TEST(NnapiExecutionProviderTest, SigmoidSupportedInputRankTest) { std::vector values_mul_x = {1.0f, 2.0f, 3.0f, 4.0f, 1.0f, 2.0f, 3.0f, 4.0f}; OrtValue ml_value_x; - CreateMLValue(TestNnapiExecutionProvider()->GetAllocator(OrtMemTypeDefault), dims_mul_x, values_mul_x, + AllocatorPtr cpu_allocator = std::make_shared(); + CreateMLValue(std::move(cpu_allocator), dims_mul_x, values_mul_x, &ml_value_x); NameMLValMap feeds; feeds.insert(std::make_pair("X", ml_value_x)); @@ -103,9 +93,7 @@ TEST(NnapiExecutionProviderTest, SigmoidSupportedInputRankTest) { feeds, {ExpectedEPNodeAssignment::None} /* params */); #else // test load only - TestModelLoad(model_file_name, - [](const Graph& graph) { ASSERT_EQ(CountAssignedNodes(graph, kNnapiExecutionProvider), 0) - << "No nodes should have been taken by the NNAPI EP"; }); + TestModelLoad(model_file_name, std::make_unique(0), ExpectedEPNodeAssignment::None); #endif } @@ -120,7 +108,8 @@ TEST(NnapiExecutionProviderTest, DynamicGraphInputTest) { std::vector dims_mul_x = {1, 1, 4, 4}; std::vector values_mul_x = {1.0f, 2.0f, 3.0f, 4.0f, 1.0f, 2.0f, 3.0f, 4.0f, 1.0f, 2.0f, 3.0f, 4.0f, 1.0f, 2.0f, 3.0f, 4.0f}; OrtValue ml_value_x; - CreateMLValue(TestNnapiExecutionProvider()->GetAllocator(OrtMemTypeDefault), dims_mul_x, values_mul_x, + AllocatorPtr cpu_allocator = std::make_shared(); + CreateMLValue(std::move(cpu_allocator), dims_mul_x, values_mul_x, &ml_value_x); NameMLValMap feeds; @@ -130,7 +119,7 @@ TEST(NnapiExecutionProviderTest, DynamicGraphInputTest) { std::make_unique(0), feeds); #else - TestModelLoad(model_file_name, + TestModelLoad(model_file_name, std::make_unique(0), [](const Graph& graph) { ASSERT_EQ(CountAssignedNodes(graph, kNnapiExecutionProvider), 1) << "Exactly one node (Add) should have been taken by the NNAPI EP"; }); #endif @@ -149,7 +138,8 @@ TEST(NnapiExecutionProviderTest, InternalUint8SupportTest) { std::vector dims_x = {1, 1, 1, 3}; std::vector values_x = {0.0f, 256.0f, 512.0f}; OrtValue ml_value_x; - CreateMLValue(TestNnapiExecutionProvider()->GetAllocator(OrtMemTypeDefault), dims_x, values_x, + AllocatorPtr cpu_allocator = std::make_shared(); + CreateMLValue(std::move(cpu_allocator), dims_x, values_x, &ml_value_x); NameMLValMap feeds; feeds.insert(std::make_pair("X", ml_value_x)); @@ -158,9 +148,7 @@ TEST(NnapiExecutionProviderTest, InternalUint8SupportTest) { std::make_unique(0), feeds); #else - TestModelLoad(model_file_name, - [](const Graph& graph) { ASSERT_GT(CountAssignedNodes(graph, kNnapiExecutionProvider), 0) - << "Some nodes should have been taken by the NNAPI EP"; }); + TestModelLoad(model_file_name, std::make_unique(0), ExpectedEPNodeAssignment::Some); #endif } @@ -206,13 +194,14 @@ TEST(NnapiExecutionProviderTest, FunctionTest) { std::vector dims_mul_x = {1, 1, 3, 2}; std::vector values_mul_x = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; OrtValue ml_value_x; - CreateMLValue(TestNnapiExecutionProvider()->GetAllocator(OrtMemTypeDefault), dims_mul_x, values_mul_x, + AllocatorPtr cpu_allocator = std::make_shared(); + CreateMLValue(cpu_allocator, dims_mul_x, values_mul_x, &ml_value_x); OrtValue ml_value_y; - CreateMLValue(TestNnapiExecutionProvider()->GetAllocator(OrtMemTypeDefault), dims_mul_x, values_mul_x, + CreateMLValue(cpu_allocator, dims_mul_x, values_mul_x, &ml_value_y); OrtValue ml_value_z; - CreateMLValue(TestNnapiExecutionProvider()->GetAllocator(OrtMemTypeDefault), dims_mul_x, values_mul_x, + CreateMLValue(cpu_allocator, dims_mul_x, values_mul_x, &ml_value_z); NameMLValMap feeds; feeds.insert(std::make_pair("X", ml_value_x)); @@ -223,9 +212,7 @@ TEST(NnapiExecutionProviderTest, FunctionTest) { std::make_unique(0), feeds); #else - TestModelLoad(model_file_name, - [](const Graph& graph) { ASSERT_GT(CountAssignedNodes(graph, kNnapiExecutionProvider), 0) - << "Some nodes should have been taken by the NNAPI EP"; }); + TestModelLoad(model_file_name, std::make_unique(0), ExpectedEPNodeAssignment::Some); #endif } @@ -266,11 +253,7 @@ TEST(NnapiExecutionProviderTest, TestNoShapeInputModel) { // test load only // since we know NNAPI supports Add op, but both Add ops in the graph has no input shape // verify the entire graph will not be assigned to NNAPI EP - SessionOptions so; - InferenceSessionWrapper session_object{so, GetEnvironment()}; - TestModelLoad(model_file_name, - [](const Graph& graph) { ASSERT_EQ(CountAssignedNodes(graph, kNnapiExecutionProvider), 0) - << "No nodes should have been taken by the NNAPI EP"; }); + TestModelLoad(model_file_name, std::make_unique(0), ExpectedEPNodeAssignment::None); } static void RunQDQModelTest( @@ -287,28 +270,15 @@ static void RunQDQModelTest( // Serialize the model to a string. std::string model_data; model.ToProto().SerializeToString(&model_data); + const auto model_data_span = AsByteSpan(model_data.data(), model_data.size()); #if defined(__ANDROID__) - RunAndVerifyOutputsWithEP(model_data, "NnapiExecutionProviderTest.TestQDQModel", + RunAndVerifyOutputsWithEP(model_data_span, "NnapiExecutionProviderTest.TestQDQModel", std::make_unique(0), helper.feeds_, params); #else // test load only - SessionOptions so; - InferenceSessionWrapper session_object{so, GetEnvironment()}; - ASSERT_STATUS_OK(session_object.RegisterExecutionProvider(std::make_unique(0))); - ASSERT_STATUS_OK(session_object.Load(model_data.data(), static_cast(model_data.size()))); - ASSERT_STATUS_OK(session_object.Initialize()); - if (params.ep_node_assignment == ExpectedEPNodeAssignment::None) { - ASSERT_EQ(CountAssignedNodes(session_object.GetGraph(), kNnapiExecutionProvider), 0) - << "No node should have been taken by the NNAPI EP"; - } else if (params.ep_node_assignment == ExpectedEPNodeAssignment::All) { - ASSERT_EQ(CountAssignedNodes(session_object.GetGraph(), kNnapiExecutionProvider), session_object.GetGraph().NumberOfNodes()) - << "All nodes should have been taken by the NNAPI EP"; - } else { - ASSERT_GT(CountAssignedNodes(session_object.GetGraph(), kNnapiExecutionProvider), 0) - << "Some nodes should have been taken by the NNAPI EP"; - } + TestModelLoad(model_data_span, std::make_unique(0), params.ep_node_assignment); #endif } @@ -518,6 +488,31 @@ TEST(NnapiExecutionProviderTest, DISABLED_TestCast) { RunQDQModelTest(build_func, "nnapi_qdq_test_graph_cast", {ExpectedEPNodeAssignment::None}); } +TEST(NnapiExecutionProviderTest, TestGather) { + auto BuildGatherTestCase = [](const std::vector& input_shape, + bool scalar_indices) { + return [input_shape, scalar_indices](ModelTestBuilder& builder) { + auto* input_arg = builder.MakeInput(input_shape, + std::numeric_limits::min(), + std::numeric_limits::max()); + auto* output_arg = builder.MakeOutput(); + auto* indices = builder.MakeScalarInitializer(1); + if (!scalar_indices) { + indices = builder.Make1DInitializer({1}); + } + auto& gather_node = builder.AddNode("Gather", {input_arg, indices}, {output_arg}); + gather_node.AddAttribute("axis", int64_t(1)); + }; + }; + + RunQDQModelTest(BuildGatherTestCase({10, 5, 5} /* input_shape */, true /* scalar_indices */), + "nnapi_test_graph_gather_scalar", {ExpectedEPNodeAssignment::All}); + + RunQDQModelTest(BuildGatherTestCase({10, 5, 5} /* input_shape */, false /* not scalar_indices */), + "nnapi_test_graph_gather", + {ExpectedEPNodeAssignment::All}); +} + #endif // !(ORT_MINIMAL_BUILD) TEST(NnapiExecutionProviderTest, NNAPIFlagsTest) { @@ -540,7 +535,7 @@ TEST(NnapiExecutionProviderTest, TestOrtFormatModel) { std::vector data = random.Gaussian(dims, 0.0f, 1.f); OrtValue ml_value; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), dims, data, + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], dims, data, &ml_value); NameMLValMap feeds; @@ -551,10 +546,7 @@ TEST(NnapiExecutionProviderTest, TestOrtFormatModel) { feeds); #else // test load only - TestModelLoad(model_file_name, - [](const Graph& graph) { ASSERT_GT(CountAssignedNodes(graph, kNnapiExecutionProvider), 0) - << "Some nodes should have been taken by the NNAPI EP"; }); - + TestModelLoad(model_file_name, std::make_unique(0), ExpectedEPNodeAssignment::Some); #endif } @@ -564,14 +556,10 @@ TEST(NnapiExecutionProviderTest, ActivationOutsideOfPartition) { constexpr auto* model_file_name = ORT_TSTR("testdata/mnist.basic.ort"); // stop NNAPI partitioning at Relu so NNAPI EP only takes first Conv const auto nnapi_partitioning_stop_ops = "Relu"; - SessionOptions so; - InferenceSessionWrapper session_object{so, GetEnvironment()}; - ASSERT_STATUS_OK(session_object.RegisterExecutionProvider( - std::make_unique(0, nnapi_partitioning_stop_ops))); - ASSERT_STATUS_OK(session_object.Load(model_file_name)); - ASSERT_STATUS_OK(session_object.Initialize()); - // expect one NNAPI partition - ASSERT_EQ(CountAssignedNodes(session_object.GetGraph(), kNnapiExecutionProvider), 1); + TestModelLoad(model_file_name, std::make_unique(0, nnapi_partitioning_stop_ops), + // expect one NNAPI partition + [](const Graph& graph) { ASSERT_EQ(CountAssignedNodes(graph, kNnapiExecutionProvider), 1) + << "Exactly one node should have been taken by the NNAPI EP"; }); } } // namespace test diff --git a/onnxruntime/test/providers/op_tester.cc b/onnxruntime/test/providers/op_tester.cc new file mode 100644 index 0000000000000..b2eaaac192b91 --- /dev/null +++ b/onnxruntime/test/providers/op_tester.cc @@ -0,0 +1,102 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "test/providers/op_tester.h" + +#include "gtest/gtest.h" +#include "gmock/gmock.h" + +#include "test/util/include/test_environment.h" +namespace onnxruntime { +namespace test { + +void OpTester::AddNodes(onnxruntime::Graph& graph, + std::vector& graph_input_defs, + std::vector& graph_output_defs, + std::vector>& add_attribute_funcs) { + // default behavior is to create a single Node for the op being tested, + // with node inputs/outputs being 1:1 with graph inputs/outputs. + auto& node = graph.AddNode("node1", op_, op_, graph_input_defs, graph_output_defs, nullptr, Domain()); + + // Add the attributes if any + for (auto& add_attribute_fn : add_attribute_funcs) + add_attribute_fn(node); +} + +onnxruntime::Model& OpTester::BuildModel(const std::unordered_map& extra_domain_to_version, + const ModelOptions& model_options) { + const auto get_defs = [](std::vector& data) { + std::vector defs; + defs.reserve(data.size()); + std::transform(data.begin(), data.end(), std::back_inserter(defs), + [](Data& data) { return &data.def; }); + return defs; + }; + + // Generate the input & output def lists + std::vector input_defs = get_defs(GetInputData()); + std::vector output_defs = get_defs(GetOutputData()); + + // Create a simple model + std::unordered_map domain_to_version(extra_domain_to_version); + const auto& domain = Domain(); + if (domain_to_version.count(domain) == 0) { + domain_to_version.insert({domain, Opset()}); + } else { + auto key_val = extra_domain_to_version.find(domain); + + ORT_ENFORCE(key_val->second <= Opset()); + + if (key_val->second < Opset()) { + domain_to_version[domain] = Opset(); + } + } + + model_ = std::make_unique( + "test", false, ModelMetaData(), PathString(), CustomSchemaRegistries(), + domain_to_version, std::vector{}, + DefaultLoggingManager().DefaultLogger(), + model_options); + + onnxruntime::Graph& graph = model_->MainGraph(); + + AddNodes(graph, input_defs, output_defs, add_attribute_funcs_); + AddInitializers(graph); + + return *model_; +} + +void OpTester::CreateModelToTest(const ModelOptions& model_options, Model*& model) { + Status status = Status::OK(); + + model = &BuildModel({}, model_options); + auto& graph = model->MainGraph(); + + const auto& ctx = GetRunContext(); + if (GetAddShapeToTensorData() && ctx.expect_result == ExpectResult::kExpectFailure) { + // capture possible exceptions from shape inference for invalid testcase + ORT_TRY { + status = graph.Resolve(ctx.resolve_options); + } + ORT_CATCH(const std::exception& ex) { + ORT_HANDLE_EXCEPTION([&]() { + status = ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, ex.what()); + }); + } + } else { + status = graph.Resolve(ctx.resolve_options); + } + + if (!status.IsOK()) { + model = nullptr; + + if (ctx.expect_result == ExpectResult::kExpectFailure) { + ASSERT_THAT(status.ErrorMessage(), testing::HasSubstr(ctx.expected_failure_string)); + } else { + ASSERT_TRUE(status.IsOK()) << "Resolve failed with status: " << status.ErrorMessage(); + } + } +} + +} // namespace test +} // namespace onnxruntime diff --git a/onnxruntime/test/providers/op_tester.h b/onnxruntime/test/providers/op_tester.h new file mode 100644 index 0000000000000..f57cc43149e4e --- /dev/null +++ b/onnxruntime/test/providers/op_tester.h @@ -0,0 +1,93 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/graph/constants.h" +#include "test/providers/base_tester.h" + +namespace onnxruntime { +class InferenceSession; +class Node; +struct SessionOptions; + +namespace test { + +// To use OpTester: +// 1. Create one with the op name +// 2. Call AddAttribute with any attributes +// 3. Call AddInput for all the inputs +// 4. Call AddOutput with all expected outputs, +// Or call AddReferenceOutputs to compute reference outputs with the model +// 5. Call Run +// +class OpTester : public BaseTester { + public: + // Default to the first opset that ORT was available (7). + // When operators are updated they need to explicitly add tests for the new opset version. + // This is due to the kernel matching logic. See KernelRegistry::VerifyKernelDef. + // Additionally, -1 is supported and defaults to the latest known opset. + // + // Defaulting to the latest opset version would result in existing operator implementations for non-CPU EPs to + // lose their test coverage until an implementation for the new version is added. + // e.g. there are CPU and GPU implementations for version 1 of an op. both are tested by a single OpTester test. + // opset changes from 1 to 2 and CPU implementation gets added. If 'opset_version' is 2 the kernel matching + // will find and run the CPU v2 implementation, but will not match the GPU v1 implementation. + // OpTester will say it was successful as at least one EP ran, and the GPU implementation of v1 no longer has + // test coverage. + explicit OpTester(std::string_view op, int opset_version = 7, std::string_view domain = onnxruntime::kOnnxDomain, + bool verify_output = true) + : BaseTester{op, opset_version, domain, verify_output}, + op_{op} { + } + + using ExpectResult = BaseTester::ExpectResult; + + // Set whether the NodeArg created by AddInput/AddOutput should include shape information + // for Tensor types. If not added, shape inferencing should resolve. If added, shape inferencing + // should validate. Default is to add. + // Additionally a symbolic dimension will be added if symbolic_dim matches a dimension in the input. + OpTester& AddShapeToTensorData(bool enable = true, int symbolic_dim = -1) { + SetAddShapeToTensorData(enable); + SetAddSymbolicDimToTensorData(symbolic_dim); + return *this; + } + + void AddAttributeProto(ONNX_NAMESPACE::AttributeProto attr) { + add_attribute_funcs_.emplace_back([attr = std::move(attr)](onnxruntime::Node& node) { + node.AddAttributeProto(attr); + }); + } + + template + void AddAttribute(std::string name, T value) { + // Generate a the proper AddAttribute call for later + add_attribute_funcs_.emplace_back([name = std::move(name), value = std::move(value)](onnxruntime::Node& node) { + node.AddAttribute(name, value); + }); + } + + virtual void AddNodes(onnxruntime::Graph& graph, + std::vector& graph_input_defs, + std::vector& graph_output_defs, + std::vector>& add_attribute_funcs); + + onnxruntime::Model& BuildModel(const std::unordered_map& extra_domain_to_version = {}, + const ModelOptions& model_options = {}); + + protected: + const std::string& Op() const noexcept { + return op_; + } + + private: + // create model for testing + void CreateModelToTest(const ModelOptions& model_options, Model*& model) override; + + std::string op_; + std::vector> add_attribute_funcs_; + std::unique_ptr model_; +}; + +} // namespace test +} // namespace onnxruntime diff --git a/onnxruntime/test/providers/provider_test_utils.cc b/onnxruntime/test/providers/provider_test_utils.cc deleted file mode 100644 index 6396355642090..0000000000000 --- a/onnxruntime/test/providers/provider_test_utils.cc +++ /dev/null @@ -1,1482 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include - -#include "core/common/logging/logging.h" -#include "core/common/logging/sinks/clog_sink.h" -#include "core/framework/tensorprotoutils.h" -#include "core/framework/data_types_internal.h" -#include "core/session/inference_session.h" -#include "core/session/onnxruntime_session_options_config_keys.h" -#include "core/graph/model_load_utils.h" -#include "gmock/gmock.h" -#include "test/providers/provider_test_utils.h" -#include "test/providers/run_options_config_keys.h" -#include "test/util/include/default_providers.h" -#include "test/framework/test_utils.h" -#include -#include -#include - -#ifdef ENABLE_TRAINING -#include "orttraining/core/session/training_session.h" -#endif - -using namespace ::onnxruntime::logging; - -namespace onnxruntime { -namespace test { - -template -Tensor copy_sort(const Tensor& src, const AllocatorPtr& allocator) { - Tensor result(src.DataType(), src.Shape(), allocator); - memcpy(result.MutableDataRaw(), src.DataRaw(), src.SizeInBytes()); - auto dst_span = gsl::make_span(result.MutableData(), result.MutableData() + result.Shape().Size()); - std::sort(dst_span.begin(), dst_span.end()); - return result; -} - -// Check functions for tensor types -template -void sort_expected_and_actual_buffers(const Tensor& expected, Tensor& expected_sorted, - const Tensor& actual, Tensor& actual_sorted) { - auto allocator = TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault); - expected_sorted = copy_sort(expected, allocator); - actual_sorted = copy_sort(actual, allocator); -} - -// Check functions for tensor types -template -void sort_expected_and_actual_buffers(std::vector& expected, - std::vector& actual) { - ORT_ENFORCE(expected.size() == actual.size(), - "The 2 containers contain different number of elements"); - std::sort(expected.begin(), expected.end()); - std::sort(actual.begin(), actual.end()); -} - -// The default implementation compares for equality, specialized versions for -// other types are below -template -struct TensorCheck { - void operator()(const Tensor& expected_tensor, const Tensor& output_tensor, - const std::string& provider_type, const CheckParams& params) const { - Tensor expected_sorted, output_sorted; - const T* expected; - const T* output; - const auto size = output_tensor.Shape().Size(); - if (params.sort_output_) { - // if order can be jumbled in the output of an operator, sort both the - // expected and output buffers prior to - // comparison this is a "best-effort" algo and should satisfy the - // requirement for the few ops that do require this - // support without investing in a more sophisticated infrastructure for the - // same - sort_expected_and_actual_buffers(expected_tensor, expected_sorted, output_tensor, output_sorted); - expected = expected_sorted.Data(); - output = output_sorted.Data(); - } else { - expected = expected_tensor.Data(); - output = output_tensor.Data(); - } - - for (int i = 0; i < size; ++i) { - EXPECT_EQ(expected[i], output[i]) << "i:" << i - << ", provider_type: " << provider_type; - } - } -}; - -template <> -struct TensorCheck { - void operator()(const Tensor& expected_tensor, - const Tensor& output_tensor, - const std::string& provider_type, const CheckParams& params) const { - const bool has_abs_err = params.absolute_error_.has_value(); - const bool has_rel_err = params.relative_error_.has_value(); - - Tensor expected_sorted, output_sorted; - const uint8_t* expected; - const uint8_t* output; - const auto size = output_tensor.Shape().Size(); - if (params.sort_output_) { - // if order can be jumbled in the output of an operator, sort both the - // expected and output buffers prior to - // comparison this is a "best-effort" algo and should satisfy the - // requirement for the few ops that do require this - // support without investing in a more sophisticated infrastructure for the - // same - sort_expected_and_actual_buffers(expected_tensor, expected_sorted, output_tensor, output_sorted); - expected = expected_sorted.Data(); - output = output_sorted.Data(); - } else { - expected = expected_tensor.Data(); - output = output_tensor.Data(); - } - - // For uint8_t results, we only allow NNAPI/XNNPACK EP to have an error tolerance, see below for the reason - // XNNPACK EP will always round to larger. For example, 0.1 will be rounded to 1.0 - // For any other EPs, we still expect an exact match for the results - // TODO: Verify if DML can possibly have a ROUNDING_MODE parameter and conform to the other EPs #41968513 - if ((provider_type == kNnapiExecutionProvider || provider_type == kDmlExecutionProvider || - provider_type == kXnnpackExecutionProvider) && - (has_abs_err || has_rel_err)) { - double threshold = has_abs_err - ? *(params.absolute_error_) - : 0.0; - - for (int i = 0; i < size; ++i) { - if (has_rel_err) { - EXPECT_NEAR(expected[i], output[i], - *(params.relative_error_) * expected[i]) // expected[i] is unsigned, can't be negative - << "i:" << i << ", provider_type: " << provider_type; - } else { // has_abs_err - EXPECT_NEAR(expected[i], output[i], threshold) - << "i:" << i << ", provider_type: " << provider_type; - } - } - } else { - for (int i = 0; i < size; ++i) { - EXPECT_EQ(expected[i], output[i]) << "i:" << i - << ", provider_type: " << provider_type; - } - } - } -}; - -template <> -struct TensorCheck { - void operator()(const Tensor& expected_tensor, - const Tensor& output_tensor, - const std::string& provider_type, const CheckParams& params) const { - Tensor expected_sorted, output_sorted; - const int8_t* expected; - const int8_t* output; - const auto size = output_tensor.Shape().Size(); - if (params.sort_output_) { - // if order can be jumbled in the output of an operator, sort both the - // expected and output buffers prior to - // comparison this is a "best-effort" algo and should satisfy the - // requirement for the few ops that do require this - // support without investing in a more sophisticated infrastructure for the - // same - sort_expected_and_actual_buffers(expected_tensor, expected_sorted, output_tensor, output_sorted); - expected = expected_sorted.Data(); - output = output_sorted.Data(); - } else { - expected = expected_tensor.template Data(); - output = output_tensor.template Data(); - } - - const bool has_abs_err = params.absolute_error_.has_value(); - if (has_abs_err) { - double threshold = *(params.absolute_error_); - - for (int i = 0; i < size; ++i) { - EXPECT_NEAR(expected[i], output[i], threshold) - << "i:" << i << ", provider_type: " << provider_type; - } - } else { - for (int i = 0; i < size; ++i) { - EXPECT_EQ(expected[i], output[i]) - << "i:" << i << ", provider_type: " << provider_type; - } - } - } -}; - -template <> -struct TensorCheck { - void operator()(const Tensor& expected_tensor, - const Tensor& output_tensor, - const std::string& provider_type, - const CheckParams& params) const { - auto size = output_tensor.Shape().Size(); - - bool has_abs_err = params.absolute_error_.has_value(); - bool has_rel_err = params.relative_error_.has_value(); - - // deal with rare cases in which order of output data from a kernel MAY be - // undefined - Tensor expected_sorted, output_sorted; - const double* expected; - const double* output; - if (params.sort_output_) { - sort_expected_and_actual_buffers(expected_tensor, expected_sorted, output_tensor, output_sorted); - expected = expected_sorted.Data(); - output = output_sorted.Data(); - } else { - expected = expected_tensor.Data(); - output = output_tensor.Data(); - } - - double threshold = 0.001; -#if defined(USE_CUDA) || defined(USE_ROCM) || defined(USE_DML) - threshold = 0.005; -#endif - - for (int i = 0; i < size; ++i) { - // NOTE: Check isnan first to work around MSVC linker bug when /LTCG:incremental is specified. - // If the isinf check is first the isnan check and branch gets omitted - if (std::isnan(expected[i])) { - ASSERT_TRUE(std::isnan(output[i])) << "Expected NaN. i:" << i << ", provider_type: " << provider_type; - } else if (std::isinf(expected[i])) { // Test infinity for equality - ASSERT_EQ(expected[i], output[i]) << "Expected infinity. i:" << i << ", provider_type: " << provider_type; - } else { - if (!has_abs_err && !has_rel_err) { - // the default for existing tests - ASSERT_NEAR(expected[i], output[i], threshold) - << "i:" << i << ", provider_type: " << provider_type; - } else { - if (has_abs_err) { - ASSERT_NEAR(expected[i], output[i], - *(params.absolute_error_)) - << "i:" << i << ", provider_type: " << provider_type; - } - if (has_rel_err) { - ASSERT_NEAR(expected[i], output[i], - *(params.relative_error_) * - std::abs(expected[i])) - << "i:" << i << ", provider_type: " << provider_type; - } - } - } - } - } -}; - -template -void InternalNumericalCheck(const Tensor& expected_tensor, - const Tensor& output_tensor, - const std::string& provider_type, - const CheckParams& params) { - const bool has_abs_err = params.absolute_error_.has_value(); - const bool has_rel_err = params.relative_error_.has_value(); - - // deal with rare cases in which order of output data from a kernel MAY be - // undefined - Tensor expected_sorted, output_sorted; - const TypeToCheck* expected; - const TypeToCheck* output; - auto size = output_tensor.Shape().Size(); - if (params.sort_output_) { - sort_expected_and_actual_buffers(expected_tensor, expected_sorted, output_tensor, output_sorted); - expected = expected_sorted.Data(); - output = output_sorted.Data(); - } else { - expected = expected_tensor.Data(); - output = output_tensor.Data(); - } - -#if defined(USE_CUDA) || defined(USE_ROCM) || defined(USE_DML) - constexpr float threshold = 0.005f; -#else - constexpr float threshold = 0.0001f; -#endif - - for (int i = 0; i < size; ++i) { - // NOTE: Check isnan first to work around MSVC linker bug when /LTCG:incremental is specified. - // If the isinf check is first the isnan check and branch gets omitted - if (std::isnan(expected[i])) { - ASSERT_TRUE(std::isnan(output[i])) << "Expected NaN. i:" << i << ", provider_type: " << provider_type; - } else if (std::isinf(expected[i])) { // Test infinity for equality - ASSERT_EQ(expected[i], output[i]) << "Expected infinity. i:" << i << ", provider_type: " << provider_type; - } else { - if (!has_abs_err && !has_rel_err) { - // the default for existing tests - ASSERT_NEAR(expected[i], output[i], threshold) - << "i:" << i << ", provider_type: " << provider_type; - } else { - if (has_abs_err) { - ASSERT_NEAR(expected[i], output[i], - *(params.absolute_error_)) - << "i:" << i << ", provider_type: " << provider_type; - } - if (has_rel_err) { - ASSERT_NEAR(expected[i], output[i], - *(params.relative_error_) * - std::abs(expected[i])) - << "i:" << i << ", provider_type: " << provider_type; - } - } - } - } -} - -template <> -struct TensorCheck { - void operator()(const Tensor& expected_tensor, - const Tensor& output_tensor, - const std::string& provider_type, - const CheckParams& params) const { - InternalNumericalCheck(expected_tensor, output_tensor, provider_type, params); - } -}; - -template <> -struct TensorCheck { - void operator()(const Tensor& expected_tensor, - const Tensor& output_tensor, - const std::string& provider_type, - const CheckParams& params) const { - auto* expected = expected_tensor.Data(); - auto* output = output_tensor.Data(); - auto size = output_tensor.Shape().Size(); - - std::vector f_expected(size); - std::vector f_output(size); - ConvertMLFloat16ToFloat(expected, f_expected.data(), static_cast(size)); - ConvertMLFloat16ToFloat(output, f_output.data(), static_cast(size)); - - // deal with rare cases in which order of output data from a kernel MAY be - // undefined - if (params.sort_output_) { - sort_expected_and_actual_buffers(f_expected, f_output); - } - - const bool has_abs_err = params.absolute_error_.has_value(); - const bool has_rel_err = params.relative_error_.has_value(); - - float threshold = 0.001f; -#if defined(USE_TENSORRT) || defined(ENABLE_TRAINING_CORE) || defined(USE_CUDA) || defined(USE_ROCM) - threshold = 0.005f; -#elif defined(USE_DML) - threshold = 0.008f; -#endif - for (int i = 0; i < size; ++i) { - if (std::isnan(f_expected[i])) { - EXPECT_TRUE(std::isnan(f_expected[i])) << "Expected NaN. i:" << i << ", provider_type: " << provider_type; - } else if (std::isinf(f_expected[i])) { // Test infinity for equality - EXPECT_EQ(f_expected[i], f_output[i]) << "Expected infinity. i:" << i << ", provider_type: " << provider_type; - } else { - if (!has_abs_err && !has_rel_err) { - // the default for existing tests - EXPECT_NEAR(f_expected[i], f_output[i], threshold) - << "i:" << i << ", provider_type: " << provider_type; - } else { - if (has_abs_err) { - EXPECT_NEAR(f_expected[i], f_output[i], - *(params.absolute_error_)) - << "i:" << i << ", provider_type: " << provider_type; - } - if (has_rel_err) { - EXPECT_NEAR(f_expected[i], f_output[i], - *(params.relative_error_) * - std::abs(expected[i])) - << "i:" << i << ", provider_type: " << provider_type; - } - } - } - } - } -}; - -template <> -struct TensorCheck { - void operator()(const Tensor& expected_tensor, - const Tensor& output_tensor, - const std::string& provider_type, - const CheckParams& params) const { - auto* expected = expected_tensor.Data(); - auto* output = output_tensor.Data(); - auto size = output_tensor.Shape().Size(); - - std::vector f_expected(size); - std::vector f_output(size); - BFloat16ToFloat(expected, f_expected.data(), static_cast(size)); - BFloat16ToFloat(output, f_output.data(), static_cast(size)); - - // deal with rare cases in which order of output data from a kernel MAY be - // undefined - if (params.sort_output_) { - sort_expected_and_actual_buffers(f_expected, f_output); - } - - /// XXX: May need to adjust threshold as BFloat is coarse - float abs_threshold = 0.0001f; - float threshold = 0.001f; -#if defined(USE_TENSORRT) || defined(ENABLE_TRAINING_CORE) || defined(USE_CUDA) || defined(USE_ROCM) || defined(USE_DML) || defined(USE_DNNL) - threshold = 0.05f; // expect at least 95% close -#endif - - for (int i = 0; i < size; ++i) { - if (std::isnan(f_expected[i])) { - EXPECT_TRUE(std::isnan(f_expected[i])) << "Expected NaN. i:" << i << ", provider_type: " << provider_type; - } else if (std::isinf(f_expected[i])) { // Test infinity for equality - EXPECT_EQ(f_expected[i], f_output[i]) << "Expected infinity. i:" << i << ", provider_type: " << provider_type; - } else { - // the default for existing tests - const float max_value = fmax(fabs(f_expected[i]), fabs(f_output[i])); - if (max_value != 0) { // max_value = 0 means output and expected are 0s. - const float abs_error = fabs(f_expected[i] - f_output[i]); - if (abs_error <= abs_threshold) { - // if the absolute error is small enough, then no need to calculate realative error - EXPECT_NEAR(0, abs_error, abs_threshold) << "provider_type: " - << provider_type; - } else { - // default for existing tests. - const float rel_error = abs_error / max_value; - EXPECT_NEAR(0, rel_error, threshold) << "provider_type: " - << provider_type; - } - } - } - } - } -}; - -void Check(const OpTester::Data& expected_data, const Tensor& output_tensor, - const std::string& provider_type) { - ORT_ENFORCE(expected_data.data_.Get().Shape() == - output_tensor.Shape(), - "Expected output shape [" + - expected_data.data_.Get().Shape().ToString() + - "] did not match run output shape [" + - output_tensor.Shape().ToString() + "] for " + - expected_data.def_.Name()); - - utils::MLTypeCallDispatcher - t_disp(output_tensor.GetElementType()); - - t_disp.Invoke(expected_data.data_.Get(), output_tensor, provider_type, MakeCheckParams(expected_data)); -} - -// Check for non tensor types - -template -void Check(const OpTester::Data& expected_data, const T& run_output, - const std::string& provider_type) { - EXPECT_EQ(expected_data.data_.Get(), run_output) << "provider_type: " - << provider_type; -} - -template <> -void Check(const OpTester::Data& expected_data, - const TensorSeq& output_seq, - const std::string& provider_type) { - const auto& exp_seq = expected_data.data_.Get(); - - // first ensure data types match - EXPECT_EQ(exp_seq.DataType(), output_seq.DataType()) - << "Data types don't match: Expected: " - << DataTypeImpl::ToString(exp_seq.DataType()) - << " Output: " << output_seq.DataType() - << " provider_type: " << provider_type; - - // check num of contained tensors - size_t expected_num_tensors = exp_seq.Size(); - size_t output_num_tensors = output_seq.Size(); - EXPECT_EQ(expected_num_tensors, output_num_tensors) - << "Mismatch in number of tensors in the sequence" - << " Expected: " << expected_num_tensors - << " Output: " << output_num_tensors - << " provider_type: " << provider_type; - - // now check the contents of the tensors - CheckParams check_params = MakeCheckParams(expected_data); - - auto element_type = exp_seq.DataType()->AsPrimitiveDataType()->GetDataType(); - utils::MLTypeCallDispatcher - t_disp(element_type); - - for (size_t i = 0; i < output_num_tensors; ++i) { - t_disp.Invoke(exp_seq.Get(i), output_seq.Get(i), provider_type, check_params); - } -} - -template -void CheckDispatch(MLDataType type, const OpTester::Data& expected_data, - OrtValue& ort_value, const std::string& provider_type) { - if (type == DataTypeImpl::GetType()) - Check(expected_data, ort_value.Get(), provider_type); - else - ORT_THROW("OpTester:Check() not implemented for output tensor type of ", - type); -} - -template -void CheckDispatch(MLDataType type, const OpTester::Data& expected_data, - OrtValue& ort_value, const std::string& provider_type) { - if (type == DataTypeImpl::GetType()) - Check(expected_data, ort_value.Get(), provider_type); - else - CheckDispatch(type, expected_data, ort_value, - provider_type); -} - -void Check(const OpTester::Data& expected_data, OrtValue& ort_value, - const std::string& provider_type) { - CheckDispatch< -#if !defined(DISABLE_ML_OPS) - VectorMapStringToFloat, VectorMapInt64ToFloat, -#endif - TensorSeq>( - expected_data.data_.Type(), expected_data, ort_value, provider_type); -} - -void DebugTrap() { -#if _MSC_VER - __debugbreak(); -#else - raise(SIGTRAP); -#endif -} - -OpTester::~OpTester() { -#ifndef NDEBUG - if (!run_called_) { - std::cerr << "Someone forgot to call OpTester::Run()" << std::endl; - DebugTrap(); - } -#endif -} - -void OpTester::FillFeedsAndOutputNames( - std::unordered_map& feeds, - std::vector& output_names) { - for (auto& output : output_data_) { - if (output.def_.Exists()) - output_names.push_back(output.def_.Name()); - } - - FillFeeds(feeds); -} - -void OpTester::FillFeeds(std::unordered_map& feeds) { - for (size_t i = 0; i < input_data_.size(); ++i) { - if (std::find(initializer_index_.begin(), initializer_index_.end(), i) == - initializer_index_.end() && - input_data_[i].def_.Exists() && - // We don't include optional type OrtValues of None because this is - // how we expect users to deal with sending through "None"s as graph inputs - // (i.e.) don't send them through at all - input_data_[i].data_.IsAllocated()) { - feeds[input_data_[i].def_.Name()] = input_data_[i].data_; - } - } -} - -void OpTester::SetOutputAbsErr(const char* name, float v) { - auto it = - std::find_if(output_data_.begin(), output_data_.end(), - [name](Data& data) { return (data.def_.Name() == name); }); - ORT_ENFORCE(it != output_data_.end()); - it->absolute_error_ = optional(v); -} - -void OpTester::SetOutputRelErr(const char* name, float v) { - auto it = - std::find_if(output_data_.begin(), output_data_.end(), - [name](Data& data) { return (data.def_.Name() == name); }); - ORT_ENFORCE(it != output_data_.end()); - it->relative_error_ = optional(v); -} - -void OpTester::AddNodes( - onnxruntime::Graph& graph, - std::vector& graph_input_defs, - std::vector& graph_output_defs, - std::vector>& add_attribute_funcs) { - // default behavior is to create a single Node for the op being tested, with - // node inputs/outputs - // being 1:1 with graph inputs/outputs. - auto& node = graph.AddNode("node1", op_, op_, graph_input_defs, - graph_output_defs, nullptr, domain_); - - // Add the attributes if any - for (auto& add_attribute_fn : add_attribute_funcs) - add_attribute_fn(node); -} - -std::vector OpTester::GetDimsForProto(gsl::span dims) { - std::vector dims_for_proto{dims.begin(), dims.end()}; - if (add_symbolic_dim_to_tensor_data_ >= 0 && - dims.size() > static_cast(add_symbolic_dim_to_tensor_data_)) { - dims_for_proto[add_symbolic_dim_to_tensor_data_] = -1; - } - return dims_for_proto; -} - -void OpTester::AddShapeToTensorData(NodeArg& node_arg, gsl::span dims, - const std::vector* dim_params) { - if (dim_params && !(dim_params->empty()) && add_shape_to_tensor_data_) { - // If dim_params presents, configure node_arg's dim value based on dim_params, which supports symbolic dim and dim broadcast. - const auto& dim_params_data = *dim_params; - onnx::TensorShapeProto new_shape; - - // currently hard-code the reserved symbolic names. - // TODO: when the list grows longer, consider move it to a better place. - const static std::unordered_set reserved_symbolic{"batch", "seq"}; - - for (size_t i = 0; i < dim_params_data.size(); ++i) { - if (reserved_symbolic.find(dim_params_data[i]) != reserved_symbolic.end()) { - new_shape.add_dim()->set_dim_param(dim_params_data[i]); - } else { - ASSERT_TRUE(std::stoi(dim_params_data[i]) == dims[i]); - new_shape.add_dim()->set_dim_value(dims[i]); - } - } - node_arg.SetShape(new_shape); - } -} - -#if !defined(DISABLE_SPARSE_TENSORS) -static std::unique_ptr MakeSparseTensor(MLDataType data_type, const gsl::span& dims) { - TensorShape shape{dims}; - auto allocator = test::AllocatorManager::Instance().GetAllocator(CPU); - auto p_tensor = std::make_unique(data_type, shape, std::move(allocator)); - return p_tensor; -} - -void OpTester::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()); -} - -NodeArg OpTester::MakeSparseNodeArg(int32_t dtype, const char* name, - const gsl::span& dims, const std::vector* dim_params) { - std::vector dims_for_proto = GetDimsForProto(dims); - TSparseTensorProto type_proto(dtype, add_shape_to_tensor_data_ ? &dims_for_proto : nullptr); - NodeArg node_arg(name, &type_proto.proto); - AddShapeToTensorData(node_arg, dims, dim_params); - return node_arg; -} - -void OpTester::AddSparseTensorData(std::vector& data, NodeArg node_arg, - std::unique_ptr p_tensor, - const CheckParams& check_params) { - OrtValue value; - auto ml_type = DataTypeImpl::GetType(); - value.Init(p_tensor.release(), ml_type, ml_type->GetDeleteFunc()); - data.push_back(Data(std::move(node_arg), std::move(value), - optional(check_params.relative_error_), optional(check_params.absolute_error_), - check_params.sort_output_)); -} - -void OpTester::AddSparseCooTensorData(std::vector& data, - MLDataType data_type, - const char* name, - gsl::span dims, - gsl::span values, - gsl::span indices, - const CheckParams& check_params, - const std::vector* dim_params) { - const auto elem_size = data_type->Size(); - const auto dtype = data_type->AsPrimitiveDataType()->GetDataType(); - const auto nnz = values.size_bytes() / elem_size; - ORT_ENFORCE(dims.size() == 2U, "Expecting a 2-D dense shape"); - ORT_ENFORCE((nnz == indices.size() || 2 * nnz == indices.size()), "Expecting indices to have either nnz or (2 * nnz) length"); - auto p_tensor = MakeSparseTensor(data_type, dims); - auto mutator = p_tensor->MakeCooData(nnz, indices.size()); - CopyDataToTensor(values, mutator.Values()); - CopyDataToTensor(gsl::as_bytes(indices), mutator.Indices()); - - NodeArg node_arg = MakeSparseNodeArg(dtype, name, dims, dim_params); - AddSparseTensorData(data, std::move(node_arg), std::move(p_tensor), check_params); -} - -void OpTester::AddSparseCooTensorStrings(std::vector& data, - const char* name, - gsl::span dims, - gsl::span values, - gsl::span indices, - const std::vector* dim_params) { - auto data_type = DataTypeImpl::GetType(); - const auto nnz = values.size(); - const auto dtype = data_type->AsPrimitiveDataType()->GetDataType(); - ORT_ENFORCE(dims.size() == 2U, "Expecting a 2-D dense shape"); - ORT_ENFORCE((nnz == indices.size() || 2 * nnz == indices.size()), "Expecting indices to have either nnz or (2 * nnz) length"); - auto p_tensor = MakeSparseTensor(data_type, dims); - // linear index is 1-D index, otherwise 2-D index - auto mutator = p_tensor->MakeCooData(nnz, indices.size()); - auto mutable_values = mutator.Values().MutableDataAsSpan(); - ORT_ENFORCE(values.size() == mutable_values.size(), "Must allocate space for values"); - std::copy(values.begin(), values.end(), mutable_values.begin()); - CopyDataToTensor(gsl::as_bytes(indices), mutator.Indices()); - NodeArg node_arg = MakeSparseNodeArg(dtype, name, dims, dim_params); - AddSparseTensorData(data, std::move(node_arg), std::move(p_tensor), CheckParams()); -} - -void OpTester::AddSparseCsrTensorData(std::vector& data, - MLDataType data_type, - const char* name, - gsl::span dims, - gsl::span values, - gsl::span inner_indices, - gsl::span outer_indices, - const CheckParams& check_params, - const std::vector* dim_params) { - const auto elem_size = data_type->Size(); - const auto dtype = data_type->AsPrimitiveDataType()->GetDataType(); - const auto nnz = values.size_bytes() / elem_size; - ORT_ENFORCE(dims.size() == 2U, "Expecting a 2-D dense shape"); - ORT_ENFORCE(nnz == inner_indices.size(), "Expecting the same number of inner_indices as nnz"); - auto p_tensor = MakeSparseTensor(data_type, dims); - - auto mutator = p_tensor->MakeCsrData(nnz, inner_indices.size(), outer_indices.size()); - CopyDataToTensor(values, mutator.Values()); - CopyDataToTensor(gsl::as_bytes(inner_indices), mutator.Inner()); - CopyDataToTensor(gsl::as_bytes(outer_indices), mutator.Outer()); - - NodeArg node_arg = MakeSparseNodeArg(dtype, name, dims, dim_params); - AddSparseTensorData(data, std::move(node_arg), std::move(p_tensor), check_params); -} - -void OpTester::AddSparseCsrTensorStrings(std::vector& data, - const char* name, - gsl::span dims, - gsl::span values, - gsl::span inner_indices, - gsl::span outer_indices, - const std::vector* dim_params) { - auto data_type = DataTypeImpl::GetType(); - const auto nnz = values.size(); - const auto dtype = data_type->AsPrimitiveDataType()->GetDataType(); - - ORT_ENFORCE(dims.size() == 2U, "Expecting a 2-D dense shape"); - ORT_ENFORCE(nnz == inner_indices.size(), "Expecting the same number of inner_indices as nnz"); - auto p_tensor = MakeSparseTensor(data_type, dims); - - auto mutator = p_tensor->MakeCsrData(nnz, inner_indices.size(), outer_indices.size()); - auto mutable_values = mutator.Values().MutableDataAsSpan(); - ORT_ENFORCE(values.size() == mutable_values.size(), "Must allocate space for values"); - std::copy(values.begin(), values.end(), mutable_values.begin()); - CopyDataToTensor(gsl::as_bytes(inner_indices), mutator.Inner()); - CopyDataToTensor(gsl::as_bytes(outer_indices), mutator.Outer()); - NodeArg node_arg = MakeSparseNodeArg(dtype, name, dims, dim_params); - AddSparseTensorData(data, std::move(node_arg), std::move(p_tensor), CheckParams()); -} -#endif // !defined(DISABLE_SPARSE_TENSORS) - -void OpTester::AddInitializers(onnxruntime::Graph& graph) { - for (auto index : initializer_index_) { - auto& data = input_data_[index]; - auto& tensor = data.data_.Get(); - ONNX_NAMESPACE::TensorProto tensor_proto; - // 1. set dimension - auto& shape = tensor.Shape(); - for (auto& dim : shape.GetDims()) { - tensor_proto.add_dims(dim); - } - // 2. set type - tensor_proto.set_data_type( - data.def_.TypeAsProto()->tensor_type().elem_type()); - // 3. data - if (data.def_.TypeAsProto()->tensor_type().elem_type() == - ONNX_NAMESPACE::TensorProto_DataType_STRING) { - const std::string* string_data = tensor.Data(); - for (auto i = 0; i < shape.Size(); i++) { - tensor_proto.add_string_data(string_data[i]); - } - } else { - auto buffer_size = tensor.DataType()->Size() * shape.Size(); - tensor_proto.set_raw_data(tensor.DataRaw(), buffer_size); - } - // 4. name - tensor_proto.set_name(data.def_.Name()); - graph.AddInitializedTensor(tensor_proto); - } -} - -std::unique_ptr OpTester::BuildGraph( - const std::unordered_map& extra_domain_to_version, - const ModelOptions& model_options) { - // Generate the input & output def lists - std::vector node_input_defs; - std::vector output_defs; - - for (size_t i = 0; i < input_data_.size(); ++i) { - node_input_defs.push_back(&input_data_[i].def_); - } - - for (auto& data : output_data_) { - output_defs.push_back(&data.def_); - } - - // Create a simple model - std::unordered_map domain_to_version(extra_domain_to_version); - if (domain_to_version.count(domain_) == 0) { - domain_to_version.insert({domain_, opset_version_}); - } else { - auto key_val = extra_domain_to_version.find(domain_); - - ORT_ENFORCE(key_val->second <= opset_version_); - - if (key_val->second < opset_version_) { - domain_to_version[domain_] = opset_version_; - } - } - - auto p_model = std::make_unique( - "test", false, ModelMetaData(), PathString(), custom_schema_registries_, - domain_to_version, std::vector{}, - DefaultLoggingManager().DefaultLogger(), - model_options); - onnxruntime::Graph& graph = p_model->MainGraph(); - AddNodes(graph, node_input_defs, output_defs, add_attribute_funcs_); - - // Add Initializer - AddInitializers(graph); - return p_model; -} - -template -std::vector OpTester::ExecuteModel( - Model& model, SessionType& session_object, ExpectResult expect_result, - const std::string& expected_failure_string, const RunOptions* run_options, - const std::unordered_map& feeds, - const std::vector& output_names, - const std::string& provider_type, bool allow_released_onnx_opset_only) { - std::string s1; - const bool rc = model.ToProto().SerializeToString(&s1); - if (!rc) { - LOGS_DEFAULT(ERROR) << "Failed to serialize proto to string"; - return {}; - } - std::stringstream sstr(s1); - auto status = session_object.Load(sstr, allow_released_onnx_opset_only); - EXPECT_TRUE(status.IsOK()) << status.ErrorMessage(); - if (!status.IsOK()) { - LOGS_DEFAULT(ERROR) << "Load failed with status: " << status.ErrorMessage(); - return {}; - } - - status = session_object.Initialize(); - - if (!status.IsOK()) { - if (expect_result == ExpectResult::kExpectFailure) { - EXPECT_TRUE(!status.IsOK()); - // Disable expected_failure_string checks for OpenVINO EP - if (provider_type != kOpenVINOExecutionProvider) { - EXPECT_THAT(status.ErrorMessage(), - testing::HasSubstr(expected_failure_string)); - } - } else { - LOGS_DEFAULT(ERROR) << "Initialize failed with status: " - << status.ErrorMessage(); - EXPECT_TRUE(status.IsOK()) << status.ErrorMessage(); - } - } - - if (!status.IsOK()) { - return {}; - } - - RunOptions default_run_options{}; - default_run_options.run_tag = op_; - default_run_options.run_log_verbosity_level = 1; - - std::vector fetches; - for (int i = 0; i < num_run_calls_; ++i) { - fetches.clear(); - status = - session_object.Run(run_options ? *run_options : default_run_options, - feeds, output_names, &fetches); - - if (status.IsOK()) { - EXPECT_TRUE(expect_result == ExpectResult::kExpectSuccess) - << "Expected failure but Run was successful"; - if (expect_result == ExpectResult::kExpectFailure) { - return {}; - } - } else { - if (expect_result == ExpectResult::kExpectFailure) { - // Disable expected_failure_string checks for MKL-DNN and OpenVINO EP's - if (provider_type != kDnnlExecutionProvider && - provider_type != kOpenVINOExecutionProvider) { - EXPECT_THAT(status.ErrorMessage(), - testing::HasSubstr(expected_failure_string)); - } - } else { - LOGS_DEFAULT(ERROR) << "Run failed with status: " - << status.ErrorMessage(); - EXPECT_TRUE(status.IsOK()) << status.ErrorMessage(); - } - return {}; - } - } - - // Verify the outputs - // Todo: support check output with map/sequence/.... - if (verify_output_) { - if (custom_output_verifier_) { - // do custom verification if provided - custom_output_verifier_(fetches, provider_type); - } else { - // default verification - size_t idx = 0; - for (auto& expected_data : output_data_) { - OrtValue& ort_value = fetches[idx]; - - if (expected_data.def_.Exists()) { // optional edges won't exist (so skip them) - if (!expected_data.data_.IsAllocated()) { // optional type output (None) - EXPECT_TRUE(!ort_value.IsAllocated()) - << "Expected to see an output of None " - << "but instead got an output that wasn't None"; - - // Make sure types align - EXPECT_EQ(expected_data.data_.Type(), ort_value.Type()) - << "Expected optional type: " << expected_data.data_.Type() - << " but instead got optional type: " << ort_value.Type(); - } - - else if (expected_data.data_.IsTensor()) { - // verify output shape inference when input defs have shape - if (add_shape_to_tensor_data_) { - auto out_shape_proto = expected_data.def_.Shape(); - EXPECT_TRUE(out_shape_proto != nullptr); - const auto tensor_shape = - utils::GetTensorShapeFromTensorShapeProto(*out_shape_proto); - const auto inferred_dims = tensor_shape.GetDims(); - const auto& expected_shape = - expected_data.data_.Get().Shape(); - EXPECT_TRUE(inferred_dims.size() == - expected_shape.NumDimensions()); - for (size_t d = 0; d < inferred_dims.size(); ++d) { - // check equal unless the input involved a symbolic dimension - if (inferred_dims[d] != -1) { - EXPECT_EQ(expected_shape[d], inferred_dims[d]) - << "Output idx = " << idx << " dim = " << d; - } - } - } - - Check(expected_data, ort_value.Get(), provider_type); - } else { - Check(expected_data, ort_value, provider_type); - } - - ++idx; - - // skip missing trailing optional outputs - if (idx == fetches.size()) - break; - } - } - } - } - - return fetches; -} - -bool SetEpsForAllNodes( - Graph& graph, - const std::vector>& execution_providers, - const std::vector>* custom_registries) { - const OpSchemaKernelTypeStrResolver kernel_type_str_resolver{}; - for (auto& node : graph.Nodes()) { - if (node.OpType() == kConstant) - continue; - - bool found = false; - - for (const auto& ep : execution_providers) { - auto provider_type = ep->Type(); - - node.SetExecutionProviderType(provider_type); - if (provider_type == onnxruntime::kOpenVINOExecutionProvider || - provider_type == onnxruntime::kTensorrtExecutionProvider || - // provider_type == onnxruntime::kTvmExecutionProvider || - provider_type == onnxruntime::kNnapiExecutionProvider || - provider_type == onnxruntime::kCoreMLExecutionProvider || - provider_type == onnxruntime::kDnnlExecutionProvider || - provider_type == onnxruntime::kQnnExecutionProvider || - provider_type == onnxruntime::kSnpeExecutionProvider) { - found = true; - break; - } - - // Check the EP has an impl for the node from builtin registry. - if (KernelRegistry::HasImplementationOf(*ep->GetKernelRegistry(), node, ep->Type(), kernel_type_str_resolver)) { - found = true; - break; - } - - // Check the EP has an impl for the node from custom_registries - if (custom_registries != nullptr && - std::any_of(custom_registries->cbegin(), custom_registries->cend(), - [&](auto reg) { return KernelRegistry::HasImplementationOf( - *reg->GetKernelRegistry(), - node, ep->Type(), - kernel_type_str_resolver); })) { - found = true; - break; - } - } - - // We will reach here: - // - either we could not find an impl in all possible kernel registries - // - or we skip the registry search and blindly assign the node to the EP due to impl details. - if (!found) { - return false; - } - } - - // all nodes have been assigned an EP - return true; -} - -OpTester& OpTester::Config(const SessionOptions& sess_options) { - ctx_.session_options = sess_options; - return *this; -} - -OpTester& OpTester::Config(ExpectResult expect_result, const std::string& expected_failure_string) { - ctx_.expect_result = expect_result; - ctx_.expected_failure_string = expected_failure_string; - return *this; -} - -OpTester& OpTester::ConfigExcludeEps(const std::unordered_set& excluded_provider_types) { - ctx_.excluded_provider_types = excluded_provider_types; - return *this; -} - -OpTester& OpTester::Config(const RunOptions* run_options) { - ctx_.run_options = run_options; - return *this; -} - -OpTester& OpTester::ConfigEps(std::vector>&& execution_providers) { - ORT_ENFORCE(execution_providers.size() > 0); - ctx_.run_with_specified_eps = true; - ctx_.execution_providers = std::move(execution_providers); - return *this; -} - -OpTester& OpTester::Config(const Graph::ResolveOptions& resolve_options) { - ctx_.resolve_options = resolve_options; - return *this; -} - -void OpTester::Run( - ExpectResult expect_result, const std::string& expected_failure_string, - const std::unordered_set& excluded_provider_types, - const RunOptions* run_options, - std::vector>* execution_providers, - ExecutionMode execution_mode, - const Graph::ResolveOptions& options) { - SessionOptions so; - so.use_per_session_threads = false; - so.session_logid = op_; - so.session_log_verbosity_level = 1; - so.execution_mode = execution_mode; - so.use_deterministic_compute = use_determinism_; - so.graph_optimization_level = TransformerLevel::Default; // 'Default' == off - Run(so, expect_result, expected_failure_string, excluded_provider_types, - run_options, execution_providers, options); -} - -#define ASSERT_PROVIDER_STATUS_OK(function) \ - do { \ - Status _tmp_status = function; \ - ASSERT_TRUE(_tmp_status.IsOK()) << "provider: " << provider_type << ", error: " << _tmp_status; \ - } while (false) - -void OpTester::Run( - SessionOptions so, // Take the SessionOptions by value (i.e. make a copy) - // because we may need to modify it - ExpectResult expect_result, const std::string& expected_failure_string, - const std::unordered_set& excluded_provider_types, - const RunOptions* run_options, - std::vector>* execution_providers, - const Graph::ResolveOptions& options, - /*out*/ size_t* number_of_pre_packed_weights_counter, - /*out*/ size_t* number_of_shared_pre_packed_weights_counter) { - if (execution_providers == nullptr) { - ctx_.run_with_specified_eps = false; - ctx_.execution_providers.clear(); - } else { - this->ConfigEps(std::move(*execution_providers)); - // NOTE: some callsites do the following: - // - // std::vector> execution_providers; - // execution_providers.push_back(DefaultCPUExecutionProvider()); - // test.run(..., &execution_providers, ...); - // execution_providers[0] = DefaultCUDAExecutionProvider(); // <-- std::move cause segfault here. - // test.run(..., &execution_providers, ...); - // - // So we need to restore the old vector's size. - execution_providers->resize(ctx_.execution_providers.size()); - } - - (*this) - .Config(so) - .Config(expect_result, expected_failure_string) - .Config(run_options) - .ConfigExcludeEps(excluded_provider_types) - .Config(options) - .RunWithConfig(number_of_pre_packed_weights_counter, number_of_shared_pre_packed_weights_counter); -} - -void OpTester::RunWithConfig(size_t* number_of_pre_packed_weights_counter, - size_t* number_of_shared_pre_packed_weights_counter) { - std::string cur_provider = "not set"; - ORT_TRY { -#ifndef NDEBUG - run_called_ = true; -#endif - - // IsAllowReleasedONNXOpsetsOnlySet() checks for the appropriate env var in the process (i.e.) process-wide - // `IsAllowReleasedONNXOpsetsOnlySetForThisTest()` is for this specific OpTester instance - // We will only support released opsets iff IsAllowReleasedONNXOpsetsOnlySet() and `IsAllowReleasedONNXOpsetsOnlySetForThisTest()` - // are both true - auto allow_released_onnx_opset_only = - IsAllowReleasedONNXOpsetsOnlySetForThisTest() && model_load_utils::IsAllowReleasedONNXOpsetsOnlySet(); - - if (allow_released_onnx_opset_only) { - auto& onnx_released_versions = - ONNX_NAMESPACE::OpSchemaRegistry::DomainToVersionRange::Instance().LastReleaseVersionMap(); - auto it = onnx_released_versions.find(domain_); - if (it != onnx_released_versions.end() && opset_version_ > it->second) { - LOGS_DEFAULT(WARNING) << "Encountered model with opset version greater than released onnx opset version. " - << "Skipping this test. To run this test set environment variable ALLOW_RELEASED_ONNX_OPSET_ONLY to \"0\". " - << "Opset version of current model is " << opset_version_ - << ", the latest released onnx opset version is " << it->second << "."; - GTEST_SKIP(); - } - } - - fetches_.clear(); - bool cache_enabled = cached_model_ != nullptr; - const bool strict_shape_type_inference = ctx_.session_options.config_options.GetConfigOrDefault( - kOrtSessionOptionsConfigStrictShapeTypeInference, "1") == "1"; - const ModelOptions model_options(allow_released_onnx_opset_only, - strict_shape_type_inference); - auto p_model = !cache_enabled ? BuildGraph({}, model_options) : cached_model_; - auto& graph = p_model->MainGraph(); - - Status status = Status::OK(); - if (!cache_enabled) { - if (add_shape_to_tensor_data_ && - ctx_.expect_result == ExpectResult::kExpectFailure) { - // capture possible exceptions from shape inference for invalid testcase - ORT_TRY { - status = graph.Resolve(ctx_.resolve_options); - } - ORT_CATCH(const std::exception& ex) { - ORT_HANDLE_EXCEPTION([&]() { - status = ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, ex.what()); - }); - } - } else { - status = graph.Resolve(ctx_.resolve_options); - } - - if (!status.IsOK()) { - if (ctx_.expect_result == ExpectResult::kExpectFailure) { - EXPECT_TRUE(!status.IsOK()); - EXPECT_THAT(status.ErrorMessage(), - testing::HasSubstr(ctx_.expected_failure_string)); - } else { - LOGS_DEFAULT(ERROR) << "Resolve failed with status: " - << status.ErrorMessage(); - EXPECT_TRUE(status.IsOK()) << status.ErrorMessage(); - } - } - - if (!status.IsOK()) { - return; - } - } - - // Hookup the inputs and outputs - std::unordered_map feeds; - std::vector output_names; - FillFeedsAndOutputNames(feeds, output_names); - - // Run the model - if (ctx_.run_with_specified_eps) { - ExecuteModelForEps( - std::move(ctx_.execution_providers), *p_model, ctx_.session_options, - ctx_.expect_result, ctx_.expected_failure_string, - ctx_.run_options, feeds, output_names, - /*custom_registries=*/nullptr, - /*assign_ep_for_nodes=*/false, - allow_released_onnx_opset_only, - number_of_pre_packed_weights_counter, - number_of_shared_pre_packed_weights_counter); - } else { -#ifdef USE_TENSORRT - // only run trt ep to reduce test time - static const std::string all_provider_types[] = { - kTensorrtExecutionProvider, - }; -#else - static const std::string all_provider_types[] = { - kCpuExecutionProvider, - kCudaExecutionProvider, - kDnnlExecutionProvider, - kTensorrtExecutionProvider, - kOpenVINOExecutionProvider, - kDmlExecutionProvider, - kAclExecutionProvider, - kArmNNExecutionProvider, - kNnapiExecutionProvider, - kRocmExecutionProvider, - kCoreMLExecutionProvider, - kQnnExecutionProvider, - kSnpeExecutionProvider, - kXnnpackExecutionProvider, - }; -#endif - - bool has_run = false; - - for (const std::string& provider_type : all_provider_types) { - if (ctx_.excluded_provider_types.count(provider_type) > 0) - continue; - - cur_provider = provider_type; - - std::unique_ptr execution_provider; - if (provider_type == onnxruntime::kCpuExecutionProvider) - execution_provider = DefaultCpuExecutionProvider(); - else if (provider_type == onnxruntime::kCudaExecutionProvider) - execution_provider = DefaultCudaExecutionProvider(); - else if (provider_type == onnxruntime::kDnnlExecutionProvider) - execution_provider = DefaultDnnlExecutionProvider(); - else if (provider_type == onnxruntime::kOpenVINOExecutionProvider) - execution_provider = DefaultOpenVINOExecutionProvider(); - else if (provider_type == onnxruntime::kTensorrtExecutionProvider) - execution_provider = DefaultTensorrtExecutionProvider(); - else if (provider_type == onnxruntime::kNnapiExecutionProvider) - execution_provider = DefaultNnapiExecutionProvider(); - else if (provider_type == onnxruntime::kRknpuExecutionProvider) - execution_provider = DefaultRknpuExecutionProvider(); - else if (provider_type == onnxruntime::kAclExecutionProvider) - execution_provider = DefaultAclExecutionProvider(); - else if (provider_type == onnxruntime::kArmNNExecutionProvider) - execution_provider = DefaultArmNNExecutionProvider(); - else if (provider_type == onnxruntime::kRocmExecutionProvider) - execution_provider = DefaultRocmExecutionProvider(); - else if (provider_type == onnxruntime::kCoreMLExecutionProvider) - execution_provider = DefaultCoreMLExecutionProvider(); - else if (provider_type == onnxruntime::kSnpeExecutionProvider) - execution_provider = DefaultSnpeExecutionProvider(); - else if (provider_type == onnxruntime::kQnnExecutionProvider) - execution_provider = DefaultQnnExecutionProvider(); - else if (provider_type == onnxruntime::kXnnpackExecutionProvider) - execution_provider = DefaultXnnpackExecutionProvider(); - else if (provider_type == onnxruntime::kDmlExecutionProvider) - execution_provider = DefaultDmlExecutionProvider(); - - // skip if execution provider is disabled - if (execution_provider == nullptr) - continue; - - ExecuteModelForEps( - [&execution_provider]() { - std::vector> ret; - ret.emplace_back(std::move(execution_provider)); - return ret; - }(), - *p_model, ctx_.session_options, - ctx_.expect_result, ctx_.expected_failure_string, - ctx_.run_options, feeds, output_names, - &custom_session_registries_, - /*try_assign_ep_for_nodes=*/true, - allow_released_onnx_opset_only, - number_of_pre_packed_weights_counter, - number_of_shared_pre_packed_weights_counter); - - // Run Models with subscribed run_options->config_options - if (ctx_.run_options != nullptr && - ctx_.run_options->config_options.GetConfigEntry(kOpTesterRunOptionsConfigTestTunableOp) == "true") { - std::vector> execution_providers; - if (provider_type == onnxruntime::kRocmExecutionProvider) { - execution_providers.emplace_back(DefaultRocmExecutionProvider(/*test_tunable_op=*/true)); - } - - if (!execution_providers.empty()) { - ExecuteModelForEps( - std::move(execution_providers), *p_model, ctx_.session_options, - ctx_.expect_result, ctx_.expected_failure_string, - ctx_.run_options, feeds, output_names, - &custom_session_registries_, - /*assign_ep_for_nodes=*/true, - allow_released_onnx_opset_only, - number_of_pre_packed_weights_counter, - number_of_shared_pre_packed_weights_counter); - } - } - - has_run = true; - cur_provider = "not set"; - } - -#ifdef USE_TENSORRT - // We are allowing tests to be run with only TensorRT EP, but TensorRT EP may not support all tests and may be in excluded providers list. - // So, no registered EPs were able to run the model is okay for this situation. - ORT_UNUSED_PARAMETER(has_run); -#else - EXPECT_TRUE(has_run) - << "No registered execution providers were able to run the model."; -#endif - } - } - ORT_CATCH(const std::exception& ex) { - ORT_HANDLE_EXCEPTION([&]() { - std::cerr << ex.what() << "\nProvider:" << cur_provider << "\n"; - }); - // rethrow as some tests for error handling expect this - ORT_RETHROW; - } -} - -void OpTester::ExecuteModelForEps( - std::vector>&& execution_providers, - onnxruntime::Model& model, - SessionOptions sess_options, // session options is copied to avoid the side effect in this function - onnxruntime::test::OpTester::ExpectResult expect_result, - const std::string& expected_failure_string, - const onnxruntime::RunOptions* run_options, - const std::unordered_map& feeds, - const std::vector& output_names, - const std::vector>* custom_registries, - bool try_assign_ep_for_nodes, - bool allow_released_onnx_opset_only, - size_t* number_of_pre_packed_weights_counter, - size_t* number_of_shared_pre_packed_weights_counter) { - for (auto& entry : execution_providers) { - // Be noted, entry in execution providers passed in OpTester will be std::moved in the first OpTester::Run(), - // To make the error more obvious to debug (instead of a segment fault), we do check explicitly here. - ASSERT_TRUE(entry) << "Execution provider entry invalid."; - - if (entry->Type() == kDmlExecutionProvider) { - sess_options.enable_mem_pattern = false; - sess_options.execution_mode = ExecutionMode::ORT_SEQUENTIAL; - break; - } - } - - InferenceSession session_object{sess_options, GetEnvironment()}; - - if (add_prepacked_shared_container_to_sessions_) { - ASSERT_STATUS_OK(session_object.AddPrePackedWeightsContainer(&prepacked_weights_container_)); - } - ASSERT_TRUE(!execution_providers.empty()) << "Empty execution providers vector."; - if (try_assign_ep_for_nodes && !SetEpsForAllNodes(model.MainGraph(), execution_providers, custom_registries)) { - std::string providers; - for (const auto& ep : execution_providers) { - providers.append(ep->Type() + " "); - } - LOGS_DEFAULT(WARNING) << "registered execution providers " << providers << "were unable to run the model."; - return; - } - - std::string provider_type; - for (auto&& ep : execution_providers) { - provider_type += ep->Type() + ":"; - } - provider_type.resize(provider_type.size() - 1); // remove the trailing ':' - - if (custom_registries != nullptr) { - for (const auto& reg : *custom_registries) { - ASSERT_PROVIDER_STATUS_OK(session_object.RegisterCustomRegistry(reg)); - } - } - - for (auto&& entry : execution_providers) { - ASSERT_STATUS_OK(session_object.RegisterExecutionProvider(std::move(entry))); - } - - fetches_ = ExecuteModel( - model, session_object, expect_result, expected_failure_string, - run_options, feeds, output_names, provider_type, allow_released_onnx_opset_only); - - // After the model has initialized (happens in ExecuteModel), - // we should be able to tell how many constant initializers were pre-packed - // and out of these pre-packed ones how many of them used a "cached" version - // from the shared container. - // Populate these value if the user has requested this information. - if (number_of_pre_packed_weights_counter != nullptr) { - *number_of_pre_packed_weights_counter = - session_object.GetSessionState().GetNumberOfPrepacksCounter(); - } - - if (number_of_shared_pre_packed_weights_counter != nullptr) { - *number_of_shared_pre_packed_weights_counter = - session_object.GetSessionState().GetUsedSharedPrePackedWeightCounter(); - } -}; - -void OpTester::AddReferenceOutputs(const std::string& model_path, float abs_error, std::unique_ptr ep) { - SessionOptions so; - so.session_logid = op_; - so.session_log_verbosity_level = 1; - so.graph_optimization_level = TransformerLevel::Default; - - RunOptions run_options; - run_options.run_tag = op_; - run_options.run_log_verbosity_level = 1; - - Status status; - InferenceSession subgraph_session_object{so, GetEnvironment()}; - status = subgraph_session_object.RegisterExecutionProvider(std::move(ep)); - ASSERT_TRUE((status = subgraph_session_object.Load(model_path)).IsOK()) << status; - ASSERT_TRUE((status = subgraph_session_object.Initialize()).IsOK()) << status; - - // Retrieve output names - auto model_outputs = subgraph_session_object.GetModelOutputs(); - ASSERT_TRUE(model_outputs.first.IsOK()); - std::vector output_names; - std::transform(model_outputs.second->begin(), - model_outputs.second->end(), - std::back_inserter(output_names), - [](const onnxruntime::NodeArg* node_arg) -> std::string { return node_arg->Name(); }); - - NameMLValMap feeds; - for (size_t i = 0; i < input_data_.size(); ++i) { - if (input_data_[i].def_.Exists()) { - feeds[input_data_[i].def_.Name()] = input_data_[i].data_; - } - } - - std::vector subgraph_fetches; - ASSERT_TRUE((status = subgraph_session_object.Run(run_options, feeds, output_names, &subgraph_fetches)).IsOK()) << status; - - for (size_t out_idx = 0; out_idx < subgraph_fetches.size(); out_idx++) { - // Retrieve TypeProto - ASSERT_TRUE(subgraph_fetches[out_idx].Type()->IsTensorType()) << status; - const Tensor& t = subgraph_fetches[out_idx].Get(); - const TensorTypeBase* tensor_type = DataTypeImpl::TensorTypeFromONNXEnum(t.GetElementType()); - - // Construct a temp TypeProto with shape information - ONNX_NAMESPACE::TypeProto tmp_type_proto(*(tensor_type->GetTypeProto())); - auto mutable_shape = tmp_type_proto.mutable_tensor_type()->mutable_shape(); - for (auto i : t.Shape().GetDims()) { - auto* mutable_dim = mutable_shape->add_dim(); - mutable_dim->set_dim_value(i); - } - - if (abs_error != 0.0f) { - output_data_.push_back(Data(NodeArg(output_names[out_idx], &tmp_type_proto), - std::move(subgraph_fetches[out_idx]), - optional(), optional(abs_error))); - } else { - output_data_.push_back(Data(NodeArg(output_names[out_idx], &tmp_type_proto), - std::move(subgraph_fetches[out_idx]), - optional(), optional())); - } - } -} - -#ifdef ENABLE_TRAINING -// Deprecated code. Remove this when training::TrainingSession is removed. -template std::vector OpTester::ExecuteModel( - Model& model, training::TrainingSession& session_object, - ExpectResult expect_result, const std::string& expected_failure_string, - const RunOptions* run_options, - const std::unordered_map& feeds, - const std::vector& output_names, const std::string& provider_type, - bool allow_released_onnx_opset_only); -#endif - -} // namespace test -} // namespace onnxruntime diff --git a/onnxruntime/test/providers/provider_test_utils.h b/onnxruntime/test/providers/provider_test_utils.h index 1647190291133..87dc5980e9e50 100644 --- a/onnxruntime/test/providers/provider_test_utils.h +++ b/onnxruntime/test/providers/provider_test_utils.h @@ -3,1182 +3,19 @@ #pragma once -#include -#include -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include "core/common/gsl.h" - -#include "core/common/logging/logging.h" -#include "core/common/optional.h" -#include "core/framework/allocatormgr.h" -#include "core/framework/customregistry.h" -#include "core/framework/data_types.h" -#include "core/framework/execution_frame.h" -#include "core/framework/op_kernel.h" -#include "core/framework/prepacked_weights_container.h" -#include "core/framework/run_options.h" -#include "core/framework/session_options.h" -#include "core/framework/session_state.h" -#include "core/framework/tensor.h" -#include "core/framework/TensorSeq.h" -#include "core/framework/to_tensor_proto_element_type.h" -#include "core/graph/graph_viewer.h" -#include "core/graph/model.h" -#include "core/providers/providers.h" -#include "core/util/math_cpuonly.h" -#include "test/framework/TestAllocatorManager.h" -#include "test/test_environment.h" -#include "test/util/include/asserts.h" +#include "test/providers/checkers.h" +#include "test/providers/op_tester.h" +#include "test/providers/model_tester.h" namespace onnxruntime { -class InferenceSession; -struct SessionOptions; - namespace test { -template -struct SeqTensors { - void AddTensor(const std::vector& shape0, const std::vector& data0) { - tensors.push_back(Tensor{shape0, data0}); - } - - template - struct Tensor { - std::vector shape; - std::vector data; - }; - std::vector> tensors; -}; - -template -struct TTypeProto { - explicit TTypeProto(const std::vector* shape = nullptr) { - proto.mutable_tensor_type()->set_elem_type(utils::ToTensorProtoElementType()); - if (shape) { - auto mutable_shape = proto.mutable_tensor_type()->mutable_shape(); - for (auto i : *shape) { - auto* mutable_dim = mutable_shape->add_dim(); - if (i != -1) - mutable_dim->set_dim_value(i); - else - mutable_dim->set_dim_param("symbolic"); - } - } - } - ONNX_NAMESPACE::TypeProto proto; -}; - -// Variable template for ONNX_NAMESPACE::TensorProto_DataTypes, s_type_proto, etc.. -template -struct TTensorType { - static const TTypeProto s_type_proto; -}; - -template -const TTypeProto TTensorType::s_type_proto; - -#if !defined(DISABLE_SPARSE_TENSORS) -struct TSparseTensorProto { - explicit TSparseTensorProto(int32_t dtype, const std::vector* shape = nullptr) { - proto.mutable_sparse_tensor_type()->set_elem_type(dtype); - if (shape) { - auto m_shape = proto.mutable_sparse_tensor_type()->mutable_shape(); - for (int64_t v : *shape) { - auto* m_dim = m_shape->add_dim(); - if (v != -1) - m_dim->set_dim_value(v); - else - m_dim->set_dim_param("symbolic"); - } - } - } - ONNX_NAMESPACE::TypeProto proto; -}; -#endif - -// TypeProto for map -template -struct MTypeProto { - MTypeProto() { - proto.mutable_map_type()->set_key_type(utils::ToTensorProtoElementType()); - proto.mutable_map_type()->mutable_value_type()->mutable_tensor_type()->set_elem_type(utils::ToTensorProtoElementType()); - proto.mutable_map_type()->mutable_value_type()->mutable_tensor_type()->mutable_shape()->clear_dim(); - } - ONNX_NAMESPACE::TypeProto proto; -}; - -template -struct MMapType { - static const MTypeProto s_map_type_proto; -}; - -template -const MTypeProto MMapType::s_map_type_proto; - -// TypeProto for vector> -template -struct VectorOfMapTypeProto { - VectorOfMapTypeProto() { - auto* map_type = proto.mutable_sequence_type()->mutable_elem_type()->mutable_map_type(); - map_type->set_key_type(utils::ToTensorProtoElementType()); - map_type->mutable_value_type()->mutable_tensor_type()->set_elem_type(utils::ToTensorProtoElementType()); - map_type->mutable_value_type()->mutable_tensor_type()->mutable_shape()->clear_dim(); - } - ONNX_NAMESPACE::TypeProto proto; -}; - -template -struct VectorOfMapType { - static const VectorOfMapTypeProto s_vec_map_type_proto; -}; - -template -const VectorOfMapTypeProto VectorOfMapType::s_vec_map_type_proto; - -template -struct SequenceTensorTypeProto { - SequenceTensorTypeProto() { - MLDataType dt = DataTypeImpl::GetTensorType(); - const auto* elem_proto = dt->GetTypeProto(); - proto.mutable_sequence_type()->mutable_elem_type()->CopyFrom(*elem_proto); - } - ONNX_NAMESPACE::TypeProto proto; -}; - -template -struct SequenceTensorType { - static const SequenceTensorTypeProto s_sequence_tensor_type_proto; -}; - -template -const SequenceTensorTypeProto SequenceTensorType::s_sequence_tensor_type_proto; - -#if !defined(DISABLE_OPTIONAL_TYPE) - -struct OptionalTypeProto { - OptionalTypeProto(const ONNX_NAMESPACE::TypeProto& type_proto) { - proto.mutable_optional_type()->mutable_elem_type()->CopyFrom(type_proto); - } - ONNX_NAMESPACE::TypeProto proto; -}; - -#endif - -struct CheckParams { - bool sort_output_ = false; - optional absolute_error_; - optional relative_error_; -}; - -// To use OpTester: -// 1. Create one with the op name -// 2. Call AddAttribute with any attributes -// 3. Call AddInput for all the inputs -// 4. Call AddOutput with all expected outputs, -// Or call AddReferenceOutputs to compute reference outputs with the model -// 5. Call Run -class OpTester { - public: - // Default to the first opset that ORT was available (7). - // When operators are updated they need to explicitly add tests for the new opset version. - // This is due to the kernel matching logic. See KernelRegistry::VerifyKernelDef. - // Additionally, -1 is supported and defaults to the latest known opset. - // - // Defaulting to the latest opset version would result in existing operator implementations for non-CPU EPs to - // lose their test coverage until an implementation for the new version is added. - // e.g. there are CPU and GPU implementations for version 1 of an op. both are tested by a single OpTester test. - // opset changes from 1 to 2 and CPU implementation gets added. If 'opset_version' is 2 the kernel matching - // will find and run the CPU v2 implementation, but will not match the GPU v1 implementation. - // OpTester will say it was successful as at least one EP ran, and the GPU implementation of v1 no longer has - // test coverage. - explicit OpTester(const char* op, int opset_version = 7, const char* domain = onnxruntime::kOnnxDomain, bool verify_output = true) - : op_(op), domain_(domain), opset_version_(opset_version), verify_output_(verify_output) { - if (opset_version_ < 0) { - static int latest_onnx_version = - ONNX_NAMESPACE::OpSchemaRegistry::DomainToVersionRange().Map().at(ONNX_NAMESPACE::ONNX_DOMAIN).second; - opset_version_ = latest_onnx_version; - } - } - - virtual ~OpTester(); - - // Set whether the NodeArg created by AddInput/AddOutput should include shape information - // for Tensor types. If not added, shape inferencing should resolve. If added, shape inferencing - // should validate. Default is to add. - // Additionally a symbolic dimension will be added if symbolic_dim matches a dimension in the input. - OpTester& AddShapeToTensorData(bool add_shape = true, int symbolic_dim = -1) { - add_shape_to_tensor_data_ = add_shape; - add_symbolic_dim_to_tensor_data_ = symbolic_dim; - return *this; - } - - // We have an initializer_list and vector version of the Add functions because std::vector is specialized for - // bool and we can't get the raw data out. So those cases must use an initializer_list - - // Dims variant is needed to reduce the number of overloads - // MS compiler refuses to create a gsl::span from initializer_list especially - // if it contains a single element - using DimsVariant = std::variant, TensorShapeVector>; - - template - void AddInput(const char* name, std::initializer_list dims, std::initializer_list values, - bool is_initializer = false, const std::vector* dim_params = nullptr) { - const DimsVariant dims_var = std::vector(dims); - AddData(input_data_, name, dims_var, values.begin(), values.size(), is_initializer, false, dim_params); - } - - template - void AddInput(const char* name, std::initializer_list dims, const std::vector& values, - bool is_initializer = false, const std::vector* dim_params = nullptr) { - const DimsVariant dims_var = std::vector(dims); - AddData(input_data_, name, dims_var, values.data(), values.size(), is_initializer, false, dim_params); - } - - template - void AddInput(const char* name, std::initializer_list dims, const T* p_values, - const size_t size, bool is_initializer = false, - const std::vector* dim_params = nullptr) { - const DimsVariant dims_var = std::vector(dims); - AddData(input_data_, name, dims_var, p_values, size, is_initializer, false, dim_params); - } - - template - void AddInput(const char* name, std::initializer_list dims, const TensorShapeVector& values, - bool is_initializer = false, const std::vector* dim_params = nullptr) { - const DimsVariant dims_var = std::vector(dims); - AddData(input_data_, name, dims_var, values.data(), values.size(), is_initializer, false, dim_params); - } - - template - void AddInput(const char* name, const DimsVariant& dims, std::initializer_list values, - bool is_initializer = false, const std::vector* dim_params = nullptr) { - AddData(input_data_, name, dims, values.begin(), values.size(), is_initializer, false, dim_params); - } - - template - void AddInput(const char* name, const DimsVariant& dims, const std::vector& values, - bool is_initializer = false, const std::vector* dim_params = nullptr) { - AddData(input_data_, name, dims, values.data(), values.size(), is_initializer, false, dim_params); - } - - template - void AddInput(const char* name, const DimsVariant& dims, const T* p_values, - const size_t size, bool is_initializer = false, - const std::vector* dim_params = nullptr) { - AddData(input_data_, name, dims, p_values, size, is_initializer, false, dim_params); - } - -#if !defined(DISABLE_SPARSE_TENSORS) - // Useful to add boolean data - template - void AddSparseCooInput(const char* name, const std::vector& dims, - const std::initializer_list& values, const std::vector& indices, - const std::vector* dim_params = nullptr) { - auto ml_type = DataTypeImpl::GetType(); - AddSparseCooTensorData(input_data_, ml_type, name, dims, - gsl::make_span(values).as_bytes(), - gsl::make_span(indices), - CheckParams(), dim_params); - } - - template - void AddSparseCooInput(const char* name, const std::vector& dims, - const std::vector& values, const std::vector& indices, - const std::vector* dim_params = nullptr) { - auto ml_type = DataTypeImpl::GetType(); - AddSparseCooTensorData(input_data_, ml_type, name, dims, - gsl::as_bytes(gsl::make_span(values)), - gsl::make_span(indices), - CheckParams(), dim_params); - } - - template - void AddSparseCooInput(const char* name, const std::vector& dims, - gsl::span values_span, - const std::vector& indices, - const std::vector* dim_params = nullptr) { - auto ml_type = DataTypeImpl::GetType(); - AddSparseCooTensorData(input_data_, ml_type, name, dims, - values_span.as_bytes(), - gsl::make_span(indices), - CheckParams(), dim_params); - } - - void AddSparseCooInput(const char* name, const std::vector& dims, - const std::vector& values, - const std::vector& indices, - const std::vector* dim_params = nullptr) { - AddSparseCooTensorStrings(input_data_, name, dims, - gsl::make_span(values), - gsl::make_span(indices), - dim_params); - } - - // Useful to add boolean data - template - void AddSparseCsrInput(const char* name, const std::vector& dims, - const std::initializer_list& values, - const std::vector& inner_indices, - const std::vector& outer_indices, - const std::vector* dim_params = nullptr) { - auto ml_type = DataTypeImpl::GetType(); - AddSparseCsrTensorData(input_data_, ml_type, name, dims, - gsl::make_span(values).as_bytes(), - gsl::make_span(inner_indices), - gsl::make_span(outer_indices), - CheckParams(), dim_params); - } - - template - void AddSparseCsrInput(const char* name, const std::vector& dims, - const std::vector& values, - const std::vector& inner_indices, - const std::vector& outer_indices, - const std::vector* dim_params = nullptr) { - auto ml_type = DataTypeImpl::GetType(); - AddSparseCsrTensorData(input_data_, ml_type, name, dims, - gsl::as_bytes(gsl::make_span(values)), - gsl::make_span(inner_indices), - gsl::make_span(outer_indices), - CheckParams(), dim_params); - } - - template - void AddSparseCsrInput(const char* name, const std::vector& dims, - gsl::span values_span, - const std::vector& inner_indices, - const std::vector& outer_indices, - const std::vector* dim_params = nullptr) { - auto ml_type = DataTypeImpl::GetType(); - AddSparseCsrTensorData(input_data_, ml_type, name, dims, - values_span.as_bytes(), - gsl::make_span(inner_indices), - gsl::make_span(outer_indices), - CheckParams(), dim_params); - } - - void AddSparseCsrInput(const char* name, const std::vector& dims, - const std::vector& values, - const std::vector& inner_indices, - const std::vector& outer_indices, - const std::vector* dim_params = nullptr) { - AddSparseCsrTensorStrings(input_data_, name, dims, - gsl::make_span(values), - gsl::make_span(inner_indices), - gsl::make_span(outer_indices), - dim_params); - } -#endif - - // Add other registered types, possibly experimental - template - void AddInput(const char* name, const T& val) { - auto mltype = DataTypeImpl::GetType(); - ORT_ENFORCE(mltype != nullptr, "T must be a registered cpp type"); - auto ptr = std::make_unique(val); - OrtValue value; - value.Init(ptr.get(), mltype, mltype->GetDeleteFunc()); - ptr.release(); - input_data_.push_back(Data(NodeArg(name, mltype->GetTypeProto()), std::move(value), optional(), - optional())); - } - - template - void AddInput(const char* name, T&& val) { - auto mltype = DataTypeImpl::GetType(); - ORT_ENFORCE(mltype != nullptr, "T must be a registered cpp type"); - auto ptr = std::make_unique(std::move(val)); - OrtValue value; - value.Init(ptr.get(), mltype, mltype->GetDeleteFunc()); - ptr.release(); - input_data_.push_back(Data(NodeArg(name, mltype->GetTypeProto()), std::move(value), optional(), - optional())); - } - - template - void AddSeqInput(const char* name, const SeqTensors& seq_tensors) { - AddSeqData(input_data_, name, &seq_tensors); - } - - template - void AddSeqOutput(const char* name, const SeqTensors& seq_tensors, - float rel_error = 0.0f, float abs_error = 0.0f) { - AddSeqData(output_data_, name, &seq_tensors, false, rel_error, abs_error); - } - -#if !defined(DISABLE_OPTIONAL_TYPE) - - template - void AddOptionalTypeTensorInput(const char* name, const DimsVariant& dims, - const std::initializer_list* values = nullptr, - bool is_initializer = false, const std::vector* dim_params = nullptr) { - AddData(input_data_, name, dims, values ? values->begin() : nullptr, - values ? values->size() : 0, is_initializer, false, dim_params, 0.0f, 0.0f, true); - } - - template - void AddOptionalTypeTensorInput(const char* name, std::initializer_list dims, - const std::initializer_list* values = nullptr, - bool is_initializer = false, const std::vector* dim_params = nullptr) { - DimsVariant dims_var = std::vector(dims); - AddData(input_data_, name, dims_var, values ? values->begin() : nullptr, - values ? values->size() : 0, is_initializer, false, dim_params, 0.0f, 0.0f, true); - } - - template - void AddOptionalTypeTensorOutput(const char* name, const DimsVariant& dims, - const std::initializer_list* expected_values = nullptr, - bool sort_output = false, float rel_error = 0.0f, float abs_error = 0.0f) { - AddData(output_data_, name, dims, expected_values ? expected_values->begin() : nullptr, - expected_values ? expected_values->size() : 0, false, - sort_output, nullptr /* dim_params */, rel_error, abs_error, true); - } - - template - void AddOptionalTypeTensorOutput(const char* name, std::initializer_list dims, - const std::initializer_list* expected_values = nullptr, - bool sort_output = false, float rel_error = 0.0f, float abs_error = 0.0f) { - DimsVariant dims_var = std::vector(dims); - AddData(output_data_, name, dims_var, expected_values ? expected_values->begin() : nullptr, - expected_values ? expected_values->size() : 0, false, - sort_output, nullptr /* dim_params */, rel_error, abs_error, true); - } - - template - void AddOptionalTypeSeqInput(const char* name, - const SeqTensors* seq_tensors) { - AddSeqData(input_data_, name, seq_tensors, true); - } - - template - void AddOptionalTypeSeqOutput(const char* name, - const SeqTensors* seq_tensors, - float rel_error = 0.0f, float abs_error = 0.0f) { - AddSeqData(output_data_, name, seq_tensors, true, rel_error, abs_error); - } - -#endif - - template - void AddInput(const char* name, const std::map& val) { - std::unique_ptr> ptr = std::make_unique>(val); - OrtValue value; - value.Init(ptr.release(), DataTypeImpl::GetType>(), - DataTypeImpl::GetType>()->GetDeleteFunc()); - input_data_.push_back(Data(NodeArg(name, &MMapType::s_map_type_proto.proto), std::move(value), - optional(), optional())); - } - - /* - * Use this API to add an input *edge* to the node/op being tested that won't - * have any data passed into. - * Such an edge will have the qualifier OpSchema::Optional in the schema. - * This is exposed to ensure the op kernel implementations can be tested to handle - * presence/absence of such optional input edges. - */ - template - void AddOptionalInputEdge() { - std::string name; // empty == input doesn't exist - input_data_.push_back(Data(NodeArg(name, &TTensorType::s_type_proto.proto), OrtValue(), optional(), - optional())); - } - - template - void AddOutput(const char* name, std::initializer_list dims, std::initializer_list expected_values, - bool sort_output = false, float rel_error = 0.0f, float abs_error = 0.0f) { - const DimsVariant dims_var = std::vector(dims); - AddData(output_data_, name, dims_var, expected_values.begin(), expected_values.size(), false, - sort_output, nullptr /* dim_params */, rel_error, abs_error); - } - - template - void AddOutput(const char* name, std::initializer_list dims, const std::vector& expected_values, - bool sort_output = false, float rel_error = 0.0f, float abs_error = 0.0f) { - const DimsVariant dims_var = std::vector(dims); - AddData(output_data_, name, dims_var, expected_values.data(), expected_values.size(), false, - sort_output, nullptr /* dim_params */, rel_error, abs_error); - } - - template - void AddOutput(const char* name, std::initializer_list dims, const T* p_values, const size_t size, - bool sort_output = false, float rel_error = 0.0f, float abs_error = 0.0f) { - const DimsVariant dims_var = std::vector(dims); - AddData(output_data_, name, dims_var, p_values, size, false, - sort_output, nullptr /* dim_params */, rel_error, abs_error); - } - - template - void AddOutput(const char* name, const DimsVariant& dims, std::initializer_list expected_values, - bool sort_output = false, float rel_error = 0.0f, float abs_error = 0.0f) { - AddData(output_data_, name, dims, expected_values.begin(), expected_values.size(), false, - sort_output, nullptr /* dim_params */, rel_error, abs_error); - } - - // This function doesn't work for vector because const vector cannot invoke its data(). - template - void AddOutput(const char* name, const DimsVariant& dims, const std::vector& expected_values, - bool sort_output = false, float rel_error = 0.0f, float abs_error = 0.0f) { - AddData(output_data_, name, dims, expected_values.data(), expected_values.size(), false, - sort_output, nullptr /* dim_params */, rel_error, abs_error); - } - - template - void AddOutput(const char* name, const DimsVariant& dims, const TensorShapeVector& expected_values, - bool sort_output = false, float rel_error = 0.0f, float abs_error = 0.0f) { - AddData(output_data_, name, dims, expected_values.data(), expected_values.size(), false, - sort_output, nullptr /* dim_params */, rel_error, abs_error); - } - - template - void AddOutput(const char* name, const DimsVariant& dims, const T* p_values, const size_t size, - bool sort_output = false, float rel_error = 0.0f, float abs_error = 0.0f) { - AddData(output_data_, name, dims, p_values, size, false, - sort_output, nullptr /* dim_params */, rel_error, abs_error); - } - -#if !defined(DISABLE_SPARSE_TENSORS) - template - void AddSparseCooOutput(const char* name, const std::vector& dims, - const std::initializer_list& expected_values, - const std::vector& expected_indices, - const CheckParams& check_params = CheckParams()) { - auto ml_type = DataTypeImpl::GetType(); - AddSparseCooTensorData(output_data_, ml_type, name, dims, - gsl::make_span(expected_values).as_bytes(), - gsl::make_span(expected_indices), - check_params, nullptr /*dim_params*/); - } - - template - void AddSparseCooOutput(const char* name, const std::vector& dims, - const std::vector& expected_values, - const std::vector& expected_indices, - const CheckParams& check_params = CheckParams()) { - auto ml_type = DataTypeImpl::GetType(); - AddSparseCooTensorData(output_data_, ml_type, name, dims, - gsl::make_span(expected_values).as_bytes(), - gsl::make_span(expected_indices), - check_params, nullptr /*dim_params*/); - } - - template - void AddSparseCooOutput(const char* name, const std::vector& dims, - gsl::span expected_values_span, - const std::vector& expected_indices, - const CheckParams& check_params = CheckParams()) { - auto ml_type = DataTypeImpl::GetType(); - AddSparseCooTensorData(output_data_, ml_type, name, dims, - expected_values_span.as_bytes(), - gsl::make_span(expected_indices), - check_params, nullptr /*dim_params*/); - } - - void AddSparseCooOutput(const char* name, const std::vector& dims, - const std::vector& expected_values, - const std::vector& expected_indices) { - AddSparseCooTensorStrings(output_data_, name, dims, - gsl::make_span(expected_values), - gsl::make_span(expected_indices)); - } - - template - void AddSparseCsrOutput(const char* name, const std::vector& dims, - const std::initializer_list& values, - const std::vector& inner_indices, - const std::vector& outer_indices, - const CheckParams& check_params = CheckParams()) { - auto ml_type = DataTypeImpl::GetType(); - AddSparseCsrTensorData(output_data_, ml_type, name, dims, - gsl::make_span(values).as_bytes(), - gsl::make_span(inner_indices), - gsl::make_span(outer_indices), - check_params, nullptr /*dim_params*/); - } - - template - void AddSparseCsrOutput(const char* name, const std::vector& dims, - const std::vector& values, - const std::vector& inner_indices, - const std::vector& outer_indices, - const CheckParams& check_params = CheckParams()) { - auto ml_type = DataTypeImpl::GetType(); - AddSparseCsrTensorData(output_data_, ml_type, name, dims, - gsl::make_span(values).as_bytes(), - gsl::make_span(inner_indices), - gsl::make_span(outer_indices), - check_params, nullptr /*dim_params*/); - } - - template - void AddSparseCsrOutput(const char* name, const std::vector& dims, - gsl::span expected_values_span, - const std::vector& expected_inner_indices, - const std::vector& expected_outer_indices, - const CheckParams& check_params = CheckParams()) { - auto ml_type = DataTypeImpl::GetType(); - AddSparseCsrTensorData(output_data_, ml_type, name, dims, - expected_values_span.as_bytes(), - gsl::make_span(expected_inner_indices), - gsl::make_span(expected_outer_indices), - check_params, nullptr /*dim_params*/); - } - - void AddSparseCsrOutput(const char* name, const std::vector& dims, - const std::vector& expected_values, - const std::vector& expected_inner_indices, - const std::vector& expected_outer_indices) { - AddSparseCsrTensorStrings(output_data_, name, dims, - gsl::make_span(expected_values), - gsl::make_span(expected_inner_indices), - gsl::make_span(expected_outer_indices)); - } -#endif - - /* - * Use this API to add an output *edge* to the node/op being tested that shouldn't have any - * data produced into. - * Such an edge will have the qualifier OpSchema::Optional in the schema. - * This is exposed to ensure the op kernel implementations can be tested to handle - * presence/absence of such optional output edges. - */ - template - void AddOptionalOutputEdge() { - std::string name; // empty == output doesn't exist - output_data_.push_back(Data(NodeArg(name, &TTensorType::s_type_proto.proto), OrtValue(), optional(), - optional())); - } - - // Add other registered types, possibly experimental - template - void AddOutput(const char* name, const T& val) { - auto mltype = DataTypeImpl::GetType(); - ORT_ENFORCE(mltype != nullptr, "T must be a registered cpp type"); - auto ptr = std::make_unique(val); - OrtValue value; - value.Init(ptr.get(), mltype, mltype->GetDeleteFunc()); - ptr.release(); - output_data_.push_back(Data(NodeArg(name, mltype->GetTypeProto()), std::move(value), optional(), - optional())); - } - - template - void AddOutput(const char* name, T&& val) { - auto mltype = DataTypeImpl::GetType(); - ORT_ENFORCE(mltype != nullptr, "T must be a registered cpp type"); - auto ptr = std::make_unique(std::move(val)); - OrtValue value; - value.Init(ptr.get(), mltype, mltype->GetDeleteFunc()); - ptr.release(); - output_data_.push_back(Data(NodeArg(name, mltype->GetTypeProto()), std::move(value), optional(), - optional())); - } - - // Add non tensor output - template - void AddOutput(const char* name, const std::vector>& val) { - auto ptr = std::make_unique>>(val); - OrtValue ml_value; - ml_value.Init(ptr.release(), DataTypeImpl::GetType>>(), - DataTypeImpl::GetType>>()->GetDeleteFunc()); - output_data_.push_back(Data(NodeArg(name, &VectorOfMapType::s_vec_map_type_proto.proto), std::move(ml_value), - optional(), optional())); - } - - // Generate the reference outputs with the model file - void AddReferenceOutputs(const std::string& model_path, float abs_error = 0.0f, std::unique_ptr ep = nullptr); - - void AddCustomOpRegistry(std::shared_ptr registry) { - custom_schema_registries_.push_back(registry->GetOpschemaRegistry()); - custom_session_registries_.push_back(registry); - } - - void SetOutputAbsErr(const char* name, float v); - void SetOutputRelErr(const char* name, float v); - - // Number of times to call InferenceSession::Run. The same feeds are used each time. - // e.g. used to verify the generator ops behave as expected - void SetNumRunCalls(int n) { - ORT_ENFORCE(n > 0); - num_run_calls_ = n; - } - - using CustomOutputVerifierFn = - std::function& /*fetches*/, const std::string& /*provider_type*/)>; - - void SetCustomOutputVerifier(CustomOutputVerifierFn custom_output_verifier) { - custom_output_verifier_ = custom_output_verifier; - } - - void AddAttributeProto(ONNX_NAMESPACE::AttributeProto attr) { - add_attribute_funcs_.emplace_back([attr = std::move(attr)](onnxruntime::Node& node) { - node.AddAttributeProto(attr); - }); - } - - template - void AddAttribute(std::string name, T value) { - // Generate a the proper AddAttribute call for later - add_attribute_funcs_.emplace_back([name = std::move(name), value = std::move(value)](onnxruntime::Node& node) { - node.AddAttribute(name, value); - }); - } - - enum class ExpectResult { kExpectSuccess, - kExpectFailure }; - - OpTester& Config(const SessionOptions& sess_options); - OpTester& Config(ExpectResult expect_result, const std::string& expected_failure_string); - OpTester& ConfigExcludeEps(const std::unordered_set& excluded_provider_types); - OpTester& Config(const RunOptions* run_options); - OpTester& ConfigEps(std::vector>&& execution_providers); - OpTester& Config(const Graph::ResolveOptions& resolve_options); - - void RunWithConfig(size_t* number_of_pre_packed_weights_counter = nullptr, - size_t* number_of_shared_pre_packed_weights_counter = nullptr); - - // [[deprecated("Use builder pattern Config* and RunWithConfig")]] - void Run(ExpectResult expect_result = ExpectResult::kExpectSuccess, const std::string& expected_failure_string = "", - const std::unordered_set& excluded_provider_types = {}, - const RunOptions* run_options = nullptr, - std::vector>* execution_providers = nullptr, - ExecutionMode execution_mode = ExecutionMode::ORT_SEQUENTIAL, - const Graph::ResolveOptions& resolve_options = {}); - - // [[deprecated("Use builder pattern Config* and RunWithConfig")]] - void Run(SessionOptions session_options, - ExpectResult expect_result = ExpectResult::kExpectSuccess, - const std::string& expected_failure_string = "", - const std::unordered_set& excluded_provider_types = {}, - const RunOptions* run_options = nullptr, - std::vector>* execution_providers = nullptr, - const Graph::ResolveOptions& resolve_options = {}, - /*out*/ size_t* number_of_pre_packed_weights_counter = nullptr, - /*out*/ size_t* number_of_shared_pre_packed_weights_counter = nullptr); - - std::vector - GetFetches() { return fetches_; } - - std::unique_ptr BuildGraph(const std::unordered_map& extra_domain_to_version = {}, - const ModelOptions& model_options = ModelOptions{}); - - // storing p_model as cache - void SetModelCache(std::shared_ptr model) { - cached_model_ = model; - } - - std::shared_ptr GetModelCache() { - return cached_model_; - } - - // clear input/output data, fetches will be cleared in Run() - void ClearData() { - input_data_.clear(); - output_data_.clear(); - initializer_index_.clear(); - } - - struct Data { - onnxruntime::NodeArg def_; - OrtValue data_; - optional relative_error_; - optional absolute_error_; - bool sort_output_; - Data(onnxruntime::NodeArg&& def, OrtValue&& data, optional&& rel, optional&& abs, - bool sort_output = false) - : def_(std::move(def)), - data_(std::move(data)), - relative_error_(std::move(rel)), - absolute_error_(abs), - sort_output_(sort_output) {} - Data(Data&&) = default; - Data& operator=(Data&&) = default; - }; - - std::vector& GetInputData() { - return input_data_; - } - - std::vector& GetOutputData() { - return output_data_; - } - - void SetDeterminism(bool use_determinism) { - use_determinism_ = use_determinism; - } - - void EnableSharingOfPrePackedWeightsAcrossSessions() { - add_prepacked_shared_container_to_sessions_ = true; - } - - size_t GetNumPrePackedWeightsShared() const { - return prepacked_weights_container_.GetNumberOfElements(); - } - - bool test_allow_released_onnx_opset_only_ = true; - - protected: - // Set test_allow_released_onnx_opset_only_ to false or override this method and return false - // if inheriting from OpTester to allow testing of a non-released ONNX opset operator - virtual bool IsAllowReleasedONNXOpsetsOnlySetForThisTest() const { - return test_allow_released_onnx_opset_only_; - } - - virtual void AddNodes(onnxruntime::Graph& graph, std::vector& graph_input_defs, - std::vector& graph_output_defs, - std::vector>& add_attribute_funcs); - - void AddInitializers(onnxruntime::Graph& graph); - - void FillFeedsAndOutputNames(std::unordered_map& feeds, - std::vector& output_names); - - void FillFeeds(std::unordered_map& feeds); - - template - std::vector ExecuteModel(Model& model, - SessionType& session_object, - ExpectResult expect_result, - const std::string& expected_failure_string, - const RunOptions* run_options, - const std::unordered_map& feeds, - const std::vector& output_names, - const std::string& provider_type, - bool allow_released_onnx_opset_only = true); - - struct RunContext { - SessionOptions session_options{}; - ExpectResult expect_result{ExpectResult::kExpectSuccess}; - std::string expected_failure_string{}; - std::unordered_set excluded_provider_types = {}; - const RunOptions* run_options{}; - bool run_with_specified_eps{false}; - std::vector> execution_providers{}; - Graph::ResolveOptions resolve_options{}; - }; - - RunContext ctx_{}; - - const char* op_; - std::vector input_data_; - std::vector output_data_; - std::vector fetches_; - - // for gradient unit tests only - std::shared_ptr cached_model_; - -#ifndef NDEBUG - bool run_called_{}; -#endif - - protected: - gsl::span ToDimsSpan(const DimsVariant& dims_var) { - gsl::span result; - switch (dims_var.index()) { - case 0: - result = std::get<0>(dims_var); - break; - case 1: - result = std::get<1>(dims_var); - break; - default: - ORT_THROW("Unhandled dims variant"); - } - return result; - } - - template - void AddData(std::vector& data, const char* name, const DimsVariant& dims_var, const T* values, - int64_t values_count, bool is_initializer = false, bool sort_output = false, - const std::vector* dim_params = nullptr, - float rel_error = 0.0f, float abs_error = 0.0f, bool is_optional_type_tensor = false) { - auto dims = ToDimsSpan(dims_var); -#if defined(DISABLE_OPTIONAL_TYPE) - if (is_optional_type_tensor) { - ORT_THROW("Optional type is not supported in this build"); - } -#endif - - ORT_TRY { - TensorShape shape{dims}; - - OrtValue value; - - if (!is_optional_type_tensor || (is_optional_type_tensor && values != nullptr)) { - // In case values is nullptr for optional type tensor, it means we are creating - // an optional type tensor which is None and we hence skip values count validation - ORT_ENFORCE(shape.Size() == values_count, - values_count, " input values doesn't match tensor size of ", - shape.Size()); - - // If it is an optional tensor type with no values (i.e.) None, - // we won't even pass it in to Run() as part of the feeds, - // so we don't even have to create a Tensor. - // Conversely, if it is an optional tensor type with values, - // we pass it in as a regular tensor. - auto allocator = test::AllocatorManager::Instance().GetAllocator(CPU); - Tensor::InitOrtValue(DataTypeImpl::GetType(), shape, std::move(allocator), value); - - // values *could* be nullptr for a non-optional tensor if it is empty. - // Update the data buffer of the input only if values if non-nullptr. - if (values != nullptr) { - auto* data_ptr = value.GetMutable()->MutableData(); - for (int64_t i = 0; i < values_count; i++) { - data_ptr[i] = values[i]; - } - } - } else { // "None" Tensor OrtValue. Initialize appropriately. - auto ml_tensor = DataTypeImpl::GetType(); - value.Init(nullptr, ml_tensor, ml_tensor->GetDeleteFunc()); - } - - std::vector dims_for_proto = GetDimsForProto(dims); - TTypeProto tensor_type_proto(add_shape_to_tensor_data_ ? &dims_for_proto : nullptr); - -#if !defined(DISABLE_OPTIONAL_TYPE) - OptionalTypeProto optional_type_proto(tensor_type_proto.proto); - auto node_arg = NodeArg(name, !is_optional_type_tensor ? &tensor_type_proto.proto : &optional_type_proto.proto); -#else - auto node_arg = NodeArg(name, &tensor_type_proto.proto); -#endif - - AddShapeToTensorData(node_arg, dims, dim_params); - - optional rel; - optional abs; - - if (rel_error != 0.0f) { - rel = rel_error; - } - - if (abs_error != 0.0f) { - abs = abs_error; - } - - data.push_back(Data(std::move(node_arg), std::move(value), std::move(rel), std::move(abs), sort_output)); - - // Optional values cannot be initializers - if (is_initializer && !is_optional_type_tensor) { - initializer_index_.push_back(data.size() - 1); - } - } - ORT_CATCH(const std::exception& ex) { - ORT_HANDLE_EXCEPTION([&]() { - std::cerr << "AddData for '" << name << "' threw: " << ex.what(); - }); - ORT_RETHROW; - } - } - - private: - // Execute the model for a single execution providers combination - void ExecuteModelForEps( - std::vector>&& execution_providers, - onnxruntime::Model& model, - SessionOptions sess_options, - onnxruntime::test::OpTester::ExpectResult expect_result, - const std::string& expected_failure_string, - const onnxruntime::RunOptions* run_options, - const std::unordered_map& feeds, - const std::vector& output_names, - const std::vector>* custom_registries, - bool try_assign_ep_for_nodes, - bool allow_released_onnx_opset_only, - size_t* number_of_pre_packed_weights_counter, - size_t* number_of_shared_pre_packed_weights_counter); - - template - void AddSeqData(std::vector& data, const char* name, - const SeqTensors* seq_tensors, - bool is_optional_sequence_tensor_type = false, - float rel_error = 0.0f, float abs_error = 0.0f) { -#if defined(DISABLE_OPTIONAL_TYPE) - if (is_optional_sequence_tensor_type) { - ORT_THROW("Optional type is not supported in this build"); - } -#endif - - std::unique_ptr ptr; - SequenceTensorTypeProto sequence_tensor_proto; - - if (seq_tensors) { - auto num_tensors = seq_tensors->tensors.size(); - auto elem_type = DataTypeImpl::GetType(); - - ptr = std::make_unique(elem_type); - ptr->Reserve(num_tensors); - for (size_t i = 0; i < num_tensors; ++i) { - TensorShape shape{seq_tensors->tensors[i].shape}; - auto values_count = static_cast(seq_tensors->tensors[i].data.size()); - ORT_ENFORCE(shape.Size() == values_count, values_count, - " input values doesn't match tensor size of ", shape.Size()); - - auto allocator = test::AllocatorManager::Instance().GetAllocator(CPU); - Tensor tensor(elem_type, shape, allocator); - - auto* data_ptr = tensor.MutableData(); - for (int64_t x = 0; x < values_count; ++x) { - data_ptr[x] = seq_tensors->tensors[i].data[x]; - } - - ptr->Add(std::move(tensor)); - - if (add_shape_to_tensor_data_) { - auto* output_tensor_type = sequence_tensor_proto.proto.mutable_sequence_type() - ->mutable_elem_type() - ->mutable_tensor_type(); - if (i == 0) { - ONNX_NAMESPACE::TensorShapeProto* seq_input_shape = output_tensor_type->mutable_shape(); - output_tensor_type->set_elem_type(utils::ToTensorProtoElementType()); - for (size_t j = 0; j < shape.NumDimensions(); ++j) { - auto dim = seq_input_shape->add_dim(); - dim->set_dim_value(shape[j]); - } - } else { - ONNX_NAMESPACE::TensorShapeProto shape_proto; - for (size_t j = 0; j < shape.NumDimensions(); ++j) { - auto dim = shape_proto.add_dim(); - dim->set_dim_value(shape[j]); - } - - ONNX_NAMESPACE::UnionShapeInfo(shape_proto, *output_tensor_type); - } - } - } - } - - OrtValue value; - auto mltype = DataTypeImpl::GetType(); - - // nullptr means None OrtValue which we will skip inserting into the feeds - value.Init(ptr ? ptr.release() : nullptr, mltype, mltype->GetDeleteFunc()); - -#if !defined(DISABLE_OPTIONAL_TYPE) - OptionalTypeProto optional_type_proto(sequence_tensor_proto.proto); - auto node_arg = NodeArg(name, !is_optional_sequence_tensor_type - ? &sequence_tensor_proto.proto - : &optional_type_proto.proto); -#else - auto node_arg = NodeArg(name, &sequence_tensor_proto.proto); -#endif - - optional rel; - optional abs; - - if (rel_error != 0.0f) { - rel = rel_error; - } - - if (abs_error != 0.0f) { - abs = abs_error; - } - - data.push_back(Data(std::move(node_arg), std::move(value), std::move(rel), std::move(abs))); - } - - std::vector GetDimsForProto(gsl::span dims); - - void AddShapeToTensorData(NodeArg& node_arg, gsl::span dims, const std::vector* dim_params); - - void CopyDataToTensor(gsl::span data, Tensor& dst); - -#if !defined(DISABLE_SPARSE_TENSORS) - NodeArg MakeSparseNodeArg(int32_t dtype, const char* name, - const gsl::span& dims, - const std::vector* dim_params); - - void AddSparseCooTensorData(std::vector& data, - MLDataType data_type, - const char* name, - gsl::span dims, - gsl::span values, - gsl::span indices, - const CheckParams& check_params, - const std::vector* dim_params = nullptr); - - void AddSparseCooTensorStrings(std::vector& data, - const char* name, - gsl::span dims, - gsl::span values, - gsl::span indices, - const std::vector* dim_params = nullptr); - - void AddSparseCsrTensorData(std::vector& data, - MLDataType data_type, - const char* name, - gsl::span dims, - gsl::span values, - gsl::span inner_indices, - gsl::span outer_indices, - const CheckParams& check_params, - const std::vector* dim_params = nullptr); - - void AddSparseCsrTensorStrings(std::vector& data, - const char* name, - gsl::span dims, - gsl::span values, - gsl::span inner_indices, - gsl::span outer_indices, - const std::vector* dim_params = nullptr); - - void AddSparseTensorData(std::vector& data, NodeArg node_arg, - std::unique_ptr p_tensor, - const CheckParams& check_params); -#endif - - const char* domain_; - int opset_version_; - bool add_shape_to_tensor_data_ = true; - int add_symbolic_dim_to_tensor_data_ = -1; - int num_run_calls_ = 1; - std::vector initializer_index_; - std::vector> add_attribute_funcs_; - - IOnnxRuntimeOpSchemaRegistryList custom_schema_registries_; - std::vector> custom_session_registries_; - - bool verify_output_; - - bool use_determinism_ = false; - - CustomOutputVerifierFn custom_output_verifier_; - - bool add_prepacked_shared_container_to_sessions_ = false; - - onnxruntime::PrepackedWeightsContainer prepacked_weights_container_; -}; - -template -void ExpectThrow(OpTester& test, const std::string& error_msg) { - ORT_TRY { - test.Run(); - // should throw and not reach this - EXPECT_TRUE(false) << "Expected Run() to throw"; - } - ORT_CATCH(TException ex) { - ORT_UNUSED_PARAMETER(error_msg); - ORT_HANDLE_EXCEPTION([&]() { - EXPECT_THAT(ex.what(), testing::HasSubstr(error_msg)); - }); - } -} - -void DebugTrap(); - -void Check(const OpTester::Data& expected_data, const Tensor& output_tensor, const std::string& provider_type); - -inline const Tensor& FetchTensor(const OrtValue& ort_value) { - return ort_value.Get(); -} - -inline void ConvertFloatToMLFloat16(const float* f_datat, MLFloat16* h_data, int input_size) { +inline void ConvertFloatToMLFloat16(const float* f_datat, MLFloat16* h_data, size_t input_size) { auto in_vector = ConstEigenVectorMap(f_datat, input_size); auto output_vector = EigenVectorMap(static_cast(static_cast(h_data)), input_size); output_vector = in_vector.template cast(); } -inline void ConvertMLFloat16ToFloat(const MLFloat16* h_data, float* f_data, int input_size) { +inline void ConvertMLFloat16ToFloat(const MLFloat16* h_data, float* f_data, size_t input_size) { auto in_vector = ConstEigenVectorMap(static_cast(static_cast(h_data)), input_size); auto output_vector = EigenVectorMap(f_data, input_size); @@ -1187,7 +24,7 @@ inline void ConvertMLFloat16ToFloat(const MLFloat16* h_data, float* f_data, int inline std::vector FloatsToMLFloat16s(const std::vector& f) { std::vector m(f.size()); - ConvertFloatToMLFloat16(f.data(), m.data(), static_cast(f.size())); + ConvertFloatToMLFloat16(f.data(), m.data(), f.size()); return m; } @@ -1202,18 +39,5 @@ inline std::vector FloatsToBFloat16s(const std::vector& input) std::transform(input.begin(), input.end(), std::back_inserter(output), [](float f) { return BFloat16(f); }); return output; } - -inline CheckParams MakeCheckParams(const OpTester::Data& d) { - return CheckParams{d.sort_output_, d.absolute_error_, d.relative_error_}; -} - -inline std::vector GetShapeVector(const TensorShape& shape) { - std::vector result; - const auto dims = shape.GetDims(); - result.resize(dims.size()); - result.assign(dims.begin(), dims.end()); - return result; -} - } // namespace test } // namespace onnxruntime diff --git a/onnxruntime/test/providers/qnn/argmaxmin_op_test.cc b/onnxruntime/test/providers/qnn/argmaxmin_op_test.cc new file mode 100644 index 0000000000000..eaeebba5bea5c --- /dev/null +++ b/onnxruntime/test/providers/qnn/argmaxmin_op_test.cc @@ -0,0 +1,239 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#if !defined(ORT_MINIMAL_BUILD) + +#include +#include + +#include "core/graph/node_attr_utils.h" +#include "test/providers/qnn/qnn_test_utils.h" + +#include "onnx/onnx_pb.h" +#include "gtest/gtest.h" + +namespace onnxruntime { +namespace test { + +// Builds a float32 model with ArgMin/ArgMax. +static GetTestModelFn BuildArgMxxTestCase(const std::string& op_type, TestInputDef input_def, + const std::vector& attrs) { + return [op_type, input_def, attrs](ModelTestBuilder& builder) { + auto* input = MakeTestInput(builder, input_def); + + auto* argm_output = builder.MakeIntermediate(); + Node& argm_node = builder.AddNode(op_type, {input}, {argm_output}); + for (const auto& attr : attrs) { + argm_node.AddAttributeProto(attr); + } + + // Add cast to uint32 + auto* output = builder.MakeOutput(); + Node& cast_node = builder.AddNode("Cast", {argm_output}, {output}); + const auto dst_type = ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_UINT32; + cast_node.AddAttribute("to", static_cast(dst_type)); + }; +} + +// Builds a QDQ model with ArgMin/ArgMax and a Cast to uint32. The quantization parameters are computed from the provided +// input definition. +template +static GetTestQDQModelFn BuildQDQArgMxxTestCase(const std::string& op_type, TestInputDef input_def, + const std::vector& attrs) { + return [op_type, input_def, attrs](ModelTestBuilder& builder, + std::vector>& output_qparams) { + ORT_UNUSED_PARAMETER(output_qparams); + QuantParams input_qparams = GetTestInputQuantParams(input_def); + + auto* input = MakeTestInput(builder, input_def); + + // input -> Q -> DQ -> + auto* input_qdq = AddQDQNodePair(builder, input, input_qparams.scale, input_qparams.zero_point); + auto* argm_output = builder.MakeIntermediate(); + Node& argm_node = builder.AddNode(op_type, {input_qdq}, {argm_output}); + for (const auto& attr : attrs) { + argm_node.AddAttributeProto(attr); + } + + // Cast to uint32 (HTP does not support int64 as graph output) + auto* output = builder.MakeOutput(); + Node& cast_node = builder.AddNode("Cast", {argm_output}, {output}); + const auto dst_type = ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_UINT32; + cast_node.AddAttribute("to", static_cast(dst_type)); + }; +} + +// Runs an ArgMax/ArgMin model on the QNN CPU backend. Checks the graph node assignment, and that inference +// outputs for QNN EP and CPU EP match. +static void RunCPUArgMxxOpTest(const std::string& op_type, TestInputDef input_def, + const std::vector& attrs, + 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 + + RunQnnModelTest(BuildArgMxxTestCase(op_type, input_def, attrs), + provider_options, + opset, + expected_ep_assignment); +} + +// Runs a QDQ ArgMax/ArgMin model on the QNN (HTP) EP and the ORT CPU EP. Checks the graph node assignment, and that inference +// running the QDQ model on QNN EP is at least as accurate as on ORT CPU EP (when compared to the baseline float32 model). +template +static void RunQDQArgMxxOpTest(const std::string& op_type, TestInputDef input_def, + const std::vector& attrs, + 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 + + TestQDQModelAccuracy(BuildArgMxxTestCase(op_type, input_def, attrs), // baseline float32 model + BuildQDQArgMxxTestCase(op_type, input_def, attrs), // QDQ model + provider_options, + opset, + expected_ep_assignment, + 1e-5f); +} + +// +// CPU tests: +// + +// Test that ArgMax/ArgMin with default attributes works on QNN CPU backend. Compares output with CPU EP. +TEST_F(QnnCPUBackendTests, ArgMaxMin_DefaultAttrs) { + RunCPUArgMxxOpTest("ArgMax", + TestInputDef({1, 3, 4, 4}, false, -10.0f, 10.0f), // Random input. + {}, // All default ONNX attributes. + ExpectedEPNodeAssignment::All, 13); + RunCPUArgMxxOpTest("ArgMin", + TestInputDef({1, 3, 4, 4}, false, -10.0f, 10.0f), // Random input. + {}, // All default ONNX attributes. + ExpectedEPNodeAssignment::All, 13); +} + +#if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) +// +// HTP tests: +// + +// Test that Q/DQ(uint8) ArgMax/ArgMin with default attributes works on HTP backend. +// Compares output with CPU EP. +TEST_F(QnnHTPBackendTests, ArgMaxMinU8_DefaultAttrs) { + RunQDQArgMxxOpTest("ArgMax", + TestInputDef({1, 3, 4}, false, -10.0f, 10.0f), // Random input. + {}, // All default ONNX attributes. + ExpectedEPNodeAssignment::All, 13); + RunQDQArgMxxOpTest("ArgMin", + TestInputDef({1, 3, 4, 4}, false, -10.0f, 10.0f), // Random input. + {}, // Default ONNX attributes. + ExpectedEPNodeAssignment::All, 13); +} + +// Tests that Q/DQ(uint8) ArgMax/ArgMin with axis of -1 works on HTP backend. +// Compares output with CPU EP. +TEST_F(QnnHTPBackendTests, ArgMaxMinU8_AxisLast) { + RunQDQArgMxxOpTest("ArgMax", + TestInputDef({1, 3, 4, 4}, false, -10.0f, 10.0f), // Random input. + {utils::MakeAttribute("axis", static_cast(-1))}, // axis is -1 + ExpectedEPNodeAssignment::All, 13); + RunQDQArgMxxOpTest("ArgMin", + TestInputDef({1, 3, 4, 4}, false, -10.0f, 10.0f), // Random input. + {utils::MakeAttribute("axis", static_cast(-1))}, // axis is -1 + ExpectedEPNodeAssignment::All, 13); +} + +// Tests that Q/DQ(uint8) ArgMax/ArgMin with axis of -1 and keepdims = false works on HTP backend. +// Compares output with CPU EP. +TEST_F(QnnHTPBackendTests, ArgMaxMinU8_NotKeepDims) { + RunQDQArgMxxOpTest("ArgMax", + TestInputDef({1, 3, 4, 4}, false, -10.0f, 10.0f), // Random input. + {utils::MakeAttribute("axis", static_cast(-1)), + utils::MakeAttribute("keepdims", static_cast(0))}, + ExpectedEPNodeAssignment::All, 13); + RunQDQArgMxxOpTest("ArgMin", + TestInputDef({1, 3, 4, 4}, false, -10.0f, 10.0f), // Random input. + {utils::MakeAttribute("keepdims", static_cast(0))}, + ExpectedEPNodeAssignment::All, 13); +} + +// Tests that Q/DQ ArgMax/ArgMin with select_last_index = 1 is not supported. +TEST_F(QnnHTPBackendTests, ArgMaxMinU8_SelectLastIndex_NonZero_Unsupported) { + RunQDQArgMxxOpTest("ArgMax", + TestInputDef({1, 3, 4, 4}, false, -10.0f, 10.0f), // Random input. + {utils::MakeAttribute("select_last_index", static_cast(1))}, + ExpectedEPNodeAssignment::None, 13); + RunQDQArgMxxOpTest("ArgMin", + TestInputDef({1, 3, 4, 4}, false, -10.0f, 10.0f), // Random input. + {utils::MakeAttribute("select_last_index", static_cast(1))}, + ExpectedEPNodeAssignment::None, 13); +} + +// Tests that Q/DQ ArgMax/ArgMin with input rank > 4 on HTP is not supported. +TEST_F(QnnHTPBackendTests, ArgMaxMinU8_RankGreaterThan4_Unsupported) { + RunQDQArgMxxOpTest("ArgMax", + TestInputDef({1, 3, 4, 4, 4}, false, -10.0f, 10.0f), // Random input. + {}, + ExpectedEPNodeAssignment::None, 13); + RunQDQArgMxxOpTest("ArgMin", + TestInputDef({1, 3, 4, 4, 4}, false, -10.0f, 10.0f), // Random input. + {}, + ExpectedEPNodeAssignment::None, 13); +} + +// Test that ArgMax/ArgMin are not supported if they generate a graph output. +TEST_F(QnnHTPBackendTests, ArgMaxMin_AsGraphOutputUnsupported) { + ProviderOptions provider_options; + +#if defined(_WIN32) + provider_options["backend_path"] = "QnnHtp.dll"; +#else + provider_options["backend_path"] = "libQnnHtp.so"; +#endif + + // Utility function that creates a QDQ model with ArgMax/ArgMin that produce a graph output. + auto model_builder_func = [](const std::string& op_type, const TestInputDef& input_def, + const std::vector& attrs) -> GetTestModelFn { + return [op_type, input_def, attrs](ModelTestBuilder& builder) { + QuantParams input_qparams = GetTestInputQuantParams(input_def); + + auto* input = MakeTestInput(builder, input_def); + auto* output = builder.MakeOutput(); + + // input -> Q -> DQ -> + auto* input_qdq = AddQDQNodePair(builder, input, input_qparams.scale, input_qparams.zero_point); + + Node& argm_node = builder.AddNode(op_type, {input_qdq}, {output}); + for (const auto& attr : attrs) { + argm_node.AddAttributeProto(attr); + } + }; + }; + + const int expected_nodes_in_graph = -1; // Don't care exactly how many nodes in graph assigned to CPU EP. + RunQnnModelTest(model_builder_func("ArgMax", TestInputDef({1, 3, 4}, false, -1.0f, 1.0f), {}), + provider_options, + 13, + ExpectedEPNodeAssignment::None, // No nodes should be assigned to QNN EP! + expected_nodes_in_graph); + RunQnnModelTest(model_builder_func("ArgMin", TestInputDef({1, 3, 4}, false, -1.0f, 1.0f), {}), + provider_options, + 13, + ExpectedEPNodeAssignment::None, // No nodes should be assigned to QNN EP! + expected_nodes_in_graph); +} + +#endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) +} // namespace test +} // namespace onnxruntime +#endif // !defined(ORT_MINIMAL_BUILD) diff --git a/onnxruntime/test/providers/qnn/average_pool_test.cc b/onnxruntime/test/providers/qnn/average_pool_test.cc index c3cb696507986..0ee52f7fec21a 100644 --- a/onnxruntime/test/providers/qnn/average_pool_test.cc +++ b/onnxruntime/test/providers/qnn/average_pool_test.cc @@ -5,7 +5,9 @@ #include #include +#include +#include "core/graph/node_attr_utils.h" #include "test/optimizer/qdq_test_utils.h" #include "test/providers/qnn/qnn_test_utils.h" @@ -16,102 +18,12 @@ namespace onnxruntime { namespace test { -// Returns a function that creates a graph with a single AveragePool operator. -static GetTestModelFn BuildAveragePoolTestCase(const std::vector& shape, - const std::vector& kernel_shape, - const std::vector& strides, - const std::vector& pads, - int64_t count_include_pad, - const std::string& auto_pad = "NOTSET") { - return [shape, kernel_shape, strides, pads, - count_include_pad, auto_pad](ModelTestBuilder& builder) { - // Random input data - auto input = builder.MakeInput(shape, 0.0f, 10.0f); - - auto* output = builder.MakeOutput(); - Node& pool_node = builder.AddNode("AveragePool", {input}, {output}); - - pool_node.AddAttribute("kernel_shape", kernel_shape); - - if (!strides.empty()) { - pool_node.AddAttribute("strides", strides); - } - - pool_node.AddAttribute("auto_pad", auto_pad); - - if (!pads.empty() && auto_pad == "NOTSET") { - pool_node.AddAttribute("pads", pads); - } - - if (count_include_pad > 0) { - pool_node.AddAttribute("count_include_pad", count_include_pad); - } - }; -} - -// Returns a function that creates a graph with a QDQ AveragePool operator. -template -GetQDQTestCaseFn BuildAveragePoolQDQTestCase(const std::vector& shape, - const std::vector& kernel_shape, - const std::vector& strides, - const std::vector& pads, - int64_t count_include_pad, - const std::string& auto_pad = "NOTSET") { - return [shape, kernel_shape, strides, pads, - count_include_pad, auto_pad](ModelTestBuilder& builder) { - float dq_scale = 0.0038f; - float pool_output_scale = 0.0038f; - float q_scale = 0.0038f; - QuantType dq_zp = std::numeric_limits::max() / 2; - QuantType pool_output_zp = std::numeric_limits::max() / 2; - QuantType q_zp = std::numeric_limits::max() / 2; - - auto* input_arg = builder.MakeInput(shape, -1.0f, 1.0f); - auto* output_arg = builder.MakeOutput(); - - // add QDQ + AveragePool - auto* dq_output = AddQDQNodePair(builder, input_arg, dq_scale, dq_zp); - auto* averagepool_output = builder.MakeIntermediate(); - Node& pool_node = builder.AddNode("AveragePool", {dq_output}, {averagepool_output}); - - pool_node.AddAttribute("kernel_shape", kernel_shape); - - if (!strides.empty()) { - pool_node.AddAttribute("strides", strides); - } - - pool_node.AddAttribute("auto_pad", auto_pad); - - if (!pads.empty() && auto_pad == "NOTSET") { - pool_node.AddAttribute("pads", pads); - } - - if (count_include_pad > 0) { - pool_node.AddAttribute("count_include_pad", count_include_pad); - } - - // add QDQ output - auto* q_output = builder.MakeIntermediate(); - builder.AddQuantizeLinearNode(averagepool_output, - pool_output_scale, - pool_output_zp, - q_output); - builder.AddDequantizeLinearNode(q_output, - q_scale, - q_zp, - output_arg); - }; -} - // Runs an AveragePool model on the QNN CPU backend. Checks the graph node assignment, and that inference // outputs for QNN and CPU match. -static void RunAveragePoolOpTest(const std::vector& shape, - const std::vector& kernel_shape, - const std::vector& strides, - const std::vector& pads, - int64_t count_include_pad, - const std::string& auto_pad, - ExpectedEPNodeAssignment expected_ep_assignment, const char* test_description, +static void RunAveragePoolOpTest(const std::string& op_type, + const std::vector>& input_defs, + const std::vector& attrs, + ExpectedEPNodeAssignment expected_ep_assignment, int opset = 18) { ProviderOptions provider_options; #if defined(_WIN32) @@ -120,26 +32,20 @@ static void RunAveragePoolOpTest(const std::vector& shape, provider_options["backend_path"] = "libQnnCpu.so"; #endif - constexpr int expected_nodes_in_partition = 1; - RunQnnModelTest(BuildAveragePoolTestCase(shape, kernel_shape, strides, pads, count_include_pad, auto_pad), + RunQnnModelTest(BuildOpTestCase(op_type, input_defs, {}, attrs), provider_options, opset, - expected_ep_assignment, - expected_nodes_in_partition, - test_description); + expected_ep_assignment); } -// Runs a QDQ AveragePool model on the QNN HTP backend. Checks the graph node assignment, and that inference -// outputs for QNN and CPU match. +// Runs a QDQ AveragePool model on the QNN HTP backend. Checks the graph node assignment, and that accuracy +// on QNN EP is at least as good as on CPU EP. template -static void RunQDQAveragePoolOpTest(const std::vector& shape, - const std::vector& kernel_shape, - const std::vector& strides, - const std::vector& pads, - int64_t count_include_pad, - const std::string& auto_pad, - ExpectedEPNodeAssignment expected_ep_assignment, const char* test_description, - int opset = 18, float fp32_abs_err = 1e-5f) { +static void RunQDQAveragePoolOpTest(const std::string& op_type, + const std::vector>& input_defs, + const std::vector& attrs, + ExpectedEPNodeAssignment expected_ep_assignment, + int opset = 18) { ProviderOptions provider_options; #if defined(_WIN32) provider_options["backend_path"] = "QnnHtp.dll"; @@ -147,15 +53,11 @@ static void RunQDQAveragePoolOpTest(const std::vector& shape, provider_options["backend_path"] = "libQnnHtp.so"; #endif - constexpr int expected_nodes_in_partition = 1; - RunQnnModelTest(BuildAveragePoolQDQTestCase(shape, kernel_shape, strides, pads, count_include_pad, - auto_pad), - provider_options, - opset, - expected_ep_assignment, - expected_nodes_in_partition, - test_description, - fp32_abs_err); + TestQDQModelAccuracy(BuildOpTestCase(op_type, input_defs, {}, attrs), + BuildQDQOpTestCase(op_type, input_defs, {}, attrs), + provider_options, + opset, + expected_ep_assignment); } // @@ -163,47 +65,49 @@ static void RunQDQAveragePoolOpTest(const std::vector& shape, // // AveragePool with kernel size equal to the spatial dimension of input tensor. -TEST_F(QnnCPUBackendTests, TestAveragePool_Global) { - RunAveragePoolOpTest({1, 2, 3, 3}, // shape - {3, 3}, // kernel_shape - {3, 3}, // strides - {0, 0, 0, 0}, // pads - 0, // count_include_pad - "NOTSET", - ExpectedEPNodeAssignment::All, "TestAveragePool_Global"); +TEST_F(QnnCPUBackendTests, AveragePool_AsGlobal) { + RunAveragePoolOpTest("AveragePool", + {TestInputDef({1, 2, 3, 3}, false, GetFloatDataInRange(-10.0f, 10.0f, 18))}, + {utils::MakeAttribute("kernel_shape", std::vector{3, 3}), + utils::MakeAttribute("strides", std::vector{3, 3})}, + ExpectedEPNodeAssignment::All); +} + +// Test GlobalAveragePool on QNN CPU backend. +TEST_F(QnnCPUBackendTests, GlobalAveragePool) { + RunAveragePoolOpTest("GlobalAveragePool", + {TestInputDef({1, 2, 3, 3}, false, GetFloatDataInRange(-10.0f, 10.0f, 18))}, + {}, + ExpectedEPNodeAssignment::All); } // AveragePool that counts padding. -TEST_F(QnnCPUBackendTests, TestAveragePool_CountIncludePad) { - RunAveragePoolOpTest({1, 2, 3, 3}, // shape - {1, 1}, // kernel_shape - {1, 1}, // strides - {0, 0, 0, 0}, // pads - 1, // count_include_pad - "NOTSET", - ExpectedEPNodeAssignment::All, "TestAveragePool_CountIncludePad"); +TEST_F(QnnCPUBackendTests, AveragePool_CountIncludePad) { + RunAveragePoolOpTest("AveragePool", + {TestInputDef({1, 2, 3, 3}, false, GetFloatDataInRange(-10.0f, 10.0f, 18))}, + {utils::MakeAttribute("kernel_shape", std::vector{1, 1}), + utils::MakeAttribute("count_include_pad", static_cast(1))}, + ExpectedEPNodeAssignment::All); } // AveragePool that use auto_pad 'SAME_UPPER'. -TEST_F(QnnCPUBackendTests, TestAveragePool_AutopadSameUpper) { - RunAveragePoolOpTest({1, 2, 3, 3}, // shape - {1, 1}, // kernel_shape - {1, 1}, // strides - {}, // pads - 1, // count_include_pad - "SAME_UPPER", - ExpectedEPNodeAssignment::All, "TestAveragePool_CountIncludePad"); +TEST_F(QnnCPUBackendTests, AveragePool_AutopadSameUpper) { + RunAveragePoolOpTest("AveragePool", + {TestInputDef({1, 2, 3, 3}, false, GetFloatDataInRange(-10.0f, 10.0f, 18))}, + {utils::MakeAttribute("kernel_shape", std::vector{1, 1}), + utils::MakeAttribute("count_include_pad", static_cast(1)), + utils::MakeAttribute("auto_pad", "SAME_UPPER")}, + ExpectedEPNodeAssignment::All); } // AveragePool that use auto_pad 'SAME_LOWER'. -TEST_F(QnnCPUBackendTests, TestAveragePool_AutopadSameLower) { - RunAveragePoolOpTest({1, 2, 3, 3}, // shape - {1, 1}, // kernel_shape - {1, 1}, // strides - {}, // pads - 1, // count_include_pad - "SAME_LOWER", - ExpectedEPNodeAssignment::All, "TestAveragePool_CountIncludePad"); +TEST_F(QnnCPUBackendTests, AveragePool_AutopadSameLower) { + RunAveragePoolOpTest("AveragePool", + {TestInputDef({1, 2, 3, 3}, false, GetFloatDataInRange(-10.0f, 10.0f, 18))}, + {utils::MakeAttribute("kernel_shape", std::vector{1, 1}), + utils::MakeAttribute("count_include_pad", static_cast(1)), + utils::MakeAttribute("auto_pad", "SAME_LOWER")}, + ExpectedEPNodeAssignment::All); } #if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) @@ -212,50 +116,63 @@ TEST_F(QnnCPUBackendTests, TestAveragePool_AutopadSameLower) { // // QDQ AveragePool with kernel size equal to the spatial dimension of input tensor. -TEST_F(QnnHTPBackendTests, TestAveragePool_Global_HTP_u8) { - RunQDQAveragePoolOpTest({1, 2, 3, 3}, // shape - {3, 3}, // kernel_shape - {3, 3}, // strides - {0, 0, 0, 0}, // pads - 0, // count_include_pad - "NOTSET", - ExpectedEPNodeAssignment::All, "TestAveragePool_Global_HTP_u8"); +TEST_F(QnnHTPBackendTests, AveragePool_AsGlobal) { + std::vector input = {32.1289f, -59.981f, -17.2799f, 62.7263f, 33.6205f, -19.3515f, -54.0113f, 37.5648f, 61.5357f, + -52.5769f, 27.3637f, -9.01382f, -65.5612f, 19.9497f, -47.9228f, 26.9813f, 83.064f, 0.362503f}; + RunQDQAveragePoolOpTest("AveragePool", + {TestInputDef({1, 2, 3, 3}, false, input)}, + {utils::MakeAttribute("kernel_shape", std::vector{3, 3}), + utils::MakeAttribute("strides", std::vector{3, 3})}, + ExpectedEPNodeAssignment::All); +} + +// Test accuracy for 8-bit QDQ GlobalAveragePool with input of rank 4. +TEST_F(QnnHTPBackendTests, GlobalAveragePool) { + std::vector input = GetFloatDataInRange(-32.0f, 32.0f, 18); + + RunQDQAveragePoolOpTest("GlobalAveragePool", + {TestInputDef({1, 2, 3, 3}, false, input)}, + {}, + ExpectedEPNodeAssignment::All); } // QDQ AveragePool that counts padding. -TEST_F(QnnHTPBackendTests, TestAveragePool_CountIncludePad_HTP_u8) { - RunQDQAveragePoolOpTest({1, 2, 3, 3}, // shape - {1, 1}, // kernel_shape - {1, 1}, // strides - {0, 0, 0, 0}, // pads - 1, // count_include_pad - "NOTSET", - ExpectedEPNodeAssignment::All, "TestAveragePool_CountIncludePad_HTP_u8", - 18, 0.00381f); +TEST_F(QnnHTPBackendTests, AveragePool_CountIncludePad_HTP_u8) { + std::vector input = {-9.0f, -7.33f, -6.0f, -5.0f, -4.0f, -3.0f, -2.0f, -1.0f, 0.0f, + 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f}; + + RunQDQAveragePoolOpTest("AveragePool", + {TestInputDef({1, 2, 3, 3}, false, input)}, + {utils::MakeAttribute("kernel_shape", std::vector{1, 1}), + utils::MakeAttribute("count_include_pad", static_cast(1))}, + ExpectedEPNodeAssignment::All, + 18); } // QDQ AveragePool that use auto_pad 'SAME_UPPER'. -TEST_F(QnnHTPBackendTests, TestAveragePool_AutopadSameUpper_HTP_u8) { - RunQDQAveragePoolOpTest({1, 2, 3, 3}, // shape - {1, 1}, // kernel_shape - {1, 1}, // strides - {}, // pads - 0, // count_include_pad - "SAME_UPPER", - ExpectedEPNodeAssignment::All, "TestAveragePool_AutopadSameUpper_HTP_u8", - 18, 0.00381f); +TEST_F(QnnHTPBackendTests, AveragePool_AutopadSameUpper_HTP_u8) { + std::vector input = {-9.0f, -7.33f, -6.0f, -5.0f, -4.0f, -3.0f, -2.0f, -1.0f, 0.0f, + 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f}; + + RunQDQAveragePoolOpTest("AveragePool", + {TestInputDef({1, 2, 3, 3}, false, input)}, + {utils::MakeAttribute("kernel_shape", std::vector{1, 1}), + utils::MakeAttribute("auto_pad", "SAME_UPPER")}, + ExpectedEPNodeAssignment::All, + 18); } // QDQ AveragePool that use auto_pad 'SAME_LOWER'. -TEST_F(QnnHTPBackendTests, TestAveragePool_AutopadSameLower_HTP_u8) { - RunQDQAveragePoolOpTest({1, 2, 3, 3}, // shape - {1, 1}, // kernel_shape - {1, 1}, // strides - {}, // pads - 0, // count_include_pad - "SAME_LOWER", - ExpectedEPNodeAssignment::All, "TestAveragePool_AutopadSameLower_HTP_u8", - 18, 0.00381f); +TEST_F(QnnHTPBackendTests, AveragePool_AutopadSameLower_HTP_u8) { + std::vector input = {-9.0f, -7.33f, -6.0f, -5.0f, -4.0f, -3.0f, -2.0f, -1.0f, 0.0f, + 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f}; + + RunQDQAveragePoolOpTest("AveragePool", + {TestInputDef({1, 2, 3, 3}, false, input)}, + {utils::MakeAttribute("kernel_shape", std::vector{1, 1}), + utils::MakeAttribute("auto_pad", "SAME_LOWER")}, + ExpectedEPNodeAssignment::All, + 18); } #endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) diff --git a/onnxruntime/test/providers/qnn/batch_norm_htp_test.cc b/onnxruntime/test/providers/qnn/batch_norm_htp_test.cc index 850c60d73c799..9b65ca7bda3e2 100644 --- a/onnxruntime/test/providers/qnn/batch_norm_htp_test.cc +++ b/onnxruntime/test/providers/qnn/batch_norm_htp_test.cc @@ -15,53 +15,133 @@ namespace onnxruntime { namespace test { #if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) -// Creates the graph: -// _______________________ -// input_u8 -> DQ -> | | -// scale_u8 (initializer) -> DQ -> | | -// bias_u8 (initializer) -> DQ -> | BatchNormalization | -> Q -> output_u8 -// mean_u8 (initializer) -> DQ -> | | -// var_u8 (initializer) -> DQ -> |_______________________| -// -// Currently used to test QNN EP. +// Computes the mean and variance of inputs within a channel. +// Requires an input with rank >= 3 +static void ComputeChannelMeanAndVar(const std::vector& input_data, const std::vector& input_shape, + std::vector& mean_vals, std::vector& var_vals) { + const size_t input_rank = input_shape.size(); + const size_t num_batches = input_shape[0]; + const size_t num_channels = input_shape[1]; + + size_t batch_stride = 1; + for (size_t i = 1; i < input_rank; i++) { + batch_stride *= input_shape[i]; + } + const size_t channel_stride = batch_stride / num_channels; + + assert(mean_vals.size() == num_channels); + assert(var_vals.size() == num_channels); + for (size_t i = 0; i < num_channels; i++) { + mean_vals[i] = 0.0f; + var_vals[i] = 0.0f; + } + + // Compute running sum of elements within each channel. The running sum is stored in the mean_vals array directly. + for (size_t b = 0; b < num_batches; b++) { + const size_t batch_start = b * batch_stride; + + for (size_t c = 0; c < num_channels; c++) { + const size_t chan_start = batch_start + (c * channel_stride); + + for (size_t i = chan_start; i < chan_start + channel_stride; i++) { + mean_vals[c] += input_data[i]; + } + } + } + + // Divide sums by the number of elements in a channel to get the mean. + for (size_t c = 0; c < num_channels; c++) { + mean_vals[c] /= static_cast(num_batches * channel_stride); + } + + // Compute running sum of deviations from mean within each channel. The running sum is stored in the var_vals array directly. + for (size_t b = 0; b < num_batches; b++) { + const size_t batch_start = b * batch_stride; + + for (size_t c = 0; c < num_channels; c++) { + const size_t chan_start = batch_start + (c * channel_stride); + + for (size_t i = chan_start; i < chan_start + channel_stride; i++) { + const float deviation = input_data[i] - mean_vals[c]; + var_vals[c] += (deviation * deviation); + } + } + } + + // Divide sums by the number of elements in a channel to get the variance. + for (size_t c = 0; c < num_channels; c++) { + var_vals[c] /= static_cast(num_batches * channel_stride); + } +} + +static GetTestModelFn BuildBatchNormTestCase(const TestInputDef& input_def, + const TestInputDef& scale_def, + const TestInputDef& bias_def) { + ORT_ENFORCE(input_def.IsRawData()); // Need raw data to compute mean and variance inputs. + ORT_ENFORCE(input_def.GetShape().size() > 2); // Need at least rank 3 data for convenience. + + return [input_def, scale_def, bias_def](ModelTestBuilder& builder) { + const auto& input_shape = input_def.GetShape(); + const auto& input_data = input_def.GetRawData(); + const int64_t num_channels = input_shape[1]; + + NodeArg* input = MakeTestInput(builder, input_def); + NodeArg* scale = MakeTestInput(builder, scale_def); + NodeArg* bias = MakeTestInput(builder, bias_def); + + std::vector mean_vals(num_channels); + std::vector var_vals(num_channels); + ComputeChannelMeanAndVar(input_data, input_shape, mean_vals, var_vals); + + NodeArg* mean = builder.MakeInitializer({num_channels}, mean_vals); + NodeArg* var = builder.MakeInitializer({num_channels}, var_vals); + NodeArg* output = builder.MakeOutput(); + builder.AddNode("BatchNormalization", {input, scale, bias, mean, var}, {output}); + }; +} + template -GetQDQTestCaseFn BuildQDQBatchNormTestCase(const std::vector& input_shape) { - return [input_shape](ModelTestBuilder& builder) { +GetTestQDQModelFn BuildQDQBatchNormTestCase(const TestInputDef& input_def, + const TestInputDef& scale_def, + const TestInputDef& bias_def) { + ORT_ENFORCE(input_def.IsRawData()); // Need raw data to compute mean and variance inputs. + ORT_ENFORCE(input_def.GetShape().size() > 2); // Need at least rank 3 data for convenience. + + return [input_def, scale_def, bias_def](ModelTestBuilder& builder, + std::vector>& output_qparams) { + const auto& input_shape = input_def.GetShape(); + const auto& input_data = input_def.GetRawData(); const int64_t num_channels = input_shape[1]; - const InputQType quant_zero_point = 0; - const float quant_scale = 1.0f; - auto* input = builder.MakeInput(input_shape, std::numeric_limits::min(), - std::numeric_limits::max()); - auto* dq_input = builder.MakeIntermediate(); - builder.AddDequantizeLinearNode(input, 0.0039f, quant_zero_point, dq_input); + NodeArg* input = MakeTestInput(builder, input_def); + QuantParams input_qparams = GetTestInputQuantParams(input_def); + NodeArg* input_qdq = AddQDQNodePair(builder, input, input_qparams.scale, input_qparams.zero_point); - auto* dq_scale_output = builder.MakeIntermediate(); - auto* scale = builder.MakeInitializer({num_channels}, static_cast(1), static_cast(127)); - builder.AddDequantizeLinearNode(scale, 0.0028f, quant_zero_point, dq_scale_output); + NodeArg* scale = MakeTestInput(builder, scale_def); + QuantParams scale_qparams = GetTestInputQuantParams(scale_def); + NodeArg* scale_qdq = AddQDQNodePair(builder, scale, scale_qparams.scale, scale_qparams.zero_point); - auto* dq_bias_output = builder.MakeIntermediate(); - auto* bias = builder.MakeInitializer({num_channels}, std::vector(num_channels)); - builder.AddDequantizeLinearNode(bias, quant_scale, quant_zero_point, dq_bias_output); + NodeArg* bias = MakeTestInput(builder, bias_def); + QuantParams bias_qparams = GetTestInputQuantParams(bias_def); + NodeArg* bias_qdq = AddQDQNodePair(builder, bias, bias_qparams.scale, bias_qparams.zero_point); - auto* dq_mean_output = builder.MakeIntermediate(); - auto* mean = builder.MakeInitializer({num_channels}, std::vector(num_channels)); - builder.AddDequantizeLinearNode(mean, quant_scale, quant_zero_point, dq_mean_output); + std::vector mean_vals(num_channels); + std::vector var_vals(num_channels); + ComputeChannelMeanAndVar(input_data, input_shape, mean_vals, var_vals); - auto* dq_var_output = builder.MakeIntermediate(); - auto* var = builder.MakeInitializer({num_channels}, std::vector(num_channels, 255)); - builder.AddDequantizeLinearNode(var, 0.003921f, 0, dq_var_output); + NodeArg* mean = builder.MakeInitializer({num_channels}, mean_vals); + QuantParams mean_qparams = GetDataQuantParams(mean_vals); + NodeArg* mean_qdq = AddQDQNodePair(builder, mean, mean_qparams.scale, mean_qparams.zero_point); - auto* batchnorm_output = builder.MakeIntermediate(); - builder.AddNode("BatchNormalization", {dq_input, dq_scale_output, dq_bias_output, dq_mean_output, dq_var_output}, {batchnorm_output}); + NodeArg* var = builder.MakeInitializer({num_channels}, var_vals); + QuantParams var_qparams = GetDataQuantParams(var_vals); + NodeArg* var_qdq = AddQDQNodePair(builder, var, var_qparams.scale, var_qparams.zero_point); - auto* q_output = builder.MakeIntermediate(); - builder.AddQuantizeLinearNode(batchnorm_output, 0.00377f, quant_zero_point, q_output); + auto* batchnorm_output = builder.MakeIntermediate(); + builder.AddNode("BatchNormalization", {input_qdq, scale_qdq, bias_qdq, mean_qdq, var_qdq}, + {batchnorm_output}); - auto* final_output = builder.MakeOutput(); - builder.AddDequantizeLinearNode(q_output, 0.00377f, - quant_zero_point, - final_output); + AddQDQNodePairWithOutputAsGraphOutput(builder, batchnorm_output, output_qparams[0].scale, output_qparams[0].zero_point); }; } @@ -70,12 +150,12 @@ GetQDQTestCaseFn BuildQDQBatchNormTestCase(const std::vector& input_sha * outputs for QNN and CPU match. * * \param input_shape The input's shape. - * \param test_description Description of the test for error reporting. * \param expected_ep_assignment How many nodes are expected to be assigned to QNN (All, Some, or None). - * \param num_modes_in_graph The number of expected nodes in the graph. */ -static void RunBatchNormQDQTest(const std::vector& input_shape, const char* test_description, - ExpectedEPNodeAssignment expected_ep_assignment, int num_nodes_in_graph) { +static void RunBatchNormQDQTest(const TestInputDef& input_def, + const TestInputDef& scale_def, + const TestInputDef& bias_def, + ExpectedEPNodeAssignment expected_ep_assignment) { ProviderOptions provider_options; #if defined(_WIN32) provider_options["backend_path"] = "QnnHtp.dll"; @@ -84,30 +164,61 @@ static void RunBatchNormQDQTest(const std::vector& input_shape, const c #endif // Runs model with DQ-> InstanceNorm -> Q and compares the outputs of the CPU and QNN EPs. - RunQnnModelTest(BuildQDQBatchNormTestCase(input_shape), - provider_options, - 11, - expected_ep_assignment, - num_nodes_in_graph, - test_description); + TestQDQModelAccuracy(BuildBatchNormTestCase(input_def, scale_def, bias_def), + BuildQDQBatchNormTestCase(input_def, scale_def, bias_def), + provider_options, + 11, + expected_ep_assignment, + 1e-5f); } +// TODO: FIX TRANSLATION!!! // Check that QNN compiles DQ -> BatchNormalization -> Q as a single unit. // Use an input of rank 3. -TEST_F(QnnHTPBackendTests, TestQDQBatchNorm1D) { - RunBatchNormQDQTest({1, 2, 3}, "TestQDQBatchNorm1D", ExpectedEPNodeAssignment::All, 1); +// QNN v2.13 +// Inaccuracy detected for output 'output', element 4. +// Output quant params: scale=0.019084848463535309, zero_point=9. +// Expected val: 1.7755576372146606 +// QNN QDQ val: 2.9963212013244629 (err 1.2207635641098022) +// CPU QDQ val: 0.82064849138259888 (err 0.95490914583206177) +TEST_F(QnnHTPBackendTests, DISABLED_BatchNorm1D) { + constexpr int64_t num_channels = 2; + + RunBatchNormQDQTest(TestInputDef({1, num_channels, 3}, false, {-5.0f, -4.0f, -3.0f, 0.0f, 2.0f, 5.0f}), // Input data + TestInputDef({num_channels}, true, {1.0f, 2.0f}), // Scale initializer + TestInputDef({num_channels}, true, {1.1f, 2.1f}), // Bias initializer + ExpectedEPNodeAssignment::All); } +// TODO: FIX TRANSLATION!!! // Check that QNN compiles DQ -> BatchNormalization -> Q as a single unit. // Use an input of rank 4. -TEST_F(QnnHTPBackendTests, TestQDQBatchNorm2D) { - RunBatchNormQDQTest({2, 3, 4, 5}, "TestQDQBatchNorm2D", ExpectedEPNodeAssignment::All, 1); +// QNN v2.13 +// Inaccuracy detected for output 'output', element 14. +// Output quant params: scale=0.023071292787790298, zero_point=19. +// Expected val: 2.8554618358612061 +// QNN QDQ val: 5.3294687271118164 (err 2.4740068912506104) +// CPU QDQ val: 1.6611330509185791 (err 1.194328784942627) +TEST_F(QnnHTPBackendTests, DISABLED_BatchNorm2D) { + constexpr int64_t num_channels = 2; + std::vector input_data = {-8.0f, -6.0f, -4.0f, -2.0f, 0.0f, 1.1f, 3.3f, 8.0f, + -7.0f, -5.0f, -3.0f, -1.0f, 0.0f, 2.1f, 4.3f, 7.0f}; + + RunBatchNormQDQTest(TestInputDef({2, num_channels, 2, 2}, false, input_data), // Input data + TestInputDef({num_channels}, true, {1.0f, 2.0f}), // Scale initializer + TestInputDef({num_channels}, true, {1.1f, 2.1f}), // Bias initializer + ExpectedEPNodeAssignment::All); } // Check that QNN compiles DQ -> BatchNormalization -> Q as a single unit. // Use an input of rank 5. QNN BatchNormalization doesn't support 5D on HTP -TEST_F(QnnHTPBackendTests, TestQDQBatchNorm3D) { - RunBatchNormQDQTest({1, 2, 3, 4, 5}, "TestQDQBatchNorm3D", ExpectedEPNodeAssignment::None, 8); +TEST_F(QnnHTPBackendTests, BatchNorm3D) { + constexpr int64_t num_channels = 2; + constexpr int64_t num_elems = 1 * num_channels * 3 * 4 * 5; + RunBatchNormQDQTest(TestInputDef({1, num_channels, 3, 4, 5}, false, std::vector(num_elems)), // Input data (all zeros) + TestInputDef({num_channels}, true, {1.0f, 2.0f}), // Scale initializer + TestInputDef({num_channels}, true, {1.1f, 2.1f}), // Bias initializer + ExpectedEPNodeAssignment::None); } #endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) diff --git a/onnxruntime/test/providers/qnn/cast_test.cc b/onnxruntime/test/providers/qnn/cast_test.cc index aa566faf851db..0b2d168b06ca1 100644 --- a/onnxruntime/test/providers/qnn/cast_test.cc +++ b/onnxruntime/test/providers/qnn/cast_test.cc @@ -43,13 +43,12 @@ static GetTestModelFn BuildCastTestCase(const std::vector& shape, * * \param shape The shape of the input and output. Input data is randomly generated with this shape. * \param dst_type The destination type as an instance of the DataType enum in TensorProto. - * \param test_description Description of the test for error reporting. * \param expected_ep_assignment How many nodes are expected to be assigned to QNN (All, Some, or None). * \param use_htp True to run on HTP backend. Otherwise, runs on CPU. */ template static void RunCastOpTest(const std::vector& shape, ONNX_NAMESPACE::TensorProto_DataType dst_type, - ExpectedEPNodeAssignment expected_ep_assignment, const char* test_description, + ExpectedEPNodeAssignment expected_ep_assignment, bool use_htp) { ProviderOptions provider_options; #if defined(_WIN32) @@ -58,13 +57,10 @@ static void RunCastOpTest(const std::vector& shape, ONNX_NAMESPACE::Ten provider_options["backend_path"] = use_htp ? "libQnnHtp.so" : "libQnnCpu.so"; #endif - constexpr int expected_nodes_in_partition = 1; RunQnnModelTest(BuildCastTestCase(shape, dst_type), provider_options, 13, // opset - expected_ep_assignment, - expected_nodes_in_partition, - test_description); + expected_ep_assignment); } // @@ -74,19 +70,19 @@ static void RunCastOpTest(const std::vector& shape, ONNX_NAMESPACE::Ten // Cast int32_t to float on CPU TEST_F(QnnCPUBackendTests, TestCastInt32ToFloat) { RunCastOpTest({2, 3}, ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_FLOAT, ExpectedEPNodeAssignment::All, - "TestCastInt32ToFloat", false); + false); } // Cast uint8_t to float on CPU TEST_F(QnnCPUBackendTests, TestCastUInt8ToFloat) { RunCastOpTest({2, 3}, ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_FLOAT, ExpectedEPNodeAssignment::All, - "TestCastUInt8ToFloat", false); + false); } // Cast float to int32_t on CPU TEST_F(QnnCPUBackendTests, TestCastFloatToInt32) { RunCastOpTest({2, 3}, ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_INT32, ExpectedEPNodeAssignment::All, - "TestCastInt32ToFloat", false); + false); } #if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) @@ -97,19 +93,19 @@ TEST_F(QnnCPUBackendTests, TestCastFloatToInt32) { // Cast int32_t to float on HTP TEST_F(QnnHTPBackendTests, TestCastInt32ToFloatHTP) { RunCastOpTest({3, 3}, ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_FLOAT, ExpectedEPNodeAssignment::All, - "TestCastInt32ToFloatHTP", true); + true); } // Cast uint8_t to float on HTP TEST_F(QnnHTPBackendTests, TestCastUInt8ToFloatHTP) { RunCastOpTest({3, 3}, ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_FLOAT, ExpectedEPNodeAssignment::All, - "TestCastUInt8ToFloatHTP", true); + true); } // Cast float to int32_t on HTP TEST_F(QnnHTPBackendTests, TestCastFloatToInt32HTP) { RunCastOpTest({3, 3}, ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_INT32, ExpectedEPNodeAssignment::All, - "TestCastFloatToInt32HTP", true); + true); } #endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) diff --git a/onnxruntime/test/providers/qnn/clip_op_test.cc b/onnxruntime/test/providers/qnn/clip_op_test.cc new file mode 100644 index 0000000000000..15ba3b5de2fa1 --- /dev/null +++ b/onnxruntime/test/providers/qnn/clip_op_test.cc @@ -0,0 +1,188 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#if !defined(ORT_MINIMAL_BUILD) + +#include + +#include "test/providers/qnn/qnn_test_utils.h" +#include "core/graph/node_attr_utils.h" + +#include "onnx/onnx_pb.h" +#include "gtest/gtest.h" + +namespace onnxruntime { +namespace test { + +// Runs a model with a Clip operator on the QNN CPU backend. Checks the graph node assignment +// and that inference outputs for QNN EP and CPU EP match. +template +static void RunClipTestOnCPU(const TestInputDef& input_def, + const std::vector>& min_max_defs, + 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 + + RunQnnModelTest(BuildOpTestCase("Clip", {input_def}, min_max_defs, {}), + provider_options, + opset, + expected_ep_assignment); +} + +// +// CPU tests: +// + +// Test that Clip with a dynamic min or max input is not supported by QNN EP. +TEST_F(QnnCPUBackendTests, Clip_Dynamic_MinMax_Unsupported) { + // Dynamic min input is not supported. + RunClipTestOnCPU(TestInputDef({1, 3, 4, 4}, false, -10.0f, 10.0f), + {TestInputDef({}, false /* is_initializer */, {-5.0f})}, + ExpectedEPNodeAssignment::None); // Should not be assigned to QNN EP. + // Dynamic max input is not supported. + RunClipTestOnCPU(TestInputDef({1, 3, 4, 4}, false, -10.0f, 10.0f), + {TestInputDef({}, true, {-5.0f}), + TestInputDef({}, false, {5.0f})}, + ExpectedEPNodeAssignment::None); // Should not be assigned to QNN EP. +} + +// Test Clip with default min/max. +TEST_F(QnnCPUBackendTests, Clip_4D_f32_DefaultMinMax) { + RunClipTestOnCPU(TestInputDef({1, 3, 4, 4}, false, GetFloatDataInRange(-10.0f, 10.0f, 48)), + {}, // Don't specify min/max inputs. + ExpectedEPNodeAssignment::All); +} + +// Test Clip with 5D input. +TEST_F(QnnCPUBackendTests, Clip_5D_f32) { + RunClipTestOnCPU(TestInputDef({1, 1, 3, 4, 4}, false, GetFloatDataInRange(-10.0f, 10.0f, 48)), + {TestInputDef({}, true, {-5.0f}), + TestInputDef({}, true, {5.0f})}, + ExpectedEPNodeAssignment::All); +} + +#if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) +// +// HTP tests: +// + +// Runs a QDQ Clip model on the QNN (HTP) EP and the ORT CPU EP. Checks the graph node assignment and that inference +// running the QDQ model on QNN EP is at least as accurate as on ORT CPU EP (compared to the baseline float32 model). +template +static void RunQDQClipTestOnHTP(const TestInputDef& input_def, + const std::vector>& min_max_defs, + ExpectedEPNodeAssignment expected_ep_assignment, + 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 + + auto f32_model_builder = BuildOpTestCase("Clip", {input_def}, {min_max_defs}, {}); + auto qdq_model_builder = BuildQDQOpTestCase("Clip", {input_def}, {min_max_defs}, {}, + kOnnxDomain, use_contrib_qdq); + + TestQDQModelAccuracy(f32_model_builder, + qdq_model_builder, + provider_options, + opset, + expected_ep_assignment); +} + +// Test 8-bit QDQ Clip with default min/max. +// NOTE: The Clip operator is *optimized* away during L1 optimizations, so QNN EP does not get a graph with a Clip op. +// Instead, QNN EP will get a graph with a Q -> DQ. +// - Original sequence: Q1 -> DQ1 -> Clip -> Q2 -> DQ2 +// - ClipQuantFusion: Fuses Clip -> QuantizeLinear resulting in Q1 -> DQ1 -> Q2' -> DQ2 +// - DoubleQDQPairsRemover: Simplifies remaining Q1 -> DQ1 -> Q2' -> DQ2 sequence to Q1 -> DQ2. +TEST_F(QnnHTPBackendTests, Clip_U8_DefaultMinMax_Rank4) { + RunQDQClipTestOnHTP(TestInputDef({1, 3, 4, 4}, false, GetFloatDataInRange(-10.0f, 10.0f, 48)), + {}, // Don't specify min/max inputs. + ExpectedEPNodeAssignment::All); +} + +// Test 16-bit QDQ Clip with default min/max. +// NOTE: The Clip operator is *optimized* away during L1 optimizations, so QNN EP does not get a graph with a Clip op. +// Instead, QNN EP will get a graph with a Q -> DQ. +// - Original sequence: Q1 -> DQ1 -> Clip -> Q2 -> DQ2 +// - ClipQuantFusion: Fuses Clip -> QuantizeLinear resulting in Q1 -> DQ1 -> Q2' -> DQ2 +// - DoubleQDQPairsRemover: Simplifies remaining Q1 -> DQ1 -> Q2' -> DQ2 sequence to Q1 -> DQ2. +TEST_F(QnnHTPBackendTests, Clip_U16_DefaultMinMax_Rank4) { + RunQDQClipTestOnHTP(TestInputDef({1, 3, 4, 4}, false, GetFloatDataInRange(-10.0f, 10.0f, 48)), + {}, // Don't specify min/max inputs. + ExpectedEPNodeAssignment::All, + 13, // opset + true); // Use com.microsoft Q/DQ ops +} + +// Test 8-bit QDQ Clip with non-default min and max inputs. QNN EP will get a graph with a Clip operator. +TEST_F(QnnHTPBackendTests, Clip_U8_Rank4) { + RunQDQClipTestOnHTP(TestInputDef({1, 3, 4, 4}, false, GetFloatDataInRange(-10.0f, 10.0f, 48)), + {TestInputDef({}, true, {-5.0f}), + TestInputDef({}, true, {5.0f})}, + ExpectedEPNodeAssignment::All); +} + +// Test 16-bit QDQ Clip with non-default min and max inputs. QNN EP will get a graph with a Clip operator. +TEST_F(QnnHTPBackendTests, Clip_U16_Rank4) { + RunQDQClipTestOnHTP(TestInputDef({1, 3, 4, 4}, false, GetFloatDataInRange(-10.0f, 10.0f, 48)), + {TestInputDef({}, true, {-5.0f}), + TestInputDef({}, true, {5.0f})}, + ExpectedEPNodeAssignment::All, + 13, // opset + true); // Use com.microsoft Q/DQ ops +} + +// Test QDQ Clip of rank 5. +TEST_F(QnnHTPBackendTests, Clip_U8_Rank5) { + // We can't use the usual model-building functions because they add standalone Quantize and Dequantize nodes + // at the input and output. These Q/DQ ops get lowered to QNN's Quantize and Dequantize operators, which DO NOT + // support rank 5 tensors. Therefore, we have to create a test model that only instantiates the DQ -> Clip -> Q + // QDQ node group, which gets lowered to a single QNN Clip node. + GetTestModelFn model_fn = [](ModelTestBuilder& builder) { + // input (u8) -> DQ -> + NodeArg* quant_input = builder.MakeInput({1, 1, 2, 2, 2}, {0, 1, 6, 10, 20, 100, 128, 255}); + NodeArg* input_dq = builder.MakeIntermediate(); + builder.AddDequantizeLinearNode(quant_input, 1.0f, 0, input_dq); // scale = 1.0, zp = 0 + + // Min/Max initializers + NodeArg* min_input = builder.MakeScalarInitializer(5.0f); + NodeArg* max_input = builder.MakeScalarInitializer(100.0f); + + // Clip -> + NodeArg* clip_output = builder.MakeIntermediate(); + builder.AddNode("Clip", {input_dq, min_input, max_input}, {clip_output}); + + // Q -> output (u8) + NodeArg* output = builder.MakeOutput(); + builder.AddQuantizeLinearNode(clip_output, 1.0f, 0, output); // scale = 1.0, zp = 0 + }; + + ProviderOptions provider_options; + +#if defined(_WIN32) + provider_options["backend_path"] = "QnnHtp.dll"; +#else + provider_options["backend_path"] = "libQnnHtp.so"; +#endif + + RunQnnModelTest(model_fn, + provider_options, + 13, // opset + ExpectedEPNodeAssignment::All); +} + +#endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) +} // namespace test +} // namespace onnxruntime +#endif // !defined(ORT_MINIMAL_BUILD) diff --git a/onnxruntime/test/providers/qnn/conv_htp_test.cc b/onnxruntime/test/providers/qnn/conv_htp_test.cc deleted file mode 100644 index 2412166d3cb39..0000000000000 --- a/onnxruntime/test/providers/qnn/conv_htp_test.cc +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#if !defined(ORT_MINIMAL_BUILD) - -#include -#include "core/graph/graph.h" - -#include "test/optimizer/qdq_test_utils.h" -#include "test/providers/qnn/qnn_test_utils.h" - -#include "gtest/gtest.h" - -namespace onnxruntime { -namespace test { -#if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) - -// Check that QNN compiles DQ -> Conv -> Q as a single unit. -TEST_F(QnnHTPBackendTests, TestQDQConvU8U8S32) { - ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif - - RunQnnModelTest(BuildQDQConvTestCase({1, 1, 5, 5}, // Input shape - {1, 1, 3, 3}), // Weights shape - provider_options, - 18, // Opset - ExpectedEPNodeAssignment::All, // All nodes assigned to QNN EP. - 1, // Expect 1 fused node in graph. - "QDQConvU8U8S32"); -} -#endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) - -} // namespace test -} // namespace onnxruntime - -#endif \ No newline at end of file diff --git a/onnxruntime/test/providers/qnn/conv_test.cc b/onnxruntime/test/providers/qnn/conv_test.cc new file mode 100644 index 0000000000000..0549051bc2387 --- /dev/null +++ b/onnxruntime/test/providers/qnn/conv_test.cc @@ -0,0 +1,861 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#if !defined(ORT_MINIMAL_BUILD) + +#include +#include "core/graph/graph.h" + +#include "test/providers/qnn/qnn_test_utils.h" + +#include "gtest/gtest.h" + +namespace onnxruntime { +namespace test { + +// Creates a graph with a single float32 Conv operator. Used for testing CPU backend. +static GetTestModelFn BuildF32ConvTestCase(const std::string& conv_op_type, const TestInputDef& input_def, + const TestInputDef& weights_def, + const TestInputDef& bias_def, + const std::vector& strides, + const std::vector& pads, + const std::vector& dilations, + const std::string& auto_pad = "NOTSET") { + return [conv_op_type, input_def, weights_def, bias_def, strides, pads, + dilations, auto_pad](ModelTestBuilder& builder) { + std::vector conv_inputs = { + MakeTestInput(builder, input_def), + MakeTestInput(builder, weights_def)}; + + if (!bias_def.GetShape().empty()) { + conv_inputs.push_back(MakeTestInput(builder, bias_def)); + } + + auto* output = builder.MakeOutput(); + + Node& convNode = builder.AddNode(conv_op_type, conv_inputs, {output}); + convNode.AddAttribute("auto_pad", auto_pad); + + if (!pads.empty() && auto_pad == "NOTSET") { + convNode.AddAttribute("pads", pads); + } + + if (!strides.empty()) { + convNode.AddAttribute("strides", strides); + } + + if (!dilations.empty()) { + convNode.AddAttribute("dilations", dilations); + } + }; +} + +// Runs a Conv model on the QNN CPU backend. Checks the graph node assignment, and that inference +// outputs for QNN EP and CPU EP match. +static void RunCPUConvOpTest(const std::string& conv_op_type, const TestInputDef& input_def, + const TestInputDef& weights_def, + const TestInputDef& bias_def, + const std::vector& strides, + const std::vector& pads, + const std::vector& dilations, + const std::string& auto_pad, + ExpectedEPNodeAssignment expected_ep_assignment, + 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 + + RunQnnModelTest(BuildF32ConvTestCase(conv_op_type, input_def, weights_def, bias_def, strides, pads, dilations, auto_pad), + provider_options, + opset, + expected_ep_assignment, + fp32_abs_err); +} + +// Creates a graph with a single Q/DQ Conv operator. Used for testing HTP backend. +template +static GetTestQDQModelFn BuildQDQConvTestCase(const std::string& conv_op_type, + const TestInputDef& input_def, + const TestInputDef& weights_def, + const TestInputDef& bias_def, + const std::vector& strides, + const std::vector& pads, + const std::vector& dilations, + const std::string& auto_pad = "NOTSET", + bool use_contrib_qdq = false) { + return [conv_op_type, input_def, weights_def, bias_def, strides, pads, + dilations, auto_pad, use_contrib_qdq](ModelTestBuilder& builder, + std::vector>& output_qparams) { + std::vector conv_inputs; + + // input -> Q/DQ -> + auto* input = MakeTestInput(builder, input_def); + QuantParams input_qparams = GetTestInputQuantParams(input_def); + auto* input_qdq = AddQDQNodePair(builder, input, input_qparams.scale, input_qparams.zero_point, + use_contrib_qdq); + conv_inputs.push_back(input_qdq); + + // weights -> Q/DQ -> + auto* weights = MakeTestInput(builder, weights_def); + QuantParams weights_qparams = GetTestInputQuantParams(weights_def); + auto* weights_qdq = AddQDQNodePair(builder, weights, weights_qparams.scale, + weights_qparams.zero_point, use_contrib_qdq); + conv_inputs.push_back(weights_qdq); + + // bias -> + if (!bias_def.GetShape().empty()) { + // Bias requirement taken from python quantization tool: onnx_quantizer.py::quantize_bias_static() + const float bias_scale = input_qparams.scale * weights_qparams.scale; + + conv_inputs.push_back(MakeTestQDQBiasInput(builder, bias_def, bias_scale, use_contrib_qdq)); + } + + auto* conv_output = builder.MakeIntermediate(); + Node& conv_node = builder.AddNode(conv_op_type, conv_inputs, {conv_output}); + + conv_node.AddAttribute("auto_pad", auto_pad); + + if (!pads.empty() && auto_pad == "NOTSET") { + conv_node.AddAttribute("pads", pads); + } + if (!strides.empty()) { + conv_node.AddAttribute("strides", strides); + } + if (!dilations.empty()) { + conv_node.AddAttribute("dilations", dilations); + } + + AddQDQNodePairWithOutputAsGraphOutput(builder, conv_output, output_qparams[0].scale, + output_qparams[0].zero_point, use_contrib_qdq); + }; +} + +// Runs a Conv model on the QNN HTP backend. Checks the graph node assignment, and that inference +// outputs for QNN EP and CPU EP match. +template +static void RunHTPConvOpTest(const std::string& conv_op_type, const TestInputDef& input_def, + const TestInputDef& weights_def, + const TestInputDef& bias_def, + const std::vector& strides, + const std::vector& pads, + const std::vector& dilations, + const std::string& auto_pad, + ExpectedEPNodeAssignment expected_ep_assignment, + bool use_contrib_qdq = false, + int opset = 13, + float fp32_abs_err = 1e-5f) { + ProviderOptions provider_options; + +#if defined(_WIN32) + provider_options["backend_path"] = "QnnHtp.dll"; +#else + provider_options["backend_path"] = "libQnnHtp.so"; +#endif + + TestQDQModelAccuracy(BuildF32ConvTestCase(conv_op_type, input_def, weights_def, bias_def, strides, pads, dilations, + auto_pad), + BuildQDQConvTestCase(conv_op_type, input_def, weights_def, + bias_def, strides, pads, dilations, + auto_pad, use_contrib_qdq), + provider_options, + opset, + expected_ep_assignment, + fp32_abs_err); +} + +// 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) { + 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 + TestInputDef({2}, false, -1.0f, 1.0f), // Random dynamic bias + {1, 1}, // default strides + {0, 0, 0, 0}, // default pads + {1, 1}, // default dilations + "NOTSET", // No auto-padding + ExpectedEPNodeAssignment::All); +} + +// Check that QNN compiles DQ -> Conv -> Q as a single unit. +// Tests bias as an initializer. +TEST_F(QnnCPUBackendTests, Convf32_bias_initializer) { + 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 + TestInputDef({2}, true, -1.0f, 1.0f), // Random static bias + {1, 1}, // default strides + {0, 0, 0, 0}, // default pads + {1, 1}, // default dilations + "NOTSET", // No auto-padding + ExpectedEPNodeAssignment::All); +} + +// Tests Conv's auto_pad value "SAME_UPPER" (compares to CPU EP). +TEST_F(QnnCPUBackendTests, Convf32_AutoPadUpper) { + RunCPUConvOpTest("Conv", + TestInputDef({1, 1, 3, 3}, false, -3.0f, 3.0f), // Random dynamic input + TestInputDef({2, 1, 2, 2}, true, -1.0f, 1.0f), // Random static weights + TestInputDef({2}, true, -1.0f, 1.0f), // Random static bias + {1, 1}, // strides + {}, // pads + {1, 1}, // dilations + "SAME_UPPER", // auto_pad + ExpectedEPNodeAssignment::All); +} + +// Tests ConvTranspose's auto_pad value "SAME_UPPER" (compares to CPU EP). +TEST_F(QnnCPUBackendTests, ConvTransposef32_AutoPadUpper) { + RunCPUConvOpTest("ConvTranspose", + TestInputDef({1, 1, 3, 3}, false, -3.0f, 3.0f), // Random dynamic input + TestInputDef({1, 2, 2, 2}, true, -1.0f, 1.0f), // Random static weights + TestInputDef({2}, true, -1.0f, 1.0f), // Random static bias + {1, 1}, // strides + {}, // pads + {1, 1}, // dilations + "SAME_UPPER", // auto_pad + ExpectedEPNodeAssignment::All); +} + +// Tests Conv's auto_pad value "SAME_LOWER" (compares to CPU EP). +TEST_F(QnnCPUBackendTests, Convf32_AutoPadLower) { + RunCPUConvOpTest("Conv", + TestInputDef({1, 1, 3, 3}, false, -3.0f, 3.0f), // Random dynamic input + TestInputDef({2, 1, 2, 2}, false, -1.0f, 1.0f), // Random dynamic weights + TestInputDef({2}, true, -1.0f, 1.0f), // Random static bias + {1, 1}, // strides + {}, // pads + {1, 1}, // dilations + "SAME_LOWER", // auto_pad + ExpectedEPNodeAssignment::All); +} + +// Tests ConvTranspose's auto_pad value "SAME_LOWER" (compares to CPU EP). +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 + TestInputDef({2}, true, -1.0f, 1.0f), // Random static bias + {1, 1}, // strides + {}, // pads + {1, 1}, // dilations + "SAME_LOWER", // auto_pad + ExpectedEPNodeAssignment::All); +} + +// large input,output, pads +TEST_F(QnnCPUBackendTests, Convf32_large_input1_pad_bias_initializer) { + RunCPUConvOpTest("Conv", + TestInputDef({1, 3, 60, 452}, false, 0.0f, 10.0f), // Random dynamic input + TestInputDef({16, 3, 3, 3}, true, 0.0f, 1.0f), // Random dynamic weights + TestInputDef({16}, true, -1.0f, 1.0f), // Random static bias + {1, 1}, + {1, 1, 1, 1}, + {1, 1}, + "NOTSET", + ExpectedEPNodeAssignment::All, + 13, + 1e-4f); +} + +TEST_F(QnnCPUBackendTests, Convf32_large_input2_nopad_bias_initializer) { +#if defined(_WIN32) + // Tolerance needs to be > 1.52588e-05 on Windows x64 + // TODO: Investigate why + float fp32_abs_err = 1e-4f; +#else + float fp32_abs_err = 1e-5f; // default value +#endif + + RunCPUConvOpTest("Conv", + TestInputDef({1, 32, 16, 113}, false, -3.0f, 3.0f), // Random dynamic input + TestInputDef({16, 32, 1, 1}, false, -1.0f, 1.0f), // Random dynamic weights + TestInputDef({16}, true, -1.0f, 1.0f), // Random static bias + {1, 1}, + {0, 0, 0, 0}, + {1, 1}, + "NOTSET", + ExpectedEPNodeAssignment::All, + 13, // opset + fp32_abs_err); +} + +// Test 1D Conv with static weights (implemented in QNN EP as 2D convolution with height of 1). +TEST_F(QnnCPUBackendTests, Conv1Df32_StaticWeights_DefaultBias) { + std::vector input_data = {0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f}; + RunCPUConvOpTest("Conv", + TestInputDef({1, 2, 4}, false, input_data), // Dynamic input + TestInputDef({1, 2, 2}, true, {1.0f, 2.0f, 3.0f, 4.0f}), // Static weights + TestInputDef({1}, true, {1.0f}), // Initializer Bias + {1}, // Strides + {0, 0}, // Pads + {1}, // Dilations + "NOTSET", + ExpectedEPNodeAssignment::All); +} + +// Test 1D Conv with dynamic weights (implemented in QNN EP as 2D convolution with height of 1). +TEST_F(QnnCPUBackendTests, Conv1Df32_DynamicWeights_DefaultBias) { + std::vector input_data = {0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f}; + RunCPUConvOpTest("Conv", + TestInputDef({1, 2, 4}, false, input_data), // Dynamic input + TestInputDef({1, 2, 2}, false, {1.0f, 2.0f, 3.0f, 4.0f}), // Dynamic weights + TestInputDef(), // Default bias + {1}, // Strides + {0, 0}, // Pads + {1}, // Dilations + "NOTSET", + ExpectedEPNodeAssignment::All); +} + +// Test 1D ConvTranspose with static weights (implemented in QNN EP as 2D convolution with height of 1). +TEST_F(QnnCPUBackendTests, ConvTranspose1Df32_StaticWeights_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 + TestInputDef({2, 1, 2}, true, {1.0f, 2.0f, 3.0f, 4.0f}), // Static weights + TestInputDef({1}, true, {0.0f}), // Zero bias + {1}, // Strides + {0, 0}, // Pads + {1}, // Dilations + "NOTSET", + ExpectedEPNodeAssignment::All); +} + +// Test 1D ConvTranspose with dynamic weights (implemented in QNN EP as 2D convolution with height of 1). +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 + TestInputDef({2, 1, 2}, false, {1.0f, 2.0f, 3.0f, 4.0f}), // Dynamic weights + TestInputDef({1}, true, {0.0f}), // Zero bias + {1}, // Strides + {0, 0}, // Pads + {1}, // Dilations + "NOTSET", + ExpectedEPNodeAssignment::All); +} + +#if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) + +// The bug is from a QDQ model, and Conv node gets processed before it's producer Mul node +// A Transpose node gets inserted between Mul and the dynamic weight tensor shape on Conv +// to make Conv weight with shape HWNC +// However it changes Mul output shape to HWNC and cause issue +// It has to be QDQ model, because the DQ node with initializer on Conv gets processed first +// and DQ node requires its node unit to be processed +// 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 + + auto BuildConvMulGraph = [](ModelTestBuilder& builder) { + // DQ node for Conv input + auto* dq_i_output = builder.MakeIntermediate(); + auto* conv_dq_input = builder.MakeInitializer({1, 32, 16, 113}, static_cast(0), static_cast(127)); + + // DQ node for Conv bias + auto* dq_bias_output = builder.MakeIntermediate(); + auto* bias = builder.MakeInitializer({16}, static_cast(0), static_cast(127)); + + // Mul node + // DQ nodes for Mul + auto* mul_dq1_output = builder.MakeIntermediate(); + auto* mul_input1 = builder.MakeInput({16, 32, 1, 1}, static_cast(0), static_cast(127)); + + auto* mul_dq2_output = builder.MakeIntermediate(); + auto* mul_input2 = builder.MakeInitializer({16, 1, 1, 1}, static_cast(0), static_cast(127)); + builder.AddDequantizeLinearNode(mul_input1, .03f, 0, mul_dq1_output); + builder.AddDequantizeLinearNode(mul_input2, .03f, 0, mul_dq2_output); + + auto* mul_output = builder.MakeIntermediate(); + builder.AddNode("Mul", {mul_dq1_output, mul_dq2_output}, {mul_output}); + + auto* mul_dq_output = AddQDQNodePair(builder, mul_output, .03f, 0); + + builder.AddDequantizeLinearNode(conv_dq_input, .04f, 0, dq_i_output); + builder.AddDequantizeLinearNode(bias, .0012f, 0, dq_bias_output); + // Conv node + auto* conv_output = builder.MakeIntermediate(); + + Node& conv_node = builder.AddNode("Conv", {dq_i_output, mul_dq_output, dq_bias_output}, {conv_output}); + conv_node.AddAttribute("auto_pad", "NOTSET"); + conv_node.AddAttribute("pads", std::vector{0, 0, 0, 0}); + conv_node.AddAttribute("strides", std::vector{1, 1}); + conv_node.AddAttribute("dilations", std::vector{1, 1}); + + auto* q_output = builder.MakeIntermediate(); + builder.AddQuantizeLinearNode(conv_output, .039f, 0, q_output); + + auto* dq_output = builder.MakeOutput(); + builder.AddDequantizeLinearNode(q_output, .039f, 0, dq_output); + }; + + RunQnnModelTest(BuildConvMulGraph, + provider_options, + 13, + ExpectedEPNodeAssignment::All); +} + +// Check that QNN compiles DQ -> Conv -> Q as a single unit. +// Tests bias as a dynamic input. +TEST_F(QnnHTPBackendTests, ConvU8U8S32_bias_dynamic_input) { + RunHTPConvOpTest("Conv", + TestInputDef({1, 1, 5, 5}, false, 0.0f, 10.0f), // Random dynamic input + TestInputDef({1, 1, 3, 3}, true, -10.0f, 10.0f), // Random static input + TestInputDef({1}, false, {2.0f}), // Dynamic bias + {1, 1}, // Strides + {0, 0, 0, 0}, // Pads + {1, 1}, // Dilations + "NOTSET", + ExpectedEPNodeAssignment::All); +} + +// Tests 16-bit QDQ Conv with dynamic weights and bias (uses QNN's Conv2d) +// TODO: Inaccuracy detected for output 'output', element 0. +// Output quant params: scale=0.0040235077030956745, zero_point=0. +// Expected val: 87.354057312011719 +// QNN QDQ val: 0 (err 87.354057312011719) +// CPU QDQ val: 87.3583984375 (err 0.00434112548828125) +TEST_F(QnnHTPBackendTests, DISABLED_ConvU16S16S32_DynamicBias) { + TestInputDef input_def({1, 2, 5, 5}, false, GetFloatDataInRange(-10.0f, 10.0f, 50)); + TestInputDef weight_def({1, 2, 3, 3}, false, GetFloatDataInRange(-1.0f, 5.0f, 18)); + RunHTPConvOpTest("Conv", + input_def, // Input + weight_def.OverrideValueRange(-5.0f, 5.0f), // Weights (symmetric quant range) + TestInputDef({1}, false, {2.0f}), // Bias + {1, 1}, // Strides + {0, 0, 0, 0}, // Pads + {1, 1}, // Dilations + "NOTSET", + ExpectedEPNodeAssignment::All, + true); // Use com.microsoft QDQ ops for 16-bit +} + +// Tests 16-bit QDQ Conv with dynamic weights and bias (uses QNN's DepthwiseConv2d) +// TODO(adrianlizarraga): FAIL: Failed to finalize QNN graph. Error code 1002 +TEST_F(QnnHTPBackendTests, DISABLED_DepthwiseConvU16S16S32_DynamicBias) { + TestInputDef input_def({1, 1, 5, 5}, false, GetFloatDataInRange(-10.0f, 10.0f, 25)); + TestInputDef weight_def({1, 1, 3, 3}, false, GetFloatDataInRange(-1.0f, 5.0f, 9)); + RunHTPConvOpTest("Conv", + input_def, // Input + weight_def.OverrideValueRange(-5.0f, 5.0f), // Weights (symmetric quant range) + TestInputDef({1}, false, {2.0f}), // Bias + {1, 1}, // Strides + {0, 0, 0, 0}, // Pads + {1, 1}, // Dilations + "NOTSET", + ExpectedEPNodeAssignment::All, + true); // Use com.microsoft QDQ ops for 16-bit +} + +// Tests 16-bit QDQ Conv with dynamic weights and no bias. +// TODO: Inaccuracy detected for output 'output', element 0. +// Output quant params: scale=0.0039929896593093872, zero_point=0. +// Expected val: 85.354057312011719 +// QNN QDQ val: 0 (err 85.354057312011719) +// CPU QDQ val: 85.358139038085938 (err 0.00408172607421875) +TEST_F(QnnHTPBackendTests, DISABLED_ConvU16S16S32_NoBias) { + TestInputDef input_def({1, 2, 5, 5}, false, GetFloatDataInRange(-10.0f, 10.0f, 50)); + TestInputDef weight_def({1, 2, 3, 3}, false, GetFloatDataInRange(-1.0f, 5.0f, 18)); + RunHTPConvOpTest("Conv", + input_def, // Input + weight_def.OverrideValueRange(-5.0f, 5.0f), // Weights (symmetric quant range) + TestInputDef(), // Bias + {1, 1}, // Strides + {0, 0, 0, 0}, // Pads + {1, 1}, // Dilations + "NOTSET", + ExpectedEPNodeAssignment::All, + true); // Use com.microsoft QDQ ops for 16-bit +} + +// Tests 16-bit QDQ Conv with dynamic weights and no bias (uses QNN's DepthWiseConv2d) +// TODO(adrianlizarraga): FAIL: Failed to finalize QNN graph. Error code 1002 +TEST_F(QnnHTPBackendTests, DISABLED_DepthwiseConvU16S16S32_NoBias) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 25); + std::vector weight_data = GetFloatDataInRange(-10.0f, 10.0f, 9); + RunHTPConvOpTest("Conv", + TestInputDef({1, 1, 5, 5}, false, input_data), // Input + TestInputDef({1, 1, 3, 3}, false, weight_data), // Weights + TestInputDef(), // Bias + {1, 1}, // Strides + {0, 0, 0, 0}, // Pads + {1, 1}, // Dilations + "NOTSET", + ExpectedEPNodeAssignment::All, + true); // Use com.microsoft QDQ ops for 16-bit +} + +// Tests 16-bit activations, 8-bit static weights QDQ Conv with static bias. +// Uses QNN's DepthwiseConv2d operator. +// TODO: Inaccuracy detected for output 'output', element 8. +// Output quant params: scale=0.0027466239407658577, zero_point=10194. +// Expected val: 152 +// QNN QDQ val: 151.8004150390625 (err 0.1995849609375) +// CPU QDQ val: 151.9981689453125 (err 0.0018310546875) +TEST_F(QnnHTPBackendTests, DepthwiseConvU16U8S32_StaticBias) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 25); + std::vector weight_data = GetFloatDataInRange(-1.0f, 5.0f, 9); + RunHTPConvOpTest("Conv", + TestInputDef({1, 1, 5, 5}, false, input_data), // Input + TestInputDef({1, 1, 3, 3}, true, weight_data), // Weights + TestInputDef({1}, true, {2.0f}), // Bias + {1, 1}, // Strides + {0, 0, 0, 0}, // Pads + {1, 1}, // Dilations + "NOTSET", + ExpectedEPNodeAssignment::All, + true, // Use com.microsoft QDQ ops for 16-bit + 13, + 0.2f); +} + +// Tests 16-bit activations, 8-bit static weights QDQ Conv with static bias. +// TODO: Inaccuracy detected for output 'output', element 0. +// Output quant params: scale=0.0040235077030956745, zero_point=0. +// Expected val: 87.354057312011719 +// QNN QDQ val: 87.559577941894531 (err 0.2055206298828125) +// CPU QDQ val: 87.398635864257812 (err 0.04457855224609375) +TEST_F(QnnHTPBackendTests, ConvU16U8S32_StaticBias) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 50); + std::vector weight_data = GetFloatDataInRange(-1.0f, 5.0f, 18); + RunHTPConvOpTest("Conv", + TestInputDef({1, 2, 5, 5}, false, input_data), // Input + TestInputDef({1, 2, 3, 3}, true, weight_data), // Weights + TestInputDef({1}, true, {2.0f}), // Bias + {1, 1}, // Strides + {0, 0, 0, 0}, // Pads + {1, 1}, // Dilations + "NOTSET", + ExpectedEPNodeAssignment::All, + true, // Use com.microsoft QDQ ops for 16-bit + 13, + 0.6f); +} + +// Tests 16-bit activations, 8-bit static weights QDQ Conv with dynamic bias. +// Uses QNN's DepthwiseConv2d operator. +// TODO: Inaccuracy detected for output 'output', element 1. +// Output quant params: scale=0.0027466239407658577, zero_point=10194. +// Expected val: -13.000001907348633 +// QNN QDQ val: -13.095903396606445 (err 0.0959014892578125) +// CPU QDQ val: -12.999771118164062 (err 0.0002307891845703125) +TEST_F(QnnHTPBackendTests, DepthwiseConvU16U8S32_DynamicBias) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 25); + std::vector weight_data = GetFloatDataInRange(-1.0f, 5.0f, 9); + RunHTPConvOpTest("Conv", + TestInputDef({1, 1, 5, 5}, false, input_data), // Input + TestInputDef({1, 1, 3, 3}, true, weight_data), // Weights + TestInputDef({1}, false, {2.0f}), // Bias + {1, 1}, // Strides + {0, 0, 0, 0}, // Pads + {1, 1}, // Dilations + "NOTSET", + ExpectedEPNodeAssignment::All, + true, // Use com.microsoft QDQ ops for 16-bit + 13, + 0.2f); +} + +// Tests 16-bit activations, 8-bit static weights QDQ Conv with dynamic bias. +// TODO: Inaccuracy detected for output 'output', element 0. +// Output quant params: scale=0.0040235077030956745, zero_point=0. +// Expected val: 87.354057312011719 +// QNN QDQ val: 87.559577941894531 (err 0.2055206298828125) +// CPU QDQ val: 87.398635864257812 (err 0.04457855224609375) +TEST_F(QnnHTPBackendTests, ConvU16U8S32_DynamicBias) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 50); + std::vector weight_data = GetFloatDataInRange(-1.0f, 5.0f, 18); + RunHTPConvOpTest("Conv", + TestInputDef({1, 2, 5, 5}, false, input_data), // Input + TestInputDef({1, 2, 3, 3}, true, weight_data), // Weights + TestInputDef({1}, false, {2.0f}), // Bias + {1, 1}, // Strides + {0, 0, 0, 0}, // Pads + {1, 1}, // Dilations + "NOTSET", + ExpectedEPNodeAssignment::All, + true, // Use com.microsoft QDQ ops for 16-bit + 13, + 0.57f); +} + +// Tests 16-bit activations, 8-bit static weights QDQ Conv with no bias +// TODO: Inaccuracy detected for output 'output', element 7. +// Output quant params: scale=0.0039929896593093872, zero_point=0. +// Expected val: 246.98667907714844 +// QNN QDQ val: 247.82090759277344 (err 0.834228515625) +// CPU QDQ val: 247.24192810058594 (err 0.2552490234375) +TEST_F(QnnHTPBackendTests, ConvU16U8S32_NoBias) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 50); + std::vector weight_data = GetFloatDataInRange(-1.0f, 5.0f, 18); + RunHTPConvOpTest("Conv", + TestInputDef({1, 2, 5, 5}, false, input_data), // Input + TestInputDef({1, 2, 3, 3}, true, weight_data), // Weights + TestInputDef(), // Bias + {1, 1}, // Strides + {0, 0, 0, 0}, // Pads + {1, 1}, // Dilations + "NOTSET", + ExpectedEPNodeAssignment::All, + true, // Use com.microsoft QDQ ops for 16-bit + 13, + 0.58f); +} + +// Tests 16-bit activations, 8-bit static weights QDQ Conv with no bias +// Uses QNN's DepthwiseConv2d operator. +// TODO: Inaccuracy detected for output 'output', element 8. +// Output quant params: scale=0.0027466239407658577, zero_point=10923. +// Expected val: 150 +// QNN QDQ val: 149.80087280273438 (err 0.199127197265625) +// CPU QDQ val: 149.99862670898438 (err 0.001373291015625) +TEST_F(QnnHTPBackendTests, DepthwiseConvU16U8S32_NoBias) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 25); + std::vector weight_data = GetFloatDataInRange(-1.0f, 5.0f, 9); + RunHTPConvOpTest("Conv", + TestInputDef({1, 1, 5, 5}, false, input_data), // Input + TestInputDef({1, 1, 3, 3}, true, weight_data), // Weights + TestInputDef(), // Bias + {1, 1}, // Strides + {0, 0, 0, 0}, // Pads + {1, 1}, // Dilations + "NOTSET", + ExpectedEPNodeAssignment::All, + true, // Use com.microsoft QDQ ops for 16-bit + 13, + 0.2f); +} + +// Test that dynamic weights with default bias works for Conv. This was previously not working +// on older versions of QNN sdk. +TEST_F(QnnHTPBackendTests, ConvU8U8S32_DynamicWeight_NoBias) { + RunHTPConvOpTest("Conv", + TestInputDef({1, 3, 32, 32}, false, -10.0f, 10.0f), // Input + TestInputDef({1, 3, 4, 4}, false, -10.0f, 10.0f), // Weights + TestInputDef(), // Bias + {1, 1}, // Strides + {0, 0, 0, 0}, // Pads + {1, 1}, // Dilations + "NOTSET", + ExpectedEPNodeAssignment::All); +} + +// Test that dynamic weights with default bias works for ConvTranspose. This was previously not working +// on older versions of QNN sdk. +TEST_F(QnnHTPBackendTests, ConvTransposeU8U8S32_DynamicWeight_NoBias) { + RunHTPConvOpTest("ConvTranspose", + TestInputDef({1, 3, 32, 32}, false, -10.0f, 10.0f), // Input + TestInputDef({3, 1, 4, 4}, false, -10.0f, 10.0f), // Weights + TestInputDef(), // Bias + {1, 1}, // Strides + {0, 0, 0, 0}, // Pads + {1, 1}, // Dilations + "NOTSET", + ExpectedEPNodeAssignment::All); +} + +// Check that QNN compiles DQ -> Conv -> Q as a single unit. +// Tests bias as an initializer. +TEST_F(QnnHTPBackendTests, ConvU8U8S32_bias_initializer) { + RunHTPConvOpTest("Conv", + TestInputDef({1, 1, 5, 5}, false, 0.0f, 10.0f), // Random dynamic input + TestInputDef({1, 1, 3, 3}, true, -10.0f, 10.0f), // Random static weight + TestInputDef({1}, true, {2.0f}), // Initializer bias + {1, 1}, // Strides + {0, 0, 0, 0}, // Pads + {1, 1}, // Dilations + "NOTSET", + ExpectedEPNodeAssignment::All); +} + +// Tests 1D Conv with bias as an initializer. +TEST_F(QnnHTPBackendTests, Conv1DU8U8S32_bias_initializer) { + std::vector input_data = {0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f}; + RunHTPConvOpTest("Conv", + TestInputDef({1, 2, 4}, false, input_data), // Dynamic input + TestInputDef({1, 2, 2}, true, {1.f, 2.f, 3.f, 4.f}), // Static weight + TestInputDef({1}, true, {1.0f}), // Initializer bias + {1}, // strides + {0, 0}, // pads + {1}, // dilations + "NOTSET", + ExpectedEPNodeAssignment::All); +} + +// Tests 1D ConvTranspose with bias as an initializer. +TEST_F(QnnHTPBackendTests, ConvTranspose1DU8U8S32_bias_initializer) { + std::vector input_data = {0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f}; + RunHTPConvOpTest("ConvTranspose", + TestInputDef({1, 2, 4}, false, input_data), // Dynamic input + TestInputDef({2, 1, 2}, true, {1.f, 2.f, 3.f, 4.f}), // Static weight + TestInputDef({1}, true, {1.0f}), // Initializer bias + {1}, // strides + {0, 0}, // pads + {1}, // dilations + "NOTSET", + ExpectedEPNodeAssignment::All); +} + +// Tests auto_pad value "SAME_UPPER" on HTP backend (compares to CPU EP). +TEST_F(QnnHTPBackendTests, ConvU8U8S32_AutoPadUpper) { + RunHTPConvOpTest("Conv", + TestInputDef({1, 1, 5, 5}, false, 0.f, 10.f), // Dynamic input + TestInputDef({1, 1, 4, 4}, true, -1.f, 1.f), // Static weights + TestInputDef({1}, true, {1.0f}), // Initializer bias + {1, 1}, // strides + {}, // pads + {1, 1}, // dilations + "SAME_UPPER", // auto_pad + ExpectedEPNodeAssignment::All, + false, // use_contrib_qdq + 13); +} + +// Tests Conv1d auto_pad value "SAME_UPPER" on HTP backend (compares to CPU EP). +TEST_F(QnnHTPBackendTests, Conv1DU8U8S32_AutoPadUpper) { + std::vector input_data = {0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f}; + RunHTPConvOpTest("Conv", + TestInputDef({1, 2, 4}, false, input_data), // Dynamic input + TestInputDef({1, 2, 2}, true, {1.f, 2.f, 3.f, 4.f}), // Static weight + TestInputDef({1}, true, {1.0f}), // Initializer bias + {1}, // strides + {0}, // pads + {1}, // dilations + "SAME_UPPER", // auto_pad + ExpectedEPNodeAssignment::All, + false, // use_contrib_qdq + 13); +} + +// Tests TransposeConv1d auto_pad value "SAME_UPPER" on HTP backend (compares to CPU EP). +TEST_F(QnnHTPBackendTests, ConvTranspose1DU8U8S32_AutoPadUpper) { + std::vector input_data = {0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f}; + RunHTPConvOpTest("ConvTranspose", + TestInputDef({1, 2, 4}, false, input_data), // Dynamic input + TestInputDef({2, 1, 2}, true, {1.f, 2.f, 3.f, 4.f}), // Static weight + TestInputDef({1}, true, {1.0f}), // Initializer bias + {1}, // strides + {0}, // pads + {1}, // dilations + "SAME_UPPER", // auto_pad + ExpectedEPNodeAssignment::All, + false, // use_contrib_qdq + 13); +} + +// Tests Conv's auto_pad value "SAME_LOWER" on HTP backend (compares to CPU EP). +TEST_F(QnnHTPBackendTests, ConvU8U8S32_AutoPadLower) { + RunHTPConvOpTest("Conv", + TestInputDef({1, 1, 5, 5}, false, 0.f, 10.f), // Dynamic input + TestInputDef({1, 1, 4, 4}, true, -1.f, 1.f), // Static weights + TestInputDef({1}, true, {1.0f}), // Initializer bias + {1, 1}, // strides + {}, // pads + {1, 1}, // dilations + "SAME_LOWER", // auto_pad + ExpectedEPNodeAssignment::All, + false, // use_contrib_qdq + 13); +} + +// Tests ConvTranspose's auto_pad value "SAME_LOWER" on HTP backend (compares to CPU EP). +TEST_F(QnnHTPBackendTests, ConvTransposeU8U8S32_AutoPadLower) { + RunHTPConvOpTest("ConvTranspose", + TestInputDef({1, 1, 5, 5}, false, 0.f, 10.f), // Dynamic input + TestInputDef({1, 1, 4, 4}, true, -1.f, 1.f), // Static weights + TestInputDef({1}, true, {1.0f}), // Initializer bias + {1, 1}, // strides + {}, // pads + {1, 1}, // dilations + "SAME_LOWER", // auto_pad + ExpectedEPNodeAssignment::All, + false, // use_contrib_qdq + 13); +} + +// Tests Conv1d auto_pad value "SAME_LOWER" on HTP backend (compares to CPU EP). +TEST_F(QnnHTPBackendTests, Conv1DU8U8S32_AutoPadLower) { + std::vector input_data = {0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f}; + RunHTPConvOpTest("Conv", + TestInputDef({1, 2, 4}, false, input_data), // Dynamic input + TestInputDef({1, 2, 2}, true, {1.f, 2.f, 3.f, 4.f}), // Static weight + TestInputDef({1}, true, {1.0f}), // Initializer bias + {1}, // strides + {0}, // pads + {1}, // dilations + "SAME_LOWER", // auto_pad + ExpectedEPNodeAssignment::All, + false, // use_contrib_qdq + 13); +} + +// Tests ConvTranspose 1d auto_pad value "SAME_LOWER" on HTP backend (compares to CPU EP). +TEST_F(QnnHTPBackendTests, ConvTranspose1DU8U8S32_AutoPadLower) { + std::vector input_data = {0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f}; + RunHTPConvOpTest("ConvTranspose", + TestInputDef({1, 2, 4}, false, input_data), // Dynamic input + TestInputDef({2, 1, 2}, true, {1.f, 2.f, 3.f, 4.f}), // Static weight + TestInputDef({1}, true, {1.0f}), // Initializer bias + {1}, // strides + {0}, // pads + {1}, // dilations + "SAME_LOWER", // auto_pad + ExpectedEPNodeAssignment::All, + false, // use_contrib_qdq + 13); +} + +TEST_F(QnnHTPBackendTests, ConvU8U8S32_large_input1_padding_bias_initializer) { + RunHTPConvOpTest("Conv", + TestInputDef({1, 3, 60, 452}, false, 0.f, 10.f), // Dynamic input + TestInputDef({16, 3, 3, 3}, true, -1.f, 1.f), // Static weights + TestInputDef({16}, true, std::vector(16, 1.f)), // Initializer bias + {1, 1}, + {1, 1, 1, 1}, + {1, 1}, + "NOTSET", + ExpectedEPNodeAssignment::All); +} + +TEST_F(QnnHTPBackendTests, ConvU8U8S32_large_input2_bias_initializer) { + RunHTPConvOpTest("Conv", + TestInputDef({1, 128, 8, 56}, false, 0.f, 10.f), // Dynamic input + TestInputDef({32, 128, 1, 1}, true, -1.f, 1.f), // Random static weights + TestInputDef({32}, true, -1.f, 1.f), // Random initializer bias + {1, 1}, + {0, 0, 0, 0}, + {1, 1}, + "NOTSET", + ExpectedEPNodeAssignment::All); +} + +TEST_F(QnnHTPBackendTests, ConvU8U8S32_LargeInput_Dilations_Pads) { + RunHTPConvOpTest("Conv", + TestInputDef({1, 3, 768, 1152}, false, 0.f, 10.f), // Dynamic input + TestInputDef({64, 3, 7, 7}, true, -1.f, 1.f), // Static weights + TestInputDef({64}, true, -1.f, 1.f), // Initializer bias + {2, 2}, // strides + {3, 3, 3, 3}, // pads + {1, 1}, // dilations + "NOTSET", // auto_pad + ExpectedEPNodeAssignment::All); +} +#endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) + +} // namespace test +} // namespace onnxruntime + +#endif diff --git a/onnxruntime/test/providers/qnn/flatten_op_test.cc b/onnxruntime/test/providers/qnn/flatten_op_test.cc new file mode 100644 index 0000000000000..637d3257ddea7 --- /dev/null +++ b/onnxruntime/test/providers/qnn/flatten_op_test.cc @@ -0,0 +1,202 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#if !defined(ORT_MINIMAL_BUILD) + +#include + +#include "test/providers/qnn/qnn_test_utils.h" +#include "core/graph/node_attr_utils.h" + +#include "onnx/onnx_pb.h" +#include "gtest/gtest.h" + +namespace onnxruntime { +namespace test { + +// Runs a model with a Flatten operator on the QNN CPU backend. Checks the graph node assignment +// and that inference outputs for QNN EP and CPU EP match. +template +static void RunFlattenTestOnCPU(const TestInputDef& input_def, + const std::vector& attrs, + 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 + + RunQnnModelTest(BuildOpTestCase("Flatten", {input_def}, {}, attrs), + provider_options, + opset, + expected_ep_assignment); +} + +// +// CPU tests: +// + +// Test that Flatten input (rank4) with axis == 0. +TEST_F(QnnCPUBackendTests, Flatten_Rank4_Axis0) { + RunFlattenTestOnCPU(TestInputDef({1, 3, 4, 4}, false, -10.0f, 10.0f), + {utils::MakeAttribute("axis", static_cast(0))}, + ExpectedEPNodeAssignment::All); +} + +// Test that Flatten input (rank4) with axis == -1. +TEST_F(QnnCPUBackendTests, Flatten_Rank4_AxisNeg1) { + RunFlattenTestOnCPU(TestInputDef({1, 3, 4, 4}, false, -10.0f, 10.0f), + {utils::MakeAttribute("axis", static_cast(-1))}, + ExpectedEPNodeAssignment::All); +} + +// Test that Flatten input (rank5) with axis == 2. +TEST_F(QnnCPUBackendTests, Flatten_Rank5_Axis2) { + RunFlattenTestOnCPU(TestInputDef({1, 2, 3, 4, 4}, false, -10.0f, 10.0f), + {utils::MakeAttribute("axis", static_cast(2))}, + ExpectedEPNodeAssignment::All); +} + +#if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) +// +// HTP tests: +// + +// Runs a model with a non-QDQ Flatten operator on the QNN HTP backend. Checks the graph node assignment +// and that inference outputs for QNN EP and CPU EP match. +template +static void RunFlattenTestOnHTP(const TestInputDef& input_def, + const std::vector& attrs, + 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 + + RunQnnModelTest(BuildOpTestCase("Flatten", {input_def}, {}, attrs), + provider_options, + opset, + expected_ep_assignment); +} + +// Runs a QDQ Flatten model on the QNN (HTP) EP and the ORT CPU EP. Checks the graph node assignment and that inference +// running the QDQ model on QNN EP is at least as accurate as on ORT CPU EP (compared to the baseline float32 model). +template +static void RunQDQFlattenTestOnHTP(const TestInputDef& input_def, + const std::vector& attrs, + ExpectedEPNodeAssignment expected_ep_assignment, + 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 + + auto f32_model_builder = BuildOpTestCase("Flatten", {input_def}, {}, attrs); + auto qdq_model_builder = BuildQDQOpTestCase("Flatten", {input_def}, {}, attrs, kOnnxDomain, use_contrib_qdq); + TestQDQModelAccuracy(f32_model_builder, + qdq_model_builder, + provider_options, + opset, + expected_ep_assignment); +} + +// Test 8-bit QDQ Flatten input (rank4) with axis == 0. +TEST_F(QnnHTPBackendTests, Flatten_Rank4_Axis0) { + RunQDQFlattenTestOnHTP(TestInputDef({1, 3, 4, 4}, false, -10.0f, 10.0f), + {utils::MakeAttribute("axis", static_cast(0))}, + ExpectedEPNodeAssignment::All); +} + +// Test 16-bit QDQ Flatten input (rank4) with axis == 0. +TEST_F(QnnHTPBackendTests, Flatten_Rank4_Axis0_U16) { + RunQDQFlattenTestOnHTP(TestInputDef({1, 3, 4, 4}, false, -10.0f, 10.0f), + {utils::MakeAttribute("axis", static_cast(0))}, + ExpectedEPNodeAssignment::All, + 13, // opset + true); // Use com.microsoft Q/DQ ops +} + +// Test 8-bit QDQ Flatten input (rank4) with axis == -1. +TEST_F(QnnHTPBackendTests, Flatten_Rank4_AxisNeg1) { + RunQDQFlattenTestOnHTP(TestInputDef({1, 3, 4, 4}, false, -10.0f, 10.0f), + {utils::MakeAttribute("axis", static_cast(-1))}, + ExpectedEPNodeAssignment::All); +} + +// Test 16-bit QDQ Flatten input (rank4) with axis == -1. +TEST_F(QnnHTPBackendTests, Flatten_Rank4_AxisNeg1_U16) { + RunQDQFlattenTestOnHTP(TestInputDef({1, 3, 4, 4}, false, -10.0f, 10.0f), + {utils::MakeAttribute("axis", static_cast(-1))}, + ExpectedEPNodeAssignment::All, + 13, // opset + true); // Use com.microsoft Q/DQ ops +} + +// Test 8-bit QDQ Flatten with an input of rank5. +TEST_F(QnnHTPBackendTests, Flatten_QDQ8bit_Rank5) { + // We can't use the usual model-building functions because they add standalone Quantize and Dequantize nodes + // at the input and output. These Q/DQ ops get lowered to QNN's Quantize and Dequantize operators, which DO NOT + // support rank 5 tensors. Therefore, we have to create a test model that only instantiates the DQ -> Flatten -> Q + // QDQ node group, which gets lowered to a single QNN Reshape node. + GetTestModelFn model_fn = [](ModelTestBuilder& builder) { + // input (u8) -> DQ -> + NodeArg* quant_input = builder.MakeInput({1, 2, 3, 4, 5}, 0, 255); + NodeArg* input_dq = builder.MakeIntermediate(); + builder.AddDequantizeLinearNode(quant_input, 1.0f, 0, input_dq); // scale = 1.0, zp = 0 + + // Flatten -> + NodeArg* flatten_output = builder.MakeIntermediate(); + Node& flatten_node = builder.AddNode("Flatten", {input_dq}, {flatten_output}); + flatten_node.AddAttribute("axis", static_cast(2)); + + // Q -> output (u8) + NodeArg* output = builder.MakeOutput(); + builder.AddQuantizeLinearNode(flatten_output, 1.0f, 0, output); // scale = 1.0, zp = 0 + }; + + ProviderOptions provider_options; + +#if defined(_WIN32) + provider_options["backend_path"] = "QnnHtp.dll"; +#else + provider_options["backend_path"] = "libQnnHtp.so"; +#endif + + RunQnnModelTest(model_fn, + provider_options, + 13, // opset + ExpectedEPNodeAssignment::All); +} + +// Test that int32 non-QDQ Flatten runs on HTP backend. +TEST_F(QnnHTPBackendTests, Flatten_Int32_Rank4_Axis2) { + std::vector input_data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + RunFlattenTestOnHTP(TestInputDef({1, 3, 2, 2}, false, input_data), + {utils::MakeAttribute("axis", static_cast(2))}, + ExpectedEPNodeAssignment::All); +} + +// Test that rank 5 int32 Flatten runs on HTP backend. +TEST_F(QnnHTPBackendTests, Flatten_Int32_Rank5_Axis2) { + std::vector input_data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}; + RunFlattenTestOnHTP(TestInputDef({1, 3, 2, 2, 2}, false, input_data), + {utils::MakeAttribute("axis", static_cast(2))}, + ExpectedEPNodeAssignment::All); +} + +#endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) +} // namespace test +} // namespace onnxruntime +#endif // !defined(ORT_MINIMAL_BUILD) diff --git a/onnxruntime/test/providers/qnn/gather_op_htp_test.cc b/onnxruntime/test/providers/qnn/gather_op_htp_test.cc index 428240f86b22c..37e0db906d054 100644 --- a/onnxruntime/test/providers/qnn/gather_op_htp_test.cc +++ b/onnxruntime/test/providers/qnn/gather_op_htp_test.cc @@ -5,8 +5,8 @@ #include #include "core/graph/graph.h" +#include "core/graph/node_attr_utils.h" -#include "test/optimizer/qdq_test_utils.h" #include "test/providers/qnn/qnn_test_utils.h" #include "gtest/gtest.h" @@ -15,18 +15,14 @@ namespace onnxruntime { namespace test { #if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) -/** - * Runs a Gather op model on the QNN HTP backend. Checks the graph node assignment, and that inference - * outputs for QNN and CPU match. - * - * \param opset The opset version. - * \param test_description Description of the test for error reporting. - * \param scalar_indices whether the incidices input is scalar or not. - * \param expected_ep_assignment How many nodes are expected to be assigned to QNN (All, Some, or None) - */ +// Test the accuracy of a QDQ Gather model on QNN EP. Checks if the QDQ model on QNN EP as accurate as the QDQ model on CPU EP +// (compared to float32 model). template -static void RunGatherOpQDQTest(int opset, const char* test_description, bool scalar_indices = false, - ExpectedEPNodeAssignment expected_ep_assignment = ExpectedEPNodeAssignment::All) { +static void RunQDQGatherOpTest(const TestInputDef& input_def, + const TestInputDef& indices_def, + const std::vector& attrs, + int opset, + ExpectedEPNodeAssignment expected_ep_assignment) { ProviderOptions provider_options; #if defined(_WIN32) provider_options["backend_path"] = "QnnHtp.dll"; @@ -34,59 +30,71 @@ static void RunGatherOpQDQTest(int opset, const char* test_description, bool sca provider_options["backend_path"] = "libQnnHtp.so"; #endif - constexpr int expected_nodes_in_partition = 1; - if (scalar_indices) { - RunQnnModelTest(BuildQDQGatherOpScalarIndicesTestCase({2, 3, 4}, // input shape - 1, // indices - 1), // axis - provider_options, - opset, - expected_ep_assignment, - expected_nodes_in_partition, - test_description); - } else { - RunQnnModelTest(BuildQDQGatherOpTestCase({2, 3, 4}, // input shape - std::vector{1}, // indices - {1}, // indices_shape - 1), // axis - provider_options, - opset, - expected_ep_assignment, - expected_nodes_in_partition, - test_description); - } + auto f32_model_builder = BuildOpTestCase("Gather", {input_def}, {indices_def}, attrs); + auto qdq_model_builder = BuildQDQOpTestCase("Gather", {input_def}, {indices_def}, attrs); + + TestQDQModelAccuracy(f32_model_builder, + qdq_model_builder, + provider_options, + opset, + expected_ep_assignment); } // Test creates a DQ -> Gather -> Q -> DQ graph, and checks that all -// nodes are supported by the QNN EP, and that the inference results match the CPU EP results. +// nodes are supported by the QNN EP, and that the inference results are as accurate as CPU EP. // -// - Uses uint8 as the quantization type. -TEST_F(QnnHTPBackendTests, TestQDQGatherOpU8) { - RunGatherOpQDQTest(11, "TestQDQGatherOpU8"); +// Static int64 indices with default axis. +TEST_F(QnnHTPBackendTests, GatherOp_IndicesStaticInt64_Axis0) { + RunQDQGatherOpTest(TestInputDef({3, 2}, false, {1.0f, 1.2f, 2.3f, 3.4f, 4.5f, 5.7f}), + TestInputDef({2, 2}, true, {0, 1, 1, 2}), + {utils::MakeAttribute("axis", static_cast(0))}, + 13, + ExpectedEPNodeAssignment::All); +} + +// Tests that dynamic int64 indices are not supported on HTP backend. +TEST_F(QnnHTPBackendTests, GatherOp_IndicesDynamicInt64_Axis0) { + RunQDQGatherOpTest(TestInputDef({3, 2}, false, {1.0f, 1.2f, 2.3f, 3.4f, 4.5f, 5.7f}), + TestInputDef({2, 2}, false, {0, 1, 1, 2}), + {utils::MakeAttribute("axis", static_cast(0))}, + 13, + ExpectedEPNodeAssignment::None); } // Test creates a DQ -> Gather -> Q -> DQ graph, and checks that all -// nodes are supported by the QNN EP, and that the inference results match the CPU EP results. +// nodes are supported by the QNN EP, and that the inference results are as accurate as CPU EP. // -// - Uses int8 as the quantization type. -TEST_F(QnnHTPBackendTests, TestQDQGatherOpI8) { - RunGatherOpQDQTest(11, "TestQDQGatherOpI8"); +// Static int32 indices with default axis. +TEST_F(QnnHTPBackendTests, GatherOp_IndicesStaticInt32_Axis0) { + RunQDQGatherOpTest(TestInputDef({3, 2}, false, {1.0f, 1.2f, 2.3f, 3.4f, 4.5f, 5.7f}), + TestInputDef({2, 2}, true, {0, 1, 1, 2}), + {utils::MakeAttribute("axis", static_cast(0))}, + 13, + ExpectedEPNodeAssignment::All); } // Test creates a DQ -> Gather -> Q -> DQ graph, and checks that all -// nodes are supported by the QNN EP, and that the inference results match the CPU EP results. +// nodes are supported by the QNN EP, and that the inference results are as accurate as CPU EP. // -// - Uses uint8 as the quantization type. -TEST_F(QnnHTPBackendTests, TestQDQGatherOpScalarIndicesU8) { - RunGatherOpQDQTest(11, "TestQDQGatherOpScalarIndicesU8", true); +// Dynamic int32 indices with default axis. +TEST_F(QnnHTPBackendTests, GatherOp_IndicesDynamicInt32_Axis0) { + RunQDQGatherOpTest(TestInputDef({3, 2}, false, {1.0f, 1.2f, 2.3f, 3.4f, 4.5f, 5.7f}), + TestInputDef({2, 2}, false, {0, 1, 1, 2}), + {utils::MakeAttribute("axis", static_cast(0))}, + 13, + ExpectedEPNodeAssignment::All); } // Test creates a DQ -> Gather -> Q -> DQ graph, and checks that all -// nodes are supported by the QNN EP, and that the inference results match the CPU EP results. +// nodes are supported by the QNN EP, and that the inference results are as accurate as CPU EP. // -// - Uses int8 as the quantization type. -TEST_F(QnnHTPBackendTests, TestQDQGatherOpScalarIndicesI8) { - RunGatherOpQDQTest(11, "TestQDQGatherOpScalarIndicesI8", true); +// Static int32 indices with axis = 1 +TEST_F(QnnHTPBackendTests, GatherOp_IndicesStaticInt32_Axis1) { + RunQDQGatherOpTest(TestInputDef({3, 3}, false, {1.0f, 1.2f, 1.9f, 2.3f, 3.4f, 3.9f, 4.5f, 5.7f, 5.9f}), + TestInputDef({1, 2}, true, {0, 2}), + {utils::MakeAttribute("axis", static_cast(1))}, + 13, + ExpectedEPNodeAssignment::All); } #endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) diff --git a/onnxruntime/test/providers/qnn/gemm_op_test.cc b/onnxruntime/test/providers/qnn/gemm_op_test.cc new file mode 100644 index 0000000000000..15f26717b06fd --- /dev/null +++ b/onnxruntime/test/providers/qnn/gemm_op_test.cc @@ -0,0 +1,341 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#if !defined(ORT_MINIMAL_BUILD) + +#include +#include + +#include "test/providers/qnn/qnn_test_utils.h" +#include "core/graph/node_attr_utils.h" + +#include "onnx/onnx_pb.h" +#include "gtest/gtest.h" + +namespace onnxruntime { +namespace test { + +// Runs a model with a Gemm operator on the QNN CPU backend. Checks the graph node assignment +// and that inference outputs for QNN EP and CPU EP match. +template +static void RunGemmTestOnCPU(const std::vector>& input_defs, + const std::vector& attrs, + 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 + + RunQnnModelTest(BuildOpTestCase("Gemm", input_defs, {}, attrs), + provider_options, + opset, + expected_ep_assignment); +} + +// +// CPU tests: +// + +// Test that Gemm with non-default 'alpha' or 'beta' attributes is not supported by QNN EP. +TEST_F(QnnCPUBackendTests, Gemm_NonDefaultAlphaBeta_Unsupported) { + // Check that alpha != 1.0f is not supported. + RunGemmTestOnCPU({TestInputDef({1, 2}, false, -10.0f, 10.0f), + TestInputDef({2, 4}, false, -10.0f, 10.0f)}, + {utils::MakeAttribute("alpha", 1.5f)}, + ExpectedEPNodeAssignment::None); // Should not be assigned to QNN EP. + + // Check that beta != 1.0f is not supported. + RunGemmTestOnCPU({TestInputDef({1, 2}, false, -10.0f, 10.0f), + TestInputDef({2, 4}, false, -10.0f, 10.0f), + TestInputDef({1, 4}, false, -1.0f, 1.0f)}, + {utils::MakeAttribute("beta", 1.2f)}, + ExpectedEPNodeAssignment::None); // Should not be assigned to QNN EP. +} + +// Test that Gemm with general 2D bias (M, N) is NOT supported (unless M == 1). +// QNN's FullyConnected operator only supports `outputVector = ( inputAsVector * weightsMatrix ) + biasesVector` +TEST_F(QnnCPUBackendTests, Gemm_2D_Bias_Unsupported) { + std::vector input_a_data = GetFloatDataInRange(-10.0f, 10.0f, 6); + std::vector input_b_data = GetFloatDataInRange(-5.0f, 5.0f, 12); + + // 2D matrix mul with bias not supported. + RunGemmTestOnCPU({TestInputDef({2, 3}, false, input_a_data), + TestInputDef({3, 4}, false, input_b_data), + TestInputDef({2, 4}, false, -1.0f, 1.0f)}, + {}, + ExpectedEPNodeAssignment::None); // Should not be assigned to QNN EP. + + // However, 2D matrix mul without a bias is supported. Input A's 0th dimension is interpreted as `batch_size`. + RunGemmTestOnCPU({TestInputDef({2, 3}, false, input_a_data), + TestInputDef({3, 4}, false, input_b_data)}, + {}, + ExpectedEPNodeAssignment::All); // Assigned to QNN EP. +} + +// Test Gemm with dynamic (i.e., not initializer) inputs (A, B, Bias). +TEST_F(QnnCPUBackendTests, Gemm_Dynamic_A_B_Bias) { + std::vector input_a_data = GetFloatDataInRange(-10.0f, 10.0f, 6); + std::vector input_b_data = GetFloatDataInRange(-5.0f, 5.0f, 24); + std::vector input_c_data = GetFloatDataInRange(-1.0f, 1.0f, 4); + RunGemmTestOnCPU({TestInputDef({1, 6}, false, input_a_data), + TestInputDef({6, 4}, false, input_b_data), + TestInputDef({1, 4}, false, input_c_data)}, + {}, + ExpectedEPNodeAssignment::All); +} + +// Test Gemm with static B and Bias inputs. +TEST_F(QnnCPUBackendTests, Gemm_Static_B_And_Bias) { + std::vector input_a_data = GetFloatDataInRange(-10.0f, 10.0f, 6); + std::vector input_b_data = GetFloatDataInRange(-5.0f, 5.0f, 24); + std::vector input_c_data = GetFloatDataInRange(-1.0f, 1.0f, 4); + RunGemmTestOnCPU({TestInputDef({1, 6}, false, input_a_data), + TestInputDef({6, 4}, true, input_b_data), + TestInputDef({1, 4}, true, input_c_data)}, + {}, + ExpectedEPNodeAssignment::All); +} + +// Test Gemm with transposed A/B and static B and Bias inputs. +TEST_F(QnnCPUBackendTests, Gemm_TransAB_Static_B_And_Bias) { + std::vector input_a_data = GetFloatDataInRange(-10.0f, 10.0f, 6); + std::vector input_b_data = GetFloatDataInRange(-5.0f, 5.0f, 24); + std::vector input_c_data = GetFloatDataInRange(-1.0f, 1.0f, 4); + RunGemmTestOnCPU({TestInputDef({6, 1}, false, input_a_data), + TestInputDef({4, 6}, true, input_b_data), + TestInputDef({1, 4}, true, input_c_data)}, + {utils::MakeAttribute("transA", static_cast(1)), + utils::MakeAttribute("transB", static_cast(1))}, + ExpectedEPNodeAssignment::All); +} + +// Test Gemm with transposed A/B and dynamic (i.e., not initializer) B and Bias inputs. +TEST_F(QnnCPUBackendTests, Gemm_TransAB_Dynamic_B_And_Bias) { + std::vector input_a_data = GetFloatDataInRange(-10.0f, 10.0f, 6); + std::vector input_b_data = GetFloatDataInRange(-5.0f, 5.0f, 24); + std::vector input_c_data = GetFloatDataInRange(-1.0f, 1.0f, 4); + RunGemmTestOnCPU({TestInputDef({6, 1}, false, input_a_data), + TestInputDef({4, 6}, false, input_b_data), + TestInputDef({1, 4}, false, input_c_data)}, + {utils::MakeAttribute("transA", static_cast(1)), + utils::MakeAttribute("transB", static_cast(1))}, + ExpectedEPNodeAssignment::All); +} + +#if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) +// +// HTP tests: +// + +// Returns a function that builds a model with a QDQ Gemm node. +template +inline GetTestQDQModelFn BuildQDQGemmTestCase(const std::vector>& input_defs, + const std::vector& attrs, + bool use_contrib_qdq = false) { + return [input_defs, attrs, use_contrib_qdq](ModelTestBuilder& builder, + std::vector>& output_qparams) { + const size_t num_inputs = input_defs.size(); + assert(num_inputs == 2 || num_inputs == 3); + + std::vector op_inputs; + op_inputs.reserve(num_inputs); + + // Process input 0 + NodeArg* input0 = MakeTestInput(builder, input_defs[0]); + QuantParams input0_qparams = GetTestInputQuantParams(input_defs[0]); + NodeArg* input0_after_qdq = AddQDQNodePair(builder, input0, input0_qparams.scale, + input0_qparams.zero_point, use_contrib_qdq); + op_inputs.push_back(input0_after_qdq); + + // Process input 1 + NodeArg* input1 = MakeTestInput(builder, input_defs[1]); + QuantParams input1_qparams = GetTestInputQuantParams(input_defs[1]); + NodeArg* input1_after_qdq = AddQDQNodePair(builder, input1, input1_qparams.scale, + input1_qparams.zero_point, use_contrib_qdq); + op_inputs.push_back(input1_after_qdq); + + // Process bias + if (num_inputs == 3) { + NodeArg* bias_input = MakeTestQDQBiasInput(builder, input_defs[2], input0_qparams.scale * input1_qparams.scale, + use_contrib_qdq); + op_inputs.push_back(bias_input); + } + + // Op -> op_output + auto* gemm_output = builder.MakeIntermediate(); + Node& gemm_node = builder.AddNode("Gemm", op_inputs, {gemm_output}); + + for (const auto& attr : attrs) { + gemm_node.AddAttributeProto(attr); + } + + // op_output -> Q -> DQ -> output + AddQDQNodePairWithOutputAsGraphOutput(builder, gemm_output, output_qparams[0].scale, + output_qparams[0].zero_point, use_contrib_qdq); + }; +} + +// Runs a QDQ Gemm model on the QNN (HTP) EP and the ORT CPU EP. Checks the graph node assignment and that inference +// running the QDQ model on QNN EP is at least as accurate as on ORT CPU EP (compared to the baseline float32 model). +template +static void RunQDQGemmTestOnHTP(const std::vector>& input_defs, + const std::vector& attrs, + ExpectedEPNodeAssignment expected_ep_assignment, + int opset = 13, + float f32_abs_err = 1e-4f, + 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 + auto f32_model_builder = BuildOpTestCase("Gemm", input_defs, {}, attrs); + auto qdq_model_builder = BuildQDQGemmTestCase(input_defs, attrs, use_contrib_qdq); + TestQDQModelAccuracy(f32_model_builder, + qdq_model_builder, + provider_options, + opset, + expected_ep_assignment, + f32_abs_err); +} + +// Test 8-bit QDQ Gemm with dynamic inputs A and Bias. The B input is an initializer. +TEST_F(QnnHTPBackendTests, Gemm_Dynamic_A_Static_B_Dynamic_Bias_U8) { + std::vector input_a_data = GetFloatDataInRange(-10.0f, 10.0f, 6); + std::vector input_b_data = GetFloatDataInRange(-5.0f, 5.0f, 24); + std::vector input_c_data = GetFloatDataInRange(-1.0f, 1.0f, 4); + RunQDQGemmTestOnHTP({TestInputDef({1, 6}, false, input_a_data), + TestInputDef({6, 4}, true, input_b_data), + TestInputDef({1, 4}, false, input_c_data)}, + {}, + ExpectedEPNodeAssignment::All); +} + +// Test 16-bit QDQ Gemm with dynamic inputs A and Bias. The B input is an initializer. +// TODO: Inaccuracy detected for output 'output_0', element 0. +// Output quant params: scale=0.001872879103757441, zero_point=0. +// Expected val: 120.73912048339844 +// QNN QDQ val: 0 (err 120.73912048339844) +// CPU QDQ val: 120.73889923095703 (err 0.00022125244140625) +TEST_F(QnnHTPBackendTests, DISABLED_Gemm_Dynamic_A_Static_B_Dynamic_Bias_U16) { + std::vector input_a_data = GetFloatDataInRange(-10.0f, 10.0f, 6); + std::vector input_b_data = GetFloatDataInRange(-5.0f, 5.0f, 24); + std::vector input_c_data = GetFloatDataInRange(-1.0f, 1.0f, 4); + RunQDQGemmTestOnHTP({TestInputDef({1, 6}, false, input_a_data), + TestInputDef({6, 4}, true, input_b_data), + TestInputDef({1, 4}, false, input_c_data)}, + {}, + ExpectedEPNodeAssignment::All, + 13, // opset + 1e-4f, // f32_abs_err + true); // Use com.microsoft Q/DQ ops +} + +// Test QDQ Gemm (16bit act, 8bit weight) with dynamic inputs A and Bias. The B input is an initializer. +// TODO: Allow small inaccuracies based on % of expected value. +// Inaccuracy detected for output 'output_0', element 0. +// Output quant params: scale=0.001872879103757441, zero_point=0. +// Expected val: 120.73912048339844 +// QNN QDQ val: 120.48043823242188 (err 0.2586822509765625) +// CPU QDQ val: 120.48980712890625 (err 0.2493133544921875) +TEST_F(QnnHTPBackendTests, Gemm_Dynamic_A_Static_B_Dynamic_Bias_U16Act_U8Weight) { + std::vector input_a_data = GetFloatDataInRange(-10.0f, 10.0f, 6); + std::vector input_b_data = GetFloatDataInRange(-5.0f, 5.0f, 24); + std::vector input_c_data = GetFloatDataInRange(-1.0f, 1.0f, 4); + RunQDQGemmTestOnHTP({TestInputDef({1, 6}, false, input_a_data), + TestInputDef({6, 4}, true, input_b_data), + TestInputDef({1, 4}, false, input_c_data)}, + {}, + ExpectedEPNodeAssignment::All, + 13, // opset + 0.15f, // f32_abs_err + true); // Use com.microsoft Q/DQ ops +} + +// Test QDQ Gemm with dynamic A and B inputs. The Bias is static. +// TODO: Inaccuracy detected for output 'output', element 0. +// Output quant params: scale=0.48132994771003723, zero_point=0. +// Expected val: 120.73912048339844 +// QNN QDQ val: 77.012794494628906 (err 43.726325988769531) +// CPU QDQ val: 119.85115814208984 (err 0.88796234130859375) +TEST_F(QnnHTPBackendTests, DISABLED_Gemm_Dynamic_A_B_Static_Bias) { + std::vector input_a_data = GetFloatDataInRange(-10.0f, 10.0f, 6); + std::vector input_b_data = GetFloatDataInRange(-5.0f, 5.0f, 24); + std::vector input_c_data = GetFloatDataInRange(-1.0f, 1.0f, 4); + RunQDQGemmTestOnHTP({TestInputDef({1, 6}, false, input_a_data), + TestInputDef({6, 4}, false, input_b_data), // Dynamic => inaccuracy + TestInputDef({1, 4}, true, input_c_data)}, + {}, + ExpectedEPNodeAssignment::All); +} + +// Test QDQ Gemm with static B and Bias inputs. +TEST_F(QnnHTPBackendTests, Gemm_Static_B_And_Bias) { + std::vector input_a_data = GetFloatDataInRange(-10.0f, 10.0f, 6); + std::vector input_b_data = GetFloatDataInRange(-5.0f, 5.0f, 24); + std::vector input_c_data = GetFloatDataInRange(-1.0f, 1.0f, 4); + RunQDQGemmTestOnHTP({TestInputDef({1, 6}, false, input_a_data), + TestInputDef({6, 4}, true, input_b_data), + TestInputDef({1, 4}, true, input_c_data)}, + {}, + ExpectedEPNodeAssignment::All); +} + +// Test 8-bit QDQ Gemm with transposed A/B and static B and Bias inputs. +TEST_F(QnnHTPBackendTests, Gemm_TransAB_Static_B_And_Bias_U8) { + std::vector input_a_data = GetFloatDataInRange(-10.0f, 10.0f, 6); + std::vector input_b_data = GetFloatDataInRange(-5.0f, 5.0f, 24); + std::vector input_c_data = GetFloatDataInRange(-1.0f, 1.0f, 4); + RunQDQGemmTestOnHTP({TestInputDef({6, 1}, false, input_a_data), + TestInputDef({4, 6}, true, input_b_data), + TestInputDef({1, 4}, true, input_c_data)}, + {utils::MakeAttribute("transA", static_cast(1)), + utils::MakeAttribute("transB", static_cast(1))}, + ExpectedEPNodeAssignment::All); +} + +// Test QDQ Gemm (16bit activation, 8bit weight) with transposed A/B and static B and Bias inputs. +// TODO: Allow small inaccuracies based on % of expected value. +// Inaccuracy detected for output 'output_0', element 0. +// Output quant params: scale=0.00047966410056687891, zero_point=0. +// Expected val: 29.434776306152344 +// QNN QDQ val: 29.191877365112305 (err 0.24289894104003906) +// CPU QDQ val: 29.197153091430664 (err 0.23762321472167969) +TEST_F(QnnHTPBackendTests, Gemm_TransAB_Static_B_And_Bias_U16Act_U8Weight) { + std::vector input_a_data = GetFloatDataInRange(-10.0f, 10.0f, 6); + std::vector input_b_data = GetFloatDataInRange(-5.0f, 5.0f, 24); + std::vector input_c_data = GetFloatDataInRange(-1.0f, 1.0f, 4); + RunQDQGemmTestOnHTP({TestInputDef({6, 1}, false, input_a_data), + TestInputDef({4, 6}, true, input_b_data), + TestInputDef({1, 4}, true, input_c_data)}, + {utils::MakeAttribute("transA", static_cast(1)), + utils::MakeAttribute("transB", static_cast(1))}, + ExpectedEPNodeAssignment::All, + 13, // opset + 0.15f, // f32_abs_err + true); // Use com.microsoft Q/DQ ops +} + +// Test QDQ Gemm with transposed A/B and dynamic (i.e., not initializer) B and Bias inputs. +TEST_F(QnnHTPBackendTests, Gemm_TransAB_Dynamic_B_And_Bias) { + std::vector input_a_data = GetFloatDataInRange(-10.0f, 10.0f, 6); + std::vector input_b_data = GetFloatDataInRange(-5.0f, 5.0f, 24); + std::vector input_c_data = GetFloatDataInRange(-1.0f, 1.0f, 4); + RunQDQGemmTestOnHTP({TestInputDef({6, 1}, false, input_a_data), + TestInputDef({4, 6}, false, input_b_data), + TestInputDef({1, 4}, false, input_c_data)}, + {utils::MakeAttribute("transA", static_cast(1)), + utils::MakeAttribute("transB", static_cast(1))}, + ExpectedEPNodeAssignment::All); +} + +#endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) +} // namespace test +} // namespace onnxruntime +#endif // !defined(ORT_MINIMAL_BUILD) diff --git a/onnxruntime/test/providers/qnn/instance_norm_htp_test.cc b/onnxruntime/test/providers/qnn/instance_norm_htp_test.cc index cc648ad7e8b4a..f662ac14336f8 100644 --- a/onnxruntime/test/providers/qnn/instance_norm_htp_test.cc +++ b/onnxruntime/test/providers/qnn/instance_norm_htp_test.cc @@ -5,6 +5,7 @@ #include #include "core/graph/graph.h" +#include "core/graph/node_attr_utils.h" #include "test/optimizer/qdq_test_utils.h" #include "test/providers/qnn/qnn_test_utils.h" @@ -15,18 +16,56 @@ namespace onnxruntime { namespace test { #if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) +// Function that builds a QDQ model with an InstanceNormalization operator. +template +static GetTestQDQModelFn BuildQDQInstanceNormTestCase(const TestInputDef& input_def, + const TestInputDef& scale_def, + const TestInputDef& bias_def, + const std::vector& attrs) { + return [input_def, scale_def, bias_def, attrs](ModelTestBuilder& builder, + std::vector>& output_qparams) { + // input => Q => DQ => + NodeArg* input = MakeTestInput(builder, input_def); + QuantParams input_qparams = GetTestInputQuantParams(input_def); + NodeArg* input_qdq = AddQDQNodePair(builder, input, input_qparams.scale, input_qparams.zero_point); + + // scale => Q => DQ => + NodeArg* scale = MakeTestInput(builder, scale_def); + QuantParams scale_qparams = GetTestInputQuantParams(scale_def); + NodeArg* scale_qdq = AddQDQNodePair(builder, scale, scale_qparams.scale, scale_qparams.zero_point); + + // bias (as int32) => DQ => + NodeArg* bias_qdq = MakeTestQDQBiasInput(builder, bias_def, input_qparams.scale * scale_qparams.scale); + + // InstanceNormalization operator. + auto* instance_norm_output = builder.MakeIntermediate(); + Node& inst_norm_node = builder.AddNode("InstanceNormalization", {input_qdq, scale_qdq, bias_qdq}, + {instance_norm_output}); + for (const auto& attr : attrs) { + inst_norm_node.AddAttributeProto(attr); + } + + // Add instance_norm_output -> Q -> output_u8 + AddQDQNodePairWithOutputAsGraphOutput(builder, instance_norm_output, output_qparams[0].scale, output_qparams[0].zero_point); + }; +} + /** * Runs an InstanceNormalization model on the QNN HTP backend. Checks the graph node assignment, and that inference * outputs for QNN and CPU match. * - * \param input_shape The input's shape. - * \param epsilon The epsilon attribute. - * \param test_description Description of the test for error reporting. + * \param input_def The test input's definition (shape, is_initializer, data). + * \param scale_def The scale input's definition. Correct shapes must be 1D [num_input_channels]. + * \param bias_def The bias input's definition. Correct shapes must be 1D [num_input_channels]. + * \param attrs The node's attributes. The only valid attribute for InstanceNormalization is 'epsilon'. * \param expected_ep_assignment How many nodes are expected to be assigned to QNN (All, Some, or None). - * \param num_modes_in_graph The number of expected nodes in the graph. */ -static void RunInstanceNormQDQTest(const std::vector& input_shape, float epsilon, const char* test_description, - ExpectedEPNodeAssignment expected_ep_assignment, int num_nodes_in_graph) { +template +static void RunInstanceNormQDQTest(const TestInputDef& input_def, + const TestInputDef& scale_def, + const TestInputDef& bias_def, + const std::vector& attrs, + ExpectedEPNodeAssignment expected_ep_assignment) { ProviderOptions provider_options; #if defined(_WIN32) provider_options["backend_path"] = "QnnHtp.dll"; @@ -35,30 +74,41 @@ static void RunInstanceNormQDQTest(const std::vector& input_shape, floa #endif // Runs model with DQ-> InstanceNorm -> Q and compares the outputs of the CPU and QNN EPs. - RunQnnModelTest(BuildQDQInstanceNormTestCase(input_shape, epsilon), - provider_options, - 18, - expected_ep_assignment, - num_nodes_in_graph, - test_description); + TestQDQModelAccuracy(BuildOpTestCase("InstanceNormalization", {input_def, scale_def, bias_def}, {}, attrs), + BuildQDQInstanceNormTestCase(input_def, scale_def, bias_def, attrs), + provider_options, + 18, + expected_ep_assignment, + 1e-5f); } // Check that QNN compiles DQ -> InstanceNormalization -> Q as a single unit. // Use an input of rank 4. -TEST_F(QnnHTPBackendTests, TestQDQInstanceNormU8) { - RunInstanceNormQDQTest({1, 2, 3, 3}, 1e-05f, "TestQDQInstanceNormU8", ExpectedEPNodeAssignment::All, 1); +TEST_F(QnnHTPBackendTests, InstanceNormU8) { + RunInstanceNormQDQTest(TestInputDef({1, 2, 3, 3}, false, -10.0f, 10.0f), + TestInputDef({2}, true, -2.0f, 2.0f), + TestInputDef({2}, true, -3.0f, 3.0f), + {}, + ExpectedEPNodeAssignment::All); } // Check that QNN compiles DQ -> InstanceNormalization -> Q as a single unit. // Use an input of rank 3. -TEST_F(QnnHTPBackendTests, TestQDQInstanceNormU8Rank3) { - RunInstanceNormQDQTest({1, 2, 3}, 1e-05f, "TestQDQInstanceNormU8Rank3", ExpectedEPNodeAssignment::All, 1); +TEST_F(QnnHTPBackendTests, InstanceNormU8Rank3) { + RunInstanceNormQDQTest(TestInputDef({1, 2, 3}, false, {6.0f, 4.0f, 2.0f, 6.0f, 8.0f, 2.0f}), + TestInputDef({2}, true, {1.0f, 2.0f}), + TestInputDef({2}, true, {1.0f, 3.0f}), + {}, + ExpectedEPNodeAssignment::All); } // Check that QNN InstanceNorm operator does not handle inputs with rank > 4. -TEST_F(QnnHTPBackendTests, TestQDQInstanceNormU8Rank5) { - // No nodes should be assigned to QNN EP, and graph should have 5 (non-fused) nodes. - RunInstanceNormQDQTest({1, 2, 3, 3, 3}, 1e-05f, "TestQDQInstanceNormU8Rank5", ExpectedEPNodeAssignment::None, 5); +TEST_F(QnnHTPBackendTests, InstanceNormU8Rank5) { + RunInstanceNormQDQTest(TestInputDef({1, 2, 3, 3, 3}, false, -10.0f, 10.0f), + TestInputDef({2}, true, -2.0f, 2.0f), + TestInputDef({2}, true, -3.0f, 3.0f), + {}, + ExpectedEPNodeAssignment::None); } #endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) diff --git a/onnxruntime/test/providers/qnn/layer_norm_test.cc b/onnxruntime/test/providers/qnn/layer_norm_test.cc new file mode 100644 index 0000000000000..085454004e5a5 --- /dev/null +++ b/onnxruntime/test/providers/qnn/layer_norm_test.cc @@ -0,0 +1,158 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#if !defined(ORT_MINIMAL_BUILD) + +#include +#include "core/graph/graph.h" +#include "core/graph/node_attr_utils.h" + +#include "test/optimizer/qdq_test_utils.h" +#include "test/providers/qnn/qnn_test_utils.h" + +#include "gtest/gtest.h" + +namespace onnxruntime { +namespace test { +#if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) + +// Runs an LayerNorm model on the QNN CPU backend. Checks the graph node assignment and that inference +// outputs for QNN and CPU match. +static void RunLayerNormCpuTest(const TestInputDef& input_def, + const TestInputDef& scale_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 + + RunQnnModelTest(BuildOpTestCase("LayerNormalization", {input_def, scale_def}, {}, attrs), + provider_options, + 17, + expected_ep_assignment); +} + +TEST_F(QnnCPUBackendTests, LayerNorm) { + RunLayerNormCpuTest(TestInputDef({2, 3}, false, GetFloatDataInRange(0.0f, 10.0f, 6)), + TestInputDef({2, 3}, false, GetFloatDataInRange(0.0f, 10.0f, 6)), + {utils::MakeAttribute("axis", static_cast(0))}, + ExpectedEPNodeAssignment::All); +} + +TEST_F(QnnCPUBackendTests, LayerNorm1D_Axis0) { + RunLayerNormCpuTest(TestInputDef({1, 2, 3}, false, GetFloatDataInRange(0.0f, 10.0f, 6)), + TestInputDef({1, 2, 3}, false, GetFloatDataInRange(0.0f, 10.0f, 6)), + {utils::MakeAttribute("axis", static_cast(0))}, + ExpectedEPNodeAssignment::All); +} + +TEST_F(QnnCPUBackendTests, LayerNorm1D_AxisLast) { + RunLayerNormCpuTest(TestInputDef({1, 2, 3}, false, GetFloatDataInRange(0.0f, 10.0f, 6)), + TestInputDef({3}, false, GetFloatDataInRange(0.0f, 10.0f, 3)), + {utils::MakeAttribute("axis", static_cast(-1))}, + ExpectedEPNodeAssignment::All); +} + +TEST_F(QnnCPUBackendTests, LayerNorm2D) { + RunLayerNormCpuTest(TestInputDef({1, 2, 3, 3}, false, GetFloatDataInRange(0.0f, 10.0f, 18)), + TestInputDef({1, 2, 3, 3}, false, GetFloatDataInRange(0.0f, 10.0f, 18)), + {utils::MakeAttribute("axis", static_cast(0))}, + ExpectedEPNodeAssignment::All); +} + +TEST_F(QnnCPUBackendTests, LayerNorm3D) { + RunLayerNormCpuTest(TestInputDef({1, 2, 3, 3, 4}, false, GetFloatDataInRange(0.0f, 10.0f, 72)), + TestInputDef({1, 2, 3, 3, 4}, false, GetFloatDataInRange(0.0f, 10.0f, 72)), + {utils::MakeAttribute("axis", static_cast(0))}, + ExpectedEPNodeAssignment::All); +} + +template +GetTestQDQModelFn BuildQDQLayerNormTestCase(const TestInputDef& input_def, + const TestInputDef& scale_def, + const std::vector& attrs) { + return [input_def, scale_def, attrs](ModelTestBuilder& builder, + std::vector>& output_qparams) { + // input -> Q -> DQ -> + NodeArg* input = MakeTestInput(builder, input_def); + QuantParams input_qparams = GetTestInputQuantParams(input_def); + NodeArg* input_qdq = AddQDQNodePair(builder, input, input_qparams.scale, input_qparams.zero_point); + + // scale input -> Q -> DQ -> + NodeArg* scale = MakeTestInput(builder, scale_def); + QuantParams scale_qparams = GetTestInputQuantParams(scale_def); + NodeArg* scale_qdq = AddQDQNodePair(builder, scale, scale_qparams.scale, scale_qparams.zero_point); + + // LayerNormalization + NodeArg* layer_norm_output = builder.MakeIntermediate(); + Node& layer_norm_node = builder.AddNode("LayerNormalization", {input_qdq, scale_qdq}, {layer_norm_output}); + + for (const auto& attr : attrs) { + layer_norm_node.AddAttributeProto(attr); + } + + // layer_norm_output -> Q -> DQ -> output + AddQDQNodePairWithOutputAsGraphOutput(builder, layer_norm_output, output_qparams[0].scale, + output_qparams[0].zero_point); + }; +} + +// Runs a QDQ LayerNorm model on the QNN HTP backend. Checks the graph node assignment and that inference +// outputs for QNN are as accurate as CPU EP (compares against f32 model and QDQ model). +template +static void RunLayerNormQDQTest(const TestInputDef& input_def, + const TestInputDef& scale_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 + + TestQDQModelAccuracy(BuildOpTestCase("LayerNormalization", {input_def, scale_def}, {}, attrs), + BuildQDQLayerNormTestCase(input_def, scale_def, attrs), + provider_options, + 17, // opset + expected_ep_assignment); +} + +// Test that QNN HTP only supports axis = -1 (i.e., last dimension). +TEST_F(QnnHTPBackendTests, LayerNorm1D_Axis0_Unsupported) { + RunLayerNormQDQTest(TestInputDef({1, 2, 3}, false, 0.0f, 10.0f), + TestInputDef({1, 2, 3}, true, 0.0f, 10.0f), + {utils::MakeAttribute("axis", static_cast(0))}, // Unsupported axis + ExpectedEPNodeAssignment::None); +} + +// Test accuracy of 8-bit QDQ LayerNorm with a static scale input. This used to fail on QNN DK 2.13, +// but was fixed in QNN SDK 2.14. +TEST_F(QnnHTPBackendTests, LayerNorm1D_LastAxis_StaticScale) { + RunLayerNormQDQTest(TestInputDef({1, 2, 3}, false, GetFloatDataInRange(0.0f, 10.0f, 6)), + TestInputDef({3}, true, GetFloatDataInRange(0.0f, 1.0f, 3)), // Static + {utils::MakeAttribute("axis", static_cast(-1))}, // Last axis + ExpectedEPNodeAssignment::All); +} + +// Test accuracy of 8-bit QDQ LayerNorm with a dynamic scale input. +// TODO(adrianlizarraga): Investigate graph finalization error in QNN SDK 2.14.1 +// Failed QNN FinalizeGraphs: QnnDsp Failed to finalize graph (id: 1) with err 1002 +// C:\qnn_src\QNN\HTP\HTP\src\hexagon\prepare\graph_prepare.cc:232:ERROR:could not create op: q::flat_from_vtcm +// C:\qnn_src\QNN\HTP\HTP\src\hexagon\prepare\graph_prepare.cc:1021:ERROR:Op 0x103d00000002 preparation failed with err:-1 +TEST_F(QnnHTPBackendTests, DISABLED_LayerNorm1D_LastAxis_DynamicScale) { + RunLayerNormQDQTest(TestInputDef({1, 2, 3}, false, GetFloatDataInRange(0.0f, 10.0f, 6)), + TestInputDef({3}, false, GetFloatDataInRange(0.0f, 1.0f, 3)), // Dynamic + {utils::MakeAttribute("axis", static_cast(-1))}, // Last axis + ExpectedEPNodeAssignment::All); +} + +#endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) + +} // namespace test +} // namespace onnxruntime + +#endif diff --git a/onnxruntime/test/providers/qnn/leakyrelu_op_htp_test.cc b/onnxruntime/test/providers/qnn/leakyrelu_op_htp_test.cc index 18f2e11337e2b..e3077ec569923 100644 --- a/onnxruntime/test/providers/qnn/leakyrelu_op_htp_test.cc +++ b/onnxruntime/test/providers/qnn/leakyrelu_op_htp_test.cc @@ -5,6 +5,7 @@ #include #include "core/graph/graph.h" +#include "core/graph/node_attr_utils.h" #include "test/optimizer/qdq_test_utils.h" #include "test/providers/qnn/qnn_test_utils.h" @@ -15,18 +16,12 @@ namespace onnxruntime { namespace test { #if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) -/** - * Runs a LeakyRelu op model on the QNN HTP backend. Checks the graph node assignment, and that inference - * outputs for QNN and CPU match. - * - * \param op_type The LeakyRelu op type (e.g., ReduceSum). - * \param opset The opset version. - * \param test_description Description of the test for error reporting. - * \param expected_ep_assignment How many nodes are expected to be assigned to QNN (All, Some, or None) - */ +// Checks the accuracy of a QDQ LeakyRelu model by comparing to ORT CPU EP. template -static void RunLeakyReluOpQDQTest(int opset, const char* test_description, - ExpectedEPNodeAssignment expected_ep_assignment = ExpectedEPNodeAssignment::All) { +static void RunLeakyReluOpQDQTest(const TestInputDef& input_def, + const std::vector& attrs, + int opset, + ExpectedEPNodeAssignment expected_ep_assignment) { ProviderOptions provider_options; #if defined(_WIN32) provider_options["backend_path"] = "QnnHtp.dll"; @@ -34,29 +29,33 @@ static void RunLeakyReluOpQDQTest(int opset, const char* test_description, provider_options["backend_path"] = "libQnnHtp.so"; #endif - constexpr int expected_nodes_in_partition = 1; - RunQnnModelTest(BuildQDQLeakyReluOpTestCase({2, 3, 4}), - provider_options, - opset, - expected_ep_assignment, - expected_nodes_in_partition, - test_description); + TestQDQModelAccuracy(BuildOpTestCase("LeakyRelu", {input_def}, {}, attrs), + BuildQDQOpTestCase("LeakyRelu", {input_def}, {}, attrs), + provider_options, + opset, + expected_ep_assignment); } // Test creates a DQ -> Gather -> Q -> DQ graph, and checks that all // nodes are supported by the QNN EP, and that the inference results match the CPU EP results. // // - Uses uint8 as the quantization type. -TEST_F(QnnHTPBackendTests, TestQDQLeakyReluOpSet15) { - RunLeakyReluOpQDQTest(15, "TestQDQLeakyReluOpSet15"); +TEST_F(QnnHTPBackendTests, LeakyReluOpSet15) { + RunLeakyReluOpQDQTest(TestInputDef({1, 2, 3}, false, {-40.0f, -20.0f, 0.0f, 10.0f, 30.0f, 40.0f}), + {utils::MakeAttribute("alpha", 0.2f)}, + 15, + ExpectedEPNodeAssignment::All); } // Test creates a DQ -> Gather -> Q -> DQ graph, and checks that all // nodes are supported by the QNN EP, and that the inference results match the CPU EP results. // // - Uses uint8 as the quantization type. -TEST_F(QnnHTPBackendTests, TestQDQLeakyReluOpSet16) { - RunLeakyReluOpQDQTest(16, "TestQDQLeakyReluOpSet16"); +TEST_F(QnnHTPBackendTests, LeakyReluOpSet16) { + RunLeakyReluOpQDQTest(TestInputDef({1, 2, 3}, false, {-40.0f, -20.0f, 0.0f, 10.0f, 30.0f, 40.0f}), + {utils::MakeAttribute("alpha", 0.2f)}, + 16, + ExpectedEPNodeAssignment::All); } #endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) diff --git a/onnxruntime/test/providers/qnn/logical_comp_ops_test.cc b/onnxruntime/test/providers/qnn/logical_comp_ops_test.cc new file mode 100644 index 0000000000000..59105136781f4 --- /dev/null +++ b/onnxruntime/test/providers/qnn/logical_comp_ops_test.cc @@ -0,0 +1,198 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#if !defined(ORT_MINIMAL_BUILD) + +#include +#include + +#include "test/optimizer/qdq_test_utils.h" +#include "test/providers/qnn/qnn_test_utils.h" + +#include "onnx/onnx_pb.h" + +#include "gtest/gtest.h" + +namespace onnxruntime { +namespace test { + +// Creates a graph with a single logical operator (e.g., Equal). Used for testing CPU backend. +static GetTestModelFn BuildLogicalOpTestCase(const std::string& op_type, const std::vector& shape) { + return [op_type, shape](ModelTestBuilder& builder) { + auto* input0 = builder.MakeInput(shape, 0.0f, 20.0f); + auto* input1 = builder.MakeInput(shape, 0.0f, 20.0f); + NodeArg* output = nullptr; + + // Explicitly set output type/shape for logical comparison ops implemented as functions. + if (op_type == "GreaterOrEqual" || op_type == "LessOrEqual") { + output = builder.MakeOutput(shape); + } else { + output = builder.MakeOutput(); + } + + builder.AddNode(op_type, {input0, input1}, {output}); + }; +} + +// Creates a graph with a single Q/DQ logical operator. Used for testing HTP backend. +template +static GetTestModelFn BuildQDQLogicalOpTestCase(const std::string& op_type, const std::vector& shape) { + return [op_type, shape](ModelTestBuilder& builder) { + const InputQType zero_point = std::numeric_limits::max() / 2; + constexpr float qdq_scale = 0.0038f; + + auto* input0 = builder.MakeInput(shape, -1.0f, 1.0f); + auto* input1 = builder.MakeInput(shape, -1.0f, 1.0f); + NodeArg* output = nullptr; + + // Explicitly set output type/shape for logical comparison ops implemented as functions. + if (op_type == "GreaterOrEqual" || op_type == "LessOrEqual") { + output = builder.MakeOutput(shape); + } else { + output = builder.MakeOutput(); + } + + // input -> Q -> DQ -> Op + auto* qdq0_output = AddQDQNodePair(builder, input0, qdq_scale, zero_point); + auto* qdq1_output = AddQDQNodePair(builder, input1, qdq_scale, zero_point); + + // Op -> output + builder.AddNode(op_type, {qdq0_output, qdq1_output}, {output}); + }; +} + +// Runs a model with a logical operator on the QNN CPU backend. Checks the graph node assignment, and that inference +// outputs for QNN EP and CPU EP match. +static void RunCPULogicalOpTest(const std::string& op_type, const std::vector& shape, + ExpectedEPNodeAssignment expected_ep_assignment, + int opset = 17) { + ProviderOptions provider_options; + +#if defined(_WIN32) + provider_options["backend_path"] = "QnnCpu.dll"; +#else + provider_options["backend_path"] = "libQnnCpu.so"; +#endif + + RunQnnModelTest(BuildLogicalOpTestCase(op_type, shape), + provider_options, + opset, + expected_ep_assignment); +} + +// Runs a model with a logical operator on the QNN HTP backend. Checks the graph node assignment, and that inference +// outputs for QNN EP and CPU EP match. +template +static void RunQDQLogicalOpTest(const std::string& op_type, const std::vector& shape, + ExpectedEPNodeAssignment expected_ep_assignment, + int opset = 17) { + ProviderOptions provider_options; +#if defined(_WIN32) + provider_options["backend_path"] = "QnnHtp.dll"; +#else + provider_options["backend_path"] = "libQnnHtp.so"; +#endif + + RunQnnModelTest(BuildQDQLogicalOpTestCase(op_type, shape), + provider_options, + opset, + expected_ep_assignment); +} + +// +// CPU tests: +// + +TEST_F(QnnCPUBackendTests, LogicalOpEqual4D) { + RunCPULogicalOpTest("Equal", {1, 3, 16, 16}, ExpectedEPNodeAssignment::All); +} + +TEST_F(QnnCPUBackendTests, LogicalOpGreater4D) { + RunCPULogicalOpTest("Greater", {1, 3, 16, 16}, ExpectedEPNodeAssignment::All); +} + +TEST_F(QnnCPUBackendTests, LogicalOpGreaterOrEqual4D) { + RunCPULogicalOpTest("GreaterOrEqual", {1, 3, 16, 16}, ExpectedEPNodeAssignment::All); +} + +TEST_F(QnnCPUBackendTests, LogicalOpLess4D) { + RunCPULogicalOpTest("Less", {1, 3, 16, 16}, ExpectedEPNodeAssignment::All); +} + +TEST_F(QnnCPUBackendTests, LogicalOpLessOrEqual4D) { + RunCPULogicalOpTest("LessOrEqual", {1, 3, 16, 16}, ExpectedEPNodeAssignment::All); +} + +#if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) +// +// HTP tests: +// + +TEST_F(QnnHTPBackendTests, LogicalOpEqual4D) { + RunQDQLogicalOpTest("Equal", {1, 3, 16, 16}, ExpectedEPNodeAssignment::All); +} + +TEST_F(QnnHTPBackendTests, LogicalOpGreater4D) { + RunQDQLogicalOpTest("Greater", {1, 3, 16, 16}, ExpectedEPNodeAssignment::All); +} + +TEST_F(QnnHTPBackendTests, LogicalOpGreaterOrEqual4D) { + RunQDQLogicalOpTest("GreaterOrEqual", {1, 3, 16, 16}, ExpectedEPNodeAssignment::All); +} + +TEST_F(QnnHTPBackendTests, LogicalOpLess4D) { + RunQDQLogicalOpTest("Less", {1, 3, 16, 16}, ExpectedEPNodeAssignment::All); +} + +TEST_F(QnnHTPBackendTests, LogicalOpLessOrEqual4D) { + RunQDQLogicalOpTest("LessOrEqual", {1, 3, 16, 16}, ExpectedEPNodeAssignment::All); +} + +// Test for bug 44777546. +// 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 + + // Model building function that creates a QDQ graph with an Equal node followed by + // a Cast to float32. + auto build_qdq_equal_to_cast = [](ModelTestBuilder& builder) { + constexpr uint8_t zero_point = 0; + constexpr float qdq_scale = 0.0038f; + const std::vector input_shape = {1, 3, 8, 8}; + + auto* input0 = builder.MakeInput(input_shape, -1.0f, 1.0f); + auto* input1 = builder.MakeInput(input_shape, -1.0f, 1.0f); + auto* output = builder.MakeOutput(); + + // input -> Q -> DQ -> Op + auto* qdq0_output = AddQDQNodePair(builder, input0, qdq_scale, zero_point); + auto* qdq1_output = AddQDQNodePair(builder, input1, qdq_scale, zero_point); + + // Equal -> + auto* equal_output = builder.MakeIntermediate(); + builder.AddNode("Equal", {qdq0_output, qdq1_output}, {equal_output}); + + // -> Cast -> output + Node& cast_node = builder.AddNode("Cast", {equal_output}, {output}); + cast_node.AddAttribute("to", + static_cast(ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_FLOAT)); + }; + + RunQnnModelTest(build_qdq_equal_to_cast, + provider_options, + 17, // opset + ExpectedEPNodeAssignment::All, + 1); // expected nodes in graph +} + +#endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) + +} // namespace test +} // namespace onnxruntime + +#endif // !defined(ORT_MINIMAL_BUILD) diff --git a/onnxruntime/test/providers/qnn/lrn_op_test.cc b/onnxruntime/test/providers/qnn/lrn_op_test.cc new file mode 100644 index 0000000000000..4f64b4a7e0d3f --- /dev/null +++ b/onnxruntime/test/providers/qnn/lrn_op_test.cc @@ -0,0 +1,153 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#if !defined(ORT_MINIMAL_BUILD) + +#include +#include + +#include "test/optimizer/qdq_test_utils.h" +#include "test/providers/qnn/qnn_test_utils.h" + +#include "onnx/onnx_pb.h" + +#include "gtest/gtest.h" + +namespace onnxruntime { +namespace test { + +// Creates a graph with a single LRN operator. Used for testing CPU backend. +static GetTestModelFn BuildLRNTestCase(const TestInputDef& input_def, int64_t size, + float alpha = 0.0001f, float beta = 0.75f, float bias = 1.0f) { + return [input_def, size, alpha, beta, bias](ModelTestBuilder& builder) { + auto* input = MakeTestInput(builder, input_def); + auto* output = builder.MakeOutput(); + + Node& lrn_node = builder.AddNode("LRN", {input}, {output}); + lrn_node.AddAttribute("size", size); + lrn_node.AddAttribute("alpha", alpha); + lrn_node.AddAttribute("beta", beta); + lrn_node.AddAttribute("bias", bias); + }; +} + +// Creates a graph with a single Q/DQ LRN operator. Used for testing HTP backend. +template +static GetTestQDQModelFn BuildQDQLRNTestCase(const TestInputDef& input_def, int64_t size, + float alpha = 0.0001f, float beta = 0.75f, float bias = 1.0f) { + return [input_def, size, alpha, beta, bias](ModelTestBuilder& builder, + std::vector>& output_qparams) { + // input -> Q -> DQ -> + NodeArg* input = MakeTestInput(builder, input_def); + QuantParams input_qparams = GetTestInputQuantParams(input_def); + NodeArg* input_qdq = AddQDQNodePair(builder, input, input_qparams.scale, input_qparams.zero_point); + + // LRN + NodeArg* lrn_output = builder.MakeIntermediate(); + Node& lrn_node = builder.AddNode("LRN", {input_qdq}, {lrn_output}); + lrn_node.AddAttribute("size", size); + lrn_node.AddAttribute("alpha", alpha); + lrn_node.AddAttribute("beta", beta); + lrn_node.AddAttribute("bias", bias); + + // LRN output -> Q -> DQ -> final output + AddQDQNodePairWithOutputAsGraphOutput(builder, lrn_output, output_qparams[0].scale, + output_qparams[0].zero_point); + }; +} + +// Runs an LRN model on the QNN CPU backend. Checks the graph node assignment, and that inference +// outputs for QNN EP and CPU EP match. +static void RunCPULRNOpTest(const TestInputDef& input_def, int64_t size, + ExpectedEPNodeAssignment expected_ep_assignment, + float alpha = 0.0001f, float beta = 0.75f, float bias = 1.0f, int opset = 13) { + 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"; + fp32_abs_err = 1.5e-5f; // On linux we need slightly larger tolerance. +#endif + + RunQnnModelTest(BuildLRNTestCase(input_def, size, alpha, beta, bias), + provider_options, + opset, + expected_ep_assignment, + fp32_abs_err); +} + +// Runs an LRN model on the QNN HTP backend. Checks the graph node assignment, and that inference +// outputs for QNN EP and CPU EP match. +template +static void RunQDQLRNOpTest(const TestInputDef& input_def, int64_t size, + ExpectedEPNodeAssignment expected_ep_assignment, + float alpha = 0.0001f, float beta = 0.75f, float bias = 1.0f, + int opset = 13) { + ProviderOptions provider_options; +#if defined(_WIN32) + provider_options["backend_path"] = "QnnHtp.dll"; +#else + provider_options["backend_path"] = "libQnnHtp.so"; +#endif + + TestQDQModelAccuracy(BuildLRNTestCase(input_def, size, alpha, beta, bias), + BuildQDQLRNTestCase(input_def, size, alpha, beta, bias), + provider_options, + opset, + expected_ep_assignment, + 1e-5f); +} + +// +// CPU tests: +// + +TEST_F(QnnCPUBackendTests, LRNSize3) { + RunCPULRNOpTest(TestInputDef({1, 128, 4, 5}, false, -10.0f, 10.0f), + 3, // Size + ExpectedEPNodeAssignment::All); +} + +TEST_F(QnnCPUBackendTests, LRNSize5) { + RunCPULRNOpTest(TestInputDef({1, 128, 4, 5}, false, -10.0f, 10.0f), + 5, // Size + ExpectedEPNodeAssignment::All); +} + +TEST_F(QnnCPUBackendTests, LRN_size_larger_than_channel) { + RunCPULRNOpTest(TestInputDef({1, 128, 4, 5}, false, -10.0f, 10.0f), + 255, // Size + ExpectedEPNodeAssignment::All); +} + +#if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) +// +// HTP tests: +// + +TEST_F(QnnHTPBackendTests, LRNSize3) { + RunQDQLRNOpTest(TestInputDef({1, 128, 4, 5}, false, -10.0f, 10.0f), + 3, // Size + ExpectedEPNodeAssignment::All); +} + +TEST_F(QnnHTPBackendTests, LRNSize5) { + RunQDQLRNOpTest(TestInputDef({1, 128, 4, 5}, false, -10.0f, 10.0f), + 5, // Size + ExpectedEPNodeAssignment::All); +} + +TEST_F(QnnHTPBackendTests, LRN_size_larger_than_channel) { + RunQDQLRNOpTest(TestInputDef({1, 128, 4, 5}, false, -10.0f, 10.0f), + 255, // Size + ExpectedEPNodeAssignment::All); +} + +#endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) + +} // namespace test +} // namespace onnxruntime + +#endif // !defined(ORT_MINIMAL_BUILD) diff --git a/onnxruntime/test/providers/qnn/matmul_test.cpp b/onnxruntime/test/providers/qnn/matmul_test.cpp new file mode 100644 index 0000000000000..e721ccbcb45a9 --- /dev/null +++ b/onnxruntime/test/providers/qnn/matmul_test.cpp @@ -0,0 +1,205 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#if !defined(ORT_MINIMAL_BUILD) + +#include +#include + +#include "test/providers/qnn/qnn_test_utils.h" + +#include "onnx/onnx_pb.h" + +#include "gtest/gtest.h" + +namespace onnxruntime { +namespace test { + +// Returns a function that creates a graph with MatMul operator. +static GetTestModelFn BuildMatMulOpTestCase(const TestInputDef& input1_def, + const TestInputDef& input2_def) { + return [input1_def, input2_def](ModelTestBuilder& builder) { + NodeArg* input1 = MakeTestInput(builder, input1_def); + NodeArg* input2 = MakeTestInput(builder, input2_def); + NodeArg* output = builder.MakeOutput(); + builder.AddNode("MatMul", {input1, input2}, {output}); + }; +} + +// Returns a function that creates a graph with a QDQ MatMul operator. +template +static GetTestQDQModelFn BuildMatMulOpQDQTestCase(const TestInputDef& input1_def, + const TestInputDef& input2_def, + bool use_contrib_qdq) { + return [input1_def, input2_def, use_contrib_qdq](ModelTestBuilder& builder, + std::vector>& output_qparams) { + // input1 -> Q -> DQ -> + NodeArg* input1 = MakeTestInput(builder, input1_def); + QuantParams input1_qparams = GetTestInputQuantParams(input1_def); + auto* input1_qdq = AddQDQNodePair(builder, input1, input1_qparams.scale, input1_qparams.zero_point, + use_contrib_qdq); + + // input2 -> Q -> DQ -> + NodeArg* input2 = MakeTestInput(builder, input2_def); + QuantParams input2_qparams = GetTestInputQuantParams(input2_def); + auto* input2_qdq = AddQDQNodePair(builder, input2, input2_qparams.scale, input2_qparams.zero_point, + use_contrib_qdq); + + // MatMul + auto* op_output = builder.MakeIntermediate(); + builder.AddNode("MatMul", {input1_qdq, input2_qdq}, {op_output}); + + // op_output -> Q -> DQ -> output + AddQDQNodePairWithOutputAsGraphOutput(builder, op_output, output_qparams[0].scale, + output_qparams[0].zero_point, use_contrib_qdq); + }; +} + +// Runs an MatMul model on the QNN CPU backend. Checks the graph node assignment, and that inference +// outputs for QNN and CPU match. +static void RunMatMulOpOpTest(const TestInputDef& input1_def, + const TestInputDef& input2_def, + ExpectedEPNodeAssignment expected_ep_assignment, + int opset = 13, + float f32_abs_err = 1e-4f) { + ProviderOptions provider_options; +#if defined(_WIN32) + provider_options["backend_path"] = "QnnCpu.dll"; +#else + provider_options["backend_path"] = "libQnnCpu.so"; +#endif + + RunQnnModelTest(BuildMatMulOpTestCase(input1_def, input2_def), + provider_options, + opset, + expected_ep_assignment, + f32_abs_err); +} + +// Runs a QDQ MatMul model on the QNN HTP backend. Checks the graph node assignment, and that the +// QDQ model is accurate on QNN EP (compared to CPU EP). +template +static void RunQDQMatMulOpOpTest(const TestInputDef& input1_def, + const TestInputDef& input2_def, + ExpectedEPNodeAssignment expected_ep_assignment, + int opset = 18, + bool use_contrib_qdq = false, + float fp32_abs_err = 1e-4f) { + ProviderOptions provider_options; +#if defined(_WIN32) + provider_options["backend_path"] = "QnnHtp.dll"; +#else + provider_options["backend_path"] = "libQnnHtp.so"; +#endif + + TestQDQModelAccuracy(BuildMatMulOpTestCase(input1_def, input2_def), + BuildMatMulOpQDQTestCase(input1_def, input2_def, + use_contrib_qdq), + provider_options, + opset, + expected_ep_assignment, + fp32_abs_err); +} + +// +// CPU tests: +// + +TEST_F(QnnCPUBackendTests, MatMulOp) { + RunMatMulOpOpTest(TestInputDef({2, 3}, false, {-10.0f, -4.0f, -2.0f, 0.0f, 5.0f, 10.0f}), + TestInputDef({3, 2}, false, {-10.0f, -6.0f, -1.0f, 0.0f, 3.0f, 10.0f}), + ExpectedEPNodeAssignment::All, 18); +} + +// Test MatMul broadcasting +// Note slight inaccuracy in CPU backend: +// Expected: contains 896 values, where each value and its corresponding value in 16-byte object +// <80-03 00-00 00-00 00-00 40-00 34-DD F7-01 00-00> are an almost-equal pair +// Actual: 16-byte object <80-03 00-00 00-00 00-00 40-00 23-DD F7-01 00-00>, +// where the value pair (73.68116, 73.680809) at index #80 don't match, which is -0.000350952 from 73.6812 +TEST_F(QnnCPUBackendTests, MatMulOp_Broadcast) { + // Create two matrices with element values in the range [-10.0, 10.0]. + std::vector input_a = GetFloatDataInRange(-10.0f, 10.0f, 28 * 64); + std::vector input_b = GetFloatDataInRange(-10.0f, 10.0f, 64 * 32); + + RunMatMulOpOpTest(TestInputDef({28, 1, 64}, false, input_a), + TestInputDef({64, 32}, false, input_b), + ExpectedEPNodeAssignment::All, 18, 0.0004f); +} + +#if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) +// +// HTP tests: +// + +TEST_F(QnnHTPBackendTests, MatMulOp_HTP_u8) { + std::vector input0_data = {-10.0f, -4.0f, -2.0f, 0.0f, 5.0f, 10.0f}; + std::vector input1_data = {-10.0f, -6.0f, -1.0f, 0.0f, 3.0f, 10.0f}; + RunQDQMatMulOpOpTest(TestInputDef({2, 3}, false, input0_data), + TestInputDef({3, 2}, false, input1_data), + ExpectedEPNodeAssignment::All, 18); +} + +// Test QDQ MatMul with 16-bit act, 8-bit weights (static) +// TODO: (SLIGHT) Inaccuracy detected for output 'output', element 0. +// Output quant params: scale=0.0015259021893143654, zero_point=0. +// Expected val: 98 +// QNN QDQ val: 97.720298767089844 (err 0.27970123291015625) +// CPU QDQ val: 97.726402282714844 (err 0.27359771728515625) +TEST_F(QnnHTPBackendTests, MatMulOp_HTP_A16_W8Static) { + std::vector input0_data = {-10.0f, -4.0f, -2.0f, 0.0f, 5.0f, 10.0f}; + std::vector input1_data = {-10.0f, -6.0f, -1.0f, 0.0f, 3.0f, 10.0f}; + RunQDQMatMulOpOpTest(TestInputDef({2, 3}, false, input0_data), + TestInputDef({3, 2}, true, input1_data), + ExpectedEPNodeAssignment::All, + 18, + true, // Use com.microsoft Q/DQ ops + 7e-3f); +} + +// Test 16-bit QDQ MatMul with static weights +// TODO: Inaccuracy detected for output 'output', element 0. +// Output quant params: scale=0.0015259021893143654, zero_point=0. +// Expected val: 98 +// QNN QDQ val: 0.65461206436157227 (err 97.345390319824219) +// CPU QDQ val: 98.002593994140625 (err 0.002593994140625) +TEST_F(QnnHTPBackendTests, DISABLED_MatMulOp_HTP_A16_W16) { + std::vector input0_data = {-10.0f, -4.0f, -2.0f, 0.0f, 5.0f, 10.0f}; + std::vector input1_data = {-10.0f, -6.0f, -1.0f, 0.0f, 3.0f, 10.0f}; + RunQDQMatMulOpOpTest(TestInputDef({2, 3}, false, input0_data), + TestInputDef({3, 2}, true, input1_data), + ExpectedEPNodeAssignment::All, + 18, + true); // Use com.microsoft Q/DQ ops +} + +// Test 8-bit QDQ MatMul broadcasting +TEST_F(QnnHTPBackendTests, MatMulOp_Broadcast) { + RunQDQMatMulOpOpTest(TestInputDef({28, 1, 64}, false, -10.0f, 10.0f), + TestInputDef({64, 32}, false, -10.0f, 10.0f), + ExpectedEPNodeAssignment::All, 18); +} + +// Test 16-bit QDQ MatMul broadcasting +// TODO: Inaccuracy detected for output 'output', element 0. +// Output quant params: scale=0.0028538699261844158, zero_point=6050. +// Expected val: 169.76341247558594 +// QNN QDQ val: -16.675161361694336 (err 186.43856811523438) +// CPU QDQ val: 169.762451171875 (err 0.0009613037109375) +TEST_F(QnnHTPBackendTests, DISABLED_MatMulOp_Broadcast_A16_W16) { + std::vector input_a = GetFloatDataInRange(-10.0f, 10.0f, 28 * 64); + std::vector input_b = GetFloatDataInRange(-10.0f, 10.0f, 64 * 32); + + RunQDQMatMulOpOpTest(TestInputDef({28, 1, 64}, false, input_a), + TestInputDef({64, 32}, true, input_b), + ExpectedEPNodeAssignment::All, + 18, + true); // Use com.microsoft Q/DQ ops +} + +#endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) + +} // namespace test +} // namespace onnxruntime + +#endif // !defined(ORT_MINIMAL_BUILD) diff --git a/onnxruntime/test/providers/qnn/max_min_op_test.cc b/onnxruntime/test/providers/qnn/max_min_op_test.cc new file mode 100644 index 0000000000000..3deff121f3c72 --- /dev/null +++ b/onnxruntime/test/providers/qnn/max_min_op_test.cc @@ -0,0 +1,134 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#if !defined(ORT_MINIMAL_BUILD) + +#include + +#include "test/providers/qnn/qnn_test_utils.h" + +#include "onnx/onnx_pb.h" +#include "gtest/gtest.h" + +namespace onnxruntime { +namespace test { + +// Runs an Max/Min model on the QNN CPU backend. Checks the graph node assignment, and that inference +// outputs for QNN EP and CPU EP match. +static void RunCPUMinOrMaxOpTest(const std::string& op_type, + const std::vector>& input_defs, + 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 + + RunQnnModelTest(BuildOpTestCase(op_type, input_defs, {}, {}, kOnnxDomain), + provider_options, + opset, + expected_ep_assignment); +} + +// Runs a QDQ Max/Min model on the QNN (HTP) EP and the ORT CPU EP. Checks the graph node assignment, and that inference +// running the QDQ model on QNN EP is at least as accurate as on ORT CPU EP (when compared to the baseline float32 model). +template +static void RunQDQMinOrMaxOpTest(const std::string& op_type, + const std::vector>& input_defs, + 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 + + TestQDQModelAccuracy(BuildOpTestCase(op_type, input_defs, {}, {}, kOnnxDomain), // baseline float32 model + BuildQDQOpTestCase(op_type, input_defs, {}, {}, kOnnxDomain), // QDQ model + provider_options, + opset, + expected_ep_assignment); +} + +// +// CPU tests: +// + +// Test that Min with 1 input is *NOT* supported on CPU backend. +TEST_F(QnnCPUBackendTests, Min_1Input_NotSupported) { + RunCPUMinOrMaxOpTest("Min", + {TestInputDef({1, 3, 4, 4}, false, -10.0f, 10.0f)}, + ExpectedEPNodeAssignment::None, 13); +} + +// Test that Max with 1 input is *NOT* supported on CPU backend. +TEST_F(QnnCPUBackendTests, Max_1Input_NotSupported) { + RunCPUMinOrMaxOpTest("Max", + {TestInputDef({1, 3, 4, 4}, false, -10.0f, 10.0f)}, + ExpectedEPNodeAssignment::None, 13); +} + +// Test Min with 2 inputs on CPU backend. +TEST_F(QnnCPUBackendTests, Min_2Inputs) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 48); + RunCPUMinOrMaxOpTest("Min", + {TestInputDef({1, 3, 4, 4}, false, input_data), + TestInputDef({1, 3, 4, 4}, false, input_data)}, + ExpectedEPNodeAssignment::All, 13); +} + +// Test Max with 2 inputs on CPU backend. +TEST_F(QnnCPUBackendTests, Max_2Inputs) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 48); + RunCPUMinOrMaxOpTest("Max", + {TestInputDef({1, 3, 4, 4}, false, input_data), + TestInputDef({1, 3, 4, 4}, false, input_data)}, + ExpectedEPNodeAssignment::All, 13); +} + +#if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) +// +// HTP tests: +// + +// Test that Min with 1 input is *NOT* supported on HTP backend. +TEST_F(QnnHTPBackendTests, Min_1Input_NotSupported) { + RunQDQMinOrMaxOpTest("Min", + {TestInputDef({1, 3, 4, 4}, false, -10.0f, 10.0f)}, + ExpectedEPNodeAssignment::None, 13); +} + +// Test that Max with 1 input is *NOT* supported on HTP backend. +TEST_F(QnnHTPBackendTests, Max_1Input_NotSupported) { + RunQDQMinOrMaxOpTest("Max", + {TestInputDef({1, 3, 4, 4}, false, -10.0f, 10.0f)}, + ExpectedEPNodeAssignment::None, 13); +} + +// Test accuracy of 8-bit Q/DQ Min with 2 inputs on HTP backend. +TEST_F(QnnHTPBackendTests, Min_2Inputs) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 48); + RunQDQMinOrMaxOpTest("Min", + {TestInputDef({1, 3, 4, 4}, false, input_data), + TestInputDef({1, 3, 4, 4}, false, input_data)}, + ExpectedEPNodeAssignment::All, 13); +} + +// Test accuracy of 8-bit Q/DQ Max with 2 inputs on HTP backend. +TEST_F(QnnHTPBackendTests, Max_2Inputs) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 48); + RunQDQMinOrMaxOpTest("Max", + {TestInputDef({1, 3, 4, 4}, false, input_data), + TestInputDef({1, 3, 4, 4}, false, input_data)}, + ExpectedEPNodeAssignment::All, 13); +} + +#endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) +} // namespace test +} // namespace onnxruntime +#endif // !defined(ORT_MINIMAL_BUILD) diff --git a/onnxruntime/test/providers/qnn/pad_op_test.cpp b/onnxruntime/test/providers/qnn/pad_op_test.cpp new file mode 100644 index 0000000000000..95961e423833a --- /dev/null +++ b/onnxruntime/test/providers/qnn/pad_op_test.cpp @@ -0,0 +1,346 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#if !defined(ORT_MINIMAL_BUILD) + +#include +#include + +#include "core/graph/node_attr_utils.h" +#include "test/optimizer/qdq_test_utils.h" +#include "test/providers/qnn/qnn_test_utils.h" + +#include "onnx/onnx_pb.h" + +#include "gtest/gtest.h" + +namespace onnxruntime { +namespace test { + +// Returns a function that creates a graph with a single Pad operator. +static GetTestModelFn BuildPadTestCase(const TestInputDef& data_def, + const TestInputDef& pads_def, + const TestInputDef& constant_value_def, + const std::vector& attrs, + bool has_constant_value = true) { + return [data_def, pads_def, constant_value_def, attrs, has_constant_value](ModelTestBuilder& builder) { + NodeArg* data = MakeTestInput(builder, data_def); + NodeArg* pads = MakeTestInput(builder, pads_def); + std::vector inputs{data, pads}; + if (has_constant_value) { + NodeArg* constant_value = MakeTestInput(builder, constant_value_def); + inputs.push_back(constant_value); + } + NodeArg* output = builder.MakeOutput(); + Node& pad_node = builder.AddNode("Pad", inputs, {output}); + + for (const auto& attr : attrs) { + pad_node.AddAttributeProto(attr); + } + }; +} + +// Returns a function that creates a graph with a QDQ Pad operator. +template +GetTestQDQModelFn BuildPadQDQTestCase(const TestInputDef& data_def, + const TestInputDef& pads_def, + const TestInputDef& constant_value_def, + const std::vector& attrs, + bool has_constant_value, + bool constant_value_quantized) { + return [data_def, pads_def, constant_value_def, attrs, has_constant_value, constant_value_quantized](ModelTestBuilder& builder, + std::vector>& output_qparams) { + std::vector inputs; + // data -> Q -> DQ -> + NodeArg* data = MakeTestInput(builder, data_def); + QuantParams data_qparams = GetTestInputQuantParams(data_def); + NodeArg* data_qdq = AddQDQNodePair(builder, data, data_qparams.scale, data_qparams.zero_point); + inputs.push_back(data_qdq); + + // pads + NodeArg* pads = MakeTestInput(builder, pads_def); + inputs.push_back(pads); + + // constant_value -- QNN support both quantized and non-quantized + if (has_constant_value) { + if (constant_value_quantized) { + // constant_value -> Q -> DQ -> + NodeArg* constant_value = MakeTestInput(builder, constant_value_def); + QuantParams constant_value_qparams = GetTestInputQuantParams(constant_value_def); + NodeArg* constant_value_qdq = AddQDQNodePair(builder, constant_value, + constant_value_qparams.scale, + constant_value_qparams.zero_point); + inputs.push_back(constant_value_qdq); + } else { + NodeArg* constant_value = MakeTestInput(builder, constant_value_def); + inputs.push_back(constant_value); + } + } + + NodeArg* output = builder.MakeIntermediate(); + Node& pad_node = builder.AddNode("Pad", inputs, {output}); + + for (const auto& attr : attrs) { + pad_node.AddAttributeProto(attr); + } + + // op_output -> Q -> DQ -> output + AddQDQNodePairWithOutputAsGraphOutput(builder, output, output_qparams[0].scale, + output_qparams[0].zero_point); + }; +} + +// Runs an Pad model on the QNN CPU backend. Checks the graph node assignment, and that inference +// outputs for QNN and CPU match. +static void RunPadOpTest(const TestInputDef& data_def, + const TestInputDef& pads_def, + const TestInputDef& constant_value_def, + const std::vector& attrs, + ExpectedEPNodeAssignment expected_ep_assignment, + bool has_constant_value = true, + int opset = 18) { + ProviderOptions provider_options; +#if defined(_WIN32) + provider_options["backend_path"] = "QnnCpu.dll"; +#else + provider_options["backend_path"] = "libQnnCpu.so"; +#endif + + RunQnnModelTest(BuildPadTestCase(data_def, pads_def, constant_value_def, attrs, has_constant_value), + provider_options, + opset, + expected_ep_assignment); +} + +// Runs a QDQ Pad model on the QNN HTP backend. Checks the graph node assignment, and that inference +// outputs for QNN and CPU match. +template +static void RunQDQPadOpTest(const TestInputDef& data_def, + const TestInputDef& pads_def, + const TestInputDef& constant_value_def, + const std::vector& attrs, + ExpectedEPNodeAssignment expected_ep_assignment, + bool has_constant_value = true, + 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 + + TestQDQModelAccuracy(BuildPadTestCase(data_def, pads_def, constant_value_def, attrs), + BuildPadQDQTestCase(data_def, pads_def, constant_value_def, attrs, + has_constant_value, constant_value_quantized), + provider_options, + opset, + expected_ep_assignment, + 1e-5f); +} + +// +// CPU tests: +// + +// Pad 2d +TEST_F(QnnCPUBackendTests, Pad2d) { + RunPadOpTest(TestInputDef({3, 2}, false, {1.0f, 1.2f, 2.3f, 3.4f, 4.5f, 5.6f}), + TestInputDef({4}, true, {0, 2, 0, 0}), + TestInputDef({1}, true, {0.0f}), + {utils::MakeAttribute("mode", "constant")}, + ExpectedEPNodeAssignment::All); +} + +// Pad 2d, pads input not initializer +TEST_F(QnnCPUBackendTests, Pad2dPadsNotIni) { + RunPadOpTest(TestInputDef({3, 2}, false, {1.0f, 1.2f, 2.3f, 3.4f, 4.5f, 5.6f}), + TestInputDef({4}, false, {0, 2, 0, 0}), + TestInputDef({1}, true, {0.0f}), + {utils::MakeAttribute("mode", "constant")}, + ExpectedEPNodeAssignment::None); +} + +// 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) { + 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, 2, 0, 0}), + TestInputDef({1}, true, {0.0f}), + {utils::MakeAttribute("mode", "reflect")}, + ExpectedEPNodeAssignment::All, + has_constant_value); +} + +// Pad edge mode +TEST_F(QnnCPUBackendTests, PadModeEdge) { + 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, 2, 0, 0}), + TestInputDef({1}, true, {0.0f}), + {utils::MakeAttribute("mode", "edge")}, + ExpectedEPNodeAssignment::All, + has_constant_value); +} + +// Pad wrap mode not supported +TEST_F(QnnCPUBackendTests, PadModeWrap) { + 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, 2, 0, 0}), + TestInputDef({1}, true, {0.0f}), + {utils::MakeAttribute("mode", "wrap")}, + ExpectedEPNodeAssignment::None, // not supported + has_constant_value); +} + +// Pad 4d +TEST_F(QnnCPUBackendTests, Pad4d) { + RunPadOpTest(TestInputDef({1, 2, 2, 2}, false, + {1.0f, 1.0f, + 1.0f, 1.0f, + 1.0f, 1.0f, + 1.0f, 1.0f}), + TestInputDef({8}, true, {0, 0, 0, 1, 0, 0, 0, 1}), + TestInputDef({1}, true, {0.0f}), + {utils::MakeAttribute("mode", "constant")}, + ExpectedEPNodeAssignment::All); +} + +// Pad 5d supported +TEST_F(QnnCPUBackendTests, Pad5d) { + RunPadOpTest(TestInputDef({1, 2, 2, 2, 2}, false, GetFloatDataInRange(1.0f, 10.0f, 16)), + TestInputDef({10}, true, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0}), + TestInputDef({1}, true, {5.0f}), + {utils::MakeAttribute("mode", "constant")}, + ExpectedEPNodeAssignment::All); +} + +// Pad 6d supported +TEST_F(QnnCPUBackendTests, Pad6d) { + RunPadOpTest(TestInputDef({1, 2, 2, 2, 2, 2}, false, GetFloatDataInRange(1.0f, 10.0f, 32)), + TestInputDef({12}, true, {0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0}), + TestInputDef({1}, true, {0.0f}), + {utils::MakeAttribute("mode", "constant")}, + ExpectedEPNodeAssignment::None); +} + +#if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) +// +// HTP tests: +// +// QDQ Pad +TEST_F(QnnHTPBackendTests, PadNoConstantValue) { + bool has_constant_value_input = false; + RunQDQPadOpTest(TestInputDef({3, 2}, false, {1.0f, 1.2f, 2.3f, 3.4f, 4.5f, 5.6f}), + TestInputDef({4}, true, {0, 2, 0, 0}), + TestInputDef({1}, true, {0.0f}), + {utils::MakeAttribute("mode", "constant")}, + ExpectedEPNodeAssignment::All, + has_constant_value_input); +} + +TEST_F(QnnHTPBackendTests, PadHasConstantValueNonQuantized) { + bool has_constant_value_input = true; + bool constant_value_quantized = false; + RunQDQPadOpTest(TestInputDef({3, 2}, false, {1.0f, 1.2f, 2.3f, 3.4f, 4.5f, 5.6f}), + TestInputDef({4}, true, {0, 2, 0, 0}), + TestInputDef({1}, true, {0.0f}), + {utils::MakeAttribute("mode", "constant")}, + ExpectedEPNodeAssignment::All, + has_constant_value_input, + constant_value_quantized); +} + +TEST_F(QnnHTPBackendTests, PadHasConstantValueQuantized) { + bool has_constant_value_input = true; + bool constant_value_quantized = true; + RunQDQPadOpTest(TestInputDef({3, 2}, false, {1.0f, 1.2f, 2.3f, 3.4f, 4.5f, 5.6f}), + TestInputDef({4}, true, {0, 2, 0, 0}), + TestInputDef({1}, true, {0.0f}), + {utils::MakeAttribute("mode", "constant")}, + ExpectedEPNodeAssignment::All, + has_constant_value_input, + constant_value_quantized); +} + +// QNN graph execute error. Error code: 6031 +TEST_F(QnnHTPBackendTests, DISABLED_PadReflectMode) { + bool has_constant_value_input = false; + RunQDQPadOpTest(TestInputDef({3, 2}, false, {1.0f, 1.2f, 2.3f, 3.4f, 4.5f, 5.6f}), + TestInputDef({4}, true, {0, 2, 0, 0}), + TestInputDef({1}, true, {0.0f}), + {utils::MakeAttribute("mode", "reflect")}, + ExpectedEPNodeAssignment::All, + has_constant_value_input); +} + +TEST_F(QnnHTPBackendTests, PadEdgeMode) { + bool has_constant_value_input = false; + RunQDQPadOpTest(TestInputDef({3, 2}, false, {1.0f, 1.2f, 2.3f, 3.4f, 4.5f, 5.6f}), + TestInputDef({4}, true, {0, 2, 0, 0}), + TestInputDef({1}, true, {0.0f}), + {utils::MakeAttribute("mode", "edge")}, + ExpectedEPNodeAssignment::All, + has_constant_value_input); +} + +// wrap mode not supported +TEST_F(QnnHTPBackendTests, PadWrapMode) { + bool has_constant_value_input = false; + RunQDQPadOpTest(TestInputDef({3, 2}, false, {1.0f, 1.2f, 2.3f, 3.4f, 4.5f, 5.6f}), + TestInputDef({4}, true, {0, 2, 0, 0}), + TestInputDef({1}, true, {0.0f}), + {utils::MakeAttribute("mode", "wrap")}, + ExpectedEPNodeAssignment::None, + has_constant_value_input); +} + +TEST_F(QnnHTPBackendTests, Pad4d) { + RunQDQPadOpTest(TestInputDef({1, 2, 2, 2}, false, + {1.0f, 2.0f, + 3.0f, 4.0f, + 5.0f, 6.0f, + 7.0f, 8.0f}), + TestInputDef({8}, true, {0, 0, 0, 1, 0, 0, 0, 1}), + TestInputDef({1}, true, {5.0f}), + {utils::MakeAttribute("mode", "constant")}, + ExpectedEPNodeAssignment::All); +} + +// Inaccuracy detected for output 'output', element 0. +// Output quant params: scale=0.035294119268655777, zero_point=0. +// Expected val: 9 +// QNN QDQ val: 8.0117654800415039 (err 0.98823451995849609) +// CPU QDQ val: 9 (err 0) +// QNN limitation? pad_constant_value has to be within the range of input[0]. +// Here pad_constant_value = 9.0 > max(input[0]) = 8.0 +TEST_F(QnnHTPBackendTests, DISABLED_Pad4dOutOfRangePadConstantValue) { + RunQDQPadOpTest(TestInputDef({1, 2, 2, 2}, false, + {1.0f, 2.0f, + 3.0f, 4.0f, + 5.0f, 6.0f, + 7.0f, 8.0f}), + TestInputDef({8}, true, {0, 0, 0, 1, 0, 0, 0, 1}), + TestInputDef({1}, true, {9.0f}), // pad_constant_value out of input[0] range + {utils::MakeAttribute("mode", "constant")}, + ExpectedEPNodeAssignment::All); +} + +// Pad 5d supported, but Quantize & Dequantize doesn't support 5d +TEST_F(QnnHTPBackendTests, DISABLED_Pad5d) { + RunQDQPadOpTest(TestInputDef({1, 2, 2, 2, 2}, false, GetFloatDataInRange(1.0f, 10.0f, 16)), + TestInputDef({10}, true, {0, 0, 0, 1, 0, 0, 0, 1, 0, 0}), + TestInputDef({1}, true, {2.0f}), + {utils::MakeAttribute("mode", "constant")}, + ExpectedEPNodeAssignment::All); +} + +#endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) + +} // namespace test +} // namespace onnxruntime + +#endif // !defined(ORT_MINIMAL_BUILD) \ No newline at end of file diff --git a/onnxruntime/test/providers/qnn/pool_op_test.cpp b/onnxruntime/test/providers/qnn/pool_op_test.cpp new file mode 100644 index 0000000000000..7ed9072a95b32 --- /dev/null +++ b/onnxruntime/test/providers/qnn/pool_op_test.cpp @@ -0,0 +1,269 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#if !defined(ORT_MINIMAL_BUILD) + +#include +#include + +#include "core/graph/node_attr_utils.h" +#include "test/optimizer/qdq_test_utils.h" +#include "test/providers/qnn/qnn_test_utils.h" + +#include "onnx/onnx_pb.h" + +#include "gtest/gtest.h" + +namespace onnxruntime { +namespace test { + +// Returns a function that creates a graph with a QDQ MaxPool operator. +template +GetTestQDQModelFn BuildPoolQDQTestCase(const std::string& op_type, + const TestInputDef& input_def, + const std::vector& attrs) { + return [op_type, input_def, attrs](ModelTestBuilder& builder, + std::vector>& output_qparams) { + // input -> Q -> DQ -> + NodeArg* input = MakeTestInput(builder, input_def); + QuantParams input_qparams = GetTestInputQuantParams(input_def); + NodeArg* input_qdq = AddQDQNodePair(builder, input, input_qparams.scale, input_qparams.zero_point); + + // MaxPool + NodeArg* pool_output = builder.MakeIntermediate(); + Node& pool_node = builder.AddNode(op_type, {input_qdq}, {pool_output}); + + for (const auto& attr : attrs) { + pool_node.AddAttributeProto(attr); + } + + // op_output -> Q -> DQ -> output + // NOTE: Input and output quantization parameters must be equal for MaxPool. + output_qparams[0] = input_qparams; // Overwrite! + AddQDQNodePairWithOutputAsGraphOutput(builder, pool_output, input_qparams.scale, + input_qparams.zero_point); + }; +} + +// Runs an MaxPool model on the QNN CPU backend. Checks the graph node assignment, and that inference +// outputs for QNN and CPU match. +static void RunPoolOpTest(const std::string& op_type, + const TestInputDef& input_def, + const std::vector& attrs, + 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 + + RunQnnModelTest(BuildOpTestCase(op_type, {input_def}, {}, attrs), + provider_options, + opset, + expected_ep_assignment); +} + +// Runs a QDQ MaxPool model on the QNN HTP backend. Checks the graph node assignment, and that inference +// outputs for QNN and CPU match. +template +static void RunQDQPoolOpTest(const std::string& op_type, + const TestInputDef& input_def, + const std::vector& attrs, + ExpectedEPNodeAssignment expected_ep_assignment, + int opset = 18) { + ProviderOptions provider_options; +#if defined(_WIN32) + provider_options["backend_path"] = "QnnHtp.dll"; +#else + provider_options["backend_path"] = "libQnnHtp.so"; +#endif + + TestQDQModelAccuracy(BuildOpTestCase(op_type, {input_def}, {}, attrs), + BuildPoolQDQTestCase(op_type, input_def, attrs), + provider_options, + opset, + expected_ep_assignment, + 1e-5f); +} + +// +// CPU tests: +// + +// MaxPool with kernel size equal to the spatial dimension of input tensor. +TEST_F(QnnCPUBackendTests, MaxPool_Global) { + RunPoolOpTest("MaxPool", + TestInputDef({1, 2, 3, 3}, false, -10.0f, 10.0f), // Dynamic input with range [-10, 10] + {utils::MakeAttribute("kernel_shape", std::vector{3, 3}), + utils::MakeAttribute("strides", std::vector{3, 3}), + utils::MakeAttribute("pads", std::vector{0, 0, 0, 0}), + utils::MakeAttribute("dilations", std::vector{1, 1}), + utils::MakeAttribute("ceil_mode", static_cast(0)), + utils::MakeAttribute("storage_order", static_cast(0)), + utils::MakeAttribute("auto_pad", "NOTSET")}, + ExpectedEPNodeAssignment::All); +} + +TEST_F(QnnCPUBackendTests, MaxPool_Large_Input) { + RunPoolOpTest("MaxPool", + TestInputDef({1, 125, 8, 56}, false, -10.0f, 10.0f), // Dynamic input with range [-10, 10] + {utils::MakeAttribute("kernel_shape", std::vector{2, 2}), + utils::MakeAttribute("strides", std::vector{2, 2}), + utils::MakeAttribute("pads", std::vector{0, 0, 0, 0}), + utils::MakeAttribute("dilations", std::vector{1, 1}), + utils::MakeAttribute("ceil_mode", static_cast(0)), + utils::MakeAttribute("storage_order", static_cast(0)), + utils::MakeAttribute("auto_pad", "NOTSET")}, + ExpectedEPNodeAssignment::All); +} + +// QNN v2.13, backendValidateOpConfig() failed for node `MaxPool` of type `PoolMax2d` with error code 4003 +TEST_F(QnnCPUBackendTests, DISABLED_MaxPool_Ceil) { + RunPoolOpTest("MaxPool", + TestInputDef({1, 2, 3, 3}, false, -10.0f, 10.0f), // Dynamic input with range [-10, 10] + {utils::MakeAttribute("kernel_shape", std::vector{3, 3}), + utils::MakeAttribute("strides", std::vector{3, 3}), + utils::MakeAttribute("pads", std::vector{0, 0, 0, 0}), + utils::MakeAttribute("dilations", std::vector{1, 1}), + utils::MakeAttribute("ceil_mode", static_cast(1)), + utils::MakeAttribute("storage_order", static_cast(0)), + utils::MakeAttribute("auto_pad", "NOTSET")}, + ExpectedEPNodeAssignment::All); +} + +// QNN v2.13, backendValidateOpConfig() failed for node `MaxPool` of type `PoolMax2d` with error code 4003 +TEST_F(QnnCPUBackendTests, DISABLED_MaxPool_Large_Input2_Ceil) { + RunPoolOpTest("MaxPool", + TestInputDef({1, 128, 16, 113}, false, -10.0f, 10.0f), // Dynamic input with range [-10, 10] + {utils::MakeAttribute("kernel_shape", std::vector{2, 2}), + utils::MakeAttribute("strides", std::vector{2, 2}), + utils::MakeAttribute("pads", std::vector{0, 0, 0, 0}), + utils::MakeAttribute("dilations", std::vector{1, 1}), + utils::MakeAttribute("ceil_mode", static_cast(1)), + utils::MakeAttribute("storage_order", static_cast(0)), + utils::MakeAttribute("auto_pad", "NOTSET")}, + ExpectedEPNodeAssignment::All); +} + +// GlobalMaxPool test +TEST_F(QnnCPUBackendTests, GlobalMaxPoolTest) { + RunPoolOpTest("GlobalMaxPool", + TestInputDef({1, 2, 3, 3}, false, -10.0f, 10.0f), // Dynamic input with range [-10, 10] + {}, + ExpectedEPNodeAssignment::All); +} + +#if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) +// +// HTP tests: +// +// QDQ MaxPool with kernel size equal to the spatial dimension of input tensor. +TEST_F(QnnHTPBackendTests, MaxPool_Global_HTP_u8) { + RunQDQPoolOpTest("MaxPool", + TestInputDef({1, 2, 3, 3}, false, -10.0f, 10.0f), // Dynamic input with range [-10, 10] + {utils::MakeAttribute("kernel_shape", std::vector{3, 3}), + utils::MakeAttribute("strides", std::vector{3, 3}), + utils::MakeAttribute("pads", std::vector{0, 0, 0, 0}), + utils::MakeAttribute("dilations", std::vector{1, 1}), + utils::MakeAttribute("ceil_mode", static_cast(0)), + utils::MakeAttribute("storage_order", static_cast(0)), + utils::MakeAttribute("auto_pad", "NOTSET")}, + ExpectedEPNodeAssignment::All); +} + +TEST_F(QnnHTPBackendTests, MaxPool_Large_Input_HTP_u8) { + RunQDQPoolOpTest("MaxPool", + TestInputDef({1, 125, 8, 56}, false, -10.0f, 10.0f), // Dynamic input with range [-10, 10] + {utils::MakeAttribute("kernel_shape", std::vector{2, 2}), + utils::MakeAttribute("strides", std::vector{2, 2}), + utils::MakeAttribute("pads", std::vector{0, 0, 0, 0}), + utils::MakeAttribute("dilations", std::vector{1, 1}), + utils::MakeAttribute("ceil_mode", static_cast(0)), + utils::MakeAttribute("storage_order", static_cast(0)), + utils::MakeAttribute("auto_pad", "NOTSET")}, + ExpectedEPNodeAssignment::All); +} + +TEST_F(QnnHTPBackendTests, MaxPool_Ceil_HTP_u8) { + RunQDQPoolOpTest("MaxPool", + TestInputDef({1, 2, 3, 3}, false, -10.0f, 10.0f), // Dynamic input with range [-10, 10] + {utils::MakeAttribute("kernel_shape", std::vector{3, 3}), + utils::MakeAttribute("strides", std::vector{3, 3}), + utils::MakeAttribute("pads", std::vector{0, 0, 0, 0}), + utils::MakeAttribute("dilations", std::vector{1, 1}), + utils::MakeAttribute("ceil_mode", static_cast(1)), + utils::MakeAttribute("storage_order", static_cast(0)), + utils::MakeAttribute("auto_pad", "NOTSET")}, + ExpectedEPNodeAssignment::All); +} + +// QNN v2.13: Inaccuracy detected for output 'output', element 58367. +// Output quant params: scale=0.078431375324726105, zero_point=127. +// Expected val: 5.6846914291381836 +// QNN QDQ val: -5.3333334922790527 (err 11.018024444580078) +// CPU QDQ val: 5.6470589637756348 (err 0.037632465362548828) +TEST_F(QnnHTPBackendTests, DISABLED_MaxPool_Large_Input2_Ceil_HTP_u8) { + RunQDQPoolOpTest("MaxPool", + TestInputDef({1, 128, 16, 113}, false, -10.0f, 10.0f), // Dynamic input with range [-10, 10] + {utils::MakeAttribute("kernel_shape", std::vector{2, 2}), + utils::MakeAttribute("strides", std::vector{2, 2}), + utils::MakeAttribute("pads", std::vector{0, 0, 0, 0}), + utils::MakeAttribute("dilations", std::vector{1, 1}), + utils::MakeAttribute("ceil_mode", static_cast(1)), + utils::MakeAttribute("storage_order", static_cast(0)), + utils::MakeAttribute("auto_pad", "NOTSET")}, + ExpectedEPNodeAssignment::All); +} + +// QNN v2.13: Certain large input sizes cause the QNN graph to fail to finalize with error 1002 (QNN_COMMON_ERROR_MEM_ALLOC). +// Fixed in QNN v2.14.1. +TEST_F(QnnHTPBackendTests, MaxPool_LargeInput_1Pads) { + RunQDQPoolOpTest("MaxPool", + TestInputDef({1, 64, 384, 576}, false, -10.0f, 10.0f), // Dynamic input with range [-10, 10] + {utils::MakeAttribute("kernel_shape", std::vector{3, 3}), + utils::MakeAttribute("strides", std::vector{2, 2}), + utils::MakeAttribute("pads", std::vector{1, 1, 1, 1}), + utils::MakeAttribute("dilations", std::vector{1, 1}), + utils::MakeAttribute("ceil_mode", static_cast(0)), + utils::MakeAttribute("storage_order", static_cast(0)), + utils::MakeAttribute("auto_pad", "NOTSET")}, + ExpectedEPNodeAssignment::All); +} + +// QDQ GlobalMaxPool test +TEST_F(QnnHTPBackendTests, GlobalMaxPool_u8) { + RunQDQPoolOpTest("GlobalMaxPool", + TestInputDef({1, 2, 3, 3}, false, -10.0f, 10.0f), // Dynamic input with range [-10, 10] + {}, + ExpectedEPNodeAssignment::All); +} + +TEST_F(QnnHTPBackendTests, GlobalMaxPool_Large_Input_u8) { + RunQDQPoolOpTest("GlobalMaxPool", + TestInputDef({1, 128, 16, 113}, false, -10.0f, 10.0f), // Dynamic input with range [-10, 10] + {}, + ExpectedEPNodeAssignment::All); +} + +// initial_sequencer_dp.cc:156:ERROR:A single op, "q::MaxPool_valid.tcm" (Op ID: 277700000016), requires 0x6c0800 bytes of TCM, which is greater than the TCM size of 0x400000! +// QnnDsp graph prepare failed 13 +// QnnDsp Failed to finalize graph QNN_983391626356502531_0 with err: 1002 +// QnnDsp Failed to finalize graph (id: 1) with err 1002 +// QnnDsp Wake up free backend 1 thread(s) +// QnnDsp QnnGraph_finalize done. status 0x3ea +// Failed to finalize QNN graph. +TEST_F(QnnHTPBackendTests, DISABLED_GlobalMaxPool_LargeInput2_u8) { + RunQDQPoolOpTest("GlobalMaxPool", + TestInputDef({1, 64, 384, 576}, false, -10.0f, 10.0f), // Dynamic input with range [-10, 10] + {}, + ExpectedEPNodeAssignment::All); +} + +#endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) + +} // namespace test +} // namespace onnxruntime + +#endif // !defined(ORT_MINIMAL_BUILD) \ No newline at end of file diff --git a/onnxruntime/test/providers/qnn/qnn_basic_test.cc b/onnxruntime/test/providers/qnn/qnn_basic_test.cc index b8fd8efce4585..a441e828c0cc6 100644 --- a/onnxruntime/test/providers/qnn/qnn_basic_test.cc +++ b/onnxruntime/test/providers/qnn/qnn_basic_test.cc @@ -5,6 +5,7 @@ #include "core/session/onnxruntime_cxx_api.h" #include "core/session/onnxruntime_session_options_config_keys.h" +#include "core/providers/cpu/cpu_provider_factory.h" // For OrtSessionOptionsAppendExecutionProvider_CPU #include "core/session/inference_session.h" #include "test/providers/qnn/qnn_test_utils.h" @@ -31,8 +32,15 @@ namespace test { // Loads a simple ONNX model that adds floats. TEST(QnnEP, TestAddEpUsingPublicApi) { { - // C++ API test Ort::SessionOptions so; + + // Can only enforce that model runs on QNN in linux CI machines + // because they support the CPU backend and emulate the HPT backend. + // TODO: Remove #ifdef when Windows Arm64 machines support the CPU backend. +#if defined(__linux__) + so.AddConfigEntry(kOrtSessionOptionsDisableCPUEPFallback, "1"); // Disable fallback to the CPU EP. +#endif + onnxruntime::ProviderOptions options; #if defined(_WIN32) @@ -63,6 +71,100 @@ TEST(QnnEP, TestAddEpUsingPublicApi) { } } +// Tests the `session.disable_cpu_ep_fallback` configuration option when the backend cannot be loaded. +// When the option is enabled, session creation throws an exception because the backend cannot be found. +TEST(QnnEP, TestDisableCPUFallback_BackendNotFound) { + { + Ort::SessionOptions so; + so.AddConfigEntry(kOrtSessionOptionsDisableCPUEPFallback, "1"); // Disable fallback to the CPU EP. + + onnxruntime::ProviderOptions options; +#if defined(_WIN32) + options["backend_path"] = "DoesNotExist.dll"; // Invalid backend path! +#else + options["backend_path"] = "libDoesNotExist.so"; // Invalid backend path! +#endif + + so.AppendExecutionProvider("QNN", options); + + const ORTCHAR_T* ort_model_path = ORT_MODEL_FOLDER "constant_floats.onnx"; + + try { + Ort::Session session(*ort_env, ort_model_path, so); + FAIL(); // Should not get here! + } catch (const Ort::Exception& excpt) { + ASSERT_EQ(excpt.GetOrtErrorCode(), ORT_FAIL); + ASSERT_THAT(excpt.what(), testing::HasSubstr("This session contains graph nodes that are assigned to the default " + "CPU EP, but fallback to CPU EP has been explicitly disabled by " + "the user.")); + } + } +} + +// Tests the `session.disable_cpu_ep_fallback` configuration option when the entire model cannot be assigned to QNN EP. +// When the option is enabled, Session creation should throw an exception. +TEST(QnnEP, TestDisableCPUFallback_ModelNotFullySupported) { + { + Ort::SessionOptions so; + so.AddConfigEntry(kOrtSessionOptionsDisableCPUEPFallback, "1"); // Disable fallback to the CPU EP. + + onnxruntime::ProviderOptions options; +#if defined(_WIN32) + options["backend_path"] = "QnnCpu.dll"; +#else + options["backend_path"] = "libQnnCpu.so"; +#endif + + so.AppendExecutionProvider("QNN", options); + + // QNN EP doesn't support MatMulInteger. + const ORTCHAR_T* ort_model_path = ORT_MODEL_FOLDER "qnn_ep_partial_support.onnx"; + + try { + Ort::Session session(*ort_env, ort_model_path, so); + FAIL(); // Should not get here! + } catch (const Ort::Exception& excpt) { + ASSERT_EQ(excpt.GetOrtErrorCode(), ORT_FAIL); + ASSERT_THAT(excpt.what(), testing::HasSubstr("This session contains graph nodes that are assigned to the default " + "CPU EP, but fallback to CPU EP has been explicitly disabled by " + "the user.")); + } + } +} + +// Tests invalid use of the `session.disable_cpu_ep_fallback` configuration option. +// It is invalid to set the option and explicitly add the CPU EP to the session. +TEST(QnnEP, TestDisableCPUFallback_ConflictingConfig) { + { + Ort::SessionOptions so; + so.AddConfigEntry(kOrtSessionOptionsDisableCPUEPFallback, "1"); // Disable fallback to the CPU EP. + + onnxruntime::ProviderOptions options; +#if defined(_WIN32) + options["backend_path"] = "QnnCpu.dll"; +#else + options["backend_path"] = "libQnnCpu.so"; +#endif + + so.AppendExecutionProvider("QNN", options); + + // Invalid! Adds CPU EP to session, but also disables CPU fallback. + Ort::Status status(OrtSessionOptionsAppendExecutionProvider_CPU(so, 1)); + + const ORTCHAR_T* ort_model_path = ORT_MODEL_FOLDER "constant_floats.onnx"; + + try { + Ort::Session session(*ort_env, ort_model_path, so); + FAIL(); // Should not get here! + } catch (const Ort::Exception& excpt) { + ASSERT_EQ(excpt.GetOrtErrorCode(), ORT_INVALID_ARGUMENT); + ASSERT_THAT(excpt.what(), testing::HasSubstr("Conflicting session configuration: explicitly added the CPU EP to the " + "session, but also disabled fallback to the CPU EP via session " + "configuration options.")); + } + } +} + // Helper function that runs an ONNX model with a NHWC Resize operator to test that // type/shape inference succeeds during layout transformation. // Refer to onnxruntime/core/graph/contrib_ops/nhwc_inference_context.h. @@ -158,8 +260,8 @@ TEST_F(QnnCPUBackendTests, TestNHWCResizeShapeInference_sizes_opset18) { TEST_F(QnnHTPBackendTests, TestNHWCResizeShapeInference_qdq_sizes_opset18) { RunNHWCResizeModel(ORT_MODEL_FOLDER "nhwc_resize_sizes_opset18.quant.onnx", true); } -#endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) +#endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) #endif // !defined(ORT_MINIMAL_BUILD) } // namespace test diff --git a/onnxruntime/test/providers/qnn/qnn_test_utils.cc b/onnxruntime/test/providers/qnn/qnn_test_utils.cc index e6d50c87fbac6..51df93f8853ec 100644 --- a/onnxruntime/test/providers/qnn/qnn_test_utils.cc +++ b/onnxruntime/test/providers/qnn/qnn_test_utils.cc @@ -4,33 +4,58 @@ #if !defined(ORT_MINIMAL_BUILD) #include "test/providers/qnn/qnn_test_utils.h" +#include #include "test/util/include/asserts.h" #include "test/util/include/default_providers.h" #include "test/util/include/test/test_environment.h" -#include "core/graph/graph.h" +#include "core/common/span_utils.h" #include "core/framework/compute_capability.h" +#include "core/graph/graph.h" namespace onnxruntime { namespace test { -void RunQnnModelTest(const GetTestModelFn& build_test_case, const ProviderOptions& provider_options, - int opset_version, ExpectedEPNodeAssignment expected_ep_assignment, int num_nodes_in_ep, - const char* test_description, float fp32_abs_err) { - std::function graph_verify = [num_nodes_in_ep, test_description](const Graph& graph) -> void { - ASSERT_EQ(graph.NumberOfNodes(), num_nodes_in_ep) << test_description; - }; +std::vector GetFloatDataInRange(float min_val, float max_val, size_t num_elems) { + if (num_elems == 0) { + return {}; + } + + if (num_elems == 1) { + return {min_val}; + } + + std::vector data; + data.reserve(num_elems); + const float step_size = (max_val - min_val) / static_cast(num_elems - 1); + float val = min_val; + for (size_t i = 0; i < num_elems; i++) { + data.push_back(val); + val += step_size; + } + + // Ensure that max_val is included exactly (due to rounding from adding step sizes). + data[num_elems - 1] = max_val; + + return data; +} + +void RunQnnModelTest(const GetTestModelFn& build_test_case, const ProviderOptions& provider_options, + int opset_version, ExpectedEPNodeAssignment expected_ep_assignment, + float fp32_abs_err, logging::Severity log_severity) { EPVerificationParams verification_params; verification_params.ep_node_assignment = expected_ep_assignment; - verification_params.graph_verifier = &graph_verify; verification_params.fp32_abs_err = fp32_abs_err; // Add kMSDomain to cover contrib op like Gelu const std::unordered_map domain_to_version = {{"", opset_version}, {kMSDomain, 1}}; - onnxruntime::Model model(test_description, false, ModelMetaData(), PathString(), + auto& logging_manager = DefaultLoggingManager(); + logging_manager.SetDefaultLoggerSeverity(log_severity); + + onnxruntime::Model model("QNN_EP_TestModel", false, ModelMetaData(), PathString(), IOnnxRuntimeOpSchemaRegistryList(), domain_to_version, {}, - DefaultLoggingManager().DefaultLogger()); + logging_manager.DefaultLogger()); Graph& graph = model.MainGraph(); ModelTestBuilder helper(graph); build_test_case(helper); @@ -40,11 +65,89 @@ void RunQnnModelTest(const GetTestModelFn& build_test_case, const ProviderOption // Serialize the model to a string. std::string model_data; model.ToProto().SerializeToString(&model_data); - RunAndVerifyOutputsWithEP(model_data, "QnnEP.TestQDQModel", + RunAndVerifyOutputsWithEP(AsByteSpan(model_data.data(), model_data.size()), "QNN_EP_TestLogID", QnnExecutionProviderWithOptions(provider_options), helper.feeds_, verification_params); } +void InferenceModel(const std::string& model_data, const char* log_id, + std::unique_ptr execution_provider, + ExpectedEPNodeAssignment expected_ep_assignment, const NameMLValMap& feeds, + std::vector& output_vals) { + SessionOptions so; + so.session_logid = log_id; + RunOptions run_options; + run_options.run_tag = so.session_logid; + + InferenceSessionWrapper session_object{so, GetEnvironment()}; + + std::string provider_type = kCpuExecutionProvider; + if (execution_provider) { + provider_type = execution_provider->Type(); + ASSERT_STATUS_OK(session_object.RegisterExecutionProvider(std::move(execution_provider))); + } + ASSERT_STATUS_OK(session_object.Load(model_data.data(), static_cast(model_data.size()))); + ASSERT_STATUS_OK(session_object.Initialize()); + + const auto& graph = session_object.GetGraph(); + + auto ep_nodes = CountAssignedNodes(graph, provider_type); + if (expected_ep_assignment == ExpectedEPNodeAssignment::All) { + // Verify the entire graph is assigned to the EP + ASSERT_EQ(ep_nodes, graph.NumberOfNodes()) << "Not all nodes were assigned to " << provider_type; + } else if (expected_ep_assignment == ExpectedEPNodeAssignment::None) { + ASSERT_EQ(ep_nodes, 0) << "No nodes are supposed to be assigned to " << provider_type; + } else { + ASSERT_GT(ep_nodes, 0) << "No nodes were assigned to " << provider_type; + } + + const auto& outputs = graph.GetOutputs(); + std::vector output_names; + + output_names.reserve(outputs.size()); + for (const auto* node_arg : outputs) { + if (node_arg->Exists()) { + output_names.push_back(node_arg->Name()); + } + } + + ASSERT_STATUS_OK(session_object.Run(run_options, feeds, output_names, &output_vals)); +} + +NodeArg* MakeTestQDQBiasInput(ModelTestBuilder& builder, const TestInputDef& bias_def, float bias_scale, + bool use_contrib_qdq) { + NodeArg* bias_int32 = nullptr; + + // Bias must be int32 to be detected as a QDQ node unit. + // We must quantize the data. + if (bias_def.IsRandomData()) { + // Create random initializer def that is quantized to int32 + const auto& rand_info = bias_def.GetRandomDataInfo(); + TestInputDef bias_int32_def(bias_def.GetShape(), bias_def.IsInitializer(), + static_cast(rand_info.min / bias_scale), + static_cast(rand_info.max / bias_scale)); + bias_int32 = MakeTestInput(builder, bias_int32_def); + } else { + assert(bias_def.IsRawData()); + // Create raw data initializer def that is quantized to int32 + const auto& bias_f32_raw = bias_def.GetRawData(); + const size_t num_elems = bias_f32_raw.size(); + + std::vector bias_int32_raw(num_elems); + for (size_t i = 0; i < num_elems; i++) { + bias_int32_raw[i] = static_cast(bias_f32_raw[i] / bias_scale); + } + + TestInputDef bias_int32_def(bias_def.GetShape(), bias_def.IsInitializer(), bias_int32_raw); + bias_int32 = MakeTestInput(builder, bias_int32_def); + } + + auto* bias = builder.MakeIntermediate(); + builder.AddDequantizeLinearNode(bias_int32, bias_scale, 0, bias, use_contrib_qdq); + + return bias; +} + // Mock IKernelLookup class passed to QNN EP's GetCapability() function in order to // determine if the HTP backend is supported on specific platforms (e.g., Windows ARM64). // TODO: Remove once HTP can be emulated on Windows ARM64. @@ -65,7 +168,34 @@ static BackendSupport GetHTPSupport(const onnxruntime::logging::Logger& logger) ModelTestBuilder helper(graph); // Build simple QDQ graph: DQ -> InstanceNormalization -> Q - GetQDQTestCaseFn build_test_case = BuildQDQInstanceNormTestCase({1, 2, 3, 3}, 1e-05f); + GetQDQTestCaseFn build_test_case = [](ModelTestBuilder& builder) { + const uint8_t quant_zero_point = 0; + const float quant_scale = 1.0f; + + auto* dq_scale_output = builder.MakeIntermediate(); + auto* scale = builder.MakeInitializer({2}, std::vector{1, 2}); + builder.AddDequantizeLinearNode(scale, quant_scale, quant_zero_point, dq_scale_output); + + // Add bias (initializer) -> DQ -> + auto* dq_bias_output = builder.MakeIntermediate(); + auto* bias = builder.MakeInitializer({2}, std::vector{1, 1}); + builder.AddDequantizeLinearNode(bias, 1.0f, 0, dq_bias_output); + + // Add input_u8 -> DQ -> + auto* input_u8 = builder.MakeInput({1, 2, 3}, std::vector{1, 2, 3, 4, 5, 6}); + auto* dq_input_output = builder.MakeIntermediate(); + builder.AddDequantizeLinearNode(input_u8, quant_scale, quant_zero_point, dq_input_output); + + // Add dq_input_output -> InstanceNormalization -> + auto* instance_norm_output = builder.MakeIntermediate(); + builder.AddNode("InstanceNormalization", {dq_input_output, dq_scale_output, dq_bias_output}, + {instance_norm_output}); + + // Add instance_norm_output -> Q -> output_u8 + auto* output_u8 = builder.MakeOutput(); + builder.AddQuantizeLinearNode(instance_norm_output, quant_scale, quant_zero_point, output_u8); + }; + build_test_case(helper); helper.SetGraphOutputs(); auto status = model.MainGraph().Resolve(); @@ -198,4 +328,4 @@ bool ReduceOpHasAxesInput(const std::string& op_type, int opset_version) { } // 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_test_utils.h b/onnxruntime/test/providers/qnn/qnn_test_utils.h index 91d74b2c12cf0..14c62f98f6a3e 100644 --- a/onnxruntime/test/providers/qnn/qnn_test_utils.h +++ b/onnxruntime/test/providers/qnn/qnn_test_utils.h @@ -5,19 +5,528 @@ #if !defined(ORT_MINIMAL_BUILD) #include +#include #include #include "core/framework/provider_options.h" +#include "core/util/qmath.h" #include "test/optimizer/qdq_test_utils.h" #include "test/util/include/test_utils.h" +#include "test/util/include/test/test_environment.h" +#include "test/util/include/default_providers.h" #include "gtest/gtest.h" namespace onnxruntime { namespace test { +// Signature for function that builds a float32 model. using GetTestModelFn = std::function; +// Class that stores quantization params (scale, zero point). +// Has a static function that computes quantization parameters from a floating-point range. +template +struct QuantParams { + float scale; + QType zero_point; + + static QuantParams Compute(float rmin, float rmax) { + // Ensure a minimum range of 0.0001 (required by QNN) + rmax = std::max(rmax, rmin + 0.0001f); + + // Both QNN and ORT require the range to include 0.0f + rmin = std::min(rmin, 0.0f); + rmax = std::max(rmax, 0.0f); + + constexpr float qmin = static_cast(std::numeric_limits::min()); + constexpr float qmax = static_cast(std::numeric_limits::max()); + + const float scale = rmax == rmin ? 1.0f : (rmax - rmin) / (qmax - qmin); + const float initial_zero_point = qmin - (rmin / scale); + const QType zero_point = static_cast(RoundHalfToEven(std::max(qmin, std::min(qmax, initial_zero_point)))); + + return QuantParams{scale, zero_point}; + } +}; + +// Signature for function that builds a QDQ model. +// The parameter `output_qparams` contains quantization parameters that *can* be used for the QDQ model output. +// These output quantization parameters are computed by first running the float32 model and determining the +// range of output values. Note that the function is able to overwrite the output_qparams parameter if necessary +// (Example: MaxPool must have identical input and output quantization params). +template +using GetTestQDQModelFn = std::function>& output_qparams)>; + +// Computes quantization parameters for an array of floating-point values. +template +inline QuantParams GetDataQuantParams(gsl::span data) { + // Get min/max of raw data. + float min_val = std::numeric_limits::max(); + float max_val = std::numeric_limits::min(); + + for (auto val : data) { + min_val = std::min(min_val, val); + max_val = std::max(max_val, val); + } + + return QuantParams::Compute(min_val, max_val); +} + +/** + * Returns a float vector with data in the specified range. Uses linear interpolation to fill the elements in the array + * and ensures that min_val, 0.0f, and max_val are all included. + * TODO(adrianlizarraga): Should use this instead of random *float* test inputs for test repeatability/stability! + * + * \param min_val The minimum value. + * \param max_val The maximum value. + * \param num_elems The number of elements in the result. Should be at least 3 to include min, 0, and max. + * \return A vector of floats with elements set to values in the specified range. + */ +std::vector GetFloatDataInRange(float min_val, float max_val, size_t num_elems); + +// Class that defines an input that can be created with ModelTestBuilder. +// Defines whether the input is an initializer and if the data should be randomized or if +// set to an explicit value. +template +struct TestInputDef { + struct RawData { + std::vector data; + }; + + struct RandomData { + T min; + T max; + }; + + TestInputDef() = default; + + // Creates a random input definition. Specify its shape, whether it's an initializer, and + // the min/max range. + TestInputDef(std::vector shape, bool is_initializer, T rand_min, T rand_max) + : shape_(std::move(shape)), + data_info_(RandomData{rand_min, rand_max}), + is_initializer_(is_initializer), + has_range_override_(false), + range_override_() {} + + // Create an input definition with explicit data. Specify its shape, whether it's an initializer, + // and the raw data. + TestInputDef(std::vector shape, bool is_initializer, std::vector data) + : shape_(std::move(shape)), + data_info_(RawData{std::move(data)}), + is_initializer_(is_initializer), + has_range_override_(false), + range_override_() {} + + TestInputDef(TestInputDef&& other) = default; + TestInputDef(const TestInputDef& other) = default; + + TestInputDef& operator=(const TestInputDef& other) = default; + TestInputDef& operator=(TestInputDef&& other) = default; + + // Overrides the range of input values reported by TestInputDef::GetRange(). + // This is useful when you want to quantize over a range that is larger or smaller + // than the actual range of the data. + // + // Returns a reference to this object to allow chaining. + TestInputDef& OverrideValueRange(T range_min, T range_max) { + range_override_.first = range_min; + range_override_.second = range_max; + has_range_override_ = true; + return *this; + } + + const std::vector& GetShape() const { + return shape_; + } + + bool IsInitializer() const { + return is_initializer_; + } + + bool IsRandomData() const { + return data_info_.index() == 1; + } + + const RandomData& GetRandomDataInfo() const { + return std::get(data_info_); + } + + bool IsRawData() const { + return data_info_.index() == 0; + } + + const std::vector& GetRawData() const { + return std::get(data_info_).data; + } + + // Get the range of values represented by this input, which is necessary for computing quantization parameters. + // For raw data, we return [min, max] of the elements. + // For random data, we return [rand_min, rand_max]. + // Optionally, the user can override this range by using OverrideValueRange(). + std::pair GetRange() const { + if (has_range_override_) { + return range_override_; + } + + auto which_type = data_info_.index(); + std::pair range; + + if (which_type == 0) { + // Get min/max of raw data. + range.first = std::numeric_limits::max(); + range.second = std::numeric_limits::min(); + + for (auto val : std::get(data_info_).data) { + range.first = std::min(range.first, val); + range.second = std::max(range.second, val); + } + } else { + assert(which_type == 1); + RandomData rand_info = std::get(data_info_); + range.first = rand_info.min; + range.second = rand_info.max; + } + + return range; + } + + private: + std::vector shape_; + std::variant data_info_; + bool is_initializer_{false}; + bool has_range_override_{false}; + std::pair range_override_; +}; + +template +inline QuantParams GetTestInputQuantParams(const TestInputDef& input_def) { + const std::pair frange = input_def.GetRange(); + return QuantParams::Compute(frange.first, frange.second); +} + +/** + * Inferences a given serialized model. Returns output values via an out-param. + * + * \param model_data The serialized ONNX model to inference. + * \param log_id The logger ID. + * \param execution_provider The EP on which to run the model. Set to nullptr for CPU EP. + * \param expected_ep_assignment Describes "which nodes" should be assigned to the EP. + * \param feeds The input feeds. + * \param output_vals Initialized to the inference results. + */ +void InferenceModel(const std::string& model_data, const char* log_id, + std::unique_ptr execution_provider, + ExpectedEPNodeAssignment expected_ep_assignment, const NameMLValMap& feeds, + std::vector& output_vals); + +/** + * Tests the accuracy of a QDQ model on QNN EP by runnning 3 inferences: + * + * 1. float model on CPU EP (baseline) + * 2. QDQ model on CPU EP + * 3. QDQ model on QNN EP + * + * This function checks that running the QDQ model on QNN EP (#3) is at least as accurate (+- small tolerance) + * as running the QDQ model on CPU EP (#2). We primarily measure accuracy by comparing to the baseline (#1). + * + * \param f32_model_fn Function that builds the float model (baseline for comparison). + * \param qdq_model_fn Function that builds the QDQ model (run by CPU EP and QNN EP). + * \param qnn_options QNN EP provider options. + * \param opset_version The opset version. + * \param expected_ep_assignment Describes "which nodes" should be assigned to the EP. + * \param fp32_abs_err Small tolerance used for floating-point comparisons. + * \param log_severity The logger's severity setting. + */ +template +inline void TestQDQModelAccuracy(const GetTestModelFn& f32_model_fn, const GetTestQDQModelFn& qdq_model_fn, + const ProviderOptions& qnn_options, int opset_version, + ExpectedEPNodeAssignment expected_ep_assignment, float fp32_abs_err = 1e-4f, + logging::Severity log_severity = logging::Severity::kERROR) { + // Add kMSDomain to cover contrib op like Gelu + const std::unordered_map domain_to_version = {{"", opset_version}, {kMSDomain, 1}}; + + auto& logging_manager = DefaultLoggingManager(); + logging_manager.SetDefaultLoggerSeverity(log_severity); + + // Create float model and serialize it to a string. + onnxruntime::Model f32_model("f32_model", false, ModelMetaData(), PathString(), + IOnnxRuntimeOpSchemaRegistryList(), domain_to_version, {}, + logging_manager.DefaultLogger()); + ModelTestBuilder f32_helper(f32_model.MainGraph()); + std::string f32_model_data; + f32_model_fn(f32_helper); + f32_helper.SetGraphOutputs(); + ASSERT_STATUS_OK(f32_model.MainGraph().Resolve()); + f32_model.ToProto().SerializeToString(&f32_model_data); + + // Run f32 model on CPU EP and collect outputs. + std::vector cpu_f32_outputs; + InferenceModel(f32_model_data, "f32_model_logger", nullptr, ExpectedEPNodeAssignment::All, + f32_helper.feeds_, cpu_f32_outputs); + ASSERT_FALSE(cpu_f32_outputs.empty()); + + const size_t num_outputs = cpu_f32_outputs.size(); + + // Compute output range(s) and quantization params. + std::vector> output_qparams; + std::vector> output_vals; + std::vector output_types; + output_qparams.resize(num_outputs); + output_vals.resize(num_outputs); + output_types.resize(num_outputs); + + for (size_t i = 0; i < num_outputs; i++) { + auto& tensor = cpu_f32_outputs[i].Get(); + int32_t elem_type = tensor.GetElementType(); + + if (elem_type == ONNX_NAMESPACE::TensorProto_DataType_FLOAT) { + output_vals[i] = tensor.DataAsSpan(); + output_qparams[i] = GetDataQuantParams(output_vals[i]); + } + + output_types[i] = elem_type; + } + + // Create QDQ model and serialize it to a string. + onnxruntime::Model qdq_model("qdq_model", false, ModelMetaData(), PathString(), + IOnnxRuntimeOpSchemaRegistryList(), domain_to_version, {}, + logging_manager.DefaultLogger()); + ModelTestBuilder qdq_helper(qdq_model.MainGraph()); + std::string qdq_model_data; + qdq_model_fn(qdq_helper, output_qparams); + qdq_helper.SetGraphOutputs(); + ASSERT_STATUS_OK(qdq_model.MainGraph().Resolve()); + qdq_model.ToProto().SerializeToString(&qdq_model_data); + + // Run QDQ model on QNN EP and collect outputs. + std::vector qnn_qdq_outputs; + InferenceModel(qdq_model_data, "qdq_model_logger", QnnExecutionProviderWithOptions(qnn_options), + expected_ep_assignment, qdq_helper.feeds_, qnn_qdq_outputs); + + if (expected_ep_assignment != ExpectedEPNodeAssignment::None) { + // Run QDQ model on CPU EP and collect outputs. + std::vector cpu_qdq_outputs; + InferenceModel(qdq_model_data, "qdq_model_logger", nullptr, ExpectedEPNodeAssignment::All, + qdq_helper.feeds_, cpu_qdq_outputs); + ASSERT_EQ(cpu_qdq_outputs.size(), num_outputs); + ASSERT_EQ(qnn_qdq_outputs.size(), num_outputs); + + // limit the error message count in case test with large data failed + size_t max_error_count = 10; + size_t error_count = 0; + + // Compare accuracy of QDQ results with float model. + // QNN EP must be at least as accurate as CPU EP when running the QDQ model. + const std::string base_output_name = "output_"; + for (size_t i = 0; i < num_outputs; i++) { + std::string debug_output_name = base_output_name + std::to_string(i); + auto& cpu_qdq_tensor = cpu_qdq_outputs[i].Get(); + auto& qnn_qdq_tensor = qnn_qdq_outputs[i].Get(); + + ASSERT_EQ(cpu_qdq_tensor.GetElementType(), output_types[i]); + ASSERT_EQ(qnn_qdq_tensor.GetElementType(), output_types[i]); + + if (output_types[i] == ONNX_NAMESPACE::TensorProto_DataType_FLOAT) { + const size_t num_vals = output_vals[i].size(); + gsl::span cpu_f32_vals = output_vals[i]; + gsl::span cpu_qdq_vals = cpu_qdq_tensor.DataAsSpan(); + gsl::span qnn_qdq_vals = qnn_qdq_tensor.DataAsSpan(); + + ASSERT_EQ(num_vals, cpu_qdq_vals.size()); + ASSERT_EQ(num_vals, qnn_qdq_vals.size()); + + for (size_t j = 0; j < num_vals && error_count < max_error_count; j++) { + const float expected_val = cpu_f32_vals[j]; // "ground-truth" + const float qnn_qdq_val = qnn_qdq_vals[j]; + const float cpu_qdq_val = cpu_qdq_vals[j]; + const float cpu_err = std::fabs(expected_val - cpu_qdq_val); + const float qnn_err = std::fabs(expected_val - qnn_qdq_val); + + // Case 1 (qnn_err <= cpu_err): QNN EP is *more* accurate, which makes (qnn_err - cpu_err) zero or + // a negative value. + // Case 2 (qnn_err > cpu_err): QNN EP is less accurate, but the error difference is within 1 + // quantization unit (i.e., scale). This can occur due to rounding differences. + const bool is_as_accurate_as_cpu_qdq = (qnn_err - cpu_err) <= (output_qparams[i].scale + fp32_abs_err); + if (!is_as_accurate_as_cpu_qdq) { + ++error_count; + } + + EXPECT_TRUE(is_as_accurate_as_cpu_qdq) + << "Inaccuracy detected for output '" << debug_output_name + << "', element " << j + << ".\nOutput quant params: scale=" << output_qparams[i].scale + << ", zero_point=" << static_cast(output_qparams[i].zero_point) + << ".\nExpected val: " << expected_val << "\n" + << "QNN QDQ val: " << qnn_qdq_val << " (err " << qnn_err << ")\n" + << "CPU QDQ val: " << cpu_qdq_val << " (err " << cpu_err << ")"; + } + } else { + VerifyOutput(debug_output_name, cpu_f32_outputs[i].Get(), qnn_qdq_tensor, fp32_abs_err); + } + } + } +} + +/** + * Creates and returns an input in a test model graph. The input's characteristics are defined + * by the provided input definition. + * + * \param builder Model builder object used to build the model's inputs, outputs, and nodes. + * \param input_def Input definition that describes what kind of input to create. + * \return A pointer to the new input. + */ +template +inline NodeArg* MakeTestInput(ModelTestBuilder& builder, const TestInputDef& input_def) { + NodeArg* input = nullptr; + const auto& shape = input_def.GetShape(); + const bool is_initializer = input_def.IsInitializer(); + + if (input_def.IsRawData()) { // Raw data. + const std::vector& raw_data = input_def.GetRawData(); + + if (is_initializer) { + input = builder.MakeInitializer(shape, raw_data); + } else { + input = builder.MakeInput(shape, raw_data); + } + } else { // Random data + const auto& rand_info = input_def.GetRandomDataInfo(); + + if (is_initializer) { + input = builder.MakeInitializer(shape, rand_info.min, rand_info.max); + } else { + input = builder.MakeInput(shape, rand_info.min, rand_info.max); + } + } + + return input; +} + +template <> +inline NodeArg* MakeTestInput(ModelTestBuilder& builder, const TestInputDef& input_def) { + NodeArg* input = nullptr; + const auto& shape = input_def.GetShape(); + const bool is_initializer = input_def.IsInitializer(); + + if (input_def.IsRawData()) { // Raw data. + const std::vector& raw_data = input_def.GetRawData(); + + if (is_initializer) { + input = builder.MakeInitializerBool(shape, raw_data); + } else { + input = builder.MakeInput(shape, raw_data); + } + } else { // Random data + if (is_initializer) { + input = builder.MakeRandInitializerBool(shape); + } else { + input = builder.MakeInputBool(shape); + } + } + + return input; +} + +// ONNX spec does not allow quantizing float to int32. However, this function will create an int32 input (divide by scale) +// and then return the output of DequantizeLinear. Note that bias_scale should be generally be equal +// to input_scale * weights_scale. See quantization tool: onnx_quantizer.py::quantize_bias_static() +// +// i.e., initial bias => manual quantization (int32) => DQ => final float bias +NodeArg* MakeTestQDQBiasInput(ModelTestBuilder& builder, const TestInputDef& bias_def, float bias_scale, + bool use_contrib_qdq = false); + +/** + * Returns a function that builds a model with a single operator with N inputs type InputType1 and M inputs + * of type InputType2. + * + * \param op_type The operator to instantiate. + * \param input_defs_1 List of input definitions of type InputType1. + * \param input_defs_2 List of input definitions of type InputType2. + * \param attrs List of operator attributes. + * \param op_domain The operator's domain. Defaults to the ONNX domain (i.e., ""). + * \returns A model building function. + */ +template +inline GetTestModelFn BuildOpTestCase(const std::string& op_type, + const std::vector>& input_defs_1, + const std::vector>& input_defs_2, + const std::vector& attrs, + const std::string& op_domain = kOnnxDomain) { + return [op_type, input_defs_1, input_defs_2, attrs, op_domain](ModelTestBuilder& builder) { + std::vector op_inputs; + op_inputs.reserve(input_defs_1.size() + input_defs_2.size()); + + for (const auto& input_def : input_defs_1) { + NodeArg* input = MakeTestInput(builder, input_def); + op_inputs.push_back(input); + } + + for (const auto& input_def : input_defs_2) { + NodeArg* input = MakeTestInput(builder, input_def); + op_inputs.push_back(input); + } + + auto* output = builder.MakeOutput(); + Node& onnx_node = builder.AddNode(op_type, op_inputs, {output}, op_domain); + + for (const auto& attr : attrs) { + onnx_node.AddAttributeProto(attr); + } + }; +} + +/** + * Returns a function that builds a model with a single QDQ operator with N float (quantizeable) inputs + * and M inputs of a potentially different type. + * + * \param op_type The operator to instantiate. + * \param input_defs List of input definitions. + * \param attrs List of operator attributes. + * \param op_domain The operator's domain. Defaults to the ONNX domain (i.e., ""). + * \returns A model building function. + */ +template +inline GetTestQDQModelFn BuildQDQOpTestCase(const std::string& op_type, + const std::vector>& quant_input_defs, + const std::vector>& non_quant_input_defs, + const std::vector& attrs, + const std::string& op_domain = kOnnxDomain, + bool use_contrib_qdq = false) { + return [op_type, quant_input_defs, non_quant_input_defs, attrs, op_domain, + use_contrib_qdq](ModelTestBuilder& builder, std::vector>& output_qparams) { + std::vector op_inputs; + op_inputs.reserve(quant_input_defs.size() + non_quant_input_defs.size()); + + // Create QDQ inputs + for (const auto& input_def : quant_input_defs) { + NodeArg* input = MakeTestInput(builder, input_def); + QuantParams input_qparams = GetTestInputQuantParams(input_def); + NodeArg* input_after_qdq = AddQDQNodePair(builder, input, input_qparams.scale, + input_qparams.zero_point, use_contrib_qdq); + op_inputs.push_back(input_after_qdq); + } + + // Create non-QDQ inputs + for (const auto& input_def : non_quant_input_defs) { + NodeArg* input = MakeTestInput(builder, input_def); + op_inputs.push_back(input); + } + + // Op -> op_output + auto* op_output = builder.MakeIntermediate(); + Node& onnx_node = builder.AddNode(op_type, op_inputs, {op_output}, op_domain); + + for (const auto& attr : attrs) { + onnx_node.AddAttributeProto(attr); + } + + // op_output -> Q -> DQ -> output + AddQDQNodePairWithOutputAsGraphOutput(builder, op_output, output_qparams[0].scale, + output_qparams[0].zero_point, use_contrib_qdq); + }; +} + /** * Runs a test model on the QNN EP. Checks the graph node assignment, and that inference * outputs for QNN and CPU match. @@ -26,13 +535,12 @@ using GetTestModelFn = std::function; * \param provider_options Provider options for QNN EP. * \param opset_version The opset version. * \param expected_ep_assignment How many nodes are expected to be assigned to QNN (All, Some, or None). - * \param num_modes_in_ep The expected number of nodes assigned to QNN EP's partition. - * \param test_description Description of the test for error reporting. * \param fp32_abs_err The acceptable error between CPU EP and QNN EP. + * \param log_severity The logger's minimum severity level. */ void RunQnnModelTest(const GetTestModelFn& build_test_case, const ProviderOptions& provider_options, - int opset_version, ExpectedEPNodeAssignment expected_ep_assignment, int num_nodes_in_ep, - const char* test_description, float fp32_abs_err = 1e-5f); + int opset_version, ExpectedEPNodeAssignment expected_ep_assignment, + float fp32_abs_err = 1e-5f, logging::Severity log_severity = logging::Severity::kERROR); enum class BackendSupport { SUPPORT_UNKNOWN, @@ -75,4 +583,4 @@ bool ReduceOpHasAxesInput(const std::string& op_type, int opset_version); } // 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/reduce_op_cpu_test.cc b/onnxruntime/test/providers/qnn/reduce_op_cpu_test.cc deleted file mode 100644 index 3be7416f51649..0000000000000 --- a/onnxruntime/test/providers/qnn/reduce_op_cpu_test.cc +++ /dev/null @@ -1,229 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#if !defined(ORT_MINIMAL_BUILD) - -#include -#include - -#include "test/optimizer/qdq_test_utils.h" -#include "test/providers/qnn/qnn_test_utils.h" - -#include "gtest/gtest.h" - -namespace onnxruntime { -namespace test { - -/** - * Creates a graph with a single reduce operator (e.g., ReduceSum, ReduceMin, etc.). Reduce operators take the - * axes of reduction as either a node attribute or an optional input (depending on opset). - * - * \param reduce_op_type The string denoting the reduce operator's type (e.g., "ReduceSum"). - * \param input_shape The shape of the input. Input data is randomly generated with this shape. - * \param axes_as_input True if the "axes" are specified as a node input. - * \param axes The axes of reduction. - * \param keepdims True if the output's rank should match the input. This is a node attribute that defaults to true. - * \param noop_with_empty_axes True if empty axes should force the node to act as a NoOp (no operation). - * This is a node attribute that defaults to false. - * \param domain The domain to assign to the graph node. - * - * \return A function that builds the graph with the provided builder. - */ -template -static GetTestModelFn BuildReduceOpTestCase(const std::string& reduce_op_type, - const std::vector& input_shape, - bool axes_as_input, std::vector axes, bool keepdims, - bool noop_with_empty_axes) { - return [reduce_op_type, input_shape, axes_as_input, axes, keepdims, - noop_with_empty_axes](ModelTestBuilder& builder) { - std::vector input_args; - - // Input data arg - input_args.push_back(builder.MakeInput(input_shape, static_cast(0), - static_cast(20))); - - // Axes input (initializer) for newer opsets. - if (axes_as_input) { - input_args.push_back(builder.MakeInitializer({static_cast(axes.size())}, axes)); - } - - auto* reduce_sum_output = builder.MakeOutput(); - Node& reduce_sum_node = builder.AddNode(reduce_op_type, input_args, {reduce_sum_output}); - reduce_sum_node.AddAttribute("keepdims", static_cast(keepdims)); - - // Older opsets have "axes" as a node attribute. - if (!axes_as_input) { - reduce_sum_node.AddAttribute("axes", axes); - } else { - reduce_sum_node.AddAttribute("noop_with_empty_axes", static_cast(noop_with_empty_axes)); - } - }; -} - -/** - * Runs a ReduceOp model on the QNN CPU backend. Checks the graph node assignment, and that inference - * outputs for QNN and CPU match. - * - * \param op_type The ReduceOp type (e.g., ReduceSum). - * \param opset The opset version. Some opset versions have "axes" as an attribute or input. - * \param test_description Description of the test for error reporting. - * \param expected_ep_assignment How many nodes are expected to be assigned to QNN (All, Some, or None) - * \param keepdims Common attribute for all reduce operations. - */ -template -static void RunReduceOpCpuTest(const std::string& op_type, int opset, const char* test_description, - ExpectedEPNodeAssignment expected_ep_assignment = ExpectedEPNodeAssignment::All, - bool keepdims = true) { - ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnCpu.dll"; -#else - provider_options["backend_path"] = "libQnnCpu.so"; -#endif - - constexpr int expected_nodes_in_partition = 1; - RunQnnModelTest(BuildReduceOpTestCase(op_type, - {2, 2}, // input shape - ReduceOpHasAxesInput(op_type, opset), - {0, 1}, // axes - keepdims, - false), // noop_with_empty_axes - provider_options, - opset, - expected_ep_assignment, - expected_nodes_in_partition, - test_description); -} - -// -// ReduceSum -// - -// Test creates a graph with a ReduceSum node, and checks that all -// nodes are supported by the QNN EP (cpu backend), and that the inference results match the CPU EP results. -// -// - The input and output data type is int32. -// - Uses opset 13, which has "axes" as an input. -TEST_F(QnnCPUBackendTests, TestInt32ReduceSumOpset13) { - RunReduceOpCpuTest("ReduceSum", 13, "TestInt32ReduceSumOpset13"); -} - -// Test creates a graph with a ReduceSum node, and checks that all -// nodes are supported by the QNN EP (cpu backend), and that the inference results match the CPU EP results. -// -// - The input and output data type is int32. -// - Uses opset 11, which has "axes" as an attribute. -TEST_F(QnnCPUBackendTests, TestInt32ReduceSumOpset11) { - RunReduceOpCpuTest("ReduceSum", 11, "TestInt32ReduceSumOpset11"); -} - -// Test creates a graph with a ReduceSum node, and checks that all -// nodes are supported by the QNN EP (cpu backend), and that the inference results match the CPU EP results. -// -// - The input and output data type is float. -// - Uses opset 13, which has "axes" as an input. -TEST_F(QnnCPUBackendTests, TestFloatReduceSumOpset13) { - RunReduceOpCpuTest("ReduceSum", 13, "TestFloatReduceSumOpset13"); -} - -// Test creates a graph with a ReduceSum node, and checks that all -// nodes are supported by the QNN EP (cpu backend), and that the inference results match the CPU EP results. -// -// - The input and output data type is float. -// - Uses opset 11, which has "axes" as an attribute. -TEST_F(QnnCPUBackendTests, TestFloatReduceSumOpset11) { - RunReduceOpCpuTest("ReduceSum", 11, "TestFloatReduceSumOpset11"); -} - -// -// ReduceProd -// - -// Test creates a graph with a ReduceProd node, and checks that all -// nodes are supported by the QNN EP (cpu backend), and that the inference results match the CPU EP results. -// -// - The input and output data type is float. -// - Uses opset 18, which has "axes" as an input. -TEST_F(QnnCPUBackendTests, TestReduceProdOpset18) { - RunReduceOpCpuTest("ReduceProd", 18, "TestReduceProdOpset18"); -} - -// Test creates a graph with a ReduceProd node, and checks that all -// nodes are supported by the QNN EP (cpu backend), and that the inference results match the CPU EP results. -// -// - The input and output data type is float. -// - Uses opset 13, which has "axes" as an attribute. -TEST_F(QnnCPUBackendTests, TestReduceProdOpset13) { - RunReduceOpCpuTest("ReduceProd", 13, "TestReduceProdOpset13"); -} - -// -// ReduceMax -// - -// Test creates a graph with a ReduceMax node, and checks that all -// nodes are supported by the QNN EP (cpu backend), and that the inference results match the CPU EP results. -// -// - The input and output data type is float. -// - Uses opset 18, which has "axes" as an input. -TEST_F(QnnCPUBackendTests, TestReduceMaxOpset18) { - RunReduceOpCpuTest("ReduceMax", 18, "TestReduceMaxOpset18"); -} - -// Test creates a graph with a ReduceMax node, and checks that all -// nodes are supported by the QNN EP (cpu backend), and that the inference results match the CPU EP results. -// -// - The input and output data type is float. -// - Uses opset 13, which has "axes" as an attribute. -TEST_F(QnnCPUBackendTests, TestReduceMaxOpset13) { - RunReduceOpCpuTest("ReduceMax", 13, "TestReduceMaxOpset13"); -} - -// -// ReduceMin -// - -// Test creates a graph with a ReduceMin node, and checks that all -// nodes are supported by the QNN EP (cpu backend), and that the inference results match the CPU EP results. -// -// - The input and output data type is float. -// - Uses opset 18, which has "axes" as an input. -TEST_F(QnnCPUBackendTests, TestReduceMinOpset18) { - RunReduceOpCpuTest("ReduceMin", 18, "TestReduceMinOpset18"); -} - -// Test creates a graph with a ReduceMin node, and checks that all -// nodes are supported by the QNN EP (cpu backend), and that the inference results match the CPU EP results. -// -// - The input and output data type is float. -// - Uses opset 13, which has "axes" as an attribute. -TEST_F(QnnCPUBackendTests, TestReduceMinOpset13) { - RunReduceOpCpuTest("ReduceMin", 13, "TestReduceMinOpset18"); -} - -// -// ReduceMean -// - -// Test creates a graph with a ReduceMean node, and checks that all -// nodes are supported by the QNN EP (cpu backend), and that the inference results match the CPU EP results. -// -// - The input and output data type is float. -// - Uses opset 18, which has "axes" as an input. -TEST_F(QnnCPUBackendTests, TestReduceMeanOpset18) { - RunReduceOpCpuTest("ReduceMean", 18, "TestReduceMeanOpset18"); -} - -// Test creates a graph with a ReduceMean node, and checks that all -// nodes are supported by the QNN EP (cpu backend), and that the inference results match the CPU EP results. -// -// - The input and output data type is float. -// - Uses opset 13, which has "axes" as an attribute. -TEST_F(QnnCPUBackendTests, TestReduceMeanOpset13) { - RunReduceOpCpuTest("ReduceMean", 13, "TestReduceMeanOpset13"); -} - -} // namespace test -} // namespace onnxruntime - -#endif // !defined(ORT_MINIMAL_BUILD) \ No newline at end of file diff --git a/onnxruntime/test/providers/qnn/reduce_op_htp_test.cc b/onnxruntime/test/providers/qnn/reduce_op_htp_test.cc deleted file mode 100644 index 947a273f6aa4d..0000000000000 --- a/onnxruntime/test/providers/qnn/reduce_op_htp_test.cc +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#if !defined(ORT_MINIMAL_BUILD) - -#include -#include "core/graph/graph.h" - -#include "test/optimizer/qdq_test_utils.h" -#include "test/providers/qnn/qnn_test_utils.h" - -#include "gtest/gtest.h" - -namespace onnxruntime { -namespace test { -#if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) - -/** - * Runs a ReduceOp model on the QNN HTP backend. Checks the graph node assignment, and that inference - * outputs for QNN and CPU match. - * - * \param op_type The ReduceOp type (e.g., ReduceSum). - * \param opset The opset version. Some opset versions have "axes" as an attribute or input. - * \param test_description Description of the test for error reporting. - * \param expected_ep_assignment How many nodes are expected to be assigned to QNN (All, Some, or None) - * \param keepdims Common attribute for all reduce operations. - */ -template -static void RunReduceOpQDQTest(const std::string& op_type, int opset, const char* test_description, - ExpectedEPNodeAssignment expected_ep_assignment = ExpectedEPNodeAssignment::All, - bool keepdims = true) { - ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif - - constexpr int expected_nodes_in_partition = 1; - RunQnnModelTest(BuildQDQReduceOpTestCase(op_type, - {2, 2}, // Input shape - ReduceOpHasAxesInput(op_type, opset), // Axes is an input - {0, 1}, // Axes - keepdims, // keepdims - false), // noop_with_empty_axes - provider_options, - opset, - expected_ep_assignment, - expected_nodes_in_partition, - test_description); -} - -// -// ReduceSum -// - -// Test creates a Q -> DQ -> ReduceSum -> Q -> DQ graph, and checks that all -// nodes are supported by the QNN EP, and that the inference results match the CPU EP results. -// -// - Uses uint8 as the quantization type. -// - Uses opset 13, which has "axes" as an input. -TEST_F(QnnHTPBackendTests, TestQDQReduceSumU8Opset13) { - RunReduceOpQDQTest("ReduceSum", 13, "TestQDQReduceSumU8Opset13"); -} - -// Test creates a Q -> DQ -> ReduceSum -> Q -> DQ graph, and checks that all -// nodes are supported by the QNN EP, and that the inference results match the CPU EP results. -// -// - Uses uint8 as the quantization type. -// - Uses opset 11, which has "axes" as an attribute. -TEST_F(QnnHTPBackendTests, TestQDQReduceSumU8Opset11) { - RunReduceOpQDQTest("ReduceSum", 11, "TestQDQReduceSumU8Opset11"); -} - -// Test creates a Q -> DQ -> ReduceSum -> Q -> DQ graph, and checks that all -// nodes are supported by the QNN EP, and that the inference results match the CPU EP results. -// -// - Uses int8 as the quantization type. -// - Uses opset 13, which has "axes" as an input. -TEST_F(QnnHTPBackendTests, TestQDQReduceSumS8Opset13) { - RunReduceOpQDQTest("ReduceSum", 13, "TestQDQReduceSumS8Opset13"); -} - -// -// ReduceMax -// - -// ReduceMax on Linux's HTP emulator is always off by an amount equal to the final DQ.scale -// Works fine on windows arm64. -#if !defined(__linux__) -// Test creates a Q -> DQ -> ReduceMax -> Q -> DQ graph, and checks that all -// nodes are supported by the QNN EP, and that the inference results match the CPU EP results. -// -// - Uses uint8 as the quantization type. -// - Uses opset 18, which has "axes" as an input. -TEST_F(QnnHTPBackendTests, TestQDQReduceMaxU8Opset18) { - RunReduceOpQDQTest("ReduceMax", 18, "TestQDQReduceMaxU8Opset18"); -} - -// Test creates a Q -> DQ -> ReduceMax -> Q -> DQ graph, and checks that all -// nodes are supported by the QNN EP, and that the inference results match the CPU EP results. -// -// - Uses uint8 as the quantization type. -// - Uses opset 13, which has "axes" as an attribute. -TEST_F(QnnHTPBackendTests, TestQDQReduceMaxU8Opset13) { - RunReduceOpQDQTest("ReduceMax", 13, "TestQDQReduceMaxU8Opset13"); -} - -// Test creates a Q -> DQ -> ReduceMax -> Q -> DQ graph, and checks that all -// nodes are supported by the QNN EP, and that the inference results match the CPU EP results. -// -// - Uses int8 as the quantization type. -// - Uses opset 18, which has "axes" as an input. -TEST_F(QnnHTPBackendTests, TestQDQReduceMaxS8Opset18) { - RunReduceOpQDQTest("ReduceMax", 18, "TestQDQReduceMaxS8Opset18"); -} -#endif // !defined(__linux__) - -// -// ReduceMin -// -// ReduceMin on Linux's HTP emulator is always off by an amount equal to the final DQ.scale -// Works fine on windows arm64. -#if !defined(__linux__) -// Test creates a Q -> DQ -> ReduceMin -> Q -> DQ graph, and checks that all -// nodes are supported by the QNN EP, and that the inference results match the CPU EP results. -// -// - Uses uint8 as the quantization type. -// - Uses opset 18, which has "axes" as an input. -TEST_F(QnnHTPBackendTests, TestQDQReduceMinU8Opset18) { - RunReduceOpQDQTest("ReduceMin", 18, "TestQDQReduceMinU8Opset18"); -} - -// Test creates a Q -> DQ -> ReduceMin -> Q -> DQ graph, and checks that all -// nodes are supported by the QNN EP, and that the inference results match the CPU EP results. -// -// - Uses uint8 as the quantization type. -// - Uses opset 13, which has "axes" as an attribute. -TEST_F(QnnHTPBackendTests, TestQDQReduceMinU8Opset13) { - RunReduceOpQDQTest("ReduceMin", 13, "TestQDQReduceMinU8Opset13"); -} - -// Test creates a Q -> DQ -> ReduceMin -> Q -> DQ graph, and checks that all -// nodes are supported by the QNN EP, and that the inference results match the CPU EP results. -// -// Uses int8 as the quantization type. -TEST_F(QnnHTPBackendTests, TestQDQReduceMinS8Opset18) { - RunReduceOpQDQTest("ReduceMin", 18, "TestQDQReduceMinS8Opset18"); -} -#endif // !defined(__linux__) - -// -// ReduceMean -// - -// Test creates a Q -> DQ -> ReduceMean -> Q -> DQ graph, and checks that all -// nodes are supported by the QNN EP, and that the inference results match the CPU EP results. -// -// - Uses uint8 as the quantization type. -// - Uses opset 18, which has "axes" as an input. -TEST_F(QnnHTPBackendTests, TestQDQReduceMeanU8Opset18) { - RunReduceOpQDQTest("ReduceMean", 18, "TestQDQReduceMeanU8Opset18"); -} - -// Test creates a Q -> DQ -> ReduceMean -> Q -> DQ graph, and checks that all -// nodes are supported by the QNN EP, and that the inference results match the CPU EP results. -// -// - Uses uint8 as the quantization type. -// - Uses opset 13, which has "axes" as an attribute. -TEST_F(QnnHTPBackendTests, TestQDQReduceMeanU8Opset13) { - RunReduceOpQDQTest("ReduceMean", 13, "TestQDQReduceMeanU8Opset13"); -} - -// Test creates a Q -> DQ -> ReduceMean -> Q -> DQ graph, and checks that all -// nodes are supported by the QNN EP, and that the inference results match the CPU EP results. -// -// - Uses int8 as the quantization type. -// - Uses opset 18, which has "axes" as an input. -TEST_F(QnnHTPBackendTests, TestQDQReduceMeanS8Opset18) { - RunReduceOpQDQTest("ReduceMean", 18, "TestQDQReduceMeanS8Opset18"); -} - -#endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) -} // namespace test -} // namespace onnxruntime - -#endif \ No newline at end of file diff --git a/onnxruntime/test/providers/qnn/reduce_op_test.cc b/onnxruntime/test/providers/qnn/reduce_op_test.cc new file mode 100644 index 0000000000000..57252f93492e5 --- /dev/null +++ b/onnxruntime/test/providers/qnn/reduce_op_test.cc @@ -0,0 +1,651 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#if !defined(ORT_MINIMAL_BUILD) + +#include +#include "core/graph/graph.h" + +#include "test/optimizer/qdq_test_utils.h" +#include "test/providers/qnn/qnn_test_utils.h" + +#include "gtest/gtest.h" + +namespace onnxruntime { +namespace test { + +/** + * Creates a graph with a single reduce operator (e.g., ReduceSum, ReduceMin, etc.). Reduce operators take the + * axes of reduction as either a node attribute or an optional input (depending on opset). + * + * \param reduce_op_type The string denoting the reduce operator's type (e.g., "ReduceSum"). + * \param input_def The input definition (shape, data, etc.) + * \param axes_as_input True if the "axes" are specified as a node input. + * \param axes The axes of reduction. + * \param keepdims True if the output's rank should match the input. This is a node attribute that defaults to true. + * \param noop_with_empty_axes True if empty axes should force the node to act as a NoOp (no operation). + * This is a node attribute that defaults to false. + * \param domain The domain to assign to the graph node. + * + * \return A function that builds the graph with the provided builder. + */ +template +static GetTestModelFn BuildReduceOpTestCase(const std::string& reduce_op_type, + const TestInputDef& input_def, + bool axes_as_input, std::vector axes, bool keepdims, + bool noop_with_empty_axes) { + return [reduce_op_type, input_def, axes_as_input, axes, keepdims, + noop_with_empty_axes](ModelTestBuilder& builder) { + std::vector input_args; + + // Input data arg + input_args.push_back(MakeTestInput(builder, input_def)); + + // Axes input (initializer) for newer opsets. + if (axes_as_input) { + input_args.push_back(builder.MakeInitializer({static_cast(axes.size())}, axes)); + } + + auto* reduce_sum_output = builder.MakeOutput(); + Node& reduce_sum_node = builder.AddNode(reduce_op_type, input_args, {reduce_sum_output}); + reduce_sum_node.AddAttribute("keepdims", static_cast(keepdims)); + + // Older opsets have "axes" as a node attribute. + if (!axes_as_input) { + reduce_sum_node.AddAttribute("axes", axes); + } else { + reduce_sum_node.AddAttribute("noop_with_empty_axes", static_cast(noop_with_empty_axes)); + } + }; +} + +/** + * Runs a ReduceOp model on the QNN CPU backend. Checks the graph node assignment, and that inference + * outputs for QNN and CPU match. + * + * \param op_type The ReduceOp type (e.g., ReduceSum). + * \param input_def The input definition (shape, data, etc.) + * \param axes The axes of reduction. + * \param opset The opset version. Some opset versions have "axes" as an attribute or input. + * \param expected_ep_assignment How many nodes are expected to be assigned to QNN (All, Some, or None) + * \param keepdims Common attribute for all reduce operations. + */ +template +static void RunReduceOpCpuTest(const std::string& op_type, + const TestInputDef& input_def, + const std::vector& axes, + bool keepdims, + int opset, + 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 + + RunQnnModelTest(BuildReduceOpTestCase(op_type, + input_def, //{2, 2}, // input shape + ReduceOpHasAxesInput(op_type, opset), + axes, //{0, 1}, // axes + keepdims, + false), // noop_with_empty_axes + provider_options, + opset, + expected_ep_assignment, + fp32_abs_err); +} + +// +// ReduceSum +// + +// Test creates a graph with a ReduceSum node, and checks that all +// nodes are supported by the QNN EP (cpu backend), and that the inference results match the CPU EP results. +// +// - The input and output data type is int32. +// - Uses opset 13, which has "axes" as an input. +TEST_F(QnnCPUBackendTests, ReduceSumOpset13_Int32) { + RunReduceOpCpuTest("ReduceSum", + TestInputDef({2, 2}, false, -10.0f, 10.0f), + std::vector{0, 1}, + true, // keepdims + 13, + ExpectedEPNodeAssignment::All); +} + +// Test creates a graph with a ReduceSum node, and checks that all +// nodes are supported by the QNN EP (cpu backend), and that the inference results match the CPU EP results. +// +// - The input and output data type is int32. +// - Uses opset 11, which has "axes" as an attribute. +TEST_F(QnnCPUBackendTests, ReduceSumOpset11_Int32) { + RunReduceOpCpuTest("ReduceSum", + TestInputDef({2, 2}, false, -10.0f, 10.0f), + std::vector{0, 1}, + true, // keepdims + 11, + ExpectedEPNodeAssignment::All); +} + +// Test creates a graph with a ReduceSum node, and checks that all +// nodes are supported by the QNN EP (cpu backend), and that the inference results match the CPU EP results. +// +// - The input and output data type is float. +// - Uses opset 13, which has "axes" as an input. +TEST_F(QnnCPUBackendTests, ReduceSumOpset13_Float) { + RunReduceOpCpuTest("ReduceSum", + TestInputDef({2, 2}, false, -10.0f, 10.0f), + std::vector{0, 1}, + true, // keepdims + 13, + ExpectedEPNodeAssignment::All); +} + +// Test creates a graph with a ReduceSum node, and checks that all +// nodes are supported by the QNN EP (cpu backend), and that the inference results match the CPU EP results. +// +// - The input and output data type is float. +// - Uses opset 11, which has "axes" as an attribute. +TEST_F(QnnCPUBackendTests, ReduceSumOpset11_Float) { + RunReduceOpCpuTest("ReduceSum", + TestInputDef({2, 2}, false, -10.0f, 10.0f), + std::vector{0, 1}, + true, // keepdims + 11, + ExpectedEPNodeAssignment::All); +} + +// +// ReduceProd +// + +// Test creates a graph with a ReduceProd node, and checks that all +// nodes are supported by the QNN EP (cpu backend), and that the inference results match the CPU EP results. +// +// - The input and output data type is float. +// - Uses opset 18, which has "axes" as an input. +TEST_F(QnnCPUBackendTests, ReduceProdOpset18) { + RunReduceOpCpuTest("ReduceProd", + TestInputDef({2, 2}, false, {-10.0f, -8.2f, 0.0f, 10.0f}), + std::vector{0, 1}, + true, // keepdims + 18, + ExpectedEPNodeAssignment::All); +} + +// TODO: Investigate slight inaccuracy. x64 Windows/Linux require a slightly larger error tolerance greater than 1.5e-5f. +// LOG: ... the value pair (208.881729, 208.881744) at index #0 don't match, which is 1.52588e-05 from 208.882 +TEST_F(QnnCPUBackendTests, ReduceProdOpset18_SlightlyInaccurate_WindowsLinuxX64) { + RunReduceOpCpuTest("ReduceProd", + TestInputDef({2, 2}, false, {3.21289f, -5.9981f, -1.72799f, 6.27263f}), + std::vector{0, 1}, + true, // keepdims + 18, + ExpectedEPNodeAssignment::All, + 2e-5f); // x64 Linux & Windows require larger tolerance. +} + +// Test creates a graph with a ReduceProd node, and checks that all +// nodes are supported by the QNN EP (cpu backend), and that the inference results match the CPU EP results. +// +// - The input and output data type is float. +// - Uses opset 13, which has "axes" as an attribute. +TEST_F(QnnCPUBackendTests, ReduceProdOpset13) { + RunReduceOpCpuTest("ReduceProd", + TestInputDef({2, 2}, false, {-10.0f, -8.2f, 0.0f, 10.0f}), + std::vector{0, 1}, + true, // keepdims + 13, + ExpectedEPNodeAssignment::All); +} + +// +// ReduceMax +// + +// Test creates a graph with a ReduceMax node, and checks that all +// nodes are supported by the QNN EP (cpu backend), and that the inference results match the CPU EP results. +// +// - The input and output data type is float. +// - Uses opset 18, which has "axes" as an input. +TEST_F(QnnCPUBackendTests, ReduceMaxOpset18) { + RunReduceOpCpuTest("ReduceMax", + TestInputDef({2, 2}, false, -10.0f, 10.0f), + std::vector{0, 1}, + true, // keepdims + 18, + ExpectedEPNodeAssignment::All); +} + +// Test creates a graph with a ReduceMax node, and checks that all +// nodes are supported by the QNN EP (cpu backend), and that the inference results match the CPU EP results. +// +// - The input and output data type is float. +// - Uses opset 13, which has "axes" as an attribute. +TEST_F(QnnCPUBackendTests, ReduceMaxOpset13) { + RunReduceOpCpuTest("ReduceMax", + TestInputDef({2, 2}, false, -10.0f, 10.0f), + std::vector{0, 1}, + true, // keepdims + 13, + ExpectedEPNodeAssignment::All); +} + +// +// ReduceMin +// + +// Test creates a graph with a ReduceMin node, and checks that all +// nodes are supported by the QNN EP (cpu backend), and that the inference results match the CPU EP results. +// +// - The input and output data type is float. +// - Uses opset 18, which has "axes" as an input. +TEST_F(QnnCPUBackendTests, ReduceMinOpset18) { + RunReduceOpCpuTest("ReduceMin", + TestInputDef({2, 2}, false, -10.0f, 10.0f), + std::vector{0, 1}, + true, // keepdims + 18, + ExpectedEPNodeAssignment::All); +} + +// Test creates a graph with a ReduceMin node, and checks that all +// nodes are supported by the QNN EP (cpu backend), and that the inference results match the CPU EP results. +// +// - The input and output data type is float. +// - Uses opset 13, which has "axes" as an attribute. +TEST_F(QnnCPUBackendTests, ReduceMinOpset13) { + RunReduceOpCpuTest("ReduceMin", + TestInputDef({2, 2}, false, -10.0f, 10.0f), + std::vector{0, 1}, + true, // keepdims + 13, + ExpectedEPNodeAssignment::All); +} + +// +// ReduceMean +// + +// Test creates a graph with a ReduceMean node, and checks that all +// nodes are supported by the QNN EP (cpu backend), and that the inference results match the CPU EP results. +// +// - The input and output data type is float. +// - Uses opset 18, which has "axes" as an input. +TEST_F(QnnCPUBackendTests, ReduceMeanOpset18) { + RunReduceOpCpuTest("ReduceMean", + TestInputDef({2, 2}, false, -10.0f, 10.0f), + std::vector{0, 1}, + true, // keepdims + 18, + ExpectedEPNodeAssignment::All); +} + +// Test creates a graph with a ReduceMean node, and checks that all +// nodes are supported by the QNN EP (cpu backend), and that the inference results match the CPU EP results. +// +// - The input and output data type is float. +// - Uses opset 13, which has "axes" as an attribute. +TEST_F(QnnCPUBackendTests, ReduceMeanOpset13) { + RunReduceOpCpuTest("ReduceMean", + TestInputDef({2, 2}, false, -10.0f, 10.0f), + std::vector{0, 1}, + true, // keepdims + 13, + ExpectedEPNodeAssignment::All); +} + +#if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) + +// Creates the following graph if axes is an input (newer opsets): +// _______________________ +// input (f32) -> Q -> DQ -> | | -> Q -> DQ -> output (f32) +// axes (int32, initializer) -> | Reduce___ | +// |_______________________| +// +// Creates the following graph if axes is an attribute (older opsets): +// _______________________ +// input (f32) -> Q -> DQ -> | | -> Q -> DQ -> output (f32) +// | Reduce___ | +// |_______________________| +// +template +GetTestQDQModelFn BuildQDQReduceOpTestCase(const std::string& reduce_op_type, + const TestInputDef& input_def, + bool axes_as_input, const std::vector& axes, bool keepdims, + bool noop_with_empty_axes) { + return [reduce_op_type, input_def, axes_as_input, axes, keepdims, + noop_with_empty_axes](ModelTestBuilder& builder, + std::vector>& output_qparams) { + // input -> Q -> DQ -> + NodeArg* input = MakeTestInput(builder, input_def); + QuantParams input_qparams = GetTestInputQuantParams(input_def); + auto* input_qdq = AddQDQNodePair(builder, input, input_qparams.scale, input_qparams.zero_point); + + // -> ReduceOp (e.g., ReduceSum) -> + std::vector reduce_op_inputs; + reduce_op_inputs.push_back(input_qdq); + + if (axes_as_input) { + reduce_op_inputs.push_back(builder.MakeInitializer({static_cast(axes.size())}, axes)); + } + + auto* op_output = builder.MakeIntermediate(); + Node& reduce_sum_node = builder.AddNode(reduce_op_type, reduce_op_inputs, {op_output}); + reduce_sum_node.AddAttribute("keepdims", static_cast(keepdims)); + + if (axes_as_input) { + reduce_sum_node.AddAttribute("noop_with_empty_axes", static_cast(noop_with_empty_axes)); + } else { + reduce_sum_node.AddAttribute("axes", axes); + } + + // -> Q -> DQ -> final output + AddQDQNodePairWithOutputAsGraphOutput(builder, op_output, output_qparams[0].scale, output_qparams[0].zero_point); + }; +} + +/** + * Runs a ReduceOp model on the QNN HTP backend. Checks the graph node assignment, and that inference + * outputs for QNN and CPU match. + * + * \param op_type The ReduceOp type (e.g., ReduceSum). + * \param input_def The input definition (shape, data, etc.). + * \param axes The axes input (or attribute). + * \param keepdims Common attribute for all reduce operations. + * \param opset The opset version. Some opset versions have "axes" as an attribute or input. + * \param expected_ep_assignment How many nodes are expected to be assigned to QNN (All, Some, or None) + * \param fp32_abs_err Error tolerance. + */ +template +static void RunReduceOpQDQTest(const std::string& op_type, + const TestInputDef& input_def, + const std::vector& axes, + bool keepdims, + int opset, + ExpectedEPNodeAssignment expected_ep_assignment, + float fp32_abs_err = 1e-4f) { + ProviderOptions provider_options; +#if defined(_WIN32) + provider_options["backend_path"] = "QnnHtp.dll"; +#else + provider_options["backend_path"] = "libQnnHtp.so"; +#endif + + constexpr bool noop_with_empty_axes = false; + const bool axes_as_input = ReduceOpHasAxesInput(op_type, opset); // Later opsets have "axes" as an input. + + TestQDQModelAccuracy(BuildReduceOpTestCase(op_type, input_def, axes_as_input, axes, keepdims, + noop_with_empty_axes), + BuildQDQReduceOpTestCase(op_type, input_def, axes_as_input, axes, keepdims, + noop_with_empty_axes), + provider_options, + opset, + expected_ep_assignment, + fp32_abs_err); +} + +// +// ReduceSum +// + +// Test creates a Q -> DQ -> ReduceSum -> Q -> DQ graph, and checks that all +// nodes are supported by the QNN EP, and that the inference results match the CPU EP results. +// +// - Uses uint8 as the quantization type. +// - Uses opset 13, which has "axes" as an input. +TEST_F(QnnHTPBackendTests, ReduceSumU8Opset13) { + RunReduceOpQDQTest("ReduceSum", + TestInputDef({2, 2}, false, {-10.0f, 3.21289f, -5.9981f, 10.0f}), + {0, 1}, // axes + true, // keepdims + 13, // opset + ExpectedEPNodeAssignment::All); +} + +// TODO: Investigate inaccuracy +// Input values: 3.21289 -5.9981 -1.72799 6.27263 +// Input quantization params [-10, 10]: scale=0.0784313753, zero_point=127 +// +// Inaccuracy detected for output 'output', element 0. +// Output quant params: scale=0.0068997270427644253, zero_point=0. +// Expected val: 1.7594304084777832 +// QNN QDQ val: 1.731831431388855 (err 0.027598977088928223) +// CPU QDQ val: 1.7594304084777832 (err 0) +TEST_F(QnnHTPBackendTests, DISABLED_ReduceSumU8Opset13_Inaccurate) { + const std::vector input_data = {3.21289f, -5.9981f, -1.72799f, 6.27263f}; + RunReduceOpQDQTest("ReduceSum", + TestInputDef({2, 2}, false, input_data).OverrideValueRange(-10.0f, 10.0f), + {0, 1}, // axes + true, // keepdims + 13, // opset + ExpectedEPNodeAssignment::All); +} +// Test creates a Q -> DQ -> ReduceSum -> Q -> DQ graph, and checks that all +// nodes are supported by the QNN EP, and that the inference results match the CPU EP results. +// +// - Uses uint8 as the quantization type. +// - Uses opset 11, which has "axes" as an attribute. +TEST_F(QnnHTPBackendTests, ReduceSumU8Opset11) { + RunReduceOpQDQTest("ReduceSum", + TestInputDef({2, 2}, false, {-10.0f, 3.21289f, -5.9981f, 10.0f}), + {0, 1}, // axes + true, // keepdims + 11, // opset + ExpectedEPNodeAssignment::All); +} + +// Test creates a Q -> DQ -> ReduceSum -> Q -> DQ graph, and checks that all +// nodes are supported by the QNN EP, and that the inference results match the CPU EP results. +// +// - Uses int8 as the quantization type. +// - Uses opset 13, which has "axes" as an input. +TEST_F(QnnHTPBackendTests, ReduceSumS8Opset13) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 9); + + RunReduceOpQDQTest("ReduceSum", + TestInputDef({3, 3}, false, input_data), + {0, 1}, // axes + true, // keepdims + 13, // opset + ExpectedEPNodeAssignment::All); +} + +// Tests that keepdims = false generates expected results. +TEST_F(QnnHTPBackendTests, ReduceSumS8Opset13_NoKeepDims) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 9); + + RunReduceOpQDQTest("ReduceSum", + TestInputDef({3, 3}, false, input_data), + {1}, // axes + false, // keepdims + 13, // opset + ExpectedEPNodeAssignment::All); +} + +// Test that we don't support rank 5 Reduce ops. +TEST_F(QnnHTPBackendTests, ReduceSumS8Opset13_Rank5Unsupported) { + RunReduceOpQDQTest("ReduceSum", + TestInputDef({1, 3, 4, 4, 2}, false, -10.0f, 10.0f), + {0, 1, 2, 3, 4}, // axes + true, // keepdims + 13, // opset + ExpectedEPNodeAssignment::None); +} + +// +// ReduceMax +// + +// Test creates a Q -> DQ -> ReduceMax -> Q -> DQ graph, and checks that all +// nodes are supported by the QNN EP, and that the inference results match the CPU EP results. +// +// - Uses uint8 as the quantization type. +// - Uses opset 18, which has "axes" as an input. +TEST_F(QnnHTPBackendTests, ReduceMaxU8Opset18) { + RunReduceOpQDQTest("ReduceMax", + TestInputDef({2, 2}, false, -10.0f, 10.0f), + {0, 1}, // axes + true, // keepdims + 18, // opset + ExpectedEPNodeAssignment::All); +} + +// Test creates a Q -> DQ -> ReduceMax -> Q -> DQ graph, and checks that all +// nodes are supported by the QNN EP, and that the inference results match the CPU EP results. +// +// - Uses uint8 as the quantization type. +// - Uses opset 13, which has "axes" as an attribute. +TEST_F(QnnHTPBackendTests, ReduceMaxU8Opset13) { + RunReduceOpQDQTest("ReduceMax", + TestInputDef({2, 2}, false, -10.0f, 10.0f), + {0, 1}, // axes + true, // keepdims + 13, // opset + ExpectedEPNodeAssignment::All); +} + +// Test creates a Q -> DQ -> ReduceMax -> Q -> DQ graph, and checks that all +// nodes are supported by the QNN EP, and that the inference results match the CPU EP results. +// +// - Uses int8 as the quantization type. +// - Uses opset 18, which has "axes" as an input. +TEST_F(QnnHTPBackendTests, ReduceMaxS8Opset18) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 9); + + RunReduceOpQDQTest("ReduceMax", + TestInputDef({3, 3}, false, input_data), + {0, 1}, // axes + true, // keepdims + 18, // opset + ExpectedEPNodeAssignment::All); +} + +// +// ReduceMin +// + +// Test creates a Q -> DQ -> ReduceMin -> Q -> DQ graph, and checks that all +// nodes are supported by the QNN EP, and that the inference results match the CPU EP results. +// +// - Uses uint8 as the quantization type. +// - Uses opset 18, which has "axes" as an input. +TEST_F(QnnHTPBackendTests, ReduceMinU8Opset18) { + RunReduceOpQDQTest("ReduceMin", + TestInputDef({2, 2}, false, -10.0f, 10.0f), + {0, 1}, // axes + true, // keepdims + 18, // opset + ExpectedEPNodeAssignment::All); +} + +// Test creates a Q -> DQ -> ReduceMin -> Q -> DQ graph, and checks that all +// nodes are supported by the QNN EP, and that the inference results match the CPU EP results. +// +// - Uses uint8 as the quantization type. +// - Uses opset 13, which has "axes" as an attribute. +TEST_F(QnnHTPBackendTests, ReduceMinU8Opset13) { + RunReduceOpQDQTest("ReduceMin", + TestInputDef({2, 2}, false, -10.0f, 10.0f), + {0, 1}, // axes + true, // keepdims + 13, // opset + ExpectedEPNodeAssignment::All); +} + +// Test creates a Q -> DQ -> ReduceMin -> Q -> DQ graph, and checks that all +// nodes are supported by the QNN EP, and that the inference results match the CPU EP results. +// +// Uses int8 as the quantization type. +TEST_F(QnnHTPBackendTests, ReduceMinS8Opset18) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 9); + + RunReduceOpQDQTest("ReduceMin", + TestInputDef({3, 3}, false, input_data), + {0, 1}, // axes + true, // keepdims + 18, // opset + ExpectedEPNodeAssignment::All); +} + +// +// ReduceMean +// + +// Test creates a Q -> DQ -> ReduceMean -> Q -> DQ graph, and checks that all +// nodes are supported by the QNN EP, and that the inference results match the CPU EP results. +// +// - Uses uint8 as the quantization type. +// - Uses opset 18, which has "axes" as an input. +TEST_F(QnnHTPBackendTests, ReduceMeanU8Opset18) { + RunReduceOpQDQTest("ReduceMean", + TestInputDef({2, 2}, false, {-10.0f, 3.21289f, -5.9981f, 10.0f}), + {0, 1}, // axes + true, // keepdims + 18, // opset + ExpectedEPNodeAssignment::All); +} + +// TODO: Investigate inaccuracy +// Input values: 3.21289 -5.9981 -1.72799 6.27263 +// Input quantization params [-10, 10]: scale=0.0784313753, zero_point=127 +// +// Inaccuracy detected for output 'output', element 0. +// Output quant params: scale=0.0017249317606911063, zero_point=0. +// Expected val: 0.4398576021194458 +// QNN QDQ val: 0.43295785784721375 (err 0.0068997442722320557) +// CPU QDQ val: 0.4398576021194458 (err 0) +TEST_F(QnnHTPBackendTests, DISABLED_ReduceMeanU8Opset18_Inaccurate) { + const std::vector input_data = {3.21289f, -5.9981f, -1.72799f, 6.27263f}; + RunReduceOpQDQTest("ReduceMean", + TestInputDef({2, 2}, false, input_data).OverrideValueRange(-10.0f, 10.0f), + {0, 1}, // axes + true, // keepdims + 18, // opset + ExpectedEPNodeAssignment::All); +} + +// Test creates a Q -> DQ -> ReduceMean -> Q -> DQ graph, and checks that all +// nodes are supported by the QNN EP, and that the inference results match the CPU EP results. +// +// - Uses uint8 as the quantization type. +// - Uses opset 13, which has "axes" as an attribute. +TEST_F(QnnHTPBackendTests, ReduceMeanU8Opset13) { + RunReduceOpQDQTest("ReduceMean", + TestInputDef({2, 2}, false, {-10.0f, 3.21289f, -5.9981f, 10.0f}), + {0, 1}, // axes + true, // keepdims + 13, // opset + ExpectedEPNodeAssignment::All); +} + +// Test creates a Q -> DQ -> ReduceMean -> Q -> DQ graph, and checks that all +// nodes are supported by the QNN EP, and that the inference results match the CPU EP results. +// +// - Uses int8 as the quantization type. +// - Uses opset 18, which has "axes" as an input. +// +// TODO(adrianlizarraga): Inaccuracy detected for output 'output', element 0. +// Output quant params: scale=0.0007829521200619638, zero_point=127. +// Expected val: -0.19965279102325439 +// QNN QDQ val: -0.19730393588542938 (err 0.0023488551378250122) +// CPU QDQ val: -0.19965279102325439 (err 0) +TEST_F(QnnHTPBackendTests, ReduceMeanS8Opset18) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 48); + + RunReduceOpQDQTest("ReduceMean", + TestInputDef({1, 3, 4, 4}, false, input_data), + {0, 1, 2, 3}, // axes + true, // keepdims + 18, // opset + ExpectedEPNodeAssignment::All, + 0.0016f); // TODO: Remove additional tolerance needed for inaccuracy +} + +#endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) +} // namespace test +} // namespace onnxruntime + +#endif diff --git a/onnxruntime/test/providers/qnn/reshape_op_test.cc b/onnxruntime/test/providers/qnn/reshape_op_test.cc new file mode 100644 index 0000000000000..eb495e44ec770 --- /dev/null +++ b/onnxruntime/test/providers/qnn/reshape_op_test.cc @@ -0,0 +1,225 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#if !defined(ORT_MINIMAL_BUILD) + +#include + +#include "test/providers/qnn/qnn_test_utils.h" +#include "core/graph/node_attr_utils.h" + +#include "onnx/onnx_pb.h" +#include "gtest/gtest.h" + +namespace onnxruntime { +namespace test { + +// Runs a model with a Reshape operator on the QNN CPU backend. Checks the graph node assignment +// and that inference outputs for QNN EP and CPU EP match. +template +static void RunReshapeTestOnCPU(const TestInputDef& input_def, + const TestInputDef& shape_def, + const std::vector& attrs, + 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 + + RunQnnModelTest(BuildOpTestCase("Reshape", {input_def}, {shape_def}, attrs), + provider_options, + opset, + expected_ep_assignment); +} + +// +// CPU tests: +// + +// Test that Reshape with a dynamic shape input is not supported by QNN EP. +TEST_F(QnnCPUBackendTests, Reshape_DynamicShape_Unsupported) { + RunReshapeTestOnCPU(TestInputDef({1, 3, 4, 4}, false, -10.0f, 10.0f), + TestInputDef({2}, false /* is_initializer */, {1, 48}), + {}, // Attributes + ExpectedEPNodeAssignment::None, // Should not be assigned to QNN EP. + 19); // Opset +} + +// Test that Reshape with an enabled 'allowzero' attribute is not supported by QNN EP. +TEST_F(QnnCPUBackendTests, Reshape_AllowZeroAttr_Unsupported) { + RunReshapeTestOnCPU(TestInputDef({1, 3, 4, 4}, false, -10.0f, 10.0f), + TestInputDef({2}, true, {1, 48}), + {utils::MakeAttribute("allowzero", static_cast(1))}, + ExpectedEPNodeAssignment::None, // Should not be assigned to QNN EP. + 19); // Opset +} + +// Test Reshape of rank 4 -> rank 2. +TEST_F(QnnCPUBackendTests, Reshape_4D_f32) { + RunReshapeTestOnCPU(TestInputDef({1, 3, 4, 4}, false, GetFloatDataInRange(-10.0f, 10.0f, 48)), + TestInputDef({2}, true, {1, 48}), + {}, // Attributes + ExpectedEPNodeAssignment::All, + 19); // Opset +} + +#if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) +// +// HTP tests: +// + +// Returns a function that creates a graph with a QDQ Reshape operator. +template +GetTestQDQModelFn BuildQDQReshapeTestCase(const TestInputDef& input_def, + const TestInputDef& shape_def, + const std::vector& attrs, + bool use_contrib_qdq = false) { + return [input_def, shape_def, attrs, + use_contrib_qdq](ModelTestBuilder& builder, + std::vector>& output_qparams) { + // input -> Q -> DQ -> + NodeArg* input = MakeTestInput(builder, input_def); + QuantParams input_qparams = GetTestInputQuantParams(input_def); + NodeArg* input_qdq = AddQDQNodePair(builder, input, input_qparams.scale, input_qparams.zero_point, + use_contrib_qdq); + + // shape input + NodeArg* shape_input = MakeTestInput(builder, shape_def); + + // Reshape op + NodeArg* reshape_output = builder.MakeIntermediate(); + Node& reshape_node = builder.AddNode("Reshape", {input_qdq, shape_input}, {reshape_output}); + + for (const auto& attr : attrs) { + reshape_node.AddAttributeProto(attr); + } + + // op_output -> Q -> DQ -> output + // NOTE: Input and output quantization parameters must be equal for Reshape. + output_qparams[0] = input_qparams; // Overwrite! + AddQDQNodePairWithOutputAsGraphOutput(builder, reshape_output, input_qparams.scale, + input_qparams.zero_point, use_contrib_qdq); + }; +} + +// Runs a model with a non-QDQ Reshape operator on the QNN HTP backend. Checks the graph node assignment +// and that inference outputs for QNN EP and CPU EP match. +template +static void RunReshapeTestOnHTP(const TestInputDef& input_def, + const TestInputDef& shape_def, + const std::vector& attrs, + ExpectedEPNodeAssignment expected_ep_assignment, + int opset = 19) { + ProviderOptions provider_options; + +#if defined(_WIN32) + provider_options["backend_path"] = "QnnHtp.dll"; +#else + provider_options["backend_path"] = "libQnnHtp.so"; +#endif + + RunQnnModelTest(BuildOpTestCase("Reshape", {input_def}, {shape_def}, attrs), + provider_options, + opset, + expected_ep_assignment); +} + +// Runs a QDQ Reshape model on the QNN (HTP) EP and the ORT CPU EP. Checks the graph node assignment and that inference +// running the QDQ model on QNN EP is at least as accurate as on ORT CPU EP (compared to the baseline float32 model). +template +static void RunQDQReshapeTestOnHTP(const TestInputDef& input_def, + const TestInputDef& shape_def, + const std::vector& attrs, + ExpectedEPNodeAssignment expected_ep_assignment, + int opset = 19, + 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 + + auto f32_model_builder = BuildOpTestCase("Reshape", {input_def}, {shape_def}, attrs); + auto qdq_model_builder = BuildQDQReshapeTestCase(input_def, shape_def, attrs, use_contrib_qdq); + TestQDQModelAccuracy(f32_model_builder, + qdq_model_builder, + provider_options, + opset, + expected_ep_assignment); +} + +// Test that QDQ Reshape with a dynamic shape input is not supported by QNN EP. +TEST_F(QnnHTPBackendTests, Reshape_DynamicShape_Unsupported) { + RunQDQReshapeTestOnHTP(TestInputDef({1, 3, 4, 4}, false, -10.0f, 10.0f), + TestInputDef({2}, false /* is_initializer */, {1, 48}), + {}, // Attributes + ExpectedEPNodeAssignment::None, // Should not be assigned to QNN EP. + 19); // Opset +} + +// Test that QDQ Reshape with an enabled 'allowzero' attribute is not supported by QNN EP. +TEST_F(QnnHTPBackendTests, Reshape_AllowZeroAttr_Unsupported) { + RunQDQReshapeTestOnHTP(TestInputDef({1, 3, 4, 4}, false, -10.0f, 10.0f), + TestInputDef({2}, true, {1, 48}), + {utils::MakeAttribute("allowzero", static_cast(1))}, + ExpectedEPNodeAssignment::None, // Should not be assigned to QNN EP. + 19); // Opset +} + +// Test 8-bit QDQ Reshape of rank 4 -> rank 2. +TEST_F(QnnHTPBackendTests, Reshape_4D_u8) { + RunQDQReshapeTestOnHTP(TestInputDef({1, 3, 4, 4}, false, GetFloatDataInRange(-10.0f, 10.0f, 48)), + TestInputDef({2}, true, {1, 48}), + {}, // Attributes + ExpectedEPNodeAssignment::All, + 19); // Opset +} + +// Test 16-bit QDQ Reshape of rank 4 -> rank 2. +TEST_F(QnnHTPBackendTests, Reshape_4D_u16) { + RunQDQReshapeTestOnHTP(TestInputDef({1, 3, 4, 4}, false, GetFloatDataInRange(-10.0f, 10.0f, 48)), + TestInputDef({2}, true, {1, 48}), + {}, // Attributes + ExpectedEPNodeAssignment::All, + 19, // Opset + true); // Use com.microsoft Q/DQ ops +} + +// Test that int32 Reshape runs on HTP backend. +TEST_F(QnnHTPBackendTests, Reshape_4D_int32) { + std::vector input_data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + RunReshapeTestOnHTP(TestInputDef({1, 3, 2, 2}, false, input_data), + TestInputDef({3}, true, {1, 1, 12}), + {}, // Attributes + ExpectedEPNodeAssignment::All, + 19); // Opset +} + +// Test QDQ Reshape with a shape value of 0 (copy dimension from input) +TEST_F(QnnHTPBackendTests, Reshape_4D_0MeansCopy) { + RunQDQReshapeTestOnHTP(TestInputDef({1, 3, 4, 4}, false, GetFloatDataInRange(-10.0f, 10.0f, 48)), + TestInputDef({3}, true, {1, 0, 16}), // zero means copy => '(1, 3, 16)' + {}, // Attributes + ExpectedEPNodeAssignment::All, + 19); // Opset +} + +// Test QDQ Reshape with a shape value of -1 (dimension is inferred from the expected number of elements) +TEST_F(QnnHTPBackendTests, Reshape_4D_Neg1MeansInfer) { + RunQDQReshapeTestOnHTP(TestInputDef({1, 3, 4, 4}, false, GetFloatDataInRange(-10.0f, 10.0f, 48)), + TestInputDef({3}, true, {1, 3, -1}), // -1 means infer => '(1, 3, 16)' + {}, // Attributes + ExpectedEPNodeAssignment::All, + 19); // Opset +} + +#endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) +} // namespace test +} // namespace onnxruntime +#endif // !defined(ORT_MINIMAL_BUILD) diff --git a/onnxruntime/test/providers/qnn/resize_test.cc b/onnxruntime/test/providers/qnn/resize_test.cc index 679256d628de8..cd6865d443cc0 100644 --- a/onnxruntime/test/providers/qnn/resize_test.cc +++ b/onnxruntime/test/providers/qnn/resize_test.cc @@ -27,18 +27,18 @@ namespace test { * * \return A function that builds the graph with the provided builder. */ -static GetTestModelFn BuildResizeTestCase(const std::vector& shape, - const std::vector& sizes_data, - const std::string& mode = "nearest", - const std::string& coordinate_transformation_mode = "half_pixel", - const std::string& nearest_mode = "round_prefer_floor") { - return [shape, sizes_data, mode, coordinate_transformation_mode, nearest_mode](ModelTestBuilder& builder) { - auto* input = builder.MakeInput(shape, 0.0f, 20.0f); - auto* roi = builder.MakeInitializer({0}, {}); - auto* scales = builder.MakeInitializer({0}, {}); - auto* sizes = builder.Make1DInitializer(sizes_data); - - auto* output = builder.MakeOutput(); +static GetTestModelFn GetResizeModelBuilder(const TestInputDef& input_def, + const std::vector& sizes_data, + const std::string& mode = "nearest", + const std::string& coordinate_transformation_mode = "half_pixel", + const std::string& nearest_mode = "round_prefer_floor") { + return [input_def, sizes_data, mode, coordinate_transformation_mode, nearest_mode](ModelTestBuilder& builder) { + NodeArg* input = MakeTestInput(builder, input_def); + NodeArg* roi = builder.MakeInitializer({0}, {}); + NodeArg* scales = builder.MakeInitializer({0}, {}); + NodeArg* sizes = builder.Make1DInitializer(sizes_data); + + NodeArg* output = builder.MakeOutput(); Node& resize_node = builder.AddNode("Resize", {input, roi, scales, sizes}, {output}); resize_node.AddAttribute("mode", mode); resize_node.AddAttribute("coordinate_transformation_mode", coordinate_transformation_mode); @@ -49,17 +49,17 @@ static GetTestModelFn BuildResizeTestCase(const std::vector& shape, }; } -static GetTestModelFn BuildResizeTestCaseWithScales(const std::vector& shape, - const std::vector& scales_data, - const std::string& mode = "nearest", - const std::string& coordinate_transformation_mode = "half_pixel", - const std::string& nearest_mode = "round_prefer_floor") { - return [shape, scales_data, mode, coordinate_transformation_mode, nearest_mode](ModelTestBuilder& builder) { - auto* input = builder.MakeInput(shape, 0.0f, 20.0f); - auto* roi = builder.MakeInitializer({0}, {}); - auto* scales = builder.Make1DInitializer(scales_data); - - auto* output = builder.MakeOutput(); +static GetTestModelFn GetResizeModelBuilderWithScales(const TestInputDef& input_def, + const std::vector& scales_data, + const std::string& mode = "nearest", + const std::string& coordinate_transformation_mode = "half_pixel", + const std::string& nearest_mode = "round_prefer_floor") { + return [input_def, scales_data, mode, coordinate_transformation_mode, nearest_mode](ModelTestBuilder& builder) { + NodeArg* input = MakeTestInput(builder, input_def); + NodeArg* roi = builder.MakeInitializer({0}, {}); + NodeArg* scales = builder.Make1DInitializer(scales_data); + + NodeArg* output = builder.MakeOutput(); Node& resize_node = builder.AddNode("Resize", {input, roi, scales}, {output}); resize_node.AddAttribute("mode", mode); resize_node.AddAttribute("coordinate_transformation_mode", coordinate_transformation_mode); @@ -70,24 +70,57 @@ static GetTestModelFn BuildResizeTestCaseWithScales(const std::vector& }; } +template +static GetTestQDQModelFn GetQDQResizeModelBuilder(const TestInputDef& input_def, + const std::vector& sizes_data, + const std::string& mode = "nearest", + const std::string& coordinate_transformation_mode = "half_pixel", + const std::string& nearest_mode = "round_prefer_floor") { + return [input_def, sizes_data, mode, + coordinate_transformation_mode, nearest_mode](ModelTestBuilder& builder, + std::vector>& output_qparams) { + // input -> Q -> DQ -> + NodeArg* input = MakeTestInput(builder, input_def); + QuantParams input_qparams = GetTestInputQuantParams(input_def); + NodeArg* input_qdq = AddQDQNodePair(builder, input, input_qparams.scale, input_qparams.zero_point); + + NodeArg* roi = builder.MakeInitializer({0}, {}); + NodeArg* scales = builder.MakeInitializer({0}, {}); + NodeArg* sizes = builder.Make1DInitializer(sizes_data); + + NodeArg* resize_output = builder.MakeIntermediate(); + Node& resize_node = builder.AddNode("Resize", {input_qdq, roi, scales, sizes}, {resize_output}); + resize_node.AddAttribute("mode", mode); + resize_node.AddAttribute("coordinate_transformation_mode", coordinate_transformation_mode); + + if (mode == "nearest") { + resize_node.AddAttribute("nearest_mode", nearest_mode); + } + + // Resize requires the output quantization parameters to match the input. + output_qparams[0] = input_qparams; + AddQDQNodePairWithOutputAsGraphOutput(builder, resize_output, output_qparams[0].scale, + output_qparams[0].zero_point); + }; +} + /** * Runs a Resize model on the QNN CPU backend. Checks the graph node assignment, and that inference * outputs for QNN and CPU match. * - * \param shape The shape of the input and output. Input data is randomly generated with this shape. + * \param input_def The input definition (shape, data, etc). * \param sizes_data The sizes input which determines the output shape. * \param mode The resize mode (e.g., nearest, linear). * \param coordinate_transformation_mode The coordinate transformation mode (e.g., half_pixel, pytorch_half_pixel). * \param nearest_mode The rounding for "nearest" mode (e.g., round_prefer_floor, floor). * \param expected_ep_assignment How many nodes are expected to be assigned to QNN (All, Some, or None). - * \param test_description Description of the test for error reporting. * \param opset The opset version to use. */ -static void RunCPUResizeOpTest(const std::vector& shape, const std::vector& sizes_data, +static void RunCPUResizeOpTest(const TestInputDef& input_def, const std::vector& sizes_data, const std::string& mode, const std::string& coordinate_transformation_mode, const std::string& nearest_mode, - ExpectedEPNodeAssignment expected_ep_assignment, const char* test_description, - int opset = 11) { + ExpectedEPNodeAssignment expected_ep_assignment, + int opset = 19) { ProviderOptions provider_options; #if defined(_WIN32) provider_options["backend_path"] = "QnnCpu.dll"; @@ -95,20 +128,17 @@ static void RunCPUResizeOpTest(const std::vector& shape, const std::vec provider_options["backend_path"] = "libQnnCpu.so"; #endif - constexpr int expected_nodes_in_partition = 1; - RunQnnModelTest(BuildResizeTestCase(shape, sizes_data, mode, coordinate_transformation_mode, nearest_mode), + RunQnnModelTest(GetResizeModelBuilder(input_def, sizes_data, mode, coordinate_transformation_mode, nearest_mode), provider_options, opset, - expected_ep_assignment, - expected_nodes_in_partition, - test_description); + expected_ep_assignment); } -static void RunCPUResizeOpTestWithScales(const std::vector& shape, const std::vector& scales_data, +static void RunCPUResizeOpTestWithScales(const TestInputDef& input_def, const std::vector& scales_data, const std::string& mode, const std::string& coordinate_transformation_mode, const std::string& nearest_mode, - ExpectedEPNodeAssignment expected_ep_assignment, const char* test_description, - int opset = 11) { + ExpectedEPNodeAssignment expected_ep_assignment, + int opset = 19) { ProviderOptions provider_options; #if defined(_WIN32) provider_options["backend_path"] = "QnnCpu.dll"; @@ -116,21 +146,19 @@ static void RunCPUResizeOpTestWithScales(const std::vector& shape, cons provider_options["backend_path"] = "libQnnCpu.so"; #endif - constexpr int expected_nodes_in_partition = 1; - RunQnnModelTest(BuildResizeTestCaseWithScales(shape, scales_data, mode, coordinate_transformation_mode, nearest_mode), + RunQnnModelTest(GetResizeModelBuilderWithScales(input_def, scales_data, mode, coordinate_transformation_mode, nearest_mode), provider_options, opset, - expected_ep_assignment, - expected_nodes_in_partition, - test_description); + expected_ep_assignment); } template -static void RunQDQResizeOpTest(const std::vector& shape, const std::vector& sizes_data, +static void RunQDQResizeOpTest(const TestInputDef& input_def, + const std::vector& sizes_data, const std::string& mode, const std::string& coordinate_transformation_mode, const std::string& nearest_mode, - ExpectedEPNodeAssignment expected_ep_assignment, float fp32_abs_err, - const char* test_description) { + ExpectedEPNodeAssignment expected_ep_assignment, + int opset = 19) { ProviderOptions provider_options; #if defined(_WIN32) provider_options["backend_path"] = "QnnHtp.dll"; @@ -138,107 +166,158 @@ static void RunQDQResizeOpTest(const std::vector& shape, const std::vec provider_options["backend_path"] = "libQnnHtp.so"; #endif - constexpr int expected_nodes_in_partition = 1; - RunQnnModelTest(BuildQDQResizeTestCase(shape, sizes_data, mode, coordinate_transformation_mode, - nearest_mode, true), - provider_options, - 18, // opset - expected_ep_assignment, - expected_nodes_in_partition, - test_description, - fp32_abs_err); + TestQDQModelAccuracy(GetResizeModelBuilder(input_def, sizes_data, mode, coordinate_transformation_mode, nearest_mode), + GetQDQResizeModelBuilder(input_def, sizes_data, mode, coordinate_transformation_mode, + nearest_mode), + provider_options, + opset, + expected_ep_assignment); } // // CPU tests: // -// TODO: Enable QnnCPU tests that use "nearest" mode. -// -// Our non-quantized implementation of Resize uses QNN's ResizeNearestNeighbor operator, -// which is __not__ equivalent to ONNX's Resize operator with a single specific "nearest_mode". -// The following disabled unit tests would pass if we removed the check in QNN EP that expects the -// "nearest_mode" to be "floor". Sometimes, ResizeNearestNeighbor is equivalent to ONNX Resize with -// "round_prefer_floor", and other times it is equivalent to ONNX Resize with "round_prefer_ceil". - // Upsample that uses "round_prefer_floor" as the "nearest_mode". // coordinate_transformation_mode: "half_pixel" -TEST_F(QnnCPUBackendTests, DISABLED_TestResizeUpsampleNearestHalfPixel_rpf) { - RunCPUResizeOpTest({1, 2, 7, 5}, {1, 2, 21, 10}, "nearest", "half_pixel", "round_prefer_floor", - ExpectedEPNodeAssignment::All, "TestResizeUpsampleNearestHalfPixel_rpf"); +TEST_F(QnnCPUBackendTests, ResizeUpsampleNearestHalfPixel_rpf) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 70); + RunCPUResizeOpTest(TestInputDef({1, 2, 7, 5}, false, input_data), + {1, 2, 21, 10}, // Sizes + "nearest", + "half_pixel", + "round_prefer_floor", + ExpectedEPNodeAssignment::All); } // Upsample that uses "round_prefer_ceil" as the "nearest_mode". // coordinate_transformation_mode: "half_pixel" -TEST_F(QnnCPUBackendTests, DISABLED_TestResizeUpsampleNearestHalfPixel_rpc) { - RunCPUResizeOpTest({1, 1, 2, 4}, {1, 1, 7, 5}, "nearest", "half_pixel", "round_prefer_ceil", - ExpectedEPNodeAssignment::All, "TestResizeUpsampleNearestHalfPixel_rpc"); +TEST_F(QnnCPUBackendTests, ResizeUpsampleNearestHalfPixel_rpc) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 8); + RunCPUResizeOpTest(TestInputDef({1, 1, 2, 4}, false, input_data), + {1, 1, 7, 5}, "nearest", "half_pixel", "round_prefer_ceil", + ExpectedEPNodeAssignment::All); } // Downsample that uses "round_prefer_ceil" as the "nearest_mode". // coordinate_transformation_mode: "half_pixel" -TEST_F(QnnCPUBackendTests, DISABLED_TestResizeDownsampleNearestHalfPixel_rpc) { - RunCPUResizeOpTest({1, 1, 2, 4}, {1, 1, 1, 3}, "nearest", "half_pixel", "round_prefer_ceil", - ExpectedEPNodeAssignment::All, "TestResizeDownsampleNearestHalfPixel_rpc"); +TEST_F(QnnCPUBackendTests, ResizeDownsampleNearestHalfPixel_rpc) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 8); + RunCPUResizeOpTest(TestInputDef({1, 1, 2, 4}, false, input_data), + {1, 1, 1, 3}, "nearest", "half_pixel", "round_prefer_ceil", + ExpectedEPNodeAssignment::All); } // Downsample that uses "round_prefer_floor" as the "nearest_mode". // coordinate_transformation_mode: "half_pixel" -TEST_F(QnnCPUBackendTests, DISABLED_TestResizeDownsampleNearestHalfPixel_rpf) { - RunCPUResizeOpTest({1, 1, 2, 4}, {1, 1, 1, 2}, "nearest", "half_pixel", "round_prefer_ceil", - ExpectedEPNodeAssignment::All, "TestResizeDownsampleNearestHalfPixel_rpf"); +TEST_F(QnnCPUBackendTests, ResizeDownsampleNearestHalfPixel_rpf) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 8); + RunCPUResizeOpTest(TestInputDef({1, 1, 2, 4}, false, input_data), + {1, 1, 1, 2}, "nearest", "half_pixel", "round_prefer_ceil", + ExpectedEPNodeAssignment::All); } // Upsample that uses "round_prefer_floor" as the "nearest_mode". // coordinate_transformation_mode: "align_corners" -TEST_F(QnnCPUBackendTests, DISABLED_TestResizeUpsampleNearestAlignCorners_rpf) { - RunCPUResizeOpTest({1, 2, 7, 5}, {1, 2, 21, 10}, "nearest", "align_corners", "round_prefer_floor", - ExpectedEPNodeAssignment::All, "TestResizeUpsampleNearestAlignCorners_rpf"); +TEST_F(QnnCPUBackendTests, ResizeUpsampleNearestAlignCorners_rpf) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 70); + RunCPUResizeOpTest(TestInputDef({1, 2, 7, 5}, false, input_data), + {1, 2, 21, 10}, "nearest", "align_corners", "round_prefer_floor", + ExpectedEPNodeAssignment::All); +} + +// Upsample that uses "round_prefer_floor" as the "nearest_mode". +// coordinate_transformation_mode: "asymmetric" +TEST_F(QnnCPUBackendTests, ResizeUpsampleNearestAsymmetric_rpf) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 70); + RunCPUResizeOpTest(TestInputDef({1, 2, 7, 5}, false, input_data), + {1, 2, 21, 10}, "nearest", "asymmetric", "round_prefer_floor", + ExpectedEPNodeAssignment::All); } // Upsample that uses "round_prefer_ceil" as the "nearest_mode". // coordinate_transformation_mode: "align_corners" -TEST_F(QnnCPUBackendTests, DISABLED_TestResizeUpsampleNearestAlignCorners_rpc) { - RunCPUResizeOpTest({1, 1, 2, 4}, {1, 1, 7, 5}, "nearest", "align_corners", "round_prefer_ceil", - ExpectedEPNodeAssignment::All, "TestResizeUpsampleNearestAlignCorners_rpc"); +TEST_F(QnnCPUBackendTests, ResizeUpsampleNearestAlignCorners_rpc) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 8); + RunCPUResizeOpTest(TestInputDef({1, 1, 2, 4}, false, input_data), + {1, 1, 7, 5}, "nearest", "align_corners", "round_prefer_ceil", + ExpectedEPNodeAssignment::All); } // Downsample that uses "round_prefer_ceil" as the "nearest_mode". // coordinate_transformation_mode: "align_corners" -TEST_F(QnnCPUBackendTests, DISABLED_TestResizeDownsampleNearestAlignCorners_rpc) { - RunCPUResizeOpTest({1, 1, 2, 4}, {1, 1, 1, 3}, "nearest", "align_corners", "round_prefer_ceil", - ExpectedEPNodeAssignment::All, "TestResizeDownsampleNearestAlignCorners_rpc"); +TEST_F(QnnCPUBackendTests, ResizeDownsampleNearestAlignCorners_rpc) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 8); + RunCPUResizeOpTest(TestInputDef({1, 1, 2, 4}, false, input_data), + {1, 1, 1, 3}, "nearest", "align_corners", "round_prefer_ceil", + ExpectedEPNodeAssignment::All); } // Downsample that uses "round_prefer_floor" as the "nearest_mode". // coordinate_transformation_mode: "align_corners" -TEST_F(QnnCPUBackendTests, DISABLED_TestResizeDownsampleNearestAlignCorners_rpf) { - RunCPUResizeOpTest({1, 1, 2, 4}, {1, 1, 1, 2}, "nearest", "align_corners", "round_prefer_floor", - ExpectedEPNodeAssignment::All, "TestResizeDownsampleNearestAlignCorners_rpf"); +TEST_F(QnnCPUBackendTests, ResizeDownsampleNearestAlignCorners_rpf) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 8); + RunCPUResizeOpTest(TestInputDef({1, 1, 2, 4}, false, input_data), + {1, 1, 1, 2}, "nearest", "align_corners", "round_prefer_floor", + ExpectedEPNodeAssignment::All); } // // Cpu tests that use the "linear" mode. // -TEST_F(QnnCPUBackendTests, TestResize2xLinearHalfPixel) { - RunCPUResizeOpTest({1, 3, 4, 5}, {1, 3, 8, 10}, "linear", "half_pixel", "", - ExpectedEPNodeAssignment::All, "TestResize2xLinearHalfPixel"); +TEST_F(QnnCPUBackendTests, 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, TestResize2xLinearHalfPixel_scales) { - RunCPUResizeOpTestWithScales({1, 3, 4, 5}, {1.0f, 1.0f, 2.0f, 2.0f}, "linear", "half_pixel", "", - ExpectedEPNodeAssignment::All, "TestResize2xLinearHalfPixel_scales"); +TEST_F(QnnCPUBackendTests, 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", "", + ExpectedEPNodeAssignment::All); } -TEST_F(QnnCPUBackendTests, TestResize2xLinearAlignCorners) { - RunCPUResizeOpTest({1, 3, 4, 5}, {1, 3, 8, 10}, "linear", "align_corners", "", - ExpectedEPNodeAssignment::All, "TestResize2xLinearAlignCorners"); +TEST_F(QnnCPUBackendTests, Resize2xLinearAlignCorners) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 60); + RunCPUResizeOpTest(TestInputDef({1, 3, 4, 5}, false, input_data), + {1, 3, 8, 10}, "linear", "align_corners", "", + ExpectedEPNodeAssignment::All); +} + +TEST_F(QnnCPUBackendTests, Resize2xLinearAlignCorners_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", "align_corners", "", + ExpectedEPNodeAssignment::All); +} + +// Test Resize downsample with mode: "linear", coordinate_transformation_mode: "align_corners" +// TODO: Enable ResizeOpTest.ResizeOpLinearDownSampleTest_4DBilinear_align_corners in cpu resize_op tests when fixed. +// +// Input f32[1,1,2,4]: 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0 +// Expected output f32[1, 1, 1, 2]: 1.0, 4.0 +// Actual output f32[1, 1, 1, 2]: NaN, NaN +TEST_F(QnnCPUBackendTests, DISABLED_Resize_DownSample_Linear_AlignCorners_scales) { + std::vector input_data = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f}; + RunCPUResizeOpTestWithScales(TestInputDef({1, 1, 2, 4}, false, input_data), + {1.0f, 1.0f, 0.6f, 0.6f}, "linear", "align_corners", "", + ExpectedEPNodeAssignment::All); } -TEST_F(QnnCPUBackendTests, TestResize2xLinearAlignCorners_scales) { - RunCPUResizeOpTestWithScales({1, 3, 4, 5}, {1.0f, 1.0f, 2.0f, 2.0f}, "linear", "align_corners", "", - ExpectedEPNodeAssignment::All, "TestResize2xLinearAlignCorners_scales"); +// Test Resize downsample with mode: "linear", coordinate_transformation_mode: "half_pixel" +// TODO: Enable ResizeOpTest.ResizeOpLinearDownSampleTest_4DBilinear cpu resize_op tests when fixed. +// +// Input f32[1,1,2,4]: 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0 +// Expected output f32[1, 1, 1, 2]: 2.6666 4.3333 +// Actual output f32[1, 1, 1, 2]: NaN, NaN +TEST_F(QnnCPUBackendTests, DISABLED_Resize_DownSample_Linear_HalfPixel_scales) { + std::vector input_data = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f}; + RunCPUResizeOpTestWithScales(TestInputDef({1, 1, 2, 4}, false, input_data), + {1.0f, 1.0f, 0.6f, 0.6f}, "linear", "half_pixel", "", + ExpectedEPNodeAssignment::All); } #if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) @@ -246,16 +325,121 @@ TEST_F(QnnCPUBackendTests, TestResize2xLinearAlignCorners_scales) { // HTP tests: // -TEST_F(QnnHTPBackendTests, TestQDQU8Resize2xLinearPytorchHalfPixel) { - RunQDQResizeOpTest({1, 3, 4, 4}, {1, 3, 8, 8}, "linear", "pytorch_half_pixel", "", - ExpectedEPNodeAssignment::All, 0.0031f, - "TestQDQU8Resize2xLinearPytorchHalfPixel"); +// Test QDQ Resize downsample with mode: "linear", coordinate_transformation_mode: "align_corners" +TEST_F(QnnHTPBackendTests, Resize_DownSample_Linear_AlignCorners) { + std::vector input_data = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f}; + RunQDQResizeOpTest(TestInputDef({1, 1, 2, 4}, false, input_data), + {1, 1, 1, 2}, "linear", "align_corners", "", + ExpectedEPNodeAssignment::All); +} + +// Test QDQ Resize downsample with mode: "linear", coordinate_transformation_mode: "half_pixel" +TEST_F(QnnHTPBackendTests, Resize_DownSample_Linear_HalfPixel) { + std::vector input_data = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f}; + RunQDQResizeOpTest(TestInputDef({1, 1, 2, 4}, false, input_data), + {1, 1, 1, 2}, "linear", "half_pixel", "", + ExpectedEPNodeAssignment::All); +} + +// Test 2x QDQ Resize mode: "linear", coordinate_transformation_mode: "pytorch_half_pixel" +// QNN EP uses QNN's Resize op. +TEST_F(QnnHTPBackendTests, ResizeU8_2xLinearPytorchHalfPixel) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 48); + RunQDQResizeOpTest(TestInputDef({1, 3, 4, 4}, false, input_data), + {1, 3, 8, 8}, "linear", "pytorch_half_pixel", "", + ExpectedEPNodeAssignment::All); +} + +// Test 2x QDQ Resize mode: "linear", coordinate_transformation_mode: "half_pixel" +// QNN EP uses QNN's Resize op. +TEST_F(QnnHTPBackendTests, ResizeU8_2xLinearHalfPixel) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 48); + RunQDQResizeOpTest(TestInputDef({1, 3, 4, 4}, false, input_data), + {1, 3, 8, 8}, "linear", "half_pixel", "", + ExpectedEPNodeAssignment::All); +} + +// Test 2x QDQ Resize mode: "linear", coordinate_transformation_mode: "align_corners" +// QNN EP uses QNN's Resize op. +TEST_F(QnnHTPBackendTests, ResizeU8_2xLinearAlignCorners) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 48); + RunQDQResizeOpTest(TestInputDef({1, 3, 4, 4}, false, input_data), + {1, 3, 8, 8}, "linear", "align_corners", "", + ExpectedEPNodeAssignment::All); +} + +// Test 2x QDQ Resize mode: "linear", coordinate_transformation_mode: "asymmetric" +// QNN EP uses QNN's Resize op. +TEST_F(QnnHTPBackendTests, ResizeU8_2xLinearAsymmetric) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 48); + RunQDQResizeOpTest(TestInputDef({1, 3, 4, 4}, false, input_data), + {1, 3, 8, 8}, "linear", "asymmetric", "", + ExpectedEPNodeAssignment::All); +} + +// Test 2x QDQ Resize mode: "nearest", coordinate_transformation_mode: "half_pixel", nearest_mode: "round_prefer_floor" +// QNN EP uses QNN's Resize op. +TEST_F(QnnHTPBackendTests, ResizeU8_2xNearestHalfPixelRoundPreferFloor) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 48); + RunQDQResizeOpTest(TestInputDef({1, 3, 4, 4}, false, input_data), + {1, 3, 8, 8}, "nearest", "half_pixel", "round_prefer_floor", + ExpectedEPNodeAssignment::All); +} + +// Test that the nearest_mode "ceil" is not supported on the HTP backend. +TEST_F(QnnHTPBackendTests, ResizeU8_NearestModeCeil_Unsupported) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 48); + RunQDQResizeOpTest(TestInputDef({1, 3, 4, 4}, false, input_data), + {1, 3, 8, 8}, "nearest", "asymmetric", "ceil", + ExpectedEPNodeAssignment::None); +} + +// Test 3x QDQ Resize mode: "nearest", coordinate_transformation_mode: "asymmetric", nearest_mode: "floor". +// QNN EP uses QNN's ResizeNearestNeighbor op. +TEST_F(QnnHTPBackendTests, ResizeU8_3xNearestAsymmetricFloor) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 48); + RunQDQResizeOpTest(TestInputDef({1, 3, 4, 4}, false, input_data), + {1, 3, 12, 12}, "nearest", "asymmetric", "floor", + ExpectedEPNodeAssignment::All); +} + +// Test 2x QDQ Resize mode: "nearest", coordinate_transformation_mode: "asymmetric", nearest_mode: "round_prefer_floor" +// QNN EP uses QNN's Resize op. +TEST_F(QnnHTPBackendTests, ResizeU8_2xNearestAsymmetricRoundPreferFloor) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 8); + RunQDQResizeOpTest(TestInputDef({1, 2, 2, 2}, false, input_data), + {1, 2, 4, 4}, "nearest", "asymmetric", "round_prefer_floor", + ExpectedEPNodeAssignment::All); +} + +// Test 3x QDQ Resize mode: "nearest", coordinate_transformation_mode: "asymmetric", nearest_mode: "round_prefer_floor" +// QNN EP uses QNN's Resize op. +// +// TODO: Inaccuracy detected for output 'output_0', element 2. +// Output quant params: scale=0.078431375324726105, zero_point=127. +// Expected val: -3.3333334922790527 +// QNN QDQ val: -9.960784912109375 (err 6.6274514198303223) +// CPU QDQ val: -3.2941176891326904 (err 0.039215803146362305) +// +// More debugging info: +// Input elements f32[1,1,2,2] = -10.0000000 -3.33333349 3.33333302 10.0000000 +// 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) { + 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); } -TEST_F(QnnHTPBackendTests, TestQDQU8Resize2xNearestHalfPixelRoundPreferFloor) { - RunQDQResizeOpTest({1, 3, 4, 4}, {1, 3, 8, 8}, "nearest", "half_pixel", "round_prefer_floor", - ExpectedEPNodeAssignment::All, 1e-5f, - "TestQDQU8Resize2xNearestHalfPixelRoundPreferFloor"); +// Test 0.5x QDQ Resize mode: "nearest", coordinate_transformation_mode: "asymmetric", nearest_mode: "floor" +// QNN EP uses QNN's ResizeNearestNeighbor op. +TEST_F(QnnHTPBackendTests, ResizeU8_HalfNearestAsymmetricFloor) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 48); + RunQDQResizeOpTest(TestInputDef({1, 3, 4, 4}, false, input_data), + {1, 3, 2, 2}, "nearest", "asymmetric", "floor", + ExpectedEPNodeAssignment::All); } #endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) diff --git a/onnxruntime/test/providers/qnn/simple_op_htp_test.cc b/onnxruntime/test/providers/qnn/simple_op_htp_test.cc index 96b340295ba7f..f77c098f72116 100644 --- a/onnxruntime/test/providers/qnn/simple_op_htp_test.cc +++ b/onnxruntime/test/providers/qnn/simple_op_htp_test.cc @@ -4,7 +4,10 @@ #if !defined(ORT_MINIMAL_BUILD) #include +#include +#include #include "core/graph/graph.h" +#include "core/graph/node_attr_utils.h" #include "test/optimizer/qdq_test_utils.h" #include "test/providers/qnn/qnn_test_utils.h" @@ -13,54 +16,119 @@ namespace onnxruntime { namespace test { -#if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) -// Creates the graph: -// _______________________ -// | | -// input_u8 -> DQ -> | SimpleOp | -> Q -> output_u8 -// |_______________________| +// Runs a non-QDQ model on the QNN CPU backend and compares output to CPU EP. +template +static void RunOpTestOnCPU(const std::string& op_type, + const std::vector>& input_defs, + const std::vector& attrs, + int opset_version, + 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 + + RunQnnModelTest(BuildOpTestCase(op_type, input_defs, {}, attrs, op_domain), + provider_options, + opset_version, + expected_ep_assignment); +} + +// Test float DepthToSpace on the QNN CPU backend. +// TODO: Flaky test tails often. +// Value of: expected_tensor.DataAsSpan() +// Expected: contains 16 values, where each value and its corresponding value in 16-byte object +// <10-00 00-00 00-00 00-00 40-00 23-D1 82-02 00-00> are an almost-equal pair +// Actual: 16-byte object <10-00 00-00 00-00 00-00 40-00 12-D1 82-02 00-00>, where the value pair (2, 0.1) at +// index #2 don't match, which is -1.9 from 2 // -// Currently used to test QNN EP. -template -GetQDQTestCaseFn BuildQDQSingleInputOpTestCase(const std::vector& input_shape, - const std::string& op_type, - const std::string& domain = kOnnxDomain) { - return [input_shape, op_type, domain](ModelTestBuilder& builder) { - const InputQType quant_zero_point = 0; - const float quant_scale = 1.0f; - - auto* input = builder.MakeInput(input_shape, std::numeric_limits::min(), - std::numeric_limits::max()); - auto* dq_input = builder.MakeIntermediate(); - builder.AddDequantizeLinearNode(input, quant_scale, quant_zero_point, dq_input); +// If/when fixed, enable QNN EP in cpu test TensorOpTest.SpaceToDepthTest_1 +TEST_F(QnnCPUBackendTests, DISABLED_SpaceToDepth_Flaky) { + std::vector X = + {0.0f, 0.1f, 0.2f, 0.3f, + 1.0f, 1.1f, 1.2f, 1.3f, - auto* op_output = builder.MakeIntermediate(); - builder.AddNode(op_type, {dq_input}, {op_output}, domain); + 2.0f, 2.1f, 2.2f, 2.3f, + 3.0f, 3.1f, 3.2f, 3.3f}; - auto* q_output = builder.MakeIntermediate(); - builder.AddQuantizeLinearNode(op_output, quant_scale, quant_zero_point, q_output); + for (size_t i = 0; i < 4; i++) { + RunOpTestOnCPU("SpaceToDepth", + {TestInputDef({1, 2, 2, 4}, false, X)}, + {utils::MakeAttribute("blocksize", static_cast(2))}, + 7, + ExpectedEPNodeAssignment::All); + } +} - auto* final_output = builder.MakeOutput(); - builder.AddDequantizeLinearNode(q_output, quant_scale, quant_zero_point, final_output); - }; +// Value of: expected_tensor.DataAsSpan() +// Expected: contains 108 values, where each value and its corresponding value in 16-byte object +// <6C-00 00-00 00-00 00-00 40-00 23-BB 0E-02 00-00> are an almost-equal pair +// Actual: 16-byte object <6C-00 00-00 00-00 00-00 40-00 12-BB 0E-02 00-00>, where the value pair (18, 1) +// 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) { + 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., + 22., 23., 24., 25., 26., 27., 28., 29., 30., 31., 32., + 33., 34., 35., 36., 37., 38., 39., 40., 41., 42., 43., + 44., 45., 46., 47., 48., 49., 50., 51., 52., 53., 54., + 55., 56., 57., 58., 59., 60., 61., 62., 63., 64., 65., + 66., 67., 68., 69., 70., 71., 72., 73., 74., 75., 76., + 77., 78., 79., 80., 81., 82., 83., 84., 85., 86., 87., + 88., 89., 90., 91., 92., 93., 94., 95., 96., 97., 98., + 99., 100., 101., 102., 103., 104., 105., 106., 107.}; + + for (size_t i = 0; i < 4; i++) { + RunOpTestOnCPU("SpaceToDepth", + {TestInputDef({2, 3, 3, 6}, false, X)}, + {utils::MakeAttribute("blocksize", static_cast(3))}, + 7, + ExpectedEPNodeAssignment::All); + } +} + +#if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) + +// Tests the accuracy of a QDQ model on QNN EP by comparing to CPU EP, which runs both the fp32 model +// and the QDQ model. +template +static void RunQDQOpTest(const std::string& op_type, + const std::vector>& input_defs, + const std::vector& attrs, + int opset_version, + ExpectedEPNodeAssignment expected_ep_assignment, + const std::string& op_domain = kOnnxDomain, + bool use_contrib_qdq = false, + float fp32_abs_err = 1e-4f) { + ProviderOptions provider_options; +#if defined(_WIN32) + provider_options["backend_path"] = "QnnHtp.dll"; +#else + provider_options["backend_path"] = "libQnnHtp.so"; +#endif + + TestQDQModelAccuracy(BuildOpTestCase(op_type, input_defs, {}, attrs, op_domain), + BuildQDQOpTestCase(op_type, input_defs, {}, attrs, op_domain, use_contrib_qdq), + provider_options, + opset_version, + expected_ep_assignment, + fp32_abs_err); } -/** - * Runs an Simple Op model on the QNN HTP backend. Checks the graph node assignment, and that inference - * outputs for QNN and CPU match. - * - * \param input_shape The input's shape. - * \param test_description Description of the test for error reporting. - * \param expected_ep_assignment How many nodes are expected to be assigned to QNN (All, Some, or None). - * \param num_modes_in_graph The number of expected nodes in the graph. - */ -static void RunQDQSingleInputOpTest(const std::vector& input_shape, const std::string& op_type, - const char* test_description, - int opset_version, - ExpectedEPNodeAssignment expected_ep_assignment, - int num_nodes_in_graph, - const std::string& domain = kOnnxDomain) { +// Runs a non-QDQ model on HTP and compares output to CPU EP. +template +static void RunOpTest(const std::string& op_type, + const std::vector>& input_defs, + const std::vector& attrs, + int opset_version, + ExpectedEPNodeAssignment expected_ep_assignment, + const std::string& op_domain = kOnnxDomain) { ProviderOptions provider_options; #if defined(_WIN32) provider_options["backend_path"] = "QnnHtp.dll"; @@ -68,42 +136,953 @@ static void RunQDQSingleInputOpTest(const std::vector& input_shape, con provider_options["backend_path"] = "libQnnHtp.so"; #endif - // Runs model with DQ-> InstanceNorm -> Q and compares the outputs of the CPU and QNN EPs. - RunQnnModelTest(BuildQDQSingleInputOpTestCase(input_shape, op_type, domain), + // Runs model with a Q/DQ binary op and compares the outputs of the CPU and QNN EPs. + RunQnnModelTest(BuildOpTestCase(op_type, input_defs, {}, attrs, op_domain), provider_options, opset_version, - expected_ep_assignment, - num_nodes_in_graph, - test_description); + expected_ep_assignment); +} + +// Test the accuracy of QDQ Sigmoid. +TEST_F(QnnHTPBackendTests, UnaryOp_Sigmoid) { + RunQDQOpTest("Sigmoid", + {TestInputDef({1, 2, 3}, false, GetFloatDataInRange(-10.0f, 10.0f, 6))}, + {}, + 13, + ExpectedEPNodeAssignment::All); +} + +// Tests accuracy of 16-bit QDQ Sigmoid. +TEST_F(QnnHTPBackendTests, UnaryOp_Sigmoid_U16) { + RunQDQOpTest("Sigmoid", + {TestInputDef({1, 2, 3}, false, GetFloatDataInRange(-10.0f, 10.0f, 6))}, + {}, + 13, + ExpectedEPNodeAssignment::All, + kOnnxDomain, + true); // Use MS domain Q/DQ ops +} + +// Test the accuracy of QDQ Tanh. +TEST_F(QnnHTPBackendTests, UnaryOp_Tanh) { + RunQDQOpTest("Tanh", + {TestInputDef({1, 2, 3}, false, GetFloatDataInRange(-10.0f, 10.0f, 6))}, + {}, + 13, + ExpectedEPNodeAssignment::All); +} + +// Tests accuracy of 16-bit QDQ Tanh. +TEST_F(QnnHTPBackendTests, UnaryOp_Tanh_U16) { + RunQDQOpTest("Tanh", + {TestInputDef({1, 2, 3}, false, GetFloatDataInRange(-10.0f, 10.0f, 6))}, + {}, + 13, + ExpectedEPNodeAssignment::All, + kOnnxDomain, + true); // Use MS domain Q/DQ ops } // Check that QNN compiles DQ -> Gelu -> Q as a single unit. // Use an input of rank 3. -TEST_F(QnnHTPBackendTests, TestQDQGeluTest) { - RunQDQSingleInputOpTest({1, 2, 3}, "Gelu", "TestQDQGeluTest", 11, ExpectedEPNodeAssignment::All, 1, kMSDomain); +TEST_F(QnnHTPBackendTests, UnaryOp_Gelu) { + RunQDQOpTest("Gelu", + {TestInputDef({1, 2, 3}, false, GetFloatDataInRange(-10.0f, 10.0f, 6))}, + {}, + 11, + ExpectedEPNodeAssignment::All, + kMSDomain); // GeLu is a contrib op. +} + +// Tests accuracy of 16-bit QDQ GeLu. +// TODO(adrianlizarraga): Inaccuracy detected for output 'output', element 5. +// Output quant params: scale=0.00015259021893143654, zero_point=0. +// Expected val: 10 +// QNN QDQ val: 9.997406005859375 (err 0.002593994140625) +// CPU QDQ val: 9.999847412109375 (err 0.000152587890625) +TEST_F(QnnHTPBackendTests, UnaryOp_Gelu_U16) { + const std::vector input_data = {-10.0f, -8.4f, 0.0f, 4.3f, 7.1f, 10.0f}; + RunQDQOpTest("Gelu", + {TestInputDef({1, 2, 3}, false, input_data)}, + {}, + 11, + ExpectedEPNodeAssignment::All, + kMSDomain, // GeLu is a contrib op. + true, // Use MS domain Q/DQ ops. + 0.0025f); // TODO(adrianlizarraga): Accuracy } // Check that QNN compiles DQ -> Elu -> Q as a single unit. // Use an input of rank 3. -TEST_F(QnnHTPBackendTests, TestQDQEluTest) { - RunQDQSingleInputOpTest({1, 2, 3}, "Elu", "TestQDQGeluTest", 11, ExpectedEPNodeAssignment::All, 1); +TEST_F(QnnHTPBackendTests, UnaryOp_Elu) { + RunQDQOpTest("Elu", + {TestInputDef({1, 2, 3}, false, GetFloatDataInRange(-10.0f, 10.0f, 6))}, + {}, + 11, + ExpectedEPNodeAssignment::All); +} + +// Tests accuracy of 16-bit QDQ Elu. +// TODO(adrianlizarraga): Re-enable. This works on QNN SDK 2.14.1! +// Inaccuracy detected for output 'output', element 1. +// Output quant params: scale=0.00011093531065853313, zero_point=8992. +// 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) { + RunQDQOpTest("Elu", + {TestInputDef({1, 2, 3}, false, GetFloatDataInRange(-10.0f, 10.0f, 6))}, + {}, + 11, + ExpectedEPNodeAssignment::All, + kOnnxDomain, + true); +} + +// Tests accuracy of QDQ Relu +// TODO: Relu does not set negative values to zero! +// Could be due to ORT's ReluQuantFusion! +// +// Inaccuracy detected for output 'output', element 0. +// Output quant params: scale=0.039215687662363052, zero_point=0. +// Expected val: 0 +// QNN QDQ val: -10 (err 10) +// CPU QDQ val: 0 (err 0) +TEST_F(QnnHTPBackendTests, DISABLED_UnaryOp_Relu) { + RunQDQOpTest("Relu", + {TestInputDef({1, 2, 3}, false, GetFloatDataInRange(-10.0f, 10.0f, 6))}, + {}, + 14, + ExpectedEPNodeAssignment::All); } // Check that QNN compiles DQ -> HardSwish -> Q as a single unit. // Use an input of rank 3. -TEST_F(QnnHTPBackendTests, TestQDQHardSwishTest) { - RunQDQSingleInputOpTest({1, 2, 3}, "HardSwish", "TestQDQGeluTest", 14, ExpectedEPNodeAssignment::All, 1); +TEST_F(QnnHTPBackendTests, UnaryOp_HardSwish) { + RunQDQOpTest("HardSwish", + {TestInputDef({1, 2, 3}, false, GetFloatDataInRange(-10.0f, 10.0f, 6))}, + {}, + 14, + ExpectedEPNodeAssignment::All); } -// Check that QNN compiles DQ -> HardSwish -> Q as a single unit. +// Tests accuracy of 16-bit QDQ HardSwish +// TODO(adrianlizarraga): Inaccuracy detected for output 'output', element 5. +// Output quant params: scale=0.00015259021893143654, zero_point=0. +// Expected val: 10 +// QNN QDQ val: 9.999237060546875 (err 0.000762939453125) +// CPU QDQ val: 9.999847412109375 (err 0.000152587890625) +TEST_F(QnnHTPBackendTests, UnaryOp_HardSwish_U16) { + const std::vector input_data = {-10.0f, -8.4f, 0.0f, 4.3f, 7.1f, 10.0f}; + RunQDQOpTest("HardSwish", + {TestInputDef({1, 2, 3}, false, input_data)}, + {}, + 14, + ExpectedEPNodeAssignment::All, + kOnnxDomain, + true, + 0.001f); // TODO(adrianlizarraga): Remove additional tolerance needed for inaccuracy +} + +// Check that QNN compiles DQ -> Atan -> Q as a single unit. +// Use an input of rank 3. +TEST_F(QnnHTPBackendTests, UnaryOp_Atan) { + RunQDQOpTest("Atan", + {TestInputDef({1, 2, 3}, false, GetFloatDataInRange(-10.0f, 10.0f, 6))}, + {}, + 14, + ExpectedEPNodeAssignment::All); +} + +// Tests accuracy of 16-bit QDQ Atan +// TODO(adrianlizarraga): Inaccuracy detected for output 'output', element 1. +// Output quant params: scale=4.4895936298416927e-05, zero_point=32768. +// Expected val: -1.4219063520431519 +// QNN QDQ val: -1.4220787286758423 (err 0.00017237663269042969) +// CPU QDQ val: -1.4218991994857788 (err 7.152557373046875e-06) +TEST_F(QnnHTPBackendTests, UnaryOp_Atan_U16) { + const std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 6); + RunQDQOpTest("Atan", + {TestInputDef({1, 2, 3}, false, input_data)}, + {}, + 14, + ExpectedEPNodeAssignment::All, + kOnnxDomain, // Atan domain + true, // Q/DQ op domain is com.microsoft + 1.8e-4f); +} + +// Check that QNN compiles DQ -> Asin -> Q as a single unit. +// Use an input of rank 3. +TEST_F(QnnHTPBackendTests, UnaryOp_Asin) { + RunQDQOpTest("Asin", + {TestInputDef({1, 2, 3}, false, GetFloatDataInRange(-0.5, 0.5, 6))}, + {}, + 13, + ExpectedEPNodeAssignment::All); +} + +// Check that QNN compiles DQ -> Sign -> Q as a single unit. +// Use an input of rank 3. +TEST_F(QnnHTPBackendTests, UnaryOp_Sign) { + RunQDQOpTest("Sign", + {TestInputDef({1, 2, 3}, false, GetFloatDataInRange(-10.0f, 10.0f, 6))}, + {}, + 13, + ExpectedEPNodeAssignment::All); +} + +// Tests accuracy of 16-bit QDQ Sign +TEST_F(QnnHTPBackendTests, UnaryOp_Sign_U16) { + const std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 6); + RunQDQOpTest("Sign", + {TestInputDef({1, 2, 3}, false, input_data)}, + {}, + 13, + ExpectedEPNodeAssignment::All, + kOnnxDomain, // Sign op domain + true); // Use com.microsoft Q/DQ op domains +} + +// Check that QNN compiles DQ -> Sin -> Q as a single unit. +// Use an input of rank 3. +TEST_F(QnnHTPBackendTests, UnaryOp_Sin) { + RunQDQOpTest("Sin", + {TestInputDef({1, 2, 3}, false, -3.14159f, 3.14159f)}, + {}, + 11, + ExpectedEPNodeAssignment::All); +} + +// Check that QNN compiles DQ -> Cos -> Q as a single unit. +// Use an input of rank 3. +TEST_F(QnnHTPBackendTests, UnaryOp_Cos) { + RunQDQOpTest("Cos", + {TestInputDef({1, 2, 3}, false, {-3.14159f, -1.5f, -0.5f, 0.0f, 1.5, 3.14159f})}, + {}, + 11, + ExpectedEPNodeAssignment::All); +} + +// Check that QNN compiles DQ -> Cos -> Q as a single unit. +// Use an input of rank 3. +TEST_F(QnnHTPBackendTests, UnaryOp_Cos_InaccurateFixed) { + RunQDQOpTest("Cos", + {TestInputDef({1, 2, 3}, false, {-3.14159f, -1.88436f, -0.542863f, 0.0f, 1.05622f, 3.14159f})}, + {}, + 11, + ExpectedEPNodeAssignment::All); +} + +// Check that QNN compiles DQ -> Log -> Q as a single unit. // Use an input of rank 3. -TEST_F(QnnHTPBackendTests, TestQDQAtanTest) { - RunQDQSingleInputOpTest({1, 2, 3}, "Atan", "TestQDQGeluTest", 11, ExpectedEPNodeAssignment::All, 1); +TEST_F(QnnHTPBackendTests, UnaryOp_Log) { + RunQDQOpTest("Log", + {TestInputDef({1, 2, 3}, false, {3.14159f, 100.88436f, 10.542863f, 9.1f, 1.05622f, 3.14159f})}, + {}, + 11, ExpectedEPNodeAssignment::All); +} + +// Test accuracy of 8-bit QDQ Exp +TEST_F(QnnHTPBackendTests, UnaryOp_Exp) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 6); + RunQDQOpTest("Exp", + {TestInputDef({1, 2, 3}, false, input_data)}, + {}, + 13, + ExpectedEPNodeAssignment::All); +} + +// Test accuracy of 8-bit QDQ Sqrt +TEST_F(QnnHTPBackendTests, UnaryOp_Sqrt) { + std::vector input_data = GetFloatDataInRange(0.0f, 20.0f, 9); + RunQDQOpTest("Sqrt", + {TestInputDef({1, 3, 3}, false, input_data)}, + {}, + 13, + ExpectedEPNodeAssignment::All); +} + +// Test accuracy of 8-bit QDQ Neg +TEST_F(QnnHTPBackendTests, UnaryOp_Neg) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 6); + RunQDQOpTest("Neg", + {TestInputDef({1, 2, 3}, false, input_data)}, + {}, + 13, + ExpectedEPNodeAssignment::All); +} + +// Test Not operator on HTP backend. +TEST_F(QnnHTPBackendTests, UnaryOp_Not) { + RunOpTest("Not", + {TestInputDef({1, 4}, false, {false, false, true, true})}, + {}, + 17, + ExpectedEPNodeAssignment::All); +} + +// Test accuracy of 8-bit QDQ Round +TEST_F(QnnHTPBackendTests, UnaryOp_Round) { + std::vector input_data = GetFloatDataInRange(-9.0f, 9.0f, 6); + RunQDQOpTest("Round", + {TestInputDef({1, 2, 3}, false, input_data)}, + {}, + 11, + ExpectedEPNodeAssignment::All); +} + +// Tests accuracy of 16-bit QDQ Log +TEST_F(QnnHTPBackendTests, UnaryOp_Log_U16) { + const std::vector input_data = GetFloatDataInRange(1.0f, 128.0f, 6); + RunQDQOpTest("Log", + {TestInputDef({1, 2, 3}, false, input_data)}, + {}, + 11, + ExpectedEPNodeAssignment::All, + kOnnxDomain, // Log op domain + true); // Use com.microsoft domain for Q/DQ ops +} + +// Check that QNN compiles DQ -> Softmax -> Q as a single unit. +// Test that the default axis (-1) for SoftMax opset 13 works. +TEST_F(QnnHTPBackendTests, UnaryOp_Softmax13_DefaultAxis) { + RunQDQOpTest("Softmax", + {TestInputDef({1, 2, 3}, false, -5.0f, 5.0f)}, + {}, // Uses default axis of -1 for opset 13 + 13, + ExpectedEPNodeAssignment::All); +} + +// Tests accuracy of 16-bit QDQ Softmax (opset 13) with default axis +TEST_F(QnnHTPBackendTests, UnaryOp_Softmax13_U16_DefaultAxis) { + const std::vector input_data = GetFloatDataInRange(-5.0f, 5.0f, 6); + RunQDQOpTest("Softmax", + {TestInputDef({1, 2, 3}, false, input_data)}, + {}, // Uses default axis of -1 for opset 13 + 13, + ExpectedEPNodeAssignment::All, + kOnnxDomain, // Sofmax's domain + true); // Use com.microsoft domain for Q/DQ ops +} + +// Check that QNN compiles DQ -> Softmax -> Q as a single unit. +// Test that an axis != -1 is not supported. +TEST_F(QnnHTPBackendTests, UnaryOp_Softmax13_UnsupportedAxis) { + RunQDQOpTest("Softmax", + {TestInputDef({1, 2, 3}, false, -5.0f, 5.0f)}, + {utils::MakeAttribute("axis", static_cast(1))}, + 13, + ExpectedEPNodeAssignment::None); +} + +// 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) { + RunQDQOpTest("Softmax", + {TestInputDef({1, 2, 3}, false, -5.0f, 5.0f)}, + {}, // Uses default axis of 1 for opset < 13. + 11, + ExpectedEPNodeAssignment::None); +} + +// 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) { + RunQDQOpTest("Softmax", + {TestInputDef({1, 2, 3}, false, -5.0f, 5.0f)}, + {utils::MakeAttribute("axis", static_cast(-1))}, + 11, + ExpectedEPNodeAssignment::All); +} + +// Check that QNN compiles DQ -> LogSoftmax -> Q as a single unit. +// Test that the default axis (-1) for LogSoftmax opset 13 works. +TEST_F(QnnHTPBackendTests, UnaryOp_LogSoftmax13_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 + 13, + ExpectedEPNodeAssignment::All); +} + +// Check that QNN compiles DQ -> LogSoftmax -> Q as a single unit. +// Test that an axis != -1 is not supported. +TEST_F(QnnHTPBackendTests, UnaryOp_LogSoftmax13_UnsupportedAxis) { + std::vector input_data = GetFloatDataInRange(-5.0f, 5.0f, 6); + RunQDQOpTest("LogSoftmax", + {TestInputDef({1, 2, 3}, false, input_data)}, + {utils::MakeAttribute("axis", static_cast(1))}, + 13, + ExpectedEPNodeAssignment::None); +} + +// 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) { + 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); +} + +// 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) { + std::vector input_data = GetFloatDataInRange(-5.0f, 5.0f, 6); + RunQDQOpTest("LogSoftmax", + {TestInputDef({1, 2, 3}, false, input_data)}, + {utils::MakeAttribute("axis", static_cast(-1))}, + 11, + ExpectedEPNodeAssignment::All); +} + +// Test accuracy of QDQ Abs op. +TEST_F(QnnHTPBackendTests, UnaryOp_Abs) { + RunQDQOpTest("Abs", + {TestInputDef({1, 2, 3}, false, GetFloatDataInRange(-10.0f, 10.0f, 6))}, + {}, + 13, + ExpectedEPNodeAssignment::All); +} + +// Test accuracy of 16-bit QDQ Abs op. +TEST_F(QnnHTPBackendTests, UnaryOp_Abs_U16) { + const std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 6); + RunQDQOpTest("Abs", + {TestInputDef({1, 2, 3}, false, input_data)}, + {}, + 13, + ExpectedEPNodeAssignment::All, + kOnnxDomain, // Abs op's domain + true); // Use com.microsoft domain for Q/DQ ops +} + +// Test accuracy of QDQ Ceil op. +TEST_F(QnnHTPBackendTests, UnaryOp_Ceil) { + const std::vector input_data = GetFloatDataInRange(-12.0f, 12.0f, 6); + RunQDQOpTest("Ceil", + {TestInputDef({1, 2, 3}, false, input_data)}, + {}, + 13, + ExpectedEPNodeAssignment::All); } +// Test accuracy of 16-bit QDQ Ceil op. +TEST_F(QnnHTPBackendTests, UnaryOp_Ceil_U16) { + const std::vector input_data = GetFloatDataInRange(-12.0f, 12.0f, 6); + RunQDQOpTest("Ceil", + {TestInputDef({1, 2, 3}, false, input_data)}, + {}, + 13, + ExpectedEPNodeAssignment::All, + kOnnxDomain, // Ceil op's domain + true); // Use com.microsoft domain for Q/DQ ops +} + +// Test QDQ Floor op. +TEST_F(QnnHTPBackendTests, UnaryOp_Floor) { + const std::vector input_data = GetFloatDataInRange(-12.0f, 12.0f, 6); + RunQDQOpTest("Floor", + {TestInputDef({1, 2, 3}, false, input_data)}, + {}, + 13, + ExpectedEPNodeAssignment::All); +} + +// Test QDQ DepthToSpace. +TEST_F(QnnHTPBackendTests, DepthToSpaceOp_CRD) { + const std::vector X = {0., 1., 2., + 3., 4., 5., + 9., 10., 11., + 12., 13., 14., + 18., 19., 20., + 21., 22., 23., + 27., 28., 29., + 30., 31., 32.}; + RunQDQOpTest("DepthToSpace", + {TestInputDef({1, 4, 2, 3}, false, X)}, + {utils::MakeAttribute("blocksize", static_cast(2)), + utils::MakeAttribute("mode", "CRD")}, + 11, + ExpectedEPNodeAssignment::All); +} + +// Test 16-bit QDQ DepthToSpace. +TEST_F(QnnHTPBackendTests, DepthToSpaceOp_U16_CRD) { + const std::vector X = {0., 1., 2., + 3., 4., 5., + 9., 10., 11., + 12., 13., 14., + 18., 19., 20., + 21., 22., 23., + 27., 28., 29., + 30., 31., 32.}; + RunQDQOpTest("DepthToSpace", + {TestInputDef({1, 4, 2, 3}, false, X)}, + {utils::MakeAttribute("blocksize", static_cast(2)), + utils::MakeAttribute("mode", "CRD")}, + 11, + ExpectedEPNodeAssignment::All, + kOnnxDomain, // Op's domain + true); // Use com.microsoft domain for Q/DQ ops +} + +// Test QDQ DepthToSpace. +TEST_F(QnnHTPBackendTests, DepthToSpaceOp_DCR) { + const std::vector X = {0., 1., 2., + 3., 4., 5., + 9., 10., 11., + 12., 13., 14., + 18., 19., 20., + 21., 22., 23., + 27., 28., 29., + 30., 31., 32.}; + RunQDQOpTest("DepthToSpace", + {TestInputDef({1, 4, 2, 3}, false, X)}, + {utils::MakeAttribute("blocksize", static_cast(2)), + utils::MakeAttribute("mode", "DCR")}, + 11, + ExpectedEPNodeAssignment::All); +} + +// Test QDQ SpaceToDepth. +TEST_F(QnnHTPBackendTests, SpaceToDepthOp) { + const std::vector X = {0.0f, 0.1f, 0.2f, 0.3f, + 1.0f, 1.1f, 1.2f, 1.3f, + + 2.0f, 2.1f, 2.2f, 2.3f, + 3.0f, 3.1f, 3.2f, 3.3f}; + RunQDQOpTest("SpaceToDepth", + {TestInputDef({1, 2, 2, 4}, false, X)}, + {utils::MakeAttribute("blocksize", static_cast(2))}, + 11, + ExpectedEPNodeAssignment::All); +} + +// Test 16-bit QDQ SpaceToDepth. +TEST_F(QnnHTPBackendTests, SpaceToDepthOp_U16) { + const std::vector X = {0.0f, 0.1f, 0.2f, 0.3f, + 1.0f, 1.1f, 1.2f, 1.3f, + + 2.0f, 2.1f, 2.2f, 2.3f, + 3.0f, 3.1f, 3.2f, 3.3f}; + RunQDQOpTest("SpaceToDepth", + {TestInputDef({1, 2, 2, 4}, false, X)}, + {utils::MakeAttribute("blocksize", static_cast(2))}, + 11, + ExpectedEPNodeAssignment::All, + kOnnxDomain, // Op's domain + true); // Use com.microsoft domain for Q/DQ ops +} + +// Run QDQ model on HTP twice +// 1st run will generate the Qnn context cache binary file +// 2nd run will load and run from Qnn context cache binary file +TEST_F(QnnHTPBackendTests, ContextBinaryCacheTest) { + ProviderOptions provider_options; +#if defined(_WIN32) + provider_options["backend_path"] = "QnnHtp.dll"; +#else + provider_options["backend_path"] = "libQnnHtp.so"; +#endif + provider_options["qnn_context_cache_enable"] = "1"; + const std::string context_binary_file = "./qnn_context_binary_test.bin"; + provider_options["qnn_context_cache_path"] = context_binary_file; + + const TestInputDef input_def({1, 2, 3}, false, -10.0f, 10.0f); + const std::string op_type = "Atan"; + + // Runs model with DQ-> Atan-> Q and compares the outputs of the CPU and QNN EPs. + // 1st run will generate the Qnn context cache binary file + TestQDQModelAccuracy(BuildOpTestCase(op_type, {input_def}, {}, {}), + BuildQDQOpTestCase(op_type, {input_def}, {}, {}), + provider_options, + 14, + ExpectedEPNodeAssignment::All); + + // Make sure the Qnn context cache binary file is generated + EXPECT_TRUE(std::filesystem::exists(context_binary_file.c_str())); + + // 2nd run will load and run from Qnn context cache binary file + TestQDQModelAccuracy(BuildOpTestCase(op_type, {input_def}, {}, {}), + BuildQDQOpTestCase(op_type, {input_def}, {}, {}), + provider_options, + 14, + ExpectedEPNodeAssignment::All); +} + +TEST_F(QnnHTPBackendTests, QuantAccuracyTest) { + ProviderOptions provider_options; + +#if defined(_WIN32) + provider_options["backend_path"] = "QnnHtp.dll"; +#else + provider_options["backend_path"] = "libQnnHtp.so"; +#endif + + // Note: a graph input -> Q -> DQ -> is optimized by Qnn to have a perfectly accurate output. + // ORT's CPU EP, on the otherhand, actually quantizes and dequantizes the input, which leads to different outputs. + auto builder_func = [](ModelTestBuilder& builder) { + const TestInputDef input0_def({1, 2, 3}, false, {1.0f, 2.0f, 10.0f, 20.0f, 100.0f, 200.0f}); + + // input -> Q -> Transpose -> DQ -> output + NodeArg* input0 = MakeTestInput(builder, input0_def); + QuantParams qparams = GetTestInputQuantParams(input0_def); + + auto* quant_input = builder.MakeIntermediate(); + builder.AddQuantizeLinearNode(input0, qparams.scale, qparams.zero_point, quant_input); + + auto* op_output = builder.MakeIntermediate(); + builder.AddNode("Transpose", {quant_input}, {op_output}); + + NodeArg* output = builder.MakeOutput(); + builder.AddDequantizeLinearNode(op_output, qparams.scale, qparams.zero_point, output); + }; + + // Runs model with DQ-> Atan-> Q and compares the outputs of the CPU and QNN EPs. + // 1st run will generate the Qnn context cache binary file + RunQnnModelTest(builder_func, + provider_options, + 13, + ExpectedEPNodeAssignment::All); +} + +// Test 8-bit QDQ Add +TEST_F(QnnHTPBackendTests, BinaryOp_Add4D) { + RunQDQOpTest("Add", + {TestInputDef({1, 2, 2, 2}, false, -10.0f, 10.0f), + TestInputDef({1, 2, 2, 2}, false, -10.0f, 10.0f)}, + {}, + 17, + ExpectedEPNodeAssignment::All); +} + +// Test 16-bit QDQ Add +TEST_F(QnnHTPBackendTests, BinaryOp_Add4D_U16) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 8); + RunQDQOpTest("Add", + {TestInputDef({1, 2, 2, 2}, false, input_data), + TestInputDef({1, 2, 2, 2}, false, input_data)}, + {}, + 17, + ExpectedEPNodeAssignment::All, + kOnnxDomain, + true); // Use com.microsoft Q/DQ ops +} + +// Test 8-bit QDQ Sub +TEST_F(QnnHTPBackendTests, BinaryOp_Sub4D) { + RunQDQOpTest("Sub", + {TestInputDef({1, 3, 8, 8}, false, -10.0f, 10.0f), + TestInputDef({1, 3, 8, 8}, false, -10.0f, 10.0f)}, + {}, + 17, + ExpectedEPNodeAssignment::All); +} + +// Test 16-bit QDQ Sub +TEST_F(QnnHTPBackendTests, BinaryOp_Sub4D_U16) { + std::vector input0_data = GetFloatDataInRange(-10.0f, 10.0f, 8); + std::vector input1_data = GetFloatDataInRange(0.0f, 20.0f, 8); + RunQDQOpTest("Sub", + {TestInputDef({1, 2, 2, 2}, false, input0_data), + TestInputDef({1, 2, 2, 2}, false, input1_data)}, + {}, + 17, + ExpectedEPNodeAssignment::All, + kOnnxDomain, + true); // Use com.microsoft Q/DQ ops +} + +TEST_F(QnnHTPBackendTests, BinaryOp_Sub4D_LargeInputs) { + RunQDQOpTest("Sub", + {TestInputDef({1, 3, 768, 1152}, false, -1.0f, 1.0f), + TestInputDef({1, 3, 768, 1152}, false, -1.0f, 1.0f)}, + {}, + 17, + ExpectedEPNodeAssignment::All); +} + +TEST_F(QnnHTPBackendTests, BinaryOp_Sub4D_Broadcast) { + RunQDQOpTest("Sub", + {TestInputDef({1, 3, 768, 1152}, false, -1.0f, 1.0f), + TestInputDef({3, 1, 1}, true, {1.0f, 0.5f, -0.3f})}, + {}, + 17, + ExpectedEPNodeAssignment::All); +} + +// Test accuracy of QDQ Pow +#if defined(__linux__) +// TODO: This fails on Linux (HTP emulation). Works on Windows ARM64. +// Inaccuracy detected for output 'output', element 0. +// Output quant params: scale=0.051073111593723297, zero_point=2. +// Expected val: 0.0099999997764825821 +// QNN QDQ val: 12.921497344970703 (err 12.911497116088867) +// CPU QDQ val: -0.10214622318744659 (err 0.11214622110128403) +TEST_F(QnnHTPBackendTests, DISABLED_BinaryOp_Pow) { +#else +TEST_F(QnnHTPBackendTests, BinaryOp_Pow) { +#endif + std::vector bases_input = {-10.0f, -8.0f, -6.0f, 1.0f, 2.0f, 3.0f, 5.5f, 10.0f}; + std::vector exponents_input = {-2.0f, -1.0f, 0.0f, 0.5f, 1.0f, 2.0f, 1.5f, 0.2f}; + RunQDQOpTest("Pow", + {TestInputDef({1, 2, 2, 2}, false, bases_input), + TestInputDef({1, 2, 2, 2}, false, exponents_input)}, + {}, + 15, + ExpectedEPNodeAssignment::All); +} + +// Test accuracy of QDQ PRelu with dynamic slopes. +TEST_F(QnnHTPBackendTests, BinaryOp_PRelu_DynamicSlopes) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 8); + std::vector slopes_data = GetFloatDataInRange(-1.0f, 1.0f, 8); + RunQDQOpTest("PRelu", + {TestInputDef({1, 2, 2, 2}, false, input_data), + TestInputDef({1, 2, 2, 2}, false, slopes_data)}, + {}, + 16, + ExpectedEPNodeAssignment::All); +} + +// Test accuracy of QDQ PRelu with static slope weights. +TEST_F(QnnHTPBackendTests, BinaryOp_PRelu_StaticSlopes) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 8); + std::vector slopes_data = GetFloatDataInRange(-1.0f, 1.0f, 8); + RunQDQOpTest("PRelu", + {TestInputDef({1, 2, 2, 2}, false, input_data), + TestInputDef({1, 2, 2, 2}, true, slopes_data)}, + {}, + 16, + ExpectedEPNodeAssignment::All); +} + +TEST_F(QnnHTPBackendTests, BinaryOp_Div4D_SmallInputs) { + std::vector input0_data = {-10.0f, -8.0f, -1.0f, 0.0f, 1.0f, 2.1f, 8.0f, 10.0f}; + std::vector input1_data = {5.0f, 4.0f, 1.0f, 1.0f, 1.0f, 4.0f, 4.0f, 5.0f}; + RunQDQOpTest("Div", + {TestInputDef({1, 2, 2, 2}, false, input0_data), + TestInputDef({1, 2, 2, 2}, false, input1_data)}, + {}, + 17, + ExpectedEPNodeAssignment::All); +} + +// Test 16-bit QDQ Sub with small input values. +TEST_F(QnnHTPBackendTests, BinaryOp_Div4D_U16_SmallInputs) { + std::vector input0_data = {-10.0f, -8.0f, -1.0f, 0.0f, 1.0f, 2.1f, 8.0f, 10.0f}; + std::vector input1_data = {5.0f, 4.0f, 1.0f, 1.0f, 1.0f, 4.0f, 4.0f, 5.0f}; + RunQDQOpTest("Div", + {TestInputDef({1, 2, 2, 2}, false, input0_data), + TestInputDef({1, 2, 2, 2}, false, input1_data)}, + {}, + 17, + ExpectedEPNodeAssignment::All, + kOnnxDomain, + true); // Use com.microsoft Q/DQ ops +} + +// TODO: Enable when this is fixed. +// QNN v2.13: Inaccuracy detected for output 'output', element 2551923. +// Output quant params: scale=4100.92626953125, zero_point=126. +// Expected val: -277957.3125 +// QNN QDQ val: 0 (err 277957.3125) +// CPU QDQ val: -516716.71875 (err 238759.40625) +TEST_F(QnnHTPBackendTests, DISABLED_BinaryOp_Div4D_LargeInputs) { + RunQDQOpTest("Div", + {TestInputDef({1, 3, 768, 1152}, false, -1.0f, 1.0f), + TestInputDef({1, 3, 768, 1152}, false, -1.0f, 1.0f)}, + {}, + 17, + ExpectedEPNodeAssignment::All); +} + +TEST_F(QnnHTPBackendTests, BinaryOp_Div4D_Broadcast) { + RunQDQOpTest("Div", + {TestInputDef({1, 3, 768, 1152}, false, -1.0f, 1.0f), + TestInputDef({3, 1, 1}, true, {1.0f, 0.5f, -0.3f})}, + {}, + 17, + ExpectedEPNodeAssignment::All); +} + +// Test 8-bit QDQ Mul +TEST_F(QnnHTPBackendTests, BinaryOp_Mul4D) { + std::vector input_data = GetFloatDataInRange(-10.0, 10.0f, 8); + RunQDQOpTest("Mul", + {TestInputDef({1, 2, 2, 2}, false, input_data), + TestInputDef({1, 2, 2, 2}, false, input_data)}, + {}, + 17, + ExpectedEPNodeAssignment::All); +} + +// Test 16-bit QDQ Mul +TEST_F(QnnHTPBackendTests, BinaryOp_Mul4D_U16) { + std::vector input_data = GetFloatDataInRange(-10.0f, 10.0f, 8); + RunQDQOpTest("Mul", + {TestInputDef({1, 2, 2, 2}, false, input_data), + TestInputDef({1, 2, 2, 2}, false, input_data)}, + {}, + 17, + ExpectedEPNodeAssignment::All, + kOnnxDomain, + true); // Use com.microsoft Q/DQ ops +} + +// Test And +TEST_F(QnnHTPBackendTests, BinaryOp_And4D) { + RunOpTest("And", + {TestInputDef({1, 4}, false, {false, false, true, true}), + TestInputDef({1, 4}, false, {false, true, false, true})}, + {}, + 17, + ExpectedEPNodeAssignment::All); +} + +// Test that Or is not yet supported on CPU backend. +TEST_F(QnnHTPBackendTests, BinaryOp_HTP_Or_Unsupported) { + RunOpTest("Or", + {TestInputDef({1, 4}, false, {false, false, true, true}), + TestInputDef({1, 4}, false, {false, true, false, true})}, + {}, + 17, + ExpectedEPNodeAssignment::None); +} + +// Test 8-bit QDQ GridSample with bilinear +TEST_F(QnnHTPBackendTests, GridSample_Bilinear) { + RunQDQOpTest("GridSample", + {TestInputDef({1, 1, 3, 2}, false, GetFloatDataInRange(-10.0f, 10.0f, 6)), + TestInputDef({1, 2, 4, 2}, false, GetFloatDataInRange(-10.0f, 10.0f, 16))}, + {utils::MakeAttribute("align_corners", static_cast(0)), + utils::MakeAttribute("mode", "bilinear"), + utils::MakeAttribute("padding_mode", "zeros")}, + 17, + ExpectedEPNodeAssignment::All); +} + +// Test 16-bit QDQ GridSample with bilinear +TEST_F(QnnHTPBackendTests, GridSample_U16_Bilinear) { + RunQDQOpTest("GridSample", + {TestInputDef({1, 1, 3, 2}, false, GetFloatDataInRange(-10.0f, 10.0f, 6)), + TestInputDef({1, 2, 4, 2}, false, GetFloatDataInRange(-10.0f, 10.0f, 16))}, + {utils::MakeAttribute("align_corners", static_cast(0)), + utils::MakeAttribute("mode", "bilinear"), + utils::MakeAttribute("padding_mode", "zeros")}, + 17, + ExpectedEPNodeAssignment::All, + kOnnxDomain, + true); // Use com.microsoft Q/DQ ops +} + +// Test 8-bit QDQ GridSample with align corners +TEST_F(QnnHTPBackendTests, GridSample_AlignCorners) { + RunQDQOpTest("GridSample", + {TestInputDef({1, 1, 3, 2}, false, GetFloatDataInRange(-10.0f, 10.0f, 6)), + TestInputDef({1, 2, 4, 2}, false, GetFloatDataInRange(-10.0f, 10.0f, 16))}, + {utils::MakeAttribute("align_corners", static_cast(1)), + utils::MakeAttribute("mode", "bilinear"), + utils::MakeAttribute("padding_mode", "zeros")}, + 17, + ExpectedEPNodeAssignment::All); +} + +// Test 16-bit QDQ GridSample with align corners +TEST_F(QnnHTPBackendTests, GridSample_U16_AlignCorners) { + RunQDQOpTest("GridSample", + {TestInputDef({1, 1, 3, 2}, false, GetFloatDataInRange(-10.0f, 10.0f, 6)), + TestInputDef({1, 2, 4, 2}, false, GetFloatDataInRange(-10.0f, 10.0f, 16))}, + {utils::MakeAttribute("align_corners", static_cast(1)), + utils::MakeAttribute("mode", "bilinear"), + utils::MakeAttribute("padding_mode", "zeros")}, + 17, + ExpectedEPNodeAssignment::All, + kOnnxDomain, + true); // Use com.microsoft Q/DQ ops +} + +// Test QDQ GridSample with padding mode: border +// Inaccuracy detected for output 'output', element 0. +// Output quant params: scale=0.046370312571525574, zero_point=129. +// Expected val: 3.3620510101318359 +// QNN QDQ val: 3.2922921180725098 (err 0.069758892059326172) +// CPU QDQ val: 3.3850328922271729 (err 0.022981882095336914) +TEST_F(QnnHTPBackendTests, DISABLED_GridSample_BorderPadding) { + RunQDQOpTest("GridSample", + {TestInputDef({1, 1, 3, 2}, false, -10.0f, 10.0f), + TestInputDef({1, 2, 4, 2}, false, -10.0f, 10.0f)}, + {utils::MakeAttribute("mode", "bilinear"), + utils::MakeAttribute("padding_mode", "border")}, + 17, + ExpectedEPNodeAssignment::All); +} + +// Test 8-bit QDQ GridSample with nearest mode +TEST_F(QnnHTPBackendTests, GridSample_Nearest) { + RunQDQOpTest("GridSample", + {TestInputDef({1, 1, 3, 2}, false, GetFloatDataInRange(-10.0f, 10.0f, 6)), + TestInputDef({1, 2, 4, 2}, false, GetFloatDataInRange(-10.0f, 10.0f, 16))}, + {utils::MakeAttribute("mode", "nearest")}, + 17, + ExpectedEPNodeAssignment::All); +} + +// Test 16-bit QDQ GridSample with nearest mode +TEST_F(QnnHTPBackendTests, GridSample_U16_Nearest) { + RunQDQOpTest("GridSample", + {TestInputDef({1, 1, 3, 2}, false, GetFloatDataInRange(-10.0f, 10.0f, 6)), + TestInputDef({1, 2, 4, 2}, false, GetFloatDataInRange(-10.0f, 10.0f, 16))}, + {utils::MakeAttribute("mode", "nearest")}, + 17, + ExpectedEPNodeAssignment::All, + kOnnxDomain, + true); +} + +// Test QDQ GridSample with reflection padding mode +// Inaccuracy detected for output 'output', element 2. +// Output quant params: scale=0.024269860237836838, zero_point=0. +// 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) { + RunQDQOpTest("GridSample", + {TestInputDef({1, 1, 3, 2}, false, -10.0f, 10.0f), + TestInputDef({1, 2, 4, 2}, false, -10.0f, 10.0f)}, + {utils::MakeAttribute("padding_mode", "reflection")}, + 17, + ExpectedEPNodeAssignment::All); +} + +// Test QDQ Concat: 3 inputs concatenated at the last axis. +TEST_F(QnnHTPBackendTests, VariadicOp_Concat_3Inputs_LastAxis) { + RunQDQOpTest("Concat", + {TestInputDef({1, 2, 2, 2}, false, -10.0f, 10.0f), + TestInputDef({1, 2, 2, 3}, false, -1.0f, 1.0f), + TestInputDef({1, 2, 2, 1}, false, -2.0f, 2.0f)}, + {utils::MakeAttribute("axis", static_cast(-1))}, + 13, + ExpectedEPNodeAssignment::All); +} + +// Test QDQ Concat: 2 inputs concatenated at the second axis. +TEST_F(QnnHTPBackendTests, VariadicOp_Concat_2Inputs_2ndAxis) { + RunQDQOpTest("Concat", + {TestInputDef({1, 2, 2, 2}, false, -10.0f, 10.0f), + TestInputDef({1, 3, 2, 2}, false, -2.0f, 2.0f)}, + {utils::MakeAttribute("axis", static_cast(1))}, + 13, + ExpectedEPNodeAssignment::All); +} #endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) } // namespace test } // namespace onnxruntime -#endif \ No newline at end of file +#endif diff --git a/onnxruntime/test/providers/qnn/slice_htp_test.cc b/onnxruntime/test/providers/qnn/slice_htp_test.cc new file mode 100644 index 0000000000000..edc079dc65276 --- /dev/null +++ b/onnxruntime/test/providers/qnn/slice_htp_test.cc @@ -0,0 +1,131 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#if !defined(ORT_MINIMAL_BUILD) + +#include +#include "core/graph/graph.h" +#include "core/graph/node_attr_utils.h" + +#include "test/optimizer/qdq_test_utils.h" +#include "test/providers/qnn/qnn_test_utils.h" + +#include "gtest/gtest.h" + +namespace onnxruntime { +namespace test { +#if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) + +/** + * Runs an Slice model on the QNN HTP backend. Checks the graph node assignment, and that inference + * outputs for QNN and CPU match. + * + * \param data_def The data input's definition (shape, is_initializer, data). + * \param starts_def The starts input's definition. + * \param ends_def The ends input's definition. + * \param axes_def The axes input's definition. + * \param steps_def The steps input's definition. + * \param expected_ep_assignment How many nodes are expected to be assigned to QNN (All, Some, or None). + */ +template +static void RunSliceQDQTest(const TestInputDef& data_def, + const TestInputDef& starts_def, + const TestInputDef& ends_def, + const TestInputDef& axes_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 + + const std::vector> f32_inputs = {data_def}; + const std::vector> int64_inputs = {starts_def, ends_def, axes_def, steps_def}; + + TestQDQModelAccuracy(BuildOpTestCase("Slice", f32_inputs, int64_inputs, {}), + BuildQDQOpTestCase("Slice", f32_inputs, int64_inputs, {}), + provider_options, + 18, + expected_ep_assignment); +} + +/** + * Runs an Slice model on the QNN HTP backend. Checks the graph node assignment, and that inference + * outputs for QNN and CPU match. + * + * \param data_def The data (int32_t) input's definition (shape, is_initializer, data). + * \param starts_def The starts input's definition. + * \param ends_def The ends input's definition. + * \param axes_def The axes input's definition. + * \param steps_def The steps input's definition. + * \param expected_ep_assignment How many nodes are expected to be assigned to QNN (All, Some, or None). + */ +template +static void RunSliceNonQDQOnHTP(const TestInputDef& data_def, + const TestInputDef& starts_def, + const TestInputDef& ends_def, + const TestInputDef& axes_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 + auto f32_model_builder = BuildOpTestCase("Slice", {data_def}, + {starts_def, ends_def, axes_def, steps_def}, {}); + RunQnnModelTest(f32_model_builder, + provider_options, + 13, + expected_ep_assignment); +} + +// Check that QNN compiles DQ -> Slice -> Q as a single unit. +TEST_F(QnnHTPBackendTests, SliceSmallDataQDQU8) { + RunSliceQDQTest(TestInputDef({8}, false, 0.0f, 1.0f), + TestInputDef({1}, true, {0}), + TestInputDef({1}, true, {-1}), + TestInputDef({1}, true, {0}), + TestInputDef({1}, true, {2}), + ExpectedEPNodeAssignment::All); +} + +// Check that QNN compiles DQ -> Slice -> Q as a single unit. +TEST_F(QnnHTPBackendTests, SliceLargePositiveDataQDQU8) { + RunSliceQDQTest(TestInputDef({5120}, false, 0.0f, 1.0f), + TestInputDef({1}, true, {0}), + TestInputDef({1}, true, {-1}), + TestInputDef({1}, true, {0}), + TestInputDef({1}, true, {2}), + ExpectedEPNodeAssignment::All); +} + +// Check that QNN compiles DQ -> Slice -> Q as a single unit. +TEST_F(QnnHTPBackendTests, SliceLargeNegativeDataQDQU8) { + RunSliceQDQTest(TestInputDef({5120}, false, 0.0f, 1.0f), + TestInputDef({1}, true, {0}), + TestInputDef({1}, true, {-1}), + TestInputDef({1}, true, {0}), + TestInputDef({1}, true, {2}), + ExpectedEPNodeAssignment::All); +} + +// Check that QNN supports Slice with int32 data input on HTP +TEST_F(QnnHTPBackendTests, SliceInt32OnHTP) { + RunSliceNonQDQOnHTP(TestInputDef({5120}, false, -100, 100), + TestInputDef({1}, true, {0}), + TestInputDef({1}, true, {-1}), + TestInputDef({1}, true, {0}), + TestInputDef({1}, true, {2}), + ExpectedEPNodeAssignment::All); +} + +#endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) + +} // namespace test +} // namespace onnxruntime + +#endif \ No newline at end of file diff --git a/onnxruntime/test/providers/qnn/split_op_test.cc b/onnxruntime/test/providers/qnn/split_op_test.cc new file mode 100644 index 0000000000000..57e4b211777bb --- /dev/null +++ b/onnxruntime/test/providers/qnn/split_op_test.cc @@ -0,0 +1,387 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#if !defined(ORT_MINIMAL_BUILD) + +#include + +#include "test/providers/qnn/qnn_test_utils.h" + +#include "onnx/onnx_pb.h" +#include "gtest/gtest.h" + +namespace onnxruntime { +namespace test { + +template +GetTestModelFn BuildSplitTestCase(const TestInputDef& input_def, + const std::vector& split, bool split_is_input, + int64_t axis, int64_t num_outputs) { + return [input_def, split, split_is_input, axis, num_outputs](ModelTestBuilder& builder) { + std::vector op_inputs; + + op_inputs.push_back(MakeTestInput(builder, input_def)); + + if (split_is_input && !split.empty()) { + op_inputs.push_back(builder.Make1DInitializer(split)); + } + + // Determine the actual number of outputs from the 'split' or 'num_outputs' arguments. + // In opset 18, the num_outputs attribute or the split input can determine the actual number of outputs. + // In opset 13, the split input determines the number of actual outputs. + // In opsets < 13, the split attribute determines the number of actual outputs. + size_t actual_num_outputs = (num_outputs > -1) ? static_cast(num_outputs) : split.size(); + + std::vector split_outputs; + for (size_t i = 0; i < actual_num_outputs; i++) { + split_outputs.push_back(builder.MakeOutput()); + } + + Node& split_node = builder.AddNode("Split", op_inputs, split_outputs); + + if (!split_is_input && !split.empty()) { + split_node.AddAttribute("split", split); + } + + if (num_outputs > -1) { + split_node.AddAttribute("num_outputs", num_outputs); + } + + split_node.AddAttribute("axis", axis); + }; +} + +template +static void RunSplitOpTestOnCPU(const TestInputDef& input_def, + const std::vector& split, + int64_t axis, + int64_t num_outputs, + int opset, + ExpectedEPNodeAssignment expected_ep_assignment) { + ProviderOptions provider_options; + +#if defined(_WIN32) + provider_options["backend_path"] = "QnnCpu.dll"; +#else + provider_options["backend_path"] = "libQnnCpu.so"; +#endif + + const bool split_is_input = opset >= 13; + RunQnnModelTest(BuildSplitTestCase(input_def, split, split_is_input, axis, num_outputs), + provider_options, + opset, + expected_ep_assignment); +} + +// +// CPU tests: +// + +// Test Split opset 18 on CPU backend: equal split of axis 0 via 'num_outputs' attribute +// and 'split' input. +TEST_F(QnnCPUBackendTests, Split_Equal_Axis0_Opset18) { + // Use 'split' input (initializer). + RunSplitOpTestOnCPU(TestInputDef({4, 2}, false, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.f, 8.f}), + {2, 2}, // split + 0, // axis + -1, // num_outputs + 18, // opset + ExpectedEPNodeAssignment::All); + RunSplitOpTestOnCPU(TestInputDef({4, 2}, false, {1, 2, 3, 4, 5, 6, 7, 8}), + {2, 2}, // split + 0, // axis + -1, // num_outputs + 18, // opset + ExpectedEPNodeAssignment::All); + + // Use 'num_outputs' attribute. + RunSplitOpTestOnCPU(TestInputDef({4, 2}, false, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.f, 8.f}), + {}, // split (use num_outputs instead) + 0, // axis + 2, // num_outputs + 18, // opset + ExpectedEPNodeAssignment::All); + RunSplitOpTestOnCPU(TestInputDef({4, 2}, false, {1, 2, 3, 4, 5, 6, 7, 8}), + {}, // split (use num_outputs instead) + 0, // axis + 2, // num_outputs + 18, // opset + ExpectedEPNodeAssignment::All); +} + +// Test Split opset 13 on CPU backend: equal split of axis 0 +TEST_F(QnnCPUBackendTests, Split_Equal_Axis0_Opset13) { + RunSplitOpTestOnCPU(TestInputDef({4, 2}, false, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.f, 8.f}), + {2, 2}, // split + 0, // axis + -1, // num_outputs (not in opset 13) + 13, // opset + ExpectedEPNodeAssignment::All); + RunSplitOpTestOnCPU(TestInputDef({4, 2}, false, {1, 2, 3, 4, 5, 6, 7, 8}), + {2, 2}, // split + 0, // axis + -1, // num_outputs (not in opset 13) + 13, // opset + ExpectedEPNodeAssignment::All); +} + +// Test Split opset 11 on CPU backend: equal split of axis 0 +TEST_F(QnnCPUBackendTests, Split_Equal_Axis0_Opset11) { + RunSplitOpTestOnCPU(TestInputDef({4, 2}, false, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.f, 8.f}), + {2, 2}, // split + 0, // axis + -1, // num_outputs (not in opset 11) + 11, // opset + ExpectedEPNodeAssignment::All); + RunSplitOpTestOnCPU(TestInputDef({4, 2}, false, {1, 2, 3, 4, 5, 6, 7, 8}), + {2, 2}, // split + 0, // axis + -1, // num_outputs (not in opset 11) + 11, // opset + ExpectedEPNodeAssignment::All); +} + +// Test Split opset 13 on CPU backend: unequal split of axis 1 +TEST_F(QnnCPUBackendTests, Split_Unequal_Axis1_Opset13) { + RunSplitOpTestOnCPU(TestInputDef({2, 4}, false, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.f, 8.f}), + {1, 3}, // split + 1, // axis + -1, // num_outputs (not in opset 13) + 13, // opset + ExpectedEPNodeAssignment::All); + RunSplitOpTestOnCPU(TestInputDef({2, 4}, false, {1, 2, 3, 4, 5, 6, 7, 8}), + {1, 3}, // split + 1, // axis + -1, // num_outputs (not in opset 13) + 13, // opset + ExpectedEPNodeAssignment::All); +} + +// Test Split opset 11 on CPU backend: unequal split of axis 1 +TEST_F(QnnCPUBackendTests, Split_Unequal_Axis1_Opset11) { + RunSplitOpTestOnCPU(TestInputDef({2, 4}, false, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.f, 8.f}), + {1, 3}, // split + 1, // axis + -1, // num_outputs (not in opset 11) + 11, // opset + ExpectedEPNodeAssignment::All); + RunSplitOpTestOnCPU(TestInputDef({2, 4}, false, {1, 2, 3, 4, 5, 6, 7, 8}), + {1, 3}, // split + 1, // axis + -1, // num_outputs (not in opset 11) + 11, // opset + ExpectedEPNodeAssignment::All); +} + +#if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) +// +// HTP tests: +// + +// Return function that builds a model with a QDQ Split. +template +GetTestQDQModelFn BuildQDQSplitTestCase(const TestInputDef& input_def, + const std::vector& split, + bool split_is_input, + int64_t axis, + int64_t num_outputs, + bool use_contrib_qdq = false) { + return [input_def, split, split_is_input, axis, num_outputs, + use_contrib_qdq](ModelTestBuilder& builder, + std::vector>& output_qparams) { + std::vector op_inputs; + + // Add QDQ input + NodeArg* input = MakeTestInput(builder, input_def); + QuantParams input_qparams = GetTestInputQuantParams(input_def); + NodeArg* input_after_qdq = AddQDQNodePair(builder, input, input_qparams.scale, + input_qparams.zero_point, use_contrib_qdq); + op_inputs.push_back(input_after_qdq); + + // Add split input + if (split_is_input && !split.empty()) { + op_inputs.push_back(builder.Make1DInitializer(split)); + } + + // Determine the actual number of outputs from the 'split' or 'num_outputs' arguments. + // In opset 18, the num_outputs attribute or the split input can determine the actual number of outputs. + // In opset 13, the split input determines the number of actual outputs. + // In opsets < 13, the split attribute determines the number of actual outputs. + size_t actual_num_outputs = (num_outputs > -1) ? static_cast(num_outputs) : split.size(); + + std::vector split_outputs; + for (size_t i = 0; i < actual_num_outputs; i++) { + split_outputs.push_back(builder.MakeIntermediate()); + } + + Node& split_node = builder.AddNode("Split", op_inputs, split_outputs); + + if (!split_is_input && !split.empty()) { + split_node.AddAttribute("split", split); + } + + if (num_outputs > -1) { + split_node.AddAttribute("num_outputs", num_outputs); + } + + split_node.AddAttribute("axis", axis); + + // op_output -> Q -> DQ -> output + assert(output_qparams.size() == actual_num_outputs); + for (size_t i = 0; i < actual_num_outputs; i++) { + // NOTE: Input and output quantization parameters must be equal for Split. + output_qparams[i] = input_qparams; + AddQDQNodePairWithOutputAsGraphOutput(builder, split_outputs[i], output_qparams[i].scale, + output_qparams[i].zero_point, use_contrib_qdq); + } + }; +} + +// Runs a non-QDQ Split operator on the HTP backend. +template +static void RunSplitOpTestOnHTP(const TestInputDef& input_def, + const std::vector& split, + int64_t axis, + int64_t num_outputs, + 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 + + const bool split_is_input = opset >= 13; + RunQnnModelTest(BuildSplitTestCase(input_def, split, split_is_input, axis, num_outputs), + provider_options, + opset, + expected_ep_assignment); +} + +// Runs a QDQ Split operator on the HTP backend. +template +static void RunQDQSplitOpTestOnHTP(const TestInputDef& input_def, + const std::vector& split, + int64_t axis, + int64_t num_outputs, + int opset, + 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 + + const bool split_is_input = opset >= 13; + auto f32_model_builder = BuildSplitTestCase(input_def, split, split_is_input, axis, num_outputs); + auto qdq_model_builder = BuildQDQSplitTestCase(input_def, split, split_is_input, axis, num_outputs, + use_contrib_qdq); + TestQDQModelAccuracy(f32_model_builder, + qdq_model_builder, + provider_options, + opset, + expected_ep_assignment); +} + +// Test that HTP can run non-QDQ Split (int32 input). +TEST_F(QnnHTPBackendTests, Split_Int32_Opset13) { + // Equal split. + RunSplitOpTestOnHTP(TestInputDef({4, 2}, false, {1, 2, 3, 4, 5, 6, 7, 8}), + {2, 2}, // split + 0, // axis + -1, // num_outputs (not in opset 13) + 13, // opset + ExpectedEPNodeAssignment::All); +} + +// Test 8-bit QDQ Split opset 18 on HTP backend: equal split of axis 0 via 'num_outputs' attribute +// and 'split' input. +TEST_F(QnnHTPBackendTests, Split_Equal_Axis0_Opset18) { + // Use 'split' input (initializer). + RunQDQSplitOpTestOnHTP(TestInputDef({4, 2}, false, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.f, 8.f}), + {2, 2}, // split + 0, // axis + -1, // num_outputs + 18, // opset + ExpectedEPNodeAssignment::All); + + // Use 'num_outputs' attribute. + RunQDQSplitOpTestOnHTP(TestInputDef({4, 2}, false, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.f, 8.f}), + {}, // split (use num_outputs instead) + 0, // axis + 2, // num_outputs + 18, // opset + ExpectedEPNodeAssignment::All); +} + +// Test 16-bit QDQ Split opset 18 on HTP backend: equal split of axis 0 via 'num_outputs' attribute +// and 'split' input. +TEST_F(QnnHTPBackendTests, Split_Equal_Axis0_Opset18_U16) { + // Use 'split' input (initializer). + RunQDQSplitOpTestOnHTP(TestInputDef({4, 2}, false, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.f, 8.f}), + {2, 2}, // split + 0, // axis + -1, // num_outputs + 18, // opset + ExpectedEPNodeAssignment::All, + true); // Use com.microsoft Q/DQ ops + + // Use 'num_outputs' attribute. + RunQDQSplitOpTestOnHTP(TestInputDef({4, 2}, false, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.f, 8.f}), + {}, // split (use num_outputs instead) + 0, // axis + 2, // num_outputs + 18, // opset + ExpectedEPNodeAssignment::All, + true); // Use com.microsoft Q/DQ ops +} + +// Test QDQ Split op on HTP backend: equal split on axis 0 with opset 13. +TEST_F(QnnHTPBackendTests, Split_Equal_Axis0_Opset13) { + RunQDQSplitOpTestOnHTP(TestInputDef({4, 2}, false, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.f, 8.f}), + {2, 2}, // split + 0, // axis + -1, // num_outputs (not in opset 13) + 13, // opset + ExpectedEPNodeAssignment::All); +} + +// Test QDQ Split op on HTP backend: equal split on axis 0 with opset 11. +TEST_F(QnnHTPBackendTests, Split_Equal_Axis0_Opset11) { + RunQDQSplitOpTestOnHTP(TestInputDef({4, 2}, false, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.f, 8.f}), + {2, 2}, // split + 0, // axis + -1, // num_outputs (not in opset 11) + 11, // opset + ExpectedEPNodeAssignment::All); +} + +// Test Split opset 13 on HTP backend: unequal split of axis 1 +TEST_F(QnnHTPBackendTests, Split_Unequal_Axis1_Opset13) { + RunQDQSplitOpTestOnHTP(TestInputDef({2, 4}, false, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.f, 8.f}), + {1, 3}, // split + 1, // axis + -1, // num_outputs (not in opset 13) + 13, // opset + ExpectedEPNodeAssignment::All); +} + +// Test Split opset 11 on HTP backend: unequal split of axis 1 +TEST_F(QnnHTPBackendTests, Split_Unequal_Axis1_Opset11) { + RunQDQSplitOpTestOnHTP(TestInputDef({2, 4}, false, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.f, 8.f}), + {1, 3}, // split + 1, // axis + -1, // num_outputs (not in opset 11) + 11, // opset + ExpectedEPNodeAssignment::All); +} + +#endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) +} // namespace test +} // namespace onnxruntime +#endif // !defined(ORT_MINIMAL_BUILD) diff --git a/onnxruntime/test/providers/qnn/squeeze_unsqueeze_op_test.cc b/onnxruntime/test/providers/qnn/squeeze_unsqueeze_op_test.cc new file mode 100644 index 0000000000000..33d2f64c0315e --- /dev/null +++ b/onnxruntime/test/providers/qnn/squeeze_unsqueeze_op_test.cc @@ -0,0 +1,324 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#if !defined(ORT_MINIMAL_BUILD) + +#include + +#include "test/providers/qnn/qnn_test_utils.h" + +#include "onnx/onnx_pb.h" +#include "gtest/gtest.h" + +namespace onnxruntime { +namespace test { + +// Runs a model with a Squeeze (or Unsqueeze) operator on the QNN CPU backend. Checks the graph node assignment +// and that inference outputs for QNN EP and CPU EP match. +template +static void RunSqueezeTestOnCPU(const std::string& op_type, // Squeeze or Unsqueeze + const TestInputDef& input_def, + const TestInputDef& axes_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 + + RunQnnModelTest(BuildOpTestCase(op_type, {input_def}, {axes_def}, {}), + provider_options, + opset, + expected_ep_assignment); +} + +// +// CPU tests: +// + +// Test that Squeeze with a dynamic axes input is not supported by QNN EP. +TEST_F(QnnCPUBackendTests, Squeeze_DynamicAxes_Unsupported) { + RunSqueezeTestOnCPU("Squeeze", + TestInputDef({1, 3, 4, 4}, false, -10.0f, 10.0f), + TestInputDef({1}, false /* is_initializer */, {0}), + ExpectedEPNodeAssignment::None); // Should not be assigned to QNN EP. +} + +// Test that Unsqueeze with a dynamic axes input is not supported by QNN EP. +TEST_F(QnnCPUBackendTests, Unsqueeze_DynamicAxes_Unsupported) { + RunSqueezeTestOnCPU("Unsqueeze", + TestInputDef({1, 3, 4, 4}, false, -10.0f, 10.0f), + TestInputDef({1}, false /* is_initializer */, {0}), + ExpectedEPNodeAssignment::None); // Should not be assigned to QNN EP. +} + +// Test Squeeze of rank 5 -> rank 2. +TEST_F(QnnCPUBackendTests, Squeeze_Rank5_Rank2_f32) { + RunSqueezeTestOnCPU("Squeeze", + TestInputDef({1, 3, 1, 2, 4}, false, -10.0f, 10.0f), + TestInputDef({2}, true, {0, 2}), // Squeeze axes 0 and 2 => (3, 2, 4) + ExpectedEPNodeAssignment::All); +} + +// Test Squeeze of rank 4 -> rank 3 with a negative axes value. +TEST_F(QnnCPUBackendTests, Squeeze_Rank4_Rank3_NegAxes_f32) { + RunSqueezeTestOnCPU("Squeeze", + TestInputDef({1, 3, 2, 1}, false, -10.0f, 10.0f), + TestInputDef({1}, true, {-1}), // Squeeze last axis => (1, 3, 2) + ExpectedEPNodeAssignment::All); +} + +// Test Unsqueeze of rank 3 -> rank 5. +TEST_F(QnnCPUBackendTests, Unsqueeze_Rank3_Rank5_f32) { + RunSqueezeTestOnCPU("Unsqueeze", + TestInputDef({3, 2, 4}, false, -10.0f, 10.0f), + TestInputDef({2}, true, {0, 2}), // Add 1's => (1, 3, 1, 2, 4) + ExpectedEPNodeAssignment::All); +} + +// Test Unsqueeze of rank 3 -> rank 4 with a negative axes value. +TEST_F(QnnCPUBackendTests, Unsqueeze_Rank3_Rank4_NegAxes_f32) { + RunSqueezeTestOnCPU("Unsqueeze", + TestInputDef({1, 3, 2}, false, -10.0f, 10.0f), + TestInputDef({1}, true, {-1}), // Add 1 as last axis => (1, 3, 2, 1) + ExpectedEPNodeAssignment::All); +} + +#if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) +// +// HTP tests: +// + +// Returns a function that creates a graph with a QDQ (Un)Squeeze operator. +template +GetTestQDQModelFn BuildQDQSqueezeTestCase(const std::string& op_type, // Squeeze or Unsqueeze + const TestInputDef& input_def, + const TestInputDef& axes_def, + bool use_contrib_qdq = false) { + return [op_type, input_def, axes_def, + use_contrib_qdq](ModelTestBuilder& builder, + std::vector>& output_qparams) { + // input -> Q -> DQ -> + NodeArg* input = MakeTestInput(builder, input_def); + QuantParams input_qparams = GetTestInputQuantParams(input_def); + NodeArg* input_qdq = AddQDQNodePair(builder, input, input_qparams.scale, input_qparams.zero_point, + use_contrib_qdq); + + // axes input + NodeArg* axes_input = MakeTestInput(builder, axes_def); + + // (Un)Squeeze op + NodeArg* op_output = builder.MakeIntermediate(); + builder.AddNode(op_type, {input_qdq, axes_input}, {op_output}); + + // op_output -> Q -> DQ -> output + // NOTE: Input and output quantization parameters must be equal for (Un)Squeeze. + output_qparams[0] = input_qparams; // Overwrite! + AddQDQNodePairWithOutputAsGraphOutput(builder, op_output, input_qparams.scale, + input_qparams.zero_point, use_contrib_qdq); + }; +} + +// Runs a model with a non-QDQ (Un)Squeeze operator on the QNN HTP backend. Checks the graph node assignment +// and that inference outputs for QNN EP and CPU EP match. +template +static void RunSqueezeTestOnHTP(const std::string& op_type, // Squeeze or Unsqueeze + const TestInputDef& input_def, + const TestInputDef& axes_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 + + RunQnnModelTest(BuildOpTestCase(op_type, {input_def}, {axes_def}, {}), + provider_options, + opset, + expected_ep_assignment); +} + +// Runs a QDQ (Un)Squeeze model on the QNN (HTP) EP and the ORT CPU EP. Checks the graph node assignment and +// that inference running the QDQ model on QNN EP is at least as accurate as on ORT CPU EP +// (when compared to the baseline float32 model). +template +static void RunQDQSqueezeTestOnHTP(const std::string& op_type, + const TestInputDef& input_def, + const TestInputDef& axes_def, + ExpectedEPNodeAssignment expected_ep_assignment, + 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 + + auto f32_model_builder = BuildOpTestCase(op_type, {input_def}, {axes_def}, {}); + auto qdq_model_builder = BuildQDQSqueezeTestCase(op_type, input_def, axes_def, use_contrib_qdq); + + TestQDQModelAccuracy(f32_model_builder, + qdq_model_builder, + provider_options, + opset, + expected_ep_assignment); +} + +// Test that QDQ Squeeze with a dynamic axes input is not supported by QNN EP. +TEST_F(QnnHTPBackendTests, Squeeze_DynamicAxes_Unsupported) { + RunQDQSqueezeTestOnHTP("Squeeze", + TestInputDef({1, 3, 4, 4}, false, -10.0f, 10.0f), + TestInputDef({1}, false /* is_initializer */, {0}), + ExpectedEPNodeAssignment::None); // Should not be assigned to QNN EP. +} + +// Test that Unsqueeze with a dynamic axes input is not supported by QNN EP. +TEST_F(QnnHTPBackendTests, Unsqueeze_DynamicAxes_Unsupported) { + RunQDQSqueezeTestOnHTP("Unsqueeze", + TestInputDef({1, 3, 4, 4}, false, -10.0f, 10.0f), + TestInputDef({1}, false /* is_initializer */, {0}), + ExpectedEPNodeAssignment::None); // Should not be assigned to QNN EP. +} + +// Test Squeeze of rank 5 -> rank 2. +TEST_F(QnnHTPBackendTests, Squeeze_Rank5_Rank2_f32) { + // We can't use the usual model-building functions because they add standalone Quantize and Dequantize nodes + // at the input and output. These Q/DQ ops get lowered to QNN's Quantize and Dequantize operators, which DO NOT + // support rank 5 tensors. Therefore, we have to create a test model that only instantiates the DQ -> Squeeze -> Q + // QDQ node group, which gets lowered to a single QNN Reshape node. + GetTestModelFn model_fn = [](ModelTestBuilder& builder) { + // input (u8) -> DQ -> + NodeArg* quant_input = builder.MakeInput({1, 3, 1, 2, 4}, 0, 255); + NodeArg* input_dq = builder.MakeIntermediate(); + builder.AddDequantizeLinearNode(quant_input, 1.0f, 0, input_dq); // scale = 1.0, zp = 0 + + // axes_input -> + NodeArg* axes_input = builder.Make1DInitializer({0, 2}); // Squeeze axes 0 and 2 => (3, 2, 4) + + // Squeeze -> + NodeArg* squeeze_output = builder.MakeIntermediate(); + builder.AddNode("Squeeze", {input_dq, axes_input}, {squeeze_output}); + + // Q -> output (u8) + NodeArg* output = builder.MakeOutput(); + builder.AddQuantizeLinearNode(squeeze_output, 1.0f, 0, output); // scale = 1.0, zp = 0 + }; + + ProviderOptions provider_options; + +#if defined(_WIN32) + provider_options["backend_path"] = "QnnHtp.dll"; +#else + provider_options["backend_path"] = "libQnnHtp.so"; +#endif + + RunQnnModelTest(model_fn, + provider_options, + 13, // opset + ExpectedEPNodeAssignment::All); +} + +// Test 8-bit QDQ Squeeze of rank 4 -> rank 3 with a negative axes value. +TEST_F(QnnHTPBackendTests, Squeeze_Rank4_Rank3_NegAxes_u8) { + RunQDQSqueezeTestOnHTP("Squeeze", + TestInputDef({1, 3, 2, 1}, false, -10.0f, 10.0f), + TestInputDef({1}, true, {-1}), // Squeeze last axis => (1, 3, 2) + ExpectedEPNodeAssignment::All); +} + +// Test 16-bit QDQ Squeeze of rank 4 -> rank 3 with a negative axes value. +TEST_F(QnnHTPBackendTests, Squeeze_Rank4_Rank3_NegAxes_u16) { + RunQDQSqueezeTestOnHTP("Squeeze", + TestInputDef({1, 3, 2, 1}, false, -10.0f, 10.0f), + TestInputDef({1}, true, {-1}), // Squeeze last axis => (1, 3, 2) + ExpectedEPNodeAssignment::All, + 13, // opset + true); // Use com.microsoft Q/DQ ops +} + +// Test QDQ Unsqueeze of rank 3 -> rank 5. +TEST_F(QnnHTPBackendTests, Unsqueeze_Rank3_Rank5_f32) { + // We can't use the usual model-building functions because they add standalone Quantize and Dequantize nodes + // at the input and output. These Q/DQ ops get lowered to QNN's Quantize and Dequantize operators, which DO NOT + // support rank 5 tensors. Therefore, we have to create a test model that only instantiates the DQ -> Unsqueeze -> Q + // QDQ node group, which gets lowered to a single QNN Reshape node. + GetTestModelFn model_fn = [](ModelTestBuilder& builder) { + // input (u8) -> DQ -> + NodeArg* quant_input = builder.MakeInput({3, 2, 4}, 0, 255); + NodeArg* input_dq = builder.MakeIntermediate(); + builder.AddDequantizeLinearNode(quant_input, 1.0f, 0, input_dq); // scale = 1.0, zp = 0 + + // axes_input -> + NodeArg* axes_input = builder.Make1DInitializer({0, 2}); // Add 1's => (1, 3, 1, 2, 4) + + // Unsqueeze -> + NodeArg* unsqueeze_output = builder.MakeIntermediate(); + builder.AddNode("Unsqueeze", {input_dq, axes_input}, {unsqueeze_output}); + + // Q -> output (u8) + NodeArg* output = builder.MakeOutput(); + builder.AddQuantizeLinearNode(unsqueeze_output, 1.0f, 0, output); // scale = 1.0, zp = 0 + }; + + ProviderOptions provider_options; + +#if defined(_WIN32) + provider_options["backend_path"] = "QnnHtp.dll"; +#else + provider_options["backend_path"] = "libQnnHtp.so"; +#endif + + RunQnnModelTest(model_fn, + provider_options, + 13, // opset + ExpectedEPNodeAssignment::All); +} + +// Test 8-bit QDQ Unsqueeze of rank 3 -> rank 4 with a negative axes value. +TEST_F(QnnHTPBackendTests, Unsqueeze_Rank3_Rank4_NegAxes_u8) { + RunQDQSqueezeTestOnHTP("Unsqueeze", + TestInputDef({1, 3, 2}, false, -10.0f, 10.0f), + TestInputDef({1}, true, {-1}), // Add 1 as last axis => (1, 3, 2, 1) + ExpectedEPNodeAssignment::All); +} + +// Test 16-bit QDQ Unsqueeze of rank 3 -> rank 4 with a negative axes value. +TEST_F(QnnHTPBackendTests, Unsqueeze_Rank3_Rank4_NegAxes_u16) { + RunQDQSqueezeTestOnHTP("Unsqueeze", + TestInputDef({1, 3, 2}, false, -10.0f, 10.0f), + TestInputDef({1}, true, {-1}), // Add 1 as last axis => (1, 3, 2, 1) + ExpectedEPNodeAssignment::All, + 13, // opset + true); // Use com.microsoft Q/DQ ops +} + +// Test that int32 Squeeze runs on HTP backend. +TEST_F(QnnHTPBackendTests, Squeeze_Int32_Rank4_Rank3) { + std::vector input_data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + RunSqueezeTestOnHTP("Squeeze", + TestInputDef({1, 3, 2, 2}, false, input_data), + TestInputDef({1}, true, {0}), // Squeeze 0th axis => (3, 2, 2) + ExpectedEPNodeAssignment::All); +} + +// Test that int32 Unsqueeze runs on HTP backend. +TEST_F(QnnHTPBackendTests, Unsqueeze_Int32_Rank3_Rank4) { + std::vector input_data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + RunSqueezeTestOnHTP("Unsqueeze", + TestInputDef({3, 2, 2}, false, input_data), + TestInputDef({1}, true, {0}), // Unsqueeze 0th axis => (1, 3, 2, 2) + ExpectedEPNodeAssignment::All); +} + +#endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) +} // namespace test +} // namespace onnxruntime +#endif // !defined(ORT_MINIMAL_BUILD) diff --git a/onnxruntime/test/providers/qnn/tile_op_test.cc b/onnxruntime/test/providers/qnn/tile_op_test.cc new file mode 100644 index 0000000000000..2b35c730ee5fe --- /dev/null +++ b/onnxruntime/test/providers/qnn/tile_op_test.cc @@ -0,0 +1,132 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#if !defined(ORT_MINIMAL_BUILD) + +#include + +#include "test/providers/qnn/qnn_test_utils.h" +#include "core/graph/node_attr_utils.h" + +#include "onnx/onnx_pb.h" +#include "gtest/gtest.h" + +namespace onnxruntime { +namespace test { + +// Runs a model with a Tile operator on the QNN CPU backend. Checks the graph node assignment +// and that inference outputs for QNN EP and CPU EP match. +template +static void RunTileTestOnCPU(const TestInputDef& input_def, + const TestInputDef& repeats_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 + + RunQnnModelTest(BuildOpTestCase("Tile", {input_def}, {repeats_def}, {}), + provider_options, + opset, + expected_ep_assignment); +} + +// Test that Tile with a dynamic repeats input is not supported by QNN EP. +TEST_F(QnnCPUBackendTests, Tile_DynamicRepeats_Unsupported) { + RunTileTestOnCPU(TestInputDef({2, 2}, false, {1.0f, 2.0f, 3.0f, 4.0f}), + TestInputDef({2}, false /* is_initializer */, {1, 2}), + ExpectedEPNodeAssignment::None); // Should not be assigned to QNN EP. +} + +// Test that Tile with rank 4 float input. +TEST_F(QnnCPUBackendTests, Tile_F32_Rank4) { + std::vector input_data = {-4.0f, -3.0f, -1.0f, 0.0f, 1.0f, 2.0f, 3.0f, 4.0f}; + RunTileTestOnCPU(TestInputDef({1, 2, 2, 2}, false, input_data), + TestInputDef({4}, true /* is_initializer */, {1, 2, 1, 1}), + ExpectedEPNodeAssignment::All); +} + +#if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) +// +// HTP tests: +// + +// Returns a function that creates a graph with a QDQ Tile operator. +template +GetTestQDQModelFn BuildQDQTileTestCase(const TestInputDef& input_def, + const TestInputDef& repeats_def, + bool use_contrib_qdq = false) { + return [input_def, repeats_def, use_contrib_qdq](ModelTestBuilder& builder, + std::vector>& output_qparams) { + // input -> Q -> DQ -> + NodeArg* input = MakeTestInput(builder, input_def); + QuantParams input_qparams = GetTestInputQuantParams(input_def); + NodeArg* input_qdq = AddQDQNodePair(builder, input, input_qparams.scale, input_qparams.zero_point, + use_contrib_qdq); + + // repeats input + NodeArg* repeats_input = MakeTestInput(builder, repeats_def); + + // Tile op + NodeArg* tile_output = builder.MakeIntermediate(); + builder.AddNode("Tile", {input_qdq, repeats_input}, {tile_output}); + + // op_output -> Q -> DQ -> output + // NOTE: Input and output quantization parameters must be equal for Tile. + output_qparams[0] = input_qparams; // Overwrite! + AddQDQNodePairWithOutputAsGraphOutput(builder, tile_output, input_qparams.scale, + input_qparams.zero_point, use_contrib_qdq); + }; +} + +// Runs a QDQ Tile model on the QNN (HTP) EP and the ORT CPU EP. Checks the graph node assignment and that inference +// running the QDQ model on QNN EP is at least as accurate as on ORT CPU EP (compared to the baseline float32 model). +template +static void RunQDQTileTestOnHTP(const TestInputDef& input_def, + const TestInputDef& repeats_def, + ExpectedEPNodeAssignment expected_ep_assignment, + 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 + + auto f32_model_builder = BuildOpTestCase("Tile", {input_def}, {repeats_def}, {}); + auto qdq_model_builder = BuildQDQTileTestCase(input_def, repeats_def, use_contrib_qdq); + TestQDQModelAccuracy(f32_model_builder, + qdq_model_builder, + provider_options, + opset, + expected_ep_assignment); +} + +// Test 8-bit QDQ Tile with rank 4 input. +TEST_F(QnnHTPBackendTests, Tile_U8_Rank4) { + std::vector input_data = {-4.0f, -3.0f, -1.0f, 0.0f, 1.0f, 2.0f, 3.0f, 4.0f}; + RunQDQTileTestOnHTP(TestInputDef({1, 2, 2, 2}, false, input_data), + TestInputDef({4}, true /* is_initializer */, {1, 2, 1, 1}), + ExpectedEPNodeAssignment::All); +} + +// Test 16-bit QDQ Tile with rank 4 input. +TEST_F(QnnHTPBackendTests, Tile_U16_Rank4) { + std::vector input_data = {-4.0f, -3.0f, -1.0f, 0.0f, 1.0f, 2.0f, 3.0f, 4.0f}; + RunQDQTileTestOnHTP(TestInputDef({1, 2, 2, 2}, false, input_data), + TestInputDef({4}, true /* is_initializer */, {1, 2, 1, 1}), + ExpectedEPNodeAssignment::All, + 13, // opset + true); // Use com.microsoft Q/DQ ops +} + +#endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) +} // namespace test +} // namespace onnxruntime +#endif // !defined(ORT_MINIMAL_BUILD) diff --git a/onnxruntime/test/providers/qnn/topk_op_test.cc b/onnxruntime/test/providers/qnn/topk_op_test.cc new file mode 100644 index 0000000000000..93e725af5f20e --- /dev/null +++ b/onnxruntime/test/providers/qnn/topk_op_test.cc @@ -0,0 +1,209 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#if !defined(ORT_MINIMAL_BUILD) + +#include + +#include "test/providers/qnn/qnn_test_utils.h" +#include "core/graph/node_attr_utils.h" + +#include "onnx/onnx_pb.h" +#include "gtest/gtest.h" + +namespace onnxruntime { +namespace test { + +// Returns a function that builds a model with a TopK operator. +template +inline GetTestModelFn BuildTopKTestCase(const TestInputDef& input_def, + const TestInputDef& k_def, + const std::vector& attrs, + bool cast_output_indices = true) { + return [input_def, k_def, attrs, cast_output_indices](ModelTestBuilder& builder) { + NodeArg* input = MakeTestInput(builder, input_def); + NodeArg* k_input = MakeTestInput(builder, k_def); + + NodeArg* values_output = builder.MakeOutput(); + NodeArg* indices_output = cast_output_indices ? builder.MakeIntermediate() : builder.MakeOutput(); + Node& topk_node = builder.AddNode("TopK", {input, k_input}, {values_output, indices_output}); + + for (const auto& attr : attrs) { + topk_node.AddAttributeProto(attr); + } + + // Cast indices to uint32 + if (cast_output_indices) { + auto* uint32_indices_output = builder.MakeOutput(); + Node& cast_node = builder.AddNode("Cast", {indices_output}, {uint32_indices_output}); + const auto dst_type = ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_UINT32; + cast_node.AddAttribute("to", static_cast(dst_type)); + } + }; +} + +// Runs a model with a TopK operator on the QNN CPU backend. Checks the graph node assignment +// and that inference outputs for QNN EP and CPU EP match. +template +static void RunTopKTestOnCPU(const TestInputDef& input_def, + const TestInputDef& k_def, + const std::vector& attrs, + 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 + + RunQnnModelTest(BuildTopKTestCase(input_def, k_def, attrs, false /*cast_output_indices*/), + provider_options, + opset, + expected_ep_assignment); +} + +// +// CPU tests: +// + +// Test that TopK with a dynamic K input is not supported by QNN EP. +TEST_F(QnnCPUBackendTests, TopK_DynamicK_Unsupported) { + RunTopKTestOnCPU(TestInputDef({1, 3, 4, 4}, false, GetFloatDataInRange(-10.0f, 10.0f, 48)), + TestInputDef({1}, false /* is_initializer */, {2}), + {}, // Attributes + ExpectedEPNodeAssignment::None); // Should not be assigned to QNN EP. +} + +// Test that TopK with an axis attribute that is not the last dimension is not supported by QNN EP. +TEST_F(QnnCPUBackendTests, TopK_NonLastAxis_Unsupported) { + RunTopKTestOnCPU(TestInputDef({1, 3, 4, 4}, false, GetFloatDataInRange(-10.0f, 10.0f, 48)), + TestInputDef({1}, true /* is_initializer */, {2}), + {utils::MakeAttribute("axis", static_cast(1))}, + ExpectedEPNodeAssignment::None); // Should not be assigned to QNN EP. +} + +// Test that TopK that returns the top k minimum values is not supported by QNN EP. +TEST_F(QnnCPUBackendTests, TopK_MinValues_Unsupported) { + RunTopKTestOnCPU(TestInputDef({1, 3, 4, 4}, false, GetFloatDataInRange(-10.0f, 10.0f, 48)), + TestInputDef({1}, true /* is_initializer */, {2}), + {utils::MakeAttribute("largest", static_cast(0))}, + ExpectedEPNodeAssignment::None); // Should not be assigned to QNN EP. +} + +// Test TopK on CPU backend: top 2 largest floats from last axis +TEST_F(QnnCPUBackendTests, TopK_LargestFloats_LastAxis) { + RunTopKTestOnCPU(TestInputDef({1, 3, 4, 4}, false, GetFloatDataInRange(-10.0f, 10.0f, 48)), + TestInputDef({1}, true /* is_initializer */, {2}), + {}, // Attributes + ExpectedEPNodeAssignment::All); +} + +// Test TopK on CPU backend: top 2 largest int32s from last axis +TEST_F(QnnCPUBackendTests, TopK_LargestInt32s_LastAxis) { + std::vector input_data = {-6, -5, -4, -3, -2, 0, 1, 2, 3, 4, 5, 6}; + RunTopKTestOnCPU(TestInputDef({1, 2, 2, 3}, false, input_data), + TestInputDef({1}, true /* is_initializer */, {2}), + {}, // Attributes + ExpectedEPNodeAssignment::All); +} + +#if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) +// +// HTP tests: +// + +// Returns a function that creates a graph with a QDQ TopK operator. +template +GetTestQDQModelFn BuildQDQTopKTestCase(const TestInputDef& input_def, + const TestInputDef& k_def, + const std::vector& attrs, + bool use_contrib_qdq = false) { + return [input_def, k_def, attrs, use_contrib_qdq](ModelTestBuilder& builder, + std::vector>& output_qparams) { + // input -> Q -> DQ -> + NodeArg* input = MakeTestInput(builder, input_def); + QuantParams input_qparams = GetTestInputQuantParams(input_def); + NodeArg* input_qdq = AddQDQNodePair(builder, input, input_qparams.scale, input_qparams.zero_point, + use_contrib_qdq); + + // K input + NodeArg* k_input = MakeTestInput(builder, k_def); + + // Reshape op + NodeArg* values_output = builder.MakeIntermediate(); + NodeArg* indices_output = builder.MakeIntermediate(); + Node& topk_node = builder.AddNode("TopK", {input_qdq, k_input}, {values_output, indices_output}); + + for (const auto& attr : attrs) { + topk_node.AddAttributeProto(attr); + } + + // op_output -> Q -> DQ -> output + // NOTE: Input and output quantization parameters must be equal for Reshape. + output_qparams[0] = input_qparams; // Overwrite! + AddQDQNodePairWithOutputAsGraphOutput(builder, values_output, input_qparams.scale, + input_qparams.zero_point, use_contrib_qdq); + + // Cast indices to uint32 (HTP backend does not support int64 graph outputs) + auto* uint32_indices_output = builder.MakeOutput(); + Node& cast_node = builder.AddNode("Cast", {indices_output}, {uint32_indices_output}); + const auto dst_type = ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_UINT32; + cast_node.AddAttribute("to", static_cast(dst_type)); + }; +} + +// Runs a QDQ TopK model on the QNN (HTP) EP and the ORT CPU EP. Checks the graph node assignment and that inference +// running the QDQ model on QNN EP is at least as accurate as on ORT CPU EP (compared to the baseline float32 model). +template +static void RunQDQTopKTestOnHTP(const TestInputDef& input_def, + const TestInputDef& k_def, + const std::vector& attrs, + ExpectedEPNodeAssignment expected_ep_assignment, + int opset = 19, + 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 + + auto f32_model_builder = BuildTopKTestCase(input_def, k_def, attrs, true /*cast_output_indices*/); + auto qdq_model_builder = BuildQDQTopKTestCase(input_def, k_def, attrs, use_contrib_qdq); + TestQDQModelAccuracy(f32_model_builder, + qdq_model_builder, + provider_options, + opset, + expected_ep_assignment); +} + +// Test 8-bit QDQ TopK on HTP backend: top 2 largest floats from last axis +TEST_F(QnnHTPBackendTests, TopK_LargestFloats_U8_LastAxis) { + RunQDQTopKTestOnHTP(TestInputDef({1, 3, 4, 4}, false, GetFloatDataInRange(-10.0f, 10.0f, 48)), + TestInputDef({1}, true /* is_initializer */, {2}), + {}, // Attributes + ExpectedEPNodeAssignment::All); +} + +// Test 16-bit QDQ TopK on HTP backend: top 2 largest floats from last axis +// TODO: Inaccuracy detected for output 'output_0', element 6. +// Output quant params: scale=0.00061036087572574615, zero_point=32768. +// Expected val: -7.2340402603149414 +// QNN QDQ val: -17.446556091308594 (err 10.212515830993652) +// CPU QDQ val: -7.2339968681335449 (err 4.3392181396484375e-05) +TEST_F(QnnHTPBackendTests, DISABLED_TopK_LargestFloats_U16_LastAxis) { + RunQDQTopKTestOnHTP(TestInputDef({1, 3, 4, 4}, false, GetFloatDataInRange(-20.0f, 20.0f, 48)), + TestInputDef({1}, true /* is_initializer */, {2}), + {}, // Attributes + ExpectedEPNodeAssignment::All, + 19, // opset + true); // Use com.microsoft Q/DQ ops +} + +#endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) +} // namespace test +} // namespace onnxruntime +#endif // !defined(ORT_MINIMAL_BUILD) diff --git a/onnxruntime/test/providers/qnn/transpose_htp_test.cc b/onnxruntime/test/providers/qnn/transpose_htp_test.cc new file mode 100644 index 0000000000000..8d8c1ebb0fd15 --- /dev/null +++ b/onnxruntime/test/providers/qnn/transpose_htp_test.cc @@ -0,0 +1,135 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#if !defined(ORT_MINIMAL_BUILD) + +#include +#include "core/graph/graph.h" +#include "core/graph/node_attr_utils.h" + +#include "test/optimizer/qdq_test_utils.h" +#include "test/providers/qnn/qnn_test_utils.h" + +#include "gtest/gtest.h" + +namespace onnxruntime { +namespace test { +#if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) + +// Function that builds a model with a Transpose operator. +template +GetTestModelFn BuildTransposeTestCase(const TestInputDef& input_def, + const std::vector& attrs) { + return [input_def, attrs](ModelTestBuilder& builder) { + NodeArg* input = MakeTestInput(builder, input_def); + + NodeArg* output = builder.MakeOutput(); + Node& test_node = builder.AddNode("Transpose", {input}, {output}); + + for (const auto& attr : attrs) { + test_node.AddAttributeProto(attr); + } + }; +} + +// Function that builds a QDQ model with a Transpose operator. +template +static GetTestQDQModelFn BuildQDQTransposeTestCase(const TestInputDef& input_def, + const std::vector& attrs) { + return [input_def, attrs](ModelTestBuilder& builder, std::vector>& output_qparams) { + NodeArg* input = MakeTestInput(builder, input_def); + QuantParams input_qparams = GetTestInputQuantParams(input_def); + NodeArg* input_qdq = AddQDQNodePair(builder, input, input_qparams.scale, input_qparams.zero_point); + + auto* output = builder.MakeIntermediate(); + Node& test_node = builder.AddNode("Transpose", {input_qdq}, {output}); + + for (const auto& attr : attrs) { + test_node.AddAttributeProto(attr); + } + + AddQDQNodePairWithOutputAsGraphOutput(builder, output, output_qparams[0].scale, output_qparams[0].zero_point); + }; +} + +/** + * Runs an Transpose model on the QNN HTP backend. Checks the QDQ graph node assignment, and that inference + * outputs for QNN and CPU match. + * + * \param input_def The data (int32_t) input's definition (shape, is_initializer, data). + * \attrs node attributes + * \param expected_ep_assignment How many nodes are expected to be assigned to QNN (All, Some, or None). + */ +template +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 + + // Runs model with DQ-> Transpose -> Q and compares the outputs of the CPU and QNN EPs. + TestQDQModelAccuracy(BuildTransposeTestCase(input_def, attrs), + BuildQDQTransposeTestCase(input_def, attrs), + provider_options, + 18, + expected_ep_assignment, + 1e-5f); +} + +/** + * Runs an Transpose model on the QNN HTP backend. Checks the graph node assignment, and that inference + * outputs for QNN and CPU match. + * + * \param input_def The data (int32_t) input's definition (shape, is_initializer, data). + * \attrs node attributes + * \param expected_ep_assignment How many nodes are expected to be assigned to QNN (All, Some, or None). + */ +template +static void RunTransposeNonQDQOnHTP(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 + + RunQnnModelTest(BuildTransposeTestCase(input_def, attrs), + provider_options, + 13, + expected_ep_assignment, + 1e-5f); +} + +// Check that QNN compiles DQ -> Transpose -> Q as a single unit. +TEST_F(QnnHTPBackendTests, TransposeQDQU8) { + RunTransposeQDQTest(TestInputDef({1, 3, 224, 128}, false, 0.0f, 1.0f), + {utils::MakeAttribute("perm", std::vector{0, 2, 3, 1})}, + ExpectedEPNodeAssignment::All); +} + +// Check that QNN supports Transpose with int32 data input on HTP +TEST_F(QnnHTPBackendTests, TransposeInt32OnHTP) { + RunTransposeNonQDQOnHTP(TestInputDef({1, 3, 224, 128}, false, -100, 100), + {utils::MakeAttribute("perm", std::vector{0, 2, 3, 1})}, + ExpectedEPNodeAssignment::All); +} + +// Check that QNN supports Transpose with float32 data input on HTP +TEST_F(QnnHTPBackendTests, TransposeFloatOnHTP) { + RunTransposeNonQDQOnHTP(TestInputDef({1, 3, 224, 128}, false, 0, 10.0f), + {utils::MakeAttribute("perm", std::vector{0, 2, 3, 1})}, + ExpectedEPNodeAssignment::All); +} + +#endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) + +} // namespace test +} // namespace onnxruntime + +#endif \ No newline at end of file diff --git a/onnxruntime/test/providers/qnn/where_htp_test.cc b/onnxruntime/test/providers/qnn/where_htp_test.cc new file mode 100644 index 0000000000000..49f3ef0fd983a --- /dev/null +++ b/onnxruntime/test/providers/qnn/where_htp_test.cc @@ -0,0 +1,141 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#if !defined(ORT_MINIMAL_BUILD) + +#include +#include "core/graph/graph.h" +#include "core/graph/node_attr_utils.h" + +#include "test/optimizer/qdq_test_utils.h" +#include "test/providers/qnn/qnn_test_utils.h" + +#include "gtest/gtest.h" + +namespace onnxruntime { +namespace test { +#if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) + +// Function that builds a float32 model with a Where operator. +GetTestModelFn BuildWhereTestCase(const TestInputDef& condition_def, + const TestInputDef& x_def, + const TestInputDef& y_def) { + return [condition_def, x_def, y_def](ModelTestBuilder& builder) { + NodeArg* condition = MakeTestInput(builder, condition_def); + NodeArg* x = MakeTestInput(builder, x_def); + NodeArg* y = MakeTestInput(builder, y_def); + + NodeArg* output = builder.MakeOutput(); + builder.AddNode("Where", {condition, x, y}, {output}); + }; +} + +// Function that builds a QDQ model with a Where operator. +template +static GetTestQDQModelFn BuildQDQWhereTestCase(const TestInputDef& condition_def, + const TestInputDef& x_def, + const TestInputDef& y_def) { + return [condition_def, x_def, y_def](ModelTestBuilder& builder, + std::vector>& output_qparams) { + // condition + NodeArg* condition = MakeTestInput(builder, condition_def); + + // x => Q => DQ => + NodeArg* x = MakeTestInput(builder, x_def); + QuantParams x_qparams = GetTestInputQuantParams(x_def); + NodeArg* x_qdq = AddQDQNodePair(builder, x, x_qparams.scale, x_qparams.zero_point); + + // y => Q => DQ => + NodeArg* y = MakeTestInput(builder, y_def); + QuantParams y_qparams = GetTestInputQuantParams(y_def); + NodeArg* y_qdq = AddQDQNodePair(builder, y, y_qparams.scale, y_qparams.zero_point); + + // Where operator. + auto* where_output = builder.MakeIntermediate(); + builder.AddNode("Where", {condition, x_qdq, y_qdq}, {where_output}); + + // Add output -> Q -> output_u8 + AddQDQNodePairWithOutputAsGraphOutput(builder, where_output, output_qparams[0].scale, output_qparams[0].zero_point); + }; +} + +/** + * Runs an Where model on the QNN HTP backend. Checks the graph node assignment, and that inference + * outputs for QNN and CPU match. + * + * \param condition_def The condition input's definition (shape, is_initializer, data). + * \param x_def The x input's definition. + * \param y_def The y input's definition. + * \param expected_ep_assignment How many nodes are expected to be assigned to QNN (All, Some, or None). + */ +template +static void RunWhereQDQTest(const TestInputDef& condition_def, + const TestInputDef& x_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 + + // Runs model with DQ-> Where -> Q and compares the outputs of the CPU and QNN EPs. + TestQDQModelAccuracy(BuildWhereTestCase(condition_def, x_def, y_def), + BuildQDQWhereTestCase(condition_def, x_def, y_def), + provider_options, + 18, + expected_ep_assignment, + 1e-5f); +} + +// Check that QNN compiles DQ -> Where -> Q as a single unit. +TEST_F(QnnHTPBackendTests, WhereQDQU8) { + RunWhereQDQTest(TestInputDef({4, 3, 2}, false, + {true, false, true, false, true, false, + true, false, true, false, true, false, + true, false, true, false, true, false, + true, false, true, false, true, false}), + TestInputDef({4, 3, 2}, true, 0.0f, 2.0f), + TestInputDef({4, 3, 2}, true, 2.0f, 3.0), + ExpectedEPNodeAssignment::All); +} + +// Check that QNN compiles DQ -> Where -> Q as a single unit. +// Check QNN Where works with broadcast +TEST_F(QnnHTPBackendTests, WhereBroadcastU8) { + RunWhereQDQTest(TestInputDef({2}, false, {true, false}), + TestInputDef({4, 3, 2}, true, -2.0f, 2.0f), + TestInputDef({1}, true, {3.0f}), + ExpectedEPNodeAssignment::All); +} + +// Check that QNN compiles DQ -> Where -> Q as a single unit. +// Large data broadcast, QNN v2.13 failed +TEST_F(QnnHTPBackendTests, WhereLargeDataU8) { + RunWhereQDQTest(TestInputDef({5120}, false, false, true), + TestInputDef({1, 16, 64, 5120}, true, -5000.0f, 0.0f), + TestInputDef({1, 16, 64, 5120}, true, 0.0f, 5000.0f), + ExpectedEPNodeAssignment::All); +} + +// Check that QNN compiles DQ -> Where -> Q as a single unit. +// Large data broadcast, QNN v2.13 failed to finalize graph +// C:\qnn_src\QNN\HTP\HTP\src\hexagon\prepare\seq\initial_sequencer_dp.cc:156:ERROR:A single op, +// "q::Broadcast" (Op ID: 19c700000012), requires 0x500800 bytes of TCM, which is greater than the TCM size of 0x400000! +// QnnDsp graph prepare failed 13 +// QnnDsp Failed to finalize graph QNN_4851394333842096633_1 with err: 1002 +// QnnDsp Failed to finalize graph (id: 1) with err 1002 +TEST_F(QnnHTPBackendTests, DISABLED_WhereLargeDataBroadcastU8) { + RunWhereQDQTest(TestInputDef({5120}, false, false, true), + TestInputDef({1, 16, 64, 5120}, true, 0.0f, 1.0f), + TestInputDef({1}, true, {3.0f}), + ExpectedEPNodeAssignment::All); +} + +#endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) + +} // namespace test +} // namespace onnxruntime + +#endif \ No newline at end of file diff --git a/onnxruntime/test/providers/rknpu/rknpu_basic_test.cc b/onnxruntime/test/providers/rknpu/rknpu_basic_test.cc index d86d11734e3d4..63a672615c27b 100644 --- a/onnxruntime/test/providers/rknpu/rknpu_basic_test.cc +++ b/onnxruntime/test/providers/rknpu/rknpu_basic_test.cc @@ -60,12 +60,13 @@ TEST(RknpuExecutionProviderTest, FunctionTest) { std::vector dims_mul_x = {1, 1, 3, 2}; std::vector values_mul_x = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; + AllocatorPtr cpu_allocator = std::make_shared(); OrtValue ml_value_x; - CreateMLValue(TestRknpuExecutionProvider()->GetAllocator(OrtMemTypeDefault), dims_mul_x, values_mul_x, &ml_value_x); + CreateMLValue(cpu_allocator, dims_mul_x, values_mul_x, &ml_value_x); OrtValue ml_value_y; - CreateMLValue(TestRknpuExecutionProvider()->GetAllocator(OrtMemTypeDefault), dims_mul_x, values_mul_x, &ml_value_y); + CreateMLValue(cpu_allocator, dims_mul_x, values_mul_x, &ml_value_y); OrtValue ml_value_z; - CreateMLValue(TestRknpuExecutionProvider()->GetAllocator(OrtMemTypeDefault), dims_mul_x, values_mul_x, &ml_value_z); + CreateMLValue(cpu_allocator, dims_mul_x, values_mul_x, &ml_value_z); NameMLValMap feeds; feeds.insert(std::make_pair("X", ml_value_x)); feeds.insert(std::make_pair("Y", ml_value_y)); diff --git a/onnxruntime/test/providers/tensorrt/tensorrt_basic_test.cc b/onnxruntime/test/providers/tensorrt/tensorrt_basic_test.cc index 1dc34eed3d211..288cdfca2b56d 100644 --- a/onnxruntime/test/providers/tensorrt/tensorrt_basic_test.cc +++ b/onnxruntime/test/providers/tensorrt/tensorrt_basic_test.cc @@ -38,7 +38,8 @@ void VerifyOutputs(const std::vector& fetches, const std::vector& fetches, const std::vector dims) { +void CreateBaseModel(std::string model_name, + std::string graph_name, + std::vector dims, + bool add_non_zero_node = false) { onnxruntime::Model model(graph_name, false, DefaultLoggingManager().DefaultLogger()); auto& graph = model.MainGraph(); std::vector inputs; @@ -80,10 +95,27 @@ void CreateBaseModel(std::string model_name, std::string graph_name, std::vector inputs.clear(); inputs.push_back(&output_arg); inputs.push_back(&input_arg_3); - auto& output_arg_2 = graph.GetOrCreateNodeArg("M", &float_tensor); - outputs.clear(); - outputs.push_back(&output_arg_2); - graph.AddNode("node_2", "Add", "node 2.", inputs, outputs); + + if (add_non_zero_node) { + auto& output_arg_2 = graph.GetOrCreateNodeArg("node_2_out_1", &float_tensor); + outputs.clear(); + outputs.push_back(&output_arg_2); + graph.AddNode("node_2", "Add", "node 2.", inputs, outputs); + + inputs.clear(); + inputs.push_back(&output_arg_2); + ONNX_NAMESPACE::TypeProto int_tensor; + int_tensor.mutable_tensor_type()->set_elem_type(ONNX_NAMESPACE::TensorProto_DataType_INT64); + auto& output_arg_3 = graph.GetOrCreateNodeArg("M", &int_tensor); + outputs.clear(); + outputs.push_back(&output_arg_3); + graph.AddNode("node_3", "NonZero", "node 3.", inputs, outputs); + } else { + auto& output_arg_2 = graph.GetOrCreateNodeArg("M", &float_tensor); + outputs.clear(); + outputs.push_back(&output_arg_2); + graph.AddNode("node_2", "Add", "node 2.", inputs, outputs); + } auto status = graph.Resolve(); ASSERT_TRUE(status.IsOK()); @@ -102,16 +134,26 @@ void RunSession(InferenceSession& session_object, VerifyOutputs(fetches, expected_dims, expected_values); } +void RunSession2(InferenceSession& session_object, + RunOptions& run_options, + NameMLValMap& feeds, + std::vector output_names, + std::vector expected_dims, + std::vector expected_values) { + std::vector fetches; + auto status = session_object.Run(run_options, feeds, output_names, &fetches); + ASSERT_TRUE(status.IsOK()); + VerifyOutputs(fetches, expected_dims, expected_values); +} + void RunWithOneSessionSingleThreadInference(std::string model_name, std::string sess_log_id) { SessionOptions so; so.session_logid = sess_log_id; RunOptions run_options; run_options.run_tag = so.session_logid; InferenceSession session_object{so, GetEnvironment()}; - onnxruntime::AllocatorManager allocator_manager; auto cuda_provider = DefaultCudaExecutionProvider(); - cuda_provider->RegisterAllocator(allocator_manager); - auto cpu_allocator = cuda_provider->GetAllocator(OrtMemTypeCPU); + auto cpu_allocator = cuda_provider->CreatePreferredAllocators()[1]; std::vector dims_mul_x = {1, 3, 2}; std::vector values_mul_x = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; OrtValue ml_value_x; @@ -159,10 +201,14 @@ void RunWithOneSessionSingleThreadInference(std::string model_name, std::string 0, 0, 0, - 2, + 3, -1, nullptr, - nullptr}; + nullptr, + nullptr, + nullptr, + nullptr, + 0}; params.trt_engine_cache_enable = 1; std::unique_ptr execution_provider = TensorrtExecutionProviderWithOptions(¶ms); @@ -182,16 +228,14 @@ void RunWithOneSessionSingleThreadInference(std::string model_name, std::string RunSession(session_object, run_options, feeds, output_names, expected_dims_mul_m, expected_values_mul_m); } -void RunWithOneSessionMultiThreadsInference(std::string model_name, std::string sess_log_id) { +void RunWithOneSessionMultiThreadsInference(std::string model_name, std::string sess_log_id, bool has_non_zero_node = false) { SessionOptions so; so.session_logid = sess_log_id; RunOptions run_options; run_options.run_tag = so.session_logid; InferenceSession session_object{so, GetEnvironment()}; - onnxruntime::AllocatorManager allocator_manager; auto cuda_provider = DefaultCudaExecutionProvider(); - cuda_provider->RegisterAllocator(allocator_manager); - auto cpu_allocator = cuda_provider->GetAllocator(OrtMemTypeCPU); + auto cpu_allocator = cuda_provider->CreatePreferredAllocators()[1]; std::vector dims_mul_x = {1, 3, 2}; std::vector values_mul_x = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; OrtValue ml_value_x; @@ -212,6 +256,8 @@ void RunWithOneSessionMultiThreadsInference(std::string model_name, std::string // prepare expected inputs and outputs std::vector expected_dims_mul_m = {1, 3, 2}; std::vector expected_values_mul_m = {3.0f, 6.0f, 9.0f, 12.0f, 15.0f, 18.0f}; + std::vector expected_dims_nonzero_m = {3, 6}; + std::vector expected_values_nonzero_m = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 0, 1, 0, 1, 0, 1}; OrtTensorRTProviderOptionsV2 params{ 0, @@ -239,10 +285,14 @@ void RunWithOneSessionMultiThreadsInference(std::string model_name, std::string 0, 0, 0, - 2, + 3, -1, nullptr, - nullptr}; + nullptr, + nullptr, + nullptr, + nullptr, + 0}; params.trt_engine_cache_enable = 1; std::unique_ptr execution_provider = TensorrtExecutionProviderWithOptions(¶ms); @@ -262,8 +312,12 @@ void RunWithOneSessionMultiThreadsInference(std::string model_name, std::string std::vector threads; int num_thread = 5; - for (int i = 0; i < num_thread; ++i) - threads.push_back(std::thread(RunSession, std::ref(session_object), std::ref(run_options), std::ref(feeds), std::ref(output_names), std::ref(expected_dims_mul_m), std::ref(expected_values_mul_m))); + for (int i = 0; i < num_thread; ++i) { + if (has_non_zero_node) + threads.push_back(std::thread(RunSession2, std::ref(session_object), std::ref(run_options), std::ref(feeds), std::ref(output_names), std::ref(expected_dims_nonzero_m), std::ref(expected_values_nonzero_m))); + else + threads.push_back(std::thread(RunSession, std::ref(session_object), std::ref(run_options), std::ref(feeds), std::ref(output_names), std::ref(expected_dims_mul_m), std::ref(expected_values_mul_m))); + } for (auto& th : threads) th.join(); @@ -294,6 +348,12 @@ TEST(TensorrtExecutionProviderTest, SessionCreationWithSingleThreadAndInferenceW CreateBaseModel(model_name, graph_name, dims); RunWithOneSessionMultiThreadsInference(model_name, sess_log_id); + + // In addition to the test case that whole model can be run by TRT, we also need to test the case where + // the model is partitioned into TRT EP and CUDA EP subgraphs. + // We did observe synchronization issue for TRT EP without PerContextThread implementation running those models. + CreateBaseModel(model_name, graph_name, dims, true); + RunWithOneSessionMultiThreadsInference(model_name, sess_log_id, true); } // Test loading same model in different way, when hash id is generated via model name/model content/env metadata @@ -342,10 +402,8 @@ TEST(TensorrtExecutionProviderTest, TRTPluginsCustomOpTest) { RunOptions run_options; run_options.run_tag = so.session_logid; InferenceSession session_object{so, GetEnvironment()}; - onnxruntime::AllocatorManager allocator_manager; auto cuda_provider = DefaultCudaExecutionProvider(); - cuda_provider->RegisterAllocator(allocator_manager); - auto cpu_allocator = cuda_provider->GetAllocator(OrtMemTypeCPU); + auto cpu_allocator = cuda_provider->CreatePreferredAllocators()[1]; std::vector dims_op_x = {12, 256, 256}; std::vector values_op_x(1.0f, 786432); // 786432=12*256*256 OrtValue ml_value_x; @@ -390,10 +448,14 @@ TEST(TensorrtExecutionProviderTest, TRTPluginsCustomOpTest) { 0, 0, 0, - 2, + 3, -1, nullptr, - nullptr}; + nullptr, + nullptr, + nullptr, + nullptr, + 0}; std::unique_ptr execution_provider = TensorrtExecutionProviderWithOptions(¶ms); EXPECT_TRUE(session_object.RegisterExecutionProvider(std::move(execution_provider)).IsOK()); @@ -430,10 +492,8 @@ TEST_P(TensorrtExecutionProviderCacheTest, Run) { RunOptions run_options; run_options.run_tag = so.session_logid; InferenceSession session_object{so, GetEnvironment()}; - onnxruntime::AllocatorManager allocator_manager; auto cuda_provider = DefaultCudaExecutionProvider(); - cuda_provider->RegisterAllocator(allocator_manager); - auto cpu_allocator = cuda_provider->GetAllocator(OrtMemTypeCPU); + auto cpu_allocator = cuda_provider->CreatePreferredAllocators()[1]; std::vector dims_mul_x = {1, 3, 2}; std::vector values_mul_x = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; OrtValue ml_value_x; @@ -482,10 +542,14 @@ TEST_P(TensorrtExecutionProviderCacheTest, Run) { 0, 0, 0, - 2, + 3, -1, nullptr, - nullptr}; + nullptr, + nullptr, + nullptr, + nullptr, + 0}; if (cache_type.compare("engine") == 0) { /* Following code block tests the functionality of engine and optimization profile of ORT TRT, including: @@ -509,9 +573,9 @@ TEST_P(TensorrtExecutionProviderCacheTest, Run) { // TRT engine will be created and cached // TRT profile will be created and cached only for dynamic input shape // Data in profile, - // X: 1, 3, 3, 2, 2, 2 - // Y: 1, 3, 3, 2, 2, 2 - // Z: 1, 3, 3, 2, 2, 2 + // X: 1, 3, 3, 3, 2, 2, 2, 2 + // Y: 1, 3, 3, 3, 2, 2, 2, 2 + // Z: 1, 3, 3, 3, 2, 2, 2, 2 status = session_object.Run(run_options, feeds, output_names, &fetches); ASSERT_TRUE(status.IsOK()); VerifyOutputs(fetches, expected_dims_mul_m, expected_values_mul_m); @@ -528,18 +592,20 @@ TEST_P(TensorrtExecutionProviderCacheTest, Run) { profile_files = GetCachesByType("./", ".profile"); ASSERT_EQ(profile_files.size(), 1); std::ifstream profile_file(profile_files[0], std::ios::binary | std::ios::in); - auto shape_ranges = DeserializeProfile(profile_file); + auto shape_ranges = DeserializeProfileV2(profile_file); - // check min/max shape ranges of dynamic shape dimensions + // check min/max/opt shape ranges of dynamic shape dimensions for (auto it = shape_ranges.cbegin(); it != shape_ranges.cend(); ++it) { auto ranges = it->second; for (auto it2 = ranges.cbegin(); it2 != ranges.cend(); ++it2) { if (it2->first == 1) { - ASSERT_EQ(it2->second.first, 3); - ASSERT_EQ(it2->second.second, 3); + ASSERT_EQ(it2->second[0][0], 3); + ASSERT_EQ(it2->second[0][1], 3); + ASSERT_EQ(it2->second[0][2], 3); } else if (it2->first == 2) { - ASSERT_EQ(it2->second.first, 2); - ASSERT_EQ(it2->second.second, 2); + ASSERT_EQ(it2->second[0][0], 2); + ASSERT_EQ(it2->second[0][1], 2); + ASSERT_EQ(it2->second[0][2], 2); } } } @@ -548,9 +614,9 @@ TEST_P(TensorrtExecutionProviderCacheTest, Run) { // another inference run with input shape {1, 1, 6} // TRT engine and profile will be updated // Data in profile, - // X: 1, 1, 3, 2, 2, 6 - // Y: 1, 1, 3, 2, 2, 6 - // Z: 1, 1, 3, 2, 2, 6 + // X: 1, 1, 3, 3, 2, 2, 6, 6 + // Y: 1, 1, 3, 3, 2, 2, 6, 6 + // Z: 1, 1, 3, 3, 2, 2, 6, 6 dims_mul_x = {1, 1, 6}; CreateMLValue(cpu_allocator, dims_mul_x, values_mul_x, &ml_value_x); CreateMLValue(cpu_allocator, dims_mul_x, values_mul_x, &ml_value_y); @@ -578,22 +644,78 @@ TEST_P(TensorrtExecutionProviderCacheTest, Run) { profile_files = GetCachesByType("./", ".profile"); ASSERT_EQ(profile_files.size(), 1); std::ifstream profile_file2(profile_files[0], std::ios::binary | std::ios::in); - auto shape_ranges2 = DeserializeProfile(profile_file2); + auto shape_ranges2 = DeserializeProfileV2(profile_file2); - // check min/max shape ranges of dynamic shape dimensions + // check min/max/opt shape ranges of dynamic shape dimensions for (auto it = shape_ranges2.cbegin(); it != shape_ranges2.cend(); ++it) { auto ranges = it->second; for (auto it2 = ranges.cbegin(); it2 != ranges.cend(); ++it2) { if (it2->first == 1) { - ASSERT_EQ(it2->second.first, 1); - ASSERT_EQ(it2->second.second, 3); + ASSERT_EQ(it2->second[0][0], 1); + ASSERT_EQ(it2->second[0][1], 3); + ASSERT_EQ(it2->second[0][2], 3); } else if (it2->first == 2) { - ASSERT_EQ(it2->second.first, 2); - ASSERT_EQ(it2->second.second, 6); + ASSERT_EQ(it2->second[0][0], 2); + ASSERT_EQ(it2->second[0][1], 6); + ASSERT_EQ(it2->second[0][2], 6); } } } } + + // Test explicit min/max/opt profile shapes + // create another session object with TRT EP provider options: + // trt_profile_min_shapes=X:1x1x1,Y:1x1x1,Z:1x1x1 + // trt_profile_max_shapes=X:1x6x6,Y:1x6x6,Z:1x6x6 + // trt_profile_opt_shapes=X:1x2x3,Y:1x2x3,Z:1x2x3 + // + // TRT engine and profile will be updated + // Data in profile, + // X: 1, 1, 6, 2, 2, 1, 6, 3 + // Y: 1, 1, 6, 2, 2, 1, 6, 3 + // Y: 1, 1, 6, 2, 2, 1, 6, 3 + InferenceSession session_object2{so, GetEnvironment()}; + params.trt_profile_min_shapes = "X:1x1x1,Y:1x1x1,Z:1x1x1"; + params.trt_profile_max_shapes = "X:1x6x6,Y:1x6x6,Z:1x6x6"; + params.trt_profile_opt_shapes = "X:1x2x3,Y:1x2x3,Z:1x2x3"; + std::unique_ptr execution_provider2 = TensorrtExecutionProviderWithOptions(¶ms); + EXPECT_TRUE(session_object2.RegisterExecutionProvider(std::move(execution_provider2)).IsOK()); + status = session_object2.Load(model_name); + ASSERT_TRUE(status.IsOK()); + status = session_object2.Initialize(); + ASSERT_TRUE(status.IsOK()); + + status = session_object2.Run(run_options, feeds, output_names, &fetches); + + if (input_type.compare("static") == 0) { + // Can't run inference since input shape changes but the engine is built with static input + ASSERT_FALSE(status.IsOK()); + } else { + ASSERT_TRUE(status.IsOK()); + VerifyOutputs(fetches, expected_dims_mul_m, expected_values_mul_m); + + profile_files = GetCachesByType("./", ".profile"); + ASSERT_EQ(profile_files.size(), 1); + std::ifstream profile_file2(profile_files[0], std::ios::binary | std::ios::in); + auto shape_ranges2 = DeserializeProfileV2(profile_file2); + + // check min/max/opt shape ranges of dynamic shape dimensions + for (auto it = shape_ranges2.cbegin(); it != shape_ranges2.cend(); ++it) { + auto ranges = it->second; + for (auto it2 = ranges.cbegin(); it2 != ranges.cend(); ++it2) { + if (it2->first == 1) { + ASSERT_EQ(it2->second[0][0], 1); + ASSERT_EQ(it2->second[0][1], 6); + ASSERT_EQ(it2->second[0][2], 2); + } else if (it2->first == 2) { + ASSERT_EQ(it2->second[0][0], 1); + ASSERT_EQ(it2->second[0][1], 6); + ASSERT_EQ(it2->second[0][2], 3); + } + } + } + } + } else if (cache_type.compare("timing") == 0) { /* Following code block tests the functionality of timing cache, including: * - timing cache cache serialization/de-serialization @@ -712,10 +834,8 @@ TEST(TensorrtExecutionProviderTest, FunctionTest) { run_options.run_tag = so.session_logid; InferenceSession session_object{so, GetEnvironment()}; - onnxruntime::AllocatorManager allocator_manager; auto cuda_provider = DefaultCudaExecutionProvider(); - cuda_provider->RegisterAllocator(allocator_manager); - auto cpu_allocator = cuda_provider->GetAllocator(OrtMemTypeCPU); + auto cpu_allocator = cuda_provider->CreatePreferredAllocators()[1]; std::vector dims_mul_x = {1, 3, 2}; std::vector values_mul_x = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; @@ -816,10 +936,8 @@ TEST(TensorrtExecutionProviderTest, DISABLED_NodeIndexMappingTest) { // [W:onn run_options.run_tag = so.session_logid; InferenceSession session_object{so, GetEnvironment()}; - onnxruntime::AllocatorManager allocator_manager; auto cuda_provider = DefaultCudaExecutionProvider(); - cuda_provider->RegisterAllocator(allocator_manager); - auto cpu_allocator = cuda_provider->GetAllocator(OrtMemTypeCPU); + auto cpu_allocator = cuda_provider->CreatePreferredAllocators()[1]; std::vector dims_mul_x = {1, 3, 2}; std::vector values_mul_x = {true, false, true, false, true, false}; @@ -937,10 +1055,8 @@ TEST(TensorrtExecutionProviderTest, RemoveCycleTest) { run_options.run_tag = so.session_logid; InferenceSession session_object{so, GetEnvironment()}; - onnxruntime::AllocatorManager allocator_manager; auto cuda_provider = DefaultCudaExecutionProvider(); - cuda_provider->RegisterAllocator(allocator_manager); - auto cpu_allocator = cuda_provider->GetAllocator(OrtMemTypeCPU); + auto cpu_allocator = cuda_provider->CreatePreferredAllocators()[1]; OrtValue ml_value_x; CreateMLValue(cpu_allocator, dims_mul_x, values_mul_x, &ml_value_x); diff --git a/onnxruntime/test/providers/tester_types.h b/onnxruntime/test/providers/tester_types.h new file mode 100644 index 0000000000000..efab5805743d5 --- /dev/null +++ b/onnxruntime/test/providers/tester_types.h @@ -0,0 +1,141 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once +#include "core/framework/tensor.h" +#include "core/framework/TensorSeq.h" + +namespace onnxruntime { +namespace test { + +template +struct TTypeProto { + explicit TTypeProto(const std::vector* shape = nullptr) { + proto.mutable_tensor_type()->set_elem_type(utils::ToTensorProtoElementType()); + if (shape) { + auto mutable_shape = proto.mutable_tensor_type()->mutable_shape(); + for (auto i : *shape) { + auto* mutable_dim = mutable_shape->add_dim(); + if (i != -1) + mutable_dim->set_dim_value(i); + else + mutable_dim->set_dim_param("symbolic"); + } + } + } + ONNX_NAMESPACE::TypeProto proto; +}; + +// Variable template for ONNX_NAMESPACE::TensorProto_DataTypes, s_type_proto, etc.. +template +struct TTensorType { + static const TTypeProto s_type_proto; +}; + +template +const TTypeProto TTensorType::s_type_proto; + +#if !defined(DISABLE_SPARSE_TENSORS) +struct TSparseTensorProto { + explicit TSparseTensorProto(int32_t dtype, const std::vector* shape = nullptr) { + proto.mutable_sparse_tensor_type()->set_elem_type(dtype); + if (shape) { + auto m_shape = proto.mutable_sparse_tensor_type()->mutable_shape(); + for (int64_t v : *shape) { + auto* m_dim = m_shape->add_dim(); + if (v != -1) + m_dim->set_dim_value(v); + else + m_dim->set_dim_param("symbolic"); + } + } + } + ONNX_NAMESPACE::TypeProto proto; +}; +#endif + +// TypeProto for map +template +struct MTypeProto { + MTypeProto() { + proto.mutable_map_type()->set_key_type(utils::ToTensorProtoElementType()); + proto.mutable_map_type()->mutable_value_type()->mutable_tensor_type()->set_elem_type( + utils::ToTensorProtoElementType()); + proto.mutable_map_type()->mutable_value_type()->mutable_tensor_type()->mutable_shape()->clear_dim(); + } + ONNX_NAMESPACE::TypeProto proto; +}; + +template +struct MMapType { + static const MTypeProto s_map_type_proto; +}; + +template +const MTypeProto MMapType::s_map_type_proto; + +// TypeProto for vector> +template +struct VectorOfMapTypeProto { + VectorOfMapTypeProto() { + auto* map_type = proto.mutable_sequence_type()->mutable_elem_type()->mutable_map_type(); + map_type->set_key_type(utils::ToTensorProtoElementType()); + map_type->mutable_value_type()->mutable_tensor_type()->set_elem_type(utils::ToTensorProtoElementType()); + map_type->mutable_value_type()->mutable_tensor_type()->mutable_shape()->clear_dim(); + } + ONNX_NAMESPACE::TypeProto proto; +}; + +template +struct VectorOfMapType { + static const VectorOfMapTypeProto s_vec_map_type_proto; +}; + +template +const VectorOfMapTypeProto VectorOfMapType::s_vec_map_type_proto; + +template +struct SequenceTensorTypeProto { + SequenceTensorTypeProto() { + MLDataType dt = DataTypeImpl::GetTensorType(); + const auto* elem_proto = dt->GetTypeProto(); + proto.mutable_sequence_type()->mutable_elem_type()->CopyFrom(*elem_proto); + } + ONNX_NAMESPACE::TypeProto proto; +}; + +template +struct SequenceTensorType { + static const SequenceTensorTypeProto s_sequence_tensor_type_proto; +}; + +template +const SequenceTensorTypeProto SequenceTensorType::s_sequence_tensor_type_proto; + +#if !defined(DISABLE_OPTIONAL_TYPE) + +struct OptionalTypeProto { + OptionalTypeProto(const ONNX_NAMESPACE::TypeProto& type_proto) { + proto.mutable_optional_type()->mutable_elem_type()->CopyFrom(type_proto); + } + ONNX_NAMESPACE::TypeProto proto; +}; + +#endif + +template +struct SeqTensors { + void AddTensor(const std::vector& shape0, const std::vector& data0) { + tensors.push_back(Tensor{shape0, data0}); + } + + template + struct Tensor { + std::vector shape; + std::vector data; + }; + std::vector> tensors; +}; + +} // namespace test +} // namespace onnxruntime diff --git a/onnxruntime/test/providers/xnnpack/xnnpack_basic_test.cc b/onnxruntime/test/providers/xnnpack/xnnpack_basic_test.cc index 7046e36006c97..225649ef391b1 100644 --- a/onnxruntime/test/providers/xnnpack/xnnpack_basic_test.cc +++ b/onnxruntime/test/providers/xnnpack/xnnpack_basic_test.cc @@ -5,6 +5,7 @@ #include #include "core/common/logging/logging.h" +#include "core/common/span_utils.h" #include "core/framework/utils.h" #include "core/graph/graph.h" #include "core/providers/xnnpack/xnnpack_execution_provider.h" @@ -109,23 +110,18 @@ TEST(XnnpackEP, TestAllocatorSharing) { // and use the same EP instances in both std::vector> eps{ std::make_shared(XnnpackExecutionProviderInfo{}), - std::make_shared(CPUExecutionProviderInfo{}, true /* delay allocator creation to allow sharing */)}; + std::make_shared(CPUExecutionProviderInfo{})}; std::vector> eps1{ std::make_shared(XnnpackExecutionProviderInfo{}), - std::make_shared(CPUExecutionProviderInfo{}, true /* delay allocator creation to allow sharing */)}; + std::make_shared(CPUExecutionProviderInfo{})}; // check RegisterAllocator is implemented properly and supports calls from multiple inference sessions init_session(eps, session1); init_session(eps, session2); init_session(eps1, session3); - // check that allocator sharing worked. the internal testing EP should be using the CPU EP allocator - ASSERT_EQ(eps[0]->GetAllocator(OrtMemType::OrtMemTypeDefault).get(), - eps[1]->GetAllocator(OrtMemType::OrtMemTypeDefault).get()) - << "EPs do not have the same default allocator"; - ASSERT_EQ(eps[0]->GetAllocator(OrtMemType::OrtMemTypeDefault).get(), - eps1[1]->GetAllocator(OrtMemType::OrtMemTypeDefault).get()) - << "EPs do not have the same default allocator"; + ASSERT_EQ(session1.GetAllocator(OrtMemoryInfo()).get(), session3.GetAllocator(OrtMemoryInfo()).get()) << "should use the same allocator from xnnpack cross session"; + // TODO(leca): should also check there is only 1 allocator in session1.GetSessionState().GetAllocators() which is used by both xnnpack EP and CPU EP } TEST(XnnpackEP, TestAddEpUsingPublicApi) { @@ -185,7 +181,8 @@ static void RunModelTest( // Serialize the model to a string. std::string model_data; model.ToProto().SerializeToString(&model_data); - RunAndVerifyOutputsWithEP(model_data, "XnnpackEP.TestQDQModel", + const auto model_data_span = AsByteSpan(model_data.data(), model_data.size()); + RunAndVerifyOutputsWithEP(model_data_span, "XnnpackEP.TestQDQModel", DefaultXnnpackExecutionProvider(), helper.feeds_, params); } @@ -211,7 +208,7 @@ static void RunModelTestWithPath(const ORTCHAR_T* ort_model_path, const char* gr RandomValueGenerator generator; TensorShape input_shape_x{input_shape}; std::vector input_x = generator.Uniform(input_shape_x.GetDims(), - -64, 64); + -10, 24); OrtValue ml_value_x; CreateMLValue(input_shape_x.GetDims(), input_x.data(), OrtMemoryInfo(), &ml_value_x); NameMLValMap feeds; diff --git a/onnxruntime/test/python/onnx_backend_test_series.py b/onnxruntime/test/python/onnx_backend_test_series.py index 344a20a07e644..e8dc93049e18e 100644 --- a/onnxruntime/test/python/onnx_backend_test_series.py +++ b/onnxruntime/test/python/onnx_backend_test_series.py @@ -86,14 +86,15 @@ def apply_filters(filters, category): def load_jsonc(basename: str): """Returns a deserialized object from the JSONC file in testdata/.""" - with open( - os.path.join( - os.path.dirname(os.path.realpath(__file__)), - "testdata", - basename, - ), - encoding="utf-8", - ) as f: # pylint: disable=invalid-name + filename = os.path.join( + os.path.dirname(os.path.realpath(__file__)), + "testdata", + basename, + ) + if not os.path.exists(filename): + raise FileNotFoundError(f"File not found {filename!r}.") + + with open(filename, encoding="utf-8") as f: # pylint: disable=invalid-name lines = f.readlines() lines = [x.split("//")[0] for x in lines] return json.loads("\n".join(lines)) @@ -133,10 +134,6 @@ def create_backend_test(test_name=None): if backend.supports_device("OPENVINO_GPU_FP32") or backend.supports_device("OPENVINO_GPU_FP16"): current_failing_tests += apply_filters(filters, "current_failing_tests_OPENVINO_GPU") - if backend.supports_device("OPENVINO_MYRIAD"): - current_failing_tests += apply_filters(filters, "current_failing_tests_OPENVINO_GPU") - current_failing_tests += apply_filters(filters, "current_failing_tests_OPENVINO_MYRIAD") - if backend.supports_device("OPENVINO_CPU_FP32"): current_failing_tests += apply_filters(filters, "current_failing_tests_OPENVINO_CPU_FP32") diff --git a/onnxruntime/test/python/onnxruntime_test_collective.py b/onnxruntime/test/python/onnxruntime_test_collective.py index a6e420fe47040..db1ebb5384730 100644 --- a/onnxruntime/test/python/onnxruntime_test_collective.py +++ b/onnxruntime/test/python/onnxruntime_test_collective.py @@ -3,17 +3,31 @@ import unittest import numpy as np -import onnx # noqa: F401 from mpi4py import MPI -from onnx import AttributeProto, GraphProto, TensorProto, helper # noqa: F401 +from onnx import TensorProto, helper +from parameterized import parameterized import onnxruntime as ort class ORTBertPretrainTest(unittest.TestCase): - def _create_allreduce_ut_model(self, shape): - X = helper.make_tensor_value_info("X", TensorProto.FLOAT, shape) # noqa: N806 - Y = helper.make_tensor_value_info("Y", TensorProto.FLOAT, shape) # noqa: N806 + @staticmethod + def _create_model_with_opsets( + graph_def, + ): + opset_imports = [ + helper.make_operatorsetid("", 18), + helper.make_operatorsetid(".com.microsoft", 1), + ] + return helper.make_model( + graph_def, + producer_name="ORTBertPretrainTest in onnxruntime_test_collective.py", + opset_imports=opset_imports, + ) + + def _create_allreduce_ut_model(self, shape, elem_type: TensorProto.DataType = TensorProto.FLOAT): + X = helper.make_tensor_value_info("X", elem_type, shape) # noqa: N806 + Y = helper.make_tensor_value_info("Y", elem_type, shape) # noqa: N806 node_def = helper.make_node("AllReduce", ["X"], ["Y"], domain="com.microsoft") graph_def = helper.make_graph( [node_def], @@ -21,41 +35,133 @@ def _create_allreduce_ut_model(self, shape): [X], [Y], ) - return helper.make_model(graph_def, producer_name="ort-distributed-inference-unittest") + return ORTBertPretrainTest._create_model_with_opsets(graph_def) def _get_rank_size(self): comm = MPI.COMM_WORLD return comm.Get_rank(), comm.Get_size() - def _create_allgather_ut_model(self, shape): - X = helper.make_tensor_value_info("X", TensorProto.FLOAT, shape) # noqa: N806 - rank, size = self._get_rank_size() - output_shape = [s * size if _ == 0 else s for _, s in enumerate(shape)] - Y = helper.make_tensor_value_info("Y", TensorProto.FLOAT, output_shape) # noqa: N806 - node_def = helper.make_node("AllGather", ["X"], ["Y"], domain="com.microsoft", group_size=size) + def _create_allgather_ut_model( + self, + shape, + axis, + # Element type for AllGather's input and output. + elem_type: TensorProto.DataType = TensorProto.FLOAT, + # Element type for Model's input and output. + communication_elem_type: TensorProto.DataType = TensorProto.FLOAT, + ): + X = helper.make_tensor_value_info("X", elem_type, shape) # noqa: N806 + _, group_size = self._get_rank_size() + output_shape = [s * group_size if axis_index == axis else s for axis_index, s in enumerate(shape)] + Y = helper.make_tensor_value_info("Y", elem_type, output_shape) # noqa: N806 + if elem_type != communication_elem_type: + # With elem_type and external_element_type, we use the pattern + # model input type -> Cast -> elem_type -> AllGather -> elem_type -> Cast -> model output type + # so that we can test boolean tensors and other special types. + node_defs = [ + helper.make_node("Cast", ["X"], ["X_casted"], to=communication_elem_type), + helper.make_node( + "AllGather", ["X_casted"], ["Y_casted"], domain="com.microsoft", group_size=group_size, axis=axis + ), + helper.make_node("Cast", ["Y_casted"], ["Y"], to=elem_type), + ] + else: + # When elem_type == external_element_type, the pattern + # model input type -> Cast -> elem_type -> AllGather -> elem_type -> Cast -> model output type + # is reduced to + # model input type -> AllGather -> model output type + node_defs = [ + helper.make_node("AllGather", ["X"], ["Y"], domain="com.microsoft", group_size=group_size, axis=axis), + ] graph_def = helper.make_graph( - [node_def], + node_defs, "", [X], [Y], ) - return helper.make_model(graph_def, producer_name="ort-distributed-inference-unittest") + return ORTBertPretrainTest._create_model_with_opsets(graph_def) - def _create_alltoall_ut_model(self, shape): - X = helper.make_tensor_value_info("X", TensorProto.FLOAT, shape) # noqa: N806 - Y = helper.make_tensor_value_info("Y", TensorProto.FLOAT, shape) # noqa: N806 + def _create_alltoall_ut_model( + self, + shape, + elem_type: TensorProto.DataType = TensorProto.FLOAT, + communication_elem_type: TensorProto.DataType = TensorProto.FLOAT, + ): + X = helper.make_tensor_value_info("X", elem_type, shape) # noqa: N806 + Y = helper.make_tensor_value_info("Y", elem_type, shape) # noqa: N806 _, size = self._get_rank_size() - node_def = helper.make_node("AllToAll", ["X"], ["Y"], domain="com.microsoft", group_size=size) + # Explanation is in comments for model creation in _create_allgather_ut_model. + # Basically, ORT Python API doesn't support bool tensor yet, so we need to feed int64 + # tensor and cast it to bool before running communication op. + if elem_type != communication_elem_type: + node_defs = [ + helper.make_node("Cast", ["X"], ["X_casted"], to=communication_elem_type), + helper.make_node( + "AllToAll", + ["X_casted"], + ["Y_casted"], + domain="com.microsoft", + group_size=size, + ), + helper.make_node("Cast", ["Y_casted"], ["Y"], to=elem_type), + ] + else: + node_defs = [ + helper.make_node("AllToAll", ["X"], ["Y"], domain="com.microsoft", group_size=size), + ] graph_def = helper.make_graph( - [node_def], + node_defs, "", [X], [Y], ) - return helper.make_model(graph_def, producer_name="ort-distributed-inference-unittest") + return ORTBertPretrainTest._create_model_with_opsets(graph_def) - def test_all_reduce(self): - model = self._create_allreduce_ut_model((128, 128)) + def _create_alltoall_ut_model_for_boolean_tensor( + self, + shape, + # Tuple or list of bool values; e.g., [True, False] if + # shape is (2,) or [[True, False], [False, True]] if + # shape is (2, 2). + # It's input of AllToAll. + value, + ): + Y = helper.make_tensor_value_info("Y", TensorProto.BOOL, shape) # noqa: N806 + _, size = self._get_rank_size() + # Explanation is in comments for model creation in _create_allgather_ut_model. + # Basically, ORT Python API doesn't support bool tensor yet, so we need to feed int64 + # tensor and cast it to bool before running communication op. + x_const_value = helper.make_tensor("condition", TensorProto.BOOL, shape, value) + node_defs = [ + helper.make_node( + "Constant", + [], + ["X"], + value=x_const_value, + ), + helper.make_node( + "AllToAll", + ["X"], + ["Y"], + domain="com.microsoft", + group_size=size, + ), + ] + graph_def = helper.make_graph( + node_defs, + "", + [], + [Y], + ) + return ORTBertPretrainTest._create_model_with_opsets(graph_def) + + @parameterized.expand( + [ + (np.float32, TensorProto.FLOAT), + ] + ) + def test_all_reduce(self, np_elem_type, elem_type): + model = self._create_allreduce_ut_model((128, 128), elem_type) rank, size = self._get_rank_size() ort_sess = ort.InferenceSession( model.SerializeToString(), @@ -63,12 +169,37 @@ def test_all_reduce(self): provider_options=[{"device_id": str(rank)}, {}], ) - input = np.ones((128, 128), dtype=np.float32) + # Input for size == 4 + # For rank == 0: + # Input: [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]] + # Output: [[4, 4, 4, 4], [4, 4, 4, 4], [4, 4, 4, 4], [4, 4, 4, 4]] + # + # For rank == 1: + # Input: [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]] + # Output: [[4, 4, 4, 4], [4, 4, 4, 4], [4, 4, 4, 4], [4, 4, 4, 4]] + # + # For rank == 2: + # Input: [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]] + # Output: [[4, 4, 4, 4], [4, 4, 4, 4], [4, 4, 4, 4], [4, 4, 4, 4]] + # + # For rank == 3: + # Input: [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]] + # Output: [[4, 4, 4, 4], [4, 4, 4, 4], [4, 4, 4, 4], [4, 4, 4, 4]] + + input = np.ones((128, 128), dtype=np_elem_type) outputs = ort_sess.run(None, {"X": input}) - assert np.allclose(outputs[0], size * input) - def test_all_gather(self): - model = self._create_allgather_ut_model((128, 128)) + np.testing.assert_allclose( + outputs[0], size * input, err_msg=f"{rank}: AllGather ({np_elem_type}, {elem_type}): results mismatch" + ) + + @parameterized.expand( + [ + (np.float32, TensorProto.FLOAT, TensorProto.FLOAT), + ] + ) + def test_all_gather(self, np_elem_type, elem_type, communication_elem_type): + model = self._create_allgather_ut_model((128, 128), 0, elem_type, communication_elem_type) rank, size = self._get_rank_size() ort_sess = ort.InferenceSession( model.SerializeToString(), @@ -76,17 +207,51 @@ def test_all_gather(self): provider_options=[{"device_id": str(rank)}, {}], ) + # Input for size == 2 + # For rank == 0: + # Input: [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] + # Output: [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], + # [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]] + # + # For rank == 1: + # Input: [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]] + # Output: [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], + # [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]] + input = np.ones((128, 128), dtype=np.float32) * rank outputs = ort_sess.run(None, {"X": input}) - expected_output = np.zeros((128, 128), dtype=np.float32) + expected_output = np.zeros((128, 128), dtype=np_elem_type) for _ in range(size - 1): - expected_output = np.concatenate((expected_output, np.ones((128, 128), dtype=np.float32) * (_ + 1))) + expected_output = np.concatenate((expected_output, np.ones((128, 128), dtype=np_elem_type) * (_ + 1))) + + np.testing.assert_allclose( + outputs[0], + expected_output, + err_msg=f"{rank}: AllGather (axis0) ({np_elem_type}, {elem_type}, {communication_elem_type}): results mismatch", + ) + + def test_all_gather_bool(self): + model = self._create_allgather_ut_model((4,), 0, TensorProto.INT64, TensorProto.INT64) + rank, _ = self._get_rank_size() + + ort_sess = ort.InferenceSession( + model.SerializeToString(), + providers=["CUDAExecutionProvider", "CPUExecutionProvider"], + provider_options=[{"device_id": str(rank)}, {}], + ) + + x = np.array([True, True, False, False]).astype(np.int64) + y = ort_sess.run(None, {"X": x})[0] - assert np.allclose(outputs[0], expected_output) + y_expected = np.array( + [True, True, False, False] * 4, + ).astype(np.int64) - def test_all_to_all(self): - model = self._create_alltoall_ut_model((128, 128)) + np.testing.assert_allclose(y, y_expected, err_msg=f"{rank}: AllGather (bool): results mismatch") + + def test_all_gather_axis1(self): + model = self._create_allgather_ut_model((128, 128), 1) rank, size = self._get_rank_size() ort_sess = ort.InferenceSession( model.SerializeToString(), @@ -97,13 +262,125 @@ def test_all_to_all(self): input = np.ones((128, 128), dtype=np.float32) * rank outputs = ort_sess.run(None, {"X": input}) - expected_output = np.zeros((int(128 / size), 128), dtype=np.float32) + expected_output = np.zeros((128, 128), dtype=np.float32) for _ in range(size - 1): + expected_output = np.concatenate((expected_output, np.ones((128, 128), dtype=np.float32) * (_ + 1)), axis=1) + + np.testing.assert_allclose(outputs[0], expected_output, err_msg=f"{rank}: AllGather (axis1): results mismatch") + + @parameterized.expand( + [ + (np.float32, TensorProto.FLOAT, TensorProto.FLOAT), + (np.int64, TensorProto.INT64, TensorProto.INT64), + (np.int64, TensorProto.INT64, TensorProto.BOOL), + ] + ) + def test_all_to_all(self, np_elem_type, elem_type, communication_elem_type): + model = self._create_alltoall_ut_model( + (8, 8), elem_type=elem_type, communication_elem_type=communication_elem_type + ) + rank, size = self._get_rank_size() + ort_sess = ort.InferenceSession( + model.SerializeToString(), + providers=["CUDAExecutionProvider", "CPUExecutionProvider"], + provider_options=[{"device_id": str(rank)}, {}], + ) + + # Casting to Boolean needs to be handled as a special case because only absoluate zero equates + # to False and everything else to True. Post casting, however, the original input can never be + # receovered when going in the opposite direction. The end results are always going to be in the + # set [0, 1]. + + input = np.ones((8, 8), dtype=np_elem_type) * rank + + if communication_elem_type == TensorProto.BOOL: + # Input for size == 4 + # For rank == 0: + # Input: [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] + # Output: [[0, 0, 0, 0], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]] + # + # For rank == 1: + # Input: [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]] + # Output: [[0, 0, 0, 0], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]] + # + # For rank == 2: + # Input: [[2, 2, 2, 2], [2, 2, 2, 2], [2, 2, 2, 2], [2, 2, 2, 2]] + # Output: [[0, 0, 0, 0], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]] + # + # For rank == 3: + # Input: [[3, 3, 3, 3], [3, 3, 3, 3], [3, 3, 3, 3], [3, 3, 3, 3]] + # Output: [[0, 0, 0, 0], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]] + expected_output = np.concatenate( - (expected_output, np.ones((int(128 / size), 128), dtype=np.float32) * (_ + 1)) + ( + np.zeros((8 // size, 8), dtype=np_elem_type), + np.ones((8 - (8 // size), 8), dtype=np_elem_type), + ) ) + else: + # Input for size == 4 + # For rank == 0: + # Input: [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] + # Output: [[0, 0, 0, 0], [1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3]] + # + # For rank == 1: + # Input: [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]] + # Output: [[0, 0, 0, 0], [1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3]] + # + # For rank == 2: + # Input: [[2, 2, 2, 2], [2, 2, 2, 2], [2, 2, 2, 2], [2, 2, 2, 2]] + # Output: [[0, 0, 0, 0], [1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3]] + # + # For rank == 3: + # Input: [[3, 3, 3, 3], [3, 3, 3, 3], [3, 3, 3, 3], [3, 3, 3, 3]] + # Output: [[0, 0, 0, 0], [1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3]] + + expected_output = np.zeros((8 // size, 8), dtype=np_elem_type) + for _ in range(size - 1): + expected_output = np.concatenate( + (expected_output, np.ones((8 // size, 8), dtype=np_elem_type) * (_ + 1)) + ) + + outputs = ort_sess.run(None, {"X": input}) + + np.testing.assert_allclose( + outputs[0], + expected_output, + err_msg=f"{rank}: AllToAll ({np_elem_type}, {elem_type}, {communication_elem_type}): results mismatch", + ) + + def test_all_to_all_bool(self): + rank, _ = self._get_rank_size() + + # Input for size == 2 + # For rank == 0: + # Input: [True, True, True, True] + # Output: [True, True, False, False] + # + # For rank == 1: + # Input: [False, False, False, False] + # Output: [True, True, False, False] + + if rank == 0: + x = [True, True, True, True] + else: + x = [False, False, False, False] + + model = self._create_alltoall_ut_model_for_boolean_tensor((4,), x) + + ort_sess = ort.InferenceSession( + model.SerializeToString(), + providers=["CUDAExecutionProvider", "CPUExecutionProvider"], + provider_options=[{"device_id": str(rank)}, {}], + ) + + y = ort_sess.run(None, {}) + + y_expected = np.array( + [True, False, False, False], + ).astype(np.int64) - assert np.allclose(outputs[0], expected_output) + np.testing.assert_allclose(y[0], y_expected, err_msg=f"{rank}: AllToAll (bool): results mismatch") if __name__ == "__main__": diff --git a/onnxruntime/test/python/onnxruntime_test_float8.py b/onnxruntime/test/python/onnxruntime_test_float8.py new file mode 100644 index 0000000000000..76ca5d9538374 --- /dev/null +++ b/onnxruntime/test/python/onnxruntime_test_float8.py @@ -0,0 +1,710 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# pylint: disable=C0116,W0212,R1720,C0103,C0114 + +import os +import platform +import sys +import unittest + +import numpy as np +import packaging.version as pv +import parameterized +from numpy.testing import assert_allclose +from onnx import TensorProto +from onnx import __version__ as onnx_version +from onnx.checker import check_model +from onnx.helper import make_graph, make_model, make_node, make_opsetid, make_tensor, make_tensor_value_info +from onnx.reference import ReferenceEvaluator + +import onnxruntime + +# handle change from python 3.8 and on where loading a dll from the current directory needs to be explicitly allowed. +if platform.system() == "Windows" and sys.version_info[:2] >= (3, 8): + os.add_dll_directory(os.getcwd()) + +available_providers = [provider for provider in onnxruntime.get_available_providers()] + + +class TestInferenceSession(unittest.TestCase): + """ + All float 8 values were computed by using the python functions implemented in onnx: + `float32_to_float8e4m3 + `_, + `float32_to_float8e5m2 + `_, + `float8e4m3_to_float32 + `_, + `float8e5m2_to_float32 + `_. + """ + + dtypes = {"FLOAT": np.float32, "FLOAT16": np.float16} # noqa: RUF012 + x = np.array( + [0.4068359375, 352, 416, 336, 304, 272, -248, -100, 1e-4, 1e-2, 416, 432, 1e5, np.inf, -np.inf, np.nan], + dtype=np.float32, + ) + expected_saturate = ( + {} + if not hasattr(TensorProto, "FLOAT8E4M3FN") + else { + TensorProto.FLOAT8E4M3FN: np.array( + [ + 0.40625, + 352.0, + 416.0, + 320.0, + 320.0, + 256.0, + -256.0, + -96.0, + 0.0, + 0.009765625, + 416.0, + 448.0, + 448.0, + 448.0, + -448.0, + np.nan, + ], + dtype=np.float32, + ), + TensorProto.FLOAT8E4M3FNUZ: np.array( + [ + 0.40625, + 240.0, + 240.0, + 240.0, + 240.0, + 240.0, + -240.0, + -96.0, + 0.0, + 0.009765625, + 240.0, + 240.0, + 240.0, + 240.0, + -240.0, + np.nan, + ], + dtype=np.float32, + ), + TensorProto.FLOAT8E5M2: np.array( + [ + 0.4375, + 384.0, + 384.0, + 320.0, + 320.0, + 256.0, + -256.0, + -96.0, + 0.0001068115234375, + 0.009765625, + 384.0, + 448.0, + 57344.0, + 57344.0, + -57344.0, + np.nan, + ], + dtype=np.float32, + ), + TensorProto.FLOAT8E5M2FNUZ: np.array( + [ + 0.4375, + 384.0, + 384.0, + 320.0, + 320.0, + 256.0, + -256.0, + -96.0, + 0.0001068115234375, + 0.009765625, + 384.0, + 448.0, + 57344.0, + 57344.0, + -57344.0, + np.nan, + ], + dtype=np.float32, + ), + } + ) + + expected_no_saturate = ( + {} + if not hasattr(TensorProto, "FLOAT8E4M3FN") + else { + TensorProto.FLOAT8E4M3FN: np.array( + [ + 0.40625, + 352.0, + 416.0, + 320.0, + 320.0, + 256.0, + -256.0, + -96.0, + 0.0, + 0.009765625, + 416.0, + 448.0, + np.nan, + np.nan, + np.nan, + np.nan, + ], + dtype=np.float32, + ), + TensorProto.FLOAT8E4M3FNUZ: np.array( + [ + 0.40625, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + -96.0, + 0.0, + 0.009765625, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + ], + dtype=np.float32, + ), + TensorProto.FLOAT8E5M2: np.array( + [ + 0.4375, + 384.0, + 384.0, + 320.0, + 320.0, + 256.0, + -256.0, + -96.0, + 0.0001068115234375, + 0.009765625, + 384.0, + 448.0, + np.inf, + np.inf, + -np.inf, + np.nan, + ], + dtype=np.float32, + ), + TensorProto.FLOAT8E5M2FNUZ: np.array( + [ + 0.4375, + 384.0, + 384.0, + 320.0, + 320.0, + 256.0, + -256.0, + -96.0, + 0.0001068115234375, + 0.009765625, + 384.0, + 448.0, + np.nan, + np.nan, + np.nan, + np.nan, + ], + dtype=np.float32, + ), + } + ) + + def model_cast_cast(self, to, float_name, saturate): + src = getattr(TensorProto, float_name) + x = make_tensor_value_info("X", src, [None]) + y = make_tensor_value_info("Y", src, [None]) + node1 = make_node("Cast", ["X"], ["T"], to=to, saturate=saturate) + node2 = make_node("Cast", ["T"], ["Y"], to=src) + graph = make_graph([node1, node2], "lr", [x], [y]) + onnx_model = make_model(graph, opset_imports=[make_opsetid("", 19)]) + check_model(onnx_model) + return onnx_model + + def model_cast_cast_f16_float(self, to, saturate, rev=False): + x = make_tensor_value_info("X", TensorProto.FLOAT if rev else TensorProto.FLOAT16, [None]) + y = make_tensor_value_info("Y", TensorProto.FLOAT16 if rev else TensorProto.FLOAT, [None]) + node1 = make_node("Cast", ["X"], ["T"], to=to, saturate=saturate) + node2 = make_node("Cast", ["T"], ["Y"], to=TensorProto.FLOAT16 if rev else TensorProto.FLOAT) + graph = make_graph([node1, node2], "lr", [x], [y]) + onnx_model = make_model(graph, opset_imports=[make_opsetid("", 19)]) + check_model(onnx_model) + return onnx_model + + @unittest.skipIf(pv.Version(onnx_version) < pv.Version("1.15.0"), reason="needs onnx>=1.15.0") + @parameterized.parameterized.expand( + [ + ("FLOAT8E4M3FN", "FLOAT", 1), + ("FLOAT8E4M3FNUZ", "FLOAT", 1), + ("FLOAT8E5M2", "FLOAT", 1), + ("FLOAT8E5M2FNUZ", "FLOAT", 1), + ("FLOAT8E4M3FN", "FLOAT", 0), + ("FLOAT8E4M3FNUZ", "FLOAT", 0), + ("FLOAT8E5M2", "FLOAT", 0), + ("FLOAT8E5M2FNUZ", "FLOAT", 0), + ("FLOAT8E4M3FN", "FLOAT16", 1), + ("FLOAT8E4M3FNUZ", "FLOAT16", 1), + ("FLOAT8E5M2", "FLOAT16", 1), + ("FLOAT8E5M2FNUZ", "FLOAT16", 1), + ("FLOAT8E4M3FN", "FLOAT16", 0), + ("FLOAT8E4M3FNUZ", "FLOAT16", 0), + ("FLOAT8E5M2", "FLOAT16", 0), + ("FLOAT8E5M2FNUZ", "FLOAT16", 0), + ] + ) + @unittest.skipIf(not hasattr(TensorProto, "FLOAT8E4M3FN"), reason="needs onnx>=1.14.0") + def test_model_cast_cast_reference(self, name: str, float_name: str, saturate: int): + to = getattr(TensorProto, name) + expected = TestInferenceSession.expected_saturate if saturate else TestInferenceSession.expected_no_saturate + x = TestInferenceSession.x.astype(TestInferenceSession.dtypes[float_name]) + expect = expected[to].astype(TestInferenceSession.dtypes[float_name]) + onnx_model = self.model_cast_cast(to, float_name, saturate) + ref = ReferenceEvaluator(onnx_model) + y = ref.run(None, {"X": x})[0] + assert_allclose(expect, y) + self.assertEqual(expect.shape, y.shape) + self.assertEqual(expect.dtype, y.dtype) + + @parameterized.parameterized.expand( + [ + ("FLOAT8E4M3FN", "FLOAT", 1), + ("FLOAT8E4M3FNUZ", "FLOAT", 1), + ("FLOAT8E5M2", "FLOAT", 1), + ("FLOAT8E5M2FNUZ", "FLOAT", 1), + ("FLOAT8E4M3FN", "FLOAT", 0), + ("FLOAT8E4M3FNUZ", "FLOAT", 0), + ("FLOAT8E5M2", "FLOAT", 0), + ("FLOAT8E5M2FNUZ", "FLOAT", 0), + ("FLOAT8E4M3FN", "FLOAT16", 1), + ("FLOAT8E4M3FNUZ", "FLOAT16", 1), + ("FLOAT8E5M2", "FLOAT16", 1), + ("FLOAT8E5M2FNUZ", "FLOAT16", 1), + ("FLOAT8E4M3FN", "FLOAT16", 0), + ("FLOAT8E4M3FNUZ", "FLOAT16", 0), + ("FLOAT8E5M2", "FLOAT16", 0), + ("FLOAT8E5M2FNUZ", "FLOAT16", 0), + ] + ) + @unittest.skipIf(not hasattr(TensorProto, "FLOAT8E4M3FN"), reason="needs onnx>=1.14.0") + def test_model_cast_cast_cpu(self, name: str, float_name: str, saturate: int): + so = onnxruntime.SessionOptions() + so.graph_optimization_level = onnxruntime.GraphOptimizationLevel.ORT_DISABLE_ALL + # so.add_session_config_entry("session.allow_released_opsets_only", "0") + + to = getattr(TensorProto, name) + expected = TestInferenceSession.expected_saturate if saturate else TestInferenceSession.expected_no_saturate + x = TestInferenceSession.x.astype(TestInferenceSession.dtypes[float_name]) + expect = expected[to].astype(TestInferenceSession.dtypes[float_name]) + + onnx_model = self.model_cast_cast(to, float_name, saturate) + sess = onnxruntime.InferenceSession( + onnx_model.SerializeToString(), so, providers=["CPUExecutionProvider"], read_config_from_model=1 + ) + y = sess.run(None, {"X": x})[0] + assert_allclose(expect, y) + self.assertEqual(expect.shape, y.shape) + self.assertEqual(expect.dtype, y.dtype) + + @parameterized.parameterized.expand( + [ + ("FLOAT8E4M3FN", "FLOAT", 1, "CUDAExecutionProvider"), + ("FLOAT8E5M2", "FLOAT", 1, "CUDAExecutionProvider"), + ("FLOAT8E4M3FN", "FLOAT", 0, "CUDAExecutionProvider"), + ("FLOAT8E5M2", "FLOAT", 0, "CUDAExecutionProvider"), + ("FLOAT8E4M3FN", "FLOAT16", 1, "CUDAExecutionProvider"), + ("FLOAT8E5M2", "FLOAT16", 1, "CUDAExecutionProvider"), + ("FLOAT8E4M3FN", "FLOAT16", 0, "CUDAExecutionProvider"), + ("FLOAT8E5M2", "FLOAT16", 0, "CUDAExecutionProvider"), + ] + ) + @unittest.skipIf(not hasattr(TensorProto, "FLOAT8E4M3FN"), reason="needs onnx>=1.14.0") + @unittest.skipIf("CUDAExecutionProvider" not in available_providers, reason="Not running on CUDA.") + def test_model_cast_cast_cuda(self, name: str, float_name: str, saturate: int, provider: str): + so = onnxruntime.SessionOptions() + so.graph_optimization_level = onnxruntime.GraphOptimizationLevel.ORT_DISABLE_ALL + # so.add_session_config_entry("session.allow_released_opsets_only", "0") + + to = getattr(TensorProto, name) + expected = TestInferenceSession.expected_saturate if saturate else TestInferenceSession.expected_no_saturate + x = TestInferenceSession.x.astype(TestInferenceSession.dtypes[float_name]) + expect = expected[to].astype(TestInferenceSession.dtypes[float_name]) + + onnx_model = self.model_cast_cast(to, float_name, saturate) + sess = onnxruntime.InferenceSession( + onnx_model.SerializeToString(), so, providers=[provider], read_config_from_model=1 + ) + y = sess.run(None, {"X": x})[0] + try: + assert_allclose(expect, y) + except AssertionError as e: + raise AssertionError( + f"Discrepancies with name={name}, float_name={float_name}, " + f"saturate={saturate}\nexpect={expect}\ny={y}" + ) from e + self.assertEqual(expect.shape, y.shape) + self.assertEqual(expect.dtype, y.dtype) + + @parameterized.parameterized.expand( + [ + ("FLOAT8E4M3FN", "FLOAT", 1, "CUDAExecutionProvider"), + ("FLOAT8E5M2", "FLOAT", 1, "CUDAExecutionProvider"), + ("FLOAT8E4M3FN", "FLOAT", 0, "CUDAExecutionProvider"), + ("FLOAT8E5M2", "FLOAT", 0, "CUDAExecutionProvider"), + ("FLOAT8E4M3FN", "FLOAT16", 1, "CUDAExecutionProvider"), + ("FLOAT8E5M2", "FLOAT16", 1, "CUDAExecutionProvider"), + ("FLOAT8E4M3FN", "FLOAT16", 0, "CUDAExecutionProvider"), + ("FLOAT8E5M2", "FLOAT16", 0, "CUDAExecutionProvider"), + ] + ) + @unittest.skipIf(not hasattr(TensorProto, "FLOAT8E4M3FN"), reason="needs onnx>=1.14.0") + @unittest.skipIf("CUDAExecutionProvider" not in available_providers, reason="Not running on CUDA.") + def test_model_cast_cast_cuda_ortvalue(self, name: str, float_name: str, saturate: int, provider: str): + so = onnxruntime.SessionOptions() + so.graph_optimization_level = onnxruntime.GraphOptimizationLevel.ORT_DISABLE_ALL + # so.add_session_config_entry("session.allow_released_opsets_only", "0") + + to = getattr(TensorProto, name) + expected = TestInferenceSession.expected_saturate if saturate else TestInferenceSession.expected_no_saturate + x = TestInferenceSession.x.astype(TestInferenceSession.dtypes[float_name]) + expect = expected[to].astype(TestInferenceSession.dtypes[float_name]) + + onnx_model = self.model_cast_cast(to, float_name, saturate) + ortv = onnxruntime.OrtValue.ortvalue_from_numpy(x, device_type="cuda") + sess = onnxruntime.InferenceSession( + onnx_model.SerializeToString(), so, providers=[provider], read_config_from_model=1 + ) + y = sess.run_with_ort_values(["Y"], {"X": ortv})[0].numpy() + try: + assert_allclose(expect, y) + except AssertionError as e: + raise AssertionError( + f"Discrepancies with name={name}, float_name={float_name}, " + f"saturate={saturate}\nexpect={expect}\ny={y}" + ) from e + self.assertEqual(expect.shape, y.shape) + self.assertEqual(expect.dtype, y.dtype) + + def model_qdq(self, to, float_name, saturate, castq=False, castdq=False, like=False, initializer=False): + fltype = getattr(TensorProto, float_name) + x = make_tensor_value_info("X", fltype, [None]) + y = make_tensor_value_info("Y", fltype, [None]) + if initializer: + scale = make_tensor("scale", fltype, [1], [1.0]) + zero = make_tensor("zero", to, [1], [0.0]) + else: + scale = make_node("Constant", [], ["scale"], value=make_tensor("scale", fltype, [1], [1.0])) + zero = make_node("Constant", [], ["zero"], value=make_tensor("zero", to, [1], [0.0])) + if castq: + if like: + node1 = make_node("CastLike", ["X", "zero"], ["Temp"], saturate=saturate) + else: + node1 = make_node("Cast", ["X"], ["Temp"], saturate=saturate, to=to) + else: + node1 = make_node("QuantizeLinear", ["X", "scale", "zero"], ["Temp"], saturate=saturate, axis=0) + if castdq: + if like: + node2 = make_node("CastLike", ["Temp", "scale"], ["Y"]) + else: + node2 = make_node("Cast", ["Temp"], ["Y"], to=fltype) + else: + node2 = make_node("DequantizeLinear", ["Temp", "scale"], ["Y"], axis=0) + if initializer: + graph = make_graph([node1, node2], "lr", [x], [y], [scale, zero]) + else: + graph = make_graph([scale, zero, node1, node2], "lr", [x], [y]) + onnx_model = make_model(graph, opset_imports=[make_opsetid("", 19)]) + check_model(onnx_model) + return onnx_model + + @unittest.skipIf(pv.Version(onnx_version) < pv.Version("1.15.0"), reason="needs onnx>=1.15.0") + @parameterized.parameterized.expand( + [ + ("FLOAT8E4M3FN", "FLOAT", 1), + ("FLOAT8E4M3FNUZ", "FLOAT", 1), + ("FLOAT8E5M2", "FLOAT", 1), + ("FLOAT8E5M2FNUZ", "FLOAT", 1), + ("FLOAT8E4M3FN", "FLOAT", 0), + ("FLOAT8E4M3FNUZ", "FLOAT", 0), + ("FLOAT8E5M2", "FLOAT", 0), + ("FLOAT8E5M2FNUZ", "FLOAT", 0), + ("FLOAT8E4M3FN", "FLOAT16", 1), + ("FLOAT8E4M3FNUZ", "FLOAT16", 1), + ("FLOAT8E5M2", "FLOAT16", 1), + ("FLOAT8E5M2FNUZ", "FLOAT16", 1), + ("FLOAT8E4M3FN", "FLOAT16", 0), + ("FLOAT8E4M3FNUZ", "FLOAT16", 0), + ("FLOAT8E5M2", "FLOAT16", 0), + ("FLOAT8E5M2FNUZ", "FLOAT16", 0), + ] + ) + @unittest.skipIf(not hasattr(TensorProto, "FLOAT8E4M3FN"), reason="needs onnx>=1.14.0") + def test_model_qdq_reference(self, name: str, float_name: str, saturate: int): + to = getattr(TensorProto, name) + expected = TestInferenceSession.expected_saturate if saturate else TestInferenceSession.expected_no_saturate + x = TestInferenceSession.x.astype(TestInferenceSession.dtypes[float_name]) + expect = expected[to].astype(TestInferenceSession.dtypes[float_name]) + + onnx_model = self.model_qdq(to, float_name, saturate) + ref = ReferenceEvaluator(onnx_model) + y = ref.run(None, {"X": x})[0] + assert_allclose(expect, y) + self.assertEqual(expect.shape, y.shape) + # A bug in the reference implementation, + # enable that test when onnx package is fixed. + # self.assertEqual(expect.dtype, y.dtype) + + @parameterized.parameterized.expand( + [ + ("FLOAT8E4M3FN", "FLOAT", 1), + ("FLOAT8E4M3FNUZ", "FLOAT", 1), + ("FLOAT8E5M2", "FLOAT", 1), + ("FLOAT8E5M2FNUZ", "FLOAT", 1), + ("FLOAT8E4M3FN", "FLOAT", 0), + ("FLOAT8E4M3FNUZ", "FLOAT", 0), + ("FLOAT8E5M2", "FLOAT", 0), + ("FLOAT8E5M2FNUZ", "FLOAT", 0), + ("FLOAT8E4M3FN", "FLOAT16", 1), + ("FLOAT8E4M3FNUZ", "FLOAT16", 1), + ("FLOAT8E5M2", "FLOAT16", 1), + ("FLOAT8E5M2FNUZ", "FLOAT16", 1), + ("FLOAT8E4M3FN", "FLOAT16", 0), + ("FLOAT8E4M3FNUZ", "FLOAT16", 0), + ("FLOAT8E5M2", "FLOAT16", 0), + ("FLOAT8E5M2FNUZ", "FLOAT16", 0), + ] + ) + @unittest.skipIf(not hasattr(TensorProto, "FLOAT8E4M3FN"), reason="needs onnx>=1.14.0") + def test_model_qdq_cpu(self, name: str, float_name: str, saturate: int): + so = onnxruntime.SessionOptions() + so.graph_optimization_level = onnxruntime.GraphOptimizationLevel.ORT_DISABLE_ALL + so.add_session_config_entry("session.allow_released_opsets_only", "0") + + to = getattr(TensorProto, name) + expected = TestInferenceSession.expected_saturate if saturate else TestInferenceSession.expected_no_saturate + x = TestInferenceSession.x.astype(TestInferenceSession.dtypes[float_name]) + expect = expected[to].astype(TestInferenceSession.dtypes[float_name]) + + onnx_model = self.model_qdq(to, float_name, saturate) + try: + sess = onnxruntime.InferenceSession( + onnx_model.SerializeToString(), so, providers=["CPUExecutionProvider"], read_config_from_model=1 + ) + except Exception as e: + raise AssertionError( + f"Cannot build InferenceSession with name={name}, float_name={float_name}, saturate={saturate}." + ) from e + y = sess.run(None, {"X": x})[0] + assert_allclose(expect, y) + self.assertEqual(expect.shape, y.shape) + self.assertEqual(expect.dtype, y.dtype) + + @parameterized.parameterized.expand( + [ + ("FLOAT8E4M3FN", "FLOAT", 1), + ("FLOAT8E4M3FNUZ", "FLOAT", 1), + ("FLOAT8E5M2", "FLOAT", 1), + ("FLOAT8E5M2FNUZ", "FLOAT", 1), + ("FLOAT8E4M3FN", "FLOAT", 0), + ("FLOAT8E4M3FNUZ", "FLOAT", 0), + ("FLOAT8E5M2", "FLOAT", 0), + ("FLOAT8E5M2FNUZ", "FLOAT", 0), + ("FLOAT8E4M3FN", "FLOAT16", 1), + ("FLOAT8E4M3FNUZ", "FLOAT16", 1), + ("FLOAT8E5M2", "FLOAT16", 1), + ("FLOAT8E5M2FNUZ", "FLOAT16", 1), + ("FLOAT8E4M3FN", "FLOAT16", 0), + ("FLOAT8E4M3FNUZ", "FLOAT16", 0), + ("FLOAT8E5M2", "FLOAT16", 0), + ("FLOAT8E5M2FNUZ", "FLOAT16", 0), + ] + ) + @unittest.skipIf(not hasattr(TensorProto, "FLOAT8E4M3FN"), reason="needs onnx>=1.14.0") + def test_model_qdq_cpu_init(self, name: str, float_name: str, saturate: int): + so = onnxruntime.SessionOptions() + so.graph_optimization_level = onnxruntime.GraphOptimizationLevel.ORT_DISABLE_ALL + so.add_session_config_entry("session.allow_released_opsets_only", "0") + + to = getattr(TensorProto, name) + expected = TestInferenceSession.expected_saturate if saturate else TestInferenceSession.expected_no_saturate + x = TestInferenceSession.x.astype(TestInferenceSession.dtypes[float_name]) + expect = expected[to].astype(TestInferenceSession.dtypes[float_name]) + + onnx_model = self.model_qdq(to, float_name, saturate, initializer=True) + try: + sess = onnxruntime.InferenceSession( + onnx_model.SerializeToString(), so, providers=["CPUExecutionProvider"], read_config_from_model=1 + ) + except Exception as e: + raise AssertionError( + f"Cannot build InferenceSession with name={name}, float_name={float_name}, saturate={saturate}." + ) from e + y = sess.run(None, {"X": x})[0] + assert_allclose(expect, y) + self.assertEqual(expect.shape, y.shape) + self.assertEqual(expect.dtype, y.dtype) + + @parameterized.parameterized.expand( + [ + ("FLOAT8E4M3FN", "FLOAT", 1), + ("FLOAT8E4M3FNUZ", "FLOAT", 1), + ("FLOAT8E5M2", "FLOAT", 1), + ("FLOAT8E5M2FNUZ", "FLOAT", 1), + ("FLOAT8E4M3FN", "FLOAT", 0), + ("FLOAT8E4M3FNUZ", "FLOAT", 0), + ("FLOAT8E5M2", "FLOAT", 0), + ("FLOAT8E5M2FNUZ", "FLOAT", 0), + ("FLOAT8E4M3FN", "FLOAT16", 1), + ("FLOAT8E4M3FNUZ", "FLOAT16", 1), + ("FLOAT8E5M2", "FLOAT16", 1), + ("FLOAT8E5M2FNUZ", "FLOAT16", 1), + ("FLOAT8E4M3FN", "FLOAT16", 0), + ("FLOAT8E4M3FNUZ", "FLOAT16", 0), + ("FLOAT8E5M2", "FLOAT16", 0), + ("FLOAT8E5M2FNUZ", "FLOAT16", 0), + ] + ) + @unittest.skipIf(not hasattr(TensorProto, "FLOAT8E4M3FN"), reason="needs onnx>=1.14.0") + def test_model_cast_like_x2_cpu(self, name: str, float_name: str, saturate: int): + so = onnxruntime.SessionOptions() + so.graph_optimization_level = onnxruntime.GraphOptimizationLevel.ORT_DISABLE_ALL + # so.add_session_config_entry("session.allow_released_opsets_only", "0") + + to = getattr(TensorProto, name) + expected = TestInferenceSession.expected_saturate if saturate else TestInferenceSession.expected_no_saturate + x = TestInferenceSession.x.astype(TestInferenceSession.dtypes[float_name]) + expect = expected[to].astype(TestInferenceSession.dtypes[float_name]) + + onnx_model = self.model_qdq(to, float_name, saturate, True, True, True) + self.assertTrue("CastLike", str(onnx_model)) + try: + sess = onnxruntime.InferenceSession( + onnx_model.SerializeToString(), so, providers=["CPUExecutionProvider"], read_config_from_model=1 + ) + except Exception as e: + raise AssertionError( + f"Cannot build InferenceSession with name={name}, float_name={float_name}, saturate={saturate}." + ) from e + y = sess.run(None, {"X": x})[0] + try: + assert_allclose(expect, y) + except AssertionError as e: + # TODO: if not saturate, it fails, CastLike is probably handled with Cast but where? + if not saturate: + return + raise AssertionError( + f"Discrepancies with name={name}, float_name={float_name}, " + f"saturate={saturate}\nexpect={expect}\ny={y}" + ) from e + self.assertEqual(expect.shape, y.shape) + self.assertEqual(expect.dtype, y.dtype) + + @parameterized.parameterized.expand( + [ + ("FLOAT8E4M3FN", "FLOAT", 1, "CUDAExecutionProvider"), + ("FLOAT8E5M2", "FLOAT", 1, "CUDAExecutionProvider"), + ("FLOAT8E4M3FN", "FLOAT", 0, "CUDAExecutionProvider"), + ("FLOAT8E5M2", "FLOAT", 0, "CUDAExecutionProvider"), + ("FLOAT8E4M3FN", "FLOAT16", 1, "CUDAExecutionProvider"), + ("FLOAT8E5M2", "FLOAT16", 1, "CUDAExecutionProvider"), + ("FLOAT8E4M3FN", "FLOAT16", 0, "CUDAExecutionProvider"), + ("FLOAT8E5M2", "FLOAT16", 0, "CUDAExecutionProvider"), + ] + ) + @unittest.skipIf(not hasattr(TensorProto, "FLOAT8E4M3FN"), reason="needs onnx>=1.14.0") + @unittest.skipIf("CUDAExecutionProvider" not in available_providers, reason="Not running on CUDA.") + def test_model_qdq_cuda(self, name: str, float_name: str, saturate: int, provider: str): + so = onnxruntime.SessionOptions() + so.graph_optimization_level = onnxruntime.GraphOptimizationLevel.ORT_DISABLE_ALL + # so.add_session_config_entry("session.allow_released_opsets_only", "0") + + to = getattr(TensorProto, name) + expected = TestInferenceSession.expected_saturate if saturate else TestInferenceSession.expected_no_saturate + x = TestInferenceSession.x.astype(TestInferenceSession.dtypes[float_name]) + expect = expected[to].astype(TestInferenceSession.dtypes[float_name]) + + onnx_model = self.model_qdq(to, float_name, saturate, False, False) + sess = onnxruntime.InferenceSession( + onnx_model.SerializeToString(), so, providers=[provider], read_config_from_model=1 + ) + try: + y = sess.run(None, {"X": x})[0] + except Exception as e: + raise AssertionError( + f"qdq failed with name={name!r}, float_name={float_name!r}, " + f"saturate={saturate!r}, provider={provider!r}." + ) from e + assert_allclose(expect, y) + self.assertEqual(expect.shape, y.shape) + self.assertEqual(expect.dtype, y.dtype) + + @parameterized.parameterized.expand( + [ + ("FLOAT8E4M3FN", "FLOAT", 1, "CUDAExecutionProvider"), + ("FLOAT8E5M2", "FLOAT", 1, "CUDAExecutionProvider"), + ("FLOAT8E4M3FN", "FLOAT", 0, "CUDAExecutionProvider"), + ("FLOAT8E5M2", "FLOAT", 0, "CUDAExecutionProvider"), + ("FLOAT8E4M3FN", "FLOAT16", 1, "CUDAExecutionProvider"), + ("FLOAT8E5M2", "FLOAT16", 1, "CUDAExecutionProvider"), + ("FLOAT8E4M3FN", "FLOAT16", 0, "CUDAExecutionProvider"), + ("FLOAT8E5M2", "FLOAT16", 0, "CUDAExecutionProvider"), + ] + ) + @unittest.skipIf(not hasattr(TensorProto, "FLOAT8E4M3FN"), reason="needs onnx>=1.14.0") + @unittest.skipIf("CUDAExecutionProvider" not in available_providers, reason="Not running on CUDA.") + def test_model_qdq_cuda_ortvalue(self, name: str, float_name: str, saturate: int, provider: str): + so = onnxruntime.SessionOptions() + so.graph_optimization_level = onnxruntime.GraphOptimizationLevel.ORT_DISABLE_ALL + # so.add_session_config_entry("session.allow_released_opsets_only", "0") + + to = getattr(TensorProto, name) + expected = TestInferenceSession.expected_saturate if saturate else TestInferenceSession.expected_no_saturate + x = TestInferenceSession.x.astype(TestInferenceSession.dtypes[float_name]) + expect = expected[to].astype(TestInferenceSession.dtypes[float_name]) + + onnx_model = self.model_qdq(to, float_name, saturate, False, False) + ortv = onnxruntime.OrtValue.ortvalue_from_numpy(x, device_type="cuda") + sess = onnxruntime.InferenceSession( + onnx_model.SerializeToString(), so, providers=[provider], read_config_from_model=1 + ) + try: + y = sess.run_with_ort_values(["Y"], {"X": ortv})[0].numpy() + except Exception as e: + raise AssertionError( + f"qdq failed with name={name!r}, float_name={float_name!r}, " + f"saturate={saturate!r}, provider={provider!r}." + ) from e + assert_allclose(expect, y) + self.assertEqual(expect.shape, y.shape) + self.assertEqual(expect.dtype, y.dtype) + + @unittest.skipIf("CUDAExecutionProvider" not in available_providers, reason="Not running on CUDA.") + def test_compare_cpu_cuda_e4m3fn(self): + folder = os.path.join(os.path.dirname(__file__), "..", "testdata", "float8") + model = os.path.join(folder, "te.cast_fp8_1_fp32.onnx") + data = np.load(os.path.join(folder, "te.cast_fp8_1_fp32_input.npy")) + + sess_cpu = onnxruntime.InferenceSession(model, providers=["CPUExecutionProvider"]) + sess_cuda = onnxruntime.InferenceSession(model, providers=["CUDAExecutionProvider"]) + cpu_res = sess_cpu.run(None, {"input": data})[0] + cuda_res = sess_cuda.run(None, {"input": data})[0] + self.assertEqual(cuda_res.tolist(), cpu_res.tolist()) + + +if __name__ == "__main__": + unittest.main(verbosity=2) diff --git a/onnxruntime/test/python/onnxruntime_test_ort_trainer.py b/onnxruntime/test/python/onnxruntime_test_ort_trainer.py index a3972151dd169..4cf2e5d7f7588 100644 --- a/onnxruntime/test/python/onnxruntime_test_ort_trainer.py +++ b/onnxruntime/test/python/onnxruntime_test_ort_trainer.py @@ -138,7 +138,7 @@ def create_ort_trainer( return model, model_desc, device -def runBertTrainingTest( # noqa: N802 +def run_bert_training_test( gradient_accumulation_steps, use_mixed_precision, allreduce_post_accumulation, @@ -516,10 +516,10 @@ def run_mnist_training_and_testing(onnx_opset_ver): # noqa: N805 err_msg="test accuracy mismatch", ) - def testMNISTTrainingAndTestingOpset12(self): # noqa: N802 + def test_mnist_training_and_testing_opset12(self): TestOrtTrainer.run_mnist_training_and_testing(onnx_opset_ver=12) - def testMNISTResumeTrainingAndTesting(self): # noqa: N802 + def test_mnist_resume_training_and_testing(self): torch.manual_seed(1) device = torch.device("cuda") @@ -588,7 +588,7 @@ def testMNISTResumeTrainingAndTesting(self): # noqa: N802 err_msg="test accuracy mismatch", ) - def testMNISTStateDict(self): # noqa: N802 + def test_mnist_state_dict(self): torch.manual_seed(1) device = torch.device("cuda") @@ -617,7 +617,7 @@ def testMNISTStateDict(self): # noqa: N802 "bias_buffer", } - def testMNISTSaveAsONNX(self): # noqa: N802 + def test_mnist_save_as_onnx(self): torch.manual_seed(1) device = torch.device("cuda") onnx_file_name = "mnist.onnx" @@ -643,7 +643,7 @@ def testMNISTSaveAsONNX(self): # noqa: N802 trainer.save_as_onnx(onnx_file_name) assert os.path.exists(onnx_file_name) - def testMNISTDevice(self): # noqa: N802 + def test_mnist_device(self): torch.manual_seed(1) device = torch.device("cuda") @@ -662,7 +662,7 @@ def testMNISTDevice(self): # noqa: N802 loss, _ = trainer.train_step(data, target, torch.tensor([learningRate])) - def testMNISTInitializerNames(self): # noqa: N802 + def test_mnist_initializer_names(self): torch.manual_seed(1) device = torch.device("cuda") @@ -683,7 +683,7 @@ def testMNISTInitializerNames(self): # noqa: N802 n for n, t in model.named_parameters() } - def testMNISTInitializerNamesWithInternalLoss(self): # noqa: N802 + def test_mnist_initializer_names_with_internal_loss(self): torch.manual_seed(1) device = torch.device("cuda") @@ -711,7 +711,7 @@ def get_lr_this_step(global_step): assert {n.name for n in trainer.onnx_model_.graph.initializer} == {n for n, t in model.named_parameters()} - def testMNISTFrozenWeight(self): # noqa: N802 + def test_mnist_frozen_weight(self): torch.manual_seed(1) device = torch.device("cuda") @@ -738,7 +738,7 @@ def testMNISTFrozenWeight(self): # noqa: N802 fc2_trainstep_2 = trainer.state_dict()["fc2.weight"] assert np.array_equal(fc1_trainstep_1, fc1_trainstep_2) and not np.array_equal(fc2_trainstep_1, fc2_trainstep_2) - def testMNISTTorchBuffer(self): # noqa: N802 + def test_mnist_torch_buffer(self): torch.manual_seed(1) device = torch.device("cuda") @@ -767,7 +767,7 @@ def testMNISTTorchBuffer(self): # noqa: N802 bias_buffer_trainstep_1, bias_buffer_trainstep_2 ) - def testMNISTFrozenWeightCheckpoint(self): # noqa: N802 + def test_mnist_frozen_weight_checkpoint(self): torch.manual_seed(1) device = torch.device("cuda") @@ -806,7 +806,7 @@ def testMNISTFrozenWeightCheckpoint(self): # noqa: N802 loaded_state_dict = trainer.state_dict() assert state_dict.keys() == loaded_state_dict.keys() - def testMNISTTrainingCheckpoint(self): # noqa: N802 + def test_mnist_training_checkpoint(self): torch.manual_seed(1) device = torch.device("cuda") @@ -860,7 +860,7 @@ def testMNISTTrainingCheckpoint(self): # noqa: N802 for key in state_dict: assert np.array_equal(state_dict[key], loaded_state_dict[key]) - def testBertTrainingBasic(self): # noqa: N802 + def test_bert_training_basic(self): expected_losses = [ 11.027887, 11.108191, @@ -872,7 +872,7 @@ def testBertTrainingBasic(self): # noqa: N802 10.920979, ] expected_eval_loss = [10.958977] - actual_losses, actual_eval_loss = runBertTrainingTest( + actual_losses, actual_eval_loss = run_bert_training_test( gradient_accumulation_steps=1, use_mixed_precision=False, allreduce_post_accumulation=False, @@ -894,7 +894,7 @@ def testBertTrainingBasic(self): # noqa: N802 err_msg="evaluation loss mismatch", ) - def testBertTrainingGradientAccumulation(self): # noqa: N802 + def test_bert_training_gradient_accumulation(self): expected_losses = [ 11.027887, 11.108191, @@ -907,7 +907,7 @@ def testBertTrainingGradientAccumulation(self): # noqa: N802 ] expected_eval_loss = [10.958998] - actual_losses, actual_eval_loss = runBertTrainingTest( + actual_losses, actual_eval_loss = run_bert_training_test( gradient_accumulation_steps=4, use_mixed_precision=False, allreduce_post_accumulation=False, @@ -929,7 +929,7 @@ def testBertTrainingGradientAccumulation(self): # noqa: N802 err_msg="evaluation loss mismatch", ) - def testBertCheckpointingBasic(self): # noqa: N802 + def test_bert_checkpointing_basic(self): model, _, _ = create_ort_trainer( gradient_accumulation_steps=1, use_mixed_precision=False, @@ -963,7 +963,7 @@ def testBertCheckpointingBasic(self): # noqa: N802 for k, v in loaded_sd.items(): assert torch.all(torch.eq(v, sd[k])) - def testWrapModelLossFnStateDict(self): # noqa: N802 + def test_wrap_model_loss_fn_state_dict(self): torch.manual_seed(1) device = torch.device("cuda") diff --git a/onnxruntime/test/python/onnxruntime_test_ort_trainer_with_mixed_precision.py b/onnxruntime/test/python/onnxruntime_test_ort_trainer_with_mixed_precision.py index 53ace2a642652..3b994e6f26710 100644 --- a/onnxruntime/test/python/onnxruntime_test_ort_trainer_with_mixed_precision.py +++ b/onnxruntime/test/python/onnxruntime_test_ort_trainer_with_mixed_precision.py @@ -4,11 +4,11 @@ import unittest from numpy.testing import assert_allclose, assert_array_equal -from onnxruntime_test_ort_trainer import runBertTrainingTest +from onnxruntime_test_ort_trainer import run_bert_training_test class TestOrtTrainer(unittest.TestCase): - def testBertTrainingMixedPrecision(self): # noqa: N802 + def test_bert_training_mixed_precision(self): expected_losses = [ 11.034248352050781, 11.125300407409668, @@ -21,7 +21,7 @@ def testBertTrainingMixedPrecision(self): # noqa: N802 ] expected_all_finites = [True, True, True, True, True, True, True, True] expected_eval_loss = [10.959012985229492] - actual_losses, actual_all_finites, actual_eval_loss = runBertTrainingTest( + actual_losses, actual_all_finites, actual_eval_loss = run_bert_training_test( gradient_accumulation_steps=1, use_mixed_precision=True, allreduce_post_accumulation=False, @@ -38,7 +38,7 @@ def testBertTrainingMixedPrecision(self): # noqa: N802 err_msg="evaluation loss mismatch", ) - def testBertTrainingMixedPrecisionInternalLossScale(self): # noqa: N802 + def test_bert_training_mixed_precision_internal_loss_scale(self): expected_losses = [ 11.034248352050781, 11.125300407409668, @@ -50,7 +50,7 @@ def testBertTrainingMixedPrecisionInternalLossScale(self): # noqa: N802 10.971782684326172, ] expected_eval_loss = [10.959012985229492] - actual_losses, actual_eval_loss = runBertTrainingTest( + actual_losses, actual_eval_loss = run_bert_training_test( gradient_accumulation_steps=1, use_mixed_precision=True, allreduce_post_accumulation=False, @@ -67,7 +67,7 @@ def testBertTrainingMixedPrecisionInternalLossScale(self): # noqa: N802 err_msg="evaluation loss mismatch", ) - def testBertTrainingGradientAccumulationMixedPrecision(self): # noqa: N802 + def test_bert_training_gradient_accumulation_mixed_precision(self): expected_losses = [ 11.034248352050781, 11.125300407409668, @@ -80,7 +80,7 @@ def testBertTrainingGradientAccumulationMixedPrecision(self): # noqa: N802 ] expected_all_finites = [True, True] expected_eval_loss = [10.95903205871582] - actual_losses, actual_all_finites, actual_eval_loss = runBertTrainingTest( + actual_losses, actual_all_finites, actual_eval_loss = run_bert_training_test( gradient_accumulation_steps=4, use_mixed_precision=True, allreduce_post_accumulation=False, diff --git a/onnxruntime/test/python/onnxruntime_test_python.py b/onnxruntime/test/python/onnxruntime_test_python.py index e700b48acd83e..59f7781bb4f8a 100644 --- a/onnxruntime/test/python/onnxruntime_test_python.py +++ b/onnxruntime/test/python/onnxruntime_test_python.py @@ -1,8 +1,9 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -# pylint: disable=C0116,W0212,R1720,C0114 +from __future__ import annotations import copy +import ctypes import gc import os import pathlib @@ -59,17 +60,21 @@ def run_model_with_input(self, session_object, input_name, input_value, iter_num predict = session_object.run(None, {input_name: input_value})[0] queue.put(max(predict.flatten().tolist())) - def testTvmImported(self): # noqa: N802 + def test_tvm_imported(self): if "TvmExecutionProvider" not in onnxrt.get_available_providers(): return import tvm self.assertTrue(tvm is not None) - def testGetVersionString(self): # noqa: N802 + def test_get_version_string(self): self.assertIsNot(onnxrt.get_version_string(), None) - def testModelSerialization(self): # noqa: N802 + def test_get_build_info(self): + self.assertIsNot(onnxrt.get_build_info(), None) + self.assertIn("Build Info", onnxrt.get_build_info()) + + def test_model_serialization(self): try: so = onnxrt.SessionOptions() so.log_severity_level = 1 @@ -81,6 +86,62 @@ def testModelSerialization(self): # noqa: N802 providers=["CPUExecutionProvider"], ) self.assertTrue(os.path.isfile(so.optimized_model_filepath)) + os.remove(so.optimized_model_filepath) + except Fail as onnxruntime_error: + if ( + str(onnxruntime_error) == "[ONNXRuntimeError] : 1 : FAIL : Unable to serialize model as it contains" + " compiled nodes. Please disable any execution providers which generate compiled nodes." + ): + pass + else: + raise onnxruntime_error + + def test_model_serialization_with_external_initializers(self): + try: + so = onnxrt.SessionOptions() + so.log_severity_level = 1 + so.logid = "TestModelSerializationWithExternalInitializers" + so.optimized_model_filepath = "./model_with_external_initializers.onnx" + external_initializers_file = "external_initializers.bin" + so.add_session_config_entry( + "session.optimized_model_external_initializers_file_name", external_initializers_file + ) + so.add_session_config_entry("session.optimized_model_external_initializers_min_size_in_bytes", "100") + onnxrt.InferenceSession( + get_name("mnist.onnx"), + sess_options=so, + providers=["CPUExecutionProvider"], + ) + self.assertTrue(os.path.isfile(so.optimized_model_filepath)) + self.assertTrue(os.path.isfile(external_initializers_file)) + os.remove(so.optimized_model_filepath) + os.remove(external_initializers_file) + except Fail as onnxruntime_error: + if ( + str(onnxruntime_error) == "[ONNXRuntimeError] : 1 : FAIL : Unable to serialize model as it contains" + " compiled nodes. Please disable any execution providers which generate compiled nodes." + ): + pass + else: + raise onnxruntime_error + + def test_model_serialization_with_external_initializers_to_directory(self): + try: + so = onnxrt.SessionOptions() + so.log_severity_level = 1 + so.logid = "TestModelSerializationWithExternalInitializersToDirectory" + directory = "./testdata/" + so.optimized_model_filepath = os.path.join(directory, "model_with_external_initializers_in_dir.onnx") + external_initializers_file = "external_initializers_in_dir.bin" + so.add_session_config_entry( + "session.optimized_model_external_initializers_file_name", external_initializers_file + ) + so.add_session_config_entry("session.optimized_model_external_initializers_min_size_in_bytes", "100") + onnxrt.InferenceSession(get_name("mnist.onnx"), sess_options=so, providers=["CPUExecutionProvider"]) + self.assertTrue(os.path.isfile(so.optimized_model_filepath)) + self.assertTrue(os.path.isfile(os.path.join(directory, external_initializers_file))) + os.remove(so.optimized_model_filepath) + os.remove(os.path.join(directory, external_initializers_file)) except Fail as onnxruntime_error: if ( str(onnxruntime_error) == "[ONNXRuntimeError] : 1 : FAIL : Unable to serialize model as it contains" @@ -90,7 +151,91 @@ def testModelSerialization(self): # noqa: N802 else: raise onnxruntime_error - def testGetProviders(self): # noqa: N802 + def test_model_serialization_with_original_external_initializers_to_directory(self): + try: + so = onnxrt.SessionOptions() + so.log_severity_level = 1 + so.logid = "TestModelSerializationWithOriginalExternalInitializersToDirectory" + directory = "./testdata/" + so.optimized_model_filepath = os.path.join(directory, "model_opt_with_ext_data.onnx") + external_initializers_file = "model_opt_with_ext_data.bin" + so.add_session_config_entry( + "session.optimized_model_external_initializers_file_name", external_initializers_file + ) + so.add_session_config_entry("session.optimized_model_external_initializers_min_size_in_bytes", "100") + onnxrt.InferenceSession( + get_name("model_with_orig_ext_data.onnx"), sess_options=so, providers=["CPUExecutionProvider"] + ) + self.assertTrue(os.path.isfile(so.optimized_model_filepath)) + self.assertTrue(os.path.isfile(os.path.join(directory, external_initializers_file))) + os.remove(so.optimized_model_filepath) + os.remove(os.path.join(directory, external_initializers_file)) + except Fail as onnxruntime_error: + if ( + str(onnxruntime_error) == "[ONNXRuntimeError] : 1 : FAIL : Unable to serialize model as it contains" + " compiled nodes. Please disable any execution providers which generate compiled nodes." + ): + pass + else: + raise onnxruntime_error + + def test_model_serialization_with_original_external_initializers_to_current_directory(self): + optimized_model_filepath = "model_opt_with_ext_data_1.onnx" + external_initializers_file = "model_opt_with_ext_data_1.bin" + optimized_model_filepath_2 = "model_opt_with_ext_data_2.onnx" + external_initializers_file_2 = "model_opt_with_ext_data_2.bin" + + so = onnxrt.SessionOptions() + so.log_severity_level = 1 + so.logid = "TestModelSerializationWithOriginalExternalInitializersToCurrentDirectory" + so.optimized_model_filepath = optimized_model_filepath + + so.add_session_config_entry( + "session.optimized_model_external_initializers_file_name", external_initializers_file + ) + + # TODO(anyone): Set this to 100 will cause test error since some tensor below the threshold + # still refers to the original external data file. We shall fix this issue so that the + # optimized model only refers to one external data file. + so.add_session_config_entry("session.optimized_model_external_initializers_min_size_in_bytes", "10") + session1 = onnxrt.InferenceSession( + get_name("model_with_orig_ext_data.onnx"), sess_options=so, providers=["CPUExecutionProvider"] + ) + del session1 + self.assertTrue(os.path.isfile(optimized_model_filepath)) + self.assertTrue(os.path.isfile(external_initializers_file)) + + so2 = onnxrt.SessionOptions() + so2.log_severity_level = 1 + so2.logid = "TestModelSerializationWithExternalInitializersInCurrentDirectory" + so2.optimized_model_filepath = optimized_model_filepath_2 + so2.add_session_config_entry( + "session.optimized_model_external_initializers_file_name", external_initializers_file_2 + ) + so2.add_session_config_entry("session.optimized_model_external_initializers_min_size_in_bytes", "10") + + # verify that we can load the optimized model with external data in current directory and save + # optimized model with external data to current directory. + session2 = onnxrt.InferenceSession( + optimized_model_filepath, sess_options=so2, providers=["CPUExecutionProvider"] + ) + del session2 + self.assertTrue(os.path.isfile(optimized_model_filepath_2)) + self.assertTrue(os.path.isfile(external_initializers_file_2)) + + # Remove model 1 to make sure optimized model 2 can be loaded independently from model 1 + os.remove(optimized_model_filepath) + os.remove(external_initializers_file) + + session3 = onnxrt.InferenceSession( + optimized_model_filepath_2, sess_options=onnxrt.SessionOptions(), providers=["CPUExecutionProvider"] + ) + del session3 + + os.remove(optimized_model_filepath_2) + os.remove(external_initializers_file_2) + + def test_get_providers(self): self.assertTrue("CPUExecutionProvider" in onnxrt.get_available_providers()) # get_all_providers() returns the default EP order from highest to lowest. # CPUExecutionProvider should always be last. @@ -98,18 +243,18 @@ def testGetProviders(self): # noqa: N802 sess = onnxrt.InferenceSession(get_name("mul_1.onnx"), providers=onnxrt.get_available_providers()) self.assertTrue("CPUExecutionProvider" in sess.get_providers()) - def testEnablingAndDisablingTelemetry(self): # noqa: N802 + def test_enabling_and_disabling_telemetry(self): onnxrt.disable_telemetry_events() # no-op on non-Windows builds # may be no-op on certain Windows builds based on build configuration onnxrt.enable_telemetry_events() - def testDeserializationFromPathObject(self): # noqa: N802 + def test_deserialization_from_path_object(self): # path object is allowed onnxrt.InferenceSession(pathlib.Path(get_name("mul_1.onnx")), providers=available_providers) - def testSetProviders(self): # noqa: N802 + def test_set_providers(self): if "CUDAExecutionProvider" in onnxrt.get_available_providers(): sess = onnxrt.InferenceSession(get_name("mul_1.onnx"), providers=["CUDAExecutionProvider"]) # confirm that CUDA Provider is in list of registered providers. @@ -119,7 +264,7 @@ def testSetProviders(self): # noqa: N802 # confirm only CPU Provider is registered now. self.assertEqual(["CPUExecutionProvider"], sess.get_providers()) - def testSetProvidersWithOptions(self): # noqa: N802 + def test_set_providers_with_options(self): if "TensorrtExecutionProvider" in onnxrt.get_available_providers(): sess = onnxrt.InferenceSession(get_name("mul_1.onnx"), providers=["TensorrtExecutionProvider"]) self.assertIn("TensorrtExecutionProvider", sess.get_providers()) @@ -183,12 +328,9 @@ def testSetProvidersWithOptions(self): # noqa: N802 """ if "CUDAExecutionProvider" in onnxrt.get_available_providers(): - import ctypes - import sys # noqa: F401 + cuda_success = 0 - CUDA_SUCCESS = 0 # noqa: N806 - - def runBaseTest1(): # noqa: N802 + def run_base_test1(): sess = onnxrt.InferenceSession(get_name("mul_1.onnx"), providers=["CUDAExecutionProvider"]) self.assertTrue("CUDAExecutionProvider" in sess.get_providers()) @@ -207,7 +349,7 @@ def runBaseTest1(): # noqa: N802 sess.get_providers(), ) - def runBaseTest2(): # noqa: N802 + def run_base_test2(): sess = onnxrt.InferenceSession(get_name("mul_1.onnx"), providers=["CUDAExecutionProvider"]) self.assertIn("CUDAExecutionProvider", sess.get_providers()) @@ -255,6 +397,8 @@ def test_get_and_set_option_with_values(option_name, option_values): test_get_and_set_option_with_values("tunable_op_tuning_enable", ["1", "0"]) + test_get_and_set_option_with_values("tunable_op_max_tuning_duration_ms", ["-1", "1"]) + option["gpu_external_alloc"] = "0" option["gpu_external_free"] = "0" option["gpu_external_empty_cache"] = "0" @@ -286,27 +430,21 @@ def test_get_and_set_option_with_values(option_name, option_values): with self.assertRaises(RuntimeError): sess.set_providers(["CUDAExecutionProvider"], [option]) - def getCudaDeviceCount(): # noqa: N802 - import ctypes - + def get_cuda_device_count(): num_device = ctypes.c_int() result = ctypes.c_int() error_str = ctypes.c_char_p() result = cuda.cuInit(0) result = cuda.cuDeviceGetCount(ctypes.byref(num_device)) - if result != CUDA_SUCCESS: + if result != cuda_success: cuda.cuGetErrorString(result, ctypes.byref(error_str)) print("cuDeviceGetCount failed with error code %d: %s" % (result, error_str.value.decode())) return -1 return num_device.value - def setDeviceIdTest(i): # noqa: N802 - import ctypes - - import onnxruntime as onnxrt - + def set_device_id_test(i): device = ctypes.c_int() result = ctypes.c_int() error_str = ctypes.c_char_p() @@ -319,21 +457,21 @@ def setDeviceIdTest(i): # noqa: N802 sess.get_providers(), ) result = cuda.cuCtxGetDevice(ctypes.byref(device)) - if result != CUDA_SUCCESS: + if result != cuda_success: cuda.cuGetErrorString(result, ctypes.byref(error_str)) - print("cuCtxGetDevice failed with error code %d: %s" % (result, error_str.value.decode())) + print(f"cuCtxGetDevice failed with error code {result}: {error_str.value.decode()}") - self.assertEqual(result, CUDA_SUCCESS) + self.assertEqual(result, cuda_success) self.assertEqual(i, device.value) - def runAdvancedTest(): # noqa: N802 - num_device = getCudaDeviceCount() + def run_advanced_test(): + num_device = get_cuda_device_count() if num_device < 0: return # Configure session to be ready to run on all available cuda devices for i in range(num_device): - setDeviceIdTest(i) + set_device_id_test(i) sess = onnxrt.InferenceSession(get_name("mul_1.onnx"), providers=["CPUExecutionProvider"]) @@ -353,22 +491,21 @@ def runAdvancedTest(): # noqa: N802 for libname in libnames: try: cuda = ctypes.CDLL(libname) - runBaseTest1() - runBaseTest2() - runAdvancedTest() + run_base_test1() + run_base_test2() + run_advanced_test() except OSError: continue else: break else: - runBaseTest1() - runBaseTest2() - # raise OSError("could not load any of: " + ' '.join(libnames)) + run_base_test1() + run_base_test2() if "ROCMExecutionProvider" in onnxrt.get_available_providers(): - def runRocmOptionsTest(): # noqa: N802 + def run_rocm_options_test(): sess = onnxrt.InferenceSession(get_name("mul_1.onnx"), providers=["ROCMExecutionProvider"]) self.assertIn("ROCMExecutionProvider", sess.get_providers()) options = sess.get_provider_options() @@ -391,22 +528,24 @@ def test_get_and_set_option_with_values(option_name, option_values): test_get_and_set_option_with_values("tunable_op_tuning_enable", ["1", "0"]) - runRocmOptionsTest() + test_get_and_set_option_with_values("tunable_op_max_tuning_duration_ms", ["-1", "1"]) + + run_rocm_options_test() - def testInvalidSetProviders(self): # noqa: N802 + def test_invalid_set_providers(self): with self.assertRaises(RuntimeError) as context: sess = onnxrt.InferenceSession(get_name("mul_1.onnx"), providers=["CPUExecutionProvider"]) sess.set_providers(["InvalidProvider"]) self.assertTrue("Unknown Provider Type: InvalidProvider" in str(context.exception)) - def testSessionProviders(self): # noqa: N802 + def test_session_providers(self): if "CUDAExecutionProvider" in onnxrt.get_available_providers(): # create session from scratch, but constrain it to only use the CPU. sess = onnxrt.InferenceSession(get_name("mul_1.onnx"), providers=["CPUExecutionProvider"]) self.assertEqual(["CPUExecutionProvider"], sess.get_providers()) - def testGetAndSetTuningResults(self): # noqa: N802 - def getTuningResultsForEp(sess, ep): # without the outer list # noqa: N802 + def test_get_and_set_tuning_results(self): + def get_tuning_results_for_ep(sess, ep): # without the outer list tuning_results = sess.get_tuning_results() self.assertGreaterEqual(len(tuning_results), 1) tuning_results_for_this_ep = [t for t in tuning_results if t.get("ep") == ep] @@ -417,23 +556,23 @@ def getTuningResultsForEp(sess, ep): # without the outer list # noqa: N802 probe_params_sig = "probe_but_not_an_params_signature" probe_value = 10000000 - def copyTuningResultsWithProbe(tr): # noqa: N802 + def copy_tuning_results_with_probe(tr): tr = copy.deepcopy(tr) tr["results"][probe_op_sig] = {probe_params_sig: probe_value} return tr - def assertTuningResultsLoaded(sess, ep): # noqa: N802 - tr = getTuningResultsForEp(sess, ep) + def assert_tuning_results_loaded(sess, ep): + tr = get_tuning_results_for_ep(sess, ep) self.assertIn(probe_op_sig, tr["results"]) self.assertEqual(tr["results"][probe_op_sig], {probe_params_sig: probe_value}) - def assertTuningResultsNotLoaded(sess, ep): # noqa: N802 - tr = getTuningResultsForEp(sess, ep) + def assert_tuning_results_not_loaded(sess, ep): + tr = get_tuning_results_for_ep(sess, ep) self.assertNotIn(probe_op_sig, tr["results"]) - def doTestGetAndSetTuningResults(ep): # noqa: N802 + def do_test_get_and_set_tuning_results(ep): sess = onnxrt.InferenceSession(get_name("mul_1.onnx"), providers=[ep]) - tuning_results = getTuningResultsForEp(sess, ep) + tuning_results = get_tuning_results_for_ep(sess, ep) self.assertIn("ep", tuning_results) self.assertIn("results", tuning_results) @@ -442,53 +581,53 @@ def doTestGetAndSetTuningResults(ep): # noqa: N802 self.assertNotIn("NOT_A_VALIDATOR_KEY", tuning_results["validators"]) # invalid EP will be rejected - invalid_unknown_ep = copyTuningResultsWithProbe(tuning_results) + invalid_unknown_ep = copy_tuning_results_with_probe(tuning_results) invalid_unknown_ep["ep"] = "UnknownEP" sess.set_tuning_results([invalid_unknown_ep]) with self.assertRaises(RuntimeError) as context: sess.set_tuning_results([invalid_unknown_ep], error_on_invalid=True) self.assertIn("Cannot find execution provider UnknownEP", str(context.exception)) - assertTuningResultsNotLoaded(sess, ep) + assert_tuning_results_not_loaded(sess, ep) # missing validator key will be rejected - mismatched_validator_key_missing = copyTuningResultsWithProbe(tuning_results) + mismatched_validator_key_missing = copy_tuning_results_with_probe(tuning_results) mismatched_validator_key_missing["validators"].pop("ORT_VERSION") sess.set_tuning_results([mismatched_validator_key_missing]) with self.assertRaises(RuntimeError) as context: sess.set_tuning_results([mismatched_validator_key_missing], error_on_invalid=True) self.assertIn("ORT_VERSION", str(context.exception)) self.assertIn("is not provided for validation", str(context.exception)) - assertTuningResultsNotLoaded(sess, ep) + assert_tuning_results_not_loaded(sess, ep) - mismatched_validator_key_extra = copyTuningResultsWithProbe(tuning_results) + mismatched_validator_key_extra = copy_tuning_results_with_probe(tuning_results) mismatched_validator_key_extra["validators"]["NOT_A_VALIDATOR_KEY"] = "NOT_USED" sess.set_tuning_results([mismatched_validator_key_extra]) with self.assertRaises(RuntimeError) as context: sess.set_tuning_results([mismatched_validator_key_extra], error_on_invalid=True) self.assertIn("NOT_A_VALIDATOR_KEY", str(context.exception)) self.assertIn("is unable to consume it", str(context.exception)) - assertTuningResultsNotLoaded(sess, ep) + assert_tuning_results_not_loaded(sess, ep) - validation_failure = copyTuningResultsWithProbe(tuning_results) + validation_failure = copy_tuning_results_with_probe(tuning_results) validation_failure["validators"]["ORT_VERSION"] = "This is not a proper ORT_VERSION value!" sess.set_tuning_results([validation_failure]) with self.assertRaises(RuntimeError) as context: sess.set_tuning_results([validation_failure], error_on_invalid=True) self.assertIn("Failed to load TuningResults", str(context.exception)) self.assertIn("version mismatch", str(context.exception)) - assertTuningResultsNotLoaded(sess, ep) + assert_tuning_results_not_loaded(sess, ep) - loadable = copyTuningResultsWithProbe(tuning_results) + loadable = copy_tuning_results_with_probe(tuning_results) sess.set_tuning_results([loadable], error_on_invalid=True) - assertTuningResultsLoaded(sess, ep) + assert_tuning_results_loaded(sess, ep) if "CUDAExecutionProvider" in onnxrt.get_available_providers(): - doTestGetAndSetTuningResults("CUDAExecutionProvider") + do_test_get_and_set_tuning_results("CUDAExecutionProvider") if "ROCMExecutionProvider" in onnxrt.get_available_providers(): - doTestGetAndSetTuningResults("ROCMExecutionProvider") + do_test_get_and_set_tuning_results("ROCMExecutionProvider") - def testRunModel(self): # noqa: N802 + def test_run_model(self): sess = onnxrt.InferenceSession(get_name("mul_1.onnx"), providers=available_providers) x = np.array([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]], dtype=np.float32) input_name = sess.get_inputs()[0].name @@ -503,7 +642,38 @@ def testRunModel(self): # noqa: N802 output_expected = np.array([[1.0, 4.0], [9.0, 16.0], [25.0, 36.0]], dtype=np.float32) np.testing.assert_allclose(output_expected, res[0], rtol=1e-05, atol=1e-08) - def testRunModelFromBytes(self): # noqa: N802 + def test_run_async(self): + event = threading.Event() + output_expected = np.array([[1.0, 4.0], [9.0, 16.0], [25.0, 36.0]], dtype=np.float32) + + class MyData: + def __init__(self, id): + self.__id = id + + def get_id(self): + return self.__id + + my_data = MyData(123456) + + def callback(res: np.ndarray, data: MyData, err: str) -> None: + self.assertEqual(len(err), 0) + self.assertEqual(len(res), 1) + self.assertEqual(data.get_id(), 123456) + np.testing.assert_allclose(output_expected, res[0], rtol=1e-05, atol=1e-08) + event.set() + + so = onnxrt.SessionOptions() + so.intra_op_num_threads = 2 + + sess = onnxrt.InferenceSession(get_name("mul_1.onnx"), so, providers=available_providers) + + x = np.array([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]], dtype=np.float32) + sess.run_async(["Y"], {"X": x}, callback, my_data) + + event.wait(10) # timeout in 10 sec + self.assertTrue(event.is_set()) + + def test_run_model_from_bytes(self): with open(get_name("mul_1.onnx"), "rb") as f: content = f.read() sess = onnxrt.InferenceSession(content, providers=onnxrt.get_available_providers()) @@ -520,7 +690,7 @@ def testRunModelFromBytes(self): # noqa: N802 output_expected = np.array([[1.0, 4.0], [9.0, 16.0], [25.0, 36.0]], dtype=np.float32) np.testing.assert_allclose(output_expected, res[0], rtol=1e-05, atol=1e-08) - def testRunModel2(self): # noqa: N802 + def test_run_model2(self): sess = onnxrt.InferenceSession(get_name("matmul_1.onnx"), providers=onnxrt.get_available_providers()) x = np.array([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]], dtype=np.float32) input_name = sess.get_inputs()[0].name @@ -535,7 +705,7 @@ def testRunModel2(self): # noqa: N802 output_expected = np.array([[5.0], [11.0], [17.0]], dtype=np.float32) np.testing.assert_allclose(output_expected, res[0], rtol=1e-05, atol=1e-08) - def testRunModel2Contiguous(self): # noqa: N802 + def test_run_model2_contiguous(self): sess = onnxrt.InferenceSession(get_name("matmul_1.onnx"), providers=onnxrt.get_available_providers()) x = np.array([[2.0, 1.0], [4.0, 3.0], [6.0, 5.0]], dtype=np.float32)[:, [1, 0]] input_name = sess.get_inputs()[0].name @@ -553,7 +723,7 @@ def testRunModel2Contiguous(self): # noqa: N802 rescontiguous = sess.run([output_name], {input_name: xcontiguous}) np.testing.assert_allclose(output_expected, rescontiguous[0], rtol=1e-05, atol=1e-08) - def testRunModelMultipleThreads(self): # noqa: N802 + def test_run_model_multiple_threads(self): # Skip this test for a "pure" DML onnxruntime python wheel. # We keep this test enabled for instances where both DML and CUDA EPs are available # (Windows GPU CI pipeline has this config) - this test will pass because CUDA has higher precedence @@ -610,7 +780,7 @@ def testRunModelMultipleThreads(self): # noqa: N802 while q.qsize() > 0: self.assertEqual(result, q.get()) - def testListAsInput(self): # noqa: N802 + def test_list_as_input(self): sess = onnxrt.InferenceSession(get_name("mul_1.onnx"), providers=onnxrt.get_available_providers()) x = np.array([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]], dtype=np.float32) input_name = sess.get_inputs()[0].name @@ -618,18 +788,18 @@ def testListAsInput(self): # noqa: N802 output_expected = np.array([[1.0, 4.0], [9.0, 16.0], [25.0, 36.0]], dtype=np.float32) np.testing.assert_allclose(output_expected, res[0], rtol=1e-05, atol=1e-08) - def testStringListAsInput(self): # noqa: N802 + def test_string_list_as_input(self): sess = onnxrt.InferenceSession(get_name("identity_string.onnx"), providers=available_providers_without_tvm) x = np.array(["this", "is", "identity", "test"], dtype=str).reshape((2, 2)) x_name = sess.get_inputs()[0].name res = sess.run([], {x_name: x.tolist()}) np.testing.assert_equal(x, res[0]) - def testRunDevice(self): # noqa: N802 + def test_run_device(self): device = onnxrt.get_device() self.assertTrue("CPU" in device or "GPU" in device) - def testRunModelSymbolicInput(self): # noqa: N802 + def test_run_model_symbolic_input(self): sess = onnxrt.InferenceSession(get_name("matmul_2.onnx"), providers=available_providers_without_tvm) x = np.array([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]], dtype=np.float32) input_name = sess.get_inputs()[0].name @@ -646,7 +816,7 @@ def testRunModelSymbolicInput(self): # noqa: N802 output_expected = np.array([[5.0], [11.0], [17.0]], dtype=np.float32) np.testing.assert_allclose(output_expected, res[0], rtol=1e-05, atol=1e-08) - def testBooleanInputs(self): # noqa: N802 + def test_boolean_inputs(self): sess = onnxrt.InferenceSession(get_name("logicaland.onnx"), providers=available_providers) a = np.array([[True, True], [False, False]], dtype=bool) b = np.array([[True, False], [True, False]], dtype=bool) @@ -678,7 +848,7 @@ def testBooleanInputs(self): # noqa: N802 res = sess.run([output_name], {a_name: a, b_name: b}) np.testing.assert_equal(output_expected, res[0]) - def testStringInput1(self): # noqa: N802 + def test_string_input1(self): sess = onnxrt.InferenceSession(get_name("identity_string.onnx"), providers=available_providers_without_tvm) x = np.array(["this", "is", "identity", "test"], dtype=str).reshape((2, 2)) @@ -699,7 +869,7 @@ def testStringInput1(self): # noqa: N802 res = sess.run([output_name], {x_name: x}) np.testing.assert_equal(x, res[0]) - def testStringInput2(self): # noqa: N802 + def test_string_input2(self): sess = onnxrt.InferenceSession(get_name("identity_string.onnx"), providers=available_providers_without_tvm) x = np.array(["Olá", "你好", "여보세요", "hello"], dtype=str).reshape((2, 2)) @@ -720,7 +890,7 @@ def testStringInput2(self): # noqa: N802 res = sess.run([output_name], {x_name: x}) np.testing.assert_equal(x, res[0]) - def testInputBytes(self): # noqa: N802 + def test_input_bytes(self): sess = onnxrt.InferenceSession(get_name("identity_string.onnx"), providers=available_providers_without_tvm) x = np.array([b"this", b"is", b"identity", b"test"]).reshape((2, 2)) @@ -741,7 +911,7 @@ def testInputBytes(self): # noqa: N802 res = sess.run([output_name], {x_name: x}) np.testing.assert_equal(x, res[0].astype("|S8")) - def testInputObject(self): # noqa: N802 + def test_input_object(self): sess = onnxrt.InferenceSession(get_name("identity_string.onnx"), providers=available_providers_without_tvm) x = np.array(["this", "is", "identity", "test"], object).reshape((2, 2)) @@ -762,7 +932,7 @@ def testInputObject(self): # noqa: N802 res = sess.run([output_name], {x_name: x}) np.testing.assert_equal(x, res[0]) - def testInputVoid(self): # noqa: N802 + def test_input_void(self): sess = onnxrt.InferenceSession(get_name("identity_string.onnx"), providers=available_providers_without_tvm) # numpy 1.20+ doesn't automatically pad the bytes based entries in the array when dtype is np.void, # so we use inputs where that is the case @@ -787,7 +957,7 @@ def testInputVoid(self): # noqa: N802 expr = np.array([["must", "have"], ["same", "size"]], dtype=object) np.testing.assert_equal(expr, res[0]) - def testRaiseWrongNumInputs(self): # noqa: N802 + def test_raise_wrong_num_inputs(self): with self.assertRaises(ValueError) as context: sess = onnxrt.InferenceSession(get_name("logicaland.onnx"), providers=onnxrt.get_available_providers()) a = np.array([[True, True], [False, False]], dtype=bool) @@ -796,7 +966,7 @@ def testRaiseWrongNumInputs(self): # noqa: N802 "Required inputs (['input1:0']) are missing from input feed (['input:0'])", str(context.exception) ) - def testModelMeta(self): # noqa: N802 + def test_model_meta(self): model_path = "../models/opset8/test_squeezenet/model.onnx" if not os.path.exists(model_path): return @@ -808,7 +978,7 @@ def testModelMeta(self): # noqa: N802 self.assertEqual("", modelmeta.description) self.assertEqual("", modelmeta.graph_description) - def testProfilerWithSessionOptions(self): # noqa: N802 + def test_profiler_with_session_options(self): so = onnxrt.SessionOptions() so.enable_profiling = True sess = onnxrt.InferenceSession( @@ -829,8 +999,10 @@ def testProfilerWithSessionOptions(self): # noqa: N802 self.assertTrue(tag in lines[i]) self.assertTrue("]" in lines[-1]) - def testProfilerGetStartTimeNs(self): # noqa: N802 - def getSingleSessionProfilingStartTime(): # noqa: N802 + os.remove(profile_file) + + def test_profiler_get_start_time_ns(self): + def get_single_session_profiling_start_time(): so = onnxrt.SessionOptions() so.enable_profiling = True sess = onnxrt.InferenceSession( @@ -838,19 +1010,21 @@ def getSingleSessionProfilingStartTime(): # noqa: N802 sess_options=so, providers=onnxrt.get_available_providers(), ) - return sess.get_profiling_start_time_ns() + start_time = sess.get_profiling_start_time_ns() + os.remove(sess.end_profiling()) + return start_time # Get 1st profiling's start time - start_time_1 = getSingleSessionProfilingStartTime() + start_time_1 = get_single_session_profiling_start_time() # Get 2nd profiling's start time - start_time_2 = getSingleSessionProfilingStartTime() + start_time_2 = get_single_session_profiling_start_time() # Get 3rd profiling's start time - start_time_3 = getSingleSessionProfilingStartTime() + start_time_3 = get_single_session_profiling_start_time() # Chronological profiling's start time self.assertTrue(start_time_1 <= start_time_2 <= start_time_3) - def testGraphOptimizationLevel(self): # noqa: N802 + def test_graph_optimization_level(self): opt = onnxrt.SessionOptions() # default should be all optimizations optimization self.assertEqual(opt.graph_optimization_level, onnxrt.GraphOptimizationLevel.ORT_ENABLE_ALL) @@ -865,7 +1039,7 @@ def testGraphOptimizationLevel(self): # noqa: N802 sess.run([], {"input1:0": a, "input:0": b}) - def testSequenceLength(self): # noqa: N802 + def test_sequence_length(self): sess = onnxrt.InferenceSession(get_name("sequence_length.onnx"), providers=available_providers_without_tvm) x = [ np.array([1.0, 0.0, 3.0, 44.0, 23.0, 11.0], dtype=np.float32).reshape((2, 3)), @@ -886,7 +1060,7 @@ def testSequenceLength(self): # noqa: N802 res = sess.run([output_name], {x_name: x}) self.assertEqual(output_expected, res[0]) - def testSequenceConstruct(self): # noqa: N802 + def test_sequence_construct(self): sess = onnxrt.InferenceSession( get_name("sequence_construct.onnx"), providers=available_providers_without_tvm, @@ -918,7 +1092,7 @@ def testSequenceConstruct(self): # noqa: N802 np.testing.assert_array_equal(output_expected, res[0]) - def testSequenceInsert(self): # noqa: N802 + def test_sequence_insert(self): opt = onnxrt.SessionOptions() opt.execution_mode = onnxrt.ExecutionMode.ORT_SEQUENTIAL sess = onnxrt.InferenceSession( @@ -948,13 +1122,13 @@ def testSequenceInsert(self): # noqa: N802 ) np.testing.assert_array_equal(output_expected, res[0]) - def testOrtExecutionMode(self): # noqa: N802 + def test_ort_execution_mode(self): opt = onnxrt.SessionOptions() self.assertEqual(opt.execution_mode, onnxrt.ExecutionMode.ORT_SEQUENTIAL) opt.execution_mode = onnxrt.ExecutionMode.ORT_PARALLEL self.assertEqual(opt.execution_mode, onnxrt.ExecutionMode.ORT_PARALLEL) - def testLoadingSessionOptionsFromModel(self): # noqa: N802 + def test_loading_session_options_from_model(self): try: os.environ["ORT_LOAD_CONFIG_FROM_MODEL"] = str(1) sess = onnxrt.InferenceSession( @@ -978,6 +1152,8 @@ def testLoadingSessionOptionsFromModel(self): # noqa: N802 self.assertEqual(session_options.enable_profiling, True) # from the ORT config + os.remove(sess.end_profiling()) + except Exception: raise @@ -985,7 +1161,7 @@ def testLoadingSessionOptionsFromModel(self): # noqa: N802 # Make sure the usage of the feature is disabled after this test os.environ["ORT_LOAD_CONFIG_FROM_MODEL"] = str(0) - def testSessionOptionsAddFreeDimensionOverrideByDenotation(self): # noqa: N802 + def test_session_options_add_free_dimension_override_by_denotation(self): so = onnxrt.SessionOptions() so.add_free_dimension_override_by_denotation("DATA_BATCH", 3) so.add_free_dimension_override_by_denotation("DATA_CHANNEL", 5) @@ -1000,7 +1176,7 @@ def testSessionOptionsAddFreeDimensionOverrideByDenotation(self): # noqa: N802 # Free dims with denotations - "DATA_BATCH" and "DATA_CHANNEL" have values assigned to them. self.assertEqual(input_shape, [3, 5, 5]) - def testSessionOptionsAddFreeDimensionOverrideByName(self): # noqa: N802 + def test_session_options_add_free_dimension_override_by_name(self): so = onnxrt.SessionOptions() so.add_free_dimension_override_by_name("Dim1", 4) so.add_free_dimension_override_by_name("Dim2", 6) @@ -1015,14 +1191,14 @@ def testSessionOptionsAddFreeDimensionOverrideByName(self): # noqa: N802 # "Dim1" and "Dim2" have values assigned to them. self.assertEqual(input_shape, [4, 6, 5]) - def testSessionOptionsAddConfigEntry(self): # noqa: N802 + def test_session_options_add_config_entry(self): so = onnxrt.SessionOptions() key = "CONFIG_KEY" val = "CONFIG_VAL" so.add_session_config_entry(key, val) self.assertEqual(so.get_session_config_entry(key), val) - def testInvalidSessionOptionsConfigEntry(self): # noqa: N802 + def test_invalid_session_options_config_entry(self): so = onnxrt.SessionOptions() invalide_key = "INVALID_KEY" with self.assertRaises(RuntimeError) as context: @@ -1031,7 +1207,7 @@ def testInvalidSessionOptionsConfigEntry(self): # noqa: N802 "SessionOptions does not have configuration with key: " + invalide_key in str(context.exception) ) - def testSessionOptionsAddInitializer(self): # noqa: N802 + def test_session_options_add_initializer(self): # Create an initializer and add it to a SessionOptions instance so = onnxrt.SessionOptions() # This initializer is different from the actual initializer in the model for "W" @@ -1057,7 +1233,7 @@ def testSessionOptionsAddInitializer(self): # noqa: N802 ) ) - def testSessionOptionsAddExternalInitializers(self): # noqa: N802 + def test_session_options_add_external_initializers(self): # Create an external initializer data in OrtValue # This initializer will replace the initializer with external data reference in the graph ortvalue_initializer = onnxrt.OrtValue.ortvalue_from_numpy(np.array([0, 0, 1, 1]).astype(np.int64)) @@ -1070,7 +1246,7 @@ def testSessionOptionsAddExternalInitializers(self): # noqa: N802 providers=["CPUExecutionProvider"], ) - def testRegisterCustomOpsLibrary(self): # noqa: N802 + def test_register_custom_ops_library(self): if sys.platform.startswith("win"): shared_library = "custom_op_library.dll" if not os.path.exists(shared_library): @@ -1124,7 +1300,7 @@ def testRegisterCustomOpsLibrary(self): # noqa: N802 custom_op_model, sess_options=so3, providers=available_providers_without_tvm_and_tensorrt ) - def testOrtValue(self): # noqa: N802 + def test_ort_value(self): numpy_arr_input = np.array([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]], dtype=np.float32) numpy_arr_output = np.array([[1.0, 4.0], [9.0, 16.0], [25.0, 36.0]], dtype=np.float32) @@ -1162,7 +1338,7 @@ def test_session_with_ortvalue_input(ortvalue): # The constructed OrtValue should still be valid after being used in a session self.assertTrue(np.array_equal(ortvalue2.numpy(), numpy_arr_input)) - def testOrtValue_ghIssue9799(self): # noqa: N802 + def test_ort_value_gh_issue9799(self): if "CUDAExecutionProvider" in onnxrt.get_available_providers(): session = onnxrt.InferenceSession( get_name("identity_9799.onnx"), @@ -1176,7 +1352,7 @@ def testOrtValue_ghIssue9799(self): # noqa: N802 outs = session.run(output_names=["output"], input_feed=upstreams_onnxrt)[0] self.assertTrue(np.allclose(inps, outs)) - def testSparseTensorCooFormat(self): # noqa: N802 + def test_sparse_tensor_coo_format(self): cpu_device = onnxrt.OrtDevice.make("cpu", 0) shape = [9, 9] values = np.array([1.0, 2.0, 3.0], dtype=np.float32) @@ -1243,7 +1419,7 @@ def testSparseTensorCooFormat(self): # noqa: N802 with self.assertRaises(RuntimeError): sparse_tensor.to_cuda(cuda_device) - def testSparseTensorCsrFormat(self): # noqa: N802 + def test_sparse_tensor_csr_format(self): cpu_device = onnxrt.OrtDevice.make("cpu", 0) shape = [9, 9] values = np.array([1.0, 2.0, 3.0], dtype=np.float32) @@ -1284,7 +1460,7 @@ def testSparseTensorCsrFormat(self): # noqa: N802 self.assertEqual(cuda_sparse_tensor.dense_shape(), shape) self.assertEqual(cuda_sparse_tensor.data_type(), "sparse_tensor(float)") - def testRunModelWithCudaCopyStream(self): # noqa: N802 + def test_run_model_with_cuda_copy_stream(self): available_providers = onnxrt.get_available_providers() if "CUDAExecutionProvider" not in available_providers: @@ -1306,11 +1482,11 @@ def testRunModelWithCudaCopyStream(self): # noqa: N802 for _iteration in range(100000): session.run(output_names=["output"], input_feed={"shape": shape}) - def testSharedAllocatorUsingCreateAndRegisterAllocator(self): # noqa: N802 + def test_shared_allocator_using_create_and_register_allocator(self): # Create and register an arena based allocator # To create an OrtArenaCfg using non-default parameters, use one of below templates: - # ort_arena_cfg = onnxrt.OrtArenaCfg(0, -1, -1, -1) - Note: doesn't expose initial_growth_chunk_size_bytes option + # ort_arena_cfg = onnxrt.OrtArenaCfg(0, -1, -1, -1) - Note: doesn't expose initial_growth_chunk_size_bytes/max_power_of_two_extend_bytes option # ort_arena_cfg = onnxrt.OrtArenaCfg({"max_mem": -1, ""arena_extend_strategy": 1, etc..}) ort_memory_info = onnxrt.OrtMemoryInfo( "Cpu", @@ -1340,7 +1516,25 @@ def testSharedAllocatorUsingCreateAndRegisterAllocator(self): # noqa: N802 providers=onnxrt.get_available_providers(), ) - def testMemoryArenaShrinkage(self): # noqa: N802 + if "CUDAExecutionProvider" in available_providers: + cuda_mem_info = onnxrt.OrtMemoryInfo( + "Cuda", + onnxrt.OrtAllocatorType.ORT_ARENA_ALLOCATOR, + 0, + onnxrt.OrtMemType.DEFAULT, + ) + ort_arena_cfg = onnxrt.OrtArenaCfg(0, -1, -1, -1) + onnxrt.create_and_register_allocator_v2("CUDAExecutionProvider", cuda_mem_info, {}, ort_arena_cfg) + so3 = onnxrt.SessionOptions() + so3.log_severity_level = 1 + so3.add_session_config_entry("session.use_env_allocators", "1") + onnxrt.InferenceSession( + get_name("mul_1.onnx"), + sess_options=so3, + providers=onnxrt.get_available_providers(), + ) + + def test_memory_arena_shrinkage(self): if platform.architecture()[0] == "32bit" or "ppc" in platform.machine() or "powerpc" in platform.machine(): # on x86 or ppc builds, the CPU allocator does not use an arena print("Skipping testMemoryArenaShrinkage in 32bit or powerpc platform.") @@ -1373,7 +1567,7 @@ def testMemoryArenaShrinkage(self): # noqa: N802 ) sess2.run([], {input_name: x}, ro2) - def testCheckAndNormalizeProviderArgs(self): # noqa: N802 + def test_check_and_normalize_provider_args(self): from onnxruntime.capi.onnxruntime_inference_collection import check_and_normalize_provider_args valid_providers = ["a", "b", "c"] @@ -1425,7 +1619,7 @@ def check_failure(providers, provider_options): # provider options unsupported mixed specification check_failure([("a", {1: 2})], [{3: 4}]) - def testRegisterCustomEPsLibrary(self): # noqa: N802 + def test_register_custom_e_ps_library(self): from onnxruntime.capi import _pybind_state as C available_eps = C.get_available_providers() @@ -1465,7 +1659,7 @@ def testRegisterCustomEPsLibrary(self): # noqa: N802 ) print("Create session with customize execution provider successfully!") - def testCreateAllocator(self): # noqa: N802 + def test_create_allocator(self): def verify_allocator(allocator, expected_config): for key, val in expected_config.items(): if key == "max_mem": @@ -1478,6 +1672,8 @@ def verify_allocator(allocator, expected_config): self.assertEqual(allocator.max_dead_bytes_per_chunk, val) elif key == "initial_growth_chunk_size_bytes": self.assertEqual(allocator.initial_growth_chunk_size_bytes, val) + elif key == "max_power_of_two_extend_bytes": + self.assertEqual(allocator.max_power_of_two_extend_bytes, val) else: raise ValueError("Invalid OrtArenaCfg option: " + key) @@ -1502,6 +1698,18 @@ def verify_allocator(allocator, expected_config): ort_arena_cfg_kvp = onnxrt.OrtArenaCfg(expected_kvp_allocator) verify_allocator(ort_arena_cfg_kvp, expected_kvp_allocator) + # Verify key-value pair initialization + expected_kvp_allocator = { + "max_mem": 32, + "arena_extend_strategy": 11, + "initial_chunk_size_bytes": 18, + "max_dead_bytes_per_chunk": 14, + "initial_growth_chunk_size_bytes": 12, + "max_power_of_two_extend_bytes": 17, + } + ort_arena_cfg_kvp = onnxrt.OrtArenaCfg(expected_kvp_allocator) + verify_allocator(ort_arena_cfg_kvp, expected_kvp_allocator) + if __name__ == "__main__": unittest.main(verbosity=1) diff --git a/onnxruntime/test/python/onnxruntime_test_python_azure.py b/onnxruntime/test/python/onnxruntime_test_python_azure.py index 24bf928a29cbf..f20da21f7e79d 100644 --- a/onnxruntime/test/python/onnxruntime_test_python_azure.py +++ b/onnxruntime/test/python/onnxruntime_test_python_azure.py @@ -1,107 +1,14 @@ -import unittest +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. -import numpy as np -from helper import get_name +import unittest import onnxruntime as ort -class TestAmlEndpoint(unittest.TestCase): - # test an endpoint of adding floats - def testAddf(self): # noqa: N802 - sess_opt = ort.SessionOptions() - sess_opt.add_session_config_entry("azure.endpoint_type", "triton") - sess_opt.add_session_config_entry("azure.uri", "https://endpoint-2930.westus2.inference.ml.azure.com") - sess_opt.add_session_config_entry("azure.model_name", "addf") - sess_opt.add_session_config_entry("azure.model_version", "1") - sess_opt.add_session_config_entry("azure.verbose", "true") - - sess = ort.InferenceSession(get_name("azure_models/addf.onnx"), sess_opt, providers=["CPUExecutionProvider"]) - - run_opt = ort.RunOptions() - run_opt.log_severity_level = 1 - run_opt.add_run_config_entry("use_azure", "1") - run_opt.add_run_config_entry("azure.auth_key", "lVUg86Ba7abAZU3GeKAMEtYy1wy9LacX") - - x = np.array([1, 2, 3, 4]).astype(np.float32) - y = np.array([4, 3, 2, 1]).astype(np.float32) - - z = sess.run(None, {"X": x, "Y": y}, run_opt)[0] - - expected_z = np.array([5, 5, 5, 5]).astype(np.float32) - np.testing.assert_allclose(z, expected_z, rtol=1e-05, atol=1e-08) - - # test an endpoint of adding doubles - def testAddf8(self): # noqa: N802 - sess_opt = ort.SessionOptions() - sess_opt.add_session_config_entry("azure.endpoint_type", "triton") - sess_opt.add_session_config_entry("azure.uri", "https://endpoint-1364.westus2.inference.ml.azure.com") - sess_opt.add_session_config_entry("azure.model_name", "addf8") - sess_opt.add_session_config_entry("azure.model_version", "1") - sess_opt.add_session_config_entry("azure.verbose", "true") - - sess = ort.InferenceSession(get_name("azure_models/addf8.onnx"), sess_opt, providers=["CPUExecutionProvider"]) - - run_opt = ort.RunOptions() - run_opt.log_severity_level = 1 - run_opt.add_run_config_entry("use_azure", "1") - run_opt.add_run_config_entry("azure.auth_key", "bUxzw3kZxJMjUbntLcVU3Duqq1nc87m5") - - x = np.array([1, 2, 3, 4]).astype(np.double) - y = np.array([4, 3, 2, 1]).astype(np.double) - - z = sess.run(None, {"X": x, "Y": y}, run_opt)[0] - - expected_z = np.array([5, 5, 5, 5]).astype(np.double) - np.testing.assert_allclose(z, expected_z, rtol=1e-05, atol=1e-08) - - # test an endpoint of adding int - def testAddi4(self): # noqa: N802 - sess_opt = ort.SessionOptions() - sess_opt.add_session_config_entry("azure.endpoint_type", "triton") - sess_opt.add_session_config_entry("azure.uri", "https://endpoint-9879.westus2.inference.ml.azure.com") - sess_opt.add_session_config_entry("azure.model_name", "addi4") - sess_opt.add_session_config_entry("azure.model_version", "1") - sess_opt.add_session_config_entry("azure.verbose", "true") - - sess = ort.InferenceSession(get_name("azure_models/addi4.onnx"), sess_opt, providers=["CPUExecutionProvider"]) - - run_opt = ort.RunOptions() - run_opt.log_severity_level = 1 - run_opt.add_run_config_entry("use_azure", "1") - run_opt.add_run_config_entry("azure.auth_key", "hRflo7KIj1DoOdfLw5R8PphBiMBOY4C8") - - x = np.array([1, 2, 3, 4]).astype(np.int32) - y = np.array([4, 3, 2, 1]).astype(np.int32) - - z = sess.run(None, {"X": x, "Y": y}, run_opt)[0] - - expected_z = np.array([5, 5, 5, 5]).astype(np.int32) - np.testing.assert_allclose(z, expected_z, rtol=1e-05, atol=1e-08) - - # test an endpoint of "And" - def testAnd(self): # noqa: N802 - sess_opt = ort.SessionOptions() - sess_opt.add_session_config_entry("azure.endpoint_type", "triton") - sess_opt.add_session_config_entry("azure.uri", "https://endpoint-6811.westus2.inference.ml.azure.com") - sess_opt.add_session_config_entry("azure.model_name", "and") - sess_opt.add_session_config_entry("azure.model_version", "1") - sess_opt.add_session_config_entry("azure.verbose", "true") - - sess = ort.InferenceSession(get_name("azure_models/and.onnx"), sess_opt, providers=["CPUExecutionProvider"]) - - run_opt = ort.RunOptions() - run_opt.log_severity_level = 1 - run_opt.add_run_config_entry("use_azure", "1") - run_opt.add_run_config_entry("azure.auth_key", "fdCZuuoHEimRb4ukWZhtLhbcwzyKYgUu") - - x = np.array([True, False]).astype(bool) - y = np.array([True, True]).astype(bool) - - z = sess.run(None, {"X": x, "Y": y}, run_opt)[0] - - expected_z = np.array([True, False]).astype(bool) - np.testing.assert_allclose(z, expected_z, rtol=1e-05, atol=1e-08) +class TestAzureEP(unittest.TestCase): + def test_availability(self): + self.assertIn("AzureExecutionProvider", ort.get_available_providers()) if __name__ == "__main__": diff --git a/onnxruntime/test/python/onnxruntime_test_python_backend.py b/onnxruntime/test/python/onnxruntime_test_python_backend.py index b7fb95f834455..1f6cd78f28334 100644 --- a/onnxruntime/test/python/onnxruntime_test_python_backend.py +++ b/onnxruntime/test/python/onnxruntime_test_python_backend.py @@ -13,7 +13,7 @@ class TestBackend(unittest.TestCase): - def testRunModel(self): # noqa: N802 + def test_run_model(self): name = get_name("mul_1.onnx") rep = backend.prepare(name) x = np.array([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]], dtype=np.float32) @@ -21,7 +21,7 @@ def testRunModel(self): # noqa: N802 output_expected = np.array([[1.0, 4.0], [9.0, 16.0], [25.0, 36.0]], dtype=np.float32) np.testing.assert_allclose(output_expected, res[0], rtol=1e-05, atol=1e-08) - def testAllocationPlanWorksWithOnlyExecutePathToFetchesOption(self): # noqa: N802 + def test_allocation_plan_works_with_only_execute_path_to_fetches_option(self): """ (inp0) (inp1) | \\/ | diff --git a/onnxruntime/test/python/onnxruntime_test_python_backend_mlops.py b/onnxruntime/test/python/onnxruntime_test_python_backend_mlops.py index 42103fbbe3bc7..b5400b487cfc2 100644 --- a/onnxruntime/test/python/onnxruntime_test_python_backend_mlops.py +++ b/onnxruntime/test/python/onnxruntime_test_python_backend_mlops.py @@ -32,7 +32,7 @@ def check_list_of_map_to_float(testcase, expected_rows, actual_rows): class TestBackend(unittest.TestCase): - def testRunModelNonTensor(self): # noqa: N802 + def test_run_model_non_tensor(self): name = get_name("pipeline_vectorize.onnx") rep = backend.prepare(name) x = {0: 25.0, 1: 5.13, 2: 0.0, 3: 0.453, 4: 5.966} @@ -40,7 +40,7 @@ def testRunModelNonTensor(self): # noqa: N802 output_expected = np.array([[49.752754]], dtype=np.float32) np.testing.assert_allclose(output_expected, res[0], rtol=1e-05, atol=1e-08) - def testRunModelProto(self): # noqa: N802 + def test_run_model_proto(self): name = datasets.get_example("logreg_iris.onnx") model = load(name) @@ -65,7 +65,7 @@ def testRunModelProto(self): # noqa: N802 check_list_of_map_to_float(self, output_expected, res[1]) - def testRunModelProtoApi(self): # noqa: N802 + def test_run_model_proto_api(self): name = datasets.get_example("logreg_iris.onnx") model = load(name) diff --git a/onnxruntime/test/python/onnxruntime_test_python_cudagraph.py b/onnxruntime/test/python/onnxruntime_test_python_cudagraph.py index 5dd927a566e81..c4e13e773535d 100644 --- a/onnxruntime/test/python/onnxruntime_test_python_cudagraph.py +++ b/onnxruntime/test/python/onnxruntime_test_python_cudagraph.py @@ -1,24 +1,67 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -import gc # noqa: F401 -import os # noqa: F401 -import sys # noqa: F401 -import threading # noqa: F401 -import time # noqa: F401 - -# -*- coding: UTF-8 -*- import unittest +from typing import Dict, List import numpy as np from helper import get_name import onnxruntime as onnxrt -from onnxruntime.capi.onnxruntime_pybind11_state import Fail # noqa: F401 + + +class CudaGraphHelper: + def __init__( + self, + ort_session: onnxrt.InferenceSession, + input_and_output_shape: Dict[str, List[int]], + device_id: int = 0, + ): + self.input_names = [input.name for input in ort_session.get_inputs()] + self.output_names = [output.name for output in ort_session.get_outputs()] + + self.input_and_output_shape = input_and_output_shape + self.io_numpy_type = self.get_io_numpy_type_map(ort_session) + self.io_binding = ort_session.io_binding() + self.io_ort_value = {} + + for name in self.input_names + self.output_names: + ort_value = onnxrt.OrtValue.ortvalue_from_shape_and_type( + input_and_output_shape[name], self.io_numpy_type[name], "cuda", device_id + ) + self.io_ort_value[name] = ort_value + if name in self.input_names: + self.io_binding.bind_ortvalue_input(name, ort_value) + else: + self.io_binding.bind_ortvalue_output(name, ort_value) + + def get_io_numpy_type_map(self, ort_session: onnxrt.InferenceSession): + ort_type_to_numpy_type = { + "tensor(int64)": np.longlong, + "tensor(int32)": np.intc, + "tensor(float)": np.float32, + "tensor(float16)": np.float16, + } + + name_to_numpy_type = {} + for _input in ort_session.get_inputs(): + name_to_numpy_type[_input.name] = ort_type_to_numpy_type[_input.type] + + for output in ort_session.get_outputs(): + name_to_numpy_type[output.name] = ort_type_to_numpy_type[output.type] + + return name_to_numpy_type + + def update_inputs(self, inputs: Dict[str, np.ndarray]): + for input_name in self.input_names: + self.io_ort_value[input_name].update_inplace(inputs[input_name]) + + def get_output(self, output_name: str): + return self.io_ort_value[output_name].numpy() class TestInferenceSessionWithCudaGraph(unittest.TestCase): - def testOrtValueUpdateInPlace(self): # noqa: N802 + def test_ort_value_update_in_place(self): x0 = np.array([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]], dtype=np.float32) ortvalue_cpu = onnxrt.OrtValue.ortvalue_from_numpy(x0) np.testing.assert_allclose(x0, ortvalue_cpu.numpy()) @@ -34,45 +77,90 @@ def testOrtValueUpdateInPlace(self): # noqa: N802 ortvalue_gpu.update_inplace(x1) np.testing.assert_allclose(x1, ortvalue_gpu.numpy()) - def testRunModelWithCudaGraph(self): # noqa: N802 - if "CUDAExecutionProvider" in onnxrt.get_available_providers(): + def test_select_ep_to_run_cuda_graph(self): + if "TensorrtExecutionProvider" in onnxrt.get_available_providers(): + providers = [("TensorrtExecutionProvider", {"trt_cuda_graph_enable": True})] + self.run_model_with_cuda_graph(providers) + elif "CUDAExecutionProvider" in onnxrt.get_available_providers(): providers = [("CUDAExecutionProvider", {"enable_cuda_graph": True})] - INPUT_SIZE = 1280 # noqa: N806 - x = np.array([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]] * INPUT_SIZE, dtype=np.float32) - y = np.array([[0.0], [0.0], [0.0]] * INPUT_SIZE, dtype=np.float32) - x_ortvalue = onnxrt.OrtValue.ortvalue_from_numpy(x, "cuda", 0) - y_ortvalue = onnxrt.OrtValue.ortvalue_from_numpy(y, "cuda", 0) - - session = onnxrt.InferenceSession(get_name("matmul_2.onnx"), providers=providers) - io_binding = session.io_binding() - - # Bind the input and output - io_binding.bind_ortvalue_input("X", x_ortvalue) - io_binding.bind_ortvalue_output("Y", y_ortvalue) + self.run_model_with_cuda_graph(providers) + + def run_model_with_cuda_graph(self, providers): + INPUT_SIZE = 1280 # noqa: N806 + x = np.array([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]] * INPUT_SIZE, dtype=np.float32) + y = np.array([[0.0], [0.0], [0.0]] * INPUT_SIZE, dtype=np.float32) + x_ortvalue = onnxrt.OrtValue.ortvalue_from_numpy(x, "cuda", 0) + y_ortvalue = onnxrt.OrtValue.ortvalue_from_numpy(y, "cuda", 0) + + onnxrt.set_default_logger_severity(0) + session = onnxrt.InferenceSession(get_name("matmul_2.onnx"), providers=providers) + io_binding = session.io_binding() + + # Bind the input and output + io_binding.bind_ortvalue_input("X", x_ortvalue) + io_binding.bind_ortvalue_output("Y", y_ortvalue) + + # One regular run for the necessary memory allocation and cuda graph capturing + session.run_with_iobinding(io_binding) + expected_y = np.array([[5.0], [11.0], [17.0]] * INPUT_SIZE, dtype=np.float32) + np.testing.assert_allclose(expected_y, y_ortvalue.numpy(), rtol=1e-05, atol=1e-05) + + # After capturing, CUDA graph replay happens from this Run onwards + session.run_with_iobinding(io_binding) + np.testing.assert_allclose(expected_y, y_ortvalue.numpy(), rtol=1e-05, atol=1e-05) + + # Update input and then replay CUDA graph + x_ortvalue.update_inplace( + np.array( + [[10.0, 20.0], [30.0, 40.0], [50.0, 60.0]] * INPUT_SIZE, + dtype=np.float32, + ) + ) + session.run_with_iobinding(io_binding) + np.testing.assert_allclose( + np.array([[50.0], [110.0], [170.0]] * INPUT_SIZE, dtype=np.float32), + y_ortvalue.numpy(), + rtol=1e-05, + atol=1e-05, + ) + + def test_arena_with_cuda_graph(self): + if "CUDAExecutionProvider" in onnxrt.get_available_providers(): + # To test cuda graph catpure, we set Arena extend strategy to be SameAsRequested so as to detect any + # potential memory allocation after the first run. + providers = [ + ("CUDAExecutionProvider", {"enable_cuda_graph": True, "arena_extend_strategy": "kSameAsRequested"}) + ] + test_model_path = get_name("squeezenet/model.onnx") + + input_and_output_shape = { + "data_0": [16, 3, 224, 224], + "softmaxout_1": [16, 1000, 1, 1], + } + + session_options = onnxrt.SessionOptions() + # It is optional to disable memory pattern since min_num_runs_before_cuda_graph_capture_ = 2. + session_options.enable_mem_pattern = False + session = onnxrt.InferenceSession(test_model_path, session_options, providers=providers) + + cuda_graph_helper = CudaGraphHelper(session, input_and_output_shape) + io_binding = cuda_graph_helper.io_binding + + # Create a random input for testing. + np.random.seed(0) + inputs = {"data_0": np.random.randint(0, 256, size=input_and_output_shape["data_0"]).astype(np.float32)} # One regular run for the necessary memory allocation and cuda graph capturing + cuda_graph_helper.update_inputs(inputs) session.run_with_iobinding(io_binding) - expected_y = np.array([[5.0], [11.0], [17.0]] * INPUT_SIZE, dtype=np.float32) - np.testing.assert_allclose(expected_y, y_ortvalue.numpy(), rtol=1e-05, atol=1e-05) + expected_output = cuda_graph_helper.get_output("softmaxout_1") # After capturing, CUDA graph replay happens from this Run onwards + cuda_graph_helper.update_inputs(inputs) session.run_with_iobinding(io_binding) - np.testing.assert_allclose(expected_y, y_ortvalue.numpy(), rtol=1e-05, atol=1e-05) - - # Update input and then replay CUDA graph - x_ortvalue.update_inplace( - np.array( - [[10.0, 20.0], [30.0, 40.0], [50.0, 60.0]] * INPUT_SIZE, - dtype=np.float32, - ) - ) - session.run_with_iobinding(io_binding) - np.testing.assert_allclose( - np.array([[50.0], [110.0], [170.0]] * INPUT_SIZE, dtype=np.float32), - y_ortvalue.numpy(), - rtol=1e-05, - atol=1e-05, - ) + output = cuda_graph_helper.get_output("softmaxout_1") + + np.testing.assert_allclose(expected_output, output, rtol=1e-02, atol=1e-02) if __name__ == "__main__": diff --git a/onnxruntime/test/python/onnxruntime_test_python_iobinding.py b/onnxruntime/test/python/onnxruntime_test_python_iobinding.py index 8009d97ba34ce..56417f13fbea4 100644 --- a/onnxruntime/test/python/onnxruntime_test_python_iobinding.py +++ b/onnxruntime/test/python/onnxruntime_test_python_iobinding.py @@ -16,40 +16,43 @@ from onnxruntime.capi._pybind_state import OrtValue as C_OrtValue from onnxruntime.capi._pybind_state import OrtValueVector, SessionIOBinding +test_params = [ + ("cuda", "CUDAExecutionProvider", C_OrtDevice.cuda), + ("dml", "DmlExecutionProvider", C_OrtDevice.dml), +] + class TestIOBinding(unittest.TestCase): - def create_ortvalue_input_on_gpu(self): + def _create_ortvalue_input_on_gpu(self, device): return onnxrt.OrtValue.ortvalue_from_numpy( - np.array([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]], dtype=np.float32), "cuda", 0 + np.array([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]], dtype=np.float32), device, 0 ) - def create_ortvalue_alternate_input_on_gpu(self): + def _create_ortvalue_alternate_input_on_gpu(self, device): return onnxrt.OrtValue.ortvalue_from_numpy( np.array([[2.0, 4.0], [6.0, 8.0], [10.0, 12.0]], dtype=np.float32), - "cuda", + device, 0, ) - def create_uninitialized_ortvalue_input_on_gpu(self): - return onnxrt.OrtValue.ortvalue_from_shape_and_type([3, 2], np.float32, "cuda", 0) + def _create_uninitialized_ortvalue_input_on_gpu(self, device): + return onnxrt.OrtValue.ortvalue_from_shape_and_type([3, 2], np.float32, device, 0) - def create_numpy_input(self): + def _create_numpy_input(self): return np.array([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]], dtype=np.float32) - def create_expected_output(self): + def _create_expected_output(self): return np.array([[1.0, 4.0], [9.0, 16.0], [25.0, 36.0]], dtype=np.float32) - def create_expected_output_alternate(self): + def _create_expected_output_alternate(self): return np.array([[2.0, 8.0], [18.0, 32.0], [50.0, 72.0]], dtype=np.float32) def test_bind_input_to_cpu_arr(self): - self.create_numpy_input() - session = onnxrt.InferenceSession(get_name("mul_1.onnx"), providers=onnxrt.get_available_providers()) io_binding = session.io_binding() # Bind Numpy object (input) that's on CPU to wherever the model needs it - io_binding.bind_cpu_input("X", self.create_numpy_input()) + io_binding.bind_cpu_input("X", self._create_numpy_input()) # Bind output to CPU io_binding.bind_output("Y") @@ -57,254 +60,280 @@ def test_bind_input_to_cpu_arr(self): # Invoke Run session.run_with_iobinding(io_binding) - # Sync if different CUDA streams + # Sync if different streams io_binding.synchronize_outputs() - # Get outputs over to CPU (the outputs which were bound to CUDA will get copied over to the host here) + # Get outputs over to CPU (the outputs which were bound to the GPU will get copied over to the host here) ort_output = io_binding.copy_outputs_to_cpu()[0] # Validate results - self.assertTrue(np.array_equal(self.create_expected_output(), ort_output)) + self.assertTrue(np.array_equal(self._create_expected_output(), ort_output)) - @unittest.skip("Could not find an implementation for Identity(19) node with name ''") def test_bind_input_types(self): - opset = onnx_opset_version() - devices = [ - ( - C_OrtDevice(C_OrtDevice.cpu(), C_OrtDevice.default_memory(), 0), - ["CPUExecutionProvider"], - ) - ] - if "CUDAExecutionProvider" in onnxrt.get_all_providers(): - devices.append( - ( - C_OrtDevice(C_OrtDevice.cuda(), C_OrtDevice.default_memory(), 0), - ["CUDAExecutionProvider"], - ) - ) - - for device, provider in devices: - for dtype in [ - np.float32, - np.float64, - np.int32, - np.uint32, - np.int64, - np.uint64, - np.int16, - np.uint16, - np.int8, - np.uint8, - np.float16, - np.bool_, - ]: - with self.subTest(dtype=dtype, device=str(device)): - x = np.arange(8).reshape((-1, 2)).astype(dtype) - proto_dtype = NP_TYPE_TO_TENSOR_TYPE[x.dtype] - - X = helper.make_tensor_value_info("X", proto_dtype, [None, x.shape[1]]) # noqa: N806 - Y = helper.make_tensor_value_info("Y", proto_dtype, [None, x.shape[1]]) # noqa: N806 - - # inference - node_add = helper.make_node("Identity", ["X"], ["Y"]) - - # graph - graph_def = helper.make_graph([node_add], "lr", [X], [Y], []) - model_def = helper.make_model( - graph_def, - producer_name="dummy", - ir_version=7, - producer_version="0", - opset_imports=[helper.make_operatorsetid("", opset)], - ) - - sess = onnxrt.InferenceSession(model_def.SerializeToString(), providers=provider) - - bind = SessionIOBinding(sess._sess) - ort_value = C_OrtValue.ortvalue_from_numpy(x, device) - bind.bind_ortvalue_input("X", ort_value) - bind.bind_output("Y", device) - sess._sess.run_with_iobinding(bind, None) - ortvaluevector = bind.get_outputs() - self.assertIsInstance(ortvaluevector, OrtValueVector) - ortvalue = bind.get_outputs()[0] - y = ortvalue.numpy() - assert_almost_equal(x, y) - - bind = SessionIOBinding(sess._sess) - bind.bind_input("X", device, dtype, x.shape, ort_value.data_ptr()) - bind.bind_output("Y", device) - sess._sess.run_with_iobinding(bind, None) - ortvalue = bind.get_outputs()[0] - y = ortvalue.numpy() - assert_almost_equal(x, y) + for device, execution_provider, generate_device in test_params: + with self.subTest(execution_provider): + if execution_provider not in onnxrt.get_available_providers(): + self.skipTest(f"Skipping on {device.upper()}.") + + opset = onnx_opset_version() + devices = [ + ( + C_OrtDevice(C_OrtDevice.cpu(), C_OrtDevice.default_memory(), 0), + ["CPUExecutionProvider"], + ), + ( + C_OrtDevice(generate_device(), C_OrtDevice.default_memory(), 0), + [execution_provider], + ), + ] + + for inner_device, provider in devices: + for dtype in [ + np.float32, + np.float64, + np.int32, + np.uint32, + np.int64, + np.uint64, + np.int16, + np.uint16, + np.int8, + np.uint8, + np.float16, + np.bool_, + ]: + with self.subTest(dtype=dtype, inner_device=str(inner_device)): + x = np.arange(8).reshape((-1, 2)).astype(dtype) + proto_dtype = NP_TYPE_TO_TENSOR_TYPE[x.dtype] + + X = helper.make_tensor_value_info("X", proto_dtype, [None, x.shape[1]]) # noqa: N806 + Y = helper.make_tensor_value_info("Y", proto_dtype, [None, x.shape[1]]) # noqa: N806 + + # inference + node_add = helper.make_node("Identity", ["X"], ["Y"]) + + # graph + graph_def = helper.make_graph([node_add], "lr", [X], [Y], []) + model_def = helper.make_model( + graph_def, + producer_name="dummy", + ir_version=7, + producer_version="0", + opset_imports=[helper.make_operatorsetid("", opset)], + ) + + sess = onnxrt.InferenceSession(model_def.SerializeToString(), providers=provider) + + bind = SessionIOBinding(sess._sess) + ort_value = C_OrtValue.ortvalue_from_numpy(x, inner_device) + bind.bind_ortvalue_input("X", ort_value) + bind.bind_output("Y", inner_device) + sess._sess.run_with_iobinding(bind, None) + ortvaluevector = bind.get_outputs() + self.assertIsInstance(ortvaluevector, OrtValueVector) + ortvalue = bind.get_outputs()[0] + y = ortvalue.numpy() + assert_almost_equal(x, y) + + bind = SessionIOBinding(sess._sess) + bind.bind_input("X", inner_device, dtype, x.shape, ort_value.data_ptr()) + bind.bind_output("Y", inner_device) + sess._sess.run_with_iobinding(bind, None) + ortvalue = bind.get_outputs()[0] + y = ortvalue.numpy() + assert_almost_equal(x, y) def test_bind_input_only(self): - input = self.create_ortvalue_input_on_gpu() + for device, execution_provider, _ in test_params: + with self.subTest(execution_provider): + if execution_provider not in onnxrt.get_available_providers(): + self.skipTest(f"Skipping on {device.upper()}.") + input = self._create_ortvalue_input_on_gpu(device) - session = onnxrt.InferenceSession(get_name("mul_1.onnx"), providers=onnxrt.get_available_providers()) - io_binding = session.io_binding() + session = onnxrt.InferenceSession(get_name("mul_1.onnx"), providers=onnxrt.get_available_providers()) + io_binding = session.io_binding() - # Bind input to CUDA - io_binding.bind_input("X", "cuda", 0, np.float32, [3, 2], input.data_ptr()) + # Bind input to the GPU + io_binding.bind_input("X", device, 0, np.float32, [3, 2], input.data_ptr()) - # Sync if different CUDA streams - io_binding.synchronize_inputs() + # Sync if different streams + io_binding.synchronize_inputs() - # Bind output to CPU - io_binding.bind_output("Y") + # Bind output to CPU + io_binding.bind_output("Y") - # Invoke Run - session.run_with_iobinding(io_binding) + # Invoke Run + session.run_with_iobinding(io_binding) - # Sync if different CUDA streams - io_binding.synchronize_outputs() + # Sync if different streams + io_binding.synchronize_outputs() - # Get outputs over to CPU (the outputs which were bound to CUDA will get copied over to the host here) - ort_output = io_binding.copy_outputs_to_cpu()[0] + # Get outputs over to CPU (the outputs which were bound to the GPU will get copied over to the host + # here) + ort_output = io_binding.copy_outputs_to_cpu()[0] - # Validate results - self.assertTrue(np.array_equal(self.create_expected_output(), ort_output)) + # Validate results + self.assertTrue(np.array_equal(self._create_expected_output(), ort_output)) def test_bind_input_and_preallocated_output(self): - input = self.create_ortvalue_input_on_gpu() + for device, execution_provider, _ in test_params: + with self.subTest(execution_provider): + if execution_provider not in onnxrt.get_available_providers(): + self.skipTest(f"Skipping on {device.upper()}.") - session = onnxrt.InferenceSession(get_name("mul_1.onnx"), providers=onnxrt.get_available_providers()) - io_binding = session.io_binding() - - # Bind input to CUDA - io_binding.bind_input("X", "cuda", 0, np.float32, [3, 2], input.data_ptr()) - - # Bind output to CUDA - output = self.create_uninitialized_ortvalue_input_on_gpu() - io_binding.bind_output("Y", "cuda", 0, np.float32, [3, 2], output.data_ptr()) - - # Sync if different CUDA streams - io_binding.synchronize_inputs() - - # Invoke Run - session.run_with_iobinding(io_binding) + input = self._create_ortvalue_input_on_gpu(device) - # Sync if different CUDA streams - io_binding.synchronize_outputs() + session = onnxrt.InferenceSession(get_name("mul_1.onnx"), providers=onnxrt.get_available_providers()) + io_binding = session.io_binding() - # Get outputs over to CPU (the outputs which were bound to CUDA will get copied over to the host here) - ort_output_vals = io_binding.copy_outputs_to_cpu()[0] - # Validate results - self.assertTrue(np.array_equal(self.create_expected_output(), ort_output_vals)) + # Bind input to the GPU + io_binding.bind_input("X", device, 0, np.float32, [3, 2], input.data_ptr()) - # Validate if ORT actually wrote to pre-allocated buffer by copying the Torch allocated buffer - # to the host and validating its contents - ort_output_vals_in_cpu = output.numpy() - # Validate results - self.assertTrue(np.array_equal(self.create_expected_output(), ort_output_vals_in_cpu)) + # Bind output to the GPU + output = self._create_uninitialized_ortvalue_input_on_gpu(device) + io_binding.bind_output("Y", device, 0, np.float32, [3, 2], output.data_ptr()) - def test_bind_input_and_non_preallocated_output(self): - session = onnxrt.InferenceSession(get_name("mul_1.onnx"), providers=onnxrt.get_available_providers()) - io_binding = session.io_binding() + # Sync if different streams + io_binding.synchronize_inputs() - # Bind input to CUDA - io_binding.bind_input( - "X", - "cuda", - 0, - np.float32, - [3, 2], - self.create_ortvalue_input_on_gpu().data_ptr(), - ) + # Invoke Run + session.run_with_iobinding(io_binding) - # Bind output to CUDA - io_binding.bind_output("Y", "cuda") + # Sync if different streams + io_binding.synchronize_outputs() - # Sync if different CUDA streams - io_binding.synchronize_inputs() + # Get outputs over to CPU (the outputs which were bound to the GPU will get copied over to the host + # here) + ort_output_vals = io_binding.copy_outputs_to_cpu()[0] + # Validate results + self.assertTrue(np.array_equal(self._create_expected_output(), ort_output_vals)) - # Invoke Run - session.run_with_iobinding(io_binding) + # Validate if ORT actually wrote to pre-allocated buffer by copying the allocated buffer + # to the host and validating its contents + ort_output_vals_in_cpu = output.numpy() + # Validate results + self.assertTrue(np.array_equal(self._create_expected_output(), ort_output_vals_in_cpu)) - # Sync if different CUDA streams - io_binding.synchronize_outputs() + def test_bind_input_and_non_preallocated_output(self): + for device, execution_provider, _ in test_params: + with self.subTest(execution_provider): + if execution_provider not in onnxrt.get_available_providers(): + self.skipTest(f"Skipping on {device.upper()}.") + + session = onnxrt.InferenceSession(get_name("mul_1.onnx"), providers=onnxrt.get_available_providers()) + io_binding = session.io_binding() + + input = self._create_ortvalue_input_on_gpu(device) + + # Bind input to the GPU + io_binding.bind_input( + "X", + device, + 0, + np.float32, + [3, 2], + input.data_ptr(), + ) - # This call returns an OrtValue which has data allocated by ORT on CUDA - ort_outputs = io_binding.get_outputs() - self.assertEqual(len(ort_outputs), 1) - self.assertEqual(ort_outputs[0].device_name(), "cuda") - # Validate results (by copying results to CPU by creating a Numpy object) - self.assertTrue(np.array_equal(self.create_expected_output(), ort_outputs[0].numpy())) - - # We should be able to repeat the above process as many times as we want - try once more - ort_outputs = io_binding.get_outputs() - self.assertEqual(len(ort_outputs), 1) - self.assertEqual(ort_outputs[0].device_name(), "cuda") - # Validate results (by copying results to CPU by creating a Numpy object) - self.assertTrue(np.array_equal(self.create_expected_output(), ort_outputs[0].numpy())) - - # Change the bound input and validate the results in the same bound OrtValue - # Bind alternate input to CUDA - io_binding.bind_input( - "X", - "cuda", - 0, - np.float32, - [3, 2], - self.create_ortvalue_alternate_input_on_gpu().data_ptr(), - ) + # Bind output to the GPU + io_binding.bind_output("Y", device) + + # Sync if different streams + io_binding.synchronize_inputs() + + # Invoke Run + session.run_with_iobinding(io_binding) + + # Sync if different streams + io_binding.synchronize_outputs() + + # This call returns an OrtValue which has data allocated by ORT on the GPU + ort_outputs = io_binding.get_outputs() + self.assertEqual(len(ort_outputs), 1) + self.assertEqual(ort_outputs[0].device_name(), device) + # Validate results (by copying results to CPU by creating a Numpy object) + self.assertTrue(np.array_equal(self._create_expected_output(), ort_outputs[0].numpy())) + + # We should be able to repeat the above process as many times as we want - try once more + ort_outputs = io_binding.get_outputs() + self.assertEqual(len(ort_outputs), 1) + self.assertEqual(ort_outputs[0].device_name(), device) + # Validate results (by copying results to CPU by creating a Numpy object) + self.assertTrue(np.array_equal(self._create_expected_output(), ort_outputs[0].numpy())) + + input = self._create_ortvalue_alternate_input_on_gpu(device) + + # Change the bound input and validate the results in the same bound OrtValue + # Bind alternate input to the GPU + io_binding.bind_input( + "X", + device, + 0, + np.float32, + [3, 2], + input.data_ptr(), + ) - # Sync if different CUDA streams - io_binding.synchronize_inputs() + # Sync if different streams + io_binding.synchronize_inputs() - # Invoke Run - session.run_with_iobinding(io_binding) + # Invoke Run + session.run_with_iobinding(io_binding) - # Sync if different CUDA streams - io_binding.synchronize_outputs() + # Sync if different streams + io_binding.synchronize_outputs() - # This call returns an OrtValue which has data allocated by ORT on CUDA - ort_outputs = io_binding.get_outputs() - self.assertEqual(len(ort_outputs), 1) - self.assertEqual(ort_outputs[0].device_name(), "cuda") - # Validate results (by copying results to CPU by creating a Numpy object) - self.assertTrue(np.array_equal(self.create_expected_output_alternate(), ort_outputs[0].numpy())) + # This call returns an OrtValue which has data allocated by ORT on the GPU + ort_outputs = io_binding.get_outputs() + self.assertEqual(len(ort_outputs), 1) + self.assertEqual(ort_outputs[0].device_name(), device) + # Validate results (by copying results to CPU by creating a Numpy object) + self.assertTrue(np.array_equal(self._create_expected_output_alternate(), ort_outputs[0].numpy())) def test_bind_input_and_bind_output_with_ortvalues(self): - session = onnxrt.InferenceSession(get_name("mul_1.onnx"), providers=onnxrt.get_available_providers()) - io_binding = session.io_binding() + for device, execution_provider, _ in test_params: + with self.subTest(execution_provider): + if execution_provider not in onnxrt.get_available_providers(): + self.skipTest(f"Skipping on {device.upper()}.") - # Bind ortvalue as input - input_ortvalue = self.create_ortvalue_input_on_gpu() - io_binding.bind_ortvalue_input("X", input_ortvalue) + session = onnxrt.InferenceSession(get_name("mul_1.onnx"), providers=onnxrt.get_available_providers()) + io_binding = session.io_binding() - # Bind ortvalue as output - output_ortvalue = self.create_uninitialized_ortvalue_input_on_gpu() - io_binding.bind_ortvalue_output("Y", output_ortvalue) + # Bind ortvalue as input + input_ortvalue = self._create_ortvalue_input_on_gpu(device) + io_binding.bind_ortvalue_input("X", input_ortvalue) - # Sync if different CUDA streams - io_binding.synchronize_inputs() + # Bind ortvalue as output + output_ortvalue = self._create_uninitialized_ortvalue_input_on_gpu(device) + io_binding.bind_ortvalue_output("Y", output_ortvalue) - # Invoke Run - session.run_with_iobinding(io_binding) + # Sync if different streams + io_binding.synchronize_inputs() - # Sync if different CUDA streams - io_binding.synchronize_outputs() + # Invoke Run + session.run_with_iobinding(io_binding) - # Inspect contents of output_ortvalue and make sure that it has the right contents - self.assertTrue(np.array_equal(self.create_expected_output(), output_ortvalue.numpy())) + # Sync if different streams + io_binding.synchronize_outputs() - # Bind another ortvalue as input - input_ortvalue_2 = self.create_ortvalue_alternate_input_on_gpu() - io_binding.bind_ortvalue_input("X", input_ortvalue_2) + # Inspect contents of output_ortvalue and make sure that it has the right contents + self.assertTrue(np.array_equal(self._create_expected_output(), output_ortvalue.numpy())) - # Sync if different CUDA streams - io_binding.synchronize_inputs() + # Bind another ortvalue as input + input_ortvalue_2 = self._create_ortvalue_alternate_input_on_gpu(device) + io_binding.bind_ortvalue_input("X", input_ortvalue_2) - # Invoke Run - session.run_with_iobinding(io_binding) + # Sync if different streams + io_binding.synchronize_inputs() - # Sync if different CUDA streams - io_binding.synchronize_outputs() + # Invoke Run + session.run_with_iobinding(io_binding) + + # Sync if different streams + io_binding.synchronize_outputs() - # Inspect contents of output_ortvalue and make sure that it has the right contents - self.assertTrue(np.array_equal(self.create_expected_output_alternate(), output_ortvalue.numpy())) + # Inspect contents of output_ortvalue and make sure that it has the right contents + self.assertTrue(np.array_equal(self._create_expected_output_alternate(), output_ortvalue.numpy())) if __name__ == "__main__": diff --git a/onnxruntime/test/python/onnxruntime_test_python_keras.py b/onnxruntime/test/python/onnxruntime_test_python_keras.py index c24cb6954df98..99d964f03169c 100644 --- a/onnxruntime/test/python/onnxruntime_test_python_keras.py +++ b/onnxruntime/test/python/onnxruntime_test_python_keras.py @@ -43,7 +43,7 @@ def custom_activation(scope, operator, container): class TestInferenceSessionKeras(unittest.TestCase): - def testRunModelConv(self): # noqa: N802 + def test_run_model_conv(self): # keras model N, C, H, W = 2, 3, 5, 5 # noqa: N806 x = np.random.rand(N, H, W, C).astype(np.float32, copy=False) diff --git a/onnxruntime/test/python/onnxruntime_test_python_mlops.py b/onnxruntime/test/python/onnxruntime_test_python_mlops.py index c9cb9bfbf58aa..6cdf820c8a0e9 100644 --- a/onnxruntime/test/python/onnxruntime_test_python_mlops.py +++ b/onnxruntime/test/python/onnxruntime_test_python_mlops.py @@ -13,7 +13,7 @@ class TestInferenceSession(unittest.TestCase): - def testZipMapStringFloat(self): # noqa: N802 + def test_zip_map_string_float(self): sess = onnxrt.InferenceSession( get_name("zipmap_stringfloat.onnx"), providers=onnxrt.get_available_providers(), @@ -37,7 +37,7 @@ def testZipMapStringFloat(self): # noqa: N802 res = sess.run([output_name], {x_name: x}) self.assertEqual(output_expected, res[0]) - def testZipMapInt64Float(self): # noqa: N802 + def test_zip_map_int64_float(self): sess = onnxrt.InferenceSession( get_name("zipmap_int64float.onnx"), providers=onnxrt.get_available_providers(), @@ -58,7 +58,7 @@ def testZipMapInt64Float(self): # noqa: N802 res = sess.run([output_name], {x_name: x}) self.assertEqual(output_expected, res[0]) - def testDictVectorizer(self): # noqa: N802 + def test_dict_vectorizer(self): sess = onnxrt.InferenceSession( get_name("pipeline_vectorize.onnx"), providers=onnxrt.get_available_providers(), @@ -108,7 +108,7 @@ def testDictVectorizer(self): # noqa: N802 output_expected = np.array([[49.752754]], dtype=np.float32) np.testing.assert_allclose(output_expected, res[0], rtol=1e-05, atol=1e-08) - def testLabelEncoder(self): # noqa: N802 + def test_label_encoder(self): sess = onnxrt.InferenceSession(get_name("LabelEncoder.onnx"), providers=onnxrt.get_available_providers()) input_name = sess.get_inputs()[0].name self.assertEqual(input_name, "input") diff --git a/onnxruntime/test/python/onnxruntime_test_python_nested_control_flow_op.py b/onnxruntime/test/python/onnxruntime_test_python_nested_control_flow_op.py new file mode 100644 index 0000000000000..bf354ad9f9e10 --- /dev/null +++ b/onnxruntime/test/python/onnxruntime_test_python_nested_control_flow_op.py @@ -0,0 +1,259 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import unittest +from copy import deepcopy +from typing import Optional, Sequence, Tuple + +import numpy as np +from onnx import ModelProto, NodeProto, TensorProto, ValueInfoProto, checker, helper + +import onnxruntime as ort + + +def make_vi_like(vi: ValueInfoProto, name: str) -> ValueInfoProto: + """Makes a copy of `vi` with a new name.""" + new_vi = deepcopy(vi) + new_vi.name = name + return new_vi + + +def make_optional_tensor_value_info(name: str, elem_type: int, shape: Sequence[int]) -> ValueInfoProto: + """Makes a `ValueInfoProto` with optional type.""" + tensor_type_proto = helper.make_tensor_type_proto( + elem_type=elem_type, + shape=shape, + ) + opt_type_proto = helper.make_optional_type_proto(tensor_type_proto) + + vi = helper.make_tensor_value_info(name, elem_type, shape) + vi.type.CopyFrom(opt_type_proto) + return vi + + +def make_optional_vi(vi: ValueInfoProto, name: Optional[str] = None) -> ValueInfoProto: + """Makes a copy of `vi` with optional type.""" + name = name or vi.name + ".opt" + vi_type = vi.type.tensor_type + vi_shape = [d.dim_param if d.dim_param else d.dim_value for d in vi_type.shape.dim] + opt_vi = make_optional_tensor_value_info(name, vi_type.elem_type, vi_shape) + return opt_vi + + +def make_const(vi: ValueInfoProto, name: str, value: int = 0) -> Tuple[ValueInfoProto, NodeProto, TensorProto]: + """Creates a constant 1D tensor from `vi`.""" + const_vi = make_vi_like(vi, name) + const_shape = [d.dim_value for d in vi.type.tensor_type.shape.dim] + const_shape_tensor = helper.make_tensor(f"{name}.shape", TensorProto.INT64, [len(const_shape)], const_shape) + const_fill = helper.make_tensor(f"{name}.const.value", const_vi.type.tensor_type.elem_type, [1], [value]) + const_node = helper.make_node( + "ConstantOfShape", + inputs=[const_shape_tensor.name], + outputs=[const_vi.name], + name=f"ConstantOfShape.{name}", + value=const_fill, + ) + return const_vi, const_node, const_shape_tensor + + +# This is a three-layer nested control flow ops model. +# The innermost subgraphs have the outer scope values that are the inputs, x2 and x3, of the top-level graph. +def make_opt_nested_greater_or_equal() -> ModelProto: + """ + Creates a nested graph with (`optional(x1)`, `x2`, x3`) tensor inputs. + + `x3` is similar to an optional input with default value of -1. + """ + # Inputs/outputs + x1_vi = helper.make_tensor_value_info("x1", TensorProto.FLOAT, [1, 2]) + x2_vi = helper.make_tensor_value_info("x2", TensorProto.FLOAT, [1, 2]) + x3_vi = helper.make_tensor_value_info("x3", TensorProto.FLOAT, [1]) + y_vi = helper.make_tensor_value_info("y", TensorProto.FLOAT, [1, 2]) + opt_x1_vi = make_optional_vi(x1_vi, name="x1.opt") + + # Add `x1` and `x2` subgraph + y1_vi = make_vi_like(y_vi, "x1.add.x2") + input_get_elem_node = helper.make_node( + "OptionalGetElement", + inputs=[opt_x1_vi.name], + outputs=[x1_vi.name], + name="OptionalGetElement.Input", + ) + add_node = helper.make_node("Add", inputs=[x1_vi.name, x2_vi.name], outputs=[y1_vi.name], name="Add_Op") + add_x1_x2_subgraph = helper.make_graph( + [input_get_elem_node, add_node], + name="add-x1-x2-subgraph", + inputs=[], + outputs=[y1_vi], + value_info=[opt_x1_vi, x1_vi, x2_vi], + ) + + # Add `x2` and const subgraph + y2_vi = make_vi_like(y_vi, "x2.add.const") + const_vi, const_node, const_shape_tensor = make_const(x1_vi, "x1.const", value=1) + add_const_node = helper.make_node( + "Add", + inputs=[const_vi.name, x2_vi.name], + outputs=[y2_vi.name], + name="Add_Const", + ) + add_x2_const_subgraph = helper.make_graph( + [const_node, add_const_node], + name="add-x2-const-subgraph", + inputs=[], + outputs=[y2_vi], + value_info=[const_vi, x2_vi], + initializer=[const_shape_tensor], + ) + + # Add `x3` and const subgraph + add_const_out_vi = make_vi_like(x3_vi, "out.1") + y3_vi = make_vi_like(y_vi, "x3.add.const") + const_vi, const_node, const_shape_tensor = make_const(x3_vi, "x3.const", value=2) + add_const_node = helper.make_node( + "Add", + inputs=[const_vi.name, x3_vi.name], + outputs=[add_const_out_vi.name], + name="Add_Const.1", + ) + expand_shape = helper.make_tensor(f"{add_const_out_vi}.shape", TensorProto.INT64, [2], [1, 2]) + expand_node = helper.make_node( + "Expand", + inputs=[add_const_out_vi.name, expand_shape.name], + outputs=[y3_vi.name], + name="Expand.out", + ) + add_x3_const_subgraph = helper.make_graph( + [const_node, add_const_node, expand_node], + name="add-x3-const-subgraph", + inputs=[], + outputs=[y3_vi], + value_info=[x3_vi, const_vi, add_const_out_vi], + initializer=[const_shape_tensor, expand_shape], + ) + + # Subgraph flow based on `x3` value + y3_if_vi = make_vi_like(y_vi, "x3.if.out") + x3_eq_vi, x3_const_node, x3_const_shape_tensor = make_const(x3_vi, "x3.equal", value=0) + x3_ge_vi = helper.make_tensor_value_info( + "x3_ge", + TensorProto.BOOL, + shape=[1], + ) + x3_ge_node = helper.make_node( + "GreaterOrEqual", + inputs=[x3_vi.name, x3_eq_vi.name], + outputs=[x3_ge_vi.name], + name="GreaterOrEqual.Target", + ) + x3_has_elem_vi = helper.make_tensor_value_info( + "x3_has_elem", + TensorProto.BOOL, + shape=[], # scalar + ) + x3_has_elem_node = helper.make_node( + "Squeeze", + inputs=[x3_ge_vi.name], + outputs=[x3_has_elem_vi.name], + name="Squeeze.x3", + ) + if_input_node = helper.make_node( + "If", + inputs=[x3_has_elem_vi.name], # condition + outputs=[y3_if_vi.name], + name="If.OptionalHasElement.x3", + then_branch=add_x3_const_subgraph, + else_branch=add_x2_const_subgraph, + ) + x3_subgraph = helper.make_graph( + [x3_const_node, x3_ge_node, x3_has_elem_node, if_input_node], + name="x3-subgraph", + inputs=[], + outputs=[y3_if_vi], + value_info=[x3_vi, x3_eq_vi, x3_ge_vi, x3_has_elem_vi], + initializer=[x3_const_shape_tensor], + ) + + # Construct main graph + x1_has_elem_vi = helper.make_tensor_value_info( + "x1_has_elem", + TensorProto.BOOL, + shape=[], # scalar + ) + x1_has_elem_node = helper.make_node( + "OptionalHasElement", + inputs=[opt_x1_vi.name], + outputs=[x1_has_elem_vi.name], + name="OptionalHasElement.x1", + ) + if_input_node = helper.make_node( + "If", + inputs=[x1_has_elem_vi.name], # condition + outputs=[y_vi.name], + name="If.OptionalHasElement.x1", + then_branch=add_x1_x2_subgraph, + else_branch=x3_subgraph, + ) + graph = helper.make_graph( + [x1_has_elem_node, if_input_node], + "opt-graph", + [opt_x1_vi, x2_vi, x3_vi], + [y_vi], + value_info=[x1_has_elem_vi], + ) + + m = helper.make_model( + graph, + opset_imports=[ + helper.make_opsetid("", 15), + ], + ) + + checker.check_model(m, full_check=True) + + return m + + +def test_nested_optional_greater_or_equal(use_trt: bool = False) -> None: + m = make_opt_nested_greater_or_equal() + + providers = ["CUDAExecutionProvider"] + if use_trt: + providers.insert(0, "TensorrtExecutionProvider") + session = ort.InferenceSession( + m.SerializeToString(), + providers=providers, + ) + + x1_name, x2_name, x3_name = (i.name for i in m.graph.input) + session.run( + [m.graph.output[0].name], + { + x1_name: None, + x2_name: np.ones((1, 2), dtype=np.float32), + x3_name: np.array([-1], dtype=np.float32), + }, + ) + + return + + +# ORT has a similar unit test Test3LayerNestedSubgraph where this 3-layer nested graph consumes the same initializer in different subgraphs. +# However, this unit test is slightly different. This is also a 3-layer nested graph but consumes the outer scope values (which are the inputs +# of the top-level graph) in different subgraphs. +class TestNestedControlFlowOpsGraph(unittest.TestCase): + # We currently only test CUDA/TRT EP due to users only raise this issue when using CUDA/TRT EP. + @unittest.skipIf( + "TensorrtExecutionProvider" not in ort.get_available_providers() + and "CUDAExecutionProvider" not in ort.get_available_providers(), + reason="Test CUDA/TRT EP only", + ) + def test_3_level_control_flow_ops_graph(self): + if "CUDAExecutionProvider" in ort.get_available_providers(): + test_nested_optional_greater_or_equal(use_trt=False) + if "TensorrtExecutionProvider" in ort.get_available_providers(): + test_nested_optional_greater_or_equal(use_trt=True) + + +if __name__ == "__main__": + unittest.main(module=__name__, buffer=True) diff --git a/onnxruntime/test/python/onnxruntime_test_python_sparse_matmul.py b/onnxruntime/test/python/onnxruntime_test_python_sparse_matmul.py index 4abe799ac89d7..22a09ef565d59 100644 --- a/onnxruntime/test/python/onnxruntime_test_python_sparse_matmul.py +++ b/onnxruntime/test/python/onnxruntime_test_python_sparse_matmul.py @@ -14,7 +14,7 @@ class TestSparseToDenseMatmul(unittest.TestCase): - def testRunSparseOutputOrtValueVector(self): # noqa: N802 + def test_run_sparse_output_ort_value_vector(self): """ Try running models using the new run_with_ort_values sparse_initializer_as_output.onnx - requires no inputs, but only one output @@ -28,7 +28,7 @@ def testRunSparseOutputOrtValueVector(self): # noqa: N802 res = sess._sess.run_with_ort_values({}, ["values"], RunOptions()) self.assertIsInstance(res, OrtValueVector) - def testRunSparseOutputOnly(self): # noqa: N802 + def test_run_sparse_output_only(self): """ Try running models using the new run_with_ort_values sparse_initializer_as_output.onnx - requires no inputs, but only one output @@ -52,7 +52,7 @@ def testRunSparseOutputOnly(self): # noqa: N802 self.assertTrue(np.array_equal(values, sparse_output.values())) self.assertTrue(np.array_equal(indices, sparse_output.as_coo_view().indices())) - def testRunContribSparseMatMul(self): # noqa: N802 + def test_run_contrib_sparse_mat_mul(self): """ Mutliple sparse COO tensor to dense """ 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 d0ea59b994cb7..67db411ddc246 100644 --- a/onnxruntime/test/python/onnxruntime_test_python_symbolic_shape_infer.py +++ b/onnxruntime/test/python/onnxruntime_test_python_symbolic_shape_infer.py @@ -49,7 +49,7 @@ def test_symbolic_shape_infer(self): # https://github.com/onnx/models/issues/562 if any(model_name in str(filename) for model_name in skipped_models): - print(f"Skip symbolic shape inference on : {str(filename)}") + print(f"Skip symbolic shape inference on : {filename!s}") continue print("Running symbolic shape inference on : " + str(filename)) diff --git a/onnxruntime/test/python/onnxruntime_test_training_unit_tests.py b/onnxruntime/test/python/onnxruntime_test_training_unit_tests.py index 4f322478673ae..540f39b797bdb 100644 --- a/onnxruntime/test/python/onnxruntime_test_training_unit_tests.py +++ b/onnxruntime/test/python/onnxruntime_test_training_unit_tests.py @@ -12,18 +12,18 @@ import onnxruntime from onnxruntime.capi.ort_trainer import IODescription, ModelDescription, ORTTrainer -torch.manual_seed(1) -onnxruntime.set_seed(1) - class TestTrainingDropout(unittest.TestCase): - def testTrainingAndEvalDropout(self): # noqa: N802 - # Temporarily disable this test. - # The graph below will trigger ORT - # to sort backward graph before forward graph which gives incorrect result. - # TODO Re-enable when that is fixed. - return + def setUp(self): + torch.manual_seed(1) + onnxruntime.set_seed(1) + @unittest.skip( + "Temporarily disable this test. The graph below will trigger ORT to " + "sort backward graph before forward graph which gives incorrect result. " + "https://github.com/microsoft/onnxruntime/issues/16801" + ) + def test_training_and_eval_dropout(self): class TwoDropoutNet(nn.Module): def __init__(self, drop_prb_1, drop_prb_2, dim_size): super().__init__() diff --git a/onnxruntime/test/python/quantization/op_test_utils.py b/onnxruntime/test/python/quantization/op_test_utils.py index 81506caab1b19..e94ac5c961583 100644 --- a/onnxruntime/test/python/quantization/op_test_utils.py +++ b/onnxruntime/test/python/quantization/op_test_utils.py @@ -3,10 +3,133 @@ import numpy as np import onnx +from onnx import TensorProto +from onnx.helper import float32_to_float8e4m3, np_dtype_to_tensor_dtype +from onnx.numpy_helper import float8e4m3_to_float32 +from onnx.reference import ReferenceEvaluator +from onnx.reference import ops as onnx_ops +from onnx.reference.custom_element_types import float8e4m3fn, float8e4m3fnuz, float8e5m2, float8e5m2fnuz +from onnx.reference.op_run import OpRun import onnxruntime from onnxruntime.quantization import CalibrationDataReader +onnx_recent_enough = hasattr(OpRun, "infer_name") + +if onnx_recent_enough: + # Test with ReferenceEvaluator requires PR https://github.com/onnx/onnx/pull/5408/. + # https://github.com/onnx/onnx/pull/5408 + try: + from onnx.reference.op_run import to_array_extended + + except ImportError: + to_array_extended = None + onnx_recent_enough = False + + +class QGemm(OpRun): + op_domain = "com.microsoft" + + f8_types = { + TensorProto.FLOAT8E4M3FN, + TensorProto.FLOAT8E4M3FNUZ, + TensorProto.FLOAT8E5M2, + TensorProto.FLOAT8E5M2FNUZ, + } + + def get_tensor_type(self, tensor: np.ndarray) -> int: + if tensor.dtype == float8e4m3fn and tensor.dtype.descr[0][0] == "e4m3fn": + return TensorProto.FLOAT8E4M3FN + if tensor.dtype == float8e4m3fnuz and tensor.dtype.descr[0][0] == "e4m3fnuz": + return TensorProto.FLOAT8E4M3FNUZ + if tensor.dtype == float8e5m2 and tensor.dtype.descr[0][0] == "e5m2": + return TensorProto.FLOAT8E5M2 + if tensor.dtype == float8e5m2fnuz and tensor.dtype.descr[0][0] == "e5m2fnuz": + return TensorProto.FLOAT8E5M2FNUZ + return np_dtype_to_tensor_dtype(tensor.dtype) + + def _run( + self, + A, + a_scale, + a_zero_point, + B, + b_scale, + b_zero_point, + C=None, + y_scale=None, + y_zero_point=None, + transA=0, + transB=0, + alpha=1.0, + ): + if transA: + A = A.T + if transB: + B = B.T + + a_type = self.get_tensor_type(a_zero_point) + b_type = self.get_tensor_type(b_zero_point) + y_type = self.get_tensor_type(y_zero_point) + if a_type == TensorProto.FLOAT8E4M3FN and b_type == TensorProto.FLOAT8E4M3FN: + a_scaled = (float8e4m3_to_float32(A).astype(float) - float8e4m3_to_float32(a_zero_point)) * np.float32( + a_scale + ) + b_scaled = (float8e4m3_to_float32(B).astype(float) - float8e4m3_to_float32(b_zero_point)) * np.float32( + b_scale + ) + y = a_scaled @ b_scaled * np.float32(alpha) + if C is not None: + dtype = self.get_tensor_type(C) + if dtype not in (TensorProto.FLOAT, TensorProto.FLOAT16): + raise TypeError(f"C.dtype must be float16 or float 32 not {dtype}.") + y += C.astype(np.float32) + if y_scale is not None: + y /= y_scale + if y_zero_point is not None: + y += float8e4m3_to_float32(y_zero_point) + ry = y.ravel() + + fy = np.empty(ry.shape, dtype=float8e4m3fn) + for i in range(fy.shape[0]): + el = float32_to_float8e4m3(ry[i]) # type: ignore[assignment] + fy[i] = el + y = fy.reshape(y.shape) + else: + raise NotImplementedError("y_zero_point is not empty. QGemm is not implemented in that case.") + return (y,) + elif a_type in self.f8_types or b_type in self.f8_types or y_type in self.f8_types: + raise NotImplementedError(f"QGemm not implemented for zero_types {a_type}, {b_type}, {y_type}.") + else: + if TensorProto.FLOAT8E4M3FN in {a_type, b_type, y_type}: + raise TypeError(f"Unexpected type for A: {dtype}, B:{dtype} or Y:{dtype}.") + a_scaled = (A.astype(float) - a_zero_point) * np.float32(a_scale) + b_scaled = (B.astype(float) - b_zero_point) * np.float32(b_scale) + y = a_scaled @ b_scaled * np.float32(alpha) + if C is not None: + y += C * np.float32(a_scale) * np.float32(b_scale) + if y_scale is not None: + y /= np.float32(y_scale) + if y_zero_point is not None: + y += y_zero_point + + if y_zero_point is not None: + dtype = y_zero_point.dtype + elif C is not None: + dtype = C.dtype + else: + dtype = A.dtype + + y = np.rint(y) + if dtype == np.uint8: + y = np.clip(y, 0, 255) + elif dtype == np.int8: + y = np.clip(y, -128, 127) + else: + raise ValueError(f"Unexpected dtype={dtype}, it should be uint8 or int8.") + + return (y.astype(dtype),) + class TestDataFeeds(CalibrationDataReader): def __init__(self, data_feeds): @@ -23,7 +146,7 @@ def rewind(self): self.iter_next = iter(self.data_feeds) -def InputFeedsNegOneZeroOne(n, name2shape): # noqa: N802 +def input_feeds_neg_one_zero_one(n, name2shape): """ randomize n feed according to shape, its values are from -1, 0, and 1 """ @@ -68,25 +191,180 @@ def check_op_type_count(testcase, model_path, **kwargs): ) -def check_model_correctness(testcase, model_path_origin, model_path_to_check, inputs, rtol=1e-2, atol=0.05): +def check_sign_f8_quantization(model_path_origin, model_path_to_check): + """ + Quantization to float 8 type does not change the sign as zero_point is always null. + This function checks that the quantized parameters did not change. + """ + with open(model_path_origin, "rb") as f: + model = onnx.load(f) + names = {init.name: init for init in model.graph.initializer} + with open(model_path_to_check, "rb") as f: + model_f8 = onnx.load(f) + names_f8 = {init.name: init for init in model_f8.graph.initializer} + for init in model_f8.graph.initializer: + if not init.name.endswith("_quantized"): + continue + name = init.name.replace("_quantized", "") + if name not in names: + raise AssertionError(f"Unable to find {name!r} in {set(names)}.") + scale_zp = [i.name for i in model_f8.graph.initializer if i.name.startswith(name)] + if len(scale_zp) not in (1, 3): + raise AssertionError( + f"Need one or three names not {scale_zp}, all names: {set(i.name for i in model_f8.graph.initializer)}." + ) + scale = [name for name in scale_zp if "scale" in name] + zero = [name for name in scale_zp if "zero" in name] + if len(scale_zp) == 3: + if len(scale) != 1: + raise AssertionError(f"Need one name not {scale}.") + if len(zero) != 1: + raise AssertionError(f"Need one name not {zero}.") + else: + if len(scale) != 0: + raise AssertionError(f"No scale is expected but has {scale}.") + if len(zero) != 0: + raise AssertionError(f"No zero is expected but has {zero}.") + + expected_sign = onnx.numpy_helper.to_array(names[name]) >= 0 + + if "bias" in init.name: + if init.data_type >= 17: + raise AssertionError(f"bias {init.name!r} should be float 16 not {init.data_type}.") + continue + if init.data_type < 17: + raise AssertionError(f"Initializer {init.name!r} not a float 8 type.") + raw = np.array([int(i) for i in init.raw_data]) + got_sign = raw <= 128 + try: + np.testing.assert_allclose(expected_sign.ravel(), got_sign) + except AssertionError as e: + scale_value = onnx.numpy_helper.to_array(names_f8[scale[0]]) + err_msg = f"Sign are different for {name!r}, scale={scale_value}." + if to_array_extended is not None: + values = onnx.numpy_helper.to_array(names[name]).flatten() + f8_values = to_array_extended(init) + zero = onnx_ops.op_cast.Cast_19.eval(np.array(0), to=init.data_type) + dq = onnx_ops.op_dequantize_linear.DequantizeLinear.eval(f8_values, scale_value, zero).flatten() + q = onnx_ops.op_quantize_linear.QuantizeLinear_19.eval(values, scale_value, zero).flatten() + qdq = onnx_ops.op_dequantize_linear.DequantizeLinear.eval(q, scale_value, zero).flatten() + err_msg = ( + f"{err_msg}\nvalues={values[:20]}\nqu={f8_values.flatten()[:20]}" + f"\n{q.flatten()[:20]}\ndq={dq[:20]}\nqdq={qdq[:20]}" + ) + raise AssertionError(err_msg) from e + + +def check_model_correctness( + testcase, + model_path_origin, + model_path_to_check, + inputs, + rtol=1e-2, + atol=0.05, + providers=None, + dynamic=False, + is_gemm=False, +): + if providers is None: + providers = ["CPUExecutionProvider"] sess_options = onnxruntime.SessionOptions() sess_options.graph_optimization_level = onnxruntime.GraphOptimizationLevel.ORT_DISABLE_ALL - origin_sess = onnxruntime.InferenceSession( - model_path_origin, sess_options=sess_options, providers=["CPUExecutionProvider"] - ) - origin_results = origin_sess.run([], inputs) + sess_options.optimized_model_filepath = model_path_to_check + ".optimized.onnx" + origin_sess = onnxruntime.InferenceSession(model_path_origin, sess_options=sess_options, providers=providers) + origin_results = origin_sess.run(None, inputs) + + with open(model_path_origin, "rb") as f: + model_onnx = onnx.load(f) + ops_set = set(node.op_type for node in model_onnx.graph.node) + check_reference_evaluator = not (ops_set & {"EmbedLayerNormalization", "Conv", "Attention", "Transpose"}) + + if check_reference_evaluator and onnx_recent_enough: + ref = ReferenceEvaluator(model_path_origin) + ref_origin_results = ref.run(None, inputs) + for idx, ref_output in enumerate(origin_results): + output = ref_origin_results[idx] + np.testing.assert_allclose( + ref_output, + output, + rtol=rtol, + atol=atol, + err_msg=f"Model {model_path_to_check!r} failed for providers={providers!r}.", + ) + + # Verifies the shapes in the quantized model. + if is_gemm: + expected_shapes = {} + with open(model_path_origin, "rb") as f: + model = onnx.load(f) + for init in model.graph.initializer: + expected_shapes[init.name] = tuple(init.dims) + checked = 0 + f8_quantization = False + with open(model_path_to_check, "rb") as f: + model_check = onnx.load(f) + for init in model_check.graph.initializer: + if init.name.endswith("_quantized"): + name = init.name.replace("_quantized", "") + expected = expected_shapes[name] + shape = tuple(init.dims) + if not dynamic and expected != shape: + raise AssertionError( + f"Shape mismatch for initializer {init.name!r} from {init.name!r}, " + f"shape={shape} != {expected} (expected)." + ) + else: + checked += 1 + if "zero_point" in init.name: + dt = init.data_type + f8_quantization = f8_quantization or dt in ( + TensorProto.FLOAT8E4M3FN, + TensorProto.FLOAT8E4M3FNUZ, + TensorProto.FLOAT8E5M2, + TensorProto.FLOAT8E5M2FNUZ, + ) + if checked == 0: + raise AssertionError( + f"Unable to check expected shape, expected_shapes={expected_shapes}, " + f"names={[init.name for init in model_check.graph.initializer]}." + ) + if f8_quantization: + check_sign_f8_quantization(model_path_origin, model_path_to_check) + + # Verifies the expected outputs. + if check_reference_evaluator and onnx_recent_enough: + # Needs pv.Version(onnx.__version__) >= pv.Version("1.16.0") + ref = ReferenceEvaluator(model_path_to_check, new_ops=[QGemm]) + target_results = ref.run(None, inputs) + testcase.assertEqual(len(origin_results), len(target_results), "result count are different") + for idx, ref_output in enumerate(origin_results): + output = target_results[idx] + np.testing.assert_allclose( + ref_output, + output, + rtol=rtol, + atol=atol, + err_msg=f"Model {model_path_to_check!r} failed for providers={providers!r}.", + ) + # enable QDQ transformers # sess_options.graph_optimization_level = onnxruntime.GraphOptimizationLevel.ORT_ENABLE_EXTENDED target_sess = onnxruntime.InferenceSession( model_path_to_check, sess_options=sess_options, - providers=["CPUExecutionProvider"], + providers=providers, ) target_results = target_sess.run([], inputs) testcase.assertEqual(len(origin_results), len(target_results), "result count are different") for idx, ref_output in enumerate(origin_results): output = target_results[idx] - np.testing.assert_allclose(ref_output, output, rtol=rtol, atol=atol) + np.testing.assert_allclose( + ref_output, + output, + rtol=rtol, + atol=atol, + err_msg=f"Model {model_path_to_check!r} failed for providers={providers!r}.", + ) def check_op_nodes(testcase, model_path, node_checker): @@ -118,7 +396,7 @@ def check_qtype_by_node_type(testcase, model_to_check, check_list): testcase.assertTrue(vi.type.tensor_type.elem_type == check_item[2]) else: # if (tensor_name in initializers): init = initializers[tensor_name] - testcase.assertTrue(init.data_type == check_item[2]) + testcase.assertEqual(init.data_type, check_item[2]) def create_clip_node(input_name, output_name, node_name, initializers, min_value=-1.0, max_value=1.0): diff --git a/onnxruntime/test/python/quantization/resnet_code.py b/onnxruntime/test/python/quantization/resnet_code.py new file mode 100644 index 0000000000000..2f78047c824a6 --- /dev/null +++ b/onnxruntime/test/python/quantization/resnet_code.py @@ -0,0 +1,13757 @@ +import numpy +from onnx import numpy_helper +from onnx.helper import make_graph, make_model, make_node, make_opsetid, make_tensor_value_info, set_model_props + + +def create_model(): + initializers = [] + nodes = [] + inputs = [] + outputs = [] + functions = [] + + # opsets + opsets = {"": 13} + + # initializers + + list_value = [ + -0.013732648454606533, + -0.005861935671418905, + 0.06889285147190094, + -0.1172710582613945, + 0.08841240406036377, + -0.03748627379536629, + 0.016256270930171013, + -0.1059316024184227, + 0.08246039599180222, + 0.14295539259910583, + -0.32958757877349854, + 0.1631188541650772, + 0.05412565544247627, + -0.10758306831121445, + 0.12607362866401672, + -0.4987836182117462, + 0.7441706657409668, + -0.24774713814258575, + -0.30415549874305725, + 0.4033295810222626, + -0.13447114825248718, + 0.04623159021139145, + 0.2380414456129074, + -1.226112723350525, + 2.150630235671997, + -1.702580213546753, + 0.5305419564247131, + -0.06836353242397308, + -0.20055373013019562, + 0.7035881280899048, + -0.8389442563056946, + -0.1904432326555252, + 1.2609282732009888, + -1.0670661926269531, + 0.4142579436302185, + 0.04739700257778168, + -0.3265092074871063, + 1.1873037815093994, + -1.6817731857299805, + 0.9709527492523193, + -0.09095840901136398, + -0.12556785345077515, + 0.0835147574543953, + -0.24109329283237457, + 0.032948240637779236, + 0.46304041147232056, + -0.6594106554985046, + 0.349990576505661, + -0.04113377630710602, + 0.016451245173811913, + 0.008994563482701778, + -0.028321878984570503, + -0.05336569994688034, + 0.16036668419837952, + -0.12088149785995483, + 0.031160499900579453, + -0.0618649423122406, + 0.07205374538898468, + 0.15965768694877625, + -0.3389044404029846, + 0.21603335440158844, + 0.04029613360762596, + -0.0813034325838089, + 0.1019665077328682, + -0.4873599112033844, + 0.7873126268386841, + -0.2951086163520813, + -0.43754327297210693, + 0.5905176401138306, + -0.21821773052215576, + 0.06022067740559578, + 0.26326146721839905, + -1.6453089714050293, + 2.606400728225708, + -1.8939754962921143, + 0.5196341276168823, + 0.0055860355496406555, + -0.2335057258605957, + 0.9807199239730835, + -1.2137882709503174, + -0.2699125409126282, + 1.7379733324050903, + -1.4401814937591553, + 0.435971736907959, + -0.04829222336411476, + -0.24543480575084686, + 1.3292583227157593, + -2.0375823974609375, + 1.2458536624908447, + -0.08251484483480453, + -0.14181238412857056, + 0.10612589120864868, + -0.21671657264232635, + 0.1129523366689682, + 0.3666985034942627, + -0.7546612024307251, + 0.42979565262794495, + -0.0976259633898735, + -0.0008812264422886074, + 0.02994859404861927, + -0.07027778774499893, + 0.01393035613000393, + 0.07363647222518921, + -0.10249849408864975, + 0.06602989137172699, + -0.012129798531532288, + 0.10730132460594177, + -0.04546127840876579, + -0.16065146028995514, + 0.14788293838500977, + -0.05488971993327141, + 0.03601694852113724, + 0.07513345777988434, + -0.23953600227832794, + 0.48062530159950256, + -0.42057543992996216, + -0.02402813360095024, + 0.17920851707458496, + -0.10703158378601074, + -0.028666120022535324, + 0.2815375030040741, + -0.860264241695404, + 1.4422725439071655, + -1.2058128118515015, + 0.5272247791290283, + -0.06504356116056442, + -0.20021803677082062, + 0.44968947768211365, + -0.3856053650379181, + -0.1589551419019699, + 0.7579770684242249, + -0.8349987268447876, + 0.3225692808628082, + 0.08153475821018219, + -0.43163740634918213, + 0.8742384910583496, + -0.9722443222999573, + 0.579015851020813, + -0.06688100844621658, + -0.12384293973445892, + 0.08289378881454468, + -0.10082041472196579, + -0.11204896867275238, + 0.3934254050254822, + -0.4511864185333252, + 0.32745760679244995, + -0.06534548103809357, + -0.028830429539084435, + 0.021844232454895973, + 0.01775779016315937, + -0.004250001162290573, + 0.013087524101138115, + -0.001250433037057519, + -0.040545206516981125, + -0.014049320481717587, + -0.024194253608584404, + -0.023865194991230965, + -0.0038033330347388983, + 0.00920871365815401, + -0.006582418456673622, + 0.0032474950421601534, + -0.0369916632771492, + -0.16640843451023102, + -0.28968843817710876, + -0.3531132638454437, + -0.26307201385498047, + -0.13392697274684906, + -0.03747623786330223, + 0.08083077520132065, + 0.2026241272687912, + 0.25018608570098877, + 0.2529378831386566, + 0.2307336926460266, + 0.13928599655628204, + 0.08631229400634766, + 0.13893137872219086, + 0.4867081344127655, + 0.7170669436454773, + 0.8331555724143982, + 0.6734364032745361, + 0.3549460768699646, + 0.16798041760921478, + -0.14487245678901672, + -0.47733625769615173, + -0.7670150995254517, + -0.875726580619812, + -0.6291986703872681, + -0.2910463213920593, + -0.09991979598999023, + -0.009158087894320488, + 0.018850643187761307, + 0.02646111696958542, + -0.009077857248485088, + 0.029430989176034927, + -0.03707962855696678, + -0.05111744999885559, + -0.02076525054872036, + 0.011828843504190445, + 0.017857171595096588, + 0.02548048458993435, + -0.009077494964003563, + 0.0022066361270844936, + -0.02064262516796589, + -0.008582246489822865, + -0.022748643532395363, + -0.03038850985467434, + 0.0006585497176274657, + -0.0016039719339460135, + -0.01612498238682747, + 0.013966801576316357, + -0.05851661041378975, + -0.21422894299030304, + -0.33863192796707153, + -0.3720807433128357, + -0.3030800521373749, + -0.1737397164106369, + -0.05903157964348793, + 0.15018144249916077, + 0.27454254031181335, + 0.31182464957237244, + 0.30118387937545776, + 0.24605700373649597, + 0.14123573899269104, + 0.14992672204971313, + 0.20660799741744995, + 0.5046274662017822, + 0.7706091403961182, + 0.8978630900382996, + 0.7368614673614502, + 0.3929724097251892, + 0.23079657554626465, + -0.21169082820415497, + -0.5920398235321045, + -0.893406867980957, + -0.9499238729476929, + -0.730407178401947, + -0.3615736961364746, + -0.15422092378139496, + -0.024615347385406494, + 0.005115498788654804, + 0.024657316505908966, + 0.028517475351691246, + 0.027910854667425156, + -0.009482389315962791, + -0.042242538183927536, + -0.017875321209430695, + 0.00430292496457696, + 0.015949612483382225, + 0.003636278910562396, + -0.018156034871935844, + -0.0009349065367132425, + -0.0010362856555730104, + -0.013051170855760574, + -0.009141271002590656, + -8.714485738892108e-05, + 0.02399279735982418, + 0.01753612607717514, + -0.013710699044167995, + -0.014245252124965191, + -0.0028008236549794674, + -0.08206935226917267, + -0.1098734438419342, + -0.10250325500965118, + -0.08874496072530746, + -0.031079040840268135, + 0.004536658991128206, + 0.03923843801021576, + 0.08478657901287079, + 0.07715648412704468, + 0.018803801387548447, + 0.013921198435127735, + 0.015864359214901924, + 0.04947463795542717, + 0.039856068789958954, + 0.1712094396352768, + 0.362756609916687, + 0.4192918539047241, + 0.2668488621711731, + 0.11430513113737106, + 0.06648365408182144, + -0.058979276567697525, + -0.24177154898643494, + -0.3709423542022705, + -0.3979431986808777, + -0.29706764221191406, + -0.11569518595933914, + -0.01848490908741951, + -0.015523962676525116, + 0.05081642046570778, + 0.09057094901800156, + 0.08520761132240295, + 0.04497350752353668, + -0.019453801214694977, + -0.06109466031193733, + 0.011463015340268612, + -0.008522219955921173, + -0.005283404141664505, + -0.017313135787844658, + -0.0015744483098387718, + -0.011845857836306095, + -0.016727561131119728, + -0.006708915811032057, + 0.0008860539528541267, + -0.010050912387669086, + -0.028460539877414703, + -0.0165643822401762, + -0.016545938327908516, + -0.00567589420825243, + -0.0032017906196415424, + -0.0130555285140872, + -0.026848897337913513, + -0.02615198865532875, + 0.002669057110324502, + -0.027966763824224472, + -0.03851256147027016, + -0.014509409666061401, + -0.029059220105409622, + -0.007284109480679035, + 0.04045313969254494, + 0.10005538910627365, + 0.014574537053704262, + -0.044292762875556946, + -0.01750861294567585, + -0.02231375314295292, + -0.004432118032127619, + 0.10051869601011276, + 0.1443023532629013, + 0.0508832149207592, + -0.04350621998310089, + -0.0025447055231779814, + -0.014583000913262367, + -0.02153291553258896, + 0.018860718235373497, + 0.03618147224187851, + 0.007304056081920862, + -0.029104959219694138, + 0.00576505484059453, + -0.016025763005018234, + -0.025094063952565193, + -0.05296780914068222, + -0.037012189626693726, + -0.04414081946015358, + -0.053135257214307785, + -0.028890708461403847, + -0.010220452211797237, + -0.027575822547078133, + -0.01087758969515562, + -0.027209162712097168, + -0.030827227979898453, + -0.007646164856851101, + -0.016133273020386696, + 0.000639698002487421, + -0.0034172122832387686, + 0.03914793208241463, + 0.030786357820034027, + 0.005965455900877714, + 0.020923329517245293, + -0.03435938432812691, + -0.0026781477499753237, + 0.04278327897191048, + 0.20045910775661469, + 0.21770593523979187, + 0.09422573447227478, + 0.03198440372943878, + -0.021056609228253365, + 0.028007682412862778, + 0.19196027517318726, + 0.4791645109653473, + 0.5333831906318665, + 0.3014310598373413, + 0.103666290640831, + -0.03651479259133339, + 0.027079502120614052, + 0.19239209592342377, + 0.5168290138244629, + 0.5564895868301392, + 0.2977963089942932, + 0.07770062237977982, + -0.042239490896463394, + -0.017265107482671738, + 0.08760321140289307, + 0.2775075435638428, + 0.312491774559021, + 0.12284757196903229, + 0.019664151594042778, + -0.026643047109246254, + 0.0009152573184110224, + 0.016156431287527084, + 0.09042830765247345, + 0.08991760015487671, + 0.013326293788850307, + 0.02613811008632183, + 0.021025240421295166, + 0.0198842640966177, + 0.03375901281833649, + 0.028616728261113167, + 0.026605166494846344, + 0.04126269370317459, + 0.029309948906302452, + 0.01408455427736044, + -0.003831037785857916, + 0.01922326348721981, + -0.018229445442557335, + -0.013015883974730968, + 0.017597628757357597, + -0.007964612916111946, + 0.045263469219207764, + 0.0184696726500988, + -0.001163159729912877, + -0.1809321641921997, + -0.22486254572868347, + -0.08606110513210297, + 0.001087217591702938, + 0.037091098725795746, + -0.013625397346913815, + -0.178089901804924, + -0.5483279824256897, + -0.612791895866394, + -0.32531827688217163, + -0.06506585329771042, + 0.05076128616929054, + -0.007585812360048294, + -0.20981833338737488, + -0.6155760884284973, + -0.7119701504707336, + -0.354442298412323, + -0.04236743599176407, + 0.045713260769844055, + 0.03192479908466339, + -0.07216271013021469, + -0.310979425907135, + -0.3656359910964966, + -0.13522450625896454, + 0.008291869424283504, + 0.03362602740526199, + -0.0009240762447007, + 0.01604474149644375, + -0.055634208023548126, + -0.06180194392800331, + 0.0222025066614151, + 0.027704820036888123, + -0.034385330975055695, + -0.07050742954015732, + -0.06287489086389542, + 0.03521641716361046, + -0.00020920530369039625, + 0.05458284169435501, + 0.058752644807100296, + -0.08097169548273087, + -0.01668735221028328, + 0.18557283282279968, + 0.26208117604255676, + 0.1253771185874939, + 0.07758381962776184, + -0.022084739059209824, + 0.016727397218346596, + 0.23247942328453064, + 0.35444316267967224, + 0.21802566945552826, + -0.04409221559762955, + -0.08573070168495178, + -0.0994141548871994, + 0.07754423469305038, + 0.14311672747135162, + 0.04036660119891167, + -0.29222917556762695, + -0.38828015327453613, + -0.26185816526412964, + -0.12845511734485626, + 0.04763585329055786, + -0.017382778227329254, + -0.16010743379592896, + -0.2395028918981552, + -0.2049665004014969, + -0.041346337646245956, + 0.091490738093853, + -0.005191737785935402, + -0.07687077671289444, + -0.08105621486902237, + -0.05329642817378044, + -0.03404862806200981, + 0.11478845030069351, + 0.13328343629837036, + -0.037197597324848175, + -0.01787363924086094, + -0.016605347394943237, + 0.007853846065700054, + 0.029950136318802834, + 0.10808859020471573, + 0.02873288467526436, + -0.1766187697649002, + -0.17560969293117523, + -0.03922238200902939, + 0.14447443187236786, + 0.1534212827682495, + 0.11272227019071579, + 0.008810695260763168, + -0.1485181748867035, + 0.07839693129062653, + 0.43013128638267517, + 0.4898712635040283, + 0.26522761583328247, + 0.10202436149120331, + -0.07163076847791672, + 0.09933187812566757, + 0.47377726435661316, + 0.6340300440788269, + 0.36741772294044495, + -0.04812543839216232, + -0.17370514571666718, + -0.17513291537761688, + 0.22105705738067627, + 0.3226463794708252, + 0.09850790351629257, + -0.4044247269630432, + -0.6237908601760864, + -0.4679968059062958, + -0.1954391747713089, + 0.09878316521644592, + -0.004430827684700489, + -0.31550562381744385, + -0.5235733985900879, + -0.4510284662246704, + -0.13843706250190735, + 0.10064390301704407, + -0.006748788990080357, + -0.12714813649654388, + -0.2107744812965393, + -0.18755048513412476, + -0.05646044388413429, + 0.12781813740730286, + 0.18928050994873047, + -0.04337320104241371, + -0.04973407834768295, + -0.04690375551581383, + 0.0245530866086483, + 0.10698680579662323, + 0.1646823137998581, + 0.081840381026268, + -0.01471243891865015, + -0.03138890117406845, + -0.04195617139339447, + 0.012708203867077827, + 0.033312954008579254, + 0.02409377694129944, + -0.0036440726835280657, + -0.06239784508943558, + 0.0037516560405492783, + 0.11261500418186188, + 0.13069754838943481, + 0.05901307612657547, + 0.048614490777254105, + -0.027712708339095116, + 0.027247682213783264, + 0.19195327162742615, + 0.2688453793525696, + 0.1509387195110321, + 0.020540937781333923, + -0.004100556951016188, + -0.012650247663259506, + 0.039176344871520996, + 0.09037251025438309, + -0.004689970053732395, + -0.23859903216362, + -0.2364242821931839, + -0.15189304947853088, + -0.0761493444442749, + -0.0028172829188406467, + -0.04328106716275215, + -0.16187387704849243, + -0.21743592619895935, + -0.1282283067703247, + -0.024501819163560867, + 0.04029383510351181, + -0.027387680485844612, + -0.05414740741252899, + -0.08344019204378128, + -0.06591048091650009, + 0.012637111358344555, + 0.06905930489301682, + 0.08426016569137573, + -0.0030199100729078054, + 0.034059297293424606, + 0.01111840270459652, + 0.013492933474481106, + 0.0674189031124115, + 0.08242739737033844, + 0.006129032466560602, + -0.07763395458459854, + -0.03002289868891239, + -0.055725954473018646, + 0.008795201778411865, + 0.02994825504720211, + -0.06114519387483597, + -0.0560108907520771, + -0.008179228752851486, + -0.07149285078048706, + -0.02700420655310154, + -0.01306728646159172, + 0.06276566535234451, + 0.007125973701477051, + -0.03540417551994324, + -0.039717916399240494, + 0.009147526696324348, + -0.06517947465181351, + 0.0720859095454216, + -0.05035398155450821, + 0.06659520417451859, + -0.01841895841062069, + 0.004233633633702993, + -0.020911216735839844, + -0.004646372981369495, + 1.6690073013305664, + 0.4517613649368286, + -0.07667035609483719, + 0.005556757096201181, + -0.02638973295688629, + 0.044588603079319, + -0.020916732028126717, + 0.2571280598640442, + -0.009559552185237408, + -0.043380800634622574, + 0.03196016326546669, + -0.03783237189054489, + -0.03076902963221073, + 0.03180111199617386, + 0.06352709978818893, + 0.020281998440623283, + -0.00741154421120882, + -0.0009214285528287292, + -0.0476187989115715, + -0.07208544760942459, + -0.05323023349046707, + -0.011103631928563118, + 0.02877136506140232, + -0.05324484035372734, + -0.10076326876878738, + 0.026193000376224518, + 0.03536469116806984, + 0.045722659677267075, + -0.03756006807088852, + 0.022998394444584846, + 0.0019359687576070428, + 0.01654801517724991, + 0.047304198145866394, + -0.08431598544120789, + -0.0645647644996643, + -0.17326746881008148, + -0.10692577064037323, + -0.08416426181793213, + -0.04107839986681938, + -0.0012680464424192905, + -0.02600814774632454, + -0.014215772971510887, + 0.2114446610212326, + -0.040954578667879105, + -0.05050172284245491, + 0.004194092936813831, + -0.0025900816544890404, + -0.1359374076128006, + 0.03946976363658905, + 2.3023669719696045, + 0.7484877109527588, + -0.1994970589876175, + -0.06490366160869598, + 0.007983183488249779, + -0.017937449738383293, + -0.12516839802265167, + 0.3313288688659668, + 0.11946671456098557, + -0.16942338645458221, + -0.007721045054495335, + 0.02824605070054531, + -0.05310647189617157, + -0.1122083067893982, + -0.17094524204730988, + -0.08465421944856644, + -0.09679102897644043, + -0.03848385065793991, + 0.040121182799339294, + -0.06661732494831085, + 0.0005764663219451904, + -0.05729356408119202, + -0.04778655245900154, + -0.034835152328014374, + -0.07634143531322479, + -0.05054831504821777, + 0.00597620103508234, + 0.04499154910445213, + -0.03308190405368805, + -0.04915233701467514, + -0.05842791870236397, + 0.003590918146073818, + 0.055837079882621765, + -0.02547842636704445, + -0.018847621977329254, + -0.2073899656534195, + -0.14987564086914062, + -0.03971748799085617, + 0.05886378139257431, + 0.020922083407640457, + -0.039155181497335434, + -0.028855402022600174, + 0.08688661456108093, + -0.1402827501296997, + -0.05810496211051941, + 0.037841811776161194, + -0.04082907736301422, + -0.1191127747297287, + -0.10852136462926865, + 1.6274418830871582, + 0.3678200840950012, + -0.2865799367427826, + -0.05291350558400154, + 0.023858532309532166, + -0.046683818101882935, + -0.2307816743850708, + -0.001670230645686388, + -0.17716962099075317, + -0.16724731028079987, + 0.040194038301706314, + -0.023075448349118233, + -0.01538322027772665, + -0.07914327085018158, + -0.19621343910694122, + -0.11628971993923187, + -0.05851752683520317, + 0.06313594430685043, + 0.017808571457862854, + 0.02447943389415741, + 0.048611078411340714, + -0.009247995913028717, + 0.00789090245962143, + 0.06673033535480499, + 0.0661577433347702, + 0.019111329689621925, + 0.038164373487234116, + 0.029342610388994217, + -0.03547409921884537, + -0.11017149686813354, + -0.11077891290187836, + 0.001108204829506576, + -0.0330691784620285, + -0.05039837956428528, + 0.017638904973864555, + 0.277705579996109, + 0.5606598258018494, + 0.5469182133674622, + 0.13591277599334717, + 0.012421006336808205, + 0.046348799020051956, + -0.02721901424229145, + -0.5645118355751038, + -1.072814702987671, + -0.9852984547615051, + -0.3608386516571045, + -0.010197073221206665, + -0.09785731136798859, + -0.02597353421151638, + 0.4627133309841156, + 1.1483618021011353, + 0.9505703449249268, + 0.17471027374267578, + -0.016467586159706116, + 0.026623696088790894, + 0.04765752702951431, + -0.4000166058540344, + -0.8956774473190308, + -0.6268588304519653, + -0.09439487755298615, + 0.02861764468252659, + -0.004155704285949469, + 0.08989865332841873, + 0.27384331822395325, + 0.6518518328666687, + 0.4184596836566925, + 0.13106893002986908, + 0.0050344159826636314, + 0.007061495911329985, + -0.016157688573002815, + -0.1364346295595169, + -0.27324289083480835, + -0.14245718717575073, + -0.04623992741107941, + -0.015541884116828442, + 0.030779436230659485, + 0.03756715729832649, + 0.01957445964217186, + -0.04964561015367508, + -0.0211405660957098, + 0.044496409595012665, + -0.026335055008530617, + -0.11620140820741653, + -0.11803250014781952, + 0.18242181837558746, + 0.5057784914970398, + 0.5045838952064514, + 0.03748183697462082, + 0.05692485347390175, + 0.1608155369758606, + 0.02245517633855343, + -0.7651812434196472, + -1.5504053831100464, + -1.3563542366027832, + -0.4314505457878113, + -0.028384560719132423, + -0.12238024920225143, + 0.106974296271801, + 1.11427903175354, + 2.173083543777466, + 1.747692346572876, + 0.5455064177513123, + 0.03363418206572533, + 0.11388687789440155, + -0.05905687436461449, + -0.8059568405151367, + -1.6196117401123047, + -1.1898213624954224, + -0.2654758095741272, + -0.004251840524375439, + -0.0916782096028328, + -0.024067873135209084, + 0.22692462801933289, + 0.6695711612701416, + 0.3673460781574249, + -0.017016466706991196, + -0.029604146257042885, + 0.020365707576274872, + 0.03215239942073822, + 0.0070981839671730995, + -0.14026938378810883, + -0.02425236999988556, + 0.059152450412511826, + -0.006319367326796055, + 0.003989882301539183, + 0.048541076481342316, + 0.003988460637629032, + -0.03105335496366024, + -0.08329232037067413, + 0.03226872906088829, + 0.02119620516896248, + -0.0953872874379158, + -0.15174035727977753, + 0.07963212579488754, + 0.29094186425209045, + 0.2690921127796173, + -0.020104877650737762, + 0.024988379329442978, + 0.15326620638370514, + 0.1256464123725891, + -0.40941280126571655, + -0.946648120880127, + -0.8358487486839294, + -0.14284957945346832, + -0.07980851829051971, + -0.1435413807630539, + 0.038134895265102386, + 0.8021518588066101, + 1.552701473236084, + 1.2496209144592285, + 0.38152581453323364, + 0.07136060297489166, + 0.14329172670841217, + -0.06546801328659058, + -0.5923707485198975, + -1.253793478012085, + -0.9458200335502625, + -0.156633198261261, + -0.04217473417520523, + -0.11199303716421127, + -0.07520301640033722, + 0.15331010520458221, + 0.4794600307941437, + 0.2449675053358078, + -0.10396319627761841, + 0.0034801275469362736, + 0.04475663974881172, + 0.024035215377807617, + 0.056806568056344986, + -0.07363307476043701, + -0.001563104335218668, + 0.05157755687832832, + 0.043718185275793076, + 0.02102719619870186, + 0.11859089881181717, + 0.08675580471754074, + -0.13180124759674072, + -0.15522590279579163, + 0.03273458778858185, + -0.0019622649997472763, + 0.1011638194322586, + -0.10800585150718689, + -0.6884365677833557, + -0.5495791435241699, + 0.0780424103140831, + 0.33674973249435425, + -0.21274283528327942, + -0.4183696210384369, + -0.8053947687149048, + 0.03347628563642502, + 1.3938312530517578, + 0.9454176425933838, + -0.012210174463689327, + 0.04924672842025757, + 0.16284359991550446, + 1.1340152025222778, + 2.0020322799682617, + 0.2796843647956848, + -0.968036413192749, + -0.5768532752990723, + 0.17757350206375122, + 0.37485063076019287, + 0.11534234136343002, + -1.2916942834854126, + -1.692176103591919, + -0.30523377656936646, + 0.14307916164398193, + 0.03928302228450775, + -0.19196964800357819, + -0.4533900022506714, + -0.3294944167137146, + 0.5480389595031738, + 0.4497548043727875, + 0.2170887440443039, + -0.05817069113254547, + -0.06957870721817017, + 0.03169052675366402, + 0.23751793801784515, + 0.0823391005396843, + -0.04811413958668709, + -0.051265716552734375, + -0.0395645909011364, + -0.03849785774946213, + 0.04607917368412018, + 0.09946659207344055, + -0.029992828145623207, + -0.05369366332888603, + -0.005230880342423916, + 0.012808755040168762, + 0.1821947544813156, + 0.05478882044553757, + -0.47736144065856934, + -0.44480830430984497, + -0.036321353167295456, + 0.13646431267261505, + -0.04045571759343147, + -0.21837295591831207, + -0.6888197660446167, + -0.08431777358055115, + 0.96018385887146, + 0.6788493990898132, + 0.011028020642697811, + 0.05917810648679733, + 0.02488739602267742, + 0.6898419857025146, + 1.4259209632873535, + 0.13193827867507935, + -0.8078985810279846, + -0.31056249141693115, + 0.018122224137187004, + 0.137860506772995, + 0.051947757601737976, + -0.9757952094078064, + -1.1060559749603271, + 0.06675099581480026, + 0.2091575562953949, + -0.029623042792081833, + -0.0705878809094429, + -0.18514159321784973, + -0.07947035878896713, + 0.5719470381736755, + 0.2286168485879898, + -0.03433626517653465, + 0.0036030709743499756, + 0.006251791957765818, + 0.04144154116511345, + 0.08598234504461288, + -0.050599172711372375, + -0.10440917313098907, + -0.02927244082093239, + -0.04102599248290062, + -0.07101748138666153, + -0.03579306975007057, + 0.03586365282535553, + 0.06752362847328186, + 0.048901572823524475, + -0.020898710936307907, + -0.009411930106580257, + 0.10169848799705505, + 0.1812015175819397, + -0.014482695609331131, + -0.12548771500587463, + -0.060731250792741776, + -0.034499138593673706, + 0.0829617902636528, + 0.04616715386509895, + -0.20867496728897095, + -0.1990129053592682, + 0.1773940473794937, + 0.13156233727931976, + -0.03437860682606697, + 0.04012921825051308, + -0.11132699251174927, + -0.023460939526557922, + 0.2713286876678467, + -0.06662362813949585, + -0.2709292471408844, + -0.0030232456047087908, + -0.10379529744386673, + -0.07136038690805435, + 0.03757762163877487, + -0.20515622198581696, + -0.1231834888458252, + 0.26915228366851807, + 0.0998353362083435, + -0.031466737389564514, + 0.04657471179962158, + 0.07664929330348969, + 0.10308870673179626, + 0.23429608345031738, + -0.06942534446716309, + -0.09051290899515152, + 0.03243685141205788, + 0.04053235426545143, + -0.021392958238720894, + -0.05330868810415268, + -0.11525140702724457, + -0.03889385238289833, + 0.01636480540037155, + -0.009352890774607658, + 0.13151532411575317, + -0.14738643169403076, + -0.18289834260940552, + 0.15955400466918945, + -0.001023759599775076, + 0.028809679672122, + 0.012261062860488892, + 0.29654747247695923, + -0.285063236951828, + -0.40187928080558777, + 0.3713407516479492, + 0.009383893571794033, + -0.023022817447781563, + -0.003799814498052001, + 0.48470190167427063, + -0.43402406573295593, + -0.5858806371688843, + 0.5751441717147827, + 0.05045031011104584, + -0.05559438094496727, + -0.02045449987053871, + 0.5281224250793457, + -0.5058223605155945, + -0.5950849056243896, + 0.6492323279380798, + 0.013408469036221504, + -0.05940670147538185, + -0.0044364179484546185, + 0.3112560212612152, + -0.34908774495124817, + -0.42427319288253784, + 0.43349501490592957, + 0.03724945709109306, + -0.05263671651482582, + -0.010485195554792881, + 0.1261255145072937, + -0.1349790245294571, + -0.2524855136871338, + 0.24608080089092255, + 0.036001257598400116, + -0.028843939304351807, + 0.0056989979930222034, + 0.04458172619342804, + -0.06122935935854912, + -0.166972354054451, + 0.14557687938213348, + 0.018050044775009155, + 0.032598987221717834, + -0.0055792503990232944, + 0.24355076253414154, + -0.21433626115322113, + -0.29646870493888855, + 0.1958809792995453, + 0.015435033477842808, + 0.05235098674893379, + 0.010786890983581543, + 0.47903597354888916, + -0.4127257168292999, + -0.6203306317329407, + 0.47024452686309814, + 0.0823090448975563, + -0.04538045823574066, + -0.004072466865181923, + 0.7509317994117737, + -0.6508772969245911, + -0.8481631278991699, + 0.7875698208808899, + 0.0966777428984642, + -0.10461349785327911, + 0.0063789174892008305, + 0.7535857558250427, + -0.8082649111747742, + -0.8165622353553772, + 0.9064085483551025, + 0.04986630380153656, + -0.10200339555740356, + 0.0314355194568634, + 0.46324053406715393, + -0.5523763298988342, + -0.5632953643798828, + 0.6378755569458008, + 0.07833302766084671, + -0.07979781180620193, + 0.031164664775133133, + 0.1967470794916153, + -0.21681970357894897, + -0.29283079504966736, + 0.3367702066898346, + 0.034929461777210236, + -0.047199901193380356, + -0.0033645557705312967, + 0.05454660952091217, + -0.11264829337596893, + -0.190998375415802, + 0.17961400747299194, + 0.0009085010970011353, + -0.0001827089727157727, + 0.04841821268200874, + 0.019923821091651917, + -0.07004066556692123, + -0.10590090602636337, + 0.054114967584609985, + 0.04302384704351425, + 0.00462615629658103, + 0.022948985919356346, + 0.1673787385225296, + -0.1319379210472107, + -0.2711219787597656, + 0.2387620061635971, + 0.05667697265744209, + -0.018639734014868736, + -0.07672597467899323, + 0.3503187298774719, + -0.2981504797935486, + -0.38647517561912537, + 0.4072522521018982, + 0.010913677513599396, + -0.05246961489319801, + -0.04058554396033287, + 0.39216771721839905, + -0.3605193495750427, + -0.34857264161109924, + 0.46899959444999695, + -0.03358001261949539, + -0.05188553035259247, + -0.023204902186989784, + 0.17140533030033112, + -0.2120431810617447, + -0.2144550085067749, + 0.2837989032268524, + -0.0191226527094841, + -0.020922169089317322, + 0.004324179142713547, + 0.038136694580316544, + -0.042803723365068436, + -0.11487454175949097, + 0.11820490658283234, + 0.003412557765841484, + 0.0035020115319639444, + 0.03646541014313698, + -0.010104459710419178, + -0.010897459462285042, + -0.09292570501565933, + 0.06823977828025818, + 0.02677192911505699, + 0.020071662962436676, + 0.005776307079941034, + 0.02613351307809353, + 0.017107944935560226, + -0.0002623539185151458, + -0.039298396557569504, + -0.0314190648496151, + -0.019773684442043304, + -0.01924789510667324, + 0.04253160580992699, + 0.09694722294807434, + 0.1925637573003769, + 0.1901547759771347, + 0.09470294415950775, + -0.00296174269169569, + -0.03602522239089012, + 0.03572473302483559, + 0.08787581324577332, + 0.1773553043603897, + 0.20970025658607483, + 0.14899243414402008, + 0.05427362397313118, + -0.032429151237010956, + 0.023915717378258705, + 0.06557436287403107, + 0.13488733768463135, + 0.17550915479660034, + 0.17485061287879944, + 0.10260436683893204, + -0.005381361581385136, + -0.05573735386133194, + -0.09410752356052399, + -0.07940010726451874, + -0.03424998000264168, + 0.007975265383720398, + 0.028827181085944176, + 0.023788832128047943, + -0.02962818741798401, + -0.13474339246749878, + -0.22529757022857666, + -0.20413516461849213, + -0.14711618423461914, + -0.05960607901215553, + 0.04579121991991997, + 0.005325576290488243, + -0.11592217534780502, + -0.2260522097349167, + -0.2467145025730133, + -0.22054187953472137, + -0.13919179141521454, + 0.0016459478065371513, + 0.0515579916536808, + 0.060555730015039444, + 0.040788713842630386, + -0.017907800152897835, + -0.026459651067852974, + -0.02488812990486622, + 0.015644825994968414, + 0.10543125867843628, + 0.19312354922294617, + 0.28380078077316284, + 0.28878358006477356, + 0.16968156397342682, + 0.04848042502999306, + -0.00986899808049202, + 0.06337545067071915, + 0.16356752812862396, + 0.2444516271352768, + 0.29273414611816406, + 0.2314801961183548, + 0.12695762515068054, + -0.022283215075731277, + 0.018402203917503357, + 0.07152476161718369, + 0.14247483015060425, + 0.18759845197200775, + 0.20828258991241455, + 0.14114585518836975, + -0.047197990119457245, + -0.13794781267642975, + -0.17509934306144714, + -0.1696663200855255, + -0.1206701323390007, + -0.036128126084804535, + 0.007180679589509964, + 0.006984225939959288, + -0.09600912779569626, + -0.22975720465183258, + -0.33287662267684937, + -0.2942708134651184, + -0.20305578410625458, + -0.08411446958780289, + 0.042896877974271774, + -0.020053744316101074, + -0.16365791857242584, + -0.3145587742328644, + -0.3321540057659149, + -0.2667454183101654, + -0.1542910486459732, + -0.006954069249331951, + 0.020191870629787445, + 0.014010002836585045, + 0.0016916356980800629, + -0.04649524390697479, + -0.014931428246200085, + -0.017954425886273384, + -0.020003901794552803, + 0.03831968829035759, + 0.08447518199682236, + 0.14068123698234558, + 0.13400419056415558, + 0.08205568045377731, + -0.0004489773709792644, + -0.019211264327168465, + 0.023363608866930008, + 0.08738930523395538, + 0.12299696356058121, + 0.13070489466190338, + 0.09040816128253937, + 0.03286544978618622, + -0.006979941390454769, + -0.0010930931894108653, + 0.04313739389181137, + 0.10121051222085953, + 0.11390950530767441, + 0.11383924633264542, + 0.06694260239601135, + -0.00425445893779397, + -0.0666416585445404, + -0.09225274622440338, + -0.0977785512804985, + -0.07118111103773117, + -0.026749763637781143, + -0.019425569102168083, + 0.03321055322885513, + -0.0033978468272835016, + -0.08309262245893478, + -0.15557922422885895, + -0.14969374239444733, + -0.07188998907804489, + -0.018716221675276756, + 0.022834330797195435, + 0.004232254344969988, + -0.04141783341765404, + -0.125192329287529, + -0.14545302093029022, + -0.12225300818681717, + -0.05844716727733612, + 0.010607236064970493, + 0.024218380451202393, + -0.002702374942600727, + -0.030814893543720245, + 0.03507756441831589, + -0.0506589449942112, + 0.03415676951408386, + 0.0011444400297477841, + 0.0026324463542550802, + 0.028514407575130463, + -0.01849454641342163, + -0.030959082767367363, + -0.05565863475203514, + 0.05771413818001747, + 0.003916156478226185, + -0.004474544432014227, + 0.04403551295399666, + 0.1733711212873459, + -0.37650829553604126, + 0.22322984039783478, + 0.0032540319953113794, + -0.01139416079968214, + -0.039046600461006165, + 0.0021948080975562334, + 0.5777754783630371, + -1.1944804191589355, + 0.769478976726532, + -0.1349843591451645, + 0.0004430754925124347, + -0.0061850035563111305, + -0.08340868353843689, + 0.8327823877334595, + -1.649588942527771, + 1.126111388206482, + -0.2918313145637512, + 0.003614947199821472, + 0.0016799914883449674, + -0.03255167230963707, + 0.6123784184455872, + -1.1993682384490967, + 0.8305437564849854, + -0.13622376322746277, + 0.00905851274728775, + -0.006772476714104414, + 0.07578610628843307, + 0.05859832838177681, + -0.4543764293193817, + 0.26330503821372986, + 0.0259060300886631, + -0.0007997890934348106, + 0.01269856933504343, + 0.006897627376019955, + -0.02491801232099533, + -0.03139931708574295, + 0.0028456314466893673, + 0.0008253560517914593, + -0.01086023822426796, + -0.004186873324215412, + 0.06299160420894623, + -0.039931319653987885, + -0.09315146505832672, + 0.05495935305953026, + 0.027547571808099747, + -0.010900916531682014, + -0.025233760476112366, + 0.060600072145462036, + 0.21010243892669678, + -0.5445898771286011, + 0.35070353746414185, + -0.033771682530641556, + -0.0269146841019392, + -0.025363197550177574, + -0.021729450672864914, + 0.70921790599823, + -1.4368270635604858, + 0.9582043290138245, + -0.1708265244960785, + 0.010022420436143875, + -0.032301150262355804, + -0.08667651563882828, + 1.0338889360427856, + -1.913576364517212, + 1.262008547782898, + -0.23795078694820404, + -0.032233912497758865, + -0.01397701445966959, + -0.05402921140193939, + 0.7621430158615112, + -1.387437343597412, + 0.8621506094932556, + -0.14765247702598572, + -0.004747485741972923, + 0.0017516895895823836, + 0.08154146373271942, + 0.16601374745368958, + -0.5324177742004395, + 0.27442997694015503, + 0.03274058923125267, + -0.008812552317976952, + 0.005774920806288719, + 0.04165825620293617, + -0.011749272234737873, + -0.01953396573662758, + -0.009672109968960285, + 0.01170953270047903, + 0.003071938641369343, + -0.018979815766215324, + 0.062123894691467285, + -0.004921444226056337, + -0.03380037844181061, + 0.01310884952545166, + 0.007953890599310398, + -0.0012086924398317933, + -0.03317898139357567, + -0.0015596294542774558, + 0.08166785538196564, + -0.2291223704814911, + 0.11783571541309357, + -0.016078786924481392, + 0.018957575783133507, + 0.025793947279453278, + -0.09036394208669662, + 0.3833881616592407, + -0.5794023871421814, + 0.4610825777053833, + -0.14165280759334564, + -0.007412370759993792, + 0.05252876877784729, + -0.21435455977916718, + 0.6177686452865601, + -0.8516795635223389, + 0.667263925075531, + -0.22572898864746094, + -0.004465761594474316, + 0.02589319832623005, + -0.1893543303012848, + 0.43213585019111633, + -0.6462821364402771, + 0.434274822473526, + -0.15750259160995483, + -0.01198036689311266, + -2.4281514924950898e-05, + 0.039562296122312546, + 0.11126027256250381, + -0.23193514347076416, + 0.1412443071603775, + -0.011839920654892921, + 0.007880321703851223, + 0.02950354479253292, + 0.011689653620123863, + -0.07272310554981232, + -0.03319466486573219, + -0.003948990721255541, + 0.03549842908978462, + -0.02165558747947216, + -0.09912239760160446, + -0.08742356300354004, + 0.30591821670532227, + 0.23934677243232727, + 0.02658180706202984, + -0.022127188742160797, + -0.02769642136991024, + 0.16399237513542175, + 0.5140998959541321, + 0.007951628416776657, + -0.5589093565940857, + -0.24106110632419586, + -0.02753414213657379, + 0.06947467476129532, + 0.048558495938777924, + -0.5370690822601318, + -0.761831521987915, + 0.16272802650928497, + 0.29426246881484985, + 0.07943751662969589, + -0.022394873201847076, + -0.217612162232399, + -0.03093647211790085, + 0.5945476293563843, + 0.2873935103416443, + -0.16481661796569824, + -0.02931203693151474, + -0.029083512723445892, + 0.06754925847053528, + 0.20200076699256897, + -0.07271742075681686, + -0.1976277083158493, + -0.04189611226320267, + 0.06403793394565582, + -0.00022445111244451255, + -0.01032529678195715, + -0.03415631130337715, + 0.009091783314943314, + 0.04317992925643921, + 0.07196266949176788, + -0.025028688833117485, + -0.02722775563597679, + -0.017168480902910233, + -0.027666645124554634, + -0.06734028458595276, + 0.10843724757432938, + 0.08066407591104507, + -0.027849983423948288, + -0.0045820740051567554, + -0.03388727456331253, + 0.16772156953811646, + 0.651636004447937, + 0.34874194860458374, + -0.1454945057630539, + -0.18056720495224, + 0.11703842133283615, + 0.43017855286598206, + 0.7624525427818298, + -0.3420296907424927, + -1.272199273109436, + -0.5284644365310669, + -0.005667245015501976, + 0.08240436762571335, + -0.13299596309661865, + -1.3164156675338745, + -1.659982442855835, + 0.19898656010627747, + 0.6253566741943359, + 0.25137946009635925, + -0.18244975805282593, + -0.5360167622566223, + -0.06195700913667679, + 1.2547520399093628, + 1.0296341180801392, + 0.10651036351919174, + -0.023540280759334564, + -0.07594245672225952, + 0.1492130160331726, + 0.5033117532730103, + 0.09394379705190659, + -0.22459803521633148, + -0.22473134100437164, + -0.04738321527838707, + 0.04127531498670578, + 0.0682951882481575, + -0.02095615118741989, + -0.1233135387301445, + -0.10028401762247086, + -0.008111395873129368, + -0.000617706507910043, + 0.018859047442674637, + 0.028446361422538757, + -0.06159031391143799, + -0.1292838156223297, + 0.051308393478393555, + 0.11001072078943253, + -0.02056661807000637, + -0.012175443582236767, + -0.1313694268465042, + 0.0067574759013950825, + 0.4612729251384735, + 0.323080450296402, + -0.09392253309488297, + -0.1256203055381775, + 0.03537299111485481, + 0.2556088864803314, + 0.6467183232307434, + -0.16340143978595734, + -0.8799455165863037, + -0.3312987685203552, + 0.01464154850691557, + 0.07046713680028915, + 0.053634822368621826, + -0.8514915108680725, + -1.176972508430481, + 0.2056443840265274, + 0.4998764395713806, + 0.1268644779920578, + -0.10905193537473679, + -0.3750888705253601, + -0.06701061874628067, + 0.9052186608314514, + 0.6792045831680298, + -0.00323892361484468, + -0.0007412935374304652, + -0.03608793020248413, + 0.1009129211306572, + 0.36775916814804077, + 0.035214491188526154, + -0.2273784875869751, + -0.15815992653369904, + -0.004773923195898533, + 0.06374036520719528, + 0.04737555980682373, + -0.0563247986137867, + -0.09587392956018448, + -0.043853096663951874, + 0.032572731375694275, + -0.0036250585690140724, + 0.07889056205749512, + -0.03589344769716263, + -0.019771328195929527, + 0.04937156289815903, + 0.039052557200193405, + -0.013377528637647629, + -0.0841481015086174, + -0.03358105197548866, + -0.2128981053829193, + -0.14468812942504883, + 0.14675867557525635, + 0.2550889551639557, + 0.22369499504566193, + -0.0032973098568618298, + 0.006679064594209194, + -0.11752036958932877, + 0.025247232988476753, + 0.23064176738262177, + 0.25043538212776184, + 0.3474777638912201, + 0.2151806503534317, + 0.051294319331645966, + 0.16301114857196808, + 0.25422143936157227, + -0.1796918362379074, + -0.6128425598144531, + -0.42049655318260193, + 0.07740531116724014, + -0.007960617542266846, + 0.2504507601261139, + 0.2932300865650177, + -0.5157915949821472, + -1.2904177904129028, + -1.0362532138824463, + -0.22443994879722595, + 0.007411653641611338, + 0.16024430096149445, + 0.33939966559410095, + -0.2748318016529083, + -0.8487470149993896, + -0.5955387949943542, + 0.033155132085084915, + -0.09185351431369781, + -0.05639262869954109, + 0.17084303498268127, + 0.11292264610528946, + -0.046329669654369354, + 0.11495561897754669, + 0.31740760803222656, + -0.13903948664665222, + 0.05507560819387436, + 0.10180198401212692, + -0.1369788944721222, + -0.10618618875741959, + -0.001083499751985073, + 0.16340164840221405, + 0.07591762393712997, + 0.3417445123195648, + 0.27897438406944275, + -0.32192930579185486, + -0.5731648206710815, + -0.46150147914886475, + -0.03230089321732521, + 0.04096771031618118, + 0.22242987155914307, + 0.027000218629837036, + -0.4113498628139496, + -0.433158278465271, + -0.5252256393432617, + -0.3510502874851227, + -0.133863165974617, + -0.38554033637046814, + -0.45547229051589966, + 0.2475612610578537, + 1.154951572418213, + 0.8282179236412048, + -0.13197137415409088, + -0.03350961208343506, + -0.5282800197601318, + -0.5297923684120178, + 0.9037952423095703, + 2.516275405883789, + 2.086421489715576, + 0.3573826849460602, + -0.010694397613406181, + -0.31418153643608093, + -0.5325371026992798, + 0.48083701729774475, + 1.7732245922088623, + 1.2747145891189575, + -0.06401863694190979, + 0.14296381175518036, + 0.07267159968614578, + -0.28001847863197327, + -0.29204103350639343, + 0.12853951752185822, + -0.1998838633298874, + -0.6375644207000732, + 0.06310836225748062, + -0.020014479756355286, + -0.08150970935821533, + 0.08175478130578995, + 0.07667485624551773, + 0.0025236753281205893, + -0.08504530042409897, + -0.035742271691560745, + -0.1332666128873825, + -0.15150736272335052, + 0.18459312617778778, + 0.3363596200942993, + 0.2501969635486603, + 0.029292423278093338, + -0.060296736657619476, + -0.1142202764749527, + -0.05918247997760773, + 0.18826954066753387, + 0.2183520495891571, + 0.21247169375419617, + 0.14935970306396484, + 0.09923429787158966, + 0.21808095276355743, + 0.21930061280727386, + -0.060535889118909836, + -0.5729222297668457, + -0.4199080169200897, + 0.058897778391838074, + 0.050647757947444916, + 0.2784770131111145, + 0.2754706144332886, + -0.40136128664016724, + -1.3269731998443604, + -1.124815583229065, + -0.11878778040409088, + -0.005137663800269365, + 0.17839783430099487, + 0.2115524858236313, + -0.24165289103984833, + -0.9655010104179382, + -0.7425088286399841, + 0.0304054357111454, + -0.07012742757797241, + -0.015557953156530857, + 0.1128007024526596, + 0.18957749009132385, + -0.07996463775634766, + 0.09505810588598251, + 0.34419506788253784, + -0.3072076439857483, + 0.03868290036916733, + 0.11494885385036469, + 0.03748936951160431, + 0.0797261893749237, + -0.003397951368242502, + -0.07380004972219467, + -0.11507676541805267, + -0.10298885405063629, + 0.10698320716619492, + 0.06602972000837326, + 0.08226803690195084, + 0.0037747276946902275, + -0.162277951836586, + 0.01671667955815792, + 0.09137773513793945, + 0.18799471855163574, + 0.04144813120365143, + 0.1285877376794815, + 0.1820434182882309, + 0.04940629005432129, + 0.0991915687918663, + 0.10219171643257141, + -0.013141660951077938, + -0.051191627979278564, + 0.05468929558992386, + 0.087598517537117, + 0.15897324681282043, + 0.11863455921411514, + -0.00814050156623125, + -0.07701541483402252, + -0.14013728499412537, + -0.044140227138996124, + -0.05328791216015816, + 0.06760499626398087, + 0.12053386867046356, + 0.09780212491750717, + -0.053725965321063995, + -0.07915244251489639, + -0.0032519602682441473, + 0.019637396559119225, + 0.07848430424928665, + 0.019138827919960022, + 0.1460287868976593, + 0.1281038075685501, + 0.024417784065008163, + 0.059176862239837646, + 0.0658111497759819, + -0.016405148431658745, + -0.18877744674682617, + 0.16666102409362793, + 0.1610611230134964, + 0.08374520391225815, + 0.11570518463850021, + 0.11903064697980881, + 0.1294964700937271, + 0.06379758566617966, + 0.08417274057865143, + 0.12754113972187042, + 0.025328608229756355, + 0.05170705169439316, + 0.0835295170545578, + 0.07477264851331711, + 0.11244285851716995, + 0.11559426784515381, + 0.045258160680532455, + -0.14825093746185303, + -0.08153342455625534, + 0.06288623809814453, + 0.11952362209558487, + 0.11784297972917557, + 0.011141132563352585, + -0.21666541695594788, + -0.29976174235343933, + -0.2279169261455536, + -0.11828474700450897, + 0.12436322867870331, + 0.10465826094150543, + -0.09751085937023163, + -0.292611300945282, + -0.37374064326286316, + -0.31437963247299194, + -0.25637903809547424, + 0.06173908710479736, + 0.14131486415863037, + 0.008434675633907318, + -0.23816508054733276, + -0.30330890417099, + -0.22094152867794037, + -0.11608295142650604, + 0.13235151767730713, + 0.15353602170944214, + 0.15839524567127228, + 0.012247815728187561, + -0.08126968890428543, + -0.003756331978365779, + 0.10660683363676071, + 0.21976575255393982, + -0.04188326746225357, + 0.15462253987789154, + 0.06303395330905914, + 0.006879634689539671, + 0.008284888230264187, + 0.07084798067808151, + 0.1211942657828331, + 0.10190404951572418, + 0.02935362420976162, + -0.05645999684929848, + -0.16800500452518463, + -0.1850246787071228, + -0.09476880729198456, + -0.025327544659376144, + 0.054355036467313766, + -0.035813912749290466, + -0.18694879114627838, + -0.34871891140937805, + -0.3151862621307373, + -0.1943007856607437, + -0.09755205363035202, + 0.014881589449942112, + -0.14875493943691254, + -0.37112873792648315, + -0.37739917635917664, + -0.3241480886936188, + -0.2915399968624115, + -0.11268249899148941, + -0.019726404920220375, + -0.2510305941104889, + -0.38005372881889343, + -0.3622463345527649, + -0.2932804226875305, + -0.28574010729789734, + -0.1505027860403061, + -0.004947682376950979, + -0.18587322533130646, + -0.34759166836738586, + -0.28965193033218384, + -0.21052972972393036, + -0.18780536949634552, + -0.07400713860988617, + 0.11154936999082565, + -0.03556853160262108, + -0.1896934062242508, + -0.18135806918144226, + -0.10117948800325394, + -0.0393117293715477, + 0.06517928093671799, + -0.016659021377563477, + -0.011290309950709343, + -0.007930322550237179, + 0.008189777843654156, + 0.03678786754608154, + 0.021890517324209213, + 0.0034292477648705244, + 0.02200375869870186, + 0.0014921070542186499, + -0.0800287202000618, + -0.17657361924648285, + -0.18702608346939087, + -0.12880444526672363, + -0.022084584459662437, + 0.026420501992106438, + -0.023968446999788284, + -0.07948111742734909, + -0.16741475462913513, + -0.18733707070350647, + -0.16539834439754486, + -0.07347387820482254, + -0.009723886847496033, + -0.02016977220773697, + -0.061092622578144073, + -0.13145211338996887, + -0.15919029712677002, + -0.15043555200099945, + -0.10107766091823578, + 0.0016151965828612447, + 0.0627974420785904, + 0.08695066720247269, + 0.11727584898471832, + 0.11745581030845642, + 0.11329426616430283, + 0.0533670075237751, + -0.016355818137526512, + 0.008450252935290337, + 0.06448577344417572, + 0.1538505256175995, + 0.21232697367668152, + 0.14713847637176514, + 0.039088234305381775, + -0.015588105656206608, + 0.026483291760087013, + 0.060862988233566284, + 0.18265819549560547, + 0.23042462766170502, + 0.168768972158432, + 0.034099943935871124, + -0.018249109387397766, + -0.0321880541741848, + -0.03254542127251625, + -0.03061222843825817, + -0.0026304698549211025, + 0.017764942720532417, + 0.010707704350352287, + 0.009254949167370796, + -0.04533161595463753, + -0.1483704000711441, + -0.2637183666229248, + -0.2678598165512085, + -0.1737881749868393, + -0.049990858882665634, + 0.013515918515622616, + -0.054345693439245224, + -0.1467861533164978, + -0.24911582469940186, + -0.2831358015537262, + -0.22300836443901062, + -0.13739243149757385, + -0.017879672348499298, + -0.040345460176467896, + -0.09990613907575607, + -0.16936856508255005, + -0.2266550064086914, + -0.2020808756351471, + -0.1509508341550827, + 0.014163740910589695, + 0.07591170817613602, + 0.09185601025819778, + 0.10455341637134552, + 0.09514842182397842, + 0.09877350926399231, + 0.053898438811302185, + 0.005704578943550587, + 0.0591997392475605, + 0.13600079715251923, + 0.21777905523777008, + 0.2574957311153412, + 0.20117221772670746, + 0.11415109038352966, + -0.001181072206236422, + 0.09470006823539734, + 0.18978413939476013, + 0.3073742389678955, + 0.36875811219215393, + 0.3069853186607361, + 0.1708926260471344, + -0.0325310118496418, + -0.02656698040664196, + 0.016060845926404, + 0.02459372952580452, + 0.04165660962462425, + 0.033969976007938385, + 0.012855498120188713, + 0.030497560277581215, + 0.004896117839962244, + -0.030887477099895477, + -0.13454437255859375, + -0.1294785887002945, + -0.06398608535528183, + 0.016156472265720367, + 0.03577340394258499, + -0.0033482143189758062, + -0.07112833857536316, + -0.16465041041374207, + -0.1621057391166687, + -0.09478478878736496, + -0.03555302321910858, + -0.001592929707840085, + -0.01719600521028042, + -0.06598587334156036, + -0.1411861628293991, + -0.1496778130531311, + -0.11535074561834335, + -0.0905962884426117, + -0.013807609677314758, + 0.029542237520217896, + 0.039138730615377426, + 0.03988270089030266, + 0.02665030211210251, + 0.049553126096725464, + -0.0015685928519815207, + -0.018007200211286545, + 0.009533192962408066, + 0.06910547614097595, + 0.1034330427646637, + 0.15017645061016083, + 0.10221225768327713, + 0.020978443324565887, + -0.023747621104121208, + 0.02295384369790554, + 0.09313814342021942, + 0.1771395057439804, + 0.21169933676719666, + 0.17989481985569, + 0.05862005427479744, + -0.004540165886282921, + 0.021994179114699364, + -0.003493826137855649, + -0.000224211675231345, + 0.031808022409677505, + -0.05090906098484993, + 0.001970196608453989, + 0.01633802428841591, + 0.0049764602445065975, + 0.0006027702474966645, + -0.005952450912445784, + -0.009886081330478191, + -0.08520589768886566, + 0.030780712142586708, + 0.00037104589864611626, + 0.011886775493621826, + -0.023506291210651398, + 0.08029806613922119, + -0.005086984951049089, + -0.07738454639911652, + 0.06721897423267365, + -0.02397127076983452, + 0.006669329944998026, + -0.016343094408512115, + 0.06056324020028114, + 0.15656796097755432, + -0.49836501479148865, + 0.2475810945034027, + -0.009270203299820423, + -0.006855266634374857, + 0.0034896093420684338, + -0.027938276529312134, + 0.5722692012786865, + -1.1357109546661377, + 0.5644665956497192, + 0.015787361189723015, + -0.015141892246901989, + -0.0032788251992315054, + -0.04797150194644928, + 0.6196744441986084, + -1.1540743112564087, + 0.6065864562988281, + 0.0019708566833287477, + 0.006332532037049532, + 0.014192940667271614, + 0.03773411735892296, + 0.27323007583618164, + -0.594700813293457, + 0.2488076239824295, + -0.008853388018906116, + 0.005692378617823124, + 0.000576167949475348, + -0.027197014540433884, + 0.022015029564499855, + -0.02571249194443226, + 0.004507753532379866, + -0.002439734758809209, + -0.01994609646499157, + 0.03601142391562462, + 0.008136607706546783, + 0.01658148691058159, + -0.06548810750246048, + 0.022721221670508385, + -0.0038820707704871893, + -0.0007800398161634803, + 0.001392301986925304, + 0.09576108306646347, + -0.014628835022449493, + -0.14505760371685028, + 0.07135403156280518, + -0.00839388556778431, + -0.004555124789476395, + -0.04466082155704498, + 0.1456393599510193, + 0.3475525975227356, + -0.7879117131233215, + 0.36262738704681396, + 0.008226356469094753, + 0.0055343699641525745, + -0.061139706522226334, + 0.08975803852081299, + 0.9340736269950867, + -1.7307822704315186, + 0.796896755695343, + -0.024700213223695755, + -0.013090251013636589, + -0.05148586630821228, + 0.050525497645139694, + 0.927090048789978, + -1.7473385334014893, + 0.7727715373039246, + -0.005721901543438435, + 0.010676853358745575, + -0.012798544019460678, + 0.11131046712398529, + 0.4181194007396698, + -0.8475598096847534, + 0.33206430077552795, + 0.018843427300453186, + 0.0006885005859658122, + 0.027498219162225723, + 0.00207257061265409, + 0.0032615051604807377, + -0.021950624883174896, + -0.008452882058918476, + -0.007631891872733831, + -0.028561849147081375, + 0.04865337535738945, + -0.0023105579894036055, + -0.026170270517468452, + -0.011794357560575008, + 0.004327487666159868, + 0.01756221242249012, + 0.0011611212976276875, + -0.008793564513325691, + 0.0741758644580841, + -0.057649385184049606, + -0.006000686902552843, + -0.022717488929629326, + -0.0047143916599452496, + 0.005709030199795961, + -0.05611564591526985, + 0.05792170390486717, + 0.1873699128627777, + -0.3856293857097626, + 0.1371920108795166, + 0.018953431397676468, + 0.015250314958393574, + -0.0016827551880851388, + -0.08515634387731552, + 0.6517581939697266, + -0.9557326436042786, + 0.46986615657806396, + -0.014306572265923023, + -0.01625121757388115, + -0.016088897362351418, + -0.13429272174835205, + 0.6437729001045227, + -1.0167845487594604, + 0.5061463117599487, + 0.00879831612110138, + -0.008598369546234608, + 0.02747279778122902, + 0.007245234213769436, + 0.2527446150779724, + -0.47163763642311096, + 0.15560215711593628, + 0.005050336476415396, + -0.024848125874996185, + -0.0006449198699556291, + -0.008673148229718208, + -0.06940636038780212, + -0.016248086467385292, + 0.1250494420528412, + 0.026387182995676994, + 0.009615709073841572, + -0.0025482974015176296, + -0.04534498229622841, + -0.2626228630542755, + -0.2753732204437256, + 0.052055053412914276, + 0.010792221873998642, + 0.007360508665442467, + 0.10271529853343964, + 0.1113760769367218, + -0.31120774149894714, + -0.49849262833595276, + -0.2206398844718933, + 0.04994913563132286, + 0.054614756256341934, + 0.27786919474601746, + 0.56647789478302, + 0.20970205962657928, + -0.22717078030109406, + -0.17321231961250305, + -0.07836200296878815, + -0.09607961028814316, + 0.10685958713293076, + 0.40848156809806824, + 0.34087467193603516, + -0.005242985673248768, + -0.0682876780629158, + -0.0694413110613823, + -0.1886596381664276, + -0.04473332315683365, + 0.18096435070037842, + 0.1961163580417633, + 0.0014336564345285296, + 0.014584851451218128, + 0.0462430939078331, + -0.1556192934513092, + -0.12809665501117706, + 0.0213937908411026, + 0.10984069108963013, + -0.023050926625728607, + -0.013447473756968975, + 0.007857509888708591, + -0.027979737147688866, + -0.04768490046262741, + -0.09350565075874329, + -0.1659490317106247, + 0.007927919737994671, + 0.26641780138015747, + 0.03398526459932327, + 0.02118881419301033, + -0.006898822728544474, + -0.15209096670150757, + -0.4939330220222473, + -0.42655149102211, + 0.08215854316949844, + 0.02115131914615631, + 0.08892140537500381, + 0.2164168655872345, + 0.12431265413761139, + -0.47813764214515686, + -0.6588870882987976, + -0.3097454905509949, + 0.0837375745177269, + 0.1548176258802414, + 0.49661529064178467, + 0.7337944507598877, + 0.1966201215982437, + -0.29367199540138245, + -0.2547970116138458, + -0.11655519157648087, + -0.11720486730337143, + 0.21941716969013214, + 0.5902130603790283, + 0.42572125792503357, + 0.020460324361920357, + -0.12768393754959106, + -0.12030418962240219, + -0.2582310736179352, + -0.0355166494846344, + 0.2766987085342407, + 0.28080257773399353, + 0.08665957301855087, + 0.027141664177179337, + 0.02690703421831131, + -0.25276950001716614, + -0.23180679976940155, + 0.015180152840912342, + 0.11523276567459106, + 0.041165824979543686, + 0.017444534227252007, + 0.0009439520072191954, + -0.025763530284166336, + -0.022880665957927704, + -0.024819007143378258, + -0.04901815578341484, + 0.027672944590449333, + 0.11211585998535156, + 0.024664992466568947, + -0.010093869641423225, + 0.009466213174164295, + -0.043605536222457886, + -0.17007218301296234, + -0.1366996467113495, + 0.08740171790122986, + -0.014591479673981667, + -0.0031720874831080437, + 0.0835830345749855, + 0.028662094846367836, + -0.21436777710914612, + -0.24753160774707794, + -0.06092096120119095, + 0.03788171336054802, + 0.04295210912823677, + 0.19064708054065704, + 0.3095722496509552, + 0.08003447204828262, + -0.09509303420782089, + -0.05495578795671463, + -0.052218906581401825, + -0.07204427570104599, + 0.07710819691419601, + 0.18033725023269653, + 0.0834946483373642, + -0.049662720412015915, + -0.06561554968357086, + -0.013351643458008766, + -0.11217659711837769, + 0.031957074999809265, + 0.12180440872907639, + 0.06891122460365295, + -0.013705568388104439, + 0.0011150656500831246, + 0.03281388059258461, + -0.11285661906003952, + -0.06422404199838638, + 0.04218210279941559, + 0.014165353029966354, + -0.006244795396924019, + 0.01745765097439289, + 0.08924975246191025, + 0.01710040494799614, + -0.14013372361660004, + -0.21913501620292664, + 0.03613810986280441, + 0.14273521304130554, + 0.05801931768655777, + 0.021427493542432785, + 0.23185034096240997, + 0.2427377849817276, + -0.4384608566761017, + -0.7205182909965515, + -0.18313364684581757, + 0.033575087785720825, + -0.0809125304222107, + 0.04173902049660683, + 0.7251381874084473, + 1.1058244705200195, + -0.015065462328493595, + -0.6434917449951172, + -0.3080260753631592, + -0.090518057346344, + -0.3659006655216217, + -0.4520319700241089, + 0.5924424529075623, + 1.4148176908493042, + 0.5285682082176208, + -0.027211233973503113, + -0.07359065115451813, + -0.08583711832761765, + -0.5631492137908936, + -1.0246236324310303, + -0.1835726648569107, + 0.3307121694087982, + 0.22562064230442047, + 0.05237145721912384, + 0.13263091444969177, + 0.13899636268615723, + -0.1626550555229187, + -0.3918432295322418, + -0.03585565462708473, + 0.06904798001050949, + 0.029870154336094856, + 0.04289601743221283, + 0.05758490040898323, + 0.10055387020111084, + -0.011962685734033585, + -0.13269846141338348, + 0.0012237781193107367, + 0.05511128902435303, + 0.03764793649315834, + -0.07580426335334778, + -0.1750984787940979, + 0.0189101230353117, + 0.08156414330005646, + 0.01691802591085434, + 0.004023027140647173, + 0.18009696900844574, + 0.22744491696357727, + -0.38747039437294006, + -0.6413040161132812, + -0.19208981096744537, + 0.01971367374062538, + -0.036756888031959534, + 0.004946697968989611, + 0.7331712245941162, + 1.1178003549575806, + 0.03220612183213234, + -0.5881579518318176, + -0.24453559517860413, + -0.11856977641582489, + -0.43593257665634155, + -0.5339378118515015, + 0.49467018246650696, + 1.3376370668411255, + 0.5238692164421082, + 0.04584280773997307, + 0.004761924035847187, + -0.032823480665683746, + -0.5419207811355591, + -1.0093209743499756, + -0.19847697019577026, + 0.20687319338321686, + 0.12301573902368546, + 0.07981085777282715, + 0.14125365018844604, + 0.19885297119617462, + -0.1678825318813324, + -0.4042292535305023, + 0.004483209457248449, + 0.03009556047618389, + 0.010802071541547775, + 0.005967534612864256, + 0.0892769992351532, + 0.07342032343149185, + -0.0588892325758934, + -0.09044717997312546, + 0.06307072192430496, + -0.012583961710333824, + -0.006880680099129677, + 0.0030021765269339085, + 0.01633061282336712, + 0.06990820169448853, + 0.0070900083519518375, + -0.03546716272830963, + -0.022131899371743202, + -0.02906683459877968, + 0.010664403438568115, + -0.18731924891471863, + -0.158770352602005, + 0.08571326732635498, + 0.039154618978500366, + 0.032578419893980026, + -0.005781106185168028, + 0.17460086941719055, + 0.2787456810474396, + -0.13416190445423126, + -0.23966801166534424, + -0.004878139588981867, + 0.02796499989926815, + -0.06610933691263199, + -0.19162042438983917, + 0.11163146048784256, + 0.371842622756958, + 0.06444671750068665, + 0.016595548018813133, + 0.01164282951503992, + 0.08330011367797852, + -0.03192862868309021, + -0.2867860198020935, + -0.07080501317977905, + -0.016348646953701973, + -0.06306261569261551, + -0.016291450709104538, + 0.010558445006608963, + 0.13014638423919678, + 0.06202690303325653, + -0.03361419215798378, + 0.0691375732421875, + 0.003561250865459442, + -0.013095442205667496, + -0.050333790481090546, + -0.019117066636681557, + 0.0012089330703020096, + -0.004555183462798595, + -0.022682132199406624, + 0.04747068136930466, + -0.06425238400697708, + -0.0010437731398269534, + -0.0071629988960921764, + -0.04302623122930527, + -0.04830477759242058, + -0.04069536179304123, + -0.06627446413040161, + -0.011470981873571873, + 0.03961857780814171, + 0.026594260707497597, + -0.020662540569901466, + -0.05999285355210304, + -0.053548794239759445, + -0.025959201157093048, + -0.015834785997867584, + 0.013910192996263504, + -0.015868371352553368, + -0.056620921939611435, + -0.06785159558057785, + -0.061030179262161255, + -0.03560228645801544, + -0.04177624359726906, + -0.024657463654875755, + -0.04889696091413498, + 0.004557035397738218, + 0.15414470434188843, + 0.21642963588237762, + 0.035425592213869095, + -0.04339970648288727, + -0.05034525692462921, + -0.08522290736436844, + 0.10652441531419754, + 0.6791198253631592, + 0.7785530686378479, + 0.19941796362400055, + -0.05430706962943077, + -0.02583213709294796, + -0.055139996111392975, + 0.17940561473369598, + 0.6757862567901611, + 0.8240399360656738, + 0.25826773047447205, + -0.062254682183265686, + -0.026456547901034355, + -0.027271386235952377, + -0.0026193747762590647, + 0.11893659085035324, + 0.1915995329618454, + 0.013776157051324844, + 0.08452087640762329, + 0.009950258769094944, + 0.01774573139846325, + 0.06609759479761124, + 0.06512798368930817, + 0.07601971179246902, + 0.09192144125699997, + 0.007696932647377253, + -0.056120894849300385, + -0.03937293961644173, + 0.043086692690849304, + 0.055803027004003525, + 0.08208976686000824, + 0.03658852353692055, + 0.025779196992516518, + -0.0340605266392231, + 0.03186321631073952, + 0.09720855951309204, + 0.10651290416717529, + 0.09562067687511444, + 0.08120692521333694, + 0.06832587718963623, + 0.03940538689494133, + 0.09561086446046829, + -0.03726261481642723, + -0.3520663380622864, + -0.4187469184398651, + -0.11643502116203308, + 0.06203937157988548, + 0.056670401245355606, + 0.11540547758340836, + -0.2742924690246582, + -1.1301417350769043, + -1.2482489347457886, + -0.4411431849002838, + 0.08538330346345901, + 0.036888301372528076, + 0.08759869635105133, + -0.32129940390586853, + -1.1163593530654907, + -1.26430082321167, + -0.48638999462127686, + 0.1056363582611084, + 0.042436979711055756, + 0.07075526565313339, + -0.08341801166534424, + -0.30567145347595215, + -0.39268070459365845, + -0.10187282413244247, + -0.02507772110402584, + -0.0044433241710066795, + -0.009278317913413048, + -0.02964872494339943, + -0.018799586221575737, + -0.03760084509849548, + -0.030454028397798538, + -0.004638439975678921, + 0.026587119325995445, + 0.0095819728448987, + -0.007110759150236845, + -0.006491640582680702, + -0.028083719313144684, + -0.009543413296341896, + -0.005706887226551771, + 0.013012710027396679, + -0.010281933471560478, + -0.0544208325445652, + -0.023230208083987236, + -0.05344587564468384, + -0.04052828997373581, + -0.028035156428813934, + -0.011922319419682026, + -0.045427750796079636, + 0.020700184628367424, + 0.2117788940668106, + 0.21090814471244812, + 0.07214333862066269, + -0.019348343834280968, + -0.014455118216574192, + -0.03561105206608772, + 0.17339389026165009, + 0.49509289860725403, + 0.5219546556472778, + 0.26121678948402405, + -0.029803339391946793, + -0.013761913403868675, + -0.04028521850705147, + 0.17008572816848755, + 0.45583003759384155, + 0.4757367670536041, + 0.22357690334320068, + -0.050064269453287125, + -0.021086007356643677, + -0.039873600006103516, + 0.06433176249265671, + 0.20187893509864807, + 0.2078690379858017, + 0.07802058011293411, + 0.022050827741622925, + -0.05272649601101875, + -0.024311071261763573, + -0.12387345731258392, + -0.20065246522426605, + 0.0262442696839571, + 0.20101603865623474, + 0.056791841983795166, + -0.008266052231192589, + 0.025132112205028534, + -0.23289933800697327, + -0.5296569466590881, + -0.282010018825531, + 0.025113720446825027, + 0.13172000646591187, + 0.16999290883541107, + 0.31588253378868103, + 0.05583454668521881, + -0.5321000814437866, + -0.5585035085678101, + -0.23885560035705566, + 0.0461968369781971, + 0.13807418942451477, + 0.6536149382591248, + 0.6385176777839661, + -0.15636183321475983, + -0.5484278798103333, + -0.5470613241195679, + -0.06269911676645279, + -0.06726553291082382, + 0.5561463236808777, + 1.0985187292099, + 0.6801460385322571, + 0.12841203808784485, + -0.21693651378154755, + -0.19168342649936676, + -0.43073776364326477, + -0.15226863324642181, + 0.41150590777397156, + 0.47421786189079285, + 0.25146934390068054, + -0.017203813418745995, + -0.09694849699735641, + -0.4082376956939697, + -0.3549531400203705, + -0.023591510951519012, + 0.12086013704538345, + 0.08050766587257385, + -0.044960521161556244, + -0.0031193571630865335, + 0.014398006722331047, + -0.005931032355874777, + 0.01548685971647501, + 0.05407734215259552, + -0.006386967841535807, + 0.021660227328538895, + 0.01656133122742176, + 0.002835798542946577, + 0.0008500503608956933, + 0.021802745759487152, + 0.13470955193042755, + 0.06802596151828766, + 0.0033256933093070984, + 0.03037848509848118, + 0.054654810577631, + -0.034221138805150986, + 0.015171438455581665, + 0.23395732045173645, + 0.24771827459335327, + 0.16352902352809906, + -0.07505007833242416, + -0.0814652070403099, + -0.21493901312351227, + -0.3109704852104187, + 0.013416547328233719, + 0.12807825207710266, + 0.12044191360473633, + -0.007915153168141842, + 0.0100772799924016, + -0.15165796875953674, + -0.4013277292251587, + -0.24811144173145294, + -0.06641282886266708, + 0.022568246349692345, + 0.061083581298589706, + 0.09920243173837662, + 0.0695505365729332, + -0.12213064730167389, + -0.12606006860733032, + -0.04593949392437935, + -0.040190644562244415, + 0.03899035230278969, + 0.12688779830932617, + 0.114081971347332, + -0.013348283246159554, + 0.03325115144252777, + 0.007111718878149986, + 0.048056699335575104, + -0.003726312192156911, + 0.05401211231946945, + 0.05355936661362648, + 0.21303032338619232, + 0.2944865822792053, + -0.13604623079299927, + -0.3770989775657654, + -0.0808275118470192, + -0.006103217601776123, + -0.02005188539624214, + 0.37605899572372437, + 0.7776278853416443, + 0.32064270973205566, + -0.23708422482013702, + -0.23380732536315918, + -0.22103570401668549, + -0.45596328377723694, + 0.07213663309812546, + 0.9384943246841431, + 0.8762810230255127, + 0.3557227551937103, + -0.09239326417446136, + -0.25462013483047485, + -0.9858288168907166, + -0.9860153198242188, + 0.2600172162055969, + 0.7731484770774841, + 0.7665594816207886, + 0.14806008338928223, + 0.13109923899173737, + -0.6917864680290222, + -1.580305814743042, + -0.9557210803031921, + -0.16357193887233734, + 0.3189502954483032, + 0.28703632950782776, + 0.5599567890167236, + 0.2459551841020584, + -0.5451022982597351, + -0.6926754713058472, + -0.4368602931499481, + 0.027606861665844917, + 0.025857241824269295, + 0.5376880764961243, + 0.535673975944519, + 0.09012678265571594, + -0.14688564836978912, + -0.1812361180782318, + 0.050619762390851974, + 0.021388273686170578, + -0.05923623591661453, + -0.006538081914186478, + 0.05171535536646843, + -0.051560595631599426, + -0.007643367163836956, + 0.027748188003897667, + 0.0024676925968378782, + -0.008760283701121807, + 0.13039670884609222, + 0.18568934500217438, + 0.06342563778162003, + 0.030788781121373177, + -0.004423442296683788, + -0.041261281818151474, + 0.013299684040248394, + 0.22491391003131866, + 0.27831292152404785, + 0.0883866474032402, + 0.048967570066452026, + 0.0012756097130477428, + -0.03215779736638069, + 0.02710782177746296, + 0.20178261399269104, + 0.22446107864379883, + 0.06052157282829285, + 0.019020315259695053, + 0.02715166099369526, + -0.03146626800298691, + -0.017960363999009132, + 0.11820292472839355, + 0.16114193201065063, + 0.05221821367740631, + -0.02201441302895546, + -0.026308327913284302, + 0.008580431342124939, + -0.02444308064877987, + 0.061380185186862946, + 0.11184953153133392, + 0.006053542252629995, + -0.03248603641986847, + -0.037558719515800476, + 0.01881473697721958, + -0.02349863201379776, + 0.02150980569422245, + 0.09881952404975891, + 0.03962325677275658, + -0.0031782283913344145, + -0.0030868228059262037, + -0.007606725674122572, + -0.06136326491832733, + 0.022755015641450882, + 0.09683670848608017, + 0.0016674631042405963, + 0.01306125894188881, + 0.011335537768900394, + -0.01769089885056019, + 0.005807302892208099, + 0.19103741645812988, + 0.2631426155567169, + 0.10424992442131042, + 0.025223100557923317, + -0.024689532816410065, + -0.03370697423815727, + 0.0512213259935379, + 0.2983294129371643, + 0.37597405910491943, + 0.18788966536521912, + 0.056492965668439865, + -0.006051253993064165, + -0.027141474187374115, + 0.06733105331659317, + 0.29171472787857056, + 0.32160115242004395, + 0.14176633954048157, + 0.008538221009075642, + -0.013039524666965008, + -0.04279422387480736, + 0.03345612436532974, + 0.19111940264701843, + 0.25728005170822144, + 0.09830093383789062, + -0.03371569141745567, + -0.05277566984295845, + -0.0011038694065064192, + -0.013657800853252411, + 0.10037966072559357, + 0.1724642813205719, + 0.04436478391289711, + -0.02240786701440811, + -0.02181128039956093, + 0.019526727497577667, + -0.050060197710990906, + 0.017275504767894745, + 0.07785085588693619, + -0.001727179973386228, + -0.0014453287003561854, + 0.019352080300450325, + -0.003202121239155531, + -0.04241566359996796, + 0.005586653482168913, + 0.06037082523107529, + 0.014115821570158005, + -0.00568200321868062, + 0.018071964383125305, + -0.0007147599244490266, + 0.011219227686524391, + 0.10582104325294495, + 0.15557849407196045, + 0.06189450994133949, + 0.014160261489450932, + 0.00814653467386961, + -0.028064200654625893, + 0.026086319237947464, + 0.1474728286266327, + 0.18273885548114777, + 0.06638553738594055, + 0.019263381138443947, + 0.028977060690522194, + -0.02551555074751377, + 0.01937149092555046, + 0.12000202387571335, + 0.1285850703716278, + 0.047506313771009445, + -0.011383740231394768, + 0.02826755866408348, + -0.009583448991179466, + -0.02093282900750637, + 0.07994058728218079, + 0.0926218256354332, + 0.0318426676094532, + -0.024409465491771698, + 0.020994359627366066, + 0.03295197710394859, + -0.034276511520147324, + 0.037398867309093475, + 0.0794353187084198, + 0.022805212065577507, + 0.0015407208120450377, + 0.013169347308576107, + 0.038584139198064804, + -0.002118688775226474, + 0.03358406573534012, + 0.09085306525230408, + 0.04255761206150055, + 0.010275964625179768, + 0.025351760908961296, + 0.04205995053052902, + 0.1319226324558258, + 0.049708493053913116, + -0.03743802383542061, + -0.04293569549918175, + -0.07646205276250839, + -0.04986324533820152, + 0.15992362797260284, + 0.011027384549379349, + -0.32150742411613464, + -0.3761928677558899, + -0.1654653549194336, + -0.08728181570768356, + 0.044714685529470444, + -0.007500737439841032, + -0.41376256942749023, + -0.6625701189041138, + -0.21809393167495728, + 0.10641554743051529, + 0.09274336695671082, + 0.10189083218574524, + -0.1175118163228035, + -0.2905261516571045, + -0.06248515099287033, + 0.4791955053806305, + 0.49865299463272095, + 0.23415400087833405, + 0.12729482352733612, + -0.05814196541905403, + -0.003843356389552355, + 0.16410382091999054, + 0.40895968675613403, + 0.22034852206707, + 0.021014101803302765, + -0.05658271536231041, + -0.012199933640658855, + 0.034277670085430145, + 0.09565535932779312, + 0.18921032547950745, + 0.010441004298627377, + -0.07427560538053513, + -0.09049694985151291, + -0.00554919708520174, + 0.021386168897151947, + 0.0297325998544693, + 0.06431404501199722, + -0.07367311418056488, + -0.08734254539012909, + -0.059512097388505936, + 0.11382041126489639, + 0.19622667133808136, + 0.02534862980246544, + -0.09704668819904327, + -0.10857658833265305, + -0.10241919010877609, + -0.037928055971860886, + 0.17917697131633759, + -0.0396210141479969, + -0.472421795129776, + -0.5453466176986694, + -0.23921693861484528, + -0.06353127211332321, + 0.033679377287626266, + -0.011634309776127338, + -0.523267924785614, + -0.8400278091430664, + -0.3026646375656128, + 0.17986975610256195, + 0.20296970009803772, + 0.14190459251403809, + -0.12953802943229675, + -0.3968985378742218, + -0.13779792189598083, + 0.548722505569458, + 0.7039015293121338, + 0.4025704264640808, + 0.19535738229751587, + -0.08568660169839859, + -0.0589536651968956, + 0.1868993639945984, + 0.5782724618911743, + 0.43018248677253723, + 0.08876730501651764, + -0.10219226032495499, + -0.04660544916987419, + 0.018129168078303337, + 0.14359626173973083, + 0.3174169361591339, + 0.07668197154998779, + -0.13716676831245422, + -0.2058524489402771, + -0.023707473650574684, + 0.03213014453649521, + 0.06718969345092773, + 0.0917893499135971, + -0.10766899585723877, + -0.206499844789505, + -0.12713390588760376, + -0.03174767270684242, + 0.046395305544137955, + 0.018318502232432365, + -0.002416136907413602, + -0.027143845334649086, + -0.0036621293984353542, + -0.019220896065235138, + 0.05427055433392525, + 0.05058867856860161, + -0.05274957790970802, + -0.11321325600147247, + -0.07062514126300812, + -0.01720590703189373, + -0.00901520811021328, + 0.01746262051165104, + -0.08946436643600464, + -0.2304752618074417, + -0.1021895483136177, + 0.013501768000423908, + 0.029721295461058617, + -0.010094762779772282, + 0.009764805436134338, + -0.06424269080162048, + -0.03032868541777134, + 0.13044297695159912, + 0.12166891992092133, + 0.07157951593399048, + 0.029467372223734856, + -0.03827595338225365, + -0.031337328255176544, + -0.026486340910196304, + 0.05953369289636612, + 0.029497025534510612, + 0.022669093683362007, + -0.01055963709950447, + -0.025020133703947067, + 0.002589448355138302, + 0.017152298241853714, + 0.062067389488220215, + 0.008266719058156013, + 0.00563611788675189, + -0.0044869836419820786, + 0.003065212396904826, + 0.014371387660503387, + 0.013636622577905655, + 0.021183570846915245, + -0.012462744489312172, + -0.02493542619049549, + 0.009652925655245781, + -0.09309647232294083, + -0.09614148736000061, + 0.020278261974453926, + 0.262399286031723, + 0.0025974283926188946, + -0.09532646089792252, + -0.0391894206404686, + -0.003332971129566431, + -0.25919869542121887, + -0.2104814499616623, + 0.5975717306137085, + 0.20378711819648743, + -0.20521192252635956, + 0.005045099183917046, + 0.16707547008991241, + -0.08322134613990784, + -1.1734565496444702, + 0.4060916006565094, + 0.9109339714050293, + -0.22450445592403412, + -0.14085394144058228, + 0.19534644484519958, + 0.6220589280128479, + -1.0614460706710815, + -1.2444484233856201, + 1.1965712308883667, + 0.5032565593719482, + -0.26604175567626953, + -0.13583213090896606, + 0.6453277468681335, + 0.4994892477989197, + -1.7917202711105347, + -0.15182015299797058, + 0.7891079783439636, + 0.10711944103240967, + -0.11587982624769211, + 0.08287231624126434, + 0.7848142981529236, + -0.1764022707939148, + -1.0492321252822876, + 0.15281184017658234, + 0.3100045919418335, + -0.0461110882461071, + -0.06824400275945663, + 0.25544390082359314, + 0.3444065451622009, + -0.3189513683319092, + -0.3503313362598419, + 0.05462741479277611, + -0.041028521955013275, + 0.00624969182536006, + -0.0014677124563604593, + 0.10383514314889908, + -0.03467189520597458, + -0.03946290910243988, + 0.012734192423522472, + -0.003676857566460967, + -0.1616411954164505, + -0.034441810101270676, + 0.34758275747299194, + -0.0017601394793018699, + -0.17407774925231934, + 0.05167992413043976, + 0.12394318729639053, + -0.018228475004434586, + -0.71342533826828, + 0.39672648906707764, + 0.4870489537715912, + -0.27272745966911316, + -0.02687050960958004, + 0.09090551733970642, + 0.46698617935180664, + -0.6089348196983337, + -0.7488552331924438, + 0.8327828645706177, + 0.19947239756584167, + -0.17806877195835114, + -0.09197663515806198, + 0.3198661506175995, + 0.42619431018829346, + -1.1321229934692383, + -0.05452701821923256, + 0.4155597984790802, + -0.001295815804041922, + -0.06596186012029648, + -0.05821318179368973, + 0.4515152871608734, + 0.06321248412132263, + -0.6065720319747925, + 0.10882120579481125, + 0.13767170906066895, + 0.01809641905128956, + -0.070295050740242, + 0.04035783186554909, + 0.22459834814071655, + -0.048405971378088, + -0.14622822403907776, + -0.01119917817413807, + 0.00666345190256834, + 0.04815478250384331, + -0.017866114154458046, + -0.04813665896654129, + -0.02366034686565399, + 0.03589487820863724, + -0.0066519430838525295, + 0.0004148671869188547, + -0.014153627678751945, + 0.04403751716017723, + 0.04098428785800934, + -0.10525348782539368, + -0.0078808031976223, + 0.0444580540060997, + -0.027595041319727898, + 0.010916849598288536, + -0.1390431821346283, + 0.20334453880786896, + -0.006475532427430153, + -0.16053295135498047, + 0.06964287906885147, + -0.025649840012192726, + 0.12622858583927155, + -0.09694403409957886, + -0.09791161119937897, + 0.2617567479610443, + -0.06268735229969025, + -0.03128494322299957, + -0.017743078991770744, + -0.02372320368885994, + 0.2195650041103363, + -0.2456466406583786, + 0.031090563163161278, + 0.010196326300501823, + -0.04323133826255798, + 0.02746250294148922, + -0.079569011926651, + 0.06894756853580475, + 0.11414647102355957, + -0.12175147980451584, + 0.025397513061761856, + 0.006027852185070515, + 0.013360690325498581, + -0.024561991915106773, + -0.10966529697179794, + 0.04913714900612831, + 0.09801583737134933, + 0.00013951699656900018, + -0.03194398432970047, + 0.002382949460297823, + -0.003335593966767192, + 0.023621119558811188, + 0.024585755541920662, + -0.016027197241783142, + -0.02846739999949932, + -0.012949706055223942, + -0.020852699875831604, + -0.016913240775465965, + 0.016088848933577538, + 0.141468346118927, + 0.07285624742507935, + -0.008997173048555851, + -0.033306676894426346, + -0.03418722003698349, + -0.15127411484718323, + -0.047440435737371445, + 0.2687169015407562, + 0.17237843573093414, + 0.03505166247487068, + -0.06994523108005524, + -0.031143782660365105, + -0.3024960458278656, + -0.1552041918039322, + 0.33517369627952576, + 0.28441429138183594, + 0.06471730768680573, + -0.0613982267677784, + -0.02271229960024357, + -0.29379361867904663, + -0.3259792923927307, + 0.16062304377555847, + 0.29220375418663025, + 0.10862076282501221, + -0.005909152328968048, + 0.049116987735033035, + -0.20140305161476135, + -0.3278747797012329, + -0.02566053718328476, + 0.14338354766368866, + 0.006411381531506777, + -0.007274044211953878, + 0.08232597261667252, + -0.04198717698454857, + -0.17330540716648102, + -0.01131037063896656, + 0.08018575608730316, + -0.02374250255525112, + -0.002276432001963258, + 0.00019528658594936132, + -0.024716932326555252, + 0.026509074494242668, + 0.08361849933862686, + 0.012956380844116211, + -0.06030649319291115, + -0.020338360220193863, + -0.03577016666531563, + -0.06858085840940475, + 0.008245388977229595, + 0.25225168466567993, + 0.16135559976100922, + -0.03690743073821068, + -0.09188401699066162, + -0.10410526394844055, + -0.25971388816833496, + -0.07926154136657715, + 0.3933144509792328, + 0.33186599612236023, + 0.059405017644166946, + -0.11824909597635269, + -0.10528354346752167, + -0.4808295667171478, + -0.25224801898002625, + 0.4267246127128601, + 0.4853539764881134, + 0.16933484375476837, + -0.073345847427845, + -0.02648857608437538, + -0.4723232388496399, + -0.4904792010784149, + 0.1938265562057495, + 0.44070878624916077, + 0.22439399361610413, + 0.03877745941281319, + 0.08536087721586227, + -0.31432414054870605, + -0.5158097743988037, + -0.09537900239229202, + 0.20227058231830597, + 0.07895126938819885, + 0.059195615351200104, + 0.14728911221027374, + -0.059377528727054596, + -0.2884902060031891, + -0.12288203090429306, + 0.05220698565244675, + -0.045279599726200104, + 0.019795719534158707, + -0.009819806553423405, + -0.013713877648115158, + 0.0012175077572464943, + 0.03281072899699211, + 0.0017424041870981455, + -0.028847966343164444, + -0.0032059827353805304, + -0.020358575507998466, + 0.0009416870889253914, + -0.007760196924209595, + 0.07921157032251358, + 0.03826644644141197, + -0.02976907789707184, + -0.03300238028168678, + -0.017963968217372894, + -0.055836472660303116, + -0.03299689665436745, + 0.15166012942790985, + 0.06786434352397919, + 0.008589516393840313, + -0.05790036544203758, + -0.0029997669626027346, + -0.14070068299770355, + -0.08799122273921967, + 0.19680362939834595, + 0.14703704416751862, + 0.03569985553622246, + -0.02847554162144661, + 0.03601403906941414, + -0.1339161992073059, + -0.20527805387973785, + 0.1060374304652214, + 0.16269326210021973, + 0.0575268417596817, + 0.0029672966338694096, + 0.018848277628421783, + -0.1029881089925766, + -0.19446833431720734, + -0.055140964686870575, + 0.09632515162229538, + 0.01196608692407608, + 0.01994382217526436, + 0.0030014747753739357, + 0.0029817752074450254, + -0.09395840018987656, + -0.038611751049757004, + 0.03793984279036522, + -0.006295992527157068, + 0.01736803539097309, + -0.0961727425456047, + 0.1318971812725067, + 0.00169672432821244, + 0.02773740515112877, + -0.03737606480717659, + -0.02413480542600155, + -0.07371329516172409, + 0.04465596005320549, + 0.34972262382507324, + 0.269726425409317, + 0.14907677471637726, + -0.15323053300380707, + -0.24987848103046417, + -0.32931339740753174, + 0.05209995433688164, + 0.5192161798477173, + 0.5108750462532043, + 0.2627664804458618, + -0.26889729499816895, + -0.49891141057014465, + -0.5081418752670288, + 0.13535383343696594, + 0.7318623661994934, + 0.7116816639900208, + 0.2973657250404358, + -0.38982102274894714, + -0.7131763100624084, + -0.5916072130203247, + 0.1200462281703949, + 0.7752112746238708, + 0.6947993636131287, + 0.21100594103336334, + -0.5576100945472717, + -0.7797606587409973, + -0.6058254837989807, + 0.08617032319307327, + 0.6432424187660217, + 0.522933304309845, + 0.16018754243850708, + -0.5134027004241943, + -0.6838728189468384, + -0.5088241100311279, + 0.10101393610239029, + 0.4321025311946869, + 0.3330003023147583, + 0.10116448998451233, + -0.2786642014980316, + -0.4134466052055359, + -0.3247438967227936, + 0.009768294170498848, + 0.008712833747267723, + -0.029476309195160866, + 0.007709377445280552, + 0.025279967114329338, + 0.01615188643336296, + 0.01585867628455162, + -0.0031516810413450003, + -0.06462288647890091, + -0.055517926812171936, + -0.013180199079215527, + -0.014849795028567314, + 0.05535515025258064, + 0.04162544384598732, + 0.0022392054088413715, + -0.09408581256866455, + -0.07889631390571594, + -0.032870080322027206, + 0.0382377915084362, + 0.07495865970849991, + 0.08439645916223526, + 0.008036677725613117, + -0.1167779192328453, + -0.10782196372747421, + -0.06854722648859024, + 0.06310252100229263, + 0.09643208235502243, + 0.08629462122917175, + -0.016969647258520126, + -0.10456187278032303, + -0.10410942137241364, + -0.017384463921189308, + 0.03931420296430588, + 0.11296819150447845, + 0.08688211441040039, + -0.018024103716015816, + -0.0985492691397667, + -0.10534191876649857, + 0.016594627872109413, + 0.024613894522190094, + 0.09626104682683945, + 0.056779902428388596, + -0.01314453687518835, + -0.1173979789018631, + -0.07576211541891098, + -0.00741730397567153, + 0.04463285952806473, + 0.06365535408258438, + 0.029472019523382187, + 0.06097950413823128, + -0.0884813666343689, + -0.020469073206186295, + -0.004499382339417934, + 0.006147715728729963, + 0.0061135985888540745, + 0.046618249267339706, + -0.024977274239063263, + -0.2809607684612274, + -0.20776452124118805, + -0.10792756825685501, + 0.10520339012145996, + 0.2195160835981369, + 0.27846819162368774, + -0.0425783209502697, + -0.4539273977279663, + -0.4210258722305298, + -0.24160517752170563, + 0.2377386838197708, + 0.4254952371120453, + 0.40258923172950745, + -0.08894401043653488, + -0.6261403560638428, + -0.6177268624305725, + -0.2941279113292694, + 0.36115866899490356, + 0.6176164746284485, + 0.5170959234237671, + -0.12760992348194122, + -0.6392932534217834, + -0.6288641095161438, + -0.20397846400737762, + 0.4859760105609894, + 0.7283636927604675, + 0.5233575105667114, + -0.08038943260908127, + -0.513219952583313, + -0.4611802101135254, + -0.08622774481773376, + 0.41959214210510254, + 0.6145293116569519, + 0.4252074360847473, + -0.08993257582187653, + -0.3586794435977936, + -0.23889268934726715, + -0.07402873039245605, + 0.2362663745880127, + 0.33187127113342285, + 0.24442552030086517, + -0.10037989169359207, + -0.1200498715043068, + -0.06188809871673584, + 0.009648810140788555, + 0.07703708112239838, + -0.07734857499599457, + -0.16337357461452484, + -0.13160429894924164, + -0.037760209292173386, + 0.10750655829906464, + 0.21975228190422058, + 0.21332265436649323, + 0.1482381671667099, + -0.012174196541309357, + -0.03128019720315933, + 0.06983920931816101, + 0.2055918425321579, + 0.16611628234386444, + 0.20955723524093628, + 0.21407610177993774, + 0.13214662671089172, + 0.01558306161314249, + 0.20919384062290192, + 0.21453723311424255, + 0.10980720072984695, + 0.10323476791381836, + 0.1754676252603531, + 0.16320686042308807, + 0.076839879155159, + 0.2669583261013031, + 0.29500535130500793, + 0.18005967140197754, + 0.14900699257850647, + 0.2337430715560913, + 0.2607984244823456, + -0.08909865468740463, + 0.12383633106946945, + 0.27329200506210327, + 0.2634970247745514, + 0.2298160344362259, + 0.22673286497592926, + 0.1753624528646469, + -0.14258335530757904, + -0.033422429114580154, + 0.09338828176259995, + 0.21975602209568024, + 0.2488732784986496, + 0.21165378391742706, + 0.08514796197414398, + 0.0776415765285492, + -0.028732767328619957, + -0.0827818363904953, + -0.14784079790115356, + -0.06101813539862633, + -0.10570015013217926, + -0.07298385351896286, + -0.03352680057287216, + -0.08094660192728043, + -0.08546923100948334, + -0.025722583755850792, + -0.04828448221087456, + -0.15816760063171387, + -0.22295169532299042, + -0.04976325109601021, + -0.12255501747131348, + -0.04869991913437843, + 0.09818085283041, + 0.2285904735326767, + 0.015187943354249, + -0.19952231645584106, + -0.1415022611618042, + -0.09511925280094147, + 0.10828559100627899, + 0.35640013217926025, + 0.5399265289306641, + 0.3026861250400543, + -0.10532847791910172, + -0.0455780103802681, + -0.09365752339363098, + 0.2482689470052719, + 0.5483031272888184, + 0.6572608947753906, + 0.4098849594593048, + -0.0039499495178461075, + -0.11641024053096771, + -0.22666053473949432, + -0.03133581206202507, + 0.2815704643726349, + 0.3229265809059143, + 0.009749597869813442, + -0.19616934657096863, + -0.05046992748975754, + -0.15597671270370483, + -0.22775587439537048, + -0.14872166514396667, + -0.12174414098262787, + -0.23433859646320343, + -0.238412007689476, + 0.09725375473499298, + 0.08522887527942657, + 0.006490080617368221, + -0.024619178846478462, + 0.07278231531381607, + 0.13406167924404144, + 0.22993306815624237, + 0.10250072181224823, + 0.09119024127721786, + -0.07687287777662277, + -0.1012108325958252, + -0.09500063210725784, + -0.10082961618900299, + 0.09466016292572021, + 0.11299365013837814, + -0.033278487622737885, + -0.20269805192947388, + -0.21449527144432068, + -0.08820098638534546, + -0.18970704078674316, + -0.050536416471004486, + -0.03471578657627106, + -0.13205547630786896, + -0.18150201439857483, + -0.03963223099708557, + 0.13029472529888153, + -0.11594776809215546, + -0.173879474401474, + 0.017406627535820007, + -0.11885572224855423, + -0.06966021656990051, + 0.1687183529138565, + 0.2677668035030365, + -0.020446041598916054, + -0.11710261553525925, + 0.044354867190122604, + -0.10054060816764832, + -0.1287878155708313, + -0.03600803390145302, + -0.03198331966996193, + -0.22372953593730927, + -0.11045534163713455, + 0.22963544726371765, + 0.16736479103565216, + -0.023956498131155968, + -0.0882943719625473, + -0.11904646456241608, + -0.10481738299131393, + 0.083598293364048, + 0.058089643716812134, + -0.04821285232901573, + 0.16764044761657715, + -0.13788309693336487, + -0.1412951946258545, + 0.059633608907461166, + 0.012824267148971558, + -0.03141501545906067, + -0.017422236502170563, + 0.3908282518386841, + -0.31520241498947144, + -0.27876099944114685, + 0.17109407484531403, + 0.011913848109543324, + -0.04440265893936157, + 0.05610174685716629, + 0.5290316343307495, + -0.4506116211414337, + -0.2946499288082123, + 0.2802693545818329, + 0.04180249199271202, + -0.05673402547836304, + 0.0445592887699604, + 0.4933576285839081, + -0.4903600513935089, + -0.3259376883506775, + 0.26069584488868713, + 0.047843094915151596, + -0.053804315626621246, + 0.029928382486104965, + 0.3588394224643707, + -0.39090782403945923, + -0.18598265945911407, + 0.1703576147556305, + 0.010407418012619019, + 0.019840527325868607, + -0.017079327255487442, + 0.21012797951698303, + -0.1586841642856598, + -0.12738685309886932, + 0.12431345880031586, + 0.028149213641881943, + 0.05083676427602768, + -0.07053223252296448, + 0.12090320140123367, + -0.13737183809280396, + -0.09807822853326797, + 0.07203921675682068, + -0.01965559460222721, + 0.036479320377111435, + -0.02657422423362732, + 0.2924504280090332, + -0.19397024810314178, + -0.20908842980861664, + 0.07435549795627594, + 0.011985386721789837, + -0.051603686064481735, + 0.039122600108385086, + 0.5911946892738342, + -0.45937344431877136, + -0.43863579630851746, + 0.23180224001407623, + 0.05592876672744751, + -0.10227655619382858, + 0.1371937245130539, + 0.7193072438240051, + -0.6789532899856567, + -0.5275344252586365, + 0.4098500609397888, + 0.09136661887168884, + -0.08802130073308945, + 0.12226735055446625, + 0.6819202303886414, + -0.7316576838493347, + -0.5229181051254272, + 0.37578293681144714, + 0.09086397290229797, + -0.05128701403737068, + 0.09287497401237488, + 0.5103837251663208, + -0.6150248646736145, + -0.3208717107772827, + 0.29780012369155884, + 0.071808360517025, + 0.04605705663561821, + 0.028153980150818825, + 0.30872926115989685, + -0.32211968302726746, + -0.1925150454044342, + 0.18948692083358765, + 0.07391810417175293, + 0.08546463400125504, + -0.07042243331670761, + 0.14390304684638977, + -0.22509464621543884, + -0.12615789473056793, + 0.09681600332260132, + 0.0030679223127663136, + 0.06206878274679184, + -0.0493885837495327, + 0.11675205081701279, + -0.09476804733276367, + -0.0708041712641716, + 0.027848264202475548, + 0.018535451963543892, + 0.01112216804176569, + -0.023546719923615456, + 0.2808285057544708, + -0.2312571257352829, + -0.16320407390594482, + 0.15229304134845734, + -0.007220278959721327, + -0.026767488569021225, + -0.008487970568239689, + 0.39064091444015503, + -0.3746477961540222, + -0.22930599749088287, + 0.23297259211540222, + -0.020648201927542686, + -0.03918099403381348, + -0.03193120285868645, + 0.37857353687286377, + -0.38306936621665955, + -0.25103962421417236, + 0.2414209097623825, + 0.007709929719567299, + -0.041483473032712936, + -0.001570625347085297, + 0.315625935792923, + -0.276553213596344, + -0.13154125213623047, + 0.17517149448394775, + 0.03219839558005333, + 0.002647437620908022, + -0.012777225114405155, + 0.17064248025417328, + -0.13943275809288025, + -0.10204917937517166, + 0.09418098628520966, + 0.026260169222950935, + 0.05167905613780022, + -0.024634944275021553, + 0.0931941494345665, + -0.11875593662261963, + -0.0752263143658638, + 0.0569780170917511, + 0.00024334408226422966, + -0.001991289434954524, + -0.012094452045857906, + -0.0012201170902699232, + 0.01342268567532301, + 0.006425719242542982, + 0.01147665549069643, + -0.002208880614489317, + -0.019385183230042458, + -0.024868011474609375, + 0.00465290667489171, + 0.009205960668623447, + 0.0016242304118350148, + 0.0059639886021614075, + -0.03436571732163429, + 0.01672518253326416, + 0.008815832436084747, + 0.06389293074607849, + 0.06249547377228737, + 0.06542838364839554, + 0.043118152767419815, + 0.04117512330412865, + 0.014435848221182823, + 0.0065850247628986835, + 0.03811212629079819, + -0.006077034864574671, + -0.004025861620903015, + 0.006247953977435827, + 0.014478449709713459, + 0.0009701942908577621, + -0.002422194229438901, + 0.009390920400619507, + -0.052253514528274536, + -0.05192738026380539, + -0.010346310213208199, + -0.001328076352365315, + -0.002972622634842992, + 0.0015572139527648687, + 0.022503724321722984, + -0.002475353656336665, + 0.001927886507473886, + 0.02994818612933159, + 0.02062363363802433, + -0.0010653833160176873, + -0.005995174869894981, + 0.024450020864605904, + 0.013005194254219532, + 0.0496530681848526, + 0.029475165531039238, + 0.004157512914389372, + -0.0007043799851089716, + 0.01860312558710575, + 0.03839566186070442, + 0.00014980587002355605, + 0.018569663166999817, + 0.05668198689818382, + 0.04645680636167526, + 0.01642409712076187, + 0.03577466681599617, + 0.03575601801276207, + -0.03680748492479324, + -0.01865880750119686, + 0.041660092771053314, + 0.033268485218286514, + 0.03338993713259697, + 0.04665865749120712, + -0.03322917968034744, + -0.2860279381275177, + -0.28877392411231995, + -0.09617949277162552, + 0.014234350994229317, + 0.038012001663446426, + -0.016850680112838745, + -0.27252569794654846, + -0.6714493632316589, + -0.686245322227478, + -0.3376169502735138, + -0.0812990590929985, + 0.003058002796024084, + -0.026376569643616676, + -0.29216718673706055, + -0.6779875159263611, + -0.6917123198509216, + -0.3184400796890259, + -0.058261968195438385, + 0.06338769942522049, + 0.03199980780482292, + -0.09837217628955841, + -0.3355932831764221, + -0.30900436639785767, + -0.04878076910972595, + 0.061543505638837814, + 0.04651529714465141, + 0.0263908002525568, + 0.0030237447936087847, + -0.10458099842071533, + -0.07959774881601334, + 0.05430716276168823, + 0.056767694652080536, + 0.00796051137149334, + -0.016737859696149826, + -0.042338743805885315, + -0.0198048185557127, + -0.03085070475935936, + -0.058721307665109634, + -0.036032311618328094, + -0.0035414688754826784, + -8.359456842299551e-05, + -0.02213932015001774, + 0.02032857947051525, + 0.021788733080029488, + -0.03522418439388275, + -0.025317413732409477, + -0.042937491089105606, + -0.05680134892463684, + -0.012510996311903, + 0.226289302110672, + 0.24401520192623138, + 0.022300971671938896, + -0.030825607478618622, + -0.05485948920249939, + 0.007590078748762608, + 0.2208130657672882, + 0.6964298486709595, + 0.7457719445228577, + 0.3470557630062103, + 0.06941442936658859, + -0.03543366119265556, + 0.035853609442710876, + 0.2872598171234131, + 0.7504303455352783, + 0.7509996294975281, + 0.34327855706214905, + 0.024429334327578545, + -0.05711393058300018, + -0.034500252455472946, + 0.057939525693655014, + 0.33292675018310547, + 0.3141649067401886, + 0.033748809248209, + -0.062175147235393524, + -0.041224412620067596, + -0.01891348883509636, + -0.014519350603222847, + 0.08635713160037994, + 0.03148616850376129, + -0.08749162405729294, + -0.05658482387661934, + 0.00018510188965592533, + 0.002624311950057745, + -0.003570129396393895, + 0.0067627751268446445, + -0.01349653396755457, + -0.003961967770010233, + 0.0034001911990344524, + -0.00385954394005239, + 0.018012456595897675, + -0.018755480647087097, + -0.03163064643740654, + -0.0035233700182288885, + 0.011690095998346806, + -0.014693490229547024, + 0.017746854573488235, + 0.05693097040057182, + 0.1272590607404709, + 0.23477119207382202, + 0.19823509454727173, + 0.05071045830845833, + -0.007188393268734217, + -0.05571149289608002, + -0.06468938291072845, + -0.017831332981586456, + -0.07572834193706512, + -0.19599483907222748, + -0.15608063340187073, + -0.039450764656066895, + -0.035583946853876114, + -0.1605951488018036, + -0.5041624307632446, + -0.6836286783218384, + -0.3773191571235657, + -0.08623629808425903, + -0.04881078004837036, + 0.029403403401374817, + 0.15516817569732666, + 0.4108496308326721, + 0.6393839716911316, + 0.4688946008682251, + 0.2135964334011078, + 0.0623941570520401, + 0.02426956780254841, + -8.065254223765805e-05, + -0.00816427543759346, + -0.09353788942098618, + -0.06872912496328354, + -0.029405562207102776, + 0.012364620342850685, + 0.0060868943110108376, + 0.017015695571899414, + -0.0076495204120874405, + -0.006090708542615175, + -0.016521835699677467, + 0.009218892082571983, + 0.030833140015602112, + -0.0002345978282392025, + 0.03332215175032616, + 0.0030349211301654577, + 0.009600857272744179, + 0.05706647038459778, + 0.06095677986741066, + -0.016137542203068733, + 0.03195658698678017, + 0.13535599410533905, + 0.28229761123657227, + 0.4573267698287964, + 0.39102476835250854, + 0.17547546327114105, + 0.005337159149348736, + -0.07699840515851974, + -0.12667469680309296, + -0.16613735258579254, + -0.2908898890018463, + -0.44942277669906616, + -0.34229782223701477, + -0.16225378215312958, + -0.1100199744105339, + -0.4044281840324402, + -0.9058251976966858, + -1.1549302339553833, + -0.7502554059028625, + -0.2716369032859802, + -0.13495275378227234, + 0.08614412695169449, + 0.3164423108100891, + 0.7155097723007202, + 1.0356683731079102, + 0.7939887642860413, + 0.39567017555236816, + 0.16957539319992065, + 0.02675812318921089, + 0.048314403742551804, + 0.053107086569070816, + -0.009243623353540897, + -0.011442561633884907, + 0.004911235999315977, + 0.012210517190396786, + 0.006660772021859884, + -0.004562888294458389, + -0.009606098756194115, + -0.01610635593533516, + -0.03475078567862511, + 0.007796770427376032, + 0.02015513926744461, + 0.020311446860432625, + 0.009043446741998196, + -0.01929326355457306, + -0.04183953255414963, + -0.003052672604098916, + 0.020744286477565765, + 0.01371331699192524, + 0.004048139322549105, + 0.0692848190665245, + 0.16867054998874664, + 0.2799474000930786, + 0.28119951486587524, + 0.13579942286014557, + -0.0015732255997136235, + -0.05406518653035164, + -0.05831173434853554, + -0.034435681998729706, + -0.11925295740365982, + -0.2570647895336151, + -0.19120880961418152, + -0.09981344640254974, + -0.011702792719006538, + -0.22477947175502777, + -0.5395713448524475, + -0.7111374139785767, + -0.4207299053668976, + -0.11811137199401855, + -0.035199034959077835, + 0.024358956143260002, + 0.16262274980545044, + 0.46769100427627563, + 0.677872896194458, + 0.4637402892112732, + 0.15558630228042603, + 0.04467496648430824, + 0.03221412003040314, + 0.02430277317762375, + -0.006398700177669525, + -0.07235423475503922, + -0.03669704124331474, + -0.000992153538390994, + 0.02220241352915764, + -0.03329842537641525, + 0.05199713259935379, + -0.14053553342819214, + 0.1906905472278595, + -0.13544943928718567, + 0.08535720407962799, + -0.009813228622078896, + 0.03578176349401474, + -0.05863757058978081, + 0.33848440647125244, + -0.49837300181388855, + 0.15308170020580292, + 0.14865124225616455, + -0.12349266558885574, + -0.025796135887503624, + 0.17790427803993225, + -0.7813658714294434, + 0.853188693523407, + 0.2489670068025589, + -0.7378701567649841, + 0.2207188457250595, + 0.05207442864775658, + -0.4280349314212799, + 1.1408430337905884, + -0.24505679309368134, + -1.5490919351577759, + 1.4560288190841675, + -0.31143030524253845, + -0.03536878153681755, + 0.5640448331832886, + -0.6874421834945679, + -1.210310697555542, + 2.6637399196624756, + -1.6589887142181396, + 0.2221546173095703, + 0.10179737955331802, + -0.4354941248893738, + 0.034149203449487686, + 1.480568528175354, + -2.072199821472168, + 0.9205833673477173, + 0.021510563790798187, + -0.07755836099386215, + 0.17983688414096832, + 0.040537625551223755, + -0.5325585603713989, + 0.550999641418457, + -0.11060550063848495, + -0.09052976220846176, + -0.048361390829086304, + 0.03450514376163483, + -0.11854307353496552, + 0.23462797701358795, + -0.17563995718955994, + 0.0653814822435379, + -0.009748813696205616, + 0.07013920694589615, + -0.08628369867801666, + 0.3019683063030243, + -0.630340576171875, + 0.274477481842041, + 0.15417183935642242, + -0.036220982670784, + -0.07344137132167816, + 0.2339126616716385, + -1.0395091772079468, + 1.2002928256988525, + 0.085142120718956, + -0.7080597281455994, + 0.23101751506328583, + 0.016307154670357704, + -0.45877355337142944, + 1.617128849029541, + -0.6593433618545532, + -1.8957709074020386, + 1.746606469154358, + -0.37062564492225647, + 0.01213759370148182, + 0.5851964354515076, + -1.0307577848434448, + -1.4803766012191772, + 3.812014102935791, + -2.0028398036956787, + 0.12008816003799438, + 0.01813559979200363, + -0.5065457820892334, + 0.17598780989646912, + 2.0418734550476074, + -2.680522918701172, + 0.7466094493865967, + 0.16271913051605225, + -0.04379571974277496, + 0.21930621564388275, + 0.041255541145801544, + -0.6644601821899414, + 0.481300413608551, + 0.05410065874457359, + -0.09025495499372482, + 0.01954805478453636, + 0.01899997517466545, + -0.1337241530418396, + 0.19821906089782715, + -0.06395180523395538, + -0.03586877882480621, + 0.01973363384604454, + 0.013873124495148659, + -0.09288538247346878, + 0.4300728440284729, + -0.4235192537307739, + 0.03646458685398102, + 0.10077393800020218, + -0.07569073140621185, + -0.08176662772893906, + 0.3834531605243683, + -0.747482419013977, + 0.4493187367916107, + 0.2960513234138489, + -0.5245057344436646, + 0.27831950783729553, + 0.0731748417019844, + -0.45574328303337097, + 0.6987965703010559, + 0.019539732486009598, + -1.1160184144973755, + 1.0756875276565552, + -0.3804619312286377, + -0.040626902133226395, + 0.2780243456363678, + -0.32946258783340454, + -0.8122196793556213, + 1.9535348415374756, + -1.300661563873291, + 0.3443142771720886, + 0.04858396574854851, + -0.17409801483154297, + -0.07783844321966171, + 1.0875797271728516, + -1.5148566961288452, + 0.8014272451400757, + -0.19643208384513855, + -0.033590562641620636, + 0.11178025603294373, + 0.08284300565719604, + -0.5165408849716187, + 0.5841389894485474, + -0.24739950895309448, + 0.027926180511713028, + -0.028708497062325478, + 0.0037401756271719933, + -0.0047450135461986065, + 0.008427698165178299, + 0.009801353327929974, + -0.0029346586670726538, + -0.010193527676165104, + 0.014876358211040497, + 0.009861295111477375, + -0.005554665345698595, + -0.06270359456539154, + -0.0316256619989872, + 0.006706684362143278, + 0.04316525161266327, + 0.008637072518467903, + -0.03666357323527336, + -0.0719730481505394, + -0.1525861918926239, + -0.14396126568317413, + -0.05387119948863983, + 0.01955549605190754, + 0.007112634833902121, + -0.05175568535923958, + -0.16772602498531342, + -0.20807777345180511, + -0.18768996000289917, + -0.17093753814697266, + -0.03334345668554306, + 0.0011808606795966625, + -0.01579100452363491, + -0.12589050829410553, + -0.17219413816928864, + -0.19648219645023346, + -0.21980451047420502, + -0.04920821264386177, + 0.0012217299081385136, + 0.023885242640972137, + -0.056074876338243484, + -0.13907776772975922, + -0.19139252603054047, + -0.13652737438678741, + -0.0027339402586221695, + 0.004720518831163645, + -0.00037206560955382884, + 0.017924504354596138, + -0.02118082158267498, + -0.06553903222084045, + -0.0435921773314476, + 0.02721239998936653, + 0.020702000707387924, + 0.024033410474658012, + 0.005382229574024677, + -0.01273527555167675, + -0.01742861233651638, + 0.007402990944683552, + 0.010333286598324776, + 0.02598601020872593, + 0.012456837110221386, + -0.03471057116985321, + -0.10051856189966202, + -0.08084382116794586, + -0.023420603945851326, + 0.031205907464027405, + 0.00424322672188282, + -0.03734385594725609, + -0.1152661070227623, + -0.2012551724910736, + -0.1995576024055481, + -0.07972321659326553, + -0.011126434430480003, + -0.0185835100710392, + -0.06944561004638672, + -0.21481844782829285, + -0.26795628666877747, + -0.24916253983974457, + -0.17833945155143738, + -0.06658200174570084, + -0.00305415247566998, + -0.054028186947107315, + -0.19072681665420532, + -0.256619930267334, + -0.26868295669555664, + -0.21621295809745789, + -0.06564134359359741, + 0.0031192339956760406, + 0.013205861672759056, + -0.08044812828302383, + -0.18137820065021515, + -0.23007699847221375, + -0.13054916262626648, + -0.01135951280593872, + 0.013734308071434498, + 0.010981118306517601, + -0.02249351143836975, + -0.05804377421736717, + -0.10652261227369308, + -0.04163172468543053, + 0.017101088538765907, + -0.028687385842204094, + -0.0019976652693003416, + 0.009987232275307178, + 0.010130539536476135, + 0.0015575449215248227, + -0.000983694102615118, + -0.012845008634030819, + 0.01329281460493803, + 0.0029350779950618744, + -0.003755913581699133, + -0.036475058645009995, + -0.0245466697961092, + -0.0020879909861832857, + 0.025867130607366562, + -0.0065954397432506084, + 0.008656582795083523, + -0.04037104919552803, + -0.11718368530273438, + -0.13506115972995758, + -0.024255141615867615, + 0.014097613282501698, + -0.0009370348998345435, + -0.010953565128147602, + -0.12869219481945038, + -0.18789908289909363, + -0.19098156690597534, + -0.12795749306678772, + -0.002666366985067725, + -0.004907527007162571, + -0.014610078185796738, + -0.11913872510194778, + -0.19921070337295532, + -0.21869640052318573, + -0.1849898099899292, + -0.03470952808856964, + 0.0064156935550272465, + 0.03401843458414078, + -0.04000416398048401, + -0.12354391813278198, + -0.16908879578113556, + -0.10385500639677048, + 0.002833302365615964, + -0.036176733672618866, + -0.001048827893100679, + 0.010002595372498035, + -0.020798830315470695, + -0.0488261841237545, + -0.002972641494125128, + 0.016395021229982376, + -0.045770127326250076, + -0.12710650265216827, + -0.1637774109840393, + -0.1411965787410736, + 0.20447289943695068, + 0.509396493434906, + 0.07264503091573715, + 0.12041529268026352, + -0.015143441036343575, + -0.2673257887363434, + -0.3589763641357422, + 0.11289574205875397, + 0.8517020344734192, + 0.7068799138069153, + 0.067301444709301, + -0.02102830447256565, + -0.5235708355903625, + -1.2064802646636963, + -0.856619656085968, + 0.26774707436561584, + 0.6825867295265198, + 0.13516077399253845, + 0.3054035007953644, + -0.0727991834282875, + -1.4912222623825073, + -1.906838297843933, + -0.8574200868606567, + -0.15282419323921204, + 0.39327505230903625, + 0.9758505821228027, + 1.2323224544525146, + 0.18179064989089966, + -0.947610080242157, + -0.6657719016075134, + -0.19935055077075958, + -0.09150458872318268, + 0.34379544854164124, + 1.2025749683380127, + 0.9517407417297363, + -0.12023784220218658, + -0.3146151900291443, + -0.1049022302031517, + -0.34867578744888306, + -0.32945582270622253, + 0.28920575976371765, + 0.7844374179840088, + 0.35520124435424805, + 0.007452746387571096, + 0.018862545490264893, + -0.0021927610505372286, + 0.0321974977850914, + 0.05439181253314018, + -0.030729038640856743, + -0.03517322614789009, + -0.037830010056495667, + -0.056672073900699615, + -0.017769837751984596, + 0.06385952979326248, + 0.08161566406488419, + 0.07809178531169891, + 0.06333671510219574, + -0.036322008818387985, + -0.06432312726974487, + -0.03629852458834648, + 0.010879911482334137, + 0.088901087641716, + 0.0021402277052402496, + 0.09618857502937317, + 0.02661084569990635, + -0.03414442762732506, + -0.08736730366945267, + -0.048222169280052185, + 0.03507986292243004, + -0.053828027099370956, + 0.006044292356818914, + 0.04232194274663925, + 0.001624415279366076, + -0.028371643275022507, + -0.08724038302898407, + -0.005835397634655237, + 0.01057528518140316, + 0.04210871085524559, + 0.06106603890657425, + 0.04250370338559151, + 0.0028668276499956846, + -0.07583706080913544, + -0.06849333643913269, + -0.08538331836462021, + -0.021475542336702347, + 0.044341571629047394, + 0.03604369983077049, + 0.05146002024412155, + 0.00280605535954237, + -0.004615028854459524, + -0.07857430726289749, + -0.03716180846095085, + 0.010876243002712727, + -0.03418488800525665, + 0.007391764782369137, + 0.05969953536987305, + 0.08769611269235611, + 0.066011443734169, + -0.10404568910598755, + -0.27194535732269287, + -0.05224551260471344, + -0.03618992492556572, + -0.023098375648260117, + 0.13832588493824005, + 0.21510572731494904, + -0.07285867631435394, + -0.489085853099823, + -0.33285844326019287, + -0.04830349236726761, + 0.014211038127541542, + 0.2612524926662445, + 0.6911754608154297, + 0.5294638276100159, + -0.2706173360347748, + -0.39350029826164246, + -0.05156399682164192, + -0.16490484774112701, + 0.1161464974284172, + 0.8029336929321289, + 1.1809980869293213, + 0.5025736689567566, + 0.07084998488426208, + -0.1901131123304367, + -0.4918227195739746, + -0.603122889995575, + -0.09460704773664474, + 0.5786081552505493, + 0.35392242670059204, + 0.1328991800546646, + -0.008106965571641922, + -0.2159435749053955, + -0.6369062662124634, + -0.5241336822509766, + 0.06276796758174896, + 0.1139409989118576, + 0.05483332276344299, + 0.1703934520483017, + 0.14603517949581146, + -0.16187912225723267, + -0.4139055907726288, + -0.14918148517608643, + -0.06163417547941208, + 0.005302567034959793, + 0.015524876303970814, + -0.11895350366830826, + -0.19724233448505402, + 0.03412429615855217, + 0.10862118750810623, + 0.08550503104925156, + -0.008599682711064816, + -0.03031114675104618, + -0.33224624395370483, + -0.27994298934936523, + 0.196475550532341, + 0.31109708547592163, + 0.17151644825935364, + -0.04994147643446922, + -0.167176753282547, + -0.5247878432273865, + -0.21136601269245148, + 0.54701828956604, + 0.6110883951187134, + 0.04194486886262894, + -0.27640673518180847, + -0.0795169249176979, + -0.360530287027359, + 0.3472684621810913, + 1.5428175926208496, + 1.0249378681182861, + -0.2724844515323639, + -0.3013695478439331, + 0.020736562088131905, + -0.019495302811264992, + 0.7758124470710754, + 1.5381159782409668, + 0.028625331819057465, + -1.289720892906189, + -0.5894255638122559, + 0.0526396706700325, + 0.11443997919559479, + 0.5935031771659851, + 0.47169724106788635, + -1.2507063150405884, + -1.351940631866455, + -0.03894977271556854, + 0.05095001682639122, + 0.01581231690943241, + 0.11137383431196213, + -0.22327138483524323, + -0.9629225730895996, + -0.2607772946357727, + 0.5907121300697327, + 0.006906076334416866, + 0.002633580705150962, + 0.01940075121819973, + 0.0143396882340312, + 0.020781584084033966, + -0.07249777764081955, + -0.016355905681848526, + 0.016553230583667755, + -0.027528395876288414, + 0.0244428887963295, + 0.024910561740398407, + 0.027229825034737587, + -0.04104151204228401, + 0.007100561633706093, + 0.0157785601913929, + -0.06626633554697037, + 0.006520191207528114, + 0.021171070635318756, + 0.036674920469522476, + -0.06950324773788452, + -0.03003627620637417, + 2.178798422391992e-05, + -0.07278106361627579, + 0.014382920227944851, + 0.0982266515493393, + 0.1454961597919464, + -0.10096189379692078, + 0.022237209603190422, + -0.00040665315464138985, + -0.013766243122518063, + 0.06440296769142151, + 0.21751047670841217, + 0.02519127167761326, + -0.23383572697639465, + 0.0038903038948774338, + -0.042271602898836136, + -0.012596859596669674, + 0.023778460919857025, + 0.07685687392950058, + -0.21480663120746613, + -0.19205358624458313, + 0.04876565560698509, + -0.016765035688877106, + -0.02620583213865757, + 0.01641852967441082, + 0.02201787941157818, + -0.07457322627305984, + -0.003633625339716673, + 0.07550841569900513, + 0.024774253368377686, + 0.04710151255130768, + 0.09110233932733536, + -0.017366377636790276, + -0.04366954043507576, + -0.039786458015441895, + 0.005311290733516216, + 0.037867460399866104, + 0.05367766693234444, + 0.07434491813182831, + -0.07251215726137161, + -0.04231821000576019, + -0.023427855223417282, + 0.036294277757406235, + 0.07782749086618423, + 0.11835407465696335, + 0.08753973245620728, + -0.20742319524288177, + -0.13341759145259857, + -0.008225077763199806, + 0.07292432337999344, + 0.006392402108758688, + 0.021914338693022728, + -0.09218581020832062, + -0.44192466139793396, + -0.1744878888130188, + 0.014938815496861935, + 0.10678526759147644, + -0.012087192386388779, + -0.024533385410904884, + -0.1804407387971878, + -0.3253834545612335, + 0.040678758174180984, + 0.2011708915233612, + 0.17262929677963257, + -0.0045212251134216785, + -0.033313386142253876, + -0.10575363039970398, + -0.07636692374944687, + 0.20343273878097534, + 0.28330928087234497, + 0.043149981647729874, + -0.01109551265835762, + -0.0027725452091544867, + 0.003926735837012529, + 0.029440222308039665, + 0.23945140838623047, + 0.09122566133737564, + -0.15140119194984436, + 0.08737201988697052, + 0.07120998948812485, + 0.05722665786743164, + -0.04388495534658432, + 0.02116825245320797, + 0.023315919563174248, + 0.10898162424564362, + 0.11808467656373978, + 0.03412344306707382, + 0.002771642990410328, + -0.1959579437971115, + -0.05181330814957619, + -0.0044630044139921665, + 0.12481725960969925, + 0.09140311926603317, + 0.03444851189851761, + -0.10931172221899033, + -0.3204459846019745, + -0.21193139255046844, + -0.11101037263870239, + 0.04186606407165527, + -0.07420916110277176, + -0.2004990428686142, + -0.26937955617904663, + -0.12928874790668488, + 0.20819628238677979, + -0.17379426956176758, + -0.2181481271982193, + 0.005387924611568451, + -0.24132733047008514, + -0.23942433297634125, + 0.41489261388778687, + 1.0702778100967407, + 0.024913936853408813, + -0.28405970335006714, + 0.083008773624897, + -0.11059781163930893, + -0.17623695731163025, + -0.17386195063591003, + 0.010644182562828064, + -0.32716259360313416, + -0.2135595828294754, + 0.1223129853606224, + 0.07060510665178299, + -0.048680394887924194, + -0.3332099914550781, + -0.25886017084121704, + -0.18619979918003082, + -0.00733158877119422, + 0.03393476828932762, + -0.010564662516117096, + -0.01817108877003193, + -0.05650597810745239, + -0.01891104131937027, + -0.0554141066968441, + -0.004592927638441324, + -0.0013615720672532916, + -0.05552899092435837, + -0.0560498908162117, + -0.1080632209777832, + -0.013965745456516743, + -0.03290533646941185, + -0.02599845454096794, + -0.02877708151936531, + -0.05670137703418732, + -0.07158109545707703, + -0.08808472007513046, + -0.03919175639748573, + -0.08478893339633942, + -0.08045543730258942, + -0.10066724568605423, + -0.048338882625103, + -0.06750114262104034, + 0.08164039999246597, + 0.3343777060508728, + 0.004952755756676197, + -0.14891156554222107, + 0.032855477184057236, + -0.03277512267231941, + 0.0474768728017807, + 0.6316664814949036, + 1.2214386463165283, + 0.2548498213291168, + -0.13185030221939087, + -0.018188906833529472, + -0.07653989642858505, + -0.01643386110663414, + 0.06630122661590576, + 0.23864209651947021, + -0.013703612610697746, + -0.09347789734601974, + -0.0900193303823471, + -0.04930814355611801, + -0.02791711315512657, + -0.15441712737083435, + -0.01623091846704483, + -0.0447690524160862, + -0.06071227043867111, + -0.04737209901213646, + -0.059769801795482635, + -0.04375007003545761, + -0.00650476710870862, + 0.021540174260735512, + -0.05590728670358658, + -0.13030850887298584, + -0.022067781537771225, + -0.05066747963428497, + 0.00609770929440856, + 0.108611099421978, + 0.1621929407119751, + 0.05232185125350952, + -0.049729123711586, + -0.11906369775533676, + -0.030973592773079872, + 0.057787079364061356, + 0.1610448956489563, + 0.18756121397018433, + 0.07277501374483109, + -0.05777435004711151, + -0.05227195844054222, + 0.14434091746807098, + 0.1889694482088089, + 0.26951169967651367, + 0.4710105359554291, + 0.2164669781923294, + 0.05052375793457031, + -0.0038236663676798344, + 0.20267778635025024, + 0.31214746832847595, + 0.7506387829780579, + 1.2302387952804565, + 0.4363090693950653, + 0.16759593784809113, + -0.049752235412597656, + 0.044786907732486725, + 0.14537742733955383, + 0.2227499932050705, + 0.37362414598464966, + 0.16590620577335358, + 0.0864599421620369, + -0.14058542251586914, + -0.04404178634285927, + -0.0325944609940052, + -0.019113417714834213, + 0.17414243519306183, + 0.11160623282194138, + -0.034911543130874634, + 0.1523953527212143, + 0.04554234445095062, + -0.054958827793598175, + -0.11794494092464447, + -0.19570015370845795, + -0.21358126401901245, + -0.1885669231414795, + -0.08286706358194351, + -0.29818814992904663, + -0.52330082654953, + -0.6190353631973267, + -0.682529091835022, + -0.6171367764472961, + -0.4793100655078888, + -0.11180876195430756, + -0.3490432798862457, + -0.5531057715415955, + -0.6426181793212891, + -0.6420838832855225, + -0.4970071613788605, + -0.27038174867630005, + -0.09740017354488373, + -0.1929621547460556, + -0.30848363041877747, + -0.27204805612564087, + -0.2515120208263397, + -0.07497832179069519, + 0.03551386669278145, + -0.05060403421521187, + 0.08276989310979843, + 0.14321963489055634, + 0.3583574593067169, + 0.40667927265167236, + 0.39398193359375, + 0.27561235427856445, + 0.005085935816168785, + 0.2793635427951813, + 0.48155927658081055, + 0.7088037729263306, + 0.7394692897796631, + 0.6158861517906189, + 0.3986552655696869, + 0.025508087128400803, + 0.38533228635787964, + 0.5305332541465759, + 0.6659612059593201, + 0.6396889090538025, + 0.5396444797515869, + 0.39010515809059143, + -0.03072960674762726, + 0.014305810444056988, + 0.029885446652770042, + 0.038084372878074646, + 0.012448564171791077, + 0.034353457391262054, + 0.048626724630594254, + 0.048866890370845795, + 0.07561437785625458, + 0.09152165800333023, + 0.08432324975728989, + 0.09332144260406494, + 0.07517607510089874, + 0.049146559089422226, + 0.03146318346261978, + 0.06335246562957764, + 0.06438779830932617, + 0.06851581484079361, + 0.09263566881418228, + 0.06460423022508621, + 0.011992924846708775, + 0.03396693989634514, + 0.04433950409293175, + 0.04642309248447418, + 0.0022602551616728306, + -0.0361824594438076, + -0.0005105047021061182, + 0.030808264389634132, + 0.0022333709057420492, + -0.017826544120907784, + -0.03796307370066643, + -0.012887164019048214, + -0.028499294072389603, + -0.03367336839437485, + -0.03668365254998207, + -0.02807682938873768, + -0.07444571703672409, + -0.081318199634552, + -0.09610070288181305, + -0.05368436127901077, + -0.09006591141223907, + -0.10038736462593079, + -0.04115951433777809, + -0.056811004877090454, + -0.09935522079467773, + -0.11107856035232544, + -0.07852742075920105, + -0.0942930206656456, + -0.07625897973775864, + -0.12966541945934296, + -0.038938648998737335, + 0.04580259323120117, + 0.10179819911718369, + 0.17127273976802826, + 0.17857632040977478, + 0.13426578044891357, + 0.04687841981649399, + 0.2424812912940979, + 0.42633309960365295, + 0.5291624069213867, + 0.6012980937957764, + 0.5449428558349609, + 0.3945220708847046, + 0.07037744671106339, + 0.26918724179267883, + 0.44614800810813904, + 0.5331310629844666, + 0.568580687046051, + 0.43367546796798706, + 0.25516101717948914, + 0.08428427577018738, + 0.177769735455513, + 0.24885930120944977, + 0.2178547978401184, + 0.13834305107593536, + 0.07452446967363358, + 0.005187708884477615, + 0.050621017813682556, + -0.08428733795881271, + -0.15576106309890747, + -0.25531095266342163, + -0.34646397829055786, + -0.3276817202568054, + -0.24377694725990295, + 0.02817704901099205, + -0.2531633675098419, + -0.3907041549682617, + -0.5944734811782837, + -0.6062930822372437, + -0.5171639919281006, + -0.3501560389995575, + -0.019397703930735588, + -0.2758809030056, + -0.4118667244911194, + -0.5375933051109314, + -0.5525977611541748, + -0.44681206345558167, + -0.2748269736766815, + -0.04229651764035225, + -0.005005967803299427, + -0.011332424357533455, + 0.011387092061340809, + -0.015463154762983322, + -0.012038768269121647, + 0.011360889300704002, + 0.03551746904850006, + 0.05123865604400635, + 0.020377267152071, + 0.1065637394785881, + 0.18875306844711304, + 0.18516196310520172, + 0.12519532442092896, + -0.042940977960824966, + -0.03246130794286728, + -0.016645772382616997, + 0.07807288318872452, + -0.7815885543823242, + -0.5930942296981812, + 0.03312799707055092, + -0.04537777230143547, + -0.022234303876757622, + 0.009241255931556225, + 0.16947965323925018, + -0.0700032040476799, + -0.06346366554498672, + 0.09555318206548691, + 0.02858082763850689, + 0.009246457368135452, + 0.03902693837881088, + 0.007071994710713625, + 0.10085106641054153, + 0.0881502702832222, + 0.011019160971045494, + 0.006030070595443249, + -0.012882355600595474, + -0.01701420359313488, + 0.022596944123506546, + -0.05345382168889046, + 0.02355102449655533, + -0.0091088330373168, + 0.00015542628534603864, + -0.0004997836658731103, + -0.006951311603188515, + 0.01267238613218069, + -0.0033983420580625534, + -0.0030770134180784225, + 0.02975126914680004, + 0.010702245868742466, + -0.016947058960795403, + 0.007774800062179565, + 0.09566964209079742, + 0.07426714897155762, + 0.1621979922056198, + 0.12728945910930634, + 0.06112523376941681, + 0.06061968579888344, + 0.07934501022100449, + 0.11534841358661652, + 0.10001469403505325, + 0.15475066006183624, + 0.1828109323978424, + 0.02134544588625431, + -0.015320047736167908, + 0.012000483460724354, + -0.014393450692296028, + -1.5520576238632202, + -1.2115217447280884, + 0.017239907756447792, + -0.007013735361397266, + 0.0019166347337886691, + 0.025112343952059746, + 0.1803419440984726, + -0.30807924270629883, + -0.33957329392433167, + 0.10846519470214844, + 0.06151076406240463, + 0.054799750447273254, + 0.06235412135720253, + 0.09605015069246292, + 0.16495031118392944, + 0.12624189257621765, + 0.12234552949666977, + 0.006969878450036049, + 0.0033541936427354813, + 0.008165130391716957, + 0.035377491265535355, + -0.03170061111450195, + 0.019396571442484856, + -0.011411413550376892, + 0.019043665379285812, + 0.00957057997584343, + 0.0055394587107002735, + 0.05569477006793022, + 0.0076510305516421795, + 0.018707536160945892, + 0.06073765829205513, + 0.006503407843410969, + -0.0058801183477044106, + -0.03229741007089615, + 0.0386439748108387, + 0.03167358413338661, + 0.027749545872211456, + -0.04634377732872963, + -0.00019781991431955248, + 0.024982664734125137, + 0.009453915059566498, + 0.1091528981924057, + 0.21055325865745544, + 0.23810525238513947, + 0.13829846680164337, + -0.019112061709165573, + -0.0014926757430657744, + 0.01856786385178566, + 0.10649964213371277, + -0.8599057793617249, + -0.6383436322212219, + 0.10839059948921204, + -0.038730181753635406, + -0.030203847214579582, + -0.033147793263196945, + 0.18132103979587555, + -0.1427767276763916, + -0.11132896691560745, + 0.10957232862710953, + -0.00349965482018888, + 0.03486581891775131, + 0.016247740015387535, + 0.060106489807367325, + 0.1439678966999054, + 0.07201634347438812, + 0.07603273540735245, + -0.0072280303575098515, + 0.01600506529211998, + -0.012912745587527752, + 0.015192546881735325, + -0.034853674471378326, + 0.026164958253502846, + 0.001483929343521595, + 0.0508253313601017, + -0.010546445846557617, + -0.024398569017648697, + -0.0043407524935901165, + 0.0030393539927899837, + -0.009643012657761574, + -0.008882591500878334, + 0.01182172168046236, + 0.003359999740496278, + -0.01145304087549448, + -7.34154018573463e-05, + 0.007416137028485537, + -0.012022661976516247, + 0.013550116680562496, + -0.005982181057333946, + -0.019205773249268532, + -0.0811527743935585, + -0.06323252618312836, + -0.026379290968179703, + -0.04671972244977951, + -0.006205265875905752, + 0.05242094770073891, + 0.05065605416893959, + 0.01961991749703884, + 0.021542323753237724, + 0.04147094115614891, + 0.04451332613825798, + 0.05155060812830925, + 0.15659169852733612, + 0.4448348879814148, + 0.7207449078559875, + 0.8680058717727661, + 0.7269517779350281, + 0.36259666085243225, + 0.10394725203514099, + -0.20449180901050568, + -0.42664405703544617, + -0.7290332317352295, + -0.9376083016395569, + -0.735107958316803, + -0.3541502356529236, + -0.23789332807064056, + -0.10901623964309692, + -0.26809337735176086, + -0.38465574383735657, + -0.44440212845802307, + -0.4070444703102112, + -0.22405119240283966, + -0.14190013706684113, + 0.07151509076356888, + 0.21848519146442413, + 0.41893038153648376, + 0.4783499836921692, + 0.4281534254550934, + 0.28631147742271423, + 0.057699400931596756, + 0.0029010034631937742, + -0.02580493874847889, + -0.02152368798851967, + -0.025850815698504448, + 0.004789783153682947, + 0.021941278129816055, + 0.00574735039845109, + -0.004016151186078787, + -0.014377521350979805, + -0.0828985944390297, + -0.06380187720060349, + -0.048879947513341904, + -0.04580164700746536, + -0.030843649059534073, + 0.024663949385285378, + 0.03409295156598091, + 0.060452476143836975, + 0.037006158381700516, + 0.058853648602962494, + 0.07275765389204025, + 0.02882941998541355, + 0.14549848437309265, + 0.4268765151500702, + 0.7150183320045471, + 0.8942612409591675, + 0.7532845139503479, + 0.3846176564693451, + 0.15604183077812195, + -0.19108416140079498, + -0.42633384466171265, + -0.7508237361907959, + -0.9448286890983582, + -0.719300389289856, + -0.3583783805370331, + -0.2060524821281433, + -0.10382426530122757, + -0.2624296545982361, + -0.4049411416053772, + -0.4338999092578888, + -0.41390693187713623, + -0.22797809541225433, + -0.14593803882598877, + 0.08197329193353653, + 0.2430788278579712, + 0.3906225562095642, + 0.47147202491760254, + 0.42429792881011963, + 0.29326340556144714, + 0.06683206558227539, + 0.004355552606284618, + -0.007973028346896172, + 0.0035172239877283573, + -0.0018502225866541266, + -0.015291260555386543, + 0.0025160792283713818, + 0.0015979957534000278, + 0.011951611377298832, + -0.0004334237310104072, + -0.00172338483389467, + 0.017284434288740158, + -0.00445173867046833, + -0.004828867502510548, + 0.004030159674584866, + 0.03321678191423416, + -0.016998661682009697, + -0.029765218496322632, + -0.07912255078554153, + -0.0494595468044281, + 0.012136446312069893, + 0.029541414231061935, + -0.01129366084933281, + 0.09502168744802475, + 0.21533286571502686, + 0.3453419804573059, + 0.22987395524978638, + 0.04720258712768555, + 0.0032486498821526766, + -0.0042808204889297485, + -0.10162857174873352, + -0.21601493656635284, + -0.3040534257888794, + -0.19600912928581238, + -0.0568307563662529, + -0.0062937624752521515, + -0.021828925237059593, + -0.03831009939312935, + -0.08992031216621399, + -0.08103442937135696, + -0.07600760459899902, + -0.02319694682955742, + -0.008472982794046402, + -0.004151565954089165, + 0.05002164468169212, + 0.0985124409198761, + 0.11273156106472015, + 0.10279814153909683, + 0.032678257673978806, + -0.023295480757951736, + -0.022312145680189133, + 0.032877422869205475, + 0.08301658928394318, + -0.049675002694129944, + -0.05956050381064415, + 0.006878976244479418, + 0.011597251519560814, + -0.03617611899971962, + -0.005020621232688427, + 0.0066283573396503925, + 0.061849869787693024, + 0.0668889507651329, + -0.1120104044675827, + 0.0215831957757473, + -0.008177083916962147, + 0.019240612164139748, + -0.03794482350349426, + -0.21581093966960907, + 0.3248063623905182, + 0.0525924488902092, + -0.13873063027858734, + -0.030904211103916168, + -0.004122832324355841, + 0.2784009277820587, + -0.42068102955818176, + -0.15351417660713196, + 0.4266241192817688, + -0.10780557245016098, + 0.03840374946594238, + -0.15116721391677856, + 0.2292502224445343, + 0.23400554060935974, + -0.5023872256278992, + 0.14868289232254028, + 0.09809935092926025, + 0.03480924293398857, + -0.046804867684841156, + -0.14212554693222046, + 0.3073779344558716, + -0.029529480263590813, + -0.13998086750507355, + -0.02750661037862301, + 0.010526027530431747, + 0.032874979078769684, + -0.07645174115896225, + -0.02746269293129444, + 0.10902399569749832, + -0.00446560001000762, + -0.01339190173894167, + 0.003540819976478815, + -0.04410126060247421, + -0.10884726047515869, + 0.016081949695944786, + 0.15211890637874603, + 0.04027504846453667, + -0.05552368983626366, + 0.04718002676963806, + 0.014503135345876217, + -0.2764658033847809, + -0.16068166494369507, + 0.3356778621673584, + 0.06485499441623688, + -0.07164154946804047, + 0.084479421377182, + 0.2702949047088623, + -0.1339409202337265, + -0.9642015695571899, + 0.47433769702911377, + 0.4715694189071655, + -0.17669782042503357, + -0.04434441775083542, + 0.2641690671443939, + 0.7357130646705627, + -1.2222046852111816, + -0.8205837607383728, + 0.9091072678565979, + 0.14896778762340546, + -0.09332367032766342, + -0.16173647344112396, + 0.8782246708869934, + 0.3819980323314667, + -1.619883418083191, + 0.059255462139844894, + 0.42745286226272583, + -0.03186821565032005, + -0.16420172154903412, + 0.12124066799879074, + 0.8650834560394287, + -0.3728218674659729, + -0.5816569328308105, + 0.10949260741472244, + -0.010671291500329971, + -0.07903271913528442, + -0.09700250625610352, + 0.3192030191421509, + 0.2756008505821228, + -0.2616698145866394, + -0.11051242798566818, + 0.016789941117167473, + -0.0484573096036911, + -0.12333080172538757, + 0.0158428642898798, + 0.11172449588775635, + 0.014953864738345146, + -0.011746960692107677, + 0.05310823395848274, + 0.030244171619415283, + -0.23969320952892303, + -0.1039247065782547, + 0.285805881023407, + -0.04652552306652069, + -0.05380000174045563, + 0.05430186912417412, + 0.25547218322753906, + -0.06164371967315674, + -0.7386756539344788, + 0.4393811821937561, + 0.2623714804649353, + -0.1849273294210434, + -0.049713607877492905, + 0.1656467467546463, + 0.6638666391372681, + -0.899787187576294, + -0.5747878551483154, + 0.7465870976448059, + -0.025567445904016495, + -0.051771312952041626, + -0.19754628837108612, + 0.6828271746635437, + 0.4451557695865631, + -1.2559787034988403, + 0.07448688894510269, + 0.27905938029289246, + 0.003908769693225622, + -0.18454433977603912, + -0.011183545924723148, + 0.7449039816856384, + -0.228777676820755, + -0.47592073678970337, + 0.13784541189670563, + 0.019371675327420235, + -0.06424596160650253, + -0.1660400629043579, + 0.2080633044242859, + 0.2942465841770172, + -0.20263032615184784, + -0.0709841251373291, + -0.0021153483539819717, + -0.028180474415421486, + -0.021557176485657692, + 0.012511649169027805, + 0.06533018499612808, + 0.006560645066201687, + -0.01908997632563114, + -0.020228691399097443, + 0.10450740903615952, + 0.04476405307650566, + -0.20389842987060547, + -0.36356496810913086, + -0.18690945208072662, + 0.06581642478704453, + 0.005246834829449654, + -0.14777734875679016, + 0.04554577171802521, + 0.7314760088920593, + 1.1759854555130005, + 0.7747871279716492, + 0.08771117031574249, + 0.04425497353076935, + 0.14875195920467377, + -0.05036012455821037, + -1.0561891794204712, + -1.7835016250610352, + -1.313464879989624, + -0.4041728973388672, + -0.08825081586837769, + -0.18483860790729523, + -0.09619659930467606, + 0.6506555676460266, + 1.2331949472427368, + 1.057729721069336, + 0.3030258119106293, + 0.053314659744501114, + 0.10696353763341904, + 0.19720971584320068, + -0.19457301497459412, + -0.3546113669872284, + -0.3773464560508728, + 0.007737448439002037, + 0.007112926337867975, + -0.026632368564605713, + -0.07708505541086197, + 0.016982559114694595, + 0.03331448882818222, + 0.03235285356640816, + -0.04479134455323219, + 0.0062864539213478565, + -0.04983896017074585, + -0.014209658838808537, + 0.025105496868491173, + 0.07187403738498688, + -0.019782420247793198, + -0.0387532040476799, + 0.01098113413900137, + 0.10765481740236282, + -0.005502769257873297, + -0.29967597126960754, + -0.5370010733604431, + -0.25729984045028687, + 0.0341138020157814, + -0.01927473582327366, + -0.11736954003572464, + 0.09457080066204071, + 0.8881804943084717, + 1.5049697160720825, + 1.0347492694854736, + 0.22410355508327484, + -0.004720119293779135, + 0.1449226438999176, + -0.11916695535182953, + -1.2009364366531372, + -2.080855369567871, + -1.5549882650375366, + -0.5231477618217468, + -0.005029830615967512, + -0.11258674412965775, + 0.03710457682609558, + 0.9192798137664795, + 1.525830626487732, + 1.3018689155578613, + 0.44408130645751953, + 0.006972550880163908, + 0.07937697321176529, + 0.060622286051511765, + -0.4068094491958618, + -0.5964561104774475, + -0.6058750152587891, + -0.1743212193250656, + -0.0038881103973835707, + -0.04932431876659393, + -0.04989266395568848, + 0.07228495925664902, + 0.10359980911016464, + 0.11054171621799469, + 0.017031395807862282, + -0.012849675491452217, + -0.02224516123533249, + -0.019851619377732277, + 0.04567919671535492, + 0.12134519219398499, + 0.018673665821552277, + -0.03933878242969513, + 0.03506385162472725, + 0.07499910145998001, + -0.004981306381523609, + -0.269795298576355, + -0.4478399455547333, + -0.3141564130783081, + 0.014856644906103611, + -0.01102763693779707, + -0.11778493225574493, + -0.00048367868294008076, + 0.46917271614074707, + 0.8380635976791382, + 0.5829758048057556, + 0.14924737811088562, + 0.00504975114017725, + 0.1242799386382103, + 0.027800291776657104, + -0.5343790054321289, + -0.9185061454772949, + -0.6974499225616455, + -0.1733488291501999, + 0.028415951877832413, + -0.07513032108545303, + 0.010947657749056816, + 0.5501428246498108, + 0.8556726574897766, + 0.6854383945465088, + 0.21023745834827423, + -0.04757346957921982, + 0.028925150632858276, + -0.05005616322159767, + -0.4106282889842987, + -0.5990055203437805, + -0.5274976491928101, + -0.18928098678588867, + 0.007199999876320362, + 0.004744168370962143, + -0.006203897297382355, + 0.16117095947265625, + 0.20310591161251068, + 0.17358633875846863, + 0.057794276624917984, + 0.0018837900133803487, + -0.021730661392211914, + 0.03705505281686783, + 0.048999205231666565, + 0.017187459394335747, + -0.04760497808456421, + -0.06534644961357117, + 0.027641354128718376, + -0.02722003310918808, + -0.09557735174894333, + 0.2721945643424988, + 0.06861108541488647, + -0.17862513661384583, + 0.029542427510023117, + -0.028343068435788155, + -0.24357359111309052, + 0.2928915321826935, + 0.6317090392112732, + -0.5675624012947083, + -0.31298428773880005, + 0.119928739964962, + -0.04503166303038597, + 0.1997436285018921, + 0.9068917632102966, + -0.6105388402938843, + -1.176649808883667, + 0.391012579202652, + 0.21436090767383575, + 0.06404570490121841, + 0.4306352436542511, + -0.18372972309589386, + -1.6093186140060425, + 0.5129231810569763, + 0.8333584666252136, + -0.11607109010219574, + 0.024050598964095116, + -0.027272621169686317, + -0.8072280883789062, + 0.15613007545471191, + 1.0115277767181396, + -0.1886059194803238, + -0.1662863790988922, + -0.07484262436628342, + -0.11359186470508575, + -0.05765556916594505, + 0.48085057735443115, + 0.031143836677074432, + -0.20803743600845337, + 0.005643316078931093, + -0.011422591283917427, + -0.02063453011214733, + 0.010139239020645618, + 0.026931140571832657, + 0.02650240994989872, + 0.014503400772809982, + -0.030498046427965164, + 0.01038119662553072, + -0.041832923889160156, + -0.11747029423713684, + 0.24838468432426453, + 0.08126607537269592, + -0.17684465646743774, + 0.009867151267826557, + -0.04349489137530327, + -0.22892898321151733, + 0.3097872734069824, + 0.6229272484779358, + -0.5710748434066772, + -0.2540203332901001, + 0.15970031917095184, + -0.05765099450945854, + 0.24631772935390472, + 0.9121918678283691, + -0.6539115309715271, + -1.1680796146392822, + 0.43742635846138, + 0.1981748640537262, + 0.060766786336898804, + 0.48115089535713196, + -0.2704729437828064, + -1.668082594871521, + 0.6258481740951538, + 0.8217618465423584, + -0.17844447493553162, + 0.07583325356245041, + -0.031355466693639755, + -0.884739100933075, + 0.21298757195472717, + 1.0279508829116821, + -0.2118954360485077, + -0.16616611182689667, + -0.025157395750284195, + -0.11329160630702972, + -0.08147483319044113, + 0.46636614203453064, + 0.023730026558041573, + -0.21343427896499634, + -0.015201984904706478, + -0.00498165050521493, + 0.022955382242798805, + 0.020228328183293343, + -0.029405873268842697, + -0.032065436244010925, + 0.047389160841703415, + -0.01793060638010502, + 0.01669210195541382, + 0.05227159336209297, + -0.11703876405954361, + 0.006789325270801783, + 0.03741219639778137, + -0.04651298373937607, + -0.012846981175243855, + 0.024231625720858574, + -0.13399703800678253, + -0.024073680862784386, + 0.2970501184463501, + -0.1497301310300827, + -0.04287628084421158, + 0.08405227214097977, + -0.06020639091730118, + -0.01648692972958088, + 0.4150170087814331, + -0.17000712454319, + -0.43461430072784424, + 0.27202337980270386, + 0.006708468310534954, + -0.04474359005689621, + 0.15199843049049377, + -0.03348325565457344, + -0.6591396331787109, + 0.4057810306549072, + 0.25226324796676636, + -0.16070741415023804, + 0.03464199975132942, + 0.023064177483320236, + -0.35642316937446594, + 0.22774185240268707, + 0.37138837575912476, + -0.24171461164951324, + -0.023513946682214737, + 0.028774995356798172, + -0.02702418342232704, + -0.012504744343459606, + 0.17893734574317932, + -0.1554262489080429, + -0.09501983970403671, + 0.06177212670445442, + -0.013536165468394756, + 0.012441401369869709, + 0.006566522642970085, + -0.018207622691988945, + 0.003373368876054883, + -0.034891802817583084, + 0.002223123563453555, + 0.006169564090669155, + 0.022658145055174828, + -0.005327044054865837, + -0.023764559999108315, + -0.004386506043374538, + -0.02777106687426567, + 0.01950058527290821, + 0.004401096608489752, + 0.02882237359881401, + 0.01790205016732216, + -0.007827110588550568, + -0.005222277250140905, + -0.05361752584576607, + 0.008359426632523537, + -0.026494475081562996, + -0.015572195872664452, + -0.04412947595119476, + -0.006163781508803368, + 0.180303692817688, + 0.17117105424404144, + -0.014117442071437836, + 0.014543564058840275, + 0.03875281661748886, + 0.002004631096497178, + 0.11982911080121994, + 0.609316349029541, + 0.5792325735092163, + 0.10267578810453415, + -0.02287464588880539, + -0.011516223661601543, + -0.02587946131825447, + 0.019127164036035538, + 0.2742871046066284, + 0.23896890878677368, + -0.013414637185633183, + 0.012439075857400894, + 0.01148916780948639, + 0.0024075021501630545, + -0.028374193236231804, + -0.02938784286379814, + -0.061723873019218445, + -0.03288640081882477, + 0.010918691754341125, + 0.01171314436942339, + 0.00894222967326641, + -0.0050367508083581924, + 0.00322812981903553, + -0.01958087645471096, + 0.000401448953198269, + 0.00655051926150918, + 0.008647873997688293, + -0.015351405367255211, + -0.022286182269454002, + -0.0018973759142681956, + -0.032965533435344696, + 0.009401706047356129, + 0.01680464670062065, + 0.01722409576177597, + 0.017367251217365265, + -0.0012145076179876924, + 0.015895379707217216, + -0.013976357877254486, + 0.01587546430528164, + -0.019388504326343536, + -0.004597584251314402, + -0.026080038398504257, + 0.020517753437161446, + 0.20680218935012817, + 0.20302064716815948, + 0.03813354671001434, + 0.027738921344280243, + 0.02183712273836136, + 0.023807305842638016, + 0.14632326364517212, + 0.5991678237915039, + 0.608651340007782, + 0.15929070115089417, + -0.02112223394215107, + -0.020013611763715744, + -0.03723381832242012, + 0.032139480113983154, + 0.27032363414764404, + 0.24862462282180786, + 0.02374681644141674, + 0.007894856855273247, + 0.00042308925185352564, + -0.004832752980291843, + -0.024313796311616898, + -0.0018940505106002092, + -0.02681432105600834, + 0.002362651750445366, + 0.013330202549695969, + 0.012553646229207516, + 0.002630018163472414, + 0.002979951212182641, + 0.0015847217291593552, + -0.03376828506588936, + -0.010844729840755463, + -0.002748559694737196, + 0.012938202358782291, + -0.011872833594679832, + -0.0025761008728295565, + 0.003677211469039321, + -0.04305516183376312, + 0.001133457524701953, + 0.0020396243780851364, + 0.01797032356262207, + 0.016580887138843536, + 0.04445189982652664, + 0.013270077295601368, + -0.04839251935482025, + 0.011546633206307888, + -0.015829432755708694, + 0.019473392516374588, + -0.011464826762676239, + 0.018693143501877785, + 0.18201367557048798, + 0.16157257556915283, + 0.02082117274403572, + 0.015915032476186752, + 0.010720869526267052, + -0.0020238866563886404, + 0.09329187124967575, + 0.46998023986816406, + 0.5186727046966553, + 0.09814783185720444, + -0.016547314822673798, + 0.00325066689401865, + -0.028936590999364853, + 0.01002424769103527, + 0.21822214126586914, + 0.22012007236480713, + 0.008229314349591732, + 0.015599996782839298, + 0.014740276150405407, + 0.0019725109450519085, + 0.003613655688241124, + -0.03043546713888645, + -0.06308998167514801, + 0.014664110727608204, + 0.06775129586458206, + -0.12990300357341766, + -0.03638269379734993, + -0.03883139044046402, + 0.05194637551903725, + 0.03896122798323631, + -0.05132362246513367, + -0.07234688848257065, + -0.36106064915657043, + -0.2839237451553345, + -0.11496391147375107, + 0.3026673197746277, + 0.3528609871864319, + 0.21559017896652222, + -0.11970120668411255, + -0.5473688244819641, + -0.5362005233764648, + -0.21015112102031708, + 0.4089161455631256, + 0.6033567786216736, + 0.38614287972450256, + -0.12437233328819275, + -0.6394402384757996, + -0.6945835947990417, + -0.3482857942581177, + 0.5189254283905029, + 0.8457668423652649, + 0.6248002648353577, + -0.12700730562210083, + -0.6978924870491028, + -0.7764106392860413, + -0.4171960651874542, + 0.44747814536094666, + 0.8406224846839905, + 0.6821274161338806, + -0.07793218642473221, + -0.5459966659545898, + -0.6139025092124939, + -0.35998886823654175, + 0.27800890803337097, + 0.6048891544342041, + 0.591307520866394, + -0.04850815609097481, + -0.3863481283187866, + -0.3542836606502533, + -0.2491992861032486, + 0.1616278886795044, + 0.3402666747570038, + 0.4610227644443512, + -0.010262396186590195, + 0.0408165417611599, + 0.006382474210113287, + -0.011430315673351288, + -0.027895113453269005, + -0.009767768904566765, + 0.005882019177079201, + 0.05225436016917229, + 0.0415218211710453, + 0.08244743943214417, + 0.026765575632452965, + -0.05404946208000183, + -0.06101839989423752, + -0.028233220800757408, + 0.03128793090581894, + 0.07133004069328308, + 0.0718698799610138, + 0.042146697640419006, + -0.08380170166492462, + -0.09263177216053009, + -0.07569421827793121, + 0.032425008714199066, + 0.12351400405168533, + 0.09103626012802124, + -0.004768018145114183, + -0.05960838869214058, + -0.11922567337751389, + -0.10132396221160889, + 0.044341862201690674, + 0.100867860019207, + 0.09607693552970886, + -0.00129030947573483, + -0.05481477826833725, + -0.1278291642665863, + -0.12058380991220474, + 0.016678951680660248, + 0.09958931058645248, + 0.08456224203109741, + 0.061599165201187134, + -0.049776893109083176, + -0.11354166269302368, + -0.09844806790351868, + 0.004753128159791231, + 0.07868346571922302, + 0.06464104354381561, + 0.020981626585125923, + -0.010770543478429317, + -0.08838209509849548, + -0.07265795767307281, + -0.058313023298978806, + 0.10897739976644516, + 0.026735201478004456, + 0.03972309082746506, + -0.019998662173748016, + -0.048948734998703, + 0.03377270698547363, + 0.053406376391649246, + 0.27304399013519287, + 0.20850272476673126, + 0.07890326529741287, + -0.22241365909576416, + -0.2816997468471527, + -0.1745096743106842, + 0.08957889676094055, + 0.4962941110134125, + 0.4586986303329468, + 0.20177948474884033, + -0.3625744581222534, + -0.47758376598358154, + -0.32412785291671753, + 0.0669194757938385, + 0.5394997596740723, + 0.601328432559967, + 0.24388420581817627, + -0.4319041073322296, + -0.6893490552902222, + -0.5106037259101868, + 0.10174300521612167, + 0.5457565784454346, + 0.6549625992774963, + 0.38772058486938477, + -0.3778320252895355, + -0.6820934414863586, + -0.551069438457489, + 0.049600999802351, + 0.45137161016464233, + 0.5143972039222717, + 0.3713279068470001, + -0.26546329259872437, + -0.5121409893035889, + -0.47691628336906433, + 0.03843758627772331, + 0.30808231234550476, + 0.3185756504535675, + 0.22629432380199432, + -0.14860986173152924, + -0.2915389835834503, + -0.3552006185054779, + -0.003137432038784027, + -0.01327254343777895, + -0.027139298617839813, + 0.04800891876220703, + 0.05380738899111748, + -0.01380784809589386, + 0.0022881641052663326, + -0.012132279574871063, + 0.06182793900370598, + 0.03762871399521828, + 0.0966145321726799, + 0.08963571488857269, + 0.06551238149404526, + 0.031640589237213135, + -0.010532311163842678, + 0.07195396721363068, + 0.11343465745449066, + 0.11621421575546265, + 0.047318290919065475, + 0.1111951395869255, + 0.044054243713617325, + 0.016777141019701958, + 0.03392713516950607, + 0.06047024950385094, + -0.7924502491950989, + -0.7310910224914551, + 0.031088173389434814, + 0.0906061977148056, + 0.022829236462712288, + 0.04470035433769226, + 0.025999872013926506, + -0.8246837258338928, + -0.723675549030304, + 0.15835590660572052, + 0.07358791679143906, + -0.015819497406482697, + -0.014207872562110424, + 0.08506257086992264, + 0.08868777751922607, + 0.0976945012807846, + 0.11740022897720337, + 0.016287995502352715, + -0.024363648146390915, + 0.04249691963195801, + 0.02909177541732788, + 0.12011238187551498, + 0.10729824751615524, + 0.05927390977740288, + 0.04731644690036774, + 0.008210064843297005, + 0.03859357163310051, + -0.005175672471523285, + 0.01984376832842827, + -0.0011626111809164286, + -0.0010909241391345859, + 0.02311880886554718, + 0.007646523881703615, + 0.04582137614488602, + -0.0027255103923380375, + 0.027656713500618935, + 0.02781369723379612, + 0.015750093385577202, + 0.040563344955444336, + -0.007784596644341946, + 0.006534814368933439, + 0.002403199439868331, + -0.020037032663822174, + -0.011717663146555424, + 0.07826739549636841, + 0.018203573301434517, + 0.021228624507784843, + 0.014112413860857487, + -0.02866269089281559, + -0.9502679109573364, + -0.825043797492981, + 0.05938851460814476, + 0.06553053110837936, + 0.015418429858982563, + 0.0616452619433403, + -0.0094453701749444, + -0.9471839666366577, + -0.7922234535217285, + 0.13069523870944977, + 0.04939320683479309, + 0.007429714780300856, + 0.022599652409553528, + 0.0820123627781868, + 0.06440276652574539, + 0.09897352755069733, + 0.0856291800737381, + 0.006608777679502964, + -0.0005533680086955428, + 0.021656949073076248, + 0.014818831346929073, + 0.03757459297776222, + -0.001428246614523232, + 0.03473127633333206, + 0.03607869893312454, + 0.017313262447714806, + 0.0025767614133656025, + -0.033292777836322784, + 0.027883101254701614, + -0.007534499745815992, + -0.04302362725138664, + -0.01795666106045246, + -0.007667913101613522, + 0.012547189369797707, + -0.021762438118457794, + 0.03789107874035835, + 0.06384614109992981, + 0.0014223429607227445, + -0.01393786258995533, + -0.041693057864904404, + -0.01813604310154915, + 0.065328449010849, + 0.15736474096775055, + 0.1531635969877243, + 0.09920474886894226, + -0.04044449329376221, + 0.010558396577835083, + 0.05559245124459267, + 0.10931257158517838, + -0.5784384608268738, + -0.5109886527061462, + 0.17690584063529968, + 0.07484250515699387, + 0.010378374718129635, + 0.0890144556760788, + 0.13172735273838043, + -0.6058865785598755, + -0.49908995628356934, + 0.1835336685180664, + 0.005293308291584253, + -0.03870566934347153, + -0.025229454040527344, + 0.12571711838245392, + 0.14792272448539734, + 0.14905226230621338, + 0.0700206533074379, + -0.035034529864788055, + 0.013128797523677349, + 0.015581230632960796, + 0.005400130525231361, + 0.07070232182741165, + 0.03829728811979294, + -0.013876918703317642, + -0.019958000630140305, + -0.020086020231246948, + -0.019999003037810326, + -0.015111410059034824, + 0.11963249742984772, + -0.08270428329706192, + -0.0025947154499590397, + -0.010668564587831497, + 0.016670405864715576, + -0.03206938877701759, + -0.053453829139471054, + 0.1236601173877716, + -0.020077411085367203, + 0.00779569149017334, + -0.0318986251950264, + 0.03579804673790932, + -0.060723867267370224, + -0.009301809594035149, + 0.09249342232942581, + -0.13378725945949554, + 0.17496798932552338, + -0.0935625433921814, + 0.06569044291973114, + -0.18187756836414337, + 0.06397300213575363, + 0.3793930113315582, + -0.5664302706718445, + 0.23658618330955505, + -0.03206830099225044, + 0.03155658766627312, + 0.039305318146944046, + -0.6008145213127136, + 1.0417630672454834, + -0.5062726140022278, + -0.04698493704199791, + 0.0979752242565155, + -0.037326715886592865, + 0.26255178451538086, + -0.590207576751709, + 0.4195419251918793, + 0.12212422490119934, + -0.26122942566871643, + 0.06442253291606903, + -0.07682429254055023, + 0.12608948349952698, + -0.13872937858104706, + -0.030260663479566574, + 0.2047160565853119, + -0.13068141043186188, + 0.016608506441116333, + -0.021629147231578827, + 0.04659907519817352, + 0.024417348206043243, + 0.06751634925603867, + -0.1705978959798813, + 0.0655774399638176, + -0.0041802311316132545, + -0.02263445220887661, + -0.014069054275751114, + 0.06242800131440163, + 0.08984102308750153, + -0.19382472336292267, + 0.09380361437797546, + -0.0032764992211014032, + -0.03950225189328194, + -0.08896161615848541, + 0.28387022018432617, + 0.1668996810913086, + -0.5457127094268799, + 0.21796099841594696, + 0.012032964266836643, + 0.030721815302968025, + -0.4431600570678711, + 0.3104412257671356, + 1.0070439577102661, + -1.1077969074249268, + 0.08187273889780045, + 0.1387241780757904, + 0.09014563262462616, + -0.25378379225730896, + -0.9253583550453186, + 1.9745515584945679, + -0.6605072617530823, + -0.4394792318344116, + 0.11501576751470566, + 0.03007262572646141, + 0.2538164258003235, + -1.1462018489837646, + 0.7988958954811096, + 0.46934643387794495, + -0.4244523048400879, + -0.0001816617150325328, + -0.04351970925927162, + 0.20500127971172333, + -0.40710335969924927, + -0.15871365368366241, + 0.4640160799026489, + -0.06024328991770744, + -0.016036653891205788, + -0.012419192120432854, + 0.05552554875612259, + 0.050986770540475845, + -0.0171927809715271, + -0.12105240672826767, + 0.03947274759411812, + 0.009537882171571255, + -0.026668362319469452, + 0.017273351550102234, + 0.10812800377607346, + -0.015008139424026012, + -0.14154496788978577, + 0.08008233457803726, + -0.01306608971208334, + -0.05574854835867882, + -0.06091056764125824, + 0.2888447940349579, + 0.05022002384066582, + -0.4581625759601593, + 0.21146118640899658, + -0.01495362538844347, + 0.02946372702717781, + -0.38554418087005615, + 0.30167311429977417, + 0.7605867981910706, + -0.898481547832489, + 0.11953620612621307, + 0.12686115503311157, + 0.09949854761362076, + -0.14409342408180237, + -0.7404491901397705, + 1.5449001789093018, + -0.5307857394218445, + -0.3347839415073395, + 0.09940771013498306, + 0.009087899699807167, + 0.3081797957420349, + -0.9053899049758911, + 0.5102643370628357, + 0.4646914303302765, + -0.36200836300849915, + -0.043260715901851654, + -0.05309509113430977, + 0.22480911016464233, + -0.2674587666988373, + -0.25316888093948364, + 0.435017466545105, + -0.017485838383436203, + -0.049459364265203476, + 0.012460661120712757, + -0.02262282371520996, + -0.04392899200320244, + 0.013330060057342052, + 0.05963548645377159, + -0.020561739802360535, + -0.013496879488229752, + -0.02310933545231819, + -0.06549905985593796, + 0.12132573872804642, + 0.22165189683437347, + -0.07683887332677841, + -0.12427931278944016, + 0.05543455854058266, + 0.009089780040085316, + 0.19844494760036469, + 0.07650767266750336, + -0.48934996128082275, + -0.35080164670944214, + 0.13422781229019165, + 0.022217294201254845, + -0.006589306052774191, + -0.18357548117637634, + -0.6055922508239746, + 0.09492127597332001, + 0.7073907256126404, + 0.1777055710554123, + -0.05434347689151764, + 0.04566245526075363, + -0.023967979475855827, + 0.4856843054294586, + 0.8131930828094482, + -0.2068077027797699, + -0.3863125145435333, + 0.02887917123734951, + -0.05048410966992378, + 0.051201049238443375, + 0.057671088725328445, + -0.6412642002105713, + -0.39739903807640076, + 0.11036981642246246, + 0.06687764078378677, + -0.018151026219129562, + 0.0022760110441595316, + -0.09328305721282959, + 0.1352599710226059, + 0.19680921733379364, + 0.032235175371170044, + -0.06123670935630798, + -0.013810456730425358, + -0.01821190118789673, + -0.029903864488005638, + 0.027588335797190666, + 0.0762094110250473, + -0.046041399240493774, + 0.017117975279688835, + -0.018925148993730545, + 0.00423092395067215, + 0.2065701186656952, + 0.157025545835495, + -0.26491472125053406, + -0.24569831788539886, + 0.0873267725110054, + 0.004694689530879259, + 0.1838335543870926, + -0.18973900377750397, + -0.9744532108306885, + -0.41959065198898315, + 0.409589946269989, + 0.22223009169101715, + -0.0989728644490242, + -0.40883490443229675, + -0.8418471813201904, + 0.40256521105766296, + 1.4742398262023926, + 0.4913789629936218, + -0.14741277694702148, + -0.0028576564509421587, + 0.0861843004822731, + 1.0056577920913696, + 1.479182481765747, + -0.21940617263317108, + -0.8383130431175232, + -0.30560192465782166, + 0.12028121203184128, + 0.24013034999370575, + 0.11750353127717972, + -1.1071972846984863, + -0.9066778421401978, + -0.055051110684871674, + 0.15361995995044708, + 0.0032418384216725826, + -0.08823435008525848, + -0.3188804090023041, + -0.02160414680838585, + 0.2972750663757324, + 0.17006494104862213, + 0.03401973098516464, + 0.017106015235185623, + 0.010733614675700665, + 0.004688877146691084, + 0.02985573373734951, + 0.046415988355875015, + -0.05177726596593857, + -0.04624386876821518, + 0.026672907173633575, + 0.03479000926017761, + 0.22761401534080505, + 0.12049756944179535, + -0.23494181036949158, + -0.2207801640033722, + 0.06036320701241493, + 0.02112250216305256, + 0.16173022985458374, + -0.14196650683879852, + -0.8236543536186218, + -0.3530665934085846, + 0.3715725541114807, + 0.25781863927841187, + -0.09806561470031738, + -0.341796338558197, + -0.7201419472694397, + 0.2111824005842209, + 1.1648427248001099, + 0.3866075575351715, + -0.1955428272485733, + -0.13164694607257843, + -0.06048528477549553, + 0.7989920973777771, + 1.143347144126892, + -0.19509637355804443, + -0.6719933152198792, + -0.26912447810173035, + 0.16733723878860474, + 0.32526257634162903, + 0.1910397708415985, + -0.8516904711723328, + -0.6005953550338745, + 0.10627525299787521, + 0.16700856387615204, + 0.032433755695819855, + -0.11345972120761871, + -0.270126610994339, + -0.012052524834871292, + 0.25489771366119385, + 0.14647918939590454, + -0.014324051328003407, + -0.011148945428431034, + -0.0011708218371495605, + -0.018903911113739014, + -0.010648071765899658, + -0.017981043085455894, + 0.014055400155484676, + -0.020784996449947357, + -0.030126383528113365, + 0.1150858998298645, + -0.1112036183476448, + -0.023664508014917374, + 0.1651369333267212, + -0.055412910878658295, + -0.007318025920540094, + -0.07404221594333649, + 0.3068569302558899, + -0.6175673007965088, + 0.35226404666900635, + 0.1940349042415619, + -0.22921296954154968, + 0.06411048769950867, + 0.001689439988695085, + 0.23336739838123322, + -0.9470900893211365, + 1.2042961120605469, + -0.44587329030036926, + -0.15847182273864746, + 0.07572423666715622, + 0.11138042062520981, + -0.2075018584728241, + -0.2651064693927765, + 0.8896074295043945, + -0.7130936980247498, + 0.10370831191539764, + 0.07730382680892944, + 0.02368813008069992, + -0.20520009100437164, + 0.13611918687820435, + 0.31062978506088257, + -0.471883624792099, + 0.21489326655864716, + -0.0216743852943182, + -0.04020361602306366, + -0.022920167073607445, + 0.16054102778434753, + -0.002624030224978924, + -0.14670424163341522, + 0.12018264085054398, + -0.043656397610902786, + -0.005084550939500332, + 0.03873870149254799, + -0.07967288792133331, + -0.007439201697707176, + 0.027688704431056976, + 0.08916077762842178, + -0.0036629599053412676, + -0.01389122661203146, + 0.1402083784341812, + -0.2923351228237152, + -0.01932896114885807, + 0.224355086684227, + -0.013193303719162941, + -0.03984276205301285, + -0.04474477842450142, + 0.3302844762802124, + -0.9746807217597961, + 0.5603556036949158, + 0.3556183874607086, + -0.2713812589645386, + 0.01890619471669197, + 0.06983876973390579, + 0.09052442759275436, + -1.3613605499267578, + 1.8220031261444092, + -0.40902698040008545, + -0.31302449107170105, + 0.03893759846687317, + 0.11448371410369873, + -0.4220678210258484, + -0.3677598237991333, + 1.539440631866455, + -0.8297391533851624, + -0.08504960685968399, + 0.0629446730017662, + -0.016804160550236702, + -0.31778836250305176, + 0.2363198846578598, + 0.6452136635780334, + -0.700931191444397, + 0.09927428513765335, + 0.0019635935313999653, + -0.05397690460085869, + -0.014552262611687183, + 0.2352754771709442, + 0.09991656988859177, + -0.28891685605049133, + 0.07818552106618881, + -0.021534763276576996, + -0.009461677633225918, + -0.01069199200719595, + -0.008059840649366379, + -0.0129952197894454, + 0.038492631167173386, + 0.018906958401203156, + -0.025432486087083817, + -0.03420932963490486, + 0.09104404598474503, + -0.10342919826507568, + -0.035048507153987885, + 0.1415904313325882, + -0.052986644208431244, + -0.021596742793917656, + -0.049690280109643936, + 0.3079117238521576, + -0.5487046837806702, + 0.27024003863334656, + 0.15158434212207794, + -0.16488635540008545, + 0.027642132714390755, + 0.004561549983918667, + 0.21555493772029877, + -0.9188903570175171, + 1.0972669124603271, + -0.3528037667274475, + -0.07574182748794556, + 0.021962830796837807, + 0.08826783299446106, + -0.18681983649730682, + -0.2789378762245178, + 0.864517331123352, + -0.5642455816268921, + 0.07469761371612549, + 0.03803368657827377, + 0.014268620871007442, + -0.17712704837322235, + 0.1349189728498459, + 0.3181247115135193, + -0.45067182183265686, + 0.1391848623752594, + 0.009777083061635494, + -0.028080958873033524, + -0.03586730733513832, + 0.14503192901611328, + -0.014655024744570255, + -0.1472700834274292, + 0.07361634075641632, + -0.0029754601418972015, + -0.006887470372021198, + -0.019166842103004456, + 0.0034907464869320393, + -0.015169994905591011, + 0.053831856697797775, + -0.028789488598704338, + -0.02033298648893833, + 0.0018537036376073956, + 0.07567961513996124, + -0.07041627168655396, + -0.047083087265491486, + 0.17573483288288116, + -0.04860217124223709, + 0.013171656988561153, + 0.020158233121037483, + -0.006270059384405613, + -0.28434091806411743, + 0.2760852873325348, + 0.32198208570480347, + -0.43535903096199036, + 0.03188510239124298, + 0.019360313192009926, + -0.20063988864421844, + 0.04450676590204239, + 0.9678076505661011, + -0.683987021446228, + -0.3979112207889557, + 0.2618143558502197, + -0.049711134284734726, + -0.06456997990608215, + 0.6518288850784302, + -0.1357039213180542, + -1.1304017305374146, + 0.4881652295589447, + 0.19583553075790405, + -0.03677722439169884, + 0.21429045498371124, + 0.09559855610132217, + -0.7311355471611023, + 0.10988117009401321, + 0.4949330687522888, + -0.17359353601932526, + 0.03822369873523712, + 0.011371256783604622, + -0.1900172382593155, + -0.04778448864817619, + 0.2897090017795563, + -0.02235160581767559, + -0.05582524091005325, + 0.007624597754329443, + -0.027456223964691162, + -0.029680097475647926, + -0.023810429498553276, + 0.15409281849861145, + 0.013284318149089813, + -0.0788225457072258, + -0.025637971237301826, + 0.01406402699649334, + -0.13676859438419342, + 0.027384959161281586, + 0.30458444356918335, + -0.11150643229484558, + -0.06806201487779617, + 0.009601237252354622, + -0.0866582989692688, + -0.2328706979751587, + 0.5188567638397217, + 0.3787381649017334, + -0.655829906463623, + 0.0072118742391467094, + -0.0031494891736656427, + -0.2424815446138382, + 0.28893929719924927, + 1.2396824359893799, + -1.0406886339187622, + -0.6376030445098877, + 0.4103420078754425, + -0.05929668992757797, + 0.03918358311057091, + 0.9274081587791443, + -0.28890565037727356, + -1.6682262420654297, + 0.66976398229599, + 0.35488471388816833, + 0.027932289987802505, + 0.3169145882129669, + 0.09107685089111328, + -1.2099432945251465, + 0.11623579263687134, + 0.7632684707641602, + -0.16506360471248627, + 0.037474747747182846, + -0.005203985143452883, + -0.35939401388168335, + -0.17138688266277313, + 0.525232195854187, + 0.10247340798377991, + -0.14317406713962555, + 0.007572649512439966, + -0.006046198774129152, + 0.06188087910413742, + -0.050851333886384964, + 0.032844241708517075, + 0.0544477179646492, + -0.07947597652673721, + -0.03073730878531933, + 0.04025515541434288, + -0.010001083835959435, + -0.11831062287092209, + 0.17422229051589966, + -0.05468267202377319, + -0.04996664077043533, + 0.023996006697416306, + 0.02888253889977932, + -0.18709556758403778, + 0.13987921178340912, + 0.32867854833602905, + -0.31714990735054016, + 0.019951285794377327, + 0.027247004210948944, + -0.19416090846061707, + -0.006519266404211521, + 0.7540720105171204, + -0.5474190711975098, + -0.27137213945388794, + 0.20772530138492584, + -0.042619917541742325, + -0.09566087275743484, + 0.548494815826416, + -0.1599852293729782, + -0.9178788661956787, + 0.5456539988517761, + 0.07497559487819672, + 0.003984459210187197, + 0.18640351295471191, + 0.12121234089136124, + -0.7249511480331421, + 0.2559764087200165, + 0.4684237241744995, + -0.19216996431350708, + 0.018075481057167053, + 0.02684594877064228, + -0.221074178814888, + -0.09164194762706757, + 0.3596596121788025, + -0.08310746401548386, + -0.10815230011940002, + -0.015406409278512001, + -0.011985878460109234, + 0.028467312455177307, + -0.0879230722784996, + 0.0347294844686985, + 0.05081191286444664, + 0.00362736196257174, + 0.010529003106057644, + -0.002672453410923481, + 0.025318201631307602, + -0.06232529878616333, + 0.008822780102491379, + 0.06744717806577682, + 0.003999210894107819, + -0.0022885131184011698, + -0.046704765409231186, + 0.13673964142799377, + -0.2590992748737335, + -0.022161437198519707, + 0.258914053440094, + -0.10650330036878586, + 0.023435762152075768, + 0.06992689520120621, + 0.03760937228798866, + -0.5444027185440063, + 0.4131152629852295, + 0.25325170159339905, + -0.2482522875070572, + 0.010479461401700974, + 0.045747850090265274, + -0.1541248857975006, + -0.35291528701782227, + 0.9078133702278137, + -0.34428781270980835, + -0.14787709712982178, + -0.024105649441480637, + -0.007651817053556442, + -0.14991067349910736, + 0.17544956505298615, + 0.3692120611667633, + -0.46861159801483154, + 0.10201738774776459, + 0.003734431229531765, + -0.010433703660964966, + 0.022045455873012543, + 0.0944862961769104, + 0.01679016835987568, + -0.16537833213806152, + 0.07900089025497437, + -0.004211293533444405, + -0.01076442189514637, + 0.09729930013418198, + -0.1490965485572815, + -0.02511671558022499, + 0.0766475573182106, + 0.010980346240103245, + -0.010220799595117569, + -0.0004861881607212126, + 0.09204736351966858, + -0.179045170545578, + -0.025164175778627396, + 0.15608654916286469, + 0.004787537269294262, + -0.0005253870622254908, + 0.034556396305561066, + 0.1509256660938263, + -0.5432079434394836, + -0.03155849874019623, + 0.513609766960144, + -0.14458952844142914, + 0.015178131870925426, + 0.09172039479017258, + -0.12612608075141907, + -0.926306962966919, + 0.8281942009925842, + 0.5954549908638, + -0.492740273475647, + 0.007195526268333197, + -0.018258413299918175, + -0.4074647128582001, + -0.43008187413215637, + 1.7370752096176147, + -0.350849986076355, + -0.5158001780509949, + -0.017458094283938408, + -0.08306471258401871, + -0.2334563285112381, + 0.445117712020874, + 0.7808031439781189, + -0.7913723587989807, + -0.11814796179533005, + -0.00913319457322359, + 0.0223994143307209, + 0.1012248545885086, + 0.25349485874176025, + 0.028286214917898178, + -0.4809858798980713, + 0.05953341722488403, + 0.015634188428521156, + 0.005101620219647884, + 0.10901974141597748, + -0.11964976042509079, + -0.09117673337459564, + 0.0734483003616333, + 0.01821213960647583, + 5.350751234800555e-05, + -0.020279232412576675, + 0.1097220927476883, + -0.1354990452528, + -0.08653146773576736, + 0.11775246262550354, + -0.012575668282806873, + 0.0310806967318058, + 0.010271146893501282, + 0.20337054133415222, + -0.3854014277458191, + -0.09943562000989914, + 0.3921409249305725, + -0.08432158827781677, + 0.010676748119294643, + 0.040244489908218384, + -0.0015478944405913353, + -0.7022866010665894, + 0.49858638644218445, + 0.42338883876800537, + -0.2982582449913025, + -0.005396307446062565, + -0.008777705952525139, + -0.2325415015220642, + -0.4083922803401947, + 1.186205506324768, + -0.26399391889572144, + -0.2621048092842102, + -0.015712907537817955, + -0.04675402492284775, + -0.1797540783882141, + 0.2992522716522217, + 0.4747498333454132, + -0.5266988277435303, + 0.04581758379936218, + -0.04037958011031151, + 0.0071074217557907104, + 0.047499995678663254, + 0.16617828607559204, + -0.03973710536956787, + -0.2953551113605499, + 0.10628587752580643, + -0.00904526561498642, + 0.010427894070744514, + 0.08035022020339966, + 0.03841109946370125, + -0.06335253268480301, + -0.06992083787918091, + 0.015409895218908787, + -0.026900725439190865, + -0.04523912072181702, + 0.08087682723999023, + 0.12542113661766052, + 0.018750213086605072, + -0.23430712521076202, + 0.11755944788455963, + -0.019747508689761162, + -0.03171322122216225, + -0.12132623791694641, + 0.2640603184700012, + 0.38445138931274414, + -0.5724408030509949, + 0.15661633014678955, + 0.01949799247086048, + -0.021771302446722984, + -0.18984957039356232, + -0.23499636352062225, + 1.2112919092178345, + -0.7037869095802307, + -0.14260035753250122, + 0.01848726160824299, + 0.06443414837121964, + -0.11740390956401825, + -0.8794785141944885, + 1.4160369634628296, + 0.016899125650525093, + -0.5444768071174622, + 0.017313210293650627, + 0.0508052259683609, + 0.11102095246315002, + -0.790285587310791, + 0.3501206636428833, + 0.7238660454750061, + -0.49468666315078735, + -0.019021952524781227, + -0.01212992612272501, + 0.15032203495502472, + -0.3573611080646515, + -0.1293754130601883, + 0.45295456051826477, + -0.08407819271087646, + -0.008717959746718407, + 0.022566653788089752, + -0.012640242464840412, + 0.03181227669119835, + 0.0638526976108551, + -0.058120664209127426, + -0.042917650192976, + 0.02129550836980343, + -0.018790805712342262, + -0.00655191857367754, + 0.05951414257287979, + 0.12890471518039703, + -0.1886381357908249, + 0.059096939861774445, + -0.016928592696785927, + 0.02327263168990612, + -0.17282842099666595, + 0.13812857866287231, + 0.38889989256858826, + -0.5282873511314392, + 0.07564643770456314, + -0.006128210574388504, + -0.00876594614237547, + -0.18427829444408417, + -0.26697441935539246, + 1.2529815435409546, + -0.6549165844917297, + -0.2111111879348755, + 0.011410325765609741, + 0.07089994102716446, + -0.12627695500850677, + -0.8245998024940491, + 1.4581915140151978, + -0.01822204887866974, + -0.5626582503318787, + -0.01661459542810917, + 0.03759436681866646, + 0.10841676592826843, + -0.7652962803840637, + 0.4360819458961487, + 0.7012669444084167, + -0.47011038661003113, + 0.01529701892286539, + -0.0033166150096803904, + 0.12170535326004028, + -0.3871544301509857, + -0.05247795954346657, + 0.4504147171974182, + -0.11442532390356064, + -0.00882577896118164, + 0.005190832540392876, + -0.05153197422623634, + 0.0055236960761249065, + 0.09320031106472015, + -0.03762076050043106, + -0.021778371185064316, + 0.00750907463952899, + 0.014965789392590523, + -0.015135630965232849, + -0.037086039781570435, + 0.08020154386758804, + -0.04429963231086731, + 0.0038218852132558823, + -0.01712334342300892, + 0.053772956132888794, + -0.05226677283644676, + -0.024439912289381027, + 0.12774989008903503, + -0.18722355365753174, + 0.0683830976486206, + -0.010828870348632336, + -0.012880662456154823, + 0.02679484151303768, + -0.13696907460689545, + 0.46868517994880676, + -0.322968989610672, + 0.052930932492017746, + 0.009463602676987648, + -0.046861011534929276, + 0.07714711129665375, + -0.35792097449302673, + 0.5517901182174683, + -0.13382655382156372, + -0.12921281158924103, + 0.018562642857432365, + -0.03842621296644211, + 0.10284601897001266, + -0.28243398666381836, + 0.13314206898212433, + 0.20769073069095612, + -0.1551610678434372, + 0.018036767840385437, + -0.03553476929664612, + 0.036686040461063385, + -0.09568552672863007, + 0.008917863480746746, + 0.11340243369340897, + -0.04745811969041824, + 0.005833764094859362, + -0.04174824804067612, + 0.022730106487870216, + 0.0013601485406979918, + -0.07473982870578766, + -0.004801879171282053, + 0.05632775276899338, + -0.04081303998827934, + 0.11509573459625244, + 0.004507652949541807, + -0.24791881442070007, + 0.43171870708465576, + -0.1362573653459549, + -0.10758046060800552, + 0.02746163308620453, + -0.2954745888710022, + 0.30186471343040466, + 0.3135572075843811, + -1.2296111583709717, + 0.8754236102104187, + -0.11699853837490082, + 0.022482017055153847, + 0.24945153295993805, + -0.7858022451400757, + 0.5181443095207214, + 1.4243930578231812, + -1.876152515411377, + 0.4689188003540039, + 0.04258054122328758, + -0.030832920223474503, + 0.9340220093727112, + -1.512351632118225, + -0.3731614947319031, + 2.021338701248169, + -0.7801089286804199, + -0.09288544207811356, + -0.12423597276210785, + -0.36861127614974976, + 1.1679530143737793, + -0.4960964024066925, + -1.0398281812667847, + 0.686152458190918, + 0.02052121050655842, + 0.07246638089418411, + -0.01763315312564373, + -0.37442535161972046, + 0.33217450976371765, + 0.22260302305221558, + -0.2657756209373474, + 0.00016369696822948754, + 0.008136127144098282, + -0.03592197597026825, + 0.022231513634324074, + 0.041430093348026276, + -0.06439317017793655, + 0.03496818616986275, + -0.05143435671925545, + 0.09930871427059174, + 0.017110232263803482, + -0.3834381699562073, + 0.44344815611839294, + -0.00280396337620914, + -0.11487428843975067, + 0.050503507256507874, + -0.22837062180042267, + 0.47540077567100525, + 0.5802375674247742, + -1.7325034141540527, + 0.8587368130683899, + 0.10429240018129349, + -0.02456486038863659, + 0.1340152472257614, + -1.2299835681915283, + 0.7986555099487305, + 2.2204456329345703, + -2.4498374462127686, + 0.33742472529411316, + 0.1001473218202591, + 0.08700849115848541, + 0.9933257102966309, + -2.5278031826019287, + -0.5935835242271423, + 2.710871934890747, + -0.87749183177948, + -0.06125229224562645, + -0.19061818718910217, + -0.04017600044608116, + 1.7519460916519165, + -0.7798219919204712, + -1.28012216091156, + 0.7500321269035339, + 0.02245335467159748, + 0.08263842761516571, + -0.1563340127468109, + -0.3502165377140045, + 0.5060794949531555, + 0.11768018454313278, + -0.2394258826971054, + 0.0027446788735687733, + -0.0012661140644922853, + 0.010839025489985943, + 0.04500429332256317, + -0.04333498701453209, + -0.027386408299207687, + 0.04357098788022995, + -0.04407481476664543, + 0.08443310111761093, + -0.08108946681022644, + -0.20346391201019287, + 0.3825778365135193, + -0.16498182713985443, + -0.04287993535399437, + 0.05340999737381935, + -0.14011172950267792, + 0.29446643590927124, + 0.2738667130470276, + -1.1299961805343628, + 0.7827413082122803, + -0.07552053779363632, + -0.03602323681116104, + 0.16167275607585907, + -0.6924317479133606, + 0.4478289783000946, + 1.2428895235061646, + -1.4833877086639404, + 0.4690392315387726, + -0.00820756796747446, + -0.09873292595148087, + 0.692342221736908, + -1.0981175899505615, + -0.3906446695327759, + 1.438644528388977, + -0.719068169593811, + 0.026173872873187065, + -0.09383898228406906, + -0.3282022774219513, + 1.0363390445709229, + -0.23960772156715393, + -0.7638148069381714, + 0.5488630533218384, + -0.015319733880460262, + 0.11911362409591675, + 0.017409542575478554, + -0.4231888949871063, + 0.23724795877933502, + 0.1191876158118248, + -0.15694500505924225, + -0.03534351661801338, + 0.06342366337776184, + 0.17738288640975952, + 0.012300643138587475, + -0.06408121436834335, + -0.06030220910906792, + 0.0018237337935715914, + 0.07659764587879181, + 0.1820947527885437, + 0.24410061538219452, + -0.06998514384031296, + -0.1491813361644745, + -0.06184092164039612, + 0.04607890918850899, + 0.15362663567066193, + 0.18308304250240326, + 0.08175522834062576, + -0.305602103471756, + -0.2915116548538208, + -0.08144206553697586, + 0.07138665020465851, + -0.03521484509110451, + -0.0914112851023674, + -0.2766699492931366, + -0.6285344362258911, + -0.38168880343437195, + -0.0033710987772792578, + 0.14477019011974335, + -0.03885374590754509, + -0.11367184668779373, + -0.1979650855064392, + -0.3575190007686615, + 0.016150522977113724, + 0.28292712569236755, + 0.2836199402809143, + -0.016672370955348015, + -0.034946177154779434, + -0.014770845882594585, + -0.0004113636096008122, + 0.29938748478889465, + 0.3562523126602173, + 0.13313128054141998, + -0.029499055817723274, + 0.007187174167484045, + 0.0636785551905632, + 0.047712039202451706, + 0.20670579373836517, + 0.10999035090208054, + -0.1150810718536377, + 0.00879934523254633, + -0.009125287644565105, + -0.013732590712606907, + 0.04738131910562515, + 0.0549951009452343, + -0.014094026759266853, + -0.01195482350885868, + -0.017125386744737625, + -0.071754589676857, + -0.023961570113897324, + 0.013098018243908882, + 0.05972208455204964, + -0.032899752259254456, + -0.024354496970772743, + -0.013116234913468361, + -0.05865325778722763, + -0.006360829807817936, + 0.12809234857559204, + 0.14038555324077606, + -0.022946689277887344, + -0.039698828011751175, + 0.05144746974110603, + -0.025034509599208832, + 0.08764739334583282, + 0.24594412744045258, + 0.19307002425193787, + -0.04085381329059601, + -0.020323628559708595, + 0.022060081362724304, + 0.01799374632537365, + 0.09039195626974106, + 0.1681770235300064, + 0.0016234283102676272, + -0.23777234554290771, + -0.11634974926710129, + -0.014439117163419724, + -0.034799374639987946, + 0.0457066111266613, + 0.049919649958610535, + -0.1926913857460022, + -0.2680967450141907, + 0.0018220803467556834, + -0.012749310582876205, + -0.04389086738228798, + 0.0060565415769815445, + -0.012036234140396118, + -0.12737582623958588, + -0.05777670815587044, + 0.09932202100753784, + 0.09969642758369446, + -0.1296343356370926, + -0.2964152693748474, + -0.05487265810370445, + 0.12073978036642075, + 0.06634647399187088, + 0.004042446613311768, + -0.1586746722459793, + -0.6267098784446716, + -0.5184157490730286, + -0.032286129891872406, + 0.28023189306259155, + 0.12663227319717407, + -0.08828771114349365, + -0.2600027620792389, + -0.5287090539932251, + -0.0994620993733406, + 0.7820600271224976, + 0.9638882279396057, + 0.2193463146686554, + -0.13466303050518036, + 0.042050741612911224, + -0.02292742393910885, + 0.7523098587989807, + 1.7435946464538574, + 1.111282229423523, + -0.2104763388633728, + -0.35129284858703613, + 0.08224371820688248, + 0.11167984455823898, + 0.6513852477073669, + 0.9696454405784607, + -0.1501394510269165, + -1.1777327060699463, + -0.7738466262817383, + 0.01114045549184084, + 0.004884988535195589, + 0.2849186658859253, + 0.14232710003852844, + -1.0306764841079712, + -1.2078118324279785, + -0.14658716320991516, + 0.036605384200811386, + 0.0001495486794738099, + 0.12111346423625946, + -0.24653346836566925, + -0.7028710246086121, + -0.18977169692516327, + 0.5171932578086853, + -0.02514370158314705, + 0.0885375589132309, + -0.1023016944527626, + 0.023200739175081253, + 0.11839435249567032, + -0.09749021381139755, + 0.008283962495625019, + 0.0106261121109128, + -0.031724803149700165, + -0.1594654619693756, + 0.433218389749527, + -0.33944255113601685, + 0.14406877756118774, + -0.0339396670460701, + 0.09370072185993195, + -0.35916459560394287, + 0.7577320337295532, + -0.5531823635101318, + -0.016844574362039566, + 0.2994873523712158, + -0.21487002074718475, + -0.16125759482383728, + 0.35567227005958557, + 0.09099612385034561, + -1.3889282941818237, + 1.9466298818588257, + -1.2556309700012207, + 0.4389301836490631, + -0.010665428824722767, + 0.4707520306110382, + -1.4310415983200073, + 2.0986156463623047, + -1.5515614748001099, + 0.3905705511569977, + 0.01881679706275463, + 0.057307951152324677, + -0.29734691977500916, + 0.369127094745636, + -0.05115725100040436, + -0.44008156657218933, + 0.48642784357070923, + -0.13904061913490295, + -0.004375698510557413, + -0.06351548433303833, + 0.256020188331604, + -0.34121274948120117, + 0.22490821778774261, + 0.004067304544150829, + -0.059063635766506195, + -0.010710661299526691, + 0.03514768183231354, + -0.08577805012464523, + 0.05103181675076485, + 0.04276616871356964, + -0.10832246392965317, + 0.03325289487838745, + 0.06318283081054688, + -0.11063538491725922, + -0.062119144946336746, + 0.40978243947029114, + -0.5597845315933228, + 0.34106317162513733, + -0.030269838869571686, + 0.057014383375644684, + -0.44329890608787537, + 1.0965592861175537, + -1.0767146348953247, + 0.13287265598773956, + 0.517289400100708, + -0.310720294713974, + -0.15501761436462402, + 0.5854693055152893, + -0.12469431757926941, + -1.7694847583770752, + 2.6433238983154297, + -1.596714735031128, + 0.3888415992259979, + -0.02415616251528263, + 0.42178481817245483, + -1.8008503913879395, + 2.8845136165618896, + -1.7628657817840576, + 0.1951047033071518, + 0.11415407806634903, + 0.07305648922920227, + -0.34212157130241394, + 0.46562451124191284, + 0.03175807744264603, + -0.7942091226577759, + 0.6133171319961548, + -0.14596694707870483, + 0.010496735572814941, + -0.03459644690155983, + 0.2948842942714691, + -0.47654271125793457, + 0.2612597346305847, + 0.016025209799408913, + -0.05287598818540573, + -0.01606004498898983, + 0.022197037935256958, + 0.028397703543305397, + -0.0390767939388752, + 0.0037972000427544117, + -0.07010228931903839, + 0.10934390872716904, + 0.017220165580511093, + 0.02215729095041752, + -0.14772991836071014, + 0.2353552132844925, + -0.3846408724784851, + 0.23990634083747864, + -0.02300707995891571, + 0.12085225433111191, + -0.3576957881450653, + 0.6410096883773804, + -0.532350480556488, + -0.002389132045209408, + 0.41821879148483276, + -0.24739143252372742, + -0.10216745734214783, + 0.16793736815452576, + 0.16367803514003754, + -1.1304419040679932, + 1.676539421081543, + -1.064436435699463, + 0.26995453238487244, + -0.07634275406599045, + 0.3324422240257263, + -1.11312997341156, + 1.8095507621765137, + -1.2477567195892334, + 0.3605581820011139, + -0.06627745926380157, + 0.008511146530508995, + -0.19528241455554962, + 0.4320055842399597, + -0.22881783545017242, + -0.18463851511478424, + 0.3064245581626892, + -0.14437103271484375, + 0.02049900032579899, + 0.018321938812732697, + 0.14011529088020325, + -0.26683253049850464, + 0.2172057181596756, + -0.12119362503290176, + 0.025965997949242592, + -0.03424325957894325, + 0.0433838777244091, + 0.1072857677936554, + 0.1997794657945633, + 0.0648089200258255, + -0.06444115936756134, + -0.13146057724952698, + 0.02106364443898201, + -0.22582228481769562, + -0.007233713287860155, + 0.18876874446868896, + -0.5612399578094482, + 0.2632557451725006, + 0.44088244438171387, + 0.11389002948999405, + -0.2791701555252075, + -0.18004432320594788, + 0.8571203947067261, + -1.9517340660095215, + -1.4906251430511475, + 0.3436146676540375, + 0.31222787499427795, + -0.20083315670490265, + -0.217665895819664, + 3.801243782043457, + 1.2014728784561157, + -0.9149202704429626, + 0.6968244910240173, + 0.12756747007369995, + -0.06783506274223328, + -2.086660385131836, + 0.5455523133277893, + 0.49095916748046875, + -0.5991013050079346, + 0.7938552498817444, + -0.1335069239139557, + 0.4730406701564789, + -1.00951087474823, + -0.537578821182251, + -0.49764835834503174, + -1.2683815956115723, + -0.045739322900772095, + -0.16049732267856598, + 0.30239275097846985, + 0.035600025206804276, + 0.6344828605651855, + 0.8256548643112183, + -0.12940075993537903, + 0.09257010370492935, + -0.11000311374664307, + 0.003206665627658367, + -0.008585316129028797, + -0.14573170244693756, + 0.172541081905365, + 0.2107972949743271, + -0.05270108953118324, + -0.08480435609817505, + 0.1914149820804596, + 0.21630872786045074, + -0.23309426009655, + -0.29484814405441284, + -0.1899339109659195, + 0.02601807750761509, + -0.05416746065020561, + 0.20924429595470428, + 0.15566189587116241, + -0.1556546688079834, + -0.23387494683265686, + -0.5112816691398621, + 0.24130745232105255, + -0.049835484474897385, + -0.2685615122318268, + -0.024764614179730415, + 0.5458847880363464, + 0.9501044750213623, + 0.1328524947166443, + 0.21218529343605042, + 0.2524968683719635, + -0.5205130577087402, + -0.3361912667751312, + 1.1678112745285034, + -0.004513490945100784, + -0.9149109125137329, + 0.2125048041343689, + 0.22423015534877777, + -0.08384363353252411, + -0.2866036593914032, + -0.20210212469100952, + -1.2377471923828125, + -0.7704879641532898, + 0.365038126707077, + -0.08308980613946915, + -0.08326874673366547, + 0.456358402967453, + 0.35142943263053894, + 0.19268833100795746, + 0.3706081509590149, + -0.04951317980885506, + 0.10151109844446182, + 0.005193099845200777, + -0.1124582439661026, + -0.08353164792060852, + -0.18709596991539001, + -0.18975794315338135, + 0.17628741264343262, + 0.05536900460720062, + 0.008301885798573494, + -0.1890449970960617, + 0.056875281035900116, + 0.7981322407722473, + -0.05872391164302826, + -0.4860122501850128, + -0.08073797076940536, + 0.13145819306373596, + -0.03608228266239166, + -0.6600452661514282, + 2.243560314178467, + 1.9288626909255981, + -0.5698518753051758, + -0.2486664056777954, + 0.42693793773651123, + 0.2667267322540283, + -4.395429611206055, + -2.15342378616333, + 0.819127082824707, + -0.9362612962722778, + -0.3760467767715454, + 0.5671858787536621, + 2.468177080154419, + -1.6694080829620361, + -0.49952322244644165, + 1.502772569656372, + -1.0188850164413452, + -0.10419629514217377, + -0.36795151233673096, + 1.2645196914672852, + 0.7223924994468689, + 1.751431941986084, + 2.018704891204834, + -0.3197852671146393, + 0.22054125368595123, + -0.19326329231262207, + -0.5307535529136658, + -0.9362435936927795, + -1.0772119760513306, + -0.19870880246162415, + -0.0650869607925415, + -0.0796947032213211, + 0.15733301639556885, + 0.08798394352197647, + 0.0010860684560611844, + 0.05327683687210083, + 0.1107875183224678, + 0.13224183022975922, + 0.08979664742946625, + 0.004348093178123236, + -0.07060158997774124, + -0.19925491511821747, + -0.15811985731124878, + -0.08220887929201126, + -0.022623460739850998, + 0.08509720861911774, + 0.00792989507317543, + -0.14345014095306396, + -0.2720486521720886, + -0.18885627388954163, + -0.11063539236783981, + -0.0355350486934185, + 0.048891279846429825, + -0.12828074395656586, + -0.2712610363960266, + -0.20134924352169037, + -0.1863398402929306, + -0.19976121187210083, + -0.09535074234008789, + 0.009852319024503231, + -0.2776590585708618, + -0.3087778687477112, + -0.21431012451648712, + -0.19772370159626007, + -0.23412325978279114, + -0.11640459299087524, + 0.09514907747507095, + -0.17561811208724976, + -0.29451555013656616, + -0.2381855845451355, + -0.18296842277050018, + -0.18682444095611572, + -0.023345205932855606, + 0.1438502073287964, + 0.02504260651767254, + -0.1554802507162094, + -0.1477985382080078, + -0.07874225080013275, + -0.002977968193590641, + 0.1048416793346405, + -0.1779504120349884, + 0.13204343616962433, + 0.14215172827243805, + 0.049610622227191925, + 0.0888131782412529, + 0.07250366359949112, + 0.0696505531668663, + 0.009899160824716091, + 0.032067786902189255, + 0.08401404321193695, + -0.03567894548177719, + -0.004740188363939524, + -0.0021664693485945463, + -0.011156522668898106, + 0.0821070745587349, + 0.10295391082763672, + -0.0017653254326432943, + -0.16915833950042725, + -0.062223054468631744, + 0.004783258773386478, + 0.038355808705091476, + 0.10124270617961884, + -0.003437258303165436, + -0.18881437182426453, + -0.15905225276947021, + -0.12576808035373688, + -0.11059725284576416, + 0.021587060764431953, + 0.07237453758716583, + -0.1706620156764984, + -0.27434206008911133, + -0.23003827035427094, + -0.20530915260314941, + -0.20856624841690063, + -0.021966496482491493, + 0.13395215570926666, + -0.03810539469122887, + -0.2409798800945282, + -0.2515420913696289, + -0.1872486174106598, + -0.15951117873191833, + 0.04223426431417465, + 0.09909931570291519, + 0.12328703701496124, + -0.057749148458242416, + -0.1300545036792755, + -0.046062104403972626, + 0.019744107499718666, + 0.09484386444091797, + -0.2709728479385376, + 0.03540695831179619, + 0.1206774190068245, + 0.057636432349681854, + 0.10385740548372269, + 0.032486993819475174, + -0.020434774458408356, + -0.10122086852788925, + -0.0023329253308475018, + 0.16941140592098236, + 0.098082534968853, + 0.1250472217798233, + 0.06134447827935219, + -0.025240115821361542, + 0.004181401338428259, + 0.14425808191299438, + 0.17515034973621368, + 0.04739757999777794, + 0.1618604063987732, + 0.1751406490802765, + 0.09162088483572006, + 0.09512057155370712, + 0.13736343383789062, + 0.028775952756404877, + 0.042535409331321716, + 0.08839954435825348, + 0.09229374676942825, + 0.1658262014389038, + 0.09852072596549988, + 0.002680110279470682, + -0.05479496717453003, + -0.03634755313396454, + -0.002902726177126169, + -0.023990361019968987, + 0.1277875006198883, + 0.12727677822113037, + 0.1002269834280014, + -0.040967896580696106, + -0.07101184874773026, + -0.007902896963059902, + 0.019561029970645905, + 0.145268052816391, + 0.017638152465224266, + 0.19240263104438782, + 0.12857146561145782, + 0.05043037235736847, + 0.11596394330263138, + 0.12513381242752075, + 0.12088746577501297, + 0.04333524778485298, + 0.05500142276287079, + 0.05169082432985306, + -0.09941842406988144, + -0.005959822330623865, + -0.032586321234703064, + -0.03065132349729538, + -0.04826900362968445, + 0.14192889630794525, + 0.2543988823890686, + 0.09563885629177094, + -0.28965362906455994, + -0.1341734230518341, + 0.033991701900959015, + -0.22402706742286682, + -0.3190857768058777, + 0.011840387247502804, + 0.9620282053947449, + 1.0609054565429688, + -0.13429726660251617, + -0.20191268622875214, + 0.05324135720729828, + -0.16234318912029266, + -0.9101927280426025, + -1.7916113138198853, + 0.3981992304325104, + 1.3173034191131592, + 0.53525310754776, + 0.18472574651241302, + 0.3719426691532135, + 0.7792536020278931, + -0.027768991887569427, + -2.245561122894287, + -1.2211185693740845, + 0.22817185521125793, + -0.0023349972907453775, + -0.12598364055156708, + 0.06836964190006256, + 0.9917387366294861, + 1.1885775327682495, + -0.2851368486881256, + -0.7428704500198364, + -0.04798422381281853, + -0.00811613816767931, + -0.19619861245155334, + -0.28184008598327637, + 0.0828644260764122, + 0.44643187522888184, + 0.1461745798587799, + -0.005575121380388737, + -0.06604957580566406, + 0.011459077708423138, + 0.03927984461188316, + 0.0634538009762764, + -0.005732079967856407, + -0.01014732290059328, + 0.07607843726873398, + 0.06948187947273254, + -0.010600326582789421, + -0.056259915232658386, + -0.24602480232715607, + -0.01649448834359646, + 0.11143466085195541, + -0.0027401424013078213, + -0.012853104621171951, + 0.08452893793582916, + 0.639316201210022, + 0.5167437195777893, + -0.2775256335735321, + -0.22241903841495514, + -0.07067711651325226, + -0.06368192285299301, + -0.4687917232513428, + -1.1776493787765503, + 0.36015447974205017, + 0.9171182513237, + 0.1905054748058319, + -0.010661551728844643, + 0.10800722986459732, + 0.5352235436439514, + 0.18558207154273987, + -1.5184046030044556, + -0.8130561709403992, + 0.15417319536209106, + 0.0713079422712326, + -0.07369451224803925, + -0.09037846326828003, + 0.6168488264083862, + 0.9663773775100708, + -0.007113471627235413, + -0.33585548400878906, + -0.02738586813211441, + 0.061310965567827225, + -0.0955657884478569, + -0.23896107077598572, + -0.1107473075389862, + 0.1830059289932251, + 0.10748914629220963, + -0.040772341191768646, + -0.05803938955068588, + -0.0004895658930763602, + 0.07664632797241211, + 0.039049405604600906, + -0.002806248841807246, + -0.02642429992556572, + 0.05169009417295456, + -0.036710865795612335, + -0.1002974808216095, + -0.12001149356365204, + -0.08043934404850006, + 0.11466419696807861, + 0.12322796136140823, + 0.07564827799797058, + 0.10148002207279205, + 0.04720174893736839, + 0.14046646654605865, + -0.0819464847445488, + -0.30803975462913513, + -0.0838734582066536, + -0.0801682323217392, + 0.05861072987318039, + 0.04970559477806091, + -0.20592759549617767, + 0.2673366665840149, + 0.2431953400373459, + -0.10027645528316498, + -0.07884806394577026, + -0.09939537942409515, + 0.1181628480553627, + 0.25269386172294617, + -0.3439132571220398, + -0.11160463094711304, + 0.08640077710151672, + 0.07200870662927628, + -0.03449570760130882, + -0.17610406875610352, + -0.021308166906237602, + 0.30556705594062805, + 0.05186203494668007, + -0.004691269714385271, + -0.005278654862195253, + 0.06289899349212646, + 0.052224051207304, + -0.05927770212292671, + -0.1586783081293106, + -0.022610770538449287, + 0.03463536128401756, + 0.004338411148637533, + 0.01452699676156044, + -0.008622901514172554, + 0.010536444373428822, + -0.038111478090286255, + 0.013373414985835552, + 0.007125865668058395, + -0.003420598339289427, + 0.03533756732940674, + 0.0320388600230217, + 0.045789655297994614, + -0.08139114826917648, + -0.03447948023676872, + -0.01453007198870182, + -0.004573625046759844, + 0.10279268026351929, + 0.10881853848695755, + 0.07537791877985, + -0.10887791216373444, + -0.0980544164776802, + -0.06889445334672928, + 0.006558350287377834, + 0.197514146566391, + 0.17890937626361847, + 0.07630149275064468, + -0.16081148386001587, + -0.16685302555561066, + -0.11421715468168259, + -0.013679573312401772, + 0.22477784752845764, + 0.20761631429195404, + 0.07321957498788834, + -0.17697854340076447, + -0.17810045182704926, + -0.1579347848892212, + -0.02679254300892353, + 0.1408146619796753, + 0.15144851803779602, + 0.08801613748073578, + -0.13237154483795166, + -0.13181765377521515, + -0.1279487907886505, + -0.01779216341674328, + 0.08145096898078918, + 0.05625852569937706, + 0.07724357396364212, + -0.04653938114643097, + -0.07479449361562729, + -0.06189379468560219, + -0.04310920089483261, + 0.02028634026646614, + -0.006228619255125523, + 0.03549303859472275, + -0.043929651379585266, + 0.007818001322448254, + 0.00874761026352644, + -0.017027731984853745, + 0.11014463752508163, + 0.0841977447271347, + 0.05960552394390106, + -0.12814101576805115, + -0.0544624924659729, + -0.045333195477724075, + 0.02336869016289711, + 0.22365787625312805, + 0.18523427844047546, + 0.09366372227668762, + -0.20144090056419373, + -0.16367222368717194, + -0.13003699481487274, + 0.0590205080807209, + 0.3301562964916229, + 0.26524844765663147, + 0.09425198286771774, + -0.26156124472618103, + -0.28513699769973755, + -0.21749621629714966, + 0.04356053099036217, + 0.35879984498023987, + 0.29898661375045776, + 0.0977487862110138, + -0.28175386786460876, + -0.2964495122432709, + -0.249031201004982, + 0.028877725824713707, + 0.26395633816719055, + 0.23059280216693878, + 0.09593978524208069, + -0.22489066421985626, + -0.2248908430337906, + -0.19214706122875214, + 0.007535146549344063, + 0.15299226343631744, + 0.09148521721363068, + 0.06946425884962082, + -0.1445557326078415, + -0.11587042361497879, + -0.0978587418794632, + -0.00984917301684618, + -0.012626220472157001, + -0.02837960794568062, + 0.02399199828505516, + -0.005340439733117819, + 0.023224178701639175, + 0.011642432771623135, + 0.003958537708967924, + 0.042965203523635864, + 0.01099414099007845, + 0.024063799530267715, + -0.0702008455991745, + 0.007805663626641035, + 0.0050195748917758465, + 0.017281856387853622, + 0.10123670846223831, + 0.06401767581701279, + 0.02626805007457733, + -0.1073761060833931, + -0.03802435100078583, + -0.014407800510525703, + -0.0006281707319431007, + 0.15516239404678345, + 0.12629136443138123, + 0.033691491931676865, + -0.17609107494354248, + -0.15251316130161285, + -0.07914211601018906, + -0.015578335151076317, + 0.18422608077526093, + 0.1740245372056961, + 0.06139932945370674, + -0.17213505506515503, + -0.1602732092142105, + -0.08922445774078369, + -0.012822975404560566, + 0.13543544709682465, + 0.12543149292469025, + 0.07651004195213318, + -0.13805902004241943, + -0.09661149233579636, + -0.052669934928417206, + -0.03268992528319359, + 0.0391642227768898, + 0.01116940937936306, + 0.04585625231266022, + -0.06474924832582474, + -0.023607701063156128, + -0.007017284631729126, + -0.026150476187467575, + 0.05729387328028679, + -0.10095079243183136, + 0.16617903113365173, + -0.13664309680461884, + 0.026482274755835533, + 0.008411461487412453, + -0.03410203382372856, + 0.022963764145970345, + 0.008903563022613525, + 0.11244194954633713, + -0.20863348245620728, + 0.11064451932907104, + -0.024916114285588264, + 0.009591493755578995, + -0.26092270016670227, + 0.5717483758926392, + -0.38539814949035645, + 0.035056713968515396, + 0.08623965084552765, + -0.016184961423277855, + 0.11129201203584671, + -0.6138678789138794, + 1.3646206855773926, + -1.4969615936279297, + 0.8465064764022827, + -0.2794847786426544, + 0.05826558917760849, + 0.07709132134914398, + -0.5444677472114563, + 1.3013663291931152, + -1.5686073303222656, + 0.9930508732795715, + -0.39188963174819946, + 0.08085884898900986, + -0.05875617265701294, + 0.03498996049165726, + 0.23967482149600983, + -0.3468690514564514, + 0.19146253168582916, + 0.019604403525590897, + -0.027150027453899384, + -0.024670494720339775, + 0.09944183379411697, + -0.11718503385782242, + 0.09772855788469315, + -0.11857263743877411, + 0.09660946577787399, + -0.03638811036944389, + -0.0295167975127697, + 0.1032838523387909, + -0.12557579576969147, + 0.11812210828065872, + -0.08446288853883743, + 0.027706580236554146, + 0.010997293516993523, + -0.06348618865013123, + 0.09578556567430496, + -0.0165568757802248, + -0.014778072014451027, + -0.07772849500179291, + 0.11245536059141159, + -0.043248821049928665, + 0.013345679268240929, + -0.22149333357810974, + 0.6456363797187805, + -0.7280437350273132, + 0.3046833574771881, + 0.06304280459880829, + -0.07310052216053009, + 0.08824795484542847, + -0.65179842710495, + 1.6453673839569092, + -2.046448230743408, + 1.3267604112625122, + -0.42399832606315613, + 0.0010522910160943866, + 0.07953720539808273, + -0.5960973501205444, + 1.5601089000701904, + -2.084894895553589, + 1.4612183570861816, + -0.5491638779640198, + 0.13709494471549988, + -0.09170618653297424, + 0.07287970930337906, + 0.24422486126422882, + -0.4581631124019623, + 0.29479551315307617, + -0.07515113800764084, + -0.012292998842895031, + -0.04451148584485054, + 0.14961428940296173, + -0.15577177703380585, + 0.06323063373565674, + -0.07806269824504852, + 0.07061618566513062, + -0.026793144643306732, + -0.051938362419605255, + 0.13946141302585602, + -0.14129231870174408, + 0.11092118173837662, + -0.08889970183372498, + 0.034787945449352264, + -0.008983314968645573, + -0.04930088296532631, + 0.09856640547513962, + -0.09350966662168503, + 0.07015673816204071, + -0.06468848884105682, + 0.08028972148895264, + -0.02378295361995697, + 0.004251216538250446, + -0.11239825189113617, + 0.2660067081451416, + -0.367576539516449, + 0.2212517410516739, + -0.035011082887649536, + -0.037866897881031036, + 0.11835235357284546, + -0.4868132174015045, + 0.9402765035629272, + -1.0933791399002075, + 0.9518744349479675, + -0.5096855759620667, + 0.12277142703533173, + 0.12916085124015808, + -0.4648635983467102, + 0.8895858526229858, + -1.0776352882385254, + 1.023865818977356, + -0.5914785861968994, + 0.1682877242565155, + -0.05646277964115143, + 0.04132156819105148, + -0.01790236309170723, + -0.059831030666828156, + 0.10092897713184357, + -0.1268356889486313, + 0.013669619336724281, + -0.02746082842350006, + 0.11544085294008255, + -0.2124193012714386, + 0.2733248472213745, + -0.1360178142786026, + 0.025302443653345108, + 0.01249375008046627, + -0.015119954012334347, + 0.017966970801353455, + 0.00269943755120039, + 0.014392177574336529, + 0.007648292928934097, + 0.011665135622024536, + -0.006192799191921949, + 0.004215092398226261, + 0.017718149349093437, + 0.046436555683612823, + 0.044417623430490494, + 0.01518242433667183, + -0.0020157198887318373, + -0.01828707568347454, + -0.029163505882024765, + -0.03131464868783951, + -0.004393945913761854, + 0.048599082976579666, + 0.015757638961076736, + -0.015650734305381775, + -0.002684049541130662, + -0.0697445422410965, + -0.25050923228263855, + -0.4758685231208801, + -0.5382962822914124, + -0.38907238841056824, + -0.12599025666713715, + -0.00266047241166234, + 0.0758173018693924, + 0.26593172550201416, + 0.4203726053237915, + 0.4958920478820801, + 0.3697706162929535, + 0.12434400618076324, + 0.026325728744268417, + 0.022295912727713585, + 0.08135133236646652, + 0.2627769708633423, + 0.26325660943984985, + 0.12326934933662415, + 0.058665141463279724, + 0.04346219077706337, + -0.0013142779935151339, + -0.10037153959274292, + -0.27075886726379395, + -0.28071707487106323, + -0.17300420999526978, + -0.06914675980806351, + 0.004067219793796539, + -0.020674005150794983, + 0.02103183977305889, + 0.0033879741095006466, + 0.013523808680474758, + -0.007318845018744469, + -0.009975744411349297, + -0.02981705591082573, + 0.023193644359707832, + 0.09624253213405609, + 0.1077117845416069, + 0.11186518520116806, + 0.07592211663722992, + 0.04614634811878204, + 0.015908582136034966, + -0.05212458223104477, + -0.1262977123260498, + -0.10974782705307007, + -0.07645918428897858, + -0.06987964361906052, + -0.08783216774463654, + -0.046172842383384705, + -0.22593465447425842, + -0.5281140804290771, + -0.8424770832061768, + -0.9608982801437378, + -0.7363743185997009, + -0.3312055170536041, + -0.10426472127437592, + 0.24067367613315582, + 0.5504152178764343, + 0.81276935338974, + 0.9592635035514832, + 0.7479950785636902, + 0.32608768343925476, + 0.14525265991687775, + 0.15008939802646637, + 0.32246851921081543, + 0.5287250876426697, + 0.5817036032676697, + 0.37340155243873596, + 0.20366452634334564, + 0.1546182781457901, + -0.11224830150604248, + -0.29856279492378235, + -0.5281672477722168, + -0.5890122056007385, + -0.4024880528450012, + -0.23706914484500885, + -0.0641399398446083, + -0.0025121152866631746, + 0.0051757702603936195, + -0.014290476217865944, + 0.0043721878901124, + -0.004783981014043093, + 0.021787043660879135, + -0.004969750996679068, + -0.022116241976618767, + 0.05208030343055725, + 0.07022145390510559, + 0.03730607405304909, + 0.03242917358875275, + 0.04344351217150688, + -0.01189794484525919, + -0.0418211966753006, + -0.059125497937202454, + -0.014576594345271587, + 0.01294493954628706, + -0.011262460611760616, + -0.059920165687799454, + -0.04733816161751747, + -0.12665517628192902, + -0.29677024483680725, + -0.5247481465339661, + -0.6474934816360474, + -0.4751538038253784, + -0.1937171369791031, + -0.05117221921682358, + 0.14646948873996735, + 0.32891425490379333, + 0.5415402054786682, + 0.6071264147758484, + 0.4653589427471161, + 0.18045872449874878, + 0.09937354922294617, + 0.1264665126800537, + 0.18507222831249237, + 0.31783968210220337, + 0.3545042872428894, + 0.22468777000904083, + 0.09973976761102676, + 0.1227618008852005, + -0.07824759930372238, + -0.20465101301670074, + -0.36476215720176697, + -0.38243186473846436, + -0.2540777623653412, + -0.13525226712226868, + -0.03621843457221985, + -0.012233156710863113, + -0.01481863297522068, + -0.04313792288303375, + 0.002874002791941166, + -0.028444716706871986, + -0.04687628522515297, + -0.026806645095348358, + -0.0228339321911335, + -0.015892738476395607, + -0.015550780110061169, + 0.07011140882968903, + 0.0017389585264027119, + -0.05721491947770119, + -0.017484690994024277, + -0.03954736143350601, + -0.006339249666780233, + 0.08166316151618958, + 0.37439921498298645, + 0.2830294966697693, + 0.00668215099722147, + -0.038873329758644104, + -0.012295035645365715, + 0.04932165890932083, + 0.31826695799827576, + 0.8449289202690125, + 0.7123299241065979, + 0.2574000954627991, + 0.04747961834073067, + -0.04416817054152489, + -0.005029442720115185, + 0.2027042657136917, + 0.6639980673789978, + 0.6243636012077332, + 0.21359916031360626, + 0.027929672971367836, + -0.05395142361521721, + -0.04981911554932594, + -0.006375179626047611, + 0.23660773038864136, + 0.2155737280845642, + 0.020577391609549522, + -0.032118700444698334, + -0.02332071214914322, + -0.009217707440257072, + -0.038096409291028976, + 0.05811609327793121, + 0.03776064142584801, + -0.03570764884352684, + -0.042420413345098495, + 0.017812976613640785, + 0.019242385402321815, + 0.030057156458497047, + 0.003040613606572151, + 0.02378096617758274, + 0.04043402150273323, + 0.0243258997797966, + 0.014026327058672905, + 0.005650558043271303, + -0.002831381279975176, + -0.0645776093006134, + -0.03761167451739311, + 0.043774381279945374, + 0.010685136541724205, + 0.031011218205094337, + -0.0025828774087131023, + -0.11959855258464813, + -0.3524792194366455, + -0.30037227272987366, + -0.053334690630435944, + 0.009859252721071243, + 0.0010005333460867405, + -0.04819931834936142, + -0.3154168128967285, + -0.7240553498268127, + -0.6380828022956848, + -0.25695785880088806, + -0.06639125943183899, + 0.03295261785387993, + -0.012727363035082817, + -0.24232468008995056, + -0.6055921912193298, + -0.5679556727409363, + -0.20067356526851654, + -0.03628019988536835, + 0.04774145409464836, + 0.029560575261712074, + -0.038632482290267944, + -0.24032950401306152, + -0.2095729559659958, + -0.006905315909534693, + 0.02563827484846115, + 0.03053808957338333, + 0.0012747920118272305, + 0.004095789045095444, + -0.07932732999324799, + -0.046672020107507706, + 0.02153847925364971, + 0.019504766911268234, + -0.006118285935372114, + 0.0026654782705008984, + 0.013819373212754726, + -0.01078135147690773, + 0.0070082321763038635, + 0.00906399916857481, + 0.010149766691029072, + 0.000516490894369781, + 0.00034157291520386934, + 0.02412085421383381, + 0.006926041562110186, + 0.023299943655729294, + 0.01129852794110775, + -0.0018704778049141169, + 0.016042279079556465, + 0.023886069655418396, + 0.04207555204629898, + -0.0021778997033834457, + 0.041684601455926895, + 0.05059140920639038, + 0.03518521040678024, + -0.0032736151479184628, + -0.0007146652205847204, + 0.015503454953432083, + -0.11896659433841705, + -0.07006713002920151, + 0.007565992418676615, + 0.012584990821778774, + 0.00843358226120472, + 0.017024952918291092, + 0.0359124094247818, + -0.05997823178768158, + -0.04116949439048767, + -0.016472430899739265, + 0.002696823561564088, + 0.00829327292740345, + 0.016238784417510033, + 0.0455794483423233, + 0.0019872160628437996, + -0.005927432328462601, + -0.003552153240889311, + 0.020063765347003937, + 0.00010026743984781206, + 0.01045019831508398, + 0.034689340740442276, + 0.014206668362021446, + 0.015128945000469685, + 0.00972809735685587, + 0.019944868981838226, + 0.020581791177392006, + 0.02938947267830372, + 0.03923909366130829, + 0.03601628914475441, + 0.030168617144227028, + 0.05403255671262741, + 0.03985666483640671, + 0.020015308633446693, + 0.0285494402050972, + 0.013555807992815971, + -0.04409409686923027, + -0.07503483444452286, + 0.01716756261885166, + 0.02053452841937542, + 0.057520389556884766, + 0.02973104454576969, + -0.04563397541642189, + -0.2676408588886261, + -0.30933722853660583, + -0.11671236902475357, + 0.0020135289523750544, + 0.022801443934440613, + -0.03161352127790451, + -0.2704106271266937, + -0.5803710222244263, + -0.5762420296669006, + -0.30449461936950684, + -0.0780220776796341, + 0.017343536019325256, + -0.05319945886731148, + -0.2906038463115692, + -0.598426342010498, + -0.5925986766815186, + -0.31852787733078003, + -0.09950074553489685, + 0.05888299271464348, + 0.01939479075372219, + -0.1060815081000328, + -0.3505017161369324, + -0.3200446665287018, + -0.10609738528728485, + 0.03659524768590927, + 0.056114207953214645, + 0.03447861596941948, + 0.014380007050931454, + -0.09436371922492981, + -0.07562272250652313, + 0.04223132133483887, + 0.06327345967292786, + -0.03735652193427086, + -0.052881840616464615, + -0.058017320930957794, + -0.02474917098879814, + -0.02431381866335869, + -0.0629878118634224, + -0.05212349444627762, + -0.03820814937353134, + -0.0034579068887978792, + -0.004930540919303894, + 0.07968354970216751, + 0.07278168946504593, + 0.015167324803769588, + -0.013638288713991642, + -0.05875609815120697, + -0.008851750753819942, + 0.10708516091108322, + 0.33075177669525146, + 0.3502756953239441, + 0.14791442453861237, + 0.03131852671504021, + -0.028764141723513603, + 0.07454497367143631, + 0.3000347316265106, + 0.6147283315658569, + 0.6289594173431396, + 0.3398674726486206, + 0.13494613766670227, + -0.03705109655857086, + 0.0633230209350586, + 0.3147434592247009, + 0.595033586025238, + 0.594217836856842, + 0.33864542841911316, + 0.11264053732156754, + -0.059276629239320755, + 0.005206871312111616, + 0.14524762332439423, + 0.37473905086517334, + 0.34477534890174866, + 0.12632343173027039, + 0.011062734760344028, + -0.06149457022547722, + -0.028670497238636017, + 0.011082210578024387, + 0.13112866878509521, + 0.1106843650341034, + -0.0025933771394193172, + -0.03781202808022499, + 0.030325254425406456, + 0.017758814617991447, + 0.01635698974132538, + -0.008786264806985855, + -0.0005018062074668705, + 0.005934061016887426, + 0.020206287503242493, + 0.019497420638799667, + -0.01290479488670826, + -0.010817185044288635, + -0.032760608941316605, + -0.026973316445946693, + -0.0021766452118754387, + -0.012848617509007454, + -0.0002560729335527867, + -0.02383977733552456, + -0.05322824791073799, + -0.05382781848311424, + -0.04459262639284134, + -0.04581240937113762, + -0.03465775027871132, + 0.0026904877740889788, + -0.026097090914845467, + -0.05170493200421333, + -0.04981262609362602, + -0.05221042037010193, + -0.05268307775259018, + -0.04735802114009857, + 0.019142162054777145, + -0.019374292343854904, + -0.03312355652451515, + -0.04133244976401329, + -0.033129844814538956, + -0.01844680868089199, + -0.024726904928684235, + 0.0012146441731601954, + -0.025521529838442802, + -0.03120318427681923, + -0.04863203689455986, + -0.021450525149703026, + -0.04190714284777641, + -0.02833862416446209, + 0.017827404662966728, + -0.010181388817727566, + -0.020994380116462708, + -0.04290826618671417, + -0.031555648893117905, + -0.030525390058755875, + -0.024981478229165077, + -0.017512500286102295, + 0.019927235320210457, + 0.00433371402323246, + -0.009276121854782104, + -0.03990143537521362, + -0.021251117810606956, + 0.017825132235884666, + -0.02313065528869629, + 0.012881814502179623, + 0.0009175563463941216, + -0.0656605213880539, + -0.007037178613245487, + 0.023603176698088646, + 0.04873553663492203, + 0.013912673108279705, + 9.78652315097861e-05, + -0.03166677802801132, + -0.11772678792476654, + -0.034320034086704254, + 0.04952533170580864, + 0.10113520920276642, + 0.030472615733742714, + -0.05131377652287483, + -0.1371452510356903, + -0.2326214611530304, + -0.0629519522190094, + 0.12444627285003662, + 0.15845368802547455, + 0.014535457827150822, + -0.06888624280691147, + -0.18798232078552246, + -0.24720685184001923, + -0.04858007654547691, + 0.26889580488204956, + 0.2433905005455017, + -0.01772989332675934, + -0.06027546152472496, + -0.12164203822612762, + -0.20018024742603302, + 0.0035393801517784595, + 0.27190765738487244, + 0.1929154396057129, + -0.012923460453748703, + -0.013931642286479473, + -0.043986693024635315, + -0.0655391663312912, + 0.04751605913043022, + 0.13482201099395752, + 0.06690078228712082, + -0.01862635649740696, + 0.02938506379723549, + 0.01789080537855625, + -0.006509440019726753, + -0.029202938079833984, + -0.023693149909377098, + 0.01042762491852045, + -0.0035929735749959946, + 0.024952176958322525, + -0.013459124602377415, + -0.10798560827970505, + -0.020217353478074074, + 0.017876077443361282, + 0.07628928124904633, + 0.04444783553481102, + 0.012667268514633179, + -0.09012818336486816, + -0.22452381253242493, + -0.07556752860546112, + 0.07942477613687515, + 0.17035256326198578, + 0.0396822914481163, + -0.08236342668533325, + -0.23916372656822205, + -0.3645225763320923, + -0.10748416185379028, + 0.1996970921754837, + 0.3076043725013733, + -0.0033923503942787647, + -0.13259321451187134, + -0.28894615173339844, + -0.3605952262878418, + -0.07969008386135101, + 0.3583948314189911, + 0.4267900586128235, + -0.02228585258126259, + -0.11386624723672867, + -0.21445821225643158, + -0.26956692337989807, + 0.026791207492351532, + 0.37918713688850403, + 0.37130093574523926, + -0.05172214284539223, + -0.05132569745182991, + -0.07469630241394043, + -0.11400169134140015, + 0.07863093167543411, + 0.24061299860477448, + 0.19393151998519897, + -0.03217098489403725, + 0.013085477985441685, + 0.032348379492759705, + 0.03207695484161377, + 0.010604938492178917, + -0.026534704491496086, + -0.018284842371940613, + -0.01768680103123188, + -0.001516501884907484, + 0.013829287141561508, + -0.034318119287490845, + 0.015753330662846565, + -0.0018936718115583062, + 0.014737343415617943, + 0.03306088596582413, + 0.020835628733038902, + -0.03396771103143692, + -0.10758449137210846, + -0.03052518330514431, + 0.020080547779798508, + 0.06180800125002861, + 0.03735671192407608, + -0.037925880402326584, + -0.09720461815595627, + -0.21495617926120758, + -0.06842153519392014, + 0.08532039076089859, + 0.13350333273410797, + 0.03649023920297623, + -0.03904158994555473, + -0.1483580619096756, + -0.2068314403295517, + -0.05687328055500984, + 0.21108660101890564, + 0.21018920838832855, + 0.009318819269537926, + -0.037683792412281036, + -0.09845960140228271, + -0.1535443514585495, + 0.004504916723817587, + 0.20256847143173218, + 0.1799001693725586, + -0.03175490349531174, + -0.020391397178173065, + -0.007309200707823038, + -0.06765769422054291, + 0.013149870559573174, + 0.08469820767641068, + 0.04147877171635628, + -0.0027241194620728493, + 0.008016721345484257, + 0.001382349175401032, + 0.0001219741752720438, + -0.059255484491586685, + -0.03761141747236252, + 0.0381690077483654, + -0.01603613793849945, + 0.0017731477273628116, + -0.016544193029403687, + 0.09518970549106598, + 0.1735895872116089, + 0.005558829288929701, + -0.13464735448360443, + -0.0703420490026474, + 0.001990854274481535, + -0.03426021337509155, + -0.4390500485897064, + -0.11292288452386856, + 0.20430812239646912, + 0.14832687377929688, + 0.06074441969394684, + -0.03749264031648636, + 0.408058226108551, + 0.43119552731513977, + -0.3804298937320709, + -0.3694773018360138, + -0.03696960583329201, + 0.04022200033068657, + -0.0812998041510582, + -0.4322642385959625, + 0.19638888537883759, + 0.7809834480285645, + 0.11584538966417313, + -0.04975399747490883, + -0.015579828992486, + 0.1362757831811905, + 0.027220597490668297, + -0.4703449606895447, + -0.3726261258125305, + 0.11754196882247925, + -0.01204066164791584, + -0.00118898821529001, + -0.05152498185634613, + 0.08767394721508026, + 0.14183296263217926, + 0.01692730002105236, + -0.04587334021925926, + 0.011115594767034054, + 0.021572716534137726, + -0.021584773436188698, + -0.012763801962137222, + 0.05708793178200722, + 0.021982798352837563, + -0.02731800265610218, + 0.03000856563448906, + 0.006653181277215481, + -0.02485630102455616, + -0.20296195149421692, + -0.10483214259147644, + 0.20483383536338806, + 0.1350196748971939, + -0.08543248474597931, + 0.02644401416182518, + 0.26855263113975525, + 0.1071053072810173, + -0.8168368935585022, + -0.6617473363876343, + 0.02877889946103096, + 0.21807144582271576, + -0.02164696715772152, + -0.03712613880634308, + 0.9743875861167908, + 1.1631361246109009, + -0.45643851161003113, + -0.8180081844329834, + -0.28109386563301086, + -0.09115415811538696, + -0.4352502226829529, + -0.7433719038963318, + 0.5383746027946472, + 1.7271664142608643, + 0.509749174118042, + -0.0689467042684555, + 0.010011479258537292, + 0.11752951890230179, + -0.28825971484184265, + -1.113126277923584, + -0.6029489636421204, + 0.357056587934494, + 0.19766344130039215, + 0.023361098021268845, + 0.04305602237582207, + 0.24867205321788788, + 0.16359609365463257, + -0.2485191822052002, + -0.2251967489719391, + 0.030422789976000786, + 0.0049157580360770226, + -0.05497031658887863, + -0.030760835856199265, + 0.034536562860012054, + 0.019565051421523094, + -0.00933124776929617, + 0.01611645519733429, + 0.07988770306110382, + -0.021982649341225624, + -0.21876110136508942, + -0.10555483400821686, + 0.1893070936203003, + 0.14684906601905823, + -0.031080693006515503, + 0.09768003225326538, + 0.3261844515800476, + 0.1466774046421051, + -0.6738073825836182, + -0.5424039363861084, + 0.04689512774348259, + 0.22039148211479187, + -0.07084018737077713, + -0.07436021417379379, + 0.8260523080825806, + 1.0253428220748901, + -0.38162854313850403, + -0.727206289768219, + -0.2605172097682953, + -0.0996573269367218, + -0.3653049170970917, + -0.6791687607765198, + 0.43514078855514526, + 1.4186147451400757, + 0.38797008991241455, + -0.12675431370735168, + 0.02766786515712738, + 0.14237603545188904, + -0.2306709885597229, + -0.9204807877540588, + -0.5071616172790527, + 0.32662850618362427, + 0.20703284442424774, + -0.020968681201338768, + 0.014105334877967834, + 0.24642448127269745, + 0.20103473961353302, + -0.15519124269485474, + -0.22072142362594604, + 0.049920063465833664, + -0.05465548485517502, + 0.018651481717824936, + 0.030082669109106064, + 0.05234164372086525, + 0.10243640840053558, + 0.03569166734814644, + 0.038984544575214386, + 0.05248976871371269, + 0.24501988291740417, + 0.4674161374568939, + 0.7142530083656311, + 0.7423628568649292, + 0.6262048482894897, + 0.4019012451171875, + -0.010997634381055832, + 0.17266513407230377, + 0.4467124342918396, + 0.7795005440711975, + 0.8282667994499207, + 0.6824804544448853, + 0.3955397605895996, + 0.009771074168384075, + 0.10707246512174606, + 0.23039454221725464, + 0.33151063323020935, + 0.36120596528053284, + 0.3240644633769989, + 0.17939962446689606, + -0.01115038525313139, + -0.11081521213054657, + -0.2146066278219223, + -0.3572347164154053, + -0.44021451473236084, + -0.38320258259773254, + -0.24643990397453308, + 0.031578775495290756, + -0.21325217187404633, + -0.4312629997730255, + -0.7276368141174316, + -0.8273008465766907, + -0.718246340751648, + -0.4161607027053833, + -0.06636986136436462, + -0.28078269958496094, + -0.476252943277359, + -0.734549880027771, + -0.7796792984008789, + -0.6637035608291626, + -0.41896238923072815, + 0.021693198010325432, + 0.006199972704052925, + -0.016619624570012093, + -0.010678192600607872, + 0.012267512269318104, + 0.004102918319404125, + -0.004080160986632109, + -0.0029241242446005344, + -0.027252744883298874, + -0.0772257149219513, + -0.09107967466115952, + -0.11302012205123901, + -0.08569496124982834, + -0.07242150604724884, + -0.016465697437524796, + -0.04874062165617943, + -0.09103028476238251, + -0.09025602042675018, + -0.07523388415575027, + -0.06320428103208542, + -0.048220545053482056, + -0.028701437637209892, + -0.008647853508591652, + -0.022354092448949814, + -0.06076030433177948, + -0.030872423201799393, + -0.045786645263433456, + -0.04190178960561752, + 0.03718986362218857, + 0.021405767649412155, + 0.007675759959965944, + 0.02794131636619568, + 0.030316906049847603, + 0.007403802592307329, + 0.04861852154135704, + 0.023217258974909782, + 0.04545973241329193, + 0.07504793256521225, + 0.06824314594268799, + 0.07417462021112442, + 0.0769289955496788, + 0.0766506940126419, + -0.0028638055082410574, + 0.05911175534129143, + 0.055706772953271866, + 0.10735032707452774, + 0.10494870692491531, + 0.11092723160982132, + 0.09338293969631195, + 0.04235343262553215, + -0.022347571328282356, + -0.026347652077674866, + -0.06954608112573624, + -0.06944439560174942, + -0.05570404976606369, + -0.042987462133169174, + -0.056951191276311874, + -0.2151203453540802, + -0.3603246510028839, + -0.5899456143379211, + -0.6453464031219482, + -0.5338351726531982, + -0.31790611147880554, + 0.049492284655570984, + -0.12898015975952148, + -0.40155911445617676, + -0.6737278699874878, + -0.7170611619949341, + -0.5817899703979492, + -0.32979026436805725, + -0.005899591837078333, + -0.07673019915819168, + -0.190496027469635, + -0.34019437432289124, + -0.3314637243747711, + -0.2796767055988312, + -0.1381818801164627, + -0.008025999180972576, + 0.08429048955440521, + 0.2105528861284256, + 0.3415210545063019, + 0.4151126444339752, + 0.34003961086273193, + 0.21059827506542206, + -0.03514896333217621, + 0.1792585551738739, + 0.3903186321258545, + 0.6413942575454712, + 0.7557680010795593, + 0.6069726943969727, + 0.3415443003177643, + 0.03447553142905235, + 0.21517080068588257, + 0.4215562045574188, + 0.6151171922683716, + 0.6550290584564209, + 0.5680058002471924, + 0.33561068773269653, + -0.12205997854471207, + -0.0038300298620015383, + 0.3281119763851166, + -0.2328944057226181, + -0.03834507241845131, + 0.05432930961251259, + -0.014430212788283825, + 0.006271198857575655, + 0.32864242792129517, + 0.47277259826660156, + -0.5593215227127075, + -0.14971251785755157, + 0.13066314160823822, + -0.09738356620073318, + 0.2966129779815674, + 0.5606555342674255, + -0.3184640407562256, + -2.022890090942383, + -0.361995667219162, + 0.5496177673339844, + 0.02796279452741146, + -0.21818380057811737, + -0.5373459458351135, + -1.9538941383361816, + -1.9984712600708008, + 1.6747761964797974, + 1.5063239336013794, + -0.24534250795841217, + -0.040306344628334045, + -0.16963164508342743, + -0.40690454840660095, + 1.3548375368118286, + 3.922116279602051, + 0.8723023533821106, + -0.8986141681671143, + 0.06912416964769363, + 0.2192920595407486, + 0.352949321269989, + 1.2243634462356567, + 1.1395865678787231, + -1.5146961212158203, + -1.1557590961456299, + -0.05440744385123253, + -0.04629289731383324, + -0.002693743444979191, + -0.21906790137290955, + -0.5464610457420349, + -1.1933224201202393, + 0.01913866586983204, + 0.09363497048616409, + -0.06080613285303116, + -0.049100056290626526, + 0.04482033848762512, + -0.04087500274181366, + -0.009318803437054157, + 0.009458474814891815, + -0.09565524011850357, + -0.2264278084039688, + -0.0698866918683052, + 0.13825084269046783, + 0.014815542846918106, + -0.05801662430167198, + 0.012776852585375309, + -0.0753035843372345, + -0.07555855065584183, + 0.484436959028244, + 0.6397283673286438, + 0.12687323987483978, + -0.01779526099562645, + 0.05689511448144913, + 0.06747376173734665, + 0.26353734731674194, + 0.5908273458480835, + 0.4315526783466339, + -0.5426794290542603, + -0.44501280784606934, + -0.019558124244213104, + -0.03320806100964546, + -0.025809556245803833, + 0.17376014590263367, + -0.5201969742774963, + -1.2842578887939453, + -0.3674038052558899, + 0.0882175862789154, + -0.030023137107491493, + -0.1173325777053833, + 0.02555503323674202, + -0.39882710576057434, + -0.37364596128463745, + 0.3550366163253784, + 0.3903135359287262, + 0.04022252932190895, + 0.016731394454836845, + 0.11207644641399384, + -0.020967213436961174, + -0.028497911989688873, + 0.37590932846069336, + 0.14920172095298767, + 0.029958104714751244, + 0.039632707834243774, + -0.24969367682933807, + 0.16809938848018646, + 0.07703239470720291, + -0.03522319719195366, + -0.007072617299854755, + 0.07751759141683578, + -0.06782346963882446, + -0.4010501801967621, + 0.41269779205322266, + 0.1311105638742447, + -0.07331988960504532, + 0.08240311592817307, + -0.20034979283809662, + -0.4718745946884155, + -0.178948312997818, + 1.3285318613052368, + 0.20384186506271362, + -0.48546233773231506, + -0.09941625595092773, + 0.13249020278453827, + 0.29977336525917053, + 1.2681238651275635, + 1.5725642442703247, + -1.0834472179412842, + -1.0335719585418701, + 0.25975045561790466, + 0.06584863364696503, + 0.1609305590391159, + 0.25940945744514465, + -0.8426372408866882, + -2.590407609939575, + -0.4723183214664459, + 0.7581043243408203, + -0.03634117543697357, + -0.10199672728776932, + -0.3744191527366638, + -0.7823801636695862, + -0.7062401175498962, + 1.116550087928772, + 0.7735803127288818, + 0.012776976451277733, + 0.034575968980789185, + -0.10188565403223038, + 0.2212170958518982, + 0.5182898044586182, + 0.8056022524833679, + -0.1897655427455902, + -0.005556725896894932, + -0.003909373190253973, + -0.02175678312778473, + -0.04085654392838478, + -0.03573022410273552, + -0.0038509985897690058, + 0.02454996667802334, + 0.039437733590602875, + 0.02077251859009266, + 0.02166259102523327, + 0.17245841026306152, + 0.09513862431049347, + -0.10491111874580383, + -0.08084940910339355, + -0.026179829612374306, + 0.0215831957757473, + -0.16602416336536407, + -0.2803819179534912, + 0.23894084990024567, + 0.3269801735877991, + 0.04504352807998657, + 0.0009768904419615865, + 0.01959501951932907, + 0.24426960945129395, + -0.1451571136713028, + -0.5944203734397888, + -0.17875447869300842, + 0.028336334973573685, + 0.004323791246861219, + -0.045389141887426376, + 0.0343034490942955, + 0.46665430068969727, + 0.3707427978515625, + -0.114569291472435, + 0.04335101321339607, + -0.018011711537837982, + -0.021181274205446243, + -0.19074901938438416, + -0.20113815367221832, + 0.048786211758852005, + 0.08533122390508652, + -0.06084573268890381, + 0.01217757910490036, + 0.030666939914226532, + 0.05272842198610306, + 0.010849648155272007, + -0.05913804844021797, + -0.04202868044376373, + -0.0015147016383707523, + -0.03421122953295708, + 0.015080726705491543, + 0.12191007286310196, + 0.10450142621994019, + -0.04972418025135994, + -0.07557133585214615, + -0.02221665158867836, + -0.0861242413520813, + -0.14919178187847137, + -0.04388582333922386, + 0.4605262875556946, + 0.5697804093360901, + 0.1583399623632431, + -0.045628566294908524, + -0.05220475420355797, + -0.13630147278308868, + -0.7103163599967957, + -1.0178179740905762, + 0.1927143931388855, + 0.7479860186576843, + 0.47013771533966064, + 0.16943301260471344, + 0.2398149073123932, + 0.4710526168346405, + -0.5974176526069641, + -1.8564051389694214, + -0.7726883292198181, + 0.05584309995174408, + 0.08902852982282639, + 0.0931839719414711, + 0.46213099360466003, + 1.2080260515213013, + 0.6001025438308716, + -0.590207576751709, + -0.4145379662513733, + -0.04529324173927307, + -0.08303339034318924, + -0.2470429688692093, + -0.03481363505125046, + 0.4808541238307953, + 0.4001348614692688, + -0.1292688548564911, + -0.03635162487626076, + -0.006270444020628929, + -0.0314505510032177, + -0.13043232262134552, + -0.10837803781032562, + 0.10718243569135666, + 0.07523836195468903, + -0.00597786670550704, + 0.06580565124750137, + 0.11166563630104065, + 0.021869506686925888, + -0.10510984063148499, + -0.07651247084140778, + 0.01229890063405037, + -0.08976037800312042, + -0.14929910004138947, + -0.018859578296542168, + 0.4408939778804779, + 0.4029107689857483, + -0.05015433207154274, + -0.13887189328670502, + -0.04514491930603981, + -0.07346425950527191, + -0.5277182459831238, + -0.7335640788078308, + 0.24182197451591492, + 0.626846432685852, + 0.23399080336093903, + 0.09675730019807816, + 0.15529058873653412, + 0.42680656909942627, + -0.4012089967727661, + -1.3605350255966187, + -0.4793834686279297, + 0.10987094044685364, + 0.07592830061912537, + 0.003319029463455081, + 0.24004696309566498, + 0.9590277671813965, + 0.4946591258049011, + -0.4889579117298126, + -0.34744441509246826, + -0.020535729825496674, + -0.026767954230308533, + -0.2090117186307907, + -0.11841326951980591, + 0.37452432513237, + 0.39960840344429016, + -0.07025045901536942, + -0.022984744980931282, + 0.022319970652461052, + -0.0027356306090950966, + -0.13681942224502563, + -0.09797768294811249, + 0.09914079308509827, + 0.10856777429580688, + ] + value = numpy.array(list_value, dtype=numpy.float32).reshape((64, 3, 7, 7)) + tensor = numpy_helper.from_array(value, name="onnx::Conv_501") + + initializers.append(tensor) + + list_value = [ + 3.085598945617676, + 2.2436060905456543, + 4.244357585906982, + 1.4069645404815674, + -4.00622034072876, + 2.595770835876465, + 2.7202603816986084, + 2.4405417442321777, + 1.1759933233261108, + 2.021026372909546, + 2.6628992557525635, + 6.445226192474365, + -7.029932498931885, + 1.1305793523788452, + 2.537140369415283, + 5.456772327423096, + 4.780154705047607, + 10.039976119995117, + 2.912492275238037, + 15.781542778015137, + 2.5154318809509277, + 2.628824472427368, + 2.2992050647735596, + 2.0950584411621094, + -7.93365478515625, + 2.067786931991577, + 4.094852447509766, + 1.673399806022644, + 3.1814424991607666, + 22.49496078491211, + 2.232640027999878, + 2.6427979469299316, + -9.418174743652344, + 1.790976643562317, + 2.3774726390838623, + 2.5836219787597656, + 2.5608203411102295, + 2.287343978881836, + 2.6439085006713867, + 16.859027862548828, + 1.8699607849121094, + -3.6987526416778564, + 2.6861538887023926, + 2.8997464179992676, + 2.689293384552002, + 2.6654043197631836, + 2.3799915313720703, + 2.5603086948394775, + 3.146122694015503, + 2.715951681137085, + 2.889486789703369, + 2.966134548187256, + -4.960191249847412, + 2.6123547554016113, + 1.3074164390563965, + 2.2033026218414307, + 2.2114620208740234, + 4.132844924926758, + 4.893764495849609, + 2.6469600200653076, + 2.654136896133423, + 1.9311997890472412, + 2.881012439727783, + 2.6991193294525146, + ] + value = numpy.array(list_value, dtype=numpy.float32) + tensor = numpy_helper.from_array(value, name="onnx::Conv_502") + + initializers.append(tensor) + + list_value = [ + 0.057212892919778824, + 0.06299274414777756, + -0.018499961122870445, + -0.06501776725053787, + -0.015820641070604324, + 0.024293724447488785, + 0.05624663084745407, + -0.025112055242061615, + 0.043546054512262344, + 0.08439744263887405, + 0.005678815301507711, + 0.0034800865687429905, + 0.030301403254270554, + -0.011669250205159187, + -0.005434689112007618, + -0.1591511219739914, + 0.02324092946946621, + -0.018942436203360558, + 0.025366367772221565, + -0.07414374500513077, + 0.03468436002731323, + -0.003742520697414875, + -0.06651683896780014, + 0.005561002530157566, + 0.04527103528380394, + -0.13710148632526398, + 0.0025444801431149244, + 0.03583350405097008, + 0.015219246037304401, + -0.053635064512491226, + 0.004856681916862726, + -0.07223699986934662, + 0.016770021989941597, + 0.0012010147329419851, + 0.014582094736397266, + -0.005172556731849909, + 0.02009868621826172, + -0.0064261858351528645, + -0.029086023569107056, + 0.001915874076075852, + 0.0008194410474970937, + 0.01620865799486637, + 0.03067426010966301, + -0.0018463254673406482, + 0.05358384922146797, + -0.003966080490499735, + -0.05991416424512863, + -0.06455761194229126, + 0.01634763367474079, + -0.013959774747490883, + 0.03615918383002281, + 0.004434086848050356, + 0.02086004987359047, + -0.004025993403047323, + -0.8869641423225403, + 0.05558132007718086, + 0.024729542434215546, + -0.005809253081679344, + -0.025079259648919106, + 0.04757235199213028, + 0.0023902510292828083, + 0.01522061601281166, + 0.011692625470459461, + 0.023033330217003822, + -0.012664714828133583, + -0.29325294494628906, + -0.006855700630694628, + -0.243958979845047, + 0.0024398649111390114, + -0.060877203941345215, + -0.21996521949768066, + -0.008708474226295948, + -0.06639625877141953, + -0.03170674294233322, + -0.09708897024393082, + 0.013403226621448994, + 0.024766888469457626, + 0.2594103217124939, + -0.02221749909222126, + 0.0662861093878746, + -0.15123076736927032, + -0.010314224287867546, + -0.0029192541260272264, + 0.05985910817980766, + 0.021665453910827637, + 0.003247617743909359, + -0.006802591495215893, + 0.00772367138415575, + 0.0399332195520401, + 0.005198766943067312, + 0.006013805978000164, + -0.04212838411331177, + -0.03166411817073822, + 0.13363900780677795, + 0.006383878644555807, + -0.05536859482526779, + 0.02053261175751686, + 0.015062958002090454, + 0.03352641686797142, + -0.2944328486919403, + 0.019855381920933723, + -0.15567174553871155, + -0.06759943068027496, + 0.07467031478881836, + 0.01674237661063671, + 0.004549413453787565, + -0.0032498433720320463, + -0.1837870180606842, + -0.04725493863224983, + -0.111307792365551, + 0.022237055003643036, + 0.004200428258627653, + 0.00970534235239029, + -0.045657914131879807, + -0.024577995762228966, + 0.0035376595333218575, + 0.008936531841754913, + -0.03904002904891968, + 0.05013228952884674, + -0.011168933473527431, + -0.008444730192422867, + 0.0035155978985130787, + -0.023502476513385773, + 0.005275514908134937, + -0.09448224306106567, + -0.009177467785775661, + -0.010720008052885532, + 0.004110944457352161, + -0.0060218218713998795, + 0.058124978095293045, + -0.0016586220590397716, + 0.15812785923480988, + -0.049118027091026306, + -0.007983109913766384, + -0.04265601187944412, + -0.01627231575548649, + 0.33705562353134155, + 0.01555223111063242, + 0.035853929817676544, + 0.0005046340520493686, + 0.054810188710689545, + -0.08808254450559616, + -0.0013819067971780896, + -0.14938786625862122, + -0.019771935418248177, + 0.004152575507760048, + 0.021979758515954018, + 0.1985529363155365, + -0.07694264501333237, + 0.013187955133616924, + -0.016572976484894753, + -0.03094586730003357, + -0.03673199936747551, + -0.03916170820593834, + -0.003836784977465868, + -0.012262578122317791, + 0.005559554789215326, + 0.1488093137741089, + -0.01842501200735569, + -0.004847189411520958, + -0.02391587756574154, + 0.015824301168322563, + 0.012022596783936024, + 0.06724318116903305, + -0.032682593911886215, + 0.00450896704569459, + -0.0024625889491289854, + 0.00933725107461214, + -0.04473242908716202, + 0.06270455569028854, + -0.02062271721661091, + -0.01071448065340519, + -0.017757099121809006, + 0.01575278490781784, + -0.06489317119121552, + -0.01519051194190979, + 0.0028058059979230165, + 0.00917835533618927, + -0.01291860081255436, + -0.009537308476865292, + 0.041757628321647644, + 0.03203853219747543, + -0.10918509215116501, + -0.007152496371418238, + -0.06777876615524292, + 0.03223242610692978, + 0.01780836284160614, + -0.09791012853384018, + -0.009385241195559502, + 0.013184775598347187, + 0.0031673219054937363, + -0.010640445165336132, + 0.024713385850191116, + -0.026738369837403297, + -0.004191657993942499, + -0.13764967024326324, + -0.003720735665410757, + 0.01737186871469021, + 0.015459887683391571, + 0.033229030668735504, + 0.008042111992835999, + -0.007184108253568411, + 0.008226306177675724, + 0.0031303109135478735, + 0.0406314842402935, + -0.8669105768203735, + 0.02079751342535019, + -0.17030003666877747, + -0.03849703446030617, + 0.034153200685977936, + -0.007219486869871616, + 0.11227627843618393, + -0.2681085467338562, + 0.015872526913881302, + 0.10855260491371155, + -0.008631505072116852, + 0.02556358277797699, + 0.06043418496847153, + -0.012900532223284245, + -0.08834894001483917, + 0.028099440038204193, + -0.05156330019235611, + 0.032628703862428665, + 0.044928934425115585, + 0.006176372990012169, + 0.007333829998970032, + -0.037409231066703796, + -0.046724822372198105, + -0.011172871105372906, + 0.04603327810764313, + 0.03288746625185013, + -0.20848578214645386, + 0.0028185085393488407, + -0.032673876732587814, + 0.061944279819726944, + 0.016787173226475716, + 0.02703898213803768, + -0.0060023171827197075, + 0.06870592385530472, + 0.03154531493782997, + 0.02784041129052639, + 0.007780189625918865, + 0.02033168077468872, + 0.0019289497286081314, + 0.02545374445617199, + 0.04262726008892059, + 0.01301807351410389, + -0.023882156237959862, + 0.027872221544384956, + -0.013518108054995537, + -0.0031075032893568277, + 0.03753834590315819, + 0.0369209349155426, + -0.014378191903233528, + 0.004397932440042496, + -0.030286893248558044, + -0.007679021451622248, + -0.045032769441604614, + 0.032050322741270065, + -0.03373495861887932, + -0.04363032802939415, + 0.034301597625017166, + -0.07021668553352356, + 0.03942524269223213, + -0.11061309278011322, + 0.049139462411403656, + 0.04161922261118889, + -0.01507576834410429, + -0.012748259119689465, + 0.06599434465169907, + 0.007602245546877384, + -0.03973209857940674, + -0.06923151016235352, + 0.026153067126870155, + -0.04221056029200554, + -0.4828230142593384, + 0.03360651433467865, + 0.01847662217915058, + -0.08594681322574615, + 0.04071836546063423, + -0.0035729086957871914, + 0.0049045816995203495, + -0.036198534071445465, + 0.03046257793903351, + 0.013275806792080402, + 0.09266786277294159, + -0.03625647351145744, + -0.059672992676496506, + 0.050213005393743515, + -0.018153885379433632, + -0.0858495831489563, + 0.01621098257601261, + -0.03029749169945717, + 0.02193332649767399, + 0.0422661192715168, + 0.6109512448310852, + -0.01068826112896204, + -0.02184930257499218, + -0.03213764354586601, + -0.03148162364959717, + -0.055331334471702576, + 0.006972005590796471, + -0.00815682765096426, + 0.014874683693051338, + -0.012943249195814133, + -0.03318992629647255, + -0.0010484680533409119, + 0.005414161365479231, + -0.013610370457172394, + 0.008836873807013035, + -0.05890084058046341, + -0.022663919255137444, + -0.018899116665124893, + -0.01037894282490015, + 0.005064660683274269, + 0.08522599190473557, + 0.0075323861092329025, + 0.013720778748393059, + 0.032096460461616516, + -0.008450351655483246, + 0.020377663895487785, + 0.04537765309214592, + 0.014030816033482552, + 0.024340089410543442, + 0.0231801588088274, + -0.10347768664360046, + 0.041163086891174316, + -0.060614243149757385, + -0.09241361171007156, + 0.05831432715058327, + -0.16008608043193817, + -0.04505622759461403, + 0.04866329953074455, + -0.0656094029545784, + 0.09627313911914825, + 0.1153625100851059, + 0.008151216432452202, + 0.03813345730304718, + 0.05990723893046379, + 0.24788673222064972, + 0.06294118613004684, + 0.11761849373579025, + -0.0722033903002739, + -0.013892017304897308, + -0.016778236255049706, + 0.038522012531757355, + -0.015539593063294888, + 0.01263216882944107, + 0.0003969807003159076, + -0.0224238783121109, + -0.005919966846704483, + 0.031987495720386505, + -0.014712700620293617, + 0.03508169203996658, + 0.07568854838609695, + -0.011961974203586578, + 0.027983952313661575, + -0.03512958809733391, + -0.010324078612029552, + -0.2895449995994568, + 0.007338976487517357, + -0.042290836572647095, + -0.1640917807817459, + -0.034807007759809494, + -0.1268443465232849, + 0.18418198823928833, + -0.3867812156677246, + -0.14214494824409485, + 0.001021744217723608, + 0.11288078874349594, + 0.006741920951753855, + -0.006421610247343779, + 0.021150892600417137, + 0.02486848644912243, + 0.002660338068380952, + 0.03732302784919739, + 0.10844919830560684, + -0.032568808645009995, + 0.009477612562477589, + 0.053578171879053116, + -0.07421902567148209, + 0.05660263076424599, + 0.03038308583199978, + 0.049440011382102966, + 0.0395139642059803, + 0.0217339675873518, + 0.028231965377926826, + 0.1661153882741928, + -0.02168717049062252, + 0.055143170058727264, + -0.14159196615219116, + 0.05894732475280762, + 0.006888065952807665, + -0.06988262385129929, + 0.017527412623167038, + -0.007171930745244026, + -0.00448343763127923, + 0.02932717651128769, + -0.00652179354801774, + -0.002897858154028654, + 0.020487705245614052, + -0.027063967660069466, + -0.02539752423763275, + -0.1066114604473114, + -0.10011029988527298, + -0.03331710025668144, + -0.003807300003245473, + -0.010441976599395275, + -0.005605363752692938, + 0.09679440408945084, + 0.020033519715070724, + -0.010188378393650055, + -0.030630890280008316, + -0.00955540407449007, + 0.02825581096112728, + -0.4307324290275574, + 0.012557203881442547, + 0.043258048593997955, + 0.09386534243822098, + -0.009555542841553688, + 0.05304868891835213, + 0.014706632122397423, + -0.012911850586533546, + 0.0981304720044136, + -0.010722141712903976, + -0.027317194268107414, + 0.0893903523683548, + -0.19983792304992676, + -0.15778200328350067, + -0.1012115329504013, + -0.3758164644241333, + -0.05782865360379219, + -0.01230492815375328, + -0.37126046419143677, + -0.01596723683178425, + 0.0020407456904649734, + -0.017498979344964027, + 0.005369496997445822, + -0.023121315985918045, + 0.022279681637883186, + -0.006232256535440683, + 0.05115891620516777, + 0.006679570768028498, + 0.0026316209696233273, + 0.04291496425867081, + 0.04381528124213219, + -0.05994122102856636, + 0.007081915624439716, + -0.04571640491485596, + 0.07592425495386124, + -0.00836833007633686, + 0.008123279549181461, + -0.008003163151443005, + -0.003938044421374798, + 0.005643180105835199, + 0.016194086521863937, + -0.004063089843839407, + 0.012334472499787807, + 0.017072021961212158, + 0.005761854816228151, + 0.004702428821474314, + 0.005736868362873793, + 0.0017962371930480003, + 0.059996701776981354, + 0.19533602893352509, + 0.02649352326989174, + -0.06493135541677475, + -0.05955052375793457, + 0.015692468732595444, + -0.10623155534267426, + 0.07290898263454437, + 0.036108434200286865, + -0.01248949021100998, + 0.16444285213947296, + -0.005899128969758749, + 0.07875277101993561, + 0.0014204353792592883, + 0.03381470963358879, + -0.09680792689323425, + 0.002102318685501814, + 0.026962973177433014, + 0.031665392220020294, + -0.18168538808822632, + 0.11163855344057083, + -0.5409999489784241, + 0.07833191007375717, + -0.005324948113411665, + 0.0267564058303833, + 0.02250477857887745, + 0.03249068558216095, + -0.18441715836524963, + -0.006447427906095982, + 0.037927329540252686, + 0.0005173985846340656, + -0.02617005631327629, + 0.05929232016205788, + -0.028510913252830505, + 0.05447050556540489, + 0.012390155345201492, + 0.00046797769027762115, + -0.008598590269684792, + -0.17247197031974792, + -0.02855759859085083, + 0.033968932926654816, + -0.09011702984571457, + 0.05276056379079819, + 0.03299655020236969, + -0.005699596833437681, + -0.1954648792743683, + 0.011109501123428345, + -0.0013570536393672228, + -0.6543989181518555, + 0.009102803654968739, + 0.0407538004219532, + 0.04312055557966232, + 0.027609223499894142, + -0.035538043826818466, + 0.027167823165655136, + -0.024043193086981773, + 0.0047575319185853004, + -0.006788836792111397, + 0.025714389979839325, + 0.007848678156733513, + -0.07680192589759827, + 0.009700766764581203, + -0.0097329281270504, + 0.00586724653840065, + 0.022815868258476257, + -0.023448282852768898, + -0.05608998239040375, + 0.10786863416433334, + -0.02803603559732437, + 0.012898198328912258, + -0.009270391426980495, + -0.021972229704260826, + 0.26533082127571106, + -0.01021308358758688, + -0.01972626894712448, + 0.062940314412117, + 0.022569671273231506, + 0.027042347937822342, + -0.05669092759490013, + -0.01200617104768753, + -0.006279367487877607, + -0.009608528576791286, + -0.013600943610072136, + -0.02187415212392807, + 0.0351138636469841, + 0.006282923277467489, + -0.011123511008918285, + -0.009205769747495651, + 0.001010146806947887, + -0.4796978235244751, + -0.0030205894727259874, + -0.011987377889454365, + -0.027548225596547127, + 0.009372347965836525, + -0.005388603545725346, + -0.006444129627197981, + -0.02501147985458374, + 0.027465635910630226, + 0.027784524485468864, + 0.006878893356770277, + -0.027763860300183296, + -0.0047700353898108006, + -0.018965192139148712, + 0.027898501604795456, + 0.022454144433140755, + 0.02973407506942749, + 0.03505602851510048, + 0.04003170132637024, + -0.004336829297244549, + -0.01998550072312355, + -0.06097743660211563, + -0.07844759523868561, + 0.0013787010684609413, + 0.0066132270731031895, + -0.03124997951090336, + 0.0313432514667511, + 0.047656893730163574, + 0.06175797060132027, + -0.02077358029782772, + -0.004535601008683443, + -0.10219905525445938, + -0.07125344127416611, + -0.06927482783794403, + -0.04813461750745773, + -0.02618095651268959, + -0.01255929097533226, + -0.009180150926113129, + -0.005838831886649132, + 0.09108023345470428, + -0.032710760831832886, + 0.03091445378959179, + -0.01955563761293888, + 0.0959300771355629, + -0.09353741258382797, + -0.0761636272072792, + -0.023445438593626022, + -0.012328366748988628, + 0.05850536748766899, + -0.052494827657938004, + 0.0025638933293521404, + -0.017152179032564163, + -0.004435579292476177, + 0.12312240898609161, + -0.007241012528538704, + 0.09605048596858978, + 0.03355967625975609, + -0.015987426042556763, + -0.03470349311828613, + -0.02499505691230297, + -0.015004142187535763, + -0.018609771504998207, + -0.06654462963342667, + 0.013861652463674545, + -0.005973289255052805, + -0.04734775796532631, + 0.08755116909742355, + 0.03012942522764206, + 0.07887610793113708, + -0.01827712170779705, + 0.10793066769838333, + 0.10793614387512207, + -0.01075535174459219, + 0.03439560532569885, + 0.011567444540560246, + 0.0016386889619752765, + -0.031207261607050896, + -0.01707504875957966, + 0.20471863448619843, + 0.0025428179651498795, + 0.004082779865711927, + -0.012389302253723145, + 0.0400562584400177, + -0.21075034141540527, + 0.012872264720499516, + -0.01639414019882679, + 0.016652485355734825, + 0.0016037120949476957, + -0.006540367379784584, + -0.0068405005149543285, + -0.2484254390001297, + 0.0008089764742180705, + -0.022340824827551842, + -0.005441636312752962, + 0.002882100408896804, + 0.008654038421809673, + 0.07159754633903503, + -0.02537086047232151, + 0.011997461318969727, + -0.49913132190704346, + -0.02300887741148472, + 0.044442202895879745, + 0.001787978457286954, + 0.010291379876434803, + 0.009601960889995098, + -0.5312613248825073, + -0.014247804880142212, + 0.06685849279165268, + 0.035772595554590225, + 0.03432310372591019, + 0.03151272237300873, + -0.10318460315465927, + -0.030476456508040428, + -0.004469831008464098, + -0.16645164787769318, + -0.021104637533426285, + 0.013934006914496422, + -0.011767406016588211, + 0.008054615929722786, + 0.06089277192950249, + 0.0003409573109820485, + -0.0053401123732328415, + 0.05970478057861328, + -0.004363172687590122, + 0.014423285610973835, + -0.002795026171952486, + -0.019875092431902885, + -0.07540513575077057, + -0.09043378382921219, + 0.00750827556475997, + -0.045314721763134, + -0.00724808732047677, + 0.005193864461034536, + -0.020468784496188164, + -0.01098695583641529, + -0.0003122477210126817, + -0.007263806648552418, + -0.03325646370649338, + 0.021689830347895622, + -0.13272541761398315, + 0.02332465350627899, + -0.019292252138257027, + 0.05533658340573311, + -0.018616480752825737, + -0.015228793025016785, + -0.28432801365852356, + -0.29721561074256897, + 0.04648810625076294, + -0.014750649221241474, + -0.15370936691761017, + -0.1497083604335785, + 0.013243601657450199, + 0.042343802750110626, + -0.017519792541861534, + -0.0161418616771698, + 0.00807454064488411, + -0.023562468588352203, + -0.0315413773059845, + 0.03386805206537247, + 0.2854529917240143, + 0.0191020630300045, + -0.49126777052879333, + 0.052687134593725204, + -0.023298051208257675, + -0.009119837544858456, + 0.05149759724736214, + -0.8527837991714478, + 0.08062390983104706, + 0.057379938662052155, + -0.020724931731820107, + -0.006624895613640547, + 0.05322050303220749, + 0.017887847498059273, + 0.04229281470179558, + 0.04171830415725708, + 0.029683062806725502, + -0.00028416322311386466, + 0.1112222746014595, + -0.0448714978992939, + -0.005255761090666056, + 0.017773712053894997, + -0.0016064767260104418, + -0.013840594328939915, + -0.00398495327681303, + -4.32919041486457e-05, + 0.040796443819999695, + 0.018185198307037354, + -0.018671950325369835, + 0.0028256692457944155, + -0.020582057535648346, + 0.05567716807126999, + -0.056062404066324234, + 0.01614757999777794, + -0.0029299987945705652, + 0.048686008900403976, + 0.04299888014793396, + 0.12249592691659927, + 0.01469603180885315, + -0.1254546344280243, + -0.18532024323940277, + -0.003263876074925065, + 0.014804725535213947, + 0.004450956825166941, + -0.013681051321327686, + -0.0030781759414821863, + -0.03433656692504883, + -0.0035507124848663807, + 0.1600082814693451, + -0.028547707945108414, + -0.00989136379212141, + -0.012126478366553783, + -0.12963305413722992, + 0.008547360077500343, + 0.017959514632821083, + -0.012571084313094616, + 0.0008666724897921085, + -0.010519342496991158, + -0.009684977121651173, + -0.04285729303956032, + 0.015031769871711731, + -0.030043724924325943, + 0.018907636404037476, + 0.08019450306892395, + -0.04836742579936981, + 0.01025464478880167, + -0.004908542148768902, + -0.10327022522687912, + -0.10163667798042297, + -0.03403499722480774, + -0.019678063690662384, + -0.043049123138189316, + 0.0384567566215992, + -0.05596519634127617, + -0.09381429851055145, + -0.18688108026981354, + -0.09762943536043167, + -0.03164997324347496, + -0.006416287273168564, + 0.07003920525312424, + -0.016646990552544594, + -0.025972194969654083, + -0.028768088668584824, + -0.06332779675722122, + 0.045144014060497284, + -0.03735211119055748, + -0.010442189872264862, + 0.10948455333709717, + 0.14629514515399933, + -0.023416690528392792, + -0.01347778458148241, + 0.020830679684877396, + 0.0003131759003736079, + 0.007049075793474913, + 0.06547018885612488, + 0.03152740001678467, + 0.08380027115345001, + 0.03185325488448143, + -0.015359007753431797, + 0.08864206075668335, + 0.032676901668310165, + -0.002908645663410425, + 0.053111132234334946, + 0.0026159954722970724, + -0.05177146941423416, + -0.033048152923583984, + -0.0020293137058615685, + -0.07363513857126236, + -0.17662747204303741, + 0.004798125941306353, + 0.07139395922422409, + 0.019802849739789963, + 0.009199771098792553, + -0.009043877013027668, + -0.07681646943092346, + -0.06748555600643158, + 0.05094710737466812, + 0.0014789587585255504, + -0.0166088305413723, + -0.27988284826278687, + 0.03634800389409065, + 0.05322619527578354, + -0.15566207468509674, + -0.019964642822742462, + -0.010204506106674671, + -0.011832086369395256, + -0.0680927112698555, + -0.05793820694088936, + 0.0020100779365748167, + -0.24647225439548492, + 0.04904041066765785, + -0.05589786171913147, + -0.030167482793331146, + 0.023974033072590828, + -0.22719347476959229, + 0.019620347768068314, + -0.18078163266181946, + -0.11321499198675156, + -0.023790234699845314, + -0.1266157031059265, + 0.01117659267038107, + 0.13824795186519623, + -0.024211348965764046, + -0.0548308864235878, + 0.04849318787455559, + -0.0016174454940482974, + -0.01826266385614872, + 0.006709347013384104, + -0.350631982088089, + 0.03139018639922142, + 0.021502504125237465, + -0.12596893310546875, + 0.04311670735478401, + -0.005905786994844675, + -0.0807335153222084, + -0.07214773446321487, + -0.2054852843284607, + -0.04526854678988457, + -0.09145382046699524, + 0.002603817731142044, + -0.01951524056494236, + -0.0028278473764657974, + -0.03270411863923073, + -0.0003385065938346088, + -0.019816655665636063, + -0.003430107608437538, + 0.010664679110050201, + 0.030127109959721565, + 0.02611778862774372, + 0.030213139951229095, + 0.04682943969964981, + 0.010338326916098595, + -0.02618880569934845, + 0.014982170425355434, + -0.06979402899742126, + 0.06403722614049911, + 0.025545112788677216, + -0.11981001496315002, + 0.004320457112044096, + 0.008849565871059895, + 0.07450827211141586, + -0.04322020336985588, + -0.07648278027772903, + 0.009221173822879791, + -0.12771189212799072, + 0.027474528178572655, + -0.1637975573539734, + -0.022587651386857033, + 0.0713210329413414, + -0.09652210026979446, + -0.04942077025771141, + -0.08977267891168594, + -0.004629603121429682, + -0.09891843795776367, + 0.0004028059483971447, + 0.12999524176120758, + 0.009417874738574028, + -0.012465995736420155, + 0.09959464520215988, + 0.012048770673573017, + 0.00529639283195138, + -0.1231047734618187, + -0.010156300850212574, + -0.0067022680304944515, + 0.09231371432542801, + 0.1372271031141281, + 0.01140755694359541, + -0.014376018196344376, + 0.009014246053993702, + -0.0558021254837513, + 0.009297777898609638, + -0.023461824283003807, + 0.12312523275613785, + 0.0013492326252162457, + -0.10130659490823746, + 0.07867099344730377, + -0.04363301396369934, + -0.05203291028738022, + 0.010715829208493233, + 0.2679101228713989, + 0.047242000699043274, + 0.009700302965939045, + -0.004188477993011475, + 0.04595324397087097, + -0.10256988555192947, + 0.013266253285109997, + 0.13415516912937164, + -0.06461263447999954, + -0.04262775555253029, + 0.014638054184615612, + -0.020396970212459564, + 0.016008291393518448, + 0.012964261695742607, + 0.030219901353120804, + -0.03906702250242233, + -0.009459082037210464, + -0.006880247965455055, + 0.009383107535541058, + 0.0591101311147213, + -0.049882922321558, + -0.014105924405157566, + -0.04896679148077965, + 0.021726086735725403, + -0.013863577507436275, + -0.05801064148545265, + -0.031143831089138985, + 0.0010298469569534063, + -0.03104572743177414, + 0.1193046048283577, + 0.00880056619644165, + -0.01678626798093319, + 0.0014990485506132245, + -0.001967367948964238, + -0.0053575835190713406, + -0.006879259832203388, + -0.008937212638556957, + 0.014141763560473919, + 0.00687083275988698, + -0.0012949275551363826, + 0.017160816118121147, + -0.035110652446746826, + -0.00976842176169157, + 0.026605995371937752, + 0.004003277514129877, + 0.010927689261734486, + 0.002173327375203371, + -0.05133439600467682, + -0.04658171907067299, + 0.03023359179496765, + -0.015038624405860901, + 0.016580749303102493, + 0.02393144741654396, + 0.004817661829292774, + -0.008468102663755417, + 0.017239807173609734, + 0.019924553111195564, + 0.02557404898107052, + 0.01985766738653183, + -0.01881517469882965, + -0.14637643098831177, + -0.005403783638030291, + -0.013156545348465443, + -0.3882855176925659, + 0.01537711638957262, + 0.005061861593276262, + 0.018044542521238327, + 0.00010373388067819178, + -0.01769324019551277, + -0.020439250394701958, + 0.01761222817003727, + 0.017716309055685997, + -0.01828574948012829, + 0.0059916484169662, + 0.006117791403084993, + -0.0025541253853589296, + 0.01598154753446579, + 0.0015296537894755602, + 0.006711189169436693, + -0.005831963382661343, + 0.024547481909394264, + 0.011665170080959797, + 0.013990279287099838, + -0.009193074889481068, + -0.0014407691778615117, + 0.0025373499374836683, + -0.001535113900899887, + 0.022016262635588646, + 0.002165747107937932, + -0.00010288839985150844, + -0.01185672264546156, + 0.3959958255290985, + -0.06701132655143738, + 0.024550342932343483, + -0.007259713020175695, + 0.00011224728223169222, + 0.08959072828292847, + 0.006745494436472654, + -0.007461291737854481, + -0.0010788652580231428, + -0.003997487016022205, + 0.0023250498343259096, + 0.005845727398991585, + 0.002441686810925603, + 0.0010628585005179048, + 0.004687050357460976, + 0.03825820982456207, + 0.0027951127849519253, + 0.004356732591986656, + 0.0036379920784384012, + -0.00048690394032746553, + -0.31681910157203674, + 0.01621195860207081, + 0.009373913519084454, + -0.005099120549857616, + 0.004866141825914383, + 0.008112045004963875, + -0.009933174587786198, + -0.006929770577698946, + 0.005561198107898235, + -0.2225065976381302, + -0.00019208311277907342, + -0.003284667618572712, + 0.010527989827096462, + -0.010160842910408974, + -0.008410060778260231, + 0.004605174530297518, + 0.01542133092880249, + 0.013958578929305077, + 0.0021779180970042944, + 0.002810562262311578, + 0.001369283301755786, + -0.0003347232413943857, + 0.013902815990149975, + -0.0022218015510588884, + 0.00024955783737823367, + -0.0019350153161212802, + 0.0025213193148374557, + -0.0054915109649300575, + -0.00011564489977899939, + -0.0037644850090146065, + -0.002863431815057993, + -0.0025196163915097713, + 0.02352992817759514, + 0.00354134407825768, + -0.010700036771595478, + -0.03428381308913231, + 0.008170859888195992, + 0.005420713219791651, + -0.0013479178305715322, + 0.0015741022070869803, + -0.18286381661891937, + 0.03189067915081978, + 0.0014371845172718167, + -4.885893940809183e-05, + -0.004666821099817753, + -0.026595929637551308, + -0.0064376350492239, + 0.01583540253341198, + -0.085715651512146, + -0.00916224904358387, + -0.3605174124240875, + 0.019973354414105415, + 0.05533794313669205, + 0.053907446563243866, + 0.030877795070409775, + -0.919844925403595, + 8.968543988885358e-05, + -0.02068270742893219, + 0.012602192349731922, + 0.03245612978935242, + 0.06622699648141861, + 0.00882122665643692, + -0.03616628423333168, + -0.02428283728659153, + 0.003318701172247529, + -0.0007259293342940509, + -0.026197656989097595, + -0.059503961354494095, + 0.029495801776647568, + -0.006955073680728674, + -0.01926456019282341, + 0.009927013888955116, + 0.059641581028699875, + 0.0016886347439140081, + -0.029346982017159462, + 0.01948450319468975, + -0.04397860914468765, + 0.025248751044273376, + 0.04597266763448715, + 0.009454794228076935, + -0.018872544169425964, + -0.039650529623031616, + 0.026324709877371788, + -0.01808176562190056, + 0.028935831040143967, + 0.009501701220870018, + -0.05183069407939911, + -0.005787428934127092, + -0.021436212584376335, + 0.029735956341028214, + 0.0350160151720047, + 0.033825185149908066, + 0.03185566887259483, + 0.018431033939123154, + 0.02450188808143139, + 0.03271135315299034, + -0.0027792940381914377, + -0.0004625302099157125, + 0.01268392987549305, + 0.045023106038570404, + 0.05562014505267143, + 0.029052015393972397, + -0.002513203304260969, + -0.08349838852882385, + 7.017837560852058e-06, + -0.0014392733573913574, + 0.016982918605208397, + 0.016358936205506325, + -0.024013325572013855, + -0.004375616554170847, + -0.03734249249100685, + 0.04336351156234741, + 0.07323610782623291, + -0.0243068914860487, + 0.009403819218277931, + 0.02663031965494156, + 0.01930687017738819, + 0.02175578847527504, + 0.01639295555651188, + 0.024892140179872513, + 0.031219134107232094, + 0.02986173704266548, + -0.002100786194205284, + 0.05054357647895813, + 0.04015854373574257, + 0.0048207067884504795, + -0.03244275599718094, + 0.027246609330177307, + 0.00409608893096447, + -0.0054193479008972645, + 0.07014931738376617, + 0.009954879060387611, + 0.022472694516181946, + -0.47738370299339294, + -0.019097158685326576, + 0.028984038159251213, + -0.042564358562231064, + -0.006040808744728565, + 0.04094231128692627, + -0.007740774191915989, + -0.07854597270488739, + 0.003920051269233227, + -0.050799619406461716, + 0.023691626265645027, + 0.019952887669205666, + 0.00716764759272337, + -0.0046928380616009235, + 0.00041822553612291813, + 0.006359069608151913, + 0.017860781401395798, + -0.22999149560928345, + -0.02180831879377365, + -0.024055887013673782, + -0.0226126741617918, + -0.01795077696442604, + 0.015591473318636417, + -0.004053472075611353, + 0.016760380938649178, + 0.03378744795918465, + -0.0027090508956462145, + 0.00999806821346283, + 0.019252799451351166, + 0.0027550198137760162, + 0.03454355522990227, + -0.0295003242790699, + -0.007663591764867306, + 0.061172280460596085, + 0.049142658710479736, + -0.00858291145414114, + -0.0035321018658578396, + -0.7689260244369507, + 0.0004916944890283048, + 0.02915046364068985, + 0.017000442370772362, + -0.003298018593341112, + -0.0405484102666378, + 0.021160880103707314, + 0.0013289587805047631, + -0.07510386407375336, + 0.03890690207481384, + 0.03729970380663872, + -0.04906352981925011, + -0.10020274668931961, + 0.01506283599883318, + -0.053726132959127426, + 0.016631007194519043, + 0.03425036743283272, + 0.03358260169625282, + -0.023937245830893517, + -0.13656578958034515, + -0.13947314023971558, + 0.012915699742734432, + 0.02431132085621357, + -0.03089652583003044, + 0.1382707953453064, + 0.056695129722356796, + -0.09263960272073746, + 0.10406216233968735, + 0.02619105577468872, + -0.01678614132106304, + -0.16045455634593964, + 8.974489173851907e-05, + -0.03521093726158142, + -0.028908027336001396, + 0.21234789490699768, + -0.02046572044491768, + -0.09703273326158524, + 0.05248226970434189, + 0.011973158456385136, + 0.004557646345347166, + -0.018632734194397926, + -0.1649131029844284, + -0.00682018743827939, + -0.12712189555168152, + 0.10513507574796677, + 0.020745709538459778, + 0.02996259182691574, + -0.15409024059772491, + -0.08719073981046677, + -0.14634187519550323, + -0.16255779564380646, + -0.15963757038116455, + -0.1324772834777832, + -0.022830091416835785, + -0.06426219642162323, + -0.025459224358201027, + 0.00281702633947134, + 0.03255268186330795, + -0.05778049677610397, + -0.30381152033805847, + -0.06582051515579224, + -0.033722274005413055, + 0.014956191182136536, + 0.004153797868639231, + 0.2391217201948166, + -0.0311420951038599, + 0.001518488978035748, + 0.019769812002778053, + -0.056324463337659836, + -0.006009253207594156, + -0.21367721259593964, + -0.0481688529253006, + 0.22422266006469727, + 0.0402204655110836, + 0.1432792693376541, + 0.14159953594207764, + -0.0025862890761345625, + -0.028965365141630173, + 0.011978867463767529, + 0.161293163895607, + 0.028642605990171432, + -0.008417634293437004, + -0.10145614296197891, + 0.08381767570972443, + 0.05199432373046875, + 0.18680602312088013, + -0.023287687450647354, + 0.03601476550102234, + 0.03738229721784592, + 0.19291405379772186, + 0.03553088754415512, + 0.05483124405145645, + 0.09577616304159164, + -0.004635817836970091, + 0.052481625229120255, + -0.042084019631147385, + -0.2629147469997406, + -0.006157668773084879, + -0.0401761569082737, + 0.02154349908232689, + -0.056558139622211456, + -0.003753019031137228, + 0.01922912523150444, + 0.1291409730911255, + -0.21358416974544525, + 0.004696246236562729, + 0.13787509500980377, + -0.07022479176521301, + -0.06828727573156357, + 0.09193858504295349, + -0.06863763928413391, + -0.05677935853600502, + -0.030970478430390358, + -0.10181070864200592, + -0.1247706487774849, + 0.014181962236762047, + -0.09259836375713348, + -0.03174220770597458, + -0.014812505804002285, + -0.024658311158418655, + -0.04815720021724701, + -0.01683010160923004, + 0.015726473182439804, + 0.002938281511887908, + -0.1586887538433075, + -0.29276973009109497, + -0.029981529340147972, + -0.046828676015138626, + -0.04909103736281395, + 0.06043976545333862, + 0.03698069602251053, + -0.04807118698954582, + 0.0943484902381897, + 0.01930702105164528, + 0.06498143821954727, + 0.0381690077483654, + -0.19611406326293945, + 0.006944946013391018, + 0.06454038619995117, + -0.19779883325099945, + 0.04966692253947258, + 0.046355295926332474, + 0.0590626522898674, + -0.24392037093639374, + -0.0018132536206394434, + 0.010944955050945282, + -0.014556891284883022, + 0.051466893404722214, + -0.0059846509248018265, + -0.06719732284545898, + 0.030604040250182152, + 0.051190104335546494, + -0.053196243941783905, + -0.06912374496459961, + -0.06263922154903412, + 0.05626852437853813, + 0.013047950342297554, + -0.005828890949487686, + 0.056055404245853424, + 0.007044378202408552, + 0.030499491840600967, + -0.035373322665691376, + 0.030934391543269157, + 0.04358363524079323, + 0.001537138712592423, + 0.005963161122053862, + -0.005889860913157463, + 0.053225863724946976, + 0.052091702818870544, + -0.02871675044298172, + 0.05662619322538376, + -0.4585985839366913, + 0.06490323692560196, + 0.02542230300605297, + 0.017592567950487137, + 0.05066920816898346, + -0.20954127609729767, + -0.06689731031656265, + -0.3632309138774872, + -0.03407476842403412, + 0.04976007342338562, + 0.03856723755598068, + 0.009329214692115784, + -0.10107281804084778, + 0.007077769376337528, + -0.005482642911374569, + 0.04388934373855591, + 0.03984231874346733, + 0.005358297843486071, + 0.05032944679260254, + 0.007170544005930424, + 0.017318176105618477, + -0.03577208146452904, + -0.02195456624031067, + 0.014414021745324135, + -0.008203372359275818, + 0.04585091397166252, + -0.012298643589019775, + 0.03959968313574791, + -0.06015963852405548, + -0.1360240876674652, + -0.07704123109579086, + -0.0842466950416565, + -0.11261942237615585, + 0.0433686338365078, + -0.1059969812631607, + 0.014813154004514217, + 0.04216694459319115, + 0.10441470146179199, + 0.04579426348209381, + 0.026033954694867134, + 0.08725529909133911, + -0.14662955701351166, + -0.0726592168211937, + 0.1293957382440567, + 0.013497715815901756, + -0.01318936888128519, + -0.05188713222742081, + 0.08793413639068604, + 0.1094818189740181, + 0.07991892844438553, + 0.03549068048596382, + -0.04469897970557213, + -0.10442564636468887, + 0.13456915318965912, + 0.01154977548867464, + -0.05959299951791763, + 0.01768219843506813, + 0.0179652888327837, + -0.010112428106367588, + 0.020603090524673462, + -0.7144030928611755, + 0.20126283168792725, + 0.058172807097435, + -0.10543914139270782, + 0.07461538910865784, + -0.1744592934846878, + 0.055722273886203766, + -0.046595826745033264, + 0.06237049773335457, + 0.05800141766667366, + 0.04118870943784714, + 0.002582935383543372, + 0.010623090900480747, + -0.0439014658331871, + 0.044685740023851395, + -0.017063472419977188, + -0.0173367727547884, + -0.04761765897274017, + 0.06136244907975197, + 0.08495236933231354, + 0.24923592805862427, + -0.061080869287252426, + 0.15922360122203827, + -0.09322690963745117, + -0.09617402404546738, + 0.0029533954802900553, + 0.12630371749401093, + 0.0011397749185562134, + 0.0005059551913291216, + -0.060922350734472275, + -0.16446451842784882, + 0.057099178433418274, + 0.03073902614414692, + -0.031064951792359352, + 0.012277435511350632, + 0.020447896793484688, + 0.06010727211833, + 0.07065457105636597, + 0.026963504031300545, + 0.010798406787216663, + -0.02631279267370701, + 0.02046871930360794, + -0.004800989292562008, + -0.03282550349831581, + 0.053904879838228226, + -0.03294985368847847, + -0.4204113185405731, + 0.028552187606692314, + 0.023685462772846222, + 0.0017703581834211946, + 0.02868991158902645, + -0.3585520088672638, + -0.011516556143760681, + -0.00248165475204587, + 0.011379038915038109, + 0.0459531806409359, + 0.015357235446572304, + 0.05573337897658348, + 0.06516549736261368, + 0.02981666848063469, + 0.05498211458325386, + 0.028714550659060478, + -0.005899528972804546, + 0.008476868271827698, + 0.11328839510679245, + 0.020578190684318542, + -0.15382742881774902, + 0.015724696218967438, + -0.08402770012617111, + 0.060314107686281204, + 0.032343748956918716, + 0.014438764192163944, + -0.13614842295646667, + -0.0017508765449747443, + 0.09998518973588943, + -0.06364594399929047, + 0.049632295966148376, + -0.11922458559274673, + -0.08834195137023926, + 0.019541991874575615, + 0.06320779770612717, + 0.017419861629605293, + -0.0028468866366893053, + -0.14753428101539612, + 0.02623703144490719, + -0.011462770402431488, + 0.06676206737756729, + -0.014891563914716244, + -0.002118025440722704, + 0.02519390918314457, + -0.29581141471862793, + 0.0264339130371809, + 0.04027356952428818, + 0.00412194337695837, + 0.03778498247265816, + -0.012331741861999035, + 0.15336745977401733, + -0.034510836005210876, + 0.0319819413125515, + 0.01916184462606907, + 0.04952343553304672, + -0.026733938604593277, + -0.014996573328971863, + 0.0010714810341596603, + 0.01959756202995777, + -0.0392388179898262, + -0.0052064210176467896, + -0.05015777423977852, + -0.0002977418771479279, + -0.04029487073421478, + -0.012846150435507298, + -0.09198840707540512, + 0.0118671590462327, + -0.06176264211535454, + 0.006427878048270941, + 0.04043034091591835, + -0.017270859330892563, + -0.012422707863152027, + 0.01713552325963974, + -0.026697810739278793, + 0.2446632832288742, + -0.020500628277659416, + -0.0012782106641680002, + -0.13429665565490723, + 0.07528743892908096, + -0.002225265372544527, + 0.06695574522018433, + 0.0017388156848028302, + -0.0629071593284607, + -0.05081196129322052, + 0.042025983333587646, + 0.029097404330968857, + 0.07048555463552475, + -0.11881273239850998, + 0.012633765116333961, + -0.06181430071592331, + 0.038810230791568756, + 0.05186169967055321, + 0.03248963877558708, + 0.07868267595767975, + 0.024977494031190872, + 0.023991582915186882, + 0.0023529180325567722, + 0.07197123020887375, + 0.02653665468096733, + 0.058702051639556885, + 0.015001803636550903, + 0.043739400804042816, + -0.07251746207475662, + 0.045659150928258896, + -0.02111324854195118, + 0.26666632294654846, + 0.1975221484899521, + -0.031074335798621178, + 0.029075143858790398, + 0.013020229525864124, + 0.015244663693010807, + 0.01387549377977848, + -0.025354426354169846, + 0.06151636317372322, + -0.034430794417858124, + 0.00752665288746357, + 0.1678706705570221, + -0.016560610383749008, + 0.0421285480260849, + -0.02527586743235588, + -0.02166694961488247, + -0.034658536314964294, + 0.036866605281829834, + -0.036233626306056976, + 0.02042747661471367, + 0.028099242597818375, + 0.020503878593444824, + 0.022789381444454193, + 0.08666791766881943, + -0.06426636874675751, + -0.043599683791399, + 0.1136128157377243, + 0.020200412720441818, + -0.003839759388938546, + -0.06010120362043381, + -0.02218424715101719, + 0.09008956700563431, + 0.008711264468729496, + -0.04874516651034355, + -0.011533043347299099, + -0.036206502467393875, + -0.006006627343595028, + -0.0350450798869133, + 0.005623341538012028, + 0.09562186151742935, + -0.03952183946967125, + -0.013931595720350742, + -0.020029470324516296, + 0.0022144403774291277, + -0.020198611542582512, + 0.012238736264407635, + 0.054415784776210785, + -0.024457741528749466, + -0.01174110360443592, + 0.031656913459300995, + 0.060322560369968414, + 0.01573050767183304, + 0.03361794352531433, + 0.022875478491187096, + 0.036340806633234024, + -0.02932620421051979, + 0.0224352665245533, + -0.013475337065756321, + -0.030774995684623718, + 0.013921404257416725, + -0.01229875348508358, + -0.07986237108707428, + -0.007543445099145174, + 0.05208213999867439, + -0.04440496116876602, + -0.029659371823072433, + -0.029070377349853516, + 0.07376870512962341, + -0.07208643853664398, + -0.05429431423544884, + -0.007887271232903004, + 0.011400371789932251, + 0.014227204024791718, + 0.01763899251818657, + -0.0426466204226017, + 0.0024213625583797693, + 0.02564665488898754, + 0.0020850151777267456, + 0.027386819943785667, + 0.12722602486610413, + -0.060991525650024414, + -0.009061425924301147, + 0.014208497479557991, + -0.006956137716770172, + 0.09096626192331314, + 0.0037735258229076862, + -0.8347064852714539, + -0.2857951521873474, + 0.0011818337952718139, + 0.0341162234544754, + -0.04230167716741562, + 0.05230262130498886, + 0.08486262708902359, + -0.34235459566116333, + -0.02393503487110138, + 0.02718495950102806, + 0.050966840237379074, + 0.024611525237560272, + -0.004936584271490574, + -0.036420952528715134, + -0.009803534485399723, + 0.05421328917145729, + 0.008357672952115536, + 0.020987343043088913, + -0.007292840629816055, + 0.018060531467199326, + 0.06739793717861176, + 0.06161382421851158, + 0.000842935056425631, + -0.007857701741158962, + 0.023870037868618965, + -0.009690430946648121, + -0.04231289029121399, + -0.22531479597091675, + 0.034284885972738266, + 0.07360551506280899, + 0.0421777106821537, + 0.000788167177233845, + -0.3953339457511902, + -0.042627450078725815, + -0.02774403616786003, + 0.02647743932902813, + -0.01561375055462122, + 0.04745408892631531, + 0.021774733439087868, + 0.006606150884181261, + 0.03879173845052719, + 0.06500626355409622, + 0.044954728335142136, + 0.01523532159626484, + 0.04741065576672554, + -0.13645507395267487, + 0.0038059696089476347, + -0.012993253767490387, + -0.004529603291302919, + 0.03268986567854881, + -0.025349941104650497, + -0.02268051542341709, + -0.0001516443444415927, + -0.010289257392287254, + -0.0010476588504388928, + -0.0690254345536232, + 0.04298266023397446, + -0.05470968782901764, + 0.04369102790951729, + -0.007372597698122263, + 0.027607066556811333, + 0.0009343988494947553, + -0.09573916345834732, + 0.04389296472072601, + -0.01522558368742466, + -0.03138086944818497, + 0.04511113464832306, + -0.0342172235250473, + -0.00033129166695289314, + -0.037289440631866455, + 0.055575959384441376, + 0.01849759928882122, + 0.03041103295981884, + -0.01965116336941719, + 0.07604960352182388, + -0.0399625338613987, + -0.008190250024199486, + -0.015386211685836315, + -0.04315667226910591, + 0.0023679479490965605, + 0.018971435725688934, + -0.005599244497716427, + -0.029607947915792465, + 0.07574024051427841, + -0.013816094025969505, + 0.04464992880821228, + 0.00032806122908368707, + 0.06071484833955765, + 0.04261377081274986, + 0.012208743952214718, + 0.0801805928349495, + 0.02875029854476452, + -0.0662921741604805, + 0.015754999592900276, + 0.05831082537770271, + 0.03810921683907509, + 0.05483977496623993, + -0.019509335979819298, + 0.0032034649048000574, + 0.011807492934167385, + -0.01916244812309742, + 0.022101666778326035, + -0.0366031751036644, + 0.10915965586900711, + 0.030322788283228874, + -0.028386037796735764, + -0.05443429946899414, + -0.02489445172250271, + 0.0892239362001419, + -0.05427740886807442, + -0.034238025546073914, + -0.04136161506175995, + -0.041148390620946884, + 0.06879492849111557, + -0.37424594163894653, + 0.028803903609514236, + 0.05349116027355194, + 0.0359492301940918, + -0.3629145622253418, + -0.17875684797763824, + -0.012246759608387947, + 0.2744927704334259, + -0.010421697050333023, + -0.19415415823459625, + 0.005668101832270622, + 0.018326066434383392, + 0.28319111466407776, + -0.008164885453879833, + -0.07401272654533386, + -0.04154321923851967, + 0.030028337612748146, + -0.008959534578025341, + -0.03160349279642105, + -0.0191870778799057, + 0.044875819236040115, + 0.052173007279634476, + 0.012135458178818226, + 0.008775291964411736, + 0.005302258301526308, + 0.009224606677889824, + -0.07574712485074997, + 0.06096252053976059, + 0.02645082212984562, + 0.05135556682944298, + 0.021985528990626335, + 0.0076704383827745914, + 0.02961125783622265, + -0.07608609646558762, + -0.17564956843852997, + 0.03679918497800827, + -0.2696506083011627, + 0.0627906322479248, + 0.031165480613708496, + 0.01799822598695755, + 0.02351829782128334, + 0.015595306642353535, + -0.25137314200401306, + -0.011266927234828472, + 0.04895596578717232, + 0.01718883402645588, + 0.0009224268142133951, + 0.021923478692770004, + 0.044791676104068756, + 0.079147569835186, + 0.02014082670211792, + -0.0003547854721546173, + -0.02535748854279518, + -0.029639363288879395, + -0.01965961419045925, + -0.37630724906921387, + 0.01674639992415905, + 0.01316642016172409, + -0.025120021775364876, + -0.12474260479211807, + 0.059980470687150955, + 0.036066047847270966, + -0.15973420441150665, + -0.010871605016291142, + 0.014708316884934902, + -0.2174367904663086, + 0.012985467910766602, + -0.03782057762145996, + -0.003427069401368499, + -0.011010636575520039, + 0.02433733455836773, + 0.08641276508569717, + -0.004630533047020435, + 0.019430357962846756, + -0.02088969387114048, + -0.06182911619544029, + 0.02577812969684601, + 0.015741532668471336, + 0.04723552614450455, + -0.003783567575737834, + 0.11646346747875214, + 0.01827184483408928, + -0.0999741181731224, + -0.0031216999050229788, + -0.002268272452056408, + -0.019456079229712486, + -0.003156653605401516, + 0.0067732855677604675, + 0.027299508452415466, + 0.06979037076234818, + 0.013329057022929192, + -0.016705401241779327, + 0.33774301409721375, + 0.007617524825036526, + 0.044453222304582596, + 0.0016282782889902592, + 0.0010982973035424948, + 0.04183036834001541, + 0.016857653856277466, + 0.006673034280538559, + -0.0187662523239851, + 0.0037163379602134228, + -0.04568779841065407, + -0.007807960733771324, + 0.016653010621666908, + 0.0033014933578670025, + 0.015063234604895115, + 0.012843966484069824, + -0.012042546644806862, + 0.016909126192331314, + 0.022089935839176178, + -0.002550398698076606, + 0.04166745766997337, + -0.0014742743223905563, + -0.010846617631614208, + -0.12333541363477707, + 0.0018612967105582356, + 0.04913188889622688, + -0.029431112110614777, + 0.01824735291302204, + 0.10425490140914917, + -0.08880072832107544, + 0.03029320202767849, + 0.018876856192946434, + 0.016104502603411674, + 0.00882721971720457, + 0.0029782119672745466, + 0.007922517135739326, + -0.02030068263411522, + -0.029835309833288193, + 0.006661414168775082, + -0.04313879832625389, + -0.001850730157457292, + -0.0035070034209638834, + -0.0070700813084840775, + 0.009637435898184776, + -0.016844747588038445, + -0.026075454428792, + 0.0030682040378451347, + 0.004208600614219904, + -0.005515689495950937, + -0.018976539373397827, + -0.019196776673197746, + -0.008948019705712795, + 0.016215825453400612, + 0.00296461652033031, + 0.14222395420074463, + -0.029066482558846474, + -0.011013337410986423, + -0.01267730537801981, + -0.004976287949830294, + -0.016607511788606644, + -0.0005681798211298883, + -0.012520174495875835, + -0.0015903630992397666, + -0.0013642794219776988, + -0.21956196427345276, + -0.0011431180173531175, + -0.0008808697457425296, + -0.022889399901032448, + 0.024718068540096283, + -0.054929111152887344, + -0.015585094690322876, + -0.018188318237662315, + -0.0008287815726362169, + -0.01957552134990692, + 0.10818513482809067, + -0.0034382494632154703, + -0.02667389065027237, + -0.01304248720407486, + -0.0034645304549485445, + -0.008519704453647137, + -0.015123830176889896, + -0.008219013921916485, + -0.009952309541404247, + -2.3375787350232713e-05, + -0.012512428686022758, + -0.001955948770046234, + -0.0029842876829206944, + -0.004291659686714411, + 0.006655955221503973, + 0.007771315053105354, + 0.014132227748632431, + -0.007390063256025314, + -0.024650415405631065, + -0.022503213956952095, + 0.0032607221510261297, + -0.008497492410242558, + 0.00860870536416769, + 0.002819088753312826, + -0.01841069757938385, + -0.010009711608290672, + -0.2912862300872803, + 0.017160022631287575, + 0.11349690705537796, + -0.027656083926558495, + -0.04482223838567734, + -0.019336597993969917, + 0.07413014769554138, + 0.014554106630384922, + 0.020965611562132835, + -0.028231356292963028, + -0.0582813061773777, + 0.05617539584636688, + -0.05042734369635582, + 0.025630727410316467, + -0.0956532284617424, + -0.14554104208946228, + -0.020851148292422295, + 0.006990485824644566, + 0.08457829803228378, + -0.11314752697944641, + 0.004020951222628355, + -0.03477870300412178, + 0.005594289395958185, + 0.011181964538991451, + 0.010988114401698112, + 0.019416088238358498, + 0.026451971381902695, + -0.00452260859310627, + 0.0004952011513523757, + 0.012377702631056309, + -0.0063480171374976635, + 0.0256175734102726, + -0.020753338932991028, + 0.03223377838730812, + -0.1147943064570427, + -0.009170151315629482, + 0.015267477370798588, + -0.0009072314132936299, + -0.1621374636888504, + 0.022807778790593147, + 0.007394107989966869, + 0.01378557924181223, + -0.10719677805900574, + -0.000919080339372158, + -0.006567052565515041, + -0.007409179583191872, + -0.007469762582331896, + -0.004784661345183849, + -0.03967805579304695, + 0.015857066959142685, + -0.02015744335949421, + 0.056037548929452896, + 0.03962035849690437, + 0.08429893851280212, + 0.022117067128419876, + -0.2675061821937561, + 0.016738418489694595, + 0.0037785861641168594, + 0.004771686624735594, + -0.134505033493042, + -0.010618447326123714, + -0.004784524440765381, + 0.014044507406651974, + -0.03105556219816208, + 0.05049083009362221, + 0.012162688188254833, + 0.005920265335589647, + 0.008554516360163689, + 0.0025892227422446012, + 0.023483717814087868, + -0.20711173117160797, + 0.03360452130436897, + -0.24758699536323547, + -0.05136318504810333, + -0.015016172081232071, + 0.06466241925954819, + 0.023470288142561913, + 0.023495715111494064, + 0.004300899337977171, + 0.02461574412882328, + 0.025745516642928123, + -0.026187308132648468, + 0.08441776037216187, + -0.06955462694168091, + -0.11116205900907516, + -0.2169608771800995, + -0.004244703333824873, + -0.024184226989746094, + -0.10068271309137344, + -0.021129190921783447, + -0.021129680797457695, + -0.0054467362351715565, + 0.17416934669017792, + 0.015367642976343632, + -0.01237915363162756, + 0.024573752656579018, + 0.004588739015161991, + 0.05616860091686249, + -0.0018992060795426369, + -0.12394066900014877, + -0.03691404312849045, + -0.15878455340862274, + 0.10572423785924911, + 0.014409378170967102, + -0.008566108532249928, + -0.20319701731204987, + -0.018277373164892197, + -0.21615462005138397, + -0.11269525438547134, + -0.2767113745212555, + -0.25617966055870056, + -0.0036413148045539856, + -0.008058675564825535, + -0.051732294261455536, + -0.013052727095782757, + 0.05229722708463669, + -0.03535814583301544, + 0.3111231327056885, + -0.044130608439445496, + -0.02232682704925537, + -0.0040402463637292385, + 0.013798556290566921, + -0.07689940929412842, + -0.028940049931406975, + -0.00565366679802537, + -0.028972560539841652, + -0.007728889584541321, + 0.013665011152625084, + -0.014678380452096462, + -0.06747694313526154, + -0.06480871140956879, + -0.00028885426581837237, + -0.01525174267590046, + 0.027096102014183998, + -0.05200905352830887, + 0.0066903820261359215, + 0.0023834225721657276, + -0.002379713812842965, + -0.0208051148802042, + 0.335977703332901, + 0.03895771875977516, + -0.04814215749502182, + -0.037339694797992706, + -0.004409746266901493, + 0.07042848318815231, + -0.08318590372800827, + -0.04138712212443352, + 0.06309781968593597, + 0.007484383415430784, + 0.09696535021066666, + 0.024134323000907898, + -0.009859816171228886, + -0.06243982911109924, + 0.04630015045404434, + -0.06593744456768036, + 0.009306293912231922, + 0.5033899545669556, + 0.007804783061146736, + 0.024170484393835068, + -0.036085959523916245, + 0.016438491642475128, + 0.01678072288632393, + -0.006299734115600586, + -0.027441656216979027, + -0.014344800263643265, + 0.022293711081147194, + 0.011197407729923725, + -0.0026971842162311077, + 0.2685070335865021, + 0.01403988990932703, + -0.005100077483803034, + -0.026031343266367912, + -0.005419034510850906, + -0.014735087752342224, + -0.0283498577773571, + 0.002656748052686453, + -0.07137783616781235, + 0.02235356532037258, + -0.02970476634800434, + 0.20672672986984253, + 0.017398398369550705, + 0.02438206970691681, + 0.025746773928403854, + -0.03279582038521767, + 0.043908532708883286, + -0.003417646512389183, + 0.020200302824378014, + 0.007243862375617027, + -0.004560714587569237, + -0.01142876222729683, + -0.028091270476579666, + -0.2949703335762024, + 0.0729827880859375, + 0.004566277377307415, + 0.16689160466194153, + 0.034872010350227356, + -0.09590360522270203, + -0.13309867680072784, + 0.06429398059844971, + 0.04174232855439186, + -0.022723963484168053, + -0.04695400968194008, + 0.013115685433149338, + 0.013574879616498947, + 0.04794493317604065, + -0.015077140182256699, + 0.09493618458509445, + 0.008845972828567028, + 0.020302923396229744, + 0.02037016488611698, + 0.009083293378353119, + 0.0747746080160141, + -0.008078188635408878, + 0.024796344339847565, + -0.015212535858154297, + -0.005867444910109043, + 0.08309170603752136, + 0.03676094114780426, + 0.07232356816530228, + -0.3577176630496979, + 0.0013658110983669758, + -0.0009247250854969025, + 0.02284996211528778, + 0.012630275450646877, + 0.013745593838393688, + 0.003447894938290119, + 0.03563565015792847, + -0.031025355681777, + -0.07258180528879166, + -0.13482442498207092, + -0.029425248503684998, + -0.014927731826901436, + 0.045984312891960144, + -0.0176406130194664, + -0.22678181529045105, + -0.025248311460018158, + -0.11617762595415115, + -0.056157518178224564, + 0.009453062899410725, + -0.34616726636886597, + 0.05691010504961014, + -0.32302799820899963, + -0.026544231921434402, + -0.007374088745564222, + -0.07682909071445465, + -0.021214107051491737, + -0.07102422416210175, + 0.02693488635122776, + 0.014817211776971817, + 0.015572831965982914, + 0.04313618317246437, + -0.1277216374874115, + 0.02174532599747181, + -0.0226149819791317, + -0.00010956164624076337, + 0.023728065192699432, + 0.008212783373892307, + 0.010561724193394184, + -0.011036543175578117, + -0.022485855966806412, + 0.008243439719080925, + -0.03383245691657066, + -0.5630682110786438, + 0.0015974265988916159, + -0.28416821360588074, + 0.04123701527714729, + -0.0042976438999176025, + 0.03786511346697807, + 0.01862393692135811, + -0.04082413762807846, + -0.05792848393321037, + 0.0068894242867827415, + 0.0024085959885269403, + 0.001471342402510345, + 0.030681759119033813, + -0.026314062997698784, + 0.0555737242102623, + 0.03169534355401993, + 0.0031395808327943087, + 0.018701769411563873, + -0.5604594945907593, + 0.01526441890746355, + -0.00621993700042367, + 0.0009401043644174933, + 0.01587403193116188, + 0.030135583132505417, + -0.007350685074925423, + 0.006527469493448734, + 0.016000108793377876, + -0.042957425117492676, + 0.018247080966830254, + 0.0025622656103223562, + -0.03169511258602142, + 0.09235119074583054, + -0.013365034945309162, + 0.01607452519237995, + 0.017734844237565994, + 0.05609896034002304, + 0.04819876700639725, + -0.0871855691075325, + 0.05157865956425667, + 0.009171447716653347, + 0.022200705483555794, + -0.005507844965904951, + -0.024452703073620796, + 0.010224574245512486, + -0.006914906669408083, + 0.004650818649679422, + 0.02167516015470028, + 0.10456826537847519, + -0.07652094960212708, + -6.050072988728061e-05, + 0.012855490669608116, + 0.022669879719614983, + 0.022655120119452477, + 0.033012885600328445, + 0.025709744542837143, + 0.00481270719319582, + 0.005920717027038336, + -0.08545156568288803, + -0.004363589454442263, + -0.01531639602035284, + 0.030760569497942924, + 0.02796284481883049, + -0.03690989315509796, + 0.044959694147109985, + -0.14276015758514404, + -0.0002254673163406551, + -0.15694372355937958, + 0.012381293810904026, + -0.021977441385388374, + 0.005496624857187271, + -0.035593707114458084, + -0.0950438603758812, + 0.03825876861810684, + 0.05915532633662224, + -0.023323312401771545, + 0.017213119193911552, + -0.03807183355093002, + 0.02619507722556591, + 0.02741156332194805, + 0.005847832188010216, + 0.0020307491067796946, + 0.025714349001646042, + -0.04780200496315956, + 0.010206928476691246, + -0.01345440000295639, + 0.029133174568414688, + -0.0014764482621103525, + 0.004046705551445484, + -0.007725241594016552, + 0.013041527941823006, + 0.0018969239899888635, + 0.002417983952909708, + -0.010975837707519531, + 0.0015862436266615987, + 0.00597577728331089, + 0.002882696921005845, + 0.02855525352060795, + -0.005954153370112181, + 0.04090835899114609, + -0.39500924944877625, + 0.03586621209979057, + -0.5250031352043152, + -0.05697731301188469, + -0.09568691998720169, + -0.07179264724254608, + 0.04683076590299606, + 0.009320023469626904, + -0.11629963666200638, + -0.0016945215174928308, + 0.01624997705221176, + -0.0063682254403829575, + 0.15033549070358276, + -0.5171176791191101, + -0.01525783073157072, + 0.016417231410741806, + -0.00303818890824914, + 0.2500321865081787, + 0.022074062377214432, + 0.01191191840916872, + 0.012274803593754768, + 0.016534989699721336, + -0.028437916189432144, + 0.04241323843598366, + -0.01824999786913395, + -0.34815871715545654, + 0.04734490439295769, + -0.06419701874256134, + -0.022288290783762932, + -0.0004865761147812009, + 0.05369419604539871, + -0.058212973177433014, + -0.2196469008922577, + 0.010950890369713306, + 0.029042819514870644, + -0.07349151372909546, + -0.0422789566218853, + 0.062069639563560486, + 0.05589267984032631, + 0.014877256006002426, + 0.04236084595322609, + 0.03975239768624306, + 0.16930873692035675, + 0.03981085494160652, + 0.11499395221471786, + 0.0271450225263834, + 0.013969083316624165, + -0.0002660648606251925, + 0.010936664417386055, + -0.18389767408370972, + -0.10237602889537811, + 0.03041323646903038, + -0.013864071108400822, + -0.015729930251836777, + 0.037400804460048676, + -0.009598327800631523, + -0.09533312171697617, + -0.014712700620293617, + 0.08537333458662033, + -0.007200485561043024, + -0.31139102578163147, + -0.06366845220327377, + 0.02039063163101673, + -0.023356139659881592, + -0.0029549277387559414, + -0.12494662404060364, + 0.011755092069506645, + -0.26468148827552795, + -0.11541861295700073, + 0.010529865510761738, + -0.05965733155608177, + -0.05945499241352081, + -0.08796169608831406, + -0.014683439396321774, + 0.008732054382562637, + 0.010073489509522915, + 0.09553763270378113, + 0.034884922206401825, + 0.018675342202186584, + -0.009549405425786972, + -0.0007051719003356993, + -0.16936513781547546, + -0.0030460187699645758, + -0.022060535848140717, + -0.06689190864562988, + 0.013926704414188862, + 0.012043816037476063, + -0.0587068572640419, + -0.03814113140106201, + 0.06235629320144653, + 0.013228330761194229, + 0.04154474660754204, + -0.08039120584726334, + 0.028436705470085144, + -0.042226389050483704, + -0.019135186448693275, + 0.03747033327817917, + -0.14261123538017273, + 0.02827540971338749, + 0.0455685593187809, + -0.031124960631132126, + -0.007588588632643223, + 0.0034326373133808374, + -0.07682976871728897, + 0.24654042720794678, + -0.014518304727971554, + -0.07052458822727203, + -0.08241941034793854, + -0.04116151109337807, + -0.048463717103004456, + -0.038745298981666565, + 0.036902472376823425, + 0.0442035011947155, + 0.05572585016489029, + -0.014312628656625748, + 0.010794793255627155, + -0.3440641760826111, + -0.5161325335502625, + 0.0005156552069820464, + -0.010257269255816936, + -0.02412656880915165, + -0.023385023698210716, + 0.05533458665013313, + -0.012186119332909584, + -0.029286568984389305, + 0.04116401448845863, + -0.044610101729631424, + -0.019175484776496887, + 0.06835268437862396, + 0.06366674602031708, + 0.0373748242855072, + 0.03804386034607887, + 0.05369521677494049, + -0.04451881721615791, + 0.0018838117830455303, + 0.34775662422180176, + 0.010958605445921421, + -0.047990139573812485, + 0.04386777803301811, + -0.10427688807249069, + 0.04417382925748825, + 4.402965714689344e-05, + 0.01935163326561451, + -0.06753949075937271, + 0.02735923044383526, + 0.01465953141450882, + 0.06198301538825035, + -0.015980403870344162, + -0.2108263075351715, + 0.008177559822797775, + 0.006046924740076065, + 0.002665479900315404, + 0.20868580043315887, + -0.013740362599492073, + 0.008203004486858845, + -0.005066391546279192, + 0.026405498385429382, + 0.01383009273558855, + 0.012581533752381802, + 0.009014940820634365, + 0.022820021957159042, + -0.008534795604646206, + 0.2603924572467804, + 0.02297227643430233, + -0.000749691273085773, + 0.044753506779670715, + 0.018596511334180832, + 0.006852792575955391, + -0.008686172775924206, + -0.10452616959810257, + 0.017021872103214264, + 0.003722329391166568, + -0.025453045964241028, + -0.011473417282104492, + -0.017907623201608658, + 0.01400628499686718, + -0.1670989990234375, + 0.004298652987927198, + -0.0022204748820513487, + 0.16521315276622772, + -0.008831127546727657, + 0.026490870863199234, + 0.006190746556967497, + -0.0177209060639143, + 0.08967147767543793, + 0.0033069502096623182, + -0.005021366756409407, + 0.0004906906979158521, + 0.0169216375797987, + -0.06124846637248993, + -0.005200678016990423, + 0.08404737710952759, + -0.010559299029409885, + -0.006309974938631058, + 0.023113396018743515, + -0.010227260179817677, + 0.001256447983905673, + 0.019783375784754753, + -0.006308461539447308, + -0.04529590904712677, + -0.00908862054347992, + -0.043217338621616364, + -0.32200074195861816, + 0.02592635713517666, + 0.030795685946941376, + -0.001814531977288425, + 0.0092842485755682, + 0.07088880985975266, + -0.0867588147521019, + 0.024099843576550484, + -0.0034031609538942575, + 0.007234686985611916, + -0.02505563199520111, + 0.0030480287969112396, + -0.019158190116286278, + 0.26473408937454224, + -0.011918547563254833, + -0.023240016773343086, + -0.06084466353058815, + -0.021916134282946587, + -0.010251260362565517, + -0.0009625791572034359, + 0.082605741918087, + -0.013018425554037094, + 0.007627277635037899, + -0.0010813736589625478, + 0.007952406071126461, + 0.06551267951726913, + -0.026020025834441185, + 0.050048135221004486, + -0.010610008612275124, + -0.02429312653839588, + -0.025263017043471336, + -0.04611891135573387, + 0.04451768472790718, + -0.08045025914907455, + -0.048037610948085785, + 0.008019295521080494, + 0.0160224549472332, + 0.002078550634905696, + -0.0202508345246315, + -0.5446130633354187, + 0.012585492804646492, + -0.0331973135471344, + 0.08371605724096298, + -0.00590998912230134, + -0.013058983720839024, + 0.027742384001612663, + 0.1042199358344078, + -0.3072803318500519, + 0.06284149736166, + -0.28551968932151794, + 0.026768438518047333, + 0.022245990112423897, + 0.018242113292217255, + -0.035077981650829315, + 0.03546127676963806, + 0.10165776312351227, + -0.025475669652223587, + -0.014933750964701176, + 0.040547240525484085, + -0.033055808395147324, + 0.011755919083952904, + -0.014459444209933281, + -0.03455093130469322, + 0.020743343979120255, + 0.02720930427312851, + -0.287664532661438, + 0.008260028436779976, + -0.009877690114080906, + 0.16657423973083496, + -0.010943812318146229, + -0.012381386943161488, + 0.030678801238536835, + 0.1559792459011078, + 0.038967035710811615, + -0.023399239405989647, + 0.015019542537629604, + -0.014201333746314049, + -0.014202176593244076, + -0.006699408870190382, + -0.13175444304943085, + 0.004643211141228676, + 0.012747463770210743, + -0.04086190089583397, + 0.06581410765647888, + -0.12192045897245407, + -0.03126347437500954, + 0.011175516061484814, + -0.00914736744016409, + -0.02883930690586567, + -0.11305265873670578, + -0.04405384883284569, + -0.009120048955082893, + -0.008926079608500004, + -0.03169447183609009, + 0.05464877560734749, + 0.25674498081207275, + 0.08497058600187302, + -0.023222925141453743, + 0.35592252016067505, + -0.006929511670023203, + 0.025255810469388962, + -0.05150032415986061, + 0.039239466190338135, + -0.07082924991846085, + -0.017321549355983734, + 0.17293211817741394, + -0.02155853807926178, + -0.014333213679492474, + 0.0031305316369980574, + -0.013490653596818447, + -0.1376512199640274, + -0.021713266149163246, + -0.029826253652572632, + -0.0011473714839667082, + -0.012434332631528378, + -0.04860873892903328, + 0.013857590034604073, + 0.0703854188323021, + 0.034528713673353195, + -0.014423011802136898, + 0.0882454589009285, + -0.091700978577137, + 0.038885727524757385, + 0.012043441645801067, + -0.03183690831065178, + -0.014495689421892166, + -0.019726552069187164, + -0.010094117373228073, + -0.004218627233058214, + -0.04413086175918579, + -0.1344134360551834, + -0.0004976870259270072, + -0.0008357573533430696, + 0.04518067091703415, + 0.046797975897789, + 0.24766182899475098, + 0.01065139751881361, + -0.0034267394803464413, + -0.016103556379675865, + -0.05139121413230896, + 0.012563390657305717, + -0.03310413286089897, + -0.030157553032040596, + 0.046670909970998764, + 0.012565785087645054, + -0.040275491774082184, + 0.023816417902708054, + -0.38536572456359863, + 0.04508889466524124, + 0.13637560606002808, + -0.010654824785888195, + 0.0459851399064064, + -0.0046302699483931065, + -0.020852191373705864, + 0.10662271827459335, + 0.06486576050519943, + 0.05727925896644592, + 0.09816201776266098, + 0.04878557100892067, + -0.16256237030029297, + 0.014547038823366165, + 0.018567964434623718, + -0.07284612208604813, + 0.017150163650512695, + 0.0246741883456707, + -0.38470372557640076, + -0.07465949654579163, + 0.03010236658155918, + -0.004397575277835131, + -0.06618984788656235, + -0.02908281609416008, + 0.060166433453559875, + -0.0020949048921465874, + 0.007689109072089195, + -0.0047390698455274105, + -0.014199030585587025, + -0.01794746331870556, + -0.02528063952922821, + 0.002218312583863735, + 0.10169881582260132, + 0.010602130554616451, + -0.06605861335992813, + -0.0008762837387621403, + -0.035027723759412766, + -0.011684391647577286, + 0.02247578091919422, + 0.17245104908943176, + 0.22525252401828766, + -0.010771296918392181, + 0.05595310404896736, + 0.06338834017515182, + -0.0038216698449105024, + -0.0032836494501680136, + 0.005779017228633165, + -0.18020786345005035, + -0.05066698044538498, + -0.0035458216443657875, + -0.10578767210245132, + -0.041712939739227295, + 0.2104150652885437, + -0.03753345459699631, + 0.013989892788231373, + 0.01988149993121624, + 0.05108603090047836, + 0.04496738687157631, + -0.3034508526325226, + 0.0226743221282959, + -0.0431472510099411, + -0.025635428726673126, + -0.18961989879608154, + -0.17218825221061707, + 0.03576141223311424, + 0.060613714158535004, + -0.011970550753176212, + -0.21435107290744781, + 0.01422552578151226, + 0.02974064089357853, + -0.061079952865839005, + 0.031064646318554878, + 0.009629320353269577, + -0.13762925565242767, + 0.01928475871682167, + 0.007310172542929649, + 0.06103459745645523, + -0.16216528415679932, + 0.03330384939908981, + 0.09578404575586319, + -0.0037327276077121496, + 0.029233848676085472, + -0.0015759399393573403, + 0.005511409603059292, + -0.4195749759674072, + 0.024169376119971275, + 0.13220365345478058, + 0.007961929775774479, + 0.008045470342040062, + 0.01919495314359665, + -0.023188553750514984, + 0.07084394991397858, + -0.24922333657741547, + 0.02011212892830372, + -0.18514998257160187, + 0.03114209696650505, + 0.09826567023992538, + 0.00592303741723299, + -0.010020115412771702, + 0.027117054909467697, + -0.214133620262146, + -0.01214816514402628, + 0.06564164906740189, + 0.02513044886291027, + 0.02132420241832733, + -0.02127540111541748, + -0.041606876999139786, + 0.04196378216147423, + -0.02060609683394432, + 0.01730814389884472, + -0.17418994009494781, + 0.03462710976600647, + -0.017470642924308777, + -0.3992193639278412, + 0.02652592957019806, + 0.025042008608579636, + 0.026447610929608345, + -0.19199316203594208, + 3.27593952533789e-05, + 0.002988220192492008, + -0.21171888709068298, + 0.03300239518284798, + 0.015727035701274872, + -0.008947308175265789, + 0.03924538940191269, + -0.08990193158388138, + 0.023726975545287132, + 0.03463870286941528, + -0.05018220469355583, + 0.13170146942138672, + 0.054000236093997955, + 0.01158218178898096, + 0.062349993735551834, + -0.014724616892635822, + 0.039657603949308395, + 0.04436490684747696, + 0.014076294377446175, + 0.07666806876659393, + 0.09630247205495834, + -0.04152659326791763, + -0.1860806941986084, + -0.07671733945608139, + 0.031573690474033356, + -0.44617798924446106, + -0.004897239152342081, + -0.03991628438234329, + 0.01880800537765026, + -0.04769768565893173, + 0.02198435738682747, + 0.01341161783784628, + -0.12239313870668411, + 0.019765935838222504, + 0.005221452098339796, + -0.025201082229614258, + 0.005132562946528196, + 0.08668412268161774, + 0.0035341952461749315, + 0.008583099581301212, + 0.032979920506477356, + 0.03324040770530701, + 0.04411708936095238, + -0.008390798233449459, + 0.040486790239810944, + -0.059673551470041275, + 0.02003314346075058, + -0.0990666076540947, + 0.03971675783395767, + 0.012021057307720184, + 0.0017271327087655663, + 0.01818535290658474, + 0.0025106174871325493, + 0.043714240193367004, + 0.019146842882037163, + -0.0041794623248279095, + 0.033447377383708954, + 0.06863203644752502, + -0.004350902978330851, + 0.0113364327698946, + -0.05825724080204964, + -0.04649435728788376, + -0.10618306696414948, + 0.02653644233942032, + 0.012514552101492882, + 0.019399365410208702, + -0.0022177041973918676, + 0.017741208896040916, + 0.04115311801433563, + 0.05122101679444313, + 0.055051617324352264, + 0.01687677949666977, + -0.03698579967021942, + 0.10053858160972595, + -0.007528421934694052, + 0.003968802746385336, + 0.02458524890244007, + -0.02144794538617134, + 0.026791265234351158, + -0.016701897606253624, + 0.014119372703135014, + -0.03460531681776047, + -0.02320348098874092, + 0.056146953254938126, + 0.028700685128569603, + -0.14820916950702667, + -0.016996873542666435, + 0.025667931884527206, + 0.08408629894256592, + 0.00034475952270440757, + 0.007573155220597982, + 0.06784884631633759, + 0.025982951745390892, + -0.08363039791584015, + -0.015748541802167892, + -0.0029514851048588753, + -0.01523523684591055, + 0.10500328987836838, + 0.3070858418941498, + -0.024624783545732498, + 0.0058471946977078915, + -0.039751242846250534, + 0.0012745993444696069, + -0.0796508714556694, + 0.024727927520871162, + 0.056764136999845505, + -0.013338261283934116, + -0.04794292524456978, + -0.02609768509864807, + -0.010784422047436237, + -0.048712026327848434, + 0.020345501601696014, + 0.0021618579048663378, + -0.0021724768448621035, + 0.03056410700082779, + -0.01633712649345398, + -0.47168225049972534, + -0.014639903791248798, + -0.012550815008580685, + 0.03358187526464462, + 0.07889427989721298, + -0.03615899011492729, + -0.002809660043567419, + -0.006953644100576639, + 0.02024337276816368, + -0.0738825723528862, + -0.006984011270105839, + -0.04472561925649643, + -0.027498915791511536, + 0.07207506150007248, + -0.09166522324085236, + -0.008861960843205452, + 0.05264359340071678, + 0.01889069564640522, + -0.1380404680967331, + -0.010141258127987385, + 0.015403619967401028, + -0.16416165232658386, + -0.03529815003275871, + 0.042106859385967255, + 0.11173021793365479, + -0.3143587112426758, + 0.011045016348361969, + 0.0012351945042610168, + 0.03840603306889534, + 0.0685538575053215, + -0.000746160454582423, + -0.028142500668764114, + 0.027154160663485527, + 0.005731801502406597, + 0.04433267563581467, + -0.8158469796180725, + 0.02226361259818077, + -0.07650655508041382, + 0.026958195492625237, + -0.005810025613754988, + -0.020102059468626976, + -0.0019310436910018325, + 0.07697021961212158, + -0.057701658457517624, + 0.05954534560441971, + 0.0027106746565550566, + -0.06311310827732086, + 0.011713752523064613, + -0.0034454476553946733, + -0.0006881420267745852, + 0.08937360346317291, + -0.0008253820124082267, + -0.031066063791513443, + -0.14708301424980164, + -0.04438449814915657, + 0.004772413522005081, + 0.05992274731397629, + 0.07473544776439667, + -0.1784757375717163, + -0.19057415425777435, + -0.014637955464422703, + -0.24898527562618256, + 0.13606221973896027, + -0.018039124086499214, + -0.047193415462970734, + -0.06526428461074829, + 0.04075757786631584, + 0.049901530146598816, + -0.008585861884057522, + 0.01616351678967476, + -3.091737016802654e-05, + 0.024283329024910927, + 0.008861682377755642, + -0.0005823548417538404, + 0.0997646301984787, + 0.051001910120248795, + 0.009473294951021671, + -0.0032046104315668344, + 0.018362928181886673, + 0.008627718314528465, + -0.4148157835006714, + -0.016077928245067596, + 0.0745391696691513, + 0.00724065862596035, + 0.08948155492544174, + 0.11626332253217697, + -0.052439428865909576, + 0.005599102005362511, + 0.002622961765155196, + 0.07586965709924698, + 0.03274847939610481, + -0.02099076844751835, + -0.04666733741760254, + -0.0013019372709095478, + 0.04945925995707512, + 0.11393380910158157, + 0.006346395239233971, + 0.04721064493060112, + 0.010331138968467712, + 0.08918803185224533, + 0.04288423806428909, + -0.09234773367643356, + 0.020141584798693657, + -3.256054696976207e-05, + -0.02799108810722828, + 0.018966441974043846, + -0.4136410355567932, + -0.07217283546924591, + 0.01840362884104252, + -0.055327851325273514, + 0.003275467548519373, + -0.017174070701003075, + -0.032178670167922974, + 0.09021560847759247, + -0.524413526058197, + 0.01994725503027439, + 0.10380692034959793, + -0.01043684035539627, + -0.00011200909648323432, + 0.01331041194498539, + 0.020127851516008377, + -0.025159789249300957, + 0.05252581834793091, + 0.04759140685200691, + 0.0032084162812680006, + -0.03579062595963478, + 0.054719552397727966, + -0.04674411937594414, + 0.028389262035489082, + 0.001127603929489851, + -0.0006243048119358718, + -0.00550495833158493, + -0.022523507475852966, + -0.024282312020659447, + 0.009519628249108791, + -0.39908328652381897, + -0.009265545755624771, + -0.00037090369733050466, + 0.06425131112337112, + -0.05998316407203674, + -0.015221518464386463, + -0.004825026262551546, + 0.11847284436225891, + -0.011302731931209564, + -0.006884834263473749, + -0.04678218811750412, + -0.012078279629349709, + 0.021638741716742516, + -0.016819776967167854, + -0.009127719327807426, + -0.002491263672709465, + 0.0016752213705331087, + -0.016600262373685837, + 0.011772023513913155, + -0.013447183184325695, + -0.020662957802414894, + -0.011593316681683064, + 0.008270744234323502, + -0.0026990456972271204, + -0.004406482446938753, + -0.023110052570700645, + -0.00208942755125463, + -0.1711198389530182, + 0.012432538904249668, + -0.0045453268103301525, + 0.024807902052998543, + -0.0035043740645051003, + -0.004001997876912355, + -0.013488625176250935, + -0.02020987868309021, + -0.01216109935194254, + -0.004432092886418104, + 0.09323672950267792, + -0.015641510486602783, + -0.019307948648929596, + 0.01117538008838892, + -0.01422040443867445, + 0.01705607771873474, + -0.0029596879612654448, + -0.0021530911326408386, + -0.006551788654178381, + 0.00429268553853035, + -0.1620807945728302, + -0.014128226786851883, + -0.005428737495094538, + -0.006771362852305174, + 0.005730633158236742, + 0.0007243106956593692, + 0.0024031582288444042, + -0.00199915561825037, + 0.006133859045803547, + -0.013380909338593483, + 0.00733462069183588, + -0.001863821060396731, + -0.0020169683266431093, + -0.014070986770093441, + -0.006501683499664068, + -0.029421553015708923, + 0.0009377509704791009, + -0.01718256250023842, + -0.05819401144981384, + -0.018859732896089554, + 0.0010356366401538253, + 0.006394123658537865, + -0.021985618397593498, + -0.01204769592732191, + -0.002014884725213051, + -0.019398409873247147, + -0.013122898526489735, + -0.017277296632528305, + -0.002270353492349386, + -0.05294327810406685, + -0.020317314192652702, + -0.018196573480963707, + -0.010375416837632656, + -0.019704729318618774, + -0.016109557822346687, + -0.0167380403727293, + -0.0285252146422863, + -0.02665277197957039, + -0.03554505482316017, + -0.00741522666066885, + -0.013580105267465115, + -0.026335405185818672, + -0.011694515123963356, + -0.004639182705432177, + -0.03996071219444275, + -0.022463932633399963, + -0.007204636000096798, + -0.021065134555101395, + -0.014410646632313728, + 0.0035447971895337105, + -0.0013098351191729307, + -0.024171002209186554, + 0.00047751085367053747, + -0.01870289072394371, + -0.06016797944903374, + -0.025703946128487587, + -0.009730588644742966, + -0.021792838349938393, + -0.024519823491573334, + -0.01843440905213356, + -0.0016325484029948711, + -0.008116388693451881, + -0.017774557694792747, + -0.04375867918133736, + -0.03893980756402016, + -0.018188582733273506, + -0.007122726645320654, + -0.028115490451455116, + -0.01821342669427395, + -0.01011319737881422, + -0.02616124413907528, + -0.013797983527183533, + -0.03202736750245094, + -0.030110370367765427, + -0.01883666031062603, + -0.01185502391308546, + -0.006012012716382742, + -0.017311619594693184, + -0.022577986121177673, + -0.02101938985288143, + 0.0025952248834073544, + -0.005058783106505871, + -0.004162575118243694, + -0.01559755764901638, + -0.017923563718795776, + -0.04231095686554909, + -0.017630560323596, + -0.011938830837607384, + -0.01587115228176117, + 0.004972478374838829, + -0.016601158306002617, + 0.15419845283031464, + 0.0009241115767508745, + 0.051028184592723846, + 0.008128340356051922, + -0.019917558878660202, + -0.0010339801665395498, + 0.022349294275045395, + -0.0072520882822573185, + 0.0017750378465279937, + -0.10526080429553986, + 0.03420695662498474, + 0.019183926284313202, + -0.0006544998032040894, + -0.0032203509472310543, + -0.01216941885650158, + -0.03561796247959137, + 0.024905826896429062, + -0.026948239654302597, + -0.01913355104625225, + -0.014459407888352871, + 0.006972283590584993, + -0.033184293657541275, + 0.04884861409664154, + -0.002296984428539872, + -0.19194477796554565, + 0.00392142403870821, + 0.009490449912846088, + -0.02687196619808674, + -0.06327224522829056, + -0.03684951737523079, + -0.0002613202668726444, + -0.012086644768714905, + 0.03630973398685455, + 0.007296048104763031, + 0.011186012998223305, + 0.0074085514061152935, + -0.020394617691636086, + -0.010585476644337177, + -0.030289918184280396, + 0.0773506686091423, + 0.008841303177177906, + 0.019423579797148705, + 0.001184571417979896, + 0.005553434602916241, + 0.015373414382338524, + -0.0027953842654824257, + 0.013204757124185562, + 0.029097743332386017, + 0.012627501040697098, + 0.02102004364132881, + -0.09469914436340332, + -0.023324014618992805, + 0.029243655502796173, + 0.002979277865961194, + -0.004492263309657574, + 0.20549021661281586, + -0.3244459927082062, + 0.025892559438943863, + 0.009620796889066696, + -0.05520407855510712, + -0.02271144650876522, + 0.008378816768527031, + -0.0671214610338211, + -0.016056722030043602, + -0.02355658821761608, + 0.0005429868469946086, + -0.007960098795592785, + 0.02513299137353897, + -0.13005328178405762, + -0.0025323680602014065, + -0.02197088487446308, + -0.02404806576669216, + 0.08261960744857788, + 0.17078880965709686, + 0.02880753017961979, + -0.03642067685723305, + 0.021994341164827347, + -0.012368184514343739, + -0.10681373625993729, + 0.16371481120586395, + 0.17881983518600464, + -0.10202010720968246, + -0.08641688525676727, + -0.1259487271308899, + 0.06907707452774048, + 0.023792706429958344, + -0.02534419298171997, + 0.016984017565846443, + -0.06743635982275009, + 0.08445960283279419, + -0.08037827908992767, + -0.11935994029045105, + -0.31716489791870117, + -0.01860150322318077, + 0.060669515281915665, + -0.06137414649128914, + 0.09878886491060257, + 0.01794014871120453, + 0.12382296472787857, + -0.016424886882305145, + 0.09045679122209549, + -0.02998783066868782, + -0.00972777884453535, + -0.024124544113874435, + 0.09879253059625626, + 0.05500243604183197, + -0.06635259836912155, + 0.11268552392721176, + 0.011751363053917885, + -0.04690232127904892, + -0.025168607011437416, + 0.088335320353508, + -0.1140628531575203, + 0.04129032790660858, + -0.04258979484438896, + -0.0903872698545456, + 0.008473021909594536, + -0.026690304279327393, + -0.051559556275606155, + -0.05481572076678276, + -0.05251916125416756, + -0.0018165932269766927, + 0.09836867451667786, + 0.0054859439842402935, + 0.06432581692934036, + 0.10621821135282516, + -0.019325286149978638, + -0.028727786615490913, + 0.014013150706887245, + -0.008022608235478401, + -0.006281842477619648, + -0.0297000203281641, + 0.01525485422462225, + -0.4346403479576111, + 0.07787995040416718, + -0.25380268692970276, + 0.05261845141649246, + 0.010875157080590725, + 0.0014149334747344255, + 0.05021188035607338, + -0.24382442235946655, + 0.0807114690542221, + 0.022907381877303123, + 0.006440790370106697, + -0.017028095200657845, + 0.001552293193526566, + 0.05961666256189346, + -0.14113056659698486, + 0.03398876264691353, + -0.005411976482719183, + -0.014025667682290077, + -0.5433799624443054, + 0.019015472382307053, + 0.04091138765215874, + 0.05059061944484711, + 0.0274446289986372, + -0.010288042947649956, + -0.001335533568635583, + -0.013533512130379677, + 0.018798377364873886, + -0.04099345579743385, + 0.0031264263670891523, + -0.21071769297122955, + -0.014384736306965351, + -0.1045387014746666, + -0.014340974390506744, + 0.001986369490623474, + -0.04118456318974495, + -0.10952988266944885, + 0.049147430807352066, + -0.08382093161344528, + -0.1741400957107544, + -0.0885215476155281, + -0.10934099555015564, + 0.05553343519568443, + 0.02434251271188259, + 0.006634524557739496, + -0.0017163373995572329, + 0.0185443926602602, + 0.06250902265310287, + -0.17145656049251556, + -0.07543934881687164, + 0.026583310216665268, + 0.01634727604687214, + 0.003603539662435651, + -0.2817271649837494, + 0.03882112354040146, + 0.011341865174472332, + 0.00826666783541441, + 0.050427842885255814, + -0.22358834743499756, + 0.06419781595468521, + 0.03245265409350395, + -0.04503164440393448, + -0.023194484412670135, + -0.027968740090727806, + 0.08563586324453354, + 0.07954753190279007, + -0.08513130992650986, + 0.02850884199142456, + 0.008976672776043415, + 0.07886530458927155, + 0.0022273347713053226, + -0.09540755301713943, + 0.032016951590776443, + -0.05196075513958931, + 0.10555616766214371, + 0.07629868388175964, + 0.039732079952955246, + -0.0029798501636832952, + 0.014692343771457672, + 0.09200941026210785, + -0.04299614951014519, + -0.023488566279411316, + -0.01851060427725315, + 0.09257487207651138, + 0.055612049996852875, + 0.06423109769821167, + -0.28587806224823, + -0.09950444847345352, + 0.10397437959909439, + 0.025166453793644905, + -0.03235514089465141, + -0.033381711691617966, + 0.1513858139514923, + 0.06468874961137772, + 0.01928441785275936, + 0.0032701045274734497, + -0.0579083226621151, + -0.022929169237613678, + 0.012971373274922371, + -0.018524186685681343, + -0.06484643369913101, + 0.012233717367053032, + 0.06590451300144196, + -0.04558677598834038, + 0.05253027006983757, + 0.048656731843948364, + -0.2288871705532074, + 0.037114787846803665, + -0.20519588887691498, + 0.0058607361279428005, + -0.002009372925385833, + -0.006671734619885683, + -0.07107856124639511, + -0.07407436519861221, + 0.03941629081964493, + 0.0447598397731781, + 0.03509354963898659, + -0.061107732355594635, + -0.09305761009454727, + -0.012180411256849766, + 0.04902016744017601, + 0.07974442094564438, + -0.016854410991072655, + 0.005089411046355963, + -0.08127597719430923, + 0.03258403390645981, + 0.039813362061977386, + -0.01668727956712246, + 0.027226485311985016, + -0.029213925823569298, + -0.008598217740654945, + 0.00931101106107235, + 0.026936721056699753, + -0.03083401545882225, + -0.05799110606312752, + -0.008277476765215397, + -0.014854338951408863, + -0.20012643933296204, + 0.012290815822780132, + 0.007194168865680695, + 0.06858328729867935, + -0.3296163082122803, + -0.11424986273050308, + 0.009912200272083282, + -0.06211454048752785, + 0.0007546336855739355, + 0.03507614880800247, + 0.10649498552083969, + -0.03036407195031643, + 0.0646015852689743, + -0.01595110446214676, + -0.16919563710689545, + 0.0013865949586033821, + -0.08339446783065796, + 0.06962471455335617, + 0.016058098524808884, + -0.04729780554771423, + 0.010602935217320919, + 0.01470863912254572, + 0.06903938204050064, + 0.014901719056069851, + -0.15120048820972443, + 0.016727851703763008, + 0.05003673583269119, + 0.04370126873254776, + 0.029703885316848755, + 0.021875420585274696, + 0.026293285191059113, + -0.01048936415463686, + 0.00040810942300595343, + -0.015616541728377342, + -0.062451593577861786, + 0.010016348212957382, + -0.06790193170309067, + -0.02077331207692623, + 0.007985175587236881, + -0.04435744881629944, + 0.06920231133699417, + 0.018344474956393242, + 0.028591370210051537, + 0.021957838907837868, + 0.0017570338677614927, + 0.036665257066488266, + 0.015438515692949295, + -0.0006347382441163063, + 0.04621066153049469, + -0.001942177303135395, + 0.010664877481758595, + -0.016754357144236565, + 0.006541184149682522, + -0.027716301381587982, + -0.0058586387895047665, + -0.005346015095710754, + 0.020482052117586136, + 0.06882552057504654, + 0.0026622572913765907, + 0.016321638599038124, + 0.017728103324770927, + -0.13356441259384155, + 0.030281176790595055, + 1.0354949154134374e-05, + 0.050639618188142776, + 0.0013030078262090683, + -0.11136802285909653, + -0.006832807790488005, + -0.09628921747207642, + 0.046699415892362595, + 0.002175685251131654, + 0.008100612089037895, + 0.012449901551008224, + -0.01713990420103073, + -0.000769267207942903, + 0.022544430568814278, + -0.0018787183798849583, + -0.014189678244292736, + 0.37042510509490967, + -0.030317893251776695, + 0.012663356028497219, + -0.04071582853794098, + 0.01653047651052475, + 0.06578584760427475, + 0.005606585182249546, + 0.0029362838249653578, + -0.02035594917833805, + 0.016131827607750893, + -0.06512665003538132, + 0.020292088389396667, + 0.12818951904773712, + -0.00017647731874603778, + 0.0004811069811694324, + 0.013025660999119282, + -0.006004344671964645, + 0.011330580338835716, + 0.0021733916364610195, + -0.0026290342211723328, + 0.008579215034842491, + -0.017107143998146057, + 0.0032798980828374624, + 0.21415431797504425, + -0.011049880646169186, + 0.04915957152843475, + -0.01152863260358572, + 0.01988764852285385, + -0.30189022421836853, + 0.1491061896085739, + 0.022540517151355743, + 0.02323656715452671, + -0.0028044115751981735, + -0.02501249685883522, + 0.0016759912250563502, + 0.023405946791172028, + 0.0865691602230072, + 0.0056661744602024555, + 0.2334042638540268, + -0.05771901085972786, + 0.03428330272436142, + -0.05191519856452942, + 0.025708407163619995, + -0.11474912613630295, + 0.05345827341079712, + 0.050046734511852264, + -0.03785427287220955, + 0.02726786397397518, + 0.008640051819384098, + -0.05810163915157318, + 0.19147679209709167, + 0.12065602838993073, + -0.08667072653770447, + -0.12831886112689972, + 0.027053257450461388, + -0.1771622896194458, + -0.2615586817264557, + 0.112942636013031, + 0.002398239215835929, + 0.00907410029321909, + 0.059947770088911057, + 0.040937639772892, + 0.003431124845519662, + 0.012721046805381775, + -0.10228776186704636, + 0.04169567674398422, + -0.04826785624027252, + -0.021415220573544502, + 0.027615519240498543, + 0.16087181866168976, + 0.03552674129605293, + -0.36409878730773926, + 0.0015418739058077335, + 0.03940089792013168, + -0.12929502129554749, + 0.017082052305340767, + -0.07193783670663834, + 0.10395099222660065, + -0.2240910828113556, + -0.003303584409877658, + -0.0074868109077215195, + -0.13708709180355072, + 0.2098008245229721, + 0.013808795250952244, + -0.03606148064136505, + 0.001965852687135339, + 0.04186573252081871, + 0.02105732634663582, + -0.11873909085988998, + -0.08529136329889297, + 0.0060731275007128716, + 0.04803553968667984, + 0.07665349543094635, + 0.026997262611985207, + 0.05191565304994583, + 0.09013131260871887, + 0.013081093318760395, + 0.04667182266712189, + -0.19899451732635498, + 0.004642056301236153, + 0.0025570227298885584, + -0.2640555500984192, + 0.008254006505012512, + 0.05971720814704895, + -0.002980671590194106, + 0.0011313167633488774, + -0.004445134196430445, + 0.01951296627521515, + -0.006634386721998453, + -0.008033698424696922, + 0.012400158680975437, + -0.15906694531440735, + 0.007047838997095823, + 0.0003521084145177156, + -0.00517050176858902, + -0.0003226286207791418, + -0.01226231548935175, + -0.06750697642564774, + -0.03061128593981266, + -0.0027100055012851954, + 0.004726986400783062, + 0.010185977444052696, + 0.021205933764576912, + -0.05105980113148689, + -0.006725164130330086, + 0.26042309403419495, + 0.003935054875910282, + 0.009450466372072697, + -0.009512278251349926, + 0.036205559968948364, + 0.0066987741738557816, + 0.05687355250120163, + -0.0070350514724850655, + 0.021287698298692703, + 0.004246287513524294, + -0.004053668584674597, + 0.0030501342844218016, + -0.003596516093239188, + 0.00571554945781827, + 0.039099883288145065, + 0.06648323684930801, + 0.011140268296003342, + 0.002779693342745304, + 0.0004113377653993666, + 0.0019621821120381355, + 0.002047213725745678, + -9.034215327119455e-05, + 0.006674906238913536, + -0.024464793503284454, + 4.372629337012768e-05, + 0.04560312256217003, + 0.029951298609375954, + 0.0053787860088050365, + 0.010052027180790901, + 0.0018156497972086072, + 0.001613074098713696, + -0.3710610568523407, + 0.18385423719882965, + 0.0197732076048851, + -2.409513217571657e-05, + 0.043657880276441574, + 0.029824273660779, + -0.0015272254822775722, + -0.0009817760437726974, + 0.030571524053812027, + 0.05133187025785446, + 0.021092001348733902, + -0.022430723533034325, + -0.011050102300941944, + -0.01653454266488552, + 0.00856624636799097, + 0.007617316208779812, + 0.023697074502706528, + -0.00541776092723012, + -0.06940567493438721, + -0.024501511827111244, + 0.0029131292831152678, + 0.005110545549541712, + 0.02394089475274086, + 0.009317552670836449, + -0.05198051407933235, + -0.14872707426548004, + -0.03553030639886856, + 0.05354774370789528, + 0.053996339440345764, + 0.016679847612977028, + -0.4505158066749573, + 0.006403166800737381, + -0.014287465251982212, + 0.010499212890863419, + 0.00510875741019845, + 0.0230255089700222, + -0.04791099205613136, + -0.08405473828315735, + -0.00807158276438713, + -0.016310568898916245, + -0.018034789711236954, + -0.03381670266389847, + 0.038599055260419846, + 0.01189411524683237, + 0.0038598189130425453, + 0.0077203805558383465, + -0.0006835742969997227, + 0.3038807809352875, + 0.00930703990161419, + -0.017654214054346085, + -0.029550395905971527, + 0.0014829621650278568, + -0.010562432929873466, + -0.011867706663906574, + -0.008104459382593632, + 0.008003979921340942, + -0.028282882645726204, + 0.00898829661309719, + -0.04963170364499092, + 0.014971665106713772, + 0.028662119060754776, + 0.055792808532714844, + 0.018142173066735268, + 0.029526766389608383, + 0.04726170003414154, + 0.020290115848183632, + -0.01347910612821579, + -0.027794860303401947, + -0.033374592661857605, + 0.05699307844042778, + -0.005888971965759993, + 0.009723466821014881, + 0.011825029738247395, + 0.0005665962235070765, + -0.22433574497699738, + 0.04777664318680763, + 0.054696254432201385, + 0.06447272002696991, + 0.006656138692051172, + -0.2656468152999878, + -0.006602808367460966, + -0.04309352487325668, + 0.024392882362008095, + -0.046948980540037155, + 0.17317010462284088, + -0.014694501645863056, + 0.09150391072034836, + 0.05414793640375137, + -0.0034523033536970615, + -0.029682809486985207, + -0.11646991223096848, + 0.036394182592630386, + -0.008510537445545197, + -0.09555189311504364, + 0.012331446632742882, + 0.022554755210876465, + 0.037040166556835175, + 0.011939534917473793, + -0.035405583679676056, + -0.008284371346235275, + 0.008629710413515568, + -0.0017152110813185573, + -0.01656493730843067, + 0.02205522358417511, + -0.008015291765332222, + -0.02198217809200287, + -0.08165504783391953, + 0.018647879362106323, + 0.010489191859960556, + 0.0009643095545470715, + 0.08301698416471481, + 0.00795030314475298, + -0.08973152935504913, + 0.05324552580714226, + 0.0187348835170269, + 0.00770497927442193, + 0.016434336081147194, + 0.0031714467331767082, + 0.031489044427871704, + -0.01682765781879425, + -0.0006042059976607561, + 0.006229344755411148, + 0.0031935630831867456, + -0.03694210946559906, + -0.027148112654685974, + 0.03319454565644264, + 0.013541879132390022, + 0.04362545907497406, + 0.010766182094812393, + 0.01287879142910242, + 0.02723391354084015, + 0.01831277459859848, + -0.0028144901152700186, + 0.0317537821829319, + -0.05053209140896797, + 0.03341667726635933, + 0.009338690899312496, + 0.030376508831977844, + 0.028512636199593544, + 0.002190604107454419, + 0.031132254749536514, + 0.04174429178237915, + 0.025147251784801483, + 0.02602408640086651, + 0.022863827645778656, + 0.024160150438547134, + 0.04043813422322273, + 0.011693909764289856, + 0.008020071312785149, + 0.010814648121595383, + 0.014862221665680408, + 0.043966785073280334, + 0.04133215174078941, + 0.03920775279402733, + 0.02128027193248272, + -0.0024078795686364174, + 0.03185494989156723, + 0.030951442196965218, + 0.008766901679337025, + -0.0013500713976100087, + 0.012680909596383572, + 0.01911563239991665, + 0.02226334996521473, + 0.03873631730675697, + 0.005242412444204092, + 0.02335301972925663, + 0.00577192846685648, + 0.0019918885082006454, + 0.019501060247421265, + 0.048295676708221436, + 0.027288099750876427, + 0.03500128164887428, + 0.032504353672266006, + 0.03619033470749855, + 0.022762063890695572, + 0.014124974608421326, + 0.04055529460310936, + 0.040181197226047516, + 0.04843837395310402, + 0.019578352570533752, + 0.04370861127972603, + 0.024640914052724838, + 0.027013463899493217, + 0.04700532928109169, + 0.018523193895816803, + 0.03569294884800911, + 0.031140455976128578, + 0.010298499837517738, + 0.03979840502142906, + 0.015059049241244793, + 0.020604899153113365, + 0.010335667058825493, + 0.02557498589158058, + 0.015946611762046814, + 0.018900645896792412, + 0.05494159087538719, + 0.015756357461214066, + 0.0452926866710186, + 0.04820817708969116, + -0.0183499027043581, + 0.04002442955970764, + -0.08226092159748077, + -0.034417178481817245, + 0.059122342616319656, + 0.028960591182112694, + -0.020427608862519264, + -0.043222296983003616, + 0.023134637624025345, + -0.014232538640499115, + -0.06970997899770737, + -0.0035826240200549364, + -0.015384080819785595, + -0.0695020854473114, + 0.03645527362823486, + 0.013986784033477306, + -0.027729706838726997, + -0.05711805075407028, + -0.0763891413807869, + -0.16338491439819336, + -0.02358265034854412, + -0.004730133805423975, + 0.022057903930544853, + -0.011578230187296867, + 0.040772147476673126, + -0.059327173978090286, + -0.03819728270173073, + -0.050089117139577866, + -0.005152902565896511, + -0.3071111738681793, + -0.010683669708669186, + 0.030922774225473404, + 0.08924981951713562, + 0.005679265595972538, + 0.06334424018859863, + 0.016136568039655685, + -0.02575727365911007, + -0.012562219053506851, + 0.007206748705357313, + -0.1373208612203598, + -0.010450832545757294, + -0.05991309881210327, + -0.006700845435261726, + -0.006468744482845068, + -0.02040017955005169, + -0.010068708099424839, + 0.008442427963018417, + 0.012259873561561108, + -0.002103718463331461, + -0.019605906680226326, + -0.010690353810787201, + 0.0005222380859777331, + -0.015031278133392334, + -0.012983204796910286, + -0.03552224859595299, + -0.007792052812874317, + -0.035602111369371414, + -0.03479204699397087, + -0.02480080910027027, + -0.05733964219689369, + 4.38804054283537e-05, + -0.021825626492500305, + -0.03287259489297867, + -0.05437042564153671, + -0.007981077767908573, + 0.023045696318149567, + 0.05785335600376129, + 0.03685669228434563, + 0.04314129799604416, + -0.005843586288392544, + -0.024806369096040726, + -0.02562016434967518, + 0.0015172295970842242, + -0.01568800024688244, + -0.005925294477492571, + 0.010173594579100609, + 0.06834683567285538, + 0.024159085005521774, + -0.009547322988510132, + 0.014080812223255634, + 0.013578452169895172, + 0.035671167075634, + 0.01240566186606884, + -0.021352441981434822, + 0.05245270952582359, + -0.008943279273808002, + -0.010131126269698143, + 0.02976749651134014, + 0.0600045844912529, + 0.0014893191400915384, + 0.03796907886862755, + 0.01258794590830803, + -0.025344882160425186, + 0.14140591025352478, + 0.028354406356811523, + 0.0035325682256370783, + 0.05017172172665596, + 0.01994139887392521, + 0.03679897263646126, + -0.009579945355653763, + -0.012607194483280182, + -0.00034231581958010793, + 0.00046832446241751313, + 0.057916246354579926, + 0.02351403795182705, + 0.06157909706234932, + 0.00789523497223854, + -0.018361341208219528, + 0.0018971840618178248, + -0.007180131506174803, + -0.0010631990153342485, + -0.03140748664736748, + -0.028505641967058182, + 0.010669395327568054, + -0.036474280059337616, + 0.01703447848558426, + 0.04667484760284424, + -0.007303370162844658, + 0.01768752932548523, + 0.012412219308316708, + 0.013702306896448135, + 0.07651616632938385, + 0.05469715967774391, + 0.013292597606778145, + -0.006288900971412659, + 0.0215559434145689, + 0.010094149969518185, + -0.024216346442699432, + -0.15225785970687866, + 0.05467289313673973, + 0.019871067255735397, + 0.04662928730249405, + 0.05072600021958351, + -0.011824453249573708, + -0.028083933517336845, + 0.013322187587618828, + -0.044827401638031006, + 0.05955006927251816, + -0.006152187939733267, + 0.013426700606942177, + -0.014220507815480232, + 0.022510837763547897, + 0.019426455721259117, + -0.05546477064490318, + -0.49202534556388855, + 0.026985207572579384, + -0.08852843940258026, + 0.07166163623332977, + 0.05509938299655914, + -0.42284780740737915, + -0.05131356418132782, + 0.0196990966796875, + -0.008681846782565117, + 0.02739996463060379, + 0.0010900507913902402, + 0.04289104416966438, + -0.06694932281970978, + 0.05930810049176216, + -0.02174360118806362, + 0.03464379161596298, + 0.018284866586327553, + 0.018807150423526764, + 0.019874336197972298, + -0.03665176033973694, + -0.2980017066001892, + 0.050937239080667496, + -0.013874954544007778, + -0.0229057464748621, + 0.016420641914010048, + 0.024160616099834442, + -0.10750921070575714, + -0.010134756565093994, + 0.026874780654907227, + 0.007151094265282154, + 0.06304068863391876, + -0.11811652034521103, + -0.12590888142585754, + 0.031846947968006134, + -0.06898463517427444, + 0.03395693376660347, + -0.00010166154243052006, + -0.19019480049610138, + 0.06616076827049255, + -0.035927142947912216, + 0.08526375889778137, + 0.0015017242403700948, + -0.009137739427387714, + 0.04529058188199997, + -0.23621641099452972, + 0.02148340456187725, + -0.02741178683936596, + -0.20779411494731903, + ] + value = numpy.array(list_value, dtype=numpy.float32).reshape((64, 64, 1, 1)) + tensor = numpy_helper.from_array(value, name="onnx::Conv_504") + + initializers.append(tensor) + + list_value = [ + 5.195802688598633, + 0.940099835395813, + -7.016428470611572, + 5.185446739196777, + -4.134859085083008, + 2.0121846199035645, + 5.215719223022461, + 3.371406078338623, + 3.7616095542907715, + -3.6593239307403564, + 15.99945068359375, + 3.306276321411133, + 5.790191173553467, + 6.33050537109375, + 3.4512906074523926, + 2.5531861782073975, + 4.278702259063721, + 4.350361347198486, + 8.025779724121094, + -2.8830037117004395, + 2.915111541748047, + 3.592482805252075, + 5.810481071472168, + 3.4743332862854004, + 3.5245680809020996, + 1.8243598937988281, + 8.069726943969727, + 1.401036024093628, + 5.110081672668457, + -12.873579978942871, + 10.977816581726074, + 5.909627437591553, + -0.4007779359817505, + -20.147268295288086, + 6.649413585662842, + 3.325921058654785, + 5.84471321105957, + 4.47447395324707, + 3.754193067550659, + -5.167671203613281, + 3.2778055667877197, + -9.067073822021484, + 2.6243438720703125, + 1.7002031803131104, + 5.476454734802246, + 2.510835647583008, + 3.856968402862549, + 2.3172807693481445, + 12.462139129638672, + 7.355924129486084, + 4.140628814697266, + 4.807559967041016, + 5.7524309158325195, + 4.128836154937744, + 11.4532470703125, + -12.482564926147461, + 5.590144157409668, + 0.9172697067260742, + 4.356811046600342, + 0.9934853315353394, + -4.3548994064331055, + 15.853201866149902, + -5.241130828857422, + 5.9644365310668945, + ] + value = numpy.array(list_value, dtype=numpy.float32) + tensor = numpy_helper.from_array(value, name="onnx::Conv_505") + + initializers.append(tensor) + + # inputs + + inputs.append(make_tensor_value_info("input", 1, ["batch_size", 3, 32, 32])) + + # outputs + + outputs.append(make_tensor_value_info("/layer1/layer1.0/relu/Relu_output_0", 1, ["batch_size", 64, 8, 8])) + + # nodes + + node = make_node( + "Conv", + ["input", "onnx::Conv_501", "onnx::Conv_502"], + ["/conv1/Conv_output_0"], + name="/conv1/Conv", + dilations=[1, 1], + group=1, + kernel_shape=[7, 7], + pads=[3, 3, 3, 3], + strides=[2, 2], + domain="", + ) + nodes.append(node) + + node = make_node("Relu", ["/conv1/Conv_output_0"], ["/relu/Relu_output_0"], name="/relu/Relu", domain="") + nodes.append(node) + + node = make_node( + "MaxPool", + ["/relu/Relu_output_0"], + ["/maxpool/MaxPool_output_0"], + name="/maxpool/MaxPool", + ceil_mode=0, + kernel_shape=[3, 3], + pads=[1, 1, 1, 1], + strides=[2, 2], + domain="", + ) + nodes.append(node) + + node = make_node( + "Conv", + ["/maxpool/MaxPool_output_0", "onnx::Conv_504", "onnx::Conv_505"], + ["/layer1/layer1.0/conv1/Conv_output_0"], + name="/layer1/layer1.0/conv1/Conv", + dilations=[1, 1], + group=1, + kernel_shape=[1, 1], + pads=[0, 0, 0, 0], + strides=[1, 1], + domain="", + ) + nodes.append(node) + + node = make_node( + "Relu", + ["/layer1/layer1.0/conv1/Conv_output_0"], + ["/layer1/layer1.0/relu/Relu_output_0"], + name="/layer1/layer1.0/relu/Relu", + domain="", + ) + nodes.append(node) + + # opsets + opset_imports = [make_opsetid(domain, 1 if version is None else version) for domain, version in opsets.items()] + + # graph + graph = make_graph(nodes, "torch_jit", inputs, outputs, initializers) + # '7' + + onnx_model = make_model(graph, opset_imports=opset_imports, functions=functions) + onnx_model.ir_version = 7 + onnx_model.producer_name = "pytorch" + onnx_model.producer_version = "" + onnx_model.domain = "" + onnx_model.model_version = 0 + onnx_model.doc_string = "" + set_model_props(onnx_model, {}) + + return onnx_model diff --git a/onnxruntime/test/python/quantization/test_calibration.py b/onnxruntime/test/python/quantization/test_calibration.py index 14be6fa45c8c1..795447e8b79f6 100644 --- a/onnxruntime/test/python/quantization/test_calibration.py +++ b/onnxruntime/test/python/quantization/test_calibration.py @@ -275,7 +275,7 @@ def test_augment_graph_config_3(self): for output in added_outputs: self.assertTrue(output in augmented_model_outputs) - def construct_test_compute_range_model(self, test_model_path): + def construct_test_compute_data_model(self, test_model_path): # (input) # | # Relu @@ -323,15 +323,15 @@ def construct_test_compute_range_model(self, test_model_path): model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 13)]) onnx.save(model, test_model_path) - def test_compute_range(self): + def test_compute_data(self): test_model_path = Path(self._tmp_model_dir.name).joinpath("./test_model_4.onnx") - self.construct_test_compute_range_model(test_model_path.as_posix()) + self.construct_test_compute_data_model(test_model_path.as_posix()) augmented_model_path = Path(self._tmp_model_dir.name).joinpath("./augmented_test_model_4.onnx") calibrater = create_calibrator(test_model_path, augmented_model_path=augmented_model_path.as_posix()) data_reader = TestDataReader() calibrater.collect_data(data_reader) - tensors_range = calibrater.compute_range() + tensors_range = calibrater.compute_data() sess_options = onnxruntime.SessionOptions() sess_options.graph_optimization_level = onnxruntime.GraphOptimizationLevel.ORT_DISABLE_ALL @@ -355,7 +355,7 @@ def test_compute_range(self): output_names = [infer_session.get_outputs()[i].name for i in range(len(infer_session.get_outputs()))] output_min_max_dict = dict(zip(output_names, min_max_pairs)) for output_name in output_min_max_dict: - self.assertEqual(output_min_max_dict[output_name], tensors_range[output_name]) + self.assertEqual(output_min_max_dict[output_name], tensors_range[output_name].range_value) def test_augment_graph_with_zero_value_dimension(self): """TEST_CONFIG_5""" diff --git a/onnxruntime/test/python/quantization/test_onnx_model.py b/onnxruntime/test/python/quantization/test_onnx_model.py index 59f408b1eef5c..bdffae87fa4b4 100644 --- a/onnxruntime/test/python/quantization/test_onnx_model.py +++ b/onnxruntime/test/python/quantization/test_onnx_model.py @@ -5,14 +5,15 @@ # license information. # -------------------------------------------------------------------------- +import tempfile import unittest +from pathlib import Path import numpy as np import onnx from onnx import TensorProto, helper, numpy_helper -from op_test_utils import TestDataFeeds, check_model_correctness, check_op_type_count, check_op_type_order # noqa: F401 +from op_test_utils import check_op_type_order -import onnxruntime # noqa: F401 from onnxruntime.quantization.onnx_model import ONNXModel @@ -25,97 +26,148 @@ def generate_input_initializer(tensor_shape, tensor_dtype, input_name): return init +def construct_model_for_topo_sort(model_path): + # (input) + # | + # GRU + # / \ + # Conv(1) \ + # | \ + # Relu Conv(2) + # | | + # \ / + # Add + # | + # (output) + initializers = [] + input = helper.make_tensor_value_info("input", TensorProto.FLOAT, [4, 8, 12]) + output = helper.make_tensor_value_info("output", TensorProto.FLOAT, [4, 2, 8, 8]) + + # make GRU + initializers.append(generate_input_initializer([2, 24, 12], np.float32, "W_GRU")) + initializers.append(generate_input_initializer([2, 24, 8], np.float32, "R_GRU")) + initializers.append(generate_input_initializer([2, 8, 8], np.float32, "H_GRU")) + gru_node = helper.make_node( + "GRU", + ["input", "W_GRU", "R_GRU", "", "", "H_GRU"], + ["GRU_O"], + hidden_size=8, + direction="bidirectional", + ) + + initializers.append(generate_input_initializer([2, 2, 1, 1], np.float32, "W1")) + initializers.append(generate_input_initializer([2, 2, 1, 1], np.float32, "W2")) + initializers.append(generate_input_initializer([2], np.float32, "B1")) + initializers.append(generate_input_initializer([2], np.float32, "B2")) + conv_node_1 = helper.make_node("Conv", ["GRU_O", "W1", "B1"], ["Conv1_O"], name="Conv1") + conv_node_2 = helper.make_node("Conv", ["GRU_O", "W2", "B2"], ["Conv2_O"], name="Conv2") + relu_node = helper.make_node("Relu", ["Conv1_O"], ["Relu_O"], name="Relu") + add_node = helper.make_node("Add", ["Relu_O", "Conv2_O"], ["output"], name="Add") + graph = helper.make_graph( + [conv_node_1, relu_node, conv_node_2, gru_node, add_node], + "onnx_model_test", + [input], + [output], + initializer=initializers, + ) + model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 13)]) + onnx.save(model, model_path) + + +def construct_model_for_topo_sort_constant(model_path): + # (input) Constant + # \ / + # \ / + # \ / + # \ / + # Add + # | + # (output) + + initializers = [] + input = helper.make_tensor_value_info("input", TensorProto.FLOAT, [4, 8, 12]) + output = helper.make_tensor_value_info("output", TensorProto.FLOAT, [4, 8, 12]) + + # make nodes + constant_node = helper.make_node("Constant", [], ["const_output"], value_float=42.0) + add_node = helper.make_node("Add", ["input", "const_output"], ["output"], name="Add") + graph = helper.make_graph( + [add_node, constant_node], + "onnx_model_test", + [input], + [output], + initializer=initializers, + ) + model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 13)]) + onnx.save(model, model_path) + + +def construct_model_for_topo_sort_empty_input_output(model_path): + # (input1) (input2) + # | | + # Op1 Op1 + # \ / + # \ / + # \ / + # \ / + # Op2 + # | + # Op3 + # | + # (output) + + input1 = helper.make_tensor_value_info("input1", TensorProto.FLOAT, [4, 8, 12]) + input2 = helper.make_tensor_value_info("input2", TensorProto.FLOAT, [4, 8, 12]) + output = helper.make_tensor_value_info("output", TensorProto.FLOAT, [4, 8, 12]) + + # make nodes + op1_node_1 = helper.make_node("Op1", ["input1"], ["", "", "Op1_1_output"], name="op1_1", domain="Test") + op1_node_2 = helper.make_node("Op1", ["input2"], ["", "", "Op1_2_output"], name="op1_2", domain="Test") + op2_node = helper.make_node("Op2", ["Op1_1_output", "Op1_2_output"], ["op2_output"], name="op2", domain="Test") + op3_node = helper.make_node("Op3", ["", "op2_output"], ["output"], name="op3", domain="Test") + graph = helper.make_graph( + [op1_node_1, op1_node_2, op3_node, op2_node], + "onnx_model_topo_test", + [input1, input2], + [output], + ) + model = helper.make_model(graph, opset_imports=[helper.make_opsetid("Test", 1), helper.make_opsetid("", 13)]) + onnx.save(model, model_path) + + class TestONNXModel(unittest.TestCase): - def construct_model(self, model_path): - # (input) - # | - # GRU - # / \ - # Conv(1) \ - # | \ - # Relu Conv(2) - # | | - # \ / - # Add - # | - # (output) - initializers = [] - input = helper.make_tensor_value_info("input", TensorProto.FLOAT, [4, 8, 12]) - output = helper.make_tensor_value_info("output", TensorProto.FLOAT, [4, 2, 8, 8]) - - # make GRU - initializers.append(generate_input_initializer([2, 24, 12], np.float32, "W_GRU")) - initializers.append(generate_input_initializer([2, 24, 8], np.float32, "R_GRU")) - initializers.append(generate_input_initializer([2, 8, 8], np.float32, "H_GRU")) - gru_node = onnx.helper.make_node( - "GRU", - ["input", "W_GRU", "R_GRU", "", "", "H_GRU"], - ["GRU_O"], - hidden_size=8, - direction="bidirectional", - ) - - initializers.append(generate_input_initializer([2, 2, 1, 1], np.float32, "W1")) - initializers.append(generate_input_initializer([2, 2, 1, 1], np.float32, "W2")) - initializers.append(generate_input_initializer([2], np.float32, "B1")) - initializers.append(generate_input_initializer([2], np.float32, "B2")) - conv_node_1 = onnx.helper.make_node("Conv", ["GRU_O", "W1", "B1"], ["Conv1_O"], name="Conv1") - conv_node_2 = onnx.helper.make_node("Conv", ["GRU_O", "W2", "B2"], ["Conv2_O"], name="Conv2") - relu_node = onnx.helper.make_node("Relu", ["Conv1_O"], ["Relu_O"], name="Relu") - add_node = onnx.helper.make_node("Add", ["Relu_O", "Conv2_O"], ["output"], name="Add") - graph = helper.make_graph( - [conv_node_1, relu_node, conv_node_2, gru_node, add_node], - "onnx_model_test", - [input], - [output], - initializer=initializers, - ) - model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 13)]) - onnx.save(model, model_path) - - def construct_model_Constant(self, model_path): # noqa: N802 - # (input) Constant - # \ / - # \ / - # \ / - # \ / - # Add - # | - # (output) - - initializers = [] - input = helper.make_tensor_value_info("input", TensorProto.FLOAT, [4, 8, 12]) - output = helper.make_tensor_value_info("output", TensorProto.FLOAT, [4, 8, 12]) - - # make nodes - constant_node = onnx.helper.make_node("Constant", [], ["const_output"], value_float=42.0) - add_node = onnx.helper.make_node("Add", ["input", "const_output"], ["output"], name="Add") - graph = helper.make_graph( - [add_node, constant_node], - "onnx_model_test", - [input], - [output], - initializer=initializers, - ) - model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 13)]) - onnx.save(model, model_path) + @classmethod + def setUpClass(cls): + cls._tmp_model_dir = tempfile.TemporaryDirectory(prefix="test_onnx_model.") + + @classmethod + def tearDownClass(cls): + cls._tmp_model_dir.cleanup() def test_topo_sort(self): - test_model_path = "onnx_model_topo_sort.onnx" - self.construct_model(test_model_path) + test_model_path = str(Path(self._tmp_model_dir.name) / "onnx_model_topo_sort.onnx") + construct_model_for_topo_sort(test_model_path) onnx_model = ONNXModel(onnx.load(test_model_path)) check_op_type_order(self, onnx_model.model, ["Conv", "Relu", "Conv", "GRU", "Add"]) onnx_model.topological_sort() check_op_type_order(self, onnx_model.model, ["GRU", "Conv", "Conv", "Relu", "Add"]) def test_topo_sort_constant(self): - test_model_path = "onnx_model_topo_sort_constant.onnx" - self.construct_model_Constant(test_model_path) + test_model_path = str(Path(self._tmp_model_dir.name) / "onnx_model_topo_sort_constant.onnx") + construct_model_for_topo_sort_constant(test_model_path) onnx_model = ONNXModel(onnx.load(test_model_path)) check_op_type_order(self, onnx_model.model, ["Add", "Constant"]) onnx_model.topological_sort() check_op_type_order(self, onnx_model.model, ["Constant", "Add"]) + def test_topo_sort_empty_input_output(self): + test_model_path = str(Path(self._tmp_model_dir.name) / "onnx_model_topo_empty_input_output.onnx") + construct_model_for_topo_sort_empty_input_output(test_model_path) + onnx_model = ONNXModel(onnx.load(test_model_path)) + check_op_type_order(self, onnx_model.model, ["Op1", "Op1", "Op3", "Op2"]) + onnx_model.topological_sort() + check_op_type_order(self, onnx_model.model, ["Op1", "Op1", "Op2", "Op3"]) + if __name__ == "__main__": unittest.main() diff --git a/onnxruntime/test/python/quantization/test_op_attention.py b/onnxruntime/test/python/quantization/test_op_attention.py index 2ed1d2a678adf..dd2b939307ba1 100644 --- a/onnxruntime/test/python/quantization/test_op_attention.py +++ b/onnxruntime/test/python/quantization/test_op_attention.py @@ -75,7 +75,9 @@ def make_matmul_node(input_name, weight_shape, weight_name, output_name): [output_tensor], initializer=initializers, ) - model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 13)]) + model = helper.make_model( + graph, opset_imports=[helper.make_opsetid("", 13), helper.make_opsetid("com.microsoft", 1)] + ) model.ir_version = onnx.IR_VERSION onnx.save(model, output_model_path) diff --git a/onnxruntime/test/python/quantization/test_op_concat.py b/onnxruntime/test/python/quantization/test_op_concat.py index 1c2a1fa44defc..5107ae07923b1 100644 --- a/onnxruntime/test/python/quantization/test_op_concat.py +++ b/onnxruntime/test/python/quantization/test_op_concat.py @@ -9,10 +9,10 @@ import numpy as np from onnx import TensorProto, helper, numpy_helper, save from op_test_utils import ( - InputFeedsNegOneZeroOne, check_model_correctness, check_op_type_count, check_qtype_by_node_type, + input_feeds_neg_one_zero_one, ) from onnxruntime.quantization import QuantFormat, QuantType, quantize_static @@ -91,7 +91,7 @@ def quantize_concat_test(self, activation_type, weight_type, extra_options={}): np.random.seed(1) model_fp32_path = "concat_fp32.onnx" self.construct_model(model_fp32_path) - data_reader = InputFeedsNegOneZeroOne(1, {"input": [1, 3, 15, 15]}) + data_reader = input_feeds_neg_one_zero_one(1, {"input": [1, 3, 15, 15]}) activation_proto_qtype = TensorProto.UINT8 if activation_type == QuantType.QUInt8 else TensorProto.INT8 activation_type_str = "u8" if (activation_type == QuantType.QUInt8) else "s8" diff --git a/onnxruntime/test/python/quantization/test_op_embed_layernorm.py b/onnxruntime/test/python/quantization/test_op_embed_layernorm.py index c68dac39b013a..8e15bfb61c8fb 100644 --- a/onnxruntime/test/python/quantization/test_op_embed_layernorm.py +++ b/onnxruntime/test/python/quantization/test_op_embed_layernorm.py @@ -27,7 +27,7 @@ def input_feeds_int32(self, n, name2shape): dr = TestDataFeeds(input_data_list) return dr - def construct_model(self, batch, hidden_size, sequence_length, model_path): + def construct_model(self, batch, hidden_size, sequence_length, model_path, empty_segment=False): # # \ / # (EmbedLayerNormalization) @@ -72,10 +72,10 @@ def construct_model(self, batch, hidden_size, sequence_length, model_path): # EmbedLayerNormalization Node: embed_layer_norm_inputs = [ "input_ids", - "segment_ids", + "segment_ids" if not empty_segment else "", "word_embed", "pos_embed", - "seg_embed", + "seg_embed" if not empty_segment else "", "gamma", "beta", ] @@ -92,16 +92,22 @@ def construct_model(self, batch, hidden_size, sequence_length, model_path): graph_name = "embed_layernorm_graph" inputs = [input_ids_tensor, segment_ids_tensor] outputs = [layernorm_out_tensor, mask_index_out_tensor] - initializers = [ - word_embed_initializer, - pos_embed_initializer, - seg_embed_initializer, - gamma_initializer, - beta_initializer, - ] + initializers = ( + [ + word_embed_initializer, + pos_embed_initializer, + seg_embed_initializer, + gamma_initializer, + beta_initializer, + ] + if not empty_segment + else [word_embed_initializer, pos_embed_initializer, gamma_initializer, beta_initializer] + ) graph = helper.make_graph(nodes, graph_name, inputs, outputs, initializer=initializers) - model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 14)]) + model = helper.make_model( + graph, opset_imports=[helper.make_opsetid("", 14), helper.make_opsetid("com.microsoft", 1)] + ) model.ir_version = 7 # use stable onnx ir version onnx.save(model, model_path) @@ -132,6 +138,33 @@ def test_quantize_batch_size_1(self): check_model_correctness(self, model_f32_path, model_uint8_path, data_reader.get_next()) + def test_quantize_batch_size_1_empty_segment(self): + batch = 1 + hidden_size = 4 + sequence_length = 4 + + model_f32_path = "test_embed_layer_norm_unit_test_batch1_empty_segment.onnx" + model_uint8_path = "test_embed_layer_norm_unit_test_batch1_uint8_empty_segment.onnx" + + self.construct_model(batch, hidden_size, sequence_length, model_f32_path, empty_segment=True) + + data_reader = self.input_feeds_int32( + 1, + { + "input_ids": [batch, sequence_length], + "segment_ids": [batch, sequence_length], + }, + ) + + quantize_dynamic(model_f32_path, model_uint8_path) + + # Quantization should not have any DequantizeLinear nodes: + qnode_counts = {"DequantizeLinear": 0, "QEmbedLayerNormalization": 1} + check_op_type_count(self, model_uint8_path, **qnode_counts) + data_reader.rewind() + + check_model_correctness(self, model_f32_path, model_uint8_path, data_reader.get_next()) + def test_quantize_batch_size_2(self): batch = 2 hidden_size = 4 @@ -159,6 +192,33 @@ def test_quantize_batch_size_2(self): check_model_correctness(self, model_f32_path, model_uint8_path, data_reader.get_next()) + def test_quantize_batch_size_2_empty_segment(self): + batch = 2 + hidden_size = 4 + sequence_length = 4 + + model_f32_path = "test_embed_layer_norm_unit_test_batch2_empty_segment.onnx" + model_uint8_path = "test_embed_layer_norm_unit_test_batch2_uint8_empty_segment.onnx" + + self.construct_model(batch, hidden_size, sequence_length, model_f32_path, empty_segment=True) + + data_reader = self.input_feeds_int32( + 1, + { + "input_ids": [batch, sequence_length], + "segment_ids": [batch, sequence_length], + }, + ) + + quantize_dynamic(model_f32_path, model_uint8_path) + + # Quantization should not have any DequantizeLinear nodes: + qnode_counts = {"DequantizeLinear": 0, "QEmbedLayerNormalization": 1} + check_op_type_count(self, model_uint8_path, **qnode_counts) + data_reader.rewind() + + check_model_correctness(self, model_f32_path, model_uint8_path, data_reader.get_next()) + if __name__ == "__main__": unittest.main() diff --git a/onnxruntime/test/python/quantization/test_op_gemm.py b/onnxruntime/test/python/quantization/test_op_gemm.py index 89bc0fe19747d..54ef1cc1d5446 100644 --- a/onnxruntime/test/python/quantization/test_op_gemm.py +++ b/onnxruntime/test/python/quantization/test_op_gemm.py @@ -6,13 +6,24 @@ # -------------------------------------------------------------------------- import unittest +import warnings import numpy as np import onnx +from numpy.testing import assert_allclose from onnx import TensorProto, helper -from op_test_utils import TestDataFeeds, check_model_correctness, check_op_type_count, check_qtype_by_node_type +from onnx.reference import ReferenceEvaluator +from op_test_utils import ( + QGemm, + TestDataFeeds, + check_model_correctness, + check_op_type_count, + check_qtype_by_node_type, + onnx_recent_enough, +) -from onnxruntime.quantization import QuantFormat, QuantType, quantize_dynamic, quantize_static +from onnxruntime import InferenceSession +from onnxruntime.quantization import CalibrationMethod, QuantFormat, QuantType, quantize_dynamic, quantize_static class TestOpGemm(unittest.TestCase): @@ -26,7 +37,7 @@ def input_feeds(self, n, name2shape): dr = TestDataFeeds(input_data_list) return dr - def construct_model_gemm(self, output_model_path): + def construct_model_gemm(self, output_model_path, add_clip=True): # (input) # | # Gemm @@ -67,15 +78,20 @@ def make_gemm(input_name, weight_shape, weight_name, bias_shape, bias_name, outp gemm1_output_name, ) - # make Clip - clip_min_name = "clip_min" - clip_max_name = "clip_max" - clip_output_name = "clip_output" - clip_inputs = [gemm1_output_name, clip_min_name, clip_max_name] - clip_outputs = [clip_output_name] - initializers.append(onnx.numpy_helper.from_array(np.array(-1.0, dtype=np.float32), name=clip_min_name)) - initializers.append(onnx.numpy_helper.from_array(np.array(1.0, dtype=np.float32), name=clip_max_name)) - clip_node = onnx.helper.make_node("Clip", clip_inputs, clip_outputs) + if add_clip: + # make Clip + clip_min_name = "clip_min" + clip_max_name = "clip_max" + clip_output_name = "clip_output" + clip_inputs = [gemm1_output_name, clip_min_name, clip_max_name] + clip_outputs = [clip_output_name] + initializers.append(onnx.numpy_helper.from_array(np.array(-1.0, dtype=np.float32), name=clip_min_name)) + initializers.append(onnx.numpy_helper.from_array(np.array(1.0, dtype=np.float32), name=clip_max_name)) + clip_node = onnx.helper.make_node("Clip", clip_inputs, clip_outputs) + + else: + clip_output_name = "clip_output" + clip_node = onnx.helper.make_node("Identity", [gemm1_output_name], [clip_output_name]) # make gemm2 node gemm2_node = make_gemm( @@ -103,6 +119,16 @@ def make_gemm(input_name, weight_shape, weight_name, bias_shape, bias_name, outp onnx.save(model, output_model_path) + @staticmethod + def str_type(qtype): + if qtype == QuantType.QUInt8: + return "u8" + if qtype == QuantType.QInt8: + return "s8" + if qtype == QuantType.QFLOAT8E4M3FN: + return "f8e4m3fn" + raise ValueError(f"Unexpected value for qtype={qtype}") + def static_quant_test( self, model_fp32_path, @@ -110,10 +136,11 @@ def static_quant_test( activation_type, weight_type, extra_options={}, # noqa: B006 + calibrate_method=CalibrationMethod.MinMax, ): - activation_proto_qtype = TensorProto.UINT8 if activation_type == QuantType.QUInt8 else TensorProto.INT8 - activation_type_str = "u8" if (activation_type == QuantType.QUInt8) else "s8" - weight_type_str = "u8" if (weight_type == QuantType.QUInt8) else "s8" + activation_proto_qtype = activation_type.tensor_type + activation_type_str = self.str_type(activation_type) + weight_type_str = self.str_type(weight_type) model_int8_path = f"gemm_fp32.quant_{activation_type_str}{weight_type_str}.onnx" data_reader.rewind() @@ -125,22 +152,66 @@ def static_quant_test( activation_type=activation_type, weight_type=weight_type, extra_options=extra_options, + calibrate_method=calibrate_method, ) - qdq_count = 1 if activation_type == QuantType.QUInt8 else 2 - clip_count = 0 if activation_type == QuantType.QUInt8 else 1 - quant_nodes = {"QGemm": 2, "QuantizeLinear": qdq_count, "DequantizeLinear": qdq_count, "Clip": clip_count} + if activation_type == QuantType.QFLOAT8E4M3FN or weight_type == QuantType.QFLOAT8E4M3FN: + quant_nodes = {"QGemm": 2, "QuantizeLinear": 2, "DequantizeLinear": 2, "Identity": 1} + qnode_io_qtypes = { + "QuantizeLinear": [ + ["i", 2, activation_proto_qtype], + ["o", 0, activation_proto_qtype], + ] + } + else: + qdq_count = 1 if activation_type != QuantType.QInt8 else 2 + clip_count = 0 if activation_type != QuantType.QInt8 else 1 + quant_nodes = {"QGemm": 2, "QuantizeLinear": qdq_count, "DequantizeLinear": qdq_count, "Clip": clip_count} + qnode_io_qtypes = { + "QuantizeLinear": [ + ["i", 2, activation_proto_qtype], + ["o", 0, activation_proto_qtype], + ] + } + + if activation_type_str == "f8e4m3fn" and weight_type_str == "f8e4m3fn": + with open(model_int8_path, "rb") as f: + onx = onnx.load(f) + + nf8 = 0 + for init in onx.graph.initializer: + if init.data_type not in (TensorProto.FLOAT, TensorProto.FLOAT16, TensorProto.FLOAT8E4M3FN): + raise AssertionError(f"Unexpected data_type={init.data_type} for initializer {init.name!r}.") + if init.data_type == TensorProto.FLOAT8E4M3FN: + nf8 += 1 + if nf8 < 4: + raise AssertionError(f"Unexpected low number of float 8 initializer ({nf8}).") + check_op_type_count(self, model_int8_path, **quant_nodes) - qnode_io_qtypes = { - "QuantizeLinear": [ - ["i", 2, activation_proto_qtype], - ["o", 0, activation_proto_qtype], - ] - } qnode_io_qtypes.update({"DequantizeLinear": [["i", 2, activation_proto_qtype]]}) check_qtype_by_node_type(self, model_int8_path, qnode_io_qtypes) data_reader.rewind() - check_model_correctness(self, model_fp32_path, model_int8_path, data_reader.get_next()) + if activation_type_str == "f8e4m3fn" and weight_type_str == "f8e4m3fn": + # QGemm is not implemented for CPU. + try: + check_model_correctness( + self, + model_fp32_path, + model_int8_path, + data_reader.get_next(), + providers=["CUDAExecutionProvider", "CPUExecutionProvider"], + is_gemm=True, + ) + except Exception as e: + if ( + "Type 'tensor(float8e4m3fn)' of input parameter (input_quantized) of operator (QGemm) in node () is invalid." + in str(e) + ): + warnings.warn("Fix this test when QGemm is implemented.") + return + raise e + else: + check_model_correctness(self, model_fp32_path, model_int8_path, data_reader.get_next(), is_gemm=True) def static_quant_test_qdq( self, @@ -149,10 +220,11 @@ def static_quant_test_qdq( activation_type, weight_type, extra_options={}, # noqa: B006 + calibrate_method=CalibrationMethod.MinMax, ): - activation_proto_qtype = TensorProto.UINT8 if activation_type == QuantType.QUInt8 else TensorProto.INT8 - activation_type_str = "u8" if (activation_type == QuantType.QUInt8) else "s8" - weight_type_str = "u8" if (weight_type == QuantType.QUInt8) else "s8" + activation_proto_qtype = activation_type.tensor_type + activation_type_str = self.str_type(activation_type) + weight_type_str = self.str_type(weight_type) model_int8_path = f"gemm_fp32.quant_dqd_{activation_type_str}{weight_type_str}.onnx" data_reader.rewind() @@ -164,12 +236,34 @@ def static_quant_test_qdq( activation_type=activation_type, weight_type=weight_type, extra_options=extra_options, + calibrate_method=calibrate_method, ) - clip_count = 0 if activation_type == QuantType.QUInt8 else 1 - q_count = 3 if activation_type == QuantType.QUInt8 else 4 - dq_count = 7 if activation_type == QuantType.QUInt8 else 8 - quant_nodes = {"Gemm": 2, "QuantizeLinear": q_count, "DequantizeLinear": dq_count, "Clip": clip_count} + if activation_type == QuantType.QUInt8: + clip_count = 0 + q_count = 3 + dq_count = 7 + cast_count = 0 + elif activation_type == QuantType.QInt8: + clip_count = 1 + q_count = 4 + dq_count = 8 + cast_count = 0 + elif activation_type == QuantType.QFLOAT8E4M3FN: + clip_count = 0 + q_count = 4 + dq_count = 6 + cast_count = 2 + else: + raise AssertionError(f"Test not implemented for activation_type={activation_type}.") + + quant_nodes = { + "Gemm": 2, + "QuantizeLinear": q_count, + "DequantizeLinear": dq_count, + "Clip": clip_count, + "Cast": cast_count, + } check_op_type_count(self, model_int8_path, **quant_nodes) qnode_io_qtypes = { "QuantizeLinear": [ @@ -179,7 +273,7 @@ def static_quant_test_qdq( } check_qtype_by_node_type(self, model_int8_path, qnode_io_qtypes) data_reader.rewind() - check_model_correctness(self, model_fp32_path, model_int8_path, data_reader.get_next()) + check_model_correctness(self, model_fp32_path, model_int8_path, data_reader.get_next(), is_gemm=True) def dynamic_quant_test( self, @@ -210,6 +304,8 @@ def dynamic_quant_test( model_fp32_path, model_int8_path, {"input": np.random.rand(5, 10).astype(np.float32)}, + dynamic=True, + is_gemm=True, ) def test_quantize_gemm(self): @@ -262,6 +358,423 @@ def test_quantize_gemm_s8s8(self): # self.dynamic_quant_test(model_fp32_path, data_reader, activation_type=QuantType.QInt8, weight_type=QuantType.QInt8, # extra_options={'ActivationSymmetric': True}) + def test_quantize_gemm_e4m3fn_same(self): + np.random.seed(1) + model_fp32_path = "gemm_fp32.onnx" + self.construct_model_gemm(model_fp32_path, add_clip=False) + data_reader = self.input_feeds(1, {"input": [5, 10]}) + + self.static_quant_test_qdq( + model_fp32_path, + data_reader, + activation_type=QuantType.QFLOAT8E4M3FN, + weight_type=QuantType.QFLOAT8E4M3FN, + extra_options={"scenario": "same"}, + calibrate_method=CalibrationMethod.Distribution, + ) + self.static_quant_test( + model_fp32_path, + data_reader, + activation_type=QuantType.QFLOAT8E4M3FN, + weight_type=QuantType.QFLOAT8E4M3FN, + extra_options={"scenario": "same"}, + calibrate_method=CalibrationMethod.Distribution, + ) + + def test_quantize_gemm_e4m3fn_p3(self): + np.random.seed(1) + model_fp32_path = "gemm_fp32.onnx" + self.construct_model_gemm(model_fp32_path, add_clip=False) + data_reader = self.input_feeds(1, {"input": [5, 10]}) + + self.static_quant_test_qdq( + model_fp32_path, + data_reader, + activation_type=QuantType.QFLOAT8E4M3FN, + weight_type=QuantType.QFLOAT8E4M3FN, + extra_options={"scenario": "p3"}, + calibrate_method=CalibrationMethod.Distribution, + ) + self.static_quant_test( + model_fp32_path, + data_reader, + activation_type=QuantType.QFLOAT8E4M3FN, + weight_type=QuantType.QFLOAT8E4M3FN, + extra_options={"scenario": "p3"}, + calibrate_method=CalibrationMethod.Distribution, + ) + + def test_qgemm_ref_uint8(self): + model = onnx.helper.make_model( + onnx.helper.make_graph( + [ + onnx.helper.make_node( + "QGemm", + ["A", "scaleA", "zpA", "B", "scaleB", "zpB", "C", "scale", "zp"], + ["Y"], + alpha=1.0, + transB=1, + domain="com.microsoft", + ) + ], + "qgemm_graph", + [ + onnx.helper.make_tensor_value_info("A", TensorProto.UINT8, [None, None]), + onnx.helper.make_tensor_value_info("scaleA", TensorProto.FLOAT, [1]), + onnx.helper.make_tensor_value_info("zpA", TensorProto.UINT8, [1]), + onnx.helper.make_tensor_value_info("B", TensorProto.UINT8, [None, None]), + onnx.helper.make_tensor_value_info("scaleB", TensorProto.FLOAT, [1]), + onnx.helper.make_tensor_value_info("zpB", TensorProto.UINT8, [1]), + onnx.helper.make_tensor_value_info("C", TensorProto.INT32, [None, None]), + onnx.helper.make_tensor_value_info("scale", TensorProto.FLOAT, [1]), + onnx.helper.make_tensor_value_info("zp", TensorProto.UINT8, [1]), + ], + [ + onnx.helper.make_tensor_value_info("Y", TensorProto.UINT8, [None, None]), + ], + ), + opset_imports=[onnx.helper.make_opsetid("", 18), onnx.helper.make_opsetid("com.microsoft", 1)], + ) + + sess = InferenceSession(model.SerializeToString(), providers=["CPUExecutionProvider"]) + ref = ReferenceEvaluator(model, new_ops=[QGemm]) + + # simple case + A = np.array([[2, 1], [1, 0]], dtype=np.uint8) + scaleA = np.array([1], dtype=np.float32) + zpA = np.array([0], dtype=np.uint8) + B = np.array([[0, 1], [1, 3]], dtype=np.uint8) + scaleB = np.array([1], dtype=np.float32) + zpB = np.array([0], dtype=np.uint8) + C = np.array([[0, 0], [0, 0]], dtype=np.int32) + scale = np.array([1], dtype=np.float32) + zp = np.array([0], dtype=np.uint8) + feeds = dict(A=A, scaleA=scaleA, zpA=zpA, B=B, scaleB=scaleB, zpB=zpB, C=C, scale=scale, zp=zp) + expected = sess.run(None, feeds)[0] + got = ref.run(None, feeds)[0] + assert_allclose(expected, got) + + # different scale for A + scaleA *= 2 + expected = sess.run(None, feeds)[0] + got = ref.run(None, feeds)[0] + assert_allclose(expected, got) + + # different scale for B + scaleB *= 20 + expected = sess.run(None, feeds)[0] + got = ref.run(None, feeds)[0] + assert_allclose(expected, got) + + # different scale for output + scale *= 0.5 + expected = sess.run(None, feeds)[0] + got = ref.run(None, feeds)[0] + assert_allclose(expected, got) + + # negative scaleA + scaleA *= -1 + expected = sess.run(None, feeds)[0] + got = ref.run(None, feeds)[0] + assert_allclose(expected, got) + + # zpA != 0 + zpA += 5 + expected = sess.run(None, feeds)[0] + got = ref.run(None, feeds)[0] + assert_allclose(expected, got) + + # zpB != 0 + zpB += 105 + expected = sess.run(None, feeds)[0] + got = ref.run(None, feeds)[0] + assert_allclose(expected, got) + + # zp != 0 + zp += 77 + expected = sess.run(None, feeds)[0] + got = ref.run(None, feeds)[0] + assert_allclose(expected, got) + + def test_qgemm_ref_int8(self): + model = onnx.helper.make_model( + onnx.helper.make_graph( + [ + onnx.helper.make_node( + "QGemm", + ["A", "scaleA", "zpA", "B", "scaleB", "zpB", "C", "scale", "zp"], + ["Y"], + alpha=1.0, + transB=1, + domain="com.microsoft", + ) + ], + "qgemm_graph", + [ + onnx.helper.make_tensor_value_info("A", TensorProto.INT8, [None, None]), + onnx.helper.make_tensor_value_info("scaleA", TensorProto.FLOAT, [1]), + onnx.helper.make_tensor_value_info("zpA", TensorProto.INT8, [1]), + onnx.helper.make_tensor_value_info("B", TensorProto.INT8, [None, None]), + onnx.helper.make_tensor_value_info("scaleB", TensorProto.FLOAT, [1]), + onnx.helper.make_tensor_value_info("zpB", TensorProto.INT8, [1]), + onnx.helper.make_tensor_value_info("C", TensorProto.INT32, [None, None]), + onnx.helper.make_tensor_value_info("scale", TensorProto.FLOAT, [1]), + onnx.helper.make_tensor_value_info("zp", TensorProto.INT8, [1]), + ], + [ + onnx.helper.make_tensor_value_info("Y", TensorProto.INT8, [None, None]), + ], + ), + opset_imports=[onnx.helper.make_opsetid("", 18), onnx.helper.make_opsetid("com.microsoft", 1)], + ) + + sess = InferenceSession(model.SerializeToString(), providers=["CPUExecutionProvider"]) + ref = ReferenceEvaluator(model, new_ops=[QGemm]) + + # simple case + A = np.array([[2, 1], [1, 0]], dtype=np.int8) + scaleA = np.array([1], dtype=np.float32) + zpA = np.array([0], dtype=np.int8) + B = np.array([[0, 1], [1, 3]], dtype=np.int8) + scaleB = np.array([1], dtype=np.float32) + zpB = np.array([0], dtype=np.int8) + C = np.array([[0, 0], [0, 0]], dtype=np.int32) + scale = np.array([1], dtype=np.float32) + zp = np.array([0], dtype=np.int8) + feeds = dict(A=A, scaleA=scaleA, zpA=zpA, B=B, scaleB=scaleB, zpB=zpB, C=C, scale=scale, zp=zp) + expected = sess.run(None, feeds)[0] + got = ref.run(None, feeds)[0] + assert_allclose(expected, got) + + # different scale for A + scaleA *= 2 + expected = sess.run(None, feeds)[0] + got = ref.run(None, feeds)[0] + assert_allclose(expected, got) + + # different scale for B + scaleB *= 20 + expected = sess.run(None, feeds)[0] + got = ref.run(None, feeds)[0] + assert_allclose(expected, got) + + # different scale for output + scale *= 0.5 + expected = sess.run(None, feeds)[0] + got = ref.run(None, feeds)[0] + assert_allclose(expected, got) + + # negative scaleA + scaleA *= -1 + expected = sess.run(None, feeds)[0] + got = ref.run(None, feeds)[0] + assert_allclose(expected, got) + + # zpA != 0 + zpA += 5 + expected = sess.run(None, feeds)[0] + got = ref.run(None, feeds)[0] + assert_allclose(expected, got) + + # zpB != 0 + zpB += 105 + expected = sess.run(None, feeds)[0] + got = ref.run(None, feeds)[0] + assert_allclose(expected, got) + + # zp != 0 + zp -= 77 + expected = sess.run(None, feeds)[0] + got = ref.run(None, feeds)[0] + assert_allclose(expected, got) + + def test_q_ref_uint8(self): + model = onnx.helper.make_model( + onnx.helper.make_graph( + [ + onnx.helper.make_node( + "QuantizeLinear", + ["A", "scaleA", "zpA"], + ["Y"], + axis=0, + ) + ], + "qgemm_graph", + [ + onnx.helper.make_tensor_value_info("A", TensorProto.FLOAT, [None, None]), + onnx.helper.make_tensor_value_info("scaleA", TensorProto.FLOAT, [1]), + onnx.helper.make_tensor_value_info("zpA", TensorProto.UINT8, [1]), + ], + [ + onnx.helper.make_tensor_value_info("Y", TensorProto.UINT8, [None, None]), + ], + ), + opset_imports=[onnx.helper.make_opsetid("", 18), onnx.helper.make_opsetid("com.microsoft", 1)], + ) + + sess = InferenceSession(model.SerializeToString(), providers=["CPUExecutionProvider"]) + ref = ReferenceEvaluator(model, new_ops=[QGemm]) + + # simple case + A = np.array([[2, 1], [1, 0]], dtype=np.float32) + scaleA = np.array([1], dtype=np.float32) + zpA = np.array([0], dtype=np.uint8) + feeds = dict(A=A, scaleA=scaleA, zpA=zpA) + expected = sess.run(None, feeds)[0] + got = ref.run(None, feeds)[0] + assert_allclose(expected, got) + + # different scale for A + scaleA *= 2 + expected = sess.run(None, feeds)[0] + got = ref.run(None, feeds)[0] + if onnx_recent_enough: + # Test with ReferenceEvaluator requires PR https://github.com/onnx/onnx/pull/5408/. + assert_allclose(expected, got) + else: + self.assertEqual(expected.shape, got.shape) + + # negative scaleA + scaleA *= -1 + expected = sess.run(None, feeds)[0] + got = ref.run(None, feeds)[0] + if onnx_recent_enough: + # Test with ReferenceEvaluator requires PR https://github.com/onnx/onnx/pull/5408/. + assert_allclose(expected, got) + else: + self.assertEqual(expected.shape, got.shape) + + # zpA != 0 + zpA += 5 + expected = sess.run(None, feeds)[0] + got = ref.run(None, feeds)[0] + if onnx_recent_enough: + # Test with ReferenceEvaluator requires PR https://github.com/onnx/onnx/pull/5408/. + assert_allclose(expected, got) + else: + self.assertEqual(expected.shape, got.shape) + + def test_q_ref_int8(self): + model = onnx.helper.make_model( + onnx.helper.make_graph( + [ + onnx.helper.make_node( + "QuantizeLinear", + ["A", "scaleA", "zpA"], + ["Y"], + axis=0, + ) + ], + "qgemm_graph", + [ + onnx.helper.make_tensor_value_info("A", TensorProto.FLOAT, [None, None]), + onnx.helper.make_tensor_value_info("scaleA", TensorProto.FLOAT, [1]), + onnx.helper.make_tensor_value_info("zpA", TensorProto.INT8, [1]), + ], + [ + onnx.helper.make_tensor_value_info("Y", TensorProto.INT8, [None, None]), + ], + ), + opset_imports=[onnx.helper.make_opsetid("", 18), onnx.helper.make_opsetid("com.microsoft", 1)], + ) + + sess = InferenceSession(model.SerializeToString(), providers=["CPUExecutionProvider"]) + ref = ReferenceEvaluator(model, new_ops=[QGemm]) + + # simple case + A = np.array([[2, 1], [1, 0]], dtype=np.float32) + scaleA = np.array([1], dtype=np.float32) + zpA = np.array([0], dtype=np.int8) + feeds = dict(A=A, scaleA=scaleA, zpA=zpA) + expected = sess.run(None, feeds)[0] + got = ref.run(None, feeds)[0] + assert_allclose(expected, got) + + # different scale for A + scaleA *= 2 + expected = sess.run(None, feeds)[0] + got = ref.run(None, feeds)[0] + if onnx_recent_enough: + # Test with ReferenceEvaluator requires PR https://github.com/onnx/onnx/pull/5408/. + assert_allclose(expected, got) + else: + self.assertEqual(expected.shape, got.shape) + + # negative scaleA + scaleA *= -1 + expected = sess.run(None, feeds)[0] + got = ref.run(None, feeds)[0] + if onnx_recent_enough: + # Test with ReferenceEvaluator requires PR https://github.com/onnx/onnx/pull/5408/. + assert_allclose(expected, got) + else: + self.assertEqual(expected.shape, got.shape) + + # zpA != 0 + zpA += 5 + expected = sess.run(None, feeds)[0] + got = ref.run(None, feeds)[0] + if onnx_recent_enough: + # Test with ReferenceEvaluator requires PR https://github.com/onnx/onnx/pull/5408/. + assert_allclose(expected, got) + else: + self.assertEqual(expected.shape, got.shape) + + def test_qgemm_ref_uint8_specific_example(self): + model = onnx.helper.make_model( + onnx.helper.make_graph( + [ + onnx.helper.make_node( + "QGemm", + ["A", "scaleA", "zpA", "B", "scaleB", "zpB", "C", "scale", "zp"], + ["Y"], + alpha=1.0, + transB=1, + domain="com.microsoft", + ) + ], + "qgemm_graph", + [ + onnx.helper.make_tensor_value_info("A", TensorProto.UINT8, [None, None]), + onnx.helper.make_tensor_value_info("scaleA", TensorProto.FLOAT, [1]), + onnx.helper.make_tensor_value_info("zpA", TensorProto.UINT8, [1]), + onnx.helper.make_tensor_value_info("B", TensorProto.UINT8, [None, None]), + onnx.helper.make_tensor_value_info("scaleB", TensorProto.FLOAT, [1]), + onnx.helper.make_tensor_value_info("zpB", TensorProto.UINT8, [1]), + onnx.helper.make_tensor_value_info("C", TensorProto.INT32, [None, None]), + onnx.helper.make_tensor_value_info("scale", TensorProto.FLOAT, [1]), + onnx.helper.make_tensor_value_info("zp", TensorProto.UINT8, [1]), + ], + [ + onnx.helper.make_tensor_value_info("Y", TensorProto.UINT8, [None, None]), + ], + ), + opset_imports=[onnx.helper.make_opsetid("", 18), onnx.helper.make_opsetid("com.microsoft", 1)], + ) + + sess = InferenceSession(model.SerializeToString(), providers=["CPUExecutionProvider"]) + ref = ReferenceEvaluator(model, new_ops=[QGemm]) + + # simple case + feeds = { + "A": np.array([[1, 1, 128, 255, 128, 1, 255], [1, 128, 1, 1, 255, 255, 128]], dtype=np.uint8), + "B": np.array( + [[170, 89, 92, 72, 142, 27, 174], [164, 36, 99, 97, 152, 71, 105], [71, 153, 144, 129, 144, 86, 107]], + dtype=np.uint8, + ), + "C": np.array([[-710, -11278, 2355]], dtype=np.int32), + "scale": np.array([0.00784314], dtype=np.float32), + "scaleA": np.array([0.0062805], dtype=np.float32), + "scaleB": np.array([0.00274995], dtype=np.float32), + "zp": np.array([128], dtype=np.uint8), + "zpA": np.array([137], dtype=np.uint8), + "zpB": np.array([111], dtype=np.uint8), + } + + expected = sess.run(None, feeds)[0] + got = ref.run(None, feeds)[0] + assert_allclose(expected, got) + if __name__ == "__main__": - unittest.main() + unittest.main(verbosity=2) diff --git a/onnxruntime/test/python/quantization/test_op_matmulfpq4.py b/onnxruntime/test/python/quantization/test_op_matmulfpq4.py new file mode 100644 index 0000000000000..170bb09a0fdeb --- /dev/null +++ b/onnxruntime/test/python/quantization/test_op_matmulfpq4.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +import tempfile +import unittest +from pathlib import Path +from typing import Dict, Tuple, Union + +import numpy as np +import onnx +from onnx import TensorProto, helper +from op_test_utils import TestDataFeeds, check_model_correctness, check_op_type_count + +from onnxruntime.quantization import MatMulWeight4Quantizer, quant_utils + + +class TestOpMatMulFpQ4(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls._tmp_model_dir = tempfile.TemporaryDirectory(prefix="test_matmulfpq4.") + + @classmethod + def tearDownClass(cls): + cls._tmp_model_dir.cleanup() + + def fill_int4_data(self, shape: Union[int, Tuple[int, ...]], symmetric: bool) -> np.ndarray: + line = np.zeros(shape) + line = line.reshape(-1) + + if symmetric: + v = -2.0 + for i in range(line.shape[0]): + if v == 0 or v == -3 or v == 3: + v += 1 + line[i] = v + v += 1 + if v >= 8: + v = -8 + else: + v = 0.0 + for i in range(line.shape[0]): + line[i] = v + v += 1 + if v >= 16: + v = 0 + + return line.reshape(shape) + + def input_feeds(self, n: int, name2shape: Dict[str, Union[int, Tuple[int, ...]]]) -> TestDataFeeds: + input_data_list = [] + for _i in range(n): + inputs = {} + for name, shape in name2shape.items(): + inputs.update({name: np.random.randint(-1, 2, shape).astype(np.float32)}) + input_data_list.extend([inputs]) + dr = TestDataFeeds(input_data_list) + return dr + + def construct_model_matmul(self, output_model_path: str, symmetric: bool) -> None: + # (input) + # | + # MatMul + # | + # (output) + input_name = "input" + output_name = "output" + initializers = [] + + def make_gemm(input_name, weight_shape: Union[int, Tuple[int, ...]], weight_name: str, output_name: str): + weight_data = self.fill_int4_data(weight_shape, symmetric).astype(np.float32) + initializers.append(onnx.numpy_helper.from_array(weight_data, name=weight_name)) + return onnx.helper.make_node( + "MatMul", + [input_name, weight_name], + [output_name], + ) + + in_features = 52 + out_features = 288 + # make MatMulFpQ4 node + matmul_node = make_gemm( + input_name, + [in_features, out_features], + "linear1.weight", + output_name, + ) + + # make graph + input_tensor = helper.make_tensor_value_info(input_name, TensorProto.FLOAT, [-1, in_features]) + output_tensor = helper.make_tensor_value_info(output_name, TensorProto.FLOAT, [-1, out_features]) + graph_name = "matmul_test" + graph = helper.make_graph( + [matmul_node], + graph_name, + [input_tensor], + [output_tensor], + initializer=initializers, + ) + model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 13)]) + model.ir_version = 7 # use stable onnx ir version + + onnx.save(model, output_model_path) + + def quant_test( + self, + model_fp32_path: str, + data_reader: TestDataFeeds, + quantization_type: int, # 0: BlkQ4Sym, 1: BlkQ4Zp8 + ): + qtype_str = "BlkQ4Sym" if (quantization_type == 0) else "BlkQ4Zp8" + model_int4_path = str(Path(self._tmp_model_dir.name).joinpath(f"matmulfpq4_{qtype_str}.onnx").absolute()) + + # Quantize fp32 model to int4 model + model = quant_utils.load_model_with_shape_infer(Path(model_fp32_path)) + quant = MatMulWeight4Quantizer(model, quantization_type) + quant.process() + quant.model.save_model_to_file(model_int4_path, False) + + quant_nodes = {"MatMulFpQ4": 1} + check_op_type_count(self, model_int4_path, **quant_nodes) + + data_reader.rewind() + + try: + check_model_correctness(self, model_fp32_path, model_int4_path, data_reader.get_next()) + except Exception as exception: + if "4b quantization not yet supported on this hardware platform!" in exception.args[0]: + # Currently we don't have int4 quantization support on all platforms, has to tolerate this exception + pass + else: + raise exception + + def test_quantize_matmul_int4_symmetric(self): + np.random.seed(13) + + model_fp32_path = str(Path(self._tmp_model_dir.name).joinpath("matmul_fp32_symmetric.onnx").absolute()) + self.construct_model_matmul(model_fp32_path, symmetric=True) + data_reader = self.input_feeds(1, {"input": [100, 52]}) + self.quant_test(model_fp32_path, data_reader, quantization_type=MatMulWeight4Quantizer.BlkQ4Sym) + + def test_quantize_matmul_int4_offsets(self): + model_fp32_path = str(Path(self._tmp_model_dir.name).joinpath("matmul_fp32_offset.onnx").absolute()) + self.construct_model_matmul(model_fp32_path, symmetric=False) + data_reader = self.input_feeds(1, {"input": [100, 52]}) + self.quant_test(model_fp32_path, data_reader, quantization_type=MatMulWeight4Quantizer.BlkQ4Zp8) + + +if __name__ == "__main__": + unittest.main() diff --git a/onnxruntime/test/python/quantization/test_op_split.py b/onnxruntime/test/python/quantization/test_op_split.py index 4a81f134f235d..13803b4d3e662 100644 --- a/onnxruntime/test/python/quantization/test_op_split.py +++ b/onnxruntime/test/python/quantization/test_op_split.py @@ -10,10 +10,10 @@ import onnx from onnx import TensorProto, helper, save from op_test_utils import ( - InputFeedsNegOneZeroOne, check_model_correctness, check_op_type_count, check_qtype_by_node_type, + input_feeds_neg_one_zero_one, ) from onnxruntime.quantization import QuantFormat, QuantType, quantize_static @@ -78,7 +78,7 @@ def quantize_split_test(self, activation_type, weight_type, extra_options={}): np.random.seed(1) model_fp32_path = "split_fp32.onnx" self.construct_model(model_fp32_path) - data_reader = InputFeedsNegOneZeroOne(1, {"input": [6, 3]}) + data_reader = input_feeds_neg_one_zero_one(1, {"input": [6, 3]}) activation_proto_qtype = TensorProto.UINT8 if activation_type == QuantType.QUInt8 else TensorProto.INT8 activation_type_str = "u8" if (activation_type == QuantType.QUInt8) else "s8" diff --git a/onnxruntime/test/python/quantization/test_op_where.py b/onnxruntime/test/python/quantization/test_op_where.py index 400594c780193..4f96283c7d03b 100644 --- a/onnxruntime/test/python/quantization/test_op_where.py +++ b/onnxruntime/test/python/quantization/test_op_where.py @@ -50,7 +50,9 @@ def construct_model(model_path, input_shape): [out_put], initializer=initializers, ) - model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 16)]) + model = helper.make_model( + graph, opset_imports=[helper.make_opsetid("", 16), helper.make_opsetid("com.microsoft", 1)] + ) save(model, model_path) def quantize_where_test(self, activation_type, weight_type, extra_options={}): # noqa: B006 @@ -145,7 +147,7 @@ def test_quantize_where_u8u8(self): self.quantize_where_test(QuantType.QUInt8, QuantType.QUInt8, extra_options={"ForceQuantizeNoInputCheck": True}) print(__name__) - def test_quantize_where_u8u8_no_ForceQuantizeNoInputCheck(self): # noqa: N802 + def test_quantize_where_u8u8_no_force_quantize_no_input_check(self): self.quantize_where_test(QuantType.QUInt8, QuantType.QUInt8, extra_options={"ForceQuantizeNoInputCheck": False}) print(__name__) diff --git a/onnxruntime/test/python/quantization/test_qdq.py b/onnxruntime/test/python/quantization/test_qdq.py index f9f90998c8dc0..5c2db435d7fb5 100644 --- a/onnxruntime/test/python/quantization/test_qdq.py +++ b/onnxruntime/test/python/quantization/test_qdq.py @@ -21,6 +21,7 @@ ) from onnxruntime.quantization import QDQQuantizer, QuantFormat, QuantizationMode, QuantType, quantize_static +from onnxruntime.quantization.calibrate import TensorData class TestQDQFormat(unittest.TestCase): @@ -72,19 +73,22 @@ def test_qdq_extra_options(self): test_model_path = "./test_qdq_finetune.onnx" onnx.save(model, test_model_path) - compute_range = { - "P": [0.1, 0.1], - "Q": [0.1, 0.1], - "M": [0.1, 0.1], - "N": [0.1, 0.1], - "L": [0.1, 0.1], - "O": [0.1, 0.1], + def td(vals): + return TensorData(lowest=vals[0], highest=vals[1]) + + compute_data = { + "P": td([0.1, 0.1]), + "Q": td([0.1, 0.1]), + "M": td([0.1, 0.1]), + "N": td([0.1, 0.1]), + "L": td([0.1, 0.1]), + "O": td([0.1, 0.1]), } op_types_to_quantize = ["Add"] mode = QuantizationMode.QLinearOps - model = onnx.load_model(test_model_path, False) + model = onnx.load_model(test_model_path) quantizer = QDQQuantizer( model, True, # per_channel @@ -93,7 +97,7 @@ def test_qdq_extra_options(self): True, # static QuantType.QInt8, # weight_type QuantType.QInt8, # activation_type - compute_range, + compute_data, [], # nodes_to_quantize ["Add2"], # nodes_to_exclude op_types_to_quantize, @@ -170,22 +174,25 @@ def test_qdq_extra_options_2(self): test_model_path = "./test_qdq_finetune_2.onnx" onnx.save(model, test_model_path) - compute_range = { - "L": [0.1, 0.1], - "M": [0.1, 0.1], - "N": [0.1, 0.1], - "O": [0.1, 0.1], - "P": [0.1, 0.1], - "Q": [0.1, 0.1], - "R": [0.1, 0.1], - "S": [0.1, 0.1], - "T": [0.1, 0.1], + def td(vals): + return TensorData(lowest=vals[0], highest=vals[1]) + + compute_data = { + "L": td([0.1, 0.1]), + "M": td([0.1, 0.1]), + "N": td([0.1, 0.1]), + "O": td([0.1, 0.1]), + "P": td([0.1, 0.1]), + "Q": td([0.1, 0.1]), + "R": td([0.1, 0.1]), + "S": td([0.1, 0.1]), + "T": td([0.1, 0.1]), } op_types_to_quantize = ["Add", "MatMul"] mode = QuantizationMode.QLinearOps - model = onnx.load_model(test_model_path, False) + model = onnx.load_model(test_model_path) quantizer = QDQQuantizer( model, True, # per_channel @@ -194,7 +201,7 @@ def test_qdq_extra_options_2(self): True, # static QuantType.QInt8, # weight_type QuantType.QInt8, # activation_type - compute_range, + compute_data, [], # nodes_to_quantize ["Add"], # nodes_to_exclude op_types_to_quantize, @@ -301,7 +308,6 @@ def verify_quantize_conv(self, has_bias, per_channel, is_quant_type_int8=False): reduce_range=per_channel, activation_type=QuantType.QInt8 if is_quant_type_int8 else QuantType.QUInt8, weight_type=QuantType.QInt8 if is_quant_type_int8 else QuantType.QUInt8, - optimize_model=False, ) data_reader.rewind() qdq_nodes = { @@ -324,7 +330,6 @@ def verify_quantize_conv(self, has_bias, per_channel, is_quant_type_int8=False): reduce_range=per_channel, activation_type=QuantType.QInt8 if is_quant_type_int8 else QuantType.QUInt8, weight_type=QuantType.QInt8 if is_quant_type_int8 else QuantType.QUInt8, - optimize_model=False, ) data_reader.rewind() qop_nodes = {"QLinearConv": 1, "QuantizeLinear": 1, "DequantizeLinear": 1} @@ -409,7 +414,6 @@ def verify(self, per_channel, is_quant_type_int8): reduce_range=per_channel, activation_type=QuantType.QInt8 if is_quant_type_int8 else QuantType.QUInt8, weight_type=QuantType.QInt8 if is_quant_type_int8 else QuantType.QUInt8, - optimize_model=False, ) data_reader.rewind() # topo sort check @@ -440,7 +444,6 @@ def verify(self, per_channel, is_quant_type_int8): reduce_range=per_channel, activation_type=QuantType.QInt8 if is_quant_type_int8 else QuantType.QUInt8, weight_type=QuantType.QInt8 if is_quant_type_int8 else QuantType.QUInt8, - optimize_model=False, ) data_reader.rewind() qop_nodes = {"QLinearConv": 1, "QuantizeLinear": 1, "DequantizeLinear": 1} @@ -563,29 +566,30 @@ def construct_model_conv_relu(self, output_model_path, input_shape, weight_shape onnx.save(model, output_model_path) - def verify(self, per_channel, is_quant_type_int8): + def verify_qdq(self, per_channel, activation_type, weight_type, extra_options=None): np.random.seed(1) model_fp32_path = str(Path(self._tmp_model_dir.name) / f"conv_relu_fp32.{per_channel}.onnx") - model_int8_qdq_path = str(Path(self._tmp_model_dir.name) / f"conv_relu_quant_qdq.{per_channel}.onnx") - model_int8_qop_path = str(Path(self._tmp_model_dir.name) / f"conv_relu_quant_qop.{per_channel}.onnx") + model_qdq_path = str( + Path(self._tmp_model_dir.name) / f"conv_relu_quant_qdq.{activation_type}.{weight_type}.{per_channel}.onnx" + ) data_reader = self.input_feeds(1, {"input": [1, 8, 33, 33]}) self.construct_model_conv_relu(model_fp32_path, [1, 8, 33, 33], [16, 8, 3, 3], [1, 16, 31, 31]) quantize_static( model_fp32_path, - model_int8_qdq_path, + model_qdq_path, data_reader, quant_format=QuantFormat.QDQ, per_channel=per_channel, reduce_range=per_channel, - activation_type=QuantType.QInt8 if is_quant_type_int8 else QuantType.QUInt8, - weight_type=QuantType.QInt8 if is_quant_type_int8 else QuantType.QUInt8, - optimize_model=False, + activation_type=activation_type, + weight_type=weight_type, + extra_options=extra_options, ) data_reader.rewind() # topo sort check check_op_type_order( self, - model_int8_qdq_path, + model_qdq_path, [ "DequantizeLinear", "QuantizeLinear", @@ -595,9 +599,15 @@ def verify(self, per_channel, is_quant_type_int8): "DequantizeLinear", ], ) - check_model_correctness(self, model_fp32_path, model_int8_qdq_path, data_reader.get_next()) + check_model_correctness(self, model_fp32_path, model_qdq_path, data_reader.get_next()) + + def verify_qop(self, per_channel, is_quant_type_int8): + np.random.seed(1) + model_fp32_path = str(Path(self._tmp_model_dir.name) / f"conv_relu_fp32.{per_channel}.onnx") + model_int8_qop_path = str(Path(self._tmp_model_dir.name) / f"conv_relu_quant_qop.{per_channel}.onnx") + data_reader = self.input_feeds(1, {"input": [1, 8, 33, 33]}) + self.construct_model_conv_relu(model_fp32_path, [1, 8, 33, 33], [16, 8, 3, 3], [1, 16, 31, 31]) - data_reader.rewind() quantize_static( model_fp32_path, model_int8_qop_path, @@ -607,7 +617,6 @@ def verify(self, per_channel, is_quant_type_int8): reduce_range=per_channel, activation_type=QuantType.QInt8 if is_quant_type_int8 else QuantType.QUInt8, weight_type=QuantType.QInt8 if is_quant_type_int8 else QuantType.QUInt8, - optimize_model=False, ) data_reader.rewind() qop_nodes = {"QLinearConv": 1, "QuantizeLinear": 1, "DequantizeLinear": 1} @@ -616,10 +625,25 @@ def verify(self, per_channel, is_quant_type_int8): def test_quantize_conv_without_bias(self): # only test cases per_channel=True and reduce_range=True to avoid saturation on avx2 and avx512 for weight type int8 - self.verify(True, True) # per_channel:False, is_quant_type_int8:True + self.verify_qdq(True, QuantType.QInt8, QuantType.QInt8) # per_channel:True + self.verify_qop(True, True) # per_channel:True, is_quant_type_int8:True - self.verify(False, False) # per_channel:False, is_quant_type_int8:False - self.verify(True, False) # per_channel:True, is_quant_type_int8:False + self.verify_qdq(False, QuantType.QUInt8, QuantType.QUInt8) # per_channel:False + self.verify_qop(False, False) # per_channel:False, is_quant_type_int8:False + + self.verify_qdq(True, QuantType.QUInt8, QuantType.QUInt8) # per_channel:True + self.verify_qop(True, False) # per_channel:True, is_quant_type_int8:False + + # 16-bit QDQ via contrib ops + self.verify_qdq(False, QuantType.QUInt16, QuantType.QUInt16, {"UseQDQContribOps": True}) + self.verify_qdq(False, QuantType.QInt16, QuantType.QInt16, {"UseQDQContribOps": True}) + self.verify_qdq(False, QuantType.QUInt16, QuantType.QUInt8, {"UseQDQContribOps": True}) + self.verify_qdq(False, QuantType.QInt16, QuantType.QInt8, {"UseQDQContribOps": True}) + + self.verify_qdq(True, QuantType.QUInt16, QuantType.QUInt16, {"UseQDQContribOps": True}) + self.verify_qdq(True, QuantType.QInt16, QuantType.QInt16, {"UseQDQContribOps": True}) + self.verify_qdq(True, QuantType.QUInt16, QuantType.QUInt8, {"UseQDQContribOps": True}) + self.verify_qdq(True, QuantType.QInt16, QuantType.QInt8, {"UseQDQContribOps": True}) def test_quantize_relu_conv(self): float_model_path = str(Path(self._tmp_model_dir.name) / "float_relu_convs_model.onnx") @@ -636,7 +660,6 @@ def test_quantize_relu_conv(self): reduce_range=False, activation_type=QuantType.QInt8, weight_type=QuantType.QInt8, - optimize_model=False, ) @@ -690,7 +713,7 @@ def test_activation_only(self): data_reader = self.input_feeds(2, {"input": [1, 3, 1, 3]}) qdq_model_path = str(Path(self._tmp_model_dir.name) / "qdq_relu_convs_model.onnx") - quantize_static(float_model_path, qdq_model_path, data_reader, optimize_model=False) + quantize_static(float_model_path, qdq_model_path, data_reader) qop_nodes = {"Clip": 1, "Relu": 1, "QuantizeLinear": 0, "DequantizeLinear": 0} check_op_type_count(self, qdq_model_path, **qop_nodes) diff --git a/onnxruntime/test/python/quantization/test_qdq_loss_debug.py b/onnxruntime/test/python/quantization/test_qdq_loss_debug.py index a3f7d29002648..e9108f157f953 100644 --- a/onnxruntime/test/python/quantization/test_qdq_loss_debug.py +++ b/onnxruntime/test/python/quantization/test_qdq_loss_debug.py @@ -109,13 +109,7 @@ def rewind(self): def augment_model_collect_activations( model_path: str, augmented_model_path: str, data_reader: TestDataReader ) -> Dict[str, List[np.ndarray]]: - aug_model = modify_model_output_intermediate_tensors(model_path) - - onnx.save( - aug_model, - augmented_model_path, - save_as_external_data=False, - ) + modify_model_output_intermediate_tensors(model_path, augmented_model_path) tensor_dict = collect_activations(augmented_model_path, data_reader) return tensor_dict @@ -180,7 +174,6 @@ def test_create_activation_matching_present(self): reduce_range=False, activation_type=QuantType.QInt8, weight_type=QuantType.QInt8, - optimize_model=False, ) data_reader.rewind() @@ -238,7 +231,6 @@ def test_create_weight_matching(self): reduce_range=False, activation_type=QuantType.QInt8, weight_type=QuantType.QInt8, - optimize_model=False, ) # Call function under test and verify all weights are present @@ -307,7 +299,6 @@ def test_create_weight_matching_per_channel(self): reduce_range=False, activation_type=QuantType.QInt8, weight_type=QuantType.QInt8, - optimize_model=False, ) # Call function under test and verify all weights are present diff --git a/onnxruntime/test/python/quantization/test_quant_util.py b/onnxruntime/test/python/quantization/test_quant_util.py index 9823f8f3d2770..6efa279393f03 100644 --- a/onnxruntime/test/python/quantization/test_quant_util.py +++ b/onnxruntime/test/python/quantization/test_quant_util.py @@ -13,7 +13,7 @@ import onnx from onnx import TensorProto, helper, numpy_helper -from onnxruntime.quantization.quant_utils import compute_scale_zp, load_model, model_has_infer_metadata +from onnxruntime.quantization.quant_utils import compute_scale_zp, load_model_with_shape_infer, model_has_infer_metadata class TestQuantUtil(unittest.TestCase): @@ -61,7 +61,7 @@ def test_load_external_model(self): self.assertFalse(model_has_infer_metadata(model)) model_file_path = temp_dir + "/test_load_external_model.onnx" onnx.save(model, model_file_path, save_as_external_data=True) - model_reloaded = load_model(Path(model_file_path), False) + model_reloaded = load_model_with_shape_infer(Path(model_file_path)) self.assertTrue(model_has_infer_metadata(model_reloaded)) diff --git a/onnxruntime/test/python/quantization/test_quantize_static.py b/onnxruntime/test/python/quantization/test_quantize_static.py index 1fb7ad2e9efa4..5ad5a49f00c14 100644 --- a/onnxruntime/test/python/quantization/test_quantize_static.py +++ b/onnxruntime/test/python/quantization/test_quantize_static.py @@ -7,12 +7,13 @@ import tempfile import unittest +from importlib.util import find_spec from pathlib import Path import numpy as np import onnx from onnx import TensorProto, helper -from op_test_utils import InputFeedsNegOneZeroOne, check_model_correctness, generate_random_initializer +from op_test_utils import check_model_correctness, generate_random_initializer, input_feeds_neg_one_zero_one from onnxruntime.quantization import QuantType, StaticQuantConfig, quantize, quantize_static @@ -72,7 +73,7 @@ def tearDownClass(cls): cls._tmp_model_dir.cleanup() def test_save_as_external(self): - data_reader = InputFeedsNegOneZeroOne(10, {"input": [1, self._channel_size, 1, 3]}) + data_reader = input_feeds_neg_one_zero_one(10, {"input": [1, self._channel_size, 1, 3]}) for use_external_data_format in [True, False]: quant_model_path = str(Path(self._tmp_model_dir.name) / f"quant.{use_external_data_format}.onnx") quantize_static( @@ -89,7 +90,7 @@ def test_save_as_external(self): data_reader.rewind() def test_static_quant_config(self): - data_reader = InputFeedsNegOneZeroOne(10, {"input": [1, self._channel_size, 1, 3]}) + data_reader = input_feeds_neg_one_zero_one(10, {"input": [1, self._channel_size, 1, 3]}) quant_config = StaticQuantConfig(data_reader) quant_model_path = str(Path(self._tmp_model_dir.name) / "quant.config.onnx") quantize(self._model_fp32_path, quant_model_path, quant_config) @@ -98,6 +99,25 @@ def test_static_quant_config(self): check_model_correctness(self, self._model_fp32_path, quant_model_path, data_reader.get_next()) data_reader.rewind() + @unittest.skip( + "Skip failed test in Python Packaging Test Pipeline." + "During importing neural_compressor, pycocotools throws ValueError: numpy.ndarray size changed" + ) + def test_smooth_quant(self): + if not find_spec("neural_compressor"): + self.skipTest("skip test_smooth_quant since neural_compressor is not installed") + data_reader = input_feeds_neg_one_zero_one(10, {"input": [1, self._channel_size, 1, 3]}) + quant_config = StaticQuantConfig(data_reader, extra_options={"SmoothQuant": True}) + quant_model_path = str(Path(self._tmp_model_dir.name) / "quant.config.onnx") + quantize(self._model_fp32_path, quant_model_path, quant_config) + + data_reader.rewind() + check_model_correctness(self, self._model_fp32_path, quant_model_path, data_reader.get_next()) + data_reader.rewind() + + model = onnx.load(quant_model_path) + self.assertIn("Mul", [i.op_type for i in model.graph.node]) + if __name__ == "__main__": unittest.main() diff --git a/onnxruntime/test/python/quantization/test_quantize_static_resnet.py b/onnxruntime/test/python/quantization/test_quantize_static_resnet.py new file mode 100644 index 0000000000000..1efa283af6881 --- /dev/null +++ b/onnxruntime/test/python/quantization/test_quantize_static_resnet.py @@ -0,0 +1,138 @@ +# ------------------------------------------------------------------------- +# 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 random +import tempfile +import unittest + +import numpy as np +import onnx +from numpy.testing import assert_allclose +from onnx.numpy_helper import to_array +from resnet_code import create_model + +from onnxruntime import InferenceSession +from onnxruntime import __version__ as ort_version +from onnxruntime.quantization import QuantFormat, QuantType, quantize_static +from onnxruntime.quantization.calibrate import CalibrationDataReader, CalibrationMethod + + +class FakeResnetCalibrationDataReader(CalibrationDataReader): + def __init__(self, batch_size: int = 16): + super().__init__() + self.dataset = [ + (np.random.rand(1, 3, 32, 32).astype(np.float32), random.randint(0, 9)) for _ in range(batch_size) + ] + self.iterator = iter(self.dataset) + + def get_next(self) -> dict: + try: + return {"input": next(self.iterator)[0]} + except Exception: + return None + + +class TestStaticQuantizationResNet(unittest.TestCase): + def test_quantize_static_resnet(self): + kwargs = { + "activation_type": QuantType.QUInt8, + "weight_type": QuantType.QInt8, + "calibrate_method": CalibrationMethod.Percentile, + "extra_options": { + "ActivationSymmetric": False, + "EnableSubgraph": False, + "ForceQuantizeNoInputCheck": False, + "MatMulConstBOnly": False, + "WeightSymmetric": True, + "extra.Sigmoid.nnapi": False, + }, + "nodes_to_exclude": None, + "nodes_to_quantize": None, + "op_types_to_quantize": None, + "per_channel": True, + "quant_format": QuantFormat.QDQ, + "reduce_range": False, + } + + proto = create_model() + + with tempfile.TemporaryDirectory() as temp: + model = os.path.join(temp, "resnet_first_nodes.onnx") + with open(model, "wb") as f: + f.write(proto.SerializeToString()) + + for per_channel in [True, False]: + kwargs["per_channel"] = per_channel + dataloader = FakeResnetCalibrationDataReader(16) + with self.subTest(per_channel=per_channel): + qdq_file = os.path.join( + temp, f"preprocessed-small-qdq-{1 if per_channel else 0}-ort-{ort_version}.onnx" + ) + quantize_static( + model_input=model, + model_output=qdq_file, + calibration_data_reader=dataloader, + use_external_data_format=False, + **kwargs, + ) + + # With onnxruntime==1.15.1, the initializer 'onnx::Conv_504_zero_point' is: + # * uint8(128) if per_channel is False + # * int8([0, 0, ....]) if per_channel is True + # With onnxruntime>1.16.0 + # * uint8(128) if per_channel is False + # * uint8([128, 128, ..., 127, ...]) if per_channel is True + # QLinearConv : zero point of per-channel filter must be same. + # That's why the quantization forces a symmetric quantization into INT8. + # zero_point is guaranted to be zero whatever the channel is. + + with open(qdq_file, "rb") as f: + onx = onnx.load(f) + for init in onx.graph.initializer: + arr = to_array(init) + if ( + arr.dtype == np.int8 + and "zero_point" not in init.name + and not init.name.endswith("quantized") + ): + raise AssertionError( + f"Initializer {init.name!r} has type {arr.dtype} and " + f"shape {arr.shape} but should be {np.uint8}." + ) + + sess = InferenceSession(qdq_file, providers=["CPUExecutionProvider"]) + shape = (1, 3, 32, 32) + size = np.prod(shape) + dummy = (np.arange(size) / float(size)).astype(np.float32).reshape(shape) + got = sess.run(None, {"input": dummy}) + self.assertEqual(got[0].shape, (1, 64, 8, 8)) + self.assertEqual(got[0].dtype, np.float32) + if per_channel: + expected = np.array( + [ + [[1.0862497091293335, 0.9609132409095764], [1.0862497091293335, 0.9191343784332275]], + [[0.7520190477371216, 1.0026921033859253], [1.0444709062576294, 1.0862497091293335]], + [[0.0, 0.0], [0.0, 0.0]], + [[0.0, 0.0], [0.9609132409095764, 0.7937979102134705]], + ], + dtype=np.float32, + ) + assert_allclose(expected, got[0][0, :4, :2, :2], atol=0.2) + else: + expected = np.array( + [ + [[1.428238868713379, 1.2602107524871826], [1.3442248106002808, 1.2182037830352783]], + [[0.8821475505828857, 1.0921826362609863], [1.1341897249221802, 1.1761966943740845]], + [[0.0, 0.0], [0.0, 0.0]], + [[0.0, 0.0], [1.2182037830352783, 1.050175666809082]], + ], + dtype=np.float32, + ) + assert_allclose(expected, got[0][0, :4, :2, :2], atol=0.2) + + +if __name__ == "__main__": + unittest.main(verbosity=2) diff --git a/onnxruntime/test/python/test_pytorch_export_contrib_ops.py b/onnxruntime/test/python/test_pytorch_export_contrib_ops.py index a378721932a35..5e20d6b4e692a 100644 --- a/onnxruntime/test/python/test_pytorch_export_contrib_ops.py +++ b/onnxruntime/test/python/test_pytorch_export_contrib_ops.py @@ -49,9 +49,7 @@ def to_numpy(tensor): # These set of tests verify ONNX model export and compares outputs between # PyTorch and ORT. class ONNXExporterTest(unittest.TestCase): - from torch.onnx.symbolic_helper import _export_onnx_opset_version - - opset_version = _export_onnx_opset_version + opset_version = 17 keep_initializers_as_inputs = True # For IR version 3 type export. def setUp(self): diff --git a/onnxruntime/test/python/transformers/benchmark_mha.py b/onnxruntime/test/python/transformers/benchmark_mha.py new file mode 100644 index 0000000000000..1e75268ea6c5d --- /dev/null +++ b/onnxruntime/test/python/transformers/benchmark_mha.py @@ -0,0 +1,343 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# -------------------------------------------------------------------------- + +""" +Benchmark performance of MultiHeadAttention with Nvidia GPU of Compute Capability 8.0, 8.6 or 8.9 in Linux: +sh benchmark_mha.sh +""" + +import math +import os +import statistics +import time + +import torch +from onnx import TensorProto, helper + +from onnxruntime import InferenceSession +from onnxruntime.transformers.io_binding_helper import CudaSession + + +class InputFormats: + Q_K_V_BSNH = 0 + QKV_BSN3H = 1 + Q_KV_BSNH_BSN2H = 2 + + @staticmethod + def input_format_str(format: int) -> str: + return "QKV" if format == 1 else "Q,KV" if format == 2 else "Q,K,V" + + +class Config: + batch_size: int = 0 + sequence_length: int = 0 + kv_sequence_length: int = 0 + num_heads: int = 0 + head_size: int = 0 + causal: bool = False + input_format: int = InputFormats.Q_K_V_BSNH + + def __init__(self, b, s, s2, n, h, causal, input_format): + self.batch_size = b + self.sequence_length = s + self.kv_sequence_length = s2 + self.num_heads = n + self.head_size = h + self.causal = causal + self.input_format = input_format + + +def create_multihead_attention_graph(config: Config): + query = helper.make_tensor_value_info( + "query", + TensorProto.FLOAT16, + [ + config.batch_size, + config.sequence_length, + config.num_heads * config.head_size, + ], + ) + + key = helper.make_tensor_value_info( + "key", + TensorProto.FLOAT16, + [ + config.batch_size, + config.kv_sequence_length, + config.num_heads * config.head_size, + ], + ) + + value = helper.make_tensor_value_info( + "value", + TensorProto.FLOAT16, + [ + config.batch_size, + config.kv_sequence_length, + config.num_heads * config.head_size, + ], + ) + + packed_qkv = helper.make_tensor_value_info( + "query", + TensorProto.FLOAT16, + [ + config.batch_size, + config.sequence_length, + config.num_heads, + 3, + config.head_size, + ], + ) + + packed_kv = helper.make_tensor_value_info( + "key", + TensorProto.FLOAT16, + [ + config.batch_size, + config.kv_sequence_length, + config.num_heads, + 2, + config.head_size, + ], + ) + + if config.input_format == InputFormats.QKV_BSN3H: + input_names = ["query"] + inputs = [packed_qkv] + elif config.input_format == InputFormats.Q_KV_BSNH_BSN2H: + input_names = ["query", "key"] + inputs = [query, packed_kv] + else: # input_format==InputFormats.Q_K_V_BSNH + input_names = ["query", "key", "value"] + inputs = [query, key, value] + + nodes = [ + helper.make_node( + "MultiHeadAttention", + input_names, + ["output"], + "MultiHeadAttention_0", + num_heads=config.num_heads, + domain="com.microsoft", + ), + ] + + outputs = [ + helper.make_tensor_value_info( + "output", + TensorProto.FLOAT16, + [config.batch_size, config.sequence_length, config.num_heads * config.head_size], + ), + ] + + graph = helper.make_graph( + nodes, + "MultiHeadAttention_Graph", + inputs, + outputs, + ) + + model = helper.make_model(graph) + return model.SerializeToString() + + +def input_output_shapes(config: Config): + if config.input_format == InputFormats.QKV_BSN3H: + return { + "query": (config.batch_size, config.sequence_length, config.num_heads, 3, config.head_size), + "output": (config.batch_size, config.sequence_length, config.num_heads * config.head_size), + } + + if config.input_format == InputFormats.Q_KV_BSNH_BSN2H: + return { + "query": (config.batch_size, config.sequence_length, config.num_heads * config.head_size), + "key": (config.batch_size, config.kv_sequence_length, config.num_heads, 2, config.head_size), + "output": (config.batch_size, config.sequence_length, config.num_heads * config.head_size), + } + + return { + "query": (config.batch_size, config.sequence_length, config.num_heads * config.head_size), + "key": (config.batch_size, config.kv_sequence_length, config.num_heads * config.head_size), + "value": (config.batch_size, config.kv_sequence_length, config.num_heads * config.head_size), + "output": (config.batch_size, config.sequence_length, config.num_heads * config.head_size), + } + + +def create_session( + device_id: int, config: Config, provider: str = "CUDAExecutionProvider", enable_cuda_graph: bool = False +) -> CudaSession: + onnx_model_str = create_multihead_attention_graph(config) + provider_options = CudaSession.get_cuda_provider_options(device_id, enable_cuda_graph) + ort_session = InferenceSession(onnx_model_str, providers=[(provider, provider_options), "CPUExecutionProvider"]) + device = torch.device("cuda", device_id) + cuda_session = CudaSession(ort_session, device, enable_cuda_graph) + shape_dict = input_output_shapes(config) + cuda_session.allocate_buffers(shape_dict) + return cuda_session + + +def measure_latency(cuda_session: CudaSession, input_dict): + start = time.time() + _ = cuda_session.infer(input_dict) + end = time.time() + return end - start + + +def flops(batch, sequence_length, head_size, num_heads, causal): + return 4 * batch * sequence_length**2 * num_heads * head_size // (2 if causal else 1) + + +def tflops_per_second(flop, time): + return (flop / time / 10**12) if not math.isnan(time) else 0.0 + + +def get_sm8x_kernel_name(config: Config) -> str: + # This classification is for Nvidia GPU of Compute Capability 8.* like A100. + # Note that some kernel might not exist in older or newer GPUs. + if os.getenv("ORT_DISABLE_FLASH_ATTENTION") != "1": + if config.input_format == InputFormats.QKV_BSN3H: + min_seq_len = os.getenv("ORT_MIN_SEQ_LEN_FLASH_ATTENTION_PACKED_QKV") + min_length = int(min_seq_len) if min_seq_len is not None else 513 + if config.sequence_length >= min_length: + return "Flash" + else: + return "Flash" + + if (os.getenv("ORT_DISABLE_FUSED_CROSS_ATTENTION") != "1" and config.kv_sequence_length <= 128) or ( + os.getenv("ORT_DISABLE_FUSED_ATTENTION") != "1" + and (config.sequence_length <= 384 or os.getenv("ORT_DISABLE_TRT_FLASH_ATTENTION") != "1") + ): + return "TRT" + + if os.getenv("ORT_DISABLE_MEMORY_EFFICIENT_ATTENTION") != "1": + return "MemEff" + + return "Unfused" + + +def run_tflops_test(dtype=torch.float16, enable_cuda_graph: bool = False, repeats: int = 100): + device_id = torch.cuda.current_device() + device = torch.device("cuda", device_id) + + # (batch_size, sequence_length, num_heads, head_size) + configs = [ + (32, 512, 64, 32), + (32, 512, 128, 16), + (16, 1024, 64, 32), + (16, 1024, 128, 16), + (8, 2048, 64, 32), + (8, 2048, 128, 16), + (4, 4096, 64, 32), + (4, 4096, 128, 16), + (2, 8192, 64, 32), + (2, 8192, 128, 16), + (1, 16384, 64, 32), + (1, 16384, 128, 16), + # stable diffusion + (1, 4096, 8, 40), + (1, 4096, 8, 80), + (1, 4096, 8, 160), + (4, 4096, 8, 40), + (4, 4096, 8, 80), + (4, 4096, 8, 160), + (1, 16384, 8, 40), + (1, 16384, 8, 80), + (1, 16384, 8, 160), + # bert-base + (128, 128, 12, 64), + (64, 128, 12, 64), + (128, 384, 12, 64), + (64, 384, 12, 64), + (128, 512, 12, 64), + (64, 512, 12, 64), + # TNLGv4 + (4, 2048, 32, 128), + (4, 4096, 32, 128), + (8, 2048, 32, 128), + (8, 4096, 32, 128), + ] + + print(f"enable_cuda_graph={enable_cuda_graph}") + + # List of environment variables to enable/disable attention kernels + print("Environment Variables:") + env_names = [ + "ORT_DISABLE_FLASH_ATTENTION", + "ORT_MIN_SEQ_LEN_FLASH_ATTENTION_PACKED_QKV", + "ORT_DISABLE_FUSED_ATTENTION", + "ORT_DISABLE_TRT_FLASH_ATTENTION", + "ORT_ENABLE_FUSED_CAUSAL_ATTENTION", + "ORT_DISABLE_FUSED_CROSS_ATTENTION", + "ORT_DISABLE_MEMORY_EFFICIENT_ATTENTION", + ] + for name in env_names: + value = os.getenv(name) + if value is not None: + print(f"{name}={value}") + print() + + print("format\tcausal\tbatch\tseqlen\theads\th_dim\tms\tTFLOPS\tkernel") + causal = False + for input_format in [InputFormats.Q_K_V_BSNH, InputFormats.Q_KV_BSNH_BSN2H, InputFormats.QKV_BSN3H]: + for batch_size, sequence_length, num_heads, head_size in configs: + config = Config(batch_size, sequence_length, sequence_length, num_heads, head_size, causal, input_format) + + session = create_session(device_id, config, enable_cuda_graph=enable_cuda_graph) + + qkv = torch.randn(batch_size, sequence_length, 3, num_heads, head_size, device=device, dtype=dtype) + q, k, v = qkv.unbind(dim=2) + + if input_format == InputFormats.QKV_BSN3H: + if config.sequence_length != config.kv_sequence_length: + continue + q = torch.reshape(q, (-1, config.num_heads, config.head_size)) + k = torch.reshape(k, (-1, config.num_heads, config.head_size)) + v = torch.reshape(v, (-1, config.num_heads, config.head_size)) + packed_qkv = torch.dstack((q, k, v)).reshape( + config.batch_size, config.sequence_length, config.num_heads, 3, config.head_size + ) + input_dict = {"query": packed_qkv.contiguous()} + elif input_format == InputFormats.Q_KV_BSNH_BSN2H: + q = torch.reshape(q, (config.batch_size, config.sequence_length, -1)) + k = torch.reshape(k, (-1, config.num_heads, config.head_size)) + v = torch.reshape(v, (-1, config.num_heads, config.head_size)) + packed_kv = torch.dstack((k, v)).reshape( + config.batch_size, config.sequence_length, config.num_heads, 2, config.head_size + ) + input_dict = {"query": q.contiguous(), "key": packed_kv.contiguous()} + else: # input_format == InputFormats.Q_K_V_BSNH + 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)) + input_dict = { + "query": q.contiguous(), + "key": k.contiguous(), + "value": v.contiguous(), + } + + # warm up session + _ = measure_latency(session, input_dict) + + latency_list = [] + for _ in range(repeats): + latency = measure_latency(session, input_dict) + latency_list.append(latency) + average_latency = statistics.mean(latency_list) + + del session + + # compute TFLOPS per second + speed = tflops_per_second(flops(batch_size, sequence_length, head_size, num_heads, causal), average_latency) + + kernel = get_sm8x_kernel_name(config) + format = InputFormats.input_format_str(input_format) + print( + f"{format}\t{causal}\t{batch_size}\t{sequence_length}\t{num_heads}\t{head_size}\t{average_latency * 1000:.2f}\t{speed:.2f}\t{kernel}" + ) + + +if __name__ == "__main__": + run_tflops_test(enable_cuda_graph=False) diff --git a/onnxruntime/test/python/transformers/benchmark_mha.sh b/onnxruntime/test/python/transformers/benchmark_mha.sh new file mode 100644 index 0000000000000..7b21cf1cc1e08 --- /dev/null +++ b/onnxruntime/test/python/transformers/benchmark_mha.sh @@ -0,0 +1,14 @@ +echo "flash attention v2" +ORT_DISABLE_FLASH_ATTENTION=0 ORT_MIN_SEQ_LEN_FLASH_ATTENTION_PACKED_QKV=0 python benchmark_mha.py | tee result.txt + +echo "===" +echo "TensorRT attention kernels - cross attention (when kv_seq_len <= 128) or fused attention (when seq_len <= 384) or flash attention (seq_len > 384)" +ORT_DISABLE_FLASH_ATTENTION=1 python benchmark_mha.py | tee -a result.txt + +echo "===" +echo "Memory Efficient attention" +ORT_DISABLE_FLASH_ATTENTION=1 ORT_DISABLE_TRT_FLASH_ATTENTION=1 ORT_DISABLE_FUSED_ATTENTION=1 ORT_DISABLE_FUSED_CROSS_ATTENTION=1 python benchmark_mha.py | tee -a result.txt + +echo "===" +echo "Unfused Attention (some configurations might fail)" +ORT_DISABLE_FLASH_ATTENTION=1 ORT_DISABLE_TRT_FLASH_ATTENTION=1 ORT_DISABLE_FUSED_ATTENTION=1 ORT_DISABLE_FUSED_CROSS_ATTENTION=1 ORT_DISABLE_MEMORY_EFFICIENT_ATTENTION=1 python benchmark_mha.py | tee -a result.txt diff --git a/onnxruntime/test/python/transformers/bert_padding.py b/onnxruntime/test/python/transformers/bert_padding.py new file mode 100644 index 0000000000000..a4ef7652643ab --- /dev/null +++ b/onnxruntime/test/python/transformers/bert_padding.py @@ -0,0 +1,131 @@ +# From https://github.com/Dao-AILab/flash-attention/blob/2286d7cea7ca8264165c16b2442b6436c43140de/flash_attn/bert_padding.py + +import torch +import torch.nn.functional as F +from einops import rearrange, repeat + + +class IndexFirstAxis(torch.autograd.Function): + @staticmethod + def forward(ctx, input, indices): + ctx.save_for_backward(indices) + assert input.ndim >= 2 + ctx.first_axis_dim, other_shape = input.shape[0], input.shape[1:] + second_dim = other_shape.numel() + # TD [2022-03-04] For some reason torch.gather is a bit faster than indexing. + # return input[indices] + return torch.gather(rearrange(input, "b ... -> b (...)"), 0, repeat(indices, "z -> z d", d=second_dim)).reshape( + -1, *other_shape + ) + + @staticmethod + def backward(ctx, grad_output): + (indices,) = ctx.saved_tensors + assert grad_output.ndim >= 2 + other_shape = grad_output.shape[1:] + grad_output = rearrange(grad_output, "b ... -> b (...)") + grad_input = torch.zeros( + [ctx.first_axis_dim, grad_output.shape[1]], device=grad_output.device, dtype=grad_output.dtype + ) + # TD [2022-03-04] For some reason torch.scatter is a bit faster than indexing. + # grad_input[indices] = grad_output + grad_input.scatter_(0, repeat(indices, "z -> z d", d=grad_output.shape[1]), grad_output) + return grad_input.reshape(ctx.first_axis_dim, *other_shape), None + + +index_first_axis = IndexFirstAxis.apply + + +class IndexPutFirstAxis(torch.autograd.Function): + @staticmethod + def forward(ctx, values, indices, first_axis_dim): + ctx.save_for_backward(indices) + assert indices.ndim == 1 + assert values.ndim >= 2 + output = torch.zeros(first_axis_dim, *values.shape[1:], device=values.device, dtype=values.dtype) + # TD [2022-03-04] For some reason torch.scatter is a bit faster than indexing. + output[indices] = values + # output.scatter_(0, repeat(indices, 'z -> z d', d=values.shape[1]), values) + return output + + @staticmethod + def backward(ctx, grad_output): + (indices,) = ctx.saved_tensors + # TD [2022-03-04] For some reason torch.gather is a bit faster than indexing. + grad_values = grad_output[indices] + # grad_values = torch.gather(grad_output, 0, repeat(indices, 'z -> z d', d=grad_output.shape[1])) + return grad_values, None, None + + +index_put_first_axis = IndexPutFirstAxis.apply + + +class IndexFirstAxisResidual(torch.autograd.Function): + @staticmethod + def forward(ctx, input, indices): + ctx.save_for_backward(indices) + assert input.ndim >= 2 + ctx.first_axis_dim, _ = input.shape[0], input.shape[1:] + # TD [2022-03-04] For some reason torch.gather is a bit faster than indexing. + output = input[indices] + # We don't want to reshape input (b ... -> b (...)) since it could change the channel_last + # memory format to channel_first. In other words, input might not be contiguous. + # If we don't detach, Pytorch complains about output being a view and is being modified inplace + return output, input.detach() + + @staticmethod + def backward(ctx, grad_output, grad_residual): + (indices,) = ctx.saved_tensors + assert grad_output.ndim >= 2 + other_shape = grad_output.shape[1:] + assert grad_residual.shape[1:] == other_shape + grad_input = grad_residual + # grad_input[indices] += grad_output + indices = indices.reshape(indices.shape[0], *((1,) * (grad_output.ndim - 1))) + indices = indices.expand_as(grad_output) + grad_input.scatter_add_(0, indices, grad_output) + return grad_input.reshape(ctx.first_axis_dim, *other_shape), None + + +index_first_axis_residual = IndexFirstAxisResidual.apply + + +def unpad_input(hidden_states, attention_mask): + """ + Arguments: + hidden_states: (batch, seqlen, ...) + attention_mask: (batch, seqlen), bool / int, 1 means valid and 0 means not valid. + Return: + hidden_states: (total_nnz, ...), where total_nnz = number of tokens in selected in attention_mask. + cu_seqlens: (batch + 1), the cumulative sequence lengths, used to index into hidden_states. + max_seqlen_in_batch: int + """ + seqlens_in_batch = attention_mask.sum(dim=-1, dtype=torch.int32) + indices = torch.nonzero(attention_mask.flatten(), as_tuple=False).flatten() + max_seqlen_in_batch = seqlens_in_batch.max().item() + cu_seqlens = F.pad(torch.cumsum(seqlens_in_batch, dim=0, dtype=torch.torch.int32), (1, 0)) + # TD [2022-03-04] We don't want to index with a bool mask, because Pytorch will expand the + # bool mask, then call nonzero to get the indices, then index with those. The indices is @dim + # times larger than it needs to be, wasting memory. It's faster and more memory-efficient to + # index with integer indices. Moreover, torch's index is a bit slower than it needs to be, + # so we write custom forward and backward to make it a bit faster. + return ( + index_first_axis(rearrange(hidden_states, "b s ... -> (b s) ..."), indices), + indices, + cu_seqlens, + max_seqlen_in_batch, + ) + + +def pad_input(hidden_states, indices, batch, seqlen): + """ + Arguments: + hidden_states: (total_nnz, ...), where total_nnz = number of tokens in selected in attention_mask. + indices: (total_nnz) + Return: + hidden_states: (batch, seqlen, ...) + """ + # output = torch.zeros((batch * seqlen), dim, device=hidden_states.device, dtype=hidden_states.dtype) + # output[indices] = hidden_states + output = index_put_first_axis(hidden_states, indices, batch * seqlen) + return rearrange(output, "(b s) ... -> b s ...", b=batch) diff --git a/onnxruntime/test/python/transformers/gpt2_model_generator.py b/onnxruntime/test/python/transformers/gpt2_model_generator.py index 6d4d6ea920e42..4a1b48d4d1b48 100644 --- a/onnxruntime/test/python/transformers/gpt2_model_generator.py +++ b/onnxruntime/test/python/transformers/gpt2_model_generator.py @@ -555,6 +555,8 @@ def create_gpt2_embedlayer( num_heads=4, epsilon=0.1, one_attention_node=False, + has_skip_layer_norm=True, + output_embedding_sum=False, ): # Construct input and output nodes inputs = [ @@ -564,21 +566,47 @@ def create_gpt2_embedlayer( helper.make_tensor_value_info("output_0", TensorProto.FLOAT, ["batch_size", "sequence_length", hidden_size]) ] + if output_embedding_sum: + outputs.append( + helper.make_tensor_value_info( + "embedding_sum", TensorProto.FLOAT, ["batch_size", "sequence_length", hidden_size] + ) + ) + # Construct graph nodes embed_layernorm_nodes = [ helper.make_node("Gather", ["word_embeddings_weight", "ids"], ["gather_0_out"], "gather_word_embeddings"), helper.make_node("Gather", ["pos_embeddings_weight", "ids"], ["gather_1_out"], "gather_position_embeddings"), helper.make_node("Add", ["gather_0_out", "gather_1_out"], ["add_0_out"], "add_before_layernorm"), helper.make_node("Gather", ["token_embeddings_weight", "ids"], ["gather_2_out"], "gather_token_embeddings"), - helper.make_node( - "SkipLayerNormalization", - ["add_0_out", "gather_2_out", "layernorm_weight", "layernorm_bias"], - ["skip_layernorm_out"], - "skip_layernorm", - domain="com.microsoft", - epsilon=epsilon, - ), ] + + if has_skip_layer_norm: + embed_layernorm_nodes.append( + helper.make_node( + "SkipLayerNormalization", + ["add_0_out", "gather_2_out", "layernorm_weight", "layernorm_bias"], + ["skip_layernorm_out"] if not output_embedding_sum else ["skip_layernorm_out", "", "", "embedding_sum"], + "skip_layernorm", + domain="com.microsoft", + epsilon=epsilon, + ) + ) + else: + embed_layernorm_nodes.append( + helper.make_node("Add", ["add_0_out", "gather_2_out"], ["embedding_sum"], "embedding_sum") + ) + + embed_layernorm_nodes.append( + helper.make_node( + "LayerNormalization", + ["embedding_sum", "layernorm_weight", "layernorm_bias"], + ["skip_layernorm_out"], + "layernorm", + epsilon=epsilon, + ) + ) + attention_nodes = ( [ helper.make_node("MatMul", ["skip_layernorm_out", "q_weight"], ["q_out"], "q_attn"), @@ -708,6 +736,7 @@ def create_gpt2_fused_embedlayer( num_heads=4, epsilon=0.1, one_attention_node=False, + output_embedding_sum=False, ): # Construct input and output nodes inputs = [ @@ -716,6 +745,12 @@ def create_gpt2_fused_embedlayer( outputs = [ helper.make_tensor_value_info("output_0", TensorProto.FLOAT, ["batch_size", "sequence_length", hidden_size]) ] + if output_embedding_sum: + outputs.append( + helper.make_tensor_value_info( + "embedding_sum", TensorProto.FLOAT, ["batch_size", "sequence_length", hidden_size] + ) + ) # Construct graph nodes embed_layernorm_nodes = [ @@ -732,7 +767,9 @@ def create_gpt2_fused_embedlayer( "", "ids", ], - ["EmbedLayerNormalization_0_output", "EmbedLayerNormalization_0_dummy_mask_index"], + ["EmbedLayerNormalization_0_output", "EmbedLayerNormalization_0_dummy_mask_index", "embedding_sum"] + if output_embedding_sum + else ["EmbedLayerNormalization_0_output", "EmbedLayerNormalization_0_dummy_mask_index"], "EmbedLayerNormalization_0", domain="com.microsoft", epsilon=epsilon, @@ -876,3 +913,9 @@ def create_gpt2_fused_embedlayer( model = create_gpt2_fused_embedlayer(one_attention_node=True) onnx.save(model, "./test_data/models/gpt2_embedlayer_one_attn_exp.onnx") + + model = create_gpt2_embedlayer(one_attention_node=True, output_embedding_sum=True) + onnx.save(model, "gpt2_embedlayer_one_attn_output_sum.onnx") + + model = create_gpt2_fused_embedlayer(one_attention_node=True, output_embedding_sum=True) + onnx.save(model, "./test_data/models/gpt2_embedlayer_one_attn_output_sum_exp.onnx") diff --git a/onnxruntime/test/python/transformers/model_loader.py b/onnxruntime/test/python/transformers/model_loader.py index fc66fdd92fe8d..2d871123ec8bb 100644 --- a/onnxruntime/test/python/transformers/model_loader.py +++ b/onnxruntime/test/python/transformers/model_loader.py @@ -5,7 +5,6 @@ # -------------------------------------------------------------------------- import os -import unittest # noqa: F401 from onnx import ModelProto, TensorProto, external_data_helper, load_model, numpy_helper from parity_utilities import find_transformers_source diff --git a/onnxruntime/test/python/transformers/parity_utilities.py b/onnxruntime/test/python/transformers/parity_utilities.py index 472b768e4aa94..d7f79304d2d2b 100644 --- a/onnxruntime/test/python/transformers/parity_utilities.py +++ b/onnxruntime/test/python/transformers/parity_utilities.py @@ -6,6 +6,7 @@ import argparse import os import sys +from pathlib import Path import numpy import torch @@ -51,6 +52,7 @@ def find_transformers_source(sub_dir_paths=[]): # noqa: B006 "transformers", *sub_dir_paths, ) + source_dir = os.path.normpath(source_dir) if os.path.exists(source_dir): if source_dir not in sys.path: sys.path.append(source_dir) @@ -66,13 +68,10 @@ def create_inputs( device=torch.device("cuda"), # noqa: B008 ): float_type = torch.float16 if float16 else torch.float32 - input = torch.normal(mean=0.0, std=10.0, size=(batch_size, sequence_length, hidden_size)).to(float_type).to(device) - return input + return torch.normal(mean=0.0, std=10.0, size=(batch_size, sequence_length, hidden_size)).to(float_type).to(device) def export_onnx(model, onnx_model_path, float16, hidden_size, device): - from pathlib import Path - Path(onnx_model_path).parent.mkdir(parents=True, exist_ok=True) input_hidden_states = create_inputs(hidden_size=hidden_size, float16=float16, device=device) diff --git a/onnxruntime/test/python/transformers/test_attention_fusion.py b/onnxruntime/test/python/transformers/test_attention_fusion.py index 2edc2ec06d631..76d1dcf013321 100644 --- a/onnxruntime/test/python/transformers/test_attention_fusion.py +++ b/onnxruntime/test/python/transformers/test_attention_fusion.py @@ -31,7 +31,18 @@ def verify_fusion(self, optimized_model, expected_model_filename): expected_model = OnnxModel(onnx.load(expected_model_path)) expected_model.topological_sort(is_deterministic=True) - self.assertEqual(str(optimized_model.model.graph), str(expected_model.model.graph)) + 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 test_multi_head_attention_fusion(self): model = create_bert_attention() diff --git a/onnxruntime/test/python/transformers/test_data/models/attention_mha.onnx b/onnxruntime/test/python/transformers/test_data/models/attention_mha.onnx index 76d808538e0e4..216f5444d88ce 100644 Binary files a/onnxruntime/test/python/transformers/test_data/models/attention_mha.onnx and b/onnxruntime/test/python/transformers/test_data/models/attention_mha.onnx differ diff --git a/onnxruntime/test/python/transformers/test_data/models/attention_opt.onnx b/onnxruntime/test/python/transformers/test_data/models/attention_opt.onnx index ececb8701a283..cc712c61afb77 100644 Binary files a/onnxruntime/test/python/transformers/test_data/models/attention_opt.onnx and b/onnxruntime/test/python/transformers/test_data/models/attention_opt.onnx differ diff --git a/onnxruntime/test/python/transformers/test_data/models/attention_with_varied_qkv_opt.onnx b/onnxruntime/test/python/transformers/test_data/models/attention_with_varied_qkv_opt.onnx index da048bbe5cd34..25dc71ff51215 100644 Binary files a/onnxruntime/test/python/transformers/test_data/models/attention_with_varied_qkv_opt.onnx and b/onnxruntime/test/python/transformers/test_data/models/attention_with_varied_qkv_opt.onnx differ diff --git a/onnxruntime/test/python/transformers/test_data/models/bert_3d_attention_opt.onnx b/onnxruntime/test/python/transformers/test_data/models/bert_3d_attention_opt.onnx index fe5384bd4e234..53a2809038aac 100644 Binary files a/onnxruntime/test/python/transformers/test_data/models/bert_3d_attention_opt.onnx and b/onnxruntime/test/python/transformers/test_data/models/bert_3d_attention_opt.onnx differ diff --git a/onnxruntime/test/python/transformers/test_data/models/gpt2_attention_add_opt_no_skiplayernorm.onnx b/onnxruntime/test/python/transformers/test_data/models/gpt2_attention_add_opt_no_skiplayernorm.onnx index 177c29f607ddb..b4ed7169df447 100644 Binary files a/onnxruntime/test/python/transformers/test_data/models/gpt2_attention_add_opt_no_skiplayernorm.onnx and b/onnxruntime/test/python/transformers/test_data/models/gpt2_attention_add_opt_no_skiplayernorm.onnx differ diff --git a/onnxruntime/test/python/transformers/test_data/models/gpt2_attention_add_opt_skiplayernorm.onnx b/onnxruntime/test/python/transformers/test_data/models/gpt2_attention_add_opt_skiplayernorm.onnx index 036d6c16010a3..0ef3b083191c1 100644 Binary files a/onnxruntime/test/python/transformers/test_data/models/gpt2_attention_add_opt_skiplayernorm.onnx and b/onnxruntime/test/python/transformers/test_data/models/gpt2_attention_add_opt_skiplayernorm.onnx differ diff --git a/onnxruntime/test/python/transformers/test_data/models/gpt2_attention_opt_no_skiplayernorm.onnx b/onnxruntime/test/python/transformers/test_data/models/gpt2_attention_opt_no_skiplayernorm.onnx index 7f1174d966011..62b51b9dd2dfa 100644 Binary files a/onnxruntime/test/python/transformers/test_data/models/gpt2_attention_opt_no_skiplayernorm.onnx and b/onnxruntime/test/python/transformers/test_data/models/gpt2_attention_opt_no_skiplayernorm.onnx differ diff --git a/onnxruntime/test/python/transformers/test_data/models/gpt2_attention_opt_skiplayernorm.onnx b/onnxruntime/test/python/transformers/test_data/models/gpt2_attention_opt_skiplayernorm.onnx index ee11024900e39..0ef3b083191c1 100644 Binary files a/onnxruntime/test/python/transformers/test_data/models/gpt2_attention_opt_skiplayernorm.onnx and b/onnxruntime/test/python/transformers/test_data/models/gpt2_attention_opt_skiplayernorm.onnx differ diff --git a/onnxruntime/test/python/transformers/test_data/models/gpt2_embedlayer_one_attn_output_sum_exp.onnx b/onnxruntime/test/python/transformers/test_data/models/gpt2_embedlayer_one_attn_output_sum_exp.onnx new file mode 100644 index 0000000000000..853f3f5cf7f2c Binary files /dev/null and b/onnxruntime/test/python/transformers/test_data/models/gpt2_embedlayer_one_attn_output_sum_exp.onnx differ diff --git a/onnxruntime/test/python/transformers/test_data/models/gpt2_megatron_opt_no_skiplayernorm.onnx b/onnxruntime/test/python/transformers/test_data/models/gpt2_megatron_opt_no_skiplayernorm.onnx index debd5244abce5..8f545aa8b3bb9 100644 Binary files a/onnxruntime/test/python/transformers/test_data/models/gpt2_megatron_opt_no_skiplayernorm.onnx and b/onnxruntime/test/python/transformers/test_data/models/gpt2_megatron_opt_no_skiplayernorm.onnx differ diff --git a/onnxruntime/test/python/transformers/test_data/models/gpt2_megatron_opt_skiplayernorm.onnx b/onnxruntime/test/python/transformers/test_data/models/gpt2_megatron_opt_skiplayernorm.onnx index 856d76947a4da..8d0f1697b5386 100644 Binary files a/onnxruntime/test/python/transformers/test_data/models/gpt2_megatron_opt_skiplayernorm.onnx and b/onnxruntime/test/python/transformers/test_data/models/gpt2_megatron_opt_skiplayernorm.onnx differ diff --git a/onnxruntime/test/python/transformers/test_data/models/pruned_attention_opt.onnx b/onnxruntime/test/python/transformers/test_data/models/pruned_attention_opt.onnx index 51bf9f08ff0f5..337ede0e4ec39 100644 Binary files a/onnxruntime/test/python/transformers/test_data/models/pruned_attention_opt.onnx and b/onnxruntime/test/python/transformers/test_data/models/pruned_attention_opt.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 2fc6a8959d9da..25265839c82a9 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_mha_fused.onnx b/onnxruntime/test/python/transformers/test_data/models/whisper/decoder_mha_fused.onnx index 0c5035f7dcc6b..5f21da7e591d9 100644 Binary files a/onnxruntime/test/python/transformers/test_data/models/whisper/decoder_mha_fused.onnx and b/onnxruntime/test/python/transformers/test_data/models/whisper/decoder_mha_fused.onnx differ diff --git a/onnxruntime/test/python/transformers/test_data/models/whisper/decoder_mha_split_bias_fused.onnx b/onnxruntime/test/python/transformers/test_data/models/whisper/decoder_mha_split_bias_fused.onnx new file mode 100644 index 0000000000000..1da242e19e711 Binary files /dev/null and b/onnxruntime/test/python/transformers/test_data/models/whisper/decoder_mha_split_bias_fused.onnx differ diff --git a/onnxruntime/test/python/transformers/test_data/models/whisper/decoder_with_past_cross_mha_fused.onnx b/onnxruntime/test/python/transformers/test_data/models/whisper/decoder_with_past_cross_mha_fused.onnx index 7b3368d8245f8..e7a201658bb4d 100644 Binary files a/onnxruntime/test/python/transformers/test_data/models/whisper/decoder_with_past_cross_mha_fused.onnx and b/onnxruntime/test/python/transformers/test_data/models/whisper/decoder_with_past_cross_mha_fused.onnx differ diff --git a/onnxruntime/test/python/transformers/test_data/models/whisper/decoder_with_past_cross_mha_split_bias_fused.onnx b/onnxruntime/test/python/transformers/test_data/models/whisper/decoder_with_past_cross_mha_split_bias_fused.onnx new file mode 100644 index 0000000000000..bc72c9b350087 Binary files /dev/null and b/onnxruntime/test/python/transformers/test_data/models/whisper/decoder_with_past_cross_mha_split_bias_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 1119e4c51a699..969f20b2860c3 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 new file mode 100644 index 0000000000000..ca7f33a3f1d8d Binary files /dev/null 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_data/models/whisper/encoder_attention_with_sln_fused.onnx b/onnxruntime/test/python/transformers/test_data/models/whisper/encoder_attention_with_sln_fused.onnx index 190b70741fc4c..15a178863b9e5 100644 Binary files a/onnxruntime/test/python/transformers/test_data/models/whisper/encoder_attention_with_sln_fused.onnx and b/onnxruntime/test/python/transformers/test_data/models/whisper/encoder_attention_with_sln_fused.onnx differ diff --git a/onnxruntime/test/python/transformers/test_embedlayer_fusion.py b/onnxruntime/test/python/transformers/test_embedlayer_fusion.py index 732833e5da27d..ccd367fdbbe01 100644 --- a/onnxruntime/test/python/transformers/test_embedlayer_fusion.py +++ b/onnxruntime/test/python/transformers/test_embedlayer_fusion.py @@ -74,6 +74,38 @@ def test_embedlayer_fusion_one_attn_node(self): os.remove(original_model_path) os.remove(optimized_model_path) + def test_embedlayer_fusion_with_embedding_sum_output(self): + model = create_gpt2_embedlayer(one_attention_node=True, output_embedding_sum=True) + path = "." + original_model_path = os.path.join(path, "gpt2_embedlayer_one_attn_output_sum.onnx") + optimized_model_path = os.path.join(path, "gpt2_embedlayer_one_attn_output_sum_opt.onnx") + expected_model_filename = "gpt2_embedlayer_one_attn_output_sum_exp.onnx" + + onnx.save(model, original_model_path) + optimized_model = optimize_model(original_model_path, model_type="gpt2") + optimized_model.save_model_to_file(optimized_model_path, use_external_data_format=True) + + self.verify_fusion(optimized_model, expected_model_filename) + self.verify_parity(optimized_model_path, expected_model_filename) + os.remove(original_model_path) + os.remove(optimized_model_path) + + def test_embedlayer_fusion_with_embedding_sum_output_no_sln(self): + model = create_gpt2_embedlayer(one_attention_node=True, has_skip_layer_norm=False, output_embedding_sum=True) + path = "." + original_model_path = os.path.join(path, "gpt2_embedlayer_one_attn_output_sum_no_sln.onnx") + optimized_model_path = os.path.join(path, "gpt2_embedlayer_one_attn_output_sum_no_sln_opt.onnx") + expected_model_filename = "gpt2_embedlayer_one_attn_output_sum_exp.onnx" + + onnx.save(model, original_model_path) + optimized_model = optimize_model(original_model_path, model_type="gpt2") + optimized_model.save_model_to_file(optimized_model_path, use_external_data_format=True) + + self.verify_fusion(optimized_model, expected_model_filename) + self.verify_parity(optimized_model_path, expected_model_filename) + os.remove(original_model_path) + os.remove(optimized_model_path) + if __name__ == "__main__": unittest.main() diff --git a/onnxruntime/test/python/transformers/test_flash_attn.py b/onnxruntime/test/python/transformers/test_flash_attn.py new file mode 100644 index 0000000000000..f90a9475b4588 --- /dev/null +++ b/onnxruntime/test/python/transformers/test_flash_attn.py @@ -0,0 +1,528 @@ +# -------------------------------------------------------------------------- +# Copyright 2020 The HuggingFace Inc. team +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# ------------------------------------------------------------------------- +import math + +import numpy +import torch +from bert_padding import pad_input, unpad_input +from einops import rearrange, repeat +from onnx import TensorProto, helper + +from onnxruntime import InferenceSession, SessionOptions + +torch.manual_seed(0) + + +class Config: + batch_size = 0 + sequence_length = 0 + kv_sequence_length = 0 + num_heads = 0 + head_size = 0 + + def __init__(self, b, s, s2, n, h): + self.batch_size = b + self.sequence_length = s + self.kv_sequence_length = s2 + self.num_heads = n + self.head_size = h + + +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 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=["CUDAExecutionProvider"]) + ort_output = ort_session.run(None, ort_inputs) + output = torch.tensor(ort_output) + return output + + +def flash_attn_func(q, k, v, config, causal=False): + 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=["CUDAExecutionProvider"]) + ort_output = ort_session.run(None, ort_inputs) + output = torch.tensor(ort_output) + return output + + +def attention_ref( + q, + k, + v, + query_padding_mask=None, + key_padding_mask=None, + dropout_p=0.0, + dropout_mask=None, + causal=False, + upcast=True, + reorder_ops=False, +): + """ + Arguments: + q: (batch_size, seqlen_q, nheads, head_dim) + k: (batch_size, seqlen_k, nheads_k, head_dim) + v: (batch_size, seqlen_k, nheads_k, head_dim) + query_padding_mask: (batch_size, seqlen_q) + key_padding_mask: (batch_size, seqlen_k) + dropout_p: float + dropout_mask: (batch_size, nheads, seqlen_q, seqlen_k) + upcast: whether to cast all inputs to fp32, do all computation in fp32, then cast + output back to fp16/bf16. + reorder_ops: whether to change the order of operations (scaling k instead of scaling k, etc.) + without changing the math. This is to estimate the numerical error from operation + reordering. + Output: + output: (batch_size, seqlen_q, nheads, head_dim) + attention: (batch_size, nheads, seqlen_q, seqlen_k), softmax after dropout + """ + dtype_og = q.dtype + if upcast: + q, k, v = q.float(), k.float(), v.float() + seqlen_q, seqlen_k = q.shape[1], k.shape[1] + k = repeat(k, "b s h d -> b s (h g) d", g=q.shape[2] // k.shape[2]) + v = repeat(v, "b s h d -> b s (h g) d", g=q.shape[2] // v.shape[2]) + d = q.shape[-1] + if not reorder_ops: + scores = torch.einsum("bthd,bshd->bhts", q / math.sqrt(d), k) + else: + scores = torch.einsum("bthd,bshd->bhts", q, k / math.sqrt(d)) + if key_padding_mask is not None: + scores.masked_fill_(rearrange(~key_padding_mask, "b s -> b 1 1 s"), float("-inf")) + if causal: + causal_mask = torch.triu(torch.ones(seqlen_q, seqlen_k, dtype=torch.bool, device=q.device), 1) + scores.masked_fill_(causal_mask, float("-inf")) + attention = torch.softmax(scores, dim=-1) + dropout_scaling = 1.0 / (1 - dropout_p) + if dropout_mask is not None: + attention_drop = attention.masked_fill(~dropout_mask, 0.0) + else: + attention_drop = attention + output = torch.einsum("bhts,bshd->bthd", attention_drop, v * dropout_scaling) + if query_padding_mask is not None: + output.masked_fill_(rearrange(~query_padding_mask, "b s -> b s 1 1"), 0.0) + attention = attention.masked_fill(rearrange(~query_padding_mask, "b s -> b 1 s 1"), 0.0) + 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 +): + 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, + ) + + +def parity_check( + 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.num_heads, + config.head_size, + device="cuda", + dtype=torch.float16, + requires_grad=False, + ) + v = torch.randn( + config.batch_size, + config.kv_sequence_length, + config.num_heads, + config.head_size, + device="cuda", + dtype=torch.float16, + requires_grad=False, + ) + out = flash_attn_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) + out_ref = out_ref.detach().cpu().numpy() + # Compare results + print( + " B:", + config.batch_size, + " S:", + config.sequence_length, + " N:", + config.num_heads, + " h:", + config.head_size, + " Mean Error:", + numpy.mean(numpy.abs(out - out_ref)), + numpy.allclose( + out, + out_ref, + rtol=rtol, + atol=atol, + equal_nan=True, + ), + ) + + +if __name__ == "__main__": + print("-------- TEST PACKED MHA ---------") + for b in [5]: + for s in [97, 128, 200, 256, 257, 384, 512, 768, 1024, 1025, 2048]: + for n in [6]: + for h in [32, 40, 59, 64, 80, 96, 111, 128, 160, 192, 224, 256]: + config = Config(b, s, s, n, h) + parity_check(config, True) + print("-------- TEST MHA ---------") + for b in [5]: + for s, s2 in [ + (113, 203), + (128, 217), + (113, 211), + (108, 256), + (256, 512), + (512, 256), + (1024, 1024), + (1023, 1024), + (1024, 1023), + (2048, 2048), + ]: + for n in [6]: + for h in [32, 40, 59, 64, 80, 96, 111, 128, 160, 192, 224, 256]: + config = Config(b, s, s2, n, h) + parity_check(config, False) diff --git a/onnxruntime/test/python/transformers/test_gemmfastgelu_fusion.py b/onnxruntime/test/python/transformers/test_gemmfastgelu_fusion.py index 3a948705770ee..431ae21cd5eaf 100644 --- a/onnxruntime/test/python/transformers/test_gemmfastgelu_fusion.py +++ b/onnxruntime/test/python/transformers/test_gemmfastgelu_fusion.py @@ -43,7 +43,7 @@ def float_tensor(name: str, shape: List[int], random=False): return helper.make_tensor(name, TensorProto.FLOAT, shape, weights) -def create_MatMul_FastGelu_withoutBias(batch_size, m, n, k): # noqa: N802 +def create_mat_mul_fast_gelu_without_bias(batch_size, m, n, k): # MatMul + FastGelu nodes = [ helper.make_node("MatMul", ["input", "matmul_weight"], ["fastgelu_input"], "matmul"), @@ -77,7 +77,7 @@ def create_MatMul_FastGelu_withoutBias(batch_size, m, n, k): # noqa: N802 return helper.make_model(graph) -def create_MatMul_FastGelu_withBias(batch_size, m, n, k): # noqa: N802 +def create_mat_mul_fast_gelu_with_bias(batch_size, m, n, k): # MatMul + FastGelu nodes = [ helper.make_node("MatMul", ["input", "matmul_weight"], ["fastgelu_input"], "matmul"), @@ -122,7 +122,7 @@ def verify_fusion(self, optimized_model, expected_model_filename): self.assertEqual(str(optimized_model.model.graph), str(expected_model.model.graph)) def test_gemmfastgelu_fusion_withoutbias(self): - model = create_MatMul_FastGelu_withoutBias(32, 128, 64, 1024) + model = create_mat_mul_fast_gelu_without_bias(32, 128, 64, 1024) dir = "." model_path = os.path.join(dir, "gemmfastgelu_nobias.onnx") onnx.save(model, model_path) @@ -135,7 +135,7 @@ def test_gemmfastgelu_fusion_withoutbias(self): self.verify_fusion(optimized_model, "gemmfastgelu_nobias_opt.onnx") def test_gemmfastgelu_fusion_withbias(self): - model = create_MatMul_FastGelu_withBias(32, 128, 64, 1024) + model = create_mat_mul_fast_gelu_with_bias(32, 128, 64, 1024) dir = "." model_path = os.path.join(dir, "gemmfastgelu_withbias.onnx") onnx.save(model, model_path) diff --git a/onnxruntime/test/python/transformers/test_generation.py b/onnxruntime/test/python/transformers/test_generation.py index 24536d7b43e6a..55c51435823c6 100644 --- a/onnxruntime/test/python/transformers/test_generation.py +++ b/onnxruntime/test/python/transformers/test_generation.py @@ -6,6 +6,7 @@ # -------------------------------------------------------------------------- import os +import shutil import unittest import onnx @@ -19,10 +20,12 @@ from benchmark_helper import Precision from convert_generation import main as run from models.t5.convert_to_onnx import export_onnx_models as export_t5_onnx_models + from models.whisper.convert_to_onnx import main as run_whisper else: from onnxruntime.transformers.benchmark_helper import Precision from onnxruntime.transformers.convert_generation import main as run from onnxruntime.transformers.models.t5.convert_to_onnx import export_onnx_models as export_t5_onnx_models + from onnxruntime.transformers.models.whisper.convert_to_onnx import main as run_whisper class TestBeamSearchGpt(unittest.TestCase): @@ -281,5 +284,100 @@ def test_external_data(self): ) +class TestBeamSearchWhisper(unittest.TestCase): + """Test BeamSearch for Whisper""" + + def setUp(self): + self.model_name = "openai/whisper-tiny" + 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.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.base_arguments = [ + "-m", + self.model_name, + "--output", + self.onnx_folder, + "--use_external_data_format", + ] + self.fp32_cpu_arguments = [ + "--precision", + "fp32", + "--optimize_onnx", + ] + self.fp16_cuda_arguments = [ + "--precision", + "fp16", + "--provider", + "cuda", + "--optimize_onnx", + "--use_gpu", + ] + self.int8_cpu_arguments = [ + "--precision", + "int8", + "--quantize_embedding_layer", + ] + + def tearDown(self): + pytorch_dir = os.path.join(".", self.pytorch_folder) + if os.path.exists(pytorch_dir): + shutil.rmtree(pytorch_dir) + onnx_dir = os.path.join(".", self.onnx_folder) + if os.path.exists(onnx_dir): + shutil.rmtree(onnx_dir) + + def remove_onnx_files(self): + if os.path.exists(self.beam_search_onnx_path): + os.remove(self.beam_search_onnx_path) + os.remove(self.beam_search_onnx_path + ".data") + + if os.path.exists(self.decoder_onnx_path): + os.remove(self.decoder_onnx_path) + os.remove(self.decoder_onnx_path + ".data") + + if os.path.exists(self.encoder_onnx_path): + os.remove(self.encoder_onnx_path) + os.remove(self.encoder_onnx_path + ".data") + + def run_export(self, arguments): + max_diff = run_whisper(arguments) + self.assertTrue(os.path.exists(self.beam_search_onnx_path), "Whisper model was not exported") + self.remove_onnx_files() + self.assertTrue(max_diff == 0, f"ORT and PyTorch have a parity mismatch of {max_diff}") + + def run_configs(self, optional_arguments): + # FP32 CPU + arguments = self.base_arguments + self.fp32_cpu_arguments + optional_arguments + self.run_export(arguments) + + if self.enable_cuda: + # FP16 CUDA + arguments = self.base_arguments + self.fp16_cuda_arguments + optional_arguments + self.run_export(arguments) + + # INT8 CPU + arguments = self.base_arguments + self.int8_cpu_arguments + optional_arguments + self.run_export(arguments) + + @pytest.mark.slow + def test_required_args(self): + optional_args = [] + self.run_configs(optional_args) + + @pytest.mark.slow + def test_forced_decoder_ids(self): + decoder_input_ids = ["--use_forced_decoder_ids"] + self.run_configs(decoder_input_ids) + + @pytest.mark.slow + def test_logits_processor(self): + logits_processor = ["--use_logits_processor"] + self.run_configs(logits_processor) + + if __name__ == "__main__": unittest.main() diff --git a/onnxruntime/test/python/transformers/test_optimizer.py b/onnxruntime/test/python/transformers/test_optimizer.py index d1fb88c0d0322..eedadfd8d4448 100644 --- a/onnxruntime/test/python/transformers/test_optimizer.py +++ b/onnxruntime/test/python/transformers/test_optimizer.py @@ -311,7 +311,7 @@ def test_huggingface_vit_fusion(self): @unittest.skipUnless(is_tf_available(), "skip TestBertOptimizationTF since tensorflow is not available") class TestTensorflowModelOptimization(unittest.TestCase): - def Setup(self): # noqa: N802 + def setUp(self): try: import tf2onnx # noqa: F401 except ImportError: diff --git a/onnxruntime/test/python/transformers/test_optimizer_stable_diffusion.py b/onnxruntime/test/python/transformers/test_optimizer_stable_diffusion.py new file mode 100644 index 0000000000000..dca250f39fae2 --- /dev/null +++ b/onnxruntime/test/python/transformers/test_optimizer_stable_diffusion.py @@ -0,0 +1,271 @@ +# ------------------------------------------------------------------------- +# 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 shutil +import unittest + +import numpy as np +import pytest +from parity_utilities import find_transformers_source + +if find_transformers_source(): + from compare_bert_results import run_test + from fusion_options import FusionOptions + from optimizer import optimize_model +else: + from onnxruntime.transformers.compare_bert_results import run_test + from onnxruntime.transformers.fusion_options import FusionOptions + from onnxruntime.transformers.optimizer import optimize_model + +if find_transformers_source(["models", "stable_diffusion"]): + from optimize_pipeline import main as optimize_stable_diffusion +else: + from onnxruntime.transformers.models.stable_diffusion.optimize_pipeline import main as optimize_stable_diffusion + + +TINY_MODELS = { + "stable-diffusion": "hf-internal-testing/tiny-stable-diffusion-torch", + "stable-diffusion-xl": "echarlaix/tiny-random-stable-diffusion-xl", +} + + +class TestStableDiffusionOptimization(unittest.TestCase): + def verify_node_count(self, onnx_model, expected_node_count, test_name): + for op_type, count in expected_node_count.items(): + if len(onnx_model.get_nodes_by_op_type(op_type)) != count: + print(f"Counters is not expected in test: {test_name}") + for op, counter in expected_node_count.items(): + print(f"{op}: {len(onnx_model.get_nodes_by_op_type(op))} expected={counter}") + + self.assertEqual(len(onnx_model.get_nodes_by_op_type(op_type)), count) + + def verify_clip_optimizer(self, clip_onnx_path, optimized_clip_onnx_path, expected_counters, float16=False): + fusion_options = FusionOptions("clip") + m = optimize_model( + clip_onnx_path, + model_type="clip", + num_heads=0, + hidden_size=0, + opt_level=0, + optimization_options=fusion_options, + use_gpu=True, + ) + self.verify_node_count(m, expected_counters, "test_clip") + + if float16: + m.convert_float_to_float16( + keep_io_types=True, + ) + print(m.get_operator_statistics()) + m.save_model_to_file(optimized_clip_onnx_path) + + threshold = 1e-2 if float16 else 3e-3 + max_abs_diff, passed = run_test( + clip_onnx_path, + optimized_clip_onnx_path, + output_dir=None, + batch_size=1, + sequence_length=77, + use_gpu=True, + test_cases=10, + seed=1, + verbose=False, + rtol=1e-1, + atol=threshold, + input_ids_name="input_ids", + segment_ids_name=None, + input_mask_name=None, + mask_type=0, + ) + + self.assertLess(max_abs_diff, threshold) + self.assertTrue(passed) + + @pytest.mark.slow + def test_clip_sd(self): + save_directory = "tiny-random-stable-diffusion" + if os.path.exists(save_directory): + shutil.rmtree(save_directory, ignore_errors=True) + + model_type = "stable-diffusion" + model_name = TINY_MODELS[model_type] + + from optimum.onnxruntime import ORTStableDiffusionPipeline + + base = ORTStableDiffusionPipeline.from_pretrained(model_name, export=True) + base.save_pretrained(save_directory) + + clip_onnx_path = os.path.join(save_directory, "text_encoder", "model.onnx") + optimized_clip_onnx_path = os.path.join(save_directory, "text_encoder", "opt.onnx") + self.verify_clip_optimizer( + clip_onnx_path, + optimized_clip_onnx_path, + expected_counters={ + "EmbedLayerNormalization": 0, + "Attention": 5, + "SkipLayerNormalization": 10, + "LayerNormalization": 1, + "Gelu": 0, + "BiasGelu": 0, + }, + float16=True, + ) + + @pytest.mark.slow + def test_clip_sdxl(self): + save_directory = "tiny-random-stable-diffusion-xl" + if os.path.exists(save_directory): + shutil.rmtree(save_directory, ignore_errors=True) + + model_type = "stable-diffusion-xl" + model_name = TINY_MODELS[model_type] + + from optimum.onnxruntime import ORTStableDiffusionXLPipeline + + base = ORTStableDiffusionXLPipeline.from_pretrained(model_name, export=True) + base.save_pretrained(save_directory) + + clip_onnx_path = os.path.join(save_directory, "text_encoder", "model.onnx") + optimized_clip_onnx_path = os.path.join(save_directory, "text_encoder", "opt.onnx") + self.verify_clip_optimizer( + clip_onnx_path, + optimized_clip_onnx_path, + expected_counters={ + "EmbedLayerNormalization": 0, + "Attention": 5, + "SkipLayerNormalization": 10, + "LayerNormalization": 1, + "Gelu": 0, + "BiasGelu": 5, + }, + ) + + clip_onnx_path = os.path.join(save_directory, "text_encoder_2", "model.onnx") + optimized_clip_onnx_path = os.path.join(save_directory, "text_encoder_2", "opt.onnx") + self.verify_clip_optimizer( + clip_onnx_path, + optimized_clip_onnx_path, + expected_counters={ + "EmbedLayerNormalization": 0, + "Attention": 5, + "SkipLayerNormalization": 10, + "LayerNormalization": 1, + "Gelu": 0, + "BiasGelu": 5, + }, + ) + + @pytest.mark.slow + def test_optimize_sdxl_fp32(self): + save_directory = "tiny-random-stable-diffusion-xl" + if os.path.exists(save_directory): + shutil.rmtree(save_directory, ignore_errors=True) + + model_type = "stable-diffusion-xl" + model_name = TINY_MODELS[model_type] + + from optimum.onnxruntime import ORTStableDiffusionXLPipeline + + baseline = ORTStableDiffusionXLPipeline.from_pretrained(model_name, export=True) + if not os.path.exists(save_directory): + baseline.save_pretrained(save_directory) + + batch_size, num_images_per_prompt, height, width = 2, 2, 64, 64 + latents = baseline.prepare_latents( + batch_size * num_images_per_prompt, + baseline.unet.config["in_channels"], + height, + width, + dtype=np.float32, + generator=np.random.RandomState(0), + ) + + optimized_directory = "tiny-random-stable-diffusion-xl-optimized" + argv = [ + "--input", + save_directory, + "--output", + optimized_directory, + "--disable_group_norm", + "--disable_bias_splitgelu", + "--overwrite", + ] + optimize_stable_diffusion(argv) + + treatment = ORTStableDiffusionXLPipeline.from_pretrained(optimized_directory, provider="CUDAExecutionProvider") + inputs = { + "prompt": ["starry night by van gogh"] * batch_size, + "num_inference_steps": 3, + "num_images_per_prompt": num_images_per_prompt, + "height": height, + "width": width, + "guidance_rescale": 0.1, + "output_type": "np", + } + + ort_outputs_1 = baseline(latents=latents, **inputs) + ort_outputs_2 = treatment(latents=latents, **inputs) + self.assertTrue(np.allclose(ort_outputs_1.images[0], ort_outputs_2.images[0], atol=1e-3)) + + @pytest.mark.slow + def test_optimize_sdxl_fp16(self): + """This tests optimized fp16 pipeline, and result is deterministic for a given seed""" + save_directory = "tiny-random-stable-diffusion-xl" + if os.path.exists(save_directory): + shutil.rmtree(save_directory, ignore_errors=True) + + model_type = "stable-diffusion-xl" + model_name = TINY_MODELS[model_type] + + from optimum.onnxruntime import ORTStableDiffusionXLPipeline + + baseline = ORTStableDiffusionXLPipeline.from_pretrained(model_name, export=True) + if not os.path.exists(save_directory): + baseline.save_pretrained(save_directory) + + optimized_directory = "tiny-random-stable-diffusion-xl-optimized-fp16" + argv = [ + "--input", + save_directory, + "--output", + optimized_directory, + "--disable_group_norm", + "--disable_bias_splitgelu", + "--float16", + "--overwrite", + ] + optimize_stable_diffusion(argv) + + fp16_pipeline = ORTStableDiffusionXLPipeline.from_pretrained( + optimized_directory, provider="CUDAExecutionProvider" + ) + batch_size, num_images_per_prompt, height, width = 1, 1, 64, 64 + inputs = { + "prompt": ["starry night by van gogh"] * batch_size, + "num_inference_steps": 3, + "num_images_per_prompt": num_images_per_prompt, + "height": height, + "width": width, + "guidance_rescale": 0.1, + "output_type": "latent", + } + + seed = 123 + np.random.seed(seed) + ort_outputs_1 = fp16_pipeline(**inputs) + + np.random.seed(seed) + ort_outputs_2 = fp16_pipeline(**inputs) + + np.random.seed(seed) + ort_outputs_3 = fp16_pipeline(**inputs) + + self.assertTrue(np.array_equal(ort_outputs_1.images[0], ort_outputs_2.images[0])) + self.assertTrue(np.array_equal(ort_outputs_1.images[0], ort_outputs_3.images[0])) + + +if __name__ == "__main__": + unittest.main() diff --git a/onnxruntime/test/python/transformers/test_parity_decoder_attention.py b/onnxruntime/test/python/transformers/test_parity_decoder_attention.py index 992a805eb2eb3..e870e7f95fcee 100644 --- a/onnxruntime/test/python/transformers/test_parity_decoder_attention.py +++ b/onnxruntime/test/python/transformers/test_parity_decoder_attention.py @@ -10,9 +10,7 @@ # license information. # ------------------------------------------------------------------------- -import math # noqa: F401 -import os # noqa: F401 -from typing import Dict, List, Optional, Tuple # noqa: F401 +from typing import List, Optional, Tuple import numpy import torch @@ -239,7 +237,7 @@ def forward( return attn_output, new_key_cache, new_value_cache - def ORT_forward( # noqa: N802 + def ort_forward( self, query, key: Tensor, @@ -458,7 +456,7 @@ def parity_check( use_past, has_key_padding_mask, ) - attn_output_ort, new_key_cache_ort, new_value_cache_ort = attn.ORT_forward( + attn_output_ort, new_key_cache_ort, new_value_cache_ort = attn.ort_forward( query, key, key_padding_mask, @@ -468,7 +466,7 @@ def parity_check( use_past, has_key_padding_mask, ) - attn_output_ort_1, _, _ = attn.ORT_forward( + attn_output_ort_1, _, _ = attn.ort_forward( query, key, key_padding_mask, diff --git a/onnxruntime/test/python/transformers/test_parity_gelu.py b/onnxruntime/test/python/transformers/test_parity_gelu.py index dfafb9b7e7c5c..5edc0e78d7d5d 100644 --- a/onnxruntime/test/python/transformers/test_parity_gelu.py +++ b/onnxruntime/test/python/transformers/test_parity_gelu.py @@ -28,7 +28,7 @@ import unittest import torch -from parity_utilities import * # noqa: F403 +from parity_utilities import export_onnx, optimize_onnx, parse_arguments, run_parity from torch import nn @@ -36,7 +36,7 @@ class Gelu(nn.Module): def __init__(self, formula=4, fp32_gelu_op=False): super().__init__() self.formula = formula - self.fp32_gelu_op = True + self.fp32_gelu_op = fp32_gelu_op def gelu(self, x): if self.formula == 0: @@ -98,12 +98,12 @@ def run( # Do not re-use onnx file from previous test since weights of model are random. onnx_model_path = "./temp/gelu_{}_{}.onnx".format(formula, "fp16" if float16 else "fp32") - export_onnx(model, onnx_model_path, float16, hidden_size, device) # noqa: F405 + export_onnx(model, onnx_model_path, float16, hidden_size, device) if optimized: optimized_onnx_path = "./temp/gelu_{}_opt_{}.onnx".format(formula, "fp16" if float16 else "fp32") use_gpu = float16 and not fp32_gelu_op - optimize_onnx( # noqa: F405 + optimize_onnx( onnx_model_path, optimized_onnx_path, Gelu.get_fused_op(formula), @@ -115,7 +115,7 @@ def run( else: onnx_path = onnx_model_path - num_failure = run_parity( # noqa: F405 + num_failure = run_parity( model, onnx_path, batch_size, @@ -226,9 +226,7 @@ def test_cpu(self): def test_cuda(self): if not torch.cuda.is_available(): - import pytest - - pytest.skip("test requires GPU and torch+cuda") + self.skipTest("test requires GPU and torch+cuda") else: gpu = torch.device("cuda") for i in self.formula_to_test: @@ -236,7 +234,7 @@ def test_cuda(self): if __name__ == "__main__": - args, remaining_args = parse_arguments(namespace_filter=unittest) # noqa: F405 + args, remaining_args = parse_arguments(namespace_filter=unittest) TestGeluParity.verbose = args.log_verbose TestGeluParity.optimized = args.optimize diff --git a/onnxruntime/test/python/transformers/test_parity_huggingface_gpt_attention.py b/onnxruntime/test/python/transformers/test_parity_huggingface_gpt_attention.py index 1158f38e2887a..85b30bea4f0af 100644 --- a/onnxruntime/test/python/transformers/test_parity_huggingface_gpt_attention.py +++ b/onnxruntime/test/python/transformers/test_parity_huggingface_gpt_attention.py @@ -12,16 +12,22 @@ import os import random import unittest +from pathlib import Path import numpy import onnx import pytest import torch from onnx import helper -from parity_utilities import compare_outputs, create_ort_session, parse_arguments +from parity_utilities import compare_outputs, create_ort_session, find_transformers_source, parse_arguments from torch import nn from transformers.modeling_utils import Conv1D +if find_transformers_source(): + from onnx_model import OnnxModel +else: + from onnxruntime.transformers.onnx_model import OnnxModel + DEBUG_OUTPUTS = ["qk", "norm_qk", "softmax", "attn_weights"] @@ -206,8 +212,6 @@ def get_output_names(debug=False): def export_onnx(model, onnx_model_path, float16, hidden_size, num_attention_heads, debug, device): - from pathlib import Path - Path(onnx_model_path).parent.mkdir(parents=True, exist_ok=True) input_hidden_states, attention_mask, layer_past = create_inputs( @@ -254,8 +258,6 @@ def export_onnx(model, onnx_model_path, float16, hidden_size, num_attention_head def optimize_onnx(input_onnx_path, optimized_onnx_path, num_heads, debug): - from onnxruntime.transformers.onnx_model import OnnxModel - m = onnx.load(input_onnx_path) onnx_model = OnnxModel(m) @@ -337,7 +339,7 @@ def verify_attention( ort_outputs = onnxruntime_inference(ort_session, input_hidden_states, attention_mask, layer_past) - tolerance = 1e-03 if float16 else 1e-05 + tolerance = 1e-02 if float16 else 1e-04 is_all_close, max_diff = compare_outputs(torch_outputs, ort_outputs, atol=tolerance, verbose=True) max_diffs.append(max_diff) if is_all_close: @@ -513,9 +515,7 @@ def test_cpu(self): def test_cuda(self): if not torch.cuda.is_available(): - import pytest - - pytest.skip("test requires GPU and torch+cuda") + self.skipTest("test requires GPU and torch+cuda") else: gpu = torch.device("cuda") self.run_small(self.optimized, gpu, verbose=self.verbose) @@ -523,9 +523,7 @@ def test_cuda(self): @pytest.mark.slow def test_large_cuda(self): if not torch.cuda.is_available(): - import pytest - - pytest.skip("test requires GPU and torch+cuda") + self.skipTest("test requires GPU and torch+cuda") else: gpu = torch.device("cuda") self.run_large(self.optimized, gpu, verbose=self.verbose) diff --git a/onnxruntime/test/python/transformers/test_parity_layernorm.py b/onnxruntime/test/python/transformers/test_parity_layernorm.py index 648bfde7a8342..a75c28484e94d 100644 --- a/onnxruntime/test/python/transformers/test_parity_layernorm.py +++ b/onnxruntime/test/python/transformers/test_parity_layernorm.py @@ -9,10 +9,10 @@ import onnx import torch -from parity_utilities import * # noqa: F403 +from parity_utilities import export_onnx, find_transformers_source, optimize_onnx, parse_arguments, run_parity from torch import nn -if find_transformers_source(): # noqa: F405 +if find_transformers_source(): from onnx_model import OnnxModel else: from onnxruntime.transformers.onnx_model import OnnxModel @@ -150,14 +150,12 @@ def run( # Do not re-use onnx file from previous test since weights of model are random. onnx_model_path = "./temp/layer_norm_{}_formula{}.onnx".format("fp16" if float16 else "fp32", formula) - export_onnx(model, onnx_model_path, float16, hidden_size, device) # noqa: F405 + export_onnx(model, onnx_model_path, float16, hidden_size, device) if optimized: optimized_onnx_path = "./temp/layer_norm_{}_formula{}_opt.onnx".format("fp16" if float16 else "fp32", formula) if (not float16) or cast_fp16: - optimize_onnx( # noqa: F405 - onnx_model_path, optimized_onnx_path, expected_op=LayerNorm.get_fused_op(), verbose=verbose - ) + optimize_onnx(onnx_model_path, optimized_onnx_path, expected_op=LayerNorm.get_fused_op(), verbose=verbose) else: if cast_onnx_only: optimize_fp16_onnx_with_cast(onnx_model_path, optimized_onnx_path, epsilon=epsilon) @@ -168,7 +166,7 @@ def run( else: onnx_path = onnx_model_path - num_failure = run_parity( # noqa: F405 + num_failure = run_parity( model, onnx_path, batch_size, @@ -299,16 +297,14 @@ def test_cpu(self): def test_cuda(self): if not torch.cuda.is_available(): - import pytest - - pytest.skip("test requires GPU and torch+cuda") + self.skipTest("test requires GPU and torch+cuda") else: gpu = torch.device("cuda") self.run_one(self.optimized, gpu, hidden_size=self.hidden_size, run_extra_tests=True, verbose=self.verbose) if __name__ == "__main__": - args, remaining_args = parse_arguments(namespace_filter=unittest) # noqa: F405 + args, remaining_args = parse_arguments(namespace_filter=unittest) TestLayerNormParity.verbose = args.log_verbose TestLayerNormParity.optimized = args.optimize diff --git a/onnxruntime/test/python/transformers/test_parity_neox_attention.py b/onnxruntime/test/python/transformers/test_parity_neox_attention.py index 0c119da69c812..8c8e871a854b0 100644 --- a/onnxruntime/test/python/transformers/test_parity_neox_attention.py +++ b/onnxruntime/test/python/transformers/test_parity_neox_attention.py @@ -10,10 +10,15 @@ # license information. # ------------------------------------------------------------------------- +import unittest + import numpy as np import torch +from onnx import TensorProto, helper from torch import nn +np.random.seed(0) +torch.manual_seed(0) torch.set_printoptions(threshold=10000) @@ -24,10 +29,7 @@ def create_neox_attention_graph( qkv_weight, qkv_bias, num_heads, - use_rotary, ): - from onnx import TensorProto, helper - nodes = [ helper.make_node( "Attention", @@ -40,7 +42,7 @@ def create_neox_attention_graph( "NeoXAttention_0", num_heads=num_heads, unidirectional=1, - do_rotary=(use_rotary is True), + do_rotary=1, domain="com.microsoft", ), ] @@ -66,6 +68,67 @@ def create_neox_attention_graph( return model.SerializeToString() +def create_neox_decoder_masked_self_attention_graph( + batch_size, + seq_len, + past_seq_len, + hidden_size, + qkv_weight, + qkv_bias, + num_heads, +): + nodes = [ + helper.make_node( + "DecoderMaskedSelfAttention", + [ + "input", + "weight", + "bias", + "mask_index", + "past", + "", # relative_position_bias + "past_sequence_length", + ], + ["output", "present"], + "NeoXDecoderMaskedSelfAttention_0", + num_heads=num_heads, + past_present_share_buffer=1, + do_rotary=1, + domain="com.microsoft", + ), + ] + + initializers = [ + helper.make_tensor("weight", TensorProto.FLOAT, [hidden_size, 3 * hidden_size], qkv_weight.flatten().tolist()), + helper.make_tensor("bias", TensorProto.FLOAT, [3 * hidden_size], qkv_bias.flatten().tolist()), + ] + + total_seq_len = seq_len + past_seq_len + + graph = helper.make_graph( + nodes, + "NeoXAttention_Graph", + [ + helper.make_tensor_value_info("input", TensorProto.FLOAT, [batch_size, seq_len, hidden_size]), + helper.make_tensor_value_info("mask_index", TensorProto.INT32, [batch_size, total_seq_len]), + helper.make_tensor_value_info( + "past", TensorProto.FLOAT, [2, batch_size, num_heads, total_seq_len, hidden_size // num_heads] + ), + helper.make_tensor_value_info("past_sequence_length", TensorProto.INT32, [1]), + ], + [ + helper.make_tensor_value_info("output", TensorProto.FLOAT, [batch_size, seq_len, hidden_size]), + helper.make_tensor_value_info( + "present", TensorProto.FLOAT, [2, batch_size, num_heads, total_seq_len, hidden_size // num_heads] + ), + ], + initializers, + ) + + model = helper.make_model(graph) + return model.SerializeToString() + + class RotaryEmbedding(torch.nn.Module): def __init__(self, dim, max_position_embeddings, base=10000, device=None): super().__init__() @@ -111,9 +174,9 @@ def apply_rotary_pos_emb(q, k, cos, sin, offset: int = 0): class GPTNeoXAttention(nn.Module): - def __init__(self, batch_size, seq_len, num_head, hidden_size, use_rotary): + def __init__(self, batch_size, seq_len, num_head, hidden_size, past_seq_len=0): super().__init__() - self.use_rotary = use_rotary + self.do_rotary = True self.num_attention_heads = num_head self.hidden_size = hidden_size self.head_size = self.hidden_size // self.num_attention_heads @@ -133,18 +196,31 @@ def __init__(self, batch_size, seq_len, num_head, hidden_size, use_rotary): # self.query_key_value.weight.data.copy_(torch.tensor(np.ones((3 * hidden_size, hidden_size)))) # self.query_key_value.bias.data.copy_(torch.tensor(np.zeros((3 * hidden_size)))) - self.onnx_graph = create_neox_attention_graph( - batch_size, - seq_len, - self.hidden_size, - self.query_key_value.weight.reshape(self.num_attention_heads, 3, -1) - .transpose(0, 1) - .reshape(3 * self.hidden_size, -1) - .transpose(0, 1), - self.query_key_value.bias.reshape(self.num_attention_heads, 3, -1).transpose(0, 1).reshape(-1), - self.num_attention_heads, - self.use_rotary, - ) + if past_seq_len > 0: + self.onnx_graph = create_neox_decoder_masked_self_attention_graph( + batch_size, + seq_len, + past_seq_len, + self.hidden_size, + self.query_key_value.weight.reshape(self.num_attention_heads, 3, -1) + .transpose(0, 1) + .reshape(3 * self.hidden_size, -1) + .transpose(0, 1), + self.query_key_value.bias.reshape(self.num_attention_heads, 3, -1).transpose(0, 1).reshape(-1), + self.num_attention_heads, + ) + else: + self.onnx_graph = create_neox_attention_graph( + batch_size, + seq_len, + self.hidden_size, + self.query_key_value.weight.reshape(self.num_attention_heads, 3, -1) + .transpose(0, 1) + .reshape(3 * self.hidden_size, -1) + .transpose(0, 1), + self.query_key_value.bias.reshape(self.num_attention_heads, 3, -1).transpose(0, 1).reshape(-1), + self.num_attention_heads, + ) @classmethod def _merge_heads(cls, tensor, num_attention_heads, attn_head_size): @@ -204,21 +280,83 @@ def _attn(self, query, key, value, attention_mask=None, head_mask=None): attn_output = torch.matmul(attn_weights, value) return attn_output, attn_weights + # Reorder 'K' from [B, N, S, H] to [B, N, H/4, S, 4] + def reorder_key_cache(self, key_cache, batch_size, num_heads, sequence_length, head_size, max_sequence_length): + ordered = np.zeros_like(key_cache) + + # assume float + num_inner_elements = 4 + chunks = int(head_size / num_inner_elements) + + for b in range(batch_size): + for h in range(num_heads): + for c in range(chunks): + for s in range(sequence_length): + base_offset = (b * num_heads * max_sequence_length * head_size) + ( + h * max_sequence_length * head_size + ) + input_base_offset = base_offset + (s * head_size) + (c * num_inner_elements) + output_base_offset = ( + base_offset + (c * max_sequence_length * num_inner_elements) + (s * num_inner_elements) + ) + for e in range(num_inner_elements): + ordered[output_base_offset + e] = key_cache[input_base_offset + e] + + return ordered + def onnx_forward( self, hidden_states, + attention_mask=None, + layer_past=None, ): + import onnxruntime + + sess_options = onnxruntime.SessionOptions() + cuda_providers = ["CUDAExecutionProvider"] + if cuda_providers[0] not in onnxruntime.get_available_providers(): + return None + ort_session = onnxruntime.InferenceSession(self.onnx_graph, sess_options, providers=["CUDAExecutionProvider"]) + ort_inputs = { "input": np.ascontiguousarray(hidden_states.cpu().numpy()), } - from onnxruntime import InferenceSession, SessionOptions + if attention_mask is not None: + ort_inputs["mask_index"] = np.ascontiguousarray(attention_mask.cpu().numpy()) + + if layer_past is not None: + past_key = np.ascontiguousarray(layer_past[0].detach().numpy()) + past_value = np.ascontiguousarray(layer_past[1].detach().numpy()) + + past_seq_len = past_key.shape[2] + max_seq_len = past_seq_len + hidden_states.shape[1] + + past_key_padded = np.zeros( + [past_key.shape[0], past_key.shape[1], max_seq_len, past_key.shape[3]], + dtype=np.float32, + ) + past_value_padded = np.zeros( + [past_value.shape[0], past_value.shape[1], max_seq_len, past_value.shape[3]], + dtype=np.float32, + ) + past_key_padded[:, :, : past_key.shape[2], :] = past_key + past_value_padded[:, :, : past_value.shape[2], :] = past_value + reordered_past_key = self.reorder_key_cache( + past_key_padded.flatten(), + batch_size=past_key_padded.shape[0], + num_heads=self.num_attention_heads, + sequence_length=past_seq_len, + head_size=self.head_size, + max_sequence_length=max_seq_len, + ) + reordered_past_key = reordered_past_key.reshape(past_key_padded.shape) + ort_inputs["past"] = np.stack((reordered_past_key, past_value_padded), axis=0) + ort_inputs["past_sequence_length"] = np.array([past_seq_len], dtype=np.int32) - sess_options = SessionOptions() - ort_session = InferenceSession(self.onnx_graph, sess_options, providers=["CUDAExecutionProvider"]) ort_output = ort_session.run(None, ort_inputs) - output = torch.tensor(ort_output) + output = torch.tensor(ort_output[0]) return output @@ -226,10 +364,7 @@ def torch_forward( self, hidden_states, attention_mask=None, - head_mask=None, layer_past=None, - use_cache=False, - output_attentions=False, ): has_layer_past = layer_past is not None @@ -248,7 +383,7 @@ def torch_forward( key = qkv[..., self.head_size : 2 * self.head_size].permute(0, 2, 1, 3) value = qkv[..., 2 * self.head_size :].permute(0, 2, 1, 3) - if self.use_rotary: + if self.do_rotary: # Compute rotary embeddings on rotary_ndims query_rot = query[..., : self.rotary_ndims] query_pass = query[..., self.rotary_ndims :] @@ -265,9 +400,6 @@ def torch_forward( query, key = apply_rotary_pos_emb(query_rot, key_rot, cos, sin, offset=offset) query = torch.cat((query, query_pass), dim=-1) key = torch.cat((key, key_pass), dim=-1) - # print("query", query.shape, query) - # print("key", key.shape, key) - # print("value", value.shape, value) # Cache QKV values if has_layer_past: @@ -277,7 +409,7 @@ def torch_forward( value = torch.cat((past_value, value), dim=-2) # Compute attention - attn_output, _ = self._attn(query, key, value, attention_mask, head_mask) + attn_output, _ = self._attn(query, key, value, attention_mask, head_mask=None) # Reshape outputs attn_output = self._merge_heads(attn_output, self.num_attention_heads, self.head_size) @@ -285,25 +417,57 @@ def torch_forward( return attn_output -if __name__ == "__main__": - for batch_size in [1, 2, 4, 8]: - for seq_len in [32, 128, 512, 1024, 2048]: - for num_head in [12]: - for hidden_size in [768]: - attn = GPTNeoXAttention(batch_size, seq_len, num_head, hidden_size, use_rotary=True) - - hidden_states = torch.normal(mean=0.5, std=0.1, size=(batch_size, seq_len, hidden_size)).to( - torch.float32 - ) - - torch_output = attn.torch_forward(hidden_states) - ort_output = attn.onnx_forward(hidden_states) - print( - "Parity check with shape BNSH = ({},{},{},{})".format( - batch_size, seq_len, num_head, hidden_size +class TestGPTNeoXAttention(unittest.TestCase): + def test_gpt_neox_attention(self): + for batch_size in [1, 2, 4, 8]: + for seq_len in [32, 128, 512, 1024, 2048]: + for num_head in [12]: + for hidden_size in [768]: + attn = GPTNeoXAttention(batch_size, seq_len, num_head, hidden_size) + + hidden_states = torch.normal(mean=0.5, std=0.1, size=(batch_size, seq_len, hidden_size)).to( + torch.float32 ) - ) - if torch.allclose(torch_output, ort_output, atol=1e-6): - print("Success!") - else: - print("Failure!") + + torch_output = attn.torch_forward(hidden_states) + ort_output = attn.onnx_forward(hidden_states) + if ort_output is not None: + assert torch.allclose(torch_output, ort_output, atol=1e-4) + + def test_gpt_neox_decoder_masked_self_attention(self): + for batch_size in [1, 2, 4, 8]: + for past_seq_len in [1, 4, 32, 128, 512, 1024]: + total_seq_len = past_seq_len + 1 + for num_head in [12]: + for hidden_size in [768]: + attn = GPTNeoXAttention(batch_size, 1, num_head, hidden_size, past_seq_len) + + hidden_states = torch.normal(mean=0.5, std=0.1, size=(batch_size, 1, hidden_size)).to( + torch.float32 + ) + + attention_mask = torch.ones((batch_size, total_seq_len)).to(torch.int32) + past_key = torch.normal( + mean=0.5, + std=0.1, + size=(batch_size, num_head, past_seq_len, hidden_size // num_head), + ).to(torch.float32) + past_value = torch.normal( + mean=0.5, + std=0.1, + size=(batch_size, num_head, past_seq_len, hidden_size // num_head), + ).to(torch.float32) + layer_past = (past_key, past_value) + + torch_output = attn.torch_forward( + hidden_states, attention_mask=attention_mask, layer_past=layer_past + ) + ort_output = attn.onnx_forward( + hidden_states, attention_mask=attention_mask, layer_past=layer_past + ) + if ort_output is not None: + assert torch.allclose(torch_output, ort_output, atol=1e-4) + + +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 23218e4943042..c7fb398dde82e 100644 --- a/onnxruntime/test/python/transformers/test_parity_t5_mha.py +++ b/onnxruntime/test/python/transformers/test_parity_t5_mha.py @@ -16,6 +16,7 @@ import numpy as np import torch +from onnx import TensorProto, helper from torch import nn torch.manual_seed(0) @@ -30,8 +31,6 @@ def create_t5_mha_graph( use_past, is_static_kv, ): - from onnx import TensorProto, helper - use_present = not use_past if not is_static_kv and use_past: use_present = True @@ -163,8 +162,6 @@ def create_t5_decoder_masked_mha_graph( num_heads, is_cross_attention, ): - from onnx import TensorProto, helper - nodes = [ helper.make_node( "DecoderMaskedMultiHeadAttention", @@ -491,7 +488,7 @@ def project(hidden_states, proj_layer, key_value_states, past_key_value): # attn_output = self.o(attn_output) # ORT places this matmul outside of MHA op present_key_value_state = (key_states, value_states) if (self.is_decoder and use_cache) else None - outputs = (attn_output,) + (present_key_value_state,) + outputs = (attn_output, present_key_value_state) return outputs @@ -628,7 +625,7 @@ def project(hidden_states, proj_layer, key_value_states, past_key_value): if past_key_value is not None and self.is_static_kv: output = torch.tensor(ort_output) else: - output = (torch.tensor(ort_output[0]),) + ((torch.tensor(ort_output[1]), torch.tensor(ort_output[2])),) + output = (torch.tensor(ort_output[0]), (torch.tensor(ort_output[1]), torch.tensor(ort_output[2]))) return output diff --git a/onnxruntime/test/python/transformers/test_skip_layer_norm_fusion.py b/onnxruntime/test/python/transformers/test_skip_layer_norm_fusion.py new file mode 100644 index 0000000000000..5b3a3f18cd744 --- /dev/null +++ b/onnxruntime/test/python/transformers/test_skip_layer_norm_fusion.py @@ -0,0 +1,276 @@ +# ------------------------------------------------------------------------- +# 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 +from typing import Dict, List + +import numpy as np +import onnx +from onnx import TensorProto, helper, numpy_helper +from parity_utilities import find_transformers_source + +if find_transformers_source(): + from fusion_options import FusionOptions + from optimizer import optimize_model +else: + from onnxruntime.transformers.fusion_options import FusionOptions + from onnxruntime.transformers.optimizer import optimize_model + + +def float_tensor(name: str, shape: List[int], random=False): + low = 0.0 + high = 1.0 + total_elements = 1 + for x in shape: + total_elements *= x + weights = [np.random.uniform(low, high) for _ in range(total_elements)] if random else [1.0] * total_elements + return helper.make_tensor(name, TensorProto.FLOAT, shape, weights) + + +class TestFusion(unittest.TestCase): + def verify_skip_layer_norm_fusion( + self, + model_path: str, + expected_counter: Dict[str, int], + expected_inputs: List[str], + expected_outputs: List[str], + ): + options = FusionOptions("bert") + optimized_model = optimize_model(model_path, optimization_options=options, opt_level=0) + + ops = ["Add", "LayerNormalization", "SkipLayerNormalization", "Cast"] + for op in ops: + nodes = optimized_model.get_nodes_by_op_type(op) + print(op, len(nodes), expected_counter[op]) + self.assertEqual(len(nodes), expected_counter[op]) + + if op == "SkipLayerNormalization" and expected_counter[op] == 1: + print(nodes[0].input) + print(nodes[0].output) + self.assertEqual(nodes[0].input, expected_inputs) + self.assertEqual(nodes[0].output, expected_outputs) + + def create_test_model( + self, + batch_size: int = 1, + sequence_length: int = 2, + hidden_size: int = 3, + add_graph_output: bool = True, + bias: int = 0, # 0 - no bias, 1 - bias in input_1, 2 - bias in input_2 + cast_before_add_bias=False, + ): + matmul = helper.make_node("MatMul", ["input_0", "matmul_weight"], ["matmul_output"], "matmul") + cast_node = helper.make_node("Cast", ["matmul_output"], ["matmul_output_cast"], to=1) + add_bias = helper.make_node( + "Add", + ["matmul_output_cast" if cast_before_add_bias else "matmul_output", "bias"], + ["input_1" if bias == 1 else "input_2"], + "add_bias", + ) + + add_before_layer_norm = helper.make_node("Add", ["input_1", "input_2"], ["layernorm_input"], "add_layernorm") + layer_norm = helper.make_node( + "LayerNormalization", + ["layernorm_input", "layer_norm_weight", "layer_norm_bias"], + ["output"], + "layernorm", + axis=-1, + epsion=0.000009999999747378752, + ) + + initializers = [ # initializers + float_tensor("layer_norm_weight", [hidden_size]), + float_tensor("layer_norm_bias", [hidden_size]), + ] + + if bias > 0: + weight_tensor = float_tensor("matmul_weight", [hidden_size, hidden_size]) + # MatMul weights is float16 when there is Cast node + if cast_before_add_bias: + weight_tensor.CopyFrom( + numpy_helper.from_array(numpy_helper.to_array(weight_tensor).astype(np.float16), weight_tensor.name) + ) + initializers.append(weight_tensor) + + bias_tensor = float_tensor("bias", [hidden_size]) + initializers.append(bias_tensor) + + input_0 = helper.make_tensor_value_info( + "input_0", + TensorProto.FLOAT16 if cast_before_add_bias else TensorProto.FLOAT, + [batch_size, sequence_length, hidden_size], + ) + + input_1 = helper.make_tensor_value_info( + "input_1", + TensorProto.FLOAT, + [batch_size, sequence_length, hidden_size], + ) + + input_2 = helper.make_tensor_value_info( + "input_2", + TensorProto.FLOAT, + [batch_size, sequence_length, hidden_size], + ) + + output = helper.make_tensor_value_info( + "output", + TensorProto.FLOAT, + [batch_size, sequence_length, hidden_size], + ) + + layernorm_input = helper.make_tensor_value_info( + "layernorm_input", + TensorProto.FLOAT, + [batch_size, sequence_length, hidden_size], + ) + + nodes = [add_before_layer_norm, layer_norm] + if bias > 0: + nodes.insert(0, add_bias) + if cast_before_add_bias: + nodes.insert(0, cast_node) + nodes.insert(0, matmul) + + node_name = "SkipLayerNormFusionModel" + if bias == 0: + graph = helper.make_graph( + nodes, + node_name, + [input_1, input_2], # inputs + [output, layernorm_input] if add_graph_output else [output], # outputs + initializers, + ) + elif bias == 1: + graph = helper.make_graph( + nodes, + node_name, + [input_0, input_2], # inputs + [output, layernorm_input] if add_graph_output else [output], # outputs + initializers, + ) + else: + graph = helper.make_graph( + nodes, + node_name, + [input_0, input_1], # inputs + [output, layernorm_input] if add_graph_output else [output], # outputs + initializers, + ) + + onnx_opset = helper.make_opsetid("ai.onnx", min(onnx.defs.onnx_opset_version(), 16)) + return helper.make_model(graph, opset_imports=(onnx_opset,)) + + def test_skip_layer_norm_no_graph_output(self): + model = self.create_test_model(batch_size=1, sequence_length=2, hidden_size=3, add_graph_output=False) + model_name = "skip_layer_norm_add_no_graph_output.onnx" + onnx.save(model, model_name) + self.verify_skip_layer_norm_fusion( + model_name, + { + "Add": 0, + "LayerNormalization": 0, + "SkipLayerNormalization": 1, + "Cast": 0, + }, + ["input_1", "input_2", "layer_norm_weight", "layer_norm_bias"], + ["output"], + ) + os.remove(model_name) + + def test_skip_layer_norm_graph_output(self): + model = self.create_test_model(batch_size=1, sequence_length=2, hidden_size=3, add_graph_output=True) + model_name = "skip_layer_norm_add_has_graph_output.onnx" + onnx.save(model, model_name) + self.verify_skip_layer_norm_fusion( + model_name, + { + "Add": 0, + "LayerNormalization": 0, + "SkipLayerNormalization": 1, + "Cast": 0, + }, + ["input_1", "input_2", "layer_norm_weight", "layer_norm_bias"], + ["output", "", "", "layernorm_input"], + ) + os.remove(model_name) + + def test_skip_layer_norm_graph_output_bias1(self): + model = self.create_test_model(batch_size=1, sequence_length=2, hidden_size=3, add_graph_output=True, bias=1) + model_name = "skip_layer_norm_add_has_graph_output_bias1.onnx" + onnx.save(model, model_name) + self.verify_skip_layer_norm_fusion( + model_name, + { + "Add": 0, + "LayerNormalization": 0, + "SkipLayerNormalization": 1, + "Cast": 0, + }, + ["matmul_output", "input_2", "layer_norm_weight", "layer_norm_bias", "bias"], + ["output", "", "", "layernorm_input"], + ) + os.remove(model_name) + + def test_skip_layer_norm_graph_output_bias2(self): + model = self.create_test_model(batch_size=1, sequence_length=2, hidden_size=3, add_graph_output=True, bias=2) + model_name = "skip_layer_norm_add_has_graph_output_bias1.onnx" + onnx.save(model, model_name) + self.verify_skip_layer_norm_fusion( + model_name, + { + "Add": 0, + "LayerNormalization": 0, + "SkipLayerNormalization": 1, + "Cast": 0, + }, + ["matmul_output", "input_1", "layer_norm_weight", "layer_norm_bias", "bias"], + ["output", "", "", "layernorm_input"], + ) + os.remove(model_name) + + def test_skip_layer_norm_graph_output_cast_bias1(self): + model = self.create_test_model( + batch_size=1, sequence_length=2, hidden_size=3, add_graph_output=True, bias=1, cast_before_add_bias=True + ) + model_name = "skip_layer_norm_add_has_graph_output_cast_bias1.onnx" + onnx.save(model, model_name) + self.verify_skip_layer_norm_fusion( + model_name, + { + "Add": 0, + "LayerNormalization": 0, + "SkipLayerNormalization": 1, + "Cast": 1, + }, + ["matmul_output_cast", "input_2", "layer_norm_weight", "layer_norm_bias", "bias"], + ["output", "", "", "layernorm_input"], + ) + os.remove(model_name) + + def test_skip_layer_norm_graph_output_cast_bias2(self): + model = self.create_test_model( + batch_size=1, sequence_length=2, hidden_size=3, add_graph_output=True, bias=2, cast_before_add_bias=True + ) + model_name = "skip_layer_norm_add_has_graph_output_cast_bias2.onnx" + onnx.save(model, model_name) + self.verify_skip_layer_norm_fusion( + model_name, + { + "Add": 0, + "LayerNormalization": 0, + "SkipLayerNormalization": 1, + "Cast": 1, + }, + ["matmul_output_cast", "input_1", "layer_norm_weight", "layer_norm_bias", "bias"], + ["output", "", "", "layernorm_input"], + ) + os.remove(model_name) + + +if __name__ == "__main__": + unittest.main() diff --git a/onnxruntime/test/python/transformers/test_whisper.py b/onnxruntime/test/python/transformers/test_whisper.py index 1aeea0b00c612..ebda0bccaadcf 100644 --- a/onnxruntime/test/python/transformers/test_whisper.py +++ b/onnxruntime/test/python/transformers/test_whisper.py @@ -37,7 +37,18 @@ def verify_fusion(self, optimized_model, expected_model_filename): expected_model = OnnxModel(onnx.load(expected_model_path)) expected_model.topological_sort(is_deterministic=True) - self.assertEqual(str(optimized_model.model.graph), str(expected_model.model.graph)) + 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 + ) + ) # Attention type #1 in onnx_model_bart.py def test_encoder_attention_fusion_with_skiplayernorm(self): @@ -123,6 +134,61 @@ def test_decoder_with_past_multihead_cross_attention_fusion(self): os.remove(model_path) self.verify_fusion(optimized_model, "decoder_with_past_cross_mha_fused.onnx") + # Attention type #4 in onnx_model_bart.py + def test_decoder_multihead_attention_split_bias_fusion(self): + num_heads = 4 + hidden_size = 64 + model = create_whisper_decoder_multihead_attention(num_heads=num_heads, hidden_size=hidden_size) + dir = "." + model_path = os.path.join(dir, "whisper_decoder_mha.onnx") + onnx.save(model, model_path) + options = FusionOptions("bart") + options.use_multi_head_attention = True + options.disable_multi_head_attention_bias = True + optimized_model = optimize_model( + model_path, model_type="bart", num_heads=num_heads, hidden_size=hidden_size, optimization_options=options + ) + os.remove(model_path) + self.verify_fusion(optimized_model, "decoder_mha_split_bias_fused.onnx") + + # Attention type #3 in onnx_model_bart.py + def test_decoder_with_past_multihead_self_attention_split_bias_fusion_with_skiplayernorm(self): + num_heads = 4 + hidden_size = 64 + model = create_whisper_decoder_with_past_multihead_self_attention( + num_heads=num_heads, hidden_size=hidden_size, add_before_layernorm=False + ) + dir = "." + model_path = os.path.join(dir, "whisper_decoder_with_past_self_mha.onnx") + onnx.save(model, model_path) + options = FusionOptions("bart") + options.use_multi_head_attention = True + options.disable_multi_head_attention_bias = True + + optimized_model = optimize_model( + model_path, model_type="bart", num_heads=num_heads, hidden_size=hidden_size, optimization_options=options + ) + os.remove(model_path) + self.verify_fusion(optimized_model, "decoder_with_past_self_mha_split_bias_fused.onnx") + + # Attention type #5 in onnx_model_bart.py + def test_decoder_with_past_multihead_cross_attention_split_bias_fusion(self): + num_heads = 4 + hidden_size = 64 + model = create_whisper_decoder_with_past_multihead_cross_attention(num_heads=num_heads, hidden_size=hidden_size) + dir = "." + model_path = os.path.join(dir, "whisper_decoder_with_past_cross_mha.onnx") + onnx.save(model, model_path) + options = FusionOptions("bart") + options.use_multi_head_attention = True + options.disable_multi_head_attention_bias = True + + optimized_model = optimize_model( + model_path, model_type="bart", num_heads=num_heads, hidden_size=hidden_size, optimization_options=options + ) + os.remove(model_path) + self.verify_fusion(optimized_model, "decoder_with_past_cross_mha_split_bias_fused.onnx") + if __name__ == "__main__": unittest.main() diff --git a/onnxruntime/test/python/transformers/test_whisper_timestamp_processor.py b/onnxruntime/test/python/transformers/test_whisper_timestamp_processor.py new file mode 100644 index 0000000000000..66200af06f511 --- /dev/null +++ b/onnxruntime/test/python/transformers/test_whisper_timestamp_processor.py @@ -0,0 +1,75 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +import unittest + +import numpy as np +import pytest +import torch + +from onnxruntime import InferenceSession, SessionOptions + + +class TestTimestampProcessor(unittest.TestCase): + def generate_model(self, arguments: str): + from onnxruntime.transformers.models.whisper.convert_to_onnx import main as whisper_to_onnx + + whisper_to_onnx(arguments.split()) + + def generate_dataset(self): + from datasets import load_dataset + from transformers import AutoProcessor + + processor = AutoProcessor.from_pretrained("openai/whisper-tiny") + ds = load_dataset("hf-internal-testing/librispeech_asr_dummy", "clean", split="validation") + inputs = processor(ds[0]["audio"]["array"], return_tensors="pt") + input_features = inputs.input_features + return [input_features, processor] + + def run_timestamp(self, provider: str): + self.generate_model("-m openai/whisper-tiny --optimize_onnx --precision fp32 -l -e") + [input_features, processor] = self.generate_dataset() + model_path = "./onnx_models/whisper-tiny_beamsearch.onnx" + sess_options = SessionOptions() + sess_options.log_severity_level = 4 + sess = InferenceSession(model_path, sess_options, providers=[provider]) + input_data = input_features.repeat(1, 1, 1) + ort_inputs = { + "input_features": np.float32(input_data.cpu().numpy()), + "max_length": np.array([128], dtype=np.int32), + "min_length": np.array([0], dtype=np.int32), + "num_beams": np.array([1], dtype=np.int32), + "num_return_sequences": np.array([1], dtype=np.int32), + "length_penalty": np.array([1.0], dtype=np.float32), + "repetition_penalty": np.array([1.0], dtype=np.float32), + "logits_processor": np.array([1], dtype=np.int32), + } + ort_out = sess.run(None, ort_inputs) + ort_out_tensor = torch.from_numpy(ort_out[0]) + ort_transcription = processor.batch_decode( + ort_out_tensor[0][0].view(1, -1), skip_special_tokens=True, output_offsets=True + ) + expected_transcription = [ + { + "text": " Mr. Quilter is the apostle of the middle classes and we are glad to welcome his gospel.", + "offsets": [ + { + "text": " Mr. Quilter is the apostle of the middle classes and we are glad to welcome his gospel.", + "timestamp": (0.0, 5.44), + } + ], + } + ] + self.assertEqual(ort_transcription, expected_transcription) + + @pytest.mark.slow + def test_timestamp_cpu(self): + provider = "CPUExecutionProvider" + self.run_timestamp(provider) + + +if __name__ == "__main__": + unittest.main() diff --git a/onnxruntime/test/quantization/quantization_test.cc b/onnxruntime/test/quantization/quantization_test.cc index 4f55e7aa7ff8c..bdfac77b336d4 100644 --- a/onnxruntime/test/quantization/quantization_test.cc +++ b/onnxruntime/test/quantization/quantization_test.cc @@ -4,7 +4,6 @@ #include "gtest/gtest.h" #include "core/framework/tensor.h" -#include "core/framework/allocatormgr.h" #include "core/quantization/quantization.h" #include "test/framework/test_utils.h" @@ -99,7 +98,7 @@ void EnsureQuantizedTensorParam(const float scale, const T zero_point) { TensorShape shape({1}); // First, create the scale tensor: - auto alloc = TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault); + auto alloc = TestCPUExecutionProvider()->CreatePreferredAllocators()[0]; auto num_bytes = shape.Size() * sizeof(float); void* data = alloc->Alloc(num_bytes); float* float_data = static_cast(data); diff --git a/onnxruntime/test/shared_lib/custom_op_utils.h b/onnxruntime/test/shared_lib/custom_op_utils.h index 74975b53d7960..8ead4056b1b54 100644 --- a/onnxruntime/test/shared_lib/custom_op_utils.h +++ b/onnxruntime/test/shared_lib/custom_op_utils.h @@ -377,3 +377,91 @@ struct StandaloneCustomOp : Ort::CustomOpBase { + void* CreateKernel(const OrtApi&, const OrtKernelInfo* info) const { return new MulTopKernelFloat(info); } + const char* GetName() const { return "MulTop"; } + const char* GetExecutionProviderType() const { return "CPUExecutionProvider"; } + size_t GetInputTypeCount() const { return 1; } + ONNXTensorElementDataType GetInputType(size_t) const { return ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT; } + size_t GetOutputTypeCount() const { return 1; } + ONNXTensorElementDataType GetOutputType(size_t) const { return ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT; } +}; + +struct MulTopKernelInt32 { + MulTopKernelInt32(const OrtKernelInfo*){}; + ~MulTopKernelInt32() = default; + void Compute(OrtKernelContext*){}; +}; + +struct MulTopOpInt32 : Ort::CustomOpBase { + void* CreateKernel(const OrtApi&, const OrtKernelInfo* info) const { return new MulTopKernelInt32(info); } + const char* GetName() const { return "MulTop"; } + const char* GetExecutionProviderType() const { return "CPUExecutionProvider"; } + size_t GetInputTypeCount() const { return 1; } + ONNXTensorElementDataType GetInputType(size_t) const { return ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32; } + size_t GetOutputTypeCount() const { return 1; } + ONNXTensorElementDataType GetOutputType(size_t) const { return ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32; } +}; + +struct MulTopKernelDouble { + MulTopKernelDouble(const OrtKernelInfo*){}; + ~MulTopKernelDouble() = default; + void Compute(OrtKernelContext*){}; +}; + +// MulTopOpDouble and MulTopOpFloat has input count mismatch +struct MulTopOpDouble : Ort::CustomOpBase { + void* CreateKernel(const OrtApi&, const OrtKernelInfo* info) const { return new MulTopKernelDouble(info); } + const char* GetName() const { return "MulTop"; } + const char* GetExecutionProviderType() const { return "CPUExecutionProvider"; } + size_t GetInputTypeCount() const { return 2; } + ONNXTensorElementDataType GetInputType(size_t) const { return ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE; } + size_t GetOutputTypeCount() const { return 1; } + ONNXTensorElementDataType GetOutputType(size_t) const { return ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE; } +}; + +struct MulTopKernelInt16 { + MulTopKernelInt16(const OrtKernelInfo*){}; + ~MulTopKernelInt16() = default; + void Compute(OrtKernelContext*){}; +}; + +// MulTopOpInt16 and MulTopOpFloat has output count mismatch +struct MulTopOpInt16 : Ort::CustomOpBase { + void* CreateKernel(const OrtApi&, const OrtKernelInfo* info) const { return new MulTopKernelInt16(info); } + const char* GetName() const { return "MulTop"; } + const char* GetExecutionProviderType() const { return "CPUExecutionProvider"; } + size_t GetInputTypeCount() const { return 1; } + ONNXTensorElementDataType GetInputType(size_t) const { return ONNX_TENSOR_ELEMENT_DATA_TYPE_INT16; } + size_t GetOutputTypeCount() const { return 2; } + ONNXTensorElementDataType GetOutputType(size_t) const { return ONNX_TENSOR_ELEMENT_DATA_TYPE_INT16; } +}; + +// MulTopKernelFloat16 and MulTopOpFloat has input characteristic mismatch +struct MulTopKernelFloat16 { + MulTopKernelFloat16(const OrtKernelInfo*){}; + ~MulTopKernelFloat16() = default; + void Compute(OrtKernelContext*){}; +}; + +struct MulTopOpFloat16 : Ort::CustomOpBase { + void* CreateKernel(const OrtApi&, const OrtKernelInfo* info) const { return new MulTopKernelFloat16(info); } + const char* GetName() const { return "MulTop"; } + const char* GetExecutionProviderType() const { return "CPUExecutionProvider"; } + size_t GetInputTypeCount() const { return 1; } + ONNXTensorElementDataType GetInputType(size_t) const { return ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16; } + size_t GetOutputTypeCount() const { return 1; } + ONNXTensorElementDataType GetOutputType(size_t) const { return ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16; } + OrtCustomOpInputOutputCharacteristic GetInputCharacteristic(size_t) const { + return OrtCustomOpInputOutputCharacteristic::INPUT_OUTPUT_OPTIONAL; + } +}; \ No newline at end of file diff --git a/onnxruntime/test/shared_lib/rocm_ops.hip b/onnxruntime/test/shared_lib/rocm_ops.hip new file mode 100644 index 0000000000000..5f8a9189454c4 --- /dev/null +++ b/onnxruntime/test/shared_lib/rocm_ops.hip @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License + +#include "hip/hip_runtime.h" + +__global__ void _Add(long long sz, float* Z, const float* X, const float* Y) { + long long offset = hipBlockDim_x*hipBlockIdx_x + hipThreadIdx_x; + if (offset < sz) { + Z[offset] = X[offset] + Y[offset]; + } +} + +void rocm_add(int64_t sz, float* Z, const float* X, const float* Y, hipStream_t compute_stream) { + _Add<<<256, 256, 0, compute_stream>>>(static_cast(sz), Z, X, Y); +} + diff --git a/onnxruntime/test/shared_lib/test_inference.cc b/onnxruntime/test/shared_lib/test_inference.cc index 07ce0f773df34..8357ce22fb710 100644 --- a/onnxruntime/test/shared_lib/test_inference.cc +++ b/onnxruntime/test/shared_lib/test_inference.cc @@ -15,9 +15,11 @@ #include "gmock/gmock.h" #include "core/common/common.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 "core/session/onnxruntime_run_options_config_keys.h" #include "core/util/thread_utils.h" @@ -46,9 +48,9 @@ constexpr size_t countof(T (&)[N]) { return N; } extern std::unique_ptr ort_env; -template +template void RunSession(OrtAllocator* allocator, Ort::Session& session_object, - const std::vector& inputs, + const std::vector& inputs, const char* output_name, const std::vector& dims_y, const std::vector& values_y, @@ -58,8 +60,8 @@ void RunSession(OrtAllocator* allocator, Ort::Session& session_object, 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())); + 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; @@ -80,13 +82,17 @@ void RunSession(OrtAllocator* allocator, Ort::Session& session_object, OutT* f = output_tensor->GetTensorMutableData(); for (size_t i = 0; i != total_len; ++i) { - ASSERT_EQ(values_y[i], f[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]); + } } } -template +template static void TestInference(Ort::Env& env, const std::basic_string& model_uri, - const std::vector& inputs, + const std::vector& inputs, const char* output_name, const std::vector& expected_dims_y, const std::vector& expected_values_y, @@ -115,7 +121,13 @@ static void TestInference(Ort::Env& env, const std::basic_string& mod dnnl_options.use_arena = 1; dnnl_options.threadpool_args = nullptr; session_options.AppendExecutionProvider_Dnnl(dnnl_options); - std::cout << "Running simple inference with dnnl provider" << std::endl; +#else + return; +#endif + } else if (provider_type == 3) { +#ifdef USE_ROCM + OrtROCMProviderOptions rocm_options; + session_options.AppendExecutionProvider_ROCM(rocm_options); #else return; #endif @@ -139,26 +151,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); } } @@ -172,6 +184,9 @@ static constexpr PATH_TYPE SEQUENCE_MODEL_URI_2 = TSTR("testdata/optional_sequen #endif static constexpr PATH_TYPE CUSTOM_OP_MODEL_URI = TSTR("testdata/foo_1.onnx"); static constexpr PATH_TYPE CUSTOM_OP_LIBRARY_TEST_MODEL_URI = TSTR("testdata/custom_op_library/custom_op_test.onnx"); +#if !defined(DISABLE_FLOAT8_TYPES) +static constexpr PATH_TYPE CUSTOM_OP_LIBRARY_TEST_MODEL_FLOAT8_URI = TSTR("testdata/custom_op_library/custom_op_test_float8.onnx"); +#endif #if defined(USE_OPENVINO) && (!defined(ORT_MINIMAL_BUILD) || defined(ORT_MINIMAL_BUILD_CUSTOM_OPS)) static constexpr PATH_TYPE CUSTOM_OP_OPENVINO_WRAPPER_LIB_TEST_MODEL_URI = TSTR( "testdata/custom_op_openvino_wrapper_library/custom_op_mnist_ov_wrapper.onnx"); @@ -187,6 +202,7 @@ static constexpr PATH_TYPE VARIADIC_INPUT_OUTPUT_CUSTOM_OP_MODEL_URI = TSTR("tes static constexpr PATH_TYPE VARIADIC_UNDEF_INPUT_OUTPUT_CUSTOM_OP_MODEL_URI = TSTR( "testdata/custom_op_variadic_undef_io.onnx"); static constexpr PATH_TYPE CUSTOM_OP_MODEL_WITH_ATTRIBUTES_URI = TSTR("testdata/foo_bar_3.onnx"); +static constexpr PATH_TYPE CUSTOM_OP_SINGLE_SCHEMA_MULTI_KERNEL = TSTR("testdata/custom_op_single_schema_multi_kernel.onnx"); #if !defined(DISABLE_SPARSE_TENSORS) static constexpr PATH_TYPE SPARSE_OUTPUT_MODEL_URI = TSTR("testdata/sparse_initializer_as_output.onnx"); #ifndef DISABLE_CONTRIB_OPS @@ -1047,7 +1063,7 @@ TEST(CApiTest, invalid_variadic_input_homogeneity_custom_op) { Ort::Session session(*ort_env, VARIADIC_UNDEF_INPUT_OUTPUT_CUSTOM_OP_MODEL_URI, session_options); FAIL(); } catch (const Ort::Exception& excpt) { - ASSERT_THAT(excpt.what(), testing::HasSubstr("Type Error: Type parameter (T0) of Optype (VariadicNode) bound " + ASSERT_THAT(excpt.what(), testing::HasSubstr("Type Error: Type parameter (Input0) of Optype (VariadicNode) bound " "to different types")); } } @@ -1381,12 +1397,61 @@ TEST(CApiTest, test_custom_op_library) { #ifdef USE_CUDA TestInference(*ort_env, CUSTOM_OP_LIBRARY_TEST_MODEL_URI, inputs, "output", expected_dims_y, expected_values_y, 1, nullptr, lib_name.c_str()); +#elif USE_ROCM + TestInference(*ort_env, CUSTOM_OP_LIBRARY_TEST_MODEL_URI, inputs, "output", expected_dims_y, + expected_values_y, 3, nullptr, lib_name.c_str()); #else TestInference(*ort_env, CUSTOM_OP_LIBRARY_TEST_MODEL_URI, inputs, "output", expected_dims_y, expected_values_y, 0, nullptr, lib_name.c_str()); #endif } +#if !defined(DISABLE_FLOAT8_TYPES) + +struct InputF8 { + const char* name = nullptr; + std::vector dims; + std::vector values; +}; + +// See test test_custom_op_library_float8. +#if defined(__ANDROID__) +TEST(CApiTest, DISABLED_test_custom_op_library_float8) { +#elif defined(REDUCED_OPS_BUILD) && defined(USE_CUDA) +TEST(CApiTest, DISABLED_test_custom_op_library_float8) { +#else +TEST(CApiTest, test_custom_op_library_float8) { +#endif + std::cout << "Running inference using custom op shared library" << std::endl; + + std::vector inputs(2); + inputs[0].name = "X"; + inputs[0].dims = {2}; + inputs[0].values = {0, 1}; + inputs[1].name = "Y"; + inputs[1].dims = {2}; + inputs[1].values = {3, 4}; + + // prepare expected inputs and outputs + std::vector expected_dims_y = {2}; + std::vector expected_values_y = {0, 1}; + + onnxruntime::PathString lib_name; +#if defined(_WIN32) + lib_name = ORT_TSTR("custom_op_library.dll"); +#elif defined(__APPLE__) + lib_name = ORT_TSTR("libcustom_op_library.dylib"); +#else + lib_name = ORT_TSTR("./libcustom_op_library.so"); +#endif + + TestInference(*ort_env, CUSTOM_OP_LIBRARY_TEST_MODEL_FLOAT8_URI, inputs, + "Z", expected_dims_y, + expected_values_y, 0, nullptr, lib_name.c_str()); +} + +#endif + #if !defined(ORT_MINIMAL_BUILD) || defined(ORT_MINIMAL_BUILD_CUSTOM_OPS) #if defined(__ANDROID__) // Disable on android because custom op libraries are not copied to the emulator. @@ -1738,10 +1803,25 @@ TEST(CApiTest, io_binding_cuda) { } #endif -#if defined(USE_CUDA) -TEST(CApiTest, cuda_graph) { +#if defined(USE_CUDA) || defined(USE_TENSORRT) +TEST(CApiTest, basic_cuda_graph) { const auto& api = Ort::GetApi(); + Ort::SessionOptions session_options; +#if defined(USE_TENSORRT) + // Enable cuda graph in TRT provider option. + OrtTensorRTProviderOptionsV2* trt_options; + ASSERT_TRUE(api.CreateTensorRTProviderOptions(&trt_options) == nullptr); + std::unique_ptr + rel_trt_options(trt_options, api.ReleaseTensorRTProviderOptions); + std::vector keys{"trt_cuda_graph_enable"}; + std::vector values{"1"}; + ASSERT_TRUE(api.UpdateTensorRTProviderOptions(rel_trt_options.get(), keys.data(), values.data(), keys.size()) == nullptr); + + ASSERT_TRUE(api.SessionOptionsAppendExecutionProvider_TensorRT_V2( + static_cast(session_options), + rel_trt_options.get()) == nullptr); +#else // Enable cuda graph in cuda provider option. OrtCUDAProviderOptionsV2* cuda_options = nullptr; ASSERT_TRUE(api.CreateCUDAProviderOptions(&cuda_options) == nullptr); @@ -1751,12 +1831,11 @@ TEST(CApiTest, cuda_graph) { std::vector values{"1"}; ASSERT_TRUE(api.UpdateCUDAProviderOptions(rel_cuda_options.get(), keys.data(), values.data(), 1) == nullptr); - Ort::SessionOptions session_options; ASSERT_TRUE(api.SessionOptionsAppendExecutionProvider_CUDA_V2( static_cast(session_options), rel_cuda_options.get()) == nullptr); +#endif - // Create IoBinding for inputs and outputs. Ort::Session session(*ort_env, MODEL_URI, session_options); Ort::MemoryInfo info_cuda("Cuda", OrtAllocatorType::OrtArenaAllocator, 0, OrtMemTypeDefault); @@ -1785,6 +1864,7 @@ TEST(CApiTest, cuda_graph) { Ort::Value bound_y = Ort::Value::CreateTensor(info_cuda, reinterpret_cast(output_data.get()), expected_y.size(), expected_y_shape.data(), expected_y_shape.size()); + // Create IoBinding for inputs and outputs. Ort::IoBinding binding(session); binding.BindInput("X", bound_x); binding.BindOutput("Y", bound_y); @@ -1816,11 +1896,37 @@ TEST(CApiTest, cuda_graph) { binding.ClearBoundInputs(); binding.ClearBoundOutputs(); } + +#ifndef REDUCED_OPS_BUILD +// The following test uses some ops not supported in the reduced ops build +TEST(CApiTest, cuda_graph_with_shape_nodes) { + const auto& api = Ort::GetApi(); + + // Enable cuda graph in cuda provider option. + OrtCUDAProviderOptionsV2* cuda_options = nullptr; + ASSERT_TRUE(api.CreateCUDAProviderOptions(&cuda_options) == nullptr); + std::unique_ptr + rel_cuda_options(cuda_options, api.ReleaseCUDAProviderOptions); + std::vector keys{"enable_cuda_graph"}; + std::vector values{"1"}; + ASSERT_TRUE(api.UpdateCUDAProviderOptions(rel_cuda_options.get(), keys.data(), values.data(), 1) == nullptr); + + Ort::SessionOptions session_options; + ASSERT_TRUE(api.SessionOptionsAppendExecutionProvider_CUDA_V2( + static_cast(session_options), + rel_cuda_options.get()) == nullptr); + + // Successful loading of the ONNX model with shape nodes with cuda graph feature enabled + Ort::Session session(*ort_env, TSTR("testdata/cuda_graph_with_shape_nodes.onnx"), session_options); +} + +#endif + #endif TEST(CApiTest, create_tensor) { const char* s[] = {"abc", "kmp"}; - int64_t expected_len = 2; + constexpr int64_t expected_len = 2; auto default_allocator = std::make_unique(); Ort::Value tensor = Ort::Value::CreateTensor(default_allocator.get(), &expected_len, 1, @@ -1829,8 +1935,8 @@ TEST(CApiTest, create_tensor) { Ort::ThrowOnError(Ort::GetApi().FillStringTensor(tensor, s, expected_len)); auto shape_info = tensor.GetTensorTypeAndShapeInfo(); - int64_t len = shape_info.GetElementCount(); - ASSERT_EQ(len, expected_len); + const auto len = shape_info.GetElementCount(); + ASSERT_EQ(len, static_cast(expected_len)); std::vector shape_array(len); size_t data_len = tensor.GetStringTensorDataLength(); @@ -1841,20 +1947,20 @@ TEST(CApiTest, create_tensor) { TEST(CApiTest, fill_string_tensor) { const char* s[] = {"abc", "kmp"}; - int64_t expected_len = 2; + constexpr int64_t expected_len = 2; auto default_allocator = std::make_unique(); Ort::Value tensor = Ort::Value::CreateTensor(default_allocator.get(), &expected_len, 1, ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING); - for (int64_t i = 0; i < expected_len; i++) { + for (size_t i = 0; i < expected_len; i++) { tensor.FillStringTensorElement(s[i], i); } auto shape_info = tensor.GetTensorTypeAndShapeInfo(); - int64_t len = shape_info.GetElementCount(); - ASSERT_EQ(len, expected_len); + const auto len = shape_info.GetElementCount(); + ASSERT_EQ(len, static_cast(expected_len)); } TEST(CApiTest, fill_string_tensor_directly) { @@ -1865,16 +1971,16 @@ TEST(CApiTest, fill_string_tensor_directly) { Ort::Value tensor = Ort::Value::CreateTensor(&default_allocator, &expected_len, 1U, ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING); - for (size_t i = 0; i < static_cast(expected_len); i++) { + for (size_t i = 0; i < expected_len; i++) { auto* buffer = tensor.GetResizedStringTensorElementBuffer(i, s[i].size()); memcpy(buffer, s[i].data(), s[i].size()); } auto shape_info = tensor.GetTensorTypeAndShapeInfo(); - int64_t len = shape_info.GetElementCount(); - ASSERT_EQ(len, expected_len); + const auto len = shape_info.GetElementCount(); + ASSERT_EQ(len, static_cast(expected_len)); - for (size_t i = 0; i < static_cast(expected_len); i++) { + for (size_t i = 0; i < expected_len; i++) { auto element = tensor.GetStringTensorElement(i); ASSERT_EQ(s[i], element); } @@ -1882,8 +1988,8 @@ TEST(CApiTest, fill_string_tensor_directly) { TEST(CApiTest, get_string_tensor_element) { const char* s[] = {"abc", "kmp"}; - int64_t expected_len = 2; - int64_t element_index = 0; + constexpr int64_t expected_len = 2; + constexpr int64_t element_index = 0; auto default_allocator = std::make_unique(); Ort::Value tensor = Ort::Value::CreateTensor(default_allocator.get(), &expected_len, 1, @@ -1925,48 +2031,117 @@ TEST(CApiTest, create_tensor_with_data_float16) { // Example with C++. However, what we are feeding underneath is really // a continuous buffer of uint16_t // Use 3rd party libraries such as Eigen to convert floats and doubles to float16 types. - Ort::Float16_t values[] = {15360, 16384, 16896, 17408, 17664}; // 1.f, 2.f, 3.f, 4.f, 5.f - constexpr size_t values_length = sizeof(values) / sizeof(values[0]); + constexpr float values[] = {1.f, 2.f, 3.f, 4.f, 5.f}; + constexpr size_t values_length = std::size(values); + constexpr uint16_t expected_values[values_length] = {15360, 16384, 16896, 17408, 17664}; - std::vector dims = {static_cast(values_length)}; + std::vector fp16_values; + fp16_values.reserve(values_length); + std::transform(std::begin(values), std::end(values), std::back_inserter(fp16_values), + [](float fl) { return Ort::Float16_t(fl); }); + + for (size_t i = 0; i < values_length; ++i) { + ASSERT_EQ(expected_values[i], fp16_values[i].val); + } + + constexpr int64_t dims = static_cast(values_length); Ort::MemoryInfo info("Cpu", OrtDeviceAllocator, 0, OrtMemTypeDefault); - Ort::Value tensor = Ort::Value::CreateTensor(info, values, values_length, dims.data(), dims.size()); + Ort::Value tensor = Ort::Value::CreateTensor(info, fp16_values.data(), values_length, &dims, 1u); const auto* new_pointer = tensor.GetTensorData(); - ASSERT_EQ(new_pointer, values); + + ASSERT_EQ(new_pointer, fp16_values.data()); auto type_info = tensor.GetTypeInfo(); auto tensor_info = type_info.GetTensorTypeAndShapeInfo(); + const auto element_count = tensor_info.GetElementCount(); + ASSERT_EQ(values_length, element_count); ASSERT_NE(tensor_info, nullptr); ASSERT_EQ(1u, tensor_info.GetDimensionsCount()); ASSERT_EQ(tensor_info.GetElementType(), ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16); - Ort::Float16_t value_at_1 = tensor.At({1}); - ASSERT_EQ(values[1], value_at_1); + const Ort::Float16_t& value_at_1 = tensor.At({1}); + ASSERT_EQ(expected_values[1], value_at_1.val); + + std::vector output_values; + output_values.reserve(values_length); + const auto data_span = gsl::make_span(tensor.GetTensorData(), element_count); + std::transform(data_span.begin(), data_span.end(), std::back_inserter(output_values), + [](const Ort::Float16_t& fp16) { return static_cast(fp16); }); + + for (size_t i = 0; i < values_length; ++i) { + ASSERT_NEAR(values[i], output_values[i], 1e-3); + } } TEST(CApiTest, create_tensor_with_data_bfloat16) { // Example with C++. However, what we are feeding underneath is really // a continuous buffer of uint16_t // Conversion from float to bfloat16 is simple. Strip off half of the bytes from float. - Ort::BFloat16_t values[] = {16256, 16384, 16448, 16512, 16544}; // 1.f, 2.f, 3.f, 4.f, 5.f + constexpr float values[] = {1.f, 2.f, 3.f, 4.f, 5.f}; + constexpr size_t values_length = std::size(values); + constexpr uint16_t expected_values[] = {16256, 16384, 16448, 16512, 16544}; // 1.f, 2.f, 3.f, 4.f, 5.f + + constexpr int64_t dims = static_cast(values_length); + + std::vector b16_values; + b16_values.reserve(values_length); + std::transform(std::begin(values), std::end(values), std::back_inserter(b16_values), + [](float fl) { return Ort::BFloat16_t(fl); }); + + for (size_t i = 0; i < values_length; ++i) { + ASSERT_EQ(expected_values[i], b16_values[i].val); + } + + Ort::MemoryInfo info("Cpu", OrtDeviceAllocator, 0, OrtMemTypeDefault); + + Ort::Value tensor = Ort::Value::CreateTensor(info, b16_values.data(), values_length, &dims, 1u); + const auto* new_pointer = tensor.GetTensorData(); + ASSERT_EQ(new_pointer, b16_values.data()); + auto type_info = tensor.GetTypeInfo(); + const auto tensor_info = type_info.GetTensorTypeAndShapeInfo(); + const auto element_count = tensor_info.GetElementCount(); + ASSERT_NE(tensor_info, nullptr); + ASSERT_EQ(1u, tensor_info.GetDimensionsCount()); + ASSERT_EQ(tensor_info.GetElementType(), ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16); + + const Ort::BFloat16_t& value_at_1 = tensor.At({1}); + ASSERT_EQ(expected_values[1], value_at_1.val); + + std::vector output_values; + output_values.reserve(values_length); + const auto data_span = gsl::make_span(tensor.GetTensorData(), element_count); + std::transform(data_span.begin(), data_span.end(), std::back_inserter(output_values), + [](const Ort::BFloat16_t& b16) { return static_cast(b16); }); + + for (size_t i = 0; i < values_length; ++i) { + ASSERT_NEAR(values[i], output_values[i], 1e-3); + } +} + +#if !defined(DISABLE_FLOAT8_TYPES) + +TEST(CApiTest, create_tensor_with_data_float8) { + Ort::Float8E4M3FN_t values[] = {0, 1, 2, 3, 4}; constexpr size_t values_length = sizeof(values) / sizeof(values[0]); std::vector dims = {static_cast(values_length)}; Ort::MemoryInfo info("Cpu", OrtDeviceAllocator, 0, OrtMemTypeDefault); - Ort::Value tensor = Ort::Value::CreateTensor(info, values, values_length, dims.data(), dims.size()); - const auto* new_pointer = tensor.GetTensorData(); + Ort::Value tensor = Ort::Value::CreateTensor(info, values, values_length, dims.data(), dims.size()); + const auto* new_pointer = tensor.GetTensorData(); ASSERT_EQ(new_pointer, values); auto type_info = tensor.GetTypeInfo(); auto tensor_info = type_info.GetTensorTypeAndShapeInfo(); ASSERT_NE(tensor_info, nullptr); ASSERT_EQ(1u, tensor_info.GetDimensionsCount()); - ASSERT_EQ(tensor_info.GetElementType(), ONNX_TENSOR_ELEMENT_DATA_TYPE_BFLOAT16); + ASSERT_EQ(tensor_info.GetElementType(), ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FN); - Ort::BFloat16_t value_at_1 = tensor.At({1}); + Ort::Float8E4M3FN_t value_at_1 = tensor.At({1}); ASSERT_EQ(values[1], value_at_1); } +#endif + TEST(CApiTest, access_tensor_data_elements) { /** * Create a 2x3 data blob that looks like: @@ -2207,9 +2382,14 @@ TEST(CApiTest, get_available_providers_cpp) { } TEST(CApiTest, get_version_string_cpp) { - std::string version_string = Ort::GetVersionString(); + auto version_string = Ort::GetVersionString(); ASSERT_FALSE(version_string.empty()); - ASSERT_EQ(version_string, ORT_VERSION); + ASSERT_EQ(version_string, std::string(ORT_VERSION)); +} + +TEST(CApiTest, get_build_info_string) { + auto build_info_string = Ort::GetBuildInfoString(); + ASSERT_FALSE(build_info_string.empty()); } TEST(CApiTest, TestSharedAllocators) { @@ -2337,6 +2517,53 @@ TEST(CApiTest, TestSharedAllocators) { // Ensure that there was no leak custom_allocator.LeakCheck(); } +#ifdef USE_CUDA + { + OrtMemoryInfo* cuda_meminfo = nullptr; + ASSERT_TRUE(api.CreateMemoryInfo("Cuda", OrtArenaAllocator, 0, OrtMemTypeDefault, &cuda_meminfo) == nullptr); + std::unique_ptr rel_info(cuda_meminfo, api.ReleaseMemoryInfo); + + OrtArenaCfg* arena_cfg = nullptr; + ASSERT_TRUE(api.CreateArenaCfg(0, -1, -1, -1, &arena_cfg) == nullptr); + std::unique_ptr rel_arena_cfg(arena_cfg, api.ReleaseArenaCfg); + + std::vector keys, values; + ASSERT_TRUE(api.CreateAndRegisterAllocatorV2(env_ptr, onnxruntime::kCudaExecutionProvider, cuda_meminfo, arena_cfg, keys.data(), values.data(), 0) == nullptr); + + // Test that duplicates are handled + std::unique_ptr status_releaser( + api.CreateAndRegisterAllocatorV2(env_ptr, onnxruntime::kCudaExecutionProvider, cuda_meminfo, arena_cfg, keys.data(), values.data(), 0), + api.ReleaseStatus); + ASSERT_FALSE(status_releaser.get() == nullptr); + + { + // create session 1 + Ort::SessionOptions cuda_session_options; + cuda_session_options.AddConfigEntry(kOrtSessionOptionsConfigUseEnvAllocators, "1"); + cuda_session_options.AppendExecutionProvider_CUDA(OrtCUDAProviderOptions{}); + Ort::Session session1(*ort_env, MODEL_URI, cuda_session_options); + RunSession(allocator_for_input_memory_allocation.get(), + session1, + inputs, + "Y", + expected_dims_y, + expected_values_y, + nullptr); + + // create session 2 + Ort::Session session2(*ort_env, MODEL_URI, cuda_session_options); + RunSession(allocator_for_input_memory_allocation.get(), + session2, + inputs, + "Y", + expected_dims_y, + expected_values_y, + nullptr); + } + + ASSERT_TRUE(api.UnregisterAllocator(env_ptr, cuda_meminfo) == nullptr); + } +#endif } TEST(CApiTest, TestSharingOfInitializerAndItsPrepackedVersion) { @@ -2386,7 +2613,7 @@ TEST(CApiTest, TestSharingOfInitializerAndItsPrepackedVersion) { ASSERT_TRUE(model_file_stream.good()); model_file_stream.seekg(0, std::ios::end); - size_t size = model_file_stream.tellg(); + const auto size = onnxruntime::narrow(model_file_stream.tellg()); model_file_stream.seekg(0, std::ios::beg); std::vector file_contents(size, 0); model_file_stream.read(&file_contents[0], size); @@ -2491,8 +2718,8 @@ TEST(CApiTest, ConfigureCudaArenaAndDemonstrateMemoryArenaShrinkage) { Ort::SessionOptions session_options; - const char* keys[] = {"max_mem", "arena_extend_strategy", "initial_chunk_size_bytes", "max_dead_bytes_per_chunk", "initial_growth_chunk_size_bytes"}; - const size_t values[] = {0 /*let ort pick default max memory*/, 0, 1024, 0, 256}; + const char* keys[] = {"max_mem", "arena_extend_strategy", "initial_chunk_size_bytes", "max_dead_bytes_per_chunk", "initial_growth_chunk_size_bytes", "max_power_of_two_extend_bytes"}; + const size_t values[] = {0 /*let ort pick default max memory*/, 0, 1024, 0, 256, 1L << 24}; OrtArenaCfg* arena_cfg = nullptr; ASSERT_TRUE(api.CreateArenaCfgV2(keys, values, 5, &arena_cfg) == nullptr); @@ -2536,12 +2763,21 @@ TEST_P(CApiTensorRTTest, TestConfigureTensorRTProviderOptions) { ASSERT_TRUE(api.CreateTensorRTProviderOptions(&trt_options) == nullptr); std::unique_ptr rel_trt_options(trt_options, api.ReleaseTensorRTProviderOptions); + // Only test updating provider option with user provided compute stream + cudaStream_t compute_stream = nullptr; + void* user_compute_stream = nullptr; + cudaStreamCreateWithFlags(&compute_stream, cudaStreamNonBlocking); + ASSERT_TRUE(api.UpdateTensorRTProviderOptionsWithValue(rel_trt_options.get(), "user_compute_stream", compute_stream) == nullptr); + ASSERT_TRUE(api.GetTensorRTProviderOptionsByName(rel_trt_options.get(), "user_compute_stream", &user_compute_stream) == nullptr); + ASSERT_TRUE(user_compute_stream == (void*)compute_stream); + cudaStreamDestroy(compute_stream); + const char* engine_cache_path = "./trt_engine_folder"; - std::vector keys{"device_id", "trt_fp16_enable", "trt_int8_enable", "trt_engine_cache_enable", + std::vector keys{"device_id", "has_user_compute_stream", "trt_fp16_enable", "trt_int8_enable", "trt_engine_cache_enable", "trt_engine_cache_path", option_name.c_str()}; - std::vector values{"0", "1", "0", "1", + std::vector values{"0", "0", "1", "0", "1", engine_cache_path, option_value.c_str()}; ASSERT_TRUE(api.UpdateTensorRTProviderOptions(rel_trt_options.get(), keys.data(), values.data(), keys.size()) == nullptr); @@ -2595,7 +2831,7 @@ INSTANTIATE_TEST_SUITE_P(CApiTensorRTTest, CApiTensorRTTest, #ifdef USE_CUDA -// This test uses CreateCUDAProviderOptions/UpdateCUDAProviderOptions APIs to configure and create a CUDA Execution Provider instance +// This test uses CreateCUDAProviderOptions/UpdateCUDAProviderOptions/UpdateCUDAProviderOptionsWithValue APIs to configure and create a CUDA Execution Provider instance TEST(CApiTest, TestConfigureCUDAProviderOptions) { const auto& api = Ort::GetApi(); @@ -2603,12 +2839,21 @@ TEST(CApiTest, TestConfigureCUDAProviderOptions) { ASSERT_TRUE(api.CreateCUDAProviderOptions(&cuda_options) == nullptr); std::unique_ptr rel_cuda_options(cuda_options, api.ReleaseCUDAProviderOptions); + // Only test updating OrtCUDAProviderOptionsV2 instance with user provided compute stream not running the inference + cudaStream_t compute_stream = nullptr; + void* user_compute_stream = nullptr; + cudaStreamCreateWithFlags(&compute_stream, cudaStreamNonBlocking); + ASSERT_TRUE(api.UpdateCUDAProviderOptionsWithValue(rel_cuda_options.get(), "user_compute_stream", compute_stream) == nullptr); + ASSERT_TRUE(api.GetCUDAProviderOptionsByName(rel_cuda_options.get(), "user_compute_stream", &user_compute_stream) == nullptr); + ASSERT_TRUE(user_compute_stream == (void*)compute_stream); + cudaStreamDestroy(compute_stream); + std::vector keys{ - "device_id", "gpu_mem_limit", "arena_extend_strategy", + "device_id", "has_user_compute_stream", "gpu_mem_limit", "arena_extend_strategy", "cudnn_conv_algo_search", "do_copy_in_default_stream", "cudnn_conv_use_max_workspace", "cudnn_conv1d_pad_to_nc1d"}; std::vector values{ - "0", "1024", "kSameAsRequested", + "0", "0", "1024", "kSameAsRequested", "DEFAULT", "1", "1"}; ASSERT_TRUE(api.UpdateCUDAProviderOptions(rel_cuda_options.get(), keys.data(), values.data(), 6) == nullptr); @@ -2825,3 +3070,383 @@ TEST(CApiTest, TestMultiStreamInferenceSimpleSSD) { ASSERT_TRUE(output_dims == expected_output_dims); } #endif + +#if !defined(REDUCED_OPS_BUILD) && !defined(DISABLE_OPTIONAL_TYPE) + +TEST(LiteCustomOpTest, CustomFunc) { + Ort::SessionOptions session_options; + session_options.SetIntraOpNumThreads(1); + session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED); + session_options.SetLogSeverityLevel(0); +#if defined(_WIN32) + session_options.RegisterCustomOpsLibrary(ORT_TSTR("custom_op_library.dll")); +#elif defined(__APPLE__) + session_options.RegisterCustomOpsLibrary(ORT_TSTR("libcustom_op_library.dylib")); +#else + session_options.RegisterCustomOpsLibrary(ORT_TSTR("./libcustom_op_library.so")); +#endif + + Ort::Session session{*ort_env, TSTR("testdata/fuse_select_filter.onnx"), session_options}; + + const char* input_names[] = {"vector_1", "vector_2", "alpha", "indices"}; + const char* output_names[] = {"vector_filtered"}; + + float vector_1_value[] = {0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f}; + int64_t vector_1_dim[] = {10}; + + float vector_2_value[] = {0.f, 1.f, 2.f, 3.f, 4.f, 5.f}; + int64_t vector_2_dim[] = {6}; + + int32_t alpha_value[] = {2}; + int64_t alpha_dim[] = {1}; + + int32_t indices_value[] = {0, 1, 2, 3, 4, 5}; + int64_t indices_dim[] = {6}; + + auto memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault); + + Ort::Value input_tensors[] = { + Ort::Value::CreateTensor(memory_info, vector_1_value, 10, vector_1_dim, 1), + Ort::Value::CreateTensor(memory_info, vector_2_value, 6, vector_2_dim, 1), + Ort::Value::CreateTensor(memory_info, alpha_value, 1, alpha_dim, 1), + Ort::Value::CreateTensor(memory_info, indices_value, 6, indices_dim, 1)}; + + Ort::RunOptions run_options; + auto output_tensors = session.Run(run_options, input_names, input_tensors, 4, output_names, 1); + const auto& vector_filterred = output_tensors.at(0); + auto type_shape_info = vector_filterred.GetTensorTypeAndShapeInfo(); + const float* floats_output = static_cast(vector_filterred.GetTensorRawData()); + ASSERT_TRUE(floats_output[0] == 8); + ASSERT_TRUE(floats_output[1] == 16); +} + +struct Merge { + Merge(const OrtApi* ort_api, const OrtKernelInfo* info) { + int64_t reverse; + ORT_ENFORCE(ort_api->KernelInfoGetAttribute_int64(info, "reverse", &reverse) == nullptr); + reverse_ = reverse != 0; + } + void Compute(const Ort::Custom::Tensor& strings_in, + std::string_view string_in, + Ort::Custom::Tensor* strings_out) { + std::vector string_pool; + for (const auto& s : strings_in.Data()) { + string_pool.emplace_back(s.data(), s.size()); + } + string_pool.emplace_back(string_in.data(), string_in.size()); + if (reverse_) { + for (auto& str : string_pool) { + std::reverse(str.begin(), str.end()); + } + std::reverse(string_pool.begin(), string_pool.end()); + } + strings_out->SetStringOutput(string_pool, {static_cast(string_pool.size())}); + } + bool reverse_ = false; +}; + +TEST(LiteCustomOpTest, CustomStruct) { + const auto& ortApi = Ort::GetApi(); + + Ort::CustomOpDomain v2_domain{"v2"}; + std::unique_ptr mrg_op_ptr{Ort::Custom::CreateLiteCustomOp("Merge", "CPUExecutionProvider")}; + v2_domain.Add(mrg_op_ptr.get()); + + Ort::SessionOptions session_options; + session_options.SetIntraOpNumThreads(1); + session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED); + session_options.Add(v2_domain); + session_options.SetLogSeverityLevel(0); + + Ort::Session session{*ort_env, TSTR("testdata/merge.onnx"), session_options}; + + const char* input_names[] = {"str_in_1", "str_in_2"}; + const char* output_names[] = {"str_out"}; + + OrtAllocator* allocator = nullptr; + ASSERT_TRUE(!ortApi.GetAllocatorWithDefaultOptions(&allocator)); + auto memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault); + + int64_t str_1_dims[] = {2}; + int64_t str_2_dims[] = {1}; + + Ort::Value input_tensors[] = {Ort::Value::CreateTensor(allocator, str_1_dims, 1, ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING), + Ort::Value::CreateTensor(allocator, str_2_dims, 1, ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING)}; + + const char* str_1_raw[] = {"abc", "de"}; + const char* str_2_raw[] = {"fg"}; + + input_tensors[0].FillStringTensor(str_1_raw, 2); + input_tensors[1].FillStringTensor(str_2_raw, 1); + + Ort::RunOptions run_options; + auto output_tensors = session.Run(run_options, input_names, input_tensors, 2, output_names, 1); + const auto& str_out_tensor = output_tensors.at(0); + auto num_chars = str_out_tensor.GetStringTensorDataLength(); + std::vector chars(num_chars + 1, '\0'); + std::vector offsets(3); + str_out_tensor.GetStringTensorContent(static_cast(chars.data()), num_chars, offsets.data(), offsets.size()); + ASSERT_TRUE(strncmp(chars.data(), "gfedcba", 7) == 0); +} + +TEST(LiteCustomOpTest, MissingOptional) { + Ort::SessionOptions session_options; + session_options.SetIntraOpNumThreads(1); + session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED); + session_options.SetLogSeverityLevel(0); +#if defined(_WIN32) + session_options.RegisterCustomOpsLibrary(ORT_TSTR("custom_op_library.dll")); +#elif defined(__APPLE__) + session_options.RegisterCustomOpsLibrary(ORT_TSTR("libcustom_op_library.dylib")); +#else + session_options.RegisterCustomOpsLibrary(ORT_TSTR("./libcustom_op_library.so")); +#endif + + Ort::Session session(*ort_env, TSTR("testdata/optional_2.onnx"), session_options); + + const char* input_names[] = {"float_in_1", "float_in_2"}; + const char* output_names[] = {"float_out_1"}; + + float vector_1_value[] = {0.f, 1.f, 2.f}; + int64_t vector_1_dim[] = {3}; + + float vector_2_value[] = {4.f, 5.f, 6.f, 7.f}; + int64_t vector_2_dim[] = {4}; + + auto memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault); + + Ort::Value input_tensors[] = { + Ort::Value::CreateTensor(memory_info, vector_1_value, gsl::narrow_cast(vector_1_dim[0]), + vector_1_dim, 1), + Ort::Value::CreateTensor(memory_info, vector_2_value, gsl::narrow_cast(vector_2_dim[0]), + vector_2_dim, 1)}; + + Ort::RunOptions run_options; + auto output_tensors = session.Run(run_options, input_names, input_tensors, 2, output_names, 1); + ASSERT_TRUE(output_tensors.size() == 1); +} + +TEST(LiteCustomOpTest, HasOptional) { + Ort::SessionOptions session_options; + session_options.SetIntraOpNumThreads(1); + session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED); + session_options.SetLogSeverityLevel(0); +#if defined(_WIN32) + session_options.RegisterCustomOpsLibrary(ORT_TSTR("custom_op_library.dll")); +#elif defined(__APPLE__) + session_options.RegisterCustomOpsLibrary(ORT_TSTR("libcustom_op_library.dylib")); +#else + session_options.RegisterCustomOpsLibrary(ORT_TSTR("./libcustom_op_library.so")); +#endif + + Ort::Session session(*ort_env, TSTR("testdata/optional_3.onnx"), session_options); + + const char* input_names[] = {"float_in_1", "float_in_2", "float_in_3"}; + const char* output_names[] = {"float_out_1", "float_out_2"}; + + float vector_1_value[] = {0.f, 1.f, 2.f}; + int64_t vector_1_dim[] = {3}; + + float vector_2_value[] = {4.f, 5.f, 6.f, 7.f}; + int64_t vector_2_dim[] = {4}; + + float vector_3_value[] = {8.f, 9.f}; + int64_t vector_3_dim[] = {2}; + + auto memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault); + + Ort::Value input_tensors[] = { + Ort::Value::CreateTensor(memory_info, vector_1_value, gsl::narrow_cast(vector_1_dim[0]), + vector_1_dim, 1), + Ort::Value::CreateTensor(memory_info, vector_2_value, gsl::narrow_cast(vector_2_dim[0]), + vector_2_dim, 1), + Ort::Value::CreateTensor(memory_info, vector_3_value, gsl::narrow_cast(vector_3_dim[0]), + vector_3_dim, 1), + }; + + Ort::RunOptions run_options; + auto output_tensors = session.Run(run_options, input_names, input_tensors, 3, output_names, 2); + ASSERT_TRUE(output_tensors.size() == 2); +} + +TEST(MultiKernelSingleSchemaTest, valid) { + Ort::SessionOptions session_options; + session_options.SetIntraOpNumThreads(1); + session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED); + session_options.SetLogSeverityLevel(0); +#if defined(_WIN32) + session_options.RegisterCustomOpsLibrary(ORT_TSTR("custom_op_library.dll")); +#elif defined(__APPLE__) + session_options.RegisterCustomOpsLibrary(ORT_TSTR("libcustom_op_library.dylib")); +#else + session_options.RegisterCustomOpsLibrary(ORT_TSTR("./libcustom_op_library.so")); +#endif + + Ort::Session session(*ort_env, CUSTOM_OP_SINGLE_SCHEMA_MULTI_KERNEL, session_options); + + const char* input_names[] = {"X"}; + const char* output_names[] = {"Y", "Z"}; + float x_value[] = {0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f}; + int64_t x_dim[] = {10}; + auto memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault); + + Ort::Value input_tensors[1] = { + Ort::Value::CreateTensor(memory_info, x_value, 10, x_dim, 1), + }; + + Ort::RunOptions run_options; + auto output_tensors = session.Run(run_options, input_names, input_tensors, 1, output_names, 2); + ASSERT_TRUE(*output_tensors[1].GetTensorData() == 72); +} + +// expect input count mismatch exception +TEST(MultiKernelSingleSchemaTest, InputCountMismatch) { + Ort::CustomOpDomain v2_domain("v2"); + MulTopOpFloat mul_top_f32; + MulTopOpDouble mul_top_double; + + v2_domain.Add(&mul_top_f32); + v2_domain.Add(&mul_top_double); + + Ort::SessionOptions session_options; + session_options.SetIntraOpNumThreads(1); + session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED); + session_options.SetLogSeverityLevel(0); + session_options.Add(v2_domain); + + EXPECT_THROW(Ort::Session session(*ort_env, CUSTOM_OP_SINGLE_SCHEMA_MULTI_KERNEL, session_options), std::exception); +} + +// expect output count mismatch exception +TEST(MultiKernelSingleSchemaTest, OutputMismatch) { + Ort::CustomOpDomain v2_domain("v2"); + MulTopOpFloat mul_top_f32; + MulTopOpInt16 mul_top_int64; + + v2_domain.Add(&mul_top_f32); + v2_domain.Add(&mul_top_int64); + + Ort::SessionOptions session_options; + session_options.SetIntraOpNumThreads(1); + session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED); + session_options.SetLogSeverityLevel(0); + session_options.Add(v2_domain); + + EXPECT_THROW(Ort::Session session(*ort_env, CUSTOM_OP_SINGLE_SCHEMA_MULTI_KERNEL, session_options), std::exception); +} + +// expect characteristic mismatch exception +TEST(MultiKernelSingleSchemaTest, CharacterMismatch) { + Ort::CustomOpDomain v2_domain("v2"); + MulTopOpFloat mul_top_f32; + MulTopOpFloat16 mul_top_f16; + + v2_domain.Add(&mul_top_f32); + v2_domain.Add(&mul_top_f16); + + Ort::SessionOptions session_options; + session_options.SetIntraOpNumThreads(1); + session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED); + session_options.SetLogSeverityLevel(0); + session_options.Add(v2_domain); + + EXPECT_THROW(Ort::Session session(*ort_env, CUSTOM_OP_SINGLE_SCHEMA_MULTI_KERNEL, session_options), std::exception); +} + +TEST(MultiKernelSingleSchemaTest, DuplicateKernel) { + Ort::CustomOpDomain v2_domain("v2"); + MulTopOpFloat mul_top_f32_1; + MulTopOpFloat mul_top_f32_2; + MulTopOpInt32 mul_top_i32; + + v2_domain.Add(&mul_top_f32_1); + v2_domain.Add(&mul_top_f32_2); + v2_domain.Add(&mul_top_i32); + + Ort::SessionOptions session_options; + session_options.SetIntraOpNumThreads(1); + session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED); + session_options.SetLogSeverityLevel(0); + session_options.Add(v2_domain); + + EXPECT_NO_THROW(Ort::Session session(*ort_env, CUSTOM_OP_SINGLE_SCHEMA_MULTI_KERNEL, session_options)); +} + +#endif + +static std::thread::id caller_tid = std::this_thread::get_id(); +static std::atomic_bool atomic_wait{false}; + +void CallbackSucceed(void* user_data, OrtValue** outputs, size_t num_outputs, OrtStatusPtr status_ptr) { + auto callee_tid = std::this_thread::get_id(); + EXPECT_NE(*(reinterpret_cast(user_data)), callee_tid); + Ort::Status status(status_ptr); + EXPECT_TRUE(status.IsOK()); + EXPECT_EQ(num_outputs, 1UL); + Ort::Value output_value(outputs[0]); + EXPECT_EQ(output_value.At({1, 0}), 9.f); + output_value.release(); + atomic_wait.store(true); +} + +TEST(CApiTest, RunAsync) { + Ort::SessionOptions session_options; + session_options.SetIntraOpNumThreads(2); + Ort::Session session(*ort_env, MODEL_URI, session_options); + + const char* input_names[] = {"X"}; + float x_value[] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; + int64_t x_dim[] = {3, 2}; + auto memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault); + + Ort::Value input_tensors[1] = { + Ort::Value::CreateTensor(memory_info, x_value, 6, x_dim, 2), + }; + + const char* output_names[] = {"Y"}; + Ort::RunOptions run_options; + Ort::Value output_values[1] = {Ort::Value{nullptr}}; + + EXPECT_NO_THROW(session.RunAsync(run_options, + input_names, + input_tensors, + 1, + output_names, + output_values, + 1, + CallbackSucceed, + &caller_tid)); + + std::chrono::duration dur{100}; + // timeout in about 10 secs + for (int i = 0; i < 100 && !atomic_wait.load(); ++i) { + std::this_thread::sleep_for(dur); + } + + EXPECT_EQ(atomic_wait.load(), true); +} + +void CallbackFail(void*, OrtValue**, size_t, OrtStatusPtr) { + EXPECT_TRUE(false); // the callback is not supposed to be invoked +} + +TEST(CApiTest, RunAsyncFail) { + Ort::SessionOptions session_options; + session_options.SetIntraOpNumThreads(1); // This will cause RunAsync fail + Ort::Session session(*ort_env, MODEL_URI, session_options); + + const char* input_names[] = {"X"}; + float x_value[] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}; + int64_t x_dim[] = {3, 2}; + + auto memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault); + + Ort::Value input_tensors[1] = { + Ort::Value::CreateTensor(memory_info, x_value, 6, x_dim, 2), + }; + Ort::Value output_values[1] = {Ort::Value{nullptr}}; + const char* output_names[] = {"Y"}; + + Ort::RunOptions run_options; + EXPECT_THROW(session.RunAsync(run_options, input_names, input_tensors, 1, output_names, output_values, 1, CallbackFail, nullptr), std::exception); +} diff --git a/onnxruntime/test/shared_lib/test_model_loading.cc b/onnxruntime/test/shared_lib/test_model_loading.cc index e2e0f7ffb8e92..8ae106bb0c2d2 100644 --- a/onnxruntime/test/shared_lib/test_model_loading.cc +++ b/onnxruntime/test/shared_lib/test_model_loading.cc @@ -3,6 +3,7 @@ #include "core/session/onnxruntime_cxx_api.h" #include "onnxruntime_session_options_config_keys.h" +#include "core/common/narrow.h" #include "test/util/include/asserts.h" #include #include "test_fixture.h" @@ -24,7 +25,7 @@ TEST(CApiTest, model_from_array) { std::ifstream file(model_path, std::ios::binary | std::ios::ate); if (!file) ORT_THROW("Error reading model"); - buffer.resize(file.tellg()); + buffer.resize(narrow(file.tellg())); file.seekg(0, std::ios::beg); if (!file.read(buffer.data(), buffer.size())) ORT_THROW("Error reading model"); diff --git a/onnxruntime/test/shared_lib/test_nontensor_types.cc b/onnxruntime/test/shared_lib/test_nontensor_types.cc index a431c42bb9294..e8160d1619cb3 100644 --- a/onnxruntime/test/shared_lib/test_nontensor_types.cc +++ b/onnxruntime/test/shared_lib/test_nontensor_types.cc @@ -307,6 +307,323 @@ TEST(CApiTest, TypeInfoSequence) { ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64); } +TEST(CPPApi, ConvertFloatToFloat16) { + // Test data type + { + constexpr float sample = 1.0f; + Ort::Float16_t flt16(sample); + EXPECT_FALSE(flt16.IsNaN()); + auto int_rep = flt16.val; + const Ort::Float16_t flt_from_int = Ort::Float16_t::FromBits(int_rep); + EXPECT_FALSE(flt_from_int.IsNaN()); + EXPECT_EQ(flt16, flt_from_int); + const double diff = std::fabs(sample - flt_from_int.ToFloat()); + if (diff > FLT_EPSILON || (std::isnan(diff) && !std::isnan(sample))) { + EXPECT_TRUE(false); + } + } + // Test bulk conversion + { + const float sample[] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f}; + std::vector converted; + converted.reserve(std::size(sample)); + + // Run conversion + std::transform(std::begin(sample), std::end(sample), std::back_inserter(converted), + [](float v) { return Ort::Float16_t(v); }); + + for (size_t i = 0; i < std::size(sample); ++i) { + EXPECT_FALSE(converted[i].IsNaN()); + const double diff = std::fabs(sample[i] - converted[i].ToFloat()); + if ((std::isnan(diff) && !std::isnan(sample[i])) || diff > FLT_EPSILON) { + EXPECT_TRUE(false); + } + } + + std::vector back_converted; + back_converted.reserve(std::size(sample)); + std::transform(converted.cbegin(), converted.cend(), std::back_inserter(back_converted), + [](const Ort::Float16_t& bf) { return static_cast(bf); }); + + for (size_t i = 0; i < std::size(sample); ++i) { + EXPECT_FALSE(std::isnan(back_converted[i])); + const double diff = std::fabs(sample[i] - back_converted[i]); + if ((std::isnan(diff) && !std::isnan(sample[i])) || diff > FLT_EPSILON) { + EXPECT_TRUE(false); + } + } + } +} + +TEST(CPPApi, Float16Zeros) { + const auto positive_zero = Ort::Float16_t::FromBits(0x0000); + EXPECT_FALSE(positive_zero.IsNegative()); + const float float_positive_zero = static_cast(positive_zero); + EXPECT_EQ(+0.0f, float_positive_zero); + EXPECT_FALSE(std::signbit(float_positive_zero)); + + const auto negative_zero = Ort::Float16_t::FromBits(0x8000); + EXPECT_TRUE(negative_zero.IsNegative()); + const float float_positive_negzero = static_cast(negative_zero); + EXPECT_EQ(-0.0f, float_positive_negzero); + EXPECT_TRUE(std::signbit(float_positive_negzero)); +} + +namespace { +const auto EpsilonFl16 = Ort::Float16_t::FromBits(Ort::Float16_t::kEpsilonBits); +const auto NaNFl16 = Ort::Float16_t::FromBits(Ort::Float16_t::kPositiveQNaNBits); +const auto MinValueFl16 = Ort::Float16_t::FromBits(Ort::Float16_t::kMinValueBits); +const auto MaxValueFl16 = Ort::Float16_t::FromBits(Ort::Float16_t::kMaxValueBits); +const auto InfinityFl16 = Ort::Float16_t::FromBits(Ort::Float16_t::kPositiveInfinityBits); +} // namespace + +TEST(CPPApi, Float16Comparision) { + const auto left = Ort::Float16_t(-33.33f); + const auto left_same = Ort::Float16_t(-33.33f); + const auto right = Ort::Float16_t(66.66f); + const auto right_same = Ort::Float16_t(66.66f); + + EXPECT_LT(EpsilonFl16, right); + + EXPECT_EQ(left, left_same); + EXPECT_NE(left, left_same.Negate()); + + EXPECT_EQ(right, right_same); + EXPECT_NE(right, right_same.Negate()); + + EXPECT_LT(left, right); + EXPECT_LT(right.Negate(), left); + EXPECT_LT(left.Negate(), right); +} + +TEST(CPPApi, Float16TestNAN) { + const Ort::Float16_t fp16NANFromSingle(std::numeric_limits::quiet_NaN()); + EXPECT_TRUE(fp16NANFromSingle.IsNaN()); + + // NaN are not equal to each other + EXPECT_NE(NaNFl16, fp16NANFromSingle); + + const float NanFromBFloat16 = fp16NANFromSingle.ToFloat(); + EXPECT_TRUE(std::isnan(NanFromBFloat16)); + + EXPECT_FALSE(MaxValueFl16.IsNaN()); +} + +TEST(CPPApi, Float16NaNComparision) { + EXPECT_FALSE(NaNFl16 < NaNFl16); + EXPECT_TRUE(NaNFl16 != NaNFl16); + EXPECT_FALSE(NaNFl16 == NaNFl16); + + EXPECT_FALSE(MaxValueFl16 < NaNFl16); + EXPECT_FALSE(MaxValueFl16 == NaNFl16); + EXPECT_FALSE(NaNFl16 < MinValueFl16); + + EXPECT_LT(MinValueFl16, MaxValueFl16); +} + +TEST(CPPApi, Float16Infinity) { + EXPECT_FALSE(MinValueFl16.IsInfinity()); + EXPECT_FALSE(MaxValueFl16.IsInfinity()); + EXPECT_TRUE(MaxValueFl16.IsFinite()); + + const Ort::Float16_t pos_infinity_from_float(std::numeric_limits::infinity()); + EXPECT_TRUE(pos_infinity_from_float.IsInfinity()); + EXPECT_FALSE(pos_infinity_from_float.IsFinite()); + EXPECT_FALSE(pos_infinity_from_float.IsNegative()); + + const Ort::Float16_t neg_infinity_from_float(-std::numeric_limits::infinity()); + EXPECT_TRUE(neg_infinity_from_float.IsInfinity()); + EXPECT_FALSE(neg_infinity_from_float.IsFinite()); + EXPECT_TRUE(neg_infinity_from_float.IsNegative()); + + const float pos_infinity_from_bfloat16 = static_cast(InfinityFl16); + EXPECT_TRUE(std::isinf(pos_infinity_from_bfloat16)); +} + +TEST(CPPApi, Float16NormalSubnormal) { + EXPECT_FALSE(InfinityFl16.IsNormal()); + EXPECT_TRUE(Ort::Float16_t(45.6f).IsNormal()); + EXPECT_FALSE(Ort::Float16_t(45.6f).IsSubnormal()); + + // 0b0_0000_0000_000_0001 ~0.000000059604645 + constexpr uint16_t min_subnormal_bits = 0x0001; + const Ort::Float16_t smallest_subnormal = Ort::Float16_t::FromBits(min_subnormal_bits); + EXPECT_TRUE(smallest_subnormal.IsSubnormal()); + EXPECT_FALSE(smallest_subnormal.IsNormal()); + + // float smallest positive subnormal is ~1.40129846432481707092E-45, and + // in float the same number above would be normal + const float float_from_smallest_subnormal = static_cast(smallest_subnormal); + EXPECT_TRUE(std::isnormal(float_from_smallest_subnormal)); + + // 0b0_0000_0000_111_1111; ~0.000060975552 + constexpr uint16_t max_subnormal_bits = 0x007F; + const Ort::Float16_t largest_subnormal = Ort::Float16_t::FromBits(max_subnormal_bits); + EXPECT_TRUE(largest_subnormal.IsSubnormal()); + EXPECT_FALSE(largest_subnormal.IsNormal()); + + // However, in float the same number above would be normal + const float float_from_largest_subnormal = static_cast(largest_subnormal); + EXPECT_TRUE(std::isnormal(float_from_largest_subnormal)); +} + +TEST(CPPApi, BFloat16ConvertFloatToBFloat16) { + // Test data type + { + constexpr float sample = 1.0f; + Ort::BFloat16_t flt16(sample); + EXPECT_FALSE(flt16.IsNaN()); + auto int_rep = flt16.val; + const Ort::BFloat16_t flt_from_int = Ort::BFloat16_t::FromBits(int_rep); + EXPECT_FALSE(flt_from_int.IsNaN()); + EXPECT_EQ(flt16, flt_from_int); + const double diff = std::fabs(sample - flt_from_int.ToFloat()); + if (diff > FLT_EPSILON || (std::isnan(diff) && !std::isnan(sample))) { + EXPECT_TRUE(false); + } + } + // Test bulk conversion + { + const float sample[] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f}; + std::vector converted; + converted.reserve(std::size(sample)); + + // Run conversion + std::transform(std::begin(sample), std::end(sample), std::back_inserter(converted), + [](float v) { return Ort::BFloat16_t(v); }); + + for (size_t i = 0; i < std::size(sample); ++i) { + EXPECT_FALSE(converted[i].IsNaN()); + const double diff = std::fabs(sample[i] - converted[i].ToFloat()); + if ((std::isnan(diff) && !std::isnan(sample[i])) || diff > FLT_EPSILON) { + EXPECT_TRUE(false); + } + } + + std::vector back_converted; + back_converted.reserve(std::size(sample)); + std::transform(converted.cbegin(), converted.cend(), std::back_inserter(back_converted), + [](const Ort::BFloat16_t& bf) { return static_cast(bf); }); + + for (size_t i = 0; i < std::size(sample); ++i) { + EXPECT_FALSE(std::isnan(back_converted[i])); + const double diff = std::fabs(sample[i] - back_converted[i]); + if ((std::isnan(diff) && !std::isnan(sample[i])) || diff > FLT_EPSILON) { + EXPECT_TRUE(false); + } + } + } +} + +TEST(CPPApi, BFloat16Zeros) { + const auto positive_zero = Ort::BFloat16_t::FromBits(0x0000); + EXPECT_FALSE(positive_zero.IsNegative()); + const float float_positive_zero = static_cast(positive_zero); + EXPECT_EQ(+0.0f, float_positive_zero); + EXPECT_FALSE(std::signbit(float_positive_zero)); + + const auto negative_zero = Ort::BFloat16_t::FromBits(0x8000); + EXPECT_TRUE(negative_zero.IsNegative()); + const float float_positive_negzero = static_cast(negative_zero); + EXPECT_EQ(-0.0f, float_positive_negzero); + EXPECT_TRUE(std::signbit(float_positive_negzero)); +} + +namespace { +const auto EpsilonBfl16 = Ort::BFloat16_t::FromBits(Ort::BFloat16_t::kEpsilonBits); +const auto NaNBfl15 = Ort::BFloat16_t::FromBits(Ort::BFloat16_t::kPositiveQNaNBits); +const auto MinValueBfl16 = Ort::BFloat16_t::FromBits(Ort::BFloat16_t::kMinValueBits); +const auto MaxValueBfl16 = Ort::BFloat16_t::FromBits(Ort::BFloat16_t::kMaxValueBits); +const auto InfinityBFl16 = Ort::BFloat16_t::FromBits(Ort::BFloat16_t::kPositiveInfinityBits); +} // namespace + +TEST(CPPApi, BFloat16Comparision) { + const auto left = Ort::BFloat16_t(-33.33f); + const auto left_same = Ort::BFloat16_t(-33.33f); + const auto right = Ort::BFloat16_t(66.66f); + const auto right_same = Ort::BFloat16_t(66.66f); + + EXPECT_LT(EpsilonBfl16, right); + + EXPECT_EQ(left, left_same); + EXPECT_NE(left, left_same.Negate()); + + EXPECT_EQ(right, right_same); + EXPECT_NE(right, right_same.Negate()); + + EXPECT_LT(left, right); + EXPECT_LT(right.Negate(), left); + EXPECT_LT(left.Negate(), right); +} + +TEST(CPPApi, BFloat16TestNAN) { + const Ort::BFloat16_t fp16NANFromSingle(std::numeric_limits::quiet_NaN()); + EXPECT_TRUE(fp16NANFromSingle.IsNaN()); + + // NaN are not equal to each other + EXPECT_NE(NaNBfl15, fp16NANFromSingle); + + const float NanFromBFloat16 = fp16NANFromSingle.ToFloat(); + EXPECT_TRUE(std::isnan(NanFromBFloat16)); + + EXPECT_FALSE(MaxValueBfl16.IsNaN()); +} + +TEST(CPPApi, BFloat16NaNComparision) { + EXPECT_FALSE(NaNBfl15 < NaNBfl15); + EXPECT_TRUE(NaNBfl15 != NaNBfl15); + EXPECT_FALSE(NaNBfl15 == NaNBfl15); + + EXPECT_FALSE(MaxValueBfl16 < NaNBfl15); + EXPECT_FALSE(MaxValueBfl16 == NaNBfl15); + EXPECT_FALSE(NaNBfl15 < MinValueBfl16); + + EXPECT_LT(MinValueBfl16, MaxValueBfl16); +} + +TEST(CPPApi, BFloat16Infinity) { + EXPECT_FALSE(MinValueBfl16.IsInfinity()); + EXPECT_FALSE(MaxValueBfl16.IsInfinity()); + EXPECT_TRUE(MaxValueBfl16.IsFinite()); + + const Ort::BFloat16_t pos_infinity_from_float(std::numeric_limits::infinity()); + EXPECT_TRUE(pos_infinity_from_float.IsInfinity()); + EXPECT_FALSE(pos_infinity_from_float.IsFinite()); + EXPECT_FALSE(pos_infinity_from_float.IsNegative()); + + const Ort::BFloat16_t neg_infinity_from_float(-std::numeric_limits::infinity()); + EXPECT_TRUE(neg_infinity_from_float.IsInfinity()); + EXPECT_FALSE(neg_infinity_from_float.IsFinite()); + EXPECT_TRUE(neg_infinity_from_float.IsNegative()); + + const float pos_infinity_from_bfloat16 = static_cast(InfinityBFl16); + EXPECT_TRUE(std::isinf(pos_infinity_from_bfloat16)); +} + +TEST(CPPApi, BFloat16NormalSubnormal) { + EXPECT_FALSE(InfinityBFl16.IsNormal()); + EXPECT_TRUE(Ort::BFloat16_t(45.6f).IsNormal()); + EXPECT_FALSE(Ort::BFloat16_t(45.6f).IsSubnormal()); + + // 0b0_0000_0000_000_0001 + constexpr uint16_t min_subnormal_bits = 0x0001; + const Ort::BFloat16_t smallest_subnormal = Ort::BFloat16_t::FromBits(min_subnormal_bits); + EXPECT_TRUE(smallest_subnormal.IsSubnormal()); + EXPECT_FALSE(smallest_subnormal.IsNormal()); + + const float float_from_smallest_subnormal = static_cast(smallest_subnormal); + EXPECT_FALSE(std::isnormal(float_from_smallest_subnormal)); + + // 0b0_0000_0000_111_1111; + constexpr uint16_t max_subnormal_bits = 0x007F; + const Ort::BFloat16_t largest_subnormal = Ort::BFloat16_t::FromBits(max_subnormal_bits); + EXPECT_TRUE(largest_subnormal.IsSubnormal()); + EXPECT_FALSE(largest_subnormal.IsNormal()); + + const float float_from_largest_subnormal = static_cast(largest_subnormal); + EXPECT_FALSE(std::isnormal(float_from_largest_subnormal)); +} + #if !defined(DISABLE_SPARSE_TENSORS) TEST(CApiTest, SparseTensorUsingAPI) { Ort::MemoryInfo info("Cpu", OrtDeviceAllocator, 0, OrtMemTypeDefault); @@ -351,7 +668,7 @@ TEST(CApiTest, SparseTensorUsingAPI) { { const auto* values = coo_st.GetSparseTensorValues(); - auto val_span = gsl::make_span(values, values_shape[0]); + auto val_span = gsl::make_span(values, gsl::narrow_cast(values_shape[0])); ASSERT_TRUE(std::equal(expected_values.cbegin(), expected_values.cend(), val_span.begin(), val_span.end())); } @@ -537,7 +854,7 @@ TEST(CApiTest, SparseTensorFillSparseTensorFormatAPI) { { const auto* values = coo_st.GetSparseTensorValues(); - auto val_span = gsl::make_span(values, values_shape[0]); + auto val_span = gsl::make_span(values, gsl::narrow_cast(values_shape[0])); ASSERT_TRUE(std::equal(expected_values.cbegin(), expected_values.cend(), val_span.begin(), val_span.end())); } @@ -811,7 +1128,7 @@ TEST(CApiTest, SparseTensorFillSparseFormatStringsAPI) { /// XXX: Do something about this API. /// Need to add N + 1 terminating offset, or skip the first zero offset /// altogether and add the N + 1 - csr_st.GetStringTensorContent(buffer.get(), data_len, offsets.get(), values_len); + csr_st.GetStringTensorContent(buffer.get(), data_len, offsets.get(), gsl::narrow_cast(values_len)); for (size_t i = 0, limit = expected_values.size(); i < limit; ++i) { const auto& ex = expected_values[i]; const char* p = &buffer[offsets[i]]; diff --git a/onnxruntime/test/testdata/attention/attention_test_data.txt b/onnxruntime/test/testdata/attention/attention_test_data.txt new file mode 100644 index 0000000000000..e32d87b4a4ce1 --- /dev/null +++ b/onnxruntime/test/testdata/attention/attention_test_data.txt @@ -0,0 +1,4996 @@ +name:Weight_64_3_64.weight_data +-0.004707,-0.006775,0.0009236,0.003067,-0.00806,0.00779,0.0004425,0.00846,0.00048, +0.00999,0.00115,0.00226,-0.00705,0.004467,0.001455,-0.006073,0.00465,-0.00861, +-0.002779,0.00883,-0.002996,0.008354,-0.003141,-0.007374,0.001634,-0.009544,0.00198, +0.005894,0.001434,0.001589,0.00921,-0.00507,0.00448,0.0002687,-0.003147,0.001627, +-0.005608,0.006516,0.00935,-0.004715,0.00833,-0.00563,0.00281,-0.005875,0.000629, +0.00993,-0.002695,0.004486,-0.00528,-0.003807,0.00521,0.00010276,0.003307,0.000701, +0.0001151,0.00649,0.00934,-0.001063,0.002327,-0.0002892,0.003317,-0.003506,0.004875, +0.0006566,0.000953,-0.005898,0.00326,0.00877,0.00923,-0.00622,-0.006588,0.007748, +-0.001789,0.00002104,0.002937,0.00816,0.005833,-0.006634,0.006985,0.00951,0.002947, +0.001871,-0.009445,0.0004554,-0.006294,-0.00649,0.00917,-0.004158,-0.00462,-0.001531, +-0.00658,-0.00364,-0.00462,0.003723,0.009636,0.003305,-0.00984,0.006126,-0.0010395, +-0.00852,0.006287,-0.002949,-0.004,-0.002415,0.0009527,0.001624,0.00364,0.007088, +-0.00717,-0.009224,-0.00997,0.001726,-0.00877,-0.000602,0.0089,0.009026,-0.009514, +0.00852,0.0003986,-0.006855,-0.00583,0.003622,-0.00526,0.001879,-0.007053,0.00006664, +0.00972,-0.000457,-0.00759,-0.007107,0.002337,-0.004204,-0.005676,0.00985,0.00978, +-0.004486,0.005093,-0.009285,0.004093,-0.00682,0.00963,-0.006954,-0.003674,-0.003822, +0.00202,-0.004635,-0.0009174,-0.001202,0.00639,-0.004356,-0.00741,-0.00586,-0.00319, +-0.002506,0.005047,0.007156,-0.00765,0.00702,0.007477,0.000626,-0.001587,-0.005455, +0.005814,-0.002127,0.00834,0.001279,0.007996,-0.005787,-0.006924,-0.004063,-0.00435, +-0.00427,0.0002115,0.00981,-0.00138,-0.007965,-0.004536,-0.003431,0.00416,0.005894, +0.006054,0.00907,0.00388,-0.006763,0.001692,-0.00797,-0.00691,0.00798,0.00867, +-0.00788,0.002062,-0.003761,0.009834,-0.002445,-0.00613,0.0096,-0.005466,-0.0008426, +0.0002431,-0.009995,0.003736,-0.0071,-0.003593,0.006386,0.005997,-0.003328,0.007515, +-0.008675,0.00547,-0.00388,0.00473,0.00362,-0.00469,0.006958,-0.001264,-0.003887, +-0.004276,-0.000396,0.00453,-0.00465,-0.007343,-0.005787,-0.00927,-0.006058,-0.004566, +-0.009056,-0.00891,0.007633,0.001098,-0.003368,-0.007214,-0.00905,-0.00898,-0.008736, +-0.00948,0.003162,0.004402,-0.006245,-0.00515,-0.00378,-0.003248,-0.00304,0.001834, +-0.002672,0.005234,-0.007706,0.0084,0.00832,-0.00904,-0.00596,0.009926,-0.00869, +0.001513,0.00728,0.001057,0.001452,0.00785,0.001203,-0.004528,0.006573,0.003656, +0.005966,-0.006985,0.002844,0.00883,0.0004826,0.003279,0.006916,0.00263,-0.002415, +-0.001928,-0.0004041,-0.004593,-0.00204,0.007965,-0.008224,-0.00591,-0.002144,0.000688, +0.001676,-0.00949,-0.003304,-0.007637,0.00973,-0.008224,-0.001211,-0.003345,0.002115, +-0.00615,-0.004955,-0.00803,0.00807,-0.0006227,0.00845,-0.006916,0.004353,-0.000934, +0.005604,-0.00825,-0.004402,-0.00441,0.00257,-0.008415,0.006542,0.001357,-0.004974, +-0.00993,0.0001058,0.002855,-0.0081,0.001513,-0.00191,0.0004003,0.003874,-0.0015545, +-0.00736,0.006718,0.005135,0.003859,-0.0054,0.00993,0.000952,0.00228,0.001163, +0.00918,0.00582,0.00308,0.008415,0.00889,0.00011665,-0.007362,-0.009926,-0.00784, +0.005817,-0.002918,0.005043,-0.003029,0.0085,-0.007362,-0.00857,0.006832,-0.00055, +0.008835,-0.00522,-0.002085,0.00353,-0.007706,0.006283,0.004414,-0.002405,-0.003002, +-0.00946,-0.001164,-0.004177,0.00834,-0.001576,0.00855,0.004025,0.000285,-0.004486, +-0.00703,-0.003061,0.003452,0.001276,0.008446,-0.001302,0.004333,-0.00898,-0.002445, +-0.006523,0.0004334,-0.003206,-0.00349,-0.005497,-0.007786,0.007397,0.00925,0.002077, +0.004074,0.006626,-0.001693,-0.0005975,-0.005074,0.00324,0.00925,-0.009735,-0.007133, +-0.0064,-0.00455,-0.003153,0.0056,-0.006073,-0.00274,-0.00587,-0.005066,0.003595, +-0.00932,-0.005,0.00569,0.008415,0.006866,0.003952,-0.009285,-0.008064,0.00824, +0.0000188,-0.001233,0.005726,-0.0007806,-0.008385,-0.001798,-0.008095,0.00986,0.006924, +0.00712,-0.00964,-0.00797,0.00943,-0.007416,0.007904,0.006893,0.00799,-0.007164, +0.007214,0.00931,0.000645,-0.0058,0.009254,-0.002079,0.000969,0.009636,-0.002365, +-0.002348,0.007053,-0.002796,-0.007652,-0.001554,0.00402,-0.002838,-0.006958,0.000331, +0.006435,-0.004036,0.007595,0.00812,0.00637,0.007732,-0.006916,0.003952,-0.008064, +-0.00928,0.00468,-0.000512,-0.006287,0.00607,-0.001904,-0.00458,0.003412,0.000382, +-0.00822,-0.00486,0.0008364,0.0004992,0.003582,0.0088,0.002453,-0.00856,0.00886, +0.0077,0.0004592,-0.001417,-0.005142,0.004696,-0.003576,0.004807,-0.00851,-0.006245, +-0.003649,-0.0001528,0.004017,-0.006123,-0.004158,-0.00445,0.004864,-0.0005493,0.00399, +-0.007244,0.003246,0.00407,0.00929,-0.006706,0.0084,-0.003496,0.00843,0.00514, +0.002714,-0.0001633,-0.00866,0.004837,-0.003016,0.00593,-0.00849,0.001287,-0.007706, +0.001479,-0.002241,0.00843,-0.001236,-0.007572,-0.004448,-0.001927,0.001139,0.004982, +-0.00673,-0.000568,0.009346,0.000487,0.001392,-0.009605,0.00944,0.002022,0.00617, +0.00472,0.009575,-0.006416,0.004265,0.002005,0.000578,0.002592,0.002707,-0.005333, +-0.00928,-0.00935,-0.00833,-0.00205,-0.005795,-0.001061,-0.003605,0.003078,0.00592, +0.0006485,-0.00504,0.002682,0.00826,-0.003983,-0.00493,0.00406,-0.00838,0.0032, +0.0009565,0.00471,0.00504,0.004612,-0.002768,0.00791,-0.002892,0.00471,0.00588, +0.005978,-0.005203,-0.009995,0.009346,-0.00802,0.003807,0.001364,-0.00736,0.009285, +-0.001995,0.002632,-0.00904,0.007042,-0.00326,0.006516,0.00492,0.00734,-0.00867, +-0.002512,-0.003729,0.0027,-0.002659,-0.009514,-0.005634,-0.001473,-0.00545,0.003551, +0.001995,-0.003704,0.006386,0.003313,-0.002823,0.00105,0.00993,0.00951,-0.007275, +-0.002213,-0.003418,0.00599,0.00948,0.007572,-0.00944,-0.00924,0.00011665,0.0069, +-0.00544,0.007515,-0.006832,-0.007774,0.00853,-0.0007486,-0.00643,-0.0001878,-0.00849, +-0.007603,0.0016985,-0.00986,0.003975,-0.002176,-0.009796,0.004795,-0.00699,-0.006725, +0.00109,0.004498,-0.00569,-0.00584,0.004047,-0.001022,0.001479,-0.00751,-0.002579, +-0.004086,0.007603,-0.0000106,0.007366,0.0029,-0.003498,0.007385,-0.00759,-0.005886, +0.00476,-0.0003812,-0.00008225,0.00998,0.002716,-0.00925,-0.00439,-0.000902,-0.00296, +-0.007347,-0.005882,-0.001428,-0.002855,-0.003311,-0.000793,-0.00403,-0.00829,-0.00999, +-0.00838,0.008804,0.004124,-0.005882,0.001305,0.00511,0.00799,-0.00953,-0.008575, +-0.00556,-0.00858,0.00565,0.00908,0.00591,0.0007925,-0.00912,-0.005894,-0.002588, +-0.00957,-0.00682,0.002174,0.00706,0.00528,0.0069,-0.004517,-0.002382,0.005596, +0.00645,0.00956,0.00796,0.007706,0.004818,0.002308,0.001367,-0.004177,0.00842, +0.007416,-0.00404,-0.009094,0.00447,-0.00284,-0.002499,-0.0001582,0.001681,0.004993, +-0.0059,0.007282,-0.00809,0.00927,0.004948,0.009766,-0.00618,-0.001559,-0.00461, +0.001866,0.00827,-0.00785,-0.003101,0.00977,-0.00444,-0.00916,-0.0008535,0.004913, +0.005627,0.007965,0.000532,-0.00878,0.004047,-0.005302,0.00201,0.002964,-0.00895, +0.005768,0.00388,0.007526,-0.00783,0.003794,0.005363,0.003454,-0.002235,-0.003494, +-0.001541,-0.00003624,-0.0007634,-0.0014,-0.003124,0.00829,-0.00298,-0.00868,-0.001243, +-0.005383,-0.009964,0.004433,-0.002045,-0.00753,0.002361,-0.007473,-0.002419,-0.000931, +0.00585,0.007114,-0.002247,0.00472,-0.003033,-0.001974,0.001622,-0.007473,-0.005375, +-0.005013,0.00436,0.00662,-0.0053,0.000606,-0.00849,-0.007004,0.006794,-0.0005445, +-0.001269,0.00391,0.006294,0.007088,-0.009026,-0.001965,-0.008545,0.002115,0.003534, +-0.00857,0.00412,-0.00722,-0.006386,0.00595,-0.003778,-0.00886,-0.0002267,0.00249, +-0.002825,0.0003204,0.0002894,-0.004147,-0.003632,0.001764,-0.002983,0.006584,-0.004402, +0.006493,0.002014,-0.0061,0.00816,0.005585,-0.008125,0.006546,-0.00956,0.004185, +0.001067,0.001277,0.007835,-0.003933,0.00979,-0.003376,0.006573,-0.00501,0.0007577, +0.00133,-0.00737,0.00885,-0.00599,-0.001151,-0.001389,-0.00987,-0.003214,-0.00649, +0.005424,0.0004575,0.002352,0.005722,-0.001995,-0.007717,0.001034,-0.006557,0.0088, +-0.003183,-0.00663,0.00634,-0.003008,-0.004925,0.00539,-0.00432,-0.00651,0.009895, +0.00532,-0.0003607,0.003397,0.006145,0.00531,-0.006275,0.00985,-0.00471,0.00817, +-0.00927,0.007217,0.005924,0.003187,0.001192,-0.003986,-0.0000217,-0.0012245,-0.003933, +-0.00617,-0.002232,0.00444,0.002008,0.0006056,-0.002827,-0.007366,0.002996,-0.006752, +-0.004143,0.001662,-0.00793,0.002161,0.0001992,0.00803,-0.0000725,0.001066,0.004745, +-0.005367,-0.00641,0.00431,-0.004715,0.008575,-0.007202,0.003786,-0.00247,0.006382, +-0.006832,0.00505,-0.001084,0.009674,0.00458,-0.00473,-0.00656,-0.00011283,0.004417, +-0.001419,-0.0005164,0.0000397,-0.00395,0.00417,-0.005512,0.0088,0.00568,-0.0005984, +0.003128,-0.006283,-0.0000904,-0.004738,0.00687,0.00592,-0.005768,-0.00859,0.003523, +0.001169,-0.004498,0.00541,0.002956,0.00896,-0.002571,0.0006533,0.002089,-0.00473, +-0.002241,0.005016,0.001295,0.005993,-0.008064,0.000595,-0.007744,-0.00201,0.0075, +-0.00942,0.0002023,-0.00979,-0.002243,0.002829,-0.004322,0.009125,0.00704,0.007282, +0.00807,0.005447,0.00518,-0.0010195,-0.004803,-0.001293,-0.001305,0.00975,-0.00564, +-0.005215,-0.009445,0.00999,0.00959,-0.009224,-0.0053,-0.002106,-0.00839,0.001516, +0.003109,0.004414,-0.00921,-0.00868,0.00833,0.00809,0.004654,0.00678,0.002237, +0.007195,-0.004875,-0.001252,0.0073,0.007275,0.00825,-0.005936,0.00594,-0.00381, +-0.002117,0.009,-0.003998,-0.00104,-0.00421,0.00526,0.001031,0.00902,0.006794, +-0.00912,-0.0002892,0.002966,0.00478,0.00581,0.007217,0.008156,-0.0000639,-0.003164, +0.00859,-0.00897,0.00409,0.0008936,-0.00991,-0.008316,-0.004055,0.001252,-0.00473, +-0.002,-0.003933,0.000755,-0.00992,0.003569,-0.00812,-0.004215,-0.00774,0.00907, +0.00653,-0.00992,-0.006252,-0.00468,-0.001105,-0.007717,0.005302,0.003773,-0.001262, +-0.006207,-0.005707,0.0053,0.00415,0.002441,0.0009265,-0.006744,0.00994,-0.0004816, +-0.002108,-0.003267,0.0000461,0.004364,-0.00596,-0.008675,0.005703,0.002748,0.00961, +0.006767,-0.0000575,-0.00845,-0.003597,0.003616,0.00423,0.009705,-0.00976,-0.0085, +0.00307,-0.004032,-0.00784,-0.00901,-0.00873,0.00543,0.00744,-0.006588,-0.004765, +-0.007202,0.006306,-0.007484,0.007442,-0.00008386,0.006374,0.00879,0.002039,-0.003298, +0.003407,0.004673,0.0068,0.0001981,0.002296,0.008194,-0.00805,-0.007637,-0.00903, +-0.004025,0.001553,0.00881,0.001311,-0.005016,-0.006916,-0.009926,-0.00801,0.00945, +0.0001532,0.00234,-0.002968,-0.002174,0.004585,-0.00658,0.000132,0.0004494,-0.00954, +-0.00848,0.009964,-0.0006323,-0.005016,0.001238,0.00433,0.001477,0.00578,0.00794, +-0.00512,-0.00207,-0.00145,-0.001166,0.008644,-0.00915,0.007187,-0.00415,0.006035, +-0.004177,0.00817,-0.00432,0.001062,-0.005272,-0.0004163,0.005154,0.005688,-0.002985, +-0.004,-0.003176,0.00137,0.0002158,0.003798,0.0002009,-0.01,0.00311,-0.004234, +0.00681,-0.005657,-0.00963,0.00916,0.00847,-0.002085,-0.00211,0.006813,-0.00473, +0.00873,0.0008483,0.004253,0.00865,-0.007156,-0.00996,0.005413,-0.004253,0.00847, +0.004482,0.000647,-0.006702,0.00845,-0.009254,-0.0001926,0.003868,-0.00788,0.00951, +-0.0005136,-0.007698,0.00889,-0.00953,0.007965,0.004982,-0.004345,0.00841,0.007034, +0.006092,0.004166,0.00682,-0.004635,0.003433,-0.006527,-0.0002658,0.005455,0.001926, +-0.003582,-0.0065,0.002348,-0.001918,-0.00488,-0.006416,-0.000873,-0.00942,0.005177, +-0.00194,0.006374,0.003983,0.00963,0.00697,-0.00809,-0.00791,-0.003254,-0.00669, +-0.001487,0.002129,-0.000799,-0.003944,0.002693,0.00667,0.00892,0.002377,0.001005, +-0.00792,0.002398,-0.001093,0.0006456,-0.002361,0.00533,0.0064,0.004524,-0.0066, +0.004406,0.007538,0.00611,0.006294,0.0004857,-0.00859,0.00928,-0.005505,-0.001135, +-0.00712,-0.00923,0.007534,0.00258,0.00685,-0.00873,0.001684,-0.001002,-0.0005627, +0.00352,-0.007324,0.00838,0.00731,0.006733,-0.003832,-0.00522,0.00299,0.000935, +-0.005245,0.000987,0.007515,0.00704,0.0086,0.00133,0.0038,0.00622,-0.0085, +0.00988,0.00625,0.00835,-0.006023,0.007084,-0.002728,0.009995,0.0008073,0.00341, +-0.004547,0.005917,-0.00818,-0.009705,0.00907,-0.008965,0.003483,-0.00556,-0.001769, +0.0068,0.007442,0.00497,-0.001922,0.002583,-0.00834,0.004417,0.005028,0.006336, +0.00402,-0.00773,0.00672,0.00324,0.003595,-0.00852,0.00503,-0.00794,-0.009766, +-0.000813,-0.006924,-0.006622,0.0008802,0.004177,0.007427,-0.001697,0.008575,0.00414, +0.00728,0.001138,0.000674,-0.00209,0.004883,-0.003029,0.0084,-0.00798,-0.003302, +0.007866,0.0006804,0.00306,0.006325,0.000508,-0.002022,0.00473,0.00958,-0.001912, +-0.002256,0.001385,0.001143,0.007668,-0.002575,0.004364,0.00919,-0.00924,0.00558, +-0.00447,-0.004196,-0.00547,0.00868,-0.001469,-0.00849,0.006397,-0.00529,0.002329, +0.00847,-0.009705,0.00233,0.000902,0.006073,-0.00536,0.000875,0.002682,-0.003347, +0.00905,-0.00399,-0.005783,-0.00942,0.00671,-0.008095,-0.004467,-0.008415,0.007996, +-0.00848,-0.00531,0.002605,-0.00632,-0.007652,0.009605,0.00929,0.007782,-0.006844, +-0.00115,-0.006626,-0.007526,-0.001129,0.00943,0.004242,-0.00486,0.00963,-0.006386, +-0.004513,0.00185,-0.001695,0.00976,-0.001186,0.001484,0.00429,0.000502,-0.009285, +0.005882,-0.00674,0.00882,0.00816,-0.008705,-0.003618,0.00406,0.007607,-0.001528, +-0.006336,0.006943,0.00753,-0.004963,-0.00602,0.002424,-0.009476,0.007385,0.00988, +-0.00359,-0.005722,0.006863,-0.00398,-0.005486,-0.004898,-0.0000809,-0.001511,0.00307, +0.002613,0.0004046,0.005634,0.00449,0.008606,-0.002146,0.002882,-0.007065,-0.00796, +-0.001136,-0.001323,0.004715,-0.007004,-0.007565,-0.002895,0.007523,0.007027,0.001487, +-0.003323,0.004665,0.007706,0.009186,0.00814,-0.003918,-0.002062,0.00514,0.00858, +0.00251,0.007576,-0.008736,0.001245,-0.007298,-0.006157,0.00719,-0.008446,-0.00864, +0.006535,-0.00002605,0.003567,0.002258,0.003443,-0.006207,0.00934,0.007515,-0.00916, +0.00861,-0.00939,0.008644,0.00656,0.001708,0.007935,-0.001997,0.002934,0.001758, +0.004932,0.005432,0.007812,0.00046,-0.00562,0.009186,0.002731,-0.00234,0.00913, +0.006542,-0.001783,0.001575,0.003267,0.00676,0.00647,-0.002998,0.00408,-0.002005, +0.002071,0.0001754,-0.003132,0.009705,-0.003107,0.00847,-0.006504,-0.0005784,-0.004715, +-0.008415,-0.005634,-0.00926,-0.006958,0.004932,0.0076,0.008896,0.006042,0.001687, +0.000543,0.005047,-0.002184,0.003963,0.00716,0.003468,-0.003925,0.0073,0.00385, +0.002712,-0.00893,-0.00004303,-0.00814,0.00937,0.0017395,0.00555,0.005833,-0.001491, +-0.00863,0.00947,0.001972,-0.00984,0.004642,0.003994,0.00923,-0.00984,0.0049, +-0.00987,-0.009834,-0.0005865,-0.006485,-0.0005198,0.00919,0.0004432,0.001068,0.009254, +-0.00881,-0.003483,0.00565,-0.007793,-0.00989,-0.00908,0.00276,-0.002663,-0.006893, +0.006332,-0.004177,0.006104,-0.00004715,-0.003693,0.003576,0.00255,-0.00928,-0.002916, +-0.007755,-0.00729,-0.0061,0.006523,0.00254,0.0008516,-0.0003228,-0.004017,-0.007374, +-0.005207,0.009056,-0.002869,0.004906,0.007675,0.003086,-0.008026,-0.00861,-0.006744, +0.0002438,0.00375,0.003315,0.00235,0.006836,-0.005516,0.00434,-0.004208,0.002483, +0.006413,0.00674,0.005604,-0.002977,-0.00732,-0.00908,0.007484,0.004456,-0.00822, +0.007442,-0.003195,0.005753,0.007698,-0.006397,-0.00785,-0.009605,-0.00419,0.00676, +-0.00833,-0.00997,-0.0003414,0.00906,-0.0071,-0.006092,-0.00885,-0.007866,0.000824, +-0.003231,-0.0006027,0.0074,0.00764,0.005795,0.002886,0.00958,-0.007668,0.004158, +0.00622,0.00119,0.00277,-0.00571,-0.0006685,-0.006645,0.0004497,0.00218,-0.00405, +0.00485,-0.007504,-0.001411,-0.001933,-0.009964,0.002077,0.00159,-0.002796,0.005787, +0.00335,0.001426,-0.005413,0.00994,0.001742,-0.00715,-0.0099,0.007744,-0.0008388, +-0.000603,-0.002,0.005436,0.00178,0.009796,-0.001966,-0.007397,-0.001909,0.00931, +0.0003397,-0.006817,0.0069,0.002558,0.00808,-0.007313,-0.00984,-0.00001967,0.002756, +0.009995,-0.00715,0.004765,-0.006096,0.004337,0.005642,0.00763,0.007103,-0.0002332, +0.00322,0.00284,0.003447,0.0012,-0.001126,-0.002625,0.00961,-0.005272,0.0053, +-0.002483,-0.00931,0.007687,-0.002417,0.004463,0.001136,-0.005375,-0.00672,0.007084, +0.0006213,-0.00912,0.006542,0.00606,0.003868,0.001709,-0.007484,0.004448,-0.00842, +0.00427,-0.00975,0.006847,-0.0071,0.0005484,0.00909,-0.004642,0.00564,-0.001863, +-0.006863,0.0087,-0.003702,-0.001783,-0.004032,0.003088,-0.002344,-0.00323,-0.00966, +0.008286,0.006916,-0.001279,0.003246,0.00921,0.007122,-0.006985,0.0002171,0.000837, +0.001388,0.001075,-0.008095,0.007515,0.00999,0.00423,-0.0004835,-0.009026,0.007538, +0.00877,-0.002445,0.003437,0.00485,-0.008125,-0.007767,0.00934,-0.0069,0.00804, +-0.001232,0.00959,-0.007687,0.005993,0.0006413,-0.00814,-0.002447,-0.001008,0.002981, +0.001682,0.004833,-0.00382,-0.0008454,-0.006485,0.00567,0.004982,-0.00484,0.00922, +-0.004585,0.00426,0.0004027,0.0006104,-0.0063,-0.00273,-0.006138,0.005367,-0.004303, +0.001937,-0.003523,0.007137,-0.005737,-0.00869,-0.00481,-0.00816,0.0002303,-0.0002975, +-0.002365,0.00207,-0.004353,-0.00924,0.00395,-0.00843,-0.0043,-0.0004406,0.004807, +-0.00694,0.001308,-0.000525,0.000463,-0.006813,0.00775,0.006725,-0.00984,-0.0003664, +0.009964,0.007217,0.001767,-0.004524,0.002432,0.000869,-0.005993,0.007275,-0.001423, +-0.00711,-0.001464,0.007347,-0.004776,0.00513,-0.00942,0.003813,-0.00489,-0.00835, +-0.00711,-0.002565,0.004646,0.002693,0.000531,-0.001337,-0.0008225,0.0005493,-0.003017, +0.003242,-0.00651,0.00958,0.006573,-0.00635,0.008,-0.004864,0.003464,-0.007538, +-0.00917,-0.002682,0.00431,-0.00604,0.002548,0.000772,-0.00769,-0.002756,0.004482, +0.001484,-0.004753,-0.003052,0.0002143,0.003023,0.002924,0.00821,0.004673,0.003557, +0.0092,-0.00654,0.001993,0.00835,-0.008736,-0.0003886,-0.00677,0.0004423,-0.00723, +-0.002926,0.00994,0.00784,0.001214,0.00311,0.003584,0.00856,0.001752,-0.004345, +-0.003647,0.00984,-0.006798,0.001661,0.0005393,0.0004299,0.001711,-0.006824,0.003633, +0.00506,-0.002146,0.005653,-0.00959,0.0009027,-0.009674,0.002176,-0.002815,-0.007362, +-0.0002565,-0.005466,0.006443,0.00541,-0.006615,-0.00668,0.0000291,-0.00249,-0.00648, +0.006466,0.005596,-0.00963,-0.00289,-0.007336,0.001666,-0.001227,0.008835,-0.00396, +-0.001764,-0.00962,-0.00461,0.00488,0.00606,-0.00959,0.005497,0.003384,-0.002548, +0.00479,0.001423,-0.004772,0.0001752,0.00884,0.0069,0.00792,-0.001779,0.0007215, +-0.007557,0.004314,-0.006527,-0.00513,-0.00855,-0.00873,-0.00709,-0.007538,-0.002918, +-0.00867,0.000341,0.0004723,0.007336,-0.0009327,-0.005554,0.007065,0.00586,-0.003202, +-0.001984,-0.007755,0.006268,0.003624,0.001136,0.002611,-0.007374,-0.00522,0.005642, +0.003551,0.005558,0.00512,-0.001255,0.00445,0.006657,-0.003395,-0.0000211,-0.00948, +-0.00525,0.007614,0.007603,-0.00872,0.00983,-0.0059,0.005405,-0.005775,0.001911, +-0.006306,-0.008446,0.006702,0.001295,-0.007904,-0.00613,-0.00737,0.004997,0.00699, +-0.008514,0.001029,0.008705,0.00543,-0.0097,-0.00839,0.00201,0.00319,-0.00767, +0.003147,-0.00936,0.003647,0.007465,0.00802,0.001254,0.00955,0.006344,-0.00754, +0.007072,-0.007305,-0.002403,-0.006702,-0.00827,0.007183,-0.001834,-0.0057,-0.007095, +0.00332,-0.0008297,0.004333,0.0008926,-0.00629,0.007393,0.006477,-0.004684,0.002182, +-0.004246,0.007324,0.001202,0.00993,0.001759,-0.001665,0.0067,0.003798,-0.007454, +-0.00821,0.001178,0.004494,0.00384,0.003609,0.007614,0.00976,-0.00918,-0.002209, +0.002016,0.0093,0.00638,-0.007572,-0.008224,-0.000771,-0.00854,-0.001513,-0.007267, +0.00887,-0.00107,-0.007755,0.004757,0.002693,0.00439,-0.00927,-0.003588,0.001711, +-0.002756,0.00974,-0.004158,0.00621,0.00451,0.007935,-0.002064,-0.0081,-0.00682, +0.006042,-0.003317,-0.003391,-0.00688,-0.00743,0.003933,-0.00816,-0.003164,-0.001821, +-0.001942,0.005005,0.00597,0.00595,0.0086,0.003202,-0.00803,-0.00892,-0.002626, +0.000533,-0.002506,0.00506,-0.00822,-0.000431,0.000955,-0.004826,-0.006626,0.001367, +0.00684,-0.00793,0.00634,-0.004353,-0.00682,0.00657,0.000718,-0.002306,0.006966, +0.006992,-0.006275,0.00843,0.004826,0.00886,-0.004,0.00901,0.005543,-0.00566, +-0.009575,0.005444,0.00633,-0.005756,0.007687,0.001801,-0.005802,0.001708,-0.004517, +0.00808,0.00984,-0.00847,0.00959,-0.002443,-0.001829,-0.003305,-0.00392,-0.006924, +-0.002266,0.001481,0.001099,-0.00549,0.004787,0.00784,-0.008514,-0.00288,-0.00858, +0.003025,0.002846,0.001469,0.00927,0.006443,-0.00908,0.009445,-0.009636,-0.0003245, +0.003815,-0.0001975,0.0007005,-0.00984,0.0005784,0.0006576,-0.00885,0.001424,-0.004414, +0.006252,0.002722,-0.002953,0.001995,0.00942,-0.0000668,-0.007507,0.00201,0.00344, +0.002167,-0.001902,-0.00691,0.00427,-0.006607,-0.003334,-0.00143,-0.00676,0.00736, +0.005222,-0.0004745,-0.0005236,-0.00818,0.004253,-0.002077,0.007355,-0.00157,-0.004112, +-0.007156,0.002766,-0.001808,-0.003685,0.002918,0.005814,0.00126,0.00001913,-0.0002122, +0.00882,-0.001593,0.005184,-0.006516,0.00848,0.00835,-0.0006256,0.00252,-0.00594, +0.005688,-0.0089,0.000832,0.00922,0.002317,-0.003725,-0.005905,0.001728,0.002249, +-0.00986,0.008896,-0.0001637,0.006817,-0.0092,0.008484,-0.00751,-0.002232,0.007233, +0.001008,0.003746,-0.005726,0.006203,0.000586,0.00568,0.000979,-0.00249,-0.004295, +-0.005775,0.0093,-0.002306,0.002426,-0.00712,0.004265,0.00659,-0.00504,-0.002317, +0.003494,-0.005882,0.00602,0.001864,-0.008255,0.00559,-0.001576,-0.004242,-0.005627, +0.00521,0.003729,-0.005524,-0.005688,0.00695,-0.00475,-0.0001157,-0.007744,-0.007935, +0.006092,-0.007626,0.002676,-0.00196,-0.00932,-0.001797,-0.0081,-0.004524,0.002777, +-0.0007696,-0.0008817,-0.00864,0.00834,-0.001039,-0.00899,-0.007412,-0.002197,0.003298, +0.00258,0.00667,0.001576,-0.002626,-0.001692,-0.00107,-0.001912,-0.00997,-0.005493, +-0.0098,-0.001864,0.001933,0.005116,-0.00938,-0.0002704,0.0001253,-0.00465,-0.00414, +0.001244,0.002434,-0.003223,0.007835,0.004036,0.00748,-0.00903,0.004265,-0.002977, +0.00732,0.006317,-0.00563,-0.008224,-0.00867,0.00962,-0.005325,0.00101,-0.00856, +0.00735,-0.00862,-0.003899,-0.004925,0.0069,0.004513,-0.009895,-0.00239,0.00992, +-0.00149,0.001915,-0.002604,0.0095,0.007416,0.005016,-0.002281,0.008125,-0.009476, +-0.009056,0.003843,-0.002602,0.0089,0.003674,0.00132,-0.00627,0.009186,0.006226, +-0.00442,0.003323,-0.00282,0.00831,0.007153,-0.00724,-0.002815,-0.0001028,0.00809, +0.00871,-0.007435,-0.0018835,0.002344,0.00975,-0.00286,-0.00835,-0.003582,-0.000401, +0.007904,-0.00499,0.003502,-0.009605,0.00367,-0.007473,-0.003994,-0.002377,0.00413, +0.000489,0.005356,0.00786,0.00476,-0.005436,0.005947,-0.000724,-0.00671,0.00569, +-0.00826,0.00846,-0.006634,-0.003334,-0.00802,-0.007126,-0.001247,0.00596,-0.009056, +0.0005774,-0.00648,0.006126,-0.00668,-0.004116,-0.0002975,0.0002549,-0.006977,0.002117, +0.0007377,-0.00803,-0.003365,0.00819,-0.002949,-0.00969,0.006794,-0.007645,-0.00099, +0.006966,0.009735,0.002426,0.005592,0.0003273,-0.003353,-0.002249,-0.00514,-0.002508, +-0.008156,-0.000979,0.0002344,-0.006508,0.00781,0.001318,-0.00498,0.00858,-0.003828, +-0.00504,0.00639,-0.002424,0.002552,0.003736,-0.00797,0.00761,0.006474,0.004166, +-0.009026,0.00638,0.0097,-0.007202,-0.008224,-0.005714,0.001017,0.004894,-0.00898, +0.00874,-0.004066,-0.002527,0.000754,-0.002802,0.009315,-0.00817,-0.008705,-0.0006857, +0.006992,0.000913,0.005993,0.005013,0.009346,-0.00574,0.008575,0.004166,-0.00604, +-0.0032,0.0014925,0.008865,-0.006435,-0.004417,0.000921,0.00928,-0.001739,0.000586, +0.007904,0.007347,0.00331,-0.0078,-0.004005,0.0074,-0.005825,-0.007244,-0.002626, +-0.005917,0.006508,0.007263,-0.001506,-0.003498,0.00693,0.004097,0.00934,-0.003752, +-0.006752,0.001534,0.003906,0.001351,0.00367,0.0086,-0.00536,-0.001699,0.001546, +-0.00277,-0.0005455,-0.002718,-0.00583,-0.0009003,-0.001003,0.001612,-0.003557,-0.006004, +0.001006,-0.00925,-0.0008187,-0.002907,0.003675,0.00394,0.005608,-0.007133,0.001691, +0.006428,0.003813,-0.00542,-0.00583,0.002207,-0.001088,0.00714,0.006233,0.002617, +-0.00419,-0.00916,0.004063,-0.002892,0.000514,0.00224,0.0001853,0.0007997,0.0005536, +-0.00639,-0.007015,0.00309,0.006184,-0.00982,-0.0002372,0.0009604,0.00962,0.00678, +-0.006653,-0.004955,-0.0003958,0.006428,0.004517,0.00672,0.003792,-0.006046,-0.00221, +-0.00727,-0.00748,-0.004204,-0.00982,0.0007663,0.00661,-0.003647,-0.006973,0.002605, +0.0001023,0.004536,-0.00647,0.009735,0.00945,-0.00967,-0.0003023,-0.0086,0.008736, +-0.00701,0.00258,-0.002716,-0.00162,-0.006996,0.007664,0.007595,0.00403,0.00233, +-0.00481,-0.001349,-0.005196,-0.009026,0.00606,0.001146,0.001434,0.00967,0.004448, +-0.004837,-0.007168,-0.005234,0.002514,0.005306,0.003088,0.0018215,-0.00558,-0.006596, +0.002018,-0.003408,-0.001384,-0.006065,-0.001212,-0.002604,-0.00767,0.0001342,-0.00851, +-0.00392,0.003862,0.00701,0.003605,-0.00965,-0.00714,0.00956,-0.00888,-0.001019, +0.0024,-0.00961,-0.005238,0.005333,0.00871,0.007607,-0.00756,-0.004772,-0.00912, +-0.004047,0.003483,0.003294,0.006577,-0.005505,0.00996,0.009964,0.0004187,0.005898, +0.00796,-0.00165,-0.003225,-0.001258,0.00853,-0.008865,0.00815,-0.001117,-0.00685, +0.001974,0.00915,0.00667,0.009605,0.007107,0.007698,-0.004387,-0.0003958,-0.005062, +0.002188,-0.004875,-0.002922,-0.0003638,0.006268,0.00785,0.006138,0.000505,-0.0003953, +-0.00841,-0.00958,-0.007126,-0.003107,0.0078,0.003452,-0.009254,-0.00117,-0.00878, +-0.00911,-0.0004418,0.00831,-0.004524,0.003872,0.0044,0.006424,0.000634,-0.004883, +-0.002487,-0.00512,-0.00692,-0.00521,-0.001761,0.008575,-0.006393,0.00351,0.00914, +-0.006035,-0.002264,-0.009636,0.00918,-0.00967,-0.004944,-0.0004587,-0.002478,-0.00814, +0.00816,-0.004776,0.00954,0.003471,-0.006172,0.003603,0.009346,0.00455,0.00982, +0.00476,0.0007815,-0.003096,-0.0000307,-0.005608,0.009315,0.00374,-0.007366,-0.001133, +-0.00944,0.006847,0.00631,0.005394,0.003088,-0.00644,-0.0004168,-0.00923,-0.003254, +-0.005077,0.00637,-0.001415,-0.003235,-0.001729,-0.0082,0.006664,-0.006,0.00663, +-0.001547,-0.004116,-0.00542,0.00521,-0.00286,-0.00396,0.004547,-0.0001363,0.000979, +-0.00634,-0.006767,-0.0000603,0.008316,0.00756,-0.004993,-0.00645,-0.002295,0.004288, +0.00901,0.008194,-0.004192,-0.002182,-0.005836,-0.003983,-0.007183,-0.0061,0.001098, +-0.0009274,0.005207,0.0002102,-0.003925,0.0056,-0.00296,0.006134,-0.007744,0.006126, +-0.005047,-0.006134,0.004818,-0.005283,0.005272,-0.00779,-0.003086,-0.000607,0.005486, +0.0005345,-0.007305,-0.0048,-0.00876,-0.00433,0.006165,-0.002474,-0.00953,-0.002066, +0.002918,0.006382,0.003317,0.00826,-0.009995,0.004143,0.00985,-0.0002116,-0.002989, +-0.007805,0.0003633,-0.00365,-0.00916,0.009834,0.003513,-0.00379,0.00736,-0.00957, +0.005726,-0.00772,-0.00803,-0.002052,-0.005585,-0.00781,-0.00599,0.00954,0.002024, +-0.005745,0.003054,-0.009415,-0.005054,0.00424,0.003218,0.00826,0.00817,-0.00409, +0.00518,0.00216,0.006756,-0.00411,-0.003344,-0.004898,0.00001055,0.006104,0.001057, +-0.000702,0.00771,-0.001743,0.001407,-0.005104,-0.007717,-0.002026,-0.006405,0.00886, +0.0006466,-0.00951,-0.00395,-0.00814,0.00936,0.001143,-0.00485,0.00584,-0.002224, +0.00834,-0.0003467,-0.000945,0.007034,-0.0009427,-0.009445,0.0007753,-0.006973,0.001507, +0.004105,-0.002523,0.002872,-0.001515,-0.00869,0.003103,0.000389,-0.00774,0.00441, +-0.001002,0.00783,-0.001102,-0.003883,-0.007187,-0.0001678,-0.00742,-0.00686,-0.006702, +0.00894,-0.0003886,-0.005543,0.00988,0.00411,-0.00002635,0.00851,-0.002317,0.00873, +-0.00532,-0.000835,-0.004166,-0.004036,-0.003325,-0.00799,0.003025,0.001356,-0.009575, +-0.00426,-0.003431,0.00899,-0.001455,-0.0007324,-0.00492,0.00989,-0.0002503,-0.00814, +-0.00535,-0.0035,-0.001434,0.00635,-0.005108,0.002626,0.00983,0.00672,-0.00725, +-0.004826,0.007275,-0.006763,0.002605,0.002369,-0.000976,0.00263,0.00465,-0.009544, +-0.0008945,-0.00175,-0.00799,-0.0006666,-0.00514,-0.002842,-0.001805,0.000992,0.00844, +-0.000964,-0.00636,0.001281,0.001717,0.00569,0.005917,-0.00826,-0.00859,0.004246, +0.004078,-0.005566,0.00835,-0.006893,-0.005867,0.001273,-0.005856,0.004448,0.004562, +-0.00392,-0.00855,0.0005975,0.006817,-0.005524,-0.0009527,-0.00695,-0.002172,-0.003683, +-0.00546,0.007698,-0.00858,0.003372,0.001414,-0.007786,-0.00482,0.0083,0.007534, +0.00554,0.005768,0.001982,-0.004597,-0.001634,0.000563,0.00298,0.001768,0.0004673, +0.009285,0.00518,0.00798,0.00557,-0.002504,-0.00777,0.007904,0.00939,-0.004646, +0.00527,0.00817,0.00526,0.007935,-0.00413,-0.002628,-0.008194,-0.006195,0.00884, +0.007282,0.003819,-0.00904,0.001354,-0.004368,-0.0002527,0.004684,-0.002907,-0.003862, +-0.002197,0.00858,-0.00989,0.0004277,0.008484,-0.008865,0.007275,0.00869,-0.0000226, +0.0006456,0.0002527,0.003267,0.007793,-0.001359,-0.007423,-0.004204,0.006824,-0.00801, +0.006992,-0.002182,0.00181,0.00966,-0.00888,-0.006527,-0.00873,-0.004623,-0.006767, +-0.006317,0.003017,0.002218,0.00805,-0.00677,-0.00974,-0.0083,0.008095,-0.00424, +-0.009636,0.002298,-0.00864,0.004044,0.000354,0.00949,0.00635,0.009026,-0.00806, +-0.0008893,0.002377,-0.001343,-0.001965,-0.00442,-0.006615,-0.004166,0.00719,-0.006306, +-0.009674,-0.00787,0.00712,-0.003637,0.0008287,0.005352,-0.004227,-0.00549,-0.0058, +0.00489,-0.005165,0.001942,0.00591,0.00612,0.005306,-0.00723,0.0051,0.002329, +-0.001097,0.002022,-0.006416,-0.006577,0.003603,0.004303,0.007652,0.00884,-0.003191, +0.002787,-0.009254,0.003475,-0.002266,0.00936,-0.00793,-0.00738,0.008194,0.003998, +-0.0049,0.008965,-0.000592,0.00711,0.00905,-0.0006223,-0.00735,-0.00399,-0.00808, +-0.005367,0.00705,0.0007415,0.00864,0.00883,-0.001155,0.00898,0.004406,0.00967, +0.004677,-0.003113,-0.0009146,0.00756,0.005733,-0.003647,0.00446,0.00798,0.003305, +-0.0000515,-0.003746,-0.002283,-0.004913,0.003496,-0.00773,-0.003622,0.004974,0.00244, +0.001445,-0.004826,0.002394,0.003075,-0.0006714,0.002077,-0.008675,-0.001683,0.006065, +-0.005512,-0.001691,0.007507,-0.00913,-0.0008674,-0.005,0.001398,-0.004875,-0.000567, +-0.002668,0.001711,-0.005306,-0.00883,-0.001738,0.0035,-0.006702,-0.006943,0.00884, +-0.001516,0.00991,0.003082,0.006077,-0.00437,-0.000524,-0.003986,0.007393,0.00986, +-0.0008,-0.001425,-0.001999,-0.002277,-0.00901,0.004986,0.002085,-0.0009236,0.001841, +-0.003191,0.002205,-0.00781,0.00397,-0.002066,-0.008835,-0.004585,-0.00953,-0.006496, +-0.006996,0.007233,-0.00544,0.001037,0.0028,-0.007935,-0.0055,-0.007866,0.00436, +-0.0009565,0.001419,0.007587,-0.0004418,-0.00318,-0.003857,0.007763,0.008896,0.004925, +0.00979,-0.00928,-0.001149,0.00678,-0.002733,-0.002972,-0.001726,0.006706,-0.001256, +-0.00636,0.0004964,0.0005093,-0.0008807,0.002026,0.00215,-0.007603,-0.00936,-0.001715, +-0.000935,0.0005236,0.000975,0.00786,-0.002583,0.003407,-0.002033,-0.00217,0.001398, +-0.0001027,0.0009203,0.0009117,0.00741,-0.003925,0.0007577,-0.006317,0.001241,0.005623, +0.001732,0.00374,0.00341,0.006714,0.001987,-0.0037,0.00349,-0.00431,-0.00895, +-0.009605,-0.007214,-0.00393,-0.002583,0.00841,0.00782,-0.005657,-0.00655,0.003542, +-0.004143,0.003202,-0.002695,0.0002656,0.001797,-0.0065,0.00628,-0.0001239,-0.002842, +0.00119,-0.00979,0.006287,-0.00646,0.00769,0.00831,-0.0055,0.0005436,0.006554, +-0.0001364,0.00699,0.004364,-0.00227,0.00489,0.0026,0.0007696,0.0004685,-0.001103, +0.001123,-0.002245,0.006527,-0.00828,-0.002954,-0.005226,-0.005814,-0.0002468,-0.00884, +0.008606,-0.00001067,-0.00417,-0.003376,0.00918,-0.00776,0.002684,0.006145,-0.0006285, +-0.004173,-0.004917,-0.00678,0.00248,0.007263,0.002188,-0.000213,0.00413,0.002676, +0.004948,0.007614,-0.001845,-0.00436,0.00591,0.004833,-0.002085,-0.006096,0.007378, +0.001922,0.006573,0.0016985,0.001776,0.00993,-0.00829,-0.0001675,0.004753,0.00008494, +0.00989,0.0008593,0.00636,0.0008297,-0.00482,-0.001189,-0.001576,-0.001331,-0.00881, +0.00416,-0.0008516,-0.002281,-0.00399,-0.00603,0.0031,0.00994,0.0009284,-0.00446, +-0.00944,0.00272,-0.001006,-0.006733,0.00815,0.004932,-0.004894,0.007156,0.0001193, +-0.00745,-0.000041,-0.004074,0.00829,0.006042,0.006176,-0.00509,0.005375,-0.00554, +-0.001078,-0.002928,0.00813,0.004013,0.002552,-0.0086,0.000254,-0.005844,0.004093, +-0.008224,0.006016,-0.004883,-0.006504,0.0003617,-0.00008327,0.00382,0.00786,-0.00915, +-0.004963,0.003756,0.00689,0.00833,0.005455,-0.00871,-0.00872,-0.0008054,0.001023, +-0.003527,-0.00735,0.00691,0.0092,0.004837,-0.000847,0.0006146,-0.00829,0.007317, +-0.002722,0.005962,-0.004005,0.002857,0.004414,0.00437,-0.003452,-0.004383,-0.004654, +0.007866,-0.000736,-0.001158,-0.005924,-0.002207,0.00904,0.004505,0.005688,0.003448, +-0.00414,-0.00986,-0.007446,0.00479,0.00314,0.0084,0.005714,-0.002865,0.0008903, +-0.00831,0.009415,-0.001098,0.0007825,-0.002136,-0.009995,0.00798,-0.0002449,-0.00454, +0.00262,-0.001926,0.003874,-0.001987,0.00456,0.00994,-0.00275,-0.0013485,0.00911, +-0.0011,-0.005253,0.003504,0.004726,-0.00821,0.00008196,0.004696,0.00473,0.006893, +-0.002386,0.007145,0.007584,-0.00542,-0.000596,0.002354,0.001427,0.001673,0.004646, +0.004826,0.00847,-0.005226,0.0003307,0.00536,0.002802,0.006264,-0.000479,0.00222, +0.00817,0.005253,0.005257,0.001163,0.005417,0.006603,0.00514,-0.003473,-0.001948, +0.006695,0.003492,0.000456,0.00933,0.00283,0.006935,-0.004658,-0.0008807,-0.001274, +-0.0006485,-0.00349,-0.002163,0.00811,0.001358,-0.002134,0.0005803,-0.001573,-0.005478, +-0.00496,0.00968,0.001645,-0.005756,-0.0008974,-0.00608,-0.00528,0.00005585,-0.005756, +-0.004025,-0.00772,-0.0008974,0.00786,0.00396,-0.008865,-0.00645,-0.00903,0.00802, +-0.001602,-0.0072,0.00736,0.002499,-0.00839,-0.00925,0.005943,-0.00785,-0.0081, +-0.00802,-0.005554,0.004078,0.009476,-0.00877,0.00257,-0.00439,0.006744,-0.00419, +-0.005413,0.002476,-0.002373,-0.006424,0.008736,0.006977,0.009735,0.009514,0.0009437, +-0.001418,0.004066,0.004986,-0.008644,-0.007427,-0.00988,0.006714,-0.00118,0.00924, +0.000984,0.001846,-0.00418,0.00341,0.0007763,0.008545,0.007313,0.00999,-0.000682, +0.003416,0.00465,-0.000676,0.00206,-0.00654,-0.002478,0.003826,-0.001733,-0.003693, +-0.001044,-0.004696,0.00688,0.00632,0.004963,-0.00365,-0.00772,-0.001813,-0.004898, +-0.008385,0.002,-0.007782,-0.000961,-0.003376,0.005157,-0.002651,0.007935,0.003716, +0.009,0.001195,-0.00982,-0.00532,-0.00828,-0.000279,-0.007626,0.00879,0.006996, +0.00942,0.002588,-0.0097,-0.00011635,-0.001595,-0.0006347,-0.001799,0.00126,0.005085, +0.001865,0.003216,-0.000628,-0.00474,-0.004925,-0.00626,0.006287,-0.005054,0.0079, +-0.005177,-0.009796,-0.00805,-0.001599,0.0085,-0.008965,-0.002886,-0.008606,-0.008965, +0.004757,-0.009285,0.00548,0.00816,-0.001941,0.00622,0.00755,0.00926,0.009125, +-0.004364,0.006214,-0.007137,0.001763,-0.002035,0.004326,0.00653,-0.007072,-0.003609, +-0.00504,0.004448,-0.005928,-0.007057,-0.002148,-0.004593,-0.004467,-0.009514,-0.00854, +0.001922,0.007572,-0.005016,0.003345,0.008575,-0.00967,0.000532,-0.002897,-0.005013, +-0.009834,0.00302,0.005688,0.005096,-0.003983,0.00851,0.001554,0.00394,0.005688, +-0.00537,0.00655,0.007526,0.002298,0.006126,-0.00654,-0.003433,-0.00818,-0.003098, +-0.00822,-0.00898,-0.007675,0.005955,-0.003288,0.006237,-0.002,0.002678,-0.00639, +0.00899,0.009766,0.009384,-0.0001253,0.007263,-0.003555,-0.00988,-0.00534,-0.005356, +-0.00805,0.001697,0.002516,0.0022,0.007397,-0.002075,0.00247,0.004593,-0.00543, +0.000358,-0.005047,0.00476,-0.003937,-0.002851,0.007507,0.001389,0.003235,0.00205, +-0.00474,-0.0059,0.001666,0.002943,-0.00954,-0.00828,-0.008804,0.002356,0.00836, +0.002785,0.00881,-0.00716,0.005608,0.007534,-0.00952,0.008965,0.0001839,-0.007412, +0.00693,-0.0000717,0.003857,0.00021,0.002897,-0.00452,-0.002552,-0.005962,-0.006737, +-0.0008616,0.008606,-0.005814,-0.007397,-0.006096,0.0099,-0.00955,0.001134,0.00702, +-0.0003154,0.00366,-0.009186,-0.001096,0.00984,-0.005787,0.00369,-0.001496,0.002462, +-0.00623,-0.00426,-0.004837,-0.00558,-0.003311,-0.0066,0.0077,0.003609,0.004646, +0.007996,-0.00788,0.006348,-0.00986,0.00817,0.0001633,0.0001796,-0.00899,-0.001417, +0.00972,-0.00067,-0.005535,0.001376,0.004974,0.0008225,0.008484,-0.00589,0.00828, +-0.007206,-0.00599,-0.0009503,0.000634,-0.0001874,-0.00654,0.00424,-0.001244,0.002506, +-0.009964,-0.00828,-0.002129,-0.003368,-0.0003746,-0.006798,-0.00383,0.008514,0.00818, +-0.005497,-0.0034,-0.001681,-0.004208,-0.004337,-0.0000664,0.003807,-0.006073,-0.003489, +-0.00521,0.005047,0.00367,0.005657,-0.004665,0.00671,-0.003513,0.00869,0.008095, +0.007545,0.007214,0.002594,-0.001637,0.005642,0.00526,-0.007195,0.00413,-0.006878, +0.009224,0.008514,-0.0008245,-0.004276,0.003633,-0.000534,-0.00916,-0.00905,0.00827, +0.00458,0.002428,-0.002975,0.00718,-0.00888,0.004597,0.0004854,-0.003778,0.006023, +0.001024,-0.00484,-0.0048,0.001374,-0.004204,-0.004368,0.005783,0.001205,0.007774, +-0.001196,-0.007015,0.00822,-0.005875,0.003675,0.00279,0.001947,-0.00342,-0.000307, +-0.003113,-0.0017185,-0.001276,0.0031,-0.003546,-0.003328,0.004078,0.00976,-0.002756, +0.00487,-0.007904,0.003613,0.007034,-0.00624,0.0007896,-0.0077,-0.001974,0.007397, +0.005966,-0.00627,-0.005215,0.001178,-0.00372,0.001711,-0.001743,0.00248,0.0003877, +0.005028,-0.00789,-0.0007873,-0.005753,0.00961,0.00961,0.002813,0.002567,-0.007095, +0.003628,0.0001531,0.0002968,-0.005493,-0.0001053,0.00964,0.004997,-0.00657,0.000724, +-0.00563,-0.009834,-0.003574,0.003572,-0.006805,0.007423,0.003103,-0.005455,0.00881, +-0.00777,-0.003508,0.0075,0.00404,-0.00747,0.003056,0.005142,-0.007156,-0.00923, +0.00401,0.007442,0.005077,0.007393,0.004276,-0.00851,-0.00263,-0.006123,0.003536, +0.005672,0.00887,-0.002031,-0.00524,-0.001232,0.000433,0.005398,0.009575,0.009705, +-0.007267,-0.00565,-0.003963,0.007477,-0.00216,-0.007744,-0.003347,-0.00804,-0.002136, +-0.002407,0.00826,-0.006294,0.005116,0.00007975,-0.007267,-0.003428,-0.005497,0.001562, +0.003801,-0.004646,0.004234,0.00979,0.00943,-0.002726,0.0007277,0.0007143,-0.00785, +0.00531,0.00747,-0.006287,0.0001854,0.0005198,-0.006645,-0.000202,-0.0004883,-0.001946, +0.00904,0.00122,0.005608,0.002243,-0.001732,-0.00844,-0.000973,0.00898,0.00686, +0.005028,0.005497,-0.002182,-0.007122,0.00955,0.00725,0.0000116,0.00504,0.00864, +-0.00827,-0.00476,-0.001607,0.006145,0.00777,0.00974,-0.002163,0.00857,0.006485, +-0.004356,0.00010043,0.001632,0.005432,0.00846,-0.006756,0.0005136,-0.00836,-0.009544, +0.005016,-0.002354,-0.004543,0.00419,0.00798,-0.001813,0.005913,0.003494,-0.002695, +-0.009346,-0.001584,-0.00886,-0.007374,0.00979,0.00961,0.0006576,-0.0018015,-0.009766, +-0.00821,-0.00924,0.0002823,0.003115,-0.00788,-0.005257,0.003233,-0.00939,0.00617, +0.003914,-0.002165,0.004215,0.00603,0.00498,-0.000754,0.0079,0.00463,-0.004574, +-0.00494,0.0014715,0.007866,0.005215,-0.00008845,0.00897,-0.00431,-0.00416,0.001195, +-0.007626,0.006153,0.000168,-0.001373,0.001575,-0.00368,-0.00926,0.003387,-0.006237, +-0.003305,-0.004677,0.003044,0.002283,-0.00855,-0.00383,0.005135,-0.003328,-0.005, +-0.006145,0.008995,0.00933,-0.0004253,-0.00697,-0.00895,0.001212,0.007114,0.005264, +0.003008,-0.0087,0.00578,-0.008354,0.009056,0.004955,-0.004787,0.001999,-0.008705, +-0.00722,-0.00211,0.00471,-0.0012245,-0.0003836,-0.00119,-0.005363,-0.00464,-0.00628, +-0.00855,-0.000797,0.005047,0.0006003,0.002134,0.001738,0.006653,-0.003204,0.00568, +-0.0003297,0.0001493,-0.00001603,-0.001742,-0.0004888,-0.002066,-0.003843,0.008514,0.001038, +-0.006084,0.002298,-0.00506,0.0028,-0.00588,0.006187,-0.004707,0.00482,-0.005604, +0.0099,0.002226,-0.00418,-0.00867,-0.001959,0.006733,0.00881,-0.009636,0.006523, +0.00918,-0.005287,-0.00939,0.007725,0.002266,-0.00813,0.00945,-0.009735,0.00804, +-0.00447,-0.0006757,-0.002113,0.0071,-0.002256,-0.001572,-0.002722,-0.005325,0.005184, +0.001163,0.00785,-0.00908,0.000957,-0.004894,-0.00785,0.004192,0.005585,-0.00466, +0.00659,-0.009026,0.00393,-0.00526,-0.00882,-0.006893,-0.008286,-0.000591,-0.00449, +-0.00882,0.004025,-0.00812,0.002306,0.003397,0.0002433,-0.00333,0.000728,-0.001259, +-0.0006423,0.00922,0.002346,-0.00682,-0.002346,-0.00688,0.0004377,0.0007114,-0.00878, +0.00824,-0.007797,0.00000536,0.00009096,0.00981,-0.001997,-0.006676,-0.006683,-0.00412, +0.00085,0.004017,0.00645,-0.00674,0.00846,-0.00847,-0.00199,0.003153,-0.0002362, +-0.0004025,0.007996,0.002476,0.00555,0.003628,-0.00508,0.00728,-0.00266,0.003223, +-0.007328,-0.00689,-0.00229,-0.001114,0.002768,-0.001708,0.003847,-0.007248,-0.00689, +-0.007065,-0.00772,0.005745,0.008804,0.006092,0.005795,0.001585,0.005386,-0.005962, +-0.0004244,0.008804,0.003803,0.000961,0.00976,0.0005674,0.00905,0.00982,0.005295, +-0.00009507,0.005775,-0.002659,-0.001253,-0.006416,0.008194,0.00945,0.006752,-0.00935, +0.003845,-0.006237,0.00415,0.008095,-0.00645,-0.009865,0.000944,0.00811,0.00841, +0.0002704,-0.00681,0.00514,-0.005535,-0.00543,-0.007355,0.006424,-0.0012665,-0.007423, +0.00501,0.0071,-0.0001485,-0.004772,-0.007965,-0.002703,0.00977,-0.0002038,0.00664, +0.002275,0.004887,0.00762,0.001178,0.001114,-0.000678,-0.001807,-0.004963,0.001163, +0.00273,-0.00955,0.002756,0.0005674,-0.00551,-0.00862,-0.009026,0.00948,-0.00195, +-0.001241,0.00402,0.002943,0.0001924,0.001133,-0.004086,0.002512,-0.0058,0.00159, +-0.00808,0.00575,-0.00857,-0.00701,0.009544,-0.001974,0.002966,-0.004898,-0.001783, +0.003128,-0.005596,-0.00751,-0.004704,0.00719,-0.00949,-0.001564,0.003157,0.005245, +-0.00424,0.004654,-0.00425,-0.008766,0.00912,-0.005386,0.00439,-0.002386,0.00576, +0.003857,-0.007004,0.0005574,0.006065,-0.0068,0.00985,-0.0003872,-0.004654,0.008675, +0.00801,0.001015,0.0019045,0.007225,0.0004132,-0.005173,0.001682,-0.002037,-0.003492, +0.003092,0.00231,0.007294,0.002605,-0.00941,-0.004112,0.0082,0.002506,-0.00819, +-0.0041,0.009476,0.003584,-0.00585,0.00462,-0.006348,0.00913,-0.003197,-0.004265, +-0.00945,-0.001356,0.007545,0.002289,0.001126,0.002977,0.00948,-0.00703,-0.002531, +-0.00868,-0.00619,-0.0004635,0.009254,-0.0005174,-0.00736,-0.006264,0.00779,-0.002342, +0.004997,0.00269,0.00509,-0.0041,0.00506,0.002752,-0.006416,0.00794,0.003563, +0.00551,0.006554,-0.008286,-0.00296,0.008354,-0.0079,-0.006348,0.001052,0.0007205, +0.00506,0.000453,-0.00993,-0.006424,0.005787,-0.001206,0.00876,-0.004513,-0.002857, +-0.00701,-0.00621,0.003498,0.00986,-0.00846,-0.00128,0.006294,-0.003735,0.00843, +-0.00841,-0.007465,-0.007504,-0.00734,0.00635,0.004498,-0.005688,-0.003014,0.00892, +0.00982,0.00793,-0.002365,0.003353,-0.004486,-0.00651,-0.00361,-0.00418,-0.00786, +0.007812,0.001912,-0.008156,-0.00809,-0.001939,-0.003836,-0.001578,0.00331,-0.008736, +-0.006138,-0.00877,-0.007595,0.002537,-0.007336,-0.006477,-0.007767,-0.00853,-0.003601, +-0.000952,0.007683,-0.006283,0.00796,0.006012,-0.001464,0.00718,-0.0025,-0.001972, +0.004166,0.0002615,0.00496,0.006516,0.0016,-0.008415,-0.002398,-0.001027,0.0000037, +0.00827,0.003153,0.004826,0.00619,-0.00673,-0.00834,-0.001702,0.006664,-0.00465, +-0.00909,0.003893,0.005188,0.009415,0.00191,0.00274,-0.002968,-0.003834,0.00495, +0.005985,-0.002945,0.007317,-0.00934,-0.001007,-0.005333,-0.008415,-0.0067,0.006084, +0.00689,-0.002855,-0.009254,-0.00402,0.007694,-0.007633,-0.008865,-0.00846,0.007317, +-0.00915,-0.009476,0.002455,-0.001528,-0.001358,0.0016985,-0.001466,-0.002584,-0.006992, +-0.00427,0.000739,0.00258,0.0042,0.001303,0.00963,0.002176,-0.00952,0.0005264, +-0.005226,0.008804,0.005707,-0.00763,-0.00875,0.0002716,-0.00251,-0.00646,-0.00666, +0.00936,0.005447,-0.00562,0.00967,0.001811,-0.00963,0.001052,0.00807,-0.002794, +-0.00845,0.00685,-0.003199,0.003119,-0.004333,0.0001079,-0.00884,-0.002384,-0.0008464, +-0.0053,0.0008607,0.005,0.003218,-0.001972,0.003925,-0.000635,-0.003868,-0.00636, +-0.005894,0.0005355,0.00921,-0.006687,0.00629,-0.001168,-0.00646,0.005547,-0.00963, +-0.004078,0.002125,0.008995,0.006187,0.007397,-0.00656,-0.006527,0.006042,-0.001503, +-0.00624,0.003023,-0.009995,-0.002466,0.00351,0.003439,-0.003235,0.008026,0.004158, +0.003117,-0.005856,0.00461,-0.001134,0.004257,0.00933,0.00992,-0.008156,0.004356, +0.00917,-0.007904,0.0004003,-0.00912,-0.003895,-0.005566,-0.00899,-0.0001261,-0.00272, +-0.00529,-0.005215,-0.000558,-0.006172,0.008354,0.000414,-0.004574,0.00527,0.004333, +-0.00728,-0.00797,0.0096,-0.00344,-0.00881,-0.00368,0.00844,-0.00517,-0.005783, +-0.002708,-0.006958,0.00088,0.007393,0.002115,0.00502,-0.007347,0.002518,-0.007164, +0.003891,-0.006386,0.004723,-0.007137,0.00979,0.00728,-0.007385,-0.003569,-0.001245, +0.007244,-0.004177,0.005627,-0.001364,0.007786,-0.003647,0.00975,0.003262,0.006668, +0.007492,-0.002676,0.00452,0.00613,0.009895,-0.0000653,-0.0002944,0.0095,0.00829, +0.003607,-0.00763,0.001573,0.00708,0.001338,0.00761,-0.00934,0.00425,0.004677, +0.004356,-0.00835,-0.003391,-0.00722,0.00877,0.001739,-0.0078,-0.003801,-0.002934, +0.00592,-0.00832,-0.005596,0.00847,0.002663,-0.002655,-0.00461,0.001812,-0.005447, +0.00393,-0.0001626,-0.0099,-0.005177,-0.000107,-0.004513,-0.00942,-0.004494,-0.0002584, +0.00558,0.00919,0.00483,-0.003881,0.0000862,0.00472,0.002277,0.00452,-0.005043, +-0.00812,0.006695,-0.001397,0.00708,0.00666,0.009445,0.002443,0.00672,0.00742, +0.0047,-0.0099,-0.001733,-0.001216,0.002306,0.00525,0.006687,0.007397,-0.004185, +-0.007645,0.00497,0.002726,-0.004883,0.00545,0.001207,-0.003443,0.00855,-0.008575, +-0.00995,0.00938,0.001395,-0.005894,-0.004715,0.001335,0.007214,-0.00979,-0.0009723, +-0.00884,-0.00325,-0.006447,-0.0002873,-0.006546,-0.00914,0.00311,0.001508,-0.008644, +0.003849,-0.00224,-0.0073,0.004158,-0.007076,-0.00458,-0.002794,0.00691,-0.00991, +-0.002531,-0.007236,0.00291,0.003098,-0.00666,0.00618,-0.001502,-0.008026,0.0001609, +-0.001733,0.00476,0.007725,-0.007076,-0.005398,-0.001904,0.002743,0.001987,0.002935, +0.006363,0.007755,-0.002127,-0.002626,0.003273,0.0044,-0.003975,-0.00273,-0.001413, +-0.008736,-0.005775,0.00445,-0.007412,-0.00647,0.0046,0.007393,-0.0003533,-0.00926, +-0.006104,0.001658,0.00642,-0.00962,0.00724,-0.00032,-0.00848,-0.007442,0.001179, +-0.004684,-0.001757,0.002796,0.00741,0.002192,0.003952,0.002794,-0.00581,0.00923, +-0.000795,-0.008545,0.0004318,0.007034,0.001034,-0.009224,0.0037,0.00736,-0.007587, +-0.001963,0.00037,-0.001584,-0.0001048,0.00979,-0.007168,0.003159,0.00205,-0.0082, +0.000802,0.00919,0.005257,0.000411,0.006824,0.00543,-0.00202,-0.008705,-0.0084, +-0.0008135,-0.001487,-0.00698,0.00766,0.0003076,0.002989,0.00785,0.004498,0.004917, +0.001951,0.00489,-0.000938,0.00438,-0.00010777,0.00993,-0.003304,-0.00859,0.00656, +-0.009926,0.00572,0.009445,0.004425,0.00595,0.005547,-0.00555,0.00912,-0.00391, +0.00417,-0.00732,-0.00944,-0.001693,0.003319,0.007904,0.004158,0.008026,-0.004173, +0.00174,0.00794,0.001028,-0.0004673,-0.01,0.005222,0.00968,0.00173,-0.00965, +0.00775,0.00758,-0.006916,-0.006714,0.001373,-0.00906,0.005737,-0.00403,0.003036, +-0.00832,-0.001393,-0.00903,-0.007996,-0.001152,0.00698,-0.00907,0.00455,0.0006533, +-0.001487,-0.0074,0.005177,0.00607,0.006973,-0.002907,-0.008446,0.004932,0.00457, +-0.001466,0.007805,0.002241,-0.002304,-0.006294,-0.00625,0.002876,0.005146,0.000603, +0.00309,-0.00912,0.002026,0.0096,-0.000262,0.00007397,0.001089,-0.00799,0.00948, +-0.0007935,-0.00997,0.001588,0.009674,-0.0006795,0.00958,0.00604,-0.00975,-0.001219, +-0.005093,0.00061,0.0002333,0.006195,0.006245,0.00548,0.006554,0.009155,0.003277, +-0.0027,-0.002827,0.002981,0.00059,-0.00643,0.001903,0.006195,-0.001568,-0.002792, +0.001151,-0.00969,0.0001194,0.006084,-0.00789,-0.00746,-0.000923,-0.002726,-0.0009117, +-0.009155,0.0003529,0.002682,0.00394,0.0003521,-0.006798,0.,0.006145,-0.006645, +-0.0000278,0.005737,-0.003601,0.008156,0.006905,0.00996,0.00752,0.00513,-0.001212, +-0.005558,-0.009796,-0.009056,0.001026,-0.003756,0.002048,0.00501,0.004303,0.00885, +-0.002895,0.00885,0.00881,0.008965,-0.00772,0.000675,-0.00361,0.009254,0.00947, +0.002851,-0.00443,-0.0008383,-0.001255,0.007088,-0.00718,-0.001156,0.00496,0.00543, +0.009575,-0.00932,-0.00289,-0.00961,-0.005413,0.00887,0.008194,0.007217,0.001349, +-0.00616,-0.00132,0.008255,0.008354,-0.001022,-0.00916,0.0012,0.00942,-0.005272, +-0.007713,0.00924,-0.002554,0.00812,0.002947,0.006466,0.007267,0.004383,0.006683, +-0.004047,-0.001562,0.0000953,-0.00198,-0.001826,-0.005013,0.008095,-0.00878,-0.006645, +0.005096,-0.0003052,-0.00815,-0.00986,0.0081,0.00661,-0.00097,0.006916,-0.007244, +0.004272,0.00444,-0.00546,0.003994,-0.00191,0.001437,0.00408,-0.000537,-0.007557, +0.0009537,-0.00972,-0.006805,-0.007835,-0.000847,0.005665,-0.0085,0.005657,0.006027, +-0.009285,0.00652,0.005535,0.009224,0.0007205,-0.00692,-0.00881,0.005817,-0.00506, +-0.00877,-0.00991,-0.001778,-0.002598,-0.00755,0.003616,0.00898,0.002537,-0.001853, +-0.000725,0.00202,0.001978,-0.0008383,0.004784,-0.0003638,-0.00895,0.00243,-0.00395, +0.001955,-0.002853,-0.005,0.00976,-0.0006366,-0.002913,0.002592,-0.00857,-0.0006256, +-0.0001568,0.003605,-0.001659,0.000935,-0.005302,0.00593,-0.002056,0.003723,0.005863, +0.0089,-0.004147,-0.007706,0.0006566,0.003222,-0.00247,0.005234,-0.009605,-0.00279, +0.00031,-0.008606,-0.00952,0.001459,0.008446,-0.00921,0.00895,-0.00951,-0.002565, +0.00084,0.006874,-0.004066,0.004723,-0.0006924,0.00932,0.003325,-0.006763,0.004936, +-0.003439,-0.000998,-0.008224,-0.00412,0.006996,-0.007057,-0.00992,-0.004974,0.001361, +-0.009865,0.00982,-0.00375,-0.002928,0.00166,-0.007782,-0.001827,0.000567,-0.002838, +-0.0002354,-0.00259,-0.00849,-0.001284,0.002161,0.001709,-0.00802,0.00199,-0.003202, +0.002773,0.009056,-0.001113,-0.006054,-0.00209,0.007355,0.008194,-0.005627,-0.005226, +-0.00478,0.001043,0.002869,-0.00657,-0.003176,-0.004704,-0.004574,-0.00434,0.007328, +0.00895,-0.00853,-0.006207,-0.00928,-0.009476,0.009125,0.004627,-0.004642,-0.004658, +0.00919,0.003496,0.002165,0.00413,-0.007694,0.003744,0.001043,0.002182,-0.00698, +-0.003906,0.00365,0.003763,-0.0043,0.002554,0.0094,0.00586,-0.00655,-0.00171, +-0.0009985,-0.00851,0.00584,0.004883,-0.007523,0.005016,0.003046,0.005917,-0.006622, +0.00741,-0.002499,0.0004418,-0.003113,0.0003803,0.003252,-0.00917,0.00506,-0.006687, +-0.00916,0.000701,0.00945,-0.002863,0.00827,0.00938,0.003405,-0.00935,-0.00912, +0.00259,0.001822,-0.00674,0.0008016,-0.001132,0.00899,0.001555,-0.0007024,0.00899, +-0.00938,-0.00109,-0.00674,0.001553,0.00696,0.009415,0.0005765,-0.0002084,0.004097, +0.005985,0.001656,0.005325,-0.00839,0.003904,0.00822,-0.003994,0.00635,-0.000794, +-0.00667,0.002296,-0.002838,-0.00975,-0.001081,0.005127,0.001922,0.005127,-0.008156, +-0.006653,0.00935,-0.00302,-0.00052,-0.005894,-0.009674,-0.00613,0.009705,-0.006924, +0.004726,0.004784,-0.00146,0.001746,-0.002958,0.009636,0.005665,-0.000724,0.004875, +-0.001856,-0.002975,0.0071,0.002045,0.00507,-0.007042,-0.006958,0.002089,-0.003504, +0.0004888,-0.005943,0.007607,-0.003822,-0.004692,0.0001357,0.004456,-0.00799,-0.006413, +0.002268,0.00888,-0.00872,-0.004936,-0.0091,-0.00353,-0.0052,-0.003223,-0.00825, +0.003952,-0.002771,0.006344,0.00862,0.00904,-0.00221,-0.0001844,-0.00227,0.000672, +-0.004852,-0.005795,-0.002771,-0.00653,-0.002579,0.006954,0.002605,-0.00804,0.00432, +0.0000249,-0.004536,-0.008514,0.00618,-0.002804,0.00895,-0.009094,-0.009155,-0.003836, +-0.0008125,0.007385,0.00554,-0.0004065,-0.00517,-0.006493,-0.007027,0.003748,-0.00834, +-0.006668,0.00982,-0.001279,-0.0008125,0.000629,0.003786,-0.00859,-0.000755,0.0004015, +-0.003065,-0.007042,-0.00967,0.0004108,0.00947,-0.007076,-0.0006723,0.006496,-0.001414, +0.008194,-0.000413,0.008125,0.00146,-0.006462,0.002676,-0.005474,-0.003166,0.006027, +0.001129,0.001874,0.001855,0.00766,-0.006634,-0.000823,-0.00303,0.005795,0.00279, +0.002512,0.006172,0.006474,0.000632,-0.007507,0.001753,-0.002531,0.002895,-0.007034, +0.004955,-0.0096,0.007793,-0.00803,-0.0095,0.006615,-0.00854,0.00214,0.00532, +-0.00995,0.00772,0.006977,-0.00873,-0.00617,-0.00808,-0.00479,-0.00397,0.00456, +0.003944,0.0001737,0.001538,-0.005756,0.009964,0.002096,-0.00984,0.001642,0.003113, +-0.00802,-0.003527,-0.00876,0.003502,-0.00562,0.003378,0.006676,0.000644,0.002071, +-0.00587,-0.00771,-0.0009327,-0.00441,0.007095,0.005478,0.00781,0.00952,0.006176, +0.0003223,0.00818,0.00678,-0.004147,-0.00999,0.00903,-0.00987,0.007553,-0.00438, +0.005028,0.0003302,0.0002394,-0.005104,-0.002537,-0.005333,0.004635,-0.005787,-0.005177, +-0.005615,-0.00463,0.0001181,-0.00814,0.00656,-0.00132,0.003115,-0.006237,-0.00123, +-0.008804,-0.002682,-0.00877,0.00749,-0.00863,0.004997,0.007736,-0.00963,-0.002966, +-0.00405,-0.004005,0.006763,-0.00639,0.000797,0.002903,0.00967,-0.0009356,-0.00675, +0.00917,-0.0048,0.0088,0.007168,0.00394,0.005524,0.0002052,-0.0004148,0.0059, +-0.002966,0.008,-0.00955,-0.008484,0.00856,0.003498,-0.005703,0.004974,0.0089, +-0.004208,-0.005203,-0.007496,0.003206,-0.007713,-0.0068,0.00437,0.008896,0.0007954, +0.002823,-0.002413,-0.004665,0.0007997,-0.005394,0.00806,-0.001563,-0.001497,-0.005314, +-0.00952,0.0093,0.005066,0.00407,0.004482,-0.00788,0.001537,0.00806,-0.005013, +-0.003735,0.00956,-0.00946,0.002008,-0.006847,0.003038,0.003141,-0.005787,0.005665, +0.002735,-0.002401,0.003057,0.000753,0.004444,0.00805,0.001004,-0.0065,-0.001637, +0.0065,0.004467,-0.00896,-0.006573,-0.007236,0.007435,-0.00392,-0.001908,-0.008736, +-0.0007854,0.000625,0.003866,-0.002039,-0.002193,-0.006447,-0.00793,-0.002161,-0.0073, +0.00472,0.001314,0.006416,-0.009224,0.00668,0.008865,0.009155,-0.004684,0.00807, +-0.0008855,0.002748,0.001529,-0.004765,-0.001041,0.00859,0.005573,0.00433,-0.009155, +-0.007614,0.00472,-0.0009365,0.00003576,0.002872,-0.003223,0.003098,-0.001782,0.001795, +0.006645,0.002974,-0.0094,0.005337,0.00877,-0.00649,0.00959,-0.008156,-0.0008917, +0.006607,0.00905,-0.001238,-0.001246,-0.002775,-0.002815,0.00451,-0.004486,0.003998, +0.00956,-0.00981,0.005096,-0.00876,-0.002571,0.002287,-0.002996,-0.008896,-0.006973, +0.003885,0.001993,-0.006523,0.0048,-0.005745,0.004883,0.005627,-0.00919,0.00978, +-0.000961,0.00954,0.003023,0.006172,-0.00371,-0.00509,-0.00392,-0.00989,0.00212, +-0.00917,-0.009865,0.00965,0.003618,-0.004303,0.00628,0.002913,0.0086,-0.00881, +0.004963,-0.006886,-0.00000197,-0.008736,0.004147,-0.003227,-0.001696,-0.003815,0.00957, +-0.00994,-0.006596,0.00925,0.007454,-0.001091,-0.0004747,0.009026,0.00854,0.00133, +-0.00263,0.00543,0.003836,0.004856,-0.006695,0.005478,-0.008415,0.003187,-0.00998, +0.009514,0.002903,-0.005165,-0.0004752,-0.009,-0.008965,0.005806,0.006153,0.00893, +-0.00877,-0.006866,0.004154,-0.008125,0.007202,-0.005573,0.004,-0.002998,0.002878, +0.005672,0.00607,-0.004578,0.001471,-0.002363,-0.00006247,0.0007734,0.001287,-0.0006113, +0.003868,-0.00696,-0.003672,0.00688,-0.00908,-0.00665,0.003775,-0.006355,-0.005634, +0.00421,0.00937,-0.004856,0.002947,-0.003933,-0.0086,0.00988,0.00546,-0.0008826, +0.00433,0.007183,0.002195,-0.005333,0.006683,0.003277,0.001082,0.00579,-0.00623, +-0.00966,-0.002708,0.00627,0.00581,-0.0095,0.008896,-0.002478,-0.00966,0.007526, +-0.001696,0.002949,0.001381,-0.00684,-0.005974,0.00413,0.00085,0.004032,0.004807, +0.0004041,-0.006992,0.003105,-0.0002321,0.00867,0.00237,0.00464,-0.00887,-0.005978, +-0.005844,-0.00826,0.005035,0.00953,0.006485,-0.00415,-0.00873,-0.006836,0.00572, +0.001606,-0.00828,-0.001708,-0.006145,0.00914,-0.00965,0.005646,-0.00857,0.006638, +0.00327,0.00424,0.001341,0.003788,-0.000685,0.0061,-0.00782,0.003334,-0.0068, +0.001557,0.005825,-0.0058,-0.000689,0.007496,0.00708,-0.006107,0.007668,-0.001199, +-0.00948,0.00668,-0.003176,0.003733,-0.001616,0.006714,0.00789,0.001432,0.004112, +0.00384,0.009636,0.007053,-0.00374,0.00495,0.00959,0.004135,0.00721,0.007225, +-0.0008454,0.008286,0.0000413,0.003618,0.004047,0.00454,-0.0079,0.00869,0.00706, +-0.007492,0.00493,0.00689,-0.0005245,0.00604,0.00357,0.00598,-0.00959,-0.003292, +0.0008936,0.00904,0.002445,0.00894,0.00819,0.003876,0.002953,0.003384,-0.006687, +0.002918,-0.0056,-0.0003066,-0.001384,0.007675,0.0009513,-0.007656,0.00804,-0.000968, +-0.000649,0.00913,-0.0041,0.0002625,-0.0001359,-0.008865,0.002167,0.00687,-0.00606, +0.0003486,0.0003984,-0.004803,0.006454,-0.004997,0.00892,-0.007423,-0.001277,-0.007504, +0.00762,0.003056,0.001508,-0.00391,0.00859,-0.00768,-0.003675,0.002884,0.006508, +0.000506,0.002567,0.007607,-0.003233,0.0073,0.003862,-0.003817,0.00735,0.002506, +-0.00823,-0.006706,0.005676,-0.00931,-0.004025,0.006542,0.000566,0.00919,-0.002083, +-0.00783,0.0013485,-0.00839,0.0089,-0.0066,0.009674,-0.00821,0.0061,-0.002129, +0.00598,0.008865,0.00513,-0.00582,-0.00459,-0.00962,-0.00962,-0.005966,-0.007187, +0.00995,0.004295,0.004467,0.001008,-0.00809,0.00922,-0.00768,-0.00994,-0.005596, +0.006706,0.00748,0.00942,-0.00396,0.001708,-0.00961,0.005653,0.00976,-0.001643, +0.003786,-0.002264,0.002747,-0.0003808,0.000354,0.001055,0.00584,0.006306,0.005363, +-0.006443,-0.0005603,0.00871,0.00683,-0.002083,-0.00611,-0.006573,-0.0027,0.004917, +0.006207,0.004932,-0.00669,0.005665,0.002796,0.00901,-0.000798,0.001478,0.003788, +0.000707,0.00934,0.005985,-0.00145,-0.0008683,0.00339,0.002144,0.006596,0.00984, +0.00258,0.0048,0.0003848,-0.002644,-0.002129,-0.001171,-0.002369,-0.007328,0.00841, +-0.005325,0.00968,-0.00982,-0.003754,-0.0006895,0.00784,0.003864,0.008316,-0.003483, +0.004986,-0.003044,-0.005714,-0.001846,-0.001568,0.0003648,0.00724,0.006336,-0.003222, +-0.006836,0.001214,-0.003124,-0.0006356,-0.001073,0.002682,-0.007538,-0.001701,-0.00883, +0.00986,0.006336,0.0011,-0.00879,-0.005875,0.004025,0.00613,0.004856,-0.008896, +0.0006967,0.0064,0.002707,-0.002317,-0.002214,0.002409,-0.000346,-0.006924,0.001986, +-0.003166,0.00836,-0.00899,0.0034,-0.007755,0.00407,0.00807,0.0076,0.003824, +0.003876,-0.00853,-0.00649,-0.003506,0.001777,-0.009705,-0.00516,-0.0094,0.00939, +-0.00786,-0.00911,-0.000737,0.000864,-0.00851,0.00786,-0.003422,-0.00832,-0.0007277, +0.005642,-0.00868,-0.002851,0.0005975,-0.007347,-0.001616,-0.001303,0.00717,-0.00231, +-0.008354,-0.005333,0.00864,0.006123,-0.00994,0.00313,-0.00676,-0.005806,0.008446, +-0.0007553,-0.006416,0.00223,-0.00579,0.00576,-0.00892,0.002424,-0.00486,0.00636, +0.003344,-0.003195,0.001562,0.00318,-0.007202,-0.001358,-0.0001854,0.002499,0.001725, +0.000389,-0.006737,0.002745,0.000575,-0.003534,0.004284,0.0019045,0.004898,-0.004356, +0.002254,-0.00577,0.0018215,-0.008736,0.00769,-0.00885,-0.00859,-0.00441,0.00583, +-0.009285,-0.00792,-0.00922,-0.003815,-0.00886,-0.005394,-0.00663,-0.008224,-0.00353, +0.002161,0.00301,-0.00542,-0.0085,-0.007446,-0.00846,-0.00515,0.00204,0.00543, +-0.001219,-0.007072,0.001966,-0.00894,0.0008793,-0.003418,0.00393,-0.005283,0.005756, +0.003225,0.002123,0.002283,0.00566,0.000477,0.00497,0.005295,0.002136,0.00692, +0.00872,0.00936,-0.005074,0.00645,-0.001117,0.006493,-0.00574,0.001013,0.003334, +-0.005703,-0.006992,-0.004314,0.005314,0.001457,-0.00594,-0.003252,0.00844,0.002502, +0.002604,0.00289,0.00221,-0.003344,-0.006905,-0.00799,0.007378,-0.00945,0.006023, +-0.00791,0.001273,0.003849,0.007694,0.005424,0.00298,-0.003618,-0.0001827,0.002077, +0.001976,-0.006474,0.00079,0.00982,0.004166,0.007027,0.008606,0.00818,0.00697, +-0.003006,0.0045,-0.00885,-0.00515,0.00723,-0.0001746,-0.00727,0.006237,-0.008385, +0.008194,-0.008316,-0.002525,0.002558,0.00639,0.003586,-0.00612,-0.006756,-0.008354, +0.004883,-0.00506,-0.009,-0.00537,-0.001243,-0.005596,-0.00853,-0.007545,0.00786, +0.001839,-0.002245,0.00544,-0.00196,0.004967,-0.003464,-0.005108,0.003086,0.002628, +-0.002502,-0.00665,-0.006226,0.0079,-0.002287,0.0003567,-0.001279,0.004826,0.005432, +-0.00634,-0.003204,0.0002022,-0.00198,-0.0008726,0.004055,0.00793,-0.00427,-0.00533, +0.00734,-0.00799,-0.0051,-0.009995,0.0051,0.00413,-0.00679,0.00262,0.001331, +0.001461,-0.00865,-0.00791,-0.003975,0.002504,0.0002255,0.002337,-0.00456,-0.005974, +0.000257,-0.00545,0.00842,0.005585,-0.0003774,0.0008087,-0.001679,0.003853,0.00991, +0.0031,0.00523,-0.00721,0.000989,-0.005642,-0.001042,0.007935,-0.006195,0.001426, +0.00414,0.00925,-0.00419,0.004852,-0.00639,0.00694,-0.007706,-0.00684,-0.00602, +-0.004444,0.005016,-0.00803,-0.00955,0.004097,-0.003754,0.002384,-0.007515,0.003508, +-0.00749,0.00519,0.00228,0.007015,-0.007572,-0.003864,-0.00843,0.00543,0.00911, +0.00774,0.009125,-0.003473,-0.00646,0.00856,0.004272,0.00534,0.003859,-0.0001141, +0.001515,0.003437,0.00737,0.003565,-0.002705,0.003675,0.003023,-0.0002156,-0.00894, +0.00103,-0.001797,-0.00854,0.001505,-0.00876,-0.003614,0.004887,-0.005085,0.002449, +0.00524,-0.00589,0.00784,0.001411,-0.0095,0.007797,-0.003391,0.008316,0.0094, +0.00917,-0.00658,-0.00685,-0.005085,-0.005375,0.008705,-0.004093,0.00764,-0.006172, +-0.00609,-0.0005703,-0.00941,-0.007065,0.00942,0.00403,0.00392,-0.0000164,0.000577, +0.001058,0.006317,0.0008893,0.001935,-0.009865,-0.00542,0.001452,0.00916,-0.00852, +-0.00081,0.00397,0.0069,0.003246,-0.004456,0.00777,-0.004444,0.003632,-0.002512, +-0.00284,0.009926,0.00869,-0.00636,-0.006454,0.006805,-0.00232,-0.00924,0.006268, +0.00501,-0.00951,-0.00518,0.006126,0.00966,0.00881,-0.009346,0.00912,0.00341, +0.00617,0.00984,-0.00357,0.00596,-0.0081,-0.0006824,-0.00711,0.004803,0.00484, +-0.000756,0.002865,-0.00422,0.00005835,0.00912,0.000726,0.001402,0.00644,-0.006542, +0.006016,0.003975,0.00556,0.0000735,-0.002203,0.003893,-0.000724,0.005882,-0.006226, +-0.006912,0.003027,0.0004182,-0.00728,-0.00726,-0.00896,0.008095,-0.001346,0.00898, +0.002956,-0.003334,-0.007717,-0.00876,0.00037,-0.00727,-0.003258,0.009476,0.009056, +0.00598,0.00281,0.00586,-0.00981,-0.003296,0.00769,-0.000486,0.0091,0.00634, +-0.00542,0.00512,-0.002474,-0.009514,0.00402,-0.004787,0.00274,-0.001112,-0.002436, +0.00949,-0.000839,-0.009155,0.002499,0.001512,0.001406,-0.00313,-0.002022,-0.008896, +-0.00528,-0.009254,-0.002148,-0.000707,-0.0001829,-0.001159,0.00411,-0.007637,-0.00364, +0.005135,-0.00928,-0.0000797,0.004642,-0.00817,-0.007072,-0.003914,0.00416,0.002985, +-0.0075,-0.000736,0.008934,0.004204,0.0004723,0.006306,-0.007675,-0.007835,0.0005293, +-0.002478,-0.006336,0.007996,0.002539,0.001836,0.00968,0.006844,0.001179,0.001448, +0.006042,0.00292,-0.007122,-0.001914,0.004448,0.00822,0.00672,0.000714,-0.001145, +0.009415,0.0015335,-0.005585,-0.006104,-0.0003273,-0.00987,0.001559,-0.00608,0.007664, +0.00834,-0.0002584,-0.004097,0.00745,0.005417,-0.002129,0.001597,0.00749,-0.001676, +0.006344,0.006905,0.004364,-0.00739,-0.001457,0.00806,-0.008,-0.004284,-0.00717, +0.00547,0.004463,0.00529,-0.00843,0.008064,0.00556,0.0005236,0.00918,-0.004986, +0.00578,-0.001013,-0.003479,-0.004425,-0.0076,-0.004093,0.003084,-0.00531,-0.00902, +-0.002844,0.004982,-0.00986,0.003986,0.002125,0.004036,-0.006798,0.000773,0.000544, +-0.0001241,0.009155,0.002682,-0.00997,-0.00826,0.003769,0.001383,-0.005318,0.004673, +-0.005314,0.00691,0.00212,-0.00656,-0.006226,-0.008705,0.00459,-0.003798,0.00869, +-0.002985,-0.000604,0.00826,-0.00541,-0.00502,0.000809,-0.00969,-0.006626,0.005123, +-0.0005465,-0.00858,0.005554,-0.002083,0.007343,-0.001588,-0.001642,0.0007577,0.00318, +-0.00391,0.00404,0.00886,-0.006374,-0.00958,-0.005077,-0.00218,0.00745,0.00944, +0.007233,0.003042,-0.003296,0.006786,-0.006706,0.007114,0.00566,0.005325,0.007637, +-0.00661,0.0008025,-0.002693,0.005634,0.001557,-0.007133,-0.00483,-0.00654,0.006313, +-0.00926,-0.00372,-0.00583,-0.004025,0.00761,0.00955,0.002691,-0.00915,-0.006084, +-0.008835,0.003885,0.009514,-0.00841,0.003637,-0.00765,-0.005978,0.001959,-0.005295, +-0.001565,-0.003551,-0.000824,0.005848,-0.00010514,0.00828,-0.003895,-0.003197,0.00797, +0.00998,0.004635,0.006504,0.007023,-0.00675,0.001584,0.004642,0.007458,-0.002005, +0.0000653,0.00715,0.00402,0.00782,-0.00331,0.00676,0.000039,0.00644,-0.0007744, +0.005688,0.00511,-0.005135,0.000995,0.006756,-0.002304,0.003553,-0.00938,-0.000616, +-0.00897,-0.00685,-0.00838,0.003983,-0.004807,0.002314,0.00847,0.00846,-0.007507, +0.002136,0.005905,-0.00899,0.0081,0.008,0.00889,-0.00907,-0.00489,0.00938, +-0.009254,0.00627,0.0052,-0.002031,-0.0006337,-0.001191,0.001453,-0.003918,0.001798, +-0.00491,-0.002062,-0.00889,0.00309,0.007526,0.0007014,-0.001351,-0.003838,0.00458, +0.004005,-0.00923,0.00581,-0.002983,-0.00901,0.007095,0.00844,-0.00989,0.001532, +-0.00867,0.001821,-0.005646,0.00698,-0.001757,-0.00102,-0.00511,-0.007774,0.002588, +-0.006096,0.005196,-0.002117,-0.0003762,0.00738,0.001219,0.00447,0.00867,-0.00494, +0.007313,-0.008095,0.000967,0.004776,0.00296,0.001068,0.00818,0.00749,-0.00939, +-0.00738,-0.006214,-0.00685,0.00569,0.00716,0.004375,-0.00512,-0.006252,-0.004684, +-0.002974,-0.007965,0.0025,-0.00943,0.00539,0.0003204,0.0005164,-0.006573,0.00646, +0.00502,0.007965,-0.002003,-0.00609,-0.009285,-0.005028,-0.00985,0.001395,0.00415, +0.003494,0.00957,0.009834,-0.005905,0.002436,0.001002,-0.002335,-0.00981,0.006714, +0.005135,-0.003138,-0.00786,0.005497,0.003677,0.00479,-0.00453,0.00845,0.007454, +0.000992,-0.00647,0.001218,-0.004295,0.00004745,0.005558,-0.002914,0.00861,-0.008064, +0.003328,-0.003998,-0.007595,0.00487,0.0008106,0.005287,-0.003735,0.003054,0.006645, +-0.002422,0.00974,-0.001171,0.006264,0.00908,0.002903,0.00446,0.002419,0.00806, +-0.002483,0.0089,0.0004303,-0.001789,-0.00638,-0.005802,-0.00953,-0.00526,0.006203, +-0.001033,-0.00721,0.00391,0.00923,0.006676,0.00495,-0.002512,-0.000916,0.005054, +-0.007652,0.004738,0.00826,-0.00989,-0.00202,-0.00824,-0.004333,0.002779,-0.00531, +0.00181,-0.00475,0.005234,-0.00558,0.002342,-0.001395,-0.005856,0.004074,-0.00638, +-0.003561,0.00819,0.006454,-0.00402,-0.008766,-0.006668,-0.00244,-0.00392,-0.007248, +-0.00666,0.001226,-0.0071,0.00746,0.00396,-0.00057,0.0001602,0.006924,-0.0004158, +-0.000988,-0.008385,0.004936,-0.001231,0.00533,0.00905,0.0015335,0.003677,0.00751, +-0.00807,-0.0051,0.00774,-0.000592,0.003368,-0.001825,-0.003403,0.008194,-0.0004606, +0.00312,-0.004196,0.008026,0.004883,-0.003073,-0.006607,0.00847,-0.007446,-0.00982, +-0.002375,0.009186,0.00991,0.005642,-0.00632,-0.005085,0.0084,0.002087,0.004, +0.002495,0.004326,0.00969,-0.003504,0.008514,0.000959,0.003632,-0.001369,0.005737, +0.002361,-0.00802,-0.006603,0.007866,-0.008675,0.009384,0.001016,0.006927,-0.005165, +0.001802,-0.002798,0.008415,0.00439,0.003819,0.002295,0.006844,-0.006813,0.0003488, +0.000659,0.00963,-0.00946,0.002861,-0.00614,0.002499,-0.00706,0.003216,-0.003124, +-0.004585,0.001135,-0.00212,0.007435,-0.003775,-0.0001405,-0.000892,0.006218,-0.005333, +0.007397,0.003202,0.009026,0.003717,0.00787,0.005188,0.0002823,-0.0052,0.00797, +-0.0009027,-0.006462,0.00908,-0.001527,0.005005,0.005547,0.00665,-0.002155,-0.00641, +0.00467,-0.002872,0.000676,0.0009217,0.00424,-0.000898,0.00932,0.004444,-0.009834, +0.00908,-0.0000113,-0.00378,0.00792,-0.00931,-0.002563,0.003622,0.00972,-0.0066, +-0.002348,-0.00787,0.004368,-0.00385,0.0099,0.00617,-0.001304,0.008575,-0.00803, +-0.008354,0.00794,-0.00924,0.0069,-0.00811,0.000215,-0.00519,-0.001069,0.000882, +-0.007378,0.006447,-0.003225,-0.00484,-0.00356,-0.0004394,-0.002144,-0.001932,0.0007205, +-0.00976,0.008514,-0.006294,0.00618,-0.001758,-0.00713,-0.00912,0.004726,0.00334, +0.00847,-0.0001967,0.005165,-0.004944,-0.00915,0.0062,-0.00553,0.0084,-0.0054, +0.002823,0.00272,-0.00271,-0.009514,0.00629,-0.006054,0.008865,-0.00813,-0.0076, +0.00857,-0.003681,-0.00738,-0.00872,-0.001488,0.00926,-0.001791,0.00471,-0.00482, +0.007812,-0.004654,-0.006138,0.003813,0.005768,-0.00375,-0.00992,-0.000584,0.00783, +-0.004147,0.001611,0.001342,-0.006832,-0.00138,0.005325,-0.0000265,0.009445,0.00872, +0.001329,-0.0026,0.002577,0.0072,0.00547,0.006428,-0.004864,0.00876,-0.00906, +0.007317,-0.007233,-0.00774,0.003387,-0.002037,0.00125,0.00655,-0.003298,0.008514, +-0.003757,0.007935,-0.003181,0.00629,0.00838,0.0009594,0.006897,-0.008835,0.00446, +-0.0082,-0.006042,0.00761,-0.00883,0.002434,0.001002,0.00712,-0.005688,0.003359, +-0.00606,0.002512,0.00576,0.006126,0.0009394,-0.00787,-0.00485,0.005936,0.002037, +-0.0024,-0.00618,-0.00157,0.00702,-0.007637,0.0077,-0.00784,-0.0062,-0.00975, +-0.00849,0.00843,0.003843,-0.006443,0.004993,-0.0001615,0.00902,0.00811,0.005333, +0.002123,0.001081,0.0086,-0.003103,0.005783,0.004936,-0.00898,0.001179,0.0007, +0.003462,-0.00855,0.00254,-0.0000039,-0.00468,0.0012455,0.003431,0.007538,0.0082, +0.00843,-0.001547,0.006157,0.001941,-0.0013895,-0.003096,-0.003883,-0.006382,-0.00475, +0.008766,-0.003225,0.0008793,-0.002806,-0.00432,0.003944,0.008286,0.003141,-0.00975, +-0.00439,-0.007645,0.0093,0.005238,-0.002018,-0.006023,-0.001462,0.00286,0.00525, +0.005463,-0.0005217,-0.0003283,-0.003103,-0.007656,-0.003311,-0.0002983,0.005165,0.007187, +0.00674,-0.002645,0.00882,0.009995,-0.003174,-0.002956,-0.00978,0.00841,0.005043, +0.00798,0.00003827,-0.004494,-0.00883,-0.0003128,-0.0015955,0.00958,0.001948,-0.007664, +-0.002064,0.002949,0.008736,0.00684,0.00804,0.004642,-0.000742,0.001874,-0.004864, +0.0003529,-0.001284,0.00896,-0.006954,-0.003616,0.0078,0.00815,-0.00876,-0.002783, +-0.00649,0.00976,0.009125,0.0019,-0.0004215,0.00461,0.001037,0.009384,0.003422, +0.001194,0.00923,0.00554,-0.00855,-0.001592,-0.002981,0.006016,0.002314,-0.00483, +0.002476,-0.00894,-0.000574,0.0096,-0.0002362,-0.002018,0.00283,0.00251,-0.0001559, +-0.00557,0.00661,-0.002537,0.005524,0.00961,-0.002073,0.00454,-0.006428,0.001997, +-0.00446,-0.0007524,0.002176,-0.00209,-0.00874,0.001289,0.00523,0.001575,-0.008736, +0.007057,-0.0069,-0.00512,-0.005383,0.0001678,0.001076,0.007683,-0.006207,-0.006233, +-0.00585,-0.004894,0.00773,0.00627,-0.0008707,-0.00574,-0.002068,-0.0003157,-0.00921, +-0.006275,0.007275,-0.0004473,0.002474,-0.009186,0.001432,0.003687,-0.004425,-0.002018, +0.00922,-0.00788,0.000894,-0.001047,-0.001193,0.009094,-0.0039,0.00977,0.00951, +0.00976,0.002201,0.006214,-0.002117,0.006203,0.00278,-0.006725,-0.006157,0.003757, +-0.001729,0.005405,-0.00904,-0.000435,-0.002148,-0.00849,0.00923,-0.008194,-0.001804, +-0.00392,0.0002866,-0.007317,0.005623,-0.002657,-0.005657,0.006363,0.00205,0.005215, +0.00376,0.001134,-0.003138,0.00569,0.008446,-0.003283,0.004047,-0.00322,-0.001756, +-0.006763,0.001577,-0.007225,0.006092,0.004112,-0.006554,-0.00428,0.004684,-0.000417, +0.00418,-0.000349,-0.00676,-0.004097,-0.00899,0.004936,0.00864,-0.006325,-0.004665, +-0.00834,0.00238,0.006153,-0.00914,0.004246,-0.00963,0.003986,0.00887,0.00852, +0.0002384,0.007866,-0.002577,0.0007524,-0.004887,-0.0003715,0.00564,0.008606,-0.009705, +-0.009796,-0.001706,-0.00965,0.00824,0.0009446,-0.00514,0.00492,0.002787,0.00643, +-0.0002482,0.003603,0.004097,0.00916,-0.005463,-0.003786,0.00269,-0.00688,0.002872, +0.0079,0.002403,-0.000562,0.00747,-0.00349,0.004925,-0.009,-0.003199,-0.0008674, +0.004513,0.001112,0.00242,-0.003345,-0.00588,-0.001415,0.001788,-0.00345,-0.007744, +0.005596,-0.00871,-0.001603,-0.0001678,-0.00862,0.00929,-0.005604,0.00986,0.005383, +0.00959,0.00005203,-0.002613,0.000881,0.00828,-0.00738,0.001506,0.000615,-0.001396, +0.005566,-0.00815,-0.00447,0.002577,-0.00938,-0.0007024,0.000968,0.00785,0.001473, +-0.004387,0.008286,-0.003094,0.008125,-0.004494,-0.00425,0.004585,-0.00964,0.002777, +-0.00888,0.005466,0.00231,-0.001025,-0.009186,0.004265,0.002234,-0.002064,0.006973, +-0.007336,0.001036,-0.00965,-0.003597,0.000792,-0.006615,0.00904,0.00902,-0.004856, +-0.00782,-0.0004456,0.004826,-0.001932,0.003588,-0.001571,-0.003286,-0.00523,-0.002085, +0.004658,0.00324,-0.00974,0.007122,-0.00806,-0.003452,-0.00996,0.0004315,-0.004436, +0.00442,0.0003521,-0.0000391,0.00986,0.007553,0.00816,0.004242,-0.00706,0.00857, +-0.009705,-0.00789,0.006126,0.00494,0.001126,-0.003017,-0.0005965,-0.00928,0.001935, +-0.00866,-0.002542,0.003275,0.0001297,-0.00935,0.005028,0.004097,-0.006817,0.00791, +0.0001851,-0.002525,0.00906,0.000608,0.0004106,-0.00859,-0.005623,-0.00567,0.00434, +0.004124,0.000519,0.00947,-0.002487,-0.00738,0.009346,-0.004936,0.007263,-0.00096, +0.00493,-0.00823,0.003119,-0.0003824,0.0007586,0.006584,0.00392,-0.008125,0.006313, +0.007812,-0.005913,0.005547,-0.0001316,-0.007523,0.00768,0.00142,0.00912,-0.003622, +0.00852,0.005966,-0.004467,-0.00919,-0.00866,-0.00875,-0.0000665,0.000144,0.00649, +0.003706,-0.001643,-0.003508,-0.005817,-0.0059,0.008896,0.0088,-0.005962,-0.003698, +-0.003626,0.001465,0.003386,0.002172,0.00159,0.003794,0.00751,0.001184,-0.0008216, +-0.006474,0.00761,-0.006603,0.005993,0.003044,0.00322,-0.00928,-0.00667,-0.00599, +0.00869,0.001393,-0.006184,-0.002693,0.003727,-0.003624,0.002987,-0.002718,-0.001762, +-0.007366,-0.00294,-0.004993,-0.00977,0.00814,-0.001241,0.001603,-0.00352,-0.004997, +-0.005177,-0.002817,0.002464,0.00763,0.00547,-0.007217,-0.00507,0.000908,-0.000513, +0.001423,-0.0006895,0.001677,0.001864,-0.00401,-0.003475,0.00604,-0.003687,-0.008606, +-0.00724,-0.0061,0.002502,-0.00612,-0.003128,0.000557,0.001442,-0.007397,-0.0088, +-0.0009484,0.007244,-0.008804,-0.00847,-0.00967,0.00989,0.00872,-0.005753,0.003027, +0.0014105,0.007397,-0.005905,0.007214,0.005665,0.001882,-0.002838,-0.003008,-0.00795, +-0.000239,0.0064,0.005333,0.005028,0.006863,-0.004,-0.00592,-0.001575,0.005398, +0.009575,-0.003317,0.00983,-0.0006003,0.005287,0.009094,-0.00502,-0.00495,-0.00962, +0.000787,0.005604,-0.006504,0.002504,-0.004066,-0.009766,-0.0074,-0.00766,0.009705, +0.00814,-0.005157,-0.001017,-0.008316,-0.00004405,-0.00802,-0.004677,-0.004894,-0.00705, +0.00784,0.00448,-0.007553,-0.0028,-0.006226,0.0000136,-0.004192,-0.00755,0.00278, +0.00343,-0.0006332,-0.00343,-0.004555,-0.0093,0.00261,0.00926,-0.005093,0.00627, +-0.00848,-0.00984,-0.001426,-0.00226,-0.002077,-0.001703,0.009636,0.007664,-0.003628, +0.002018,-0.006012,-0.00473,0.003834,0.00939,-0.00827,-0.00812,-0.00792,0.00924, +0.00776,0.001537,-0.00287,-0.002401,-0.00831,-0.00903,0.00591,0.003252,-0.006348, +0.001455,0.00674,-0.002382,0.0003512,-0.0017185,0.00684,0.00665,0.00782,-0.00969, +0.00418,0.00442,0.00979,0.006382,0.004642,0.00398,0.007797,0.005234,-0.005566, +-0.00903,0.003168,-0.005596,0.00006646,0.00995,-0.002335,-0.00548,0.005383,-0.004562, +0.00811,-0.005035,0.0008745,-0.0086,-0.00786,-0.00566,-0.0096,-0.000744,0.00511, +-0.003363,0.002739,0.002033,0.005455,-0.001077,0.003887,0.00735,0.00757,0.008965, +-0.002888,0.002462,0.000919,0.0008416,-0.003096,0.00875,-0.002434,0.00318,-0.002779, +0.00725,0.005062,0.00073,0.00845,0.003576,0.002874,-0.00836,-0.00859,0.00916, +-0.00745,0.00869,0.001855,0.005814,-0.002064,0.0066,-0.009346,0.004307,-0.00966, +0.00877,-0.002394,-0.00977,0.002356,-0.008255,0.001052,0.00495,-0.00963,0.00886, +-0.00476,-0.00917,-0.000619,-0.00593,0.005497,0.003141,0.002428,0.003363,0.001099, +0.00731,-0.005577,0.00666,-0.00328,0.004677,0.00761,-0.00864,-0.00873,-0.00282, +-0.004177,0.00867,-0.00536,0.004387,-0.007294,-0.0099,0.001112,-0.001063,0.004284, +0.000729,0.005604,0.00434,0.00563,-0.00618,0.00464,0.004417,0.00524,-0.00052, +-0.002462,-0.000902,0.005207,-0.002256,0.000805,-0.006252,0.003262,0.007603,-0.000191, +0.003582,-0.002598,-0.003662,-0.005585,-0.00007087,-0.00784,-0.001778,0.00996,-0.00643, +0.009796,-0.002966,0.005848,-0.003027,-0.007587,-0.003654,-0.00882,-0.001206,-0.005836, +-0.0089,-0.00608,-0.003944,-0.000564,-0.00329,0.000377,0.000702,0.000859,0.002554, +0.001499,0.005997,0.0006666,-0.00584,0.005337,-0.00734,0.006847,0.00829,0.003925, +-0.00837,-0.005886,-0.006927,-0.000641,-0.0000388,0.003124,0.007427,0.00767,-0.002771, +-0.005985,0.002094,-0.007442,-0.001377,0.003183,0.0003796,0.0068,0.0008273,-0.002102, +0.003433,-0.00931,0.0003903,-0.00771,-0.000703,0.003122,0.00833,0.001467,0.00769, +-0.004578,-0.007393,0.0054,-0.007797,-0.003767,-0.009735,-0.0007954,0.005028,-0.00809, +0.002352,-0.0002111,0.003624,0.00502,0.001048,0.00922,0.003426,0.002258,-0.00708, +0.00517,-0.00919,-0.00881,-0.00548,0.00891,0.00919,0.00597,0.001098,0.004875, +0.004875,0.00846,0.00829,0.003426,0.001049,0.00669,0.003994,0.006195,-0.004585, +-0.001221,-0.000247,-0.00613,-0.00613,0.00436,0.006775,-0.001169,-0.001771,-0.001071, +-0.003635,-0.004475,-0.00216,-0.003502,0.002285,-0.006702,0.0074,0.004845,0.00123, +-0.00434,-0.0082,0.0000914,0.00325,-0.00717,-0.003687,0.003479,0.005894,-0.002655, +0.00833,0.002365,-0.00927,0.006416,-0.0031,0.009834,0.006855,0.004673,0.00857, +-0.00627,0.00887,-0.002636,-0.0066,-0.003975,0.003056,-0.001572,-0.005142,0.007393, +0.00863,-0.000665,-0.005146,0.008965,0.005505,-0.001827,-0.001454,0.002926,-0.002275, +-0.006184,0.00991,-0.005035,-0.003462,0.00855,-0.009125,0.002832,0.005817,0.007187, +0.005844,-0.003204,-0.002201,-0.0095,-0.00862,-0.00896,0.00543,0.00010115,0.00392, +0.004917,-0.002266,0.0003471,0.006306,-0.004726,-0.002298,0.00234,-0.004726,0.00924, +-0.005363,-0.0002112,-0.0099,0.005604,-0.00523,-0.004627,-0.001949,-0.00936,0.002743, +-0.001635,0.001984,0.00972,-0.00359,0.003296,0.00074,0.004654,0.00995,-0.001584, +0.003048,0.0006003,-0.003628,-0.007668,-0.002537,-0.006584,0.00576,0.00864,-0.00899, +-0.009636,-0.005394,0.00433,0.00706,0.005005,-0.004707,0.004597,0.00852,0.008835, +0.003904,0.00457,0.004128,0.005028,-0.003986,0.005997,0.0002208,0.00777,0.00963, +0.005787,0.007023,0.00553,0.00449,0.005814,0.003082,0.0093,0.00472,-0.00985, +0.00938,0.00558,0.007088,0.00391,-0.00918,0.008415,0.00902,0.004173,-0.002716, +-0.009926,-0.00801,-0.009705,-0.0086,-0.009865,0.003788,-0.0092,0.00887,-0.001495, +-0.00314,-0.003246,-0.000836,0.001646,0.00902,-0.007233,-0.00376,-0.0057,0.005787, +-0.002974,0.00872,0.0086,-0.00443,0.003622,0.004593,0.008026,-0.0003214,0.00858, +-0.00338,0.00772,0.00448,0.00855,0.001066,-0.004692,-0.005737,0.007565,-0.0002706, +-0.002792,-0.00949,0.000827,-0.004967,0.00864,0.00788,0.009094,-0.001957,-0.002716, +0.000686,-0.00499,-0.004173,0.002407,0.00923,0.001411,-0.0005016,0.00746,-0.0087, +-0.002703,-0.003134,-0.001611,0.007404,-0.00999,-0.004158,0.00556,0.0005794,0.003775, +-0.001105,-0.00338,0.00999,0.006966,0.005802,-0.009735,-0.009834,-0.00723,-0.00656, +-0.007538,0.00995,0.00586,0.001463,-0.001861,-0.007015,0.005455,-0.00492,-0.005337, +-0.00855,-0.002764,0.003605,0.00967,-0.007256,-0.002594,0.00397,-0.00508,-0.004555, +0.009476,-0.0006495,0.003998,-0.0087,0.007294,-0.007748,0.001855,-0.0002816,-0.00983, +-0.007416,0.004444,0.003036,0.005066,0.001116,-0.0001506,-0.003181,-0.003258,-0.00816, +0.00821,-0.0007715,0.00669,0.002674,0.004074,0.009605,0.001936,-0.0052,-0.002779, +0.003435,0.003592,-0.00787,0.002615,0.007996,0.002047,0.002438,0.000739,-0.002443, +0.00817,0.009995,0.00749,0.00953,0.007427,-0.003246,-0.004795,0.003834,0.0087, +-0.00863,0.003105,-0.003313,-0.006187,0.005104,-0.00093,0.004158,0.003963,-0.00579, +-0.004044,0.004044,-0.0005593,-0.00388,-0.00249,0.006115,0.00322,0.007347,0.00813, +-0.005142,-0.0004606,0.00646,0.002186,0.00812,0.004818,0.0009236,-0.00864,0.00948, +-0.003057,0.003445,-0.004444,0.001763,-0.005806,0.001699,0.00843,-0.007423,-0.001351, +-0.007317,-0.001196,0.002996,0.005066,0.003227,0.00547,-0.00923,0.0008106,0.00789, +-0.006508,-0.0003939,-0.002443,0.007107,-0.00692,-0.007645,-0.00353,0.00661,0.000988, +-0.00769,-0.003134,0.002548,0.00495,0.0034,0.001454,0.00344,-0.00323,-0.006203, +0.001063,0.008736,-0.00737,0.00234,-0.00315,-0.008865,-0.003918,0.006042,0.0003307, +-0.001405,0.002129,-0.00682,0.000836,-0.005436,0.008385,-0.002783,-0.0007734,-0.007088, +-0.005924,0.00951,0.000002,-0.00504,-0.005474,-0.00897,0.00339,-0.003044,0.0019245, +0.00596,0.00756,-0.005936,0.007416,-0.005173,0.006367,0.0015545,-0.001073,0.008095, +0.004868,0.0000308,-0.005302,-0.0003858,-0.00421,-0.00386,0.00925,0.004604,0.001006, +-0.004482,0.00634,-0.006126,-0.00878,0.0095,-0.006985,-0.00575,-0.001845,-0.002335, +0.00908,0.00764,-0.00405,0.003431,0.004726,0.0002171,-0.005314,-0.00693,0.00867, +0.0007024,-0.007217,0.006042,-0.0002111,0.00475,-0.00635,0.00984,0.00829,-0.0008802, +-0.005093,-0.007996,-0.003607,-0.00965,-0.001188,-0.002707,0.002533,0.00328,-0.004807, +-0.002724,-0.005733,0.007996,-0.003893,-0.0002323,-0.00577,-0.007263,0.00416,-0.007385, +-0.004906,0.002007,-0.00773,-0.0004334,-0.00542,-0.0009217,0.008545,0.0005693,0.0094, +-0.000956,-0.002106,-0.0082,-0.006363,0.00431,-0.001059,-0.0054,0.002123,0.0004594, +-0.003489,-0.005173,-0.007595,0.007782,-0.0001341,0.00977,-0.00463,-0.0002378,-0.002296, +0.00667,0.00701,0.001323,-0.001699,0.00955,-0.0091,0.0089,0.00791,-0.0003197, +0.007835,-0.00828,0.00854,0.00239,0.008385,0.001974,0.000486,0.00991,0.006542, +0.007866,-0.004803,-0.004913,-0.00513,-0.0004153,0.00995,-0.00516,-0.003317,0.00682, +0.0004165,-0.00903,-0.005344,0.00786,0.003769,0.004158,0.0002446,0.00589,-0.002949, +0.0073,-0.002398,-0.004757,0.0002432,-0.00439,-0.00454,0.000453,0.00823,-0.009575, +0.00535,-0.008575,-0.00893,0.004303,0.00502,0.00617,-0.004402,0.00919,-0.00865, +0.00876,0.003645,0.0002997,-0.00925,-0.007076,0.004448,0.005196,-0.003986,0.007084, +-0.000285,-0.002855,-0.000422,-0.00872,-0.005013,0.00952,-0.008446,-0.004044,-0.00907, +0.007072,-0.00918,-0.007835,0.000878,-0.006847,-0.006,0.00731,-0.001876,-0.002565, +-0.003584,-0.003006,-0.00723,-0.003433,0.0004973,-0.00795,0.0005007,0.00608,0.00671, +0.0001765,0.00439,-0.003738,-0.006035,0.00010353,-0.00374,0.0008683,0.00773,-0.0004847, +-0.000992,0.004658,-0.003555,-0.0056,-0.001982,0.00812,0.003386,-0.001584,0.003508, +-0.006138,-0.00587,0.001421,-0.009094,-0.00468,-0.0086,0.003637,0.00896,0.00804, +-0.00744,0.002382,-0.0097,0.000659,0.007782,0.002981,-0.00869,0.0000934,-0.00882, +0.002771,-0.009544,0.0035,0.004124,-0.0014,-0.006294,-0.007614,0.00931,0.009674, +0.0003185,-0.004295,0.007084,-0.0035,-0.00334,-0.001754,0.001216,-0.004375,0.003244, +0.0001901,0.001547,0.007183,0.006447,0.005108,0.00679,0.001068,-0.00587,0.005745, +-0.00634,0.0058,0.006985,-0.000697,0.00008917,0.007835,-0.0004838,0.004795,-0.006832, +0.002398,0.00687,-0.001582,0.00709,-0.00908,-0.001573,0.009865,-0.001476,-0.000526, +0.00477,0.008026,-0.00171,0.00979,-0.005592,0.0006247,-0.00774,0.00463,-0.006676, +0.004368,-0.002373,-0.005127,-0.0013275,-0.002306,-0.0087,0.00997,0.005493,0.003786, +-0.004414,-0.005947,0.003181,-0.0004156,0.00909,-0.00656,0.001926,0.0003731,-0.009636, +0.003124,-0.0000686,-0.001972,-0.006584,0.0009604,0.004086,0.009865,0.001302,-0.00989, +-0.0086,0.005177,0.006493,-0.00523,-0.00443,0.001586,0.00937,0.007458,0.001883, +0.00774,0.0004454,0.000493,0.0003722,-0.00486,0.006435,0.002642,0.00432,-0.00272, +-0.007446,-0.007397,0.00361,0.003618,0.003956,-0.001175,0.00832,0.00794,0.001658, +0.00123,-0.003918,0.001215,-0.007427,0.003708,0.00492,-0.00968,0.008896,-0.006786, +-0.005856,0.006573,0.003876,-0.003983,0.00411,0.0076,-0.0008364,-0.00496,0.008026, +-0.00986,-0.001429,-0.007236,-0.002172,-0.003004,-0.0017185,-0.00353,-0.00817,-0.004353, +-0.003458,0.002663,-0.00599,0.002125,-0.00625,-0.00913,-0.009796,-0.004574,-0.00978, +-0.00398,-0.006096,0.003708,0.007214,0.00444,0.003742,0.004547,0.006042,0.001542, +0.002424,0.0005617,0.006477,-0.002382,0.0009637,-0.00462,-0.000934,0.0004268,0.00975, +0.002277,0.001031,-0.007103,0.006615,0.00199,0.009,0.00995,-0.002514,-0.0016575, +-0.00875,0.00936,-0.007133,0.007412,-0.001572,-0.00862,-0.00675,0.009445,-0.00819, +0.004597,-0.005493,0.004894,-0.004807,0.00346,-0.00114,0.006638,-0.005882,0.0041, +-0.002684,-0.0006037,-0.00842,0.001939,-0.0008016,0.00265,-0.005383,0.00963,0.0063, +0.006386,0.004463,-0.004173,-0.006317,0.003534,-0.00781,-0.001414,-0.004723,-0.003096, +-0.001367,0.00955,-0.0000178,-0.007214,0.00985,-0.003782,0.005688,-0.002445,0.00185, +0.00784,0.00203,0.0003746,-0.00935,0.00559,0.00718,0.005905,0.002926,0.006268, +0.0002078,0.001244,0.00467,0.006405,-0.0005364,0.00503,-0.0004387,0.006252,-0.002594, +0.001791,-0.00807,-0.001451,-0.0034,0.00958,0.003035,-0.00348,0.004818,0.008644, +-0.0005145,-0.004673,0.008934,0.00756,-0.001786,-0.005634,-0.002981,-0.007107,0.001145, +0.003677,0.004997,0.009766,0.0005856,-0.002384,0.004177,-0.00965,0.005924,-0.005596, +0.004505,0.000578,0.00663,-0.006638,0.001535,0.002502,0.002907,0.00447,0.002016, +0.008865,0.00828,-0.00975,0.0002487,-0.00796,-0.008286,-0.002083,-0.00471,0.007187, +0.004326,0.007206,0.004307,0.009346,-0.00758,-0.007545,0.00349,0.0018425,-0.00837, +-0.007935,-0.002258,0.003757,-0.0014,0.000081,0.00449,-0.000318,0.006485,-0.001184, +-0.001842,0.009476,0.00818,-0.00986,0.001612,-0.00779,0.006676,-0.0013075,0.00464, +-0.002117,-0.0087,0.00965,0.001394,0.00818,-0.005493,0.004673,-0.00439,-0.00557, +-0.001841,-0.00948,0.00607,0.00551,-0.002834,0.004883,-0.00712,0.006573,-0.002064, +0.0008054,-0.006508,0.004467,0.00773,0.004787,0.00523,-0.001751,-0.005657,0.000278, +-0.001822,-0.00639,-0.003477,-0.006767,-0.007782,0.005375,-0.00726,0.007248,0.0008335, +-0.001856,-0.00009865,-0.006054,0.006786,-0.005665,-0.007393,-0.0007014,-0.007046,-0.0065, +-0.00645,0.002195,0.004818,0.00909,-0.00862,0.007614,-0.00499,0.007423,-0.001478, +-0.005028,-0.007107,-0.00488,0.00322,-0.003801,0.0018425,0.001862,0.007713,-0.008675, +0.001135,0.00788,-0.006866,-0.00776,0.001423,-0.00392,-0.00908,0.00918,-0.006706, +-0.00828,-0.00358,-0.00956,-0.00823,0.00656,-0.00617,-0.004395,0.002705,-0.001398, +0.003265,0.007793,0.00664,0.009285,0.00851,0.00416,-0.00923,-0.006733,0.00934, +-0.00564,-0.001064,0.001106,0.00943,0.005024,0.00793,-0.005302,-0.00376,-0.0005045, +0.005325,-0.002134,-0.001494,-0.00891,-0.00803,0.00958,-0.0000229,-0.003668,0.00602, +-0.003649,-0.002918,0.006573,0.005146,-0.009995,0.00864,-0.008255,0.004868,0.001078, +-0.003546,0.00235,0.005764,-0.005116,0.009186,-0.008255,-0.00216,-0.008,-0.009125, +-0.002754,-0.0083,-0.002539,-0.0007524,-0.00843,0.003647,-0.00156,0.00498,-0.007904, +-0.00502,0.00919,0.003862,0.00599,0.001332,-0.00788,0.007374,0.001653,-0.00406, +-0.008545,-0.00444,-0.00971,-0.002436,-0.009834,-0.005573,-0.002323,-0.007126,0.004803, +-0.00913,0.002483,-0.004704,-0.0014515,-0.001035,-0.008934,-0.001855,-0.0071,0.00979, +-0.008255,0.001663,-0.001383,0.000364,-0.003595,-0.002163,0.002136,0.004894,0.006966, +0.00925,0.006557,-0.0089,-0.0007167,0.002699,0.003483,0.003017,0.004223,0.006042, +-0.002342,-0.004868,0.003157,0.006165,0.001519,-0.00874,-0.004856,-0.004116,0.002634, +-0.001233,-0.008736,0.003529,-0.001974,0.00121,-0.0006013,-0.002737,-0.00596,0.007027, +-0.00496,-0.002726,-0.00787,0.001581,0.00381,-0.004932,0.007027,-0.003616,-0.000989, +0.003532,0.002346,0.0000479,0.002907,-0.004353,0.005424,0.003124,0.00985,0.003, +-0.007805,0.001684,-0.001324,0.0005107,0.00483,-0.00992,0.000786,-0.003649,-0.0006337, +-0.001443,0.00782,0.008194,-0.00819,-0.00844,-0.004906,-0.006355,0.002932,0.004242, +0.000638,-0.00259,0.00585,-0.00864,0.00378,-0.00279,-0.00319,-0.001805,-0.002768, +-0.0007725,-0.004875,0.003784,0.00947,-0.008736,0.003262,-0.00325,-0.003826,0.007904, +0.00002706,0.006187,-0.001488,-0.001711,-0.003317,0.007446,-0.00699,-0.005573,0.00164, +0.00938,0.0002334,0.003819,-0.001427,0.00992,-0.003433,-0.0006833,-0.00492,0.005493, +0.003014,-0.006187,-0.002325,0.00741,-0.009056,0.005604,-0.003874,0.00869,0.0001504, +0.005356,0.001178,0.00786,0.003292,0.00947,-0.002808,-0.00424,-0.00999,0.004818, +0.00372,-0.003748,0.001496,0.009796,0.0000038,0.00379,0.0003746,-0.004147,0.007195, +-0.0095,0.001072,0.002129,0.00889,0.003273,0.006958,-0.004894,0.0006795,0.00892, +-0.004356,0.00594,-0.002378,0.00969,-0.0081,0.0003927,0.00789,0.00343,0.00479, +-0.0005517,-0.00652,0.000332,0.00876,-0.001309,-0.002495,-0.00831,0.007786,-0.00512, +-0.003832,-0.0006423,-0.003162,0.00807,-0.006298,-0.003601,0.002438,0.0017395,0.002686, +-0.001712,0.00424,0.00632,-0.00935,0.000598,0.005714,-0.00921,-0.002935,0.008064, +-0.001802,-0.002634,-0.006786,0.00976,0.00867,0.004066,0.002306,0.001495,-0.0003717, +-0.00597,0.00958,-0.00881,0.00856,-0.00538,-0.008575,-0.003626,0.006702,0.00932, +0.001552,0.0006847,0.00159,0.002314,0.008606,0.005955,0.00862,0.0003278,0.003115, +-0.006863,-0.0051,-0.00824,0.00592,-0.005653,0.00871,-0.008286,0.0005655,-0.005154, +-0.008766,0.008896,-0.009674,0.003782,-0.000774,0.00323,-0.00935,0.007694,-0.003578, +-0.00912,0.007362,-0.00561,0.00817,-0.00852,-0.00006425,-0.003166,0.0004108,0.006325, +-0.00928,-0.008026,-0.003891,-0.005924,-0.004284,0.00515,-0.00749,0.002983,0.003885, +0.006535,-0.001574,0.005695,-0.009155,-0.006996,-0.0012665,0.002983,-0.00932,-0.00575, +-0.008545,-0.0005817,0.002466,-0.003382,0.007477,0.00166,0.004562,-0.001331,-0.0095, +-0.00291,0.002815,-0.009796,-0.00496,0.005592,-0.00365,-0.00609,0.0008597,0.00516, +0.003986,0.002157,0.00934,-0.003363,0.000835,0.003725,0.002106,-0.005993,0.00795, +0.003122,-0.003313,-0.005383,0.0004141,0.006466,0.003517,-0.00809,0.005714,-0.007294, +-0.001924,-0.002457,-0.001897,-0.001449,0.00543,0.000466,0.008125,-0.002316,0.003128, +-0.008255,-0.001908,0.00911,0.00793,-0.001612,-0.00899,-0.004013,-0.002962,0.001639, +-0.006916,-0.009056,-0.005795,-0.001411,-0.00745,0.003126,0.000916,-0.0007496,0.003273, +0.005184,0.004128,0.003195,-0.004635,0.004826,0.00745,0.006348,-0.008865,-0.00217, +0.006275,-0.00971,0.005478,-0.003456,0.0065,0.00943,-0.005703,0.002666,-0.005745, +-0.006134,0.003513,0.00683,-0.004803,-0.003841,-0.006435,-0.007122,0.001902,0.005844, +0.007313,0.004723,0.001233,-0.00402,0.001288,0.002878,0.004196,-0.002884,-0.007454, +0.000933,-0.003576,-0.005608,-0.00908,0.00426,0.001788,-0.004856,-0.008965,-0.00546, +-0.004684,-0.002708,-0.006145,0.002111,-0.000599,-0.007187,-0.002018,-0.001014,-0.006676, +-0.00335,-0.00528,-0.009224,-0.009285,-0.00063,-0.0045,-0.005157,0.008865,0.008835, +-0.00672,0.002237,0.002687,0.005703,0.00585,0.007175,-0.007496,0.0002145,0.00924, +-0.00611,-0.003202,-0.0057,-0.001237,0.006752,0.001596,-0.001424,0.007492,0.00459, +-0.00668,-0.001726,0.00209,0.001924,0.0008316,0.0004334,0.001638,0.005665,0.000911, +-0.00552,0.00619,-0.00979,0.00549,0.004967,0.00818,-0.006157,-0.00816,0.001334, +0.0002472,0.00653,0.005257,0.0000934,-0.00261,0.00755,0.000494,0.001341,0.00236, +-0.00876,0.005054,-0.00503,0.007465,-0.005676,0.003174,-0.006325,-0.005238,-0.005608, +0.0002413,-0.003477,-0.00379,-0.002457,0.002943,-0.006855,0.001733,0.006504,-0.004406, +-0.00929,-0.00009567,0.000722,0.001004,-0.00633,0.001915,-0.001345,-0.002802,-0.00858, +-0.001694,-0.000937,0.004486,-0.00567,0.000247,0.007782,-0.0036,-0.003588,0.00717, +-0.00928,0.00838,-0.0063,0.00916,0.005352,0.00736,0.00083,-0.007248,-0.005722, +0.00325,-0.00503,0.001647,0.007767,-0.00539,0.0065,-0.002151,0.003359,0.0002371, +-0.007057,0.000602,0.00692,-0.008415,-0.001443,0.006783,-0.00778,0.00946,-0.002735, +-0.006832,0.00419,-0.009315,0.00963,-0.003994,-0.00833,0.00411,0.0076,0.005817, +-0.001542,-0.003956,0.004513,0.001667,-0.002378,-0.003075,0.002481,-0.001739,-0.005566, +-0.002113,0.003263,-0.00797,-0.008675,0.006916,0.002848,0.008446,-0.004627,-0.002216, +-0.0005455,-0.00882,0.00846,0.001422,-0.000527,-0.00826,0.0012245,0.006226,-0.008316, +0.002134,-0.006298,0.00672,-0.008026,0.003248,0.0046,0.001113,0.000221,0.000791, +0.00836,0.007805,0.006355,0.004723,0.000991,-0.00904,0.007164,0.00896,0.00788, +0.004128,-0.003473,-0.00242,0.003466,0.003286,0.002634,0.009865,0.006947,-0.0004823, +-0.005455,0.003603,0.002008,-0.004536,0.006187,0.005722,-0.00010717,0.00227,0.00967, +-0.004883,-0.0011015,0.009285,0.002121,-0.006718,0.00782,0.00481,0.002974,-0.002855, +-0.001182,-0.000961,-0.002497,-0.005707,-0.00536,-0.000726,-0.004868,-0.000473,-0.002764, +0.0002033,-0.00961,-0.00828,-0.001335,0.005314,0.007263,0.005386,-0.0006895,0.00444, +-0.00443,0.001597,0.00753,0.005608,0.002354,0.00399,0.003551,0.0035,0.00319, +0.0017185,-0.006195,-0.004467,0.006042,-0.007217,-0.00907,0.004025,-0.00671,-0.002226, +-0.00557,0.000518,-0.00805,0.008865,-0.007195,-0.004032,-0.005047,0.007072,-0.003544, +-0.00706,-0.000232,-0.00829,-0.00835,-0.002449,0.002384,-0.00886,-0.00177,-0.00641, +0.006733,-0.001213,-0.005184,0.009995,0.006573,0.003773,-0.00962,0.003693,0.003815, +0.004353,0.00224,0.0003662,0.007187,0.00817,-0.002918,-0.006615,0.00834,0.002783, +-0.000913,0.004993,-0.006687,-0.008224,0.00864,-0.000776,-0.003668,0.002398,0.001138, +0.001902,-0.004894,0.00398,0.001741,-0.00922,0.002316,0.0000156,0.00923,-0.004314, +0.00844,-0.002323,-0.001928,0.006115,0.006283,-0.001401,-0.006443,0.00693,0.007225, +0.0005593,-0.00996,-0.00842,-0.001854,0.001111,0.00157,-0.003658,-0.0003986,0.005455, +0.004204,-0.006065,0.00812,-0.00642,-0.004932,-0.00778,0.004032,0.005814,0.00329, +-0.007164,-0.00576,0.002708,-0.005424,-0.006355,-0.003983,-0.006695,-0.00661,0.005814, +-0.007137,-0.00739,-0.001341,0.000845,0.000429,-0.002764,0.006496,0.00785,-0.00622, +0.003235,0.00425,-0.00612,0.00803,0.007404,-0.001365,0.002625,0.001886,0.003359, +-0.00518,-0.002394,0.00475,0.003391,0.00693,-0.002079,-0.000818,-0.002357,-0.005272, +-0.002317,-0.000729,0.004074,0.005486,0.006023,-0.006363,0.00527,-0.003586,-0.00925, +0.003809,0.00087,0.007133,-0.001788,0.002201,0.00955,0.003735,0.007324,-0.00614, +-0.007187,-0.006783,-0.006145,-0.004665,0.007175,0.00984,0.00314,0.008064,0.007336, +-0.00337,-0.00559,0.004944,-0.007744,-0.00197,-0.006714,-0.002281,-0.002087,0.0009074, +-0.00753,0.004993,0.00319,-0.002535,-0.001945,0.0008793,-0.003357,0.004246,-0.00838, +0.007698,0.001307,0.001717,0.00824,-0.001335,-0.0002145,0.00561,-0.007168,-0.001333, +-0.00551,-0.003637,-0.007786,0.001738,0.007748,0.001321,-0.001924,0.006046,-0.009125, +0.009674,0.006313,0.002666,0.002287,-0.00956,-0.004803,-0.008675,0.003038,-0.00514, +0.00935,0.006756,0.004425,0.002203,0.00642,0.004555,0.00657,0.00157,0.00652, +-0.000512,0.003416,0.00883,-0.003372,-0.001136,-0.00302,0.007435,-0.00564,0.001519, +-0.007687,-0.00783,-0.008736,0.003899,-0.00231,0.006927,0.00558,-0.007786,0.008156, +0.004417,-0.004173,0.008865,0.004707,0.002438,-0.008896,0.00009686,-0.00338,0.002985, +0.0000722,0.004047,0.00991,0.00222,0.00381,-0.003147,0.0081,0.00392,0.001678, +-0.00647,0.00942,-0.002876,-0.001987,-0.00758,-0.003983,-0.00814,0.00255,-0.001071, +0.006855,-0.00676,-0.00801,0.00399,0.002998,0.003906,-0.002068,0.005444,-0.003128, +0.001452,-0.000623,0.007122,-0.003498,-0.000979,-0.003366,-0.001828,0.004135,0.006786, +-0.003593,-0.00814,-0.00749,-0.004894,0.009445,-0.00828,-0.005108,-0.005836,-0.002945, +-0.008125,-0.001417,-0.003443,0.00201,0.001321,0.00578,0.00224,-0.00895,-0.001515, +-0.008194,0.00883,-0.000655,-0.00831,0.005695,0.00663,0.00704,-0.00393,0.003603, +-0.005608,0.00107,-0.00902,-0.0001382,0.006287,0.006393,0.0005302,0.00898,0.00172, +0.0033,-0.001728,-0.004436,0.006794,0.001925,-0.00698,0.002726,-0.00372,0.003744, +0.007004,0.002556,-0.00895,-0.005096,0.003044,-0.002342,-0.00802,0.0067,0.006172, +0.0005546,0.009,0.006405,0.003557,-0.006527,0.002508,-0.002115,-0.00497,0.004852, +0.002605,0.009155,-0.00941,0.000894,-0.00825,0.005333,0.006023,-0.001292,0.009445, +-0.007217,0.003368,-0.007156,-0.006386,-0.00293,0.00218,-0.00803,0.00927,0.008965, +0.001402,0.00525,-0.00784,0.00418,-0.00978,-0.003138,0.002974,0.001657,-0.009834, +0.001901,-0.00948,0.005455,-0.001604,0.00559,0.006447,0.0008035,-0.002773,0.006332, +-0.00896,0.00488,0.004177,-0.00319,0.00708,0.0003064,-0.0007687,-0.003065,0.005558, +-0.003864,0.003887,-0.00855,0.006237,0.008415,-0.002693,-0.002817,-0.00904,0.003407, +0.000946,-0.00738,-0.00562,-0.0009713,-0.003506,-0.00766,0.00953,-0.004005,0.00867, +0.0004733,-0.005787,0.0005293,0.006996,0.001659,0.000469,0.001537,0.002247,-0.004242, +0.00243,-0.004093,-0.007355,-0.001,0.006374,-0.004963,0.006035,0.005245,-0.00839, +0.002262,-0.008286,0.00845,0.00911,-0.001388,-0.001848,-0.0008616,0.006363,0.002584, +-0.002827,-0.00755,-0.009834,0.002735,-0.001286,0.006,0.001821,-0.001493,-0.00819, +-0.0003796,0.008606,0.000496,0.001856,-0.00668,-0.009186,-0.00736,0.0048,-0.003502, +0.001626,-0.0001339,-0.006126,-0.00596,-0.0001252,0.001953,0.009575,-0.001304,0.004192, +-0.006035,-0.001251,0.007587,0.001031,-0.00928,0.00793,0.00653,0.0007644,-0.002647, +0.003609,-0.00461,0.000423,-0.000656,0.005367,-0.00425,0.004215,0.006554,0.005634, +-0.001172,0.00472,-0.0002402,0.003582,0.00738,0.00301,0.005417,0.009254,0.007145, +-0.0094,0.000404,0.00837,-0.00894,0.004658,0.0004907,-0.001399,-0.00873,0.0008955, +-0.001738,-0.001934,0.003742,0.002077,-0.004063,-0.007736,-0.001259,0.00867,0.00488, +0.006584,-0.00822,-0.00585,0.006927,-0.003298,-0.004593,0.000567,-0.004543,-0.007378, +0.00718,-0.00876,0.005707,0.00701,0.001537,0.005993,-0.0044,0.00847,0.00694, +0.00419,-0.00511,0.00535,0.000936,-0.0007434,0.001556,-0.0008616,-0.0085,0.003342, +0.00982,0.005077,0.005566,-0.003716,0.00839,0.007786,-0.00749,-0.007614,-0.00774, +0.00209,0.005894,-0.007534,0.003998,-0.00518,-0.00033,-0.00831,-0.00556,0.004837, +-0.001809,-0.00423,0.00916,-0.006786,0.009476,0.00841,-0.000718,0.002834,-0.00947, +0.0001942,-0.007904,-0.003672,-0.001356,-0.004658,-0.005825,0.002747,-0.00737,0.00845, +0.005226,-0.002941,-0.005226,-0.00415,0.00848,0.0007825,-0.005276,0.003502,-0.005974, +0.00866,-0.0076,0.003042,-0.003267,-0.00536,-0.006935,0.007515,0.008255,0.003098, +-0.007183,0.007355,-0.00878,-0.0001291,-0.0009227,0.000577,0.00787,0.003855,0.005337, +-0.004837,0.005676,0.004658,-0.00798,0.006424,-0.007534,0.002682,-0.003042,0.00868, +-0.003332,0.00318,0.00199,0.001096,0.00871,0.005028,-0.001416,0.006233,-0.007736, +0.00808,-0.001244,0.001611,0.005127,0.00781,-0.003036,-0.00453,-0.00516,0.007233, +-0.001684,-0.002474,0.002844,-0.00723,-0.002401,0.0015,-0.005444,-0.003035,-0.00929, +0.00947,0.00247,0.004017,0.0008864,-0.003862,0.0062,-0.00172,-0.00449,0.00796, +0.009445,0.007687,-0.007034,-0.001731,-0.00585,-0.005653,-0.002281,0.004925,-0.006744, +-0.002542,0.005775,0.00861,0.003054,0.00666,-0.00694,-0.00822,-0.001123,0.006557, +-0.00476,0.006397,0.00957,0.00888,-0.003952,-0.006313,0.001164,0.001948,-0.00758, +0.007263,-0.00801,0.00924,0.009476,-0.00979,0.007748,-0.00533,0.006195,0.00659, +0.003437,0.00546,-0.00859,0.002409,-0.006824,-0.006172,0.00663,0.004215,0.00291, +0.001303,-0.007786,-0.000654,0.00965,-0.002867,0.002117,0.00484,-0.002012,-0.004826, +-0.00801,-0.00259,0.002625,-0.000174,0.006844,-0.005554,-0.001617,0.00741,-0.00145, +-0.001762,0.005222,0.001931,0.006676,-0.002014,0.005676,-0.001987,0.003426,-0.00088, +0.002485,-0.007698,-0.00604,0.006687,-0.003902,-0.00783,-0.00817,0.00841,0.006134, +-0.00659,-0.004807,0.00649,-0.00855,-0.00605,-0.003489,0.00594,-0.00818,-0.001544, +0.003778,0.00706,-0.0002632,0.005882,0.003763,0.003439,0.00872,0.004265,0.00522, +-0.00886,-0.00803,-0.0003037,-0.00807,-0.006756,0.00789,-0.00428,-0.000516,0.005196, +-0.00981,0.00926,-0.007507,-0.00952,-0.00259,-0.003004,0.00828,-0.000515,-0.00759, +-0.002186,-0.00375,-0.00902,0.002289,-0.002497,0.00996,0.004932,-0.00803,-0.00785, +0.00993,-0.007694,0.000255,-0.0002395,-0.005318,0.005173,0.00518,-0.007427,0.00505, +0.008545,-0.00238,-0.002556,0.00932,0.009094,-0.002436,-0.00971,0.000679,0.00931, +-0.00531,0.003595,0.0065,-0.001422,0.002657,0.00864,0.001987,-0.001189,-0.0007544, +0.0002537,-0.003994,-0.00898,-0.00314,-0.00829,0.006683,-0.006706,-0.005634,0.00001407, +0.006878,0.004093,0.001739,-0.003754,0.006306,-0.001363,-0.00145,-0.00985,-0.003508, +-0.007454,0.00352,-0.004467,-0.00601,-0.007763,-0.00894,0.00583,-0.00698,0.0099, +-0.006313,0.00404,-0.002666,-0.00373,0.004604,-0.00813,-0.006283,0.004066,-0.00592, +-0.0003827,-0.002565,0.006275,0.008705,-0.007404,0.00793,-0.0009556,0.001682,0.00866, +0.00774,0.00332,0.0008507,-0.005215,-0.00757,-0.001497,0.005787,0.001453,-0.001265, +-0.00909,0.006832,0.00836,0.002867,0.002851,0.002344,0.001552,-0.0006785,-0.00941, +-0.007114,-0.003008,0.002539,0.0002484,-0.00774,0.000987,0.00991,0.00611,0.0009437, +-0.001054,0.000739,0.00809,-0.003117,-0.007812,-0.001368,-0.009674,-0.001733,0.006268, +0.003513,0.00852,-0.007652,0.004547,-0.0001137,0.003424,0.000804,-0.003584,-0.00599, +-0.005333,-0.00303,0.004303,0.009,-0.0006638,-0.0008726,0.007774,-0.0000234,-0.0002577, +0.005783,-0.008316,-0.00841,-0.003605,0.001991,0.006767,0.00508,0.00787,0.003464, +0.00908,0.007133,0.007504,-0.00896,0.000183,-0.00929,-0.0009255,-0.0034,-0.00848, +0.002066,0.0002947,0.005394,0.002613,0.00701,-0.00833,-0.001219,0.004704,0.00446, +-0.00775,0.00476,-0.007195,-0.00163,-0.003307,-0.007484,-0.00889,-0.00846,0.008156, +-0.002731,0.005733,0.0099,-0.00276,-0.00869,-0.00962,-0.00841,-0.004955,0.004997, +0.008896,0.00907,-0.000695,0.00972,0.00685,0.004505,-0.00726,-0.003025,-0.002087, +0.00797,0.006016,-0.006485,-0.00491,0.001922,-0.00934,0.006355,-0.0004008,-0.005714, +0.002274,-0.005512,0.005424,-0.0003483,0.001698,0.0006733,0.00815,-0.005264,0.002876, +-0.0000476,-0.003105,-0.001815,-0.00997,0.0004442,-0.00557,-0.007656,-0.003036,0.002333, +-0.001329,0.003675,-0.00706,-0.00807,0.001302,-0.00788,0.003828,-0.00995,-0.006676, +-0.001514,-0.005756,-0.001301,0.002438,0.007313,0.00913,0.003407,-0.002222,0.00981, +0.0012245,0.009155,0.008194,-0.004368,-0.006615,-0.0008593,-0.00582,0.003933,0.005173, +-0.001201,0.002068,-0.00915,0.00797,-0.002686,-0.00958,0.005775,0.002453,-0.003305, +0.00697,0.0001255,0.00218,0.009926,-0.007473,0.007965,0.0066,-0.003874,0.00658, +-0.007618,0.000942,0.002375,-0.007053,-0.003815,0.00569,-0.001039,0.004536,0.003641, +0.004314,-0.003353,0.00857,-0.0006385,-0.000856,-0.007175,0.007557,-0.00978,0.002863, +-0.005424,0.005215,-0.000666,-0.006275,0.005527,0.00827,-0.006187,-0.005993,0.000444, +-0.0001373,0.00458,0.009315,-0.005093,-0.00154,0.002647,0.00586,0.007473,-0.00275, +0.00046,0.008965,-0.0002766,0.00485,-0.00974,0.001143,-0.00859,-0.00027,0.007748, +-0.00341,-0.006992,-0.006664,0.0005536,0.00828,-0.003752,0.000553,0.008575,0.004868, +-0.0004208,-0.001359,0.002785,0.00247,0.0002398,0.00441,-0.007866,-0.00444,0.000598, +0.00985,0.0041,0.001188,-0.00271,-0.003817,-0.0008373,-0.004078,0.00927,-0.002739, +-0.004578,0.004482,0.000669,-0.003761,-0.00921,-0.003477,-0.00516,-0.00893,0.0007854, +0.00305,0.004894,0.00165,-0.009834,-0.00859,0.000812,-0.007256,-0.00276,-0.003006, +0.001255,-0.002705,0.005894,0.00904,0.004845,0.00814,-0.003206,0.007042,-0.003756, +-0.003365,-0.00868,0.00358,-0.009514,0.00952,-0.005753,0.00848,0.003448,0.006912, +-0.001069,-0.0006742,0.00974,-0.001088,-0.0004857,0.00841,0.006027,-0.00606,-0.001904, +-0.006058,-0.004673,0.007572,-0.009674,-0.008896,-0.002888,-0.00806,0.00633,-0.000787, +-0.002151,0.002234,-0.00991,0.00663,-0.00541,-0.006706,-0.00598,-0.00592,0.0001597, +0.001887,-0.00104,0.00994,0.0083,-0.009415,-0.00954,0.0003498,-0.009254,0.002195, +0.003555,-0.007557,0.006336,-0.00789,-0.006927,0.005497,-0.003809,-0.002302,-0.00952, +-0.0007987,-0.001707,0.00007784,-0.006718,-0.005337,0.008934,0.006355,0.006626,0.00514, +0.006844,-0.005447,-0.001604,-0.0008254,-0.004185,-0.006702,-0.001056,-0.00847,-0.005917, +-0.002684,-0.00482,-0.009514,0.004032,0.003906,0.0048,-0.004612,0.000876,-0.00497, +0.008415,-0.00986,-0.00565,-0.000717,-0.003967,-0.006863,0.00825,-0.003292,-0.00966, +0.00263,0.001377,-0.0084,0.004414,-0.0054,0.00609,-0.009026,-0.000778,-0.008385, +0.008286,-0.00352,0.00549,0.00738,-0.007515,-0.002409,-0.00558,-0.003153,-0.005985, +-0.00919,0.00001955,0.004105,-0.0009418,0.001782,0.0007043,-0.00539,-0.004562,-0.003515, +-0.00916,-0.00623,0.0002017,-0.003117,0.00392,0.00738,0.001152,-0.00806,-0.005108, +0.00985,-0.001203,0.00719,0.001182,-0.0002191,-0.00661,-0.003593,-0.001818,0.00765, +0.004604,-0.005318,-0.0009274,0.002466,-0.0003357,0.00783,-0.006584,-0.00664,0.003544, +-0.002964,-0.00983,0.001785,-0.000708,-0.00793,0.00785,0.006046,0.007812,0.0096, +0.00849,-0.001343,0.00623,-0.007465,0.001237,-0.00393,-0.0007534,-0.004776,-0.002806, +0.00451,-0.004726,0.00364,0.002312,-0.00561,-0.00462,-0.001799,-0.0005593,0.00191, +-0.002151,-0.0076,0.001353,0.001949,-0.004097,0.005615,0.002104,0.00746,-0.00824, +-0.006596,0.009285,-0.008026,0.00331,-0.008736,-0.00988,-0.002468,0.003393,-0.007675, +-0.00852,0.0067,0.00552,0.00002897,0.0002024,-0.004135,0.003683,-0.001939,-0.002998, +-0.006897,-0.00462,0.00989,0.001207,0.001254,-0.0008793,-0.004036,-0.00255,0.00871, +0.00695,0.00251,0.005455,-0.00592,-0.001793,-0.0005703,-0.00213,0.004787,-0.0025, +-0.00712,-0.003109,-0.0074,0.003607,-0.003696,-0.001566,0.007812,-0.004433,0.001471, +0.004066,-0.001959,-0.001853,-0.00985,0.006023,0.006184,-0.00586,-0.002455,0.007687, +-0.003036,-0.001865,0.0052,-0.005646,0.002298,-0.0049,-0.001856,-0.003754,-0.003891, +0.00979,0.008415,-0.00886,0.009926,0.001531,-0.001119,-0.004818,0.007763,-0.004997, +0.009415,0.002409,0.00149,0.003786,-0.001091,-0.00852,0.00888,0.0092,0.004227, +0.004055,-0.001675,-0.004677,0.003109,0.006733,0.00538,0.0086,0.002913,-0.00939, +-0.006355,0.00495,-0.007866,0.00885,0.005394,-0.00323,0.00578,-0.00476,0.006634, +-0.00769,0.001916,-0.001957,0.00988,0.004417,-0.00677,0.007565,0.00842,-0.00919, +-0.0055,0.003214,0.00413,-0.00813,0.002834,0.005272,-0.00954,0.006275,-0.00836, +0.00561,0.00951,0.004837,0.00753,0.000762,-0.002527,-0.003277,-0.00522,0.003021, +0.00706,-0.008,-0.00916,-0.002863,0.002209,-0.00828,0.00499,-0.001951,-0.002157, +0.004375,0.006233,-0.007336,-0.0002134,0.004395,-0.004135,-0.00865,0.001095,0.003302, +-0.00732,0.002275,0.00976,0.002602,-0.003263,0.00766,0.003126,0.001476,-0.001589, +0.00351,0.007305,0.00553,0.007236,-0.005352,-0.006542,-0.002747,-0.002932,-0.002441, +-0.008575,-0.00934,-0.00197,-0.004387,0.001285,0.003265,0.001039,0.004814,-0.001674, +-0.00887,0.003067,-0.007866,0.00903,0.003162,-0.004402,0.00029,0.00928,-0.002539, +-0.003176,0.002398,0.004284,0.001891,-0.000756,0.00846,0.00686,0.001065,-0.008934, +-0.00705,0.002884,-0.006603,-0.004486,0.00396,-0.009766,-0.003494,0.004738,0.00899, +0.006016,0.007515,0.003511,-0.00786,0.00949,-0.00682,0.004265,0.00728,0.0047, +0.00902,-0.00474,-0.0005236,0.005547,-0.002396,-0.006386,-0.007904,0.00722,0.005135, +0.000564,-0.003956,-0.00997,-0.00982,0.001334,0.001509,-0.002422,-0.001891,0.002316, +0.00309,-0.006355,0.007336,-0.00487,0.00010824,-0.0008583,0.002853,0.003754,-0.006348, +0.00793,0.00723,-0.00981,-0.003706,0.00317,-0.008446,-0.002966,-0.0009055,0.002184, +0.003096,0.003244,0.009674,0.002132,0.0016165,-0.006443,-0.00423,-0.00905,0.001218, +0.004185,0.00935,-0.00193,0.00179,0.004192,-0.006424,0.002945,0.0005383,0.004173, +-0.001795,0.00803,0.006462,-0.00502,-0.003693,0.001283,-0.001253,0.00715,-0.002525, +0.00824,-0.008995,-0.00549,0.004345,0.002205,0.00827,-0.004692,-0.000714,0.00686, +0.003473,0.009636,-0.001164,-0.002003,0.00674,-0.008224,-0.00462,0.00948,0.002377, +0.00781,0.002586,0.00744,-0.001399,0.003376,0.005226,-0.003313,0.007713,-0.004364, +0.0005984,-0.004997,0.00611,-0.00772,0.006653,-0.002066,0.00196,0.004326,0.00797, +-0.002724,-0.005474,0.007782,0.00728,0.007442,-0.002098,0.005306,-0.007206,-0.001974, +0.0000934,-0.003695,-0.007633,0.006306,0.006794,-0.002983,-0.00424,0.0018215,0.000337, +-0.00849,-0.00768,0.00659,0.002615,-0.008514,0.00282,0.003607,0.009544,0.00924, +0.00949,-0.006145,-0.003231,-0.001794,0.006004,-0.0005646,0.005558,0.00455,-0.005344, +0.003881,-0.00979,-0.00946,-0.0007844,0.00922,0.001785,0.00854,-0.0094,-0.005318, +0.006126,-0.0023,-0.00576,-0.00449,-0.00931,0.006935,-0.007477,0.001311,0.00797, +0.003727,-0.000941,-0.00816,-0.00646,-0.004032,-0.002666,0.009735,-0.007072,-0.007362, +0.003067,0.007732,0.00457,0.001084,-0.0085,0.00392,0.0006833,-0.001245,-0.00907, +-0.00574,-0.006786,0.005386,-0.001034,0.00993,0.00913,-0.001817,0.00613,0.002943, +-0.00825,-0.008804,-0.00333,-0.00754,0.00971,-0.0002515,0.004715,0.006126,0.004963, +0.000591,-0.00912,-0.002254,0.0006866,-0.00998,0.001433,0.00787,-0.00933,-0.004326, +0.00771,0.002146,-0.006893,-0.003952,0.001425,-0.006123,0.00807,-0.00702,-0.006565, +0.001073,0.001927,-0.004864,0.000273,-0.008224,0.00826,-0.001634,-0.006905,-0.00831, +-0.00594,-0.002901,-0.001668,-0.00987,0.006264,-0.00452,-0.00924,0.0096,0.001883, +0.005104,0.003798,-0.00859,0.002163,0.000841,0.0001701,-0.00549,0.008896,-0.00641, +-0.0086,0.0094,-0.000762,0.000456,0.002989,-0.002628,-0.00817,-0.000566,0.005928, +-0.002151,-0.004353,-0.00403,-0.0009055,0.00814,-0.005325,0.001588,-0.00841,0.001743, +-0.00651,-0.002144,0.007225,-0.00623,-0.002226,-0.004345,0.007904,-0.007748,0.001748, +-0.003706,-0.00867,0.00432,-0.00954,0.0089,-0.00607,0.00603,0.00857,0.003477, +-0.0007524,0.000207,-0.00069,0.00925,-0.003777,-0.0002985,-0.001528,0.005077,0.007435, +0.005886,-0.001046,0.00491,-0.00346,-0.00944,0.0085,0.00011885,-0.007687,0.005142, +-0.005444,0.005745,0.00565,-0.005436,0.002954,0.0009327,-0.001357,-0.006035,-0.0038, +-0.00277,0.001201,-0.006207,0.00892,-0.00958,0.002432,0.009636,-0.006413,-0.000683, +0.000565,0.00664,0.006424,0.004097,0.00754,-0.0082,0.002491,0.00003463,-0.001084, +0.009895,-0.001157,-0.0044,-0.003542,-0.005615,0.00814,-0.002285,0.009605,0.008865, +0.00906,0.0059,-0.00735,0.0007353,-0.00103,-0.004868,0.007378,0.0074,-0.001978, +-0.00555,-0.004807,0.006527,-0.00968,-0.001172,-0.00988,0.00564,0.00213,0.004536, +-0.001937,0.007717,0.00901,-0.000779,0.003677,-0.00831,-0.005554,-0.005386,-0.00959, +-0.00885,0.007416,-0.00618,0.001828,-0.0004594,-0.0006585,-0.009636,0.007168,-0.00868, +-0.00848,-0.003803,-0.00875,0.002884,0.0002168,0.005486,0.00989,-0.00828,0.00000566, +-0.00811,-0.003649,0.003096,0.00365,-0.002344,-0.00879,0.006554,-0.0003917,0.00814, +-0.001268,0.00318,0.003078,-0.002525,-0.00848,-0.0004594,0.003298,0.003225,0.002396, +-0.00686,-0.00503,0.007534,0.009636,-0.00483,-0.00788,0.004208,0.0003386,-0.001907, +0.0008726,0.004757,-0.00989,-0.007004,0.0063,-0.006622,-0.00978,0.00899,0.002703, +0.00864,-0.009964,0.00617,0.005688,0.00846,0.00576,0.00788,0.0002687,0.00853, +-0.0002925,-0.003065,-0.0000076,0.007706,0.002523,-0.00212,-0.00532,0.007347,0.001383, +-0.004616,-0.008514,-0.00672,-0.00883,0.00195,-0.003576,-0.006306,0.005207,-0.002554, +-0.001393,-0.005966,0.005707,-0.001915,-0.002625,0.007797,0.00756,-0.003504,-0.004597, +-0.002932,-0.006004,-0.00928,0.006176,0.004486,-0.00594,-0.009476,0.006813,-0.00312, +-0.0014715,0.003428,0.00991,-0.004757,-0.0006704,0.001299,0.002937,0.005505,0.00843, +-0.004585,-0.00931,0.001348,-0.008545,0.001818,-0.002092,-0.00689,-0.009026,0.00949, +0.00166,0.000547,-0.000135,-0.000778,-0.001905,0.002375,0.00974,-0.004833,0.0094, +0.004898,-0.00005084,-0.001083,-0.00499,-0.00918,-0.004326,0.001663,0.00681,-0.003672, +0.00694,-0.00438,-0.007336,0.0089,0.00451,-0.00564,0.00986,0.006157,-0.00539, +-0.00551,0.00947,0.00881,0.005436,-0.008354,-0.005894,0.002949,0.0009093,-0.002594, +-0.002369,0.00507,-0.0088,0.0051,-0.0004027,0.001238,0.00854,0.008804,0.0005126, +0.00786,-0.001762,-0.002861,0.001445,-0.006268,-0.002352,-0.00737,-0.006973,0.005512, +0.005188,0.00951,-0.006603,0.002338,-0.001549,0.000984,0.00819,0.002796,-0.003716, +-0.00731,-0.004124,-0.00725,-0.002102,0.00493,0.00313,-0.002922,0.0076,0.00537, +-0.00929,0.00819,0.00932,0.00975,0.00345,0.001942,0.001167,-0.003649,-0.00787, +0.00857,0.00359,0.0015545,-0.001327,-0.00813,0.006893,-0.00185,-0.00689,0.00396, +0.003069,-0.002464,-0.003843,0.004967,-0.00865,-0.00503,0.003744,0.0003045,0.006298, +0.0011835,0.004654,-0.00736,-0.00171,-0.00807,-0.00462,0.00526,0.00905,-0.006798, +-0.0001366,0.00969,-0.005116,0.007614,-0.007317,-0.0052,0.0007396,0.00735,-0.00347, +-0.002716,0.005177,0.003021,-0.0026,0.00685,-0.003214,0.001522,-0.000601,0.00642, +0.002537,0.009705,0.0004787,0.00933,0.005848,-0.00789,-0.005962,-0.003063,0.00734, +0.008644,-0.00652,0.00389,0.00219,-0.005104,0.004536,0.006638,-0.00424,-0.000966, +-0.00242,-0.003347,0.000761,-0.006855,-0.00816,-0.00339,0.003853,0.00752,0.000502, +0.00394,0.00875,-0.001621,-0.00972,-0.000609,-0.00796,-0.003817,0.004166,0.003754, +-0.007385,-0.001137,-0.004467,-0.001389,0.0093,0.003342,-0.005795,-0.00792,0.0082, +0.00557,-0.00656,0.003494,0.002573,0.0014925,-0.003141,0.002457,0.00789,0.0071, +-0.004307,0.001407,0.000862,-0.007122,-0.005196,-0.00306,-0.00808,-0.004246,0.00772, +0.006165,0.002718,-0.00569,-0.000952,-0.005917,0.003725,-0.0008345,-0.00265,-0.0063, +0.001651,-0.00962,0.006016,0.005035,-0.004337,0.00552,0.00373,-0.0005794,0.00202, +-0.006985,-0.00747,-0.001536,-0.007122,-0.00937,-0.00641,-0.00871,-0.00182,0.0000921, +0.007484,-0.00974,0.00521,0.001293,0.0006785,-0.00888,0.005943,-0.00055,-0.00676, +-0.0000759,0.00414,0.007065,0.0000026,-0.003262,-0.001492,0.00802,0.003487,-0.00977, +-0.006863,-0.004192,-0.007458,-0.001814,-0.004482,0.008835,-0.004826,0.00872,0.004635, +0.007317,-0.00498,-0.003536,-0.004375,0.005074,-0.002346,0.00384,0.00853,-0.00416, +-0.007164,0.0006695,0.0008926,-0.001899,0.005783,0.00535,0.00557,-0.00402,0.00006354, +-0.001951,-0.002588,-0.005276,-0.001826,-0.006058,0.001427,-0.009735,0.009224,-0.00006384, +-0.002344,-0.00004303,0.00946,-0.00841,-0.00199,-0.00494,-0.00841,-0.008835,0.00596, +-0.006348,0.007545,0.001068,0.00624,-0.005306,0.001778,-0.0009108,-0.0048,-0.000988, +-0.0005326,-0.005173,0.003748,0.001759,-0.003914,-0.006252,0.004486,0.00882,0.006035, +-0.002064,-0.003456,-0.006615,-0.004963,0.003847,-0.00342,0.006115,-0.005974,0.002302, +-0.00856,0.006847,-0.006416,-0.00226,0.005363,0.008224,-0.0003793,-0.009224,-0.002298, +-0.005264,-0.000623,-0.00803,-0.007706,0.001601,0.007046,-0.004757,0.0044,0.0046, +-0.003963,-0.007156,0.0004344,0.005592,-0.00053,0.001337,0.009186,-0.00897,-0.005627, +-0.001647,0.0092,0.0016985,-0.003633,0.008064,0.004543,-0.00698,-0.005695,0.00478, +-0.001252,0.00881,-0.00876,-0.00202,-0.009514,0.000278,-0.005013,0.007404,-0.0005183, +-0.001753,-0.00442,0.00199,-0.008156,-0.008865,-0.00308,-0.00973,-0.005714,0.007996, +-0.004395,0.00455,-0.00862,-0.0004373,0.00885,0.00984,-0.00422,0.00382,0.001032, +-0.0003273,0.004593,0.004982,0.00259,-0.00604,0.000337,0.009186,-0.003052,-0.005085, +0.005188,0.00417,0.004345,0.003605,-0.000079,-0.009575,0.00894,0.00992,0.008, +-0.00476,0.00871,-0.007538,-0.00739,-0.0069,-0.008804,-0.00526,-0.001096,0.0009003, +0.005367,0.005283,0.005047,-0.0003638,-0.001063,-0.00399,0.0081,0.004395,0.00805, +-0.00531,0.001779,0.003176,0.00775,0.0071,0.00682,-0.0007925,-0.00318,0.00897, +-0.006172,-0.00376,-0.002518,-0.007618,0.00728,0.007042,0.006863,-0.005936,0.004787, +0.005726,-0.0009775,-0.004757,-0.0002875,0.00844,0.005302,0.003609,0.005863,0.005436, +0.004433,-0.002047,0.003025,0.007694,-0.007565,-0.006165,-0.00202,-0.004505,-0.004784, +0.00921,-0.00059,0.004604,0.002249,-0.004814,-0.00519,-0.00625,0.0000181,0.00531, +0.001533,0.006847,-0.00959,-0.00846,-0.00928,-0.006386,0.002766,-0.005516,-0.0071, +0.006073,0.00907,0.005585,-0.00644,-0.00855,-0.003466,-0.009514,-0.00914,0.003702, +-0.00503,-0.00497,0.00796,-0.007763,0.007614,0.00544,0.00933,0.008316,-0.003374, +-0.00763,0.002035,0.002916,-0.0006156,-0.003872,-0.0002236,-0.00917,-0.003334,-0.004528, +0.00978,-0.0005903,-0.006786,-0.00913,-0.009254,-0.006096,0.002638,0.003622,-0.007805, +0.00873,0.001586,-0.003641,0.001905,-0.00311,-0.000627,0.005222,-0.004986,0.000169, +-0.007088,-0.00783,-0.004852,0.000881,0.004627,-0.00405,-0.006405,0.003586,0.002258, +-0.00988,0.000979,-0.002949,0.00912,0.00885,-0.002743,0.00833,0.003326,-0.0003536, +-0.003792,-0.00941,0.000213,-0.002922,-0.001483,-0.003443,-0.00307,-0.005894,0.003468, +0.001887,-0.006832,-0.00828,-0.006172,-0.00746,0.002558,0.00998,0.001123,-0.00611, +-0.005863,-0.0007744,0.003525,-0.00573,0.0009665,-0.002241,-0.0007176,-0.00918,-0.00794, +0.00216,-0.0049,0.002016,0.006763,0.00445,0.004715,0.001216,0.002068,-0.001449, +0.00249,0.00953,-0.0007606,-0.00256,0.0006046,-0.004406,-0.009415,0.003393,-0.004787, +0.002743,0.00841,0.00972,-0.00194,0.004185,0.00585,0.007504,-0.00622,0.001107, +-0.0044,0.00576,0.00772,0.00818,0.00536,0.002644,-0.00465,-0.0087,-0.00816, +0.004547,0.001851,-0.005634,0.003641,0.007618,-0.00985,0.009766,-0.00459,-0.002457, +0.00393,-0.008224,-0.003952,-0.00813,0.007393,0.005188,0.007126,0.00639,0.001274, +0.002176,-0.00894,0.002445,-0.001414,-0.00952,0.004444,-0.001607,-0.001501,0.00857, +-0.005585,-0.000724,0.003077,0.007797,0.007473,0.003546,-0.00948,-0.003933,0.004017, +-0.003176,0.001448,0.002731,0.003504,0.00831,0.007763,0.002405,-0.006264,0.00536, +-0.0083,0.001413,-0.0003624,-0.001836,0.006027,0.005173,-0.003073,-0.008354,0.00164, +-0.001941,-0.002981,0.008156,-0.004414,-0.005413,0.002527,-0.0004022,0.00625,0.008575, +0.00637,0.00765,0.0003421,0.00798,-0.005287,0.00808,-0.00646,0.000603,0.00955, +0.00889,-0.002356,-0.005306,0.002333,0.009514,-0.003855,0.0054,0.005417,0.000675, +-0.004402,0.00933,-0.005234,-0.00958,0.0089,0.009254,-0.00757,0.0098,-0.001879, +0.00789,0.002071,0.000677,-0.007763,-0.001941,0.001637,-0.003653,0.00528,0.007465, +-0.00557,-0.006004,-0.009476,0.000802,0.002075,-0.007168,0.00398,-0.006268,0.006287, +-0.009575,-0.001453,0.0092,-0.00995,-0.002644,0.005024,0.00966,-0.006878,0.00995, +-0.001319,-0.002237,0.002209,0.00861,-0.00883,-0.003874,-0.002903,0.00992,-0.0016365, +-0.00633,0.00823,-0.00771,-0.003204,-0.00563,0.00563,0.00805,-0.004936,0.003477, +0.00741,0.0043,0.006905, +=== +name:Bias_3_64.bias_data +-0.003569,-0.00789,0.002047,-0.002829,-0.000592,-0.003313,0.00805,-0.007397,-0.006844, +0.00809,-0.003479,-0.0017395,0.007904,-0.009056,0.005806,0.008896,0.004585,-0.002356, +-0.003815,-0.00673,0.005787,-0.001892,0.003233,0.005566,-0.007626,0.00835,0.009415, +-0.005707,-0.0002623,-0.007496,-0.003569,-0.00568,-0.000693,0.00857,0.006607,0.005245, +-0.0006056,0.008896,0.0000753,-0.0001878,-0.00957,-0.003975,0.003006,-0.006794,-0.007935, +0.004246,0.004948,0.008896,-0.0046,-0.002516,-0.000887,-0.004555,0.002409,0.00364, +-0.002491,0.004204,0.00010544,0.000783,0.00895,0.005367,-0.004097,-0.00592,0.009834, +0.001047,0.00677,-0.004974,-0.003212,0.00771,-0.002256,-0.001008,-0.008484,-0.002802, +0.00462,0.001329,0.004562,0.006687,0.002615,0.001449,-0.0006714,-0.001256,0.0003803, +-0.005238,-0.004112,0.001925,-0.002827,-0.00861,-0.004723,-0.002748,-0.006134,-0.00342, +-0.007168,0.006626,0.001948,-0.003838,0.006878,-0.001717,-0.003347,-0.006287,0.00455, +-0.00136,0.004364,0.006573,-0.007545,-0.004845,0.00883,0.00572,0.00675,-0.003206, +-0.00842,0.006428,0.00394,0.000642,-0.002016,0.004486,0.009964,-0.00918,-0.0084, +0.001972,0.002031,-0.00976,-0.004494,0.006958,-0.00262,0.00874,0.009865,0.0075, +-0.00271,-0.006386,0.002562,0.006397,0.00699,-0.001731,0.005432,0.00271,-0.006447, +-0.00892,0.002897,-0.0004315,0.001859,-0.003462,0.007122,-0.005135,0.005363,0.0051, +0.00806,0.00721,0.00799,0.00945,-0.006943,0.006393,0.00935,-0.0003269,-0.004536, +-0.006752,0.0095,0.00628,-0.00418,0.001624,-0.005577,-0.008606,0.005486,0.002077, +0.007378,0.004734,0.0035,0.00991,-0.001775,0.00247,-0.00613,0.007202,-0.00596, +0.003876,-0.00789,0.004505,0.004795,-0.002575,-0.002932,-0.003098,-0.005463,-0.00912, +-0.00729,0.004486,0.006138,0.006924,-0.00722,0.00841,-0.001812,-0.00959,-0.000497, +-0.00513,-0.006042,0.007645, +=== +name:CrossAttentionData_HeadSize40.query_data +-1.22662961,-0.35233688,-2.51795793,3.08565354,4.24220848,-2.51427174, +2.22180820,-1.92292845,-0.35114169,1.70695090,1.69466066,0.27359068, +-0.64067757,-0.63457423,1.04695463,4.04613352,0.97944307,0.15350986, +1.67937851,-1.36576056,0.77318615,-1.27569389,4.60397625,-3.19242692, +0.48934177,-3.07935381,-0.11483648,1.47204328,-0.63523442,0.67073810, +2.80178523,2.67149448,-2.81271029,2.68525839,4.68173981,2.91258001, +3.57226992,-3.05520511,2.54316950,2.00077820,-0.95679653,-0.32389647, +3.40642309,-3.41444898,0.42168373,3.71653891,1.74413025,-2.31608653, +-1.05382800,2.33529496,-0.03115923,-2.09196687,2.51712871,0.32415283, +1.06346369,-0.36822113,4.68930340,0.46780801,-3.73769474,0.48317379, +0.39232603,0.27411360,-3.42274952,3.13843346,-1.47643280,1.33143926, +-1.77027559,0.64681566,-2.24492526,0.45514423,3.05239010,-2.77623415, +-0.01523268,-1.31303573,-3.99167180,-1.17848396,2.49592471,2.05467582, +-4.28567028,-0.01797819, +4.67106724,1.53385055,3.39424896,3.93220329,1.68718219,2.44518471, +-2.88907123,-0.35424405,3.01430655,2.46258259,0.76977682,-0.16410893, +-0.17463332,-3.87755418,1.83313918,-2.97483563,-4.08703470,-0.08439432, +5.29304314,1.78443372,-3.78656173,-2.07051849,1.88238001,-5.19135237, +3.88775992,-2.59292984,-4.11207771,3.96229005,-0.83118176,-3.83982468, +2.46327686,-2.20555806,2.71137404,0.36317801,0.03267325,1.49253511, +-1.07765102,-0.87420821,-1.38492739,-3.10283113,-6.48412514,-3.24393439, +-3.83601141,-4.89051533,2.25563264,2.33896637,3.08240438,0.25861615, +5.35156775,-4.30155373,-0.39909154,0.51361942,1.70603693,0.56104976, +-0.53627640,-1.02876902,-1.52522588,3.84260535,0.69256341,6.54086208, +1.46197557,-0.43632865,-0.60465157,-1.64424038,1.38061714,0.57246995, +1.95028961,1.26038134,2.30116510,-0.49234268,-2.46396661,-3.20620775, +-3.26575089,1.24299562,2.17106104,-2.19775343,3.60124683,0.57973087, +1.07749140,4.91360235, +-0.21669322,0.33139130,1.75449383,9.52622700,2.17485499,-1.66917014, +0.03545052,4.18067980,0.00023159,1.33923185,-0.87918806,-3.50237155, +-1.46006012,0.60015154,5.83271360,-0.22819775,-0.31121445,5.66988373, +0.79325175,0.96488249,-1.70520842,-0.63099504,-0.57731283,-0.83466154, +-1.16551876,3.83186436,-1.45056069,0.50383788,-1.44579923,0.65660918, +2.41228318,-1.77592456,-0.22811326,-1.30705166,1.98969173,-4.51494265, +-1.47827673,-3.64490080,2.93946624,1.29824829,-3.46210217,-3.89081907, +-1.48601687,-1.11542952,-1.94489884,-0.12696570,-0.23979390,3.19791436, +-0.63295209,1.12001634,-5.84728909,1.05678606,-1.42075634,0.05558330, +4.61813593,0.36126173,-1.55681753,1.49261308,1.44369054,-1.89044309, +0.72794700,0.88410646,1.78280950,0.46480489,-1.13712585,1.98804855, +-0.50860095,-0.82247877,-0.84092993,0.15579975,-0.83490044,1.40706611, +-0.62802029,-1.00020695,-0.42161250,4.65616417,-0.14566854,-5.21770144, +-1.80859923,-1.88397610, + +0.72858512,0.76285082,-3.54603267,-2.76666427,-0.74586105,3.07966805, +-1.23183393,2.65814924,-0.48954675,-0.01422951,-0.80523360,-0.05636902, +4.50960302,0.39967048,2.12411642,-2.80581498,-1.23623741,-0.83596331, +-1.59570324,0.31865728,-2.93341351,-0.91071963,-5.62822533,-0.31141007, +3.66986752,0.29200572,4.50133896,-0.04906014,0.30284458,2.08347201, +-0.26345047,2.89623761,1.47789168,0.25719327,0.59193242,3.06752014, +0.77815592,5.36399746,-0.98917627,0.74345785,0.37825125,0.39711678, +-0.51693177,0.70721328,-1.65618515,0.39366072,-0.48523498,0.26791164, +0.74384177,-0.01070565,2.06832695,4.09473038,-1.93577170,4.44833660, +-3.57158875,1.13177609,0.04097128,0.97592485,0.32749751,-0.63181406, +1.32568705,4.11899281,-0.01445001,-3.27274179,-0.33302760,1.99459851, +-0.71278077,-2.11359572,-0.49344134,2.91824555,-0.30017141,3.06603670, +0.70625454,-1.72438312,1.29221559,2.61260676,-3.74348974,-0.74985051, +3.06313038,0.40784115, +3.00617576,0.60401130,-2.26022601,2.65955663,4.51086712,3.18778396, +-2.03404522,-1.75254703,1.52366590,2.97461796,-1.71983969,1.67460120, +-1.67232358,-4.60054970,1.20151567,-1.35206270,-2.52547383,-0.32723871, +0.20907879,3.33950758,1.31350076,4.40201521,4.84729719,-2.02246284, +2.26325178,-4.70484352,1.19820619,-2.06560230,2.01903844,0.70123076, +-2.18283868,-1.58728933,-1.76427519,1.73031628,-1.02397823,-0.82483894, +4.28719187,1.03131247,-4.00242376,0.55060416,0.69296157,-0.40307230, +-1.57899165,-0.64626098,0.38460332,-2.79192090,-0.99241018,-6.47022247, +2.35969114,2.68988562,2.01771092,-0.50948638,-4.10946798,1.78115523, +2.07683706,0.83665949,-1.96493793,1.29946780,1.07797444,0.23147804, +-2.62031913,-2.29383564,-0.75740218,-2.22285056,-1.37344193,-0.63702244, +-2.69008708,-3.54949689,-4.93013477,0.94476449,0.50843441,-2.43133783, +-0.73139656,-4.14991760,2.21933579,-0.23957914,0.21414763,1.72857785, +-1.93757868,4.37800264, +2.67474079,2.48818779,-1.69955230,3.70085597,-3.42685413,-2.94546223, +0.31883699,-3.10525227,-2.03184032,-5.62139654,2.08026147,0.76601815, +-2.61922121,1.76908946,0.33427981,0.48602962,0.68285787,-2.60781908, +-0.69706583,6.12323284,-1.74903524,4.59135532,4.35664511,-3.56304765, +-0.38409889,1.03420079,-0.45078808,0.69308978,0.21725583,-5.65227365, +2.69256592,0.09329325,-1.82679415,-0.74413943,0.29465687,3.46686363, +-1.47279978,-0.97846490,2.22824383,-1.11907578,-1.49388766,-3.98522091, +-0.20471978,-1.08247757,1.70455170,0.19429864,1.07981837,-3.89726448, +1.63762915,0.33783519,0.79741430,-2.02730107,0.82039660,-5.06940222, +0.40322316,0.00218159,-0.88644981,3.36438680,-0.04906791,3.78314805, +-0.40462697,1.39699149,-4.14074135,-0.21723330,0.92299151,-1.46231139, +3.57588029,4.19913292,6.70203686,3.35416508,-6.50804901,1.98294961, +-2.87230039,-2.51358604,1.91030347,-1.50729156,5.15285301,4.33989143, +-2.16627169,-2.91071749, +=== +name:CrossAttentionData_HeadSize40.key_data +-0.44590849,1.98493946,-1.07127249,1.40504324,2.12171221,-2.04918909, +-1.83530343,-3.76758623,0.02538997,2.64762068,-2.56781912,-1.14145339, +-1.80042803,0.39801449,0.34181327,-1.57265723,0.07036242,-2.40207338, +0.73444951,0.93564862,-1.43117201,-0.40992564,2.72084332,3.10532832, +-0.89440274,3.50889730,5.25270414,1.19936800,-2.38253307,-1.09552169, +-0.91941810,-3.95936108,-1.12715232,-2.32673430,1.70554638,-1.82651567, +0.18641475,-1.13930595,-2.08975363,0.77337563,-1.61064386,1.86085737, +1.24908817,-3.56172729,3.49342513,1.41598260,0.23467612,0.77325898, +-0.24176371,-1.04892051,2.13891983,-0.73367226,3.19356060,-3.52643967, +-2.61323428,-1.89149976,-3.33599472,-1.76190269,0.35278416,1.00504446, +4.52736902,-1.29095161,-2.10441589,-2.20554256,1.28037739,2.01972723, +-2.59777713,4.17468357,-0.63373142,1.95862389,-0.63698387,-4.30598640, +-4.10062265,1.14486885,-3.12371159,0.18818541,-2.42273569,3.72320580, +1.78546739,1.12837386, +-5.69526672,0.45080167,-0.34738344,2.19837046,2.02498674,-1.67241764, +1.03066158,3.49398828,0.68212295,-0.13683093,1.35417783,-0.76712447, +-1.20502079,1.80041981,2.03709221,-1.15552354,3.62633824,-4.34337473, +-0.03111041,-0.05806269,-5.65434170,-3.99450684,-5.27107000,1.45356524, +-8.49876404,2.57157731,-0.60446721,3.32191849,-0.79453731,0.82028484, +1.27183342,-0.99072194,0.25417966,-4.80432510,5.19692039,-0.64962041, +-1.29197633,-4.19478750,-2.35304260,3.06083965,-3.17496777,3.22834659, +2.40038896,-7.20073223,3.93310833,-4.55644560,7.31054592,-1.97445476, +-0.00740963,1.57046604,1.45884740,1.37348962,3.05838251,-3.32491112, +-0.05218773,-2.32320046,-5.33921146,-3.68838453,1.82249427,-8.29404068, +2.02283478,-1.02023602,7.00944805,4.51306248,1.65528119,3.14541531, +3.68995571,5.60512161,-0.72604638,0.62305540,-3.26601505,-1.07749093, +-4.70862913,-0.11774403,-3.28379011,-5.44625950,-1.28474891,0.05496073, +3.28144360,-1.71310043, +-3.72890472,0.47998995,-1.64674330,4.25828552,0.48567617,3.76386666, +0.72125065,2.58443975,-0.80270696,1.36818254,0.60624528,1.12298989, +2.61748505,-1.76728272,1.59453869,-1.49594533,1.61122751,-1.65819097, +1.07322979,1.00919533,1.83750582,-2.11553884,3.05492759,-1.13376379, +1.04176581,1.05297565,-3.80754805,1.75729048,1.56833780,-1.90021074, +2.53051329,-3.98260069,-2.79277897,0.57372808,1.82531142,-4.22809839, +0.12054175,-1.64285707,-1.75917435,5.92044210,2.00746799,0.08308759, +1.31818652,0.92133123,0.07876605,-0.78835499,-0.59225237,-2.75223637, +-4.23076820,-0.13776526,2.51437116,0.46347374,-0.87072194,0.47312742, +-0.91241401,2.09434414,-2.00047112,0.22087479,-3.57630754,-1.65337551, +-1.57748485,3.06805706,2.91149712,-0.84392685,-1.63053262,-3.17057562, +3.44940352,2.34603477,-1.70127904,-1.73411393,-0.44733244,2.55546784, +2.33501554,-0.44483477,1.68014634,0.99101388,0.04672858,-1.05605829, +0.71787786,-0.04861724, +-1.81776059,1.48426533,-0.53543252,-4.75410509,-3.73359323,-2.20236874, +-2.80877733,-6.16635466,1.27804232,-4.55014563,-0.30002296,-0.96774644, +-2.15660477,-2.60649943,1.64775360,-2.45114946,1.63522851,-4.00816679, +-2.96872401,5.98173285,-0.55584449,-2.16505861,-5.00163412,-1.56468248, +1.90084171,-0.29323232,0.14279747,-4.27117109,-3.05262256,3.13814020, +0.04283291,-1.22592390,2.14044142,-4.04049444,-0.79627764,-1.17387509, +4.22917747,-2.22369123,1.31827044,-1.80392468,2.89961600,-0.25374252, +-3.79463124,-1.27755213,3.14444208,0.72191542,3.55277538,-1.59686506, +2.26461124,1.25676811,0.77055168,-0.64221799,-1.82437253,1.35799241, +0.62414169,0.83287644,2.08709836,0.74611753,5.53408194,-1.18227792, +2.33974051,-4.09171057,-4.39363194,0.75839132,-0.78278774,1.09352303, +0.64267069,-0.66581339,-1.85293758,-3.92538142,3.70205355,5.30183840, +2.44776297,1.17696786,-1.28278828,0.86428756,-0.78950930,-4.30053949, +1.21166849,0.49365181, +1.22390628,-1.83765507,1.76312578,1.97146916,-0.65910506,-0.02966955, +4.04420996,0.24049535,1.59509969,2.95982647,1.49622416,-2.07731581, +1.51230788,3.48245192,2.55489254,-4.42068148,-2.77923799,-1.79879463, +-0.43417776,-0.91141713,-1.83134556,-0.77197945,-2.80744791,2.38423347, +-0.42536554,-0.29175264,-2.96979785,-2.73573685,1.16224599,1.28292751, +-2.42575717,-4.35106182,2.40325737,-1.35585093,3.63722515,0.07650419, +0.34960657,2.76701641,1.12685931,3.45839715,-1.16243958,3.93772221, +-0.69577467,-0.72007394,1.37339377,-1.43409979,3.66146350,0.36440611, +-0.08672673,2.09590149,4.58786106,1.64420795,-1.62949383,0.38805187, +2.54591107,-0.87228912,2.05350280,-3.01149988,2.49309850,-2.03635573, +-1.52769530,-0.90678239,2.77345419,2.05674124,-0.52915704,0.76992738, +4.50094604,6.16655207,1.21820283,-0.59180433,1.53090405,0.53589046, +-4.29825354,2.37933564,-1.39599502,-0.04555070,-1.91196442,-1.72819281, +2.54402304,-4.74867582, + +1.77389085,0.26504007,-3.06724691,-3.37732267,0.88862455,-4.00978708, +2.42969346,-1.52222490,-1.84140372,-4.12711906,-0.17829326,1.40618205, +3.53640866,3.14457250,-0.42408764,1.06623757,1.56950164,2.94928074, +-0.37585315,-4.58977413,-1.19122314,2.76285672,3.75529385,-3.26022458, +-1.74535918,4.89308929,0.46158761,5.31557655,1.14788485,0.56015950, +-1.68876886,-2.03965187,-0.70566773,3.10552740,3.16705012,-0.80952662, +-0.43075383,2.67507076,5.41066170,3.43606973,4.90483046,1.84608901, +-6.85163450,-3.06533241,8.21495438,4.43654871,2.09319234,-4.42602158, +0.92209107,-1.70933890,3.71371031,3.94706774,-0.36061627,2.57590103, +0.98262388,1.82917500,2.80233479,-0.51830429,6.43664169,-3.07223606, +-4.74569941,3.45030975,0.32298383,2.79728365,2.33600187,2.18209934, +1.03046095,1.77432561,-0.16497695,-1.69815969,-4.80686665,-2.34232450, +7.86733055,-0.65266341,-2.63244128,-1.64666939,-1.15842938,3.89964366, +0.06546612,2.84245849, +0.63745236,-0.60043466,0.15597063,-2.17756677,-0.84348190,-6.30688715, +1.15000510,2.18763089,0.56617486,-0.96061355,0.72410244,-2.55619860, +-3.74980140,-1.01026285,1.05149317,-0.83054101,9.09637737,-3.59927368, +0.64024138,-2.43417788,-2.71296763,-1.57347786,-0.52432519,3.47116017, +-1.22401500,-1.55714345,-1.73517704,0.57135445,4.34634066,5.07363987, +0.14575702,3.29643679,0.20970452,-1.18641806,1.82565367,3.79054165, +3.11241078,-2.33457327,-1.79234099,-0.77043331,0.94371402,4.95805883, +-1.21386683,-2.62089586,1.04984260,4.77972317,3.80148745,2.57944679, +-1.62215877,-1.48487663,-0.88516212,2.47205591,1.25198030,-1.49769402, +1.49644077,-1.21963966,-4.22067022,0.07715815,-0.05838633,0.02521211, +1.54778171,-0.68474317,3.87327027,0.36594340,3.28861642,1.84371138, +0.87659311,0.23867008,-1.22515559,0.87271261,-2.45830512,-4.59441233, +-4.72528791,1.07633507,-0.76005602,-6.56183910,0.93921316,4.07901239, +0.65637922,1.09935892, +-1.52171361,0.36837816,2.44905639,1.71517515,-3.21964288,-1.30028033, +-0.47215480,-0.03559750,2.39852405,-2.82084513,-0.07759643,-1.71475554, +5.37419796,-1.69430733,1.42850208,-4.45167494,0.05887067,1.84818649, +-2.30660439,1.29194844,-3.19126892,2.09994006,-5.04377365,-1.00292349, +-3.30398607,1.46449196,-0.73720878,3.07083178,2.50308442,-4.58036995, +-5.30711460,1.14685988,-3.43290782,-3.42758298,-1.73553753,1.28076029, +0.81061542,-4.45261192,-0.37263635,2.39974928,3.57600760,2.10931325, +-1.61413431,-2.39997077,-4.10416794,-1.38086832,-0.63188541,1.46728146, +-2.24996948,2.49746299,-0.73199594,-0.97014105,1.54047072,-2.66780996, +5.37116718,2.82218075,-1.62108850,2.72595692,-1.79463971,-1.87041128, +-4.71584415,1.82171798,-2.90882301,2.87121320,-2.57487297,-0.22736369, +1.34005880,-0.27021503,-1.39979327,1.24117494,4.63584423,1.43412280, +1.22960615,-3.07072306,4.03779936,-1.11251736,-3.76871419,-3.14926720, +-1.65451026,0.64419544, +2.68210387,5.84884739,-2.46407223,3.87640619,-0.33028477,-4.32690859, +-1.16703165,1.21859503,-0.54117912,-2.19271398,-0.51750636,1.76933861, +1.60338795,-1.61012948,4.91132116,-2.04804540,1.24183416,-0.04860526, +-2.21050048,-1.88805938,-3.04969406,-1.23892701,-0.06367862,0.46349186, +-2.34568119,-3.52605510,0.72856915,-1.24463606,3.83235240,-1.56133997, +-3.22448444,1.99090147,-2.27550173,-1.82680321,2.01301694,2.99845076, +2.90344477,-0.83625877,-1.13337862,0.64514792,0.03786933,2.19324684, +-1.80451119,0.67776012,3.11744428,-0.24457633,-0.45526421,1.37050200, +-0.05366212,-0.14649165,-7.00798512,-1.94217563,1.93492782,-1.89671147, +-0.97781098,3.61308098,1.98817432,-2.60251522,4.22469711,0.88692582, +0.89745212,1.17353654,0.54682076,-1.99516833,3.81800508,2.68964338, +1.08577883,2.27413726,-0.23109391,3.24835920,1.27708983,0.35086024, +-2.10146737,1.52129221,-0.56323838,1.71683300,-1.82481837,-3.74832487, +3.97903419,2.70656705, +0.54202497,1.58516026,0.38604254,2.67667460,3.48077846,-3.52633214, +0.68681777,-2.25850630,2.76701570,0.30912635,-3.02949572,-5.94854355, +2.52342463,0.49857450,-0.76799512,-1.38036680,3.46629524,0.67081052, +-1.44662499,0.40994781,3.02867222,3.72760630,-1.68694305,-0.75258541, +2.12057924,1.28757250,0.24050999,0.95728469,1.68175769,-3.11903358, +-1.02161658,-0.54389447,1.99784613,0.69883800,-0.92166108,-0.84107661, +0.18834084,2.21262383,2.83887744,1.16888499,-1.31167865,-1.22881663, +-0.04097224,0.81264222,0.20924969,-0.07720196,4.18504333,0.45721883, +-1.43579936,4.08936310,-1.00441456,0.45323381,-0.84993589,0.54930854, +-0.20439517,-1.31673455,2.80454016,1.10617089,-0.61983430,-1.21147370, +2.87613988,-0.63006109,-0.87298799,-1.79945171,1.75379634,-0.03284079, +-3.16018248,-1.70393991,-1.00085866,-2.04588270,3.25270534,0.62951756, +-3.74736595,1.08699441,-1.01408458,-0.82118225,0.09517595,-1.97260141, +4.06293917,-1.53105283, +=== +name:CrossAttentionData_HeadSize40.value_data +2.52200770,3.33522081,1.02251101,-0.19524473,-3.71459103,-0.02477702, +-1.39731681,-5.58580303,0.30901617,0.76306605,-2.04605818,1.61113453, +0.71565157,2.62568450,-5.18361902,-1.70342803,1.42449617,-1.30358791, +1.06270623,3.04715180,-0.25380951,2.84206176,2.05601597,-0.55873990, +-3.71717381,1.29085660,0.27478188,5.44427061,-3.59301615,-0.25955540, +-0.70427519,-1.97779632,0.98796690,-3.75880170,1.34103966,-0.39008784, +-1.04290402,-1.16061938,-1.91779065,-0.61740541,0.13198879,-3.11491537, +-0.86305869,3.78544807,-3.27862763,1.77973413,-2.43130898,0.11999905, +1.96149552,4.96055317,3.92319894,2.29237580,-4.07357836,2.23905349, +-0.84580690,-2.24981976,-2.03560781,-1.88958716,-1.10143483,2.26368880, +3.24453497,1.19321299,-3.65723705,-3.01728868,2.69581604,-3.16313481, +-6.37331009,-2.40505695,1.88986635,4.99678659,0.22641480,-1.02873325, +-1.16671526,-5.14537668,-0.41974550,0.55167019,1.17046857,6.18922234, +3.05369854,4.05916214, +1.64212084,2.18478417,-2.68270802,-1.17468357,0.31818610,1.02590501, +-2.91689920,-0.39902568,4.53725624,2.38986945,2.08665752,-3.77494550, +4.75398874,3.46525812,2.60498571,1.68801785,-1.59054160,4.38700676, +1.33280611,-2.05578661,-3.67522144,-1.85783577,1.84266996,2.48572135, +-5.76279545,4.83649015,-1.39598393,4.55631828,0.88710690,-0.25037968, +-5.06323290,-2.82429934,2.45077682,2.26839566,-2.15198541,-0.92987227, +0.98444796,-4.77959299,-1.00593686,-1.12779152,-0.41504347,-0.10360003, +-1.36064351,-2.65771484,-1.74305487,-1.43110847,3.73240304,-8.55393791, +1.61241794,0.20090955,0.16259992,2.51827145,-4.88276291,0.65994090, +-1.85566723,2.85304689,-2.25546956,-1.81180429,-0.73952389,-0.69026655, +6.46290684,-3.42528129,-1.68900692,-2.63187265,1.23666155,-1.80273986, +-5.34096527,2.39473057,-1.12343872,0.50738329,1.06165779,-1.25881910, +1.30416012,-0.39503133,1.06663299,-2.36198807,2.11466384,1.42665458, +0.47875917,0.84987718, +-1.42672980,2.15086913,1.05465066,-2.24732041,-0.04627687,1.35561931, +-2.22631431,1.87147117,2.68784380,-6.75409317,1.75816703,-1.32267916, +-0.30795556,3.21814609,1.92649913,5.51574183,-5.45856047,1.69647682, +-3.66586471,1.25441813,-2.27710414,4.21629810,0.02650413,-0.05531013, +1.46342337,0.35316384,1.58090007,0.88646221,4.47589302,-4.34421301, +0.02980316,-0.58578295,1.79196024,1.78082383,0.14971030,-4.34231663, +-0.56575900,-1.75833559,-0.84479707,-2.73750734,-4.26857948,1.44429922, +0.18011174,-1.11181009,-1.31634200,-1.98439252,3.27634311,-2.73307896, +1.83559537,-2.95653439,-3.93072486,3.32339287,-2.88254499,-0.90710086, +3.82468128,-2.26418972,0.21428287,-5.71086216,1.08876240,3.38046408, +-0.81207389,2.31772232,-0.11134154,1.18450689,-2.37789607,-0.00142117, +0.72909313,0.68614733,-0.77563363,-2.34862852,1.05669081,-1.86599076, +1.98130095,0.92516875,-2.72275639,2.71904421,0.23536620,-1.72734010, +-3.43704534,-3.67876530, +4.29205894,0.72032785,-1.49616945,-1.84139895,0.30715290,-3.04337001, +0.66906673,1.73802924,-0.07174578,2.89249015,2.21281481,-0.97710615, +-4.89526510,-1.05043483,-2.97074080,-1.34177089,2.20932603,4.01438665, +2.96217227,0.57981884,1.12104404,-0.55145615,0.68083727,1.99328470, +-4.87487507,-0.15801801,-0.08008248,2.49206161,4.36795998,-0.79805094, +-2.13833427,2.47042608,0.36067075,3.26598382,1.98279870,-1.89963067, +0.30437571,1.26811552,-1.55896103,-1.26593304,-5.15960598,-1.46925342, +4.01534986,-0.20960769,0.16190898,1.63501847,-1.58879602,0.31569052, +0.25710380,-1.18716395,3.51842332,-3.30306745,3.31757665,-1.89535034, +-1.90357256,6.20105791,1.91351593,1.04002178,1.18122804,-0.22888322, +0.66158205,3.04200125,2.67628670,-0.64249665,-2.07746315,5.54076958, +-3.00114274,0.68613434,-4.45081329,0.00587352,2.03132582,-1.60416722, +-3.08808851,0.95315832,0.46982890,-3.28788757,-2.82306862,1.49545765, +-2.77738333,-1.43082714, +-1.33299255,2.78721404,-2.25095224,-0.89978874,-1.20683730,-0.74944079, +-2.88921618,-0.18277466,0.00372136,-1.80246174,4.19822025,-1.82120311, +2.43893075,-0.92111945,-2.22253442,1.43559384,-3.10266304,1.44538188, +1.68185592,0.84382743,-1.83896518,-5.66177320,0.95111668,-5.65224314, +-3.78799438,-1.59245038,2.68568468,3.82559538,0.67030597,-1.00240803, +-6.75469112,-0.14708334,4.54812241,-3.05194640,2.39797926,-0.00272782, +-1.41322088,2.25726366,0.13995156,-0.57747078,-6.58918333,1.21203697, +-2.24320960,-1.59526610,-2.24520969,-0.37764102,-0.14032492,-4.60604239, +2.52268362,-3.05438852,-1.93661046,-1.98484039,2.17252684,2.72310734, +1.35985041,0.74225116,1.46986079,-3.13677359,0.46207923,2.92159390, +-0.26587552,0.92518401,-0.19378644,1.43351614,2.80231071,-2.39726210, +-4.11096096,1.53613114,-3.41936874,-0.81401485,4.18615103,-1.20390248, +0.29101330,-0.55211830,-0.90347737,0.72938609,-0.41552329,-2.86164975, +2.14127350,-2.71393037, + +2.06101036,-2.49327445,-0.26084259,-0.08738496,-5.46849871,2.66518831, +-2.23898268,-0.58128607,-4.77391148,3.53860617,5.66361809,1.88735557, +5.31760883,4.64165354,-1.88971460,-0.18464115,1.44575036,0.71620363, +5.20483541,0.17650539,4.55752707,0.14761698,4.97212982,0.38257861, +-0.86314517,3.00640798,2.82556558,-5.72242022,0.97359830,0.12829947, +4.27856922,3.06020951,-4.39019632,-6.17075443,-3.69274259,5.33883333, +-4.09268999,-0.42381752,-4.86064196,0.87817371,-1.66327834,2.06401992, +-0.45039526,2.00427246,6.28635406,-4.28625345,0.64066625,1.98521018, +1.28183603,1.96348131,3.25338674,-4.83068466,-1.22748399,-1.83176708, +0.99235696,3.90817499,0.15236929,-1.11182845,0.28134999,2.88753319, +0.94340092,-2.33726883,-0.26672745,-0.47063547,-3.89827800,-0.60715055, +-10.64067078,-0.46934411,-0.17723195,0.31426474,0.26794863,-2.33281183, +-0.83772266,-3.00178385,-3.04406095,5.08712959,-2.82472014,2.50977850, +-5.92609453,0.80104923, +1.74909449,3.36070085,-5.19149637,2.02698421,1.72980452,-3.32840133, +1.31092596,1.08732378,0.70107508,-4.48935890,3.30084705,-2.01938772, +-0.57465255,1.43294013,1.41905987,-8.33140659,-0.08440223,-0.86436093, +-0.86385047,-0.06775177,-1.36902046,-4.34248447,1.25420880,-0.31501776, +-4.61437702,-0.80756599,-1.81841552,-0.23593402,-1.72089577,-2.38486695, +-1.77567720,-0.99221468,-0.39361507,3.94493699,-0.44989038,-4.16036463, +-2.75135875,0.51079714,-3.13808584,-1.45286632,3.38582993,1.72332990, +0.42072344,3.39117050,-4.21982670,2.96172690,-0.30759099,-0.07023232, +-5.51846933,3.23913264,2.17243195,1.15772712,-3.94762301,2.75720644, +-1.61080432,-0.51649714,-1.34688985,2.42340302,-1.40935290,-0.30057096, +3.59142900,4.29019451,1.10035944,-2.74829841,-4.27969074,-2.08663464, +-3.74090290,-2.46784139,3.63337183,-3.26299858,5.80690861,-1.71136200, +-0.40768790,-1.70319510,2.13231635,0.14728940,4.53216934,-2.27770376, +-0.78596526,-1.09226680, +-0.45473242,-7.20685625,0.59849894,2.44483280,-0.93482894,2.15730143, +-3.87125921,-0.19056010,1.05693293,-0.16091427,2.58152556,-2.79246712, +-3.29887533,-2.00540090,0.59734398,0.59127998,-2.85143566,-1.80759144, +-3.25450134,-3.59059358,-5.00572824,-5.37265396,3.08453035,0.84874475, +0.76036537,4.34558249,4.40313244,-5.61378384,3.78151655,-1.16012287, +-1.08296275,-0.84596092,3.32365799,2.11034679,2.42330313,1.83046317, +-1.92273235,5.67875910,1.78094673,0.36037564,-3.32583952,4.43799925, +-0.46875116,2.49567175,0.28798068,1.30016363,0.28970984,-2.38507104, +0.24665418,-5.25903797,-2.31750965,-0.23577139,4.47396946,0.28329450, +1.58814597,-1.67970324,-2.79024720,-1.62729883,3.10642624,-0.66917229, +0.65675592,-4.20011568,2.47841549,1.90257025,-0.78783196,-1.41586518, +-0.06794038,0.28623959,1.59009087,-6.98170996,0.46000746,-0.39241526, +-5.81545448,-0.54146534,-2.61389065,-3.70888448,-2.71156025,-0.85459292, +0.12608814,-3.15979242, +-1.93294251,2.73354673,-0.49725151,2.27444625,3.72778368,1.63425875, +3.01002884,-1.25163877,2.17933655,-2.32454872,1.43361092,1.83992100, +-3.75518155,3.81032205,-1.86739397,-1.46299195,-4.30204821,-2.14225531, +0.60845029,0.01267266,1.35235953,-2.03360963,3.10610461,-1.08782852, +0.19948053,2.91491699,4.31269264,0.05198213,-1.56488633,-1.41555297, +-0.09313738,0.55110073,-2.35073256,-0.79985762,-0.09840333,0.75388265, +0.71233857,-0.97185916,0.35018587,-1.84444118,0.19463573,-2.20360899, +-2.36256480,-0.17715198,-3.02556229,-2.24278378,-3.03048801,1.78598678, +-0.02577947,-0.48361790,2.76573992,0.28259668,-3.19178367,3.37067890, +1.85169363,-5.36484241,-5.22926855,-1.72746205,0.77593267,-0.60533059, +-1.12855411,1.98766887,-1.15927505,7.20731497,0.39016724,-1.40255058, +-3.95324802,1.27826059,-1.00286031,1.66211963,0.10310335,1.84502232, +0.54359400,-1.47985172,4.31608820,-0.05619702,1.72841990,6.51521921, +-1.70129752,2.24409604, +5.91284990,0.88121837,-1.96858621,-1.26149762,2.30856943,-1.29645681, +-1.07195330,1.67984724,0.13962746,1.59568501,-1.93873858,1.12268782, +-1.57682693,0.18295126,5.37425900,1.95650697,3.26101947,-3.15507460, +-4.46081638,-1.66738629,-2.29049826,3.31624699,-0.19252041,-3.83471584, +-1.06477606,1.54972005,1.27188253,4.01462269,3.56644154,1.97424769, +-4.16624880,-4.84278488,0.59882414,-0.33249485,-1.11473167,-0.64004254, +0.59620667,2.88485813,3.94058657,-1.38273096,-4.01862049,-2.84879613, +-1.14927125,-1.26633883,1.44495869,1.08074188,-1.20787299,4.34522200, +1.71746707,-1.24948418,3.04108238,1.47163892,-2.11437988,-3.81353092, +-1.89427793,-2.15320063,-2.03045893,0.40097618,-0.12276602,-0.48584884, +0.98694682,-3.34362507,-3.70514822,-1.00521743,-3.40365505,4.27700996, +-1.74038815,0.02413213,0.15047586,-2.49076056,1.51251030,-1.95061517, +-2.23469496,-0.10695624,2.14359999,4.53367281,-0.52228838,-1.35633743, +0.27997780,-0.35232139, +=== +name:CrossAttentionData_HeadSize40.bias_data +-0.38124341,0.02696526,-0.11914945,-0.43795273,-0.34948170,-0.19608477,0.19725692,0.39987487, +0.04772711,-0.03419551,-0.30606642,0.42656231,-0.23178342,-0.13692456,-0.04889601,0.48739988, +-0.25891554,0.13431972,0.22861153,0.06360734,0.48096961,-0.47906545,0.43613154,-0.23511401, +-0.10595283,-0.42839217,0.28931111,-0.13180739,-0.45826656,0.23286396,-0.43407962,0.40754890, +0.23778325,0.34850210,-0.01385659,0.32141626,-0.27738628,0.27683002,0.31886810,-0.24781504, +-0.25476855,-0.46742713,-0.12478521,0.39731556,-0.12087554,0.40822440,0.13202906,-0.23747686, +0.30502868,0.27182943,-0.03640261,-0.39626551,-0.22411832,0.17324352,-0.49959660,-0.49318257, +0.31363028,0.05469471,-0.00390345,-0.46100286,-0.27253938,0.17251462,0.46564627,0.21038425, +-0.11294025,-0.36674809,-0.15023369,-0.06280217,0.16079122,0.07736248,0.22696525,-0.17971110, +-0.10770395,-0.39882037,0.49794090,-0.14199540,-0.05613044,0.39860195,0.36553562,0.32012612, +0.27079183,0.42074734,-0.40314156,-0.43726659,0.27376485,-0.38174152,-0.43700469,0.38040614, +-0.40546918,0.06927037,0.16979086,0.41458064,0.07120579,-0.08055863,0.12095112,-0.27988660, +0.06004709,-0.05600315,-0.25510073,0.41887105,-0.19016314,0.47241372,0.12890404,-0.24272856, +0.21106839,-0.40523255,0.10336459,-0.11084765,0.42408967,-0.15285304,-0.28945464,-0.25714916, +0.40978593,-0.09138483,-0.02013114,-0.39042589,-0.19557095,0.07540411,0.33955890,0.41873980, +-0.27744853,-0.33097768,-0.44587523,-0.01648277,0.34952271,-0.48838940,-0.17273578,0.37286615, +-0.10157353,-0.08097187,0.23243034,0.25516337,-0.45793599,0.08089012,0.17673731,0.03000754, +0.48834521,0.35069120,-0.32989410,0.20729345,0.24406803,0.35393929,-0.16146761,0.04258209, +0.34165633,0.44972986,0.44825548,-0.36850777,-0.08256876,-0.00416249,0.35105377,0.29640436, +-0.46063286,0.33505446,0.30497158,-0.48780718,-0.49269417,-0.06608954,-0.22655264,-0.36424011, +-0.10567203,0.26791072,-0.08976898,0.31341976,0.06027532,0.14307594,0.31587386,0.16180152, +0.34785229,0.00531715,-0.35168743,-0.11641458,0.39196932,0.44535065,0.43545735,0.15593112, +0.06171834,-0.42181283,-0.41170910,0.40969193,-0.01510030,0.07973170,-0.18156880,0.21522856, +0.03915739,-0.20913908,-0.47068381,0.35633272,-0.35124153,0.36624825,-0.05567622,-0.35343069, +0.12821168,0.35526341,-0.23420528,-0.46328634,-0.21994811,-0.27556795,0.01653767,0.42626363, +0.23239774,0.39632857,0.32416028,-0.48494491,-0.05365932,-0.10860911,0.06893444,0.46116674, +0.34345043,-0.02719739,-0.39574289,-0.39339882,0.23044002,-0.06155324,0.23292047,0.39775699, +0.12789404,-0.44719657,0.12020230,0.26871282,-0.10917315,-0.29244915,0.09059817,-0.19613290, +-0.12975609,0.41347277,-0.31107110,0.17745221,-0.46015862,-0.26369864,-0.03715026,-0.42254731, +-0.21274829,-0.42004544,-0.22337052,-0.26180822,-0.40042144,-0.40085569,0.17293042,0.15324622, +=== +name:CrossAttentionData_HeadSize40.fp32_output_data +-1.5234375,2.4179688,0.95751953,-1.9316406,0.012382507,1.4960938,-1.9111328,2.0234375,3.0371094,-6.7265625,1.4042969,-1.4414062,0.094665527,3.6640625,2.359375,5.6601562,-5.3828125,1.2773438,-4.0664062,1.6591797,-2.2949219,4.28125,-0.15026855,0.16455078,1.4853516,0.15344238,1.1035156,1.2519531,4.1132812,-3.9667969,-0.036193848,-0.94482422,1.9208984,2.1347656,-0.088317871,-4.8007812,-0.78320312,-2.0410156,-0.82910156,-2.3085938, + +0.35595703,-2.7089844,-0.53466797,3.28125,-3.3242188,1.6640625,-2.3496094,0.5625,2.3027344,4.9140625,3.5175781,1.8925781,-3.8359375,2.1679688,-0.61572266,-1.8320312,-1.9023438,-2.3320312,-0.97753906,2.5234375,3.1386719,0.89355469,-3.5566406,-3.2089844,2.5566406,-2.7363281,-6.6796875,-2.2128906,1.4150391,4.71875,0.19372559,-1.4521484,-1.3769531,-5.546875,-0.63916016,0.27954102,0.76757812,5.7695312,3.2148438,4.1953125, + +-1.5292969,2.421875,0.95019531,-1.9267578,0.0063095093,1.4873047,-1.9121094,2.0195312,3.0214844,-6.7226562,1.4140625,-1.4384766,0.097106934,3.6445312,2.3398438,5.6484375,-5.3789062,1.2714844,-4.0507812,1.6630859,-2.2890625,4.2460938,-0.14953613,0.13464355,1.4755859,0.1361084,1.1142578,1.2587891,4.1015625,-3.9589844,-0.05657959,-0.93847656,1.9316406,2.1113281,-0.073730469,-4.7851562,-0.79003906,-2.0175781,-0.82470703,-2.3007812, + +0.36401367,-2.7167969,-0.5390625,3.2988281,-3.3320312,1.6699219,-2.3613281,0.578125,2.3046875,4.9335938,3.5253906,1.8994141,-3.84375,2.1757812,-0.61328125,-1.8505859,-1.9072266,-2.3359375,-0.98144531,2.53125,3.1367188,0.89941406,-3.5683594,-3.2128906,2.5664062,-2.75,-6.6875,-2.2246094,1.4287109,4.734375,0.1895752,-1.4511719,-1.3789062,-5.5664062,-0.64257812,0.2890625,0.77099609,5.7851562,3.2265625,4.2109375, + +1.4667969,2.453125,-2.6875,-0.88574219,0.36987305,1.1777344,-2.5839844,-0.1854248,4.84375,2.1875,1.7265625,-3.8359375,5.0273438,3.9042969,3.0253906,1.9316406,-1.6171875,3.9023438,0.80761719,-1.5703125,-3.6601562,-1.6386719,1.6201172,2.6425781,-5.5585938,4.5234375,-1.7978516,4.828125,0.61767578,0.022384644,-5.0,-3.1269531,2.5644531,2.6113281,-2.3339844,-1.4707031,0.72900391,-4.9882812,-0.98535156,-0.73828125, + +-4.8515625,-0.95214844,4.0273438,-0.79248047,-0.0083236694,1.3789062,-1.3271484,0.42480469,0.70166016,-1.2441406,2.8515625,-3.4824219,3.2890625,-1.7714844,-1.5439453,6.3203125,1.9228516,0.37231445,1.2382812,0.13647461,0.65039062,2.5429688,2.5722656,-0.81738281,-2.0058594,5.5390625,-3.3691406,0.92431641,-4.78125,-0.28393555,2.0214844,-2.0117188,-3.078125,0.46289062,0.20227051,-3.3808594,-3.0253906,0.95654297,-2.4042969,-1.2744141, + +-1.9931641,2.8261719,-0.57470703,2.5820312,3.6835938,1.78125,3.1953125,-1.0664062,2.484375,-2.265625,1.1132812,1.6455078,-3.3222656,4.1640625,-1.3837891,-1.2744141,-4.1875,-2.5488281,0.1439209,0.36401367,1.2402344,-1.9980469,2.9257812,-0.83837891,0.23828125,2.7226562,3.8300781,0.30273438,-1.8193359,-1.0390625,-0.15588379,0.17749023,-2.1347656,-0.40942383,-0.30444336,0.31567383,0.43164062,-1.1347656,0.37255859,-1.3740234, + +-2.203125,-0.0076446533,-0.62060547,-0.057525635,3.2050781,-1.9433594,-0.44921875,3.3710938,1.6572266,0.31762695,2.6894531,-2.0605469,-1.546875,-2.1328125,0.13598633,0.78466797,-1.2138672,-1.0078125,0.30273438,1.375,0.62548828,-2.5820312,-1.6708984,-0.041412354,-3.34375,1.7207031,-6.5234375,0.10406494,-0.58398438,-0.98925781,0.72460938,-2.1347656,-1.4980469,-2.0566406,-0.33691406,3.9980469,-1.7851562,0.94042969,-2.71875,0.61865234, + +-2.0097656,2.9941406,-0.59277344,2.5761719,3.7832031,1.765625,3.3105469,-1.078125,2.5195312,-2.3027344,1.0693359,1.7207031,-3.3554688,4.2421875,-1.4033203,-1.2939453,-4.2109375,-2.5683594,0.17724609,0.41601562,1.3242188,-1.9326172,2.9121094,-0.88330078,0.23376465,2.6992188,3.8300781,0.42358398,-1.8964844,-1.0371094,-0.16442871,0.17700195,-2.2109375,-0.44287109,-0.33642578,0.28515625,0.49194336,-1.2324219,0.38061523,-1.4160156, + +-1.8134766,3.0039062,-0.13049316,1.6318359,4.8515625,-3.109375,0.62841797,1.4433594,1.3876953,0.27685547,1.5771484,-4.1679688,0.31225586,-1.4082031,1.3603516,3.0195312,-0.39648438,-1.6777344,1.0498047,2.3378906,0.76806641,-3.0585938,0.45361328,-0.12194824,-3.3125,-0.37817383,-8.5234375,-0.11810303,-0.23144531,-1.625,0.27539062,-2.3085938,-2.1933594,-2.8554688,-3.1679688,2.8027344,-3.1972656,1.3349609,-4.3632812,0.044036865, + +0.099182129,0.14648438,-0.45410156,1.3339844,-1.1308594,2.3261719,0.48266602,-0.72314453,-1.1728516,0.81396484,3.3339844,1.7109375,1.4560547,4.6484375,-1.4179688,-0.609375,-1.1708984,-1.0449219,2.6015625,0.47900391,2.984375,-0.81787109,3.9121094,-0.079284668,-0.32202148,2.7636719,3.0507812,-2.6972656,-0.52197266,-0.22521973,2.1601562,1.5136719,-3.2558594,-3.2714844,-2.2207031,2.7304688,-2.078125,-0.89990234,-2.3847656,0.04486084, + +1.2392578,2.2792969,0.33398438,2.2519531,0.67236328,-0.56103516,0.20678711,1.359375,-1.9707031,2.6074219,2.2851562,-2.0566406,-2.4335938,0.53466797,-0.15075684,1.9609375,-0.51464844,0.30981445,-0.49145508,1.46875,2.234375,0.87353516,0.546875,-1.8681641,-4.2265625,-0.97509766,-7.296875,-1.3476562,1.3769531,-1.8427734,3.1601562,-2.4238281,-0.82421875,-2.734375,-0.52783203,2.2089844,0.66699219,-0.421875,-3.0332031,-0.047058105, + +=== +name:CrossAttentionData_HeadSize40.fp16_output_data +-1.5244141,2.4199219,0.95751953,-1.9316406,0.012390137,1.4970703,-1.9111328,2.0234375,3.0371094,-6.7265625,1.4042969,-1.4414062,0.094665527,3.6640625,2.3613281,5.6601562,-5.3828125,1.2783203,-4.0664062,1.6591797,-2.2949219,4.28125,-0.15026855,0.16455078,1.4853516,0.15344238,1.1035156,1.2519531,4.1132812,-3.9667969,-0.036193848,-0.94482422,1.9208984,2.1347656,-0.088317871,-4.8007812,-0.78369141,-2.0410156,-0.82910156,-2.3085938, + +0.35595703,-2.7089844,-0.53417969,3.28125,-3.3242188,1.6640625,-2.3496094,0.5625,2.3027344,4.9140625,3.5175781,1.8925781,-3.8359375,2.1679688,-0.61572266,-1.8320312,-1.9023438,-2.3320312,-0.97753906,2.5234375,3.1386719,0.89355469,-3.5566406,-3.2089844,2.5566406,-2.7363281,-6.6796875,-2.2128906,1.4150391,4.71875,0.19372559,-1.4521484,-1.3769531,-5.546875,-0.63916016,0.27954102,0.76757812,5.7695312,3.2148438,4.1953125, + +-1.5283203,2.421875,0.94970703,-1.9267578,0.006313324,1.4873047,-1.9121094,2.0175781,3.0214844,-6.7226562,1.4140625,-1.4384766,0.097045898,3.6445312,2.3398438,5.6484375,-5.3789062,1.2705078,-4.0507812,1.6630859,-2.2890625,4.2460938,-0.14941406,0.13464355,1.4755859,0.1361084,1.1142578,1.2578125,4.1015625,-3.9570312,-0.056549072,-0.93798828,1.9316406,2.1113281,-0.073730469,-4.7851562,-0.79003906,-2.015625,-0.82421875,-2.3007812, + +0.36401367,-2.7167969,-0.5390625,3.2988281,-3.3300781,1.6699219,-2.3613281,0.578125,2.3046875,4.9296875,3.5253906,1.8994141,-3.84375,2.1757812,-0.61328125,-1.8505859,-1.9072266,-2.3359375,-0.98095703,2.53125,3.1347656,0.89892578,-3.5664062,-3.2128906,2.5664062,-2.75,-6.6875,-2.2246094,1.4287109,4.7304688,0.1895752,-1.4511719,-1.3789062,-5.5625,-0.64257812,0.2890625,0.77050781,5.78125,3.2246094,4.2109375, + +1.4667969,2.453125,-2.6875,-0.88574219,0.36987305,1.1767578,-2.5839844,-0.1854248,4.84375,2.1875,1.7265625,-3.8359375,5.0273438,3.9042969,3.0253906,1.9316406,-1.6171875,3.9023438,0.80712891,-1.5703125,-3.6582031,-1.6386719,1.6191406,2.6425781,-5.5585938,4.5234375,-1.7978516,4.8242188,0.61767578,0.022384644,-5.0,-3.1269531,2.5644531,2.6113281,-2.3339844,-1.4707031,0.72900391,-4.9882812,-0.98535156,-0.73828125, + +-4.8515625,-0.95214844,4.0273438,-0.79248047,-0.0082321167,1.3789062,-1.3271484,0.42504883,0.70166016,-1.2441406,2.8515625,-3.4824219,3.2890625,-1.7714844,-1.5449219,6.3203125,1.9228516,0.37255859,1.2382812,0.13635254,0.65039062,2.5429688,2.5722656,-0.81787109,-2.0058594,5.5429688,-3.3691406,0.92480469,-4.78125,-0.28393555,2.0214844,-2.0117188,-3.078125,0.46289062,0.20227051,-3.3828125,-3.0273438,0.95654297,-2.40625,-1.2744141, + +-1.9931641,2.8261719,-0.57470703,2.5820312,3.6816406,1.78125,3.1953125,-1.0664062,2.484375,-2.265625,1.1123047,1.6445312,-3.3222656,4.1601562,-1.3828125,-1.2744141,-4.1875,-2.5488281,0.1439209,0.36401367,1.2402344,-1.9980469,2.9238281,-0.83837891,0.23828125,2.7226562,3.8300781,0.30273438,-1.8193359,-1.0390625,-0.15588379,0.17749023,-2.1328125,-0.40917969,-0.30444336,0.31567383,0.43164062,-1.1347656,0.37231445,-1.3730469, + +-2.203125,-0.0080795288,-0.62060547,-0.057769775,3.2050781,-1.9423828,-0.44946289,3.3710938,1.6572266,0.31713867,2.6894531,-2.0605469,-1.546875,-2.1328125,0.13586426,0.78369141,-1.2148438,-1.0078125,0.30273438,1.375,0.62548828,-2.5820312,-1.6708984,-0.040985107,-3.34375,1.7207031,-6.5195312,0.10418701,-0.58398438,-0.98925781,0.72460938,-2.1347656,-1.4980469,-2.0566406,-0.33642578,3.9960938,-1.7841797,0.94042969,-2.71875,0.61865234, + +-2.0078125,2.9941406,-0.59277344,2.5761719,3.7832031,1.765625,3.3105469,-1.078125,2.5195312,-2.3027344,1.0693359,1.7207031,-3.3554688,4.2421875,-1.4033203,-1.2929688,-4.2070312,-2.5683594,0.17724609,0.41577148,1.3242188,-1.9326172,2.9101562,-0.88330078,0.23376465,2.6992188,3.8300781,0.42358398,-1.8964844,-1.0371094,-0.16442871,0.17700195,-2.2109375,-0.44287109,-0.33642578,0.28515625,0.49194336,-1.2324219,0.38037109,-1.4160156, + +-1.8134766,3.0058594,-0.13061523,1.6318359,4.8476562,-3.1074219,0.62841797,1.4414062,1.3876953,0.27319336,1.5742188,-4.1679688,0.31518555,-1.4072266,1.3613281,3.0175781,-0.39794922,-1.6777344,1.0517578,2.3359375,0.76806641,-3.0585938,0.45483398,-0.12078857,-3.3105469,-0.37841797,-8.515625,-0.11773682,-0.23059082,-1.6289062,0.27539062,-2.3066406,-2.1972656,-2.8554688,-3.1679688,2.7988281,-3.1972656,1.3339844,-4.359375,0.042053223, + +0.097961426,0.14807129,-0.45410156,1.3339844,-1.1279297,2.3261719,0.484375,-0.72314453,-1.1708984,0.81201172,3.3320312,1.7109375,1.453125,4.6484375,-1.4169922,-0.609375,-1.1728516,-1.0458984,2.5996094,0.47900391,2.984375,-0.81835938,3.9121094,-0.079711914,-0.32177734,2.7636719,3.0507812,-2.6953125,-0.52294922,-0.22570801,2.1582031,1.5126953,-3.2558594,-3.2695312,-2.21875,2.7285156,-2.0761719,-0.89990234,-2.3828125,0.044006348, + +1.2402344,2.2792969,0.33398438,2.2519531,0.67041016,-0.55957031,0.20666504,1.3583984,-1.9716797,2.6074219,2.2832031,-2.0546875,-2.4335938,0.53515625,-0.15100098,1.9599609,-0.51513672,0.31030273,-0.49169922,1.4677734,2.234375,0.87451172,0.54736328,-1.8681641,-4.2265625,-0.97509766,-7.296875,-1.3486328,1.3769531,-1.8427734,3.1601562,-2.4238281,-0.82421875,-2.7324219,-0.52734375,2.2089844,0.66796875,-0.42236328,-3.03125,-0.047302246, + + +=== +name:CrossAttentionData_HeadSize40_NoBias.fp32_output_data +-1.41742659,2.15152407,1.04562795,-2.24374223,-0.04717414,1.35415494,-2.22757769,1.86239254,2.69114566,-6.72842312,1.75712097,-1.32716835,-0.29526311,3.21845007,1.92469037,5.50302410,-5.44591045,1.70150733,-3.65152955,1.24731004,-2.27949309,4.20098972,0.03186192,-0.04943787,1.44350362,0.36441594,1.57309783,0.89751047,4.46334076,-4.33237123,0.01717144,-0.59184837,1.79316127,1.77931416,0.14474387,-4.33217955,-0.56225604,-1.76532054,-0.84570312,-2.73260164, + +0.12478950,-3.10866117,-0.85841137,3.77194262,-3.27266002,1.77506232,-2.42189217,0.10825679,1.95918787,4.94663668,3.91713643,2.28616691,-4.06595850,2.23235726,-0.84805435,-2.23345041,-2.03120971,-1.88641536,-1.09826195,2.25707841,3.24559855,1.18912041,-3.64727020,-3.01371503,2.68850493,-3.15157413,-6.36788988,-2.39488506,1.87837374,4.98469496,0.22985148,-1.02970588,-1.16538036,-5.13183355,-0.41686863,0.54360533,1.16716135,6.17682886,3.04362583,4.04813623, + +-1.42417967,2.15435815,1.03971374,-2.24015427,-0.05345200,1.34537208,-2.22884774,1.85825360,2.67446709,-6.72772360,1.76715374,-1.32337081,-0.29505086,3.19914651,1.90399659,5.49347830,-5.44424438,1.69376886,-3.63920736,1.25351167,-2.27403808,4.17100430,0.03175361,-0.08079768,1.43696070,0.34488928,1.58517742,0.90214115,4.45445490,-4.32695866,-0.00118921,-0.58452755,1.80395257,1.75610685,0.16048698,-4.32064056,-0.56982690,-1.73989952,-0.84093040,-2.72663569, + +0.13186364,-3.11423659,-0.86316907,3.78399539,-3.27828074,1.77901089,-2.42992020,0.11804537,1.96141636,4.95947886,3.92235184,2.29242468,-4.07375813,2.23869610,-0.84603471,-2.24866748,-2.03565598,-1.88956857,-1.10135245,2.26302266,3.24525905,1.19217336,-3.65679145,-3.01720095,2.69548559,-3.16282535,-6.37307644,-2.40397477,1.88918531,4.99577379,0.22660360,-1.02878523,-1.16615939,-5.14430475,-0.41941044,0.55101258,1.17067981,6.18814802,3.05311632,4.05843735, + +1.58491349,2.18418908,-2.61316419,-1.19461167,0.31131122,1.03194487,-2.90404654,-0.35682300,4.50262070,2.21961379,2.08062601,-3.72921634,4.65971994,3.46044660,2.59209037,1.75916731,-1.66252756,4.33679771,1.23986435,-1.99405932,-3.64911294,-1.74503422,1.80885434,2.43805814,-5.62830687,4.75278616,-1.34041858,4.48804235,0.95380831,-0.32654628,-4.96857643,-2.78253746,2.43861747,2.25903702,-2.10894275,-0.99328351,0.95549250,-4.72304869,-1.00289059,-1.15769684, + +-5.10913038,-1.38361323,3.78980398,-0.27995712,0.07776496,1.53318942,-1.45798743,0.06345022,0.32985163,-1.20825279,3.32992506,-3.16107416,3.14213490,-1.75764465,-1.81823230,6.00926352,1.83184552,0.88772279,1.13544476,-0.16091508,0.73152179,2.89268398,2.53888154,-0.62667179,-1.92644227,5.24402714,-3.04914069,0.73081797,-4.36438751,-0.01024710,2.05606008,-1.59136617,-2.93256354,0.90090895,0.44130960,-3.17225385,-2.68491602,1.39586127,-2.62767482,-1.42729461, + +-1.82169747,2.12078428,-0.43695056,2.27537584,3.42691755,1.65860319,2.57705307,-1.17967665,2.09597683,-2.18013787,1.50621653,1.55477905,-3.70713329,3.45152068,-1.70394862,-1.33734357,-4.18969202,-2.11793780,0.37242663,-0.20806181,0.96408093,-2.22627115,3.10095739,-0.97176194,0.22555678,2.99631286,4.30567598,-0.29444879,-1.22917330,-1.39327240,-0.15407819,0.46064961,-2.00380874,-0.62698770,0.04687182,0.81974965,0.54190254,-0.56075597,0.43117812,-1.70553112, + +-1.88462663,-0.18665671,-1.06960690,0.64497805,2.83166552,-2.34236050,-0.68599927,2.52589321,1.09144545,0.48552963,3.03313494,-1.95211184,-1.85385156,-1.15996051,0.42496145,0.14187109,-1.67549849,-0.85382032,0.31291258,1.16500401,0.48290920,-1.64285612,-1.35711002,1.14920509,-2.76547956,0.50387645,-6.65734005,0.06499285,-0.26013616,-0.19627771,0.56354129,-1.26614785,-0.94395208,-1.86354482,0.00720191,3.69053054,-1.17969584,2.35666990,-3.26046968,0.78327948, + +-1.86769938,2.71813035,-0.50948530,2.24504375,3.71597552,1.60988891,2.97607589,-1.22726071,2.16237378,-2.29194784,1.40557051,1.83395016,-3.73706627,3.78015113,-1.80717337,-1.43455577,-4.23915625,-2.15067673,0.56629229,-0.00130248,1.32205904,-1.98912859,3.07867503,-1.11066699,0.18896791,2.90356636,4.28740644,0.08492497,-1.52221036,-1.38736534,-0.12700811,0.50624669,-2.32619810,-0.79596692,-0.10685119,0.74229264,0.71136874,-0.93978000,0.38004258,-1.84059870, + +-2.26918745,2.92838788,-0.45714897,2.18296647,4.10041952,-2.25037718,0.51260191,0.39325786,0.90468413,-0.66815877,1.22376275,-3.15594530,0.84955496,-1.06137490,1.20908797,1.87171698,-0.91993034,-1.29943442,1.31052589,1.59136820,0.83899784,-3.01598954,0.73303372,0.39389658,-2.76502943,-0.90127987,-6.78780794,-0.19403477,0.46670800,-2.34413576,0.33809948,-1.62583923,-2.65135598,-2.10512233,-2.88674784,1.88245845,-2.78318572,1.28361940,-3.72045994,-0.64210486, + +-0.40192991,0.42336106,-0.37019759,1.41447365,0.19176102,2.02308369,0.81132519,-0.95749462,-0.39838922,-0.09587491,3.00953579,1.66607380,-0.43405950,3.86591244,-1.75709438,-0.90621388,-2.13548446,-1.09224761,2.10858512,-0.07912997,2.24841881,-1.36435628,3.77529001,-0.48102456,-0.16689897,3.00326085,3.76847577,-2.26835036,-0.41139305,-0.83580929,1.44518113,1.39267445,-2.85280180,-2.63157845,-1.30405295,2.46063781,-1.14184821,-0.49150658,-1.47628820,-0.76379204, + +1.59237325,1.84326255,0.11042996,2.89765906,-0.49430391,0.39030308,0.02746993,0.65821123,-3.10381436,2.78205943,2.55404949,-0.96529919,-2.98005986,1.13010681,-0.68560266,1.04888844,-0.81784761,1.16720343,-0.80749500,0.82892329,2.64979362,1.93710601,0.61530274,-1.93501818,-4.14114285,-1.56158972,-6.18459988,-1.75687492,2.28010345,-1.99459755,3.83940291,-1.92955184,-0.56180751,-2.16278362,0.29707330,1.89639890,1.92093897,-0.57678437,-2.60749125,-0.42066064, +=== +name:CrossAttentionData_Batch2_HeadSize32_RightSidePadding.query_data +0.66417468,-2.82039404,1.66603971,4.84341049,-1.63285708,3.61133432, +-1.07151258,-0.41698062,-1.38491797,-3.79137778,1.34514475,-2.97253704, +2.12579250,-0.02954102,2.30081463,0.21410012,1.84038579,0.46486610, +-4.49463224,0.69027799,1.01090157,0.04715919,-1.60957003,0.10730582, +-5.77672052,0.37593889,2.04825425,-1.00890708,-3.88195300,-2.69047785, +1.15699422,-1.13536406,-0.42816854,3.12039518,3.21898699,-0.51998949, +-4.72336435,-0.78055519,-0.72722042,3.17147565,-1.31066322,-3.09425855, +-3.54743338,-0.07284085,1.10525322,1.82087338,-2.03681397,-4.27978802, +0.26408362,0.58637118,-2.07128787,-3.48036027,-0.03049034,-1.99293542, +-0.67289937,1.17342246,-4.84998703,-2.43558168,1.16422236,0.26511097, +-1.98199308,-1.86423326,1.61366916,-0.35201707, +-1.43554640,-1.37493825,2.32563400,-1.31762123,-1.46716797,0.18536982, +0.85819042,-3.11506653,-1.25773919,1.30177450,0.58314162,-1.72039497, +-4.55264997,0.02031951,-2.83490133,2.69835496,-0.07102034,-2.05412841, +-1.26518285,3.30601740,-4.54173231,0.80148667,-1.36685658,-2.26921320, +-0.94192690,-2.77439642,0.43918809,1.44727242,1.53386545,2.67014980, +3.30231142,-1.60745978,-1.26032567,1.27801156,0.31288767,3.04471421, +-1.09798527,-2.76303077,-1.68329728,-4.78179169,-0.86371553,-1.57159030, +-1.06435764,3.61700702,0.71459293,-0.25048330,1.31865597,-1.83117080, +-1.10344386,2.94894052,-1.33930528,1.94855583,-1.94283628,-0.64020038, +2.24100995,1.06447530,-0.03809617,3.47241497,-2.55227089,0.12048072, +2.88777542,-1.73300576,3.10077643,-0.37158102, + +-0.76705527,-1.27237630,3.55744553,0.84103155,-2.37726879,0.20218298, +-3.41723180,1.26160014,1.45791709,-1.47226799,-2.36974764,1.49916458, +1.68845606,-1.33727181,-2.18113089,-0.64312577,-1.06002951,-0.98938328, +1.95285964,3.08321524,1.28492856,2.28907299,1.14324796,-0.11273877, +-5.96574259,-1.80337310,3.86340094,-2.42390299,-1.29642844,0.14276078, +-1.23373103,-0.51519167,-1.04046988,0.60624832,-0.93274558,2.46919179, +-0.58201206,-3.43382907,1.63227773,1.92112875,-0.17216301,2.79771209, +2.67759442,1.73900354,-0.00557053,-0.63086307,-0.37115061,0.82691956, +1.81370568,-0.48766607,-1.05545425,-2.79009533,-7.64374399,-2.65407372, +-0.84429693,1.35677493,-1.25277543,2.26928639,-1.77852845,2.31752825, +-1.28869593,-2.97340727,-2.87103486,2.17401385, +0.20970306,-1.19119942,1.11263359,0.21227169,-5.30872822,-2.15851903, +0.63067430,-0.49583313,3.05784941,0.09588236,0.76925617,1.18900692, +0.35771871,-0.97235727,1.14949071,-1.25595427,2.37192512,-0.32522821, +1.42988098,-0.38017935,2.49831486,-0.30629224,1.08675146,-1.02598715, +-0.17971759,-0.55683851,1.04535389,1.54741859,-0.05179391,0.73957652, +0.54304504,1.95280874,-1.19504929,-1.19528544,1.33258319,0.13532166, +-1.87509251,0.99605685,2.69439840,1.03421521,1.79539657,0.15001571, +0.55184591,-0.84038037,-2.08177447,-1.43082356,-1.52199960,1.69448102, +2.12475252,-2.64191580,0.10776700,-4.01538181,1.15558016,-0.09849232, +0.33533198,3.34633803,-2.89805937,-2.51580763,0.94939411,1.36254668, +0.47172806,4.40817642,-0.11368597,-2.70789719, +=== +name:CrossAttentionData_Batch2_HeadSize32_RightSidePadding.key_data +1.18319833,-0.20700163,-0.64873743,3.88316822,-2.82827115,4.12166834,0.84225285,-1.11044288, +-1.75086212,-1.66724730,2.22730064,-3.22617316,-0.14071584,0.58066225,3.04375815,-1.43881261, +-2.39294887,1.03637624,-0.98744214,1.13576865,-0.23876363,0.27395499,-0.51450062,-2.23614597, +-2.12345290,-0.68864471,2.56223369,-1.14069867,-2.14457107,-1.32647824,-1.20575166,-0.98427975, +0.43083039,-1.72496212,0.89925444,-0.33879194,-1.01836991,0.06260723,-4.40405083,1.51136112, +-1.57057071,-2.49242449,-0.37187487,-3.55319405,1.50083232,0.37271553,1.00157571,-0.50416815, +1.28753221,-0.82453167,-1.13294256,-1.49514699,0.11243388,1.89696264,-1.46173263,3.32755566, +-0.54521537,-2.61305809,-0.43132567,-0.33066380,-0.47485363,3.62707257,-0.61352783,2.21147466, +-2.39673638,0.89925957,-2.58643913,-0.81968069,3.34945726,0.73745269,-1.62732553,-4.55126476, +2.78017616,0.33757699,2.50468874,-4.14928627,0.20017165,3.62233806,-4.17984772,2.60447359, +2.16826940,1.70457518,1.03199887,2.66712570,0.50808340,-3.47132921,-2.60008478,1.03852415, +-0.53876096,3.36212158,-5.49142551,1.69825470,-2.98179603,-3.39561105,-2.33971524,1.23642313, +2.13283253,-0.56307364,-2.49120903,2.97641850,-1.28758216,3.43342829,2.49575281,0.09292871, +-0.46469527,-3.95696974,2.16474032,-2.15254521,-2.24547267,2.34235692,-1.02470589,3.97816467, +3.60425544,1.87994969,-2.46964216,1.47802746,-1.81441534,-1.56946301,0.56189334,-1.69905055, +-1.83049631,4.64296293,3.36173010,1.17065477,0.62365234,1.23748016,0.63865232,-2.90434527, +1.80253839,3.11227179,-3.96782875,-2.78780794,3.76587057,-1.66908360,1.83301187,-1.74414611, +-2.83874130,-2.00238085,-6.45539570,0.56152177,2.52830791,-4.32480669,1.40038610,0.83278954, +0.16065764,-0.13457650,2.17216778,-4.28218699,0.75475001,-0.67497885,-0.95346600,3.29623652, +1.84325528,1.18348145,-0.23741919,2.49520302,0.88820332,1.15528166,0.75733638,2.09371948, +-1.16427231,1.36415648,-1.17721760,0.19180456,-3.83617687,-0.22694540,5.14728260,-0.43242604, +-2.59039426,-1.40904129,0.58194822,-2.59625196,-3.60205126,1.45633197,3.66319609,-4.45727873, +3.95457315,-0.17875004,2.43404126,2.83592010,0.87342203,1.24538708,3.10003138,2.63025975, +4.57258415,-5.20645714,-2.55821514,0.60136455,-4.13579988,-2.04082966,2.21142578,-1.05740535, + +1.78609943,-3.10438013,-0.13040465,-3.02957106,0.91924584,0.45405358,-1.90627027,-1.05065346, +-1.21743047,-1.65989709,-0.51138550,2.04327297,0.65217698,0.77914226,1.86315429,0.75791669, +-0.55304748,-1.23857486,2.63207936,-0.51371288,5.48993397,-2.35509205,-2.30255723,3.88706803, +-1.93575382,0.03364474,-1.61156952,-2.74172544,1.64667726,0.04652762,2.88130736,-2.00066185, +0.74907655,-3.35894132,-1.85703170,1.78695405,0.16497552,0.94382036,3.04452896,-4.42404556, +-1.67239439,0.93356639,0.08288032,-0.11422639,-3.94759631,0.35302341,-1.20778334,-1.92491865, +-1.86599326,-1.29324412,-1.12795746,0.24268979,-0.50242394,2.26449108,0.91289425,-2.48235416, +-1.12685704,-0.32806787,3.28139257,3.19231367,0.99441254,-1.86975384,-3.57600951,0.07424650, +-0.45312887,5.02197504,-3.93365264,-3.30742884,-1.48101401,1.03335130,2.79531693,-3.71739435, +1.58574414,-4.52857542,1.99908066,1.53755212,1.60631371,-2.46801257,-1.85840714,5.07508087, +1.69143867,-1.04688716,-3.17096090,-4.08357859,-0.02436948,-1.26299214,1.55509603,3.11954260, +3.55844116,0.10080734,-0.57031679,2.01342750,-0.66671205,-1.89724469,2.52388906,3.71421099, +0.77953398,-1.63364959,-1.90900147,-3.60591793,1.17604601,-1.69456589,-1.62096381,-1.44886708, +-1.09821022,-1.27646899,2.73696446,-2.21802664,-0.22022307,1.76918471,-1.55524099,0.27310926, +-0.56175643,-0.59620953,2.34752941,-0.74946308,-2.33520174,1.37984359,-1.82466078,-0.04973821, +-4.77387571,-0.85034770,3.39579129,-2.82413197,-2.37980723,0.10482252,0.10614476,0.38176090, +-0.03948998,-3.33898020,0.33013302,-0.24926627,1.82249093,0.57584983,-0.68790460,-0.62760007, +0.17052543,-0.54540014,1.66043472,-0.29917845,3.31803465,0.86704284,-0.26854402,2.23795938, +-0.65058500,-2.01540327,-2.32472515,-2.85143948,-3.76564598,-0.25596800,-2.08064461,-0.60812098, +3.64154029,-2.58636141,-0.25312662,-2.22530699,-1.24763203,-3.08458424,0.69228125,-1.84211481, +1.09744453,-1.35679579,1.68044925,0.89537722,3.56465936,-0.64790231,-1.42140329,-2.85126376, +0.88302374,-0.77923191,-0.61865216,-3.08081675,0.87791818,-0.27943787,0.46918952,1.50163293, +3.43236423,1.99953759,-2.42805409,4.97383118,-2.13942194,1.45409000,-1.14207470,0.63804722, +-4.23801470,1.23076391,2.71176004,1.13607812,2.27742863,1.64165723,1.20048785,-0.66269439, + +=== +name:CrossAttentionData_Batch2_HeadSize32_RightSidePadding.value_data +2.52855659,1.00436294,0.83871710,0.97005701,1.33615291,-2.07353282,0.14190522,-1.42923164, +-0.05781263,-3.81081843,1.15263164,0.62601233,-0.93824124,1.21525323,-0.17992918,2.08717370, +3.61659431,-0.16836943,2.17779160,-0.63968349,0.32170480,1.74428463,-0.46570981,-0.07432288, +-0.21569058,0.65559602,3.58669281,0.40837619,2.40912223,1.31780922,-4.45945454,0.64903581, +-1.10752177,-1.79390311,0.89312351,-1.84512544,-1.13948750,3.87221098,-2.74163318,2.90849519, +-0.31782085,3.12108278,0.80056298,1.02164125,-0.07995117,-0.96148860,3.49803638,-4.48321056, +-1.50024915,-2.58987570,0.61711067,4.13532829,-4.38111591,-2.48988461,-0.43977243,-3.93134618, +-2.67314148,2.64455128,0.11041284,1.26786041,-0.24446392,-0.86178148,2.35680771,-1.69236851, +-1.22143269,1.99185669,2.99625540,-2.32311869,-2.26162481,3.13980794,0.37014920,3.22335911, +2.55935216,2.19479871,4.89236355,1.76135564,-2.74285603,1.39842391,-0.25135490,-4.76257038, +-0.80362052,-1.75548995,-4.70487833,1.72763062,3.14491320,3.97562551,-0.64091396,-0.49683607, +1.09094775,-0.04886785,-0.20181555,2.22182846,3.00734067,-0.52149582,-1.55592132,4.41542721, +4.68795204,-1.03364658,1.12266266,-1.50595415,-4.82583904,-0.65535200,-1.44525290,-0.24540535, +-0.44778955,2.32284093,1.60033488,0.12583408,-4.42107201,-1.32412672,-1.84733653,-1.53440499, +3.21279287,-0.37051341,0.26685789,2.25037003,0.01608747,1.66141725,-0.53394145,1.35017800, +1.35997009,-2.73341703,5.47488451,5.49519920,-1.90401053,3.37626982,-1.97467375,1.91208827, +-0.39609963,-3.46037388,-1.47946858,3.59935665,2.36377144,-2.32310963,1.95714176,-3.10615826, +-1.72878003,0.37169266,-5.95610952,-1.32819366,-1.24326205,0.17746472,2.59834385,1.83808351, +2.94952321,3.01939392,1.37281823,2.67180538,-0.32547897,1.11373281,-0.26456773,0.30103314, +-1.05465972,-1.74858260,4.66243505,-0.58474910,1.26216507,1.28856802,0.30135399,-3.24127388, +1.57217860,-3.84659171,1.52000761,-0.57999939,7.80852032,2.83661318,-1.72516418,0.70036685, +5.33224869,3.27205563,0.22613347,1.27628899,0.63828707,0.60137266,2.23047280,-3.12771320, +-0.03023779,0.80765182,-2.25078392,-2.55701947,-1.01789987,-4.81986141,5.08153057,-1.74439597, +-2.12658811,-0.01458025,-2.19556737,0.66254830,-0.97602153,-0.09858370,-2.05090475,-3.57909155, + +4.57896709,-1.96923888,-3.86827421,3.18770289,-5.16361237,1.42594528,-1.43490076,1.62748218, +0.91413617,-0.27147734,0.89311242,0.39315015,1.18184900,4.30172014,-2.32771754,1.61144018, +1.31702828,1.47999883,-0.20565452,0.75846130,-0.13237280,-2.10059071,0.12025893,-0.58277643, +1.93927395,-3.11170292,0.84666562,0.08490577,-0.36315954,-3.13071823,0.12070303,-0.10385191, +-2.37523723,2.28944397,0.12518460,-1.10043252,-1.94665289,3.44240570,1.14374518,3.27769613, +1.40222466,0.68902296,2.48193359,1.85469973,0.53099388,-2.16307211,0.67865700,-0.05084896, +0.09825261,1.40057099,-0.74452353,0.81515837,1.51540780,-1.30754757,-1.50317430,-2.04524612, +-0.49154273,0.75809133,-0.25134420,0.36961895,-0.01882899,-1.72547066,1.12012851,-6.72828960, +1.76177442,1.19128907,-0.77717477,-1.97159290,-2.30860472,2.01583147,5.43375349,2.58655977, +0.71099019,0.71843386,3.10709906,1.48128355,0.22561067,-4.27442265,-2.49249840,4.71605539, +2.19818974,-1.96133125,0.41619009,0.66834581,-3.74457240,-0.48215276,-1.28305256,-1.83142948, +-0.72452945,-1.97440028,-0.14068973,0.11765432,0.49793118,0.40227121,-1.34390569,0.92099732, +-1.21718168,-1.95382285,1.37468243,-0.72062874,2.66714525,1.06695974,-2.86761045,1.34743905, +3.30500460,-0.91894615,-0.09608981,-4.09408808,-2.57941151,-0.36501098,1.93333972,1.54577386, +-2.96415496,-2.09494066,1.63500857,-1.51829720,-0.98314112,-1.89401948,-0.54314089,-3.68928242, +1.07439506,1.70869648,0.86973846,1.71959770,1.78241849,-4.29455566,-1.55857742,-3.32966399, +0.20903873,1.40176547,-6.08825064,2.12755013,3.84799123,-0.83979988,-1.64312506,-0.69876713, +4.00779629,-2.85212469,0.09145057,1.72984874,-0.77233994,1.21815240,-1.75377214,4.08561277, +-1.20909250,-1.24881196,4.37579060,4.27434301,-2.01065826,2.96602201,3.07406378,1.22374272, +0.06376281,-1.60328245,-1.32239270,1.00765312,1.27593243,-2.14843464,-3.47884607,-0.32401958, +-2.52805567,-1.01782882,0.74270618,1.47170806,-2.56010485,-1.49985540,0.92767721,3.42378139, +5.23711205,0.47062784,-0.26747131,-2.06014609,-0.20237172,-1.60944867,-2.51956654,0.59529293, +2.63805699,0.43868792,-5.84081888,3.25271368,-4.44406748,-3.80642724,-1.59846020,-2.59634686, +0.11074528,2.04441738,-1.51878321,-2.59639883,2.23697233,0.07920718,1.31056094,-8.10540771, +=== +name:CrossAttentionData_Batch2_HeadSize32_RightSidePadding.bias_data +-0.38124341,0.02696526,-0.11914945,-0.43795273,-0.34948170,-0.19608477,0.19725692,0.39987487, +0.04772711,-0.03419551,-0.30606642,0.42656231,-0.23178342,-0.13692456,-0.04889601,0.48739988, +-0.25891554,0.13431972,0.22861153,0.06360734,0.48096961,-0.47906545,0.43613154,-0.23511401, +-0.10595283,-0.42839217,0.28931111,-0.13180739,-0.45826656,0.23286396,-0.43407962,0.40754890, +0.23778325,0.34850210,-0.01385659,0.32141626,-0.27738628,0.27683002,0.31886810,-0.24781504, +-0.25476855,-0.46742713,-0.12478521,0.39731556,-0.12087554,0.40822440,0.13202906,-0.23747686, +0.30502868,0.27182943,-0.03640261,-0.39626551,-0.22411832,0.17324352,-0.49959660,-0.49318257, +0.31363028,0.05469471,-0.00390345,-0.46100286,-0.27253938,0.17251462,0.46564627,0.21038425, +0.27079183,0.42074734,-0.40314156,-0.43726659,0.27376485,-0.38174152,-0.43700469,0.38040614, +-0.40546918,0.06927037,0.16979086,0.41458064,0.07120579,-0.08055863,0.12095112,-0.27988660, +0.06004709,-0.05600315,-0.25510073,0.41887105,-0.19016314,0.47241372,0.12890404,-0.24272856, +0.21106839,-0.40523255,0.10336459,-0.11084765,0.42408967,-0.15285304,-0.28945464,-0.25714916, +0.40978593,-0.09138483,-0.02013114,-0.39042589,-0.19557095,0.07540411,0.33955890,0.41873980, +-0.27744853,-0.33097768,-0.44587523,-0.01648277,0.34952271,-0.48838940,-0.17273578,0.37286615, +-0.10157353,-0.08097187,0.23243034,0.25516337,-0.45793599,0.08089012,0.17673731,0.03000754, +0.48834521,0.35069120,-0.32989410,0.20729345,0.24406803,0.35393929,-0.16146761,0.04258209, +-0.10567203,0.26791072,-0.08976898,0.31341976,0.06027532,0.14307594,0.31587386,0.16180152, +0.34785229,0.00531715,-0.35168743,-0.11641458,0.39196932,0.44535065,0.43545735,0.15593112, +0.06171834,-0.42181283,-0.41170910,0.40969193,-0.01510030,0.07973170,-0.18156880,0.21522856, +0.03915739,-0.20913908,-0.47068381,0.35633272,-0.35124153,0.36624825,-0.05567622,-0.35343069, +0.12821168,0.35526341,-0.23420528,-0.46328634,-0.21994811,-0.27556795,0.01653767,0.42626363, +0.23239774,0.39632857,0.32416028,-0.48494491,-0.05365932,-0.10860911,0.06893444,0.46116674, +0.34345043,-0.02719739,-0.39574289,-0.39339882,0.23044002,-0.06155324,0.23292047,0.39775699, +0.12789404,-0.44719657,0.12020230,0.26871282,-0.10917315,-0.29244915,0.09059817,-0.19613290, +=== +name:CrossAttentionData_Batch2_HeadSize32_RightSidePadding.fp32_output_data +2.42288446,1.27227366,0.74894810,1.28347683,1.39642823,-1.93045688,0.45777908,-1.26743007, +0.29003966,-3.80550122,0.80094421,0.50959778,-0.54627192,1.66060388,0.25552815,2.24310493, +3.67831278,-0.59018224,1.76608253,-0.22999156,0.30660450,1.82401633,-0.64727861,0.14090568, +-0.17653319,0.44645694,3.11600900,0.76470888,2.05788064,1.68405747,-4.51513100,0.29560512, +-0.97931010,-1.43863964,0.65891826,-2.30841184,-1.35943556,3.59664297,-2.72509551,3.33475876, +-0.08542311,3.51741123,1.12472320,0.53669631,-0.13361049,-1.07009768,3.56697083,-4.02204370, +-1.15679872,-2.61707306,0.22136778,3.74192953,-4.15067577,-2.55143785,-0.20685196,-3.53358912, +-2.54524755,2.19735479,0.23061514,1.53657317,-0.35363707,-1.15423059,2.44740582,-1.88850141, + +2.42288446,1.27227366,0.74894810,1.28347683,1.39642823,-1.93045688,0.45777908,-1.26743007, +0.29003966,-3.80550122,0.80094421,0.50959778,-0.54627192,1.66060388,0.25552815,2.24310493, +3.67831278,-0.59018224,1.76608253,-0.22999156,0.30660450,1.82401633,-0.64727861,0.14090568, +-0.17653319,0.44645694,3.11600900,0.76470888,2.05788064,1.68405747,-4.51513100,0.29560512, +-0.97931010,-1.43863964,0.65891826,-2.30841184,-1.35943556,3.59664297,-2.72509551,3.33475876, +-0.08542311,3.51741123,1.12472320,0.53669631,-0.13361049,-1.07009768,3.56697083,-4.02204370, +-1.15679872,-2.61707306,0.22136778,3.74192953,-4.15067577,-2.55143785,-0.20685196,-3.53358912, +-2.54524755,2.19735479,0.23061514,1.53657317,-0.35363707,-1.15423059,2.44740582,-1.88850141, + +4.47329473,-1.70132744,-3.95804238,3.50112128,-5.10333633,1.56902146,-1.11902511,1.78928399, +1.26198828,-0.26615992,0.54142559,0.27673587,1.57381809,4.74706888,-1.89226031,1.76737213, +1.37874687,1.05818522,-0.61736351,1.16815329,-0.14747408,-2.02085853,-0.06131025,-0.36754823, +1.97843063,-3.32084179,0.37598154,0.44123849,-0.71440083,-2.76446915,0.06502641,-0.45728233, +-1.93884647,1.51549935,0.22349268,-1.46264625,-0.93878794,2.53468966,0.09279048,3.19028425, +2.14098549,0.65744257,2.12003636,-0.21332240,-0.35039914,-1.79318547,1.08148456,0.83520722, +-0.37325758,0.44315636,-0.50703102,-0.19921407,1.08093989,-1.52517128,-1.01477206,-2.08499599, +0.05307493,0.56386751,0.16719794,0.99758488,0.35134155,-2.70159864,0.49787593,-6.01998806, + +1.88393891,1.20359635,-1.11693203,-1.24092197,-2.47922421,2.11120105,5.19413376,2.67079711, +1.07527149,0.64369327,2.57635832,1.27686763,0.69491446,-3.13548803,-2.04371452,4.62090492, +2.18864536,-2.10483122,-0.04580984,1.08532572,-3.46754074,-0.53330994,-1.35113037,-1.51521778, +-0.46994060,-2.27551699,-0.53152251,0.47133854,0.07705012,0.48279381,-1.28113365,0.48468336, +-1.54411674,0.06915778,0.64939111,-1.33318806,0.63385141,1.72500539,-1.27450287,2.53234506, +2.78955889,0.10935718,1.24130249,-2.24100065,-1.41059852,-1.18030620,1.50915027,1.37942517, +-1.41709673,-0.74830860,0.30404601,-0.99458563,0.22929534,-1.72507358,-0.68753922,-2.64537501, +0.58683372,0.88788664,0.54932535,1.45773280,0.96530700,-3.57728553,-0.41517627,-4.86154747, +=== +name:CrossAttentionData_Batch2_HeadSize32_RightSidePadding_NoBias.fp32_output_data +2.52855659,1.00436294,0.83871710,0.97005701,1.33615291,-2.07353282,0.14190522,-1.42923164, +-0.05781263,-3.81081843,1.15263164,0.62601233,-0.93824124,1.21525323,-0.17992918,2.08717370, +3.61659431,-0.16836943,2.17779160,-0.63968349,0.32170480,1.74428463,-0.46570981,-0.07432288, +-0.21569058,0.65559602,3.58669281,0.40837619,2.40912223,1.31780922,-4.45945454,0.64903581, +-1.10752177,-1.79390311,0.89312351,-1.84512544,-1.13948750,3.87221098,-2.74163318,2.90849519, +-0.31782085,3.12108278,0.80056298,1.02164125,-0.07995117,-0.96148860,3.49803638,-4.48321056, +-1.50024915,-2.58987570,0.61711067,4.13532829,-4.38111591,-2.48988461,-0.43977243,-3.93134618, +-2.67314148,2.64455128,0.11041284,1.26786041,-0.24446392,-0.86178148,2.35680771,-1.69236851, + +2.52855659,1.00436294,0.83871710,0.97005701,1.33615291,-2.07353282,0.14190522,-1.42923164, +-0.05781263,-3.81081843,1.15263164,0.62601233,-0.93824124,1.21525323,-0.17992918,2.08717370, +3.61659431,-0.16836943,2.17779160,-0.63968349,0.32170480,1.74428463,-0.46570981,-0.07432288, +-0.21569058,0.65559602,3.58669281,0.40837619,2.40912223,1.31780922,-4.45945454,0.64903581, +-1.10752177,-1.79390311,0.89312351,-1.84512544,-1.13948750,3.87221098,-2.74163318,2.90849519, +-0.31782085,3.12108278,0.80056298,1.02164125,-0.07995117,-0.96148860,3.49803638,-4.48321056, +-1.50024915,-2.58987570,0.61711067,4.13532829,-4.38111591,-2.48988461,-0.43977243,-3.93134618, +-2.67314148,2.64455128,0.11041284,1.26786041,-0.24446392,-0.86178148,2.35680771,-1.69236851, + +4.57896709,-1.96923840,-3.86827397,3.18770218,-5.16361237,1.42594552,-1.43489969,1.62748241, +0.91413617,-0.27147719,0.89311284,0.39315033,1.18184888,4.30171919,-2.32771778,1.61144078, +1.31702852,1.47999835,-0.20565441,0.75846130,-0.13237341,-2.10059047,0.12025870,-0.58277667, +1.93927360,-3.11170268,0.84666550,0.08490579,-0.36315942,-3.13071775,0.12070279,-0.10385174, +-2.09942603,1.27883554,0.42277446,-1.00997567,-0.84779590,2.87665153,0.18837044,2.81797147, +1.85540521,0.30605689,1.86793220,0.43789154,-0.20980379,-1.73483229,0.97748178,0.32941481, +-0.63111353,0.56805360,-0.17779620,0.25940496,0.92033458,-1.44722617,-1.27452552,-2.43680239, +-0.11858715,0.98449469,0.01566132,0.69114012,0.41016975,-2.33734345,0.48214769,-5.91884756, + +2.11303473,0.79722011,-1.16258705,-1.32830858,-2.66458011,1.94228184,4.57733870,2.46697760, +0.73631936,0.59500724,2.83104920,1.34561014,0.34483883,-3.20511031,-2.47195292,4.32895803, +2.08832264,-1.53225064,0.33865568,0.67958182,-3.29418707,-0.68394697,-1.10808134,-1.67574179, +-0.39239436,-2.11620450,-0.01758179,0.11357109,0.39056650,-0.03823794,-1.16129172,0.79321450, +-1.71389270,-0.13380881,0.83875018,-0.88353348,0.68820363,2.08583164,-1.14706731,2.17536139, +2.48886776,-0.22925906,1.00967121,-1.54254520,-1.24530232,-1.13623202,1.39518356,0.86095339, +-1.65063286,-0.59565234,0.61438411,-0.51743579,0.08853177,-1.64247108,-0.95491660,-2.98412538, +0.40273598,1.30096471,0.38888580,1.14056730,1.00983083,-3.19262862,-0.40963191,-4.78739595, +=== +name:CrossAttentionData_Batch1_HeadSize32_LeftSidePadding.query_data +2.88765883,1.27536213,-0.57580215,2.73696542,2.19016314,0.42629790,1.55081677,-2.01307678, +-0.80203497,-1.23206115,1.78565156,-2.09875321,-2.22730732,-0.98120236,-0.25774139,0.75868356, +-2.87585187,-0.41810805,-2.11528730,0.50642025,-0.29446256,-3.69675803,-2.73721838,-1.51089072, +0.74300194,0.27352047,-0.88251829,2.82622814,0.73837662,-2.14588642,0.37608737,-0.06190044, +-1.97659302,-2.22348428,2.25573063,-2.24459195,-2.28073978,-0.52412349,-0.57297325,3.29259396, +1.35617173,-0.83082151,0.03767079,1.82568312,0.88193995,1.15579486,1.87845564,-0.15923920, +2.37435389,1.49093378,1.95134592,-1.67609048,-0.45959851,1.63960719,3.44909906,-0.23531833, +-0.57074630,1.38279045,0.58870834,0.85297751,-1.44973445,1.56243801,-0.67229253,-0.16198707, + +-0.23966503,-0.15329531,-3.22765136,0.60538405,-0.33244422,-1.34865439,-0.24373266,-1.78808010, +-1.53090763,1.75037694,-0.71890754,0.12527336,1.26654553,-0.86477917,-1.49822962,1.67973542, +0.99763191,-0.07183220,1.55289185,1.62626481,-0.04283767,-2.55072594,-1.95238030,0.60994428, +-2.53714681,1.54605150,0.05900350,1.42194426,0.33801061,1.25557244,0.67291188,-1.36867523, +1.86936152,-1.19588101,0.75778806,1.85271311,0.02081686,2.65807819,0.78890860,-1.07388866, +4.18109226,0.06373940,2.86840463,0.90427721,-0.09531648,-0.40835506,1.60812938,-1.61683714, +-0.45421624,-2.25537109,-1.35910070,-0.25111723,-0.71782172,0.62597942,-0.42838976,0.23198499, +1.29250073,-2.01550317,0.14619158,-0.03868395,-0.74211842,-3.17291188,-1.90475547,2.02544284, +=== +name:CrossAttentionData_Batch1_HeadSize32_LeftSidePadding.key_data +1.14242256,1.08148384,-0.00962424,-1.62719429,0.86478198,0.16862091,1.01692820,-1.15278327, +-1.13622630,1.78038371,0.58222097,0.39166588,1.75063372,-1.20408881,0.75154918,0.58156419, +-0.98975772,-0.82555556,-0.72656512,-2.42399549,2.19217968,2.18518472,-1.72216129,1.35098433, +-0.34989786,-0.69064844,-0.98365444,3.10148478,0.64813483,1.78129303,-0.47006512,2.53122735, +0.09757380,0.04077591,-0.81791472,-0.19737752,1.13775492,-1.51351953,0.59109330,2.86624002, +-0.09282493,-1.69204521,1.27087700,3.53944731,0.59776509,-0.90838081,-0.15813766,-1.86199224, +0.18734205,-0.76110429,-0.02243887,-0.94068182,1.32443166,0.03512055,-0.13194422,-1.50401211, +0.92001319,0.20918207,-1.34839189,1.56431675,-0.61030018,2.39562368,-1.56722510,-0.96874726, +-0.48726845,-1.41476154,-1.45116997,0.53907454,-2.14415288,1.14340270,-0.21846619,-2.72349358, +2.99664998,-2.38684058,0.95269018,0.04208702,-1.75080788,1.24652982,-1.76879966,3.10814905, +2.48754454,-0.62601894,1.41356945,0.10340121,1.09059846,-0.78241473,-0.61477584,-0.19339988, +-0.48253334,-2.41782594,1.04690075,0.14725411,-0.20820639,-1.95920563,0.96303236,-1.20068836, + +-1.71051037,-1.90946770,-2.07985783,2.35042953,0.35059446,-0.44228595,4.08558750,-0.60121447, +0.78836018,0.35280651,0.23129070,-0.21523762,0.12277550,0.12348226,-1.62759030,-2.78246498, +4.04853964,0.29263157,-0.38621908,-1.07599223,-1.99170423,1.41409016,2.19121861,-3.53451037, +3.63692737,0.68270516,2.51469731,2.57543731,-2.39040112,-3.97164130,1.28371549,1.64144099, +-0.70385075,2.55361128,1.60707259,0.84735453,-2.07756495,-1.99240303,-3.60991144,2.87136865, +2.31296396,2.30251813,-1.05624914,-2.43777156,-0.27048296,2.39037871,-2.04504776,1.65183067, +-0.38970214,0.16808379,-1.30286717,1.90201700,-2.71696734,-0.66445369,1.27085483,-0.60816145, +1.81054437,-1.55584621,-2.19360781,-4.52794456,-0.90534067,0.94724411,2.40401077,-2.94815230, +-3.19650269,2.50638890,1.02038431,1.50519919,0.47196171,-1.89026380,-1.86559379,0.82210326, +0.10818237,1.45290673,1.62321615,-0.61283481,-1.42501950,2.10349464,-1.65715265,0.30090189, +-3.81919909,-2.44903922,-1.20557833,-0.69951278,-1.31475580,-3.73842764,1.49299407,-0.70933276, +-1.49021530,0.71776378,-1.23052382,-2.13119912,-1.20718014,2.30572701,1.78386402,-1.57122159, +=== +name:CrossAttentionData_Batch1_HeadSize32_LeftSidePadding.value_data +1.79297853,0.96909231,1.23087275,-0.61933923,-0.56477690,1.47813499,0.51474279,-3.44743419, +0.95816678,-0.20553169,-0.76906109,-4.60927439,0.40629998,0.91934747,-1.09594405,-1.45653892, +-0.59282207,0.05621797,-2.26634383,-1.30799258,1.22072279,-3.60811162,1.70111597,0.47336632, +-1.43857694,-0.13917151,-1.34617388,1.07960105,-1.77342618,0.31946269,1.19137061,2.59346104, +-1.82395399,0.73557752,2.32600021,-0.22650969,-0.48526058,1.40349376,-0.33553454,0.45531431, +0.73859257,0.37798560,0.85344458,-1.30447221,1.23349071,-0.26439479,1.18636096,-0.33328748, +-0.50939041,0.53500950,1.33486223,-1.54447496,-2.88690519,-0.06809106,-0.00597921,-1.07510388, +0.62182164,0.50033569,-0.88293070,2.56142712,0.37708595,1.59349704,-1.17139614,0.89580274, +0.69456708,2.91441655,-0.25431669,-1.20305562,2.06701255,-0.86700624,-2.23615170,0.13303493, +-2.97540593,0.08654684,1.40381706,3.54294443,-2.07661867,-1.33181918,2.24228764,1.79975545, +2.14695477,1.40222490,-0.29813689,1.94485068,1.99623775,1.53450203,0.28755581,-0.67934704, +-0.92102510,-1.52764773,1.11267352,-3.90122724,0.22128634,0.14945325,-4.38529491,-1.58423281, + +-2.45574522,-1.91599977,5.05240345,2.24617362,3.99182248,0.92924285,-0.39660916,-0.08696688, +0.24855530,0.71378094,0.92413902,1.73599064,1.03852975,2.44676781,0.35013664,0.98107171, +1.62946916,0.41239718,-1.41385484,2.49293518,2.32976985,2.89612579,2.66875219,1.47379971, +1.31164551,-1.82183075,-5.15272474,0.28575048,0.16861364,-0.47264135,0.22565089,-0.37727535, +-1.13935280,0.38051969,-2.38735437,-2.80645251,0.18637873,2.13938355,2.92260599,-0.38653925, +0.58366799,-1.67636371,-2.29396892,-1.31527638,2.39795637,0.39815575,-0.98530269,-1.29227996, +0.14452982,-0.38186538,-1.71267688,0.18121701,-2.26441002,-0.94511753,0.27371156,-2.44858527, +-0.21510160,-2.65228534,-2.16755104,0.86151361,0.77589297,-1.06628847,0.73745233,1.15778029, +-0.73659700,0.74325305,-1.97666430,-1.07301974,0.17534591,-1.66584718,1.21820331,0.67675018, +-1.08938253,1.78010321,0.39817584,-0.02914053,1.13571596,-0.44081455,1.70561552,-2.12085509, +-0.69322622,-1.87331009,-2.15000772,2.08436966,1.70494926,-3.69169927,-1.22119129,-1.60190558, +-2.09093666,-1.02816033,-1.78743768,2.34501553,2.79939008,1.82245076,1.47408092,1.10063124, +=== +name:CrossAttentionData_Batch1_HeadSize32_LeftSidePadding.bias_data +-0.38124341,0.02696526,-0.11914945,-0.43795273,-0.34948170,-0.19608477,0.19725692,0.39987487, +0.04772711,-0.03419551,-0.30606642,0.42656231,-0.23178342,-0.13692456,-0.04889601,0.48739988, +-0.25891554,0.13431972,0.22861153,0.06360734,0.48096961,-0.47906545,0.43613154,-0.23511401, +-0.10595283,-0.42839217,0.28931111,-0.13180739,-0.45826656,0.23286396,-0.43407962,0.40754890, +0.27079183,0.42074734,-0.40314156,-0.43726659,0.27376485,-0.38174152,-0.43700469,0.38040614, +-0.40546918,0.06927037,0.16979086,0.41458064,0.07120579,-0.08055863,0.12095112,-0.27988660, +0.06004709,-0.05600315,-0.25510073,0.41887105,-0.19016314,0.47241372,0.12890404,-0.24272856, +0.21106839,-0.40523255,0.10336459,-0.11084765,0.42408967,-0.15285304,-0.28945464,-0.25714916, +-0.10567203,0.26791072,-0.08976898,0.31341976,0.06027532,0.14307594,0.31587386,0.16180152, +0.34785229,0.00531715,-0.35168743,-0.11641458,0.39196932,0.44535065,0.43545735,0.15593112, +0.06171834,-0.42181283,-0.41170910,0.40969193,-0.01510030,0.07973170,-0.18156880,0.21522856, +0.03915739,-0.20913908,-0.47068381,0.35633272,-0.35124153,0.36624825,-0.05567622,-0.35343069, +=== +name:CrossAttentionData_Batch1_HeadSize32_LeftSidePadding.fp32_output_data +0.23503941,2.87619758,0.01845241,-0.75242990,1.76869011,-0.40492195,-1.65323853,0.34011719, +-2.10573196,0.13281155,0.97480160,2.74546146,-1.21957457,-0.73649400,2.52938581,1.65599120, +1.83545303,0.85856718,-0.48040742,1.86428785,1.29504943,1.38906729,0.06474495,-0.51972288, +-0.66509569,-1.45185244,0.36160457,-2.63688278,-0.10806514,0.71859169,-3.98941422,-1.58921516, + +-1.89806330,1.03079379,2.20389438,0.07467184,-0.39299977,1.51811528,-0.04347950,0.61307698, +1.03990030,0.37965038,0.50865448,-1.36013806,1.58397710,0.16757873,1.63505113,-0.15062472, +-0.41438234,0.12406474,0.90268815,-1.09105420,-2.84080887,0.03172458,-0.18386938,-0.85491556, +0.64164376,0.26578158,-1.32860518,2.83676863,0.02389192,1.94164813,-1.26734924,0.51129180, + +-0.84226906,1.01116371,-2.06643319,-0.75959998,0.23562123,-1.52277124,1.53407717,0.83855170, +-0.74153024,1.78542042,0.04648840,-0.14555511,1.52768528,0.00453609,2.14107275,-1.96492398, +-0.63150787,-2.29512286,-2.56171679,2.49406147,1.68984890,-3.61196756,-1.40276003,-1.38667703, +-2.05177927,-1.23729944,-2.25812149,2.70134830,2.44814849,2.18869901,1.41840470,0.74720055, + +-0.84226906,1.01116371,-2.06643319,-0.75959998,0.23562123,-1.52277124,1.53407717,0.83855170, +-0.74153024,1.78542042,0.04648840,-0.14555511,1.52768528,0.00453609,2.14107275,-1.96492398, +-0.63150787,-2.29512286,-2.56171679,2.49406147,1.68984890,-3.61196756,-1.40276003,-1.38667703, +-2.05177927,-1.23729944,-2.25812149,2.70134830,2.44814849,2.18869901,1.41840470,0.74720055, +=== +name:CrossAttentionData_Batch1_HeadSize32_LeftSidePadding_NoBias.fp32_output_data +0.38947105,2.65047002,0.05826539,-1.08475602,1.75782788,-0.59195572,-2.00590920,0.17207618, +-2.52548885,0.12185203,1.33714449,2.95572400,-1.67562902,-1.20251048,2.11437178,1.54135668, +1.82516265,1.29716969,-0.10031381,1.52215052,1.40468919,1.34036255,0.25199673,-0.72728944, +-0.73412323,-1.28197598,0.87092417,-3.11833549,0.24016008,0.32438612,-3.99596047,-1.28379905, + +-1.78660965,0.76788503,2.28773952,-0.24098979,-0.44741583,1.36982703,-0.36371663,0.45053560, +0.68352193,0.37366420,0.86160547,-1.23259544,1.18440890,-0.28022242,1.20201802,-0.30165902, +-0.47000250,0.54786849,1.31064832,-1.49273574,-2.81449866,-0.04432804,-0.00162671,-1.06923568, +0.59894449,0.47026503,-0.85334015,2.46559978,0.37477580,1.57208502,-1.21905136,0.85902911, + +-0.73659700,0.74325305,-1.97666430,-1.07301974,0.17534591,-1.66584718,1.21820331,0.67675018, +-1.08938253,1.78010321,0.39817584,-0.02914053,1.13571596,-0.44081455,1.70561552,-2.12085509, +-0.69322622,-1.87331009,-2.15000772,2.08436966,1.70494926,-3.69169927,-1.22119129,-1.60190558, +-2.09093666,-1.02816033,-1.78743768,2.34501553,2.79939008,1.82245076,1.47408092,1.10063124, + +-0.73659700,0.74325305,-1.97666430,-1.07301974,0.17534591,-1.66584718,1.21820331,0.67675018, +-1.08938253,1.78010321,0.39817584,-0.02914053,1.13571596,-0.44081455,1.70561552,-2.12085509, +-0.69322622,-1.87331009,-2.15000772,2.08436966,1.70494926,-3.69169927,-1.22119129,-1.60190558, +-2.09093666,-1.02816033,-1.78743768,2.34501553,2.79939008,1.82245076,1.47408092,1.10063124, +=== +name:CrossAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedKV.query_data +-0.35420692,1.31206024,-2.80201197,2.42258096,-0.86031514,-1.44535458,-0.10832444,-2.00132895, +1.62475216,0.10978927,1.84596729,0.48908550,1.44369888,0.87542874,-1.16434252,0.52133209, +1.54848897,-2.21174526,-0.28574878,0.70815033,1.18327498,3.14097571,-0.25795099,1.89341247, +-0.11603792,0.38110194,0.40873206,-1.14149106,0.79770875,-0.98069525,-1.53588808,0.50821728, +-2.21641898,0.55090773,0.80901796,-0.56089771,0.03574468,-1.27940118,-0.02213959,-0.80698186, +-0.82701880,1.72937381,1.56083691,-0.30311784,-0.25183848,0.24280515,0.29569417,-0.31162494, +0.48996922,0.22795241,2.07125854,1.45823467,3.03750706,1.53734803,0.48668906,-1.63703632, +-0.14114749,1.85963213,1.20729232,-0.28972962,-0.80783498,-1.16619551,-0.60004634,0.02498829, + +3.50846076,-2.50027657,-2.59866142,1.58495271,2.21110034,-2.74877763,-1.00267041,0.62646407, +2.50227380,-0.27291518,-0.33037442,0.75840306,0.45437157,-0.79876304,0.83509272,2.53716302, +0.01348384,-2.16307616,2.01661849,2.10746121,-1.70485222,1.35548759,1.39401650,-0.99451691, +-4.13484812,0.56262714,-0.92725742,-0.16389316,-1.31260049,2.32357836,-3.05251694,-1.12570131, +1.87849474,-1.80381167,0.52235699,2.38887334,-1.58878529,0.69571090,1.65044296,-0.27024290, +3.59580970,-1.97888982,1.17034674,0.26716161,-1.16770899,0.74609619,0.78886843,0.15717520, +-0.93303132,-0.84753871,-4.32799959,-1.94716609,-1.16980326,1.62631667,2.41053247,3.78186774, +0.26432252,-0.40396988,2.04414082,0.65150046,0.47777444,-2.57569051,0.99004912,2.47947693, +=== +name:CrossAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedKV.key_data +2.66554713,0.04116637,-1.14599442,-1.99071956,0.42523879,0.94212061,1.15597987,-1.76809072, +-1.89803648,-0.74707657,-0.71960962,0.67453432,3.31946969,1.06201041,2.29824829,0.23788756, +1.69329333,0.06745748,-1.34720469,1.81031406,-0.33143526,-2.46566057,-0.32179555,1.69001770, +-0.39678648,-0.91400242,1.56746745,0.36029303,-1.01637018,-1.84069777,0.15860040,1.35965717, +0.16654867,3.63810396,2.03763342,0.64186901,-1.02682137,2.18480039,-2.17365599,-0.56225222, +-2.48764873,1.94031644,-1.13630998,-2.51891637,-1.29985571,0.23808026,2.95523596,1.06378591, +-0.20339361,-0.56349581,1.46587682,4.12142849,0.78908098,-0.24000889,-1.15510166,0.42653239, +-1.98345447,1.06918168,2.98073006,-2.94872737,-0.67443597,-0.96227646,-1.94805872,-0.96003568, +1.06492281,0.32333452,-0.52869648,-1.25258100,0.75479198,-1.04409528,-1.81722605,0.99018478, +1.83352923,1.02711058,0.31064227,2.44383168,-1.80332434,1.57207584,-0.41058558,0.20494992, +-0.78399467,-0.35703743,-0.67568171,-1.30091023,-0.17390330,0.22340816,-0.44613233,1.23870432, +-0.16092014,-1.22258115,0.60575533,-0.17969827,1.87851882,1.13991237,-0.81591004,-1.68899822, + +-1.72543812,0.63848293,0.87042624,0.39726460,0.62647510,1.73326159,-0.55110240,-1.26900804, +1.94843686,-1.73077893,2.53475809,2.79892564,-1.91852188,0.99826050,-3.04680610,1.38900220, +-1.17920876,-2.07508063,-0.34274688,-0.24780962,1.75715542,1.27657294,-1.15560341,-2.69310951, +0.93523502,0.58213681,-2.57009196,2.56376076,0.06911665,1.73962176,0.43307841,-1.18240118, +1.52338290,1.02856898,0.40946901,1.57649779,1.22447217,0.85961932,0.30765539,-2.66427660, +-1.55998194,-0.31161505,-1.63090813,-1.62476087,1.28381526,-0.77024549,1.46711981,-0.71657622, +-0.51606011,0.87953311,0.26169056,1.03068113,0.41064253,-1.56344402,-1.53443003,-0.03009570, +-0.02123317,-1.74375248,1.60988081,1.74488568,0.59155780,-0.62032932,0.03105794,4.54175377, +-2.08403850,0.22352570,-0.17924348,0.65815634,-0.59089363,-1.66189861,0.75618476,0.03879535, +1.50222909,-0.29873836,-1.76075482,-2.97067928,0.28112072,0.72105575,0.06761266,-1.61681306, +-0.80693424,2.40102959,-2.91352296,-1.21352315,-1.62430143,-1.60909438,0.53140688,-0.28235722, +0.63271880,1.33791542,-1.37593675,-1.60502291,1.27470064,-0.96280038,0.79614848,0.31894624, +=== +name:CrossAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedKV.value_data +0.67641568,-1.44437671,0.57255918,0.11087912,0.73787844,-1.36586773, +1.45507979,-3.70331645,-0.85970032,-2.14545083,2.11107802,-0.16663373, +1.47033095,0.49124131,1.99316287,-2.68613410,0.23831765,0.90826637, +0.72628385,1.29567933,-0.07918698,0.13999116,1.22531521,0.06399018, +-2.24613571,-1.08365369,-0.68457615,-0.25960952,-0.88386559,0.46391147, +1.24469304,1.13121903, +-0.21484625,3.49263334,-1.35283577,0.38428289,-4.29686069,-4.34778786, +-0.49574745,-0.08637778,-0.50855160,-1.12334609,-1.44851387,3.36797357, +-0.91776383,-0.98647243,1.45408130,0.29062888,0.24470398,-1.28129590, +0.47530234,2.19562674,0.62674099,-2.56222868,-1.42671025,1.51795268, +-1.92045701,1.20271325,2.53190184,-0.37211552,0.92569226,-1.11019444, +1.15402830,-1.98479640, +-0.49658760,1.62168694,-1.71412969,-1.26646388,-1.37257946,1.53828073, +-0.35583261,0.03810386,0.43514529,0.97525519,-2.22109556,1.17547810, +-0.28825673,0.91509271,-1.19243717,1.09280133,-0.51078367,0.63577116, +-0.62186599,-2.80234575,-1.58007598,1.06965756,-0.89327252,-0.84735525, +-0.46283475,0.77867299,-0.07434830,1.44711912,1.07089376,0.78913736, +0.59053934,-0.32160193, + +0.51273453,1.12628150,1.96404183,0.26380035,3.41526699,1.08249199, +-1.70347631,0.42854923,-1.98269284,1.97382474,-0.12164606,-1.41219604, +0.01819625,0.73082930,-2.60845804,1.47046185,0.26324001,1.54259276, +-1.18744254,-1.77539694,1.76547086,-1.57072937,-1.83995926,-0.05529352, +1.83544660,0.69575423,-0.03345531,-1.69629955,0.04713173,1.39800107, +0.24362923,0.12432972, +-2.92895460,-0.46070760,0.20383459,1.93618548,-1.08026588,1.08253515, +-0.48318014,-2.34334373,-2.69622159,0.00661799,-1.10738027,0.03181311, +0.32897863,1.89451993,-0.01152946,0.17766151,2.46450090,-0.64409554, +2.56058550,1.29339278,2.72114944,0.87801707,-1.58970404,2.88365316, +0.46464550,-1.71912467,-1.90960062,-3.13572145,0.19871379,-0.28741950, +-0.38167781,-2.30705547, +0.64399612,0.32866889,-3.49091625,-0.02294427,1.60225844,1.83659923, +1.55193460,-0.06712314,0.76592684,0.83479869,0.49627584,0.75736403, +0.75179487,-0.32156041,1.36537170,0.57024354,0.36152276,0.93625057, +-1.69728792,-0.28833422,0.43304375,1.62640548,-0.00187188,0.80429250, +-0.77993584,1.37333393,-1.16019452,-0.91983509,0.20466281,1.09339333, +-0.99191529,3.42685890, +=== +name:CrossAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedKV.kv_data +2.66554713,0.04116637,-1.14599442,-1.99071956,0.42523879,0.94212061, +1.15597987,-1.76809072,-1.89803648,-0.74707657,-0.71960962,0.67453432, +3.31946969,1.06201041,2.29824829,0.23788756,1.69329333,0.06745748, +-1.34720469,1.81031406,-0.33143526,-2.46566057,-0.32179555,1.69001770, +-0.39678648,-0.91400242,1.56746745,0.36029303,-1.01637018,-1.84069777, +0.15860040,1.35965717, +0.67641568,-1.44437671,0.57255918,0.11087912,0.73787844,-1.36586773, +1.45507979,-3.70331645,-0.85970032,-2.14545083,2.11107802,-0.16663373, +1.47033095,0.49124131,1.99316287,-2.68613410,0.23831765,0.90826637, +0.72628385,1.29567933,-0.07918698,0.13999116,1.22531521,0.06399018, +-2.24613571,-1.08365369,-0.68457615,-0.25960952,-0.88386559,0.46391147, +1.24469304,1.13121903, + +0.16654867,3.63810396,2.03763342,0.64186901,-1.02682137,2.18480039, +-2.17365599,-0.56225222,-2.48764873,1.94031644,-1.13630998,-2.51891637, +-1.29985571,0.23808026,2.95523596,1.06378591,-0.20339361,-0.56349581, +1.46587682,4.12142849,0.78908098,-0.24000889,-1.15510166,0.42653239, +-1.98345447,1.06918168,2.98073006,-2.94872737,-0.67443597,-0.96227646, +-1.94805872,-0.96003568, +-0.21484625,3.49263334,-1.35283577,0.38428289,-4.29686069,-4.34778786, +-0.49574745,-0.08637778,-0.50855160,-1.12334609,-1.44851387,3.36797357, +-0.91776383,-0.98647243,1.45408130,0.29062888,0.24470398,-1.28129590, +0.47530234,2.19562674,0.62674099,-2.56222868,-1.42671025,1.51795268, +-1.92045701,1.20271325,2.53190184,-0.37211552,0.92569226,-1.11019444, +1.15402830,-1.98479640, + +1.06492281,0.32333452,-0.52869648,-1.25258100,0.75479198,-1.04409528, +-1.81722605,0.99018478,1.83352923,1.02711058,0.31064227,2.44383168, +-1.80332434,1.57207584,-0.41058558,0.20494992,-0.78399467,-0.35703743, +-0.67568171,-1.30091023,-0.17390330,0.22340816,-0.44613233,1.23870432, +-0.16092014,-1.22258115,0.60575533,-0.17969827,1.87851882,1.13991237, +-0.81591004,-1.68899822, +-0.49658760,1.62168694,-1.71412969,-1.26646388,-1.37257946,1.53828073, +-0.35583261,0.03810386,0.43514529,0.97525519,-2.22109556,1.17547810, +-0.28825673,0.91509271,-1.19243717,1.09280133,-0.51078367,0.63577116, +-0.62186599,-2.80234575,-1.58007598,1.06965756,-0.89327252,-0.84735525, +-0.46283475,0.77867299,-0.07434830,1.44711912,1.07089376,0.78913736, +0.59053934,-0.32160193, + +-1.72543812,0.63848293,0.87042624,0.39726460,0.62647510,1.73326159, +-0.55110240,-1.26900804,1.94843686,-1.73077893,2.53475809,2.79892564, +-1.91852188,0.99826050,-3.04680610,1.38900220,-1.17920876,-2.07508063, +-0.34274688,-0.24780962,1.75715542,1.27657294,-1.15560341,-2.69310951, +0.93523502,0.58213681,-2.57009196,2.56376076,0.06911665,1.73962176, +0.43307841,-1.18240118, +0.51273453,1.12628150,1.96404183,0.26380035,3.41526699,1.08249199, +-1.70347631,0.42854923,-1.98269284,1.97382474,-0.12164606,-1.41219604, +0.01819625,0.73082930,-2.60845804,1.47046185,0.26324001,1.54259276, +-1.18744254,-1.77539694,1.76547086,-1.57072937,-1.83995926,-0.05529352, +1.83544660,0.69575423,-0.03345531,-1.69629955,0.04713173,1.39800107, +0.24362923,0.12432972, + +1.52338290,1.02856898,0.40946901,1.57649779,1.22447217,0.85961932, +0.30765539,-2.66427660,-1.55998194,-0.31161505,-1.63090813,-1.62476087, +1.28381526,-0.77024549,1.46711981,-0.71657622,-0.51606011,0.87953311, +0.26169056,1.03068113,0.41064253,-1.56344402,-1.53443003,-0.03009570, +-0.02123317,-1.74375248,1.60988081,1.74488568,0.59155780,-0.62032932, +0.03105794,4.54175377, +-2.92895460,-0.46070760,0.20383459,1.93618548,-1.08026588,1.08253515, +-0.48318014,-2.34334373,-2.69622159,0.00661799,-1.10738027,0.03181311, +0.32897863,1.89451993,-0.01152946,0.17766151,2.46450090,-0.64409554, +2.56058550,1.29339278,2.72114944,0.87801707,-1.58970404,2.88365316, +0.46464550,-1.71912467,-1.90960062,-3.13572145,0.19871379,-0.28741950, +-0.38167781,-2.30705547, + +-2.08403850,0.22352570,-0.17924348,0.65815634,-0.59089363,-1.66189861, +0.75618476,0.03879535,1.50222909,-0.29873836,-1.76075482,-2.97067928, +0.28112072,0.72105575,0.06761266,-1.61681306,-0.80693424,2.40102959, +-2.91352296,-1.21352315,-1.62430143,-1.60909438,0.53140688,-0.28235722, +0.63271880,1.33791542,-1.37593675,-1.60502291,1.27470064,-0.96280038, +0.79614848,0.31894624, +0.64399612,0.32866889,-3.49091625,-0.02294427,1.60225844,1.83659923, +1.55193460,-0.06712314,0.76592684,0.83479869,0.49627584,0.75736403, +0.75179487,-0.32156041,1.36537170,0.57024354,0.36152276,0.93625057, +-1.69728792,-0.28833422,0.43304375,1.62640548,-0.00187188,0.80429250, +-0.77993584,1.37333393,-1.16019452,-0.91983509,0.20466281,1.09339333, +-0.99191529,3.42685890, + +=== +name:CrossAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedKV.fp16_output_data +-0.18665725,1.53655565,-1.16219902,-0.53553712,-1.76899862,-0.67172408, +-0.03719823,-0.73519617,-0.08289805,-0.22439885,-1.15095568,1.52012229, +-0.11608444,0.30267856,0.17237782,0.12366229,-0.15282108,0.15652999, +-0.05062571,-0.60356319,-0.67014134,-0.12373877,-0.62331146,-0.00974876, +-1.22021353,0.52888882,0.52984023,0.60431194,0.64458221,0.19681633, +0.87637067,-0.49721599, + +-0.21368809,3.48006248,-1.34989023,0.38081154,-4.28221798,-4.33166409, +-0.49185523,-0.09290559,-0.50751436,-1.12148952,-1.44325578,3.35744357, +-0.91217732,-0.98030341,1.45034039,0.28651160,0.24333692,-1.27377033, +0.47380278,2.18498206,0.62146491,-2.55067039,-1.42080343,1.51099622, +-1.91845036,1.19768524,2.52122355,-0.36864227,0.92257524,-1.10384953, +1.15318692,-1.97599709, + +0.25325853,0.99478984,1.75511229,0.38680723,3.04894686,1.09290445, +-1.56589723,0.21126932,-1.99892235,1.80875492,-0.18795207,-1.27262163, +0.05191655,0.80464834,-2.35645056,1.35988820,0.43171301,1.36821294, +-0.90993541,-1.52189243,1.81963241,-1.34069264,-1.79558825,0.17969209, +1.69527614,0.52177316,-0.19144230,-1.79486036,0.06081408,1.26584184, +0.17910211,-0.01467115, + +0.15915775,0.23589413,-2.89726520,0.24662971,1.27141249,1.72167253, +1.22059381,-0.36594886,0.25064397,0.74270636,0.26896626,0.62173104, +0.68196213,-0.00399938,1.11046481,0.53283978,0.64384484,0.73332942, +-1.11337614,-0.10050645,0.76519096,1.46986043,-0.24821334,1.07021677, +-0.56646812,0.94391233,-1.24186087,-1.23258281,0.20112629,0.91218621, +-0.88806105,2.59514260, +=== +name:SelfAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedQKV.query_data +-0.35420692,1.31206024,-2.80201197,2.42258096,-0.86031514,-1.44535458,-0.10832444,-2.00132895, +1.62475216,0.10978927,1.84596729,0.48908550,1.44369888,0.87542874,-1.16434252,0.52133209, +1.54848897,-2.21174526,-0.28574878,0.70815033,1.18327498,3.14097571,-0.25795099,1.89341247, +-0.11603792,0.38110194,0.40873206,-1.14149106,0.79770875,-0.98069525,-1.53588808,0.50821728, +-2.21641898,0.55090773,0.80901796,-0.56089771,0.03574468,-1.27940118,-0.02213959,-0.80698186, +-0.82701880,1.72937381,1.56083691,-0.30311784,-0.25183848,0.24280515,0.29569417,-0.31162494, +0.48996922,0.22795241,2.07125854,1.45823467,3.03750706,1.53734803,0.48668906,-1.63703632, +-0.14114749,1.85963213,1.20729232,-0.28972962,-0.80783498,-1.16619551,-0.60004634,0.02498829, + +3.50846076,-2.50027657,-2.59866142,1.58495271,2.21110034,-2.74877763,-1.00267041,0.62646407, +2.50227380,-0.27291518,-0.33037442,0.75840306,0.45437157,-0.79876304,0.83509272,2.53716302, +0.01348384,-2.16307616,2.01661849,2.10746121,-1.70485222,1.35548759,1.39401650,-0.99451691, +-4.13484812,0.56262714,-0.92725742,-0.16389316,-1.31260049,2.32357836,-3.05251694,-1.12570131, +1.87849474,-1.80381167,0.52235699,2.38887334,-1.58878529,0.69571090,1.65044296,-0.27024290, +3.59580970,-1.97888982,1.17034674,0.26716161,-1.16770899,0.74609619,0.78886843,0.15717520, +-0.93303132,-0.84753871,-4.32799959,-1.94716609,-1.16980326,1.62631667,2.41053247,3.78186774, +0.26432252,-0.40396988,2.04414082,0.65150046,0.47777444,-2.57569051,0.99004912,2.47947693, + +=== +name:SelfAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedQKV.key_data +-0.04407793,1.29459429,1.05810797,1.92067695,-0.65047157,0.99029726,-1.69796586,1.15320420, +-1.66444266,1.78305888,1.20582056,1.69975281,0.34572244,-0.60833001,2.59864879,-1.05330181, +-1.16554165,-0.03781542,-1.13475525,0.71595150,-0.91169560,1.26686060,1.60492957,-0.53510487, +-1.40180850,1.83253956,2.70238972,-1.48750985,0.47105616,-0.79477602,-1.93152475,1.04042351, +1.21863425,1.20610654,0.69031805,2.60092020,1.43040228,0.60616529,0.47948456,-1.15139377, +0.15641990,-0.46933329,0.64774191,0.35970241,-1.00424135,0.01247875,1.00281739,-1.10514688, +0.30922988,-0.82255656,-1.23242986,0.90557313,-0.38946581,-0.21124774,-2.37903309,-1.42169905, +-0.05935127,0.47488672,-0.37083727,1.31585515,-0.21577421,-0.97746384,-0.13380399,1.77390409, + +-2.65206385,1.26134932,-1.01682174,0.64366758,0.95474619,2.06720352,0.51750720,-0.07041813, +0.53124994,-3.26612782,1.37013340,0.13939659,-0.57418114,0.80680281,-3.40751696,-0.15847699, +0.97837782,-0.09121911,1.18452120,0.52711177,-1.86135840,-0.11258313,0.85863215,-2.60261130, +0.72695309,1.44092011,0.43785980,-1.63415265,-1.05772328,0.12997569,0.07356137,-0.62493324, +-0.43267637,-1.80009198,0.92961007,2.05127883,-2.85521173,-0.21652693,-0.89153922,0.15524670, +-2.16850328,1.46751809,2.51663852,-0.49499366,0.19886012,0.77093124,-1.14819765,1.47111738, +2.42824388,1.56369960,1.69934130,-0.42460468,-2.25951004,-1.18074155,3.51091242,-0.30183151, +-1.83517075,-0.56233191,2.35561657,-3.63751698,-3.20001125,-1.66120780,3.23455381,-1.86251283, + +=== +name:SelfAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedQKV.value_data +-0.89167893,0.02633595,-0.84866279,1.43489110,-2.91941142,-0.20650116,1.85965109,0.45669034, +0.07678832,0.04492294,0.67326981,0.97103029,1.53470886,-1.10242307,0.86584085,-0.34770033, +-1.24311507,-1.80293822,-1.01317739,-0.71518499,0.77814674,-0.59236068,-2.00310278,3.13277125, +-1.20754123,2.01506066,0.82650810,2.06084490,-0.46267471,1.56365979,4.31514502,-1.03099275, +-1.85462761,2.10100341,1.79686451,0.23871201,1.23598254,-0.31959364,0.50101948,-0.09527110, +-1.02331078,0.16319990,-0.54766160,0.41597658,-0.52141404,1.71663237,-0.00776333,-0.68160462, +1.76272714,-0.04465733,0.28247434,1.69360149,0.14144623,0.75038731,-1.33337545,2.23457718, +-0.07649468,1.97064841,-1.85374629,-1.59334683,0.32698441,-0.16024286,2.02828407,-0.96440399, + +-2.11639142,-1.50897706,1.63863683,2.32786226,1.32746494,0.75751448,0.57184196,0.86446053, +-0.62406683,0.78861046,0.01044065,3.51772785,-1.33701336,0.27977663,-0.35464612,0.74973166, +0.03352100,1.55007398,0.69849420,-2.47725606,-1.89363778,-1.79874682,-0.56210291,-1.75556040, +1.07565808,-0.18023658,1.63777173,1.28198206,2.19431949,0.67998970,-0.52531999,-1.89906740, +1.35158050,-2.21481490,-0.11812399,-1.74263430,-0.57895988,-0.04181165,0.78120053,-2.22377038, +-0.53264999,-2.03721714,0.21023634,2.55751204,-1.04522800,0.85386503,0.41594937,-2.98181081, +1.14034331,-1.41539204,0.13379651,3.47018123,1.53924727,1.50004411,2.87318921,1.62624204, +0.64942807,-4.54302311,-1.50294220,-1.75212634,0.27900690,-3.05124855,3.30960631,-0.07991691, + +=== +name:SelfAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedQKV.qkv_data +-0.35420692,1.31206024,-2.80201197,2.42258096,-0.86031514,-1.44535458,-0.10832444,-2.00132895, +1.62475216,0.10978927,1.84596729,0.48908550,1.44369888,0.87542874,-1.16434252,0.52133209, +1.54848897,-2.21174526,-0.28574878,0.70815033,1.18327498,3.14097571,-0.25795099,1.89341247, +-0.11603792,0.38110194,0.40873206,-1.14149106,0.79770875,-0.98069525,-1.53588808,0.50821728, +-0.04407793,1.29459429,1.05810797,1.92067695,-0.65047157,0.99029726,-1.69796586,1.15320420, +-1.66444266,1.78305888,1.20582056,1.69975281,0.34572244,-0.60833001,2.59864879,-1.05330181, +-1.16554165,-0.03781542,-1.13475525,0.71595150,-0.91169560,1.26686060,1.60492957,-0.53510487, +-1.40180850,1.83253956,2.70238972,-1.48750985,0.47105616,-0.79477602,-1.93152475,1.04042351, +-0.89167893,0.02633595,-0.84866279,1.43489110,-2.91941142,-0.20650116,1.85965109,0.45669034, +0.07678832,0.04492294,0.67326981,0.97103029,1.53470886,-1.10242307,0.86584085,-0.34770033, +-1.24311507,-1.80293822,-1.01317739,-0.71518499,0.77814674,-0.59236068,-2.00310278,3.13277125, +-1.20754123,2.01506066,0.82650810,2.06084490,-0.46267471,1.56365979,4.31514502,-1.03099275, + +-2.21641898,0.55090773,0.80901796,-0.56089771,0.03574468,-1.27940118,-0.02213959,-0.80698186, +-0.82701880,1.72937381,1.56083691,-0.30311784,-0.25183848,0.24280515,0.29569417,-0.31162494, +0.48996922,0.22795241,2.07125854,1.45823467,3.03750706,1.53734803,0.48668906,-1.63703632, +-0.14114749,1.85963213,1.20729232,-0.28972962,-0.80783498,-1.16619551,-0.60004634,0.02498829, +1.21863425,1.20610654,0.69031805,2.60092020,1.43040228,0.60616529,0.47948456,-1.15139377, +0.15641990,-0.46933329,0.64774191,0.35970241,-1.00424135,0.01247875,1.00281739,-1.10514688, +0.30922988,-0.82255656,-1.23242986,0.90557313,-0.38946581,-0.21124774,-2.37903309,-1.42169905, +-0.05935127,0.47488672,-0.37083727,1.31585515,-0.21577421,-0.97746384,-0.13380399,1.77390409, +-1.85462761,2.10100341,1.79686451,0.23871201,1.23598254,-0.31959364,0.50101948,-0.09527110, +-1.02331078,0.16319990,-0.54766160,0.41597658,-0.52141404,1.71663237,-0.00776333,-0.68160462, +1.76272714,-0.04465733,0.28247434,1.69360149,0.14144623,0.75038731,-1.33337545,2.23457718, +-0.07649468,1.97064841,-1.85374629,-1.59334683,0.32698441,-0.16024286,2.02828407,-0.96440399, + +3.50846076,-2.50027657,-2.59866142,1.58495271,2.21110034,-2.74877763,-1.00267041,0.62646407, +2.50227380,-0.27291518,-0.33037442,0.75840306,0.45437157,-0.79876304,0.83509272,2.53716302, +0.01348384,-2.16307616,2.01661849,2.10746121,-1.70485222,1.35548759,1.39401650,-0.99451691, +-4.13484812,0.56262714,-0.92725742,-0.16389316,-1.31260049,2.32357836,-3.05251694,-1.12570131, +-2.65206385,1.26134932,-1.01682174,0.64366758,0.95474619,2.06720352,0.51750720,-0.07041813, +0.53124994,-3.26612782,1.37013340,0.13939659,-0.57418114,0.80680281,-3.40751696,-0.15847699, +0.97837782,-0.09121911,1.18452120,0.52711177,-1.86135840,-0.11258313,0.85863215,-2.60261130, +0.72695309,1.44092011,0.43785980,-1.63415265,-1.05772328,0.12997569,0.07356137,-0.62493324, +-2.11639142,-1.50897706,1.63863683,2.32786226,1.32746494,0.75751448,0.57184196,0.86446053, +-0.62406683,0.78861046,0.01044065,3.51772785,-1.33701336,0.27977663,-0.35464612,0.74973166, +0.03352100,1.55007398,0.69849420,-2.47725606,-1.89363778,-1.79874682,-0.56210291,-1.75556040, +1.07565808,-0.18023658,1.63777173,1.28198206,2.19431949,0.67998970,-0.52531999,-1.89906740, + +1.87849474,-1.80381167,0.52235699,2.38887334,-1.58878529,0.69571090,1.65044296,-0.27024290, +3.59580970,-1.97888982,1.17034674,0.26716161,-1.16770899,0.74609619,0.78886843,0.15717520, +-0.93303132,-0.84753871,-4.32799959,-1.94716609,-1.16980326,1.62631667,2.41053247,3.78186774, +0.26432252,-0.40396988,2.04414082,0.65150046,0.47777444,-2.57569051,0.99004912,2.47947693, +-0.43267637,-1.80009198,0.92961007,2.05127883,-2.85521173,-0.21652693,-0.89153922,0.15524670, +-2.16850328,1.46751809,2.51663852,-0.49499366,0.19886012,0.77093124,-1.14819765,1.47111738, +2.42824388,1.56369960,1.69934130,-0.42460468,-2.25951004,-1.18074155,3.51091242,-0.30183151, +-1.83517075,-0.56233191,2.35561657,-3.63751698,-3.20001125,-1.66120780,3.23455381,-1.86251283, +1.35158050,-2.21481490,-0.11812399,-1.74263430,-0.57895988,-0.04181165,0.78120053,-2.22377038, +-0.53264999,-2.03721714,0.21023634,2.55751204,-1.04522800,0.85386503,0.41594937,-2.98181081, +1.14034331,-1.41539204,0.13379651,3.47018123,1.53924727,1.50004411,2.87318921,1.62624204, +0.64942807,-4.54302311,-1.50294220,-1.75212634,0.27900690,-3.05124855,3.30960631,-0.07991691, + +=== +name:SelfAttentionData_Batch2_HeadSize32_NoBias_NoMask_PackedQKV.fp16_output_data +-1.30247164,0.91138631,0.27991560,0.92460269,-1.14672589,-0.25474626, +1.28006065,0.22122431,-0.39251250,0.09537974,0.15242209,0.73424512, +0.65756959,0.10018224,0.49316248,-0.49014348,0.03917319,-1.05285788, +-0.46045411,0.31240013,0.50653118,-0.01954618,-1.71739793,2.74960279, +-0.72503829,1.99611449,-0.31688485,0.50197154,-0.12580720,0.82824522, +3.33957314,-1.00258613, + +-0.95444643,0.16156809,-0.67622054,1.35692120,-2.64855242,-0.21387282, +1.77109206,0.42071211,0.00508105,0.05263254,0.59368640,0.93485051, +1.40068567,-0.91866994,0.80889714,-0.36946508,-1.04718661,-1.68832910, +-0.92872351,-0.55817413,0.73664504,-0.50483698,-1.95944834,3.07422471, +-1.13381684,2.01216578,0.65180230,1.82265544,-0.41120273,1.45129156, +4.16608191,-1.02665234, + +0.21158576,-1.98279130,0.45935997,-0.40457720,0.04772174,0.22094353, +0.71238005,-1.20860445,-0.56270063,-1.10830855,0.14455934,2.87315512, +-1.14114404,0.66515017,0.16263856,-1.75517499,0.77650774,-0.44058144, +0.31942442,1.51513433,0.41078627,0.41566271,1.74393702,0.51457298, +0.78953874,-3.10888410,-0.47052401,-0.75475156,0.90861011,-1.82471263, +2.04898596,-0.67790967, + +1.17194295,-2.17825341,-0.02712549,-1.53178656,-0.48020893,-0.00040733, +0.77035600,-2.06380320,-0.53738528,-1.89084208,0.19988713,2.60725045, +-1.06034219,0.82412785,0.37603328,-2.78852081,1.08301103,-1.26178384, +0.16304730,3.16210985,1.36142719,1.32916999,2.69524455,1.45106804, +0.67150640,-4.31703520,-1.34025633,-1.59496248,0.37821823,-2.85797405, +3.11096096,-0.17414713, + +=== +name:CrossAttentionData_HeadSize16_8.query_data +2.88765883,1.27536213,-0.57580215,2.73696542,2.19016314,0.42629790,1.55081677,-2.01307678, +-0.80203497,-1.23206115,1.78565156,-2.09875321,-2.22730732,-0.98120236,-0.25774139,0.75868356, +-2.87585187,-0.41810805,-2.11528730,0.50642025,-0.29446256,-3.69675803,-2.73721838,-1.51089072, +0.74300194,0.27352047,-0.88251829,2.82622814,0.73837662,-2.14588642,0.37608737,-0.06190044, +1.83028936,-0.02953561,1.94609165,1.03678417,-3.07869005,1.13037205,2.14215207,1.29724145, +0.06229818,-2.93803453,-1.12074065,-1.75312924,-2.51804519,-0.20714152,0.94910270,0.31394321, + +-1.97659302,-2.22348428,2.25573063,-2.24459195,-2.28073978,-0.52412349,-0.57297325,3.29259396, +1.35617173,-0.83082151,0.03767079,1.82568312,0.88193995,1.15579486,1.87845564,-0.15923920, +2.37435389,1.49093378,1.95134592,-1.67609048,-0.45959851,1.63960719,3.44909906,-0.23531833, +-0.57074630,1.38279045,0.58870834,0.85297751,-1.44973445,1.56243801,-0.67229253,-0.16198707, +2.24443579,0.01009618,-2.02270651,-1.48122561,-0.71337879,-1.41594160,0.67262292,-1.45187402, +2.45791745,0.94860327,1.22767174,1.16789973,-0.69281816,0.90847492,1.16295385,-0.84179711, + +=== +name:CrossAttentionData_HeadSize16_8.key_data +1.14242256,1.08148384,-0.00962424,-1.62719429,0.86478198,0.16862091,1.01692820,-1.15278327, +-1.13622630,1.78038371,0.58222097,0.39166588,1.75063372,-1.20408881,0.75154918,0.58156419, +-0.98975772,-0.82555556,-0.72656512,-2.42399549,2.19217968,2.18518472,-1.72216129,1.35098433, +-0.34989786,-0.69064844,-0.98365444,3.10148478,0.64813483,1.78129303,-0.47006512,2.53122735, +-4.06511545,0.22256386,2.46787810,-1.64387906,-0.72458595,0.03613299,-2.20491385,1.25488305, +-1.49934030,0.09558886,0.21092418,-0.04370949,-0.54754108,0.89117372,-1.44286251,-0.89374435, +0.09757380,0.04077591,-0.81791472,-0.19737752,1.13775492,-1.51351953,0.59109330,2.86624002, +-0.09282493,-1.69204521,1.27087700,3.53944731,0.59776509,-0.90838081,-0.15813766,-1.86199224, +0.18734205,-0.76110429,-0.02243887,-0.94068182,1.32443166,0.03512055,-0.13194422,-1.50401211, +0.92001319,0.20918207,-1.34839189,1.56431675,-0.61030018,2.39562368,-1.56722510,-0.96874726, +0.36663681,1.67216635,1.97995794,-1.43150198,1.61904466,-0.26285610,-0.63515049,3.34068251, +0.54150528,1.26057637,-0.99386609,0.06303076,-1.30578506,0.03304024,-0.22100723,-0.79328370, +-0.48726845,-1.41476154,-1.45116997,0.53907454,-2.14415288,1.14340270,-0.21846619,-2.72349358, +2.99664998,-2.38684058,0.95269018,0.04208702,-1.75080788,1.24652982,-1.76879966,3.10814905, +2.48754454,-0.62601894,1.41356945,0.10340121,1.09059846,-0.78241473,-0.61477584,-0.19339988, +-0.48253334,-2.41782594,1.04690075,0.14725411,-0.20820639,-1.95920563,0.96303236,-1.20068836, +1.01268184,4.29013920,0.77999580,1.46932411,0.87674600,-1.25074506,2.45850706,0.09870356, +-0.14051074,1.17763662,-1.21477187,1.60379291,-0.01956993,0.43266663,-0.45684600,-1.02696598, + +-1.71051037,-1.90946770,-2.07985783,2.35042953,0.35059446,-0.44228595,4.08558750,-0.60121447, +0.78836018,0.35280651,0.23129070,-0.21523762,0.12277550,0.12348226,-1.62759030,-2.78246498, +4.04853964,0.29263157,-0.38621908,-1.07599223,-1.99170423,1.41409016,2.19121861,-3.53451037, +3.63692737,0.68270516,2.51469731,2.57543731,-2.39040112,-3.97164130,1.28371549,1.64144099, +0.18788165,1.15558743,2.74443531,0.92457932,-0.34628516,0.15525299,1.43510377,0.20861864, +2.88269520,0.64859426,1.78730142,-2.25655675,-1.83863652,-2.58051491,-4.23162079,1.49537027, +-0.70385075,2.55361128,1.60707259,0.84735453,-2.07756495,-1.99240303,-3.60991144,2.87136865, +2.31296396,2.30251813,-1.05624914,-2.43777156,-0.27048296,2.39037871,-2.04504776,1.65183067, +-0.38970214,0.16808379,-1.30286717,1.90201700,-2.71696734,-0.66445369,1.27085483,-0.60816145, +1.81054437,-1.55584621,-2.19360781,-4.52794456,-0.90534067,0.94724411,2.40401077,-2.94815230, +1.56385708,-0.63737142,-0.72946531,-0.79579020,-0.18071416,0.66005665,-3.16687059,-0.97323495, +0.49748731,-3.54246902,-2.14790606,0.09179869,-0.56292027,-2.96827269,1.74778676,0.12816763, +-3.19650269,2.50638890,1.02038431,1.50519919,0.47196171,-1.89026380,-1.86559379,0.82210326, +0.10818237,1.45290673,1.62321615,-0.61283481,-1.42501950,2.10349464,-1.65715265,0.30090189, +-3.81919909,-2.44903922,-1.20557833,-0.69951278,-1.31475580,-3.73842764,1.49299407,-0.70933276, +-1.49021530,0.71776378,-1.23052382,-2.13119912,-1.20718014,2.30572701,1.78386402,-1.57122159, +-1.08014178,-1.40319920,-1.40852046,0.59488881,-3.51004219,2.35288191,-2.06260157,-1.11531663, +2.51375723,0.25726259,-0.99232292,1.47292709,2.81933832,-0.39054599,0.18200648,1.54844952, +=== +name:CrossAttentionData_HeadSize16_8.value_data +1.79297853,0.96909231,1.23087275,-0.61933923,-0.56477690,1.47813499,0.51474279,-3.44743419, +0.95816678,-0.20553169,-0.76906109,-4.60927439,0.40629998,0.91934747,-1.09594405,-1.45653892, +-0.59282207,0.05621797,-2.26634383,-1.30799258,1.22072279,-3.60811162,1.70111597,0.47336632, +-1.82395399,0.73557752,2.32600021,-0.22650969,-0.48526058,1.40349376,-0.33553454,0.45531431, +0.73859257,0.37798560,0.85344458,-1.30447221,1.23349071,-0.26439479,1.18636096,-0.33328748, +-0.50939041,0.53500950,1.33486223,-1.54447496,-2.88690519,-0.06809106,-0.00597921,-1.07510388, +0.69456708,2.91441655,-0.25431669,-1.20305562,2.06701255,-0.86700624,-2.23615170,0.13303493, +-2.97540593,0.08654684,1.40381706,3.54294443,-2.07661867,-1.33181918,2.24228764,1.79975545, +2.14695477,1.40222490,-0.29813689,1.94485068,1.99623775,1.53450203,0.28755581,-0.67934704, + +-2.45574522,-1.91599977,5.05240345,2.24617362,3.99182248,0.92924285,-0.39660916,-0.08696688, +0.24855530,0.71378094,0.92413902,1.73599064,1.03852975,2.44676781,0.35013664,0.98107171, +1.62946916,0.41239718,-1.41385484,2.49293518,2.32976985,2.89612579,2.66875219,1.47379971, +-1.13935280,0.38051969,-2.38735437,-2.80645251,0.18637873,2.13938355,2.92260599,-0.38653925, +0.58366799,-1.67636371,-2.29396892,-1.31527638,2.39795637,0.39815575,-0.98530269,-1.29227996, +0.14452982,-0.38186538,-1.71267688,0.18121701,-2.26441002,-0.94511753,0.27371156,-2.44858527, +-0.73659700,0.74325305,-1.97666430,-1.07301974,0.17534591,-1.66584718,1.21820331,0.67675018, +-1.08938253,1.78010321,0.39817584,-0.02914053,1.13571596,-0.44081455,1.70561552,-2.12085509, +-0.69322622,-1.87331009,-2.15000772,2.08436966,1.70494926,-3.69169927,-1.22119129,-1.60190558, + +=== +name:CrossAttentionData_HeadSize16_8.bias_data +-0.38124341,0.02696526,-0.11914945,-0.43795273,-0.34948170,-0.19608477,0.19725692,0.39987487, +0.04772711,-0.03419551,-0.30606642,0.42656231,-0.23178342,-0.13692456,-0.04889601,0.48739988, +-0.25891554,0.13431972,0.22861153,0.06360734,0.48096961,-0.47906545,0.43613154,-0.23511401, +-0.10595283,-0.42839217,0.28931111,-0.13180739,-0.45826656,0.23286396,-0.43407962,0.40754890, +0.23778325,0.34850210,-0.01385659,0.32141626,-0.27738628,0.27683002,0.31886810,-0.24781504, +-0.25476855,-0.46742713,-0.12478521,0.39731556,-0.12087554,0.40822440,0.13202906,-0.23747686, +0.27079183,0.42074734,-0.40314156,-0.43726659,0.27376485,-0.38174152,-0.43700469,0.38040614, +-0.40546918,0.06927037,0.16979086,0.41458064,0.07120579,-0.08055863,0.12095112,-0.27988660, +0.06004709,-0.05600315,-0.25510073,0.41887105,-0.19016314,0.47241372,0.12890404,-0.24272856, +0.21106839,-0.40523255,0.10336459,-0.11084765,0.42408967,-0.15285304,-0.28945464,-0.25714916, +0.40978593,-0.09138483,-0.02013114,-0.39042589,-0.19557095,0.07540411,0.33955890,0.41873980, +-0.27744853,-0.33097768,-0.44587523,-0.01648277,0.34952271,-0.48838940,-0.17273578,0.37286615, +-0.10567203,0.26791072,-0.08976898,0.31341976,0.06027532,0.14307594,0.31587386,0.16180152, +0.34785229,0.00531715,-0.35168743,-0.11641458,0.39196932,0.44535065,0.43545735,0.15593112, +0.06171834,-0.42181283,-0.41170910,0.40969193,-0.01510030,0.07973170,-0.18156880,0.21522856, + +=== +name:CrossAttentionData_HeadSize16_8.fp32_output_data +0.70553654,2.84393549,-0.06753168,-0.78168947,1.67733526,-0.32306066,-1.46519339,-0.24197246, +0.68103230,0.09225838,-0.12426007,-2.19415975,0.82274425,0.54800904,0.77917045,-0.37480056, +1.41798937,0.70201361,-0.38768357,1.33144617,0.71884990,0.98060107,0.09563713,-0.51187015, + +-1.23079133,0.65636921,-2.42403007,-2.38468814,0.26282290,2.08802962,3.13919282,-0.17057800, +0.59563273,0.71862715,0.57042938,1.61676264,1.43126500,2.88902473,0.78586847,1.13364232, +-0.24963731,-1.69403267,-2.38265419,1.86863625,0.37573546,-2.40374231,-0.73219091,-1.54168916, + +=== +name:CrossAttentionData_HeadSize16_8_NoBias.fp32_output_data +0.88660234,2.46094799,0.10754689,-1.06147599,1.46027637,-0.32641891,-1.61505651,-0.62761730, +0.35181305,0.04672670,0.11436265,-2.31145239,0.37641913,0.18575731,0.18441223,-0.61060971, +0.62300563,0.86652821,0.32993844,-0.02772357,-0.44500753,0.32007718,0.26425001,-0.77443624, + +-1.12354600,0.38605267,-2.30243778,-2.65445495,0.21547484,1.88312864,2.78607035,-0.31523654, +0.24827829,0.71276933,0.92208558,1.73359740,1.03935337,2.44456077,0.34983918,0.97865880, +-0.25726128,-1.24286532,-1.95995116,1.54186428,0.55555028,-2.34330893,-0.46331605,-1.61526406, + +=== +name:CrossAttentionData_HeadSize16.query_data +2.88765883,1.27536213,-0.57580215,2.73696542,2.19016314,0.42629790,1.55081677,-2.01307678, +-0.80203497,-1.23206115,1.78565156,-2.09875321,-2.22730732,-0.98120236,-0.25774139,0.75868356, +-2.87585187,-0.41810805,-2.11528730,0.50642025,-0.29446256,-3.69675803,-2.73721838,-1.51089072, +0.74300194,0.27352047,-0.88251829,2.82622814,0.73837662,-2.14588642,0.37608737,-0.06190044, +-1.97659302,-2.22348428,2.25573063,-2.24459195,-2.28073978,-0.52412349,-0.57297325,3.29259396, +1.35617173,-0.83082151,0.03767079,1.82568312,0.88193995,1.15579486,1.87845564,-0.15923920, +2.37435389,1.49093378,1.95134592,-1.67609048,-0.45959851,1.63960719,3.44909906,-0.23531833, +-0.57074630,1.38279045,0.58870834,0.85297751,-1.44973445,1.56243801,-0.67229253,-0.16198707, +=== +name:CrossAttentionData_HeadSize16.key_data +1.14242256,1.08148384,-0.00962424,-1.62719429,0.86478198,0.16862091,1.01692820,-1.15278327, +-1.13622630,1.78038371,0.58222097,0.39166588,1.75063372,-1.20408881,0.75154918,0.58156419, +-0.98975772,-0.82555556,-0.72656512,-2.42399549,2.19217968,2.18518472,-1.72216129,1.35098433, +-0.34989786,-0.69064844,-0.98365444,3.10148478,0.64813483,1.78129303,-0.47006512,2.53122735, +0.09757380,0.04077591,-0.81791472,-0.19737752,1.13775492,-1.51351953,0.59109330,2.86624002, +-0.09282493,-1.69204521,1.27087700,3.53944731,0.59776509,-0.90838081,-0.15813766,-1.86199224, +0.18734205,-0.76110429,-0.02243887,-0.94068182,1.32443166,0.03512055,-0.13194422,-1.50401211, +0.92001319,0.20918207,-1.34839189,1.56431675,-0.61030018,2.39562368,-1.56722510,-0.96874726, +-0.48726845,-1.41476154,-1.45116997,0.53907454,-2.14415288,1.14340270,-0.21846619,-2.72349358, +2.99664998,-2.38684058,0.95269018,0.04208702,-1.75080788,1.24652982,-1.76879966,3.10814905, +2.48754454,-0.62601894,1.41356945,0.10340121,1.09059846,-0.78241473,-0.61477584,-0.19339988, +-0.48253334,-2.41782594,1.04690075,0.14725411,-0.20820639,-1.95920563,0.96303236,-1.20068836, +=== +name:CrossAttentionData_HeadSize16.value_data +1.79297853,0.96909231,1.23087275,-0.61933923,-0.56477690,1.47813499,0.51474279,-3.44743419, +0.95816678,-0.20553169,-0.76906109,-4.60927439,0.40629998,0.91934747,-1.09594405,-1.45653892, +-0.59282207,0.05621797,-2.26634383,-1.30799258,1.22072279,-3.60811162,1.70111597,0.47336632, +-1.43857694,-0.13917151,-1.34617388,1.07960105,-1.77342618,0.31946269,1.19137061,2.59346104, +-1.82395399,0.73557752,2.32600021,-0.22650969,-0.48526058,1.40349376,-0.33553454,0.45531431, +0.73859257,0.37798560,0.85344458,-1.30447221,1.23349071,-0.26439479,1.18636096,-0.33328748, +-0.50939041,0.53500950,1.33486223,-1.54447496,-2.88690519,-0.06809106,-0.00597921,-1.07510388, +0.62182164,0.50033569,-0.88293070,2.56142712,0.37708595,1.59349704,-1.17139614,0.89580274, +0.69456708,2.91441655,-0.25431669,-1.20305562,2.06701255,-0.86700624,-2.23615170,0.13303493, +-2.97540593,0.08654684,1.40381706,3.54294443,-2.07661867,-1.33181918,2.24228764,1.79975545, +2.14695477,1.40222490,-0.29813689,1.94485068,1.99623775,1.53450203,0.28755581,-0.67934704, +-0.92102510,-1.52764773,1.11267352,-3.90122724,0.22128634,0.14945325,-4.38529491,-1.58423281, +=== +name:CrossAttentionData_HeadSize16.bias_data +-0.38124341,0.02696526,-0.11914945,-0.43795273,-0.34948170,-0.19608477,0.19725692,0.39987487, +0.04772711,-0.03419551,-0.30606642,0.42656231,-0.23178342,-0.13692456,-0.04889601,0.48739988, +-0.25891554,0.13431972,0.22861153,0.06360734,0.48096961,-0.47906545,0.43613154,-0.23511401, +-0.10595283,-0.42839217,0.28931111,-0.13180739,-0.45826656,0.23286396,-0.43407962,0.40754890, +0.27079183,0.42074734,-0.40314156,-0.43726659,0.27376485,-0.38174152,-0.43700469,0.38040614, +-0.40546918,0.06927037,0.16979086,0.41458064,0.07120579,-0.08055863,0.12095112,-0.27988660, +0.06004709,-0.05600315,-0.25510073,0.41887105,-0.19016314,0.47241372,0.12890404,-0.24272856, +0.21106839,-0.40523255,0.10336459,-0.11084765,0.42408967,-0.15285304,-0.28945464,-0.25714916, +-0.10567203,0.26791072,-0.08976898,0.31341976,0.06027532,0.14307594,0.31587386,0.16180152, +0.34785229,0.00531715,-0.35168743,-0.11641458,0.39196932,0.44535065,0.43545735,0.15593112, +0.06171834,-0.42181283,-0.41170910,0.40969193,-0.01510030,0.07973170,-0.18156880,0.21522856, +0.03915739,-0.20913908,-0.47068381,0.35633272,-0.35124153,0.36624825,-0.05567622,-0.35343069, +=== +name:CrossAttentionData_HeadSize16.fp32_output_data +0.70553654,2.84393549,-0.06753166,-0.78168941,1.67733538,-0.32306066,-1.46519351,-0.24197248, +-1.95703733,0.05333783,0.71154630,2.09348249,-1.24223638,-0.52374214,2.15032387,1.41931129, +-0.12594563,0.02337830,-0.85073662,-0.56283176,-0.47189179,-1.30011129,0.58861959,-0.13839069, +-0.43588838,-0.25786775,-1.28476405,1.40800762,-0.92311549,1.21551156,-0.64031672,0.94095230, + +-1.87212098,1.04452848,2.18516684,0.06764929,-0.37797281,1.50475919,-0.05229051,0.59941143, +1.01834595,0.37615222,0.50706661,-1.34108353,1.56169033,0.16475427,1.63450289,-0.14124450, +-0.21351013,0.15201563,0.47484040,-0.79835385,-2.11648011,-0.13788147,-0.01865268,-0.69491959, +0.34924412,0.05382843,-1.21107709,2.20767021,-0.16749848,1.72250605,-1.32190716,0.45872629, + +=== +name:CrossAttentionData_HeadSize16_NoBias.fp32_output_data +0.88660234,2.46094799,0.10754693,-1.06147599,1.46027637,-0.32641891,-1.61505640,-0.62761730, +-2.07027483,0.02902380,0.92946291,1.71574616,-1.48879766,-0.83188367,1.50993633,1.06654513, +-0.19588387,0.41118127,-0.68736500,-0.95931244,-0.17629701,-1.62689805,0.88834876,-0.24655706, +-0.61657274,-0.09123766,-0.84804469,0.95479041,-0.72092235,0.76219988,-0.41778216,1.41442800, + +-1.75602365,0.78011239,2.26923561,-0.24788655,-0.43482834,1.35864854,-0.36920172,0.42971241, +0.66571552,0.36931390,0.85642850,-1.22419143,1.16351080,-0.27983150,1.19616866,-0.29633391, +-0.24715914,0.57112449,0.77329880,-1.16207874,-1.93779230,-0.29239467,0.21112607,-0.86494255, +0.23835859,0.22305638,-0.72983342,1.73876703,0.12544832,1.30632234,-1.24074650,0.82852137, + +=== +name:CrossAttentionDataWithPast.query_data +-0.10939738,-0.11916742,-0.23157823,-0.12894472, +-0.02661306,0.26251313,0.30725253,-0.34759378, +-0.11695808,-0.13129434,-0.17031054,-0.14986445, +-0.02826184,0.2797631,0.27337456,-0.44312602, + +=== +name:CrossAttentionDataWithPast.past_key_data +0.5967375,0.5966938,0.48602432,0.5341031, +0.55797786,0.5663399,0.57087725,0.6240304, +0.5352563,0.5648297,0.4972945,0.56637144, + +0.44123724,0.35872823,0.32176313,0.4490301, +0.3643952,0.51968557,0.50137347,0.5743993, +0.3905106,0.4741712,0.40881708,0.47243845, + +=== +name:CrossAttentionDataWithPast.past_value_data +0.40251260,0.55487730,0.49565578,0.42683450, +0.44379145,0.58945787,0.54852820,0.43376005, +0.44116694,0.44007313,0.40293324,0.53202707, + +0.35520583,0.47293650,0.45417705,0.33723440, +0.50175804,0.37620395,0.24103148,0.50958070, +0.56803876,0.37866923,0.32273075,0.44389135, +=== +name:CrossAttentionDataWithPast.fp32_output_data +0.4291,0.5275,0.4818,0.4645,0.4770,0.4082,0.3372,0.4319, +0.4291,0.5276,0.4818,0.4645,0.4768,0.4083,0.3377,0.4315, + +=== +name:SelfAttentionData_WithPast_WithRelPosBias_ForT5.query_data +0.00403503,0.08716156,-0.0358175,-0.08171791, +0.48912194,-0.22679007,-0.09093101,-0.5939322, +0.00878838,0.03355761,-0.08080226,-0.06677517, +0.55038965,-0.2720567,-0.12977877,-0.634123, + +=== +name:SelfAttentionData_WithPast_WithRelPosBias_ForT5.key_data +0.2808786,0.10041683,0.15880886,0.45283064, +0.39884242,0.12596075,0.4198916,-0.0651141, +0.31678027,0.11010794,0.21594375,0.4975329, +0.436772,0.20940652,0.44072092,-0.05601776, +=== +name:SelfAttentionData_WithPast_WithRelPosBias_ForT5.value_data +0.26421773,-0.16541699,-0.0599675,0.27200517, +-0.1074627,-0.4493224,-0.03694462,0.17997989, +0.27960598,-0.16643806,-0.07019104,0.29006317, +-0.11640988,-0.47876123,-0.01979145,0.11468418, +=== +name:SelfAttentionData_WithPast_WithRelPosBias_ForT5.rel_pos_bias_data +0.4781123,0.82420444,0.654424,0.3995186,0.5482078, +0.55570245,0.4216576,0.46001542,0.67183703,0.41973996, + +0.28494194,0.60367906,0.3453173,0.44483483,0.6770777, +0.5460559,0.31994605,0.5470492,0.5433419,0.60349935, + +=== +name:SelfAttentionData_WithPast_WithRelPosBias_ForT5.past_key_data +0.34734827,0.5592256,0.5333037,0.5122027, +0.5940516,0.44744077,0.43128848,0.55360645, +0.57874715,0.29512063,0.2780432,0.4693917, + +0.4450266,0.530704,0.3124955,0.4273598, +0.44368753,0.5890438,0.5054336,0.46042535, +0.5352153,0.5157861,0.39744973,0.5441864, + +=== +name:SelfAttentionData_WithPast_WithRelPosBias_ForT5.past_value_data +0.48998538,0.5493853,0.556647,0.7011929, +0.543909,0.5630743,0.5087797,0.3901024, +0.53116417,0.4086225,0.5320247,0.5145377, + +0.4086198,0.6913348,0.50045484,0.5338214, +0.52980417,0.5243695,0.6046111,0.53555113, +0.44936907,0.6010697,0.38031512,0.427301, +=== +name:SelfAttentionData_WithPast_WithRelPosBias_ForT5.fp32_output_data +0.4358,0.2708,0.3201,0.4347,0.1886,0.0845,0.2479,0.3289, +0.4157,0.2247,0.2826,0.4321,0.1874,0.1021,0.2427,0.3305, + +=== +name:SelfAttentionData_WithPast_WithRelPosBias_ForT5.present_key_data +0.3473,0.5592,0.5333,0.5122, +0.5941,0.4474,0.4313,0.5536, +0.5787,0.2951,0.2780,0.4694, +0.2809,0.1004,0.1588,0.4528, +0.3168,0.1101,0.2159,0.4975, + +0.4450,0.5307,0.3125,0.4274, +0.4437,0.5890,0.5054,0.4604, +0.5352,0.5158,0.3974,0.5442, +0.3988,0.1260,0.4199,-0.0651, +0.4368,0.2094,0.4407,-0.0560, + +=== +name:SelfAttentionData_WithPast_WithRelPosBias_ForT5.present_value_data +0.4900,0.5494,0.5566,0.7012, +0.5439,0.5631,0.5088,0.3901, +0.5312,0.4086,0.5320,0.5145, +0.2642,-0.1654,-0.0600,0.2720, +0.2796,-0.1664,-0.0702,0.2901, + +0.4086,0.6913,0.5005,0.5338, +0.5298,0.5244,0.6046,0.5356, +0.4494,0.6011,0.3803,0.4273, +-0.1075,-0.4493,-0.0369,0.1800, +-0.1164,-0.4788,-0.0198,0.1147, + +=== +name:AttentionDataCutlassRelPosBias.query_data +-0.029273793,0.079709493,0.064531095,0.24270254,-0.28326464,0.20984903,-0.10173888,0.18373983, + +0.089472905,-0.0063416883,-0.049477674,0.36512995,-0.23620239,0.1464397,0.068258412,0.31627196, + +0.12436871,-0.0075563118,-0.11576633,0.41008925,-0.19456652,0.20145792,0.11790096,0.39789933, + +0.002485469,0.029660821,-0.043821491,0.3892332,-0.26994205,0.14530671,0.12950704,0.36185294, + +-0.029273793,0.079709493,0.064531095,0.24270254,-0.28326464,0.20984903,-0.10173888,0.18373983, + +0.089472905,-0.0063416883,-0.049477674,0.36512995,-0.23620239,0.1464397,0.068258412,0.31627196, + +0.12436871,-0.0075563118,-0.11576633,0.41008925,-0.19456652,0.20145792,0.11790096,0.39789933, + +0.002485469,0.029660821,-0.043821491,0.3892332,-0.26994205,0.14530671,0.12950704,0.36185294, + +=== +name:AttentionDataCutlassRelPosBias.key_data +-0.32538497,0.34121913,-0.18170178,-0.015152611,0.20429322,0.25979176,0.21269324,0.0025638193, + +-0.24246037,0.21112341,-0.36959589,-0.16091451,0.24183474,0.18856162,0.094487116,-0.3053959, + +-0.35736683,0.29276621,-0.4217523,-0.20031664,0.33148992,0.26928401,0.19360018,-0.39494509, +-0.28043351,0.24279942,-0.29154932,-0.13657911,0.31932494,0.3500579,0.027172565,-0.19327414, +-0.32538497,0.34121913,-0.18170178,-0.015152611,0.20429322,0.25979176,0.21269324,0.0025638193, +-0.24246037,0.21112341,-0.36959589,-0.16091451,0.24183474,0.18856162,0.094487116,-0.3053959, +-0.35736683,0.29276621,-0.4217523,-0.20031664,0.33148992,0.26928401,0.19360018,-0.39494509, +-0.28043351,0.24279942,-0.29154932,-0.13657911,0.31932494,0.3500579,0.027172565,-0.19327414, +=== +name:AttentionDataCutlassRelPosBias.value_data +0.56916672,-0.2443777,0.47111356,-0.52134115,0.010381341,0.0696759,-0.071910433,-0.35201436, +0.70809275,-0.24479815,0.41633749,-0.34744334,-0.0044222325,0.25929695,-0.087832771,-0.281232, +0.90039468,-0.28931504,0.56394172,-0.43948689,-0.05856207,0.33713666,-0.10320446,-0.38833332, +0.76054728,-0.29080144,0.50414616,-0.42371163,-0.047198489,0.31959397,-0.22683662,-0.30321664, +0.56916672,-0.2443777,0.47111356,-0.52134115,0.010381341,0.0696759,-0.071910433,-0.35201436, +0.70809275,-0.24479815,0.41633749,-0.34744334,-0.0044222325,0.25929695,-0.087832771,-0.281232, +0.90039468,-0.28931504,0.56394172,-0.43948689,-0.05856207,0.33713666,-0.10320446,-0.38833332, +0.76054728,-0.29080144,0.50414616,-0.42371163,-0.047198489,0.31959397,-0.22683662,-0.30321664, +=== +name:AttentionDataCutlassRelPosBias.bias_data +-0.38124341,0.02696526,-0.11914945,-0.43795273, +0.04772711,-0.03419551,-0.30606642,0.42656231, +-0.25891554,0.13431972,0.22861153,0.06360734, +-0.10595283,-0.42839217,0.28931111,-0.13180739, +0.27079183,0.42074734,-0.40314156,-0.43726659, +-0.40546918,0.06927037,0.16979086,0.41458064, +=== +name:AttentionDataCutlassRelPosBias.rel_pos_bias_data +-10.808288,-10.887209,7.8799553,-4.6565766,-1.6700006,-0.033962168,7.4929152,10.944146,8.640254,-18.862164,-3.1202927,-6.3049207,3.4508536,11.722519,3.3550568,-5.4888172, +-2.0828252,-13.241742,2.9868939,1.4455698,-15.262972,-10.457437,-8.4519463,-4.4281874,10.212368,-0.28622282,12.087646,6.5218501,8.1785011,13.985523,-8.2068987,5.4260745, +-10.808288,-10.887209,7.8799553,-4.6565766,-1.6700006,-0.033962168,7.4929152,10.944146,8.640254,-18.862164,-3.1202927,-6.3049207,3.4508536,11.722519,3.3550568,-5.4888172, +-2.0828252,-13.241742,2.9868939,1.4455698,-15.262972,-10.457437,-8.4519463,-4.4281874,10.212368,-0.28622282,12.087646,6.5218501,8.1785011,13.985523,-8.2068987,5.4260745, +-10.808288,-10.887209,7.8799553,-4.6565766,-1.6700006,-0.033962168,7.4929152,10.944146,8.640254,-18.862164,-3.1202927,-6.3049207,3.4508536,11.722519,3.3550568,-5.4888172, +-2.0828252,-13.241742,2.9868939,1.4455698,-15.262972,-10.457437,-8.4519463,-4.4281874,10.212368,-0.28622282,12.087646,6.5218501,8.1785011,13.985523,-8.2068987,5.4260745, +-10.808288,-10.887209,7.8799553,-4.6565766,-1.6700006,-0.033962168,7.4929152,10.944146,8.640254,-18.862164,-3.1202927,-6.3049207,3.4508536,11.722519,3.3550568,-5.4888172, +-2.0828252,-13.241742,2.9868939,1.4455698,-15.262972,-10.457437,-8.4519463,-4.4281874,10.212368,-0.28622282,12.087646,6.5218501,8.1785011,13.985523,-8.2068987,5.4260745, +=== +name:AttentionDataCutlassRelPosBias.fp16_output_data +1.0419922,0.13000488,0.10528564,-0.86230469,-0.45336914,0.39013672,-0.048858643,0.10571289, +0.97265625,0.17590332,0.015625,-0.79248047,-0.40917969,0.31933594,0.082763672,0.12976074, +1.1455078,0.13134766,0.15014648,-0.87451172,-0.46142578,0.40161133,0.04309082,0.042663574, +1.0009766,0.17004395,0.033752441,-0.80078125,-0.41625977,0.33349609,0.080383301,0.11846924, +1.0419922,0.13000488,0.10528564,-0.86230469,-0.45336914,0.39013672,-0.048858643,0.10571289, +0.97265625,0.17590332,0.015625,-0.79248047,-0.40917969,0.31933594,0.082763672,0.12976074, +1.1455078,0.13134766,0.15014648,-0.87451172,-0.46142578,0.40161133,0.04309082,0.042663574, +1.0009766,0.17004395,0.033752441,-0.80078125,-0.41625977,0.33349609,0.080383301,0.11846924, +=== +name:CrossAttentionData_DiffSequenceLengths.query_data +0.19646919,-0.21386067,-0.27314855,0.05131477,0.21946897,-0.07689354,0.4807642,0.18482974,-0.0190681,-0.10788248,-0.15682198,0.22904971,-0.06142776,-0.4403221,-0.10195574,0.23799541, +-0.31750827,-0.32454824,0.03155137,0.03182759,0.13440096,0.34943179,0.22445532,0.11102351,0.22244338,-0.17704109,-0.13821134,-0.27173677,-0.20628595,0.13097612,-0.40789506,-0.06629883, +=== +name:CrossAttentionData_DiffSequenceLengths.key_data +-0.06913724,-0.0063149,-0.07416971,-0.18773878,-0.07364869,0.39338916,0.44416002,0.00183668,0.12395295,-0.3843816,-0.18271452,-0.08517379,0.36630916,-0.24954463,-0.01696574,0.48555979, +0.01948512,0.11289453,-0.37937133,0.3263408,0.10306013,0.04506801,-0.15723617,-0.19587921,-0.08297779,0.18130077,0.37545684,0.01042234,0.16931378,0.08593655,0.1249035,0.17468905, +0.34234244,-0.41680501,0.26368284,-0.25633363,-0.30577704,0.07245696,-0.40428748,0.38532683,0.12724897,0.22341636,-0.48387079,0.09443188,0.05678519,-0.34104036,-0.34692948,0.19552953, +-0.18123357,0.1919703,0.05438325,-0.11104943,0.42513249,0.34167,-0.14260243,-0.45640854,-0.19523193,-0.10181432,0.20495883,0.49535848,-0.14408513,0.26254781,0.09317692,0.1917018, +=== +name:CrossAttentionData_DiffSequenceLengths.value_data +-0.34887255,-0.10112371,-0.2591441,-0.15654399,0.01312815,0.16662455,-0.39409151,-0.36910505,-0.17801939,0.16156434,0.34650623,0.05325734,0.35445249,-0.11516219,-0.1832121,-0.14573532, +-0.32891817,0.32911263,-0.16132915,0.05237008,0.07855147,0.02153306,-0.49731194,0.48834542,0.40534158,-0.29236414,-0.20751059,0.02001015,0.40191137,0.48363088,-0.24245794,0.06435904, +0.30696868,-0.10562995,0.23107304,-0.33893099,0.10069857,0.36586446,0.48352161,-0.42063421,-0.07165273,-0.29545714,-0.04936351,0.04776357,-0.40667329,-0.20313922,0.42758424,0.06900373, +-0.042588,0.25352599,0.24186215,-0.45142097,0.2086974,0.33924335,-0.33406212,0.28099794,-0.21346338,-0.19353025,0.16526147,-0.38860783,0.16487245,0.38785679,0.19631127,-0.05967212, +=== +name:CrossAttentionData_DiffSequenceLengths.bias_data +-0.06178562,0.2650961,0.065642,-0.41509584,0.08267109,0.3148437,-0.16293362,0.42757658,0.250717,0.07406383,0.25164399,-0.42085104,0.35938908,0.32150411,0.40987166,-0.3713688,-0.41821991,-0.36158443,-0.10062129,-0.07569314,0.06221838,-0.37775645,-0.2986005,0.31164435, +=== +name:CrossAttentionData_DiffSequenceLengths.fp32_output_data +-0.53803939,-0.33528122,-0.16753256,-0.084826469,0.28213754,-0.23802593,-0.61857146,0.29926175,-0.53170669,-0.33900675,-0.17392565,-0.084655531,0.28832543,-0.24704586,-0.61680299,0.31617802, +-0.41967732,-0.43735462,0.051356006,-0.36559904,0.093453586,-0.13974363,-0.10689265,0.27119368,-0.40707609,-0.44006824,0.048184391,-0.35585383,0.081379525,-0.14954941,-0.086910933,0.25871021, +=== +name:CrossAttentionData_DiffSequenceLengths.present_key_data +0.18157977,0.067748934,0.17747428,-0.60858983,0.37466997,-0.31031775,0.068929464,-0.50602484,0.27020213,0.18695836,-0.12772733,-0.094510257,0.16773923,0.2553646,0.62710083,-0.4104287, +0.28574038,0.71489328,0.85403168,-0.36953211,0.72569823,0.071959481,0.39290592,0.114191,0.46244919,0.36657214,0.25263548,-0.56724799,0.52870286,0.40744066,0.53477514,-0.19667974, +0.59305942,-0.34274116,0.51532686,-0.6771847,0.37796599,0.2974802,-0.23222682,-0.32641917,0.069483444,0.26603413,0.30602723,-0.53190047,0.055485085,-0.027750492,0.45660281,0.074507415, +0.053612024,0.39396107,0.0055841804,0.013958037,0.41617426,-0.019536257,0.062942177,-0.17583926,0.78452158,0.66317415,0.26726925,-0.82777733,0.21530394,0.58405197,0.5030486,-0.179667, +=== +name:CrossAttentionData_DiffSequenceLengths.present_value_data +-0.76709247,-0.46270815,-0.35976538,-0.23223713,-0.59623933,-0.20002009,0.24588495,-0.022435799,-0.74713808,-0.032471806,-0.26195043,-0.023323059,-0.012878358,-0.65394855,-0.30813187,-0.055682987, +0.075346529,-0.2111319,-0.69269204,-0.057460696,0.41667086,-0.49291864,-0.4818126,0.16590902,0.14076985,-0.35622337,-0.79591244,0.79998976,0.46412975,0.10587442,-0.54105842,0.37600338, +-0.11125124,-0.46721438,0.13045174,-0.41462412,-0.48987266,-0.65704155,-0.14998481,-0.027929567,-0.46080792,-0.10805842,0.14124086,-0.52711409,-0.63168329,-0.55511469,0.064640187,-0.46430096, +0.16291694,-0.011891991,0.18492112,-0.10898986,-0.34445491,-0.58089566,0.12898374,0.38064808,0.27091578,-0.038513094,-0.63266265,0.59264231,0.22709084,0.010100335,-0.10228923,0.25197223, +=== +name:CrossAttentionData_DiffSequenceLengths_HeadSize8.query_data +0.74714613,-2.49789214,-0.11628322,1.33038604,0.82568336,0.07685500,2.47562003,2.61135578, +1.55278158,-1.85635769,0.36962336,0.87219834,0.69827259,0.95257485,-0.77894646,1.46218395, +1.29534733,2.14051294,1.09895217,1.39164531,-0.01471180,-1.40148544,-0.50825417,0.26134527, +-0.70491123,0.63738143,2.13708138,0.05667466,-0.44220763,0.85254443,2.00844359,-1.23413038, + +=== +name:CrossAttentionData_DiffSequenceLengths_HeadSize8.key_data +1.70455408,0.07344571,0.18893155,-1.48390186,-0.86155319,0.10993601,-0.29869685,0.73800445, +0.94670546,-1.36712539,-0.41328859,0.88237023,1.62447476,0.80396229,-1.38206959,1.62546301, +-1.61546838,-0.56213129,-0.23501799,0.89255226,-1.95987988,0.85192877,-0.06520678,-1.32849765, +2.07457638,-0.08192353,-2.03260493,0.58190948,2.22535419,-0.60754669,1.14538383,0.22928622, +-0.11596665,-0.57144678,-0.23428933,-0.68404931,-1.46875453,1.32763886,0.28525546,-0.11347114, +1.63199806,-1.44967401,-2.54707336,0.78083873,-0.19109090,0.59508920,0.58886564,0.81380880, +0.54458785,0.21354041,0.03592521,0.27506533,-0.87245977,0.65083951,0.32723498,-0.48263270, +1.54926634,-0.49424326,0.65303659,1.03355420,1.36284590,0.78218406,-1.22659552,2.27737451, + +=== +name:CrossAttentionData_DiffSequenceLengths_HeadSize8.value_data +0.20429733,-0.57036293,0.22116289,0.07601038,1.79898310,0.62182522,0.48815370,-1.59284389, +0.33195397,0.34822315,0.54315579,1.06468117,1.34500551,-0.09528533,-1.30459058,-0.07034321, +-1.34877563,1.58868146,-1.44948101,0.74792957,0.91922742,-0.56811053,0.59939134,-1.10749292, +1.36371183,-0.89673072,-0.28341034,0.93497890,1.62986696,-0.83026254,-0.20963377,-2.14284325, +-0.95242530,0.37379366,1.17815948,-0.55676895,0.74420613,0.58715403,-0.43127203,0.62706453, +0.50881875,2.14387321,0.85787302,2.32273459,-0.04902139,-0.04061748,1.55004728,-0.25090796, +-1.05647933,-0.87152874,0.70491379,-0.44258183,0.26371828,1.58179390,0.02976498,0.20476237, +1.20772719,-0.99407929,-0.15339416,0.54562038,1.29705775,-0.28651321,-0.90150839,-1.09473300, + +=== +name:CrossAttentionData_DiffSequenceLengths_HeadSize8.bias_data +-0.38124341,0.02696526,-0.11914945,-0.43795273,-0.34948170,-0.19608477,0.19725692,0.39987487, +0.04772711,-0.03419551,-0.30606642,0.42656231,-0.23178342,-0.13692456,-0.04889601,0.48739988, +0.27079183,0.42074734,-0.40314156,-0.43726659,0.27376485,-0.38174152,-0.43700469,0.38040614, +-0.40546918,0.06927037,0.16979086,0.41458064,0.07120579,-0.08055863,0.12095112,-0.27988660, +-0.10567203,0.26791072,-0.08976898,0.31341976,0.06027532,0.14307594,0.31587386,0.16180152, +0.34785229,0.00531715,-0.35168743,-0.11641458,0.39196932,0.44535065,0.43545735,0.15593112, + +=== +name:CrossAttentionData_DiffSequenceLengths_HeadSize8.fp32_output_data +-0.73531479,0.17652693,0.43294340,0.10832195,1.06569219,0.84791648,0.37950000,-0.19036117, +1.14446115,-0.09822676,-0.12345937,0.85349751,1.55650973,0.24238834,-0.30006421,-0.48439008, + +-0.55764329,-0.13255559,0.21757828,0.22631887,1.18009710,0.97638327,0.58746934,-0.60751349, +1.29570508,-0.01765576,-0.19382195,1.03120971,1.47274101,0.09958147,0.22852209,-0.86264789, +=== +name:CrossAttentionData_DiffSequenceLengths_HeadSize8.present_key_data +1.97534585,0.49419305,-0.21421000,-1.92116845,-0.58778834,-0.27180552,-0.73570156,1.11841059, +-1.34467649,-0.14138395,-0.63815951,0.45528567,-1.68611503,0.47018725,-0.50221145,-0.94809151, +0.15482518,-0.15069944,-0.63743091,-1.12131596,-1.19498968,0.94589734,-0.15174922,0.26693499, +0.81537968,0.63428771,-0.36721635,-0.16220126,-0.59869492,0.26909798,-0.10976970,-0.10222656, + +0.54123628,-1.29785502,-0.24349773,1.29695082,1.69568062,0.72340369,-1.26111841,1.34557641, +1.66910720,-0.01265316,-1.86281407,0.99649012,2.29656005,-0.68810534,1.26633501,-0.05060038, +1.22652888,-1.38040364,-2.37728262,1.19541931,-0.11988510,0.51453054,0.70981675,0.53392220, +1.14379716,-0.42497289,0.82282746,1.44813490,1.43405175,0.70162547,-1.10564446,1.99748790, + +=== +name:CrossAttentionData_DiffSequenceLengths_HeadSize8.present_value_data +0.09862530,-0.30245221,0.13139391,0.38943014,1.85925841,0.76490116,0.80402756,-1.43104243, +-1.45444763,1.85659218,-1.53925002,1.06134939,0.97950274,-0.42503458,0.91526520,-0.94569141, +-1.05809736,0.64170438,1.08839047,-0.24334919,0.80448145,0.73022997,-0.11539817,0.78886604, +-1.16215134,-0.60361803,0.61514485,-0.12916207,0.32399359,1.72486985,0.34563884,0.36656389, + +0.67980623,0.35354030,0.19146836,0.94826663,1.73697484,0.35006532,-0.86913323,0.08558790, +1.71156406,-0.89141357,-0.63509774,0.81856430,2.02183628,-0.38491189,0.22582358,-1.98691213, +0.85667104,2.14919043,0.50618559,2.20632005,0.34294793,0.40473318,1.98550463,-0.09497684, +1.55557942,-0.98876214,-0.50508159,0.42920581,1.68902707,0.15883744,-0.46605104,-0.93880188, + +=== +name:CrossAttentionData_DiffSequenceLengths_HeadSize8_NoBias.fp32_output_data +-0.65824336,-0.13227919,0.50652772,-0.20617434,0.96178705,0.75033671,0.07374202,-0.33853477, +0.79871416,-0.14487229,0.21765450,0.94517386,1.19351113,-0.20844331,-0.78461820,-0.64874089, + +-0.51557893,-0.43041292,0.32726392,-0.11220890,1.03794634,0.89304829,0.25361922,-0.68402284, +0.98060286,-0.14295936,0.11289610,1.09369516,1.15080333,-0.37929729,-0.27804646,-1.09627187, + +=== +name:CrossAttentionData_DiffSequenceLengths_HeadSize8_NoBias.present_key_data +1.70455408,0.07344571,0.18893155,-1.48390186,-0.86155319,0.10993601,-0.29869685,0.73800445, +-1.61546838,-0.56213129,-0.23501799,0.89255226,-1.95987988,0.85192877,-0.06520678,-1.32849765, +-0.11596665,-0.57144678,-0.23428933,-0.68404931,-1.46875453,1.32763886,0.28525546,-0.11347114, +0.54458785,0.21354041,0.03592521,0.27506533,-0.87245977,0.65083951,0.32723498,-0.48263270, + +0.94670546,-1.36712539,-0.41328859,0.88237023,1.62447476,0.80396229,-1.38206959,1.62546301, +2.07457638,-0.08192353,-2.03260493,0.58190948,2.22535419,-0.60754669,1.14538383,0.22928622, +1.63199806,-1.44967401,-2.54707336,0.78083873,-0.19109090,0.59508920,0.58886564,0.81380880, +1.54926634,-0.49424326,0.65303659,1.03355420,1.36284590,0.78218406,-1.22659552,2.27737451, + +=== +name:CrossAttentionData_DiffSequenceLengths_HeadSize8_NoBias.present_value_data +0.20429733,-0.57036293,0.22116289,0.07601038,1.79898310,0.62182522,0.48815370,-1.59284389, +-1.34877563,1.58868146,-1.44948101,0.74792957,0.91922742,-0.56811053,0.59939134,-1.10749292, +-0.95242530,0.37379366,1.17815948,-0.55676895,0.74420613,0.58715403,-0.43127203,0.62706453, +-1.05647933,-0.87152874,0.70491379,-0.44258183,0.26371828,1.58179390,0.02976498,0.20476237, + +0.33195397,0.34822315,0.54315579,1.06468117,1.34500551,-0.09528533,-1.30459058,-0.07034321, +1.36371183,-0.89673072,-0.28341034,0.93497890,1.62986696,-0.83026254,-0.20963377,-2.14284325, +0.50881875,2.14387321,0.85787302,2.32273459,-0.04902139,-0.04061748,1.55004728,-0.25090796, +1.20772719,-0.99407929,-0.15339416,0.54562038,1.29705775,-0.28651321,-0.90150839,-1.09473300, + +=== +name:SelfAttentionData_WithPastAndPresent_NoMask_NoRelPosBias.query_data +0.19646919,-0.21386067,-0.27314855,0.05131477,0.21946897,-0.07689354,0.4807642,0.18482974,-0.0190681,-0.10788248,-0.15682198,0.22904971,-0.06142776,-0.4403221,-0.10195574,0.23799541, +=== +name:SelfAttentionData_WithPastAndPresent_NoMask_NoRelPosBias.key_data +-0.31750827,-0.32454824,0.03155137,0.03182759,0.13440096,0.34943179,0.22445532,0.11102351,0.22244338,-0.17704109,-0.13821134,-0.27173677,-0.20628595,0.13097612,-0.40789506,-0.06629883, +=== +name:SelfAttentionData_WithPastAndPresent_NoMask_NoRelPosBias.value_data +-0.06913724,-0.0063149,-0.07416971,-0.18773878,-0.07364869,0.39338916,0.44416002,0.00183668,0.12395295,-0.3843816,-0.18271452,-0.08517379,0.36630916,-0.24954463,-0.01696574,0.48555979, +=== +name:SelfAttentionData_WithPastAndPresent_NoMask_NoRelPosBias.bias_data +0.01948512,0.11289453,-0.37937133,0.3263408,0.10306013,0.04506801,-0.15723617,-0.19587921,-0.08297779,0.18130077,0.37545684,0.01042234,0.16931378,0.08593655,0.1249035,0.17468905,0.34234244,-0.41680501,0.26368284,-0.25633363,-0.30577704,0.07245696,-0.40428748,0.38532683, +=== +name:SelfAttentionData_WithPastAndPresent_NoMask_NoRelPosBias.past_key_data +0.12724897,0.22341636,-0.48387079,0.09443188,0.05678519,-0.34104036,-0.34692948,0.19552953,-0.18123357,0.1919703,0.05438325,-0.11104943,0.42513249,0.34167,-0.14260243,-0.45640854, +=== +name:SelfAttentionData_WithPastAndPresent_NoMask_NoRelPosBias.past_value_data +-0.19523193,-0.10181432,0.20495883,0.49535848,-0.14408513,0.26254781,0.09317692,0.1917018,-0.34887255,-0.10112371,-0.2591441,-0.15654399,0.01312815,0.16662455,-0.39409151,-0.36910505, +=== +name:SelfAttentionData_WithPastAndPresent_NoMask_NoRelPosBias.fp32_output_data +-0.00033577532,-0.23549549,0.19853255,0.10450245,-0.26995566,0.37128073,0.064667389,0.29624334,0.040147364,-0.43521237,-0.096833363,-0.24481347,0.037364807,-0.0091082826,-0.40797871,0.26487666, +=== +name:SelfAttentionData_WithPastAndPresent_NoMask_NoRelPosBias.present_key_data +0.12724897,0.22341636,-0.4838708,0.094431877,-0.40048605,-0.14324747,0.4070082,0.042249933, +0.056785189,-0.34104037,-0.34692949,0.19552954,0.30371475,0.43536833,0.34935883,0.28571257, +-0.18123357,0.1919703,0.054383252,-0.11104943,0.1394656,0.0042596906,0.2372455,-0.26131442, +0.42513248,0.34167001,-0.14260243,-0.45640853,-0.03697218,0.21691267,-0.28299156,0.10839023, +=== +name:SelfAttentionData_WithPastAndPresent_NoMask_NoRelPosBias.present_value_data +-0.19523193,-0.10181432,0.20495883,0.49535847,0.27320519,-0.4231199,0.18951313,-0.4440724, +-0.14408512,0.26254782,0.093176924,0.1917018,-0.37942573,0.46584612,0.039872527,0.38716352, +-0.34887254,-0.10112371,-0.2591441,-0.15654399,0.46629539,-0.80118656,0.08096832,-0.34150741, +0.01312815,0.16662455,-0.39409152,-0.36910504,0.060532123,-0.17708766,-0.42125323,0.87088662, +=== +name:SelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias.query_data +1.29534733,2.14051294,1.09895217,1.39164531,-0.01471180,-1.40148544,-0.50825417,0.26134527, +-0.70491123,0.63738143,2.13708138,0.05667466,-0.44220763,0.85254443,2.00844359,-1.23413038, +-0.08030051,-1.25450790,-0.89664006,-0.69433510,0.20943037,1.41880298,1.42875051,0.79920006, +1.57896936,-1.13204634,-0.61002654,0.43365243,0.22888106,-0.38688308,-0.45924744,0.99473029, + +=== +name:SelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias.key_data +0.37680483,0.15317714,0.05767500,0.37780648,-2.27755547,0.89294612,-0.85582626,0.54963046, +1.67390800,-1.06330085,-2.99566054,0.68927419,1.66056263,-0.77022851,0.15417719,0.94860524, +-1.84928346,-0.52135336,0.70491475,0.37400877,0.55338752,0.52915680,0.52876079,-0.55780333, +-1.49814773,0.18675917,0.31246936,-1.32707596,0.42132780,-1.69121027,0.20342645,-0.34370381, + +=== +name:SelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias.value_data +0.60890561,-0.88021755,1.63002241,0.86171651,1.80559230,1.26110435,-0.97890180,-1.60215497, +-0.79229754,1.07830989,-0.85298145,2.76264572,0.01659799,-1.49499071,0.85316724,-2.56763911, +0.53017867,1.31909978,-1.10940945,0.68858552,-1.07115889,-2.34016919,0.48310637,-0.05351824, +-0.08850761,-0.56362265,0.05224326,-2.47377181,0.44249821,-0.10389519,-0.46113095,2.81619215, + +=== +name:SelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias.bias_data +-0.38124341,0.02696526,-0.11914945,-0.43795273,-0.34948170,-0.19608477,0.19725692,0.39987487, +0.04772711,-0.03419551,-0.30606642,0.42656231,-0.23178342,-0.13692456,-0.04889601,0.48739988, +0.27079183,0.42074734,-0.40314156,-0.43726659,0.27376485,-0.38174152,-0.43700469,0.38040614, +-0.40546918,0.06927037,0.16979086,0.41458064,0.07120579,-0.08055863,0.12095112,-0.27988660, +-0.10567203,0.26791072,-0.08976898,0.31341976,0.06027532,0.14307594,0.31587386,0.16180152, +0.34785229,0.00531715,-0.35168743,-0.11641458,0.39196932,0.44535065,0.43545735,0.15593112, + +=== +name:SelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias.past_key_data +-1.00657940,-0.46509427,-1.65118766,-0.17705369,1.71204090,0.53921354,-1.67056096,0.42517155, +-2.00129080,1.26244307,0.28864837,1.38792157,-0.59647840,-1.18904924,0.58950418,-2.26774645, +1.88496518,0.59231639,0.33360308,-1.23532701,0.10543400,-1.77481365,-0.79397631,-0.22495472, +-0.26800078,-0.20456636,1.43141091,1.55566478,-0.22702518,1.75312757,-1.29037595,-0.95538902, + +=== +name:SelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias.past_value_data +3.18056512,0.13370860,-2.20253444,2.30826044,0.86762893,-1.91499686,2.18277764,0.53384149, +-0.43230706,0.49148068,-0.29957789,-3.56583714,-1.46747136,-0.40299624,1.78018796,2.84104395, +-0.68692255,1.25688624,-0.42734757,-1.03185725,0.47858545,1.18466282,-1.06095874,-0.63918531, +1.41408277,0.74389833,0.89590931,1.06388271,1.29734015,0.42640167,-0.99740052,-2.79366398, + +=== +name:SelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias.fp32_output_data +0.72723210,-0.54989153,1.22711349,1.26993895,1.78235006,1.12648177,-0.42493403,-1.27518260, +-0.43240935,0.49647018,-0.30720428,-3.51349354,-1.45166361,-0.40844491,1.77604592,2.79678369, +0.25752395,1.53741217,-1.08321750,0.69643497,-0.78710371,-1.68901348,0.51954043,-0.00401744, +1.11207914,0.40332735,0.58328331,0.10821819,1.17628312,0.40418532,-0.74326056,-1.28571272, + +=== +name:SelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias.present_key_data +-1.00657940,-0.46509427,-1.65118766,-0.17705369,1.71204090,0.53921354,-1.67056096,0.42517155, +0.64759666,0.57392448,-0.34546655,-0.05946010,-2.00379062,0.51120460,-1.29283094,0.93003660, +-2.00129080,1.26244307,0.28864837,1.38792157,-0.59647840,-1.18904924,0.58950418,-2.26774645, +1.26843882,-0.99403048,-2.82586956,1.10385489,1.73176837,-0.85078716,0.27512830,0.66871864, +1.88496518,0.59231639,0.33360308,-1.23532701,0.10543400,-1.77481365,-0.79397631,-0.22495472, +-1.57849169,-0.10060602,0.30177319,-0.06325781,0.82715237,0.14741528,0.09175611,-0.17739719, +-0.26800078,-0.20456636,1.43141091,1.55566478,-0.22702518,1.75312757,-1.29037595,-0.95538902, +-1.90361691,0.25602955,0.48226023,-0.91249532,0.49253359,-1.77176893,0.32437757,-0.62359041, + +=== +name:SelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias.present_value_data +3.18056512,0.13370860,-2.20253444,2.30826044,0.86762893,-1.91499686,2.18277764,0.53384149, +0.50323355,-0.61230683,1.54025340,1.17513633,1.86586761,1.40418029,-0.66302794,-1.44035339, +-0.43230706,0.49148068,-0.29957789,-3.56583714,-1.46747136,-0.40299624,1.78018796,2.84104395, +-0.44444525,1.08362699,-1.20466888,2.64623117,0.40856731,-1.04964006,1.28862453,-2.41170788, +-0.68692255,1.25688624,-0.42734757,-1.03185725,0.47858545,1.18466282,-1.06095874,-0.63918531, +0.42450663,1.58701050,-1.19917846,1.00200534,-1.01088357,-2.19709325,0.79898024,0.10828328, +1.41408277,0.74389833,0.89590931,1.06388271,1.29734015,0.42640167,-0.99740052,-2.79366398, +0.25934470,-0.55830550,-0.29944417,-2.59018636,0.83446753,0.34145546,-0.02567360,2.97212315, + +=== +name:SelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias_NoBias.past_key_data +-1.27737117,-0.88584161,-1.24804604,0.26021290,1.43827605,0.92095506,-1.23355627,0.04476542, +-1.59582162,1.19317269,0.11885749,0.97334087,-0.66768420,-1.10849059,0.46855307,-1.98785996, +1.61417341,0.17156902,0.73674464,-0.79806042,-0.16833085,-1.39307213,-0.35697165,-0.60536087, +0.13746840,-0.27383673,1.26162004,1.14108407,-0.29823098,1.83368623,-1.41132712,-0.67550242, + +=== +name:SelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias_NoBias.past_value_data +3.28623724,-0.13420212,-2.11276555,1.99484074,0.80735362,-2.05807281,1.86690378,0.37204000, +-0.78015935,0.48616353,0.05210955,-3.44942260,-1.85944068,-0.84834689,1.34473062,2.68511271, +-0.58125055,0.98897558,-0.33757859,-1.34527707,0.41831014,1.04158688,-1.37683260,-0.80098683, +1.06623054,0.73858118,1.24759674,1.18029726,0.90537083,-0.01894896,-1.43285787,-2.94959521, + +=== +name:SelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias_NoBias.fp32_output_data +0.89556247,-0.80034304,1.22928894,0.98303795,1.69871271,0.90572613,-0.67420667,-1.39078152, +-0.78021139,0.48869953,0.04823331,-3.42281842,-1.85140634,-0.85111630,1.34262550,2.66261697, +0.34449580,1.26394701,-0.98046219,0.34879467,-0.82231814,-1.77519011,0.17237240,-0.17839541, +0.72679031,0.35579273,0.89621741,0.10616791,0.76930743,-0.04391927,-1.14721453,-1.25471735, + +=== +name:SelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias_NoBias.present_key_data +-1.27737117,-0.88584161,-1.24804604,0.26021290,1.43827605,0.92095506,-1.23355627,0.04476542, +0.37680483,0.15317714,0.05767500,0.37780648,-2.27755547,0.89294612,-0.85582626,0.54963046, +-1.59582162,1.19317269,0.11885749,0.97334087,-0.66768420,-1.10849059,0.46855307,-1.98785996, +1.67390800,-1.06330085,-2.99566054,0.68927419,1.66056263,-0.77022851,0.15417719,0.94860524, +1.61417341,0.17156902,0.73674464,-0.79806042,-0.16833085,-1.39307213,-0.35697165,-0.60536087, +-1.84928346,-0.52135336,0.70491475,0.37400877,0.55338752,0.52915680,0.52876079,-0.55780333, +0.13746840,-0.27383673,1.26162004,1.14108407,-0.29823098,1.83368623,-1.41132712,-0.67550242, +-1.49814773,0.18675917,0.31246936,-1.32707596,0.42132780,-1.69121027,0.20342645,-0.34370381, + +=== +name:SelfAttentionData_WithPastAndPresent_HeadSize8_NoMask_NoRelPosBias_NoBias.present_value_data +3.28623724,-0.13420212,-2.11276555,1.99484074,0.80735362,-2.05807281,1.86690378,0.37204000, +0.60890561,-0.88021755,1.63002241,0.86171651,1.80559230,1.26110435,-0.97890180,-1.60215497, +-0.78015935,0.48616353,0.05210955,-3.44942260,-1.85944068,-0.84834689,1.34473062,2.68511271, +-0.79229754,1.07830989,-0.85298145,2.76264572,0.01659799,-1.49499071,0.85316724,-2.56763911, +-0.58125055,0.98897558,-0.33757859,-1.34527707,0.41831014,1.04158688,-1.37683260,-0.80098683, +0.53017867,1.31909978,-1.10940945,0.68858552,-1.07115889,-2.34016919,0.48310637,-0.05351824, +1.06623054,0.73858118,1.24759674,1.18029726,0.90537083,-0.01894896,-1.43285787,-2.94959521, +-0.08850761,-0.56362265,0.05224326,-2.47377181,0.44249821,-0.10389519,-0.46113095,2.81619215, + +=== +name:CrossAttentionData_WithPastPassedInDirectly_NoMask.query_data +-0.10939738,-0.11916742,-0.23157823,-0.12894472, +-0.02661306,0.26251313,0.30725253,-0.34759378, +-0.11695808,-0.13129434,-0.17031054,-0.14986445, +-0.02826184,0.2797631,0.27337456,-0.44312602, + +=== +name:CrossAttentionData_WithPastPassedInDirectly_NoMask.past_key_data +0.5967375,0.5966938,0.48602432,0.5341031, +0.55797786,0.5663399,0.57087725,0.6240304, +0.5352563,0.5648297,0.4972945,0.56637144, + +0.44123724,0.35872823,0.32176313,0.4490301, +0.3643952,0.51968557,0.50137347,0.5743993, +0.3905106,0.4741712,0.40881708,0.47243845, + +=== +name:CrossAttentionData_WithPastPassedInDirectly_NoMask.past_value_data +0.40251260,0.55487730,0.49565578,0.42683450, +0.44379145,0.58945787,0.54852820,0.43376005, +0.44116694,0.44007313,0.40293324,0.53202707, + +0.35520583,0.47293650,0.45417705,0.33723440, +0.50175804,0.37620395,0.24103148,0.50958070, +0.56803876,0.37866923,0.32273075,0.44389135, + +=== +name:CrossAttentionData_WithPastPassedInDirectly_NoMask.fp32_output_data +0.44753647,0.52339733,0.46447957,0.46852112,0.44769368,0.5231511,0.464194,0.46851689, +0.43687066,0.3954815,0.37647754,0.44443309,0.43690678,0.39541441,0.37764412,0.44382966, + +=== +name:Causal_EmptyPastState.input_data +0.00838,0.007523,-0.00872,0.002882,-0.003567,0.000859,-0.002821,0.000563,0.007675,-0.002758, +0.000947,0.001149,-0.001534,0.0006075,0.002853,0.004517,0.00825,0.003687,-0.002161,0.001167, +0.005913,0.00394,-0.002136,0.00946,0.000461,-0.003593,-0.002377,-0.001609,-0.006363,0.0013485, +-0.006706,-0.005188,0.002165,0.006073,0.007717,-0.007675,0.000827,0.004253,0.00697,-0.0035, +-0.00301,0.006565,-0.0002068,-0.004593,0.00198,0.00107,-0.003082,0.002243,0.00983,0.00608, +0.001682,0.001701,-0.006935,0.004765,-0.002333,0.003805,-0.00905,0.00599,0.00998,-0.001602, +0.00744,-0.008514,0.005424,-0.002413,0.00862,0.00459,-0.002516,0.00283,-0.00272,-0.005207, +-0.00738,-0.005386,-0.00951,0.008415,0.002865,-0.00726,0.00494,0.002226,0.0000424,-0.007507, +0.002193,-0.004482,0.002386,0.005997,-0.001786,0.009,0.006435,-0.0067,-0.001984,0.001514, +-0.004917,0.003468,-0.0013685,-0.007122,0.00788,0.000825,0.00621,-0.00437,0.005653,0.009674, +0.003576,0.00956,0.0064,0.00283,-0.00797,0.00867,0.004536,-0.00985,0.004856,-0.006878, +0.006012,-0.0042,-0.00328,-0.00885,-0.0079,0.004917,-0.00594,0.003452,-0.006355,-0.003536, +0.0022,0.003494,-0.008865,0.00461,-0.00485,0.00889,-0.002272,0.00596, + +=== +name:Causal_EmptyPastState.output_data +0.0027942657,0.0067901611,0.0070953369,-0.0020713806,0.0055351257,0.0030479431,-0.0060462952, +-0.0087127686,0.0030956268,-0.00036644936,0.0014686584,-0.0038146973,0.0072097778,-0.0052490234, +0.0056114197,0.0050926208,0.0080947876,0.0074501038,0.0079498291,0.0098876953,-0.0066146851, +0.0064735413,0.0093307495,-0.00051593781,-0.0047683716,-0.0069198608,0.0094604492,0.0066146851, +-0.0040054321,0.0017976761,-0.0058059692,-0.0087051392,0.0054740906,0.0022010803,0.0075340271, +0.0047035217,0.00340271,0.0096969604,-0.0016756058,0.0020771027,-0.0063018799,0.0073280334, +-0.0056381226,0.004032135,-0.0082473755,0.0045280457,0.0045814514,-0.0026607513,-0.0031585693, +-0.003660202,-0.0053253174,-0.0089187622,-0.0073509216,0.0048408508,0.0058364868,0.0069313049, +-0.0071868896,0.008392334,-0.0018663406,-0.0092163086,-0.00048780441,-0.0054283142,-0.0061683655, +0.0078048706,0.0025291443,0.0065917969,0.0072250366,-0.0018520355,0.005531311,0.003118515, +-0.0061264038,-0.0090484619,0.003276825,-0.00047063828,0.0015802383,-0.0037345886,0.0069732666, +-0.0054092407,0.0052947998,0.004940033,0.0085220337,0.007194519,0.0078659058,0.0095214844, +-0.0065574646,0.0064315796,0.0093383789,-0.00058555603,-0.0046386719,-0.0067710876,0.0096130371, +0.0064315796,-0.0040740967,0.0017337799,-0.0057067871,-0.008682251,0.0054855347,0.0019645691, +0.0075149536,0.0047187805,0.0036354065,0.0096282959,-0.0019168854,0.0021934509,-0.0063018799, +0.0072937012,-0.006187439,0.0039825439,-0.0081253052,0.0046577454,0.0045700073,-0.0028266907, +-0.0028438568,-0.0035438538,-0.0053100586,-0.0090332031,-0.0071105957,0.004699707,0.0058021545, +0.0071411133,-0.0071678162,0.0085449219,-0.0018749237,-0.0095825195,-0.00049686432,-0.0053634644, +-0.0057945251,0.0078277588, + +=== +name:Causal_EmptyPastState.present_data +0.0070152283,-0.0049858093,-0.0029277802,0.0078277588,-0.001991272,-0.0010290146,-0.0084457397, +-0.0028400421,0.0048294067,0.0012731552,0.0047149658,0.0069084167,0.0027809143,0.0014457703, +-0.0010128021,-0.0011024475,8.4400177e-05,-0.0049972534,-0.0040206909,0.002073288,-0.0034713745, +-0.0087203979,-0.0047302246,-0.0023326874,-0.0063209534,-0.0031681061,-0.006942749,0.0064888, +0.0014505386,-0.0037765503,0.0067138672,-0.0018196106, +0.0064506531,-0.0049514771,-0.0036487579,0.0081558228,-0.0024414062,-0.0014820099,-0.0086212158, +-0.0025672913,0.0047111511,0.0011997223,0.0042953491,0.0067138672,0.0028495789,0.0015869141, +-0.00037360191,-0.0012044907,0.00029373169,-0.005065918,-0.0038700104,0.0014038086,-0.0030422211, +-0.0084838867,-0.004863739,-0.0028686523,-0.0063362122,-0.0034809113,-0.0075874329,0.0066947937, +0.0019130707,-0.0036792755,0.0070266724,-0.0016460419, + +-0.003238678,-0.0066452026,0.0043983459,-0.0016002655,0.0045623779,0.0065002441,-0.0072174072, +-0.0050315857,0.0087356567,0.0061645508,0.0069580078,-0.003320694,-0.0087814331,0.0062255859, +0.0035037994,0.00064849854,-0.0018444061,0.0043945312,0.01008606,-0.0089874268,-0.0087585449, +0.0020160675,0.00207901,-0.0097732544,-0.0042991638,0.0070266724,-0.0028743744,0.0087051392, +0.0099868774,0.0076217651,-0.0027103424,-0.006439209, +-0.0033836365,-0.0063171387,0.0043144226,-0.001707077,0.0044555664,0.0069885254,-0.0072593689, +-0.0050468445,0.008895874,0.0050582886,0.0064926147,-0.0030384064,-0.0083618164,0.0065307617, +0.0038928986,0.0005645752,-0.0024528503,0.0043983459,0.0099029541,-0.0088043213,-0.0081558228, +0.0021705627,0.0018062592,-0.0094985962,-0.0045890808,0.0068702698,-0.002532959,0.0081863403, +0.009765625,0.0077362061,-0.0026664734,-0.0060920715, + +0.0027942657,0.0067901611,0.0070953369,-0.0020713806,0.0055351257,0.0030479431,-0.0060462952, +-0.0087127686,0.0030956268,-0.00036644936,0.0014686584,-0.0038146973,0.0072097778,-0.0052490234, +0.0056114197,0.0050926208,0.0080947876,0.0074501038,0.0079498291,0.0098876953,-0.0066146851, +0.0064735413,0.0093307495,-0.00051593781,-0.0047683716,-0.0069198608,0.0094604492,0.0066146851, +-0.0040054321,0.0017976761,-0.0058059692,-0.0087051392, +0.0022659302,0.0063896179,0.0073509216,-0.0016336441,0.0055236816,0.0031890869,-0.0062026978, +-0.0093917847,0.0034580231,-0.00057506561,0.0016918182,-0.0036563873,0.0067405701,-0.005569458, +0.0049743652,0.0047874451,0.0089492798,0.0069389343,0.0077819824,0.0091552734,-0.0065002441, +0.0063934326,0.0093460083,-0.00065517426,-0.0045127869,-0.0066223145,0.009765625,0.0062484741, +-0.0041465759,0.0016708374,-0.0056037903,-0.0086669922, + +0.0054740906,0.0022010803,0.0075340271,0.0047035217,0.00340271,0.0096969604,-0.0016756058, +0.0020771027,-0.0063018799,0.0073280334,-0.0056381226,0.004032135,-0.0082473755,0.0045280457, +0.0045814514,-0.0026607513,-0.0031585693,-0.003660202,-0.0053253174,-0.0089187622,-0.0073509216, +0.0048408508,0.0058364868,0.0069313049,-0.0071868896,0.008392334,-0.0018663406,-0.0092163086, +-0.00048780441,-0.0054283142,-0.0061683655,0.0078048706, +0.0054931641,0.0017261505,0.0074958801,0.0047340393,0.003868103,0.0095596313,-0.0021572113, +0.0023078918,-0.0063018799,0.0072631836,-0.0067367554,0.0039329529,-0.0080032349,0.0047874451, +0.0045623779,-0.0029945374,-0.0025291443,-0.0034275055,-0.0052986145,-0.0091400146,-0.0068702698, +0.0045623779,0.0057678223,0.0073547363,-0.0071487427,0.0087051392,-0.0018835068,-0.0099411011, +-0.00050640106,-0.0052947998,-0.0054206848,0.0078430176, + +=== +name:AttentionDataWithNeoXRotaryEmbedding.input +0.4287963,0.5977035,0.42293033,0.6351057,0.4845531,0.5391439,0.4124713,0.5433049, +0.37774163,0.3180431,0.44363722,0.5182994,0.43589768,0.48627475,0.45227078,0.51325303, +0.59149283,0.6034224,0.56825185,0.47176513,0.66173404,0.49446547,0.5832309,0.27636415, +0.5421023,0.22842114,0.5122983,0.5403643,0.3792681,0.7081227,0.5846911,0.36291638, +0.24069376,0.5652186,0.47218105,0.35314113,0.29180172,0.54298025,0.5094933,0.34442344, +0.27879003,0.5578696,0.51955676,0.404867,0.43173364,0.45403436,0.42531654,0.4469593, +0.30894,0.5237104,0.5686937,0.39202905,0.45227802,0.51884,0.48566076,0.5195642, +0.45420885,0.49974915,0.61360604,0.5407083,0.5416252,0.60130113,0.40878344,0.5026321, +0.36094332,0.45823723,0.5022766,0.54972637,0.56175584,0.29521704,0.5912351,0.5990948, +0.7694208,0.49711886,0.6089104,0.47362688,0.50358516,0.5317237,0.45520002,0.6256647, +0.6039174,0.59254634,0.735633,0.6083761,0.455735,0.509121,0.6206219,0.29866597, +0.512721,0.5962695,0.6603932,0.5499115,0.48856714,0.44383928,0.5548054,0.6067195, +0.42055875,0.36512884,0.6314579,0.5978053,0.43992677,0.4950198,0.4990613,0.47402245, +0.3841928,0.4514953,0.41173065,0.48704207,0.4275306,0.565417,0.4723786,0.38602483, +0.39987826,0.54069394,0.47007445,0.59639764,0.53741723,0.31021428,0.5201894,0.58018726, +0.52813613,0.48928523,0.48233622,0.69692403,0.4574055,0.3373666,0.53625447,0.4984796, +0.30992252,0.52511877,0.4662611,0.66359365,0.38145542,0.3953663,0.4322517,0.7677042, +0.6129446,0.38965738,0.6082955,0.56320035,0.46091992,0.48653173,0.36820853,0.5841444, +0.51555264,0.61160696,0.6368895,0.5046478,0.50983524,0.5606541,0.5509869,0.6943398, +0.4519988,0.45234227,0.4550282,0.47099903,0.5498503,0.51132417,0.55850244,0.5767037, +0.35744628,0.57191294,0.6822697,0.5961676,0.4599238,0.39388666,0.51835227,0.3893665, +0.33833945,0.50596046,0.525316,0.47627628,0.44638678,0.5752566,0.4079546,0.53521645, +0.6184023,0.5317764,0.50995564,0.45923784,0.4020773,0.4514767,0.40666643,0.3474568, +0.41701543,0.4541454,0.5680076,0.6431823,0.5797201,0.593049,0.5492972,0.54179704, +0.6394996,0.5615224,0.2946156,0.7078154,0.27128553,0.31515485,0.56672364,0.5429839, +0.36927712,0.5013621,0.3700635,0.4908689,0.380745,0.45022348,0.6438743,0.52167505, +0.5259024,0.5534358,0.5473131,0.6075395,0.5352279,0.5406236,0.57823056,0.4579628, +0.37261674,0.6423633,0.44780436,0.4324085,0.3808142,0.5554935,0.3896746,0.49800694, +0.5174113,0.6288219,0.5131922,0.42011988,0.4737175,0.58387935,0.39602864,0.59594595, +0.5084583,0.66909194,0.24586281,0.3614008,0.5371809,0.54694915,0.5359177,0.2746721, +0.28226215,0.59719855,0.5048337,0.643393,0.29625472,0.5431959,0.36609674,0.6279355, +0.60379565,0.5625251,0.5678101,0.5114099,0.5164335,0.4493996,0.53314364,0.38242325, + +=== +name:AttentionDataWithNeoXRotaryEmbedding.weights +-0.0009358525,0.0686215,-0.04372917,-0.08817229,-0.123893544,0.010441437,0.041352347,0.0057003647, +-0.034681827,-0.041952476,-0.07401417,-0.07924387,-0.095904335,0.012535021,-0.110810965,-0.0893341, +-0.008758247,-0.007699892,-0.105070844,0.053815514,-0.093375444,-0.045227498,0.044372603,0.12477732, +-0.041563302,-0.06546044,-0.040157974,0.038623393,0.09946635,0.104043454,-0.038352847,0.06731619, +-0.06532538,0.0052699894,0.075198054,-0.009794965,-0.11843774,0.11042,-0.0065520406,0.067836866, +-0.08212325,-0.01674448,0.046592176,-0.012353003,-0.112189084,-0.035165668,-0.031126052,0.12059966, +0.116698906,0.03597203,-0.04805571,0.11184119,-0.092591584,-0.112539425,-0.07241234,0.119319096, +-0.097512394,-0.012979254,0.06384784,-0.10055958,-0.11124186,-0.017608777,-0.031462595,-0.066379994, +0.090931,-0.11468202,0.055136636,-0.100305036,-0.063121945,0.095821306,0.0022580922,-0.10333653, +0.11197263,0.025167733,-0.005883187,0.12272608,-0.108832985,0.04257591,0.07470536,0.051685333, +-0.06195885,0.07040608,-0.12177156,-0.120984465,0.10387926,-0.023041502,-0.07251185,0.10557458, +0.09440717,0.07682702,-0.12033942,-0.11961973,-0.11178213,0.049702123,-0.064076185,0.108278275, +-0.047961473,0.0402409,0.05043736,-0.022191092,0.036536247,0.016348243,-0.023352072,-0.059559494, +0.118896395,-0.028476655,0.038315386,0.035649016,-0.0698238,0.04721223,0.10924137,-0.05746761, +-0.113479316,0.08762729,0.071042135,-0.01171723,0.022524193,0.09089993,0.014588192,-0.09133743, +0.026954353,0.07445289,0.017602101,-0.07736844,0.0065063685,0.104091465,0.067662016,-0.046679497, +-0.004167691,-0.10238932,0.094334096,0.09272677,0.06345852,-0.072785035,-0.019148156,0.03061372, +0.023749128,0.031623542,0.020134479,-0.031586662,0.014956385,0.062701076,-0.07197069,0.019509241, +-0.049841866,-0.07066804,0.09542197,0.09313166,0.044622943,0.040764347,0.1097548,0.010232016, +-0.043122754,0.03990327,-0.026119605,-0.083342746,-0.057632104,-0.01153861,-0.059681147,0.023373589, +0.08554253,-0.072594315,0.07045668,0.0054560304,-0.0997636,0.0997085,0.03867276,-0.054763615, +-0.029419959,0.033954576,0.08135465,0.085372016,-0.107195064,-0.019003123,0.02014929,0.096626535, +0.004903972,0.04849486,-0.002260819,-0.08651662,-0.042068273,-0.06796631,-0.12374203,0.003892973, +0.03737995,-0.11602788,0.009419605,-0.10126768,0.056510285,-0.028087229,-0.022152677,-0.00069639087, +0.06705545,-0.01577717,-0.10245271,0.0055749863,0.056424245,0.015608177,0.12495954,-0.11271489, +-0.046599463,-0.115921244,0.01793331,-0.013516709,-0.036534652,-0.04649879,-0.00793694,0.026898727, +-0.11806233,-0.07839753,0.0018421113,0.061806828,-0.0144776255,-0.032133564,-0.0688452,0.11457668, +0.040278703,0.102972284,0.060441688,-0.10046303,0.06559415,0.06423694,-0.07033987,-0.018573686, +-0.036098227,0.11141175,-0.020887643,-0.099561915,-0.11200227,-0.014490455,0.06596582,0.114557594, +-0.08697829,-0.1179014,-0.029231817,-0.0021842122,-0.09060852,0.025729299,-0.058989406,-0.029889092, +0.09487505,-0.0006647557,-0.044376284,0.045265347,-0.088710964,0.028694168,-0.047973737,0.058330268, +-0.10573074,0.11668806,-0.121085346,-0.020639881,-0.108788624,0.018645495,0.063792124,-0.113904625, +-0.013229445,0.043206915,0.099442676,0.02460225,0.02183333,0.09903158,-0.1006351,0.061471418, +0.10097951,-0.12141888,0.039188996,0.028507128,-0.092039734,0.09912047,-0.0018796921,0.12234129, +-0.12000182,-0.059035674,0.025278434,0.017905086,0.09814021,-0.051822722,0.05976872,0.11407806, +0.024583861,0.056301743,0.06799409,0.060113534,-0.0627698,-0.068875685,-0.11955427,0.12385404, +0.07013048,0.0003376007,-0.11758265,-0.07097311,-0.050688863,0.053935066,-0.073912024,0.08515149, +-0.036391526,0.041654736,0.098288864,0.08029403,-0.019973189,-0.0850766,0.04801266,-0.0629279, +-0.016826734,0.09024921,-0.048094496,-0.017271921,0.002787739,0.10950884,0.07804394,0.09010963, +0.0047299266,-0.08176015,0.12118666,0.08650796,0.118142605,0.014159158,-0.06342392,0.04151158, +0.055382386,0.06314337,-0.0146574825,-0.00924328,0.11312665,-0.08507608,0.12447624,0.079076335, +-0.024236143,0.0054644644,0.102798,0.039679363,-0.09711844,0.07652219,0.08313364,-0.09985681, +0.012132287,-0.025186509,-0.113933325,0.097142234,0.06779912,-0.05844237,0.023647875,0.07534185, +0.06035021,0.09257145,-0.05084008,0.122963786,-0.008292019,-0.10630974,0.105654985,-0.08878659, +-0.0022453368,0.097535774,-0.107118994,0.09031907,0.0968245,-0.1167198,-0.010176986,0.05082138, +-0.07414915,0.04014395,-0.027637005,0.112165526,-0.032329112,0.06680392,-0.062283292,0.07854223, +0.03578542,-0.030066654,-0.01217927,0.06204465,-0.10351591,-0.03889908,-0.0058148056,0.047221646, +0.06785424,-0.09464595,0.04516524,-0.06679377,0.11654715,0.08527395,0.0038704127,-0.0030974895, +-0.10288064,0.004772693,-0.026589394,-0.088116765,-0.060032964,-0.098268464,0.064832866,0.10366613, +0.03146863,0.051241055,0.039898932,0.016078606,0.040997535,-0.104681715,0.041693896,0.11381799, +-0.07207313,-0.04521276,0.09849855,-0.077634886,0.018253073,0.10770008,0.025899991,-0.06469244, +0.05529219,0.066126466,-0.077414095,0.01962693,0.050024286,0.004696235,-0.009782106,0.06422919, +-0.08090299,0.013555571,-0.052067667,-0.10925062,0.072377875,-0.10657932,0.1212517,-0.088934004, +0.08305842,0.09089236,0.121341914,-0.09308301,0.0038883388,0.052985847,0.102616474,0.07674125, +-0.1093763,-0.025912777,-0.030906677,-0.10148959,0.058772743,0.08908628,-0.055584967,-0.09858112, +0.027830988,0.015994996,0.023222342,-0.004109606,-0.02681826,0.115892395,0.02748534,0.104570344, +-0.052454725,-0.031910747,0.11928576,0.080580175,0.11503346,-0.034419373,-0.07291718,-0.09297475, +0.010882765,-0.08700541,-0.049964473,0.053163335,-0.09835082,0.05254568,-0.017817453,0.112881765, +0.067564175,0.06977697,-0.103471234,-0.036502898,-0.030670926,0.12408905,-0.07691334,0.061034217, +0.0073076487,0.01707448,-0.07147831,0.09748222,-0.02550219,-0.054437026,-0.0076898336,0.04139784, +0.059312522,-0.0827612,-0.12100656,0.12431368,-0.03666188,-0.072065786,0.045051217,0.0433331, +0.099794984,0.09524681,-0.021740332,-0.08247562,-0.09898007,0.12257896,0.04882832,0.0017809272, +0.028121874,0.090550944,0.07433972,0.0029958189,0.04025404,0.046066,0.03347817,0.10061175, +0.08392388,-0.054187834,-0.07839303,-0.101254374,-0.04880835,-0.11783038,0.10342777,0.016519919, +0.017652541,0.099920034,0.1007573,-0.045114323,-0.033013985,0.06715727,-0.079730615,0.10196106, +0.050984636,0.12383056,0.08018373,-0.10160735,0.08895326,0.008450791,0.107656345,-0.102717236, +-0.058511734,0.1128557,-0.016795114,-0.11098339,0.0043157786,-0.099389315,-0.024213254,0.03527522, +0.07863557,0.026977077,-0.08574487,-0.043255597,-0.092586786,0.0064911544,0.05563724,-0.07610844, +-0.10326752,0.045752913,0.09601846,-0.099143386,-0.06804758,0.0059229583,0.057878822,0.012099728, +0.0012236834,-0.057782516,0.06650466,0.10612036,0.02525109,0.09870699,0.09806813,0.0564546, +-0.11557613,0.0141659975,-0.0057738125,-0.024899885,0.036830604,-0.030378237,0.0017949194,0.08268972, +0.05878018,0.116363525,-0.074327216,-0.0023791492,0.011315763,-0.060509518,0.010288075,-0.092395514, +-0.09199238,0.028963089,0.026719555,-0.06881052,-0.083417535,0.009823531,0.07770604,0.06730543, +0.044336706,0.121683925,0.008850485,0.106493056,-0.10951063,0.050583407,0.037486807,-0.12295079, +0.050691605,0.08122976,-0.10704945,0.030997321,0.032511562,-0.10207529,-0.028537318,-0.106362835, +-0.00444752,-0.021236613,0.1196167,0.10297643,-0.032439664,0.10772155,0.097756386,-0.11136536, +0.053746104,-0.02463314,-0.020432204,-0.08606212,-0.073817134,-0.056822196,0.10410172,0.053120285, +-0.040468305,-0.1096371,0.0003979206,0.121971235,-0.019331679,0.009456232,0.04190208,-0.0070028603, +-0.049003407,0.03321752,-0.11099233,-0.07719658,0.09546551,-0.024273887,-0.060532436,-0.049201787, +-0.12278254,-0.11918421,0.043940708,-0.04443951,0.09535654,-0.08600439,-0.01912281,-0.07591206, +0.06526373,-0.026371062,0.10761556,-0.028977469,0.020580456,-0.072606996,-0.050050482,-0.05179049, +0.100393236,0.0976564,-0.04081583,-0.04826817,0.050387934,-0.11782661,-0.030347899,0.116819814, +0.11412041,0.0049937814,-0.033555493,-0.07272948,-0.08512296,-0.053918168,0.084994,0.06208381, +0.025754854,0.09086627,0.05674705,-0.047775224,-0.04767722,0.032955468,0.1009416,-0.08462086, +0.06888653,0.071232796,0.08428565,-0.109412804,0.021307826,-0.058233947,0.05043298,-0.08142477, +-0.018528685,0.026292175,-0.06920931,-0.089562416,-0.10816315,0.08758581,0.075338855,-0.055621535, +0.033744648,-0.11819033,0.109348446,0.031861275,-0.092344984,-0.11553669,-0.022246301,-0.065322205, +-0.12285602,0.05086492,-0.06732327,0.081304014,0.053473502,0.037481263,-0.032109454,-0.12417321, +-0.07881117,0.005925745,-0.07517876,-0.0036940426,0.10353863,0.09173848,-0.111488074,-0.011954546, +-0.12455991,-0.051920027,-0.060792208,-0.0739539,-0.083698004,0.021283507,0.055346146,0.080486074, +0.019715965,-0.010096058,-0.042431504,0.008879513,-0.043846563,-0.095942795,0.095691785,0.003485486, +-0.010907099,0.067029715,0.039356783,0.04704161,-0.040449858,-0.09330173,-0.116044775,-0.0689794, +-0.075641975,0.032774225,-0.009173617,-0.021900073,-0.08282937,-0.01587972,-0.073688865,-0.096144795, +0.05149378,0.014331609,0.031518295,0.113405794,-0.06290756,0.006003484,0.07311873,-0.042594418, +0.025828034,0.11802979,-0.123187006,0.033307597,-0.054292142,0.052813873,-0.11645867,-0.051531196, +0.08170152,0.09199171,-0.057161763,-0.03888513,0.09595086,0.11313334,0.09162918,0.07659824, +-0.048144296,0.07754707,-0.08143322,-0.07283819,-0.07201268,0.08655873,-0.04374902,0.12424946, +-0.061071455,-0.035585403,-0.08104372,-0.059640035,0.06852478,0.015994743,0.10460101,-0.12429902, +-0.042396963,-0.05012457,-0.055757463,0.09227309,0.06427908,0.009031057,0.087540835,-0.112661034, +0.119105354,0.006386116,0.08906801,0.08428541,0.066388965,-0.07342273,0.010747731,0.033602387, +0.011873722,-0.105831906,0.04538855,-0.03171538,0.09135826,0.11479585,0.11358449,0.05160801, +-0.008044273,-0.023149967,-0.063728765,-0.053910315,-0.06284748,0.03387478,-0.050732404,-0.047942877, +0.06638785,-0.05568944,-0.08791123,-0.10611187,0.0050615966,0.019946113,-0.10528417,-0.030080363, +0.051365748,0.114911094,-0.045346558,-0.10455607,0.037330627,-0.037478417,-0.0873321,0.0167889, +0.01056321,0.06519191,-0.06883071,0.0118136555,-0.06194301,-0.055479363,0.013331294,0.024443045, +0.060733244,0.056523114,-0.013739809,-0.10225162,0.09214109,-0.03509043,-0.11445515,0.1119407, +-0.037739977,0.08306618,-0.055772692,0.02351375,-0.07453604,0.0518986,-0.059641466,-0.060609862, +-0.07452257,-0.05049491,0.08829157,-0.056182474,0.029487804,0.085957065,-0.034678206,-0.032351628, +-0.02974695,-0.117051944,-0.12235956,-0.08622615,0.026518703,-0.12227848,0.10346301,0.093719006, +0.019732103,0.11871673,-0.05574052,-0.054447323,0.036175415,-0.07221635,0.073877245,-0.05410713, +0.1060541,0.06892677,0.0508911,-0.05989057,0.067771524,0.10723418,0.11849196,0.107248634, +0.0631925,0.024680719,0.08469856,0.0651681,-0.06542952,-0.08047669,-0.10186769,0.07967532, +-0.03878084,-0.017777711,-0.122241676,0.054399744,-0.002552867,0.05915086,0.033431843,-0.025981456, +-0.012826905,-0.03441766,-0.054412693,-0.01828596,0.032957092,-0.047937497,0.0664708,0.028557524, +-0.02818796,-0.10965742,0.0916252,-0.076345295,0.032640263,-0.118927434,0.005630702,0.08317909, +0.036610574,-0.044364333,-0.044281155,-0.061854362,-0.028276905,0.04421571,0.0023369342,-0.0847774, +0.076194614,0.10353005,-0.11002308,0.06852916,0.10026476,-0.09274651,0.08790636,-0.013949931, +-0.12203382,-0.06615445,-0.106360406,-0.122678354,0.05032845,0.09462868,-0.0703536,0.028899834, +0.0160992,-0.03316666,-0.044425502,-0.09770803,0.009115338,-0.023268342,0.023811847,-0.04052031, +-0.0006286502,-0.04441011,-0.120958805,-0.08646503,0.01030539,0.061473116,0.058549553,-0.118880615, +0.03351967,0.120024264,-0.00641492,0.042718127,0.07186951,0.11263922,0.05997844,0.06315152, +0.011049792,-0.103502944,0.11954105,0.08007951,0.06506845,-0.050060466,0.122832134,0.016015619, +0.08627863,0.07762997,0.10978532,0.018162668,-0.049738348,0.120437786,0.109310314,-0.06019497, +-0.086516604,-0.01322034,0.023413405,0.10704532,0.060108468,0.11789827,0.08685142,0.1213492, +-0.042766795,-0.066985324,-0.015957862,0.07278837,0.03894864,-0.027461171,-0.042187914,0.07535885, +0.03667885,0.0077539384,0.032233223,0.07272585,0.06543133,0.12495425,0.01116237,0.076495126, +-0.07135892,0.12309568,-0.0118703395,0.018085241,-0.12119874,0.039941743,0.025587454,0.037392825, +-0.030888647,-0.0052886754,0.094788805,0.06802955,0.023571357,0.017787322,-0.07775855,0.10013749, +-0.05560504,0.021906689,0.02860333,0.01594676,0.004184991,-0.08538993,0.048237488,0.021508396, +-0.08969495,-0.0033421963,-0.06319147,-0.04652004,0.03696683,-0.015523002,-0.053095117,0.10158467, +-0.11170675,0.11950743,0.006988883,0.12172304,0.042453334,-0.11591582,-0.038795456,0.051098153, +-0.024491131,-0.10426055,-0.042161077,0.021551922,0.11694072,-0.010046229,-0.09479532,-0.06670743, +-0.109466314,-0.077578574,0.065688506,0.073563755,0.10612434,0.088291764,-0.11712882,-0.06384261, +0.0040664524,-0.00033023953,-0.0011499077,-0.09212187,-0.034304127,0.05902691,-0.0141197145,0.013174504, +0.0040094703,-0.065376595,0.07714905,-0.011633843,0.052517787,0.09872687,0.09756534,-0.03766206, +-0.08495374,-0.0942595,0.06297271,0.10919574,0.09663513,-0.09901948,0.08297467,0.07728118, +-0.08199507,-0.055291817,0.064526334,-0.015623346,-0.115519986,0.03743899,0.11295377,-0.049301103, +-0.025448889,-0.09289122,0.029559985,-0.039285168,0.110992655,-0.004246965,-0.08860965,0.024618879, +-0.08067712,-0.06931761,-0.0946995,-0.082356036,0.0341115,-0.02849114,-0.0023111552,-0.050554603, +0.092051595,-0.11770104,-0.08141692,0.042512834,-0.03903307,0.078222185,-0.09465791,0.067045644, +-0.10641022,0.04597117,-0.032065094,-0.04367082,-0.114681184,0.08537179,0.096831456,0.048846513, +0.04366079,-0.10799959,0.014414728,-0.10574755,0.11447844,0.07948905,0.0050534755,-0.0038082153, +-0.115878284,0.09685825,0.095125675,0.05631697,-0.0761445,0.05772616,-0.026548192,0.05728896, +0.049093217,0.04756014,0.067884445,-0.05296223,0.08028564,-0.030979514,0.108303174,-0.0662913, +-0.0024766475,-0.096327946,0.089481354,-0.07448915,0.06619671,0.073468864,0.014363319,-0.08250862, +0.072441965,-0.11338246,-0.07268743,-0.015879229,0.07752569,-0.04226312,0.11371963,0.09412779, +0.09881748,-0.049566492,-0.020962179,-0.026447698,-0.0376918,-0.056045994,0.108565465,0.10509832, +0.04792668,0.029020697,0.055611566,0.06766553,0.043272257,0.12214838,-0.0009293556,-0.1237123, +-0.012690291,0.090279356,0.07275008,-0.051572993,0.031377062,-0.054809734,-0.04266435,-0.08617702, +-0.07672377,-0.04116775,0.065008,-0.07007474,-0.011190712,-0.043301508,-0.027171925,-0.11138627, +0.024544597,0.108057275,-0.019015387,-0.050758168,-0.122825995,-0.0026661605,-0.036352172,-0.0035651922, +0.043868244,-0.06259175,-0.10351564,-0.015438944,-0.033128545,-0.008480385,0.10781656,-0.015747815, +0.029256627,-0.07561901,-0.07848926,0.010749012,-0.11465593,-0.03222771,-0.023332104,0.1025095, +-0.06588465,0.003947541,0.07648927,0.003818974,0.04309936,0.065494224,0.0041512996,0.032723635, +0.03657323,-0.09455679,0.037918597,0.10382271,-0.049616978,0.06335646,-0.035883397,-0.08454566, +-0.0019277483,-0.0690984,0.075280696,-0.011549249,-0.09021594,0.04687679,-0.010753676,0.05622287, +-0.1223886,-0.029145464,0.090479195,0.09751353,0.11944345,-0.058079854,-0.0917218,0.11869216, +0.0017205626,0.12059334,-0.0683365,0.006732762,-0.067690074,0.022192478,0.08279534,0.052536502, +-0.015063897,0.08868469,-0.09687112,0.07177822,0.0144711435,0.037471652,-0.068002,-0.121467635, +0.115942016,0.096634164,0.09836994,-0.013516799,0.06891191,0.006579846,-0.079501644,-0.09570022, +0.02985397,0.040761173,0.043043256,0.049218193,-0.116515085,0.08337882,0.019282103,-0.034637302, +-0.095729396,0.10524495,-0.06708327,0.06311166,0.11373377,0.064034805,0.023612738,-0.019062266, +0.00699465,-0.117692694,-0.024503633,-0.10909963,-0.09668505,-0.1074719,0.004546225,-0.09523687, +0.083689556,0.116784796,0.023432046,-0.04333657,0.086967915,-0.019328162,-0.09669152,0.018123, +-0.091552824,-0.123281166,0.0035891533,-0.059187382,0.043168798,-0.02201067,0.016286492,-0.07695106, +0.018125147,-0.021068215,-0.010375544,-0.10645665,0.04999785,0.046552613,0.11575377,0.091076165, +0.02149956,-0.1063883,0.06396298,0.08056058,0.06447585,-0.09933829,-0.020353913,-0.030930758, +0.089184806,-0.027259186,-0.108600885,-0.11053619,-0.11181289,-0.035457388,-0.06891361,0.116769925, +0.099111184,-0.045808718,-0.012850031,-0.002727151,0.09594023,0.01675038,-0.029852167,0.10432297, +-0.01243709,0.031324923,0.10281257,-0.059365973,-0.07969339,0.032690167,0.083924025,-0.07606122, +0.018183738,-0.029112354,0.051785573,0.009235293,0.104592666,0.11983527,0.0056230277,0.041981205, +0.11258446,0.0044424385,0.0435196,-0.010341868,-0.003608361,0.11940847,0.03835252,-0.064890936, +-0.0024784803,-0.0044016987,-0.101935655,-0.0048549026,0.09930156,0.056265816,-0.013825163,0.08920206, +0.011141479,-0.04571934,-0.00024834275,0.000839144,0.04396102,0.08519311,-0.010689586,0.10472505, +-0.053588003,0.058395848,-0.11346829,-0.00042314827,-0.028225929,0.0971801,-0.12031326,0.100587085, +-0.030605122,-0.06601375,-0.03966324,0.12204161,0.11377156,0.033279777,-0.071604475,-0.08192675, +-0.083357245,-0.057683796,0.0027604103,0.032493606,-0.08019951,-0.11289278,-0.049334764,-4.6759844e-05, +0.002350837,0.017254382,0.0779499,-0.05695921,0.081435055,-0.047300264,-0.09670581,-0.0104682, +-0.08763732,0.118665114,-0.090835705,0.07127012,0.00049574673,0.10636413,0.11925399,0.054021925, +-0.07909839,0.09301777,0.01662226,0.09597719,-0.0018342286,-0.06895071,-0.1017382,-0.010967031, +0.010242358,-0.11716457,0.082892716,0.032853067,0.007214144,0.107399955,0.08201076,-0.09976637, +-0.009699181,0.020166919,0.030881941,-0.094791204,0.0576479,0.068695545,0.08494462,-0.059477285, +0.08838555,0.09725891,0.11532448,-0.03665352,0.0725538,-0.010292068,0.07150473,-0.020225048, +-0.097554594,-0.034029394,-0.021708071,-0.006873235,0.04308355,-0.0355646,-0.12354076,0.0372577, +0.09378001,0.009980291,-0.11858654,0.05225505,-0.05808115,0.06701255,-0.035891816,-0.053126812, +-0.0059167594,-0.09137054,-0.011955187,-0.029562294,0.04150507,-0.009782121,-0.01167123,0.06975344, +0.048251033,-0.024322852,-0.049870193,-0.047731727,-0.04559906,0.09714331,-0.07744934,-0.089592606, +0.064836696,-0.12407796,-0.050192013,-0.06611198,0.114289686,0.020715728,-0.062084913,-0.011263862, +-0.079572394,0.049679562,-0.050951317,0.06657554,0.10165352,0.08454549,-0.012554705,0.106089965, +-0.08036639,0.08259523,-0.0806731,0.09947573,0.08138384,-0.046616524,-0.042360276,0.06572595, +0.046504095,-0.04653579,-0.11436312,0.044624478,-0.0908476,0.015504718,-0.105565235,0.035491437, +-0.085429475,0.01948312,0.023334667,0.11131568,0.09814112,0.12426275,-0.07208693,0.114961416, +-0.011093006,0.049126238,0.003474027,0.0052585155,0.04534039,0.058376774,-0.07046373,0.0067180544, +0.03804174,-0.009464964,-0.09943853,-0.10884996,0.124500126,-0.022602111,0.08788276,0.02751714, +-0.009884343,0.0026602745,-0.12024978,-0.01340346,-0.033548042,0.11091758,0.07371163,0.120606646, +-0.021735296,-0.07564187,-0.07376215,0.032637075,0.018671215,-0.05839011,0.0043465346,0.08002116, +0.10717882,-0.008324131,-0.061328962,-0.0017641336,-0.115786895,0.015474528,0.03694485,-0.05444546, +0.074351564,-0.108033806,0.106934234,0.04279092,0.10528329,0.10767354,0.07009491,0.124853596, +0.024826303,-0.046559826,0.026708424,-0.01977478,0.067477405,0.01821518,-0.07298966,0.014520779, +0.043227315,0.10719161,0.119103715,-0.095733404,0.0011971593,0.065728486,0.088580295,-0.12093221, +0.116176754,-0.0190012,0.103563115,-0.1196824,-0.023218498,0.06681219,0.054850787,-0.047608554, +-0.088584945,0.02905278,-0.09717506,0.11132081,0.085465044,0.01797834,0.10970013,0.004753664, +-0.08167063,0.09542024,-0.03690183,-0.09427531,0.019947976,-0.08960843,-0.04226993,-0.0887603, +-0.0055423826,-0.062473133,-0.03924218,-0.002163902,0.10861142,0.039512783,0.08480413,0.050049216, +-0.12092878,-0.11253159,0.03812714,-0.0021837652,0.11757913,-0.024517387,0.032333285,0.06479114, +-0.114574045,-0.0032083988,0.05651395,-0.0057646185,0.09764548,-0.0029108226,0.030961946,0.0666367, +-0.01846233,-0.010423109,-0.07537456,-0.00017569959,-0.02410607,-0.08609867,-0.028677851,-0.09435095, +-0.027566612,-3.516674e-05,0.07409561,-0.075100034,-0.0074748993,0.030848324,-0.0106071085,-0.05920084, +-0.07176387,-0.057153225,0.05428937,-0.08237387,-0.00076310337,-0.03636518,-0.10661474,-0.03086631, +0.029071093,0.111788645,0.03616777,-0.10651833,0.04565157,-0.040175468,-0.058808908,-0.047146097, +-0.023025572,0.06914204,0.09302898,0.11173971,-0.10525499,-0.104428545,-0.036673427,0.089709, +0.085357115,-0.05099328,0.02471593,-0.111814976,-0.055976987,-0.06256421,0.12406631,0.034811392, +-0.03357427,0.12125018,-0.05075255,-0.0865453,-0.019909576,-0.06730735,0.030938074,-0.07014519, +0.09148346,0.0045696795,-0.05845517,-0.06583436,-0.011987984,-0.093638524,-0.12368859,0.034265056, +-0.0031019896,0.028968766,0.031179637,0.03666757,-0.10388397,0.09672207,0.06898104,0.05415851, +-0.024237275,-0.008332536,0.093364045,0.07017408,-0.043173343,0.04964666,-0.08029316,0.06755619, +0.03307657,0.10356867,-0.010783613,0.08057788,-0.041744962,-0.060809955,-0.07013957,0.059277058, +-0.030148372,-0.063123405,-0.030068561,-0.1146898,-0.07409519,0.081684485,-0.016128719,0.08787316, +-0.039678395,-0.114708185,-0.039310113,0.062937394,-0.08683017,0.11629246,-0.124892294,0.092652604, +0.099238634,0.02315928,-0.0010899901,-0.052231833,0.0005546063,-0.06623228,0.0033932477,-0.019543588, +0.11158329,0.048670083,0.095292464,-0.08170986,0.091536894,-0.11020994,0.05059734,-0.07694359, +-0.07308602,0.006887406,-0.07911451,-0.11477256,-0.05746837,-0.11057703,-0.09948979,-0.03412804, +0.06099257,-0.117369354,0.06806181,-0.10941774,-0.0832994,-0.12286821,-0.07506825,-0.07916382, +-0.0034145117,0.0021096617,0.12208091,-0.06862344,0.0422066,-0.05142732,-0.041839465,0.020769194, +0.10956216,-0.030883148,0.061548963,0.09483941,-0.07789396,-0.117649406,-0.12153849,-0.051696032, +-0.04116024,-0.08534229,0.038339898,-0.0800042,0.07464154,-0.043881357,-0.08129573,-0.051947206, +0.034073234,-0.10069612,-0.012017354,0.07134122,0.0775971,-0.031892896,-0.024305716,-0.0006837249, +-0.016605377,-0.099671036,0.008108839,-0.003765121,-0.072863534,-0.014044583,0.01807274,0.036283836, +-0.08239913,-0.037554488,0.013887912,-0.0148513615,-0.07392731,-0.046184137,0.082987025,-0.007106185, +0.010876,0.03493625,0.1179699,-0.017105967,0.0140156895,0.042287678,-0.09632,0.037088245, +0.04027337,0.043101296,0.07032359,-0.11561549,-0.11425233,0.027556837,0.040312245,0.026071057, +0.041306213,-0.01701966,-0.107432336,0.11460726,0.0851533,0.09885611,0.12037431,0.085861936, +0.041916206,0.08576074,-0.026708156,0.11240134,0.10138321,-0.052884042,0.08393137,0.073057786, +-0.121504486,-0.09198205,-0.045773417,-0.10883014,0.02222833,0.03091827,0.026553512,0.037931234, +0.0022899956,-0.01669778,0.09817138,0.06998856,-0.10567339,0.095472395,-0.11272569,0.0026328117, +0.045490444,0.11328001,-0.00472942,0.044017375,0.064548105,0.04524827,-0.072074145,0.07307573, +0.05827965,-0.051886648,-0.012853682,0.124732316,-0.11824499,-0.055437386,0.11003564,0.068133876, +0.08166283,-0.08848573,0.10440053,0.08456008,-0.00531061,0.049497113,0.09180179,0.02828896, +-0.115466654,-0.049564913,0.114842445,-0.07220657,-0.117837176,-0.013269633,-0.018244043,-0.019161984, +0.07741515,0.043917865,0.04909794,-0.10483052,-0.05276926,-0.084135145,0.09678221,-0.07705933, +-0.037776634,0.10877591,0.025297672,-0.09449001,-0.03493102,-0.10358605,-0.0961851,-0.10022864, +0.043812454,0.025266483,0.0679961,0.12207633,0.12479256,0.007080391,-0.09700586,0.038539544, +-0.00632073,-0.0012481213,-0.06347902,-0.08487642,0.08475497,-0.011927888,-0.07332428,0.0018122047, +0.0020605475,0.0032693446,0.033332556,0.106102854,-0.09071569,0.007908538,-0.11895244,-0.06663042, +-0.096231,-0.08224088,0.016398624,-0.0033837706,0.04053721,0.104098335,-0.011142015,0.024819642, +0.036367163,-0.0141931325,0.053334802,0.057337478,-0.06152153,0.03023678,0.11312914,0.04937774, +0.039288983,-0.07195911,0.10410172,-0.11170322,0.0336926,-0.103223264,-0.053920344,-0.04582697, +0.036739618,0.06904186,0.062442765,-0.0064941198,0.0019867718,0.009733111,0.0012494475,-0.06272027, +0.057647735,-0.026462466,-0.11542173,0.05451812,0.105851874,-0.07775682,0.08734766,0.0036647469, +0.100780204,-0.034073442,-0.051638126,-0.08419065,0.069899976,-0.019857302,-0.048699006,0.05873221, +-0.011870325,0.036642686,-0.07226029,0.064652264,0.06971294,0.029792458,0.0756346,0.090598136, +-0.043760613,0.027379662,0.044950858,-0.11621095,-0.097561404,-0.02847983,0.11086139,-0.038365483, +0.08168702,-0.023563445,0.057727873,0.01628083,0.0010581762,0.063642725,-0.031609043,-0.10819708, +0.11469926,-0.09855835,0.105118915,-0.09679772,-0.062290043,0.034934774,0.08733359,0.096502274, +-0.09362863,0.02644582,0.03902009,-0.095148414,-0.104034945,-0.043424144,0.013580397,0.024155334, +0.041562453,0.09546748,-0.07207078,-0.004327312,0.06798452,-0.11463855,-0.094701305,-0.060111985, +-0.09650244,0.07363635,0.050870508,0.08283296,-0.053393677,0.037037507,-0.122933224,0.037519366, +0.10238087,0.07165271,0.04478611,0.12070079,0.072017476,-0.004049808,0.05070275,0.04170771, +-0.123949364,-0.023330286,0.002580285,-0.08639987,0.09197874,0.027150318,-0.011713877,-0.10161224, +0.03425792,-0.059831336,0.04030837,0.017143518,0.007848784,-0.1180128,0.08591847,0.01102531, +0.08663741,0.09153722,0.042990893,0.11212583,-0.10130747,0.046998397,0.029493049,0.014127433, +0.03984052,0.09727506,0.07352781,0.049455494,-0.035678938,0.07372323,0.051778242,0.041088715, +0.10910472,-0.09372111,-0.09939551,0.11206852,0.10879646,0.100394115,0.022097275,-0.035271764, +-0.022792265,-0.067296594,0.07250345,-0.08371167,-0.083941445,0.078786165,-0.053538427,0.11933565, +-0.024570674,0.110294595,0.07947993,-0.08581403,0.036928743,-0.10749014,0.08391629,-0.035953313, +-0.090549275,0.047469854,-0.051072583,-0.031174943,-0.11996131,0.047217086,-0.046403393,0.027051345, +0.022752613,-0.012599468,0.10538265,0.06338781,0.08464444,0.11307916,0.022340402,-0.07747193, +-0.09360561,0.0080816895,-0.028214276,0.062588096,0.02901733,0.038924724,-0.109279275,0.07625808, +0.0458121,-0.008444086,0.025171459,0.120694205,-0.0837637,0.0703906,-0.08074078,0.105892524, +-0.0042695105,0.108975306,0.07097946,-0.095680594,-0.025118396,0.070806175,0.084131986,0.12465054, +0.09080447,0.121536836,0.10520047,-0.096953586,-0.06832126,-0.12384567,-0.07723802,-0.103995144, +-0.050855383,0.082153514,-0.07461828,-0.08704701,0.01950574,0.11308929,-0.12172374,0.009115741, +0.06612846,-0.085438624,-0.053796574,0.0154363215,0.024263784,0.08388753,-0.014530897,-0.0937286, +0.05819744,-0.11472198,-0.071880504,-0.04433821,0.03382373,-0.0024882853,-0.016716108,0.003621325, +-0.008502573,-0.10176349,0.028876439,0.041705385,0.07134259,-0.119653404,-0.08552429,0.08300386, +-0.038392514,-0.07764758,0.06398511,0.03815247,0.03334059,0.061544448,0.05302733,0.017318204, +-0.019243598,0.09169415,0.074486494,-0.06289397,-0.10323775,-0.012159124,0.12464057,0.06467822, +0.040999472,0.10193339,-0.02554664,-0.056434557,0.06802158,0.11681785,-0.061239854,0.012092978, +-0.044138566,0.054921642,0.009146363,-0.012028262,0.1178505,0.112015665,0.054710403,-0.055143774, +0.041811645,0.030259475,0.020039886,-0.032487348,0.06465447,0.12432842,0.027098075,0.07841122, +0.051491633,0.0923416,0.113517106,-0.0059486926,-0.019373134,0.078457505,-0.051528275,-0.05897358, +0.070794925,-0.062418684,-0.017796904,0.05636853,-0.008684412,0.010575771,-0.08647205,0.031773046, +-0.04266852,0.010214195,0.05018896,-0.02588673,0.08787385,-0.0899452,-0.12066521,0.043223932, +-0.12300748,-0.024721235,0.08231476,0.038588315,0.091504425,0.124510065,-0.11343883,0.081149146, +0.09634367,0.10117999,0.05666709,0.005595863,-0.0061852336,0.015971929,-0.06329876,-0.07261635, +-0.04990478,-0.019746706,0.11744775,0.12295048,0.109053105,-0.112107545,0.06556149,0.030760944, +-0.10445584,-0.020623207,-0.012525097,0.03469932,0.058867097,0.039062813,0.008765504,0.1139293, +0.105508655,0.107904226,0.10513131,0.11069712,0.05178845,-0.08915427,0.08339593,-0.035926387, +-0.11941856,0.024876818,0.118405774,-0.07258269,0.10275434,0.12470122,0.0888664,-0.122734696, +-0.0735036,0.09941487,0.10500537,0.0062436014,-0.11137125,0.05446203,-0.014033064,0.124715745, +-0.09548138,-0.011229545,0.051879987,0.07045294,-0.039195865,-0.05446492,0.000697121,0.12206258, +-0.06857705,-0.047635987,0.119868174,-0.09149,-0.09189317,0.062703386,0.010391265,0.008379191, +0.048268452,-0.0351568,0.041111916,0.09990682,0.030414,0.108648136,-0.094312504,-0.082777694, +0.06872949,-0.04115264,0.062086403,0.017443284,-0.010585129,-0.019498393,0.00010740757,0.037685603, +-0.015041888,-0.11473481,-0.087345764,-0.05235131,0.101701826,0.0051520467,-0.021677405,-0.034466192, +-0.08598074,-0.048516437,-0.10755016,0.091096565,0.04168339,-0.07073164,-0.040633023,0.039927647, +-0.12425713,0.09055328,-0.10546763,0.022745013,0.09681782,-0.09350115,0.08697866,-0.09800729, +0.10885991,-0.09827322,-0.015249804,0.11214399,0.06452039,-0.07177706,-0.10125783,0.029490754, +0.11211854,0.040548265,0.046274543,-0.031137884,0.005080372,-0.07908988,-0.0006021112,0.11052573, +-0.12449078,-0.005290985,-0.07172799,0.00043436885,-0.0014564097,-0.04149294,0.044695944,-0.019199133, +0.04362759,0.058331206,0.0039360225,0.12358154,0.059879377,-0.08474289,0.048851192,-0.045876294, +-0.115499824,0.11437373,0.05313033,0.054638714,-0.043047562,0.017621174,0.106601074,0.10256645, +-0.09428392,0.08383556,0.032376736,-0.04319054,-0.041231424,-0.12461284,-0.06358534,-0.036043122, +0.005044356,0.05824171,-0.08870554,0.008165538,-0.04653801,-0.06931375,-0.09703037,-0.07928315, +-0.11720972,0.08623251,0.10089357,0.08053519,0.08545312,0.08344863,0.06937656,0.07069923, +0.123325884,0.1098499,0.115028456,-0.12442568,-0.09371658,-0.026825592,-0.015331879,-0.08537334, +-0.12441611,-0.010084584,0.12488307,0.054811537,-0.085181996,0.10658303,0.019047648,-0.0040608495, +-0.024550468,-0.064107716,-0.10985789,-0.06863542,-0.10901831,-0.0070411563,-0.008599207,-0.016794533, +0.058025494,-0.029456377,-0.12220423,0.020169288,-0.01983735,0.07163958,-0.02675423,0.09424351, +0.029748544,-0.110136464,0.11741871,-0.061632514,-0.09357816,-0.0021866858,0.016805828,-0.018822, +0.07410459,-0.059557766,-0.06718257,-0.11777249,-0.08761202,-0.11958763,0.031418696,0.04891433, +0.058018997,-0.021699667,0.0011100471,0.10278879,0.109556034,-0.0017957836,-0.021213606,-0.022411823, +-0.08278526,-0.10869783,0.07938199,0.087491676,0.033986524,0.07934867,-0.014226586,-0.048686564, +-0.06344882,0.097047776,-0.08601956,0.03388904,0.07677454,-0.030670792,-0.06754832,0.081434086, +-0.029874459,-0.024988025,-0.09120946,-0.07573433,-0.024990007,-0.042788148,-0.098134115,0.100271404, +0.04652694,0.032027826,-0.048204556,0.108082056,0.06065017,0.05083786,0.061866716,0.004895881, +0.04779595,0.06540261,-0.02953665,0.0952024,-0.03483744,0.054699913,0.120339826,0.0667385, +0.083060026,0.096614376,-4.5850873e-05,-0.024787411,-0.062520325,0.068987295,-0.05112925,0.04888332, +0.06785889,-0.119351596,-0.040060267,0.019441843,-0.032753885,0.067570984,0.04479535,0.061457112, +0.015919387,0.010609716,-0.10163359,0.09666568,0.09592259,-0.08476588,0.10537243,-0.035416797, +-0.06948593,0.064827725,0.05888392,-0.10080849,-0.028463617,0.029883087,0.09445174,-0.053482905, +0.0009582788,-0.023519412,-0.03877029,-0.057156876,-0.08577065,-0.08676168,-0.0009876043,-0.080518454, +-0.021925285,0.019329995,-0.08908515,-0.0021766275,0.070568696,0.04347308,-0.096553,0.04264033, +0.11912443,-0.07933962,0.093431264,0.029489323,-0.0016351938,-0.07634032,0.042119727,0.021642, +-0.09833905,0.11622159,-0.089942575,0.12484081,0.024931163,0.013426974,-0.048382625,0.0021752566, +0.023335487,-0.10993315,0.0163998,-0.035835266,-0.05786328,0.101888254,-0.077856615,-0.11264011, +0.012429908,0.03617911,-0.12264052,0.12153578,-0.091253,0.026951253,-0.060248047,0.036845148, +0.034316137,-0.027188748,-0.0021532923,0.06499958,0.0034866482,-0.024701238,0.051116273,-0.06732033, +-0.04909797,-0.074172676,0.004482597,-0.034518197,-0.030816823,0.00052158535,-0.07069038,0.011209756, +-0.053728625,-0.0836923,-0.1027022,-0.102550715,0.11039838,-0.0012382269,0.032745317,-0.1157715, +0.12415066,-0.022205606,-0.10737571,0.07333368,-0.12083191,0.041515484,-0.00021469593,-0.0741508, +-0.037296444,0.02549757,-0.05936177,0.026607886,-0.061927587,0.025924414,0.11304434,0.04828398, +0.028380588,0.00017523766,-0.008019567,-0.06366804,0.08680363,0.05332443,-0.12285201,-0.028474107, +0.05779271,0.0412616,0.029776141,0.023025021,0.054413766,3.0189753e-05,-0.019503072,-0.08477591, +0.005086988,0.050510556,-0.0017988235,-0.0025004745,-0.030825809,-0.07187636,0.061682463,-0.121352494, +-0.052433655,0.12319222,-0.0496542,0.028507426,0.06351985,-0.047082976,-0.10412276,0.08188389, +-0.051527888,0.011499062,0.11867669,-0.044933125,-0.05914317,-0.08640422,-0.07233575,0.026966393, +0.11487636,-0.018710464,-0.10497144,0.084966525,0.013064116,0.05408311,0.06389636,-0.07030338, +-0.10397512,0.09854716,0.020153373,0.10207045,-0.092235,0.047279075,-0.055326447,0.054117873, +-0.054093614,-0.10108076,-0.1116337,-0.0018548965,-0.0744762,0.10643618,0.08396907,-0.037966773, +-0.017041445,0.10172799,-0.049988464,-0.012328297,-0.05017379,-0.04214424,-0.033606976,-0.0143157095, +0.033163205,0.0059175044,0.03568302,0.071652904,-0.030010521,0.0042517334,0.02548644,0.045899212, +0.0404111,-0.009009212,-0.059299618,-0.058784604,-0.026049897,-0.016491309,-0.10116424,0.0012070686, +-0.07978484,-0.08085692,-0.03124842,0.11324181,0.071951,-0.09586272,-0.11222495,0.08475609, +-0.120283395,0.024668247,-0.015868127,-0.035690114,-0.017384395,0.09362796,0.013353363,0.0032110363, +-0.0637376,-0.016504616,-0.07117379,0.11564146,-0.08090685,0.103192136,-0.060192898,-0.047066063, +0.07608876,-0.11932643,0.098289564,-0.06779982,-0.058518857,0.11770566,-0.115372345,0.048522234, +0.061612844,0.026410818,-0.059120193,0.07642259,0.078532085,-0.03545682,0.1161083,-0.08274965, +0.019814014,0.038826942,0.077769294,-0.048375502,-0.075719,-0.05820456,-0.06038788,-0.03816241, +-0.020247638,-0.074394986,0.05926323,-0.11032523,-0.024370953,0.020681083,-0.00861387,0.03641832, +-0.09800002,-0.04187426,0.119381905,-0.02674669,0.12231816,-0.0026379228,-0.071288675,-0.068437055, +-0.084132195,0.12462957,-0.04663956,-0.0634041,-0.029827192,0.08102651,0.08466858,0.05087821, +-0.0014313906,0.11444254,0.061562493,-0.02671595,0.0541559,0.12495893,-0.08181763,0.0049472004, +-0.08859737,-0.08094294,0.10550925,-0.07894343,-0.09411827,-0.030135304,0.12100719,-0.059599027, +0.106637195,-0.03960322,0.002344504,0.09052238,-0.10151228,-0.010042772,0.044243857,0.10952522, +0.02802658,-0.045012817,0.12255736,-0.051119357,-0.025041178,0.10590249,-0.028067201,0.02672255, +-0.03289686,-0.016196594,0.030918956,0.02912499,0.09992118,0.10005896,-0.0033462793,-0.019404843, +-0.018528298,-0.10238214,-0.039699554,-0.10298549,0.05022642,-0.026699826,-0.028143719,0.03889413, +-0.033530056,0.060057476,-0.05451931,0.0035541654,0.09580386,0.099460006,-0.017968968,-0.11750977, +0.09804933,-0.06938739,0.0012335181,-0.052318603,0.065815404,-0.11965062,-0.032116592,-0.012645796, +0.0046304464,-0.07820067,-0.009040207,0.10543609,-0.058759674,0.048905328,0.09661318,-0.09814522, +-0.033635512,-0.110220894,-0.056364894,0.10668427,0.0072111636,0.09224166,0.043878406,0.010804564, +0.07671936,0.092248395,-0.0014366806,0.122773096,-0.10438672,0.0264059,-0.058381766,-0.06828293, +0.030063882,0.03736539,-0.059509516,-0.005556524,-0.040831313,-0.031317517,0.00542365,0.09417994, +0.031261012,0.078488454,0.035860524,0.0022168756,-0.013537928,-0.040805906,-0.016896099,0.03990467, +0.0037769675,-0.05616027,-0.098063916,0.12148763,-0.0036029965,0.095160395,-0.08273855,-0.05114068, +-0.03939399,0.039768785,0.022926316,-0.004455596,-0.109635055,0.11238912,-0.010708079,-0.11920054, +-0.077488735,0.10438171,0.07081202,-0.0789077,0.015997335,0.074719846,0.06289524,-0.016266301, +-0.06515074,0.02830267,-0.09137787,-0.005437091,0.031530663,0.123214215,0.039540917,-0.08441764, +0.08273099,0.09776826,0.018422008,0.06007108,0.033617824,0.105024904,-0.104629874,0.09371284, +-0.038902923,0.04537736,0.08882499,-0.02815716,-0.050030977,-0.037342995,-0.028538957,0.033520803, +0.09037082,-0.02040632,-0.10767828,0.05317785,-0.1069569,0.062336996,-0.07819699,0.0023141056, +0.11263551,0.016717747,0.01392518,0.08678801,-0.09537932,-0.09045985,0.03284116,-0.027942508, +0.036846742,0.09879267,-0.056818888,0.101695165,-0.03037472,0.040262476,-0.048331395,-0.10741675, +0.095222,0.0049164295,-0.008056581,-0.10430992,-0.08836354,0.00032794476,-0.080935046,0.051391885, +-0.0073852837,0.04864447,0.1235698,-0.09953846,-0.07299285,-0.05221255,-0.020342812,0.034059033, +-0.0212055,-0.0024733394,-0.1158708,0.052227706,-0.010599673,-0.08973192,-0.06302439,0.048266217, +0.07629745,-0.036065787,0.08429806,0.11320025,0.12156986,0.105115384,-0.10067718,-0.10670647, +-0.10834466,0.015427694,0.11403224,-0.06574829,0.059322298,0.09900086,-0.07798989,0.072595894, +-0.03585787,0.04666543,0.005553007,0.03476666,0.12005043,-0.103536695,-0.043080777,0.0010793805, +-0.07658915,0.1105618,0.1008708,-0.09443875,-0.07730308,-0.09214255,-0.11396228,-0.035926893, +-0.053778574,0.08108379,0.05973704,-0.10140625,0.11511949,0.07333064,0.057276726,0.015547648, +-0.08881937,-0.08827999,0.109492674,0.042767495,0.038313583,-0.020903215,-0.033695668,-0.020512104, +-0.04871306,-0.022330761,-0.10002397,0.053065553,-0.060186163,0.102274016,-0.00030949712,-0.010905117, +0.0494169,-0.11649427,-0.11229019,0.045200944,-0.11818363,0.09439595,0.07993612,0.039845526, +-0.0003412962,-0.11295289,0.020206302,0.101377144,-0.0692198,0.0057522953,0.02016899,0.063859046, +-0.07960454,-0.08471966,-0.05135873,-0.049278587,0.04700619,0.06890945,-0.123845264,0.09847242, +0.123031914,0.06773667,-0.11601061,-0.034210652,-0.059281647,-0.041009188,0.052690208,0.069337144, +0.031454563,0.093194455,-0.033128873,0.06833583,-0.058933124,0.060577765,-0.076607525,0.0975088, +-0.10760383,-0.029727325,-0.09809446,0.02817072,0.056070134,0.0026914328,0.08119385,0.030512288, +-0.088283285,-0.12441152,0.033496022,-0.014972895,-0.111961454,-0.022487864,-0.035973713,-0.108162224, +-0.120196,-0.06609927,0.039575025,0.088937566,0.049974993,-0.11465399,-0.105198056,-0.04988587, +-0.10363425,0.014633521,-0.039942995,0.02971366,-0.037167445,0.06324871,-0.07070081,-0.07135415, +0.00921528,0.021530673,0.0713467,-0.018992871,0.019452766,-0.0037843436,0.003066063,0.012157679, +0.09301302,-0.034335032,-0.037553072,-0.02057682,-0.019791648,-0.0011383891,0.013818204,0.091276765, +-0.10640471,0.01649271,-0.05403672,0.00023809075,-0.074783385,0.11966543,-0.07643965,0.095279545, +0.022725195,-0.024089247,0.07529895,-0.029710963,-0.024820164,-0.078868955,-0.0030782819,-0.0319919, +-0.11479445,0.03141938,0.11740197,-0.038971946,0.120673865,-0.013921395,-0.06844336,0.05284807, +-0.055422172,0.014436066,0.1116429,0.10658863,0.10158242,-0.01553832,-0.05389969,-0.09256598, +0.03485261,0.061701834,-0.037344635,-0.030431673,0.030335173,-0.06300072,-0.11126052,-0.057118937, +0.070346266,-0.114991665,0.009236097,-0.092723414,-0.0487144,0.051862344,0.05970034,-0.07001954, +0.117494285,-0.1004964,-0.11193836,0.0680138,0.0068926364,-0.08475295,0.1103372,-0.10832915, +-0.09614597,-0.0075980276,-0.03268014,-0.050443947,0.10414541,-0.10507475,-0.00083230436,0.10584256, +-0.11403413,0.12188773,-0.020543918,0.11670682,0.09893386,-0.0651114,-0.055262074,0.09094399, +-0.0636587,0.05236377,0.062633544,-0.032574505,-0.03303194,0.02824469,0.02817373,-0.12395099, +0.0023905635,0.02518025,-0.06622723,-0.117016315,-0.015098587,0.10721867,-0.032311857,0.085099906, +0.10975686,0.068748,0.06489985,0.023208559,0.11341037,0.119084746,-0.0064531565,-0.07507931, +0.08121103,0.089984044,-0.07869524,0.03820865,-0.09548564,0.10049926,0.04906088,0.027589932, +0.07500285,0.11106156,-0.059259653,0.015828252,0.027006,0.124951854,0.009291753,0.06710085, +-0.06056194,0.1167112,0.11509448,-0.09261039,-0.05243443,0.024461612,0.030195087,0.110238686, +0.11419298,0.058065847,-0.07138458,-0.0350118,-0.05339907,0.11878991,0.011921346,0.011376992, +0.042460054,-0.013756648,0.10300602,-0.03298004,0.0986639,0.041900024,0.052279636,0.022392705, +0.12166235,-0.11171274,-0.051637232,-0.041578323,0.10930459,-0.024231732,-0.06196998,0.033940032, +0.049769282,-0.0141851455,-0.0077695698,-0.0035692602,0.115645364,-0.080027804,-0.066107586,-0.066621706, +0.114359915,-0.1160527,0.027810797,0.11431749,0.008448094,0.025556296,-0.06390728,0.04531826, +-0.03984347,0.08302753,-0.015180111,0.086791664,-0.037591413,-0.06078762,0.018231586,-0.08264972, +0.09200893,0.09346676,0.041020542,-0.06856987,-0.04260911,-0.033545747,0.08956051,0.0892494, +0.021050468,-0.020268217,-0.019288346,0.06465098,-0.10989025,0.108196124,0.110661045,0.043136477, +0.038134053,0.12459716,0.018598929,-0.01770711,-0.072590664,-0.12066679,0.10659598,0.06559408, +-0.12237576,0.05777976,-0.11066532,-0.009630889,0.08675566,0.112997055,0.09613331,0.064672515, +0.02204831,-0.052732766,-0.0837677,-0.09067616,-0.047212362,0.043384075,-0.060582295,0.056117192, +0.020895943,-0.045190364,0.0008312166,0.0150654465,-0.022433788,-0.013575986,-0.04122798,-0.047955096, +-0.08566943,-0.10328625,0.003060326,-0.08079843,0.1113379,0.05290346,0.03000474,0.07305361, +0.10027018,-0.024251908,0.043501183,0.03774534,0.107537836,-0.02924487,-0.09340915,0.09191203, +-0.049844563,0.07923521,0.040465683,-0.030262142,-0.08098905,0.10705872,-0.053286478,-0.013226524, +-0.07285668,0.11881499,0.029376015,0.04080321,0.05733998,-0.09530793,-0.012099788,-0.043159097, +-0.10600437,-0.017921582,-0.09255116,0.06764528,-0.018725634,0.090017736,-0.03483808,-0.02035655, +0.104596466,-0.093897745,0.09875089,-0.10474117,-0.0338286,0.022422895,-0.09034407,0.12067051, +-0.0037709028,0.08854608,0.08505237,0.09993285,-0.09822632,0.09284307,0.015988573,0.07384819, +-0.10536966,0.036517322,0.098224446,0.07343818,-0.054230183,-0.0436984,-0.05779031,0.07225032, +0.098421395,0.07458311,-0.024220034,0.09794603,-0.018492728,-0.12160912,-0.10368888,0.09947783, +0.09806512,-0.114966825,0.06470765,-0.04619132,0.002325818,0.072884664,-0.120024845,0.118444756, +-0.084742635,0.09504497,0.08511315,-0.000930503,-0.07014781,0.10929936,-0.059016913,0.01741366, +0.12478626,0.055256903,-0.059675112,-0.020027101,-0.036548436,0.0045419484,0.10980654,-0.12436661, +-0.0322226,-0.09804782,-0.041479826,0.06229444,0.09951194,-0.078248635,0.085211754,0.08265424, +-0.011698723,-0.09710002,-0.05611366,0.006256297,-0.08802733,0.0348334,-0.107906535,0.019076437, +-0.11980347,-0.04437709,0.016514704,-0.050658897,0.10758777,0.024506688,0.027454957,-0.103769556, +0.07620825,0.0012947768,-0.015666634,-0.061930597,0.0925636,0.094929814,0.023884341,0.10673925, +-0.03726895,0.00067959726,0.0730463,-0.05698374,0.020211399,0.112717584,-0.027756035,-0.109712824, +-0.08352354,0.03167112,0.112418815,-0.049736887,0.085442185,0.08442429,-0.113329545,0.037925214, +0.067439035,0.02828513,0.01157245,0.013263047,-0.12262194,0.07142943,0.073161885,0.11551486, +-0.052962244,-0.0034630597,-0.008743897,0.05942604,-0.09106229,0.09632321,0.030781165,-0.10912593, +0.11138727,0.12200101,0.015219748,-0.12439862,0.11149974,-0.11998093,-0.119873986,0.036883697, +0.09295814,-0.08048689,0.03500007,-0.063136,-0.08775629,0.08731677,0.045364514,-0.077643484, +-0.07713848,-0.111981735,-0.031246603,0.021460488,-0.050939098,0.010520399,-0.06700063,-0.010095879, +-0.08933467,-0.06228049,0.07917042,0.100521564,-0.112547874,-0.09394844,0.0805621,-0.025627345, +0.007522449,0.04108624,-0.05095321,0.10346168,-0.015871912,-0.107330516,0.035581976,-0.059475243, +-0.10176173,-0.10347776,0.023999587,0.012576103,0.07358131,0.04885833,-0.07679577,0.023760736, +0.04143238,-0.08039577,0.06390537,-0.08317083,0.122696355,0.007806286,-0.028478667,0.09534532, +-0.07333355,0.04621592,-0.016003355,0.07076572,0.0034664124,-0.024314806,0.02780947,-0.01322943, +0.071995676,-0.031634167,0.11070673,0.027319744,-0.043070987,-0.010923967,-0.074632704,-0.07727668, +-0.054176047,0.08183248,0.10887949,0.04794307,-0.07705255,-0.124723166,0.04010661,0.10060254, +0.10822089,-0.11184931,0.037077725,0.03647557,0.02782622,-0.056641728,0.116396084,-0.05663158, +0.08798902,-0.109868616,0.11187282,-0.03473316,0.12131804,0.05069807,-0.0049571097,-0.10166818, +-0.08289567,0.08043198,-0.10825695,-0.013203874,-0.012069553,-0.06700161,0.027402654,0.09228186, +0.07744861,0.028239116,0.08397326,0.029417545,-0.038594857,-0.024522454,-0.105516255,0.09131332, +-0.054432854,-0.124690995,-0.00081031024,-0.024710193,-0.11144698,0.096844226,0.11488098,-0.08363542, +0.12208377,0.05448842,0.04470353,-0.0739672,-0.12176943,0.08654593,0.04552892,0.06768817, +-0.07160941,-0.10641517,0.09852831,-0.097927555,-0.10008915,0.066340834,0.050732926,0.052170843, +0.031244367,-0.000454396,-0.08794665,-0.061023697,0.06382671,-0.07291596,-0.10986668,0.06463665, +-0.047434464,0.014801994,0.030235171,0.1069486,-0.013334706,-0.12112352,0.052648306,-0.037634492, +-0.045403168,-0.020594075,0.09281571,0.046604514,0.01322937,0.037175536,-0.122978866,-0.05356428, +0.09415315,-0.04192926,0.065947205,0.117441714,0.06753342,0.06326148,-0.052978903,-0.09970248, +0.09734413,0.07710846,0.09815849,0.01371631,0.03508988,-0.07493509,-0.09895429,-0.07728188, +0.073614135,0.019041508,0.11728841,-0.03879346,0.09416835,-0.004125342,-0.019632354,-0.03915441, +0.05134636,0.06981154,0.009406358,-0.063623995,-0.09950942,-0.07873519,0.10309869,-0.053528264, +0.04359743,0.04315126,-0.017246515,0.044098437,-0.01915443,0.10870969,-0.03596817,-0.043614566, +-0.02195035,-0.042618334,0.008415058,0.11287944,-0.016781926,-0.07714142,0.114624575,0.10429153, +-0.090381294,-0.114173636,-0.08029984,-0.023890108,-0.108867854,-0.05066216,0.042117923,0.085405335, +0.01778613,-0.028640628,0.092708915,0.062241465,-0.03969796,0.12015332,0.041297525,0.10587372, +-0.058907107,-0.081446186,0.07823849,-0.012692347,0.07278693,0.026902676,0.023686111,-0.10433574, +-0.049342066,0.0903299,0.12044023,-0.033252195,-0.034893334,-0.0054131746,-0.046685725,0.059749544, +0.054901168,-0.0587067,0.045135796,-0.010719955,-0.06713885,0.07549815,-0.03006138,0.0809851, +-0.009221658,-0.067892715,0.05872141,0.02117385,0.053219944,0.0092877,-0.10784876,0.0184509, +0.026167974,0.032565013,0.11842632,-0.064476445,-0.10063225,0.0035969764,0.09747775,-0.105740875, +-0.11870204,-0.03144978,0.043903694,-0.08061959,-0.06239584,0.028433159,-0.09112105,-0.03172046, +-0.044489995,-0.050703824,-0.012209758,0.09057304,0.091593534,-0.07810676,-0.03732264,0.074922726, +0.012276307,0.033017844,0.10274319,0.009898573,-0.08832775,0.09293124,0.03719707,-0.015883446, +-0.017768323,-0.07994592,-0.066515744,-0.020587534,0.09317762,0.09529136,-0.050163895,0.08126961, +0.09742756,0.057452694,0.05443701,0.09905645,0.07069157,-0.04732442,0.067018956,-0.086569875, +0.04540214,0.023396507,-0.062130794,0.015683293,0.10960956,-0.028657407,0.051117584,-0.09691496, +-0.09427333,-0.10815263,-0.03133838,-0.07141897,0.0064960867,-0.052774414,-0.10961743,-0.03629148, +0.06005664,0.038210243,-0.08960654,0.049432248,-0.017278135,0.04182057,-0.059391618,0.066376045, +-0.07201797,0.00017744303,-0.013512343,-0.11627586,0.062691286,0.012090579,-0.096918255,0.07787624, +-0.08410025,-0.10616934,-0.011286452,0.0071364194,-0.110847086,-0.061790287,-0.04941544,0.024809644, +-0.12411782,0.037096635,0.09076585,-0.060165316,-0.0078770965,0.106346175,0.059859335,0.028575629, +0.078792065,0.08708499,-0.06709336,-0.095960826,-0.10930364,-0.0039878637,0.0040184706,-0.07452686, +0.090081066,-0.08807123,-0.058422774,0.059565097,0.09433505,0.10165182,-0.1009122,0.026276067, +-0.055491865,-0.06871387,-0.0016595572,0.09098494,0.11312863,-0.038542524,0.048722148,-0.1072422, +-0.09231828,-0.037865594,-0.053722307,-0.025734335,0.099278,-0.049669877,-0.0012224019,-0.0031813234, +-0.04427719,0.09853037,-0.083892256,-0.10227388,0.03634055,0.10607593,0.0328947,-0.060495466, +0.019484863,-0.083352685,-0.0060870647,0.10404308,0.05803372,0.11162731,0.029134363,-0.04778947, +0.07287066,0.053187072,0.007159412,0.10394898,-0.07964212,0.04461938,0.06170325,0.050492674, +0.07523392,-0.02352725,-0.026477888,-0.10103564,0.045855626,-0.06763025,-0.011528701,0.11702375, +-0.0748343,0.07927294,-0.0023805648,0.024544835,0.09567188,-0.083235115,0.09302178,0.023981988, +-0.083792105,-0.11131631,0.0013032705,0.016256317,0.0714567,0.113874346,-0.05980842,-0.07412176, +0.03416343,0.024353012,0.08383052,-0.049372002,0.0128777325,0.109846056,0.06785306,0.0704626, +0.10628888,-0.09450559,0.0903562,0.08912562,0.08517733,0.08221005,-0.109953836,-0.064503774, +-0.11548777,-0.047665015,0.073727146,-0.094673276,-0.0045855045,0.045689642,-0.12329252,0.014609292, +-0.051977232,-0.12457986,-0.098484024,0.03829515,0.015373707,-0.010625511,-0.07950351,-0.040580392, +-0.018736556,-0.094428286,-0.069083765,0.08248769,-0.04273908,0.122996554,-0.0065567344,0.059450522, +-0.054825813,-0.011478201,0.083223075,0.10021472,0.0014131069,-0.009855658,-0.12260486,-0.10219866, +-0.083070904,-0.09912287,-0.01320307,-0.005497828,-0.0051562935,0.11507979,0.09574783,0.10275999, +0.010027409,-0.005727932,-0.10744968,0.100990444,0.0348185,-0.04170485,-0.017192155,0.007868633, +0.103798494,-0.021057501,-0.09578897,-0.028543085,-0.0811764,-0.043867707,-0.09489317,-0.038564578, +-0.10133374,0.11575197,-0.02710779,0.029650882,0.022107363,-0.06644623,-0.09073509,-0.12240265, +0.018634886,0.0018370599,-0.08904292,0.029163092,0.0026989728,0.06594601,-0.11478315,-0.1096845, +-0.10503164,-0.108025596,-0.08422606,-0.064388245,0.0883843,-0.094906226,0.0021490902,-0.05127518, +-0.06063378,0.033909082,-0.08453691,-0.08440083,-0.007646933,0.046430945,-0.046009034,-0.1054488, +0.101295605,0.10293952,0.08475596,0.051633373,0.032019094,0.031030416,0.08461855,-0.036209837, +-0.0050335377,0.035888866,0.085810244,-0.10429186,0.021902576,0.12040287,-0.090231255,0.11913979, +0.029658109,-0.0038873553,-0.05413203,0.089448705,-0.019516766,-0.05843301,-0.043343782,-0.015776232, +0.09527339,0.041698933,0.039319605,-0.107295156,-0.12376529,0.00040709972,-0.0070016533,-0.04785669, +0.09974706,-0.023367971,0.06617643,0.121078074,0.08172481,-0.08585587,-0.043629885,-0.013116941, +0.05448173,0.045147583,0.10300255,-0.09347923,-0.003886357,-0.03809613,0.047201335,-0.030904442, +0.06267992,0.10409163,-0.08459887,-0.00050649047,-0.06826371,0.050887406,0.045255825,0.1117257, +-0.11190997,-0.079122275,0.1062243,0.008662507,0.10374728,-0.039129168,0.11904958,-0.00073845685, +0.087510586,0.11531106,0.09578316,0.11041115,0.054051444,0.06542447,-0.10039385,-0.031345338, +0.09153299,0.11201626,-0.07938428,-0.12257552,-0.117611915,0.03976886,0.09506342,0.01317513, +-0.06459448,-0.123576075,0.071015716,-0.0101622045,-0.009270877,0.05396907,0.05500585,0.030245975, +-0.12113316,0.08873181,0.008718595,-0.04133752,0.043408826,-0.09680389,0.10979971,-0.017540306, +-0.019329473,-0.041316345,-0.06716724,-0.10064453,-0.11796646,0.034592375,-0.06400095,-0.08042751, +-0.038719565,-0.0071981847,0.09395984,-0.007268086,0.06934345,-0.05120042,0.08847481,-0.08760372, +0.026189819,0.054343298,0.119231075,-0.027270943,0.028284937,-0.1172519,0.10858455,0.10289529, +-0.0033860207,0.027353987,-0.05192782,0.11939788,0.004147604,-0.10468066,-0.00044557452,0.06774166, +0.011906311,-0.027078032,-0.048136696,0.06630942,-0.07668541,0.06721847,0.006009996,0.105223194, +-0.06510688,-0.0042678267,0.03364241,0.07559568,-0.10644567,-0.11379255,0.11945297,0.093992144, +-0.10625161,-0.09562127,-0.08549498,-0.104601815,-0.010906637,0.07938787,-0.02233857,-0.017210439, +-0.025725022,-0.020570144,-0.11698151,-0.00087830424,-0.014220193,0.10263111,0.11963536,0.05486977, +-0.09474912,0.11841789,0.091912925,0.117331,-0.00010582805,0.054469198,0.055093706,0.027746752, +0.086557,-0.058313295,-0.03856489,0.078791216,0.06424339,0.059271544,-0.100847125,-0.06931014, +-0.093962446,-0.0884119,-0.06529668,-0.024874657,0.03131926,-0.036671147,-0.07903956,-0.01369518, +0.024542272,-0.08193521,-0.018900275,0.105325654,0.008258805,-0.0061623603,0.0990199,0.020781219, +-0.029341012,0.019647941,-0.05725412,-0.054178447,-0.005102709,0.0663759,0.09382254,0.062512204, +-0.10325104,-0.10850282,0.08432108,0.040649205,-0.018057436,-0.074683055,0.023704857,-0.03554322, +0.10156314,0.06476997,-0.0014665574,-0.116749614,-0.10205947,0.019775018,0.017019674,0.08590688, +-0.018062472,-0.11694333,-0.037865877,0.013066605,-0.04135731,0.028038636,0.09766126,0.05045028, +0.109355345,-0.025075868,0.115334824,0.07166506,-0.0657938,0.040413707,0.100744754,0.07979311, +0.1064973,0.11826222,0.061512873,0.050796285,-0.0017096251,-0.049427316,0.07303165,0.059654847, +0.007987782,-0.044755965,0.065895036,0.12485373,-0.09693281,0.022217661,0.07704009,-0.025487602, +-0.0076572746,-0.05127813,0.023758784,-0.027417451,-0.06147869,-0.096476346,-0.05274877,0.050113633, +-0.02065748,-0.07600248,-0.03234923,-0.034844175,-0.0838528,0.028840363,-0.069248244,-0.07195601, +0.040220827,0.017012715,0.01570639,0.11342749,-0.0669069,-0.010612622,0.10087335,-0.092314705, +-0.0730512,0.011873394,-0.08482619,0.0968575,0.11830069,-0.11406277,0.028180286,0.030211657, +-0.06931162,0.020030633,0.040690437,-0.027318299,0.023187518,0.081260726,0.0077966303,0.0126108825, +-0.11972499,0.018774971,-0.07109429,0.098226726,0.07111876,-0.0020525753,-0.009208113,-0.0330285, +0.09389593,-0.019134402,-0.010720119,0.10621606,0.060294673,-0.0016548783,-0.030945241,0.07456732, +-0.04248765,-0.0836111,-0.113160804,0.05102256,-0.06323776,-0.031107843,0.09301475,-0.05679059, +-0.056252927,-0.048795864,0.040418103,0.031636074,-0.009709179,-0.09078793,-0.04592246,0.0446105, +-0.065569,0.035447672,-0.050149545,0.039002776,0.089558765,0.12137687,0.057359457,0.013394743, +-0.013118133,0.043409348,-0.050522223,-0.10964604,-0.02843608,0.04052408,0.030910298,0.1031647, +0.09770505,-0.08303131,0.10245867,0.045903325,-0.09117095,0.10650256,-0.092567906,0.028409854, +0.09353897,-0.05721961,-0.105501026,0.01594913,0.035811692,0.07004745,0.09492172,0.123299554, +-0.0006028414,0.112857535,-0.09687324,-0.10013799,0.040366292,-0.108789265,0.017034903,-0.06805171, +0.052183717,-0.12056297,0.0021745414,-0.10857585,0.10116634,-0.04675874,0.0023186505,0.07497144, +-0.10488781,0.115617335,0.06372626,0.09439306,0.06814359,-0.049059138,-0.04000163,0.054877818, +0.07623546,0.053564057,-0.07084094,0.020747155,0.08355263,-0.060093835,-0.064377084,-0.06712112, +0.025009036,0.045276597,-0.09812963,0.08478926,-0.016404599,0.07793893,0.010203138,0.0020604134, +0.010063067,-0.11266366,0.016541883,-0.07274939,0.07332447,0.046559453,0.11476654,-0.051537663, +0.060189262,-0.0049894154,0.025939733,0.124446854,0.024693206,0.016362712,-0.09164651,-0.061280414, +-0.03238608,0.039423555,0.014916003,0.08468683,-0.09454849,0.08381498,0.051455617,0.040568113, +0.04510276,-0.10079661,-0.011424512,-0.06105256,0.018860117,0.0031612664,-0.06656474,-0.037723094, +0.023691654,-0.01154083,-0.1044586,-0.102322415,-0.06662387,-0.0080919415,-0.10051113,-0.068042666, +-0.0041398406,0.047074765,0.020471156,0.109765604,-0.07464711,-0.07246441,0.08144784,0.120580435, +-0.10016063,0.058416456,0.10625465,-0.09929484,0.05087948,0.042929158,-0.07379633,-0.04204929, +0.11103803,0.01757954,0.06218429,0.031886265,-0.08805302,0.08106144,0.07099095,0.0683067, +0.020482078,0.10466516,-0.12442067,-0.0014060438,0.016258389,0.015862525,0.07779896,0.1098883, +-0.019077137,-0.02416201,-0.0901729,-0.07345106,-0.1236846,-0.089983076,-0.10004754,0.0727486, +-0.03066194,-0.10687925,-0.12266362,0.096213564,-0.0100995,0.057945162,0.0005464703,0.08114128, +-0.051715106,-0.056284398,-0.0908722,0.057137102,-0.042253107,-0.11828001,0.023770332,0.0729198, +-0.0012496263,0.088054866,-0.086758405,-0.049493164,-0.051114574,0.09010936,-0.06995843,-0.11331795, +-0.124855176,0.07354875,-0.1240941,-0.09329189,0.03522128,-0.09147884,-0.065360054,0.013407126, +-0.05943975,0.03623256,-0.026164502,-0.09161392,-0.10841116,-0.10576455,-0.044388488,0.04023832, +-0.019257009,-0.112533346,-0.04508382,-0.067987815,0.08324039,-0.009101912,-0.07442507,-0.085975006, +0.11242992,0.05689673,-0.07656214,0.09764233,0.09261951,-0.1230378,-0.041915312,0.004475862, +0.012012109,0.059946775,0.0075092465,-0.007614687,0.05951436,0.10237111,0.07186213,0.016727418, +-0.02014792,0.04806952,-0.025354594,-0.09777564,0.0039822906,-0.07522237,-0.04556136,0.07187863, +-0.03186299,-0.10544813,0.013276666,0.07565056,0.11860637,0.0020040572,0.060961455,0.017714024, +-0.12041743,-0.048392013,0.03402649,-0.1038481,0.08465056,-0.098794505,0.08598916,-0.026041985, +0.025652438,0.09347734,-0.09384945,0.09195691,0.098812506,0.10957292,-0.018701762,-0.060572326, +-0.09452675,0.101169035,0.065789595,0.06688219,0.004021764,-0.109033436,-0.0932606,-0.02484715, +-0.035138547,0.07719004,-0.11724986,0.095879495,0.0429838,0.021048337,0.07380468,0.06873165, +-0.060427547,0.085843965,-0.10875301,0.064115524,-0.056836993,0.07894212,0.10357639,-0.08440161, +-0.11775282,-0.0017935485,-0.00089484453,-0.031427756,0.050839663,-0.003066048,0.031679526,-0.061577782, +0.06730406,-0.10834867,0.004477933,-0.09708527,-0.05074069,0.05247052,0.09113087,-0.038749963, +0.09734076,-0.01747033,0.008497253,-0.03361112,-0.028750911,-0.017142132,-0.11563814,0.10432467, +0.057628587,0.030893803,-0.096876964,0.11924802,-0.009177148,0.05799888,-0.030559167,0.034150958, +0.07427484,0.028848544,-0.031371966,0.07186346,-0.093020484,-0.066411436,0.06858949,0.07350862, +0.008785307,-0.07727124,0.09184219,0.081774,0.008513406,-0.04256621,-0.078802094,-0.09632437, +-0.0073524266,0.035430342,-0.01940021,0.05564849,-0.03556633,-0.11830491,-0.05839123,-0.05537042, +0.06146671,0.0026960075,-0.07718696,-0.06268193,0.039188996,0.07048777,-0.0009800941,-0.04509197, +0.04516627,-0.09005861,0.06470743,0.12054373,0.03366275,0.009849519,0.015899211,0.11534238, +-0.002090156,-0.0851126,-0.05993013,0.030745044,-0.02415888,0.06568785,-0.012787953,0.021764219, +-0.07153495,0.072637364,0.09073421,0.041491434,-0.11252555,-0.059031114,0.11179088,0.0655573, +-0.11293891,0.05239816,-0.110543296,-0.017368436,-0.050893307,0.04980643,-0.12137364,-0.08896659, +0.04159136,-0.021769747,0.018932432,0.087893024,-0.014453113,0.012075469,0.0026388168,-0.07094294, +0.035509557,0.065090835,0.115079954,-0.11314371,0.121840075,0.030929685,-0.051646978,-0.10540052, +-0.08004643,-0.089356855,-0.112021506,0.07381505,-0.06653316,-0.11657183,0.08264731,0.10898076, +-0.006200552,-0.0960899,-0.015346348,-0.047637567,0.051793993,-0.09059112,-0.034093216,0.108242184, +-0.049242377,-0.12165685,-0.09124553,0.05479528,-0.048966378,-0.027208641,0.10195236,0.047513425, +0.013226762,-0.07403794,0.06855075,-0.06551643,-0.084110215,0.11237715,0.07026932,-0.014076158, +-0.08181821,-0.047165424,0.11755115,-0.06480834,0.033235505,-0.057486385,-0.12483999,-0.08115587, +0.0790613,0.04174994,0.0037510097,0.056141138,0.055024505,0.100048095,-0.05062157,-0.10874747, +0.024347901,0.06927538,0.05894904,-0.07489404,0.024622023,-0.11252171,0.04877022,0.11688124, +0.08130148,-0.106931135,-0.08282496,-0.108563766,0.036380753,0.07944499,-0.019501954,0.044717625, +0.079716146,0.026943982,0.045238853,0.076648116,-0.10170002,-0.029058233,0.042620137,-0.033847913, +0.03252688,-0.022165135,-0.076665685,-0.06915592,0.037240863,-0.077398956,-0.05604489,0.079963386, +-0.012506887,0.060913086,0.048257962,0.05093062,0.101002604,0.07785554,0.07528621,-0.016154334, +0.08277893,-0.05173397,0.10737266,-0.0035826713,0.09516384,0.059686303,-0.11362237,-0.11008993, +0.07587102,-0.11555521,0.10071702,0.070061505,0.10866578,0.092808366,0.027357846,-0.024175972, +-0.08794041,-0.020647869,0.118869364,0.119693235,-0.11181189,-0.12079857,0.028903887,0.10936281, +0.099860296,-0.123322666,0.022146568,0.06425527,-0.10711697,0.032247722,-0.09802537,-0.010333031, +-0.122486055,0.046215862,-0.08597763,0.08342935,-0.01706168,-0.03704022,-0.08467649,-0.08233678, +-0.071942925,-0.062003344,-0.09885314,0.043631062,0.007993206,-0.01166144,-0.096386805,-0.058782145, +-0.04176943,0.078606024,-0.101579234,-0.0892048,-0.08532843,-0.04970239,0.031798795,0.08237088, +-0.024310514,0.09621929,0.0776598,0.0011870861,-0.110386476,-0.004788935,-0.11588101,0.0792499, +0.048000544,0.046362042,0.057075948,-0.1207276,-0.052610353,0.06273879,0.05954252,0.068834916, +0.09424278,-0.061369404,-0.10469836,0.079932645,-0.100223884,0.03256847,-0.020683587,0.116359234, +0.043367982,0.05237721,0.051937684,0.047280774,0.022356689,0.06041856,-0.11857736,0.01815486, +0.048186824,-0.07546568,-0.036620677,0.070607975,0.09303178,0.09211232,-0.03358586,-0.032510206, +-0.089234516,-0.033026442,-0.07837975,0.07753226,0.026971892,0.03031756,-0.052759588,-0.007017702, +0.03370425,-0.11389415,0.11789051,0.11793032,-0.008881167,-0.11046533,0.027931064,0.08501136, +0.12270212,0.1027579,-0.09945212,0.06813492,-0.025424898,0.05618401,0.094510555,0.04160571, +-0.019257516,-0.07399841,0.024494514,-0.060320273,0.008001134,0.0437157,-0.036500856,-0.07463251, +0.11318453,0.045823917,0.06758013,0.10093659,-0.101040214,0.060394824,-0.07102363,0.043827057, +-0.044834018,-0.085970476,-0.017176524,-0.024346784,-0.045759052,0.0825042,-0.115358666,-0.09406613, +-0.02353923,-0.115700185,-0.030090705,0.045026347,-0.057374224,-0.07127945,-0.06801812,0.11367491, +-0.053121,0.086594835,0.091154814,-0.004799664,0.04250221,-0.07380313,0.028982371,-0.0856249, +0.104412764,0.104742795,0.09966703,0.023196459,0.0331669,-0.025132358,0.11894302,-0.10060246, +0.12190992,0.057621345,-0.112635285,0.0012521297,-0.106304586,0.025816813,0.083827004,-0.07335146, +-0.04968603,-0.05468215,0.03483452,0.09843309,0.0503712,-0.11741795,0.03852853,-0.020183593, +-0.020290285,-0.09342523,0.08624348,-0.07763612,0.048448905,0.10616523,0.10189985,-0.07634771, +-0.08984132,0.065992326,0.052376315,0.05776158,0.06686512,0.01869969,0.12179084,-0.037586004, +-0.04773967,-0.06718981,0.10238238,0.06345819,-0.11321685,-0.048858806,0.062296838,0.048618615, +0.06772955,-0.002186045,0.019950613,-0.039722756,-0.0597762,-0.06924021,-0.10020086,0.10584335, +-0.03483443,-0.08873966,0.044086233,0.049487427,-0.020485595,-0.011082947,0.03618422,0.08422086, +0.041381344,-0.0069170594,0.11999081,0.01758127,0.04089345,0.08984946,0.12347667,-0.08559844, +0.058425575,-0.007793829,-0.031866,0.08543804,-0.102868915,-0.11979854,-0.06855945,-0.09400271, +0.01299049,0.062360182,0.0064204633,0.022739708,-0.10292947,-0.10059981,-0.06294455,-0.032281995, +0.025048703,0.012605011,-0.06330234,0.087798715,0.05956456,-0.037986428,0.08952603,0.12286508, +0.08794439,-0.03426701,0.043207347,-0.08655161,0.043197304,0.07477264,0.09019318,0.06333567, +-0.09142873,0.037245885,-0.07782224,-0.024421245,0.011208594,-0.04002817,0.08616604,0.057727262, +0.124272406,-0.0007663667,-0.035012856,-0.10431607,0.060586363,0.10677667,-0.0431159,0.03058888, +0.11636251,-0.10884483,-0.11628586,-0.085939735,-0.04765062,0.118983984,0.09516133,-0.0466844, +-0.007556379,0.01471518,0.08499563,0.10153107,0.117260754,-0.10971652,0.014347538,-0.05173035, +0.060598373,-0.04403834,-0.06554137,-0.11541097,-0.0012122691,0.103008986,0.069129765,-0.027325183, +-0.12371118,0.12101258,0.02782683,-0.08410615,-0.122425094,-0.0621095,-0.02468273,0.06391597, +-0.07333878,0.08324298,0.06950162,-0.047536105,-0.031738773,-0.01963967,0.11647123,-0.021096468, +-0.115958795,0.06321351,-0.120553985,-0.101443335,0.0996353,0.06814194,-0.01958929,-0.12263286, +0.023616359,0.1183707,0.097054765,0.09922136,-0.05144334,-0.11637989,0.0766533,-0.010606378, +-0.055246383,-0.12143318,-0.07579377,-0.11634578,-0.08926846,0.079915896,-0.066682056,-0.0027031898, +-0.122268826,0.048120365,-0.00028038025,-0.036077052,-0.09774175,-0.12232874,0.11595948,0.057680875, +-0.06161338,0.05832517,0.04978603,0.07645631,-0.07092519,-0.12281662,0.027198613,-0.0802518, +0.078354836,0.065568835,-0.12478231,0.05796796,0.00050632656,-0.08715625,0.070538476,0.04792413, +0.09634408,0.039372608,0.04321778,0.1210365,0.06279221,0.039982766,-0.11815052,0.024104357, +-0.075895414,-0.025061116,-0.02253902,-0.09619291,0.04618451,-0.07804529,0.11068076,0.047655493, +0.11900368,-0.074451506,-0.071236506,0.050440654,-0.009699002,-0.006291449,0.04657267,-0.027949348, +-0.10841668,-0.07956423,-0.09298751,0.009908497,-0.09119253,-0.068411365,-0.07472059,-0.0880035, +-0.11816113,-0.037708297,-0.028718203,-0.021542579,0.0961951,-0.041208863,0.06298907,-0.0920309, +-0.106719956,-0.032124996,-0.07509935,-0.021927297,-0.11603105,-0.03531307,-0.085542336,0.10617155, +0.00021269917,0.025793657,0.006942868,-0.010950834,0.094124794,0.09343234,-0.061130762,-0.10090667, +0.005413875,-0.022597983,0.0474675,-0.05641015,0.057545707,-0.09839249,-0.04179734,0.1242183, +0.12061931,-0.10416739,-0.06881584,-0.11801839,0.11979528,-0.05831185,0.002095148,0.083592236, +-0.029553518,-0.05793111,0.10013716,0.050326616,0.089797094,0.041108504,-0.008654594,-0.054774567, +0.025799796,0.034137532,0.053366736,-0.009735778,-0.036452144,0.03994602,0.02961205,0.05482313, +0.093309894,0.08999865,0.11260995,-0.059381932,0.0972871,-0.076539755,-0.10485628,0.089511976, +0.113985285,-0.07919617,0.12222259,-0.050578,0.102342725,-0.08069676,0.08064902,-0.016464725, +-0.123547375,0.026892394,0.09715982,-0.088220775,-0.07019308,-0.11688028,-0.112224415,0.07803391, +-0.030160517,-0.09213786,0.08005014,0.12307283,-0.108679056,0.07654248,0.048125356,0.0945262, +-0.038640738,0.055223793,-0.0013659,-0.02693437,-0.11661211,-0.08098416,0.051169977,0.06316219, +-0.025597394,-0.009825453,-0.11226368,-0.044998214,0.09182216,-0.00942868,0.06056398,-0.06220205, +0.056031376,-0.032017708,0.06963849,0.09571046,0.113085866,0.038152844,-0.115320876,0.016163498, +-0.07869224,0.08948395,0.077972755,-0.008975774,0.020354837,-0.07834704,0.10613765,-0.10676266, +-0.06531134,-0.05371,-0.0384946,-0.028271288,-0.079975694,0.07579157,0.07995571,-0.041990712, +0.079381734,0.015859067,-0.022429079,-0.06970744,-0.1118266,-0.11908044,-0.010821089,0.10083549, +0.0677131,0.07034859,0.055504575,-0.06687106,-0.03352873,0.03152567,0.11274885,-0.08978906, +0.021817327,-0.082490206,-0.10703963,-0.018033132,-0.07753584,0.12059805,0.017271653,0.057013035, +-0.039780468,0.11700165,-0.06317252,-0.113904074,-0.03788726,0.0042704046,-0.109366015,-0.07034765, +-0.11277951,-0.024566889,0.11655626,0.008002445,-0.04287365,-0.0474236,0.10524292,0.029861242, +0.035601363,0.056936473,0.06138648,-0.08465436,0.09947565,0.07010417,0.08229864,-0.045787394, +-0.012616187,0.099534154,-0.11106968,0.014700025,0.053387716,0.052487105,0.060772747,0.071982846, +0.016448766,0.09311573,-0.057887822,-0.0804304,-0.10407065,-0.08885951,0.043995544,0.021216676, +0.11050269,-0.04946935,0.084717214,-0.09563188,-0.117243886,-0.054407477,-0.11927095,0.035629258, +-0.06854214,-0.09582618,-0.036002547,0.012421966,-0.07602885,-0.095415846,0.016135007,-0.09777054, +-0.08219586,-0.05694008,0.104660526,-0.041877612,0.038949847,-0.122348875,-0.05880083,0.020000309, +-0.09862316,0.09537397,0.09985036,0.09289703,-0.023460224,0.04414077,-0.05555013,0.007413715, +-0.054075196,-0.10025486,-0.0027267784,0.092673615,-0.058913082,0.10189095,0.009476826,-0.060258538, +-0.12028524,0.08038257,0.041219085,-0.09401615,0.09583275,0.052459165,0.116893664,-0.102975756, +-0.085612774,0.108993724,0.05050361,0.041304186,0.04658951,0.06937149,0.077238366,0.058804438, +0.046698987,-0.08862366,0.064416364,-0.034004882,-0.11827235,0.031519175,0.069985464,0.0020207018, +0.010925606,0.008368149,0.01395303,0.017726824,0.026443735,-0.022853062,0.024791047,-0.026026413, +-0.023683742,-0.12046319,0.015153393,0.068305135,0.019211099,0.044572964,-0.112306744,-0.054694906, +0.027720094,-0.014414728,0.08255835,-0.08493075,-0.036536276,0.035836518,0.024922922,0.048346967, +0.06726822,0.06847659,-0.034738213,-0.095524535,0.11497265,0.115161434,0.0020885617,-0.0018142462, +0.017733082,0.019806936,-0.021265537,0.004595265,-0.027142376,-0.046677142,-0.08854461,0.054245412, +-0.12027095,-0.12145351,0.08615646,0.08158329,0.067164496,0.02194722,-0.08418454,-0.08939606, +-0.031645656,0.046738893,-0.09781368,0.12365484,0.10370307,0.035862476,0.0051648915,0.05832599, +0.027697816,-0.057069317,0.10062027,0.011381969,-0.08665235,0.123669595,-0.113088876,0.07310809, +0.09116629,-0.09005052,-0.050319165,-0.11437231,0.006200582,-0.021625295,-0.11870684,-0.0977021, +-0.07092616,0.08279021,-0.07001983,-0.021980926,0.011333987,-0.09621112,-0.07974459,0.040133312, +-0.06417219,0.119647205,0.09276262,-0.07105057,-0.11172126,0.060828328,-0.015564054,-0.12363008, +0.08759874,-0.114081725,-0.10553798,0.10137163,-0.061827675,-0.04017681,0.013177618,-0.10262883, +-0.033650562,0.059780926,0.06361911,0.02671498,0.040226355,-0.06308021,-0.12457059,0.03525333, +-0.03901416,0.06130609,0.01700069,0.07366936,-0.042957634,0.03339836,-0.03680794,0.051284418, +0.033292517,-0.06906505,-0.11892986,0.05052948,0.03733009,0.030065298,0.027853653,-0.06198375, +0.07848452,-0.11514802,-0.12261614,-0.09219575,0.072747305,-0.06359114,-0.044347897,-0.12186712, +0.051627964,0.07230973,0.035909876,0.007727787,0.020570114,-0.0033021718,0.07799815,0.08173406, +0.089328155,0.066281274,-0.056764886,0.1016936,0.009224936,0.10654314,0.06842984,0.022469327, +-0.046543628,0.09114511,0.024205059,0.028973565,0.013550654,0.107206315,0.09170546,-0.011122137, +0.07947606,0.08943552,-0.10199955,0.07945952,0.072714195,-0.02952987,0.06615119,0.024440065, +0.05036673,-0.0300107,-0.095050424,0.06850563,-0.121928066,-0.10175,-0.10220078,-0.086883396, +0.015897527,0.0442532,-0.07084139,0.08966237,-0.04100445,-0.07255529,0.0976343,0.022129327, +-0.1242169,-0.08145966,-0.10561912,0.07779008,0.064383134,-0.11337119,-0.03929238,-0.083743155, +-0.011160463,-0.09759618,0.0858005,-0.09376559,0.036249876,0.08920787,-0.10804628,-0.07703847, +-0.034358695,-0.09819102,0.08107288,-0.05705419,0.07802747,0.1089896,-0.09130432,-0.06336784, +-0.04763432,0.06870131,-0.06708026,-0.09810482,0.006448224,-0.09621188,0.061184987,-0.054287583, +-0.015974045,0.020216316,0.09801021,0.11420037,-0.03296192,0.04234323,0.09992643,0.0031138062, +0.08865596,0.032106325,0.03237696,-0.03130275,0.052035168,0.024069175,0.05974795,-0.009097725, +-0.057769075,0.021785274,-0.10469793,-0.014536172,-0.026247129,-0.11263044,-0.022476122,-0.104917645, +0.057946548,-0.05251421,-0.055912644,0.03864561,-0.06667434,-0.10451731,0.070868224,0.028252676, +-0.048724994,-0.123716906,-0.026426286,0.04515463,-0.041905075,-0.043820307,-0.08840227,-0.0708019, +-0.028664485,0.06548911,-0.12091629,-0.08737907,-0.02013123,0.025292516,0.04744816,0.010777265, +-0.109866336,-0.109510034,0.1009911,-0.089552864,0.12123503,0.0013248622,-0.11030556,0.04303673, +-0.020868465,-0.029200956,0.09747709,-0.04337196,0.015144795,0.040442586,-0.000393793,0.087307125, +0.026773334,-0.10826105,-0.12361702,0.100007534,-0.0009815991,-0.07476738,0.0781111,0.08602354, +0.06099148,0.042773917,-0.049260974,-0.03247653,-0.11636785,0.007903039,-0.042614654,0.048295036, +0.019712314,0.031698763,0.04530543,0.11654003,-0.024497792,0.024863169,-0.11170328,0.08001107, +-0.059772357,0.11609781,0.047981516,-0.061658323,0.11036599,-0.0023293197,-0.011519879,0.07254659, +-0.124467075,0.11839886,-0.04539478,-0.0871371,0.06826469,-0.11961128,0.08209838,0.07502061, +-0.012787685,0.12044148,0.07656142,-0.026383638,-0.06248595,0.120478585,-0.01516667,-0.107248574, +0.008226052,0.053640887,0.04487136,0.022854477,0.019914001,0.09117599,0.040639326,-0.11354019, +0.010869384,0.078574866,0.1106344,-0.021061882,0.11639841,0.038698047,-0.04178071,0.085568935, +-0.049952343,-0.10224098,-0.021342278,0.11995667,0.10146546,0.111786574,0.09940229,-0.1123987, +0.120465115,-0.0060305744,-0.072537005,-0.10962953,0.03725463,0.08348979,-0.001496166,-0.072685376, +0.10510786,0.049754187,-0.107694775,0.10834457,0.05491112,0.079268724,0.10230668,-0.10203487, +0.005473271,-0.09759851,0.0602818,-0.0437596,0.011014298,-0.02493669,-0.07167494,-0.0022383928, +0.11195859,-0.10794343,0.041354254,0.11427784,0.044312954,-0.124531284,-0.0061603636,-0.10986309, +-0.03137718,-0.119552955,0.10769668,0.0008519143,0.050450742,0.015376538,-0.11864194,0.038458124, +0.013056219,0.0027319342,0.008057147,0.09775601,0.10190806,-0.044437543,0.10543612,-0.036155373, +-0.043309227,0.047784492,0.04379727,0.04881929,0.070586964,0.04442939,0.0059571713,0.052985683, +-0.065500006,0.08919069,-0.07225828,-0.044542,0.041134328,-0.12235683,-0.01577419,-0.11320622, +-0.11254625,-0.049317643,-0.104496524,0.02694942,-1.5586615e-05,-0.097044885,-0.10304962,0.052947223, +0.0038793534,-0.0926992,-0.04898092,-0.079548016,0.11354907,-0.11252257,0.057287678,0.0022653043, +-0.11867763,0.015863031,0.07110517,0.10624692,0.02481918,0.09849991,-0.07415068,-0.11117834, +0.1080001,-0.08108711,-0.05068408,0.00353913,0.03681943,0.09766957,-0.041779116,0.06013696, +-0.06057042,-0.057824045,-0.01801546,0.10640511,-0.022108197,-0.0083283335,-0.09760553,0.09756982, +-0.011302918,-0.048160776,-0.12167619,-0.056399956,-0.02374281,0.021627948,0.12304883,-0.047083586, +-0.10481024,-0.015890256,0.12143019,0.06986882,-0.044162646,-0.086826384,0.020641819,0.015068695, +-0.05795285,-0.08415246,-0.007267654,0.05814013,0.038716182,-0.09122892,-0.06195636,-0.0963849, +0.012195274,-0.0056639314,-0.078693315,0.04556957,0.083732486,-0.09896983,-0.05968702,-0.075178936, +0.011924624,-0.054121703,-0.004263371,0.074102044,0.03365992,-0.09067853,-0.11220364,0.006486684, +-0.0014571697,-0.024727017,0.051460043,0.072663814,0.06408678,-0.08740099,0.110596836,0.07299186, +0.013915688,0.038526505,0.016158149,0.10411066,-0.10045004,0.020209402,0.11767769,0.01733981, +0.010517657,0.04686843,0.097562924,0.045958385,0.07445124,-0.06077382,-0.027677253,-0.080000654, +-0.11699416,-0.05517973,0.09916741,-0.068570614,-0.11963931,0.027292296,-0.035506055,0.079889596, +0.10703029,-0.00022931397,0.030908361,0.039011,0.12325482,0.016424537,0.10845198,-0.012943864, +-0.056111187,-0.11669721,0.10611582,-0.020594612,0.010343537,-0.090139404,-0.11439906,0.06486106, +0.06844655,-0.06405726,0.0651484,-0.046604335,-0.019947037,0.093251795,0.1179872,0.058270827, +-0.017469496,-0.023260131,-0.014437795,0.111302406,-0.06427644,-0.044137195,-0.027703255,-0.06381017, +-0.08488828,-0.020661607,0.12428941,-0.084076926,0.03272298,0.04475452,0.096743315,-0.018605694, +0.00042824447,-0.04192546,-0.03742957,-0.084327444,-0.05883169,0.066419944,-0.10409582,-0.123861775, +0.06904985,0.023522183,-0.10905987,0.06429337,-0.115183875,0.0936189,0.07501759,0.10876575, +0.092219844,0.12266146,-0.028725162,-0.017701507,-0.002801463,0.035588503,0.102410644,0.016213402, +0.0027011782,-0.10606699,0.09100874,-0.061778143,0.12203011,0.06880556,-0.036565527,-0.00691016, +-0.037737936,0.050509036,0.072242916,0.03262192,-0.031659976,-0.11429909,0.03645189,-0.11489466, +-0.080832794,0.004893869,0.004128605,-0.11769402,0.10564886,0.12183869,0.09026483,-0.010695428, +-0.0007843077,-0.11893876,0.0013588518,-0.11279026,0.06811765,0.051537946,0.08821136,-0.069603175, +-0.06079808,-0.049514174,-0.088631645,-0.08922851,-0.04914075,-0.069602236,0.052068844,-0.019889578, +-0.08102246,0.062414378,-0.024076909,-0.10832624,-0.028584525,-0.022492573,-0.033930644,-0.08824152, +0.017173186,-0.061565265,-0.021955803,-0.01615873,0.05560781,0.12304373,0.09466347,0.02342537, +0.10265082,-0.020125106,-0.07973237,0.10344231,-0.0052623153,0.010104001,-0.05961451,-0.05260192, +-0.070519775,0.089130804,0.029704586,-0.061992258,-0.12391722,-0.08007261,0.10912481,-0.012528494, +-0.048694357,-0.062180713,-0.07804464,0.035600707,-0.008888096,0.120789096,0.08475137,-0.0020127296, +-0.10068509,-0.022448793,-0.06412934,-0.021167323,-0.0049804896,0.07637784,0.08749524,-0.04698433, +0.10269204,-0.100186184,0.08523373,-0.1091235,-0.07686289,0.11242548,-0.116081744,0.012929693, +-0.08310877,0.029617354,-0.033410326,0.03778927,0.083480686,0.03707978,0.062182352,-0.022947654, +-0.061864525,-0.054169267,0.11759576,0.002787903,0.038638398,-0.05551149,-0.010648802,-0.020949781, +0.09264915,-0.08447416,-0.045495182,-0.013326272,0.04225406,-0.03439416,-0.026736587,0.034994617, +0.11367014,-0.11016269,-0.009755984,0.039197937,0.024414346,-0.11312266,0.04055263,-0.07788631, +-0.043726847,0.015305847,-0.09433596,-0.04034102,0.1044839,0.011744216,0.11129442,0.079120636, +-0.031170815,0.09752722,-0.09249164,0.011404932,0.027475417,-0.12462577,-0.013778731,0.0774602, +-0.019904524,-0.07176323,-0.06385769,0.108024165,-0.011280924,0.00030623376,-0.11507122,-0.11852911, +0.10285452,-0.025349632,0.014726803,-0.07364583,-0.043624952,0.006573975,0.095660165,-0.06819148, +-0.12036298,-0.1077012,-0.032041058,0.054704815,-0.04285477,0.04529716,-0.10680246,-0.10064703, +-0.111086935,-0.009681717,-0.020240143,0.11811282,-0.085950434,0.12447521,0.05436431,0.09795794, +-0.07077941,0.09813778,-0.031099215,0.02326931,0.027644098,0.107825205,-0.081595376,-0.04380852, +0.053964764,-0.017971084,-0.048067063,0.052979022,-0.027988434,0.04954289,0.051948592,-0.11220048, +0.11654355,0.06534964,-0.013250604,-0.11200933,-0.050340727,-0.119082004,0.064023614,0.012054056, +-0.030983463,0.03323628,-0.12376398,0.086609915,-0.071911514,-0.10273811,-0.10347563,-0.10461037, +0.011422262,0.049133345,0.10448162,-0.08705704,0.0628424,0.095501184,-0.018606171,-0.050850496, +0.08739525,0.07734366,-0.0605579,-0.10397145,0.03865531,0.07619479,-0.006953791,0.011712626, +0.08533716,-0.059957594,0.063785255,0.11178589,-0.025305212,-0.01156722,-0.06547473,-0.028861284, +-0.05754161,0.026162669,-0.024542838,0.061922237,-0.005558893,0.048664063,-0.024116099,-0.061913863, +0.10278228,-0.010933936,0.040510625,-0.09142381,-0.053429604,-0.05341904,0.039223805,-0.040195167, +0.048410848,-0.113588154,-0.10169877,-0.024881363,-0.09083675,0.039388284,-0.022545457,-0.02607122, +0.05214499,-4.5016408e-05,0.11390948,0.019231603,-0.03250754,-0.06385945,-0.03874013,0.0794892, +-0.08367707,-0.0063298047,-0.10753441,0.029562116,0.12133327,0.00052191317,0.02953051,0.02566047, +-0.053674147,-0.048192754,0.118840545,-0.041973367,-0.0671594,-0.11532657,-0.017890543,-0.031211913, +-0.039495543,0.06766777,-0.045498252,-0.004001379,-0.09932616,-0.011220738,0.016928732,-0.008117512, +0.10345642,-0.06150335,-0.05573249,0.04972209,0.08914876,0.09072968,-0.03314908,0.068217024, +-0.07826759,0.07623486,-0.01228182,0.080800936,-0.11838664,-0.066287234,-0.102565035,-0.111397505, +0.051611558,0.10356119,0.040096685,-0.10451031,-0.061099067,0.056339294,-0.101707906,0.009688377, +0.07970515,0.06111966,0.11910941,-0.0048106313,0.058039352,0.1156103,0.10587236,-0.0903811, +-0.1184403,0.03294061,0.08827883,0.020513251,0.013838381,0.067263424,0.035986558,0.097504705, +0.023030445,-0.08444978,0.0028038323,-0.11909242,0.12187725,-0.097579196,0.037561655,0.10618487, +-0.10487135,-0.05321829,0.0065137297,-0.092778236,0.038425177,-0.037117824,-0.06276266,-0.036287412, +-0.03283833,0.075587586,0.089948684,-0.033848375,-0.04384084,0.051197752,0.059372798,0.057026237, +0.030862778,-0.06965864,0.09708829,0.023638055,0.11710796,-0.011215389,-0.115811706,-0.004356265, +-0.034371912,-0.042074397,-0.009866744,0.083953634,-0.034145147,-0.037303776,-0.06433852,-0.069530666, +-0.048287272,-0.07974762,-0.010538653,-0.004320562,-0.061342016,0.0030985624,-0.06908822,-0.0038956702, +-0.103683114,0.11939688,-0.106729925,-0.023127988,0.07476017,-0.11329022,0.12236565,-0.021668434, +-0.0130688995,-0.09852798,0.092248544,0.03877914,0.11623885,-0.09022409,0.05133736,-0.09347573, +0.053206787,0.064887285,-0.0670816,-0.09645975,0.10236864,-0.051290125,0.078402236,0.08744764, +-0.066755995,-0.05588399,-0.04368508,0.04746124,0.056075484,-0.035978466,0.0010820329,0.037104517, +-0.015949473,0.10081871,-0.081921816,0.1178045,0.042284712,-0.022317722,0.01438871,0.012744442, +-0.019118562,-0.07146157,-0.095686495,-0.120388225,0.07722679,-0.07367061,-0.10489248,0.06572318, +-0.08733006,-0.0975105,-0.112168744,-0.089035094,-0.076130524,0.02220273,0.011962578,-0.10296112, +-0.08450991,-0.01201494,0.04904093,0.03660129,0.09965046,-0.010016695,0.12359837,0.0846667, +0.10530867,-0.08346596,-0.022844598,0.0717939,0.038376212,-0.013918072,-0.03344409,-0.04626824, +-0.11646587,-0.08133581,-0.12414573,-0.070539296,0.047855124,0.018758625,-0.04912527,-0.08975513, +-0.10423751,0.022446275,0.012384996,0.00275895,-0.023845315,-0.0751778,0.013897896,0.04932405, +-0.123673335,0.07515007,-0.023555845,-0.05870068,-0.050918013,0.05353017,0.019417897,0.008875936, +-0.099781826,-0.075101346,0.05089593,-0.11283469,-0.102248296,-0.040031552,-0.033054084,-0.09713341, +0.07909757,-0.02097933,0.05342938,-0.027803019,-0.102123424,-0.1072924,0.09437488,-0.066191, +-0.052190766,-0.11069909,0.04887384,0.027652487,-0.08220819,0.04834129,0.114782915,0.12340841, +0.09344873,-0.027544945,0.030279264,-0.03063494,-0.03367378,-0.09600411,0.030635446,0.012098059, +0.115233555,-0.11498396,-0.08780433,-0.036847368,0.09053525,0.10064867,0.09195502,-0.05298662, +0.038818136,0.041574597,-0.019848317,0.072598204,0.07783076,-0.07538098,-0.09042774,-0.09913997, +-0.07192117,0.119993374,-0.017509788,0.031911418,-0.090492204,-0.033185482,0.019116446,0.005125776, +0.10708955,0.108438656,-0.0871975,-0.11310549,-0.064956725,0.08670607,0.041525215,-0.019102722, +-0.024955705,0.11201441,-0.04274051,0.076570675,0.11538559,-0.04407035,-0.0678955,-0.082509816, +-0.03439659,0.02253431,-0.038584396,-0.06287043,0.08559778,0.06284465,0.08373347,0.0036747158, +0.04793553,0.12198466,0.10547672,-0.09946574,0.039969906,0.09609814,-0.01918991,-0.09828286, +0.11029558,-0.016835451,0.115623236,0.04729046,0.019529074,0.124985814,-0.07381888,-0.11124337, +0.06585921,-0.07784511,-0.121525556,-0.014427364,0.012489408,0.0016508251,0.08325958,-0.019755766, +0.107014894,0.012687355,0.077424586,-0.052513853,0.058716863,-0.11208463,-0.08503668,-0.055005774, +0.028534412,0.0977795,-0.019840702,-0.11997627,0.098133594,-0.11106515,0.10351509,0.07821846, +0.08281572,-0.11896016,0.023819715,0.100925535,0.05146888,-0.022953019,-0.052622557,-0.04160124, +-0.01977314,-0.0032230616,0.014096394,0.06217657,0.0023469478,0.10130255,-0.035061523,-0.013342038, +0.087022275,0.10581818,0.00088362396,0.060902774,-0.008053884,-0.042488337,0.020520717,-0.07545185, +-0.11707012,-0.07197744,-0.10792974,-0.035483032,0.042275116,0.053183526,0.1156037,0.06523009, +0.0058043003,-0.09737231,0.09597711,-0.08887717,-0.08771002,-0.05473812,-0.123248994,0.0068306327, +-0.042837337,0.008195981,0.097409174,0.118710116,0.07924792,0.03061305,-0.10981327,0.06849502, +-0.07127996,-0.09692486,-0.013725102,-0.039013132,0.107633814,0.1148601,-0.07918203,-0.08433321, +0.099751785,-0.036683828,-0.060607344,0.07168335,-0.08156587,0.07193084,0.017208293,-0.07758346, +0.0836042,0.11434843,0.10369232,0.08062786,0.032862887,0.08232005,0.07870367,-0.043292403, +0.08276041,-0.013825506,-0.059535906,0.095485836,-0.0785784,0.104497656,0.029918432,-0.028606042, +0.118324205,-0.06275213,-0.080031425,-0.03954041,0.0651073,-0.11544426,-0.10924061,-0.12454367, +-0.0005822629,-0.07918635,0.063528165,-0.013905928,-0.04658176,0.02556108,-0.026361436,-0.022289604, +0.01835467,-0.10587314,-0.10754472,0.12477073,-0.05058533,-0.07586983,-0.03288047,-0.013673559, +0.04913886,-0.0055314004,-0.076062515,-0.0004324615,0.023396969,0.039356887,0.075819135,-0.0470168, +-0.05326724,-0.024177507,0.008603424,0.0777415,-0.03908108,-0.004991621,0.0026088804,0.06815681, +0.03154689,0.05552107,0.0056480616,-0.053556323,0.09081085,-0.0056200624,-0.07106529,-0.009151623, +-0.066573456,0.10161327,0.007896498,0.07719906,-0.03240484,0.119182676,0.07663967,0.07356571, +0.031865314,0.052926257,0.11891192,0.07998884,0.047568858,-0.086104736,0.036637142,-0.021184549, +0.025034428,0.03463036,-0.117323846,-0.05872993,0.061872467,0.04466945,-0.06414312,0.076616555, +-0.0039298683,-0.07473943,0.11195624,-0.10283506,0.013471156,-0.013613507,-0.12229644,0.015981078, +-0.04833372,0.07825042,-0.03532286,-0.11398585,-0.04753886,0.0412848,-0.03451416,0.096472204, +0.08137782,0.09821549,-0.025592402,0.11408955,0.11963199,0.11549856,0.017742634,0.0027408004, +0.017307505,-0.03606026,0.021227524,-0.08248873,0.10641836,-0.011719927,0.071415424,0.06280941, +-0.03878759,0.011740193,0.105287135,0.08312386,0.12430611,0.06331752,0.047852755,-0.1107457, +0.10936226,-0.025265321,0.052446112,-0.04974021,-0.04342556,-0.06974526,-0.08604604,0.07301545, +0.07142475,-0.10869242,-0.06345937,-0.04047197,0.009451926,-0.09348628,-0.05806437,0.124323025, +0.09928036,0.1036208,0.11173171,0.06560321,0.007459253,0.09569402,0.066618174,-0.046977222, +-0.07296756,0.11759366,-0.019559935,-0.04193954,0.03952074,-0.042478442,0.0066925436,-0.012736887, +-0.046095967,0.104208514,-0.018623248,-0.09918842,0.00035527349,-0.017255157,-0.12033452,0.023461461, +-0.0689553,-0.11787146,0.109567404,0.05696653,-0.12323949,0.12369804,-0.022036642,-0.023749888, +0.09371628,0.06990942,0.02483663,0.09840298,-0.11287865,0.11708903,0.09210764,-0.10653706, +-0.015785456,-0.118480906,0.09035447,-0.027325973,0.020833477,-0.02603738,-0.07709065,0.016821608, +0.12356135,-0.10201123,0.002773434,-0.06800616,-0.09065436,-0.11456199,0.084140286,-0.044987738, +0.034928754,0.017091036,-0.0011667013,-0.022895738,-0.05290346,0.034805194,-0.007734269,0.11896928, +-0.022139996,0.09263371,0.065625295,-0.058485046,0.1164172,-0.122885495,0.1069835,-0.011896238, +-0.035610154,-0.07831374,-0.09575005,0.05354218,-0.012178674,0.021167919,-0.060284525,0.07864982, +0.014011845,-0.017359018,0.0499167,-0.10331491,0.055146784,0.092001036,0.095579445,0.10503121, +0.042097196,-0.107555345,0.02117981,-0.1211656,0.09770958,0.061185032,-0.072766244,-0.051680207, +-0.07473232,-0.049185216,0.016173303,0.061164916,-0.080366716,0.110331476,0.09725991,-0.11485253, +-0.103002414,0.048243612,-0.035862684,-0.02963695,-0.060047656,0.034450457,-0.10073152,0.07352094, +0.01882857,0.024855316,-0.06048259,0.044047132,0.057207733,0.015109494,-0.0513303,-0.011646479, +-0.019326657,0.03704977,-0.0893867,0.122350916,0.12248321,0.042304143,-0.055078745,-0.04541509, +-0.027322784,-0.04834579,-0.098769575,0.109286204,-0.0509115,-0.11731918,-0.09156184,0.059974328, +0.08238554,0.07241398,0.06201169,-0.09757587,0.12218949,0.06270619,0.010689601,-0.0240722, +0.0126913935,0.09699075,-0.008369416,-0.08218373,0.10162489,0.041232675,0.061040565,-0.10152818, +-0.1062087,0.046932057,-0.108571604,-0.099526584,0.06762917,-0.021095559,0.08639343,0.09290381, +-0.0651094,0.08358635,-0.066329494,0.03720209,0.038515583,0.04580891,0.072588935,0.05742328, +0.097968206,0.12040545,-0.025182188,-0.11622405,0.07515393,-0.01696767,-0.08046636,-0.107601106, +-0.070231825,-0.049763635,0.100457236,0.067901075,-0.1006725,-0.065617844,-0.07508755,0.11151649, +-0.045528024,0.005133942,0.0068326443,0.07690379,-0.065178335,-0.032259136,0.11916767,-0.1158469, +-0.039186627,-0.0854395,0.09091668,0.09062384,0.103732035,0.091607735,-0.07178971,0.081067935, +0.107449755,0.084227234,0.0016165227,-0.018510923,-0.0025785714,0.06094642,-0.07718,0.09620014, +0.12266329,-0.055140212,-0.004956886,0.0076148957,0.11236499,0.027167365,0.084512755,-0.040202826, +0.10748871,-0.017569304,-0.10881941,-0.1119013,-0.08801527,-0.080881506,0.038264588,0.09477721, +-0.06410609,0.10353993,-0.10864836,-0.06136702,0.059679314,-0.009443715,-0.03541346,-0.076943636, +-0.0034677684,-0.014428943,-0.098263726,-0.07358059,-0.035201386,0.008562878,0.09283835,0.05382341, +0.07281424,0.067535,-0.01607421,-0.022043183,0.008028254,0.11293876,0.06670901,-0.03141731, +0.08234288,-0.07274586,0.07387434,-0.0008713156,0.018606499,0.02381529,-0.0026851445,-0.088590294, +0.040824383,0.00076143444,-0.08020261,-0.06987104,-0.087815136,0.028882653,0.06993824,-0.09063333, +-0.080074266,0.016454995,-0.103401944,0.118662566,-0.11796309,-0.059297934,0.07694821,-0.06465855, +-0.029899687,0.061776266,0.061335146,-0.09701191,-0.050129026,-0.047942877,0.02086392,0.12245001, +-0.03237918,0.10466635,-0.015175596,-0.08805403,0.0047050267,0.04672827,0.035919875,0.035987377, +0.07793021,-0.077290714,-0.014598936,0.059479713,0.0627314,-0.019403353,0.022451267,0.078263685, +0.11771765,-0.015479475,0.09924446,-0.066290975,-0.00642021,0.029812545,-0.09019782,-0.10840173, +-0.11310221,-0.11646573,0.027916446,0.013705254,-0.111566976,-0.10431759,0.050001144,0.01795128, +-0.032824293,0.06353155,0.043273956,-0.05165316,-0.044176802,0.0754886,-0.06152375,-0.047194093, +-0.03077884,-0.044007838,-0.042031884,-0.12497039,0.08740772,-0.11943044,-0.08125229,0.02112858, +-0.021401793,0.04846354,-0.04871504,0.002431944,0.08443923,-0.010163024,0.039348856,0.039686352, +0.10152583,0.06854601,0.07089786,-0.10911457,-0.114755034,0.04531555,0.0625713,-0.0557611, +-0.08793038,-0.054457113,-0.124905586,-0.086971775,0.028390199,-0.122350246,-0.07122457,-0.10478988, +-0.012027368,-0.10569249,-0.09562586,0.057789415,-0.018688962,-0.091691986,-0.017675743,-0.11459924, +0.011097059,-0.07620144,-0.10021834,0.060573548,0.082228824,-0.04929541,-0.0046500415,0.104077294, +0.015320346,0.081406504,-0.12012114,-0.09811181,0.046364695,0.032128572,0.061018765,-0.0617072, +0.0811203,-0.08184032,0.026622921,-0.01691395,0.044317752,-0.10913284,-0.052875757,-0.122897804, +0.0017822534,0.08216867,0.05686918,0.074453965,0.035633832,0.106907904,-0.012876883,0.06608206, +0.055777296,-0.054503143,-0.05678436,0.0013672858,-0.02811277,-0.08730887,0.006406784,0.07735902, +-0.11859541,0.04433936,0.085601404,0.09910545,0.12429814,0.016695172,0.11097789,0.00044859946, +0.052102864,-0.08071284,-0.005415857,0.06290284,0.09258847,-0.0068245977,-0.0507572,0.028522894, +-0.05201949,0.097076535,0.06082897,-0.0075163245,-0.118609235,-0.122437105,-0.04681565,0.0032442808, +-0.062208697,0.0948395,0.10375285,0.047731012,-0.017136171,-0.0651167,0.065650985,0.10721369, +0.039939925,0.08619371,-0.036597773,0.06305626,-0.0015414804,-0.092923,-0.02182363,0.08759898, +-0.07398194,0.06809057,0.057356313,-0.07679869,-0.027342156,-0.059766367,-0.045160174,-0.07888864, +-0.005027756,0.050851613,0.085754365,0.11525391,-0.010713354,-0.035916835,-0.09168266,-0.09684101, +0.08949807,0.012280375,0.047364503,0.1233021,0.0031109005,0.057759255,0.069759816,-0.12172884, +-0.021093577,-0.121536106,0.0027490556,0.078578696,0.042421132,-0.06486341,-0.10222764,0.053086057, +-0.051225215,0.10178462,0.07133144,0.016545951,0.047627777,0.102457985,0.093805164,0.048425123, +0.008692741,0.004977435,0.118336454,-0.03000778,0.049312294,-0.10702732,0.10889611,-0.0691178, +-0.07492013,0.023511827,-0.006533593,0.1157587,-0.072341174,0.024217114,0.041636765,0.0077272058, +0.07711041,0.03991896,0.04928781,0.09967773,-0.024885237,0.05225998,-0.06885864,0.09558104, +-0.024369553,0.017013624,-0.11245592,0.017969504,0.09060456,0.046575963,0.039679587,-0.015311599, +-0.050132856,-0.10674411,0.11822821,0.017876208,-0.06367533,0.004183769,-0.072066456,0.08794461, +0.015695274,0.11496849,0.037069067,-0.027101964,-0.05848162,0.06078817,0.07559094,-0.032644227, +-0.098035485,0.040032506,0.065114126,0.12427254,0.06534052,-0.11573066,-0.09409164,0.0011605769, +0.0854774,-0.12337114,0.062306717,-0.046466857,-0.1150064,-0.11384903,-0.016193286,0.043183073, +0.06433223,-0.039339647,-0.0017968118,0.101028994,0.017154068,-0.008133069,-0.10814661,-0.08679551, +0.06824288,0.042335734,-0.111546904,0.07232295,-0.082586974,0.10861629,-0.10430023,0.050411537, +0.008015409,0.041904166,-0.05492735,-0.049348816,-0.009614646,-0.0071367323,-0.03301683,0.034174725, +0.10552287,0.042808518,-0.01323086,-0.007045552,0.061736897,0.11482231,-0.04381217,0.008132622, +-0.09491426,0.11940338,0.008475482,0.08565824,0.05908549,-0.108632505,0.028524533,0.11659503, +0.06058407,-0.031460598,0.0470874,0.10310094,-0.077053726,0.028231874,0.059935898,0.06916782, +-0.11983265,0.108722955,-0.033821642,-0.035373002,-0.07240778,-0.02360937,0.076584995,-0.024034142, +0.119997814,-0.08665466,0.07337077,0.04767932,0.029595569,-0.04771538,-0.005327478,-0.019314408, +-0.03509672,0.020802379,-0.04763931,0.1193811,-0.119537726,-0.041296884,0.08454619,-0.056680724, +0.087125376,0.09624216,0.075412124,0.033349454,0.12111874,-0.105874345,-0.097764686,-0.094068676, +0.02954267,0.021846741,-0.0893534,0.012598351,0.04258284,-0.024545804,-0.11142434,0.037428424, +-0.073418185,-0.08792345,-0.028050587,-0.06796928,-0.07115948,0.11913434,-0.07416184,-0.12403923, +-0.10343495,0.06875576,0.050154924,-0.0067932606,-0.0762867,-0.038828447,-0.10195163,0.03177452, +0.037187397,-0.1075134,0.05826366,-0.10521828,0.019957066,0.11730397,0.01673527,-0.09963775, +-0.066433206,-0.009367272,0.012818754,0.12437588,0.008929968,-0.01617229,-0.09509428,0.09940687, +0.04955037,-0.10273023,-0.03399089,0.12071529,0.03690113,-0.120224535,0.022046402,0.048580825, +-0.010673732,0.098843515,0.05414626,0.11382383,0.043998584,-0.07456936,0.009045273,-0.03890507, +0.053152844,0.032055497,0.05165015,0.08511889,0.08247946,-0.097585574,-0.05819571,0.08179659, +0.025095582,-0.023231938,0.023972496,0.006155029,0.026019797,-0.020864055,-0.07570678,0.044012234, +0.025580898,-0.11257522,0.11286467,-0.0042438656,-0.10143344,-0.004354,0.061128512,0.068972245, +0.12011513,-0.07727745,0.05252953,0.0025253743,-0.10179447,0.042789638,-0.1104728,-0.013402581, +0.11715454,-0.120311394,0.042998075,-0.12213321,0.089801356,-0.054275468,-0.027510047,0.0968499, +0.020671263,0.02169387,-0.08158189,-0.11361793,-0.04701738,0.05092758,0.010076538,-0.059664667, +0.06624161,-0.056229517,-0.054962486,0.02376835,0.07682975,0.019012436,-0.065152094,0.04634106, +0.07391061,-0.04433933,-0.033342004,0.122234866,0.003285095,-0.04351452,0.05248615,0.036321342, +-0.047532246,0.00040343404,0.002339512,0.09144527,0.00933291,0.016498804,-0.11365245,-0.07876976, +0.10492255,0.01789695,-0.091525495,0.09382178,0.06333138,-0.08388543,0.11010599,0.022902414, +-0.07341768,0.11425243,-0.10924469,-0.07592736,0.067688495,0.023625389,0.09133421,-0.08225401, +-0.038041756,-0.04906261,0.06901443,0.10013023,-0.06707461,0.1030685,0.12320605,-0.020158783, +0.0065739453,-0.11907476,-0.1125073,0.015604854,0.0864431,-0.084573984,0.062005028,0.0040195137, +0.12317312,0.063039556,0.109579206,0.05883336,0.02226612,-0.12498008,0.08310373,-0.010627165, +-0.052212074,0.049128875,0.05509968,0.09688319,-0.0077932626,0.1096787,-0.0005979389,-0.072199926, +0.05343239,0.08628507,-0.045210317,0.04278341,-0.07828057,-0.04763888,0.115020454,0.027848125, +-0.071546674,0.062574,0.10948248,0.04759358,-0.0035865605,-0.08301534,-0.11638521,-0.0621465, +0.12033036,0.0014724731,-0.100430995,-0.10517493,0.049586967,0.06477474,-0.1199981,-0.06017974, +-0.050493374,0.030700803,-0.0015827715,0.016222566,0.0010500699,-0.03807108,-0.10465695,0.007579714, +0.056552142,0.02329354,-0.030623108,-0.05360444,-0.030183837,0.1163948,0.09775323,0.1068155, +-0.116330564,0.12062009,-0.058204398,0.0075811744,-0.04960826,0.015292138,-0.007846534,-0.06406066, +0.08357209,0.05086039,0.029046789,-0.12024537,-0.0998258,-0.017811522,-0.06514545,-0.006177753, +0.043350667,-0.116216645,0.019656032,-0.07409033,-0.09216659,-0.077814266,0.08275862,0.08630362, +0.12173371,-0.015537679,0.026912615,0.08782461,0.05816683,0.07749587,-0.05789092,0.0305707, +-0.08556166,-0.058779746,0.05382879,-0.05383043,-0.10053763,0.12031056,-0.11365937,0.08650699, +0.118997455,0.06988886,-0.098305225,0.12188414,-0.06446424,-0.092100516,0.06835601,0.10155186, +-0.06904557,-0.124005675,-0.047178432,0.071989134,0.07569735,0.013328329,-0.07139745,-0.05154991, +-0.1113289,-0.007943973,0.10777964,-0.099801496,-0.039146483,-0.08910774,0.016052067,0.10055369, +-0.111007854,0.0912914,0.09574567,-0.035502523,-0.07126136,-0.10276586,0.0060310364,-0.11851524, +0.0034669638,0.009177893,-0.108578876,0.05937913,0.035157934,0.10497482,-0.103368655,0.00052173436, +-0.10921195,0.058846667,0.00014102459,-0.03669113,-0.043714717,-0.03967303,-0.022001043,0.034698337, +-0.041473404,-0.010771915,-0.11257884,0.043262646,-0.09231949,0.11340368,0.074466005,-0.09815925, +-0.10599303,0.09252687,0.009331375,0.0030158013,-0.039194122,0.016146138,0.094485536,-0.014446914, +-0.1000898,0.053130046,-0.090294704,-0.016074076,-0.090197876,-0.02709207,-0.025452375,0.061998174, +0.015454486,0.12486127,-0.03562352,-0.07686095,-0.063289374,0.0039556473,0.10259293,-0.082962275, +0.04815118,0.048508227,0.0013771355,-0.11408931,0.10905519,-0.080332756,0.025167868,0.008604169, +-0.06408544,-0.0022467673,-0.008435905,0.1119616,-0.09305301,-0.1233172,-0.114242315,-0.03864725, +-0.079086244,0.017697483,-0.08322652,0.107415155,0.014765337,0.0064005107,-0.105283916,-0.09748492, +-0.080258355,-0.09621121,0.10238798,-0.12330428,0.022344783,0.107004985,-0.12443811,-0.11445913, +-0.0819962,-0.11476666,-0.099176794,-0.06362486,-0.016510412,-0.026586965,-0.005267665,0.0042181164, +-0.050557762,0.018148616,-0.036604017,-0.013883889,0.109192714,-0.01372537,-0.03217864,0.036414534, +-0.06337237,0.096190736,0.086552724,-0.124296844,-0.081672415,-0.03963785,0.039291188,-0.08640377, +0.008887172,0.01336886,-0.06939165,0.10313392,-0.03947459,0.103966266,0.063072965,-0.1169153, +-0.087311506,0.013302356,0.071449205,-0.11630061,0.018628478,-0.03188318,0.12331408,-0.04919167, +0.026220948,-0.00011946261,0.019588515,-0.089797035,0.040544152,0.051378295,-0.023912609,-0.039808527, +0.11400613,-0.048715666,0.09005101,-0.11305481,-0.07857649,0.022844195,0.05985965,-0.045953974, +-0.004052505,-0.0739059,-0.025973499,0.080135286,-0.027439296,-0.015874177,-0.077522814,-0.07908863, +0.10889198,0.10755627,-0.04544495,0.118334636,-0.03141062,0.065827444,0.081569836,-0.10763554, +-0.08531955,0.09200773,0.11389227,-0.030657575,-0.055378616,0.10767804,0.123237535,0.014729276, +0.060661033,0.06497027,0.093720734,-0.08295171,0.05917594,0.026909158,-0.007611558,-0.042598367, +-0.09546028,-0.11643772,0.06942929,-0.061240822,0.0051158816,0.052482218,-0.06319687,-0.10474123, +-0.031034634,0.004491389,0.063350335,0.0543357,-0.011506975,-0.06437196,-0.10718033,-0.11374651, +0.01243189,-0.039821997,0.009851098,0.078300476,-0.042192265,0.06675732,0.11751954,-0.12318373, +-0.06456977,0.10912843,-0.047206596,0.08985016,0.012518138,0.02331543,-0.10613239,-0.068047166, +0.03446099,0.1207086,-0.032062933,0.039284483,-0.022361413,-0.08328001,-0.098928735,-0.0358212, +-0.015290618,0.01266484,-0.117029235,-0.03611985,-0.04160987,-0.11460632,-0.12416893,-0.06614292, +-0.12055017,-0.119280234,0.030407473,-0.0319328,-0.011174202,-0.07019311,0.058123127,0.07706526, +0.043061107,-0.11051661,-0.07282849,0.052559435,0.011775389,0.048481047,-0.12376745,0.0032131374, +-0.031538174,0.103032544,-0.012663722,0.083772436,0.0072228312,-0.06306349,-0.042937458,-0.074821904, +-0.036220133,-0.12426816,0.10220353,0.11048284,0.06174849,-0.009046286,0.007628605,-0.0700344, +0.021148086,-0.094132364,0.10992743,0.07646406,0.051208183,-0.10038197,-0.022367805,-0.027178958, +0.023965418,0.10635713,-0.013526231,0.08290762,-0.05860646,-0.0037027448,0.09047671,-0.000768736, +-0.014651611,-0.094729275,-0.0034672767,0.076877,-0.019005239,-0.0034086555,0.09083955,-0.036465287, +0.012533173,-0.090057865,0.05110222,-0.075050384,0.034911737,0.047761068,-0.08811326,0.10403216, +-0.09757683,0.031059325,-0.07661937,-0.016588047,0.01669319,-0.090493456,0.08304402,-0.004012838, +-0.04196568,0.0037060678,-0.03851995,-0.06077163,0.053973854,0.11139813,-0.0014833957,0.002896279, +0.0423574,0.045863867,0.057899818,-0.06283161,0.0770538,-0.009188563,-0.06444992,-0.06402427, +-0.045122653,-0.00914894,-0.041165754,0.0054378957,0.0668636,-0.07938093,0.010907888,-0.0070709735, +0.030706137,-0.06674959,-0.12238887,0.07283105,0.10922791,-0.109666005,0.1146137,-0.017651677, +0.04638937,0.011384726,0.11044632,-0.039085716,-0.086671725,0.045827657,-0.0807057,0.024301156, +0.019882321,0.034492657,0.09384331,0.0114399195,-0.08802588,-0.0237775,0.08785662,-0.118691176, +-0.10211517,0.04372336,0.028769895,-0.101067245,0.09195426,0.08627711,0.041365728,-0.0043090433, +-0.018348232,0.07682729,0.04494697,0.038073495,0.021597624,0.060900703,0.057278544,-0.010366172, +-0.119380474,0.10486573,0.105216876,-0.10742861,0.061920732,0.0029227585,-0.0914745,0.07726772, +-0.097962916,-0.109923914,0.0060213953,0.1131638,0.0046679825,0.039835155,0.09440097,0.085099146, +-0.034069315,0.070329055,-0.0017772764,-0.112262875,0.078860566,-0.11944705,-0.034918964,-0.0036699772, +-0.1017503,-0.044049338,-0.11781636,-0.008932248,0.09264973,-0.05245991,0.0015798211,0.1076643, +0.10091907,0.00446178,0.039890096,-0.03543806,-0.1164121,0.0075180978,-0.031928554,0.12114972, +0.075484484,-0.10053603,-0.09411977,-0.057670325,0.0559434,0.10153642,0.0849756,0.07260193, +-0.10451849,-0.07819301,-0.07934421,-0.021443903,0.09467539,-0.06937994,-0.11565502,-0.07070471, +-0.041673988,0.06066771,-0.035006016,0.016301095,0.010179251,-0.03679894,0.094489485,0.066045746, +-0.088950485,-0.065616906,0.04072906,-0.07513587,0.093382105,0.031472966,-0.06735055,0.004560545, +0.09774253,0.028700992,0.036958396,0.12492493,-0.007957384,-0.1121203,-0.046361968,0.10070808, +0.101979405,0.10163124,0.06972039,-0.046417147,-0.072320506,0.09950322,-0.05959995,0.091444746, +-0.11671184,-0.09641959,-0.0509865,-0.079026744,-0.04203169,0.09868376,-0.092893064,0.016612574, +-0.010788262,0.01680328,-0.006713867,-0.06557013,-0.04318686,0.018804595,-0.11801839,-0.10375553, +-0.11769749,0.07128519,-0.083986595,0.102317676,-0.08737062,-0.043329075,0.100971594,-0.11575395, +0.051050335,-0.120278805,-0.09095338,-0.04383427,-0.095063895,0.06290437,0.10184814,-0.05420102, +-0.105110064,-0.09636369,-0.08304563,-0.009934872,-0.046502724,0.1232011,-0.061541453,-0.08435339, +-0.1122348,-0.031178042,-0.121872455,0.115289554,0.09438975,-0.055144086,-0.0789765,0.04004565, +-0.07183184,-0.12267715,0.084110186,0.011811703,-0.10295068,0.0627047,-0.02542235,0.115180135, +-0.05597803,-0.10588436,0.026630536,-0.124079704,-0.03628947,0.01124391,-0.048841923,-0.09056181, +0.0045931935,0.0029857755,0.0015755892,0.089736804,-0.02135183,0.0743119,0.076160595,0.10425179, +0.0035517216,-0.048990354,0.017965868,0.12462936,0.06549935,-0.09638077,-0.057184115,0.082191974, +0.0429392,-0.06250949,-0.008199066,-0.053778917,0.09712474,-0.08301605,-0.0041463673,-0.10027853, +-0.114907175,-0.064316824,-0.091013804,-0.056643426,0.06812371,-0.044177473,0.06901495,-0.043731347, +-0.07120855,0.007349521,-0.12460804,0.04703845,-0.047839448,0.027301863,-0.037293136,0.04466635, +0.09877682,0.00910224,-0.11208062,-0.027182668,-0.01812251,0.0018523633,-0.004834816,-0.01937516, +0.12296499,0.09467366,-0.05026661,-0.03700562,0.10646328,-0.061957,-0.045952782,-0.07263604, +-0.04399626,0.08304076,-0.082595274,-0.0037258565,0.051556394,0.023675308,0.078752115,-0.055979237, +-0.0842285,0.00416936,0.050223038,-0.09975381,-0.091883406,0.09325805,0.09000735,-0.054242358, +0.08608872,0.048578963,0.11895129,-0.01969862,-0.059412584,-0.021354333,-0.01073271,-0.0725967, +0.025316462,-0.05621335,-0.03819549,0.04637797,0.034578487,-0.07062529,-0.049381584,-0.088456616, +-0.07960114,0.017021582,0.0024000704,0.094363734,0.024493903,-0.001170978,-0.0150933415,-0.09540169, +0.07705733,-0.107510656,0.041695505,-0.017308712,0.030009225,-0.105497345,0.08064209,-0.004926935, +-0.10662328,-0.10222973,0.09663825,0.040715814,0.021570563,0.02674523,-0.0063795745,0.031611905, +-0.015882626,0.12275998,-0.10084605,-0.12384763,-0.07286088,0.11011349,-0.09120357,-0.079525545, +0.067066535,-0.065979555,0.12334627,0.038119644,-0.11065142,0.016912505,-0.013944939,0.116086364, +-0.09032078,-0.006887451,0.11287539,0.05606301,-0.0603085,0.06762946,-0.053335696,0.061963692, +-0.026332125,-0.057832077,0.05577624,-0.013702482,0.03385675,0.09578128,0.027925208,-0.02689135, +0.048996896,0.023370788,0.08269131,-0.11629559,-0.116803735,-0.07723327,0.08522569,-0.023158833, +-0.0090741515,0.10071078,-0.026525706,-0.03914365,0.096305,0.055421844,-0.042750597,-0.034195825, +0.11097418,0.05061744,0.10394631,0.03296034,0.09164491,0.0013528913,0.11585462,-0.10520634, +-0.012377948,-0.009230569,0.1147162,-0.08887823,0.008047432,-0.016735539,0.054591596,-0.0026157498, +-0.0117688775,0.0072206855,0.04302779,0.113150835,-0.046138585,0.08789034,0.060711846,0.051770613, +-0.12194614,0.02013968,0.036802977,-0.0014719218,-0.11836529,-0.06860767,0.0711766,0.021847159, +0.030353203,-0.053656667,0.030640349,-0.087774694,-0.06657232,0.043423504,0.074441984,-0.11528231, +-0.041263133,-0.08386223,0.053282082,-0.07094456,0.027085155,0.11359522,0.022693694,-0.019318953, +-0.12079458,-0.029768258,0.0019186735,0.00013695657,0.059632346,-0.11987476,-0.112148285,-0.068703145, +-0.06181258,0.048552796,-0.043217465,-0.10379402,-0.054387644,-0.058119074,-0.07468939,0.039549634, +-0.034972996,0.035840273,-0.103628054,-0.05884868,0.013431773,-0.069799826,0.019946411,0.026572585, +-0.10101344,0.009566158,0.10237859,0.12152025,-0.040164173,0.12436013,0.11001232,-0.009056002, +0.0033532828,-0.008829117,-0.029799893,0.062090427,0.009574056,0.09010479,-0.083898485,0.08626062, +0.0633772,0.109086454,-0.11360529,-0.026381195,0.04505588,0.09059963,-0.09638251,0.080203995, +-0.11704801,0.08474907,-0.09950265,-0.082118616,-0.03473954,0.016889527,0.12245484,0.0306326, +-0.008190319,-0.00912264,0.0563626,0.10268444,0.005271435,-0.09818274,0.062366694,0.020156622, +0.066675246,0.044467673,-0.08027446,-0.11658649,-0.034011036,-0.090138465,0.03850667,-0.050365582, +-0.033031344,0.0056661516,-0.05651553,-0.09717116,0.033214778,-0.09741202,-0.10961603,-0.061057597, +0.078602284,-0.037372082,0.01310271,-0.117804006,-0.07388988,-0.07660696,-0.019850105,-0.05199279, +0.11101258,-0.030172303,0.008201256,-0.027655944,-0.08795649,-0.0802806,-0.065915704,-0.10345389, +-0.023752391,-0.024170563,0.08691445,0.015562117,0.027103826,0.055776,0.061291575,-0.10282245, +0.07992573,-0.10831797,-0.040711388,-0.10943633,-0.02155225,0.045082808,0.054619536,0.08844036, +-0.06444125,0.018768132,0.04526922,-0.08836201,0.022455633,0.11727697,0.045036674,-0.08757374, +-0.027918473,0.11824994,0.085459515,-0.03933561,-0.08692065,0.12150118,-0.08187935,0.07244328, +0.09219855,0.113839105,-0.042864323,0.013078287,0.08221349,0.08944245,-0.041049793,0.0020430386, +0.022602335,-0.0011310726,0.055528924,0.054423362,0.113038,0.03570853,-0.057603106,0.08267425, +-0.09652446,-0.124404475,-0.062171966,-0.09591983,-0.071203604,-0.047853976,-0.06284697,-0.110991165, +0.008574441,0.040104374,0.0023186952,0.06889191,0.063681796,-0.08171065,0.11346124,0.07317379, +-0.021604195,0.060938254,-0.12095779,0.11202668,-0.08032912,-0.0930628,-0.030957729,0.06659645, +0.004483551,-0.027693018,0.012766063,0.07892595,0.06749539,-0.036624297,0.056392968,0.035637125, +-0.010465547,0.034486502,0.0011831969,-0.0072244555,-0.11072855,0.056316003,0.07970977,0.062389582, +-0.12341648,0.09789258,-0.032703206,0.010687441,-0.0031429976,-0.11884415,-0.08666223,-0.095978975, +-0.11054294,-0.031684905,0.09157418,0.059928164,-0.053013325,-0.095465586,-0.0324032,-0.057176128, +-0.097052574,0.050069213,0.063380614,0.011073068,0.09186527,-0.11050974,-0.094778106,-0.007409245, +-0.054372072,-0.015171528,-0.11809598,0.05076486,0.11478002,0.009134695,-0.044421613,-0.004196897, +-0.059742674,0.0009059012,-0.10773714,-0.106874645,0.060498744,0.06344806,0.028538942,0.02671142, +0.05595626,-0.086646214,-0.046697617,0.094316915,-0.053162083,-0.01673153,-0.10584836,-0.01272352, +0.111140355,0.02430752,-0.041856334,0.0702948,-0.03789012,0.11074832,0.08499244,-0.034936175, +0.06137368,0.06412043,0.016230345,0.046666443,-0.102733105,-0.050952822,0.106365144,0.045553207, +-0.013444543,0.09899852,0.07232854,-0.10217267,0.0038339496,0.015856236,0.054263324,-0.11947775, +0.040364906,-0.03112173,0.022534087,0.004734844,-0.0070295334,0.08489998,0.11463833,-0.003355667, +0.07448937,-0.063441575,-0.10502298,0.0898013,0.012097895,0.09621823,-0.06243652,0.08770269, +0.038093418,-0.040315658,-0.03282897,0.029489785,-0.02031511,0.124185994,0.057865888,-0.042053014, +0.07331343,-0.08822884,0.010566786,-0.0027135462,0.0372086,-0.05712779,-0.06515166,0.018568277, +0.08114742,-0.0041433126,0.030474931,0.028036863,0.06941442,-0.022822335,-0.024136871,0.089656025, +0.09782791,-0.07725021,0.065584466,-0.11841668,-0.11258829,0.028394103,0.10984023,0.05152978, +0.07886724,-0.051191285,-0.11280762,-0.052978143,-0.06493212,0.100140154,-0.08876628,0.10490973, +0.07943007,0.029585063,-0.019812971,-0.100515366,0.020624459,-0.07416031,-0.049649432,-0.086918786, +0.030007109,-0.033411935,0.06472327,0.10670914,-0.014867082,-0.008607954,0.0653204,-0.008055478, +-0.09535594,-0.05755809,0.094168276,-0.027790606,0.0076907873,-0.050603494,-0.08787799,-0.03160681, +-0.017257303,-0.05162123,-0.015390933,-0.116507426,0.004135862,0.04940252,-0.112912804,-0.08746852, +0.034217507,0.031292394,-0.08364381,0.08947696,-0.047323436,-0.057991162,0.07229686,0.10513878, +0.114054576,-0.08002713,-0.08948167,-0.024438232,0.015423864,-0.0833129,-0.031516835,0.021403894, +0.02047798,-0.105066046,0.02510202,-0.07199611,0.07012883,0.06602864,-0.015600264,-0.01918815, +0.05466783,0.04525116,-0.019841239,0.08649732,-0.09127535,0.05212654,-0.06541991,0.10517858, +-0.02314569,-0.088755965,0.07452555,0.10204086,-0.07443015,0.0423356,-0.061553165,0.041279495, +-0.033275485,0.022929117,0.12152228,0.014871314,-0.0228744,-0.019414231,0.11048086,0.054926664, +-0.06570804,-0.055632234,-0.12302534,0.095511645,0.045047566,0.008624151,0.08372161,-0.11359751, +-0.03495872,-0.045150876,-0.12254679,0.019874781,-0.11056171,-0.08920422,-0.08240157,0.0990112, +0.06454009,0.08635825,0.058757454,0.051569834,0.007041797,0.07891166,-0.02501531,0.12051453, +-0.11972451,0.02723302,0.076436,-0.124845326,-0.06894311,-0.04931344,0.07225381,-0.014777541, +0.103091925,-0.09248999,-0.05520083,-0.026984096,0.09703261,-0.10177715,0.12373142,-0.08451317, +-0.02452971,-0.07250632,0.08164787,0.03911729,0.058007747,0.120281994,0.056705594,0.01961872, +0.07785842,-0.123880655,0.038471624,-0.12467818,-0.06323749,0.05036527,0.031179726,0.017694205, +0.03591305,-0.10654348,0.11741276,0.066287845,-0.09545559,0.09491941,0.042209536,-0.018385336, +0.0077165365,0.029669538,-0.021572337,0.05767317,0.02696979,-0.11484158,0.097556114,-0.11499138, +0.035353214,-0.041838452,0.06401929,-0.0733635,-0.057709455,-0.08152512,-0.05939494,-0.03733553, +-0.12349062,-0.005388722,-0.013180286,0.04614097,0.12371647,0.03464897,0.057870895,-0.1233387, +0.019404441,-0.08586225,0.014312327,-0.068262234,0.010957554,0.007113412,-0.05156344,-0.08037989, +0.008308604,-0.12182914,0.092330515,0.088768184,0.019781768,-0.10297924,-0.04605414,-0.07013637, +0.073290154,0.0741722,0.07908717,0.036765337,0.028800607,-0.11163068,0.04646586,-0.01359126, +0.0059746206,-0.1219601,-0.103560075,5.1647425e-05,0.05409059,-0.0077943057,0.022133604,-0.08425647, +-0.012350857,-0.060376883,-0.03080456,-0.09091352,-0.046423405,0.11772619,-0.117115304,-0.061402112, +0.05651243,0.042296663,0.028265655,0.10542394,0.10174799,-0.0013260245,-0.060116887,0.11967434, +-0.036182523,-0.03284964,-0.019267067,0.04677449,0.02809675,-0.1108211,0.05498594,-0.053221077, +-0.086960524,-0.0067441463,-0.09825669,-0.051812172,0.024828658,0.12198074,-0.017633572,0.036636367, +-0.04508005,0.030931398,0.083681986,0.11715768,0.0068194717,-0.12360677,-0.08333069,-0.106222466, +-0.009293035,0.11646047,-0.0024815053,0.06867999,-0.022660911,0.02884923,0.10007714,0.09510368, +-0.08799745,-0.03545764,0.0520287,0.08266334,-0.069135934,-0.03287807,0.026099399,0.0008045286, +-0.08873828,-0.0014654696,-0.049168944,-0.044251114,-0.12385093,-0.035269544,0.11334814,-0.031864464, +0.085132495,-0.05912572,0.11960687,0.11065236,0.033369377,0.10610926,-0.043667942,-0.09045765, +0.08433187,-0.021910146,-0.003144756,-0.08543363,0.0042606145,-0.027019128,0.043729156,-0.03086166, +-0.09663068,-0.09635311,-0.10400103,0.07183051,-0.08122079,0.11489172,-0.11548978,0.106704205, +-0.06803107,0.094387054,-0.007382214,0.032007486,-0.09665389,0.0010389835,-0.022644058,0.00050634146, +-0.018291533,0.0006567836,0.09129448,0.023289382,0.020253882,-0.037712917,0.09004812,0.11724049, +-0.060826346,-0.035343543,0.11250125,-0.11564624,0.11931495,0.09652056,-0.019034848,-0.021079272, +0.045383573,0.029874772,0.051607266,-0.054253563,0.08957414,0.11940621,0.07983874,-0.07895625, +-0.04135686,-0.039754406,-0.03177239,-0.018326,0.07146992,0.047677726,0.09536961,0.08294219, +0.072864026,-0.042051375,-0.029700935,0.021731362,-0.052474618,0.042818204,0.006611362,-0.12363291, +0.06604764,0.09182228,-0.05509235,0.048022524,-0.08701222,-0.040327772,0.022861198,0.082827315, +-0.08397828,-0.060723513,-0.09020282,0.09252237,-0.032165855,0.06855151,-0.10174537,-0.07758038, +0.07473968,-0.057282403,-0.12072499,0.031826943,-0.037607476,0.0824793,0.0538449,-0.014640108, +0.08282201,0.051994294,0.007303536,-0.055421904,-0.056959867,0.035180584,-0.10491945,-0.014008924, +-0.0048577785,0.111202165,0.060777485,-0.116793334,0.08983339,-0.05543849,0.099086136,-0.060658053, +-0.05543688,-0.07606739,-0.014424309,0.04127401,0.024547607,-0.08530389,0.106097266,-0.1047432, +-0.12170182,-0.035586447,0.061936527,0.094054386,-0.04925877,-0.050084203,-0.0491475,-0.030522063, +0.061975792,-0.011568308,0.053136766,0.04101491,-0.032264397,0.071282744,-0.030923337,0.08675796, +0.046716183,-0.046791613,-0.046630338,-0.0685852,-0.056589425,0.015908435,-0.09789564,-0.04964751, +0.045785964,0.091791525,0.021504715,-0.06843796,0.056104273,-0.06393652,-0.075543,-0.086799935, +-0.014464915,0.03945832,-0.10497314,-0.055200845,0.036524802,0.09400794,0.01689063,0.041224778, +0.121133804,0.00048978627,-0.017898053,0.045521095,-0.007190749,0.09015782,-0.106950074,-0.05816497, +0.091931686,-0.013326049,-0.036111996,-0.03987378,0.107009634,-0.08577758,0.081021816,-0.10060343, +-0.053297713,0.007287264,-0.034358323,-0.093983695,-0.09240928,-0.007503137,-0.10813621,-0.07795526, +-0.09228277,0.041632473,-0.103036135,-0.038333178,-0.044235796,-0.052786946,-0.06608671,-0.060171455, +0.060985282,0.056851864,-0.12221548,-0.023657188,-0.108990416,0.082872495,-0.02164957,-0.09139258, +-0.083174616,-0.012981623,-0.046070516,0.032714114,0.0018776953,0.11859943,0.09145017,0.01949723, +0.1219116,-0.048019826,-0.0018219501,-0.06754856,-0.09720284,-0.11101307,0.08148232,-0.071010396, +0.032777622,0.05889654,-0.00999023,-0.05293022,0.07204224,-0.02471608,-0.074497044,-0.013349846, +-0.09774314,-0.075001135,0.118965134,-0.08571157,-0.04181753,0.01660055,0.12391417,0.022502258, +-0.054542467,-0.109998405,-0.030192465,-0.009514555,-0.10770093,-0.050065547,-0.015061006,7.18832e-05, +0.0141498,-0.005099073,0.11829752,-0.102357656,0.10988596,-0.06480612,0.11410484,0.013554871, +0.070767224,-0.11979355,-0.020629182,-0.016005367,-0.05991657,0.1135374,-0.014316812,-0.07827105, +-0.04258585,0.03982413,0.017816305,-0.055028066,-0.031372964,0.12484677,0.12415174,0.06706929, +-0.104314506,0.06434563,-0.030156493,0.03867401,-0.023540348,-0.05227171,0.07467775,-0.10834046, +-0.036867827,-0.10191162,-0.06471807,-0.058687314,-0.08048928,0.08590628,-0.019598648,-0.08255941, +-0.08973792,0.038538113,0.12408592,0.08634487,-0.020778358,0.022448152,0.00045011938,0.07234946, +-0.047143877,0.048838332,-0.020562246,-0.093101695,0.10022883,-0.05914557,-0.037357762,-0.075349316, +-0.024680674,-0.11321594,-0.07048181,0.03931488,-0.085336074,-0.038685158,-0.08477163,-0.022951439, +-0.0045102984,0.11342126,-0.055800855,0.093778506,-0.09281118,-0.020197824,0.008198544,-0.06763223, +-0.07379502,-0.085145935,0.03739147,0.10531445,0.103830144,-0.115205705,-0.019777864,-0.034266755, +-0.079343915,0.0006324202,0.11242825,0.05523467,-0.06817788,0.10941307,-0.025423035,0.07039748, +-0.015679017,-0.08016802,-0.05437067,-0.039087966,-0.04944934,-0.06384879,-0.07215178,-0.0013689995, +0.03343363,-0.0036438257,-0.10257241,-0.010515347,-0.11533244,0.04695013,-0.019704789,-0.10965589, +-0.10300012,0.03366509,-0.10960689,-0.089929536,-0.05773528,0.009203821,-0.07973306,0.07252045, +-0.076666266,0.10604374,0.0767661,0.11384536,0.124024525,0.10749821,0.05999586,-0.101194814, +0.0059934407,-0.062385842,0.069738716,-0.09613879,0.09636186,0.119004786,0.031162605,-0.016771078, +0.09363827,0.074376,0.09304921,0.08392878,-0.04914379,0.120908454,0.07262242,0.0039980263, +-0.02475205,-0.069856,0.058646813,-0.08390416,-0.09566781,0.116927564,-0.041646466,0.078952804, +-0.11930774,-0.08944835,-0.07063259,-0.08347261,0.0035296232,0.036030427,-0.050004825,0.06694147, +0.114644215,0.04412557,0.06386176,-0.0025012046,0.10743892,-0.056313217,-0.10421705,0.06844349, +0.0705006,-0.11970663,0.11830613,-0.0807105,0.11953108,0.10638827,-0.11543271,0.112494275, +0.012874484,-0.02499476,-0.060863778,-0.10251227,0.12305418,0.04687226,0.071103215,-0.0489247, +-0.0107945055,-0.119611025,-0.029730245,0.060178697,0.06320016,-0.06467761,-0.093850985,-0.11308257, +0.049623743,-0.009612501,-0.015107706,0.09841849,0.11247058,-0.11008933,-0.11885221,0.08412765, +0.04077798,0.04113786,0.12051223,0.053093612,-0.043572366,0.055592224,-0.012277454,-0.081839874, +-0.0833856,0.029355034,0.10514103,-0.051163048,-0.06632361,-0.07478845,-0.011090711,-0.024758324, +0.00068436563,-0.121601015,0.071340874,-0.0466149,0.0007788092,0.003167197,-0.12367964,0.07385279, +0.025577247,0.040297657,0.075611115,-0.103785306,-0.027037576,-0.0011454672,0.029438391,-0.033714265, +0.015162602,-0.1094251,0.030903488,-0.024375007,-0.065296754,0.08164002,-0.073832795,0.088495016, +0.105792746,-0.106042415,0.04954441,-0.0073622614,0.07334618,-0.095360115,-0.096065074,-0.06164387, +-0.10916223,0.050632164,0.045219094,0.034013465,-0.06570755,0.1219158,0.040309355,0.036994696, +0.11637147,-0.106077656,0.04600267,0.09322496,-0.1139971,-0.0028256178,0.044332147,0.06969699, +0.07994509,0.085662484,0.09995666,-0.040239483,0.020812318,-0.08117904,-0.08331096,0.110602215, +-0.042612538,0.10959412,0.050212413,0.0116625875,-0.008226305,-0.09095739,-0.118478045,0.02116093, +0.12228039,0.09533054,0.11623193,0.03276126,-0.03702292,0.09886545,-0.044143707,-0.030797139, +-0.10335879,0.04821229,0.070160344,0.04551004,-0.016130626,-0.01118204,-0.11386976,-0.029616013, +-0.09582387,-0.056938663,0.10079241,0.034653574,0.006131962,-0.10620783,-0.038987994,0.00975737, +-0.101679966,-0.10125737,0.11311516,0.019497707,0.07717718,0.010277808,0.058999106,-0.04282245, +-0.051507667,-0.026468351,0.09213838,0.0037087053,-0.047685474,-0.045683697,-0.028202266,-0.07729486, +-0.022768542,-0.12168965,0.04930389,-0.12380487,-0.027550727,0.08457033,0.06490354,-0.0693838, +-0.07744257,-0.08130391,-0.10766618,-0.022129938,0.068860605,0.09146699,-0.123900965,0.02965486, +-0.02459012,0.0603552,0.04636082,0.0047994405,-0.124332964,-0.12045665,0.08940007,-0.004242778, +-0.037531078,-0.011126727,-0.027143538,0.112954795,0.05962728,-0.07677296,-0.06796597,-0.07953633, +0.03900057,0.09753722,-0.0780804,-0.11638147,0.0040611625,-0.07942867,-0.05751893,-0.07136437, +-0.04465446,-0.039309725,-0.0809007,0.05811891,0.0303372,0.11768545,-0.09428415,-0.03263259, +0.00885503,-0.036289647,0.09844153,0.052341044,0.10698223,-0.09352657,0.002065599,-0.07895833, +0.11135095,0.028936133,-0.03768322,0.10704452,-0.10439801,-0.0911973,0.0149896145,-0.119820505, +0.06709698,0.06545746,0.02267307,-0.07200056,0.024509236,0.080220014,0.11601038,0.06886646, +-0.1050127,-9.1418624e-05,-0.11432761,-0.066761404,-0.092429,0.035857663,0.100291625,0.10544361, +-0.102680534,-0.028600052,0.026625544,0.009751186,0.054671273,0.110057384,0.120800674,-0.0047495514, +-0.030266136,-0.046444878,0.054616317,0.027219936,-0.03148982,0.093780965,0.11577317,-0.110984415, +-0.10101773,-0.05505474,0.07248978,0.04998076,-0.04272455,-0.059389204,0.12222333,-0.041775405, +-0.10908577,-0.025498345,-0.035710305,-0.096956,-0.08733033,0.102346495,0.11652249,0.020743266, +0.020311266,-0.065515295,-0.107020915,-0.0383922,0.08076547,0.044977635,-0.101977274,-0.016845375, +0.020636812,0.08999923,0.08708878,0.11961889,0.0487276,0.018968984,-0.10568662,0.10773884, +0.08593482,0.037867352,-0.061765388,0.08637005,0.07835071,-0.0009289682,-0.118416175,-0.010344446, +0.12426664,-0.10541037,-0.1010119,0.0002001077,0.05324115,0.08679956,-0.04478562,0.1143159, +0.06290205,-0.020643234,-0.07710846,0.028390378,0.056714088,0.117320135,-0.117859155,0.020751953, +-0.124292955,-0.12450999,-0.11375813,0.124284476,-0.1073018,-0.08123028,0.05250001,-0.04938823, +0.049996942,0.02288735,0.023192212,0.099831834,0.013658166,-0.015603617,-0.025194094,0.058318347, +0.1122593,0.02183859,-0.09249231,0.017532423,-0.032364964,0.06230037,-0.009932399,0.07330704, +0.01629296,0.031147093,0.08618669,-0.017474577,-0.11818716,-0.10607441,-0.09686859,0.02217269, +-0.09401788,0.00085398555,-0.036615968,-0.105936855,-0.017966151,-0.061222404,0.078600615,0.042568028, +-0.06818037,-0.11513081,0.046624392,0.06209743,0.0048270375,-0.08521061,-0.11708705,0.10975751, +0.061328933,-0.027873501,-0.071437106,-0.10630903,0.039115265,-0.08959855,-0.124925524,0.055307597, +0.025215715,-0.10380736,0.027513474,0.11667231,-0.11922003,0.008536994,0.028010517,-0.071453094, +-0.013213158,0.10477829,-0.025805414,-0.035700083,0.015662596,-0.05028701,0.021655858,0.023445293, +0.005429238,-0.027491271,0.021635756,-0.0049086064,0.043959558,0.050692096,-0.0039612353,-0.07599652, +0.09077175,0.06539893,0.052588016,-0.0048774034,-0.090313986,-0.060514018,0.10430518,0.026892528, +-0.067892805,0.1158358,0.020201594,0.046877548,-0.06895438,0.118124336,-0.06457576,0.07180232, +0.09071824,0.0019119233,-0.06274553,-0.039729133,-0.08399989,0.06970455,0.02431281,-0.11692697, +-0.104804724,0.014302969,0.10261282,0.105341986,0.04358016,0.10503617,0.100150436,-0.11304988, +-0.044328928,-0.03100875,0.0030781627,-0.109493196,0.06596215,-0.07677238,-0.051426277,0.019297987, +0.08345878,-0.102729484,0.024976224,0.066510335,-0.013415515,-0.027991042,0.008559823,-0.0045431256, +-0.022665665,0.0734299,0.010683075,-0.08626206,0.069125205,-0.07413258,-0.10837105,0.00024040043, +-0.03655675,-0.09049091,0.08153251,-0.007551402,-0.07900733,0.08973886,0.051731095,0.07929742, +-0.11371392,0.10208656,-0.0030223876,0.11513999,-0.087762415,0.10726006,-0.10165183,0.0410233, +-0.039939106,0.08649635,0.029043332,0.09306045,0.04567787,-0.07836878,-0.005976692,0.10250023, +0.10430841,0.10811485,-0.025466725,0.04436551,0.0010370612,0.0061243027,0.059535995,-0.07550831, +-0.09533064,0.07133056,-0.10960622,-0.07018466,-0.079911605,-0.07993615,0.123616055,-0.014425844, +0.049610272,-0.03111054,0.013413116,0.064352944,0.049478874,-0.094500974,0.027295515,-0.11578496, +-0.08089171,-0.11394061,0.08044945,-0.054115206,0.1237883,0.07288264,0.048420385,0.063387066, +-0.11974315,-0.008900091,-0.08268504,0.10234745,0.09354295,0.036587775,-0.05695723,0.078586265, +0.08156769,-0.08951481,0.1052255,0.11957413,-0.08719829,-0.1181016,0.050259396,0.04789594, +-0.12451655,-0.10372129,0.12294492,0.08058275,0.08104579,0.010506898,-0.10892163,-0.058935866, +-0.12201904,0.07648052,0.010223761,0.0060731024,-0.046954513,0.09436846,0.08629905,0.101060554, +0.09208754,-0.05436717,-0.07334024,-0.03402549,0.03229466,0.020923778,0.008227065,-0.034669265, +-0.07423815,0.04760042,0.0843894,-0.09563658,0.02201879,0.05444783,-0.058551088,0.1058768, +0.11565904,-0.018440574,-0.10435411,0.024899885,0.112665504,0.09917796,-0.12356025,-0.037996143, +-0.09060244,0.11938137,0.05318357,0.051114112,-0.0816493,0.08009808,0.09811245,-0.07479651, +0.041055128,-0.06902233,0.072304726,0.07931256,-0.011501297,0.012041837,0.07582915,-0.09531118, +0.021381214,0.08128367,-0.036036655,-0.014676467,0.09122042,-0.045607284,-0.06492354,0.05631508, +-0.05569145,0.12128079,-0.057034075,-0.05447012,-0.10871132,-0.11153941,-0.07872358,0.111329675, +0.087481916,-0.06466138,-0.008691743,-0.003269419,0.11605121,0.015535682,0.007243097,-0.025935456, +-0.045134068,-0.044360235,-0.008552402,-0.08470276,0.10901779,0.102006406,0.012366727,-0.092245, +-0.05667375,0.05708085,-0.012862146,0.06957959,0.04884994,-0.006416142,-0.013400406,-0.05282107, +-0.034232482,0.05783941,0.036087826,0.114619344,-0.08083911,0.015873149,-0.039596424,0.09028952, +0.08526939,-0.09574315,0.073149964,0.06687908,0.039053157,-0.036458984,0.085118875,0.02425231, +0.0481966,0.059560627,-0.04287854,-0.09707281,-0.0064982176,-0.10180162,0.12390411,-0.10521062, +0.10203819,0.07470828,0.12471107,0.0016313046,-0.013030112,-0.107610166,0.03680812,-0.10126525, +-0.09483062,-0.03352657,-0.044782296,0.07252011,-0.008234113,0.067075804,0.11667512,-0.090838954, +0.011647865,0.089133486,0.08596952,-0.0017079115,0.02477637,-0.116608456,-0.117698744,0.04446368, +0.094368935,-0.11811055,0.05342123,-0.020238623,0.04372613,0.07840651,-0.094900236,-0.09084554, +0.03500487,-0.058217615,0.107969105,0.010381579,0.0136027485,0.0826536,0.08789641,0.03195417, +0.016886607,0.005640328,-0.026171088,-0.12088652,-0.015734836,-0.06098768,-0.09528975,0.08816229, +0.11786495,-0.007857919,0.118394375,0.0943553,-0.038208544,0.06714389,-0.052909806,-0.08611007, +-0.029537708,0.055294022,-0.05168335,0.10724434,0.05104281,-0.051832363,-0.014487982,0.10875304, +-0.02186349,-0.082332745,0.047073245,0.020007238,-0.10009219,0.084740326,-0.094890684,-0.066566035, +0.01236324,-0.033094674,-0.04891053,0.016385436,0.042055488,-0.104225904,-0.11465016,0.01249972, +0.03328477,0.01433523,-0.10653429,0.05422008,-0.073548466,-0.018741056,-0.05709365,-0.05985801, +-0.08595982,-0.030806616,-0.117599234,0.037491307,0.10432649,0.067297414,-0.00015877187,0.1221579, +-0.017771333,-0.057063058,-0.06540249,0.061034605,-0.024494857,0.0513649,0.013702303,0.12295674, +-0.11430134,-0.08270161,-0.11305031,0.05823277,0.124105856,0.12440394,0.07708344,-0.04289642, +0.089832336,0.05566986,0.0148745775,0.087861255,-0.121517584,0.11174926,-0.11012374,0.11772004, +0.10226515,0.095902294,0.056455866,0.0824496,0.08036281,-0.11586322,0.014780641,0.047694355, +0.026383951,0.06739935,0.10486756,-0.060626507,0.006756529,-0.011605129,0.07809508,-0.07503317, +-0.10211277,-0.114383385,0.09683564,0.09810746,0.092643455,0.044098094,-0.041968614,-0.059067056, +0.017967984,0.02150087,-0.004421428,0.04939127,-0.052093536,-0.11618869,0.03863673,-0.042106077, +-0.067903206,-0.069694266,0.030231759,-0.06353234,-0.048389196,-0.12423749,0.025235683,0.045183226, +-0.058921322,0.10553761,0.06555085,-0.014263675,0.07283971,-0.03590557,0.07443024,-0.060626075, +-0.09078944,0.1066927,-0.024707824,0.050256982,-0.04165481,-0.10950746,0.056131214,0.088302, +-0.09717199,0.035654455,0.090105176,0.036412016,0.0776127,-0.06321885,-0.062291637,0.100914955, +-0.04841803,-0.05343093,-0.024463922,-0.0016180724,-0.078385785,0.013979107,0.00993827,-0.022721916, +0.0052160174,0.019282818,0.008625701,-0.05805686,-0.002986133,-0.06593323,0.09462872,-0.06218128, +0.038760364,-0.08445567,0.071272254,0.10944761,-0.10627201,-0.0066987425,-0.02113685,0.023174778, +-0.022526205,0.013487443,0.076503724,-0.105180964,0.09301469,0.08873053,0.030057669,0.00096172094, +-0.053922236,-0.035421148,0.07281485,0.029473335,0.048330218,-0.08430484,0.12001476,0.05239941, +-0.034328863,0.0601096,-0.11783685,0.087690055,-0.03602682,0.010181099,0.076439336,0.0468456, +0.08381079,0.018237635,0.08926408,0.09037258,-0.10247345,-0.120761424,0.06210129,0.0626449, +-0.027841166,0.07850161,0.010846421,-0.05201356,0.06792602,0.0694679,-0.0760487,-0.008821398, +0.10210556,-0.06883538,-0.07971263,-0.015580848,-0.06304018,0.06271915,-0.036094174,-0.11445482, +0.05891721,0.05860871,0.10069777,0.0052688867,0.04937917,-0.012637809,-0.0001745671,0.0823677, +-0.010442987,0.03461902,-0.055802777,0.03094691,0.050099626,-0.12405403,0.0537346,-0.0015409589, +-0.115149826,-0.011409596,-0.032693967,0.052479982,-0.07420464,-0.052136734,-0.04957664,0.00972864, +0.051741645,0.035784632,0.04781483,0.06665926,0.09474705,0.030854434,-0.11285013,-0.09111963, +-0.073363036,-0.053996637,-0.029042274,0.017897353,-0.030795455,-0.089693874,0.033992857,0.11500552, +-0.05476308,0.010180905,0.092669174,0.07496512,-0.045013353,0.016438916,0.0130087435,-0.058971345, +-0.11380644,-0.017696738,0.04254237,-0.00828141,0.038965717,-0.105676904,0.062480688,0.08130595, +0.0027339458,0.0650575,-0.010281473,0.02213806,0.054373384,-0.0057062656,-0.007709697,0.07810868, +0.04021941,-0.108310044,-0.018651843,-0.0780078,0.11323978,0.12469867,0.09927724,-0.049407095, +0.04003769,-0.10391161,0.08129723,-0.013904959,0.1147946,-0.09593834,0.0005772561,0.058345005, +0.046408653,0.039300844,0.09060031,0.06835668,-0.094722316,-0.072181016,0.0052930266,0.027135164, +-0.10228008,-0.03307581,-0.010288537,0.09735982,-0.12319589,0.09947294,-0.11546576,0.05191791, +-0.012166828,0.065032825,-0.0862385,-0.0038767606,0.0019193292,0.015616998,-0.11009207,-0.0065858215, +0.053200707,0.066549465,-0.06447786,-0.021206424,-0.10284373,0.009541228,-0.07531613,0.05320874, +-0.027647913,0.09386021,0.03566952,0.08827965,-0.049176425,-0.083586544,0.08018781,-0.03676884, +-0.006581515,0.116318524,-0.017199636,-0.106663704,0.03430143,-0.08312155,-0.07671654,0.014857352, +-0.0935902,0.009704769,-0.06646417,0.09035356,-0.040879264,-0.057211965,-0.04964629,-0.12309745, +-0.015857473,-0.035686925,0.117727265,0.072947174,-0.11918303,-0.032049775,0.02262947,0.11135554, +-0.00030083954,-0.057521433,0.11199729,-0.08345096,0.11700277,0.07373263,-0.00038588047,0.011540577, +0.1107288,-0.09992409,0.051276684,-0.08125359,-0.11678721,0.07301484,-0.085960835,-0.07589191, +0.105812564,-0.01362589,0.109960705,-0.11919011,0.066337675,0.04970883,-0.03770201,-0.023707688, +-0.07360029,0.029646784,0.034893066,-0.1033653,-0.019269258,-0.070968196,-0.1134837,0.07398981, +-0.022445247,0.032475054,-0.11675605,-0.0868316,-0.035753652,-0.09930988,-0.049322784,0.069911405, +0.012515724,-0.0635176,0.11993751,0.10483907,-0.042664155,-0.011238724,-0.11738537,-0.027007401, +0.04633239,0.0950471,-0.10072608,-0.056004435,0.036040843,-0.10805747,-0.046095222,-0.007942781, +-0.028967574,-0.008278549,-0.01718156,-0.011188865,0.07515748,0.03950633,-0.014164433,0.058429167, +-0.08697823,0.09575392,-0.11742434,-0.03943713,-0.07574393,-0.09947781,-0.104701445,-0.048869893, +-0.04593283,-0.12055561,0.06411052,-0.124525994,0.014279813,-0.026051238,0.0027597547,-0.10667625, +-0.08245912,-0.07232767,-0.0035628676,0.06793679,-0.05642496,-0.087849185,-0.01708883,0.04950708, +0.10667178,0.0045940727,-0.03093411,-0.08499037,-0.048952386,-0.097522765,0.00028425455,-0.12090176, +-0.059199154,-0.103979915,0.050935373,-0.019854814,0.04677157,0.015060484,-0.01911974,-0.08963235, +-0.09729825,-0.040377274,0.0029612184,-0.10259342,-0.11112435,0.025418907,0.007230863,-0.10514364, +-0.101661816,0.091380954,-0.09128162,0.07389876,-0.0739914,0.07796502,0.10834348,-0.12493925, +-0.04301405,0.10317075,0.058080062,-0.083480075,-0.07563977,-0.115329385,-0.12343989,-0.017043158, +0.014554709,0.06472926,0.12386146,-0.08804001,0.08951314,0.060276613,-0.010222927,0.021338597, +-0.061642483,0.10866535,-0.08077009,-0.020251542,0.08943084,-0.07345721,-0.12016593,0.064772755, +-0.043940768,-0.025991753,-0.11909141,0.103526354,-0.032187656,0.058650747,-0.0846111,0.055540204, +0.070952475,-0.041155353,0.12038654,0.018347695,0.097506806,-0.10839039,-0.047908723,0.044150487, +0.053099647,0.10648319,-0.012614638,-0.058273032,0.03552425,0.026844293,0.07468739,0.041444004, +0.10649143,0.020104378,0.124795124,0.02799794,-0.041189134,-0.003524825,-0.04269363,0.10872352, +-0.12309945,0.06367995,-0.0130499005,-0.02087833,-0.030552417,-0.11947189,0.10713433,-0.03675337, +-0.022068664,-0.103068426,0.10705295,-0.07705203,0.08769061,-0.11935459,0.108846456,0.068464175, +-0.08583686,-0.10962586,0.10950942,0.077139705,-0.11133242,-0.02082102,0.021284193,-0.05823651, +-0.077660695,0.094993085,0.0005939752,-0.06437218,0.03050223,-0.052702516,0.113761365,0.047989815, +-0.07206276,-0.08758527,-0.027321145,-0.015724942,0.10004556,0.03488697,0.04643312,-0.07189523, +0.023293003,0.049053535,0.06006317,0.0017228127,0.04341346,0.10280968,-0.12016167,0.105816156, +0.09794475,0.039525554,0.087748736,0.019249186,-0.018259123,0.0131274015,-0.10219607,0.10812144, +0.048005715,0.060408473,-0.011039853,-0.11648908,0.056079686,0.010821238,-0.020642579,-0.011600271, +-0.049995944,0.010175884,0.100491,0.07062735,0.12228361,0.0988967,0.06046228,-0.0316097, +0.08518335,-0.013127461,0.036994517,0.018451229,-0.027985126,0.059083536,-0.07540381,-0.086688355, +-0.025937006,-0.10921015,0.043077514,0.00858514,-0.11778635,0.10277265,-0.030227587,-0.09611547, +0.124563664,0.09482592,-0.021670744,0.097231194,-0.04729083,-0.07950935,-0.028249592,0.123425305, +-0.016532809,0.10090087,0.10087307,-0.0939614,-0.07108581,-0.10350302,0.04719843,-0.095714316, +-0.0075583756,-0.10096608,-0.09819086,-0.09053533,0.017105624,0.024230078,0.019881845,0.0439011, +-0.047456473,0.003854856,-0.067430794,-0.02233176,0.05038348,0.123672485,-0.08008079,5.9753656e-05, +0.007669881,0.043345556,0.0267822,-0.12271787,0.07356416,0.113010824,-0.09373626,0.042519182, +-0.002174005,-0.0050628334,-0.038834274,-0.012827575,-0.012212902,-0.124586135,0.01755318,-0.030112445, +0.09400995,-0.044122458,0.11012103,-0.01784113,0.03199245,-0.07530771,-0.113494605,-0.07073447, +-0.062183917,-0.07581572,-0.0712101,-0.10805328,-0.088149816,0.028847575,-0.11750442,-0.02029121, +0.042749926,-0.10004091,0.009220257,-0.09304288,-0.033917308,0.029525384,-0.051827252,-0.11502035, +-0.09662615,0.113883615,-0.019178003,0.0020207316,-0.043087497,0.057806447,0.117455915,-0.018186823, +-0.045210734,0.0017058849,-0.07502006,0.101529,-0.012560457,0.106892854,0.0067204684,0.070493236, +0.06677349,0.085785046,-0.05528775,0.0083497465,0.09968451,-0.026649833,0.09831609,-0.10270837, +0.041062355,0.05980268,0.017649055,-0.08260164,0.08929734,-0.012551442,-0.064184904,0.0879146, +-0.037784606,-0.057577655,0.019973576,0.001015529,-0.038385317,-0.12398222,0.011908457,0.049736515, +0.07776895,-0.006780684,0.032428518,0.118179634,-0.090009585,0.06577133,-0.057838753,-0.005467817, +0.061677635,0.08721101,0.10173197,0.059958324,0.07998824,0.077891424,-0.010369107,0.018098012, +0.11699067,-0.0039150864,0.04338281,0.03920977,-8.688867e-05,-0.097639486,-0.02114147,0.07718575, +-0.09734051,0.056295365,-0.037668332,-0.10474692,0.09163891,-0.11952421,-0.02042815,0.11221203, +-0.09691319,0.0074875206,0.04414487,-0.021252096,-0.045609638,0.102345005,-0.12145758,-0.06736879, +0.06282596,0.011609152,-0.09268141,0.07492317,-0.021183893,0.116339326,-0.09992503,-0.009118184, +-0.091625854,-0.11977315,-0.08291757,-0.06745367,-0.046288177,-0.0864511,-0.10593453,-0.045257613, +-0.008677542,-0.062785625,-0.057431772,-0.07245614,-0.050964117,-0.06725925,0.10826518,-0.0025214553, +0.10553959,0.0763969,-0.023160592,0.045834467,-0.008008689,-0.024988294,-0.0031843334,0.0059345663, +-0.119285166,-0.057054564,-0.033189952,0.029693305,0.0214521,0.059273437,-0.012091145,0.066208884, +0.017632082,0.089887634,-0.12135315,-0.11213447,0.041064814,0.106908485,-0.071329296,-0.107981995, +-0.022070736,-0.030048579,-0.09953885,0.10931176,0.06242667,0.05568123,0.038078666,-0.084789485, +0.024676695,0.025642112,0.025926203,-0.0839864,-0.09953527,-0.0252451,-0.047306404,-0.09450185, +0.007706642,0.04433866,-0.0066975206,0.071293354,-0.124436855,-0.12244113,-0.053537056,-0.0027043372, +-0.04827012,-0.08444698,0.10775709,0.059342086,-0.098590955,-0.032812282,-0.06586222,-0.06553398, +0.08292274,0.0964818,0.08811988,-0.024774253,0.010108143,0.006028518,-0.113510326,-0.09967232, +-0.03363678,0.00016911328,-0.094279215,-0.057913095,-0.031032398,0.08836466,-0.10139415,-0.0076100677, +-0.046983182,-0.024132103,-0.11086927,-0.020785928,0.11489564,0.061739475,-0.0037681907,0.104466274, +-0.074017644,-0.04953368,-0.0037138462,0.10231182,0.00073863566,0.115683585,0.011494711,0.075114146, +-0.02098617,0.06929429,0.05726996,0.016958058,-0.080229804,-0.06295499,-0.12411451,0.11379148, +-0.08543293,0.023793131,-0.11561532,-0.11108588,0.01662743,0.062742665,0.010300264,-0.0796915, +0.07448071,-0.100915894,-0.07595441,0.0419067,0.019864812,0.022968695,-0.07412112,-0.07414758, +0.12250158,-0.010775581,0.08181749,0.06905617,-0.0035642982,0.019236326,0.07495412,0.06444104, +-0.04901682,-0.12411009,-0.04459609,-0.106769055,-0.019935444,0.044106334,0.114425376,0.118267626, +-0.08360806,0.102697656,-0.07922824,-0.016808733,0.0875117,-0.028330952,-0.046314806,-0.05754444, +-0.086520314,0.0024325699,-0.026060611,-0.05902639,0.09447737,-0.04715456,0.07715441,0.10014154, +-0.0074262917,-0.11114319,0.012166724,0.10826227,-0.10044193,-0.03644389,0.07236704,0.09465583, +0.027711049,0.06312232,-0.0859676,-0.11342403,-0.12344682,0.017332256,0.04600881,-0.06744307, +-0.08663577,-0.060991094,-0.030059338,-0.06583412,0.047447637,0.089479715,-0.025357917,0.03947197, +0.10601504,0.04660234,0.028734013,-0.11269894,-0.000776574,-0.06976074,0.07479654,-0.072327524, +0.04558572,0.02961947,-0.05562368,-0.026735142,0.03296171,-0.111715704,0.07288802,0.10671364, +0.12442981,0.0603593,-0.033460572,-0.03285572,0.044142544,0.044255495,-0.016570374,0.08699322, +0.016282931,-0.09495351,-0.12475605,0.08527681,0.1002817,-0.110531926,-0.11409156,0.11667438, +0.10095404,-0.05649884,-0.026749313,0.0026607811,-0.024727091,0.07529111,-0.057616368,0.09988178, +-0.1085521,0.052936956,-0.080513805,0.07324007,0.07864818,-0.080951706,-0.028929725,0.10636641, +-0.07630284,0.08102277,-0.07169992,-0.12450391,-0.03711754,0.021778107,-0.1155255,0.029965416, +0.017789945,0.11930831,-0.094656974,0.07083903,0.06798987,0.08987336,-0.03795792,-0.06005019, +0.051672593,-0.06788868,0.018837705,-0.01639098,0.07729493,0.030531496,-0.12090927,0.059583023, +-0.07639274,0.010060325,0.06477666,0.030561402,0.070215866,0.12269713,0.006254941,0.07932982, +0.124188095,0.097366825,0.047857866,-0.034752935,0.0067783445,0.003933862,-0.044835836,0.019583598, +-0.101774976,0.07843414,-0.10614206,-0.04317051,0.07413672,-0.07834761,-0.018843189,0.10685262, +0.08320707,-0.0036512762,-0.08456509,-0.017989367,0.12250647,-0.12326723,-0.039988533,0.076485276, +0.068708315,-0.039773315,-0.09998456,0.08195102,0.07744782,-0.07816844,0.009468734,0.11081292, +-0.02889818,-0.09276874,0.07830252,0.010266632,-0.0048113316,0.004165381,-0.013185874,0.013773069, +-0.06506957,-0.072661236,-0.11420411,-0.024867773,0.007300988,0.099019006,0.0063278675,0.09432091, +0.08760579,0.10391128,-0.06248793,0.040199727,0.10851963,-0.12166901,-0.119243056,-0.090089545, +-0.005791262,-0.047495022,0.071271375,0.072916284,0.1082392,-0.030664355,0.10738388,0.01646106, +-0.11604527,-0.08581631,0.09964718,0.09598896,-0.09979159,0.117728636,-0.07452293,0.10829109, +-0.07731025,-0.122054994,-0.043700367,0.11500998,0.008654594,0.019591913,0.05171591,0.12037958, +0.008588806,-0.021281287,0.033835873,0.08952735,0.06957142,0.03955552,-0.06778662,0.04544662, +-0.063991815,0.053055435,0.07891536,-0.0037028193,0.07848194,-0.04942085,-0.009462222,0.016090557, +-0.08557381,-0.114947915,-0.04487939,-0.060357153,-0.053916857,-0.117686585,0.08282623,0.11047684, +-0.064572945,0.059148625,-0.026288182,0.01652138,0.08324532,0.09651591,0.08405411,0.05115415, +0.072305545,-0.030456498,0.018164724,0.11299594,-0.04722105,0.11119929,0.06353027,0.035932824, +-0.013967931,-0.09677331,-0.06904557,-0.0371321,0.03441769,0.04707162,0.066807866,-0.018463925, +0.0005901307,0.021800682,0.0007481724,-0.10447459,-0.05044231,0.12396407,-0.062912464,0.12261765, +-0.044149876,-0.0631157,0.08792296,-0.118439004,-0.10074864,-0.0720433,0.033180296,0.08923982, +0.10241954,0.10800652,-0.03900169,0.025013775,-0.10525134,0.012943178,0.08898109,-0.067529425, +0.021512955,0.09357467,-0.0067350715,0.12333326,-0.0026676655,-0.12078738,0.0065348446,0.033659726, +0.07303621,0.09923512,-0.029775009,-0.0948794,-0.059967294,0.05282736,0.03942728,-0.1116004, +0.05151239,0.066486716,0.006461665,-0.10924764,-0.022497237,-0.12009801,-0.08419901,-0.0012863427, +-0.03294149,-0.015742034,-0.018977866,-0.106774464,0.024370447,-0.07832137,0.0864719,-0.107057825, +0.06923626,0.035407573,-0.063051194,0.072732955,0.10525589,0.009430483,-0.099911794,0.112425804, +-0.006612703,-0.12104301,0.026763394,-0.015982553,-0.090859294,0.12225047,0.028999358,0.10122487, +0.10540323,0.11072016,-0.0638618,-0.102902934,-0.06994684,-0.050027013,-0.045239404,0.06975591, +-0.109199256,-0.011401758,-0.06786899,-0.048013568,-0.08401354,-0.00061652064,-0.0016005784,0.030454755, +-0.04490024,0.11457357,-0.03399858,-0.013530567,0.04172778,-0.051393628,-0.017867848,0.049064413, +0.009595513,0.017963156,0.045576975,0.009410426,-0.0701697,0.03440723,-0.066659585,0.06918746, +-0.116536796,0.10601999,-0.068065554,-0.044262856,0.017874926,0.024237067,-0.016747206,-0.02687098, +-0.057209104,0.11915307,0.10173111,-0.044846594,0.05429779,-0.040514052,0.022156373,0.02886051, +-0.04523486,0.10832518,0.10298775,0.10093905,0.108320415,-0.008921534,0.075588554,-0.11534278, +0.06840275,-0.11706254,0.06566368,-0.115382686,0.101885036,-0.019111246,-0.08491129,-0.03324771, +-0.0285929,0.067431614,-0.056898475,0.01750575,-0.018290743,-0.028229073,-0.03166905,-0.0533728, +-0.09059158,-0.013327211,0.043564692,0.060687438,0.049506128,-0.122023195,-0.10796425,0.12296443, +0.02736941,-0.07661858,-0.03689298,-0.03675604,0.01167734,0.114254564,-0.062085643,0.11484134, +0.10895473,-0.108404994,0.028101712,-0.05301535,0.118707865,0.027271837,0.10483964,-0.1133066, +0.05655913,-0.11990611,-0.10301018,0.10336484,-0.06526895,0.11114831,-0.11830987,-0.03693667, +-0.03791924,-0.049725026,-0.058504567,0.044966385,0.029298365,0.03285481,0.016650438,0.071184665, +0.05010295,0.06213273,0.050998673,0.11546184,-0.078686655,0.029048175,0.117099,0.10598107, +-0.09951419,-0.10943492,-0.023441479,-0.120167896,0.061706185,0.005786568,-0.096045524,0.060823828, +0.092931196,0.12099643,0.12381104,-0.052070394,-0.08640246,0.013285428,0.059362873,-0.123889595, +-0.06529112,-0.12090272,0.05860643,-0.050636217,-5.1409006e-05,-0.0848213,0.071737975,0.04684837, +0.015197411,-0.03891082,0.057050407,0.030804262,0.068629205,-0.04990907,-0.09418529,-0.11393142, +0.10600962,-0.09691271,-0.106775105,0.07496096,0.11011185,-0.05490321,-0.010163158,0.07913543, +-0.051503956,-0.067804754,0.05942276,-0.0010540634,-0.104666114,0.031987935,-0.030527115,0.09636301, +0.019508615,-0.12457205,-0.105097994,-0.04389353,0.063917294,0.020292088,-0.023985147,0.0018577725, +-0.016793996,0.10812016,-0.0640336,-0.11017576,0.011519983,-0.08672331,0.06191279,-0.105452985, +-0.08929579,-0.104101166,0.07794574,-0.03447804,0.11928488,-0.108068675,-0.033734277,0.055511415, +0.028058082,0.047338605,0.02533473,0.099780545,0.08536962,-0.0506943,0.09283447,-0.064642474, +-0.043202147,-0.10728139,-0.10212237,0.032899693,0.08278184,0.074478135,-0.07678534,-0.059215546, +0.11580947,0.007617265,-0.00511533,0.014388174,-0.11992815,0.03602849,-0.12484002,-0.049280763, +-0.047644243,0.060290292,0.09473957,-0.108496875,0.07459548,0.018108234,-0.118009016,-0.030049682, +-0.08136268,0.065996066,0.013146058,-0.12142065,-0.05476518,-0.053218096,0.03979084,0.09660576, +0.0266359,0.0060551316,0.099518836,0.10150796,0.0917774,0.06421533,-0.015888706,0.021369755, +0.10994263,-0.11693105,0.021570519,-0.07953267,0.12327288,-0.11349456,0.09140286,-0.040324226, +0.0025048703,0.07779981,-0.09066382,0.07736902,-0.066762745,-0.048497647,0.09095384,-0.06657, +0.077014714,0.09266928,-0.024117634,0.07915433,0.096717,0.08073199,0.015828326,-0.035452127, +-0.06775327,-0.030599803,-0.106270775,0.05477014,0.04281026,-0.05980836,-0.037486747,0.06942397, +0.102118716,-0.0023157448,0.017414212,0.011972293,-0.035987288,0.015679285,-0.021257669,-0.03339401, +0.11627714,-0.014478818,-0.06465365,0.12480153,0.089019716,0.1138103,0.007929176,-0.09661412, +0.05027005,-0.074088335,0.067730516,-0.036539942,0.0012327284,-0.032007873,0.10389839,0.041831642, +-0.08293405,-0.11683856,0.043524444,-0.0875766,0.0047100484,0.08794294,-0.068282455,-0.07809374, +0.08828032,-0.106880054,-0.109031394,0.058958158,0.03131269,0.01085785,-0.04197535,0.00061795115, +-0.009116039,-0.08100562,0.02472572,0.06986898,-0.006924391,0.035962954,-0.073440224,0.021872818, +0.07853371,0.024873614,0.063066095,-0.1121673,0.009144381,0.004547626,0.12122707,-0.01881744, +0.026185006,0.012397215,0.06766118,0.10245921,-0.020822674,0.05120431,-0.11032048,0.038330466, +-0.12090103,0.028471902,-0.041885316,-0.023591414,0.10230264,0.024926007,0.020785451,0.10887241, +-0.08522853,0.093255624,-0.0987587,0.0042482466,0.019985482,0.09399049,-0.086018175,0.054342836, +0.016227782,0.11442083,-0.026432082,-0.0367326,-0.094372705,-0.0014661103,-0.07691707,0.111141995, +-0.029591888,-0.12496287,0.011857405,0.04891938,-0.030722097,-0.11307305,-0.122568056,0.041648775, +0.05906476,-0.06994736,0.039530903,-0.01722151,-0.04224637,0.118140474,0.019052476,0.046756044, +0.057447493,-0.014228776,0.04827082,-0.07488501,-0.07014142,0.076950446,0.053383365,-0.10420969, +0.03793691,0.03096287,0.11050637,0.10998675,0.12480867,0.088841766,0.0804085,0.113147214, +-0.11442338,0.053937837,-0.04511106,-0.09592314,-0.02383636,0.069052935,0.04716301,-0.05178404, +-0.03024149,0.085217014,-0.121402994,0.015347943,0.022425294,-0.07818891,0.078054994,-0.1083958, +-0.05834791,0.04009199,-0.07349795,-0.07219167,-0.089493856,0.025990576,0.020532757,0.07246506, +-0.034432396,0.054167867,0.0843644,0.1060082,0.12247771,0.063865885,0.120768756,-0.00836885, +0.10737455,-0.12000655,-0.066089064,-0.09552364,0.09734517,-0.060768515,0.11830413,0.1221661, +-0.07856314,0.043814376,0.002162397,0.005835071,0.013402358,-0.052697614,0.12051603,0.11143386, +-0.019188747,0.07610595,0.011842102,0.054800317,0.06510745,0.05464466,-0.071982205,0.027735293, +0.02007015,0.09013231,-0.06230253,-0.049612865,-0.0976035,0.0039717704,0.07875933,0.0059824437, +0.014342174,0.06719974,0.04155186,0.0065541416,0.09478274,-0.024600789,0.052067786,-0.023668855, +0.07919648,0.0666706,0.020469442,-0.12470782,-0.0055578053,-0.086057246,0.051694766,0.07114144, +-0.087324664,-0.09780298,0.111033216,0.0016970783,-0.0686499,0.023414046,0.056988567,-0.037096992, +-0.07404406,-0.03129123,0.09924726,-0.07421176,0.051687375,0.05500026,-0.050002858,-0.035964176, +-0.009300381,-0.09416711,-0.11180408,-0.026925936,0.079236224,-0.053548455,0.04158762,-0.07253668, +0.054335028,0.07685059,-0.116550386,0.08047663,0.007648021,0.08489932,0.0063565224,-0.013558909, +0.062186584,0.027359605,0.111387104,0.008492142,0.0926635,0.04966609,0.03609039,0.08157928, +0.022451013,-0.020238876,0.12231578,-0.049836785,-0.049515948,0.031997114,-0.10183413,0.0011652112, +0.06394687,-0.121086136,0.027382448,-0.012821287,0.051565826,0.014416143,-0.0125038475,0.048808083, +0.025086328,0.0063593388,-0.08069469,0.06882568,-0.06697106,0.04646136,0.08697687,-0.034030527, +0.054751158,-0.023869723,0.08562763,-0.070191875,0.09019026,0.015961125,0.004218504,0.029824317, +0.08514762,-0.08592425,0.0642595,0.054575577,-0.08613354,0.009840354,0.0032888204,-0.090920016, +-0.04916376,-0.013575569,0.07639252,0.12187165,0.060026824,0.06150043,0.10690208,0.06361288, +0.097332284,-0.07109025,-0.012643233,0.10800016,-0.06456825,0.10837218,0.0013162196,0.08441797, +-0.1143685,0.040167436,-0.016026706,0.053332493,0.09022151,-0.12273988,-0.033404678,0.11205059, +-0.01208888,-0.0030140132,0.08252995,-0.10544956,0.07570286,0.048434198,0.121613264,0.025429755, +-0.07472932,-0.09557468,-0.04835771,0.121463805,-0.032501236,0.0067884475,-0.077393815,0.108694255, +-0.022245944,-0.012404636,0.017383188,0.120815784,0.12111379,-0.048650414,-0.083798185,0.123583525, +0.111606196,0.1203351,0.028109416,0.11536527,0.10866012,0.028443366,-0.05447565,0.049032032, +0.02061762,0.1157669,-0.0077940077,-0.118153796,-0.113350615,0.05505249,-0.041882172,0.057925686, +-0.10258281,-0.09037614,0.1054488,-0.059303492,0.07517955,0.115489215,-0.041769817,0.044067547, +0.058327496,-0.05487314,-0.03615266,0.11601317,0.095056474,0.057407066,-0.11016603,0.010294333, +0.096548215,-0.05726476,0.011792123,0.019032374,-0.11002648,0.07365605,0.02415447,0.0829203, +-0.10780208,-0.07414892,0.074496776,0.049104437,0.059883133,0.0895475,0.0060168207,-0.03545022, +0.01123184,-0.08018194,-0.076099426,0.05938296,0.015770048,0.02600509,-0.104634404,-0.018804625, +-0.06444827,0.06952596,-0.11891967,0.07561223,0.0881912,-0.09313339,0.06665172,-0.03877653, +-0.021109238,-0.0950138,0.040632993,-0.046781987,-0.10913634,0.056697905,-0.078700095,0.076099694, +0.037763387,-0.06088917,0.085528105,-0.046229854,0.00979723,0.1113663,0.036610514,0.07728267, +0.103454694,0.054175317,0.028469935,0.10844749,-0.025300667,0.057627216,0.0056156516,0.05524978, +-0.010633022,-0.11832908,-0.123220146,0.085026175,0.109172985,-0.0521968,0.024486333,-0.07291271, +-0.040802956,0.0773468,-0.07468565,0.09964684,0.06944609,0.09447388,0.028680414,-0.05227098, +-0.034188926,0.06474827,0.034068793,0.076197445,0.0071588755,0.02210252,-0.015157148,-0.041274518, +0.039721638,-0.0041104704,-0.015653118,-0.015993163,-0.09791076,0.041946843,0.04202664,0.068808004, +0.11926198,-0.08643682,-0.08702189,-0.0371003,-0.027634531,0.048333406,0.0246934,-0.051542178, +-0.058001295,0.119721115,0.0058310926,-0.026220575,0.11391167,-0.09974091,-0.030742407,-0.109102756, +-0.010545328,-0.06355572,0.025655583,0.024547994,0.03435652,0.085986495,0.098213285,0.10841088, +-0.017484605,0.1045932,-0.06684981,-0.02272904,-0.11855188,-0.027729899,0.080963165,0.013070375, +0.012285203,-0.062388107,-0.080192596,0.06567258,-0.055504948,-0.098769635,-0.008021668,0.11364633, +0.11141585,-0.019893765,-0.06620477,-0.0018479079,-0.04986687,-0.12288031,0.103291094,-0.11170758, +-0.09939325,0.0031500757,0.039072126,0.07819526,-0.021386996,0.07164991,-0.108162194,0.10669248, +0.016798392,-0.031565547,-0.00089368224,-0.025154322,0.01896426,-0.123588145,-0.04039198,0.025806248, +0.07369381,-0.01955527,0.034324422,0.07249893,-0.007222444,-0.10478635,0.029678345,0.012263432, +-0.03602113,-0.0820308,0.10400115,0.074464634,-0.11038381,0.03313631,0.024632469,0.0046253204, +-0.059992403,-0.016449094,-0.09816241,-0.05029261,-0.016355842,0.06858541,0.06876728,0.09230435, +0.08108127,-0.110682994,-0.032294348,-0.11990692,0.03392738,-0.08298041,-0.05477166,-0.011435077, +0.10570291,-0.03953588,0.07989067,-0.031246617,-0.0014988184,0.108662054,0.05255395,-0.028169408, +-0.11841178,-0.02798815,0.038782105,-0.12102358,-0.0057162493,-0.11218251,0.11841786,0.11197908, +0.08845696,0.014620528,-0.11858247,-0.0007520765,0.08343084,0.093437895,0.085087344,-0.004926607, +-0.113425806,-0.007898435,0.12126432,-0.028470427,0.112855196,0.05825992,0.017919883,0.059206665, +0.03112097,0.077684835,0.03172362,-0.076384336,-0.04669325,-0.06266852,0.11156085,-0.06758098, +-0.015924037,0.019525155,0.10438733,0.0021187663,0.082140565,0.051481813,0.05049731,0.05348997, + +=== +name:AttentionDataWithNeoXRotaryEmbedding.bias +0.012921274,0.015607655,-0.0025690347,-0.09620342,-0.038310394,0.028336182,-0.057742983,0.11910392, +-0.021329686,-0.029287532,-0.06831166,0.06367178,0.12070382,0.11052747,-0.1134135,-0.010906458, +-0.027275577,-0.03126064,-0.11263193,0.12486756,0.101218015,-0.08797003,0.078801036,-0.03685227, +0.11405747,-0.00369519,0.06526601,-0.007782519,-0.037164003,-0.11565806,-0.0938476,0.11805937, +0.11596902,0.12006892,0.09075862,-0.11265291,-0.079891264,0.027362347,-0.11551541,-0.004822135, +0.040745273,-0.039045155,0.021577373,0.0087329,-0.048070773,0.014996886,0.026346415,-0.104582444, +0.115239695,0.12411316,-0.10270241,-0.029949531,-0.003467828,-0.0010737777,-0.044124424,0.008305907, +0.037034288,0.037558764,0.07044493,0.02371332,0.042554155,-0.016748935,-0.03282152,0.057627276, +0.098468795,0.0013111085,-0.09694767,0.040279135,-0.098205775,0.040443808,0.11919229,-0.08456744, +-0.01728569,0.11710292,0.05050887,0.119447425,-0.058948025,-0.014045924,-0.08559723,-0.06781402, +0.026872516,0.10124619,0.111734346,-0.04656139,0.106011614,-0.0891671,-0.117075205,0.016492844, +0.11645143,0.09561485,-0.091205105,-0.026062101,0.11059967,0.06537457,0.0026543885,-0.055801243, +0.07915078,0.10557233,0.08071566,0.052541316,-0.05650419,-0.12145753,0.11263573,0.029210433, +0.015763626,0.046862796,-0.04714054,-0.09059784,0.068236336,-0.015073091,-0.11961791,-0.023493499, +-0.018783271,-0.09126243,-0.09896237,-0.028903782,-0.10383962,0.06351283,-0.12072772,-0.056735456, +-0.090958446,-0.044440717,-0.124009505,-0.035018772,-0.08290787,0.0768452,-0.10442828,0.11727749, +0.11758995,0.03290361,-0.0113247335,-0.07405861,-0.055556238,-0.08457345,0.018916026,0.11854942, +-0.04181321,-0.051882207,0.027751818,-0.11699322,-0.042488053,-0.08696966,-0.08996944,-0.037741214, +0.097063705,0.053180724,0.03476517,0.104185596,0.072988436,-0.0014739782,0.030967787,-0.017249301, +0.06111832,0.02802904,0.049923286,-0.11694123,-0.016943783,0.066462934,0.04678969,0.031156898, +-0.050833255,0.08095451,-0.026759312,-0.06783678,-0.08926612,0.0010999292,-0.098703265,0.07819982, +0.016622037,-0.026472524,0.10805431,-0.0021841824,0.014784232,0.081945494,0.02112551,0.0006199628, +0.1143356,-0.09599832,0.061794326,0.031698108,-0.019378498,0.040865794,0.01023905,-0.07774389, +-0.08447838,-0.06274469,0.11284082,0.09761292,-0.013365716,0.0630935,0.07569803,0.10532519, + +=== +name:AttentionDataWithNeoXRotaryEmbedding.output +-0.41288602,0.34693867,0.17056748,-0.3000056,0.0037139729,0.6446975,0.35701394,0.4783501, +0.060810767,-0.17548372,0.5347075,-0.24958763,0.37899846,-0.0033716336,-0.14532009,-0.3094958, +0.22858009,-0.27370766,0.2448737,-0.117854,0.4475677,-0.15341815,0.20634943,-0.2152504, +-0.20829634,-0.31435978,-0.04319033,-0.11306764,-0.08076568,-0.65668076,-0.02969347,-0.14298177, +-0.41666374,0.22916545,-0.043889944,0.44246197,-0.25989074,0.0654705,0.20024723,0.116754055, +-0.26155314,-0.47822088,0.4269185,0.19983053,0.78657573,0.29853833,-0.22293046,0.5119251, +0.25182527,0.18829623,-0.22877915,0.018463401,0.046938226,-0.24568044,-0.067069344,0.16568068, +0.43599105,-0.49316847,0.41968888,0.24670804,0.24518725,0.40178925,0.2817499,0.38869864, +-0.37167335,0.37696028,0.2491411,-0.4069539,-0.025512135,0.697503,0.2736748,0.5130744, +0.08440733,-0.08830104,0.4914955,-0.26050097,0.35520625,0.03804043,-0.10277921,-0.32093158, +0.30793336,-0.19618958,0.30210054,-0.08955928,0.4240442,-0.118735656,0.15663856,-0.21542141, +-0.1299509,-0.34627512,-0.0056000445,-0.16983509,-0.061221946,-0.6379185,0.019689217,-0.10790968, +-0.44443697,0.25593972,-0.019389862,0.46486115,-0.22341447,0.0059498344,0.162151,0.017600633, +-0.22027948,-0.50053084,0.4946542,0.19559412,0.7739278,0.27242374,-0.22544684,0.5744761, +0.29612914,0.16445178,-0.28533965,-0.019356813,0.048583828,-0.18184364,-0.028799001,0.15345171, +0.44764367,-0.5045303,0.48955107,0.23092999,0.18916695,0.44125485,0.2561466,0.3750417, +-0.4177165,0.4242855,0.23527762,-0.43983376,-0.015554033,0.7411243,0.29571885,0.49034935, +0.09105395,-0.19059415,0.45305496,-0.25565678,0.3147282,0.072712675,-0.15744011,-0.2522229, +0.28598517,-0.115885735,0.18716305,-0.076459914,0.42896318,0.00024261838,0.24630134,-0.29495132, +-0.1497713,-0.3328632,-0.020976782,-0.18259642,0.052318588,-0.6616767,-0.03201641,-0.077634454, +-0.46381223,0.35139352,-0.10998587,0.37857378,-0.29113406,0.02714412,0.118249506,0.0014535487, +-0.22025385,-0.5309402,0.5069752,0.27742988,0.85060954,0.24166244,-0.30255532,0.58699757, +0.37641618,0.2186183,-0.37271595,0.087486595,0.08526345,-0.22383334,-0.06866325,0.19303375, +0.42361736,-0.4988973,0.53478855,0.27574676,0.19689696,0.5228985,0.2286603,0.41254547, +-0.38715667,0.4025734,0.24896201,-0.40581006,-0.007268807,0.69798714,0.3008909,0.5033461, +0.040404595,-0.15796751,0.39680687,-0.24920885,0.28985906,0.11799197,-0.16544515,-0.30313727, +0.30446523,-0.13475142,0.22777845,-0.03863262,0.39835036,-0.05059766,0.18062752,-0.23713541, +-0.1575769,-0.31721163,-0.02570787,-0.17792636,-0.0038699396,-0.63370764,-0.011535684,-0.07881303, +-0.47101083,0.24331519,-0.059330232,0.4296828,-0.2792168,0.011085652,0.06865603,0.024540272, +-0.1942445,-0.5154834,0.5137167,0.30345967,0.7880432,0.22699502,-0.23210928,0.5624612, +0.3241039,0.2758873,-0.35064527,0.08398114,0.080884576,-0.21506889,-0.0025116205,0.116575986, +0.43586755,-0.5633712,0.46149772,0.21475634,0.21229926,0.42853355,0.25883353,0.39509213 diff --git a/onnxruntime/test/testdata/attention/packed_multihead_attention_test_data.txt b/onnxruntime/test/testdata/attention/packed_multihead_attention_test_data.txt new file mode 100644 index 0000000000000..2e91cf46ce5f1 --- /dev/null +++ b/onnxruntime/test/testdata/attention/packed_multihead_attention_test_data.txt @@ -0,0 +1,362 @@ +name:PackedMultiHeadAttentionData_Batch2_HeadSize32_NoRelPosBias.query_data +-0.35420692,1.31206024,-2.80201197,2.42258096,-0.86031514,-1.44535458,-0.10832444,-2.00132895, +1.62475216,0.10978927,1.84596729,0.48908550,1.44369888,0.87542874,-1.16434252,0.52133209, +1.54848897,-2.21174526,-0.28574878,0.70815033,1.18327498,3.14097571,-0.25795099,1.89341247, +-0.11603792,0.38110194,0.40873206,-1.14149106,0.79770875,-0.98069525,-1.53588808,0.50821728, + +3.50846076,-2.50027657,-2.59866142,1.58495271,2.21110034,-2.74877763,-1.00267041,0.62646407, +2.50227380,-0.27291518,-0.33037442,0.75840306,0.45437157,-0.79876304,0.83509272,2.53716302, +0.01348384,-2.16307616,2.01661849,2.10746121,-1.70485222,1.35548759,1.39401650,-0.99451691, +-4.13484812,0.56262714,-0.92725742,-0.16389316,-1.31260049,2.32357836,-3.05251694,-1.12570131, + +1.87849474,-1.80381167,0.52235699,2.38887334,-1.58878529,0.69571090,1.65044296,-0.27024290, +3.59580970,-1.97888982,1.17034674,0.26716161,-1.16770899,0.74609619,0.78886843,0.15717520, +-0.93303132,-0.84753871,-4.32799959,-1.94716609,-1.16980326,1.62631667,2.41053247,3.78186774, +0.26432252,-0.40396988,2.04414082,0.65150046,0.47777444,-2.57569051,0.99004912,2.47947693, +=== +name:PackedMultiHeadAttentionData_Batch2_HeadSize32_NoRelPosBias.key_data +-0.04407793,1.29459429,1.05810797,1.92067695,-0.65047157,0.99029726,-1.69796586,1.15320420, +-1.66444266,1.78305888,1.20582056,1.69975281,0.34572244,-0.60833001,2.59864879,-1.05330181, +-1.16554165,-0.03781542,-1.13475525,0.71595150,-0.91169560,1.26686060,1.60492957,-0.53510487, +-1.40180850,1.83253956,2.70238972,-1.48750985,0.47105616,-0.79477602,-1.93152475,1.04042351, + +-2.65206385,1.26134932,-1.01682174,0.64366758,0.95474619,2.06720352,0.51750720,-0.07041813, +0.53124994,-3.26612782,1.37013340,0.13939659,-0.57418114,0.80680281,-3.40751696,-0.15847699, +0.97837782,-0.09121911,1.18452120,0.52711177,-1.86135840,-0.11258313,0.85863215,-2.60261130, +0.72695309,1.44092011,0.43785980,-1.63415265,-1.05772328,0.12997569,0.07356137,-0.62493324, + +-0.43267637,-1.80009198,0.92961007,2.05127883,-2.85521173,-0.21652693,-0.89153922,0.15524670, +-2.16850328,1.46751809,2.51663852,-0.49499366,0.19886012,0.77093124,-1.14819765,1.47111738, +2.42824388,1.56369960,1.69934130,-0.42460468,-2.25951004,-1.18074155,3.51091242,-0.30183151, +-1.83517075,-0.56233191,2.35561657,-3.63751698,-3.20001125,-1.66120780,3.23455381,-1.86251283, +=== +name:PackedMultiHeadAttentionData_Batch2_HeadSize32_NoRelPosBias.value_data +-0.89167893,0.02633595,-0.84866279,1.43489110,-2.91941142,-0.20650116,1.85965109,0.45669034, +0.07678832,0.04492294,0.67326981,0.97103029,1.53470886,-1.10242307,0.86584085,-0.34770033, +-1.24311507,-1.80293822,-1.01317739,-0.71518499,0.77814674,-0.59236068,-2.00310278,3.13277125, +-1.20754123,2.01506066,0.82650810,2.06084490,-0.46267471,1.56365979,4.31514502,-1.03099275, + +-2.11639142,-1.50897706,1.63863683,2.32786226,1.32746494,0.75751448,0.57184196,0.86446053, +-0.62406683,0.78861046,0.01044065,3.51772785,-1.33701336,0.27977663,-0.35464612,0.74973166, +0.03352100,1.55007398,0.69849420,-2.47725606,-1.89363778,-1.79874682,-0.56210291,-1.75556040, +1.07565808,-0.18023658,1.63777173,1.28198206,2.19431949,0.67998970,-0.52531999,-1.89906740, + +1.35158050,-2.21481490,-0.11812399,-1.74263430,-0.57895988,-0.04181165,0.78120053,-2.22377038, +-0.53264999,-2.03721714,0.21023634,2.55751204,-1.04522800,0.85386503,0.41594937,-2.98181081, +1.14034331,-1.41539204,0.13379651,3.47018123,1.53924727,1.50004411,2.87318921,1.62624204, +0.64942807,-4.54302311,-1.50294220,-1.75212634,0.27900690,-3.05124855,3.30960631,-0.07991691, +=== +name:PackedMultiHeadAttentionData_Batch2_HeadSize32_NoRelPosBias.qkv_data +-0.35420692,1.31206024,-2.80201197,2.42258096,-0.86031514,-1.44535458,-0.10832444,-2.00132895, +1.62475216,0.10978927,1.84596729,0.48908550,1.44369888,0.87542874,-1.16434252,0.52133209, +1.54848897,-2.21174526,-0.28574878,0.70815033,1.18327498,3.14097571,-0.25795099,1.89341247, +-0.11603792,0.38110194,0.40873206,-1.14149106,0.79770875,-0.98069525,-1.53588808,0.50821728, +-0.04407793,1.29459429,1.05810797,1.92067695,-0.65047157,0.99029726,-1.69796586,1.15320420, +-1.66444266,1.78305888,1.20582056,1.69975281,0.34572244,-0.60833001,2.59864879,-1.05330181, +-1.16554165,-0.03781542,-1.13475525,0.71595150,-0.91169560,1.26686060,1.60492957,-0.53510487, +-1.40180850,1.83253956,2.70238972,-1.48750985,0.47105616,-0.79477602,-1.93152475,1.04042351, +-0.89167893,0.02633595,-0.84866279,1.43489110,-2.91941142,-0.20650116,1.85965109,0.45669034, +0.07678832,0.04492294,0.67326981,0.97103029,1.53470886,-1.10242307,0.86584085,-0.34770033, +-1.24311507,-1.80293822,-1.01317739,-0.71518499,0.77814674,-0.59236068,-2.00310278,3.13277125, +-1.20754123,2.01506066,0.82650810,2.06084490,-0.46267471,1.56365979,4.31514502,-1.03099275, + +3.50846076,-2.50027657,-2.59866142,1.58495271,2.21110034,-2.74877763,-1.00267041,0.62646407, +2.50227380,-0.27291518,-0.33037442,0.75840306,0.45437157,-0.79876304,0.83509272,2.53716302, +0.01348384,-2.16307616,2.01661849,2.10746121,-1.70485222,1.35548759,1.39401650,-0.99451691, +-4.13484812,0.56262714,-0.92725742,-0.16389316,-1.31260049,2.32357836,-3.05251694,-1.12570131, +-2.65206385,1.26134932,-1.01682174,0.64366758,0.95474619,2.06720352,0.51750720,-0.07041813, +0.53124994,-3.26612782,1.37013340,0.13939659,-0.57418114,0.80680281,-3.40751696,-0.15847699, +0.97837782,-0.09121911,1.18452120,0.52711177,-1.86135840,-0.11258313,0.85863215,-2.60261130, +0.72695309,1.44092011,0.43785980,-1.63415265,-1.05772328,0.12997569,0.07356137,-0.62493324, +-2.11639142,-1.50897706,1.63863683,2.32786226,1.32746494,0.75751448,0.57184196,0.86446053, +-0.62406683,0.78861046,0.01044065,3.51772785,-1.33701336,0.27977663,-0.35464612,0.74973166, +0.03352100,1.55007398,0.69849420,-2.47725606,-1.89363778,-1.79874682,-0.56210291,-1.75556040, +1.07565808,-0.18023658,1.63777173,1.28198206,2.19431949,0.67998970,-0.52531999,-1.89906740, + +1.87849474,-1.80381167,0.52235699,2.38887334,-1.58878529,0.69571090,1.65044296,-0.27024290, +3.59580970,-1.97888982,1.17034674,0.26716161,-1.16770899,0.74609619,0.78886843,0.15717520, +-0.93303132,-0.84753871,-4.32799959,-1.94716609,-1.16980326,1.62631667,2.41053247,3.78186774, +0.26432252,-0.40396988,2.04414082,0.65150046,0.47777444,-2.57569051,0.99004912,2.47947693, +-0.43267637,-1.80009198,0.92961007,2.05127883,-2.85521173,-0.21652693,-0.89153922,0.15524670, +-2.16850328,1.46751809,2.51663852,-0.49499366,0.19886012,0.77093124,-1.14819765,1.47111738, +2.42824388,1.56369960,1.69934130,-0.42460468,-2.25951004,-1.18074155,3.51091242,-0.30183151, +-1.83517075,-0.56233191,2.35561657,-3.63751698,-3.20001125,-1.66120780,3.23455381,-1.86251283, +1.35158050,-2.21481490,-0.11812399,-1.74263430,-0.57895988,-0.04181165,0.78120053,-2.22377038, +-0.53264999,-2.03721714,0.21023634,2.55751204,-1.04522800,0.85386503,0.41594937,-2.98181081, +1.14034331,-1.41539204,0.13379651,3.47018123,1.53924727,1.50004411,2.87318921,1.62624204, +0.64942807,-4.54302311,-1.50294220,-1.75212634,0.27900690,-3.05124855,3.30960631,-0.07991691, +=== +name:PackedMultiHeadAttentionData_Batch2_HeadSize32_NoRelPosBias.fp16_output_data +-0.89160156,0.02633667,-0.84863281,1.4345703,-2.9199219,-0.20654297,1.859375,0.45678711, +0.076782227,0.044921875,0.67333984,0.97119141,1.5351562,-1.1025391,0.86572266,-0.34765625, +-1.2431641,-1.8027344,-1.0126953,-0.71533203,0.77832031,-0.59228516,-2.0039062,3.1328125, +-1.2080078,2.015625,0.82666016,2.0605469,-0.46264648,1.5634766,4.3164062,-1.03125, + +0.21158576,-1.98279130,0.45935997,-0.40457720,0.04772174,0.22094353,0.71238005,-1.20860445, +-0.56270063,-1.10830855,0.14455934,2.87315512,-1.14114404,0.66515017,0.16263856,-1.75517499, +0.77650774,-0.44058144,0.31942442,1.51513433,0.41078627,0.41566271,1.74393702,0.51457298, +0.78953874,-3.10888410,-0.47052401,-0.75475156,0.90861011,-1.82471263,2.04898596,-0.67790967, + +1.17194295,-2.17825341,-0.02712549,-1.53178656,-0.48020893,-0.00040733,0.77035600,-2.06380320, +-0.53738528,-1.89084208,0.19988713,2.60725045,-1.06034219,0.82412785,0.37603328,-2.78852081, +1.08301103,-1.26178384,0.16304730,3.16210985,1.36142719,1.32916999,2.69524455,1.45106804, +0.67150640,-4.31703520,-1.34025633,-1.59496248,0.37821823,-2.85797405,3.11096096,-0.17414713f +=== +name:PackedMultiHeadAttentionData_Batch2_HeadSize8_RelPosBias.query_data +-1.83615911,0.08698978,0.05601556,-1.14510250,-2.30377889,-0.39893439,0.73342341,-0.09851928, +-0.45148617,-0.16055907,-1.48271382,-0.07961921,-0.65701288,-0.25778309,-0.72851723,0.86755788, + +-0.69794613,1.27221310,0.01081287,0.61428916,-0.00753688,0.33604777,-0.65822184,-0.83206612, +0.14741525,1.17016482,-0.68234873,-1.34005868,-0.22676668,-0.29179415,-0.15037467,0.15722550, +-0.20033565,-1.51847255,0.95205748,0.54009491,1.19315910,0.81655478,0.87503016,0.09732430, +-0.53218621,-0.11167067,0.67364228,-0.59705222,-0.24946509,0.20462716,-0.56092483,-0.65660709, +=== +name:PackedMultiHeadAttentionData_Batch2_HeadSize8_RelPosBias.key_data +0.86949563,-0.10868365,-0.37917313,-1.23103046,0.25640076,-1.50652349,0.71594471,0.49057019, +-1.41292810,-0.19686662,1.25451696,-1.59823179,-1.16262913,0.84965342,0.61178929,-1.26162946, + +0.56394553,-0.14227687,1.25733399,-0.11350060,0.02068172,-0.21710102,1.00936651,0.04366954, +0.72092402,-1.80008531,1.11335325,-0.58614230,0.15335107,-0.43153843,-0.81098813,1.15529966, +0.47295785,0.65468878,-1.44158995,-0.05122741,-0.34755200,0.66963655,0.72664660,1.59155345, +-1.13806772,0.70947856,-0.65793264,-0.50718778,-1.20698619,0.32613355,0.61786091,-0.34040576, +=== +name:PackedMultiHeadAttentionData_Batch2_HeadSize8_RelPosBias.value_data +-1.19203627,0.38844836,0.68121153,0.21624038,-1.77549291,0.18574584,0.90408206,-0.22868094, +-0.95558548,1.38712502,0.81038797,0.14359820,0.15352470,0.00469783,0.03943123,0.53865469, + +-1.60517013,-0.88120216,1.91317511,-0.54577649,0.62921578,0.57512373,-0.31156173,0.57847321, +0.04376111,-0.09540533,-0.38106504,1.00102639,-0.56325150,0.90788037,-0.33356044,0.74308902, +-0.15860432,-0.24945745,0.67483073,0.18782829,-0.56960964,1.16764832,-0.72244978,0.55027384, +-0.37327161,1.19222152,-0.23447749,0.06147140,0.32951999,1.06427121,2.26385999,0.23828916, +=== +name:PackedMultiHeadAttentionData_Batch2_HeadSize8_RelPosBias.qkv_data +-1.83615911,0.08698978,0.05601556,-1.14510250,-2.30377889,-0.39893439,0.73342341,-0.09851928, +0.86949563,-0.10868365,-0.37917313,-1.23103046,0.25640076,-1.50652349,0.71594471,0.49057019, +-1.19203627,0.38844836,0.68121153,0.21624038,-1.77549291,0.18574584,0.90408206,-0.22868094, + +-0.45148617,-0.16055907,-1.48271382,-0.07961921,-0.65701288,-0.25778309,-0.72851723,0.86755788, +-1.41292810,-0.19686662,1.25451696,-1.59823179,-1.16262913,0.84965342,0.61178929,-1.26162946, +-0.95558548,1.38712502,0.81038797,0.14359820,0.15352470,0.00469783,0.03943123,0.53865469, + +-0.69794613,1.27221310,0.01081287,0.61428916,-0.00753688,0.33604777,-0.65822184,-0.83206612, +0.56394553,-0.14227687,1.25733399,-0.11350060,0.02068172,-0.21710102,1.00936651,0.04366954, +-1.60517013,-0.88120216,1.91317511,-0.54577649,0.62921578,0.57512373,-0.31156173,0.57847321, + +0.14741525,1.17016482,-0.68234873,-1.34005868,-0.22676668,-0.29179415,-0.15037467,0.15722550, +0.72092402,-1.80008531,1.11335325,-0.58614230,0.15335107,-0.43153843,-0.81098813,1.15529966, +0.04376111,-0.09540533,-0.38106504,1.00102639,-0.56325150,0.90788037,-0.33356044,0.74308902, + +-0.20033565,-1.51847255,0.95205748,0.54009491,1.19315910,0.81655478,0.87503016,0.09732430, +0.47295785,0.65468878,-1.44158995,-0.05122741,-0.34755200,0.66963655,0.72664660,1.59155345, +-0.15860432,-0.24945745,0.67483073,0.18782829,-0.56960964,1.16764832,-0.72244978,0.55027384, + +-0.53218621,-0.11167067,0.67364228,-0.59705222,-0.24946509,0.20462716,-0.56092483,-0.65660709, +-1.13806772,0.70947856,-0.65793264,-0.50718778,-1.20698619,0.32613355,0.61786091,-0.34040576, +-0.37327161,1.19222152,-0.23447749,0.06147140,0.32951999,1.06427121,2.26385999,0.23828916, +=== +name:PackedMultiHeadAttentionData_Batch2_HeadSize8_RelPosBias.rel_pos_bias_data +0.4781123,0.82420444,0.654424,0.3995186, +0.5482078,0.55570245,0.4216576,0.46001542, +0.4781123,0.82420444,0.654424,0.3995186, +0.5482078,0.55570245,0.4216576,0.46001542, + +=== +name:PackedMultiHeadAttentionData_Batch2_HeadSize8_RelPosBias.fp16_output_data +-1.1923828,0.38842773,0.68115234,0.21618652,-1.7753906,0.18579102,0.90429688,-0.2286377, +-0.95556641,1.3867188,0.81054688,0.14355469,0.15356445,0.004699707,0.039428711,0.53857422, + +-0.72265625,-0.49584961,1.1572266,-0.098266602,-0.10211182,0.93652344,-0.56201172,0.56103516, +-0.27758789,0.89697266,-0.26831055,0.27734375,0.12451172,1.0283203,1.6679688,0.35424805, + +-1.3427734,-0.76660156,1.6884766,-0.41259766,0.41162109,0.68261719,-0.38598633,0.57324219, +-0.17407227,0.57763672,-0.3046875,0.51025391,-0.097045898,0.98974609,1.0234375,0.47949219, + +=== +name:PackedMultiHeadAttentionData_Batch2_HeadSize8_BroadcastRelPosBias.query_data +-1.83615911,0.08698978,0.05601556,-1.14510250,-2.30377889,-0.39893439,0.73342341,-0.09851928, +-0.45148617,-0.16055907,-1.48271382,-0.07961921,-0.65701288,-0.25778309,-0.72851723,0.86755788, + +-1.61145306,1.15819526,0.92267495,0.05697182,-1.15679109,0.30815905,-0.16966841,1.59468949, +1.06674862,-0.94525659,-1.26431036,0.54500824,2.33555818,-1.55515289,-1.15762365,0.94301772, +-0.11946517,-0.52010381,1.17592037,1.18040121,1.71579909,0.74054289,-0.28932455,0.43039253, +-0.59887785,-1.49919224,1.02610373,0.28144905,0.54606986,0.89283150,-1.55426455,0.81868863, +0.52380687,-0.98392582,-1.63426089,-0.48980984,0.39993629,-0.29305443,0.89878768,-0.56480503, +0.36021376,0.23860840,-0.31765643,-0.26952648,-1.24825561,1.21374047,0.23826340,0.63743669, +-0.24714193,1.01905107,-0.93621284,-0.84905517,-1.20235336,-2.04996300,-0.01251672,-1.23131406, +0.75130051,1.48657084,-0.17923722,-0.58394587,0.90255487,-0.60496974,-0.31978402,0.04127264, +-0.74666536,1.14945197,0.85595274,0.87929201,0.52238762,-0.38138887,-0.09198012,0.10379392, +0.03910975,0.37068886,0.38653150,-0.84676158,0.88043237,-0.70293593,-1.86805880,0.50196815, +1.79820418,0.49160564,-1.04994130,-0.65047348,0.03673789,-1.43390560,0.33562672,0.16967399, +-0.71324098,-0.24858820,-0.42040613,-0.47096899,-2.18410730,1.29030848,0.95546865,-0.01637810, +2.10404348,-0.25014257,2.06826448,0.68731880,-0.72305721,-3.06288505,1.35467649,-2.27782655, +-2.04115343,0.01709199,1.14326739,-2.85616302,-1.63115931,1.21209049,-2.88173485,0.29401016, +0.96896434,1.49846828,-1.48152626,-0.40123838,0.66036439,-2.08949637,0.93013203,1.78407586, +-0.16418101,0.30182290,0.76461935,0.89762378,-0.70261180,1.31333566,0.86440170,-0.55341989, + +=== +name:PackedMultiHeadAttentionData_Batch2_HeadSize8_BroadcastRelPosBias.key_data +0.86949563,-0.10868365,-0.37917313,-1.23103046,0.25640076,-1.50652349,0.71594471,0.49057019, +-1.41292810,-0.19686662,1.25451696,-1.59823179,-1.16262913,0.84965342,0.61178929,-1.26162946, + +-0.39776036,-0.32152289,0.83949518,-0.68910766,2.10605407,-1.13187802,-0.02778089,-0.46233135, +-2.59193254,-0.02682346,0.07309747,-1.76444602,-1.02990091,-0.92442840,0.80414194,-1.34978604, +0.18744308,0.95530021,1.00306034,-0.06650767,0.14434582,-0.07039906,-0.42095628,1.47149456, +-0.32872301,0.28885615,-0.12510297,-0.35719556,0.36152089,-0.06192274,-0.28507957,0.75713438, +-0.59390724,-0.20499256,0.45794842,0.49178654,-0.25790799,-0.32643789,0.38682714,-0.26962680, +0.32060453,0.06873609,1.35627246,-0.55090475,0.75872916,-0.72157520,-0.75826746,-0.43329650, +-1.35081804,-0.40014201,0.26041570,0.23221464,0.90103126,-0.98436964,0.78283572,-1.78756905, +0.56045622,0.52480292,-0.67152452,-1.51145959,0.35886180,-0.41121563,0.61315238,-1.03636253, +0.32577509,-0.24800496,0.61258811,-0.14612751,0.82892537,-0.14666887,0.26352236,0.27397016, +-0.54198223,-0.38484800,-0.05891366,-0.79304564,-0.58239877,0.26545495,-0.38297540,0.79097033, +1.70193112,-0.31023103,-0.33280775,0.70939517,-1.27211368,-0.58704966,-1.81665146,0.03955793, +-0.40429014,0.48408982,1.63168097,0.71464306,0.93015838,-0.16759235,-2.20110703,0.78718776, +1.27983427,1.74217772,-1.50595713,1.52578330,0.56935966,-0.94778556,-1.28090227,-0.02918145, +0.99273205,2.60591888,1.39687920,-0.34032899,0.35641205,0.91440523,-0.69939649,2.64614010, +0.65847164,-1.24047744,-0.11745319,0.80385536,-0.55450106,-0.64750642,-0.84041762,0.10586573, +-1.74471772,0.38858974,0.77225429,-0.47355813,0.59074765,-0.50501788,-1.72981727,-1.25862873, + +=== +name:PackedMultiHeadAttentionData_Batch2_HeadSize8_BroadcastRelPosBias.value_data +-1.19203627,0.38844836,0.68121153,0.21624038,-1.77549291,0.18574584,0.90408206,-0.22868094, +-0.95558548,1.38712502,0.81038797,0.14359820,0.15352470,0.00469783,0.03943123,0.53865469, + +0.50737989,1.88879848,-0.66337180,-1.29574990,-1.86634719,-1.01549423,-0.28819263,-0.00019580, +-2.00984406,-0.95374167,0.84587288,-1.78314638,-0.26245379,-1.30501473,-1.76663613,0.81748939, +0.80457681,-0.33367968,-0.10504961,0.27371234,-0.07084391,-0.40500754,-0.04883647,-0.94577336, +1.02707481,-0.13490768,-0.18182218,-0.93900180,1.18116772,1.98105478,-0.36385471,1.03757906, +0.14796616,-0.83527970,0.16718683,1.49241018,0.43081248,-1.43449056,0.39671475,-0.70072436, +0.17739578,0.32338822,-0.67136252,0.01797877,-0.59793222,0.78523242,0.25322497,1.50049233, +-0.67545807,0.50556731,0.18512395,-1.26351786,-1.42564654,-1.06456351,-1.15261269,-0.49967349, +-1.68690670,-1.10258508,0.07205302,1.72984779,-0.86800003,-0.91829145,-0.97764057,-0.55795985, +-0.85447711,0.16153991,1.38688803,-1.06463683,-1.42907071,0.43985835,-0.49964419,0.67612225, +-0.17095472,-0.31460449,0.78414583,0.25754923,0.49601099,1.01128983,-0.85820115,1.31935477, +1.41204929,-1.20291567,0.22243243,2.67244053,0.75709999,-0.44346970,0.94684786,-0.61597395, +-0.37711632,-0.30456182,-0.73898333,0.39148647,-0.04324996,-1.18526721,-1.38802266,0.82284755, +0.33568430,-3.36413050,1.40020049,1.05561769,-1.90628219,1.38226020,0.99804544,1.02540088, +-1.05158651,-3.61572313,-2.07312417,0.55376863,-0.07229304,0.02950740,-1.17457461,0.59849799, +0.56384206,0.21395147,1.26861954,2.02004290,-0.83739442,-0.11827546,-0.42885846,-1.55389440, +-1.04708695,1.04990900,0.61408597,0.48327276,0.61544299,-0.57864964,-0.80768973,0.39645281, + +=== +name:PackedMultiHeadAttentionData_Batch2_HeadSize8_BroadcastRelPosBias.qkv_data +-1.83615911,0.08698978,0.05601556,-1.14510250,-2.30377889,-0.39893439,0.73342341,-0.09851928, +0.86949563,-0.10868365,-0.37917313,-1.23103046,0.25640076,-1.50652349,0.71594471,0.49057019, +-1.19203627,0.38844836,0.68121153,0.21624038,-1.77549291,0.18574584,0.90408206,-0.22868094, + +-0.45148617,-0.16055907,-1.48271382,-0.07961921,-0.65701288,-0.25778309,-0.72851723,0.86755788, +-1.41292810,-0.19686662,1.25451696,-1.59823179,-1.16262913,0.84965342,0.61178929,-1.26162946, +-0.95558548,1.38712502,0.81038797,0.14359820,0.15352470,0.00469783,0.03943123,0.53865469, + +-1.61145306,1.15819526,0.92267495,0.05697182,-1.15679109,0.30815905,-0.16966841,1.59468949, +-0.39776036,-0.32152289,0.83949518,-0.68910766,2.10605407,-1.13187802,-0.02778089,-0.46233135, +0.50737989,1.88879848,-0.66337180,-1.29574990,-1.86634719,-1.01549423,-0.28819263,-0.00019580, + +1.06674862,-0.94525659,-1.26431036,0.54500824,2.33555818,-1.55515289,-1.15762365,0.94301772, +-2.59193254,-0.02682346,0.07309747,-1.76444602,-1.02990091,-0.92442840,0.80414194,-1.34978604, +-2.00984406,-0.95374167,0.84587288,-1.78314638,-0.26245379,-1.30501473,-1.76663613,0.81748939, + +-0.11946517,-0.52010381,1.17592037,1.18040121,1.71579909,0.74054289,-0.28932455,0.43039253, +0.18744308,0.95530021,1.00306034,-0.06650767,0.14434582,-0.07039906,-0.42095628,1.47149456, +0.80457681,-0.33367968,-0.10504961,0.27371234,-0.07084391,-0.40500754,-0.04883647,-0.94577336, + +-0.59887785,-1.49919224,1.02610373,0.28144905,0.54606986,0.89283150,-1.55426455,0.81868863, +-0.32872301,0.28885615,-0.12510297,-0.35719556,0.36152089,-0.06192274,-0.28507957,0.75713438, +1.02707481,-0.13490768,-0.18182218,-0.93900180,1.18116772,1.98105478,-0.36385471,1.03757906, + +0.52380687,-0.98392582,-1.63426089,-0.48980984,0.39993629,-0.29305443,0.89878768,-0.56480503, +-0.59390724,-0.20499256,0.45794842,0.49178654,-0.25790799,-0.32643789,0.38682714,-0.26962680, +0.14796616,-0.83527970,0.16718683,1.49241018,0.43081248,-1.43449056,0.39671475,-0.70072436, + +0.36021376,0.23860840,-0.31765643,-0.26952648,-1.24825561,1.21374047,0.23826340,0.63743669, +0.32060453,0.06873609,1.35627246,-0.55090475,0.75872916,-0.72157520,-0.75826746,-0.43329650, +0.17739578,0.32338822,-0.67136252,0.01797877,-0.59793222,0.78523242,0.25322497,1.50049233, + +-0.24714193,1.01905107,-0.93621284,-0.84905517,-1.20235336,-2.04996300,-0.01251672,-1.23131406, +-1.35081804,-0.40014201,0.26041570,0.23221464,0.90103126,-0.98436964,0.78283572,-1.78756905, +-0.67545807,0.50556731,0.18512395,-1.26351786,-1.42564654,-1.06456351,-1.15261269,-0.49967349, + +0.75130051,1.48657084,-0.17923722,-0.58394587,0.90255487,-0.60496974,-0.31978402,0.04127264, +0.56045622,0.52480292,-0.67152452,-1.51145959,0.35886180,-0.41121563,0.61315238,-1.03636253, +-1.68690670,-1.10258508,0.07205302,1.72984779,-0.86800003,-0.91829145,-0.97764057,-0.55795985, + +-0.74666536,1.14945197,0.85595274,0.87929201,0.52238762,-0.38138887,-0.09198012,0.10379392, +0.32577509,-0.24800496,0.61258811,-0.14612751,0.82892537,-0.14666887,0.26352236,0.27397016, +-0.85447711,0.16153991,1.38688803,-1.06463683,-1.42907071,0.43985835,-0.49964419,0.67612225, + +0.03910975,0.37068886,0.38653150,-0.84676158,0.88043237,-0.70293593,-1.86805880,0.50196815, +-0.54198223,-0.38484800,-0.05891366,-0.79304564,-0.58239877,0.26545495,-0.38297540,0.79097033, +-0.17095472,-0.31460449,0.78414583,0.25754923,0.49601099,1.01128983,-0.85820115,1.31935477, + +1.79820418,0.49160564,-1.04994130,-0.65047348,0.03673789,-1.43390560,0.33562672,0.16967399, +1.70193112,-0.31023103,-0.33280775,0.70939517,-1.27211368,-0.58704966,-1.81665146,0.03955793, +1.41204929,-1.20291567,0.22243243,2.67244053,0.75709999,-0.44346970,0.94684786,-0.61597395, + +-0.71324098,-0.24858820,-0.42040613,-0.47096899,-2.18410730,1.29030848,0.95546865,-0.01637810, +-0.40429014,0.48408982,1.63168097,0.71464306,0.93015838,-0.16759235,-2.20110703,0.78718776, +-0.37711632,-0.30456182,-0.73898333,0.39148647,-0.04324996,-1.18526721,-1.38802266,0.82284755, + +2.10404348,-0.25014257,2.06826448,0.68731880,-0.72305721,-3.06288505,1.35467649,-2.27782655, +1.27983427,1.74217772,-1.50595713,1.52578330,0.56935966,-0.94778556,-1.28090227,-0.02918145, +0.33568430,-3.36413050,1.40020049,1.05561769,-1.90628219,1.38226020,0.99804544,1.02540088, + +-2.04115343,0.01709199,1.14326739,-2.85616302,-1.63115931,1.21209049,-2.88173485,0.29401016, +0.99273205,2.60591888,1.39687920,-0.34032899,0.35641205,0.91440523,-0.69939649,2.64614010, +-1.05158651,-3.61572313,-2.07312417,0.55376863,-0.07229304,0.02950740,-1.17457461,0.59849799, + +0.96896434,1.49846828,-1.48152626,-0.40123838,0.66036439,-2.08949637,0.93013203,1.78407586, +0.65847164,-1.24047744,-0.11745319,0.80385536,-0.55450106,-0.64750642,-0.84041762,0.10586573, +0.56384206,0.21395147,1.26861954,2.02004290,-0.83739442,-0.11827546,-0.42885846,-1.55389440, + +-0.16418101,0.30182290,0.76461935,0.89762378,-0.70261180,1.31333566,0.86440170,-0.55341989, +-1.74471772,0.38858974,0.77225429,-0.47355813,0.59074765,-0.50501788,-1.72981727,-1.25862873, +-1.04708695,1.04990900,0.61408597,0.48327276,0.61544299,-0.57864964,-0.80768973,0.39645281, + +=== +name:PackedMultiHeadAttentionData_Batch2_HeadSize8_BroadcastRelPosBias.rel_pos_bias_data +0.09734076,-0.01747033,0.008497253,-0.03361112,-0.028750911,-0.017142132,-0.11563814,0.10432467, +0.057628587,0.030893803,-0.096876964,0.11924802,-0.009177148,0.05799888,-0.030559167,0.034150958, +0.07427484,0.028848544,-0.031371966,0.07186346,-0.093020484,-0.066411436,0.06858949,0.07350862, +0.008785307,-0.07727124,0.09184219,0.081774,0.008513406,-0.04256621,-0.078802094,-0.09632437, +-0.0073524266,0.035430342,-0.01940021,0.05564849,-0.03556633,-0.11830491,-0.05839123,-0.05537042, +0.06146671,0.0026960075,-0.07718696,-0.06268193,0.039188996,0.07048777,-0.0009800941,-0.04509197, +0.04516627,-0.09005861,0.06470743,0.12054373,0.03366275,0.009849519,0.015899211,0.11534238, +-0.002090156,-0.0851126,-0.05993013,0.030745044,-0.02415888,0.06568785,-0.012787953,0.021764219, + +-0.07153495,0.072637364,0.09073421,0.041491434,-0.11252555,-0.059031114,0.11179088,0.0655573, +-0.11293891,0.05239816,-0.110543296,-0.017368436,-0.050893307,0.04980643,-0.12137364,-0.08896659, +0.04159136,-0.021769747,0.018932432,0.087893024,-0.014453113,0.012075469,0.0026388168,-0.07094294, +0.035509557,0.065090835,0.115079954,-0.11314371,0.121840075,0.030929685,-0.051646978,-0.10540052, +-0.08004643,-0.089356855,-0.112021506,0.07381505,-0.06653316,-0.11657183,0.08264731,0.10898076, +-0.006200552,-0.0960899,-0.015346348,-0.047637567,0.051793993,-0.09059112,-0.034093216,0.108242184, +-0.049242377,-0.12165685,-0.09124553,0.05479528,-0.048966378,-0.027208641,0.10195236,0.047513425, +0.013226762,-0.07403794,0.06855075,-0.06551643,-0.084110215,0.11237715,0.07026932,-0.014076158, + +=== +name:PackedMultiHeadAttentionData_Batch2_HeadSize8_BroadcastRelPosBias.fp16_output_data +-1.1923828,0.38842773,0.68115234,0.21618652,-1.7753906,0.18579102,0.90429688,-0.2286377, +-0.95556641,1.3867188,0.81054688,0.14355469,0.15356445,0.004699707,0.039428711,0.53857422, + +0.46826172,-0.38012695,0.23950195,0.50976562,-0.35839844,-0.4597168,0.0065727234,-0.62060547, +-0.28198242,-0.4128418,-0.44287109,0.22363281,0.062408447,0.058746338,-0.75292969,0.82275391, + +0.18103027,0.17089844,0.31738281,-0.098022461,-1.0439453,-0.43823242,-0.19689941,-0.25537109, +-0.38745117,-0.32739258,-0.40332031,0.23425293,0.13305664,-0.3503418,-1.0107422,0.859375, + +0.14135742,-0.1895752,0.50634766,0.25634766,-1.0400391,-0.37524414,-0.16821289,-0.30371094, +-0.68164062,-1.4511719,-0.52636719,0.19763184,0.082946777,0.1776123,-0.97021484,0.73828125, + +0.23144531,-0.75341797,0.52148438,0.52148438,-0.92041016,-0.27001953,0.054473877,-0.19238281, +-0.68212891,-1.3339844,-0.75,0.37451172,-0.060058594,0.0034179688,-0.8671875,0.65429688, + +0.20629883,-0.37646484,0.37646484,0.13183594,-0.94873047,-0.34375,-0.059875488,-0.22937012, +-0.58105469,-0.63671875,-0.50732422,0.30419922,0.086791992,-0.23132324,-0.91210938,0.74902344, + +0.49804688,-1.3681641,0.75146484,1.0007825,-0.93847656,0.23278809,0.44604492,0.047668457, +-1.1943359,-0.75732422,0.48681641,-0.67480469,-0.0028400421,-0.37817383,-1.2705078,0.81201172, + +0.13586426,0.0039863586,0.36181641,0.22192383,-0.89648438,-0.609375,-0.26049805,-0.43920898, +-1.046875,-0.19360352,0.30297852,-0.20007324,0.20483398,-0.50097656,-1.1142578,0.71923828, + +0.37207031,-1.8447266,0.88818359,0.71191406,-1.3359375,0.56396484,0.52001953,0.36254883, +-0.73681641,-0.90722656,-0.29516602,0.021835327,0.030609131,-0.098083496,-0.96777344,0.75927734 +=== diff --git a/onnxruntime/test/testdata/attention_no_mask_fp16.onnx b/onnxruntime/test/testdata/attention_no_mask_fp16.onnx new file mode 100644 index 0000000000000..fe8aa0038d4fd Binary files /dev/null and b/onnxruntime/test/testdata/attention_no_mask_fp16.onnx differ diff --git a/onnxruntime/test/testdata/cuda_graph_with_shape_nodes.onnx b/onnxruntime/test/testdata/cuda_graph_with_shape_nodes.onnx new file mode 100644 index 0000000000000..9f433e0e7e91b Binary files /dev/null and b/onnxruntime/test/testdata/cuda_graph_with_shape_nodes.onnx differ diff --git a/onnxruntime/test/testdata/custom_execution_provider_library/my_ep_factory.cc b/onnxruntime/test/testdata/custom_execution_provider_library/my_ep_factory.cc index c082f6147a28f..6a2d27ee95170 100644 --- a/onnxruntime/test/testdata/custom_execution_provider_library/my_ep_factory.cc +++ b/onnxruntime/test/testdata/custom_execution_provider_library/my_ep_factory.cc @@ -31,7 +31,7 @@ std::shared_ptr CreateExecutionProviderFactory_MyEP(c } struct MyEP_Provider : Provider { - GSL_SUPPRESS(c .35) + GSL_SUPPRESS(c.35) std::shared_ptr CreateExecutionProviderFactory(const void* provider_options) override { ProviderOptions* options = (ProviderOptions*)(provider_options); MyProviderInfo info; 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 cf3c2ae39fa46..57471f7c029c2 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 @@ -19,8 +19,7 @@ MyExecutionProvider::MyExecutionProvider(const MyProviderInfo& info) [](OrtDevice::DeviceId device_id) { return std::make_unique(device_id); }, device_id_, true, - {0, 1, -1, -1, -1}}; - InsertAllocator(CreateAllocator(device_info)); + {0, 1, -1, -1, -1, -1L}}; } } // namespace onnxruntime diff --git a/onnxruntime/test/testdata/custom_op_get_const_input_test_library/custom_op.cc b/onnxruntime/test/testdata/custom_op_get_const_input_test_library/custom_op.cc index 4968127c2d896..08d8bf38d45d9 100644 --- a/onnxruntime/test/testdata/custom_op_get_const_input_test_library/custom_op.cc +++ b/onnxruntime/test/testdata/custom_op_get_const_input_test_library/custom_op.cc @@ -5,7 +5,12 @@ void simple_assert(const bool cond, const std::string& text) { if (!cond) { +#ifndef ORT_NO_EXCEPTIONS throw std::runtime_error(text); +#else + std::cerr << text << std::endl; + std::terminate(); +#endif } } diff --git a/onnxruntime/test/testdata/custom_op_get_const_input_test_library/custom_op_lib.cc b/onnxruntime/test/testdata/custom_op_get_const_input_test_library/custom_op_lib.cc index 34b33a2bdc0f3..2964e19c76725 100644 --- a/onnxruntime/test/testdata/custom_op_get_const_input_test_library/custom_op_lib.cc +++ b/onnxruntime/test/testdata/custom_op_get_const_input_test_library/custom_op_lib.cc @@ -25,17 +25,21 @@ OrtStatus* ORT_API_CALL RegisterCustomOps(OrtSessionOptions* options, const OrtA OrtStatus* result = nullptr; +#ifndef ORT_NO_EXCEPTIONS try { +#endif Ort::CustomOpDomain domain{c_OpDomain}; domain.Add(&c_CustomOp); session_options.Add(domain); AddOrtCustomOpDomainToContainer(std::move(domain)); +#ifndef ORT_NO_EXCEPTIONS } catch (const std::exception& e) { Ort::Status status{e}; result = status.release(); } +#endif return result; } diff --git a/onnxruntime/test/testdata/custom_op_library/cpu/cpu_ops.cc b/onnxruntime/test/testdata/custom_op_library/cpu/cpu_ops.cc new file mode 100644 index 0000000000000..f9e537fb61047 --- /dev/null +++ b/onnxruntime/test/testdata/custom_op_library/cpu/cpu_ops.cc @@ -0,0 +1,194 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#define ORT_API_MANUAL_INIT +#include "onnxruntime_cxx_api.h" +#undef ORT_API_MANUAL_INIT + +#include "onnxruntime_lite_custom_op.h" + +using namespace Ort::Custom; + +namespace Cpu { + +void KernelOne(const Ort::Custom::Tensor& X, + const Ort::Custom::Tensor& Y, + Ort::Custom::Tensor& Z) { + auto input_shape = X.Shape(); + auto x_raw = X.Data(); + auto y_raw = Y.Data(); + auto z_raw = Z.Allocate(input_shape); + for (int64_t i = 0; i < Z.NumberOfElement(); ++i) { + z_raw[i] = x_raw[i] + y_raw[i]; + } +} + +// lite custom op as a function +void KernelTwo(const Ort::Custom::Tensor& X, + Ort::Custom::Tensor& Y) { + const auto& shape = X.Shape(); + auto X_raw = X.Data(); + auto Y_raw = Y.Allocate(shape); + auto total = std::accumulate(shape.begin(), shape.end(), 1LL, std::multiplies()); + for (int64_t i = 0; i < total; i++) { + Y_raw[i] = static_cast(round(X_raw[i])); + } +} + +template +void MulTop(const Ort::Custom::Span& in, Ort::Custom::Tensor& out) { + out.Allocate({1})[0] = in[0] * in[1]; +} + +void Fuse( + OrtKernelContext*, + const Ort::Custom::Span& vector_1, + const Ort::Custom::Span& vector_2, + int32_t alpha, + Ort::Custom::Tensor& vector_output) { + auto len_output = std::min(vector_1.size(), vector_2.size()); + float* floats_out = static_cast(vector_output.Allocate({(int64_t)len_output})); + for (size_t i = 0; i < len_output; ++i) { + floats_out[i] = (vector_1[i] + vector_2[i]) * alpha; + } +} + +void Select(const Ort::Custom::Span& indices_in, + Ort::Custom::Tensor& indices_out) { + std::vector selected_indices; + for (size_t i = 0; i < indices_in.size(); ++i) { + if (indices_in[i] % 2 == 0) { + selected_indices.push_back(indices_in[i]); + } + } + + int32_t* int_out = static_cast(indices_out.Allocate({static_cast(selected_indices.size())})); + for (size_t j = 0; j < selected_indices.size(); ++j) { + int_out[j] = selected_indices[j]; + } +} + +void Filter(const Ort::Custom::Tensor& floats_in, + Ort::Custom::Tensor& floats_out) { + const float* in = floats_in.Data(); + auto in_len = floats_in.NumberOfElement(); + + std::vector filter_floats; + for (int64_t i = 0; i < in_len; ++i) { + if (in[i] > 1.f) { + filter_floats.push_back(in[i]); + } + } + + float* out = static_cast(floats_out.Allocate({static_cast(filter_floats.size())})); + for (size_t j = 0; j < filter_floats.size(); ++j) { + out[j] = filter_floats[j]; + } +} + +void Box(const Ort::Custom::Tensor* float_in_1, + const Ort::Custom::Tensor* float_in_2, + std::optional*> float_in_3, + Ort::Custom::Tensor* float_out_1, + std::optional*> float_out_2) { + auto raw_in_1 = float_in_1->Data(); + auto raw_in_2 = float_in_2->Data(); + + auto l_in_1 = float_in_1->Shape()[0]; + auto l_in_2 = float_in_2->Shape()[0]; + auto l_out_1 = l_in_1 + l_in_2; + + auto raw_out_1 = float_out_1->Allocate({l_out_1}); + + for (int64_t i = 0; i < l_out_1; ++i) { + raw_out_1[i] = i < l_in_1 ? raw_in_1[i] : raw_in_2[i - l_in_1]; + } + + if (float_in_3.has_value() && float_out_2.has_value()) { + auto raw_in_3 = float_in_3.value()->Data(); + auto l_in_3 = float_in_3.value()->Shape()[0]; + auto l_out_2 = l_in_2 + l_in_3; + auto raw_out_2 = float_out_2.value()->Allocate({l_out_2}); + for (int64_t i = 0; i < l_out_2; ++i) { + raw_out_2[i] = i < l_in_2 ? raw_in_2[i] : raw_in_3[i - l_in_2]; + } + } +} + +#if !defined(DISABLE_FLOAT8_TYPES) +struct KernelOneFloat8 { + void Compute(OrtKernelContext* context) { + Ort::KernelContext ctx(context); + auto input_X = ctx.GetInput(0); + const Ort::Float8E4M3FN_t* X = input_X.GetTensorData(); + auto dimensions = input_X.GetTensorTypeAndShapeInfo().GetShape(); + auto output = ctx.GetOutput(0, dimensions); + Ort::Float8E4M3FN_t* out = output.GetTensorMutableData(); + const size_t size = output.GetTensorTypeAndShapeInfo().GetElementCount(); + for (size_t i = 0; i < size; i++) { + out[i] = X[i]; + } + } +}; +// legacy custom op registration +struct CustomOpOneFloat8 : Ort::CustomOpBase { + void* CreateKernel(const OrtApi& /* api */, const OrtKernelInfo* /* info */) const { + return std::make_unique().release(); + }; + const char* GetName() const { return "CustomOpOneFloat8"; }; + const char* GetExecutionProviderType() const { return "CPUExecutionProvider"; }; + size_t GetInputTypeCount() const { return 2; }; + ONNXTensorElementDataType GetInputType(size_t /*index*/) const { return ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FN; }; + size_t GetOutputTypeCount() const { return 1; }; + ONNXTensorElementDataType GetOutputType(size_t /*index*/) const { return ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT8E4M3FN; }; +}; + +void FilterFloat8(const Ort::Custom::Tensor& floats_in, + Ort::Custom::Tensor& floats_out) { + const Ort::Float8E4M3FN_t* in = floats_in.Data(); + auto in_len = floats_in.NumberOfElement(); + + std::vector filter_floats; + for (int64_t i = 0; i < in_len; ++i) { + if (in[i] > 1.f) { + filter_floats.push_back(in[i]); + } + } + + Ort::Float8E4M3FN_t* out = static_cast(floats_out.Allocate({static_cast(filter_floats.size())})); + for (size_t j = 0; j < filter_floats.size(); ++j) { + out[j] = filter_floats[j]; + } +} +#endif + +void RegisterOps(Ort::CustomOpDomain& domain) { + static const std::unique_ptr c_CustomOpOne{Ort::Custom::CreateLiteCustomOp("CustomOpOne", "CPUExecutionProvider", KernelOne)}; + static const std::unique_ptr c_CustomOpTwo{Ort::Custom::CreateLiteCustomOp("CustomOpTwo", "CPUExecutionProvider", KernelTwo)}; + static const std::unique_ptr c_MulTopOpFloat{Ort::Custom::CreateLiteCustomOp("MulTop", "CPUExecutionProvider", MulTop)}; + static const std::unique_ptr c_MulTopOpInt32{Ort::Custom::CreateLiteCustomOp("MulTop", "CPUExecutionProvider", MulTop)}; + static const std::unique_ptr c_Fuse{Ort::Custom::CreateLiteCustomOp("Fuse", "CPUExecutionProvider", Fuse)}; + static const std::unique_ptr c_Select{Ort::Custom::CreateLiteCustomOp("Select", "CPUExecutionProvider", Select)}; + static const std::unique_ptr c_Fill{Ort::Custom::CreateLiteCustomOp("Filter", "CPUExecutionProvider", Filter)}; + static const std::unique_ptr c_Box{Ort::Custom::CreateLiteCustomOp("Box", "CPUExecutionProvider", Box)}; + +#if !defined(DISABLE_FLOAT8_TYPES) + static const CustomOpOneFloat8 c_CustomOpOneFloat8; + static const std::unique_ptr c_FilterFloat8{Ort::Custom::CreateLiteCustomOp("FilterFloat8", "CPUExecutionProvider", FilterFloat8)}; +#endif + + domain.Add(c_CustomOpOne.get()); + domain.Add(c_CustomOpTwo.get()); + domain.Add(c_MulTopOpFloat.get()); + domain.Add(c_MulTopOpInt32.get()); + domain.Add(c_Fuse.get()); + domain.Add(c_Select.get()); + domain.Add(c_Fill.get()); + domain.Add(c_Box.get()); +#if !defined(DISABLE_FLOAT8_TYPES) + domain.Add(&c_CustomOpOneFloat8); + domain.Add(c_FilterFloat8.get()); +#endif +} + +} // namespace Cpu diff --git a/onnxruntime/test/testdata/custom_op_library/cpu/cpu_ops.h b/onnxruntime/test/testdata/custom_op_library/cpu/cpu_ops.h new file mode 100644 index 0000000000000..34def0377af4f --- /dev/null +++ b/onnxruntime/test/testdata/custom_op_library/cpu/cpu_ops.h @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +namespace Cpu { + +void RegisterOps(Ort::CustomOpDomain& domain); + +} \ No newline at end of file diff --git a/onnxruntime/test/testdata/custom_op_library/cuda/cuda_ops.cc b/onnxruntime/test/testdata/custom_op_library/cuda/cuda_ops.cc new file mode 100644 index 0000000000000..aba35b33b75c6 --- /dev/null +++ b/onnxruntime/test/testdata/custom_op_library/cuda/cuda_ops.cc @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifdef USE_CUDA + +#define ORT_API_MANUAL_INIT +#include "onnxruntime_cxx_api.h" +#undef ORT_API_MANUAL_INIT + +#include "core/providers/cuda/cuda_context.h" +#include "onnxruntime_lite_custom_op.h" + +// #include +// #include +template +void cuda_add(int64_t, T3*, const T1*, const T2*, cudaStream_t compute_stream); + +using namespace Ort::Custom; + +#define CUSTOM_ENFORCE(cond, msg) \ + if (!(cond)) { \ + throw std::runtime_error(msg); \ + } + +namespace Cuda { + +void KernelOne(const Ort::Custom::CudaContext& cuda_ctx, + const Ort::Custom::Tensor& X, + const Ort::Custom::Tensor& Y, + Ort::Custom::Tensor& Z) { + auto input_shape = X.Shape(); + CUSTOM_ENFORCE(cuda_ctx.cuda_stream, "failed to fetch cuda stream"); + CUSTOM_ENFORCE(cuda_ctx.cudnn_handle, "failed to fetch cudnn handle"); + CUSTOM_ENFORCE(cuda_ctx.cublas_handle, "failed to fetch cublas handle"); + auto z_raw = Z.Allocate(input_shape); + cuda_add(Z.NumberOfElement(), z_raw, X.Data(), Y.Data(), cuda_ctx.cuda_stream); +} + +void RegisterOps(Ort::CustomOpDomain& domain) { + static const std::unique_ptr c_CustomOpOne{Ort::Custom::CreateLiteCustomOp("CustomOpOne", "CUDAExecutionProvider", KernelOne)}; + domain.Add(c_CustomOpOne.get()); +} + +} // namespace Cuda + +#else + +void Cuda::RegisterOps(Ort::CustomOpDomain& domain) {} + +#endif \ No newline at end of file diff --git a/onnxruntime/test/testdata/custom_op_library/cuda/cuda_ops.h b/onnxruntime/test/testdata/custom_op_library/cuda/cuda_ops.h new file mode 100644 index 0000000000000..c0287c4932c98 --- /dev/null +++ b/onnxruntime/test/testdata/custom_op_library/cuda/cuda_ops.h @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +namespace Cuda { + +void RegisterOps(Ort::CustomOpDomain& domain); + +} \ No newline at end of file diff --git a/onnxruntime/test/testdata/custom_op_library/custom_op_library.cc b/onnxruntime/test/testdata/custom_op_library/custom_op_library.cc index 16ce9e49c8e11..40fb127eb0b8f 100644 --- a/onnxruntime/test/testdata/custom_op_library/custom_op_library.cc +++ b/onnxruntime/test/testdata/custom_op_library/custom_op_library.cc @@ -7,100 +7,16 @@ #include #include #include +#include #include "core/common/common.h" - -#ifdef USE_CUDA -#include -template -void cuda_add(int64_t, T3*, const T1*, const T2*, cudaStream_t compute_stream); -#endif +#include "core/framework/ortdevice.h" +#include "core/framework/ortmemoryinfo.h" +#include "cpu/cpu_ops.h" +#include "onnxruntime_lite_custom_op.h" static const char* c_OpDomain = "test.customop"; -struct KernelOne { - void Compute(OrtKernelContext* context) { - // Setup inputs - Ort::KernelContext ctx(context); - auto input_X = ctx.GetInput(0); - auto input_Y = ctx.GetInput(1); - const float* X = input_X.GetTensorData(); - const float* Y = input_Y.GetTensorData(); - - // Setup output - auto dimensions = input_X.GetTensorTypeAndShapeInfo().GetShape(); - - auto output = ctx.GetOutput(0, dimensions); - float* out = output.GetTensorMutableData(); - - const size_t size = output.GetTensorTypeAndShapeInfo().GetElementCount(); - - // Do computation -#ifdef USE_CUDA - cudaStream_t stream = reinterpret_cast(ctx.GetGPUComputeStream()); - cuda_add(size, out, X, Y, stream); -#else - for (size_t i = 0; i < size; i++) { - out[i] = X[i] + Y[i]; - } -#endif - } -}; - -struct KernelTwo { - void Compute(OrtKernelContext* context) { - // Setup inputs - Ort::KernelContext ctx(context); - auto input_X = ctx.GetInput(0); - const float* X = input_X.GetTensorData(); - - // Setup output - auto dimensions = input_X.GetTensorTypeAndShapeInfo().GetShape(); - - auto output = ctx.GetOutput(0, dimensions); - int32_t* out = output.GetTensorMutableData(); - - const size_t size = output.GetTensorTypeAndShapeInfo().GetElementCount(); - - // Do computation - for (size_t i = 0; i < size; i++) { - out[i] = static_cast(round(X[i])); - } - } -}; - -struct CustomOpOne : Ort::CustomOpBase { - void* CreateKernel(const OrtApi& /* api */, const OrtKernelInfo* /* info */) const { - return std::make_unique().release(); - }; - - const char* GetName() const { return "CustomOpOne"; }; - -#ifdef USE_CUDA - const char* GetExecutionProviderType() const { return "CUDAExecutionProvider"; }; -#endif - - size_t GetInputTypeCount() const { return 2; }; - ONNXTensorElementDataType GetInputType(size_t /*index*/) const { 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_FLOAT; }; -}; - -struct CustomOpTwo : Ort::CustomOpBase { - void* CreateKernel(const OrtApi& /* api */, const OrtKernelInfo* /* info */) const { - return std::make_unique().release(); - }; - - const char* GetName() const { return "CustomOpTwo"; }; - - size_t GetInputTypeCount() const { return 1; }; - ONNXTensorElementDataType GetInputType(size_t /*index*/) const { 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_INT32; }; -}; - static void AddOrtCustomOpDomainToContainer(Ort::CustomOpDomain&& domain) { static std::vector ort_custom_op_domain_container; static std::mutex ort_custom_op_domain_mutex; @@ -110,20 +26,20 @@ static void AddOrtCustomOpDomainToContainer(Ort::CustomOpDomain&& domain) { OrtStatus* ORT_API_CALL RegisterCustomOps(OrtSessionOptions* options, const OrtApiBase* api) { Ort::Global::api_ = api->GetApi(ORT_API_VERSION); - - static const CustomOpOne c_CustomOpOne; - static const CustomOpTwo c_CustomOpTwo; - OrtStatus* result = nullptr; ORT_TRY { Ort::CustomOpDomain domain{c_OpDomain}; - domain.Add(&c_CustomOpOne); - domain.Add(&c_CustomOpTwo); + Cpu::RegisterOps(domain); + + Ort::CustomOpDomain domain_v2{"v2"}; + Cpu::RegisterOps(domain_v2); Ort::UnownedSessionOptions session_options(options); session_options.Add(domain); + session_options.Add(domain_v2); AddOrtCustomOpDomainToContainer(std::move(domain)); + AddOrtCustomOpDomainToContainer(std::move(domain_v2)); } ORT_CATCH(const std::exception& e) { ORT_HANDLE_EXCEPTION([&]() { diff --git a/onnxruntime/test/testdata/custom_op_library/custom_op_test_float8.onnx b/onnxruntime/test/testdata/custom_op_library/custom_op_test_float8.onnx new file mode 100644 index 0000000000000..7cc766fb09126 Binary files /dev/null and b/onnxruntime/test/testdata/custom_op_library/custom_op_test_float8.onnx differ diff --git a/onnxruntime/test/testdata/custom_op_library/custom_op_test_float8.py b/onnxruntime/test/testdata/custom_op_library/custom_op_test_float8.py new file mode 100644 index 0000000000000..84cf71455f84a --- /dev/null +++ b/onnxruntime/test/testdata/custom_op_library/custom_op_test_float8.py @@ -0,0 +1,24 @@ +""" +This file was used to generate model `custom_op_test_float8.py`. +""" +from onnx import TensorProto +from onnx.checker import check_model +from onnx.helper import make_graph, make_model, make_node, make_opsetid, make_tensor_value_info + +X = make_tensor_value_info("X", TensorProto.FLOAT8E4M3FN, [None]) +Y = make_tensor_value_info("Y", TensorProto.FLOAT8E4M3FN, [None]) +Z = make_tensor_value_info("Z", TensorProto.FLOAT8E4M3FN, [None]) +graph = make_graph( + [make_node("CustomOpOneFloat8", ["X", "Y"], ["Z"], domain="test.customop")], + "custom_op", + [X, Y], + [Z], +) +onnx_model = make_model( + graph, + opset_imports=[make_opsetid("", 19), make_opsetid("test.customop", 1)], + ir_version=9, +) +check_model(onnx_model) +with open("custom_op_test_float8.onnx", "wb") as f: + f.write(onnx_model.SerializeToString()) diff --git a/onnxruntime/test/testdata/custom_op_library/rocm/rocm_ops.cc b/onnxruntime/test/testdata/custom_op_library/rocm/rocm_ops.cc new file mode 100644 index 0000000000000..113bfb85454a2 --- /dev/null +++ b/onnxruntime/test/testdata/custom_op_library/rocm/rocm_ops.cc @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifdef USE_ROCM + +#define ORT_API_MANUAL_INIT +#include "onnxruntime_cxx_api.h" +#undef ORT_API_MANUAL_INIT + +#include "core/providers/rocm/rocm_context.h" +#include "onnxruntime_lite_custom_op.h" + +void rocm_add(int64_t, float*, const float*, const float*, hipStream_t compute_stream); + +using namespace Ort::Custom; + +#define CUSTOM_ENFORCE(cond, msg) \ + if (!(cond)) { \ + throw std::runtime_error(msg); \ + } + +namespace Cuda { + +void KernelOne(const Ort::Custom::RocmContext& rocm_ctx, + const Ort::Custom::Tensor& X, + const Ort::Custom::Tensor& Y, + Ort::Custom::Tensor& Z) { + auto input_shape = X.Shape(); + CUSTOM_ENFORCE(rocm_ctx.hip_stream, "failed to fetch hip stream"); + CUSTOM_ENFORCE(rocm_ctx.miopen_handle, "failed to fetch miopen handle"); + CUSTOM_ENFORCE(rocm_ctx.rblas_handle, "failed to fetch rocblas handle"); + auto z_raw = Z.Allocate(input_shape); + rocm_add(Z.NumberOfElement(), z_raw, X.Data(), Y.Data(), rocm_ctx.hip_stream); +} + +void RegisterOps(Ort::CustomOpDomain& domain) { + static const std::unique_ptr c_CustomOpOne{Ort::Custom::CreateLiteCustomOp("CustomOpOne", "ROCMExecutionProvider", KernelOne)}; + domain.Add(c_CustomOpOne.get()); +} + +} // namespace Cuda + +#else + +void Cuda::RegisterOps(Ort::CustomOpDomain& domain) {} + +#endif \ No newline at end of file diff --git a/onnxruntime/test/testdata/custom_op_library/rocm/rocm_ops.h b/onnxruntime/test/testdata/custom_op_library/rocm/rocm_ops.h new file mode 100644 index 0000000000000..4e8958cd9dae0 --- /dev/null +++ b/onnxruntime/test/testdata/custom_op_library/rocm/rocm_ops.h @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +namespace Rocm { + +void RegisterOps(Ort::CustomOpDomain& domain); + +} \ No newline at end of file diff --git a/onnxruntime/test/testdata/custom_op_single_schema_multi_kernel.onnx b/onnxruntime/test/testdata/custom_op_single_schema_multi_kernel.onnx new file mode 100644 index 0000000000000..7032437d889c1 --- /dev/null +++ b/onnxruntime/test/testdata/custom_op_single_schema_multi_kernel.onnx @@ -0,0 +1,26 @@ +: +5 const_two"Constant* +value*:B const_two +$ +X + const_twotop_f32top_i"TopK +# +top_f32top_int"Cast* +to + +top_f32mul_f32"MulTop:v2 + +top_intmul_int"MulTop:v2 + +mul_f32Y"Identity + +mul_intZ"IdentitygraphZ +X + + b +Y + + b +Z + + B \ No newline at end of file diff --git a/onnxruntime/test/testdata/flatten_broadcast.onnx b/onnxruntime/test/testdata/flatten_broadcast.onnx new file mode 100644 index 0000000000000..098c0821e6fbd Binary files /dev/null and b/onnxruntime/test/testdata/flatten_broadcast.onnx differ diff --git a/onnxruntime/test/testdata/float8/te.cast_fp8_1_fp32.onnx b/onnxruntime/test/testdata/float8/te.cast_fp8_1_fp32.onnx new file mode 100644 index 0000000000000..1dec9910087fc Binary files /dev/null and b/onnxruntime/test/testdata/float8/te.cast_fp8_1_fp32.onnx differ diff --git a/onnxruntime/test/testdata/float8/te.cast_fp8_1_fp32_input.npy b/onnxruntime/test/testdata/float8/te.cast_fp8_1_fp32_input.npy new file mode 100644 index 0000000000000..706f508836888 Binary files /dev/null and b/onnxruntime/test/testdata/float8/te.cast_fp8_1_fp32_input.npy differ diff --git a/onnxruntime/test/testdata/fuse_select_filter.onnx b/onnxruntime/test/testdata/fuse_select_filter.onnx new file mode 100644 index 0000000000000..15d7dd64788d3 --- /dev/null +++ b/onnxruntime/test/testdata/fuse_select_filter.onnx @@ -0,0 +1,28 @@ +: +P +vector_1 +vector_2 +alpha vector_fused fuse_node"Fuse* + fuse_algo:v2 +4 +indicesindices_selected select_node"Select:v2 +N + vector_fused +indices_selectedvector_gathered gather_node"GatherElements +; +vector_gatheredvector_filtered filter_node"Filter:v2graphZ +vector_1 + + Z +vector_2 + + Z +alpha + + Z +indices + + b& +vector_filtered + + B \ No newline at end of file diff --git a/onnxruntime/test/testdata/gather_with_scalar_indices_then_shape.onnx b/onnxruntime/test/testdata/gather_with_scalar_indices_then_shape.onnx new file mode 100644 index 0000000000000..c9229d90771d6 Binary files /dev/null and b/onnxruntime/test/testdata/gather_with_scalar_indices_then_shape.onnx differ diff --git a/onnxruntime/test/testdata/gather_with_scalar_indices_then_shape.py b/onnxruntime/test/testdata/gather_with_scalar_indices_then_shape.py new file mode 100644 index 0000000000000..7591b1da2ab91 --- /dev/null +++ b/onnxruntime/test/testdata/gather_with_scalar_indices_then_shape.py @@ -0,0 +1,26 @@ +from pathlib import Path + +import onnx +from onnx import helper +from onnx.onnx_pb import TensorProto + +nodes = [ + helper.make_node("Gather", ["X", "indices"], ["Y"], axis=1), + helper.make_node("Shape", ["Y"], ["Y_shape"]), +] + +graph = helper.make_graph( + nodes, + "GatherWithScalarIndicesThenShape", + [ # input + helper.make_tensor_value_info("X", TensorProto.FLOAT, ["M", "N", "K"]), + helper.make_tensor_value_info("indices", TensorProto.INT64, []), + ], + [ # output + helper.make_tensor_value_info("Y", TensorProto.FLOAT, None), + helper.make_tensor_value_info("Y_shape", TensorProto.INT64, None), + ], +) + +model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 19)]) +onnx.save(model, str(Path(__file__).with_suffix(".onnx"))) diff --git a/onnxruntime/test/testdata/matmul_with_dynamic_input_shape.onnx b/onnxruntime/test/testdata/matmul_with_dynamic_input_shape.onnx new file mode 100644 index 0000000000000..69a5f19f2c80c Binary files /dev/null and b/onnxruntime/test/testdata/matmul_with_dynamic_input_shape.onnx differ diff --git a/onnxruntime/test/testdata/matmul_with_dynamic_input_shape.py b/onnxruntime/test/testdata/matmul_with_dynamic_input_shape.py new file mode 100644 index 0000000000000..111cc9e4420eb --- /dev/null +++ b/onnxruntime/test/testdata/matmul_with_dynamic_input_shape.py @@ -0,0 +1,34 @@ +from pathlib import Path + +import onnx +from onnx import TensorProto, helper + +# This model contains a MatMul where: +# - A has shape [M, K] and `M` is a dynamic dimension. +# - B is an initializer with shape [K, N]. +# - This is important for the CoreML EP which only handles the case where B is an initializer. + +# M is dynamic +M = "M" +K = 2 +N = 4 + +graph = helper.make_graph( + [ # nodes + helper.make_node("MatMul", ["A", "B"], ["Y"], "MatMul"), + ], + "MatMulWithDynamicInputShape", # name + [ # inputs + helper.make_tensor_value_info("A", TensorProto.FLOAT, [M, K]), + ], + [ # outputs + helper.make_tensor_value_info("Y", TensorProto.FLOAT, [M, N]), + ], + [ # initializers + helper.make_tensor("B", TensorProto.FLOAT, [K, N], [float(i) for i in range(K * N)]), + ], +) + +opset_imports = [helper.make_operatorsetid("", 19)] +model = helper.make_model(graph, opset_imports=opset_imports) +onnx.save(model, str(Path(__file__).parent / "matmul_with_dynamic_input_shape.onnx")) diff --git a/onnxruntime/test/testdata/merge.onnx b/onnxruntime/test/testdata/merge.onnx new file mode 100644 index 0000000000000..1ae7a86d1f0b2 --- /dev/null +++ b/onnxruntime/test/testdata/merge.onnx @@ -0,0 +1,15 @@ +: +D +str_in_1 +str_in_2str_out +merge_node"Merge* +reverse:v2graphZ +str_in_1 + + Z +str_in_2 + + b +str_out + + B \ No newline at end of file diff --git a/onnxruntime/test/testdata/mobilenet_v3_small_excerpt.onnx b/onnxruntime/test/testdata/mobilenet_v3_small_excerpt.onnx new file mode 100644 index 0000000000000..23caad00a3b43 Binary files /dev/null and b/onnxruntime/test/testdata/mobilenet_v3_small_excerpt.onnx differ diff --git a/onnxruntime/test/testdata/mobilenet_v3_small_excerpt_gen.py b/onnxruntime/test/testdata/mobilenet_v3_small_excerpt_gen.py new file mode 100644 index 0000000000000..fac80acd6d98b --- /dev/null +++ b/onnxruntime/test/testdata/mobilenet_v3_small_excerpt_gen.py @@ -0,0 +1,125 @@ +""" +Run this script to recreate the original onnx model. +Example usage: +python mobilenet_v3_small_excerpt_gen.py out_model_path.onnx + +The excerpt model and this script were generated from a full model by first extracting the excerpt with +onnx.utils.extract_model [1] and then generating the python script from the excerpt model with onnx2py [2]. + +[1]: https://github.com/onnx/onnx/blob/v1.14.0/docs/PythonAPIOverview.md#extracting-sub-model-with-inputs-outputs-tensor-names +[2]: https://github.com/microsoft/onnxconverter-common/blob/v1.13.0/onnxconverter_common/onnx2py.py +""" + +import os +import sys + +import numpy as np +import onnx +from onnx import TensorProto, helper, numpy_helper + +DATA_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "mobilenet_v3_small_excerpt_gen") + + +def clear_field(proto, field): + proto.ClearField(field) + return proto + + +def order_repeated_field(repeated_proto, key_name, order): + order = list(order) + repeated_proto.sort(key=lambda x: order.index(getattr(x, key_name))) + + +def make_node(op_type, inputs, outputs, name=None, doc_string=None, domain=None, **kwargs): + node = helper.make_node(op_type, inputs, outputs, name, doc_string, domain, **kwargs) + if doc_string == "": + node.doc_string = "" + order_repeated_field(node.attribute, "name", kwargs.keys()) + return node + + +def make_graph(*args, doc_string=None, **kwargs): + graph = helper.make_graph(*args, doc_string=doc_string, **kwargs) + if doc_string == "": + graph.doc_string = "" + return graph + + +model = helper.make_model( + opset_imports=[clear_field(helper.make_operatorsetid("", 13), "domain")], + ir_version=6, + producer_name="onnx.utils.extract_model", + graph=make_graph( + name="Extracted from {torch-jit-export}", + inputs=[helper.make_tensor_value_info("input", TensorProto.FLOAT, shape=["batch_size", 3, 224, 224])], + outputs=[helper.make_tensor_value_info("254", TensorProto.FLOAT, shape=["batch_size", 16, 112, 112])], + initializer=[ + numpy_helper.from_array( + np.load(os.path.join(DATA_DIR, "const0_535.npy")).astype("float32").reshape([16, 3, 3, 3]), name="535" + ), + numpy_helper.from_array( + np.load(os.path.join(DATA_DIR, "const1_536.npy")).astype("float32").reshape([16]), name="536" + ), + ], + value_info=[ + helper.make_tensor_value_info("534", TensorProto.FLOAT, shape=["batch_size", 16, 112, 112]), + helper.make_tensor_value_info("247", TensorProto.FLOAT, shape=[]), + helper.make_tensor_value_info("248", TensorProto.FLOAT, shape=["batch_size", 16, 112, 112]), + helper.make_tensor_value_info("249", TensorProto.FLOAT, shape=[]), + helper.make_tensor_value_info("250", TensorProto.FLOAT, shape=[]), + helper.make_tensor_value_info("251", TensorProto.FLOAT, shape=["batch_size", 16, 112, 112]), + helper.make_tensor_value_info("252", TensorProto.FLOAT, shape=[]), + helper.make_tensor_value_info("253", TensorProto.FLOAT, shape=["batch_size", 16, 112, 112]), + helper.make_tensor_value_info("254", TensorProto.FLOAT, shape=["batch_size", 16, 112, 112]), + ], + nodes=[ + make_node( + "Conv", + inputs=["input", "535", "536"], + outputs=["534"], + name="Conv_0", + dilations=[1, 1], + group=1, + kernel_shape=[3, 3], + pads=[1, 1, 1, 1], + strides=[2, 2], + ), + make_node( + "Constant", + inputs=[], + outputs=["247"], + name="Constant_1", + value=numpy_helper.from_array(np.array(3.0, dtype="float32"), name=""), + ), + make_node("Add", inputs=["534", "247"], outputs=["248"], name="Add_2"), + make_node( + "Constant", + inputs=[], + outputs=["249"], + name="Constant_3", + value=numpy_helper.from_array(np.array(0.0, dtype="float32"), name=""), + ), + make_node( + "Constant", + inputs=[], + outputs=["250"], + name="Constant_4", + value=numpy_helper.from_array(np.array(6.0, dtype="float32"), name=""), + ), + make_node("Clip", inputs=["248", "249", "250"], outputs=["251"], name="Clip_5"), + make_node( + "Constant", + inputs=[], + outputs=["252"], + name="Constant_6", + value=numpy_helper.from_array(np.array(6.0, dtype="float32"), name=""), + ), + make_node("Div", inputs=["251", "252"], outputs=["253"], name="Div_7"), + make_node("Mul", inputs=["534", "253"], outputs=["254"], name="Mul_8"), + ], + ), +) + +if __name__ == "__main__" and len(sys.argv) == 2: + _, out_path = sys.argv + onnx.save(model, out_path) diff --git a/onnxruntime/test/testdata/mobilenet_v3_small_excerpt_gen/const0_535.npy b/onnxruntime/test/testdata/mobilenet_v3_small_excerpt_gen/const0_535.npy new file mode 100644 index 0000000000000..b9007274026f1 Binary files /dev/null and b/onnxruntime/test/testdata/mobilenet_v3_small_excerpt_gen/const0_535.npy differ diff --git a/onnxruntime/test/testdata/mobilenet_v3_small_excerpt_gen/const1_536.npy b/onnxruntime/test/testdata/mobilenet_v3_small_excerpt_gen/const1_536.npy new file mode 100644 index 0000000000000..f7c79de1318e9 Binary files /dev/null and b/onnxruntime/test/testdata/mobilenet_v3_small_excerpt_gen/const1_536.npy differ diff --git a/onnxruntime/test/testdata/model_with_external_initializers.py b/onnxruntime/test/testdata/model_with_external_initializers.py index 9b987f08b6663..8d2589a9e6564 100644 --- a/onnxruntime/test/testdata/model_with_external_initializers.py +++ b/onnxruntime/test/testdata/model_with_external_initializers.py @@ -1,6 +1,8 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. +import os + import numpy as np import onnx from onnx import TensorProto, helper @@ -14,19 +16,19 @@ def create_external_data_tensor(value, tensor_name): # type: (List[Any], Text) tensor_filename = f"{tensor_name}.bin" set_external_data(tensor, location=tensor_filename) - with open(os.path.join(tensor_filename), "wb") as data_file: # noqa: F821 + with open(os.path.join(tensor_filename), "wb") as data_file: data_file.write(tensor.raw_data) tensor.ClearField("raw_data") tensor.data_location = onnx.TensorProto.EXTERNAL return tensor -def GenerateModel(model_name): # noqa: N802 +def GenerateModel(model_name, external_data_name): # noqa: N802 # Create one input (ValueInfoProto) X = helper.make_tensor_value_info("X", TensorProto.FLOAT, [1, 2]) # noqa: N806 # Create second input (ValueInfoProto) - Pads = helper.make_tensor_value_info("Pads", TensorProto.INT64, [4]) # noqa: N806 + Pads = helper.make_tensor_value_info(external_data_name, TensorProto.INT64, [4]) # noqa: N806 # Create one output (ValueInfoProto) Y = helper.make_tensor_value_info("Y", TensorProto.FLOAT, [1, 4]) # noqa: N806 @@ -34,7 +36,7 @@ def GenerateModel(model_name): # noqa: N802 # Create a node (NodeProto) node_def = helper.make_node( "Pad", # node name - ["X", "Pads"], # inputs + ["X", external_data_name], # inputs ["Y"], # outputs mode="constant", # Attributes ) @@ -53,7 +55,7 @@ def GenerateModel(model_name): # noqa: N802 1, 1, ], - "Pads", + external_data_name, ) ], ) @@ -71,4 +73,5 @@ def GenerateModel(model_name): # noqa: N802 if __name__ == "__main__": - GenerateModel("model_with_external_initializers.onnx") + GenerateModel("model_with_external_initializers.onnx", "Pads") + GenerateModel("model_with_orig_ext_data.onnx", "model_with_orig_ext_data") diff --git a/onnxruntime/test/testdata/model_with_orig_ext_data.bin b/onnxruntime/test/testdata/model_with_orig_ext_data.bin new file mode 100644 index 0000000000000..d69e6beeff85d Binary files /dev/null and b/onnxruntime/test/testdata/model_with_orig_ext_data.bin differ diff --git a/onnxruntime/test/testdata/model_with_orig_ext_data.onnx b/onnxruntime/test/testdata/model_with_orig_ext_data.onnx new file mode 100644 index 0000000000000..6f9cce0bc5b4f --- /dev/null +++ b/onnxruntime/test/testdata/model_with_orig_ext_data.onnx @@ -0,0 +1,19 @@ +  onnx-example: +: +X +model_with_orig_ext_dataY"Pad* +mode"constant +test-model*JBmodel_with_orig_ext_dataj( +locationmodel_with_orig_ext_data.binpZ +X +  + +Z& +model_with_orig_ext_data + + +b +Y +  + +B \ No newline at end of file diff --git a/onnxruntime/test/testdata/multi_stream_models/cpu_if.onnx b/onnxruntime/test/testdata/multi_stream_models/cpu_if.onnx new file mode 100644 index 0000000000000..b9374feff46f9 Binary files /dev/null and b/onnxruntime/test/testdata/multi_stream_models/cpu_if.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 75e42d537f275..71a10f646a7c6 100644 --- a/onnxruntime/test/testdata/onnx_backend_test_series_filters.jsonc +++ b/onnxruntime/test/testdata/onnx_backend_test_series_filters.jsonc @@ -35,6 +35,7 @@ "^test_batchnorm_epsilon_training_mode", "^test_batchnorm_example_old", "^test_batchnorm_example_training_mode", + "^test_col2im_pads", // still one wrong value coming from the backtest example "^test_gathernd_example_int32_batch_dim1", "^test_max_int16", "^test_max_int8", @@ -102,9 +103,9 @@ "^test_if_opt", "^test_loop16_seq_none", "^test_identity_opt", - "^test_col2im_pads*", // remove this when using ONNX with this: https://github.com/onnx/onnx/pull/4769 // Following tests are for opset 16 ops and are not yet implemented in ORT "^test_roialign_aligned_*", + "^test_roialign_mode_max", // TODO: Remove once onnx test is fixed //GPU failures "^test_batchnorm_epsilon_training_mode_cuda", "^test_batchnorm_example_training_mode_cuda", @@ -163,8 +164,6 @@ "^test_edge_pad*", "^test_equal_bcast*", "^test_equal*", - "^test_equal_string_broadcast*", - "^test_equal_string*", "^test_reflect_pad*", "^test_resize_downsample_scales_cubic_antialias*", "^test_resize_downsample_scales_linear_antialias*", @@ -184,55 +183,9 @@ "^test_wrap_pad*", "^test_basic_deform_conv_with_padding*", "^test_basic_deform_conv_without_padding*", - "^test_cast_DOUBLE_to_FLOAT*", - "^test_cast_FLOAT8E4M3FNUZ_to_FLOAT*", - "^test_cast_FLOAT8E4M3FN_to_FLOAT*", - "^test_cast_FLOAT8E5M2FNUZ_to_FLOAT*", - "^test_cast_FLOAT8E5M2_to_FLOAT*", - "^test_cast_FLOAT_to_DOUBLE*", - "^test_cast_FLOAT_to_FLOAT8E4M3FNUZ*", - "^test_cast_FLOAT_to_FLOAT8E4M3FN*", - "^test_cast_FLOAT_to_FLOAT8E5M2FNUZ*", - "^test_cast_FLOAT_to_FLOAT8E5M2*", - "^test_cast_STRING_to_FLOAT*", - "^test_cast_no_saturate_FLOAT_to_FLOAT8E4M3FNUZ*", - "^test_cast_no_saturate_FLOAT_to_FLOAT8E4M3FN*", - "^test_cast_no_saturate_FLOAT_to_FLOAT8E5M2FNUZ*", - "^test_cast_no_saturate_FLOAT_to_FLOAT8E5M2*", - "^test_castlike_DOUBLE_to_FLOAT*", - "^test_castlike_DOUBLE_to_FLOAT_expanded*", - "^test_castlike_FLOAT8E4M3FNUZ_to_FLOAT*", - "^test_castlike_FLOAT8E4M3FNUZ_to_FLOAT_expanded*", - "^test_castlike_FLOAT8E4M3FN_to_FLOAT*", - "^test_castlike_FLOAT8E4M3FN_to_FLOAT_expanded*", - "^test_castlike_FLOAT8E5M2FNUZ_to_FLOAT*", - "^test_castlike_FLOAT8E5M2FNUZ_to_FLOAT_expanded*", - "^test_castlike_FLOAT8E5M2_to_FLOAT*", - "^test_castlike_FLOAT8E5M2_to_FLOAT_expanded*", - "^test_castlike_FLOAT_to_DOUBLE*", - "^test_castlike_FLOAT_to_DOUBLE_expanded*", - "^test_castlike_FLOAT_to_FLOAT8E4M3FNUZ*", - "^test_castlike_FLOAT_to_FLOAT8E4M3FNUZ_expanded*", - "^test_castlike_FLOAT_to_FLOAT8E4M3FN*", - "^test_castlike_FLOAT_to_FLOAT8E4M3FN_expanded*", - "^test_castlike_FLOAT_to_FLOAT8E5M2FNUZ*", - "^test_castlike_FLOAT_to_FLOAT8E5M2FNUZ_expanded*", - "^test_castlike_FLOAT_to_FLOAT8E5M2*", - "^test_castlike_FLOAT_to_FLOAT8E5M2_expanded*", - "^test_castlike_STRING_to_FLOAT*", - "^test_castlike_STRING_to_FLOAT_expanded*", "^test_constant_pad_negative_axes*", "^test_deform_conv_with_mask_bias*", "^test_deform_conv_with_multiple_offset_groups*", - "^test_dequantizelinear_axis*", - "^test_dequantizelinear*", - "^test_dequantizelinear_e4m3fn*", - "^test_dequantizelinear_e5m2*", - "^test_identity*", - "^test_quantizelinear_axis*", - "^test_quantizelinear*", - "^test_quantizelinear_e4m3fn*", - "^test_quantizelinear_e5m2*", "^test_reshape_allowzero_reordered*", "^test_reshape_extended_dims*", "^test_reshape_negative_dim*", @@ -243,12 +196,8 @@ "^test_reshape_reordered_last_dims*", "^test_reshape_zero_and_negative_dim*", "^test_reshape_zero_dim*", - "^test_size*", - "^test_size_example*", // TODO: fialures with Windows GPU CI Pipeline that are introduced with ONNX opset 19. Need to be fixed before ORT 1.15 release. "^test_averagepool_*", - "^test_equal_*", - "^test_equal_*", "^test_wrap_pad_cuda", "^test_resize_downsample_scales_cubic_A_n0p5_exclude_outside_cuda", "^test_resize_downsample_scales_cubic_antialias_cuda", @@ -374,28 +323,6 @@ "^test_negative_log_likelihood.*", "^test_softmax_cross_entropy.*" ], - "current_failing_tests_OPENVINO_MYRIAD": [ - "^test_range", - "^test_dynamicquantizelinear", - "^test_operator_index", - "^test_scatter_elements_with_negative_indices", // Does not support negative indices - "^test_pow", // Runs disabled pow tests from the "current_failing_tests" list at the top - "^test_pow_types_float", // Runs disabled pow tests from the "current_failing_tests" list at the top - "^test_neg", - "^test_basic_conv_with_padding", - "^test_basic_conv_without_padding", - "^test_conv_with_strides_and_asymmetric_padding", - "^test_conv_with_strides_no_padding", - "^test_conv_with_strides_padding", - "^test_sequence_insert_at_back", - "^test_sequence_insert_at_front", - "^test_min_one_input", - "^test_max_one_input", - "^test_sum_one_input", - "^test_loop13_seq", - "^test_if_seq", - "^test_gather_elements_negative_indices" - ], "current_failing_tests_OPENVINO_GPU": [ "^test_div", // temporarily exclude vgg19 test which comsumes too much memory, run out of memory on Upsquared device. @@ -496,7 +423,13 @@ "^test_resize_downsample_scales_linear", // Runs but there's accuracy mismatch "^test_training_dropout_default_mask", // Runs but there's accuracy mismatch "^test_training_dropout_mask", // Runs but there's accuracy mismatch - "^test_training_dropout_default" // Runs but there's accuracy mismatch + "^test_training_dropout_default", // Runs but there's accuracy mismatch + "^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_range_int32_type_negative_delta_expanded_cpu", // Error but not a failure. + "test_range_float_type_positive_delta_expanded_cpu", // Error but not a failure. + "test_scan_sum_cpu", // Disabled due to output mismatch with tolerance. + "test_scan9_sum_cpu" // Disabled due to output mismatch with tolerance. ], "current_failing_tests_OPENVINO_opset18": [ // pending opset 18 support, RUNTIME_EXCEPTION : Encountered unknown exception in Initialize() @@ -739,7 +672,21 @@ // The test cases for Bernoulli op are for informational purpose. The generator operator is // non-deterministic and may not produce the same values in different implementations // even if a seed is specified. - "^test_bernoulli_*" + "^test_bernoulli_*", + // No support for float8 in numpy + "^test_cast_no_saturate*", + "^test_cast_FLOAT8*", + "^test_castlike_FLOAT8*", + "^test_cast_FLOAT_to_FLOAT8*", + "^test_castlike_FLOAT_to_FLOAT8*", + "^test_cast_FLOAT16_to_FLOAT8*", + "^test_castlike_FLOAT16_to_FLOAT8*", + "^test_dequantizelinear_e*", + "^test_quantizelinear_e*", + "^test_castlike_FLOAT_to_BFLOAT16*", + "^test_castlike_FLOAT_to_STRING*", + "^test_castlike_BFLOAT16_to*", + "^test_castlike_FLOAT_to_BFLOAT16*" ], "failing_permanently_nodejs_binding": [ // those test cases are no longer available in later opset version diff --git a/onnxruntime/test/testdata/optional_2.onnx b/onnxruntime/test/testdata/optional_2.onnx new file mode 100644 index 0000000000000..5c39419eda4d8 --- /dev/null +++ b/onnxruntime/test/testdata/optional_2.onnx @@ -0,0 +1,17 @@ +: +8 + +float_in_1 + +float_in_2 float_out_1box_node"Box:v2graphZ! + +float_in_1 + + Z! + +float_in_2 + + b" + float_out_1 + + B \ No newline at end of file diff --git a/onnxruntime/test/testdata/optional_3.onnx b/onnxruntime/test/testdata/optional_3.onnx new file mode 100644 index 0000000000000..5aa13948bbdb1 --- /dev/null +++ b/onnxruntime/test/testdata/optional_3.onnx @@ -0,0 +1,26 @@ +: +Q + +float_in_1 + +float_in_2 + +float_in_3 float_out_1 float_out_2box_node"Box:v2graphZ! + +float_in_1 + + Z! + +float_in_2 + + Z! + +float_in_3 + + b" + float_out_1 + + b" + float_out_2 + + B \ No newline at end of file diff --git a/onnxruntime/test/testdata/ort_github_issue_15949.onnx b/onnxruntime/test/testdata/ort_github_issue_15949.onnx new file mode 100644 index 0000000000000..52053ddaad332 Binary files /dev/null and b/onnxruntime/test/testdata/ort_github_issue_15949.onnx differ diff --git a/onnxruntime/test/testdata/ort_github_issue_17000.onnx b/onnxruntime/test/testdata/ort_github_issue_17000.onnx new file mode 100644 index 0000000000000..8320c19cb6de4 Binary files /dev/null and b/onnxruntime/test/testdata/ort_github_issue_17000.onnx differ diff --git a/onnxruntime/test/testdata/ort_github_issue_17000.ort b/onnxruntime/test/testdata/ort_github_issue_17000.ort new file mode 100644 index 0000000000000..08d9826dd5346 Binary files /dev/null and b/onnxruntime/test/testdata/ort_github_issue_17000.ort differ diff --git a/onnxruntime/test/testdata/ort_github_issue_17000.py b/onnxruntime/test/testdata/ort_github_issue_17000.py new file mode 100644 index 0000000000000..43c10f5590212 --- /dev/null +++ b/onnxruntime/test/testdata/ort_github_issue_17000.py @@ -0,0 +1,77 @@ +import numpy as np +import onnx +from onnx import TensorProto, helper, numpy_helper + + +def order_repeated_field(repeated_proto, key_name, order): + order = list(order) + repeated_proto.sort(key=lambda x: order.index(getattr(x, key_name))) + + +def make_node(op_type, inputs, outputs, name=None, doc_string=None, domain=None, **kwargs): + node = helper.make_node(op_type, inputs, outputs, name, doc_string, domain, **kwargs) + if doc_string == "": + node.doc_string = "" + order_repeated_field(node.attribute, "name", kwargs.keys()) + return node + + +def make_graph(*args, doc_string=None, **kwargs): + graph = helper.make_graph(*args, doc_string=doc_string, **kwargs) + if doc_string == "": + graph.doc_string = "" + return graph + + +test_graph = make_graph( + name="test_graph", + # model input of a sequence type to test IsSparseTensor issue + inputs=[ + helper.make_tensor_sequence_value_info("seq_in", TensorProto.FLOAT, shape=None), + ], + outputs=[ + helper.make_tensor_value_info("still_has_elements", TensorProto.BOOL, shape=[]), + ], + initializer=[ + numpy_helper.from_array(np.array(0, dtype="int64"), name="i0"), + ], + nodes=[ + make_node("SequenceLength", inputs=["seq_in"], outputs=["seq_len"], name="get_seq_len"), + make_node("Greater", inputs=["seq_len", "i0"], outputs=["has_elements"], name="get_has_elements"), + # If node with one branch that has no nodes to test the allocation planner issue + # if sequence has elements: + # remove one + # output bool of whether it still has elements + # else: + # output false (gives us branch with no nodes) + make_node( + "If", + name="test_if", + inputs=["has_elements"], + outputs=["still_has_elements"], + then_branch=make_graph( + name="then", + inputs=[], + outputs=[helper.make_tensor_value_info("then_bool_out", TensorProto.BOOL, shape=[])], + nodes=[ + make_node("SequenceErase", inputs=["seq_in", "i0"], outputs=["seq_less_one"]), + make_node("SequenceLength", inputs=["seq_less_one"], outputs=["new_seq_len"]), + make_node("Greater", inputs=["new_seq_len", "i0"], outputs=["then_bool_out"]), + ], + ), + else_branch=make_graph( + name="else", + initializer=[numpy_helper.from_array(np.array(False, dtype="bool"), name="else_bool_out")], + inputs=[], + outputs=[helper.make_tensor_value_info("else_bool_out", TensorProto.BOOL, shape=[])], + nodes=[], + ), + ), + ], +) + +# Graph with Sequence operations and an If node that has a subgraph with no nodes +model = helper.make_model(opset_imports=[helper.make_operatorsetid("ai.onnx", 14)], ir_version=7, graph=test_graph) + +onnx.shape_inference.infer_shapes(model, strict_mode=True) +onnx.save(model, "ort_github_issue_17000.onnx") diff --git a/onnxruntime/test/testdata/packed_attention_fp16.rbp.onnx b/onnxruntime/test/testdata/packed_attention_fp16.rbp.onnx new file mode 100644 index 0000000000000..89257df2ff38d Binary files /dev/null and b/onnxruntime/test/testdata/packed_attention_fp16.rbp.onnx differ diff --git a/onnxruntime/test/testdata/packed_attention_fp16.rbp.py b/onnxruntime/test/testdata/packed_attention_fp16.rbp.py new file mode 100644 index 0000000000000..c0ababd220fc9 --- /dev/null +++ b/onnxruntime/test/testdata/packed_attention_fp16.rbp.py @@ -0,0 +1,131 @@ +""" +Run this script to recreate the original onnx model. +Example usage: +python packed_attention_fp16.model.py out_model_path.onnx +""" + +import sys + +import numpy as np +import onnx +from onnx import TensorProto, helper, numpy_helper + + +def clear_field(proto, field): + proto.ClearField(field) + return proto + + +def order_repeated_field(repeated_proto, key_name, order): + order = list(order) + repeated_proto.sort(key=lambda x: order.index(getattr(x, key_name))) + + +def make_node(op_type, inputs, outputs, name=None, doc_string=None, domain=None, **kwargs): + node = helper.make_node(op_type, inputs, outputs, name, doc_string, domain, **kwargs) + if not doc_string: + node.doc_string = "" + order_repeated_field(node.attribute, "name", kwargs.keys()) + return node + + +def make_graph(*args, doc_string=None, **kwargs): + graph = helper.make_graph(*args, doc_string=doc_string, **kwargs) + if not doc_string: + graph.doc_string = "" + return graph + + +model = helper.make_model( + opset_imports=[ + clear_field(helper.make_operatorsetid("", 12), "domain"), + helper.make_operatorsetid("com.microsoft", 1), + ], + ir_version=7, + producer_name="onnxruntime.transformers", + producer_version="1.15.0", + graph=make_graph( + name="torch-jit-export", + inputs=[ + helper.make_tensor_value_info("input", TensorProto.FLOAT16, shape=["token_count", "hidden_size"]), + helper.make_tensor_value_info("weight", TensorProto.FLOAT16, shape=["hidden_size", "hidden_size_x_3"]), + helper.make_tensor_value_info("bias", TensorProto.FLOAT16, shape=["hidden_size_x_3"]), + helper.make_tensor_value_info("token_offset", TensorProto.INT32, shape=["batch_size", "seq_len"]), + helper.make_tensor_value_info("cumulative_sequence_length", TensorProto.INT32, shape=["batch_size_plus_1"]), + helper.make_tensor_value_info( + "rbp", TensorProto.FLOAT16, shape=["batch_size", "num_heads", "seq_len", "seq_len"] + ), + ], + outputs=[helper.make_tensor_value_info("output", TensorProto.FLOAT16, shape=["token_count", "hidden_size"])], + nodes=[ + make_node( + "Constant", + inputs=[], + outputs=["constant_0"], + name="constant_0", + value=numpy_helper.from_array(np.array([0], dtype="int64"), name=""), + ), + make_node( + "Constant", + inputs=[], + outputs=["constant_1"], + name="Constant_1", + value=numpy_helper.from_array(np.array([1], dtype="int64"), name=""), + ), + make_node( + "Constant", + inputs=[], + outputs=["constant_last"], + name="constant_last", + value=numpy_helper.from_array(np.array([-1], dtype="int64"), name=""), + ), + make_node( + "Constant", + inputs=[], + outputs=["constant_max"], + name="Constant_max", + value=numpy_helper.from_array(np.array([9223372036854775807], dtype="int64"), name=""), + ), + make_node( + "Slice", + inputs=["cumulative_sequence_length", "constant_0", "constant_last"], + outputs=["start"], + name="slice_start", + ), + make_node( + "Slice", + inputs=["cumulative_sequence_length", "constant_1", "constant_max"], + outputs=["end"], + name="slice_end", + ), + make_node("Sub", inputs=["end", "start"], outputs=["mask_idx"]), + make_node( + "RestorePadding", + inputs=["input", "token_offset"], + outputs=["restore_padding_output"], + name="RestorePadding_1", + domain="com.microsoft", + ), + make_node( + "Attention", + inputs=["restore_padding_output", "weight", "bias", "mask_idx", "", "rbp"], + outputs=["attention_outputs"], + name="Attention_0", + domain="com.microsoft", + num_heads=12, + mask_filter_value=-3.4028234663852886e38, + ), + make_node( + "RemovePadding", + inputs=["attention_outputs", "mask_idx"], + outputs=["output", "remove_padding_token_offset", "cumulated_seq_len", "max_seq_len"], + name="RemovePadding_0", + domain="com.microsoft", + ), + ], + ), +) + +if __name__ == "__main__" and len(sys.argv) == 2: + _, out_path = sys.argv + onnx.save(model, out_path) diff --git a/onnxruntime/test/testdata/qnn_ep_partial_support.onnx b/onnxruntime/test/testdata/qnn_ep_partial_support.onnx new file mode 100644 index 0000000000000..4eac77a80d2e3 Binary files /dev/null and b/onnxruntime/test/testdata/qnn_ep_partial_support.onnx differ diff --git a/onnxruntime/test/testdata/required_ops.config b/onnxruntime/test/testdata/required_ops.config index ac9d46666e1b6..e70362bab4017 100644 --- a/onnxruntime/test/testdata/required_ops.config +++ b/onnxruntime/test/testdata/required_ops.config @@ -3,9 +3,9 @@ ai.onnx;7;Abs,Add,And,BatchNormalization,Concat,Conv,Dropout,Flatten,Foo,Gather, ai.onnx;8;Add,Conv,Flatten,Gemm,MatMul,MaxPool,Mul,Relu,Reshape ai.onnx;9;Abs,Add,BatchNormalization,Cast,Clip,Concat,Constant,ConstantOfShape,Conv,Div,Equal,Gather,Gemm,Identity,If,LayerNormalization,LeakyRelu,Loop,MatMul,Mul,Pow,ReduceMean,Relu,Reshape,Scan,Shape,Sigmoid,Slice,Softmax,Softsign,Sqrt,Squeeze,Sub,Tanh,Transpose,Unsqueeze ai.onnx;10;Add,Cast,Concat,ConstantOfShape,Div,Dropout,Erf,Expand,Gather,Greater,Identity,If,LayerNormalization,Loop,MatMul,Mul,Neg,NonZero,Pow,ReduceMean,ReduceSum,Shape,Sqrt,Squeeze,Sub,Tanh,Transpose,Unsqueeze -ai.onnx;11;Abs,Add,ArgMax,BatchNormalization,Cast,Clip,Concat,Constant,ConstantOfShape,Conv,Div,Equal,Exp,Expand,Flatten,Gather,Gemm,Identity,If,LayerNormalization,Log,Loop,MatMul,MatMulInteger,Max,Min,Mul,Neg,Pow,RandomUniform,Range,ReduceMean,ReduceSum,ReduceSumSquare,Relu,Reshape,Scan,SequenceConstruct,SequenceInsert,SequenceLength,Shape,Sigmoid,Slice,Softmax,Split,Sqrt,Squeeze,Sub,Sum,Tanh,Transpose,Unsqueeze,Where +ai.onnx;11;Abs,Add,ArgMax,BatchNormalization,Cast,Clip,Concat,Constant,ConstantOfShape,Conv,Div,Equal,Exp,Expand,Flatten,Gather,Gemm,Identity,If,LayerNormalization,Log,Loop,MatMul,MatMulInteger,Max,Min,Mul,Neg,Pow,RandomUniform,Range,ReduceMean,ReduceSum,ReduceSumSquare,Relu,Reshape,Scan,SequenceConstruct,SequenceErase,SequenceInsert,SequenceLength,Shape,Sigmoid,Slice,Softmax,Split,Sqrt,Squeeze,Sub,Sum,Tanh,Transpose,Unsqueeze,Where ai.onnx;12;Add,And,Cast,Concat,Constant,ConstantOfShape,Conv,CumSum,Div,Dropout,DynamicQuantizeLinear,Equal,Erf,Expand,Flatten,Gather,GatherND,Gemm,GlobalAveragePool,Greater,Identity,If,IsInf,LayerNormalization,Less,Loop,MatMul,MatMulInteger,Min,Mul,Not,Pad,Pow,RandomNormalLike,RandomUniform,ReduceMean,ReduceSum,Relu,Reshape,Shape,Slice,Softmax,SoftmaxCrossEntropyLoss,SparseSoftmaxCrossEntropy,Split,Sqrt,Squeeze,Sub,Tanh,Transpose,Unsqueeze,Where -ai.onnx;13;Abs,Add,Cast,Concat,ConstantOfShape,Conv,DequantizeLinear,DynamicQuantizeLinear,Equal,Expand,FooBar,FooBar_Attr,Gather,Identity,LayerNormalization,MatMul,MatMulInteger,Mul,Pad,Pow,QuantizeLinear,Range,ReduceSum,Reshape,Shape,Tanh,Transpose,Unsqueeze,Where +ai.onnx;13;Abs,Add,Cast,Concat,ConstantOfShape,Conv,DequantizeLinear,DynamicQuantizeLinear,Equal,Expand,FooBar,FooBar_Attr,Gather,Greater,Identity,If,LayerNormalization,MatMul,MatMulInteger,Mul,Pad,Pow,QuantizeLinear,Range,ReduceSum,Reshape,Shape,Tanh,Transpose,Unsqueeze,Where ai.onnx;14;Add,ArgMax,Cast,Conv,Identity,Relu,Sigmoid,Sub ai.onnx;314159;Add ai.onnx.contrib;1;StringLower diff --git a/onnxruntime/test/testdata/required_ops_and_types.config b/onnxruntime/test/testdata/required_ops_and_types.config index 17687906d7250..41f374214747b 100644 --- a/onnxruntime/test/testdata/required_ops_and_types.config +++ b/onnxruntime/test/testdata/required_ops_and_types.config @@ -1,9 +1,12 @@ # required ops and types for ORT format models in testdata -ai.onnx;1;Conv{"inputs": {"0": ["float"]}},Foo,Identity +ai.onnx;1;Conv{"inputs": {"0": ["float"]}} ai.onnx;5;Reshape ai.onnx;6;Relu{"inputs": {"0": ["float"]}} ai.onnx;7;Add{"inputs": {"0": ["float"]}},Gemm{"inputs": {"0": ["float"]}},Mul{"inputs": {"0": ["float"]}} ai.onnx;8;MaxPool{"inputs": {"0": ["float"]}},Sum{"inputs": {"0": ["float"]}} ai.onnx;9;Cast{"inputs": {"0": ["float"]}, "outputs": {"0": ["bool"]}} -ai.onnx;11;ArgMax{"inputs": {"0": ["float"]}},If,Loop +ai.onnx;10;QLinearConv{"inputs": {"0": ["uint8_t"]}} +ai.onnx;11;ArgMax{"inputs": {"0": ["float"]}},Clip{"inputs": {"0": ["float"]}},Conv{"inputs": {"0": ["float"]}},If,Loop,SequenceErase,SequenceLength +ai.onnx;13;DequantizeLinear{"inputs": {"0": ["int32_t", "uint8_t"]}},Greater{"inputs": {"0": ["int64_t"]}},If,QuantizeLinear{"outputs": {"0": ["uint8_t"]}} ai.onnx.ml;1;ArrayFeatureExtractor,LinearClassifier,Normalizer,ZipMap +test;1;Foo diff --git a/onnxruntime/test/testdata/shape_then_slice_and_gather.onnx b/onnxruntime/test/testdata/shape_then_slice_and_gather.onnx new file mode 100644 index 0000000000000..7a22122152583 Binary files /dev/null and b/onnxruntime/test/testdata/shape_then_slice_and_gather.onnx differ diff --git a/onnxruntime/test/testdata/shape_then_slice_and_gather.py b/onnxruntime/test/testdata/shape_then_slice_and_gather.py new file mode 100644 index 0000000000000..382f5ff77d38b --- /dev/null +++ b/onnxruntime/test/testdata/shape_then_slice_and_gather.py @@ -0,0 +1,33 @@ +from pathlib import Path + +import onnx +from onnx import helper +from onnx.onnx_pb import TensorProto + +nodes = [ + helper.make_node("Shape", ["X"], ["X_shape"]), + helper.make_node("Gather", ["X_shape", "gather_indices"], ["gather_out"], axis=0), + helper.make_node("Slice", ["X_shape", "slice_starts", "slice_ends", "slice_axes", "slice_steps"], ["slice_out"]), +] + +graph = helper.make_graph( + nodes, + "ShapeThenSliceAndGather", + [ # input + helper.make_tensor_value_info("X", TensorProto.FLOAT, ["A", "B", "C", "D", "E"]), + ], + [ # output + helper.make_tensor_value_info("gather_out", TensorProto.INT64, None), + helper.make_tensor_value_info("slice_out", TensorProto.INT64, None), + ], + [ # initializer + helper.make_tensor("gather_indices", TensorProto.INT64, [2], [1, 3]), + helper.make_tensor("slice_starts", TensorProto.INT64, [1], [-1]), + helper.make_tensor("slice_ends", TensorProto.INT64, [1], [-6]), + helper.make_tensor("slice_axes", TensorProto.INT64, [1], [0]), + helper.make_tensor("slice_steps", TensorProto.INT64, [1], [-2]), + ], +) + +model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 19)]) +onnx.save(model, str(Path(__file__).with_suffix(".onnx"))) diff --git a/onnxruntime/test/testdata/squeezenet/model.onnx b/onnxruntime/test/testdata/squeezenet/model.onnx index b8e1dfce26d99..24de98fd4bc1e 100644 Binary files a/onnxruntime/test/testdata/squeezenet/model.onnx and b/onnxruntime/test/testdata/squeezenet/model.onnx differ diff --git a/onnxruntime/test/testdata/training_api/adamw.onnx b/onnxruntime/test/testdata/training_api/adamw.onnx index eed8ef5e4883b..9195778176c71 100644 Binary files a/onnxruntime/test/testdata/training_api/adamw.onnx and b/onnxruntime/test/testdata/training_api/adamw.onnx differ diff --git a/onnxruntime/test/testdata/training_api/checkpoint.ckpt b/onnxruntime/test/testdata/training_api/checkpoint.ckpt new file mode 100644 index 0000000000000..d0b7d0deb654c Binary files /dev/null and b/onnxruntime/test/testdata/training_api/checkpoint.ckpt differ diff --git a/onnxruntime/test/testdata/training_api/checkpoint.ckpt/paramtrain_tensors.pbseq b/onnxruntime/test/testdata/training_api/checkpoint.ckpt/paramtrain_tensors.pbseq deleted file mode 100644 index 0115dbf1289d1..0000000000000 Binary files a/onnxruntime/test/testdata/training_api/checkpoint.ckpt/paramtrain_tensors.pbseq and /dev/null differ diff --git a/onnxruntime/test/testdata/training_api/custom_ops/checkpoint b/onnxruntime/test/testdata/training_api/custom_ops/checkpoint new file mode 100644 index 0000000000000..753b24af63ba2 Binary files /dev/null and b/onnxruntime/test/testdata/training_api/custom_ops/checkpoint differ diff --git a/onnxruntime/test/testdata/training_api/custom_ops/training_model.onnx b/onnxruntime/test/testdata/training_api/custom_ops/training_model.onnx new file mode 100644 index 0000000000000..8c8e4f38d7b25 Binary files /dev/null and b/onnxruntime/test/testdata/training_api/custom_ops/training_model.onnx differ diff --git a/onnxruntime/test/testdata/training_api/load_checkpoint/paramfrozen_tensors.pbseq b/onnxruntime/test/testdata/training_api/load_checkpoint/paramfrozen_tensors.pbseq deleted file mode 100644 index 9ca440ed7f765..0000000000000 Binary files a/onnxruntime/test/testdata/training_api/load_checkpoint/paramfrozen_tensors.pbseq and /dev/null differ diff --git a/onnxruntime/test/testdata/training_api/load_checkpoint/paramtrain_tensors.pbseq b/onnxruntime/test/testdata/training_api/load_checkpoint/paramtrain_tensors.pbseq deleted file mode 100644 index b85f868362078..0000000000000 Binary files a/onnxruntime/test/testdata/training_api/load_checkpoint/paramtrain_tensors.pbseq and /dev/null differ diff --git a/onnxruntime/test/testdata/training_api/loss_1.out b/onnxruntime/test/testdata/training_api/loss_1.out index 0870a3b963b39..9ce10f18e26f3 100644 --- a/onnxruntime/test/testdata/training_api/loss_1.out +++ b/onnxruntime/test/testdata/training_api/loss_1.out @@ -1,2 +1,2 @@ loss -2.54967 \ No newline at end of file +2.1786249 diff --git a/onnxruntime/test/testdata/training_api/loss_2.out b/onnxruntime/test/testdata/training_api/loss_2.out index 8114e7494076f..4c2687e01ae7e 100644 --- a/onnxruntime/test/testdata/training_api/loss_2.out +++ b/onnxruntime/test/testdata/training_api/loss_2.out @@ -1,2 +1,2 @@ loss -0.515547 \ No newline at end of file +0.36050943 diff --git a/onnxruntime/test/testdata/training_api/ort_format/checkpoint b/onnxruntime/test/testdata/training_api/ort_format/checkpoint new file mode 100644 index 0000000000000..ab35c9ad5acde Binary files /dev/null and b/onnxruntime/test/testdata/training_api/ort_format/checkpoint differ diff --git a/onnxruntime/test/testdata/training_api/ort_format/eval_model.ort b/onnxruntime/test/testdata/training_api/ort_format/eval_model.ort new file mode 100644 index 0000000000000..69b2c7e029de0 Binary files /dev/null and b/onnxruntime/test/testdata/training_api/ort_format/eval_model.ort differ diff --git a/onnxruntime/test/testdata/training_api/ort_format/optimizer_model.ort b/onnxruntime/test/testdata/training_api/ort_format/optimizer_model.ort new file mode 100644 index 0000000000000..88f192462362d Binary files /dev/null and b/onnxruntime/test/testdata/training_api/ort_format/optimizer_model.ort differ diff --git a/onnxruntime/test/testdata/training_api/ort_format/prepare_artifacts.py b/onnxruntime/test/testdata/training_api/ort_format/prepare_artifacts.py new file mode 100644 index 0000000000000..70e8c4ac011a9 --- /dev/null +++ b/onnxruntime/test/testdata/training_api/ort_format/prepare_artifacts.py @@ -0,0 +1,70 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +"""This file is used to generate test data for ort format model tests in + orttraining/orttraining/test/training_api/core/training_capi_tests.cc.""" + +import onnx +import torch +import torch.nn as nn + +from onnxruntime.training import artifacts + + +class SimpleNet(nn.Module): + def __init__(self, input_size, hidden_size, output_size): + super().__init__() + self.fc1 = nn.Linear(input_size, hidden_size) + self.relu = nn.ReLU() + self.fc2 = nn.Linear(hidden_size, output_size) + + def forward(self, x): + out = self.fc1(x) + out = self.relu(out) + out = self.fc2(out) + return out + + +def model_export(pt_model, model_path, input_size): + # Generate random input data + input_data = torch.randn(32, input_size) + torch.onnx.export( + pt_model, + input_data, + model_path, + input_names=["input"], + output_names=["output"], + dynamic_axes={"input": {0: "batch_size"}, "output": {0: "batch_size"}}, + ) + + +def main(): + # Set the dimensions for input, hidden, and output layers + input_size = 10 + hidden_size = 20 + output_size = 5 + + # Create an instance of the neural network + pt_model = SimpleNet(input_size, hidden_size, output_size) + + train_model_path = "simplenet_training.onnx" + model_export(pt_model, train_model_path, input_size) + + onnx_model = onnx.load(train_model_path) + + requires_grad = ["fc2.weight", "fc2.bias"] + frozen_params = [param.name for param in onnx_model.graph.initializer if param.name not in requires_grad] + + # Generate the training artifacts. + artifacts.generate_artifacts( + onnx_model, + requires_grad=requires_grad, + frozen_params=frozen_params, + loss=artifacts.LossType.CrossEntropyLoss, + optimizer=artifacts.OptimType.AdamW, + ort_format=True, + ) + + +if __name__ == "__main__": + main() diff --git a/onnxruntime/test/testdata/training_api/ort_format/training_model.ort b/onnxruntime/test/testdata/training_api/ort_format/training_model.ort new file mode 100644 index 0000000000000..94bda328a9f9f Binary files /dev/null and b/onnxruntime/test/testdata/training_api/ort_format/training_model.ort differ diff --git a/onnxruntime/test/testdata/transform/bert_toy_opset14.onnx b/onnxruntime/test/testdata/transform/bert_toy_opset14.onnx new file mode 100755 index 0000000000000..150184ba7698e Binary files /dev/null and b/onnxruntime/test/testdata/transform/bert_toy_opset14.onnx differ diff --git a/onnxruntime/test/testdata/transform/constant_float16_mul.onnx b/onnxruntime/test/testdata/transform/constant_float16_mul.onnx new file mode 100644 index 0000000000000..baa682edb7f56 --- /dev/null +++ b/onnxruntime/test/testdata/transform/constant_float16_mul.onnx @@ -0,0 +1,17 @@ +onnxruntime_test: +2c1c1_node"Constant* +value*  +*xBc1v +3c2c2_node"Constant* +value* +*Bc2v + +c1 +c2 +mul_outputmul"Mul float16_mulb + +mul_output + + + +B \ No newline at end of file diff --git a/onnxruntime/test/testdata/transform/convert_qdq_ops_to_ms_domain.py b/onnxruntime/test/testdata/transform/convert_qdq_ops_to_ms_domain.py new file mode 100644 index 0000000000000..f74342403f4c3 --- /dev/null +++ b/onnxruntime/test/testdata/transform/convert_qdq_ops_to_ms_domain.py @@ -0,0 +1,177 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# -------------------------------------------------------------------------- +""" +Loads a model and updates the domain of QuantizeLinear and DequantizeLinear nodes to 'com.microsoft'. +Optionally updates zero-points to 16bit data types. + +This is used to create models for testing QDQ transformations with the contrib QDQ ops. + +Usage: +python3 convert_qdq_ops_to_ms_domain.py --input_model --output_model --use_16bit_qdq + +Models created with this script: +- qdq_with_multi_consumer_dq_nodes.fixed.qdq_contrib.onnx +- qdq_with_multi_consumer_dq_nodes.fixed.qdq16_contrib.onnx +- fusion/constant_folding_dequantizelinear.qdq_contrib.onnx +- fusion/constant_folding_dequantizelinear.qdq16_contrib.onnx +- fusion/constant_folding_qdq_node_unit.qdq_contrib.onnx +- fusion/constant_folding_qdq_node_unit.qdq16_contrib.onnx +- fusion/constant_folding_qdq_node_unit.graph_output.qdq_contrib.onnx +- fusion/constant_folding_qdq_node_unit.graph_output.qdq16_contrib.onnx +""" +from __future__ import annotations + +import argparse +import os +import struct +import sys + +import onnx +from onnx import shape_inference + +QDQ_OPS = ("QuantizeLinear", "DequantizeLinear") +QDQ_CONVERT_TYPES = {onnx.TensorProto.UINT8: onnx.TensorProto.UINT16, onnx.TensorProto.INT8: onnx.TensorProto.INT16} +TYPE_TO_STRUCT_LABEL = { + onnx.TensorProto.UINT8: "B", + onnx.TensorProto.INT8: "b", + onnx.TensorProto.UINT16: "H", + onnx.TensorProto.INT16: "h", +} + + +def convert_initializer_to_16bits(initializer: onnx.TensorProto, target_type: onnx.TensorProto.DataType): + byte_order = ">" if sys.byteorder == "big" else "<" + byte_label = TYPE_TO_STRUCT_LABEL[initializer.data_type] + short_label = TYPE_TO_STRUCT_LABEL[target_type] + + # Do not support external data + if initializer.HasField("data_location") and initializer.data_location == onnx.TensorProto.EXTERNAL: + raise Exception("Do not support initializers with external data") + + # Need to convert raw_data bytes to 16-bit values. + # NOTE: For tensors that use .int32_data instead of .raw_data, we don't need any special handling + # other than updating the data type. This is because the upper 24 bits are already cleared to zero. + if initializer.HasField("raw_data"): + num_byte_vals = len(initializer.raw_data) + + # Extract 8-bit values as int32s + int32_vals = struct.unpack(f"{byte_order}{num_byte_vals}{byte_label}", initializer.raw_data) + + # Repack int32 values as 16-bit values + initializer.raw_data = struct.pack(f"{byte_order}{num_byte_vals}{short_label}", *int32_vals) + + initializer.data_type = target_type + + +def convert_qdq_op_to_16bit( + name_to_initializer: dict[str, onnx.TensorProto], + name_to_values: dict[str, onnx.ValueInfoProto], + name_to_inputs: dict[str, onnx.ValueInfoProto], + name_to_outputs: dict[str, onnx.ValueInfoProto], + node: onnx.NodeProto, +): + zp_input = node.input[2] if len(node.input) > 2 else None + + if zp_input in name_to_initializer: + zp_initializer = name_to_initializer[zp_input] + + zp_target_type = QDQ_CONVERT_TYPES.get(zp_initializer.data_type) + if zp_target_type: + convert_initializer_to_16bits(zp_initializer, zp_target_type) + + if node.op_type == "DequantizeLinear": + input0 = node.input[0] + + if input0 in name_to_initializer: + input_initializer = name_to_initializer[input0] + input_target_type = QDQ_CONVERT_TYPES.get(input_initializer.data_type) + if input_target_type: + convert_initializer_to_16bits(input_initializer, input_target_type) + elif input0 in name_to_values: + input_val = name_to_values[input0] + input_target_type = QDQ_CONVERT_TYPES.get(input_val.type.tensor_type.elem_type) + if input_target_type: + input_val.type.tensor_type.elem_type = input_target_type + elif input0 in name_to_inputs: + input_val = name_to_inputs[input0] + input_target_type = QDQ_CONVERT_TYPES.get(input_val.type.tensor_type.elem_type) + if input_target_type: + input_val.type.tensor_type.elem_type = input_target_type + else: + # QuantizeLinear + output0 = node.output[0] + + if output0 in name_to_values: + output_val = name_to_values[output0] + output_target_type = QDQ_CONVERT_TYPES.get(output_val.type.tensor_type.elem_type) + if output_target_type: + output_val.type.tensor_type.elem_type = output_target_type + elif output0 in name_to_outputs: + output_val = name_to_outputs[output0] + output_target_type = QDQ_CONVERT_TYPES.get(output_val.type.tensor_type.elem_type) + if output_target_type: + output_val.type.tensor_type.elem_type = output_target_type + else: + raise Exception("Only support Q/DQ ops with explicit zero-point inputs") + + +def update_qdq_node_domains(graph: onnx.GraphProto, use_16bit_qdq: bool): + name_to_initializer = {initializer.name: initializer for initializer in graph.initializer} + name_to_values = {value.name: value for value in graph.value_info} + name_to_inputs = {g_input.name: g_input for g_input in graph.input} + name_to_outputs = {g_output.name: g_output for g_output in graph.output} + + for node in graph.node: + # Handle subgraphs: + for attr in node.attribute: + if attr.type == onnx.AttributeProto.GRAPH: + update_qdq_node_domains(attr.g, use_16bit_qdq) + elif attr.type == onnx.AttributeProto.GRAPHS: + for subgraph in attr.graphs: + update_qdq_node_domains(subgraph, use_16bit_qdq) + + # Update Q/DQ domains + if node.op_type in QDQ_OPS: + node.domain = "com.microsoft" + + if use_16bit_qdq: + convert_qdq_op_to_16bit(name_to_initializer, name_to_values, name_to_inputs, name_to_outputs, node) + + +def main(): + parser = argparse.ArgumentParser(description="Convert Q/DQ ops to com.microsoft domain (or 16-bit)") + parser.add_argument("--input_model", type=str, required=True, help="Input onnx model path") + parser.add_argument("--output_model", type=str, required=False, help="Output onnx model path") + parser.add_argument("--use_16bit_qdq", required=False, action="store_true", help="Convert to 16-bit QDQ") + + args = parser.parse_args() + + model = onnx.load(args.input_model) + + has_ms_domain = False + for opset in model.opset_import: + if opset.domain == "com.microsoft": + has_ms_domain = True + break + + if not has_ms_domain: + model.opset_import.extend([onnx.helper.make_opsetid("com.microsoft", 1)]) + + update_qdq_node_domains(model.graph, args.use_16bit_qdq) + model = shape_inference.infer_shapes(model) + onnx.checker.check_model(model, True) + + output_model_path = args.output_model + if not output_model_path: + base_model_name = os.path.splitext(args.input_model)[0] + suffix = ".qdq16_contrib" if args.use_16bit_qdq else ".qdq_contrib" + output_model_path = base_model_name + suffix + ".onnx" + + onnx.save_model(model, output_model_path) + print(f"[INFO] Saved model: {output_model_path}") + + +if __name__ == "__main__": + main() diff --git a/onnxruntime/test/testdata/transform/fusion/constant_folding_dequantizelinear.qdq16_contrib.onnx b/onnxruntime/test/testdata/transform/fusion/constant_folding_dequantizelinear.qdq16_contrib.onnx new file mode 100644 index 0000000000000..8fc884024b00f Binary files /dev/null and b/onnxruntime/test/testdata/transform/fusion/constant_folding_dequantizelinear.qdq16_contrib.onnx differ diff --git a/onnxruntime/test/testdata/transform/fusion/constant_folding_dequantizelinear.qdq_contrib.onnx b/onnxruntime/test/testdata/transform/fusion/constant_folding_dequantizelinear.qdq_contrib.onnx new file mode 100644 index 0000000000000..a111597ad0f41 Binary files /dev/null and b/onnxruntime/test/testdata/transform/fusion/constant_folding_dequantizelinear.qdq_contrib.onnx differ diff --git a/onnxruntime/test/testdata/transform/fusion/constant_folding_qdq_node_unit.graph_output.qdq16_contrib.onnx b/onnxruntime/test/testdata/transform/fusion/constant_folding_qdq_node_unit.graph_output.qdq16_contrib.onnx new file mode 100644 index 0000000000000..b9cae7f59f8e8 Binary files /dev/null and b/onnxruntime/test/testdata/transform/fusion/constant_folding_qdq_node_unit.graph_output.qdq16_contrib.onnx differ diff --git a/onnxruntime/test/testdata/transform/fusion/constant_folding_qdq_node_unit.graph_output.qdq_contrib.onnx b/onnxruntime/test/testdata/transform/fusion/constant_folding_qdq_node_unit.graph_output.qdq_contrib.onnx new file mode 100644 index 0000000000000..c30ffcc8d9f24 Binary files /dev/null and b/onnxruntime/test/testdata/transform/fusion/constant_folding_qdq_node_unit.graph_output.qdq_contrib.onnx differ diff --git a/onnxruntime/test/testdata/transform/fusion/constant_folding_qdq_node_unit.qdq16_contrib.onnx b/onnxruntime/test/testdata/transform/fusion/constant_folding_qdq_node_unit.qdq16_contrib.onnx new file mode 100644 index 0000000000000..8e12e10e90531 Binary files /dev/null and b/onnxruntime/test/testdata/transform/fusion/constant_folding_qdq_node_unit.qdq16_contrib.onnx differ diff --git a/onnxruntime/test/testdata/transform/fusion/constant_folding_qdq_node_unit.qdq_contrib.onnx b/onnxruntime/test/testdata/transform/fusion/constant_folding_qdq_node_unit.qdq_contrib.onnx new file mode 100644 index 0000000000000..3d58fe2a5f41b Binary files /dev/null and b/onnxruntime/test/testdata/transform/fusion/constant_folding_qdq_node_unit.qdq_contrib.onnx differ diff --git a/onnxruntime/test/testdata/transform/fusion/conv_add_fp16.onnx b/onnxruntime/test/testdata/transform/fusion/conv_add_fp16.onnx new file mode 100644 index 0000000000000..d639345c498b3 --- /dev/null +++ b/onnxruntime/test/testdata/transform/fusion/conv_add_fp16.onnx @@ -0,0 +1,109 @@ +: +; +Agraph_input_cast_3graph_input_cast3"Cast* +to + +; +Bgraph_input_cast_2graph_input_cast2"Cast* +to + +; +Wgraph_input_cast_1graph_input_cast1"Cast* +to + +; +Xgraph_input_cast_0graph_input_cast0"Cast* +to + +E +graph_input_cast_0 +graph_input_cast_1 +graph_input_cast_2C"Conv +1 +C +graph_input_cast_3graph_output_cast_0"Add += +graph_output_cast_0Ygraph_output_cast0"Cast* +tographZ +X + + + + +Z +W + + + + +Z +B + + +Z +A + + + + +b +Y + + + + +j +C + + + + + +j +Y + + + + +j, +graph_input_cast_0 + + + + + +j, +graph_input_cast_1 + + + + + +j +graph_input_cast_2 + + + +j, +graph_input_cast_3 + + + + + +j- +graph_output_cast_0 + + + + + +BB +com.microsoft.experimentalB +ai.onnx.preview.trainingB +com.microsoft.nchwcB +com.microsoft.mlfeaturizersB + +ai.onnx.mlB + com.microsoftB +ai.onnx.training \ No newline at end of file diff --git a/onnxruntime/test/testdata/transform/fusion/conv_relu_fp16.onnx b/onnxruntime/test/testdata/transform/fusion/conv_relu_fp16.onnx new file mode 100644 index 0000000000000..61d4b0b954a5d --- /dev/null +++ b/onnxruntime/test/testdata/transform/fusion/conv_relu_fp16.onnx @@ -0,0 +1,71 @@ +onnx_conv_relu: +; +Wgraph_input_cast_1graph_input_cast1"Cast* +to + +; +Xgraph_input_cast_0graph_input_cast0"Cast* +to + +H +graph_input_cast_0 +graph_input_cast_1Y"Conv* + kernel_shape@@ + +Ygraph_output_cast_0"Relu += +graph_output_cast_0Zgraph_output_cast0"Cast* +to +test-modelZ +X + + + + +Z +W + + + + +b +Z + + + + +j +Y + + + + + +j +Z + + + + +j, +graph_input_cast_0 + + + + + +j, +graph_input_cast_1 + + + + + +j- +graph_output_cast_0 + + + + + +B \ No newline at end of file diff --git a/onnxruntime/test/testdata/transform/fusion/layer_norm_fusion_scale_bias.onnx b/onnxruntime/test/testdata/transform/fusion/layer_norm_fusion_scale_bias.onnx new file mode 100644 index 0000000000000..ec0f9a97815b8 Binary files /dev/null and b/onnxruntime/test/testdata/transform/fusion/layer_norm_fusion_scale_bias.onnx differ diff --git a/onnxruntime/test/testdata/transform/fusion/layer_norm_fusion_scale_bias.py b/onnxruntime/test/testdata/transform/fusion/layer_norm_fusion_scale_bias.py new file mode 100644 index 0000000000000..a59e263763a3d --- /dev/null +++ b/onnxruntime/test/testdata/transform/fusion/layer_norm_fusion_scale_bias.py @@ -0,0 +1,81 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +import onnx +from onnx import OperatorSetIdProto, TensorProto, helper + + +def GenerateModel(model_name, has_casts=False, has_identity=False): # noqa: N802 + nodes = [ # LayerNorm subgraph + helper.make_node("ReduceMean", ["A"], ["rd_out"], "reduce1", axes=[-1], keepdims=1), + helper.make_node("Sub", ["A", "rd_out"], ["sub_out"], "sub"), + helper.make_node("Pow", ["cast_sub_out" if has_casts else "sub_out", "pow_in_2"], ["pow_out"], "pow"), + helper.make_node("ReduceMean", ["pow_out"], ["rd2_out"], "reduce2", axes=[-1], keepdims=1), + helper.make_node("Add", ["rd2_out", "const_e12_f32"], ["add1_out"], "add1"), + helper.make_node("Sqrt", ["add1_out"], ["sqrt_out"], "sqrt"), + helper.make_node("Div", ["cast_sub_out" if has_casts else "sub_out", "sqrt_out"], ["div_out"], "div"), + helper.make_node( + "Mul", + ["gamma_id_out" if has_identity else "gamma", "cast_div_out" if has_casts else "div_out"], + ["mul_out"], + "mul", + ), + helper.make_node("Add", ["mul_out", "const_e6_f16_out" if has_identity else "const_e6_f16"], ["C"], "add2"), + ] + + if has_casts: + nodes.extend( + [ + helper.make_node("Cast", ["sub_out"], ["cast_sub_out"], "cast_sub", to=1), + helper.make_node("Cast", ["div_out"], ["cast_div_out"], "cast_2", to=10), + ] + ) + + if has_identity: + nodes.extend( + [ + helper.make_node("Identity", ["gamma"], ["gamma_id_out"], "gamma_identity"), + helper.make_node("Identity", ["const_e6_f16"], ["const_e6_f16_out"], "const_e6_f16_identity"), + ] + ) + + initializers = [ # initializers + helper.make_tensor("pow_in_2", TensorProto.FLOAT, [], [2]), + helper.make_tensor("const_e12_f32", TensorProto.FLOAT, [], [1e-12]), + helper.make_tensor("const_e6_f16", TensorProto.FLOAT16, [4], [1e-6, 1e-6, 1e-6, 1e-6]), + helper.make_tensor( + "gamma", + TensorProto.FLOAT16 if has_casts else TensorProto.FLOAT, + [4], + [1, 2, 3, 4], + ), + ] + + input_type = TensorProto.FLOAT16 if has_casts else TensorProto.FLOAT + output_type = TensorProto.FLOAT16 if has_casts else TensorProto.FLOAT + + graph = helper.make_graph( + nodes, + "LayerNorm", # name + [ # inputs + helper.make_tensor_value_info("A", input_type, [16, 32, 4]), + ], + [ # outputs + helper.make_tensor_value_info("C", output_type, [16, 32, 4]), + ], + initializers, + ) + + onnxdomain = OperatorSetIdProto() + onnxdomain.version = 12 + # The empty string ("") or absence of this field implies the operator set that is defined as part of the ONNX specification. + onnxdomain.domain = "" + msdomain = OperatorSetIdProto() + msdomain.version = 1 + msdomain.domain = "com.microsoft" + opsets = [onnxdomain, msdomain] + + model = helper.make_model(graph, opset_imports=opsets) + onnx.save(model, model_name) + + +GenerateModel("layer_norm_fusion_scale_bias.onnx", True, True) diff --git a/onnxruntime/test/testdata/transform/fusion/layer_norm_shared_input.onnx b/onnxruntime/test/testdata/transform/fusion/layer_norm_shared_input.onnx new file mode 100644 index 0000000000000..ae13881d687cb Binary files /dev/null and b/onnxruntime/test/testdata/transform/fusion/layer_norm_shared_input.onnx differ diff --git a/onnxruntime/test/testdata/transform/fusion/layer_norm_shared_input.py b/onnxruntime/test/testdata/transform/fusion/layer_norm_shared_input.py new file mode 100644 index 0000000000000..0b838ca88e6bc --- /dev/null +++ b/onnxruntime/test/testdata/transform/fusion/layer_norm_shared_input.py @@ -0,0 +1,71 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +import onnx +from onnx import OperatorSetIdProto, TensorProto, helper + + +# in gpt_j_residual, there will be 2 LN share the same input +def GenerateModel(model_name): # noqa: N802 + nodes = [ + # LN1 subgraph + helper.make_node("ReduceMean", ["A"], ["LN1/rd1_out"], "LN1/reduce", axes=[-1]), + helper.make_node("Sub", ["A", "LN1/rd1_out"], ["LN1/sub1_out"], "LN1/sub"), + helper.make_node("Pow", ["LN1/sub1_out", "LN1/pow_in_2"], ["LN1/pow_out"], "LN1/pow"), + helper.make_node("ReduceMean", ["LN1/pow_out"], ["LN1/rd2_out"], "LN1/reduce2", axes=[-1]), + helper.make_node("Add", ["LN1/rd2_out", "LN1/const_0"], ["LN1/add1_out"], "LN1/add"), + helper.make_node("Sqrt", ["LN1/add1_out"], ["LN1/sqrt_out"], "LN1/sqrt"), + helper.make_node("Div", ["LN1/sub1_out", "LN1/sqrt_out"], ["LN1/div_out"], "LN1/div"), + helper.make_node("Mul", ["LN1/gamma", "LN1/div_out"], ["LN1/mul_out"], "LN1/mul"), + helper.make_node("Add", ["LN1/beta", "LN1/mul_out"], ["LN1/C"], "LN1/add2"), + # LN2 subgraph + helper.make_node("ReduceMean", ["A"], ["LN2/rd1_out"], "LN2/reduce", axes=[-1]), + helper.make_node("Sub", ["A", "LN2/rd1_out"], ["LN2/sub1_out"], "LN2/sub"), + helper.make_node("Pow", ["LN2/sub1_out", "LN2/pow_in_2"], ["LN2/pow_out"], "LN2/pow"), + helper.make_node("ReduceMean", ["LN2/pow_out"], ["LN2/rd2_out"], "LN2/reduce2", axes=[-1]), + helper.make_node("Add", ["LN2/rd2_out", "LN2/const_0"], ["LN2/add1_out"], "LN2/add"), + helper.make_node("Sqrt", ["LN2/add1_out"], ["LN2/sqrt_out"], "LN2/sqrt"), + helper.make_node("Div", ["LN2/sub1_out", "LN2/sqrt_out"], ["LN2/div_out"], "LN2/div"), + helper.make_node("Mul", ["LN2/gamma", "LN2/div_out"], ["LN2/mul_out"], "LN2/mul"), + helper.make_node("Add", ["LN2/beta", "LN2/mul_out"], ["LN2/C"], "LN2/add2"), + ] + + initializers = [ + # LN1 initializers + helper.make_tensor("LN1/pow_in_2", TensorProto.FLOAT, [], [2]), + helper.make_tensor("LN1/const_0", TensorProto.FLOAT, [], [0]), + helper.make_tensor("LN1/gamma", TensorProto.FLOAT, [4], [1, 2, 3, 4]), + helper.make_tensor("LN1/beta", TensorProto.FLOAT, [4], [1, 2, 3, 4]), + # LN2 initializers + helper.make_tensor("LN2/pow_in_2", TensorProto.FLOAT, [], [2]), + helper.make_tensor("LN2/const_0", TensorProto.FLOAT, [], [0]), + helper.make_tensor("LN2/gamma", TensorProto.FLOAT, [4], [1, 2, 3, 4]), + helper.make_tensor("LN2/beta", TensorProto.FLOAT, [4], [1, 2, 3, 4]), + ] + + graph = helper.make_graph( + nodes, + "2LayerNormShareSameInput", # name + [ # inputs + helper.make_tensor_value_info("A", TensorProto.FLOAT, [16, 32, 4]), + ], + [ # outputs + helper.make_tensor_value_info("LN1/C", TensorProto.FLOAT, [16, 32, 4]), + helper.make_tensor_value_info("LN2/C", TensorProto.FLOAT, [16, 32, 4]), + ], + initializers, + ) + + onnxdomain = OperatorSetIdProto() + onnxdomain.version = 12 + # The empty string ("") or absence of this field implies the operator set that is defined as part of the ONNX specification. + onnxdomain.domain = "" + msdomain = OperatorSetIdProto() + msdomain.version = 1 + msdomain.domain = "com.microsoft" + opsets = [onnxdomain, msdomain] + + model = helper.make_model(graph, opset_imports=opsets) + onnx.save(model, model_name) + + +GenerateModel("layer_norm_shared_input.onnx") diff --git a/onnxruntime/test/testdata/transform/pre_shape_node_elimination.onnx b/onnxruntime/test/testdata/transform/pre_shape_node_elimination.onnx new file mode 100644 index 0000000000000..f609450ca4ac3 Binary files /dev/null and b/onnxruntime/test/testdata/transform/pre_shape_node_elimination.onnx differ diff --git a/onnxruntime/test/testdata/transform/pre_shape_node_elimination.py b/onnxruntime/test/testdata/transform/pre_shape_node_elimination.py new file mode 100644 index 0000000000000..a6fdc09f95c1a --- /dev/null +++ b/onnxruntime/test/testdata/transform/pre_shape_node_elimination.py @@ -0,0 +1,40 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# -------------------------------------------------------------------------- + +import onnx +from onnx import OperatorSetIdProto, TensorProto, helper + +input_shape = [2, 2] + +input = helper.make_tensor_value_info("input", TensorProto.FLOAT, input_shape) +output = helper.make_tensor_value_info("output", TensorProto.FLOAT, input_shape) + +cast1 = helper.make_node("Cast", ["input"], ["cast1"], name="cast1", to=2) +shape1 = helper.make_node("Shape", ["cast1"], ["shape1"], name="shape1") +add = helper.make_node("Add", ["cast1", "cast1"], ["add"], name="add") +cast2 = helper.make_node("Cast", ["add"], ["cast2"], name="cast2", to=1) +shape2 = helper.make_node("Shape", ["cast2"], ["shape2"], name="shape2") +shape3 = helper.make_node("Shape", ["cast2"], ["shape3"], name="shape3") +add_shapes = helper.make_node("Add", ["shape2", "shape3"], ["add_shapes"], name="add_shapes") +cast3 = helper.make_node("Cast", ["add_shapes"], ["output"], name="cast3", to=1) + +graph_def = helper.make_graph( + [cast1, shape1, add, cast2, shape2, shape3, add_shapes, cast3], + "pre_shape_node_elimination.onnx", + [input], + [output], +) + +opsets = [] +onnxdomain = OperatorSetIdProto() +onnxdomain.version = 15 +onnxdomain.domain = "" +opsets.append(onnxdomain) + +kwargs = {} +kwargs["opset_imports"] = opsets + +model_def = helper.make_model(graph_def, producer_name="onnx-example", **kwargs) +onnx.save(model_def, "pre_shape_node_elimination.onnx") diff --git a/onnxruntime/test/testdata/transform/qdq_optimization/dup_qdq.onnx b/onnxruntime/test/testdata/transform/qdq_optimization/dup_qdq.onnx new file mode 100644 index 0000000000000..37e5996a2f15a Binary files /dev/null and b/onnxruntime/test/testdata/transform/qdq_optimization/dup_qdq.onnx differ diff --git a/onnxruntime/test/testdata/transform/qdq_with_multi_consumer_dq_nodes.fixed.qdq16_contrib.onnx b/onnxruntime/test/testdata/transform/qdq_with_multi_consumer_dq_nodes.fixed.qdq16_contrib.onnx new file mode 100644 index 0000000000000..f71114cf31bf9 Binary files /dev/null and b/onnxruntime/test/testdata/transform/qdq_with_multi_consumer_dq_nodes.fixed.qdq16_contrib.onnx differ diff --git a/onnxruntime/test/testdata/transform/qdq_with_multi_consumer_dq_nodes.fixed.qdq_contrib.onnx b/onnxruntime/test/testdata/transform/qdq_with_multi_consumer_dq_nodes.fixed.qdq_contrib.onnx new file mode 100644 index 0000000000000..1a1081544a56e Binary files /dev/null and b/onnxruntime/test/testdata/transform/qdq_with_multi_consumer_dq_nodes.fixed.qdq_contrib.onnx differ diff --git a/onnxruntime/test/unittest_main/test_main.cc b/onnxruntime/test/unittest_main/test_main.cc index b44ffc4f9947f..97169df36fdd7 100644 --- a/onnxruntime/test/unittest_main/test_main.cc +++ b/onnxruntime/test/unittest_main/test_main.cc @@ -1,12 +1,16 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#include +#include +#include +#include + #ifndef USE_ONNXRUNTIME_DLL #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wignored-qualifiers" #pragma GCC diagnostic ignored "-Wunused-parameter" -#else #endif #include #ifdef __GNUC__ @@ -14,9 +18,11 @@ #endif #endif +#include "gtest/gtest.h" + +#include "core/platform/env_var_utils.h" #include "core/session/onnxruntime_cxx_api.h" #include "core/util/thread_utils.h" -#include "gtest/gtest.h" #include "test/test_environment.h" std::unique_ptr ort_env; @@ -54,8 +60,19 @@ int TEST_MAIN(int argc, char** argv) { ORT_TRY { ::testing::InitGoogleTest(&argc, argv); - ortenv_setup(); + + // allow verbose logging to be enabled by setting this environment variable to a numeric log level + constexpr auto kLogLevelEnvironmentVariableName = "ORT_UNIT_TEST_MAIN_LOG_LEVEL"; + if (auto log_level = onnxruntime::ParseEnvironmentVariable(kLogLevelEnvironmentVariableName); + log_level.has_value()) { + *log_level = std::clamp(*log_level, + static_cast(ORT_LOGGING_LEVEL_VERBOSE), + static_cast(ORT_LOGGING_LEVEL_FATAL)); + std::cout << "Setting log level to " << *log_level << "\n"; + ort_env->UpdateEnvWithCustomLogLevel(static_cast(*log_level)); + } + status = RUN_ALL_TESTS(); } ORT_CATCH(const std::exception& ex) { diff --git a/onnxruntime/test/util/compare_ortvalue.cc b/onnxruntime/test/util/compare_ortvalue.cc index 78bbd46f5a21f..3d53d4a3a0193 100644 --- a/onnxruntime/test/util/compare_ortvalue.cc +++ b/onnxruntime/test/util/compare_ortvalue.cc @@ -2,8 +2,11 @@ // Licensed under the MIT License. #include "test/compare_ortvalue.h" + #include #include +#include +#include #ifdef __GNUC__ #pragma GCC diagnostic push @@ -25,11 +28,12 @@ #pragma GCC diagnostic pop #endif -#include "core/graph/onnx_protobuf.h" #include "core/framework/tensorprotoutils.h" #include "core/framework/utils.h" #include "core/framework/TensorSeq.h" +#include "core/graph/onnx_protobuf.h" #include +#include "core/util/math.h" using namespace onnxruntime; @@ -61,13 +65,34 @@ const char* ElementTypeToString(MLDataType type) { return DataTypeImpl::ToString(type); } +/** + * @brief Check if two values are closely matched with given tolerance. + + * Definition of closely match: + * > If any of actual_value and expected_value is nan, actual_value and expected_value must both be nan. + * > If any of actual_value and expected_value is inf, then actual_value and expected_value + * must both be inf with same sign. + * > Otherwise, diff <= tol. + + * @param actual_value The value to be checked. + * @param expected_value The baseline value used to check against. + * @param diff The absolute difference calculated by the caller from actual_value and expected_value. + * @param tol The absolute tolerance. + * @return True when closely matched; False otherwise. + */ template -bool IsResultCloselyMatch(const T& outvalue, const T& expected_value, const double diff, const double tol) { - if (diff > tol) return false; - if (std::isnan(diff) && !(std::isnan(outvalue) && std::isnan(expected_value)) && - !(std::isinf(outvalue) && std::isinf(expected_value))) - return false; - return true; +bool IsResultCloselyMatch(const T& actual_value, const T& expected_value, const double diff, const double tol) { + if (std::isnan(actual_value) || std::isnan(expected_value)) + return std::isnan(actual_value) && std::isnan(expected_value); // not possible both are not nan if diff is nan. + + if (std::isinf(actual_value) || std::isinf(expected_value)) { + if (std::isinf(actual_value) && std::isinf(expected_value)) + return (actual_value > 0 && expected_value > 0) || (actual_value < 0 && expected_value < 0); + else + return false; + } + + return (diff <= tol); } template @@ -456,6 +481,93 @@ static std::pair CompareTensorOrtValueAndTensorType return std::make_pair(COMPARE_RESULT::SUCCESS, ""); } +namespace { +template +float ParseValueToFloat(T data_value) { + return static_cast(data_value); +} + +template <> +float ParseValueToFloat(MLFloat16 data_value) { + return Eigen::half_impl::half_to_float(Eigen::half_impl::__half_raw(data_value.val)); +} + +template <> +float ParseValueToFloat(float data_value) { + // Covert float to half and then convert back to float to simulate rounding to half + return ParseValueToFloat(MLFloat16(data_value)); +} + +template +std::pair CompareFloat16WithFloatResult(const Tensor& outvalue, + const Tensor& expected_value, + double per_sample_tolerance, + double relative_per_sample_tolerance) { + const size_t size1 = static_cast(expected_value.Shape().Size()); + const ExpectT* expected_output = expected_value.Data(); + const RealT* real_output = outvalue.Data(); + + COMPARE_RESULT result = COMPARE_RESULT::SUCCESS; + std::string error_msg = ""; + + OrtThreadPoolParams to; + to.thread_pool_size = 16; + auto tp = concurrency::CreateThreadPool(&onnxruntime::Env::Default(), to, concurrency::ThreadPoolType::INTRA_OP); + + static double cost = 1; + std::once_flag write_flag; + concurrency::ThreadPool::TryParallelFor( + tp.get(), size1, cost, + [&error_msg, &result, &expected_output, &real_output, per_sample_tolerance, + relative_per_sample_tolerance, size1, &write_flag]( + std::ptrdiff_t begin, std::ptrdiff_t end) { + for (std::ptrdiff_t di = begin; di != end && di < static_cast(size1); ++di) { + float expected = ParseValueToFloat(expected_output[di]); + float real = ParseValueToFloat(real_output[di]); + const double diff = std::fabs(expected - real); + const double rtol = per_sample_tolerance + relative_per_sample_tolerance * std::fabs(expected); + if (!IsResultCloselyMatch(real, expected, diff, rtol)) { + std::ostringstream oss; + oss << "idx: " << di << ", expected " << expected << ", got " << real + << ", diff: " << diff << ", tol=" << rtol << "\n"; + std::call_once(write_flag, [&error_msg, &result, &oss]() { + error_msg = oss.str(); + result = COMPARE_RESULT::RESULT_DIFFERS; + }); + break; + } + } + }); + + return std::make_pair(result, error_msg); +} + +} // namespace + +std::pair CompareOrtValueNumerals(const OrtValue& real_mlvalue, const OrtValue& expected_mlvalue, + double per_sample_tolerance, + double relative_per_sample_tolerance) { + if (real_mlvalue.IsTensor()) { + const Tensor& outvalue = real_mlvalue.Get(); + const Tensor& expected_tensor = expected_mlvalue.Get(); + if (outvalue.DataType() == DataTypeImpl::GetType() && + expected_tensor.DataType() == DataTypeImpl::GetType()) { + return CompareFloat16WithFloatResult(outvalue, + expected_tensor, + per_sample_tolerance, + relative_per_sample_tolerance); + } else if (outvalue.DataType() == DataTypeImpl::GetType() && + expected_tensor.DataType() == DataTypeImpl::GetType()) { + return CompareFloat16WithFloatResult(outvalue, + expected_tensor, + per_sample_tolerance, + relative_per_sample_tolerance); + } + } + + return std::make_pair(COMPARE_RESULT::NOT_SUPPORT, "Unsupported compare with CompareOrtValueNumerals."); +} + std::pair VerifyValueInfo(const ONNX_NAMESPACE::ValueInfoProto& v, const OrtValue* val_ptr) { Ort::ConstValue o{val_ptr}; if (!v.has_type()) return std::make_pair(COMPARE_RESULT::SUCCESS, ""); diff --git a/onnxruntime/test/util/default_providers.cc b/onnxruntime/test/util/default_providers.cc index 5cb80f9edbd5e..28af61e15b2b5 100644 --- a/onnxruntime/test/util/default_providers.cc +++ b/onnxruntime/test/util/default_providers.cc @@ -14,12 +14,7 @@ namespace onnxruntime { namespace test { std::unique_ptr DefaultCpuExecutionProvider(bool enable_arena) { - auto ret = CPUProviderFactoryCreator::Create(enable_arena)->CreateProvider(); - // The factory created CPU provider doesn't create/reg allocators; something that is expected by - // clients of DefaultCpuExecutionProvider; hence the need to call RegisterAllocator explicitly. - AllocatorManager mgr; // needed only to call RegisterAllocator - ret->RegisterAllocator(mgr); - return ret; + return CPUProviderFactoryCreator::Create(enable_arena)->CreateProvider(); } std::unique_ptr DefaultTensorrtExecutionProvider() { @@ -91,10 +86,19 @@ std::unique_ptr MIGraphXExecutionProviderWithOptions(const O return nullptr; } +std::unique_ptr OpenVINOExecutionProviderWithOptions(const OrtOpenVINOProviderOptions* params) { +#ifdef USE_OPENVINO + return OpenVINOProviderFactoryCreator::Create(params)->CreateProvider(); +#else + ORT_UNUSED_PARAMETER(params); + return nullptr; +#endif +} + std::unique_ptr DefaultOpenVINOExecutionProvider() { #ifdef USE_OPENVINO - OrtOpenVINOProviderOptions params; - return OpenVINOProviderFactoryCreator::Create(¶ms)->CreateProvider(); + ProviderOptions provider_options_map; + return OpenVINOProviderFactoryCreator::Create(&provider_options_map)->CreateProvider(); #else return nullptr; #endif @@ -110,6 +114,16 @@ std::unique_ptr DefaultCudaExecutionProvider() { return nullptr; } +std::unique_ptr CudaExecutionProviderWithOptions(const OrtCUDAProviderOptionsV2* provider_options) { +#ifdef USE_CUDA + if (auto factory = CudaProviderFactoryCreator::Create(provider_options)) + return factory->CreateProvider(); +#else + ORT_UNUSED_PARAMETER(provider_options); +#endif + return nullptr; +} + std::unique_ptr DefaultDnnlExecutionProvider() { #ifdef USE_DNNL OrtDnnlProviderOptions dnnl_options; @@ -181,6 +195,7 @@ std::unique_ptr DefaultRocmExecutionProvider(bool test_tunab provider_options.do_copy_in_default_stream = true; provider_options.tunable_op_enable = test_tunable_op ? 1 : 0; provider_options.tunable_op_tuning_enable = test_tunable_op ? 1 : 0; + provider_options.tunable_op_max_tuning_duration_ms = 0; if (auto factory = RocmProviderFactoryCreator::Create(&provider_options)) return factory->CreateProvider(); #endif @@ -219,7 +234,7 @@ std::unique_ptr DefaultQnnExecutionProvider() { backend_path = "./QnnCpu.dll"; #endif provider_options_map["backend_path"] = backend_path; - return QNNProviderFactoryCreator::Create(provider_options_map)->CreateProvider(); + return QNNProviderFactoryCreator::Create(provider_options_map, nullptr)->CreateProvider(); #else return nullptr; #endif @@ -227,7 +242,7 @@ std::unique_ptr DefaultQnnExecutionProvider() { std::unique_ptr QnnExecutionProviderWithOptions(const ProviderOptions& options) { #ifdef USE_QNN - return QNNProviderFactoryCreator::Create(options)->CreateProvider(); + return QNNProviderFactoryCreator::Create(options, nullptr)->CreateProvider(); #else ORT_UNUSED_PARAMETER(options); return nullptr; diff --git a/onnxruntime/test/util/include/capturing_sink.h b/onnxruntime/test/util/include/capturing_sink.h new file mode 100644 index 0000000000000..39788947602df --- /dev/null +++ b/onnxruntime/test/util/include/capturing_sink.h @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/common/logging/logging.h" +#include "core/common/logging/isink.h" + +#include "date/date.h" + +namespace onnxruntime { +namespace test { + +using namespace ::onnxruntime::logging; + +class CapturingSink : public logging::ISink { + public: + void SendImpl(const Timestamp& timestamp, const std::string& logger_id, const Capture& message) override { + // operator for formatting of timestamp in ISO8601 format including microseconds + using date::operator<<; + std::ostringstream msg; + + msg << timestamp << " [" << message.SeverityPrefix() << ":" << message.Category() << ":" << logger_id << ", " + << message.Location().ToString() << "] " << message.Message(); + + messages_.push_back(msg.str()); + } + + const std::vector& Messages() const { + return messages_; + } + + private: + std::vector messages_; +}; +} // namespace test +} // namespace onnxruntime diff --git a/onnxruntime/test/util/include/compare_ortvalue.h b/onnxruntime/test/util/include/compare_ortvalue.h new file mode 100644 index 0000000000000..24b74b90026e6 --- /dev/null +++ b/onnxruntime/test/util/include/compare_ortvalue.h @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once +// TODO(): move compare_mlvalue.{h,cc} to test dir + +#include +#include + +namespace ONNX_NAMESPACE { +class ValueInfoProto; +} + +namespace Ort { +struct Value; +} + +namespace onnxruntime { +enum class COMPARE_RESULT { SUCCESS, + RESULT_DIFFERS, + TYPE_MISMATCH, + SHAPE_MISMATCH, + NOT_SUPPORT }; +std::pair CompareOrtValue(const OrtValue& real, const OrtValue& expected, + double per_sample_tolerance, + double relative_per_sample_tolerance, bool post_processing); + +// verify if the 'value' matches the 'expected' ValueInfoProto. 'value' is a model output +std::pair VerifyValueInfo(const ONNX_NAMESPACE::ValueInfoProto& expected, + const OrtValue* value); +} // namespace onnxruntime diff --git a/onnxruntime/test/util/include/current_test_name.h b/onnxruntime/test/util/include/current_test_name.h new file mode 100644 index 0000000000000..faecd3ecfc036 --- /dev/null +++ b/onnxruntime/test/util/include/current_test_name.h @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include + +#include "gtest/gtest.h" + +namespace onnxruntime::test { + +// Returns the current test's name (".") if a test is running, or "unknown". +inline std::string CurrentTestName() { + const auto* const test_info = testing::UnitTest::GetInstance()->current_test_info(); + if (test_info == nullptr) { + return "unknown"; + } + return std::string{test_info->test_suite_name()} + "." + test_info->name(); +} + +} // namespace onnxruntime::test diff --git a/onnxruntime/test/util/include/default_providers.h b/onnxruntime/test/util/include/default_providers.h index e6ddf642b4b23..1325f7aa43dbb 100644 --- a/onnxruntime/test/util/include/default_providers.h +++ b/onnxruntime/test/util/include/default_providers.h @@ -18,9 +18,6 @@ std::shared_ptr CreateExecutionProviderFactory_MIGrap std::shared_ptr CreateExecutionProviderFactory_Nnapi( uint32_t flags, const optional& partitioning_stop_ops_list); // std::shared_ptr CreateExecutionProviderFactory_Tvm(const char*); -std::shared_ptr CreateExecutionProviderFactory_OpenVINO( - const char* device_type, bool enable_vpu_fast_compile, const char* device_id, size_t num_of_threads, const char* cache_dir); -std::shared_ptr CreateExecutionProviderFactory_OpenVINO(const OrtOpenVINOProviderOptions* params); std::shared_ptr CreateExecutionProviderFactory_Rknpu(); std::shared_ptr CreateExecutionProviderFactory_Rocm(const OrtROCMProviderOptions* provider_options); std::shared_ptr CreateExecutionProviderFactory_Tensorrt(const OrtTensorRTProviderOptions* params); @@ -36,6 +33,7 @@ namespace test { // unique_ptr providers with default values for session registration std::unique_ptr DefaultCpuExecutionProvider(bool enable_arena = true); std::unique_ptr DefaultCudaExecutionProvider(); +std::unique_ptr CudaExecutionProviderWithOptions(const OrtCUDAProviderOptionsV2* provider_options); std::unique_ptr DefaultDnnlExecutionProvider(); std::unique_ptr DnnlExecutionProviderWithOptions(const OrtDnnlProviderOptions* provider_options); // std::unique_ptr DefaultTvmExecutionProvider(); @@ -44,6 +42,7 @@ std::unique_ptr TensorrtExecutionProviderWithOptions(const O std::unique_ptr TensorrtExecutionProviderWithOptions(const OrtTensorRTProviderOptionsV2* params); std::unique_ptr DefaultMIGraphXExecutionProvider(); std::unique_ptr MIGraphXExecutionProviderWithOptions(const OrtMIGraphXProviderOptions* params); +std::unique_ptr OpenVINOExecutionProviderWithOptions(const OrtOpenVINOProviderOptions* params); std::unique_ptr DefaultOpenVINOExecutionProvider(); std::unique_ptr DefaultNnapiExecutionProvider(); std::unique_ptr DefaultRknpuExecutionProvider(); diff --git a/onnxruntime/test/util/include/temp_dir.h b/onnxruntime/test/util/include/temp_dir.h index 580ff5ef1aefc..e47ba2815f0ee 100644 --- a/onnxruntime/test/util/include/temp_dir.h +++ b/onnxruntime/test/util/include/temp_dir.h @@ -20,8 +20,10 @@ class TemporaryDirectory { * Currently, the provided path is used directly as the temporary directory. * * @param path The temporary directory path. + * @param delete_if_exists If true and the temporary directory exists, delete and re-create it. + * If false, fail if the directory exists. */ - explicit TemporaryDirectory(const PathString& path); + explicit TemporaryDirectory(const PathString& path, bool delete_if_exists = true); /** * Destructor. Deletes the temporary directory. diff --git a/onnxruntime/test/util/include/tensors_from_file.h b/onnxruntime/test/util/include/tensors_from_file.h new file mode 100644 index 0000000000000..0e3da9d26b91a --- /dev/null +++ b/onnxruntime/test/util/include/tensors_from_file.h @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include +#include +#include + +namespace onnxruntime { +namespace test { + +// Read a dictionary of name to float tensors mapping from a text file. +void LoadTensorsFromFile(const std::string& path, std::unordered_map>& tensors); + +} // namespace test +} // namespace onnxruntime diff --git a/onnxruntime/test/util/include/test/compare_ortvalue.h b/onnxruntime/test/util/include/test/compare_ortvalue.h index 24b74b90026e6..545df706c9576 100644 --- a/onnxruntime/test/util/include/test/compare_ortvalue.h +++ b/onnxruntime/test/util/include/test/compare_ortvalue.h @@ -16,15 +16,33 @@ struct Value; } namespace onnxruntime { -enum class COMPARE_RESULT { SUCCESS, - RESULT_DIFFERS, - TYPE_MISMATCH, - SHAPE_MISMATCH, - NOT_SUPPORT }; + +enum class COMPARE_RESULT { + SUCCESS, + RESULT_DIFFERS, + TYPE_MISMATCH, + SHAPE_MISMATCH, + NOT_SUPPORT, +}; + std::pair CompareOrtValue(const OrtValue& real, const OrtValue& expected, double per_sample_tolerance, double relative_per_sample_tolerance, bool post_processing); +// Compare two OrtValue numerically equal or not. The difference with CompareOrtValue is that this function +// will only check the numerical values of the OrtValue, and ignore the type, shape, etc. +// +// For example, if some tests run CPU EP baseline with float, and run CUDA test with float16, we could check +// them without converting the float16 to float. Be noted: we will try convert the float value to float16 +// then back to float, to simulate rounding to half. +// +// If not equal, only return one single the differed value pair (to avoid multiple thread +// append into the same error_message string stream). +std::pair CompareOrtValueNumerals(const OrtValue& real, + const OrtValue& expected, + double per_sample_tolerance, + double relative_per_sample_tolerance); + // verify if the 'value' matches the 'expected' ValueInfoProto. 'value' is a model output std::pair VerifyValueInfo(const ONNX_NAMESPACE::ValueInfoProto& expected, const OrtValue* value); diff --git a/onnxruntime/test/util/include/test_environment.h b/onnxruntime/test/util/include/test_environment.h new file mode 100644 index 0000000000000..549804595b93d --- /dev/null +++ b/onnxruntime/test/util/include/test_environment.h @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/common/logging/logging.h" + +#ifdef HAVE_FRAMEWORK_LIB +#include "core/session/environment.h" +#endif + +namespace onnxruntime { +class Environment; + +namespace test { + +const onnxruntime::Environment& GetEnvironment(); + +/** +Static logging manager with a CLog based sink so logging macros that use the default logger will work +*/ +::onnxruntime::logging::LoggingManager& DefaultLoggingManager(); + +} // namespace test +} // namespace onnxruntime diff --git a/onnxruntime/test/util/include/test_utils.h b/onnxruntime/test/util/include/test_utils.h index 2fd51701a92c4..eb072a134b924 100644 --- a/onnxruntime/test/util/include/test_utils.h +++ b/onnxruntime/test/util/include/test_utils.h @@ -3,15 +3,21 @@ #pragma once -#include "core/framework/framework_common.h" -#include "core/framework/execution_provider.h" -#include "core/framework/ort_value.h" -#include "core/providers/cpu/cpu_execution_provider.h" - +#include +#include #include +#include #include +#include #include +#include "core/common/gsl.h" +#include "core/framework/execution_provider.h" +#include "core/framework/framework_common.h" +#include "core/framework/ort_value.h" +#include "core/providers/cpu/cpu_execution_provider.h" +#include "core/session/onnxruntime_c_api.h" + namespace onnxruntime { class Graph; @@ -38,23 +44,48 @@ struct EPVerificationParams { const std::function* graph_verifier{nullptr}; }; +// Verify equality of two output tensors. +void VerifyOutput(const std::string& output_name, + const Tensor& expected_tensor, + const Tensor& tensor, + float fp32_abs_err); + // Return number of nodes in the Graph and any subgraphs that are assigned to the specified execution provider int CountAssignedNodes(const Graph& current_graph, const std::string& ep_type); +// Verify the assignment of nodes to the EP specified by `provider_type`. +void VerifyEPNodeAssignment(const Graph& graph, const std::string& provider_type, + ExpectedEPNodeAssignment assignment); + +using ModelPathOrBytes = std::variant, + gsl::span>; + // Run the model using the CPU EP to get expected output, comparing to the output when the 'execution_provider' -// is enabled. requires that at least one node is assigned to 'execution_provider' -void RunAndVerifyOutputsWithEP(const ORTCHAR_T* model_path, - const char* log_id, +// is enabled. +void RunAndVerifyOutputsWithEP(ModelPathOrBytes model_path_or_bytes, + std::string_view log_id, std::unique_ptr execution_provider, const NameMLValMap& feeds, const EPVerificationParams& params = EPVerificationParams()); -// A helper function that takes in model_data -void RunAndVerifyOutputsWithEP(const std::string& model_data, - const char* log_id, - std::unique_ptr execution_provider, - const NameMLValMap& feeds, - const EPVerificationParams& params = EPVerificationParams()); +// Tests model loading only. +// This can be used to test EPs in builds where only loading (and not running) of a model is supported. +// Calls `check_graph` on the graph of the loaded model. +void TestModelLoad(ModelPathOrBytes model_path_or_bytes, + std::unique_ptr execution_provider, + const std::function& check_graph); + +// Tests model loading only. +// The check graph function verifies the expected EP node assignment. +inline void TestModelLoad(ModelPathOrBytes model_path_or_bytes, + std::unique_ptr execution_provider, + ExpectedEPNodeAssignment expected_node_assignment) { + auto check_node_assignment = + [provider_type = execution_provider->Type(), expected_node_assignment](const Graph& graph) { + VerifyEPNodeAssignment(graph, provider_type, expected_node_assignment); + }; + TestModelLoad(model_path_or_bytes, std::move(execution_provider), check_node_assignment); +} // Check equality of two shapes. Can successfully complete only if rank are equal and all dimensions are equal. // The way we define dimension equality is that: @@ -66,11 +97,11 @@ void CheckShapeEquality(const ONNX_NAMESPACE::TensorShapeProto* shape1, // Create OrtValue on CPU copying from provided inputs. template -void CreateInputOrtValueOnCPU(gsl::span dims, const std::vector& value, - OrtValue* p_ortvalue, AllocatorPtr alloc = nullptr) { +OrtValue CreateInputOrtValueOnCPU(gsl::span dims, gsl::span value, + AllocatorPtr alloc = nullptr) { static CPUExecutionProviderInfo info; static CPUExecutionProvider cpu_provider(info); - static AllocatorPtr cpu_allocator = cpu_provider.GetAllocator(OrtMemTypeDefault); + static AllocatorPtr cpu_allocator = cpu_provider.CreatePreferredAllocators()[0]; TensorShape shape(dims); assert(shape.Size() == static_cast(value.size())); @@ -82,9 +113,11 @@ void CreateInputOrtValueOnCPU(gsl::span dims, const std::vectorMutableDataRaw(), value.data(), p_tensor->SizeInBytes()); } - p_ortvalue->Init(p_tensor.release(), - DataTypeImpl::GetType(), - DataTypeImpl::GetType()->GetDeleteFunc()); + OrtValue ort_value; + ort_value.Init(p_tensor.release(), + DataTypeImpl::GetType(), + DataTypeImpl::GetType()->GetDeleteFunc()); + return ort_value; } } // namespace test diff --git a/onnxruntime/test/util/temp_dir.cc b/onnxruntime/test/util/temp_dir.cc index 487c919c515d9..cbd0bdc7febd6 100644 --- a/onnxruntime/test/util/temp_dir.cc +++ b/onnxruntime/test/util/temp_dir.cc @@ -9,21 +9,36 @@ namespace onnxruntime { namespace test { +namespace { +void CreateOrDeleteDirectory(const PathString& path, bool create, bool throw_on_fail = true) { + const auto status = create ? Env::Default().CreateFolder(path) : Env::Default().DeleteFolder(path); + EXPECT_TRUE(status.IsOK()) << "Failed to " << (create ? "create" : "delete") << "temporary directory " << path; -TemporaryDirectory::TemporaryDirectory(const PathString& path) + if (throw_on_fail) { + ORT_ENFORCE(status.IsOK()); + } +} +} // namespace + +TemporaryDirectory::TemporaryDirectory(const PathString& path, bool delete_if_exists) : path_{path} { // EXPECT and throw to fail even if anyone is catching exceptions const bool exists = Env::Default().FolderExists(path_); - EXPECT_TRUE(!exists) << "Temporary directory " << path_ << " already exists."; - ORT_ENFORCE(!exists); - const auto status = Env::Default().CreateFolder(path_); - EXPECT_TRUE(status.IsOK()) << "Failed to create temporary directory " << path_ << ": " << status.ErrorMessage(); - ORT_ENFORCE(status.IsOK()); + if (exists) { + if (!delete_if_exists) { + EXPECT_FALSE(exists) << "Temporary directory " << path_ << " already exists."; + ORT_ENFORCE(!exists); + } + + CreateOrDeleteDirectory(path_, /* create */ false); + } + + CreateOrDeleteDirectory(path_, /* create*/ true); } TemporaryDirectory::~TemporaryDirectory() { - const auto status = Env::Default().DeleteFolder(path_); - EXPECT_TRUE(status.IsOK()) << "Failed to delete temporary directory " << path_ << ": " << status.ErrorMessage(); + // don't throw in dtor + CreateOrDeleteDirectory(path_, /* create */ false, /* throw_on_fail */ false); } } // namespace test diff --git a/onnxruntime/test/util/tensors_from_file.cc b/onnxruntime/test/util/tensors_from_file.cc new file mode 100644 index 0000000000000..a99b5a5b4ea49 --- /dev/null +++ b/onnxruntime/test/util/tensors_from_file.cc @@ -0,0 +1,107 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include +#include +#include +#include +#include "test/util/include/tensors_from_file.h" +#include "core/common/common.h" + +namespace onnxruntime { +namespace test { + +static inline void TrimLeft(std::string& s) { + s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { + return !std::isspace(ch); + })); +} + +static inline void TrimRight(std::string& s) { + s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { + return !std::isspace(ch); + }).base(), + s.end()); +} + +static inline void Trim(std::string& s) { + TrimRight(s); + TrimLeft(s); +} + +static inline bool StartsWith(const std::string& s, const std::string& prefix) { + return s.compare(0, prefix.size(), prefix) == 0; +} + +void LoadTensorsFromFile(const std::string& path, std::unordered_map>& tensors) { + std::ifstream infile(path); + if (!infile.good()) { + ORT_THROW("Cannot open file:", path); + } + + // File format is like the following: + // name:TestCaseName1.TensorName1 + // 1.1, 2.3 + // === + // name:TestCaseName2.TensorName2 + // 3.3, 4.5, + // 5.6, 6.7 + // === + // Note that "name:" and "===" shall be at the beginning of a line without leading space! + const std::string name_prefix = "name:"; + const std::string end_tensor_prefix = "==="; + + std::string line; + while (std::getline(infile, line)) { + if (line.empty()) { + continue; + } + + std::string name; + if (StartsWith(line, name_prefix)) { + name = line.substr(name_prefix.length()); + Trim(name); + } + if (name.empty()) { + ORT_THROW("Failed to find name in line:", line); + } + + std::vector values; + while (std::getline(infile, line)) { + if (line.empty()) { + continue; + } + if (StartsWith(line, end_tensor_prefix)) { + break; + } + + std::istringstream ss(line); + for (std::string token; std::getline(ss, token, ',');) { + Trim(token); + if (token.empty()) { + continue; + } + + ORT_TRY { + float value = std::stof(token); + values.push_back(value); + } + ORT_CATCH(const std::exception&) { + ORT_THROW("Failed to parse float from name='", name, ", token='", token); + } + } + } + + if (values.size() == 0) { + ORT_THROW("No values for name=", name); + } + + auto result = tensors.insert({name, values}); + if (result.second == false) { + ORT_THROW("Failed to insert: duplicated name=", name); + } + } +} + +} // namespace test +} // namespace onnxruntime diff --git a/onnxruntime/test/util/test_utils.cc b/onnxruntime/test/util/test_utils.cc index 94fe3b3cc5f62..43845a5052e36 100644 --- a/onnxruntime/test/util/test_utils.cc +++ b/onnxruntime/test/util/test_utils.cc @@ -18,6 +18,48 @@ namespace onnxruntime { namespace test { +void VerifyOutput(const std::string& output_name, + const Tensor& expected_tensor, + const Tensor& tensor, + float fp32_abs_err) { + ASSERT_TRUE(SpanEq(expected_tensor.Shape().GetDims(), tensor.Shape().GetDims())); + ASSERT_EQ(expected_tensor.GetElementType(), tensor.GetElementType()); + auto element_type = expected_tensor.GetElementType(); + switch (element_type) { + case ONNX_NAMESPACE::TensorProto_DataType_UINT32: + EXPECT_TRUE(SpanEq(expected_tensor.DataAsSpan(), tensor.DataAsSpan())) + << " mismatch for " << output_name; + break; + case ONNX_NAMESPACE::TensorProto_DataType_INT32: + EXPECT_TRUE(SpanEq(expected_tensor.DataAsSpan(), tensor.DataAsSpan())) + << " mismatch for " << output_name; + break; + case ONNX_NAMESPACE::TensorProto_DataType_INT64: + EXPECT_TRUE(SpanEq(expected_tensor.DataAsSpan(), tensor.DataAsSpan())) + << " mismatch for " << output_name; + break; + case ONNX_NAMESPACE::TensorProto_DataType_UINT8: + EXPECT_TRUE(SpanEq(expected_tensor.DataAsSpan(), tensor.DataAsSpan())) + << " mismatch for " << output_name; + break; + case ONNX_NAMESPACE::TensorProto_DataType_INT8: + EXPECT_TRUE(SpanEq(expected_tensor.DataAsSpan(), tensor.DataAsSpan())) + << " mismatch for " << output_name; + break; + case ONNX_NAMESPACE::TensorProto_DataType_BOOL: + EXPECT_TRUE(SpanEq(expected_tensor.DataAsSpan(), tensor.DataAsSpan())) + << " mismatch for " << output_name; + break; + case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: { + EXPECT_THAT(expected_tensor.DataAsSpan(), + ::testing::Pointwise(::testing::FloatNear(fp32_abs_err), tensor.DataAsSpan())); + break; + } + default: + ORT_THROW("Unhandled data type. Please add 'case' statement for ", element_type); + } +} + static void VerifyOutputs(const std::vector& output_names, const std::vector& expected_fetches, const std::vector& fetches, @@ -27,33 +69,7 @@ static void VerifyOutputs(const std::vector& output_names, for (size_t i = 0, end = expected_fetches.size(); i < end; ++i) { auto& ltensor = expected_fetches[i].Get(); auto& rtensor = fetches[i].Get(); - ASSERT_TRUE(SpanEq(ltensor.Shape().GetDims(), rtensor.Shape().GetDims())); - auto element_type = ltensor.GetElementType(); - switch (element_type) { - case ONNX_NAMESPACE::TensorProto_DataType_INT32: - EXPECT_TRUE(SpanEq(ltensor.DataAsSpan(), rtensor.DataAsSpan())) - << " mismatch for " << output_names[i]; - break; - case ONNX_NAMESPACE::TensorProto_DataType_INT64: - EXPECT_TRUE(SpanEq(ltensor.DataAsSpan(), rtensor.DataAsSpan())) - << " mismatch for " << output_names[i]; - break; - case ONNX_NAMESPACE::TensorProto_DataType_UINT8: - EXPECT_TRUE(SpanEq(ltensor.DataAsSpan(), rtensor.DataAsSpan())) - << " mismatch for " << output_names[i]; - break; - case ONNX_NAMESPACE::TensorProto_DataType_INT8: - EXPECT_TRUE(SpanEq(ltensor.DataAsSpan(), rtensor.DataAsSpan())) - << " mismatch for " << output_names[i]; - break; - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: { - EXPECT_THAT(ltensor.DataAsSpan(), - ::testing::Pointwise(::testing::FloatNear(params.fp32_abs_err), rtensor.DataAsSpan())); - break; - } - default: - ORT_THROW("Unhandled data type. Please add 'case' statement for ", element_type); - } + VerifyOutput(output_names[i], ltensor, rtensor, params.fp32_abs_err); } } @@ -75,20 +91,51 @@ int CountAssignedNodes(const Graph& current_graph, const std::string& ep_type) { return count; } -void RunAndVerifyOutputsWithEP(const ORTCHAR_T* model_path, const char* log_id, - std::unique_ptr execution_provider, - const NameMLValMap& feeds, - const EPVerificationParams& params) { - // read raw data from model provided by the model_path - std::ifstream stream(model_path, std::ios::in | std::ios::binary); - std::string model_data((std::istreambuf_iterator(stream)), std::istreambuf_iterator()); - RunAndVerifyOutputsWithEP(model_data, log_id, std::move(execution_provider), feeds, params); +void VerifyEPNodeAssignment(const Graph& graph, const std::string& provider_type, + ExpectedEPNodeAssignment assignment) { + const auto provider_node_count = CountAssignedNodes(graph, provider_type); + if (assignment == ExpectedEPNodeAssignment::All) { + // Verify the entire graph is assigned to the EP + ASSERT_EQ(provider_node_count, graph.NumberOfNodes()) << "Not all nodes were assigned to " << provider_type; + } else if (assignment == ExpectedEPNodeAssignment::None) { + // or none of the graph + ASSERT_EQ(provider_node_count, 0) << "Some nodes were assigned to " << provider_type; + } else { + // or some of the graph + ASSERT_GT(provider_node_count, 0) << "No nodes were assigned to " << provider_type; + } +} + +static gsl::span GetModelBytes(ModelPathOrBytes model_path_or_bytes, + std::vector& byte_buffer_out) { + if (const auto* model_bytes = std::get_if>(&model_path_or_bytes); + model_bytes != nullptr) { + byte_buffer_out = std::vector{}; + return *model_bytes; + } + + const auto model_path = std::get>(model_path_or_bytes); + + std::vector byte_buffer{}; + std::ifstream stream{std::basic_string{model_path}, + std::ios::in | std::ios::binary | std::ios::ate}; + ORT_ENFORCE(stream, "Failed to open file."); + const auto num_bytes = narrow(stream.tellg()); + byte_buffer.resize(num_bytes); + stream.seekg(0); + ORT_ENFORCE(stream.read(reinterpret_cast(byte_buffer.data()), num_bytes), "Failed to read file."); + + byte_buffer_out = std::move(byte_buffer); + return gsl::span(byte_buffer_out); } -void RunAndVerifyOutputsWithEP(const std::string& model_data, const char* log_id, +void RunAndVerifyOutputsWithEP(ModelPathOrBytes model_path_or_bytes, std::string_view log_id, std::unique_ptr execution_provider, const NameMLValMap& feeds, const EPVerificationParams& params) { + std::vector model_data_buffer{}; + const auto model_data = GetModelBytes(model_path_or_bytes, model_data_buffer); + SessionOptions so; so.session_logid = log_id; RunOptions run_options; @@ -126,18 +173,8 @@ void RunAndVerifyOutputsWithEP(const std::string& model_data, const char* log_id ASSERT_STATUS_OK(session_object2.Load(model_data.data(), static_cast(model_data.size()))); ASSERT_STATUS_OK(session_object2.Initialize()); - // make sure that some nodes are assigned to the EP, otherwise this test is pointless... const auto& graph2 = session_object2.GetGraph(); - auto ep_nodes = CountAssignedNodes(graph2, provider_type); - if (params.ep_node_assignment == ExpectedEPNodeAssignment::All) { - // Verify the entire graph is assigned to the EP - ASSERT_EQ(ep_nodes, graph2.NumberOfNodes()) << "Not all nodes were assigned to " << provider_type; - } else if (params.ep_node_assignment == ExpectedEPNodeAssignment::None) { - // Check if expected failure path is correctly handled by ep. (only used in NNAPI EP QDQ model test case for now) - ASSERT_EQ(ep_nodes, 0) << "No nodes are supposed to be assigned to " << provider_type; - } else { - ASSERT_GT(ep_nodes, 0) << "No nodes were assigned to " << provider_type; - } + ASSERT_NO_FATAL_FAILURE(VerifyEPNodeAssignment(graph2, provider_type, params.ep_node_assignment)); // Run with EP and verify the result std::vector fetches; @@ -149,6 +186,22 @@ void RunAndVerifyOutputsWithEP(const std::string& model_data, const char* log_id } } +void TestModelLoad(ModelPathOrBytes model_path_or_bytes, + std::unique_ptr execution_provider, + const std::function& check_graph) { + std::vector model_data_buffer{}; + const auto model_data = GetModelBytes(model_path_or_bytes, model_data_buffer); + + SessionOptions so; + InferenceSessionWrapper session_object{so, GetEnvironment()}; + ASSERT_STATUS_OK(session_object.RegisterExecutionProvider(std::move(execution_provider))); + ASSERT_STATUS_OK(session_object.Load(model_data.data(), static_cast(model_data.size()))); + ASSERT_STATUS_OK(session_object.Initialize()); + if (check_graph) { + check_graph(session_object.GetGraph()); + } +} + void CheckShapeEquality(const ONNX_NAMESPACE::TensorShapeProto* shape1, const ONNX_NAMESPACE::TensorShapeProto* shape2) { EXPECT_NE(shape1, nullptr); diff --git a/onnxruntime/test/wasm/karma.conf.js b/onnxruntime/test/wasm/karma.conf.js index 6fab9a9555bc7..d6830501d2290 100644 --- a/onnxruntime/test/wasm/karma.conf.js +++ b/onnxruntime/test/wasm/karma.conf.js @@ -65,6 +65,10 @@ module.exports = function(config) { base: 'ChromeCanary', flags: chromeFlags }, + ChromeHeadlessTest: { + base: 'ChromeHeadless', + flags: chromeFlags + }, EdgeTest: { base: 'Edge', flags: chromeFlags diff --git a/onnxruntime/test/wasm/package-lock.json b/onnxruntime/test/wasm/package-lock.json index ad6260f7cf887..3f6db4097356e 100644 --- a/onnxruntime/test/wasm/package-lock.json +++ b/onnxruntime/test/wasm/package-lock.json @@ -386,9 +386,9 @@ } }, "node_modules/engine.io": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.4.0.tgz", - "integrity": "sha512-OgxY1c/RuCSeO/rTr8DIFXx76IzUUft86R7/P7MMbbkuzeqJoTNw2lmeD91IyGz41QYleIIjWeMJGgug043sfQ==", + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.4.2.tgz", + "integrity": "sha512-FKn/3oMiJjrOEOeUub2WCox6JhxBXq/Zn3fZOMCBxKnNYtsdKjxhl7yR3fZhM9PV+rdE75SU5SYMc+2PGzo+Tg==", "dev": true, "dependencies": { "@types/cookie": "^0.4.1", @@ -1218,9 +1218,9 @@ } }, "node_modules/socket.io-parser": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.2.tgz", - "integrity": "sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.3.tgz", + "integrity": "sha512-JMafRntWVO2DCJimKsRTh/wnqVvO4hrfwOqtO7f+uzwsQMuxO6VwImtYxaQ+ieoyshWOTJyV0fA21lccEXRPpQ==", "dev": true, "dependencies": { "@socket.io/component-emitter": "~3.1.0", @@ -1860,9 +1860,9 @@ "dev": true }, "engine.io": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.4.0.tgz", - "integrity": "sha512-OgxY1c/RuCSeO/rTr8DIFXx76IzUUft86R7/P7MMbbkuzeqJoTNw2lmeD91IyGz41QYleIIjWeMJGgug043sfQ==", + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.4.2.tgz", + "integrity": "sha512-FKn/3oMiJjrOEOeUub2WCox6JhxBXq/Zn3fZOMCBxKnNYtsdKjxhl7yR3fZhM9PV+rdE75SU5SYMc+2PGzo+Tg==", "dev": true, "requires": { "@types/cookie": "^0.4.1", @@ -2509,9 +2509,9 @@ } }, "socket.io-parser": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.2.tgz", - "integrity": "sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.3.tgz", + "integrity": "sha512-JMafRntWVO2DCJimKsRTh/wnqVvO4hrfwOqtO7f+uzwsQMuxO6VwImtYxaQ+ieoyshWOTJyV0fA21lccEXRPpQ==", "dev": true, "requires": { "@socket.io/component-emitter": "~3.1.0", diff --git a/onnxruntime/test/wasm/package.json b/onnxruntime/test/wasm/package.json index 02a8a9bb96d7e..8bd9ddc2638c8 100644 --- a/onnxruntime/test/wasm/package.json +++ b/onnxruntime/test/wasm/package.json @@ -2,7 +2,7 @@ "name": "wasm-test-adapter", "private": true, "scripts": { - "test": "karma start --browsers EdgeTest --single-run" + "test": "karma start --browsers ChromeHeadlessTest --single-run" }, "devDependencies": { "@chiragrupani/karma-chromium-edge-launcher": "^2.2.2", diff --git a/onnxruntime/wasm/api.cc b/onnxruntime/wasm/api.cc index 47cb578f7e969..174edabbc91fe 100644 --- a/onnxruntime/wasm/api.cc +++ b/onnxruntime/wasm/api.cc @@ -1,26 +1,36 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "api.h" +#ifdef ENABLE_TRAINING_APIS +#include "onnxruntime_training_cxx_api.h" +#endif #include "core/session/onnxruntime_cxx_api.h" +#include "api.h" #include #include namespace { OrtEnv* g_env; +OrtErrorCode g_last_error_code; +std::string g_last_error_message; } // namespace +static_assert(sizeof(const char*) == sizeof(size_t), "size of a pointer and a size_t value should be the same."); +static_assert(sizeof(size_t) == 4, "size of size_t should be 4 in this build (wasm32)."); + OrtErrorCode CheckStatus(OrtStatusPtr status) { - OrtErrorCode error_code = ORT_OK; if (status) { std::string error_message = Ort::GetApi().GetErrorMessage(status); - error_code = Ort::GetApi().GetErrorCode(status); - std::cerr << Ort::Exception(std::move(error_message), error_code).what() << std::endl; + g_last_error_code = Ort::GetApi().GetErrorCode(status); + g_last_error_message = Ort::Exception(std::move(error_message), g_last_error_code).what(); Ort::GetApi().ReleaseStatus(status); + } else { + g_last_error_code = ORT_OK; + g_last_error_message.clear(); } - return error_code; + return g_last_error_code; } #define CHECK_STATUS(ORT_API_NAME, ...) \ @@ -34,7 +44,6 @@ OrtErrorCode CheckStatus(OrtStatusPtr status) { } \ } while (false) -// TODO: This macro can be removed when we changed all APIs to return a status code. #define RETURN_NULLPTR_IF_ERROR(ORT_API_NAME, ...) \ do { \ if (CHECK_STATUS(ORT_API_NAME, __VA_ARGS__) != ORT_OK) { \ @@ -42,6 +51,21 @@ OrtErrorCode CheckStatus(OrtStatusPtr status) { } \ } while (false) +// use auto release macros to make sure resources get released on function return. + +// create a unique_ptr wrapper for auto release +#define REGISTER_AUTO_RELEASE(T, var, release_t, release_func) \ + std::unique_ptr auto_release_##var { var, release_func } +// register auto release for handle of Ort API resources +#define REGISTER_AUTO_RELEASE_HANDLE(T, var) \ + REGISTER_AUTO_RELEASE(Ort##T, var, void (*)(Ort##T*), [](Ort##T* p) { Ort::GetApi().Release##T(p); }) +// register auto release for Ort allocated buffers +#define REGISTER_AUTO_RELEASE_BUFFER(T, var, allocator) \ + auto auto_release_##var##_deleter = [allocator](T* p) { allocator->Free(allocator, p); }; \ + REGISTER_AUTO_RELEASE(T, var, decltype(auto_release_##var##_deleter), auto_release_##var##_deleter) +// unregister the auto release wrapper +#define UNREGISTER_AUTO_RELEASE(var) auto_release_##var.release() + int OrtInit(int num_threads, int logging_level) { // Assume that a logging level is check and properly set at JavaScript #if defined(__EMSCRIPTEN_PTHREADS__) @@ -60,6 +84,11 @@ int OrtInit(int num_threads, int logging_level) { #endif } +void OrtGetLastError(int* error_code, const char** error_message) { + *error_code = g_last_error_code; + *error_message = g_last_error_message.empty() ? nullptr : g_last_error_message.c_str(); +} + OrtSessionOptions* OrtCreateSessionOptions(size_t graph_optimization_level, bool enable_cpu_mem_arena, bool enable_mem_pattern, @@ -72,6 +101,7 @@ OrtSessionOptions* OrtCreateSessionOptions(size_t graph_optimization_level, const char* optimized_model_filepath) { OrtSessionOptions* session_options = nullptr; RETURN_NULLPTR_IF_ERROR(CreateSessionOptions, &session_options); + REGISTER_AUTO_RELEASE_HANDLE(SessionOptions, session_options); if (optimized_model_filepath) { RETURN_NULLPTR_IF_ERROR(SetOptimizedModelFilePath, session_options, optimized_model_filepath); @@ -118,13 +148,19 @@ OrtSessionOptions* OrtCreateSessionOptions(size_t graph_optimization_level, RETURN_NULLPTR_IF_ERROR(EnableOrtCustomOps, session_options); #endif - return session_options; + 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 OrtAddFreeDimensionOverride(ort_session_options_handle_t session_options, + const char* dim_param_name, + int dim_value) { + return CHECK_STATUS(AddFreeDimensionOverrideByName, session_options, dim_param_name, dim_value); +} + int OrtAddSessionConfigEntry(OrtSessionOptions* session_options, const char* config_key, const char* config_value) { @@ -136,11 +172,6 @@ void OrtReleaseSessionOptions(OrtSessionOptions* session_options) { } OrtSession* OrtCreateSession(void* data, size_t data_length, OrtSessionOptions* session_options) { - // OrtSessionOptions must not be nullptr. - if (session_options == nullptr) { - return nullptr; - } - #if defined(__EMSCRIPTEN_PTHREADS__) RETURN_NULLPTR_IF_ERROR(DisablePerSessionThreads, session_options); #else @@ -159,14 +190,10 @@ void OrtReleaseSession(OrtSession* session) { Ort::GetApi().ReleaseSession(session); } -size_t OrtGetInputCount(OrtSession* session) { - size_t input_count = 0; - return (CHECK_STATUS(SessionGetInputCount, session, &input_count) == ORT_OK) ? input_count : 0; -} - -size_t OrtGetOutputCount(OrtSession* session) { - size_t output_count = 0; - return (CHECK_STATUS(SessionGetOutputCount, session, &output_count) == ORT_OK) ? output_count : 0; +int OrtGetInputOutputCount(OrtSession* session, size_t* input_count, size_t* output_count) { + RETURN_ERROR_CODE_IF_ERROR(SessionGetInputCount, session, input_count); + RETURN_ERROR_CODE_IF_ERROR(SessionGetOutputCount, session, output_count); + return ORT_OK; } char* OrtGetInputName(OrtSession* session, size_t index) { @@ -210,100 +237,79 @@ OrtValue* OrtCreateTensor(int data_type, void* data, size_t data_length, size_t* RETURN_NULLPTR_IF_ERROR(CreateTensorAsOrtValue, allocator, dims_length > 0 ? shapes.data() : nullptr, dims_length, ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING, &value); + REGISTER_AUTO_RELEASE_HANDLE(Value, value); const char* const* strings = reinterpret_cast(data); RETURN_NULLPTR_IF_ERROR(FillStringTensor, value, strings, data_length / sizeof(const char*)); - return value; + return UNREGISTER_AUTO_RELEASE(value); } else { OrtMemoryInfo* memoryInfo = nullptr; RETURN_NULLPTR_IF_ERROR(CreateCpuMemoryInfo, OrtDeviceAllocator, OrtMemTypeDefault, &memoryInfo); + REGISTER_AUTO_RELEASE_HANDLE(MemoryInfo, memoryInfo); OrtValue* value = nullptr; int error_code = CHECK_STATUS(CreateTensorWithDataAsOrtValue, memoryInfo, data, data_length, dims_length > 0 ? shapes.data() : nullptr, dims_length, static_cast(data_type), &value); - Ort::GetApi().ReleaseMemoryInfo(memoryInfo); return (error_code == ORT_OK) ? value : nullptr; } } int OrtGetTensorData(OrtValue* tensor, int* data_type, void** data, size_t** dims, size_t* dims_length) { -#define RELEASE_AND_RETURN_ERROR_CODE_IF_ERROR(ORT_API_NAME, ...) \ - do { \ - int error_code = CHECK_STATUS(ORT_API_NAME, __VA_ARGS__); \ - if (error_code != ORT_OK) { \ - if (info != nullptr) { \ - Ort::GetApi().ReleaseTensorTypeAndShapeInfo(info); \ - } \ - if (allocator != nullptr && p_dims != nullptr) { \ - allocator->Free(allocator, p_dims); \ - } \ - if (allocator != nullptr && p_string_data != nullptr) { \ - allocator->Free(allocator, p_string_data); \ - } \ - return error_code; \ - } \ - } while (false) - - OrtTensorTypeAndShapeInfo* info = nullptr; - OrtAllocator* allocator = nullptr; - size_t* p_dims = nullptr; - void* p_string_data = nullptr; - ONNXType tensor_type; RETURN_ERROR_CODE_IF_ERROR(GetValueType, tensor, &tensor_type); if (tensor_type != ONNX_TYPE_TENSOR) { - return ORT_FAIL; + return CheckStatus( + Ort::GetApi().CreateStatus(ORT_NOT_IMPLEMENTED, "Reading data from non-tensor typed value is not supported.")); } + OrtTensorTypeAndShapeInfo* info = nullptr; RETURN_ERROR_CODE_IF_ERROR(GetTensorTypeAndShape, tensor, &info); + REGISTER_AUTO_RELEASE_HANDLE(TensorTypeAndShapeInfo, info); size_t dims_len = 0; - RELEASE_AND_RETURN_ERROR_CODE_IF_ERROR(GetDimensionsCount, info, &dims_len); + RETURN_ERROR_CODE_IF_ERROR(GetDimensionsCount, info, &dims_len); - RELEASE_AND_RETURN_ERROR_CODE_IF_ERROR(GetAllocatorWithDefaultOptions, &allocator); - p_dims = reinterpret_cast(allocator->Alloc(allocator, sizeof(size_t) * dims_len)); + OrtAllocator* allocator = nullptr; + RETURN_ERROR_CODE_IF_ERROR(GetAllocatorWithDefaultOptions, &allocator); - RELEASE_AND_RETURN_ERROR_CODE_IF_ERROR(GetTensorMutableData, tensor, data); + size_t* p_dims = reinterpret_cast(allocator->Alloc(allocator, sizeof(size_t) * dims_len)); + REGISTER_AUTO_RELEASE_BUFFER(size_t, p_dims, allocator); ONNXTensorElementDataType type; - RELEASE_AND_RETURN_ERROR_CODE_IF_ERROR(GetTensorElementType, info, &type); - *data_type = static_cast(type); + RETURN_ERROR_CODE_IF_ERROR(GetTensorElementType, info, &type); - *dims_length = dims_len; std::vector shape(dims_len, 0); - RELEASE_AND_RETURN_ERROR_CODE_IF_ERROR(GetDimensions, info, shape.data(), shape.size()); + RETURN_ERROR_CODE_IF_ERROR(GetDimensions, info, shape.data(), shape.size()); for (size_t i = 0; i < dims_len; i++) { p_dims[i] = static_cast(shape[i]); } - *dims = p_dims; if (type == ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING) { size_t num_elements; - RELEASE_AND_RETURN_ERROR_CODE_IF_ERROR(GetTensorShapeElementCount, info, &num_elements); + RETURN_ERROR_CODE_IF_ERROR(GetTensorShapeElementCount, info, &num_elements); // NOTE: ORT C-API does not expose an interface for users to get string raw data directly. There is always a copy. - // we can use the tensor raw data because it is type of "std::string *", which is very starightforward to + // we can use the tensor raw data because it is type of "std::string *", which is very straightforward to // implement and can also save memory usage. However, this approach depends on the Tensor's implementation // details. So we have to copy the string content here. size_t string_data_length; - RELEASE_AND_RETURN_ERROR_CODE_IF_ERROR(GetStringTensorDataLength, tensor, &string_data_length); + RETURN_ERROR_CODE_IF_ERROR(GetStringTensorDataLength, tensor, &string_data_length); // The buffer contains following data: // - a sequence of pointers to (const char*), size = num_elements * sizeof(const char*). // - followed by a raw buffer to store string content, size = string_data_length + 1. - static_assert(sizeof(const char*) == sizeof(size_t), "size of a pointer and a size_t value should be the same."); - size_t string_data_offset = num_elements * sizeof(const char*); size_t buf_size = string_data_offset + string_data_length; - p_string_data = allocator->Alloc(allocator, buf_size + 1); + void* p_string_data = allocator->Alloc(allocator, buf_size + 1); void* p_string_content = reinterpret_cast(p_string_data) + string_data_offset; + REGISTER_AUTO_RELEASE_BUFFER(void, p_string_data, allocator); size_t* p_offsets = reinterpret_cast(p_string_data); - RELEASE_AND_RETURN_ERROR_CODE_IF_ERROR(GetStringTensorContent, tensor, p_string_content, string_data_length, p_offsets, num_elements); + RETURN_ERROR_CODE_IF_ERROR(GetStringTensorContent, tensor, p_string_content, string_data_length, p_offsets, num_elements); // replace offsets by pointers const char** p_c_strs = reinterpret_cast(p_offsets); @@ -313,10 +319,17 @@ int OrtGetTensorData(OrtValue* tensor, int* data_type, void** data, size_t** dim // put null at the last char reinterpret_cast(p_string_data)[buf_size] = '\0'; - *data = p_string_data; + + *data = UNREGISTER_AUTO_RELEASE(p_string_data); + } else { + void* p_tensor_raw_data = nullptr; + RETURN_ERROR_CODE_IF_ERROR(GetTensorMutableData, tensor, &p_tensor_raw_data); + *data = p_tensor_raw_data; } - Ort::GetApi().ReleaseTensorTypeAndShapeInfo(info); + *data_type = static_cast(type); + *dims_length = dims_len; + *dims = UNREGISTER_AUTO_RELEASE(p_dims); return ORT_OK; } @@ -330,6 +343,7 @@ OrtRunOptions* OrtCreateRunOptions(size_t log_severity_level, const char* tag) { OrtRunOptions* run_options = nullptr; RETURN_NULLPTR_IF_ERROR(CreateRunOptions, &run_options); + REGISTER_AUTO_RELEASE_HANDLE(RunOptions, run_options); // Assume that a logging level is check and properly set at JavaScript RETURN_NULLPTR_IF_ERROR(RunOptionsSetRunLogSeverityLevel, run_options, log_severity_level); @@ -346,7 +360,7 @@ OrtRunOptions* OrtCreateRunOptions(size_t log_severity_level, RETURN_NULLPTR_IF_ERROR(RunOptionsSetRunTag, run_options, tag); } - return run_options; + return UNREGISTER_AUTO_RELEASE(run_options); } int OrtAddRunConfigEntry(OrtRunOptions* run_options, @@ -363,12 +377,9 @@ int OrtRun(OrtSession* session, const char** input_names, const ort_tensor_handle_t* inputs, size_t input_count, const char** output_names, size_t output_count, ort_tensor_handle_t* outputs, OrtRunOptions* run_options) { -#if defined(USE_JS) - EM_ASM({ Module["jsepRunPromise"] = new Promise(function(r) { Module.jsepRunPromiseResolve = r; }); }); -#endif auto status_code = CHECK_STATUS(Run, session, run_options, input_names, inputs, input_count, output_names, output_count, outputs); -#if defined(USE_JS) - EM_ASM({ Module.jsepRunPromiseResolve($0); }, status_code); +#if defined(USE_JSEP) + EM_ASM({ Module.jsepRunPromiseResolve ?.($0); }, status_code); #endif return status_code; } @@ -382,3 +393,93 @@ char* OrtEndProfiling(ort_session_handle_t session) { ? file_name : nullptr; } + +// Training API Section + +#ifdef ENABLE_TRAINING_APIS +#define CHECK_TRAINING_STATUS(ORT_API_NAME, ...) \ + CheckStatus(Ort::GetTrainingApi().ORT_API_NAME(__VA_ARGS__)) + +ort_training_checkpoint_handle_t EMSCRIPTEN_KEEPALIVE OrtTrainingLoadCheckpoint(void* checkpoint_data_buffer, + size_t checkpoint_size) { + OrtCheckpointState* checkpoint_state = nullptr; + return (CHECK_TRAINING_STATUS(LoadCheckpointFromBuffer, checkpoint_data_buffer, + checkpoint_size, &checkpoint_state) == ORT_OK) + ? checkpoint_state + : nullptr; +} + +void EMSCRIPTEN_KEEPALIVE OrtTrainingReleaseCheckpoint(ort_training_checkpoint_handle_t training_checkpoint_state_handle) { + Ort::GetTrainingApi().ReleaseCheckpointState(training_checkpoint_state_handle); +} + +ort_training_session_handle_t EMSCRIPTEN_KEEPALIVE OrtTrainingCreateSession(const ort_session_options_handle_t options, + ort_training_checkpoint_handle_t training_checkpoint_state_handle, + void* train_model, + size_t train_size, + void* eval_model, + size_t eval_size, + void* optimizer_model, + size_t optimizer_size) { + OrtTrainingSession* training_session = nullptr; + return (CHECK_TRAINING_STATUS(CreateTrainingSessionFromBuffer, g_env, options, + training_checkpoint_state_handle, train_model, train_size, + eval_model, eval_size, optimizer_model, optimizer_size, + &training_session) == ORT_OK) + ? training_session + : nullptr; +} + +int EMSCRIPTEN_KEEPALIVE OrtTrainingLazyResetGrad(ort_training_session_handle_t training_handle) { + return CHECK_TRAINING_STATUS(LazyResetGrad, training_handle); +} + +int EMSCRIPTEN_KEEPALIVE OrtTrainingRunTrainStep(ort_training_session_handle_t training_handle, + ort_tensor_handle_t* inputs, + size_t input_count, + ort_tensor_handle_t* outputs, + size_t output_count, + ort_run_options_handle_t options) { + return CHECK_TRAINING_STATUS(TrainStep, training_handle, options, input_count, inputs, output_count, outputs); +} + +int EMSCRIPTEN_KEEPALIVE OrtTrainingOptimizerStep(ort_training_session_handle_t training_handle, + const ort_run_options_handle_t run_options) { + return CHECK_TRAINING_STATUS(OptimizerStep, training_handle, run_options); +} + +int EMSCRIPTEN_KEEPALIVE OrtTrainingEvalStep(ort_training_session_handle_t training_handle, + ort_tensor_handle_t* inputs, + size_t input_count, + ort_tensor_handle_t* outputs, + size_t output_count, + ort_run_options_handle_t options) { + return CHECK_TRAINING_STATUS(EvalStep, training_handle, + options, input_count, inputs, output_count, outputs); +} + +int EMSCRIPTEN_KEEPALIVE OrtTrainingGetParametersSize(ort_training_session_handle_t training_handle, + size_t* param_size, + bool trainable_only) { + return CHECK_TRAINING_STATUS(GetParametersSize, training_handle, param_size, trainable_only); +} + +int EMSCRIPTEN_KEEPALIVE OrtTrainingCopyParametersToBuffer(ort_training_session_handle_t training_handle, + ort_tensor_handle_t parameters_buffer, + size_t parameter_count, + bool trainable_only) { + return CHECK_TRAINING_STATUS(CopyParametersToBuffer, training_handle, parameters_buffer, trainable_only); +} + +int EMSCRIPTEN_KEEPALIVE OrtTrainingCopyParametersFromBuffer(ort_training_session_handle_t training_handle, + ort_tensor_handle_t parameters_buffer, + size_t parameter_count, + bool trainable_only) { + return CHECK_TRAINING_STATUS(CopyBufferToParameters, training_handle, parameters_buffer, trainable_only); +} + +void EMSCRIPTEN_KEEPALIVE OrtTrainingReleaseSession(ort_training_session_handle_t training_handle) { + Ort::GetTrainingApi().ReleaseTrainingSession(training_handle); +} + +#endif diff --git a/onnxruntime/wasm/api.h b/onnxruntime/wasm/api.h index 80466ecd871c4..398c901e0e5ed 100644 --- a/onnxruntime/wasm/api.h +++ b/onnxruntime/wasm/api.h @@ -24,15 +24,31 @@ using ort_run_options_handle_t = OrtRunOptions*; struct OrtValue; using ort_tensor_handle_t = OrtValue*; +#ifdef ENABLE_TRAINING_APIS +struct OrtTrainingSession; +using ort_training_session_handle_t = OrtTrainingSession*; + +struct OrtCheckpointState; +using ort_training_checkpoint_handle_t = OrtCheckpointState*; +#endif + extern "C" { /** * perform global initialization. should be called only once. * @param num_threads number of total threads to use. * @param logging_level default logging level. + * @returns ORT error code. If not zero, call OrtGetLastError() to get detailed error message. */ int EMSCRIPTEN_KEEPALIVE OrtInit(int num_threads, int logging_level); +/** + * get the last error. + * @param error_code [out] a pointer to accept the error code. + * @param error_message [out] a pointer to accept the error message. The message buffer is only available before any ORT API is called. + */ +void EMSCRIPTEN_KEEPALIVE OrtGetLastError(int* error_code, const char** error_message); + /** * create an instance of ORT session options. * assume that all enum type parameters, such as graph_optimization_level, execution_mode, and log_severity_level, @@ -47,7 +63,7 @@ int EMSCRIPTEN_KEEPALIVE OrtInit(int num_threads, int logging_level); * @param log_severity_level verbose, info, warning, error or fatal * @param log_verbosity_level vlog level * @param optimized_model_filepath filepath of the optimized model to dump. - * @returns a pointer to a session option handle and must be freed by calling OrtReleaseSessionOptions(). + * @returns a session option handle. Caller must release it after use by calling OrtReleaseSessionOptions(). */ ort_session_options_handle_t EMSCRIPTEN_KEEPALIVE OrtCreateSessionOptions(size_t graph_optimization_level, bool enable_cpu_mem_arena, @@ -63,16 +79,25 @@ ort_session_options_handle_t EMSCRIPTEN_KEEPALIVE OrtCreateSessionOptions(size_t /** * append an execution provider for a session. * @param name the name of the execution provider + * @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); +/** + * add a free dimension override for one dimension of a session's input. + */ +int EMSCRIPTEN_KEEPALIVE OrtAddFreeDimensionOverride(ort_session_options_handle_t session_options, + const char* dim_param_name, + int dim_value); + /** * store configurations for a session. * @param session_options a handle to session options created by OrtCreateSessionOptions * @param config_key configuration keys and value formats are defined in * include/onnxruntime/core/session/onnxruntime_session_options_config_keys.h * @param config_value value for config_key + * @returns ORT error code. If not zero, call OrtGetLastError() to get detailed error message. */ int EMSCRIPTEN_KEEPALIVE OrtAddSessionConfigEntry(ort_session_options_handle_t session_options, const char* config_key, @@ -87,7 +112,7 @@ void EMSCRIPTEN_KEEPALIVE OrtReleaseSessionOptions(ort_session_options_handle_t * create an instance of ORT session. * @param data a pointer to a buffer that contains the ONNX or ORT format model. * @param data_length the size of the buffer in bytes. - * @returns a handle of the ORT session. + * @returns an ORT session handle. Caller must release it after use by calling OrtReleaseSession(). */ ort_session_handle_t EMSCRIPTEN_KEEPALIVE OrtCreateSession(void* data, size_t data_length, @@ -98,8 +123,16 @@ ort_session_handle_t EMSCRIPTEN_KEEPALIVE OrtCreateSession(void* data, */ void EMSCRIPTEN_KEEPALIVE OrtReleaseSession(ort_session_handle_t session); -size_t EMSCRIPTEN_KEEPALIVE OrtGetInputCount(ort_session_handle_t session); -size_t EMSCRIPTEN_KEEPALIVE OrtGetOutputCount(ort_session_handle_t session); +/** + * get model's input count and output count. + * @param session handle of the specified session + * @param input_count [out] a pointer to a size_t variable to accept input_count. + * @param output_count [out] a pointer to a size_t variable to accept output_count. + * @returns ORT error code. If not zero, call OrtGetLastError() to get detailed error message. + */ +int EMSCRIPTEN_KEEPALIVE OrtGetInputOutputCount(ort_session_handle_t session, + size_t* input_count, + size_t* output_count); /** * get the model's input name. @@ -131,7 +164,7 @@ void EMSCRIPTEN_KEEPALIVE OrtFree(void* ptr); * @param data_length size of the buffer 'data' in bytes. * @param dims a pointer to an array of dims. the array should contain (dims_length) element(s). * @param dims_length the length of the tensor's dimension - * @returns a handle of the tensor. + * @returns a tensor handle. Caller must release it after use by calling OrtReleaseTensor(). */ ort_tensor_handle_t EMSCRIPTEN_KEEPALIVE OrtCreateTensor(int data_type, void* data, size_t data_length, size_t* dims, size_t dims_length); @@ -144,6 +177,7 @@ ort_tensor_handle_t EMSCRIPTEN_KEEPALIVE OrtCreateTensor(int data_type, void* da * @param dims_length [out] specify the memory to write dims length * @remarks following temporary buffers are allocated during the call. Caller must release the buffers after use by calling OrtFree(): * 'dims' (for all types of tensor), 'data' (only for string tensor) + * @returns ORT error code. If not zero, call OrtGetLastError() to get detailed error message. */ int EMSCRIPTEN_KEEPALIVE OrtGetTensorData(ort_tensor_handle_t tensor, int* data_type, void** data, size_t** dims, size_t* dims_length); @@ -158,7 +192,7 @@ void EMSCRIPTEN_KEEPALIVE OrtReleaseTensor(ort_tensor_handle_t tensor); * @param log_verbosity_level vlog level * @param terminate if true, all incomplete OrtRun calls will exit as soon as possible * @param tag tag for this run - * @returns a pointer to a run option handle and must be freed by calling OrtReleaseRunOptions(). + * @returns a run option handle. Caller must release it after use by calling OrtReleaseRunOptions(). */ ort_run_options_handle_t EMSCRIPTEN_KEEPALIVE OrtCreateRunOptions(size_t log_severity_level, size_t log_verbosity_level, @@ -171,6 +205,7 @@ ort_run_options_handle_t EMSCRIPTEN_KEEPALIVE OrtCreateRunOptions(size_t log_sev * @param config_key configuration keys and value formats are defined in * include/onnxruntime/core/session/onnxruntime_run_options_config_keys.h * @param config_value value for config_key + * @returns ORT error code. If not zero, call OrtGetLastError() to get detailed error message. */ int EMSCRIPTEN_KEEPALIVE OrtAddRunConfigEntry(ort_run_options_handle_t run_options, const char* config_key, @@ -184,7 +219,7 @@ void EMSCRIPTEN_KEEPALIVE OrtReleaseRunOptions(ort_run_options_handle_t run_opti /** * inference the model. * @param session handle of the specified session - * @returns error code defined in enum OrtErrorCode + * @returns ORT error code. If not zero, call OrtGetLastError() to get detailed error message. */ int EMSCRIPTEN_KEEPALIVE OrtRun(ort_session_handle_t session, const char** input_names, @@ -202,4 +237,151 @@ int EMSCRIPTEN_KEEPALIVE OrtRun(ort_session_handle_t session, * Caller must release the C style string after use by calling OrtFree(). */ char* EMSCRIPTEN_KEEPALIVE OrtEndProfiling(ort_session_handle_t session); + +// Training API Section + +#ifdef ENABLE_TRAINING_APIS +/** + * @brief Load the checkpoint for training. + * + * @param checkpoint_data_buffer pointer to a buffer containing the CheckpointState + * @param checkpoint_size size of the CheckpointState in bytes + * @return ort_training_checkpoint_handle_t + */ +ort_training_checkpoint_handle_t EMSCRIPTEN_KEEPALIVE OrtTrainingLoadCheckpoint(void* checkpoint_data_buffer, size_t checkpoint_size); + +/** + * @brief Release the specified ORT training checkpoint state. + * + * @param training_checkpoint_state_handle handle for the CheckpointState + */ +void EMSCRIPTEN_KEEPALIVE OrtTrainingReleaseCheckpoint(ort_training_checkpoint_handle_t training_checkpoint_state_handle); + +/** + * Creates an instance of a training session that can be used to begin or resume training from a given checkpoint state + * for the given onnx models. + * @param options Session options that the user can customize for this training session. + * @param training_checkpoint_state_handle Training states that the training session uses as a starting point for training. + * @param train_model pointer to a buffer containing the ONNX training model + * @param train_size size of the train_model buffer in bytes + * @param eval_model pointer to a buffer containing the ONNX evaluation model + * @param eval_size size of the eval_model buffer in bytes + * @param optimizer_model pointer to a buffer containing the ONNX optimizer model + * @param optimizer_size size of the optimizer_model buffer in bytes + * @return a handle of the ORT training session + * + */ +ort_training_session_handle_t EMSCRIPTEN_KEEPALIVE OrtTrainingCreateSession(ort_session_options_handle_t options, + ort_training_checkpoint_handle_t training_checkpoint_state_handle, + void* train_model, + size_t train_size, + void* eval_model, + size_t eval_size, + void* optimizer_model, + size_t optimizer_size); + +/** + * Resets the gradients of all trainable parameters to zero for the specified TrainingSession + * @param training_handle handle of the training session + * @returns ORT error code. If not zero, call OrtGetLastError() to get detailed error message. + */ +int EMSCRIPTEN_KEEPALIVE OrtTrainingLazyResetGrad(ort_training_session_handle_t training_handle); + +/** + * @brief Run a single training step. + * + * @param training_handle session handle of the specified session + * @param inputs user inputs to the training model + * @param input_count number of user inputs to the training model + * @param outputs [out] user outputs computed by train step + * @param output_count [out] number of user outputs expected from this train step + * @param run_options handle of the run options + * @return int ORT error code. If not zero, call OrtGetLastError() to get detailed error message. + */ +int EMSCRIPTEN_KEEPALIVE OrtTrainingRunTrainStep(ort_training_session_handle_t training_handle, + ort_tensor_handle_t* inputs, size_t input_count, + ort_tensor_handle_t* outputs, + size_t output_count, + ort_run_options_handle_t run_options = nullptr); + +/** + * Performs weight updates for the trainable parameters in the given training session using the optimizer model. + * @param training_handle handle of the training session + * @param run_options optional parameter of run options for this training step + * @returns ORT error code. If not zero, call OrtGetLastError() to get detailed error message. + */ +int EMSCRIPTEN_KEEPALIVE OrtTrainingOptimizerStep(ort_training_session_handle_t training_handle, + ort_run_options_handle_t run_options = nullptr); + +/** + * Computs outputs for the eval model associated with the given training session. + * @param training_handle handle of the training session + * @param options run options for this eval step + * @param input_count number of user inputs to the eval model + * @param inputs the user inputs to the eval model + * @param output_count [out] number of user outputs expected from this eval step + * @param outputs [out] user outputs computed by the eval step + * @returns ORT error code. If not zero, call OrtGetLastError() to get detailed error message. + */ +int EMSCRIPTEN_KEEPALIVE OrtTrainingEvalStep(ort_training_session_handle_t training_handle, + ort_tensor_handle_t* inputs, + size_t input_count, + ort_tensor_handle_t* outputs, + size_t output_count, + ort_run_options_handle_t options = nullptr); + +/** + * Retrieves the size of all parameters for the training state. + * When the trainable_only argument is true, the size is calculated for trainable params only. + * + * @param training_handle handle of the training session + * @param param_size [out] size of all parameter elements + * @param trainable_only skips non-trainable parameters when true. + * @returns ORT error code. If not zero, call OrtGetLastError() to get detailed error message. + */ +int EMSCRIPTEN_KEEPALIVE OrtTrainingGetParametersSize(ort_training_session_handle_t training_handle, + size_t* param_size, + bool trainable_only); + +/** + * Copy all parameters to a contiguous buffer held by the argument parameters_buffer + * + * User is responsible for allocating and freeing resources used by the parameters_buffer. + * Parameter ordering is preserved. + * + * @param training_handle handle of the training session + * @param parameters_buffer [out] pre-allocated OrtValue buffer to copy onto. Must be same size as results of + * GetParametersSize api call + * @param parameter_count number of parameters expected in the parameters_buffer + * @param trainable_only whether to skip non-trainable parameters + * @returns ORT error code. If not zero, call OrtGetLastError() to get detailed error message. + */ +int EMSCRIPTEN_KEEPALIVE OrtTrainingCopyParametersToBuffer(ort_training_session_handle_t training_handle, + ort_tensor_handle_t parameters_buffer, + size_t parameter_count, + bool trainable_only); + +/** + * Copy parameters values from given contiguous buffer held by parameters_buffer to the training state. + * Parameter ordering is preserved. + * @param training_handle handle of the training session + * @param parameters_buffer OrtValue buffer to copy from. Must be same size as results of + * GetParametersSize api call + * @param parameter_count number of parameters expected in the parameters_buffer + * @param trainable_only whether to skip non-trainable parameters + * @returns ORT error code. If not zero, call OrtGetLastError() to get detailed error message. + */ +int EMSCRIPTEN_KEEPALIVE OrtTrainingCopyParametersFromBuffer(ort_training_session_handle_t training_handle, + ort_tensor_handle_t parameters_buffer, + size_t parameter_count, + bool trainable_only); + +/** + * @brief Release the specified ORT training session. + * + * @param training_session_handle handle of the training session + */ +void EMSCRIPTEN_KEEPALIVE OrtTrainingReleaseSession(ort_training_session_handle_t training_session_handle); + +#endif }; diff --git a/onnxruntime/wasm/js_internal_api.js b/onnxruntime/wasm/js_internal_api.js index 6c2c3522c7db2..15d393f4ce62d 100644 --- a/onnxruntime/wasm/js_internal_api.js +++ b/onnxruntime/wasm/js_internal_api.js @@ -4,13 +4,50 @@ 'use strict'; // init JSEP -Module["jsepInit"] = function (backend, alloc, free, copy, copyAsync, createKernel, releaseKernel, run) { - Module.jsepBackend = backend; - Module.jsepAlloc = alloc; - Module.jsepFree = free; - Module.jsepCopy = copy; - Module.jsepCopyAsync = copyAsync; - Module.jsepCreateKernel = createKernel; - Module.jsepReleaseKernel = releaseKernel; - Module.jsepRun = run; +Module['jsepInit'] = (backend, alloc, free, copy, copyAsync, createKernel, releaseKernel, runKernel) => { + Module.jsepBackend = backend; + Module.jsepAlloc = alloc; + Module.jsepFree = free; + Module.jsepCopy = copy; + Module.jsepCopyAsync = copyAsync; + Module.jsepCreateKernel = createKernel; + Module.jsepReleaseKernel = releaseKernel; + Module.jsepRunKernel = runKernel; + + Module['jsepOnRunStart'] = sessionId => { + Module['jsepRunPromise'] = new Promise(r => { + Module.jsepRunPromiseResolve = r; + }); + + if (Module.jsepSessionState) { + throw new Error('Session already started'); + } + + Module.jsepSessionState = { + sessionId, + errors: [] + }; + }; + + Module['jsepOnRunEnd'] = sessionId => { + if (Module.jsepSessionState.sessionId !== sessionId) { + throw new Error('Session ID mismatch'); + } + + const errorPromises = Module.jsepSessionState.errors; + Module.jsepSessionState = null; + + return errorPromises.length === 0 ? Promise.resolve() : new Promise((resolve, reject) => { + Promise.all(errorPromises).then(errors => { + errors = errors.filter(e => e); + if (errors.length > 0) { + reject(new Error(errors.join('\n'))); + } else { + resolve(); + } + }, reason => { + reject(reason); + }); + }); + }; }; diff --git a/orttraining/orttraining/core/framework/checkpoint_common.cc b/orttraining/orttraining/core/framework/checkpoint_common.cc index d7f4574b4630c..295f17b894095 100644 --- a/orttraining/orttraining/core/framework/checkpoint_common.cc +++ b/orttraining/orttraining/core/framework/checkpoint_common.cc @@ -25,9 +25,16 @@ namespace training { Status CreateOrtValuesFromTensorProtos( const std::vector& tensor_protos, NameMLValMap& name_to_ort_value) { - static const CPUExecutionProviderInfo info; - static const CPUExecutionProvider cpu_provider(info); - static const AllocatorPtr cpu_allocator = cpu_provider.GetAllocator(OrtMemTypeDefault); + bool create_arena = true; +#if defined(USE_JEMALLOC) || defined(USE_MIMALLOC) + // JEMalloc/mimalloc already have memory pool, so just use device allocator. + create_arena = false; +#elif !(defined(__amd64__) || defined(_M_AMD64) || defined(__aarch64__) || defined(_M_ARM64)) + // Disable Arena allocator for x86_32 build because it may run into infinite loop when integer overflow happens + create_arena = false; +#endif + static const AllocatorCreationInfo info{[](int) { return std::make_unique(); }, DEFAULT_CPU_ALLOCATOR_DEVICE_ID, create_arena}; + static const AllocatorPtr cpu_allocator = CreateAllocator(info); for (const auto& tensor_proto : tensor_protos) { TensorShape tensor_shape{utils::GetTensorShapeFromTensorProto(tensor_proto)}; diff --git a/orttraining/orttraining/core/framework/checkpoint_common.h b/orttraining/orttraining/core/framework/checkpoint_common.h index 27cd90390509c..316417829e43b 100644 --- a/orttraining/orttraining/core/framework/checkpoint_common.h +++ b/orttraining/orttraining/core/framework/checkpoint_common.h @@ -16,6 +16,8 @@ namespace onnxruntime { namespace training { +#if !defined(ORT_MINIMAL_BUILD) + /** * @brief Open file descriptor and call use_fn * @@ -45,6 +47,8 @@ common::Status WithOpenFile(const PathString& path, bool readonly, TUseFileFn us return !use_fn_status.IsOK() ? use_fn_status : close_status; } +#endif + /** * @brief Create OrtValues From TensorProto objects * diff --git a/orttraining/orttraining/core/framework/checkpointing.cc b/orttraining/orttraining/core/framework/checkpointing.cc index b367586584eaf..9e1aa8d17e3ee 100644 --- a/orttraining/orttraining/core/framework/checkpointing.cc +++ b/orttraining/orttraining/core/framework/checkpointing.cc @@ -32,15 +32,15 @@ constexpr const PathChar* k_tensors_data_file_name = ORT_TSTR("tensors.bin"); constexpr const PathChar* k_properties_file_name = ORT_TSTR("properties.pbseq"); PathString GetCheckpointTensorsFilePath(const PathString& checkpoint_directory) { - return ConcatPathComponent(checkpoint_directory, k_tensors_file_name); + return ConcatPathComponent(checkpoint_directory, k_tensors_file_name); } PathString GetCheckpointTensorsDataFilePath(const PathString& checkpoint_directory) { - return ConcatPathComponent(checkpoint_directory, k_tensors_data_file_name); + return ConcatPathComponent(checkpoint_directory, k_tensors_data_file_name); } PathString GetCheckpointPropertiesFilePath(const PathString& checkpoint_directory) { - return ConcatPathComponent(checkpoint_directory, k_properties_file_name); + return ConcatPathComponent(checkpoint_directory, k_properties_file_name); } Status SaveRuntimeTensor( diff --git a/orttraining/orttraining/core/framework/gradient_graph_builder.cc b/orttraining/orttraining/core/framework/gradient_graph_builder.cc index c18bbb90661bf..d66591318d5c7 100644 --- a/orttraining/orttraining/core/framework/gradient_graph_builder.cc +++ b/orttraining/orttraining/core/framework/gradient_graph_builder.cc @@ -18,6 +18,44 @@ using namespace ONNX_NAMESPACE; namespace onnxruntime { namespace training { +namespace { + +const std::unordered_set GRAD_ALLOWED_TYPES{ + ONNX_NAMESPACE::TensorProto_DataType_FLOAT, + ONNX_NAMESPACE::TensorProto_DataType_FLOAT16, + ONNX_NAMESPACE::TensorProto_DataType_DOUBLE, + ONNX_NAMESPACE::TensorProto_DataType_BFLOAT16, +}; + +std::tuple IsAllowedForGradient(const Graph* graph, const NodeArg* node_arg) { + // This is a temporary workaround for Send nodes, who output a bool. If we don't allow building gradient for + // it, the PipelineTransformer tests will fail. We should revisit the PipelineTransformer and fix it in a + // better way. (While it might not be a priority for us now.) + bool skip_elem_type_check = false; + const Node* node = graph->GetProducerNode(node_arg->Name()); + if (node && (node->OpType() == "Send")) { + skip_elem_type_check = true; + } + + bool is_tensor_type = false; + bool is_allowed_type_for_grad = false; + const auto* type_proto = node_arg->TypeAsProto(); + int32_t type = -1; + if (nullptr != type_proto && type_proto->value_case() == ONNX_NAMESPACE::TypeProto::kTensorType) { + is_tensor_type = true; + type = type_proto->tensor_type().elem_type(); + + if (skip_elem_type_check) { + is_allowed_type_for_grad = true; + } else { + is_allowed_type_for_grad = GRAD_ALLOWED_TYPES.find(type) != GRAD_ALLOWED_TYPES.end(); + } + } + + return {is_tensor_type, is_allowed_type_for_grad, type}; +} +} // namespace + using namespace common; GradientGraphBuilder::GradientGraphBuilder(Graph* graph, @@ -57,10 +95,13 @@ GradientGraphBuilder::GradientGraphBuilder(Graph* graph, const Node* node = graph_->GetProducerNode(name); if (node) { - if (forward_reachable_nodes.find(node) == forward_reachable_nodes.end()) { + const auto rets = IsAllowedForGradient(graph_, node_arg); + bool is_allowed_type_for_grad = std::get<1>(rets); + if (forward_reachable_nodes.find(node) == forward_reachable_nodes.end() || !is_allowed_type_for_grad) { non_differentiable_y_node_arg_names_.insert(name); LOGS(logger_, INFO) << "The model weights and inputs are non-differentiable from " << name << ". " - << "ORT will assume no gradient will be provided for " << name << "."; + << "ORT will assume no gradient will be provided for " << name + << ", is_allowed_type_for_grad: " << is_allowed_type_for_grad; } else { y_node_args_.insert(node_arg); y_nodes_.insert(node); @@ -164,22 +205,21 @@ NodeSet GradientGraphBuilder::ReverseBFSWithStopGradient(const NodeSet& nodes) c const std::unordered_set* edges = GetStopGradientEdges(*n); for (auto edge_it = n->InputEdgesBegin(); edge_it != n->InputEdgesEnd(); ++edge_it) { if (edges != nullptr && edges->count(edge_it->GetDstArgIndex())) { - LOGS(logger_, INFO) << "Skip building gradient for input_" << edge_it->GetDstArgIndex() - << " of node: " << n->Name(); + LOGS(logger_, VERBOSE) << "Skip building gradient for input_" << edge_it->GetDstArgIndex() + << " of node: " << n->Name(); continue; } const NodeArg* node_arg = n->InputDefs()[edge_it->GetDstArgIndex()]; - const auto* type_proto = node_arg->TypeAsProto(); - if (nullptr != type_proto && type_proto->value_case() == ONNX_NAMESPACE::TypeProto::kTensorType) { - const int32_t type = type_proto->tensor_type().elem_type(); - if (GRAD_ALLOWED_TYPES.find(type) == GRAD_ALLOWED_TYPES.end()) { - LOGS(logger_, INFO) << "Skip building gradient for input_" << edge_it->GetDstArgIndex() - << " of node: " << n->Name() << "because element type is: " << type; + const auto [is_tensor_type, is_allowed_type_for_grad, type] = IsAllowedForGradient(graph_, node_arg); + if (is_tensor_type) { + if (!is_allowed_type_for_grad) { + LOGS(logger_, VERBOSE) << "Skip building gradient for input_" << edge_it->GetDstArgIndex() + << " of node: " << n->Name() << " because element type is: " << type; continue; } } else { - LOGS(logger_, INFO) << "Skip building gradient for input_" << edge_it->GetDstArgIndex() - << " of node: " << n->Name() << "because it is not a Tensor type"; + LOGS(logger_, VERBOSE) << "Skip building gradient for input_" << edge_it->GetDstArgIndex() + << " of node: " << n->Name() << " because it is not a Tensor type"; continue; } @@ -280,12 +320,27 @@ Status GradientGraphBuilder::Build(const std::unordered_set* p_init const std::unordered_set* edges = GetStopGradientEdges(next_node); if (edges != nullptr && edges->count(edge_it->GetDstArgIndex())) { - LOGS(logger_, WARNING) << "Skip building gradient for input_" << edge_it->GetDstArgIndex() + LOGS(logger_, VERBOSE) << "Skip building gradient for input_" << edge_it->GetDstArgIndex() << " of node: " << next_node.Name(); continue; } const NodeArg* node_arg = node->OutputDefs()[edge_it->GetSrcArgIndex()]; + + // Make sure node_arg as input of next_node, has the data type allowed to compute gradient. + const auto [is_tensor_type, is_allowed_type_for_grad, type] = IsAllowedForGradient(graph_, node_arg); + if (is_tensor_type) { + if (!is_allowed_type_for_grad) { + LOGS(logger_, VERBOSE) << "Skip building gradient for input_" << edge_it->GetDstArgIndex() + << " of node: " << next_node.Name() << " because element type is: " << type; + continue; + } + } else { + LOGS(logger_, VERBOSE) << "Skip building gradient for input_" << edge_it->GetDstArgIndex() + << " of node: " << next_node.Name() << " because it is not a Tensor type"; + continue; + } + std::string grad_node_arg_name = GradientBuilderBase::GradientName(node_arg->Name()); pending_[grad_node_arg_name] += 1; diff --git a/orttraining/orttraining/core/framework/gradient_graph_builder.h b/orttraining/orttraining/core/framework/gradient_graph_builder.h index 1552ad8dc5eb9..8068d4825cee3 100644 --- a/orttraining/orttraining/core/framework/gradient_graph_builder.h +++ b/orttraining/orttraining/core/framework/gradient_graph_builder.h @@ -150,19 +150,13 @@ class GradientGraphBuilder { // The 1st and 3rd inputs are not differentiable. std::unordered_map> python_op_input_require_grad_info_; - const std::unordered_set GRAD_ALLOWED_TYPES{ - ONNX_NAMESPACE::TensorProto_DataType_FLOAT, - ONNX_NAMESPACE::TensorProto_DataType_FLOAT16, - ONNX_NAMESPACE::TensorProto_DataType_DOUBLE, - ONNX_NAMESPACE::TensorProto_DataType_BFLOAT16, - }; const std::unordered_set* GetStopGradientEdges(const Node& node) const; /** Performs a BFS on the graph with STOP_GRADIENT_EDGES constrain It will skip traversing over the edges defined in STOP_GRADIENT_EDGES map. The resulting node set contains all the nodes that are differentiable wrt the x_node_args - @param Starting nodes arg name for BFS + @param x_node_arg_names Starting nodes arg name for BFS @returns All the nodes visited during BFS */ NodeSet BFSWithStopGradient(const std::unordered_set& x_node_arg_names) const; @@ -171,14 +165,13 @@ class GradientGraphBuilder { Performs a ReverseBFS on the graph with STOP_GRADIENT_EDGES constrain It will skip traversing over the edges defined in STOP_GRADIENT_EDGES map. The resulting node set contains all the nodes that are differentiable wrt the input nodes - @param Starting nodes for ReverseBFS + @param nodes Starting nodes for ReverseBFS @returns All the nodes visited during ReverseBFS */ NodeSet ReverseBFSWithStopGradient(const NodeSet& nodes) const; /** - Check if 'x_node_args_' are reachable from 'y_node_args_' for computing the partial derivative - @param reachable_nodes All the nodes reachable from the 'y_node_args_' + Check if 'x_node_args_' are reachable from 'y_node_args_' for computing the partial derivative. @returns OK if all 'x_node_args_' are reachable, else an ONNXRUNTIME INVALID_ARGUMENT status */ Status CheckNodeArgsReachable() const; diff --git a/orttraining/orttraining/core/framework/ortmodule_graph_builder.cc b/orttraining/orttraining/core/framework/ortmodule_graph_builder.cc index e4647c58c5629..c5948e563fcf8 100644 --- a/orttraining/orttraining/core/framework/ortmodule_graph_builder.cc +++ b/orttraining/orttraining/core/framework/ortmodule_graph_builder.cc @@ -66,7 +66,8 @@ Status OrtModuleGraphBuilder::Initialize(std::istream& model_istream, // shape info to constants, the optimized graph (before gradient graph building) can not be shared. // So each time we need to start from the beginning, i.e., 1) replace input shapes, 2) apply graph optimizers, // 3) build gradient graph, and finally 4) adjust the graph inputs and outputs. -Status OrtModuleGraphBuilder::Build(const std::vector>* input_shapes_ptr) { +Status OrtModuleGraphBuilder::Build(const TrainingGraphTransformerConfiguration& pre_grad_graph_transformer_config, + const std::vector>* input_shapes_ptr) { // Make a copy of the original model. auto original_model_proto = original_model_->ToProto(); ORT_RETURN_IF_ERROR(Model::Load(original_model_proto, forward_model_, nullptr, *logger_)); @@ -82,9 +83,9 @@ Status OrtModuleGraphBuilder::Build(const std::vector>* inp return Status::OK(); } - // Optimize the inference graph and build the gradient graph. + // Optimize the forward graph and then build the gradient graph. std::unordered_set x_node_arg_names; - ORT_RETURN_IF_ERROR(OptimizeForwardGraph(x_node_arg_names)); + ORT_RETURN_IF_ERROR(OptimizeForwardGraph(pre_grad_graph_transformer_config, x_node_arg_names)); ORT_RETURN_IF_ERROR(BuildGradientGraph(x_node_arg_names)); if (config_.enable_caching) { @@ -147,7 +148,8 @@ Status OrtModuleGraphBuilder::SetConcreteInputShapes(const std::vector& x_node_arg_names) { +Status OrtModuleGraphBuilder::OptimizeForwardGraph(const TrainingGraphTransformerConfiguration& config, + std::unordered_set& x_node_arg_names) { // Resolve original graph, register and apply transformers for pre-training. Graph& forward_graph = forward_model_->MainGraph(); ORT_RETURN_IF_ERROR(forward_graph.Resolve()); @@ -161,7 +163,7 @@ Status OrtModuleGraphBuilder::OptimizeForwardGraph(std::unordered_set(i), *logger_)); } + if (!config.optimized_pre_grad_filepath.empty()) { + ORT_RETURN_IF_ERROR(Model::Save(*forward_model_, config.optimized_pre_grad_filepath)); + } + return Status::OK(); } @@ -303,7 +309,9 @@ void OrtModuleGraphBuilder::HandleOutputsAndGrads() { if (std::find(non_differentiable_indices.begin(), non_differentiable_indices.end(), i) == non_differentiable_indices.end()) { - yield_output_node_args.emplace_back(gradient_graph.GetNodeArg(grad_name)); + NodeArg* grad_node_arg = gradient_graph.GetNodeArg(grad_name); + ORT_ENFORCE(grad_node_arg != nullptr, "Differentiable param grad node arg should exist."); + yield_output_node_args.emplace_back(grad_node_arg); graph_info_.module_output_gradient_name.emplace_back(grad_name); } } @@ -329,9 +337,10 @@ void OrtModuleGraphBuilder::HandleOutputsAndGrads() { attributes.insert({full_shape_outputs_name, full_shape_outputs}); - // Handle potential duplciated output_gradient names + // Handle potential duplicated output_gradient names std::unordered_map> name_to_idx; for (size_t i = 0; i < yield_output_node_args.size(); ++i) { + ORT_ENFORCE(yield_output_node_args[i] != nullptr); const std::string& name = yield_output_node_args[i]->Name(); auto it = name_to_idx.find(name); if (it == name_to_idx.end()) { diff --git a/orttraining/orttraining/core/framework/ortmodule_graph_builder.h b/orttraining/orttraining/core/framework/ortmodule_graph_builder.h index 67b92bb3a362e..95da6817f5c91 100644 --- a/orttraining/orttraining/core/framework/ortmodule_graph_builder.h +++ b/orttraining/orttraining/core/framework/ortmodule_graph_builder.h @@ -29,9 +29,6 @@ struct OrtModuleGraphBuilderConfiguration { bool build_gradient_graph = true; bool enable_caching = false; - // Graph transformer configuration - TrainingGraphTransformerConfiguration graph_transformer_config{}; - // Log severity logging::Severity loglevel{logging::Severity::kWARNING}; }; @@ -81,10 +78,13 @@ class OrtModuleGraphBuilder { /** * Optimize the inference graph and build the gradient graph. + * @param pre_grad_graph_transformer_config The configuration to control the graph transformers before gradient + * graph is built. * @param input_shapes_ptr The pointer to vector of concrete shapes of the user inputs. * @return The status of the optimizing and building the gradient graph. */ - Status Build(const std::vector>* input_shapes_ptr = nullptr); + Status Build(const TrainingGraphTransformerConfiguration& pre_grad_graph_transformer_config, + const std::vector>* input_shapes_ptr = nullptr); /** * Get gradient model. @@ -109,7 +109,8 @@ class OrtModuleGraphBuilder { Status SetConcreteInputShapes(const std::vector>& input_shapes); // Apply graph transformers - Status OptimizeForwardGraph(std::unordered_set& x_node_arg_names); + Status OptimizeForwardGraph(const TrainingGraphTransformerConfiguration& config, + std::unordered_set& x_node_arg_names); // Build gradient graph. Status BuildGradientGraph(const std::unordered_set& x_node_arg_names); diff --git a/orttraining/orttraining/core/framework/tensorboard/event_writer.cc b/orttraining/orttraining/core/framework/tensorboard/event_writer.cc index f1d57bb01e6ac..9c0c351aeee7f 100644 --- a/orttraining/orttraining/core/framework/tensorboard/event_writer.cc +++ b/orttraining/orttraining/core/framework/tensorboard/event_writer.cc @@ -2,6 +2,8 @@ // Licensed under the MIT License. #include "orttraining/core/framework/tensorboard/event_writer.h" + +#include "onnxruntime_config.h" #include "orttraining/core/framework/tensorboard/crc32c.h" #include "core/platform/env.h" @@ -13,6 +15,9 @@ #if defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" +#if defined(HAS_SHORTEN_64_TO_32) +#pragma GCC diagnostic ignored "-Wshorten-64-to-32" +#endif #endif #include "tensorboard/compat/proto/event.pb.h" #if defined(__GNUC__) diff --git a/orttraining/orttraining/core/framework/torch/torch_proxy.cc b/orttraining/orttraining/core/framework/torch/torch_proxy.cc index 3bdcc85fb0651..377f564a00337 100644 --- a/orttraining/orttraining/core/framework/torch/torch_proxy.cc +++ b/orttraining/orttraining/core/framework/torch/torch_proxy.cc @@ -53,7 +53,7 @@ void Ort_PyList_SetItem_NoIncref(PyObject* py_list, size_t index, PyObject* item void CheckArguments( const size_t len, const std::vector& requires_grads, - const std::vector& tensor_args, + const std::vector>& tensor_args, const std::vector& tensor_indices, const std::vector obj_args, const std::vector& obj_indices) { @@ -192,18 +192,19 @@ PythonObjectPtr CreatePythonCallArguments( PyObject* callback, const size_t len, const std::vector& requires_grads, - const std::vector& tensor_args, + const std::vector>& tensor_args, const std::vector& tensor_indices, const std::vector& obj_args, const std::vector& obj_indices, const bool is_training_mode, - const bool is_inplace) { + const bool is_inplace, + const std::string& invoke_id) { ORT_ENFORCE(PyCallable_Check(callback), "Forward callback is not callable."); // The number of variables before those of // autograd.Function.apply and autograd.Function.backward. // The extra variables are used to configure the launch // forward and backward runners. - constexpr int64_t num_control_args = 5; + constexpr int64_t num_control_args = 6; // All arguments created for Python call will be destroyed along with PythonObjectPtr. PythonObjectPtr args(Ort_PyTuple_New(num_control_args + len, "forward_arguments_tuple"), PythonObjectDeleter); @@ -217,11 +218,19 @@ PythonObjectPtr CreatePythonCallArguments( Ort_PyTuple_SetItem_Incref(args.get(), 3, is_training_mode_arg, "is_training_mode"); PyObject* is_inplace_arg = is_inplace ? Py_True : Py_False; Ort_PyTuple_SetItem_Incref(args.get(), 4, is_inplace_arg, "is_inplace_mode"); + PyObject* kernel_invoke_id_arg = PyBytes_FromStringAndSize(invoke_id.c_str(), invoke_id.size()); + Ort_PyTuple_SetItem_NoIncref(args.get(), 5, kernel_invoke_id_arg, "kernel_invoke_id_arg"); // Tensor inputs to call autograd.Function.apply or autograd.Function.backward. for (size_t i = 0; i < tensor_args.size(); ++i) { + if (!tensor_args[i].has_value()) { + Ort_PyTuple_SetItem_Incref(args.get(), num_control_args + tensor_indices[i], Py_None, + "non_tensor_args"); + continue; + } + // Wrap with DLPack, then transfer to Python for its release. - PyObject* dl_tensor = training::framework::torch::ToDlpack(tensor_args[i]); + PyObject* dl_tensor = training::framework::torch::ToDlpack(tensor_args[i].value()); Ort_PyTuple_SetItem_NoIncref(args.get(), num_control_args + tensor_indices[i], dl_tensor, "dltensor"); } @@ -240,14 +249,15 @@ void Invoke( PyObject* runner, PyObject* callback, const std::vector& requires_grads, - const std::vector& tensor_args, + const std::vector>& tensor_args, const std::vector& tensor_indices, const std::vector& obj_args, const std::vector& obj_indices, void** diff_ctx, std::vector& returned_ortvalues, const bool is_training_mode, - const bool is_inplace) { + const bool is_inplace, + const std::string& invoke_id) { const auto len = tensor_args.size() + obj_args.size(); CheckArguments(len, requires_grads, tensor_args, tensor_indices, obj_args, obj_indices); RefCountTracker::GetInstance().Reset(); @@ -261,7 +271,8 @@ void Invoke( obj_args, obj_indices, is_training_mode, - is_inplace); + is_inplace, + invoke_id); RefCountTracker::GetInstance().DumpDetails("Before Invoke Python Call"); InvokeRunner(runner, args.get(), is_training_mode, diff_ctx, returned_ortvalues); @@ -273,14 +284,15 @@ void Invoke( void TorchProxy::Forward( void* callback, const std::vector& requires_grads, - const std::vector& tensor_args, + const std::vector>& tensor_args, const std::vector& tensor_indices, const std::vector& obj_args, const std::vector& obj_indices, void** diff_ctx, std::vector& returned_ortvalues, const bool is_training_mode, - const bool is_inplace) { + const bool is_inplace, + const std::string& invoke_id) { // Semantically, this lock uniquely takes the ownership of TorchProxy // so that there will be only one of TorchProxy::Forward TorchProxy::Backward // can be run at one time. @@ -299,17 +311,19 @@ void TorchProxy::Forward( diff_ctx, returned_ortvalues, is_training_mode, - is_inplace); + is_inplace, + invoke_id); } void TorchProxy::Backward( void* callback, - const std::vector& tensor_args, + const std::vector>& tensor_args, const std::vector& tensor_indices, const std::vector& obj_args, const std::vector& obj_indices, std::vector& returned_ortvalues, - const bool is_inplace) { + const bool is_inplace, + const std::string& invoke_id) { // Semantically, this lock uniquely takes the ownership of TorchProxy // so that there will be only one of TorchProxy::Forward TorchProxy::Backward // can be run at one time. @@ -332,7 +346,8 @@ void TorchProxy::Backward( nullptr /* context to store */, returned_ortvalues, true /* is_training_mode */, - is_inplace); + is_inplace, + invoke_id); } } // namespace torch } // namespace language_interop_ops diff --git a/orttraining/orttraining/core/framework/torch/torch_proxy.h b/orttraining/orttraining/core/framework/torch/torch_proxy.h index b83a3c553a639..189efc772a62c 100644 --- a/orttraining/orttraining/core/framework/torch/torch_proxy.h +++ b/orttraining/orttraining/core/framework/torch/torch_proxy.h @@ -3,6 +3,7 @@ #pragma once #include +#include #include "orttraining/core/framework/torch/python_common.h" #ifndef SHARED_PROVIDER @@ -38,23 +39,25 @@ class TorchProxy { void Forward( void* callback, const std::vector& requires_grads, - const std::vector& tensor_args, + const std::vector>& tensor_args, const std::vector& tensor_indices, const std::vector& obj_args, const std::vector& obj_indices, void** diff_ctx, std::vector& returned_ortvalues, const bool is_training_mode, - const bool is_inplace); + const bool is_inplace, + const std::string& invoke_id); void Backward( void* callback, - const std::vector& tensor_args, + const std::vector>& tensor_args, const std::vector& tensor_indices, const std::vector& obj_args, const std::vector& obj_indices, std::vector& return_args, - const bool is_inplace); + const bool is_inplace, + const std::string& invoke_id); private: TorchProxy(){}; diff --git a/orttraining/orttraining/core/framework/triton/triton_op_executor.cc b/orttraining/orttraining/core/framework/triton/triton_op_executor.cc new file mode 100644 index 0000000000000..092ab89d5d760 --- /dev/null +++ b/orttraining/orttraining/core/framework/triton/triton_op_executor.cc @@ -0,0 +1,132 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "orttraining/core/framework/triton/triton_op_executor.h" + +#include "orttraining/core/framework/torch/dlpack_python.h" +#include "orttraining/core/framework/torch/gil.h" + +namespace onnxruntime { +namespace training { +namespace framework { +namespace triton { + +namespace { +void PythonObjectDeleter(PyObject* ptr) { Py_XDECREF(ptr); } +} // namespace + +void TritonOpExecutor::Initialize(PyObject* config_getter, PyObject* executor_by_name, PyObject* executor_by_onnx) { + ORT_ENFORCE(config_getter_.get() == nullptr && config_getter != nullptr && executor_by_name_.get() == nullptr && + executor_by_name != nullptr && executor_by_onnx_.get() == nullptr && executor_by_onnx != nullptr); + Py_INCREF(config_getter); + Py_INCREF(executor_by_name); + Py_INCREF(executor_by_onnx); + PythonObjectPtr config_getter_ptr(config_getter, PythonObjectDeleter); + config_getter_ = std::move(config_getter_ptr); + PythonObjectPtr executor_by_name_ptr(executor_by_name, PythonObjectDeleter); + executor_by_name_ = std::move(executor_by_name_ptr); + PythonObjectPtr executor_by_onnx_ptr(executor_by_onnx, PythonObjectDeleter); + executor_by_onnx_ = std::move(executor_by_onnx_ptr); +} + +std::string TritonOpExecutor::GetConfigJson() { + ORT_ENFORCE(IsInitialized()); + // Python-related calls should happen only if guard is alive. + GilGuard guard; + PythonObjectPtr ret(PyObject_CallObject(config_getter_.get(), nullptr), PythonObjectDeleter); + char* buffer = nullptr; + Py_ssize_t length; + buffer = const_cast(PyUnicode_AsUTF8AndSize(ret.get(), &length)); + return std::string(buffer, length); +} + +void TritonOpExecutor::ExecuteByOnnx(int64_t onnx_key, const std::string& onnx_string, + const InlinedVector& inputs, InlinedVector& outputs, + const InlinedHashSet& bool_outputs) { + ORT_ENFORCE(IsInitialized()); + // Python-related calls should happen only if guard is alive. + GilGuard guard; + PythonObjectPtr args(PyTuple_New(static_cast(2 + inputs.size())), PythonObjectDeleter); + ORT_ENFORCE(args, "Failed to create args."); + PyTuple_SetItem(args.get(), 0, PyLong_FromLongLong(static_cast(onnx_key))); + PyTuple_SetItem(args.get(), 1, PyBytes_FromStringAndSize(onnx_string.c_str(), onnx_string.size())); + for (size_t i = 0; i < inputs.size(); ++i) { + if (!inputs[i]) { + PyTuple_SetItem(args.get(), static_cast(2 + i), Py_None); + Py_INCREF(Py_None); + } else { + PyTuple_SetItem(args.get(), static_cast(2 + i), torch::ToDlpack(*inputs[i])); + } + } + + PythonObjectPtr ret(PyObject_CallObject(executor_by_onnx_.get(), args.get()), PythonObjectDeleter); + if (ret == nullptr) { + PyErr_Print(); + ORT_THROW("Python function execution fails with the above information."); + } + ORT_ENFORCE(ret.get() != Py_None); + if (PyTuple_Check(ret.get())) { + for (size_t i = 0; i < static_cast(PyTuple_Size(ret.get())); ++i) { + outputs.emplace_back(torch::FromDlpack(PyTuple_GetItem(ret.get(), static_cast(i)), + bool_outputs.find(i) != bool_outputs.end())); + } + } else { + outputs.emplace_back(torch::FromDlpack(ret.get(), bool_outputs.find(0) != bool_outputs.end())); + } +} + +void TritonOpExecutor::ExecuteByFuncName(const std::string& func_name, const InlinedVector& inputs, + InlinedVector& outputs, const InlinedHashSet& bool_outputs, + const InlinedHashMap>& kwargs) { + ORT_ENFORCE(IsInitialized()); + // Python-related calls should happen only if guard is alive. + GilGuard guard; + PythonObjectPtr args(PyTuple_New(static_cast(1 + inputs.size())), PythonObjectDeleter); + ORT_ENFORCE(args, "Failed to create args."); + PyTuple_SetItem(args.get(), 0, PyUnicode_FromString(func_name.c_str())); + for (size_t i = 0; i < inputs.size(); ++i) { + if (!inputs[i]) { + PyTuple_SetItem(args.get(), static_cast(1 + i), Py_None); + Py_INCREF(Py_None); + } else { + PyTuple_SetItem(args.get(), static_cast(1 + i), torch::ToDlpack(*inputs[i])); + } + } + + PythonObjectPtr python_kwargs(PyDict_New(), PythonObjectDeleter); + ORT_ENFORCE(python_kwargs, "Failed to create kwargs."); + for (const auto& kv : kwargs) { + if (kv.second.second == ONNX_NAMESPACE::TensorProto_DataType_BOOL) { + std::string bool_str = kv.second.first; + std::transform(bool_str.begin(), bool_str.end(), bool_str.begin(), + [](unsigned char c) { return std::tolower(c); }); + int bool_value = bool_str == "" || bool_str == "false" || bool_str == "0" ? 0 : 1; + PyDict_SetItemString(python_kwargs.get(), kv.first.c_str(), PyBool_FromLong(bool_value)); + } else if (kv.second.second == ONNX_NAMESPACE::TensorProto_DataType_INT64) { + PyDict_SetItemString(python_kwargs.get(), kv.first.c_str(), PyLong_FromLongLong(std::stoll(kv.second.first))); + } else if (kv.second.second == ONNX_NAMESPACE::TensorProto_DataType_FLOAT) { + PyDict_SetItemString(python_kwargs.get(), kv.first.c_str(), PyFloat_FromDouble(std::stod(kv.second.first))); + } else { + ORT_THROW("Unsupported kwargs data type: ", kv.second.second); + } + } + PythonObjectPtr ret(PyObject_Call(executor_by_name_.get(), args.get(), python_kwargs.get()), PythonObjectDeleter); + if (ret == nullptr) { + PyErr_Print(); + ORT_THROW("Python function execution fails with the above information."); + } + if (ret.get() == Py_None) return; + if (PyTuple_Check(ret.get())) { + for (size_t i = 0; i < static_cast(PyTuple_Size(ret.get())); ++i) { + outputs.emplace_back(torch::FromDlpack(PyTuple_GetItem(ret.get(), static_cast(i)), + bool_outputs.find(i) != bool_outputs.end())); + } + } else { + outputs.emplace_back(torch::FromDlpack(ret.get(), bool_outputs.find(0) != bool_outputs.end())); + } +} + +} // namespace triton +} // namespace framework +} // namespace training +} // namespace onnxruntime diff --git a/orttraining/orttraining/core/framework/triton/triton_op_executor.h b/orttraining/orttraining/core/framework/triton/triton_op_executor.h new file mode 100644 index 0000000000000..7d79def2b6e7d --- /dev/null +++ b/orttraining/orttraining/core/framework/triton/triton_op_executor.h @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/common/inlined_containers.h" +#include "orttraining/core/framework/torch/python_common.h" + +#ifndef SHARED_PROVIDER +#include "core/framework/ort_value.h" +#endif + +namespace onnxruntime { +namespace training { +namespace framework { +namespace triton { + +using PythonObjectPtr = std::unique_ptr>; + +class TritonOpExecutor final { + public: + static TritonOpExecutor& Instance() { + static TritonOpExecutor instance; + return instance; + } + + void Initialize(PyObject* config_getter, PyObject* executor_by_name, PyObject* executor_by_onnx); + + bool IsInitialized() { + return config_getter_.get() != nullptr && executor_by_name_.get() != nullptr && executor_by_onnx_.get() != nullptr; + } + + std::string GetConfigJson(); + + // Execute ONNX graph by codegening, compiling and executing Triton kernels. + void ExecuteByOnnx(int64_t onnx_key, const std::string& onnx_string, const InlinedVector& inputs, + InlinedVector& outputs, const InlinedHashSet& bool_outputs = {}); + + // Execute existing Triton kernel by Python function name. + void ExecuteByFuncName(const std::string& func_name, const InlinedVector& inputs, + InlinedVector& outputs, const InlinedHashSet& bool_outputs = {}, + const InlinedHashMap>& kwargs = {}); + + private: + PythonObjectPtr config_getter_; + PythonObjectPtr executor_by_name_; + PythonObjectPtr executor_by_onnx_; +}; + +} // namespace triton +} // namespace framework +} // namespace training +} // namespace onnxruntime diff --git a/orttraining/orttraining/core/graph/gradient_builder.cc b/orttraining/orttraining/core/graph/gradient_builder.cc index 512dfb203580c..a14f849958fa7 100755 --- a/orttraining/orttraining/core/graph/gradient_builder.cc +++ b/orttraining/orttraining/core/graph/gradient_builder.cc @@ -6,6 +6,7 @@ #include #include #include +#include #include "onnx/defs/attr_proto_util.h" #include "onnx/defs/tensor_proto_util.h" @@ -752,6 +753,17 @@ IMPLEMENT_GRADIENT_BUILDER(GetGatherGradient) { SrcNodeAttributes())}; } +IMPLEMENT_GRADIENT_BUILDER(GetPadAndUnflattenGradient) { + return std::vector{ + NodeDef(OpDef("Reshape"), + {GO(0), O(1)}, + {IA("GO_reshaped")}), + NodeDef(OpDef{"Gather", kOnnxDomain, 1}, + {IA("GO_reshaped"), I(1)}, + {GI(0)}, + SrcNodeAttributes())}; +} + IMPLEMENT_GRADIENT_BUILDER(GetShrunkenGatherGradient) { return std::vector{ NodeDef("Shape", @@ -1749,8 +1761,9 @@ IMPLEMENT_GRADIENT_BUILDER(GetPythonOpGradient) { std::vector result; auto src_attrs = SrcNodeAttributes(); std::vector attrs; - ORT_ENFORCE(utils::HasString(src_attrs.at("name"))); - attrs.push_back(MakeAttribute("name", src_attrs.at("name").s())); + ORT_ENFORCE(src_attrs.count("func_name") > 0, "func_name attribute is missing."); + ORT_ENFORCE(utils::HasString(src_attrs.at("func_name"))); + attrs.push_back(MakeAttribute("func_name", src_attrs.at("func_name").s())); attrs.push_back(MakeAttribute("output_convention", src_attrs.at("input_convention").s())); attrs.push_back(MakeAttribute("inplace", src_attrs.at("inplace").i())); @@ -1983,5 +1996,149 @@ IMPLEMENT_GRADIENT_BUILDER(GetLSTMGradient) { return {NodeDef(OpDef{"LSTMGrad", kMSDomain, 1}, input_args, output_args, SrcNodeAttributes())}; } +IMPLEMENT_GRADIENT_BUILDER(GetGRUGradient) { + std::vector input_args; + + // Add inputs of the GRUTraining node as inputs of the GRUGrad node + // Add inputs from the source node for X, W, R, B, SL, H0 + // Add empty argdef for non existing inputs + for (int i = 0; i < GetSrcNodeInputSize(); i++) { + if (I(i).Exists()) { + input_args.push_back(I(i)); + } else { + input_args.push_back(ArgDef()); + } + } + + ORT_ENFORCE(GetSrcNodeOutputSize() >= 3, + "GRUTraining node must generate the outputs all hidden states (index 0), " + "and zrh gate copmutations (index 2) so that gradients can be computed."); + + if (O(0).Exists()) { + input_args.push_back(O(0)); // all hidden states output of the GRUTraining node + } else { + input_args.push_back(ArgDef()); + } + + if (O(2).Exists()) { + input_args.push_back(O(2)); // z, r, h gate computations output of the GRUTraining node + } else { + input_args.push_back(ArgDef()); + } + + // Add gradients of the outputs of the GRUTraining node as inputs to the GRUGrad node + // Gradients of the outputs of the GRUTraining node include grad_HAll, grad_HFinal + for (int o = 0; o < 2; ++o) { + if (GO(o).Exists() && IsGradientAvailableForSrcNodeOutput(o)) { + input_args.push_back(GO(o)); + } else { + input_args.push_back(ArgDef()); + } + } + + // Add gradients of the GRUTraining inputs as outputs of the GRUGrad node + // Outputs are gradients of: + // 1) X (input tensor) + // 2) W (weight tensor) + // 3) R (recurrence weight tensor) + // 4) B (bias tensor) + // 5) H0 (initial hidden state tensor) + std::vector output_args; + constexpr int sequence_length_input_index = 4; + for (int i = 0; i < GetSrcNodeInputSize(); ++i) { + if (sequence_length_input_index == i) continue; + if (I(i).Exists() && IsGradientRequiredForSrcNodeInput(i)) { + output_args.push_back(GI(i)); + } else { + output_args.push_back(ArgDef()); + } + } + + return {NodeDef(OpDef{"GRUGrad", kMSDomain, 1}, input_args, output_args, SrcNodeAttributes())}; +} + +IMPLEMENT_GRADIENT_BUILDER(GetReciprocalGradient) { + // y = 1 / x + // dy/dx = -1 / x^2 + // dL/dx = dL/dy * dy/dx = dL/dy * (-1 / x^2) + return {NodeDef("Mul", {O(0), O(0)}, {IA("Square_O0")}), + NodeDef("Neg", {IA("Square_O0")}, {IA("Neg_Square_O0")}), + NodeDef("Mul", {GO(0), IA("Neg_Square_O0")}, {GI(0)})}; +} + +IMPLEMENT_GRADIENT_BUILDER(GetLeakyReluGradient) { + return {NodeDef(OpDef{"LeakyReluGrad", kMSDomain, 1}, + {GO(0), O(0)}, {GI(0)}, SrcNodeAttributes())}; +} + +IMPLEMENT_GRADIENT_BUILDER(GetConvTransposeGradient) { + std::vector outputs; + for (int i = 0; i < GetSrcNodeInputSize(); i++) { + if (IsGradientRequiredForSrcNodeInput(i)) { + outputs.push_back(GI(i)); + } else { + outputs.push_back(ArgDef("", nullptr)); + } + } + + return std::vector{ + NodeDef(OpDef{"ConvTransposeGrad", kMSDomain, 1}, + {GO(0), I(0), I(1)}, + outputs, + SrcNodeAttributes())}; +} + +IMPLEMENT_GRADIENT_BUILDER(GetScaledSumGradient) { + int input_count = GetSrcNodeInputSize(); + auto attributes = SrcNodeAttributes(); + float scale_0 = attributes.at("scale_0").f(); + float scale_1 = attributes.at("scale_1").f(); + if (input_count == 2) { + if (scale_0 == scale_1) { + // Specialized branch to avoid duplicated data write. + NodeDef scale_node = ConstantScalarNode(scale_0, Name("Scale"), IElemType(0)); + return std::vector{ + scale_node, + NodeDef(OpDef{"Mul"}, + {GO(0), scale_node.output_args[0]}, + {GI(0)}), + NodeDef(OpDef{"Identity"}, + {GI(0)}, + {GI(1)})}; + } else { + return std::vector{ + NodeDef(OpDef{"BatchScale", kMSDomain, 1}, + {GO(0)}, + {GI(0), GI(1)}, + SrcNodeAttributes())}; + } + } else if (input_count == 3) { + float scale_2 = attributes.at("scale_2").f(); + if (scale_0 == scale_1 && scale_1 == scale_2) { + // Specialized branch to avoid duplicated data write. + NodeDef scale_node = ConstantScalarNode(scale_0, Name("Scale"), IElemType(0)); + return std::vector{ + scale_node, + NodeDef(OpDef{"Mul"}, + {GO(0), scale_node.output_args[0]}, + {GI(0)}), + NodeDef(OpDef{"Identity"}, + {GI(0)}, + {GI(1)}), + NodeDef(OpDef{"Identity"}, + {GI(0)}, + {GI(2)})}; + } else { + return std::vector{ + NodeDef(OpDef{"BatchScale", kMSDomain, 1}, + {GO(0)}, + {GI(0), GI(1), GI(2)}, + SrcNodeAttributes())}; + } + } + + ORT_THROW("ScaledSum gradient builder does not support ", input_count, " inputs"); +} + } // namespace training } // namespace onnxruntime diff --git a/orttraining/orttraining/core/graph/gradient_builder.h b/orttraining/orttraining/core/graph/gradient_builder.h index 156ed7f8c827b..a517e8af13fcc 100755 --- a/orttraining/orttraining/core/graph/gradient_builder.h +++ b/orttraining/orttraining/core/graph/gradient_builder.h @@ -39,6 +39,7 @@ DECLARE_GRADIENT_BUILDER(GetPoolGradient) DECLARE_GRADIENT_BUILDER(GetAveragePoolGradient) DECLARE_GRADIENT_BUILDER(GetMaxPoolGradient) DECLARE_GRADIENT_BUILDER(GetGatherGradient) +DECLARE_GRADIENT_BUILDER(GetPadAndUnflattenGradient) DECLARE_GRADIENT_BUILDER(GetShrunkenGatherGradient) DECLARE_GRADIENT_BUILDER(GetConvGradient) DECLARE_GRADIENT_BUILDER(GetUnsqueezeGradient) @@ -84,6 +85,11 @@ DECLARE_GRADIENT_BUILDER(GetScatterElementsGradient) DECLARE_GRADIENT_BUILDER(GetTriluGradient) DECLARE_GRADIENT_BUILDER(GetFakeQuantGradient) DECLARE_GRADIENT_BUILDER(GetLSTMGradient) +DECLARE_GRADIENT_BUILDER(GetScaledSumGradient) +DECLARE_GRADIENT_BUILDER(GetGRUGradient) +DECLARE_GRADIENT_BUILDER(GetReciprocalGradient) +DECLARE_GRADIENT_BUILDER(GetLeakyReluGradient) +DECLARE_GRADIENT_BUILDER(GetConvTransposeGradient) DECLARE_GRADIENT_BUILDER(GetExternalGradient) diff --git a/orttraining/orttraining/core/graph/gradient_builder_base.cc b/orttraining/orttraining/core/graph/gradient_builder_base.cc index d3b9faa8637ca..d57675e8b8e20 100644 --- a/orttraining/orttraining/core/graph/gradient_builder_base.cc +++ b/orttraining/orttraining/core/graph/gradient_builder_base.cc @@ -392,7 +392,7 @@ AttributeProto GradientBuilderBase::AttributeDefinitionToAttributeProto( elem_type == ONNX_NAMESPACE::TensorProto_DataType_BFLOAT16); float float_value = value.get(); if (elem_type == ONNX_NAMESPACE::TensorProto_DataType_FLOAT16) { - tensor_proto = ScalarTensorProto(MLFloat16(math::floatToHalf(float_value)), {1}); + tensor_proto = ScalarTensorProto(MLFloat16(float_value), {1}); } else if (elem_type == ONNX_NAMESPACE::TensorProto_DataType_BFLOAT16) { tensor_proto = ScalarTensorProto(BFloat16(float_value), {1}); } else { diff --git a/orttraining/orttraining/core/graph/gradient_builder_base.h b/orttraining/orttraining/core/graph/gradient_builder_base.h index c54d862a41021..2d8a87f6d4427 100644 --- a/orttraining/orttraining/core/graph/gradient_builder_base.h +++ b/orttraining/orttraining/core/graph/gradient_builder_base.h @@ -5,6 +5,7 @@ #include #include +#include "core/framework/float8.h" #include "core/framework/float16.h" #include "core/graph/graph.h" #include "core/util/math.h" @@ -261,25 +262,72 @@ class GradientBuilderBase { // We only support FP32, FP16 and BF16 for these constant nodes for now. static NodeDef ConstantScalarNode(float value, const std::string& arg_name, int elem_type) { if (elem_type == ONNX_NAMESPACE::TensorProto_DataType_FLOAT16) { - return ConstantScalarNode(MLFloat16(math::floatToHalf(value)), {1}, arg_name); + return ConstantScalarNode(MLFloat16(value), {1}, arg_name); } if (elem_type == ONNX_NAMESPACE::TensorProto_DataType_BFLOAT16) { return ConstantScalarNode(BFloat16(value), {1}, arg_name); } + if (elem_type == ONNX_NAMESPACE::TensorProto_DataType_DOUBLE) { + return ConstantScalarNode(double(value), {1}, arg_name); + } + +#if !defined(DISABLE_FLOAT8_TYPES) + + if (elem_type == ONNX_NAMESPACE::TensorProto_DataType_FLOAT8E4M3FN) { + return ConstantScalarNode(Float8E4M3FN(value, true), {1}, arg_name); + } + + if (elem_type == ONNX_NAMESPACE::TensorProto_DataType_FLOAT8E4M3FNUZ) { + return ConstantScalarNode(Float8E4M3FNUZ(value, true), {1}, arg_name); + } + + if (elem_type == ONNX_NAMESPACE::TensorProto_DataType_FLOAT8E5M2) { + return ConstantScalarNode(Float8E5M2(value, true), {1}, arg_name); + } + + if (elem_type == ONNX_NAMESPACE::TensorProto_DataType_FLOAT8E5M2FNUZ) { + return ConstantScalarNode(Float8E5M2FNUZ(value, true), {1}, arg_name); + } + +#endif + + ORT_ENFORCE(elem_type == ONNX_NAMESPACE::TensorProto_DataType_FLOAT, + "Unsupported element type for constant node: ", elem_type); + return ConstantScalarNode(value, {1}, arg_name); } static ONNX_NAMESPACE::TensorProto ScalarTensorProtoByElemType(float value, int elem_type) { if (elem_type == ONNX_NAMESPACE::TensorProto_DataType_FLOAT16) { - return ScalarTensorProto(MLFloat16(math::floatToHalf(value)), {1}); + return ScalarTensorProto(MLFloat16(value), {1}); } if (elem_type == ONNX_NAMESPACE::TensorProto_DataType_BFLOAT16) { return ScalarTensorProto(BFloat16(value), {1}); } +#if !defined(DISABLE_FLOAT8_TYPES) + + if (elem_type == ONNX_NAMESPACE::TensorProto_DataType_FLOAT8E4M3FN) { + return ScalarTensorProto(Float8E4M3FN(value, true), {1}); + } + + if (elem_type == ONNX_NAMESPACE::TensorProto_DataType_FLOAT8E4M3FNUZ) { + return ScalarTensorProto(Float8E4M3FNUZ(value, true), {1}); + } + + if (elem_type == ONNX_NAMESPACE::TensorProto_DataType_FLOAT8E5M2) { + return ScalarTensorProto(Float8E5M2(value, true), {1}); + } + + if (elem_type == ONNX_NAMESPACE::TensorProto_DataType_FLOAT8E5M2FNUZ) { + return ScalarTensorProto(Float8E5M2FNUZ(value, true), {1}); + } + +#endif + return ScalarTensorProto(value, {1}); } diff --git a/orttraining/orttraining/core/graph/gradient_builder_registry.cc b/orttraining/orttraining/core/graph/gradient_builder_registry.cc index 51a7c75ef61ac..4062b5d097394 100755 --- a/orttraining/orttraining/core/graph/gradient_builder_registry.cc +++ b/orttraining/orttraining/core/graph/gradient_builder_registry.cc @@ -70,6 +70,7 @@ void GradientBuilderRegistry::RegisterGradientBuilders() { REGISTER_GRADIENT_BUILDER("Gemm", GetGemmGradient); REGISTER_GRADIENT_BUILDER("MaxPool", GetMaxPoolGradient); REGISTER_GRADIENT_BUILDER("Gather", GetGatherGradient); + REGISTER_GRADIENT_BUILDER("PadAndUnflatten", GetPadAndUnflattenGradient); REGISTER_GRADIENT_BUILDER("ShrunkenGather", GetShrunkenGatherGradient); REGISTER_GRADIENT_BUILDER("Conv", GetConvGradient); REGISTER_GRADIENT_BUILDER("Squeeze", GetSqueezeGradient); @@ -116,6 +117,11 @@ void GradientBuilderRegistry::RegisterGradientBuilders() { REGISTER_GRADIENT_BUILDER("Trilu", GetTriluGradient); REGISTER_GRADIENT_BUILDER("FakeQuant", GetFakeQuantGradient); REGISTER_GRADIENT_BUILDER("LSTMTraining", GetLSTMGradient); + REGISTER_GRADIENT_BUILDER("ScaledSum", GetScaledSumGradient); + REGISTER_GRADIENT_BUILDER("GRUTraining", GetGRUGradient); + REGISTER_GRADIENT_BUILDER("Reciprocal", GetReciprocalGradient); + REGISTER_GRADIENT_BUILDER("LeakyRelu", GetLeakyReluGradient); + REGISTER_GRADIENT_BUILDER("ConvTranspose", GetConvTransposeGradient); REGISTER_GRADIENT_BUILDER("ExternalGradient", GetExternalGradient); }; diff --git a/orttraining/orttraining/core/graph/optimizer/adam_optimizer_builder.cc b/orttraining/orttraining/core/graph/optimizer/adam_optimizer_builder.cc index 4b44e2f62a0a9..f480e080e8ffd 100644 --- a/orttraining/orttraining/core/graph/optimizer/adam_optimizer_builder.cc +++ b/orttraining/orttraining/core/graph/optimizer/adam_optimizer_builder.cc @@ -97,7 +97,7 @@ Status AdamOptimizerBuilder::Build( ORT_THROW_IF_ERROR(IsMatchingTypeAndShape(init_tensor, element_type, weight_dims)); moment_tensor_proto = utils::TensorToTensorProto(init_tensor, gradient_moment_name); } else if (opt_configs[i].use_mixed_precision_moments) { - moment_tensor_proto = CreateTensorProto(gradient_moment_name, MLFloat16(math::floatToHalf(0.f)), weight_dims); + moment_tensor_proto = CreateTensorProto(gradient_moment_name, MLFloat16(0.f), weight_dims); } else { moment_tensor_proto = CreateTensorProto(gradient_moment_name, 0.f, weight_dims); } diff --git a/orttraining/orttraining/core/graph/optimizer/lamb_optimizer_builder.cc b/orttraining/orttraining/core/graph/optimizer/lamb_optimizer_builder.cc index d48a1b741d70f..9921b135426ec 100644 --- a/orttraining/orttraining/core/graph/optimizer/lamb_optimizer_builder.cc +++ b/orttraining/orttraining/core/graph/optimizer/lamb_optimizer_builder.cc @@ -231,7 +231,7 @@ Status LambOptimizerBuilder::Build( ORT_THROW_IF_ERROR(IsMatchingTypeAndShape(init_tensor, element_type, weight_dims)); moment_tensor_proto = utils::TensorToTensorProto(init_tensor, gradient_moment_name); } else if (opt_configs[i].use_mixed_precision_moments) { - moment_tensor_proto = CreateTensorProto(gradient_moment_name, MLFloat16(math::floatToHalf(0.f)), weight_dims); + moment_tensor_proto = CreateTensorProto(gradient_moment_name, MLFloat16(0.f), weight_dims); } else { moment_tensor_proto = CreateTensorProto(gradient_moment_name, 0.f, weight_dims); } diff --git a/orttraining/orttraining/core/graph/training_op_defs.cc b/orttraining/orttraining/core/graph/training_op_defs.cc index 7b7d5100f4f23..91b1df7b7cf2d 100644 --- a/orttraining/orttraining/core/graph/training_op_defs.cc +++ b/orttraining/orttraining/core/graph/training_op_defs.cc @@ -18,8 +18,14 @@ namespace training { using namespace ONNX_NAMESPACE; namespace { -std::array GetLSTMDimensions(InferenceContext& ctx) { - TensorShapeProto::Dimension num_directions, sequence_length, batch_size, hidden_size, hidden_size_x4, input_size; + +// TODO(pengwa): remove this once customized PythonOp shape inference is supported. +constexpr const char* kInspectActivationFuncName = "onnxruntime.training.utils.hooks._subscriber_manager._InspectActivation"; +constexpr const char* kIncrementStepFuncName = "onnxruntime.training.utils.hooks._subscriber_manager._IncrementStep"; + +std::array GetRNNDimensions(InferenceContext& ctx) { + TensorShapeProto::Dimension num_directions, sequence_length, batch_size, + hidden_size, hidden_size_x_num_gates, input_size; const auto direction = getAttribute(ctx, "direction", "forward"); if ((direction == "forward") || (direction == "reverse")) @@ -49,10 +55,10 @@ std::array GetLSTMDimensions(InferenceContext& c if (weight_shape.dim_size() != 3) { fail_shape_inference("Weight tensor must have rank 3. Actual: ", weight_shape.dim_size()); } - hidden_size_x4 = weight_shape.dim(1); + hidden_size_x_num_gates = weight_shape.dim(1); } - return {num_directions, sequence_length, batch_size, hidden_size, hidden_size_x4, input_size}; + return {num_directions, sequence_length, batch_size, hidden_size, hidden_size_x_num_gates, input_size}; } } // namespace @@ -1531,7 +1537,7 @@ void RegisterTrainingOpSchemas() { "This signal indicates if weight updates are skipped, applicable to gradient infinity check" " in mixed precision training. ", "T_BOOL", OpSchema::Optional) - .Output(0, "updated_flag", "Whether gradient is applied or not.", "T2") + .Output(0, "updated_flag", "Whether gradient is applied or not.", "T_BOOL") .Output(1, "updated_weights", "Sequence of weights after optimize.", "S_WEIGHT", OpSchema::Optional) .Output(2, "updated_momentums_1", "Sequence of momentum_1 after optimize.", "S_MOMENT", OpSchema::Optional) .Output(3, "updated_momentums_2", "Sequence of momentum_2 after optimize.", "S_MOMENT", OpSchema::Optional) @@ -1725,7 +1731,7 @@ void RegisterTrainingOpSchemas() { "Constrain input and output gradient types to float tensors.") .TypeConstraint( "T2", - OpSchema::all_tensor_types_with_bfloat(), + OpSchema::all_tensor_types_ir4(), "reset_signal can be of any tensor type.") .TypeAndShapeInferenceFunction([](ONNX_NAMESPACE::InferenceContext& ctx) { propagateShapeAndTypeFromFirstInput(ctx); @@ -1745,7 +1751,7 @@ void RegisterTrainingOpSchemas() { .Output(0, "output", "Tensor of rank q-1+r-indices[-1].", "T") .TypeConstraint( "T", - OpSchema::all_tensor_types_with_bfloat(), + OpSchema::all_tensor_types_ir4(), "Constrain input and output types to any tensor type.") .TypeConstraint( "Tind", @@ -2894,6 +2900,19 @@ Example 4: return ONNX_NAMESPACE::FunctionBodyHelper::BuildFunctionProto(functionProto, schema, body, {}); }); + ONNX_CONTRIB_OPERATOR_SCHEMA(LeakyReluGrad) + .SetDomain(kMSDomain) + .SinceVersion(1) + .SetDoc("Gradient operator for LeakyRelu.") + .Attr("alpha", "Alpha (negative slope) value.", AttributeProto::FLOAT, 0.01f) + .AllowUncheckedAttributes() + .Input(0, "dY", "The gradient tensor from output.", "T") + .Input(1, "Y", "The output tensor. ", "T") + .Output(0, "dX", "Gradient of the input.", "T") + .TypeConstraint("T", {"tensor(float16)", "tensor(float)", "tensor(double)", "tensor(bfloat16)"}, + "Constrain input and output types to float tensors.") + .TypeAndShapeInferenceFunction(ONNX_NAMESPACE::propagateShapeAndTypeFromFirstInput); + ONNX_CONTRIB_OPERATOR_SCHEMA(LayerNormalizationGrad) .SetDomain(kMSDomain) .SinceVersion(1) @@ -3093,7 +3112,7 @@ Example 4: .SetDoc("if all the inputs are available, the output will be true") .Input(0, "input_tensors", "list of dependency tensors", "T", OpSchema::Variadic, false) .Output(0, "done", "all the dependency tensors are ready", "B") - .TypeConstraint("T", OpSchema::all_tensor_types_with_bfloat(), "All Tensor types") + .TypeConstraint("T", OpSchema::all_tensor_types_ir4(), "All Tensor types") .TypeConstraint("B", {"tensor(bool)"}, "Only bool") .TypeAndShapeInferenceFunction([](ONNX_NAMESPACE::InferenceContext& ctx) { updateOutputElemType(ctx, 0, ONNX_NAMESPACE::TensorProto::BOOL); @@ -3106,7 +3125,7 @@ Example 4: .SetDoc("Barrier op with value pass through, outputs = inputs") .Input(0, "inputs", "input tensors", "T", OpSchema::Variadic, false) .Output(0, "outputs", "output tensors", "T", OpSchema::Variadic, false) - .TypeConstraint("T", OpSchema::all_tensor_types_with_bfloat(), "All Tensor types") + .TypeConstraint("T", OpSchema::all_tensor_types_ir4(), "All Tensor types") .TypeAndShapeInferenceFunction([](ONNX_NAMESPACE::InferenceContext& ctx) { for (size_t i = 0; i < ctx.getNumInputs(); ++i) { propagateElemTypeFromInputToOutput(ctx, i, i); @@ -3485,7 +3504,7 @@ Return true if all elements are true and false otherwise. "Constrain input shape to integer tensors.") .TypeConstraint( "T", - OpSchema::all_tensor_types_with_bfloat(), + OpSchema::all_tensor_types_ir4(), "Constrain input and output types to float tensors.") .TypeConstraint( "Tind", @@ -3687,19 +3706,19 @@ Return true if all elements are true and false otherwise. .SinceVersion(1) .SetSupportLevel(OpSchema::SupportType::EXPERIMENTAL) .SetDoc("Yield Op.") - .Input(0, "module_outputs", "Module outputs to be returned to pytorch.", "T", OpSchema::Variadic, + .Input(0, "module_outputs", "Module outputs to be returned to PyTorch.", "T", OpSchema::Variadic, /*is_homogeneous*/ false, /*min_arity*/ 1) /* For a situation where there are no trainable parameters in a model, the YieldOp minimum number of arguments expected for module_output_grad should be 0. */ - .Output(0, "module_outputs_grad", "Gradient of module outputs returned from pytorch.", "T", OpSchema::Variadic, + .Output(0, "module_outputs_grad", "Gradient of module outputs returned from PyTorch.", "T", OpSchema::Variadic, /*is_homogeneous*/ false, /*min_arity*/ 0) .Attr("non_differentiable_outputs", "The indices of the module outputs that doesn't have a gradient.", AttributeProto::INTS, OPTIONAL_VALUE) .Attr("full_shape_outputs", "The indices of the module outputs that must have full shape.", AttributeProto::INTS) - .TypeConstraint("T", OpSchema::all_tensor_types_with_bfloat(), "Allow inputs and outputs to be any kind of tensor.") + .TypeConstraint("T", OpSchema::all_tensor_types_ir4(), "Allow inputs and outputs to be any kind of tensor.") .TypeAndShapeInferenceFunction([](ONNX_NAMESPACE::InferenceContext& ctx) { auto non_differentiable_outputs = ctx.getAttribute("non_differentiable_outputs"); std::unordered_set non_differentiable_outputs_indices{}; @@ -3741,11 +3760,11 @@ Return true if all elements are true and false otherwise. .SetDomain(kMSDomain) .SinceVersion(1) .SetSupportLevel(OpSchema::SupportType::EXPERIMENTAL) - .SetDoc("Wrapper of Pytorch's autograd.Function implementation.") + .SetDoc("Wrapper of PyTorch's autograd.Function implementation.") .Input( 0, "inputs", - "Module outputs to be returned to pytorch.", + "Module outputs to be returned to PyTorch.", "T", OpSchema::Variadic, /*is_homogeneous*/ false, @@ -3758,13 +3777,13 @@ Return true if all elements are true and false otherwise. .Output( 1, "outputs", - "Outputs returned from pytorch.", + "Outputs returned from PyTorch.", "T", OpSchema::Variadic, /*is_homogeneous*/ false, /*min_arity*/ 1) .Attr( - "name", + "func_name", "Name of custom class.", AttributeProto::STRING) .Attr( @@ -3778,7 +3797,7 @@ Return true if all elements are true and false otherwise. "which means all inputs don't require grad. Frontend needs this info to call into torch correctly.", AttributeProto::INTS, false) - // Input Pytorch tensors. + // Input PyTorch tensors. .Attr( "input_tensor_types", "Input types of autograd.Function.apply.", @@ -3787,6 +3806,17 @@ Return true if all elements are true and false otherwise. "input_tensor_ranks", "Input tensors' ranks of autograd.Function.apply.", AttributeProto::INTS) + // Input bool scalars. + .Attr( + "input_bool_scalars", + "Python bool arguments.", + AttributeProto::INTS, + false) + .Attr( + "input_bool_scalar_positions", + "", + AttributeProto::INTS, + false) // Input int scalars. .Attr( "input_int_scalars", @@ -3809,6 +3839,22 @@ Return true if all elements are true and false otherwise. "", AttributeProto::INTS, false) + // Input bool tuple. + .Attr( + "input_bool_tuples", + "Python bool-tuple arguments.", + AttributeProto::INTS, + false) + .Attr( + "input_bool_tuple_positions", + "", + AttributeProto::INTS, + false) + .Attr( + "input_bool_tuple_begins", + "", + AttributeProto::INTS, + false) // Input int tuple. .Attr( "input_int_tuples", @@ -3917,8 +3963,9 @@ Return true if all elements are true and false otherwise. // This is a required field. ORT_ENFORCE(output_tensor_types_proto, "PythonOp's must have \"output_tensor_types\" attribute."); - std::string func_name = getAttribute(ctx, "name", ""); - if (func_name == "_InspectActivation" || func_name == "_IncrementStep") { + std::string func_name = getAttribute(ctx, "func_name", ""); + // TODO(pengwa): allow custom PythonOp shape inference. + if (func_name == kInspectActivationFuncName || func_name == kIncrementStepFuncName) { // PythonOp with the name attribute being "_InspectActivation" or "_IncrementStep" will behave exactly the // same as a normal PythonOp when execution. The only difference is that: // 1). those ops having the same number of tensor inputs and tensor outputs; @@ -3957,7 +4004,7 @@ Return true if all elements are true and false otherwise. .SetDomain(kMSDomain) .SinceVersion(1) .SetSupportLevel(OpSchema::SupportType::EXPERIMENTAL) - .SetDoc("Wrapper of Pytorch's autograd.Function's backward implementaiton.") + .SetDoc("Wrapper of PyTorch's autograd.Function's backward implementation.") .Input( 0, "context", @@ -3966,7 +4013,10 @@ Return true if all elements are true and false otherwise. .Input( 1, "inputs", - "The gradient inputs (as inputs of autograd.Function.backward).", + "The gradient inputs (as inputs of autograd.Function.backward)." + "Be noted: input name will be empty when its grad input is not needed by the autograd.Function.backward." + "In PyTorch, if a forward tensor doesn't require gradient, then it's corresponding grad will be all zeros " + "or None (depending on the value of ctx.set_materialize_grads is true or false).", "T", OpSchema::Variadic, /*is_homogeneous*/ false, @@ -3974,13 +4024,13 @@ Return true if all elements are true and false otherwise. .Output( 0, "outputs", - "Outputs returned from pytorch.", + "Outputs returned from PyTorch.", "T", OpSchema::Variadic, /*is_homogeneous*/ false, /*min_arity*/ 1) .Attr( - "name", + "func_name", "Name of custom class.", AttributeProto::STRING) .Attr( @@ -4037,22 +4087,25 @@ Return true if all elements are true and false otherwise. const auto input_tensor_types_proto = ctx.getAttribute("input_tensor_types"); // This is a required field. ORT_ENFORCE(input_tensor_types_proto, "PythonOpGrad's must have \"input_tensor_types\" attribute."); - // Check if the inferred input types match those described in the - // "input_tensor_types" attributes. + // Check if the inferred input types match those described in the "input_tensor_types" attributes. // Expected input schema: [ctx, grad_input_1, ..., grad_input_N] // Other variables are used to invoke autograd.Function.backward(ctx, grad_input1, ..., grad_input_N). // The "input_count" here means 1 + N. const auto input_count = input_tensor_types_proto->ints().size() + 1; - // The first input is a pointer which points to - // a Python object created by torch.autograd.Function.apply. + // The first input is a pointer which points to a Python object created by torch.autograd.Function.apply. // For details, see how we interpret it in PythonOpGrad implementation. for (auto i = 1; i < input_count; ++i) { + if (!ctx.hasInput(i)) { + continue; + } + const auto inferred_input_type = ctx.getInputType(i); ORT_ENFORCE(inferred_input_type, "PythonOpGrad's ", i, "-th input type is missing."); ORT_ENFORCE(inferred_input_type->value_case() == TypeProto::kTensorType, "PythonOpGrad's ", i, "-th input type must be a tensor."); ORT_ENFORCE(inferred_input_type->tensor_type().elem_type() == input_tensor_types_proto->ints().at(i - 1), - "PythonOpGrad's ", i, "-th input type must be ", input_tensor_types_proto->ints().at(i - 1)); + "PythonOpGrad's ", i, "-th input type must be ", input_tensor_types_proto->ints().at(i - 1), + ", but inferred to be ", inferred_input_type->tensor_type().elem_type()); } // Load expected output types. @@ -4062,8 +4115,9 @@ Return true if all elements are true and false otherwise. // This is a required field. ORT_ENFORCE(output_tensor_types_proto, "PythonOpGrad's must have \"output_tensor_types\" attribute."); - std::string func_name = getAttribute(ctx, "name", ""); - if (func_name == "_InspectActivation" || func_name == "_IncrementStep") { + std::string func_name = getAttribute(ctx, "func_name", ""); + // TODO(pengwa): allow custom PythonOp shape inference. + if (func_name == kInspectActivationFuncName || func_name == kIncrementStepFuncName) { // PythonOpGrad with name attribute being "_InspectActivation" or "_IncrementStep" will behave exactly // the same as a normal PythonOpGrad when execution. The only difference is that: // 1). those ops having the same number of tensor inputs and tensor outputs; @@ -4094,6 +4148,33 @@ Return true if all elements are true and false otherwise. } }); +#ifdef ENABLE_TRITON + ONNX_CONTRIB_OPERATOR_SCHEMA(TritonOp) + .SetDomain(kMSDomain) + .SinceVersion(1) + .SetDoc( + "Calling an existing Python Triton kernel by function name, " + "or compute an ONNX graph through Python code to codegen, compile and execute Triton kernels.") + .Attr("func_name", "Function name of the Python Triton kernel.", AttributeProto::STRING, std::string("")) + .Attr("onnx_key", "The hash key for the ONNX graph.", AttributeProto::INT, static_cast(0)) + .Attr("onnx_string", "The onnx string of the triton kernel.", AttributeProto::STRING, std::string("")) + .Input(0, "inputs", + "Input tensors. If to call an existing Python Triton kernel, " + "the input count and order should match the arguments of the function. If to compute an ONNX graph, " + "the input count and order should match the input count and order of the ONNX graph.", + "T", OpSchema::Variadic, + /*is_homogeneous*/ false, + /*min_arity*/ 0) + .Output(0, "outputs", + "Output tensors. If to compute an ONNX graph, " + "the output count and order should match the output count and order of the ONNX graph.", + "T", OpSchema::Variadic, + /*is_homogeneous*/ false, + /*min_arity*/ 1) + .TypeConstraint("T", OpSchema::all_tensor_types_with_bfloat(), + "Allow inputs and outputs to be any kind of tensor."); +#endif // ENABLE_TRITON + ONNX_CONTRIB_OPERATOR_SCHEMA(SoftmaxCrossEntropyLossInternal) .SetDomain(kMSDomain) .SinceVersion(1) @@ -4336,7 +4417,7 @@ Return true if all elements are true and false otherwise. .Attr( "activations", "A list of 3 (or 6 if bidirectional) activation functions " - "for input, output, forget, cell, and hidden. The activation functions must " + "for input, output, forget, cell, and hidden gates. The activation functions must " "be one of the activation functions specified above. Optional: See the equations " "for default if not specified.", AttributeProto::STRINGS, @@ -4344,7 +4425,7 @@ Return true if all elements are true and false otherwise. .Attr( "activation_alpha", "Optional scaling values used by some activation functions. The values are consumed " - "in the order of activation functions, for example (f, g, h) in LSTM. Default values " + "in the order of activation functions, for example (f, g, h) in LSTMTraining. Default values " "are the same as of corresponding ONNX operators.For example with LeakyRelu, the " "default alpha is 0.01.", AttributeProto::FLOATS, @@ -4352,7 +4433,7 @@ Return true if all elements are true and false otherwise. .Attr( "activation_beta", "Optional scaling values used by some activation functions. The values are consumed in " - "the order of activation functions, for example (f, g, h) in LSTM. Default values are " + "the order of activation functions, for example (f, g, h) in LSTMTraining. Default values are " "the same as of corresponding ONNX operators.", AttributeProto::FLOATS, OPTIONAL_VALUE) @@ -4401,7 +4482,7 @@ Return true if all elements are true and false otherwise. {"tensor(int32)"}, "Constrain the length types to int32 tensors.") .TypeAndShapeInferenceFunction([](InferenceContext& ctx) { - const auto lstm_dimensions = GetLSTMDimensions(ctx); + const auto lstm_dimensions = GetRNNDimensions(ctx); const auto& num_directions = lstm_dimensions[0]; const auto& sequence_length = lstm_dimensions[1]; const auto& batch_size = lstm_dimensions[2]; @@ -4435,6 +4516,61 @@ Return true if all elements are true and false otherwise. updateOutputShape(ctx, 4, {sequence_length, num_directions, batch_size, hidden_size_x4}); }); + ONNX_CONTRIB_OPERATOR_SCHEMA(ScaledSum) + .SetDomain(kMSDomain) + .SinceVersion(1) + .SetDoc( + "Compute scaled sum of multiple tensors in same shape (no broadcasting)." + "Formula: output = (input_0 * scale_0) + (input_1 * scale_1) + (input_2 * scale_2)") + .Attr("scale_0", "Scale for input_0.", AttributeProto::FLOAT) + .Attr("scale_1", "Scale for input_1.", AttributeProto::FLOAT) + .Attr("scale_2", "(Optional) Scale for input_2.", AttributeProto::FLOAT, OPTIONAL_VALUE) + .Input(0, "input_0", "input tensor", "T") + .Input(1, "input_1", "input tensor", "T") + .Input(2, "input_2", "input tensor", "T", OpSchema::Optional) + .Output(0, "output", "output tensor", "T") + .TypeConstraint( + "T", + {"tensor(float16)", "tensor(float)", "tensor(double)"}, + "Constrain input types to float tensors.") + .TypeAndShapeInferenceFunction([](ONNX_NAMESPACE::InferenceContext& ctx) { + if (ctx.getNumInputs() == 3 && nullptr == ctx.getAttribute("scale_2")) + fail_shape_inference("Input count must be equal with scale count."); + propagateShapeAndTypeFromFirstInput(ctx); + }); + + ONNX_CONTRIB_OPERATOR_SCHEMA(BatchScale) + .SetDomain(kMSDomain) + .SinceVersion(1) + .SetDoc( + "Compute scaled input into outputs with different scaling factors (no broadcasting)." + "Formula:" + " output_0 = input * scale_0" + " output_1 = input * scale_1" + " output_2 = input * scale_2") + .Attr("scale_0", "Scale for input_0.", AttributeProto::FLOAT) + .Attr("scale_1", "Scale for input_1.", AttributeProto::FLOAT) + .Attr("scale_2", "(Optional) Scale for input_2.", AttributeProto::FLOAT, OPTIONAL_VALUE) + .Input(0, "input", "input tensor", "T") + .Output(0, "output_0", "output tensor", "T") + .Output(1, "output_1", "output tensor", "T") + .Output(2, "output_2", "output tensor", "T", OpSchema::Optional) + .TypeConstraint( + "T", + {"tensor(float16)", "tensor(float)", "tensor(double)"}, + "Constrain input types to float tensors.") + .TypeAndShapeInferenceFunction([](ONNX_NAMESPACE::InferenceContext& ctx) { + if (ctx.getNumOutputs() == 3 && nullptr == ctx.getAttribute("scale_2")) + fail_shape_inference("Output count must be equal with scale count."); + + for (size_t i = 0; i < ctx.getNumOutputs(); ++i) { + propagateElemTypeFromInputToOutput(ctx, 0, i); + if (hasInputShape(ctx, 0)) { + propagateShapeFromInputToOutput(ctx, 0, i); + } + } + }); + ONNX_CONTRIB_OPERATOR_SCHEMA(LSTMGrad) .SetDomain(kMSDomain) .SinceVersion(1) @@ -4518,7 +4654,7 @@ Return true if all elements are true and false otherwise. {"tensor(int32)"}, "Constrain the length types to int32 tensors.") .TypeAndShapeInferenceFunction([](InferenceContext& ctx) { - const auto lstm_dimensions = GetLSTMDimensions(ctx); + const auto lstm_dimensions = GetRNNDimensions(ctx); const auto& num_directions = lstm_dimensions[0]; const auto& sequence_length = lstm_dimensions[1]; const auto& batch_size = lstm_dimensions[2]; @@ -4571,6 +4707,278 @@ Return true if all elements are true and false otherwise. updateOutputShape(ctx, 6, {num_directions, three * hidden_size}); } }); + + ONNX_CONTRIB_OPERATOR_SCHEMA(PadAndUnflatten) + .SetDomain(kMSDomain) + .SinceVersion(1) + .SetDoc( + "PadAndUnflatten operator pads zero on the first axis, and unflatten the axis into two axes according" + "to given unflatten_dims. This is used by padding elimination graph transformers." + "For each index in indices, the corresponding value in output comes from input." + "For other indices, the corresponding value in output will be padded to zero." + + "The indices don't allow duplicated index values, otherwise, though there is no runtime check" + "(in case of performance concern), the behaviour of output is undefined." + + "An example:" + " input: [[1, 2, 3, 4], [5, 6, 7, 8]], shape is [2, 4]" + " indices: [0, 5], shape is [2]" + " unflatten_dims: [2, 3], shape is [2]" + + " output: [[[1, 2, 3, 4], [0, 0, 0, 0], [0, 0, 0, 0]], [[0, 0, 0, 0], [0, 0, 0, 0], [5, 6, 7, 8]]]," + " shape is [2, 3, 4]" + " flatten_output_shape: [6, 4], shape is [2]") + .Input(0, "input", "input data of rank N, shape is [d1, d2, ..., dN]", "T") + .Input(1, "indices", "1D Tensor of int32/int64 indices, shape is [d1], each element's value ranges in [0, M1*M2).", + "T_INDEX") + .Input(2, "unflatten_dims", "1D tensor with two values, [M1, M2].", "T_INT") + .Output(0, "output", "output data of rank N+1, [M1, M2, d2, ..., dN]", "T") + .Output(1, "flatten_output_shape", "1D tensor with output shape, [M1*M2, d2, ..., dN]", "T_INT") + .TypeConstraint( + "T_INT", + {"tensor(int32)", "tensor(int64)"}, + "Constrain shape to integer tensors.") + .TypeConstraint( + "T", + {"tensor(float16)", "tensor(float)", "tensor(double)", "tensor(bfloat16)"}, + "Constrain input and output types to float tensors.") + .TypeConstraint( + "T_INDEX", + {"tensor(int32)", "tensor(int64)"}, + "Constrain indices to integer types"); + + ONNX_CONTRIB_OPERATOR_SCHEMA(GRUTraining) + .SetDomain(kMSDomain) + .SinceVersion(1) + .SetDoc( + "GRUTraining operator is adapted from GRU operator (https://github.com/onnx/onnx/blob/main/docs/Changelog.md#GRU-14)." + "The difference between the two operators is that GRUTraining generates an additional output:" + "the intermediate zrh gate outputs." + "This extra output is needed for the gradient computation while training.") + .Attr( + "activations", + "A list of 2 (or 4 if bidirectional) activation functions " + "for update, reset, and hidden gates. The activation functions must " + "be one of the activation functions specified above. Optional: See the equations " + "for default if not specified.", + AttributeProto::STRINGS, + OPTIONAL_VALUE) + .Attr( + "activation_alpha", + "Optional scaling values used by some activation functions. The values are consumed " + "in the order of activation functions, for example (f, g) in GRUTraining. Default values " + "are the same as of corresponding ONNX operators.For example with LeakyRelu, the " + "default alpha is 0.01.", + AttributeProto::FLOATS, + OPTIONAL_VALUE) + .Attr( + "activation_beta", + "Optional scaling values used by some activation functions. The values are consumed in " + "the order of activation functions, for example (f, g) in GRUTraining. Default values are " + "the same as of corresponding ONNX operators.", + AttributeProto::FLOATS, + OPTIONAL_VALUE) + .Attr( + "clip", + "Cell clip threshold. Clipping bounds the elements of a tensor in the range of " + "[-threshold, +threshold] and is applied to the input of activations. No clip if not " + "specified.", + AttributeProto::FLOAT, + OPTIONAL_VALUE) + .Attr( + "linear_before_reset", + "When computing the output of the hidden gate, apply the linear transformation " + "before multiplying by the output of the reset gate.", + AttributeProto::INT, + static_cast(0)) + .Attr( + "hidden_size", + "Number of neurons in the hidden layer.", + AttributeProto::INT, + OPTIONAL_VALUE) + .Attr( + "direction", + "Specify if the RNN is forward, reverse, or bidirectional. Must be one of " + "forward (default), reverse, or bidirectional.", + AttributeProto::STRING, + std::string("forward")) + .Input(0, "X", "Original input to the GRU cell.", "T") + .Input(1, "W", "Input weight parameters to the GRU cell.", "T") + .Input(2, "R", "Input recurrence weight parameters to the GRU cell.", "T") + .Input(3, "B", "Input bias parameters to the GRU cell.", "T", OpSchema::Optional) + .Input(4, "SL", "Sequence lengths of the input sequence.", "TSize", OpSchema::Optional) + .Input(5, "Ht0", "Initial hidden state input to the GRU cell", "T", OpSchema::Optional) + .Output(0, "HAll", "Hidden states over all sequence steps.", "T", OpSchema::Optional) + .Output(1, "HFinal", "Final hidden state.", "T", OpSchema::Optional) + .Output(2, "ZRH", "Intermediate gate computations for all sequence steps.", "T", OpSchema::Optional) + .TypeConstraint( + "T", + {"tensor(float)"}, + "Constrain the gradient input and output types to float tensors.") + .TypeConstraint( + "TSize", + {"tensor(int32)"}, + "Constrain the length types to int32 tensors.") + .TypeAndShapeInferenceFunction([](InferenceContext& ctx) { + const auto gru_dimensions = GetRNNDimensions(ctx); + const auto& num_directions = gru_dimensions[0]; + const auto& sequence_length = gru_dimensions[1]; + const auto& batch_size = gru_dimensions[2]; + const auto& hidden_size = gru_dimensions[3]; + const auto& hidden_size_x3 = gru_dimensions[4]; + + const auto num_outputs = ctx.getNumOutputs(); + for (size_t i = 0; i < num_outputs; ++i) { + propagateElemTypeFromInputToOutput(ctx, 0, i); + } + + if (num_outputs > 0) + // All hidden states + updateOutputShape(ctx, 0, {sequence_length, num_directions, batch_size, hidden_size}); + + if (num_outputs > 1) + // Final hidden state + updateOutputShape(ctx, 1, {num_directions, batch_size, hidden_size}); + + if (num_outputs > 2) + // ZRH gate computations + updateOutputShape(ctx, 2, {sequence_length, num_directions, batch_size, hidden_size_x3}); + }); + + ONNX_CONTRIB_OPERATOR_SCHEMA(GRUGrad) + .SetDomain(kMSDomain) + .SinceVersion(1) + .SetDoc( + "GRUGrad operator that computes the partial derivative of the loss with respect to GRU inputs: " + "a) The input sequence, b) Weight parameters, c) Recurrence weight parameters, d) Bias parameters, " + "e) Previous hidden state." + "This operator computes the gradient of the GRU operator from opset version 14: " + "https://github.com/onnx/onnx/blob/main/docs/Changelog.md#GRU-14") + .Attr( + "activations", + "A list of 2 (or 4 if bidirectional) activation functions " + "for update, reset, and hidden gates. The activation functions must " + "be one of the activation functions specified above. Optional: See the equations " + "for default if not specified.", + AttributeProto::STRINGS, + OPTIONAL_VALUE) + .Attr( + "activation_alpha", + "Optional scaling values used by some activation functions. The values are consumed " + "in the order of activation functions, for example (f, g) in GRUTraining. Default values " + "are the same as of corresponding ONNX operators.For example with LeakyRelu, the " + "default alpha is 0.01.", + AttributeProto::FLOATS, + OPTIONAL_VALUE) + .Attr( + "activation_beta", + "Optional scaling values used by some activation functions. The values are consumed in " + "the order of activation functions, for example (f, g) in GRUTraining. Default values are " + "the same as of corresponding ONNX operators.", + AttributeProto::FLOATS, + OPTIONAL_VALUE) + .Attr( + "clip", + "Cell clip threshold. Clipping bounds the elements of a tensor in the range of " + "[-threshold, +threshold] and is applied to the input of activations. No clip if not " + "specified.", + AttributeProto::FLOAT, + OPTIONAL_VALUE) + .Attr( + "linear_before_reset", + "When computing the output of the hidden gate, apply the linear transformation " + "before multiplying by the output of the reset gate.", + AttributeProto::INT, + static_cast(0)) + .Attr( + "hidden_size", + "Number of neurons in the hidden layer.", + AttributeProto::INT, + OPTIONAL_VALUE) + .Attr( + "direction", + "Specify if the RNN is forward, reverse, or bidirectional. Must be one of " + "forward (default), reverse, or bidirectional.", + AttributeProto::STRING, + std::string("forward")) + .Input(0, "X", "Original input to the GRU cell.", "T") + .Input(1, "W", "Input weight parameters to the GRU cell.", "T") + .Input(2, "R", "Input recurrent weight parameters to the GRU cell.", "T") + .Input(3, "B", "Input bias parameters to the GRU cell.", "T", OpSchema::Optional) + .Input(4, "SL", "Input sequence length of the input sequence.", "TSize", OpSchema::Optional) + .Input(5, "Ht0", "Initial hidden state input to the GRU cell", "T", OpSchema::Optional) + .Input(6, "HAll", "Hidden states over all sequence steps output from GRUTraining.", "T", OpSchema::Optional) + .Input(7, "ZRH", "Intermediate gate computations for all sequence steps output from GRUTraining.", "T", OpSchema::Optional) + .Input(8, "dHAll", "Gradient of loss with respect to the output Y of the GRU cell", "T", OpSchema::Optional) + .Input(9, "dHFinal", "Gradient of loss with respect to the output Y_h of the GRU cell", "T", OpSchema::Optional) + .Output(0, "dX", "Gradient of loss with respect to the input (to the GRU cell).", "T", OpSchema::Optional) + .Output(1, "dW", "Gradient of loss with respect to the weight parameters (of the GRU cell).", "T", OpSchema::Optional) + .Output(2, "dR", "Gradient of loss with respect to the recurrence weight parameters (of the GRU cell).", "T", OpSchema::Optional) + .Output(3, "dB", "Gradient of loss with respect to the bias parameters (of the GRU cell).", "T", OpSchema::Optional) + .Output(4, "dH0", "Gradient of loss with respect to the previous hidden state (of the GRU cell).", "T", OpSchema::Optional) + .TypeConstraint( + "T", + {"tensor(float)"}, + "Constrain the gradient input and output types to float tensors.") + .TypeConstraint( + "TSize", + {"tensor(int32)"}, + "Constrain the length types to int32 tensors.") + .TypeAndShapeInferenceFunction([](InferenceContext& ctx) { + const auto gru_dimensions = GetRNNDimensions(ctx); + const auto& num_directions = gru_dimensions[0]; + const auto& sequence_length = gru_dimensions[1]; + const auto& batch_size = gru_dimensions[2]; + const auto& hidden_size = gru_dimensions[3]; + const auto& hidden_size_x3 = gru_dimensions[4]; + const auto& input_size = gru_dimensions[5]; + + const auto num_outputs = ctx.getNumOutputs(); + for (size_t i = 0; i < num_outputs; ++i) { + propagateElemTypeFromInputToOutput(ctx, 0, i); + } + + if (num_outputs > 0) + // Gradient with respect to the input tensor + updateOutputShape(ctx, 0, {sequence_length, batch_size, input_size}); + + if (num_outputs > 1) + // Gradient with respect to the weight tensor + updateOutputShape(ctx, 1, {num_directions, hidden_size_x3, input_size}); + + if (num_outputs > 2) + // Gradient with respect to the recurrence weight tensor + updateOutputShape(ctx, 2, {num_directions, hidden_size_x3, hidden_size}); + + if (num_outputs > 3) { + TensorShapeProto::Dimension six; + six.set_dim_value(6); + // Gradient with respect to the bias tensor + updateOutputShape(ctx, 3, {num_directions, six * hidden_size}); + } + + if (num_outputs > 4) { + if (hasInputShape(ctx, 4)) { + // Gradient with respect to the initial hidden state + updateOutputShape(ctx, 4, {num_directions, batch_size, hidden_size}); + } + } + }); + + ONNX_CONTRIB_OPERATOR_SCHEMA(ConvTransposeGrad) + .SetDomain(kMSDomain) + .SinceVersion(1) + .Input(0, "dY", "Gradient of output Y", "T") + .Input(1, "X", "Input tensor", "T") + .Input(2, "W", "Weight tensor", "T") + .Output(0, "dX", "Gradient of X", "T", OpSchema::Optional) + .Output(1, "dW", "Gradient of W", "T", OpSchema::Optional) + .Output(2, "dB", "Gradient of B", "T", OpSchema::Optional) + .AllowUncheckedAttributes() + .TypeConstraint( + "T", + {"tensor(float16)", "tensor(float)", "tensor(double)"}, + "Constrain input and output types to float tensors."); } } // namespace training diff --git a/orttraining/orttraining/core/optimizer/compute_optimizer/padding_elimination.cc b/orttraining/orttraining/core/optimizer/compute_optimizer/padding_elimination.cc new file mode 100644 index 0000000000000..74247c059cf84 --- /dev/null +++ b/orttraining/orttraining/core/optimizer/compute_optimizer/padding_elimination.cc @@ -0,0 +1,603 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifdef ENABLE_TRAINING + +#include + +#include "core/framework/random_seed.h" +#include "core/graph/graph_utils.h" +#include "core/optimizer/initializer.h" +#include "orttraining/core/optimizer/compute_optimizer/padding_elimination.h" + +using namespace onnxruntime::optimizer::compute_optimizer; + +namespace onnxruntime { + +namespace { + +// TODO(pengwa): remove this once customized PythonOp shape inference is supported. +constexpr const char* kInspectActivationFuncName = "onnxruntime.training.utils.hooks._subscriber_manager._InspectActivation"; +constexpr const char* kIncrementStepFuncName = "onnxruntime.training.utils.hooks._subscriber_manager._IncrementStep"; + +void PushAllOutputNode(Graph& graph, std::queue& q, Node* node, std::unordered_set& visited) { + for (auto iter = node->OutputNodesBegin(); iter != node->OutputNodesEnd(); ++iter) { + Node* output_node = graph.GetNode(iter->Index()); + if (visited.find(output_node) == visited.end()) { + q.push(output_node); + } + } +} + +bool IsATenEmbedding(const Node* node) { + if (graph_utils::IsSupportedOptypeVersionAndDomain(*node, "ATen", {1}, kPytorchAtenDomain)) { + for (auto kv : node->GetAttributes()) { + if (kv.first == "operator" && kv.second.s() == "embedding") { + return true; + } + } + } + return false; +} + +// Get dims value of shape of input with indices_arg +// Implemented by add a Shape + GatherElements after input +NodeArg* GetDimsValue(Graph& graph, NodeArg* input, NodeArg* indices_arg, Node& node) { + InlinedVector shape_output_args{&graph.GetOrCreateNodeArg(graph.GenerateNodeArgName("shape_result"), + nullptr)}; + Node& shape_node = graph.AddNode(graph.GenerateNodeName("shape"), "Shape", "", {input}, + shape_output_args, nullptr, kOnnxDomain); + ORT_ENFORCE(graph.SetOpSchemaFromRegistryForNode(shape_node), "Failed to get shape for " + shape_node.Name()); + shape_node.SetExecutionProviderType(node.GetExecutionProviderType()); + + InlinedVector gather_input_args; + gather_input_args.push_back(shape_output_args[0]); + gather_input_args.push_back(indices_arg); + + InlinedVector gather_out_args{&graph.GetOrCreateNodeArg(graph.GenerateNodeArgName("gather_result"), + nullptr)}; + + Node& gather_node = graph.AddNode(graph.GenerateNodeName("gather_first_dim"), "GatherElements", "", gather_input_args, + gather_out_args, nullptr, kOnnxDomain); + ORT_ENFORCE(graph.SetOpSchemaFromRegistryForNode(gather_node), "Failed to get shape for " + gather_node.Name()); + gather_node.SetExecutionProviderType(node.GetExecutionProviderType()); + + return gather_out_args[0]; +} + +// Insert Expand to the in_index-th input of node. +// The node should have two inputs and the shape of the other input (node.InputDefs()[1-in_index]) should be +// [batch_size, seq_len, ...]. This function insert an Expand to expand shape of the in_index-th input of node with +// a shape arg of [batch_size, seq_len, 1, 1, ...] which size is equal with node.InputDefs()[1-in_index]->Shape().size. +NodeArg* InsertExpandForNodeInput(Graph& graph, + Node& node, + uint32_t in_index, + NodeArg* first_two_dims_arg, + const logging::Logger& logger) { + auto full_sized_input_shape = node.InputDefs()[1 - in_index]->Shape(); + ORT_ENFORCE(full_sized_input_shape->dim_size() >= 2); + NodeArg* expand_shape_arg = nullptr; + if (full_sized_input_shape->dim_size() == 2) { + expand_shape_arg = first_two_dims_arg; + } else { + InlinedVector other_indices(static_cast(full_sized_input_shape->dim_size()) - 2, 1); + InlinedVector concat_input_args; + concat_input_args.push_back(first_two_dims_arg); + concat_input_args.push_back( + CreateInitializerFromVector(graph, + {static_cast(other_indices.size())}, + other_indices, + graph.GenerateNodeArgName("other_shape"))); + + InlinedVector concat_output_args{&graph.GetOrCreateNodeArg(graph.GenerateNodeArgName("concat_shape_result"), + nullptr)}; + + onnxruntime::NodeAttributes attributes; + attributes["axis"] = ONNX_NAMESPACE::MakeAttribute("axis", int64_t(0)); + + Node& concat_node = graph.AddNode(graph.GenerateNodeName("concat_shape"), "Concat", "", concat_input_args, + concat_output_args, &attributes, kOnnxDomain); + ORT_ENFORCE(graph.SetOpSchemaFromRegistryForNode(concat_node), "Failed to concat shape for " + concat_node.Name()); + concat_node.SetExecutionProviderType(node.GetExecutionProviderType()); + expand_shape_arg = concat_output_args[0]; + } + + InlinedVector expand_input_args; + expand_input_args.reserve(2); + expand_input_args.push_back(node.MutableInputDefs()[in_index]); + expand_input_args.push_back(expand_shape_arg); + + InlinedVector expand_output_args; + expand_output_args.push_back( + &graph.GetOrCreateNodeArg(graph.GenerateNodeArgName("inputs_expand_result"), + node.MutableInputDefs()[1 - in_index]->TypeAsProto())); + + Node* new_expand_node = InsertIntermediateNodeOnDestInput( + graph, node, + in_index, + 0, + 0, + graph.GenerateNodeName("ExpandPaddingShape"), + "Expand", + "Expand shape of one input arg to align the other arg.", + expand_input_args, + expand_output_args, + {}, + "", + logger); + new_expand_node->SetExecutionProviderType(node.GetExecutionProviderType()); + return new_expand_node->MutableOutputDefs()[0]; +} + +// Insert Reshape + ShrunkenGather to flatten the in_index-th input of node. +// The gather_index_arg is the indices of the elements that are not padding. +NodeArg* InsertFlattenPatternForInput(Graph& graph, + Node& node, + uint32_t in_index, + NodeArg* gather_index_arg, + const logging::Logger& logger) { + InlinedVector reshape_input_args; + reshape_input_args.reserve(2); + reshape_input_args.push_back(node.MutableInputDefs()[in_index]); + std::vector new_shape; + new_shape.push_back(-1); // only support flatten 0 and 1 dims + auto input_shape = node.InputDefs()[in_index]->Shape(); + ORT_ENFORCE(input_shape->dim_size() >= 2); + ONNX_NAMESPACE::TensorShapeProto flattened_shape; + if (input_shape->dim(0).has_dim_value() && input_shape->dim(1).has_dim_value()) { + flattened_shape.add_dim()->set_dim_value(input_shape->dim(0).dim_value() * input_shape->dim(1).dim_value()); + } else { + std::string token_dim_name = MakeString("total_token_count_", utils::GetRandomSeed()); + flattened_shape.add_dim()->set_dim_param(token_dim_name); + } + for (int k = 2; k < input_shape->dim_size(); k++) { + ORT_ENFORCE(input_shape->dim(k).has_dim_value()); + new_shape.push_back(input_shape->dim(k).dim_value()); + flattened_shape.add_dim()->set_dim_value(input_shape->dim(k).dim_value()); + } + ONNX_NAMESPACE::TensorProto new_shape_const_tensor; + new_shape_const_tensor.set_name(graph.GenerateNodeArgName("new_shape")); + new_shape_const_tensor.set_data_type(ONNX_NAMESPACE::TensorProto_DataType_INT64); + new_shape_const_tensor.add_dims(new_shape.size()); + new_shape_const_tensor.set_raw_data(new_shape.data(), new_shape.size() * sizeof(int64_t)); + NodeArg* new_shape_arg = &graph_utils::AddInitializer(graph, new_shape_const_tensor); + reshape_input_args.push_back(new_shape_arg); + + InlinedVector reshape_output_args; + reshape_output_args.push_back( + &graph.GetOrCreateNodeArg(graph.GenerateNodeArgName("inputs_reshape_result"), + node.MutableInputDefs()[in_index]->TypeAsProto())); + + Node* new_reshape_node = InsertIntermediateNodeOnDestInput( + graph, node, + in_index, + 0, + 0, + graph.GenerateNodeName("Reshape"), + "Reshape", + "Reshape node to filter invalid tokens.", + reshape_input_args, + reshape_output_args, + {}, + "", + logger); + + new_reshape_node->SetExecutionProviderType(node.GetExecutionProviderType()); + auto reshape_out_arg = new_reshape_node->MutableOutputDefs()[0]; + + reshape_out_arg->SetShape(flattened_shape); + + InlinedVector gather_input_args; + gather_input_args.reserve(2); + gather_input_args.push_back(reshape_output_args[0]); + gather_input_args.push_back(gather_index_arg); + + InlinedVector gather_output_args; + gather_output_args.push_back( + &graph.GetOrCreateNodeArg(graph.GenerateNodeArgName("padding_filter_result"), + reshape_out_arg->TypeAsProto())); + + Node* new_gather_node = InsertIntermediateNodeOnDestInput( + graph, node, + in_index, + 0, + 0, + graph.GenerateNodeName("PaddingFilter"), + "ShrunkenGather", + "ShrunkenGather node to filter invalid tokens.", + gather_input_args, + gather_output_args, + {}, + kMSDomain, + logger); + + new_gather_node->SetExecutionProviderType(node.GetExecutionProviderType()); + auto gather_out_arg = new_gather_node->MutableOutputDefs()[0]; + return gather_out_arg; +} + +// Insert PadAndUnflatten to unflatten the shape of the in_index-th input of node. +// The gathergrad_index_arg is the indices of the elements that are not padding. +// The new_shape_arg is the shape of [batch_size * seqlen, ...] +// gathergrad_index_arg and new_shape_arg are the arguments needed by GatherGrad. +NodeArg* InsertNodesForOutput(Graph& graph, + Node& node, + uint32_t in_index, + NodeArg* gathergrad_index_arg, + NodeArg* first_two_dims_arg, + const logging::Logger& logger) { + InlinedVector pad_node_input_args; + pad_node_input_args.reserve(3); + pad_node_input_args.push_back(node.MutableInputDefs()[in_index]); + pad_node_input_args.push_back(gathergrad_index_arg); + pad_node_input_args.push_back(first_two_dims_arg); + + InlinedVector pad_node_output_args; + pad_node_output_args.push_back( + &graph.GetOrCreateNodeArg(graph.GenerateNodeArgName("padded_result"), + nullptr)); + pad_node_output_args.push_back( + &graph.GetOrCreateNodeArg(graph.GenerateNodeArgName("padded_d1xd2_shape"), + nullptr)); + + Node* new_gathergrad_node = InsertIntermediateNodeOnDestInput( + graph, node, + in_index, + 0 /* new_node_input_index*/, + 0 /* new_node_output_index*/, + graph.GenerateNodeName("PaddingRecover"), + "PadAndUnflatten", + "PadAndUnflatten node to recover invalid tokens.", + pad_node_input_args, + pad_node_output_args, + {}, + kMSDomain, + logger); + + new_gathergrad_node->SetExecutionProviderType(node.GetExecutionProviderType()); + return new_gathergrad_node->MutableOutputDefs()[0]; +} + +// Iterate the subgraph beginning from the start_node, and put all node args into 'subgraph' +// Also put all candidate input nodes and candidate output nodes of the subgraph into candidate_inputs and +// candidate_outputs respectively. +void IterateSubgraphFromNode(Graph& graph, + Node* start_node, + std::unordered_set& subgraph, + std::unordered_set& candidate_inputs, + std::unordered_set& candidate_outputs, + const logging::Logger& logger) { + std::queue to_visit; + std::unordered_set visited; + PushAllOutputNode(graph, to_visit, start_node, visited); + while (!to_visit.empty()) { + Node* cur = to_visit.front(); + to_visit.pop(); + visited.insert(cur); + if (graph_utils::IsSupportedOptypeVersionAndDomain(*cur, "Add", {7, 13, 14}) || + graph_utils::IsSupportedOptypeVersionAndDomain(*cur, "BiasGelu", {1}, kMSDomain) || + graph_utils::IsSupportedOptypeVersionAndDomain(*cur, "Sub", {7, 13, 14}) || + graph_utils::IsSupportedOptypeVersionAndDomain(*cur, "Mul", {7, 13, 14})) { + ORT_ENFORCE(subgraph.find(cur->MutableInputDefs()[0]) != subgraph.end() || + subgraph.find(cur->MutableInputDefs()[1]) != subgraph.end()); + if (cur->InputDefs()[0]->Shape() && cur->InputDefs()[1]->Shape()) { + if ((subgraph.find(cur->MutableInputDefs()[0]) == subgraph.end() && + cur->InputDefs()[0]->Shape()->dim_size() > cur->InputDefs()[1]->Shape()->dim_size()) || + (subgraph.find(cur->MutableInputDefs()[1]) == subgraph.end() && + cur->InputDefs()[1]->Shape()->dim_size() > cur->InputDefs()[0]->Shape()->dim_size())) { + // If the shape of one of the inputs is not in the subgraph, and it has more dimensions, + // this case is not supported now. + LOG_DEBUG_INFO(logger, "PaddingElimination::Input shapes of node:" + cur->Name() + " are not compatible." + + " arg not in subgraph has more dimensions."); + candidate_outputs.insert(cur); + continue; + } + subgraph.insert(cur->MutableOutputDefs()[0]); + PushAllOutputNode(graph, to_visit, cur, visited); + candidate_inputs.insert(cur); + } else { + LOG_DEBUG_INFO(logger, "PaddingElimination::Input of node:" + cur->Name() + " have no shape."); + candidate_outputs.insert(cur); + continue; + } + } else if (graph_utils::IsSupportedOptypeVersionAndDomain(*cur, "LayerNormalization", {1, 17}, kOnnxDomain) || + graph_utils::IsSupportedOptypeVersionAndDomain(*cur, "SimplifiedLayerNormalization", {1}, kOnnxDomain)) { + if (subgraph.find(cur->MutableInputDefs()[0]) == subgraph.end()) { + LOG_DEBUG_INFO(logger, "PaddingElimination::First input of Normalization: " + cur->Name() + + " is not in subgraph."); + candidate_outputs.insert(cur); + continue; + } + if (!cur->InputDefs()[0]->Shape()) { + LOG_DEBUG_INFO(logger, "PaddingElimination::First input of Normalization: " + cur->Name() + + " has no shape."); + candidate_outputs.insert(cur); + continue; + } + auto axis = static_cast(cur->GetAttributes().at("axis").i()); + axis = axis < 0 ? axis + cur->InputDefs()[0]->Shape()->dim_size() : axis; + if (axis < 2) { + LOG_DEBUG_INFO(logger, "PaddingElimination::axis of Normalization: " + cur->Name() + " is " + + std::to_string(axis) + ", which blocks merging leading two dims."); + candidate_outputs.insert(cur); + } else { + subgraph.insert(cur->MutableOutputDefs()[0]); + PushAllOutputNode(graph, to_visit, cur, visited); + } + } else if (graph_utils::IsSupportedOptypeVersionAndDomain(*cur, "Dropout", {12, 13})) { + ORT_ENFORCE(subgraph.find(cur->MutableInputDefs()[0]) != subgraph.end()); + subgraph.insert(cur->MutableOutputDefs()[0]); + subgraph.insert(cur->MutableOutputDefs()[1]); + PushAllOutputNode(graph, to_visit, cur, visited); + } else if (graph_utils::IsSupportedOptypeVersionAndDomain(*cur, "Cast", {9, 13}) || + graph_utils::IsSupportedOptypeVersionAndDomain(*cur, "Gelu", {1}, kMSDomain)) { + ORT_ENFORCE(subgraph.find(cur->MutableInputDefs()[0]) != subgraph.end()); + subgraph.insert(cur->MutableOutputDefs()[0]); + PushAllOutputNode(graph, to_visit, cur, visited); + } else if (graph_utils::IsSupportedOptypeVersionAndDomain(*cur, "MatMul", {1, 9, 13})) { + if (subgraph.find(cur->MutableInputDefs()[0]) != subgraph.end()) { + // If shape of [batch_size, seqlen, ...] is propagated from the first argument of MatMul. + // The dim size of the first argument must be larger than 2 to propagate the first two dims to the output. + // Or else the first two dims of the output will not be [batch_size, seqlen] and this MatMul will be added + // to candidate_outputs as the output of the subgraph. + if (cur->InputDefs()[0]->Shape()->dim_size() > 2) { + subgraph.insert(cur->MutableOutputDefs()[0]); + PushAllOutputNode(graph, to_visit, cur, visited); + } else { + LOG_DEBUG_INFO(logger, + "PaddingElimination::dim size of left input of MatMul smaller than 3 and \ + this MatMul would be the output of the subgraph."); + candidate_outputs.insert(cur); + continue; + } + } else if (subgraph.find(cur->MutableInputDefs()[1]) != subgraph.end()) { + LOG_DEBUG_INFO(logger, "PaddingElimination::right edge of MatMul would not included."); + candidate_outputs.insert(cur); + continue; + } else { + ORT_THROW("PaddingElimination::found MatMul node without input in subgraph."); + } + } else if (graph_utils::IsSupportedOptypeVersionAndDomain(*cur, "PythonOp", {1}, kMSDomain)) { + if (subgraph.find(cur->MutableInputDefs()[0]) == subgraph.end()) { + candidate_outputs.insert(cur); + continue; + } + auto func_name = static_cast(cur->GetAttributes().at("name").s()); + if (func_name == kInspectActivationFuncName || func_name == kIncrementStepFuncName) { + subgraph.insert(cur->MutableOutputDefs()[1]); + PushAllOutputNode(graph, to_visit, cur, visited); + } else { + candidate_outputs.insert(cur); + } + } else if (graph_utils::IsSupportedOptypeVersionAndDomain(*cur, "ReduceMean", {1, 11, 13, 18})) { + if (cur->InputDefs()[0]->Shape()) { + auto axes = cur->GetAttributes().at("axes").ints(); + bool axes_check = (axes.size() > 0); + for (int64_t axis : axes) { + axis = axis < 0 ? axis + cur->InputDefs()[0]->Shape()->dim_size() : axis; + if (axis < 2) { + LOG_DEBUG_INFO(logger, "PaddingElimination::axis of ReduceMean: " + cur->Name() + " is " + + std::to_string(axis) + ", which blocks merging leading two dims."); + axes_check = false; + break; + } + } + if (axes_check) { + LOG_DEBUG_INFO(logger, "PaddingElimination::ReduceMean: " + cur->Name() + " is added to subgraph."); + subgraph.insert(cur->MutableOutputDefs()[0]); + PushAllOutputNode(graph, to_visit, cur, visited); + } else { + candidate_outputs.insert(cur); + } + } else { + LOG_DEBUG_INFO(logger, "PaddingElimination::shape of input of ReduceMean: " + cur->Name() + " is unknown."); + candidate_outputs.insert(cur); + continue; + } + } else { + candidate_outputs.insert(cur); + } + } +} +} // namespace + +Status PaddingElimination::ApplyImpl(Graph& graph, bool& modified, int graph_level, const logging::Logger& logger) const { + LOG_DEBUG_INFO(logger, "Enter PaddingElimination"); + + if (sparse_embedding_input_names_.size() == 0) { + LOG_DEBUG_INFO(logger, "Exit PaddingElimination, no sparse embedding input names."); + return Status::OK(); + } + + GraphViewer graph_viewer(graph); + const auto& node_topology_list = graph_viewer.GetNodesInTopologicalOrder(); + Node* embedding_node = nullptr; + NodeArg* input_ids_arg = nullptr; + // Make sure each node_arg in subgraph has first two consecutive dims to be flattened. + // All node_args in subgraph is propagated from the embedding node + std::unordered_set subgraph; + // input args of nodes in candidate_inputs should be in subgraph or to be added Reshape + Gather. + // Put nodes that its input args may be input of the subgraph into candidate_inputs + std::unordered_set candidate_inputs; + // input args of nodes in candidate_outputs, if in subgraph, should be added GatherGrad + Reshape + // record node that its input args may be output of the subgraph into candidate_outputs + std::unordered_set candidate_outputs; + int64_t handled_input_count = 0; + int64_t handled_output_count = 0; + int64_t expanded_input_count = 0; + + // Find the valid embedding node + for (auto node_index : node_topology_list) { + auto& node = *graph.GetNode(node_index); + ORT_RETURN_IF_ERROR(Recurse(node, modified, graph_level, logger)); + + if (IsATenEmbedding(&node) && + graph_utils::IsSupportedProvider(node, GetCompatibleExecutionProviders()) && + node.InputDefs().size() >= 3 && + node.InputDefs()[2]->Exists() && + graph_utils::IsConstantInitializer(graph, node.InputDefs()[2]->Name()) && + node.InputDefs()[1]->Exists() && + graph_utils::IsGraphInput(graph, node.InputDefs()[1]) && + node.InputDefs()[1]->Shape() && + node.InputDefs()[1]->Shape()->dim_size() >= 2) { + if (std::find(sparse_embedding_input_names_.begin(), sparse_embedding_input_names_.end(), + node.InputDefs()[1]->Name()) == sparse_embedding_input_names_.end()) { + LOG_DEBUG_INFO(logger, "Skip node " + node.Name() + "(" + node.OpType() + + ") due to embedding input is not in the sparse embedding input list."); + continue; + } + const ONNX_NAMESPACE::TensorProto* padding_initializer = + graph_utils::GetConstantInitializer(graph, node.InputDefs()[2]->Name()); + if (padding_initializer != nullptr && + padding_initializer->dims_size() == 0 && + ((padding_initializer->data_type() == ONNX_NAMESPACE::TensorProto_DataType_INT32) || + (padding_initializer->data_type() == ONNX_NAMESPACE::TensorProto_DataType_INT64))) { + int64_t padding_idx = *reinterpret_cast(padding_initializer->raw_data().data()); + if (padding_idx < 0) { + continue; + } + embedding_node = &node; + input_ids_arg = embedding_node->MutableInputDefs()[1]; + for (auto output_defs : embedding_node->MutableOutputDefs()) { + subgraph.insert(output_defs); + } + break; + } + } + } + + if (!embedding_node) { + LOG_DEBUG_INFO(logger, "Exit PaddingElimination optimization for not finding any valid embedding node."); + return Status::OK(); + } + + if (!input_ids_arg->Shape()) { + LOG_DEBUG_INFO(logger, "Exit PaddingElimination optimization for not finding shape of input_ids."); + return Status::OK(); + } + auto input_ids_shape = input_ids_arg->Shape(); + // For now, we only support all the dims of input_ids_shape besides the first two has dim_value. + for (int k = 2; k < input_ids_shape->dim_size(); k++) { + if (!input_ids_shape->dim(k).has_dim_value()) { + LOG_DEBUG_INFO(logger, "Exit PaddingElimination optimization for shape dims of input_ids has no value."); + return Status::OK(); + } + } + + IterateSubgraphFromNode(graph, embedding_node, subgraph, candidate_inputs, candidate_outputs, logger); + + // Add Reshape + Sub + NonZero + Squeeze to get the not padding index to be gathered + InlinedVector reshape_input_args; + reshape_input_args.reserve(2); + reshape_input_args.push_back(input_ids_arg); + InlinedVector new_input_ids_shape; + new_input_ids_shape.reserve(static_cast(input_ids_shape->dim_size()) - 1); + new_input_ids_shape.push_back(-1); // Flatten the two leading dims + for (int k = 2; k < input_ids_shape->dim_size(); k++) { + new_input_ids_shape.push_back(input_ids_shape->dim(k).dim_value()); + } + reshape_input_args.push_back( + CreateInitializerFromVector(graph, + {static_cast(new_input_ids_shape.size())}, + new_input_ids_shape, + graph.GenerateNodeArgName("flattened_shape"))); + + InlinedVector reshape_output_args; + reshape_output_args.push_back( + &graph.GetOrCreateNodeArg(graph.GenerateNodeArgName("flattened_input_ids"), nullptr)); + + Node& reshape_node = graph.AddNode(graph.GenerateNodeName("inputs_reshape"), + "Reshape", + "input flatten first two dims", + reshape_input_args, + reshape_output_args, + nullptr, + kOnnxDomain); + ORT_ENFORCE(graph.SetOpSchemaFromRegistryForNode(reshape_node), "Failed to set op schema for " + reshape_node.Name()); + reshape_node.SetExecutionProviderType(embedding_node->GetExecutionProviderType()); + + NodeArg* squeeze_out_arg = InsertNodesForValidIndices( + graph, reshape_output_args[0], embedding_node->MutableInputDefs()[2], embedding_node->GetExecutionProviderType()); + + // Get the first two dims value of input_ids which is [batch_size, seq_len] + NodeArg* first_two_dims_arg = GetDimsValue(graph, + input_ids_arg, + CreateInitializerFromVector(graph, {2}, {0, 1}, graph.GenerateNodeArgName("first_two_indices")), + *embedding_node); + + // Add flatten pattern to each input node of the subgraph + // to flattern the shape of [batch_size, seqlen, ...] to [valid_token_count, ...] + InsertFlattenPatternForInput(graph, *embedding_node, 1, squeeze_out_arg, logger); + handled_input_count++; + modified = true; + for (auto& node : candidate_inputs) { + for (uint32_t i = 0; i < node->InputDefs().size(); ++i) { + if (subgraph.find(node->MutableInputDefs()[i]) == subgraph.end()) { + // The type of node is one of Elementwise ops. + // The input size must be 2 and there must be more than one input in the subgraph. + ORT_ENFORCE(node->InputDefs().size() == 2); + // Because candidate_inputs are nodes iterated from embedding node, each of them must have at least one arg in + // the subgraph and the i-th input of this node is not in the subgraph, so the other input must be in the subgraph + // and has shape of [batch_size, seq_len, ...] + NodeArg* arg_in_subgraph = node->MutableInputDefs()[1 - i]; + NodeArg* arg_not_in_subgraph = node->MutableInputDefs()[i]; + // There are three possibilities for the shape of arg_not_in_subgraph: + // 1. The size of arg_not_in_subgraph->Shape is smaller than arg_in_subgraph->Shape by 2, + // which means the shape of arg_not_in_subgraph has no [batch_size, seq_len] in beginning, + // and do not need to add flatten pattern to it. + // 2. The arg_not_in_subgraph->Shape.size == arg_in_subgraph->Shape.size or arg_in_subgraph->Shape.size - 1, + // and the first two dims do not equal [batch_size, seq_len]. + // In this case we just expand the arg_not_in_subgraph->Shape to [batch_size, seq_len, ...], + // then the case becomes same with 3. + // 3. The size of arg_not_in_subgraph->Shape is equal with size of arg_in_subgraph->Shape, + // and the first two dims of arg_not_in_subgraph->Shape is [batch_size, seq_len]. + // Because the shape of arg_in_subgraph will be flattened to [valid_tokens, ... ] automatically after + // the shape of input_ids is flattened, so we need to insert flatten pattern for arg_not_in_subgraph->Shape. + if (arg_not_in_subgraph->Shape()->dim_size() <= arg_in_subgraph->Shape()->dim_size() - 2) { + continue; + } else if (arg_in_subgraph->Shape()->dim_size() != arg_not_in_subgraph->Shape()->dim_size() || + arg_in_subgraph->Shape()->dim(0) != arg_not_in_subgraph->Shape()->dim(0) || + arg_in_subgraph->Shape()->dim(1) != arg_not_in_subgraph->Shape()->dim(1)) { + InsertExpandForNodeInput(graph, *node, i, first_two_dims_arg, logger); + expanded_input_count++; + } + InsertFlattenPatternForInput(graph, *node, i, squeeze_out_arg, logger); + handled_input_count++; + } + } + } + + // Add pattern to each output node of the subgraph + // to unflatten the shape of [valid_token_count, ...] to [batch_size, seq_len, ...] + for (const auto& node : candidate_outputs) { + for (uint32_t i = 0; i < node->InputDefs().size(); ++i) { + if (subgraph.find(node->MutableInputDefs()[i]) != subgraph.end()) { + InsertNodesForOutput(graph, *node, i, squeeze_out_arg, first_two_dims_arg, logger); + handled_output_count++; + } + } + } + + std::string token_dim_name = MakeString("valid_token_count_", utils::GetRandomSeed()); + // Update shape for each edge of the subgraph + for (auto edge : subgraph) { + ONNX_NAMESPACE::TensorShapeProto flattened_shape; + flattened_shape.add_dim()->set_dim_param(token_dim_name); + auto input_shape = edge->Shape(); + for (int k = 2; k < input_shape->dim_size(); k++) { + ORT_ENFORCE(input_shape->dim(k).has_dim_value()); + flattened_shape.add_dim()->set_dim_value(input_shape->dim(k).dim_value()); + edge->SetShape(flattened_shape); + } + } + if (handled_input_count > 0 || handled_output_count > 0) { + LOGS(logger, INFO) << "PaddingElimination::Total handled input node count: " << handled_input_count + << " output node count: " << handled_output_count + << " expanded input count: " << expanded_input_count; + } + return Status::OK(); +} + +} // namespace onnxruntime + +#endif diff --git a/orttraining/orttraining/core/optimizer/compute_optimizer/padding_elimination.h b/orttraining/orttraining/core/optimizer/compute_optimizer/padding_elimination.h new file mode 100644 index 0000000000000..c4f283c30fddc --- /dev/null +++ b/orttraining/orttraining/core/optimizer/compute_optimizer/padding_elimination.h @@ -0,0 +1,141 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include +#include + +#include "core/optimizer/graph_transformer.h" +#include "core/graph/graph_utils.h" +#include "core/optimizer/compute_optimizer/shared_utils.h" + +namespace onnxruntime { + +/** + * @Class PaddingElimination + * + * @brief Graph transformer that eliminates unnecessary padding computation caused by embedding sparsity. + * + * In transformer trainings, input_ids are usually padded to the same length, which is the max sequence length, + * so its shape is [batch_size, sequence_length] or [sequence_length, batch_size]. This graph transformer + * tries to MERGE the leading two dimensions and REMOVE the padding on the merged + * dimension, i.e, [batch_size, sequence_length, ...] -> [batch_size * sequence_length, ...] -> + + * + * This transformer is implemented in the following steps: + * 1. Iterate the graph and find the Embedding node that matches these requirements: + * 1.1 The 2nd input is a graph input and its rank > 2, with the first two dimensions, are: + * [batch_size, sequence_length]. Both dimensions can be symbolic or concrete dim values. + * 1.2 The 3rd input(padding idx) is a scalar constant initializer, and should >= 0. + * 2. Append embedding node in node_to_scan_list. + * Iterate the node_to_scan_list, for each node, + * 2.1 Check if it is supported for pad elimination (from a pre-defined op list). If no, record this node as output + * of the subgraph and continue to next node in node_to_scan_list. + * 2.2 Find all output_args who have dim params inheriting from embedding input ids' dim params (e.g. batch_size and + * sequence_length), if all check passes, append node's output nodes to node_to_scan_list. Otherwise, record this + * node as output of the subgraph and continue to next node in node_to_scan_list. + * 2.3 For input_args that are not affected by embedding output, check the dim params with other input_args that are + * affected by embedding output. If all check passes, append node's output nodes in node_to_scan_list and + * check if it's needed to record the input_args that are not affected by embedding as input of the subgraph + * that will be inserted 'Reshape + ShrunkenGather' pattern later. Otherwise, record this node as output of the + * subgraph and continue to next node in node_to_scan_list. + * 3. Insert pattern of 'Reshape + ShrunkenGather' before each input of the subgraph to eliminate the padding. + * 4. Insert pattern of 'GatherGrad + Reshape' after each output of the subgraph to restore the original shape. + * This is needed to ensure not to affect subsequent computations + * + * For example, given the following graph: + * 1. `input_0` is a tensor that is an in-direct output of ATen embedding node. + * 2. `input_1` is a tensor that is NOT a direct or in-direct output of ATen embedding node. + * + * embed.weight input_ids [batch_size, seq_length] padding_idx [1] scale_grad_by_freq sparse + * \ \ / / / + * \ \ / / / + * \ \ / / / + * \_________________\_________________________/________________/______________________/ + * | + * ATen:embedding + * | + * - - - - - - - - - - - -| + * | | + * input_0 | input_1 + * \ | / + * \__________ | ___________/ + * \ | / + * Subgraph + * + * | + * output + * + * + * After the transformation: + * + * input_ids [batch_size, seq_length] + * | \ + * | \ [-1] padding_idx [1] + * | \ / / + * | Reshape / + * | \ / + * | Sub + * | [-1] | + * | / NonZero + * Reshape | + * \ Squeeze + * \ / + * \ /(valid_token_index) + * \ / + * ShrunkenGather + * embed.weight \ padding_idx [1] scale_grad_by_freq sparse + * \ \ shape:[valid_token] / / / + * \ \ / / / + * \______________________\________________________________/__________________/________________/ + * | + * Aten:embedding + * - - - - - - - - - - - - - - - - - - - - | + * | | + * input_0 | input_1 + * \ [batch_size, seq_length, ...] | | + * \ | [batch_size, seq_length, ...] + * \ [-1] | | + * \ / | | + * Reshape (valid_token_index) | Reshape (valid_token_index) + * \ / | \ / + * ShrunkenGather shape:[valid_token, ...] ShrunkenGather + * \ | / + * shape:[valid_token, ...] \ | / + * \ | / + * candidate_input_node | candidate_input_node + * \ | / + * \ | / + * + * Subgraph + * + * | + * | shape:[valid_token, ...] + * | + * | (valid_token_index) + * | / ________________ (unflatten_dims), shape:[2], + * | / / value:[batch_size, seq_length] + * | / / + * PadAndUnflatten + * | + * | [batch_size, seq_length, ...] + * candidate_output_node + * + * + * + */ +class PaddingElimination : public GraphTransformer { + public: + PaddingElimination(const InlinedHashSet& compatible_execution_providers = {}, + const std::vector& sparse_embedding_input_names = {}) noexcept + : GraphTransformer("PaddingElimination", compatible_execution_providers), + sparse_embedding_input_names_{sparse_embedding_input_names} {} + + Status ApplyImpl(Graph& graph, bool& modified, int graph_level, const logging::Logger& logger) const override; + + private: + std::vector sparse_embedding_input_names_; +}; + +} // namespace onnxruntime diff --git a/orttraining/orttraining/core/optimizer/compute_optimizer/sceloss_compute_optimization.cc b/orttraining/orttraining/core/optimizer/compute_optimizer/sceloss_compute_optimization.cc index 06ac573672d64..71aa1366bceb3 100644 --- a/orttraining/orttraining/core/optimizer/compute_optimizer/sceloss_compute_optimization.cc +++ b/orttraining/orttraining/core/optimizer/compute_optimizer/sceloss_compute_optimization.cc @@ -2,6 +2,7 @@ // Licensed under the MIT License. #ifdef ENABLE_TRAINING + #include #include "orttraining/core/optimizer/compute_optimizer/sceloss_compute_optimization.h" @@ -15,74 +16,17 @@ namespace onnxruntime { -// Put utilities in anonymous namespace. -namespace { -NodeArg* InsertNodesForValidLabelIndices(Graph& graph, Node& node, NodeArg* label_input, NodeArg* reduce_index_input) { - InlinedVector input_args{label_input, reduce_index_input}; - - InlinedVector output_args{&graph.GetOrCreateNodeArg(graph.GenerateNodeArgName("label_sub_result"), - node.MutableInputDefs()[1]->TypeAsProto())}; - - Node& sub_node = graph.AddNode(graph.GenerateNodeName("labels_sub"), "Sub", "label sub padding idx", input_args, - output_args, nullptr, kOnnxDomain); - ORT_ENFORCE(graph.SetOpSchemaFromRegistryForNode(sub_node), "Failed to set op schema for " + sub_node.Name()); - sub_node.SetExecutionProviderType(node.GetExecutionProviderType()); - - auto non_zero_out_arg = &graph.GetOrCreateNodeArg(graph.GenerateNodeArgName("labels_filter_pad_result"), - node.MutableInputDefs()[1]->TypeAsProto()); - - Node& non_zero_node = graph.AddNode(graph.GenerateNodeName("labels_filter_pad"), "NonZero", - "labels filtering padding idx", - {sub_node.MutableOutputDefs()[0]}, - {non_zero_out_arg}, nullptr, kOnnxDomain); - - ORT_ENFORCE(graph.SetOpSchemaFromRegistryForNode(non_zero_node), - "Failed to set op schema for " + non_zero_node.Name()); - - const std::string dim_name = MakeString("valid_label_count_", utils::GetRandomSeed()); - - // 1D input NonZero generates output of shape (1,valid_token_count). - ONNX_NAMESPACE::TensorShapeProto non_zero_output_shape; - non_zero_output_shape.add_dim()->set_dim_value(1); - non_zero_output_shape.add_dim()->set_dim_param(dim_name); - non_zero_out_arg->SetShape(non_zero_output_shape); - non_zero_node.SetExecutionProviderType(node.GetExecutionProviderType()); - - InlinedVector squeeze_input_args; - squeeze_input_args.push_back(non_zero_out_arg); - - bool opset_lower_than_13 = onnxruntime::optimizer::compute_optimizer::GetONNXOpSetVersion(graph) < 13; - onnxruntime::NodeAttributes attributes; - if (opset_lower_than_13) { - attributes["axes"] = ONNX_NAMESPACE::MakeAttribute("axes", std::vector{0}); - } else { - squeeze_input_args.push_back(onnxruntime::optimizer::compute_optimizer::CreateInitializerFromVector( - graph, {1}, {0}, graph.GenerateNodeArgName("axes"))); - } - - auto squeeze_out_arg = &graph.GetOrCreateNodeArg(graph.GenerateNodeArgName("squeeze_adaptor"), - non_zero_out_arg->TypeAsProto()); - Node& squeeze_node = graph.AddNode(graph.GenerateNodeName("squeeze_adaptor"), "Squeeze", "nonzero_squeezer", - squeeze_input_args, {squeeze_out_arg}, &attributes, kOnnxDomain); - ORT_ENFORCE(graph.SetOpSchemaFromRegistryForNode(squeeze_node), - "Failed to set op schema for " + squeeze_node.Name()); - - // After Squeeze, the shape becomes (valid_token_count). - ONNX_NAMESPACE::TensorShapeProto squeeze_output_shape; - squeeze_output_shape.add_dim()->set_dim_param(dim_name); - squeeze_out_arg->SetShape(squeeze_output_shape); - squeeze_node.SetExecutionProviderType(node.GetExecutionProviderType()); - - return squeeze_out_arg; -} -} // namespace - Status InsertGatherBeforeSceLoss::ApplyImpl(Graph& graph, bool& modified, int /*graph_level*/, const logging::Logger& logger) const { LOG_DEBUG_INFO(logger, "Enter InsertGatherBeforeSceLoss"); + if (sparse_label_input_names_.size() == 0) { + LOG_DEBUG_INFO(logger, "Exit InsertGatherBeforeSceLoss, no sparse label input names."); + return Status::OK(); + } + GraphViewer graph_viewer(graph); - size_t handled_sce_node_count = 0; // For summary + [[maybe_unused]] size_t handled_sce_node_count = 0; // For summary const auto& order = graph_viewer.GetNodesInTopologicalOrder(); for (const auto index : order) { auto* node_ptr = graph.GetNode(index); @@ -101,8 +45,10 @@ Status InsertGatherBeforeSceLoss::ApplyImpl(Graph& graph, bool& modified, int /* continue; } + const NodeArg* label_input_arg = node.InputDefs()[1]; + // Check whether this SCE node is handled or not. - const Node* labels_producer = graph.GetProducerNode(node.MutableInputDefs()[1]->Name()); + const Node* labels_producer = graph.GetProducerNode(label_input_arg->Name()); // Skip if already inserted a ShrunkenGather node. if (labels_producer && graph_utils::IsSupportedOptypeVersionAndDomain( *labels_producer, "ShrunkenGather", {1}, kMSDomain)) { @@ -111,6 +57,20 @@ Status InsertGatherBeforeSceLoss::ApplyImpl(Graph& graph, bool& modified, int /* continue; } + // Label input can be a graph input or from a Reshape node taking a graph input as its data input. + if (labels_producer && graph_utils::IsSupportedOptypeVersionAndDomain( + *labels_producer, "Reshape", {1, 5, 13, 14}, kOnnxDomain)) { + label_input_arg = labels_producer->InputDefs()[0]; + } + // Then check if the label input is graph input and in the sparse label input list. + if (!graph.IsInputsIncludingInitializers(label_input_arg) || + std::find(sparse_label_input_names_.begin(), sparse_label_input_names_.end(), + label_input_arg->Name()) == sparse_label_input_names_.end()) { + LOG_DEBUG_INFO(logger, "Skip node " + node.Name() + "(" + node.OpType() + + ") due to labels input is not a graph input or not in the sparse label input list."); + continue; + } + // Check shape requirements. auto logits_shape = node.MutableInputDefs()[0]->Shape(); auto labels_shape = node.MutableInputDefs()[1]->Shape(); @@ -141,7 +101,8 @@ Status InsertGatherBeforeSceLoss::ApplyImpl(Graph& graph, bool& modified, int /* if (node.InputDefs().size() < 4 || !graph_utils::IsConstantInitializer( graph, node.InputDefs()[3]->Name(), /* check_outer_scope */ false)) { LOG_DEBUG_INFO(logger, "Skip node " + node.Name() + "(" + node.OpType() + - ") due to target padding idx is non-constant initializer. Input count: " + std::to_string(node.InputDefs().size())); + ") due to target padding idx is non-constant initializer. Input count: " + + std::to_string(node.InputDefs().size())); continue; } ignore_index_node_arg = node.MutableInputDefs()[3]; @@ -165,7 +126,7 @@ Status InsertGatherBeforeSceLoss::ApplyImpl(Graph& graph, bool& modified, int /* continue; } - // SoftmaxCrossEntropyLossInternal op definition guarantees that the the first dimension of both inputs must match, + // SoftmaxCrossEntropyLossInternal op definition guarantees that the first dimension of both inputs must match, // we don't do the check explicitly here. LOG_DEBUG_INFO(logger, "Inserting Sub+NonZero nodes for filtering valid tokens"); @@ -174,7 +135,7 @@ Status InsertGatherBeforeSceLoss::ApplyImpl(Graph& graph, bool& modified, int /* // subgraph retrieving valid tokens for each SoftmaxCrossEntropyLossInternal node. // The duplication will be removed by CSE graph transformers. NodeArg* valid_labels_input_arg = - InsertNodesForValidLabelIndices(graph, node, node.MutableInputDefs()[1], ignore_index_node_arg); + onnxruntime::optimizer::compute_optimizer::InsertNodesForValidIndices(graph, node.MutableInputDefs()[1], ignore_index_node_arg, node.GetExecutionProviderType()); // Insert the ShrunkenGather node on the two inputs. for (int i = 0; i < 2; ++i) { @@ -217,8 +178,7 @@ Status InsertGatherBeforeSceLoss::ApplyImpl(Graph& graph, bool& modified, int /* handled_sce_node_count += 1; } - LOG_DEBUG_INFO(logger, "Exit InsertGatherBeforeSceLoss, handled " + std::to_string(handled_sce_node_count) + - " SCE nodes"); + LOGS(logger, INFO) << "Total handled SCE node count: " << handled_sce_node_count; return Status::OK(); } diff --git a/orttraining/orttraining/core/optimizer/compute_optimizer/sceloss_compute_optimization.h b/orttraining/orttraining/core/optimizer/compute_optimizer/sceloss_compute_optimization.h index 1ebf1c497d54c..94787aca7cd1c 100644 --- a/orttraining/orttraining/core/optimizer/compute_optimizer/sceloss_compute_optimization.h +++ b/orttraining/orttraining/core/optimizer/compute_optimizer/sceloss_compute_optimization.h @@ -12,10 +12,11 @@ namespace onnxruntime { * @brief Graph transformer that inserts ShrunkenGather before SCE nodes (e.g. * SoftmaxCrossEntropyLossInternal/SoftmaxCrossEntropyLoss nodes). * - * For label sparsity, we can remove them from the compute of loss function, by inserting ShrunkenGather + * For label sparsity, we can remove them from the compute of the loss function, by inserting ShrunkenGather * operators for its two inputs. * * logits (float) [token_count, classes] labels (int64), [token_count] + * \ / * \ / * SCE Node(ignore_index=-100) * / \ @@ -23,14 +24,15 @@ namespace onnxruntime { * * Be noted in Transformer-based models: * > `token_count` usually equals with `batch size` x `sequence length`. - * > `classes` usually equals with `vocabulary`. + * > `classes` is usually equal to `vocabulary`. * - * Only insert ShrunkGather if all following conditions are met for SCE nodes`: + * Only insert ShrunkGather if all the following conditions are met for SCE nodes`: * 1. Its reduction attribute value is 'sum' or 'mean', to make sure loss is a scalar. * Otherwise, the loss is in shape [token_count], changing on `token_count` will affect subsequent computations. - * 2. Its 2nd output (log_prob) MUST NOT be graph output and not consumed by other other nodes. + * 2. Its 2nd output (log_prob) MUST NOT be a graph output and MUST NOT be consumed by other nodes. * 3. Its ignore_index exists and is a constant scalar value. - * 4. Its 2nd input label's input node is not `ShrunkGather` node (to avoid this transformer duplicated applied). + * 4. Its 2nd input label's input node is not a `ShrunkGather` node (to avoid this transformer duplicated applied). + * 5. Its 2nd input label is 1) a graph input or 2) output of a Reshape node taking a graph input as its data input. * * * After the transformation: @@ -60,19 +62,24 @@ namespace onnxruntime { * loss (shape is scalar or [valid_token_count]) log_prob [valid_token_count, classes] * * In this specific scenario, it is easy to infer that valid_token_count <= token_count. - * After insertion, loss computation flop is reduced. Additionally, upstream Gather graph optimization + * After insertion, the loss computation flop is reduced. Additionally, upstream Gather graph optimization * will try to reduce flop for other ops further. */ class InsertGatherBeforeSceLoss : public GraphTransformer { public: - InsertGatherBeforeSceLoss(const InlinedHashSet& compatible_execution_providers = {}) noexcept - : GraphTransformer("InsertGatherBeforeSceLoss", compatible_execution_providers) { + InsertGatherBeforeSceLoss(const InlinedHashSet& compatible_execution_providers = {}, + const std::vector& sparse_label_input_names = {}) noexcept + : GraphTransformer("InsertGatherBeforeSceLoss", compatible_execution_providers), + sparse_label_input_names_{sparse_label_input_names} { } /** * @brief */ Status ApplyImpl(Graph& graph, bool& modified, int graph_level, const logging::Logger& logger) const override; + + private: + std::vector sparse_label_input_names_; }; } // namespace onnxruntime diff --git a/orttraining/orttraining/core/optimizer/graph_transformer_config.h b/orttraining/orttraining/core/optimizer/graph_transformer_config.h index a73830ef1d0b8..cc3edfb016a15 100644 --- a/orttraining/orttraining/core/optimizer/graph_transformer_config.h +++ b/orttraining/orttraining/core/optimizer/graph_transformer_config.h @@ -25,8 +25,14 @@ struct TrainingGraphTransformerConfiguration : public GraphTransformerConfigurat // Enable compute optimizer. bool enable_compute_optimizer{false}; - // Enable label sparsity compute optimization. - bool enable_label_sparsity_optimization{false}; + // Enable embedding sparsity compute optimization for the input names in the below list. + std::vector sparse_embedding_input_names; + + // Enable label sparsity compute optimization for the input names in the below list. + std::vector sparse_label_input_names; + + // Path for serialization of the transformed optimized model. If empty, serialization is disabled. + std::string optimized_pre_grad_filepath; }; } // namespace training diff --git a/orttraining/orttraining/core/optimizer/graph_transformer_utils.cc b/orttraining/orttraining/core/optimizer/graph_transformer_utils.cc index 16103f005904c..6b566ed064aa4 100644 --- a/orttraining/orttraining/core/optimizer/graph_transformer_utils.cc +++ b/orttraining/orttraining/core/optimizer/graph_transformer_utils.cc @@ -53,19 +53,21 @@ #include "orttraining/core/optimizer/bitmask_dropout_replacement.h" #include "orttraining/core/optimizer/concat_replacement.h" #include "orttraining/core/optimizer/graph_transformer_registry.h" +#include "orttraining/core/optimizer/gru_replacement.h" #include "orttraining/core/optimizer/insert_output_rewriter.h" #include "orttraining/core/optimizer/localized_recompute.h" #include "orttraining/core/optimizer/loss_rewriter.h" #include "orttraining/core/optimizer/lstm_replacement.h" #include "orttraining/core/optimizer/transformer_layer_recompute.h" #include "orttraining/core/optimizer/qdq_fusion.h" - -// Only enabled in full training build. Not in on device training builds -#ifdef ENABLE_TRAINING +#include "orttraining/core/optimizer/scaled_sum_fusion.h" +#include "orttraining/core/optimizer/shape_optimizer.h" +#include "orttraining/core/optimizer/transformer_layer_recompute.h" #include "core/optimizer/compute_optimizer/upstream_gather.h" #include "core/optimizer/compute_optimizer/upstream_reshape.h" +#include "core/optimizer/pre_shape_node_elimination.h" +#include "orttraining/core/optimizer/compute_optimizer/padding_elimination.h" #include "orttraining/core/optimizer/compute_optimizer/sceloss_compute_optimization.h" -#endif namespace onnxruntime { namespace training { @@ -94,6 +96,7 @@ std::vector> GeneratePreTrainingTransformers( ORT_THROW_IF_ERROR(rule_transformer->Register(std::make_unique())); ORT_THROW_IF_ERROR(rule_transformer->Register(std::make_unique())); ORT_THROW_IF_ERROR(rule_transformer->Register(std::make_unique())); + ORT_THROW_IF_ERROR(rule_transformer->Register(std::make_unique())); ORT_THROW_IF_ERROR(rule_transformer->Register(std::make_unique())); ORT_THROW_IF_ERROR(rule_transformer->Register(std::make_unique())); ORT_THROW_IF_ERROR(rule_transformer->Register(std::make_unique())); @@ -102,11 +105,14 @@ std::vector> GeneratePreTrainingTransformers( ORT_THROW_IF_ERROR(rule_transformer->Register(std::make_unique())); ORT_THROW_IF_ERROR(rule_transformer->Register(std::make_unique())); ORT_THROW_IF_ERROR(rule_transformer->Register(std::make_unique())); + ORT_THROW_IF_ERROR(rule_transformer->Register(std::make_unique())); // Put ConstantSharing before CommonSubexpressionElimination by intention as it can create more opportunities for // CSE. For example, if A and B nodes both do Add operation with a same value but different initializers, by // default, CSE will not merge them, because the different initializers are represented by different NodeArg. transformers.emplace_back(std::make_unique(compatible_eps)); + // LayerNormFusion must be applied before CommonSubexpressionElimination as the latter will break the pattern when 2 LayerNormFusion share the same input. + transformers.emplace_back(std::make_unique(compatible_eps)); // Remove duplicate nodes. Must be applied before any recompute transformations. if (config.gelu_recompute || config.attn_dropout_recompute || config.transformer_layer_recompute) { transformers.emplace_back(std::make_unique(compatible_eps)); @@ -115,7 +121,6 @@ std::vector> GeneratePreTrainingTransformers( } transformers.emplace_back(std::make_unique(compatible_eps)); - transformers.emplace_back(std::make_unique(compatible_eps)); #if defined(USE_CUDA) || defined(USE_ROCM) transformers.emplace_back(std::make_unique(compatible_eps, true /* skip_device_check*/)); @@ -132,10 +137,12 @@ std::vector> GeneratePreTrainingTransformers( transformers.emplace_back(std::make_unique(compatible_eps)); #if defined(USE_CUDA) || defined(USE_ROCM) - // We are supposed to use execution provider as indicator, but here we don't have access to the registered EP at this point + // We are supposed to use the execution provider as an indicator, + // but here we don't have access to the registered EP at this point // as the session is not initialized yet. So using macro for now. transformers.emplace_back(std::make_unique(compatible_eps)); transformers.emplace_back(std::make_unique(compatible_eps)); + transformers.emplace_back(std::make_unique(compatible_eps)); #endif if (config.enable_gelu_approximation) { @@ -145,6 +152,10 @@ std::vector> GeneratePreTrainingTransformers( transformers.emplace_back(std::make_unique( execution_provider, false /*skip_dequantize_linear*/, compatible_eps, excluded_initializers)); transformers.emplace_back(std::make_unique(compatible_eps)); + // Put fine-grained optimizer (e.g. ShapeOptimizer) after ReshapeFusion to avoid it breaks the strong patterns + // it defines. ReshapeFusion depends on subgraph pattern matching and do replacement accordingly, ShapeOptimizer + // potentially will optimize out some nodes defined in the subgraph patterns. So we put it after ReshapeFusion. + transformers.emplace_back(std::make_unique(compatible_eps)); transformers.emplace_back(std::make_unique(compatible_eps)); if (config.gelu_recompute) { @@ -166,15 +177,18 @@ std::vector> GeneratePreTrainingTransformers( cuda_execution_provider)); } -#ifdef ENABLE_TRAINING if (config.enable_compute_optimizer) { transformers.emplace_back(std::make_unique(compatible_eps)); - if (config.enable_label_sparsity_optimization) { - transformers.emplace_back(std::make_unique(compatible_eps)); - transformers.emplace_back(std::make_unique(compatible_eps)); - } - } + transformers.emplace_back(std::make_unique(compatible_eps)); + transformers.emplace_back(std::make_unique(compatible_eps, + config.sparse_label_input_names)); +#if defined(USE_CUDA) || defined(USE_ROCM) + // Put this under CUDA/ROCM guard as it depends on PadAndUnflatten CUDA/ROCM kernel. + // Once we have a CPU kernel for PadAndUnflatten, we can remove the guard. + transformers.emplace_back(std::make_unique(compatible_eps, + config.sparse_embedding_input_names)); #endif + } } break; diff --git a/orttraining/orttraining/core/optimizer/gru_replacement.cc b/orttraining/orttraining/core/optimizer/gru_replacement.cc new file mode 100644 index 0000000000000..c4b3a5cfdabb0 --- /dev/null +++ b/orttraining/orttraining/core/optimizer/gru_replacement.cc @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "orttraining/core/optimizer/gru_replacement.h" + +#include "core/graph/graph.h" +#include "core/graph/graph_utils.h" + +namespace onnxruntime { + +Status GRUReplacement::Apply(Graph& graph, Node& gru_node, RewriteRuleEffect& rule_effect, const logging::Logger&) const { + const auto& gru_inputs = gru_node.MutableInputDefs(); + auto& gru_outputs = gru_node.MutableOutputDefs(); + + const auto* type_proto = gru_inputs.front()->TypeAsProto(); + ORT_ENFORCE(type_proto && type_proto->has_tensor_type() && type_proto->tensor_type().has_elem_type(), + "Could not decipher the type of input to GRU node: ", gru_node.Name()); + + ONNX_NAMESPACE::TypeProto gru_input_type; + gru_input_type.mutable_tensor_type()->set_elem_type(type_proto->tensor_type().elem_type()); + + if (gru_outputs.empty() || !gru_outputs[0]->Exists()) { + // Add all GRU cell optional outputs for computation even if not required to ensure all outputs are computed + // so that gradient computation can pick them up. + NodeArg& all_hidden_states = graph.GetOrCreateNodeArg(graph.GenerateNodeArgName("all_hidden_states"), + &gru_input_type); + if (!gru_outputs.empty()) { + gru_outputs[0] = &all_hidden_states; + } else { + gru_outputs.push_back(&all_hidden_states); + } + } + + if (gru_outputs.size() == 1U) { + NodeArg& placeholder = graph.GetOrCreateNodeArg("", nullptr); + gru_outputs.push_back(&placeholder); + } + + NodeArg& zrh = graph.GetOrCreateNodeArg(graph.GenerateNodeArgName("zrh"), &gru_input_type); + gru_outputs.push_back(&zrh); + + // GRUTraining should have 3 outputs + ORT_ENFORCE(gru_node.OutputDefs().size() == 3U); + + auto gru_attributes = gru_node.GetAttributes(); + gru_attributes.erase("layout"); + + Node& gru_training_node = graph.AddNode(graph.GenerateNodeName(gru_node.Name() + "_training"), + "GRUTraining", + "GRU with extra outputs needed for gradient computation.", + gru_inputs, + gru_outputs, + &gru_attributes, // AddNode makes a copy, so ok to pass pointer to local var + kMSDomain); + + // Assign provider to this new node. Provider should be same as the provider for the node being replaced. + gru_training_node.SetExecutionProviderType(gru_node.GetExecutionProviderType()); + graph_utils::FinalizeNodeFusion(graph, gru_training_node, gru_node); + rule_effect = RewriteRuleEffect::kRemovedCurrentNode; + return Status::OK(); +} + +bool GRUReplacement::SatisfyCondition(const Graph&, const Node&, const logging::Logger&) const { + return true; +} + +} // namespace onnxruntime diff --git a/orttraining/orttraining/core/optimizer/gru_replacement.h b/orttraining/orttraining/core/optimizer/gru_replacement.h new file mode 100644 index 0000000000000..6447563bedb3c --- /dev/null +++ b/orttraining/orttraining/core/optimizer/gru_replacement.h @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/optimizer/rewrite_rule.h" + +namespace onnxruntime { + +/** +@Class GRUReplacement + +This transformer is used when an GRU model is used for training. Training requires +extra set of outputs from the GRU cell that it needs to use during gradient computation. +So, this transformer will replace the existing GRU cell with the GRUTraining cell. + +The extra output that the GRUTraining generates are: +ZRH intermediate gate computations needed for gradient computation. + +*/ + +class GRUReplacement : public RewriteRule { + public: + GRUReplacement() noexcept : RewriteRule("GRUReplacement") {} + + std::vector TargetOpTypes() const noexcept override { + return {"GRU"}; + } + + private: + bool SatisfyCondition(const Graph& graph, const Node& node, const logging::Logger& logger) const override; + + Status Apply(Graph& graph, Node& node, RewriteRuleEffect& rule_effect, const logging::Logger& logger) const override; +}; + +} // namespace onnxruntime diff --git a/orttraining/orttraining/core/optimizer/lstm_replacement.cc b/orttraining/orttraining/core/optimizer/lstm_replacement.cc index 9ff83706e7d33..dcf91c3c10c68 100644 --- a/orttraining/orttraining/core/optimizer/lstm_replacement.cc +++ b/orttraining/orttraining/core/optimizer/lstm_replacement.cc @@ -51,13 +51,13 @@ Status LSTMReplacement::Apply(Graph& graph, Node& lstm_node, RewriteRuleEffect& Node& lstm_training_node = graph.AddNode(graph.GenerateNodeName(lstm_node.Name() + "_training"), "LSTMTraining", - "LSTM with extra outputs for needed for gradient computation.", + "LSTM with extra outputs needed for gradient computation.", lstm_inputs, lstm_outputs, &lstm_attributes, // AddNode makes a copy, so ok to pass pointer to local var kMSDomain); - // Assign provider to this new node. Provider should be same as the provider for old node. + // Assign provider to this new node. Provider should be same as the provider for node being replaced. lstm_training_node.SetExecutionProviderType(lstm_node.GetExecutionProviderType()); graph_utils::FinalizeNodeFusion(graph, lstm_training_node, lstm_node); rule_effect = RewriteRuleEffect::kRemovedCurrentNode; diff --git a/orttraining/orttraining/core/optimizer/megatron_transformer.cc b/orttraining/orttraining/core/optimizer/megatron_transformer.cc index 967043d7dbbbc..4ebea5cf386cc 100644 --- a/orttraining/orttraining/core/optimizer/megatron_transformer.cc +++ b/orttraining/orttraining/core/optimizer/megatron_transformer.cc @@ -203,6 +203,7 @@ bool MegatronTransformer::PartitionWeightByColumn(const Graph& graph, const Node if (optim_state_it != initial_optimizer_states_.end()) { auto& initial_states = optim_state_it->second; // partition moments same way as the weight + auto alloc = cpu_execution_provider_.CreatePreferredAllocators()[0]; for (const auto& moments_prefix : training::MOMENTS_PREFIXES) { const auto initial_state_it = initial_states.find(moments_prefix); if (initial_state_it != initial_states.end()) { @@ -230,7 +231,6 @@ bool MegatronTransformer::PartitionWeightByColumn(const Graph& graph, const Node // Allocate a new buffer to hold the partitioned optimizer state // as column partitioning cannot re-use the original // buffer as it is a non-contiguous read - auto alloc = cpu_execution_provider_.GetAllocator(OrtMemTypeDefault); p_tensor = std::make_unique(element_type, partition_shape, alloc); @@ -246,7 +246,6 @@ bool MegatronTransformer::PartitionWeightByColumn(const Graph& graph, const Node // allocate a new buffer as column partitioning cannot re-use the original // buffer as it is a non-contiguous read on original buffer - auto alloc = cpu_execution_provider_.GetAllocator(OrtMemTypeDefault); p_tensor = std::make_unique(element_type, partition_shape, alloc); @@ -961,7 +960,7 @@ Status MegatronTransformer::TransformBARTAttention(Graph& graph, bool& modified, return skip_status; } // map between reshape node and dim of reshape that must be modified - std::unordered_map reshape_node_ptrs; + std::unordered_map reshape_node_ptrs; reshape_node_ptrs[sub_graph_node_ptrs[sub_graph_node_ptrs.size() - 16]] = 1; reshape_node_ptrs[sub_graph_node_ptrs[sub_graph_node_ptrs.size() - 12]] = 1; reshape_node_ptrs[sub_graph_node_ptrs[sub_graph_node_ptrs.size() - 10]] = 0; @@ -1055,7 +1054,7 @@ Status MegatronTransformer::TransformBARTAttention(Graph& graph, bool& modified, bool is_reshape_valid = true; for (auto x : reshape_node_ptrs) { Node* node_ptr = x.first; - int64_t idx = x.second; + auto idx = x.second; auto shape_arg = node_ptr->MutableInputDefs()[1]; const ONNX_NAMESPACE::TensorProto* tensor; if (!graph.GetInitializedTensor(shape_arg->Name(), tensor)) { diff --git a/orttraining/orttraining/core/optimizer/megatron_transformer.h b/orttraining/orttraining/core/optimizer/megatron_transformer.h index aeb5397a14ea5..10330871efc00 100644 --- a/orttraining/orttraining/core/optimizer/megatron_transformer.h +++ b/orttraining/orttraining/core/optimizer/megatron_transformer.h @@ -16,7 +16,7 @@ class MegatronTransformer : public GraphTransformer { std::unordered_set& weights_to_train, std::unordered_map& weight_partition_info, training::TrainingSession::OptimizerState& initial_optimizer_states, - const IExecutionProvider& cpu_execution_provider, // Required to get allocator for optimizer partitioning by Col + IExecutionProvider& cpu_execution_provider, // Required to get allocator for optimizer partitioning by Col const InlinedHashSet& compatible_execution_providers = {}) noexcept : GraphTransformer("MegatronTransformer", compatible_execution_providers), horizontal_parallel_rank_(horizontal_parallel_rank), @@ -88,7 +88,7 @@ class MegatronTransformer : public GraphTransformer { std::unordered_set& weights_to_train_; std::unordered_map& weight_partition_info_; training::TrainingSession::OptimizerState& initial_optimizer_states_; - const IExecutionProvider& cpu_execution_provider_; + IExecutionProvider& cpu_execution_provider_; }; -} // namespace onnxruntime \ No newline at end of file +} // namespace onnxruntime diff --git a/orttraining/orttraining/core/optimizer/qdq_fusion.cc b/orttraining/orttraining/core/optimizer/qdq_fusion.cc index d5db31e87fde8..fc9a6d213f794 100644 --- a/orttraining/orttraining/core/optimizer/qdq_fusion.cc +++ b/orttraining/orttraining/core/optimizer/qdq_fusion.cc @@ -83,7 +83,7 @@ std::pair CheckForQDQPatternMatch(Graph& graph, Node& quantize_node const InlinedHashSet& compatible_execution_providers) { // Try to match the current node with QuantizeLinear in the effort of searching for the pattern // QuantizeLinear -> DequantizeLinear. - if (!graph_utils::IsSupportedOptypeVersionAndDomain(quantize_node, "QuantizeLinear", {10, 13}) || + if (!graph_utils::IsSupportedOptypeVersionAndDomain(quantize_node, "QuantizeLinear", {10, 13, 19}) || !graph_utils::IsSupportedProvider(quantize_node, compatible_execution_providers)) { return {false, nullptr}; } diff --git a/orttraining/orttraining/core/optimizer/scaled_sum_fusion.cc b/orttraining/orttraining/core/optimizer/scaled_sum_fusion.cc new file mode 100644 index 0000000000000..dcb3abf2474d3 --- /dev/null +++ b/orttraining/orttraining/core/optimizer/scaled_sum_fusion.cc @@ -0,0 +1,262 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "orttraining/core/optimizer/scaled_sum_fusion.h" + +#include +#include "core/graph/graph_utils.h" +#include "core/optimizer/initializer.h" +#include "core/optimizer/utils.h" + +namespace onnxruntime { + +namespace { + +// Supports limited data types. +static constexpr std::array supported_data_types{ + ONNX_NAMESPACE::TensorProto_DataType_FLOAT16, + ONNX_NAMESPACE::TensorProto_DataType_FLOAT, +}; + +bool IsSupportedDataType(int32_t data_type) { + return std::find(supported_data_types.cbegin(), supported_data_types.cend(), data_type) != + supported_data_types.cend(); +} + +bool IsShapeEqual(const ONNX_NAMESPACE::TensorShapeProto* lhs_shape, + const ONNX_NAMESPACE::TensorShapeProto* rhs_shape) { + ORT_ENFORCE(lhs_shape != nullptr && rhs_shape != nullptr); + + if (lhs_shape->dim_size() != rhs_shape->dim_size()) { + return false; + } + + for (int i = 0; i < lhs_shape->dim_size(); ++i) { + if (lhs_shape->dim(i).has_dim_value() && rhs_shape->dim(i).has_dim_value()) { + if (lhs_shape->dim(i).dim_value() != rhs_shape->dim(i).dim_value()) { + return false; + } + } else if (lhs_shape->dim(i).has_dim_param() && rhs_shape->dim(i).has_dim_param()) { + if (lhs_shape->dim(i).dim_param() != rhs_shape->dim(i).dim_param()) { + return false; + } + } else { + return false; + } + } + + return true; +} + +bool IsScaleOperator(Graph& graph, Node& node, + const ONNX_NAMESPACE::TensorShapeProto* output_shape, + float& scale_value) { + if (graph_utils::IsSupportedOptypeVersionAndDomain(node, "Div", {7, 13, 14})) { + // If node is Div, check: + // 1. The first input has the same shape as the given output_shape. + // 2. The second input is a constant initializer (containing a scalar or 1-D 1-element tensor). + bool first_input_check = (node.InputDefs()[0]->Shape() && + IsShapeEqual(node.InputDefs()[0]->Shape(), output_shape)); + + if (first_input_check) { + const Node* div_input_2 = graph_utils::GetInputNode(node, 1); + auto div_input_2_shape = node.InputDefs()[1]->Shape(); + bool second_input_check = div_input_2 == nullptr && div_input_2_shape && + graph_utils::IsConstantInitializer(graph, node.InputDefs()[1]->Name(), false) && + (div_input_2_shape->dim_size() == 0 // scalar + || (div_input_2_shape->dim_size() == 1 && + div_input_2_shape->dim(0).has_dim_value() && + div_input_2_shape->dim(0).dim_value() == 1) /* 1d with 1 element */); + + if (second_input_check) { + const ONNX_NAMESPACE::TensorProto* tensor_proto = nullptr; + if (!graph.GetInitializedTensor(node.InputDefs()[1]->Name(), tensor_proto)) { + return false; + } + + Initializer init_const{*tensor_proto, graph.ModelPath()}; + const auto data_type = tensor_proto->data_type(); + if (data_type == ONNX_NAMESPACE::TensorProto_DataType_FLOAT16) { + const MLFloat16* val = init_const.data(); + scale_value = 1.0f / math::halfToFloat(val[0].val); + } else if (data_type == ONNX_NAMESPACE::TensorProto_DataType_FLOAT) { + scale_value = 1.0f / *init_const.data(); + } else { + return false; + } + + return true; + } + } + } + return false; +} + +} // namespace + +Status ScaledSumFusion::ApplyImpl(Graph& graph, bool& modified, int /*graph_level*/, + const logging::Logger& logger) const { + GraphViewer graph_viewer(graph); + + [[maybe_unused]] size_t handled_scaled_sum_count = 0; // For summary + const auto& order = graph_viewer.GetNodesInTopologicalOrder(); + for (const auto index : order) { + auto* node_ptr = graph.GetNode(index); + if (!node_ptr) + // node was removed. + continue; + + auto& node = *node_ptr; + // Find an Add that takes two inputs from other nodes' outputs (instead of any graph inputs or initializers). + // We also don't allow Add is generating graph outputs. + if (!graph_utils::IsSupportedOptypeVersionAndDomain(node, "Add", {6, 7, 13, 14}) || + node.GetInputEdgesCount() != 2 /* two input MUST come from other nodes' outputs */ || + graph.IsOutput(node.OutputDefs()[0]) || + !graph_utils::IsSupportedProvider(node, GetCompatibleExecutionProviders())) { + continue; + } + + const ONNX_NAMESPACE::TensorShapeProto* output_shape = node.OutputDefs()[0]->Shape(); + const ONNX_NAMESPACE::TypeProto* output_type = node.OutputDefs()[0]->TypeAsProto(); + if (!output_shape || !output_type) { + continue; + } + + int elem_type = output_type->tensor_type().elem_type(); + if (!IsSupportedDataType(elem_type)) { + continue; + } + + InlinedVector data_input_args; + InlinedVector scales; + data_input_args.reserve(3); + scales.reserve(3); + InlinedVector> nodes_to_remove; + + // Be noted: it is possible the two input nodes are from the same node. + const Node* add_input_0 = graph_utils::GetInputNode(node, 0); + const Node* add_input_1 = graph_utils::GetInputNode(node, 1); + if (add_input_0 == nullptr || add_input_1 == nullptr) { + continue; + } + + // Check the two inputs nodes of Add, if they are scaled operators, add them to the node list to remove. + auto check_add_input = [&graph, &output_shape, &nodes_to_remove, + &data_input_args, &scales](Node* add_input_node) -> bool { + float scale_value = 1.0f; + if (!IsScaleOperator(graph, *add_input_node, output_shape, scale_value)) { + return false; + } + + // If node is not in nodes_to_remove, add it. + auto it = std::find_if(nodes_to_remove.begin(), nodes_to_remove.end(), + [&add_input_node](std::reference_wrapper n) { + return ((Node&)n).Index() == add_input_node->Index(); + }); + if (it == nodes_to_remove.end()) { + nodes_to_remove.push_back(*add_input_node); + } + + data_input_args.push_back(add_input_node->MutableInputDefs()[0]); + scales.push_back(scale_value); + + return true; + }; + + Node* add_input_node_0 = graph.GetNode(add_input_0->Index()); + Node* add_input_node_1 = graph.GetNode(add_input_1->Index()); + if (!check_add_input(add_input_node_0) || !check_add_input(add_input_node_1)) { + continue; + } + + Node* last_node = &node; + // Handle three inputs only when Add node has one single consumer; and be noted we already check earlier + // the output is not in graph outputs. + if (node.GetOutputEdgesCount() == 1) { + Node& output_node = *graph.GetNode(node.OutputEdgesBegin()->GetNode().Index()); + int output_node_port = node.OutputEdgesBegin()->GetDstArgIndex(); + // Find the next Add node that use the output of current Add node as one of its inputs. + if (graph_utils::IsSupportedOptypeVersionAndDomain(output_node, "Add", {6, 7, 13, 14}) && + !graph.IsOutput(output_node.OutputDefs()[0]) /* this Add cannot generate graph output */ + ) { + int the_other_input_port = 1 - output_node_port; + NodeArg* the_other_input_arg = output_node.MutableInputDefs()[the_other_input_port]; + const Node* the_other_input_node = graph.GetProducerNode(the_other_input_arg->Name()); + Node* mutable_the_other_input_node = the_other_input_node + ? graph.GetNode(the_other_input_node->Index()) + : nullptr; + + bool the_other_node_output_edge_check = mutable_the_other_input_node == nullptr || + mutable_the_other_input_node->GetOutputEdgesCount() == 1; + + // Also make sure the other input arg has Shape equal to output_shape, we don't want to + // handle broadcast cases now. + if (the_other_node_output_edge_check && + the_other_input_arg->Shape() && IsShapeEqual(the_other_input_arg->Shape(), output_shape)) { + last_node = &output_node; + nodes_to_remove.push_back(node); + + float scale_value = 1.0f; + if (mutable_the_other_input_node && IsScaleOperator(graph, *mutable_the_other_input_node, + output_shape, scale_value)) { + data_input_args.push_back(mutable_the_other_input_node->MutableInputDefs()[0]); + nodes_to_remove.push_back(*mutable_the_other_input_node); + scales.push_back(scale_value); + } else { + // The other input is 1). a constant initializer or graph input, OR 2). it is not a scale operator: + // then we only add node arg into data input args, NOT need add any mode into nodes_to_remove. + data_input_args.push_back(mutable_the_other_input_node->MutableInputDefs()[0]); + scales.push_back(scale_value); + } + } + } + } + + if (data_input_args.size() != scales.size() || data_input_args.size() < 2) { + continue; + } + + auto type_info = *output_type; + InlinedVector output_args{&graph.GetOrCreateNodeArg(graph.GenerateNodeArgName("ScaledSum"), &type_info)}; + Node& scaled_sum_node = graph.AddNode(graph.GenerateNodeName("ScaledSum"), + "ScaledSum", + "FusedScaledSum", + data_input_args, + output_args, + nullptr, + kMSDomain); + ORT_ENFORCE(graph.SetOpSchemaFromRegistryForNode(scaled_sum_node), + "Failed to set op schema for " + scaled_sum_node.Name()); + scaled_sum_node.SetExecutionProviderType(last_node->GetExecutionProviderType()); + + for (size_t scale_index = 0; scale_index < scales.size(); ++scale_index) { + scaled_sum_node.AddAttribute("scale_" + std::to_string(scale_index), scales[scale_index]); + } + + graph_utils::ReplaceDownstreamNodeInput(graph, *last_node, 0, scaled_sum_node, 0); + + // Firstly remove the node itself. + graph_utils::RemoveNodeOutputEdges(graph, *last_node); + graph.RemoveNode(last_node->Index()); + + // Then remove the parent nodes that may not be used by other nodes. + for (auto it = nodes_to_remove.rbegin(); it != nodes_to_remove.rend(); ++it) { + Node& n = *it; + if (n.GetOutputEdgesCount() != 0) { + continue; + } + + graph_utils::RemoveNodeOutputEdges(graph, n); + graph.RemoveNode(n.Index()); + } + + modified = true; + handled_scaled_sum_count += 1; + } + + LOGS(logger, INFO) << "Total fused ScaledSum node count: " << handled_scaled_sum_count; + + return Status::OK(); +} + +} // namespace onnxruntime diff --git a/orttraining/orttraining/core/optimizer/scaled_sum_fusion.h b/orttraining/orttraining/core/optimizer/scaled_sum_fusion.h new file mode 100644 index 0000000000000..d91c32498d2d3 --- /dev/null +++ b/orttraining/orttraining/core/optimizer/scaled_sum_fusion.h @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/optimizer/graph_transformer.h" + +namespace onnxruntime { + +/* +Fuse continuous Add without broadcasting into ScaledSum. + +Here is the pattern to find and fuse: + + input_0 scale_0 input_1 scale_1 + \ / \ / + Div Div + \ / + \ / + input_2 Add + \ / + Add + | + +scale_0 and scale_1 +> 1). MUST be scalar or single element 1D tensors, +> 2). and MUST be constant initializers. + +==> + + input_0 input_1 input_2 + \ | / + ScaledSum +(attribute: scale_0=1/scale_0, scale_1=1/scale_1, scale_2=1) + | + +**/ +class ScaledSumFusion : public GraphTransformer { + public: + explicit ScaledSumFusion(const InlinedHashSet& compatible_execution_providers = {}) noexcept + : GraphTransformer("ScaledSumFusion", compatible_execution_providers) { + } + + Status ApplyImpl(Graph& graph, bool& modified, int graph_level, const logging::Logger& logger) const override; +}; + +} // namespace onnxruntime diff --git a/orttraining/orttraining/core/optimizer/sce_loss_grad_bias_fusion.cc b/orttraining/orttraining/core/optimizer/sce_loss_grad_bias_fusion.cc index c4af401d93b3c..84bf715c7c85a 100644 --- a/orttraining/orttraining/core/optimizer/sce_loss_grad_bias_fusion.cc +++ b/orttraining/orttraining/core/optimizer/sce_loss_grad_bias_fusion.cc @@ -34,7 +34,7 @@ Status SceLossGradBiasFusion::ApplyImpl(Graph& graph, bool& modified, int graph_ NodeArg* sce_grad_def = node.MutableOutputDefs()[0]; Node* p_next = graph.GetNode(node.OutputNodesBegin()->Index()); Node* p_reshape = nullptr; - if (graph_utils::IsSupportedOptypeVersionAndDomain(*p_next, "Reshape", {5, 13, 14}) && + if (graph_utils::IsSupportedOptypeVersionAndDomain(*p_next, "Reshape", {5, 13, 14, 19}) && graph_utils::IsSupportedProvider(*p_next, GetCompatibleExecutionProviders()) && p_next->GetOutputEdgesCount() == 1) { p_reshape = p_next; diff --git a/orttraining/orttraining/core/optimizer/shape_optimizer.cc b/orttraining/orttraining/core/optimizer/shape_optimizer.cc new file mode 100644 index 0000000000000..9296e8ef20ac4 --- /dev/null +++ b/orttraining/orttraining/core/optimizer/shape_optimizer.cc @@ -0,0 +1,369 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "orttraining/core/optimizer/shape_optimizer.h" + +#include + +#include "core/common/inlined_containers.h" +#include "core/framework/tensorprotoutils.h" +#include "core/graph/graph_utils.h" +#include "core/optimizer/utils.h" + +using namespace onnxruntime::common; + +namespace onnxruntime { + +// TODO(pengwa): better way (instead of defining MACROs locally) to enable detailed debug logs +// for some specific graph transformers. +// Uncomment to log debug info for SO(Shape Optimizer). +// #define NEED_SO_LOG_DEBUG_INFO 1 + +#ifndef SO_LOG_DEBUG_INFO +#ifdef NEED_SO_LOG_DEBUG_INFO +#define SO_LOG_DEBUG_INFO(logger, message) LOGS(logger, WARNING) << message +#else +#define SO_LOG_DEBUG_INFO(logger, message) \ + ORT_UNUSED_PARAMETER(logger); \ + do { \ + } while (0) +#endif +#endif + +// Put utilities into an anonymous namespace. +namespace { + +constexpr int64_t NormalizeIndex(int64_t initial_index_value, int64_t rank) { + // Negative handling + int64_t non_negative_index = initial_index_value < 0 ? initial_index_value + rank : initial_index_value; + + // Clamp to [0, rank]. + if (non_negative_index < 0) { + non_negative_index = 0; + } else if (non_negative_index > rank) { + non_negative_index = rank; + } + + return non_negative_index; +} + +bool IsSingleValue1DShape(const ONNX_NAMESPACE::TensorShapeProto* input_shape) { + if (input_shape == nullptr) { + return false; + } + + size_t dim_size = static_cast(input_shape->dim_size()); + if (dim_size == 1 && utils::HasDimValue(input_shape->dim(0)) && input_shape->dim(0).dim_value() == 1) { + return true; + } + + return false; +} + +bool CanShapeNodeBeReplacedWithConstant(const Node& shape_node, const TensorShapeVector& dim_values, + TensorShapeVector& fold_values) { + int64_t data_rank = static_cast(dim_values.size()); + int64_t start = 0; + int64_t end = data_rank; // end is exclusive + if (graph_utils::IsSupportedOptypeVersionAndDomain(shape_node, "Shape", {15, 19})) { + // Opset-15 Shape supports slicing using a 'start' and 'end' attribute + const auto& shape_attributes = shape_node.GetAttributes(); + for (const auto& attr : shape_attributes) { + if (attr.first == "start") { + start = attr.second.i(); + } else if (attr.first == "end") { + end = attr.second.i(); + } + } + } + + int64_t start_index_normalized = NormalizeIndex(start, data_rank); + int64_t end_index_normalized = NormalizeIndex(end, data_rank); + + int64_t slice_length = end_index_normalized - start_index_normalized; + slice_length = slice_length < 0 ? 0 : slice_length; + + fold_values.clear(); + fold_values.reserve(slice_length); + for (int64_t i = start_index_normalized; i < end_index_normalized; ++i) { + if (dim_values[i] == -1) { + // Return false if it contains symbolic dim values. + return false; + } else { + fold_values.push_back(dim_values[i]); + } + } + + return true; +} + +bool CanSliceNodeBeReplacedWithConstant(const Graph& graph, const Node& slice_node, + const TensorShapeVector& dim_values, + TensorShapeVector& fold_values) { + const NodeArg* starts_input = slice_node.InputDefs()[1]; + const NodeArg* ends_input = slice_node.InputDefs()[2]; + const NodeArg* axes_input = slice_node.InputDefs().size() > 3 ? slice_node.InputDefs()[3] : nullptr; + const NodeArg* steps_input = slice_node.InputDefs().size() > 4 ? slice_node.InputDefs()[4] : nullptr; + + // TODO: We support with some constraints currently, can be extended further to support other cases. + // Support cases: + // 1. starts/ends/axes/steps are all single-value 1D tensors, axes=[0] and steps=[1]. + // 2. starts/ends are single-value 1D tensors, axes/steps are not provided, (default value: axes=[0] and steps=[1]). + if (!IsSingleValue1DShape(starts_input->Shape()) || + !IsSingleValue1DShape(ends_input->Shape()) || + (axes_input && !IsSingleValue1DShape(axes_input->Shape())) || + (steps_input && !IsSingleValue1DShape(steps_input->Shape()))) { + return false; + } + + // Try to parse the value and double-check. + InlinedVector starts_values, ends_values, axes_values, steps_values; + if (!(optimizer_utils::AppendTensorFromInitializer(graph, *starts_input, starts_values, true) && + starts_values.size() == 1)) { + return false; + } + if (!(optimizer_utils::AppendTensorFromInitializer(graph, *ends_input, ends_values, true) && + ends_values.size() == 1)) { + return false; + } + if (axes_input && !(optimizer_utils::AppendTensorFromInitializer(graph, *axes_input, axes_values, true) && + axes_values.size() == 1 && axes_values[0] == 0)) { + return false; + } + if (steps_input && !(optimizer_utils::AppendTensorFromInitializer(graph, *steps_input, steps_values, true) && + steps_values.size() == 1 && steps_values[0] == 1)) { + return false; + } + + int64_t start = starts_values[0]; + int64_t end = ends_values[0]; + + int64_t data_rank = static_cast(dim_values.size()); + int64_t start_index_normalized = NormalizeIndex(start, data_rank); + int64_t end_index_normalized = NormalizeIndex(end, data_rank); + + int64_t slice_length = end_index_normalized - start_index_normalized; + slice_length = slice_length < 0 ? 0 : slice_length; + fold_values.clear(); + fold_values.reserve(slice_length); + for (int64_t i = start_index_normalized; i < end_index_normalized; ++i) { + if (dim_values[i] == -1) { + // Return false if it contains symbolic dim values. + return false; + } else { + fold_values.push_back(dim_values[i]); + } + } + + return true; +} + +bool CanGatherNodeBeReplacedWithConstant(const Graph& graph, const Node& gather_node, + const TensorShapeVector& dim_values, + TensorShapeVector& fold_values, int& gather_output_rank) { + const NodeArg* data_input = gather_node.InputDefs()[0]; + + // TODO: We support with some constraints currently, can be extended further to support other cases. + // Support cases: + // 1. data is 1D tensor, indices is a scalar, axis=0. + // 2. data is 1D tensor, indices is a scalar, axis=0 or axis is not provided (default value: axis=0). + // 3. data is 1D tensor, indices is 1D tensor with single element, axis=0. + // 4. data is 1D tensor, indices is 1D tensor with single element, axis is not provided (default value: axis=0). + + // Gather's input MUST be 1D tensor. + if (!data_input->Shape() || data_input->Shape()->dim_size() != 1) { + return false; + } + + const NodeArg* indices_input = gather_node.InputDefs()[1]; + auto indices_shape = indices_input->Shape(); + // Indices can be 1D tensor or scalar. + if (!indices_shape || !(indices_shape->dim_size() == 0 || IsSingleValue1DShape(indices_shape))) { + // If the indices did not contain one single element, then skip it. + return false; + } + + // Try to parse int64 type constant initializers. + InlinedVector indices_values; + if (!(optimizer_utils::AppendTensorFromInitializer(graph, *indices_input, indices_values, true) && + indices_values.size() == 1)) { + return false; + } + + const ONNX_NAMESPACE::AttributeProto* axis_attr = graph_utils::GetNodeAttribute(gather_node, "axis"); + if (axis_attr && static_cast(axis_attr->i()) != 0) { + return false; + } + + int64_t start = indices_values[0]; + int64_t data_rank = static_cast(dim_values.size()); + int64_t start_index_normalized = NormalizeIndex(start, data_rank); + + if (dim_values[static_cast(start_index_normalized)] == -1) { + // Return false if it contains symbolic dim values. + return false; + } else { + fold_values.push_back(dim_values[static_cast(start_index_normalized)]); + } + + gather_output_rank = data_input->Shape()->dim_size() + indices_shape->dim_size() - 1; + return true; +} + +void UpdateNodeArgToConstant(Graph& graph, NodeArg* arg_to_update, const TensorShapeVector& values, + bool create_scalar_for_single_value = false) { + size_t length = values.size(); + bool is_scalar = length == 1 && create_scalar_for_single_value; + + // Create new TensorProto. + ONNX_NAMESPACE::TensorProto constant_tensor_proto; + constant_tensor_proto.set_name(arg_to_update->Name()); + constant_tensor_proto.set_data_type(ONNX_NAMESPACE::TensorProto_DataType_INT64); + if (!is_scalar) { + constant_tensor_proto.add_dims(length); + } + constant_tensor_proto.set_raw_data(values.data(), length * sizeof(int64_t)); + + // Add initializer into Graph. + graph.AddInitializedTensor(constant_tensor_proto); + + // Update the output arg shape. + ONNX_NAMESPACE::TensorShapeProto new_shape; + if (!is_scalar) { + new_shape.add_dim()->set_dim_value(length); + } + arg_to_update->SetShape(new_shape); +} + +} // namespace + +Status ShapeOptimizer::ApplyImpl(Graph& graph, bool& modified, int graph_level, const logging::Logger& logger) + const { + GraphViewer graph_viewer(graph); + auto& order = graph_viewer.GetNodesInTopologicalOrder(); + + for (NodeIndex i : order) { + auto* node = graph.GetNode(i); + if (!node) { + continue; + } + + if (!graph_utils::IsSupportedOptypeVersionAndDomain(*node, "Shape", {1, 13, 15, 19})) { + continue; + } + + ORT_RETURN_IF_ERROR(Recurse(*node, modified, graph_level, logger)); + + auto data_shape = node->MutableInputDefs()[0]->Shape(); + if (data_shape == nullptr) { + SO_LOG_DEBUG_INFO(logger, "Shape node's data input shape is missing." + node->Name()); + continue; + } + + // Parse data input shape, fill -1 for symbolic dimensions. + TensorShapeVector dim_values; + dim_values.reserve(data_shape->dim_size()); + bool has_concrete_dim = false; + for (int dim_index = 0; dim_index < data_shape->dim_size(); dim_index++) { + auto dim = data_shape->dim(dim_index); + if (utils::HasDimValue(dim)) { + dim_values.push_back(dim.dim_value()); + has_concrete_dim = true; + } else { + // Fill with -1 for symbolic dimension. + dim_values.push_back(-1); + } + } + + if (!has_concrete_dim) { + SO_LOG_DEBUG_INFO(logger, "No concrete dimension found, don't need try further." + node->Name()); + continue; + } + + InlinedVector nodes_to_remove; + TensorShapeVector fold_values; + // Short path - check if the shape node can be constant folded. + if (CanShapeNodeBeReplacedWithConstant(*node, dim_values, fold_values)) { + SO_LOG_DEBUG_INFO(logger, "Shape node can be constant folded." + node->Name()); + UpdateNodeArgToConstant(graph, node->MutableOutputDefs()[0], fold_values); + nodes_to_remove.push_back(node); + } else { + // Check consumers of Shape node, try best effort to constant fold them if possible. + // Currently support Gather and Slice in some cases. + auto p_ip_node = node->OutputNodesBegin(); + const auto p_ip_node_end = node->OutputNodesEnd(); + InlinedHashSet visited_nodes; + while (p_ip_node != p_ip_node_end) { + if (visited_nodes.find(&(*p_ip_node)) != visited_nodes.end()) { + // Already handled, skip the node. + ++p_ip_node; + continue; + } + + auto& output_node = *graph.GetNode(p_ip_node->Index()); + visited_nodes.insert(&output_node); + ++p_ip_node; + + NodeArg* data_input = output_node.MutableInputDefs()[0]; + // Skip when shape is not used as sliced data. + if (data_input != node->MutableOutputDefs()[0]) { + continue; + } + + TensorShapeVector slice_fold_values; + if (graph_utils::IsSupportedOptypeVersionAndDomain(output_node, "Slice", {10, 11, 13}) && + CanSliceNodeBeReplacedWithConstant(graph, output_node, dim_values, slice_fold_values)) { + SO_LOG_DEBUG_INFO(logger, "Slice node can be constant folded." + output_node.Name()); + UpdateNodeArgToConstant(graph, output_node.MutableOutputDefs()[0], slice_fold_values); + nodes_to_remove.push_back(&output_node); + continue; + } + + int gather_output_rank = 0; + TensorShapeVector gather_fold_values; + if (graph_utils::IsSupportedOptypeVersionAndDomain(output_node, "Gather", {1, 11, 13}) && + CanGatherNodeBeReplacedWithConstant(graph, output_node, dim_values, gather_fold_values, + gather_output_rank)) { + SO_LOG_DEBUG_INFO(logger, "Gather node can be constant folded." + output_node.Name()); + UpdateNodeArgToConstant(graph, output_node.MutableOutputDefs()[0], gather_fold_values, gather_output_rank == 0); + nodes_to_remove.push_back(&output_node); + continue; + } + } + } + + for (Node* node_to_remove : nodes_to_remove) { + // Remove single-output node chain for inputs of the node + auto p_ip_node = node_to_remove->InputNodesBegin(); + const auto p_ip_node_end = node_to_remove->InputNodesEnd(); + while (p_ip_node != p_ip_node_end) { + const auto& input_node = *p_ip_node; + // Update the node iterator before removing the corresponding node because removing + // the node will invalidate the node iterator + ++p_ip_node; + + // Remove the node only when there is a single output edge or the node does not produce graph output. + if (input_node.GetOutputEdgesCount() > 1 || graph.NodeProducesGraphOutput(input_node)) { + SO_LOG_DEBUG_INFO(logger, "Skip removing node: " + input_node.Name() + "(" + input_node.OpType() + ")"); + continue; + } + SO_LOG_DEBUG_INFO(logger, "Removing node: " + input_node.Name() + "(" + input_node.OpType() + ")"); + graph_utils::RemoveNodesWithOneOutputBottomUp(graph, input_node); + } + + // Remove the output edges of the constant node and then remove the node itself. + graph_utils::RemoveNodeOutputEdges(graph, *node_to_remove); + + SO_LOG_DEBUG_INFO(logger, "Removing trigger node: " + node_to_remove->Name()); + graph.RemoveNode(node_to_remove->Index()); + modified = true; + } + } + + return Status::OK(); +} + +#undef NEED_SO_LOG_DEBUG_INFO +#undef SO_LOG_DEBUG_INFO + +} // namespace onnxruntime diff --git a/orttraining/orttraining/core/optimizer/shape_optimizer.h b/orttraining/orttraining/core/optimizer/shape_optimizer.h new file mode 100644 index 0000000000000..aae7cd7b4d4b8 --- /dev/null +++ b/orttraining/orttraining/core/optimizer/shape_optimizer.h @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/optimizer/graph_transformer.h" + +namespace onnxruntime { + +/** +@class ShapeOptimizer + +Transformer that traverses the graph top-down and performs shape optimizations. + +Try best to constant fold the output of the Shape node: + 1. Shape generates 1D tensor [12, 128, 512] (all dimensions have concrete dim value), which can be constant folded + to an initializer including 1D tensor values [12, 128, 512]. (Some logic of ConstantFolding also does the same thing.) + + 2. Shape generates 1D tensor [batch_size, 128, 512] -> Slice(start=1,end=3), we can constant fold the Shape->Slice to + an initializer including 1D tensor values [128, 512]. + + 3. Shape generates 1D tensor [batch_size, 128, 512] -> Gather(axes=[0], index=[2]), we can constant fold the + Shape->Gather to an initializer including 1D tensor values [512]. + + 4. Shape since OPSET 15 takes input of shape [batch_size, 128, 512], slicing from 1 to 2(exclusive), + we can constant fold the Shape(start=1,end=2) to an initializer including 1D tensor values [128]. + +This would help clean up the graph, and combined with ConstantFolding, the graph would be much more simplified. + +*/ +class ShapeOptimizer : public GraphTransformer { + public: + ShapeOptimizer( + const InlinedHashSet& compatible_execution_providers = {}) noexcept + : GraphTransformer("ShapeOptimizer", compatible_execution_providers) { + } + + private: + Status ApplyImpl(Graph& graph, bool& modified, int graph_level, const logging::Logger& logger) const override; +}; + +} // namespace onnxruntime diff --git a/orttraining/orttraining/core/optimizer/triton_fusion.cc b/orttraining/orttraining/core/optimizer/triton_fusion.cc new file mode 100644 index 0000000000000..f2cb3c2b8c6db --- /dev/null +++ b/orttraining/orttraining/core/optimizer/triton_fusion.cc @@ -0,0 +1,436 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifdef ENABLE_TRITON + +#include +#include + +#include "orttraining/core/optimizer/triton_fusion.h" + +#include "core/framework/compute_capability.h" +#include "core/graph/model.h" +#include "core/graph/graph_utils.h" +#include "core/optimizer/initializer.h" +#include "core/optimizer/utils.h" +#include "core/providers/partitioning_utils.h" + +using namespace ONNX_NAMESPACE; +using json = nlohmann::json; + +namespace onnxruntime { + +namespace { + +using SizeTypeVec = InlinedVector; +using NodeVec = InlinedVector; +using NodeArgVec = InlinedVector; +using ConstNodeArgVec = InlinedVector; +using NodeArgSet = InlinedHashSet; +using IsSupportedFunc = std::function; + +int64_t Hash(const std::string& str) { + uint32_t hash = 0; + for (char const& c : str) { + hash = hash * 101 + c; + } + + return static_cast(hash); +} + +bool CheckAxis(const Node& node, int64_t expected_axis) { + const auto& attributes = node.GetAttributes(); + if (attributes.find("axis") == attributes.end() || !attributes.at("axis").has_i()) return false; + int64_t axis = attributes.at("axis").i(); + if (axis == expected_axis) return true; + if (axis < 0 || expected_axis < 0) { + const auto& input_shape = node.InputDefs()[0]->Shape(); + if (input_shape == nullptr) return false; + int64_t rank = static_cast(input_shape->dim_size()); + if (axis < 0) axis += rank; + int64_t non_neg_expected_axis = expected_axis < 0 ? expected_axis + rank : expected_axis; + return axis == non_neg_expected_axis; + } + return false; +} + +bool CheckAxes(const Graph& graph, const Node& node, bool single_axis, const std::vector& expected_axes) { + std::vector axes_values; + const auto& attributes = node.GetAttributes(); + if (attributes.find("axes") != attributes.end()) { + axes_values = RetrieveValues(attributes.at("axes")); + } else if (node.InputDefs().size() == 2) { + auto axes_const = graph.GetConstantInitializer(node.InputDefs()[1]->Name(), true); + if (!axes_const) { + return false; + } + Initializer initializer{*axes_const, graph.ModelPath()}; + axes_values.insert(axes_values.end(), initializer.DataAsSpan().begin(), + initializer.DataAsSpan().end()); + } else { + return false; + } + + if (expected_axes.empty()) { + return !single_axis || axes_values.size() == 1; + } + + std::vector expected_axes_values(expected_axes.begin(), expected_axes.end()); + bool has_negative_axis = false; + for (auto axis : axes_values) { + if (axis < 0) { + has_negative_axis = true; + break; + } + } + if (!has_negative_axis) { + for (auto axis : expected_axes_values) { + if (axis < 0) { + has_negative_axis = true; + break; + } + } + } + if (has_negative_axis) { + const auto& input_shape = node.InputDefs()[0]->Shape(); + if (input_shape == nullptr) return false; + int64_t rank = static_cast(input_shape->dim_size()); + for (auto& axis : axes_values) { + if (axis < 0) axis += rank; + } + for (auto& axis : expected_axes_values) { + if (axis < 0) axis += rank; + } + } + std::sort(axes_values.begin(), axes_values.end()); + std::sort(expected_axes_values.begin(), expected_axes_values.end()); + return axes_values == expected_axes_values; +} + +// A TritonOpPartition contains all connected nodes in ONNX graph which are supported by ORTModule's Triton module. +// When building the TritonOpPartition, we keep all the dependencies and output ref counts so that to make sure +// there is no dependency between two nodes in the partition through any node outside the partition. +struct TritonOpPartition { + NodeVec nodes; + NodeArgSet outputs; + NodeArgSet dependencies; + size_t output_ref_count; + + void MergeFrom(const TritonOpPartition& other) { + nodes.insert(nodes.end(), other.nodes.begin(), other.nodes.end()); + outputs.insert(other.outputs.begin(), other.outputs.end()); + dependencies.insert(other.dependencies.begin(), other.dependencies.end()); + output_ref_count += other.output_ref_count; + } + + bool IsValid(const TritonFusionConfig& config) const { + size_t count = 0; + bool all_ignore_min_nodes = true; + for (const auto& node : nodes) { + if (!config.IsNoOp(*node)) { + ++count; + if (count >= config.min_nodes) return true; + } + if (!config.IgnoreMinNodes(*node)) all_ignore_min_nodes = false; + } + return all_ignore_min_nodes; + } +}; + +} // namespace + +void from_json(const json& j, TritonFusionConfig::OpInfo& op_info) { + if (j.contains("domain")) j.at("domain").get_to(op_info.domain); + j.at("versions").get_to(op_info.versions); + if (j.contains("is_no_op")) j.at("is_no_op").get_to(op_info.is_no_op); + if (j.contains("conditions")) j.at("conditions").get_to(op_info.conditions); + if (j.contains("ignore_min_nodes")) j.at("ignore_min_nodes").get_to(op_info.ignore_min_nodes); +} + +TritonFusionConfig::TritonFusionConfig(std::string_view config_json) { + const auto& config = json::parse(config_json); + if (config.contains("ops")) { + ops = config.at("ops").get>(); + } + if (config.contains("initializer")) { + initializer = config.at("initializer").get(); + } + if (config.contains("min_nodes")) { + min_nodes = static_cast(config.at("min_nodes").get()); + } +} + +bool TritonFusionConfig::IsSupported(const Graph& graph, const Node& node) const { + const auto& op_type = node.OpType(); + auto it = ops.find(op_type); + if (it == ops.end()) { + return false; + } + + const auto& op_info = it->second; + if (!graph_utils::IsSupportedOptypeVersionAndDomain(node, op_type, op_info.versions, op_info.domain)) { + return false; + } + + for (const auto& pair : op_info.conditions) { + if (pair.first == "axis") { + if (!CheckAxis(node, static_cast(std::stoi(pair.second)))) { + return false; + } + } else if (pair.first == "axes") { + if (pair.second == "constant") { + if (!CheckAxes(graph, node, false, {})) { + return false; + } + } else if (pair.second == "single") { + if (!CheckAxes(graph, node, true, {})) { + return false; + } + } else { + const auto& axes = json::parse(pair.second); + std::vector axes_values = axes.get>(); + if (!CheckAxes(graph, node, false, axes_values)) { + return false; + } + } + } else { + return false; + } + } + + return true; +} + +bool TritonFusionConfig::IsNoOp(const Node& node) const { + const auto& op_type = node.OpType(); + return ops.find(op_type) != ops.end() && ops.at(op_type).is_no_op; +} + +bool TritonFusionConfig::IgnoreMinNodes(const Node& node) const { + const auto& op_type = node.OpType(); + return ops.find(op_type) != ops.end() && ops.at(op_type).ignore_min_nodes; +} + +const ONNX_NAMESPACE::TensorProto* TritonFusionConfig::TryGetInitializer(const Graph& graph, const Node& node, + NodeArg* node_arg) const { + if (initializer == "none" || !graph_utils::IsInitializer(graph, node_arg->Name(), true)) { + return nullptr; + } + + const ONNX_NAMESPACE::TensorProto* tensor = nullptr; + if (!graph.GetInitializedTensor(node_arg->Name(), tensor) || !tensor) { + return nullptr; + } + + if (initializer == "all") { + return tensor; + } + + if ((node.OpType() == "ReduceSum" || node.OpType() == "ReduceMean" || node.OpType() == "ReduceMax" || + node.OpType() == "ReduceMin") && + node.InputDefs().size() >= 2 and node.InputDefs()[1]->Name() == node_arg->Name()) { + return tensor; + } + + return optimizer_utils::IsScalar(*node_arg) ? tensor : nullptr; +} + +Status TritonFusion::ApplyImpl(Graph& graph, bool& modified, int graph_level, const logging::Logger& logger) const { + GraphViewer graph_viewer(graph); + const auto& node_topology_list = graph_viewer.GetNodesInTopologicalOrder(); + size_t global_id = 0; + InlinedHashMap partitions; + InlinedHashMap partitions_to_fuse; + InlinedHashMap active_outputs; + for (auto node_index : node_topology_list) { + auto* p_node = graph.GetNode(node_index); + if (!p_node) continue; + auto& node = *p_node; + ORT_RETURN_IF_ERROR(Recurse(node, modified, graph_level, logger)); + bool is_supported = + graph_utils::IsSupportedProvider(node, GetCompatibleExecutionProviders()) && config_.IsSupported(graph, node); + SizeTypeVec partitions_to_merge; + for (auto& pair : partitions) { + auto& partition = pair.second; + bool connect_to_output = false; + bool connect_to_dependency = false; + for (auto& input : node.MutableInputDefs()) { + if (partition.outputs.find(input) != partition.outputs.end()) { + partition.output_ref_count--; + connect_to_output = true; + } + if (partition.dependencies.find(input) != partition.dependencies.end()) { + connect_to_dependency = true; + } + } + if (is_supported && connect_to_output && !connect_to_dependency) { + partitions_to_merge.emplace_back(pair.first); + } else if (connect_to_output || connect_to_dependency) { + for (auto& output : node.MutableOutputDefs()) { + partition.dependencies.emplace(output); + } + } + } + + if (!partitions_to_merge.empty()) { + std::sort(partitions_to_merge.begin(), partitions_to_merge.end()); + TritonOpPartition& dst = partitions.at(partitions_to_merge[0]); + for (size_t i = partitions_to_merge.size() - 1; i > 0; --i) { + dst.MergeFrom(partitions.at(partitions_to_merge[i])); + partitions.erase(partitions_to_merge[i]); + } + + dst.nodes.emplace_back(&node); + for (auto& output : node.MutableOutputDefs()) { + dst.outputs.emplace(output); + } + dst.output_ref_count += node.GetOutputEdgesCount(); + } else if (is_supported) { + TritonOpPartition partition; + partition.nodes.emplace_back(&node); + for (auto& node_def : node.MutableOutputDefs()) { + partition.outputs.emplace(node_def); + } + partition.output_ref_count = node.GetOutputEdgesCount(); + partitions.emplace(global_id++, partition); + } + + SizeTypeVec partitions_to_erase; + for (auto& pair : partitions) { + if (pair.second.output_ref_count == 0) { + if (pair.second.IsValid(config_)) { + pair.second.outputs.clear(); + pair.second.dependencies.clear(); + partitions_to_fuse.emplace(pair); + } + partitions_to_erase.emplace_back(pair.first); + } + } + + for (auto& id : partitions_to_erase) { + partitions.erase(id); + } + + for (auto& input : node.MutableInputDefs()) { + if (active_outputs.find(input) != active_outputs.end()) { + active_outputs.at(input)--; + if (active_outputs.at(input) == 0) { + active_outputs.erase(input); + for (auto& pair : partitions) { + pair.second.dependencies.erase(input); + } + } + } + } + + for (auto it = node.OutputEdgesBegin(), end = node.OutputEdgesEnd(); it != end; ++it) { + NodeArg* output = node.MutableOutputDefs()[it->GetSrcArgIndex()]; + if (active_outputs.find(output) == active_outputs.end()) { + active_outputs.emplace(output, 1); + } else { + active_outputs.at(output)++; + } + } + } + + SizeTypeVec partition_ids; + for (auto& pair : partitions_to_fuse) { + partition_ids.emplace_back(pair.first); + } + std::sort(partition_ids.begin(), partition_ids.end()); + + for (auto& id : partition_ids) { + auto& partition = partitions_to_fuse.at(id); + + Model sub_model("test", false, logger); + Graph& sub_graph = sub_model.MainGraph(); + + NodeArgVec graph_inputs; + NodeArgVec node_outputs; + NodeArgSet graph_input_set; + NodeArgSet initializers; + ConstNodeArgVec graph_const_inputs; + InlinedHashMap output_consumer_counts; + NodeArgSet no_consumer_outputs; + for (auto& p_node : partition.nodes) { + auto& node = *p_node; + sub_graph.AddNode(node); + for (auto& input : node.MutableInputDefs()) { + if (initializers.find(input) != initializers.end()) { + continue; + } + const ONNX_NAMESPACE::TensorProto* tensor = config_.TryGetInitializer(graph, node, input); + if (tensor) { + initializers.emplace(input); + sub_graph.AddInitializedTensor(*tensor); + continue; + } + + if (output_consumer_counts.find(input) != output_consumer_counts.end()) { + output_consumer_counts.at(input)--; + if (output_consumer_counts.at(input) == 0) { + output_consumer_counts.erase(input); + } + } else if (graph_input_set.find(input) == graph_input_set.end()) { + graph_inputs.emplace_back(input); + graph_input_set.insert(input); + graph_const_inputs.emplace_back(input); + } + } + + for (auto it = p_node->OutputEdgesBegin(), end = p_node->OutputEdgesEnd(); it != end; ++it) { + NodeArg* output = p_node->MutableOutputDefs()[it->GetSrcArgIndex()]; + if (output_consumer_counts.find(output) == output_consumer_counts.end()) { + output_consumer_counts.emplace(output, 1); + } else { + output_consumer_counts.at(output)++; + } + } + + for (auto& output : node.MutableOutputDefs()) { + if (output->Name() != "") { + node_outputs.emplace_back(output); + if (output_consumer_counts.find(output) == output_consumer_counts.end()) { + no_consumer_outputs.emplace(output); + } + } + } + } + + NodeArgVec graph_outputs; + ConstNodeArgVec graph_const_outputs; + for (auto& output : node_outputs) { + if (no_consumer_outputs.find(output) != no_consumer_outputs.end() || + output_consumer_counts.find(output) != output_consumer_counts.end()) { + graph_outputs.emplace_back(output); + graph_const_outputs.emplace_back(output); + } + } + + sub_graph.SetInputs(graph_const_inputs); + sub_graph.SetOutputs(graph_const_outputs); + + auto model_proto = sub_model.ToProto(); + std::string model_str; + model_proto.SerializeToString(&model_str); + + Node& fused_node = graph.AddNode(graph.GenerateNodeName("TritonOp"), "TritonOp", "Fused nodes for TritonOp", + graph_inputs, graph_outputs, {}, kMSDomain); + fused_node.AddAttribute("onnx_key", Hash(model_str)); + fused_node.AddAttribute("onnx_string", model_str); + fused_node.SetExecutionProviderType(partition.nodes[0]->GetExecutionProviderType()); + + for (auto& p_node : partition.nodes) { + graph_utils::RemoveNodeOutputEdges(graph, *p_node); + graph.RemoveNode(p_node->Index()); + } + + modified = true; + } + + return Status::OK(); +} + +} // namespace onnxruntime + +#endif // ENABLE_TRITON diff --git a/orttraining/orttraining/core/optimizer/triton_fusion.h b/orttraining/orttraining/core/optimizer/triton_fusion.h new file mode 100644 index 0000000000000..78d62586c974d --- /dev/null +++ b/orttraining/orttraining/core/optimizer/triton_fusion.h @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifdef ENABLE_TRITON + +#pragma once + +#include "core/optimizer/graph_transformer.h" + +namespace onnxruntime { + +struct TritonFusionConfig { + struct OpInfo { + std::string domain = ""; + std::vector versions; + bool is_no_op = false; + std::unordered_map conditions = {}; + bool ignore_min_nodes = false; + }; + + TritonFusionConfig(std::string_view config_json = "{}"); + + bool IsSupported(const Graph& graph, const Node& node) const; + bool IsNoOp(const Node& node) const; + bool IgnoreMinNodes(const Node& node) const; + const ONNX_NAMESPACE::TensorProto* TryGetInitializer(const Graph& graph, const Node& node, NodeArg* node_arg) const; + + std::unordered_map ops; + std::string initializer = "none"; + size_t min_nodes = 2; +}; + +class TritonFusion : public GraphTransformer { + public: + TritonFusion(std::string_view config_json = "{}", + const InlinedHashSet& compatible_execution_providers = {}) noexcept + : GraphTransformer("TritonFusion", compatible_execution_providers), config_(config_json) {} + + Status ApplyImpl(Graph& graph, bool& modified, int graph_level, const logging::Logger& logger) const override; + + private: + bool IsSupportedNode(const Graph& graph, const Node& node) const; + + TritonFusionConfig config_; +}; + +} // namespace onnxruntime + +#endif // ENABLE_TRITON diff --git a/orttraining/orttraining/lazy_tensor/cuda_tool.cc b/orttraining/orttraining/lazy_tensor/cuda_tool.cc index 40c7248f25598..3a652ad98dfe6 100644 --- a/orttraining/orttraining/lazy_tensor/cuda_tool.cc +++ b/orttraining/orttraining/lazy_tensor/cuda_tool.cc @@ -6,7 +6,11 @@ // CUDA #include "cuda.h" #include "cuda_runtime.h" +#if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__) +#include "nvtx3/nvToolsExt.h" +#else #include "nvToolsExt.h" +#endif // Pytorch #include // ORT diff --git a/orttraining/orttraining/models/bert/main.cc b/orttraining/orttraining/models/bert/main.cc index 4c0cc66485256..3e7d9a0714fbb 100644 --- a/orttraining/orttraining/models/bert/main.cc +++ b/orttraining/orttraining/models/bert/main.cc @@ -23,12 +23,12 @@ #ifdef USE_CUDA namespace onnxruntime { -std::unique_ptr CreateCUDAPinnedAllocator(int16_t device_id, const char* name); +std::unique_ptr CreateCUDAPinnedAllocator(const char* name); } // namespace onnxruntime #endif #ifdef USE_ROCM namespace onnxruntime { -std::unique_ptr CreateROCMPinnedAllocator(int16_t device_id, const char* name); +std::unique_ptr CreateROCMPinnedAllocator(const char* name); } // namespace onnxruntime #endif @@ -631,7 +631,7 @@ void setup_training_params(BertParameters& params) { info.cudnn_conv_algo_search = OrtCudnnConvAlgoSearchExhaustive; params.providers.emplace(kCudaExecutionProvider, CudaProviderFactoryCreator::Create(&info)); - params.input_allocator = CreateCUDAPinnedAllocator(info.device_id, CUDA_PINNED); + params.input_allocator = CreateCUDAPinnedAllocator(CUDA_PINNED); } #endif @@ -647,7 +647,7 @@ void setup_training_params(BertParameters& params) { info.miopen_conv_exhaustive_search = true; // true, exhaustive search (slow) params.providers.emplace(kRocmExecutionProvider, RocmProviderFactoryCreator::Create(&info)); - params.input_allocator = CreateROCMPinnedAllocator(info.device_id, CUDA_PINNED); + params.input_allocator = CreateROCMPinnedAllocator(HIP_PINNED); } #endif diff --git a/orttraining/orttraining/models/gpt2/main.cc b/orttraining/orttraining/models/gpt2/main.cc index c5b2e91ee0c2d..165d69fb1378a 100644 --- a/orttraining/orttraining/models/gpt2/main.cc +++ b/orttraining/orttraining/models/gpt2/main.cc @@ -23,12 +23,12 @@ #ifdef USE_CUDA namespace onnxruntime { -std::unique_ptr CreateCUDAPinnedAllocator(int16_t device_id, const char* name); +std::unique_ptr CreateCUDAPinnedAllocator(const char* name); } // namespace onnxruntime #endif #ifdef USE_ROCM namespace onnxruntime { -std::unique_ptr CreateROCMPinnedAllocator(int16_t device_id, const char* name); +std::unique_ptr CreateROCMPinnedAllocator(const char* name); } // namespace onnxruntime #endif @@ -364,7 +364,7 @@ void setup_training_params(GPT2Parameters& params) { info.device_id = gsl::narrow(MPIContext::GetInstance().GetLocalRank()); info.do_copy_in_default_stream = true; params.providers.emplace(kCudaExecutionProvider, CudaProviderFactoryCreator::Create(&info)); - params.input_allocator = CreateCUDAPinnedAllocator(info.device_id, CUDA_PINNED); + params.input_allocator = CreateCUDAPinnedAllocator(CUDA_PINNED); } #endif @@ -374,7 +374,7 @@ void setup_training_params(GPT2Parameters& params) { info.device_id = gsl::narrow(MPIContext::GetInstance().GetLocalRank()); info.do_copy_in_default_stream = true; params.providers.emplace(kRocmExecutionProvider, RocmProviderFactoryCreator::Create(&info)); - params.input_allocator = CreateROCMPinnedAllocator(info.device_id, CUDA_PINNED); + params.input_allocator = CreateROCMPinnedAllocator(HIP_PINNED); } #endif diff --git a/orttraining/orttraining/models/runner/data_loader.cc b/orttraining/orttraining/models/runner/data_loader.cc index eb9b1d19774b6..0653b859468e7 100644 --- a/orttraining/orttraining/models/runner/data_loader.cc +++ b/orttraining/orttraining/models/runner/data_loader.cc @@ -24,7 +24,7 @@ static std::vector GetAllDataFiles(const PathString& dir_path) { !HasExtensionOf(filename_str, ORT_TSTR("pb"))) { return true; } - data_files.push_back(ConcatPathComponent(dir_path, filename_str)); + data_files.push_back(ConcatPathComponent(dir_path, filename_str)); return true; }); diff --git a/orttraining/orttraining/models/runner/training_util.h b/orttraining/orttraining/models/runner/training_util.h index 66bc2e07d67d1..8c76ce7e50dc9 100644 --- a/orttraining/orttraining/models/runner/training_util.h +++ b/orttraining/orttraining/models/runner/training_util.h @@ -156,7 +156,8 @@ class TrainingUtil { static AllocatorPtr GetCpuAllocator() { static CPUExecutionProviderInfo info; static CPUExecutionProvider cpu_provider(info); - return cpu_provider.GetAllocator(OrtMemTypeDefault); + static AllocatorPtr ret = cpu_provider.CreatePreferredAllocators()[0]; + return ret; } static void PrintNameMLValMap(const NameMLValMap& mlvalue_map); diff --git a/orttraining/orttraining/python/checkpointing_utils.py b/orttraining/orttraining/python/checkpointing_utils.py index ffb066b2043c4..460b9982297d1 100644 --- a/orttraining/orttraining/python/checkpointing_utils.py +++ b/orttraining/orttraining/python/checkpointing_utils.py @@ -53,7 +53,7 @@ def __init__(self, checkpoint_files, clean_state_dict=None): self.weight_shape_map = dict() self.sharded_params = set() - def _split_name(self, name): + def _split_name(self, name: str): name_split = name.split("_view_") view_num = None if len(name_split) > 1: @@ -69,7 +69,7 @@ def _split_name(self, name): elif name_split[0].endswith("_fp16"): mp_suffix = "_fp16" param_name = name_split[0] - if optimizer_key != "": # noqa: PLC1901 + if optimizer_key: param_name = param_name.split(optimizer_key)[1] param_name = param_name.split("_fp16")[0] return param_name, optimizer_key, view_num, mp_suffix diff --git a/orttraining/orttraining/python/ort_trainer.py b/orttraining/orttraining/python/ort_trainer.py index 542ba22602d44..7c90054a85dc5 100644 --- a/orttraining/orttraining/python/ort_trainer.py +++ b/orttraining/orttraining/python/ort_trainer.py @@ -1181,14 +1181,18 @@ def eval_step(self, *args, **kwargs): def _verify_fully_optimized_model(self, model): assert len(model.graph.output) > 0 # model's first output must be the loss tensor - if ( - model.graph.output[0].type.tensor_type.elem_type != onnx.TensorProto().FLOAT - and model.graph.output[0].type.tensor_type.elem_type != onnx.TensorProto().FLOAT16 - and model.graph.output[0].type.tensor_type.elem_type != onnx.TensorProto().DOUBLE - and model.graph.output[0].type.tensor_type.elem_type != onnx.TensorProto().COMPLEX64 - and model.graph.output[0].type.tensor_type.elem_type != onnx.TensorProto().COMPLEX128 - and model.graph.output[0].type.tensor_type.elem_type != onnx.TensorProto().BFLOAT16 - ): + if model.graph.output[0].type.tensor_type.elem_type not in { + onnx.TensorProto.FLOAT, + onnx.TensorProto.FLOAT16, + onnx.TensorProto.DOUBLE, + onnx.TensorProto.COMPLEX64, + onnx.TensorProto.COMPLEX128, + onnx.TensorProto.BFLOAT16, + onnx.TensorProto.FLOAT8E4M3FN, + onnx.TensorProto.FLOAT8E4M3FNUZ, + onnx.TensorProto.FLOAT8E5M2, + onnx.TensorProto.FLOAT8E5M2FNUZ, + }: raise RuntimeError( "the first output of a model to run with fully optimized ORT backend must be float types." ) @@ -1203,10 +1207,10 @@ def __init__( self, loss_scale_input_name, is_dynamic_scale, - loss_scale=float(1 << 16), # noqa: B008 + loss_scale=float(1 << 16), up_scale_window=2000, min_loss_scale=1.0, - max_loss_scale=float(1 << 24), # noqa: B008 + max_loss_scale=float(1 << 24), ): super().__init__() self.loss_scale_input_name_ = loss_scale_input_name diff --git a/orttraining/orttraining/python/orttraining_pybind_state.cc b/orttraining/orttraining/python/orttraining_pybind_state.cc index 23b02372daaf9..3f3aa396e6ca0 100644 --- a/orttraining/orttraining/python/orttraining_pybind_state.cc +++ b/orttraining/orttraining/python/orttraining_pybind_state.cc @@ -13,8 +13,10 @@ #endif #include "core/common/parse_string.h" +#include "core/framework/customregistry.h" #include "core/graph/model.h" #include "core/session/environment.h" +#include "core/session/custom_ops.h" #include "core/dlpack/dlpack_converter.h" #include "orttraining/core/session/training_session.h" #include "orttraining/core/agent/training_agent.h" @@ -34,10 +36,13 @@ #include "orttraining/core/framework/torch/custom_function_register.h" #endif +#ifdef ENABLE_TRITON +#include "orttraining/core/framework/triton/triton_op_executor.h" +#endif + #ifdef ENABLE_TRAINING_APIS #include "orttraining/training_api/checkpoint.h" #include "orttraining/training_api/lr_scheduler.h" - #endif PYBIND11_MAKE_OPAQUE(onnxruntime::OrtValueCache); @@ -167,25 +172,38 @@ struct TrainingConfigurationResult { // Thin wrapper over internal C++ Optimizer struct PyOptimizer { PyOptimizer(const std::string optimizer_model_uri, onnxruntime::training::api::CheckpointState* state, - std::vector> providers) + std::vector> providers, PySessionOptions* session_options) : optimizer_() { + auto model_identifiers = onnxruntime::training::api::ModelIdentifiers("", std::nullopt, optimizer_model_uri); auto env = GetTrainingEnv().GetORTEnv(); // XXX: We hope that env will be around when optimizer needs it. optimizer_ = std::make_shared( - optimizer_model_uri, state, onnxruntime::SessionOptions(), *env, providers); + model_identifiers, state, session_options->value, *env, providers, session_options->custom_op_domains_); } std::shared_ptr optimizer_; }; #endif -struct PyGradientGraphBuilder { - std::unique_ptr builder; - std::shared_ptr model; - std::unique_ptr logger; - std::unique_ptr gradient_graph_config; - PyGradientGraphBuilder(std::unique_ptr builder_, std::shared_ptr model_, std::unique_ptr logger_, std::unique_ptr gradient_graph_config_) - : builder(std::move(builder_)), model(std::move(model_)), logger(std::move(logger_)), gradient_graph_config(std::move(gradient_graph_config_)) {} +struct PyGradientGraphBuilderContext { + std::unique_ptr builder_; + std::shared_ptr model_; + std::unique_ptr logger_; + std::unique_ptr gradient_graph_config_; + std::shared_ptr custom_registry_; + IOnnxRuntimeOpSchemaRegistryList local_registries_; + PyGradientGraphBuilderContext(std::unique_ptr builder, + std::shared_ptr model, + std::unique_ptr logger, + std::unique_ptr gradient_graph_config, + std::shared_ptr custom_registry, + IOnnxRuntimeOpSchemaRegistryList local_registries) + : builder_(std::move(builder)), + model_(model), + logger_(std::move(logger)), + gradient_graph_config_(std::move(gradient_graph_config)), + custom_registry_(custom_registry), + local_registries_(local_registries) {} }; // TODO: this method does not handle parallel optimization. @@ -546,6 +564,20 @@ void addObjectMethodsForTraining(py::module& m, ExecutionProviderRegistrationFn return false; #endif }); + m.def("is_triton_enabled", []() -> bool { +#ifdef ENABLE_TRITON + return true; +#else + return false; +#endif + }); +#ifdef ENABLE_TRITON + m.def("register_triton_op_executor", + [](py::object config_getter, py::object executor_by_name, py::object executor_by_onnx) -> void { + training::framework::triton::TritonOpExecutor::Instance().Initialize( + config_getter.ptr(), executor_by_name.ptr(), executor_by_onnx.ptr()); + }); +#endif py::class_ config_result(m, "TrainingConfigurationResult", "pbdoc(Configuration result for training.)pbdoc"); config_result.def(py::init()) @@ -736,7 +768,9 @@ void addObjectMethodsForTraining(py::module& m, ExecutionProviderRegistrationFn .def_readwrite("transformer_layer_recompute", &TrainingGraphTransformerConfiguration::transformer_layer_recompute) .def_readwrite("number_recompute_layers", &TrainingGraphTransformerConfiguration::number_recompute_layers) .def_readwrite("enable_compute_optimizer", &TrainingGraphTransformerConfiguration::enable_compute_optimizer) - .def_readwrite("enable_label_sparsity_optimization", &TrainingGraphTransformerConfiguration::enable_label_sparsity_optimization) + .def_readwrite("sparse_embedding_input_names", &TrainingGraphTransformerConfiguration::sparse_embedding_input_names) + .def_readwrite("sparse_label_input_names", &TrainingGraphTransformerConfiguration::sparse_label_input_names) + .def_readwrite("optimized_pre_grad_filepath", &TrainingGraphTransformerConfiguration::optimized_pre_grad_filepath) .def_readwrite("propagate_cast_ops_config", &TrainingGraphTransformerConfiguration::GraphTransformerConfiguration::propagate_cast_ops_config); py::class_ module_graph_builder_config( @@ -757,7 +791,6 @@ void addObjectMethodsForTraining(py::module& m, ExecutionProviderRegistrationFn .def_readwrite("use_memory_efficient_gradient", &OrtModuleGraphBuilderConfiguration::use_memory_efficient_gradient) .def_readwrite("build_gradient_graph", &OrtModuleGraphBuilderConfiguration::build_gradient_graph) - .def_readwrite("graph_transformer_config", &OrtModuleGraphBuilderConfiguration::graph_transformer_config) .def_readwrite("enable_caching", &OrtModuleGraphBuilderConfiguration::enable_caching) .def_readwrite("loglevel", &OrtModuleGraphBuilderConfiguration::loglevel); @@ -786,13 +819,15 @@ void addObjectMethodsForTraining(py::module& m, ExecutionProviderRegistrationFn ORT_THROW_IF_ERROR(ortmodule_graph_builder->Initialize(buffer, config)); }) .def("build", - [](OrtModuleGraphBuilder* ortmodule_graph_builder) { - ORT_THROW_IF_ERROR(ortmodule_graph_builder->Build()); + [](OrtModuleGraphBuilder* ortmodule_graph_builder, + const TrainingGraphTransformerConfiguration& config) { + ORT_THROW_IF_ERROR(ortmodule_graph_builder->Build(config)); }) .def("build", [](OrtModuleGraphBuilder* ortmodule_graph_builder, + const TrainingGraphTransformerConfiguration& config, const std::vector>& input_shapes) { - ORT_THROW_IF_ERROR(ortmodule_graph_builder->Build(&input_shapes)); + ORT_THROW_IF_ERROR(ortmodule_graph_builder->Build(config, &input_shapes)); }) .def("get_gradient_model", [](OrtModuleGraphBuilder* ortmodule_graph_builder) { @@ -808,44 +843,65 @@ void addObjectMethodsForTraining(py::module& m, ExecutionProviderRegistrationFn // Provide a convenient and well-documented way to make a gradient graph. // It's possible to get the gradient graph through ORTModule by leveraging some "private" fields and not-so-well-documented APIs, so we provide this explicit and tested way to get the gradient graph. - py::class_ gradient_graph_builder(m, "GradientGraphBuilder", R"pbdoc(A utility for making a gradient graph that can be used to help train a model.)pbdoc"); + py::class_ gradient_graph_builder( + m, "GradientGraphBuilder", R"pbdoc(A utility for making a gradient graph that can be used to help train a model.)pbdoc"); // Set up methods to match the C++ `GradientGraphBuilder` interface. - gradient_graph_builder.def(py::init([]( - const py::bytes& serialized_model, - const std::unordered_set& y_node_arg_names, - const std::unordered_set& x_node_arg_names, - const std::string loss_node_arg_name) { - std::shared_ptr model; - auto logger_ptr = std::make_unique(logging::LoggingManager::DefaultLogger()); - logger_ptr->SetSeverity(logging::Severity::kINFO); - ONNX_NAMESPACE::ModelProto model_proto; - std::istringstream model_istream(serialized_model); - ORT_THROW_IF_ERROR(Model::Load(model_istream, &model_proto)); - ORT_THROW_IF_ERROR(Model::Load(model_proto, model, nullptr, *logger_ptr)); - GradientGraphConfiguration gradient_graph_config{}; - gradient_graph_config.set_gradients_as_graph_outputs = true; - // Save some objects, otherwise they get lost. - auto gradient_graph_config_ptr = std::make_unique(gradient_graph_config); - - auto builder = std::make_unique( - &model->MainGraph(), - y_node_arg_names, - x_node_arg_names, - loss_node_arg_name, - *gradient_graph_config_ptr, - *logger_ptr); - - return std::make_unique(std::move(builder), std::move(model), std::move(logger_ptr), std::move(gradient_graph_config_ptr)); - })) - .def("build", [](PyGradientGraphBuilder* gradient_graph_builder) { - ORT_THROW_IF_ERROR(gradient_graph_builder->builder->Build()); + gradient_graph_builder + .def(py::init([](const py::bytes& serialized_model, + const std::unordered_set& y_node_arg_names, + const std::unordered_set& x_node_arg_names, + const std::string loss_node_arg_name, + PySessionOptions* options) { + std::shared_ptr custom_registry; + IOnnxRuntimeOpSchemaRegistryList local_registries; + if (options && !options->custom_op_domains_.empty()) { + // Register all custom op domains that will be needed for the session + ORT_THROW_IF_ERROR(onnxruntime::CreateCustomRegistry(options->custom_op_domains_, custom_registry)); + local_registries.push_back(custom_registry->GetOpschemaRegistry()); + } + + std::shared_ptr model; + auto logger_ptr = std::make_unique(logging::LoggingManager::DefaultLogger()); + logging::Severity severity = logging::Severity::kINFO; + if (options && options->value.session_log_severity_level >= 0) { + severity = static_cast(options->value.session_log_severity_level); + } + logger_ptr->SetSeverity(severity); + ONNX_NAMESPACE::ModelProto model_proto; + std::istringstream model_istream(serialized_model); + ORT_THROW_IF_ERROR(Model::Load(model_istream, &model_proto)); + ORT_THROW_IF_ERROR(Model::Load(model_proto, model, + local_registries.empty() ? nullptr : &local_registries, + *logger_ptr)); + GradientGraphConfiguration gradient_graph_config{}; + gradient_graph_config.set_gradients_as_graph_outputs = true; + // Save some objects, otherwise they get lost. + auto gradient_graph_config_ptr = std::make_unique(gradient_graph_config); + + auto builder = std::make_unique( + &model->MainGraph(), + y_node_arg_names, + x_node_arg_names, + loss_node_arg_name, + *gradient_graph_config_ptr, + *logger_ptr); + + return std::make_unique(std::move(builder), std::move(model), + std::move(logger_ptr), std::move(gradient_graph_config_ptr), + custom_registry, std::move(local_registries)); + }), + py::arg("serialized_model"), py::arg("y_node_arg_names"), + py::arg("x_node_arg_names"), py::arg("loss_node_arg_name"), + py::arg("options") = nullptr) + .def("build", [](PyGradientGraphBuilderContext* gradient_graph_builder) { + ORT_THROW_IF_ERROR(gradient_graph_builder->builder_->Build()); }) - .def("save", [](PyGradientGraphBuilder* gradient_graph_builder, const std::string& path) { - ORT_THROW_IF_ERROR(Model::Save(*(gradient_graph_builder->model), path)); + .def("save", [](PyGradientGraphBuilderContext* gradient_graph_builder, const std::string& path) { + ORT_THROW_IF_ERROR(Model::Save(*(gradient_graph_builder->model_), path)); }) - .def("get_model", [](PyGradientGraphBuilder* gradient_graph_builder) { + .def("get_model", [](PyGradientGraphBuilderContext* gradient_graph_builder) { std::string model_str; - gradient_graph_builder->model->ToProto().SerializeToString(&model_str); + gradient_graph_builder->model_->ToProto().SerializeToString(&model_str); return py::bytes(model_str); }); @@ -883,20 +939,66 @@ void addObjectMethodsForTraining(py::module& m, ExecutionProviderRegistrationFn .def(py::init([](const std::string& model_uri, onnxruntime::training::api::CheckpointState* state, std::optional eval_model_uri, - OrtDevice device) { - onnxruntime::SessionOptions session_option; + OrtDevice device, PySessionOptions* session_options) { std::vector> provider = GetExecutionProvidersForTrainingApis(device); - auto env = GetTrainingEnv().GetORTEnv(); - return std::make_unique( - model_uri, state, session_option, *env, provider, eval_model_uri); + auto model_identifiers = onnxruntime::training::api::ModelIdentifiers(model_uri, eval_model_uri, std::nullopt); + return std::make_unique(model_identifiers, + state, session_options->value, *env, provider, + session_options->custom_op_domains_); })) .def("train_step", + [](onnxruntime::training::api::Module* model, + const std::vector& user_inputs, std::vector& user_outputs) -> void { + std::vector feeds; + const auto model_inputs_with_error = model->GetTrainingModelInputs(); + ORT_THROW_IF_ERROR(model_inputs_with_error.first); + ORT_ENFORCE(model_inputs_with_error.second, "Training model graph inputs are not defined."); + for (size_t idx = 0; idx < user_inputs.size(); ++idx) { + auto& feed = user_inputs[idx]; + // No need to process 'None's sent in by the user + // to feed Optional inputs in the graph. + // We just won't include anything in the feed and ORT + // will handle such implicit 'None's internally. + if (!feed.is(py::none())) { + const auto feed_name = model->GetTrainingModelInputName(idx); + OrtValue ort_value; + CreateGenericMLValue(model_inputs_with_error.second, GetAllocator(), feed_name, feed, &ort_value); + ThrowIfPyErrOccured(); + feeds.emplace_back(ort_value); + } + } + ORT_THROW_IF_ERROR(model->TrainStep(feeds, user_outputs)); + }) + .def("train_step_with_ort_values", [](onnxruntime::training::api::Module* model, const std::vector& user_inputs, std::vector& user_outputs) -> void { ORT_THROW_IF_ERROR(model->TrainStep(user_inputs, user_outputs)); }) .def("eval_step", + [](onnxruntime::training::api::Module* model, + const std::vector& user_inputs, std::vector& user_outputs) -> void { + std::vector feeds; + const auto model_inputs_with_error = model->GetEvalModelInputs(); + ORT_THROW_IF_ERROR(model_inputs_with_error.first); + ORT_ENFORCE(model_inputs_with_error.second, "Eval model graph inputs are not defined."); + for (size_t idx = 0; idx < user_inputs.size(); ++idx) { + auto& feed = user_inputs[idx]; + // No need to process 'None's sent in by the user + // to feed Optional inputs in the graph. + // We just won't include anything in the feed and ORT + // will handle such implicit 'None's internally. + if (!feed.is(py::none())) { + const auto feed_name = model->GetEvalModelInputName(idx); + OrtValue ort_value; + CreateGenericMLValue(model_inputs_with_error.second, GetAllocator(), feed_name, feed, &ort_value); + ThrowIfPyErrOccured(); + feeds.emplace_back(ort_value); + } + } + ORT_THROW_IF_ERROR(model->EvalStep(feeds, user_outputs)); + }) + .def("eval_step_with_ort_values", [](onnxruntime::training::api::Module* model, const std::vector& user_inputs, std::vector& user_outputs) -> void { ORT_THROW_IF_ERROR(model->EvalStep(user_inputs, user_outputs)); @@ -906,12 +1008,12 @@ void addObjectMethodsForTraining(py::module& m, ExecutionProviderRegistrationFn ORT_THROW_IF_ERROR(model->LazyResetGrad()); }) .def("copy_parameters_to_buffer", - [](onnxruntime::training::api::Module* model, OrtValue& output) -> void { - ORT_THROW_IF_ERROR(model->CopyParametersToBuffer(output)); + [](onnxruntime::training::api::Module* model, OrtValue& output, bool trainable_only) -> void { + ORT_THROW_IF_ERROR(model->CopyParametersToBuffer(output, trainable_only)); }) .def("copy_buffer_to_parameters", - [](onnxruntime::training::api::Module* model, OrtValue& input) -> void { - ORT_THROW_IF_ERROR(model->CopyBufferToParameters(input)); + [](onnxruntime::training::api::Module* model, OrtValue& input, bool trainable_only) -> void { + ORT_THROW_IF_ERROR(model->CopyBufferToParameters(input, trainable_only)); }) .def("get_parameters_size", [](onnxruntime::training::api::Module* model, bool trainable_only) -> size_t { @@ -980,10 +1082,10 @@ void addObjectMethodsForTraining(py::module& m, ExecutionProviderRegistrationFn training_optimizer .def(py::init([](const std::string optimizer_model_uri, onnxruntime::training::api::CheckpointState* state, - OrtDevice device) { + OrtDevice device, PySessionOptions* session_options) { std::vector> providers = GetExecutionProvidersForTrainingApis(device); - return std::make_unique(optimizer_model_uri, state, providers); + return std::make_unique(optimizer_model_uri, state, providers, session_options); })) .def("optimizer_step", [](PyOptimizer* optimizer) -> void { ORT_THROW_IF_ERROR(optimizer->optimizer_->Step()); @@ -1070,7 +1172,16 @@ void addObjectMethodsForTraining(py::module& m, ExecutionProviderRegistrationFn m.def("get_optimized_model", [](const py::bytes& serialized_model, - const std::unordered_set& graph_entities_that_require_gradients) { + const std::unordered_set& graph_entities_that_require_gradients, + PySessionOptions* options = nullptr) { + std::shared_ptr custom_registry; + IOnnxRuntimeOpSchemaRegistryList local_registries; + if (options && !options->custom_op_domains_.empty()) { + // Register all custom op domains that will be needed for the session + ORT_THROW_IF_ERROR(onnxruntime::CreateCustomRegistry(options->custom_op_domains_, custom_registry)); + local_registries.push_back(custom_registry->GetOpschemaRegistry()); + } + // Load the serialized model std::istringstream buffer(serialized_model); ONNX_NAMESPACE::ModelProto model_proto; @@ -1078,9 +1189,15 @@ void addObjectMethodsForTraining(py::module& m, ExecutionProviderRegistrationFn // Get the ort model from ModelProto model auto logger_ptr = std::make_unique(logging::LoggingManager::DefaultLogger()); - logger_ptr->SetSeverity(logging::Severity::kINFO); + logging::Severity severity = logging::Severity::kINFO; + if (options && options->value.session_log_severity_level >= 0) { + severity = static_cast(options->value.session_log_severity_level); + } + logger_ptr->SetSeverity(severity); std::shared_ptr ort_model; - ORT_THROW_IF_ERROR(Model::Load(model_proto, ort_model, nullptr, *logger_ptr)); + ORT_THROW_IF_ERROR(Model::Load(model_proto, ort_model, + local_registries.empty() ? nullptr : &local_registries, + *logger_ptr)); Graph& graph = ort_model->MainGraph(); ORT_THROW_IF_ERROR(graph.Resolve()); @@ -1121,6 +1238,15 @@ void addObjectMethodsForTraining(py::module& m, ExecutionProviderRegistrationFn ort_model->ToProto().SerializeToString(&model_str); return py::bytes(model_str); }); + + m.def("is_ortmodule_available", + []() { +#ifdef __linux__ + return true; +#else + return false; +#endif + }); #endif } diff --git a/orttraining/orttraining/python/orttraining_python_module.cc b/orttraining/orttraining/python/orttraining_python_module.cc index c378733e7ec2e..7024244629c3e 100644 --- a/orttraining/orttraining/python/orttraining_python_module.cc +++ b/orttraining/orttraining/python/orttraining_python_module.cc @@ -273,15 +273,8 @@ std::unique_ptr CreateTrainingEP( const SessionOptions& session_options, const std::string& provider_type, const ProviderOptionsMap& provider_options_map) { - auto provider = CreateExecutionProviderInstance(session_options, provider_type, provider_options_map); - // The CPU provider instance created by the factory doesn't create allocators by default. The session registers - // the allocators to allow sharing. However, in some training scenarios (particularly eager mode), no session is - // created but it (eager mode) relies on the allocator in the CPU provider. Hence the need to call RegisterAllocator. - if (provider_type == kCpuExecutionProvider) { - AllocatorManager mgr; // temporary only to call RegisterAllocator - provider->RegisterAllocator(mgr); - } - return provider; + // TODO(leca): REVIEW: No allocators are initialized + return CreateExecutionProviderInstance(session_options, provider_type, provider_options_map); } std::shared_ptr GetOrCreateExecutionProvider(const std::string& provider_type, @@ -360,6 +353,8 @@ PYBIND11_MODULE(onnxruntime_pybind11_state, m) { m.def("get_version_string", []() -> std::string { return ORT_VERSION; }); + m.def("get_build_info", []() -> std::string { return ORT_BUILD_INFO; }); + m.def( "clear_training_ep_instances", []() -> void { GetTrainingEnv().ClearExecutionProviderInstances(); diff --git a/orttraining/orttraining/python/training/__init__.py b/orttraining/orttraining/python/training/__init__.py index c34bd70a77934..73b1f826f68e1 100644 --- a/orttraining/orttraining/python/training/__init__.py +++ b/orttraining/orttraining/python/training/__init__.py @@ -3,17 +3,39 @@ # Licensed under the MIT License. # -------------------------------------------------------------------------- # isort: skip_file -from onnxruntime.capi._pybind_state import PropagateCastOpsStrategy, TrainingParameters # noqa: F401 -from onnxruntime.capi.training.training_session import TrainingSession # noqa: F401 +from onnxruntime.capi._pybind_state import ( + PropagateCastOpsStrategy, + TrainingParameters, + is_ortmodule_available, +) +from onnxruntime.capi.training.training_session import TrainingSession # Options need to be imported before `ORTTrainer`. -from .orttrainer_options import ORTTrainerOptions # noqa: F401 -from .orttrainer import ORTTrainer, TrainStepInfo # noqa: F401 -from . import amp, artifacts, checkpoint, model_desc_validation, optim # noqa: F401 +from .orttrainer_options import ORTTrainerOptions +from .orttrainer import ORTTrainer, TrainStepInfo +from . import amp, artifacts, checkpoint, model_desc_validation, optim -try: # noqa: SIM105 - from .ortmodule import ORTModule # noqa: F401 +__all__ = [ + "PropagateCastOpsStrategy", + "TrainingParameters", + "is_ortmodule_available", + "TrainingSession", + "ORTTrainerOptions", + "ORTTrainer", + "TrainStepInfo", + "amp", + "artifacts", + "checkpoint", + "model_desc_validation", + "optim", +] + +try: + if is_ortmodule_available(): + from .ortmodule import ORTModule # noqa: F401 + + __all__.append("ORTModule") except ImportError: # That is OK iff this is not a ORTModule training package pass diff --git a/orttraining/orttraining/python/training/_utils.py b/orttraining/orttraining/python/training/_utils.py index f4624a4e0bbff..4eb79443c8f1a 100644 --- a/orttraining/orttraining/python/training/_utils.py +++ b/orttraining/orttraining/python/training/_utils.py @@ -107,7 +107,7 @@ def dtype_torch_to_numpy(torch_dtype): elif torch_dtype == torch.bool: return np.bool_ else: - raise ValueError(f"torch_dtype ({str(torch_dtype)}) type is not supported by Numpy") + raise ValueError(f"torch_dtype ({torch_dtype!s}) type is not supported by Numpy") def dtype_onnx_to_torch(onnx_type): @@ -134,6 +134,10 @@ def dtype_onnx_to_torch(onnx_type): "COMPLEX64", "COMPLEX128", "BFLOAT16", + "FLOAT8E4M3FN", + "FLOAT8E4M3FNUZ", + "FLOAT8E5M2", + "FLOAT8E5M2FNUZ", ] if isinstance(onnx_type, int): diff --git a/orttraining/orttraining/python/training/amp/loss_scaler.py b/orttraining/orttraining/python/training/amp/loss_scaler.py index b842ec9346f9f..440372d9305ea 100644 --- a/orttraining/orttraining/python/training/amp/loss_scaler.py +++ b/orttraining/orttraining/python/training/amp/loss_scaler.py @@ -88,10 +88,10 @@ class DynamicLossScaler(LossScaler): def __init__( self, automatic_update=True, - loss_scale=float(1 << 16), # noqa: B008 + loss_scale=float(1 << 16), up_scale_window=2000, min_loss_scale=1.0, - max_loss_scale=float(1 << 24), # noqa: B008 + max_loss_scale=float(1 << 24), ): super().__init__(loss_scale) self.automatic_update = automatic_update diff --git a/orttraining/orttraining/python/training/api/checkpoint_state.py b/orttraining/orttraining/python/training/api/checkpoint_state.py index 3ee82a9360af7..285264bbed744 100644 --- a/orttraining/orttraining/python/training/api/checkpoint_state.py +++ b/orttraining/orttraining/python/training/api/checkpoint_state.py @@ -9,10 +9,17 @@ class CheckpointState: - """Class that holds the state of the training session state + """Class that holds the state of the training session + + This class holds all the state information of the training session such as the model parameters, + its gradients, the optimizer state and user defined properties. + + User defined properties can be indexed by name from the `CheckpointState` object. + + To create the `CheckpointState`, use the `CheckpointState.load_checkpoint` method. Args: - state (CheckpointState): The C.Checkpoint state object that holds the underlying session state. + state: The C.Checkpoint state object that holds the underlying session state. """ def __init__(self, state: C.CheckpointState): diff --git a/orttraining/orttraining/python/training/api/module.py b/orttraining/orttraining/python/training/api/module.py index 2c87924e49292..f8f6b4322ce79 100644 --- a/orttraining/orttraining/python/training/api/module.py +++ b/orttraining/orttraining/python/training/api/module.py @@ -9,7 +9,7 @@ from onnxruntime.capi import _pybind_state as C from onnxruntime.capi.onnxruntime_inference_collection import OrtValue, get_ort_device_type -from onnxruntime.capi.onnxruntime_pybind11_state import OrtValueVector +from onnxruntime.capi.onnxruntime_pybind11_state import OrtValueVector, SessionOptions from onnxruntime.training.api.checkpoint_state import CheckpointState @@ -25,11 +25,15 @@ class Module: - The optimizer model (optional) - The checkpoint file + Attributes: + training: True if the model is in training mode, False if it is in evaluation mode. + Args: train_model_uri: The path to the training model. state: The checkpoint state object. eval_model_uri: The path to the evaluation model. device: The device to run the model on. Default is "cpu". + session_options: The session options to use for the model. """ training: bool @@ -40,11 +44,13 @@ def __init__( state: CheckpointState, eval_model_uri: os.PathLike | None = None, device: str = "cpu", + session_options: SessionOptions | None = None, ) -> None: self.training = True options = device.split(":") self._device_type = options[0] device_id = 0 if len(options) < 2 else int(options[1]) + self._session_options = session_options if session_options is not None else SessionOptions() self._device = C.OrtDevice( get_ort_device_type(self._device_type, device_id), @@ -56,49 +62,63 @@ def __init__( state._state, os.fspath(eval_model_uri) if eval_model_uri is not None else None, self._device, + self._session_options, ) self._state = state - def __call__(self, *user_inputs) -> tuple[np.ndarray] | np.ndarray: + def __call__(self, *user_inputs) -> tuple[np.ndarray, ...] | np.ndarray | tuple[OrtValue, ...] | OrtValue: """Invokes either the training or the evaluation step of the model. Args: - user_inputs: The inputs to the model. + *user_inputs: The inputs to the model. + The user inputs can be either numpy arrays or OrtValues. Returns: - fetches : The outputs of the model. + The outputs of the model. """ - is_np_input = False - forward_inputs = OrtValueVector() - forward_inputs.reserve(len(user_inputs)) - for tensor in user_inputs: - if isinstance(tensor, np.ndarray): - is_np_input = True - forward_inputs.push_back(OrtValue.ortvalue_from_numpy(tensor)._ortvalue) - elif isinstance(tensor, OrtValue): - forward_inputs.push_back(tensor._ortvalue) - else: - raise ValueError(f"Expected input of type: numpy array or OrtValue, actual: {type(tensor)}") - fetches = OrtValueVector() - if self.training: - self._model.train_step(forward_inputs, fetches) - else: - self._model.eval_step(forward_inputs, fetches) + def _has_np_input(user_inputs): + return any(isinstance(user_input, np.ndarray) for user_input in user_inputs) + + def _take_generic_step(forward_inputs): + fetches = OrtValueVector() + if self.training: + self._model.train_step(forward_inputs, fetches) + else: + self._model.eval_step(forward_inputs, fetches) - if len(fetches) == 1: - if is_np_input: + if len(fetches) == 1: return fetches[0].numpy() - return fetches[0] + return tuple(val.numpy() for val in fetches) + + def _take_step_with_ortvalues(forward_inputs): + ort_values = OrtValueVector() + ort_values.reserve(len(forward_inputs)) + fetches = OrtValueVector() + + for tensor in forward_inputs: + ort_values.push_back(tensor._ortvalue) - return tuple(val.numpy() for val in fetches) if is_np_input else tuple(fetches) + if self.training: + self._model.train_step_with_ort_values(ort_values, fetches) + else: + self._model.eval_step_with_ort_values(ort_values, fetches) + + if len(fetches) == 1: + return OrtValue(fetches[0]) + + return tuple(OrtValue(val) for val in fetches) + + if _has_np_input(user_inputs): + return _take_generic_step([*user_inputs]) + + return _take_step_with_ortvalues(user_inputs) def train(self, mode: bool = True) -> Module: """Sets the Module in training mode. Args: - mode: whether to set training mode (True) or evaluation - mode (False). Default: True. + mode: whether to set the model to training mode (True) or evaluation mode (False). Default: True. Returns: self @@ -140,11 +160,11 @@ def get_contiguous_parameters(self, trainable_only: bool = False) -> OrtValue: self._device_type, self._device.device_id(), )._ortvalue - self._model.copy_parameters_to_buffer(parameters) + self._model.copy_parameters_to_buffer(parameters, trainable_only) return parameters - def get_parameters_size(self, trainable_only: bool = False) -> int: + def get_parameters_size(self, trainable_only: bool = True) -> int: """Returns the size of the parameters. Args: @@ -155,13 +175,13 @@ def get_parameters_size(self, trainable_only: bool = False) -> int: """ return self._model.get_parameters_size(trainable_only) - def copy_buffer_to_parameters(self, buffer: OrtValue) -> None: + def copy_buffer_to_parameters(self, buffer: OrtValue, trainable_only: bool = True) -> None: """Copies the OrtValue buffer to the training session parameters. Args: buffer: The OrtValue buffer to copy to the training session parameters. """ - self._model.copy_buffer_to_parameters(buffer) + self._model.copy_buffer_to_parameters(buffer, trainable_only) def export_model_for_inferencing( self, inference_model_uri: str | os.PathLike, graph_output_names: list[str] @@ -170,6 +190,7 @@ def export_model_for_inferencing( Once training is complete, this function can be used to drop the training specific nodes in the onnx model. In particular, this function does the following: + - Parse over the training graph and identify nodes that generate the given output names. - Drop all subsequent nodes in the graph since they are not relevant to the inference graph. diff --git a/orttraining/orttraining/python/training/api/optimizer.py b/orttraining/orttraining/python/training/api/optimizer.py index e62ee7144162c..3560988ced215 100644 --- a/orttraining/orttraining/python/training/api/optimizer.py +++ b/orttraining/orttraining/python/training/api/optimizer.py @@ -21,7 +21,9 @@ class Optimizer: """ def __init__(self, optimizer_uri: str | os.PathLike, module: Module): - self._optimizer = C.Optimizer(os.fspath(optimizer_uri), module._state._state, module._device) + self._optimizer = C.Optimizer( + os.fspath(optimizer_uri), module._state._state, module._device, module._session_options + ) def step(self) -> None: """Updates the model parameters based on the computed gradients. @@ -43,6 +45,6 @@ def get_learning_rate(self) -> float: """Gets the current learning rate of the optimizer. Returns: - float: The current learning rate. + The current learning rate. """ return self._optimizer.get_learning_rate() diff --git a/orttraining/orttraining/python/training/artifacts.py b/orttraining/orttraining/python/training/artifacts.py index ea519da89a1eb..549614de496a6 100644 --- a/orttraining/orttraining/python/training/artifacts.py +++ b/orttraining/orttraining/python/training/artifacts.py @@ -1,6 +1,7 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. +import contextlib import logging import os import pathlib @@ -9,11 +10,12 @@ import onnx -import onnxruntime.training.onnxblock as onnxblock +from onnxruntime.tools.convert_onnx_models_to_ort import OptimizationStyle, convert_onnx_models_to_ort +from onnxruntime.training import onnxblock class LossType(Enum): - """Enum to represent the loss functions supported by ORT + """Loss type to be added to the training model. To be used with the `loss` parameter of `generate_artifacts` function. """ @@ -25,12 +27,13 @@ class LossType(Enum): class OptimType(Enum): - """Enum to represent the optimizers supported by ORT + """Optimizer type to be to be used while generating the optimizer model for training. To be used with the `optimizer` parameter of `generate_artifacts` function. """ AdamW = 1 + SGD = 2 def generate_artifacts( @@ -47,7 +50,7 @@ def generate_artifacts( This function generates the following artifacts: 1. Training model (onnx.ModelProto): Contains the base model graph, loss sub graph and the gradient graph. 2. Eval model (onnx.ModelProto): Contains the base model graph and the loss sub graph - 3. Checkpoint: Contains the model parameters. + 3. Checkpoint (directory): Contains the model parameters. 4. Optimizer model (onnx.ModelProto): Model containing the optimizer graph. Args: @@ -57,12 +60,15 @@ def generate_artifacts( loss: The loss function enum to be used for training. If None, no loss node is added to the graph. optimizer: The optimizer enum to be used for training. If None, no optimizer model is generated. artifact_directory: The directory to save the generated artifacts. - If None, the current working directory is used. - **extra_options: Additional keyword arguments for artifact generation. - prefix: The prefix to be used for the generated artifacts. If not specified, no prefix is used. + If None, the current working directory is used. + prefix (str): The prefix to be used for the generated artifacts. If not specified, no prefix is used. + ort_format (bool): Whether to save the generated artifacts in ORT format or not. Default is False. + custom_op_library (str | os.PathLike): The path to the custom op library. + If not specified, no custom op library is used. + additional_output_names (List[str]): List of additional output names to be added to the training/eval model. Raises: - RuntimeError: If the loss provided is not one of the supported losses or an instance of onnxblock.Block. + RuntimeError: If the loss provided is neither one of the supported losses nor an instance of `onnxblock.Block` RuntimeError: If the optimizer provided is not one of the supported optimizers. """ @@ -99,6 +105,20 @@ def __init__(self, _loss): self._loss = _loss def build(self, *inputs_to_loss): + if "additional_output_names" in extra_options: + # If additional output names is not a list, raise an error + if not isinstance(extra_options["additional_output_names"], list): + raise RuntimeError( + f"Unknown type provided for additional output names {type(extra_options['additional_output_names'])}. " + "Expected additional output names to be a list of strings." + ) + + loss_output = self._loss(*inputs_to_loss) + if isinstance(loss_output, tuple): + return (*loss_output, *tuple(extra_options["additional_output_names"])) + else: + return (loss_output, *tuple(extra_options["additional_output_names"])) + return self._loss(*inputs_to_loss) training_block = _TrainingBlock(loss_block) @@ -120,11 +140,31 @@ def build(self, *inputs_to_loss): training_model = None eval_model = None model_params = None - with onnxblock.base(model): + + custom_op_library = extra_options.get("custom_op_library", None) + if custom_op_library is not None: + logging.info("Custom op library provided: %s", custom_op_library) + custom_op_library = pathlib.Path(custom_op_library) + + with onnxblock.base(model), onnxblock.custom_op_library( + custom_op_library + ) if custom_op_library is not None else contextlib.nullcontext(): _ = training_block(*[output.name for output in model.graph.output]) training_model, eval_model = training_block.to_model_proto() model_params = training_block.parameters() + def _export_to_ort_format(model_path, output_dir, extra_options): + if extra_options.get("ort_format", False): + custom_op_library = extra_options.get("custom_op_library", None) + if custom_op_library is not None: + custom_op_library = pathlib.Path(custom_op_library) + convert_onnx_models_to_ort( + model_path, + output_dir=output_dir, + custom_op_library_path=custom_op_library, + optimization_styles=[OptimizationStyle.Fixed], + ) + if artifact_directory is None: artifact_directory = pathlib.Path.cwd() prefix = "" @@ -138,12 +178,14 @@ def build(self, *inputs_to_loss): if os.path.exists(training_model_path): logging.info("Training model path %s already exists. Overwriting.", training_model_path) onnx.save(training_model, training_model_path) + _export_to_ort_format(training_model_path, artifact_directory, extra_options) logging.info("Saved training model to %s", training_model_path) eval_model_path = artifact_directory / f"{prefix}eval_model.onnx" if os.path.exists(eval_model_path): logging.info("Eval model path %s already exists. Overwriting.", eval_model_path) onnx.save(eval_model, eval_model_path) + _export_to_ort_format(eval_model_path, artifact_directory, extra_options) logging.info("Saved eval model to %s", eval_model_path) checkpoint_path = artifact_directory / f"{prefix}checkpoint" @@ -166,7 +208,8 @@ def build(self, *inputs_to_loss): logging.info("Optimizer enum provided: %s", optimizer.name) optim_model = None - optim_blocks = {OptimType.AdamW: onnxblock.optim.AdamW} + optim_blocks = {OptimType.AdamW: onnxblock.optim.AdamW, OptimType.SGD: onnxblock.optim.SGD} + optim_block = optim_blocks[optimizer]() with onnxblock.empty_base(): _ = optim_block(model_params) @@ -174,4 +217,5 @@ def build(self, *inputs_to_loss): optimizer_model_path = artifact_directory / f"{prefix}optimizer_model.onnx" onnx.save(optim_model, optimizer_model_path) + _export_to_ort_format(optimizer_model_path, artifact_directory, extra_options) logging.info("Saved optimizer model to %s", optimizer_model_path) diff --git a/orttraining/orttraining/python/training/checkpoint.py b/orttraining/orttraining/python/training/checkpoint.py index 3f2eeb53e0161..d0ff0650662b7 100644 --- a/orttraining/orttraining/python/training/checkpoint.py +++ b/orttraining/orttraining/python/training/checkpoint.py @@ -665,10 +665,10 @@ def __init__(self, checkpoint_files, clean_state_dict=None): self.clean_state_dict = clean_state_dict self.world_size = int(self.checkpoint_files[0].split("ZeRO")[1].split(".")[2]) + 1 assert len(self.checkpoint_files) == self.world_size, f"Could not find {self.world_size} files" - self.weight_shape_map = dict() + self.weight_shape_map = {} self.sharded_params = set() - def _split_name(self, name): + def _split_name(self, name: str): name_split = name.split("_view_") view_num = None if len(name_split) > 1: @@ -684,7 +684,7 @@ def _split_name(self, name): elif name_split[0].endswith("_fp16"): mp_suffix = "_fp16" param_name = name_split[0] - if optimizer_key != "": # noqa: PLC1901 + if optimizer_key: param_name = param_name.split(optimizer_key)[1] param_name = param_name.split("_fp16")[0] return param_name, optimizer_key, view_num, mp_suffix diff --git a/orttraining/orttraining/python/training/experimental/gradient_graph/_gradient_graph_tools.py b/orttraining/orttraining/python/training/experimental/gradient_graph/_gradient_graph_tools.py index a5242ab04789f..5ab79b3712472 100644 --- a/orttraining/orttraining/python/training/experimental/gradient_graph/_gradient_graph_tools.py +++ b/orttraining/orttraining/python/training/experimental/gradient_graph/_gradient_graph_tools.py @@ -38,7 +38,7 @@ def export_gradient_graph( """ # Make sure that loss nodes that expect multiple outputs are set up. - CustomOpSymbolicRegistry.register_all() + CustomOpSymbolicRegistry.register_all(opset_version) if not isinstance(gradient_graph_path, str): gradient_graph_path = str(gradient_graph_path) diff --git a/orttraining/orttraining/python/training/onnxblock/__init__.py b/orttraining/orttraining/python/training/onnxblock/__init__.py index b5245440e9c35..3a1ca772453f5 100644 --- a/orttraining/orttraining/python/training/onnxblock/__init__.py +++ b/orttraining/orttraining/python/training/onnxblock/__init__.py @@ -8,7 +8,7 @@ import onnxruntime.training.onnxblock.optim as optim from onnxruntime.training.onnxblock.blocks import Block from onnxruntime.training.onnxblock.checkpoint_utils import load_checkpoint_to_model, save_checkpoint -from onnxruntime.training.onnxblock.model_accessor import base, empty_base +from onnxruntime.training.onnxblock.model_accessor import base, custom_op_library, empty_base from onnxruntime.training.onnxblock.onnxblock import ForwardBlock, TrainingBlock __all__ = [ @@ -21,5 +21,6 @@ "load_checkpoint_to_model", "save_checkpoint", "base", + "custom_op_library", "empty_base", ] diff --git a/orttraining/orttraining/python/training/onnxblock/_training_graph_utils.py b/orttraining/orttraining/python/training/onnxblock/_training_graph_utils.py index 796267ea3a900..1213342004d48 100644 --- a/orttraining/orttraining/python/training/onnxblock/_training_graph_utils.py +++ b/orttraining/orttraining/python/training/onnxblock/_training_graph_utils.py @@ -2,10 +2,13 @@ # Licensed under the MIT License. import copy +import logging +import os from typing import List, Optional, Set, Tuple, Union import onnx +from onnxruntime import SessionOptions from onnxruntime.capi._pybind_state import GradientGraphBuilder, get_optimized_model @@ -66,17 +69,28 @@ def _move_initializers_to_inputs(model: onnx.ModelProto, initializer_names: Opti def _gradient_model_for( - model: onnx.ModelProto, requires_grad: Set[str], output_names: List[str], loss_name: str + model: onnx.ModelProto, + requires_grad: Set[str], + loss_name: str, + options: Optional[SessionOptions] = None, ) -> onnx.ModelProto: """Builds the gradient graph on top of the given input forward only graph.""" - builder = GradientGraphBuilder(model.SerializeToString(), set(output_names), requires_grad, loss_name) + logging.debug( + "The loss output is %s. The gradient graph will be built starting from %s_grad.", loss_name, loss_name + ) + + builder = GradientGraphBuilder(model.SerializeToString(), {loss_name}, requires_grad, loss_name, options) builder.build() return onnx.load_from_string(builder.get_model()) def build_gradient_graph( - model: onnx.ModelProto, requires_grad: Set[str], frozen_params: Set[str], output_names: Union[List[str], str] + model: onnx.ModelProto, + requires_grad: Set[str], + frozen_params: Set[str], + output_names: Union[List[str], str], + custom_op_library: Optional[str] = None, ) -> Tuple[onnx.ModelProto, onnx.ModelProto]: """Prepare the training model and the eval model. @@ -106,10 +120,14 @@ def build_gradient_graph( eval_model = copy.deepcopy(model) _disable_training_mode(eval_model) - optimized_model = onnx.load_from_string(get_optimized_model(model.SerializeToString(), requires_grad)) + options = SessionOptions() + if custom_op_library is not None: + options.register_custom_ops_library(os.fspath(custom_op_library)) + + optimized_model = onnx.load_from_string(get_optimized_model(model.SerializeToString(), requires_grad, options)) # Assumption is that the first graph output is the loss output - gradient_model = _gradient_model_for(optimized_model, requires_grad, output_names, output_names[0]) + gradient_model = _gradient_model_for(optimized_model, requires_grad, output_names[0], options) _reorder_outputs(gradient_model, output_names, requires_grad) diff --git a/orttraining/orttraining/python/training/onnxblock/blocks.py b/orttraining/orttraining/python/training/onnxblock/blocks.py index f4b62a5e9d4cd..d6146b8509d7b 100644 --- a/orttraining/orttraining/python/training/onnxblock/blocks.py +++ b/orttraining/orttraining/python/training/onnxblock/blocks.py @@ -7,6 +7,7 @@ from abc import ABC, abstractmethod from typing import Any, List, Optional +import numpy as np import onnx import onnxruntime.training.onnxblock._graph_utils as _graph_utils @@ -427,3 +428,51 @@ def build(self, cast_input_name: str): self.base.graph.node.append(cast_node) return cast_output_name + + +class Linear(Block): + def __init__(self, in_features, out_features, bias=True, alpha=1.0, beta=1.0): + super().__init__() + + self._in_features = in_features + self._bias = bias + self._out_features = out_features + self._alpha = alpha + self._beta = beta + + def build(self, linear_input_name: str): + # Weight initializer + linear_node_weight_name = _graph_utils.generate_graph_name("linear.weight") + + self.base.graph.initializer.append( + onnx.numpy_helper.from_array( + np.random.randn(self._in_features, self._out_features).astype(np.float32), linear_node_weight_name + ) + ) + + linear_node_input_names = [linear_input_name, linear_node_weight_name] + + # Bias initializer + if self._bias: + linear_node_bias_name = _graph_utils.generate_graph_name("linear.bias") + self.base.graph.initializer.append( + onnx.numpy_helper.from_array( + np.random.randn(self._out_features).astype(np.float32), linear_node_bias_name + ) + ) + linear_node_input_names.append(linear_node_bias_name) + + linear_node_output_name = _graph_utils.generate_graph_name("linear.output") + linear_node_output_names = [linear_node_output_name] + linear_node = onnx.helper.make_node( + "Gemm", + linear_node_input_names, + linear_node_output_names, + _graph_utils.generate_graph_name("linear"), + alpha=self._alpha, + beta=self._beta, + ) + + self.base.graph.node.append(linear_node) + + return linear_node_output_name diff --git a/orttraining/orttraining/python/training/onnxblock/model_accessor.py b/orttraining/orttraining/python/training/onnxblock/model_accessor.py index 96bdf5f62e235..cff435c5626c4 100644 --- a/orttraining/orttraining/python/training/onnxblock/model_accessor.py +++ b/orttraining/orttraining/python/training/onnxblock/model_accessor.py @@ -1,9 +1,11 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. +from __future__ import annotations + import copy +import os from contextlib import contextmanager -from typing import Optional import onnx @@ -29,10 +31,11 @@ def model(self) -> onnx.ModelProto: return self._model -# This variable resides in the global namespace. +# These variable resides in the global namespace. # Different methods can access this global model and manipulate it. # Its construction and destruction is managed by the base and empty_base contextmanagers _GLOBAL_ACCESSOR = None +_GLOBAL_CUSTOM_OP_LIBRARY = None @contextmanager @@ -74,7 +77,7 @@ def base(model: onnx.ModelProto): @contextmanager -def empty_base(opset_version: Optional[int] = None): +def empty_base(opset_version: int | None = None): """Registers an empty base model to be manipulated by the onnx blocks. Example: @@ -89,8 +92,7 @@ def empty_base(opset_version: Optional[int] = None): model_handle. Args: - opset_version (int, optional): The opset version to use for the model. - Defaults to onnx.defs.onnx_opset_version() + opset_version: The opset version to use for the model. Defaults to onnx.defs.onnx_opset_version() Returns: ModelAccessor: The model accessor that contains the modified model. @@ -115,3 +117,35 @@ def empty_base(opset_version: Optional[int] = None): yield _GLOBAL_ACCESSOR finally: _GLOBAL_ACCESSOR = None + + +@contextmanager +def custom_op_library(custom_op_library_path: os.PathLike): + """Registers the custom op library to be used by the onnx blocks. + + Example: + >>> with onnxblock.custom_op_library(custom_op_library_path): + >>> # manipulate the model using blocks + >>> ... + + In this example, custom_op_library will register the given input custom op library path to be used + during the model manipulation (gradient graph building and optimization). + + Args: + custom_op_library_path: The path to the custom op library. + + Returns: + ModelAccessor: The model accessor that contains the modified model. + """ + global _GLOBAL_CUSTOM_OP_LIBRARY # pylint: disable=global-statement # noqa: PLW0603 + if _GLOBAL_CUSTOM_OP_LIBRARY is not None: + raise RuntimeError("CustomOp library already set. Cannot set multiple custom op libraries.") + + if not os.path.exists(custom_op_library_path): + raise RuntimeError(f"Custom op library path {custom_op_library_path} does not exist.") + + _GLOBAL_CUSTOM_OP_LIBRARY = copy.copy(custom_op_library_path) # noqa: PLW0603 + try: + yield _GLOBAL_CUSTOM_OP_LIBRARY + finally: + _GLOBAL_CUSTOM_OP_LIBRARY = None diff --git a/orttraining/orttraining/python/training/onnxblock/onnxblock.py b/orttraining/orttraining/python/training/onnxblock/onnxblock.py index 17755fe8ab209..a2922353ac70e 100644 --- a/orttraining/orttraining/python/training/onnxblock/onnxblock.py +++ b/orttraining/orttraining/python/training/onnxblock/onnxblock.py @@ -20,7 +20,9 @@ class ForwardBlock(blocks.Block): must subclass this class. The subclass's implementation of the build method must return the name of the graph output. This block will automatically register the output as a graph output and build the model. + Example: + >>> class MyForwardBlock(ForwardBlock): >>> def __init__(self): >>> super().__init__() @@ -84,7 +86,9 @@ class TrainingBlock(blocks.Block): must subclass this class. The subclass's implementation of the build method must return the name of the output from where backpropagation must begin (typically the name of the output from the loss function). + Example: + >>> class MyTrainingBlock(TrainingBlock): >>> def __init__(self): >>> super().__init__() @@ -198,12 +202,11 @@ def __call__(self, *args, **kwargs): # The order of model inputs after gradient graph building is: user inputs, model parameters as inputs # The order of the model outputs is: user outputs, model parameter gradients (in the order of parameter inputs) self._training_model, self._eval_model = _training_graph_utils.build_gradient_graph( - model, - self._requires_grad, - self._frozen_params, - output, + model, self._requires_grad, self._frozen_params, output, accessor._GLOBAL_CUSTOM_OP_LIBRARY ) + logging.debug("Adding gradient accumulation nodes for training block %s", self.__class__.__name__) + _training_graph_utils.build_gradient_accumulation_graph(self._training_model, self._requires_grad) accessor._GLOBAL_ACCESSOR.model.CopyFrom(self._training_model) diff --git a/orttraining/orttraining/python/training/onnxblock/optim/__init__.py b/orttraining/orttraining/python/training/onnxblock/optim/__init__.py index 5d1af763f0493..4384ecf0546cc 100644 --- a/orttraining/orttraining/python/training/onnxblock/optim/__init__.py +++ b/orttraining/orttraining/python/training/onnxblock/optim/__init__.py @@ -1,6 +1,6 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -from onnxruntime.training.onnxblock.optim.optim import AdamW, ClipGradNorm +from onnxruntime.training.onnxblock.optim.optim import SGD, AdamW, ClipGradNorm -__all__ = ["AdamW", "ClipGradNorm"] +__all__ = ["AdamW", "ClipGradNorm", "SGD"] diff --git a/orttraining/orttraining/python/training/onnxblock/optim/optim.py b/orttraining/orttraining/python/training/onnxblock/optim/optim.py index 94d4c2791d779..d14b2efefe916 100644 --- a/orttraining/orttraining/python/training/onnxblock/optim/optim.py +++ b/orttraining/orttraining/python/training/onnxblock/optim/optim.py @@ -1,7 +1,7 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -from typing import Optional, Tuple +from typing import Dict, List, Optional, Tuple import onnx @@ -10,71 +10,6 @@ import onnxruntime.training.onnxblock.onnxblock as onnxblock_module -class AdamWOptimizer(blocks.Block): - """Adds an AdamWOptimizer node to the onnx model.""" - - def __init__( - self, - bias_correction: Optional[bool] = True, - betas: Tuple[float, float] = (0.9, 0.999), - eps: Optional[float] = 1e-6, - weight_decay: Optional[float] = 0.0, - ): - super().__init__() - - self._bias_correction = bias_correction - self._betas = betas - self._eps = eps - self._weight_decay = weight_decay - - def build( # pylint: disable=too-many-arguments - self, - learning_rate_name: str, - step_name: str, - parameter_sequence_name: str, - gradient_sequence_name: str, - first_order_moment_sequence_name: str, - second_order_moment_sequence_name: str, - ): - """Adds the AdamWOptimizer node to the model.""" - - # get the model to manipulate - onnx_model = self.base - - # define the node attributes - node_attributes = { - "alpha": self._betas[0], # beta1 - "beta": self._betas[1], # beta2 - "epsilon": self._eps, # epsilon - "weight_decay": self._weight_decay, # weight decay - "correct_bias": 1 if self._bias_correction else 0, # bias_correction - "adam_mode": 1, # adam mode (1 for hf/transformers/AdamW) - } - - # add the adamw node to the onnx model - adamw_input_names = [ - learning_rate_name, # learning rate - step_name, # training step - parameter_sequence_name, # param to be updated - gradient_sequence_name, # gradient of the param to be used for update - first_order_moment_sequence_name, # first order moment for this param - second_order_moment_sequence_name, # second order moment for this param - ] - adamw_output_name = _graph_utils.generate_graph_name("adamw.updated_flag") - adamw_output_names = [adamw_output_name] - adamw_node = onnx.helper.make_node( - "AdamWOptimizer", - adamw_input_names, - adamw_output_names, - name=_graph_utils.generate_graph_name("AdamWOptimizer"), - domain="com.microsoft", - **node_attributes, - ) - onnx_model.graph.node.append(adamw_node) - - return adamw_output_name - - class ClipGradNorm(blocks.Block): """Builds a gradient clipping by norm sub graph for the onnx model. @@ -125,59 +60,162 @@ def build(self, gradients_name: str): return cgn_node_output_name -class AdamW(onnxblock_module.ForwardBlock): - """Builds AdamW optimizer onnxblock for the given training parameters. +class _OptimizerBase(blocks.Block): + def __init__(self): + super().__init__() - Creates a block that updates the model parameters based on the calculated - gradient following the AdamW algorithm. + def _build_optimizer_node( + self, + input_names: List[str], + output_name: str, + node_name: str, + node_attributes: Dict, + ) -> str: + """ + Build and append an optimizer node to the ONNX graph. + + Args: + input_names (list): List of input tensor names for the optimizer node. + output_name (str): Output tensor name of the optimizer node. + node_name (str): Name of the optimizer node. + node_attributes (dict): Additional attributes for the optimizer node. + + Returns: + str: The output tensor name of the optimizer node. + """ + onnx_model = self.base - Args: - bias_correction: bool indicating whether to perform bias correction. - betas: AdamW decay rate hyperparameters. - eps: term added to the denominator for computing the moments. - weight_decay: AdamW weight decay - clip_grad (optional): an instance of the ClipGradNorm. If not provided, - gradient clipping will not be done. + # add the optimizer node to the onnx model + optimizer_node = onnx.helper.make_node( + node_name, + input_names, + [output_name], + name=_graph_utils.generate_graph_name(node_name), + domain="com.microsoft", + **node_attributes, + ) - Returns: - Returns a string of the output names from this optimizer node. - """ + onnx_model.graph.node.append(optimizer_node) + return output_name + + +class SGDOptimizer(_OptimizerBase): + def __init__(self): + super().__init__() + + def build( + self, + learning_rate_name: str, + gradients_name: str, + params_name: str, + ) -> str: + """ + Build an SGD optimizer node. + + Args: + learning_rate_name (str): Name of the learning rate input tensor. + gradients_name (str): Name of the gradients input tensor. + params_name (str): Name of the weights input tensor. + + Returns: + str: The output tensor name of the SGD optimizer node. + """ + + input_names = [learning_rate_name, gradients_name, params_name] + + return self._build_optimizer_node( + input_names, + _graph_utils.generate_graph_name("update_completed"), + "SGDOptimizerV2", + {}, + ) + + +class AdamWOptimizer(_OptimizerBase): def __init__( self, bias_correction: Optional[bool] = True, betas: Tuple[float, float] = (0.9, 0.999), eps: Optional[float] = 1e-6, weight_decay: Optional[float] = 0.0, - clip_grad=None, - ): # pylint: disable=too-many-arguments + ): super().__init__() - self._adamw = AdamWOptimizer( - bias_correction=bias_correction, - betas=betas, - eps=eps, - weight_decay=weight_decay, + self._bias_correction = bias_correction + self._betas = betas + self._eps = eps + self._weight_decay = weight_decay + + def build( + self, + learning_rate_name: str, + step_name: str, + parameter_sequence_name: str, + gradient_sequence_name: str, + first_order_moment_sequence_name: str, + second_order_moment_sequence_name: str, + ) -> str: + """ + Build an AdamW optimizer node. + + Args: + learning_rate_name (str): Name of the learning rate input tensor. + step_name (str): Name of the step input tensor. + parameter_sequence_name (str): Name of the parameter sequence input tensor. + gradient_sequence_name (str): Name of the gradient sequence input tensor. + first_order_moment_sequence_name (str): Name of the first order moment sequence input tensor. + second_order_moment_sequence_name (str): Name of the second order moment sequence input tensor. + + Returns: + str: The output tensor name of the AdamW optimizer node. + """ + + input_names = [ + learning_rate_name, + step_name, + parameter_sequence_name, + gradient_sequence_name, + first_order_moment_sequence_name, + second_order_moment_sequence_name, + ] + + # define the node attributes + node_attributes = { + "alpha": self._betas[0], # beta1 + "beta": self._betas[1], # beta2 + "epsilon": self._eps, # epsilon + "weight_decay": self._weight_decay, # weight decay + "correct_bias": 1 if self._bias_correction else 0, # bias_correction + "adam_mode": 1, # adam mode (1 for hf/transformers/AdamW) + } + + return self._build_optimizer_node( + input_names, + _graph_utils.generate_graph_name("adamw.updated_flag"), + "AdamWOptimizer", + node_attributes, ) + + +class _Optimizer(onnxblock_module.ForwardBlock): + """Base class for building optimizer onnxblocks.""" + + def __init__(self, clip_grad=None): + super().__init__() self._clip_grad = clip_grad def build(self, parameters): - """Returns an AdamW optimizer model based on the input parameters.""" - - # get the model to manipulate and update its namespace onnx_model = self.base - # TODO: Avoid hard coded input/output strings learning_rate_name = "learning_rate" - step_name = "step" params_name = "params" - first_order_moments_name = "first_order_moments" - second_order_moments_name = "second_order_moments" gradients_name = "gradients" + step_name = "step" + first_order_moments_name = "first_order_moments" trainable_parameters, _ = parameters - # create the graph inputs for the lr, step, params, grads, moments onnx_model.graph.input.extend( [ onnx.helper.make_tensor_value_info(learning_rate_name, onnx.TensorProto.FLOAT, [1]), @@ -185,17 +223,61 @@ def build(self, parameters): ] ) - # Prepare the tensor sequence inputs for params and moments - for input_name in [params_name, gradients_name, first_order_moments_name, second_order_moments_name]: + for input_name in [params_name, gradients_name, first_order_moments_name]: onnx_model.graph.input.append( onnx.helper.make_tensor_sequence_value_info(input_name, trainable_parameters[0].data_type, None) ) - # Clip the gradients if needed if self._clip_grad is not None: gradients_name = self._clip_grad(gradients_name) - # Run multi tensor AdamWOptimizer + updated_flag_name = self._optimizer_specific_logic( + learning_rate_name, params_name, gradients_name, trainable_parameters + ) + + return updated_flag_name + + def _optimizer_specific_logic( + self, + learning_rate_name: str, + params_name: str, + gradients_name: str, + trainable_parameters: Tuple[List[onnx.TensorProto], List[onnx.TensorProto]], + ) -> str: + raise NotImplementedError("Subclasses must implement _optimizer_specific_logic method.") + + +class AdamW(_Optimizer): + """Builds AdamW optimizer onnxblock for the given training parameters.""" + + def __init__(self, bias_correction=True, betas=(0.9, 0.999), eps=1e-6, weight_decay=0.0, clip_grad=None): + super().__init__(clip_grad) + self._adamw = AdamWOptimizer( + bias_correction=bias_correction, + betas=betas, + eps=eps, + weight_decay=weight_decay, + ) + + def _optimizer_specific_logic( + self, + learning_rate_name: str, + params_name: str, + gradients_name: str, + trainable_parameters: Tuple[List[onnx.TensorProto], List[onnx.TensorProto]], + ) -> str: + onnx_model = self.base + step_name = "step" + first_order_moments_name = "first_order_moments" + second_order_moments_name = "second_order_moments" + + # Prepare the tensor sequence inputs for moments + onnx_model.graph.input.append( + onnx.helper.make_tensor_sequence_value_info( + second_order_moments_name, trainable_parameters[0].data_type, None + ) + ) + updated_flag_name = self._adamw( learning_rate_name, step_name, @@ -205,9 +287,34 @@ def build(self, parameters): second_order_moments_name, ) - # Create the graph outputs + # Create graph outputs for AdamW + onnx_model.graph.output.append( + onnx.helper.make_tensor_value_info(updated_flag_name, onnx.TensorProto.BOOL, [1]) + ) + + return updated_flag_name + + +class SGD(_Optimizer): + """Builds SGD optimizer onnxblock for the given training parameters.""" + + def __init__(self, clip_grad=None): + super().__init__(clip_grad) + self._sgd = SGDOptimizer() + + def _optimizer_specific_logic( + self, + learning_rate_name: str, + params_name: str, + gradients_name: str, + trainable_parameters: Tuple[List[onnx.TensorProto], List[onnx.TensorProto]], + ) -> str: + onnx_model = self.base + updated_flag_name = self._sgd(learning_rate_name, params_name, gradients_name) + + # Create graph outputs for SGD onnx_model.graph.output.append( - onnx.helper.make_tensor_value_info(updated_flag_name, onnx.TensorProto.INT64, [1]) + onnx.helper.make_tensor_value_info(updated_flag_name, onnx.TensorProto.BOOL, [1]) ) return updated_flag_name diff --git a/orttraining/orttraining/python/training/optim/_megatron_modifier.py b/orttraining/orttraining/python/training/optim/_megatron_modifier.py index b6c5823110382..707727120c5cd 100644 --- a/orttraining/orttraining/python/training/optim/_megatron_modifier.py +++ b/orttraining/orttraining/python/training/optim/_megatron_modifier.py @@ -48,7 +48,7 @@ def clip_master_grads(target, max_norm, norm_type=2): fp32_params = [] for param_group in target.optimizer.param_groups: for param in param_group["params"]: - fp32_params.append(param) + fp32_params.append(param) # noqa: PERF402 #### THIS IS THE ORIGINAL IMPLEMENTATION #### # return self.clip_grad_norm(fp32_params, max_norm, norm_type) #### END OF THE ORIGINAL IMPLEMENTATION #### @@ -69,10 +69,10 @@ def _check_overflow(target): params = [] for group in target.fp16_groups: for param in group: - params.append(param) + params.append(param) # noqa: PERF402 for group in target.fp32_from_fp32_groups: for param in group: - params.append(param) + params.append(param) # noqa: PERF402 #### THIS IS THE ORIGINAL IMPLEMENTATION #### # self.overflow = self.loss_scaler.has_overflow(params) #### END OF THE ORIGINAL IMPLEMENTATION #### diff --git a/orttraining/orttraining/python/training/optim/_modifier.py b/orttraining/orttraining/python/training/optim/_modifier.py index e9296bc63d560..30178bf4845b2 100644 --- a/orttraining/orttraining/python/training/optim/_modifier.py +++ b/orttraining/orttraining/python/training/optim/_modifier.py @@ -137,7 +137,13 @@ def param_is_not_tensor_parallel_duplicate(param): else: for grad in grads_for_norm: - grad_norm = torch.norm(grad, norm_type) + # torch.norm is deprecated and moved to torch.linalg.norm + # with a different signature + # see https://pytorch.org/docs/stable/generated/torch.norm.html + if norm_type in {"fro", "nuc"}: + grad_norm = torch.linalg.matrix_norm(grad, norm_type) + else: + grad_norm = torch.linalg.norm(grad, norm_type) total_norm += grad_norm**norm_type if horizontal_model_parallel_grad_norm_aggregation: diff --git a/orttraining/orttraining/python/training/optim/config.py b/orttraining/orttraining/python/training/optim/config.py index d0b6d5fc33993..d63c7ab40a787 100644 --- a/orttraining/orttraining/python/training/optim/config.py +++ b/orttraining/orttraining/python/training/optim/config.py @@ -55,7 +55,7 @@ def __init__(self, name, params, defaults): "Each dict inside 'params' must contain a {'params' : [model parameter names]} entry" " and additional entries for custom hyper parameter values" ) - for k, _ in group.items(): + for k in group: if k != "params": assert ( k in defaults or k.replace("_coef", "") in defaults diff --git a/orttraining/orttraining/python/training/optim/fused_adam.py b/orttraining/orttraining/python/training/optim/fused_adam.py index 52c6cb623e020..ae8654080e69a 100644 --- a/orttraining/orttraining/python/training/optim/fused_adam.py +++ b/orttraining/orttraining/python/training/optim/fused_adam.py @@ -56,6 +56,7 @@ class FusedAdam(torch.optim.Optimizer): (AdamWMode.ADAMW_TORCH) (default: AdamWMode.ADAMW_TRANSFORMERS) set_grad_none (bool, optional): whether set grad to None when zero_grad() method is called. (default: True) + PyTorch Adam has set_to_none parameter in zero_grad(), supporting that too .. _Adam - A Method for Stochastic Optimization: https://arxiv.org/abs/1412.6980 @@ -91,8 +92,8 @@ def __init__( self._multi_tensor_applier = MultiTensorApply(2048 * 32) self._TorchTensorVector = fused_ops.TorchTensorVector - def zero_grad(self): - if self._set_grad_none: + def zero_grad(self, set_to_none=True): + if self._set_grad_none or set_to_none: for group in self.param_groups: for p in group["params"]: p.grad = None diff --git a/orttraining/orttraining/python/training/ort_triton/__init__.py b/orttraining/orttraining/python/training/ort_triton/__init__.py new file mode 100644 index 0000000000000..fbb59d1354ae7 --- /dev/null +++ b/orttraining/orttraining/python/training/ort_triton/__init__.py @@ -0,0 +1,37 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# -------------------------------------------------------------------------- + +import threading +from functools import wraps + +from onnxruntime.capi import _pybind_state as _C + +from .kernel import * # noqa: F403 +from .triton_op_executor import call_triton_by_name, call_triton_by_onnx, get_config + + +def run_once_register_triton_op_executor(f): + """ + Decorator to run a function only once. + :param f: function to be run only once during execution time despite the number of calls + :return: The original function with the params passed to it if it hasn't already been run before + """ + + @wraps(f) + def register_triton_op_executor_wrapper(*args, **kwargs): + if not register_triton_op_executor_wrapper.has_run: + with register_triton_op_executor_wrapper.lock: + if not register_triton_op_executor_wrapper.has_run: + register_triton_op_executor_wrapper.has_run = True + f(*args, **kwargs) + + register_triton_op_executor_wrapper.lock = threading.Lock() + register_triton_op_executor_wrapper.has_run = False + return register_triton_op_executor_wrapper + + +@run_once_register_triton_op_executor +def register_triton_op_executor(): + _C.register_triton_op_executor(get_config, call_triton_by_name, call_triton_by_onnx) diff --git a/orttraining/orttraining/python/training/ort_triton/_cache.py b/orttraining/orttraining/python/training/ort_triton/_cache.py new file mode 100644 index 0000000000000..ede9cd86a9da5 --- /dev/null +++ b/orttraining/orttraining/python/training/ort_triton/_cache.py @@ -0,0 +1,79 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# -------------------------------------------------------------------------- + +# from torch/_inductor/codecache.py +import base64 +import functools +import getpass +import hashlib +import os +import tempfile +from types import ModuleType +from typing import Tuple + + +@functools.lru_cache(None) +def _cache_dir(): + return f"{tempfile.gettempdir()}/ort_triton_{getpass.getuser()}" + + +def _code_hash(code): + return "c" + base64.b32encode(hashlib.sha256(code.encode("utf-8")).digest())[:51].decode("utf-8").lower() + + +def _get_code_path(source_code, ext, extra): + basename = _code_hash(source_code + extra) + subdir = os.path.join(_cache_dir(), basename[1:3]) + path = os.path.join(subdir, f"{basename}.{ext}") + return basename, subdir, path + + +def _write_atomic(path: str, source_code: str): + # use a temp file for thread safety + fd, tmp_path = tempfile.mkstemp(dir=os.path.dirname(path)) + with os.fdopen(fd, "w") as f: + f.write(source_code) + os.rename(tmp_path, path) + + +def _write(source_code, ext, extra=""): + basename, subdir, path = _get_code_path(source_code, ext, extra) + if not os.path.exists(subdir): + os.makedirs(subdir, exist_ok=True) + if not os.path.exists(path): + _write_atomic(path, source_code) + return basename, path + + +class PyCodeCache: + cache = dict() # noqa: RUF012 + clear = staticmethod(cache.clear) + + @classmethod + def load(cls, source_code) -> ModuleType: + key, path = _write(source_code, "py") + if key not in cls.cache: + with open(path) as f: + code = compile(f.read(), path, "exec") + mod = ModuleType(f"{__name__}.{key}") + mod.__file__ = path + mod.key = key + exec(code, mod.__dict__, mod.__dict__) + # another thread might set this first + cls.cache.setdefault(key, mod) + return cls.cache[key] + + +class ModuleCache: + cache = dict() # noqa: RUF012 + clear = staticmethod(cache.clear) + + @classmethod + def load(cls, key_func, mod_func, *args) -> Tuple[str, ModuleType]: + key = key_func(*args) + if key not in cls.cache: + func_name, mod = mod_func(*args) + cls.cache[key] = (func_name, mod) + return cls.cache[key] diff --git a/orttraining/orttraining/python/training/ort_triton/_codegen.py b/orttraining/orttraining/python/training/ort_triton/_codegen.py new file mode 100644 index 0000000000000..c071f01f87ea5 --- /dev/null +++ b/orttraining/orttraining/python/training/ort_triton/_codegen.py @@ -0,0 +1,485 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# -------------------------------------------------------------------------- + +""" +Generate code for each IR node. +Mostly, Nodes are classified into two categories: + 1. ElementwiseKernelNode: compute a tensor from other tensors, e.g. ElementwiseKernelNode + 2. ReduceKernelNode: perform a reduction computation on a tensor, e.g. reduce_sum/max/min + one or more axes are supported + +""" + +from typing import Tuple + +import numpy as np +import sympy +import torch +from sympy.codegen.rewriting import create_expand_pow_optimization + +from ._common import CodeBuffer, CodegenContext, NodeVisitor +from ._ir import ( + ComputeNode, + DropoutNode, + ElementwiseKernelNode, + IONode, + IRNode, + KernelNode, + ModuleNode, + OffsetCalculator, + ReduceForLoopEnd, + ReduceForLoopStart, + ReduceKernelNode, + ReduceNode, +) +from ._lowering import lower +from ._sorted_graph import SortedGraph +from ._sympy_utils import parse_shape, sympy_dot +from ._utils import may_add_brackets + + +class TritonCodegen(NodeVisitor): + """ + Specialized codegen for Triton backend. + """ + + def __init__(self): + super().__init__() + + def codegen(self, node: IRNode, context: CodegenContext, code_buffer: CodeBuffer, indent: int): + func = getattr(self, node.__class__.__name__) + assert func is not None, "unimplemented node: %s" % node.__class__.__name__ + func(node, context, code_buffer, indent) + + def _get_elementwise_offset_mask(self, offset_calc: OffsetCalculator, arg_name: str) -> Tuple[str, str]: + if offset_calc.is_x_reduced(arg_name): + return "", "" + if offset_calc.is_same_x_shape(arg_name): + return "xindex", "xmask" if offset_calc.requires_x_mask else "" + strides = offset_calc.get_input_strides(arg_name) + idx_var = [f"x{idx}" for idx in range(len(strides))] + expand_opt = create_expand_pow_optimization(6) + offset_str = str(expand_opt(sympy_dot(parse_shape(idx_var), strides))) + return offset_str, "xmask" if offset_calc.requires_x_mask else "" + + def _get_reduce_offset_mask(self, offset_calc: OffsetCalculator, arg_name: str) -> Tuple[str, str]: + offset_strs = [] + mask_strs = [] + if not offset_calc.is_x_reduced(arg_name): + x_strides = offset_calc.get_x_input_strides(arg_name) + if offset_calc.is_same_x_shape(arg_name): + xindex_str = "xindex" if x_strides[-1] == sympy.Integer(1) else f"xindex * {x_strides[-1]}" + else: + idx_var = [f"x{idx}" for idx in range(len(x_strides))] + expand_opt = create_expand_pow_optimization(6) + xindex_str = str(expand_opt(sympy_dot(parse_shape(idx_var), x_strides))) + offset_strs.append(xindex_str) + if offset_calc.requires_x_mask: + mask_strs.append("xmask") + + if not offset_calc.is_r_reduced(arg_name): + r_strides = offset_calc.get_r_input_strides(arg_name) + if offset_calc.is_same_r_shape(arg_name): + rindex_str = "rindex" if r_strides[-1] == sympy.Integer(1) else f"rindex * {r_strides[-1]}" + else: + idx_var = [f"r{idx}" for idx in range(len(r_strides))] + expand_opt = create_expand_pow_optimization(6) + rindex_str = str(expand_opt(sympy_dot(parse_shape(idx_var), r_strides))) + offset_strs.append(rindex_str) + if offset_calc.requires_r_mask: + mask_strs.append("rmask") + + return " + ".join(offset_strs), " & ".join(mask_strs) + + def _get_offset_mask(self, node: OffsetCalculator, arg_name: str) -> Tuple[str, str]: + return ( + self._get_reduce_offset_mask(node, arg_name) + if node.is_reduction + else self._get_elementwise_offset_mask(node, arg_name) + ) + + def IONode(self, node: IONode, context: CodegenContext, code_buffer: CodeBuffer, indent: int): # noqa: N802 + space_indent = " " * indent + name = node.tensor_arg.name + var_name = context.get_variable_name(name) + internal_var_name = context.get_internal_variable_name(name) + assert ( + var_name != internal_var_name + ), f"variable name {var_name} and its internal variable name should not be the same." + + offset_str, mask_str = self._get_offset_mask(node.offset_calc, node.tensor_arg.name) + if offset_str: + offset_str = f" + {offset_str}" + if mask_str: + mask_str = f", {mask_str}" + if node.is_load and mask_str: + mask_str += ", other=0.0" + + if node.is_load: + code_buffer += f"{space_indent}{internal_var_name} = tl.load({var_name}{offset_str}{mask_str})\n" + else: + code_buffer += f"{space_indent}tl.store({var_name}{offset_str}, {internal_var_name}{mask_str})\n" + + def _gen_kernel_signature(self, node: KernelNode, context: CodegenContext, code_buffer: CodeBuffer, indent: int): + is_reduction = node.offset_calc.is_reduction + space_indent = " " * indent + autotune_configs_str = "" + for config in node.offset_calc.autotune_configs.configs: + if is_reduction: + autotune_configs_str += ( + f'{space_indent} triton.Config({{"XBLOCK": {config[0]}, "RBLOCK": {config[1]}}}, ' + f"num_warps={config[2]}),\n" + ) + else: + autotune_configs_str += ( + f'{space_indent} triton.Config({{"XBLOCK": {config[0]}}}, num_warps={config[2]}),\n' + ) + keys_str = '"xnumel", "rnumel"' if is_reduction else '"xnumel"' + input_args = [context.get_variable_name(input.name) for input in node.inputs] + input_args_str = ", ".join(input_args) + if input_args_str: + input_args_str += ", " + + output_args = [context.get_variable_name(output.name) for output in node.outputs] + output_args_str = ", ".join(output_args) + ", " + + other_input_args = "seed_cuda, " if node.has_dropout else "" + # Support symbolic shape if any. + symbolic_shape_args_str = ", ".join(node.symbolic_shape_variables) + if symbolic_shape_args_str: + other_input_args += f"{symbolic_shape_args_str}, " + + blocks_str = ( + "xnumel, rnumel, XBLOCK: tl.constexpr, RBLOCK: tl.constexpr" + if is_reduction + else "xnumel, XBLOCK: tl.constexpr" + ) + + code_buffer += ( + f"{space_indent}@triton.autotune(\n" + f"{space_indent} configs=[\n" + f"{autotune_configs_str}" + f"{space_indent} ],\n" + f"{space_indent} key=[{keys_str}],\n" + f"{space_indent})\n" + f"{space_indent}@triton.jit\n" + f"{space_indent}def {node.name}({input_args_str}{output_args_str}{other_input_args}{blocks_str}):\n" + ) + + def ElementwiseKernelNode( # noqa: N802 + self, node: ElementwiseKernelNode, context: CodegenContext, code_buffer: CodeBuffer, indent: int + ): + self._gen_kernel_signature(node, context, code_buffer, indent) + offset_calc = node.offset_calc + indent += 4 + space_indent = " " * indent + code_buffer += ( + f"{space_indent}xnumel = {offset_calc.x_numel}\n" + f"{space_indent}xoffset = tl.program_id(0) * XBLOCK\n" + f"{space_indent}xindex = xoffset + tl.arange(0, XBLOCK)\n" + ) + if offset_calc.requires_x_mask: + code_buffer += f"{space_indent}xmask = xindex < xnumel\n" + for idx in range(offset_calc.x_rank): + if idx in offset_calc.x_compute_dims: + div_str = ( + f" // {may_add_brackets(str(offset_calc.x_strides[idx]))}" if idx != offset_calc.x_rank - 1 else "" + ) + mod_str = f" % {may_add_brackets(str(offset_calc.x_dims[idx]))}" if idx != 0 else "" + code_buffer += f"{space_indent}x{idx} = xindex{div_str}{mod_str}\n" + code_buffer += "\n" + + if node.has_dropout: + code_buffer += ( + f"{space_indent}t_seed_cuda = tl.load(seed_cuda)\n" + f"{space_indent}t_seed_cuda = tl.broadcast_to(t_seed_cuda, [XBLOCK])\n" + ) + + for ir_node in node.sub_nodes: + ir_node.codegen(self, context, code_buffer, indent) + + def ReduceKernelNode( # noqa: N802 + self, node: ReduceKernelNode, context: CodegenContext, code_buffer: CodeBuffer, indent: int + ): + self._gen_kernel_signature(node, context, code_buffer, indent) + offset_calc = node.offset_calc + indent += 4 + space_indent = " " * indent + code_buffer += ( + f"{space_indent}xnumel = {offset_calc.x_numel}\n" + f"{space_indent}rnumel = {offset_calc.r_numel}\n" + f"{space_indent}xoffset = tl.program_id(0) * XBLOCK\n" + f"{space_indent}xindex = xoffset + tl.arange(0, XBLOCK)[:, None]\n" + f"{space_indent}rbase = tl.arange(0, RBLOCK)[None, :]\n" + ) + if offset_calc.requires_x_mask: + code_buffer += f"{space_indent}xmask = xindex < xnumel\n" + for idx in range(offset_calc.x_rank): + if idx in offset_calc.x_compute_dims: + div_str = ( + f" // {may_add_brackets(str(offset_calc.x_strides[idx]))}" if idx != offset_calc.x_rank - 1 else "" + ) + mod_str = f" % {may_add_brackets(str(offset_calc.x_dims[idx]))}" if idx != 0 else "" + code_buffer += f"{space_indent}x{idx} = xindex{div_str}{mod_str}\n" + code_buffer += "\n" + + if node.has_dropout: + code_buffer += f"{space_indent}t_seed_cuda = tl.load(seed_cuda)\n" + code_buffer += f"{space_indent}t_seed_cuda = tl.broadcast_to(t_seed_cuda, [XBLOCK, RBLOCK])\n" + + if not offset_calc.autotune_configs.requires_for_loop: + code_buffer += f"{space_indent}rindex = rbase\n" + if offset_calc.requires_r_mask: + code_buffer += f"{space_indent}rmask = rindex < rnumel\n" + for idx in range(offset_calc.r_rank): + if idx in offset_calc.r_compute_dims: + div_str = ( + f" // {may_add_brackets(str(offset_calc.r_strides[idx]))}" + if idx != offset_calc.r_rank - 1 + else "" + ) + mod_str = f" % {may_add_brackets(str(offset_calc.r_dims[idx]))}" if idx != 0 else "" + code_buffer += f"{space_indent}r{idx} = rindex{div_str}{mod_str}\n" + + for ir_node in node.sub_nodes: + ir_node.codegen(self, context, code_buffer, indent) + if isinstance(ir_node, ReduceForLoopStart): + indent += 4 + elif isinstance(ir_node, ReduceForLoopEnd): + indent -= 4 + + _COMPUTE_CODE_TEMPLATES = { # noqa: RUF012 + "Add": "{indent}{o0} = {i0} + {i1}\n", + "Sub": "{indent}{o0} = {i0} - {i1}\n", + "Mul": "{indent}{o0} = {i0} * {i1}\n", + "Div": "{indent}{o0} = {i0} / {i1}\n", + "Relu": "{indent}{o0} = tl.maximum({i0}, 0.0)\n", + "Pow": "{indent}{o0} = tl.math.pow({i0}, {i1})\n", + "Pow2": "{indent}{o0} = {i0} * {i0}\n", + "Pow3": "{indent}{o0} = {i0} * {i0} * {i0}\n", + "Sqrt": "{indent}{o0} = tl.sqrt({i0})\n", + "Rsqrt": "{indent}{o0} = 1.0 / tl.sqrt({i0})\n", + "Cast": "{indent}{o0} = {i0}.to(tl.{dtype})\n", + "CastBool": "{indent}{o0} = {i0} != 0\n", + "Erf": "{indent}{o0} = tl.libdevice.erf({i0})\n", + "Gelu": "{indent}{o0} = (tl.libdevice.erf({i0} / 1.41421356237) + 1.0) * 0.5\n", + "Exp": "{indent}{o0} = tl.exp({i0})\n", + "Tanh": "{indent}{o0} = tl.libdevice.tanh({i0})\n", + "Where": "{indent}{o0} = tl.where({i0}, {i1}, {i2})\n", + "Sigmoid": "{indent}{o0} = tl.sigmoid({i0})\n", + "Log": "{indent}{o0} = tl.log({i0})\n", + "DropoutGrad": "{indent}p = 1 - {i2}\n{indent}{o0} = tl.where({i1}, {i0} / p, 0.0)\n", + "Identity": "{indent}{o0} = {i0}\n", + } + + def ComputeNode( # noqa: N802 + self, node: ComputeNode, context: CodegenContext, code_buffer: CodeBuffer, indent: int + ): + space_indent = " " * indent + kwargs = {} + for idx, input in enumerate(node.inputs): + kwargs[f"i{idx}"] = context.get_internal_variable_name(input.name) + for idx, output in enumerate(node.outputs): + kwargs[f"o{idx}"] = context.get_internal_variable_name(output.name) + + op_type = node.op_type + if op_type == "Pow": + if kwargs["i1"] == 2: + op_type = "Pow2" + elif kwargs["i1"] == 3: + op_type = "Pow3" + elif kwargs["i1"] == 0.5: + op_type = "Sqrt" + + if op_type == "Cast": + from_dtype = node.inputs[0].dtype.type + to_dtype = node.outputs[0].dtype.type + if from_dtype == to_dtype: + op_type = "Identity" + elif to_dtype == np.bool_: + op_type = "CastBool" + else: + kwargs["dtype"] = to_dtype.__name__ + + if op_type == "Sum": + output_var = kwargs["o0"] + formula = " + ".join([kwargs[f"i{idx}"] for idx in range(len(node.inputs))]) + code_buffer += f"{space_indent}{output_var} = {formula}\n" + return + + code_buffer += TritonCodegen._COMPUTE_CODE_TEMPLATES[op_type].format(indent=space_indent, **kwargs) + + def ReduceNode(self, node: ReduceNode, context: CodegenContext, code_buffer: CodeBuffer, indent: int): # noqa: N802 + space_indent = " " * indent + input_var_name = context.get_internal_variable_name(node.inputs[0].name) + output_var_name = context.get_internal_variable_name(node.outputs[0].name) + masks = [] + if node.offset_calc.requires_x_mask: + masks.append("xmask") + if node.offset_calc.requires_r_mask: + masks.append("rmask") + if len(masks) > 0: + masks_str = " & ".join(masks) + code_buffer += ( + f"{space_indent}{input_var_name} = tl.where({masks_str}, {input_var_name}, {node.default_value})\n" + ) + code_buffer += f"{space_indent}{output_var_name} = {node.triton_func}({input_var_name}, axis=1)[:, None]\n" + + def ReduceForLoopStart( # noqa: N802 + self, node: ReduceForLoopStart, context: CodegenContext, code_buffer: CodeBuffer, indent: int + ): + space_indent = " " * indent + offset_calc = node.offset_calc + for reduce_node in node.reduce_nodes: + tmp_var_name = "tmp_" + context.get_internal_variable_name(reduce_node.outputs[0].name) + code_buffer += ( + f"{space_indent}{tmp_var_name} = " + f"tl.zeros([XBLOCK, RBLOCK], tl.float32) + {reduce_node.default_value}\n" + ) + code_buffer += ( + f"{space_indent}for roffset in range(0, rnumel, RBLOCK):\n{space_indent} rindex = rbase + roffset\n" + ) + if offset_calc.requires_r_mask: + code_buffer += f"{space_indent} rmask = rindex < rnumel\n" + for idx in range(offset_calc.r_rank): + if idx in offset_calc.r_compute_dims: + div_str = ( + f" // {may_add_brackets(str(offset_calc.r_strides[idx]))}" if idx != offset_calc.r_rank - 1 else "" + ) + mod_str = f" % {may_add_brackets(str(offset_calc.r_dims[idx]))}" if idx != 0 else "" + code_buffer += f"{space_indent} r{idx} = rindex{div_str}{mod_str}\n" + + def ReduceForLoopEnd( # noqa: N802 + self, node: ReduceForLoopEnd, context: CodegenContext, code_buffer: CodeBuffer, indent: int + ): + space_indent = " " * indent + offset_calc = node.offset_calc + masks = [] + if offset_calc.requires_x_mask: + masks.append("xmask") + if offset_calc.requires_r_mask: + masks.append("rmask") + masks_str = " & ".join(masks) + for reduce_node in node.reduce_nodes: + input_var_name = context.get_internal_variable_name(reduce_node.inputs[0].name) + output_var_name = context.get_internal_variable_name(reduce_node.outputs[0].name) + tmp_output_var_name = "tmp_" + output_var_name + if reduce_node.op_type == "ReduceSum": + if not masks_str: + code_buffer += f"{space_indent}{tmp_output_var_name} = {tmp_output_var_name} + {input_var_name}\n" + else: + code_buffer += ( + f"{space_indent}{tmp_output_var_name} = " + f"tl.where({masks_str}, {tmp_output_var_name} + {input_var_name}, {tmp_output_var_name})\n" + ) + else: + op_str = " < " if reduce_node.op_type == "ReduceMax" else " > " + if masks_str: + masks_str += " & " + code_buffer += ( + f"{space_indent}{tmp_output_var_name} = tl.where(" + f"{masks_str}({tmp_output_var_name}{op_str}{input_var_name}), " + f"{input_var_name}, {tmp_output_var_name})\n" + ) + space_indent_outside = " " * (indent - 4) + for reduce_node in node.reduce_nodes: + output_var_name = context.get_internal_variable_name(reduce_node.outputs[0].name) + input_var_name = "tmp_" + output_var_name + code_buffer += ( + f"{space_indent_outside}{output_var_name} = " + f"{reduce_node.triton_func}({input_var_name}, axis=1)[:, None]\n" + ) + + def DropoutNode( # noqa: N802 + self, node: DropoutNode, context: CodegenContext, code_buffer: CodeBuffer, indent: int + ): + space_indent = " " * indent + input_var_name = context.get_internal_variable_name(node.inputs[0].name) + p_var_name = context.get_internal_variable_name(node.inputs[1].name) + output_var_name = context.get_internal_variable_name(node.outputs[0].name) + mask_var_name = ( + context.get_internal_variable_name(node.outputs[1].name) + if len(node.outputs) >= 2 + else "dropout_mask_output" + ) + offset_str = f"{node.global_offset} + " if node.global_offset != sympy.Integer(0) else "" + offset_str += self._get_offset_mask(node.offset_calc, node.inputs[0].name)[0] + code_buffer += ( + f"{space_indent}p = 1 - {p_var_name}\n" + f"{space_indent}random = tl.rand(t_seed_cuda, {offset_str})\n" + f"{space_indent}{mask_var_name} = random < p\n" + f"{space_indent}{output_var_name} = tl.where({mask_var_name}, {input_var_name} / p, 0.0)\n" + ) + + def ModuleNode(self, node: ModuleNode, context: CodegenContext, code_buffer: CodeBuffer, indent: int): # noqa: N802 + space_indent = " " * indent + code_buffer += ( + f"{space_indent}import triton\n" + f"{space_indent}import triton.language as tl\n" + f"{space_indent}import torch\n" + ) + + for kernel_node in node.kernels: + code_buffer += "\n\n" + kernel_node.codegen(self, CodegenContext(kernel_node.var_map), code_buffer, indent) + + input_args = ", ".join([context.get_variable_name(input.name) for input in node.inputs]) + code_buffer += f"\n\n{space_indent}def {node.func_name}({input_args}):\n" + + indent += 4 + space_indent = " " * indent + + if node.has_dropout: + code_buffer += ( + f'{space_indent}seed_cuda = torch.randint(2**31, size=(), dtype=torch.int64, device="cuda")\n\n' + ) + + for idx, kernel_node in enumerate(node.kernels): + if idx != 0: + code_buffer += "\n" + # Allocate output tensor. + for output in kernel_node.outputs: + torch_dtype = torch.from_numpy(np.zeros(1, dtype=output.dtype)).dtype + # Workaround for DLPack which doesn't support bool. + if torch_dtype == torch.bool: + torch_dtype = torch.uint8 + code_buffer += ( + f"{space_indent}{context.get_variable_name(output.name)} = " + f'torch.empty({tuple(output.shape)}, dtype={torch_dtype}, device="cuda")\n' + ) + kernel_args_str = ", ".join([context.get_variable_name(input.name) for input in kernel_node.inputs]) + if kernel_args_str: + kernel_args_str += ", " + kernel_args_str += ", ".join([context.get_variable_name(output.name) for output in kernel_node.outputs]) + # TODO: support other kinds of variable args, such as symbolic shape variable. + if kernel_node.has_dropout: + kernel_args_str += ", seed_cuda" + + if isinstance(kernel_node, ReduceKernelNode): + code_buffer += ( + f"{space_indent}x_numel = {kernel_node.offset_calc.x_numel}\n" + f"{space_indent}r_numel = {kernel_node.offset_calc.r_numel}\n" + f'{space_indent}grid = lambda meta: (triton.cdiv(x_numel, meta["XBLOCK"]),)\n' + f"{space_indent}{kernel_node.name}[grid]({kernel_args_str}, x_numel, r_numel)\n" + ) + else: + code_buffer += ( + f"{space_indent}n_elements = {kernel_node.offset_calc.x_numel}\n" + f'{space_indent}grid = lambda meta: (triton.cdiv(n_elements, meta["XBLOCK"]),)\n' + f"{space_indent}{kernel_node.name}[grid]({kernel_args_str}, n_elements)\n" + ) + + for name in node.cross_kernel_args_to_delete[idx]: + code_buffer += f"{space_indent}del {name}\n" + + return_output_str = ", ".join([context.get_variable_name(output.name) for output in node.outputs]) + code_buffer += f"\n{space_indent}return {return_output_str}\n" + + +def codegen(func_name: str, sorted_graph: SortedGraph) -> str: + module_node = lower(func_name, sorted_graph) + code_buffer = CodeBuffer() + module_node.codegen(TritonCodegen(), CodegenContext(module_node.var_map), code_buffer) + return str(code_buffer) diff --git a/orttraining/orttraining/python/training/ort_triton/_common.py b/orttraining/orttraining/python/training/ort_triton/_common.py new file mode 100644 index 0000000000000..65540202420b5 --- /dev/null +++ b/orttraining/orttraining/python/training/ort_triton/_common.py @@ -0,0 +1,188 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# -------------------------------------------------------------------------- + +from abc import abstractmethod +from typing import Any, Dict, List, Tuple + +import sympy +from onnx import GraphProto, NodeProto, TensorProto + +from ._sympy_utils import parse_shape +from ._utils import get_attribute, get_reduce_info, next_power_of_2 + + +class CodegenContext: + """ + record variable name mapping in term of IRnodes. + """ + + def __init__(self, var_map: Dict[str, str]): + self._var_map: Dict[str, str] = {**var_map} + + # Get variable name by the node arg name in ONNX graph. + def get_variable_name(self, name: str) -> str: + return self._var_map[name] + + # For some operators such as data load/store, we need an internal variable name inside the kernel function. + def get_internal_variable_name(self, name: str) -> str: + var_name = self._var_map[name] + return self._var_map[var_name] if var_name in self._var_map else var_name + + +class CodeBuffer: + def __init__(self): + self.buffer: List[str] = [] + + def __iadd__(self, other: str): + self.buffer.append(other) + return self + + def __str__(self): + return "".join(self.buffer) + + +class NodeVisitor: + @abstractmethod + def codegen(self, node: Any, context: CodegenContext, code_buffer: CodeBuffer, indent: int): + pass + + +class TensorInfo: + """ + Represent a input/output tensor of a node. + """ + + def __init__(self, dtype: TensorProto.DataType, shape: List[Any]): + self._dtype: TensorProto.DataType = dtype + self._shape: List[sympy.Expr] = parse_shape(shape) + + @property + def dtype(self) -> TensorProto.DataType: + return self._dtype + + @property + def shape(self) -> List[sympy.Expr]: + return self._shape + + +def _infer_elementwise_shape(input_infos: List[TensorInfo]) -> List[sympy.Expr]: + max_len = max([len(input_info.shape) for input_info in input_infos]) + output_shape: List[sympy.Expr] = [sympy.Integer(1)] * max_len + for input_info in input_infos: + offset = max_len - len(input_info.shape) + for i in range(len(input_info.shape)): + if not input_info.shape[i].is_number or input_info.shape[i] != 1: + output_shape[i + offset] = input_info.shape[i] + return output_shape + + +def _infer_elementwise(node: NodeProto, input_infos: List[TensorInfo], graph: GraphProto) -> List[TensorInfo]: + return [TensorInfo(input_infos[0].dtype, _infer_elementwise_shape(input_infos))] + + +def _infer_where(node: NodeProto, input_infos: List[TensorInfo], graph: GraphProto) -> List[TensorInfo]: + return [TensorInfo(input_infos[1].dtype, _infer_elementwise_shape(input_infos))] + + +def _infer_reduction(node: NodeProto, input_infos: List[TensorInfo], graph: GraphProto) -> List[TensorInfo]: + input_rank = len(input_infos[0].shape) + keep_dims, axes = get_reduce_info(node, graph, input_rank) + axes = [axis + input_rank if axis < 0 else axis for axis in axes] + axes.sort() + shape = [input_infos[0].shape[i] for i in range(input_rank) if i not in axes] + if keep_dims: + for axis in axes: + shape.insert(axis, sympy.Integer(1)) + return [TensorInfo(input_infos[0].dtype, shape)] + + +def _infer_unary(node: NodeProto, input_infos: List[TensorInfo], graph: GraphProto) -> List[TensorInfo]: + return [input_infos[0]] + + +def _infer_cast(node: NodeProto, input_infos: List[TensorInfo], graph: GraphProto) -> List[TensorInfo]: + dtype = get_attribute(node, "to", TensorProto.UNDEFINED) + assert dtype != TensorProto.UNDEFINED + return [TensorInfo(dtype, input_infos[0].shape)] + + +def _infer_dropout(node: NodeProto, input_infos: List[TensorInfo], graph: GraphProto) -> List[TensorInfo]: + return [input_infos[0], TensorInfo(TensorProto.BOOL, input_infos[0].shape)] + + +class TypeAndShapeInfer: + _INFER_FUNC_MAP = { # noqa: RUF012 + "Add": _infer_elementwise, + "Sub": _infer_elementwise, + "Mul": _infer_elementwise, + "Div": _infer_elementwise, + "Pow": _infer_elementwise, + "Sqrt": _infer_elementwise, + "Exp": _infer_elementwise, + "Where": _infer_where, + "Rsqrt": _infer_elementwise, + "Cast": _infer_cast, + "Dropout": _infer_dropout, + "DropoutGrad": _infer_unary, + "Identity": _infer_unary, + "ReduceSum": _infer_reduction, + "ReduceMax": _infer_reduction, + "ReduceMin": _infer_reduction, + "Sum": _infer_elementwise, + } + + @classmethod + def infer(cls, node: NodeProto, input_infos: List[TensorInfo], graph: GraphProto) -> List[TensorInfo]: + if node.op_type not in cls._INFER_FUNC_MAP: + raise NotImplementedError(f"Unsupported op type: {node.op_type}") + return cls._INFER_FUNC_MAP[node.op_type](node, input_infos, graph) + + +class AutotuneConfigs: + """ + Generate all autotune configs for a kernel function by it's xnumel and rnumel. + A config is a tuple of (xblock, rblock, num_warps). + If it's elementwise kernel, the rnumel is 1. + If it's reduction kernel on last contiguous dimensions, the contiguous flag is True. + """ + + def __init__(self, x_numel: int, r_numel: int, contiguous: bool): + self.configs: List[Tuple[int, int, int]] = self._gen_autotune_configs(x_numel, r_numel, contiguous) + self.requires_for_loop: bool = any(config[1] < r_numel for config in self.configs) + + def _num_warps(self, x: int, r: int) -> int: + return min(max(x * r // 256, 2), 8) + + def _gen_config(self, xnp2: int, rnp2: int, x: int, r: int) -> Tuple[int, int, int]: + x = min(x, xnp2) + r = min(r, rnp2) + return x, r, self._num_warps(x, r) + + # TODO: we need to tune more kernels to get more reasonable configs for better performance. + def _gen_autotune_configs(self, x_numel: int, r_numel: int, contiguous: bool) -> List[Tuple[int, int, int]]: + configs = [] + xnp2 = next_power_of_2(x_numel) + if r_numel == 1: + configs.append(self._gen_config(xnp2, 1, 1024, 1)) + if xnp2 > 1024: + configs.append(self._gen_config(xnp2, 1, 2048, 1)) + return configs + rnp2 = next_power_of_2(r_numel) + if contiguous: + configs.append(self._gen_config(xnp2, rnp2, 1, 2048)) + if rnp2 > 2048: + configs.append(self._gen_config(xnp2, rnp2, 1, 4096)) + elif rnp2 <= 256: + x = min(xnp2, 256 // rnp2 * 2) + configs.append(self._gen_config(xnp2, rnp2, x, rnp2)) + else: + config_set = { + self._gen_config(xnp2, rnp2, 1, 2048), + self._gen_config(xnp2, rnp2, 4, 512), + self._gen_config(xnp2, rnp2, 8, 512), + self._gen_config(xnp2, rnp2, 32, 128), + } + configs = list(config_set) + return configs diff --git a/orttraining/orttraining/python/training/ort_triton/_decompose.py b/orttraining/orttraining/python/training/ort_triton/_decompose.py new file mode 100644 index 0000000000000..e18bb16bb80db --- /dev/null +++ b/orttraining/orttraining/python/training/ort_triton/_decompose.py @@ -0,0 +1,371 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# -------------------------------------------------------------------------- + +""" +Decompose a complicated op into a series of simple ops. +"simple ops" can be executed in one pass +""" + +from typing import List + +import numpy as np +import sympy +from onnx import GraphProto, NodeProto, TensorProto, helper + +from ._utils import get_attribute, get_reduce_info, to_numpy_type + + +def _is_half_dtype(dtype: int): + return dtype in [TensorProto.FLOAT16, TensorProto.BFLOAT16] + + +class DecomposeDispatch: + """ + A node does only responsible for a single computation or a type of triton ops. + For those compound Onnx nodes, like softmax/layernorm/groupnorm, etc., we need to decompose them into a series of + simple ops. + """ + + def __init__(self): + self.count = 0 + + def __call__(self, node: NodeProto, graph: GraphProto, **kwargs) -> List[NodeProto]: + op_type = node.op_type + if not hasattr(self, op_type): + raise NotImplementedError(f"Not implemented for op type: {op_type}") + return getattr(self, op_type)(node, graph, **kwargs) + + def __contains__(self, node: NodeProto) -> bool: + return hasattr(self, node.op_type) + + def _get_unique_var_name(self, prefix): + self.count += 1 + return prefix + str(self.count) + + def _new_node(self, node_name, op_type, inputs, outputs=None, **kwargs): + name = self._get_unique_var_name(f"{node_name}_{op_type}_") + if outputs is None: + outputs = [f"{name}_out"] + for idx, output in enumerate(outputs): + if output is None: + outputs[idx] = f"{name}_out{idx}" + return helper.make_node(op_type, inputs, outputs, name, **kwargs), *outputs + + def _get_dtype_and_shape(self, arg_name: str, **kwargs): + node_arg_infos = kwargs["node_arg_infos"] + arg_info = node_arg_infos[arg_name] + return arg_info.dtype, arg_info.shape + + def _decompose_elementwise_precision(self, node: NodeProto, graph: GraphProto, **kwargs): + x = node.input[0] + dtype, _ = self._get_dtype_and_shape(x, **kwargs) + if not _is_half_dtype(dtype): + return [node] + node_name = node.name + y = node.output[0] + op_type = node.op_type + inputs = [input for input in node.input] + cast_nodes = [] + for idx, input in enumerate(inputs): + dtype, _ = self._get_dtype_and_shape(input, **kwargs) + if _is_half_dtype(dtype): + cast_node, cast_out = self._new_node(node_name, "Cast", [input], to=TensorProto.FLOAT) + cast_nodes.append(cast_node) + inputs[idx] = cast_out + op_node, op_out = self._new_node(node_name, op_type, inputs) + cast_node1, _ = self._new_node(node_name, "Cast", [op_out], outputs=[y], to=dtype) + return [*cast_nodes, op_node, cast_node1] + + def Exp(self, node: NodeProto, graph: GraphProto, **kwargs): # noqa: N802 + return self._decompose_elementwise_precision(node, graph, **kwargs) + + def Pow(self, node: NodeProto, graph: GraphProto, **kwargs): # noqa: N802 + return self._decompose_elementwise_precision(node, graph, **kwargs) + + def Sqrt(self, node: NodeProto, graph: GraphProto, **kwargs): # noqa: N802 + return self._decompose_elementwise_precision(node, graph, **kwargs) + + def LayerNormalization(self, node: NodeProto, graph: GraphProto, **kwargs): # noqa: N802 + node_name = node.name + x = node.input[0] + w = node.input[1] + b = node.input[2] + y = node.output[0] + mean = node.output[1] if len(node.output) > 1 and node.output[1] else None + inv_std_dev = node.output[2] if len(node.output) > 2 and node.output[2] else None + axis = get_attribute(node, "axis", -1) + epsilon = get_attribute(node, "epsilon", 1e-05) + xdtype, shape = self._get_dtype_and_shape(x, **kwargs) + wdtype, _ = self._get_dtype_and_shape(w, **kwargs) + is_x_half = _is_half_dtype(xdtype) + is_w_half = _is_half_dtype(wdtype) + if is_x_half or is_w_half: + decomposed_nodes = [] + if is_x_half: + cast_node, x = self._new_node(node_name, "Cast", [x], to=TensorProto.FLOAT) + decomposed_nodes.append(cast_node) + if is_w_half: + cast_node1, w = self._new_node(node_name, "Cast", [w], to=TensorProto.FLOAT) + cast_node2, b = self._new_node(node_name, "Cast", [b], to=TensorProto.FLOAT) + decomposed_nodes.append(cast_node1) + decomposed_nodes.append(cast_node2) + outputs = [None] if is_w_half else [y] + if mean is not None: + outputs.append(mean) + if inv_std_dev is not None: + outputs.append(inv_std_dev) + layer_norm_node_outputs = self._new_node( + node_name, "LayerNormalization", [x, w, b], outputs=outputs, axis=axis, epsilon=epsilon + ) + decomposed_nodes.append(layer_norm_node_outputs[0]) + if is_w_half: + cast_node3, _ = self._new_node(node_name, "Cast", [layer_norm_node_outputs[1]], outputs=[y], to=wdtype) + decomposed_nodes.append(cast_node3) + return decomposed_nodes + rank = len(shape) + if axis < 0: + axis += rank + axes = list(range(axis, rank)) + epsilon_tensor = helper.make_tensor(name="epsilon_const", data_type=xdtype, dims=(1,), vals=np.array([epsilon])) + const_node, const_out = self._new_node(node_name, "Constant", [], value=epsilon_tensor) + reducemean_node, reducemean_out = self._new_node(node_name, "ReduceMean", [x], outputs=[mean], axes=axes) + sub_node, sub_out = self._new_node(node_name, "Sub", [x, reducemean_out]) + mul_node, mul_out = self._new_node(node_name, "Mul", [sub_out, sub_out]) + reducemean_node1, reducemean_out1 = self._new_node(node_name, "ReduceMean", [mul_out], axes=axes) + add_node, add_out = self._new_node(node_name, "Add", [reducemean_out1, const_out]) + rsqrt_node, rsqrt_out = self._new_node(node_name, "Rsqrt", [add_out], outputs=[inv_std_dev]) + mul_node1, mul_out1 = self._new_node(node_name, "Mul", [sub_out, rsqrt_out]) + mul_node2, mul_out2 = self._new_node(node_name, "Mul", [w, mul_out1]) + add_node1, _ = self._new_node(node_name, "Add", [b, mul_out2], outputs=[y]) + return [ + const_node, + reducemean_node, + sub_node, + mul_node, + reducemean_node1, + add_node, + rsqrt_node, + mul_node1, + mul_node2, + add_node1, + ] + + def LayerNormalizationGrad(self, node: NodeProto, graph: GraphProto, **kwargs): # noqa: N802 + node_name = node.name + dy = node.input[0] + x = node.input[1] + w = node.input[2] + mean = node.input[3] + inv_std_dev = node.input[4] + dx = node.output[0] + dw = node.output[1] if len(node.output) > 1 and node.output[1] else None + db = node.output[2] if len(node.output) > 2 and node.output[2] else None + axis = get_attribute(node, "axis", -1) + xdtype, shape = self._get_dtype_and_shape(x, **kwargs) + wdtype, _ = self._get_dtype_and_shape(w, **kwargs) + is_x_half = _is_half_dtype(xdtype) + is_w_half = _is_half_dtype(wdtype) + if is_x_half or is_w_half: + decomposed_nodes = [] + if is_x_half: + cast_node, x = self._new_node(node_name, "Cast", [x], to=TensorProto.FLOAT) + decomposed_nodes.append(cast_node) + if is_w_half: + cast_node1, dy = self._new_node(node_name, "Cast", [dy], to=TensorProto.FLOAT) + cast_node2, w = self._new_node(node_name, "Cast", [w], to=TensorProto.FLOAT) + decomposed_nodes.append(cast_node1) + decomposed_nodes.append(cast_node2) + outputs = [None] if is_x_half else [dx] + if dw is not None: + outputs.append(None if is_w_half else dw) + if db is not None: + outputs.append(None if is_w_half else db) + layer_norm_grad_node_outputs = self._new_node( + node_name, "LayerNormalizationGrad", [dy, x, w, mean, inv_std_dev], outputs=outputs, axis=axis + ) + decomposed_nodes.append(layer_norm_grad_node_outputs[0]) + if is_x_half: + cast_node3, _ = self._new_node( + node_name, "Cast", [layer_norm_grad_node_outputs[1]], outputs=[dx], to=xdtype + ) + decomposed_nodes.append(cast_node3) + if dw is not None and is_w_half: + cast_node4, _ = self._new_node( + node_name, "Cast", [layer_norm_grad_node_outputs[2]], outputs=[dw], to=wdtype + ) + decomposed_nodes.append(cast_node4) + if db is not None and is_w_half: + cast_node5, _ = self._new_node( + node_name, "Cast", [layer_norm_grad_node_outputs[3]], outputs=[db], to=wdtype + ) + decomposed_nodes.append(cast_node5) + return decomposed_nodes + rank = len(shape) + if axis < 0: + axis += rank + axes = list(range(axis, rank)) + sub_node, sub_out = self._new_node(node_name, "Sub", [x, mean]) + mul_node, mul_out = self._new_node(node_name, "Mul", [sub_out, inv_std_dev]) + mul_node1, mul_out1 = self._new_node(node_name, "Mul", [w, dy]) + mul_node2, mul_out2 = self._new_node(node_name, "Mul", [mul_out, mul_out1]) + reducemean_node, reducemean_out = self._new_node(node_name, "ReduceMean", [mul_out2], axes=axes) + reducemean_node1, reducemean_out1 = self._new_node(node_name, "ReduceMean", [mul_out1], axes=axes) + mul_node3, mul_out3 = self._new_node(node_name, "Mul", [reducemean_out, mul_out]) + add_node, add_out = self._new_node(node_name, "Add", [mul_out3, reducemean_out1]) + sub_node1, sub_out1 = self._new_node(node_name, "Sub", [mul_out1, add_out]) + mul_node4, _ = self._new_node(node_name, "Mul", [sub_out1, inv_std_dev], outputs=[dx]) + decomposed_nodes = [ + sub_node, + mul_node, + mul_node1, + mul_node2, + reducemean_node, + reducemean_node1, + mul_node3, + add_node, + sub_node1, + mul_node4, + ] + dw_axes = list(range(axis)) + if dw is not None: + mul_node5, mul_out5 = self._new_node(node_name, "Mul", [dy, mul_out]) + reducesum_node, _ = self._new_node( + node_name, "ReduceSum", [mul_out5], outputs=[dw], axes=dw_axes, keepdims=0 + ) + decomposed_nodes.extend([mul_node5, reducesum_node]) + if db is not None: + reducesum_node1, _ = self._new_node(node_name, "ReduceSum", [dy], outputs=[db], axes=dw_axes, keepdims=0) + decomposed_nodes.append(reducesum_node1) + return decomposed_nodes + + def Softmax(self, node: NodeProto, graph: GraphProto, **kwargs): # noqa: N802 + node_name = node.name + x = node.input[0] + y = node.output[0] + axis = get_attribute(node, "axis", -1) + dtype, _ = self._get_dtype_and_shape(x, **kwargs) + if _is_half_dtype(dtype): + cast_node, x = self._new_node(node_name, "Cast", [x], to=TensorProto.FLOAT) + softmax_node, softmax_out = self._new_node(node_name, "Softmax", [x], axis=axis) + cast_node1, _ = self._new_node(node_name, "Cast", [softmax_out], outputs=[y], to=dtype) + return [cast_node, softmax_node, cast_node1] + max_node, max_out = self._new_node(node_name, "ReduceMax", [x], axes=[axis]) + sub_node, sub_out = self._new_node(node_name, "Sub", [x, max_out]) + exp_node, exp_out = self._new_node(node_name, "Exp", [sub_out]) + sum_node, sum_out = self._new_node(node_name, "ReduceSum", [exp_out], axes=[axis]) + div_node, _ = self._new_node(node_name, "Div", [exp_out, sum_out], outputs=[y]) + return [max_node, sub_node, exp_node, sum_node, div_node] + + def SoftmaxGrad_13(self, node: NodeProto, graph: GraphProto, **kwargs): # noqa: N802 + node_name = node.name + dy = node.input[0] + y = node.input[1] + dx = node.output[0] + axis = get_attribute(node, "axis", -1) + dtype, _ = self._get_dtype_and_shape(dy, **kwargs) + if _is_half_dtype(dtype): + cast_node, dy = self._new_node(node_name, "Cast", [dy], to=TensorProto.FLOAT) + cast_node1, y = self._new_node(node_name, "Cast", [y], to=TensorProto.FLOAT) + softmax_grad_node, softmax_grad_out = self._new_node(node_name, "SoftmaxGrad_13", [dy, y], axis=axis) + cast_node2, _ = self._new_node(node_name, "Cast", [softmax_grad_out], outputs=[dx], to=dtype) + return [cast_node, cast_node1, softmax_grad_node, cast_node2] + mul_node, mul_out = self._new_node(node_name, "Mul", [dy, y]) + sum_node, sum_out = self._new_node(node_name, "ReduceSum", [mul_out], axes=[axis]) + mul_node1, mul_out1 = self._new_node(node_name, "Mul", [y, sum_out]) + sub_node, _ = self._new_node(node_name, "Sub", [mul_out, mul_out1], outputs=[dx]) + return [mul_node, sum_node, mul_node1, sub_node] + + # We support to codegen for reduce Ops that are reducing on contiguous axes. If it's not, we need to decompose + # it to multiple reduce Ops. + def _decompose_reduce_axes(self, node: NodeProto, graph: GraphProto, **kwargs): + node_name = node.name + op_type = node.op_type + x = node.input[0] + y = node.output[0] + _, shape = self._get_dtype_and_shape(x, **kwargs) + rank = len(shape) + keep_dims, axes = get_reduce_info(node, graph, rank) + if len(axes) == 0: + identity_node, _ = self._new_node(node_name, "Identity", [x], outputs=[y]) + return [identity_node] + splited_axes = [] + end = len(axes) + start = end - 1 + while True: + while start > 0 and axes[start] == axes[start - 1] + 1: + start -= 1 + splited_axes.append(axes[start:end]) + if start == 0: + break + end = start + start = end - 1 + if len(splited_axes) == 1: + if len(node.input) <= 1: + return [node] + reduce_node, _ = self._new_node(node_name, op_type, [x], outputs=[y], axes=axes, keepdims=keep_dims) + return [reduce_node] + result = [] + for idx, axes in enumerate(splited_axes): + outputs = [y] if idx == len(splited_axes) - 1 else None + reduce_node, x = self._new_node(node_name, op_type, [x], outputs=outputs, axes=axes, keepdims=keep_dims) + result.append(reduce_node) + return result + + def _decompose_reduce_precision(self, node: NodeProto, graph: GraphProto, **kwargs): + x = node.input[0] + dtype, shape = self._get_dtype_and_shape(x, **kwargs) + if not _is_half_dtype(dtype): + return [node] + node_name = node.name + rank = len(shape) + keep_dims, axes = get_reduce_info(node, graph, rank) + y = node.output[0] + cast_node, x = self._new_node(node_name, "Cast", [x], to=TensorProto.FLOAT) + reduce_node, reduce_out = self._new_node(node_name, node.op_type, [x], axes=axes, keepdims=keep_dims) + cast_node1, _ = self._new_node(node_name, "Cast", [reduce_out], outputs=[y], to=dtype) + return [cast_node, reduce_node, cast_node1] + + def ReduceMax(self, node: NodeProto, graph: GraphProto, **kwargs): # noqa: N802 + return self._decompose_reduce_axes(node, graph, **kwargs) + + def ReduceMin(self, node: NodeProto, graph: GraphProto, **kwargs): # noqa: N802 + return self._decompose_reduce_axes(node, graph, **kwargs) + + def ReduceSum(self, node: NodeProto, graph: GraphProto, **kwargs): # noqa: N802 + precision_decompose_result = self._decompose_reduce_precision(node, graph, **kwargs) + # The decompose process will be called recursively, if it's already a decomposed result, just return. + if len(precision_decompose_result) != 1 or precision_decompose_result[0] != node: + return precision_decompose_result + return self._decompose_reduce_axes(node, graph, **kwargs) + + def ReduceMean(self, node: NodeProto, graph: GraphProto, **kwargs): # noqa: N802 + precision_decompose_result = self._decompose_reduce_precision(node, graph, **kwargs) + # The decompose process will be called recursively, if it's already a decomposed result, just return. + if len(precision_decompose_result) != 1 or precision_decompose_result[0] != node: + return precision_decompose_result + axes_decompose_result = self._decompose_reduce_axes(node, graph, **kwargs) + # The decompose process will be called recursively, if it's already a decomposed result, just return. + if len(axes_decompose_result) != 1 or axes_decompose_result[0] != node: + return axes_decompose_result + node_name = node.name + x = node.input[0] + y = node.output[0] + dtype, shape = self._get_dtype_and_shape(x, **kwargs) + rank = len(shape) + keep_dims, axes = get_reduce_info(node, graph, rank) + sum_node, sum_out = self._new_node(node_name, "ReduceSum", [x], axes=axes, keepdims=keep_dims) + # If it's not concrete shape, we need add more Ops such as Shape, Gather to get the dim value, + # which is not supported yet. + assert all(shape[axis].is_number for axis in axes) + denominator = int(sympy.prod([shape[axis] for axis in axes])) + denominator_tensor = helper.make_tensor( + name=f"{node_name}_denominator", + dims=(), + data_type=dtype, + vals=np.array([denominator], dtype=to_numpy_type(dtype)), + ) + denominator_node, denominator_out = self._new_node(node_name, "Constant", [], value=denominator_tensor) + div_node, _ = self._new_node(node_name, "Div", [sum_out, denominator_out], outputs=[y]) + return [sum_node, denominator_node, div_node] diff --git a/orttraining/orttraining/python/training/ort_triton/_ir.py b/orttraining/orttraining/python/training/ort_triton/_ir.py new file mode 100644 index 0000000000000..8aa5c1b13159b --- /dev/null +++ b/orttraining/orttraining/python/training/ort_triton/_ir.py @@ -0,0 +1,363 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# -------------------------------------------------------------------------- + +from abc import abstractmethod +from collections import defaultdict +from typing import Dict, List, Optional, Set, Tuple + +import numpy as np +import sympy + +from ._common import AutotuneConfigs, CodeBuffer, CodegenContext, NodeVisitor, TensorInfo +from ._sympy_utils import parse_shape +from ._utils import gen_unique_name, gen_variable_name, sort_reduce_axes, to_numpy_type + + +class TensorArg: + """ + A TensorArg represents a tensor argument in the kernel function. + It contains a name (from ONNX graph), the data type, the shape. + If it's constant (initializer or constant node), it also contains the data in numpy array. + """ + + def __init__(self, name: str, tensor_info: Optional[TensorInfo] = None, data: Optional[np.ndarray] = None): + self._name: str = name + self._data: Optional[np.ndarray] = data + if data is not None: + self._dtype: np.dtype = data.dtype + self._shape: List[sympy.Expr] = parse_shape(list(data.shape)) + else: + assert tensor_info is not None + self._dtype: np.dtype = to_numpy_type(tensor_info.dtype) + self._shape: List[sympy.Expr] = tensor_info.shape + self.cross_kernels: bool = False + + @property + def name(self) -> str: + return self._name + + @property + def dtype(self) -> np.dtype: + return self._dtype + + @property + def shape(self) -> List[sympy.Expr]: + return self._shape + + @property + def data(self) -> Optional[np.ndarray]: + return self._data + + +class OffsetCalculator: + """ + OffsetCalculator maps tensor arguments to the target shape of a kernel. + It' used to generate the offset code for data load/store for a tensor argument in a kernel with + specific target shape. + If the reduce_axes is not empty, it means the kernel is a reduction kernel, otherwise it's an element-wise kernel. + It requires the axes in reduce_axes are contiguous. + If a reduce node has non-contiguous axes, need to decompose it into multiple reduce nodes before code-gen. + """ + + def __init__(self, target_shape: List[sympy.Expr], reduce_axes: List[int]): + self.target_shape: List[sympy.Expr] = target_shape + self.is_reduction: bool = len(reduce_axes) > 0 + self.rank = len(target_shape) + self.reduce_axes = sort_reduce_axes(reduce_axes, self.rank) + self.x_dims: List[sympy.Expr] = [target_shape[dim] for dim in range(self.rank) if dim not in self.reduce_axes] + self.x_rank: int = len(self.x_dims) + self.x_numel: sympy.Expr = sympy.prod(self.x_dims) if self.x_rank > 0 else sympy.Integer(1) + self.r_dims: List[sympy.Expr] = [target_shape[dim] for dim in self.reduce_axes] + self.r_rank: int = len(self.r_dims) + self.r_numel: sympy.Expr = sympy.prod(self.r_dims) if self.r_rank > 0 else sympy.Integer(1) + self.x_strides: List[sympy.Expr] = [] + if self.x_rank > 0: + self.x_strides.append(sympy.Integer(1)) + for i in range(self.x_rank - 2, -1, -1): + self.x_strides.insert(0, self.x_strides[0] * self.x_dims[i + 1]) + # To avoid generating useless code for offset calculation, we use x_compute_dims and r_compute_dims to + # track the dimensions that need to be computed in the offset calculation. These 2 sets will be set in + # register_tensor_arg function below. + self.x_compute_dims: Set[int] = set() + self.r_strides: List[sympy.Expr] = [] + if self.r_rank > 0: + self.r_strides.append(sympy.Integer(1)) + for i in range(self.r_rank - 2, -1, -1): + self.r_strides.insert(0, self.r_strides[0] * self.r_dims[i + 1]) + self.r_compute_dims: Set[int] = set() + self.input_strides: Dict[str, List[sympy.Expr]] = dict() + # Support concrete shape only for now. + assert self.x_numel.is_integer and self.r_numel.is_integer + self.autotune_configs: AutotuneConfigs = AutotuneConfigs( + int(self.x_numel), int(self.r_numel), not self.is_reduction or self.reduce_axes[-1] == self.rank - 1 + ) + self.requires_x_mask: bool = any(int(self.x_numel) % config[0] != 0 for config in self.autotune_configs.configs) + self.requires_r_mask: bool = any(int(self.r_numel) % config[1] != 0 for config in self.autotune_configs.configs) + self.reduced_args: Set[str] = set() + + def get_input_strides(self, name: str) -> List[sympy.Expr]: + assert name in self.input_strides + return self.input_strides[name] + + def get_x_input_strides(self, name: str) -> List[sympy.Expr]: + return [dim for idx, dim in enumerate(self.get_input_strides(name)) if idx not in self.reduce_axes] + + def get_r_input_strides(self, name: str) -> List[sympy.Expr]: + return [dim for idx, dim in enumerate(self.get_input_strides(name)) if idx in self.reduce_axes] + + # Whether the x shape of the tensor argument is contiguous and is same as the target shape. + def is_same_x_shape(self, name: str) -> bool: + if ( + self.is_reduction + and self.reduce_axes[0] != 0 + and self.reduce_axes[-1] != self.rank - 1 + and not self.is_r_reduced(name) + ): + return False + return all(dim != sympy.Integer(0) for dim in self.get_x_input_strides(name)) + + # Whether the r shape of the tensor argument is same as the target shape (r shape dimensions are always contiguous). + def is_same_r_shape(self, name: str) -> bool: + return all(dim != sympy.Integer(0) for dim in self.get_r_input_strides(name)) + + def register_tensor_arg(self, tensor_arg: TensorArg): + if tensor_arg.name in self.input_strides: + return + strides = [] + input_shape = tensor_arg.shape + if tensor_arg.name in self.reduced_args: + assert self.is_reduction + reduced_rank = len(input_shape) - len(self.reduce_axes) + if len(input_shape) < reduced_rank: + input_shape = [sympy.Integer(1)] * (reduced_rank - len(input_shape)) + input_shape + input_shape = ( + input_shape[: self.reduce_axes[0]] + + ([sympy.Integer(1)] * len(self.reduce_axes)) + + input_shape[self.reduce_axes[0] :] + ) + elif len(input_shape) < len(self.target_shape): + input_shape = [sympy.Integer(1)] * (len(self.target_shape) - len(input_shape)) + input_shape + running_stride = sympy.Integer(1) + for i in range(len(self.target_shape) - 1, -1, -1): + if self.target_shape[i] == input_shape[i]: + strides.insert(0, running_stride) + running_stride = running_stride * input_shape[i] + else: + strides.insert(0, sympy.Integer(0)) + self.input_strides[tensor_arg.name] = strides + if not self.is_same_x_shape(tensor_arg.name): + for idx, dim in enumerate(self.get_x_input_strides(tensor_arg.name)): + if dim != sympy.Integer(0): + self.x_compute_dims.add(idx) + if not self.is_same_r_shape(tensor_arg.name): + for idx, dim in enumerate(self.get_r_input_strides(tensor_arg.name)): + if dim != sympy.Integer(0): + self.r_compute_dims.add(idx) + + def is_x_reduced(self, name: str) -> bool: + strides = self.get_input_strides(name) + return all(dim == sympy.Integer(0) for idx, dim in enumerate(strides) if idx not in self.reduce_axes) + + def is_r_reduced(self, name: str) -> bool: + strides = self.get_input_strides(name) + return all(dim == sympy.Integer(0) for idx, dim in enumerate(strides) if idx in self.reduce_axes) + + +class IRNode: + """ + The base class for all IR nodes. + """ + + def __init__(self, inputs: List[TensorArg], outputs: List[TensorArg]): + self.inputs: List[TensorArg] = inputs + self.outputs: List[TensorArg] = outputs + + @abstractmethod + def codegen(self, visitor: NodeVisitor, context: CodegenContext, code_buffer: CodeBuffer, indent: int = 0): + visitor.codegen(self, context, code_buffer, indent) + + +class ComputeNode(IRNode): + """ + Each operator is represented as a ComputeNode. + """ + + def __init__(self, op_type: str, inputs: List[TensorArg], outputs: List[TensorArg]): + super().__init__(inputs, outputs) + self._op_type: str = op_type + + @property + def op_type(self): + return self._op_type + + +class ReduceNode(ComputeNode): + def __init__(self, op_type: str, inputs: List[TensorArg], outputs: List[TensorArg], offset_calc: OffsetCalculator): + super().__init__(op_type, inputs, outputs) + assert op_type == "ReduceSum" or op_type == "ReduceMax" or op_type == "ReduceMin" + self.default_value: str = ( + "0.0" if op_type == "ReduceSum" else ('float("-inf")' if op_type == "ReduceMax" else 'float("inf")') + ) + self.triton_func: str = ( + "tl.sum" if op_type == "ReduceSum" else ("tl.max" if op_type == "ReduceMax" else "tl.min") + ) + self.offset_calc: OffsetCalculator = offset_calc + + +class ReduceForLoopStart(ComputeNode): + """ + For reduce kernels that need for loop to compute, ReduceForLoopStart and ReduceForLoopEnd are used to + represent the start and end of the for loop. + + shared-memory declaration + """ + + def __init__(self, reduce_nodes: List[ReduceNode], offset_calc: OffsetCalculator): + super().__init__("", [], []) + self.reduce_nodes: List[ReduceNode] = reduce_nodes + self.offset_calc: OffsetCalculator = offset_calc + + +class ReduceForLoopEnd(ComputeNode): + """ + shared-memory reduction + """ + + def __init__(self, reduce_nodes: List[ReduceNode], offset_calc: OffsetCalculator): + super().__init__("", [], []) + self.reduce_nodes: List[ReduceNode] = reduce_nodes + self.offset_calc: OffsetCalculator = offset_calc + + +class DropoutNode(ComputeNode): + """ + DropoutNode is used to represent the dropout operator. It is special because we need to track the global offset + if there are more than one dropout operators in the subgraph. + """ + + def __init__(self, inputs: List[TensorArg], outputs: List[TensorArg], offset_calc: OffsetCalculator): + super().__init__("Dropout", inputs, outputs) + self.offset_calc: OffsetCalculator = offset_calc + self.offset_calc.register_tensor_arg(inputs[0]) + self.global_offset: sympy.Expr = sympy.Integer(0) + + +class IONode(IRNode): + """ + The IONode is used to represent the input and output of the subgraph, + which is used to generate data load/store code. + + """ + + def __init__(self, tensor_arg: TensorArg, offset_calc: OffsetCalculator, is_load: bool): + super().__init__([], []) + self.tensor_arg: TensorArg = tensor_arg + self.is_load: bool = is_load + self.offset_calc: OffsetCalculator = offset_calc + self.offset_calc.register_tensor_arg(tensor_arg) + + +class KernelNode(IRNode): + """ + The KernelNode is used to represent a single kernel. Each kernel has a unique target shape. + + """ + + def __init__(self, inputs: List[TensorArg], outputs: List[TensorArg], target_shape: List, reduce_axes: List[int]): + super().__init__(inputs, outputs) + self.name: str = gen_unique_name("triton") + self.internal_args: Set[str] = set() + self.constants: Dict[str, TensorArg] = dict() + self.target_shape: List[sympy.Expr] = target_shape + self.sub_nodes: List[IRNode] = [] + self.var_map: Dict[str, str] = dict() + self.symbolic_shape_variables: List[str] = [] + self.has_dropout: bool = False + self.offset_calc: OffsetCalculator = OffsetCalculator(target_shape, reduce_axes) + + def gen_variable_names(self): + existing_names = set() + for input in self.inputs: + name = gen_variable_name(input.name, "in", existing_names) + self.var_map[input.name] = name + self.var_map[name] = "t_" + name + for output in self.outputs: + name = gen_variable_name(output.name, "out", existing_names) + self.var_map[output.name] = name + self.var_map[name] = "t_" + name + for name in self.internal_args: + self.var_map[name] = gen_variable_name(name, "t", existing_names) + for constant_name in self.constants: + self.var_map[constant_name] = gen_variable_name(constant_name, "c", existing_names) + if self.constants[constant_name].data is not None: + value = self.constants[constant_name].data + if value is not None: + assert value.size == 1, f"unsupported constant array {value}" + variable_name = self.var_map[constant_name] + assert variable_name not in self.var_map + self.var_map[variable_name] = str(np.array(value.item(), value.dtype)) + + self.symbolic_shape_variables = [str(dim) for dim in self.target_shape if dim.is_symbol] + + +class ElementwiseKernelNode(KernelNode): + def __init__(self, inputs: List[TensorArg], outputs: List[TensorArg], target_shape: List[sympy.Expr]): + super().__init__(inputs, outputs, target_shape, []) + + +class ReduceKernelNode(KernelNode): + def __init__( + self, + inputs: List[TensorArg], + outputs: List[TensorArg], + target_shape: List[sympy.Expr], + reduce_axes: List[int], + reduced_args: Set[str], + ): + super().__init__(inputs, outputs, target_shape, reduce_axes) + self.offset_calc.reduced_args.update(reduced_args) + + +class ModuleNode(IRNode): + """ + The ModuleNode is used to represent the whole subgraph. It may contain multiple kernels. + + """ + + def __init__( + self, + func_name: str, + inputs: List[TensorArg], + outputs: List[TensorArg], + constants: List[TensorArg], + cross_kernel_args: List[Tuple[TensorArg, int]], + kernels: List[KernelNode], + ): + super().__init__(inputs, outputs) + self.func_name: str = func_name + # Currently need inputs and outputs only. May need intermediate vars and constants later. + self.constants: List[TensorArg] = constants + self.kernels: List[KernelNode] = kernels + self.var_map: Dict[str, str] = dict() + existing_names = set() + for input in self.inputs: + name = gen_variable_name(input.name, "in", existing_names) + self.var_map[input.name] = name + for output in self.outputs: + name = gen_variable_name(output.name, "out", existing_names) + self.var_map[output.name] = name + self.cross_kernel_args_to_delete: Dict[int, Set[str]] = defaultdict(set) + for pair in cross_kernel_args: + name = gen_variable_name(pair[0].name, "buf", existing_names) + self.cross_kernel_args_to_delete[pair[1]].add(name) + self.var_map[pair[0].name] = name + running_offset = sympy.Integer(0) + self.has_dropout: bool = False + for kernel in self.kernels: + for ir_node in kernel.sub_nodes: + if isinstance(ir_node, DropoutNode): + ir_node.global_offset = running_offset + running_offset = running_offset + sympy.prod(ir_node.outputs[0].shape) + self.has_dropout = True diff --git a/orttraining/orttraining/python/training/ort_triton/_lowering.py b/orttraining/orttraining/python/training/ort_triton/_lowering.py new file mode 100644 index 0000000000000..16db9ab000834 --- /dev/null +++ b/orttraining/orttraining/python/training/ort_triton/_lowering.py @@ -0,0 +1,559 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# -------------------------------------------------------------------------- + +import itertools +import warnings +from collections import defaultdict +from typing import Any, Dict, List, Set, Tuple + +import sympy +from onnx import NodeProto + +from ._common import AutotuneConfigs, TensorInfo +from ._ir import ( + ComputeNode, + DropoutNode, + ElementwiseKernelNode, + IONode, + KernelNode, + ModuleNode, + OffsetCalculator, + ReduceForLoopEnd, + ReduceForLoopStart, + ReduceKernelNode, + ReduceNode, + TensorArg, +) +from ._op_config import is_reduction_node +from ._sorted_graph import SortedGraph +from ._utils import get_reduce_info, sort_reduce_axes, to_numpy_array + + +class NodeGroup: + """ + A NodeGroup contains nodes that can be lowered to a single Triton kernel node. + + """ + + def __init__(self, node: NodeProto, reduce_axes: List[int], keep_dims: int, node_arg_infos: Dict[str, TensorInfo]): + self._node_arg_infos = node_arg_infos + self.nodes_groups: List[Any] = [node] + self.target_shape: List[sympy.Expr] = self._get_target_shape(node) + rank = len(self.target_shape) + self.reduce_axes: List[int] = sort_reduce_axes(reduce_axes, rank) + x_dims = [self.target_shape[dim] for dim in range(rank) if dim not in self.reduce_axes] + # x_numel is meant to hint how many rows of tensor will be processed by each kernel. + # x is same as CUDA block in X direction. + x_numel: sympy.Expr = sympy.prod(x_dims) if len(x_dims) > 0 else sympy.Integer(1) + r_dims: List[sympy.Expr] = [self.target_shape[dim] for dim in self.reduce_axes] + # r_numel is meant to hint how many elements in a row of tensor will be processed by each kernel. + # r is a abbreviation of reduction, so, it's only used for reduction nodes. + r_numel: sympy.Expr = sympy.prod(r_dims) if len(r_dims) > 0 else sympy.Integer(1) + # Support concrete shape only for now. + assert x_numel.is_integer and r_numel.is_integer + self.autotune_configs: AutotuneConfigs = AutotuneConfigs( + int(x_numel), int(r_numel), len(self.reduce_axes) == 0 or self.reduce_axes[-1] == rank - 1 + ) + self.reduced_args: Set[str] = set() + if keep_dims != 1: + self.reduced_args.add(node.output[0]) + + # Check if shape can be broadcasted to target_shape. + # For example, [1, 3, 1, 1] can be broadcasted to [1, 3, 5, 7]. + # and we support `keepdims = false``, so [1, 3, 5, 7] is compatible with [1, 3, 5]. + def _compatible_shape(self, shape: List[sympy.Expr], split_if_different: bool) -> bool: + if split_if_different: + return shape == self.target_shape + if len(shape) > len(self.target_shape): + return False + shape = [sympy.Integer(1)] * (len(self.target_shape) - len(shape)) + shape + for axis in range(len(shape)): + if shape[axis] != self.target_shape[axis] and ( + not shape[axis].is_number or shape[axis] != sympy.Integer(1) + ): + return False + return True + + # Only we consider reduction or elementwise nodes. + # target shape does effect how we block the tensor in a triton kernel + # for reduction, it's possible to set keepdims=False + # for element-wise, output shape is always the target shape. + def _get_target_shape(self, node): + name = node.input[0] if is_reduction_node(node) else node.output[0] + return self._node_arg_infos[name].shape + + # Check if a node can be added to this group. + # a group represents a single kernel. + # Theoretically, we should fuse as more nodes as possible to benefit most from memory access pattern. + # But we have to consider the following factors: + # 1. We have to keep the order of nodes, so that we can't fuse nodes that are not adjacent. + # 2. The target shape of a group is determined by the first node in the group. + # we call it dominators, and it determinate the partition strategy of X_numel/R_numel. + # A group can't have multiple dominators. + def compatible(self, node: NodeProto, reduce_axes: List[int], keep_dims: int, split_if_different: bool) -> bool: + target_shape = self._get_target_shape(node) + if is_reduction_node(node): + # If the following nodes are all elementwise nodes on reduce output shape. + if len(self.reduce_axes) == 0 and self.target_shape == self._node_arg_infos[node.output[0]].shape: + return True + if keep_dims != 1: + return False + if ( + len(self.reduce_axes) > 0 and self.reduce_axes != sort_reduce_axes(reduce_axes, len(target_shape)) + ) or self.target_shape != target_shape: + return False + return True + return self._compatible_shape(target_shape, split_if_different) + + # 1. Create a new group with the reduction node. + # 2. Add this node to the current group. + def add_node(self, node: NodeProto, reduce_axes: List[int], keep_dims: int): + if is_reduction_node(node): + group = NodeGroup(node, reduce_axes, keep_dims, self._node_arg_infos) + self.nodes_groups.append(group) + if len(self.reduce_axes) == 0: + self.target_shape = group.target_shape + self.reduce_axes = group.reduce_axes + self.autotune_configs = group.autotune_configs + if keep_dims != 1: + for idx in range(len(self.nodes_groups) - 1): + self.reduced_args.update(self.nodes_groups[idx].input) + self.reduced_args.update(self.nodes_groups[idx].output) + return group + self.nodes_groups.append(node) + return self + + def has_reduced_elementwise_nodes(self) -> bool: + return not is_reduction_node(self.nodes_groups[0]) and len(self.reduced_args) > 0 + + def dependent_nodes(self, keep_reduce_node: bool): + node_map = dict() + reduce_nodes = [] + if not keep_reduce_node and self.has_reduced_elementwise_nodes(): + for item in self.nodes_groups: + if not isinstance(item, NodeGroup): + node_map[item.name] = item + return node_map, reduce_nodes + for item in self.nodes_groups: + if isinstance(item, NodeGroup): + node_map.update(item.dependent_nodes(keep_reduce_node)[0]) + elif keep_reduce_node or not is_reduction_node(item): + node_map[item.name] = item + else: + reduce_nodes.append(item) + return node_map, reduce_nodes + + # finalize the group, and return the flatten nodes + def flatten(self, sorted_nodes: List[NodeProto]) -> Tuple[List[NodeProto], List[List[int]]]: + if self.autotune_configs.requires_for_loop: + layers = [] + group_layer = [self] + while len(group_layer) > 0: + node_map = dict() + reduce_node_map = dict() + next_layer = [] + for group in group_layer: + sub_node_map, reduce_nodes = group.dependent_nodes(False) + node_map.update(sub_node_map) + for node in reduce_nodes: + reduce_node_map[node.name] = node + next_layer.extend([item for item in group.nodes_groups if isinstance(item, NodeGroup)]) + layers.append((node_map, reduce_node_map.values())) + group_layer = next_layer + nodes = [] + layer_indices = [] + for i in range(len(layers) - 1, -1, -1): + sub_nodes = list(layers[i][0].values()) + sub_nodes.sort(key=sorted_nodes.index) + nodes.extend(sub_nodes) + sub_layer_indices = [] + for node in layers[i][1]: + nodes.append(node) + sub_layer_indices.append(len(nodes) - 1) + layer_indices.append(sub_layer_indices) + return nodes, layer_indices + node_map, _ = self.dependent_nodes(True) + nodes = list(node_map.values()) + nodes.sort(key=sorted_nodes.index) + return nodes, [] + + def try_merge(self, other) -> bool: + if ( + self.target_shape != other.target_shape + or self.reduce_axes != other.reduce_axes + or self.has_reduced_elementwise_nodes() != other.has_reduced_elementwise_nodes() + ): + return False + self.nodes_groups.extend(other.nodes_groups) + self.reduced_args.update(other.reduced_args) + return True + + +class KernelIO: + """ + Used to represent the inputs and outputs of a kernel(triton kernel). + """ + + def __init__(self): + self.module_inputs: List[str] = [] + self.cross_kernel_inputs: List[str] = [] + self.constants: List[str] = [] + self.module_outputs: List[str] = [] + self.cross_kernel_outputs: [str] = [] + self.internal_args: List[str] = [] + + +class GraphLowering: + """ + GraphLowering does manager all steps of lowering onnx graph to triton irnode. + 1. partition the graph into kernels (one or more kernels). + Manager to allocate inputs, outputs and buffers reuse between kernels. + we call it Module + 2. convert kernel to irnodes. + 3. analyze the IR relationship and buffer/Tensor inside a kernel. + 4. Generate the Auto-Tune configs for each kernel, Tunning speed/Running faster depends. + + we will end up getting a tree-liked IR structure with explicit input/output and intermediate buffer. + + """ + + def __init__(self, sorted_graph: SortedGraph): + self._sorted_graph: SortedGraph = sorted_graph + self._node_arg_infos: Dict[str, TensorInfo] = sorted_graph.node_arg_infos + self._module_inputs: List[TensorArg] = [] + self._module_outputs: List[TensorArg] = [] + self._module_constants: List[TensorArg] = [] + self._module_input_names: Set[str] = set() + self._module_output_names: Set[str] = set() + self._module_constant_names: Set[str] = set() + self._tensor_args: Dict[str, TensorArg] = {} + # Extract module inputs, outputs and constants. + self._extract_module_io() + + # Group nodes into NodeGroups, each NodeGroup represents a kernel. + self._groups: List[NodeGroup] = [] + self._group_nodes() + + # Convert NodeGroups to KernelNodes. + self._kernel_nodes: List[KernelNode] = [] + self._kernel_io_list: List[KernelIO] = [] + self._lower() + + # A module is map to a real onnx graph. + def _extract_module_io(self): + graph = self._sorted_graph.original_graph + self._module_inputs = [TensorArg(input.name, self._node_arg_infos[input.name]) for input in graph.input] + self._module_input_names = set(arg.name for arg in self._module_inputs) + self._module_outputs = [TensorArg(output.name, self._node_arg_infos[output.name]) for output in graph.output] + self._module_output_names = set(arg.name for arg in self._module_outputs) + for initializer in graph.initializer: + data = to_numpy_array(initializer) + self._module_constants.append(TensorArg(initializer.name, data=data)) + for const_node in self._sorted_graph.const_nodes: + data = to_numpy_array(const_node) + self._module_constants.append(TensorArg(const_node.output[0], data=data)) + self._module_constant_names = set(arg.name for arg in self._module_constants) + self._tensor_args = dict( + (arg.name, arg) + for arg in itertools.chain(self._module_inputs, self._module_outputs, self._module_constants) + ) + + def _get_reduce_info(self, node) -> Tuple[int, List[int]]: + assert is_reduction_node(node) + input_rank = len(self._node_arg_infos[node.input[0]].shape) + return get_reduce_info(node, self._sorted_graph.original_graph, input_rank) + + def _process_node(self, node: NodeProto, precessors: Dict[str, List[NodeProto]], group: NodeGroup): + dependent_nodes = set() + dependent_nodes.add(node.name) + for precessor in precessors[node.name]: + if precessor.name in dependent_nodes: + continue + keep_dims = 1 + reduce_axes = [] + if is_reduction_node(precessor): + keep_dims, reduce_axes = self._get_reduce_info(precessor) + split_if_different = any( + output in self._sorted_graph.elementwise_graph_outputs for output in precessor.output + ) + if group.compatible(precessor, reduce_axes, keep_dims, split_if_different): + next_group = group.add_node(precessor, reduce_axes, keep_dims) + dependent_nodes.update(self._process_node(precessor, precessors, next_group)) + return dependent_nodes + + def _group_nodes(self): + producers = dict() + precessors = defaultdict(list) + processed = set() + groups = [] + sorted_nodes = self._sorted_graph.sorted_nodes + for node in sorted_nodes: + for output in node.output: + producers[output] = node + for input in node.input: + if input in producers: + precessors[node.name].append(producers[input]) + for value in precessors.values(): + value.sort(key=sorted_nodes.index, reverse=True) + for idx in range(len(sorted_nodes) - 1, -1, -1): + node = sorted_nodes[idx] + if node.name not in processed: + reduce_axes = [] + keep_dims = 1 + if is_reduction_node(node): + keep_dims, reduce_axes = self._get_reduce_info(node) + groups.append(NodeGroup(node, reduce_axes, keep_dims, self._node_arg_infos)) + processed.update(self._process_node(node, precessors, groups[-1])) + + # Merge groups with same target shape and reduce axes without dependency. + group_dependencies = defaultdict(set) + for i in range(len(groups) - 1): + group_inputs = set() + for node in groups[i].dependent_nodes(True)[0].values(): + group_inputs.update(node.input) + for j in range(i + 1, len(groups)): + if any(output in group_inputs for output in groups[j].nodes_groups[0].output): + group_dependencies[i].add(j) + for k in range(0, i): + if i in group_dependencies[k]: + group_dependencies[k].add(j) + + flag = set() + for i in range(len(groups)): + if i not in flag: + for j in range(i + 1, len(groups)): + if j not in flag and j not in group_dependencies[i] and groups[i].try_merge(groups[j]): + flag.add(j) + self._groups.append(groups[i]) + flag.add(i) + + def _get_node_io(self, node: NodeProto) -> Tuple[List[TensorArg], List[TensorArg]]: + input_args = [] + for input in node.input: + if input in self._tensor_args: + input_args.append(self._tensor_args[input]) + else: + input_args.append(TensorArg(input, self._node_arg_infos[input])) + self._tensor_args[input] = input_args[-1] + output_args = [] + for output in node.output: + if output in self._tensor_args: + output_args.append(self._tensor_args[output]) + else: + output_args.append(TensorArg(output, self._node_arg_infos[output])) + self._tensor_args[output] = output_args[-1] + return input_args, output_args + + def _extract_kernel_io(self, nodes: List[NodeProto]) -> KernelIO: + kernel_io = KernelIO() + input_set = set() + output_set = set() + for node in nodes: + for input in node.input: + if input in input_set: + continue + elif input in self._module_constant_names: + kernel_io.constants.append(input) + elif input in self._module_input_names: + kernel_io.module_inputs.append(input) + elif input not in output_set: + kernel_io.cross_kernel_inputs.append(input) + input_set.add(input) + for output in node.output: + if output in output_set: + continue + if output in self._module_output_names: + kernel_io.module_outputs.append(output) + else: + kernel_io.internal_args.append(output) + output_set.add(output) + return kernel_io + + def _to_compute_node(self, node: NodeProto, offset_calc: OffsetCalculator): + inputs, outputs = self._get_node_io(node) + op_type = node.op_type + if op_type == "Dropout": + return DropoutNode(inputs, outputs, offset_calc) + if is_reduction_node(node): + return ReduceNode(op_type, inputs, outputs, offset_calc) + return ComputeNode(op_type, inputs, outputs) + + def _analyze_kernel_io_list(self): + cross_kernel_inputs = set() + for kernel_io in self._kernel_io_list: + cross_kernel_inputs.update(kernel_io.cross_kernel_inputs) + for kernel_io in self._kernel_io_list: + kernel_io.cross_kernel_outputs = [arg for arg in kernel_io.internal_args if arg in cross_kernel_inputs] + kernel_io.internal_args = [ + arg for arg in kernel_io.internal_args if arg not in kernel_io.cross_kernel_outputs + ] + + def _insert_load_and_store(self, kernel_node: KernelNode): + input_names = [input.name for input in kernel_node.inputs] + output_name_map = dict() + for output in kernel_node.outputs: + output_name_map[output.name] = 0 + for node in kernel_node.sub_nodes: + for output in node.outputs: + if output.name in output_name_map: + output_name_map[output.name] += 1 + sub_nodes = kernel_node.sub_nodes + new_sub_nodes = [] + cur = 0 + nxt = 0 + reduce_store_nodes = [] + while True: + while nxt < len(sub_nodes) and not isinstance(sub_nodes[nxt], ReduceForLoopEnd): + nxt += 1 + load_cache = set() + load_nodes = [] + store_nodes = [] + for idx in range(cur, nxt): + for input in sub_nodes[idx].inputs: + if input.name in kernel_node.constants or input.name in input_names: + if (input.data is not None and input.data.size == 1) or input.name in load_cache: + continue + load_nodes.append(IONode(input, kernel_node.offset_calc, True)) + load_cache.add(input.name) + for output in sub_nodes[idx].outputs: + if output.name in output_name_map: + output_name_map[output.name] -= 1 + if output_name_map[output.name] == 0: + store_nodes.append(IONode(output, kernel_node.offset_calc, False)) + if isinstance(sub_nodes[cur], ReduceForLoopStart): + new_sub_nodes.append(sub_nodes[cur]) + cur += 1 + if nxt < len(sub_nodes): + assert isinstance(sub_nodes[nxt], ReduceForLoopEnd) + for reduce_node in sub_nodes[nxt].reduce_nodes: + input = reduce_node.inputs[0] + if input.name in kernel_node.constants or input.name in input_names: + if (input.data is not None and input.data.size == 1) or input.name in load_cache: + continue + load_nodes.append(IONode(input, kernel_node.offset_calc, True)) + load_cache.add(input.name) + new_sub_nodes.extend(load_nodes) + new_sub_nodes.extend(sub_nodes[cur:nxt]) + new_sub_nodes.extend(store_nodes) + if nxt < len(sub_nodes): + assert isinstance(sub_nodes[nxt], ReduceForLoopEnd) + for reduce_node in sub_nodes[nxt].reduce_nodes: + if reduce_node.outputs[0].name in output_name_map: + reduce_store_nodes.append(IONode(reduce_node.outputs[0], kernel_node.offset_calc, False)) + new_sub_nodes.append(sub_nodes[nxt]) + nxt += 1 + cur = nxt + if cur >= len(sub_nodes): + break + new_sub_nodes.extend(reduce_store_nodes) + kernel_node.sub_nodes = new_sub_nodes + + def _lower(self): + for group in self._groups: + is_reduction_kernel = len(group.reduce_axes) > 0 + target_shape = group.target_shape + # The inputs and outputs will be initialized later. + kernel_node = ( + ReduceKernelNode([], [], target_shape, group.reduce_axes, group.reduced_args) + if is_reduction_kernel + else ElementwiseKernelNode([], [], target_shape) + ) + self._kernel_nodes.append(kernel_node) + sub_nodes = [] + nodes, layer_indices = group.flatten(self._sorted_graph.sorted_nodes) + self._kernel_io_list.append(self._extract_kernel_io(nodes)) + if group.autotune_configs.requires_for_loop: + start = 0 + for layer_idx, indices in enumerate(layer_indices): + need_for_loop = True + if layer_idx == len(layer_indices) - 1 and group.has_reduced_elementwise_nodes(): + assert len(indices) == 0 + need_for_loop = False + reduce_nodes = [self._to_compute_node(nodes[idx], kernel_node.offset_calc) for idx in indices] + assert all(isinstance(node, ReduceNode) for node in reduce_nodes) + if need_for_loop: + sub_nodes.append(ReduceForLoopStart(reduce_nodes, kernel_node.offset_calc)) + end = indices[0] if len(indices) > 0 else len(nodes) + for idx in range(start, end): + node = nodes[idx] + assert not is_reduction_node(node) + sub_nodes.append(self._to_compute_node(node, kernel_node.offset_calc)) + if node.op_type == "Dropout": + self._kernel_nodes[-1].has_dropout = True + if len(indices) > 0: + sub_nodes.append(ReduceForLoopEnd(reduce_nodes, kernel_node.offset_calc)) + start = indices[len(indices) - 1] + 1 if len(indices) > 0 else len(nodes) + else: + for node in nodes: + sub_nodes.append(self._to_compute_node(node, kernel_node.offset_calc)) + if node.op_type == "Dropout": + self._kernel_nodes[-1].has_dropout = True + self._kernel_nodes[-1].sub_nodes = sub_nodes + + if any(kernel_node.has_dropout for kernel_node in self._kernel_nodes): + warnings.warn("Use triton's random for Dropout, ignore the random seed from ORT.", UserWarning) + + self._analyze_kernel_io_list() + cross_kernel_arg_map = dict() + for idx, kernel_io in enumerate(self._kernel_io_list): + for output in itertools.chain(kernel_io.cross_kernel_outputs, kernel_io.module_outputs): + cross_kernel_arg_map[output] = idx + dependency = defaultdict(set) + for idx, kernel_io in enumerate(self._kernel_io_list): + for input in kernel_io.cross_kernel_inputs: + dependency[cross_kernel_arg_map[input]].add(idx) + visited = set() + sorted_indices = [] + + def _topological_sort_internal(idx): + visited.add(idx) + for next_idx in dependency[idx]: + if next_idx not in visited: + _topological_sort_internal(next_idx) + sorted_indices.insert(0, idx) + + for idx in range(len(self._kernel_io_list)): + if idx not in visited: + _topological_sort_internal(idx) + + self._kernel_nodes = [self._kernel_nodes[idx] for idx in sorted_indices] + self._kernel_io_list = [self._kernel_io_list[idx] for idx in sorted_indices] + cross_kernel_arg_map.clear() + for idx, kernel_io in enumerate(self._kernel_io_list): + for arg in kernel_io.cross_kernel_inputs: + if arg not in self._module_output_names: + cross_kernel_arg_map[arg] = idx + + self._cross_kernel_args = [(self._tensor_args[key], value) for key, value in cross_kernel_arg_map.items()] + + for idx, kernel_node in enumerate(self._kernel_nodes): + kernel_io = self._kernel_io_list[idx] + kernel_node.internal_args.update(kernel_io.internal_args) + kernel_node.inputs = [ + self._tensor_args[name] + for name in itertools.chain(kernel_io.module_inputs, kernel_io.cross_kernel_inputs) + ] + kernel_node.outputs = [ + self._tensor_args[name] + for name in itertools.chain(kernel_io.module_outputs, kernel_io.cross_kernel_outputs) + ] + for name in kernel_io.constants: + kernel_node.constants[name] = self._tensor_args[name] + self._insert_load_and_store(kernel_node) + kernel_node.gen_variable_names() + + def module_node(self, func_name: str): + return ModuleNode( + func_name, + self._module_inputs, + self._module_outputs, + self._module_constants, + self._cross_kernel_args, + self._kernel_nodes, + ) + + +def lower(func_name: str, sorted_graph: SortedGraph) -> ModuleNode: + return GraphLowering(sorted_graph).module_node(func_name) diff --git a/orttraining/orttraining/python/training/ort_triton/_op_config.py b/orttraining/orttraining/python/training/ort_triton/_op_config.py new file mode 100644 index 0000000000000..f58d0e1847207 --- /dev/null +++ b/orttraining/orttraining/python/training/ort_triton/_op_config.py @@ -0,0 +1,63 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# -------------------------------------------------------------------------- +""" +This file controls the Ops supported by Triton codegen. +The Triton fusion on backend will try to extract subgraphs from the ONNX model which contain connected supported ops. +For each supported op, it has the following attributes: + - domain: The domain of the op. If not specified, the op is from ONNX domain, which is empty string. + - versions: The supported opset versions. + - is_no_op: If the op is no-op. If not specified, the op is not no-op. + - conditions: define some conditions to control the fusion. For example, for Ops that has axis attribute, + a condition "axis": "-1" means only Ops that reduce on last dimension will be fused. + For Reduce* Ops, the "axes" condition can be list of ints, such as "axes": "[-1]", + or "axes": "single", means only support Ops reduce on single constant dimension, + or "axes": "constant", means the axes attribute or input must be constant. + - ignore_min_nodes: by default is False. If set to True, the fusion will ignore the min_nodes check for this Op. + For example, if the min_nodes is 2, the fusion will only fuse the subgraphs with 2 or more + non-no-op nodes. But if the ignore_min_nodes is True for ReduceSum, it's OK to fuse a single + ReduceSum node to the subgraph. +""" + +from onnx import NodeProto + +_ELEMENTWISE_OPS = { + "Add": {"versions": [13, 14]}, + "Sub": {"versions": [13, 14]}, + "Mul": {"versions": [13, 14]}, + "Div": {"versions": [13, 14]}, + "Pow": {"versions": [13, 15]}, + "Sqrt": {"versions": [13]}, + "Exp": {"versions": [13]}, + "Where": {"versions": [9, 16]}, + "Cast": {"versions": [13]}, + "Dropout": {"versions": [13]}, + "DropoutGrad": {"domain": "com.microsoft", "versions": [1]}, + "Identity": {"versions": [13], "is_no_op": True}, + "Sum": {"versions": [13]}, +} + +_REDUCTION_OPS = { + "ReduceMean": {"versions": [13], "conditions": {"axes": "[-1]"}}, + "ReduceSum": {"versions": [13], "conditions": {"axes": "[-1]"}}, + "ReduceMax": {"versions": [13], "conditions": {"axes": "[-1]"}}, + "ReduceMin": {"versions": [13], "conditions": {"axes": "[-1]"}}, + "Softmax": {"versions": [13]}, + "SoftmaxGrad_13": {"domain": "com.microsoft", "versions": [1]}, + # Disable LayerNormalization fusion for now as it's generated Triton code is inefficient compared to C++ kernel. + # "LayerNormalization": {"versions": [1]}, + # "LayerNormalizationGrad": {"domain": "com.microsoft", "versions": [1]}, +} + + +def is_elementwise_node(node: NodeProto) -> bool: + return node.op_type in _ELEMENTWISE_OPS + + +def is_reduction_node(node: NodeProto) -> bool: + return node.op_type in _REDUCTION_OPS + + +def get_supported_ops(): + return {**_ELEMENTWISE_OPS, **_REDUCTION_OPS} diff --git a/orttraining/orttraining/python/training/ort_triton/_sorted_graph.py b/orttraining/orttraining/python/training/ort_triton/_sorted_graph.py new file mode 100644 index 0000000000000..69df567500a89 --- /dev/null +++ b/orttraining/orttraining/python/training/ort_triton/_sorted_graph.py @@ -0,0 +1,210 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# -------------------------------------------------------------------------- + +import copy +import itertools +from typing import Any, Dict, List, Set + +import numpy as np +import onnx +from onnx import GraphProto, ModelProto, NodeProto, helper + +from ._common import TensorInfo, TypeAndShapeInfer +from ._decompose import DecomposeDispatch +from ._op_config import is_elementwise_node +from ._utils import get_attribute, to_numpy_array, topological_sort + + +class SortedGraph: + """ + This class is used to + 1. decompose complex operators into preliminary operators, + 2. sort the operators in topological order, + 3. infer the type and shape of each node inputs and outputs. + + input args: + model: the ONNX model. + input_shapes: the shapes of the model inputs. Can be numeric values or symbolic values. + """ + + def __init__(self, model: ModelProto, input_shapes: List[List[Any]]): + self._model: ModelProto = model + self._graph: GraphProto = model.graph + self._input_shapes: List[List[Any]] = input_shapes + + # For elementwise graph outputs, when we group nodes to different kernels, if the target shape is different + # from other nodes' target shape, even it can be broadcasted, we still need to create a new kernel for it. + self._elementwise_graph_outputs: Set[str] = set() + for node in self._graph.node: + if is_elementwise_node(node): + self._elementwise_graph_outputs.update(node.output) + + # Topological sort the nodes in the graph. + self._sorted_nodes: List[NodeProto] = topological_sort( + [input.name for input in self._graph.input] + [initializer.name for initializer in self._graph.initializer], + self._graph.node, + ) + + self._node_arg_infos: Dict[str, TensorInfo] = {} + for idx, input in enumerate(self._graph.input): + self._node_arg_infos[input.name] = TensorInfo(input.type.tensor_type.elem_type, self._input_shapes[idx]) + for initializer in self._graph.initializer: + self._node_arg_infos[initializer.name] = TensorInfo( + initializer.data_type, + list(to_numpy_array(initializer).shape), + ) + + # Decompose complex operators. + self._decompose() + + # Sort the initializers in reference order. + # We try to reuse Triton module for different ONNX models with same graph structure, + # even the node args names in the models are different. + # Sorting the initializers can help to generate same model key for different ONNX models. + initializers = {} + for initializer in self._graph.initializer: + initializers[initializer.name] = initializer + self._sorted_initializers: List[TensorInfo] = [] + for node in self._sorted_nodes: + for input in node.input: + if input in initializers: + self._sorted_initializers.append(initializers[input]) + initializers.pop(input) + + # Split nodes to constant nodes and non-constant nodes. + self._const_nodes: List[NodeProto] = [node for node in self._sorted_nodes if node.op_type == "Constant"] + self._sorted_nodes: List[NodeProto] = [node for node in self._sorted_nodes if node.op_type != "Constant"] + + def __str__(self): + """ + Generate a unique key for the model based on the graph structure, ignoring the node args names. + We try to reuse Triton module for different ONNX models with same graph structure. + """ + graph_inputs = [] + name_map = {} + for idx, input in enumerate(self._graph.input): + shape_str = str(self._input_shapes[idx]).replace(" ", "") + graph_inputs.append(f"({input.type.tensor_type.elem_type!s},{shape_str})") + name_map[input.name] = f"i{idx}" + graph_inputs_str = ",".join(graph_inputs) + + constants = [] + for idx, initializer in enumerate(self._sorted_initializers): + data_str = np.array2string(to_numpy_array(initializer), separator=",").replace("\n", "").replace(" ", "") + constants.append(f"({initializer.data_type},{data_str})") + name_map[initializer.name] = f"c{idx}" + + for idx, node in enumerate(self._const_nodes): + value_attr = get_attribute(node, "value") + data_str = np.array2string(to_numpy_array(value_attr), separator=",").replace("\n", "").replace(" ", "") + constants.append(f"({value_attr.data_type},{data_str})") + name_map[node.output[0]] = f"c{idx + len(self._sorted_initializers)}" + constants_str = ",".join(constants) + + for idx, output in enumerate(self._graph.output): + name_map[output.name] = f"o{idx}" + + nodes = [] + for node_idx, node in enumerate(self._sorted_nodes): + inputs = [] + for input in node.input: + inputs.append(name_map.get(input, input)) + inputs_str = ",".join(inputs) + outputs = [] + for idx, output in enumerate(node.output): + if output in name_map: + outputs.append(name_map[output]) + else: + name_map[output] = f"t{node_idx}_{idx}" + outputs.append(name_map[output]) + outputs_str = ",".join(outputs) + attributes = [] + for attr in node.attribute: + fields = [str(f[1]) for f in attr.ListFields()] + attributes.append(f"{fields[0]}:{fields[2]}={fields[1]}") + attributes_str = ",".join(attributes) + nodes.append(f"{node.op_type}[{attributes_str}]({inputs_str})->({outputs_str})") + nodes_str = ",".join(nodes) + return f"{graph_inputs_str}|{len(self._graph.output)!s}|{constants_str}|{nodes_str}" + + def __hash__(self): + return hash(str(self)) + + def __eq__(self, other): + return str(self) == str(other) + + @property + def const_nodes(self) -> List[NodeProto]: + return self._const_nodes + + @property + def sorted_nodes(self) -> List[NodeProto]: + return self._sorted_nodes + + @property + def original_graph(self) -> GraphProto: + return self._graph + + @property + def node_arg_infos(self) -> Dict[str, TensorInfo]: + return self._node_arg_infos + + @property + def elementwise_graph_outputs(self) -> Set[str]: + return self._elementwise_graph_outputs + + def _decompose(self): + dispatch = DecomposeDispatch() + pos = 0 + # If a node is complex, decompose it and insert the decomposed nodes at the same position. + # All complex Ops are defined in DecomposeDispatch. + # It's possible that the decomposed nodes are also complex, so we need to do the decompose recursively. + # For example, decomposed nodes for "Softmax" contains "ReduceMean", + # which will be decomposed to "ReduceSum" and "Div" further. + while pos < len(self._sorted_nodes): + node = self._sorted_nodes[pos] + if node in dispatch: + new_nodes = dispatch(node, self._graph, node_arg_infos=self._node_arg_infos) + if len(new_nodes) != 1 or new_nodes[0] != node: + new_nodes = topological_sort(node.input, new_nodes) + self._sorted_nodes[pos : pos + 1] = new_nodes + continue + if node.op_type == "Constant": + value_attr = get_attribute(node, "value") + self._node_arg_infos[node.output[0]] = TensorInfo( + value_attr.data_type, + list(to_numpy_array(value_attr).shape), + ) + else: + input_infos = [] + for input in node.input: + input_infos.append(self._node_arg_infos[input]) + output_infos = TypeAndShapeInfer.infer(node, input_infos, self._graph) + for idx, output in enumerate(node.output): + self._node_arg_infos[output] = output_infos[idx] + pos += 1 + + # Save the ONNX graphs for debug purpose. The original ONNX graph is the subgraph from backend. + # The processed ONNX graph is the subgraph after decompose, it also contains the concrete shapes for each arg. + def save_onnx(self, file_path_prefix): + onnx.save(self._model, file_path_prefix + "_original.onnx") + processed_model = copy.deepcopy(self._model) + processed_model.graph.ClearField("node") + processed_model.graph.node.extend(self.const_nodes) + processed_model.graph.node.extend(self.sorted_nodes) + for node in itertools.chain(processed_model.graph.input, processed_model.graph.output): + node.type.tensor_type.shape.Clear() + for dim in self.node_arg_infos[node.name].shape: + node.type.tensor_type.shape.dim.add().dim_value = int(dim) + value_infos = [] + for node in itertools.chain(self.const_nodes, self.sorted_nodes): + for output in node.output: + tensor_info = self.node_arg_infos[output] + value_infos.append( + helper.make_tensor_value_info(output, tensor_info.dtype, [int(dim) for dim in tensor_info.shape]) + ) + processed_model.graph.ClearField("value_info") + processed_model.graph.value_info.extend(value_infos) + onnx.save(processed_model, file_path_prefix + "_processed.onnx") diff --git a/orttraining/orttraining/python/training/ort_triton/_sympy_utils.py b/orttraining/orttraining/python/training/ort_triton/_sympy_utils.py new file mode 100644 index 0000000000000..e3629b5effa38 --- /dev/null +++ b/orttraining/orttraining/python/training/ort_triton/_sympy_utils.py @@ -0,0 +1,26 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# -------------------------------------------------------------------------- + +import re +from typing import Any, List + +import sympy + + +def sympy_dot(seq1: List[sympy.Expr], seq2: List[sympy.Expr]) -> sympy.Expr: + assert len(seq1) == len(seq2) + return sympy.expand(sum(a * b for a, b in zip(seq1, seq2))) + + +def parse_shape(shape: List[Any]) -> List[sympy.Expr]: + symbol_shapes = [] + for dim in shape: + symbol_dim = dim + if isinstance(dim, str): + symbol_dim = sympy.Symbol(re.sub(r"[^a-zA-Z0-9_]+", "_", dim)) + elif isinstance(dim, int): + symbol_dim = sympy.Integer(dim) + symbol_shapes.append(symbol_dim) + return symbol_shapes diff --git a/orttraining/orttraining/python/training/ort_triton/_utils.py b/orttraining/orttraining/python/training/ort_triton/_utils.py new file mode 100644 index 0000000000000..c80e28f6f73df --- /dev/null +++ b/orttraining/orttraining/python/training/ort_triton/_utils.py @@ -0,0 +1,152 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# -------------------------------------------------------------------------- + +import re +import uuid +from collections import defaultdict +from typing import Any, List, Tuple + +import numpy as np +from onnx import GraphProto, NodeProto, TensorProto, helper, numpy_helper +from onnx.mapping import TENSOR_TYPE_TO_NP_TYPE + + +def gen_unique_name(prefix: str) -> str: + return prefix + "_" + uuid.uuid4().hex[:8] + + +def _topological_sort_internal(node, visited, output_consumers, sorted_nodes): + visited.add(node.name) + for next_node in output_consumers[node.name]: + if next_node.name not in visited: + _topological_sort_internal(next_node, visited, output_consumers, sorted_nodes) + + sorted_nodes.insert(0, node) + + +# Topological sort of nodes given the input names. The list of nodes contain both constant and non-constant nodes. +def topological_sort(inputs: List[str], nodes: List[NodeProto]) -> List[NodeProto]: + const_nodes = [] + non_const_nodes = [] + for node in nodes: + if not node.name: + node.name = gen_unique_name(node.op_type) + if node.op_type == "Constant": + inputs.append(node.output[0]) + const_nodes.append(node) + else: + non_const_nodes.append(node) + + # Build relationship between nodes. + graph_input_consumers = defaultdict(list) + output_consumers = defaultdict(list) + input_set = set(inputs) + for node in non_const_nodes: + for input in node.input: + if input in input_set: + graph_input_consumers[input].append(node) + for output in node.output: + if not output: + continue + for consumer in non_const_nodes: + if output in consumer.input: + output_consumers[node.name].append(consumer) + + # Topological sort. + visited = set() + sorted_nodes = [] + for input in inputs: + for node in graph_input_consumers[input]: + if node.name not in visited: + _topological_sort_internal(node, visited, output_consumers, sorted_nodes) + + return const_nodes + sorted_nodes + + +# Get attribute value from node by attribute key. +def get_attribute(node: NodeProto, attr_name: str, default_value: Any = None) -> Any: + found = [attr for attr in node.attribute if attr.name == attr_name] + if found: + return helper.get_attribute_value(found[0]) + return default_value + + +# Convert Constant node or TensorProto to numpy array. +def to_numpy_array(node: Any) -> np.ndarray: + tensor = node + if isinstance(node, NodeProto): + tensor = get_attribute(node, "value") + assert isinstance(tensor, TensorProto) + return numpy_helper.to_array(tensor) + + +def to_numpy_type(tensor_type: TensorProto.DataType) -> np.dtype: + return TENSOR_TYPE_TO_NP_TYPE[tensor_type] if not isinstance(tensor_type, np.dtype) else tensor_type + + +# Generate a unique variable name based on the node arg name. +def gen_variable_name(name: str, prefix: str, existing_names: set) -> str: + pos = name.rfind("/") + if pos != -1: + name = name[pos + 1 :] + pos = name.rfind(".") + if pos != -1: + name = name[pos + 1 :] + name = re.sub(r"[^a-zA-Z0-9]", "_", name) + if len(name) > 20: + name = name[-20:] + + name = f"{prefix}_{name}" + while name in existing_names: + name = name + "_1" + + existing_names.add(name) + return name + + +def may_add_brackets(name: str) -> str: + if not re.match("^[A-Za-z0-9_.]*$", name): + return f"({name})" + return name + + +def sort_reduce_axes(axes: List[int], rank: int, check_contiguous: bool = True) -> List[int]: + axes = [axis + rank if axis < 0 else axis for axis in axes] + axes.sort() + if check_contiguous: + for i in range(1, len(axes)): + assert axes[i] == axes[i - 1] + 1 + return axes + + +# Get the keep_dims attribute and reduce axes from a reduce node. +def get_reduce_info(node: NodeProto, graph: GraphProto, input_rank: int) -> Tuple[int, List[int]]: + keep_dims = get_attribute(node, "keepdims", 1) + noop_with_empty_axes = get_attribute(node, "noop_with_empty_axes", 0) + axes = get_attribute(node, "axes", None) + if axes is None and len(node.input) > 1: + axes_initializer = None + for initializer in graph.initializer: + if initializer.name == node.input[1]: + axes_initializer = initializer + break + assert axes_initializer is not None + axes = to_numpy_array(axes_initializer).tolist() + if axes is None: + axes = list(range(input_rank)) if noop_with_empty_axes == 0 else [] + axes = sort_reduce_axes(axes, input_rank, check_contiguous=False) + return keep_dims, axes + + +def next_power_of_2(n: int) -> int: + assert n <= 2**32, "32-bit only" + n -= 1 + n |= n >> 1 + n |= n >> 2 + n |= n >> 4 + n |= n >> 8 + n |= n >> 16 + n += 1 + return n diff --git a/orttraining/orttraining/python/training/ort_triton/kernel/__init__.py b/orttraining/orttraining/python/training/ort_triton/kernel/__init__.py new file mode 100644 index 0000000000000..97318ea2e53ae --- /dev/null +++ b/orttraining/orttraining/python/training/ort_triton/kernel/__init__.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# -------------------------------------------------------------------------- + +from ._mm import triton_gemm, triton_gemm_out, triton_matmul, triton_matmul_out +from ._slice_scel import slice_scel, slice_scel_backward, transform_slice_scel + +__all__ = [ + "triton_gemm", + "triton_gemm_out", + "triton_matmul", + "triton_matmul_out", + "slice_scel", + "slice_scel_backward", + "transform_slice_scel", +] diff --git a/orttraining/orttraining/python/training/ort_triton/kernel/_mm.py b/orttraining/orttraining/python/training/ort_triton/kernel/_mm.py new file mode 100644 index 0000000000000..ed92923589d48 --- /dev/null +++ b/orttraining/orttraining/python/training/ort_triton/kernel/_mm.py @@ -0,0 +1,484 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# -------------------------------------------------------------------------- + +import math +import os +from types import ModuleType +from typing import Tuple + +import torch + +from .._cache import ModuleCache, PyCodeCache +from .._utils import next_power_of_2 + +_DEBUG_MODE = "ORTMODULE_TRITON_DEBUG" in os.environ and int(os.getenv("ORTMODULE_TRITON_DEBUG")) == 1 + + +_MM_TEMPLATE = """ +import torch +import triton +import triton.language as tl + + +@triton.autotune( + configs=[ +{autotune_configs} + ], + key=["M", "N", "K"], +) +@triton.jit +def {kernel_name}( + A, B, OUT, M, N, K, BLOCK_M: tl.constexpr, BLOCK_N: tl.constexpr, BLOCK_K: tl.constexpr, GROUP_M: tl.constexpr +): + M = {M} + N = {N} + K = {K} + stride_am = {stride_am} + stride_ak = {stride_ak} + stride_bk = {stride_bk} + stride_bn = {stride_bn} + + # based on triton.ops.matmul + pid = tl.program_id(0) + grid_m = (M + BLOCK_M - 1) // BLOCK_M + grid_n = (N + BLOCK_N - 1) // BLOCK_N + + # re-order program ID for better L2 performance + width = GROUP_M * grid_n + group_id = pid // width + group_size = min(grid_m - group_id * GROUP_M, GROUP_M) + pid_m = group_id * GROUP_M + (pid % group_size) + pid_n = (pid % width) // (group_size) + + rm = pid_m * BLOCK_M + tl.arange(0, BLOCK_M) + rn = pid_n * BLOCK_N + tl.arange(0, BLOCK_N) + ram = tl.max_contiguous(tl.multiple_of(rm % M, BLOCK_M), BLOCK_M) + rbn = tl.max_contiguous(tl.multiple_of(rn % N, BLOCK_N), BLOCK_N) + rk = tl.arange(0, BLOCK_K) + A = A + (ram[:, None] * stride_am + rk[None, :] * stride_ak) + B = B + (rk[:, None] * stride_bk + rbn[None, :] * stride_bn) + + acc = tl.zeros((BLOCK_M, BLOCK_N), dtype=tl.float32) + for k in range(K, 0, -BLOCK_K): + if {even_k}: + a = tl.load(A) + b = tl.load(B) + else: + a = tl.load(A, mask=rk[None, :] < k, other=0.) + b = tl.load(B, mask=rk[:, None] < k, other=0.) + acc += tl.dot(a, b, allow_tf32={allow_tf32}) + A += BLOCK_K * stride_ak + B += BLOCK_K * stride_bk + + # rematerialize rm and rn to save registers + rm = pid_m * BLOCK_M + tl.arange(0, BLOCK_M) + rn = pid_n * BLOCK_N + tl.arange(0, BLOCK_N) + idx_m = rm[:, None] + idx_n = rn[None, :] + mask = (idx_m < M) & (idx_n < N) + OUT = OUT + (idx_m * N + idx_n) + tl.store(OUT, {post_process}, mask=mask) + + +def {func_name}(a, b, out): + # 1D launch kernel where each block gets its own program. + grid = lambda META: (triton.cdiv({M}, META["BLOCK_M"]) * triton.cdiv({N}, META["BLOCK_N"]),) + {kernel_name}[grid](a, b, out, {M}, {N}, {K}) +""" + + +_BMM_TEMPLATE = """ +import torch +import triton +import triton.language as tl + + +@triton.autotune( + configs=[ +{autotune_configs} + ], + key=["M", "N", "K"], +) +@triton.jit +def {kernel_name}( + A, B, OUT, M, N, K, BLOCK_M: tl.constexpr, BLOCK_N: tl.constexpr, BLOCK_K: tl.constexpr, GROUP_M: tl.constexpr +): + M = {M} + N = {N} + K = {K} + stride_aq = {stride_aq} + stride_am = {stride_am} + stride_ak = {stride_ak} + stride_bq = {stride_bq} + stride_bk = {stride_bk} + stride_bn = {stride_bn} + stride_cq = M * N + + # based on triton.ops.matmul + pid = tl.program_id(0) + grid_m = (M + BLOCK_M - 1) // BLOCK_M + grid_n = (N + BLOCK_N - 1) // BLOCK_N + + # re-order program ID for better L2 performance + width = GROUP_M * grid_n + group_id = pid // width + group_size = min(grid_m - group_id * GROUP_M, GROUP_M) + pid_m = group_id * GROUP_M + (pid % group_size) + pid_n = (pid % width) // (group_size) + + rm = pid_m * BLOCK_M + tl.arange(0, BLOCK_M) + rn = pid_n * BLOCK_N + tl.arange(0, BLOCK_N) + ram = tl.max_contiguous(tl.multiple_of(rm % M, BLOCK_M), BLOCK_M) + rbn = tl.max_contiguous(tl.multiple_of(rn % N, BLOCK_N), BLOCK_N) + rk = tl.arange(0, BLOCK_K) + + idx_q = tl.program_id(1) # batch dimension for BMM + A = A + (ram[:, None] * stride_am + rk[None, :] * stride_ak + idx_q * stride_aq) + B = B + (rk[:, None] * stride_bk + rbn[None, :] * stride_bn + idx_q * stride_bq) + + acc = tl.zeros((BLOCK_M, BLOCK_N), dtype=tl.float32) + for k in range(K, 0, -BLOCK_K): + if {even_k}: + a = tl.load(A) + b = tl.load(B) + else: + a = tl.load(A, mask=rk[None, :] < k, other=0.) + b = tl.load(B, mask=rk[:, None] < k, other=0.) + acc += tl.dot(a, b, allow_tf32={allow_tf32}) + A += BLOCK_K * stride_ak + B += BLOCK_K * stride_bk + + # rematerialize rm and rn to save registers + rm = pid_m * BLOCK_M + tl.arange(0, BLOCK_M) + rn = pid_n * BLOCK_N + tl.arange(0, BLOCK_N) + idx_q = tl.program_id(1) # batch dimension for BMM + idx_m = rm[:, None] + idx_n = rn[None, :] + mask = (idx_m < M) & (idx_n < N) + OUT = OUT + (idx_m * N + idx_n + idx_q * stride_cq) + tl.store(OUT, {post_process}, mask=mask) + + +def {func_name}(a, b, out): + # 1D launch kernel where each block gets its own program. + grid = lambda META: (triton.cdiv({M}, META["BLOCK_M"]) * triton.cdiv({N}, META["BLOCK_N"]), {batch}, 1) + {kernel_name}[grid](a, b, out, {M}, {N}, {K}) +""" + + +_GEMM_TEMPLATE = """ +import torch +import triton +import triton.language as tl + + +@triton.autotune( + configs=[ +{autotune_configs} + ], + key=["M", "N", "K"], +) +@triton.jit +def {kernel_name}( + A, B, C, OUT, M, N, K, BLOCK_M: tl.constexpr, BLOCK_N: tl.constexpr, BLOCK_K: tl.constexpr, GROUP_M: tl.constexpr +): + M = {M} + N = {N} + K = {K} + stride_am = {stride_am} + stride_ak = {stride_ak} + stride_bk = {stride_bk} + stride_bn = {stride_bn} + stride_cm = {stride_cm} + stride_cn = {stride_cn} + + # based on triton.ops.matmul + pid = tl.program_id(0) + grid_m = (M + BLOCK_M - 1) // BLOCK_M + grid_n = (N + BLOCK_N - 1) // BLOCK_N + + # re-order program ID for better L2 performance + width = GROUP_M * grid_n + group_id = pid // width + group_size = min(grid_m - group_id * GROUP_M, GROUP_M) + pid_m = group_id * GROUP_M + (pid % group_size) + pid_n = (pid % width) // (group_size) + + rm = pid_m * BLOCK_M + tl.arange(0, BLOCK_M) + rn = pid_n * BLOCK_N + tl.arange(0, BLOCK_N) + ram = tl.max_contiguous(tl.multiple_of(rm % M, BLOCK_M), BLOCK_M) + rbn = tl.max_contiguous(tl.multiple_of(rn % N, BLOCK_N), BLOCK_N) + rk = tl.arange(0, BLOCK_K) + A = A + (ram[:, None] * stride_am + rk[None, :] * stride_ak) + B = B + (rk[:, None] * stride_bk + rbn[None, :] * stride_bn) + + acc = tl.zeros((BLOCK_M, BLOCK_N), dtype=tl.float32) + for k in range(K, 0, -BLOCK_K): + if {even_k}: + a = tl.load(A) + b = tl.load(B) + else: + a = tl.load(A, mask=rk[None, :] < k, other=0.) + b = tl.load(B, mask=rk[:, None] < k, other=0.) + acc += tl.dot(a, b, allow_tf32={allow_tf32}) + A += BLOCK_K * stride_ak + B += BLOCK_K * stride_bk + + # rematerialize rm and rn to save registers + rm = pid_m * BLOCK_M + tl.arange(0, BLOCK_M) + rn = pid_n * BLOCK_N + tl.arange(0, BLOCK_N) + idx_m = rm[:, None] + idx_n = rn[None, :] + mask = (idx_m < M) & (idx_n < N) + C = C + (idx_m * stride_cm + idx_n * stride_cn) + c = tl.load(C, mask=mask, other=0.) + OUT = OUT + (idx_m * N + idx_n) + tl.store(OUT, {post_process} + c * {beta}, mask=mask) + + +def {func_name}(a, b, c, out): + # 1D launch kernel where each block gets its own program. + grid = lambda META: (triton.cdiv({M}, META["BLOCK_M"]) * triton.cdiv({N}, META["BLOCK_N"]),) + {kernel_name}[grid](a, b, c, out, {M}, {N}, {K}) +""" + + +def _mm_configs(dtype, m, n, k, trans_a, trans_b, alpha, func_name): + condidates = [ + # "BLOCK_M", "BLOCK_N", "BLOCK_K", "num_stages", "num_warps" + (32, 32, 16, 1, 2), + (64, 64, 16, 2, 4), + (64, 64, 32, 2, 4), + (64, 128, 32, 3, 4), + (128, 64, 32, 3, 4), + (64, 128, 32, 4, 8), + (128, 64, 32, 4, 8), + (64, 32, 32, 5, 8), + (32, 64, 32, 5, 8), + (128, 128, 32, 2, 8), + (64, 64, 64, 3, 8), + (32, 32, 128, 2, 4), + ] + tm = max(next_power_of_2(m), 16) + tn = max(next_power_of_2(n), 16) + tk = max(next_power_of_2(k), 16) + config_set = set() + config_strs = [] + max_bk = 1 + for bm, bn, bk, num_stages, num_warps in condidates: + new_bm = min(bm, tm) + new_bn = min(bn, tn) + new_bk = min(bk, tk) + if (new_bm, new_bn, new_bk) in config_set: + continue + config_set.add((new_bm, new_bn, new_bk)) + if new_bk > max_bk: + max_bk = new_bk + new_num_warps = min(num_warps, new_bm * new_bn // 256) + config_strs.append( + f' triton.Config({{"BLOCK_M": {new_bm}, "BLOCK_N": {new_bn}, "BLOCK_K": {new_bk}, "GROUP_M": 8}}, ' + f"num_stages={num_stages}, num_warps={new_num_warps})," + ) + autotune_configs = "\n".join(config_strs) + post_process = "acc" if alpha == 1.0 else f"acc * {alpha}" + if dtype == torch.float16: + if alpha != 1.0: + post_process = f"({post_process})" + post_process = f"{post_process}.to(tl.float16)" + return dict( + autotune_configs=autotune_configs, + kernel_name=f"kernel_{func_name}", + M=m, + N=n, + K=k, + stride_am=(1 if trans_a else k), + stride_ak=(m if trans_a else 1), + stride_bk=(1 if trans_b else n), + stride_bn=(k if trans_b else 1), + even_k=(k % max_bk == 0), + allow_tf32=torch.backends.cuda.matmul.allow_tf32, + post_process=post_process, + func_name=func_name, + ) + + +def _gen_mm_key(dtype: torch.dtype, m: int, n: int, k: int, trans_a: bool, trans_b: bool, alpha: float) -> int: + return hash(f"mm|{dtype}|{m}|{n}|{k}|{trans_a}|{trans_b}|{alpha}") % (10**8) + + +def _gen_mm_module( + dtype: torch.dtype, m: int, n: int, k: int, trans_a: bool, trans_b: bool, alpha: float +) -> Tuple[str, ModuleType]: + func_name = f"mm_{_gen_mm_key(dtype, m, n, k, trans_a, trans_b, alpha)}" + kwargs = _mm_configs(dtype, m, n, k, trans_a, trans_b, alpha, func_name) + src_code = _MM_TEMPLATE.format(**kwargs) + if _DEBUG_MODE: + os.makedirs(os.path.dirname("triton_debug/"), exist_ok=True) + with open(f"triton_debug/{func_name}.py", "w") as f: + f.write(src_code) + return func_name, PyCodeCache().load(src_code) + + +def _gen_gemm_key( + dtype: torch.dtype, + m: int, + n: int, + k: int, + stride_cm: int, + stride_cn: int, + trans_a: bool, + trans_b: bool, + alpha: float, + beta: float, +) -> int: + return hash(f"gemm|{dtype}|{m}|{n}|{k}|{stride_cm}|{stride_cn}|{trans_a}|{trans_b}|{alpha}|{beta}") % (10**8) + + +def _gen_gemm_module( + dtype: torch.dtype, + m: int, + n: int, + k: int, + stride_cm: int, + stride_cn: int, + trans_a: bool, + trans_b: bool, + alpha: float, + beta: float, +) -> Tuple[str, ModuleType]: + func_name = f"gemm_{_gen_gemm_key(dtype, m, n, k, stride_cm, stride_cn, trans_a, trans_b, alpha, beta)}" + kwargs = _mm_configs(dtype, m, n, k, trans_a, trans_b, alpha, func_name) + kwargs["stride_cm"] = stride_cm + kwargs["stride_cn"] = stride_cn + kwargs["beta"] = beta + src_code = _GEMM_TEMPLATE.format(**kwargs) + if _DEBUG_MODE: + os.makedirs(os.path.dirname("triton_debug/"), exist_ok=True) + with open(f"triton_debug/{func_name}.py", "w") as f: + f.write(src_code) + return func_name, PyCodeCache().load(src_code) + + +def _gen_bmm_key( + dtype: torch.dtype, m: int, n: int, k: int, batch_a: int, batch_b: int, trans_a: bool, trans_b: bool, alpha: float +) -> int: + return hash(f"bmm|{dtype}|{m}|{n}|{k}|{batch_a}|{batch_b}|{trans_a}|{trans_b}|{alpha}") % (10**8) + + +def _gen_bmm_module( + dtype: torch.dtype, m: int, n: int, k: int, batch_a: int, batch_b: int, trans_a: bool, trans_b: bool, alpha: float +) -> Tuple[str, ModuleType]: + func_name = f"bmm_{_gen_bmm_key(dtype, m, n, k, batch_a, batch_b, trans_a, trans_b, alpha)}" + kwargs = _mm_configs(dtype, m, n, k, trans_a, trans_b, alpha, func_name) + batch = batch_a if batch_a >= batch_b else batch_b + kwargs["stride_aq"] = m * k if batch_a == batch else 0 + kwargs["stride_bq"] = k * n if batch_b == batch else 0 + kwargs["batch"] = batch + src_code = _BMM_TEMPLATE.format(**kwargs) + if _DEBUG_MODE: + os.makedirs(os.path.dirname("triton_debug/"), exist_ok=True) + with open(f"triton_debug/{func_name}.py", "w") as f: + f.write(src_code) + return func_name, PyCodeCache().load(src_code) + + +def _matmul_internal(a, b, out, **kwargs): + rank_a = len(a.shape) + rank_b = len(b.shape) + assert rank_a >= 2 and rank_b >= 2 + trans_a = kwargs.get("trans_a", False) + trans_b = kwargs.get("trans_b", False) + alpha = kwargs.get("alpha", 1.0) + m = a.shape[-1] if trans_a else a.shape[-2] + k = a.shape[-2] if trans_a else a.shape[-1] + bk = b.shape[-1] if trans_b else b.shape[-2] + assert k == bk + n = b.shape[-2] if trans_b else b.shape[-1] + assert rank_a == 2 or rank_b == 2 or a.shape[:-2] == b.shape[:-2] + batch_shape = a.shape[:-2] if rank_a >= 3 else b.shape[:-2] + if out is None: + out = torch.empty((*batch_shape, m, n), dtype=a.dtype, device=a.device) + else: + assert out.shape == (*batch_shape, m, n) + batch = math.prod(batch_shape) + dtype = a.dtype + if batch == 1 or (rank_a >= 3 and not trans_a and rank_b == 2): + if batch != 1: + m = batch * m + func_name, mod = ModuleCache.load(_gen_mm_key, _gen_mm_module, dtype, m, n, k, trans_a, trans_b, alpha) + else: + batch_a = batch if rank_a >= 3 else 1 + batch_b = batch if rank_b >= 3 else 1 + func_name, mod = ModuleCache.load( + _gen_bmm_key, _gen_bmm_module, dtype, m, n, k, batch_a, batch_b, trans_a, trans_b, alpha + ) + func = getattr(mod, func_name) + func(a, b, out) + return out + + +def triton_matmul(a, b, **kwargs): + """ + Compute matrix multiplication of two tensors. + If trans_a is True in kwargs, input a will be transposed on last two dimensions before multiplication. + If trans_b is True in kwargs, input b will be transposed on last two dimensions before multiplication. + If alpha is specified in kwargs, the product will be multiplied by alpha. + The input tensors can be of rank 2 or higher, but currently support only simple broadcasting on batch dimensions. + I.e., the batch dimensions of a and b must either be equal, or one of them must be 1. + """ + + return _matmul_internal(a, b, None, **kwargs) + + +def triton_matmul_out(a, b, out, **kwargs): + """ + Same as triton_matmul, except that the output is allocated and passed from outside. + """ + + _matmul_internal(a, b, out, **kwargs) + + +def _gemm_internal(a, b, c, out, **kwargs): + assert len(a.shape) == 2 and len(b.shape) == 2 + trans_a = kwargs.get("trans_a", False) + trans_b = kwargs.get("trans_b", False) + alpha = kwargs.get("alpha", 1.0) + beta = kwargs.get("beta", 1.0) + m = a.shape[-1] if trans_a else a.shape[-2] + k = a.shape[-2] if trans_a else a.shape[-1] + bk = b.shape[-1] if trans_b else b.shape[-2] + assert k == bk + n = b.shape[-2] if trans_b else b.shape[-1] + stride_cm = c.shape[-1] if len(c.shape) == 2 and c.shape[-2] == m else 0 + stride_cn = 1 if len(c.shape) >= 1 and c.shape[-1] == n else 0 + if out is None: + out = torch.empty(m, n, dtype=a.dtype, device=a.device) + else: + assert out.shape == (m, n) + dtype = a.dtype + func_name, mod = ModuleCache.load( + _gen_gemm_key, _gen_gemm_module, dtype, m, n, k, stride_cm, stride_cn, trans_a, trans_b, alpha, beta + ) + func = getattr(mod, func_name) + func(a, b, c, out) + return out + + +def triton_gemm(a, b, c, **kwargs): + """ + Compute alpha * a @ b + beta * c. Here a and b are 2D tensors, and c is broadcastable to the result. + If trans_a is True in kwargs, input a will be transposed before multiplication. + If trans_b is True in kwargs, input b will be transposed before multiplication. + """ + + return _gemm_internal(a, b, c, None, **kwargs) + + +def triton_gemm_out(a, b, c, out, **kwargs): + """ + Same as triton_gemm, except that the output is allocated and passed from outside. + """ + + _gemm_internal(a, b, c, out, **kwargs) diff --git a/orttraining/orttraining/python/training/ort_triton/kernel/_slice_scel.py b/orttraining/orttraining/python/training/ort_triton/kernel/_slice_scel.py new file mode 100644 index 0000000000000..8edcc9b63ef4f --- /dev/null +++ b/orttraining/orttraining/python/training/ort_triton/kernel/_slice_scel.py @@ -0,0 +1,367 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# -------------------------------------------------------------------------- + +import itertools +import sys + +import torch +import triton +import triton.language as tl +from onnx import TensorProto, helper + +from onnxruntime.training.ortmodule import register_graph_transformer + +from .._utils import get_attribute, to_numpy_array + + +@triton.jit +def _triton_slice_log_softmax(log_prob, logit, d: tl.constexpr, c: tl.constexpr, RBLOCK: tl.constexpr): + xoffset = tl.program_id(0) + logit_xoffset = (xoffset // d * (d + 1) + xoffset % d) * c + rbase = tl.arange(0, RBLOCK) + logit_max_row = tl.zeros([RBLOCK], tl.float32) + float("-inf") + for roffset in range(0, c, RBLOCK): + rindex = rbase + roffset + rmask = rindex < c + logit_row = tl.load(logit + logit_xoffset + rindex, mask=rmask, other=0.0).to(tl.float32) + logit_max_row = tl.where(rmask & (logit_max_row < logit_row), logit_row, logit_max_row) + logit_max_reduced = tl.max(logit_max_row, axis=0) + exp_sum_row = tl.zeros([RBLOCK], tl.float32) + for roffset in range(0, c, RBLOCK): + rindex = rbase + roffset + rmask = rindex < c + logit_row = tl.load(logit + logit_xoffset + rindex, mask=rmask, other=0.0).to(tl.float32) + exp_sum_row = tl.where(rmask, exp_sum_row + tl.exp(logit_row - logit_max_reduced), exp_sum_row) + reduced_log_sum = tl.log(tl.sum(exp_sum_row, axis=0)) + logit_max_reduced + for roffset in range(0, c, RBLOCK): + rindex = rbase + roffset + rmask = rindex < c + logit_row = tl.load(logit + logit_xoffset + rindex, mask=rmask, other=0.0).to(tl.float32) + output_row = logit_row - reduced_log_sum + tl.store(log_prob + xoffset * c + rindex, output_row, mask=rmask) + + +@triton.jit +def _triton_slice_scel( + loss, + factor, + log_prob, + label, + ignore_index, + d: tl.constexpr, + c: tl.constexpr, + n_cols: tl.constexpr, + RBLOCK: tl.constexpr, +): + rbase = tl.arange(0, RBLOCK) + neg_sum_row = tl.zeros([RBLOCK], tl.float32) + factor_row = tl.zeros([RBLOCK], tl.float32) + for roffset in range(0, n_cols, RBLOCK): + rindex = rbase + roffset + rmask = rindex < n_cols + label_row = tl.load(label + (rindex // d) * (d + 1) + rindex % d + 1, mask=rmask, other=0.0).to(tl.int32) + mask = rmask & (label_row != ignore_index) + log_prob_row = tl.load(log_prob + rindex * c + label_row, mask=mask, other=0.0) + neg_sum_row = tl.where(mask, neg_sum_row - log_prob_row, neg_sum_row) + factor_row = tl.where(mask, factor_row + 1.0, factor_row) + reduced_neg_sum = tl.sum(neg_sum_row, axis=0) + reduced_factor = tl.sum(factor_row, axis=0) + loss_value = reduced_neg_sum / reduced_factor + tl.store(loss, loss_value) + tl.store(factor, reduced_factor) + + +def slice_scel(logit, label, ignore_index): + ignore_index_value = ignore_index.item() + c = logit.shape[-1] + logit_d = logit.shape[-2] + d = logit_d - 1 + n = logit.numel() // (logit_d * c) + log_prob_shape = list(logit.shape)[:-2] + [d, c] + log_prob = torch.empty(log_prob_shape, dtype=torch.float, device=logit.device) + rblock = 4096 if c > 4096 else triton.next_power_of_2(c) + num_warps = 16 if rblock >= 4096 else (8 if rblock >= 2048 else 4) + _triton_slice_log_softmax[(n * d,)](log_prob, logit, d, c, num_warps=num_warps, RBLOCK=rblock) + loss = torch.empty([], dtype=logit.dtype, device=logit.device) + factor = torch.empty([], dtype=torch.float, device=logit.device) + n_cols = n * d + rblock = 1024 if n_cols > 1024 else triton.next_power_of_2(n_cols) + _triton_slice_scel[(1,)](loss, factor, log_prob, label, ignore_index_value, d, c, n_cols, RBLOCK=rblock) + return loss, log_prob, factor + + +@triton.jit +def _triton_slice_scel_backward( + dlogit, + dloss, + log_prob, + label, + factor, + d: tl.constexpr, + c: tl.constexpr, + n_elements: tl.constexpr, + XBLOCK: tl.constexpr, +): + xoffset = tl.program_id(0) * XBLOCK + xindex = xoffset + tl.arange(0, XBLOCK) + xmask = xindex < n_elements + nd_index = xindex // c + dlogit_nd_index = (nd_index // d) * (d + 1) + nd_index % d + label_nd_index = dlogit_nd_index + 1 + c_index = xindex % c + dloss_value = tl.load(dloss).to(tl.float32) + log_prob_row = tl.load(log_prob + xindex, mask=xmask, other=0.0) + label_row = tl.load(label + label_nd_index, mask=xmask, other=0.0).to(tl.int32) + factor_value = tl.load(factor) + dlogit_row = dloss_value * (tl.exp(log_prob_row) - tl.where(c_index == label_row, 1.0, 0.0)) / factor_value + tl.store(dlogit + dlogit_nd_index * c + c_index, dlogit_row, mask=xmask) + + +@triton.jit +def _triton_slice_scel_bias_backward( + dlogit, + dloss, + log_prob, + label, + factor, + bias, + dlogit_d: tl.constexpr, + c: tl.constexpr, + n_elements: tl.constexpr, + XBLOCK: tl.constexpr, +): + xoffset = tl.program_id(0) * XBLOCK + xindex = xoffset + tl.arange(0, XBLOCK) + xmask = xindex < n_elements + dlogit_nd_index = xindex // c + dlogit_n_index = dlogit_nd_index // dlogit_d + dlogit_d_index = dlogit_nd_index % dlogit_d + nd_index = dlogit_n_index * (dlogit_d - 1) + dlogit_d_index + nd_mask = xmask & (dlogit_d_index != dlogit_d - 1) + c_index = xindex % c + dloss_value = tl.load(dloss).to(tl.float32) + log_prob_row = tl.load(log_prob + nd_index * c + c_index, mask=nd_mask, other=0.0) + label_row = tl.load(label + dlogit_nd_index + 1, mask=nd_mask, other=0.0).to(tl.int32) + factor_value = tl.load(factor) + bias_row = tl.load(bias + xindex, mask=xmask, other=0.0).to(tl.float32) + dlogit_row = dloss_value * (tl.exp(log_prob_row) - tl.where(c_index == label_row, 1.0, 0.0)) / factor_value + dlogit_row = tl.where(nd_mask, dlogit_row, 0.0) + bias_row + tl.store(dlogit + xindex, dlogit_row, mask=xmask) + + +def slice_scel_backward(dloss, log_prob, label, factor, bias): + c = log_prob.shape[-1] + d = log_prob.shape[-2] + dlogit_d = d + 1 + dlogit_shape = list(log_prob.shape)[:-2] + [dlogit_d, c] + dlogit = ( + torch.empty(dlogit_shape, dtype=dloss.dtype, device=dloss.device) + if bias is not None + else torch.zeros(dlogit_shape, dtype=dloss.dtype, device=dloss.device) + ) + n_elements = dlogit.numel() if bias is not None else log_prob.numel() + xblock = 1024 if n_elements > 1024 else triton.next_power_of_2(n_elements) + + def grid(meta): + return (triton.cdiv(n_elements, meta["XBLOCK"]),) + + if bias is not None: + _triton_slice_scel_bias_backward[grid]( + dlogit, dloss, log_prob, label, factor, bias, dlogit_d, c, n_elements, XBLOCK=xblock + ) + else: + _triton_slice_scel_backward[grid](dlogit, dloss, log_prob, label, factor, d, c, n_elements, XBLOCK=xblock) + return dlogit + + +def _get_producer(graph, arg, op_type): + for node in graph.node: + if node.op_type == op_type: + for output in node.output: + if output == arg: + return node + return None + + +def _get_consumer(graph, arg, op_type): + for node in graph.node: + if node.op_type == op_type: + for input in node.input: + if input == arg: + return node + return None + + +def _get_arg_info(graph, arg): + value_info = None + for info in itertools.chain(graph.input, graph.output, graph.value_info): + if info.name == arg: + value_info = info + if value_info is None or value_info.type is None: + return None, None + tensor_type = value_info.type.tensor_type + return tensor_type.elem_type, tensor_type.shape + + +def _get_constant(graph, arg): + initializer = None + for init in graph.initializer: + if init.name == arg: + initializer = init + if initializer is None: + return None + return to_numpy_array(initializer) + + +def _check_slice(graph, node, start, end, axis, step): + _, shape = _get_arg_info(graph, node.input[0]) + if shape is None: + return False + rank = len(shape.dim) + if axis < 0: + axis += rank + for idx, value in enumerate([start, end, axis, step]): + constant = _get_constant(graph, node.input[idx + 1]) + if constant is None or constant.size != 1: + return False + constant_value = constant.item() + if idx == 2 and constant_value < 0: + constant_value += rank + if constant_value != value: + return False + return True + + +def _get_shape_related_nodes(graph, start_arg, sub_graph_nodes): + args = [start_arg] + while len(args) > 0: + arg = args.pop(0) + for node in graph.node: + if arg in node.input and node not in sub_graph_nodes: + sub_graph_nodes.append(node) + for output in node.output: + if output not in args: + args.append(output) + + +@register_graph_transformer(devices="cuda") +def transform_slice_scel(graph): + remove_nodes = [] + triton_nodes = [] + value_infos = [] + idx = 0 + for node in graph.node: + if node.op_type != "SoftmaxCrossEntropyLossInternal": + continue + # Weight input not supported for now, support reduction=mean only for now. + # It's required that the output_type is same as the logit dtype because currently we cannot pass the attribute + # value from TritonOp. We can add support of this in the future. + if len(node.input) > 2 and node.input[2]: + continue + reduction_attr = get_attribute(node, "reduction", "mean") + if isinstance(reduction_attr, bytes): + reduction_attr = reduction_attr.decode() + if reduction_attr != "mean": + continue + elem_type, _ = _get_arg_info(graph, node.input[0]) + output_type_attr = get_attribute(node, "output_type", elem_type) + if output_type_attr != elem_type: + continue + reshape0 = _get_producer(graph, node.input[0], "Reshape") + if reshape0 is None: + continue + _, shape0 = _get_arg_info(graph, reshape0.input[0]) + _, shape1 = _get_arg_info(graph, reshape0.output[0]) + if shape0 is None or shape1 is None or shape0.dim[-1] != shape1.dim[-1]: + continue + slice0 = _get_producer(graph, reshape0.input[0], "Slice") + if slice0 is None or not _check_slice(graph, slice0, 0, -1, -2, 1): + continue + reshape1 = _get_producer(graph, node.input[1], "Reshape") + if reshape1 is None: + continue + slice1 = _get_producer(graph, reshape1.input[0], "Slice") + if slice1 is None or not _check_slice(graph, slice1, 1, sys.maxsize, -1, 1): + continue + scel_grad = _get_consumer(graph, node.output[1], "SoftmaxCrossEntropyLossInternalGrad") + if scel_grad is None: + continue + reshape2 = _get_consumer(graph, scel_grad.output[0], "Reshape") + if reshape2 is None: + continue + slice_grad = _get_consumer(graph, reshape2.output[0], "SliceGrad") + if slice_grad is None: + continue + shape_node = _get_producer(graph, slice_grad.input[1], "Shape") + if shape_node is None: + continue + bias_arg = "" + sum_node = _get_consumer(graph, slice_grad.output[0], "Sum") + if sum_node is not None and len(sum_node.input) == 2: + _, shape0 = _get_arg_info(graph, sum_node.input[0]) + _, shape1 = _get_arg_info(graph, sum_node.input[1]) + if shape0 is not None and shape0 == shape1: + bias_arg = sum_node.input[0] if sum_node.input[1] == slice_grad.output[0] else sum_node.input[1] + sub_graph_nodes = [node, reshape0, slice0, reshape1, slice1, scel_grad, reshape2, slice_grad, shape_node] + _get_shape_related_nodes(graph, slice0.output[0], sub_graph_nodes) + if bias_arg: + sub_graph_nodes.append(sum_node) + remove_nodes.extend(sub_graph_nodes) + forward_inputs = [slice0.input[0], slice1.input[0]] + if len(node.input) > 3: + forward_inputs.append(node.input[3]) + else: + ignore_index_arg = "ignore_index_" + str(idx) + ignore_index_node = helper.make_node( + "Constant", + inputs=[], + outputs=[ignore_index_arg], + value=helper.make_tensor( + name=ignore_index_arg, + data_type=TensorProto.INT64, + dims=(), + vals=[-100], + ), + ) + forward_inputs.append(ignore_index_arg) + triton_nodes.append(ignore_index_node) + # Use float for log_prob, which has better precision, but may consume more memory. + log_prob_arg = helper.make_tensor_value_info("scel_log_prob_" + str(idx), TensorProto.FLOAT, None) + factor_arg = helper.make_tensor_value_info("scel_factor_" + str(idx), TensorProto.FLOAT, None) + value_infos.extend([log_prob_arg, factor_arg]) + triton_fw_node = helper.make_node( + "TritonOp", + forward_inputs, + [node.output[0], log_prob_arg.name, factor_arg.name], + "TritonOp_Slice_SCEL_" + str(idx), + None, + "com.microsoft", + func_name="slice_scel", + ) + triton_nodes.append(triton_fw_node) + backward_outputs = [sum_node.output[0] if bias_arg else slice_grad.output[0]] + triton_bw_node = helper.make_node( + "TritonOp", + [scel_grad.input[0], log_prob_arg.name, slice1.input[0], factor_arg.name, bias_arg], + backward_outputs, + "TritonOp_Slice_SCEL_Backward_" + str(idx), + None, + "com.microsoft", + func_name="slice_scel_backward", + ) + triton_nodes.append(triton_bw_node) + idx += 1 + + all_nodes = [] + for node in graph.node: + if node not in remove_nodes: + all_nodes.append(node) + + for node in triton_nodes: + all_nodes.append(node) # noqa: PERF402 + + graph.ClearField("node") + graph.node.extend(all_nodes) + graph.value_info.extend(value_infos) diff --git a/orttraining/orttraining/python/training/ort_triton/triton_op_executor.py b/orttraining/orttraining/python/training/ort_triton/triton_op_executor.py new file mode 100644 index 0000000000000..b970c730d0441 --- /dev/null +++ b/orttraining/orttraining/python/training/ort_triton/triton_op_executor.py @@ -0,0 +1,98 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# -------------------------------------------------------------------------- + +import functools +import json +import os +import sys +from types import ModuleType +from typing import List, Tuple + +import onnx +from torch._C import _from_dlpack +from torch.utils.dlpack import to_dlpack + +from ._cache import ModuleCache, PyCodeCache +from ._codegen import codegen +from ._op_config import get_supported_ops +from ._sorted_graph import SortedGraph +from ._sympy_utils import parse_shape +from ._utils import gen_unique_name + +_DEBUG_MODE = "ORTMODULE_TRITON_DEBUG" in os.environ and int(os.getenv("ORTMODULE_TRITON_DEBUG")) == 1 + + +@functools.lru_cache(None) +def _gen_module_internal(sorted_graph: SortedGraph) -> Tuple[str, str, ModuleType]: + func_name = gen_unique_name("func") + src_code = codegen(func_name, sorted_graph) + return func_name, src_code, PyCodeCache().load(src_code) + + +def _gen_key(onnx_key: int, onnx_str: bytes, shapes: List[List[int]]) -> int: + return hash(f"{onnx_key}|{str(shapes).replace(' ', '')}") % (10**8) + + +def _gen_module(onnx_key: int, onnx_str: bytes, shapes: List[List[int]]) -> Tuple[str, ModuleType]: + model = onnx.load_model_from_string(onnx_str) + sorted_graph = SortedGraph(model, [parse_shape(shape) for shape in shapes]) + if _DEBUG_MODE: + os.makedirs(os.path.dirname("triton_debug/"), exist_ok=True) + sorted_graph.save_onnx(f"triton_debug/{onnx_key}") + func_name, src_code, mod = _gen_module_internal(sorted_graph) + if _DEBUG_MODE: + py_file_path = f"triton_debug/{func_name}_{onnx_key}.py" + with open(py_file_path, "w") as f: + f.write(src_code) + return func_name, mod + + +def get_config() -> str: + """ + Get the supported ops and other configs in JSON format to control the Triton fusion on backend side. + All supported ops are from _op_config.py. The Triton fusion will try to fuse subgraphs with connected supported ops. + The initializer value can be "none", "scalar", and "all". + "none": no initializer will be added to subgraphs. + "scalar": only related scalar initializers will be added to subgraphs. + "all": all related initializers will be added to subgraphs. + The min_nodes is used to control the minimum number of non-no-op nodes in a subgraph. + """ + + config = {"ops": get_supported_ops(), "initializer": "scalar", "min_nodes": 2} + return json.dumps(config) + + +def call_triton_by_name(func_name: str, *tensors, **kwargs): + """ + Call triton kernel by function name. It's expected that there are functions and kernels registered manually + with that func_name (normally in .kernel sub-module), this function try to get the Python function by name + and execute it with the given tensors. + """ + + torch_tensors = [_from_dlpack(tensor) if tensor is not None else None for tensor in tensors] + func = getattr(sys.modules[".".join(__name__.split(".")[:-1])], func_name) + output = func(*torch_tensors, **kwargs) + if output is not None: + if isinstance(output, tuple): + return tuple([to_dlpack(tensor) for tensor in output]) + return to_dlpack(output) + return None + + +def call_triton_by_onnx(onnx_key: int, onnx_str: bytes, *tensors): + """ + Call triton kernel by ONNX model. Load the ONNX model from onnx_str, generate the Triton function and kernels, + and execute the function with the given tensors. + """ + + assert all(tensor is not None for tensor in tensors) + torch_tensors = [_from_dlpack(tensor) for tensor in tensors] + concrete_shapes = [list(tensor.size()) for tensor in torch_tensors] + func_name, mod = ModuleCache.load(_gen_key, _gen_module, onnx_key, onnx_str, concrete_shapes) + func = getattr(mod, func_name) + output = func(*torch_tensors) + if isinstance(output, tuple): + return tuple([to_dlpack(tensor) for tensor in output]) + return to_dlpack(output) diff --git a/orttraining/orttraining/python/training/ortmodule/__init__.py b/orttraining/orttraining/python/training/ortmodule/__init__.py index 99ca9b7a611e9..59cf05bb082fc 100644 --- a/orttraining/orttraining/python/training/ortmodule/__init__.py +++ b/orttraining/orttraining/python/training/ortmodule/__init__.py @@ -12,10 +12,14 @@ from onnxruntime import set_seed from onnxruntime.capi import build_and_package_info as ort_info +from onnxruntime.capi._pybind_state import is_ortmodule_available from ._fallback import ORTModuleFallbackException, ORTModuleInitException, _FallbackPolicy, wrap_exception from .torch_cpp_extensions import is_installed as is_torch_cpp_extensions_installed +if not is_ortmodule_available(): + raise ImportError("ORTModule is not supported on this platform.") + def _defined_from_envvar(name, default_value, warn=True): new_value = os.getenv(name, None) @@ -120,7 +124,8 @@ def _are_deterministic_algorithms_enabled(): return ORTMODULE_IS_DETERMINISTIC -from .debug_options import DebugOptions, LogLevel # noqa: E402, F401 +from .graph_transformer_registry import register_graph_transformer # noqa: E402, F401 +from .options import DebugOptions, LogLevel # noqa: E402, F401 # ORTModule must be loaded only after all validation passes from .ortmodule import ORTModule # noqa: E402, F401 diff --git a/orttraining/orttraining/python/training/ortmodule/_custom_autograd_function.py b/orttraining/orttraining/python/training/ortmodule/_custom_autograd_function.py index 31a7f07f3cfbf..fece1be20c96a 100644 --- a/orttraining/orttraining/python/training/ortmodule/_custom_autograd_function.py +++ b/orttraining/orttraining/python/training/ortmodule/_custom_autograd_function.py @@ -3,6 +3,9 @@ # Licensed under the MIT License. # -------------------------------------------------------------------------- +from onnxruntime.capi._pybind_state import is_torch_interop_default_on +from onnxruntime.training import ortmodule + class Enabler: def __init__(self): @@ -83,10 +86,7 @@ def enable_custom_autograd_support(to_enable=True): custom_autograd_function_enabler.state = False -from onnxruntime.capi._pybind_state import is_torch_interop_default_on # noqa: E402 -from onnxruntime.training import ortmodule # noqa: E402 - # Enable the custom autograd by default when PythonOp backend support is enabled during build. enable_custom_autograd_support( - not ortmodule._defined_from_envvar("ORTMODULE_DISABLE_CUSTOM_AUTOGRAD_SUPPORT", 0) and is_torch_interop_default_on() + ortmodule._defined_from_envvar("ORTMODULE_ENABLE_CUSTOM_AUTOGRAD", 1) and is_torch_interop_default_on() ) diff --git a/orttraining/orttraining/python/training/ortmodule/_custom_autograd_function_exporter.py b/orttraining/orttraining/python/training/ortmodule/_custom_autograd_function_exporter.py index 0fe070b4c5528..f75d553a5f460 100644 --- a/orttraining/orttraining/python/training/ortmodule/_custom_autograd_function_exporter.py +++ b/orttraining/orttraining/python/training/ortmodule/_custom_autograd_function_exporter.py @@ -4,83 +4,125 @@ # -------------------------------------------------------------------------- import sys -import warnings +from typing import Callable, ClassVar, Dict, Optional import torch import torch.utils.checkpoint +from onnx import ModelProto from packaging import version from torch.onnx import symbolic_helper from onnxruntime.capi._pybind_state import register_miscellaneous_const_input, register_torch_autograd_function from onnxruntime.training import ortmodule +from onnxruntime.training.utils import pytorch_dtype_to_onnx -from . import _logger -from ._custom_op_symbolic_registry import pytorch_type_to_onnx +from ._custom_op_symbolic_registry import wrap_custom_export_function from ._fallback import ORTModuleONNXModelException, wrap_exception - -# Some autograd.Function's shouldn't be exported as PythonOp. -# If CheckpointFunction is exported as PythonOp, the checkpointed computation -# may be computed by Pytorch, not ORT. This situation is especially important -# for big models such as GPT-2. Exporting CheckpointFunction as PythonOp means -# every transformer would be computed by Pytorch and ORT doesn't contribute -# at all. -BANNED_AUTOGRAD_FUNCTION_NAMES = frozenset([torch.utils.checkpoint.CheckpointFunction.__name__]) - -# Mapping from pytorch scalar type to onnx scalar type. -_CAST_PYTORCH_TO_ONNX = { - "Byte": torch.onnx.TensorProtoDataType.UINT8, - "Char": torch.onnx.TensorProtoDataType.INT8, - "Double": torch.onnx.TensorProtoDataType.DOUBLE, - "Float": torch.onnx.TensorProtoDataType.FLOAT, - "Half": torch.onnx.TensorProtoDataType.FLOAT16, - "Int": torch.onnx.TensorProtoDataType.INT32, - "Long": torch.onnx.TensorProtoDataType.INT64, - "Short": torch.onnx.TensorProtoDataType.INT16, - "Bool": torch.onnx.TensorProtoDataType.BOOL, - "ComplexFloat": torch.onnx.TensorProtoDataType.COMPLEX64, - "ComplexDouble": torch.onnx.TensorProtoDataType.COMPLEX128, - "BFloat16": torch.onnx.TensorProtoDataType.BFLOAT16, - "Undefined": torch.onnx.TensorProtoDataType.UNDEFINED, -} - - -def _full_name(klass): - module = klass.__module__ - if module == "builtins": - return klass.__qualname__ # avoid outputs like 'builtins.str' - return module + "." + klass.__qualname__ - - -def pytorch_type_to_onnx(scalar_type: str) -> torch.onnx.TensorProtoDataType: # noqa: F811 - try: - return torch.onnx.JitScalarType.from_name(scalar_type).onnx_type() - except AttributeError: - return _CAST_PYTORCH_TO_ONNX[scalar_type] +from ._utils import get_fully_qualified_class_name, get_runtime_pytorch_version + + +class PythonOpShapeInferStore: + """A class to store shape inference functions for torch.autograd.Function.""" + + _CLASS_MAP: ClassVar[Dict[str, Callable]] = {} + + @classmethod + def register(cls, kclass: torch.autograd.Function) -> None: + """Register a shape inference function for a torch.autograd.Function if there is staticmethod + "infer_shape" defined. + + The signature of the shape inference function should be: + @staticmethod + def infer_shape( + node: onnx.NodeProto, + tensor_input_shapes: List[Optional[List[Union[int, str]]]], + tensor_input_dtypes: List[torch.onnx.TensorProtoDataType], + ) -> Tuple[List[Optional[List[Union[int, str]]]], List[torch.onnx.TensorProtoDataType]]: + tensor_output_shapes = [] + tensor_output_dtypes = [] + ... + return tensor_output_shapes, tensor_output_dtypes + + The tensor_input_shapes and tensor_input_dtypes are lists of shapes and dtypes of the input tensors. + The tensor_output_shapes and tensor_output_dtypes are lists of shapes and dtypes of the output tensors. + Be noted: we only pass in tensor inputs, and return tensor outputs, non-tensor inputs/outputs are ignored. + + """ + kclass_name = get_fully_qualified_class_name(kclass) + if hasattr(kclass, "infer_shape") and kclass_name not in cls._CLASS_MAP: + cls._CLASS_MAP[kclass_name] = kclass.infer_shape + + @classmethod + def register_func(cls, name: str, func: Callable) -> None: + """Register a shape inference function for a torch.autograd.Function by name.""" + cls._CLASS_MAP[name] = func + + @classmethod + def get_shape_infer(cls, name: str) -> Optional[Callable]: + return cls._CLASS_MAP.get(name, None) + + +""" +Defines a list of names of torch.autograd.Function, for checkpoint activation purposes. + +Note: + If CheckpointFunction is exported as PythonOp, the checkpoint-ed computation + (applied on every N transformer layer) may be computed by PyTorch, not ORT. + This situation should be especially noted for large language models such as GPT-2. + +As alternatives to using checkpoint activation: +1. Users could leverage HierarchalORTModule to wrap the model, which only wrap exportable +sub-nn.Module's as ORTModule. In this way, ideally, ORT could cover most of the model computation, +other than dispatching them to PyTorch. +2. Users could disable the check by setting the environment variable ORTMODULE_ALLOW_AUTOGRAD_CHECKPOINT=1. +This may imply that the exported model is not fully running on ORT, users should be aware of the potential +performance impact. +3. Users could also leverage ORT's memory optimization feature to achieve a similar effect as checkpointing +activations. Turn off PyTorch's checkpointing activation, then refer to env var ORTMODULE_MEMORY_OPT_CONFIG +to enable ORT's recomputation feature. + +""" +_UNSUPPORTED_CKPT_FUNC_NAMES = frozenset( + [ + # Full qualified name. + "torch.utils.checkpoint.CheckpointFunction", + "deepspeed.checkpointing.CheckpointFunction", + ] +) def _export_pt_1_10(g, n, *args, **kwargs): - """ - This function exports PythonOp (input: "n") into a graph - node in "g". "args" and "kwargs" are inputs to that PythonOp. - A PythonOp represents a call to autograd.Function. + """Export torch.autograd.Function in ORT PythonOp. + + Exports PythonOp (input: "n") into a graph node in "g", and registers the PythonOp's autograd.Function in ORT backend. + + Args: + g (jit_utils.GraphContext): The graph to export to. + n (torch._C.Node): The PythonOp node to export, its property "pyobj" can be used to retrieve the + torch.autograd.Function class. + https://github.com/pytorch/pytorch/blob/68cb854d73458a14684d584c25c22b17eb79dfca/torch/csrc/jit/python/python_ir.cpp#L797 + args (list): The inputs. + kwargs (dict): The keyword arguments. + """ try: - name = kwargs["name"] - if name in BANNED_AUTOGRAD_FUNCTION_NAMES and ( - not ortmodule._defined_from_envvar("ORTMODULE_ALLOW_AUTOGRAD_CHECKPOINT", 0) - or name != torch.utils.checkpoint.CheckpointFunction.__name__ - ): + func_class = n.pyobj().__self__ + func_full_qual_name = get_fully_qualified_class_name(func_class) + + # Check if the checkpointing activation is allowed. + is_ckpt_activation_allowed = ortmodule._defined_from_envvar("ORTMODULE_ALLOW_AUTOGRAD_CHECKPOINT", 0) == 1 + if is_ckpt_activation_allowed is False and func_full_qual_name in _UNSUPPORTED_CKPT_FUNC_NAMES: raise Exception( - f"The autograd.Function {name} should not be exported to ONNX. " + f"The torch.autograd.Function {func_full_qual_name} should not be exported to ONNX. " "Please replace ORTModule with HierarchalORTModule to only" "wrap exportable sub-nn.Module's as ORTModule." ) + inplace = kwargs["inplace"] - # TODO move to public API once exporter team exposes that + # TODO move to public API once the exporter team exposes that training_mode = None - runtime_pytorch_version = version.parse(torch.__version__.split("+")[0]) - if runtime_pytorch_version >= version.parse("1.12"): - # FIXME: using privated modules + if get_runtime_pytorch_version() >= version.parse("1.12"): + # FIXME: using private modules from torch.onnx import _globals # before https://github.com/pytorch/pytorch/commit/c8b9b6266b505328e503b12f6a42fd88c56374f9, @@ -96,16 +138,25 @@ def _export_pt_1_10(g, n, *args, **kwargs): training_mode = _globals.GLOBALS.training_mode == torch.onnx.TrainingMode.TRAINING else: training_mode = symbolic_helper._training_mode + cconv = n.cconv() + input_tensor_types = [] input_tensor_ranks = [] + input_bool_scalars = [] + input_bool_scalar_positions = [] + input_int_scalars = [] input_int_scalar_positions = [] input_float_scalars = [] input_float_scalar_positions = [] + input_bool_tuples = [] + input_bool_tuple_positions = [] + input_bool_tuple_begins = [] + input_int_tuples = [] input_int_tuple_positions = [] input_int_tuple_begins = [] @@ -119,72 +170,96 @@ def _export_pt_1_10(g, n, *args, **kwargs): tensor_args = [] debug_comment = "" - # Encode inputs to autograd.Function. + # Encode inputs to torch.autograd.Function. for i, arg, call_type in zip(range(len(args)), args, cconv): if call_type == "d": # Got a tensor variable. tensor_args.append(arg) - scalar_type = pytorch_type_to_onnx(arg.type().scalarType()) + scalar_type = pytorch_dtype_to_onnx(arg.type().scalarType()) input_tensor_types.append(scalar_type) input_tensor_ranks.append(arg.type().dim()) - elif call_type == "c": - # Got a non-tensor variable. - # Non-tensor can't have gradient. - if isinstance(arg, float): - # A float. - input_float_scalar_positions.append(i) - input_float_scalars.append(arg) - elif isinstance(arg, int): - # A int. - input_int_scalar_positions.append(i) - input_int_scalars.append(arg) - elif isinstance(arg, tuple): - assert len(arg) > 0 - # A tuple of int or float. - if all(isinstance(ele, int) for ele in arg): - # A tuple of ints. - input_int_tuple_positions.append(i) - input_int_tuple_begins.append(len(input_int_tuples)) - input_int_tuples.extend(list(arg)) - elif all(isinstance(ele, float) for ele in arg): - # A tuple of floats. - input_float_tuple_positions.append(i) - input_float_tuple_begins.append(len(input_float_tuples)) - input_float_tuples.extend(list(arg)) - else: - raise wrap_exception( - ORTModuleONNXModelException, Exception(f"Unknown argument type found: {type(arg)}.") - ) - else: - if name == "_InspectActivation" and isinstance(arg, str): - # _InspectActivation is a special case where the first argument is a string - # that is used to determine the activation name to be inspected. - debug_comment += arg - - # All other inputs are accessed via "pointers". - input_pointer_scalar_positions.append(i) - input_pointer_scalars.append(id(arg)) - - # For pointer (for example, ProcessGroup passed to PythonOp) needed for PythonOp execution, - # we append it into a global store to hold a reference (in case it is released after module exported). - register_miscellaneous_const_input(arg) - else: + continue + + if call_type != "c": raise wrap_exception( ORTModuleONNXModelException, Exception(f"Unknown calling convention found: {i}. Only 'd' and 'c' are supported"), ) + # Got a non-tensor variable. + # Non-tensor can't have gradient. + if isinstance(arg, float): + # A float. + input_float_scalar_positions.append(i) + input_float_scalars.append(arg) + continue + # bool check MUST be before int check since bool is a subclass of int + elif isinstance(arg, bool): + # A bool. + input_bool_scalar_positions.append(i) + input_bool_scalars.append(int(arg)) + continue + elif isinstance(arg, int): + # A int. + input_int_scalar_positions.append(i) + input_int_scalars.append(arg) + continue + + is_bool_tuple = False + is_int_tuple = False + is_float_tuple = False + if isinstance(arg, tuple) and len(arg) > 0: + # bool check MUST be before int check since bool is a subclass of int. + is_bool_tuple = all(isinstance(ele, bool) for ele in arg) + is_int_tuple = not is_bool_tuple and all(isinstance(ele, int) for ele in arg) + is_float_tuple = not is_bool_tuple and not is_int_tuple and all(isinstance(ele, float) for ele in arg) + + # Only support tuple of bool, int or float, for other types, handle it as a pointer. + if is_bool_tuple: + # A tuple of bool. + input_bool_tuple_positions.append(i) + input_bool_tuple_begins.append(len(input_bool_tuples)) + input_bool_tuples.extend([int(ele) for ele in arg]) + continue + elif is_int_tuple: + # A tuple of ints. + input_int_tuple_positions.append(i) + input_int_tuple_begins.append(len(input_int_tuples)) + input_int_tuples.extend(list(arg)) + continue + elif is_float_tuple: + # A tuple of floats. + input_float_tuple_positions.append(i) + input_float_tuple_begins.append(len(input_float_tuples)) + input_float_tuples.extend(list(arg)) + continue + + from onnxruntime.training.utils.hooks._statistics_subscriber import _InspectActivation + + is_inspect_activation = func_full_qual_name == get_fully_qualified_class_name(_InspectActivation) + if is_inspect_activation and isinstance(arg, str): + # _InspectActivation is a special case where the first argument is a string + # that is used to determine the activation name to be inspected. + debug_comment += arg + + # All other inputs are accessed via "pointers". + input_pointer_scalar_positions.append(i) + input_pointer_scalars.append(id(arg)) + + # For pointer (for example, ProcessGroup passed to PythonOp) needed for PythonOp execution, + # we append it into a global store to hold a reference (in case it is released after module exported). + register_miscellaneous_const_input(arg) + output_tensor_types = [] output_tensor_ranks = [] for arg in n.outputs(): # Type of tensor's elements. - scalar_type = pytorch_type_to_onnx(arg.type().scalarType()) + scalar_type = pytorch_dtype_to_onnx(arg.type().scalarType()) output_tensor_types.append(scalar_type) output_tensor_ranks.append(arg.type().dim()) - # TODO: add fully-qualified name. attrs = { - "name_s": name, + "func_name_s": func_full_qual_name, "inplace_i": inplace, "input_convention_s": cconv, "outputs": n.outputsSize(), @@ -196,12 +271,19 @@ def _export_pt_1_10(g, n, *args, **kwargs): "comment_s": debug_comment, } + if len(input_bool_scalars) > 0: + attrs["input_bool_scalars_i"] = input_bool_scalars + attrs["input_bool_scalar_positions_i"] = input_bool_scalar_positions if len(input_int_scalars) > 0: attrs["input_int_scalars_i"] = input_int_scalars attrs["input_int_scalar_positions_i"] = input_int_scalar_positions if len(input_float_scalars) > 0: attrs["input_float_scalars_f"] = input_float_scalars attrs["input_float_scalar_positions_i"] = input_float_scalar_positions + if len(input_bool_tuples) > 0: + attrs["input_bool_tuples_i"] = input_bool_tuples + attrs["input_bool_tuple_positions_i"] = input_bool_tuple_positions + attrs["input_bool_tuple_begins_i"] = input_bool_tuple_begins if len(input_int_tuples) > 0: attrs["input_int_tuples_i"] = input_int_tuples attrs["input_int_tuple_positions_i"] = input_int_tuple_positions @@ -216,6 +298,11 @@ def _export_pt_1_10(g, n, *args, **kwargs): returned_args = g.op("com.microsoft::PythonOp", *tensor_args, **attrs) + # Register function with class names. + register_torch_autograd_function(func_full_qual_name, func_class) + + # Register shape inference function. + PythonOpShapeInferStore.register(func_class) return returned_args except Exception as e: sys.stdout.flush() @@ -223,86 +310,26 @@ def _export_pt_1_10(g, n, *args, **kwargs): raise wrap_exception(ORTModuleONNXModelException, e) # noqa: B904 -# Starting from PyTorch 1.11, there has been a change to symbolic function signature -# in terms of how additional context is accessed. More info at -# https://github.com/pytorch/pytorch/blob/6b02648479d3615fa3260961e24f38dd0f22da94/torch/onnx/symbolic_helper.py#L48 -# This code can be cleaned up once support for PyTorch version < 1.11 is dropped. -try: - from torch.onnx import SymbolicContext - - def _export(ctx: SymbolicContext, g, *args, **kwargs): - n = ctx.cur_node - return _export_pt_1_10(g, n, *args, **kwargs) - -except ImportError: - _export = _export_pt_1_10 - - -def _post_process_after_export(exported_model, enable_custom_autograd_function, log_level): - if enable_custom_autograd_function: - return _post_process_enabling_autograd_fallback(exported_model) - - is_pythonop_needed = False - for node in exported_model.graph.node: - if node.domain == "com.microsoft" and node.op_type in ["PythonOp"]: - is_pythonop_needed = True - break - - if is_pythonop_needed and log_level <= _logger.LogLevel.WARNING: - warnings.warn( - "Detected autograd functions usage in current model, the run will fail \ - without enabling '_enable_custom_autograd_function'. Please enable it with: \ - 'module._execution_manager(is_training_mode)._enable_custom_autograd_function = True'", - UserWarning, - ) - - return exported_model - +_export = wrap_custom_export_function(_export_pt_1_10) -def _post_process_enabling_autograd_fallback(exported_model): - registered_name_mappings = {} - skipped_autograd_function_list = ortmodule._defined_from_envvar("ORTMODULE_SKIPPED_AUTOGRAD_FUNCTIONS", "").split( - "," - ) - for kclass in torch.autograd.Function.__subclasses__(): - full_qualified_name = _full_name(kclass) - if full_qualified_name in skipped_autograd_function_list: - continue - # Collect mapping of class names to full qualified class names. - if kclass.__name__ not in registered_name_mappings: - registered_name_mappings[kclass.__name__] = [] - registered_name_mappings[kclass.__name__].append(full_qualified_name) - - # Register function with class names. - register_torch_autograd_function(kclass.__name__, kclass) +def post_process_enabling_autograd_function(exported_model: ModelProto) -> ModelProto: + # Loop all PythonOp, append "_ctx" as the first output. index = 0 for node in exported_model.graph.node: - if node.domain == "com.microsoft" and node.op_type in ["PythonOp"]: + op_name_prefix = node.op_type + if node.domain == "com.microsoft" and node.op_type == "PythonOp": output_names = list(node.output) del node.output[:] node.output.append(output_names[0] + "_ctx") node.output.extend(output_names) for attr in node.attribute: - if attr.name == "name": + if attr.name == "func_name": kclass_name = attr.s.decode("utf-8") if isinstance(attr.s, bytes) else attr.s - # If the duplicated function is used in ONNX graph, we will fail in case of a wrong function call. - # Todo: remove this trick once exporter can support fully qualified name for PythonOp. - if kclass_name in registered_name_mappings and len(registered_name_mappings[kclass_name]) > 1: - error_msg = ( - "More than one torch.autograd.Function named {}, but probabbly in different namespace. " - "The conflicting autograd.Functions are: {}. Currently torch exporter cannot " - "differentiate them with full qualified name, so there is a risk exported PythonOp calls a " - "wrong autograd.Function.".format( - kclass_name, ",".join(registered_name_mappings[kclass_name]) - ) - ) - raise wrap_exception(ORTModuleONNXModelException, RuntimeError(error_msg)) - + op_name_prefix = kclass_name break - if not node.name: - node.name = node.op_type + "_id_" + str(index) - index += 1 + node.name = f"{op_name_prefix}_id_{index}" + index += 1 return exported_model diff --git a/orttraining/orttraining/python/training/ortmodule/_custom_autograd_function_runner.py b/orttraining/orttraining/python/training/ortmodule/_custom_autograd_function_runner.py index 8a7542d12180e..a5b96c4e37140 100644 --- a/orttraining/orttraining/python/training/ortmodule/_custom_autograd_function_runner.py +++ b/orttraining/orttraining/python/training/ortmodule/_custom_autograd_function_runner.py @@ -4,6 +4,9 @@ # -------------------------------------------------------------------------- import sys +import warnings +from collections import OrderedDict +from typing import Callable, Dict, List, Optional, Tuple, Union import torch from torch.utils.dlpack import from_dlpack, to_dlpack @@ -13,58 +16,195 @@ from ._fallback import ORTModuleFallbackException, ORTModuleIOError, _FallbackManager, wrap_exception # noqa: F401 -def wrap_as_dlpack_or_not(grad_flag, tensor_flag, inplace_flag, training_mode_flag, arg): - """ - If the input is a DLPack tensor, we wrap it as a torch.Tensor and - set up its attributes according to other input flags. Otherwise, - we return the input as is. - - grad_flag: indicate if "arg" requires gradient. This is only valid if - "arg" is a DLPack tensor. - tensor_flag: indicate if "arg" is a DLPack tensor. - inplace_flag: indicate if "arg" may be modified in custom function. - training_mode_flag: indicate if the top-level model is running - under training (or inference) mode. - arg: a DLPack tensor or a normal Python object (e.g, a tuple of ints). - """ - if tensor_flag: - # Got a tensor. Assume it's a DLPack tensor - # and convert it to Pytorch tensor. - if training_mode_flag: - wrapped_arg = from_dlpack(arg).detach().clone() - # TODO: This clone is just a workround to fix the bug that - # input saved for backward may be "released" by ORT. - # we need a follow up fix to avoid the copy overhead. - else: - wrapped_arg = from_dlpack(arg) +class CustomFuncOpKernelInfo: + """Store the kernel specific information retrieved with the first-time run.""" + + def __init__(self, kernel_invoke_id: str): + # kernel_invoke_id is a string contains session thread id, op kernel creation time stamp in ms, a random int, + # and address of op_kernel pointer. This can guarantee the uniqueness of the key in case of multiple + # instances of a same named PythonOp/PythonOpGrad in one session, or multiple sessions. + self.kernel_invoke_id = kernel_invoke_id + + # For the tensors generated from ORT backend, there is special handling here: + # 1. For the first time run for the kernel (the uniqueness of the kernel is defined by kernel_invoke_id), + # all such tensors will be cloned in case they are saved in context (but ORT backend is not aware of the + # reference, may release the content of the tensor before it is needed in backward). Once + # `autograd.Function.apply` completes, by checking the existence of the tensor in the saved_tensors, + # `_GlobalOpKernelInfoMap` is updated to save the input indices that are saved in context. + # 2. For the subsequent runs, if the input index is in `input_indices_to_save_in_ctx`, the tensor + # will be cloned before fed into `autograd.Function.apply` as input. + self.input_indices_to_save_in_ctx: List[int] = [] + + # To align with PyTorch `ctx.set_materialize_grads(False|True)`` + # materialize_grads_config is a map from output index to (device, dtype, shape) of the output tensor, used + # for materializing the gradient of the output tensor in backward. + self.materialize_grads: bool = False + self.materialize_grads_config: Optional[Dict[int, Tuple[torch.device, torch.dtype, torch.shape]]] = None + + +# Store the kernel specific information that cannot be retrieved and saved by PyTorch exporter. +# For those infos that can only be retrieved with real run, we try to collect them in the first time run. +# key: kernel_invoke_id, value: CustomFuncOpKernelInfo. +_GlobalOpKernelInfoMap: Dict[str, CustomFuncOpKernelInfo] = {} + + +def _get_context(forward_tensor_outputs: List[torch.Tensor]) -> Tuple[any, Optional[torch.Tensor]]: + """Search for context among all outputs. + + Note1: All forward outputs of torch.autograd.Function shared the same gradient function pointer, + so here we just get the first tensor having grad_fn attribute. + (https://github.com/PyTorch/PyTorch/blob/15532595209d2daf34d35e10f8d3d3b64966aea2/torch/csrc/autograd/custom_function.cpp#L267) - # Only requires gradient when running under training mode - # and the associated tensor has grad_flag=True (i.e., - # "requires_grad=True" in the original Pytorch script). - wrapped_arg.requires_grad = training_mode_flag and grad_flag + Note2: Context can be None because NOT all torch.autograd.Function's are differentiable. The function + https://github.com/PyTorch/PyTorch/blob/d701357d921ef167d42c125e65b6f7da6be3ad0f/torch/csrc/autograd/custom_function.cpp#L209? + means if all output of forward function is not differentiable, then grad_fn will be None (not be set). - return wrapped_arg + For example, + class Bar(torch.autograd.Function): + # A non-differentiable autograd Function whose forard output + # doesn't have grad_fn attribute. + @staticmethod + def forward(ctx, x): + y = torch.ones_like(x) + return y - # Use non-tensor as is. It's a PyObject*. - return arg + @staticmethod + def backward(ctx, dy): + dx = torch.zeros_like(dy) + return dx + + Returns: + ctx: context of the autograd.Function. + tensor: a tensor that owns the context. + + """ + ctx = None + first_tensor_output = None + for arg in forward_tensor_outputs: + if not isinstance(arg, torch.Tensor) or not hasattr(arg, "grad_fn"): + continue + + if arg.grad_fn is None: + # For following case, it is possible grad_fn exist, but its value is None, + # so we need to continue to search for the first tensor having a non-None grad_fn. + # + # >>> w = torch.randn(5, 6) + # >>> hasattr(w, "grad_fn") + # True + # >>> w.grad_fn is None + # True + # >>> w, ... = CustomFunc.apply(w) # where CustomFunc forward just return w and other tensors. + # + # Then hasattr(w, "grad_fn") is True, but w.grad_fn is None. + continue + # Use the first context we see because all of arg's share the same one. + ctx = arg.grad_fn + first_tensor_output = arg + break + if first_tensor_output is not None: + assert ctx is not None, "ctx should not be None if first_tensor_output is not None." + return (ctx, first_tensor_output) + + +def _finalize_traing_mode_forward( + kernel_invoke_id: str, + input_tensors_from_ort: Dict[int, torch.Tensor], + forward_output_tensors: List[Union[torch.Tensor, None]], +): + """Complete the epilogue of forward runner for training mode. + + Args: + kernel_invoke_id: kernel_invoke_id of the PythonOp kernel unique id. + input_tensors_from_ort: input tensors generated from ORT backend. + forward_output_tensors: output tensors of the autograd.Function. + + Things to do: + 1. Try to get context from forward output tensors. + 2. Remove the gradient functions between current autograd.Function and its input's gradient function, because + in ORT we don't depend on PyTorch's autograd engine. + 3. Register the current autograd.Function's gradient function into our PyNodeSharedPointerPool. + 4. Save kernel specific information into _GlobalOpKernelInfoMap in the first-time kernel run. + """ + + ctx, tensor_owning_ctx = _get_context(forward_output_tensors) + + # ctx being None in training mode means the forward function is not differentiable, so backward is not needed. + if ctx is None: + return None + + # Filter out the None in the saved_tensors. + saved_tensors = [t for t in ctx.saved_tensors if t is not None] + + ctx.fw_kernel_invoke_id = kernel_invoke_id + + # If this is the first time run, collect kernel specific information. + if kernel_invoke_id not in _GlobalOpKernelInfoMap: + kernel_info = CustomFuncOpKernelInfo(kernel_invoke_id) + _GlobalOpKernelInfoMap[kernel_invoke_id] = kernel_info + if len(saved_tensors): + # Check tensors generated by ORT is in the saved_tensors or not. + # If yes, save the input index of the tensor in the _GlobalOpKernelInfoMap. + kernel_info.input_indices_to_save_in_ctx = [ + arg_index + for arg_index, tensor in input_tensors_from_ort.items() + if any(tensor is saved_tensor for saved_tensor in saved_tensors) + ] + warnings.warn("Add input index to _GlobalOpKernelInfoMap, to avoid extra copy in every iteration.") + kernel_info.materialize_grads = torch_interop_utils.get_materialize_grads(tensor_owning_ctx) + kernel_info.materialize_grads_config = OrderedDict() + if kernel_info.materialize_grads: + for output_index, tensor in enumerate(forward_output_tensors): + if isinstance(tensor, torch.Tensor): + kernel_info.materialize_grads_config[output_index] = ( + tensor.device, + tensor.dtype, + tensor.shape, + ) + + # FORWARD BACKWARD FUNCTION CONNECTIONS + # input_1 (leaf, constructed by from_dlpack) <----reference---- AccumulateGrad gradient function + # ↓ ↑ + # autograd.Function apply() ------------> autograd.Function backward() + # ↓ | ↑ + # output_1, output_2 --- shared_ptr --- ↑ + # ↓ previous gradient function + + # We remove the edges starting between current autograd.Function's gradient function and + # it's input's gradient function (e.g. AccumulateGrad gradient function), then + # AccumulateGrad gradient function will be destroyed, releasing the reference to input_1 + # (https://github.com/PyTorch/PyTorch/blob/15532595209d2daf34d35e10f8d3d3b64966aea2/torch/csrc/autograd/functions/accumulate_grad.cpp#L21). + # The next edges are stored in Node, with which we can get next gradient function. + # https://github.com/PyTorch/PyTorch/blob/15532595209d2daf34d35e10f8d3d3b64966aea2/torch/csrc/autograd/function.h#L527 + torch_interop_utils.clear_grad_fns_for_next_edges(tensor_owning_ctx, saved_tensors) + + # This is mainly to hold grad_fn references by registering it into our PyNodeSharedPointerPool. + torch_interop_utils.register_grad_fn_and_remove_from_autograd(id(ctx), tensor_owning_ctx) + + return ctx def call_python_forward_function( - forward_function, requires_grad_flags, tensor_type_flags, is_training_mode, inplace, *args + forward_function: Callable, + requires_grad_flags: List[bool], + tensor_type_flags: List[int], + is_training_mode: bool, + inplace: bool, + kernel_invoke_id: str, + *args, ): """ This function bridges the gap between ORT variables and autograd.Function.apply. - It conducts basic casting from ORT to Pytorch (before calling "forward_function") and from Pytorch to ORT - (after calling "forward_function"). It also enable autograd in Pytorch. It formats returned outputs, + It conducts basic casting from ORT to PyTorch (before calling "forward_function") and from PyTorch to ORT + (after calling "forward_function"). It also enable autograd in PyTorch. It formats returned outputs, for example, dropping None's from forward_function's output list. The major difference between call_python_forward_function and call_python_backward_function is that - in the forward one, we have extra code to process autograd context from Pytorch. + in the forward one, we have extra code to process autograd context from PyTorch. Args: forward_function: pointer to autograd.Function.apply (e.g., MyReLU.apply). requires_grad_flags: requires_grad_flags[i] indicates if the i-th arg needs gradient. - tensor_type_flags: tensor_type_flagsi] indicates the type of the i-th arg. + tensor_type_flags: tensor_type_flags[i] indicates the type of the i-th arg, 0 - non-tensor, 1 - tensor. is_training_mode: indicates if this model is running under training mode. inplace: indicates if args can be modified inside the custom function. args: inputs to "backward_function". @@ -72,7 +212,7 @@ def call_python_forward_function( def generate_non_leaf_or_not(grad_flag, tensor_flag, arg, is_training_mode, is_inplace): if is_training_mode and tensor_flag and grad_flag and is_inplace: - # "multiply one" helps change the torch tensor's is_leaf to be False. + # "multiply one" helps change the torch tensor's is_leaf to False. # This is required when the torch tensor is updated in-place during forward pass. # We cannot use view here, because PyTorch handles grad_fn for view differently. non_leaf_arg = arg * 1 @@ -80,83 +220,44 @@ def generate_non_leaf_or_not(grad_flag, tensor_flag, arg, is_training_mode, is_i else: return arg - def wrap_all_outputs(result, training_mode_flag): - # This is mainly to hold grad_fn references by registering it into our PyNodeSharedPointerPool. - def register_context(result): - # Search for context among all outputs. - ctx = None - # All forward outputs of torch.autograd.Function shared a same gradient function pointer, - # so here we just get the first tensor having grad_fn attribute. - # (https://github.com/pytorch/pytorch/blob/15532595209d2daf34d35e10f8d3d3b64966aea2/torch/csrc/autograd/custom_function.cpp#L267) - first_tensor_output = None - for arg in result: - if not isinstance(arg, torch.Tensor) or not hasattr(arg, "grad_fn"): - continue - # Use the first context we see because all of arg's - # share the same one. - ctx = arg.grad_fn - first_tensor_output = arg - break - - # Context can be None because not all autograd.Function's are differentiable. The function - # https://github.com/pytorch/pytorch/blob/d701357d921ef167d42c125e65b6f7da6be3ad0f/torch/csrc/autograd/custom_function.cpp#L209? - # means if all output of forward function are not differentiable, then grad_fn will be None (not be set). - # For example, - # class Bar(torch.autograd.Function): - # # A non-differentiable autograd Function whose forard output - # # doesn't have grad_fn attribute. - # @staticmethod - # def forward(ctx, x): - # y = torch.ones_like(x) - # return y - - # @staticmethod - # def backward(ctx, dy): - # dx = torch.zeros_like(dy) - # return dx - - if training_mode_flag and ctx: - # FORWARD BACKWARD FUNCTION CONNECTIONS - # input_1 (leaf, constructed by from_dlpack) <----reference---- AccumulateGrad gradient function - # ↓ ↑ - # autograd.Function apply() ------------> autograd.Function backward() - # ↓ | ↑ - # output_1, output_2 --- shared_ptr --- ↑ - # ↓ previous gradient function - - # We remove the edges starting between current autograd.Function's gradient function and - # it's input's gradient function (e.g. AccumulateGrad gradient function), then - # AccumulateGrad gradient function will be destroyed, releasing the reference to input_1 - # (https://github.com/pytorch/pytorch/blob/15532595209d2daf34d35e10f8d3d3b64966aea2/torch/csrc/autograd/functions/accumulate_grad.cpp#L21). - # The next edges are stored in Node, with which we can get next gradient function. - # https://github.com/pytorch/pytorch/blob/15532595209d2daf34d35e10f8d3d3b64966aea2/torch/csrc/autograd/function.h#L527 - # filter out the None in the saved_tensors. - saved_tensors = [t for t in ctx.saved_tensors if t is not None] - torch_interop_utils.clear_grad_fns_for_next_edges(first_tensor_output, saved_tensors) - torch_interop_utils.register_grad_fn(id(ctx), first_tensor_output) - return ctx - - if isinstance(result, torch.Tensor): - ctx = register_context([result]) - return [ctx, to_dlpack(result)] - elif isinstance(result, (tuple, list)): - ctx = register_context(result) - wrapped = [ctx] - wrapped.extend(list(to_dlpack(value) if value is not None else None for value in result)) - # Inside the returned list, first element is context and the rest - # are DLPack tensors. - return wrapped - else: - raise wrap_exception( - ORTModuleIOError, - TypeError(f"ORTModule does not support the following model output type {type(result)}."), - ) - try: - wrapped_args = list( - wrap_as_dlpack_or_not(grad_flag, tensor_flag, inplace, is_training_mode, arg) - for grad_flag, tensor_flag, arg in zip(requires_grad_flags, tensor_type_flags, args) - ) + wrapped_args = [] + tensor_input_args_map = OrderedDict() + + # Be noted: in inference mode, we won't insert any information into _GlobalOpKernelInfoMap, because ctx + # will always be None in the first time run. + input_indices_to_save_in_ctx = None # Uninitialized + if kernel_invoke_id in _GlobalOpKernelInfoMap: + input_indices_to_save_in_ctx = _GlobalOpKernelInfoMap[kernel_invoke_id].input_indices_to_save_in_ctx + + for arg_index, (grad_flag, tensor_flag, arg) in enumerate(zip(requires_grad_flags, tensor_type_flags, args)): + if tensor_flag: + # Assume it's a DLPack tensor and convert it to PyTorch tensor. + # Note1: + # If it's first-time kernel invocation, input_indices_to_save_in_ctx is None, we do the + # copy for all tensor. Otherwise, we only copy the tensors whose indices are in + # input_indices_to_save_in_ctx. + # + # Note2: + # For inference mode, we don't need do the copy because ctx will be None, + # so nothing will be saved for ctx. + if is_training_mode and ( + input_indices_to_save_in_ctx is None or arg_index in input_indices_to_save_in_ctx + ): + wrapped_arg = from_dlpack(arg).detach().clone() + else: + wrapped_arg = from_dlpack(arg) + + # Only requires gradient when running under training mode + # and the associated tensor has grad_flag=True (i.e., + # "requires_grad=True" in the original PyTorch script). + wrapped_arg.requires_grad = is_training_mode and grad_flag + wrapped_args.append(wrapped_arg) + tensor_input_args_map[arg_index] = wrapped_arg + + else: + # Use non-tensor as is. It's a PyObject*. + wrapped_args.append(arg) with torch.set_grad_enabled(is_training_mode): # Another level of wrap to avoid requires_grad=True for leaf variables. @@ -166,11 +267,31 @@ def register_context(result): ) # Run autograd.Function.apply(...). + # TODO(pengwa): looks we are assuming all outputs will be either Tensor or None. + # We should revisit if it is possible to support other types of output, for example int, or, etc. + # But that might also requires some work in backend. result = forward_function(*new_wrapped_args) # Extract results as DLPack tensors plus autograd context. Also skips all None values. - unwrapped_values = wrap_all_outputs(result, is_training_mode) - + if isinstance(result, torch.Tensor): + ctx = None + if is_training_mode: + ctx = _finalize_traing_mode_forward(kernel_invoke_id, tensor_input_args_map, [result]) + unwrapped_values = [ctx, to_dlpack(result)] + elif isinstance(result, (tuple, list)): + ctx = None + if is_training_mode: + ctx = _finalize_traing_mode_forward(kernel_invoke_id, tensor_input_args_map, result) + wrapped = [ctx] + wrapped.extend(list(to_dlpack(value) if value is not None else None for value in result)) + # Inside the returned list, first element is context and the rest + # are DLPack tensors. + unwrapped_values = wrapped + else: + raise wrap_exception( + ORTModuleIOError, + TypeError(f"ORTModule does not support the following model output type {type(result)}."), + ) return tuple(unwrapped_values) except Exception as e: # Flush buffers. Otherwise, calling this from C++ may lose them. @@ -181,12 +302,18 @@ def register_context(result): def call_python_backward_function( - backward_function, requires_grad_flags, tensor_type_flags, is_training_mode, inplace, *args + backward_function: Callable, + requires_grad_flags: List[bool], + tensor_type_flags: List[int], + is_training_mode: bool, + inplace: bool, + kernel_invoke_id: str, + *args, ): """ This function bridges the gap between ORT variables and autograd.Function.backward. - It conducts basic casting from ORT to Pytorch (before calling "backward_function") - and from Pytorch to ORT (after calling "backward_function"). It formats returned + It conducts basic casting from ORT to PyTorch (before calling "backward_function") + and from PyTorch to ORT (after calling "backward_function"). It formats returned outputs, example, dropping None's from backward_function's output list. Args: @@ -215,18 +342,52 @@ def wrap_all_outputs(result): assert all(grad_flag == 0 for grad_flag in requires_grad_flags) # Prepare inputs for calling Python function. - wrapped_args = list( - wrap_as_dlpack_or_not(grad_flag, tensor_flag, inplace, is_training_mode, arg) - for grad_flag, tensor_flag, arg in zip(requires_grad_flags, tensor_type_flags, args) - ) + ctx = args[0] + fw_kernel_invoke_id = ctx.fw_kernel_invoke_id + wrapped_args = [] + for grad_input_index, (grad_flag, tensor_flag, arg) in enumerate( + zip(requires_grad_flags, tensor_type_flags, args) + ): + # If an input is a tensor, it is possible we get a None also when it is optional as grad input. + if tensor_flag: + if arg is None: + if _GlobalOpKernelInfoMap[fw_kernel_invoke_id].materialize_grads: + config = _GlobalOpKernelInfoMap[fw_kernel_invoke_id].materialize_grads_config + # ignore the first input, which is the ctx. + device, dtype, shape = config[grad_input_index - 1] + wrapped_arg = torch.zeros(shape, device=device, dtype=dtype) + else: + wrapped_arg = arg + else: + # Assume it's a DLPack tensor# and convert it to PyTorch tensor. + wrapped_arg = from_dlpack(arg) + + if wrapped_arg is not None: + # Only requires gradient when running under training mode + # and the associated tensor has grad_flag=True (i.e., + # "requires_grad=True" in the original PyTorch script). + wrapped_arg.requires_grad = is_training_mode and grad_flag + wrapped_args.append(wrapped_arg) + else: + # Use non-tensor as is. It's a PyObject*. + wrapped_args.append(arg) # Call Python function. result = backward_function(*wrapped_args) # Extract results as DLPack tensor list. + if isinstance(result, torch.Tensor): + result = [result] + elif isinstance(result, (tuple, list)): + result = list(result) + else: + raise wrap_exception( + ORTModuleIOError, + TypeError(f"ORTModule does not support the following model output type {type(result)}."), + ) + wrapped_returned_args = wrap_all_outputs(result) - ctx = wrapped_args[0] torch_interop_utils.unregister_grad_fn(id(ctx)) return tuple(wrapped_returned_args) diff --git a/orttraining/orttraining/python/training/ortmodule/_custom_gradient_registry.py b/orttraining/orttraining/python/training/ortmodule/_custom_gradient_registry.py index 661629b3bb5c6..156c3e001d88f 100644 --- a/orttraining/orttraining/python/training/ortmodule/_custom_gradient_registry.py +++ b/orttraining/orttraining/python/training/ortmodule/_custom_gradient_registry.py @@ -56,8 +56,8 @@ def _to_gradient_definition(gradient): class CustomGradientRegistry: - _GRADIENTS = {} - _STOP_GRADIENT_EDGES = {} + _GRADIENTS = {} # noqa: RUF012 + _STOP_GRADIENT_EDGES = {} # noqa: RUF012 @classmethod def register(cls, domain, name, attributes, fn): diff --git a/orttraining/orttraining/python/training/ortmodule/_custom_op_symbolic_registry.py b/orttraining/orttraining/python/training/ortmodule/_custom_op_symbolic_registry.py index 07b75008df2da..0dd33d493b0d1 100644 --- a/orttraining/orttraining/python/training/ortmodule/_custom_op_symbolic_registry.py +++ b/orttraining/orttraining/python/training/ortmodule/_custom_op_symbolic_registry.py @@ -3,47 +3,48 @@ # Licensed under the MIT License. # -------------------------------------------------------------------------- -import warnings # noqa: F401 +from typing import Callable import torch import torch.onnx.symbolic_helper as sym_help +from packaging import version from packaging.version import Version from torch.onnx import register_custom_op_symbolic from torch.onnx.symbolic_helper import _get_tensor_dim_size, _get_tensor_sizes, parse_args -from onnxruntime.training import ortmodule - -# Mapping from pytorch scalar type to onnx scalar type. -_CAST_PYTORCH_TO_ONNX = { - "Byte": torch.onnx.TensorProtoDataType.UINT8, - "Char": torch.onnx.TensorProtoDataType.INT8, - "Double": torch.onnx.TensorProtoDataType.DOUBLE, - "Float": torch.onnx.TensorProtoDataType.FLOAT, - "Half": torch.onnx.TensorProtoDataType.FLOAT16, - "Int": torch.onnx.TensorProtoDataType.INT32, - "Long": torch.onnx.TensorProtoDataType.INT64, - "Short": torch.onnx.TensorProtoDataType.INT16, - "Bool": torch.onnx.TensorProtoDataType.BOOL, - "ComplexFloat": torch.onnx.TensorProtoDataType.COMPLEX64, - "ComplexDouble": torch.onnx.TensorProtoDataType.COMPLEX128, - "BFloat16": torch.onnx.TensorProtoDataType.BFLOAT16, - "Undefined": torch.onnx.TensorProtoDataType.UNDEFINED, -} - - -def pytorch_type_to_onnx(scalar_type: str) -> torch.onnx.TensorProtoDataType: - try: - return torch.onnx.JitScalarType.from_name(scalar_type).onnx_type() - except AttributeError: - return _CAST_PYTORCH_TO_ONNX[scalar_type] +from onnxruntime.training.utils import pytorch_dtype_to_onnx +from ._utils import get_runtime_pytorch_version -def wrap_custom_export_function(original_func): - # Starting from PyTorch 1.11, there has been a change to symbolic function signature - # in terms of how additional context is accessed. More info at - # https://github.com/pytorch/pytorch/blob/6b02648479d3615fa3260961e24f38dd0f22da94/torch/onnx/symbolic_helper.py#L48 - # This code can be cleaned up once support for PyTorch version < 1.11 is dropped. - try: + +def wrap_custom_export_function(original_func: Callable) -> Callable: + """This function is to wrap the custom export function to make sure it can be used by different versions of PyTorch. + + Args: + original_func: The original custom export function. + + Note1: + [PyTorch exporter breaking change] Starting from PyTorch 1.11, there has been a change to symbolic function + signature in terms of how additional context is accessed. More info at + https://github.com/pytorch/pytorch/blob/6b02648479d3615fa3260961e24f38dd0f22da94/torch/onnx/symbolic_helper.py#L48 + This code can be cleaned up once support for PyTorch version < 1.11 is dropped. + Note2: + [PyTorch exporter breaking change] Custom export function's first argument is SymbolicContext since 1.11, but + is changed later, and will be deprecated in 1.13 as claimed. So we need to use GraphContext as the first + argument instead. + + """ + runtime_pytorch_version = get_runtime_pytorch_version() + + if runtime_pytorch_version >= version.parse("1.13"): + from torch.onnx._internal import jit_utils + + def _export_with_ctx(graph_context: jit_utils.GraphContext, *args, **kwargs): + return original_func(graph_context, graph_context.original_node, *args, **kwargs) + + return _export_with_ctx + + elif runtime_pytorch_version >= version.parse("1.11"): from torch.onnx import SymbolicContext def _export_with_ctx(ctx: SymbolicContext, graph, *args, **kwargs): @@ -51,7 +52,7 @@ def _export_with_ctx(ctx: SymbolicContext, graph, *args, **kwargs): return original_func(graph, node, *args, **kwargs) return _export_with_ctx - except ImportError: + else: def _export_with_no_ctx(graph, *args, **kwargs): return original_func(graph, None, *args, **kwargs) @@ -60,20 +61,20 @@ def _export_with_no_ctx(graph, *args, **kwargs): class CustomOpSymbolicRegistry: - _SYMBOLICS = {} + _SYMBOLICS = {} # noqa: RUF012 @classmethod def register(cls, name, domain, fn): cls._SYMBOLICS[domain + "::" + name] = fn @classmethod - def register_all(cls): + def register_all(cls, onnx_opset_version): for name, fn in cls._SYMBOLICS.items(): # Symbolic name is in format: domain::name register_custom_op_symbolic( name, fn, - ortmodule._defined_from_envvar("ORTMODULE_ONNX_OPSET_VERSION", ortmodule.ONNX_OPSET_VERSION), + onnx_opset_version, ) @@ -144,7 +145,7 @@ def cross_entropy_loss(g, node, logits, target, weight, reduction, ignore_index, weight_casted, ignore_index, reduction_s=reduction, - output_type_i=pytorch_type_to_onnx(output_type.scalarType()), + output_type_i=pytorch_dtype_to_onnx(output_type.scalarType()), outputs=2, ) output.setType(output_type) @@ -171,10 +172,16 @@ def embedding(g, weight, indices, padding_idx, scale_grad_by_freq, sparse): output = g.op( "org.pytorch.aten::ATen", weight, indices, padding_idx, scale_grad_by_freq, sparse, operator_s="embedding" ) - indices_shape = _get_tensor_sizes(indices) - if indices_shape is not None and hasattr(weight.type(), "with_sizes"): - output_type = weight.type().with_sizes([*indices_shape, _get_tensor_dim_size(weight, 1)]) - output.setType(output_type) + + try: + # Tolerant to the case when sizes of indices are not available or not usable (for example + # when DeepSpeed stage3 enabled, all weights size is (0), this will fail.) + indices_shape = _get_tensor_sizes(indices) + if indices_shape is not None and hasattr(weight.type(), "with_sizes"): + output_type = weight.type().with_sizes([*indices_shape, _get_tensor_dim_size(weight, 1)]) + output.setType(output_type) + except IndexError: + output.setType(weight.type()) return output diff --git a/orttraining/orttraining/python/training/ortmodule/_fallback.py b/orttraining/orttraining/python/training/ortmodule/_fallback.py index cd6464ea01eaf..44f96dcff7fb0 100644 --- a/orttraining/orttraining/python/training/ortmodule/_fallback.py +++ b/orttraining/orttraining/python/training/ortmodule/_fallback.py @@ -4,8 +4,8 @@ # -------------------------------------------------------------------------- import os -import warnings from enum import IntFlag +from logging import Logger from typing import Optional import torch @@ -67,7 +67,7 @@ class _FallbackManager: be raised to the user, terminating execution """ - def __init__(self, pytorch_module: torch.nn.Module, policy: _FallbackPolicy, retry: bool): + def __init__(self, pytorch_module: torch.nn.Module, policy: _FallbackPolicy, retry: bool, logger: Logger): self._original_module = pytorch_module # Read policy from environment variable for testing purposes @@ -103,6 +103,7 @@ def __init__(self, pytorch_module: torch.nn.Module, policy: _FallbackPolicy, ret self.retry = retry self._exception = None self._raised_fallback_exception = False + self._logger = logger def handle_exception( self, exception: Exception, log_level: _logger.LogLevel, override_policy: Optional[_FallbackPolicy] = None @@ -132,19 +133,15 @@ def _set_exception(policy: _FallbackPolicy, exception: Exception, log_level: _lo and type(exception) in self._policy_exception_map[policy.value] ) ): - if log_level <= _logger.LogLevel.INFO: - warnings.warn(f"Fallback for policy {policy.name} is pending.", UserWarning) + self._logger.info(f"Fallback for policy {policy.name} is pending.") # ORTModuleInitException exceptions do not call `fallback()` through `GraphExecutionManager`, # Instead, it fallbacks to PyTorch implicitly through `ORTModule._torch_module = TorchModulePytorch(module)` - if log_level <= _logger.LogLevel.WARNING and policy == _FallbackPolicy.FALLBACK_BAD_INITIALIZATION: - warnings.warn( - ( - f"Fallback to PyTorch due to exception {type(exception)} was triggered. " - "Report this issue with a minimal repro at https://www.github.com/microsoft/onnxruntime. " - f"See details below:\n\n{_utils.get_exception_as_string(exception)}" - ), - UserWarning, + if policy == _FallbackPolicy.FALLBACK_BAD_INITIALIZATION: + self._logger.warning( + f"Fallback to PyTorch due to exception {type(exception)} was triggered. " + "Report this issue with a minimal repro at https://www.github.com/microsoft/onnxruntime. " + f"See details below:\n\n{_utils.get_exception_as_string(exception)}" ) self._exception = exception @@ -177,18 +174,15 @@ def fallback(self, log_level: _logger.LogLevel, *inputs, **kwargs): exception_string = _utils.get_exception_as_string(self._exception) # This warning will not be raised again if retry is not enabled - warnings.warn( - ( - "Fallback to PyTorch due to exception {} was triggered. " - "Report this issue with a minimal repro at https://www.github.com/microsoft/onnxruntime. " - "See details below:\n\n{}".format(exception_type, exception_string) - ), - UserWarning, + self._logger.warning( + "Fallback to PyTorch due to exception {} was triggered. " + "Report this issue with a minimal repro at https://www.github.com/microsoft/onnxruntime. " + "See details below:\n\n{}".format(exception_type, exception_string) ) self._raised_fallback_exception = True - # Pending fallbacks are resetted to enforce retries + # Pending fallbacks are reset to enforce retries if self.retry: self._raised_fallback_exception = False self._exception = None diff --git a/orttraining/orttraining/python/training/ortmodule/_graph_execution_manager.py b/orttraining/orttraining/python/training/ortmodule/_graph_execution_manager.py old mode 100644 new mode 100755 index cbb23be541c17..dfaac5f0fa836 --- a/orttraining/orttraining/python/training/ortmodule/_graph_execution_manager.py +++ b/orttraining/orttraining/python/training/ortmodule/_graph_execution_manager.py @@ -6,11 +6,11 @@ import copy import inspect import io +import logging import os -import warnings from abc import ABC, abstractmethod # noqa: F401 -from enum import IntFlag -from functools import reduce +from hashlib import md5 as hash_fn +from typing import Dict, List, Optional, Tuple import onnx import torch @@ -19,25 +19,29 @@ import onnxruntime from onnxruntime.capi import _pybind_state as C from onnxruntime.tools.symbolic_shape_infer import SymbolicShapeInference -from onnxruntime.training import ortmodule +from onnxruntime.training.utils import ORTModelInputOutputSchemaType, onnx_dtype_to_pytorch +from onnxruntime.training.utils.hooks import configure_ort_compatible_zero_stage3 -from . import _are_deterministic_algorithms_enabled, _io, _logger, _onnx_models, _runtime_inspector, _utils -from ._custom_autograd_function_exporter import _post_process_after_export +from . import _are_deterministic_algorithms_enabled, _io, _logger, _onnx_models, _utils from ._fallback import ( ORTModuleDeviceException, ORTModuleONNXModelException, ORTModuleTorchModelException, _FallbackManager, + _FallbackPolicy, wrap_exception, ) from ._gradient_accumulation_manager import GradientAccumulationManager from ._graph_execution_interface import GraphExecutionInterface -from .debug_options import DebugOptions, LogLevel +from ._io import _FlattenedModule, _InputInfo +from ._runtime_inspector import RuntimeInspector +from ._utils import check_function_has_param, get_rank +from .options import DebugOptions, LogLevel, _RuntimeOptions from .torch_cpp_extensions.cpu.aten_op_executor import load_aten_op_executor_cpp_extension class _RunStateInfo: - def __init__(self, state, output_info): + def __init__(self, state, output_info: List[Tuple[torch.Size, torch.device, torch.dtype]]): """ :param state: State of partial run that contains intermediate tensors needed to resume the run later. :param output_info: Output info. @@ -46,30 +50,14 @@ def __init__(self, state, output_info): self.output_info = output_info -class _SkipCheck(IntFlag): - """Enumeration to specify which checks should be skipped, allowing faster execution""" - - SKIP_CHECK_DISABLED = 1 - SKIP_CHECK_DEVICE = 2 - SKIP_CHECK_BUILD_GRADIENT = 4 - SKIP_CHECK_EXECUTION_AGENT = 8 - - def is_set(self, check): - """Check whether `check` is set on the `_SkipCheck instance - - SKIP_CHECK_DISABLED implies the check will return False - """ - - return not _SkipCheck.is_disabled(self) and check in self - - def is_disabled(self): - """Check whether `_SkipCheck.SKIP_CHECK_DISABLED is set on the `_SkipCheck instance""" - - return _SkipCheck.SKIP_CHECK_DISABLED in self - - class GraphExecutionManager(GraphExecutionInterface): - def __init__(self, module, debug_options: DebugOptions, fallback_manager: _FallbackManager): + def __init__( + self, + module: _FlattenedModule, + debug_options: DebugOptions, + fallback_manager: _FallbackManager, + logger: logging.Logger, + ): """Manages construction and execution of ONNX graphs""" super().__init__(module._original_module) @@ -78,6 +66,11 @@ def __init__(self, module, debug_options: DebugOptions, fallback_manager: _Fallb self._debug_options = debug_options self._fallback_manager = fallback_manager + self._logger = logger + + # Management for ORTModule configuration. + self._runtime_options = _RuntimeOptions(self._logger) + # Original and flattened (transformed) output module self._flattened_module = module @@ -87,49 +80,20 @@ def __init__(self, module, debug_options: DebugOptions, fallback_manager: _Fallb # Model after inference optimization or gradient building. self._graph_builder = None self._graph_info = None - self._graph_initializer_names = None - self._graph_initializer_names_to_train = None - self._graph_initializers = None - - # Update constant ONNX_OPSET_VERSION with env var ORTMODULE_ONNX_OPSET_VERSION - # if defined. - ortmodule.ONNX_OPSET_VERSION = ortmodule._defined_from_envvar( - "ORTMODULE_ONNX_OPSET_VERSION", ortmodule.ONNX_OPSET_VERSION, warn=True - ) + self._graph_initializer_names = set() + self._graph_initializer_names_to_train = set() + self._graph_initializers: List[torch.nn.parameter.Parameter] = [] # TrainingAgent or InferenceAgent self._execution_agent = None - # indicators of some logic have been executed previously and thus could be skipped for faster training - # default is enabled, if not defined in os env - self._skip_check = _SkipCheck( - _SkipCheck.SKIP_CHECK_DEVICE | _SkipCheck.SKIP_CHECK_BUILD_GRADIENT | _SkipCheck.SKIP_CHECK_EXECUTION_AGENT - ) - if os.getenv("ORTMODULE_SKIPCHECK_POLICY") is not None: - self._skip_check = reduce( - lambda x, y: x | y, - [_SkipCheck[name] for name in _utils.parse_os_env_skip_check_flags("ORTMODULE_SKIPCHECK_POLICY")], - ) self._first_skip_check_warning = True - # Inspect embedding input index sparsity. - self._rt_inspector = _runtime_inspector.RuntimeInspector() - - # Graph transformer config - # Specify cast propagation strategy. Currently, three strategies are available, NONE, INSERT-AND-REDUCE and FLOOD-FILL - # The default is FLOOD_FILL, expand FP16 computation regions in the graph using allowed opcodes for the given level. - self._propagate_cast_ops_strategy = C.PropagateCastOpsStrategy.FLOOD_FILL - # Optimize by moving Cast operations if propagate_cast_ops_level is non-negative. - # - If the _propagate_cast_ops_level is set to zero, then the transformation considers only the opcodes specified by _propagate_cast_ops_allow - # as "FP16 safe", to insert/(re)move cast operations before/after to perform such operations in reduced (16-bit) precision. - # - If propagate_cast_ops_level is positive, 1 or 2, then in addition to opcode codes specified by propagate_cast_ops_allow, use onnxruntime - # predetermined list of opcodes considered safe to move before/after the cast operation. - # - Onnxruntime Level 1 predetermined "FP16 safe" opcodes include only opcodes that do not perform any computation such as Transpose, Split, Reshape, etc., - # or the computation is actually in Float such as GeLU, etc. - # whereas Level 2 predetermined "FP16 safe" opcodes include opcodes that perform computation using contrib ops, Dropout, LayerNormalization, etc. - self._propagate_cast_ops_level = 1 - # List of opcodes to be considered safe to move before/after the cast operation if propagate_cast_ops_level is zero. - self._propagate_cast_ops_allow = [] + # Inspector for runtime information, for example input data, memory usage, etc. + self._runtime_inspector = RuntimeInspector(self._logger) + + # Tracker for ORTModule model export, session creation overhead. + self.time_tracker = _logger.TimeTracker() # Value can be either torch.onnx.TrainingMode.TRAINING or torch.onnx.TrainingMode.EVAL # To be instantiated in the concrete implementation of GraphExecutionManager @@ -139,57 +103,28 @@ def __init__(self, module, debug_options: DebugOptions, fallback_manager: _Fallb # It cannot overlap with required/immutable arguments (validated in runtime) self._export_extra_kwargs = {} - # Related to training graph shape inference - self._current_input_shape = None - # default execution order is priority-based for both dynamic/static shape input for now - # if we observe the benefit of static shape, we can expose this flag to the user - self._use_static_shape = False + # Input and output infos (including schema) for exported model. + self._input_info: Optional[_InputInfo] = None + self._module_output_schema: Optional[ORTModelInputOutputSchemaType] = None - # flag to enable symbolic shape inference for dynamic shape inputs to improve performance - self._run_symbolic_shape_infer = True + # Device where the model is placed. + self._device: Optional[torch.device] = _utils.get_device_from_module(module) - # PyTorch custom Autograd function support - from ._custom_autograd_function import custom_autograd_function_enabler - - self._enable_custom_autograd_function = custom_autograd_function_enabler.state - - self._input_info = None - self._module_output_schema = None - self._device = _utils.get_device_from_module(module) - - self._module_parameters = list(inspect.signature(self._original_module.forward).parameters.values()) + # Forward function input parameters of the original module. + self._module_parameters: List[inspect.Parameter] = list( + inspect.signature(self._original_module.forward).parameters.values() + ) # TODO: remove after PyTorch ONNX exporter supports VAR_KEYWORD parameters. for input_parameter in self._module_parameters: if input_parameter.kind == inspect.Parameter.VAR_KEYWORD: - if self._debug_options.logging.log_level <= LogLevel.WARNING: - warnings.warn( - "The model's forward method has **kwargs parameter which has EXPERIMENTAL support!", UserWarning - ) + self._logger.info("The model's forward method has **kwargs parameter which has EXPERIMENTAL support!") self.is_rocm_pytorch = bool(torch.version.hip is not None and ROCM_HOME is not None) - self._use_external_gpu_allocator = True - # assign self._torch_alloc and self._torch_free if self._use_external_gpu_allocator is True - self._get_torch_gpu_allocator_function_addresses() - # WIP feature to enable caching in Gradient accumulation scenario. - self._enable_grad_acc_optimization = False self._gradient_accumulation_manager = GradientAccumulationManager() - # Memory-aware gradient builder. - self._use_memory_efficient_gradient = False - - # Enable compute optimizer by default. Allowed to be disabled via an environment variable for - # convergence parity investigation. - self._enable_compute_optimizer = ( - ortmodule._defined_from_envvar("ORTMODULE_ENABLE_COMPUTE_OPTIMIZER", 1, warn=True) == 1 - ) - self._enable_label_sparsity_optimization = ( - self._enable_compute_optimizer - and ortmodule._defined_from_envvar("ORTMODULE_ENABLE_LABEL_SPARSITY_OPT", 0, warn=True) == 1 - ) - # Flag to re-export the model due to attribute change on the original module. # Re-export will be avoided if _skip_check is enabled. self._original_model_has_changed = False @@ -197,8 +132,25 @@ def __init__(self, module, debug_options: DebugOptions, fallback_manager: _Fallb # Load ATen operator executor extension. load_aten_op_executor_cpp_extension() + # Assign self._torch_alloc and self._torch_free if self._use_external_gpu_allocator is True + self._get_torch_gpu_allocator_function_addresses() + + if self._runtime_options.enable_triton: + from onnxruntime.training.ort_triton import register_triton_op_executor + + register_triton_op_executor() + + self._zero_stage3_param_map = {} + if self._runtime_options.enable_zero_stage3_support: + # Cannot toggle feature enabling/disabling after the first time enabled. + from onnxruntime.training.utils.hooks._zero_offload_subscriber import _get_all_zero_stage3_params + + self._zero_stage3_param_map = _get_all_zero_stage3_params(self._flattened_module) + + configure_ort_compatible_zero_stage3(debug=False, stats_output_dir="ort_output", stats_overwrite=True) + def _get_torch_gpu_allocator_function_addresses(self): - if self._use_external_gpu_allocator and torch.cuda.is_available(): + if self._runtime_options.use_external_gpu_allocator and torch.cuda.is_available(): # CPP extension to get torch GPU allocator's alloc and free function addresses from onnxruntime.training.ortmodule.torch_cpp_extensions import torch_gpu_allocator @@ -225,26 +177,6 @@ def _validate_module_type(self, module): ), ) - @staticmethod - def execution_session_run_forward(execution_session, onnx_model, device, *inputs): - """Runs the forward pass on `execution_session` with given `onnx_model`, `device` and `inputs` - - This is a helper that can be called by the actual `GraphExecutionManager.forward` method - - Args: - execution_session (InferenceAgent or InferenceAgent): Agent which runs either inference or train - onnx_model (onnx.ModelProto): ONNX model - device (torch.device): PyTorch device - inputs: (torch.Tensor or a container of): User input - - Returns: - Returns a tuple (user_outputs, run_info): - user_outputs: The model output (either torch.Tensor or a container of torch.Tensor) - run_info: A _RunStateInfo which contains extra information about the execution of the graph - """ - - raise NotImplementedError - @abstractmethod def forward(self): """Executes the forward method for ORTModule @@ -254,11 +186,11 @@ def forward(self): All other methods are internal""" pass - def _build_graph(self): - if self._use_static_shape: - self._graph_builder.build(self._input_info.shape) + def _build_graph(self, config): + if self._runtime_options.use_static_shape: + self._graph_builder.build(config, self._input_info.shape) else: - self._graph_builder.build() + self._graph_builder.build(config) self._graph_info = self._graph_builder.get_graph_info() @@ -266,10 +198,7 @@ def _get_session_config(self): """Creates and returns the session configuration to be used for the ExecutionAgent""" if _are_deterministic_algorithms_enabled(): - if self._debug_options.logging.log_level <= _logger.LogLevel.INFO: - warnings.warn( - "ORTModule's determinism will be enabled because PyTorch's determinism is enabled.", UserWarning - ) + self._logger.info("ORTModule's determinism will be enabled because PyTorch's determinism is enabled.") providers = None provider_options = None @@ -280,14 +209,19 @@ def _get_session_config(self): provider_option_map = {"device_id": str(self._device.index)} if not self.is_rocm_pytorch: # Set Conv algo search mode to HEURISTIC by default, which is the same as PyTorch's default setting. - conv_algo_search = ortmodule._defined_from_envvar("ORTMODULE_CONV_ALGO_SEARCH", "HEURISTIC", warn=True) - if conv_algo_search not in ["HEURISTIC", "EXHAUSTIVE"]: - warnings.warn("Invalid value of env CONV_ALGO_SEARCH. Must be HEURISTIC or EXHAUSTIVE.") - conv_algo_search = "HEURISTIC" - provider_option_map["cudnn_conv_algo_search"] = conv_algo_search + provider_option_map["cudnn_conv_algo_search"] = self._runtime_options.conv_algo_search provider_option_map["cudnn_conv_use_max_workspace"] = "1" provider_option_map["cudnn_conv1d_pad_to_nc1d"] = "1" - if self._use_external_gpu_allocator: + if self._runtime_options.enable_tuning: + provider_option_map["tunable_op_enable"] = "1" + provider_option_map["tunable_op_tuning_enable"] = "1" + if self._runtime_options.max_tuning_duration_ms: + provider_option_map["tunable_op_max_tuning_duration_ms"] = str( + self._runtime_options.max_tuning_duration_ms + ) + elif self._runtime_options.tuning_results_path: + provider_option_map["tunable_op_enable"] = "1" + if self._runtime_options.use_external_gpu_allocator: provider_option_map["gpu_external_alloc"] = str(self._torch_alloc) provider_option_map["gpu_external_free"] = str(self._torch_free) provider_option_map["gpu_external_empty_cache"] = str(self._torch_empty_cache) @@ -309,11 +243,13 @@ def _get_session_config(self): session_options.execution_order = onnxruntime.ExecutionOrder.PRIORITY_BASED # 0:Verbose, 1:Info, 2:Warning. 3:Error, 4:Fatal. Default is 2. session_options.log_severity_level = int(self._debug_options.logging.log_level) - # Disable memory alleviation by default. Allow user to enable it via environment variable. - alleviation_config = ortmodule._defined_from_envvar("ORTMODULE_MEMORY_OPT_CONFIG", "", warn=True) - probe_level = ortmodule._defined_from_envvar("ORTMODULE_MEMORY_OPT_PROBE_RECOMPUTE_LEVEL", "1", warn=True) - session_options.add_session_config_entry("optimization.enable_memory_optimizer", alleviation_config) - session_options.add_session_config_entry("optimization.enable_memory_probe_recompute_level", probe_level) + + session_options.add_session_config_entry( + "optimization.enable_memory_optimizer", self._runtime_options.memory_optimizer_config + ) + session_options.add_session_config_entry( + "optimization.enable_memory_probe_recompute_level", self._runtime_options.probe_level + ) # Disable weight prepacking session_options.add_session_config_entry("session.disable_prepacking", "1") @@ -327,7 +263,9 @@ def _get_session_config(self): return session_options, providers, provider_options - def _export_model(self, *inputs, **kwargs): + @_logger.TrackTime(_logger.ORTModuleInitPhase.EXPORT) + @_logger.SuppressLogs(_logger.ORTModuleInitPhase.EXPORT, is_ort_filter=False) + def _export_model(self, *inputs, **kwargs) -> bool: # 1. Set the self._device from the user module # 2. Verify input schema matches the schema used on the previous model export # 3. Export the user model under self._export_training_flag mode @@ -343,7 +281,7 @@ def _export_model(self, *inputs, **kwargs): # e.g., some sympy functions in symbolic_shape_infer will change Python's random state. random_states = _utils.get_random_states() - schema = _io._extract_schema({"args": copy.copy(inputs), "kwargs": copy.copy(kwargs)}) + schema = _io._extract_schema({"args": copy.copy(inputs), "kwargs": copy.copy(kwargs)}, self._device) if ( self._onnx_models.exported_model and schema == self._input_info.schema @@ -351,9 +289,12 @@ def _export_model(self, *inputs, **kwargs): ): # All required models have already been exported previously return False - self._set_device_from_module(inputs, kwargs) - self._onnx_models.exported_model = self._get_exported_model(schema, *inputs, **kwargs) + + from onnxruntime.training.utils.hooks._subscriber_manager import no_increase_global_step + + with no_increase_global_step(): + self._onnx_models.exported_model = self._get_exported_model(schema, *inputs, **kwargs) if self._debug_options.save_onnx_models.save: self._onnx_models.save_exported_model( self._debug_options.save_onnx_models.path, @@ -361,7 +302,7 @@ def _export_model(self, *inputs, **kwargs): self._export_mode, ) - if self._run_symbolic_shape_infer: + if self._runtime_options.run_symbolic_shape_infer: self._onnx_models.exported_model = SymbolicShapeInference.infer_shapes( self._onnx_models.exported_model, auto_merge=True, guess_output_rank=True ) @@ -371,12 +312,19 @@ def _export_model(self, *inputs, **kwargs): return True - def _get_exported_model(self, input_schema, *inputs, **kwargs): - """Exports PyTorch `self._flattened_module` to ONNX for inferencing or training, using `*inputs` and `**kwargs` as input + def _get_exported_model(self, input_schema: ORTModelInputOutputSchemaType, *inputs, **kwargs) -> onnx.ModelProto: + """Exports PyTorch `self._flattened_module` to ONNX for inferencing or training, + using `*inputs` and `**kwargs` as input TODO: How to support dynamic axes? Dimensions are determined by samples """ + # VERBOSE -> FULL export verbose log + FULL torch other logs from stdout and stderr (C++ backend) + # INFO -> FULL export verbose log + FILTERED torch other logs from stdout and stderr (C++ backend) + # WARNING/ERROR -> [Rank 0] NO export verbose log + FILTERED torch other logs from stdout and stderr (C++ backend) + # Be noted: rank 0 log only is controlled by logger configured in _logger.py + torch_exporter_verbose_log = self._debug_options.logging.log_level <= LogLevel.INFO + # Setup dynamic axes for onnx model self._input_info = _io.parse_inputs_for_onnx_export(self._module_parameters, None, input_schema, inputs, kwargs) ( @@ -384,13 +332,29 @@ def _get_exported_model(self, input_schema, *inputs, **kwargs): output_dynamic_axes, self._module_output_schema, ) = _io.parse_outputs_for_onnx_export_and_extract_schema( - self._original_module, inputs, kwargs, self._debug_options.logging.log_level + self._original_module, inputs, kwargs, self._logger, self._device ) self._input_info.dynamic_axes.update(output_dynamic_axes) # FlattenedModule needs _InputInfo to expand user input from *args to *args + **kwargs self._flattened_module._input_info = self._input_info + self._logger.info("Exporting the PyTorch model to ONNX...") + + # Leverage cached model if available + cache_dir = self._runtime_options.ortmodule_cache_dir + if cache_dir: + filename = os.path.join( + cache_dir, f"{hash_fn(str(self._flattened_module).encode()).hexdigest()}_{get_rank()}.onnx" + ) + if os.path.exists(cache_dir) and os.path.isfile(filename): + self._logger.info( + f"Cached model detected! Cached model will be used to save export and initialization time." + f"If you want the model to be re-exported then DELETE {filename}." + ) + exported_model = onnx.load(filename) + return exported_model + # Export torch.nn.Module to ONNX f = io.BytesIO() @@ -406,22 +370,33 @@ def _get_exported_model(self, input_schema, *inputs, **kwargs): assert self._export_mode is not None, "Please use a concrete instance of ExecutionManager" try: - with torch.no_grad(), _logger.suppress_os_stream_output(log_level=self._debug_options.logging.log_level): + with torch.no_grad(): required_export_kwargs = { "input_names": self._input_info.names, "output_names": output_names, - "opset_version": ortmodule.ONNX_OPSET_VERSION, + "opset_version": self._runtime_options.onnx_opset_version, "do_constant_folding": False, "training": self._export_mode, "dynamic_axes": self._input_info.dynamic_axes, - "verbose": self._debug_options.logging.log_level < LogLevel.WARNING, + "verbose": torch_exporter_verbose_log, "export_params": False, "keep_initializers_as_inputs": True, } + + if check_function_has_param(torch.onnx.export, "autograd_inlining"): + # From some PyTorch version, autograd_inlining is a valid argument. + # We allow it to be True if custom autograd function is disabled (where autograd.Function + # anyway is not supported in ONNX until it can be inlined). + required_export_kwargs[ + "autograd_inlining" + ] = not self._runtime_options.enable_custom_autograd_function + invalid_args = self._export_extra_kwargs.keys() & required_export_kwargs.keys() - assert ( - len(invalid_args) == 0 - ), f"The following PyTorch exporter arguments cannot be specified: '{invalid_args}'." + + if len(invalid_args) != 0: + error_msg = f"The following PyTorch exporter arguments cannot be specified: '{invalid_args}'." + raise RuntimeError(error_msg) + torch.onnx.export( self._flattened_module, sample_inputs_as_tuple, @@ -439,9 +414,34 @@ def _get_exported_model(self, input_schema, *inputs, **kwargs): ) exported_model = onnx.load_model_from_string(f.getvalue()) - exported_model = _post_process_after_export( - exported_model, self._enable_custom_autograd_function, self._debug_options.logging.log_level - ) + if self._runtime_options.enable_custom_autograd_function: + from ._custom_autograd_function_exporter import post_process_enabling_autograd_function + + exported_model = post_process_enabling_autograd_function(exported_model) + + if self._runtime_options.enable_zero_stage3_support: + from ._zero_stage3_compatibility import post_processing_enable_zero_stage3_compat + + exported_model = post_processing_enable_zero_stage3_compat( + exported_model, + self._zero_stage3_param_map, + [name for name, _ in self._flattened_module.named_parameters()], + ) + + # Cannot append pull weight trigger name to input names as following, otherwise, the later check ( + # https://github.com/microsoft/onnxruntime/blob/068300d97eb25e5b52324e7af54a45ed1fa6a4c3/orttraining/orttraining/python/training/ortmodule/_training_manager.py#L466C18-L466C18) + # find input info mismatch, will re-initialize the graph builder. + # self._input_info.require_grad_names.append(STAGE3_PULL_WEIGHT_TRIGGER_NAME) + + # Cache model for future runs + if cache_dir: + if not os.path.exists(cache_dir): + os.makedirs(cache_dir, exist_ok=True) + filename = os.path.join( + cache_dir, f"{hash_fn(str(self._flattened_module).encode()).hexdigest()}_{get_rank()}.onnx" + ) + self._logger.info(f"Caching model for future runs to {filename}.") + onnx.save(exported_model, filename) return exported_model @@ -456,16 +456,26 @@ def _set_device_from_module(self, inputs, kwargs): ORTModuleDeviceException, RuntimeError("A device must be specified in the model or inputs!") ) - def _get_graph_transformer_config(self): + def _get_graph_transformer_config(self) -> C.TrainingGraphTransformerConfiguration: graph_transformer_config = C.TrainingGraphTransformerConfiguration() graph_transformer_config.propagate_cast_ops_config = C.PropagateCastOpsConfiguration() - graph_transformer_config.propagate_cast_ops_config.level = self._propagate_cast_ops_level - graph_transformer_config.propagate_cast_ops_config.allow = self._propagate_cast_ops_allow - graph_transformer_config.propagate_cast_ops_config.strategy = self._propagate_cast_ops_strategy - graph_transformer_config.enable_compute_optimizer = self._enable_compute_optimizer - graph_transformer_config.enable_label_sparsity_optimization = self._enable_label_sparsity_optimization + graph_transformer_config.propagate_cast_ops_config.level = self._runtime_options.propagate_cast_ops_level + graph_transformer_config.propagate_cast_ops_config.allow = self._runtime_options.propagate_cast_ops_allow + graph_transformer_config.propagate_cast_ops_config.strategy = self._runtime_options.propagate_cast_ops_strategy + graph_transformer_config.enable_compute_optimizer = self._runtime_options.enable_compute_optimizer + + if self._debug_options.save_onnx_models.save: + graph_transformer_config.optimized_pre_grad_filepath = os.path.join( + self._debug_options.save_onnx_models.path, + _onnx_models._get_onnx_file_name( + self._debug_options.save_onnx_models.name_prefix, "optimized_pre_grad", self._export_mode + ), + ) + return graph_transformer_config + @_logger.TrackTime(_logger.ORTModuleInitPhase.GRAPH_BUILDER_INIT) + @_logger.SuppressLogs(_logger.ORTModuleInitPhase.GRAPH_BUILDER_INIT) def _initialize_graph_builder(self): """Creates a new OrtModuleGraphBuilder, initializes it and saves it to self._graph_builder""" @@ -487,14 +497,20 @@ def _initialize_graph_builder(self): grad_builder_config = C.OrtModuleGraphBuilderConfiguration() grad_builder_config.initializer_names = initializer_names grad_builder_config.initializer_names_to_train = initializer_names_to_train - grad_builder_config.input_names_require_grad = self._input_info.require_grad_names + + input_names_require_grad = self._input_info.require_grad_names + if self._runtime_options.enable_zero_stage3_support: + from ._zero_stage3_compatibility import STAGE3_PULL_WEIGHT_TRIGGER_NAME + + # Add stage3 pull weight trigger name to require_grad_names, so that it will be included in the gradient graph. + input_names_require_grad.append(STAGE3_PULL_WEIGHT_TRIGGER_NAME) + grad_builder_config.input_names_require_grad = input_names_require_grad grad_builder_config.build_gradient_graph = self._export_mode == torch.onnx.TrainingMode.TRAINING - grad_builder_config.graph_transformer_config = self._get_graph_transformer_config() - grad_builder_config.enable_caching = self._enable_grad_acc_optimization + grad_builder_config.enable_caching = self._runtime_options.enable_grad_acc_optimization grad_builder_config.loglevel = _logger.ortmodule_loglevel_to_onnxruntime_c_loglevel( self._debug_options.logging.log_level ) - grad_builder_config.use_memory_efficient_gradient = self._use_memory_efficient_gradient + grad_builder_config.use_memory_efficient_gradient = self._runtime_options.use_memory_efficient_gradient self._graph_builder = C.OrtModuleGraphBuilder() # It is assumed here that the order and names of the inputs and outputs are not modified by the backend in any way @@ -537,3 +553,189 @@ def __setstate__(self, state): self.__dict__.update(state) _utils.reinitialize_graph_execution_manager(self) + + @_logger.TrackTime(_logger.ORTModuleInitPhase.DETECTION) + def _enable_conditional_optimizations( + self, graph_transformer_config: C.TrainingGraphTransformerConfiguration, inputs: Tuple, kwargs: Dict + ): + """ + Based on runtime inspection, enable conditional optimizations if applicable. + + Input sparsity-based optimization workflows: + 1. Input density observer is enabled if the sparse optimizer is ON or user wants to print input density. + 2. Input density observer inspects input tensors and returns sparsity results. + 3. If label or embedding input sparsity is found in sparsity results, graph transformer config is updated to + enable sparsity-based optimization. + + """ + + # Enable data sparsity inspection if sparse optimizer is ON or user wants to print input density. + if self._runtime_options.enable_sparse_optimizer or self._runtime_options.print_input_density: + self._runtime_inspector.enable_input_inspector( + self._onnx_models.exported_model, self._graph_builder.get_graph_info().user_input_names + ) + + if self._runtime_options.enable_sparse_optimizer: + detected_device = _utils.get_device_from_module(self._original_module) or _utils.get_device_from_inputs( + inputs, kwargs + ) + + if self._runtime_options.enable_zero_stage3_support: + self._append_pull_weight_trigger_as_input(kwargs, detected_device) + + _, embed_sparsity_results, label_sparsity_results = _io._combine_input_buffers_initializers( + self._graph_initializers, + self._graph_builder.get_graph_info().user_input_names, + self._input_info, + self._flattened_module.named_buffers(), + inputs, + kwargs, + detected_device, + self._runtime_inspector, + self._zero_stage3_param_map, + ) + + # Enable sparsity-based optimization when applicable. + if len(label_sparsity_results) > 0: + graph_transformer_config.sparse_label_input_names = list(label_sparsity_results.keys()) + self._logger.info("Label sparsity-based optimization is ON for %s", label_sparsity_results) + self._runtime_options.label_sparsity_ratio = ",".join( + [f"{k}:{v:.0f}%" for k, v in label_sparsity_results.items()] + ) + + if self._runtime_options.enable_embedding_sparse_optimizer and len(embed_sparsity_results) > 0: + graph_transformer_config.sparse_embedding_input_names = list(embed_sparsity_results.keys()) + self._logger.info("Embedding sparsity-based optimization is ON for %s", embed_sparsity_results) + self._runtime_options.embed_sparsity_ratio = ",".join( + [f"{k}:{v:.0f}%" for k, v in embed_sparsity_results.items()] + ) + + # If users don't want to print input density, disable the input density observer to avoid overhead + # when looping through inputs during training. + if not self._runtime_options.print_input_density: + self._runtime_inspector.disable_input_inspector() + + if self._runtime_options.print_memory_stat: + self._runtime_inspector.enable_memory_inspector(self._original_module) + + def _append_pull_weight_trigger_as_input(self, kwargs: Dict, device: torch.device): + from ._zero_stage3_compatibility import ( + STAGE3_PULL_WEIGHT_TRIGGER_NAME, + STAGE3_PULL_WEIGHT_TRIGGER_OUTPUT_DTYPE, + STAGE3_PULL_WEIGHT_TRIGGER_OUTPUT_SHAPE, + ) + + kwargs[STAGE3_PULL_WEIGHT_TRIGGER_NAME] = torch.zeros( + STAGE3_PULL_WEIGHT_TRIGGER_OUTPUT_SHAPE, + dtype=onnx_dtype_to_pytorch(STAGE3_PULL_WEIGHT_TRIGGER_OUTPUT_DTYPE), + device=device, + ).requires_grad_() + + return kwargs + + def _log_feature_stats(self): + if get_rank() != 0: + return + + feature_map: List[Tuple[str, bool, str]] = [ + ("ATen Executor", True, "Dispatch ATen operators to ORT's ATen executor"), + ( + "Cast Propagation", + self._runtime_options.propagate_cast_ops_level > 0, + f"Level {self._runtime_options.propagate_cast_ops_level} enabled", + ), + ( + "Custom Function", + self._runtime_options.enable_custom_autograd_function, + "Support custom torch.autograd.Function export and execution", + ), + ( + "Memory Optimizer", + len(self._runtime_options.memory_optimizer_config) > 0, + "Enable with env ORTMODULE_MEMORY_OPT_CONFIG=", + ), + ] + + # Add compute optimizer + feature_map.extend( + [ + ( + "Compute Optimizer", + self._runtime_options.enable_compute_optimizer, + "Enable/Disable with env ORTMODULE_ENABLE_COMPUTE_OPTIMIZER=1/0", + ), + ( + " -FLOPReduction", + self._runtime_options.enable_compute_optimizer, + "Reduce FLOPs by upstreaming shrinking-sized ops", + ), + ] + ) + + if self._runtime_options.enable_compute_optimizer: + if len(self._runtime_options.label_sparsity_ratio) > 0: + feature_map.append( + (" -LabelSparsityOpt", True, f"Input density: {self._runtime_options.label_sparsity_ratio}") + ) + + if len(self._runtime_options.embed_sparsity_ratio) > 0: + feature_map.append( + (" -EmbedSparsityOpt", True, f"Input density: {self._runtime_options.embed_sparsity_ratio}") + ) + + # Add fallback + feature_map.append( + ( + "Auto Fallback", + self._runtime_options.fallback_policy is not _FallbackPolicy.FALLBACK_DISABLE, + "Fallback to PyTorch when encountering unsupported ops", + ) + ) + + if self._runtime_options.enable_triton: + feature_map.append( + ( + "TritonOp Enabled", + True, + "ORT will switch to Triton for executing some ops to further accelerate training.", + ) + ) + + if self._runtime_options.enable_tuning: + desc = "Enable tunning Ops online" + if self._runtime_options.tuning_results_path: + desc += f", save tuning results to {self._runtime_options.tuning_results_path}" + feature_map.append(("Online Op Tuning", True, desc)) + elif self._runtime_options.tuning_results_path: + feature_map.append( + ( + "Offline Op Tuning", + True, + f"Use offline tuning results from {self._runtime_options.tuning_results_path}", + ) + ) + + feature_map.append( + ( + "ZeRO Stage3 Support", + self._runtime_options.enable_zero_stage3_support, + "Enable/Disable with env ORTMODULE_ENABLE_ZERO_STAGE3=1/0", + ) + ) + + mode = "training" if self._export_mode == torch.onnx.TrainingMode.TRAINING else "inference" + mode = f"{_logger.LogColor.UNDERLINE}{mode}{_logger.LogColor.ENDC}" + + stat = f"\n\n{_logger.LogColor.HEADER}***** ONNX Runtime Training (ORTModule) is accelerating your model *****{_logger.LogColor.ENDC}\n\n" + stat += f"ORTModule is enabled with following features ON/OFF for [{mode}] mode:\n\n" + for feature_tuple in feature_map: + switch_str = "ON" if feature_tuple[1] else "OFF" + stat += f"{feature_tuple[0]:<20}:\t{switch_str:<10}:\t{feature_tuple[2]:<80}\n" + + # Collect ORTModule overheads for different phases. + stat += f"\n{self.time_tracker.to_string(self._debug_options.logging.log_level < LogLevel.WARNING)}\n" + + stat += f"Versions: ONNX Runtime - {onnxruntime.__version__}, ONNX - {onnx.__version__}\n\n" + stat += f"{_logger.LogColor.HEADER}************************************************************************{_logger.LogColor.ENDC}\n\n" + + self._logger.warning(stat) diff --git a/orttraining/orttraining/python/training/ortmodule/_graph_execution_manager_factory.py b/orttraining/orttraining/python/training/ortmodule/_graph_execution_manager_factory.py index 95849a3335fe2..104cc0a894eed 100644 --- a/orttraining/orttraining/python/training/ortmodule/_graph_execution_manager_factory.py +++ b/orttraining/orttraining/python/training/ortmodule/_graph_execution_manager_factory.py @@ -3,18 +3,28 @@ # Licensed under the MIT License. # -------------------------------------------------------------------------- +from logging import Logger +from typing import Union + from ._fallback import _FallbackManager from ._inference_manager import InferenceManager +from ._io import _FlattenedModule from ._training_manager import TrainingManager -from .debug_options import DebugOptions +from .options import DebugOptions class GraphExecutionManagerFactory: - def __init__(self, module, debug_options: DebugOptions, fallback_manager: _FallbackManager): - self._training_manager = TrainingManager(module, debug_options, fallback_manager) - self._inference_manager = InferenceManager(module, debug_options, fallback_manager) + def __init__( + self, + module: _FlattenedModule, + debug_options: DebugOptions, + fallback_manager: _FallbackManager, + logger: Logger, + ): + self._training_manager = TrainingManager(module, debug_options, fallback_manager, logger) + self._inference_manager = InferenceManager(module, debug_options, fallback_manager, logger) - def __call__(self, is_training): + def __call__(self, is_training) -> Union[InferenceManager, TrainingManager]: if is_training: return self._training_manager else: diff --git a/orttraining/orttraining/python/training/ortmodule/_inference_manager.py b/orttraining/orttraining/python/training/ortmodule/_inference_manager.py index f47318b70de3f..8d8be81c549d1 100644 --- a/orttraining/orttraining/python/training/ortmodule/_inference_manager.py +++ b/orttraining/orttraining/python/training/ortmodule/_inference_manager.py @@ -3,34 +3,54 @@ # Licensed under the MIT License. # -------------------------------------------------------------------------- -import warnings +from logging import Logger +from typing import Tuple import onnx import torch from onnxruntime.capi import _pybind_state as C -from . import _are_deterministic_algorithms_enabled, _io, _logger, _use_deterministic_algorithms, _utils +from . import _are_deterministic_algorithms_enabled, _io, _use_deterministic_algorithms, _utils from ._execution_agent import InferenceAgent from ._fallback import ORTModuleFallbackException, _FallbackManager, _FallbackPolicy -from ._graph_execution_manager import GraphExecutionManager, _RunStateInfo, _SkipCheck -from .debug_options import DebugOptions +from ._graph_execution_manager import GraphExecutionManager, _RunStateInfo +from ._io import unflatten_user_output +from ._logger import ORTModuleInitPhase, SuppressLogs, TrackTime +from ._utils import save_tuning_results, set_tuning_results +from .options import DebugOptions, _SkipCheck class InferenceManager(GraphExecutionManager): """Concrete instance of GraphExecutionManager that is able to manage the inference model - InferenceManager is resposible for building and running the forward graph of the inference model + InferenceManager is responsible for building and running the forward graph of the inference model """ - def __init__(self, model, debug_options: DebugOptions, fallback_manager: _FallbackManager): - super().__init__(model, debug_options, fallback_manager) + def __init__(self, model, debug_options: DebugOptions, fallback_manager: _FallbackManager, logger: Logger): + super().__init__(model, debug_options, fallback_manager, logger) self._export_mode = torch.onnx.TrainingMode.EVAL @staticmethod - def execution_session_run_forward(execution_session, onnx_model, device, *inputs): - """Runs the forward graph on execution_session with given model inputs and device""" - + def execution_session_run_forward( + execution_session, + onnx_model: onnx.ModelProto, + device: torch.device, + *inputs, + ) -> Tuple[Tuple[torch.Tensor, ...], _RunStateInfo]: + """Runs the forward pass on `execution_session` with given `onnx_model`, `device` and `inputs` + + Args: + execution_session InferenceAgent: Agent which runs inference + onnx_model (onnx.ModelProto): ONNX model + device (torch.device): PyTorch device + inputs: (torch.Tensor or a container of): User inputs passed from ORTModule.forward(). + + Returns: + Returns a tuple (user_outputs, run_info): + user_outputs: The model output (either torch.Tensor or a container of torch.Tensor) + run_info: A _RunStateInfo which contains extra information about the execution of the graph + """ # TODO: Try to reuse the output buffers as some of the output tensors are same sizes, # especially the backward graph outputs. # REVIEW(codemzs): Consolidate Training Agent with InferenceAgent on C++ side to not @@ -58,6 +78,14 @@ def forward(self, *inputs, **kwargs): ONNX model is exported the first time this method is executed. Next, we build an optimized inference graph with module_graph_builder. Finally, we instantiate the ONNX Runtime InferenceSession through the InferenceAgent. + + The call stack is as follows: + ORTModule.forward(*inputs, **kwargs) -> + ORTModule._torch_module.forward(*inputs, **kwargs) where _torch_module is a TorchModuleORT instance -> + ORTModule._torch_module._execution_manager(is_training()).forward(*inputs, **kwargs) where: + TorchModuleORT._execution_manager(true) is a TrainingManager instance; + and TorchModuleORT._execution_manager(false) is an InferenceManager instance. + """ # Fallback to PyTorch due to failures *external* to forward(), @@ -67,41 +95,47 @@ def forward(self, *inputs, **kwargs): try: # Issue at most one warning message about fast path - if ( - self._first_skip_check_warning is True - and self._skip_check.is_disabled() is False - and self._debug_options.logging.log_level <= _logger.LogLevel.WARNING - ): + if self._first_skip_check_warning is True and self._runtime_options.skip_check.is_disabled() is False: self._first_skip_check_warning = False - warnings.warn( - f"Fast path enabled - skipping checks." - f"rebuild gradient graph: {self._skip_check.is_set(_SkipCheck.SKIP_CHECK_BUILD_GRADIENT)}," - f"execution agent recreation: {self._skip_check.is_set(_SkipCheck.SKIP_CHECK_EXECUTION_AGENT)}," - f"device check: {self._skip_check.is_set(_SkipCheck.SKIP_CHECK_DEVICE)}", - UserWarning, + self._logger.warning( + "Fast path enabled - skipping checks. rebuild gradient graph: %s, execution agent recreation: %s, " + "device check: %s", + self._runtime_options.skip_check.is_set(_SkipCheck.SKIP_CHECK_BUILD_GRADIENT), + self._runtime_options.skip_check.is_set(_SkipCheck.SKIP_CHECK_EXECUTION_AGENT), + self._runtime_options.skip_check.is_set(_SkipCheck.SKIP_CHECK_DEVICE), ) # If exporting module to ONNX for the first time, this skip check will not take effect. # It will only take effect on subsequent forward calls. build_graph = False if ( - self._skip_check.is_set(_SkipCheck.SKIP_CHECK_BUILD_GRADIENT) is False + self._runtime_options.skip_check.is_set(_SkipCheck.SKIP_CHECK_BUILD_GRADIENT) is False or not self._onnx_models.exported_model ): + self.time_tracker.start(ORTModuleInitPhase.EndToEnd) + # Exporting module to ONNX for the first time build_graph = self._export_model(*inputs, **kwargs) if build_graph: - # If model was exported, then initialize the graph builder + # If model was exported, then initialize the graph builder. self._initialize_graph_builder() # Build the inference graph if build_graph: - self._build_graph() + graph_transformer_config = self._get_graph_transformer_config() + # Set the config according to input inspection. + self._enable_conditional_optimizations(graph_transformer_config, inputs, kwargs) + + # Build the graph + self._build_graph(graph_transformer_config) # If creating the execution agent for the first time, this skip check will not take effect. # It will only take effect on subsequent forward calls. create_execution_session = False - if self._skip_check.is_set(_SkipCheck.SKIP_CHECK_EXECUTION_AGENT) is False or not self._execution_agent: + if ( + self._runtime_options.skip_check.is_set(_SkipCheck.SKIP_CHECK_EXECUTION_AGENT) is False + or not self._execution_agent + ): module_device = _utils.get_device_from_module(self._original_module) create_execution_session = ( @@ -118,27 +152,45 @@ def forward(self, *inputs, **kwargs): # Create execution session creates the inference_session self._create_execution_agent() - if self._skip_check.is_set(_SkipCheck.SKIP_CHECK_DEVICE) is False: + self.time_tracker.end(ORTModuleInitPhase.EndToEnd) + self._log_feature_stats() + + if self._runtime_options.skip_check.is_set(_SkipCheck.SKIP_CHECK_DEVICE) is False: # Assert that the input and model device match _utils._check_same_device(self._device, "Input argument to forward", *inputs) + if self._runtime_options.enable_zero_stage3_support: + self._append_pull_weight_trigger_as_input(kwargs, self._device) + + prepared_input_list, _, _ = _io._combine_input_buffers_initializers( + self._graph_initializers, + self._graph_info.user_input_names, + self._input_info, + self._flattened_module.named_buffers(), + inputs, + kwargs, + self._device, + self._runtime_inspector, + self._zero_stage3_param_map, + ) + user_outputs, _ = InferenceManager.execution_session_run_forward( self._execution_agent, self._onnx_models.optimized_model, self._device, - *_io._combine_input_buffers_initializers( - self._graph_initializers, - self._graph_info.user_input_names, - self._input_info, - self._flattened_module.named_buffers(), - inputs, - kwargs, - self._device, - self._rt_inspector.input_density_ob, - ), + *prepared_input_list, ) - return _io.unflatten_user_output(self._module_output_schema, user_outputs) + if ( + create_execution_session + and self._runtime_options.enable_tuning + and self._runtime_options.tuning_results_path + ): + save_tuning_results( + self._execution_agent._inference_session, False, self._runtime_options.tuning_results_path + ) + + return unflatten_user_output(self._module_output_schema, user_outputs) except ORTModuleFallbackException as e: # Exceptions subject to fallback are handled here self._fallback_manager.handle_exception(exception=e, log_level=self._debug_options.logging.log_level) @@ -154,10 +206,12 @@ def forward(self, *inputs, **kwargs): if self._fallback_manager.is_pending(): return self._fallback_manager.fallback(self._debug_options.logging.log_level, *inputs, **kwargs) - def _build_graph(self): + @TrackTime(ORTModuleInitPhase.BUILD_GRAPH) + @SuppressLogs(ORTModuleInitPhase.BUILD_GRAPH) + def _build_graph(self, graph_transformer_config): """Build an inference graph using the module_graph_builder""" - super()._build_graph() + super()._build_graph(graph_transformer_config) self._onnx_models.optimized_model = onnx.load_model_from_string(self._graph_builder.get_forward_model()) if self._debug_options.save_onnx_models.save: self._onnx_models.save_optimized_model( @@ -166,10 +220,8 @@ def _build_graph(self): self._export_mode, ) - self._rt_inspector.input_density_ob.initialize( - self._onnx_models.optimized_model, self._graph_info.user_input_names - ) - + @TrackTime(ORTModuleInitPhase.CREATE_SESSION) + @SuppressLogs(ORTModuleInitPhase.CREATE_SESSION) def _create_execution_agent(self): """Creates an InferenceAgent that can run forward graph on an inference model""" @@ -177,3 +229,8 @@ def _create_execution_agent(self): self._execution_agent = InferenceAgent( self._onnx_models.optimized_model.SerializeToString(), session_options, providers, provider_options ) + + if not self._runtime_options.enable_tuning and self._runtime_options.tuning_results_path: + set_tuning_results( + self._execution_agent._inference_session, False, self._runtime_options.tuning_results_path + ) diff --git a/orttraining/orttraining/python/training/ortmodule/_io.py b/orttraining/orttraining/python/training/ortmodule/_io.py index 2caf5052f784b..e7c1b30daae0d 100644 --- a/orttraining/orttraining/python/training/ortmodule/_io.py +++ b/orttraining/orttraining/python/training/ortmodule/_io.py @@ -6,14 +6,23 @@ import copy import gc import inspect -import warnings -from collections import abc +from collections import OrderedDict, abc +from logging import Logger +from typing import Dict, Iterator, List, Mapping, Optional, Sequence, Tuple +import onnx import torch +from onnxruntime.training.utils import ( + ORTModelInputOutputSchemaType, + ORTModelInputOutputType, + PrimitiveType, + extract_data_and_schema, + unflatten_data_using_schema, +) + from ._fallback import ORTModuleIOError, ORTModuleONNXModelException, wrap_exception -from ._logger import suppress_os_stream_output -from ._utils import warn_of_constant_inputs +from ._runtime_inspector import RuntimeInspector class _OutputIdentityOp(torch.autograd.Function): @@ -67,29 +76,10 @@ def symbolic(g, self): return g.op("Identity", self) -class _PrimitiveType: - _primitive_types = {int, bool, float} - - @staticmethod - def is_primitive_type(value): - return type(value) in _PrimitiveType._primitive_types - - @staticmethod - def get_tensor(value, device): - return torch.tensor(value, device=device) - - @staticmethod - def get_primitive_dtype(value): - # If `value` is a boolean, save the value of the boolean in dtype. - # This way, if the value changes from one forward call to the next, the schema will mismatch, - # and the model will be re-exported. - return f"{str(type(value))}_{value}" if isinstance(value, bool) else str(type(value)) - - def flatten_kwargs(kwargs, device): def _flatten_kwargs(value, name): - if _PrimitiveType.is_primitive_type(value): - flattened_kwargs[name] = _PrimitiveType.get_tensor(value, device) + if PrimitiveType.is_primitive_type(value): + flattened_kwargs[name] = PrimitiveType.get_tensor(value, device) elif isinstance(value, torch.Tensor): flattened_kwargs[name] = value elif isinstance(value, abc.Sequence): @@ -114,18 +104,18 @@ def _flatten_kwargs(value, name): class _InputInfo: def __init__( self, - names, - shape, - require_grad_names=None, - dynamic_axes=None, - schema=None, + names: List[str], + shape: List[List[int]], + require_grad_names: Optional[List[str]] = None, + dynamic_axes: Optional[Dict[str, Dict[int, str]]] = None, + schema: Optional[ORTModelInputOutputSchemaType] = None, num_positionals=0, ): - self.names = names - self.shape = shape - self.require_grad_names = require_grad_names if require_grad_names else [] - self.dynamic_axes = dynamic_axes if dynamic_axes else {} - self.schema = schema if schema else [] + self.names: List[str] = names + self.shape: List[List[int]] = shape + self.require_grad_names: List[str] = require_grad_names if require_grad_names else [] + self.dynamic_axes: Dict[str, Dict[int, str]] = dynamic_axes if dynamic_axes else {} + self.schema: ORTModelInputOutputSchemaType = schema if schema else [] self.num_positionals = num_positionals self.kwargs = None @@ -138,10 +128,15 @@ def __repr__(self) -> str: \tSchema: {self.schema} \t#Positionals (total): {self.num_positionals}""" - def flatten(self, args, kwargs, device): + def flatten( + self, + args: Sequence[ORTModelInputOutputType], + kwargs: Mapping[str, ORTModelInputOutputType], + device: torch.device, + ) -> Sequence[ORTModelInputOutputType]: """Flatten args and kwargs in a single tuple of tensors with strict ordering""" - ret = [_PrimitiveType.get_tensor(arg, device) if _PrimitiveType.is_primitive_type(arg) else arg for arg in args] + ret = [PrimitiveType.get_tensor(arg, device) if PrimitiveType.is_primitive_type(arg) else arg for arg in args] flattened_kwargs = flatten_kwargs(kwargs, device) ret += [flattened_kwargs[name] for name in self.names if name in flattened_kwargs] self.kwargs = kwargs @@ -153,7 +148,9 @@ def flatten(self, args, kwargs, device): return ret - def unflatten(self, flat_args): + def unflatten( + self, flat_args: Sequence[ORTModelInputOutputType] + ) -> Tuple[Sequence[ORTModelInputOutputType], Mapping[str, ORTModelInputOutputType]]: """Unflatten tuple of tensors into args and kwargs""" args = tuple(flat_args[: self.num_positionals]) @@ -163,13 +160,21 @@ def unflatten(self, flat_args): def _combine_input_buffers_initializers( - params, onnx_input_names, input_info, buffer_names, inputs, kwargs, device, input_density_ob + params: List[torch.nn.parameter.Parameter], + onnx_input_names: List[str], + input_info: Optional[_InputInfo], + named_buffer: Iterator[Tuple[str, torch.Tensor]], + inputs: Sequence[ORTModelInputOutputType], + kwargs: Mapping[str, ORTModelInputOutputType], + device: torch.device, + rt_inspector: RuntimeInspector, + zero_stage3_offload_param_map: Optional[Dict[str, torch.nn.parameter.Parameter]], ): """Creates forward `*inputs` list from user input and PyTorch initializers ONNX Runtime forward requires an ordered list of: * User input: computed from forward InferenceSession - * Initializers: computed from original PyTorch model parameters + * Initializers: computed from original PyTorch model parameters. """ def _expand_inputs(current_input, non_none_inputs, name=""): @@ -201,8 +206,10 @@ def _expand_inputs(current_input, non_none_inputs, name=""): _expand_inputs(inputs, non_none_inputs) flattened_kwargs_inputs = {} _expand_inputs(kwargs, flattened_kwargs_inputs) - buffer_names_dict = {buffer_name: inp for buffer_name, inp in buffer_names} + buffer_names_dict = {buffer_name: inp for buffer_name, inp in named_buffer} result = [] + embed_sparsity_results = OrderedDict() + label_sparsity_results = OrderedDict() for input_idx, name in enumerate(onnx_input_names): inp = None @@ -232,10 +239,15 @@ def _expand_inputs(current_input, non_none_inputs, name=""): pass if inp is not None: - if _PrimitiveType.is_primitive_type(inp): - inp = _PrimitiveType.get_tensor(inp, device) - - input_density_ob.inspect_from_input_data(name, inp) + if PrimitiveType.is_primitive_type(inp): + inp = PrimitiveType.get_tensor(inp, device) + + found, embedding_density, label_density = rt_inspector.inspect_input(name, inp) + if found: + if embedding_density < 100: + embed_sparsity_results[name] = embedding_density + if label_density < 100: + label_sparsity_results[name] = label_density result.append(inp) else: raise wrap_exception( @@ -243,12 +255,19 @@ def _expand_inputs(current_input, non_none_inputs, name=""): ) # params is a list of all initializers known to the onnx graph - result.extend(params) + if zero_stage3_offload_param_map: + for p in params: + if p not in zero_stage3_offload_param_map.values(): + result.append(p) + else: + result.extend(params) - return result + return result, embed_sparsity_results, label_sparsity_results -def deepcopy_model_input(*inputs, **kwargs): +def deepcopy_model_input( + *args, **kwargs +) -> Tuple[Sequence[ORTModelInputOutputType], Mapping[str, ORTModelInputOutputType]]: def extract_tensor(value): if isinstance(value, torch.Tensor): if value.requires_grad: @@ -258,151 +277,41 @@ def extract_tensor(value): else: return value - sample_inputs_copy = [extract_tensor(value) for value in inputs] - sample_inputs_copy = copy.deepcopy(tuple(sample_inputs_copy)) + sample_args_copy: Sequence[ORTModelInputOutputType] = [extract_tensor(value) for value in args] + sample_args_copy = copy.deepcopy(tuple(sample_args_copy)) - sample_kwargs_copy = {} + sample_kwargs_copy: Mapping[str, ORTModelInputOutputType] = {} for name, value in kwargs.items(): sample_kwargs_copy[name] = extract_tensor(value) sample_kwargs_copy = copy.deepcopy(sample_kwargs_copy) - return sample_inputs_copy, sample_kwargs_copy + return sample_args_copy, sample_kwargs_copy -class _TensorStub: - """Tensor stub class used to represent model's input or output""" +def unflatten_user_output(output_schema: Optional[ORTModelInputOutputSchemaType], outputs: List[torch.Tensor]): + try: + return unflatten_data_using_schema(outputs, output_schema) + except TypeError as e: + raise wrap_exception( + ORTModuleIOError, + TypeError(f"ORTModule fails to unflatten user output: {e}"), + ) from None - __slots__ = ["name", "dtype", "shape", "shape_dims"] - def __init__(self, name=None, dtype=None, shape=None, shape_dims=None): - self.name = name - self.dtype = dtype - self.shape = shape - self.shape_dims = shape_dims +def _extract_schema(data: ORTModelInputOutputType, device) -> ORTModelInputOutputSchemaType: + try: + _, schema = extract_data_and_schema(data, constant_as_tensor=True, device=device) + return schema + except TypeError as e: + raise wrap_exception(ORTModuleIOError, TypeError(f"ORTModule fails to extract schema from data: {e}")) from None - def __repr__(self) -> str: - result = "_TensorStub(" - if self.name is not None: - result += f"name={self.name}" - if self.dtype is not None: - if result[-1] != "(": - result += ", " - result += f"dtype={self.dtype}" - if self.shape is not None: - if result[-1] != "(": - result += ", " - result += f"shape={self.shape}" - if self.shape_dims is not None: - if result[-1] != "(": - result += ", " - result += f"shape_dims={self.shape_dims}" - result += ")" - return result - - def __eq__(self, other): - if not other: - return False - elif not isinstance(other, _TensorStub): - raise NotImplementedError("_TensorStub must only be compared to another _TensorStub instance!") - elif self.name != other.name: - return False - elif self.dtype != other.dtype: - return False - elif self.shape != other.shape: - return False - elif self.shape_dims != other.shape_dims: - return False - return True - - -def unflatten_user_output(output_schema, outputs): - """Follows the schema to generate an output that is expected by the user""" - - def _replace_stub_with_tensor_value(user_output, outputs, output_idx): - # Recursively traverse across user_output and replace all _TensorStub - # with torch.Tensor values from outputs following output_idx - - if user_output is None: - return None - elif isinstance(user_output, _TensorStub): - out = outputs[output_idx[0]] - output_idx[0] += 1 - return out - - if isinstance(user_output, abc.Sequence): - sequence_type = type(user_output) - if hasattr(sequence_type, "_make"): # namedtuple - sequence_type = type(user_output) - user_output = sequence_type._make( - _replace_stub_with_tensor_value(uo, outputs, output_idx) for uo in user_output - ) - else: - user_output = sequence_type( - _replace_stub_with_tensor_value(uo, outputs, output_idx) for uo in user_output - ) - elif isinstance(user_output, abc.Mapping): - new_user_output = copy.copy(user_output) - for key in sorted(user_output): - new_user_output[key] = _replace_stub_with_tensor_value(new_user_output[key], outputs, output_idx) - user_output = new_user_output - else: - raise wrap_exception( - ORTModuleIOError, - TypeError(f"ORTModule does not support the following model output type {type(user_output)}."), - ) - return user_output - - # It is expected that the outputs are ordered in the way defined in the exported onnx model - # which is the order in which the output schema was saved. - output_idx = [0] - user_output = _replace_stub_with_tensor_value(output_schema, outputs, output_idx) - return user_output - - -def _extract_schema(data): - """Extract the data schema by replacing every torch.Tensor value with _TensorStub""" - - if data is None: - return data - elif isinstance(data, str): - warn_of_constant_inputs(data) - return data - elif _PrimitiveType.is_primitive_type(data): - if isinstance(data, bool): - warn_of_constant_inputs(data) - return _TensorStub(dtype=_PrimitiveType.get_primitive_dtype(data), shape_dims=0) - # Depth first traversal to iterate over the data to replace every tensor with a stub - elif isinstance(data, torch.Tensor): - return _TensorStub(dtype=str(data.dtype), shape_dims=len(data.size())) - - # Instead of replacing the tensor with a stub in the original user input, build the stubbed_schema - # from scratch from the user input. - stubbed_schema = None - if isinstance(data, abc.Sequence): - sequence_type = type(data) - stubbed_schema = [_extract_schema(val) for val in data] - try: - # namedtuple can be created by passing the list sequence to method _make - stubbed_schema = sequence_type._make(stubbed_schema) - except AttributeError: - # If attribute error encountered, create the sequence directly - stubbed_schema = sequence_type(stubbed_schema) - elif isinstance(data, abc.Mapping): - dict_type = type(data) - stubbed_schema = {key: _extract_schema(data[key]) for key in data} - stubbed_schema = dict_type(**stubbed_schema) - else: - raise wrap_exception( - ORTModuleIOError, TypeError(f"ORTModule does not support the following model data type {type(data)}") - ) - return stubbed_schema - - -def _parse_outputs_and_extract_names_and_dynamic_axes(module_output): +def _parse_outputs_and_extract_names_and_dynamic_axes(module_output) -> Tuple[List[str], Dict[str, Dict[int, str]]]: """Parses through the module output and returns output names and dynamic axes""" - def _populate_output_names_and_dynamic_axes(output, output_names, output_dynamic_axes, output_idx): + def _populate_output_names_and_dynamic_axes( + output, output_names: List[str], output_dynamic_axes: Dict[str, Dict[int, str]], output_idx: List[int] + ): # Depth first traversal to traverse through the entire output collecting output names and dynamic axes if output is None: @@ -430,9 +339,9 @@ def _populate_output_names_and_dynamic_axes(output, output_names, output_dynamic TypeError(f"ORTModule does not support the following model output type {type(output)}"), ) - output_names = [] - output_dynamic_axes = {} - output_idx = [0] + output_names: List[str] = [] + output_dynamic_axes: Dict[str, Dict[int, str]] = {} + output_idx: List[int] = [0] _populate_output_names_and_dynamic_axes(module_output, output_names, output_dynamic_axes, output_idx) return output_names, output_dynamic_axes @@ -466,21 +375,53 @@ def _flatten_data(data, flat_data): class _FlattenedModule(torch.nn.Module): - def __init__(self, original_module): + def __init__(self, original_module: torch.nn.Module): super().__init__() - self._original_module = original_module + self._original_module: torch.nn.Module = original_module # Before `forward` is called, _ort_module must be assigned # Updated input info is needed to expand args into *args, **kwargs - self._input_info = None + self._input_info: Optional[_InputInfo] = None def forward(self, *args): new_args, new_kwargs = self._input_info.unflatten(args) return _transform_output_to_flat_tuple(self._original_module(*new_args, **new_kwargs)) -def parse_inputs_for_onnx_export(all_input_parameters, onnx_graph, schema, inputs, kwargs): - def _add_dynamic_shape(name, input): +def parse_inputs_for_onnx_export( + all_input_parameters: List[inspect.Parameter], + onnx_graph: Optional[onnx.ModelProto], + schema: ORTModelInputOutputSchemaType, + args: Sequence[ORTModelInputOutputType], + kwargs: Mapping[str, ORTModelInputOutputType], +) -> _InputInfo: + """Parses through the model inputs and returns _InputInfo. + + Loop through all input parameters, try to flatten them into a 1-D list of inputs. For nested data in the inputs, + construct the name in hierarchical order. + + Example 1, arg is a list, kwarg is a dict: + args = [arg1, arg2], kwargs = {"a": 4, "b": 5}, + input_names = ["arg1", "arg2", "a", "b"]. + + Example 2, arg is a list, kwarg is a dict of mixed list and scalar: + args = [arg1, arg2], kwargs = {"a": [4, 5], "b": 6}, + input_names = ["arg1", "arg2", "a_0", "a_1", "b"]. + + Example 3, arg is a list, kwarg is a dict of mixed dict and scalar: + args = [arg1, arg2], kwargs = {"a": {"c": 4, "d": 5}, "b": 6}, + input_names = ["arg1", "arg2", "a_c", "a_d", "b"]. + + Args: + all_input_parameters: All inspected input parameters from the original model forward function signature. + onnx_graph: (optional) The onnx graph. + schema: The schema extracted from the positional arguments and keyword arguments of the model. + args: The positional arguments of the model. + kwargs: The keyword arguments of the model. + + """ + + def _add_dynamic_shape(name, input) -> Dict[str, Dict[int, str]]: dynamic_axes[name] = {} for dim_idx in range(len(input.shape)): dynamic_axes[name].update({dim_idx: f"{name}_dim{dim_idx}"}) @@ -526,24 +467,43 @@ def _add_input(name, input_value, onnx_graph, onnx_graph_input_names): # Ignore optional inputs explicitly specified as None # ONNX exporter may remove unused inputs - onnx_graph_input_names = [] + onnx_graph_input_names: List[str] = [] if onnx_graph is not None: onnx_graph_input_names = {inp.name for inp in onnx_graph.graph.input} - input_names = [] - dynamic_axes = {} - input_names_require_grad = [] - input_shape = [] + input_names: List[str] = [] + dynamic_axes: Dict[str, Dict[int, str]] = {} + input_names_require_grad: List[str] = [] + input_shape: List[List[int]] = [] var_positional_idx = 0 + # Be noted, all_input_parameters is a list of inspect.Parameters parsed from the original module's forward method. + # While the execution manager's forward function will map all given model inputs to *args and **kwargs, so it is + # possible the input parameter list cannot represent the real model inputs given here (e.g., *args, **kwargs). + # But it is still fine to use all_input_parameters to make sure all model inputs are covered. + # + # Here is an example caused by the mismatch between all_input_parameters and real model inputs. + # def foo(*args, named_kwargs, **kwargs): + # ... print("foo") + # From inspection, + # > ('args', <_ParameterKind.VAR_POSITIONAL: 2>) + # > ('named_kwargs', <_ParameterKind.KEYWORD_ONLY: 3>) + # > ('kwargs', <_ParameterKind.VAR_KEYWORD: 4>) + # + # At this point, 'named_kwargs' exists in **kwargs as a result of ORTModule's forward parse all original + # model inputs in to *args and **kwargs. + # When we loop `all_input_parameters``, for the `named_kwargs`, we will try to handle it in KEYWORD_ONLY branch. + # Additionally in VAR_KEYWORD branch, we will get the `named_kwargs` value again, because its name exists in the + # `kwargs`. So _add_input avoids handling the `named_kwargs` twice, check test case `test_named_kwargs_dict_input` + # for the details. for input_idx, input_parameter in enumerate(all_input_parameters): if input_parameter.kind == inspect.Parameter.VAR_POSITIONAL: # VAR_POSITIONAL parameter carries all *args parameters from original forward method - for args_i in range(input_idx, len(inputs)): + for args_i in range(input_idx, len(args)): name = f"{input_parameter.name}_{var_positional_idx}" var_positional_idx += 1 - inp = inputs[args_i] + inp = args[args_i] _add_input(name, inp, onnx_graph, onnx_graph_input_names) elif ( input_parameter.kind == inspect.Parameter.POSITIONAL_ONLY @@ -554,8 +514,8 @@ def _add_input(name, input_value, onnx_graph, onnx_graph_input_names): name = input_parameter.name inp = None input_idx += var_positional_idx # noqa: PLW2901 - if input_idx < len(inputs) and inputs[input_idx] is not None: - inp = inputs[input_idx] + if input_idx < len(args) and args[input_idx] is not None: + inp = args[input_idx] elif name in kwargs and kwargs[name] is not None: inp = kwargs[name] _add_input(name, inp, onnx_graph, onnx_graph_input_names) @@ -570,36 +530,43 @@ def _add_input(name, input_value, onnx_graph, onnx_graph_input_names): require_grad_names=input_names_require_grad, dynamic_axes=dynamic_axes, schema=schema, - num_positionals=len(inputs), + num_positionals=len(args), ) -def parse_outputs_for_onnx_export_and_extract_schema(module, inputs, kwargs, log_level): +def parse_outputs_for_onnx_export_and_extract_schema( + module, + args: Sequence[ORTModelInputOutputType], + kwargs: Mapping[str, ORTModelInputOutputType], + logger: Logger, + device: Optional[torch.device], +): # Perform a forward call to grab outputs output_names = None output_dynamic_axes = None is_deepcopy = False - with torch.no_grad(), suppress_os_stream_output(log_level=log_level): + logger.info("Running model forward to infer output schema and dynamic axes...") + with torch.no_grad(): # Deepcopy inputs, since input values may change after model run. - sample_inputs_copy, sample_kwargs_copy = deepcopy_model_input(*inputs, **kwargs) + sample_args_copy, sample_kwargs_copy = deepcopy_model_input(*args, **kwargs) try: # Deepcopy model, in case model is stateful and changes after model run. model_copy = copy.deepcopy(module) is_deepcopy = True except Exception: model_copy = module - warnings.warn( + logger.warning( "This model cannot be deep copied (or pickled), " "which is a required step for stateful models to be properly exported to ONNX." " Compute will continue, but unexpected results may occur!" ) - sample_outputs = model_copy(*sample_inputs_copy, **sample_kwargs_copy) + sample_outputs = model_copy(*sample_args_copy, **sample_kwargs_copy) # Parse the output and extract the output_names and output_dynamic_axes to be used for onnx export output_names, output_dynamic_axes = _parse_outputs_and_extract_names_and_dynamic_axes(sample_outputs) - output_schema = _extract_schema(sample_outputs) + output_schema = _extract_schema(sample_outputs, device) if is_deepcopy: del model_copy gc.collect() diff --git a/orttraining/orttraining/python/training/ortmodule/_logger.py b/orttraining/orttraining/python/training/ortmodule/_logger.py index 197158ecc99ed..e075ced8eaac2 100644 --- a/orttraining/orttraining/python/training/ortmodule/_logger.py +++ b/orttraining/orttraining/python/training/ortmodule/_logger.py @@ -3,14 +3,21 @@ # Licensed under the MIT License. # -------------------------------------------------------------------------- -import io +import logging +import os import sys -import warnings +import tempfile +import textwrap +import time from contextlib import contextmanager from enum import IntEnum +from functools import partial +from typing import Callable, Dict, List, Optional from onnxruntime.capi._pybind_state import Severity +from ._utils import get_rank, get_world_size + class LogLevel(IntEnum): VERBOSE = 0 @@ -20,48 +27,250 @@ class LogLevel(IntEnum): FATAL = 4 +ORTMODULE_LOG_LEVEL_MAP: Dict[LogLevel, List[int]] = { + LogLevel.VERBOSE: [Severity.VERBOSE, logging.DEBUG], + LogLevel.INFO: [Severity.INFO, logging.INFO], + LogLevel.WARNING: [Severity.WARNING, logging.WARNING], + LogLevel.ERROR: [Severity.ERROR, logging.ERROR], + LogLevel.FATAL: [Severity.FATAL, logging.FATAL], +} + + +def ortmodule_loglevel_to_onnxruntime_c_loglevel(loglevel: LogLevel) -> int: + return ORTMODULE_LOG_LEVEL_MAP.get(loglevel, [Severity.WARNING, logging.WARNING])[0] + + +def ortmodule_loglevel_to_python_loglevel(loglevel: LogLevel) -> int: + return ORTMODULE_LOG_LEVEL_MAP.get(loglevel, [Severity.WARNING, logging.WARNING])[1] + + +def configure_ortmodule_logger(log_level: LogLevel) -> logging.Logger: + """Configure the logger for ortmodule according to following rules. + 1. If multiple processes are used, the rank will be appended + to the logger name. + 2. If the log level is greater than info, the logger will be + disabled for non-zero ranks. + """ + rank_info = f".rank-{get_rank()}" if get_world_size() > 1 else "" + logger = logging.getLogger(f"orttraining{rank_info}") + # Disable the logger for non-zero ranks when level > info + logger.disabled = log_level > LogLevel.INFO and get_rank() != 0 + logger.setLevel(ortmodule_loglevel_to_python_loglevel(log_level)) + return logger + + +class LogColor: + HEADER = "\033[95m" + BLUE = "\033[94m" + CYAN = "\033[96m" + GREEN = "\033[92m" + WARNING = "\033[93m" + RED = "\033[91m" + ENDC = "\033[0m" + BOLD = "\033[1m" + UNDERLINE = "\033[4m" + + +class ORTModuleInitPhase(IntEnum): + EndToEnd = 0 # The end to end of ORT first-time initialization + EXPORT = 1 # The phase of preparing and exporting the model to ONNX + GRAPH_BUILDER_INIT = 2 # The phase of initializing the graph builder + DETECTION = 3 # The phase of runtime detection + BUILD_GRAPH = 4 # The phase of optimizing forward graph (and building the gradient graph for training). + CREATE_SESSION = 5 # The phase of creating the session + + def to_string(self) -> str: + if self == ORTModuleInitPhase.EndToEnd: + return "end to end" + if self == ORTModuleInitPhase.EXPORT: + return "export" + elif self == ORTModuleInitPhase.GRAPH_BUILDER_INIT: + return "graph builder init" + elif self == ORTModuleInitPhase.DETECTION: + return "runtime detection" + elif self == ORTModuleInitPhase.BUILD_GRAPH: + return "graph building" + elif self == ORTModuleInitPhase.CREATE_SESSION: + return "session creation" + else: + return "invalid" + + +class TimeTracker: + """A simple class to track time spent in different phases of ORT backend first-time initialization.""" + + NOT_RECORD = -1.0 + + def __init__( + self, + ): + self.starts_: List[float] = [TimeTracker.NOT_RECORD] * len(ORTModuleInitPhase) + self.ends_: List[float] = [TimeTracker.NOT_RECORD] * len(ORTModuleInitPhase) + + def start(self, phase: ORTModuleInitPhase): + self.starts_[phase] = time.time() + + def end(self, phase: ORTModuleInitPhase): + self.ends_[phase] = time.time() + + def _get_duration(self, phase: ORTModuleInitPhase): + if self.ends_[phase] == TimeTracker.NOT_RECORD or self.starts_[phase] == TimeTracker.NOT_RECORD: + return TimeTracker.NOT_RECORD + return self.ends_[phase] - self.starts_[phase] + + def to_string(self, log_details=False) -> str: + end_to_end_str = self._get_duration(ORTModuleInitPhase.EndToEnd) + end_to_end_str = f"{end_to_end_str:.2f}" if end_to_end_str != TimeTracker.NOT_RECORD else "N/A" + export_str = self._get_duration(ORTModuleInitPhase.EXPORT) + export_str = f"{export_str:.2f}" if export_str != TimeTracker.NOT_RECORD else "N/A" + overhead_title_str = ( + f"Total ORT initialization overhead is {end_to_end_str}s where export takes {export_str}s.\n" + ) + + if log_details is False: + return overhead_title_str + + duration_summaries = [] + for phase in ORTModuleInitPhase: + _get_duration = self._get_duration(phase) + if phase in [ORTModuleInitPhase.EndToEnd, ORTModuleInitPhase.EXPORT]: + continue + + val = ( + f" {phase.to_string()} takes {_get_duration:.2f}s" if _get_duration != TimeTracker.NOT_RECORD else "N/A" + ) + duration_summaries.append(f"{val}") + + return f"{overhead_title_str}Other overhead details: {','.join(duration_summaries)}\n" + + +class TrackTime: + """A function decorator to track time spent in different phases of ORT backend first-time initialization.""" + + def __init__(self, phase: ORTModuleInitPhase): + self.phase = phase + + def __call__(self, func: Callable): + def wrapper(graph_execution_manager, *args, **kwargs): + if not hasattr(graph_execution_manager, "time_tracker"): + raise RuntimeError("The class of the function to be tracked must have a 'time_tracker' attribute.") + graph_execution_manager.time_tracker.start(self.phase) + result = func(graph_execution_manager, *args, **kwargs) + graph_execution_manager.time_tracker.end(self.phase) + return result + + return wrapper + + @contextmanager -def suppress_os_stream_output(suppress_stdout=True, suppress_stderr=True, log_level=LogLevel.WARNING): - """Suppress output from being printed to stdout and stderr if log_level is WARNING or higher. +def _suppress_os_stream_output(enable=True, on_exit: Optional[Callable] = None): + """Suppress output from being printed to stdout and stderr. - If there is any output detected, a single warning is issued in the context + If on_exit is not None, it will be called when the context manager exits. """ + if enable: + # stdout and stderr is written to a tempfile instead + with tempfile.TemporaryFile() as fp: + old_stdout = None + old_stderr = None + try: + # Store original stdout and stderr file no. + old_stdout = os.dup(sys.stdout.fileno()) + old_stderr = os.dup(sys.stderr.fileno()) + + # Redirect stdout and stderr (printed from Python or C++) to the file. + os.dup2(fp.fileno(), sys.stdout.fileno()) + os.dup2(fp.fileno(), sys.stderr.fileno()) + yield + finally: + sys.stdout.flush() + sys.stderr.flush() - # stdout and stderr is written to a tempfile instead - stdout = sys.stdout - stderr = sys.stderr + # Restore stdout and stderr. + if old_stdout is not None: + os.dup2(old_stdout, sys.stdout.fileno()) + if old_stderr is not None: + os.dup2(old_stderr, sys.stderr.fileno()) - suppress_logs = log_level >= LogLevel.WARNING + # Close file descriptors + os.close(old_stdout) + os.close(old_stderr) - fo = io.StringIO() + if on_exit: + on_exit(fp) - try: - if suppress_stdout and suppress_logs: - sys.stdout = fo - if suppress_stderr and suppress_logs: - sys.stderr = fo + else: yield - finally: - if suppress_stdout: - sys.stdout = stdout - if suppress_stderr: - sys.stderr = stderr - - if fo.tell() > 0 and suppress_logs: - # If anything was captured in fo, raise a single user warning letting users know that there was - # some warning or error that was raised - warnings.warn( - "There were one or more warnings or errors raised while exporting the PyTorch " - "model. Please enable INFO level logging to view all warnings and errors.", - UserWarning, - ) -def ortmodule_loglevel_to_onnxruntime_c_loglevel(loglevel): - return { - LogLevel.VERBOSE: Severity.VERBOSE, - LogLevel.INFO: Severity.INFO, - LogLevel.WARNING: Severity.WARNING, - LogLevel.ERROR: Severity.ERROR, - LogLevel.FATAL: Severity.FATAL, - }.get(loglevel, Severity.WARNING) +def _log_with_filter(logger: logging.Logger, record_filters: Optional[List[str]], name: Optional[str], fo): + """Log the content by filtering with list of string patterns. + Args: + logger: The logger to log the content. + record_filters: The list of string patterns to filter the content. + If record_filters is None, the full content will be logged. + name: The name of log filter. + fo: The file object to read the content. + """ + if fo.tell() > 0: + if logger.disabled: + return + + fo.seek(0) + suppress_output_messages = fo.readlines() + if record_filters: + filtered_messages = [] + filtered_lines = 0 + for suppressed_message in suppress_output_messages: + msg = suppressed_message.decode("utf-8") + found = False + for warning in record_filters: + if warning in msg: + found = True + filtered_lines += 1 + break + + if not found: + filtered_messages.extend(textwrap.wrap(msg, 180)) + if filtered_messages: + filtered_messages.insert(0, f"[{name}] Filtered logs ({filtered_lines} records suppressed):") + logger.warning("\n ".join(filtered_messages)) + else: + out_messages = [] + for suppressed_message in suppress_output_messages: + out_messages.extend(textwrap.wrap(suppressed_message.decode("utf-8"), 180)) + if out_messages: + out_messages.insert(0, f"[{name}] Full logs:") + logger.warning("\n ".join(out_messages)) + + +class SuppressLogs: + """A function decorator to suppress in different phases of ORT backend first-time initialization.""" + + def __init__(self, phase: ORTModuleInitPhase, is_ort_filter=True): + self.phase = phase + self.is_ort_filter = is_ort_filter + + def __call__(self, func: Callable): + def wrapper(graph_execution_manager, *args, **kwargs): + if not hasattr(graph_execution_manager, "_logger"): + raise RuntimeError("The class of the function to be tracked must have a '_logger' attribute.") + + if not hasattr(graph_execution_manager, "_debug_options"): + raise RuntimeError("The class of the function to be tracked must have a '_debug_options' attribute.") + + with _suppress_os_stream_output( + enable=graph_execution_manager._debug_options.log_level >= LogLevel.INFO, + on_exit=partial( + _log_with_filter, + graph_execution_manager._logger, + graph_execution_manager._debug_options.onnxruntime_log_filter + if self.is_ort_filter + else graph_execution_manager._debug_options.torch_exporter_filter, + self.phase.to_string(), + ), + ): + result = func(graph_execution_manager, *args, **kwargs) + return result + + return wrapper diff --git a/orttraining/orttraining/python/training/ortmodule/_onnx_models.py b/orttraining/orttraining/python/training/ortmodule/_onnx_models.py index 1dd0a12dea368..ac09c838af838 100644 --- a/orttraining/orttraining/python/training/ortmodule/_onnx_models.py +++ b/orttraining/orttraining/python/training/ortmodule/_onnx_models.py @@ -4,6 +4,7 @@ import os from dataclasses import dataclass +from typing import Optional import onnx import torch @@ -25,15 +26,14 @@ class ONNXModels: 1. exported_model: Model that is exported by torch.onnx.export 2. optimized_model: For eval mode it's exported_model with concrete input shapes set if needed, for training mode, it's optimized model after gradients graph has been built. - 3. optimized_pre_grad_model: Optimized model before gradient graph is built. It's None for eval mode. - 4. In addition, ORTModule also saves the execution_model which is the model - that is being executed by ORT. It has further optimizations done by the - InferenceSession and is saved by the InferenceSession. + In addition, ORTModule also saves two other models, to the user-provided path: + a. the pre_grad_model which is the model before the gradients graph is built. + b. the execution_model which is the model that is being executed by ORT. + It has further optimizations done by the InferenceSession and is saved by the InferenceSession. """ - exported_model: onnx.ModelProto = None - optimized_model: onnx.ModelProto = None - optimized_pre_grad_model: onnx.ModelProto = None + exported_model: Optional[onnx.ModelProto] = None + optimized_model: Optional[onnx.ModelProto] = None def save_exported_model(self, path, name_prefix, export_mode): # save the ortmodule exported model @@ -46,8 +46,3 @@ def save_optimized_model(self, path, name_prefix, export_mode): _save_model( self.optimized_model, os.path.join(path, _get_onnx_file_name(name_prefix, "optimized", export_mode)) ) - if self.optimized_pre_grad_model is not None: - _save_model( - self.optimized_pre_grad_model, - os.path.join(path, _get_onnx_file_name(name_prefix, "optimized_pre_grad", export_mode)), - ) diff --git a/orttraining/orttraining/python/training/ortmodule/_runtime_inspector.py b/orttraining/orttraining/python/training/ortmodule/_runtime_inspector.py index f4af5c02fc273..dda909e8cb0f1 100644 --- a/orttraining/orttraining/python/training/ortmodule/_runtime_inspector.py +++ b/orttraining/orttraining/python/training/ortmodule/_runtime_inspector.py @@ -3,26 +3,118 @@ # Licensed under the MIT License. # -------------------------------------------------------------------------- -import warnings +from enum import IntEnum +from logging import Logger +from typing import List, Tuple, Union import onnx import torch -from onnx import helper +from onnx import ModelProto, helper from onnx import onnx_pb as onnx_proto -from onnxruntime.training import ortmodule + +class Phase(IntEnum): + INVALID = -1 + PRE_FORWARD = 0 + POST_FORWARD = 1 + PRE_BACKWARD = 2 # not applicable for inference + POST_BACKWARD = 3 # not applicable for inference + + +def _convert_phase_to_string(phase: Phase) -> str: + if phase == Phase.PRE_FORWARD: + return "pre_forward" + elif phase == Phase.POST_FORWARD: + return "post_forward" + elif phase == Phase.PRE_BACKWARD: + return "pre_backward" + elif phase == Phase.POST_BACKWARD: + return "post_backward" + else: + return "invalid" class RuntimeInspector: - def __init__(self): - self.input_density_ob = InputDensityObserver() + """ + Runtime inspector for ORTModule. + """ + + def __init__(self, logger: Logger): + self._logger = logger + + self.input_density_ob: Union[InputDensityObserver, None] = None + self.memory_ob: Union[MemoryObserver, None] = None + + def enable_input_inspector(self, model: ModelProto, user_input_names: List[str]) -> None: + """Initialize input inspector from the given ONNX model and user input names. + + Args: + model: ONNX model. + user_input_names: User input names in the ONNX model. + + """ + if self.input_density_ob is None: + self.input_density_ob = InputDensityObserver(self._logger) + else: + raise RuntimeError("Input density observer is already enabled.") + + return self.input_density_ob.initialize(model, user_input_names) + + def inspect_input(self, input_name, input_data) -> Tuple[bool, float, float]: + """Inspect input data and print statistics. + + Args: + input_name: User input name. + input_data: User input tensor. + + Returns: + found: Whether the input name is found in `_embedding_graph_input_to_padding_idx_map` and + `_loss_label_graph_input_to_ignore_idx_map`. + embed_input_density: Density for the inspected embedding input if found to be True; otherwise, return 100. + label_input_density: Density for the inspected label input if found to be True; otherwise, return 100. + """ + if self.input_density_ob is not None: + return self.input_density_ob.inspect_from_input_data(input_name, input_data) + + return (False, 100, 100) + + def disable_input_inspector(self) -> None: + """Disable input density inspector.""" + self.input_density_ob = None + + def enable_memory_inspector(self, module: torch.nn.Module): + """Enable memory inspector for ORTModule. + + Args: + module: ORTModule. + """ + if self.memory_ob is None: + self.memory_ob = MemoryObserver(module, self._logger) + else: + raise RuntimeError("Memory observer is already enabled.") + + def inspect_memory(self, phase: Phase) -> None: + """Inspect memory usage and print statistics. + + Args: + phase: Phase to inspect. + """ + if self.memory_ob is not None: + self.memory_ob.inspect_memory(phase) class InputDensityObserver: - """Configurable input data observer for ORTModule.""" + """Training input data observer for ORTModule. + + Data observer is used to collect data/compute sparsity information for embedding and label inputs. It needs to be + firstly initialized with the ONNX model and user input names. Then, it can be used to inspect the input data + through `inspect_from_input_data()` method given user input name and input tensor. Inspection results will be + printed per `log_steps`. + + """ - def __init__(self, log_steps=10): - self._enabled = ortmodule._defined_from_envvar("ORTMODULE_ENABLE_INPUT_DENSITY_INSPECTOR", 0, warn=True) == 1 + def __init__(self, logger: Logger, log_steps=1): + self._logger = logger self._embedding_graph_input_to_padding_idx_map = {} self._loss_label_graph_input_to_ignore_idx_map = {} self._stats = [] @@ -34,21 +126,36 @@ def __init__(self, log_steps=10): self._tensor_to_node_map = {} - def initialize(self, model, user_input_names): - """Initialize data observer.""" - if not self._enabled: + def initialize(self, model: ModelProto, user_input_names: List[str]) -> None: + """Initialize data observer from the given ONNX model and user input names. + + For embedding input (e.g. ATen embedding), try to parse the padding_idx from the ONNX model, if padding_idx is + valid, register it in _embedding_graph_input_to_padding_idx_map. + For label input (e.g. SoftmaxCrossEntropyLossInternal), try to parse the ignore_index from the ONNX model, if + ignore_index is valid, register it in _loss_label_graph_input_to_ignore_idx_map. + + Args: + model: ONNX model. + user_input_names: User input names in the ONNX model. + + """ + if self._is_initialized: return - self._tensor_to_node_map.clear() - for node in model.graph.node: - for output_name in node.output: - if output_name != "": # noqa: PLC1901 - self._tensor_to_node_map[output_name] = node + try: + self._tensor_to_node_map.clear() + for node in model.graph.node: + for output_name in node.output: + if output_name != "": + self._tensor_to_node_map[output_name] = node - self._initialize_embedding_padding_inspector(model, user_input_names) - self._initialize_loss_label_padding_inspector(model, user_input_names) + self._initialize_embedding_padding_inspector(model, user_input_names) + self._initialize_loss_label_padding_inspector(model, user_input_names) - self._is_initialized = True + self._is_initialized = True + except Exception as e: + self._is_initialized = False + self._logger.warning(f"Failed to initialize InputDensityObserver due to {e}") def _initialize_embedding_padding_inspector(self, model, user_input_names): """Register embedding input padding inspector. @@ -64,20 +171,36 @@ def _initialize_embedding_padding_inspector(self, model, user_input_names): self._embedding_graph_input_to_padding_idx_map.clear() for node in model.graph.node: - if not (node.domain == "org.pytorch.aten" and node.op_type == "ATen" and node.input[1] in user_input_names): + if not ( + node.domain == "org.pytorch.aten" + and node.op_type == "ATen" + and node.input[1] in user_input_names + and len(node.input) >= 3 + ): continue found = [attr for attr in node.attribute if attr.name == "operator"] if not found or helper.get_attribute_value(found[0]).decode() != "embedding": continue - tensor = self._try_get_initializer(model, node.input[2]) + tensor = None + padding_const_node = self._try_get_node_from_its_output(node.input[2]) + if padding_const_node is None: + padding_initializer_name = node.input[2] + tensor = self._try_get_initializer(model, padding_initializer_name) + + elif padding_const_node.op_type == "Constant": + found = [attr for attr in padding_const_node.attribute if attr.name == "value"] + tensor = found[0].t + else: + continue + if tensor is None or tensor.data_type not in [onnx_proto.TensorProto.INT32, onnx_proto.TensorProto.INT64]: continue value = onnx.numpy_helper.to_array(tensor) if value.ndim != 0: - warnings.warn(f"Embedding padding_idx must be a scalar, but got a tensor of shape {value.shape}") + self._logger.warning(f"Embedding padding_idx must be a scalar, but got a tensor of shape {value.shape}") continue padding_idx = value.item() @@ -102,8 +225,6 @@ def _initialize_loss_label_padding_inspector(self, model, user_input_names): _loss_label_graph_input_to_ignore_idx_map, which is later used for collecting data/compute sparsity information for labels. """ - if not self._enabled: - return def _default_label_preprocess(labels): return labels @@ -117,13 +238,24 @@ def _default_label_preprocess(labels): ): continue - tensor = self._try_get_initializer(model, node.input[3]) + tensor = None + padding_const_node = self._try_get_node_from_its_output(node.input[3]) + if padding_const_node is None: + padding_initializer_name = node.input[3] + tensor = self._try_get_initializer(model, padding_initializer_name) + + elif padding_const_node.op_type == "Constant": + found = [attr for attr in padding_const_node.attribute if attr.name == "value"] + tensor = found[0].t + else: + continue + if tensor is None or tensor.data_type not in [onnx_proto.TensorProto.INT32, onnx_proto.TensorProto.INT64]: continue value = onnx.numpy_helper.to_array(tensor) if value.ndim != 0: - warnings.warn( + self._logger.warning( f"SoftmaxCrossEntropyLossInternal ignore_index must be a scalar, but got a tensor of shape {value.shape}" ) continue @@ -135,6 +267,8 @@ def _default_label_preprocess(labels): label_preprocess_func = _default_label_preprocess reshape_node = self._try_get_node_from_its_output(node.input[1]) + # The label input comes from graph input or a Reshape node consuming a graph input, which is aligned with + # orttraining/orttraining/core/optimizer/compute_optimizer/sceloss_compute_optimization.cc. if reshape_node is None: if node.input[1] not in user_input_names: continue @@ -185,21 +319,40 @@ def _slice_label_preprocess(labels, s=starts[0], e=ends[0], st=steps[0]): [ignore_index, label_preprocess_func] ) - def inspect_from_input_data(self, name, inp): - if not self._enabled or not self._is_initialized: - return + def inspect_from_input_data(self, name: str, inp) -> Tuple[bool, float, float]: + """Inspect input data and print statistics. + + Args: + name: User input name. + inp: User input tensor. + Returns: + found: Whether the input name is found in `_embedding_graph_input_to_padding_idx_map` and + `_loss_label_graph_input_to_ignore_idx_map`. + embed_input_density: Density for the inspected embedding input if found to be True; otherwise, return 100. + label_input_density: Density for the inspected label input if found to be True; otherwise, return 100. + """ + if not self._is_initialized: + return (False, 100, 100) + + try: + data = inp.clone() + found, embed_input_density, label_input_density = self._inspect_embed_label_input(name, data) + if found: + self._current_step += 1 - data = inp.clone() - found = self._inspect_embed_label_input(name, data) - if found: - self._current_step += 1 + if self._current_step - self._last_step >= self._log_steps: + self._last_step = self._current_step + self._print_embed_label_stats() - if self._current_step - self._last_step >= self._log_steps: - self._last_step = self._current_step - self._print_embed_label_stats() + return (found, embed_input_density, label_input_density) + except Exception as e: + self._logger.warning(f"Failed to inspect input {name} due to {e}", UserWarning) + return (False, 100, 100) def _inspect_embed_label_input(self, name, data): found = False + min_embed_density = 100 + min_label_density = 100 if ( len(self._embedding_graph_input_to_padding_idx_map) > 0 and name in self._embedding_graph_input_to_padding_idx_map @@ -207,18 +360,23 @@ def _inspect_embed_label_input(self, name, data): ): for padding_idx in self._embedding_graph_input_to_padding_idx_map[name]: valid_token = torch.count_nonzero(data - padding_idx) - valid_token_per_batch = torch.count_nonzero(data - padding_idx, dim=1) + valid_token_per_batch = "N/A" + if data.dim() > 1: + valid_token_per_batch = str(torch.count_nonzero(data - padding_idx, dim=1).tolist()) total_token = data.numel() + embed_density = float(valid_token) / float(total_token) * 100 + if embed_density < 90: + min_embed_density = min(min_embed_density, embed_density) self._stats.append( [ self._current_step, "EMBED", name, padding_idx, - float(valid_token) / float(total_token) * 100, + embed_density, valid_token, total_token, - str(valid_token_per_batch.tolist()), + valid_token_per_batch, ] ) found = True @@ -232,13 +390,16 @@ def _inspect_embed_label_input(self, name, data): data_preprocessed = preprocess_func(data) valid_token = torch.count_nonzero(data_preprocessed - ignore_index) total_token = data_preprocessed.numel() + label_density = float(valid_token) / float(total_token) * 100 + if label_density < 90: + min_label_density = min(min_label_density, label_density) self._stats.append( [ self._current_step, "LABEL", name, ignore_index, - float(valid_token) / float(total_token) * 100, + label_density, valid_token, total_token, "N/A", @@ -246,7 +407,7 @@ def _inspect_embed_label_input(self, name, data): ) found = True - return found + return found, min_embed_density, min_label_density def _print_embed_label_stats(self): if len(self._stats) > 0: @@ -254,7 +415,7 @@ def _print_embed_label_stats(self): stat += "\t| {:<10} | {:<10} | {:<15} | {:<10} | {:<10} | {:<15} | {:<15} | {:<15} |\n".format( "STEP", "INPUT TYPE", - " INPUT NAME", + "INPUT NAME", "PAD IDX", "DENSITY", "VALID TOKENS", @@ -275,11 +436,11 @@ def _print_embed_label_stats(self): step, input_type, input_name, padding_idx, density, valid_token, total_token, valid_token_per_batch ) stat += "<<<\n" - print(stat) + self._logger.info(stat) self._stats.clear() def _try_get_node_from_its_output(self, name): - if name == "" or name not in self._tensor_to_node_map: # noqa: PLC1901 + if name == "" or name not in self._tensor_to_node_map: return None return self._tensor_to_node_map[name] @@ -297,3 +458,87 @@ def _try_get_initializer_value(self, model, name): return None value = onnx.numpy_helper.to_array(tensor) return value + + +class MemoryObserver: + """Memory inspector across the training lifetime. + + On different training/inference phases, `inspect_memory` is called to print out the memory usage, including + current/peak memory usage, current/peak inactive and non-releasable memory. + """ + + NORMALIZER_FACTOR = float(1024 * 1024) + NORMALIZER_UNIT = "MiB" + + def __init__(self, m: torch.nn.Module, logger: Logger): + self._logger = logger + self._current_step = 0 + self._rank = 0 + self._world_size = 1 + if torch.distributed.is_initialized(): + self._rank = torch.distributed.get_rank() + self._world_size = torch.distributed.get_world_size() + + self._rank_info = f"[{self._rank}/{self._world_size}]" + self._pre_phase = Phase.INVALID + self._last_phase = Phase.POST_BACKWARD if m.training else Phase.POST_FORWARD + + self._is_first_inspect = True + + def inspect_memory(self, cur_phase: Phase): + if not torch.cuda.is_available(): + return + + if self._is_first_inspect: + # Clean the memory cache and memory stats before the first time run forward pass, FOR EVERY RANK. + torch.cuda.empty_cache() + torch.cuda.reset_peak_memory_stats() + self._is_first_inspect = False + + if self._rank != 0: + return + + if cur_phase < Phase.PRE_FORWARD or cur_phase > self._last_phase: + raise RuntimeError(f"Invalid phase detected: {cur_phase}") + + if (cur_phase - self._pre_phase) != 1: + raise RuntimeError(f"Invalid phase transition detected: {self._pre_phase} -> {cur_phase}") + + cur_mem_allocated = self._normalize(torch.cuda.memory_allocated()) + max_mem_allocated = self._normalize(torch.cuda.max_memory_allocated()) + cur_mem_cached = self._normalize(torch.cuda.memory_reserved()) + max_mem_cached = self._normalize(torch.cuda.max_memory_reserved()) + torch_mem_stat = torch.cuda.memory_stats() + cur_mem_inactive = self._normalize(torch_mem_stat.get("inactive_split_bytes.all.current", 0)) + max_mem_inactive = self._normalize(torch_mem_stat.get("inactive_split_bytes.all.peak", 0)) + + mem_stats = [ + ["phase", _convert_phase_to_string(cur_phase)], + ["allocated", cur_mem_allocated], # current memory alloeated for tensors + ["max allocated", max_mem_allocated], # peak memory allocated for tensors + ["cached", cur_mem_cached], # current memory cached for caching allocator + ["max cached", max_mem_cached], # peak memory cached for caching allocator. + ["inactive", cur_mem_inactive], # amount of inactive, non-releasable memory + ["max inactive", max_mem_inactive], # peak of inactive, non-releasable memory + ] + + summ = f"{self._rank_info} step {self._current_step} memory ({MemoryObserver.NORMALIZER_UNIT})" + for stat in mem_stats: + summ += f" | {stat[0]}: {stat[1]}" + + # For the 10+ steps, only print when it is power of 2. + if self._current_step < 10 or (self._current_step & (self._current_step - 1) == 0): + self._logger.info(summ) + + if cur_phase == self._last_phase: + self._increase_step() + self._pre_phase = Phase.INVALID + return + + self._pre_phase = cur_phase + + def _increase_step(self): + self._current_step += 1 + + def _normalize(self, mem_size_in_bytes: Union[float, int]) -> str: + return f"{float(mem_size_in_bytes) / MemoryObserver.NORMALIZER_FACTOR:.0f}" diff --git a/orttraining/orttraining/python/training/ortmodule/_torch_module_factory.py b/orttraining/orttraining/python/training/ortmodule/_torch_module_factory.py index d2954a287e804..5a1b09803c3b2 100644 --- a/orttraining/orttraining/python/training/ortmodule/_torch_module_factory.py +++ b/orttraining/orttraining/python/training/ortmodule/_torch_module_factory.py @@ -2,13 +2,15 @@ # Licensed under the MIT License. # _torch_module_factory.py +from logging import Logger + from ._fallback import _FallbackManager from ._torch_module_ort import TorchModuleORT -from .debug_options import DebugOptions +from .options import DebugOptions class TorchModuleFactory: - def __call__(self, module, debug_options: DebugOptions, fallback_manager: _FallbackManager): + def __call__(self, module, debug_options: DebugOptions, fallback_manager: _FallbackManager, logger: Logger): """Creates a TorchModule instance based on the input module.""" - return TorchModuleORT(module, debug_options, fallback_manager) + return TorchModuleORT(module, debug_options, fallback_manager, logger) diff --git a/orttraining/orttraining/python/training/ortmodule/_torch_module_ort.py b/orttraining/orttraining/python/training/ortmodule/_torch_module_ort.py index f9798f0c70549..125590902294d 100644 --- a/orttraining/orttraining/python/training/ortmodule/_torch_module_ort.py +++ b/orttraining/orttraining/python/training/ortmodule/_torch_module_ort.py @@ -3,6 +3,7 @@ # _torch_module_ort.py from collections import OrderedDict +from logging import Logger from typing import Callable, Iterator, Optional, Tuple, TypeVar import torch @@ -11,19 +12,27 @@ from ._fallback import ORTModuleTorchModelException, _FallbackManager, wrap_exception from ._graph_execution_manager_factory import GraphExecutionManagerFactory from ._torch_module_interface import TorchModuleInterface -from .debug_options import DebugOptions +from .options import DebugOptions T = TypeVar("T", bound="torch.nn.Module") class TorchModuleORT(TorchModuleInterface): - def __init__(self, module: torch.nn.Module, debug_options: DebugOptions, fallback_manager: _FallbackManager): + def __init__( + self, + module: torch.nn.Module, + debug_options: DebugOptions, + fallback_manager: _FallbackManager, + logger: Logger, + ): super().__init__(module) self._flattened_module = _io._FlattenedModule(module) _utils.patch_torch_module_ort_forward_method(self) - self._execution_manager = GraphExecutionManagerFactory(self._flattened_module, debug_options, fallback_manager) + self._execution_manager = GraphExecutionManagerFactory( + self._flattened_module, debug_options, fallback_manager, logger + ) def _apply(self, fn): """Override original method to delegate execution to the flattened PyTorch user module""" diff --git a/orttraining/orttraining/python/training/ortmodule/_training_manager.py b/orttraining/orttraining/python/training/ortmodule/_training_manager.py index a90971b72e0ec..19effe2086e0a 100644 --- a/orttraining/orttraining/python/training/ortmodule/_training_manager.py +++ b/orttraining/orttraining/python/training/ortmodule/_training_manager.py @@ -3,7 +3,8 @@ # Licensed under the MIT License. # -------------------------------------------------------------------------- -import warnings +from logging import Logger +from typing import Tuple import onnx import torch @@ -11,27 +12,59 @@ from onnxruntime.capi import _pybind_state as C from onnxruntime.capi.onnxruntime_inference_collection import get_ort_device_type -from . import _are_deterministic_algorithms_enabled, _io, _logger, _use_deterministic_algorithms, _utils +from . import _are_deterministic_algorithms_enabled, _io, _use_deterministic_algorithms, _utils from ._execution_agent import TrainingAgent from ._fallback import ORTModuleFallbackException, _FallbackManager, _FallbackPolicy -from ._graph_execution_manager import GraphExecutionManager, _RunStateInfo, _SkipCheck -from .debug_options import DebugOptions +from ._gradient_accumulation_manager import GradientAccumulationManager +from ._graph_execution_manager import GraphExecutionManager, _RunStateInfo +from ._io import _FlattenedModule, _InputInfo, unflatten_user_output +from ._logger import ORTModuleInitPhase, SuppressLogs, TrackTime +from ._runtime_inspector import Phase +from ._utils import save_tuning_results, set_tuning_results +from .graph_transformer_registry import GraphTransformerRegistry +from .options import DebugOptions, _SkipCheck class TrainingManager(GraphExecutionManager): """Concrete instance of GraphExecutionManager that is able to manage the training model - TrainingManager is responsible for building and running the forward and backward graph of the training model + TrainingManager is responsible for building and running the forward and backward graph of the training model. """ - def __init__(self, model, debug_options: DebugOptions, fallback_manager: _FallbackManager): - super().__init__(model, debug_options, fallback_manager) + def __init__( + self, + model: _FlattenedModule, + debug_options: DebugOptions, + fallback_manager: _FallbackManager, + logger: Logger, + ): + super().__init__(model, debug_options, fallback_manager, logger) + self._export_mode = torch.onnx.TrainingMode.TRAINING self._forward_class = self._create_autofunction_class() @staticmethod - def execution_session_run_forward(execution_session, onnx_model, device, gradient_accumulation_manager, *inputs): - """Runs the forward graph on execution_session with given model inputs and device""" + def execution_session_run_forward( + execution_session, + onnx_model: onnx.ModelProto, + device: torch.device, + gradient_accumulation_manager: GradientAccumulationManager, + *inputs, + ) -> Tuple[Tuple[torch.Tensor, ...], _RunStateInfo]: + """Runs the forward pass on `execution_session` with given `onnx_model`, `device` and `inputs` + + Args: + execution_session (InferenceAgent or TrainingAgent): Agent which runs training. + onnx_model (onnx.ModelProto): ONNX model + device (torch.device): PyTorch device + gradient_accumulation_manager (GradientAccumulationManager): Gradient accumulation manager + inputs: (torch.Tensor or a container of): User inputs passed from ORTModule.forward(). + + Returns: + Returns a tuple (user_outputs, run_info): + user_outputs: The model output (either torch.Tensor or a container of torch.Tensor) + run_info: A _RunStateInfo which contains extra information about the execution of the graph + """ # TODO: Try to reuse the output buffers as some of the output tensors are same sizes, # especially the backward graph outputs. @@ -54,7 +87,9 @@ def execution_session_run_forward(execution_session, onnx_model, device, gradien # Run and return module outputs. execution_session.run_forward(forward_inputs, forward_outputs, state, gradient_accumulation_manager.cache) - user_outputs = gradient_accumulation_manager.extract_outputs_and_maybe_update_cache(forward_outputs, device) + user_outputs: Tuple[torch.Tensor, ...] = gradient_accumulation_manager.extract_outputs_and_maybe_update_cache( + forward_outputs, device + ) output_info = [(output.shape, output.device, output.dtype) for output in user_outputs] run_info = _RunStateInfo(state, output_info) @@ -76,8 +111,9 @@ def forward(ctx, *inputs): Module outputs are returned to the user """ + self._runtime_inspector.inspect_memory(Phase.PRE_FORWARD) - if self._skip_check.is_set(_SkipCheck.SKIP_CHECK_DEVICE) is False: + if self._runtime_options.skip_check.is_set(_SkipCheck.SKIP_CHECK_DEVICE) is False: # Assert that the input and model device match _utils._check_same_device(self._device, "Input argument to forward", *inputs) @@ -110,14 +146,18 @@ def forward(ctx, *inputs): for idx in self._graph_info.output_grad_indices_non_differentiable: ctx.mark_non_differentiable(user_outputs[idx]) + self._runtime_inspector.inspect_memory(Phase.POST_FORWARD) + return user_outputs @staticmethod def backward(ctx, *grad_outputs): """Performs backward pass based on grad wrt module output""" + self._runtime_inspector.inspect_memory(Phase.PRE_BACKWARD) + assert ctx.run_info is not None, "forward() or __call__() methods must be called before backward()" - if self._skip_check.is_set(_SkipCheck.SKIP_CHECK_DEVICE) is False: + if self._runtime_options.skip_check.is_set(_SkipCheck.SKIP_CHECK_DEVICE) is False: _utils._check_same_device(self._device, "Input argument to backward", *grad_outputs) # Unpack saved_tensor to trigger version detection that catches inplace corruption @@ -163,8 +203,11 @@ def backward(ctx, *grad_outputs): # Fast version: all backward_outputs are converted first. # This version only works if backward_outputs is an OrtValueVector. - transfered_backward_outputs = _utils._ortvalues_to_torch_tensor(backward_outputs, self._device) - return tuple(transfered_backward_outputs[idx] if idx != -1 else None for idx in self._gradient_map) + transferred_backward_outputs = _utils._ortvalues_to_torch_tensor(backward_outputs, self._device) + + self._runtime_inspector.inspect_memory(Phase.POST_BACKWARD) + + return tuple(transferred_backward_outputs[idx] if idx != -1 else None for idx in self._gradient_map) return _ORTModuleFunction @@ -174,6 +217,14 @@ def forward(self, *inputs, **kwargs): ONNX model is exported the first time this method is executed. Next, we build a full training graph with module_graph_builder. Finally, we instantiate the ONNX Runtime InferenceSession. + + The call stack is as follows: + ORTModule.forward(*inputs, **kwargs) -> + ORTModule._torch_module.forward(*inputs, **kwargs) where _torch_module is a TorchModuleORT instance -> + ORTModule._torch_module._execution_manager(is_training()).forward(*inputs, **kwargs) where: + TorchModuleORT._execution_manager(true) is a TrainingManager instance; + and TorchModuleORT._execution_manager(false) is an InferenceManager instance. + """ # Fallback to PyTorch due to failures *external* to forward(), @@ -182,34 +233,32 @@ def forward(self, *inputs, **kwargs): return self._fallback_manager.fallback(self._debug_options.logging.log_level, *inputs, **kwargs) try: - if ( - self._first_skip_check_warning is True - and self._skip_check.is_disabled() is False - and self._debug_options.logging.log_level <= _logger.LogLevel.WARNING - ): + if self._first_skip_check_warning is True and self._runtime_options.skip_check.is_disabled() is False: # Only change this after the firs time a warning is issued. self._first_skip_check_warning = False - warnings.warn( - f"Fast path enabled - skipping checks." - f" Rebuild graph: {self._skip_check.is_set(_SkipCheck.SKIP_CHECK_BUILD_GRADIENT)}," - f" Execution agent: {self._skip_check.is_set(_SkipCheck.SKIP_CHECK_EXECUTION_AGENT)}," - f" Device check: {self._skip_check.is_set(_SkipCheck.SKIP_CHECK_DEVICE)}", - UserWarning, + self._logger.info( + "Fast path enabled - skipping checks.Rebuild graph: %s, Execution agent: %s, Device check: %s", + self._runtime_options.skip_check.is_set(_SkipCheck.SKIP_CHECK_BUILD_GRADIENT), + self._runtime_options.skip_check.is_set(_SkipCheck.SKIP_CHECK_EXECUTION_AGENT), + self._runtime_options.skip_check.is_set(_SkipCheck.SKIP_CHECK_DEVICE), ) # If exporting module to ONNX for the first time, this skip check will not take effect. # It will only take effect on subsequent forward calls. build_gradient_graph = False if ( - self._skip_check.is_set(_SkipCheck.SKIP_CHECK_BUILD_GRADIENT) is False + self._runtime_options.skip_check.is_set(_SkipCheck.SKIP_CHECK_BUILD_GRADIENT) is False or not self._onnx_models.exported_model ): + self.time_tracker.start(ORTModuleInitPhase.EndToEnd) + build_gradient_graph = self._export_model(*inputs, **kwargs) + if build_gradient_graph: # If model was exported, then initialize the graph builder self._initialize_graph_builder() - # since the schema was just extracted while trying to export the model and it was either + # Since the schema was just extracted while trying to export the model and it was either # saved to self._input_info.schema or checked for equality with the self._input_info.schema # it should not need to be updated again. Pass it inside parse_inputs_for_onnx_export. input_info = _io.parse_inputs_for_onnx_export( @@ -223,12 +272,20 @@ def forward(self, *inputs, **kwargs): # Build the gradient graph if build_gradient_graph: - self._build_graph() + graph_transformer_config = self._get_graph_transformer_config() + # Set the config according to input inspection. + self._enable_conditional_optimizations(graph_transformer_config, inputs, kwargs) + + # Build the gradient graph + self._build_graph(graph_transformer_config) # If creating the execution agent for the first time, this skip check will not take effect. # It will only take effect on subsequent forward calls. create_execution_session = False - if self._skip_check.is_set(_SkipCheck.SKIP_CHECK_EXECUTION_AGENT) is False or not self._execution_agent: + if ( + self._runtime_options.skip_check.is_set(_SkipCheck.SKIP_CHECK_EXECUTION_AGENT) is False + or not self._execution_agent + ): device = _utils.get_device_from_module(self._original_module) or _utils.get_device_from_inputs( inputs, kwargs ) @@ -246,26 +303,44 @@ def forward(self, *inputs, **kwargs): self._create_execution_agent() self._gradient_accumulation_manager.initialize( - self._enable_grad_acc_optimization, self._flattened_module, self._graph_info + self._runtime_options.enable_grad_acc_optimization, self._flattened_module, self._graph_info ) + self.time_tracker.end(ORTModuleInitPhase.EndToEnd) + self._log_feature_stats() + self._gradient_accumulation_manager.maybe_update_cache_before_run() - return _io.unflatten_user_output( + if self._runtime_options.enable_zero_stage3_support: + self._append_pull_weight_trigger_as_input(kwargs, self._device) + + prepared_input_list, _, _ = _io._combine_input_buffers_initializers( + self._graph_initializers, + self._graph_info.user_input_names, + self._input_info, + self._flattened_module.named_buffers(), + inputs, + kwargs, + self._device, + self._runtime_inspector, + self._zero_stage3_param_map, + ) + + outputs = unflatten_user_output( self._module_output_schema, - self._forward_class.apply( - *_io._combine_input_buffers_initializers( - self._graph_initializers, - self._graph_info.user_input_names, - self._input_info, - self._flattened_module.named_buffers(), - inputs, - kwargs, - self._device, - self._rt_inspector.input_density_ob, - ) - ), + self._forward_class.apply(*prepared_input_list), ) + + if ( + create_execution_session + and self._runtime_options.enable_tuning + and self._runtime_options.tuning_results_path + ): + save_tuning_results( + self._execution_agent._inference_session, True, self._runtime_options.tuning_results_path + ) + + return outputs except ORTModuleFallbackException as e: # Exceptions subject to fallback are handled here self._fallback_manager.handle_exception(exception=e, log_level=self._debug_options.logging.log_level) @@ -282,14 +357,22 @@ def forward(self, *inputs, **kwargs): if self._fallback_manager.is_pending(): return self._fallback_manager.fallback(self._debug_options.logging.log_level, *inputs, **kwargs) - def _build_graph(self): + @TrackTime(ORTModuleInitPhase.BUILD_GRAPH) + @SuppressLogs(ORTModuleInitPhase.BUILD_GRAPH) + def _build_graph(self, graph_transformer_config): """Build an optimized gradient graph using the module_graph_builder""" - super()._build_graph() + super()._build_graph(graph_transformer_config) self._onnx_models.optimized_model = onnx.load_model_from_string(self._graph_builder.get_gradient_model()) - self._onnx_models.optimized_pre_grad_model = onnx.load_model_from_string( - self._graph_builder.get_forward_model() + + # Apply registered graph transformers to the optimized model + device_type = self._device.type + if device_type == "cuda" and self.is_rocm_pytorch: + device_type = "rocm" + GraphTransformerRegistry.transform_all( + type(self._flattened_module._original_module).__name__, device_type, self._onnx_models.optimized_model.graph ) + if self._debug_options.save_onnx_models.save: self._onnx_models.save_optimized_model( self._debug_options.save_onnx_models.path, @@ -317,11 +400,8 @@ def _build_graph(self): else: self._gradient_map.append(-1) - # Set up data sparsity inspection. - self._rt_inspector.input_density_ob.initialize( - self._onnx_models.optimized_pre_grad_model, self._graph_info.user_input_names - ) - + @TrackTime(ORTModuleInitPhase.CREATE_SESSION) + @SuppressLogs(ORTModuleInitPhase.CREATE_SESSION) def _create_execution_agent(self): """Creates a TrainingAgent that can run the forward and backward graph on the training model""" @@ -354,6 +434,7 @@ def _create_execution_agent(self): ] * len(bw_fetches_names) local_device_rank = self._device.index if device_type == "ort" else _utils.get_device_index(self._device) + self._execution_agent = TrainingAgent( self._onnx_models.optimized_model.SerializeToString(), fw_feed_names, @@ -366,7 +447,12 @@ def _create_execution_agent(self): local_device_rank, ) - def _reinitialize_graph_builder(self, input_info): + if not self._runtime_options.enable_tuning and self._runtime_options.tuning_results_path: + set_tuning_results( + self._execution_agent._inference_session, True, self._runtime_options.tuning_results_path + ) + + def _reinitialize_graph_builder(self, input_info: _InputInfo): """Return true if the module graph builder was reinitialized""" # Model may have unused params dropped after export and not part of self._graph_initializer_names_to_train diff --git a/orttraining/orttraining/python/training/ortmodule/_utils.py b/orttraining/orttraining/python/training/ortmodule/_utils.py index 0151cd532a7e9..91825fc492208 100644 --- a/orttraining/orttraining/python/training/ortmodule/_utils.py +++ b/orttraining/orttraining/python/training/ortmodule/_utils.py @@ -7,12 +7,13 @@ import copy import functools import inspect +import json +import logging import os import random import traceback import types -import warnings -from typing import List # noqa: F401 +from typing import Callable, List, Optional, Tuple, Union import numpy as np import torch @@ -22,11 +23,8 @@ from onnxruntime.capi import _pybind_state as C from onnxruntime.capi.onnxruntime_inference_collection import OrtValue -from onnxruntime.tools import pytorch_export_contrib_ops from . import _onnx_models -from ._custom_gradient_registry import CustomGradientRegistry -from ._custom_op_symbolic_registry import CustomOpSymbolicRegistry from ._fallback_exceptions import ORTModuleDeviceException, ORTModuleIOError, wrap_exception from ._torch_module_pytorch import TorchModulePytorch from .torch_cpp_extensions.cpu.aten_op_executor import load_aten_op_executor_cpp_extension @@ -49,7 +47,8 @@ def set_random_states(states): torch.cuda.set_rng_state(torch_cuda_state) -def _ortvalue_from_torch_tensor(torch_tensor): +def _ortvalue_from_torch_tensor(torch_tensor: torch.Tensor) -> C.OrtValue: + """Converts a torch tensor to an OrtValue.""" # TODO: Current DLPack doesn't support bool and PyTorch disables converting bool tensor to DLPack in recent commit. # https://github.com/pytorch/pytorch/blob/7e7be526c9d9179f35084e9cca5b5c5ad5172100/aten/src/ATen/DLConvertor.cpp#L41 # We need to convert bool tensor to unit8 tensor to workaround this. @@ -63,7 +62,9 @@ def _ortvalue_from_torch_tensor(torch_tensor): return C.OrtValue.from_dlpack(to_dlpack(torch_tensor), is_bool_tensor) -def _ortvalues_to_torch_tensor(ortvalues, device=None): +def _ortvalues_to_torch_tensor( + ortvalues: C.OrtValueVector, device: Optional[torch.device] = None +) -> Tuple[torch.Tensor, ...]: if len(ortvalues) == 0: return tuple() @@ -75,7 +76,7 @@ def _ortvalues_to_torch_tensor(ortvalues, device=None): if not isinstance(ortvalues, C.OrtValueVector): raise TypeError("ortvalues must be an instance of OrtValueVector not %r." % type(ortvalues)) - res = ortvalues.to_dlpacks(_from_dlpack) + res: List[torch.Tensor] = ortvalues.to_dlpacks(_from_dlpack) bool_indices = ortvalues.bool_tensor_indices() if len(bool_indices): # DLPack structure does not know for sure if it stores boolean @@ -97,7 +98,7 @@ def _ortvalues_to_torch_tensor(ortvalues, device=None): return tuple(res) -def _torch_tensor_to_dlpack(tensor): +def _torch_tensor_to_dlpack(tensor: torch.Tensor): # TODO: Current DLPack doesn't support bool and PyTorch disables converting bool tensor to DLPack in recent commit. # https://github.com/pytorch/pytorch/blob/7e7be526c9d9179f35084e9cca5b5c5ad5172100/aten/src/ATen/DLConvertor.cpp#L41 # We need to convert bool tensor to unit8 tensor to workaround this. @@ -110,7 +111,7 @@ def _torch_tensor_to_dlpack(tensor): return to_dlpack(tensor) -def _check_same_device(device, argument_str, *args): +def _check_same_device(device: torch.device, argument_str: str, *args): """Check that all tensor arguments in *args reside on the same device as the input device""" assert isinstance(device, torch.device), "`device` must be a valid `torch.device` object" @@ -126,7 +127,7 @@ def _check_same_device(device, argument_str, *args): ) -def get_device_index(device): +def get_device_index(device: Union[str, int, torch.device]) -> int: if isinstance(device, str): # could be 'cuda:0', 'cuda:1', or 'cpu'. with cpu, set index=0 device = torch.device(device) @@ -135,7 +136,7 @@ def get_device_index(device): return 0 if device.index is None else device.index -def get_device_str(device): +def get_device_str(device: Union[str, int, torch.device]) -> str: if isinstance(device, str): # could be 'cuda:0', 'cuda:1', or 'cpu'. with cpu, set index=0 if device.find(":") == -1: @@ -152,12 +153,15 @@ def get_device_str(device): return device -def get_device_from_module(module): +def get_device_from_module(module) -> Optional[torch.device]: """Returns the first device found in the `module`'s parameters or None Args: module (torch.nn.Module): PyTorch model to extract device from + Returns: + torch.device: Device extracted from `module`'s parameters or None + Raises: ORTModuleFallbackException: When more than one device is found at `module` """ @@ -175,12 +179,15 @@ def get_device_from_module(module): return device -def get_device_from_inputs(args, kwargs): +def get_device_from_inputs(args, kwargs) -> Optional[torch.device]: """Returns device from first PyTorch Tensor within args or kwargs Args: args: List with inputs kwargs: Dictionary with inputs + + Returns: + torch.device: Device extracted from `args` or `kwargs` or None """ device = None @@ -191,7 +198,7 @@ def get_device_from_inputs(args, kwargs): return device -def _create_iobinding(io_binding, inputs, model, device): +def _create_iobinding(io_binding, inputs, model, device: torch.device): """Creates IO binding for a `model` inputs and output""" for idx, value_info in enumerate(model.graph.input): io_binding.bind_ortvalue_input( @@ -206,7 +213,9 @@ def _create_iobinding(io_binding, inputs, model, device): io_binding.bind_output(value_info.name, device.type, device_id=device_id) -def check_for_name_collisions_and_bind_methods_to_ortmodule(ortmodule: torch.nn.Module, user_module: torch.nn.Module): +def check_for_name_collisions_and_bind_methods_to_ortmodule( + ortmodule: torch.nn.Module, user_module: torch.nn.Module, logger: logging.Logger +): """Warns if there are any common attributes between the user's model and ORTModule and binds user methods to ORTModule If there are methods defined on the user's model that ORTModule does not recognize (custom methods), @@ -246,7 +255,7 @@ def check_for_name_collisions_and_bind_methods_to_ortmodule(ortmodule: torch.nn. # This is a user defined/overridden method. Check for collisions. if attribute_name in ortmodule_attributes: # This is a user defined method, issue a warning. - warnings.warn( + logger.warning( f"User Module's attribute name {attribute_name} collides with ORTModule's attribute name. " "User Module's method may not be called upon invocation through ORTModule." ) @@ -260,7 +269,7 @@ def check_for_name_collisions_and_bind_methods_to_ortmodule(ortmodule: torch.nn. if attribute_name not in torch_module_attributes and attribute_name in ortmodule_attributes: # This is a user defined attribute that collides with ORTModule if attribute_name in ortmodule_attributes: - warnings.warn( + logger.warning( f"User Module's attribute name {attribute_name} collides with ORTModule's attribute name. " "User Module's attribute may not be returned when trying to retrieve the attribute through ORTModule." ) @@ -336,13 +345,6 @@ def switch_backend_to_pytorch(ortmodule, pytorch_module): ortmodule.forward = pytorch_module.forward -def warn_of_constant_inputs(data): - warnings.warn( - f"Received input of type {type(data)} which may be treated as a constant by ORT by default." - " Please consider moving constant arguments to the model constructor." - ) - - def patch_torch_module_ort_forward_method(torch_module_ort): def _forward(self, *inputs, **kwargs): """Forward pass starts here and continues at `_ORTModuleFunction.forward` @@ -380,19 +382,6 @@ def _forward(self, *inputs, **kwargs): functools.update_wrapper(ortmodule.forward.__func__, ortmodule._torch_module.forward.__func__) -def reinitialize_ortmodule(ortmodule): - # Re-register contrib OPs - pytorch_export_contrib_ops.register() - CustomOpSymbolicRegistry.register_all() - CustomGradientRegistry.register_all() - - # Re-initialize the ORTModule forward method - patch_ortmodule_forward_method(ortmodule) - - # Re-bind users custom methods to ORTModule - check_for_name_collisions_and_bind_methods_to_ortmodule(ortmodule, ortmodule.module) - - def reinitialize_torch_module_ort(torch_module): # Re-initialize the forward method patch_torch_module_ort_forward_method(torch_module) @@ -418,3 +407,57 @@ def reinitialize_graph_execution_manager(graph_execution_manager): def reinitialize_training_manager(training_manager): # Redefine training managers forward_class training_manager._forward_class = training_manager._create_autofunction_class() + + +def get_runtime_pytorch_version(): + from packaging import version + + return version.parse(torch.__version__.split("+")[0]) + + +def check_function_has_param(function: Callable, param_name: str) -> bool: + return param_name in inspect.signature(function).parameters + + +def get_fully_qualified_class_name(cls: type) -> str: + """Returns the fully qualified class name of the given class.""" + module = cls.__module__ + if module == "builtins": + return cls.__qualname__ # avoid outputs like 'builtins.str' + return module + "." + cls.__qualname__ + + +def save_tuning_results(session, is_training, tuning_results_path): + """Save the online Op tuning results to a json file in the specified path.""" + + os.makedirs(tuning_results_path, exist_ok=True) + suffix = "training" if is_training else "inference" + tuning_result_file = os.path.join(tuning_results_path, f"tuning_results_{suffix}.json") + with open(tuning_result_file, "w", encoding="utf-8") as f: + json.dump(session.get_tuning_results(), f, indent=4) + + +def set_tuning_results(session, is_training, tuning_results_path): + """Set the offline Op tuning results from a json file in the specified path.""" + + suffix = "training" if is_training else "inference" + tuning_result_file = os.path.join(tuning_results_path, f"tuning_results_{suffix}.json") + if os.path.isfile(tuning_result_file): + with open(tuning_result_file, encoding="utf-8") as f: + session.set_tuning_results(json.load(f)) + + +def get_rank() -> int: + """Returns the rank of the current process. If distributed training is not initialized, returns 0.""" + if torch.distributed.is_initialized(): + return torch.distributed.get_rank() + + return 0 + + +def get_world_size() -> int: + """Returns the world size of the current process. If distributed training is not initialized, returns 1.""" + if torch.distributed.is_initialized(): + return torch.distributed.get_world_size() + + return 1 diff --git a/orttraining/orttraining/python/training/ortmodule/_zero_stage3_compatibility.py b/orttraining/orttraining/python/training/ortmodule/_zero_stage3_compatibility.py new file mode 100644 index 0000000000000..17756600d601e --- /dev/null +++ b/orttraining/orttraining/python/training/ortmodule/_zero_stage3_compatibility.py @@ -0,0 +1,312 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# -------------------------------------------------------------------------- + +from typing import Dict, List, Optional, Tuple, Union + +import torch +from onnx import ModelProto, NodeProto, TensorProto, ValueInfoProto, helper + +from onnxruntime.capi._pybind_state import register_torch_autograd_function +from onnxruntime.training.utils import pytorch_dtype_to_onnx + +from ._custom_autograd_function_exporter import PythonOpShapeInferStore +from ._utils import get_fully_qualified_class_name + +STAGE3_PULL_WEIGHT_TRIGGER_NAME = "pull_weight_trigger" +STAGE3_PULL_WEIGHT_TRIGGER_OUTPUT_DTYPE = TensorProto.FLOAT +STAGE3_PULL_WEIGHT_TRIGGER_OUTPUT_SHAPE = [1] + + +def post_processing_enable_zero_stage3_compat( + exported_model: ModelProto, + zero_stage3_named_params: Dict[str, torch.nn.parameter.Parameter], + all_param_names: List[str], +) -> ModelProto: + """This function is used to enable zero stage3 compatibility. + + Args: + exported_model (ModelProto): The exported model. + zero_stage3_named_params (Optional[Dict[str, torch.nn.parameter.Parameter]]): The offload named parameters. + all_param_names (List[str]): All parameter names. + """ + + # Register symbolic shape inference functions for PythonOp used in DeepSpeed ZeRO stage3. + _register_symbolic_shape_infer_functions() + + # Create weight retrieving function using zero_stage3_named_params. + func_full_qual_name = _create_weight_retrieval_function(zero_stage3_named_params) + + consumer_map = {} + for node in exported_model.graph.node: + for inp in node.input: + if inp not in consumer_map: + consumer_map[inp] = [] + + if node not in consumer_map[inp]: + consumer_map[inp].append(node) + + def _get_param_pull_trigger_name(param_name: str) -> str: + return f"pull_{param_name}" + + def _get_func_name(node: NodeProto) -> Optional[str]: + for attr in node.attribute: + if attr.name == "func_name": + return attr.s.decode("utf-8") if isinstance(attr.s, bytes) else attr.s + return None + + # Create weight retrieving PythonOp. + new_input, weight_pull_node = _create_weight_retrieval_pythonop( + zero_stage3_named_params, + func_full_qual_name, + STAGE3_PULL_WEIGHT_TRIGGER_NAME, + [_get_param_pull_trigger_name(pname) for pname in zero_stage3_named_params], + STAGE3_PULL_WEIGHT_TRIGGER_OUTPUT_DTYPE, + STAGE3_PULL_WEIGHT_TRIGGER_OUTPUT_SHAPE, + ) + + from onnxruntime.training.utils.hooks._zero_offload_subscriber import ORTZeROOffloadPreForwardFunction + + prefowrad_function_name = get_fully_qualified_class_name(ORTZeROOffloadPreForwardFunction) + + # Connect weight consumers to use the full-sized parameter output of ORTZeROOffloadPreForwardFunction. + for graph_input in exported_model.graph.input: + if graph_input.name not in zero_stage3_named_params: + continue + + if graph_input.name not in consumer_map: + continue + + consumers = consumer_map[graph_input.name] + pre_forward_pythonop_node = None + + for c in consumers: + if c.op_type != "PythonOp": + continue + + func_name = _get_func_name(c) + if func_name == prefowrad_function_name: + assert ( + pre_forward_pythonop_node is None + ), "Multiple ORTZeROOffloadPreForwardFunction nodes found, it should not happen" + pre_forward_pythonop_node = c + + if pre_forward_pythonop_node is None: + raise RuntimeError( + "Fail to find ORTZeROOffloadPreForwardFunction for partitioned param: " + graph_input.name + ) + + index_offset_on_python_op_input = [] + for i, input_name in enumerate(pre_forward_pythonop_node.input): + if input_name == graph_input.name: + index_offset_on_python_op_input.append(i) + + assert ( + len(index_offset_on_python_op_input) == 1 + ), f"index_offset_on_python_op_input length is not 1: {index_offset_on_python_op_input}" + + reverse_index_among_inputs = index_offset_on_python_op_input[0] - len(pre_forward_pythonop_node.input) + new_input_name = _get_param_pull_trigger_name(graph_input.name) + pre_forward_pythonop_node.input[index_offset_on_python_op_input[0]] = new_input_name + + _update_python_op_input_related_attributes( + pre_forward_pythonop_node, + new_input_name, + len(STAGE3_PULL_WEIGHT_TRIGGER_OUTPUT_SHAPE), # new rank + STAGE3_PULL_WEIGHT_TRIGGER_OUTPUT_DTYPE, # new data type + ) + + output_index = reverse_index_among_inputs + len(pre_forward_pythonop_node.output) + pre_forward_pythonop_node.output[output_index] = graph_input.name + + # If the consumer of original `graph_input.name` is PythonOp, we need also update its attributes because now + # `graph_input.name` as output of pre_forward_pythonop_node, is full-sized parameter, the rank might differ + # from the original one. + for c in consumers: + if c == pre_forward_pythonop_node or c.op_type != "PythonOp": + continue + _update_python_op_input_related_attributes( + c, + graph_input.name, + len(zero_stage3_named_params[graph_input.name].ds_shape), # new rank + pytorch_dtype_to_onnx(zero_stage3_named_params[graph_input.name].dtype), # new data type + ) + + # Delete exported_model.graph.input + graph_inputs_to_remove = [ + graph_input for graph_input in exported_model.graph.input if graph_input.name in zero_stage3_named_params + ] + for input_to_remove in graph_inputs_to_remove: + exported_model.graph.input.remove(input_to_remove) + + # Re-order graph input to make sure the weight pull trigger is before all parameter inputs. + offset = 0 + for graph_input in exported_model.graph.input: + if graph_input.name in all_param_names: + break + offset += 1 + + exported_model.graph.input.insert(offset, new_input) + exported_model.graph.node.insert(0, weight_pull_node) + + return exported_model + + +def _create_weight_retrieval_function( + zero_stage3_named_params: Optional[Dict[str, torch.nn.parameter.Parameter]] +) -> str: + """This function is used to create a weight retrieving function using zero_stage3_named_params.""" + + class WeightRetrievalFunction(torch.autograd.Function): + @staticmethod + def forward(ctx, weight_in_trigger): + params = list(zero_stage3_named_params.values()) + ctx.params = params + ctx.dtype = weight_in_trigger.dtype + ctx.device = weight_in_trigger.device + ctx.shape = weight_in_trigger.shape + return (torch.zeros(ctx.shape, device=ctx.device, dtype=ctx.dtype),) * len(params) + + @staticmethod + def backward(ctx, *grad_outputs): + return torch.zeros(ctx.shape, device=ctx.device, dtype=ctx.dtype) + + @staticmethod + def infer_shape( + node: NodeProto, + tensor_input_shapes: List[Optional[List[Union[int, str]]]], + tensor_input_dtypes: List[torch.onnx.TensorProtoDataType], + ) -> Tuple[List[Optional[List[Union[int, str]]]], List[torch.onnx.TensorProtoDataType]]: + param_count = len(zero_stage3_named_params.values()) + tensor_output_shapes = [ + tensor_input_shapes[0], + ] * param_count + tensor_output_dtypes = [ + tensor_input_dtypes[0], + ] * param_count + return tensor_output_shapes, tensor_output_dtypes + + func_full_qual_name = get_fully_qualified_class_name(WeightRetrievalFunction) + register_torch_autograd_function(func_full_qual_name, WeightRetrievalFunction) + PythonOpShapeInferStore.register(WeightRetrievalFunction) + + return func_full_qual_name + + +def _register_symbolic_shape_infer_functions(): + """This function is used to register symbolic shape inference functions for PythonOp used in + DeepSpeed ZeRO stage3.""" + + def _simple_pass_through_infer_shape( + node: NodeProto, + tensor_input_shapes: List[Optional[List[Union[int, str]]]], + tensor_input_dtypes: List[torch.onnx.TensorProtoDataType], + ) -> Tuple[List[Optional[List[Union[int, str]]]], List[torch.onnx.TensorProtoDataType]]: + return tensor_input_shapes, tensor_input_dtypes + + PythonOpShapeInferStore.register_func( + "deepspeed.runtime.zero.parameter_offload.PreBackwardFunction", _simple_pass_through_infer_shape + ) + PythonOpShapeInferStore.register_func( + "deepspeed.runtime.zero.parameter_offload.PostBackwardFunction", _simple_pass_through_infer_shape + ) + + def _linear_infer_shape( + node: NodeProto, + tensor_input_shapes: List[Optional[List[Union[int, str]]]], + tensor_input_dtypes: List[torch.onnx.TensorProtoDataType], + ) -> Tuple[List[Optional[List[Union[int, str]]]], List[torch.onnx.TensorProtoDataType]]: + # output = input.matmul(weight.t()) + tensor_input_shapes[0] # input + shape2 = tensor_input_shapes[1] # weight + output_shape = tensor_input_shapes[0] + output_shape[-1] = shape2[-2] + return [output_shape], [tensor_input_dtypes[0]] + + PythonOpShapeInferStore.register_func( + "deepspeed.runtime.zero.linear.LinearFunctionForZeroStage3", _linear_infer_shape + ) + + +def _create_weight_retrieval_pythonop( + zero_stage3_named_params: Optional[Dict[str, torch.nn.parameter.Parameter]], + func_full_qual_name: str, + input_name: str, + output_names: List[str], + STAGE3_PULL_WEIGHT_TRIGGER_OUTPUT_DTYPE, + STAGE3_PULL_WEIGHT_TRIGGER_OUTPUT_SHAPE: List[int], +) -> Tuple[ValueInfoProto, NodeProto]: + """This function is used to create a weight retrieving PythonOp.""" + offload_param_count = 0 if zero_stage3_named_params is None else len(zero_stage3_named_params) + new_input = helper.make_tensor_value_info( + input_name, STAGE3_PULL_WEIGHT_TRIGGER_OUTPUT_DTYPE, STAGE3_PULL_WEIGHT_TRIGGER_OUTPUT_SHAPE + ) + output_rank_for_pull_weight_trigger = len(STAGE3_PULL_WEIGHT_TRIGGER_OUTPUT_SHAPE) + output_dtype_for_pull_weight_trigger = STAGE3_PULL_WEIGHT_TRIGGER_OUTPUT_DTYPE + output_tensor_ranks = [ + output_rank_for_pull_weight_trigger, + ] * offload_param_count + output_tensor_types = [ + output_dtype_for_pull_weight_trigger, + ] * offload_param_count + + node_attributes = { + "comment": "", + "inplace": 0, + "input_convention": "d", + "input_tensor_ranks": [len(STAGE3_PULL_WEIGHT_TRIGGER_OUTPUT_SHAPE)], + "input_tensor_types": [STAGE3_PULL_WEIGHT_TRIGGER_OUTPUT_DTYPE], + "output_tensor_ranks": output_tensor_ranks, + "output_tensor_types": output_tensor_types, + "training_mode": 1, + "func_name": func_full_qual_name, + } + + weight_pull_node = helper.make_node( + "PythonOp", + [input_name], + ["pull_weight_trigger_ctx", *output_names], + "pull_weight_trigger", # node name + "PythonOp for weight retrieving.", + "com.microsoft", + **node_attributes, + ) + + return new_input, weight_pull_node + + +def _update_python_op_input_related_attributes(node: NodeProto, input_name: str, new_rank: int, new_dtype: int): + """This function is used to update PythonOp's input related attributes, e.g. + input_tensor_ranks and input_tensor_types. + + Args: + node (NodeProto): The PythonOp node. + input_name (str): The input name to be updated. + new_rank (int): The new rank of the input, to be used in input_tensor_ranks. + new_dtype (int): The new data type of the input, to be used in input_tensor_types. + """ + input_tensor_ranks = None + input_tensor_dtypes = None + rank_attr = None + dtype_attr = None + for attr in node.attribute: + if attr.name == "input_tensor_ranks": + input_tensor_ranks = attr.ints + rank_attr = attr + if attr.name == "input_tensor_types": + input_tensor_dtypes = attr.ints + dtype_attr = attr + + assert input_tensor_ranks is not None, "input_tensor_ranks is None" + assert input_tensor_dtypes is not None, "input_tensor_dtypes is None" + + for index, node_input_name in enumerate(node.input): + if node_input_name == input_name: + input_tensor_ranks[index] = new_rank + input_tensor_dtypes[index] = new_dtype + + node.attribute.remove(rank_attr) + node.attribute.remove(dtype_attr) + node.attribute.append(helper.make_attribute("input_tensor_ranks", input_tensor_ranks)) + node.attribute.append(helper.make_attribute("input_tensor_types", input_tensor_dtypes)) diff --git a/orttraining/orttraining/python/training/ortmodule/debug_options.py b/orttraining/orttraining/python/training/ortmodule/debug_options.py deleted file mode 100644 index 700789668a313..0000000000000 --- a/orttraining/orttraining/python/training/ortmodule/debug_options.py +++ /dev/null @@ -1,118 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. -# debug_options.py - -import os - -from ._logger import LogLevel - - -class _SaveOnnxOptions: - """Configurable option to save ORTModule intermediate onnx models.""" - - # class variable - _path_environment_key = "ORTMODULE_SAVE_ONNX_PATH" - - def __init__(self, save, name_prefix): - self._save, self._name_prefix, self._path = self._extract_info(save, name_prefix) - - def _extract_info(self, save, name_prefix): - # get the destination path from os env variable - destination_path = os.getenv(_SaveOnnxOptions._path_environment_key, os.getcwd()) - # perform validation only when save is True - if save: - self._validate(save, name_prefix, destination_path) - return save, name_prefix, destination_path - - def _validate(self, save, name_prefix, destination_path): - # check if directory is writable - if not os.access(destination_path, os.W_OK): - raise OSError( - f"Directory {destination_path} is not writable. Please set the {_SaveOnnxOptions._path_environment_key} environment variable to a writable path." - ) - - # check if input prefix is a string - if not isinstance(name_prefix, str): - raise TypeError(f"Expected name prefix of type str, got {type(name_prefix)}.") - - # if save_onnx is set, save_onnx_prefix must be a non empty string - if not name_prefix: - raise ValueError("onnx_prefix must be provided when save_onnx is set.") - - @property - def save(self): - return self._save - - @property - def name_prefix(self): - return self._name_prefix - - @property - def path(self): - return self._path - - -class _LoggingOptions: - """Configurable option to set the log level in ORTModule.""" - - # class variable - _log_level_environment_key = "ORTMODULE_LOG_LEVEL" - - def __init__(self, log_level): - self._log_level = self._extract_info(log_level) - - def _extract_info(self, log_level): - # get the log_level from os env variable - # OS environment variable log level superseeds the locally provided one - self._validate(log_level) - log_level = LogLevel[os.getenv(_LoggingOptions._log_level_environment_key, log_level.name)] - return log_level - - def _validate(self, log_level): - # check if log_level is an instance of LogLevel - if not isinstance(log_level, LogLevel): - raise TypeError(f"Expected log_level of type LogLevel, got {type(log_level)}.") - - @property - def log_level(self): - return self._log_level - - -class DebugOptions: - """Configurable debugging options for ORTModule. - - Args: - log_level (:obj:`LogLevel`, optional): Configure ORTModule log level. Defaults to LogLevel.WARNING. - log_level can also be set by setting the environment variable "ORTMODULE_LOG_LEVEL" to one of - "VERBOSE", "INFO", "WARNING", "ERROR", "FATAL". In case both are set, the environment variable - takes precedence. - save_onnx (:obj:`bool`, optional): Configure ORTModule to save onnx models. Defaults to False. - The output directory of the onnx models by default is set to the current working directory. - To change the output directory, the environment variable "ORTMODULE_SAVE_ONNX_PATH" can be - set to the destination directory path. - onnx_prefix (:obj:`str`, optional): Name prefix to the ORTModule ONNX models saved file names. - Must be provided if save_onnx is True - - Raises: - OSError: If save_onnx is True and output directory is not writable. - TypeError: If save_onnx is True and name_prefix is not a valid string. Or if - log_level is not an instance of LogLevel. - ValueError: If save_onnx is True and name_prefix is an empty string. - - """ - - def __init__(self, log_level=LogLevel.WARNING, save_onnx=False, onnx_prefix=""): - self._save_onnx_models = _SaveOnnxOptions(save_onnx, onnx_prefix) - self._logging = _LoggingOptions(log_level) - - @property - def save_onnx_models(self): - """Accessor for the ONNX saving configuration.""" - - return self._save_onnx_models - - @property - def logging(self): - """Accessor for the logging configuration.""" - - return self._logging diff --git a/orttraining/orttraining/python/training/ortmodule/experimental/hierarchical_ortmodule/_hierarchical_ortmodule.py b/orttraining/orttraining/python/training/ortmodule/experimental/hierarchical_ortmodule/_hierarchical_ortmodule.py index cb1715ccd80f7..dcaa202d46fd8 100644 --- a/orttraining/orttraining/python/training/ortmodule/experimental/hierarchical_ortmodule/_hierarchical_ortmodule.py +++ b/orttraining/orttraining/python/training/ortmodule/experimental/hierarchical_ortmodule/_hierarchical_ortmodule.py @@ -1,14 +1,14 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -# debug_options.py +# _hierarchical_ortmodule.py import tempfile import warnings import torch -from .... import ortmodule -from ... import ORTModule -from ...debug_options import DebugOptions, LogLevel +from onnxruntime.training import ortmodule +from onnxruntime.training.ortmodule import ORTModule +from onnxruntime.training.ortmodule.options import DebugOptions, LogLevel # nn.Module's in this set are considered exportable to ONNX. # For other nn.Module's, torch.onnx.export is called to check if @@ -113,9 +113,9 @@ def recursive_hook(module): # We cannot skip module in allowlist because it's possible that a module is called multiple times # so that we still need to know the number of different input sets and use _IteratedORTModule to handle it. handle_pool.append(module.register_forward_pre_hook(record_args)) - for _, sub_module in module._modules.items(): + for sub_module in module._modules.values(): if isinstance(sub_module, torch.nn.ModuleList): - for _, sub_module_item in sub_module._modules.items(): + for sub_module_item in sub_module._modules.values(): recursive_hook(sub_module_item) else: recursive_hook(sub_module) @@ -142,7 +142,7 @@ def try_export(module, args): except Exception as e: if self._log_level <= LogLevel.WARNING: warnings.warn( - f"Failed to export module with type {type(module).__name__}. Error message: {str(e)}", + f"Failed to export module with type {type(module).__name__}. Error message: {e!s}", UserWarning, ) return False @@ -176,9 +176,9 @@ def try_export(module, args): # No sub-module exists, so this module is a leaf return - for _, sub_module in sub_module_dict.items(): + for sub_module in sub_module_dict.values(): if isinstance(sub_module, torch.nn.ModuleList): - for _, sub_module_item in sub_module._modules.items(): + for sub_module_item in sub_module._modules.values(): check_exportable(sub_module_item) else: check_exportable(sub_module) @@ -268,7 +268,7 @@ def recursive_wrap(module, save_onnx=False, onnx_prefix=""): recursive_wrap(self._original_module, self._save_onnx, self._name_prefix) if self._log_level <= LogLevel.WARNING: warnings.warn( - f"Wrapped module: {str(self._original_module)}.", + f"Wrapped module: {self._original_module!s}.", UserWarning, ) self._initialized = True diff --git a/orttraining/orttraining/python/training/ortmodule/experimental/json_config/_load_config_from_json.py b/orttraining/orttraining/python/training/ortmodule/experimental/json_config/_load_config_from_json.py index 2f1451497ffcd..76c8ce3bf3220 100644 --- a/orttraining/orttraining/python/training/ortmodule/experimental/json_config/_load_config_from_json.py +++ b/orttraining/orttraining/python/training/ortmodule/experimental/json_config/_load_config_from_json.py @@ -9,11 +9,9 @@ from types import SimpleNamespace from onnxruntime.capi import _pybind_state as C -from onnxruntime.training import ortmodule +from onnxruntime.training.ortmodule._fallback import _FallbackPolicy +from onnxruntime.training.ortmodule.options import DebugOptions, LogLevel, _SaveOnnxOptions, _SkipCheck -from ..._fallback import _FallbackPolicy -from ..._graph_execution_manager import _SkipCheck -from ...debug_options import DebugOptions, LogLevel, _SaveOnnxOptions from . import JSON_PATH_ENVIRONMENT_KEY log = logging.getLogger(__name__) @@ -39,19 +37,19 @@ def _load_propagate_cast_ops(ortmodule_config_accessor, data): log.info(f"Found keyword {_load_propagate_cast_ops.loading_key} in json. Loading attributes from file.") def _update_strategy(): - ortmodule_config_accessor._propagate_cast_ops_strategy = C.PropagateCastOpsStrategy.__members__[ + ortmodule_config_accessor._runtime_options.propagate_cast_ops_strategy = C.PropagateCastOpsStrategy.__members__[ data.PropagateCastOps.Strategy ] def _update_level(): - ortmodule_config_accessor._propagate_cast_ops_level = data.PropagateCastOps.Level + ortmodule_config_accessor._runtime_options.propagate_cast_ops_level = data.PropagateCastOps.Level def _update_allow(): - ortmodule_config_accessor._propagate_cast_ops_allow = data.PropagateCastOps.Allow + ortmodule_config_accessor._runtime_options.propagate_cast_ops_allow = data.PropagateCastOps.Allow key_to_function_mapping = {"Strategy": _update_strategy, "Level": _update_level, "Allow": _update_allow} - for key, _ in data.PropagateCastOps.__dict__.items(): + for key in data.PropagateCastOps.__dict__: key_to_function_mapping[key]() @@ -64,8 +62,7 @@ def _load_use_external_gpu_allocator(ortmodule_config_accessor, data): assert isinstance( data.UseExternalGPUAllocator, bool ), f"{_load_use_external_gpu_allocator.loading_key} must be a boolean" - ortmodule_config_accessor._use_external_gpu_allocator = data.UseExternalGPUAllocator - ortmodule_config_accessor._get_torch_gpu_allocator_function_addresses() + ortmodule_config_accessor._runtime_options.use_external_gpu_allocator = data.UseExternalGPUAllocator def _load_enable_custom_autograd_function(ortmodule_config_accessor, data): @@ -79,7 +76,11 @@ def _load_enable_custom_autograd_function(ortmodule_config_accessor, data): assert isinstance( data.EnableCustomAutogradFunction, bool ), f"{_load_enable_custom_autograd_function.loading_key} must be a boolean" - ortmodule_config_accessor._enable_custom_autograd_function = data.EnableCustomAutogradFunction + + from onnxruntime.training.ortmodule._custom_autograd_function import enable_custom_autograd_support + + enable_custom_autograd_support(data.EnableCustomAutogradFunction) + ortmodule_config_accessor._runtime_options.enable_custom_autograd_function = data.EnableCustomAutogradFunction def _load_enable_grad_acc_optimization(ortmodule_config_accessor, data): @@ -91,7 +92,7 @@ def _load_enable_grad_acc_optimization(ortmodule_config_accessor, data): assert isinstance( data.EnableGradAccOptimization, bool ), f"{_load_enable_grad_acc_optimization.loading_key} must be a boolean" - ortmodule_config_accessor._enable_grad_acc_optimization = data.EnableGradAccOptimization + ortmodule_config_accessor._runtime_options.enable_grad_acc_optimization = data.EnableGradAccOptimization def _load_run_symbolic_shape_infer(ortmodule_config_accessor, data): @@ -103,7 +104,7 @@ def _load_run_symbolic_shape_infer(ortmodule_config_accessor, data): assert isinstance( data.RunSymbolicShapeInference, bool ), f"{_load_run_symbolic_shape_infer.loading_key} must be a boolean" - ortmodule_config_accessor._run_symbolic_shape_infer = data.RunSymbolicShapeInference + ortmodule_config_accessor._runtime_options.run_symbolic_shape_infer = data.RunSymbolicShapeInference def _load_use_static_shape(ortmodule_config_accessor, data): @@ -113,7 +114,7 @@ def _load_use_static_shape(ortmodule_config_accessor, data): log.info(f"Found keyword {_load_use_static_shape.loading_key} in json. Loading attributes from file.") assert isinstance(data.UseStaticShape, bool), f"{_load_use_static_shape.loading_key} must be a boolean" - ortmodule_config_accessor._use_static_shape = data.UseStaticShape + ortmodule_config_accessor._runtime_options.use_static_shape = data.UseStaticShape def _load_skip_check(ortmodule_config_accessor, data): @@ -124,7 +125,7 @@ def _load_skip_check(ortmodule_config_accessor, data): skip_check = reduce(lambda x, y: x | y, [_SkipCheck[name] for name in data.SkipCheck]) if skip_check.value > 0: - ortmodule_config_accessor._skip_check = skip_check + ortmodule_config_accessor._runtime_options.skip_check = skip_check def _load_debug_options(ortmodule_config_accessor, data): @@ -161,7 +162,7 @@ def _update_onnx_path(): "SaveONNXPath": _update_onnx_path, } - for key, _ in data.DebugOptions.__dict__.items(): + for key in data.DebugOptions.__dict__: key_to_function_mapping[key]() debug_options = DebugOptions(log_level=log_level, save_onnx=save_onnx, onnx_prefix=onnx_prefix) @@ -177,7 +178,7 @@ def _load_use_memory_efficient_gradient(ortmodule_config_accessor, data): assert isinstance( data.UseMemoryEfficientGradient, bool ), f"{_load_use_memory_efficient_gradient.loading_key} must be a boolean" - ortmodule_config_accessor._use_memory_efficient_gradient = data.UseMemoryEfficientGradient + ortmodule_config_accessor._runtime_options.use_memory_efficient_gradient = data.UseMemoryEfficientGradient def _load_fallback_policy(ortmodule_config_accessor, data): @@ -198,7 +199,7 @@ def _load_onnx_opset_version(ortmodule_config_accessor, data): log.info(f"Found keyword {_load_onnx_opset_version.loading_key} in json. Loading attributes from file.") assert isinstance(data.OnnxOpsetVersion, int), f"{_load_onnx_opset_version.loading_key} must be an int" - ortmodule.ONNX_OPSET_VERSION = data.OnnxOpsetVersion + ortmodule_config_accessor._runtime_options.onnx_opset_version = data.OnnxOpsetVersion def _define_load_function_keys(): @@ -300,5 +301,5 @@ def load_from_json(ortmodule, path=None): # update the debug config for both train and eval modes ortmodule_config_accessor = ortmodule._torch_module._execution_manager(training_mode) # iterate over the json data instead of checking for keys in json to catch key errors - for key, _ in data.__dict__.items(): + for key in data.__dict__: load_functions[key](ortmodule_config_accessor, data) diff --git a/orttraining/orttraining/python/training/ortmodule/graph_transformer_registry.py b/orttraining/orttraining/python/training/ortmodule/graph_transformer_registry.py new file mode 100644 index 0000000000000..70056179c140e --- /dev/null +++ b/orttraining/orttraining/python/training/ortmodule/graph_transformer_registry.py @@ -0,0 +1,47 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# -------------------------------------------------------------------------- + +from typing import Callable + +from onnx.onnx_ml_pb2 import GraphProto + + +class GraphTransformerRegistry: + _TRANSFORMER_FUNCS = {} # noqa: RUF012 + + @classmethod + def register(cls, target_modules: str, devices: str, priority: int, fn: Callable[[GraphProto], None]): + modules = [] + if target_modules == "all": + modules.append("all") + else: + modules = target_modules.split("|") + for module in modules: + if module in cls._TRANSFORMER_FUNCS: + cls._TRANSFORMER_FUNCS[module].append((fn, devices, priority)) + else: + cls._TRANSFORMER_FUNCS[module] = [(fn, devices, priority)] + + @classmethod + def transform_all(cls, module_name: str, device: str, graph: GraphProto): + transformers_to_apply = [] + if "all" in cls._TRANSFORMER_FUNCS: + transformers_to_apply.extend(cls._TRANSFORMER_FUNCS["all"]) + if module_name in cls._TRANSFORMER_FUNCS: + transformers_to_apply.extend(cls._TRANSFORMER_FUNCS[module_name]) + transformers_to_apply = [x for x in transformers_to_apply if x[1] == "all" or device in x[1]] + transformers_to_apply.sort(key=lambda x: x[2], reverse=True) + for fn, _, _ in transformers_to_apply: + fn(graph) + + +# target_modules can be multiple module names separated by "|", or "all" means apply to all modules. +# devices can be multiple device types separated by "|" or "all" means apply to all devices. +def register_graph_transformer(target_modules: str = "all", devices: str = "all", priority: int = 0): + def graph_transformer_wrapper(fn): + GraphTransformerRegistry.register(target_modules, devices, priority, fn) + return fn + + return graph_transformer_wrapper diff --git a/orttraining/orttraining/python/training/ortmodule/options.py b/orttraining/orttraining/python/training/ortmodule/options.py new file mode 100644 index 0000000000000..0eb6790d7a462 --- /dev/null +++ b/orttraining/orttraining/python/training/ortmodule/options.py @@ -0,0 +1,374 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# options.py + +import os +from enum import IntFlag +from functools import reduce +from logging import Logger + +from packaging import version + +from onnxruntime.capi import _pybind_state as C +from onnxruntime.training import ortmodule + +from ._fallback import _FallbackPolicy +from ._logger import LogLevel +from ._utils import get_runtime_pytorch_version, parse_os_env_skip_check_flags + + +class _SaveOnnxOptions: + """Configurable option to save ORTModule intermediate onnx models.""" + + # class variable + _path_environment_key = "ORTMODULE_SAVE_ONNX_PATH" + + def __init__(self, save, name_prefix, path: str): + self._save, self._name_prefix, self._path = self._extract_info(save, name_prefix, path) + + def _extract_info(self, save, name_prefix, path: str): + # get the destination path from os env variable + default_path = path if len(path) > 0 else os.getcwd() + destination_path = os.getenv(_SaveOnnxOptions._path_environment_key, default_path) + # perform validation only when save is True + if save: + self._validate(save, name_prefix, destination_path) + return save, name_prefix, destination_path + + def _validate(self, save, name_prefix, destination_path): + # check if directory is writable + if not os.access(destination_path, os.W_OK): + raise OSError( + f"Directory {destination_path} is not writable. Please set the " + f"{_SaveOnnxOptions._path_environment_key} environment variable to a writable path." + ) + + # check if input prefix is a string + if not isinstance(name_prefix, str): + raise TypeError(f"Expected name prefix of type str, got {type(name_prefix)}.") + + # if save_onnx is set, save_onnx_prefix must be a non empty string + if not name_prefix: + raise ValueError("onnx_prefix must be provided when save_onnx is set.") + + @property + def save(self): + return self._save + + @property + def name_prefix(self): + return self._name_prefix + + @property + def path(self): + return self._path + + +class _LoggingOptions: + """Configurable option to set the log level in ORTModule.""" + + # class variable + _log_level_environment_key = "ORTMODULE_LOG_LEVEL" + + def __init__(self, log_level): + self._log_level = self._extract_info(log_level) + + def _extract_info(self, log_level): + # get the log_level from os env variable + # OS environment variable log level superseeds the locally provided one + self._validate(log_level) + log_level = LogLevel[os.getenv(_LoggingOptions._log_level_environment_key, log_level.name)] + return log_level + + def _validate(self, log_level): + # check if log_level is an instance of LogLevel + if not isinstance(log_level, LogLevel): + raise TypeError(f"Expected log_level of type LogLevel, got {type(log_level)}.") + + @property + def log_level(self) -> LogLevel: + return self._log_level + + +class DebugOptions: + """Configurable debugging options for ORTModule. + + Args: + log_level (:obj:`LogLevel`, optional): Configure ORTModule log level. Defaults to LogLevel.WARNING. + log_level can also be set by setting the environment variable "ORTMODULE_LOG_LEVEL" to one of + "VERBOSE", "INFO", "WARNING", "ERROR", "FATAL". In case both are set, the environment variable + takes precedence. + save_onnx (:obj:`bool`, optional): Configure ORTModule to save onnx models. Defaults to False. + The output directory of the onnx models by default is set to the current working directory. + To change the output directory, the environment variable "ORTMODULE_SAVE_ONNX_PATH" can be + set to the destination directory path. + onnx_prefix (:obj:`str`, optional): Name prefix to the ORTModule ONNX models saved file names. + Must be provided if save_onnx is True + + Raises: + OSError: If save_onnx is True and output directory is not writable. + TypeError: If save_onnx is True and name_prefix is not a valid string. Or if + log_level is not an instance of LogLevel. + ValueError: If save_onnx is True and name_prefix is an empty string. + + """ + + def __init__(self, log_level=LogLevel.WARNING, save_onnx=False, onnx_prefix="", save_path="", config=None): + self.log_level = log_level + self.save_onnx = save_onnx + self.onnx_prefix = onnx_prefix + + self._save_onnx_models = _SaveOnnxOptions(self.save_onnx, self.onnx_prefix, save_path) + self._logging = _LoggingOptions(self.log_level) + + @property + def save_onnx_models(self): + """Accessor for the ONNX saving configuration.""" + + return self._save_onnx_models + + @property + def logging(self): + """Accessor for the logging configuration.""" + + return self._logging + + @property + def torch_exporter_filter(self): + """Accessor for the filter export logs configuration.""" + torch_version = get_runtime_pytorch_version() + if self.log_level >= LogLevel.INFO: + if torch_version < version.parse("2.0"): + return [ + # WARNING: The shape inference of com.microsoft::SoftmaxCrossEntropyLossInternal type is missing, so it may result in wrong shape inference for the exported graph. Please consider adding it in symbolic function. + # WARNING: The shape inference of com.microsoft::PythonOp type is missing, so it may result in wrong shape inference for the exported graph. Please consider adding it in symbolic function. + # WARNING: The shape inference of org.pytorch.aten::ATen type is missing, so it may result in wrong shape inference for the exported graph. Please consider adding it in symbolic function. + # WARNING: The shape inference of prim::Constant type is missing, so it may result in wrong shape inference for the exported graph. Please consider adding it in symbolic function. + "type is missing, so it may result in wrong shape inference", + # Warning: Checker does not support models with experimental ops: ATen + "Checker does not support models with experimental ops:", + "Dropout is a training op and should not be exported in inference mode.", + # Warning: Shape inference does not support models with experimental operators: ATen + "Shape inference does not support models with experimental operators:", + # Warning: Unsupported operator Trilu. No schema registered for this operator. + # Warning: Unsupported operator ATen. No schema registered for this operator. + # Warning: Unsupported operator SoftmaxCrossEntropyLossInternal. No schema registered for this operator. + "No schema registered for this operator.", + ] + return [ + # [W shape_type_inference.cpp:1974] Warning: The shape inference of com.microsoft::PythonOp type is missing, so it may result in wrong shape inference for the exported graph. Please consider adding it in symbolic function. (function UpdateReliable) + "type is missing, so it may result in wrong shape inference", + # diagnostics [WARNING] - None + "[WARNING] - None", + ] + + return None + + @property + def onnxruntime_log_filter(self): + """Accessor for the filter onnxruntime logs configuration.""" + if self.log_level >= LogLevel.INFO: + return [ + "CleanUnusedInitializersAndNodeArgs] Removing initializer", + "Serializing optimized model with Graph Optimization level greater than ORT_ENABLE_EXTENDED", + ] + return None + + +class _SkipCheck(IntFlag): + """Enumeration to specify which checks should be skipped, allowing faster execution""" + + SKIP_CHECK_DISABLED = 1 + SKIP_CHECK_DEVICE = 2 + SKIP_CHECK_BUILD_GRADIENT = 4 + SKIP_CHECK_EXECUTION_AGENT = 8 + + def is_set(self, check): + """Check whether `check` is set on the `_SkipCheck instance + + SKIP_CHECK_DISABLED implies the check will return False + """ + + return not _SkipCheck.is_disabled(self) and check in self + + def is_disabled(self): + """Check whether `_SkipCheck.SKIP_CHECK_DISABLED is set on the `_SkipCheck instance""" + + return _SkipCheck.SKIP_CHECK_DISABLED in self + + +class _RuntimeOptions: + """Configurable runtime options for ORTModule.""" + + def __init__(self, logger: Logger): + """Constructor for Options. + + Initially set all the options to their default values, then override them with the values + from the environment variables. + """ + self._logger = logger + + self.onnx_opset_version = ortmodule.ONNX_OPSET_VERSION + self.conv_algo_search = "HEURISTIC" + + # Configuration for cast optimization. + # Specify cast propagation strategy. Currently, three strategies are available: + # NONE, INSERT-AND-REDUCE and FLOOD-FILL + # The default is FLOOD_FILL, expand FP16 computation regions in the graph using + # allowed opcodes for the given level. + self.propagate_cast_ops_strategy = C.PropagateCastOpsStrategy.FLOOD_FILL + # Optimize by moving Cast operations if propagate_cast_ops_level is non-negative. + # - If the propagate_cast_ops_level is set to zero, then the transformation considers only the opcodes + # specified by propagate_cast_ops_allow as "FP16 safe", to insert/(re)move cast operations before/after + # to perform such operations in reduced (16-bit) precision. + # - If propagate_cast_ops_level is positive, 1 or 2, then in addition to opcode codes specified by + # propagate_cast_ops_allow, use onnxruntime predetermined list of opcodes considered safe to move + # before/after the cast operation. + # - Onnxruntime Level 1 predetermined "FP16 safe" opcodes include only opcodes that do not perform + # any computation such as Transpose, Split, Reshape, etc., or the computation is actually in Float + # such as GeLU, etc. + # - Whereas Level 2 predetermined "FP16 safe" opcodes include opcodes that perform computation using + # contrib ops, Dropout, LayerNormalization, etc. + self.propagate_cast_ops_level = 1 + # List of opcodes to be considered safe to move before/after the cast operation if propagate_cast_ops_level + # is zero. + self.propagate_cast_ops_allow = [] + + # default execution order is priority-based for both dynamic/static shape input for now + # if we observe the benefit of static shape, we can expose this flag to the user + self.use_static_shape = False + + # flag to enable symbolic shape inference for dynamic shape inputs to improve performance + self.run_symbolic_shape_infer = True + + # PyTorch custom Autograd function support + from ._custom_autograd_function import custom_autograd_function_enabler + + self.enable_custom_autograd_function = custom_autograd_function_enabler.state + + self.use_external_gpu_allocator = True + + # WIP feature to enable caching in Gradient accumulation scenario. + self.enable_grad_acc_optimization = False + + # Memory-aware gradient builder. + self.use_memory_efficient_gradient = False + + # Configuration for compute optimization. + self.enable_compute_optimizer = True + self.enable_sparse_optimizer = True + self.label_sparsity_ratio = "" + self.embed_sparsity_ratio = "" + self.enable_embedding_sparse_optimizer = False # TODO(pengwa): remove once validation on more models are done. + + # Configuration for memory optimization. + self.memory_optimizer_config = "" + self.probe_level = "1" + + # Configuration for dev tools. + self.print_input_density = False + self.print_memory_stat = False + + # Configuration for fallback. + self.fallback_policy = ortmodule.ORTMODULE_FALLBACK_POLICY + + # Configuration for skip check. + # Indicators of some logic have been executed previously and thus could be skipped for faster training + # default is enabled, if not defined in os env + self.skip_check = _SkipCheck( + _SkipCheck.SKIP_CHECK_DEVICE | _SkipCheck.SKIP_CHECK_BUILD_GRADIENT | _SkipCheck.SKIP_CHECK_EXECUTION_AGENT + ) + + # Triton support. + self.enable_triton = False + self.enable_tuning = False + self.max_tuning_duration_ms = 0 + self.tuning_results_path = "" + + # Cache exported model + self.ortmodule_cache_dir = "" + + # Experimental features. + self.enable_zero_stage3_support = False # Once enabled, cannot be disabled. + + # Override the feature config if it exists in os env. + self._override_from_env_vars() + + def _override_from_env_vars(self): + self.onnx_opset_version = int(os.getenv("ORTMODULE_ONNX_OPSET_VERSION", self.onnx_opset_version)) + self.conv_algo_search = os.getenv("ORTMODULE_CONV_ALGO_SEARCH", self.conv_algo_search) + if self.conv_algo_search not in ["HEURISTIC", "EXHAUSTIVE"]: + self._logger.warning("Invalid value of env CONV_ALGO_SEARCH. Must be HEURISTIC or EXHAUSTIVE.") + self.conv_algo_search = "HEURISTIC" + + # Configuration for compute optimization. + compute_optimizer_reset = False + if "ORTMODULE_ENABLE_COMPUTE_OPTIMIZER" in os.environ: + self.enable_compute_optimizer = int(os.getenv("ORTMODULE_ENABLE_COMPUTE_OPTIMIZER")) == 1 + compute_optimizer_reset = True + + if "ORTMODULE_ENABLE_SPARSE_OPTIMIZER" in os.environ or compute_optimizer_reset: + if "ORTMODULE_ENABLE_SPARSE_OPTIMIZER" in os.environ: + self.enable_sparse_optimizer = int(os.getenv("ORTMODULE_ENABLE_SPARSE_OPTIMIZER")) == 1 + self.enable_sparse_optimizer = self.enable_compute_optimizer and self.enable_sparse_optimizer + + # TODO(pengwa): remove once validation on more models are done. + if "ORTMODULE_ENABLE_EMBEDDING_SPARSE_OPTIMIZER" in os.environ: + self.enable_embedding_sparse_optimizer = ( + self.enable_sparse_optimizer and int(os.getenv("ORTMODULE_ENABLE_EMBEDDING_SPARSE_OPTIMIZER")) == 1 + ) + + # Configuration for memory optimization. + self.memory_optimizer_config = os.getenv("ORTMODULE_MEMORY_OPT_CONFIG", self.memory_optimizer_config) + self.probe_level = os.getenv("ORTMODULE_MEMORY_OPT_PROBE_RECOMPUTE_LEVEL", self.probe_level) + + # Configuration for dev tools. + if "ORTMODULE_PRINT_INPUT_DENSITY" in os.environ: + self.print_input_density = int(os.getenv("ORTMODULE_PRINT_INPUT_DENSITY")) == 1 + if "ORTMODULE_PRINT_MEMORY_STATS" in os.environ: + self.print_memory_stat = int(os.getenv("ORTMODULE_PRINT_MEMORY_STATS")) == 1 + + # Configuration for fallback. + if "ORTMODULE_FALLBACK_POLICY" in os.environ: + self.fallback_policy = os.getenv("ORTMODULE_FALLBACK_POLICY") + if isinstance(self.fallback_policy, str): + self.fallback_policy = _FallbackPolicy[self.fallback_policy] + + # Configuration for skip check. + if "ORTMODULE_SKIPCHECK_POLICY" in os.environ: + self.skip_check = reduce( + lambda x, y: x | y, + [_SkipCheck[name] for name in parse_os_env_skip_check_flags("ORTMODULE_SKIPCHECK_POLICY")], + ) + + # Configuration for Triton. + # Enable Triton op executor if Triton is installed, backend has support and environment variable is set. + if ( + "ORTMODULE_USE_TRITON" in os.environ + and int(os.getenv("ORTMODULE_USE_TRITON")) == 1 + and C.is_triton_enabled() + ): + try: + import triton # noqa: F401 + except ImportError: + pass + else: + self.enable_triton = True + + if "ORTMODULE_ENABLE_TUNING" in os.environ and int(os.getenv("ORTMODULE_ENABLE_TUNING")) == 1: + self.enable_tuning = True + if "ORTMODULE_MAX_TUNING_DURATION_MS" in os.environ: + max_tuning_duration_ms = int(os.getenv("ORTMODULE_MAX_TUNING_DURATION_MS")) + if max_tuning_duration_ms > 0: + self.max_tuning_duration_ms = max_tuning_duration_ms + if "ORTMODULE_TUNING_RESULTS_PATH" in os.environ: + self.tuning_results_path = os.getenv("ORTMODULE_TUNING_RESULTS_PATH") + + # Cache exported model + if "ORTMODULE_CACHE_DIR" in os.environ: + self._logger.info("ORTModule cache optimization is ON.") + self.ortmodule_cache_dir = os.getenv("ORTMODULE_CACHE_DIR") + + # Experimental features. + if "ORTMODULE_ENABLE_ZERO_STAGE3" in os.environ and int(os.getenv("ORTMODULE_ENABLE_ZERO_STAGE3")) == 1: + self.enable_zero_stage3_support = True diff --git a/orttraining/orttraining/python/training/ortmodule/ortmodule.py b/orttraining/orttraining/python/training/ortmodule/ortmodule.py index 85508601722d6..b5c52bdaef3c6 100644 --- a/orttraining/orttraining/python/training/ortmodule/ortmodule.py +++ b/orttraining/orttraining/python/training/ortmodule/ortmodule.py @@ -3,14 +3,16 @@ # Licensed under the MIT License. # -------------------------------------------------------------------------- # isort: skip_file -# Import ordering is important in this module to aviod circular dependencies +# Import ordering is important in this module to avoid circular dependencies + from ._torch_module_factory import TorchModuleFactory from ._torch_module_ort import TorchModuleORT from ._custom_op_symbolic_registry import CustomOpSymbolicRegistry from ._custom_gradient_registry import CustomGradientRegistry from . import _utils -from .debug_options import DebugOptions +from .options import DebugOptions from ._fallback import _FallbackManager, _FallbackPolicy, ORTModuleFallbackException +from ._logger import configure_ortmodule_logger from onnxruntime.training import ortmodule from onnxruntime.tools import pytorch_export_contrib_ops @@ -33,7 +35,7 @@ class ORTModule(torch.nn.Module): debug_options (:obj:`DebugOptions`, optional): debugging options for ORTModule. """ - def __init__(self, module, debug_options=None): + def __init__(self, module: torch.nn.Module, debug_options: Optional[DebugOptions] = None): # NOTE: torch.nn.Modules that call setattr on their internal attributes regularly # (for example PyTorch Lightning), will trigger regular re-exports. This is # because ORTModule auto detects such setattrs on the original module and @@ -51,9 +53,14 @@ def __init__(self, module, debug_options=None): if not debug_options: debug_options = DebugOptions() + self._logger = configure_ortmodule_logger(debug_options.logging.log_level) + # Fallback settings self._fallback_manager = _FallbackManager( - pytorch_module=module, policy=ortmodule.ORTMODULE_FALLBACK_POLICY, retry=ortmodule.ORTMODULE_FALLBACK_RETRY + pytorch_module=module, + policy=ortmodule.ORTMODULE_FALLBACK_POLICY, + retry=ortmodule.ORTMODULE_FALLBACK_RETRY, + logger=self._logger, ) try: @@ -63,19 +70,21 @@ def __init__(self, module, debug_options=None): super().__init__() - self._torch_module = TorchModuleFactory()(module, debug_options, self._fallback_manager) + self._torch_module = TorchModuleFactory()(module, debug_options, self._fallback_manager, self._logger) _utils.patch_ortmodule_forward_method(self) # Support contrib OPs pytorch_export_contrib_ops.register() - CustomOpSymbolicRegistry.register_all() + CustomOpSymbolicRegistry.register_all( + self._torch_module._execution_manager(module.training)._runtime_options.onnx_opset_version + ) CustomGradientRegistry.register_all() # Warn user if there are name collisions between user model's and ORTModule attributes # And if there are custom methods defined on the user's model, copy and bind them to # ORTModule. - _utils.check_for_name_collisions_and_bind_methods_to_ortmodule(self, module) + _utils.check_for_name_collisions_and_bind_methods_to_ortmodule(self, module, self._logger) except ORTModuleFallbackException as e: # Although backend is switched to PyTorch here, @@ -110,8 +119,7 @@ def __init__(self, module, debug_options=None): # This declaration is for automatic document generation purposes only # The actual forward implementation is bound during ORTModule initialization def forward(self, *inputs, **kwargs): - """Delegate the :meth:`~torch.nn.Module.forward` pass of PyTorch training to - ONNX Runtime. + """Delegate the :meth:`~torch.nn.Module.forward` pass of PyTorch training to ONNX Runtime. The first call to forward performs setup and checking steps. During this call, ORTModule determines whether the module can be trained with ONNX Runtime. For @@ -119,9 +127,8 @@ def forward(self, *inputs, **kwargs): Execution is interupted if ONNX Runtime cannot process the model for training. Args: - *inputs and **kwargs represent the positional, variable positional, keyword - and variable keyword arguments defined in the user's PyTorch module's forward - method. Values can be torch tensors and primitive types. + inputs: positional, variable positional inputs to the PyTorch module's forward method. + kwargs: keyword and variable keyword arguments to the PyTorch module's forward method. Returns: The output as expected from the forward method defined by the user's @@ -312,4 +319,15 @@ def __getstate__(self): def __setstate__(self, state): self.__dict__.update(state) - _utils.reinitialize_ortmodule(self) + # Re-register contrib OPs + pytorch_export_contrib_ops.register() + CustomOpSymbolicRegistry.register_all( + self._torch_module._execution_manager(self.module.training)._runtime_options.onnx_opset_version + ) + CustomGradientRegistry.register_all() + + # Re-initialize the ORTModule forward method + _utils.patch_ortmodule_forward_method(self) + + # Re-bind users custom methods to ORTModule + _utils.check_for_name_collisions_and_bind_methods_to_ortmodule(self, self.module, self._logger) diff --git a/orttraining/orttraining/python/training/ortmodule/torch_cpp_extensions/cpu/torch_interop_utils/torch_interop_utils.cc b/orttraining/orttraining/python/training/ortmodule/torch_cpp_extensions/cpu/torch_interop_utils/torch_interop_utils.cc index 32d458bb3913e..e55aacb2334b2 100644 --- a/orttraining/orttraining/python/training/ortmodule/torch_cpp_extensions/cpu/torch_interop_utils/torch_interop_utils.cc +++ b/orttraining/orttraining/python/training/ortmodule/torch_cpp_extensions/cpu/torch_interop_utils/torch_interop_utils.cc @@ -4,8 +4,9 @@ #include #include #include +#include -// In Torch forward run (e.g. THPFunction_apply), ctx of type THPFunction* (which is also a PyObject*) +// In PyTorch forward run (e.g. THPFunction_apply), ctx of type THPFunction* (which is also a PyObject*) // is created (https://github.com/pytorch/pytorch/blob/15532595209d2daf34d35e10f8d3d3b64966aea2/torch/csrc/autograd/python_function.cpp#L673). // The ctx is used to run user-defined forward function and backward function as the first // parameter. The same time, a cdata of type std::shared_ptr is created @@ -19,7 +20,7 @@ // b). the consumer operator of forward run outputs, will let its own PyNode/Node (gradient function) // owns the grad_fn_ (of type std::shared_ptr) of all inputs that require grad. // https://github.com/pytorch/pytorch/blob/15532595209d2daf34d35e10f8d3d3b64966aea2/torch/csrc/autograd/function.h#L263 -// BUT, if we run torch computation within PythonOp, b) is lost. SO, for some cases, where forward outputs +// BUT, if we run torch computation within PythonOp, b) is lost. So for some cases, where forward outputs // are not used and freed before backward function runs, the grad_fn_ (std::shared_ptr) references // in a) will be released. Without b)'s reference, grad_fn_ release PyNode as reference count reach 0; // Then when PythonOpGrad runs, segment fault. @@ -33,12 +34,16 @@ class PyNodeSharedPointerPool { return pool; }; - void RegisterGradFunc(const size_t& ctx_address, torch::autograd::AutogradMeta* autograd_meta) { + void RegisterGradFuncAndRemoveFromAutoGrad(const size_t& ctx_address, + torch::autograd::AutogradMeta* autograd_meta) { auto it = grad_fns_.find(ctx_address); TORCH_CHECK(it == grad_fns_.end(), "should not register grad_fn twice for ctx ", ctx_address); // Add new entry if key hasn't been registered. + // After this, the grad_fn_ is removed from torch autograd. grad_fns_.emplace(ctx_address, std::move(autograd_meta->grad_fn_)); + TORCH_CHECK(autograd_meta->grad_fn_ == nullptr, "fail to remove grad_fn_ from torch autograd for ctx ", + ctx_address); }; void UnRegisterGradFunc(const size_t& ctx_address) { @@ -90,8 +95,10 @@ void clear_grad_fns_for_next_edges(at::Tensor target, std::vector sa // will release the AccumulateGrad function. if (dynamic_cast(node_func)) { if (grad_fn_to_tensor_map.find(node_func) != grad_fn_to_tensor_map.end()) { - // skip the edges that connect to saved_tensors. Because when unpack ctx.saved_tensors (using input, = ctx.saved_tensors) in backward, - // there is such a check : if the saved tensor is a leaf and requires grad, it it should have grad accumulator. + // skip the edges that connect to saved_tensors. Because when unpack ctx.saved_tensors using + // following code in backward: + // input, = ctx.saved_tensors + // there is such a check: if the saved tensor is a leaf and requires grad, it should have grad accumulator. // If we clean the edge, then an exception "RuntimeError: No grad accumulator for a saved leaf!" will be thrown continue; } else { @@ -101,26 +108,26 @@ void clear_grad_fns_for_next_edges(at::Tensor target, std::vector sa } } -void register_grad_fn(size_t ctx_address, at::Tensor target) { +void register_grad_fn_and_remove_from_autograd(size_t ctx_address, at::Tensor target) { torch::autograd::AutogradMeta* autograd_meta = torch::autograd::impl::get_autograd_meta(target); - PyNodeSharedPointerPool::GetInstance().RegisterGradFunc(ctx_address, autograd_meta); + PyNodeSharedPointerPool::GetInstance().RegisterGradFuncAndRemoveFromAutoGrad(ctx_address, autograd_meta); } void unregister_grad_fn(size_t ctx_address) { PyNodeSharedPointerPool::GetInstance().UnRegisterGradFunc(ctx_address); } -// Supposed to be cleared on python program exit to resolve following issue: -// When training program exits, PyNodeSharedPointerPool destructor is called, if grad_fns_ is not empty, -// PyNode::release_variables() will be called. -// (https://github.com/pytorch/pytorch/blob/15532595209d2daf34d35e10f8d3d3b64966aea2/torch/csrc/autograd/python_function.cpp#L168) -// The other hand, there is known issue when acquiring GIL in pybind11 destructors, there will be probably deadlock issue. -// (https://github.com/pybind/pybind11/issues/1446) -// The resolution here, we remove all maintained states before program exits. +// Supposed to be cleared on python program exit to resolve the following issue: +// When training program exits, PyNodeSharedPointerPool destructor is called, if grad_fns_ is not empty, +// PyNode::release_variables() will be called. +// (https://github.com/pytorch/pytorch/blob/15532595209d2daf34d35e10f8d3d3b64966aea2/torch/csrc/autograd/python_function.cpp#L168) +// On The other hand, there is a known issue when acquiring GIL in pybind11 destructors, there will be +// probably a deadlock issue. (https://github.com/pybind/pybind11/issues/1446) +// The resolution here, we remove all maintained states before the program exits. -// A known existing issue: when forward functions is called repeatedly without corresponding backward calls, -// grad functions keeps accumulating without releasing, there might be memory (bound to those gradient function) leaks. -// Ideally this usually won't happen in real training case, so it should be fine. +// A known existing issue: when forward functions are called repeatedly without corresponding backward calls, +// grad functions keep accumulating without releasing, there might be memory (bound to those gradient functions) leaks. +// Ideally this usually won't happen in real training cases, so it should be fine. // We CANNOT explicitly clear grad functions before each forward pass to mitigate the known issue above. // For example: @@ -128,16 +135,27 @@ void unregister_grad_fn(size_t ctx_address) { // loss2 = forward_run(inputs2) // loss = loss1 + loss2 // loss.backward() -// If we clear grad functions in the beginning of the second `forward_run`, when `loss.backward()` runs, +// If we clear grad functions at the beginning of the second `forward_run`, when `loss.backward()` runs, // the backward path of `loss1` will fail to run PythonOpGrad ops (if there is any). void clear_all_grad_fns() { PyNodeSharedPointerPool::GetInstance().ClearAll(); } +bool get_materialize_grads(at::Tensor target) { + torch::autograd::AutogradMeta* autograd_meta = torch::autograd::impl::get_autograd_meta(target); + const auto& grad_fn = autograd_meta->grad_fn_; + auto py_node_fn = dynamic_cast(grad_fn.get()); + TORCH_CHECK(py_node_fn != nullptr, "grad_fn is not PyNode type."); + THPFunction* py_fn = (THPFunction*)py_node_fn->obj; + return py_fn->materialize_grads; +} + PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { - m.def("register_grad_fn", ®ister_grad_fn, "increase grad_fn shared pointer reference."); - m.def("unregister_grad_fn", &unregister_grad_fn, "release grad_fn shared pointer reference."); - m.def("clear_all_grad_fns", &clear_all_grad_fns, "clear all grad_fn shared pointer references."); + m.def("register_grad_fn_and_remove_from_autograd", ®ister_grad_fn_and_remove_from_autograd, + "Increase grad_fn shared pointer reference."); + m.def("unregister_grad_fn", &unregister_grad_fn, "Release grad_fn shared pointer reference."); + m.def("clear_all_grad_fns", &clear_all_grad_fns, "Clear all grad_fn shared pointer references."); m.def("clear_grad_fns_for_next_edges", &clear_grad_fns_for_next_edges, - "remove reference on next edges' gradient functions."); + "Remove reference on next edges' gradient functions."); + m.def("get_materialize_grads", &get_materialize_grads, "Return whether materialize_grads is enabled or not."); } diff --git a/orttraining/orttraining/python/training/orttrainer_options.py b/orttraining/orttraining/python/training/orttrainer_options.py index fc8322855ddb4..c63ac6f82c87f 100644 --- a/orttraining/orttraining/python/training/orttrainer_options.py +++ b/orttraining/orttraining/python/training/orttrainer_options.py @@ -482,7 +482,7 @@ def __init__(self, options={}): # noqa: B006 def __repr__(self): return "{%s}" % str( ", ".join( - f"'{k}': {repr(v)}" + f"'{k}': {v!r}" for (k, v) in self.__dict__.items() if k not in ["_original_opts", "_validated_opts", "_main_class_name"] ) diff --git a/orttraining/orttraining/python/training/postprocess.py b/orttraining/orttraining/python/training/postprocess.py index b2da6186b62cf..6c2adb6af7978 100644 --- a/orttraining/orttraining/python/training/postprocess.py +++ b/orttraining/orttraining/python/training/postprocess.py @@ -385,7 +385,7 @@ def layer_norm_transform(model): all_nodes.append(node) for node in layer_norm_nodes: - all_nodes.append(node) + all_nodes.append(node) # noqa: PERF402 graph.ClearField("node") graph.node.extend(all_nodes) diff --git a/orttraining/orttraining/python/training/torchdynamo/ort_backend.py b/orttraining/orttraining/python/training/torchdynamo/ort_backend.py index b8d7990e64cf8..a576bc20ed330 100644 --- a/orttraining/orttraining/python/training/torchdynamo/ort_backend.py +++ b/orttraining/orttraining/python/training/torchdynamo/ort_backend.py @@ -5,7 +5,7 @@ import dataclasses import logging -from typing import Any, Callable, Dict, Mapping, Set, Tuple, Union +from typing import Any, Dict, List, Mapping, Optional, Set, Tuple, Union import numpy as np import onnx @@ -14,17 +14,21 @@ import torch._ops import torch._prims.executor import torch.fx -import torch.jit import torch.onnx -import torch.onnx._onnx_supported_ops -from torch._decomp import decomposition_table + +# TODO(wschin,justinchuby): Since the internal APIs are not stable, please +# contact us if you hit errors. +import torch.onnx._internal +import torch.onnx._internal.diagnostics +import torch.onnx._internal.exporter +import torch.onnx._internal.fx.decomposition_table +import torch.onnx._internal.fx.passes from torch._subclasses.fake_tensor import FakeTensor -from torch.fx.experimental.proxy_tensor import make_fx from torch.fx.passes.fake_tensor_prop import FakeTensorProp from torch.fx.passes.infra.partitioner import CapabilityBasedPartitioner from torch.fx.passes.operator_support import OperatorSupport from torch.fx.passes.tools_common import CALLABLE_NODE_OPS -from torch.onnx._globals import GLOBALS as ONNX_GLOBALS +from torch.utils import _pytree import onnxruntime # type: ignore from onnxruntime.capi import _pybind_state as ORTC @@ -41,6 +45,19 @@ torch.bool: np.bool_, } +_ONNX_ELEMENT_TYPE_TO_TORCH_DTYPE = { + 1: torch.float32, + 2: torch.uint8, + 3: torch.int8, + 5: torch.int16, + 6: torch.int32, + 7: torch.int64, + 9: torch.bool, + 10: torch.float16, +} + +_TORCH_DTYPE_TO_ONNX_ELEMENT_TYPE = {value: key for key, value in _ONNX_ELEMENT_TYPE_TO_TORCH_DTYPE.items()} + def _nvtx_range_push(name: str): """If PyTorch is installed with CUDA support, this starts NVTX range. @@ -67,7 +84,7 @@ def _get_ort_device_type(device_type: str): return ORTC.OrtDevice.cpu() # type: ignore # ort pytorch device is mapped to NPU OrtDevice type if device_type == "ort": - return ORTC.OrtDevice.npu() + return ORTC.OrtDevice.npu() # type: ignore raise ValueError("Unsupported device type: " + device_type) @@ -77,115 +94,6 @@ def _get_ort_device_type(device_type: str): # logger.setLevel(logging.INFO) -def _get_onnx_supported_table() -> Set[str]: - # TODO(wechi): this entire function should be replaced by a formal a exporter API. - - onnx_supported_ops: Set[str] = set() - for aten_op_name, schema in torch.onnx._onnx_supported_ops.all_symbolics_schemas().items(): - # TODO(wechi): aten_op_name could be prim::add in addition to aten::add. - # We should build another dictionary for storing support table for prim ops. - # Currently, we only consider aten ops as before. - if not aten_op_name.startswith("aten::"): - logger.info("Skip %s in support table because it's not in aten domain.", aten_op_name) - continue - short_op_name = aten_op_name.split("aten::")[1] - if not hasattr(torch.ops.aten, short_op_name): # type: ignore - # Some aten ops are not in torch.ops.aten. Those are excluded until we - # figure out why. - logger.info("Skip %s in support table because it's not found in torch.ops.aten.", aten_op_name) - continue - # aten_op_name is aten symbol's name; e.g., "sum" for aten::sum. - # opsets_string is the ONNX opsets that can express info[0]; e.g., "15 16 17" - # indicates that opset 15, opset 16, and opset 17 can all express aten_op_name. - if ONNX_GLOBALS.export_onnx_opset_version in schema.opsets: - logger.info("Add %s to support table.", aten_op_name) - onnx_supported_ops.add(aten_op_name) - return onnx_supported_ops - - -def _get_support_dictionaries_and_decomposition_tables() -> ( - Tuple[ - Dict[torch._ops.OpOverload, Any], - Dict[str, Any], - Dict[torch._ops.OpOverload, Callable], - Dict[torch._ops.OpOverload, Callable], - ] -): - # The keys of this dictionary are OpOverload's which can be - # exported by ONNX exporter. Type of key is torch._ops.OpOverload. - # For example, if torch.ops.aten.add.default is a key in support_dict, - # all torch.fx.Node's with torch.ops.aten.add.default as target will - # be selected by CapabilityBasedPartitioner and sent to ORT for - # computation. - # We choose torch._ops.OpOverload as the key because - # 1. torch._ops.OpOverload uniquely identifies an op. We don't want - # to use OpOverloadPacket because it contains overloads of the same op. - # This allows us to select supported ops at the finest grain. - # 2. torch._ops.OpOverload is what we get from torch.fx.Node.target. Getting - # qualified name using _get_qualified_name is not needed. - support_dictionary: Dict[torch._ops.OpOverload, Any] = {} - for aten_op_name in _get_onnx_supported_table(): - short_op_name = aten_op_name.split("aten::")[1] - op_overload_packet = getattr(torch.ops.aten, short_op_name) # type: ignore - # Due to the lack of overload name in exporting function's name, assume - # each exporting function (e.g., torch.onnx.symbolic_opset9.add) support - # all overloads (e.g., in torch.ops.aten.add). - # Thus, we register all torch._ops.OpOverload's for the same exporting function. - # Please manually exclude torch._ops.OpOverload if exporter fails. - for overload in op_overload_packet.overloads(): - op_overload = getattr(op_overload_packet, overload) - support_dictionary[op_overload] = None - - # No decomposition table. OpOverload in this table shouldn't be found - # in aten2aten_decomposition_table. - # The symbols in this set will be replaced by torch.ops.aten.to.dtype in replace_to_copy_with_to because - # only aten.to has ONNX exporter. - # If the replacement fails, ONNX exporter will fail because only aten.to has ONNX exporter. - # TODO(wechi): For a long-term solution, we need to ensure every op used in op decomposision has - # an exporter. - no_decomposition_table: Set[torch._ops.OpOverload] = { - torch.ops.aten._to_copy.default, # type: ignore - torch.ops.aten._to_copy.out, # type: ignore - } - - # decomposition_table currently contains both aten2aten and aten2prim decompositions - # This is a hack to separate them, as ONNX only recognizes aten symbols. - aten2aten_decomposition_table: Dict[torch._ops.OpOverload, Callable] = {} - aten2prim_decomposition_table: Dict[torch._ops.OpOverload, Callable] = {} - - for op_overload, decomp_fn in decomposition_table.items(): - if op_overload in support_dictionary: - # ONNX can express this op, no need to decompose. - continue - if "torch._refs" in decomp_fn.__module__: - aten2prim_decomposition_table[op_overload] = decomp_fn - else: - if op_overload in no_decomposition_table: - continue - # Assume ONNX can express ops after decomposition. - # If no, exporter will fail and the user need to - # remove this decomposition rule. - aten2aten_decomposition_table[op_overload] = decomp_fn - - # Some torch.fx.Node's are converted to ONNX-compatible ops - # by torch.jit.script. They don't have direct ONNX exporting - # functions but still runnable in ORT. - extra_support_dictionary: Dict[str, Any] = { - "getattr": None, - "_operator.getitem": None, - } - - return support_dictionary, extra_support_dictionary, aten2aten_decomposition_table, aten2prim_decomposition_table - - -( - _SUPPORT_DICT, - _EXTRA_SUPPORT_DICT, - _ATEN2ATEN_DECOMP, - _ATEN2PRIM_DECOMP, -) = _get_support_dictionaries_and_decomposition_tables() - - class OrtOperatorSupport(OperatorSupport): """ Operator support for ONNXRuntime backend. It has two-level of support decision. @@ -194,8 +102,13 @@ class OrtOperatorSupport(OperatorSupport): is used by OperatorSupport.is_node_supported. """ - def __init__(self): - super().__init__(_EXTRA_SUPPORT_DICT) + def __init__(self, support_dict: Set[Any], extra_support_dict: Dict[str, Any]): + # Use extra_support_dict[op_name] = None to indicate + # we support op_name with all input types. Otherwise, + # see support_dict (type: SupportDict) in operator_support.py + # for specifying supported types. + super().__init__(extra_support_dict) + self._support_dict = support_dict def is_node_supported(self, submodules: Mapping[str, torch.nn.Module], node: torch.fx.Node) -> bool: # OperatorSupport.is_node_supported returns True for non-callable nodes. @@ -204,7 +117,7 @@ def is_node_supported(self, submodules: Mapping[str, torch.nn.Module], node: tor if node.op not in CALLABLE_NODE_OPS: return False # This is the and the only place to decide if aten op is supported. - if node.op == "call_function" and node.target in _SUPPORT_DICT: + if node.op == "call_function" and node.target in self._support_dict: logger.info("support_dict supports node.target: %s (type: %s)", node.target, type(node.target)) return True logger.info("support_dict doesn't support node.target: %s (type: %s)", node.target, type(node.target)) @@ -218,31 +131,6 @@ def is_node_supported(self, submodules: Mapping[str, torch.nn.Module], node: tor return False -def _jit_graph_to_onnx_model(graph, operator_export_type): - r""" - This function exports torch::jit::Graph object - to serialized ONNX ModelProto. - It only keeps the essential parts for IR graph conversions. - It also does not interact with actual PyTorch modules nor - PyTorch tensor inputs. - """ - graph = torch.onnx.utils._optimize_graph(graph, operator_export_type, params_dict={}) - proto, _, _, _ = graph._export_onnx( # type: ignore - {}, - ONNX_GLOBALS.export_onnx_opset_version, - {}, - False, - operator_export_type, - False, - False, - {}, - True, - "", - {}, - ) - return proto - - def _move_placeholder_to_front(graph_module: torch.fx.GraphModule) -> None: """ In torch.fx.Graph, placehoder is a special assignment node. If it's not @@ -300,56 +188,78 @@ def _replace_to_copy_with_to(fx_module: torch.fx.GraphModule) -> None: fx_module.recompile() -def _fx_to_torchscript( - fx_module: torch.fx.GraphModule, -) -> torch.jit.ScriptModule: - """Convert torch.fx.Graph to torch.jit.ScriptModule.""" +def _create_onnx_model(onnx_proto): + return onnx.ModelProto.FromString(onnx_proto) + - for node in fx_module.graph.nodes: - new_kwargs = {} - for k, v in node.kwargs.items(): - if isinstance(v, torch.device): - v = v.type # noqa: PLW2901 - new_kwargs[k] = v - node.kwargs = new_kwargs - for node in fx_module.graph.nodes: - if isinstance(node.target, torch._ops.OpOverload): - node.target = node.target.overloadpacket - fx_module.graph.lint() - fx_module.recompile() - return torch.jit.script(fx_module) # type: ignore +def _create_onnx_session(onnx_proto, eps: Tuple[str, ...], session_options): + # TODO(wechi): Add more EPs per PyTorch device types. + # TODO(wechi): enable external allocators. + return onnxruntime.InferenceSession(onnx_proto, providers=eps, sess_options=session_options) -def _decorate_script_module(script_module: torch.jit.ScriptModule, expected_inputs, expected_outputs): - for i, input_value in enumerate(script_module.graph.inputs()): # type: ignore - if input_value.debugName() == "self": - script_module.graph.eraseInput(i) # type: ignore - break - for input_value, expected_input in zip(script_module.graph.inputs(), expected_inputs): # type: ignore - input_value.setType(torch._C.TensorType.create_from_tensor(expected_input)) - for output_value, expected_output in zip(script_module.graph.outputs(), expected_outputs): # type: ignore - output_value.setType(torch._C.TensorType.create_from_tensor(expected_output)) +def _infer_ep_from_device(*args) -> Tuple[str, ...]: + """Return the first valid device (i.e., GPU or CPU) in argument list.""" + eps = [] + for arg in args: + if hasattr(arg, "device"): + device = arg.device + if device.type == "cuda": + eps.append("CUDAExecutionProvider") + elif device.type == "cpu": + eps.append("CPUExecutionProvider") + return tuple(eps) -def _create_onnx_proto(script_module): - onnx_proto = _jit_graph_to_onnx_model(script_module.graph, torch.onnx.OperatorExportTypes.ONNX) - return onnx_proto +def _extract_graph_module_inputs(graph_module: torch.fx.GraphModule) -> Tuple[Any, ...]: + placeholders = [] + for node in graph_module.graph.nodes: + if node.op == "placeholder": + if hasattr(node, "meta") and "val" in node.meta: + assert isinstance(node.meta["val"], torch.Tensor) + placeholders.append(node) -def _create_onnx_model(onnx_proto): - return onnx.ModelProto.FromString(onnx_proto) +def _extract_graph_module_outputs(graph_module: torch.fx.GraphModule) -> Any: + """Collect "val" fields from outputs metadata in this torch.fx.GraphModule.""" + for node in graph_module.graph.nodes: + if node.op == "output": + # Output node is unique. Let's retrieve output values from + # this node's input list. And then just return. + return node.args[0] + raise ValueError("No output node found in this torch.fx.GraphModule.") + + +def _infer_ep_from_graph_module(graph_module: torch.fx.GraphModule) -> Tuple[str, ...]: + """Return the all valid devices (i.e., GPU or CPU) among outputs of this torch.fx.GraphModule.""" + flattened_output_args, _ = _pytree.tree_flatten(_extract_graph_module_outputs(graph_module)) + # Output arguments with example value (type: torch.Tensor) in the `graph_module`. + selected_output_args = [ + output_arg.meta["val"] + for output_arg in flattened_output_args + # output_arg must have tensor for its device information. + # Otherwise, skip it. + if (hasattr(output_arg, "meta") and "val" in output_arg.meta) + ] + return _infer_ep_from_device(*selected_output_args) -def _create_onnx_session(onnx_proto, ep: str): - # TODO(wechi): Add more EPs per PyTorch device types. - # TODO(wechi): enable external allocators. - return onnxruntime.InferenceSession(onnx_proto, providers=[ep]) +def _sort_eps(eps: Tuple[str, ...]) -> Tuple[str, ...]: + """Sort execution providers in eps based on pre-set priority.""" + def get_execution_provider_priority(ep: str) -> int: + if ep == "CPUExecutionProvider": + # Lowest priority. + return 2 + if ep == "CUDAExecutionProvider": + # Higher priority than CPU but lower than + # other specialized EPs. + return 1 + # Highest priority. + return 0 -def _infer_ep_from_device(device): - if device.type == "cuda": - return "CUDAExecutionProvider" - return "CPUExecutionProvider" + unique_eps = set(eps) + return tuple(sorted(unique_eps, key=get_execution_provider_priority, reverse=True)) def _get_onnx_devices(values: Tuple[torch.Tensor, ...]) -> Tuple[ORTC.OrtDevice, ...]: # type: ignore @@ -453,28 +363,87 @@ def _assert_allclose_with_detailed_error_message( ) -@dataclasses.dataclass -class OrtExecutionInfo: +class OrtExecutionInfoPerSession: """Information required to execute torch.fx.GraphModule using onnxruntime.InferenceSession""" + def __init__( + self, + session: onnxruntime.InferenceSession, + input_names: Tuple[str, ...], + input_value_infos: Tuple[onnx.ValueInfoProto, ...], + output_names: Tuple[str, ...], + output_value_infos: Tuple[onnx.ValueInfoProto, ...], + input_devices: Tuple[ORTC.OrtDevice, ...], # type: ignore + output_devices: Tuple[ORTC.OrtDevice, ...], # type: ignore + example_outputs: Union[Tuple[torch.Tensor, ...], torch.Tensor], + ): + # Carrier of ONNX model and its executor. + self.session: onnxruntime.InferenceSession = session + # For the ONNX model stored in self.session, self.input_names[i] is the + # name of the i-th positional input. + self.input_names: Tuple[str, ...] = input_names + # self.input_name[i]'s type information is stored in self.input_value_infos[i]. + self.input_value_infos: Tuple[onnx.ValueInfoProto, ...] = input_value_infos + # Similar to self.input_names, but for outputs. + self.output_names: Tuple[str, ...] = output_names + # Similar to self.input_value_infos but for outputs. + self.output_value_infos: Tuple[onnx.ValueInfoProto, ...] = output_value_infos + # For the ONNX model stored in self.session, self.input_devices[i] is the + # i-th positional input's device. + self.input_devices: Tuple[ORTC.OrtDevice, ...] = input_devices # type: ignore + # Similar to self.input_devices, but for outputs. + self.output_devices: Tuple[ORTC.OrtDevice, ...] = output_devices # type: ignore + # This is the outputs of executing the original torch.fx.GraphModule with example inputs + # (i.e., args passed into OrtBackend._ort_acclerated_call). + self.example_outputs: Union[Tuple[torch.Tensor, ...], torch.Tensor] = example_outputs + + def is_supported(self, *args): + # Compare the args and the input schema in ONNX model and + # return the first match. + if len(args) != len(self.input_value_infos): + return False + for arg, value_info in zip(args, self.input_value_infos): + if not isinstance(arg, torch.Tensor): + return False + onnx_dtype = _TORCH_DTYPE_TO_ONNX_ELEMENT_TYPE[arg.dtype] + if onnx_dtype != value_info.type.tensor_type.elem_type: + return False + for dim, onnx_dim in zip(arg.shape, value_info.type.tensor_type.shape.dim): + if isinstance(dim, int) and (onnx_dim.dim_value == dim or onnx_dim.dim_param): + continue + elif isinstance(dim, torch.SymInt) and onnx_dim.dim_param: + continue + else: + return False + return True + + +@dataclasses.dataclass +class OrtExecutionInfoForAllGraphModules: def __init__(self): - # session self.sessions[mod] is created for computing the graph in mod. - self.sessions: Dict[torch.fx.GraphModule, onnxruntime.InferenceSession] = {} - # self.input_names[mod] contains all input names in the ONNX model exported from mod. - # self.input_names[mod][i] is the name of the i-th positional input of the graph in mod. - self.input_names: Dict[torch.fx.GraphModule, Tuple[str, ...]] = {} - # Similar to self.input_names, but for outputs of the graph. - self.output_names: Dict[torch.fx.GraphModule, Tuple[str, ...]] = {} - # self.input_devices[mod] contains devices of inputs fed to mod.forward (excluding self). - # self.input_devices[mod][i] is the i-th positional input's device. - self.input_devices: Dict[torch.fx.GraphModule, Tuple[ORTC.OrtDevice, ...]] = {} # type: ignore - # Similar to self.input_devices, but for outputs of the graph. - self.output_devices: Dict[torch.fx.GraphModule, Tuple[ORTC.OrtDevice, ...]] = {} # type: ignore - # This is a debug flag. When True, this backend will compare its - self.assert_allclose_to_baseline: bool = False - # We need example outputs to determine output schema of ORT run. - # self.example_outputs[mod] is the outputs of mod.forward(*self.example_inputs[mod]). - self.example_outputs: Dict[torch.fx.GraphModule, Union[Tuple[torch.Tensor, ...], torch.Tensor]] = {} + # All sessions (and their related information) created by exporting the same GraphModule + # with different inputs. + self.execution_info_per_graph_module: Dict[torch.fx.GraphModule, List[OrtExecutionInfoPerSession]] = {} + + def search_reusable_session_execution_info(self, graph_module: torch.fx.GraphModule, *args): + if graph_module not in self.execution_info_per_graph_module: + return None + # All execution information for ONNX models exported from the same `graph_module` + # with different inputs. + candidates = self.execution_info_per_graph_module[graph_module] + + for candidate in candidates: + if candidate.is_supported(*args): + # Returns the first session that accepts this input schema. + return candidate + # No reusable session found. + return None + + def cache_session_execution_info(self, graph_module: torch.fx.GraphModule, info: OrtExecutionInfoPerSession): + if graph_module not in self.execution_info_per_graph_module: + self.execution_info_per_graph_module[graph_module] = [info] + else: + self.execution_info_per_graph_module[graph_module].append(info) class OrtBackend: @@ -487,14 +456,66 @@ class OrtBackend: 3. Inside _ort_accelerated_call, it creates onnxruntime.InferenceSession and calls it to execute the sub-graph. """ - def __init__(self, ep: str = "", preallocate_output: bool = False): - self._supported_ops = OrtOperatorSupport() + def __init__( + self, + ep: str = "CPUExecutionProvider", + preallocate_output: bool = False, + session_options=None, + onnx_exporter_options: Optional["torch.onnx.ExportOptions"] = None, + ): + # onnx_exporter_options contains information shared between exporter and DORT. + # For example, they should use the same decomposition table when + # 1. capturing FX graph in torch.compile (see how we create aot_ort in register_backend.py) + # 2. call exporter's API to convert `torch.fx.GraphModule` to ONNX model + # (see onnxfunction_dispatcher passed to FxOnnxInterpreter.run below). + if onnx_exporter_options is None: + onnx_exporter_options = torch.onnx.ExportOptions() + # Convert user-facing option to internal option used by ONNX exporter + # to access required information. + # Some useful fields: + # - Decomposition table for decomposing FX operators in exporter is + # self.resolved_onnx_exporter_options.decomposition_table. + # - self.resolved_onnx_exporter_options.onnx_registry records what + # aten/prim ops are supported by exporter and their exporters (type: callable). + self.resolved_onnx_exporter_options = torch.onnx._internal.exporter.ResolvedExportOptions(onnx_exporter_options) + + # TODO(wechi): This line must generate result identical to the call of + # _create_onnx_supports_op_overload_table(...) inside + # create_onnx_friendly_decomposition_table(...) in + # torch/onnx/_internal/fx/decomposition_table.py. + support_dict = torch.onnx._internal.fx.decomposition_table._create_onnx_supports_op_overload_table( + # This is identical to self.resolved_onnx_exporter_options.onnxfunction_dispatcher.onnx_registry. + self.resolved_onnx_exporter_options.onnx_registry + ) # type: ignore + + extra_support_dict: Dict[str, Any] = { + "getattr": None, + "_operator.getitem": None, + } + + self._supported_ops = OrtOperatorSupport(support_dict, extra_support_dict) # TODO: this is a naive implementation of cache without proper guard self._partitioner_cache: Dict[torch.fx.GraphModule, torch.fx.GraphModule] = {} - # TODO: this is a naive implementation of cache without proper guard, this will only work for identical inputs - self._ort_execution_info = OrtExecutionInfo() + # Conceptually, this filed is a 2-layer dictionary + # GraphModule 0 + # ONNX Model 0 (with ORT InferenceSession and related information. type: OrtExecutionInfoPerSession) + # ONNX Model 1 + # ... + # GraphModule 1 + # ONNX Model 2 (with ORT InferenceSession and related information. type: OrtExecutionInfoPerSession) + # ONNX Model 3 + # ... + # ... + # , which caches all previous compilation result so that we can reuse them. + # ONNX Model 0 and 1 are exported from the same GraphModule 0 but with different inputs + # (e.g., tensors with different ranks). GraphModule 0 and GraphModule 1 are different + # graphs captured by Dynamo and sent to OrtBackend.compile. + self._all_ort_execution_info = OrtExecutionInfoForAllGraphModules() + + self._assert_allclose_to_baseline = False self.ep = ep + self.session_options = session_options # preallocate_output allows for allocating output torch Tensor buffers and feeding them to InferenceSession # in order to avoid internal allocation of output buffers in InferenceSession. @@ -507,14 +528,16 @@ def __init__(self, ep: str = "", preallocate_output: bool = False): self.preallocate_output = preallocate_output def _ort_acclerated_call(self, graph_module: torch.fx.GraphModule, *args, **kwargs): - if graph_module in self._ort_execution_info.sessions: - # We have seen this graph before, so we can use cached objects including session. - onnx_session = self._ort_execution_info.sessions[graph_module] - input_names = self._ort_execution_info.input_names[graph_module] - output_names = self._ort_execution_info.output_names[graph_module] - input_devices = self._ort_execution_info.input_devices[graph_module] - output_devices = self._ort_execution_info.output_devices[graph_module] - prim_outputs = self._ort_execution_info.example_outputs[graph_module] + cached_execution_info_per_session = self._all_ort_execution_info.search_reusable_session_execution_info( + graph_module, *args + ) + if cached_execution_info_per_session: + onnx_session = cached_execution_info_per_session.session + input_names = cached_execution_info_per_session.input_names + output_names = cached_execution_info_per_session.output_names + input_devices = cached_execution_info_per_session.input_devices + output_devices = cached_execution_info_per_session.output_devices + prim_outputs = cached_execution_info_per_session.example_outputs else: # It's first time seeing such as graph. Let's make a new session # (type: onnxruntime.InferenceSession) for it. @@ -526,37 +549,76 @@ def _ort_acclerated_call(self, graph_module: torch.fx.GraphModule, *args, **kwar # # WARNING: The downstream code should not change prim_outputs and # this backend should always produces output with schema identical to prim_outputs'. - try: - prim_outputs = FakeTensorProp(graph_module).propagate(*args, **kwargs) - except Exception: - logger.info(f"FakeTensorProb failed for {graph_module}") - # When FakeTensorProp fails, it is not possible to preallocate output buffers - # because the output shapes are not inferred. + + if self.resolved_onnx_exporter_options.dynamic_shapes: + # No pre-allocation when dynamic shape is enabled. self.preallocate_output = False + extracted_outputs = _extract_graph_module_outputs(graph_module) - # rethrow FakeTensorProb failure because it is not yet currently handled. - raise - self._ort_execution_info.example_outputs[graph_module] = prim_outputs - # Compile the torch.fx.GraphModule into a torch.jit.ScriptModule. - script_module = _fx_to_torchscript(graph_module) - # Post-processing step to add expected input and output type information - # to the graph in torch.jit.ScriptModule. Expected inputs is "args" and "kwargs" - # while expected outputs is "prim_outputs". - if isinstance(prim_outputs, tuple): - _decorate_script_module(script_module, args, prim_outputs) + def maybe_map_to_meta_val(value): + if hasattr(value, "meta") and "val" in value.meta: + # Select outputs with "val" information. Without "val", + # it's not possible access output_arg.meta["val"].device. + return value.meta["val"] + else: + return value + + prim_outputs = _pytree.tree_map(maybe_map_to_meta_val, extracted_outputs) else: - _decorate_script_module(script_module, args, (prim_outputs,)) - # Generate ONNX ModelProto from torch._C.Graph. - onnx_proto = _create_onnx_proto(script_module) + try: + prim_outputs = FakeTensorProp(graph_module).propagate(*args, **kwargs) + except Exception: + logger.info(f"FakeTensorProb failed for {graph_module}") + # When FakeTensorProp fails, it is not possible to preallocate output buffers + # because the output shapes are not inferred. + self.preallocate_output = False + + # rethrow FakeTensorProb failure because it is not yet currently handled. + raise + + from torch.onnx._internal.fx import fx_onnx_interpreter + + # Create the object to iterate through the nodes in graph one-by-one + # and calls the corresponding ONNX exporter for each node. + fx_interpreter = fx_onnx_interpreter.FxOnnxInterpreter( + diagnostic_context=self.resolved_onnx_exporter_options.diagnostic_context + ) + # Start the per-node exporting process. It's conceptually a for loop + # scanning through the nodes in the graph. + exported = fx_interpreter.run( + fx_graph_module=graph_module, + onnxfunction_dispatcher=self.resolved_onnx_exporter_options.onnxfunction_dispatcher, + op_level_debug=self.resolved_onnx_exporter_options.op_level_debug, + ) + # Convert the exported result to ONNX ModelProto. + onnx_proto = exported.to_model_proto( + opset_version=self.resolved_onnx_exporter_options.onnx_registry.opset_version + ).SerializeToString() # Initialize a ORT session to execute this ONNX model. - # TorchDynamo assumes all inputs/outputs are on the same device, - # so we add execution provider only based on the first input's device. - ep = self.ep or _infer_ep_from_device(args[0].device) + # Note that TorchDynamo assumes all inputs/outputs are on the + # same device, but it's subject to change (very likely with + # dynamic shape support), so we add execution providers + # based on the all inputs/outputs plus a default OrtBackend.ep. + eps_from_args = _infer_ep_from_device(args) + eps_from_graph_module = _infer_ep_from_graph_module(graph_module) + if eps_from_args: + # If user feeds CUDA tensor as input argument, + # we want to use CUDA EP. + # Thus, `eps_from_args` (deduced from input arguments) + # has highest priority. + selected_eps = _sort_eps((*eps_from_args, self.ep)) + elif eps_from_graph_module: + # If there is no EP in input arguments, we deduce EP from + # graph_module's outputs. Those outputs may come from + # FakeTensorProp or Dynamo's built-in symbolic shape inference. + selected_eps = _sort_eps((*eps_from_graph_module, self.ep)) + else: + # No EP found in inputs and outputs, let's use default. + selected_eps = (self.ep,) - onnx_session = _create_onnx_session(onnx_proto, ep) + onnx_session = _create_onnx_session(onnx_proto, selected_eps, self.session_options) # Cache ORT session. It's reused for the same "graph_module". - self._ort_execution_info.sessions[graph_module] = onnx_session # Generate ONNX model and extract its input and output names. onnx_model = _create_onnx_model(onnx_proto) # TODO(wechi): ORT session should provide a API to extract @@ -571,10 +633,19 @@ def _ort_acclerated_call(self, graph_module: torch.fx.GraphModule, *args, **kwar output_devices = _get_onnx_devices(prim_outputs) else: output_devices = _get_onnx_devices((prim_outputs,)) - self._ort_execution_info.input_names[graph_module] = input_names - self._ort_execution_info.output_names[graph_module] = output_names - self._ort_execution_info.input_devices[graph_module] = input_devices - self._ort_execution_info.output_devices[graph_module] = output_devices + + execution_info_per_session = OrtExecutionInfoPerSession( + session=onnx_session, + input_names=input_names, + input_value_infos=tuple(input for input in onnx_model.graph.input), + output_names=output_names, + output_value_infos=tuple(output for output in onnx_model.graph.output), + input_devices=input_devices, + output_devices=output_devices, + example_outputs=prim_outputs, + ) + + self._all_ort_execution_info.cache_session_execution_info(graph_module, execution_info_per_session) if isinstance(prim_outputs, tuple): assert all(isinstance(elem, torch.Tensor) for elem in prim_outputs) @@ -592,7 +663,7 @@ def _ort_acclerated_call(self, graph_module: torch.fx.GraphModule, *args, **kwar self.preallocate_output, ) _nvtx_range_pop() - if self._ort_execution_info.assert_allclose_to_baseline: + if self._assert_allclose_to_baseline: # Compute baseline. baseline_outputs = torch._prims.executor.execute(graph_module, *args, executor="aten") # Ensure every output tensor is close to the corresponding baseline. @@ -615,7 +686,7 @@ def _ort_acclerated_call(self, graph_module: torch.fx.GraphModule, *args, **kwar self.preallocate_output, ) assert len(onnx_outputs) == 1 - if self._ort_execution_info.assert_allclose_to_baseline: + if self._assert_allclose_to_baseline: # Compute baseline. baseline_outputs = torch._prims.executor.execute(graph_module, *args, executor="aten") # Ensure output tensor is close to the corresponding baseline. @@ -627,15 +698,11 @@ def compile(self, graph_module: torch.fx.GraphModule, args) -> torch.fx.GraphMod if graph_module in self._partitioner_cache: partitioned_prim_graph_module = self._partitioner_cache[graph_module] else: - prim_graph_module = make_fx( - graph_module, tracing_mode="fake", _allow_non_fake_inputs=True, decomposition_table=_ATEN2ATEN_DECOMP - )(*args) + prim_graph_module = graph_module # TODO(wechi): this is required for removing aten::_to_copy in _replace_to_copy_with_to. - # We need input and output tensors' devices to decide if aten::_to_copy is just a Cast. - FakeTensorProp(prim_graph_module).propagate(*args) _replace_to_copy_with_to(prim_graph_module) partitioner = CapabilityBasedPartitioner( - prim_graph_module, self._supported_ops, allows_single_node_partition=False + prim_graph_module, self._supported_ops, allows_single_node_partition=True ) partitioned_prim_graph_module = partitioner.partition_and_fuse() self._partitioner_cache[graph_module] = partitioned_prim_graph_module diff --git a/orttraining/orttraining/python/training/torchdynamo/register_backend.py b/orttraining/orttraining/python/training/torchdynamo/register_backend.py index 6f6c0f6575b0b..3a49e85ab836d 100644 --- a/orttraining/orttraining/python/training/torchdynamo/register_backend.py +++ b/orttraining/orttraining/python/training/torchdynamo/register_backend.py @@ -5,14 +5,37 @@ from functorch.compile import min_cut_rematerialization_partition from torch._dynamo.backends.common import aot_autograd +from torch.onnx._internal.exporter import ExportOptions from .ort_backend import OrtBackend -# This should be the underlying compiler for ALL graphs if -# the user uses ORT to accelerate PyTorch via Dynamo. -# By using a global compiler for all graphs, cached compilation -# results can be reused when encountering the identical graphs. -DEFAULT_BACKEND = OrtBackend() + +def make_aot_ort(dynamic: bool = True): + """Wrap OrtBackend as PyTorch's AOT compiler. + + Example usages: + import torch + from onnxruntime.training.torchdynamo.register_backend import make_aot_ort + use_dynamic = True + local_aot_ort, _ = make_aot_ort(dynamic = use_dynamic) + + @torch._dynamo.optimize(local_aot_ort, dynamic=use_dynamic) + def foo(x: torch.Tensor): + return torch.sigmoid(x) + + x = torch.rand(2, 2, dtype=torch.float) + torch.testing.assert_close(torch.sigmoid(x), foo(x)) + """ + ort_backend = OrtBackend(onnx_exporter_options=ExportOptions(dynamic_shapes=dynamic)) + return ( + aot_autograd( + fw_compiler=ort_backend, + partition_fn=min_cut_rematerialization_partition, + decompositions=ort_backend.resolved_onnx_exporter_options.decomposition_table, + ), + ort_backend, + ) + # Wrap ORT as a compiler in Dynamo for training (i.e., when .backward is called). # @@ -28,7 +51,24 @@ # compiled_model = torch._dynamo.optimize(aot_ort)(model) # result = compiled_model(torch.rand(2, 2, dtype=torch.float) # result.sum().backward() -aot_ort = aot_autograd(fw_compiler=DEFAULT_BACKEND, partition_fn=min_cut_rematerialization_partition) +# +# DEFAULT_BACKEND should be the underlying compiler for ALL graphs if +# the user uses ORT to accelerate PyTorch via Dynamo. +# By using a global compiler for all graphs, cached compilation +# results can be reused when encountering the identical graphs. +aot_ort, DEFAULT_BACKEND = make_aot_ort(dynamic=False) + +# Similar to aot_ort but should be used with +# torch._dynamo.optimize(dynamic_aot_ort, dynamic=True) +# to enable dynamic shapes in ONNX graph. +# +# Similar to DEFAULT_BACKEND but DEFAULT_DYNAMIC_BACKEND enables dynamic shapes +# when exporting FX graph to ONNX. +# Note that this backend must be used with +# torch._dynamo.optimize(DEFAULT_DYNAMIC_BACKEND, dynamic=True) +# Without `dynamic=True`, the FX graph only contains static shapes, and results ONNX graph +# with static shapes. +dynamic_aot_ort, DEFAULT_DYNAMIC_BACKEND = make_aot_ort(dynamic=True) # Declare ORT as a compiler in Dynamo for inference (i.e., when .backward is NOT called). # @@ -42,3 +82,8 @@ # model = torch.nn.Linear(2, 2) # compiled_model = torch._dynamo.optimize(ort)(model) ort = DEFAULT_BACKEND + +# Similar to ort but should be used with +# torch._dynamo.optimize(dynamic_ort, dynamic=True) +# to enable dynamic shapes in ONNX graph. +dynamic_ort = DEFAULT_DYNAMIC_BACKEND diff --git a/orttraining/orttraining/python/training/utils/__init__.py b/orttraining/orttraining/python/training/utils/__init__.py new file mode 100644 index 0000000000000..fa7c9f2750cdd --- /dev/null +++ b/orttraining/orttraining/python/training/utils/__init__.py @@ -0,0 +1,22 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# __init__.py + +from onnxruntime.training.utils.torch_io_helper import ( + ORTModelInputOutputSchemaType, + ORTModelInputOutputType, + PrimitiveType, + extract_data_and_schema, + unflatten_data_using_schema, +) +from onnxruntime.training.utils.torch_type_map import onnx_dtype_to_pytorch, pytorch_dtype_to_onnx + +__all__ = [ + "PrimitiveType", + "ORTModelInputOutputType", + "ORTModelInputOutputSchemaType", + "extract_data_and_schema", + "unflatten_data_using_schema", + "pytorch_dtype_to_onnx", + "onnx_dtype_to_pytorch", +] diff --git a/orttraining/orttraining/python/training/utils/hooks/__init__.py b/orttraining/orttraining/python/training/utils/hooks/__init__.py index 34e4a5bd04b81..89c0d44abbb7a 100644 --- a/orttraining/orttraining/python/training/utils/hooks/__init__.py +++ b/orttraining/orttraining/python/training/utils/hooks/__init__.py @@ -3,10 +3,35 @@ # Licensed under the MIT License. # -------------------------------------------------------------------------- + +import torch + __all__ = [ "StatisticsSubscriber", - "SubscriberManager", + "GlobalSubscriberManager", + "inspect_activation", + "ZeROOffloadSubscriber", + "configure_ort_compatible_zero_stage3", ] -from ._statistics_subscriber import StatisticsSubscriber +from ._statistics_subscriber import StatisticsSubscriber, _InspectActivation from ._subscriber_manager import SubscriberManager +from ._zero_offload_subscriber import ZeROOffloadSubscriber, configure_ort_compatible_zero_stage3 + +# Define a global uninitialized subscriber manager for usage where it is needed by different Python files. +GlobalSubscriberManager = SubscriberManager() + + +def inspect_activation(activation_name: str, tensor: torch.Tensor) -> torch.Tensor: + for sub in GlobalSubscriberManager._subscribers: + if isinstance(sub, StatisticsSubscriber): + return _InspectActivation.apply( + activation_name, + None, + GlobalSubscriberManager.get_run_context(), + tensor, + sub.module_post_forward_impl, + sub.module_pre_backward_impl, + ) + + raise RuntimeError("StatisticsSubscriber is not registered, cannot inspect activation.") diff --git a/orttraining/orttraining/python/training/utils/hooks/_statistics_subscriber.py b/orttraining/orttraining/python/training/utils/hooks/_statistics_subscriber.py index 60f6586f1f3b6..db1c69cf95ba4 100644 --- a/orttraining/orttraining/python/training/utils/hooks/_statistics_subscriber.py +++ b/orttraining/orttraining/python/training/utils/hooks/_statistics_subscriber.py @@ -6,12 +6,92 @@ import os import shutil import warnings +from io import TextIOWrapper from pathlib import Path -from typing import Union +from typing import List, Optional, Tuple, Union +import onnx import torch -from ._subscriber_base import SubscriberBase +from ._subscriber_base import RuntimeStates, SubscriberBase + + +class _InspectActivation(torch.autograd.Function): + """ + This class is used to run the subscriber's forward and backward functions. + The function will be called by two kinds of callers: + 1. SubscriberManager calls it for each registered nn.Module. + 2. Users who want to inspect the activation tensor at any place of model definition code. + """ + + @staticmethod + def forward( + ctx, + activation_name: str, + module_idx: Optional[int], + run_ctx: RuntimeStates, + input_tensor: torch.Tensor, + module_post_forward, + module_pre_backward, + ): + """ + Args: + ctx: context object to store intermediate information. + activation_name: the name of the activation tensor. + module_idx: unit id of the module (address of the module instance). + run_ctx: runtime context. + For call case 2 - need retrieve the runtime state from GlobalSubscriberManager. + input_tensor: the activation tensor. + + Make sure there is a same number of `tensor` type inputs and outputs. + This is enforced by ORT's PythonOp's schema check. + """ + depth = -1 + if module_idx is not None: + depth = run_ctx.global_states.module_index_to_depth[module_idx] + + input_tensor_copied = None + if input_tensor is None or not isinstance(input_tensor, torch.Tensor): + input_tensor_copied = input_tensor + else: + input_tensor_copied = input_tensor.detach().clone() + + ctx.current_step = run_ctx.global_states.execution_step + ctx.name = activation_name + ctx.id = module_idx + ctx.depth = depth + ctx.module_pre_backward = module_pre_backward + + module_post_forward(input_tensor_copied, depth, activation_name, ctx.current_step) + + return input_tensor.detach() if input_tensor is not None else None + + @staticmethod + def backward(ctx, grad_output: torch.Tensor): + val = None + if grad_output is None or not isinstance(grad_output, torch.Tensor): + val = grad_output + else: + val = grad_output.detach().clone() + + ctx.module_pre_backward(val, ctx.depth, ctx.name, ctx.current_step) + + return ( + None, + None, + None, + grad_output.detach() if grad_output is not None else None, + None, + None, + ) + + @staticmethod + def infer_shape( + node: onnx.NodeProto, + tensor_input_shapes: List[Optional[List[Union[int, str]]]], + tensor_input_dtypes: List[torch.onnx.TensorProtoDataType], + ) -> Tuple[List[Optional[List[Union[int, str]]]], List[torch.onnx.TensorProtoDataType]]: + return tensor_input_shapes, tensor_input_dtypes class StatisticsSubscriber(SubscriberBase): @@ -39,6 +119,8 @@ def __init__( start_step: Union[None, int] = None, end_step: Union[None, int] = None, override_output_dir: bool = False, + run_on_cpu: bool = False, + bucket_size: int = 1024 * 1024 * 1024 // 2, ): """ Steps in [start_step, end_step) will run subscriber actions. @@ -48,9 +130,14 @@ def __init__( start_step: the first step that runs subscriber actions. end_step: the end step (exclusively) that runs subscriber actions. override_output_dir: whether `output_dir` can be overridden if it already exists. + run_on_cpu: whether to run the subscriber actions on CPU, this should be the last resort when inserted + inspector node affects memory peak causing the original recipe run to fail with OOM. + bucket_size: the size of the bucket to split the statistic calculation. """ super().__init__(start_step=start_step, end_step=end_step) self._output_dir = output_dir + self._run_on_cpu = run_on_cpu + self._bucket_size = bucket_size if os.path.exists(self._output_dir): if override_output_dir: warnings.warn(f"Output directory {self._output_dir} already exists, overriding it.") @@ -61,6 +148,15 @@ def __init__( "Set override_output_dir=True for StatisticsSubscriber if this is the intention." ) + def post_forward_tensor_apply_impl( + self, run_rtx: RuntimeStates, module: torch.nn.Module, tensor_index: int, tensor: torch.Tensor + ) -> torch.Tensor: + module_index = run_rtx.global_states.module_to_module_index[module] + name = f"{module.__class__.__name__}_{module_index}_{tensor_index}th_output" + return _InspectActivation.apply( + name, module_index, run_rtx, tensor, self.module_post_forward_impl, self.module_pre_backward_impl + ) + def module_post_forward_impl(self, activation: torch.Tensor, depth: int, name: str, step: int): output_file_path = os.path.join(f"{self._output_dir}", f"step_{step}") return self._summarize_activations(activation, depth, name, output_file_path, True) @@ -83,30 +179,97 @@ def _summarize_activations(self, tensor: torch.Tensor, depth: int, name: str, st order_file_path = step_path / "order.txt" tensor_file_path = step_path / output_file_name - # This is to try the best effort to align the count of numbers per line for easier comparison in diff views, - # though it does not always guarantee to do this way. - torch.set_printoptions(precision=6, linewidth=128) + with order_file_path.open(mode="a", encoding="utf-8") as f: + f.write(f"{output_file_name}\n") + + with tensor_file_path.open(mode="w", encoding="utf-8") as f: + _summarize_tensor(display_name, tensor, f, depth, self._run_on_cpu, self._bucket_size) + - flatten_array = tensor.flatten() - zero_tensor = torch.tensor(0, dtype=flatten_array.dtype, device=flatten_array.device) +def _summarize_tensor( + display_name: str, + tensor: torch.Tensor, + f: TextIOWrapper, + depth: int = 0, + run_on_cpu: bool = False, + bucket_size: int = 1024 * 1024 * 1024 // 2, +): + # This is to try the best effort to align the count of numbers per line for easier comparison in diff views, + # though it does not always guarantee to do this way. + torch.set_printoptions(precision=6, linewidth=128) + + tensor_shape = tensor.shape + tensor_dtype = tensor.dtype + flatten_array = tensor.flatten().view(-1) + + if run_on_cpu: + flatten_array = flatten_array.to("cpu") + + if run_on_cpu: num_nan = torch.isnan(flatten_array).sum() num_inf = torch.isinf(flatten_array).sum() + num_neg = (flatten_array < 0).sum() + num_pos = (flatten_array > 0).sum() + num_zero = (flatten_array == 0).sum() + min_value = flatten_array.min() + max_value = flatten_array.max() + mean_value = flatten_array.mean() + std_value = flatten_array.std() + else: + # Split the calculation for each bucket, then do another round of calculation on the bucket results. + # This can at the best effort reduce the peak memory impact. + element_count = flatten_array.numel() + ceil_bucket_count = (element_count + bucket_size - 1) // (bucket_size) + nan_buckets = torch.zeros(ceil_bucket_count, dtype=torch.int64, device=flatten_array.device) + inf_buckets = torch.zeros(ceil_bucket_count, dtype=torch.int64, device=flatten_array.device) + neg_buckets = torch.zeros(ceil_bucket_count, dtype=torch.int64, device=flatten_array.device) + pos_buckets = torch.zeros(ceil_bucket_count, dtype=torch.int64, device=flatten_array.device) + zero_buckets = torch.zeros(ceil_bucket_count, dtype=torch.int64, device=flatten_array.device) + min_buckets = torch.zeros(ceil_bucket_count, dtype=flatten_array.dtype, device=flatten_array.device) + max_buckets = torch.zeros(ceil_bucket_count, dtype=flatten_array.dtype, device=flatten_array.device) + mean_buckets = torch.zeros(ceil_bucket_count, dtype=flatten_array.dtype, device=flatten_array.device) + std_buckets = torch.zeros(ceil_bucket_count, dtype=flatten_array.dtype, device=flatten_array.device) - with order_file_path.open(mode="a", encoding="utf-8") as f: - f.write(f"{output_file_name}\n") + # Summary for each bucket + element_count_per_bucket = torch.zeros(ceil_bucket_count, dtype=torch.int64, device=flatten_array.device) + for i in range(ceil_bucket_count): + end = min((i + 1) * bucket_size, element_count) + bucket = flatten_array[i * bucket_size : end] + element_count_per_bucket[i] = bucket.numel() - with tensor_file_path.open(mode="w", encoding="utf-8") as f: - f.write( - f"{'>'*depth + display_name} shape: {tensor.shape} dtype: {tensor.dtype} size: {flatten_array.size()} \n" - f"min: {flatten_array.min()} max: {flatten_array.max()}, mean: {flatten_array.mean()}, " - f"std: {flatten_array.std()} \n" - f"nan: {num_nan}, inf: {num_inf}\n" - ) - f.write(f"samples(top 128): {flatten_array[:128]}\n") - - f.write( - f"neg: {torch.less(flatten_array, zero_tensor).to(torch.int64).sum()}, " - f"pos: {torch.greater(flatten_array, zero_tensor).to(torch.int64).sum()}, " - f"zero: {torch.eq(flatten_array, zero_tensor).to(torch.int64).sum()},\n" - ) - f.write(f"{'='*16}\n") + nan_buckets[i] = torch.isnan(bucket).sum() + inf_buckets[i] = torch.isinf(bucket).sum() + neg_buckets[i] = (bucket < 0).sum() + pos_buckets[i] = (bucket > 0).sum() + zero_buckets[i] = (bucket == 0).sum() + min_buckets[i] = bucket.min() + max_buckets[i] = bucket.max() + mean_buckets[i] = bucket.sum() + std_buckets[i] = bucket.std() + + # Reduction across all buckets + num_nan = nan_buckets.sum() + num_inf = inf_buckets.sum() + num_neg = neg_buckets.sum() + num_pos = pos_buckets.sum() + num_zero = zero_buckets.sum() + min_value = min_buckets.min() + max_value = max_buckets.max() + mean_value = float(mean_buckets.sum()) / float(element_count) + # Here we refer to + # https://math.stackexchange.com/questions/2971315/how-do-i-combine-standard-deviations-of-two-groups + # to calculate the combined standard deviation of all buckets. + s = (element_count_per_bucket - 1) * (std_buckets**2) + element_count_per_bucket * ( + (mean_buckets - mean_value) ** 2 + ) + std_value = torch.sqrt(s.sum() / (element_count - 1)) + + f.write( + f"{'>'*max(0, depth) + display_name} shape: {tensor_shape} dtype: {tensor_dtype} size: {flatten_array.size()} \n" + f"min: {min_value} max: {max_value}, mean: {mean_value}, " + f"std: {std_value} \n" + f"nan: {num_nan}, inf: {num_inf}\n" + ) + f.write(f"samples(top 128): {flatten_array[:128]}\n") + f.write(f"neg: {num_neg}, pos: {num_pos}, zero: {num_zero},\n") + f.write(f"{'='*16}\n") diff --git a/orttraining/orttraining/python/training/utils/hooks/_subscriber_base.py b/orttraining/orttraining/python/training/utils/hooks/_subscriber_base.py index 572f2fb99b3b9..1b9a6fc91ec3c 100644 --- a/orttraining/orttraining/python/training/utils/hooks/_subscriber_base.py +++ b/orttraining/orttraining/python/training/utils/hooks/_subscriber_base.py @@ -5,34 +5,54 @@ import sys -from typing import Union +from typing import Optional, Tuple import torch +from onnxruntime.training.utils import ORTModelInputOutputType -class SubscriberBase: + +class RuntimeStates: """ - Base class for all module hook subscribers. - Currently, the hook here only means post-forward hook and pre-backward hook. + A data struct holding states for runtime context. + > Global states that are one-time collected during model hook registration. A global execution step is + also initialized to reflect how many steps have been executed, it will get updated after each step + completes its forward path. + """ + + class _GlobalStates: + def __init__(self): + # Used to track current execution step, e.g. how many forward/backward path is called. + self.execution_step = 0 + # Used to store the depth of each module, which indicate the indentation level of the module. + self.module_index_to_depth = {} + # Used to store the unique id of each sequential activation. + self.module_to_module_index = {} - A module hook subscriber is a class that implements the `module_post_forward_impl` and `module_pre_backward_impl` - function. - > The post_forward hook is called after the activation is generated in the forward path. - > The pre_backward hook is called before the activation gradient is computed. + def __init__(self): + self.global_states = RuntimeStates._GlobalStates() - The post_forward path: - Module_A generates activation tensor_a --> Post forward hook (calling subscribers' forward one by one) --> - Module_B generates activation tensor_b --> ... - The pre_backward path: - Module_B backward run, tensor_b's gradient is computed as tensor_b_grad --> - Pre-backward hook (calling subscribers' backward one by one) --> - Module_A backward run, tensor_a's gradient is computed as tensor_a_grad +class SubscriberBase: + """ + Base class for all module hook subscribers. - Be noted: the "Pre"/"Post" is described from the perspective of Module_A. + A module hook subscriber is a class that allow define custom actions to be executed during the nn.Module's hooks. + Two types of APIs can be used to define custom actions: + 1. Module level interfaces: + pre_forward_module_apply - called inside the nn.Module's pre-forward hook. + post_forward_module_apply - called inside the nn.Module's post-forward hook. + post_forward_outmost_module_apply - called inside the nn.Module's post-forward hook, but only for the outmost module. + 2. Tensor level interfaces: + pre_forward_tensor_apply - called inside the nn.Module's pre-forward hook, for each input tensor. + post_forward_tensor_apply - called inside the nn.Module's post-forward hook, for each output tensor. + + For ORT runs, tensor's flows are important, that's the reason we have tensor input as function input, + and tensor output as function output for all the APIs. + With this, the overall flow can be traced as a data flow graph (DAG). """ - def __init__(self, start_step: Union[None, int], end_step: Union[None, int]): + def __init__(self, start_step: Optional[int], end_step: Optional[int]): """ Steps in [start_step, end_step) will run the subscriber's actions, and other steps will skip. If start_step is None, 0 is given; if end_step is None, sys.maxsize is given. @@ -40,34 +60,152 @@ def __init__(self, start_step: Union[None, int], end_step: Union[None, int]): self._start_step: int = start_step if start_step is not None else 0 self._end_step: int = end_step if end_step is not None else sys.maxsize - def module_post_forward(self, activation: torch.Tensor, depth: int, name: str, step: int): + def pre_forward_module_apply( + self, + run_rtx: RuntimeStates, + module: torch.nn.Module, + args: ORTModelInputOutputType, + kwargs: ORTModelInputOutputType, + ) -> Tuple[ORTModelInputOutputType, ORTModelInputOutputType]: + """This function is called inside the nn.Module's pre-forward hook. + + Args: + run_rtx (RuntimeStates): The runtime states of SubscriberManager. + module (torch.nn.Module): The module that is being executed. + args (ORTModelInputOutputType): The positional arguments that are passed to the module's pre-forward hook. + kwargs (ORTModelInputOutputType): The keyword arguments that are passed to the module's pre-forward hook. + + Returns: + Tuple[ORTModelInputOutputType, ORTModelInputOutputType]: Updated args and kwargs. + """ - This function will be run after the torch Module forward is completed. + if self._need_skip_step(run_rtx.global_states.execution_step): + return args, kwargs + + updated_args, updated_kwargs = self.pre_forward_module_apply_impl(run_rtx, module, args, kwargs) + return updated_args, updated_kwargs + + def pre_forward_module_apply_impl( + self, + run_rtx: RuntimeStates, + module: torch.nn.Module, + args: ORTModelInputOutputType, + kwargs: ORTModelInputOutputType, + ) -> Tuple[ORTModelInputOutputType, ORTModelInputOutputType]: + return args, kwargs + + def pre_forward_tensor_apply( + self, run_rtx: RuntimeStates, module: torch.nn.Module, tensor_index: int, tensor: torch.Tensor + ) -> torch.Tensor: + """This function is called inside the nn.Module's pre-forward hook. Args: - activation: Tensor to be inspected. - depth: The indent level of the torch Module generating `activation`. - name: The unique name for the `activation`. - step: Current execution step. + run_rtx (RuntimeStates): The runtime states of SubscriberManager. + module (torch.nn.Module): The module that is being executed. + tensor_index (int): The index of the tensor in the input tensor list. + tensor (torch.Tensor): The tensor is one of module's forward inputs. """ - if self._start_step <= step < self._end_step: - self.module_post_forward_impl(activation, depth, name, step) + if self._need_skip_step(run_rtx.global_states.execution_step): + return tensor - def module_pre_backward(self, activation: torch.Tensor, depth: int, name: str, step: int): + return self.pre_forward_tensor_apply_impl(run_rtx, module, tensor_index, tensor) + + def pre_forward_tensor_apply_impl( + self, run_rtx: RuntimeStates, module: torch.nn.Module, tensor_index: int, tensor: torch.Tensor + ) -> torch.Tensor: + return tensor + + def post_forward_module_apply( + self, + run_rtx: RuntimeStates, + module: torch.nn.Module, + args: ORTModelInputOutputType, + outputs: ORTModelInputOutputType, + ) -> Tuple[ORTModelInputOutputType, ORTModelInputOutputType]: + """This function is called inside the nn.Module's post-forward hook. + + Args: + run_rtx (RuntimeStates): The runtime states of SubscriberManager. + module (torch.nn.Module): The module that is being executed. + args (ORTModelInputOutputType): The inputs arguments that are passed to the module's post-forward + hook as input. + outputs (ORTModelInputOutputType): The outputs arguments that are passed to the module's post-forward + hook as input. + + Returns: + Tuple[ORTModelInputOutputType, ORTModelInputOutputType]: Updated inputs and outputs. """ - This function will be run before the torch Module backward run. + if self._need_skip_step(run_rtx.global_states.execution_step): + return args, outputs + + return self.post_forward_module_apply_impl(run_rtx, module, args, outputs) + + def post_forward_module_apply_impl( + self, + run_rtx: RuntimeStates, + module: torch.nn.Module, + args: ORTModelInputOutputType, + outputs: ORTModelInputOutputType, + ) -> Tuple[ORTModelInputOutputType, ORTModelInputOutputType]: + return args, outputs + + def post_forward_tensor_apply( + self, run_rtx: RuntimeStates, module: torch.nn.Module, tensor_index: int, tensor: torch.Tensor + ) -> torch.Tensor: + """This function is called inside the nn.Module's post-forward hook. Args: - activation: Tensor to be inspected. - depth: The indent level of the torch Module generating `activation`. - name: The unique name for the `activation`. - step: Current execution step. + run_rtx (RuntimeStates): The runtime states of SubscriberManager. + module (torch.nn.Module): The module that is being executed. + tensor_index (int): The index of the tensor in the output tensor list. + tensor (torch.Tensor): The tensor is one of module's forward outputs. + + Returns: + torch.Tensor: Updated tensor. """ - if self._start_step <= step < self._end_step: - self.module_pre_backward_impl(activation, depth, name, step) + if self._need_skip_step(run_rtx.global_states.execution_step): + return tensor + + return self.post_forward_tensor_apply_impl(run_rtx, module, tensor_index, tensor) - def module_post_forward_impl(self, activation: torch.Tensor, depth: int, name: str, step: int): - raise NotImplementedError() + def post_forward_tensor_apply_impl( + self, run_rtx: RuntimeStates, module: torch.nn.Module, tensor_index: int, tensor: torch.Tensor + ) -> torch.Tensor: + return tensor - def module_pre_backward_impl(self, activation: torch.Tensor, depth: int, name: str, step: int): - raise NotImplementedError() + def post_forward_outmost_module_apply( + self, + run_rtx: RuntimeStates, + module: torch.nn.Module, + args: ORTModelInputOutputType, + outputs: ORTModelInputOutputType, + ) -> Tuple[ORTModelInputOutputType, ORTModelInputOutputType]: + """This function is called inside the outmost nn.Module's post-forward hook. + + Args: + run_rtx (RuntimeStates): The runtime states of SubscriberManager. + module (torch.nn.Module): The module that is being executed. + args (ORTModelInputOutputType): The inputs arguments that are passed to the module's post-forward + hook as input. + outputs (ORTModelInputOutputType): The outputs arguments that are passed to the module's post-forward + hook as input. + + Returns: + Tuple[ORTModelInputOutputType, ORTModelInputOutputType]: Updated inputs and outputs. + """ + if self._need_skip_step(run_rtx.global_states.execution_step): + return args, outputs + + return self.post_forward_outmost_module_apply_impl(run_rtx, module, args, outputs) + + def post_forward_outmost_module_apply_impl( + self, + run_rtx: RuntimeStates, + module: torch.nn.Module, + args: ORTModelInputOutputType, + outputs: ORTModelInputOutputType, + ) -> Tuple[ORTModelInputOutputType, ORTModelInputOutputType]: + return args, outputs + + def _need_skip_step(self, current_step: int) -> bool: + return current_step < self._start_step or current_step >= self._end_step diff --git a/orttraining/orttraining/python/training/utils/hooks/_subscriber_manager.py b/orttraining/orttraining/python/training/utils/hooks/_subscriber_manager.py index 3312182334587..b2bc64be42fc1 100644 --- a/orttraining/orttraining/python/training/utils/hooks/_subscriber_manager.py +++ b/orttraining/orttraining/python/training/utils/hooks/_subscriber_manager.py @@ -4,99 +4,34 @@ # -------------------------------------------------------------------------- -from collections import abc -from typing import Callable, List, Union +import inspect +from contextlib import contextmanager +from typing import List, Optional, Set, Tuple, Union +import onnx import torch -from onnxruntime.training.ortmodule import ORTModule +from onnxruntime.training.utils import extract_data_and_schema, unflatten_data_using_schema -from ._subscriber_base import SubscriberBase +from ._subscriber_base import RuntimeStates, SubscriberBase +ORT_NO_INCREASE_GLOBAL_STEP = [False] -class _RuntimeStates: - """ - A data struct holding states for runtime context. Tho kinds of states are included: - > Global states that are one-time collected during model hook registration. A global execution step is - also initialized to reflect how many steps have been executed, it will get updated after each step - completes its forward path. - > Intra-execution step states, initialized and cleaned up intended only for current execution step. - Usually, it carries intermediate information during the model execution. - """ - - class _GlobalStates: - def __init__(self): - # Used to track current execution step, e.g. how many forward/backward path is called. - self.execution_step = 0 - # Used to store the depth of each module, which indicate the indentation level of the module. - self.module_index_to_depth = {} - # Used to store the unique id of each sequential activation. - self.module_to_module_index = {} - - self.subscribers = set() - - class _ExecutionStepStates: - def __init__(self): - # Used to store the activation tensor names, if already handled, then skipped. - # Need to clear after each step. - self.observed_activation_names = {} - - def __init__(self): - self.global_states = _RuntimeStates._GlobalStates() - self.reset_step_states() - - def reset_step_states(self): - self.execution_step_states = _RuntimeStates._ExecutionStepStates() - -class _InspectActivation(torch.autograd.Function): - """ - This class is used to run the subscriber's forward and backward functions. +@contextmanager +def no_increase_global_step(): + """During ONNX model export phase, forward run is triggered, but we don't want to increase the global step, then + Then the first iteration run will still start with 0, aligned with PyTorch's first iteration run. """ - - @staticmethod - def forward(ctx, activation_name: str, module_idx: int, run_ctx: _RuntimeStates, input_tensor): - """ - Make sure there is a same number of `tensor` type inputs and outputs. - This is enforced by ORT's PythonOp's schema check. - """ - depth = run_ctx.global_states.module_index_to_depth[module_idx] - - input_tensor_copied = None - if input_tensor is None or not isinstance(input_tensor, torch.Tensor): - input_tensor_copied = input_tensor - else: - input_tensor_copied = input_tensor.detach().clone() - - ctx.current_step = run_ctx.global_states.execution_step - ctx.name = activation_name - ctx.id = module_idx - ctx.depth = depth - ctx.subscribers = run_ctx.global_states.subscribers - - # Run subscribers sequentially. - for subscriber in run_ctx.global_states.subscribers: - subscriber.module_post_forward(input_tensor_copied, depth, activation_name, ctx.current_step) - - return input_tensor.detach() if input_tensor is not None else None - - @staticmethod - def backward(ctx, grad_output): - val = None - if grad_output is None or not isinstance(grad_output, torch.Tensor): - val = grad_output - else: - val = grad_output.detach().clone() - - for subscriber in ctx.subscribers: - subscriber.module_pre_backward(val, ctx.depth, ctx.name, ctx.current_step) - - return None, None, None, grad_output.detach() if grad_output is not None else None + try: + ORT_NO_INCREASE_GLOBAL_STEP[0] = True + yield + finally: + ORT_NO_INCREASE_GLOBAL_STEP[0] = False class _IncrementStep(torch.autograd.Function): - """ - This class is used to manage the global execution step, e.g. + """This class is used to manage the global execution step, e.g. global step increment by one, once a full forward path is completed and the state clear. This autograd Function is registered as a post-forward hook to the root module. So once the root @@ -105,65 +40,55 @@ class _IncrementStep(torch.autograd.Function): """ @staticmethod - def forward(ctx, run_ctx, input_tensor): - """ - Make sure there is a same number of `tensor` inputs and outputs. + def forward(ctx, run_ctx: RuntimeStates, *input_tensor_list: Tuple[torch.Tensor, ...]) -> Tuple[torch.Tensor, ...]: + """Make sure there is the same number of `tensor` inputs and outputs. This is enforced by ORT's PythonOp's schema check. """ ctx.current_step = run_ctx.global_states.execution_step ctx.run_ctx = run_ctx - # We cannot do the step incremental here. Imagine the outside-most module has multiple outputs, - # we need to increase the step only at the very last output handling. - # We avoid the complexity to probe the last output handling, and instead, we assume once - # the very first backward of the outside-most module is called, then the forward pass MUST be completed. - - # Be noted: it is not safe to register _IncrementStep only for one of the outputs of the outside-most module, - # because we are not sure which output branch is executed earlier, for example. - # OuterMostModuleOutputs - # / \ - # OuterMostModuleOutputs_0_0th_output OuterMostModuleOutputs_0_1th_output - # | | - # PythonOp(_InspectActivation) PythonOp(_InspectActivation) - # | | - # PythonOp(_IncrementStep) graph output - # | - # graph output - # The PythonOp(_InspectActivation) (who relies on global step) after 1th output is possible - # to run before or after PythonOp(_IncrementStep), so increasing the step is not safe. - - return input_tensor.detach() if isinstance(input_tensor, torch.Tensor) else input_tensor + # Uncomment the following line for debugging purposes. + # if ctx.current_step >= 0: + # print(f"{'='*6} Completed forward pass for STEP {ctx.current_step} {'='*6}") - @staticmethod - def backward(ctx, grad_output): - # In case there are multiple backward calls for multiple outputs of the outside-most module. - if ctx.current_step == ctx.run_ctx.global_states.execution_step: - if ctx.current_step >= 0: - print(f"{'='*6} Completed forward pass for STEP {ctx.current_step} {'='*6}") + if ORT_NO_INCREASE_GLOBAL_STEP[0] is False: ctx.run_ctx.global_states.execution_step += 1 - ctx.run_ctx.reset_step_states() - return None, grad_output.detach() if isinstance(grad_output, torch.Tensor) else grad_output + return tuple(t.detach().requires_grad_(t.requires_grad) for t in input_tensor_list) + + @staticmethod + def backward(ctx, *grad_output: Tuple[Optional[torch.Tensor], ...]) -> Tuple[Optional[torch.Tensor], ...]: + return (None, *tuple(g for g in grad_output)) + + @staticmethod + def infer_shape( + node: onnx.NodeProto, + tensor_input_shapes: List[Optional[List[Union[int, str]]]], + tensor_input_dtypes: List[torch.onnx.TensorProtoDataType], + ) -> Tuple[List[Optional[List[Union[int, str]]]], List[torch.onnx.TensorProtoDataType]]: + return tensor_input_shapes, tensor_input_dtypes class SubscriberManager: - """ - This class is used to manage all the subscribers and register the post-forward hook to the root module. - `subscribe()` is used to register a list of subscribers. + """This class is used to manage all the subscribers and register subscribers' custom actions as PyTorch hooks + to the nn.Modules. - Currently, the hook handled here is post forward hook for nn.Module. The hook is registered for all nn.Modules - recursively. Each hook inserts a PythonOp for every tensor output generated by the corresponding module. - Each subscriber implementation is called in the PythonOp's forward function, and backward function. + For the module-level/tensor_level custom actions defined by subscribers, they are registered as corresponding + PyTorch hooks in the sequence of the subscribers' registration order. There is one special handling for global step increment and state clear. A post-forward hook is registered for the outside-most module, which is the root module. In that hook, _IncrementStep is called, which will - increase the step by 1 once the very first time its backward is called (check _IncrementStep for details). + increase the step by 1 once the post forward hook is called if running without no_increase_global_step(). + `no_increase_global_step` is used to skip the step increment during ONNX model export. """ def __init__(self): - self._run_ctx: _RuntimeStates = _RuntimeStates() + self._run_ctx = RuntimeStates() + self._subscribers: Set[SubscriberBase] = set() + self._pre_forward_hooks = [] + self._post_forward_hooks = [] - def subscribe(self, module: Union[torch.nn.Module, ORTModule], subscribers: List[SubscriberBase]): + def subscribe(self, module: torch.nn.Module, subscribers: List[SubscriberBase]): """ The API is called externally to register hooks that are implicitly defined by subscribers. Each time all global states will be cleaned up once called. @@ -172,49 +97,110 @@ def subscribe(self, module: Union[torch.nn.Module, ORTModule], subscribers: List raise ValueError("module must be a torch.nn.Module instance") self._reset_all_states() + self._subscribers.clear() - if isinstance(module, ORTModule): - module = module.module + try: + # Put the import here to avoid the module level dependency on onnxruntime.training.ortmodule + from onnxruntime.training.ortmodule import ORTModule + + if isinstance(module, ORTModule): + module = module.module + except ImportError: + pass for subscriber in subscribers: if not isinstance(subscriber, SubscriberBase): raise ValueError("subscriber must be a SubscriberBase instance") - self._run_ctx.global_states.subscribers.add(subscriber) + self._subscribers.add(subscriber) self._initialize(module) + def get_subscriber(self, subscriber_type: type) -> SubscriberBase: + for subscriber in self._subscribers: + if isinstance(subscriber, subscriber_type): + return subscriber + raise RuntimeError(f"Subscriber {subscriber_type} is not registered.") + + def get_run_context(self) -> RuntimeStates: + return self._run_ctx + def _reset_all_states(self): - self._run_ctx = _RuntimeStates() + self._pre_forward_hooks.clear() + self._post_forward_hooks.clear() + self._run_ctx = RuntimeStates() def _initialize(self, module: torch.nn.Module): - """ - Register hooks for the specified module. - """ - if len(self._run_ctx.global_states.subscribers) == 0: + """Register hooks for the specified module.""" + if len(self._subscribers) == 0: raise RuntimeError("No subscribers are registered.") + def _pre_forward_outmost_module_hook(module, module_inputs): + # This check is to support the case where module is first registered in the subscriber manager, + # then the module and hook are copied, when new module instance runs to the hook, the global states + # are not reset, so the logic depends on the global states will fail. So in the outer-most pre-forward hook + # we reset the global states. + + # Be noted, the first run anyway will run in PyTorch. + if module not in self._run_ctx.global_states.module_to_module_index: + import warnings + + warnings.warn( + "Initialize global states for the first time, this should only happen once for each outmost module." + ) + self._initialize_one_time_global_states(module) + return module_inputs + + module.register_forward_pre_hook(_pre_forward_outmost_module_hook) + next_module_index = [0] - # Register post forward hook for every module, inside the hook, we loop every tensor output of the module, - # and wrap it with an autograd Function called _InspectActivation (which takes in a tensor and returns the same - # tensor). In this way, we keep ORT and PyTorch run have the same boundary to check activation equality. self._register_hooks_recursively(module, 1, next_module_index) # Register post forward hook for the outside-most module, then we increase the dump step. - # Be noted, if backward is not triggered, the global dump step remains the original number, - # which means the subsequent run will override the previous dump files. This indeed happens to imagine ORTModule - # firstly export graph (run the forward only), after the gradient graph is built, another forward+backward is - # triggered, override the previous dump files. - def _post_forward_outmost_module_hook(module, _, module_outputs): - def _apply_to_tensors_func(_, outputs): - return _IncrementStep.apply(self._run_ctx, outputs) + def _post_forward_outmost_module_hook(module, module_inputs, module_outputs): + # Call post outmost module forward custom actions for subscribers + for sub in self._subscribers: + module_inputs, module_outputs = sub.post_forward_outmost_module_apply( + self._run_ctx, module, module_inputs, module_outputs + ) + + flatten_output_tensor_list, output_schema = extract_data_and_schema(module_outputs) + output_tensors = _IncrementStep.apply(self._run_ctx, *flatten_output_tensor_list) + restored_outputs = unflatten_data_using_schema(output_tensors, output_schema) - return self._apply_function_to_tensors(module, module_outputs, _apply_to_tensors_func) + return restored_outputs module.register_forward_hook(_post_forward_outmost_module_hook) + def _initialize_one_time_global_states(self, module: torch.nn.Module): + def _reset_recursively(module: torch.nn.Module, depth: int, next_module_index: List[int]): + """ + Called to register hooks for every `torch.nn.Module`. Due to `Module` can contain child `Module`s, + this function is called recursively by passing in `next_module_index` - a list of int to maintain a + global incremental unique module id. + + Args: + module: torch.nn.Module to register hook. + depth: the indent of the module compared with the outside-most Module. + next_module_index: list of int, carrying a global unique module index that can be used next. + """ + module_index = next_module_index[0] + module.id = module_index # STAGE3WARN#1: needed by DeepSpeed + self._run_ctx.global_states.module_index_to_depth[module_index] = depth + self._run_ctx.global_states.module_to_module_index[module] = module_index + + for child in module.children(): + if ( + isinstance(child, torch.nn.Module) + and child not in self._run_ctx.global_states.module_to_module_index + ): + next_module_index[0] += 1 + _reset_recursively(child, depth + 1, next_module_index) + + next_module_index = [0] + _reset_recursively(module, 1, next_module_index) + def _register_hooks_recursively(self, module: torch.nn.Module, depth: int, next_module_index: List[int]): - """ - Called to register hooks for every `torch.nn.Module`. Due to `Module` can contain child `Module`s, + """Register hooks for every `torch.nn.Module`. Due to `Module` can contain child `Module`s, this function is called recursively by passing in `next_module_index` - a list of int to maintain a global incremental unique module id. @@ -224,6 +210,7 @@ def _register_hooks_recursively(self, module: torch.nn.Module, depth: int, next_ next_module_index: list of int, carrying a global unique module index that can be used next. """ module_index = next_module_index[0] + module.id = module_index # STAGE3WARN#2: needed by DeepSpeed self._run_ctx.global_states.module_index_to_depth[module_index] = depth self._run_ctx.global_states.module_to_module_index[module] = module_index @@ -232,69 +219,54 @@ def _register_hooks_recursively(self, module: torch.nn.Module, depth: int, next_ next_module_index[0] += 1 self._register_hooks_recursively(child, depth + 1, next_module_index) - def _post_forward_module_hook(module, _, module_outputs): - if module in self._run_ctx.global_states.module_to_module_index and isinstance(module, torch.nn.Module): - module_index = self._run_ctx.global_states.module_to_module_index[module] - - def _apply_to_tensors_func(index, activation_tensor): - name = f"{module.__class__.__name__}_{module_index}_{index}th_output" - if name not in self._run_ctx.execution_step_states.observed_activation_names: - self._run_ctx.execution_step_states.observed_activation_names[name] = True - return _InspectActivation.apply(name, module_index, self._run_ctx, activation_tensor) - - return activation_tensor - - return self._apply_function_to_tensors(module, module_outputs, _apply_to_tensors_func) - return module_outputs - - module.register_forward_hook(_post_forward_module_hook) - - def _is_builtin_type(self, obj): - # https://stackoverflow.com/a/17795199 - return obj.__class__.__module__ in ["__builtin__", "builtins"] - - def _apply_function_to_tensors(self, module: torch.nn.Module, data, func: Callable): - """ - Apply func to all tensors in the given object. - - Args: - module: the module that generates the tensors. - data: the object that contains activation tensors. - func: the function to apply to the tensors. - """ - tensor_output_idx: List[int] = [0] - - def _apply_to_tensors_by_flatten( - module: torch.nn.Module, - index_for_tensor_output: List[int], - outputs, - func: Callable, - ): - if isinstance(outputs, abc.Sequence): - touched_outputs = [] - for output in outputs: - touched_output = _apply_to_tensors_by_flatten(module, index_for_tensor_output, output, func) - touched_outputs.append(touched_output) - return outputs.__class__(touched_outputs) - - if isinstance(outputs, abc.Mapping): - # apply inplace to avoid recreating dict inherited objects - for key in outputs: - outputs[key] = _apply_to_tensors_by_flatten( - module, - index_for_tensor_output, - outputs[key], - func, - ) - return outputs - - if isinstance(outputs, torch.Tensor): - cur_id = index_for_tensor_output[0] - index_for_tensor_output[0] += 1 - return func(cur_id, outputs) - - if not self._is_builtin_type(outputs): - raise RuntimeError(f"Unknown type {type(outputs)}") - return outputs - - return _apply_to_tensors_by_flatten(module, tensor_output_idx, data, func) + def _pre_forward_module_with_kwargs_hook(module, module_inputs, kwargs): + # Module level hook + for sub in self._subscribers: + module_inputs, kwargs = sub.pre_forward_module_apply(self._run_ctx, module, module_inputs, kwargs) + + # Tensor level hook + flatten_positional_input_tensor_list, input_schema = extract_data_and_schema(module_inputs) + flatten_keyword_input_tensor_list, keyword_input_schema = extract_data_and_schema(kwargs) + + for sub in self._subscribers: + tensor_list = [] + for tensor_index, tensor in enumerate(flatten_positional_input_tensor_list): + tensor_list.append(sub.pre_forward_tensor_apply(self._run_ctx, module, tensor_index, tensor)) + flatten_positional_input_tensor_list = tensor_list + + tensor_list = [] + for tensor_index, tensor in enumerate(flatten_keyword_input_tensor_list): + tensor_list.append(sub.pre_forward_tensor_apply(self._run_ctx, module, tensor_index, tensor)) + flatten_keyword_input_tensor_list = tensor_list + + module_inputs = unflatten_data_using_schema(flatten_positional_input_tensor_list, input_schema) + kwargs = unflatten_data_using_schema(flatten_keyword_input_tensor_list, keyword_input_schema) + + return module_inputs, kwargs + + def _pre_forward_module_hook(module, module_inputs): + return _pre_forward_module_with_kwargs_hook(module, module_inputs, {}) + + def _post_forward_module_hook(module, module_inputs, module_outputs): + # Module level hook + for sub in self._subscribers: + _, module_outputs = sub.post_forward_module_apply(self._run_ctx, module, module_inputs, module_outputs) + + # Tensor level hook + flatten_output_tensor_list, output_schema = extract_data_and_schema(module_outputs) + for sub in self._subscribers: + tensor_list = [] + for tensor_index, tensor in enumerate(flatten_output_tensor_list): + tensor_list.append(sub.post_forward_tensor_apply(self._run_ctx, module, tensor_index, tensor)) + flatten_output_tensor_list = tensor_list + + return unflatten_data_using_schema(flatten_output_tensor_list, output_schema) + + # "with_kwargs" is not available for low versions of PyTorch. + if "with_kwargs" in inspect.signature(module.register_forward_pre_hook).parameters: + self._pre_forward_hooks.append( + module.register_forward_pre_hook(_pre_forward_module_with_kwargs_hook, with_kwargs=True) + ) + else: + self._pre_forward_hooks.append(module.register_forward_pre_hook(_pre_forward_module_hook)) + self._post_forward_hooks.append(module.register_forward_hook(_post_forward_module_hook)) diff --git a/orttraining/orttraining/python/training/utils/hooks/_zero_offload_subscriber.py b/orttraining/orttraining/python/training/utils/hooks/_zero_offload_subscriber.py new file mode 100644 index 0000000000000..ad1297962db71 --- /dev/null +++ b/orttraining/orttraining/python/training/utils/hooks/_zero_offload_subscriber.py @@ -0,0 +1,527 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# -------------------------------------------------------------------------- + +import ctypes +import inspect +import warnings +from collections import OrderedDict +from types import CodeType, FunctionType +from typing import Callable, Dict, List, Optional, Tuple, Union + +import onnx +import torch + +from onnxruntime.training.utils import ( + ORTModelInputOutputType, + extract_data_and_schema, + pytorch_dtype_to_onnx, + unflatten_data_using_schema, +) + +from ._subscriber_base import RuntimeStates, SubscriberBase + + +def _get_ort_compatible_zero_stage3_hook_function(debug, stats_output_dir, stats_overwrite): + """Create ort compatible hook function for DeepSpeed ZeRO stage3. + + Args: + debug: whether to enable convergence debugging. + stats_output_dir: the directory to store convergence stats. + stats_overwrite: whether to overwrite the stats file if it already exists. + """ + + # Used to monkey patch the original function + # Adapted from https://github.com/microsoft/DeepSpeed/blob/e8318634b4313eaad89842cf4322e1762d34ced3/deepspeed/runtime/zero/parameter_offload.py#L333 + def _setup_zero_stage3_ort_compatible_hooks(self): + self.hierarchy = 0 + + from onnxruntime.training.utils.hooks import StatisticsSubscriber, SubscriberManager, ZeROOffloadSubscriber + from onnxruntime.training.utils.hooks._zero_offload_subscriber import _zero_offload_one_time_initializer + + subscribers = [ZeROOffloadSubscriber(self, _zero_offload_one_time_initializer)] + if debug is True: + subscribers.append(StatisticsSubscriber(output_dir=stats_output_dir, override_output_dir=stats_overwrite)) + # Each DeepSpeed engine has a separate subscriber manager. + self._offload_subscriber_manager = SubscriberManager() + self._offload_subscriber_manager.subscribe(self.module, subscribers) + self.forward_hooks.extend(self._offload_subscriber_manager._pre_forward_hooks) + self.forward_hooks.extend(self._offload_subscriber_manager._post_forward_hooks) + + # Add top module to stack trace + global FWD_MODULE_STACK # noqa: PLW0602 + FWD_MODULE_STACK.append(self.module) + + return _setup_zero_stage3_ort_compatible_hooks + + +# Adapted from https://github.com/microsoft/DeepSpeed/blob/e8318634b4313eaad89842cf4322e1762d34ced3/deepspeed/runtime/zero/linear.py#L104 +# In the original logic, if bias is None, after export to ONNX, None becomes a constant, so backward op complains +# output count more than needed. +def _zero3_linear_wrap_ort_compatible(input, weight, bias=None): + from deepspeed.runtime.zero.linear import LinearFunctionForZeroStage3 + + return LinearFunctionForZeroStage3.apply(input, weight, bias) + + +class _ZeROOffloadOneTimeInitializer: + """Store the hook functions from DeepSpeed ZeRO offload. + + Hook functions code collected from DeepSpeed. + """ + + def __init__(self): + self._code_store: OrderedDict[str, CodeType] = {} + + def collect_code(self, function: Callable): + """Collect the function `CodeType`, which is the code object of the function.""" + code_obj = function.__code__ + for c in code_obj.co_consts: + if inspect.iscode(c): + self._code_store[c.co_name] = c + + +_zero_offload_one_time_initializer = None + +try: + # Have to import below explicitly, otherwise it complains about _apply_to_tensors_only not found. + # The hooks reference functions or classes in that file. + from deepspeed.runtime.zero.parameter_offload import * # noqa: F403 + from deepspeed.runtime.zero.parameter_offload import DeepSpeedZeRoOffload, _apply_to_tensors_only # noqa: F401 + from deepspeed.utils import instrument_w_nvtx # noqa: F401 + + # Used to collect the hook functions's code object from DeepSpeed ZeRO offload, this should be initialized only once. + if _zero_offload_one_time_initializer is None: + _zero_offload_one_time_initializer = _ZeROOffloadOneTimeInitializer() + _zero_offload_one_time_initializer.collect_code(DeepSpeedZeRoOffload._register_hooks_recursively) + _zero_offload_one_time_initializer.collect_code(DeepSpeedZeRoOffload.setup_zero_stage3_hooks) + + # This is the function to enable ORT ZeRO offload. + def configure_ort_compatible_zero_stage3(debug=False, stats_output_dir="./", stats_overwrite=False): + """Configure ZeRO stage3 to be ORT compatible. + + This function will overwrite the original DeepSpeed ZeRO stage3 hooks to make it ORT compatible. + """ + + # Only done once no matter how many times this function is called for different modules. + DeepSpeedZeRoOffload.setup_zero_stage3_hooks = _get_ort_compatible_zero_stage3_hook_function( + debug, stats_output_dir, stats_overwrite + ) + + from deepspeed.runtime.zero.linear import zero3_linear_wrap + + if torch.nn.functional.linear is zero3_linear_wrap: + torch.nn.functional.linear = _zero3_linear_wrap_ort_compatible + +except ImportError as e: + warnings.warn(f"DeepSpeed import error {e}") + + def configure_ort_compatible_zero_stage3(debug=False, stats_output_dir=None, stats_overwrite=False): + raise RuntimeError("DeepSpeed is not installed, cannot configure ORT compatible ZeRO stage3.") + + +def _get_params_for_current_module(module: torch.nn.Module) -> List[torch.nn.parameter.Parameter]: + """Retrieve the parameters for this module. + + Logic adapted from + https://github.com/microsoft/DeepSpeed/blob/9d79cfd1e90cae9306dc1b5837d374b2c9489ac8/deepspeed/runtime/zero/partitioned_param_coordinator.py#L267 + """ + from deepspeed.runtime.zero.partitioned_param_coordinator import iter_params + + # Retrieve all parameters for this module. + partitioned_params = [param for param in iter_params(module)] + + return partitioned_params + + +def _get_all_zero_stage3_params(module: torch.nn.Module) -> Dict[str, torch.nn.parameter.Parameter]: + """Retrieve all the parameters that are offloaded.""" + from deepspeed.runtime.zero.partition_parameters import ZeroParamStatus + + all_offloaed_params = OrderedDict() + for name, param in module.named_parameters(): + if hasattr(param, "ds_status") and param.ds_status == ZeroParamStatus.NOT_AVAILABLE: + all_offloaed_params[name] = param + + return all_offloaed_params + + +class ORTZeROOffloadPreForwardFunction(torch.autograd.Function): + """This function is a common bridge to call original PyTorch's pre_forward_function""" + + @staticmethod + def forward( + ctx, + module, + pre_forward_with_kwargs_function, + args_schema, + kwargs_schema, + args_tensor_count, + kwargs_tensor_count, + *tensor_list, + ): + """ + Args: + ctx: context object + module: the module to be called + pre_forward_with_kwargs_function: the function to be called before forward (PyTorch's pre_forward_function) + args_schema: the schema of the args, used to reconstruct the args in original form in + PyTorch's pre_forward_function's inputs. + kwargs_schema: the schema of the kwargs, used to reconstruct the kwargs in original form in + PyTorch's pre_forward_function's inputs. + args_tensor_count: the number of tensors in args. + kwargs_tensor_count: the number of tensors in kwargs. + tensor_list: the list of tensors, the first args_tensor_count tensors are args, the next + kwargs_tensor_count tensors are kwargs, the rest are the parameters for offload. + """ + args_tensors = tensor_list[:args_tensor_count] + kwargs_tensors = tensor_list[args_tensor_count : args_tensor_count + kwargs_tensor_count] + + # For PyTorch runs, the sizes are all 0, it does not need a gradient because + # param._detach().requires_grad_(False) is called. + # But for ORT runs, the sizes are all [1], as output of weight retrieval function. + # So we keep track of the shapes and dtypes of the passed-in tensors, then generate the grads in backward. + # While for both PyTorch and ORT runs, the grad is not important because they are not param grads + # anymore, they are only used for completing the full backward propagation. + passed_in_param_tensors = tensor_list[args_tensor_count + kwargs_tensor_count :] + ctx.shapes = [p.shape for p in passed_in_param_tensors] + ctx.dtypes = [p.dtype for p in passed_in_param_tensors] + ctx.devices = [p.device for p in passed_in_param_tensors] + + args = unflatten_data_using_schema(args_tensors, args_schema) + kwargs = unflatten_data_using_schema(kwargs_tensors, kwargs_schema) + + # We will re-retrieve the parameter tensors other than use the one passed in input (of size 0 for + # those partitioned params). + # This is required for ORT run because in ORT graph, the tensor of size 0 will always be size 0 + # (this step is not necessary for PyTorch run, because PyTorch will re-use the same tensor + # while .data got updated to full-sized data after pre_forward_with_kwargs_function is called). + partitioned_params = _get_params_for_current_module(module) + ctx.partitioned_params = partitioned_params + + assert len(partitioned_params) == len(passed_in_param_tensors) + + f_ret = pre_forward_with_kwargs_function(module, args, kwargs) + + if f_ret is None: + updated_args, updated_kwargs = args, kwargs + else: + assert isinstance(f_ret, tuple) + updated_args, updated_kwargs = f_ret + + ctx.module = module + + updated_args_tensors, _ = extract_data_and_schema(updated_args) + updated_kwargs_tensors, _ = extract_data_and_schema(updated_kwargs) + + rets = tuple(updated_args_tensors + updated_kwargs_tensors) + rets += tuple([p.detach().requires_grad_(p.requires_grad) for p in partitioned_params]) + + # PyTorch exporter does not support an empty list of tensors, so we have this check. + assert len(rets) != 0 + return rets + + @staticmethod + def backward(ctx, *grads): + updated_grads = grads + + input_count = len(updated_grads) - len(ctx.partitioned_params) + param_start_offset = input_count + + # Only need to accumulate grad explicitly for ORT run (e.g. ctx.shapes[0] == (1,)); + # In the PyTorch run, the accumulation happens automatically. + need_manual_grad_acc = len(ctx.shapes) > 0 and ctx.shapes[0] == (1,) + if need_manual_grad_acc: + for param_index, p in enumerate(ctx.partitioned_params): + g = updated_grads[param_index + param_start_offset] + if g is None: + raise RuntimeError(f"param {p} has no grad, this should not happen.") + # Param gradient accumulation is triggered here, along with the attached hooks, done by PyTorch. + assert p.shape == g.shape, f"param_index: {param_index} - param shape {p.shape} != grad shape {g.shape}" + p.backward(g) + + # At this point, the **real** param grads are already updated, the following grads are only used for + # completing the full backward propagation, will not affect parameter updates. + passed_in_param_grad = [ + torch.zeros(shape, dtype=dtype, device=device) + for shape, dtype, device in zip(ctx.shapes, ctx.dtypes, ctx.devices) + ] + + zero_grads = updated_grads[:input_count] + tuple(passed_in_param_grad) + + return (None, None, None, None, None, None, *zero_grads) + + @staticmethod + def infer_shape( + node: onnx.NodeProto, + tensor_input_shapes: List[Optional[List[Union[int, str]]]], + tensor_input_dtypes: List[torch.onnx.TensorProtoDataType], + ) -> Tuple[List[Optional[List[Union[int, str]]]], List[torch.onnx.TensorProtoDataType]]: + input_pointer_scalars_attr_name = "input_pointer_scalars" + found = [attr for attr in node.attribute if attr.name == input_pointer_scalars_attr_name] + assert len(found) == 1 + input_pointer_scalars = found[0].ints + + # Restore the nn.Module from the pointer. + module = ctypes.cast(input_pointer_scalars[0], ctypes.py_object).value + + partitioned_params = _get_params_for_current_module(module) + tensor_output_shapes = tensor_input_shapes + tensor_output_dtypes = tensor_input_dtypes + start_offset = len(tensor_input_shapes) - len(partitioned_params) + for index, param in enumerate(partitioned_params): + tensor_output_shapes[start_offset + index] = list(param.ds_shape) + tensor_output_dtypes[start_offset + index] = pytorch_dtype_to_onnx(param.dtype) + assert len(tensor_output_shapes) == len(tensor_input_shapes) + assert len(tensor_output_dtypes) == len(tensor_input_dtypes) + + return tensor_output_shapes, tensor_output_dtypes + + +class ORTZeROOffloadPostForwardFunction(torch.autograd.Function): + @staticmethod + def forward( + ctx, + module, + post_forward_function, + pre_backward_function, + output_schema, + *output_tensors, + ): + """ + Args: + ctx: context object + module: the module to be called + post_forward_function: the function to be called after forward (PyTorch's post_forward_function) + pre_backward_function: the function to be called before backward (PyTorch's pre_backward_function) + output_schema: the schema of the output, used to reconstruct the output in its original form in + PyTorch's post_forward_function's inputs. + output_tensors: the list of tensors. + + """ + outputs = unflatten_data_using_schema(output_tensors, output_schema) + + # STAGE3WARN#3: _post_forward_module_hook's second argument `input is not used, so we just pass a None here. + updated_outputs = post_forward_function(module, None, outputs) + + if updated_outputs is None: + updated_output_tensors = output_tensors + else: + updated_output_tensors, _ = extract_data_and_schema(updated_outputs) + + ctx.module = module + ctx.pre_backward_function = pre_backward_function + rets = [o.detach().requires_grad_(o.requires_grad) for o in updated_output_tensors] + return tuple(rets) + + @staticmethod + def backward(ctx, *grads): + updated_args = grads + if ctx.pre_backward_function is not None: + ret = ctx.pre_backward_function(ctx.module, grads) + if ret is not None: + updated_args = ret + return (None, None, None, None, *updated_args) + + @staticmethod + def infer_shape( + node: onnx.NodeProto, + tensor_input_shapes: List[Optional[List[Union[int, str]]]], + tensor_input_dtypes: List[torch.onnx.TensorProtoDataType], + ) -> Tuple[List[Optional[List[Union[int, str]]]], List[torch.onnx.TensorProtoDataType]]: + return tensor_input_shapes, tensor_input_dtypes + + +class _ZeROOffloadFunctions: + def __init__(self, one_time_init: _ZeROOffloadOneTimeInitializer, offloader) -> None: + self._function_store: OrderedDict[str, FunctionType] = {} + self._one_time_init = one_time_init + for name, code in self._one_time_init._code_store.items(): + cell = self._create_closure_for_ds_hook_function(offloader) + self._function_store[name] = FunctionType(code, globals(), code.co_name, None, (cell,)) + + def get(self, name: str) -> FunctionType: + return self._function_store[name] + + def _create_closure_for_ds_hook_function(self, offloader): + # https://stackoverflow.com/questions/17395338/how-to-access-a-function-inside-a-function + def make_closure_cell(_self): + def nested(): + return _self + + return nested.__closure__[0] + + cell = make_closure_cell(offloader) + return cell + + +class ZeROOffloadSubscriber(SubscriberBase): + """This subscriber is used to enable ZeRO Offload feature in a way compatible with ORTModule.""" + + def __init__(self, offloader, one_time_init: _ZeROOffloadOneTimeInitializer, enable_debug_info: bool = False): + super().__init__(None, None) + self._offloader = offloader + self._functions = _ZeROOffloadFunctions(one_time_init, self._offloader) + self._enable_debug_info = enable_debug_info + + def pre_forward_module_apply_impl( + self, + run_rtx: RuntimeStates, + module: torch.nn.Module, + args: ORTModelInputOutputType, + kwargs: ORTModelInputOutputType, + ) -> Tuple[ORTModelInputOutputType, ORTModelInputOutputType]: + """This function is a dispatcher to call DeepSpeed stage3 pre forward hooks in sequence. + + All hook functions can be retrieved from the function store, due to exporter only supports a list of tensors as + input and output for torch.autograd.Function, so we do flatten and unflatten here. + + """ + ## Handle `_post_backward_module_hook` + + # Put `_post_backward_module_hook` first because in backward, it is responsible for unloading parameters, + # we want ORTZeROOffloadPreForwardFunction's backward still be able to access the full sized parameters. + _post_backward_module_hook = self._functions.get("_post_backward_module_hook") + # STAGE3WARN#4: most logic in _post_backward_module_hook can be traced correctly so we don't need to + # wrap with PythonOp. For those cannot be traced, we handle them in STAGE3WARN#5. + updated_args = _post_backward_module_hook(module, args) + + ## Handle `_pre_forward_module_hook` + + args_tensors, args_schema = extract_data_and_schema(updated_args) + kwargs_tensors, kwargs_schema = extract_data_and_schema(kwargs) + + _pre_forward_module_hook = self._functions.get("_pre_forward_module_hook") + + args_tensor_count = len(args_tensors) + kwargs_tensor_count = len(kwargs_tensors) + + def _wrap_pre_forward_module_hook(module, args, kwargs): + rets = _pre_forward_module_hook(module, args) + updated_args, updated_kwargs = args, kwargs + if rets is not None: + updated_args = rets + + # STAGE3WARN#5: Moved from _post_backward_module_hook to make sure ORT run will trigger every iteration. + module.ds_grads_remaining = 0 + + return updated_args, updated_kwargs + + # Need to pass the parameters as input to let the exporter trace the related weights for + # current ORTZeROOffloadPreForwardFunction + partitioned_params = _get_params_for_current_module(module) + # Don't require grad for passed-in parameter, otherwise it will be treated as a leaf node, in backward + # returned 0-sized grad did not match the param's gradient accumulator function's input shape metadata, + # PyTorch run will fail during backward. + # This will not harm parameter gradient build either in ORT or PyTorch, imagine the weights are used by + # computation anyway, so the gradient will be built. This hook only references the parameter, but won't + # generate a gradient path for it. + detached_partitioned_params = [p.detach().requires_grad_(False) for p in partitioned_params] + + all_tensors = args_tensors + kwargs_tensors + detached_partitioned_params + + self._check_all_tensor(all_tensors, module, "pre_forward_module_apply_impl input check") + + rets = ORTZeROOffloadPreForwardFunction.apply( + module, + _wrap_pre_forward_module_hook, + args_schema, + kwargs_schema, + args_tensor_count, + kwargs_tensor_count, + *all_tensors, + ) + + self._check_all_tensor(rets, module, "pre_forward_module_apply_impl output check") + + updated_args_tensors = rets[:args_tensor_count] + updated_kwargs_tensors = rets[args_tensor_count : args_tensor_count + kwargs_tensor_count] + + updated_args = unflatten_data_using_schema(updated_args_tensors, args_schema) + updated_kwargs = unflatten_data_using_schema(updated_kwargs_tensors, kwargs_schema) + + return updated_args, updated_kwargs + + def post_forward_module_apply_impl( + self, + run_rtx: RuntimeStates, + module: torch.nn.Module, + args: ORTModelInputOutputType, + outputs: ORTModelInputOutputType, + ) -> Tuple[ORTModelInputOutputType, ORTModelInputOutputType]: + """This function is a dispatcher to call DeepSpeed stage3 post forward hooks in sequence. + + All hook functions can be retrieved from function store, due to exporter only supports a list of tensors as + input and output for torch.autograd.Function, so we do flatten and unflatten here. + + """ + + outputs_tensors, outputs_schema = extract_data_and_schema(outputs) + + _post_forward_module_hook = self._functions.get("_post_forward_module_hook") + + def _wrap_post_forward_module_hook(module, input, outputs): + # STAGE3WARN#6: _post_forward_module_hook applied this for each tensor output, so we do a simple wrap here. + from deepspeed.runtime.zero.partition_parameters import is_zero_param + + updated_outputs = _post_forward_module_hook(module, input, outputs) + if updated_outputs: + for updated_output in updated_outputs: + # restore zero param attributes if those get stripped by `backward_function` + if not is_zero_param(updated_output) and is_zero_param(outputs): + updated_output.ds_param_alias = outputs + return updated_outputs + else: + return outputs + + self._check_all_tensor(outputs_tensors, module, "post_forward_module_apply_impl input check") + + updated_outputs_tensors = ORTZeROOffloadPostForwardFunction.apply( + module, _wrap_post_forward_module_hook, None, outputs_schema, *outputs_tensors + ) + + self._check_all_tensor(updated_outputs_tensors, module, "post_forward_module_apply_impl output check") + + assert len(updated_outputs_tensors) == len(outputs_tensors) + + # WARN: we assume updated_output_tensors can REUSE the outputs_schema. + updated_outputs = unflatten_data_using_schema(updated_outputs_tensors, outputs_schema) + + _pre_backward_module_hook = self._functions.get("_pre_backward_module_hook") + # STAGE3WARN#7: _pre_backward_module_hook's second argument `input is not used, so we just pass a None here. + # STAGE3WARN#8: part of the original _pre_backward_module_hook can be traced correctly so we moved them into + # _wrap_post_forward_module_hook above. + updated_outputs = _pre_backward_module_hook(module, None, updated_outputs) + + return args, updated_outputs + + def post_forward_outmost_module_apply_impl( + self, + run_rtx: RuntimeStates, + module: torch.nn.Module, + args: ORTModelInputOutputType, + outputs: ORTModelInputOutputType, + ) -> Tuple[ORTModelInputOutputType, ORTModelInputOutputType]: + outputs_tensors, outputs_schema = extract_data_and_schema(outputs) + + _end_of_forward_hook = self._functions.get("_end_of_forward_hook") + self._check_all_tensor(outputs_tensors, module, "post_forward_outmost_module_apply_impl input check") + + updated_outputs_tensors = ORTZeROOffloadPostForwardFunction.apply( + module, _end_of_forward_hook, None, outputs_schema, *outputs_tensors + ) + + self._check_all_tensor(updated_outputs_tensors, module, "post_forward_outmost_module_apply_impl output check") + + assert len(updated_outputs_tensors) == len(outputs_tensors) + updated_outputs = unflatten_data_using_schema(updated_outputs_tensors, outputs_schema) + return args, updated_outputs + + def _check_all_tensor(self, tensor_list: Tuple[torch.Tensor], module: torch.nn.Module, name: str): + if not self._enable_debug_info: + return + + for t in tensor_list: + if not isinstance(t, torch.Tensor): + raise RuntimeError(f"{name} fail: {module.__class__.__name__}, input type: {type(t)}") diff --git a/orttraining/orttraining/python/training/utils/torch_io_helper.py b/orttraining/orttraining/python/training/utils/torch_io_helper.py new file mode 100644 index 0000000000000..6d7d978e90054 --- /dev/null +++ b/orttraining/orttraining/python/training/utils/torch_io_helper.py @@ -0,0 +1,313 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# -------------------------------------------------------------------------- + +import copy +import warnings +from collections import abc +from typing import List, Mapping, Optional, Sequence, Tuple, Union + +import torch + + +class PrimitiveType: + """Helper class for Python primitive types.""" + + _primitive_types = {int, bool, float} # noqa: RUF012 + + @staticmethod + def is_primitive_type(value): + """Check if `value` is a Python primitive type.""" + return type(value) in PrimitiveType._primitive_types + + @staticmethod + def get_tensor(value, device) -> torch.Tensor: + """Convert `value` to a torch.Tensor.""" + return torch.tensor(value, device=device) + + @staticmethod + def get_primitive_dtype(value): + # If `value` is a boolean, save the value of the boolean in dtype. + # This way, if the value changes from one forward call to the next, the schema will mismatch, + # and the model will be re-exported. + return f"{type(value)!s}_{value}" if isinstance(value, bool) else str(type(value)) + + +# Data types supported as model inputs and outputs. +ORTModelInputOutputType = Union[ + None, + str, + int, + bool, + float, + torch.Tensor, + Sequence["ORTModelInputOutputType"], + Mapping[str, "ORTModelInputOutputType"], +] + + +class _TensorStub: + """Tensor stub class used to represent model's input or output""" + + __slots__ = ["tensor_idx", "name", "dtype", "shape", "shape_dims"] + + def __init__( + self, + tensor_idx: int, + name: Optional[str] = None, + dtype: Optional[str] = None, + shape=None, + shape_dims: Optional[int] = None, + ): + self.tensor_idx = tensor_idx + self.name: Optional[str] = name + self.dtype: Optional[str] = dtype + self.shape = shape + self.shape_dims: Optional[int] = shape_dims # r.g. rank. + + def __repr__(self) -> str: + result = "_TensorStub(" + + list_of_str = [] + if self.tensor_idx is not None: + list_of_str.append(f"tensor_idx={self.tensor_idx}") + if self.name is not None: + list_of_str.append(f"name={self.name}") + if self.dtype is not None: + list_of_str.append(f"dtype={self.dtype}") + if self.shape is not None: + list_of_str.append(f"shape={self.shape}") + if self.shape_dims is not None: + list_of_str.append(f"shape_dims={self.shape_dims}") + + result += ",".join(list_of_str) + ")" + return result + + def __str__(self) -> str: + return self.__repr__() + + def __eq__(self, other): + if not other: + return False + elif not isinstance(other, _TensorStub): + raise NotImplementedError("_TensorStub must only be compared to another _TensorStub instance!") + elif self.tensor_idx != other.tensor_idx: + return False + elif self.name != other.name: + return False + elif self.dtype != other.dtype: + return False + elif self.shape != other.shape: + return False + elif self.shape_dims != other.shape_dims: + return False + return True + + +# Data schema used to represent model's input or output. +ORTModelInputOutputSchemaType = Union[ + None, + str, + _TensorStub, + Sequence["ORTModelInputOutputSchemaType"], + Mapping[str, "ORTModelInputOutputSchemaType"], +] + + +def _warn_of_constant_inputs(data): + warnings.warn( + f"Received input of type {type(data)} which may be treated as a constant by ORT by default." + " Please consider moving constant arguments to the model constructor." + ) + + +def extract_data_and_schema( + data: ORTModelInputOutputType, constant_as_tensor=False, device: Optional[torch.device] = None +) -> Tuple[List[torch.Tensor], ORTModelInputOutputSchemaType]: + """Extract the data schema by replacing every torch.Tensor value with _TensorStub, and return all tensors in + a list. + + Depth first traversal to iterate over the data: + > Replace every tensor with a stub + > Replace None/str typed data with itself + > For other primitive types: + If constant_as_tensor is True, create tensor from data , and replace them with a stub in returned schema; + Otherwise, replace them with themselves in returned schema. + + Examples: + Example 1, list: + data = [torch.tensor(1), torch.tensor(2)] + schema = [_TensorStub(shape=()), _TensorStub(shape=())] + + Example 2, dict: + data = {"a": torch.tensor(1), "b": torch.tensor(2)} + schema = {"a": _TensorStub(shape=()), "b": _TensorStub(shape=())} + + Example 3, dict of list: + data = {"a": [torch.tensor(1), torch.tensor(2)], "b": [torch.tensor(3), torch.tensor(4)]} + schema = {"a": [_TensorStub(shape=()), _TensorStub(shape=())], + "b": [_TensorStub(shape=()), _TensorStub(shape=())]} + + Example 4, nested dict: + data = {"a": {"b": torch.tensor(1), "c": torch.tensor(2)}, + "d": {"e": torch.tensor(3), "f": torch.tensor(4)}} + schema = {"a": {"b": _TensorStub(shape=()), "c": _TensorStub(shape=())}, + "d": {"e": _TensorStub(shape=()), "f": _TensorStub(shape=())}} + + Example 5, dict of mixed list and dict: + data = {"a": [torch.tensor(1), torch.tensor(2)], "b": {"c": torch.tensor(3), "d": torch.tensor(4)}} + schema = {"a": [_TensorStub(shape=()), _TensorStub(shape=())], + "b": {"c": _TensorStub(shape=()), "d": _TensorStub(shape=())}} + + Args: + data: The data to extract the schema from, which can be in any kind of nested structure, + including Sequence and Mapping. + constant_as_tensor: Whether to treat constant inputs as tensor. Default is False. + device: The device to create tensor for the constant. + + + Returns: + Tuple: + The first value: a list of tensors extracted from the data. + The second value: schema of the data, which has the same structure as the data. + + + """ + + flatten_tensor_data = [] + tensor_idx = [-1] + + def _flatten_from_data(data: ORTModelInputOutputType, prefix_name: str = ""): + if data is None: + return data + elif isinstance(data, str): + _warn_of_constant_inputs(data) + return data + elif PrimitiveType.is_primitive_type(data): + _warn_of_constant_inputs(data) + if constant_as_tensor: + tensor_idx[0] += 1 + flatten_tensor_data.append(PrimitiveType.get_tensor(data, device)) + return _TensorStub( + tensor_idx[0], dtype=PrimitiveType.get_primitive_dtype(data), shape_dims=0, name=prefix_name + ) + return data + # Depth first traversal to iterate over the data to replace every tensor with a stub + elif isinstance(data, torch.Tensor): + tensor_idx[0] += 1 + flatten_tensor_data.append(data) + return _TensorStub( + tensor_idx[0], + dtype=str(data.dtype), + shape_dims=len(data.size()), + name=prefix_name, + ) + elif isinstance(data, abc.Sequence): + sequence_type = type(data) + stubbed_schema = [] + for i, val in enumerate(data): + stubbed_schema.append(_flatten_from_data(val, f"{prefix_name}_{i}" if prefix_name else f"{i}")) + + try: + # namedtuple can be created by passing the list sequence to method _make + stubbed_schema = sequence_type._make(stubbed_schema) + except AttributeError: + # If attribute error is encountered, create the sequence directly + stubbed_schema = sequence_type(stubbed_schema) + return stubbed_schema + elif isinstance(data, abc.Mapping): + dict_type = type(data) + stubbed_schema = {} + for key, val in sorted(data.items()): + stubbed_schema[key] = _flatten_from_data(val, f"{prefix_name}_{key}" if prefix_name else f"{key}") + stubbed_schema = dict_type(**stubbed_schema) + return stubbed_schema + else: + raise TypeError(f"Unsupported flatten data type: {type(data)}") + + schemas = _flatten_from_data(data) + return flatten_tensor_data, schemas + + +def unflatten_data_using_schema( + data: List[torch.Tensor], schema: ORTModelInputOutputSchemaType +) -> ORTModelInputOutputType: + """Follows the schema to generate an output that is expected by the user. + + Depth first traversal to iterate over the schema: + > Replace every _TensorStub with a tensor from data. For each _TensorStub, the tensor is selected from `data` + by its tensor_idx. + + Examples: + Example 1, schema is a list: + data = [torch.tensor(1), torch.tensor(2)] + schema = [_TensorStub(shape=()), True, _TensorStub(shape=()), 1, 2.0, "abc"] + output = [torch.tensor(1), True, torch.tensor(2), 1, 2.0, "abc"] + + Example 2, schema is a dict: + data = [torch.tensor(1), torch.tensor(2)] + schema = {"a": _TensorStub(shape=()), "b": _TensorStub(shape=()), "c": True, "d": 1, "e": 2.0, "f": "abc"} + output = {"a": torch.tensor(1), "b": torch.tensor(2), "c": True, "d": 1, "e": 2.0, "f": "abc"} + + Example 3, schema is a dict of list: + data = [torch.tensor(1), torch.tensor(2), torch.tensor(3), torch.tensor(4)] + schema = {"a": [_TensorStub(shape=()), _TensorStub(shape=())], "b": [_TensorStub(shape=()), _TensorStub(shape=())]} + output = {"a": [torch.tensor(1), torch.tensor(2)], "b": [torch.tensor(3), torch.tensor(4)]} + + Example 4, schema is a nested dict: + data = [torch.tensor(1), torch.tensor(2), torch.tensor(3), torch.tensor(4)] + schema = {"a": {"b": _TensorStub(shape=()), "c": _TensorStub(shape=())}, + "d": {"e": _TensorStub(shape=()), "f": _TensorStub(shape=())}} + output = {"a": {"b": torch.tensor(1), "c": torch.tensor(2)}, "d": {"e": torch.tensor(3), "f": torch.tensor(4)}} + + Example 5, dict of mixed list and dict: + data = [torch.tensor(1), torch.tensor(2), torch.tensor(3), torch.tensor(4)] + schema = {"a": [_TensorStub(shape=()), _TensorStub(shape=())], "b": {"c": _TensorStub(shape=()), "d": _TensorStub(shape=())}} + output = {"a": [torch.tensor(1), torch.tensor(2)], "b": {"c": torch.tensor(3), "d": torch.tensor(4)}} + + + Args: + data (List[torch.Tensor]): List of tensors to be used to replace the _TensorStub in schema + schema (ORTModelInputOutputSchemaType): Schema to follow to generate the output + + Returns: + output (ORTModelInputOutputType): Output that is expected by the user + + """ + + def _replace_stub_with_tensor_value(data_schema: ORTModelInputOutputSchemaType, data: List[torch.Tensor]): + # Recursively traverse across user_output and replace all _TensorStub + # with torch.Tensor values from outputs following output_idx + + if data_schema is None: + return None + elif isinstance(data_schema, str): + return data_schema + elif PrimitiveType.is_primitive_type(data_schema): + return data_schema + elif isinstance(data_schema, _TensorStub): + assert isinstance( + data[data_schema.tensor_idx], torch.Tensor + ), f"Expecting torch.Tensor, got {type(data[data_schema.tensor_idx])}" + return data[data_schema.tensor_idx] + elif isinstance(data_schema, abc.Sequence): + sequence_type = type(data_schema) + if hasattr(sequence_type, "_make"): # namedtuple + sequence_type = type(data_schema) + data_schema = sequence_type._make(_replace_stub_with_tensor_value(uo, data) for uo in data_schema) + else: + data_schema = sequence_type(_replace_stub_with_tensor_value(uo, data) for uo in data_schema) + return data_schema + elif isinstance(data_schema, abc.Mapping): + new_user_output = copy.copy(data_schema) + for key, schema_val in sorted(data_schema.items()): + new_user_output[key] = _replace_stub_with_tensor_value(schema_val, data) + data_schema = new_user_output + + return data_schema + + raise TypeError(f"Unsupported unflatten data type: {type(data_schema)}.") + + user_output = _replace_stub_with_tensor_value(schema, data) + return user_output diff --git a/orttraining/orttraining/python/training/utils/torch_type_map.py b/orttraining/orttraining/python/training/utils/torch_type_map.py new file mode 100644 index 0000000000000..bdacab8ad04fe --- /dev/null +++ b/orttraining/orttraining/python/training/utils/torch_type_map.py @@ -0,0 +1,56 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# -------------------------------------------------------------------------- + + +from typing import Union + +import torch + +# Mapping from pytorch scalar type to onnx scalar type. +_CAST_PYTORCH_TO_ONNX = { + "Byte": [torch.onnx.TensorProtoDataType.UINT8, torch.uint8], + "Char": [torch.onnx.TensorProtoDataType.INT8, torch.int8], + "Double": [torch.onnx.TensorProtoDataType.DOUBLE, torch.double], + "Float": [torch.onnx.TensorProtoDataType.FLOAT, torch.float], + "Half": [torch.onnx.TensorProtoDataType.FLOAT16, torch.half], + "Int": [torch.onnx.TensorProtoDataType.INT32, torch.int], + "Long": [torch.onnx.TensorProtoDataType.INT64, torch.int64], + "Short": [torch.onnx.TensorProtoDataType.INT16, torch.short], + "Bool": [torch.onnx.TensorProtoDataType.BOOL, torch.bool], + "ComplexFloat": [torch.onnx.TensorProtoDataType.COMPLEX64, torch.complex64], + "ComplexDouble": [torch.onnx.TensorProtoDataType.COMPLEX128, torch.complex128], + "BFloat16": [torch.onnx.TensorProtoDataType.BFLOAT16, torch.bfloat16], + # Not yet defined in torch. + # "Float8E4M3FN": torch.onnx.TensorProtoDataType.FLOAT8E4M3FN, + # "Float8E4M3FNUZ": torch.onnx.TensorProtoDataType.FLOAT8E4M3FNUZ, + # "Float8E5M2": torch.onnx.TensorProtoDataType.FLOAT8E5M2, + # "Float8E5M2FNUZ": torch.onnx.TensorProtoDataType.FLOAT8E5M2FNUZ, + "Undefined": [torch.onnx.TensorProtoDataType.UNDEFINED, None], +} + + +_DTYPE_TO_ONNX = {torch_dtype: onnx_dtype for k, (onnx_dtype, torch_dtype) in _CAST_PYTORCH_TO_ONNX.items()} + +_ONNX_TO_DTYPE = {onnx_dtype: torch_dtype for torch_dtype, onnx_dtype in _DTYPE_TO_ONNX.items()} + + +def pytorch_dtype_to_onnx(dtype_or_scalar_type: Union[torch.dtype, str]) -> torch.onnx.TensorProtoDataType: + """Converts a pytorch dtype or scalar type string to an onnx dtype.""" + dtype = dtype_or_scalar_type + if isinstance(dtype, str): + if dtype not in _CAST_PYTORCH_TO_ONNX: + raise RuntimeError(f"Unsupported dtype {dtype}") + return _CAST_PYTORCH_TO_ONNX[dtype][0] + + if dtype not in _DTYPE_TO_ONNX: + raise RuntimeError(f"Unsupported dtype {dtype}") + return _DTYPE_TO_ONNX[dtype] + + +def onnx_dtype_to_pytorch(dtype: torch.onnx.TensorProtoDataType) -> torch.dtype: + """Converts an onnx dtype to a pytorch dtype.""" + if dtype not in _ONNX_TO_DTYPE: + raise RuntimeError(f"Unsupported dtype {dtype}") + return _ONNX_TO_DTYPE[dtype] diff --git a/orttraining/orttraining/test/distributed/partition_utils.hpp b/orttraining/orttraining/test/distributed/partition_utils.h similarity index 100% rename from orttraining/orttraining/test/distributed/partition_utils.hpp rename to orttraining/orttraining/test/distributed/partition_utils.h diff --git a/orttraining/orttraining/test/distributed/pipeline_partition_test.cc b/orttraining/orttraining/test/distributed/pipeline_partition_test.cc index 3aec1a8c6ef0b..e80b4529937e5 100644 --- a/orttraining/orttraining/test/distributed/pipeline_partition_test.cc +++ b/orttraining/orttraining/test/distributed/pipeline_partition_test.cc @@ -9,7 +9,7 @@ #include "gtest/gtest.h" -#include "partition_utils.hpp" +#include "partition_utils.h" namespace onnxruntime { namespace test { @@ -223,4 +223,4 @@ TEST(ComparePartitions, BertToy) { } } // namespace test -} // namespace onnxruntime \ No newline at end of file +} // namespace onnxruntime diff --git a/orttraining/orttraining/test/framework/checkpointing_test.cc b/orttraining/orttraining/test/framework/checkpointing_test.cc index e087ba9c0a2ac..b91cc2f1d5f5f 100644 --- a/orttraining/orttraining/test/framework/checkpointing_test.cc +++ b/orttraining/orttraining/test/framework/checkpointing_test.cc @@ -106,10 +106,10 @@ TEST(CheckpointingTest, SaveAndLoad) { TemporaryDirectory tmp_dir{ORT_TSTR("checkpointing_test_dir")}; PathString checkpoint_path{ - ConcatPathComponent(tmp_dir.Path(), ORT_TSTR("test_checkpoint"))}; + ConcatPathComponent(tmp_dir.Path(), ORT_TSTR("test_checkpoint"))}; // this path doesn't need to exist, we just consider its parent directory PathString model_path{ - ConcatPathComponent(tmp_dir.Path(), ORT_TSTR("test_model.onnx"))}; + ConcatPathComponent(tmp_dir.Path(), ORT_TSTR("test_model.onnx"))}; DataTransferManager data_transfer{}; ASSERT_STATUS_OK(data_transfer.RegisterDataTransfer(std::make_unique())); diff --git a/orttraining/orttraining/test/framework/slice_concatenate_test.cc b/orttraining/orttraining/test/framework/slice_concatenate_test.cc index 3bcabd2da567c..1eda3a7be793e 100644 --- a/orttraining/orttraining/test/framework/slice_concatenate_test.cc +++ b/orttraining/orttraining/test/framework/slice_concatenate_test.cc @@ -23,10 +23,10 @@ typedef std::vector ArgMap; // Create ML value. OrtValue CreateTensorValue(const std::vector& shape, const std::vector& initializer, const bool allocate_on_gpu) { #ifdef USE_CUDA - auto cpu_allocator = allocate_on_gpu ? DefaultCudaExecutionProvider()->GetAllocator(OrtMemTypeDefault) : TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault); + auto cpu_allocator = allocate_on_gpu ? DefaultCudaExecutionProvider()->CreatePreferredAllocators()[0] : TestCPUExecutionProvider()->CreatePreferredAllocators()[0]; #else ORT_ENFORCE(allocate_on_gpu != true); - auto cpu_allocator = TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault); + auto cpu_allocator = TestCPUExecutionProvider()->CreatePreferredAllocators()[0]; #endif auto element_type = onnxruntime::DataTypeImpl::GetType(); diff --git a/orttraining/orttraining/test/gradient/allreduce_op_test.cc b/orttraining/orttraining/test/gradient/allreduce_op_test.cc index 0a9e96c18fcd7..82f01a3c43681 100644 --- a/orttraining/orttraining/test/gradient/allreduce_op_test.cc +++ b/orttraining/orttraining/test/gradient/allreduce_op_test.cc @@ -497,27 +497,27 @@ TEST(AllreduceTest, GPUHierarchicalAdasumAllreduceOptimizerTest) { NameMLValMap feeds; // Learning rate inputs OrtValue ml_value_eta; - CreateMLValue(testCPUExecutionProvider->GetAllocator(OrtMemTypeDefault), {1}, {eta}, &ml_value_eta); + CreateMLValue(testCPUExecutionProvider->CreatePreferredAllocators()[0], {1}, {eta}, &ml_value_eta); feeds.insert(std::make_pair(lr_string, ml_value_eta)); // Grad scale inputs OrtValue ml_value_scale; - CreateMLValue(testCPUExecutionProvider->GetAllocator(OrtMemTypeDefault), {1}, {scale}, &ml_value_scale); + CreateMLValue(testCPUExecutionProvider->CreatePreferredAllocators()[0], {1}, {scale}, &ml_value_scale); feeds.insert(std::make_pair(grad_divisor_string, ml_value_scale)); // Update count inputs OrtValue ml_value_uc; - CreateMLValue(testCPUExecutionProvider->GetAllocator(OrtMemTypeDefault), {1}, {update_count}, &ml_value_uc); + CreateMLValue(testCPUExecutionProvider->CreatePreferredAllocators()[0], {1}, {update_count}, &ml_value_uc); feeds.insert(std::make_pair(update_count_string, ml_value_uc)); // Gradient inputs OrtValue ml_value_input_t; - CreateMLValue(testCPUExecutionProvider->GetAllocator(OrtMemTypeDefault), dims_allreduce_input, values_allreduce_input, &ml_value_input_t); + CreateMLValue(testCPUExecutionProvider->CreatePreferredAllocators()[0], dims_allreduce_input, values_allreduce_input, &ml_value_input_t); feeds.insert(std::make_pair(input_gradient_string, ml_value_input_t)); // Weight inputs OrtValue ml_value_weight_inputs; - CreateMLValue(testCPUExecutionProvider->GetAllocator(OrtMemTypeDefault), + CreateMLValue(testCPUExecutionProvider->CreatePreferredAllocators()[0], dims_allreduce_input, values_weight_input, &ml_value_weight_inputs); @@ -525,7 +525,7 @@ TEST(AllreduceTest, GPUHierarchicalAdasumAllreduceOptimizerTest) { // M1 inputs OrtValue ml_value_m1_inputs; - CreateMLValue(testCPUExecutionProvider->GetAllocator(OrtMemTypeDefault), + CreateMLValue(testCPUExecutionProvider->CreatePreferredAllocators()[0], dims_allreduce_input, values_m1_input, &ml_value_m1_inputs); @@ -533,7 +533,7 @@ TEST(AllreduceTest, GPUHierarchicalAdasumAllreduceOptimizerTest) { // M2 inputs OrtValue ml_value_m2_inputs; - CreateMLValue(testCPUExecutionProvider->GetAllocator(OrtMemTypeDefault), + CreateMLValue(testCPUExecutionProvider->CreatePreferredAllocators()[0], dims_allreduce_input, values_m2_input, &ml_value_m2_inputs); @@ -674,22 +674,22 @@ TEST(AllreduceTest, GPUHierarchicalAdasumAllreduceOptimizerFP16Test) { NameMLValMap feeds; // Learning rate inputs OrtValue ml_value_eta; - CreateMLValue(testCPUExecutionProvider->GetAllocator(OrtMemTypeDefault), {1}, {eta}, &ml_value_eta); + CreateMLValue(testCPUExecutionProvider->CreatePreferredAllocators()[0], {1}, {eta}, &ml_value_eta); feeds.insert(std::make_pair(lr_string, ml_value_eta)); // Grad scale inputs OrtValue ml_value_scale; - CreateMLValue(testCPUExecutionProvider->GetAllocator(OrtMemTypeDefault), {1}, {scale}, &ml_value_scale); + CreateMLValue(testCPUExecutionProvider->CreatePreferredAllocators()[0], {1}, {scale}, &ml_value_scale); feeds.insert(std::make_pair(grad_divisor_string, ml_value_scale)); // Update count inputs OrtValue ml_value_uc; - CreateMLValue(testCPUExecutionProvider->GetAllocator(OrtMemTypeDefault), {1}, {update_count}, &ml_value_uc); + CreateMLValue(testCPUExecutionProvider->CreatePreferredAllocators()[0], {1}, {update_count}, &ml_value_uc); feeds.insert(std::make_pair(update_count_string, ml_value_uc)); // Gradient inputs OrtValue ml_value_input_t; - CreateMLValue(testCPUExecutionProvider->GetAllocator(OrtMemTypeDefault), + CreateMLValue(testCPUExecutionProvider->CreatePreferredAllocators()[0], dims_allreduce_input, values_allreduce_input_half, &ml_value_input_t); @@ -697,7 +697,7 @@ TEST(AllreduceTest, GPUHierarchicalAdasumAllreduceOptimizerFP16Test) { // Weight inputs OrtValue ml_value_weight_inputs; - CreateMLValue(testCPUExecutionProvider->GetAllocator(OrtMemTypeDefault), + CreateMLValue(testCPUExecutionProvider->CreatePreferredAllocators()[0], dims_allreduce_input, values_weight_input, &ml_value_weight_inputs); @@ -705,7 +705,7 @@ TEST(AllreduceTest, GPUHierarchicalAdasumAllreduceOptimizerFP16Test) { // M1 inputs OrtValue ml_value_m1_inputs; - CreateMLValue(testCPUExecutionProvider->GetAllocator(OrtMemTypeDefault), + CreateMLValue(testCPUExecutionProvider->CreatePreferredAllocators()[0], dims_allreduce_input, values_m1_input, &ml_value_m1_inputs); @@ -713,7 +713,7 @@ TEST(AllreduceTest, GPUHierarchicalAdasumAllreduceOptimizerFP16Test) { // M2 inputs OrtValue ml_value_m2_inputs; - CreateMLValue(testCPUExecutionProvider->GetAllocator(OrtMemTypeDefault), + CreateMLValue(testCPUExecutionProvider->CreatePreferredAllocators()[0], dims_allreduce_input, values_m2_input, &ml_value_m2_inputs); @@ -813,7 +813,7 @@ TEST(AllreduceTest, GPUHierarchicalAdasumAllreduceTest) { status = session_object.Initialize(); ASSERT_TRUE(status.IsOK()); OrtValue ml_value_input_t; - CreateMLValue(testCPUExecutionProvider->GetAllocator(OrtMemTypeDefault), dims_allreduce_input, values_allreduce_input, &ml_value_input_t); + CreateMLValue(testCPUExecutionProvider->CreatePreferredAllocators()[0], dims_allreduce_input, values_allreduce_input, &ml_value_input_t); NameMLValMap feeds; feeds.insert(std::make_pair(input_gradient_string, ml_value_input_t)); @@ -918,7 +918,7 @@ TEST(AllreduceTest, GPUHierarchicalAdasumFP16AllreduceTest) { status = session_object.Initialize(); ASSERT_TRUE(status.IsOK()); OrtValue ml_value_input_t; - CreateMLValue(testCPUExecutionProvider->GetAllocator(OrtMemTypeDefault), + CreateMLValue(testCPUExecutionProvider->CreatePreferredAllocators()[0], dims_allreduce_input, values_allreduce_input_half, &ml_value_input_t); NameMLValMap feeds; @@ -1025,7 +1025,7 @@ TEST(AllreduceTest, GPUAdasumAllreduceTest) { status = session_object.Initialize(); ASSERT_TRUE(status.IsOK()); OrtValue ml_value_input_t; - CreateMLValue(testCPUExecutionProvider->GetAllocator(OrtMemTypeDefault), + CreateMLValue(testCPUExecutionProvider->CreatePreferredAllocators()[0], dims_allreduce_input, values_allreduce_input, &ml_value_input_t); @@ -1132,7 +1132,7 @@ TEST(AllreduceTest, GPUAdasumFP16AllreduceTest) { status = session_object.Initialize(); ASSERT_TRUE(status.IsOK()); OrtValue ml_value_input_t; - CreateMLValue(testCPUExecutionProvider->GetAllocator(OrtMemTypeDefault), + CreateMLValue(testCPUExecutionProvider->CreatePreferredAllocators()[0], dims_allreduce_input, values_allreduce_input_half, &ml_value_input_t); NameMLValMap feeds; diff --git a/orttraining/orttraining/test/gradient/gradient_checker.cc b/orttraining/orttraining/test/gradient/gradient_checker.cc index 4adf31679da90..b30540ec68317 100644 --- a/orttraining/orttraining/test/gradient/gradient_checker.cc +++ b/orttraining/orttraining/test/gradient/gradient_checker.cc @@ -18,11 +18,12 @@ limitations under the License. #include "orttraining/test/gradient/gradient_checker.h" #include -#include "orttraining/test/gradient/gradient_op_test_utils.h" + #include "orttraining/core/framework/gradient_graph_builder.h" #include "orttraining/core/graph/gradient_config.h" -#include "test/util/include/test_random_seed.h" + #include "test/util/include/default_providers.h" +#include "test/util/include/test_random_seed.h" namespace onnxruntime { namespace test { @@ -104,25 +105,25 @@ inline void GradientChecker::InitJacobians(size_t row_count, si template inline std::vector GradientChecker::EvaluateFunctionAtInput( - OpTester& op_session, const std::vector& x_infos, const std::vector& y_infos, + GradientOpTester& op_tester, const std::vector& x_infos, const std::vector& y_infos, std::vector>* x_datas, std::vector>* y_datas, std::vector>* execution_providers) { - AddDatas(op_session, x_infos, y_infos, x_datas, y_datas); + AddDatas(op_tester, x_infos, y_infos, x_datas, y_datas); // If EPs is not set, the OpTester will run over all possible EPs and keep the outputs of last run as the // actual output data, which is time wasting. What we need is the forward graph outputs for numeric Jacobian, // using CPU EP only is enough. std::vector> eps = GetExecutionProviders(execution_providers, true); - op_session.Run(OpTester::ExpectResult::kExpectSuccess, "", {}, nullptr, &eps); - return op_session.GetFetches(); + op_tester.Run(&eps); + return op_tester.GetFetches(); } template -inline void GradientChecker::AddDatas(OpTester& op_session, const std::vector& x_infos, +inline void GradientChecker::AddDatas(GradientOpTester& op_tester, const std::vector& x_infos, const std::vector& y_infos, std::vector>* x_datas, std::vector>* y_datas) { - op_session.ClearData(); + op_tester.ClearData(); for (size_t data_index = 0; data_index < x_datas->size(); ++data_index) { std::string name = "input" + std::to_string(data_index); const std::vector& data = (*x_datas)[data_index]; @@ -130,23 +131,23 @@ inline void GradientChecker::AddDatas(OpTester& op_session, con if (x_infos[data_index].data_type == DataTypeImpl::GetTensorType()) { std::vector int64_data(data.size()); std::transform(data.begin(), data.end(), int64_data.begin(), [](X_T x) { return static_cast(x); }); - op_session.AddInput(name.c_str(), x_infos[data_index].shape.AsShapeVector(), int64_data, false, - &x_infos[data_index].dim_params); + op_tester.AddInput(name.c_str(), x_infos[data_index].shape.AsShapeVector(), int64_data, false, + &x_infos[data_index].dim_params); } else if (x_infos[data_index].data_type == DataTypeImpl::GetTensorType()) { std::vector int32_data(data.size()); std::transform(data.begin(), data.end(), int32_data.begin(), [](X_T x) { return static_cast(x); }); - op_session.AddInput(name.c_str(), x_infos[data_index].shape.AsShapeVector(), int32_data, false, - &x_infos[data_index].dim_params); + op_tester.AddInput(name.c_str(), x_infos[data_index].shape.AsShapeVector(), int32_data, false, + &x_infos[data_index].dim_params); } else if (x_infos[data_index].data_type == DataTypeImpl::GetTensorType()) { std::unique_ptr p_data(new bool[data.size()]); for (size_t i = 0; i < data.size(); ++i) { p_data[i] = static_cast(data[i]); } - op_session.AddInput(name.c_str(), x_infos[data_index].shape.AsShapeVector(), p_data.get(), data.size(), - false, &x_infos[data_index].dim_params); + op_tester.AddInput(name.c_str(), x_infos[data_index].shape.AsShapeVector(), p_data.get(), data.size(), + false, &x_infos[data_index].dim_params); } else { - op_session.AddInput(name.c_str(), x_infos[data_index].shape.AsShapeVector(), data, false, - &x_infos[data_index].dim_params); + op_tester.AddInput(name.c_str(), x_infos[data_index].shape.AsShapeVector(), data, false, + &x_infos[data_index].dim_params); } } @@ -157,9 +158,9 @@ inline void GradientChecker::AddDatas(OpTester& op_session, con if (y_infos[data_index].data_type == DataTypeImpl::GetTensorType()) { std::vector int64_data(data.size()); std::transform(data.begin(), data.end(), int64_data.begin(), [](Y_T x) { return static_cast(x); }); - op_session.AddOutput(name.c_str(), y_infos[data_index].shape.AsShapeVector(), int64_data); + op_tester.AddOutput(name.c_str(), y_infos[data_index].shape.AsShapeVector(), int64_data); } else { - op_session.AddOutput(name.c_str(), y_infos[data_index].shape.AsShapeVector(), data); + op_tester.AddOutput(name.c_str(), y_infos[data_index].shape.AsShapeVector(), data); } } } @@ -174,10 +175,10 @@ inline Status GradientChecker::ComputeTheoreticalJacobianTransp size_t y_num = y_infos.size(); size_t x_num = x_infos.size(); // build the graph once and reuse it later in the looping logic - GradientOpTester op_session(op_def.type.c_str(), x_infos, y_infos, op_def.opset_version, op_def.domain.c_str(), - false); - op_session.AddShapeToTensorData(add_shape); - ORT_RETURN_IF_ERROR(InitOpTesterWithGradGraph(op_session, x_infos, y_infos, x_datas, y_datas, attributes)); + GradientOpTester op_tester(op_def.type.c_str(), op_def.opset_version, op_def.domain.c_str(), + false, &x_infos, &y_infos); + op_tester.AddShapeToTensorData(add_shape); + ORT_RETURN_IF_ERROR(InitOpTesterWithGradGraph(op_tester, x_infos, y_infos, x_datas, y_datas, attributes)); // currently only supported scalar valued fns - and complex types are not supported for (size_t y_idx = 0; y_idx < y_num; y_idx++) { // for each dy input @@ -190,7 +191,7 @@ inline Status GradientChecker::ComputeTheoreticalJacobianTransp // Compute the theoretical Jacobians one row at a time by back propagating // '1.0' for each element of 'dy', while holding all other elements of 'dy' at zero. for (size_t c = 0; c < dy_size; ++c) { // for each value in the dy input vector - AddDatas(op_session, x_infos, y_infos, x_datas, y_datas); + AddDatas(op_tester, x_infos, y_infos, x_datas, y_datas); // While calculating theoretical jacobian transpose we calculate the gradient by // setting back propagating one element of dY at a time and setting everything else to zero @@ -202,9 +203,8 @@ inline Status GradientChecker::ComputeTheoreticalJacobianTransp // actual output data, which is time wasting. So if caller doesn't pass in the EPs, we will use the default // EPs according to the environment. std::vector> eps = GetExecutionProviders(execution_providers); - op_session.Run(static_cast(y_idx), static_cast(c), OpTester::ExpectResult::kExpectSuccess, "", {}, - nullptr, &eps); - auto gradients = op_session.GetFetches(); + op_tester.Run(static_cast(y_idx), static_cast(c), &eps); + auto gradients = op_tester.GetFetches(); for (size_t x_idx = 0, grad_idx = 0; x_idx < x_num; x_idx++) { if (!x_infos[x_idx].has_gradient) { @@ -227,62 +227,47 @@ inline Status GradientChecker::ComputeTheoreticalJacobianTransp template inline Status GradientChecker::InitOpTesterWithGraph( - OpTester& op_session, const std::vector& x_infos, const std::vector& y_infos, + GradientOpTester& op_tester, const std::vector& x_infos, const std::vector& y_infos, std::vector>* x_datas, std::vector>* y_datas, const std::vector& attributes, const std::unordered_map& extra_domain_to_version) { - AddDatas(op_session, x_infos, y_infos, x_datas, y_datas); + AddDatas(op_tester, x_infos, y_infos, x_datas, y_datas); // Currently only allows setting int attributes to zero. TODO: Expand this for (auto attr : attributes) { - op_session.AddAttributeProto(attr); + op_tester.AddAttributeProto(attr); } // build graph - auto p_model = op_session.BuildGraph(extra_domain_to_version); - auto& graph = p_model->MainGraph(); - - Status status = Status::OK(); - status = graph.Resolve(); - - if (!status.IsOK()) { - LOGS_DEFAULT(ERROR) << "Resolve failed with status: " << status.ErrorMessage(); - EXPECT_TRUE(status.IsOK()) << status.ErrorMessage(); - } - - if (!status.IsOK()) { - return status; - } - - // cache the graph for later use - std::shared_ptr model_shared_ptr(std::move(p_model)); - op_session.SetModelCache(model_shared_ptr); - - return Status::OK(); + return op_tester.BuildAndCacheModel(extra_domain_to_version); } template inline Status GradientChecker::InitOpTesterWithGradGraph( - OpTester& op_session, const std::vector& x_infos, const std::vector& y_infos, + GradientOpTester& op_tester, const std::vector& x_infos, const std::vector& y_infos, std::vector>* x_datas, std::vector>* y_datas, const std::vector& attributes) { std::unordered_map extra_domain_to_version{{kMSDomain, 1}, {kOnnxDomain, 9}}; ORT_RETURN_IF_ERROR( - InitOpTesterWithGraph(op_session, x_infos, y_infos, x_datas, y_datas, attributes, extra_domain_to_version)); + InitOpTesterWithGraph(op_tester, x_infos, y_infos, x_datas, y_datas, attributes, extra_domain_to_version)); + // build grad graph - auto p_model = op_session.GetModelCache(); - auto& graph = p_model->MainGraph(); + auto& model = op_tester.GetModel(); + auto& graph = model.MainGraph(); std::unordered_set weights_to_train; - for (size_t i = 0; i < op_session.GetInputData().size(); i++) { + const auto& input_data = op_tester.GetInputData(); + const auto& output_data = op_tester.GetOutputData(); + + for (size_t i = 0; i < input_data.size(); i++) { if (x_infos[i].has_gradient) { - weights_to_train.insert(op_session.GetInputData()[i].def_.Name()); + weights_to_train.insert(input_data[i].def.Name()); } } std::unordered_set dy_values; - for (size_t i = 0; i < op_session.GetOutputData().size(); i++) { + for (size_t i = 0; i < output_data.size(); i++) { if (y_infos[i].has_gradient) { - dy_values.insert(op_session.GetOutputData()[i].def_.Name()); + dy_values.insert(output_data[i].def.Name()); } } @@ -290,10 +275,7 @@ inline Status GradientChecker::InitOpTesterWithGradGraph( gradient_graph_config.set_gradients_as_graph_outputs = true; training::GradientGraphBuilder grad_graph_builder(&graph, dy_values, weights_to_train, "", gradient_graph_config, logging::LoggingManager::DefaultLogger()); - Status status = grad_graph_builder.Build(); - EXPECT_TRUE(status.IsOK()) << status.ErrorMessage(); - - return Status::OK(); + return grad_graph_builder.Build(); } template @@ -308,9 +290,9 @@ inline Status GradientChecker::ComputeNumericJacobianTranspose( X_T x_delta = static_cast(delta); // build the graph once and reuse it later in the looping logic - OpTester op_session(op_def.type.c_str(), op_def.opset_version, op_def.domain.c_str(), false); - op_session.AddShapeToTensorData(add_shape); - ORT_RETURN_IF_ERROR(InitOpTesterWithGraph(op_session, x_infos, y_infos, x_datas, y_datas, attributes)); + GradientOpTester op_tester(op_def.type.c_str(), op_def.opset_version, op_def.domain.c_str(), false); + op_tester.AddShapeToTensorData(add_shape); + ORT_RETURN_IF_ERROR(InitOpTesterWithGraph(op_tester, x_infos, y_infos, x_datas, y_datas, attributes)); for (size_t x_idx = 0; x_idx < x_num; ++x_idx) { if (!x_infos[x_idx].has_gradient) { @@ -328,13 +310,12 @@ inline Status GradientChecker::ComputeNumericJacobianTranspose( // Evaluate at positive delta. (*x_datas)[x_idx][r] = v + x_delta; - std::vector y_plus = - EvaluateFunctionAtInput(op_session, x_infos, y_infos, x_datas, y_datas, execution_providers); + std::vector y_plus = EvaluateFunctionAtInput(op_tester, x_infos, y_infos, x_datas, y_datas, execution_providers); // Evaluate at negative delta. (*x_datas)[x_idx][r] = v - x_delta; std::vector y_minus = - EvaluateFunctionAtInput(op_session, x_infos, y_infos, x_datas, y_datas, execution_providers); + EvaluateFunctionAtInput(op_tester, x_infos, y_infos, x_datas, y_datas, execution_providers); for (size_t y_idx = 0; y_idx < y_num; ++y_idx) { if (!y_infos[y_idx].has_gradient) { diff --git a/orttraining/orttraining/test/gradient/gradient_checker.h b/orttraining/orttraining/test/gradient/gradient_checker.h index e9dec055b1777..e2820da5682c6 100644 --- a/orttraining/orttraining/test/gradient/gradient_checker.h +++ b/orttraining/orttraining/test/gradient/gradient_checker.h @@ -18,32 +18,11 @@ limitations under the License. #pragma once #include "test/providers/provider_test_utils.h" #include "orttraining/core/session/training_session.h" +#include "orttraining/test/gradient/gradient_op_test_utils.h" namespace onnxruntime { namespace test { -struct TensorInfo { - TensorInfo(std::initializer_list shape_init, bool has_gradient = true, - std::function* transformer = nullptr, - MLDataType data_type = DataTypeImpl::GetTensorType(), - const std::vector& dim_params = std::vector{}) - : shape(gsl::make_span(shape_init.begin(), shape_init.end())), - has_gradient(has_gradient), - transformer(transformer), - data_type(data_type), - dim_params(dim_params) {} - - TensorInfo(const TensorShape& shape, bool has_gradient = true, std::function* transformer = nullptr, - MLDataType data_type = DataTypeImpl::GetTensorType()) - : shape(shape), has_gradient(has_gradient), transformer(transformer), data_type(data_type) {} - - TensorShape shape; - bool has_gradient; - std::function* transformer; - MLDataType data_type; - std::vector dim_params; -}; - // TODO: This class currently assumes the inputs share types and the outputs share a type. // However there are cases like MaxPool and Gather where this is not true. template @@ -91,43 +70,48 @@ class GradientChecker { private: void InitJacobians(size_t row_count, size_t col_count, std::vector>* jacobians); - void AddDatas(OpTester& op_session, const std::vector& x_infos, const std::vector& y_infos, + void AddDatas(GradientOpTester& op_tester, + const std::vector& x_infos, const std::vector& y_infos, std::vector>* x_datas, std::vector>* y_datas); - std::vector EvaluateFunctionAtInput(OpTester& op_tester, const std::vector& x_infos, + std::vector EvaluateFunctionAtInput(GradientOpTester& op_tester, + const std::vector& x_infos, const std::vector& y_infos, std::vector>* x_datas, std::vector>* y_datas, std::vector>* execution_providers); - Status InitOpTesterWithGraph(OpTester& op_tester, const std::vector& x_infos, - const std::vector& y_infos, std::vector>* x_datas, - std::vector>* y_datas, + Status InitOpTesterWithGraph(GradientOpTester& op_tester, + const std::vector& x_infos, const std::vector& y_infos, + std::vector>* x_datas, std::vector>* y_datas, const std::vector& attributes, const std::unordered_map& extra_domain_to_version = {}); - Status InitOpTesterWithGradGraph(OpTester& op_tester, const std::vector& x_infos, - const std::vector& y_infos, std::vector>* x_datas, - std::vector>* y_datas, + Status InitOpTesterWithGradGraph(GradientOpTester& op_tester, + const std::vector& x_infos, const std::vector& y_infos, + std::vector>* x_datas, std::vector>* y_datas, const std::vector& attributes); Status ComputeTheoreticalJacobianTranspose( - const training::OpDef& op_def, const std::vector& x_infos, const std::vector& y_infos, + const training::OpDef& op_def, + const std::vector& x_infos, const std::vector& y_infos, std::vector>* x_datas, std::vector>* y_datas, std::vector>* jacobian_ts, const std::vector& row_strides, const std::vector& col_strides, const std::vector& attributes, bool add_shape = true, std::vector>* execution_providers = nullptr); Status ComputeNumericJacobianTranspose( - const training::OpDef& op_def, const std::vector& x_infos, const std::vector& y_infos, - const JAC_T delta, std::vector>* x_datas, std::vector>* y_datas, + const training::OpDef& op_def, + const std::vector& x_infos, const std::vector& y_infos, const JAC_T delta, + std::vector>* x_datas, std::vector>* y_datas, std::vector>* jacobian_ts, const std::vector& row_strides, const std::vector& col_strides, const std::vector& attributes, bool add_shape = true, std::vector>* execution_providers = nullptr); - Status ComputeGradientErrorInternal(const training::OpDef& op_name, const std::vector& x_infos, - const std::vector& y_infos, std::vector>* x_datas, - std::vector>* y_datas, JAC_T* max_error, + Status ComputeGradientErrorInternal(const training::OpDef& op_name, + const std::vector& x_infos, const std::vector& y_infos, + std::vector>* x_datas, std::vector>* y_datas, + JAC_T* max_error, const std::vector& attributes, bool check_not_have_gradient = true, bool check_not_have_shape_inferencing = false, diff --git a/orttraining/orttraining/test/gradient/gradient_op_test_utils.cc b/orttraining/orttraining/test/gradient/gradient_op_test_utils.cc index 5738ff831fc8c..b9f7e3fe465b8 100644 --- a/orttraining/orttraining/test/gradient/gradient_op_test_utils.cc +++ b/orttraining/orttraining/test/gradient/gradient_op_test_utils.cc @@ -1,87 +1,33 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "gradient_op_test_utils.h" +#include "orttraining/test/gradient/gradient_op_test_utils.h" + +#include "gmock/gmock.h" + #include "core/framework/kernel_type_str_resolver.h" #include "core/session/inference_session.h" + #include "orttraining/core/session/training_session.h" #include "orttraining/core/framework/gradient_graph_builder.h" #include "orttraining/core/graph/gradient_config.h" -#include "default_providers.h" + +#include "test/util/include/default_providers.h" namespace onnxruntime { namespace test { -// TODO: Refactor this so that we dont build gradient graph in every run -void GradientOpTester::Run( - int output_index_to_use_as_loss, - int data_index_of_output, - ExpectResult expect_result, - const std::string& expected_failure_string, - const std::unordered_set& /*excluded_provider_types*/, - const RunOptions* run_options, - std::vector>* execution_providers) { - try { -#ifndef NDEBUG - run_called_ = true; -#endif - fetches_.clear(); +void GradientOpTester::Run(int output_index_to_use_as_loss, + int data_index_of_output, + std::vector>* execution_providers) { + SetTestFunctionCalled(); + try { std::unordered_map extra_domain_to_version{{kMSDomain, 1}, {kOnnxDomain, 9}}; - bool cacheEnabled = cached_model_ != nullptr; - auto p_model = !cacheEnabled ? BuildGraph(extra_domain_to_version) : cached_model_; - auto& graph = p_model->MainGraph(); - - Status status = Status::OK(); - if (!cacheEnabled) { - if (expect_result == ExpectResult::kExpectFailure) { - // capture possible exceptions from shape inference for invalid testcase - try { - status = graph.Resolve(); - } catch (const std::exception& ex) { - status = ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, ex.what()); - } - } else { - status = graph.Resolve(); - } - - if (!status.IsOK()) { - if (expect_result == ExpectResult::kExpectFailure) { - EXPECT_TRUE(!status.IsOK()); - EXPECT_THAT(status.ErrorMessage(), testing::HasSubstr(expected_failure_string)); - } else { - LOGS_DEFAULT(ERROR) << "Resolve failed with status: " << status.ErrorMessage(); - EXPECT_TRUE(status.IsOK()) << status.ErrorMessage(); - } - } - - // TODO: We will need finer control over both inputs and ouptuts - // Not all inputs/outputs reqiures/have a gradient, e.g.index in gather - std::unordered_set weights_to_train; - for (size_t i = 0; i < input_data_.size(); i++) { - if (input_infos_[i].has_gradient) { - weights_to_train.insert(input_data_[i].def_.Name()); - } - } - std::unordered_set dy_values; - for (size_t i = 0; i < output_data_.size(); i++) { - if (output_infos_[i].has_gradient) { - dy_values.insert(output_data_[i].def_.Name()); - } - } - - training::GradientGraphConfiguration gradient_graph_config; - gradient_graph_config.set_gradients_as_graph_outputs = true; - training::GradientGraphBuilder grad_graph_builder(&graph, - dy_values, - weights_to_train, - "", - gradient_graph_config, - logging::LoggingManager::DefaultLogger()); - status = grad_graph_builder.Build(); - EXPECT_TRUE(status.IsOK()) << status.ErrorMessage(); - } + ORT_ENFORCE(cached_model_, "BuildAndCacheModel must be called first"); + Model& model = *cached_model_; + Graph& graph = model.MainGraph(); // Hookup the inputs and outputs std::unordered_map feeds; @@ -98,19 +44,18 @@ void GradientOpTester::Run( new_input_args.emplace_back(input_arg); } } + if (new_input_args.size() != input_size) { graph.SetInputs(new_input_args); // By setting this, Graph::SetGraphInputsOutputs could infer the input as expected. graph.SetGraphResolveNeeded(); graph.SetGraphProtoSyncNeeded(); - status = graph.Resolve(); - EXPECT_TRUE(status.IsOK()) << status.ErrorMessage(); + ASSERT_STATUS_OK(graph.Resolve()); } // Run the model SessionOptions so; - so.session_logid = op_; - so.session_log_verbosity_level = 1; + so.session_logid = Op(); static const std::string all_provider_types[] = { kCpuExecutionProvider, @@ -119,6 +64,7 @@ void GradientOpTester::Run( kDnnlExecutionProvider, kTensorrtExecutionProvider, }; + bool has_run = false; if (execution_providers) { @@ -132,8 +78,7 @@ void GradientOpTester::Run( onnxruntime::training::TrainingSession session_object{so, GetEnvironment()}; - ASSERT_TRUE(!execution_providers->empty()) - << "Empty execution providers vector."; + ASSERT_TRUE(!execution_providers->empty()) << "Empty execution providers vector."; std::string provider_types; for (auto& entry : *execution_providers) { @@ -157,10 +102,8 @@ void GradientOpTester::Run( has_run = true; - fetches_ = ExecuteModel( - *p_model, session_object, expect_result, expected_failure_string, - run_options, feeds, output_names, provider_types); - + ExecuteModel( + model, session_object, ExpectResult::kExpectSuccess, "", nullptr, feeds, output_names, provider_types); } else { for (const std::string& provider_type : all_provider_types) { std::unique_ptr execution_provider; @@ -219,12 +162,12 @@ void GradientOpTester::Run( EXPECT_TRUE(session_object.RegisterExecutionProvider(std::move(execution_provider)).IsOK()); - fetches_ = ExecuteModel(*p_model, session_object, expect_result, expected_failure_string, run_options, - feeds, output_names, provider_type); + ExecuteModel( + model, session_object, ExpectResult::kExpectSuccess, "", nullptr, feeds, output_names, provider_type); } } - EXPECT_TRUE(has_run) << "No registered execution providers were able to run the model."; + EXPECT_TRUE(has_run) << "No registered execution providers were able to run the model."; } catch (const std::exception& ex) { std::cerr << ex.what(); // rethrow as some tests for error handling expect this @@ -236,33 +179,45 @@ void GradientOpTester::FillFeedsAndOutputNames(std::unordered_map& output_names, int output_index_to_use_as_loss, int data_index_of_output) { + // this method is for usage when these two properties are set + assert(input_infos_ && output_infos_); + + const auto& input_infos = *input_infos_; + const auto& output_infos = *output_infos_; + OpTester::FillFeedsAndOutputNames(feeds, output_names); output_names.clear(); // ignore output names + const auto& input_data = GetInputData(); + const auto& output_data = GetOutputData(); + // add gradients as output instead - for (size_t i = 0; i < input_data_.size(); ++i) { - if (!input_infos_[i].has_gradient) { + for (size_t i = 0; i < input_data.size(); ++i) { + if (!input_infos[i].has_gradient) { continue; } - output_names.push_back(input_data_[i].def_.Name() + "_grad"); + output_names.push_back(input_data[i].def.Name() + "_grad"); } // Append gradient names and values to feeds std::vector gradient_data; - for (size_t i = 0; i < output_data_.size(); i++) { - if (!output_infos_[i].has_gradient) { + for (size_t i = 0; i < output_data.size(); i++) { + if (!output_infos[i].has_gradient) { continue; } - auto shape = output_data_[i].data_.Get().Shape(); + + auto shape = output_data[i].data.Get().Shape(); std::vector values(shape.Size(), 0.0); if (output_index_to_use_as_loss == static_cast(i)) { values[data_index_of_output] = 1.0; // set only one value to one to construct jacobian matrix } - AddData(gradient_data, (output_data_[i].def_.Name() + "_grad").c_str(), shape.AsShapeVector(), values.data(), values.size(), true); + + AddData(gradient_data, (output_data[i].def.Name() + "_grad").c_str(), shape.AsShapeVector(), + values.data(), values.size(), true); } for (size_t i = 0; i < gradient_data.size(); ++i) { - feeds[gradient_data[i].def_.Name()] = gradient_data[i].data_; + feeds[gradient_data[i].def.Name()] = gradient_data[i].data; } } diff --git a/orttraining/orttraining/test/gradient/gradient_op_test_utils.h b/orttraining/orttraining/test/gradient/gradient_op_test_utils.h index 77ccf0c88a8bc..ae090d76fb3dd 100644 --- a/orttraining/orttraining/test/gradient/gradient_op_test_utils.h +++ b/orttraining/orttraining/test/gradient/gradient_op_test_utils.h @@ -2,43 +2,110 @@ // Licensed under the MIT License. #pragma once + +#include +#include + #include "test/providers/provider_test_utils.h" -#include "gradient_checker.h" namespace onnxruntime { namespace test { + +struct TensorInfo { + TensorInfo(std::initializer_list shape_init, + bool has_gradient = true, + std::function* transformer = nullptr, + MLDataType data_type = DataTypeImpl::GetTensorType(), + const std::vector& dim_params = std::vector{}) + : shape(gsl::make_span(shape_init.begin(), shape_init.end())), + has_gradient(has_gradient), + transformer(transformer), + data_type(data_type), + dim_params(dim_params) {} + + TensorInfo(const TensorShape& shape, bool has_gradient = true, std::function* transformer = nullptr, + MLDataType data_type = DataTypeImpl::GetTensorType()) + : shape(shape), has_gradient(has_gradient), transformer(transformer), data_type(data_type) {} + + TensorShape shape; + bool has_gradient; + std::function* transformer; + MLDataType data_type; + std::vector dim_params; +}; + using TestDataVector = std::tuple>, // Input data std::vector>, // output data std::vector>>; // attribute +// NOTE: We proxy OpTester methods instead of making them virtual as no other derived class needs to override them class GradientOpTester : public OpTester { public: explicit GradientOpTester(const char* op, - const std::vector& input_infos, - const std::vector& output_infos, int opset_version = 9, const char* domain = onnxruntime::kOnnxDomain, - bool verify_output = true) + bool verify_output = true, + const std::vector* input_infos = nullptr, + const std::vector* output_infos = nullptr) : OpTester(op, opset_version, domain, verify_output), - input_infos_(input_infos), - output_infos_(output_infos) {} + input_infos_{input_infos}, + output_infos_{output_infos} { + } + + // we save the resolved model on the first build and re-use in Run calls + Status BuildAndCacheModel(const std::unordered_map& extra_domain_to_version) { + auto& model = OpTester::BuildModel(extra_domain_to_version); + auto status = model.MainGraph().Resolve(); + if (status.IsOK()) { + cached_model_ = &model; + } + return status; + } + + Model& GetModel() { + ORT_ENFORCE(cached_model_, "Expected BuildAndCacheModel to have been called first"); + return *cached_model_; + } + + // Basic Run + void Run(std::vector>* execution_providers) { + BaseTester::Run(ExpectResult::kExpectSuccess, "expected_failure_string", {}, nullptr, execution_providers); + } + + // Run when input_infos_ and output_infos_ are set void Run(int output_index_to_use_as_loss, int data_index_of_output, - ExpectResult expect_result = ExpectResult::kExpectSuccess, - const std::string& expected_failure_string = "", - const std::unordered_set& excluded_provider_types = {}, - const RunOptions* run_options = nullptr, - std::vector>* execution_providers = nullptr); + std::vector>* execution_providers); + + const std::vector& GetInputData() { + return BaseTester::GetInputData(); + } + + const std::vector& GetOutputData() { + return BaseTester::GetOutputData(); + } + + void ClearData() { + BaseTester::GetInputData().clear(); + BaseTester::GetOutputData().clear(); + BaseTester::GetInitializerIndexes().clear(); + } private: + void CreateModelToTest(const ModelOptions& /*model_options*/, Model*& model) override { + // NOTE: The current setup doesn't allow ModelOptions to be set/used as we call BuildGraph directly. + model = &GetModel(); + } + void FillFeedsAndOutputNames(std::unordered_map& feeds, std::vector& output_names, int output_index_to_use_as_loss, int data_index_of_output); - std::vector input_infos_; - std::vector output_infos_; + const std::vector* input_infos_; + const std::vector* output_infos_; + Model* cached_model_{nullptr}; }; } // namespace test } // namespace onnxruntime diff --git a/orttraining/orttraining/test/gradient/gradient_ops_test.cc b/orttraining/orttraining/test/gradient/gradient_ops_test.cc index 79d1e045f037d..597801f4030c1 100644 --- a/orttraining/orttraining/test/gradient/gradient_ops_test.cc +++ b/orttraining/orttraining/test/gradient/gradient_ops_test.cc @@ -2999,6 +2999,307 @@ TEST(GradientCheckerTest, TriluGrad) { } } +// TODO (enable once found why it fails on ROCM) +#if defined(USE_CUDA) +TEST(GradientCheckerTest, PadAndUnflattenGrad) { + float max_error; + GradientChecker gradient_checker; + OpDef op_def{"PadAndUnflatten", kMSDomain, 1}; + TensorInfo shape_info({2}, false, nullptr, DataTypeImpl::GetTensorType()); + TensorInfo indices_info({4}, false, nullptr, DataTypeImpl::GetTensorType()); + TensorInfo x_info({4, 3}); + std::vector> x_datas = {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, {3, 5, 0, 1}, {5, 2}}; + + TensorInfo padded_out_info({5, 2, 3}, true); + TensorInfo out_shape_info({2}, false, nullptr, DataTypeImpl::GetTensorType()); + + std::vector> execution_providers; +#ifdef USE_CUDA + execution_providers.emplace_back(DefaultCudaExecutionProvider()); +#elif USE_ROCM + execution_providers.emplace_back(DefaultRocmExecutionProvider()); +#endif + + ASSERT_STATUS_OK(gradient_checker.ComputeGradientError(op_def, {x_info, indices_info, shape_info}, + {padded_out_info, out_shape_info}, &max_error, + x_datas, {}, true, false, &execution_providers)); + EXPECT_IS_TINY(max_error); +} + +TEST(GradientCheckerTest, ScaledSumGrad) { + // Two inputs. + { + float max_error; + GradientChecker gradient_checker; + OpDef op_def{"ScaledSum", kMSDomain, 1}; + TensorInfo x_info({4, 3}); + TensorInfo y_info({4, 3}); + std::vector> x_datas = { + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, + {0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f}, + }; + + TensorInfo output0_info({4, 3}, true); + std::vector attributes = {}; + attributes.push_back(MakeAttribute("scale_0", static_cast(0.5))); + attributes.push_back(MakeAttribute("scale_1", static_cast(0.3))); + std::vector> execution_providers; +#ifdef USE_CUDA + execution_providers.emplace_back(DefaultCudaExecutionProvider()); +#elif USE_ROCM + execution_providers.emplace_back(DefaultRocmExecutionProvider()); +#endif + + ASSERT_STATUS_OK(gradient_checker.ComputeGradientError(op_def, {x_info, y_info}, + {output0_info}, &max_error, + x_datas, attributes, true, false, &execution_providers)); + EXPECT_IS_TINY(max_error); + } + + // Three inputs. + { + float max_error; + GradientChecker gradient_checker; + OpDef op_def{"ScaledSum", kMSDomain, 1}; + TensorInfo x_info({4, 3}); + TensorInfo y_info({4, 3}); + TensorInfo z_info({4, 3}); + std::vector> x_datas = { + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, + {0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f}, + {0.01f, 0.02f, 0.03f, 0.04f, 0.05f, 0.06f, -0.07f, -0.08f, -0.09f, -0.10f, -0.11f, -0.12f}, + }; + + TensorInfo output0_info({4, 3}, true); + std::vector attributes = {}; + attributes.push_back(MakeAttribute("scale_0", static_cast(0.2))); + attributes.push_back(MakeAttribute("scale_1", static_cast(0.3))); + attributes.push_back(MakeAttribute("scale_2", static_cast(0.5))); + std::vector> execution_providers; +#ifdef USE_CUDA + execution_providers.emplace_back(DefaultCudaExecutionProvider()); +#elif USE_ROCM + execution_providers.emplace_back(DefaultRocmExecutionProvider()); +#endif + + ASSERT_STATUS_OK(gradient_checker.ComputeGradientError(op_def, {x_info, y_info, z_info}, + {output0_info}, &max_error, + x_datas, attributes, true, false, &execution_providers)); + EXPECT_IS_TINY(max_error); + } +} +#endif + +TEST(GradientCheckerTest, ReciprocalGrad) { + // Avoid division by 0 by using the transformer. + std::function transformer = [](float x) { return x > 0 ? x + 0.2f : x - 0.2f; }; + UnaryOpGradientTest("Reciprocal", kOnnxDomain, 12, nullptr, &transformer); +} + +TEST(GradientCheckerTest, LeakyReluGrad) { + // Gradient is non continuous at 0, so we need to avoid it. + std::function transformer = [](float x) { return x > 0 ? x + 0.2f : x - 0.2f; }; + UnaryOpGradientTest("LeakyRelu", kOnnxDomain, 16, nullptr, &transformer); +} + +#ifdef USE_CUDA +void ConvTransposeGradientCheckerTest(std::vector>* execution_providers) { + float max_error; + GradientChecker gradient_checker; + OpDef op_def{"ConvTranspose"}; + + float error_tolerance = 3e-1f; + + // 1D convolution + { + TensorShape x_shape({2, 2, 5}); + TensorShape w_shape({2, 2, 3}); + TensorShape b_shape({2}); + TensorShape y_shape({2, 2, 5}); + ASSERT_STATUS_OK(gradient_checker.ComputeGradientError( + op_def, {x_shape, w_shape, b_shape}, {y_shape}, &max_error, + {MakeAttribute("kernel_shape", std::vector{3}), MakeAttribute("pads", std::vector{1, 1})}, + false, false, execution_providers)); + EXPECT_IS_TINIER_THAN(max_error, error_tolerance); + } + + // 1D strided convolution + { + TensorShape x_shape({2, 1, 7}); + TensorShape w_shape({1, 1, 3}); + TensorShape b_shape({1}); + TensorShape y_shape({2, 1, 13}); + ASSERT_STATUS_OK(gradient_checker.ComputeGradientError( + op_def, {x_shape, w_shape, b_shape}, {y_shape}, &max_error, + {MakeAttribute("kernel_shape", std::vector{3}), MakeAttribute("pads", std::vector{1, 1}), + MakeAttribute("strides", std::vector{2})}, + false, false, execution_providers)); + EXPECT_IS_TINIER_THAN(max_error, error_tolerance); + } + + // 1D pointwise convolution (with padding) + { + TensorShape x_shape({2, 1, 5}); + TensorShape w_shape({1, 1, 1}); + TensorShape b_shape({1}); + TensorShape y_shape({2, 1, 3}); + ASSERT_STATUS_OK(gradient_checker.ComputeGradientError( + op_def, {x_shape, w_shape, b_shape}, {y_shape}, &max_error, + {MakeAttribute("kernel_shape", std::vector{1}), MakeAttribute("pads", std::vector{1, 1})}, + false, false, execution_providers)); + EXPECT_IS_TINIER_THAN(max_error, error_tolerance); + } + + // 1D pointwise convolution (no padding) + { + TensorShape x_shape({2, 1, 5}); + TensorShape w_shape({1, 1, 1}); + TensorShape b_shape({1}); + TensorShape y_shape({2, 1, 5}); + ASSERT_STATUS_OK(gradient_checker.ComputeGradientError( + op_def, {x_shape, w_shape, b_shape}, {y_shape}, &max_error, + {MakeAttribute("kernel_shape", std::vector{1}), MakeAttribute("pads", std::vector{0, 0})}, + false, false, execution_providers)); + EXPECT_IS_TINIER_THAN(max_error, error_tolerance); + } + + // 2D convolution + { + TensorShape x_shape({1, 1, 3, 3}); + TensorShape w_shape({1, 1, 3, 3}); + TensorShape b_shape({1}); + TensorShape y_shape({1, 1, 3, 3}); + ASSERT_STATUS_OK( + gradient_checker.ComputeGradientError(op_def, {x_shape, w_shape, b_shape}, {y_shape}, &max_error, + {MakeAttribute("kernel_shape", std::vector{3, 3}), + MakeAttribute("pads", std::vector{1, 1, 1, 1})}, + false, false, execution_providers)); + EXPECT_IS_TINIER_THAN(max_error, error_tolerance); + } + + // 2D convolution + { + TensorShape x_shape({2, 1, 5, 5}); + TensorShape w_shape({1, 1, 3, 3}); + TensorShape b_shape({1}); + TensorShape y_shape({2, 1, 5, 5}); + ASSERT_STATUS_OK( + gradient_checker.ComputeGradientError(op_def, {x_shape, w_shape, b_shape}, {y_shape}, &max_error, + {MakeAttribute("kernel_shape", std::vector{3, 3}), + MakeAttribute("pads", std::vector{1, 1, 1, 1})}, + false, false, execution_providers)); + EXPECT_IS_TINIER_THAN(max_error, error_tolerance); + } + + // 2D pointwise convolution (with padding) + { + TensorShape x_shape({1, 1, 3, 3}); + TensorShape w_shape({1, 1, 1, 1}); + TensorShape b_shape({1}); + TensorShape y_shape({1, 1, 1, 1}); + ASSERT_STATUS_OK( + gradient_checker.ComputeGradientError(op_def, {x_shape, w_shape, b_shape}, {y_shape}, &max_error, + {MakeAttribute("kernel_shape", std::vector{1, 1}), + MakeAttribute("pads", std::vector{1, 1, 1, 1})}, + false, false, execution_providers)); + EXPECT_IS_TINIER_THAN(max_error, error_tolerance); + } + + // 2D pointwise convolution (no padding) + { + TensorShape x_shape({1, 1, 3, 3}); + TensorShape w_shape({1, 1, 1, 1}); + TensorShape b_shape({1}); + TensorShape y_shape({1, 1, 3, 3}); + ASSERT_STATUS_OK( + gradient_checker.ComputeGradientError(op_def, {x_shape, w_shape, b_shape}, {y_shape}, &max_error, + {MakeAttribute("kernel_shape", std::vector{1, 1}), + MakeAttribute("pads", std::vector{0, 0, 0, 0})}, + false, false, execution_providers)); + EXPECT_IS_TINIER_THAN(max_error, error_tolerance); + } + + // 2D strided convolution + { + TensorShape x_shape({2, 1, 7, 5}); + TensorShape w_shape({1, 1, 3, 3}); + TensorShape b_shape({1}); + TensorShape y_shape({2, 1, 13, 9}); + ASSERT_STATUS_OK(gradient_checker.ComputeGradientError( + op_def, {x_shape, w_shape, b_shape}, {y_shape}, &max_error, + {MakeAttribute("kernel_shape", std::vector{3, 3}), + MakeAttribute("pads", std::vector{1, 1, 1, 1}), MakeAttribute("strides", std::vector{2, 2})}, + false, false, execution_providers)); + EXPECT_IS_TINIER_THAN(max_error, error_tolerance); + } + + // 2D dilated convolution (no padding) + { + TensorShape x_shape({2, 1, 5, 5}); + TensorShape w_shape({1, 1, 3, 3}); + TensorShape b_shape({1}); + TensorShape y_shape({2, 1, 9, 9}); + ASSERT_STATUS_OK( + gradient_checker.ComputeGradientError(op_def, {x_shape, w_shape, b_shape}, {y_shape}, &max_error, + {MakeAttribute("kernel_shape", std::vector{3, 3}), + MakeAttribute("pads", std::vector{0, 0, 0, 0}), + MakeAttribute("dilations", std::vector{2, 2})}, + false, false, execution_providers)); + EXPECT_IS_TINIER_THAN(max_error, error_tolerance); + } + + // 2D dilated convolution (with padding) + { + TensorShape x_shape({2, 1, 7, 5}); + TensorShape w_shape({1, 1, 3, 3}); + TensorShape b_shape({1}); + TensorShape y_shape({2, 1, 9, 7}); + ASSERT_STATUS_OK( + gradient_checker.ComputeGradientError(op_def, {x_shape, w_shape, b_shape}, {y_shape}, &max_error, + {MakeAttribute("kernel_shape", std::vector{3, 3}), + MakeAttribute("pads", std::vector{1, 1, 1, 1}), + MakeAttribute("dilations", std::vector{2, 2})}, + false, false, execution_providers)); + EXPECT_IS_TINIER_THAN(max_error, error_tolerance); + } + + // 3D convolution + { + TensorShape x_shape({2, 1, 5, 5, 5}); + TensorShape w_shape({1, 1, 3, 3, 3}); + TensorShape b_shape({1}); + TensorShape y_shape({2, 1, 5, 5, 5}); + ASSERT_STATUS_OK( + gradient_checker.ComputeGradientError(op_def, {x_shape, w_shape, b_shape}, {y_shape}, &max_error, + {MakeAttribute("kernel_shape", std::vector{3, 3, 3}), + MakeAttribute("pads", std::vector{1, 1, 1, 1, 1, 1})}, + false, false, execution_providers)); + EXPECT_IS_TINIER_THAN(max_error, error_tolerance); + } + + // 3D strided convolution + { + TensorShape x_shape({2, 1, 7, 5, 5}); + TensorShape w_shape({1, 1, 3, 3, 3}); + TensorShape b_shape({1}); + TensorShape y_shape({2, 1, 13, 9, 9}); + ASSERT_STATUS_OK( + gradient_checker.ComputeGradientError(op_def, {x_shape, w_shape, b_shape}, {y_shape}, &max_error, + {MakeAttribute("kernel_shape", std::vector{3, 3, 3}), + MakeAttribute("pads", std::vector{1, 1, 1, 1, 1, 1}), + MakeAttribute("strides", std::vector{2, 2, 2})}, + false, false, execution_providers)); + EXPECT_IS_TINIER_THAN(max_error, error_tolerance); + } +} + +TEST(GradientCheckerTest, ConvTransposeGrad) { + std::vector> execution_providers; + execution_providers.push_back(DefaultCudaExecutionProvider()); + ConvTransposeGradientCheckerTest(&execution_providers); +} +#endif // USE_CUDA + } // namespace test } // namespace onnxruntime diff --git a/orttraining/orttraining/test/graph/gradient_graph_builder_test.cc b/orttraining/orttraining/test/graph/gradient_graph_builder_test.cc index ceeedd23ad454..358deb421bc21 100644 --- a/orttraining/orttraining/test/graph/gradient_graph_builder_test.cc +++ b/orttraining/orttraining/test/graph/gradient_graph_builder_test.cc @@ -22,7 +22,6 @@ using namespace onnxruntime::logging; using namespace onnxruntime::training; -using namespace google::protobuf::util; using namespace onnxruntime::path_utils; using namespace onnxruntime::test::training_session_test_utils; diff --git a/orttraining/orttraining/test/graph/optimizer_graph_builder_test.cc b/orttraining/orttraining/test/graph/optimizer_graph_builder_test.cc index a7fe828a109b7..84a45398534e7 100644 --- a/orttraining/orttraining/test/graph/optimizer_graph_builder_test.cc +++ b/orttraining/orttraining/test/graph/optimizer_graph_builder_test.cc @@ -174,15 +174,15 @@ static void TestOptimizerGraphBuilderWithInitialStates(OptimizerGraphConfig conf OrtValue ml_value; for (const auto& key : MOMENTS_PREFIXES) { - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), dims, values, &ml_value); + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], dims, values, &ml_value); per_weight_states.insert(std::make_pair(key, std::move(ml_value))); } if (optimizer_op_name == k_adam_optimizer_op_name) { - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), dims, uc_value, &ml_value); + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], dims, uc_value, &ml_value); per_weight_states.insert(std::make_pair(ADAM_UC_PREFIX, std::move(ml_value))); } else if (optimizer_op_name == k_lamb_optimizer_op_name) { // add "Step" for lamb - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), dims, uc_value, &ml_value); + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], dims, uc_value, &ml_value); shared_states.insert(std::make_pair(LAMB_STEP_TENSOR_NAME, std::move(ml_value))); config.shared_optimizer_states = std::move(shared_states); } diff --git a/orttraining/orttraining/test/model/data_loader_test.cc b/orttraining/orttraining/test/model/data_loader_test.cc index 70a04cc2f0b0a..f00e418c9ef70 100644 --- a/orttraining/orttraining/test/model/data_loader_test.cc +++ b/orttraining/orttraining/test/model/data_loader_test.cc @@ -113,7 +113,7 @@ TEST(TrainingDataLoaderTest, DataLoader_OneSingleFile) { constexpr size_t max_num_files_preload = 3; const MapStringToString input_name_map = {{"a", "a"}, {"b", "b"}, {"c", "c"}}; TemporaryDirectory tmp_dir{ORT_TSTR("training_data_loader_test_dir")}; - const PathString& train_data_dir = ConcatPathComponent(tmp_dir.Path(), ORT_TSTR("single_file")); + const PathString& train_data_dir = ConcatPathComponent(tmp_dir.Path(), ORT_TSTR("single_file")); ASSERT_STATUS_OK(CreateInputDataFiles(train_data_dir, 1, {"a", "b", "c"})); DataLoader data_loader(input_name_map, train_data_dir, @@ -131,7 +131,7 @@ TEST(TrainingDataLoaderTest, DataLoader_OneSingleFileFailParsing) { constexpr size_t max_num_files_preload = 3; const MapStringToString input_name_map = {{"a_invalid", "a"}, {"b", "b"}, {"c", "c"}}; TemporaryDirectory tmp_dir{ORT_TSTR("training_data_loader_test_dir")}; - const PathString& train_data_dir = ConcatPathComponent(tmp_dir.Path(), ORT_TSTR("single_file")); + const PathString& train_data_dir = ConcatPathComponent(tmp_dir.Path(), ORT_TSTR("single_file")); ASSERT_STATUS_OK(CreateInputDataFiles(train_data_dir, 1, {"a", "b", "c"})); DataLoader data_loader(input_name_map, train_data_dir, @@ -147,7 +147,7 @@ void TestDataLoaderWithMultipleFiles( const size_t* const start_data_set_index = nullptr) { const MapStringToString input_name_map = {{"a", "a"}, {"b", "b"}, {"c", "c"}}; TemporaryDirectory tmp_dir{ORT_TSTR("training_data_loader_test_dir")}; - const PathString& train_data_dir = ConcatPathComponent(tmp_dir.Path(), ORT_TSTR("multiple_files")); + const PathString& train_data_dir = ConcatPathComponent(tmp_dir.Path(), ORT_TSTR("multiple_files")); ASSERT_STATUS_OK(CreateInputDataFiles( train_data_dir, num_input_files, {"a", "b", "c"})); diff --git a/orttraining/orttraining/test/model/training_runner_test.cc b/orttraining/orttraining/test/model/training_runner_test.cc index b8be4dfd20bd8..12ea285a5da6c 100644 --- a/orttraining/orttraining/test/model/training_runner_test.cc +++ b/orttraining/orttraining/test/model/training_runner_test.cc @@ -20,9 +20,9 @@ namespace training { namespace test { const PathString k_original_model_path = - ConcatPathComponent(ORT_TSTR("testdata"), ORT_TSTR("test_training_model.onnx")); + ConcatPathComponent(ORT_TSTR("testdata"), ORT_TSTR("test_training_model.onnx")); const PathString k_backward_model_path = - ConcatPathComponent(ORT_TSTR("testdata"), ORT_TSTR("temp_backward_model.onnx")); + ConcatPathComponent(ORT_TSTR("testdata"), ORT_TSTR("temp_backward_model.onnx")); const PathString k_output_directory = ORT_TSTR("training_runner_test_output"); diff --git a/orttraining/orttraining/test/optimizer/compute_optimizer_test.cc b/orttraining/orttraining/test/optimizer/compute_optimizer_test.cc index 825ab3b3c2819..cf510ea43c89f 100644 --- a/orttraining/orttraining/test/optimizer/compute_optimizer_test.cc +++ b/orttraining/orttraining/test/optimizer/compute_optimizer_test.cc @@ -36,8 +36,12 @@ namespace test { #define MODEL_FOLDER ORT_TSTR("testdata/transform/") +namespace { +const InlinedHashSet compatible_eps = {}; +} + /* -Test graph include multiple equivalent subgraphs as below. +Test graph includes multiple equivalent subgraphs as below. graph input [32, 256] (float) graph input [32] (int64_t) | | \_____________ _______/ graph input -1, scalar (int64_t) @@ -110,7 +114,7 @@ TEST(ComputeOptimizerTests, InsertGatherBeforeSceLoss_Allowed) { auto build_test_case = [is_sce_internal](ModelTestBuilder& builder) { auto* input1_arg = builder.MakeInput({{32, 256}}); - auto* input2_arg = builder.MakeInput({{32}}); + auto* input2_arg = builder.MakeInput({{32}}, "label"); auto* sce_out1 = builder.MakeOutput(); NodeArg* empty = builder.MakeEmptyInput(); auto* sce_out2 = builder.MakeIntermediate(); @@ -133,7 +137,8 @@ TEST(ComputeOptimizerTests, InsertGatherBeforeSceLoss_Allowed) { std::vector opsets{12, 13, 14, 15}; for (auto opset : opsets) { - std::unique_ptr transformer = std::make_unique(); + std::unique_ptr transformer = + std::make_unique(compatible_eps, std::vector{"label"}); ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, opset, *logger, std::move(transformer), TransformerLevel::Level1, 1, pre_graph_checker, post_graph_checker)); @@ -142,7 +147,78 @@ TEST(ComputeOptimizerTests, InsertGatherBeforeSceLoss_Allowed) { } /* -Test graph include multiple equivalent subgraphs as below. +Test graph includes multiple equivalent subgraphs as below. + graph input [32, 256] (float) graph input [32] (int64_t) + | | + \_____________ _______/ graph input -1, scalar (int64_t) + \ / _______/ + \ / / + SCE Node, reduction = 'mean', output_type=1 + | + | + graph output, loss, scalar (float) +*/ +TEST(ComputeOptimizerTests, InsertGatherBeforeSceLoss_NotAllowed_LabelNameNotMatch) { + const logging::Logger* logger = &logging::LoggingManager::DefaultLogger(); + + for (const bool is_sce_internal : {true, false}) { + auto pre_graph_checker = [is_sce_internal](Graph& graph) -> Status { + auto op_count_pre = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_count_pre.size() == 1U); + if (is_sce_internal) + TEST_RETURN_IF_NOT(op_count_pre["com.microsoft.SoftmaxCrossEntropyLossInternal"] == 1); + else + TEST_RETURN_IF_NOT(op_count_pre["SoftmaxCrossEntropyLoss"] == 1); + return Status::OK(); + }; + + auto post_graph_checker = [is_sce_internal](Graph& graph) { + auto op_count_post = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_count_post.size() == 1U); + if (is_sce_internal) + TEST_RETURN_IF_NOT(op_count_post["com.microsoft.SoftmaxCrossEntropyLossInternal"] == 1); + else + TEST_RETURN_IF_NOT(op_count_post["SoftmaxCrossEntropyLoss"] == 1); + return Status::OK(); + }; + + auto build_test_case = [is_sce_internal](ModelTestBuilder& builder) { + auto* input1_arg = builder.MakeInput({{32, 256}}); + auto* input2_arg = builder.MakeInput({{32}}, "label111"); + auto* sce_out1 = builder.MakeOutput(); + + NodeArg* empty = builder.MakeEmptyInput(); + auto* sce_out2 = builder.MakeIntermediate(); + + if (is_sce_internal) { + auto* ignore_index_arg = builder.MakeScalarInitializer(-100); + Node& sce = builder.AddNode("SoftmaxCrossEntropyLossInternal", + {input1_arg, input2_arg, empty, ignore_index_arg}, + {sce_out1, sce_out2}, kMSDomain); + sce.AddAttribute("reduction", "mean"); + sce.AddAttribute("output_type", static_cast(1)); + } else { + Node& sce = builder.AddNode("SoftmaxCrossEntropyLoss", + {input1_arg, input2_arg, empty}, + {sce_out1, sce_out2}); + sce.AddAttribute("reduction", "mean"); + sce.AddAttribute("ignore_index", static_cast(-100)); + } + }; + + std::vector opsets{12, 13, 14, 15}; + for (auto opset : opsets) { + std::unique_ptr transformer = + std::make_unique(compatible_eps, std::vector{"label"}); + ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, opset, *logger, std::move(transformer), + TransformerLevel::Level1, + 1, pre_graph_checker, post_graph_checker)); + } + } +} + +/* +Test graph includes multiple equivalent subgraphs as below. graph input [32, 256] (float) graph input [32] (int64_t) | | \_____________ _______/ graph input -1, scalar (int64_t) @@ -179,7 +255,7 @@ TEST(ComputeOptimizerTests, InsertGatherBeforeSceLoss_NotAllowed_ReduceNone) { auto build_test_case = [is_sce_internal](ModelTestBuilder& builder) { auto* input1_arg = builder.MakeInput({{32, 256}}); - auto* input2_arg = builder.MakeInput({{32}}); + auto* input2_arg = builder.MakeInput({{32}}, "label"); auto* sce_out1 = builder.MakeOutput(); NodeArg* empty = builder.MakeEmptyInput(); @@ -203,7 +279,8 @@ TEST(ComputeOptimizerTests, InsertGatherBeforeSceLoss_NotAllowed_ReduceNone) { std::vector opsets{12, 13, 14, 15}; for (auto opset : opsets) { - std::unique_ptr transformer = std::make_unique(); + std::unique_ptr transformer = + std::make_unique(compatible_eps, std::vector{"label"}); ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, opset, *logger, std::move(transformer), TransformerLevel::Level1, 1, pre_graph_checker, post_graph_checker)); @@ -249,7 +326,7 @@ TEST(ComputeOptimizerTests, InsertGatherBeforeSceLoss_NotAllowed_NoIgnoreIndex) auto build_test_case = [is_sce_internal](ModelTestBuilder& builder) { auto* input1_arg = builder.MakeInput({{32, 256}}); - auto* input2_arg = builder.MakeInput({{32}}); + auto* input2_arg = builder.MakeInput({{32}}, "label"); auto* sce_out1 = builder.MakeOutput(); auto* sce_out2 = builder.MakeIntermediate(); @@ -269,7 +346,8 @@ TEST(ComputeOptimizerTests, InsertGatherBeforeSceLoss_NotAllowed_NoIgnoreIndex) std::vector opsets{12, 13, 14, 15}; for (auto opset : opsets) { - std::unique_ptr transformer = std::make_unique(); + std::unique_ptr transformer = + std::make_unique(compatible_eps, std::vector{"label"}); ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, opset, *logger, std::move(transformer), TransformerLevel::Level1, 1, pre_graph_checker, post_graph_checker)); @@ -288,8 +366,9 @@ TEST(ComputeOptimizerTests, InsertGatherBeforeSceLoss_MlmBertE2E) { std::map op_to_count = CountOpsInGraph(graph); onnxruntime::GraphTransformerManager graph_transformation_mgr{3}; - ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::make_unique(), - TransformerLevel::Level1)); + ASSERT_STATUS_OK(graph_transformation_mgr.Register( + std::make_unique(compatible_eps, std::vector{"labels"}), + TransformerLevel::Level1)); ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level1, *logger)); { @@ -328,7 +407,7 @@ TEST(ComputeOptimizerTests, InsertGatherBeforeSceLoss_MlmBertE2E) { } onnxruntime::test::TemporaryDirectory tmp_dir{ORT_TSTR("compute_optimizer_test_tmp_dir")}; - PathString new_model_uri{ConcatPathComponent( + PathString new_model_uri{ConcatPathComponent( tmp_dir.Path(), ORT_TSTR("insert_gather_before_sceloss_bert_e2e_optimized.onnx"))}; ASSERT_STATUS_OK(Model::Save(*model, new_model_uri)); diff --git a/orttraining/orttraining/test/optimizer/graph_transform_test.cc b/orttraining/orttraining/test/optimizer/graph_transform_test.cc index 52b90ca4fa449..94ca87b2ac519 100644 --- a/orttraining/orttraining/test/optimizer/graph_transform_test.cc +++ b/orttraining/orttraining/test/optimizer/graph_transform_test.cc @@ -26,9 +26,14 @@ #include "orttraining/core/session/training_session.h" #include "orttraining/core/optimizer/loss_rewriter.h" #include "orttraining/core/optimizer/bias_softmax_dropout_fusion.h" -#include "orttraining/core/optimizer/sce_loss_grad_bias_fusion.h" #include "orttraining/core/optimizer/qdq_fusion.h" +#include "orttraining/core/optimizer/scaled_sum_fusion.h" +#include "orttraining/core/optimizer/sce_loss_grad_bias_fusion.h" #include "orttraining/core/optimizer/lstm_replacement.h" +#include "orttraining/core/optimizer/gru_replacement.h" +#ifdef ENABLE_TRITON +#include "orttraining/core/optimizer/triton_fusion.h" +#endif #include @@ -1020,7 +1025,7 @@ TEST_P(LSTMReplacementTestsParameterized, CheckLSTMReplacement) { std::map op_to_count1 = CountOpsInGraph(graph); ASSERT_TRUE(op_to_count1.count("LSTM") && op_to_count1["LSTM"] == 1); - ASSERT_FALSE(op_to_count1.count("LSTMTraining")); + ASSERT_FALSE(op_to_count1.count("com.microsoft.LSTMTraining")); auto rule_transformer_L1 = std::make_unique("LSTMReplacement"); ASSERT_STATUS_OK(rule_transformer_L1->Register(std::make_unique())); @@ -1047,6 +1052,88 @@ INSTANTIATE_TEST_SUITE_P( std::make_tuple(3, false, false, true), std::make_tuple(3, true, true, true))); +class GRUReplacementTestsParameterized : public GraphTransformationTests, + public ::testing::WithParamInterface> { +}; + +TEST_P(GRUReplacementTestsParameterized, CheckGRUReplacement) { + Model model("GRUReplacement", true, ModelMetaData(), PathString(), + IOnnxRuntimeOpSchemaRegistryList(), {{"", 14}, {"com.microsoft", 1}}, {}, *logger_); + auto& graph = model.MainGraph(); + + TypeProto tensor; + tensor.mutable_tensor_type()->set_elem_type(TensorProto_DataType_FLOAT); + onnxruntime::NodeArg X("X", &tensor); + onnxruntime::NodeArg W("W", &tensor); + onnxruntime::NodeArg R("R", &tensor); + onnxruntime::NodeArg B("B", &tensor); + onnxruntime::NodeArg SL("", nullptr); + onnxruntime::NodeArg H0("H0", &tensor); + + onnxruntime::NodeArg HAll("HAll", &tensor); + onnxruntime::NodeArg HAllDummy("", nullptr); + onnxruntime::NodeArg Ht("Ht", &tensor); + onnxruntime::NodeArg HtDummy("", nullptr); + + InlinedVector outputs; + const int num_outputs = std::get<0>(GetParam()); + outputs.reserve(num_outputs); + const bool output_hall = std::get<1>(GetParam()); + const bool output_final_h = std::get<2>(GetParam()); + + if (num_outputs > 0) { + if (output_hall) { + outputs.push_back(&HAll); + } else { + outputs.push_back(&HAllDummy); + } + } + + if (num_outputs > 1) { + if (output_final_h) { + outputs.push_back(&Ht); + } else { + outputs.push_back(&HtDummy); + } + } + + Node& gru_node = graph.AddNode( + "gru", "GRU", "GRU operator", + {&X, &W, &R, &B, &SL, &H0}, outputs, nullptr); + gru_node.AddAttribute("hidden_size", static_cast(128)); + + auto status = graph.Resolve(); + EXPECT_EQ(status, Status::OK()); + + std::map op_to_count1 = CountOpsInGraph(graph); + ASSERT_TRUE(op_to_count1.count("GRU") && op_to_count1["GRU"] == 1); + ASSERT_FALSE(op_to_count1.count("com.microsoft.GRUTraining")); + + auto rule_transformer_L1 = std::make_unique("GRUReplacement"); + ASSERT_STATUS_OK(rule_transformer_L1->Register(std::make_unique())); + onnxruntime::GraphTransformerManager graph_transformation_mgr{5}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::move(rule_transformer_L1), TransformerLevel::Level1)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level1, *logger_)); + + std::map op_to_count2 = CountOpsInGraph(graph); + ASSERT_FALSE(op_to_count2.count("GRU")); + ASSERT_TRUE(op_to_count2.count("com.microsoft.GRUTraining") && op_to_count2["com.microsoft.GRUTraining"] == 1); + + const auto nodes = graph.Nodes(); + ASSERT_FALSE(nodes.empty()); + const auto& gru_outputs = nodes.begin()->OutputDefs(); + ASSERT_EQ(gru_outputs.size(), 3U); +} + +INSTANTIATE_TEST_SUITE_P( + GRUReplacementTests, + GRUReplacementTestsParameterized, + ::testing::Values( + std::make_tuple(0, false, false), + std::make_tuple(1, true, false), + std::make_tuple(1, false, true), + std::make_tuple(2, true, true))); + class QDQFusionTestsParameterized : public GraphTransformationTests, public ::testing::WithParamInterface> { }; @@ -1133,7 +1220,7 @@ static void RunPartitionCorrectnessTest(std::string model_path, [&generator, &distribution](float& value) { value = distribution(generator); }); OrtValue ml_value; - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), dims_X, values_X, &ml_value); + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], dims_X, values_X, &ml_value); feeds.insert(std::make_pair(input_names[i], ml_value)); } @@ -1212,11 +1299,466 @@ TEST_F(GraphTransformationTests, MegatronSelfAttentionPartitionCorrectnessTest) TEST_F(GraphTransformationTests, MegatronBARTSelfAttentionPartitionCorrectnessTest) { RunPartitionCorrectnessTest("testdata/transform/model_parallel/bart_self_attention_megatron_basic_test", *logger_, 2, {"input"}, {{6, 8, 4}}); } + // end of USE_CUDA #endif +/* +Test graph as below. + graph input [1, 1, 256, 256] (float) scalar_0 graph input [1, 1, 256, 256] (float) + \ / / + Div Div -- scalar_1 +[1, 1, 256, 256] (float) scalar_3 \ / + \ / Add + Div / + \ / + \ / + Add + | + Identity + | + graph out [1, 1, 256, 256] (float) + +*/ +TEST_F(GraphTransformationTests, ScaledSumFusionThreeInputs) { + auto pre_graph_checker = [](Graph& graph) -> Status { + auto op_count_pre = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_count_pre.size() == 3U); + TEST_RETURN_IF_NOT(op_count_pre["Div"] == 3); + TEST_RETURN_IF_NOT(op_count_pre["Add"] == 2); + TEST_RETURN_IF_NOT(op_count_pre["Identity"] == 1); + TEST_RETURN_IF_NOT(graph.GetAllInitializedTensors().size() == 3U); + return Status::OK(); + }; + + auto post_graph_checker = [](Graph& graph) { + auto op_count = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_count.size() == 2U); + TEST_RETURN_IF_NOT(op_count["com.microsoft.ScaledSum"] == 1); + TEST_RETURN_IF_NOT(op_count["Identity"] == 1); + + for (auto& node : graph.Nodes()) { + if (node.OpType() == "ScaledSum") { + TEST_RETURN_IF_NOT(node.InputDefs().size() == 3U); + + auto& attrs = node.GetAttributes(); + TEST_RETURN_IF_NOT(attrs.find("scale_0") != attrs.end()); + TEST_RETURN_IF_NOT(attrs.find("scale_1") != attrs.end()); + TEST_RETURN_IF_NOT(attrs.find("scale_2") != attrs.end()); + TEST_RETURN_IF_NOT(1.0f / 0.5f == attrs.at("scale_0").f()); + TEST_RETURN_IF_NOT(1.0f / 0.3f == attrs.at("scale_1").f()); + TEST_RETURN_IF_NOT(1.0f / 0.2f == attrs.at("scale_2").f()); + } + } + + return Status::OK(); + }; + + InlinedVector switch_orders{false, true}; + for (bool switch_order : switch_orders) { + auto build_test_case = [switch_order](ModelTestBuilder& builder) { + auto* input_0_arg = builder.MakeInput({{1, 1, 256, 256}}); + auto* input_1_arg = builder.MakeInput({{1, 1, 256, 256}}); + auto* input_2_arg = builder.MakeInput({{1, 1, 256, 256}}); + auto* scalar_0_arg = builder.MakeScalarInitializer(0.5f); + auto* scalar_1_arg = builder.MakeScalarInitializer(0.3f); + auto* scalar_2_arg = builder.MakeScalarInitializer(0.2f); + auto* div0_out = builder.MakeIntermediate(); + auto* div1_out = builder.MakeIntermediate(); + auto* div2_out = builder.MakeIntermediate(); + builder.AddNode("Div", {input_0_arg, scalar_0_arg}, {div0_out}); + builder.AddNode("Div", {input_1_arg, scalar_1_arg}, {div1_out}); + + auto* add1_out = builder.MakeIntermediate(); + builder.AddNode("Add", {div0_out, div1_out}, {add1_out}); + + builder.AddNode("Div", {input_2_arg, scalar_2_arg}, {div2_out}); + auto* add2_out = builder.MakeIntermediate(); + if (switch_order) { + builder.AddNode("Add", {div2_out, add1_out}, {add2_out}); + } else { + builder.AddNode("Add", {add1_out, div2_out}, {add2_out}); + } + + auto* graph_out = builder.MakeOutput(); + builder.AddNode("Identity", {add2_out}, {graph_out}); + }; + + const std::vector opsets{12, 13, 14, 15}; + for (auto& opset_version : opsets) { + std::unique_ptr transformer = std::make_unique(); + ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, opset_version, *logger_, std::move(transformer), + TransformerLevel::Level1, + 1, pre_graph_checker, post_graph_checker)); + } + } +} + +/* +Test graph as below. + graph input [1, 1, 256, 256] (float) scalar_0 graph input [1, 1, 256, 256] (float) + \ / | + Div Div -- scalar_1 +[1, 1, 256, 256] (float) scalar_3 \ / + \ / Add + Sub / + \ / + \ / + Add + | + Identity + | + graph out [1, 1, 256, 256] (float) + +*/ +TEST_F(GraphTransformationTests, ScaledSumFusionThreeInputs_LastAddNotHaveScaleInput) { + auto pre_graph_checker = [](Graph& graph) -> Status { + auto op_count_pre = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_count_pre.size() == 4U); + TEST_RETURN_IF_NOT(op_count_pre["Div"] == 2); + TEST_RETURN_IF_NOT(op_count_pre["Add"] == 2); + TEST_RETURN_IF_NOT(op_count_pre["Identity"] == 1); + TEST_RETURN_IF_NOT(op_count_pre["Sub"] == 1); + TEST_RETURN_IF_NOT(graph.GetAllInitializedTensors().size() == 3U); + return Status::OK(); + }; + + auto post_graph_checker = [](Graph& graph) { + auto op_count = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_count.size() == 3U); + TEST_RETURN_IF_NOT(op_count["com.microsoft.ScaledSum"] == 1); + TEST_RETURN_IF_NOT(op_count["Identity"] == 1); + TEST_RETURN_IF_NOT(op_count["Sub"] == 1); + + for (auto& node : graph.Nodes()) { + if (node.OpType() == "ScaledSum") { + TEST_RETURN_IF_NOT(node.InputDefs().size() == 3U); + + auto& attrs = node.GetAttributes(); + TEST_RETURN_IF_NOT(attrs.find("scale_0") != attrs.end()); + TEST_RETURN_IF_NOT(attrs.find("scale_1") != attrs.end()); + TEST_RETURN_IF_NOT(attrs.find("scale_2") != attrs.end()); + TEST_RETURN_IF_NOT(1.0f / 0.5f == attrs.at("scale_0").f()); + TEST_RETURN_IF_NOT(1.0f / 0.3f == attrs.at("scale_1").f()); + TEST_RETURN_IF_NOT(1.0f == attrs.at("scale_2").f()); + } + } + + return Status::OK(); + }; + + InlinedVector switch_orders{false, true}; + for (bool switch_order : switch_orders) { + auto build_test_case = [switch_order](ModelTestBuilder& builder) { + auto* input_0_arg = builder.MakeInput({{1, 1, 256, 256}}); + auto* input_1_arg = builder.MakeInput({{1, 1, 256, 256}}); + auto* input_2_arg = builder.MakeInput({{1, 1, 256, 256}}); + auto* scalar_0_arg = builder.MakeScalarInitializer(0.5f); + auto* scalar_1_arg = builder.MakeScalarInitializer(0.3f); + auto* scalar_2_arg = builder.MakeScalarInitializer(0.2f); + auto* div0_out = builder.MakeIntermediate(); + auto* div1_out = builder.MakeIntermediate(); + auto* sub0_out = builder.MakeIntermediate(); + builder.AddNode("Div", {input_0_arg, scalar_0_arg}, {div0_out}); + builder.AddNode("Div", {input_1_arg, scalar_1_arg}, {div1_out}); + + auto* add1_out = builder.MakeIntermediate(); + builder.AddNode("Add", {div0_out, div1_out}, {add1_out}); + + builder.AddNode("Sub", {input_2_arg, scalar_2_arg}, {sub0_out}); + auto* add2_out = builder.MakeIntermediate(); + if (switch_order) { + builder.AddNode("Add", {sub0_out, add1_out}, {add2_out}); + } else { + builder.AddNode("Add", {add1_out, sub0_out}, {add2_out}); + } + + auto* graph_out = builder.MakeOutput(); + builder.AddNode("Identity", {add2_out}, {graph_out}); + }; + + const std::vector opsets{12, 13, 14, 15}; + for (auto& opset_version : opsets) { + std::unique_ptr transformer = std::make_unique(); + ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, opset_version, *logger_, std::move(transformer), + TransformerLevel::Level1, + 1, pre_graph_checker, post_graph_checker)); + } + } +} + +/* +Test graph as below. + graph input [1, 1, 256, 256] (float) scalar_0 graph input [1, 1, 256, 256] (float) + \ / / + Div Div -- scalar_1 +[1, 1, 256, 256] (float) scalar_3 \ / + \ / Add + Div / \ + \ / Identity + \ / | + Add graph out [1, 1, 256, 256] (float) + | + Identity + | + graph out [1, 1, 256, 256] (float) + +*/ +TEST_F(GraphTransformationTests, ScaledSumFusionTwoInputs) { + auto pre_graph_checker = [](Graph& graph) -> Status { + auto op_count_pre = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_count_pre.size() == 3U); + TEST_RETURN_IF_NOT(op_count_pre["Div"] == 3); + TEST_RETURN_IF_NOT(op_count_pre["Add"] == 2); + TEST_RETURN_IF_NOT(op_count_pre["Identity"] == 2); + TEST_RETURN_IF_NOT(graph.GetAllInitializedTensors().size() == 3U); + return Status::OK(); + }; + + auto post_graph_checker = [](Graph& graph) { + auto op_count = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_count.size() == 4U); + TEST_RETURN_IF_NOT(op_count["Div"] == 1); + TEST_RETURN_IF_NOT(op_count["Add"] == 1); + TEST_RETURN_IF_NOT(op_count["com.microsoft.ScaledSum"] == 1); + TEST_RETURN_IF_NOT(op_count["Identity"] == 2); + + for (auto& node : graph.Nodes()) { + if (node.OpType() == "ScaledSum") { + TEST_RETURN_IF_NOT(node.InputDefs().size() == 2U); + + auto& attrs = node.GetAttributes(); + TEST_RETURN_IF_NOT(attrs.find("scale_0") != attrs.end()); + TEST_RETURN_IF_NOT(attrs.find("scale_1") != attrs.end()); + TEST_RETURN_IF_NOT(attrs.find("scale_2") == attrs.end()); + TEST_RETURN_IF_NOT(1.0f / 0.5f == attrs.at("scale_0").f()); + TEST_RETURN_IF_NOT(1.0f / 0.3f == attrs.at("scale_1").f()); + } + } + return Status::OK(); + }; + + InlinedVector switch_orders{false, true}; + for (bool switch_order : switch_orders) { + auto build_test_case = [switch_order](ModelTestBuilder& builder) { + auto* input_0_arg = builder.MakeInput({{1, 1, 256, 256}}); + auto* input_1_arg = builder.MakeInput({{1, 1, 256, 256}}); + auto* input_2_arg = builder.MakeInput({{1, 1, 256, 256}}); + auto* scalar_0_arg = builder.MakeScalarInitializer(0.5f); + auto* scalar_1_arg = builder.MakeScalarInitializer(0.3f); + auto* scalar_2_arg = builder.MakeScalarInitializer(0.2f); + auto* div0_out = builder.MakeIntermediate(); + auto* div1_out = builder.MakeIntermediate(); + auto* div2_out = builder.MakeIntermediate(); + builder.AddNode("Div", {input_0_arg, scalar_0_arg}, {div0_out}); + builder.AddNode("Div", {input_1_arg, scalar_1_arg}, {div1_out}); + + auto* add1_out = builder.MakeIntermediate(); + builder.AddNode("Add", {div0_out, div1_out}, {add1_out}); + + builder.AddNode("Div", {input_2_arg, scalar_2_arg}, {div2_out}); + auto* add2_out = builder.MakeIntermediate(); + if (switch_order) { + builder.AddNode("Add", {div2_out, add1_out}, {add2_out}); + } else { + builder.AddNode("Add", {add1_out, div2_out}, {add2_out}); + } + + auto* graph_out = builder.MakeOutput(); + builder.AddNode("Identity", {add2_out}, {graph_out}); + + auto* graph_output2 = builder.MakeOutput(); + builder.AddNode("Identity", {add1_out}, {graph_output2}); + }; + + const std::vector opsets{12, 13, 14, 15}; + for (auto& opset_version : opsets) { + std::unique_ptr transformer = std::make_unique(); + ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, opset_version, *logger_, std::move(transformer), + TransformerLevel::Level1, + 1, pre_graph_checker, post_graph_checker)); + } + } +} + // end of DISABLE_CONTRIB_OPS #endif +#ifdef ENABLE_TRITON +TEST_F(GraphTransformationTests, TritonFusion) { + auto model_uri = MODEL_FOLDER "bert_toy_opset14.onnx"; + std::shared_ptr model; + ASSERT_STATUS_OK(Model::Load(model_uri, model, nullptr, *logger_)); + Graph& graph = model->MainGraph(); + std::map op_to_count = CountOpsInGraph(graph); + ASSERT_TRUE(op_to_count["Add"] == 17); + ASSERT_TRUE(op_to_count["Sub"] == 1); + ASSERT_TRUE(op_to_count["Mul"] == 7); + ASSERT_TRUE(op_to_count["Div"] == 3); + ASSERT_TRUE(op_to_count["Cast"] == 7); + ASSERT_TRUE(op_to_count["Dropout"] == 4); + ASSERT_TRUE(op_to_count["Softmax"] == 1); + ASSERT_TRUE(op_to_count["LayerNormalization"] == 4); + + { + auto model_uri = MODEL_FOLDER "bert_toy_opset14.onnx"; + std::shared_ptr model; + ASSERT_STATUS_OK(Model::Load(model_uri, model, nullptr, *logger_)); + Graph& graph = model->MainGraph(); + const char* config = R"( + { + "ops": { + "Add": { "versions": [13, 14] }, + "Sub": { "versions": [13, 14] }, + "Mul": { "versions": [13, 14] }, + "Div": { "versions": [13, 14] }, + "Cast": { "versions": [13] }, + "Dropout": { "versions": [13] }, + "Softmax": { "versions": [13], "conditions": { "axis": "-1" } }, + "LayerNormalization": { "versions": [1], "conditions": { "axis": "-1" } } + }, + "initializer": "scalar", + "min_nodes": 2 + } + )"; + + std::unique_ptr transformer = std::make_unique(config); + onnxruntime::GraphTransformerManager graph_transformation_mgr{1}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::move(transformer), TransformerLevel::Level1)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level1, *logger_)); + + op_to_count = CountOpsInGraph(graph); + ASSERT_TRUE(op_to_count["Add"] == 6); + ASSERT_TRUE(op_to_count["Sub"] == 0); + ASSERT_TRUE(op_to_count["Mul"] == 0); + ASSERT_TRUE(op_to_count["Div"] == 0); + ASSERT_TRUE(op_to_count["Cast"] == 4); + ASSERT_TRUE(op_to_count["Dropout"] == 0); + ASSERT_TRUE(op_to_count["Softmax"] == 0); + ASSERT_TRUE(op_to_count["LayerNormalization"] == 0); + ASSERT_TRUE(op_to_count["com.microsoft.TritonOp"] == 10); + } + + // No Dropout. + { + auto model_uri = MODEL_FOLDER "bert_toy_opset14.onnx"; + std::shared_ptr model; + ASSERT_STATUS_OK(Model::Load(model_uri, model, nullptr, *logger_)); + Graph& graph = model->MainGraph(); + const char* config = R"( + { + "ops": { + "Add": { "versions": [13, 14] }, + "Sub": { "versions": [13, 14] }, + "Mul": { "versions": [13, 14] }, + "Div": { "versions": [13, 14] }, + "Cast": { "versions": [13] }, + "Softmax": { "versions": [13], "conditions": { "axis": "-1" } }, + "LayerNormalization": { "versions": [1], "conditions": { "axis": "-1" } } + }, + "initializer": "scalar", + "min_nodes": 2 + } + )"; + + std::unique_ptr transformer = std::make_unique(config); + onnxruntime::GraphTransformerManager graph_transformation_mgr{1}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::move(transformer), TransformerLevel::Level1)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level1, *logger_)); + + op_to_count = CountOpsInGraph(graph); + ASSERT_TRUE(op_to_count["Add"] == 8); + ASSERT_TRUE(op_to_count["Sub"] == 0); + ASSERT_TRUE(op_to_count["Mul"] == 0); + ASSERT_TRUE(op_to_count["Div"] == 0); + ASSERT_TRUE(op_to_count["Cast"] == 4); + ASSERT_TRUE(op_to_count["Dropout"] == 4); + ASSERT_TRUE(op_to_count["Softmax"] == 0); + ASSERT_TRUE(op_to_count["LayerNormalization"] == 0); + ASSERT_TRUE(op_to_count["com.microsoft.TritonOp"] == 10); + } + + // Ignore min nodes. + { + auto model_uri = MODEL_FOLDER "bert_toy_opset14.onnx"; + std::shared_ptr model; + ASSERT_STATUS_OK(Model::Load(model_uri, model, nullptr, *logger_)); + Graph& graph = model->MainGraph(); + const char* config = R"( + { + "ops": { + "Add": { "versions": [13, 14] }, + "Sub": { "versions": [13, 14] }, + "Mul": { "versions": [13, 14] }, + "Div": { "versions": [13, 14] }, + "Cast": { "versions": [13], "ignore_min_nodes": true }, + "Dropout": { "versions": [13] }, + "Softmax": { "versions": [13], "conditions": { "axis": "-1" } }, + "LayerNormalization": { "versions": [1], "conditions": { "axis": "-1" } } + }, + "initializer": "scalar", + "min_nodes": 2 + } + )"; + + std::unique_ptr transformer = std::make_unique(config); + onnxruntime::GraphTransformerManager graph_transformation_mgr{1}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::move(transformer), TransformerLevel::Level1)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level1, *logger_)); + + op_to_count = CountOpsInGraph(graph); + ASSERT_TRUE(op_to_count["Add"] == 6); + ASSERT_TRUE(op_to_count["Sub"] == 0); + ASSERT_TRUE(op_to_count["Mul"] == 0); + ASSERT_TRUE(op_to_count["Div"] == 0); + ASSERT_TRUE(op_to_count["Cast"] == 0); + ASSERT_TRUE(op_to_count["Dropout"] == 0); + ASSERT_TRUE(op_to_count["Softmax"] == 0); + ASSERT_TRUE(op_to_count["LayerNormalization"] == 0); + ASSERT_TRUE(op_to_count["com.microsoft.TritonOp"] == 14); + } + + // Exclude Softmax using axis attribute. + { + auto model_uri = MODEL_FOLDER "bert_toy_opset14.onnx"; + std::shared_ptr model; + ASSERT_STATUS_OK(Model::Load(model_uri, model, nullptr, *logger_)); + Graph& graph = model->MainGraph(); + const char* config = R"( + { + "ops": { + "Add": { "versions": [13, 14] }, + "Sub": { "versions": [13, 14] }, + "Mul": { "versions": [13, 14] }, + "Div": { "versions": [13, 14] }, + "Cast": { "versions": [13]}, + "Dropout": { "versions": [13] }, + "Softmax": { "versions": [13], "conditions": { "axis": "1" } }, + "LayerNormalization": { "versions": [1], "conditions": { "axis": "-1" } } + }, + "initializer": "scalar", + "min_nodes": 2 + } + )"; + + std::unique_ptr transformer = std::make_unique(config); + onnxruntime::GraphTransformerManager graph_transformation_mgr{1}; + ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::move(transformer), TransformerLevel::Level1)); + ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level1, *logger_)); + + op_to_count = CountOpsInGraph(graph); + ASSERT_TRUE(op_to_count["Add"] == 6); + ASSERT_TRUE(op_to_count["Sub"] == 0); + ASSERT_TRUE(op_to_count["Mul"] == 0); + ASSERT_TRUE(op_to_count["Div"] == 0); + ASSERT_TRUE(op_to_count["Cast"] == 4); + ASSERT_TRUE(op_to_count["Dropout"] == 1); + ASSERT_TRUE(op_to_count["Softmax"] == 1); + ASSERT_TRUE(op_to_count["LayerNormalization"] == 0); + ASSERT_TRUE(op_to_count["com.microsoft.TritonOp"] == 10); + } +} +#endif + } // namespace test } // namespace onnxruntime diff --git a/orttraining/orttraining/test/optimizer/shape_optimizer_test.cc b/orttraining/orttraining/test/optimizer/shape_optimizer_test.cc new file mode 100644 index 0000000000000..ea05b29c8668b --- /dev/null +++ b/orttraining/orttraining/test/optimizer/shape_optimizer_test.cc @@ -0,0 +1,1043 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/graph/model.h" +#include "test/framework/test_utils.h" +#include "test/test_environment.h" + +#include "gtest/gtest.h" +#include "core/optimizer/utils.h" +#include "test/optimizer/graph_transform_test_builder.h" +#include "test/optimizer/graph_transform_test_fixture.h" +#include "test/util/include/asserts.h" +#include "orttraining/core/optimizer/shape_optimizer.h" + +using namespace std; +using namespace ONNX_NAMESPACE; + +namespace onnxruntime { +namespace test { + +#ifndef DISABLE_CONTRIB_OPS + +TEST(ShapeOptimizerTests, Shape15CannotFold) { + /* + [attention_mask1_dim0,512,1536] + | + Identity + | + [attention_mask1_dim0,512,1536] + | + Shape15 + | + [2]: (attention_mask1_dim0,512) + | + Identity + | + [2] + */ + + std::string identity_output_name; + + auto pre_graph_checker = [&](Graph& graph) -> Status { + auto op_to_count = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_to_count["Identity"] == 2); + TEST_RETURN_IF_NOT(op_to_count["Shape"] == 1); + + identity_output_name = ""; + for (auto& node : graph.Nodes()) { + if (node.OpType().compare("Identity") == 0) + identity_output_name = node.MutableOutputDefs()[0]->Name(); + } + + return Status::OK(); + }; + + auto post_graph_checker = [&](Graph& graph) -> Status { + auto op_to_count = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_to_count["Identity"] == 2); + TEST_RETURN_IF_NOT(op_to_count["Shape"] == 1); + + TEST_RETURN_IF_NOT(!identity_output_name.empty()); + auto input_arg = graph.GetNodeArg(identity_output_name); + // Try to parse int64 type constant initializers. + InlinedVector shape_values; + TEST_RETURN_IF_NOT(!optimizer_utils::AppendTensorFromInitializer(graph, *input_arg, shape_values, true)); + + return Status::OK(); + }; + + std::vector opset_candidates{15}; + for (auto opset : opset_candidates) { + auto build_test_case = [&](ModelTestBuilder& builder) { + std::vector> identity_input_shape; + identity_input_shape.reserve(3); + identity_input_shape.push_back("attention_mask1_dim0"); + identity_input_shape.push_back(512); + identity_input_shape.push_back(1536); + + auto* identity_input_arg = builder.MakeSymbolicInput(identity_input_shape); + auto* identity_out_arg = builder.MakeIntermediate(); + builder.AddNode("Identity", {identity_input_arg}, {identity_out_arg}); + + auto* shape_out_arg = builder.MakeIntermediate(); + Node& shape_node = builder.AddNode("Shape", {identity_out_arg}, {shape_out_arg}); + shape_node.AddAttribute("start", static_cast(0)); + shape_node.AddAttribute("end", static_cast(2)); + + auto* identity_out_arg_1 = builder.MakeOutput(); + builder.AddNode("Identity", {shape_out_arg}, {identity_out_arg_1}); + }; + const logging::Logger* logger = &logging::LoggingManager::DefaultLogger(); + InlinedHashSet compatible_eps; + std::unique_ptr transformer = std::make_unique(compatible_eps); + ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, opset, *logger, std::move(transformer), + TransformerLevel::Level1, 1, + pre_graph_checker, post_graph_checker)); + } +} + +TEST(ShapeOptimizerTests, Shape15) { + /* + [attention_mask1_dim0,512,1536] + | + Identity + | + [attention_mask1_dim0,512,1536] + | + Shape15 + | + [2]: (512,1536) + | + Identity + | + [2] + */ + + std::string shape_output_name; + + auto pre_graph_checker = [&](Graph& graph) -> Status { + auto op_to_count = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_to_count["Identity"] == 2); + TEST_RETURN_IF_NOT(op_to_count["Shape"] == 1); + + shape_output_name = ""; + for (auto& node : graph.Nodes()) { + if (node.OpType().compare("Shape") == 0) + shape_output_name = node.MutableOutputDefs()[0]->Name(); + } + return Status::OK(); + }; + + auto post_graph_checker = [&](Graph& graph) -> Status { + auto op_to_count = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_to_count["Identity"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Shape"] == 0); + + TEST_RETURN_IF_NOT(!shape_output_name.empty()); + auto input_arg = graph.GetNodeArg(shape_output_name); + // Try to parse int64 type constant initializers. + InlinedVector shape_values; + TEST_RETURN_IF_NOT(optimizer_utils::AppendTensorFromInitializer(graph, *input_arg, shape_values, true)); + TEST_RETURN_IF_NOT(shape_values.size() == 2U); + TEST_RETURN_IF_NOT(shape_values[0] == 512); + TEST_RETURN_IF_NOT(shape_values[1] == 1536); + return Status::OK(); + }; + + std::vector opset_candidates{15}; + for (auto opset : opset_candidates) { + auto build_test_case = [&](ModelTestBuilder& builder) { + std::vector> identity_input_shape; + identity_input_shape.reserve(3); + identity_input_shape.push_back("attention_mask1_dim0"); + identity_input_shape.push_back(512); + identity_input_shape.push_back(1536); + + auto* identity_input_arg = builder.MakeSymbolicInput(identity_input_shape); + auto* identity_out_arg = builder.MakeIntermediate(); + builder.AddNode("Identity", {identity_input_arg}, {identity_out_arg}); + + auto* shape_out_arg = builder.MakeIntermediate(); + builder.AddNode("Shape", {identity_out_arg}, {shape_out_arg}) + .AddAttribute("start", static_cast(-2)); + + auto* identity_out_arg_1 = builder.MakeOutput(); + builder.AddNode("Identity", {shape_out_arg}, {identity_out_arg_1}); + }; + + const logging::Logger* logger = &logging::LoggingManager::DefaultLogger(); + InlinedHashSet compatible_eps; + std::unique_ptr transformer = std::make_unique(compatible_eps); + ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, opset, *logger, std::move(transformer), + TransformerLevel::Level1, 1, + pre_graph_checker, post_graph_checker)); + } +} + +TEST(ShapeOptimizerTests, Shape15TakesGraphInput) { + /* + [attention_mask1_dim0,512,1536] + | + Shape15 + | + [2]: (512,1536) + | + Identity + | + [2] + */ + + std::string shape_output_name; + auto pre_graph_checker = [&](Graph& graph) -> Status { + auto op_to_count = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_to_count["Identity"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Shape"] == 1); + + shape_output_name = ""; + for (auto& node : graph.Nodes()) { + if (node.OpType().compare("Shape") == 0) + shape_output_name = node.MutableOutputDefs()[0]->Name(); + } + return Status::OK(); + }; + + auto post_graph_checker = [&](Graph& graph) -> Status { + auto op_to_count = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_to_count["Identity"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Shape"] == 0); + + TEST_RETURN_IF_NOT(!shape_output_name.empty()); + auto input_arg = graph.GetNodeArg(shape_output_name); + // Try to parse int64 type constant initializers. + InlinedVector shape_values; + TEST_RETURN_IF_NOT(optimizer_utils::AppendTensorFromInitializer(graph, *input_arg, shape_values, true)); + TEST_RETURN_IF_NOT(shape_values.size() == 2U); + TEST_RETURN_IF_NOT(shape_values[0] == 512); + TEST_RETURN_IF_NOT(shape_values[1] == 1536); + return Status::OK(); + }; + + std::vector opset_candidates{15}; + for (auto opset : opset_candidates) { + auto build_test_case = [&](ModelTestBuilder& builder) { + std::vector> shape_input_shape; + shape_input_shape.reserve(3); + shape_input_shape.push_back("attention_mask1_dim0"); + shape_input_shape.push_back(512); + shape_input_shape.push_back(1536); + + auto* shape_input_arg = builder.MakeSymbolicInput(shape_input_shape); + auto* shape_out_arg = builder.MakeIntermediate(); + builder.AddNode("Shape", {shape_input_arg}, {shape_out_arg}) + .AddAttribute("start", static_cast(-2)); + + auto* identity_out_arg_1 = builder.MakeOutput(); + builder.AddNode("Identity", {shape_out_arg}, {identity_out_arg_1}); + }; + + const logging::Logger* logger = &logging::LoggingManager::DefaultLogger(); + InlinedHashSet compatible_eps; + std::unique_ptr transformer = std::make_unique(compatible_eps); + ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, opset, *logger, std::move(transformer), + TransformerLevel::Level1, 1, + pre_graph_checker, post_graph_checker)); + } +} + +TEST(ShapeOptimizerTests, Shape15GeneratesGraphOutput) { + /* + [attention_mask1_dim0,512,1536] + | + Identity + | + [attention_mask1_dim0,512,1536] + | + Shape15 + | + [2]: (512,1536) + | + [2] + */ + std::string shape_output_name; + auto pre_graph_checker = [&](Graph& graph) -> Status { + auto op_to_count = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_to_count["Identity"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Shape"] == 1); + + shape_output_name = ""; + for (auto& node : graph.Nodes()) { + if (node.OpType().compare("Shape") == 0) + shape_output_name = node.MutableOutputDefs()[0]->Name(); + } + return Status::OK(); + }; + + auto post_graph_checker = [&](Graph& graph) -> Status { + auto op_to_count = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_to_count["Identity"] == 0); + TEST_RETURN_IF_NOT(op_to_count["Shape"] == 0); + + TEST_RETURN_IF_NOT(!shape_output_name.empty()); + auto input_arg = graph.GetNodeArg(shape_output_name); + // Try to parse int64 type constant initializers. + InlinedVector shape_values; + TEST_RETURN_IF_NOT(optimizer_utils::AppendTensorFromInitializer(graph, *input_arg, shape_values, true)); + TEST_RETURN_IF_NOT(shape_values.size() == 2U); + TEST_RETURN_IF_NOT(shape_values[0] == 512); + TEST_RETURN_IF_NOT(shape_values[1] == 1536); + return Status::OK(); + }; + + std::vector opset_candidates{15}; + for (auto opset : opset_candidates) { + auto build_test_case = [&](ModelTestBuilder& builder) { + std::vector> identity_input_shape; + identity_input_shape.reserve(3); + identity_input_shape.push_back("attention_mask1_dim0"); + identity_input_shape.push_back(512); + identity_input_shape.push_back(1536); + + auto* identity_input_arg = builder.MakeSymbolicInput(identity_input_shape); + auto* identity_out_arg = builder.MakeIntermediate(); + builder.AddNode("Identity", {identity_input_arg}, {identity_out_arg}); + + auto* shape_out_arg = builder.MakeOutput(); + builder.AddNode("Shape", {identity_out_arg}, {shape_out_arg}) + .AddAttribute("start", static_cast(-2)); + }; + + const logging::Logger* logger = &logging::LoggingManager::DefaultLogger(); + InlinedHashSet compatible_eps; + std::unique_ptr transformer = std::make_unique(compatible_eps); + ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, opset, *logger, std::move(transformer), + TransformerLevel::Level1, 1, + pre_graph_checker, post_graph_checker)); + } +} + +TEST(ShapeOptimizerTests, Slice) { + /* + [attention_mask1_dim0,512,1536] + | + Shape + | + [4]: (attention_mask1_dim0,512,1536) + | + Slice + | + [2]: (512, 1536) + | + Identity + | + [2] + */ + + std::string slice_output_name; + + auto pre_graph_checker = [&](Graph& graph) -> Status { + auto op_to_count = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_to_count["Identity"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Shape"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Slice"] == 1); + + slice_output_name = ""; + for (auto& node : graph.Nodes()) { + if (node.OpType().compare("Slice") == 0) + slice_output_name = node.MutableOutputDefs()[0]->Name(); + } + return Status::OK(); + }; + + auto post_graph_checker = [&](Graph& graph) -> Status { + auto op_to_count = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_to_count["Identity"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Shape"] == 0); + TEST_RETURN_IF_NOT(op_to_count["Slice"] == 0); + + TEST_RETURN_IF_NOT(!slice_output_name.empty()); + auto input_arg = graph.GetNodeArg(slice_output_name); + // Try to parse int64 type constant initializers. + InlinedVector shape_values; + TEST_RETURN_IF_NOT(optimizer_utils::AppendTensorFromInitializer(graph, *input_arg, shape_values, true)); + TEST_RETURN_IF_NOT(shape_values.size() == 2U); + TEST_RETURN_IF_NOT(shape_values[0] == 512); + TEST_RETURN_IF_NOT(shape_values[1] == 1536); + return Status::OK(); + }; + + std::vector opset_candidates{10, 11, 12, 13, 14, 15}; + for (auto opset : opset_candidates) { + auto build_test_case = [&](ModelTestBuilder& builder) { + std::vector> shape_input_shape; + shape_input_shape.reserve(3); + shape_input_shape.push_back("attention_mask1_dim0"); + shape_input_shape.push_back(512); + shape_input_shape.push_back(1536); + + auto* shape_input_arg = builder.MakeSymbolicInput(shape_input_shape); + auto* shape_out_arg = builder.MakeIntermediate(); + builder.AddNode("Shape", {shape_input_arg}, {shape_out_arg}); + + // Slice after opset 1 have such schema. + auto* slice_out_arg = builder.MakeIntermediate(); + auto* starts_input_arg = builder.MakeInitializer({1}, {-2}); + auto* ends_input_arg = builder.MakeInitializer({1}, {3}); + auto* axes_input_arg = builder.MakeInitializer({1}, {0}); + builder.AddNode("Slice", {shape_out_arg, starts_input_arg, ends_input_arg, axes_input_arg}, {slice_out_arg}); + + auto* identity_out_arg_1 = builder.MakeOutput(); + builder.AddNode("Identity", {slice_out_arg}, {identity_out_arg_1}); + }; + + const logging::Logger* logger = &logging::LoggingManager::DefaultLogger(); + InlinedHashSet compatible_eps; + std::unique_ptr transformer = std::make_unique(compatible_eps); + ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, opset, *logger, std::move(transformer), + TransformerLevel::Level1, 1, + pre_graph_checker, post_graph_checker)); + } +} + +TEST(ShapeOptimizerTests, SliceGeneratesGraphOutput) { + /* + [attention_mask1_dim0,512,1536] + | + Shape + | + [4]: (attention_mask1_dim0,512,1536) + | + Slice + | + [2]: (512, 1536) + | + [2] + This test also test when axes and step input are missing. + */ + + std::string slice_output_name; + auto pre_graph_checker = [&](Graph& graph) -> Status { + auto op_to_count = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_to_count["Shape"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Slice"] == 1); + + slice_output_name = ""; + for (auto& node : graph.Nodes()) { + if (node.OpType().compare("Slice") == 0) + slice_output_name = node.MutableOutputDefs()[0]->Name(); + } + + return Status::OK(); + }; + + auto post_graph_checker = [&](Graph& graph) -> Status { + auto op_to_count = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_to_count["Shape"] == 0); + TEST_RETURN_IF_NOT(op_to_count["Slice"] == 0); + + TEST_RETURN_IF_NOT(!slice_output_name.empty()); + auto input_arg = graph.GetNodeArg(slice_output_name); + // Try to parse int64 type constant initializers. + InlinedVector shape_values; + TEST_RETURN_IF_NOT(optimizer_utils::AppendTensorFromInitializer(graph, *input_arg, shape_values, true)); + TEST_RETURN_IF_NOT(shape_values.size() == 2U); + TEST_RETURN_IF_NOT(shape_values[0] == 512); + TEST_RETURN_IF_NOT(shape_values[1] == 1536); + return Status::OK(); + }; + + std::vector opset_candidates{10, 11, 12, 13, 14, 15}; + for (auto opset : opset_candidates) { + auto build_test_case = [&](ModelTestBuilder& builder) { + std::vector> shape_input_shape; + shape_input_shape.reserve(3); + shape_input_shape.push_back("attention_mask1_dim0"); + shape_input_shape.push_back(512); + shape_input_shape.push_back(1536); + + auto* shape_input_arg = builder.MakeSymbolicInput(shape_input_shape); + auto* shape_out_arg = builder.MakeIntermediate(); + builder.AddNode("Shape", {shape_input_arg}, {shape_out_arg}); + + // Slice after opset 1 have such schema. + auto* slice_out_arg = builder.MakeOutput(); + auto* starts_input_arg = builder.MakeInitializer({1}, {-2}); + auto* ends_input_arg = builder.MakeInitializer({1}, {3}); + builder.AddNode("Slice", {shape_out_arg, starts_input_arg, ends_input_arg}, {slice_out_arg}); + }; + + const logging::Logger* logger = &logging::LoggingManager::DefaultLogger(); + InlinedHashSet compatible_eps; + std::unique_ptr transformer = std::make_unique(compatible_eps); + ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, opset, *logger, std::move(transformer), + TransformerLevel::Level1, 1, + pre_graph_checker, post_graph_checker)); + } +} + +TEST(ShapeOptimizerTests, Gather) { + /* + [attention_mask1_dim0,512,24,64] + | + Shape + | + [4] + / \ + Gather Gather + | | + []: (attention_mask1_dim0,) [1]: (24,) + | | + [] means a shape for scalar. + */ + + std::vector gather_output_names; + gather_output_names.reserve(2); + auto pre_graph_checker = [&](Graph& graph) -> Status { + auto op_to_count = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_to_count["Shape"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Gather"] == 2); + + gather_output_names.clear(); + for (auto& node : graph.Nodes()) { + if (node.OpType().compare("Gather") == 0) { + gather_output_names.push_back(node.MutableOutputDefs()[0]->Name()); + } + } + + return Status::OK(); + }; + + auto post_graph_checker = [&](Graph& graph) -> Status { + auto op_to_count = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_to_count["Shape"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Gather"] == 1); + + for (auto& node : graph.Nodes()) { + if (node.OpType() == "Gather") { + for (auto& gather_output_name : gather_output_names) { + if (gather_output_name.compare(node.MutableOutputDefs()[0]->Name()) != 0) { + // Try to parse int64 type constant initializers. + InlinedVector shape_values; + auto input_arg = graph.GetNodeArg(gather_output_name); + TEST_RETURN_IF_NOT(optimizer_utils::AppendTensorFromInitializer(graph, *input_arg, shape_values, true)); + TEST_RETURN_IF_NOT(shape_values.size() == 1U); + TEST_RETURN_IF_NOT(shape_values[0] == 24); + } + } + } + } + + return Status::OK(); + }; + + std::vector opset_candidates{10, 11, 12, 13, 14, 15}; + for (auto opset : opset_candidates) { + auto build_test_case = [&](ModelTestBuilder& builder) { + std::vector> shape_input_shape; + shape_input_shape.reserve(4); + shape_input_shape.push_back("attention_mask1_dim0"); + shape_input_shape.push_back(512); + shape_input_shape.push_back(24); + shape_input_shape.push_back(64); + + auto* shape_input_arg = builder.MakeSymbolicInput(shape_input_shape); + auto* shape_out_arg = builder.MakeIntermediate(); + // Shape before opset 15 have such schema, the test schema did not cover opset 15. + builder.AddNode("Shape", {shape_input_arg}, {shape_out_arg}); + + auto* indices_input_arg = builder.MakeScalarInitializer(0); + auto* gather_out_arg = builder.MakeOutput(); + builder.AddNode("Gather", {shape_out_arg, indices_input_arg}, {gather_out_arg}) + .AddAttribute("axis", static_cast(0)); + + auto* indices_input_arg_1 = builder.MakeInitializer({1}, {2}); + auto* gather_out_arg_1 = builder.MakeOutput(); + builder.AddNode("Gather", {shape_out_arg, indices_input_arg_1}, {gather_out_arg_1}) + .AddAttribute("axis", static_cast(0)); + }; + + const logging::Logger* logger = &logging::LoggingManager::DefaultLogger(); + InlinedHashSet compatible_eps; + std::unique_ptr e = std::make_unique(CPUExecutionProviderInfo()); + std::unique_ptr transformer = std::make_unique(compatible_eps); + ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, opset, *logger, std::move(transformer), + TransformerLevel::Level1, 1, + pre_graph_checker, post_graph_checker)); + } +} + +TEST(ShapeOptimizerTests, ConcreteDimUsedBySlice) { + /* + [attention_mask1_dim0,24,512,512] + | + Dropout + / \ + [attention_mask1_dim0,24,512,512] [attention_mask1_dim0,24,512,512] + | | + Shape | + | | + [4] | + / \ | + Slice Slice | + | | | + [1]: (512,) [1]: (512,) | + | | | + Squeeze Squeeze | + | | | + [1]: -1 Unsqueeze Unsqueeze / + \ \ / / + ConcatTraining / + | / + | / + [3]: (-1, 512, 512) / + \ / + Reshape + | + */ + + std::vector slice_output_names; + auto pre_graph_checker = [&slice_output_names](Graph& graph) -> Status { + auto op_to_count = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_to_count["Dropout"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Slice"] == 2); + TEST_RETURN_IF_NOT(op_to_count["Squeeze"] == 2); + TEST_RETURN_IF_NOT(op_to_count["Unsqueeze"] == 2); + TEST_RETURN_IF_NOT(op_to_count["com.microsoft.ConcatTraining"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Shape"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Reshape"] == 1); + + slice_output_names.clear(); + for (auto& node : graph.Nodes()) { + if (node.OpType().compare("Slice") == 0) { + slice_output_names.push_back(node.OutputDefs()[0]->Name()); + } + } + + return Status::OK(); + }; + + auto post_graph_checker = [&slice_output_names](Graph& graph) -> Status { + auto op_to_count = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_to_count["Dropout"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Slice"] == 0); + TEST_RETURN_IF_NOT(op_to_count["Squeeze"] == 2); + TEST_RETURN_IF_NOT(op_to_count["Unsqueeze"] == 2); + TEST_RETURN_IF_NOT(op_to_count["com.microsoft.ConcatTraining"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Shape"] == 0); + TEST_RETURN_IF_NOT(op_to_count["Reshape"] == 1); + + for (auto slice_output_name : slice_output_names) { + auto input_arg = graph.GetNodeArg(slice_output_name); + TEST_RETURN_IF_NOT(input_arg != nullptr); + InlinedVector shape_values; + // Try to parse int64 type constant initializers. + TEST_RETURN_IF_NOT(optimizer_utils::AppendTensorFromInitializer(graph, *input_arg, shape_values, true)); + TEST_RETURN_IF_NOT(shape_values.size() == 1U); + TEST_RETURN_IF_NOT(shape_values[0] == 512); + } + + return Status::OK(); + }; + + std::vector opset_candidates{10, 11, 12, 13, 14, 15}; + for (auto opset : opset_candidates) { + auto build_test_case = [&](ModelTestBuilder& builder) { + std::vector> dropout_input_shape; + dropout_input_shape.reserve(4); + dropout_input_shape.push_back("attention_mask1_dim0"); + dropout_input_shape.push_back(24); + dropout_input_shape.push_back(512); + dropout_input_shape.push_back(512); + + auto* dropout_input_arg = builder.MakeSymbolicInput(dropout_input_shape); + auto* dropout_out_arg = builder.MakeIntermediate(); + auto* mask_out_arg = builder.MakeIntermediate(); + constexpr float ratio = 0.10000000149011612f; + if (opset < 12) { + builder.AddNode("Dropout", {dropout_input_arg}, {dropout_out_arg, mask_out_arg}) + .AddAttribute("ratio", ratio); + } else { + auto* ratio_input_arg = builder.MakeScalarInitializer(ratio); + auto* mode_input_arg = builder.MakeInitializerBool({}, std::vector{true}); + builder.AddNode("Dropout", {dropout_input_arg, ratio_input_arg, mode_input_arg}, + {dropout_out_arg, mask_out_arg}); + } + + auto* shape_out_arg = builder.MakeIntermediate(); + // Shape before opset 15 have such schema, the test schema did not cover opset 15. + builder.AddNode("Shape", {dropout_out_arg}, {shape_out_arg}); + + // Slice after opset 1 have such schema. + auto* slice_out_arg = builder.MakeIntermediate(); + auto* starts_input_arg = builder.MakeInitializer({1}, {-2}); + auto* ends_input_arg = builder.MakeInitializer({1}, {-1}); + auto* axes_input_arg = builder.MakeInitializer({1}, {0}); + builder.AddNode("Slice", {shape_out_arg, starts_input_arg, ends_input_arg, axes_input_arg}, {slice_out_arg}); + + auto* starts_input_arg_1 = builder.MakeInitializer({1}, {-1}); + auto* ends_input_arg_1 = builder.MakeInitializer({1}, {9223372036854775807}); + auto* axes_input_arg_1 = builder.MakeInitializer({1}, {0}); + auto* slice_out_arg_1 = builder.MakeIntermediate(); + builder.AddNode("Slice", {shape_out_arg, starts_input_arg_1, ends_input_arg_1, axes_input_arg_1}, + {slice_out_arg_1}); + + auto* squeeze_out_arg = builder.MakeIntermediate(); + auto* squeeze_out_arg_1 = builder.MakeIntermediate(); + const std::vector squeeze_axes{0}; + if (opset < 13) { + builder.AddNode("Squeeze", {slice_out_arg}, {squeeze_out_arg}).AddAttribute("axes", squeeze_axes); + builder.AddNode("Squeeze", {slice_out_arg_1}, {squeeze_out_arg_1}).AddAttribute("axes", squeeze_axes); + } else { + auto* squeeze_axes_input_arg = builder.MakeInitializer({1}, squeeze_axes); + builder.AddNode("Squeeze", {slice_out_arg, squeeze_axes_input_arg}, {squeeze_out_arg}); + auto* squeeze_axes_input_arg_1 = builder.MakeInitializer({1}, squeeze_axes); + builder.AddNode("Squeeze", {slice_out_arg_1, squeeze_axes_input_arg_1}, {squeeze_out_arg_1}); + } + + auto* unsqueeze_out_arg = builder.MakeIntermediate(); + auto* unsqueeze_out_arg_1 = builder.MakeIntermediate(); + const std::vector unsqueeze_axes{0}; + if (opset < 13) { + builder.AddNode("Unsqueeze", {squeeze_out_arg}, {unsqueeze_out_arg}).AddAttribute("axes", unsqueeze_axes); + builder.AddNode("Unsqueeze", {squeeze_out_arg_1}, {unsqueeze_out_arg_1}).AddAttribute("axes", unsqueeze_axes); + } else { + auto* unsqueeze_axes_input_arg = builder.MakeInitializer({1}, unsqueeze_axes); + builder.AddNode("Unsqueeze", {squeeze_out_arg, unsqueeze_axes_input_arg}, {unsqueeze_out_arg}); + auto* unsqueeze_axes_input_arg_1 = builder.MakeInitializer({1}, unsqueeze_axes); + builder.AddNode("Unsqueeze", {squeeze_out_arg_1, unsqueeze_axes_input_arg_1}, {unsqueeze_out_arg_1}); + } + + auto* concat_training_out_arg = builder.MakeIntermediate(); + auto* concat_input_arg = builder.MakeInitializer({1}, {-1}); + builder.AddNode("ConcatTraining", {concat_input_arg, unsqueeze_out_arg, unsqueeze_out_arg_1}, + {concat_training_out_arg}, kMSDomain) + .AddAttribute("axis", static_cast(0)); + + auto* reshape_out_arg = builder.MakeOutput(); + builder.AddNode("Reshape", {dropout_out_arg, concat_training_out_arg}, {reshape_out_arg}); + }; + + const logging::Logger* logger = &logging::LoggingManager::DefaultLogger(); + InlinedHashSet compatible_eps; + std::unique_ptr e = std::make_unique(CPUExecutionProviderInfo()); + std::unique_ptr transformer = std::make_unique(compatible_eps); + ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, opset, *logger, std::move(transformer), + TransformerLevel::Level1, 1, + pre_graph_checker, post_graph_checker)); + } +} + +TEST(ShapeOptimizerTests, ConcreteDimUsedByGatherSlice) { + /* + [attention_mask1_dim0,512,1536] [4]: (0, 0, 24, -1) + \ / + Reshape + / + [attention_mask1_dim0,512,24,64] + | \ + Shape Transpose + | | + [4] [attention_mask1_dim0,24,512,64] + / \ \ + Gather Slice \ + | | \ + []: (512,) [1]: (64,) | + | | | + | Squeeze | + | | | + [1]: -1 Unsqueeze Unsqueeze / + \ \ / / + ConcatTraining / + | / + | / + [3]: (-1, 512, 64) / + \ / + Reshape + | + [] means a shape for scalar. + */ + + std::string gather_output_name, slice_output_name; + auto pre_graph_checker = [&](Graph& graph) -> Status { + auto op_to_count = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_to_count["Shape"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Transpose"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Gather"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Slice"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Squeeze"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Unsqueeze"] == 2); + TEST_RETURN_IF_NOT(op_to_count["com.microsoft.ConcatTraining"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Reshape"] == 2); + + for (auto& node : graph.Nodes()) { + if (node.OpType().compare("Gather") == 0) { + gather_output_name = node.OutputDefs()[0]->Name(); + } else if (node.OpType().compare("Slice") == 0) { + slice_output_name = node.OutputDefs()[0]->Name(); + } + } + + return Status::OK(); + }; + + auto post_graph_checker = [&](Graph& graph) -> Status { + auto op_to_count = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_to_count["Shape"] == 0); + TEST_RETURN_IF_NOT(op_to_count["Transpose"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Gather"] == 0); + TEST_RETURN_IF_NOT(op_to_count["Slice"] == 0); + TEST_RETURN_IF_NOT(op_to_count["Squeeze"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Unsqueeze"] == 2); + TEST_RETURN_IF_NOT(op_to_count["com.microsoft.ConcatTraining"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Reshape"] == 2); + + auto gather_output_arg = graph.GetNodeArg(gather_output_name); + TEST_RETURN_IF_NOT(gather_output_arg != nullptr); + // Try to parse int64 type constant initializers. + InlinedVector gather_out_values; + TEST_RETURN_IF_NOT(optimizer_utils::AppendTensorFromInitializer(graph, *gather_output_arg, gather_out_values, true)); + TEST_RETURN_IF_NOT(gather_out_values.size() == 1U); + TEST_RETURN_IF_NOT(gather_out_values[0] == 512); + + auto slice_out_arg = graph.GetNodeArg(slice_output_name); + TEST_RETURN_IF_NOT(slice_out_arg != nullptr); + // Try to parse int64 type constant initializers. + InlinedVector slice_out_values; + TEST_RETURN_IF_NOT(optimizer_utils::AppendTensorFromInitializer(graph, *slice_out_arg, slice_out_values, true)); + TEST_RETURN_IF_NOT(slice_out_values.size() == 1U); + TEST_RETURN_IF_NOT(slice_out_values[0] == 64); + + return Status::OK(); + }; + + std::vector opset_candidates{10, 11, 12, 13, 14, 15}; + for (auto opset : opset_candidates) { + auto build_test_case = [&](ModelTestBuilder& builder) { + std::vector> reshape_input_shape; + reshape_input_shape.reserve(3); + reshape_input_shape.push_back("attention_mask1_dim0"); + reshape_input_shape.push_back(512); + reshape_input_shape.push_back(1536); + + auto* reshape_input_arg = builder.MakeSymbolicInput(reshape_input_shape); + auto* target_shape_input_arg = builder.MakeInitializer({4}, {0, 0, 24, -1}); + auto* reshape_out_arg = builder.MakeIntermediate(); + builder.AddNode("Reshape", {reshape_input_arg, target_shape_input_arg}, {reshape_out_arg}); + + auto* shape_out_arg = builder.MakeIntermediate(); + // Shape before opset 15 have such schema, the test schema did not cover opset 15. + builder.AddNode("Shape", {reshape_out_arg}, {shape_out_arg}); + auto* transpose_out_arg = builder.MakeIntermediate(); + builder.AddNode("Transpose", {reshape_out_arg}, {transpose_out_arg}) + .AddAttribute("perm", std::vector{0, 2, 1, 3}); + + auto* indices_input_arg = builder.MakeScalarInitializer(1); + auto* gather_out_arg = builder.MakeIntermediate(); + builder.AddNode("Gather", {shape_out_arg, indices_input_arg}, {gather_out_arg}) + .AddAttribute("axis", static_cast(0)); + + auto* starts_input_arg_1 = builder.MakeInitializer({1}, {-1}); + auto* ends_input_arg_1 = builder.MakeInitializer({1}, {9223372036854775807}); + auto* axes_input_arg_1 = builder.MakeInitializer({1}, {0}); + auto* slice_out_arg_1 = builder.MakeIntermediate(); + builder.AddNode("Slice", {shape_out_arg, starts_input_arg_1, ends_input_arg_1, axes_input_arg_1}, + {slice_out_arg_1}); + + auto* squeeze_out_arg_1 = builder.MakeIntermediate(); + const std::vector squeeze_axes{0}; + if (opset < 13) { + builder.AddNode("Squeeze", {slice_out_arg_1}, {squeeze_out_arg_1}).AddAttribute("axes", squeeze_axes); + } else { + auto* squeeze_axes_input_arg_1 = builder.MakeInitializer({1}, squeeze_axes); + builder.AddNode("Squeeze", {slice_out_arg_1, squeeze_axes_input_arg_1}, {squeeze_out_arg_1}); + } + + auto* unsqueeze_out_arg = builder.MakeIntermediate(); + auto* unsqueeze_out_arg_1 = builder.MakeIntermediate(); + const std::vector unsqueeze_axes{0}; + if (opset < 13) { + builder.AddNode("Unsqueeze", {gather_out_arg}, {unsqueeze_out_arg}).AddAttribute("axes", unsqueeze_axes); + builder.AddNode("Unsqueeze", {squeeze_out_arg_1}, {unsqueeze_out_arg_1}).AddAttribute("axes", unsqueeze_axes); + } else { + auto* unsqueeze_axes_input_arg = builder.MakeInitializer({1}, unsqueeze_axes); + builder.AddNode("Unsqueeze", {gather_out_arg, unsqueeze_axes_input_arg}, {unsqueeze_out_arg}); + auto* unsqueeze_axes_input_arg_1 = builder.MakeInitializer({1}, unsqueeze_axes); + builder.AddNode("Unsqueeze", {squeeze_out_arg_1, unsqueeze_axes_input_arg_1}, {unsqueeze_out_arg_1}); + } + + auto* concat_training_out_arg = builder.MakeIntermediate(); + auto* concat_input_arg = builder.MakeInitializer({1}, {-1}); + builder.AddNode("ConcatTraining", {concat_input_arg, unsqueeze_out_arg, unsqueeze_out_arg_1}, + {concat_training_out_arg}, kMSDomain) + .AddAttribute("axis", static_cast(0)); + + auto* reshape_out_arg_1 = builder.MakeOutput(); + builder.AddNode("Reshape", {transpose_out_arg, concat_training_out_arg}, {reshape_out_arg_1}); + }; + + const logging::Logger* logger = &logging::LoggingManager::DefaultLogger(); + InlinedHashSet compatible_eps; + std::unique_ptr e = std::make_unique(CPUExecutionProviderInfo()); + std::unique_ptr transformer = std::make_unique(compatible_eps); + ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, opset, *logger, std::move(transformer), + TransformerLevel::Level1, 1, + pre_graph_checker, post_graph_checker)); + } +} + +TEST(ShapeOptimizerTests, SymbolicDimUsedByGather_ConcreteDimUsedByGather) { + /* + [attention_mask1_dim0,512,1536] [4]: (0, 0, 24, -1) + \ / + Reshape + / + [attention_mask1_dim0,512,24,64] + | \ + Shape Transpose + | | + [4] [attention_mask1_dim0,24,512,64] + / | | + Gather Gather | + | | | + []: (attention_mask1_dim0,) [1]: (24,) | + | | | + | | | + | | / + Unsqueeze | [1]: -1 / + \ | / / + ConcatTraining / + | / + | / + [3]: (attention_mask1_dim0, 24, -1) / + \ / + Reshape + | + [] means a shape for scalar. + */ + auto pre_graph_checker = [&](Graph& graph) -> Status { + auto op_to_count = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_to_count["Shape"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Transpose"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Gather"] == 2); + TEST_RETURN_IF_NOT(op_to_count["Unsqueeze"] == 1); + TEST_RETURN_IF_NOT(op_to_count["com.microsoft.ConcatTraining"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Reshape"] == 2); + + return Status::OK(); + }; + + auto post_graph_checker = [&](Graph& graph) -> Status { + auto op_to_count = CountOpsInGraph(graph); + TEST_RETURN_IF_NOT(op_to_count["Shape"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Transpose"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Gather"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Unsqueeze"] == 1); + TEST_RETURN_IF_NOT(op_to_count["com.microsoft.ConcatTraining"] == 1); + TEST_RETURN_IF_NOT(op_to_count["Reshape"] == 2); + + for (auto& node : graph.Nodes()) { + if (node.OpType() == "Reshape") { + NodeArg* shape_input = node.MutableInputDefs()[1]; + auto p_output_node = node.OutputNodesBegin(); + const auto p_output_node_end = node.OutputNodesEnd(); + bool find_transpose = false; + while (p_output_node != p_output_node_end) { + const auto& output_node = *p_output_node; + if (output_node.OpType().compare("Transpose") == 0) { + find_transpose = true; + break; + } + ++p_output_node; + } + + if (find_transpose) { + // Ignore the first Reshape node. + continue; + } + + // Try to parse int64 type constant initializers. + InlinedVector shape_values; + TEST_RETURN_IF_NOT(!optimizer_utils::AppendTensorFromInitializer(graph, *shape_input, shape_values, true)); + TEST_RETURN_IF_NOT(graph.GetProducerNode( + node.MutableInputDefs()[1]->Name()) + ->OpType() + .compare("ConcatTraining") == 0); + } else if (node.OpType() == "ConcatTraining") { + NodeArg* shape_input = node.MutableInputDefs()[1]; + + // Try to parse int64 type constant initializers. + InlinedVector shape_values; + TEST_RETURN_IF_NOT(optimizer_utils::AppendTensorFromInitializer(graph, *shape_input, shape_values, true)); + TEST_RETURN_IF_NOT(shape_values.size() == 1U); + TEST_RETURN_IF_NOT(shape_values[0] == 24); + } + } + + return Status::OK(); + }; + + std::vector opset_candidates{10, 11, 12, 13, 14, 15}; + for (auto opset : opset_candidates) { + auto build_test_case = [&](ModelTestBuilder& builder) { + std::vector> reshape_input_shape; + reshape_input_shape.reserve(3); + reshape_input_shape.push_back("attention_mask1_dim0"); + reshape_input_shape.push_back(512); + reshape_input_shape.push_back(1536); + + auto* reshape_input_arg = builder.MakeSymbolicInput(reshape_input_shape); + auto* target_shape_input_arg = builder.MakeInitializer({4}, {0, 0, 24, -1}); + auto* reshape_out_arg = builder.MakeIntermediate(); + builder.AddNode("Reshape", {reshape_input_arg, target_shape_input_arg}, {reshape_out_arg}); + + auto* shape_out_arg = builder.MakeIntermediate(); + // Shape before opset 15 have such schema, the test schema did not cover opset 15. + builder.AddNode("Shape", {reshape_out_arg}, {shape_out_arg}); + auto* transpose_out_arg = builder.MakeIntermediate(); + builder.AddNode("Transpose", {reshape_out_arg}, {transpose_out_arg}) + .AddAttribute("perm", std::vector{0, 2, 1, 3}); + + auto* indices_input_arg = builder.MakeScalarInitializer(0); + auto* gather_out_arg = builder.MakeIntermediate(); + builder.AddNode("Gather", {shape_out_arg, indices_input_arg}, {gather_out_arg}) + .AddAttribute("axis", static_cast(0)); + + auto* indices_input_arg_1 = builder.MakeInitializer({1}, {2}); + auto* gather_out_arg_1 = builder.MakeIntermediate(); + builder.AddNode("Gather", {shape_out_arg, indices_input_arg_1}, {gather_out_arg_1}) + .AddAttribute("axis", static_cast(0)); + + auto* unsqueeze_out_arg = builder.MakeIntermediate(); + const std::vector unsqueeze_axes{0}; + if (opset < 13) { + builder.AddNode("Unsqueeze", {gather_out_arg}, {unsqueeze_out_arg}).AddAttribute("axes", unsqueeze_axes); + } else { + auto* unsqueeze_axes_input_arg = builder.MakeInitializer({1}, unsqueeze_axes); + builder.AddNode("Unsqueeze", {gather_out_arg, unsqueeze_axes_input_arg}, {unsqueeze_out_arg}); + } + + auto* concat_training_out_arg = builder.MakeIntermediate(); + auto* concat_input_arg = builder.MakeInitializer({1}, {-1}); + builder.AddNode("ConcatTraining", {unsqueeze_out_arg, gather_out_arg_1, concat_input_arg}, + {concat_training_out_arg}, kMSDomain) + .AddAttribute("axis", static_cast(0)); + + auto* reshape_out_arg_1 = builder.MakeOutput(); + builder.AddNode("Reshape", {transpose_out_arg, concat_training_out_arg}, {reshape_out_arg_1}); + }; + + const logging::Logger* logger = &logging::LoggingManager::DefaultLogger(); + InlinedHashSet compatible_eps; + std::unique_ptr e = std::make_unique(CPUExecutionProviderInfo()); + std::unique_ptr transformer = std::make_unique(compatible_eps); + ASSERT_STATUS_OK(TestGraphTransformer(build_test_case, opset, *logger, std::move(transformer), + TransformerLevel::Level1, 1, + pre_graph_checker, post_graph_checker)); + } +} + +// end of DISABLE_CONTRIB_OPS +#endif + +} // namespace test +} // namespace onnxruntime diff --git a/orttraining/orttraining/test/python/_test_helpers.py b/orttraining/orttraining/test/python/_test_helpers.py index 33dbe66b96069..a9a4c7b1cc2ef 100644 --- a/orttraining/orttraining/test/python/_test_helpers.py +++ b/orttraining/orttraining/test/python/_test_helpers.py @@ -349,7 +349,7 @@ def run_training_test_on_device_and_compare( expected_outputs=[], # noqa: B006 expected_grads=[], # noqa: B006 ): - repeats = 16 + repeats = 8 for _i in range(repeats): m = pt_model_builder_func() x = pt_model_inputs_generator() diff --git a/orttraining/orttraining/test/python/how_to_add_ortmodule_ci_pipeline_tests.md b/orttraining/orttraining/test/python/how_to_add_ortmodule_ci_pipeline_tests.md index 32fc83b341174..3fbb6a819ab3c 100644 --- a/orttraining/orttraining/test/python/how_to_add_ortmodule_ci_pipeline_tests.md +++ b/orttraining/orttraining/test/python/how_to_add_ortmodule_ci_pipeline_tests.md @@ -5,7 +5,7 @@ This is a simple guide on how the ortmodule CI pipeline works and how it can be ### The Pipeline The ortmodule CI pipeline is intended for running tests related to the ```ORTModule``` class. -The pipeline ```yml``` file is defined in [```tools/ci_build/github/azure-pipelines/orttraining-linux-gpu-ortmodule-test-ci-pipeline.yml```](https://github.com/microsoft/onnxruntime/blob/thiagofc/ortmodule-api/tools/ci_build/github/azure-pipelines/orttraining-linux-gpu-ortmodule-test-ci-pipeline.yml). +The pipeline ```yml``` file is defined in [```tools/ci_build/github/azure-pipelines/orttraining-linux-gpu-test-ci-pipeline.yml```](https://github.com/microsoft/onnxruntime/blob/thiagofc/ortmodule-api/tools/ci_build/github/azure-pipelines/orttraining-linux-gpu-test-ci-pipeline.yml). The pipeline runs on every pull request commit to the branch ```thiagofc/ortmodule```. ## Running Locally @@ -41,4 +41,4 @@ Follow the below steps to add new ortmodule tests that will run in this pipeline > **Note**: If the test requires multiple ```run_subprocess()``` calls, restructure the test file(s) such that they have a single entry point. -Once the above has been tried and tested, submit a pull request and the tests should be executed in the ortmodule ci pipeline. Make sure to search for ```'Running: Dummy ortmodule tests'``` in the pipeline logs to ensure that the newly added tests were successfully run in the pipeline. \ No newline at end of file +Once the above has been tried and tested, submit a pull request and the tests should be executed in the ortmodule ci pipeline. Make sure to search for ```'Running: Dummy ortmodule tests'``` in the pipeline logs to ensure that the newly added tests were successfully run in the pipeline. diff --git a/orttraining/orttraining/test/python/orttraining_ortmodule_distributed_tests.py b/orttraining/orttraining/test/python/orttraining_ortmodule_distributed_tests.py index 08b304cb0e3b2..80db8cd9f17a4 100644 --- a/orttraining/orttraining/test/python/orttraining_ortmodule_distributed_tests.py +++ b/orttraining/orttraining/test/python/orttraining_ortmodule_distributed_tests.py @@ -70,6 +70,19 @@ def run_ortmodule_fairscale_sharded_optimizer_tests(cwd, log, data_dir): run_subprocess(command, cwd=cwd, log=log).check_returncode() +def run_distributed_cache_test(cwd, log): + log.debug("Running: ORTModule Cache Test") + + command = [ + "torchrun", + "--nproc_per_node", + "2", + "orttraining_test_ortmodule_cache.py", + ] + + run_subprocess(command, cwd=cwd, log=log).check_returncode() + + def main(): args = parse_arguments() cwd = args.cwd @@ -82,6 +95,8 @@ def main(): run_ortmodule_deepspeed_pipeline_parallel_tests(cwd, log) run_ortmodule_fairscale_sharded_optimizer_tests(cwd, log, args.mnist) + + run_distributed_cache_test(cwd, log) return 0 diff --git a/orttraining/orttraining/test/python/orttraining_ortmodule_tests.py b/orttraining/orttraining/test/python/orttraining_ortmodule_tests.py index d97b3b5e2b6a2..0e7e9d23ee627 100644 --- a/orttraining/orttraining/test/python/orttraining_ortmodule_tests.py +++ b/orttraining/orttraining/test/python/orttraining_ortmodule_tests.py @@ -4,6 +4,7 @@ import argparse import logging +import os import sys from _test_commons import run_subprocess @@ -150,18 +151,18 @@ def run_hooks_tests(cwd, log): run_subprocess(command, cwd=cwd, log=log).check_returncode() -def run_pytorch_export_contrib_ops_tests(cwd, log): - log.debug("Running: PyTorch Export Contrib Ops Tests") +def run_utils_tests(cwd, log): + log.debug("Running: Utils tests") - command = [sys.executable, "-m", "pytest", "-sv", "test_pytorch_export_contrib_ops.py"] + command = [sys.executable, "-m", "pytest", "-sv", "orttraining_test_utilities.py"] run_subprocess(command, cwd=cwd, log=log).check_returncode() -def run_lstm_training_op_tests(cwd, log): - log.debug("Running: LSTM Training Ops Tests") +def run_pytorch_export_contrib_ops_tests(cwd, log): + log.debug("Running: PyTorch Export Contrib Ops Tests") - command = [sys.executable, "-m", "pytest", "-sv", "orttraining_test_lstm.py"] + command = [sys.executable, "-m", "pytest", "-sv", "test_pytorch_export_contrib_ops.py"] run_subprocess(command, cwd=cwd, log=log).check_returncode() @@ -178,15 +179,17 @@ def main(): run_ortmodule_poc_net(cwd, log, no_cuda=False, data_dir=args.mnist) - run_ortmodule_poc_net(cwd, log, no_cuda=True, data_dir=args.mnist) + if os.getenv("ORTMODULE_DISABLE_CPU_TRAINING_TEST", "0") != "1": + run_ortmodule_poc_net(cwd, log, no_cuda=True, data_dir=args.mnist) run_ortmodule_hf_bert_for_sequence_classification_from_pretrained( cwd, log, no_cuda=False, data_dir=args.bert_data, transformers_cache=args.transformers_cache ) - run_ortmodule_hf_bert_for_sequence_classification_from_pretrained( - cwd, log, no_cuda=True, data_dir=args.bert_data, transformers_cache=args.transformers_cache - ) + if os.getenv("ORTMODULE_DISABLE_CPU_TRAINING_TEST", "0") != "1": + run_ortmodule_hf_bert_for_sequence_classification_from_pretrained( + cwd, log, no_cuda=True, data_dir=args.bert_data, transformers_cache=args.transformers_cache + ) run_ortmodule_torch_lightning(cwd, log, args.mnist) @@ -202,13 +205,13 @@ def main(): run_hooks_tests(cwd, log) + run_utils_tests(cwd, log) + run_experimental_gradient_graph_tests(cwd, log) # TODO(bmeswani): Enable this test once it can run with latest pytorch # run_pytorch_export_contrib_ops_tests(cwd, log) - run_lstm_training_op_tests(cwd, log) - return 0 diff --git a/orttraining/orttraining/test/python/orttraining_test_checkpoint_storage.py b/orttraining/orttraining/test/python/orttraining_test_checkpoint_storage.py index 77ba7c41c1268..71d13fdcfd290 100644 --- a/orttraining/orttraining/test/python/orttraining_test_checkpoint_storage.py +++ b/orttraining/orttraining/test/python/orttraining_test_checkpoint_storage.py @@ -159,7 +159,7 @@ def test_checkpoint_storage_saved_dict_matches_loaded(checkpoint_storage_test_pa ) def test_checkpoint_storage_saving_non_supported_types_fails(checkpoint_storage_test_parameterized_setup): to_save = checkpoint_storage_test_parameterized_setup - with pytest.raises(Exception): + with pytest.raises(Exception): # noqa: B017 _checkpoint_storage.save(to_save, pytest.checkpoint_path) @@ -233,7 +233,7 @@ def test_checkpoint_storage_saving_and_loading_empty_dictionaries_succeeds(check def test_checkpoint_storage_load_file_that_does_not_exist_fails(checkpoint_storage_test_setup): - with pytest.raises(Exception): + with pytest.raises(Exception): # noqa: B017 _checkpoint_storage.load(pytest.checkpoint_path) diff --git a/orttraining/orttraining/test/python/orttraining_test_dort.py b/orttraining/orttraining/test/python/orttraining_test_dort.py index ae6d1ac3c46f4..88d9c00984d3e 100644 --- a/orttraining/orttraining/test/python/orttraining_test_dort.py +++ b/orttraining/orttraining/test/python/orttraining_test_dort.py @@ -4,10 +4,13 @@ import unittest import torch +import torch._dynamo +import torch.onnx._internal.exporter from torch import nn from torch.nn import functional as F +from torch.utils import _pytree -from onnxruntime.training.torchdynamo.register_backend import aot_ort, ort +from onnxruntime.training.torchdynamo.register_backend import aot_ort, dynamic_aot_ort, make_aot_ort, ort class TestTorchDynamoOrt(unittest.TestCase): @@ -24,11 +27,11 @@ def test_elementwise_model(self): def run_elementwise_model(): # A function to test DORT. def elementwise_model(tensor_x: torch.Tensor): - tensor_w = tensor_x.relu() + tensor_w = tensor_x.sigmoid() tensor_y = tensor_w * tensor_w + 1.5 tensor_z = tensor_y + tensor_x tensor_p = tensor_z * tensor_x - tensor_q = tensor_p.relu() + tensor_q = tensor_p.sigmoid() return tensor_q @torch._dynamo.optimize(aot_ort) @@ -55,6 +58,141 @@ def run(fun, list_x): for _ in range(5): run_elementwise_model() + def test_dynamo_shape_model(self): + torch._dynamo.reset() + """Test DORT with a pure function.""" + + def run_elementwise_model(): + # A function to test DORT. + def elementwise_model(tensor_x: torch.Tensor): + tensor_y = tensor_x.sigmoid() + tensor_z = tensor_y + tensor_x + tensor_p = tensor_z * tensor_x + tensor_q = tensor_p.sigmoid() + return tensor_q + + # This function should only generate one graph and execute + # it for all inputs. + # With dynamic_shape=True, Dynamo sends FX graphs with dynamic + # shapes (e.g., batch size is a symbol "batch" instead of a fixed + # number) to OrtBackend.compile(...). + @torch._dynamo.optimize(dynamic_aot_ort, dynamic=True) + def optimized_elementwise_model(tensor_x: torch.Tensor): + return elementwise_model(tensor_x) + + def run(fun, seed: torch.Tensor): + tensor_x = seed.detach().clone().requires_grad_() + tensor_y = fun(tensor_x) + tensor_y.sum().backward() + return tensor_x, tensor_y, tensor_x.grad + + # Dimension changed. + for shape in [(2, 3), (3, 4)]: + seed = torch.rand(shape) + # Baseline. + tensor_x, tensor_y, tensor_x_grad = run(elementwise_model, seed) + # ORT result. + tensor_x_new, tensor_y_new, tensor_x_grad_new = run(optimized_elementwise_model, seed) + + torch.testing.assert_close(tensor_x, tensor_x_new) + torch.testing.assert_close(tensor_y, tensor_y_new) + torch.testing.assert_close(tensor_x_grad, tensor_x_grad_new) + + # Rank changed. + for shape in [(1,), (2,), (2, 3), (2, 3, 4)]: + seed = torch.rand(shape) + # Baseline. + tensor_x, tensor_y, tensor_x_grad = run(elementwise_model, seed) + # ORT result. + tensor_x_new, tensor_y_new, tensor_x_grad_new = run(optimized_elementwise_model, seed) + + torch.testing.assert_close(tensor_x, tensor_x_new) + torch.testing.assert_close(tensor_y, tensor_y_new) + torch.testing.assert_close(tensor_x_grad, tensor_x_grad_new) + + run_elementwise_model() + + def test_elementwise_model_with_dynamic_shapes_and_complicated_output_schema(self): + torch._dynamo.reset() + + def run_elementwise_model(): + # A function to test DORT. + def elementwise_model(tensor_x: torch.Tensor): + tensor_y = tensor_x.sigmoid() + tensor_z = tensor_y + tensor_x + tensor_p = tensor_z * tensor_x + tensor_q = tensor_p.sigmoid() + return (tensor_q, (tensor_y, tensor_z)) + + local_aot_ort, ort_backend = make_aot_ort(dynamic=True) + cached = ort_backend._all_ort_execution_info.execution_info_per_graph_module + # Before compilation, no graph is generated. + assert len(cached) == 0 + + # This function should only generate one graph and execute + # it for all inputs. + # With dynamic_shape=True, Dynamo sends FX graphs with dynamic + # shapes (e.g., batch size is a symbol "batch" instead of a fixed + # number) to OrtBackend.compile(...). + @torch._dynamo.optimize(local_aot_ort, dynamic=True) + def optimized_elementwise_model(tensor_x: torch.Tensor): + return elementwise_model(tensor_x) + + def run(fun, seed: torch.Tensor): + tensor_x = seed.detach().clone().requires_grad_() + result = fun(tensor_x) + forward_outputs, _ = _pytree.tree_flatten(result) + result[0].sum().backward() + return (tensor_x, *forward_outputs, tensor_x.grad) + + # Dimension changed. + for shape in [(2, 3), (3, 4)]: + seed = torch.rand(shape) + # Baseline. + baseline_tensors = run(elementwise_model, seed) + # ORT result. + tensors = run(optimized_elementwise_model, seed) + + for tensor, baseline_tensor in zip(tensors, baseline_tensors): + torch.testing.assert_close(tensor, baseline_tensor) + + assert ( + len(cached.keys()) == 2 + ), "Should only see two GraphModules so far. One for forward and the other one for backward." + for value in cached.values(): + assert len(value) == 1, ( + "One GraphModule should only be mapped to one ONNX model since " + "dynamic shape is enabled and input tensor's rank is unchanged." + ) + + # Rank changed. + for shape in [(1,), (2,), (2, 3), (2, 3, 4)]: + seed = torch.rand(shape) + # Baseline. + baseline_tensors = run(elementwise_model, seed) + # ORT result. + tensors = run(optimized_elementwise_model, seed) + + for tensor, baseline_tensor in zip(tensors, baseline_tensors): + torch.testing.assert_close(tensor, baseline_tensor) + + # 4 GraphModule's respectively for + # - (1,) + # - (2,) + # - (2, 3), (3, 4) + # - (2, 3, 4) + # Because (1,) is treated as a special dimension in Dynamo, + # we can NOT merge (1,) and (2,). More specifically, their GraphModule's + # are hashed to different values. + # Another 4 GraphModule's for the corresponding backward passes. + assert len(cached.keys()) == 8 + for value in cached.values(): + # When dynamic shape is enabled, there should be only one ONNX model + # for inputs with the same rank. + assert len(value) == 1 + + run_elementwise_model() + def test_elementwise_model_for_inference(self): torch._dynamo.reset() @@ -118,6 +256,58 @@ def run(fun, list_x): run_to_copy() + def test_aten_full(self): + torch._dynamo.reset() + + def run_no_input_model(): + # A function to test. + def no_input_model(): + return torch.ops.aten.full([2, 3], 1.5) + + @torch._dynamo.optimize(aot_ort) + def optimized_no_input_model(): + return no_input_model() + + def run(fun): + tensor_x = fun() + return tensor_x + + # Baseline. + tensor_x = run(no_input_model) + # ORT result. + tensor_x_new = run(optimized_no_input_model) + + torch.testing.assert_close(tensor_x, tensor_x_new) + + for _ in range(5): + run_no_input_model() + + def test_aten_full_with_device(self): + torch._dynamo.reset() + + def run_no_input_model(): + # A function to test. + def no_input_model(): + return torch.ops.aten.full([2, 3], 1.5, device="cpu") + + @torch._dynamo.optimize(aot_ort) + def optimized_no_input_model(): + return no_input_model() + + def run(fun): + tensor_x = fun() + return tensor_x + + # Baseline. + tensor_x = run(no_input_model) + # ORT result. + tensor_x_new = run(optimized_no_input_model) + + torch.testing.assert_close(tensor_x, tensor_x_new) + + for _ in range(5): + run_no_input_model() + def test_mnist_model(self): torch._dynamo.reset() """Test DORT with a simple nn.Module.""" diff --git a/orttraining/orttraining/test/python/orttraining_test_dort_custom_ops.py b/orttraining/orttraining/test/python/orttraining_test_dort_custom_ops.py new file mode 100644 index 0000000000000..c2a6ed504a206 --- /dev/null +++ b/orttraining/orttraining/test/python/orttraining_test_dort_custom_ops.py @@ -0,0 +1,200 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import os +import sys +import unittest + +import onnxscript +import torch +import torch._dynamo +from functorch.compile import min_cut_rematerialization_partition +from torch._dynamo.backends.common import aot_autograd +from torch.library import Library + +import onnxruntime +from onnxruntime.training.torchdynamo.ort_backend import OrtBackend + +# Dummy operator set to map aten::mul.Tensor to test.customop::CustomOpOne +# in ONNX model executed by DORT. +# Print the output of to_model_proto in ort_backend.py for the generated +# ONNX model. +custom_opset = onnxscript.values.Opset(domain="test.customop", version=1) + + +# Exporter for torch.ops.aten.mul.Tensor. +@onnxscript.script(custom_opset) +def custom_exporter_for_aten_add_Tensor(x, y): + # This function represents an ONNX function. Register below + # set this function as the FX-to-ONNX exporter of "aten::mul.Tensor". + return custom_opset.CustomOpOne(x, y) + + +# Exporter for torch.ops.foo.bar.default. +@onnxscript.script(custom_opset) +def custom_exporter_for_foo_bar_default(x): + # This function represents an ONNX function. Register below + # set this function as the FX-to-ONNX exporter of "aten::mul.Tensor". + return custom_opset.CustomOpOne(x, x) + + +class TestTorchDynamoOrtCustomOp(unittest.TestCase): + """Containers of custom op lib test for TorchDynamo ORT (DORT) backend.""" + + def setUp(self): + # Make computation deterministic. + torch.manual_seed(42) + + @staticmethod + def search_for_custom_op_library_path(): + """Searches for the path of the custom op library file. + + The returned path may change depending on the platform of the CI. + + Returns: + str: The path of the custom op library file. + + Raises: + FileNotFoundError: If the custom op library file is not found + in the expected location. + """ + if sys.platform.startswith("win"): + shared_library = "custom_op_library.dll" + if not os.path.exists(shared_library): + raise FileNotFoundError(f"Unable to find '{shared_library}'") + + elif sys.platform.startswith("darwin"): + shared_library = "libcustom_op_library.dylib" + if not os.path.exists(shared_library): + raise FileNotFoundError(f"Unable to find '{shared_library}'") + + else: + shared_library = "./libcustom_op_library.so" + if not os.path.exists(shared_library): + raise FileNotFoundError(f"Unable to find '{shared_library}'") + + return shared_library + + @staticmethod + def create_onnxruntime_session_options(): + """Creates an ONNXRuntime session options object. + + The returned option object is configured to enable custom + operator's implementation visible in ONNXRuntime. + + Returns: + onnxruntime.SessionOptions: An ONNXRuntime session options object. + """ + custom_op_library_path = TestTorchDynamoOrtCustomOp.search_for_custom_op_library_path() + session_options = onnxruntime.SessionOptions() + session_options.register_custom_ops_library(custom_op_library_path) + return session_options + + def test_export_aten_mul_as_onnx_custom_op_and_run_ort(self): + """A Custom Operator Test for DORT + + In this test, aten.mul.Tensor is exported to test.customop::CustomOpOne and + executed by ORT. + """ + torch._dynamo.reset() + + # Register custom_exporter_for_aten_add_Tensor as "aten::mul.Tensor"'s + # exporter. + # Use custom_exporter_for_aten_add_Tensor.to_function_proto() to see + # the sub-graph representing "aten::mul.Tensor". + onnx_registry = torch.onnx.OnnxRegistry() + onnx_registry.register_op( + function=custom_exporter_for_aten_add_Tensor, + namespace="aten", + op_name="mul", + overload="Tensor", + ) + + # In order to use custom exporting function inside PyTorch-to-ONNX exporter used in DORT, create executor of ONNX model with custom `onnx_registry`. + ort_backend = OrtBackend( + ep="CPUExecutionProvider", + session_options=TestTorchDynamoOrtCustomOp.create_onnxruntime_session_options(), + onnx_exporter_options=torch.onnx.ExportOptions(dynamic_shapes=True, onnx_registry=onnx_registry), + ) + + # Wrap ORT executor as a Dynamo backend. + aot_ort = aot_autograd( + fw_compiler=ort_backend, + partition_fn=min_cut_rematerialization_partition, + decompositions=ort_backend.resolved_onnx_exporter_options.decomposition_table, + ) + + def one_mul(tensor_x: torch.Tensor, tensor_y: torch.Tensor): + return torch.mul(tensor_x, tensor_y) + + opt_mul = torch._dynamo.optimize(aot_ort)(one_mul) + + tensor_x = torch.ones((64, 64), dtype=torch.float32) + tensor_y = torch.ones((64, 64), dtype=torch.float32) + + for _ in range(5): + result_ref = torch.add(tensor_x, tensor_y) + result_ort = opt_mul(tensor_x, tensor_y) + torch.testing.assert_close(result_ref, result_ort) + + def test_export_pytorch_custom_op_to_onnx_custom_op_and_run_ort(self): + """A Custom Operator Test. + + In this test, torch.ops.foo.bar.default is exported to + test.customop::CustomOpOne and executed by ORT. + + See test_export_aten_mul_as_onnx_custom_op_and_run_ort for mapping + official PyTorch operator (e.g., aten.mul.Tensor) to ONNX custom operator. + """ + torch._dynamo.reset() + + foo_lib = Library("foo", "DEF") + bar_name = foo_lib.define("bar(Tensor self) -> Tensor") + + def bar_impl(self: torch.Tensor) -> torch.Tensor: + # foo::bar.default will be mapped to test.customop::CustomOpOne. + # In ORT, test.customop::CustomOpOne is simply an Add for testing. + return torch.add(self, self) + + foo_lib.impl(bar_name, bar_impl, "CompositeExplicitAutograd") + + # Ask exporter to map "torch.ops.foo.bar" to + # custom_exporter_for_foo_bar_default. + onnx_registry = torch.onnx.OnnxRegistry() + onnx_registry.register_op( + function=custom_exporter_for_foo_bar_default, + namespace="foo", + op_name="bar", + ) + + # Create executor of ONNX model. + ort_backend = OrtBackend( + ep="CPUExecutionProvider", + session_options=TestTorchDynamoOrtCustomOp.create_onnxruntime_session_options(), + onnx_exporter_options=torch.onnx.ExportOptions(onnx_registry=onnx_registry), + ) + # Allow torch.ops.foo.bar.default to be sent to DORT. + # _support_dict tells Dynamo which ops to sent to DORT. + ort_backend._supported_ops._support_dict.add(torch.ops.foo.bar.default) + + # Wrap ORT executor as a Dynamo backend. + aot_ort = aot_autograd( + fw_compiler=ort_backend, + partition_fn=min_cut_rematerialization_partition, + decompositions=ort_backend.resolved_onnx_exporter_options.decomposition_table, + ) + + def one_foo(tensor_x: torch.Tensor): + return torch.ops.foo.bar(tensor_x) + + opt_foo = torch._dynamo.optimize(aot_ort)(one_foo) + + for _ in range(5): + x = torch.randn(3, 2, device="cpu") + expected = torch.ops.foo.bar(x) + actual = opt_foo(x) + torch.testing.assert_close(expected, actual) + + +if __name__ == "__main__": + unittest.main() diff --git a/orttraining/orttraining/test/python/orttraining_test_gru.py b/orttraining/orttraining/test/python/orttraining_test_gru.py new file mode 100644 index 0000000000000..fcb7e13b1694f --- /dev/null +++ b/orttraining/orttraining/test/python/orttraining_test_gru.py @@ -0,0 +1,720 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import os +import tempfile + +import numpy as np +import onnx +import pytest +from onnx import TensorProto, helper + +import onnxruntime as ort + + +def sigmoid(z): + """Computes the sigmoid of the given numpy array.""" + return 1 / (1 + np.exp(-z)) + + +class GRU: + """GRU utility class for testing. + + This class exposes four copmutation methods: + - forward_np: computes the GRU forward pass using numpy + - forward_ort: computes the GRU forward pass using ORT + - backward_np: computes the GRU backward pass using numpy + - backward_ort: computes the GRU backward pass using ORT + and two onnx model generation methods: + - forward_graph: generates the GRU forward onnx graph (with the GRUTraining node) + - backward_graph: generates the GRU backward onnx graph (with the GRUGrad node) + """ + + def __init__(self, sequence_length, batch_size, input_size, hidden_size, linear_before_reset): + """Initializes the GRU class. + + Args: + sequence_length (int): the sequence length + batch_size (int): the batch size + input_size (int): the input size + hidden_size (int): the hidden size + """ + self._sequence_length = sequence_length + self._batch_size = batch_size + self.input_size = input_size + self._hidden_size = hidden_size + self._num_directions = 1 + self._linear_before_reset = linear_before_reset + self._forward_model = None + self._backward_model = None + + def forward_np( + self, + inputs, + weights, + recurrence_weights, + bias=None, + initial_hidden_state=None, + ): + """Computes the GRU forward pass using numpy. + + The computation follows the following rules: + - zt = sigmoid(Xt*(Wz^T) + Ht-1*(Rz^T) + Wbz + Rbz) + - rt = sigmoid(Xt*(Wr^T) + Ht-1*(Rr^T) + Wbr + Rbr) + - ht = tanh(Xt*(Wh^T) + (rt (.) Ht-1)*(Rh^T) + Rbh + Wbh) + - Ht = (1 - zt) (.) ht + zt (.) Ht-1 + + + Args: + input (np.array): the input tensor of shape (sequence_length, batch_size, input_size) + weights (np.array): the weight tensor of shape + (num_directions, 3 * hidden_size, input_size) + recurrence_weights (np.array): the recurrence weight tensor of shape + (num_directions, 3 * hidden_size, hidden_size) + bias (np.array, optional): the bias tensor of shape + (num_directions, 6 * hidden_size). Defaults to None. + H0 (np.array, optional): the initial hidden state tensor of shape + (num_directions, batch_size, hidden_size). + Defaults to None. + + Returns: + HAll (np.array): all hidden states tensor of shape + (sequence_length, num_directions, batch_size, hidden_size) + HFinal (np.array): the final hidden state tensor of shape + (num_directions, batch_size, hidden_size) + ZRH (np.array): all intermediate values of the gates tensor of shape + (sequence_length, num_directions, batch_size, 3 * hidden_size) + """ + all_hidden_states = np.zeros( + (self._sequence_length, self._num_directions, self._batch_size, self._hidden_size), np.float32 + ) + final_hidden_state = np.zeros((self._num_directions, self._batch_size, self._hidden_size), np.float32) + zrh = np.zeros( + (self._sequence_length, self._num_directions, self._batch_size, 3 * self._hidden_size), np.float32 + ) + + weights_z = np.squeeze(weights[:, : self._hidden_size, :], axis=0) + weights_r = np.squeeze(weights[:, self._hidden_size : 2 * self._hidden_size, :], axis=0) + weights_h = np.squeeze(weights[:, 2 * self._hidden_size :, :], axis=0) + + rweights_z = np.squeeze(recurrence_weights[:, : self._hidden_size, :], axis=0) + rweights_r = np.squeeze(recurrence_weights[:, self._hidden_size : 2 * self._hidden_size, :], axis=0) + rweights_h = np.squeeze(recurrence_weights[:, 2 * self._hidden_size :, :], axis=0) + + wb_z = ( + np.squeeze(bias[:, : self._hidden_size], axis=0) + if bias is not None + else np.zeros((self._hidden_size), np.float32) + ) + wb_r = ( + np.squeeze(bias[:, self._hidden_size : 2 * self._hidden_size], axis=0) + if bias is not None + else np.zeros((self._hidden_size), np.float32) + ) + wb_h = ( + np.squeeze(bias[:, 2 * self._hidden_size : 3 * self._hidden_size], axis=0) + if bias is not None + else np.zeros((self._hidden_size), np.float32) + ) + rb_z = ( + np.squeeze(bias[:, 3 * self._hidden_size : 4 * self._hidden_size], axis=0) + if bias is not None + else np.zeros((self._hidden_size), np.float32) + ) + rb_r = ( + np.squeeze(bias[:, 4 * self._hidden_size : 5 * self._hidden_size], axis=0) + if bias is not None + else np.zeros((self._hidden_size), np.float32) + ) + rb_h = ( + np.squeeze(bias[:, 5 * self._hidden_size :], axis=0) + if bias is not None + else np.zeros((self._hidden_size), np.float32) + ) + + for idx in range(self._batch_size): + prev_h = ( + initial_hidden_state[0, idx, :] + if initial_hidden_state is not None + else np.zeros((self._hidden_size), np.float32) + ) + for t in range(self._sequence_length): + current_input = inputs[t, idx, :] + + update_gate = sigmoid(np.dot(current_input, weights_z.T) + np.dot(prev_h, rweights_z.T) + wb_z + rb_z) + reset_gate = sigmoid(np.dot(current_input, weights_r.T) + np.dot(prev_h, rweights_r.T) + wb_r + rb_r) + if self._linear_before_reset: + hidden_gate = np.tanh( + np.dot(current_input, weights_h.T) + (reset_gate * (np.dot(prev_h, rweights_h.T) + rb_h)) + wb_h + ) + else: + hidden_gate = np.tanh( + np.dot(current_input, weights_h.T) + np.dot((reset_gate * prev_h), rweights_h.T) + wb_h + rb_h + ) + + zrh[t, 0, idx, : self._hidden_size] = update_gate + zrh[t, 0, idx, self._hidden_size : 2 * self._hidden_size] = reset_gate + zrh[t, 0, idx, 2 * self._hidden_size :] = hidden_gate + + final_hidden_state[0, idx, :] = ((1 - update_gate) * hidden_gate) + (update_gate * prev_h) + + all_hidden_states[t, 0, idx, :] = final_hidden_state[0, idx, :] + + prev_h = final_hidden_state[0, idx, :] + + return all_hidden_states, final_hidden_state, zrh + + def forward_ort( + self, + inputs, + weights, + recurrence_weights, + bias=None, + initial_hidden_state=None, + ): + """Run GRU forward pass using ONNX Runtime.""" + ort_inputs = {"inputs": inputs, "weights": weights, "recurrence_weights": recurrence_weights} + if bias is not None: + ort_inputs["bias"] = bias + if initial_hidden_state is not None: + ort_inputs["initial_hidden_state"] = initial_hidden_state + + ort_outs = None + with tempfile.TemporaryDirectory() as tmpdirname: + model_path = os.path.join(tmpdirname, "gru.onnx") + onnx.save(self._forward_model, model_path) + ort_session = ort.InferenceSession(model_path, providers=["CPUExecutionProvider"]) + ort_outs = ort_session.run(None, ort_inputs) + + return ort_outs + + def forward_graph( + self, + bias=True, + sequence_lengths=False, + initial_hidden_state=True, + ): + """Create a graph for GRU forward pass.""" + inputs = helper.make_tensor_value_info( + "inputs", TensorProto.FLOAT, [self._sequence_length, self._batch_size, self.input_size] + ) + weights = helper.make_tensor_value_info( + "weights", TensorProto.FLOAT, [self._num_directions, 3 * self._hidden_size, self.input_size] + ) + recurrence_weights = helper.make_tensor_value_info( + "recurrence_weights", TensorProto.FLOAT, [self._num_directions, 3 * self._hidden_size, self._hidden_size] + ) + bias = ( + helper.make_tensor_value_info("bias", TensorProto.FLOAT, [self._num_directions, 6 * self._hidden_size]) + if bias + else None + ) + sequence_lengths = ( + helper.make_tensor_value_info("sequence_lengths", TensorProto.INT64, [self._batch_size]) + if sequence_lengths + else None + ) + initial_hidden_state = ( + helper.make_tensor_value_info( + "initial_hidden_state", TensorProto.FLOAT, [self._num_directions, self._batch_size, self._hidden_size] + ) + if initial_hidden_state + else None + ) + + all_hidden_states = helper.make_tensor_value_info( + "all_hidden_states", + TensorProto.FLOAT, + [self._sequence_length, self._num_directions, self._batch_size, self._hidden_size], + ) + final_hidden_state = helper.make_tensor_value_info( + "final_hidden_state", TensorProto.FLOAT, [self._num_directions, self._batch_size, self._hidden_size] + ) + zrh = helper.make_tensor_value_info( + "zrh", + TensorProto.FLOAT, + [self._sequence_length, self._num_directions, self._batch_size, 3 * self._hidden_size], + ) + + gru = helper.make_node( + "GRUTraining", + inputs=[ + "inputs", + "weights", + "recurrence_weights", + "bias" if bias else "", + "sequence_lengths" if sequence_lengths else "", + "initial_hidden_state" if initial_hidden_state else "", + ], + outputs=["all_hidden_states", "final_hidden_state", "zrh"], + domain="com.microsoft", + hidden_size=self._hidden_size, + linear_before_reset=1 if self._linear_before_reset else 0, + ) + + graph = helper.make_graph( + [gru], + "gru", + [ + gi + for gi in [ + inputs, + weights, + recurrence_weights, + bias, + sequence_lengths, + initial_hidden_state, + ] + if gi + ], + [all_hidden_states, final_hidden_state, zrh], + ) + + self._forward_model = helper.make_model( + graph, + producer_name="orttraining", + opset_imports=[helper.make_opsetid("", 14), helper.make_opsetid("com.microsoft", 1)], + ) + + return self._forward_model + + def backward_np( + self, + inputs, + weights, + recurrence_weights, + bias, + initial_hidden_state, + all_hidden_states, + zrh, + grad_all_hidden_states, + grad_final_hidden_state=None, + ): + """Compute the backward pass of GRU using numpy. + + The computation follows the following rules: + - zt = sigmoid(Xt*(Wz^T) + Ht-1*(Rz^T) + Wbz + Rbz) + - rt = sigmoid(Xt*(Wr^T) + Ht-1*(Rr^T) + Wbr + Rbr) + - ht = tanh(Xt*(Wh^T) + (rt (.) Ht-1)*(Rh^T) + Rbh + Wbh) + - Ht = (1 - zt) (.) ht + zt (.) Ht-1 + + + Args: + inputs (np.ndarray): input tensor of shape (sequence_length, batch_size, input_size) + weights (np.ndarray): weight tensor of shape (num_directions, 3 * hidden_size, input_size) + recurrence_weights (np.ndarray): recurrence weight tensor of shape (num_directions, 3 * hidden_size, hidden_size) + bias (bool): whether to compute the bias gradient or not + initial_hidden_state (np.ndarray): initial hidden state tensor of shape (num_directions, batch_size, hidden_size) + all_hidden_states (np.ndarray): output tensor of shape (sequence_length, num_directions, batch_size, hidden_size) + zrh (np.ndarray): update, reset and hidden gate tensor of shape (sequence_length, num_directions, batch_size, 3 * hidden_size) + grad_all_hidden_states (np.ndarray): gradient of HAll + grad_final_hidden_state (np.ndarray): gradient of Ht + + Returns: + tuple[np.ndarray]: gradients of inputs, weights, recurrence_weights, bias, initial_hidden_state + """ + grad_inputs = np.zeros((self._sequence_length, self._batch_size, self.input_size), np.float32) + grad_weights = np.zeros((self._num_directions, 3 * self._hidden_size, self.input_size), np.float32) + grad_recurrence_weights = np.zeros((self._num_directions, 3 * self._hidden_size, self._hidden_size), np.float32) + grad_bias = np.zeros((self._num_directions, 6 * self._hidden_size), np.float32) if bias is not None else None + grad_initial_hidden_state = ( + np.zeros((self._num_directions, self._batch_size, self._hidden_size), np.float32) + if initial_hidden_state is not None + else None + ) + + weights_z = np.squeeze(weights[:, : self._hidden_size, :], axis=0) + weights_r = np.squeeze(weights[:, self._hidden_size : 2 * self._hidden_size, :], axis=0) + weights_h = np.squeeze(weights[:, 2 * self._hidden_size :, :], axis=0) + + rweights_z = np.squeeze(recurrence_weights[:, : self._hidden_size, :], axis=0) + rweights_r = np.squeeze(recurrence_weights[:, self._hidden_size : 2 * self._hidden_size, :], axis=0) + rweights_h = np.squeeze(recurrence_weights[:, 2 * self._hidden_size :, :], axis=0) + + rb_h = ( + np.squeeze(bias[:, 5 * self._hidden_size :], axis=0) + if bias is not None + else np.zeros((self._hidden_size), np.float32) + ) + + for idx in range(self._batch_size): + grad_h = ( + grad_final_hidden_state[0, idx, :] + if grad_final_hidden_state is not None + else np.zeros((self._hidden_size), np.float32) + ) + for t in reversed(range(self._sequence_length)): + current_input = inputs[t, idx, :] + + update_gate = zrh[t, 0, idx, : self._hidden_size] + reset_gate = zrh[t, 0, idx, self._hidden_size : 2 * self._hidden_size] + hidden_gate = zrh[t, 0, idx, 2 * self._hidden_size :] + + grad_h += grad_all_hidden_states[t, 0, idx, :] + + prev_h = ( + all_hidden_states[t - 1, 0, idx, :] + if t > 0 + else initial_hidden_state[0, idx, :] + if initial_hidden_state is not None + else 0 + ) + + grad_update_gate = (prev_h - hidden_gate) * grad_h + grad_hidden_gate = grad_h * (1 - update_gate) + + grad_update_activation = grad_update_gate * update_gate * (1 - update_gate) + grad_hidden_activation = grad_hidden_gate * (1 - (hidden_gate * hidden_gate)) + + if self._linear_before_reset: + grad_reset_gate = grad_hidden_activation * (np.dot(prev_h, rweights_h.T) + rb_h) + else: + grad_reset_gate = np.dot(grad_hidden_activation, rweights_h) * prev_h + grad_reset_activation = grad_reset_gate * reset_gate * (1 - reset_gate) + + grad_inputs[t, idx, :] = ( + np.dot(grad_update_activation, weights_z) + + np.dot(grad_reset_activation, weights_r) + + np.dot(grad_hidden_activation, weights_h) + ) + if self._linear_before_reset: + grad_h = ( + grad_h * update_gate + + np.dot(grad_update_activation, rweights_z) + + np.dot(grad_reset_activation, rweights_r) + + np.dot(grad_hidden_activation * reset_gate, rweights_h) + ) + else: + grad_h = ( + grad_h * update_gate + + np.dot(grad_update_activation, rweights_z) + + np.dot(grad_reset_activation, rweights_r) + + (np.dot(grad_hidden_activation, rweights_h) * reset_gate) + ) + + if t == 0 and grad_initial_hidden_state is not None: + grad_initial_hidden_state[0, idx, :] = grad_h + + grad_weights[0, : self._hidden_size, :] += np.dot( + np.expand_dims(grad_update_activation, axis=0).T, np.expand_dims(current_input, axis=0) + ) + grad_weights[0, self._hidden_size : 2 * self._hidden_size, :] += np.dot( + np.expand_dims(grad_reset_activation, axis=0).T, np.expand_dims(current_input, axis=0) + ) + grad_weights[0, 2 * self._hidden_size :, :] += np.dot( + np.expand_dims(grad_hidden_activation, axis=0).T, np.expand_dims(current_input, axis=0) + ) + + grad_recurrence_weights[0, : self._hidden_size, :] += np.dot( + np.expand_dims(grad_update_activation, axis=0).T, np.expand_dims(prev_h, axis=0) + ) + grad_recurrence_weights[0, self._hidden_size : 2 * self._hidden_size, :] += np.dot( + np.expand_dims(grad_reset_activation, axis=0).T, np.expand_dims(prev_h, axis=0) + ) + if self._linear_before_reset: + grad_recurrence_weights[0, 2 * self._hidden_size :, :] += np.dot( + np.expand_dims(grad_hidden_activation * reset_gate, axis=0).T, np.expand_dims(prev_h, axis=0) + ) + else: + grad_recurrence_weights[0, 2 * self._hidden_size :, :] += np.dot( + np.expand_dims(grad_hidden_activation, axis=0).T, np.expand_dims(prev_h * reset_gate, axis=0) + ) + + if grad_bias is not None: + grad_bias[0, : self._hidden_size] += grad_update_activation + grad_bias[0, self._hidden_size : 2 * self._hidden_size] += grad_reset_activation + grad_bias[0, 2 * self._hidden_size : 3 * self._hidden_size] += grad_hidden_activation + grad_bias[0, 3 * self._hidden_size : 4 * self._hidden_size] += grad_update_activation + grad_bias[0, 4 * self._hidden_size : 5 * self._hidden_size] += grad_reset_activation + if self._linear_before_reset: + grad_bias[0, 5 * self._hidden_size :] = grad_bias[0, 5 * self._hidden_size :] + ( + grad_hidden_activation * reset_gate + ) + else: + grad_bias[0, 5 * self._hidden_size :] += grad_hidden_activation + + return tuple( + [ + out + for out in [ + grad_inputs, + grad_weights, + grad_recurrence_weights, + grad_bias, + grad_initial_hidden_state, + ] + if out is not None + ] + ) + + def backward_graph( + self, + bias=True, + sequence_lengths=False, + initial_hidden_state=True, + final_hidden_state=False, + ): + """Generate the ONNX graph for the backward pass of the GRU operator.""" + inputs = helper.make_tensor_value_info( + "inputs", TensorProto.FLOAT, [self._sequence_length, self._batch_size, self.input_size] + ) + weights = helper.make_tensor_value_info( + "weights", TensorProto.FLOAT, [self._num_directions, 3 * self._hidden_size, self.input_size] + ) + recurrence_weights = helper.make_tensor_value_info( + "recurrence_weights", TensorProto.FLOAT, [self._num_directions, 3 * self._hidden_size, self._hidden_size] + ) + bias = ( + helper.make_tensor_value_info("bias", TensorProto.FLOAT, [self._num_directions, 6 * self._hidden_size]) + if bias + else None + ) + sequence_lengths = ( + helper.make_tensor_value_info("sequence_lengths", TensorProto.INT64, [self._batch_size]) + if sequence_lengths + else None + ) + initial_hidden_state = ( + helper.make_tensor_value_info( + "initial_hidden_state", TensorProto.FLOAT, [self._num_directions, self._batch_size, self._hidden_size] + ) + if initial_hidden_state + else None + ) + + all_hidden_states = helper.make_tensor_value_info( + "all_hidden_states", + TensorProto.FLOAT, + [self._sequence_length, self._num_directions, self._batch_size, self._hidden_size], + ) + final_hidden_state = ( + helper.make_tensor_value_info( + "final_hidden_state", TensorProto.FLOAT, [self._num_directions, self._batch_size, self._hidden_size] + ) + if final_hidden_state + else None + ) + zrh = helper.make_tensor_value_info( + "zrh", + TensorProto.FLOAT, + [self._sequence_length, self._num_directions, self._batch_size, 3 * self._hidden_size], + ) + grad_all_hidden_states = helper.make_tensor_value_info( + "grad_all_hidden_states", + TensorProto.FLOAT, + [self._sequence_length, self._num_directions, self._batch_size, self._hidden_size], + ) + grad_final_hidden_state = ( + helper.make_tensor_value_info( + "grad_final_hidden_state", + TensorProto.FLOAT, + [self._num_directions, self._batch_size, self._hidden_size], + ) + if final_hidden_state + else None + ) + + grad_inputs = helper.make_tensor_value_info( + "grad_inputs", TensorProto.FLOAT, [self._sequence_length, self._batch_size, self.input_size] + ) + grad_weights = helper.make_tensor_value_info( + "grad_weights", TensorProto.FLOAT, [self._num_directions, 3 * self._hidden_size, self.input_size] + ) + grad_recurrence_weights = helper.make_tensor_value_info( + "grad_recurrence_weights", + TensorProto.FLOAT, + [self._num_directions, 3 * self._hidden_size, self._hidden_size], + ) + grad_bias = ( + helper.make_tensor_value_info("grad_bias", TensorProto.FLOAT, [self._num_directions, 6 * self._hidden_size]) + if bias + else None + ) + grad_initial_hidden_state = ( + helper.make_tensor_value_info( + "grad_initial_hidden_state", + TensorProto.FLOAT, + [self._num_directions, self._batch_size, self._hidden_size], + ) + if initial_hidden_state + else None + ) + + gru = helper.make_node( + "GRUGrad", + inputs=[ + "inputs", + "weights", + "recurrence_weights", + "bias" if bias is not None else "", + "sequence_lengths" if sequence_lengths is not None else "", + "initial_hidden_state" if initial_hidden_state is not None else "", + "all_hidden_states" if all_hidden_states is not None else "", + "zrh" if zrh is not None else "", + "grad_all_hidden_states" if grad_all_hidden_states is not None else "", + "grad_final_hidden_state" if grad_final_hidden_state is not None else "", + ], + outputs=[ + "grad_inputs", + "grad_weights", + "grad_recurrence_weights", + "grad_bias" if grad_bias is not None else "", + "grad_initial_hidden_state" if grad_initial_hidden_state is not None else "", + ], + domain="com.microsoft", + hidden_size=self._hidden_size, + linear_before_reset=1 if self._linear_before_reset else 0, + ) + + graph = helper.make_graph( + [gru], + "gru", + [ + gi + for gi in [ + inputs, + weights, + recurrence_weights, + bias, + sequence_lengths, + initial_hidden_state, + all_hidden_states, + zrh, + grad_all_hidden_states, + grad_final_hidden_state, + ] + if gi + ], + [ + go + for go in [ + grad_inputs, + grad_weights, + grad_recurrence_weights, + grad_bias, + grad_initial_hidden_state, + ] + if go + ], + ) + + self._backward_model = helper.make_model( + graph, + producer_name="orttraining", + opset_imports=[helper.make_opsetid("", 14), helper.make_opsetid("com.microsoft", 1)], + ) + + return self._backward_model + + def backward_ort( + self, + inputs, + weights, + recurrence_weights, + bias=None, + initial_hidden_state=None, + all_hidden_states=None, + zrh=None, + grad_all_hidden_states=None, + grad_final_hidden_state=None, + ): + """Run GRU backward using ONNX Runtime. + + Users must call backward_graph before calling this function. + """ + ort_inputs = { + "inputs": inputs, + "weights": weights, + "recurrence_weights": recurrence_weights, + "all_hidden_states": all_hidden_states, + "zrh": zrh, + "grad_all_hidden_states": grad_all_hidden_states, + } + if bias is not None: + ort_inputs["bias"] = bias + if initial_hidden_state is not None: + ort_inputs["initial_hidden_state"] = initial_hidden_state + if grad_final_hidden_state is not None: + ort_inputs["grad_final_hidden_state"] = grad_final_hidden_state + + ort_outs = None + with tempfile.TemporaryDirectory() as tmpdirname: + model_path = os.path.join(tmpdirname, "gru_gradient.onnx") + onnx.save(self._backward_model, model_path) + ort_session = ort.InferenceSession(model_path, providers=["CPUExecutionProvider"]) + ort_outs = ort_session.run(None, ort_inputs) + return ort_outs + + +@pytest.mark.parametrize("sequence_length", [2, 4, 16, 32]) +@pytest.mark.parametrize("batch_size", [32]) +@pytest.mark.parametrize("input_size", [32]) +@pytest.mark.parametrize("hidden_size", [32]) +@pytest.mark.parametrize("linear_before_reset", [True, False]) +def test_gru_forward(sequence_length, batch_size, input_size, hidden_size, linear_before_reset): + num_directions = 1 + + gru = GRU(sequence_length, batch_size, input_size, hidden_size, linear_before_reset) + _ = gru.forward_graph(bias=True, sequence_lengths=False, initial_hidden_state=True) + + inputs = np.random.rand(sequence_length, batch_size, input_size).astype(np.float32) + weights = np.random.rand(num_directions, 3 * hidden_size, input_size).astype(np.float32) + recurrence_weights = np.random.rand(num_directions, 3 * hidden_size, hidden_size).astype(np.float32) + bias = np.random.rand(num_directions, 6 * hidden_size).astype(np.float32) + initial_hidden_state = np.random.rand(num_directions, batch_size, hidden_size).astype(np.float32) + + outs_ort = gru.forward_ort(inputs, weights, recurrence_weights, bias, initial_hidden_state) + outs_np = gru.forward_np(inputs, weights, recurrence_weights, bias, initial_hidden_state) + + for ort_out, np_out in zip(outs_ort, outs_np): + assert np.allclose(ort_out, np_out, rtol=1e-03, atol=1e-05) + + +@pytest.mark.parametrize("sequence_length", [2, 4, 16, 32]) +@pytest.mark.parametrize("batch_size", [32]) +@pytest.mark.parametrize("input_size", [32]) +@pytest.mark.parametrize("hidden_size", [32]) +@pytest.mark.parametrize("linear_before_reset", [True, False]) +def test_gru_backward(sequence_length, batch_size, input_size, hidden_size, linear_before_reset): + np.random.seed(seed=None) + num_directions = 1 + + gru = GRU(sequence_length, batch_size, input_size, hidden_size, linear_before_reset) + _ = gru.backward_graph(bias=True, sequence_lengths=False, initial_hidden_state=True, final_hidden_state=True) + + inputs = np.random.rand(sequence_length, batch_size, input_size).astype(np.float32) + weights = np.random.rand(num_directions, 3 * hidden_size, input_size).astype(np.float32) + recurrence_weights = np.random.rand(num_directions, 3 * hidden_size, hidden_size).astype(np.float32) + bias = np.random.rand(num_directions, 6 * hidden_size).astype(np.float32) + initial_hidden_state = np.random.rand(num_directions, batch_size, hidden_size).astype(np.float32) + + all_hidden_states = np.random.rand(sequence_length, num_directions, batch_size, hidden_size).astype(np.float32) + zrh = np.random.rand(sequence_length, num_directions, batch_size, 3 * hidden_size).astype(np.float32) + grad_all_hidden_states = np.random.rand(sequence_length, num_directions, batch_size, hidden_size).astype(np.float32) + grad_final_hidden_state = np.random.rand(num_directions, batch_size, hidden_size).astype(np.float32) + + outs_ort = gru.backward_ort( + inputs, + weights, + recurrence_weights, + bias, + initial_hidden_state, + all_hidden_states, + zrh, + grad_all_hidden_states, + grad_final_hidden_state, + ) + outs_np = gru.backward_np( + inputs, + weights, + recurrence_weights, + bias, + initial_hidden_state, + all_hidden_states, + zrh, + grad_all_hidden_states, + grad_final_hidden_state, + ) + + for ort_out, np_out in zip(outs_ort, outs_np): + assert np.allclose(ort_out, np_out, rtol=1e-01, atol=1e-03) diff --git a/orttraining/orttraining/test/python/orttraining_test_hooks.py b/orttraining/orttraining/test/python/orttraining_test_hooks.py index 80f29ad88105f..a58b3919c55d8 100644 --- a/orttraining/orttraining/test/python/orttraining_test_hooks.py +++ b/orttraining/orttraining/test/python/orttraining_test_hooks.py @@ -8,7 +8,7 @@ import torch from onnxruntime.training.ortmodule import ORTModule -from onnxruntime.training.utils.hooks import StatisticsSubscriber, SubscriberManager +from onnxruntime.training.utils.hooks import GlobalSubscriberManager, StatisticsSubscriber, inspect_activation class NeuralNetSingleOutput(torch.nn.Module): @@ -55,8 +55,7 @@ def test_statistic_subscriber_single_output(device, backend): with tempfile.TemporaryDirectory() as temporary_dir: output_dir_path = os.path.join(temporary_dir, f"{backend}_out") - sub_manager = SubscriberManager() - sub_manager.subscribe(model, [StatisticsSubscriber(output_dir_path, override_output_dir=True)]) + GlobalSubscriberManager.subscribe(model, [StatisticsSubscriber(output_dir_path, override_output_dir=True)]) if backend == "ortmodule": model = ORTModule(model) @@ -100,9 +99,7 @@ def test_statistic_subscriber_multiple_outputs(device, backend): with tempfile.TemporaryDirectory() as temporary_dir: output_dir_path = os.path.join(temporary_dir, f"{backend}_out") - - sub_manager = SubscriberManager() - sub_manager.subscribe(model, [StatisticsSubscriber(output_dir_path, override_output_dir=True)]) + GlobalSubscriberManager.subscribe(model, [StatisticsSubscriber(output_dir_path, override_output_dir=True)]) if backend == "ortmodule": model = ORTModule(model) @@ -137,3 +134,69 @@ def test_statistic_subscriber_multiple_outputs(device, backend): assert len(os.listdir(step_dir)) == len(expected_files) for file in expected_files: assert os.path.exists(os.path.join(step_dir, file)) + + +class NeuralNetUserAnnotateIntermediateTensor(torch.nn.Module): + def __init__(self, input_size, hidden_size, num_classes): + super().__init__() + + self.fc1 = torch.nn.Linear(input_size, hidden_size) + self.relu = torch.nn.ReLU() + self.fc2 = torch.nn.Linear(hidden_size, num_classes) + + def forward(self, input1, input2): + model_input = input1 + input2 + out = self.fc1(model_input) + out = inspect_activation("fc1_out", out) + out = self.relu(out) + out = inspect_activation("relu_out", out) + out = self.fc2(out) + return out + + +@pytest.mark.parametrize("device", ["cpu", "cuda"]) +@pytest.mark.parametrize("backend", ["torch", "ortmodule"]) +def test_statistic_subscriber_user_annotate_intermediate_tensors(device, backend): + input_size = 8 + hidden_size = 16 + num_classes = 32 + model = NeuralNetUserAnnotateIntermediateTensor(input_size, hidden_size, num_classes) + model.to(device) + model.train() + + with tempfile.TemporaryDirectory() as temporary_dir: + output_dir_path = os.path.join(temporary_dir, f"{backend}_out") + GlobalSubscriberManager.subscribe(model, [StatisticsSubscriber(output_dir_path, override_output_dir=True)]) + + if backend == "ortmodule": + model = ORTModule(model) + + batch_size = 4 + input1_tensor = torch.randn(batch_size, input_size, device=device) + input2_tensor = torch.randn(batch_size, input_size, device=device) + for _ in range(5): + y = model(input1_tensor, input2_tensor) + y.sum().backward() + + assert os.path.exists(output_dir_path) + + expected_files = [ + "order.txt", + "Linear_1_0th_output_forward", + "Linear_1_0th_output_backward", + "NeuralNetUserAnnotateIntermediateTensor_0_0th_output_forward", + "NeuralNetUserAnnotateIntermediateTensor_0_0th_output_backward", + "ReLU_2_0th_output_forward", + "ReLU_2_0th_output_backward", + "Linear_3_0th_output_forward", + "Linear_3_0th_output_backward", + "fc1_out_forward", + "fc1_out_backward", + "relu_out_forward", + "relu_out_backward", + ] + + for i in range(5): + step_dir = os.path.join(output_dir_path, f"step_{i}") + for file in expected_files: + assert os.path.exists(os.path.join(step_dir, file)) diff --git a/orttraining/orttraining/test/python/orttraining_test_layer_norm_transform.py b/orttraining/orttraining/test/python/orttraining_test_layer_norm_transform.py index 35d59c1750de4..6a3788e2fc44a 100644 --- a/orttraining/orttraining/test/python/orttraining_test_layer_norm_transform.py +++ b/orttraining/orttraining/test/python/orttraining_test_layer_norm_transform.py @@ -176,7 +176,7 @@ def layer_norm_transform(model_proto): all_nodes.append(node) for node in layer_norm_nodes: - all_nodes.append(node) + all_nodes.append(node) # noqa: PERF402 graph_proto.ClearField("node") graph_proto.node.extend(all_nodes) diff --git a/orttraining/orttraining/test/python/orttraining_test_lstm.py b/orttraining/orttraining/test/python/orttraining_test_lstm.py index c03c145fb77fd..2b296cf70c2c1 100644 --- a/orttraining/orttraining/test/python/orttraining_test_lstm.py +++ b/orttraining/orttraining/test/python/orttraining_test_lstm.py @@ -840,9 +840,9 @@ def backward_ort( @pytest.mark.parametrize("sequence_length", [2, 4, 16, 32]) -@pytest.mark.parametrize("batch_size", [2, 4, 32]) -@pytest.mark.parametrize("input_size", [2, 4, 32]) -@pytest.mark.parametrize("hidden_size", [2, 4, 32]) +@pytest.mark.parametrize("batch_size", [32]) +@pytest.mark.parametrize("input_size", [32]) +@pytest.mark.parametrize("hidden_size", [32]) def test_lstm_forward(sequence_length, batch_size, input_size, hidden_size): num_directions = 1 @@ -871,9 +871,9 @@ def test_lstm_forward(sequence_length, batch_size, input_size, hidden_size): @pytest.mark.parametrize("sequence_length", [2, 4, 16, 32]) -@pytest.mark.parametrize("batch_size", [2, 4, 32]) -@pytest.mark.parametrize("input_size", [2, 4, 32]) -@pytest.mark.parametrize("hidden_size", [2, 4, 32]) +@pytest.mark.parametrize("batch_size", [32]) +@pytest.mark.parametrize("input_size", [32]) +@pytest.mark.parametrize("hidden_size", [32]) def test_lstm_backward(sequence_length, batch_size, input_size, hidden_size): num_directions = 1 diff --git a/orttraining/orttraining/test/python/orttraining_test_onnx_ops_ortmodule.py b/orttraining/orttraining/test/python/orttraining_test_onnx_ops_ortmodule.py index 27629133dfb3d..4f0925c5c855b 100644 --- a/orttraining/orttraining/test/python/orttraining_test_onnx_ops_ortmodule.py +++ b/orttraining/orttraining/test/python/orttraining_test_onnx_ops_ortmodule.py @@ -78,7 +78,7 @@ def run_step(model, x): self.assertIn('op_type: "%s"' % name, str(onnx_graph_inf)) for onnx_model in [onnx_graph_inf, onnx_graph_train]: for oimp in onnx_model.opset_import: - if oimp.domain == "": # noqa: PLC1901 + if oimp.domain == "": self.assertEqual(oimp.version, 15) if op_grad_type is not None: if isinstance(op_grad_type, tuple): diff --git a/orttraining/orttraining/test/python/orttraining_test_onnxblock.py b/orttraining/orttraining/test/python/orttraining_test_onnxblock.py index ce919f470668d..f7a7220dd66ea 100644 --- a/orttraining/orttraining/test/python/orttraining_test_onnxblock.py +++ b/orttraining/orttraining/test/python/orttraining_test_onnxblock.py @@ -554,6 +554,32 @@ def mse_loss(prediction, target): _ = ort_session.run(ort_output_names, ort_inputs) +@pytest.mark.parametrize( + "block", + [SimpleTrainingBlockWithMSELoss, SimpleTrainingBlockWithCrossEntropyLoss, SimpleTrainingBlockWithBCEWithLogitsLoss], +) +@pytest.mark.parametrize("grad_clipping", [None, onnxblock.optim.ClipGradNorm(2.5)]) +def test_sgd_optimizer_composition(block, grad_clipping): + # Given + device = "cpu" + batch_size, input_size, hidden_size, output_size = 64, 784, 500, 10 + pt_model, base_model = _get_models(device, batch_size, input_size, hidden_size, output_size) + + # When / Then no error occurs + simple_block = block() + for name, _ in pt_model.named_parameters(): + simple_block.requires_grad(name) + + with onnxblock.base(base_model): + _ = simple_block(base_model.graph.output[0].name) + + optimizer = onnxblock.optim.SGD(clip_grad=grad_clipping) + with onnxblock.empty_base() as accessor: + _ = optimizer(simple_block.parameters()) + optimizer_model = accessor.model + assert optimizer_model + + def test_retrieve_parameters(): # Given device = "cuda" @@ -629,6 +655,8 @@ def test_load_checkpoint(): # When simple_block.requires_grad("fc2.weight", True) simple_block.requires_grad("fc1.bias", True) + simple_block.requires_grad("fc1.weight", True) + simple_block.requires_grad("fc2.bias", True) with onnxblock.base(onnx_model): _ = simple_block(onnx_model.graph.output[0].name) @@ -819,6 +847,39 @@ def mse_loss(prediction, target): assert np.allclose(ort_grad, _to_numpy(pt_param.grad)) +def test_additional_output_names(): + class DropoutModel(torch.nn.Module): + def __init__(self): + super().__init__() + self.dropout = torch.nn.Dropout(p=0.5) + + def forward(self, x): + return self.dropout(x) + + model = DropoutModel() + onnx_model = _get_onnx_model(model, (torch.randn(1, 3, 224, 224),)) + + with tempfile.TemporaryDirectory() as temp_dir: + artifacts.generate_artifacts(onnx_model, loss=artifacts.LossType.CrossEntropyLoss, artifact_directory=temp_dir) + + eval_model = onnx.load(os.path.join(temp_dir, "eval_model.onnx")) + + # Make sure only loss is the output + assert len(eval_model.graph.output) == 1 + + # Re-generate artifacts with additional output names + artifacts.generate_artifacts( + onnx_model, + loss=artifacts.LossType.CrossEntropyLoss, + artifact_directory=temp_dir, + additional_output_names=["output-0"], + ) + + # Make sure the eval model has two outputs + eval_model = onnx.load(os.path.join(temp_dir, "eval_model.onnx")) + assert len(eval_model.graph.output) == 2 + + def test_eval_model_has_no_training_mode_dropout(): class DropoutModel(torch.nn.Module): def __init__(self): @@ -915,3 +976,26 @@ def build(self, output_name): all_nodes = [node.op_type for node in model.graph.node] assert "LabelEncoder" in all_nodes + + +def test_save_ort_format(): + device = "cpu" + batch_size, input_size, hidden_size, output_size = 64, 784, 500, 10 + _, base_model = _get_models(device, batch_size, input_size, hidden_size, output_size) + + with tempfile.TemporaryDirectory() as temp_dir: + artifacts.generate_artifacts( + base_model, + requires_grad=["fc1.weight", "fc1.bias", "fc2.weight", "fc2.bias"], + loss=artifacts.LossType.CrossEntropyLoss, + optimizer=artifacts.OptimType.AdamW, + artifact_directory=temp_dir, + ort_format=True, + ) + + assert os.path.exists(os.path.join(temp_dir, "training_model.onnx")) + assert os.path.exists(os.path.join(temp_dir, "training_model.ort")) + assert os.path.exists(os.path.join(temp_dir, "eval_model.onnx")) + assert os.path.exists(os.path.join(temp_dir, "eval_model.ort")) + assert os.path.exists(os.path.join(temp_dir, "optimizer_model.onnx")) + assert os.path.exists(os.path.join(temp_dir, "optimizer_model.ort")) diff --git a/orttraining/orttraining/test/python/orttraining_test_ort_apis.py b/orttraining/orttraining/test/python/orttraining_test_ort_apis.py index ce96ee3da6658..506aafbe9f618 100644 --- a/orttraining/orttraining/test/python/orttraining_test_ort_apis.py +++ b/orttraining/orttraining/test/python/orttraining_test_ort_apis.py @@ -8,7 +8,6 @@ import argparse import logging -import os import sys from _test_commons import run_subprocess @@ -43,31 +42,6 @@ def run_onnxblock_tests(cwd, log): run_subprocess(command, cwd=cwd, log=log).check_returncode() -def run_onnxruntime_test_all_ctest(cwd, log, filter): - """Calls onnxruntime_test_all gtest executable with the given filter.""" - - command = [os.path.join(cwd, "onnxruntime_test_all"), f"--gtest_filter={filter}"] - - run_subprocess(command, cwd=cwd, log=log).check_returncode() - - -def run_training_api_tests(cwd, log): - """Runs the onnxruntime_test_all executable with the TrainingApiTest* gtest filter.""" - - log.debug("Running: TrainingApi and TrainingCApi tests") - - run_onnxruntime_test_all_ctest(cwd, log, "TrainingApiTest*") - run_onnxruntime_test_all_ctest(cwd, log, "TrainingCApiTest*") - - -def run_checkpoint_api_tests(cwd, log): - """Runs the onnxruntime_test_all executable with the CheckpointApiTest* gtest filter.""" - - log.debug("Running: TrainingApi tests") - - run_onnxruntime_test_all_ctest(cwd, log, "CheckpointApiTest*") - - def main(): args = parse_arguments() cwd = args.cwd @@ -78,10 +52,6 @@ def main(): run_training_apis_python_api_tests(cwd, log) - run_training_api_tests(cwd, log) - - run_checkpoint_api_tests(cwd, log) - return 0 diff --git a/orttraining/orttraining/test/python/orttraining_test_ortmodule_api.py b/orttraining/orttraining/test/python/orttraining_test_ortmodule_api.py index 4104ee7d11fee..bf26fd1822dc4 100644 --- a/orttraining/orttraining/test/python/orttraining_test_ortmodule_api.py +++ b/orttraining/orttraining/test/python/orttraining_test_ortmodule_api.py @@ -23,22 +23,16 @@ from packaging.version import Version # Import autocasting libs +from torch import nn from torch.cuda import amp from transformers import AdamW, AutoConfig, BertForSequenceClassification, Trainer from transformers.modeling_outputs import SequenceClassifierOutput import onnxruntime.training.ortmodule as ortmodule_module from onnxruntime.training.optim import AdamWMode, FusedAdam -from onnxruntime.training.ortmodule import ( - DebugOptions, - LogLevel, - ORTModule, - _fallback, - _graph_execution_manager, - _io, - _utils, -) +from onnxruntime.training.ortmodule import DebugOptions, LogLevel, ORTModule, _fallback, _io, _utils from onnxruntime.training.ortmodule._custom_gradient_registry import register_gradient +from onnxruntime.training.ortmodule.options import _SkipCheck DEFAULT_OPSET = 15 @@ -4008,6 +4002,7 @@ def forward(self, bool_argument, input1): ], ) def test_unused_parameters(model, none_pt_params): + torch.manual_seed(2333) device = "cuda" N, D_in, H1, H2, D_out = 64, 784, 500, 400, 10 # noqa: F841, N806 @@ -4216,17 +4211,12 @@ def test_hf_save_pretrained(): def test_ortmodule_string_inputs_are_ignored(): pt_model = MyStrNet() - ort_model = ORTModule(copy.deepcopy(pt_model)) - x = torch.randn(1, 2) - - with pytest.warns(UserWarning) as warning_record: + target_str = "Received input of type which may be treated as a constant by ORT by default." + with pytest.warns(UserWarning, match=target_str): + ort_model = ORTModule(copy.deepcopy(pt_model), DebugOptions(log_level=LogLevel.INFO)) + x = torch.randn(1, 2) out = ort_model(x, "hello") - - assert ( - "Received input of type which may be treated as a constant by ORT by default." - in warning_record[1].message.args[0] - ) - _test_helpers.assert_values_are_close(out, x + 1) + _test_helpers.assert_values_are_close(out, x + 1) def test_ortmodule_list_input(): @@ -4451,7 +4441,7 @@ def forward(self, input1): # model with optimization enabled opt_model = ORTModule(copy.deepcopy(pt_model)) - opt_model._torch_module._execution_manager(is_training=True)._enable_grad_acc_optimization = True + opt_model._torch_module._execution_manager(is_training=True)._runtime_options.enable_grad_acc_optimization = True opt_optimizer = torch.optim.Adam(opt_model.parameters()) def run_step(model, x): @@ -4803,7 +4793,7 @@ def forward(self, a): del os.environ["ORTMODULE_SKIPCHECK_POLICY"] -def test_ortmodule_attribute_name_collision_warning(): +def test_ortmodule_attribute_name_collision_warning(caplog): class UserNet(torch.nn.Module): def __init__(self): super().__init__() @@ -4818,17 +4808,14 @@ def load_state_dict(self): device = "cuda" pt_model = UserNet().to(device) - with pytest.warns(UserWarning) as warning_record: - ORTModule(pt_model) - # FutureWarning('The first argument to symbolic functions is deprecated in 1.13 and will be removed in the future. - # Please annotate treat the first argument (g) as GraphContext and use context information from the object - # instead.') - # TODO(bmeswani): Check with the exporter team as to what this might mean for ortmodule. - assert len(warning_record) == 3 + ORTModule(pt_model) + warning_record = [record.message for record in caplog.records if record.levelname == "WARNING"] - assert "_torch_module collides with ORTModule's attribute name." in warning_record[1].message.args[0] - assert "load_state_dict collides with ORTModule's attribute name." in warning_record[2].message.args[0] + assert len(warning_record) == 2 + + assert "_torch_module collides with ORTModule's attribute name." in warning_record[-2] + assert "load_state_dict collides with ORTModule's attribute name." in warning_record[-1] def test_ortmodule_ortmodule_method_attribute_copy(): @@ -4879,10 +4866,10 @@ def run_forward(self, *args, **kwargs): @pytest.mark.parametrize( "policy_str, policy", [ - ("SKIP_CHECK_DISABLED", _graph_execution_manager._SkipCheck.SKIP_CHECK_DISABLED), - ("SKIP_CHECK_DEVICE", _graph_execution_manager._SkipCheck.SKIP_CHECK_DEVICE), - ("SKIP_CHECK_BUILD_GRADIENT", _graph_execution_manager._SkipCheck.SKIP_CHECK_BUILD_GRADIENT), - ("SKIP_CHECK_EXECUTION_AGENT", _graph_execution_manager._SkipCheck.SKIP_CHECK_EXECUTION_AGENT), + ("SKIP_CHECK_DISABLED", _SkipCheck.SKIP_CHECK_DISABLED), + ("SKIP_CHECK_DEVICE", _SkipCheck.SKIP_CHECK_DEVICE), + ("SKIP_CHECK_BUILD_GRADIENT", _SkipCheck.SKIP_CHECK_BUILD_GRADIENT), + ("SKIP_CHECK_EXECUTION_AGENT", _SkipCheck.SKIP_CHECK_EXECUTION_AGENT), ], ) def test_ortmodule_skip_check_load_from_os_env(policy_str, policy): @@ -4893,7 +4880,7 @@ def test_ortmodule_skip_check_load_from_os_env(policy_str, policy): ort_model = ORTModule(model) for training_mode in [False, True]: - assert ort_model._torch_module._execution_manager(training_mode)._skip_check == policy + assert ort_model._torch_module._execution_manager(training_mode)._runtime_options.skip_check == policy del os.environ["ORTMODULE_SKIPCHECK_POLICY"] @@ -5227,10 +5214,8 @@ def run_step(model, x): N, D_in, H, D_out = 120, 15360, 500, 15360 # noqa: N806 pt_model = NeuralNetSigmoid(D_in, H, D_out).to(device) - old_opst_cst = ortmodule_module.ONNX_OPSET_VERSION old_opset = os.getenv("ORTMODULE_ONNX_OPSET_VERSION", None) os.environ["ORTMODULE_ONNX_OPSET_VERSION"] = "13" - assert ortmodule_module.ONNX_OPSET_VERSION == 15 ort_model = ORTModule(copy.deepcopy(pt_model)) @@ -5241,7 +5226,7 @@ def run_step(model, x): pt_prediction, pt_loss = run_step(pt_model, pt_x) if step == 0: model_onx = ort_model._torch_module._execution_manager._training_manager._onnx_models - for name in ["exported_model", "optimized_model", "optimized_pre_grad_model"]: + for name in ["exported_model", "optimized_model"]: onx = getattr(model_onx, name) opv = None for op in onx.opset_import: @@ -5256,21 +5241,25 @@ def run_step(model, x): del os.environ["ORTMODULE_ONNX_OPSET_VERSION"] else: os.environ["ORTMODULE_ONNX_OPSET_VERSION"] = old_opset - assert ortmodule_module.ONNX_OPSET_VERSION == 13 - ortmodule_module.ONNX_OPSET_VERSION = old_opst_cst + + assert ort_model._torch_module._execution_manager(True)._runtime_options.onnx_opset_version == 13 @pytest.mark.parametrize("opset_version", [12, 13, 14, 15]) def test_opset_version_change(opset_version): + original_env = None + if "ORTMODULE_ONNX_OPSET_VERSION" in os.environ: + original_env = os.environ["ORTMODULE_ONNX_OPSET_VERSION"] + del os.environ["ORTMODULE_ONNX_OPSET_VERSION"] + device = "cuda" N, D_in, H, D_out = 64, 784, 500, 10 # noqa: N806 x = torch.randn(N, D_in, device=device) model = NeuralNetSinglePositionalArgument(D_in, H, D_out).to(device) - ort_model = ORTModule(model) - ortmodule_module.ONNX_OPSET_VERSION = opset_version + ort_model = ORTModule(model) # Make sure model runs without any exception prediction = ort_model(x) @@ -5282,6 +5271,9 @@ def test_opset_version_change(opset_version): exported_model = ort_model._torch_module._execution_manager(ort_model._is_training())._onnx_models.exported_model assert exported_model.opset_import[0].version == opset_version + if original_env is not None: + os.environ["ORTMODULE_ONNX_OPSET_VERSION"] = original_env + def test_serialize_ortmodule(): device = "cuda" @@ -5672,3 +5664,721 @@ def run_step(model, input, target): _test_helpers.assert_values_are_close(ort_prediction, pt_prediction) _test_helpers.assert_values_are_close(ort_input.grad, pt_input.grad) + + +@pytest.mark.parametrize("embed_is_sparse", [False, True]) +@pytest.mark.parametrize("label_is_sparse", [False, True]) +@pytest.mark.parametrize("rank", [1, 2]) +def test_runtime_inspector_label_and_embed_sparsity_detection(embed_is_sparse, label_is_sparse, rank, caplog): + os.environ["ORTMODULE_ENABLE_EMBEDDING_SPARSE_OPTIMIZER"] = "1" + + class NeuralNetCrossEntropyLoss(torch.nn.Module): + def __init__(self, num_embeddings, embedding_dim): + super().__init__() + self.embedding = torch.nn.Embedding(num_embeddings, embedding_dim, padding_idx=1) + self.num_class = 3 + self.fc1 = torch.nn.Linear(embedding_dim, self.num_class, bias=False) + with torch.no_grad(): + self.fc1.weight.fill_(1.0) + self.loss_fct = torch.nn.CrossEntropyLoss() + + def forward(self, input, labels): + output = self.embedding(input) + output = self.fc1(output) + if rank == 1: + return self.loss_fct(output, labels) + else: + return self.loss_fct(output.view(-1, self.num_class), labels.view(-1)) + + device = "cuda" + num_embeddings, embedding_dim = 16, 128 + pt_model = NeuralNetCrossEntropyLoss(num_embeddings, embedding_dim).to(device) + from onnxruntime.training.ortmodule import DebugOptions, LogLevel + + ort_model = ORTModule(pt_model, DebugOptions(log_level=LogLevel.INFO)) + + def run_step(model, input, positions): + with amp.autocast(True): + loss = model(input, positions) + loss.backward() + return loss + + # batch_size = 3 + # sequence = 4 + + if embed_is_sparse: + input = torch.tensor([[0, 2, 3, 4], [2, 3, 1, 1], [1, 1, 1, 1]], device=device) + else: + input = torch.tensor([[0, 2, 3, 4], [2, 3, 5, 6], [8, 7, 7, 7]], device=device) + + if label_is_sparse: + label = torch.tensor([[1, 2, -100, 2], [-100, -100, 2, 1], [-100, 1, 2, -100]], device=device) + else: + label = torch.tensor([[1, 2, 0, 2], [0, 0, 2, 1], [0, 1, 2, 0]], device=device) + + if rank == 1: + input = input.view(-1) + label = label.view(-1) + + _ = run_step(ort_model, input, label) + + found_embed_is_sparse = False + found_label_is_sparse = False + for record in caplog.records: + if "Label sparsity-based optimization is ON for" in record.getMessage(): + found_label_is_sparse = True + + if "Embedding sparsity-based optimization is ON for" in record.getMessage(): + found_embed_is_sparse = True + + if label_is_sparse: + assert found_label_is_sparse + + if embed_is_sparse: + assert found_embed_is_sparse + + +@pytest.mark.parametrize( + "test_cases", + [ + ("Add", 0), + ("Add", 2), + ("Add", 3), + ("Add", 4), + ("Sub", 0), + ("Sub", 2), + ("Sub", 3), + ("Sub", 4), + ("Mul", 0), + ("Mul", 2), + ("Mul", 3), + ("Mul", 4), + ("MatMul", 0), + ("MatMul", 1), + ("Dropout", 0), + ("LayerNormalization", 0), + ("Cast", 0), + ("BiasGelu", 0), + ("Gelu", 0), + ("ReduceMean", 0), + ("ReduceMean", 1), + ], +) +def test_ops_for_padding_elimination(test_cases): + os.environ["ORTMODULE_ENABLE_EMBEDDING_SPARSE_OPTIMIZER"] = "1" + test_op = test_cases[0] + case = test_cases[1] + + class ToyModel(torch.nn.Module): + def __init__(self, vocab_size, hidden_size, pad_token_id): + super().__init__() + self.word_embeddings = nn.Embedding(vocab_size, hidden_size, padding_idx=pad_token_id) + if test_op == "LayerNormalization": + self.LayerNorm = nn.LayerNorm(hidden_size, eps=1e-05) + self.hidden_size = hidden_size + + # test test_elementwise op for padding elimination + # in case 0, the shapes of inputs of test_op are [batch_size, seqlen, hidden_size] and [hidden_size], + # the test_op should be included in padding elimination subgraph and the PadAndUnflatten should be + # added to output of test_op. + # in case 2, the shapes of inputs of test_op are [batch_size, seqlen, hidden_size] and [batch_size, 1, hidden_size], + # the test_op should be included in padding elimination subgraph and a 'Expand + Reshape + ShrunkenGather' + # pattern should be insert to the arg of [batch_size, 1, hidden_size]. + # in case 3, the shapes of inputs of test_op are [batch_size, seqlen, hidden_size] and [1, hidden_size], + # the test_op should be included in padding elimination subgraph and a 'Expand + Reshape + ShrunkenGather' + # pattern should be insert to the arg of [batch_size, 1, hidden_size]. + # in case 4, the shapes of inputs of test_op are [batch_size, seqlen, hidden_size] and [batch_size, seqlen, hidden_size], + # the test_op should be included in padding elimination subgraph and the PadAndUnflatten should be added to + # output of test_op. Besides, the other input of Add should be added 'Reshape + ShrunkenGather' to + # flatten and elimination padding. + def test_elementwise(self, input_ids): + input_shape = input_ids.size() + one_input = None + if case == 0: + one_input = torch.ones(self.hidden_size, dtype=torch.long).to(device) + elif case == 2: + one_input = torch.ones((input_shape[0], 1, self.hidden_size), dtype=torch.long).to(device) + elif case == 3: + one_input = torch.ones((1, self.hidden_size), dtype=torch.long).to(device) + elif case == 4: + one_input = torch.ones(input_shape, dtype=torch.long).to(device) + one_input = one_input.unsqueeze(-1).expand(-1, -1, self.hidden_size) + inputs_embeds = self.word_embeddings(input_ids) + if test_op == "Add": + output = one_input + inputs_embeds + elif test_op == "Sub": + output = one_input - inputs_embeds + elif test_op == "Mul": + output = one_input * inputs_embeds + else: + output = None + return output + + # test MatMul op for padding elimination + # in case 0, the shapes of inputs of MatMul are [batch_size, seqlen, hidden_size] and [hidden_size, 128] + # the MatMul should be included in padding elimination subgraph and the PadAndUnflatten should be + # added to output of MatMul. + # in case 1, the shapes of inputs of MatMul are [2, seqlen] and [batch_size, seqlen, hidden_size] + # this case is not support in padding elimination, so the MatMul should not be included in padding + # elimination subgraph and the PadAndUnflatten should be added before MatMul. + def test_matmul(self, input_ids): + inputs_embeds = self.word_embeddings(input_ids) + output = None + if case == 0: + matmul_input = torch.randn((self.hidden_size, 128)).to(device) + output = torch.matmul(inputs_embeds, matmul_input) + elif case == 1: + matmul_input = torch.randn((2, input_ids.size(1))).to(device) + output = torch.matmul(matmul_input, inputs_embeds) + return output + + # test other ops for padding elimination + # all these ops should be included in padding elimination subgraph and the PadAndUnflatten should be added to + # output of these ops. + def test_other(self, input_ids): + inputs_embeds = self.word_embeddings(input_ids) + output = None + if test_op == "Dropout": + output = torch.nn.functional.dropout(inputs_embeds, p=0.5, training=True) + elif test_op == "LayerNormalization": + output = self.LayerNorm(inputs_embeds) + elif test_op == "Cast": + output = inputs_embeds.to(torch.float16) + elif test_op == "BiasGelu": + bias = torch.randn((self.hidden_size,)).to(device) + output = torch.nn.functional.gelu(inputs_embeds + bias) + elif test_op == "Gelu": + output = torch.nn.functional.gelu(inputs_embeds) + elif test_op == "ReduceMean": + # In case 0, the inputs_embeds are reduced at last dimension, the ReduceMean should be included in padding + # elimination subgraph and the PadAndUnflatten should be added to output of ReduceMean. + # In case 1, the inputs_embeds are reduced at first dimension which is not supported in padding elimination, + # so the ReduceMean should not be included in padding elimination subgraph and the PadAndUnflatten should + # be added before ReduceMean. + if case == 0: + output = torch.mean(inputs_embeds, dim=-1) + elif case == 1: + output = torch.mean(inputs_embeds, dim=0) + return output + + def forward(self, input_ids): + if test_op in ["Add", "Mul", "Sub"]: + output = self.test_elementwise(input_ids) + elif test_op == "MatMul": + output = self.test_matmul(input_ids) + else: + output = self.test_other(input_ids) + return output + + # Generate one batch of inputs (shape:[batch_size, max_seq_length]). + # Each input has random length from 1 to max_seq_length*0.8 with values from 2 to vocab_size and padded with 1 at + # [max_seq_length - length:]. + def generate_inputs(batch_size, max_seq_length, vocab_size): + batched_inputs = [] + for _ in range(batch_size): + # Generate random length from 1 to max_seq_length*0.8, to ensure sparsity > 20% + seq_len = random.randint(1, int(max_seq_length * 0.8)) + + # Generate input values and padding respectively and concatenate them + input_id = torch.randint(2, vocab_size, (seq_len,), dtype=torch.long, device=device) + padding = torch.ones((max_seq_length - seq_len,), dtype=torch.long, device=device) + batched_inputs.append(torch.cat((input_id, padding))) + return torch.stack(batched_inputs) + + vocab_size, hidden_size = 50265, 768 + batch_size, max_seq_length = 8, 128 + device = "cuda" + model = ORTModule(ToyModel(vocab_size, hidden_size, 1).to(device)) + x = generate_inputs(batch_size, max_seq_length, vocab_size) + model(x) + + training_model = model._torch_module._execution_manager(True)._onnx_models.optimized_model + if test_op == "Sub": + assert len([node.op_type for node in training_model.graph.node if node.op_type == "Sub"]) == 2 + else: + assert len([node.op_type for node in training_model.graph.node if node.op_type == "Sub"]) == 1 + assert len([node.op_type for node in training_model.graph.node if node.op_type == "NonZero"]) == 1 + assert len([node.op_type for node in training_model.graph.node if node.op_type == "Squeeze"]) == 1 + assert len([node.op_type for node in training_model.graph.node if node.op_type == "PadAndUnflatten"]) == 1 + if case >= 2: + assert len([node.op_type for node in training_model.graph.node if node.op_type == "ShrunkenGather"]) == 2 + else: + assert len([node.op_type for node in training_model.graph.node if node.op_type == "ShrunkenGather"]) == 1 + gathergrad_node = [node for node in training_model.graph.node if node.op_type == "PadAndUnflatten"][0] + + def find_input_node_type(model, arg): + result = [] + for node in model.graph.node: + if arg in node.output: + result.append(node) + return result[0].op_type if len(result) == 1 else None + + gathergrad_input_optypes = [find_input_node_type(training_model, arg) for arg in gathergrad_node.input] + if test_op == "Add" or test_op == "Mul" or test_op == "Sub": + assert test_op in gathergrad_input_optypes + else: + if case == 0: + assert test_op in gathergrad_input_optypes + else: + assert "ATen" in gathergrad_input_optypes + + del os.environ["ORTMODULE_ENABLE_EMBEDDING_SPARSE_OPTIMIZER"] + + +def test_e2e_padding_elimination(): + os.environ["ORTMODULE_ENABLE_EMBEDDING_SPARSE_OPTIMIZER"] = "1" + seed = 5033 + random.seed(seed) + np.random.seed(seed) + torch.manual_seed(seed) + torch.cuda.manual_seed(seed) + torch.cuda.manual_seed_all(seed) + torch.backends.cudnn.determinstic = True + torch.backends.cudnn.benchmark = False + + class OneLayer(torch.nn.Module): + def __init__(self, hidden_size, num_attention_heads): + super().__init__() + self.num_attention_heads = num_attention_heads + self.attention_head_size = int(hidden_size / num_attention_heads) + self.all_head_size = num_attention_heads * self.attention_head_size + self.query = nn.Linear(hidden_size, self.all_head_size) + self.key = nn.Linear(hidden_size, self.all_head_size) + self.value = nn.Linear(hidden_size, self.all_head_size) + self.dropout1 = nn.Dropout(0.0) + self.dense = nn.Linear(hidden_size, hidden_size) + self.LayerNorm = nn.LayerNorm(hidden_size, eps=1e-05) + self.dropout2 = nn.Dropout(0.0) + + def transpose_for_scores(self, x: torch.Tensor) -> torch.Tensor: + new_x_shape = x.size()[:-1] + (self.num_attention_heads, self.attention_head_size) + x = x.view(new_x_shape) + return x.permute(0, 2, 1, 3) + + def forward(self, hidden_states, attention_mask): + query_layer = self.transpose_for_scores(self.query(hidden_states)) + key_layer = self.transpose_for_scores(self.key(hidden_states)) + value_layer = self.transpose_for_scores(self.value(hidden_states)) + attention_scores = torch.matmul(query_layer, key_layer.transpose(-1, -2)) + attention_scores = attention_scores / math.sqrt(self.attention_head_size) + attention_scores = attention_scores + attention_mask + attention_probs = nn.functional.softmax(attention_scores, dim=-1) + attention_probs = self.dropout1(attention_probs) + context_layer = torch.matmul(attention_probs, value_layer) + context_layer = context_layer.permute(0, 2, 1, 3).contiguous() + new_context_layer_shape = context_layer.size()[:-2] + (self.all_head_size,) + context_layer = context_layer.view(new_context_layer_shape) + + output = self.dense(context_layer) + output = self.dropout2(output) + output = self.LayerNorm(output + hidden_states) + return output + + # This toy model is written referring to HuggingFace bert-large-uncased model in run_glue.py: + # https://github.com/huggingface/optimum/blob/72133e595f9a054c3221ec9ea87f42e0bdaa062b/examples/onnxruntime/training/text-classification/run_glue.py + # This is just a simple version of it for convenient testing. + class ToyModel(torch.nn.Module): + def __init__(self, num_hidden_layers, vocab_size, hidden_size, num_attention_heads, pad_token_id, num_labels): + super().__init__() + self.word_embeddings = nn.Embedding(vocab_size, hidden_size, padding_idx=pad_token_id) + self.token_type_embeddings = nn.Embedding(1, hidden_size) + self.LayerNorm = nn.LayerNorm(hidden_size, eps=1e-05) + self.dropout = nn.Dropout(0.0) + self.layer = nn.ModuleList([OneLayer(hidden_size, num_attention_heads) for _ in range(num_hidden_layers)]) + self.out_proj = nn.Linear(hidden_size, num_labels) + + def forward(self, input_ids, attention_mask, target): + input_shape = input_ids.size() + token_type_ids = torch.zeros(input_shape, dtype=torch.long).to(device) + inputs_embeds = self.word_embeddings(input_ids) + token_type_embeddings = self.token_type_embeddings(token_type_ids) + embeddings = inputs_embeds + token_type_embeddings + embeddings = self.LayerNorm(embeddings) + hidden_states = self.dropout(embeddings) + extended_attention_mask = attention_mask[:, None, None, :] + extended_attention_mask = extended_attention_mask.to(dtype=torch.float32) + extended_attention_mask = (1.0 - extended_attention_mask) * torch.finfo(torch.float32).min + for _, layer_module in enumerate(self.layer): + hidden_states = layer_module(hidden_states, extended_attention_mask) + x = hidden_states[:, 0, :] + x = self.out_proj(x) + loss_fct = torch.nn.CrossEntropyLoss() + return loss_fct(x, target) + + def run_step(model, inputs, mask, target): + loss = model(inputs, mask, target) + loss.backward() + return loss + + def run_optim_step(optimizer): + optimizer.step() + optimizer.zero_grad(set_to_none=False) + + # Generate one batch of inputs (shape:[batch_size, max_seq_length]) and masks (shape:[batch_size, max_seq_length]). + # Each input has random length from 1 to max_seq_length*0.8 with values from 2 to vocab_size and padded with 1 at + # [max_seq_length - length:]. Values of masks are 1 at [0:length] and 0 at [length:max_seq_length]. + def generate_inputs(batch_size, max_seq_length, vocab_size): + batched_inputs = [] + batched_masks = [] + for _ in range(batch_size): + # Generate random length from 1 to max_seq_length*0.8, to ensure sparsity > 20% + seq_len = random.randint(1, int(max_seq_length * 0.8)) + + # Generate input values and padding respectively and concatenate them + input_id = torch.randint(2, vocab_size, (seq_len,), dtype=torch.long, device=device) + padding = torch.ones((max_seq_length - seq_len,), dtype=torch.long, device=device) + batched_inputs.append(torch.cat((input_id, padding))) + + # Generate mask values and padding respectively and concatenate them + mask_ones = torch.ones((seq_len,), device=device) + mask_zeros = torch.zeros((max_seq_length - seq_len,), device=device) + batched_masks.append(torch.cat((mask_ones, mask_zeros))) + return torch.stack(batched_inputs), torch.stack(batched_masks) + + num_layers, vocab_size, hidden_size, num_attention_heads = 12, 50265, 768, 12 + batch_size, max_seq_length = 8, 128 + device = "cuda" + pt_model = ToyModel(num_layers, vocab_size, hidden_size, num_attention_heads, 1, 3).to(device) + ort_model = ORTModule(copy.deepcopy(pt_model)) + pt_optimizer = torch.optim.Adam(pt_model.parameters()) + ort_optimizer = torch.optim.Adam(ort_model.parameters()) + + for _ in range(10): + pt_input, pt_mask = generate_inputs(batch_size, max_seq_length, vocab_size) + ort_input = copy.deepcopy(pt_input) + ort_mask = copy.deepcopy(pt_mask) + pt_target = torch.randint(3, (batch_size,), device=device) + ort_target = copy.deepcopy(pt_target) + # Run one step of forward and backward for torch and ort respectively + pt_prediction = run_step(pt_model, pt_input, pt_mask, pt_target) + ort_prediction = run_step(ort_model, ort_input, ort_mask, ort_target) + + # Run one step of optimizer for torch and ort respectively + run_optim_step(pt_optimizer) + run_optim_step(ort_optimizer) + + for pt_param, ort_param in zip(pt_model.parameters(), ort_model.parameters()): + _test_helpers.assert_values_are_close(pt_param.grad, ort_param.grad, atol=1e-4, rtol=1e-5) + + if os.getenv("ORTMODULE_ROCM_TEST", "0") == "1": + # For ROCm EP, the difference between ORT and PyTorch is larger than CUDA EP. + _test_helpers.assert_values_are_close(ort_prediction, pt_prediction, atol=2e-3, rtol=2e-4) + else: + _test_helpers.assert_values_are_close(ort_prediction, pt_prediction, atol=1e-3, rtol=1e-4) + + training_model = ort_model._torch_module._execution_manager(True)._onnx_models.optimized_model + assert "ShrunkenGather" in [node.op_type for node in training_model.graph.node] + assert "PadAndUnflatten" in [node.op_type for node in training_model.graph.node] + del os.environ["ORTMODULE_ENABLE_EMBEDDING_SPARSE_OPTIMIZER"] + + +@pytest.mark.skipif( + Version(torch.__version__) >= Version("1.13.0"), + reason="PyTorch since 1.13 don't output expected warning messages any more", +) +@pytest.mark.parametrize("log_level", [LogLevel.VERBOSE, LogLevel.INFO, LogLevel.WARNING]) +def test_ortmodule_log_level_control(log_level, caplog): + class NeuralNetCrossEntropyLoss(torch.nn.Module): + def __init__(self, num_embeddings, embedding_dim): + super().__init__() + self.embedding = torch.nn.Embedding(num_embeddings, embedding_dim, padding_idx=1) + + def forward(self, input, positions): + output = torch.transpose(self.embedding(input), 0, 1) + ignored_index = output.size(1) + loss_fct = torch.nn.CrossEntropyLoss(ignore_index=ignored_index) + return loss_fct(output, positions) + + device = "cuda" + num_embeddings, embedding_dim = 32, 128 + pt_model = NeuralNetCrossEntropyLoss(num_embeddings, embedding_dim).to(device) + + ort_model = ORTModule(pt_model, DebugOptions(log_level=log_level)) + use_fp16 = True + + def run_step(model, input, positions): + with amp.autocast(use_fp16): + loss = model(input, positions) + loss.backward() + return loss + + N = random.randint(16, 32) # noqa: N806 + input = torch.randint(high=num_embeddings, size=(N,), dtype=torch.int64, device=device) + positions = torch.randint(high=N, size=(embedding_dim,), dtype=torch.int64, device=device) + _ = run_step(ort_model, input, positions) + + found_missing_inference_log = False + for record in caplog.records: + msg = record.getMessage() + if "The shape inference of com.microsoft::SoftmaxCrossEntropyLossInternal type is missing" in msg: + found_missing_inference_log = True + break + + if log_level == LogLevel.VERBOSE: + assert found_missing_inference_log + else: + assert not found_missing_inference_log + + +def test_cache_exported_model(): + class Net(torch.nn.Module): + def __init__(self): + super().__init__() + self.fc = torch.nn.Linear(10, 1) + + def forward(self, x): + x = x.view(x.shape[0], -1) + x = torch.nn.functional.relu(self.fc(x)) + return x + + data = torch.randn(1, 10) + + with tempfile.TemporaryDirectory() as temporary_dir: + os.environ["ORTMODULE_CACHE_DIR"] = temporary_dir + + # first time seeing the model, architecture should be cached under ORTMODULE_CACHE_DIR + model_pre_cache = Net() + model_pre_cache = ORTModule(model_pre_cache, DebugOptions(log_level=LogLevel.INFO)) + + torch.onnx.export = unittest.mock.MagicMock(side_effect=torch.onnx.export) + _ = model_pre_cache(data) + torch.onnx.export.assert_called() + torch.onnx.export.reset_mock() + + # second time seeing the model, architecture should be loaded from ORTMODULE_CACHE_DIR + model_post_cache = Net() + model_post_cache = ORTModule(model_post_cache, DebugOptions(log_level=LogLevel.INFO)) + + torch.onnx.export = unittest.mock.MagicMock(side_effect=torch.onnx.export) + _ = model_post_cache(data) + torch.onnx.export.assert_not_called() + torch.onnx.export.reset_mock() + + del os.environ["ORTMODULE_CACHE_DIR"] + + +def test_reciprocal_gradient(): + class ReciprocalModel(torch.nn.Module): + def __init__(self): + super().__init__() + + def forward(self, x): + return 1 / x + + def run_step(model, x): + prediction = model(x) + loss = prediction.sum() + loss.backward() + return prediction, loss + + device = "cuda" + pt_model = ReciprocalModel().to(device) + ort_model = ORTModule(copy.deepcopy(pt_model)) + + pt_x = torch.randn(3, 224, 224, requires_grad=True, device=device) + with torch.no_grad(): + pt_x[pt_x <= 0] -= 0.2 + pt_x[pt_x > 0] += 0.2 + ort_x = copy.deepcopy(pt_x) + + pt_prediction, pt_loss = run_step(pt_model, pt_x) + ort_prediction, ort_loss = run_step(ort_model, ort_x) + _test_helpers.assert_values_are_close(pt_prediction, ort_prediction) + _test_helpers.assert_values_are_close(pt_loss, ort_loss) + _test_helpers.assert_values_are_close(pt_x.grad, ort_x.grad) + + +def test_leakyrelu_gradient(): + class LeakyReluModel(torch.nn.Module): + def __init__(self): + super().__init__() + self.leakyrelu = nn.LeakyReLU(0.5) + + def forward(self, x): + return self.leakyrelu(x) + + def run_step(model, x): + prediction = model(x) + loss = prediction.sum() + loss.backward() + return prediction, loss + + device = "cuda" + pt_model = LeakyReluModel().to(device) + ort_model = ORTModule(copy.deepcopy(pt_model)) + + pt_x = torch.randn(3, 224, 224, requires_grad=True, device=device) + with torch.no_grad(): + pt_x[pt_x <= 0] -= 0.2 + pt_x[pt_x > 0] += 0.2 + ort_x = copy.deepcopy(pt_x) + + pt_prediction, pt_loss = run_step(pt_model, pt_x) + ort_prediction, ort_loss = run_step(ort_model, ort_x) + _test_helpers.assert_values_are_close(pt_prediction, ort_prediction) + _test_helpers.assert_values_are_close(pt_loss, ort_loss) + _test_helpers.assert_values_are_close(pt_x.grad, ort_x.grad) + + +@pytest.mark.skipif( + os.getenv("ORTMODULE_ROCM_TEST", "0") == "1", reason="Skip for ROCm because the kernel is not implemented for ROCm" +) +@pytest.mark.parametrize("use_fp16", [False, True]) +@pytest.mark.parametrize("conv_algo_search", [None, "EXHAUSTIVE", "HEURISTIC"]) +def test_conv_transpose_gradient(use_fp16, conv_algo_search): + class ChainedTransposedConv(nn.Module): + def __init__(self): + super().__init__() + + # Transposed Convolution 1D + self.conv1d_transpose = nn.ConvTranspose1d( + in_channels=4, out_channels=2, kernel_size=3, stride=2, padding=1 + ) + self.relu1 = nn.ReLU() + + # Transposed Convolution 2D + self.conv2d_transpose = nn.ConvTranspose2d( + in_channels=2, out_channels=3, kernel_size=3, stride=2, padding=1 + ) + self.relu2 = nn.ReLU() + + # Transposed Convolution 3D + self.conv3d_transpose = nn.ConvTranspose3d( + in_channels=3, out_channels=4, kernel_size=3, stride=2, padding=1 + ) + self.relu3 = nn.ReLU() + + def forward(self, x): + out1d = self.relu1(self.conv1d_transpose(x)) + out2d = self.relu2(self.conv2d_transpose(out1d.unsqueeze(2))) + out3d = self.relu3(self.conv3d_transpose(out2d.unsqueeze(2))) + return out3d.squeeze(2) + + if conv_algo_search is not None: + os.environ["ORTMODULE_CONV_ALGO_SEARCH"] = conv_algo_search + + def run_step(model, x): + with amp.autocast(use_fp16): + loss = model(x).sum() + loss.backward() + + return ( + x.grad, + model.conv1d_transpose.weight.grad, + model.conv1d_transpose.bias.grad, + model.conv2d_transpose.weight.grad, + model.conv2d_transpose.bias.grad, + model.conv3d_transpose.weight.grad, + model.conv3d_transpose.bias.grad, + ) + + device = "cuda" + pt_model = ChainedTransposedConv().to(device) + ort_model = ORTModule(copy.deepcopy(pt_model)) + + pt_x = torch.randn(1, 4, 8, requires_grad=True, device=device) + ort_x = copy.deepcopy(pt_x) + + pt_grads = run_step(pt_model, pt_x) + ort_grads = run_step(ort_model, ort_x) + + for pt_grad, ort_grad in zip(pt_grads, ort_grads): + if use_fp16: + assert torch.allclose(pt_grad, ort_grad, atol=1e-3, rtol=1e-3) + else: + assert torch.allclose(pt_grad, ort_grad) + + if conv_algo_search is not None: + del os.environ["ORTMODULE_CONV_ALGO_SEARCH"] + + +@pytest.mark.skipif( + os.getenv("ORTMODULE_ROCM_TEST", "0") == "1", reason="Skip for ROCm because the kernel is not implemented for ROCm" +) +@pytest.mark.parametrize("conv_algo_search", [None, "EXHAUSTIVE", "HEURISTIC"]) +def test_conv_transpose_gradient_with_groups(conv_algo_search): + class TransposedConv3DWithGroups(nn.Module): + def __init__(self): + super().__init__() + # in_channels, out_channels, kernel_size, stride, padding + self.conv_transpose = nn.ConvTranspose3d( + in_channels=6, out_channels=4, kernel_size=3, stride=2, padding=1, groups=2 + ) + + def forward(self, x): + return self.conv_transpose(x) + + if conv_algo_search is not None: + os.environ["ORTMODULE_CONV_ALGO_SEARCH"] = conv_algo_search + + def run_step(model, x): + loss = model(x).sum() + loss.backward() + + return ( + x.grad, + model.conv_transpose.weight.grad, + model.conv_transpose.bias.grad, + ) + + device = "cuda" + pt_model = TransposedConv3DWithGroups().to(device) + ort_model = ORTModule(copy.deepcopy(pt_model)) + + pt_x = torch.randn(1, 6, 8, 16, 16, requires_grad=True, device=device) + ort_x = copy.deepcopy(pt_x) + + pt_grads = run_step(pt_model, pt_x) + ort_grads = run_step(ort_model, ort_x) + + for pt_grad, ort_grad in zip(pt_grads, ort_grads): + assert torch.allclose(pt_grad, ort_grad) + + if conv_algo_search is not None: + del os.environ["ORTMODULE_CONV_ALGO_SEARCH"] + + +@pytest.mark.skipif( + os.getenv("ORTMODULE_ROCM_TEST", "0") == "1", reason="Skip for ROCm because the kernel is not implemented for ROCm" +) +@pytest.mark.parametrize("conv_algo_search", [None, "EXHAUSTIVE", "HEURISTIC"]) +def test_conv_transpose_gradient_with_strides_padding_and_dilation(conv_algo_search): + class ConvTransposeComplexModel(nn.Module): + def __init__(self): + super().__init__() + self.conv_transpose = nn.ConvTranspose3d( + 16, 33, (3, 5, 2), stride=(2, 1, 1), padding=(0, 4, 2), dilation=(1, 2, 1) + ) + self.param = nn.Parameter(torch.randn(20, 33, 21, 50, 97)) + + def forward(self, x): + return self.conv_transpose(x) * self.param + + if conv_algo_search is not None: + os.environ["ORTMODULE_CONV_ALGO_SEARCH"] = conv_algo_search + + def run_step(model, x): + loss = model(x).sum() + loss.backward() + + return ( + x.grad, + model.conv_transpose.weight.grad, + model.conv_transpose.bias.grad, + ) + + device = "cuda" + pt_model = ConvTransposeComplexModel().to(device) + ort_model = ORTModule(copy.deepcopy(pt_model)).to(device) + + pt_x = torch.randn(20, 16, 10, 50, 100, requires_grad=True, device=device) + ort_x = copy.deepcopy(pt_x) + + pt_grads = run_step(pt_model, pt_x) + ort_grads = run_step(ort_model, ort_x) + + for pt_grad, ort_grad in zip(pt_grads, ort_grads): + assert torch.allclose(pt_grad, ort_grad, atol=1e-2, rtol=1e-2) + + if conv_algo_search is not None: + del os.environ["ORTMODULE_CONV_ALGO_SEARCH"] diff --git a/orttraining/orttraining/test/python/orttraining_test_ortmodule_autograd.py b/orttraining/orttraining/test/python/orttraining_test_ortmodule_autograd.py index 33821843e4311..ae9bc4328cb26 100644 --- a/orttraining/orttraining/test/python/orttraining_test_ortmodule_autograd.py +++ b/orttraining/orttraining/test/python/orttraining_test_ortmodule_autograd.py @@ -5,11 +5,20 @@ # pylint: disable=C0103 # pylint: disable=W0212 +import copy +import os +from typing import Tuple + +import onnx import pytest import torch - -# FIXME: Remove star imports -from _test_helpers import * # noqa: F403 +from _test_helpers import ( + assert_gradients_match_and_reset_gradient, + assert_values_are_close, + compare_tensor_list, + run_evaluate_test_and_compare, + run_training_test_and_compare, +) from packaging.version import Version from torch.nn.parameter import Parameter @@ -28,10 +37,10 @@ def torch_version_lower_than(v): @pytest.fixture(scope="session", autouse=True) def run_before_test_session(request): def insert_disable_fallback_in_env(): - os.environ["ORTMODULE_FALLBACK_POLICY"] = "FALLBACK_DISABLE" # noqa: F405 + os.environ["ORTMODULE_FALLBACK_POLICY"] = "FALLBACK_DISABLE" def remove_disable_fallback_from_env(): - del os.environ["ORTMODULE_FALLBACK_POLICY"] # noqa: F405 + del os.environ["ORTMODULE_FALLBACK_POLICY"] insert_disable_fallback_in_env() request.addfinalizer(remove_disable_fallback_from_env) @@ -86,7 +95,7 @@ def input_generator(): # generate a label that have same shape as forward output. label_input = torch.ones([output_size]) - run_training_test_and_compare(model_builder, input_generator, label_input) # noqa: F405 + run_training_test_and_compare(model_builder, input_generator, label_input) def test_gelu_custom_func_rets_not_as_module_output(): @@ -144,7 +153,7 @@ def input_generator(): # generate a label that have same shape as forward output. label_input = torch.ones([output_size]) - run_training_test_and_compare(model_builder, input_generator, label_input) # noqa: F405 + run_training_test_and_compare(model_builder, input_generator, label_input) def test_gelu_multiple_forward_runs(): @@ -196,7 +205,7 @@ def input_generator(): # generate a label that have same shape as forward output. label_input = torch.ones([output_size]) - run_training_test_and_compare(model_builder, input_generator, label_input, run_forward_twice=True) # noqa: F405 + run_training_test_and_compare(model_builder, input_generator, label_input, run_forward_twice=True) def test_megatronf(): @@ -236,17 +245,43 @@ def input_generator(): # generate a label that have same shape as forward output. label_input = torch.ones([output_size]) - run_training_test_and_compare(model_builder, input_generator, label_input) # noqa: F405 + run_training_test_and_compare(model_builder, input_generator, label_input) def test_scalar_and_tuple(): + alpha_value = 5.0 + beta_value = (-1.0, 2.0) + gamma_value = -1.0 + delta_value = True + epsilon_value = (False, True) + zeta_value = 1 + eta_value = (2, 3) + theta_value = (3.0, 4.0) + class ScalarAndTupleFunction(torch.autograd.Function): @staticmethod - def forward(ctx, input, alpha, beta, gamma): + def forward( + ctx, + input, + alpha: float, + beta: Tuple[float, float], + gamma: float, + delta: bool, + epsilon: Tuple[bool, bool], + zeta: int, + eta: Tuple[int, int], + theta: Tuple[float, float], + ): ctx.save_for_backward(input) ctx.alpha = alpha ctx.beta = beta ctx.gamma = gamma + ctx.delta = delta + ctx.epsilon = epsilon + ctx.zeta = zeta + ctx.eta = eta + ctx.theta = theta + return alpha * beta[0] * beta[1] * gamma * input.clamp(min=0) @staticmethod @@ -257,7 +292,32 @@ def backward(ctx, grad_output): gamma = ctx.gamma grad_input = grad_output.clone() grad_input[input < 0] = 0 - return alpha * beta[0] * beta[1] * gamma * grad_input, None, None, None + + assert alpha == alpha_value + assert isinstance(alpha, float) + + assert all(a == b for a, b in zip(beta, beta_value)) + assert all(isinstance(x, float) for x in beta) + + assert gamma == gamma_value + assert isinstance(gamma, float) + + assert ctx.delta == delta_value + assert isinstance(ctx.delta, bool) + + assert all(a == b for a, b in zip(ctx.epsilon, epsilon_value)) + assert all(isinstance(x, bool) for x in ctx.epsilon) + + assert ctx.zeta == zeta_value + assert isinstance(ctx.zeta, int) + + assert all(a == b for a, b in zip(ctx.eta, eta_value)) + assert all(isinstance(x, int) for x in ctx.eta) + + assert all(a == b for a, b in zip(ctx.theta, theta_value)) + assert all(isinstance(x, float) for x in ctx.theta) + + return alpha * beta[0] * beta[1] * gamma * grad_input, None, None, None, None, None, None, None, None class ScalarAndTupleModel(torch.nn.Module): def __init__(self, output_size): @@ -268,7 +328,9 @@ def __init__(self, output_size): def forward(self, x): h = self.linear_a(x) - h = self.activation(h, 5.0, (-1.0, 2.0), -1.0) + h = self.activation( + h, alpha_value, beta_value, gamma_value, delta_value, epsilon_value, zeta_value, eta_value, theta_value + ) h = self.linear_b(h) return h @@ -283,7 +345,7 @@ def input_generator(): # generate a label that have same shape as forward output. label_input = torch.ones([output_size]) - run_training_test_and_compare(model_builder, input_generator, label_input) # noqa: F405 + run_training_test_and_compare(model_builder, input_generator, label_input) def test_scalar_and_tuple_reordered(): @@ -330,7 +392,7 @@ def input_generator(): # generate a label that have same shape as forward output. label_input = torch.ones([output_size]) - run_training_test_and_compare(model_builder, input_generator, label_input) # noqa: F405 + run_training_test_and_compare(model_builder, input_generator, label_input) def test_pointer_type(): @@ -365,7 +427,7 @@ def input_generator(): # generate a label that have same shape as forward output. label_input = torch.ones([output_size]) - run_training_test_and_compare(model_builder, input_generator, label_input) # noqa: F405 + run_training_test_and_compare(model_builder, input_generator, label_input) @pytest.mark.skip( @@ -415,7 +477,7 @@ def input_generator(): label_input = torch.ones([output_size]) # Test when input is in-place updated, but does not require gradient. - run_training_test_and_compare(model_builder, input_generator, label_input, ignore_grad_compare=True) # noqa: F405 + run_training_test_and_compare(model_builder, input_generator, label_input, ignore_grad_compare=True) @pytest.mark.skip( @@ -464,7 +526,7 @@ def input_generator(): # which is a duplicated computation with the PythonOp. # So for the weights that are used twice BUT SHOULD only used once, the gradients are almost 2x than PyTorch's grad, # this is the reason we ignore the gradient compare here. - run_training_test_and_compare(model_builder, input_generator, label_input, ignore_grad_compare=True) # noqa: F405 + run_training_test_and_compare(model_builder, input_generator, label_input, ignore_grad_compare=True) @pytest.mark.skip(reason="disable due to exporter bug https://github.com/microsoft/onnx-converters-private/issues/37.") @@ -511,7 +573,7 @@ def input_generator(): # generate a label that have same shape as forward output. label_input = torch.ones([output_size]) - run_training_test_and_compare(model_builder, input_generator, label_input) # noqa: F405 + run_training_test_and_compare(model_builder, input_generator, label_input) @pytest.mark.skip( @@ -563,7 +625,7 @@ def input_generator(): # duplicated computation with the PythonOp. Thus, for the weights that are used twice BUT SHOULD # only used once, the gradients are almost 2x than PyTorch's grad, this is the reason we # ignore the gradient compare here. - run_training_test_and_compare(model_builder, input_generator, label_input, ignore_grad_compare=True) # noqa: F405 + run_training_test_and_compare(model_builder, input_generator, label_input, ignore_grad_compare=True) @pytest.mark.skip( @@ -615,7 +677,7 @@ def input_generator(): # should reuse the input torch tensor @140214095996104, 140212816617984 but actually not." It seems # if we don't have mark_dirty() in auto grad forward, the result is not using the input_, # (maybe a view of it, because data address is same) - run_training_test_and_compare(model_builder, input_generator, label_input, ignore_grad_compare=True) # noqa: F405 + run_training_test_and_compare(model_builder, input_generator, label_input, ignore_grad_compare=True) ########################################################################################## @@ -665,7 +727,7 @@ def input_generator(): # generate a label that have same shape as forward output. label_input = torch.ones([output_size]) - run_training_test_and_compare(model_builder, input_generator, label_input) # noqa: F405 + run_training_test_and_compare(model_builder, input_generator, label_input) def test_evaluation(): @@ -706,7 +768,7 @@ def input_generator(): label_input = torch.ones([output_size]) # Test pure inferencing scenarios, when inputs don't requires_grad. - run_evaluate_test_and_compare(model_builder, input_generator, label_input) # noqa: F405 + run_evaluate_test_and_compare(model_builder, input_generator, label_input) @pytest.mark.skipif( @@ -770,7 +832,155 @@ def input_generator(): label_input = torch.ones([output_size]) # Test multi-input and multi-output custom function. - run_training_test_and_compare(model_builder, input_generator, label_input) # noqa: F405 + run_training_test_and_compare(model_builder, input_generator, label_input) + + +@pytest.mark.skipif( + torch_version_lower_than("1.10.0"), + reason="PyTorch older than 1.10.0 has bugs for exporting multiple output custom function", +) +def test_two_outputs_function_none_grad_fn(): + """This test is to verify the case that the first output tensor has grad_fn attr, but its grad_fn is None.""" + + class TwoOutputFunction(torch.autograd.Function): + @staticmethod + def forward(ctx, non_grad_fn_tensor, x, y): + z = x * y + # The first input is nn.Module input, who has grad_fn attr, but its grad_fn is None. + return ( + non_grad_fn_tensor, + z, + ) + + @staticmethod + def backward(ctx, dc, dz): + return dc, dz, dz + + class TwoOutputModel(torch.nn.Module): + def __init__(self, output_size): + super().__init__() + self.fun = TwoOutputFunction.apply + self.bias = Parameter(torch.empty(output_size, device=torch.cuda.current_device(), dtype=torch.float)) + self.int_type_tensor = torch.tensor([1, 4, 6, 7], device=torch.cuda.current_device(), dtype=torch.int64) + + with torch.no_grad(): + self.bias.uniform_() + + def forward(self, x): + non_grad_fn_tensor, a = self.fun(self.int_type_tensor, x, self.bias) + assert hasattr(non_grad_fn_tensor, "grad_fn") + assert non_grad_fn_tensor.grad_fn is None + return a + + output_size = 2 + + def model_builder(): + return TwoOutputModel(output_size) + + def input_generator(): + return torch.randn(output_size, dtype=torch.float) + + # generate a label that have same shape as forward output. + label_input = torch.ones([output_size]) + + # Test multi-input and multi-output custom function. + run_training_test_and_compare(model_builder, input_generator, label_input) + + +class MultipleOutputsFunctionWithNoGradOutput(torch.autograd.Function): + @staticmethod + def forward(ctx, x, y, test_config_materialize_grad): + ctx.save_for_backward(x, y) + w = x + y + z = x * y + u = z.to(torch.float32).sum() + + ctx.w_shape = w.shape + ctx.w_dtype = w.dtype + ctx.w_device = w.device + ctx.u_shape = u.shape + ctx.u_dtype = u.dtype + ctx.u_device = u.device + ctx.z_shape = z.shape + ctx.z_dtype = z.dtype + ctx.z_device = z.device + + ctx.set_materialize_grads(test_config_materialize_grad) + ctx.test_config_materialize_grad = test_config_materialize_grad + + # Note1: + # The requires_grad attribute values for w and z are both True, but in backward run, only z_grad will be needed. + # w_grad will be None/all zero. + return w, u, z + + @staticmethod + def backward(ctx, dw, du, dz): + x, y = ctx.saved_tensors + if ctx.test_config_materialize_grad: + assert dw is not None + assert du is not None + assert dz is not None + + assert dw.shape == ctx.w_shape + assert dw.dtype == ctx.w_dtype + assert dw.device == ctx.w_device + assert du.shape == ctx.u_shape + assert du.dtype == ctx.u_dtype + assert du.device == ctx.u_device + assert dz.shape == ctx.z_shape + assert dz.dtype == ctx.z_dtype + assert dz.device == ctx.z_device + else: + assert dw is None + assert du is not None + assert dz is not None + + assert du.shape == ctx.u_shape + assert du.dtype == ctx.u_dtype + assert du.device == ctx.u_device + assert dz.shape == ctx.z_shape + assert dz.dtype == ctx.z_dtype + assert dz.device == ctx.z_device + + dx = dz * y + dy = dz * x + return dx, dy, None + + +@pytest.mark.skipif( + torch_version_lower_than("1.10.0"), + reason="PyTorch older than 1.10.0 has bugs for exporting multiple output custom function", +) +@pytest.mark.parametrize("materialize_grad", [True, False]) +def test_multiple_outputs_function_with_no_grad_output(materialize_grad: bool): + class MultipleOutputsFunctionWithNoGradOutputModel(torch.nn.Module): + def __init__(self, output_size): + super().__init__() + self.fun = MultipleOutputsFunctionWithNoGradOutput.apply + self.bias = Parameter(torch.empty(output_size, device=torch.cuda.current_device(), dtype=torch.float)) + + with torch.no_grad(): + self.bias.uniform_() + + def forward(self, x): + # Be noted, the first output is not used in backward, so it should not require grad. + _, u, b = self.fun(x, self.bias, materialize_grad) + + return b * u.to(b.dtype) + + output_size = 2 + + def model_builder(): + return MultipleOutputsFunctionWithNoGradOutputModel(output_size) + + def input_generator(): + return torch.randn(output_size, dtype=torch.float) + + # generate a label that have same shape as forward output. + label_input = torch.ones([output_size]) + + # Test multi-input and multi-output custom function. + run_training_test_and_compare(model_builder, input_generator, label_input) def test_inner_module_call(): @@ -836,12 +1046,12 @@ def get_inner_module_call_result(x, device, use_ort): # Test indirect ORTModule call from custom function result_pth = get_inner_module_call_result(x.detach(), "cuda:0", False) result_ort = get_inner_module_call_result(x.detach(), "cuda:0", True) - compare_tensor_list(result_ort, result_pth) # noqa: F405 + compare_tensor_list(result_ort, result_pth) # Test indirect ORTModule call from custom function result_ort = get_inner_module_call_result(x.detach(), "cpu", True) result_pth = get_inner_module_call_result(x.detach(), "cpu", False) - compare_tensor_list(result_ort, result_pth) # noqa: F405 + compare_tensor_list(result_ort, result_pth) @pytest.mark.skipif( @@ -894,9 +1104,9 @@ def input_generator_with_requires_grad(): label_input = torch.ones([output_size]) # Test multi-input and multi-output custom function. - run_training_test_and_compare(model_builder, input_generator, label_input) # noqa: F405 + run_training_test_and_compare(model_builder, input_generator, label_input) - run_training_test_and_compare(model_builder, input_generator_with_requires_grad, label_input) # noqa: F405 + run_training_test_and_compare(model_builder, input_generator_with_requires_grad, label_input) def test_multiple_stream_in_forward_function(): @@ -942,7 +1152,7 @@ def input_generator(): label_input = torch.ones([output_size]) # Test multi-input and multi-output custom function. - run_training_test_and_compare( # noqa: F405 + run_training_test_and_compare( model_builder, input_generator, label_input, expected_outputs=[torch.tensor([0.224, 0.272])] ) @@ -990,7 +1200,7 @@ def input_generator(): label_input = torch.ones([output_size]) # Test multi-input and multi-output custom function. - run_training_test_and_compare( # noqa: F405 + run_training_test_and_compare( model_builder, input_generator, label_input, expected_outputs=[torch.tensor([0.224, 0.272])] ) @@ -1037,7 +1247,7 @@ def input_generator(): label_input = torch.ones([output_size]) # Test multi-input and multi-output custom function. - run_training_test_and_compare( # noqa: F405 + run_training_test_and_compare( model_builder, input_generator, label_input, expected_outputs=[torch.tensor([0.224, 0.272])] ) @@ -1086,7 +1296,7 @@ def input_generator(): label_input = torch.ones([output_size]) # Test multi-input and multi-output custom function. - run_training_test_and_compare( # noqa: F405 + run_training_test_and_compare( model_builder, input_generator, label_input, expected_outputs=[torch.tensor([0.224, 0.272])] ) @@ -1180,7 +1390,7 @@ def run(): print("Ref:") print(y_ref) - os.environ["ORTMODULE_ALLOW_AUTOGRAD_CHECKPOINT"] = "1" # noqa: F405 + os.environ["ORTMODULE_ALLOW_AUTOGRAD_CHECKPOINT"] = "1" m = ORTModule(m) @@ -1195,56 +1405,11 @@ def run(): print("Train:") assert torch.allclose(y_ref, y_train) - del os.environ["ORTMODULE_ALLOW_AUTOGRAD_CHECKPOINT"] # noqa: F405 + del os.environ["ORTMODULE_ALLOW_AUTOGRAD_CHECKPOINT"] run() -def test_skipped_autograd_function(): - class TestSkippedFunction(torch.autograd.Function): - @staticmethod - # bias is an optional argument - def forward(ctx, x): - ctx.save_for_backward(x) - return x * 0.5 * (1.0 + torch.tanh(0.79788456 * x * (1 + 0.044715 * x * x))) - - @staticmethod - def backward(ctx, grad_output): - return None - - class TestSkippedModel(torch.nn.Module): - def __init__(self, output_size): - super().__init__() - self.custom_fn = TestSkippedFunction.apply - self.bias = Parameter(torch.empty(output_size, device=torch.cuda.current_device(), dtype=torch.float)) - - with torch.no_grad(): - self.bias.uniform_() - - def forward(self, model_input): - # model_input did not require_grad - out = self.custom_fn(model_input) - return out + self.bias - - output_size = 1024 - - os.environ[ # noqa: F405 - "ORTMODULE_SKIPPED_AUTOGRAD_FUNCTIONS" - ] = "orttraining_test_ortmodule_autograd.test_skipped_autograd_function..TestSkippedFunction" - - m = ORTModule(TestSkippedModel(output_size).to("cuda")) - can_run = True - try: - m(torch.randn(output_size, dtype=torch.float, device="cuda")) - except RuntimeError as e: - assert "No forward registered for TestSkippedFunction" in str(e) - can_run = False - - assert not can_run - - del os.environ["ORTMODULE_SKIPPED_AUTOGRAD_FUNCTIONS"] # noqa: F405 - - def test_pythonop_training_mode(): def check_pythonop_training_mode(model, is_eval_mode): ## make sure the ort's PythonOp's training_mode is correct @@ -1307,7 +1472,6 @@ def forward(self, model_input): check_pythonop_training_mode(ortmodule, is_eval_mode=True) -@pytest.mark.skip(reason="TODO(yangu): need fix this test run random segment fault.") def test_python_op_save_input_for_backward(): class GeLUFunctionTakeActivationInput(torch.autograd.Function): @staticmethod @@ -1357,13 +1521,199 @@ def forward(self, x): x = torch.nn.functional.relu(layer(x)) return x + device = "cuda" + output_size = 1024 + pt_model = TestModule(output_size).to(device) + ort_model = ORTModule(copy.deepcopy(pt_model)) + + def _run_step(model, input): + loss = model(input).sum() + loss.backward() + return loss + + import warnings + + for index in range(10): + count = 0 + with warnings.catch_warnings(record=True) as w: + input = torch.randn(output_size, device=device, dtype=torch.float) + pt_prediction = _run_step(pt_model, input) + ort_prediction = _run_step(ort_model, input) + + assert_values_are_close(ort_prediction, pt_prediction, rtol=1e-04, atol=1.0) + assert_gradients_match_and_reset_gradient(ort_model, pt_model, atol=1e-5) + + for i in range(len(w)): + msg = str(w[i].message) + if "Add input index to _GlobalOpKernelInfoMap" in msg: + count += 1 + + if index == 0: + assert count == 1 + else: + assert count == 0 + + +class DupNamedFunction(torch.autograd.Function): + @staticmethod + def forward(ctx, input, bias): + ctx.save_for_backward(input, bias) + assert False # should not be called # noqa: B011 + return bias + input + + @staticmethod + def backward(ctx, grad_output): + assert False # should not be called # noqa: B011 + return grad_output, grad_output + + +def test_duplicate_named_functions(): + triggered = [False, False] + + class DupNamedFunction(torch.autograd.Function): + @staticmethod + def forward(ctx, input, bias): + ctx.save_for_backward(input, bias) + triggered[0] = True + return bias - input + + @staticmethod + def backward(ctx, grad_output): + triggered[1] = True + return -grad_output, grad_output + + class DpNamedModel(torch.nn.Module): + def __init__(self, output_size): + super().__init__() + self.relu = DupNamedFunction.apply + self.bias = Parameter(torch.empty(output_size, device=torch.cuda.current_device(), dtype=torch.float)) + + with torch.no_grad(): + self.bias.uniform_() + + def forward(self, model_input): + out = self.relu(model_input, self.bias) + return out + output_size = 1024 def model_builder(): - return TestModule(output_size) + return DpNamedModel(output_size) def input_generator(): - return torch.randn(output_size, output_size, dtype=torch.float).requires_grad_() + return torch.randn(output_size, dtype=torch.float) + # generate a label that have same shape as forward output. label_input = torch.ones([output_size]) - run_training_test_and_compare(model_builder, input_generator, label_input) # noqa: F405 + + run_training_test_and_compare(model_builder, input_generator, label_input) + + assert triggered[0] + assert triggered[1] + + +def test_customized_shape_inference(): + def _check_pythonop_shape(model): + graph = model._torch_module._execution_manager._training_manager._onnx_models.optimized_model.graph + found_pythonop = False + python_op_input = [] + python_op_output = [] + for node in graph.node: + if node.op_type == "PythonOp": + found_pythonop = True + python_op_input = node.input + python_op_output = node.output + break + + assert found_pythonop, "PythonOp should be found in the optimized_model" + + input_shapes = [None] + input_dtypes = [None] + + output_shapes = [None, None] + output_dtypes = [None, None] + + def _find_shape_and_dtype(value_infos): + for value_info in value_infos: + if value_info.name == python_op_input[0]: + input_shapes[0] = value_info.type.tensor_type.shape + input_dtypes[0] = value_info.type.tensor_type.elem_type + + if value_info.name == python_op_output[0]: + output_shapes[0] = value_info.type.tensor_type.shape + output_dtypes[0] = value_info.type.tensor_type.elem_type + + if value_info.name == python_op_output[1]: + output_shapes[1] = value_info.type.tensor_type.shape + output_dtypes[1] = value_info.type.tensor_type.elem_type + + _find_shape_and_dtype(graph.input) + _find_shape_and_dtype(graph.value_info) + + assert all(s is not None for s in input_shapes), "PythonOp input shape should be found in the optimized_model" + assert ( + all(d is not None for d in input_dtypes) is not None + ), "PythonOp input dtype should be found in the optimized_model" + + assert all(s is not None for s in output_shapes), "PythonOp output shape should be found in the optimized_model" + assert ( + all(d is not None for d in output_dtypes) is not None + ), "PythonOp output dtype should be found in the optimized_model" + + def _compare_shape(shape1, shape2): + if len(shape1.dim) != len(shape2.dim): + return False + + for dim1, dim2 in zip(shape1.dim, shape2.dim): + if dim1.HasField("dim_value") and dim1.HasField("dim_value") and dim1.dim_value == dim2.dim_value: + continue + + if dim1.HasField("dim_param") and dim1.HasField("dim_param") and dim1.dim_param == dim2.dim_param: + continue + + return False + + return True + + assert output_dtypes[0] == onnx.TensorProto.INT64 + assert len(output_shapes[0].dim) == 0 + assert _compare_shape(input_shapes[0], output_shapes[1]) + assert input_dtypes[0] == output_dtypes[1] + + class CustomShapeInferFunction(torch.autograd.Function): + @staticmethod + def forward(ctx, x): + ctx.save_for_backward(x) + return x * 0.5 * (1.0 + torch.tanh(0.79788456 * x * (1 + 0.044715 * x * x))) + + @staticmethod + def backward(ctx, grad_output): + x = ctx.saved_tensors + tanh_out = torch.tanh(0.79788456 * x * (1 + 0.044715 * x * x)) + ff = 0.5 * x * ((1 - tanh_out * tanh_out) * (0.79788456 + 0.1070322243 * x * x)) + 0.5 * (1 + tanh_out) + return ff * grad_output + + @staticmethod + def infer_shape(node: onnx.NodeProto, tensor_input_shapes, tensor_input_dtypes): + return [tensor_input_shapes[0]], [tensor_input_dtypes[0]] + + class TestModel(torch.nn.Module): + def __init__(self, output_size): + super().__init__() + self.custom_fn = CustomShapeInferFunction.apply + self.bias = Parameter(torch.empty(output_size, dtype=torch.float)) + + with torch.no_grad(): + self.bias.uniform_() + + def forward(self, model_input): + # model_input did not require_grad + out = self.custom_fn(model_input) + return out + self.bias + + output_size = 1024 + ortmodule = ORTModule( + TestModel(output_size), + ).train() + _ = ortmodule(torch.randn(output_size, dtype=torch.float)) + _check_pythonop_shape(ortmodule) diff --git a/orttraining/orttraining/test/python/orttraining_test_ortmodule_bert_classifier.py b/orttraining/orttraining/test/python/orttraining_test_ortmodule_bert_classifier.py index 856d61d23ccbc..3d92e0b323c19 100644 --- a/orttraining/orttraining/test/python/orttraining_test_ortmodule_bert_classifier.py +++ b/orttraining/orttraining/test/python/orttraining_test_ortmodule_bert_classifier.py @@ -220,7 +220,7 @@ def _download_dataset(download_dir): # Load the dataset into a pandas dataframe. df = pd.read_csv( - os.path.join(args.data_dir, "in_domain_train.tsv"), + os.path.join(args.data_dir if os.path.exists(args.data_dir) else "cola_public/raw", "in_domain_train.tsv"), delimiter="\t", header=None, names=["sentence_source", "label", "label_notes", "sentence"], diff --git a/orttraining/orttraining/test/python/orttraining_test_ortmodule_bert_classifier_autocast.py b/orttraining/orttraining/test/python/orttraining_test_ortmodule_bert_classifier_autocast.py index 04bd1f5e82cbd..87c8e66231a29 100644 --- a/orttraining/orttraining/test/python/orttraining_test_ortmodule_bert_classifier_autocast.py +++ b/orttraining/orttraining/test/python/orttraining_test_ortmodule_bert_classifier_autocast.py @@ -218,7 +218,7 @@ def _download_dataset(download_dir): # Load the dataset into a pandas dataframe. df = pd.read_csv( - os.path.join(args.data_dir, "in_domain_train.tsv"), + os.path.join(args.data_dir if os.path.exists(args.data_dir) else "cola_public/raw", "in_domain_train.tsv"), delimiter="\t", header=None, names=["sentence_source", "label", "label_notes", "sentence"], @@ -420,7 +420,7 @@ def main(): ) model = ORTModule(model, debug_options) - model._torch_module._execution_manager(is_training=True)._enable_grad_acc_optimization = True + model._torch_module._execution_manager(is_training=True)._runtime_options.enable_grad_acc_optimization = True # Tell pytorch to run this model on the GPU. if torch.cuda.is_available() and not args.no_cuda: diff --git a/orttraining/orttraining/test/python/orttraining_test_ortmodule_cache.py b/orttraining/orttraining/test/python/orttraining_test_ortmodule_cache.py new file mode 100755 index 0000000000000..f888152f03616 --- /dev/null +++ b/orttraining/orttraining/test/python/orttraining_test_ortmodule_cache.py @@ -0,0 +1,46 @@ +import os +import tempfile +import unittest.mock + +import torch + +from onnxruntime.training.ortmodule import DebugOptions, LogLevel, ORTModule + +torch.distributed.init_process_group(backend="nccl") + + +class Net(torch.nn.Module): + def __init__(self): + super().__init__() + self.fc = torch.nn.Linear(10, 1) + + def forward(self, x): + x = x.view(x.shape[0], -1) + x = torch.nn.functional.relu(self.fc(x)) + return x + + +data = torch.randn(1, 10) + +with tempfile.TemporaryDirectory() as temporary_dir: + os.environ["ORTMODULE_CACHE_DIR"] = temporary_dir + + # first time seeing the model, architecture should be cached under ORTMODULE_CACHE_DIR + model_pre_cache = Net() + model_pre_cache = ORTModule(model_pre_cache, DebugOptions(log_level=LogLevel.INFO)) + + torch.onnx.export = unittest.mock.MagicMock(side_effect=torch.onnx.export) + _ = model_pre_cache(data) + torch.onnx.export.assert_called() + torch.onnx.export.reset_mock() + + # second time seeing the model, architecture should be loaded from ORTMODULE_CACHE_DIR + model_post_cache = Net() + model_post_cache = ORTModule(model_post_cache, DebugOptions(log_level=LogLevel.INFO)) + + torch.onnx.export = unittest.mock.MagicMock(side_effect=torch.onnx.export) + _ = model_post_cache(data) + torch.onnx.export.assert_not_called() + torch.onnx.export.reset_mock() + + del os.environ["ORTMODULE_CACHE_DIR"] diff --git a/orttraining/orttraining/test/python/orttraining_test_ortmodule_experimental_json_config.py b/orttraining/orttraining/test/python/orttraining_test_ortmodule_experimental_json_config.py index cc46a2db95003..4350740690b91 100644 --- a/orttraining/orttraining/test/python/orttraining_test_ortmodule_experimental_json_config.py +++ b/orttraining/orttraining/test/python/orttraining_test_ortmodule_experimental_json_config.py @@ -38,27 +38,29 @@ def test_load_config_from_json_1(): ort_model_attributes = model._torch_module._execution_manager(training_mode) # test propagate cast ops - assert ort_model_attributes._propagate_cast_ops_strategy == C.PropagateCastOpsStrategy.FLOOD_FILL - assert ort_model_attributes._propagate_cast_ops_level == 3 - assert ort_model_attributes._propagate_cast_ops_allow == ["ABC", "DEF"] + assert ( + ort_model_attributes._runtime_options.propagate_cast_ops_strategy == C.PropagateCastOpsStrategy.FLOOD_FILL + ) + assert ort_model_attributes._runtime_options.propagate_cast_ops_level == 3 + assert ort_model_attributes._runtime_options.propagate_cast_ops_allow == ["ABC", "DEF"] # test use external gpu allocator - assert ort_model_attributes._use_external_gpu_allocator is False + assert ort_model_attributes._runtime_options.use_external_gpu_allocator is False # test enable custom autograd function - assert ort_model_attributes._enable_custom_autograd_function is True + assert ort_model_attributes._runtime_options.enable_custom_autograd_function is True # test use static shape - assert ort_model_attributes._use_static_shape is True + assert ort_model_attributes._runtime_options.use_static_shape is True # test run symbolic shape inference - assert ort_model_attributes._run_symbolic_shape_infer is False + assert ort_model_attributes._runtime_options.run_symbolic_shape_infer is False # test enable grad acc optimization - assert ort_model_attributes._enable_grad_acc_optimization is True + assert ort_model_attributes._runtime_options.enable_grad_acc_optimization is True # test skip check - assert ort_model_attributes._skip_check.value == 14 + assert ort_model_attributes._runtime_options.skip_check.value == 14 # test debug options assert ort_model_attributes._debug_options.save_onnx_models.save is True @@ -66,13 +68,13 @@ def test_load_config_from_json_1(): assert ort_model_attributes._debug_options.logging.log_level.name == "VERBOSE" # test use memory aware gradient builder. - assert ort_model_attributes._use_memory_efficient_gradient is False + assert ort_model_attributes._runtime_options.use_memory_efficient_gradient is False # test fallback policy assert ort_model_attributes._fallback_manager.policy.value == 1 # assert onnx opset version - assert ortmodule.ONNX_OPSET_VERSION == 13 + assert ort_model_attributes._runtime_options.onnx_opset_version == 13 def test_load_config_from_json_2(): @@ -91,27 +93,30 @@ def test_load_config_from_json_2(): ort_model_attributes = model._torch_module._execution_manager(training_mode) # test propagate cast ops - assert ort_model_attributes._propagate_cast_ops_strategy == C.PropagateCastOpsStrategy.INSERT_AND_REDUCE - assert ort_model_attributes._propagate_cast_ops_level == 5 - assert ort_model_attributes._propagate_cast_ops_allow == ["XYZ", "PQR"] + assert ( + ort_model_attributes._runtime_options.propagate_cast_ops_strategy + == C.PropagateCastOpsStrategy.INSERT_AND_REDUCE + ) + assert ort_model_attributes._runtime_options.propagate_cast_ops_level == 5 + assert ort_model_attributes._runtime_options.propagate_cast_ops_allow == ["XYZ", "PQR"] # test use external gpu allocator - assert ort_model_attributes._use_external_gpu_allocator is True + assert ort_model_attributes._runtime_options.use_external_gpu_allocator is True # test enable custom autograd function - assert ort_model_attributes._enable_custom_autograd_function is False + assert ort_model_attributes._runtime_options.enable_custom_autograd_function is False # test use static shape - assert ort_model_attributes._use_static_shape is False + assert ort_model_attributes._runtime_options.use_static_shape is False # test run symbolic shape inference - assert ort_model_attributes._run_symbolic_shape_infer is True + assert ort_model_attributes._runtime_options.run_symbolic_shape_infer is True # test enable grad acc optimization - assert ort_model_attributes._enable_grad_acc_optimization is False + assert ort_model_attributes._runtime_options.enable_grad_acc_optimization is False # test skip check - assert ort_model_attributes._skip_check.value == 10 + assert ort_model_attributes._runtime_options.skip_check.value == 10 # test debug options assert ort_model_attributes._debug_options.save_onnx_models.save is True @@ -119,10 +124,10 @@ def test_load_config_from_json_2(): assert ort_model_attributes._debug_options.logging.log_level.name == "INFO" # test use memory aware gradient builder. - assert ort_model_attributes._use_memory_efficient_gradient is True + assert ort_model_attributes._runtime_options.use_memory_efficient_gradient is True # test fallback policy assert ort_model_attributes._fallback_manager.policy.value == 250 # assert onnx opset version - assert ortmodule.ONNX_OPSET_VERSION == 12 + assert ort_model_attributes._runtime_options.onnx_opset_version == 12 diff --git a/orttraining/orttraining/test/python/orttraining_test_ortmodule_fallback.py b/orttraining/orttraining/test/python/orttraining_test_ortmodule_fallback.py index 7dc9b5aa24f75..34453c89157a8 100644 --- a/orttraining/orttraining/test/python/orttraining_test_ortmodule_fallback.py +++ b/orttraining/orttraining/test/python/orttraining_test_ortmodule_fallback.py @@ -78,11 +78,11 @@ def forward(self, point): else: with pytest.raises(_fallback.ORTModuleFallbackException) as type_error: ort_model(inputs) - assert "ORTModule does not support the following model data type" in str(type_error.value) + assert "ORTModule fails to extract schema from data" in str(type_error.value) else: with pytest.raises(_fallback.ORTModuleFallbackException) as type_error: ort_model(inputs) - assert "ORTModule does not support the following model data type" in str(type_error.value) + assert "ORTModule fails to extract schema from data" in str(type_error.value) @pytest.mark.parametrize( @@ -302,16 +302,18 @@ def __init__(self, x): with pytest.raises(_fallback.ORTModuleIOError) as ex_info: _ = ort_model(torch.randn(1, 2), CustomClass(1)) assert ( - "ORTModule does not support the following model data" - " type .CustomClass'>" in str(ex_info.value) ) else: with pytest.raises(_fallback.ORTModuleIOError) as ex_info: _ = ort_model(torch.randn(1, 2), CustomClass(1)) assert ( - "ORTModule does not support the following model data" - " type .CustomClass'>" in str(ex_info.value) ) @@ -533,7 +535,7 @@ def forward(self, x, y): @pytest.mark.parametrize("is_training,persist_fallback", list(itertools.product([True, False], repeat=2))) -def test_ortmodule_fallback_warn_message(is_training, persist_fallback): +def test_ortmodule_fallback_warn_message(is_training, persist_fallback, caplog): # is_training: True for torch.nn.Module training model, eval mode otherwise policy = "FALLBACK_UNSUPPORTED_DEVICE" @@ -555,18 +557,35 @@ def test_ortmodule_fallback_warn_message(is_training, persist_fallback): inputs = torch.randn(N, D_in, device=data_device) for i in range(3): - with pytest.raises(RuntimeError), pytest.warns(UserWarning) as warning_record: + # The run MUST fail no matter with ORT or PyTorch, so we catch the RuntimeError here in case it breaks the test. + # Be noted, the logs will be caught by caplog. + with pytest.raises(RuntimeError): ort_model(inputs) # For retries, the warn message will always be logged if not persist_fallback: - assert "Fallback to PyTorch due to exception" in str(warning_record[0].message.args[0]) + if i == 0: + # For the first time, run ORTModule, feature map is logged as warning + # And the fallback warning is logged. + assert len(caplog.records) >= 2 + else: + # For the other time, only the fallback warning is logged. + assert len(caplog.records) == 1 + assert "Fallback to PyTorch due to exception" in caplog.records[-1].message + caplog.clear() continue # If `retries` is not enabled, only log the warn message once if i == 0: - assert "Fallback to PyTorch due to exception" in str(warning_record[0].message.args[0]) + # For the first time, run ORTModule, feature map is logged as warning + # And the fallback warning is logged. + assert len(caplog.records) >= 2 + assert "Fallback to PyTorch due to exception" in caplog.records[-1].message + caplog.clear() else: - assert warning_record.list == [] + # For the other time, no fallback warning will be logged because + # we are running with PyTorch. + assert len(caplog.records) == 0 + caplog.clear() del os.environ["ORTMODULE_SKIPCHECK_POLICY"] diff --git a/orttraining/orttraining/test/python/orttraining_test_ortmodule_pytorch_ddp.py b/orttraining/orttraining/test/python/orttraining_test_ortmodule_pytorch_ddp.py index 85fe86ab93639..5006b7c30766c 100644 --- a/orttraining/orttraining/test/python/orttraining_test_ortmodule_pytorch_ddp.py +++ b/orttraining/orttraining/test/python/orttraining_test_ortmodule_pytorch_ddp.py @@ -146,6 +146,104 @@ def demo_checkpoint(rank, world_size, use_ort_module): cleanup() +""" +CustomEmbedding is adapted from +https://github.com/huggingface/transformers/blob/312b104ff65514736c0475814fec19e47425b0b5/src/transformers/models/distilbert/modeling_distilbert.py#L91. +""" + + +class CustomEmbeddings(nn.Module): + def __init__(self): + super().__init__() + vocab_size = 511 + dim = 10 + pad_token_id = 0 + max_position_embeddings = 16 + self.word_embeddings = nn.Embedding(vocab_size, dim, padding_idx=pad_token_id) + self.position_embeddings = nn.Embedding(max_position_embeddings, dim) + self.LayerNorm = nn.LayerNorm(dim, eps=1e-12) + self.register_buffer("position_ids", torch.arange(max_position_embeddings).expand((1, -1)), persistent=False) + + def forward(self, input_ids: torch.Tensor) -> torch.Tensor: + input_embeds = self.word_embeddings(input_ids) # (bs, max_seq_length, dim) + seq_length = input_embeds.size(1) + position_ids = self.position_ids[:, :seq_length] + position_embeddings = self.position_embeddings(position_ids) # (bs, max_seq_length, dim) + + embeddings = input_embeds + position_embeddings # (bs, max_seq_length, dim) + embeddings = self.LayerNorm(embeddings) # (bs, max_seq_length, dim) + return embeddings + + +""" +This module calls `CustomEmbeddings`, which will generate a series of nodes (Shape->Gather->Unsqueeze...) whos +allocate output tensors on CPU memory. Then this test can converge failures when CUDA EP enabled, CPU device +allocation and usage are correct. +""" + + +class AnotherLayerOfToyModel(nn.Module): + def __init__(self): + super().__init__() + self.embedding = CustomEmbeddings() + self.t = ToyModel() + + def forward(self, x): + embed_val = self.embedding(x) + return self.t(embed_val) + + +""" +`Mixed device allocation` here means ORT backend allocates output tensors on CPU for some nodes and +on CUDA for other nodes. This test could help catch regression when ORT allocation planner logic got changed with bugs. +""" + + +def demo_mixed_device_allocation_training(rank, world_size, use_ort_module): + torch.manual_seed(0) + print(f"Running basic DDP example on rank {rank}.") + setup(rank, world_size) + device = "cuda:" + str(rank) + + # create a model and move it to GPU with id rank + model = AnotherLayerOfToyModel().to(device) + if use_ort_module: + model = ORTModule(model) + print(f" Rank {rank} uses ORTModule.") + else: + print(f" Rank {rank} uses Pytorch's nn.Module.") + + ddp_model = DDP(model, device_ids=[device]) + + loss_fn = nn.MSELoss() + optimizer = optim.Adagrad(ddp_model.parameters(), lr=0.01) + + batch = 2 + max_seq_length = 16 + x = torch.randint(1, 511, (batch, max_seq_length)).to(device) + y = torch.randn(batch, max_seq_length, 5).to(device) + + loss_history = [] + + for i in range(5): + optimizer.zero_grad() + p = ddp_model(x) + loss = loss_fn(p, y) + with torch.no_grad(): + print(f" Rank {rank} at iteration {i} has loss {loss}.") + loss.backward() + optimizer.step() + with torch.no_grad(): + loss_history.append(torch.unsqueeze(loss, 0)) + + loss_history = torch.cat(loss_history).cpu() + expected_loss_history = torch.FloatTensor([1.1589857340, 1.0975260735, 1.0628030300, 1.0386666059, 1.0196533203]) + + assert torch.allclose(expected_loss_history, loss_history) + + cleanup() + + def run_demo(demo_fn, world_size, use_ort_module): mp.spawn(demo_fn, args=(world_size, use_ort_module), nprocs=world_size, join=True) @@ -160,3 +258,4 @@ def parse_args(): args = parse_args() run_demo(demo_basic, 4, args.use_ort_module) run_demo(demo_checkpoint, 4, args.use_ort_module) + run_demo(demo_mixed_device_allocation_training, 4, args.use_ort_module) diff --git a/orttraining/orttraining/test/python/orttraining_test_ortmodule_triton.py b/orttraining/orttraining/test/python/orttraining_test_ortmodule_triton.py new file mode 100644 index 0000000000000..318de843efb8f --- /dev/null +++ b/orttraining/orttraining/test/python/orttraining_test_ortmodule_triton.py @@ -0,0 +1,779 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import copy +import json +import os +import random + +import _test_helpers +import onnx +import pytest +import torch +from onnx import TensorProto, helper +from torch._C import _from_dlpack +from torch.utils.dlpack import to_dlpack + +from onnxruntime.training.ort_triton import call_triton_by_name, call_triton_by_onnx +from onnxruntime.training.ortmodule import DebugOptions, ORTModule + +pytest.importorskip("triton") + +DEVICE = "cuda" + + +@pytest.fixture(scope="session", autouse=True) +def run_before_test_session(request): + def insert_use_triton_env(): + os.environ["ORTMODULE_USE_TRITON"] = "1" + + def remove_use_triton_env(): + del os.environ["ORTMODULE_USE_TRITON"] + + insert_use_triton_env() + request.addfinalizer(remove_use_triton_env) + + +def _onnx_dtype_to_torch_dtype(onnx_dtype): + if onnx_dtype == TensorProto.FLOAT: + return torch.float32 + elif onnx_dtype == TensorProto.FLOAT16: + return torch.float16 + else: + raise RuntimeError("Unsupported ONNX dtype") + + +def _torch_add(input1, input2): + return input1 + input2 + + +def _torch_sub(input1, input2): + return input1 - input2 + + +def _torch_mul(input1, input2): + return input1 * input2 + + +def _torch_div(input1, input2): + return input1 / input2 + + +def _torch_pow(input, exponent): + return torch.pow(input, exponent) + + +def _torch_sqrt(input): + return torch.sqrt(input) + + +def _torch_exp(input): + return torch.exp(input) + + +def _torch_cast(input, **kwargs): + return input.to(_onnx_dtype_to_torch_dtype(kwargs.get("to"))) + + +def _torch_where(condition, x, y): + return torch.where(condition, x, y) + + +def _torch_sum(*inputs): + result = inputs[0] + for input in inputs[1:]: + result += input + return result + + +def _troch_dropout_gard(dy, mask, **kwargs): + ratio = kwargs.get("ratio", 0.5) + return torch.where(mask, dy / (1.0 - ratio), 0.0) + + +def _torch_softmax(input, **kwargs): + axis = kwargs.get("axis", -1) + return torch.softmax(input, axis) + + +def _torch_reduce(input, func, **kwargs): + rank = len(input.shape) + axes = kwargs.get("axes", [idx for idx in range(rank)]) + keepdims = kwargs.get("keepdims", True) + axes = [axis if axis >= 0 else rank + axis for axis in axes] + axes.sort(reverse=True) + result = input + for axis in axes: + result = func(result, dim=axis, keepdim=keepdims) + if func == torch.max or func == torch.min: + result = result[0] + return result + + +def _torch_reduce_sum(input, **kwargs): + return _torch_reduce(input, torch.sum, **kwargs) + + +def _torch_reduce_mean(input, **kwargs): + return _torch_reduce(input, torch.mean, **kwargs) + + +def _torch_reduce_max(input, **kwargs): + return _torch_reduce(input, torch.max, **kwargs) + + +def _torch_reduce_min(input, **kwargs): + return _torch_reduce(input, torch.min, **kwargs) + + +def _torch_layer_norm(input, weight, bias, **kwargs): + rank = len(input.shape) + axis = kwargs.get("axis", -1) + if axis < 0: + axis += rank + normalized_shape = input.shape[axis:] + return torch.nn.functional.layer_norm(input, normalized_shape, weight, bias) + + +class TorchFuncExecutor: + _INFER_FUNC_MAP = { # noqa: RUF012 + "Add": _torch_add, + "Sub": _torch_sub, + "Mul": _torch_mul, + "Div": _torch_div, + "Pow": _torch_pow, + "Sqrt": _torch_sqrt, + "Exp": _torch_exp, + "Cast": _torch_cast, + "Where": _torch_where, + "Sum": _torch_sum, + "DropoutGrad": _troch_dropout_gard, + "ReduceSum": _torch_reduce_sum, + "ReduceMean": _torch_reduce_mean, + "ReduceMax": _torch_reduce_max, + "ReduceMin": _torch_reduce_min, + "Softmax": _torch_softmax, + "LayerNormalization": _torch_layer_norm, + } + + @classmethod + def run(cls, op_type, *torch_tensors, **kwargs): + if op_type not in cls._INFER_FUNC_MAP: + raise NotImplementedError(f"Unsupported op type: {op_type}") + return cls._INFER_FUNC_MAP[op_type](*torch_tensors, **kwargs) + + +def _run_op_test(op_type, onnx_dtype, create_model_func, gen_inputs_func, **kwargs): + rtol = kwargs.get("rtol", 1e-03 if onnx_dtype == TensorProto.FLOAT16 else 1e-04) + atol = kwargs.get("atol", 1e-03 if onnx_dtype == TensorProto.FLOAT16 else 1e-05) + pt_inputs = gen_inputs_func(_onnx_dtype_to_torch_dtype(onnx_dtype)) + ort_inputs = copy.deepcopy(pt_inputs) + ort_inputs = [tensor.to(torch.uint8) if tensor.dtype == torch.bool else tensor for tensor in ort_inputs] + pt_outputs = TorchFuncExecutor.run(op_type, *pt_inputs, **kwargs) + model_str = create_model_func(op_type, onnx_dtype, **kwargs).SerializeToString() + ort_outputs = call_triton_by_onnx(hash(model_str), model_str, *[to_dlpack(tensor) for tensor in ort_inputs]) + if isinstance(pt_outputs, tuple): + assert isinstance(ort_outputs, tuple) + assert len(pt_outputs) == len(ort_outputs) + for pt_output, ort_output in zip(pt_outputs, ort_outputs): + _test_helpers.assert_values_are_close(pt_output, _from_dlpack(ort_output), rtol=rtol, atol=atol) + else: + _test_helpers.assert_values_are_close(pt_outputs, _from_dlpack(ort_outputs), rtol=rtol, atol=atol) + + +def _run_step(model, *tensors): + prediction = model(*tensors) + loss = prediction.sum() + loss.backward() + return prediction + + +def _run_module_test(module_cls, dtype, gen_inputs_func, triton_op_count, **kwargs): + pt_model = module_cls().to(DEVICE).to(dtype) + ort_model = ORTModule(copy.deepcopy(pt_model), DebugOptions(save_onnx=True, onnx_prefix="triton_model")) + rtol = kwargs.get("rtol", 1e-03 if dtype == torch.float16 else 1e-04) + atol = kwargs.get("atol", 1e-03 if dtype == torch.float16 else 1e-05) + for _ in range(10): + pt_inputs = gen_inputs_func(dtype) + ort_inputs = copy.deepcopy(pt_inputs) + pt_output = _run_step(pt_model, *pt_inputs) + ort_output = _run_step(ort_model, *ort_inputs) + _test_helpers.assert_values_are_close(pt_output, ort_output, rtol=rtol, atol=atol) + _test_helpers.assert_gradients_match_and_reset_gradient(pt_model, ort_model, rtol=rtol, atol=atol) + for i in range(len(pt_inputs)): + if pt_inputs[i].requires_grad: + _test_helpers.assert_values_are_close(pt_inputs[i].grad, ort_inputs[i].grad, rtol=rtol, atol=atol) + + assert os.path.exists(os.path.join(os.getcwd(), "triton_model_torch_exported_training.onnx")) + assert os.path.exists(os.path.join(os.getcwd(), "triton_model_optimized_training.onnx")) + assert os.path.exists(os.path.join(os.getcwd(), "triton_model_optimized_pre_grad_training.onnx")) + assert os.path.exists(os.path.join(os.getcwd(), "triton_model_execution_model_training.onnx")) + model = onnx.load(os.path.join(os.getcwd(), "triton_model_execution_model_training.onnx")) + actual_triton_op_count = 0 + for node in model.graph.node: + if node.op_type == "TritonOp": + actual_triton_op_count += 1 + assert actual_triton_op_count == triton_op_count + os.remove(os.path.join(os.getcwd(), "triton_model_torch_exported_training.onnx")) + os.remove(os.path.join(os.getcwd(), "triton_model_optimized_training.onnx")) + os.remove(os.path.join(os.getcwd(), "triton_model_optimized_pre_grad_training.onnx")) + os.remove(os.path.join(os.getcwd(), "triton_model_execution_model_training.onnx")) + + +def _run_tunable_op_test(module_cls, dtype, gen_inputs_func, tunable_op, impl_count, **kwargs): + pt_model = module_cls().to(DEVICE).to(dtype) + ort_model = ORTModule(copy.deepcopy(pt_model)) + rtol = kwargs.get("rtol", 1e-03 if dtype == torch.float16 else 1e-04) + atol = kwargs.get("atol", 1e-03 if dtype == torch.float16 else 1e-05) + os.environ["ORTMODULE_ENABLE_TUNING"] = "1" + os.environ["ORTMODULE_TUNING_RESULTS_PATH"] = "./" + for _ in range(5): + pt_inputs = gen_inputs_func(dtype) + ort_inputs = copy.deepcopy(pt_inputs) + pt_output = _run_step(pt_model, *pt_inputs) + ort_output = _run_step(ort_model, *ort_inputs) + _test_helpers.assert_values_are_close(pt_output, ort_output, rtol=rtol, atol=atol) + _test_helpers.assert_gradients_match_and_reset_gradient(pt_model, ort_model, rtol=rtol, atol=atol) + tunable_results_file = os.path.join(os.getcwd(), "tuning_results_training.json") + assert os.path.exists(tunable_results_file) + with open(tunable_results_file) as f: + tunable_results = json.load(f) + assert tunable_op in str(tunable_results) + del os.environ["ORTMODULE_ENABLE_TUNING"] + for i in range(impl_count - 1): + new_tunable_results = copy.deepcopy(tunable_results) + for k, v in new_tunable_results[0]["results"].items(): + if tunable_op in k: + for param, impl in v.items(): + v[param] = (impl + 1 + i) % impl_count + with open(tunable_results_file, "w") as f: + json.dump(new_tunable_results, f) + ort_model = ORTModule(copy.deepcopy(pt_model)) + for _ in range(5): + pt_inputs = gen_inputs_func(dtype) + ort_inputs = copy.deepcopy(pt_inputs) + pt_output = _run_step(pt_model, *pt_inputs) + ort_output = _run_step(ort_model, *ort_inputs) + _test_helpers.assert_values_are_close(pt_output, ort_output, rtol=rtol, atol=atol) + _test_helpers.assert_gradients_match_and_reset_gradient(pt_model, ort_model, rtol=rtol, atol=atol) + os.remove(tunable_results_file) + del os.environ["ORTMODULE_TUNING_RESULTS_PATH"] + + +@pytest.mark.parametrize("op_type", ["Add", "Sub", "Mul", "Div"]) +@pytest.mark.parametrize("onnx_dtype", [TensorProto.FLOAT, TensorProto.FLOAT16]) +@pytest.mark.parametrize("input_shapes", [([1024, 2], [1024, 2]), ([2, 3, 3, 3], [3, 1, 3]), ([2049], [1])]) +def test_binary_elementwise_op(op_type, onnx_dtype, input_shapes): + def _create_model(op_type, onnx_dtype): + graph = helper.make_graph( + [helper.make_node(op_type, ["X", "Y"], ["Z"], name="test")], + "test", + [ + helper.make_tensor_value_info("X", onnx_dtype, None), + helper.make_tensor_value_info("Y", onnx_dtype, None), + ], + [helper.make_tensor_value_info("Z", onnx_dtype, None)], + ) + return helper.make_model(graph, producer_name="test") + + def _gen_inputs(dtype): + return [ + torch.randn(*input_shapes[0], dtype=dtype, device=DEVICE), + torch.randn(*input_shapes[1], dtype=dtype, device=DEVICE), + ] + + _run_op_test(op_type, onnx_dtype, _create_model, _gen_inputs) + + +@pytest.mark.parametrize("onnx_dtype", [TensorProto.FLOAT, TensorProto.FLOAT16]) +@pytest.mark.parametrize("input_shapes", [([1024, 2], [1024, 2]), ([2, 3, 3, 3], [3, 1, 3], [2, 1, 3, 1])]) +def test_sum_op(onnx_dtype, input_shapes): + def _create_model(op_type, onnx_dtype): + graph = helper.make_graph( + [helper.make_node(op_type, [f"I{idx}" for idx in range(len(input_shapes))], ["O"], name="test")], + "test", + [helper.make_tensor_value_info(f"I{idx}", onnx_dtype, None) for idx in range(len(input_shapes))], + [helper.make_tensor_value_info("O", onnx_dtype, None)], + ) + return helper.make_model(graph, producer_name="test") + + def _gen_inputs(dtype): + return [torch.randn(*input_shape, dtype=dtype, device=DEVICE) for input_shape in input_shapes] + + _run_op_test("Sum", onnx_dtype, _create_model, _gen_inputs) + + +@pytest.mark.parametrize("op_type", ["Sqrt", "Exp"]) +@pytest.mark.parametrize("onnx_dtype", [TensorProto.FLOAT, TensorProto.FLOAT16]) +@pytest.mark.parametrize("input_shape", [[1024, 4], [2, 3, 3, 3], [2049, 1]]) +def test_unary_elementwise_op(op_type, onnx_dtype, input_shape): + def _create_model(op_type, onnx_dtype): + graph = helper.make_graph( + [helper.make_node(op_type, ["X"], ["Y"], name="test")], + "test", + [helper.make_tensor_value_info("X", onnx_dtype, None)], + [helper.make_tensor_value_info("Y", onnx_dtype, None)], + ) + return helper.make_model(graph, producer_name="test") + + def _gen_inputs(dtype): + return [torch.rand(*input_shape, dtype=dtype, device=DEVICE)] + + _run_op_test(op_type, onnx_dtype, _create_model, _gen_inputs) + + +@pytest.mark.parametrize("onnx_dtype", [TensorProto.FLOAT, TensorProto.FLOAT16]) +@pytest.mark.parametrize("input_shape_and_exponent", [([1024, 2], 2.0), ([2, 3, 3, 3], 0.5), ([2049], 3.0)]) +def test_pow_op(onnx_dtype, input_shape_and_exponent): + def _create_model(op_type, onnx_dtype): + graph = helper.make_graph( + [helper.make_node(op_type, ["X", "Y"], ["Z"], name="test")], + "test", + [ + helper.make_tensor_value_info("X", onnx_dtype, None), + helper.make_tensor_value_info("Y", onnx_dtype, None), + ], + [helper.make_tensor_value_info("Z", onnx_dtype, None)], + ) + return helper.make_model(graph, producer_name="test") + + def _gen_inputs(dtype): + return [ + torch.rand(*input_shape_and_exponent[0], dtype=dtype, device=DEVICE), + torch.tensor(input_shape_and_exponent[1], dtype=dtype, device=DEVICE), + ] + + _run_op_test("Pow", onnx_dtype, _create_model, _gen_inputs) + + +@pytest.mark.parametrize("onnx_dtype", [TensorProto.FLOAT, TensorProto.FLOAT16]) +@pytest.mark.parametrize("input_shape", [[1024, 2], [2, 3, 3, 3], [1, 2050]]) +def test_cast_op(onnx_dtype, input_shape): + def _create_model(op_type, onnx_dtype, **kwargs): + graph = helper.make_graph( + [helper.make_node(op_type, ["X"], ["Y"], name="test", **kwargs)], + "test", + [ + helper.make_tensor_value_info("X", onnx_dtype, None), + ], + [helper.make_tensor_value_info("Y", kwargs.get("to"), None)], + ) + return helper.make_model(graph, producer_name="test") + + def _gen_inputs(dtype): + return [torch.randn(*input_shape, dtype=dtype, device=DEVICE)] + + kwargs = {"to": TensorProto.FLOAT16 if onnx_dtype == TensorProto.FLOAT else TensorProto.FLOAT} + _run_op_test("Cast", onnx_dtype, _create_model, _gen_inputs, **kwargs) + + +@pytest.mark.parametrize("onnx_dtype", [TensorProto.FLOAT, TensorProto.FLOAT16]) +@pytest.mark.parametrize("input_shapes", [([2, 1024], [2, 1024], [2, 1024]), ([2, 1, 3, 1], [2, 3, 3, 3], [3, 1, 3])]) +def test_where_op(onnx_dtype, input_shapes): + def _create_model(op_type, onnx_dtype): + graph = helper.make_graph( + [helper.make_node(op_type, ["C", "X", "Y"], ["Z"], name="test")], + "test", + [ + helper.make_tensor_value_info("C", TensorProto.BOOL, None), + helper.make_tensor_value_info("X", onnx_dtype, None), + helper.make_tensor_value_info("Y", onnx_dtype, None), + ], + [helper.make_tensor_value_info("Z", onnx_dtype, None)], + ) + return helper.make_model(graph, producer_name="test") + + def _gen_inputs(dtype): + return [ + torch.rand(*input_shapes[0], dtype=dtype, device=DEVICE) < 0.5, + torch.randn(*input_shapes[1], dtype=dtype, device=DEVICE), + torch.randn(*input_shapes[2], dtype=dtype, device=DEVICE), + ] + + _run_op_test("Where", onnx_dtype, _create_model, _gen_inputs) + + +@pytest.mark.parametrize("onnx_dtype", [TensorProto.FLOAT, TensorProto.FLOAT16]) +@pytest.mark.parametrize("input_shape_and_ratio", [([1024, 2], 0.2), ([25, 75], 0.6), ([1, 2049], 0.5)]) +def test_dropout_op(onnx_dtype, input_shape_and_ratio): + graph = helper.make_graph( + [ + helper.make_node("Add", ["X1", "X2"], ["T1"], name="add1"), + helper.make_node("Dropout", ["T1", "ratio"], ["Y1", "mask1"], name="dropout1"), + helper.make_node("Add", ["Y1", "X3"], ["T2"], name="add2"), + helper.make_node("Dropout", ["T2", "ratio"], ["Y2", "mask2"], name="dropout2"), + ], + "test", + [ + helper.make_tensor_value_info("X1", onnx_dtype, None), + helper.make_tensor_value_info("X2", onnx_dtype, None), + helper.make_tensor_value_info("X3", onnx_dtype, None), + ], + [ + helper.make_tensor_value_info("Y1", onnx_dtype, None), + helper.make_tensor_value_info("mask1", TensorProto.BOOL, None), + helper.make_tensor_value_info("Y2", onnx_dtype, None), + helper.make_tensor_value_info("mask2", TensorProto.BOOL, None), + ], + initializer=[helper.make_tensor("ratio", TensorProto.FLOAT, (), [input_shape_and_ratio[1]])], + ) + model_str = helper.make_model(graph, producer_name="test").SerializeToString() + torch_dtype = _onnx_dtype_to_torch_dtype(onnx_dtype) + input_tensor = [ + torch.randn(*input_shape_and_ratio[0], dtype=torch_dtype, device=DEVICE), + torch.randn(*input_shape_and_ratio[0], dtype=torch_dtype, device=DEVICE), + torch.randn(*input_shape_and_ratio[0], dtype=torch_dtype, device=DEVICE), + ] + outputs = call_triton_by_onnx(hash(model_str), model_str, *[to_dlpack(t) for t in input_tensor]) + y1, mask1, y2, mask2 = tuple([_from_dlpack(o).detach().cpu().numpy().flatten() for o in outputs]) + x1 = (input_tensor[0] + input_tensor[1]).detach().cpu().numpy().flatten() + x2 = y1 * mask1 + input_tensor[2].detach().cpu().numpy().flatten() + + def _check_output(x, y, mask, ratio): + all_count = 0 + masked_count = 0 + for x_value, y_value, mask_value in zip(x, y, mask): + if mask_value: + assert abs(y_value - x_value / (1.0 - ratio)) < 0.05 + else: + assert y_value == 0 + if not mask_value: + masked_count += 1 + all_count += 1 + assert abs(masked_count / all_count - ratio) < 0.05 + + _check_output(x1, y1, mask1, input_shape_and_ratio[1]) + _check_output(x2, y2, mask2, input_shape_and_ratio[1]) + assert any(mask1[i] != mask2[i] for i in range(len(mask1))) + + +@pytest.mark.parametrize("onnx_dtype", [TensorProto.FLOAT, TensorProto.FLOAT16]) +@pytest.mark.parametrize("input_shape_and_ratio", [([1024, 2], 0.2), ([25, 75], 0.6), ([1, 2049], 0.5)]) +def test_dropout_grad_op(onnx_dtype, input_shape_and_ratio): + def _create_model(op_type, onnx_dtype, **kwargs): + graph = helper.make_graph( + [ + helper.make_node(op_type, ["dY", "mask", "ratio"], ["dX"], name="test", domain="com.microsoft"), + ], + "test", + [ + helper.make_tensor_value_info("dY", onnx_dtype, None), + helper.make_tensor_value_info("mask", TensorProto.BOOL, None), + ], + [helper.make_tensor_value_info("dX", onnx_dtype, None)], + initializer=[helper.make_tensor("ratio", TensorProto.FLOAT, (), [input_shape_and_ratio[1]])], + ) + return helper.make_model(graph, producer_name="test") + + def _gen_inputs(dtype): + return [ + torch.randn(*input_shape_and_ratio[0], dtype=dtype, device=DEVICE), + torch.rand(*input_shape_and_ratio[0], dtype=dtype, device=DEVICE) >= input_shape_and_ratio[1], + ] + + kwargs = {"ratio": input_shape_and_ratio[1]} + _run_op_test("DropoutGrad", onnx_dtype, _create_model, _gen_inputs, **kwargs) + + +@pytest.mark.parametrize("op_type", ["ReduceSum", "ReduceMean", "ReduceMax", "ReduceMin"]) +@pytest.mark.parametrize("onnx_dtype", [TensorProto.FLOAT, TensorProto.FLOAT16]) +@pytest.mark.parametrize( + "input_shape_and_reduce_info", + [ + ([2, 1024], [-1], True), + ([1050, 3], [0], False), + ([2, 3, 3, 3], [1, 2], True), + ([123, 4, 5, 6], [2], False), + ([16, 8, 16, 8], [1, 3], True), + ([16, 8, 16, 8], [0, 2], False), + ], +) +def test_reduce_op(op_type, onnx_dtype, input_shape_and_reduce_info): + def _create_model(op_type, onnx_dtype, **kwargs): + reduce_inputs = ["X"] + initializer = [] + if input_shape_and_reduce_info[1] is not None: + reduce_inputs.append("axes") + initializer.append( + helper.make_tensor( + "axes", + onnx.TensorProto.INT64, + [len(input_shape_and_reduce_info[1])], + input_shape_and_reduce_info[1], + ) + ) + node = ( + helper.make_node(op_type, reduce_inputs, ["Y"], name="test", keepdims=input_shape_and_reduce_info[2]) + if input_shape_and_reduce_info[2] is not None + else helper.make_node(op_type, reduce_inputs, ["Y"], name="test") + ) + graph = helper.make_graph( + [node], + "test", + [helper.make_tensor_value_info("X", onnx_dtype, None)], + [helper.make_tensor_value_info("Y", onnx_dtype, None)], + initializer=initializer, + ) + return helper.make_model(graph, producer_name="test") + + def _gen_inputs(dtype): + return [torch.randn(*input_shape_and_reduce_info[0], dtype=dtype, device=DEVICE)] + + kwargs = {} + if input_shape_and_reduce_info[1] is not None: + kwargs["axes"] = input_shape_and_reduce_info[1] + if input_shape_and_reduce_info[2] is not None: + kwargs["keepdims"] = input_shape_and_reduce_info[2] + if onnx_dtype == TensorProto.FLOAT16: + kwargs["atol"] = 1e-2 + kwargs["rtol"] = 1e-2 + _run_op_test(op_type, onnx_dtype, _create_model, _gen_inputs, **kwargs) + + +@pytest.mark.parametrize("onnx_dtype", [TensorProto.FLOAT, TensorProto.FLOAT16]) +@pytest.mark.parametrize("input_shape_and_axis", [([2, 1024], -1), ([2, 3, 3, 3], 1), ([4, 2049], 1)]) +def test_softmax_op(onnx_dtype, input_shape_and_axis): + def _create_model(op_type, onnx_dtype, **kwargs): + graph = helper.make_graph( + [helper.make_node(op_type, ["X"], ["Y"], name="test", **kwargs)], + "test", + [helper.make_tensor_value_info("X", onnx_dtype, None)], + [helper.make_tensor_value_info("Y", onnx_dtype, None)], + ) + return helper.make_model(graph, producer_name="test") + + def _gen_inputs(dtype): + return [torch.randn(*input_shape_and_axis[0], dtype=dtype, device=DEVICE)] + + kwargs = {"axis": input_shape_and_axis[1]} + _run_op_test("Softmax", onnx_dtype, _create_model, _gen_inputs, **kwargs) + + +@pytest.mark.parametrize("onnx_dtype", [TensorProto.FLOAT, TensorProto.FLOAT16]) +@pytest.mark.parametrize("input_shape_and_axis", [([2, 1024], -1), ([2, 3, 3, 3], 2), ([4, 2049], 1)]) +def test_layer_norm_op(onnx_dtype, input_shape_and_axis): + def _create_model(op_type, onnx_dtype, **kwargs): + graph = helper.make_graph( + [helper.make_node(op_type, ["X", "W", "B"], ["Y"], name="test", **kwargs)], + "test", + [ + helper.make_tensor_value_info("X", onnx_dtype, None), + helper.make_tensor_value_info("W", onnx_dtype, None), + helper.make_tensor_value_info("B", onnx_dtype, None), + ], + [helper.make_tensor_value_info("Y", onnx_dtype, None)], + ) + return helper.make_model(graph, producer_name="test") + + def _gen_inputs(dtype): + return [ + torch.randn(*input_shape_and_axis[0], dtype=dtype, device=DEVICE), + torch.randn(*input_shape_and_axis[0][input_shape_and_axis[1] :], dtype=dtype, device=DEVICE), + torch.randn(input_shape_and_axis[0][input_shape_and_axis[1] :], dtype=dtype, device=DEVICE), + ] + + kwargs = {"axis": input_shape_and_axis[1]} + _run_op_test("LayerNormalization", onnx_dtype, _create_model, _gen_inputs, **kwargs) + + +@pytest.mark.parametrize("dtype", [torch.float, torch.float16]) +@pytest.mark.parametrize( + "input_info", + [ + ([32, 64], False, [64, 16], False, 1.0), + ([33, 68], False, [18, 68], True, 0.5), + ([128, 64], True, [128, 32], False, 0.5), + ([123, 234], True, [345, 123], True, -1.0), + ([22, 33, 44], False, [44, 55], False, 1.0), + ([22, 33, 44], False, [666, 44], True, 0.2), + ([22, 33, 44], True, [33, 666], False, -0.2), + ([64, 128], False, [16, 64, 128], True, 0.5), + ([16, 32, 64], False, [16, 64, 32], False, 1.0), + ([8, 16, 32, 16], True, [8, 16, 32, 32], True, 1.0), + ], +) +def test_matmul(dtype, input_info): + pt_inputs = [ + torch.rand(*input_info[0], dtype=dtype, device=DEVICE), + torch.rand(*input_info[2], dtype=dtype, device=DEVICE), + ] + ort_inputs = copy.deepcopy(pt_inputs) + kwargs = {} + if input_info[1]: + pt_inputs[0] = pt_inputs[0].transpose(-1, -2) + kwargs["trans_a"] = True + if input_info[3]: + pt_inputs[1] = pt_inputs[1].transpose(-1, -2) + kwargs["trans_b"] = True + if input_info[4] != 1.0: + kwargs["alpha"] = input_info[4] + pt_output = torch.matmul(*pt_inputs) * input_info[4] + alloc_out = random.choice([True, False]) + if alloc_out: + ort_output = torch.empty(pt_output.shape, dtype=dtype, device=DEVICE) + ort_inputs.append(ort_output) + call_triton_by_name("triton_matmul_out", *[to_dlpack(tensor) for tensor in ort_inputs], **kwargs) + else: + ort_output = _from_dlpack( + call_triton_by_name("triton_matmul", *[to_dlpack(tensor) for tensor in ort_inputs], **kwargs) + ) + rtol = 1e-02 if dtype == torch.float16 else 1e-04 + atol = 1e-02 if dtype == torch.float16 else 1e-05 + _test_helpers.assert_values_are_close(pt_output, ort_output, rtol=rtol, atol=atol) + + +@pytest.mark.parametrize("dtype", [torch.float, torch.float16]) +@pytest.mark.parametrize( + "input_info", + [ + ([64, 32], False, [32, 64], False, [64, 64], 1.0, 0.0), + ([65, 129], False, [65, 129], True, [65, 1], 0.5, -0.5), + ([127, 63], True, [127, 127], False, [127], -1.0, 0.2), + ([256, 64], True, [128, 256], True, [1], 0.2, 0.5), + ], +) +def test_gemm(dtype, input_info): + pt_inputs = [ + torch.rand(*input_info[0], dtype=dtype, device=DEVICE), + torch.rand(*input_info[2], dtype=dtype, device=DEVICE), + torch.rand(*input_info[4], dtype=dtype, device=DEVICE), + ] + ort_inputs = copy.deepcopy(pt_inputs) + kwargs = {} + if input_info[1]: + pt_inputs[0] = pt_inputs[0].transpose(-1, -2) + kwargs["trans_a"] = True + if input_info[3]: + pt_inputs[1] = pt_inputs[1].transpose(-1, -2) + kwargs["trans_b"] = True + if input_info[5] != 1.0: + kwargs["alpha"] = input_info[5] + if input_info[6] != 1.0: + kwargs["beta"] = input_info[6] + pt_output = torch.matmul(pt_inputs[0], pt_inputs[1]) * input_info[5] + pt_inputs[2] * input_info[6] + alloc_out = random.choice([True, False]) + if alloc_out: + ort_output = torch.empty(pt_output.shape, dtype=dtype, device=DEVICE) + ort_inputs.append(ort_output) + call_triton_by_name("triton_gemm_out", *[to_dlpack(tensor) for tensor in ort_inputs], **kwargs) + else: + ort_output = _from_dlpack( + call_triton_by_name("triton_gemm", *[to_dlpack(tensor) for tensor in ort_inputs], **kwargs) + ) + rtol = 1e-02 if dtype == torch.float16 else 1e-04 + atol = 1e-02 if dtype == torch.float16 else 1e-05 + _test_helpers.assert_values_are_close(pt_output, ort_output, rtol=rtol, atol=atol) + + +@pytest.mark.parametrize("dtype", [torch.float32, torch.float16]) +def test_elementwise_module(dtype): + n, d, h, w = 8, 768, 12, 64 + + class NeuralNetElementwise(torch.nn.Module): + def forward(self, input1, input2, input3, input4): + return input1 + input2 - input3 * input4 + + def _gen_inputs(dtype): + return [ + torch.rand(n, d, h, w, dtype=dtype, device=DEVICE, requires_grad=True), + torch.rand(w, dtype=dtype, device=DEVICE, requires_grad=True), + torch.rand(d, 1, 1, dtype=dtype, device=DEVICE, requires_grad=True), + torch.rand(n, 1, h, w, dtype=dtype, device=DEVICE, requires_grad=True), + ] + + _run_module_test(NeuralNetElementwise, dtype, _gen_inputs, 1) + + +@pytest.mark.parametrize("dtype", [torch.float32, torch.float16]) +@pytest.mark.parametrize("input_shapes_and_axis", [([2, 3, 3, 3], [3, 3], 2), ([2, 1024], [2, 1024], -1)]) +def test_softmax_module(dtype, input_shapes_and_axis): + class NeuralNetSoftmax(torch.nn.Module): + def forward(self, input1, input2): + return torch.softmax(input1 * input2, dim=input_shapes_and_axis[2]) + + def _gen_inputs(dtype): + return [ + torch.randn(*input_shapes_and_axis[0], dtype=dtype, device=DEVICE, requires_grad=True), + torch.randn(*input_shapes_and_axis[1], dtype=dtype, device=DEVICE, requires_grad=True), + ] + + _run_module_test(NeuralNetSoftmax, dtype, _gen_inputs, 2) + + +@pytest.mark.parametrize("dtype", [torch.float32, torch.float16]) +@pytest.mark.parametrize( + "input_shapes_and_axis", [([2, 1024], [2, 1024], -1), ([2, 2049], [2, 1], -1), ([2, 3, 3, 3], [3, 3], 2)] +) +def test_layer_norm_module(dtype, input_shapes_and_axis): + pytest.skip("LayerNorm is disabled for now due to perf issue.") + + class NeuralNetLayerNorm(torch.nn.Module): + def __init__(self): + super().__init__() + self.layer_norm = torch.nn.LayerNorm( + input_shapes_and_axis[0][input_shapes_and_axis[2] :], device=DEVICE, dtype=dtype + ) + + def forward(self, input1, input2): + return self.layer_norm(input1 * input2) + + def _gen_inputs(dtype): + return [ + torch.randn(*input_shapes_and_axis[0], dtype=dtype, device=DEVICE, requires_grad=True), + torch.randn(*input_shapes_and_axis[1], dtype=dtype, device=DEVICE, requires_grad=True), + ] + + _run_module_test(NeuralNetLayerNorm, dtype, _gen_inputs, 2) + + +@pytest.mark.parametrize("dtype", [torch.float32, torch.float16]) +@pytest.mark.parametrize("has_sum", [True, False]) +def test_slice_scel_module(dtype, has_sum): + class NeuralNetSliceScel(torch.nn.Module): + def forward(self, logits, labels): + shift_logits = logits[..., :-1, :].contiguous() + labels = labels[..., 1:].contiguous() + loss_fct = torch.nn.CrossEntropyLoss() + loss = loss_fct(shift_logits.view(-1, shift_logits.size(-1)), labels.view(-1)) + return logits + loss if has_sum else loss + + def _gen_inputs(dtype): + return [ + (torch.rand(4, 8, 16) * 0.01).to(dtype=dtype, device=DEVICE).requires_grad_(True), + torch.randint(0, 16, (4, 8), dtype=torch.int64, device=DEVICE), + ] + + _run_module_test(NeuralNetSliceScel, dtype, _gen_inputs, 2) + + +@pytest.mark.parametrize("dtype", [torch.float32, torch.float16]) +@pytest.mark.parametrize("input_shapes", [([128, 64], [64, 64]), ([16, 64, 128], [16, 128, 64])]) +def test_matmul_tunable_op(dtype, input_shapes): + class NeuralNetMatmul(torch.nn.Module): + def forward(self, input1, input2): + return torch.matmul(input1, input2) + + def _gen_inputs(dtype): + return [ + torch.rand(*input_shapes[0], dtype=dtype, device=DEVICE, requires_grad=True), + torch.rand(*input_shapes[1], dtype=dtype, device=DEVICE, requires_grad=True), + ] + + _run_tunable_op_test(NeuralNetMatmul, dtype, _gen_inputs, "MatMulTunableOp", 2) + + +@pytest.mark.parametrize("dtype", [torch.float32, torch.float16]) +@pytest.mark.parametrize("m_n_k", [(64, 64, 64)]) +def test_gemm_tunable_op(dtype, m_n_k): + class NeuralNetGemm(torch.nn.Module): + def __init__(self): + super().__init__() + self.linear = torch.nn.Linear(m_n_k[2], m_n_k[1]) + + def forward(self, input): + return self.linear(input) + + def _gen_inputs(dtype): + return [torch.rand(m_n_k[0], m_n_k[2], dtype=dtype, device=DEVICE, requires_grad=True)] + + _run_tunable_op_test(NeuralNetGemm, dtype, _gen_inputs, "GemmTunableOp", 2) diff --git a/orttraining/orttraining/test/python/orttraining_test_orttrainer_bert_toy_onnx.py b/orttraining/orttraining/test/python/orttraining_test_orttrainer_bert_toy_onnx.py index aae92b3245685..45b87b32f7d64 100644 --- a/orttraining/orttraining/test/python/orttraining_test_orttrainer_bert_toy_onnx.py +++ b/orttraining/orttraining/test/python/orttraining_test_orttrainer_bert_toy_onnx.py @@ -134,7 +134,7 @@ def load_bert_onnx_model(): class CustomLossScaler(amp.LossScaler): - def __init__(self, loss_scale=float(1 << 16)): # noqa: B008 + def __init__(self, loss_scale=float(1 << 16)): super().__init__(loss_scale) self._initial_loss_scale = loss_scale self.loss_scale = loss_scale @@ -151,7 +151,7 @@ def update(self, train_step_info): class LegacyCustomLossScaler: - def __init__(self, loss_scale=float(1 << 16)): # noqa: B008 + def __init__(self, loss_scale=float(1 << 16)): self._initial_loss_scale = loss_scale self.loss_scale_ = loss_scale diff --git a/orttraining/orttraining/test/python/orttraining_test_orttrainer_frontend.py b/orttraining/orttraining/test/python/orttraining_test_orttrainer_frontend.py index 0382cec990195..fa13625f0ddac 100644 --- a/orttraining/orttraining/test/python/orttraining_test_orttrainer_frontend.py +++ b/orttraining/orttraining/test/python/orttraining_test_orttrainer_frontend.py @@ -28,7 +28,7 @@ def get_model_opset(model_onnx): for op in model_onnx.opset_import: - if op.domain == "": # noqa: PLC1901 + if op.domain == "": return op.version return None @@ -390,10 +390,10 @@ def testOptimizerConfig(optim_name, lr, alpha, default_alpha): # 1:1 mapping between defaults and params's hyper parameters for param in params: - for k, _ in param.items(): + for k in param: if k != "params": assert k in cfg.defaults, "hyper parameter {k} not present in one of the parameter params" - for k, _ in cfg.defaults.items(): + for k in cfg.defaults: for param in cfg.params: assert k in param, "hyper parameter {k} not present in one of the parameter params" @@ -1039,7 +1039,7 @@ def testORTTrainerInternalUseContribOps(enable_onnx_contrib_ops): # Training loop data, targets = batcher_fn(train_data, 0) if not enable_onnx_contrib_ops and not pytorch_110: - with pytest.raises(Exception): + with pytest.raises(Exception): # noqa: B017 _, _ = trainer.train_step(data, targets) else: _, _ = trainer.train_step(data, targets) diff --git a/orttraining/orttraining/test/python/orttraining_test_python_bindings.py b/orttraining/orttraining/test/python/orttraining_test_python_bindings.py index 65cf259327a6d..56338ddbaffef 100644 --- a/orttraining/orttraining/test/python/orttraining_test_python_bindings.py +++ b/orttraining/orttraining/test/python/orttraining_test_python_bindings.py @@ -4,14 +4,17 @@ from __future__ import annotations import os +import pathlib import tempfile import numpy as np +import onnx import pytest import torch from orttraining_test_onnxblock import _get_models import onnxruntime.training.onnxblock as onnxblock +from onnxruntime import OrtValue, SessionOptions from onnxruntime.training import artifacts from onnxruntime.training.api import CheckpointState, LinearLRScheduler, Module, Optimizer @@ -25,17 +28,25 @@ def build(self, output_name): return self.loss(output_name) -def _create_training_artifacts(artifact_directory: str | os.PathLike): +def _create_training_artifacts( + artifact_directory: str | os.PathLike, + requires_grad: list[str] | None = None, + frozen_params: list[str] | None = None, + optimizer_type=artifacts.OptimType.AdamW, +): device = "cpu" batch_size, input_size, hidden_size, output_size = 64, 784, 500, 10 pt_model, onnx_model = _get_models(device, batch_size, input_size, hidden_size, output_size) - requires_grad = [name for name, param in pt_model.named_parameters() if param.requires_grad] - frozen_params = [name for name, param in pt_model.named_parameters() if not param.requires_grad] + if requires_grad is None: + requires_grad = [name for name, param in pt_model.named_parameters() if param.requires_grad] + + if frozen_params is None: + frozen_params = [name for name, param in pt_model.named_parameters() if not param.requires_grad] artifacts.generate_artifacts( onnx_model, - optimizer=artifacts.OptimType.AdamW, + optimizer=optimizer_type, loss=artifacts.LossType.CrossEntropyLoss, requires_grad=requires_grad, frozen_params=frozen_params, @@ -66,7 +77,6 @@ def test_train_step(): # Create Checkpoint State. state = CheckpointState.load_checkpoint(checkpoint_file_path) # Create a Module. - print(training_model_file_path) model = Module(training_model_file_path, state) model.train() ort_loss = model(inputs, labels) @@ -104,7 +114,8 @@ def test_eval_step(): assert fetches -def test_optimizer_step(): +@pytest.mark.parametrize("optimizer_type", [artifacts.OptimType.SGD, artifacts.OptimType.AdamW]) +def test_optimizer_step(optimizer_type): # Generating random data for testing. inputs = torch.randn(64, 784).numpy() labels = torch.randint(high=10, size=(64,), dtype=torch.int64).numpy() @@ -116,7 +127,7 @@ def test_optimizer_step(): _, optimizer_model_file_path, _, - ) = _create_training_artifacts(temp_dir) + ) = _create_training_artifacts(temp_dir, optimizer_type=optimizer_type) # Create Checkpoint State. state = CheckpointState.load_checkpoint(checkpoint_file_path) # Create a Module and Optimizer. @@ -133,7 +144,8 @@ def test_optimizer_step(): assert not np.array_equal(old_flatten_params.numpy(), new_params.numpy()) -def test_get_and_set_lr(): +@pytest.mark.parametrize("optimizer_type", [artifacts.OptimType.SGD, artifacts.OptimType.AdamW]) +def test_get_and_set_lr(optimizer_type): with tempfile.TemporaryDirectory() as temp_dir: ( checkpoint_file_path, @@ -141,7 +153,7 @@ def test_get_and_set_lr(): _, optimizer_model_file_path, _, - ) = _create_training_artifacts(temp_dir) + ) = _create_training_artifacts(temp_dir, optimizer_type=optimizer_type) # Create Checkpoint State. state = CheckpointState.load_checkpoint(checkpoint_file_path) # Create a Module and Optimizer. @@ -159,7 +171,8 @@ def test_get_and_set_lr(): assert lr != new_lr -def test_scheduler_step(): +@pytest.mark.parametrize("optimizer_type", [artifacts.OptimType.SGD, artifacts.OptimType.AdamW]) +def test_scheduler_step(optimizer_type): # Generating random data for testing. inputs = torch.randn(64, 784).numpy() labels = torch.randint(high=10, size=(64,), dtype=torch.int64).numpy() @@ -171,7 +184,7 @@ def test_scheduler_step(): _, optimizer_model_file_path, _, - ) = _create_training_artifacts(temp_dir) + ) = _create_training_artifacts(temp_dir, optimizer_type=optimizer_type) # Create Checkpoint State. state = CheckpointState.load_checkpoint(checkpoint_file_path) # Create a Module and Optimizer. @@ -231,7 +244,9 @@ def test_training_module_checkpoint(): assert np.array_equal(old_flatten_params.numpy(), new_params.numpy()) -def test_copy_buffer_to_parameters(): +@pytest.mark.parametrize("optimizer_type", [artifacts.OptimType.SGD, artifacts.OptimType.AdamW]) +@pytest.mark.parametrize("trainable_only", [True, False]) +def test_copy_buffer_to_parameters(trainable_only, optimizer_type): # Generating random data for testing. inputs = torch.randn(64, 784).numpy() labels = torch.randint(high=10, size=(64,), dtype=torch.int64).numpy() @@ -243,7 +258,12 @@ def test_copy_buffer_to_parameters(): _, optimizer_model_file_path, _, - ) = _create_training_artifacts(temp_dir) + ) = _create_training_artifacts( + temp_dir, + requires_grad=["fc2.weight", "fc2.bias"], + frozen_params=["fc1.weight", "fc1.bias"], + optimizer_type=optimizer_type, + ) state = CheckpointState.load_checkpoint(checkpoint_file_path) # Create a Module and Optimizer. @@ -251,7 +271,7 @@ def test_copy_buffer_to_parameters(): optimizer = Optimizer(optimizer_model_file_path, model) # Keep a copy of the parameters. - old_output_params = model.get_contiguous_parameters() + old_output_params = model.get_contiguous_parameters(trainable_only=trainable_only) # Run a Training Step. model.train() @@ -259,15 +279,15 @@ def test_copy_buffer_to_parameters(): optimizer.step() # Get the new parameters. - output_params = model.get_contiguous_parameters() + output_params = model.get_contiguous_parameters(trainable_only=trainable_only) # Make sure old params are different from new params. assert not np.array_equal(old_output_params.numpy(), output_params.numpy()) # Copy the old parameters to the model. - model.copy_buffer_to_parameters(old_output_params) + model.copy_buffer_to_parameters(old_output_params, trainable_only=trainable_only) # Get the saved parameters. - saved_params = model.get_contiguous_parameters() + saved_params = model.get_contiguous_parameters(trainable_only=trainable_only) # Make sure the saved parameters are the same as the old parameters. assert np.array_equal(old_output_params.numpy(), saved_params.numpy()) @@ -366,5 +386,180 @@ def test_get_input_output_names(): # Create a Module. model = Module(training_model_file_path, state, eval_model_file_path) - assert model.input_names() == ["input-0", "labels"] - assert model.output_names() == ["onnx::loss::128"] + training_model = onnx.load(training_model_file_path) + assert model.input_names() == [input.name for input in training_model.graph.input][:2] + assert model.output_names() == [output.name for output in training_model.graph.output][:1] + + +def test_ort_custom_ops(): + def _create_custom_op_trainable_onnx_model(): + """This function takes in a pre generated custom op model and adds a trainable linear layer to it""" + onnx_model = onnx.load(os.path.join("testdata", "custom_op_library", "custom_op_test.onnx")) + onnx_model.graph.value_info.append( + onnx.helper.make_tensor_value_info("output_1", onnx.TensorProto.FLOAT, [3, 5]) + ) + + class CustomOpBlockWithLinear(onnxblock.ForwardBlock): + def __init__(self): + super().__init__() + self.linear = onnxblock.blocks.Linear(5, 10) + + def build(self, linear_input): + return self.linear(linear_input) + + custom_op_block = CustomOpBlockWithLinear() + with onnxblock.base(onnx_model) as model_accessor: + model_accessor.model.opset_import.append(onnx.helper.make_opsetid("test.customop", 1)) + model_accessor.model.opset_import.append(onnx.helper.make_opsetid("", 14)) + model_accessor.model.ir_version = 7 + _ = custom_op_block("output_1") + + return custom_op_block.to_model_proto() + + onnx_model = _create_custom_op_trainable_onnx_model() + custom_op_library = os.path.join(os.getcwd(), "libcustom_op_library.so") + with tempfile.TemporaryDirectory() as temp_dir: + artifacts.generate_artifacts( + onnx_model, + optimizer=artifacts.OptimType.AdamW, + loss=artifacts.LossType.CrossEntropyLoss, + requires_grad=[param.name for param in onnx_model.graph.initializer], + artifact_directory=temp_dir, + custom_op_library=custom_op_library, + ) + + session_options = SessionOptions() + session_options.register_custom_ops_library(custom_op_library) + + training_model_file_path = pathlib.Path(temp_dir) / "training_model.onnx" + eval_model_file_path = pathlib.Path(temp_dir) / "eval_model.onnx" + checkpoint_file_path = pathlib.Path(temp_dir) / "checkpoint" + + # Create Checkpoint State. + state = CheckpointState.load_checkpoint(checkpoint_file_path) + + # Create a Module. + # The custom op library is built either for cuda or cpu (but not for both). + # Since the training api pipeline build uses cuda, we need to specify the device as cuda. + # Otherwise the custom op library will not have the required kernels. + model = Module( + training_model_file_path, state, eval_model_file_path, device="cuda", session_options=session_options + ) + + x = np.random.randn(3, 5).astype(np.float32) + y = np.random.randn(3, 5).astype(np.float32) + labels = np.random.randint(0, 10, size=(3,), dtype=np.int64) + _ = model(x, y, labels) + + +def test_string_inputs(): + def _create_string_input_trainable_model(): + """This function creates an onnx model with string inputs""" + + class BlockWithStringInputs(onnxblock.ForwardBlock): + def __init__(self): + super().__init__() + self.cast = onnxblock.blocks.Cast(to=onnx.TensorProto.FLOAT) + self.linear = onnxblock.blocks.Linear(4, 2) + + def build(self, string_input): + return self.linear(self.cast(string_input)) + + string_block = BlockWithStringInputs() + with onnxblock.empty_base() as model_accessor: + model_accessor.model.graph.input.extend( + [ + onnx.helper.make_tensor_value_info("input", onnx.TensorProto.STRING, [1, 4]), + ] + ) + _ = string_block("input") + + return string_block.to_model_proto() + + onnx_model = _create_string_input_trainable_model() + with tempfile.TemporaryDirectory() as temp_dir: + artifacts.generate_artifacts( + onnx_model, + optimizer=artifacts.OptimType.AdamW, + loss=artifacts.LossType.CrossEntropyLoss, + requires_grad=[param.name for param in onnx_model.graph.initializer], + artifact_directory=temp_dir, + ) + + training_model_file_path = pathlib.Path(temp_dir) / "training_model.onnx" + eval_model_file_path = pathlib.Path(temp_dir) / "eval_model.onnx" + checkpoint_file_path = pathlib.Path(temp_dir) / "checkpoint" + + # Create Checkpoint State. + state = CheckpointState.load_checkpoint(checkpoint_file_path) + + # Create a Module. + model = Module(training_model_file_path, state, eval_model_file_path) + + strs = np.array([["1.0", "2.0", "3.0", "4.0"]], dtype=str) + labels = np.random.randint(0, 2, size=(1,), dtype=np.int64) + + model.train() + _ = model(strs, labels) + + model.eval() + _ = model(strs, labels) + + +def test_train_step_with_ort_values(): + # Generating random data for testing. + inputs_np = torch.randn(64, 784).numpy() + inputs = OrtValue.ortvalue_from_numpy(inputs_np) + labels_np = torch.randint(high=10, size=(64,), dtype=torch.int64).numpy() + labels = OrtValue.ortvalue_from_numpy(labels_np) + + with tempfile.TemporaryDirectory() as temp_dir: + ( + checkpoint_file_path, + training_model_file_path, + _, + _, + pt_model, + ) = _create_training_artifacts(temp_dir) + # Create Checkpoint State. + state = CheckpointState.load_checkpoint(checkpoint_file_path) + # Create a Module. + model = Module(training_model_file_path, state) + model.train() + ort_loss = model(inputs, labels) + assert isinstance(ort_loss, OrtValue) + + # Calculate loss using pytorch model to compare it with Module's output. + pt_outputs = pt_model(torch.from_numpy(inputs_np)) + loss_fn = torch.nn.CrossEntropyLoss() + pt_loss = loss_fn(pt_outputs, torch.from_numpy(labels_np).long()) + + assert np.allclose(ort_loss.numpy(), pt_loss.detach().numpy()) + + +def test_eval_step_with_ort_values(): + # Generating random data for testing. + inputs_np = torch.randn(64, 784).numpy() + inputs = OrtValue.ortvalue_from_numpy(inputs_np) + labels_np = torch.randint(high=10, size=(64,), dtype=torch.int64).numpy() + labels = OrtValue.ortvalue_from_numpy(labels_np) + + with tempfile.TemporaryDirectory() as temp_dir: + ( + checkpoint_file_path, + training_model_file_path, + eval_model_file_path, + _, + _, + ) = _create_training_artifacts(temp_dir) + # Create Checkpoint State. + state = CheckpointState.load_checkpoint(checkpoint_file_path) + # Create a Module. + model = Module(training_model_file_path, state, eval_model_file_path) + model.train() + model(inputs, labels) + + model.eval() + fetches = model(inputs, labels) + assert isinstance(fetches, OrtValue) + assert fetches diff --git a/orttraining/orttraining/test/python/orttraining_test_utilities.py b/orttraining/orttraining/test/python/orttraining_test_utilities.py new file mode 100644 index 0000000000000..0892bafcdb95d --- /dev/null +++ b/orttraining/orttraining/test/python/orttraining_test_utilities.py @@ -0,0 +1,290 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +from collections import abc + +import pytest +import torch + +from onnxruntime.training.utils import extract_data_and_schema, unflatten_data_using_schema +from onnxruntime.training.utils.torch_io_helper import _TensorStub + + +@pytest.mark.parametrize( + "input_output_map", + [ + # single element + [ + True, # test input + [], # expected output: flatten tensor list + True, # expected output: extracted schema + # expected output: flatten tensor list when constant_as_tensor=True + [torch.tensor(True)], + ], + [ + False, # test input + [], # expected output: flatten tensor list + False, # expected output: extracted schema + # expected output: flatten tensor list when constant_as_tensor=True + [torch.tensor(False)], + ], + [ + 1, # test input + [], # expected output: flatten tensor list + 1, # expected output: extracted schema + # expected output: flatten tensor list when constant_as_tensor=True + [torch.tensor(1)], + ], + [ + 2.0, # test input + [], # expected output: flatten tensor list + 2.0, # expected output: extracted schema + # expected output: flatten tensor list when constant_as_tensor=True + [torch.tensor(2.0)], + ], + [ + "abc", # test input + [], # expected output: flatten tensor list + "abc", # expected output: extracted schema + # expected output: flatten tensor list when constant_as_tensor=True + [], + ], + [ + None, # test input + [], # expected output: flatten tensor list + None, # expected output: extracted schema + # expected output: flatten tensor list when constant_as_tensor=True + [], + ], + [ + torch.tensor([1, 2, 3]), # test input + [torch.tensor([1, 2, 3])], # expected output: flatten tensor list + _TensorStub(tensor_idx=0, name="", dtype=torch.int64, shape_dims=1), # expected output: extracted schema + # expected output: flatten tensor list when constant_as_tensor=True + [torch.tensor([1, 2, 3])], + ], + # list + [ + [True, False, 1, 2.0, "abc", None], # test input + [], # expected output: flatten tensor list + [True, False, 1, 2.0, "abc", None], # expected output: extracted schema + # expected output: flatten tensor list when constant_as_tensor=True + [torch.tensor(True), torch.tensor(False), torch.tensor(1), torch.tensor(2.0)], + ], + [ + [True, False, 1, 2.0, "abc", None, torch.tensor([1, 2, 3]), torch.tensor([4, 5, 6])], + [torch.tensor([1, 2, 3]), torch.tensor([4, 5, 6])], + [ + True, + False, + 1, + 2.0, + "abc", + None, + _TensorStub(tensor_idx=0, name="6", dtype=torch.int64, shape_dims=1), + _TensorStub(tensor_idx=1, name="7", dtype=torch.int64, shape_dims=1), + ], + # for constant_as_tensor=True test + [ + torch.tensor(True), + torch.tensor(False), + torch.tensor(1), + torch.tensor(2.0), + torch.tensor([1, 2, 3]), + torch.tensor([4, 5, 6]), + ], + ], + # dict + [ + {"a": True, "b": False, "c": 1, "d": 2.0, "e": "abc", "f": None}, + [], + {"a": True, "b": False, "c": 1, "d": 2.0, "e": "abc", "f": None}, + # for constant_as_tensor=True test + [torch.tensor(True), torch.tensor(False), torch.tensor(1), torch.tensor(2.0)], + ], + [ + {"a": True, "b": False, "c": 1, "d": 2.0, "e": "abc", "f": None, "g": torch.tensor([1, 2, 3])}, + [torch.tensor([1, 2, 3])], + { + "a": True, + "b": False, + "c": 1, + "d": 2.0, + "e": "abc", + "f": None, + "g": _TensorStub(tensor_idx=0, name="g", dtype=torch.int64, shape_dims=1), + }, + # for constant_as_tensor=True test + [torch.tensor(True), torch.tensor(False), torch.tensor(1), torch.tensor(2.0), torch.tensor([1, 2, 3])], + ], + # list of list + [ + [[True, False, 1, 2.0, "abc", None]], + [], + [[True, False, 1, 2.0, "abc", None]], + # for constant_as_tensor=True test + [torch.tensor(True), torch.tensor(False), torch.tensor(1), torch.tensor(2.0)], + ], + [ + [[True, False, 1, 2.0, "abc", None, torch.tensor([1, 2, 3])]], + [torch.tensor([1, 2, 3])], + [ + [ + True, + False, + 1, + 2.0, + "abc", + None, + _TensorStub(tensor_idx=0, name="0_6", dtype=torch.int64, shape_dims=1), + ] + ], + # for constant_as_tensor=True test + [torch.tensor(True), torch.tensor(False), torch.tensor(1), torch.tensor(2.0), torch.tensor([1, 2, 3])], + ], + # list of dict + [ + [{"a": True, "b": False, "c": 1, "d": 2.0, "e": "abc", "f": None}], + [], + [{"a": True, "b": False, "c": 1, "d": 2.0, "e": "abc", "f": None}], + # for constant_as_tensor=True test + [torch.tensor(True), torch.tensor(False), torch.tensor(1), torch.tensor(2.0)], + ], + [ + [{"a": True, "b": False, "c": 1, "d": 2.0, "e": "abc", "f": None, "g": torch.tensor([1, 2, 3])}], + [torch.tensor([1, 2, 3])], + [ + { + "a": True, + "b": False, + "c": 1, + "d": 2.0, + "e": "abc", + "f": None, + "g": _TensorStub(tensor_idx=0, name="0_g", dtype=torch.int64, shape_dims=1), + } + ], + # for constant_as_tensor=True test + [torch.tensor(True), torch.tensor(False), torch.tensor(1), torch.tensor(2.0), torch.tensor([1, 2, 3])], + ], + # dict of list + [ + {"a": [True, False, 1, 2.0, "abc", None]}, + [], + {"a": [True, False, 1, 2.0, "abc", None]}, + # for constant_as_tensor=True test + [torch.tensor(True), torch.tensor(False), torch.tensor(1), torch.tensor(2.0)], + ], + [ + {"a": [True, False, 1, 2.0, "abc", None, torch.tensor([1, 2, 3])]}, + [torch.tensor([1, 2, 3])], + { + "a": [ + True, + False, + 1, + 2.0, + "abc", + None, + _TensorStub(tensor_idx=0, name="a_6", dtype=torch.int64, shape_dims=1), + ] + }, + # for constant_as_tensor=True test + [torch.tensor(True), torch.tensor(False), torch.tensor(1), torch.tensor(2.0), torch.tensor([1, 2, 3])], + ], + # dict of dict + [ + {"a": {"b": torch.tensor([1, 2, 3]), "c": torch.tensor([4, 5, 6])}}, + [torch.tensor([1, 2, 3]), torch.tensor([4, 5, 6])], + { + "a": { + "b": _TensorStub(tensor_idx=0, name="a_b", dtype=torch.int64, shape_dims=1), + "c": _TensorStub(tensor_idx=1, name="a_c", dtype=torch.int64, shape_dims=1), + } + }, + # for constant_as_tensor=True test + [torch.tensor([1, 2, 3]), torch.tensor([4, 5, 6])], + ], + # list of mixed types + [ + [[torch.tensor([[1.3]]), {"a": True}], {"b": torch.tensor([1, 2, 3]), "c": [torch.tensor([4, 5]), 2.0]}], + [torch.tensor([[1.3]]), torch.tensor([1, 2, 3]), torch.tensor([4, 5])], + [ + [_TensorStub(tensor_idx=0, name="0_0", dtype=torch.float32, shape_dims=2), {"a": True}], + { + "b": _TensorStub(tensor_idx=1, name="1_b", dtype=torch.int64, shape_dims=1), + "c": [_TensorStub(tensor_idx=2, name="1_c_0", dtype=torch.int64, shape_dims=1), 2.0], + }, + ], + # for constant_as_tensor=True test + [ + torch.tensor([[1.3]]), + torch.tensor(True), + torch.tensor([1, 2, 3]), + torch.tensor([4, 5]), + torch.tensor(2.0), + ], + ], + ], +) +@pytest.mark.parametrize( + "flag", + [0, 1, 2], +) # 0: flatten, 1: unflatten, 2: flatten and unflatten +def test_data_flatten_and_unflatten(input_output_map, flag: int): + raw_data = input_output_map[0] + flatten_data = input_output_map[1] + flatten_schema = input_output_map[2] + + def _recursive_compare(real, expected): + assert type(real) == type(expected) + if isinstance(real, str): + assert real == expected + elif isinstance(real, abc.Sequence): + assert len(real) == len(expected) + for i in range(len(real)): + _recursive_compare(real[i], expected[i]) + elif isinstance(real, abc.Mapping): + assert len(real.keys()) == len(expected.keys()) + for real_key, real_value in real.items(): + _recursive_compare(real_value, expected[real_key]) + else: + if isinstance(real, torch.Tensor): + assert torch.allclose(real, expected) + else: + assert real == expected + + if flag == 0: + out, schema = extract_data_and_schema(raw_data) + assert all([torch.allclose(o, d) if isinstance(o, torch.Tensor) else o == d for o, d in zip(out, flatten_data)]) + if not isinstance(raw_data, torch.Tensor): + assert type(schema) == type(raw_data) + + assert str(schema) == str(flatten_schema) + + flatten_data_constant_as_tensor = input_output_map[3] + out, schema = extract_data_and_schema(raw_data, constant_as_tensor=True, device=torch.device("cpu")) + if isinstance( + raw_data, + ( + type(None), + str, + ), + ): + assert raw_data == schema + else: + assert all( + [ + torch.allclose(o, d) if isinstance(o, torch.Tensor) else o == d + for o, d in zip(out, flatten_data_constant_as_tensor) + ] + ) + + elif flag == 1: + restored_data = unflatten_data_using_schema(flatten_data, flatten_schema) + _recursive_compare(restored_data, raw_data) + elif flag == 2: + out, schema = extract_data_and_schema(raw_data) + restored_data = unflatten_data_using_schema(out, schema) + + _recursive_compare(restored_data, raw_data) diff --git a/orttraining/orttraining/test/python/qat_poc_example/quantize.py b/orttraining/orttraining/test/python/qat_poc_example/quantize.py index 077738daff982..6d9ea284fd3ef 100644 --- a/orttraining/orttraining/test/python/qat_poc_example/quantize.py +++ b/orttraining/orttraining/test/python/qat_poc_example/quantize.py @@ -51,13 +51,12 @@ def quantize_static(input_model_dir, output_model_dir): # Quantize the model logging.info( - "Invoking onnxruntime.quantization.quantize_static with optimize_model=False, AddQDQPairToWeight=True and QuantizeBias=False.." + "Invoking onnxruntime.quantization.quantize_static with AddQDQPairToWeight=True and QuantizeBias=False.." ) logging.info("Quantized model will be saved to %s." % output_model_dir) quantization.quantize_static( input_model_dir, output_model_dir, calibration_data_reader, - optimize_model=False, extra_options=extra_options, ) diff --git a/orttraining/orttraining/test/session/training_session_test.cc b/orttraining/orttraining/test/session/training_session_test.cc index ff2935c0756bd..b6ed80c426afc 100644 --- a/orttraining/orttraining/test/session/training_session_test.cc +++ b/orttraining/orttraining/test/session/training_session_test.cc @@ -17,7 +17,6 @@ using namespace onnxruntime::logging; using namespace onnxruntime::training; -using namespace google::protobuf::util; using namespace onnxruntime::path_utils; using namespace onnxruntime::test::training_session_test_utils; @@ -35,7 +34,7 @@ static void RunTrainingSessionLoadOptimTests(std::string optim_name, bool mixed_ TrainingSession::OptimizerState init_optimizer_state{}; if (mixed_precision_moments) { - GenerateOptimizerInitialState(optim_name, MLFloat16(math::floatToHalf(2.5)), init_optimizer_state); + GenerateOptimizerInitialState(optim_name, MLFloat16(2.5f), init_optimizer_state); } else { GenerateOptimizerInitialState(optim_name, 2.5f, init_optimizer_state); } diff --git a/orttraining/orttraining/test/session/training_session_test_utils.cc b/orttraining/orttraining/test/session/training_session_test_utils.cc index d7cafa1f7ca3e..868388d4b9a93 100644 --- a/orttraining/orttraining/test/session/training_session_test_utils.cc +++ b/orttraining/orttraining/test/session/training_session_test_utils.cc @@ -8,7 +8,6 @@ using namespace onnxruntime::logging; using namespace onnxruntime::training; -using namespace google::protobuf::util; using namespace onnxruntime::path_utils; namespace onnxruntime { @@ -47,14 +46,14 @@ void GenerateOptimizerInitialState(const std::string& optimizer_op_name, const T optim_state.insert(std::make_pair(param_prefix, std::move(mlValue))); } if (optimizer_op_name == k_adam_optimizer_op_name) { - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), {1}, uc_value, &mlValue); + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], {1}, uc_value, &mlValue); optim_state.insert(std::make_pair(ADAM_UC_PREFIX, std::move(mlValue))); } result.insert(std::make_pair(weight_name, std::move(optim_state))); } if (optimizer_op_name == k_lamb_optimizer_op_name) { // add "Step" for lamb - CreateMLValue(TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), {1}, uc_value, &mlValue); + CreateMLValue(TestCPUExecutionProvider()->CreatePreferredAllocators()[0], {1}, uc_value, &mlValue); shared_states.insert(std::make_pair(LAMB_STEP_TENSOR_NAME, std::move(mlValue))); result.insert(std::make_pair(onnxruntime::training::SHARED_OPTIMIZER_STATES_KEY, std::move(shared_states))); } @@ -105,7 +104,7 @@ void VerifyState(const DataTransferManager& data_transfer_mgr, const NameMLValMa auto& actual_gpu_tensor = a_state_it.second.Get(); // Copying tensor to CPU when cuda is enabled. - auto cpu_allocator = TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault); + auto cpu_allocator = TestCPUExecutionProvider()->CreatePreferredAllocators()[0]; Tensor actual_tensor{actual_gpu_tensor.DataType(), actual_gpu_tensor.Shape(), cpu_allocator}; ORT_ENFORCE(data_transfer_mgr.CopyTensor(actual_gpu_tensor, actual_tensor).IsOK()); #else diff --git a/orttraining/orttraining/test/training_api/core/checkpoint_test.cc b/orttraining/orttraining/test/training_api/core/checkpoint_test.cc index 4fca303b26d66..1369c9c69865a 100644 --- a/orttraining/orttraining/test/training_api/core/checkpoint_test.cc +++ b/orttraining/orttraining/test/training_api/core/checkpoint_test.cc @@ -28,7 +28,7 @@ #include "test/test_environment.h" #include "test/util/include/asserts.h" #include "test/util/include/temp_dir.h" -#include "test/util/include/test/test_environment.h" +#include "test/util/include/test_environment.h" #include "orttraining/test/training_api/common/synthetic_data_loader.h" #include "orttraining/test/training_api/core/data_utils.h" #include "default_providers.h" @@ -36,11 +36,8 @@ using onnxruntime::test::TemporaryDirectory; using namespace onnxruntime::training::api; -namespace onnxruntime { -namespace training { -namespace test { +namespace onnxruntime::training::test { -namespace { #define MODEL_FOLDER ORT_TSTR("testdata/") /** @@ -90,9 +87,6 @@ TEST(CheckpointApiTest, SaveOnnxModelAsCheckpoint_ThenLoad_CPU) { // Remove the temporary directory if it already exists. auto ckpt_test_root_dir = ORT_TSTR("checkpointing_api_test_dir"); - if (Env::Default().FolderExists(ckpt_test_root_dir)) { - ORT_ENFORCE(Env::Default().DeleteFolder(ckpt_test_root_dir).IsOK()); - } TemporaryDirectory tmp_dir{ckpt_test_root_dir}; /// Phase 2 - Run save checkpoint APIs. @@ -100,25 +94,9 @@ TEST(CheckpointApiTest, SaveOnnxModelAsCheckpoint_ThenLoad_CPU) { // Call Save APIs. PathString checkpoint_path{ - ConcatPathComponent(tmp_dir.Path(), ORT_TSTR("e2e_ckpt_save_cpu"))}; + ConcatPathComponent(tmp_dir.Path(), ORT_TSTR("e2e_ckpt_save_cpu"))}; ASSERT_STATUS_OK(SaveCheckpoint(trainable_param_values, non_trainable_param_values, checkpoint_path)); - // Check the ckpt files in the directory. - std::set expected_file_names{ORT_TSTR("paramfrozen_tensors.pbseq"), ORT_TSTR("paramtrain_tensors.pbseq")}; - std::set valid_file_names; - LoopDir(checkpoint_path, - [&valid_file_names](const PathChar* filename, OrtFileType file_type) -> bool { - PathString filename_str = filename; - bool is_valid_ckpt_file_exts = HasExtensionOf(filename_str, ORT_TSTR("pbseq")); - if (filename_str[0] == '.' || file_type == OrtFileType::TYPE_DIR || !is_valid_ckpt_file_exts) { - return true; - } - valid_file_names.emplace(filename_str); - return true; - }); - - ASSERT_EQ(expected_file_names, valid_file_names); - /// Phase 3 - Run load checkpoint APIs. /// And check the result comparable with initial parameter values. @@ -160,6 +138,113 @@ TEST(CheckpointApiTest, SaveOnnxModelAsCheckpoint_ThenLoad_CPU) { } } +/** + * Load ONNX model from file path, save into ORT checkpoint files, + * Then load it into a bytes buffer and then load the buffer to a checkpoint, compare with the initial parameter values. + */ +TEST(CheckpointApiTest, SaveOnnxModelAsCheckpointThenLoadFromBufferCPU) { + /// Phase 1 - Test Preparation + /// Prepare the data and dest folder for saving checkpoint. + /// Also cooked the data for test result comparison. + + // Model path and trainable parameter name definitions. + auto model_uri = MODEL_FOLDER "transform/computation_reduction/gathernd/e2e.onnx"; + std::vector expected_trainable_param_names{ + "bert.encoder.layer.2.output.LayerNorm.weight", + "bert.encoder.layer.2.output.LayerNorm.bias", + "add1_initializerr", + "cls.predictions.transform.LayerNorm.weight", + "cls.predictions.transform.LayerNorm.bias", + "bert.embeddings.word_embeddings.weight_transposed", + "cls.predictions.bias", + }; + + // Extract a weight value baseline to compare. + // expected_trainable_param_name_to_ort_value is used to compare with the values after restoring from checkpoint. + auto logger_ptr = std::make_unique(logging::LoggingManager::DefaultLogger()); + std::shared_ptr p_model; + ORT_ENFORCE(Model::Load(model_uri, p_model, nullptr, *logger_ptr).IsOK()); + Graph& graph = p_model->MainGraph(); + + std::vector trainable_param_values; + trainable_param_values.reserve(expected_trainable_param_names.size()); + std::vector non_trainable_param_values; + const auto& initializer_tensors = graph.GetAllInitializedTensors(); + for (const auto& [initializer_name, tensor_proto] : initializer_tensors) { + if (std::find(expected_trainable_param_names.begin(), expected_trainable_param_names.end(), initializer_name) != + expected_trainable_param_names.end()) { + trainable_param_values.emplace_back(static_cast(*tensor_proto)); + } else { + non_trainable_param_values.emplace_back(static_cast(*tensor_proto)); + } + } + + std::unordered_map expected_trainable_param_name_to_ort_value; + ORT_ENFORCE(CreateOrtValuesFromTensorProtos(trainable_param_values, expected_trainable_param_name_to_ort_value) + .IsOK()); + + // Remove the temporary directory if it already exists. + auto ckpt_test_root_dir = ORT_TSTR("checkpointing_api_test_dir"); + TemporaryDirectory tmp_dir{ckpt_test_root_dir}; + + /// Phase 2 - Run save checkpoint APIs. + /// And check the result checkpoint files. + + // Call Save APIs. + PathString checkpoint_path{ + ConcatPathComponent(tmp_dir.Path(), ORT_TSTR("e2e_ckpt_save_cpu"))}; + ASSERT_STATUS_OK(SaveCheckpoint(trainable_param_values, non_trainable_param_values, checkpoint_path)); + + /// Phase 3 - Run load checkpoint APIs. + /// And check the result comparable with initial parameter values. + + // Call Load APIs + size_t num_bytes = 0; + ASSERT_STATUS_OK(Env::Default().GetFileLength(checkpoint_path.c_str(), num_bytes)); + std::vector checkpoint_bytes(num_bytes); + + std::ifstream bytes_stream(checkpoint_path, std::ifstream::in | std::ifstream::binary); + bytes_stream.read(reinterpret_cast(checkpoint_bytes.data()), num_bytes); + + ASSERT_TRUE(bytes_stream); + + CheckpointState checkpoint_state_to_load; + ASSERT_STATUS_OK(LoadCheckpointFromBuffer(checkpoint_bytes, checkpoint_state_to_load)); + ModuleCheckpointState module_state = checkpoint_state_to_load.module_checkpoint_state; + const auto& param_states = module_state.named_parameters; + std::unordered_map restored_param_name_to_ort_values; + std::vector restored_trainable_param_names; + for (auto it = param_states.begin(); it != param_states.end(); ++it) { + restored_param_name_to_ort_values.insert({it->first, it->second->Data()}); + if (it->second->RequiresGrad()) { + restored_trainable_param_names.emplace_back(it->first); + } + } + + // Check loaded parameter's values are same with original ones. + ASSERT_EQ(expected_trainable_param_name_to_ort_value.size(), restored_trainable_param_names.size()); + ASSERT_EQ(expected_trainable_param_name_to_ort_value.size(), 7); + ASSERT_EQ(restored_param_name_to_ort_values.size(), 9); + + std::sort(expected_trainable_param_names.begin(), expected_trainable_param_names.end()); + std::sort(restored_trainable_param_names.begin(), restored_trainable_param_names.end()); + ASSERT_EQ(expected_trainable_param_names, restored_trainable_param_names); + + for (const auto& name : restored_trainable_param_names) { + const auto& restored_ort_value = restored_param_name_to_ort_values[name]; + const auto& expected_ort_value = expected_trainable_param_name_to_ort_value.at(name); + + ASSERT_TRUE(restored_ort_value.IsTensor() && expected_ort_value.IsTensor()); + const Tensor& restored_tensor = restored_ort_value.Get(); + const Tensor& expected_tensor = expected_ort_value.Get(); + ASSERT_EQ(expected_tensor.DataType(), restored_tensor.DataType()); + ASSERT_EQ(expected_tensor.SizeInBytes(), restored_tensor.SizeInBytes()); + ASSERT_EQ(expected_tensor.DataType(), restored_tensor.DataType()); + + ASSERT_EQ(std::memcmp(expected_tensor.DataRaw(), restored_tensor.DataRaw(), expected_tensor.SizeInBytes()), 0); + } +} + /** * Load ONNX model with parameters set to 0 from file path, Load Checkpoint weights into the Model, * Then compare the new weights to 0 to make sure they were changed after loading checkpoint to model. @@ -171,7 +256,7 @@ TEST(CheckpointApiTest, LoadCheckpointToModel) { ASSERT_STATUS_OK(Model::Load(model_uri, p_model)); // Phase 2: Load the checkpoint weights into the Model. // Call Load APIs - auto checkpoint_uri = MODEL_FOLDER "training_api/load_checkpoint"; + auto checkpoint_uri = MODEL_FOLDER "training_api/checkpoint.ckpt"; ASSERT_STATUS_OK(LoadCheckpointToModel(checkpoint_uri, p_model)); // Phase 3: Make sure the Model's weights are not equal to zero after loading the new ones. @@ -191,14 +276,12 @@ TEST(CheckpointApiTest, LoadCheckpointToModel) { } /** - * Create Module with sets of parameters, - * Create Optimizer passing in Module's parameters. + * Create Module passing in checkpoint state, + * Create Optimizer passing in checkpoint state. * Save Optimizer states into ORT checkpoint files, * Then load it into ORT, compare with the initial optimizer states values. */ -#if defined(USE_CUDA) - -TEST(CheckpointApiTest, SaveOptimizerStateAsCheckpoint_ThenLoad_CUDA) { +TEST(CheckpointApiTest, SaveOptimizerStateAsCheckpoint_ThenLoad) { /// Phase 1 - Test Preparation /// Prepare the data and dest folder for saving checkpoint. /// Also cooked the data for test result comparison. @@ -206,7 +289,8 @@ TEST(CheckpointApiTest, SaveOptimizerStateAsCheckpoint_ThenLoad_CUDA) { auto optim_uri = "testdata/training_api/adamw.onnx"; // Generate randomized weight values using synthetic data generator. - constexpr int64_t fc2_weight_dim_in = 10, fc2_weight_dim_out = 500, fc1_weight_dim_in = 500, fc1_weight_dim_out = 784; + constexpr int64_t fc2_weight_dim_in = 10, fc2_weight_dim_out = 500, + fc1_weight_dim_in = 500, fc1_weight_dim_out = 784; const std::vector fc1_weight_shape{fc1_weight_dim_in, fc1_weight_dim_out}; const std::vector fc1_bias_shape{fc1_weight_dim_in}; const std::vector fc2_weight_shape{fc2_weight_dim_in, fc2_weight_dim_out}; @@ -243,73 +327,48 @@ TEST(CheckpointApiTest, SaveOptimizerStateAsCheckpoint_ThenLoad_CUDA) { onnxruntime::SessionOptions session_option; std::unique_ptr env; ORT_THROW_IF_ERROR(Environment::Create(nullptr, env)); - std::vector> cuda_provider{onnxruntime::test::DefaultCudaExecutionProvider()}; - auto model = std::make_unique(model_uri, &state, session_option, - *env, cuda_provider); - auto optimizer = std::make_unique(optim_uri, &state, session_option, - *env, cuda_provider); - - /// Phase 2 - Run Optimizer.GetStateDict and call save checkpoint APIs. - /// And check the result checkpoint files. - - CheckpointState checkpoint_state; - ORT_ENFORCE(optimizer->GetStateDict(checkpoint_state.optimizer_checkpoint_state).IsOK()); + std::vector> providers; +#if defined(USE_CUDA) + providers.push_back(onnxruntime::test::DefaultCudaExecutionProvider()); +#endif + auto model_identifier = ModelIdentifiers(onnxruntime::ToUTF8String(model_uri), + std::nullopt, + std::optional(onnxruntime::ToUTF8String(optim_uri))); + auto model = std::make_unique(model_identifier, &state, session_option, + *env, providers); + auto optimizer = std::make_unique(model_identifier, &state, session_option, + *env, providers); // Remove the temporary directory if it already exists. auto ckpt_test_root_dir = ORT_TSTR("checkpointing_api_test_dir"); - if (Env::Default().FolderExists(ckpt_test_root_dir)) { - ORT_ENFORCE(Env::Default().DeleteFolder(ckpt_test_root_dir).IsOK()); - } TemporaryDirectory tmp_dir{ckpt_test_root_dir}; // Call Save APIs. PathString checkpoint_path{ - ConcatPathComponent(tmp_dir.Path(), ORT_TSTR("e2e_ckpt_save_cpu"))}; - ASSERT_STATUS_OK(SaveCheckpoint(checkpoint_state, checkpoint_path, true)); - - // Check the ckpt files in the directory. - std::set expected_file_names{ - ORT_TSTR("optim_group0_momentum0_tensors.pbseq"), - ORT_TSTR("optim_group0_momentum1_tensors.pbseq"), - ORT_TSTR("optim_group0_properties.pbseq"), - }; - - std::set valid_file_names; - LoopDir(checkpoint_path, - [&valid_file_names, &checkpoint_path](const PathChar* filename, OrtFileType file_type) -> bool { - PathString filename_str = filename; - bool is_valid_ckpt_file_exts = - HasExtensionOf(filename_str, ORT_TSTR("pbseq")) || HasExtensionOf(filename_str, ORT_TSTR("bin")); - if (filename_str[0] == '.' || file_type == OrtFileType::TYPE_DIR || !is_valid_ckpt_file_exts) { - return true; - } - valid_file_names.emplace(filename_str); - return true; - }); - - ASSERT_EQ(expected_file_names, valid_file_names); + ConcatPathComponent(tmp_dir.Path(), ORT_TSTR("e2e_ckpt_save_cpu"))}; + ASSERT_STATUS_OK(SaveCheckpoint(state, checkpoint_path, true)); - /// Phase 3 - Run load checkpoint APIs. + /// Phase 2 - Run load checkpoint APIs. /// Validate the result matches with initial optimizer state values. // Call Load APIs CheckpointState checkpoint_state_to_load; ASSERT_STATUS_OK(LoadCheckpoint(checkpoint_path, checkpoint_state_to_load)); OptimizerCheckpointState optimizer_state = checkpoint_state_to_load.optimizer_checkpoint_state; - std::unordered_map>& + InlinedHashMap>& group_optimizer_states = optimizer_state.group_named_optimizer_states; ASSERT_EQ(group_optimizer_states.size(), 1); ASSERT_EQ(group_optimizer_states.begin()->first, "group0"); - std::unordered_map& + InlinedHashMap& param_named_optimizer_states = group_optimizer_states["group0"]->param_named_optimizer_states; ASSERT_EQ(param_named_optimizer_states.size(), named_parameters.size()); for (auto it = param_named_optimizer_states.begin(); it != param_named_optimizer_states.end(); ++it) { ASSERT_TRUE(named_parameters.find(it->first) != named_parameters.end()); - for (auto& [momentum_name, restored_ort_value] : it->second.momentum_named_states) { + for (auto& [momentum_name, restored_ort_value] : it->second) { ASSERT_TRUE(momentum_name == "momentum0" || momentum_name == "momentum1"); const OrtValue& param_ort_value = name_to_ort_value[it->first]; ASSERT_TRUE(restored_ort_value.IsTensor() && param_ort_value.IsTensor()); @@ -318,10 +377,9 @@ TEST(CheckpointApiTest, SaveOptimizerStateAsCheckpoint_ThenLoad_CUDA) { ASSERT_EQ(param_tensor.DataType(), restored_tensor.DataType()); ASSERT_EQ(param_tensor.SizeInBytes(), restored_tensor.SizeInBytes()); - ASSERT_EQ(param_tensor.DataType(), restored_tensor.DataType()); std::vector state_vect; - OrtValueToVec(restored_ort_value, state_vect); + CpuOrtValueToVec(restored_ort_value, state_vect); for (size_t i = 0; i < state_vect.size(); i++) { ASSERT_EQ(state_vect[i], 0.0f); } @@ -329,8 +387,6 @@ TEST(CheckpointApiTest, SaveOptimizerStateAsCheckpoint_ThenLoad_CUDA) { } } -#endif - /** * Create PropertyBag with sets of properties, * Save properties into ORT checkpoint files, @@ -357,9 +413,6 @@ TEST(CheckpointApiTest, SaveCustomPropertyAsCheckpoint_ThenLoad_CPU) { // Remove the temporary directory if it already exists. auto ckpt_test_root_dir = ORT_TSTR("checkpointing_api_test_dir"); - if (Env::Default().FolderExists(ckpt_test_root_dir)) { - ORT_ENFORCE(Env::Default().DeleteFolder(ckpt_test_root_dir).IsOK()); - } TemporaryDirectory tmp_dir{ckpt_test_root_dir}; /// Phase 2 - Call save checkpoint APIs. @@ -367,34 +420,14 @@ TEST(CheckpointApiTest, SaveCustomPropertyAsCheckpoint_ThenLoad_CPU) { // Call Save APIs. PathString checkpoint_path{ - ConcatPathComponent(tmp_dir.Path(), ORT_TSTR("e2e_ckpt_save_cpu"))}; - ASSERT_STATUS_OK(SaveCheckpoint(checkpoint_state, checkpoint_path, true)); - - // Check the ckpt files in the directory. - std::set expected_file_names{ - ORT_TSTR("custom_properties.pbseq"), - }; - - std::set valid_file_names; - LoopDir(checkpoint_path, - [&valid_file_names](const PathChar* filename, OrtFileType file_type) -> bool { - PathString filename_str = filename; - bool is_valid_ckpt_file_exts = - HasExtensionOf(filename_str, ORT_TSTR("pbseq")) || HasExtensionOf(filename_str, ORT_TSTR("bin")); - if (filename_str[0] == '.' || file_type == OrtFileType::TYPE_DIR || !is_valid_ckpt_file_exts) { - return true; - } - valid_file_names.emplace(filename_str); - return true; - }); - - ASSERT_EQ(expected_file_names, valid_file_names); + ConcatPathComponent(tmp_dir.Path(), ORT_TSTR("e2e_ckpt_save_cpu"))}; + ASSERT_STATUS_OK(SaveCheckpoint(checkpoint_state, checkpoint_path, false)); // Call Load APIs CheckpointState checkpoint_state_to_load; ASSERT_STATUS_OK(LoadCheckpoint(checkpoint_path, checkpoint_state_to_load)); PropertyBag& restored_property_bag = checkpoint_state_to_load.property_bag; - ASSERT_EQ(restored_property_bag.Size(), 3); + ASSERT_EQ(restored_property_bag.size(), 3); float restored_f_data = restored_property_bag.GetProperty(f_property_name); ASSERT_FLOAT_EQ(f_data, restored_f_data); int64_t restored_i_data = restored_property_bag.GetProperty(i_property_name); @@ -402,7 +435,4 @@ TEST(CheckpointApiTest, SaveCustomPropertyAsCheckpoint_ThenLoad_CPU) { std::string restored_s_data = restored_property_bag.GetProperty(s_property_name); ASSERT_EQ(s_data, restored_s_data); } -} // namespace -} // namespace test -} // namespace training -} // namespace onnxruntime +} // namespace onnxruntime::training::test diff --git a/orttraining/orttraining/test/training_api/core/data_utils.h b/orttraining/orttraining/test/training_api/core/data_utils.h index 815fbd1b8a2f4..7724bc0c26fa3 100644 --- a/orttraining/orttraining/test/training_api/core/data_utils.h +++ b/orttraining/orttraining/test/training_api/core/data_utils.h @@ -8,26 +8,28 @@ #include "core/framework/ort_value.h" #include "core/framework/tensor.h" +#include "default_providers.h" #include "test/framework/test_utils.h" #include "test/util/include/test_utils.h" namespace onnxruntime::training::test { template -void OrtValueToVec(const OrtValue& val, std::vector& output) { - const Tensor& tensor = val.Get(); +void CpuOrtValueToVec(const OrtValue& src_cpu_ortvalue, std::vector& output) { + const Tensor& tensor = src_cpu_ortvalue.Get(); int64_t num_elem = tensor.Shape().Size(); const T* val_ptr = tensor.template Data(); output.assign(val_ptr, val_ptr + num_elem); } template -void CudaOrtValueToCpuVec(const OrtValue& val, std::vector& output, - std::shared_ptr cuda_provider, - std::shared_ptr cpu_provider) { - const Tensor& src_tensor = val.Get(); +void CudaOrtValueToCpuVec(const OrtValue& src_cuda_ortvalue, std::vector& output) { + std::unique_ptr cuda_provider = onnxruntime::test::DefaultCudaExecutionProvider(); + std::unique_ptr cpu_provider = onnxruntime::test::DefaultCpuExecutionProvider(); - auto allocator = cpu_provider->GetAllocator(OrtMemTypeDefault); + const Tensor& src_tensor = src_cuda_ortvalue.Get(); + + auto allocator = cpu_provider->CreatePreferredAllocators()[0]; ORT_ENFORCE(allocator, "Cpu allocator is a nullptr."); auto dst_tensor = std::make_unique(src_tensor.DataType(), src_tensor.Shape(), allocator); @@ -55,7 +57,7 @@ inline void GenerateRandomInput(gsl::span dims, OrtValue& input) TensorShape shape(dims); std::vector data(shape.Size()); GenerateRandomData(data); - onnxruntime::test::CreateInputOrtValueOnCPU(dims, data, &input); + input = onnxruntime::test::CreateInputOrtValueOnCPU(dims, data); } } // namespace onnxruntime::training::test diff --git a/orttraining/orttraining/test/training_api/core/training_api_tests.cc b/orttraining/orttraining/test/training_api/core/training_api_tests.cc index 1487c2b29d7ef..2170f7957e6a6 100644 --- a/orttraining/orttraining/test/training_api/core/training_api_tests.cc +++ b/orttraining/orttraining/test/training_api/core/training_api_tests.cc @@ -19,6 +19,7 @@ #include "default_providers.h" using json = nlohmann::json; +using namespace onnxruntime::training::api; namespace onnxruntime { namespace training { @@ -28,6 +29,43 @@ namespace { #define MODEL_FOLDER ORT_TSTR("testdata/training_api/") +constexpr int64_t TOTAL_STEP_COUNT = 100; +constexpr float INITIAL_LR = 1e-3f; + +/** + * @brief Create a Fake Optimizer Checkpoint State On CPU. + * + * @param named_parameters Parameter list + * @param momentum_keys Optimizer momentum keys. + * @param optimizer_checkpoint_state Used as output to store the state containing faked data. + * @return Status + */ +Status CreateFakeOptimizerCheckpointStateOnCPU( + const std::unordered_map>& named_parameters, + const InlinedVector& momentum_keys, + OptimizerCheckpointState& optimizer_checkpoint_state) { + auto& grouped_optimizer_states = optimizer_checkpoint_state.group_named_optimizer_states; + grouped_optimizer_states.insert({"group0", std::make_shared()}); + GroupOptimizerState& group_optimizer_state = *(grouped_optimizer_states["group0"]); + + auto& param_named_optimizer_states = group_optimizer_state.param_named_optimizer_states; + for (auto& pair : named_parameters) { + if (pair.second->RequiresGrad()) { + param_named_optimizer_states.insert({pair.first, ParameterOptimizerState()}); + ParameterOptimizerState& cur_param_optimizer_states = param_named_optimizer_states[pair.first]; + for (auto& state_name : momentum_keys) { + OrtValue param_moment_state; + OrtValue param = pair.second->Data(); + const auto& param_tensor = param.template Get(); + GenerateRandomInput(param_tensor.Shape().GetDims(), param_moment_state); + cur_param_optimizer_states.insert({state_name, std::move(param_moment_state)}); + } + } + } + + return Status::OK(); +} + void TestModuleExport(const std::vector>& providers) { auto training_model_uri = MODEL_FOLDER "training_model.onnx"; auto eval_model_uri = MODEL_FOLDER "eval_model.onnx"; @@ -38,9 +76,12 @@ void TestModuleExport(const std::vector>& pr std::unique_ptr env; ASSERT_STATUS_OK(Environment::Create(nullptr, env)); + auto model_identifier = ModelIdentifiers(onnxruntime::ToUTF8String(training_model_uri), + std::optional(onnxruntime::ToUTF8String(eval_model_uri)), + std::nullopt); auto model = std::make_unique( - ToUTF8String(training_model_uri), &state, onnxruntime::SessionOptions(), - *env, providers, ToUTF8String(eval_model_uri)); + model_identifier, &state, onnxruntime::SessionOptions(), + *env, providers); auto test_dir = ORT_TSTR("export_model_for_inferencing_test_dir"); if (Env::Default().FolderExists(test_dir)) { @@ -48,7 +89,7 @@ void TestModuleExport(const std::vector>& pr } onnxruntime::test::TemporaryDirectory tmp_dir{test_dir}; PathString inference_model_path{ - ConcatPathComponent(tmp_dir.Path(), ORT_TSTR("inference_model.onnx"))}; + ConcatPathComponent(tmp_dir.Path(), ORT_TSTR("inference_model.onnx"))}; std::vector graph_output_names({"output-0"}); ASSERT_STATUS_OK(model->ExportModelForInferencing(ToUTF8String(inference_model_path), graph_output_names)); @@ -91,88 +132,6 @@ void TestModuleExport(const std::vector>& pr ASSERT_EQ(outputs.size(), 1U); } -#if defined(USE_CUDA) - -constexpr int64_t total_step_count = 100; -constexpr float initial_lr = 1e-3f; -constexpr int64_t resume_step = total_step_count / 2; - -void CompareValue(float expected, float output, float rtol = 1e-4, float atol = 1e-5) { - ASSERT_NEAR(expected, output, atol); - ASSERT_NEAR(expected, output, rtol * std::abs(expected)); -} - -void TestLRSchduler(const std::basic_string& test_file_name, float initial_lr, int64_t total_step_count, - int64_t warmup_step_count) { - /// Load model and optimizer graph, create Module, Optimizer and LRScheduler instances. - auto model_uri = MODEL_FOLDER "training_model.onnx"; - auto optim_uri = MODEL_FOLDER "adamw.onnx"; - - onnxruntime::training::api::CheckpointState state; - auto checkpoint_to_load_path = MODEL_FOLDER "checkpoint.ckpt"; - ASSERT_STATUS_OK(LoadCheckpoint(checkpoint_to_load_path, state)); - - onnxruntime::SessionOptions session_option; - std::unique_ptr env; - ASSERT_STATUS_OK(Environment::Create(nullptr, env)); - const std::vector> providers{onnxruntime::test::DefaultCudaExecutionProvider()}; - auto model = std::make_unique( - ToUTF8String(model_uri), &state, - session_option, *env, providers); - auto optim = std::make_shared( - ToUTF8String(optim_uri), &state, session_option, - *env, providers); - - OrtValue input, target; - GenerateRandomInput(std::array{2, 784}, input); - onnxruntime::test::CreateInputOrtValueOnCPU( - std::array{2}, std::vector(2, 1), &target); - - /// Load test data for learning rate schedulers. - auto data_uri = ORT_TSTR("testdata/test_data_generation/lr_scheduler/" + test_file_name); - std::ifstream in{data_uri}; - // Element of vector represent a pair of > - typedef std::vector>> TestDataDictType; - TestDataDictType test_data; - const json j = json::parse(in); - j.get_to(test_data); - - int64_t resume_step = (*test_data.begin()).first; - ASSERT_EQ(total_step_count, static_cast(test_data.size()) + resume_step); - - if (resume_step != 0) { - /// Reset optimizer states to match the initial state we want to test. - onnxruntime::training::api::OptimizerCheckpointState optimizer_checkpoint_states; - auto group_opt_state = - optimizer_checkpoint_states.group_named_optimizer_states["group0"] = - std::make_shared(); - group_opt_state->step = resume_step; - group_opt_state->initial_lr = initial_lr; - ASSERT_STATUS_OK(optim->LoadStateDict(optimizer_checkpoint_states)); - } - - // KNOWN ISSUE: LinearLRScheduler by default use optim's states to calculate the first step's learning rate. - // If we restored it after creation, it will only affect the learning rate from the second step. - auto scheduler = std::make_unique( - optim, warmup_step_count, total_step_count); - - for (auto it = test_data.begin(); it != test_data.end(); ++it) { - onnxruntime::training::api::OptimizerCheckpointState optimizer_states; - ASSERT_STATUS_OK(optim->GetStateDict(optimizer_states)); - auto group_optimizer_state = optimizer_states.group_named_optimizer_states["group0"]; - CompareValue(it->second[0], group_optimizer_state->learning_rate); - ASSERT_EQ(it->first, group_optimizer_state->step); - - std::vector inputs{input, target}; - std::vector fetches; - ASSERT_STATUS_OK(model->TrainStep(inputs, fetches)); - ASSERT_STATUS_OK(optim->Step()); - ASSERT_STATUS_OK(scheduler->Step()); - } -} - -#endif - } // namespace TEST(TrainingApiTest, ModuleParametersSize) { @@ -185,7 +144,9 @@ TEST(TrainingApiTest, ModuleParametersSize) { onnxruntime::SessionOptions session_option; std::unique_ptr env; ASSERT_STATUS_OK(Environment::Create(nullptr, env)); - auto model = std::make_unique(ToUTF8String(model_uri), + auto model_identifiers = ModelIdentifiers(onnxruntime::ToUTF8String(model_uri), + std::nullopt, std::nullopt); + auto model = std::make_unique(model_identifiers, &state, session_option, *env, std::vector>()); size_t params_size = 0; @@ -208,7 +169,10 @@ TEST(TrainingApiTest, ModuleCopyBufferToParameters) { onnxruntime::SessionOptions session_option; std::unique_ptr env; ASSERT_STATUS_OK(Environment::Create(nullptr, env)); - auto model = std::make_unique(ToUTF8String(model_uri), + auto model_identifier = ModelIdentifiers(onnxruntime::ToUTF8String(model_uri), + std::nullopt, + std::nullopt); + auto model = std::make_unique(model_identifier, &state, session_option, *env, std::vector>()); int64_t params_size = static_cast(model->GetParametersSize()); @@ -219,13 +183,13 @@ TEST(TrainingApiTest, ModuleCopyBufferToParameters) { Tensor::InitOrtValue(DataTypeImpl::GetType(), {params_size}, reinterpret_cast(expected_param_buffer.data()), - onnxruntime::test::TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault)->Info(), + onnxruntime::test::TestCPUExecutionProvider()->CreatePreferredAllocators()[0]->Info(), input_params, 0); ASSERT_STATUS_OK(model->CopyBufferToParameters(input_params)); OrtValue output_params; Tensor::InitOrtValue(DataTypeImpl::GetType(), {params_size}, - onnxruntime::test::TestCPUExecutionProvider()->GetAllocator(OrtMemTypeDefault), + onnxruntime::test::TestCPUExecutionProvider()->CreatePreferredAllocators()[0], output_params); ASSERT_STATUS_OK(model->CopyParametersToBuffer(output_params)); @@ -246,14 +210,17 @@ TEST(TrainingApiTest, ModuleTrainStep) { onnxruntime::SessionOptions session_option; std::unique_ptr env; ASSERT_STATUS_OK(Environment::Create(nullptr, env)); - auto model = std::make_unique(ToUTF8String(model_uri), + auto model_identifier = ModelIdentifiers(onnxruntime::ToUTF8String(model_uri), + std::nullopt, + std::nullopt); + auto model = std::make_unique(model_identifier, &state, session_option, *env, std::vector>()); ASSERT_EQ(model->GetTrainingModelOutputCount(), 1); OrtValue input, target; GenerateRandomInput(std::array{2, 784}, input); - onnxruntime::test::CreateInputOrtValueOnCPU( - std::array{2}, std::vector(2, 1), &target); + target = onnxruntime::test::CreateInputOrtValueOnCPU( + std::array{2}, std::vector(2, 1)); auto data_loader = std::vector>(4, std::vector{input, target}); size_t step = 0; @@ -271,12 +238,12 @@ TEST(TrainingApiTest, ModuleTrainStep) { bias_grad = bias_param->Gradient(); if (step > 1) { - OrtValueToVec(bias_grad, current_bias_grad_vec); + CpuOrtValueToVec(bias_grad, current_bias_grad_vec); for (size_t i = 0; i < current_bias_grad_vec.size(); i++) { ASSERT_EQ(current_bias_grad_vec[i], single_bias_grad_vec[i] * step); } } else { - OrtValueToVec(bias_grad, single_bias_grad_vec); + CpuOrtValueToVec(bias_grad, single_bias_grad_vec); } } // reset grad @@ -286,23 +253,201 @@ TEST(TrainingApiTest, ModuleTrainStep) { std::vector& inputs = *data_loader.begin(); std::vector fetches; ASSERT_STATUS_OK(model->TrainStep(inputs, fetches)); - OrtValueToVec(bias_grad, current_bias_grad_vec); + CpuOrtValueToVec(bias_grad, current_bias_grad_vec); for (size_t i = 0; i < current_bias_grad_vec.size(); i++) { ASSERT_EQ(current_bias_grad_vec[i], single_bias_grad_vec[i]); } } +TEST(TrainingApiTest, OptimizerCreatedWithOptimizerCheckpointState) { + std::vector run_cuda_list{false}; + // #ifdef USE_CUDA + // run_cuda_list.push_back(true); + // #endif + + for (auto run_cuda : run_cuda_list) { + std::vector> providers; + if (run_cuda) { + providers = {onnxruntime::test::DefaultCudaExecutionProvider()}; + } else { + providers = {onnxruntime::test::DefaultCpuExecutionProvider()}; + } + + auto model_uri = MODEL_FOLDER "training_model.onnx"; + auto optim_uri = MODEL_FOLDER "adamw.onnx"; + + CheckpointState state; + auto checkpoint_to_load_path = MODEL_FOLDER "checkpoint.ckpt"; + ASSERT_STATUS_OK(onnxruntime::training::api::LoadCheckpoint(checkpoint_to_load_path, state)); + + onnxruntime::SessionOptions session_option; + std::unique_ptr env; + + ASSERT_STATUS_OK(Environment::Create(nullptr, env)); + + auto model_identifier = ModelIdentifiers(onnxruntime::ToUTF8String(model_uri), + std::nullopt, + std::optional(onnxruntime::ToUTF8String(optim_uri))); + + std::shared_ptr model = std::make_shared( + model_identifier, &state, session_option, + *env, providers); + + // Load state dict from faked optimizer checkpoint state. + CheckpointState new_state = state; + OptimizerCheckpointState& external_optimizer_checkpoint_state = new_state.optimizer_checkpoint_state; + ASSERT_STATUS_OK(CreateFakeOptimizerCheckpointStateOnCPU(model->NamedParameters(), + {"momentum0", "momentum1"}, + external_optimizer_checkpoint_state)); + std::shared_ptr optim = std::make_shared( + model_identifier, &new_state, session_option, *env, providers); + + ASSERT_TRUE(optim.get() != nullptr); + } +} + +void TestLRSchduler(const std::basic_string& test_file_name, + float initial_lr, + int64_t total_step_count, + int64_t warmup_step_count) { + std::vector run_cuda_list{false}; +#ifdef USE_CUDA + run_cuda_list.push_back(true); +#endif + + for (auto run_cuda : run_cuda_list) { + std::vector> providers; + if (run_cuda) { + providers = {onnxruntime::test::DefaultCudaExecutionProvider()}; + } else { + providers = {onnxruntime::test::DefaultCpuExecutionProvider()}; + } + + auto model_uri = MODEL_FOLDER "training_model.onnx"; + auto optim_uri = MODEL_FOLDER "adamw.onnx"; + + CheckpointState state; + auto checkpoint_to_load_path = MODEL_FOLDER "checkpoint.ckpt"; + ASSERT_STATUS_OK(onnxruntime::training::api::LoadCheckpoint(checkpoint_to_load_path, state)); + + onnxruntime::SessionOptions session_option; + std::unique_ptr env; + + ASSERT_STATUS_OK(Environment::Create(nullptr, env)); + + auto model_identifier = ModelIdentifiers(onnxruntime::ToUTF8String(model_uri), + std::nullopt, + std::optional(onnxruntime::ToUTF8String(optim_uri))); + + std::shared_ptr model = std::make_shared( + model_identifier, &state, session_option, + *env, providers); + + OrtValue input, target; + GenerateRandomInput(std::array{2, 784}, input); + target = onnxruntime::test::CreateInputOrtValueOnCPU( + std::array{2}, std::vector(2, 1)); + + /// Load test data for learning rate schedulers. + auto data_uri = ORT_TSTR("testdata/test_data_generation/lr_scheduler/" + test_file_name); + std::ifstream in{data_uri}; + // Element of vector represent a pair of > + typedef std::vector>> TestDataDictType; + TestDataDictType test_data; + const json j = json::parse(in); + j.get_to(test_data); + + int64_t resume_step = (*test_data.begin()).first; + ASSERT_EQ(total_step_count, static_cast(test_data.size()) + resume_step); + + if (resume_step != 0) { + state.optimizer_checkpoint_state.group_named_optimizer_states.insert( + {"group0", std::make_shared()}); + auto& group_opt_state = state.optimizer_checkpoint_state.group_named_optimizer_states["group0"]; + /// Reset optimizer states to match the initial state we want to test. + group_opt_state->step = resume_step; + group_opt_state->initial_lr = initial_lr; + } + + std::shared_ptr optim = std::make_shared( + model_identifier, &state, session_option, + *env, providers); + + // KNOWN ISSUE: LinearLRScheduler by default use optim's states to calculate the first step's learning rate. + // If we restored it after creation, it will only affect the learning rate from the second step. + auto scheduler = std::make_unique( + optim, warmup_step_count, total_step_count); + + for (auto it = test_data.begin(); it != test_data.end(); ++it) { + OptimizerCheckpointState& optimizer_states = state.optimizer_checkpoint_state; + auto group_optimizer_state = optimizer_states.group_named_optimizer_states["group0"]; + + constexpr const float rtol = 1e-4f, atol = 1e-5f; + ASSERT_NEAR(it->second[0], group_optimizer_state->learning_rate, atol); + ASSERT_NEAR(it->second[0], group_optimizer_state->learning_rate, rtol * std::abs(it->second[0])); + + ASSERT_EQ(it->first, group_optimizer_state->step); + + std::vector inputs{input, target}; + std::vector fetches; + ASSERT_STATUS_OK(model->TrainStep(inputs, fetches)); + ASSERT_STATUS_OK(optim->Step()); + ASSERT_STATUS_OK(scheduler->Step()); + } + } +} + +TEST(TrainingApiTest, LinearLRScheduler_NoWarmUp_Test) { + // No warm up. + TestLRSchduler(ORT_TSTR("warmup_linear_scheduler_warmupstep-0.json"), INITIAL_LR, TOTAL_STEP_COUNT, 0); +} + +TEST(TrainingApiTest, LinearLRScheduler_NoWarmUp_ResumeFromCheckpoint_Test) { + // No warm up. + TestLRSchduler(ORT_TSTR("warmup_linear_scheduler_warmupstep-0_restored.json"), INITIAL_LR, TOTAL_STEP_COUNT, 0); +} + +TEST(TrainingApiTest, LinearLRScheduler_WarmUp30Step_Test) { + // Warmp up completed before saving checkpoint. + TestLRSchduler(ORT_TSTR("warmup_linear_scheduler_warmupstep-30.json"), INITIAL_LR, TOTAL_STEP_COUNT, 30); +} + +TEST(TrainingApiTest, LinearLRScheduler_WarmUp30Step_ResumeFromCheckpoint_Test) { + // Warmp up completed before saving checkpoint. + TestLRSchduler(ORT_TSTR("warmup_linear_scheduler_warmupstep-30_restored.json"), INITIAL_LR, TOTAL_STEP_COUNT, 30); +} + +TEST(TrainingApiTest, LinearLRScheduler_WarmUp70Step_Test) { + // Warmp up completed after saving checkpoint. + TestLRSchduler(ORT_TSTR("warmup_linear_scheduler_warmupstep-70.json"), INITIAL_LR, TOTAL_STEP_COUNT, 70); +} + +TEST(TrainingApiTest, LinearLRScheduler_WarmUp70Step_ResumeFromCheckpoint_Test) { + // Warmp up completed after saving checkpoint. + TestLRSchduler(ORT_TSTR("warmup_linear_scheduler_warmupstep-70_restored.json"), INITIAL_LR, TOTAL_STEP_COUNT, 70); +} + +TEST(TrainingApiTest, LinearLRScheduler_WarmUp200Step_Test) { + // All steps are in warm-up phase. + TestLRSchduler(ORT_TSTR("warmup_linear_scheduler_warmupstep-200.json"), INITIAL_LR, TOTAL_STEP_COUNT, 200); +} + +TEST(TrainingApiTest, LinearLRScheduler_WarmUp200Step_ResumeFromCheckpoint_Test) { + // All steps are in warm-up phase. + TestLRSchduler(ORT_TSTR("warmup_linear_scheduler_warmupstep-200_restored.json"), INITIAL_LR, TOTAL_STEP_COUNT, 200); +} + TEST(TrainingApiTest, ModuleExportModelForInferencingCPU) { std::vector> providers{onnxruntime::test::DefaultCpuExecutionProvider()}; TestModuleExport(providers); } #if defined(USE_CUDA) - TEST(TrainingApiTest, ModuleExportModelForInferencingCUDA) { std::vector> providers{onnxruntime::test::DefaultCudaExecutionProvider()}; TestModuleExport(providers); } +#endif TEST(TrainingApiTest, OptimStep) { auto model_uri = MODEL_FOLDER "training_model.onnx"; @@ -314,54 +459,64 @@ TEST(TrainingApiTest, OptimStep) { onnxruntime::SessionOptions session_option; std::unique_ptr env; - std::vector> providers{onnxruntime::test::DefaultCudaExecutionProvider()}; - std::shared_ptr cuda_provider = providers.front(); - std::shared_ptr cpu_provider = onnxruntime::test::DefaultCpuExecutionProvider(); + std::vector> providers; +#if defined(USE_CUDA) + providers.push_back(onnxruntime::test::DefaultCudaExecutionProvider()); +#endif ASSERT_STATUS_OK(Environment::Create(nullptr, env)); + + auto model_identifier = ModelIdentifiers(onnxruntime::ToUTF8String(model_uri), + std::nullopt, + std::optional(onnxruntime::ToUTF8String(optim_uri))); auto model = std::make_unique( - ToUTF8String(model_uri), &state, session_option, + model_identifier, &state, session_option, *env, providers); auto optim = std::make_unique( - ToUTF8String(optim_uri), &state, session_option, + model_identifier, &state, session_option, *env, providers); OrtValue input, target; GenerateRandomInput(std::array{2, 784}, input); - onnxruntime::test::CreateInputOrtValueOnCPU( - std::array{2}, std::vector(2, 1), &target); + target = onnxruntime::test::CreateInputOrtValueOnCPU( + std::array{2}, std::vector(2, 1)); auto data_loader = std::vector>(4, std::vector{input, target}); - size_t step = 0; std::string param_name = "fc2.weight"; - // before training, check if optim state is initialized to 0 - onnxruntime::training::api::OptimizerCheckpointState optimizer_states; - ASSERT_STATUS_OK(optim->GetStateDict(optimizer_states)); + onnxruntime::training::api::OptimizerCheckpointState& optimizer_states = state.optimizer_checkpoint_state; onnxruntime::training::api::ParameterOptimizerState& param_state = optimizer_states.group_named_optimizer_states["group0"]->param_named_optimizer_states.at(param_name); - OrtValue& moment_1 = param_state.momentum_named_states.at("momentum0"); + OrtValue& moment_1 = param_state.at("momentum0"); std::vector param_vec_before_optimizer_step; - CudaOrtValueToCpuVec(model->NamedParameters().at(param_name)->Data(), param_vec_before_optimizer_step, - cuda_provider, cpu_provider); std::vector moment_1_vec; - CudaOrtValueToCpuVec(moment_1, moment_1_vec, cuda_provider, cpu_provider); +#if defined(USE_CUDA) + CudaOrtValueToCpuVec(model->NamedParameters().at(param_name)->Data(), param_vec_before_optimizer_step); + CudaOrtValueToCpuVec(moment_1, moment_1_vec); +#else + CpuOrtValueToVec(model->NamedParameters().at(param_name)->Data(), param_vec_before_optimizer_step); + CpuOrtValueToVec(moment_1, moment_1_vec); +#endif + for (size_t i = 0; i < moment_1_vec.size(); i++) { ASSERT_EQ(moment_1_vec[i], 0.0f); } for (auto it = data_loader.begin(); it != data_loader.end(); ++it) { - step += 1; std::vector& inputs = *it; std::vector fetches; ASSERT_STATUS_OK(model->TrainStep(inputs, fetches)); - std::vector grads; - CudaOrtValueToCpuVec(model->NamedParameters().at(param_name)->Gradient(), grads, - cuda_provider, cpu_provider); ASSERT_STATUS_OK(optim->Step()); - // get optim state and check if it is updated - CudaOrtValueToCpuVec(moment_1, moment_1_vec, cuda_provider, cpu_provider); + // get gradients and optim state and check if it is updated + std::vector grads; +#if defined(USE_CUDA) + CudaOrtValueToCpuVec(model->NamedParameters().at(param_name)->Gradient(), grads); + CudaOrtValueToCpuVec(moment_1, moment_1_vec); +#else + CpuOrtValueToVec(model->NamedParameters().at(param_name)->Gradient(), grads); + CpuOrtValueToVec(moment_1, moment_1_vec); +#endif for (size_t i = 0; i < moment_1_vec.size(); i++) { if (grads[i] != 0.0f) { ASSERT_NE(moment_1_vec[i], 0.0f); @@ -369,8 +524,11 @@ TEST(TrainingApiTest, OptimStep) { } std::vector param_vec_after_optimizer_step; - CudaOrtValueToCpuVec(model->NamedParameters().at(param_name)->Data(), param_vec_after_optimizer_step, - cuda_provider, cpu_provider); +#if defined(USE_CUDA) + CudaOrtValueToCpuVec(model->NamedParameters().at(param_name)->Data(), param_vec_after_optimizer_step); +#else + CpuOrtValueToVec(model->NamedParameters().at(param_name)->Data(), param_vec_after_optimizer_step); +#endif for (size_t i = 0; i < param_vec_after_optimizer_step.size(); ++i) { if (grads[i] != 0.0f && moment_1_vec[i] != 0.0f) { ASSERT_NE(param_vec_after_optimizer_step[i], param_vec_before_optimizer_step[i]); @@ -379,48 +537,6 @@ TEST(TrainingApiTest, OptimStep) { } } -TEST(TrainingApiTest, LinearLRScheduler_NoWarmUp_Test) { - // No warm up. - TestLRSchduler(ORT_TSTR("warmup_linear_scheduler_warmupstep-0.json"), initial_lr, total_step_count, 0); -} - -TEST(TrainingApiTest, LinearLRScheduler_NoWarmUp_ResumeFromCheckpoint_Test) { - // No warm up. - TestLRSchduler(ORT_TSTR("warmup_linear_scheduler_warmupstep-0_restored.json"), initial_lr, total_step_count, 0); -} - -TEST(TrainingApiTest, LinearLRScheduler_WarmUp30Step_Test) { - // Warmp up completed before saving checkpoint. - TestLRSchduler(ORT_TSTR("warmup_linear_scheduler_warmupstep-30.json"), initial_lr, total_step_count, 30); -} - -TEST(TrainingApiTest, LinearLRScheduler_WarmUp30Step_ResumeFromCheckpoint_Test) { - // Warmp up completed before saving checkpoint. - TestLRSchduler(ORT_TSTR("warmup_linear_scheduler_warmupstep-30_restored.json"), initial_lr, total_step_count, 30); -} - -TEST(TrainingApiTest, LinearLRScheduler_WarmUp70Step_Test) { - // Warmp up completed after saving checkpoint. - TestLRSchduler(ORT_TSTR("warmup_linear_scheduler_warmupstep-70.json"), initial_lr, total_step_count, 70); -} - -TEST(TrainingApiTest, LinearLRScheduler_WarmUp70Step_ResumeFromCheckpoint_Test) { - // Warmp up completed after saving checkpoint. - TestLRSchduler(ORT_TSTR("warmup_linear_scheduler_warmupstep-70_restored.json"), initial_lr, total_step_count, 70); -} - -TEST(TrainingApiTest, LinearLRScheduler_WarmUp200Step_Test) { - // All steps are in warm-up phase. - TestLRSchduler(ORT_TSTR("warmup_linear_scheduler_warmupstep-200.json"), initial_lr, total_step_count, 200); -} - -TEST(TrainingApiTest, LinearLRScheduler_WarmUp200Step_ResumeFromCheckpoint_Test) { - // All steps are in warm-up phase. - TestLRSchduler(ORT_TSTR("warmup_linear_scheduler_warmupstep-200_restored.json"), initial_lr, total_step_count, 200); -} - -#endif - } // namespace test } // namespace training } // namespace onnxruntime diff --git a/orttraining/orttraining/test/training_api/core/training_capi_tests.cc b/orttraining/orttraining/test/training_api/core/training_capi_tests.cc index 9fb1fefa4ab34..d734be8e3474b 100644 --- a/orttraining/orttraining/test/training_api/core/training_capi_tests.cc +++ b/orttraining/orttraining/test/training_api/core/training_capi_tests.cc @@ -2,6 +2,7 @@ // Licensed under the MIT License. #include "gtest/gtest.h" +#include "gmock/gmock.h" #include "onnxruntime_c_api.h" #include "onnxruntime_training_c_api.h" @@ -10,11 +11,13 @@ #include "orttraining/training_api/checkpoint.h" #include "orttraining/test/training_api/core/data_utils.h" +#include "test/util/include/asserts.h" #include "test/util/include/temp_dir.h" namespace onnxruntime::training::test { #define MODEL_FOLDER ORT_TSTR("testdata/training_api/") +#define ORT_FORMAT_MODEL_FOLDER ORT_TSTR("testdata/training_api/ort_format/") TEST(TrainingCApiTest, SaveCheckpoint) { auto model_uri = MODEL_FOLDER "training_model.onnx"; @@ -29,7 +32,7 @@ TEST(TrainingCApiTest, SaveCheckpoint) { } onnxruntime::test::TemporaryDirectory tmp_dir{test_dir}; PathString checkpoint_path{ - ConcatPathComponent(tmp_dir.Path(), ORT_TSTR("new_checkpoint.ckpt"))}; + ConcatPathComponent(tmp_dir.Path(), ORT_TSTR("new_checkpoint.ckpt"))}; Ort::CheckpointState::SaveCheckpoint(checkpoint_state, checkpoint_path); @@ -38,6 +41,33 @@ TEST(TrainingCApiTest, SaveCheckpoint) { new_checkpoint_state, model_uri); } +TEST(TrainingCApiTest, LoadCheckpointFromBuffer) { + Ort::Env env; + size_t num_bytes = 0; + PathString checkpoint_path = MODEL_FOLDER "checkpoint.ckpt"; + ASSERT_STATUS_OK(Env::Default().GetFileLength(checkpoint_path.c_str(), num_bytes)); + std::vector checkpoint_bytes(num_bytes); + + std::ifstream bytes_stream(checkpoint_path, std::ifstream::in | std::ifstream::binary); + bytes_stream.read(reinterpret_cast(checkpoint_bytes.data()), num_bytes); + + ASSERT_TRUE(bytes_stream); + + Ort::CheckpointState checkpoint_state = Ort::CheckpointState::LoadCheckpointFromBuffer(checkpoint_bytes); + + auto test_dir = ORT_TSTR("save_checkpoint_dir"); + if (Env::Default().FolderExists(test_dir)) { + ORT_ENFORCE(Env::Default().DeleteFolder(test_dir).IsOK()); + } + onnxruntime::test::TemporaryDirectory tmp_dir{test_dir}; + PathString new_checkpoint_path{ + ConcatPathComponent(tmp_dir.Path(), ORT_TSTR("new_checkpoint.ckpt"))}; + + Ort::CheckpointState::SaveCheckpoint(checkpoint_state, new_checkpoint_path); + + Ort::CheckpointState new_checkpoint_state = Ort::CheckpointState::LoadCheckpoint(new_checkpoint_path); +} + TEST(TrainingCApiTest, AddIntProperty) { Ort::CheckpointState checkpoint_state = Ort::CheckpointState::LoadCheckpoint(MODEL_FOLDER "checkpoint.ckpt"); @@ -138,4 +168,154 @@ TEST(TrainingCApiTest, FromBuffer) { training_session.FromBuffer(buffer); } +TEST(TrainingCApiTest, RegisterCustomOps) { + auto model_uri = MODEL_FOLDER "custom_ops/training_model.onnx"; + + Ort::Env env; + Ort::CheckpointState checkpoint_state = Ort::CheckpointState::LoadCheckpoint(MODEL_FOLDER "custom_ops/checkpoint"); + Ort::SessionOptions session_options; + +#if defined(_WIN32) + session_options.RegisterCustomOpsLibrary(ORT_TSTR("custom_op_library.dll")); +#elif defined(__APPLE__) + session_options.RegisterCustomOpsLibrary(ORT_TSTR("libcustom_op_library.dylib")); +#else + session_options.RegisterCustomOpsLibrary(ORT_TSTR("libcustom_op_library.so")); +#endif + +#ifdef USE_CUDA + Ort::ThrowOnError(OrtSessionOptionsAppendExecutionProvider_CUDA(session_options, 0)); +#endif + + Ort::TrainingSession training_session = Ort::TrainingSession(env, session_options, checkpoint_state, model_uri); + + Ort::MemoryInfo memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault); + + std::vector ort_inputs; + std::vector input_shape{3, 5}; + + std::vector x{1.1f, 2.2f, 3.3f, 4.4f, 5.5f, + 6.6f, 7.7f, 8.8f, 9.9f, 10.0f, + 11.1f, 12.2f, 13.3f, 14.4f, 15.5f}; + ort_inputs.emplace_back(Ort::Value::CreateTensor(memory_info, x.data(), + x.size() * sizeof(float), + input_shape.data(), input_shape.size(), + ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT)); + + std::vector y{15.5f, 14.4f, 13.3f, 12.2f, 11.1f, + 10.0f, 9.9f, 8.8f, 7.7f, 6.6f, + 5.5f, 4.4f, 3.3f, 2.2f, 1.1f}; + ort_inputs.emplace_back(Ort::Value::CreateTensor(memory_info, y.data(), + y.size() * sizeof(float), + input_shape.data(), input_shape.size(), + ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT)); + + std::vector labels{0, 8, 4}; + std::vector labels_shape{3}; + ort_inputs.emplace_back(Ort::Value::CreateTensor(memory_info, labels.data(), + labels.size() * sizeof(int64_t), + labels_shape.data(), labels_shape.size(), + ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64)); + + auto loss = training_session.TrainStep(ort_inputs); + ASSERT_EQ(loss.size(), 1U); + ASSERT_TRUE(loss.front().IsTensor()); +} + +TEST(TrainingCApiTest, LoadModelsAndCreateSession) { + auto model_path = MODEL_FOLDER "training_model.onnx"; + + Ort::Env env; + Ort::CheckpointState checkpoint_state = Ort::CheckpointState::LoadCheckpoint(MODEL_FOLDER "checkpoint.ckpt"); + Ort::TrainingSession training_session = Ort::TrainingSession(env, + Ort::SessionOptions(), + checkpoint_state, + model_path); +} + +TEST(TrainingCApiTest, LoadModelsAndCreateSession_ORTFormat) { + auto train_model_path = ORT_FORMAT_MODEL_FOLDER "training_model.ort"; + auto eval_train_model_path = ORT_FORMAT_MODEL_FOLDER "eval_model.ort"; + auto optimizer_model_path = ORT_FORMAT_MODEL_FOLDER "optimizer_model.ort"; + + Ort::Env env; + Ort::CheckpointState checkpoint_state = Ort::CheckpointState::LoadCheckpoint(ORT_FORMAT_MODEL_FOLDER "checkpoint"); + Ort::TrainingSession training_session = Ort::TrainingSession(env, + Ort::SessionOptions(), + checkpoint_state, + train_model_path, + eval_train_model_path, + optimizer_model_path); +} + +TEST(TrainingCApiTest, LoadONNXModelsFromBuffer) { + auto model_path = MODEL_FOLDER "training_model.onnx"; + size_t model_data_len = 0; + ASSERT_STATUS_OK(Env::Default().GetFileLength(model_path, model_data_len)); + std::vector train_model_data(model_data_len); + std::ifstream bytes_stream(model_path, std::ifstream::in | std::ifstream::binary); + bytes_stream.read(reinterpret_cast(train_model_data.data()), model_data_len); + ASSERT_TRUE(train_model_data.size() == model_data_len); + + Ort::Env env; + Ort::CheckpointState checkpoint_state = Ort::CheckpointState::LoadCheckpoint(MODEL_FOLDER "checkpoint.ckpt"); + Ort::TrainingSession training_session = Ort::TrainingSession(env, + Ort::SessionOptions(), + checkpoint_state, + train_model_data); +} + +TEST(TrainingCApiTest, LoadORTFormatModelsFromBuffer) { + auto train_model_path = ORT_FORMAT_MODEL_FOLDER "training_model.ort"; + auto eval_model_path = ORT_FORMAT_MODEL_FOLDER "eval_model.ort"; + auto optimizer_model_path = ORT_FORMAT_MODEL_FOLDER "optimizer_model.ort"; + size_t model_data_len = 0; + ASSERT_STATUS_OK(Env::Default().GetFileLength(train_model_path, model_data_len)); + std::vector train_model_data(model_data_len); + { + std::ifstream bytes_stream(train_model_path, std::ifstream::in | std::ifstream::binary); + bytes_stream.read(reinterpret_cast(train_model_data.data()), model_data_len); + ASSERT_TRUE(train_model_data.size() == model_data_len); + } + + model_data_len = 0; + ASSERT_STATUS_OK(Env::Default().GetFileLength(eval_model_path, model_data_len)); + std::vector eval_model_data(model_data_len); + { + std::ifstream bytes_stream(eval_model_path, std::ifstream::in | std::ifstream::binary); + bytes_stream.read(reinterpret_cast(eval_model_data.data()), model_data_len); + ASSERT_TRUE(eval_model_data.size() == model_data_len); + } + + model_data_len = 0; + ASSERT_STATUS_OK(Env::Default().GetFileLength(optimizer_model_path, model_data_len)); + std::vector optimizer_model_data(model_data_len); + { + std::ifstream bytes_stream(optimizer_model_path, std::ifstream::in | std::ifstream::binary); + bytes_stream.read(reinterpret_cast(optimizer_model_data.data()), model_data_len); + ASSERT_TRUE(optimizer_model_data.size() == model_data_len); + } + + Ort::Env env; + Ort::CheckpointState checkpoint_state = Ort::CheckpointState::LoadCheckpoint(ORT_FORMAT_MODEL_FOLDER "checkpoint"); + Ort::TrainingSession training_session = Ort::TrainingSession(env, Ort::SessionOptions(), + checkpoint_state, train_model_data, + eval_model_data, optimizer_model_data); +} + +TEST(TrainingCApiTest, LoadModelsFromBufferThrows) { + Ort::Env env; + Ort::CheckpointState checkpoint_state = Ort::CheckpointState::LoadCheckpoint(MODEL_FOLDER "checkpoint.ckpt"); + + try { + std::vector train_model_data; + Ort::TrainingSession training_session = Ort::TrainingSession(env, + Ort::SessionOptions(), + checkpoint_state, + train_model_data); + } catch (const std::exception& ex) { + ASSERT_THAT(ex.what(), + testing::HasSubstr("Training Session Creation failed. Train model data cannot be NULL.")); + } +} } // namespace onnxruntime::training::test diff --git a/orttraining/orttraining/test/training_api/trainer/trainer.cc b/orttraining/orttraining/test/training_api/trainer/trainer.cc index ff4a8243741b5..fc09d6815415c 100644 --- a/orttraining/orttraining/test/training_api/trainer/trainer.cc +++ b/orttraining/orttraining/test/training_api/trainer/trainer.cc @@ -321,7 +321,7 @@ int RunTraining(const TestRunnerParameters& params) { // Save trained weights std::ostringstream oss; oss << "ckpt_" << params.model_name << std::to_string(batch_idx); - PathString ckpt_file = ConcatPathComponent(params.output_dir, ToPathString(oss.str())); + PathString ckpt_file = ConcatPathComponent(params.output_dir, ToPathString(oss.str())); checkpoint_state.AddProperty("epoch", epoch); checkpoint_state.AddProperty("loss", *loss); checkpoint_state.AddProperty("framework", "onnxruntime"); @@ -336,7 +336,7 @@ int RunTraining(const TestRunnerParameters& params) { // Save trained weights std::ostringstream oss; oss << "ckpt_" << params.model_name; - PathString ckpt_file = ConcatPathComponent(params.output_dir, ToPathString(oss.str())); + PathString ckpt_file = ConcatPathComponent(params.output_dir, ToPathString(oss.str())); Ort::CheckpointState::SaveCheckpoint(checkpoint_state, ckpt_file); auto end = std::chrono::high_resolution_clock::now(); diff --git a/orttraining/orttraining/test/training_ops/cpu/activation/activation_op_test.cc b/orttraining/orttraining/test/training_ops/cpu/activation/activation_op_test.cc index 52c01da54b4ea..c700c73086c99 100644 --- a/orttraining/orttraining/test/training_ops/cpu/activation/activation_op_test.cc +++ b/orttraining/orttraining/test/training_ops/cpu/activation/activation_op_test.cc @@ -89,6 +89,10 @@ float QuickGeluGrad(float dy, float x, float alpha) { float sigmoid = v >= 0 ? 1.f / (1.f + std::exp(-v)) : 1.f - 1.f / (1 + std::exp(v)); return dy * sigmoid * (1 + v * (1 - sigmoid)); } + +constexpr float LeakyReluGrad(float dy, float y, float alpha) { + return dy * (y > 0.0f ? 1.0f : alpha); +} } // namespace TEST(GeluGradTest, Basic) { @@ -263,6 +267,23 @@ TEST(QuickGeluGradTest, Basic) { } } +TEST(LeakyReluGradTest, Basic) { + const std::vector y_vals = {-1.0f, 0, 1.0f, 100.0f, -100.0f, 1000.0f, -1000.0f}; + const std::vector dY(7, 1.0f); + float alpha = 0.5f; + + TestElementwiseGradientOp( + "LeakyReluGrad", + {{"dY", dY}, {"Y", y_vals}}, + [alpha](const std::vector& params) { + ORT_ENFORCE(params.size() == 2); + const auto dy = params[0], y = params[1]; + + return LeakyReluGrad(dy, y, alpha); + }, + {{"alpha", alpha}}, 1, kMSDomain); +} + namespace { template void TestBiasGeluGradBroadcastBias(const std::string& op, int opset_version, const std::string& domain, @@ -298,12 +319,14 @@ TEST(BiasGeluGradDxTest, BroadcastBias) { TestBiasGeluGradBroadcastBias("BiasGeluGrad_dX", 1, kMSDomain, {2, 3, 4, 5}, GeluGrad); TestBiasGeluGradBroadcastBias("BiasGeluGrad_dX", 1, kMSDomain, {2, 4, 3072}, GeluGrad); TestBiasGeluGradBroadcastBias("BiasGeluGrad_dX", 1, kMSDomain, {2, 16384}, GeluGrad); + TestBiasGeluGradBroadcastBias("BiasGeluGrad_dX", 1, kMSDomain, {2, 2333}, GeluGrad); } TEST(BiasFastGeluGradDxTest, BroadcastBias) { TestBiasGeluGradBroadcastBias("BiasFastGeluGrad_dX", 1, kMSDomain, {2, 3, 4, 5}, GeluApproximationGrad); TestBiasGeluGradBroadcastBias("BiasFastGeluGrad_dX", 1, kMSDomain, {2, 4, 3072}, GeluApproximationGrad); TestBiasGeluGradBroadcastBias("BiasFastGeluGrad_dX", 1, kMSDomain, {2, 16384}, GeluApproximationGrad); + TestBiasGeluGradBroadcastBias("BiasFastGeluGrad_dX", 1, kMSDomain, {2, 2333}, GeluApproximationGrad); } } // namespace test diff --git a/orttraining/orttraining/test/training_ops/cpu/nn/dropout_op_test.cc b/orttraining/orttraining/test/training_ops/cpu/nn/dropout_op_test.cc index 904eb357346d7..1b4fdbd6ac6d1 100644 --- a/orttraining/orttraining/test/training_ops/cpu/nn/dropout_op_test.cc +++ b/orttraining/orttraining/test/training_ops/cpu/nn/dropout_op_test.cc @@ -54,7 +54,7 @@ void RunDropoutTest(const bool use_mask, const std::vector& input_shape ratio = 0.5f; } else { if (use_float16_ratio) { - t.AddInput("ratio", {}, {MLFloat16(math::floatToHalf(ratio))}); + t.AddInput("ratio", {}, {MLFloat16(ratio)}); } else { t.AddInput("ratio", {}, {ratio}); } @@ -79,7 +79,7 @@ void RunDropoutTest(const bool use_mask, const std::vector& input_shape auto output_verifier = [&](const std::vector& fetches, const std::string& provider_type) { ASSERT_GE(fetches.size(), 1); - const auto& output_tensor = FetchTensor(fetches[0]); + const auto& output_tensor = fetches[0].Get(); auto output_span = output_tensor.DataAsSpan(); const auto num_dropped_values = std::count(output_span.begin(), output_span.end(), 0.0f); @@ -100,7 +100,7 @@ void RunDropoutTest(const bool use_mask, const std::vector& input_shape if (use_mask) { ASSERT_GE(fetches.size(), 2); - const auto& mask_tensor = FetchTensor(fetches[1]); + const auto& mask_tensor = fetches[1].Get(); auto mask_span = mask_tensor.DataAsSpan(); ASSERT_EQ(mask_span.size(), output_span.size()) << "provider: " << provider_type; diff --git a/orttraining/orttraining/test/training_ops/cpu/rnn/gru_test.cc b/orttraining/orttraining/test/training_ops/cpu/rnn/gru_test.cc new file mode 100644 index 0000000000000..dd305fd8f1329 --- /dev/null +++ b/orttraining/orttraining/test/training_ops/cpu/rnn/gru_test.cc @@ -0,0 +1,170 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "test/providers/compare_provider_test_utils.h" +#include "test/providers/provider_test_utils.h" +#include "test/util/include/default_providers.h" + +namespace onnxruntime { +namespace test { + +TEST(GRUTest, ForwardCompute) { + std::vector> providers; + providers.emplace_back(DefaultCpuExecutionProvider()); + + OpTester test("GRUTraining", 1, onnxruntime::kMSDomain); + + constexpr int sequence_length = 2; + constexpr int batch_size = 2; + constexpr int hidden_size = 3; + constexpr int input_size = 2; + constexpr int directions = 1; + + test.AddAttribute("hidden_size", hidden_size); + + test.AddInput("input_tensor", {sequence_length, batch_size, input_size}, + {1.0f, 3.0f, 5.0f, 7.0f, 2.0f, 4.0f, 6.0f, 8.0f}); + test.AddInput("weights", {directions, 3 * hidden_size, input_size}, + {0.1f, 0.2f, + 0.3f, 0.4f, + 1.0f, 2.0f, + 3.0f, 4.0f, + 10.0f, 11.0f, + 12.0f, 13.0f, + 0.6f, 0.7f, + 0.8f, 0.9f, + 6.0f, 7.0f}); + test.AddInput("recurrence_weights", {directions, 3 * hidden_size, hidden_size}, + {8.0f, 9.0f, 16.0f, + 17.0f, 18.0f, 19.0, + 0.1f, 0.2f, 0.3f, + 0.4f, 1.0f, 2.0f, + 0.6f, 0.7f, 0.8f, + 0.9f, 6.0f, 7.0f, + 3.0f, 4.0f, 10.0f, + 11.0f, 12.0f, 13.0f, + 0.1f, 0.3f, 0.5f}); + test.AddInput("bias", {directions, 6 * hidden_size}, + {3.0f, 4.0f, 10.0f, 11.0f, 12.0f, 13.0f, 0.6f, 0.7f, + 0.8f, 0.9f, 6.0f, 7.0f, 0.1f, 0.2f, 0.3f, 0.4f, + 1.0f, 2.0f}); + + test.AddOutput( + "HAll", {sequence_length, directions, batch_size, hidden_size}, + {0.00993967f, 1.01322e-05f, 0.0f, 0.00301844f, + 5.96047e-07f, 0.0f, 0.0167009f, 1.43641e-05f, + 0.0f, 0.00519647f, 8.9407e-07f, 0.0f}); + test.AddOutput( + "final_h", {directions, batch_size, hidden_size}, + {0.0167009f, 1.43641e-05f, 0.0f, 0.00519647f, 8.9407e-07f, 0.0f}); + test.AddOutput( + "zrh", {sequence_length, directions, batch_size, 3 * hidden_size}, + {0.990048f, 0.99999f, 1.0f, 1.0f, 1.0f, 1.0f, 0.998778f, 0.999939f, + 1.0f, 0.996982f, 0.999999f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 0.99317f, 0.999996f, 1.0f, 1.0f, 1.0f, 1.0f, + 0.999914f, 0.999998f, 1.0f, 0.997815f, 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f}); + + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {}, nullptr, &providers); +} + +TEST(GRUTest, BackwardCompute) { + std::vector> providers; + providers.emplace_back(DefaultCpuExecutionProvider()); + + OpTester test("GRUGrad", 1, onnxruntime::kMSDomain); + + constexpr int sequence_length = 2; + constexpr int batch_size = 2; + constexpr int hidden_size = 3; + constexpr int input_size = 2; + constexpr int directions = 1; + + test.AddAttribute("hidden_size", hidden_size); + + test.AddInput("input_tensor", {sequence_length, batch_size, input_size}, + {1.0f, 3.0f, 5.0f, 7.0f, 2.0f, 4.0f, 6.0f, 8.0f}); + test.AddInput("weights", {directions, 3 * hidden_size, input_size}, + {0.1f, 0.2f, + 0.3f, 0.4f, + 1.0f, 2.0f, + 3.0f, 4.0f, + 10.0f, 11.0f, + 12.0f, 13.0f, + 0.6f, 0.7f, + 0.8f, 0.9f, + 6.0f, 7.0f}); + test.AddInput("recurrence_weights", {directions, 3 * hidden_size, hidden_size}, + {8.0f, 9.0f, 16.0f, + 17.0f, 18.0f, 19.0, + 0.1f, 0.2f, 0.3f, + 0.4f, 1.0f, 2.0f, + 0.6f, 0.7f, 0.8f, + 0.9f, 6.0f, 7.0f, + 3.0f, 4.0f, 10.0f, + 11.0f, 12.0f, 13.0f, + 0.1f, 0.3f, 0.5f}); + test.AddInput("bias", {directions, 6 * hidden_size}, + {3.0f, 4.0f, 10.0f, 11.0f, 12.0f, 13.0f, 0.6f, 0.7f, + 0.8f, 0.9f, 6.0f, 7.0f, 0.1f, 0.2f, 0.3f, 0.4f, + 1.0f, 2.0f}); + + test.AddOptionalInputEdge(); + test.AddOptionalInputEdge(); + + test.AddInput( + "HAll", {sequence_length, directions, batch_size, hidden_size}, + {0.00993967f, 1.01322e-05f, 0.0f, 0.00301844f, + 5.96047e-07f, 0.0f, 0.0167009f, 1.43641e-05f, + 0.0f, 0.00519647f, 8.9407e-07f, 0.0f}); + test.AddInput( + "zrh", {sequence_length, directions, batch_size, 3 * hidden_size}, + {0.990048f, 0.99999f, 1.0f, 1.0f, 1.0f, 1.0f, 0.998778f, 0.999939f, + 1.0f, 0.996982f, 0.999999f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 0.99317f, 0.999996f, 1.0f, 1.0f, 1.0f, 1.0f, + 0.999914f, 0.999998f, 1.0f, 0.997815f, 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f}); + + test.AddInput( + "grad_HAll", {sequence_length, directions, batch_size, hidden_size}, + {0.13658696f, 0.37761405f, 0.5353489f, + 0.53866684f, 0.02047455f, 0.42426682f, + 0.12669823f, 0.28094783f, 0.82699543f, + 0.12687224f, 0.4540311f, 0.4124293f}); + + test.AddOptionalInputEdge(); + + test.AddOutput( + "dX", {sequence_length, batch_size, input_size}, + {-0.000249756f, -0.000501315f, -0.000199651f, -0.000399207f, + -8.53292e-05f, -0.000170508f, -2.75774e-05f, -5.51547e-05f}); + test.AddOutput( + "dW", {directions, 3 * hidden_size, input_size}, + {-0.015847f, -0.0271209f, -1.11526e-05f, + -2.73875e-05f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, + 6.51075e-06f, 1.92345e-05f, 8.03933e-10f, + 2.4027e-09f, 0.0f, 0.0f}); + test.AddOutput( + "dR", {directions, 3 * hidden_size, hidden_size}, + {-9.28927e-06f, -8.78505e-09f, 0.0f, + -1.11518e-08f, -1.13678e-11f, 0.0f, + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, + 1.47958e-09f, 1.50824e-12f, 0.0f, + 4.52003e-14f, 4.60759e-17f, 0.0f, + 0.0f, 0.0f, 0.0f}); + test.AddOutput( + "dB", {directions, 6 * hidden_size}, + {-0.00563696f, -8.11746e-06f, 0.0f, 0.0f, 0.0f, 0.0f, + 6.36189e-06f, 7.99385e-10f, 0.0f, -0.00563696f, -8.11746e-06f, 0.0f, + 0.0f, 0.0f, 0.0f, 6.36189e-06f, 7.99385e-10f, 0.0f}); + + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {}, nullptr, &providers); +} + +} // namespace test +} // namespace onnxruntime diff --git a/orttraining/orttraining/test/training_ops/cpu/tensor/gather_grad_op_test.cc b/orttraining/orttraining/test/training_ops/cpu/tensor/gather_grad_op_test.cc index 7337f1e35857f..ced03d9df5c29 100644 --- a/orttraining/orttraining/test/training_ops/cpu/tensor/gather_grad_op_test.cc +++ b/orttraining/orttraining/test/training_ops/cpu/tensor/gather_grad_op_test.cc @@ -15,11 +15,10 @@ namespace test { namespace { template -std::vector CalculateOutput( - int64_t axis, - const TensorShape& output_shape, - const std::vector& grad, - const std::vector& indices) { +std::vector CalculateOutput(int64_t axis, + const TensorShape& output_shape, + const std::vector& grad, + const std::vector& indices) { const int64_t num_batches = output_shape.SizeToDimension(axis); const int64_t gather_dimension_size = output_shape[axis]; const int64_t num_gathered_per_index = output_shape.SizeFromDimension(axis + 1); @@ -43,12 +42,11 @@ std::vector CalculateOutput( } template -void ConfigureGatherGradRandomDataOpTester( - int64_t axis, - const TensorShape& X_shape, - const TensorShape& indices_shape, - optional random_seed, - OpTester& test) { +void ConfigureGatherGradRandomDataOpTester(int64_t axis, + const TensorShape& X_shape, + const TensorShape& indices_shape, + optional random_seed, + OpTester& test) { ASSERT_LE(0, axis); ASSERT_LT(static_cast(axis), X_shape.NumDimensions()); @@ -68,8 +66,7 @@ void ConfigureGatherGradRandomDataOpTester( test.AddAttribute("axis", axis); // auto shape_dims = X_shape.GetDims(); // std::vector v_dims(shape_dims.cbegin(), shape_dims.cend()); - test.AddInput( - "shape", {static_cast(X_shape.NumDimensions())}, X_shape.AsShapeVector()); + test.AddInput("shape", {static_cast(X_shape.NumDimensions())}, X_shape.GetDims()); test.AddInput("indices", indices_shape.AsShapeVector(), indices); test.AddInput("grad", dY_shape.AsShapeVector(), grad); test.AddOutput("output", X_shape.AsShapeVector(), output); @@ -204,7 +201,7 @@ void RunGatherGradConsistentOutputTest( auto output_handler = [&provider_outputs](const std::vector& fetches, const std::string& provider_type) { ASSERT_EQ(fetches.size(), 1); - const Tensor& output_tensor = FetchTensor(fetches[0]); + const Tensor& output_tensor = fetches[0].Get(); const auto output_size = output_tensor.Shape().Size(); std::vector output; output.reserve(output_size); diff --git a/orttraining/orttraining/test/training_ops/cpu/tensor/gather_nd_grad_op_test.cc b/orttraining/orttraining/test/training_ops/cpu/tensor/gather_nd_grad_op_test.cc index 19392478acec2..6af13393e3e1b 100644 --- a/orttraining/orttraining/test/training_ops/cpu/tensor/gather_nd_grad_op_test.cc +++ b/orttraining/orttraining/test/training_ops/cpu/tensor/gather_nd_grad_op_test.cc @@ -1,6 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +// TODO(askhade): enable these tests for all training builds. +// 2 of the tests are failing for winx86 builds. +// Need more debugging to find the root cause. +#ifdef ENABLE_TRAINING #include "gtest/gtest.h" #include "test/providers/provider_test_utils.h" #include "test/common/cuda_op_test_utils.h" @@ -114,3 +118,5 @@ TEST(GatherNDGradOpTest, GatherNDGrad_batch_dims_two_negative_indices) { } // namespace test } // namespace onnxruntime + +#endif diff --git a/orttraining/orttraining/test/training_ops/cuda/activations_test.cc b/orttraining/orttraining/test/training_ops/cuda/activations_test.cc index 656db10e90d7f..3173610597f71 100644 --- a/orttraining/orttraining/test/training_ops/cuda/activations_test.cc +++ b/orttraining/orttraining/test/training_ops/cuda/activations_test.cc @@ -90,6 +90,13 @@ TEST(CudaKernelTest, TanhGrad_basic) { } } +TEST(CudaKernelTest, LeakyReluGrad_basic) { + std::vector> test_dims{{4}, {16, 2}, {8, 2, 128, 128}}; + for (const auto& test_dim : test_dims) { + TestActivations(test_dim, "LeakyReluGrad", true /* grad_op */); + } +} + static void TestActivationsWithBroadcastBias( const std::vector& tensor_dim, const std::string& operator_name, diff --git a/orttraining/orttraining/test/training_ops/cuda/batch_scale_test.cc b/orttraining/orttraining/test/training_ops/cuda/batch_scale_test.cc new file mode 100644 index 0000000000000..eb229b82caa55 --- /dev/null +++ b/orttraining/orttraining/test/training_ops/cuda/batch_scale_test.cc @@ -0,0 +1,120 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +#if defined(USE_CUDA) || defined(USE_ROCM) + +#include "test/common/tensor_op_test_utils.h" +#include "test/providers/provider_test_utils.h" + +namespace onnxruntime { +namespace test { + +static void PrepareInputAndOutputData(const std::vector& input, + const std::vector& scales, + std::vector>& outputs) { + for (size_t i = 0; i < outputs.size(); ++i) { + outputs.at(i).resize(input.size()); + } + + for (size_t i = 0; i < input.size(); ++i) { + outputs[0][i] = input[i] * scales[0]; + outputs[1][i] = input[i] * scales[1]; + if (outputs.size() == 3) + outputs[2][i] = input[i] * scales[2]; + } +} + +template +static void RunBatchScaleOpTester(const std::vector& input, + const std::vector& scales, + const std::vector>& outputs, + const std::vector& shape) { + ORT_ENFORCE(scales.size() == outputs.size(), "scales and outputs should have the same size."); + OpTester test("BatchScale", 1, onnxruntime::kMSDomain); + test.AddInput("input", shape, input); + test.AddOutput("output_0", shape, outputs[0]); + test.AddOutput("output_1", shape, outputs[1]); + if (outputs.size() == 3) { + test.AddOutput("output_2", shape, outputs[2]); + } + test.AddAttribute("scale_0", scales[0]); + test.AddAttribute("scale_1", scales[1]); + if (scales.size() == 3) { + test.AddAttribute("scale_2", scales[2]); + } + + // Exclude CPU EP since it is not implemented yet. + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kCpuExecutionProvider}); +} + +static void RunBatchScaleTestWithFloatAndMLFloat16(const std::vector& input, + const std::vector& scales, + const std::vector& shape) { + std::vector> outputs; + outputs.resize(scales.size()); + PrepareInputAndOutputData(input, scales, outputs); + RunBatchScaleOpTester(input, scales, outputs, shape); + + std::vector input_half; + input_half.resize(input.size()); + ConvertFloatToMLFloat16(input.data(), input_half.data(), static_cast(input.size())); + + std::vector> outputs_half; + outputs_half.resize(scales.size()); + for (size_t i = 0; i < outputs.size(); ++i) { + outputs_half[i].resize(outputs[i].size()); + ConvertFloatToMLFloat16(outputs[i].data(), outputs_half[i].data(), static_cast(outputs[i].size())); + } + + RunBatchScaleOpTester(input_half, scales, outputs_half, shape); +} + +TEST(BatchScaleTest, SmallTensor1D) { + std::vector input = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.f}; + float scale_0 = 0.25f; + float scale_1 = 0.25f; + float scale_2 = 0.5f; + std::vector shape{static_cast(input.size())}; + RunBatchScaleTestWithFloatAndMLFloat16(input, {scale_0, scale_1, scale_2}, shape); + RunBatchScaleTestWithFloatAndMLFloat16(input, {scale_0, scale_1}, shape); +} + +TEST(BatchScaleTest, SmallTensorVectorized1D) { + std::vector input = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.f, 7.0f, 8.0f, + 9.0f, 10.0f, 11.0f, 12.f, 13.0f, 14.0f, 15.0f, 16.0f, + 17.0f, 18.0f, 19.0f, 20.0f, 21.0f, 22.f, 23.0f, 24.0f, + 25.0f, 26.0f, 27.0f, 28.0f, 29.0f, 30.f, 31.0f, 32.0f}; + float scale_0 = 0.25f; + float scale_1 = 0.25f; + float scale_2 = 0.5f; + std::vector shape{static_cast(input.size())}; + RunBatchScaleTestWithFloatAndMLFloat16(input, {scale_0, scale_1, scale_2}, shape); + RunBatchScaleTestWithFloatAndMLFloat16(input, {scale_0, scale_1}, shape); +} + +TEST(BatchScaleTest, SmallTensor2D) { + std::vector input = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.f, 7.f, 8.f, 9.f}; + float scale_0 = 0.25f; + float scale_1 = 0.25f; + float scale_2 = 0.5f; + std::vector shape{3, 3}; + RunBatchScaleTestWithFloatAndMLFloat16(input, {scale_0, scale_1, scale_2}, shape); + RunBatchScaleTestWithFloatAndMLFloat16(input, {scale_0, scale_1}, shape); +} + +TEST(BatchScaleTest, SmallTensorVectorized2D) { + std::vector input = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.f, 7.0f, 8.0f, + 9.0f, 10.0f, 11.0f, 12.f, 13.0f, 14.0f, 15.0f, 16.0f, + 17.0f, 18.0f, 19.0f, 20.0f, 21.0f, 22.f, 23.0f, 24.0f, + 25.0f, 26.0f, 27.0f, 28.0f, 29.0f, 30.f, 31.0f, 32.0f}; + float scale_0 = 0.25f; + float scale_1 = 0.25f; + float scale_2 = 0.5f; + std::vector shape{4, 8}; + RunBatchScaleTestWithFloatAndMLFloat16(input, {scale_0, scale_1, scale_2}, shape); + RunBatchScaleTestWithFloatAndMLFloat16(input, {scale_0, scale_1}, shape); +} + +} // namespace test +} // namespace onnxruntime + +#endif diff --git a/orttraining/orttraining/test/training_ops/cuda/conv_transpose_grad_test.cc b/orttraining/orttraining/test/training_ops/cuda/conv_transpose_grad_test.cc new file mode 100644 index 0000000000000..18c5ff94373dc --- /dev/null +++ b/orttraining/orttraining/test/training_ops/cuda/conv_transpose_grad_test.cc @@ -0,0 +1,360 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "gtest/gtest.h" +#include "test/providers/provider_test_utils.h" + +namespace onnxruntime::contrib::test { + +using namespace onnxruntime::test; + +#if USE_CUDA +namespace { + +struct ConvTransposeGradOpAttributes { + std::vector dilations; + int64_t group; + std::vector kernel_shape; + std::vector pads; + std::vector strides; +}; + +void TestConvTransposeGradOp(const ConvTransposeGradOpAttributes& attributes, + const std::vector>& inputs, + const std::vector>& input_shapes, + const std::vector>& outputs, + const std::vector>& output_shapes, + bool is_half = false) { + OpTester test("ConvTransposeGrad", 1, kMSDomain); + test.AddAttribute("group", attributes.group); + test.AddAttribute("kernel_shape", attributes.kernel_shape); + test.AddAttribute("pads", attributes.pads); + + if (!attributes.dilations.empty()) { + test.AddAttribute("dilations", attributes.dilations); + } + + if (!attributes.strides.empty()) { + test.AddAttribute("strides", attributes.strides); + } + + if (is_half) { + std::vector dY_half(inputs[0].size()); + ConvertFloatToMLFloat16(inputs[0].data(), dY_half.data(), static_cast(inputs[0].size())); + test.AddInput("dY", input_shapes[0], dY_half); + + std::vector X_half(inputs[1].size()); + ConvertFloatToMLFloat16(inputs[1].data(), X_half.data(), static_cast(inputs[1].size())); + test.AddInput("X", input_shapes[1], X_half); + + std::vector W_half(inputs[2].size()); + ConvertFloatToMLFloat16(inputs[2].data(), W_half.data(), static_cast(inputs[2].size())); + test.AddInput("W", input_shapes[2], W_half); + + std::vector dX_half(outputs[0].size()); + ConvertFloatToMLFloat16(outputs[0].data(), dX_half.data(), static_cast(outputs[0].size())); + test.AddOutput("dX", output_shapes[0], dX_half); + + std::vector dW_half(outputs[1].size()); + ConvertFloatToMLFloat16(outputs[1].data(), dW_half.data(), static_cast(outputs[1].size())); + test.AddOutput("dW", output_shapes[1], dW_half); + + if (outputs.size() >= 3) { + std::vector dB_half(outputs[2].size()); + ConvertFloatToMLFloat16(outputs[2].data(), dB_half.data(), static_cast(outputs[2].size())); + test.AddOutput("dB", output_shapes[2], dB_half); + } + } else { + test.AddInput("dY", input_shapes[0], inputs[0]); + test.AddInput("X", input_shapes[1], inputs[1]); + test.AddInput("W", input_shapes[2], inputs[2]); + + test.AddOutput("dX", output_shapes[0], outputs[0]); + test.AddOutput("dW", output_shapes[1], outputs[1]); + + if (outputs.size() >= 3) { + test.AddOutput("dB", output_shapes[2], outputs[2]); + } + } + + test.Run(); +} + +} // namespace + +TEST(ConvTransposeGradTest, ConvTranspose1DDefaultAttributes) { + ConvTransposeGradOpAttributes attrs = { + std::vector{1}, // dilations + 1, // group + std::vector{2}, // kernel_shape + std::vector{0, 0}, // pads + std::vector{1}, // strides + }; + + std::vector dY(12, 1.0f); + std::vector dY_shape = {1, 2, 6}; + std::vector X = {0.1868f, -0.1679f, 1.2677f, 2.1288f, -0.0331f, + 1.0454f, 0.7722f, 0.2963f, -0.8684f, -0.0547f}; + std::vector X_shape = {1, 2, 5}; + std::vector W = {0.0847f, -0.0066f, + 0.1212f, 0.2317f, + -0.4975f, 0.2762f, + -0.2644f, 0.3210f}; + std::vector W_shape = {2, 2, 2}; + std::vector dX = {0.4309f, 0.4309f, 0.4309f, 0.4309f, 0.4309f, + -0.1647f, -0.1647f, -0.1647f, -0.1647f, -0.1647f}; + std::vector dX_shape = X_shape; + std::vector dW = {3.3823f, 3.3823f, + 3.3823f, 3.3823f, + 1.1908f, 1.1908f, + 1.1908f, 1.1908f}; + std::vector dW_shape = W_shape; + std::vector dB = {6.f, 6.f}; + std::vector dB_shape = {2}; + + for (const bool is_half : {false, true}) + TestConvTransposeGradOp( + attrs, // attributes + {dY, X, W}, // inputs + {dY_shape, X_shape, W_shape}, // input shapes + {dX, dW, dB}, // outputs + {dX_shape, dW_shape, dB_shape}, // output shapes + is_half); +} + +TEST(ConvTransposeGradTest, ConvTranspose1DStrideAndPadding) { + ConvTransposeGradOpAttributes attrs = { + std::vector{1}, // dilations + 1, // group + std::vector{2}, // kernel_shape + std::vector{2, 2}, // pads + std::vector{2}, // strides + }; + + std::vector dY(12, 1.0f); + std::vector dY_shape = {1, 2, 6}; + std::vector X = {-0.0254f, -1.4303f, -0.1568f, 1.2318f, -0.8365f, + 2.0836f, -1.0181f, -0.7539f, 0.4484f, -0.5799f}; + std::vector X_shape = {1, 2, 5}; + std::vector W = {-0.1438f, 0.2386f, + -0.3085f, 0.1149f, + -0.1653f, -0.0707f, + -0.1479f, -0.0918f}; + std::vector W_shape = {2, 2, 2}; + std::vector dX = {0.0000f, -0.0988f, -0.0988f, -0.0988f, 0.0000f, + 0.0000f, -0.4757f, -0.4757f, -0.4757f, 0.0000f}; + std::vector dX_shape = X_shape; + std::vector dW = {-0.3553f, -0.3553f, + -0.3553f, -0.3553f, + -1.3236f, -1.3236f, + -1.3236f, -1.3236f}; + std::vector dW_shape = W_shape; + std::vector dB = {6.f, 6.f}; + std::vector dB_shape = {2}; + + for (const bool is_half : {false, true}) + TestConvTransposeGradOp( + attrs, // attributes + {dY, X, W}, // inputs + {dY_shape, X_shape, W_shape}, // input shapes + {dX, dW, dB}, // outputs + {dX_shape, dW_shape, dB_shape}, // output shapes + is_half); +} + +TEST(ConvTransposeGradTest, ConvTranspose1D) { + ConvTransposeGradOpAttributes attrs = { + std::vector{2}, // dilations + 2, // group + std::vector{3}, // kernel_shape + std::vector{2, 2}, // pads + std::vector{2}, // strides + }; + + std::vector dY(38, 1.0f); + std::vector dY_shape = {1, 2, 19}; + std::vector X = {0.2816f, 1.4660f, 0.1002f, -0.2460f, -0.1027f, 0.1228f, -0.8516f, -1.0246f, -0.6576f, -1.0280f, + 0.1093f, 0.1447f, 1.1279f, 0.1085f, -0.3438f, -0.6224f, -0.0902f, 2.2791f, -2.1910f, 1.9736f}; + std::vector X_shape = {1, 2, 10}; + std::vector W = {-0.1050f, -0.0622f, -0.3632f, + -0.3861f, -0.0134f, -0.0277f}; + std::vector W_shape = {2, 1, 3}; + std::vector dX = {-0.4254f, -0.5304f, -0.5304f, -0.5304f, -0.5304f, -0.5304f, -0.5304f, -0.5304f, -0.5304f, -0.1672f, + -0.0411f, -0.4272f, -0.4272f, -0.4272f, -0.4272f, -0.4272f, -0.4272f, -0.4272f, -0.4272f, -0.3995f}; + std::vector dX_shape = X_shape; + std::vector dW = {-2.2215f, -1.9400f, -0.9120f, + 2.3863f, 2.4956f, 0.5220f}; + std::vector dW_shape = W_shape; + std::vector dB = {19.f, 19.f}; + std::vector dB_shape = {2}; + + for (const bool is_half : {false, true}) + TestConvTransposeGradOp( + attrs, // attributes + {dY, X, W}, // inputs + {dY_shape, X_shape, W_shape}, // input shapes + {dX, dW, dB}, // outputs + {dX_shape, dW_shape, dB_shape}, // output shapes + is_half); +} + +TEST(ConvTransposeGradTest, ConvTranspose2DDefaultAttributes) { + ConvTransposeGradOpAttributes attrs = { + std::vector{1, 1}, // dilations + 1, // group + std::vector{3, 3}, // kernel_shape + std::vector{0, 0, 0, 0}, // pads + std::vector{1, 1}, // strides + }; + + std::vector dY(98, 1.0f); + std::vector dY_shape = {1, 2, 7, 7}; + std::vector X = {1.1371f, -0.1498f, -1.7541f, -0.7585f, 1.6009f, -0.7496f, 0.1535f, -0.2533f, -1.0811f, 0.9760f, + -0.2528f, 0.1820f, -1.7450f, 0.1632f, -0.3469f, 1.1150f, -2.6888f, -0.1632f, -0.3269f, 0.6904f, + 1.3036f, 0.7883f, 0.4459f, 0.1223f, 0.1576f, -0.8187f, 0.2281f, 1.5320f, 1.2643f, -0.5163f, + 1.0677f, -0.2141f, 1.2992f, -2.1865f, -0.6346f, 0.8938f, 0.8346f, -2.7397f, 0.9223f, 0.8166f, + 1.1736f, -1.3644f, 0.0316f, -1.2904f, 0.7062f, 0.2470f, 0.4559f, 0.8493f, 1.0519f, 0.9915f}; + std::vector X_shape = {1, 2, 5, 5}; + std::vector W = {0.0761f, 0.0270f, -0.1677f, 0.1803f, -0.0824f, -0.0285f, + 0.2098f, -0.0569f, -0.1514f, 0.0338f, -0.1962f, -0.2169f, + 0.0432f, -0.1977f, -0.0814f, -0.1866f, -0.1574f, -0.0198f, + 0.0097f, 0.0019f, -0.1204f, 0.2018f, -0.1750f, -0.0549f, + -0.0687f, -0.1269f, 0.1913f, 0.1331f, -0.0632f, 0.0821f, + 0.0127f, 0.1761f, -0.0883f, -0.1370f, 0.1472f, 0.0690f}; + std::vector W_shape = {2, 2, 3, 3}; + std::vector dX = {-0.9725f, -0.9725f, -0.9725f, -0.9725f, -0.9725f, -0.9725f, -0.9725f, -0.9725f, -0.9725f, -0.9725f, + -0.9725f, -0.9725f, -0.9725f, -0.9725f, -0.9725f, -0.9725f, -0.9725f, -0.9725f, -0.9725f, -0.9725f, + -0.9725f, -0.9725f, -0.9725f, -0.9725f, -0.9725f, 0.1905f, 0.1905f, 0.1905f, 0.1905f, 0.1905f, + 0.1905f, 0.1905f, 0.1905f, 0.1905f, 0.1905f, 0.1905f, 0.1905f, 0.1905f, 0.1905f, 0.1905f, + 0.1905f, 0.1905f, 0.1905f, 0.1905f, 0.1905f, 0.1905f, 0.1905f, 0.1905f, 0.1905f, 0.1905f}; + std::vector dX_shape = X_shape; + std::vector dW = {-1.4343f, -1.4343f, -1.4343f, -1.4343f, -1.4343f, -1.4343f, + -1.4343f, -1.4343f, -1.4343f, -1.4343f, -1.4343f, -1.4343f, + -1.4343f, -1.4343f, -1.4343f, -1.4343f, -1.4343f, -1.4343f, + 4.6009f, 4.6009f, 4.6009f, 4.6009f, 4.6009f, 4.6009f, + 4.6009f, 4.6009f, 4.6009f, 4.6009f, 4.6009f, 4.6009f, + 4.6009f, 4.6009f, 4.6009f, 4.6009f, 4.6009f, 4.6009f}; + std::vector dW_shape = W_shape; + std::vector dB = {49.f, 49.f}; + std::vector dB_shape = {2}; + + for (const bool is_half : {false, true}) + TestConvTransposeGradOp( + attrs, // attributes + {dY, X, W}, // inputs + {dY_shape, X_shape, W_shape}, // input shapes + {dX, dW, dB}, // outputs + {dX_shape, dW_shape, dB_shape}, // output shapes + is_half); +} + +TEST(ConvTransposeGradTest, ConvTranspose2D) { + ConvTransposeGradOpAttributes attrs = { + std::vector{2, 2}, // dilations + 2, // group + std::vector{3, 3}, // kernel_shape + std::vector{2, 2, 2, 2}, // pads + std::vector{2, 2}, // strides + }; + + std::vector dY(162U, 1.0f); + std::vector dY_shape = {1, 2, 9, 9}; + std::vector X = {-1.0158f, 0.1709f, -0.1660f, 0.3881f, 0.4017f, 1.5497f, 1.1205f, 0.2553f, -0.4359f, -0.0467f, + 1.1374f, -0.0713f, 0.2248f, 0.8915f, -0.7239f, 0.1679f, -1.5604f, -0.8521f, 0.8966f, 3.3743f, + -0.5516f, 0.2516f, -0.4091f, -0.9868f, 0.3008f, 1.1066f, -0.7039f, -1.5273f, -0.3666f, 0.9392f, + 0.1264f, -1.6604f, -1.4810f, 0.6654f, -0.2007f, -1.0660f, -0.5420f, -0.7030f, 0.0411f, 2.1082f, + -0.7995f, 0.2422f, 1.2848f, -0.1747f, 1.7935f, -0.1123f, -0.6668f, -2.2383f, 1.5419f, -2.7614f}; + std::vector X_shape = {1, 2, 5, 5}; + std::vector W = {-0.2057f, -0.0411f, 0.0277f, 0.2221f, 0.1901f, 0.1435f, + -0.2249f, 0.3299f, -0.2203f, -0.1013f, -0.3326f, 0.1005f, + -0.0536f, 0.3067f, 0.3297f, 0.2728f, 0.1649f, -0.2548f}; + std::vector W_shape = {2, 1, 3, 3}; + std::vector dX = {0.4431f, 0.4403f, 0.4403f, 0.4403f, 0.5171f, 0.4297f, 0.2212f, 0.2212f, 0.2212f, 0.2704f, + 0.4297f, 0.2212f, 0.2212f, 0.2212f, 0.2704f, 0.4297f, 0.2212f, 0.2212f, 0.2212f, 0.2704f, + 0.3202f, 0.3366f, 0.3366f, 0.3366f, 0.1654f, 0.5465f, 0.7658f, 0.7658f, 0.7658f, 0.6908f, + 0.3144f, 0.4323f, 0.4323f, 0.4323f, 0.2569f, 0.3144f, 0.4323f, 0.4323f, 0.4323f, 0.2569f, + 0.3144f, 0.4323f, 0.4323f, 0.4323f, 0.2569f, 0.4043f, 0.2494f, 0.2494f, 0.2494f, -0.1808f}; + std::vector dX_shape = X_shape; + std::vector dW = {2.2293f, 4.5327f, 1.6281f, 3.0240f, 4.3115f, 1.0052f, + 3.8675f, 5.7067f, 2.7011f, -2.7512f, -4.6026f, -5.5423f, + -4.4098f, -5.1546f, -7.0335f, -0.2852f, -0.9177f, -5.5580f}; + std::vector dW_shape = W_shape; + std::vector dB = {81.f, 81.f}; + std::vector dB_shape = {2}; + + for (const bool is_half : {false, true}) + TestConvTransposeGradOp( + attrs, // attributes + {dY, X, W}, // inputs + {dY_shape, X_shape, W_shape}, // input shapes + {dX, dW, dB}, // outputs + {dX_shape, dW_shape, dB_shape}, // output shapes + is_half); +} + +TEST(ConvTransposeGradTest, ConvTranspose3D) { + ConvTransposeGradOpAttributes attrs = { + std::vector{2, 2, 2}, // dilations + 2, // group + std::vector{2, 2, 2}, // kernel_shape + std::vector{2, 2, 2, 2, 2, 2}, // pads + std::vector{2, 2, 2}, // strides + }; + + std::vector dY(250U, 1.0f); + std::vector dY_shape = {1, 2, 5, 5, 5}; + std::vector X = {-0.2396f, 0.4280f, -1.3505f, -0.4366f, -1.3296f, 0.3531f, 0.0645f, -1.5480f, + -1.7464f, -0.9160f, 1.5065f, -0.0788f, 0.0487f, 2.4641f, 0.3855f, 2.0499f, + 0.7068f, -0.8076f, -0.4442f, 0.1003f, -0.5056f, -0.1430f, -0.3744f, -0.2637f, + -1.1012f, 1.0213f, 0.0503f, 0.0147f, -0.3664f, 0.8834f, -1.1478f, -0.8221f, + -0.5649f, -0.4224f, -0.6779f, -0.9363f, 1.1972f, 0.2094f, 0.5676f, -0.2718f, + -0.1678f, -0.4178f, -0.4672f, 0.2777f, -0.7953f, -0.5603f, -2.8694f, 1.5743f, + -0.5057f, -0.2529f, 0.5894f, -0.3980f, -0.6719f, -0.3425f, 0.0821f, 0.8672f, + 0.7218f, 1.5519f, 1.6513f, -1.1956f, 0.8471f, 0.4295f, -1.3917f, -1.2202f, + 0.1054f, -2.2191f, -0.9546f, 1.1750f, -2.3637f, 1.6297f, -0.5796f, 0.3850f, + 0.9287f, -0.3492f, -0.7284f, 0.2987f, -0.7534f, 0.7747f, -1.3198f, -0.3633f, + 1.8635f, -0.3187f, 0.9032f, -0.6083f, -0.4236f, -0.1929f, -1.1715f, -0.5591f, + -1.8290f, -1.1503f, 0.1430f, 0.6048f, -0.3148f, 1.0638f, -0.2946f, -0.4990f, + -1.4443f, -0.7757f, -1.5374f, -0.4567f, -0.2998f, 0.0521f, 1.6293f, -0.6720f, + -0.0102f, -0.6598f, 0.5005f, 0.4203f, 1.3911f, 1.5988f, 0.3991f, 1.4931f, + 0.9741f, 0.3557f, 0.1088f, -1.1806f, 1.1115f, -1.3283f, 1.7235f, 0.4177f, + 0.7992f, -1.7248f, -0.5339f, -0.3153f, 0.1379f, 0.7493f, 0.3028f, -0.9473f}; + std::vector X_shape = {1, 2, 4, 4, 4}; + std::vector W = {-0.1093f, -0.0511f, 0.1132f, 0.3369f, -0.3531f, -0.1766f, 0.0628f, 0.2118f, + 0.3068f, 0.3217f, -0.2903f, -0.1633f, -0.3261f, -0.0990f, 0.2497f, -0.1553f}; + std::vector W_shape = {2, 1, 2, 2, 2}; + std::vector dX = {0.2118f, 0.2746f, 0.2746f, 0.0628f, 0.0352f, -0.2550f, -0.2550f, -0.2902f, + 0.0352f, -0.2550f, -0.2550f, -0.2902f, -0.1766f, -0.5297f, -0.5297f, -0.3531f, + 0.5487f, 0.7247f, 0.7247f, 0.1760f, 0.3210f, 0.0346f, 0.0346f, -0.2864f, + 0.3210f, 0.0346f, 0.0346f, -0.2864f, -0.2277f, -0.6901f, -0.6901f, -0.4624f, + 0.5487f, 0.7247f, 0.7247f, 0.1760f, 0.3210f, 0.0346f, 0.0346f, -0.2864f, + 0.3210f, 0.0346f, 0.0346f, -0.2864f, -0.2277f, -0.6901f, -0.6901f, -0.4624f, + 0.3369f, 0.4501f, 0.4501f, 0.1132f, 0.2858f, 0.2897f, 0.2897f, 0.0038f, + 0.2858f, 0.2897f, 0.2897f, 0.0038f, -0.0511f, -0.1604f, -0.1604f, -0.1093f, + -0.1553f, 0.0944f, 0.0944f, 0.2497f, -0.2542f, -0.3307f, -0.3307f, -0.0765f, + -0.2542f, -0.3307f, -0.3307f, -0.0765f, -0.0990f, -0.4251f, -0.4251f, -0.3261f, + -0.3185f, -0.3592f, -0.3592f, -0.0407f, -0.0958f, -0.1557f, -0.1557f, -0.0600f, + -0.0958f, -0.1557f, -0.1557f, -0.0600f, 0.2227f, 0.2035f, 0.2035f, -0.0193f, + -0.3185f, -0.3592f, -0.3592f, -0.0407f, -0.0958f, -0.1557f, -0.1557f, -0.0600f, + -0.0958f, -0.1557f, -0.1557f, -0.0600f, 0.2227f, 0.2035f, 0.2035f, -0.0193f, + -0.1633f, -0.4536f, -0.4536f, -0.2903f, 0.1584f, 0.1749f, 0.1749f, 0.0165f, + 0.1584f, 0.1749f, 0.1749f, 0.0165f, 0.3217f, 0.6285f, 0.6285f, 0.3068f}; + std::vector dX_shape = X_shape; + std::vector dW = {-2.3068f, -2.1096f, -0.4322f, 0.4820f, 1.5420f, -4.1569f, -4.9628f, -5.5716f, + 1.0492f, 1.6683f, -6.3262f, -3.2359f, 2.4532f, -2.3299f, -5.1917f, -9.2525f}; + std::vector dW_shape = W_shape; + std::vector dB = {125.f, 125.f}; + std::vector dB_shape = {2}; + + for (const bool is_half : {false, true}) + TestConvTransposeGradOp( + attrs, // attributes + {dY, X, W}, // inputs + {dY_shape, X_shape, W_shape}, // input shapes + {dX, dW, dB}, // outputs + {dX_shape, dW_shape, dB_shape}, // output shapes + is_half); +} +#endif // USE_CUDA + +} // namespace onnxruntime::contrib::test diff --git a/orttraining/orttraining/test/training_ops/cuda/cross_entropy_test.cc b/orttraining/orttraining/test/training_ops/cuda/cross_entropy_test.cc index 0c64cddc20d54..d9800ce0e0d3e 100644 --- a/orttraining/orttraining/test/training_ops/cuda/cross_entropy_test.cc +++ b/orttraining/orttraining/test/training_ops/cuda/cross_entropy_test.cc @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#include #include #include "test/compare_ortvalue.h" #include "test/util/include/default_providers.h" @@ -283,14 +284,18 @@ TEST(CrossEntropyTest, SparseSoftmaxCrossEntropyGrad_LargeSizeTensor) { TestSparseSoftmaxCrossEntropyGrad(dY_dims, log_prob_dims, index_dims, dX_dims, "sum"); } -static void PrepareSCELossTestData(const std::vector* X_dims, - const std::vector* index_dims, const std::vector* weight_dims, - const std::int64_t ignore_index, - std::vector& X_data, std::vector& index_data, - std::vector& weight_data) { +template +void PrepareSCELossTestData(const std::vector* X_dims, + const std::vector* index_dims, const std::vector* weight_dims, + const std::int64_t ignore_index, + std::vector& X_data, + std::vector& index_data, + std::vector& weight_data) { // create rand inputs + ParallelRandomValueGenerator prandom{2333}; + X_data = prandom.Uniform(*X_dims, -200.0f, 200.0f); + RandomValueGenerator random{2333}; - X_data = random.Uniform(*X_dims, -200.0f, 200.0f); index_data = random.Uniform(*index_dims, 0, (*X_dims)[1]); // Add one data point that has ignore_index. if (index_data.size() > 0) { @@ -298,7 +303,7 @@ static void PrepareSCELossTestData(const std::vector* X_dims, } if (weight_dims) { - weight_data = random.Uniform(*weight_dims, 0.0f, 1.0f); + weight_data = prandom.Uniform(*weight_dims, 0.0f, 1.0f); } } @@ -316,9 +321,9 @@ static std::vector RunSCELossWithEP(const char* op, const std::vector* weight_dims, const std::vector* Y_dims, const std::vector* log_prob_dims, - std::vector& X_data, + std::vector& X_data, std::vector& index_data, - std::vector& weight_data) { + std::vector& weight_data) { /** * OpTester's atol/rtol check is too strict for our testing cases. Imagine expected value is 4.7683704451628728e-07, * real value is 0, even we set rtol=1e-1, atol = 1e-4. The check still fail. @@ -330,11 +335,11 @@ static std::vector RunSCELossWithEP(const char* op, * So here we disable OpTester's check by default, and do the check externally. */ bool need_verify_outputs = false; - std::vector> expected_values; + std::vector> expected_values; // Still need feed the output data even we don't want to verify it. - expected_values.push_back(FillZeros(*Y_dims)); + expected_values.push_back(FillZeros(*Y_dims)); if (log_prob_dims) { - expected_values.push_back(FillZeros(*log_prob_dims)); + expected_values.push_back(FillZeros(*log_prob_dims)); } OpTester test(op, opset_version, domain, need_verify_outputs /*verify_output*/); @@ -349,46 +354,21 @@ static std::vector RunSCELossWithEP(const char* op, test.AddAttribute("ignore_index", ignore_index); } - if (std::is_same::value) { - std::vector X_data_half(X_data.size()); - ConvertFloatToMLFloat16(X_data.data(), X_data_half.data(), static_cast(X_data.size())); - test.AddInput("X", *X_dims, X_data_half); - } else { - test.AddInput("X", *X_dims, X_data); - } + test.AddInput("X", *X_dims, X_data); test.AddInput("index", *index_dims, index_data); if (weight_dims) { - if (std::is_same::value) { - std::vector weight_data_half(weight_data.size()); - ConvertFloatToMLFloat16(weight_data.data(), weight_data_half.data(), static_cast(weight_data.size())); - test.AddInput("weight", *weight_dims, weight_data_half); - } else { - test.AddInput("weight", *weight_dims, weight_data); - } + test.AddInput("weight", *weight_dims, weight_data); } if (is_internal_op && ignore_index != -1) { test.AddInput("ignore_index", {}, &ignore_index, 1); } - if (std::is_same::value) { - std::vector output_half(expected_values[0].size()); - ConvertFloatToMLFloat16(expected_values[0].data(), output_half.data(), static_cast(expected_values[0].size())); - test.AddOutput("output", *Y_dims, output_half); - - if (log_prob_dims) { - std::vector log_prob_half(expected_values[1].size()); - ConvertFloatToMLFloat16(expected_values[1].data(), log_prob_half.data(), static_cast(expected_values[1].size())); - test.AddOutput("log_prob", *log_prob_dims, log_prob_half); - } - - } else { - test.AddOutput("output", *Y_dims, expected_values[0]); - if (log_prob_dims) { - test.AddOutput("log_prob", *log_prob_dims, expected_values[1]); - } + test.AddOutput("output", *Y_dims, expected_values[0]); + if (log_prob_dims) { + test.AddOutput("log_prob", *log_prob_dims, expected_values[1]); } std::vector> eps; @@ -407,23 +387,38 @@ static void TestSCELoss(const char* op, int opset_version, ASSERT_TRUE((std::is_same::value || std::is_same::value)); ASSERT_TRUE((std::is_same::value || std::is_same::value)); - std::vector X_data, weight_data; + std::vector X_data, weight_data; std::vector index_data; - PrepareSCELossTestData(X_dims, index_dims, weight_dims, ignore_index, X_data, index_data, weight_data); + PrepareSCELossTestData(X_dims, index_dims, weight_dims, ignore_index, X_data, index_data, weight_data); // Run on CPU using float input and output // (because the CPU implementation doesn't support variant input output types.) // Be noted, no result comparison is done here. - std::vector cpu_fetches = RunSCELossWithEP( - op, opset_version, domain, - []() -> std::unique_ptr { return DefaultCpuExecutionProvider(); }, - reduction, ignore_index, error_tolerance, - X_dims, index_dims, weight_dims, - Y_dims, log_prob_dims, - X_data, index_data, weight_data); + std::vector cpu_fetches; + if (std::is_same::value) { + std::vector X_data_temp(X_data.size()); + std::vector weight_data_temp(weight_data.size()); + ConvertMLFloat16ToFloat(reinterpret_cast(X_data.data()), X_data_temp.data(), X_data.size()); + ConvertMLFloat16ToFloat(reinterpret_cast(weight_data.data()), weight_data_temp.data(), weight_data.size()); + cpu_fetches = RunSCELossWithEP( + op, opset_version, domain, + []() -> std::unique_ptr { return DefaultCpuExecutionProvider(); }, + reduction, ignore_index, error_tolerance, + X_dims, index_dims, weight_dims, + Y_dims, log_prob_dims, + X_data_temp, index_data, weight_data_temp); + } else { + cpu_fetches = RunSCELossWithEP( + op, opset_version, domain, + []() -> std::unique_ptr { return DefaultCpuExecutionProvider(); }, + reduction, ignore_index, error_tolerance, + X_dims, index_dims, weight_dims, + Y_dims, log_prob_dims, + X_data, index_data, weight_data); + } // Run on CUDA. - // Be noted, no result comparison is done here because OpTester's check is too strick for our test cases. + // Be noted, no result comparison is done here because OpTester's check is too strict for our test cases. // Check more details in comment of RunSCELossWithEP. std::vector target_fetches = RunSCELossWithEP( op, opset_version, domain, @@ -442,22 +437,10 @@ static void TestSCELoss(const char* op, int opset_version, // Compare ASSERT_EQ(cpu_fetches.size(), target_fetches.size()); for (size_t i = 0; i < cpu_fetches.size(); i++) { - if (std::is_same::value) { - auto y_data_size = cpu_fetches[i].Get().Shape().Size(); - std::vector cpu_temp_buffer; - cpu_temp_buffer.resize(y_data_size); - const float* y_buffer = cpu_fetches[i].Get().Data(); - std::copy(y_buffer, y_buffer + y_data_size, cpu_temp_buffer.begin()); - - std::vector ret_half(cpu_temp_buffer.size()); - ConvertFloatToMLFloat16(cpu_temp_buffer.data(), ret_half.data(), static_cast(cpu_temp_buffer.size())); - - OrtValue target; - test::CreateInputOrtValueOnCPU(cpu_fetches[i].Get().Shape().GetDims(), ret_half, &target); - auto ret = CompareOrtValue(target_fetches[i], target, error_tolerance /*per_sample_tolerance*/, - error_tolerance /*relative_per_sample_tolerance*/, false); + if (!std::is_same::value) { // baseline output is float. + auto ret = CompareOrtValueNumerals(target_fetches[i], cpu_fetches[i], error_tolerance /*per_sample_tolerance*/, + error_tolerance /*relative_per_sample_tolerance*/); EXPECT_EQ(ret.first, COMPARE_RESULT::SUCCESS) << ret.second; - } else { auto ret = CompareOrtValue(target_fetches[i], cpu_fetches[i], error_tolerance /*per_sample_tolerance*/, error_tolerance /*relative_per_sample_tolerance*/, false); @@ -655,6 +638,29 @@ TEST(CrossEntropyTest, DISABLED_SoftmaxCrossEntropyLoss_LargeSizeTensor) { TestSoftmaxCrossEntropyLoss(&X_dims, &index_dims, nullptr, &Y_dims_none, &log_prob_dims, "none"); } +#ifndef _WIN32 +// Disable the large size tests for Windows because it is too slow, running on Linux would be enough. +// This test requires lots of memory, currently, it can run with 16GB V100 GPU. +TEST(CrossEntropyTest, DISABLED_SoftmaxCrossEntropyLossInternal_LargeSizeTensorUInt64Index) { + // The element count is bigger than the upper limit of int32_t. + constexpr int64_t bsz = 419431; + constexpr int64_t vocab_size = 5120; + std::vector X_dims{bsz, vocab_size}; + std::vector index_dims{bsz}; + std::vector weight_dims{vocab_size}; + std::vector Y_dims{}; + std::vector Y_dims_none{bsz}; + std::vector log_prob_dims{bsz, vocab_size}; + + constexpr std::int64_t ignore_index = -1; + constexpr double error_tolerance = 1e-3; + // Only test reduce mean because it's too costly to run more tests. + TestSCELoss("SoftmaxCrossEntropyLossInternal", 1, onnxruntime::kMSDomain, + &X_dims, &index_dims, &weight_dims, &Y_dims, &log_prob_dims, "mean", + ignore_index, error_tolerance); +} +#endif + static void TestSoftmaxCrossEntropyLossGrad(const std::vector& dY_dims, const std::vector& log_prob_dims, const std::vector& index_dims, @@ -678,11 +684,11 @@ static void TestSoftmaxCrossEntropyLossGrad(const std::vector& dY_dims, } if (test_fp16) { std::vector dY_data_half(dY_data.size()); - ConvertFloatToMLFloat16(dY_data.data(), dY_data_half.data(), static_cast(dY_data.size())); + ConvertFloatToMLFloat16(dY_data.data(), dY_data_half.data(), dY_data.size()); test.AddInput("dY", dY_dims, dY_data_half); std::vector log_prob_data_half(log_prob_data.size()); - ConvertFloatToMLFloat16(log_prob_data.data(), log_prob_data_half.data(), static_cast(log_prob_data.size())); + ConvertFloatToMLFloat16(log_prob_data.data(), log_prob_data_half.data(), log_prob_data.size()); test.AddInput("log_prob", log_prob_dims, log_prob_data_half); test.AddInput("index", index_dims, index_data); @@ -738,7 +744,7 @@ TEST(CrossEntropyTest, SoftmaxCrossEntropyLossGrad_LargeSizeTensor) { TestSoftmaxCrossEntropyLossGrad({2, 30528}, log_prob_dims, index_dims, dX_dims, "none"); } -TEST(CrossEntropyTest, DISABLED_SoftmaxCrossEntropyLossGrad_TinySizeTensor_half) { // [E:onnxruntime:Default, compare_provider_test_utils.cc:105 CompareWithCPU] Initialize failed with status: Could not find an implementation for Equal(19) node with name '' +TEST(CrossEntropyTest, SoftmaxCrossEntropyLossGrad_TinySizeTensor_half) { std::vector dY_dims{}; std::vector log_prob_dims{8, 2}; std::vector index_dims{8}; @@ -753,7 +759,7 @@ TEST(CrossEntropyTest, DISABLED_SoftmaxCrossEntropyLossGrad_TinySizeTensor_half) TestSoftmaxCrossEntropyLossGrad({8}, log_prob_dims, index_dims, dX_dims, "none", 0, true, 5e-2); } -TEST(CrossEntropyTest, DISABLED_SoftmaxCrossEntropyLossGrad_SmallSizeTensor_half) { // [E:onnxruntime:Default, compare_provider_test_utils.cc:105 CompareWithCPU] Initialize failed with status: Could not find an implementation for Equal(19) node with name '' +TEST(CrossEntropyTest, SoftmaxCrossEntropyLossGrad_SmallSizeTensor_half) { std::vector dY_dims{}; std::vector log_prob_dims{8, 20, 10}; std::vector index_dims{8, 10}; @@ -763,7 +769,7 @@ TEST(CrossEntropyTest, DISABLED_SoftmaxCrossEntropyLossGrad_SmallSizeTensor_half TestSoftmaxCrossEntropyLossGrad({8, 10}, log_prob_dims, index_dims, dX_dims, "none", -1, true, 5e-2); } -TEST(CrossEntropyTest, DISABLED_SoftmaxCrossEntropyLossGrad_LargeSizeTensor_half) { // [E:onnxruntime:Default, compare_provider_test_utils.cc:105 CompareWithCPU] Initialize failed with status: Could not find an implementation for Equal(19) node with name '' +TEST(CrossEntropyTest, SoftmaxCrossEntropyLossGrad_LargeSizeTensor_half) { std::vector dY_dims{}; std::vector log_prob_dims{2, 512, 30528}; std::vector index_dims{2, 30528}; @@ -773,26 +779,28 @@ TEST(CrossEntropyTest, DISABLED_SoftmaxCrossEntropyLossGrad_LargeSizeTensor_half TestSoftmaxCrossEntropyLossGrad({2, 30528}, log_prob_dims, index_dims, dX_dims, "none", -1, true, 5e-2); } -static void PrepareSCELossInternalGradTestData( +template +void PrepareSCELossInternalGradTestData( const std::vector& dY_dims, const std::vector& log_prob_dims, const std::vector& index_dims, const std::vector& weight_dims, const std::vector& dX_dims, const std::int64_t ignore_index, bool has_bias, - std::vector& dY_data, std::vector& log_prob_data, - std::vector& index_data, std::vector& weight_data, - std::vector& bias_data) { + std::vector& dY_data, std::vector& log_prob_data, + std::vector& index_data, std::vector& weight_data, + std::vector& bias_data) { // Create rand inputs RandomValueGenerator random{2333}; - dY_data = random.Uniform(dY_dims, -10.0f, 10.0f); - log_prob_data = random.Uniform(log_prob_dims, -10.0f, 10.0f); + ParallelRandomValueGenerator prandom{2333}; + dY_data = prandom.Uniform(dY_dims, -10.0f, 10.0f); + log_prob_data = prandom.Uniform(log_prob_dims, -10.0f, 10.0f); index_data = random.Uniform(index_dims, 0, dX_dims[1]); // Add one data point that has ignore_index. if ((ignore_index != -1) && (index_data.size() > 0)) { index_data[0] = ignore_index; } - weight_data = random.Uniform(weight_dims, 0.0f, 1.0f); + weight_data = prandom.Uniform(weight_dims, 0.0f, 1.0f); if (has_bias) { - bias_data = random.Uniform(dX_dims, 0.0f, 1.0f); + bias_data = prandom.Uniform(dX_dims, 0.0f, 1.0f); } } @@ -809,11 +817,11 @@ static std::vector RunSCELossInternalGradWithEP( const std::vector& index_dims, const std::vector& weight_dims, const std::vector& dX_dims, - std::vector& dY_data, - std::vector& log_prob_data, + std::vector& dY_data, + std::vector& log_prob_data, std::vector& index_data, - std::vector& weight_data, - std::vector& bias_data) { + std::vector& weight_data, + std::vector& bias_data) { /** * OpTester's atol/rtol check is too strict for our testing cases. Imagine expected value is 4.7683704451628728e-07, * real value is 0, even we set rtol=1e-1, atol = 1e-4. The check still fail with the following check: @@ -825,7 +833,7 @@ static std::vector RunSCELossInternalGradWithEP( * So here we disable OpTester's check by default, and do the check externally. */ bool need_verify_outputs = false; - std::vector expected_value = FillZeros(dX_dims); + std::vector expected_value = FillZeros(dX_dims); ORT_ENFORCE((std::is_same::value || std::is_same::value)); ORT_ENFORCE((std::is_same::value || std::is_same::value)); @@ -840,56 +848,21 @@ static std::vector RunSCELossInternalGradWithEP( test->AddAttribute("output_type", static_cast(utils::ToTensorProtoElementType())); } - if (std::is_same::value) { - std::vector dY_data_half(dY_data.size()); - ConvertFloatToMLFloat16(dY_data.data(), dY_data_half.data(), static_cast(dY_data.size())); - test->AddInput("dY", dY_dims, dY_data_half); - - std::vector log_prob_data_half(log_prob_data.size()); - ConvertFloatToMLFloat16(log_prob_data.data(), log_prob_data_half.data(), static_cast(log_prob_data.size())); - test->AddInput("log_prob", log_prob_dims, log_prob_data_half); - - test->AddInput("index", index_dims, index_data); - - std::vector weight_data_half(weight_data.size()); - ConvertFloatToMLFloat16(weight_data.data(), weight_data_half.data(), static_cast(weight_data.size())); - test->AddInput("weight", weight_dims, weight_data_half); - - if (ignore_index != -1 || has_bias) { - test->AddInput("ignore_index", {}, &ignore_index, 1); - } - } else { - test->AddInput("dY", dY_dims, dY_data); - test->AddInput("log_prob", log_prob_dims, log_prob_data); - test->AddInput("index", index_dims, index_data); - test->AddInput("weight", weight_dims, weight_data); - if (ignore_index != -1 || has_bias) { - test->AddInput("ignore_index", {}, &ignore_index, 1); - } + test->AddInput("dY", dY_dims, dY_data); + test->AddInput("log_prob", log_prob_dims, log_prob_data); + test->AddInput("index", index_dims, index_data); + test->AddInput("weight", weight_dims, weight_data); + if (ignore_index != -1 || has_bias) { + test->AddInput("ignore_index", {}, &ignore_index, 1); } - if (std::is_same::value) { - // Be noted, bias should be aligned with output's data type. - if (has_bias) { - std::vector bias_data_half(bias_data.size()); - ConvertFloatToMLFloat16(bias_data.data(), bias_data_half.data(), static_cast(bias_data.size())); - test->AddInput("bias", dX_dims, bias_data_half); - } - - std::vector expected_data_half(expected_value.size()); - ConvertFloatToMLFloat16(expected_value.data(), expected_data_half.data(), static_cast(expected_value.size())); - test->AddOutput("dX", dX_dims, expected_data_half, false /*sort_output*/, - error_tolerance /*rel_error*/, error_tolerance /*abs_error*/); - - } else { - if (has_bias) { - test->AddInput("bias", dX_dims, bias_data); - } - - test->AddOutput("dX", dX_dims, expected_value, false /*sort_output*/, - error_tolerance /*rel_error*/, error_tolerance /*abs_error*/); + if (has_bias) { + test->AddInput("bias", dX_dims, bias_data); } + test->AddOutput("dX", dX_dims, expected_value, false /*sort_output*/, + error_tolerance /*rel_error*/, error_tolerance /*abs_error*/); + std::vector> eps; eps.emplace_back(ep_creator()); test->Run(OpTester::ExpectResult::kExpectSuccess, "", {}, nullptr, &eps); @@ -906,20 +879,56 @@ static void TestSoftmaxCrossEntropyLossInternalGrad(const std::vector& const std::int64_t ignore_index = -1, const double error_tolerance = 1e-4, const bool has_bias = false) { - std::vector dY_data, log_prob_data, weight_data, bias_data; + std::vector dY_data, log_prob_data, weight_data; + std::vector bias_data; std::vector index_data; - PrepareSCELossInternalGradTestData(dY_dims, log_prob_dims, index_dims, weight_dims, dX_dims, ignore_index, has_bias, - dY_data, log_prob_data, index_data, weight_data, bias_data); + PrepareSCELossInternalGradTestData(dY_dims, log_prob_dims, index_dims, weight_dims, dX_dims, ignore_index, + has_bias, dY_data, log_prob_data, index_data, weight_data, bias_data); + std::vector cpu_fetches; // Run on CPU using float input and output // (because the CPU implementation doesn't support variant input output types.) // Be noted, no result comparison is done here. - std::vector cpu_fetches = - RunSCELossInternalGradWithEP( + if constexpr (std::is_same::value) { + std::vector dY_data_temp(dY_data.size()); + std::vector log_prob_data_temp(log_prob_data.size()); + std::vector weight_data_temp(weight_data.size()); + ConvertMLFloat16ToFloat(reinterpret_cast(dY_data.data()), dY_data_temp.data(), dY_data.size()); + ConvertMLFloat16ToFloat(reinterpret_cast(log_prob_data.data()), log_prob_data_temp.data(), + log_prob_data.size()); + ConvertMLFloat16ToFloat(reinterpret_cast(weight_data.data()), weight_data_temp.data(), weight_data.size()); + if constexpr (std::is_same::value) { + std::vector bias_data_temp(bias_data.size()); + ConvertMLFloat16ToFloat(reinterpret_cast(bias_data.data()), bias_data_temp.data(), bias_data.size()); + cpu_fetches = RunSCELossInternalGradWithEP( + []() -> std::unique_ptr { return DefaultCpuExecutionProvider(); }, + reduction, ignore_index, error_tolerance, has_bias, + dY_dims, log_prob_dims, index_dims, weight_dims, dX_dims, + dY_data_temp, log_prob_data_temp, index_data, weight_data_temp, bias_data_temp); + } else { + cpu_fetches = RunSCELossInternalGradWithEP( + []() -> std::unique_ptr { return DefaultCpuExecutionProvider(); }, + reduction, ignore_index, error_tolerance, has_bias, + dY_dims, log_prob_dims, index_dims, weight_dims, dX_dims, + dY_data_temp, log_prob_data_temp, index_data, weight_data_temp, bias_data); + } + } else { + if constexpr (std::is_same::value) { + std::vector bias_data_temp(bias_data.size()); + ConvertMLFloat16ToFloat(reinterpret_cast(bias_data.data()), bias_data_temp.data(), bias_data.size()); + cpu_fetches = RunSCELossInternalGradWithEP( + []() -> std::unique_ptr { return DefaultCpuExecutionProvider(); }, + reduction, ignore_index, error_tolerance, has_bias, + dY_dims, log_prob_dims, index_dims, weight_dims, dX_dims, + dY_data, log_prob_data, index_data, weight_data, bias_data_temp); + } else { + cpu_fetches = RunSCELossInternalGradWithEP( []() -> std::unique_ptr { return DefaultCpuExecutionProvider(); }, reduction, ignore_index, error_tolerance, has_bias, dY_dims, log_prob_dims, index_dims, weight_dims, dX_dims, dY_data, log_prob_data, index_data, weight_data, bias_data); + } + } // Run on CUDA and compare results with cpu results. std::vector target_fetches = @@ -938,22 +947,10 @@ static void TestSoftmaxCrossEntropyLossInternalGrad(const std::vector& // Compare ASSERT_EQ(cpu_fetches.size(), target_fetches.size()); for (size_t i = 0; i < cpu_fetches.size(); i++) { - if (std::is_same::value) { - auto y_data_size = cpu_fetches[i].Get().Shape().Size(); - std::vector cpu_temp_buffer; - cpu_temp_buffer.resize(y_data_size); - const float* y_buffer = cpu_fetches[i].Get().Data(); - std::copy(y_buffer, y_buffer + y_data_size, cpu_temp_buffer.begin()); - - std::vector ret_half(cpu_temp_buffer.size()); - ConvertFloatToMLFloat16(cpu_temp_buffer.data(), ret_half.data(), static_cast(cpu_temp_buffer.size())); - - OrtValue target; - test::CreateInputOrtValueOnCPU(cpu_fetches[i].Get().Shape().GetDims(), ret_half, &target); - auto ret = CompareOrtValue(target_fetches[i], target, error_tolerance /*per_sample_tolerance*/, - error_tolerance /*relative_per_sample_tolerance*/, false); + if (!std::is_same::value) { + auto ret = CompareOrtValueNumerals(target_fetches[i], cpu_fetches[i], error_tolerance /*per_sample_tolerance*/, + error_tolerance /*relative_per_sample_tolerance*/); EXPECT_EQ(ret.first, COMPARE_RESULT::SUCCESS) << ret.second; - } else { auto ret = CompareOrtValue(target_fetches[i], cpu_fetches[i], error_tolerance /*per_sample_tolerance*/, error_tolerance /*relative_per_sample_tolerance*/, false); @@ -1073,5 +1070,26 @@ TEST(CrossEntropyTest, SoftmaxCrossEntropyLossInternalGrad_TinySizeTensorFloatIn "none", 0, 5e-2, true); } +#ifndef _WIN32 +// Disable the large size tests for Windows because it is too slow, running on Linux would be enough. +// This test requires lots of memory, currently, it can run with 16GB V100 GPU. +TEST(CrossEntropyTest, DISABLED_SoftmaxCrossEntropyLossInternalGrad_LargeSizeTensorUInt64Index) { + // The element count is bigger than the upper limit of int32_t. + constexpr int64_t bsz = 419431; + constexpr int64_t vocab_size = 5120; + std::vector dY_dims{}; + std::vector log_prob_dims{bsz, vocab_size}; + std::vector index_dims{bsz}; + std::vector weight_dims{vocab_size}; + std::vector dX_dims{bsz, vocab_size}; + TestSoftmaxCrossEntropyLossInternalGrad(dY_dims, log_prob_dims, index_dims, weight_dims, + dX_dims, "mean", -1, 1e-3, false /*has_bias*/); + + // This test did not test against reduce-sum because the absolute value after computing is pretty big, sometimes + // around 65535, CPU baseline result is smaller than 65535, but CUDA result is a little bigger than it, generating + // inf, which is not a good test case. +} +#endif + } // namespace test } // namespace onnxruntime diff --git a/orttraining/orttraining/test/training_ops/cuda/layer_norm_test.cc b/orttraining/orttraining/test/training_ops/cuda/layer_norm_test.cc index df74a03025632..e86aa871b6c5f 100644 --- a/orttraining/orttraining/test/training_ops/cuda/layer_norm_test.cc +++ b/orttraining/orttraining/test/training_ops/cuda/layer_norm_test.cc @@ -253,27 +253,23 @@ TEST(CudaKernelTest, InvertibleLayerNormGrad_LargeSizeTensor) { TestInvertibleLayerNormGrad(X_dims, -1, 5e-3); } -TEST(CudaKernelTest, DISABLED_InvertibleLayerNormGrad_SmallSizeTensor_FP16) { // Failed to find kernel for Cast(19) (node InsertedCast_Y_grad). Op with name (InsertedCast_Y_grad) and type (Cast) kernel is not supported in CPUExecutionProvider. Encountered following errors: (Op with name (InsertedCast_Y_grad) and type (Cast) Version mismatch. node_version: 19 kernel start version: 6 kernel_end_version: 12 - // Op with name (InsertedCast_Y_grad) and type (Cast) Version mismatch. node_version: 19 kernel start version: 13 kernel_end_version: +TEST(CudaKernelTest, InvertibleLayerNormGrad_SmallSizeTensor_FP16) { const std::vector X_dims{4, 20, 128}; TestInvertibleLayerNormGrad(X_dims, -1, 2e-3, true); } -TEST(CudaKernelTest, DISABLED_InvertibleLayerNormGrad_SmallSizeTensor_IntermediateAxis_FP16) { // Failed to find kernel for Cast(19) (node InsertedCast_Y_grad). Op with name (InsertedCast_Y_grad) and type (Cast) kernel is not supported in CPUExecutionProvider. Encountered following errors: (Op with name (InsertedCast_Y_grad) and type (Cast) Version mismatch. node_version: 19 kernel start version: 6 kernel_end_version: 12 - // Op with name (InsertedCast_Y_grad) and type (Cast) Version mismatch. node_version: 19 kernel start version: 13 kernel_end_version: +TEST(CudaKernelTest, InvertibleLayerNormGrad_SmallSizeTensor_IntermediateAxis_FP16) { const std::vector X_dims{4, 20, 16, 8}; constexpr int64_t axis = -2; TestInvertibleLayerNormGrad(X_dims, axis, 2e-3, true); } -TEST(CudaKernelTest, DISABLED_InvertibleLayerNormGrad_MidSizeTensor_FP16) { // Failed to find kernel for Cast(19) (node InsertedCast_Y_grad). Op with name (InsertedCast_Y_grad) and type (Cast) kernel is not supported in CPUExecutionProvider. Encountered following errors: (Op with name (InsertedCast_Y_grad) and type (Cast) Version mismatch. node_version: 19 kernel start version: 6 kernel_end_version: 12 - // Op with name (InsertedCast_Y_grad) and type (Cast) Version mismatch. node_version: 19 kernel start version: 13 kernel_end_version +TEST(CudaKernelTest, InvertibleLayerNormGrad_MidSizeTensor_FP16) { const std::vector X_dims{8, 80, 768}; TestInvertibleLayerNormGrad(X_dims, -1, 2e-3, true); } -TEST(CudaKernelTest, DISABLED_InvertibleLayerNormGrad_LargeSizeTensor_FP16) { // Failed to find kernel for Cast(19) (node InsertedCast_Y_grad). Op with name (InsertedCast_Y_grad) and type (Cast) kernel is not supported in CPUExecutionProvider. Encountered following errors: (Op with name (InsertedCast_Y_grad) and type (Cast) Version mismatch. node_version: 19 kernel start version: 6 kernel_end_version: 12 - // Op with name (InsertedCast_Y_grad) and type (Cast) Version mismatch. node_version: 19 kernel start version: 13 kernel_end_version: +TEST(CudaKernelTest, InvertibleLayerNormGrad_LargeSizeTensor_FP16) { const std::vector X_dims{16, 512, 1024}; TestInvertibleLayerNormGrad(X_dims, -1, 2e-3, true); } diff --git a/orttraining/orttraining/test/training_ops/cuda/optimizer/adamw_test.cc b/orttraining/orttraining/test/training_ops/cuda/optimizer/adamw_test.cc index 2e7bef63d7ef6..9bbdd68c5ddfa 100644 --- a/orttraining/orttraining/test/training_ops/cuda/optimizer/adamw_test.cc +++ b/orttraining/orttraining/test/training_ops/cuda/optimizer/adamw_test.cc @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#include + #include "gtest/gtest.h" #include "nlohmann/json.hpp" diff --git a/orttraining/orttraining/test/training_ops/cuda/optimizer/common.cc b/orttraining/orttraining/test/training_ops/cuda/optimizer/common.cc index 7bbf413e4b9ff..a914cd1409d75 100644 --- a/orttraining/orttraining/test/training_ops/cuda/optimizer/common.cc +++ b/orttraining/orttraining/test/training_ops/cuda/optimizer/common.cc @@ -186,7 +186,7 @@ void AdamWTestLoop( // Add test outputs as baseline. if (update_signal == nullptr || *update_signal) { - test.AddOutput("updated_flag", {}, {1}); + test.AddOutput("updated_flag", {}, {1}); test.AddSeqOutput("updated_weights", data.UpdatedWeightSeq(), weight_tolerance.first, weight_tolerance.second); test.AddSeqOutput("updated_momentums_1", data.UpdatedMomentum_1_Seq(), momentum_1_tolerance.first, momentum_1_tolerance.second); @@ -195,7 +195,7 @@ void AdamWTestLoop( } else { // No update happens. - test.AddOutput("updated_flag", {}, {0}); + test.AddOutput("updated_flag", {}, {0}); test.AddSeqOutput("updated_weights", data.WeightSeq(), weight_tolerance.first, weight_tolerance.second); test.AddSeqOutput("updated_momentums_1", data.Momentum_1_Seq(), momentum_1_tolerance.first, momentum_1_tolerance.second); diff --git a/orttraining/orttraining/test/training_ops/cuda/optimizer/sgd_test.cc b/orttraining/orttraining/test/training_ops/cuda/optimizer/sgd_test.cc index 894e788760dcb..fd9fe4bafe994 100644 --- a/orttraining/orttraining/test/training_ops/cuda/optimizer/sgd_test.cc +++ b/orttraining/orttraining/test/training_ops/cuda/optimizer/sgd_test.cc @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#include + #include "gtest/gtest.h" #include "nlohmann/json.hpp" diff --git a/orttraining/orttraining/test/training_ops/cuda/pad_and_unflatten_test.cc b/orttraining/orttraining/test/training_ops/cuda/pad_and_unflatten_test.cc new file mode 100644 index 0000000000000..a800f17e59ae0 --- /dev/null +++ b/orttraining/orttraining/test/training_ops/cuda/pad_and_unflatten_test.cc @@ -0,0 +1,105 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "test/common/tensor_op_test_utils.h" +#include "test/providers/provider_test_utils.h" + +namespace onnxruntime { +namespace test { + +#if defined(USE_CUDA) || defined(USE_ROCM) + +TEST(PadAndUnflattenTest, FloatType1D) { + std::vector input = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.f}; + std::vector indices = {1, 3, 5, 7, 9, 11}; + std::vector unflatten_dims = {5, 3}; + + std::vector output = {0.0f, 1.0f, 0.0f, 2.0f, 0.0f, 3.0f, 0.0f, 4.0f, + 0.0f, 5.0f, 0.0f, 6.0f, 0.0f, 0.0f, 0.0f}; + + std::vector full_flatten_dims = {15}; + + OpTester test("PadAndUnflatten", 1, onnxruntime::kMSDomain); + test.AddInput("input", {6}, input); + test.AddInput("indices", {6}, indices); + test.AddInput("unflatten_dims", {2}, unflatten_dims); + test.AddOutput("output", {5, 3}, output); + test.AddOutput("full_flatten_dims", {1}, full_flatten_dims); + test.Run(); +} + +TEST(PadAndUnflattenTest, FloatType2D) { + std::vector input = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.f, 7.f, 8.f, 9.f}; + std::vector indices = {1, 3, 4}; + std::vector unflatten_dims = {2, 3}; + + std::vector output = {0.0f, 0.0f, 0.0f, 1.0f, 2.0f, 3.0f, 0.0f, 0.0f, 0.0f, + 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 0.0f, 0.0f, 0.0f}; + + std::vector full_flatten_dims = {6, 3}; + + OpTester test("PadAndUnflatten", 1, onnxruntime::kMSDomain); + test.AddInput("input", {3, 3}, input); + test.AddInput("indices", {3}, indices); + test.AddInput("unflatten_dims", {2}, unflatten_dims); + test.AddOutput("output", {2, 3, 3}, output); + test.AddOutput("full_flatten_dims", {2}, full_flatten_dims); + test.Run(); +} + +TEST(PadAndUnflattenTest, MLFloat16Type1D) { + std::vector input = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.f}; + std::vector indices = {1, 3, 5, 7, 9, 11}; + std::vector unflatten_dims = {5, 3}; + + std::vector output = {0.0f, 1.0f, 0.0f, 2.0f, 0.0f, 3.0f, 0.0f, 4.0f, + 0.0f, 5.0f, 0.0f, 6.0f, 0.0f, 0.0f, 0.0f}; + + std::vector full_flatten_dims = {15}; + + std::vector input_half; + input_half.resize(input.size()); + ConvertFloatToMLFloat16(input.data(), input_half.data(), int(input.size())); + std::vector output_half; + output_half.resize(output.size()); + ConvertFloatToMLFloat16(output.data(), output_half.data(), int(output.size())); + + OpTester test("PadAndUnflatten", 1, onnxruntime::kMSDomain); + test.AddInput("input", {6}, input_half); + test.AddInput("indices", {6}, indices); + test.AddInput("unflatten_dims", {2}, unflatten_dims); + test.AddOutput("output", {5, 3}, output_half); + test.AddOutput("full_flatten_dims", {1}, full_flatten_dims); + test.Run(); +} + +TEST(PadAndUnflattenTest, MLFloat16Type2D) { + std::vector input = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.f, 7.f, 8.f, 9.f}; + std::vector indices = {1, 3, 4}; + std::vector unflatten_dims = {2, 3}; + + std::vector output = {0.0f, 0.0f, 0.0f, 1.0f, 2.0f, 3.0f, 0.0f, 0.0f, 0.0f, + 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 0.0f, 0.0f, 0.0f}; + + std::vector full_flatten_dims = {6, 3}; + + std::vector input_half; + input_half.resize(input.size()); + ConvertFloatToMLFloat16(input.data(), input_half.data(), int(input.size())); + std::vector output_half; + output_half.resize(output.size()); + ConvertFloatToMLFloat16(output.data(), output_half.data(), int(output.size())); + + OpTester test("PadAndUnflatten", 1, onnxruntime::kMSDomain); + test.AddInput("input", {3, 3}, input_half); + test.AddInput("indices", {3}, indices); + test.AddInput("unflatten_dims", {2}, unflatten_dims); + test.AddOutput("output", {2, 3, 3}, output_half); + test.AddOutput("full_flatten_dims", {2}, full_flatten_dims); + test.Run(); +} + +#endif + +} // namespace test +} // namespace onnxruntime diff --git a/orttraining/orttraining/test/training_ops/cuda/scaled_sum_test.cc b/orttraining/orttraining/test/training_ops/cuda/scaled_sum_test.cc new file mode 100644 index 0000000000000..ae55aaa1afb6b --- /dev/null +++ b/orttraining/orttraining/test/training_ops/cuda/scaled_sum_test.cc @@ -0,0 +1,129 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#if defined(USE_CUDA) || defined(USE_ROCM) + +#include "test/common/tensor_op_test_utils.h" +#include "test/providers/provider_test_utils.h" + +namespace onnxruntime { +namespace test { + +static void PrepareInputAndOutputData(const std::vector>& input, + const std::vector& scales, + std::vector& output) { + output.resize(input[0].size()); + size_t scale_size = scales.size(); + for (size_t i = 0; i < input[0].size(); ++i) { + output[i] = input[0][i] * scales[0] + input[1][i] * scales[1] + (scale_size == 3 ? input[2][i] * scales[2] : 0.0f); + } +} + +template +static void RunScaledSumOpTester(const std::vector>& inputs, + const std::vector& scales, + const std::vector& output, + const std::vector& shape) { + OpTester test("ScaledSum", 1, onnxruntime::kMSDomain); + test.AddInput("input0", shape, inputs[0]); + test.AddInput("input1", shape, inputs[1]); + if (scales.size() == 3) { + test.AddInput("input2", shape, inputs[2]); + } + + test.AddOutput("output", shape, output); + test.AddAttribute("scale_0", scales[0]); + test.AddAttribute("scale_1", scales[1]); + if (scales.size() == 3) { + test.AddAttribute("scale_2", scales[2]); + } + + // Exclude CPU EP since it is not implemented yet. + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kCpuExecutionProvider}); +} + +static void RunScaledSumWithFloatAndMLFloat16(const std::vector>& inputs, + const std::vector& scales, + const std::vector& shape) { + std::vector output; + PrepareInputAndOutputData(inputs, scales, output); + RunScaledSumOpTester(inputs, scales, output, shape); + + std::vector> inputs_half; + inputs_half.resize(inputs.size()); + for (size_t i = 0; i < inputs.size(); ++i) { + inputs_half[i].resize(inputs[i].size()); + ConvertFloatToMLFloat16(inputs[i].data(), inputs_half[i].data(), static_cast(inputs[i].size())); + } + + std::vector output_half; + output_half.resize(output.size()); + ConvertFloatToMLFloat16(output.data(), output_half.data(), static_cast(output.size())); + + RunScaledSumOpTester(inputs_half, scales, output_half, shape); +} + +TEST(ScaledSumTest, SmallTensor1D) { + std::vector> inputs = {{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.f}, + {0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f}, + {0.01f, 0.02f, 0.03f, 0.04f, 0.05f, 0.06f}}; + + float scale_0 = 0.25f; + float scale_1 = 0.25f; + float scale_2 = 0.5f; + + std::vector shape{static_cast(inputs[0].size())}; + RunScaledSumWithFloatAndMLFloat16(inputs, {scale_0, scale_1, scale_2}, shape); + + RunScaledSumWithFloatAndMLFloat16(inputs, {scale_0, scale_1}, shape); +} // namespace test + +TEST(ScaledSumTest, SmallTensorVectorized1D) { + std::vector input = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.f, 7.0f, 8.0f, + 9.0f, 10.0f, 11.0f, 12.f, 13.0f, 14.0f, 15.0f, 16.0f, + 17.0f, 18.0f, 19.0f, 20.0f, 21.0f, 22.f, 23.0f, 24.0f, + 25.0f, 26.0f, 27.0f, 28.0f, 29.0f, 30.f, 31.0f, 32.0f}; + std::vector> inputs{input, input, input}; + float scale_0 = 0.25f; + float scale_1 = 0.25f; + float scale_2 = 0.5f; + + std::vector shape{static_cast(input.size())}; + RunScaledSumWithFloatAndMLFloat16(inputs, {scale_0, scale_1, scale_2}, shape); + + RunScaledSumWithFloatAndMLFloat16(inputs, {scale_0, scale_1}, shape); +} + +TEST(ScaledSumTest, SmallTensor2D) { + std::vector input = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.f, 7.f, 8.f, 9.f}; + std::vector> inputs{input, input, input}; + float scale_0 = 0.25f; + float scale_1 = 0.25f; + float scale_2 = 0.5f; + + std::vector shape{3, 3}; + RunScaledSumWithFloatAndMLFloat16(inputs, {scale_0, scale_1, scale_2}, shape); + + RunScaledSumWithFloatAndMLFloat16(inputs, {scale_0, scale_1}, shape); +} + +TEST(ScaledSumTest, SmallTensorVectorized2D) { + std::vector input = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.f, 7.0f, 8.0f, + 9.0f, 10.0f, 11.0f, 12.f, 13.0f, 14.0f, 15.0f, 16.0f, + 17.0f, 18.0f, 19.0f, 20.0f, 21.0f, 22.f, 23.0f, 24.0f, + 25.0f, 26.0f, 27.0f, 28.0f, 29.0f, 30.f, 31.0f, 32.0f}; + std::vector> inputs{input, input, input}; + float scale_0 = 0.25f; + float scale_1 = 0.25f; + float scale_2 = 0.5f; + + std::vector shape{4, 8}; + RunScaledSumWithFloatAndMLFloat16(inputs, {scale_0, scale_1, scale_2}, shape); + + RunScaledSumWithFloatAndMLFloat16(inputs, {scale_0, scale_1}, shape); +} + +} // namespace test +} // namespace onnxruntime + +#endif diff --git a/orttraining/orttraining/test/training_ops/cuda/softmax_dropout_test.cc b/orttraining/orttraining/test/training_ops/cuda/softmax_dropout_test.cc index 6e31d1c7d9a72..8c9ff298cad9c 100644 --- a/orttraining/orttraining/test/training_ops/cuda/softmax_dropout_test.cc +++ b/orttraining/orttraining/test/training_ops/cuda/softmax_dropout_test.cc @@ -45,11 +45,11 @@ void LaunchBiasSoftmaxDropoutTester(const std::vector& input_dims, cons auto output_verifier = [&](const std::vector& fetches, const std::string& provider_type) { ASSERT_EQ(fetches.size(), 3); - const auto& dropout_output_tensor = FetchTensor(fetches[0]); + const auto& dropout_output_tensor = fetches[0].Get(); auto dropout_output_span = dropout_output_tensor.DataAsSpan(); - const auto& mask_tensor = FetchTensor(fetches[1]); + const auto& mask_tensor = fetches[1].Get(); auto mask_span = mask_tensor.DataAsSpan(); - const auto& softmax_output_tensor = FetchTensor(fetches[2]); + const auto& softmax_output_tensor = fetches[2].Get(); auto softmax_output_span = softmax_output_tensor.DataAsSpan(); const auto num_dropped_values = std::count(mask_span.begin(), mask_span.end(), false); @@ -163,7 +163,7 @@ void LaunchSoftmaxDropoutGradTester(const std::vector& dims, const std: auto output_verifier = [&](const std::vector& fetches, const std::string& provider_type) { ASSERT_EQ(fetches.size(), 1); - const auto& dx_tensor = FetchTensor(fetches[0]); + const auto& dx_tensor = fetches[0].Get(); auto dx_span = dx_tensor.DataAsSpan(); ASSERT_EQ(dx_data.size(), dx_span.size()) << "provider: " << provider_type; for (size_t i = 0; i < dx_data.size(); ++i) { diff --git a/orttraining/orttraining/test/training_ops/cuda/softmax_test.cc b/orttraining/orttraining/test/training_ops/cuda/softmax_test.cc index 75bb47320876b..45edac3df2806 100644 --- a/orttraining/orttraining/test/training_ops/cuda/softmax_test.cc +++ b/orttraining/orttraining/test/training_ops/cuda/softmax_test.cc @@ -187,21 +187,21 @@ TEST(CudaKernelTest, SoftmaxGrad_SmallTensor_AllAxis) { } // large tensor to check cuda DNN softmax backward -TEST(CudaKernelTest, DISABLED_SoftmaxGrad_LargeTensor_LastAxis) { +TEST(CudaKernelTest, SoftmaxGrad_LargeTensor_LastAxis) { std::vector dY_dims{8, 16, 2048}; std::vector Y_dims{8, 16, 2048}; std::vector dX_dims{8, 16, 2048}; TestSoftmaxGrad(dY_dims, Y_dims, dX_dims, 2); } -TEST(CudaKernelTest, DISABLED_SoftmaxGrad_LargeTensor_LastAxis_Float16) { +TEST(CudaKernelTest, SoftmaxGrad_LargeTensor_LastAxis_Float16) { std::vector dY_dims{8, 16, 2048}; std::vector Y_dims{8, 16, 2048}; std::vector dX_dims{8, 16, 2048}; TestSoftmaxGrad(dY_dims, Y_dims, dX_dims, 2, false, 1e-3, 1e-3); } -TEST(CudaKernelTest, DISABLED_SoftmaxGrad_LargeTensor_LastAxis_Float16_NoPowerOfTwo) { +TEST(CudaKernelTest, SoftmaxGrad_LargeTensor_LastAxis_Float16_NoPowerOfTwo) { std::vector dY_dims{8, 16, 1500}; std::vector Y_dims{8, 16, 1500}; std::vector dX_dims{8, 16, 1500}; @@ -209,7 +209,7 @@ TEST(CudaKernelTest, DISABLED_SoftmaxGrad_LargeTensor_LastAxis_Float16_NoPowerOf } // large tensor to check cuda DNN softmax backward -TEST(CudaKernelTest, DISABLED_SoftmaxGrad_LargeTensor_AllAxis) { +TEST(CudaKernelTest, SoftmaxGrad_LargeTensor_AllAxis) { std::vector dY_dims{8, 16, 512}; std::vector Y_dims{8, 16, 512}; std::vector dX_dims{8, 16, 512}; @@ -217,7 +217,7 @@ TEST(CudaKernelTest, DISABLED_SoftmaxGrad_LargeTensor_AllAxis) { TestSoftmaxGrad(dY_dims, Y_dims, dX_dims, 1); } -TEST(CudaKernelTest, DISABLED_SoftmaxGrad_LargeTensor_AllAxis_Float16) { +TEST(CudaKernelTest, SoftmaxGrad_LargeTensor_AllAxis_Float16) { std::vector dY_dims{8, 16, 512}; std::vector Y_dims{8, 16, 512}; std::vector dX_dims{8, 16, 512}; @@ -225,7 +225,7 @@ TEST(CudaKernelTest, DISABLED_SoftmaxGrad_LargeTensor_AllAxis_Float16) { TestSoftmaxGrad(dY_dims, Y_dims, dX_dims, 1, false, 1e-3, 1e-3); } -TEST(CudaKernelTest, DISABLED_SoftmaxGrad_LargeTensor_AllAxis_Float16_NoPowerOfTwo) { +TEST(CudaKernelTest, SoftmaxGrad_LargeTensor_AllAxis_Float16_NoPowerOfTwo) { std::vector dY_dims{8, 16, 1500}; std::vector Y_dims{8, 16, 1500}; std::vector dX_dims{8, 16, 1500}; @@ -248,28 +248,28 @@ TEST(CudaKernelTest, LogSoftmaxGrad_SmallTensor_AllAxis) { TestSoftmaxGrad(dY_dims, Y_dims, dX_dims, 1, true); } -TEST(CudaKernelTest, DISABLED_LogSoftmaxGrad_LargeTensor_LastAxis) { +TEST(CudaKernelTest, LogSoftmaxGrad_LargeTensor_LastAxis) { std::vector dY_dims{8, 16, 2048}; std::vector Y_dims{8, 16, 2048}; std::vector dX_dims{8, 16, 2048}; TestSoftmaxGrad(dY_dims, Y_dims, dX_dims, 2, true); } -TEST(CudaKernelTest, DISABLED_LogSoftmaxGrad_LargeTensor_LastAxis_Float16) { +TEST(CudaKernelTest, LogSoftmaxGrad_LargeTensor_LastAxis_Float16) { std::vector dY_dims{8, 16, 2048}; std::vector Y_dims{8, 16, 2048}; std::vector dX_dims{8, 16, 2048}; TestSoftmaxGrad(dY_dims, Y_dims, dX_dims, 2, true, 1e-3, 1e-3); } -TEST(CudaKernelTest, DISABLED_LogSoftmaxGrad_LargeTensor_LastAxis_Float16_NoPowerOfTwo) { +TEST(CudaKernelTest, LogSoftmaxGrad_LargeTensor_LastAxis_Float16_NoPowerOfTwo) { std::vector dY_dims{8, 16, 1500}; std::vector Y_dims{8, 16, 1500}; std::vector dX_dims{8, 16, 1500}; TestSoftmaxGrad(dY_dims, Y_dims, dX_dims, 2, true, 1e-3, 1e-3); } -TEST(CudaKernelTest, DISABLED_LogSoftmaxGrad_LargeTensor_AllAxis) { +TEST(CudaKernelTest, LogSoftmaxGrad_LargeTensor_AllAxis) { std::vector dY_dims{8, 16, 512}; std::vector Y_dims{8, 16, 512}; std::vector dX_dims{8, 16, 512}; @@ -277,7 +277,7 @@ TEST(CudaKernelTest, DISABLED_LogSoftmaxGrad_LargeTensor_AllAxis) { TestSoftmaxGrad(dY_dims, Y_dims, dX_dims, 1, true, 1e-3, 1e-3); } -TEST(CudaKernelTest, DISABLED_LogSoftmaxGrad_LargeTensor_AllAxis_Float16) { +TEST(CudaKernelTest, LogSoftmaxGrad_LargeTensor_AllAxis_Float16) { std::vector dY_dims{8, 16, 512}; std::vector Y_dims{8, 16, 512}; std::vector dX_dims{8, 16, 512}; @@ -285,7 +285,7 @@ TEST(CudaKernelTest, DISABLED_LogSoftmaxGrad_LargeTensor_AllAxis_Float16) { TestSoftmaxGrad(dY_dims, Y_dims, dX_dims, 1, true, 1e-3, 1e-3); } -TEST(CudaKernelTest, DISABLED_LogSoftmaxGrad_LargeTensor_AllAxis_Float16_NoPowerOfTwo) { +TEST(CudaKernelTest, LogSoftmaxGrad_LargeTensor_AllAxis_Float16_NoPowerOfTwo) { std::vector dY_dims{8, 16, 1500}; std::vector Y_dims{8, 16, 1500}; std::vector dX_dims{8, 16, 1500}; diff --git a/orttraining/orttraining/test/training_ops/function_op_test_utils.cc b/orttraining/orttraining/test/training_ops/function_op_test_utils.cc index f4c6f46f2f483..9504ba2c1e69a 100644 --- a/orttraining/orttraining/test/training_ops/function_op_test_utils.cc +++ b/orttraining/orttraining/test/training_ops/function_op_test_utils.cc @@ -2,30 +2,31 @@ // Licensed under the MIT License. #include "gtest/gtest.h" -#include "test/providers/provider_test_utils.h" #include "core/session/inference_session.h" #include "core/graph/graph.h" -#include "orttraining/test/training_ops/function_op_test_utils.h" + #include "orttraining/core/graph/graph_augmenter.h" +#include "orttraining/test/training_ops/function_op_test_utils.h" + +#include "test/providers/provider_test_utils.h" +#include "test/util/include/asserts.h" namespace onnxruntime { namespace test { -TwoDArray OpFunctionTester::RunFunctionBodyGraphOnCPU() { -#ifndef NDEBUG - run_called_ = true; -#endif +void OpFunctionTester::RunFunctionBodyGraphOnCPU(TwoDArray& results) { + SetTestFunctionCalled(); - auto p_model = BuildGraph(); - auto& graph = p_model->MainGraph(); + auto& model = BuildModel(); + auto& graph = model.MainGraph(); + const auto& op = Op(); - Status status = graph.Resolve(); - ORT_ENFORCE(status.IsOK()); + ASSERT_STATUS_OK(graph.Resolve()); auto& node = *graph.Nodes().begin(); - ORT_ENFORCE(node.OpType() == op_); - // Inline function will call Resolve itself - ORT_THROW_IF_ERROR(graph.InlineFunction(node)); + ASSERT_EQ(node.OpType(), op); + ASSERT_STATUS_OK(graph.InlineFunction(node)); + ASSERT_STATUS_OK(graph.Resolve()); // Hookup the inputs and outputs std::unordered_map feeds; @@ -34,23 +35,19 @@ TwoDArray OpFunctionTester::RunFunctionBodyGraphOnCPU() { // Run the model SessionOptions so; - so.session_logid = op_; - so.session_log_verbosity_level = 1; + so.session_logid = op; InferenceSession cpu_session_object{so, GetEnvironment()}; // Run the inlined graph with cpu std::string s1; - p_model->ToProto().SerializeToString(&s1); + model.ToProto().SerializeToString(&s1); std::istringstream str(s1); - status = cpu_session_object.Load(str); - EXPECT_TRUE(status.IsOK()) << status.ErrorMessage(); - - status = cpu_session_object.Initialize(); - EXPECT_TRUE(status.IsOK()) << status.ErrorMessage(); + ASSERT_STATUS_OK(cpu_session_object.Load(str)); + ASSERT_STATUS_OK(cpu_session_object.Initialize()); RunOptions run_options; - run_options.run_tag = op_; + run_options.run_tag = op; run_options.run_log_verbosity_level = 1; #ifdef ENABLE_TRAINING @@ -59,23 +56,20 @@ TwoDArray OpFunctionTester::RunFunctionBodyGraphOnCPU() { #endif std::vector cpu_fetches; - status = cpu_session_object.Run(run_options, feeds, output_names, &cpu_fetches); - EXPECT_TRUE(status.IsOK()) << status.ErrorMessage(); + ASSERT_STATUS_OK(cpu_session_object.Run(run_options, feeds, output_names, &cpu_fetches)); auto fetch_index = 0; - auto run_results = TwoDArray(cpu_fetches.size()); + results = TwoDArray(cpu_fetches.size()); for (auto& fetch : cpu_fetches) { const Tensor& t = fetch.Get(); auto float_val = t.Data(); for (auto i = 0; i < t.Shape().Size(); ++i) { - run_results[fetch_index].push_back(float_val[i]); + results[fetch_index].push_back(float_val[i]); } fetch_index++; } - - return run_results; } OpFunctionTester::~OpFunctionTester(){}; @@ -122,13 +116,14 @@ void CompareResults(const onnxruntime::training::OpDef& op_def, CreateEmpty2DArray(output_dims), output_dims, attributes, opset_version); - auto run_results = inline_tester->RunFunctionBodyGraphOnCPU(); + TwoDArray results; + ASSERT_NO_FATAL_FAILURE(inline_tester->RunFunctionBodyGraphOnCPU(results)); // Use run_results got from inline testing as expected data, // test against all registered kernels. auto test = CreateOpTester(op_def, input_data, input_dims, - run_results, output_dims, + results, output_dims, attributes, opset_version); test->Run(OpTester::ExpectResult::kExpectSuccess, "", {}); diff --git a/orttraining/orttraining/test/training_ops/function_op_test_utils.h b/orttraining/orttraining/test/training_ops/function_op_test_utils.h index 564f908fe7933..8fdaec8f6d4ae 100644 --- a/orttraining/orttraining/test/training_ops/function_op_test_utils.h +++ b/orttraining/orttraining/test/training_ops/function_op_test_utils.h @@ -8,13 +8,16 @@ namespace onnxruntime { namespace test { using ONNX_NAMESPACE::AttributeProto; -typedef std::vector> TwoDArray; +using TwoDArray = std::vector>; class OpFunctionTester : public OpTester { public: OpFunctionTester(const char* op, int opset_version = 9, const char* domain = onnxruntime::kOnnxDomain) : OpTester(op, opset_version, domain) {} - TwoDArray RunFunctionBodyGraphOnCPU(); + + // NOTE: wrap this call with ASSERT_NO_FATAL_FAILURE if your test has additional code following it. + // See CompareResults for an example of doing that. + void RunFunctionBodyGraphOnCPU(TwoDArray& results); virtual ~OpFunctionTester(); }; diff --git a/orttraining/orttraining/training_api/checkpoint.cc b/orttraining/orttraining/training_api/checkpoint.cc index 73b24ae49fffd..dbcef78c3965c 100644 --- a/orttraining/orttraining/training_api/checkpoint.cc +++ b/orttraining/orttraining/training_api/checkpoint.cc @@ -1,581 +1,762 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "core/common/inlined_containers.h" -#include "core/common/logging/logging.h" -#include "core/common/logging/sinks/clog_sink.h" -#include "core/common/path.h" -#include "core/framework/framework_common.h" -#include "core/graph/graph_viewer.h" -#include "core/graph/model.h" -#include "core/platform/env.h" -#include "core/platform/path_lib.h" -#include "core/util/protobuf_parsing_utils.h" - -#include "orttraining/core/framework/checkpoint_common.h" -#include "orttraining/core/framework/protobuf_message_sequence.h" #include "orttraining/training_api/checkpoint.h" -#include "orttraining/training_api/utils.h" -namespace onnxruntime { -namespace training { -namespace api { +#include "core/flatbuffers/checkpoint_version.h" +#include "core/flatbuffers/schema/ort_training_checkpoint.fbs.h" +#include "core/framework/framework_common.h" +#include "core/graph/graph_flatbuffers_utils.h" + +namespace onnxruntime::training::api { namespace { -const PathString k_tensor_proto_file_name = ORT_TSTR("tensors.pbseq"); -const PathString k_tensor_proto_properties_file_name = ORT_TSTR("properties.pbseq"); -const PathString k_trainable_param_root_prefix = ORT_TSTR("paramtrain"); -const PathString k_non_trainable_param_root_prefix = ORT_TSTR("paramfrozen"); -const PathString k_optimizer_root_prefix = ORT_TSTR("optim"); -const PathString k_property_root_prefix = ORT_TSTR("custom"); -const PathString k_name_separator = ORT_TSTR("_"); +/** + * @brief Sort keys of a hash map. + * @param hash_map Hash map to sort. + * @param keys Sorted keys. + */ +template +InlinedVector SortedKeys(const T& hash_map) { + InlinedVector keys; + keys.reserve(hash_map.size()); + for ([[maybe_unused]] const auto& [key, value] : hash_map) { + keys.push_back(key); + } + std::sort(keys.begin(), keys.end()); -const char builtin_lr_property_name[] = "builtin.initial_learning_rate"; -const char builtin_step_property_name[] = "builtin.step"; + return keys; +} /** - * @brief Create TensorProtos From OrtValue objects + * @brief Create flatbuffer tensor from OrtValue object * - * @param name_to_ort_value name to OrtValue mapping. - * @param data_transfer_manager data transfer manager to copy the tensor in OrtValue. - * @param saved_tensor_protos saved results. - * @return Status + * @param tensor_name Name of the tensor + * @param ort_value OrtValue object to save to the flatbuffer tensor. + * @param copy_tensor Function to copy the tensor to a cpu buffer. + * @param builder Builder to create flatbuffer tensors. + * @param flatbuffer_tensor Flatbuffer tensor to be populated. + * @return Status of the operation. */ -Status CreateTensorProtosFromOrtValues( - const NameMLValMap& name_to_ort_value, - const DataTransferManager& data_transfer_manager, - std::vector& saved_tensor_protos) { - // Order the tensors by name. - InlinedVector ordered_tensor_names{}; - ordered_tensor_names.reserve(name_to_ort_value.size()); - std::transform(name_to_ort_value.begin(), name_to_ort_value.end(), std::back_inserter(ordered_tensor_names), - [](const NameMLValMap::value_type& v) { return v.first; }); - std::sort(ordered_tensor_names.begin(), ordered_tensor_names.end()); - - saved_tensor_protos.reserve(ordered_tensor_names.size()); - - uint64_t total_bytes = 0; - constexpr uint64_t PROTOBUF_UPPER_LIMIT = 2 * 1000 * 1000 * 1000; - for (const auto& tensor_name : ordered_tensor_names) { - const OrtValue& ort_value = name_to_ort_value.at(tensor_name); - ORT_RETURN_IF_NOT(ort_value.IsTensor(), "ort_value.IsTensor() was false"); - const Tensor& src_tensor = ort_value.Get(); - - // Currently large model size not considered, so exception thrown here - // when protobuf upper limit hit. - total_bytes += static_cast(src_tensor.SizeInBytes()); - if (total_bytes >= PROTOBUF_UPPER_LIMIT) { - ORT_THROW("checkpoint file size hit upper limit."); - } - - saved_tensor_protos.emplace_back(utils::CopyTensorToTensorProto( - src_tensor, tensor_name, data_transfer_manager)); +Status FlatbufferTensorFromOrtValue( + const std::string& tensor_name, const OrtValue& ort_value, + const std::function copy_tensor, + flatbuffers::FlatBufferBuilder& builder, + flatbuffers::Offset& fbs_tensor) { + // Check if the OrtValue is a tensor. + ORT_RETURN_IF_NOT(ort_value.IsTensor(), "Only tensor OrtValues can be saved to a checkpoint."); + const onnxruntime::Tensor& src_tensor = ort_value.Get(); + + // Check if the tensor is on CPU. If not, we need to copy the tensor to CPU before saving it. + if (const auto& tensor_location = src_tensor.Location(); + tensor_location.device.Type() != OrtDevice::CPU) { + InlinedVector tensor_data_buffer{}; + tensor_data_buffer.resize(src_tensor.SizeInBytes()); + const OrtMemoryInfo cpu_alloc_info{onnxruntime::CPU, OrtDeviceAllocator}; + onnxruntime::Tensor dst_tensor{src_tensor.DataType(), src_tensor.Shape(), tensor_data_buffer.data(), cpu_alloc_info}; + ORT_RETURN_IF_ERROR(copy_tensor(src_tensor, dst_tensor)); + ORT_RETURN_IF_ERROR(fbs::utils::SaveOrtTensorOrtFormat(tensor_name, dst_tensor, builder, fbs_tensor)); + } else { + ORT_RETURN_IF_ERROR(fbs::utils::SaveOrtTensorOrtFormat(tensor_name, src_tensor, builder, fbs_tensor)); } return Status::OK(); } -PathString GetTensorProtoFilePath(const PathString& checkpoint_directory, const PathString& filename_prefix) { - std::basic_ostringstream oss; - oss << filename_prefix << k_name_separator << k_tensor_proto_file_name; - return ConcatPathComponent(checkpoint_directory, oss.str()); -} +/** + * @brief Create OrtValue object from flatbuffer tensor + * + * @param fbs_tensor Flatbuffer tensor. + * @param tensor_name Name of the tensor. + * @param ort_value OrtValue object to be populated. + * @return Status of the operation. + */ +Status OrtValueFromFlatbufferTensor(const fbs::Tensor& fbs_tensor, + std::string& tensor_name, OrtValue& ort_value) { + // The assumption is that the flatbuffer buffer will be destructed once the checkpoint has been loaded. + // And so, we must allocate a buffer where the tensor data can be copied using the cpu allocator. + // This buffer is owned by the OrtValue. + static CPUExecutionProviderInfo info; + static CPUExecutionProvider cpu_provider(info); + AllocatorPtr cpu_allocator = cpu_provider.CreatePreferredAllocators()[0]; -PathString GetTensorProtoPropertiesFilePath( - const PathString& checkpoint_directory, const PathString& filename_prefix) { - std::basic_ostringstream oss; - oss << filename_prefix << k_name_separator << k_tensor_proto_properties_file_name; - return ConcatPathComponent(checkpoint_directory, oss.str()); -} + std::unique_ptr ort_tensor = std::make_unique(); + ORT_RETURN_IF_ERROR(fbs::utils::LoadOrtTensorOrtFormat(fbs_tensor, cpu_allocator, tensor_name, *ort_tensor)); -PathString StringConcat( - const PathString& s_a, const PathString& s_b, - const PathString& del = k_name_separator) { - std::basic_ostringstream oss; - oss << s_a << del << s_b; - return oss.str(); + ort_value.Init(ort_tensor.release(), DataTypeImpl::GetType(), + DataTypeImpl::GetType()->GetDeleteFunc()); + + return Status::OK(); } -void StringSplit(const PathString& s, std::vector& results, - const PathString& del = k_name_separator) { - ORT_ENFORCE(!s.empty(), "String to split is empty"); - size_t start = 0; - size_t end = s.find(del); - while (end != std::string::npos) { - results.push_back(s.substr(start, end - start)); - start = end + del.size(); - end = s.find(del, start); +/** + * @brief Create flatbuffer tensors from OrtValue objects + * + * @param name_to_ort_value Name to OrtValue map. + * @param data_transfer_manager Data transfer manager to copy the OrtValue tensor to a cpu buffer. + * @param builder Builder to create flatbuffer tensors. + * @param flatbuffer_tensors Flatbuffer tensors to be populated. + * @return Status of the operation. + */ +Status FlatbufferTensorsFromOrtValues( + const InlinedHashMap& name_to_ort_value, + const DataTransferManager* data_transfer_manager, + flatbuffers::FlatBufferBuilder& builder, + std::vector>& flatbuffer_tensors) { + for (const auto& name : SortedKeys(name_to_ort_value)) { + const OrtValue& ort_value = name_to_ort_value.at(name); + flatbuffers::Offset fbs_tensor; + ORT_RETURN_IF_ERROR(FlatbufferTensorFromOrtValue( + name, ort_value, [&data_transfer_manager](const auto& src_tensor, auto& dst_tensor) { + ORT_RETURN_IF_NOT(data_transfer_manager, + "Cannot save OrtValue to a checkpoint. Expected: A valid data transfer manager. ", + "Actual: nullptr."); + return data_transfer_manager->CopyTensor(src_tensor, dst_tensor); + }, + builder, fbs_tensor)); + flatbuffer_tensors.push_back(fbs_tensor); } - results.push_back(s.substr(start, end - start)); -} -bool StringStartsWith(PathString const& s, PathString const& p) { - return s.rfind(p, 0) == 0; + return Status::OK(); } -bool StringEndsWith(PathString const& s, PathString const& p) { - if (p.size() > s.size()) return false; - return std::equal(p.rbegin(), p.rend(), s.rbegin()); -} +/** + * @brief Create OrtValue objects from flatbuffer tensors. + * + * @param flatbuffer_tensors Flatbuffer tensors. + * @param name_to_ort_value Name to OrtValue map to be populated. + * @return Status of the operation. + */ +Status OrtValuesFromFlatbufferTensors( + const flatbuffers::Vector>& flatbuffer_tensors, + InlinedHashMap& name_to_ort_value) { + for (const auto* fbs_tensor : flatbuffer_tensors) { + ORT_RETURN_IF_NOT(fbs_tensor, "Encountered a nullptr flatbuffer tensor. Checkpoint file is invalid."); + + std::string tensor_name; + OrtValue ort_value; + ORT_RETURN_IF_ERROR(OrtValueFromFlatbufferTensor(*fbs_tensor, tensor_name, ort_value)); + name_to_ort_value.emplace(std::move(tensor_name), std::move(ort_value)); + } -void WriteTensorProtoToFile(const PathString& file_path, - const std::vector& tensor_protos, - std::string caller_context) { - auto file_write_status = WithOpenFile( - file_path, false, - [&tensor_protos](int fd) { - google::protobuf::io::FileOutputStream output{fd}; - ORT_RETURN_IF_ERROR(WriteProtoMessageSequence(tensor_protos, output)); - return Status::OK(); - }); - - ORT_ENFORCE(file_write_status.IsOK(), caller_context, " write file failed: ", ToUTF8String(file_path)); + return Status::OK(); } -void LoadTensorProtoFromFile(const PathString& file_path, - std::vector& tensor_protos, - std::string caller_context) { - auto file_read_status = WithOpenFile( - file_path, true, - [&tensor_protos](int fd) { - google::protobuf::io::FileInputStream input{fd}; - ORT_RETURN_IF_ERROR(ReadProtoMessageSequence(tensor_protos, input)); - return Status::OK(); - }); - - ORT_ENFORCE(file_read_status.IsOK(), caller_context, " load file failed: ", ToUTF8String(file_path)); -} +namespace save { -template -void FilterFilesFromDirectory(const PathString& folder_path, Func func) { - LoopDir(folder_path, [&func](const PathChar* filename, OrtFileType file_type) -> bool { - if (filename[0] == '.' || file_type == OrtFileType::TYPE_DIR) { - return true; - } +/** + * @brief Save from a checkpoint flatbuffer to file. + * @param checkpoint_path Path to save the checkpoint file. + * @param builder Flatbuffer builder containing the checkpoint buffer. + * @return Status of the operation. + * + */ +Status ToFile(const PathString& checkpoint_path, flatbuffers::FlatBufferBuilder& builder) { + std::ofstream file(checkpoint_path, std::ios::binary); + const uint8_t* buf = builder.GetBufferPointer(); + int size = builder.GetSize(); + file.write(reinterpret_cast(buf), size); + ORT_RETURN_IF_NOT(file, "Failed to save checkpoint to file: ", ToUTF8String(checkpoint_path)); - return func(filename); - }); + return Status::OK(); } -Status OrtSaveInternal( - const std::vector& trainable_tensor_protos, - const std::vector& non_trainable_tensor_protos, +#if !defined(ORT_MINIMAL_BUILD) +/** + * @brief Save from ONNX initializers to a checkpoint file. + * + * @param trainable_tensor_protos trainable parameters in TensorProto format. + * @param non_trainable_tensor_protos non-trainable parameters in TensorProto format. + * @param checkpoint_path file where checkpoint is saved. + * @return Status + */ +Status FromTensorProtos( + gsl::span trainable_tensor_protos, + gsl::span non_trainable_tensor_protos, const PathString& checkpoint_path) { - // Make sure name unique across trainable and non-trainable lists. - std::set trainable_unique_names; - std::set non_trainable_unique_names; - InlinedVector inter_sec; - auto check_unique = [](const std::vector& tensor_protos, - std::set& unique_names) { - for (auto& tensor_proto : tensor_protos) { - ORT_ENFORCE(unique_names.find(tensor_proto.name()) == unique_names.end(), - "Duplicated tensor proto named ", tensor_proto.name()); - unique_names.emplace(tensor_proto.name()); + const auto check_unique = [](gsl::span tensor_protos, + InlinedHashSet& unique_names) { + for (const auto& tensor_proto : tensor_protos) { + ORT_RETURN_IF_NOT(unique_names.find(tensor_proto.name()) == unique_names.end(), + "Duplicated tensor proto named ", tensor_proto.name()); + unique_names.insert(tensor_proto.name()); } + + return Status::OK(); }; - check_unique(trainable_tensor_protos, trainable_unique_names); - check_unique(non_trainable_tensor_protos, non_trainable_unique_names); - std::set_intersection(trainable_unique_names.begin(), trainable_unique_names.end(), - non_trainable_unique_names.begin(), non_trainable_unique_names.end(), - std::back_inserter(inter_sec)); - ORT_RETURN_IF_NOT(inter_sec.empty(), "Tensor name exists in both trainable param list and non-trainable param list."); - - // Keep following saving logic aligned with OrtSaveModuleStatesInternal. - LOGS_DEFAULT(INFO) - << "Saving model checkpoint files to " << ToUTF8String(checkpoint_path); - LOGS_DEFAULT_IF(Env::Default().FolderExists(checkpoint_path), WARNING) - << "Checkpoint directory exists - data may be overwritten."; - ORT_RETURN_IF_ERROR(Env::Default().CreateFolder(checkpoint_path)); - - // Save TensorProto to file. - if (trainable_tensor_protos.size() > 0) { - WriteTensorProtoToFile( - GetTensorProtoFilePath(checkpoint_path, k_trainable_param_root_prefix), - trainable_tensor_protos, "[trainable_param]"); - } - if (non_trainable_tensor_protos.size() > 0) { - WriteTensorProtoToFile( - GetTensorProtoFilePath(checkpoint_path, k_non_trainable_param_root_prefix), - non_trainable_tensor_protos, "[non_trainable_param]"); + // Make sure name unique across trainable and non-trainable lists. + InlinedHashSet unique_names; + unique_names.reserve(trainable_tensor_protos.size() + non_trainable_tensor_protos.size()); + ORT_RETURN_IF_ERROR(check_unique(trainable_tensor_protos, unique_names)); + ORT_RETURN_IF_ERROR(check_unique(non_trainable_tensor_protos, unique_names)); + + constexpr size_t m_bytes = 1024 * 1024; + size_t fbs_buffer_size = 0U; + for (const auto& tensor_proto : trainable_tensor_protos) { + fbs_buffer_size += tensor_proto.ByteSizeLong(); + } + for (const auto& tensor_proto : non_trainable_tensor_protos) { + fbs_buffer_size += tensor_proto.ByteSizeLong(); } - return Status::OK(); + // Align buffer size to 1MB. + fbs_buffer_size = std::max(fbs_buffer_size, m_bytes); + fbs_buffer_size = ((fbs_buffer_size + m_bytes - 1) / m_bytes) * m_bytes; + flatbuffers::FlatBufferBuilder builder(fbs_buffer_size); + + const auto tensor_protos_to_fbs_tensors = [&builder](const auto& tensor_protos, auto& fbs_tensors) { + fbs_tensors.reserve(tensor_protos.size()); + for (const auto& tensor_proto : tensor_protos) { + flatbuffers::Offset fbs_tensor; + ORT_RETURN_IF_ERROR( + fbs::utils::SaveInitializerOrtFormat(builder, tensor_proto, Path(), fbs_tensor)); + fbs_tensors.push_back(fbs_tensor); + } + + return Status::OK(); + }; + + std::vector> trainable_tensors; + ORT_RETURN_IF_ERROR(tensor_protos_to_fbs_tensors(trainable_tensor_protos, trainable_tensors)); + + std::vector> non_trainable_tensors; + ORT_RETURN_IF_ERROR(tensor_protos_to_fbs_tensors(non_trainable_tensor_protos, non_trainable_tensors)); + + const auto fbs_trainable_tensors = builder.CreateVector(trainable_tensors); + const auto fbs_non_trainable_tensors = builder.CreateVector(non_trainable_tensors); + + fbs::ModuleStateBuilder module_state_builder(builder); + module_state_builder.add_requires_grad_params(fbs_trainable_tensors); + module_state_builder.add_frozen_params(fbs_non_trainable_tensors); + flatbuffers::Offset fbs_module_state = module_state_builder.Finish(); + + fbs::CheckpointBuilder checkpoint_builder(builder); + checkpoint_builder.add_version(kCheckpointVersion); + checkpoint_builder.add_module_state(fbs_module_state); + const auto checkpoint = checkpoint_builder.Finish(); + builder.Finish(checkpoint, fbs::CheckpointIdentifier()); + + return save::ToFile(checkpoint_path, builder); } +#endif -Status OrtSaveModuleStatesInternal(ModuleCheckpointState& module_state, - const PathString& parameter_folder_path) { - // Write weight tensors files. - const auto& param_states = module_state.named_parameters; - if (!param_states.empty()) { - ORT_ENFORCE(module_state.train_session_data_transfer_mgr, - "module checkpoint state has null train_session_data_transfer_mgr."); - - InlinedHashMap> - parameter_ort_values; - for (auto it = param_states.begin(); it != param_states.end(); ++it) { - if (it->second->RequiresGrad()) { - parameter_ort_values[k_trainable_param_root_prefix].insert({it->first, it->second->Data()}); - } else { - parameter_ort_values[k_non_trainable_param_root_prefix].insert({it->first, it->second->Data()}); - } - } +/** + * @brief Save from the module state to a flatbuffer checkpoint module state. + * + * @param module_state module state containing the model's trainable and non-trainable parameters. + * @param builder Flatbuffer builder. + * @param fbs_module_state Flatbuffer module state to be populated. + * @return Status of the operation. + */ +Status FromModuleState(const ModuleCheckpointState& module_state, + flatbuffers::FlatBufferBuilder& builder, + flatbuffers::Offset& fbs_module_state) { + if (module_state.named_parameters.empty()) { + return Status::OK(); + } - // Parameters saving. - for (auto& pair : parameter_ort_values) { - std::vector param_tensor_protos; - ORT_RETURN_IF_ERROR(CreateTensorProtosFromOrtValues( - pair.second, - *module_state.train_session_data_transfer_mgr, - param_tensor_protos)); - - // Save TensorProto to file. - WriteTensorProtoToFile( - GetTensorProtoFilePath(parameter_folder_path, pair.first), - param_tensor_protos, "[param]"); + size_t num_requires_grad_params = std::count_if( + module_state.named_parameters.begin(), module_state.named_parameters.end(), + [](const auto& name_param_pair) { return name_param_pair.second->RequiresGrad(); }); + size_t num_frozen_params = module_state.named_parameters.size() - num_requires_grad_params; + + InlinedHashMap requires_grad_params; + requires_grad_params.reserve(num_requires_grad_params); + InlinedHashMap frozen_params; + frozen_params.reserve(num_frozen_params); + for (const auto& [name, value] : module_state.named_parameters) { + if (value->RequiresGrad()) { + requires_grad_params.insert({name, value->Data()}); + } else { + frozen_params.insert({name, value->Data()}); } } + std::vector> trainable_tensors; + trainable_tensors.reserve(requires_grad_params.size()); + ORT_RETURN_IF_ERROR(FlatbufferTensorsFromOrtValues( + requires_grad_params, + module_state.train_session_data_transfer_mgr, + builder, trainable_tensors)); + + std::vector> non_trainable_tensors; + non_trainable_tensors.reserve(frozen_params.size()); + ORT_RETURN_IF_ERROR(FlatbufferTensorsFromOrtValues( + frozen_params, + module_state.train_session_data_transfer_mgr, + builder, non_trainable_tensors)); + + const auto fbs_trainable_tensors = builder.CreateVector(trainable_tensors); + const auto fbs_non_trainable_tensors = builder.CreateVector(non_trainable_tensors); + + fbs::ModuleStateBuilder module_state_builder(builder); + module_state_builder.add_requires_grad_params(fbs_trainable_tensors); + module_state_builder.add_frozen_params(fbs_non_trainable_tensors); + fbs_module_state = module_state_builder.Finish(); + return Status::OK(); } -Status OrtSaveOptimizerStatesInternal(OptimizerCheckpointState& optimizer_state, - const PathString& checkpoint_path) { +/** + * @brief Save from the optimizer state to a flatbuffer checkpoint optimizer state. + * + * @param optimizer_state optimizer state containing the optimizer's state (for example learning rate, step, first + * and second order momentums ...). + * @param builder Flatbuffer builder. + * @param fbs_optimizer_groups Flatbuffer optimizer groups to be populated. + * @return Status of the operation. + */ +Status FromOptimizerState(const OptimizerCheckpointState& optimizer_state, + flatbuffers::FlatBufferBuilder& builder, + std::vector>& fbs_optimizer_groups) { if (optimizer_state.group_named_optimizer_states.empty()) { return Status::OK(); } - ORT_ENFORCE(optimizer_state.optimizer_session_data_transfer_mgr, - "optimizer checkpoint state has null optimizer_session_data_transfer_mgr."); - - // Write optimizer state tensors files. - for (auto& group_named_optimizer_state : optimizer_state.group_named_optimizer_states) { - const PathString group_name = ToPathString(group_named_optimizer_state.first); - const std::shared_ptr& group_optimizer_state_ptr = group_named_optimizer_state.second; - const PathString& cur_group_filename_prefix = - StringConcat(k_optimizer_root_prefix, group_name); - - // Re-organize optimizer_state_ort_values mapping - // Firstly indexed by momentum names; Secondly indexed by parameter names. - InlinedHashMap> optimizer_state_ort_values; - for (const auto& [param_name, param_optimizer_state] : group_optimizer_state_ptr->param_named_optimizer_states) { - for (const auto& [momentum_name, m_state_val] : param_optimizer_state.momentum_named_states) { - if (optimizer_state_ort_values.find(momentum_name) == optimizer_state_ort_values.end()) { - std::unordered_map param_name_to_ortvalue{{param_name, m_state_val}}; - optimizer_state_ort_values.insert({momentum_name, param_name_to_ortvalue}); - } else { - optimizer_state_ort_values[momentum_name].insert({param_name, m_state_val}); - } - } + fbs_optimizer_groups.reserve(optimizer_state.group_named_optimizer_states.size()); + for (const auto& group_name : SortedKeys(optimizer_state.group_named_optimizer_states)) { + const std::shared_ptr& group_optimizer_state_ptr = + optimizer_state.group_named_optimizer_states.at(group_name); + + std::vector> optimizer_states; + optimizer_states.reserve(group_optimizer_state_ptr->param_named_optimizer_states.size()); + + for (const auto& param_name : SortedKeys(group_optimizer_state_ptr->param_named_optimizer_states)) { + const auto& param_optimizer_state = group_optimizer_state_ptr->param_named_optimizer_states.at(param_name); + std::vector> momentums; + momentums.reserve(param_optimizer_state.size()); + ORT_RETURN_IF_ERROR(FlatbufferTensorsFromOrtValues( + param_optimizer_state, + optimizer_state.optimizer_session_data_transfer_mgr, + builder, momentums)); + + const auto fbs_param_name = builder.CreateString(param_name); + const auto fbs_momentums = builder.CreateVector(momentums); + fbs::ParameterOptimizerStateBuilder optimizer_state_builder(builder); + optimizer_state_builder.add_param_name(fbs_param_name); + optimizer_state_builder.add_momentums(fbs_momentums); + + flatbuffers::Offset fbs_optimizer_state = optimizer_state_builder.Finish(); + optimizer_states.push_back(fbs_optimizer_state); } - // Save each optimizer state (of all parameters) into single file. - // For example: save "momentum_1" of all parameters into one file. - for (auto& pair : optimizer_state_ort_values) { - const PathString momentum_name = ToPathString(pair.first); - const std::unordered_map& param_name_to_ortvalue = pair.second; - const PathString& cur_state_filename_prefix = - StringConcat(cur_group_filename_prefix, momentum_name); - - std::vector saved_tensor_protos; - ORT_RETURN_IF_ERROR(CreateTensorProtosFromOrtValues( - param_name_to_ortvalue, - *optimizer_state.optimizer_session_data_transfer_mgr, - saved_tensor_protos)); - - // Save TensorProto to file. - WriteTensorProtoToFile( - GetTensorProtoFilePath(checkpoint_path, cur_state_filename_prefix), - saved_tensor_protos, "[optimizer_state]"); - } + const auto fbs_group_name = builder.CreateString(group_name); + const auto fbs_optimizer_states = builder.CreateVector(optimizer_states); - // Storing group-wise properties. - PropertyBag properties; - properties.AddProperty(builtin_lr_property_name, group_optimizer_state_ptr->initial_lr); - properties.AddProperty(builtin_step_property_name, group_optimizer_state_ptr->step); - std::vector group_wise_properties_tensor_protos; - properties.ToTensorProtos(group_wise_properties_tensor_protos); + fbs::OptimizerGroupBuilder optimizer_state_builder(builder); + optimizer_state_builder.add_group_name(fbs_group_name); + optimizer_state_builder.add_initial_learning_rate(group_optimizer_state_ptr->initial_lr); + optimizer_state_builder.add_step(group_optimizer_state_ptr->step); + optimizer_state_builder.add_optimizer_states(fbs_optimizer_states); + auto fbs_optimizer_group = optimizer_state_builder.Finish(); + fbs_optimizer_groups.push_back(fbs_optimizer_group); + } - WriteTensorProtoToFile( - GetTensorProtoPropertiesFilePath(checkpoint_path, cur_group_filename_prefix), - group_wise_properties_tensor_protos, "[param_group_properties]"); + return Status::OK(); +} + +/** + * @brief Save from user defined properties to a flatbuffer checkpoint property bag. + * + * @param property_bag user defined properties. + * @param builder Flatbuffer builder. + * @param fbs_property_bag Flatbuffer property bag to be populated. + * @return Status of the operation. + */ +Status FromPropertyBag(const PropertyBag& property_bag, flatbuffers::FlatBufferBuilder& builder, + flatbuffers::Offset& fbs_property_bag) { + if (property_bag.size() == 0U) { + return Status::OK(); + } + + std::vector> ints; + std::vector> floats; + std::vector> strings; + for (const auto& name : SortedKeys(property_bag)) { + const auto& value = property_bag.GetProperty(name); + const auto fbs_property_name = builder.CreateString(name); + if (std::holds_alternative(value)) { + fbs::IntPropertyBuilder int_property_builder(builder); + int_property_builder.add_name(fbs_property_name); + int_property_builder.add_value(std::get(value)); + flatbuffers::Offset property = int_property_builder.Finish(); + ints.push_back(property); + } else if (std::holds_alternative(value)) { + fbs::FloatPropertyBuilder float_property_builder(builder); + float_property_builder.add_name(fbs_property_name); + float_property_builder.add_value(std::get(value)); + flatbuffers::Offset property = float_property_builder.Finish(); + floats.push_back(property); + } else if (std::holds_alternative(value)) { + const auto fbs_property_value = builder.CreateString(std::get(value)); + fbs::StringPropertyBuilder string_property_builder(builder); + string_property_builder.add_name(fbs_property_name); + string_property_builder.add_value(fbs_property_value); + flatbuffers::Offset property = string_property_builder.Finish(); + strings.push_back(property); + } else { + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Unknown property type encountered in the property bag."); + } } + const auto fbs_ints = builder.CreateVector(ints); + const auto fbs_floats = builder.CreateVector(floats); + const auto fbs_strings = builder.CreateVector(strings); + + fbs::PropertyBagBuilder property_bag_builder(builder); + property_bag_builder.add_ints(fbs_ints); + property_bag_builder.add_floats(fbs_floats); + property_bag_builder.add_strings(fbs_strings); + fbs_property_bag = property_bag_builder.Finish(); + return Status::OK(); } -Status OrtSaveInternal( - CheckpointState& state, const PathString& checkpoint_path, const bool include_optimizer_state) { - LOGS_DEFAULT(INFO) << "Saving model checkpoint files to " << ToUTF8String(checkpoint_path); - LOGS_DEFAULT_IF(Env::Default().FolderExists(checkpoint_path), WARNING) - << "Checkpoint directory exists - data may be overwritten."; - ORT_RETURN_IF_ERROR(Env::Default().CreateFolder(checkpoint_path)); +/** + * @brief Save from a checkpoint state to a checkpoint file. + * + * @param state parameter/optimizer and other user defined training states. + * @param checkpoint_path file where checkpoint is saved. + * @param include_optimizer_state Whether to include optimizer state in the checkpoint. + * @return Status of the operation. + */ +Status FromCheckpointState( + const CheckpointState& state, const PathString& checkpoint_path, const bool include_optimizer_state) { + flatbuffers::FlatBufferBuilder builder(1024); // Write weight tensors files. - ORT_RETURN_IF_ERROR(OrtSaveModuleStatesInternal(state.module_checkpoint_state, checkpoint_path)); + flatbuffers::Offset module_state; + ORT_RETURN_IF_ERROR(FromModuleState(state.module_checkpoint_state, builder, module_state)); // Write optimizer state tensors files. + std::vector> optimizer_groups; if (include_optimizer_state) { - ORT_RETURN_IF_ERROR(OrtSaveOptimizerStatesInternal(state.optimizer_checkpoint_state, checkpoint_path)); + ORT_RETURN_IF_ERROR(FromOptimizerState(state.optimizer_checkpoint_state, builder, optimizer_groups)); } - // Write properties file - const PropertyBag& property_bag = state.property_bag; - if (property_bag.Size() > 0) { - std::vector properties_tensor_protos; - property_bag.ToTensorProtos(properties_tensor_protos); + flatbuffers::Offset property_bag; + ORT_RETURN_IF_ERROR(FromPropertyBag(state.property_bag, builder, property_bag)); - WriteTensorProtoToFile( - GetTensorProtoPropertiesFilePath(checkpoint_path, k_property_root_prefix), - properties_tensor_protos, "[custom_properties]"); - } + const auto fbs_optimizer_groups = builder.CreateVector(optimizer_groups); - LOGS_DEFAULT(INFO) << "Checkpoint saved successfully."; - return Status::OK(); + fbs::CheckpointBuilder checkpoint_builder(builder); + checkpoint_builder.add_version(kCheckpointVersion); + checkpoint_builder.add_module_state(module_state); + checkpoint_builder.add_optimizer_groups(fbs_optimizer_groups); + checkpoint_builder.add_property_bag(property_bag); + const auto checkpoint = checkpoint_builder.Finish(); + builder.Finish(checkpoint, fbs::CheckpointIdentifier()); + + return save::ToFile(checkpoint_path, builder); } -Status OrtLoadModuleStatesInternal( - const PathString& parameter_folder_path, ModuleCheckpointState& module_state) { - // Find parameter files. - InlinedVector> param_filenames; - FilterFilesFromDirectory( - parameter_folder_path, - [¶m_filenames](const PathChar* filename) -> bool { - PathString filename_str = filename; - if (StringStartsWith(filename_str, k_trainable_param_root_prefix)) { - param_filenames.push_back(std::make_pair(filename_str, true)); - } else if (StringStartsWith(filename_str, k_non_trainable_param_root_prefix)) { - param_filenames.push_back(std::make_pair(filename_str, false)); - } - return true; - }); - - if (param_filenames.empty()) { - return Status::OK(); - } +} // namespace save - // Parameter parsing. - auto& named_parameters = module_state.named_parameters; - auto load_model_proto_into_module = - [&named_parameters](const PathString module_state_file_path, bool is_trainable) -> Status { - std::vector param_tensor_protos{}; +namespace load { - LoadTensorProtoFromFile(module_state_file_path, param_tensor_protos, "[params]"); +/** + * @brief Load checkpoint flatbuffer from file. + * @param checkpoint_path Path to the checkpoint file. + * @param checkpoint_bytes Contents of the checkpoint file in bytes. + * @param checkpoint_span Checkpoint bytes represented as a span. + * @return Status of the operation. + * + */ +Status FromFile(const PathString& checkpoint_path, InlinedVector& checkpoint_bytes) { + size_t num_bytes = 0; + ORT_RETURN_IF_ERROR(Env::Default().GetFileLength(checkpoint_path.c_str(), num_bytes)); + checkpoint_bytes.resize(num_bytes); - std::unordered_map name_to_ort_values; - ORT_RETURN_IF_ERROR(CreateOrtValuesFromTensorProtos(param_tensor_protos, name_to_ort_values)); - for (auto it = name_to_ort_values.begin(); it != name_to_ort_values.end(); ++it) { - auto param = std::make_shared(it->first, it->second, is_trainable); - named_parameters.insert({it->first, param}); - } - return Status::OK(); - }; + std::ifstream bytes_stream(checkpoint_path, std::ifstream::in | std::ifstream::binary); + bytes_stream.read(reinterpret_cast(checkpoint_bytes.data()), num_bytes); - for (auto& pair : param_filenames) { - auto param_file_path = ConcatPathComponent(parameter_folder_path, pair.first); - ORT_RETURN_IF_ERROR(load_model_proto_into_module(param_file_path, pair.second)); - } + ORT_RETURN_IF_NOT(bytes_stream, "Loading checkpoint from ", ToUTF8String(checkpoint_path), " failed. Only ", + bytes_stream.gcount(), "/", num_bytes, " bytes could be read."); return Status::OK(); } -Status OrtLoadOptimizerStatesInternal(const PathString& optimizer_folder_path, - OptimizerCheckpointState& optimizer_state) { - // Optimizer states parsing. - std::vector optim_state_filenames; - std::vector optim_property_filenames; - FilterFilesFromDirectory( - optimizer_folder_path, - [&optim_state_filenames, &optim_property_filenames](const PathChar* filename) -> bool { - PathString filename_str = filename; - if (StringStartsWith(filename_str, k_optimizer_root_prefix)) { - if (StringEndsWith(filename_str, k_tensor_proto_file_name)) { - optim_state_filenames.push_back(filename_str); - } else if (StringEndsWith(filename_str, k_tensor_proto_properties_file_name)) { - optim_property_filenames.push_back(filename_str); - } else { - ORT_THROW("Unexpected file extension."); - } - } - return true; - }); - - auto& grouped_optimizer_states = optimizer_state.group_named_optimizer_states; - // For each optimizer state files, parse the data and feed into grouped_optimizer_states. - for (auto& filename : optim_state_filenames) { - std::vector results; - StringSplit(filename, results); - ORT_ENFORCE(results.size() >= 3U, "Incorrect optimizer state filename."); - const std::string& group_name = ToUTF8String(results[1]); - const std::string& momentum_name = ToUTF8String(results[2]); - - const PathString cur_group_filename_prefix = - StringConcat(k_optimizer_root_prefix, results[1]); - PathString cur_momentum_state_filename_prefix = - StringConcat(cur_group_filename_prefix, results[2]); - ORT_ENFORCE(filename.compare(StringConcat(cur_momentum_state_filename_prefix, k_tensor_proto_file_name)) == 0); - - if (grouped_optimizer_states.find(group_name) == grouped_optimizer_states.end()) { - grouped_optimizer_states.insert({group_name, std::make_shared()}); - } +/** + * @brief Load from a flatbuffer checkpoint module state to a module state. + * + * @param fbs_module_state Flatbuffer module state. + * @param module_state Module state to be populated. + * @return Status of the operation. + */ +Status ToModuleState( + const onnxruntime::fbs::ModuleState& fbs_module_state, ModuleCheckpointState& module_state) { + const auto* requires_grad_params = fbs_module_state.requires_grad_params(); + ORT_RETURN_IF_NOT(requires_grad_params, "Expected: Valid trainable tensors flatbuffer.", + " Actual: Encountered a nullptr. Checkpoint file is invalid"); + flatbuffers::uoffset_t trainable_params_size = requires_grad_params->size(); + InlinedHashMap trainable_params; + trainable_params.reserve(trainable_params_size); + ORT_RETURN_IF_ERROR(OrtValuesFromFlatbufferTensors(*requires_grad_params, trainable_params)); + + for (auto& [name, value] : trainable_params) { + auto param = std::make_shared(name, value, true); + module_state.named_parameters.insert({name, param}); + } - auto& group_optimizer_state = grouped_optimizer_states[group_name]; - std::unordered_map& - param_optimizer_states = group_optimizer_state->param_named_optimizer_states; - - const PathString& tensor_file_path = GetTensorProtoFilePath(optimizer_folder_path, - cur_momentum_state_filename_prefix); - std::vector param_optimizer_state_tensor_protos{}; - LoadTensorProtoFromFile(tensor_file_path, param_optimizer_state_tensor_protos, "[optimizer_state]"); - - std::unordered_map name_to_ort_values; - ORT_RETURN_IF_ERROR(CreateOrtValuesFromTensorProtos(param_optimizer_state_tensor_protos, name_to_ort_values)); - for (auto& pair : name_to_ort_values) { - auto& param_name = pair.first; - if (param_optimizer_states.find(param_name) == param_optimizer_states.end()) { - ParameterOptimizerState param_state; - param_optimizer_states.insert({param_name, param_state}); - } - param_optimizer_states[param_name].momentum_named_states.insert({momentum_name, std::move(pair.second)}); - } + const auto* frozen_params = fbs_module_state.frozen_params(); + ORT_RETURN_IF_NOT(frozen_params, "Expected: Valid non trainable tensors flatbuffer.", + " Actual: Encountered a nullptr. Checkpoint file is invalid"); + flatbuffers::uoffset_t non_trainable_params_size = frozen_params->size(); + InlinedHashMap non_trainable_params; + non_trainable_params.reserve(non_trainable_params_size); + ORT_RETURN_IF_ERROR(OrtValuesFromFlatbufferTensors(*frozen_params, non_trainable_params)); + + for (auto& [name, value] : non_trainable_params) { + auto param = std::make_shared(name, value, false); + module_state.named_parameters.insert({name, param}); } - // For each optimizer properties files, parse the data and feed into grouped_optimizer_states. - for (auto& filename : optim_property_filenames) { - std::vector results; - StringSplit(filename, results); - ORT_ENFORCE(results.size() >= 2U, "Incorrect optimizer property filename."); - const std::string& group_name = ToUTF8String(results[1]); + return Status::OK(); +} - if (grouped_optimizer_states.find(group_name) == grouped_optimizer_states.end()) { - grouped_optimizer_states.insert({group_name, std::make_shared()}); +/** + * @brief Load from a flatbuffer checkpoint optimizer state to an optimizer state. + * + * @param optimizer_groups Flatbuffer optimizer groups. + * @param optimizer_state Optimizer state to be populated. + * @return Status of the operation. + */ +Status ToOptimizerState( + const flatbuffers::Vector>& optimizer_groups, + OptimizerCheckpointState& optimizer_state) { + for (const auto* optimizer_group : optimizer_groups) { + ORT_RETURN_IF_NOT(optimizer_group, "Expected: Valid optimizer groups flatbuffer.", + " Actual: Encountered a nullptr. Checkpoint file is invalid"); + + std::string group_name = optimizer_group->group_name()->str(); + const int64_t step = optimizer_group->step(); + const float initial_learning_rate = optimizer_group->initial_learning_rate(); + + const auto* parameter_optimizer_states = optimizer_group->optimizer_states(); + ORT_RETURN_IF_NOT(parameter_optimizer_states, "Expected: Valid parameter optimizer states flatbuffer.", + " Actual: Encountered a nullptr. Checkpoint file is invalid"); + + [[maybe_unused]] auto [optimizer_state_it, inserted] = + optimizer_state.group_named_optimizer_states.emplace( + std::move(group_name), std::make_shared()); + + ORT_RETURN_IF_NOT(inserted, "Encountered a duplicate optimizer group name: ", group_name, + ". Checkpoint file is invalid."); + + optimizer_state_it->second->step = step; + optimizer_state_it->second->initial_lr = initial_learning_rate; + for (const auto* parameter_optimizer_state : *parameter_optimizer_states) { + const std::string param_name = parameter_optimizer_state->param_name()->str(); + const auto* momentums = parameter_optimizer_state->momentums(); + ORT_RETURN_IF_NOT(momentums, "Expected: Valid optimizer momentum tensors flatbuffer.", + " Actual: Encountered a nullptr. Checkpoint file is invalid"); + ORT_RETURN_IF_ERROR(OrtValuesFromFlatbufferTensors( + *momentums, optimizer_state_it->second->param_named_optimizer_states[param_name])); } + } - auto& group_optimizer_state = grouped_optimizer_states[group_name]; + return Status::OK(); +} - // Parse group-wise properties. - const PathString cur_group_filename_prefix = StringConcat(k_optimizer_root_prefix, results[1]); - const PathString& tensor_file_path = GetTensorProtoPropertiesFilePath(optimizer_folder_path, - cur_group_filename_prefix); - std::vector group_wise_property_protos{}; - LoadTensorProtoFromFile(tensor_file_path, group_wise_property_protos, "[optimizer_groupwise_property]"); +/** + * @brief Load from a flatbuffer checkpoint property bag to a property bag. + * + * @param fbs_property_bag Flatbuffer property bag. + * @param property_bag Property bag to be populated. + * @return Status of the operation. + */ +Status ToPropertyBag(const onnxruntime::fbs::PropertyBag& fbs_property_bag, + PropertyBag& property_bag) { + const auto* ints = fbs_property_bag.ints(); + if (nullptr != ints) { + for (const auto* int_property : *ints) { + ORT_RETURN_IF_NOT(int_property, "Checkpoint is invalid. Expected: Valid flatbuffer int property. ", + "Actual: nullptr."); + ORT_RETURN_IF_NOT(int_property->name(), "Checkpoint is invalid. Expected: Valid flatbuffer int property name. ", + "Actual: nullptr."); + const std::string name = int_property->name()->str(); + const auto value = int_property->value(); + property_bag.AddProperty(name, value); + } + } - PropertyBag properties; - for (auto& property_proto : group_wise_property_protos) { - properties.AddProperty(property_proto); + const auto* floats = fbs_property_bag.floats(); + if (nullptr != floats) { + for (const auto* float_property : *floats) { + ORT_RETURN_IF_NOT(float_property, "Checkpoint is invalid. Expected: Valid flatbuffer float property. ", + "Actual: nullptr."); + ORT_RETURN_IF_NOT(float_property->name(), "Checkpoint is invalid. Expected: Valid flatbuffer float property name. ", + "Actual: nullptr."); + const std::string name = float_property->name()->str(); + const auto value = float_property->value(); + property_bag.AddProperty(name, value); } + } - group_optimizer_state->initial_lr = properties.GetProperty(builtin_lr_property_name); - group_optimizer_state->step = properties.GetProperty(builtin_step_property_name); - grouped_optimizer_states.insert({group_name, group_optimizer_state}); + const auto* strings = fbs_property_bag.strings(); + if (nullptr != strings) { + for (const auto* string_property : *strings) { + ORT_RETURN_IF_NOT(string_property, "Checkpoint is invalid. Expected: Valid flatbuffer string property. ", + "Actual: nullptr."); + ORT_RETURN_IF_NOT(string_property->name(), "Checkpoint is invalid. Expected: Valid flatbuffer string property name. ", + "Actual: nullptr."); + ORT_RETURN_IF_NOT(string_property->value(), "Checkpoint is invalid. Expected: Valid flatbuffer string property value. ", + "Actual: nullptr."); + const std::string name = string_property->name()->str(); + const std::string value = string_property->value()->str(); + property_bag.AddProperty(name, value); + } } return Status::OK(); } -Status OrtLoadCustomPropertyInternal(const PathString& property_folder_path, - PropertyBag& property_bag) { - // Find custom property files. - std::vector custom_property_filenames; - FilterFilesFromDirectory( - property_folder_path, - [&custom_property_filenames](const PathChar* filename) -> bool { - PathString filename_str = filename; - if (StringStartsWith(filename_str, k_property_root_prefix)) { - custom_property_filenames.push_back(filename_str); - } - return true; - }); - - if (custom_property_filenames.empty()) { - return Status::OK(); - } +#if !defined(ORT_MINIMAL_BUILD) +/** + * @brief Load checkpoint from a checkpoint file to initializers in a model proto. + * + * @param checkpoint_path Path to the checkpoint file. + * @param model_proto Model proto to be populated. + * @return Status of the operation. + */ +Status ToModelProto(gsl::span checkpoint_bytes, + ONNX_NAMESPACE::ModelProto& model_proto) { + flatbuffers::Verifier verifier(checkpoint_bytes.data(), checkpoint_bytes.size()); + ORT_RETURN_IF_NOT(fbs::VerifyCheckpointBuffer(verifier), "Checkpoint verification failed."); - for (auto& property_file_path : custom_property_filenames) { - std::vector property_protos{}; - auto property_file_full_path = ConcatPathComponent(property_folder_path, property_file_path); - LoadTensorProtoFromFile(property_file_full_path, property_protos, "[custom_property]"); + const auto* fbs_checkpoint = fbs::GetCheckpoint(checkpoint_bytes.data()); + ORT_RETURN_IF_NOT(fbs_checkpoint, "Checkpoint is invalid. Expected: Valid checkpoint flatbuffer. Actual: nullptr."); - for (auto& property_proto : property_protos) { - property_bag.AddProperty(property_proto); - } + const auto checkpoint_version = fbs_checkpoint->version(); + ORT_RETURN_IF_NOT(IsCheckpointVersionSupported(checkpoint_version), + "Checkpoint is invalid. Checkpoint version ", checkpoint_version, " is not supported."); + + const auto* module_state = fbs_checkpoint->module_state(); + if (nullptr == module_state) { + return Status::OK(); } - return Status::OK(); -} + const auto* requires_grad_params = module_state->requires_grad_params(); + ORT_RETURN_IF_NOT(requires_grad_params, + "Checkpoint is invalid. Expected: Valid trainable params flatbuffer. Actual: nullptr."); + + const auto* frozen_params = module_state->frozen_params(); + ORT_RETURN_IF_NOT(frozen_params, + "Checkpoint is invalid. Expected: Valid non-trainable params flatbuffer. Actual: nullptr."); -Status OrtLoadInternal(const PathString& checkpoint_path, - ONNX_NAMESPACE::ModelProto& model_proto) { - // Find tensor proto files. InlinedHashMap param_tensor_protos; - InlinedVector tensor_proto_filenames; - - FilterFilesFromDirectory( - checkpoint_path, - [&tensor_proto_filenames](const PathChar* filename) -> bool { - PathString filename_str = filename; - if (StringEndsWith(filename_str, k_tensor_proto_file_name)) { - tensor_proto_filenames.push_back(filename_str); - } - return true; - }); - - // Load tensor protos to the tensorProto Vector - for (const auto& tensor_file_path : tensor_proto_filenames) { - std::vector tensor_protos{}; - const auto tensor_file_full_path = ConcatPathComponent(checkpoint_path, tensor_file_path); - LoadTensorProtoFromFile(tensor_file_full_path, tensor_protos, "[params]"); - - for (auto& tensor_proto : tensor_protos) { - auto tensor_proto_name = tensor_proto.name(); - param_tensor_protos.emplace(std::make_pair(tensor_proto_name, std::move(tensor_proto))); + param_tensor_protos.reserve( + static_cast(requires_grad_params->size()) + static_cast(frozen_params->size())); + + const auto flatbuffer_tensors_to_tensor_protos = [¶m_tensor_protos](const auto& flatbuffer_tensors) { + OrtFormatLoadOptions load_options{false, false}; + for (const auto* fbs_tensor : flatbuffer_tensors) { + ORT_RETURN_IF_NOT(fbs_tensor, "Checkpoint is invalid. Expected: Valid flatbuffer tensor. Actual: nullptr."); + ONNX_NAMESPACE::TensorProto tensor_proto; + ORT_RETURN_IF_ERROR(fbs::utils::LoadInitializerOrtFormat(*fbs_tensor, tensor_proto, load_options)); + param_tensor_protos.insert({fbs_tensor->name()->str(), tensor_proto}); } - } - // Load imported initializers into the Model + return Status::OK(); + }; + + ORT_RETURN_IF_ERROR(flatbuffer_tensors_to_tensor_protos(*requires_grad_params)); + ORT_RETURN_IF_ERROR(flatbuffer_tensors_to_tensor_protos(*frozen_params)); + + // Copy loaded tensor protos to the initializers in the ModelProto for (auto& init : *(model_proto.mutable_graph()->mutable_initializer())) { - ORT_ENFORCE(init.has_name(), "An initializer should have a name."); - auto it = param_tensor_protos.find(init.name()); - if (it == param_tensor_protos.end()) { + ORT_RETURN_IF_NOT(init.has_name(), "ModelProto is invalid. Expected: All initializers must have names."); + const auto it = param_tensor_protos.find(init.name()); + if (it == param_tensor_protos.cend()) { continue; } - init = it->second; + init.CopyFrom(it->second); } return Status::OK(); } +#endif + +/** + * @brief Load checkpoint from a checkpoint file to a checkpoint state. + * + * @param checkpoint_path Path to the checkpoint file. + * @param state Checkpoint state to be populated. + * @return Status of the operation. + */ +Status ToCheckpointState(gsl::span checkpoint_bytes, CheckpointState& state) { + flatbuffers::Verifier verifier(checkpoint_bytes.data(), checkpoint_bytes.size()); + ORT_RETURN_IF_NOT(fbs::VerifyCheckpointBuffer(verifier), "Checkpoint verification failed."); + + const auto* fbs_checkpoint = fbs::GetCheckpoint(checkpoint_bytes.data()); + ORT_RETURN_IF_NOT(fbs_checkpoint, "Checkpoint is invalid. Expected: Valid checkpoint flatbuffer. Actual: nullptr."); + + const auto checkpoint_version = fbs_checkpoint->version(); + ORT_RETURN_IF_NOT(IsCheckpointVersionSupported(checkpoint_version), + "Checkpoint is invalid. Checkpoint version ", checkpoint_version, " is not supported."); + + const auto* fbs_module_state = fbs_checkpoint->module_state(); + if (nullptr != fbs_module_state) { + ORT_RETURN_IF_ERROR(ToModuleState(*fbs_module_state, state.module_checkpoint_state)); + } + + const auto* fbs_optimizer_groups = fbs_checkpoint->optimizer_groups(); + if (nullptr != fbs_optimizer_groups) { + ORT_RETURN_IF_ERROR(ToOptimizerState(*fbs_optimizer_groups, state.optimizer_checkpoint_state)); + } + + const auto* fbs_property_bag = fbs_checkpoint->property_bag(); + if (nullptr != fbs_property_bag) { + ORT_RETURN_IF_ERROR(ToPropertyBag(*fbs_property_bag, state.property_bag)); + } -Status OrtLoadInternal(const PathString& checkpoint_path, CheckpointState& state) { - ORT_ENFORCE(Env::Default().FolderExists(checkpoint_path), "Checkpoint folder does not exist."); - ORT_RETURN_IF_ERROR(OrtLoadModuleStatesInternal(checkpoint_path, state.module_checkpoint_state)); - ORT_RETURN_IF_ERROR(OrtLoadOptimizerStatesInternal(checkpoint_path, state.optimizer_checkpoint_state)); - ORT_RETURN_IF_ERROR(OrtLoadCustomPropertyInternal(checkpoint_path, state.property_bag)); return Status::OK(); } +} // namespace load + } // namespace -Status SaveCheckpoint(const std::vector& trainable_tensor_protos, - const std::vector& non_trainable_tensor_protos, +#if !defined(ORT_MINIMAL_BUILD) +Status SaveCheckpoint(gsl::span trainable_tensor_protos, + gsl::span non_trainable_tensor_protos, const PathString& checkpoint_path) { - return OrtSaveInternal(trainable_tensor_protos, non_trainable_tensor_protos, checkpoint_path); + ORT_RETURN_IF_NOT(FLATBUFFERS_LITTLEENDIAN, "ORT training checkpoint format only supports little-endian machines"); + return save::FromTensorProtos(trainable_tensor_protos, non_trainable_tensor_protos, checkpoint_path); } +#endif -Status SaveCheckpoint(CheckpointState& states, const PathString& checkpoint_path, +Status SaveCheckpoint(const CheckpointState& states, const PathString& checkpoint_path, const bool include_optimizer_state) { - return OrtSaveInternal(states, checkpoint_path, include_optimizer_state); + ORT_RETURN_IF_NOT(FLATBUFFERS_LITTLEENDIAN, "ORT training checkpoint format only supports little-endian machines"); + return save::FromCheckpointState(states, checkpoint_path, include_optimizer_state); } Status LoadCheckpoint(const PathString& checkpoint_path, CheckpointState& checkpoint_states) { - return OrtLoadInternal(checkpoint_path, checkpoint_states); + ORT_RETURN_IF_NOT(FLATBUFFERS_LITTLEENDIAN, "ORT training checkpoint format only supports little-endian machines"); + + InlinedVector checkpoint_bytes; + ORT_RETURN_IF_ERROR(load::FromFile(checkpoint_path, checkpoint_bytes)); + return load::ToCheckpointState(checkpoint_bytes, checkpoint_states); } +Status LoadCheckpointFromBuffer(gsl::span checkpoint_bytes, CheckpointState& checkpoint_state) { + ORT_RETURN_IF_NOT(FLATBUFFERS_LITTLEENDIAN, "ORT training checkpoint format only supports little-endian machines"); + + return load::ToCheckpointState(checkpoint_bytes, checkpoint_state); +} + +#if !defined(ORT_MINIMAL_BUILD) Status LoadCheckpointToModel(const PathString& checkpoint_path, ONNX_NAMESPACE::ModelProto& model_proto) { - return OrtLoadInternal(checkpoint_path, model_proto); + ORT_RETURN_IF_NOT(FLATBUFFERS_LITTLEENDIAN, "ORT training checkpoint format only supports little-endian machines"); + + InlinedVector checkpoint_bytes; + ORT_RETURN_IF_ERROR(load::FromFile(checkpoint_path, checkpoint_bytes)); + return load::ToModelProto(checkpoint_bytes, model_proto); } +#endif -} // namespace api -} // namespace training -} // namespace onnxruntime +} // namespace onnxruntime::training::api diff --git a/orttraining/orttraining/training_api/checkpoint.h b/orttraining/orttraining/training_api/checkpoint.h index 5e3d469d9a372..5d8554662f48d 100644 --- a/orttraining/orttraining/training_api/checkpoint.h +++ b/orttraining/orttraining/training_api/checkpoint.h @@ -4,43 +4,26 @@ #pragma once #include "core/platform/path_lib.h" -#include "core/platform/env.h" -#include "onnx/defs/tensor_proto_util.h" - +#include "orttraining/training_api/checkpoint_property.h" #include "orttraining/training_api/module.h" #include "orttraining/training_api/optimizer.h" -#include "orttraining/training_api/checkpoint_property.h" /** - * There are two representation for checkpoint respectively in memory and files: - * - * 1. CheckpointState. A data class representing traing states in memory, which include: - * i. module state: - * a instance of data class `ModuleCheckpointState` managed along with Module/Parameter classes, - * ii. optimizer state: - * a instance of data class `OptimizerCheckpointState` managed along with Optimizer class, - * iii. user defined training properties, for example 'epoch', 'best_score': - * a instance of data class `PropertyBag`. + * The CheckpointState is a data class representing traning states in memory, which include: + * - Module state: Contains the model's trainable and non-trainable parameters. + * - Optimizer state: Contains the optimizer's state (for example learning rate, step, first + * and second order momentums ...). + * - User defined properties: For example 'epoch', 'best_score' ... * - * In terms of class dependencies, Checkpoint implementations are dependent on (and on top of) - * Parameter/Module/Optimizer, NOT vice versa. + * These states can be used to begin or resume training from a checkpoint. In order to pause training, + * the user can save the CheckpointState to a checkpoint file. * - * 2. A directory of files: - * checkpoint/ - * paramtrain_tensors.pbseq - trainable parameter tensor protobuf messages - * paramfrozen_tensors.pbseq - non_trainable parameter tensor protobuf messages - * optim_group0_momentum0_tensors.pbseq - optimizer momentum state tensor protobuf messages - * optim_group0_momentum1_tensors.pbseq - optimizer momentum state tensor protobuf messages - * optim_group0_properties.pbseq - group-wise optimizer property tensor protobuf messages - * custom_properties.pbseq - custom property protobuf messages + * The checkpoint file is a single flatbuffer file containing all the states highlighted above. + * The flatbuffer schema is defined in onnxruntime/core/flatbuffers/schema/ort_training_checkpoint.fbs * - * LoadCheckpoint takes CheckpointState as outputs, loading from a directory of checkpoint. - * SaveCheckpoint takes CheckpointState as inputs, saving checkpoint files into a directory. */ -namespace onnxruntime { -namespace training { -namespace api { +namespace onnxruntime::training::api { struct CheckpointState { public: @@ -53,44 +36,54 @@ struct CheckpointState { * @brief Save training states as ORT checkpoint. * * @param state parameter/optimizer and other user defined training states. - * @param checkpoint_path folder where checkpoint is saved. + * @param checkpoint_path file where checkpoint is saved. * @return Status - * TODO: change state to const ref */ -Status SaveCheckpoint(CheckpointState& state, const PathString& checkpoint_path, +Status SaveCheckpoint(const CheckpointState& state, const PathString& checkpoint_path, const bool include_optimizer_state); +#if !defined(ORT_MINIMAL_BUILD) /** * @brief Save ONNX initializers as ORT checkpoint. * * @param trainable_tensor_protos trainable parameters in TensorProto format. * @param non_trainable_tensor_protos non-trainable parameters in TensorProto format. - * @param checkpoint_path folder where checkpoint is saved. + * @param checkpoint_path file where checkpoint is saved. * @return Status */ -Status SaveCheckpoint(const std::vector& trainable_tensor_protos, - const std::vector& non_trainable_tensor_protos, +Status SaveCheckpoint(gsl::span trainable_tensor_protos, + gsl::span non_trainable_tensor_protos, const PathString& checkpoint_path); +#endif /** * @brief Load training states from ORT checkpoint. * - * @param checkpoint_path folder where checkpoint is stored. + * @param checkpoint_path file where checkpoint is stored. * @param checkpoint_states parameter/optimizer and other user defined training states. * @return Status */ Status LoadCheckpoint(const PathString& checkpoint_path, CheckpointState& checkpoint_state); +/** + * @brief Load training states from ORT checkpoint bytes buffer. + * @param checkpoint_bytes bytes buffer of the checkpoint. + * @param checkpoint_state parameter/optimizer and other user defined training states. + * @return Status + */ +Status LoadCheckpointFromBuffer(gsl::span checkpoint_bytes, + CheckpointState& checkpoint_state); + +#if !defined(ORT_MINIMAL_BUILD) /** * @brief Load training states from ORT checkpoint into a ModelProto. - * @param checkpoint_path folder where checkpoint is stored. - * @param model_proto Model Proto. + * @param checkpoint_path file where checkpoint is stored. + * @param model_proto ONNX model to load the checkpoint to. * @return Status */ Status LoadCheckpointToModel(const PathString& checkpoint_path, ONNX_NAMESPACE::ModelProto& model_proto); +#endif -} // namespace api -} // namespace training -} // namespace onnxruntime +} // namespace onnxruntime::training::api diff --git a/orttraining/orttraining/training_api/checkpoint_property.cc b/orttraining/orttraining/training_api/checkpoint_property.cc deleted file mode 100644 index dce21003f9f8d..0000000000000 --- a/orttraining/orttraining/training_api/checkpoint_property.cc +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#include "onnx/defs/tensor_proto_util.h" -#include "core/common/inlined_containers.h" -#include "core/platform/path_lib.h" -#include "core/platform/env.h" -#include "core/framework/tensorprotoutils.h" -#include "orttraining/training_api/checkpoint_property.h" - -namespace onnxruntime { -namespace training { -namespace api { - -namespace { - -template -void ParsePropertyFromTensorProto(const ONNX_NAMESPACE::TensorProto& tensor_proto, - std::string& name, - PropertyDataType& value) { - TensorShape tensor_shape = utils::GetTensorShapeFromTensorProto(tensor_proto); - ORT_ENFORCE(tensor_shape.Size() == 1, "Only scalar value is supported for checkpoint property."); - Path model_path; - InlinedVector data_vector(1); - T* p = data_vector.data(); - ORT_THROW_IF_ERROR(utils::UnpackTensor(tensor_proto, model_path, p, 1)); - name = tensor_proto.name(); - value = data_vector[0]; -} - -} // namespace - -void PropertyBag::AddProperty(const ONNX_NAMESPACE::TensorProto& tensor_proto) { - ORT_ENFORCE(named_properties_.find(tensor_proto.name()) == named_properties_.end(), - "Duplicated property named ", tensor_proto.name()); - - if (!IsSupportedDataType(tensor_proto.data_type())) { - ORT_THROW("Failed to add property from tensorproto: float, int64_t and std::string data types supported only."); - } - - auto data_type = tensor_proto.data_type(); - std::string prop_name; - PropertyDataType prop_value; - switch (data_type) { - case ONNX_NAMESPACE::TensorProto::FLOAT: { - ParsePropertyFromTensorProto(tensor_proto, prop_name, prop_value); - break; - } - case ONNX_NAMESPACE::TensorProto::STRING: { - ParsePropertyFromTensorProto(tensor_proto, prop_name, prop_value); - break; - } - case ONNX_NAMESPACE::TensorProto::INT64: { - ParsePropertyFromTensorProto(tensor_proto, prop_name, prop_value); - break; - } - default: - ORT_THROW("Unsupported input data type of ", data_type); - } - - named_properties_.insert({prop_name, prop_value}); -} - -} // namespace api -} // namespace training -} // namespace onnxruntime diff --git a/orttraining/orttraining/training_api/checkpoint_property.h b/orttraining/orttraining/training_api/checkpoint_property.h index 2f4460f1fbf93..d7b1e295df53e 100644 --- a/orttraining/orttraining/training_api/checkpoint_property.h +++ b/orttraining/orttraining/training_api/checkpoint_property.h @@ -8,11 +8,8 @@ #include #include "core/common/inlined_containers.h" -#include "onnx/defs/tensor_proto_util.h" -namespace onnxruntime { -namespace training { -namespace api { +namespace onnxruntime::training::api { using PropertyDataType = std::variant; @@ -31,8 +28,6 @@ struct PropertyBag { named_properties_.insert({name, val}); } - void AddProperty(const ONNX_NAMESPACE::TensorProto& tensor_proto); - template T GetProperty(const std::string& name) const { auto it = named_properties_.find(name); @@ -43,24 +38,15 @@ struct PropertyBag { return *tval; } - void ToTensorProtos(std::vector& properties_tensor_protos) const { - for (auto it = named_properties_.begin(); it != named_properties_.end(); ++it) { - onnx::TensorProto t_proto; - if (const float* fval = std::get_if(&it->second); fval != nullptr) { - t_proto = ONNX_NAMESPACE::ToTensor(*fval); - } else if (const int64_t* ival = std::get_if(&it->second); ival != nullptr) { - t_proto = ONNX_NAMESPACE::ToTensor(*ival); - } else if (const std::string* sval = std::get_if(&it->second); sval != nullptr) { - t_proto = ONNX_NAMESPACE::ToTensor(*sval); - } else { - ORT_THROW("Should not go there, unexpected data_type for prop value."); - } - t_proto.set_name(it->first); - properties_tensor_protos.emplace_back(t_proto); - } + auto begin() const { + return named_properties_.begin(); + } + + auto end() const { + return named_properties_.end(); } - size_t Size() const { + size_t size() const { return named_properties_.size(); } @@ -69,15 +55,6 @@ struct PropertyBag { } private: - const InlinedVector supported_data_types{ - ONNX_NAMESPACE::TensorProto::FLOAT, - ONNX_NAMESPACE::TensorProto::INT64, - ONNX_NAMESPACE::TensorProto::STRING}; - - bool IsSupportedDataType(int32_t data_type) const { - return std::find(supported_data_types.begin(), supported_data_types.end(), data_type) != supported_data_types.end(); - } - InlinedHashMap named_properties_; }; @@ -89,6 +66,4 @@ inline PropertyDataType PropertyBag::GetProperty(const std::st return it->second; } -} // namespace api -} // namespace training -} // namespace onnxruntime +} // namespace onnxruntime::training::api diff --git a/orttraining/orttraining/training_api/include/onnxruntime_training_c_api.h b/orttraining/orttraining/training_api/include/onnxruntime_training_c_api.h index 2d8aafd44f748..0af737074964d 100644 --- a/orttraining/orttraining/training_api/include/onnxruntime_training_c_api.h +++ b/orttraining/orttraining/training_api/include/onnxruntime_training_c_api.h @@ -13,7 +13,7 @@ * * In order to train a model with onnxruntime, the following training artifacts must be generated: * - The training onnx model - * - The checkpoint directory + * - The checkpoint file * - The optimizer onnx model * - The eval onnx model model (optional) * @@ -123,9 +123,9 @@ struct OrtTrainingApi { /// \name Accessing The Training Session State /// @{ - /** \brief Load a checkpoint state from directory on disk into checkpoint_state. + /** \brief Load a checkpoint state from a file on disk into checkpoint_state. * - * This function will parse a checkpoint directory, pull relevant files and load the training + * This function will parse a checkpoint file, pull relevant data and load the training * state into the checkpoint_state. This checkpoint state can then be used to create the * training session by invoking OrtTrainingApi::CreateTrainingSession. By doing so, the training * session will resume training from the given checkpoint state. @@ -133,7 +133,7 @@ struct OrtTrainingApi { * training state (including model parameters, its gradients, the optimizer states and the properties). * As a result, it is required that the checkpoint state outlive the lifetime of the training session. * - * \param[in] checkpoint_path Path to the checkpoint directory + * \param[in] checkpoint_path Path to the checkpoint file * \param[out] checkpoint_state Checkpoint state that contains the states of the training session. * * \snippet{doc} snippets.dox OrtStatus Return Value @@ -142,14 +142,14 @@ struct OrtTrainingApi { ORT_API2_STATUS(LoadCheckpoint, _In_ const ORTCHAR_T* checkpoint_path, _Outptr_ OrtCheckpointState** checkpoint_state); - /** \brief Save the given state to a checkpoint directory on disk. + /** \brief Save the given state to a checkpoint file on disk. * - * This function serializes the provided checkpoint state to a directory on disk. + * This function serializes the provided checkpoint state to a file on disk. * This checkpoint can later be loaded by invoking OrtTrainingApi::LoadCheckpoint to resume * training from this snapshot of the state. * * \param[in] checkpoint_state The checkpoint state to save. - * \param[in] checkpoint_path Path to the checkpoint directory. + * \param[in] checkpoint_path Path to the checkpoint file. * \param[in] include_optimizer_state Flag to indicate whether to save the optimizer state or not. * * \snippet{doc} snippets.dox OrtStatus Return Value @@ -172,7 +172,7 @@ struct OrtTrainingApi { * - The training onnx model * - The evaluation onnx model (optional) * - The optimizer onnx model - * - The checkpoint directory + * - The checkpoint file * * These artifacts can be generated using the `onnxruntime-training` python [utility](https://github.com/microsoft/onnxruntime/blob/main/orttraining/orttraining/python/training/onnxblock/README.md). * @@ -190,7 +190,29 @@ struct OrtTrainingApi { ORT_API2_STATUS(CreateTrainingSession, _In_ const OrtEnv* env, _In_ const OrtSessionOptions* options, _Inout_ OrtCheckpointState* checkpoint_state, _In_ const ORTCHAR_T* train_model_path, _In_ const ORTCHAR_T* eval_model_path, _In_ const ORTCHAR_T* optimizer_model_path, - _Outptr_ OrtTrainingSession** out); + _Outptr_result_maybenull_ OrtTrainingSession** out); + + /** \brief Create a training session that can be used to begin or resume training. + * This api provides a way to load all the training artifacts from buffers instead of files. + * + * \param[in] env Environment to be used for the training session. + * \param[in] options Session options that the user can customize for this training session. + * \param[in] checkpoint_state Training states that the training session uses as a starting point for training. + * \param[in] train_model_data Buffer containing the model data to be used to perform training + * \param[in] train_data_length Length of the buffer containing train_model_data + * \param[in] eval_model_data Buffer containing the model data to be used to perform evaluation + * \param[in] eval_data_length Length of the buffer containing eval_model_data + * \param[in] optim_model_data Buffer containing the model data to be used to perform weight update + * \param[in] optim_data_length Length of the buffer containing optim_model_data + * \param[out] out Created training session. + * + */ + ORT_API2_STATUS(CreateTrainingSessionFromBuffer, _In_ const OrtEnv* env, + _In_ const OrtSessionOptions* options, _Inout_ OrtCheckpointState* checkpoint_state, + _In_ const void* train_model_data, size_t train_data_length, + _In_ const void* eval_model_data, size_t eval_data_length, + _In_ const void* optim_model_data, size_t optim_data_length, + _Outptr_result_maybenull_ OrtTrainingSession** out); /// @} @@ -623,6 +645,31 @@ struct OrtTrainingApi { _Out_ enum OrtPropertyType* property_type, _Outptr_ void** property_value); /// @} + + /// \name Accessing The Training Session State + /// @{ + + /** \brief Load a checkpoint state from a buffer into checkpoint_state. + * + * This function will parse a checkpoint bytes buffer, pull relevant data and load the training + * state into the checkpoint_state. This checkpoint state can then be used to create the + * training session by invoking OrtTrainingApi::CreateTrainingSession. By doing so, the training + * session will resume training from the given checkpoint state. + * \note Note that the training session created with a checkpoint state uses this state to store the entire + * training state (including model parameters, its gradients, the optimizer states and the properties). + * As a result, it is required that the checkpoint state outlive the lifetime of the training session. + * + * \param[in] checkpoint_buffer Path to the checkpoint bytes buffer. + * \param[in] num_bytes Number of bytes in the checkpoint buffer. + * \param[out] checkpoint_state Checkpoint state that contains the states of the training session. + * + * \snippet{doc} snippets.dox OrtStatus Return Value + * + */ + ORT_API2_STATUS(LoadCheckpointFromBuffer, _In_ const void* checkpoint_buffer, + _In_ const size_t num_bytes, _Outptr_ OrtCheckpointState** checkpoint_state); + + /// @} }; typedef struct OrtTrainingApi OrtTrainingApi; diff --git a/orttraining/orttraining/training_api/include/onnxruntime_training_cxx_api.h b/orttraining/orttraining/training_api/include/onnxruntime_training_cxx_api.h index 96e9013818d5b..0edef20ba6da8 100644 --- a/orttraining/orttraining/training_api/include/onnxruntime_training_cxx_api.h +++ b/orttraining/orttraining/training_api/include/onnxruntime_training_cxx_api.h @@ -71,27 +71,40 @@ class CheckpointState : public detail::Base { /// \name Accessing The Training Session State /// @{ - /** \brief Load a checkpoint state from directory on disk into checkpoint_state. + /** \brief Load a checkpoint state from a file on disk into checkpoint_state. * - * This function will parse a checkpoint directory, pull relevant files and load the training + * This function will parse a checkpoint file, pull relevant data and load the training * state and return an instance of Ort::CheckpointState. This checkpoint state can then be used to create the * training session by instantiating Ort::TrainingSession. By doing so, the training session will resume * training from the given checkpoint state. * - * \param[in] path_to_checkpoint Path to the checkpoint directory + * \param[in] path_to_checkpoint Path to the checkpoint file * \return Ort::CheckpointState object which holds the state of the training session parameters. * */ static CheckpointState LoadCheckpoint(const std::basic_string& path_to_checkpoint); - /** \brief Save the given state to a checkpoint directory on disk. + /** \brief Load a checkpoint state from a buffer. * - * This function serializes the provided checkpoint state to a directory on disk. + * This function will parse a checkpoint buffer, pull relevant data and load the training + * state and return an instance of Ort::CheckpointState. This checkpoint state can then be used to create the + * training session by instantiating Ort::TrainingSession. By doing so, the training session will resume + * training from the given checkpoint state. + * + * \param[in] buffer Buffer containing the checkpoint data. + * \return Ort::CheckpointState object which holds the state of the training session parameters. + * + */ + static CheckpointState LoadCheckpointFromBuffer(const std::vector& buffer); + + /** \brief Save the given state to a checkpoint file on disk. + * + * This function serializes the provided checkpoint state to a file on disk. * This checkpoint can later be loaded by invoking Ort::CheckpointState::LoadCheckpoint to resume * training from this snapshot of the state. * * \param[in] checkpoint_state The checkpoint state to save. - * \param[in] path_to_checkpoint Path to the checkpoint directory. + * \param[in] path_to_checkpoint Path to the checkpoint file. * \param[in] include_optimizer_state Flag to indicate whether to save the optimizer state or not. * */ @@ -131,7 +144,7 @@ class CheckpointState : public detail::Base { * - The training onnx model * - The evaluation onnx model (optional) * - The optimizer onnx model - * - The checkpoint directory + * - The checkpoint file * * These artifacts can be generated using the `onnxruntime-training` python [utility](https://github.com/microsoft/onnxruntime/blob/main/orttraining/orttraining/python/training/onnxblock/README.md). * @@ -163,6 +176,20 @@ class TrainingSession : public detail::Base { const std::optional>& eval_model_path = std::nullopt, const std::optional>& optimizer_model_path = std::nullopt); + /** \brief Create a training session that can be used to begin or resume training. + * This constructor allows the users to load the models from buffers instead of files. + * + * \param[in] env Env to be used for the training session. + * \param[in] session_options SessionOptions that the user can customize for this training session. + * \param[in] checkpoint_state Training states that the training session uses as a starting point for training. + * \param[in] train_model_data Buffer containing training model data. + * \param[in] eval_model_data Buffer containing evaluation model data. + * \param[in] optim_model_data Buffer containing optimizer model (used for performing weight/parameter update). + * + */ + TrainingSession(const Env& env, const SessionOptions& session_options, CheckpointState& checkpoint_state, + const std::vector& train_model_data, const std::vector& eval_model_data = {}, + const std::vector& optim_model_data = {}); /// @} /// \name Implementing The Training Loop @@ -181,7 +208,6 @@ class TrainingSession : public detail::Base { * \param[in] input_values The user inputs to the training model. * \return A std::vector of Ort::Value objects that represents the output of the forward pass of the training model. * - * \snippet{doc} snippets.dox OrtStatus Return Value * */ std::vector TrainStep(const std::vector& input_values); diff --git a/orttraining/orttraining/training_api/include/onnxruntime_training_cxx_inline.h b/orttraining/orttraining/training_api/include/onnxruntime_training_cxx_inline.h index 8929e0d185998..c0048458ddf4d 100644 --- a/orttraining/orttraining/training_api/include/onnxruntime_training_cxx_inline.h +++ b/orttraining/orttraining/training_api/include/onnxruntime_training_cxx_inline.h @@ -24,6 +24,23 @@ inline TrainingSession::TrainingSession(const Env& env, const SessionOptions& se ThrowOnError(GetTrainingApi().TrainingSessionGetEvalModelOutputCount(p_, &eval_model_output_count_)); } +inline TrainingSession::TrainingSession(const Env& env, const SessionOptions& session_options, + CheckpointState& checkpoint_state, + const std::vector& train_model_data, + const std::vector& eval_model_data, + const std::vector& optim_model_data) { + ThrowOnError(GetTrainingApi().CreateTrainingSessionFromBuffer( + env, session_options, checkpoint_state, + train_model_data.data(), train_model_data.size(), + eval_model_data.data(), eval_model_data.size(), + optim_model_data.data(), optim_model_data.size(), + &p_)); + + ThrowOnError(GetTrainingApi().TrainingSessionGetTrainingModelOutputCount(p_, &training_model_output_count_)); + + ThrowOnError(GetTrainingApi().TrainingSessionGetEvalModelOutputCount(p_, &eval_model_output_count_)); +} + inline std::vector TrainingSession::TrainStep(const std::vector& input_values) { std::vector output_values; output_values.reserve(training_model_output_count_); @@ -51,7 +68,7 @@ inline std::vector TrainingSession::EvalStep(const std::vector& in RunOptions run_options; ThrowOnError(GetTrainingApi().EvalStep( p_, run_options, input_values.size(), ort_input_values, - training_model_output_count_, ort_output_values)); + eval_model_output_count_, ort_output_values)); return output_values; } @@ -175,6 +192,12 @@ inline CheckpointState CheckpointState::LoadCheckpoint(const std::basic_string& buffer) { + OrtCheckpointState* checkpoint_state; + ThrowOnError(GetTrainingApi().LoadCheckpointFromBuffer(buffer.data(), buffer.size(), &checkpoint_state)); + return CheckpointState(checkpoint_state); +} + inline void CheckpointState::SaveCheckpoint(const CheckpointState& checkpoint_states, const std::basic_string& path_to_checkpoint, const bool include_optimizer_state) { @@ -208,9 +231,12 @@ inline void CheckpointState::AddProperty(const std::string& property_name, const ThrowOnError(GetTrainingApi().AddProperty(p_, property_name.c_str(), OrtPropertyType::OrtFloatProperty, value_p)); } else if (std::holds_alternative(property_value)) { std::string value = std::get(property_value); - auto buffer = std::make_unique(value.length() + 1).release(); - memcpy(buffer, value.c_str(), value.length()); - ThrowOnError(GetTrainingApi().AddProperty(p_, property_name.c_str(), OrtPropertyType::OrtStringProperty, buffer)); + auto buffer = std::make_unique(value.length() + 1); + memcpy(buffer.get(), value.c_str(), value.length()); + // AddProperty takes a char* and calls PropertyBag::AddProperty which takes a std::string. The data will be + // copied at that point so buffer can free the local allocation once the call is made. + ThrowOnError(GetTrainingApi().AddProperty(p_, property_name.c_str(), OrtPropertyType::OrtStringProperty, + buffer.get())); } else { ThrowStatus(Status("Unknown property type received.", OrtErrorCode::ORT_INVALID_ARGUMENT)); } diff --git a/orttraining/orttraining/training_api/module.cc b/orttraining/orttraining/training_api/module.cc index 0987e87dd8202..d1775e358163c 100644 --- a/orttraining/orttraining/training_api/module.cc +++ b/orttraining/orttraining/training_api/module.cc @@ -12,7 +12,6 @@ #include "core/graph/graph_utils.h" #include "orttraining/training_api/checkpoint.h" -#include "orttraining/training_api/utils.h" using namespace onnxruntime; @@ -25,6 +24,7 @@ namespace { // TODO: consolidate with frontend tooling const std::string ACCUMULATE_GRAD_CONTROL_INPUT_NAME{"lazy_reset_grad"}; +#if !defined(ORT_MINIMAL_BUILD) std::unordered_set GetReverseReachableNodes(Graph& inference_graph, InlinedVector& output_node_args) { // Perform a graph traversal from the graph outputs to collect all reachable nodes from the outputs @@ -116,7 +116,7 @@ Status TransformModelInputsForInference(Graph& inference_graph, return Status::OK(); } - +#endif } // namespace Status Parameter::SetGrad(const std::string& gradient_name, const OrtValue& param_grad) { @@ -149,16 +149,16 @@ Status Parameter::ResetGrad() { return Status::OK(); } -Module::Module(const std::string& train_model_path_or_bytes, +Module::Module(const ModelIdentifiers& model_identifiers, CheckpointState* state, const onnxruntime::SessionOptions& session_options, const Environment& env, const std::vector>& providers, - const std::optional& eval_model_path_or_bytes) + [[maybe_unused]] gsl::span op_domains) : state_{state} { // Enforce weight prepacking is disabled - // If user explicitly enabled weight prepacking then return error. - // Default value is enabled. Therefore, explicitly disable it if the value is not set by user. + // If the user explicitly enabled weight prepacking then return an error. + // Default value is enabled. Therefore, explicitly disable it if the value is not set by the user. std::string disable_prepacking = ""; if (session_options.config_options.TryGetConfigEntry(kOrtSessionOptionsConfigDisablePrepacking, disable_prepacking)) { ORT_ENFORCE(disable_prepacking == "1", "Prepacking is not supported for training scenarios."); @@ -168,7 +168,18 @@ Module::Module(const std::string& train_model_path_or_bytes, } train_sess_ = std::make_unique(session_options, env); - ORT_THROW_IF_ERROR(train_sess_->Load(train_model_path_or_bytes)); +#if !defined(ORT_MINIMAL_BUILD) || defined(ORT_MINIMAL_BUILD_CUSTOM_OPS) + if (!op_domains.empty()) { + ORT_THROW_IF_ERROR(train_sess_->AddCustomOpDomains(op_domains)); + } +#endif + + // Load the training model + ORT_THROW_IF_ERROR(std::holds_alternative(model_identifiers.train_model) + ? train_sess_->Load(std::get(model_identifiers.train_model)) + : train_sess_->Load(std::get>(model_identifiers.train_model).data(), + static_cast(std::get>(model_identifiers.train_model).size()))); + for (const auto& provider : providers) { ORT_THROW_IF_ERROR(train_sess_->RegisterExecutionProvider(provider)); } @@ -178,12 +189,12 @@ Module::Module(const std::string& train_model_path_or_bytes, state_->module_checkpoint_state.train_session_data_transfer_mgr = &train_sess_->GetDataTransferManager(); // Extract model input and output names - std::vector train_input_names, train_output_names; + InlinedVector train_input_names, train_output_names; utils::GetGraphInputOutputNames(train_sess_, train_input_names, train_output_names); // Reorder the extracted input names in the following order: // user inputs, weights, gradients, reset_grad - std::vector user_input_names, param_input_names, grad_input_names, reset_grad_name; + InlinedVector user_input_names, param_input_names, grad_input_names, reset_grad_name; std::unordered_map param_name_to_grad_input_index_map; for (const auto& input_name : train_input_names) { @@ -214,13 +225,13 @@ Module::Module(const std::string& train_model_path_or_bytes, } } - // Loop each parameter, allocate it's memory based on user specified device. + // Loop each parameter, and allocate its memory based on the user-specified device. auto& train_sess_state = train_sess_->GetSessionState(); for (auto& param_name : param_input_names) { auto params_iter = state_->module_checkpoint_state.named_parameters.find(param_name); ORT_ENFORCE(params_iter != state_->module_checkpoint_state.named_parameters.end()); - // Retrieve the target device for "param_name" + // Retrieve the target device for "param_name". InlinedVector node_info_vec; ORT_THROW_IF_ERROR(train_sess_state.GetInputNodeInfo(param_name, node_info_vec)); const auto& node_info = node_info_vec.front(); @@ -229,14 +240,12 @@ Module::Module(const std::string& train_model_path_or_bytes, ORT_ENFORCE(target_device == *(it->device), "Inconsistent device requirements found for input: ", param_name); } - // TODO(pengwa): consider whether we should alloc contiguous buffer for parameters or gradients. // Copy ortvalue buffer from CPU to target_device for this "param_name" (based on graph partitioning) - // Only copies data if target device is not the same as the current device the buffer is placed on - + // Only copies data if the target device is not the same as the current device the buffer is placed on OrtValue& param_data = params_iter->second->Data(); ORT_ENFORCE(param_data.IsTensor()); const Tensor& param_data_tensor = param_data.Get(); - // If the source device type is already same as target device skip copy + // If the source device type is already the same as target device skip copy if (param_data_tensor.Location().device.Type() != target_device.Type()) { // TODO: move this outside of the for loop? auto target_allocator = train_sess_state.GetAllocator(target_device); @@ -257,7 +266,7 @@ Module::Module(const std::string& train_model_path_or_bytes, if (params_iter->second->RequiresGrad()) { // Create gradient accumulation buffer. auto it = param_name_to_grad_input_index_map.find(param_name); - ORT_ENFORCE(it != param_name_to_grad_input_index_map.end(), "Gradient buffer input not providered for param: ", + ORT_ENFORCE(it != param_name_to_grad_input_index_map.end(), "Gradient buffer input not provided for param: ", param_name); const size_t grad_input_index = it->second; @@ -265,47 +274,63 @@ Module::Module(const std::string& train_model_path_or_bytes, // TODO: don't pre-allocate the gradient buffer. // Gradient usually stays on the same device of its parameter. OrtValue param_grad; - ORT_THROW_IF_ERROR(utils::OrtValueLike(train_sess_state, param_data, param_grad)); + ORT_THROW_IF_ERROR(utils::CreateZeroValuedOrtValueLike(train_sess_state, param_data, param_grad)); ORT_THROW_IF_ERROR(params_iter->second->SetGrad(param_grad_name, param_grad)); gradients_[grad_input_index] = params_iter->second->Gradient(); } } - if (eval_model_path_or_bytes.has_value()) { + if (model_identifiers.IsEvalModelAvailable()) { eval_sess_ = std::make_unique(session_options, env); - ORT_THROW_IF_ERROR(eval_sess_->Load(eval_model_path_or_bytes.value())); - for (const auto& provider : providers) { - ORT_THROW_IF_ERROR(eval_sess_->RegisterExecutionProvider(provider)); +#if !defined(ORT_MINIMAL_BUILD) || defined(ORT_MINIMAL_BUILD_CUSTOM_OPS) + if (!op_domains.empty()) { + ORT_THROW_IF_ERROR(eval_sess_->AddCustomOpDomains(op_domains)); } - ORT_THROW_IF_ERROR(eval_sess_->Initialize()); - utils::GetGraphInputOutputNames(eval_sess_, eval_input_names_, eval_output_names_); - - // Eval model validation - // We are making certain assumptions: Like the order in which parameters occur will be same between train and eval - // graphs, and all the weights present in both graphs match. - // TODO: Add the checks instead of making assumptions?? - std::vector eval_user_input_names, eval_param_input_names; - for (const auto& input_name : eval_input_names_) { - if (state_->module_checkpoint_state.named_parameters.find(input_name) != - state_->module_checkpoint_state.named_parameters.end()) { - // it is a parameter - eval_param_input_names.emplace_back(input_name); - continue; - } else { - // It is a user input. We handle user inputs separately in eval - // because eval graph might have different user inputs. - // Eg if loss is not a part of eval graph, it won't have - // certain inputs like targets - eval_user_input_names.emplace_back(input_name); - } +#endif + if (std::holds_alternative>(model_identifiers.eval_model)) { + ORT_THROW_IF_ERROR(eval_sess_->Load(std::get>(model_identifiers.eval_model).value())); + } else { + auto model_data = std::get>(model_identifiers.eval_model); + ORT_THROW_IF_ERROR(eval_sess_->Load(model_data.data(), static_cast(model_data.size()))); } - eval_input_names_ = eval_user_input_names; - eval_user_input_count_ = eval_user_input_names.size(); - eval_input_names_.insert(eval_input_names_.end(), eval_param_input_names.begin(), eval_param_input_names.end()); + } else { + return; + } - // Keep a copy of the eval model path to be able to later export the model for inferencing. - // The inference model will be reconstructed from the eval model. - eval_model_path_ = eval_model_path_or_bytes.value(); + for (const auto& provider : providers) { + ORT_THROW_IF_ERROR(eval_sess_->RegisterExecutionProvider(provider)); + } + ORT_THROW_IF_ERROR(eval_sess_->Initialize()); + utils::GetGraphInputOutputNames(eval_sess_, eval_input_names_, eval_output_names_); + + // Eval model validation + // We are making certain assumptions: Like the order in which parameters occur will be same between train and eval + // graphs, and all the weights present in both graphs match. + // TODO(askhade): Add the checks instead of making assumptions?? + InlinedVector eval_user_input_names, eval_param_input_names; + for (const auto& input_name : eval_input_names_) { + if (state_->module_checkpoint_state.named_parameters.find(input_name) != + state_->module_checkpoint_state.named_parameters.end()) { + // it is a parameter + eval_param_input_names.emplace_back(input_name); + continue; + } else { + // It is user input. We handle user inputs separately in the eval + // because the eval graph might have different user inputs. + // Eg if loss is not a part of the eval graph, it won't have + // certain inputs like targets + eval_user_input_names.emplace_back(input_name); + } + } + eval_input_names_ = eval_user_input_names; + eval_user_input_count_ = eval_user_input_names.size(); + eval_input_names_.insert(eval_input_names_.end(), eval_param_input_names.begin(), eval_param_input_names.end()); + + // Keep a copy of the eval model path to be able to later export the model for inferencing. + // The inference model will be reconstructed from the eval model. + // TODO(askhade): Find a fix to export model for inference when the eval model is loaded from a buffer. + if (std::holds_alternative>(model_identifiers.eval_model)) { + eval_model_path_ = std::get>(model_identifiers.eval_model); } } @@ -451,8 +476,7 @@ Status Module::TrainStep(const std::vector& inputs, std::vector(!accumulate_gradient_, &reset_grad_input); feeds.push_back(reset_grad_input); - auto status = train_sess_->Run(RunOptions(), train_input_names_, feeds, train_output_names_, &outputs); - ORT_THROW_IF_ERROR(status); + ORT_THROW_IF_ERROR(train_sess_->Run(RunOptions(), train_input_names_, feeds, train_output_names_, &outputs)); // Reset the flag after every step. In case the ResetGrad was called before running // the current step, it will have done the effective resetting during the @@ -471,13 +495,17 @@ Status Module::EvalStep(const std::vector& inputs, std::vector graph_output_names) const { - ORT_RETURN_IF(!eval_sess_ || eval_model_path_.empty(), + ORT_RETURN_IF(!eval_sess_ || !eval_model_path_.has_value(), "Eval model was not provided. Cannot export a model for inferencing."); ONNX_NAMESPACE::ModelProto eval_model; - ORT_THROW_IF_ERROR(Model::Load(ToPathString(eval_model_path_), eval_model)); + ORT_THROW_IF_ERROR(Model::Load(ToPathString(eval_model_path_.value()), eval_model)); // Clone the eval mode into an inference onnxruntime::Model. std::shared_ptr inference_model; @@ -492,11 +520,11 @@ Status Module::ExportModelForInferencing(const std::string& inference_model_path ORT_RETURN_IF_ERROR(TransformModelInputsForInference(inference_model->MainGraph(), state_->module_checkpoint_state.named_parameters, eval_sess_->GetDataTransferManager())); - // Save the model at desired location. + // Save the model at the desired location. ORT_THROW_IF_ERROR(Model::Save(*inference_model, inference_model_path)); - return Status::OK(); } +#endif size_t Module::GetTrainingModelInputCount() const noexcept { return train_user_input_count_; @@ -520,6 +548,14 @@ std::string Module::GetEvalModelInputName(size_t index) const { return eval_input_names_.at(index); } +std::pair Module::GetTrainingModelInputs() const noexcept { + return train_sess_->GetModelInputs(); +} + +std::pair Module::GetEvalModelInputs() const noexcept { + return eval_sess_->GetModelInputs(); +} + } // namespace api } // namespace training } // namespace onnxruntime diff --git a/orttraining/orttraining/training_api/module.h b/orttraining/orttraining/training_api/module.h index 71f7659e8e74e..adb633343263e 100644 --- a/orttraining/orttraining/training_api/module.h +++ b/orttraining/orttraining/training_api/module.h @@ -3,7 +3,9 @@ #pragma once +#include #include "core/session/inference_session.h" +#include "orttraining/training_api/utils.h" namespace onnxruntime { namespace training { @@ -54,16 +56,32 @@ struct ModuleCheckpointState { struct CheckpointState; +/** + * @brief Module class for running training forward and backward. + * + * This class is responsible for running forward and backward. + * It does NOT own the parameters but only holds a weak reference to the passed + * 'CheckpointState' in the constructor. + * + * During initialization, if the Parameter (stored in `CheckpointState`)'s + * device does not match the target device, it will re-create the tensor on the + * target device and update the Parameter's data in place. The 'target device' + * is extracted from node placement. + * + * Currently, we only support load checkpoints from the constructor; + * no public API to load state dict after Module instance is created. + */ struct Module { public: // Initialize a module from an ORT inference session with loaded // training ONNX model and load parameters - Module(const std::string& train_model_path_or_bytes, + // The model and checkpoint state can be provided as a file path or a byte array + Module(const ModelIdentifiers& model_identifiers, CheckpointState* state, const onnxruntime::SessionOptions& session_options, const Environment& env, const std::vector>& providers, - const std::optional& eval_model_path_or_bytes = std::nullopt); + gsl::span op_domains = gsl::span()); // Return the trainable/nontrainable parameters std::vector> Parameters() const; @@ -102,10 +120,12 @@ struct Module { // Copy parameter values from contiguous buffer held by parameters_buffer onto parameters Status CopyBufferToParameters(OrtValue& parameters_buffer, const bool trainable_only = true); +#if !defined(ORT_MINIMAL_BUILD) // Load the eval model from eval_model_path_or_bytes and transform it for the purpose of // inferencing, and serialize to given path Status ExportModelForInferencing(const std::string& inference_model_path, gsl::span graph_output_names) const; +#endif // Returns the user input count for training graph size_t GetTrainingModelInputCount() const noexcept; @@ -119,21 +139,31 @@ struct Module { // Returns the user input name for eval graph at given index std::string GetEvalModelInputName(size_t index) const; + // Returns the input definitions of the Training model + std::pair GetTrainingModelInputs() const noexcept; + + // Returns the input definitions of the Eval model + std::pair GetEvalModelInputs() const noexcept; + private: std::unique_ptr train_sess_{nullptr}; std::unique_ptr eval_sess_{nullptr}; - std::vector train_input_names_; - std::vector train_output_names_; - std::vector eval_input_names_; - std::vector eval_output_names_; - std::vector weight_names_; - std::vector weights_; - std::vector gradients_; - bool accumulate_gradient_ = false; + + InlinedVector train_input_names_; + InlinedVector train_output_names_; + InlinedVector eval_input_names_; + InlinedVector eval_output_names_; + InlinedVector weight_names_; + + InlinedVector weights_; + InlinedVector gradients_; + CheckpointState* state_; // Non owning pointer to the state. - std::string eval_model_path_; - size_t train_user_input_count_ = 0U; - size_t eval_user_input_count_ = 0U; + + bool accumulate_gradient_ = false; + std::optional eval_model_path_; + size_t train_user_input_count_{0U}; + size_t eval_user_input_count_{0U}; }; } // namespace api diff --git a/orttraining/orttraining/training_api/onnxruntime_training_c_api.cc b/orttraining/orttraining/training_api/onnxruntime_training_c_api.cc index 286c38196efc9..6693bba348648 100644 --- a/orttraining/orttraining/training_api/onnxruntime_training_c_api.cc +++ b/orttraining/orttraining/training_api/onnxruntime_training_c_api.cc @@ -6,12 +6,15 @@ #include "core/framework/error_code_helper.h" #include "core/framework/random_seed.h" #include "core/session/abi_session_options_impl.h" +#include "core/session/onnxruntime_session_options_config_keys.h" #include "core/session/ort_apis.h" #include "core/session/ort_env.h" #include "orttraining/training_api/checkpoint.h" #include "orttraining/training_api/ort_training_apis.h" #include "orttraining/training_api/training_session.h" +using namespace onnxruntime::training::api; + namespace { std::vector> CreateProviders( @@ -25,40 +28,85 @@ std::vector> CreateProviders( return execution_providers; } +static OrtStatus* CreateSessionAndLoadModel(_In_ const OrtEnv* env, _In_ const OrtSessionOptions* options, + _Inout_ OrtCheckpointState* checkpoint_state, + const ModelIdentifiers& model_identifiers, + std::unique_ptr& train_sess) { + auto chkpt_state = reinterpret_cast(checkpoint_state); + + using ProvidersType = std::vector>; + train_sess = std::make_unique(env->GetEnvironment(), + options == nullptr ? onnxruntime::SessionOptions() : options->value, + options == nullptr + ? ProvidersType() + : CreateProviders(options->provider_factories), + chkpt_state, + model_identifiers, + options == nullptr + ? gsl::span() + : options->custom_op_domains_); + + return nullptr; +} + } // namespace ORT_API_STATUS_IMPL(OrtTrainingApis::CreateTrainingSession, _In_ const OrtEnv* env, _In_ const OrtSessionOptions* options, _Inout_ OrtCheckpointState* checkpoint_state, _In_ const ORTCHAR_T* train_model_path, _In_ const ORTCHAR_T* eval_model_path, - _In_ const ORTCHAR_T* optimizer_model_path, _Outptr_ OrtTrainingSession** out) { + _In_ const ORTCHAR_T* optimizer_model_path, _Outptr_result_maybenull_ OrtTrainingSession** out) { API_IMPL_BEGIN + if (options != nullptr && options->value.config_options.GetConfigOrDefault(kOrtSessionOptionsConfigUseEnvAllocators, "0") == "1") { + return OrtApis::CreateStatus(ORT_NOT_IMPLEMENTED, "Use Env Allocators is not supported for on device training."); + } std::unique_ptr train_sess; - auto chkpt_state = reinterpret_cast(checkpoint_state); OrtStatus* status = nullptr; *out = nullptr; - ORT_TRY { - using ProvidersType = std::vector>; - train_sess = std::make_unique( - env->GetEnvironment(), - options == nullptr ? onnxruntime::SessionOptions() : options->value, - options == nullptr ? ProvidersType() : CreateProviders(options->provider_factories), - chkpt_state, - onnxruntime::training::api::ModelIdentifiers( - onnxruntime::ToUTF8String(train_model_path), - eval_model_path ? std::optional(onnxruntime::ToUTF8String(eval_model_path)) - : std::nullopt, - optimizer_model_path ? std::optional(onnxruntime::ToUTF8String(optimizer_model_path)) - : std::nullopt)); - - *out = reinterpret_cast(train_sess.release()); - } - ORT_CATCH(const std::exception& e) { - ORT_HANDLE_EXCEPTION([&]() { - status = OrtApis::CreateStatus(ORT_FAIL, e.what()); - }); - } + ORT_ENFORCE(train_model_path != nullptr, + "Train model path is required to create TrainingSession, it cannot be empty."); + + auto model_identifiers = onnxruntime::training::api::ModelIdentifiers( + onnxruntime::ToUTF8String(train_model_path), + eval_model_path ? std::optional(onnxruntime::ToUTF8String(eval_model_path)) + : std::nullopt, + optimizer_model_path ? std::optional(onnxruntime::ToUTF8String(optimizer_model_path)) + : std::nullopt); + + ORT_API_RETURN_IF_ERROR(CreateSessionAndLoadModel(env, options, checkpoint_state, model_identifiers, train_sess)); + *out = reinterpret_cast(train_sess.release()); + + return status; + API_IMPL_END +} + +ORT_API_STATUS_IMPL(OrtTrainingApis::CreateTrainingSessionFromBuffer, _In_ const OrtEnv* env, + _In_ const OrtSessionOptions* options, _Inout_ OrtCheckpointState* checkpoint_state, + _In_ const void* train_model_data, size_t train_data_length, + _In_ const void* eval_model_data, size_t eval_data_length, + _In_ const void* optim_model_data, size_t optim_data_length, + _Outptr_result_maybenull_ OrtTrainingSession** out) { + API_IMPL_BEGIN + std::unique_ptr train_sess; + OrtStatus* status = nullptr; + *out = nullptr; + ORT_ENFORCE(train_model_data != nullptr && train_data_length != 0, + "Training Session Creation failed. Train model data cannot be NULL."); + + auto model_identifiers = ModelIdentifiers(gsl::make_span(reinterpret_cast(train_model_data), + train_data_length), + eval_data_length == 0 || eval_model_data == nullptr + ? gsl::span() + : gsl::make_span(reinterpret_cast(eval_model_data), + eval_data_length), + optim_data_length == 0 || optim_model_data == nullptr + ? gsl::span() + : gsl::make_span(reinterpret_cast(optim_model_data), + optim_data_length)); + + ORT_API_RETURN_IF_ERROR(CreateSessionAndLoadModel(env, options, checkpoint_state, model_identifiers, train_sess)); + *out = reinterpret_cast(train_sess.release()); return status; API_IMPL_END } @@ -281,6 +329,22 @@ ORT_API_STATUS_IMPL(OrtTrainingApis::SaveCheckpoint, _In_ OrtCheckpointState* ch API_IMPL_END } +ORT_API_STATUS_IMPL(OrtTrainingApis::LoadCheckpointFromBuffer, _In_ const void* checkpoint_buffer, + _In_ const size_t num_bytes, _Outptr_ OrtCheckpointState** checkpoint_state) { + API_IMPL_BEGIN + + *checkpoint_state = nullptr; + auto chkpt_state = std::make_unique(); + const auto* checkpoint_bytes = reinterpret_cast(checkpoint_buffer); + gsl::span checkpoint_span(checkpoint_bytes, num_bytes); + ORT_API_RETURN_IF_STATUS_NOT_OK( + onnxruntime::training::api::LoadCheckpointFromBuffer(checkpoint_span, *chkpt_state)); + *checkpoint_state = reinterpret_cast(chkpt_state.release()); + + return nullptr; + API_IMPL_END +} + ORT_API_STATUS_IMPL(OrtTrainingApis::GetParametersSize, _Inout_ OrtTrainingSession* sess, _Out_ size_t* out, bool trainable_only) { API_IMPL_BEGIN @@ -329,6 +393,9 @@ ORT_API_STATUS_IMPL(OrtTrainingApis::ExportModelForInferencing, _Inout_ OrtTrain _In_reads_(graph_outputs_len) const char* const* graph_output_names) { API_IMPL_BEGIN + OrtStatus* status = nullptr; + +#if !defined(ORT_MINIMAL_BUILD) if (graph_outputs_len == 0U) { return OrtApis::CreateStatus( ORT_INVALID_ARGUMENT, @@ -350,8 +417,16 @@ ORT_API_STATUS_IMPL(OrtTrainingApis::ExportModelForInferencing, _Inout_ OrtTrain ORT_API_RETURN_IF_STATUS_NOT_OK( session->ExportModelForInferencing(onnxruntime::ToUTF8String(inference_model_path), output_names)); +#else + ORT_UNUSED_PARAMETER(sess); + ORT_UNUSED_PARAMETER(inference_model_path); + ORT_UNUSED_PARAMETER(graph_outputs_len); + ORT_UNUSED_PARAMETER(graph_output_names); + status = OrtApis::CreateStatus(ORT_NOT_IMPLEMENTED, + "Inference model cannot be exported in a minimal training build."); +#endif - return nullptr; + return status; API_IMPL_END } @@ -491,6 +566,7 @@ static constexpr OrtTrainingApi ort_training_api = { &OrtTrainingApis::LoadCheckpoint, &OrtTrainingApis::SaveCheckpoint, &OrtTrainingApis::CreateTrainingSession, + &OrtTrainingApis::CreateTrainingSessionFromBuffer, &OrtTrainingApis::TrainingSessionGetTrainingModelOutputCount, &OrtTrainingApis::TrainingSessionGetEvalModelOutputCount, &OrtTrainingApis::TrainingSessionGetTrainingModelOutputName, @@ -516,7 +592,7 @@ static constexpr OrtTrainingApi ort_training_api = { &OrtTrainingApis::TrainingSessionGetEvalModelInputName, &OrtTrainingApis::AddProperty, &OrtTrainingApis::GetProperty, -}; + &OrtTrainingApis::LoadCheckpointFromBuffer}; ORT_API(const OrtTrainingApi*, OrtTrainingApis::GetTrainingApi, uint32_t) { // No constraints on the API version yet. diff --git a/orttraining/orttraining/training_api/optimizer.cc b/orttraining/orttraining/training_api/optimizer.cc index 2008e4c7c3a48..7f583ce8f6e76 100644 --- a/orttraining/orttraining/training_api/optimizer.cc +++ b/orttraining/orttraining/training_api/optimizer.cc @@ -2,6 +2,7 @@ // Licensed under the MIT License. #include "orttraining/training_api/optimizer.h" +#include "core/flatbuffers/flatbuffers_utils.h" #include "core/framework/execution_provider.h" #include "core/framework/TensorSeq.h" #include "core/providers/cpu/cpu_execution_provider.h" @@ -17,23 +18,11 @@ namespace api { namespace { -// Currently all parameters are in a single group, so we hardcode group0 here. constexpr char GROUP_ZERO_NAME[] = "group0"; - -// TODO: don't hard code the state names, should get the state names according to the optimizer types. -// TODO: Consolidate with frontend tooling -const std::vector MOMENT_STATE_NAMES{"momentum0", "momentum1"}; - -constexpr std::array AdamWOptimizerInputs = { - "learning_rate", - "step", - "params", - "gradients", - "first_order_moments", - "second_order_moments"}; +static constexpr std::array CommonOptimizerInputs{"learning_rate", "step", "params", "gradients"}; Status GraphInputsAreExpected(gsl::span actual_graph_inputs, - gsl::span expected_graph_inputs) { + gsl::span expected_graph_inputs) { const auto stringify = [](const auto& container) { if (container.empty()) { return std::string("[]"); @@ -71,103 +60,227 @@ Status GraphInputsAreExpected(gsl::span actual_graph_inputs, } // namespace -Status Optimizer::GenerateMomentumNamedStates() { +std::unique_ptr OptimizerAlorithmFactory::CreateInstance( + std::shared_ptr model, int32_t& group_count) { + std::map, int32_t> opt_type_to_freq_map; +#if !defined(ORT_MINIMAL_BUILD) + if (model != nullptr) { + Graph& graph = model->MainGraph(); + for (auto& node : graph.Nodes()) { + if (node.Domain() == kMSDomain && (node.OpType() == "AdamWOptimizer" || node.OpType() == "SGDOptimizerV2")) { + auto domain_type_pair = std::make_pair(node.Domain(), node.OpType()); + if (opt_type_to_freq_map.find(domain_type_pair) == opt_type_to_freq_map.end()) { + opt_type_to_freq_map[domain_type_pair] = 0; + } + + opt_type_to_freq_map[domain_type_pair] += 1; + } + } + } else { +#else + ORT_UNUSED_PARAMETER(model); +#endif + // TODO(baijumeswani): Figure out the best way to extract the optimizer type + // from the model (either onnx model or ort format model) or from the checkpoint. + // For now, assume that the optimizer type is AdamWOptimizer when using ort format models. + opt_type_to_freq_map[std::make_pair(kMSDomain, "AdamWOptimizer")] = 1; +#if !defined(ORT_MINIMAL_BUILD) + } +#endif + + ORT_ENFORCE(opt_type_to_freq_map.size() == 1U, "Only support one type of optimizer algorithm, but got: " + + std::to_string(opt_type_to_freq_map.size())); + auto opt_it = opt_type_to_freq_map.begin(); + auto& op_type = opt_it->first.second; + group_count = opt_it->second; + ORT_ENFORCE(group_count == 1, "Group count can only be 1, but got: " + std::to_string(group_count)); + + // TODO: to support multiple groups, need to create a mapping between each group to its parameter list. + if (op_type == "AdamWOptimizer") { + return std::make_unique(); + } else if (op_type == "SGDOptimizerV2") { + return std::make_unique(); + } else { + ORT_NOT_IMPLEMENTED("Not implemented for optimizer algo: " + opt_it->first.second); + } +} + +std::unique_ptr OptimizerAlorithmFactory::CreateInstance( + const PathString& optim_path, int32_t& group_count) { + std::shared_ptr model = nullptr; +#if !defined(ORT_MINIMAL_BUILD) + if (!fbs::utils::IsOrtFormatModel(optim_path)) { + ORT_ENFORCE(Model::Load(optim_path, model, nullptr, + logging::LoggingManager::DefaultLogger()) + .IsOK()); + } +#else + ORT_UNUSED_PARAMETER(optim_path); +#endif + return CreateInstance(model, group_count); +} + +std::unique_ptr OptimizerAlorithmFactory::CreateInstance( + const uint8_t* optim_model_data, size_t optim_model_data_len, int32_t& group_count) { + std::shared_ptr model = nullptr; +#if !defined(ORT_MINIMAL_BUILD) + if (!fbs::utils::IsOrtFormatModelBytes(optim_model_data, static_cast(optim_model_data_len))) { + ONNX_NAMESPACE::ModelProto model_proto; + ORT_ENFORCE(model_proto.ParseFromArray(optim_model_data, static_cast(optim_model_data_len)) == true, + "Failed to load model because protobuf parsing failed."); + + ORT_ENFORCE(Model::Load(std::move(model_proto), model, nullptr, + logging::LoggingManager::DefaultLogger(), ModelOptions(true, true)) + .IsOK()); + } +#else + ORT_UNUSED_PARAMETER(optim_model_data); + ORT_UNUSED_PARAMETER(optim_model_data_len); +#endif + + return CreateInstance(model, group_count); +} + +Status Optimizer::GenerateMomentumNamedStates(OptimizerCheckpointState& optimizer_checkpoint_states) { + auto group_optimizer_state_it = + optimizer_checkpoint_states.group_named_optimizer_states.find(GROUP_ZERO_NAME); + ORT_ENFORCE(group_optimizer_state_it != optimizer_checkpoint_states.group_named_optimizer_states.end(), + "Group 0 not found in the optimizer checkpoint states."); + + optimizer_state_ = group_optimizer_state_it->second; + auto& param_named_optimizer_states = optimizer_state_->param_named_optimizer_states; auto& optim_sess_state = optim_sess_->GetSessionState(); for (auto& pair : state_->module_checkpoint_state.named_parameters) { if (pair.second->RequiresGrad()) { param_named_optimizer_states.insert({pair.first, ParameterOptimizerState()}); ParameterOptimizerState& cur_param_optimizer_states = param_named_optimizer_states[pair.first]; - for (auto& state_name : MOMENT_STATE_NAMES) { + for (auto& state_name : optimizer_algo_ptr_->momentum_keys) { OrtValue param_state; - ORT_ENFORCE(utils::OrtValueLike(optim_sess_state, pair.second->Data(), param_state).IsOK(), + ORT_ENFORCE(utils::CreateZeroValuedOrtValueLike(optim_sess_state, pair.second->Data(), param_state).IsOK(), "Error generating moment state for ", pair.first); - cur_param_optimizer_states.momentum_named_states.insert({state_name, std::move(param_state)}); + cur_param_optimizer_states.insert({state_name, std::move(param_state)}); } } } + return Status::OK(); } // Constructs the ortvalue inputs to be fed to the graph at each step Status Optimizer::ConstructInputs() { - if (optimizer_type_ == OptimizerType::AdamW) { - auto& param_named_optimizer_states = optimizer_state_->param_named_optimizer_states; - - std::vector params, grads, first_order_moments, second_order_moments; - - // Collect all the non user defined inputs from the state_->module_checkpoint_state.named_parameters. - for (auto& [parameter_name, parameter] : state_->module_checkpoint_state.named_parameters) { - if (parameter->RequiresGrad()) { - // Collect parameters and prepare for tensorseq creation - auto* param_tensor = parameter->Data().GetMutable(); - params.emplace_back( - Tensor(param_tensor->DataType(), param_tensor->Shape(), - param_tensor->MutableDataRaw(), param_tensor->Location())); - - // Collect gradients and prepare for tensorseq creation - auto* grad_tensor = parameter->Gradient().GetMutable(); - grads.emplace_back( - Tensor(grad_tensor->DataType(), grad_tensor->Shape(), - grad_tensor->MutableDataRaw(), grad_tensor->Location())); - - // Collect first order moments and prepare for tensorseq creation - auto* first_order_moment_tensor = param_named_optimizer_states.at(parameter_name) - .momentum_named_states.at(MOMENT_STATE_NAMES[0]) - .GetMutable(); - first_order_moments.emplace_back( - Tensor(first_order_moment_tensor->DataType(), first_order_moment_tensor->Shape(), - first_order_moment_tensor->MutableDataRaw(), first_order_moment_tensor->Location())); - - // Collect second order moments and prepare for tensorseq creation - auto* second_order_moment_tensor = param_named_optimizer_states.at(parameter_name) - .momentum_named_states.at(MOMENT_STATE_NAMES[1]) - .GetMutable(); - second_order_moments.emplace_back( - Tensor(second_order_moment_tensor->DataType(), second_order_moment_tensor->Shape(), - second_order_moment_tensor->MutableDataRaw(), second_order_moment_tensor->Location())); + inputs_.clear(); + + auto& param_named_optimizer_states = optimizer_state_->param_named_optimizer_states; + + InlinedVector params, grads; + InlinedVector> list_of_momentums; + list_of_momentums.resize(optimizer_algo_ptr_->momentum_keys.size()); + + // Collect all the non-user-defined inputs from the named_parameters_. + for (auto& [parameter_name, parameter] : state_->module_checkpoint_state.named_parameters) { + if (parameter->RequiresGrad()) { + // Collect parameters and prepare for tensorseq creation + auto* param_tensor = parameter->Data().GetMutable(); + params.emplace_back( + Tensor(param_tensor->DataType(), param_tensor->Shape(), + param_tensor->MutableDataRaw(), param_tensor->Location())); + + // Collect gradients and prepare for tensorseq creation + auto* grad_tensor = parameter->Gradient().GetMutable(); + grads.emplace_back( + Tensor(grad_tensor->DataType(), grad_tensor->Shape(), + grad_tensor->MutableDataRaw(), grad_tensor->Location())); + + // Collect moments and prepare for tensorseq creation + for (size_t m_index = 0; m_index < optimizer_algo_ptr_->momentum_keys.size(); ++m_index) { + auto* moment_tensor = + param_named_optimizer_states.at(parameter_name) + .at(optimizer_algo_ptr_->momentum_keys[m_index]) + .GetMutable(); + list_of_momentums[m_index].emplace_back( + Tensor(moment_tensor->DataType(), moment_tensor->Shape(), + moment_tensor->MutableDataRaw(), moment_tensor->Location())); } } + } - const auto tensorseq_inserter = [](auto& tensors, auto* inputs) { - ORT_ENFORCE(!tensors.empty(), "Tensors vector cannot be empty while building a tensor sequence."); + const auto tensorseq_inserter = [](auto& tensors, auto* inputs) { + ORT_ENFORCE(!tensors.empty(), "Tensors vector cannot be empty while building a tensor sequence."); - auto tensor_seq = std::make_unique(tensors.front().DataType()); - tensor_seq->Reserve(tensors.size()); - for (auto& tensor : tensors) { - tensor_seq->Add(std::move(tensor)); - } - inputs->emplace_back( - OrtValue(tensor_seq.release(), DataTypeImpl::GetType(), - DataTypeImpl::GetType()->GetDeleteFunc())); - }; - - // Add the params and moments as tensorseq ortvalues to inputs - tensorseq_inserter(params, &inputs_); - tensorseq_inserter(grads, &inputs_); - tensorseq_inserter(first_order_moments, &inputs_); - tensorseq_inserter(second_order_moments, &inputs_); + auto tensor_seq = std::make_unique(tensors.front().DataType()); + tensor_seq->Reserve(tensors.size()); + for (auto& tensor : tensors) { + tensor_seq->Add(std::move(tensor)); + } + inputs->emplace_back( + OrtValue(tensor_seq.release(), DataTypeImpl::GetType(), + DataTypeImpl::GetType()->GetDeleteFunc())); + }; + + // Add the params/grads as tensorseq ortvalues to inputs + tensorseq_inserter(params, &inputs_); + tensorseq_inserter(grads, &inputs_); + // Add all other momentums as tensorseq ortvalues to inputs. + for (auto& m : list_of_momentums) { + tensorseq_inserter(m, &inputs_); } - // Add other optimizer reordering logic here + return Status::OK(); -} +} // namespace api -Optimizer::Optimizer(const std::string& optim_path_or_bytes, +Optimizer::Optimizer(const ModelIdentifiers& model_identifiers, CheckpointState* state, const onnxruntime::SessionOptions& session_options, const Environment& env, - const std::vector>& providers) + const std::vector>& providers, + gsl::span op_domains) : optim_sess_(std::make_unique(session_options, env)), state_(state) { - if (state_->optimizer_checkpoint_state.group_named_optimizer_states.empty()) { - state_->optimizer_checkpoint_state.group_named_optimizer_states.insert( - {GROUP_ZERO_NAME, std::make_shared()}); + Initialize(model_identifiers, providers, op_domains); + + ORT_ENFORCE(state != nullptr, "Checkpoint state cannot be null."); + auto g_it = state_->optimizer_checkpoint_state.group_named_optimizer_states.find(GROUP_ZERO_NAME); + bool find_group_zero = g_it != state_->optimizer_checkpoint_state.group_named_optimizer_states.end(); + if (!find_group_zero || g_it->second->param_named_optimizer_states.empty()) { + if (!find_group_zero) + state_->optimizer_checkpoint_state.group_named_optimizer_states.insert( + {GROUP_ZERO_NAME, std::make_shared()}); + ORT_THROW_IF_ERROR(GenerateMomentumNamedStates(state_->optimizer_checkpoint_state)); + ORT_THROW_IF_ERROR(ConstructInputs()); + } else { + ORT_THROW_IF_ERROR(LoadStateDict(state_->optimizer_checkpoint_state)); } - optimizer_state_ = state_->optimizer_checkpoint_state.group_named_optimizer_states.at(GROUP_ZERO_NAME); +} + +void Optimizer::Initialize(const ModelIdentifiers& model_identifiers, + const std::vector>& providers, + [[maybe_unused]] gsl::span op_domains) { +#if !defined(ORT_MINIMAL_BUILD) || defined(ORT_MINIMAL_BUILD_CUSTOM_OPS) + if (!op_domains.empty()) { + ORT_THROW_IF_ERROR(optim_sess_->AddCustomOpDomains(op_domains)); + } +#endif + for (const auto& execution_provider : providers) { ORT_THROW_IF_ERROR(optim_sess_->RegisterExecutionProvider(execution_provider)); } - ORT_THROW_IF_ERROR(optim_sess_->Load(optim_path_or_bytes)); + ORT_ENFORCE(model_identifiers.IsOptimizerModelAvailable(), "Optimizer model is not available."); + + if (std::holds_alternative>(model_identifiers.optim_model)) { + auto optimizer_model = std::get>(model_identifiers.optim_model); + // The above call to IsOptimizerModelAvailable() ensures that optimizer_model is not nullopt + ORT_THROW_IF_ERROR(optim_sess_->Load(optimizer_model.value())); + optimizer_algo_ptr_ = OptimizerAlorithmFactory::CreateInstance(ToWideString(optimizer_model.value()), group_count_); + } else { + auto optimizer_model = std::get>(model_identifiers.optim_model); + ORT_THROW_IF_ERROR(optim_sess_->Load(optimizer_model.data(), + static_cast(optimizer_model.size()))); + optimizer_algo_ptr_ = OptimizerAlorithmFactory::CreateInstance(optimizer_model.data(), + optimizer_model.size(), + group_count_); + } + ORT_THROW_IF_ERROR(optim_sess_->Initialize()); // Make sure that the checkpoint state can copy tensors @@ -175,14 +288,13 @@ Optimizer::Optimizer(const std::string& optim_path_or_bytes, utils::GetGraphInputOutputNames(optim_sess_, input_names_, output_names_); - if (optimizer_type_ == OptimizerType::AdamW) { - ORT_THROW_IF_ERROR(GraphInputsAreExpected(input_names_, AdamWOptimizerInputs)); - - ORT_THROW_IF_ERROR(GenerateMomentumNamedStates()); - } else { - ORT_THROW("Unsupported optimizer type"); - } - ORT_THROW_IF_ERROR(ConstructInputs()); + InlinedVector all_input_names; + all_input_names.reserve(CommonOptimizerInputs.size() + optimizer_algo_ptr_->optimizer_states_inputs.size()); + all_input_names.insert(all_input_names.end(), CommonOptimizerInputs.begin(), + CommonOptimizerInputs.end()); + all_input_names.insert(all_input_names.end(), optimizer_algo_ptr_->optimizer_states_inputs.begin(), + optimizer_algo_ptr_->optimizer_states_inputs.end()); + ORT_THROW_IF_ERROR(GraphInputsAreExpected(input_names_, all_input_names)); } Status Optimizer::Step() { @@ -190,7 +302,7 @@ Status Optimizer::Step() { utils::WrapInOrtValue(optimizer_state_->learning_rate, &learning_rate_input); // Use step count + 1 before running optimizer step. // This is necessary since bias correction uses the step - // as a power. Using power of 0 is wrong. + // as a power. Using the power of 0 is wrong. utils::WrapInOrtValue(optimizer_state_->step + 1, &step_input); std::vector feeds({learning_rate_input, step_input}); feeds.insert(feeds.end(), inputs_.begin(), inputs_.end()); @@ -199,37 +311,67 @@ Status Optimizer::Step() { auto status = optim_sess_->Run(RunOptions(), input_names_, feeds, output_names_, &outputs); ORT_THROW_IF_ERROR(status); - // extract step output and update - if (utils::GetValue(outputs[0]) == 1LL) { + // Extract step output and update + if (utils::GetScalarFromOrtValue(outputs[0]) == true) { optimizer_state_->step++; } return Status::OK(); } -Status Optimizer::GetStateDict(OptimizerCheckpointState& optimizer_checkpoint_state) { - auto& grouped_optimizer_states = optimizer_checkpoint_state.group_named_optimizer_states; +Status Optimizer::LoadStateDict(OptimizerCheckpointState& optimizer_checkpoint_states) { + auto group_optimizer_state_it = + optimizer_checkpoint_states.group_named_optimizer_states.find(GROUP_ZERO_NAME); + ORT_ENFORCE(group_optimizer_state_it != optimizer_checkpoint_states.group_named_optimizer_states.end(), + "Group 0 not found in the optimizer checkpoint states."); - // To support multiple groups, Optimizer constructor need accept informations for groupping. - grouped_optimizer_states.insert({GROUP_ZERO_NAME, std::make_shared(*optimizer_state_)}); + optimizer_state_ = group_optimizer_state_it->second; + constexpr bool strict_match = true; - // Pass the optimizer session data transfer manager for data copying when saving. - // An alternative is, we can do copy at this stage. ORT_RETURN_IF_NOT(optim_sess_, "optimizer session not initialized"); - const DataTransferManager& sess_data_transfer_manager = optim_sess_->GetDataTransferManager(); - optimizer_checkpoint_state.optimizer_session_data_transfer_mgr = &sess_data_transfer_manager; - return Status::OK(); -} + auto& optim_sess_state = optim_sess_->GetSessionState(); + auto& param_named_optimizer_states = optimizer_state_->param_named_optimizer_states; -Status Optimizer::LoadStateDict(const OptimizerCheckpointState& optimizer_checkpoint_states) { - auto group_optimizer_state_it = - optimizer_checkpoint_states.group_named_optimizer_states.find(GROUP_ZERO_NAME); - ORT_ENFORCE(group_optimizer_state_it != optimizer_checkpoint_states.group_named_optimizer_states.cend(), - "Group 0 not found in the optimizer checkpoint states."); - optimizer_state_->initial_lr = group_optimizer_state_it->second->initial_lr; - optimizer_state_->step = group_optimizer_state_it->second->step; + for (auto& params_iter : state_->module_checkpoint_state.named_parameters) { + if (params_iter.second->RequiresGrad()) { + bool src_exist = param_named_optimizer_states.find(params_iter.first) != + param_named_optimizer_states.cend(); + + ORT_ENFORCE(src_exist || !strict_match, "Parameter ", params_iter.first, + " not found in the source optimizer checkpoint states."); + + InlinedHashMap& momentum_named_states = + param_named_optimizer_states.at(params_iter.first); + + OrtValue& param_data = params_iter.second->Data(); + ORT_ENFORCE(param_data.IsTensor()); + const Tensor& param_data_tensor = param_data.Get(); + const auto& param_data_device = param_data_tensor.Location().device; + auto target_allocator = optim_sess_state.GetAllocator(param_data_device); + ORT_ENFORCE(target_allocator != nullptr); + + for (auto& momentum_state_pair : momentum_named_states) { + OrtValue& param_momentum = momentum_state_pair.second; + ORT_ENFORCE(param_momentum.IsTensor()); + const Tensor& param_momentum_tensor = param_momentum.Get(); + + // If the source device type is already the same as the target device skip copy. + if (param_momentum_tensor.Location().device.Type() != param_data_device.Type()) { + // Create a new tensor on the target_device and switch the source_ortvalue to point to this new tensor + auto target_tensor = std::make_unique(param_momentum_tensor.DataType(), + param_momentum_tensor.Shape(), + target_allocator); + ORT_THROW_IF_ERROR(optim_sess_state.GetDataTransferMgr().CopyTensor(param_momentum_tensor, + *target_tensor.get())); + auto ml_tensor_type = DataTypeImpl::GetType(); + param_momentum.Init(target_tensor.release(), ml_tensor_type, ml_tensor_type->GetDeleteFunc()); + } + } + } + } + + ORT_THROW_IF_ERROR(ConstructInputs()); - // TODO(pengwa): restore the momentums state from checkpoint. return Status::OK(); } diff --git a/orttraining/orttraining/training_api/optimizer.h b/orttraining/orttraining/training_api/optimizer.h index 4c28a600bad2c..d9bc4870bb7ed 100644 --- a/orttraining/orttraining/training_api/optimizer.h +++ b/orttraining/orttraining/training_api/optimizer.h @@ -2,6 +2,7 @@ // Licensed under the MIT License. #pragma once + #include "core/providers/cpu/cpu_execution_provider.h" #include "core/session/inference_session.h" #include "core/session/environment.h" @@ -18,18 +19,19 @@ namespace api { * For Adam optimizer, it looks like: * { "moment_0": OrtValue, "moment_1": OrtValue,}. */ -struct ParameterOptimizerState { - std::unordered_map momentum_named_states; -}; +typedef InlinedHashMap ParameterOptimizerState; /** * @brief States belong to one specific group of trainable Parameters. */ struct GroupOptimizerState { int64_t step = 0; - float initial_lr = 0.001f; // Default value used in torch AdamW - float learning_rate{initial_lr}; // Adaptive learning rate as training proceeds. - std::unordered_map param_named_optimizer_states; + float initial_lr = 0.001f; // Default value used in torch AdamW + + // Adaptive learning rate as training proceeds. Be noted, learning_rate can be + // restored by lr scheduler from given step and initial_lr, though, we still save/load this in checkpoint. + float learning_rate{initial_lr}; + InlinedHashMap param_named_optimizer_states; }; /** @@ -39,18 +41,57 @@ struct GroupOptimizerState { */ struct OptimizerCheckpointState { public: - std::unordered_map> group_named_optimizer_states; + InlinedHashMap> group_named_optimizer_states; const DataTransferManager* optimizer_session_data_transfer_mgr; }; -enum class OptimizerType { - AdamW, - // More optimizers can be added later as: - // Lamb, +struct OptimizerAlgorithmBase { + OptimizerAlgorithmBase(const InlinedVector& momentum_keys, + const InlinedVector& optimizer_states_inputs) + : momentum_keys(momentum_keys), optimizer_states_inputs(optimizer_states_inputs) {} + InlinedVector momentum_keys; + InlinedVector optimizer_states_inputs; +}; + +struct AdamWOptimizerAlgorithm : public OptimizerAlgorithmBase { + AdamWOptimizerAlgorithm() : OptimizerAlgorithmBase({"momentum0", "momentum1"}, + {"first_order_moments", "second_order_moments"}) {} +}; + +struct SGDOptimizerV2Algorithm : public OptimizerAlgorithmBase { + SGDOptimizerV2Algorithm() : OptimizerAlgorithmBase({"momentum0"}, + {"first_order_moments"}) {} +}; + +struct OptimizerAlorithmFactory { + static std::unique_ptr CreateInstance(const PathString& optim_path, + int32_t& group_count); + static std::unique_ptr CreateInstance(const uint8_t* optim_model_data, + size_t optim_model_data_len, int32_t& group_count); + static std::unique_ptr CreateInstance(std::shared_ptr model, int32_t& group_count); }; struct CheckpointState; +/** + * @brief Optimizer class for running gradient updates. + * + * This class is responsible for running gradient updates on the parameters. + * > It does NOT own the parameters, and will not modify the "named_parameters" in `CheckpointState` + * passed from the constructor. + * A tensor sequence is created based on the "named_parameters" to construct parameter input (of type tensorseq). + * > If 'optimizer_checkpoint_states' is provided in the constructor as part of `CheckpointState`. + * Optimizer will reuse the data buffer from the passed in 'optimizer_checkpoint_states'. + * >> If the device of momentums in 'optimizer_checkpoint_states' is not + * matching its parameter device, a copy will be done during the 'LoadStateDict', + * but reserving using the original OrtValue with the copied data buffer; + * >> Otherwise, it generates the optimizer state initialized as all zeros and owns them. + * > If 'optimizer_checkpoint_states' is not provided in the constructor as part of `CheckpointState`. + * The optimizer states are initialized as all zeros on the same device of corresponding parameters. + * + * Currently, we only support load checkpoints from the constructor; + * no public API to load state dict after Optimizer instance is created. + */ struct Optimizer { friend struct LRSchedulerBase; @@ -58,18 +99,15 @@ struct Optimizer { // Initialize an optimizer module from an ORT inference session with loaded // training ONNX model For each parameter, initialize the OptimizerState based // on the graph input's ValueInfoProto if the parameter doesn't have it already. - Optimizer(const std::string& optim_path_or_bytes, + Optimizer(const ModelIdentifiers& model_identifiers, CheckpointState* state, const onnxruntime::SessionOptions& session_options, const Environment& env, - const std::vector>& providers); + const std::vector>& providers, + gsl::span op_domains = gsl::span()); Status Step(); - Status GetStateDict(OptimizerCheckpointState& optimizer_checkpoint_states); - - Status LoadStateDict(const OptimizerCheckpointState& optimizer_checkpoint_states); - Status SetLearningRate(float lr) { optimizer_state_->learning_rate = lr; return Status::OK(); @@ -86,24 +124,42 @@ struct Optimizer { } private: + void Initialize(const ModelIdentifiers& model_identifiers, + const std::vector>& providers, + gsl::span op_domains); + int64_t GetStep() const { return optimizer_state_->step; } - // Generates optimizer momentum states for applicable optimizer types - Status GenerateMomentumNamedStates(); + // Generates optimizer momentum states for parameters that require grad. + Status GenerateMomentumNamedStates(OptimizerCheckpointState& optimizer_checkpoint_states); // Constructs the ortvalue inputs to be fed to the graph - // at each step + // at each step. Status ConstructInputs(); - // TODO: load this info from checkpoint - OptimizerType optimizer_type_ = OptimizerType::AdamW; + /** + * @brief Load states from optimizer_checkpoint_states into current optimizer state. + * + * Be noted Optimizer will reuse the data buffer of passed in optimizer_checkpoint_states. + * If the device of momentums in optimizer_checkpoint_states is not matching its parameter device, + * an implicit copy will be done during the LoadStateDict, but reserving using the original OrtValue + * with the copied data buffer. + * @return Status + */ + Status LoadStateDict(OptimizerCheckpointState& optimizer_checkpoint_states); + + std::unique_ptr optimizer_algo_ptr_; std::unique_ptr optim_sess_; - CheckpointState* state_; // Non owning pointer to the state. + + CheckpointState* state_; // Non owning pointer to the state std::shared_ptr optimizer_state_; - std::vector input_names_; - std::vector output_names_; - std::vector inputs_; + + InlinedVector input_names_; + InlinedVector output_names_; + InlinedVector inputs_; + + int32_t group_count_{0}; }; } // namespace api diff --git a/orttraining/orttraining/training_api/ort_training_apis.h b/orttraining/orttraining/training_api/ort_training_apis.h index 3f8edede36f02..c87108957c975 100644 --- a/orttraining/orttraining/training_api/ort_training_apis.h +++ b/orttraining/orttraining/training_api/ort_training_apis.h @@ -8,7 +8,14 @@ ORT_API(const OrtTrainingApi*, GetTrainingApi, uint32_t version); ORT_API_STATUS_IMPL(CreateTrainingSession, _In_ const OrtEnv* env, _In_ const OrtSessionOptions* options, _Inout_ OrtCheckpointState* checkpoint_state, _In_ const ORTCHAR_T* train_model_path, _In_ const ORTCHAR_T* eval_model_path, _In_ const ORTCHAR_T* optimizer_model_path, - _Outptr_ OrtTrainingSession** out); + _Outptr_result_maybenull_ OrtTrainingSession** out); + +ORT_API_STATUS_IMPL(CreateTrainingSessionFromBuffer, _In_ const OrtEnv* env, + _In_ const OrtSessionOptions* options, _Inout_ OrtCheckpointState* checkpoint_state, + _In_ const void* train_model_data, size_t train_data_length, + _In_ const void* eval_model_data, size_t eval_data_length, + _In_ const void* optim_model_data, size_t optim_data_length, + _Outptr_result_maybenull_ OrtTrainingSession** out); ORT_API_STATUS_IMPL(TrainingSessionGetTrainingModelOutputCount, _In_ const OrtTrainingSession* sess, _Out_ size_t* out); @@ -84,4 +91,7 @@ ORT_API_STATUS_IMPL(GetProperty, _In_ const OrtCheckpointState* checkpoint_state _In_ const char* property_name, _Inout_ OrtAllocator* allocator, _Out_ enum OrtPropertyType* property_type, _Outptr_ void** property_value); +ORT_API_STATUS_IMPL(LoadCheckpointFromBuffer, _In_ const void* checkpoint_buffer, + _In_ const size_t num_bytes, _Outptr_ OrtCheckpointState** checkpoint_state); + } // namespace OrtTrainingApis diff --git a/orttraining/orttraining/training_api/training_session.cc b/orttraining/orttraining/training_api/training_session.cc index 8332558f9aea7..45f0f0ddcf7f4 100644 --- a/orttraining/orttraining/training_api/training_session.cc +++ b/orttraining/orttraining/training_api/training_session.cc @@ -2,22 +2,22 @@ // Licensed under the MIT License. #include "orttraining/training_api/training_session.h" +#include "orttraining/training_api/utils.h" -namespace onnxruntime { -namespace training { -namespace api { +namespace onnxruntime::training::api { TrainingSession::TrainingSession(const Environment& session_env, const SessionOptions& session_options, const std::vector>& providers, CheckpointState* state, - const ModelIdentifiers& model_identifiers) + const ModelIdentifiers& model_identifiers, + gsl::span custom_op_domains) : state_{state}, - module_{std::make_unique(model_identifiers.train_model, state_, - session_options, session_env, providers, model_identifiers.eval_model)}, - optimizer_{model_identifiers.optim_model.has_value() + module_{std::make_unique(model_identifiers, state_, + session_options, session_env, providers, custom_op_domains)}, + optimizer_{model_identifiers.IsOptimizerModelAvailable() ? std::make_unique( - model_identifiers.optim_model.value(), state_, + model_identifiers, state_, session_options, session_env, providers) : std::unique_ptr()} {} @@ -115,11 +115,11 @@ Status TrainingSession::CopyBufferToParameters(OrtValue& parameters_buffer, cons return module_->CopyBufferToParameters(parameters_buffer, trainable_only); } +#if !defined(ORT_MINIMAL_BUILD) Status TrainingSession::ExportModelForInferencing(const std::string& inference_model_path, gsl::span graph_output_names) const { return module_->ExportModelForInferencing(inference_model_path, graph_output_names); } +#endif -} // namespace api -} // namespace training -} // namespace onnxruntime +} // namespace onnxruntime::training::api diff --git a/orttraining/orttraining/training_api/training_session.h b/orttraining/orttraining/training_api/training_session.h index 2e7f06055fd19..13b0ae79093de 100644 --- a/orttraining/orttraining/training_api/training_session.h +++ b/orttraining/orttraining/training_api/training_session.h @@ -3,25 +3,17 @@ #pragma once #include "core/common/common.h" -#include "module.h" -#include "optimizer.h" -#include "lr_scheduler.h" -#include "checkpoint.h" +#include "orttraining/training_api/module.h" +#include "orttraining/training_api/optimizer.h" +#include "orttraining/training_api/lr_scheduler.h" +#include "orttraining/training_api/checkpoint.h" +#include "orttraining/training_api/utils.h" namespace onnxruntime { namespace training { namespace api { using namespace common; -struct ModelIdentifiers { - const std::string train_model; - const std::optional eval_model, optim_model; - ModelIdentifiers(const std::string& train_model_uri, - const std::optional& eval_model_uri, - const std::optional& optim_model_uri) - : train_model(train_model_uri), eval_model(eval_model_uri), optim_model(optim_model_uri) {} -}; - // Wrapper on top of module and optimizer classes and is the only class exposed via capis class TrainingSession { public: @@ -29,7 +21,8 @@ class TrainingSession { const SessionOptions& session_options, const std::vector>& providers, CheckpointState* state, - const ModelIdentifiers& model_identifiers); + const ModelIdentifiers& model_identifiers, + gsl::span custom_op_domains = gsl::span()); Status RegisterScheduler(const std::function< std::unique_ptr(std::shared_ptr)>& get_scheduler, @@ -75,8 +68,10 @@ class TrainingSession { Status CopyBufferToParameters(OrtValue& parameters_buffer, const bool trainable_only = true); +#if !defined(ORT_MINIMAL_BUILD) Status ExportModelForInferencing(const std::string& inference_model_path, gsl::span graph_output_names) const; +#endif private: ORT_DISALLOW_COPY_ASSIGNMENT_AND_MOVE(TrainingSession); diff --git a/orttraining/orttraining/training_api/utils.cc b/orttraining/orttraining/training_api/utils.cc index e719c48bea8f7..6a00aa229b9df 100644 --- a/orttraining/orttraining/training_api/utils.cc +++ b/orttraining/orttraining/training_api/utils.cc @@ -19,9 +19,9 @@ namespace utils { const std::vector GRAD_SUFFIX{"_grad.accumulation.buffer", "_grad", "_grad.accumulation.out"}; void GetGraphInputOutputNames(const std::unique_ptr& session_object, - std::vector& input_names, - std::vector& output_names) { - auto get_names = [](const std::vector* node_args, std::vector& names) { + InlinedVector& input_names, + InlinedVector& output_names) { + auto get_names = [](const std::vector* node_args, InlinedVector& names) { ORT_ENFORCE(nullptr != node_args); for (const auto* arg : *node_args) { names.push_back(arg->Name()); @@ -57,7 +57,7 @@ bool GetParamNameFromGradient(const std::string& grad_name, std::string& param_n return false; } -Status OrtValueLike(const SessionState& sess_state, const OrtValue& input_val, OrtValue& output_val) { +Status CreateZeroValuedOrtValueLike(const SessionState& sess_state, const OrtValue& input_val, OrtValue& output_val) { const auto& param_tensor = input_val.template Get(); const TensorShape& shape = param_tensor.Shape(); auto& tensor_location = param_tensor.Location(); diff --git a/orttraining/orttraining/training_api/utils.h b/orttraining/orttraining/training_api/utils.h index 27391e596c746..f16f0f947fbd5 100644 --- a/orttraining/orttraining/training_api/utils.h +++ b/orttraining/orttraining/training_api/utils.h @@ -10,12 +10,46 @@ namespace onnxruntime { namespace training { namespace api { + +struct ModelIdentifiers { + // ModelIdentifiers struct enables an easy way to store and identify the models used for training, evaluation + // and model updates(optimizer model). + // The model can be specified by a path to the model file or by a span of bytes containing the model data. + // Training model is required, evaluation and optimizer models are optional. + std::variant> train_model; + std::variant, gsl::span> eval_model; + std::variant, gsl::span> optim_model; + + ModelIdentifiers(std::variant> training_model, + std::variant, gsl::span> evaluation_model, + std::variant, gsl::span> optimzer_model) + : train_model(training_model), eval_model(evaluation_model), optim_model(optimzer_model) {} + + bool IsModelAvailable(const std::variant, gsl::span>& model) const { + if ((std::holds_alternative>(model) && + std::get>(model).has_value()) || + (std::holds_alternative>(model) && + std::get>(model).size() > 0)) { + return true; + } + return false; + } + + bool IsEvalModelAvailable() const { + return IsModelAvailable(eval_model); + } + + bool IsOptimizerModelAvailable() const { + return IsModelAvailable(optim_model); + } +}; + namespace utils { // Get names of graph inputs and outputs void GetGraphInputOutputNames(const std::unique_ptr& session_object, - std::vector& input_names, - std::vector& output_names); + InlinedVector& input_names, + InlinedVector& output_names); // Fetch the parameter name from suffix: name = param_name+suffix, // returns True if suffix is present in name else False bool GetParamNameFromSuffix(const std::string& name, const std::string& suffix, std::string& param_name); @@ -25,7 +59,7 @@ bool GetParamNameFromSuffix(const std::string& name, const std::string& suffix, bool GetParamNameFromGradient(const std::string& grad_name, std::string& param_name); // Allocate OrtValue like the input ortvalue on the same device -Status OrtValueLike(const SessionState& sess_state, const OrtValue& input_val, OrtValue& output_val); +Status CreateZeroValuedOrtValueLike(const SessionState& sess_state, const OrtValue& input_val, OrtValue& output_val); // Create OrtValue from a single value of type T template @@ -34,7 +68,7 @@ void WrapInOrtValue(T value, AllocatorPtr alloc = nullptr) { static CPUExecutionProviderInfo info; static CPUExecutionProvider cpu_provider(info); - static AllocatorPtr cpu_allocator = cpu_provider.GetAllocator(OrtMemTypeDefault); + static AllocatorPtr cpu_allocator = cpu_provider.CreatePreferredAllocators()[0]; TensorShape shape({1}); auto element_type = DataTypeImpl::GetType(); @@ -48,8 +82,12 @@ void WrapInOrtValue(T value, } template -T GetValue(OrtValue& ort_value) { +T GetScalarFromOrtValue(OrtValue& ort_value) { const Tensor& tensor = ort_value.Get(); + const TensorShape& shape = tensor.Shape(); + size_t dim_count = shape.NumDimensions(); + // Be noted: TensorShape returns 1 for rank 0 tensor. + ORT_ENFORCE(shape.Size() == 1 && (dim_count == 0 || dim_count == 1)); T val; if (DataTypeImpl::GetType() == tensor.DataType()) { val = *(tensor.template Data()); diff --git a/orttraining/orttraining/training_ops/cpu/activation/activations_grad.cc b/orttraining/orttraining/training_ops/cpu/activation/activations_grad.cc index b7958961b7608..f42fa0c4dc984 100644 --- a/orttraining/orttraining/training_ops/cpu/activation/activations_grad.cc +++ b/orttraining/orttraining/training_ops/cpu/activation/activations_grad.cc @@ -148,7 +148,8 @@ Status BiasGeluGrad_dX::Compute(OpKernelContext* context auto* dX = context->Output(0, input_shape); ORT_ENFORCE(dX); - const auto input_size = input_shape.Size(), bias_size = bias_shape.Size(); + const auto input_size = narrow(input_shape.Size()), + bias_size = narrow(bias_shape.Size()); // X + B, broadcasting AllocatorPtr allocator; @@ -163,7 +164,7 @@ Status BiasGeluGrad_dX::Compute(OpKernelContext* context X_plus_B_array = X_array.colwise() + B_vector; // dX - const auto biased_X_span = gsl::make_span(X_plus_B_buffer.get(), X->Shape().Size()); + const auto biased_X_span = gsl::make_span(X_plus_B_buffer.get(), narrow(X->Shape().Size())); ORT_RETURN_IF_ERROR((ComputeGeluGradDX( dY->template DataAsSpan(), biased_X_span, dX->template MutableDataAsSpan(), GeluComputationMode{}))); diff --git a/orttraining/orttraining/training_ops/cpu/cpu_training_kernels.cc b/orttraining/orttraining/training_ops/cpu/cpu_training_kernels.cc index dda92fbb41cc4..e1e0e520bb444 100644 --- a/orttraining/orttraining/training_ops/cpu/cpu_training_kernels.cc +++ b/orttraining/orttraining/training_ops/cpu/cpu_training_kernels.cc @@ -53,6 +53,7 @@ class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, GeluG class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, SigmoidGrad); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, TanhGrad); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, QuickGeluGrad); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kMSDomain, 1, LeakyReluGrad); // REVIEW(mzs): ConstEigenVectorArrayMap.cast, // default entry to avoid the list become empty after ops-reducing BuildKernelCreateInfo, BuildKernelCreateInfo, @@ -179,6 +183,7 @@ Status RegisterCpuTrainingKernels(KernelRegistry& kernel_registry) { BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, + BuildKernelCreateInfo, // REVIEW(mzs): ConstEigenVectorArrayMap.cast, @@ -225,6 +230,10 @@ Status RegisterCpuTrainingKernels(KernelRegistry& kernel_registry) { kCpuExecutionProvider, kMSDomain, 1, float, LSTMTraining)>, BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, // the kernels within the following ifdef are not included in a build with // --enable_training_ops but without --enable_training @@ -257,7 +266,10 @@ Status RegisterCpuTrainingKernels(KernelRegistry& kernel_registry) { }; for (auto& function_table_entry : function_table) { - ORT_RETURN_IF_ERROR(kernel_registry.Register(function_table_entry())); + KernelCreateInfo info = function_table_entry(); + if (info.kernel_def != nullptr) { // filter disabled entries where type is void + ORT_RETURN_IF_ERROR(kernel_registry.Register(std::move(info))); + } } return Status::OK(); } diff --git a/orttraining/orttraining/training_ops/cpu/loss/cross_entropy.cc b/orttraining/orttraining/training_ops/cpu/loss/cross_entropy.cc index e2cdf238a0ccc..9aad7edf68bfa 100644 --- a/orttraining/orttraining/training_ops/cpu/loss/cross_entropy.cc +++ b/orttraining/orttraining/training_ops/cpu/loss/cross_entropy.cc @@ -6,7 +6,6 @@ #include "core/util/math_cpuonly.h" #include "core/providers/common.h" #include -#include "core/util/math.h" #include "core/providers/cpu/math/matmul_helper.h" #include "core/common/gsl.h" @@ -14,38 +13,38 @@ namespace onnxruntime { namespace contrib { template -void ComputeShareSoftmaxCrossEntropyCPU(const int n, - const int d, - const int nd, +void ComputeShareSoftmaxCrossEntropyCPU(const int nd, + const int c, + const Eigen::Index nd_c, const T* logit_data, T* shifted_logit, T* log_prob_data) { // Find the max in each batch, resulting in a tensor of shape [batch] // logit_max = max(logit_data) - std::vector logit_max(n); - math::RowwiseMax(n, d, logit_data, logit_max.data(), nullptr); + std::vector logit_max(nd); + math::RowwiseMax(nd, c, logit_data, logit_max.data(), nullptr); // Subtract the max in batch b from every element in batch b. // Broadcasts along the batch dimension. // shifted_logit = logit_data - logit_max - gsl::copy(gsl::make_span(logit_data, nd), gsl::make_span(shifted_logit, nd)); - math::SubToCol(n, d, logit_max.data(), shifted_logit, nullptr); + gsl::copy(gsl::make_span(logit_data, nd_c), gsl::make_span(shifted_logit, nd_c)); + math::SubToCol(nd, c, logit_max.data(), shifted_logit, nullptr); // exp_shifted_logit = exp(shifted_logit) - math::Exp(nd, shifted_logit, log_prob_data, nullptr); + math::Exp(nd_c, shifted_logit, log_prob_data, nullptr); // sum_exp = sum_{class} (exp_shifted_logit) float* sum_exp = logit_max.data(); - math::RowwiseSum(n, d, log_prob_data, sum_exp, nullptr); + math::RowwiseSum(nd, c, log_prob_data, sum_exp, nullptr); // log_sum_exp = log(sum_exp) float* log_sum_exp = sum_exp; - math::Log(n, sum_exp, log_sum_exp, nullptr); + math::Log(nd, sum_exp, log_sum_exp, nullptr); // log_prob = shifted_logit - log(sum_exp) // the subtraction broadcasts along the batch dimension - gsl::copy(gsl::make_span(shifted_logit, nd), gsl::make_span(log_prob_data, nd)); - math::SubToCol(n, d, log_sum_exp, log_prob_data, nullptr); + gsl::copy(gsl::make_span(shifted_logit, nd_c), gsl::make_span(log_prob_data, nd_c)); + math::SubToCol(nd, c, log_sum_exp, log_prob_data, nullptr); } ONNX_OPERATOR_KERNEL_EX( @@ -70,7 +69,7 @@ Status SoftmaxCrossEntropy::Compute(OpKernelContext* context) const { int64_t D = logit_shape[logit_shape.NumDimensions() - 1]; const int n = gsl::narrow_cast(N); const int d = gsl::narrow_cast(D); - const int nd = gsl::narrow_cast(N * D); + const ptrdiff_t nd = narrow(N * D); Tensor* loss = context->Output(0, TensorShape({})); Tensor* log_prob = context->Output(1, logit_shape); @@ -85,7 +84,9 @@ Status SoftmaxCrossEntropy::Compute(OpKernelContext* context) const { // probability = exp(shifted_logit) / sum(exp(shifted_logit)) // where shifted_logit = logit - max_logit // along classes - ComputeShareSoftmaxCrossEntropyCPU(n, d, nd, logit_data, + + ComputeShareSoftmaxCrossEntropyCPU(n, d, nd, + logit_data, shifted_logit.data(), log_prob_data); @@ -180,7 +181,7 @@ Status SparseSoftmaxCrossEntropy::Compute(OpKernelContext* context) const { int64_t D = logit_shape[logit_shape.NumDimensions() - 1]; const int n = gsl::narrow_cast(N); const int d = gsl::narrow_cast(D); - const int nd = gsl::narrow_cast(N * D); + const ptrdiff_t nd = narrow(N * D); Tensor* loss = context->Output(0, TensorShape({})); Tensor* log_prob = context->Output(1, logit_shape); @@ -192,6 +193,7 @@ Status SparseSoftmaxCrossEntropy::Compute(OpKernelContext* context) const { // computation begins here std::vector shifted_logit(nd); + ComputeShareSoftmaxCrossEntropyCPU(n, d, nd, logit_data, shifted_logit.data(), log_prob_data); diff --git a/orttraining/orttraining/training_ops/cpu/loss/cross_entropy.h b/orttraining/orttraining/training_ops/cpu/loss/cross_entropy.h index dd0d5750e0e95..4a180fa66e44b 100644 --- a/orttraining/orttraining/training_ops/cpu/loss/cross_entropy.h +++ b/orttraining/orttraining/training_ops/cpu/loss/cross_entropy.h @@ -5,6 +5,7 @@ #include "core/framework/op_kernel.h" #include "orttraining/training_ops/cpu/loss/reduction_type.h" +#include "core/util/math_cpuonly.h" namespace onnxruntime { namespace contrib { @@ -24,7 +25,7 @@ class LossBase : public OpKernel { template void ComputeShareSoftmaxCrossEntropyCPU(const int n, const int d, - const int nd, + const Eigen::Index nd, const T* logit_data, T* shifted_logit, T* log_prob_data); diff --git a/orttraining/orttraining/training_ops/cpu/loss/softmax_cross_entropy_loss.cc b/orttraining/orttraining/training_ops/cpu/loss/softmax_cross_entropy_loss.cc index c1b9865b53eb8..b3c04af1a2659 100644 --- a/orttraining/orttraining/training_ops/cpu/loss/softmax_cross_entropy_loss.cc +++ b/orttraining/orttraining/training_ops/cpu/loss/softmax_cross_entropy_loss.cc @@ -5,7 +5,6 @@ #include "core/util/math_cpuonly.h" #include "core/providers/common.h" #include -#include "core/util/math.h" #include "core/providers/cpu/math/matmul_helper.h" #include "core/providers/cpu/tensor/transpose.h" #include "core/providers/cpu/controlflow/scan_utils.h" @@ -113,8 +112,8 @@ Status SoftmaxCrossEntropyLoss::Compute(OpKernelContext* context) const VerifyLogitWeightAndLabelShape(logit_shape, label_shape, p_weight ? &p_weight->Shape() : nullptr); // N_D = N * D1 * D2...D*K - int64_t N_D; - int64_t C; + int64_t N_D = 0; + int64_t C = 0; GetNDCFromLogitAndLabelShape(logit_shape, label_shape, N_D, C); const T1* logit_data = logit.template Data(); OrtValue transpose_output; @@ -133,7 +132,7 @@ Status SoftmaxCrossEntropyLoss::Compute(OpKernelContext* context) const const int n_d = gsl::narrow_cast(N_D); const int c = gsl::narrow_cast(C); - const int n_d_c = gsl::narrow_cast(N_D * C); + const uint64_t n_d_c = N_D * C; Tensor* loss = context->Output(0, reduction_ == ReductionType::NONE ? TensorShape(label.Shape()) : TensorShape({})); T1* log_prob_data; std::vector log_prob_data_buffer(0); @@ -143,14 +142,16 @@ Status SoftmaxCrossEntropyLoss::Compute(OpKernelContext* context) const log_prob = context->Output(1, logit_shape); log_prob_data = log_prob->template MutableData(); } else { - log_prob_data_buffer.resize(logit_shape.Size()); + log_prob_data_buffer.resize(narrow(logit_shape.Size())); log_prob_data = log_prob_data_buffer.data(); } const T2* label_data = label.template Data(); T1* loss_data = loss->template MutableData(); - std::vector shifted_logit(n_d_c); - ComputeShareSoftmaxCrossEntropyCPU(n_d, c, n_d_c, logit_data, shifted_logit.data(), log_prob_data); + std::vector shifted_logit(narrow(n_d_c)); + ORT_ENFORCE(n_d_c <= static_cast(std::numeric_limits::max())); + ComputeShareSoftmaxCrossEntropyCPU(n_d, c, static_cast(n_d_c), logit_data, shifted_logit.data(), + log_prob_data); std::vector loss_sample_buffer(0); T1* loss_sample; if (reduction_ == ReductionType::NONE) { @@ -232,7 +233,7 @@ Status SoftmaxCrossEntropyLoss::Compute(OpKernelContext* context) const transpose_output.GetMutable()->Reshape(log_prob->Shape()); log_prob->Reshape(log_prob_shape); ORT_RETURN_IF_ERROR(TransposeBase::DoTranspose(permutations, *log_prob, *transpose_output.GetMutable())); - memcpy(log_prob_data, transposed_data, log_prob_shape.Size() * sizeof(T1)); + memcpy(log_prob_data, transposed_data, narrow(log_prob_shape.Size() * sizeof(T1))); log_prob->Reshape(new_shape); } @@ -260,17 +261,15 @@ Status SoftmaxCrossEntropyLossGrad::Compute(OpKernelContext* context) co VerifyLogitWeightAndLabelShape(probability_shape, label_shape, p_weight ? &p_weight->Shape() : nullptr); // N_D = N * D1 * D2...D*K - int64_t N_D; - int64_t C; + int64_t N_D = 0; + int64_t C = 0; GetNDCFromLogitAndLabelShape(probability_shape, label_shape, N_D, C); - const int n_d = gsl::narrow_cast(N_D); - const int c = gsl::narrow_cast(C); const T1* dY_data = dY.template Data(); const T1* log_prob_data = log_prob.template Data(); const T2* label_data = label.template Data(); Tensor* d_logit = context->Output(0, probability_shape); T1* d_logit_data = d_logit->template MutableData(); - std::memset(d_logit_data, 0, sizeof(T1) * n_d); + std::memset(d_logit_data, 0, narrow(sizeof(T1) * N_D)); OrtValue transpose_output; TensorShapeVector new_shape; std::vector permutations; @@ -285,90 +284,107 @@ Status SoftmaxCrossEntropyLossGrad::Compute(OpKernelContext* context) co log_prob_data = (*transpose_output.GetMutable()).template Data(); } - // REVIEW(codemzs): Use parallel for below. + static constexpr double cost = 1.0; + auto* tp = context->GetOperatorThreadPool(); if (p_weight) { const Tensor& weight = *p_weight; const T1* weight_data = weight.template Data(); if (reduction_ == ReductionType::NONE) { - for (int i = 0; i < n_d; i++) { - T2 label_sample = label_data[i]; - T1 weight_smaple = weight_data[label_sample] * dY_data[i]; - for (int j = 0; j < c; j++) { - int index = i * c + j; - if (ignore_index == label_sample) { - d_logit_data[index] = 0; - } else { - d_logit_data[index] = (exp(log_prob_data[index]) - (label_sample == j)) * weight_smaple; - } - } - } - + concurrency::ThreadPool::TryParallelFor( + tp, narrow(N_D * C), cost, + [&label_data, &weight_data, &d_logit_data, &log_prob_data, ignore_index, C, &dY_data]( + std::ptrdiff_t begin, std::ptrdiff_t end) { + for (std::ptrdiff_t index = begin; index != end; ++index) { + int64_t row = index / C; + int64_t col = index % C; + T2 label_sample = label_data[row]; + T1 weight_smaple = weight_data[label_sample] * dY_data[row]; + if (ignore_index == label_sample) { + d_logit_data[index] = 0; + } else { + d_logit_data[index] = (exp(log_prob_data[index]) - (label_sample == col)) * weight_smaple; + } + } + }); } else { T1 dY_scaled = *dY_data; if (reduction_ == ReductionType::MEAN) { - T1 sum_weight = (T1)0; - for (int i = 0; i < n_d; i++) { + double sum_weight = (double)0; + for (int64_t i = 0; i < N_D; i++) { if (ignore_index != label_data[i]) { sum_weight += weight_data[label_data[i]]; } } if (sum_weight != 0) { - dY_scaled = *dY_data / sum_weight; + dY_scaled = static_cast(*dY_data / sum_weight); } } - for (int i = 0; i < n_d; i++) { - T2 label_sample = label_data[i]; - T1 weight_smaple = weight_data[label_sample] * dY_scaled; - for (int j = 0; j < c; j++) { - int index = i * c + j; - if (ignore_index == label_sample) { - d_logit_data[index] = 0; - } else { - d_logit_data[index] = (exp(log_prob_data[index]) - (label_sample == j)) * weight_smaple; - } - } - } + concurrency::ThreadPool::TryParallelFor( + tp, narrow(N_D * C), cost, + [&label_data, &weight_data, dY_scaled, &d_logit_data, &log_prob_data, ignore_index, C]( + std::ptrdiff_t begin, std::ptrdiff_t end) { + for (std::ptrdiff_t index = begin; index != end; ++index) { + int64_t row = index / C; + int64_t col = index % C; + T2 label_sample = label_data[row]; + T1 weight_smaple = weight_data[label_sample] * dY_scaled; + if (ignore_index == label_sample) { + d_logit_data[index] = 0; + } else { + d_logit_data[index] = (exp(log_prob_data[index]) - (label_sample == col)) * weight_smaple; + } + } + }); } } else { if (reduction_ == ReductionType::NONE) { - for (int i = 0; i < n_d; i++) { - T2 label_sample = label_data[i]; - for (int j = 0; j < c; j++) { - int index = i * c + j; - if (ignore_index == label_sample) { - d_logit_data[index] = 0; - } else { - d_logit_data[index] = (exp(log_prob_data[index]) - (label_sample == j)) * dY_data[i]; - } - } - } + concurrency::ThreadPool::TryParallelFor( + tp, narrow(N_D * C), cost, + [&label_data, &d_logit_data, &log_prob_data, ignore_index, C, &dY_data]( + std::ptrdiff_t begin, std::ptrdiff_t end) { + for (std::ptrdiff_t index = begin; index != end; ++index) { + int64_t row = index / C; + int64_t col = index % C; + T2 label_sample = label_data[row]; + if (ignore_index == label_sample) { + d_logit_data[index] = 0; + } else { + d_logit_data[index] = (exp(log_prob_data[index]) - (label_sample == col)) * dY_data[row]; + } + } + }); + } else { T1 dY_scaled = *dY_data; - int unignored_sample_count = 0; - for (int i = 0; i < n_d; i++) { + uint64_t unignored_sample_count = 0; + for (int64_t i = 0; i < N_D; i++) { if (ignore_index != label_data[i]) { unignored_sample_count += 1; } } if ((reduction_ == ReductionType::MEAN) && (unignored_sample_count != 0)) { - dY_scaled = *dY_data / unignored_sample_count; + dY_scaled = static_cast(*dY_data / unignored_sample_count); } - for (int i = 0; i < n_d; i++) { - T2 label_sample = label_data[i]; - for (int j = 0; j < c; j++) { - int index = i * c + j; - if (ignore_index == label_sample) { - d_logit_data[index] = 0; - } else { - d_logit_data[index] = (exp(log_prob_data[index]) - (label_sample == j)) * dY_scaled; - } - } - } + concurrency::ThreadPool::TryParallelFor( + tp, narrow(N_D * C), cost, + [&label_data, &d_logit_data, &log_prob_data, ignore_index, C, &dY_scaled]( + std::ptrdiff_t begin, std::ptrdiff_t end) { + for (std::ptrdiff_t index = begin; index != end; ++index) { + int64_t row = index / C; + int64_t col = index % C; + T2 label_sample = label_data[row]; + if (ignore_index == label_sample) { + d_logit_data[index] = 0; + } else { + d_logit_data[index] = (exp(log_prob_data[index]) - (label_sample == col)) * dY_scaled; + } + } + }); } } @@ -382,7 +398,7 @@ Status SoftmaxCrossEntropyLossGrad::Compute(OpKernelContext* context) co d_logit->Reshape(logit_shape); ORT_RETURN_IF_ERROR(TransposeBase::DoTranspose(permutations, *d_logit, *transpose_output.GetMutable())); auto* transposed_data = (*transpose_output.GetMutable()).template Data(); - memcpy(d_logit_data, transposed_data, probability_shape.Size() * sizeof(T1)); + memcpy(d_logit_data, transposed_data, narrow(probability_shape.Size() * sizeof(T1))); d_logit->Reshape(new_shape); } @@ -391,9 +407,14 @@ Status SoftmaxCrossEntropyLossGrad::Compute(OpKernelContext* context) co if (p_bias) { ORT_ENFORCE(probability_shape.Size() == p_bias->Shape().Size()); const T1* bias_data = p_bias->Data(); - for (size_t i = 0; i < static_cast(probability_shape.Size()); ++i) { - d_logit_data[i] += bias_data[i]; - } + concurrency::ThreadPool::TryParallelFor( + tp, narrow(probability_shape.Size()), cost, + [&d_logit_data, &bias_data]( + std::ptrdiff_t begin, std::ptrdiff_t end) { + for (std::ptrdiff_t index = begin; index != end; ++index) { + d_logit_data[index] += bias_data[index]; + } + }); } return Status::OK(); diff --git a/orttraining/orttraining/training_ops/cpu/nn/batch_norm_grad.cc b/orttraining/orttraining/training_ops/cpu/nn/batch_norm_grad.cc index 65c9b66a8ec8a..23ce97ce55d95 100644 --- a/orttraining/orttraining/training_ops/cpu/nn/batch_norm_grad.cc +++ b/orttraining/orttraining/training_ops/cpu/nn/batch_norm_grad.cc @@ -2,6 +2,7 @@ // Licensed under the MIT License. #include "orttraining/training_ops/cpu/nn/batch_norm_grad.h" +#include "core/common/narrow.h" #include "core/util/math_cpuonly.h" #include "core/framework/op_kernel_context_internal.h" #include "core/providers/cpu/nn/batch_norm_helper.h" @@ -34,11 +35,11 @@ Status BatchNormalizationGrad::Compute(OpKernelContext* ctx) const { auto* dBias_data = ctx->Output(2, channel_shape)->template MutableData(); const auto& dims_vec = X_shape.GetDims(); - const size_t N = dims_vec[0]; - const size_t C = dims_vec[1]; // assume NCHW as per the spec + const size_t N = narrow(dims_vec[0]); + const size_t C = narrow(dims_vec[1]); // assume NCHW as per the spec // calculate sample_size (per individual channel) - size_t sample_size = X_shape.SizeFromDimension(2); + size_t sample_size = narrow(X_shape.SizeFromDimension(2)); size_t scale_tensor_size = C; ConstEigenVectorArrayMap scale_arr(scale_data, scale_tensor_size); diff --git a/orttraining/orttraining/training_ops/cpu/nn/broadcast_grad_args.cc b/orttraining/orttraining/training_ops/cpu/nn/broadcast_grad_args.cc index 9854dccdf2830..ee5cc7b15677c 100644 --- a/orttraining/orttraining/training_ops/cpu/nn/broadcast_grad_args.cc +++ b/orttraining/orttraining/training_ops/cpu/nn/broadcast_grad_args.cc @@ -3,6 +3,8 @@ #include "orttraining/training_ops/cpu/nn/broadcast_grad_args.h" +#include "core/common/narrow.h" + namespace onnxruntime { namespace contrib { #define REGISTER_KERNEL_TYPED(T) \ @@ -22,8 +24,8 @@ template Status BroadcastGradientArgs::Compute(OpKernelContext* context) const { const Tensor* a_shape = context->Input(0); const Tensor* b_shape = context->Input(1); - const T* A_dims = a_shape->template Data(); - const T* B_dims = b_shape->template Data(); + const auto A_dims = a_shape->template DataAsSpan(); + const auto B_dims = b_shape->template DataAsSpan(); const T a_size = a_shape->Shape().Size(); const T b_size = b_shape->Shape().Size(); @@ -36,8 +38,8 @@ Status BroadcastGradientArgs::Compute(OpKernelContext* context) const { T k = ndim - 1; for (; i >= 0 && j >= 0; --k) { - auto A_dim = A_dims[i], - B_dim = B_dims[j]; + auto A_dim = A_dims[narrow(i)], + B_dim = B_dims[narrow(j)]; if (A_dim != B_dim) { if (A_dim == 1) { @@ -45,8 +47,8 @@ Status BroadcastGradientArgs::Compute(OpKernelContext* context) const { } else if (B_dim == 1) { b_axes.push_back(k); } else { - TensorShape a(A_dims, a_size); - TensorShape b(B_dims, b_size); + TensorShape a(A_dims); + TensorShape b(B_dims); return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Broadcast is not possible between inputs of shapes: ", a, " and ", b); diff --git a/orttraining/orttraining/training_ops/cpu/nn/conv_grad.cc b/orttraining/orttraining/training_ops/cpu/nn/conv_grad.cc index 5598c68e46455..6c8d8390d24a1 100644 --- a/orttraining/orttraining/training_ops/cpu/nn/conv_grad.cc +++ b/orttraining/orttraining/training_ops/cpu/nn/conv_grad.cc @@ -16,6 +16,7 @@ /* Modifications Copyright (c) Microsoft. */ #include "orttraining/training_ops/cpu/nn/conv_grad.h" +#include "core/common/narrow.h" #include "core/util/math.h" #include "core/util/math_cpuonly.h" @@ -72,23 +73,24 @@ Status ConvGrad::Compute(OpKernelContext* context) const { AllocatorPtr alloc; ORT_RETURN_IF_ERROR(context->GetTempSpaceAllocator(&alloc)); - BufferUniquePtr col_buffer(alloc->Alloc(sizeof(T) * col_buffer_size), BufferDeleter(alloc)); + BufferUniquePtr col_buffer(alloc->Alloc(narrow(sizeof(T) * col_buffer_size)), BufferDeleter(alloc)); T* col_buffer_data = static_cast(col_buffer.get()); const T* Xdata = X->template Data(); const T* Wdata = W->template Data(); const T* dYdata = dY->template Data(); - BufferUniquePtr bias_multiplier(alloc->Alloc(sizeof(T) * output_image_size), BufferDeleter(alloc)); + BufferUniquePtr bias_multiplier(alloc->Alloc(narrow(sizeof(T) * output_image_size)), BufferDeleter(alloc)); T* bias_multiplier_data = nullptr; Tensor* dB = context->Output(2, {M}); T* dBdata = nullptr; if (dB) { dBdata = dB->template MutableData(); - math::Set(dB->Shape().Size(), static_cast(0), dBdata, &CPUMathUtil::Instance()); + math::Set(narrow(dB->Shape().Size()), + static_cast(0), dBdata, &CPUMathUtil::Instance()); bias_multiplier_data = static_cast(bias_multiplier.get()); - math::Set(output_image_size, + math::Set(narrow(output_image_size), static_cast(1), bias_multiplier_data, &CPUMathUtil::Instance()); @@ -98,7 +100,7 @@ Status ConvGrad::Compute(OpKernelContext* context) const { if (dW) { dWdata = dW->template MutableData(); // Pre-setting the gradients to zero. - math::Set(dW->Shape().Size(), 0, dWdata, &CPUMathUtil::Instance()); + math::Set(narrow(dW->Shape().Size()), 0, dWdata, &CPUMathUtil::Instance()); } bool skip_im2col = (kernel_size == 1) && conv_attrs_.HasStridesOneAndNoPadding(); @@ -159,9 +161,9 @@ Status ConvGrad::Compute(OpKernelContext* context) const { math::Gemm( CblasNoTrans, CblasTrans, - M / conv_attrs_.group, - kernel_dim, - output_image_size, + narrow(M / conv_attrs_.group), + narrow(kernel_dim), + narrow(output_image_size), 1, dYdata + group_id * Y_offset, skip_im2col ? Xdata + group_id * X_offset : col_buffer_data, @@ -197,9 +199,9 @@ Status ConvGrad::Compute(OpKernelContext* context) const { math::Gemm( CblasTrans, CblasNoTrans, - kernel_dim, - output_image_size, - M / conv_attrs_.group, + narrow(kernel_dim), + narrow(output_image_size), + narrow(M / conv_attrs_.group), 1, Wdata + group_id * W_offset, dYdata, diff --git a/orttraining/orttraining/training_ops/cpu/nn/dropout_7.cc b/orttraining/orttraining/training_ops/cpu/nn/dropout_7.cc index 0f04b96755695..0e0af6c85bd00 100644 --- a/orttraining/orttraining/training_ops/cpu/nn/dropout_7.cc +++ b/orttraining/orttraining/training_ops/cpu/nn/dropout_7.cc @@ -35,7 +35,7 @@ Status Dropout_7::Compute(OpKernelContext* context) const { void* target = Y.MutableDataRaw(X_type); if (target != source) { // If source and target pointers are not equal, we need to copy the data. - memcpy(target, source, shape.Size() * X_type->Size()); + memcpy(target, source, X.SizeInBytes()); } } else { float scale = 1.0f / keep_prob_; diff --git a/orttraining/orttraining/training_ops/cpu/nn/layer_norm.cc b/orttraining/orttraining/training_ops/cpu/nn/layer_norm.cc index 5749502792c96..b76af47f7fa56 100644 --- a/orttraining/orttraining/training_ops/cpu/nn/layer_norm.cc +++ b/orttraining/orttraining/training_ops/cpu/nn/layer_norm.cc @@ -49,10 +49,10 @@ Status LayerNormGrad::Compute(OpKernelContext* op_kernel_context) const Tensor* X = op_kernel_context->Input(input_index++); const auto& X_shape = X->Shape(); const auto axis = HandleNegativeAxis(axis_, X_shape.NumDimensions()); - ORT_ENFORCE(X_shape.SizeToDimension(axis) <= std::numeric_limits::max()); - ORT_ENFORCE(X_shape.SizeFromDimension(axis) <= std::numeric_limits::max()); - const auto N = static_cast(X_shape.SizeToDimension(axis)); - const auto M = static_cast(X_shape.SizeFromDimension(axis)); + ORT_ENFORCE(X_shape.SizeToDimension(gsl::narrow_cast(axis)) <= std::numeric_limits::max()); + ORT_ENFORCE(X_shape.SizeFromDimension(gsl::narrow_cast(axis)) <= std::numeric_limits::max()); + const auto N = static_cast(X_shape.SizeToDimension(gsl::narrow_cast(axis))); + const auto M = static_cast(X_shape.SizeFromDimension(gsl::narrow_cast(axis))); ORT_ENFORCE(M != 1); const Tensor* scale = op_kernel_context->Input(input_index++); @@ -139,10 +139,10 @@ Status InvertibleLayerNormGrad::Compute(OpKernelContext* op_kernel_context) c const auto& Y_shape = Y_grad->Shape(); const auto& X_shape = Y_shape; const auto axis = HandleNegativeAxis(axis_, X_shape.NumDimensions()); - ORT_ENFORCE(X_shape.SizeToDimension(axis) <= std::numeric_limits::max()); - ORT_ENFORCE(X_shape.SizeFromDimension(axis) <= std::numeric_limits::max()); - const auto N = static_cast(X_shape.SizeToDimension(axis)); - const auto M = static_cast(X_shape.SizeFromDimension(axis)); + ORT_ENFORCE(X_shape.SizeToDimension(gsl::narrow_cast(axis)) <= std::numeric_limits::max()); + ORT_ENFORCE(X_shape.SizeFromDimension(gsl::narrow_cast(axis)) <= std::numeric_limits::max()); + const auto N = static_cast(X_shape.SizeToDimension(gsl::narrow_cast(axis))); + const auto M = static_cast(X_shape.SizeFromDimension(gsl::narrow_cast(axis))); ORT_ENFORCE(M != 1); const auto& scale_shape = scale->Shape(); diff --git a/orttraining/orttraining/training_ops/cpu/nn/pool_gradient_op.cc b/orttraining/orttraining/training_ops/cpu/nn/pool_gradient_op.cc index eb580bc14839f..769b4d1bc2bd8 100644 --- a/orttraining/orttraining/training_ops/cpu/nn/pool_gradient_op.cc +++ b/orttraining/orttraining/training_ops/cpu/nn/pool_gradient_op.cc @@ -2,6 +2,7 @@ // Licensed under the MIT License. #include "orttraining/training_ops/cpu/nn/pool_gradient_op.h" +#include "core/common/narrow.h" #include "core/util/math_cpuonly.h" #include "core/providers/common.h" #include @@ -51,7 +52,7 @@ Status MaxPoolGrad::Compute(OpKernelContext* context) const { const int64_t* indices_data = indices->template Data(); T* dX_data = dX->template MutableData(); - EigenVectorMap(dX_data, dX_shape.Size()).setZero(); + EigenVectorMap(dX_data, narrow(dX_shape.Size())).setZero(); for (int64_t i = 0; i < dY->Shape().Size(); ++i) { T* p_dX_data = dX_data + indices_data[i]; @@ -85,27 +86,32 @@ Status AveragePoolGrad::Compute3DAveragePoolGrad(OpKernelContext* context) co int64_t dY_elements_in_each_channel = dY_shape[2] * dY_shape[3] * dY_shape[4]; for (int cur_channel = 0; cur_channel < channels; cur_channel++) { - ConstEigenArrayMap dY_arr = ConstEigenArrayMap(dY_data, dY_shape[3], dY_shape[2] * dY_shape[4]); - EigenArrayMap dX_arr = EigenArrayMap(dX_data, dX_shape[3], dX_shape[2] * dX_shape[4]); + ConstEigenArrayMap dY_arr = ConstEigenArrayMap(dY_data, narrow(dY_shape[3]), + narrow(dY_shape[2] * dY_shape[4])); + EigenArrayMap dX_arr = EigenArrayMap(dX_data, narrow(dX_shape[3]), + narrow(dX_shape[2] * dX_shape[4])); for (int d = 0; d < dY_shape[4]; ++d) { const int64_t p = std::max(d * stride_third_dim - pads_[2], 0); const int64_t a = std::min(d * stride_third_dim - pads_[2] + kernel_third_dim, dX_shape[4]); for (int h = 0; h < dY_shape[2]; ++h) { - const int64_t t = std::max(h * stride_first_dim - pads_[0], 0); - const int64_t b = std::min(h * stride_first_dim - pads_[0] + kernel_first_dim, dX_shape[2]); + const Eigen::Index t = narrow(std::max(h * stride_first_dim - pads_[0], 0)); + const Eigen::Index b = + narrow(std::min(h * stride_first_dim - pads_[0] + kernel_first_dim, dX_shape[2])); for (int w = 0; w < dY_shape[3]; ++w) { - const int64_t l = std::max(w * stride_second_dim - pads_[1], 0); - const int64_t r = std::min(w * stride_second_dim - pads_[1] + kernel_second_dim, dX_shape[3]); - const int64_t dy_index = d * dY_shape[2] * dY_shape[3] + h * dY_shape[3] + w; + const Eigen::Index l = narrow(std::max(w * stride_second_dim - pads_[1], 0)); + const Eigen::Index r = + narrow(std::min(w * stride_second_dim - pads_[1] + kernel_second_dim, + dX_shape[3])); + const Eigen::Index dy_index = narrow(d * dY_shape[2] * dY_shape[3] + h * dY_shape[3] + w); const T scale = T(1.0f) / static_cast(count_include_pad_ ? kernel_first_dim * kernel_second_dim * kernel_third_dim : (a - p) * (b - t) * (r - l)); for (int64_t i = p; i < a; ++i) { - dX_arr.block(l, i * dX_shape[2] + t, r - l, b - t) = dY_arr(dy_index) * scale; + dX_arr.block(l, narrow(i * dX_shape[2] + t), r - l, b - t) = dY_arr(dy_index) * scale; } } } @@ -143,18 +149,22 @@ Status AveragePoolGrad::Compute2DAveragePoolGrad(OpKernelContext* context) co const T* dY_ptr = dY_data; for (int cur_channel = 0; cur_channel < channels; cur_channel++) { - ConstEigenArrayMap dY_arr = ConstEigenArrayMap(dY_ptr, dY_shape[3], dY_shape[2]); - EigenArrayMap dX_arr = EigenArrayMap(dX_ptr, dX_shape[3], dX_shape[2]); + ConstEigenArrayMap dY_arr = ConstEigenArrayMap(dY_ptr, narrow(dY_shape[3]), + narrow(dY_shape[2])); + EigenArrayMap dX_arr = EigenArrayMap(dX_ptr, narrow(dX_shape[3]), + narrow(dX_shape[2])); for (int h = 0; h < dY_shape[2]; ++h) { - const int64_t t = std::max(h * stride_first_dim - pads_[0], 0); - const int64_t b = std::min(h * stride_first_dim - pads_[0] + kernel_first_dim, dX_shape[2]); + const Eigen::Index t = narrow(std::max(h * stride_first_dim - pads_[0], 0)); + const Eigen::Index b = + narrow(std::min(h * stride_first_dim - pads_[0] + kernel_first_dim, dX_shape[2])); for (int w = 0; w < dY_shape[3]; ++w) { - const int64_t l = std::max(w * stride_second_dim - pads_[1], 0); - const int64_t r = std::min(w * stride_second_dim - pads_[1] + kernel_second_dim, dX_shape[3]); + const Eigen::Index l = narrow(std::max(w * stride_second_dim - pads_[1], 0)); + const Eigen::Index r = + narrow(std::min(w * stride_second_dim - pads_[1] + kernel_second_dim, dX_shape[3])); - const int64_t dy_index = h * dY_shape[3] + w; + const Eigen::Index dy_index = narrow(h * dY_shape[3] + w); const T scale = T(1.0f) / static_cast(count_include_pad_ ? kernel_first_dim * kernel_second_dim : (b - t) * (r - l)); dX_arr.block(l, t, r - l, b - t) += dY_arr(dy_index) * scale; } @@ -185,12 +195,13 @@ Status AveragePoolGrad::Compute1DAveragePoolGrad(OpKernelContext* context) co const float* dY_ptr = dY_data; for (int cur_channel = 0; cur_channel < channels; cur_channel++) { // for every channel group - ConstEigenArrayMap dY_arr = ConstEigenArrayMap(dY_ptr, dY_shape[2], 1); - EigenArrayMap dX_arr = EigenArrayMap(dX_ptr, dX_shape[2], 1); + ConstEigenArrayMap dY_arr = ConstEigenArrayMap(dY_ptr, narrow(dY_shape[2]), 1); + EigenArrayMap dX_arr = EigenArrayMap(dX_ptr, narrow(dX_shape[2]), 1); for (int dy_index = 0; dy_index < dY_shape[2]; ++dy_index) { - const int64_t left_index = std::max(dy_index * stride_size - pads_[0], 0); - const int64_t right_index = std::min(dy_index * stride_size - pads_[0] + kernel_size, dX_shape[2]); + const auto left_index = narrow(std::max(dy_index * stride_size - pads_[0], 0)); + const auto right_index = narrow(std::min(dy_index * stride_size - pads_[0] + kernel_size, + dX_shape[2])); const T scale = T(1.0f) / static_cast(count_include_pad_ ? kernel_size : right_index - left_index); @@ -217,7 +228,7 @@ Status AveragePoolGrad::Compute(OpKernelContext* context) const { const TensorShape dX_shape = TensorShape::FromExistingBuffer(output_tensor_shapes_[0]); Tensor* dX = context->Output(0, dX_shape); T* dX_data = dX->template MutableData(); - EigenVectorMap(dX_data, dX_shape.Size()).setZero(); + EigenVectorMap(dX_data, narrow(dX_shape.Size())).setZero(); switch (dX_shape.NumDimensions()) { case 3: diff --git a/orttraining/orttraining/training_ops/cpu/op_gradients.cc b/orttraining/orttraining/training_ops/cpu/op_gradients.cc index 93200f50e7172..c3476161c1e53 100644 --- a/orttraining/orttraining/training_ops/cpu/op_gradients.cc +++ b/orttraining/orttraining/training_ops/cpu/op_gradients.cc @@ -30,9 +30,13 @@ Status ReluGrad::Compute(OpKernelContext* context) const { auto& X = *context->Input(1); auto& dX = *context->Output(0, dY.Shape()); - EigenVectorArrayMap(dX.template MutableData(), dX.Shape().Size()) = - (ConstEigenVectorArrayMap(X.template Data(), X.Shape().Size()) > T(0)) - .select(ConstEigenVectorArrayMap(dY.template Data(), dY.Shape().Size()), T(0)); + auto dY_span = dY.template DataAsSpan(); + auto X_span = X.template DataAsSpan(); + auto dX_span = dX.template MutableDataAsSpan(); + + EigenVectorArrayMap(dX_span.data(), dX_span.size()) = + (ConstEigenVectorArrayMap(X_span.data(), X_span.size()) > T(0)) + .select(ConstEigenVectorArrayMap(dY_span.data(), dY_span.size()), T(0)); return Status::OK(); } @@ -63,8 +67,8 @@ Status SoftmaxGrad::Compute(OpKernelContext* context) const { size_t rank = input_shape.NumDimensions(); const size_t axis = static_cast(HandleNegativeAxis(axis_, rank)); - size_t N = input_shape.SizeToDimension(axis); - size_t D = input_shape.SizeFromDimension(axis); + size_t N = narrow(input_shape.SizeToDimension(axis)); + size_t D = narrow(input_shape.SizeFromDimension(axis)); if (N == 0) { return Status::OK(); @@ -94,8 +98,8 @@ Status SoftmaxGrad::Compute(OpKernelContext* context) const { for (auto e : permutation) { transposed_input_dims.push_back(input_shape[e]); } - N = TensorShape(transposed_input_dims).SizeToDimension(rank - 1); - D = TensorShape(transposed_input_dims).SizeFromDimension(rank - 1); + N = narrow(TensorShape(transposed_input_dims).SizeToDimension(rank - 1)); + D = narrow(TensorShape(transposed_input_dims).SizeFromDimension(rank - 1)); // Allocate a temporary tensor to hold transposed input auto temp_input0 = Tensor(Y.DataType(), TensorShape(transposed_input_dims), alloc); @@ -185,9 +189,12 @@ Status SigmoidGrad::Compute(OpKernelContext* context) const { auto& dY = *context->Input(0); auto& Y = *context->Input(1); auto& dX = *context->Output(0, dY.Shape()); - EigenVectorArrayMap dx = EigenVectorArrayMap(dX.template MutableData(), dX.Shape().Size()); - ConstEigenVectorArrayMap y = ConstEigenVectorArrayMap(Y.template Data(), Y.Shape().Size()); - ConstEigenVectorArrayMap dy = ConstEigenVectorArrayMap(dY.template Data(), dY.Shape().Size()); + EigenVectorArrayMap dx = EigenVectorArrayMap(dX.template MutableData(), + narrow(dX.Shape().Size())); + ConstEigenVectorArrayMap y = ConstEigenVectorArrayMap(Y.template Data(), + narrow(Y.Shape().Size())); + ConstEigenVectorArrayMap dy = ConstEigenVectorArrayMap(dY.template Data(), + narrow(dY.Shape().Size())); dx = dy * y * (1 - y); return Status::OK(); } @@ -205,9 +212,12 @@ Status TanhGrad::Compute(OpKernelContext* context) const { auto& dY = *context->Input(0); auto& Y = *context->Input(1); auto& dX = *context->Output(0, dY.Shape()); - EigenVectorArrayMap dx = EigenVectorArrayMap(dX.template MutableData(), dX.Shape().Size()); - ConstEigenVectorArrayMap y = ConstEigenVectorArrayMap(Y.template Data(), Y.Shape().Size()); - ConstEigenVectorArrayMap dy = ConstEigenVectorArrayMap(dY.template Data(), dY.Shape().Size()); + EigenVectorArrayMap dx = EigenVectorArrayMap(dX.template MutableData(), + narrow(dX.Shape().Size())); + ConstEigenVectorArrayMap y = ConstEigenVectorArrayMap(Y.template Data(), + narrow(Y.Shape().Size())); + ConstEigenVectorArrayMap dy = ConstEigenVectorArrayMap(dY.template Data(), + narrow(dY.Shape().Size())); dx = dy * (1 - y * y); return Status::OK(); } @@ -240,7 +250,7 @@ Status QuickGeluGrad::Compute(OpKernelContext* context) const { p_dx[i] = p_x[i] * alpha_; } - MlasComputeLogistic(p_dx, p_dx, count); + MlasComputeLogistic(p_dx, p_dx, narrow(count)); for (int64_t i = 0; i < count; i++) { p_dx[i] = p_dy[i] * p_dx[i] * (1.f + alpha_ * p_x[i] * (1.f - p_dx[i])); @@ -250,5 +260,24 @@ Status QuickGeluGrad::Compute(OpKernelContext* context) const { return Status::OK(); } +ONNX_OPERATOR_KERNEL_EX(LeakyReluGrad, kMSDomain, 1, kCpuExecutionProvider, + KernelDefBuilder().TypeConstraint("T", DataTypeImpl::GetTensorType()), + LeakyReluGrad); + +template +Status LeakyReluGrad::Compute(OpKernelContext* context) const { + auto& dY = *context->Input(0); + auto& Y = *context->Input(1); + auto& dX = *context->Output(0, dY.Shape()); + EigenVectorArrayMap dx = EigenVectorArrayMap(dX.template MutableData(), + narrow(dX.Shape().Size())); + ConstEigenVectorArrayMap y = ConstEigenVectorArrayMap(Y.template Data(), + narrow(Y.Shape().Size())); + ConstEigenVectorArrayMap dy = ConstEigenVectorArrayMap(dY.template Data(), + narrow(dY.Shape().Size())); + dx = (y > 0.0f).select(dy, alpha_ * dy); + return Status::OK(); +} + } // namespace contrib } // namespace onnxruntime diff --git a/orttraining/orttraining/training_ops/cpu/op_gradients.h b/orttraining/orttraining/training_ops/cpu/op_gradients.h index be1268dac5d1b..64dad382a8d9f 100644 --- a/orttraining/orttraining/training_ops/cpu/op_gradients.h +++ b/orttraining/orttraining/training_ops/cpu/op_gradients.h @@ -78,5 +78,19 @@ class SoftmaxGrad final : public OpKernel { bool is_logsoftmaxgrad_; }; +template +class LeakyReluGrad final : public OpKernel { + public: + explicit LeakyReluGrad(const OpKernelInfo& info) : OpKernel(info) { + alpha_ = info.GetAttrOrDefault("alpha", 0.01f); + } + + Status Compute(OpKernelContext* context) const override; + + private: + ORT_DISALLOW_COPY_ASSIGNMENT_AND_MOVE(LeakyReluGrad); + float alpha_; +}; + } // namespace contrib } // namespace onnxruntime diff --git a/orttraining/orttraining/training_ops/cpu/optimizer/adamw/adamw.cc b/orttraining/orttraining/training_ops/cpu/optimizer/adamw/adamw.cc index 8fe0cb89255ab..753a1674576fd 100644 --- a/orttraining/orttraining/training_ops/cpu/optimizer/adamw/adamw.cc +++ b/orttraining/orttraining/training_ops/cpu/optimizer/adamw/adamw.cc @@ -137,7 +137,7 @@ Status AdamWOptimizer::Compute(OpKernelContext* ctx) const { AdamWOptimizerBase::Prepare p; ORT_RETURN_IF_ERROR(PrepareForCompute(ctx, p)); - int64_t* updated_flag_ptr = p.updated_flag->template MutableData(); + bool* updated_flag_ptr = p.updated_flag->template MutableData(); const Tensor* update_signal = ctx->Input(6); if (update_signal == nullptr || *update_signal->template Data()) { @@ -182,9 +182,9 @@ Status AdamWOptimizer::Compute(OpKernelContext* ctx) const { } } - *updated_flag_ptr = 1; + *updated_flag_ptr = true; } else { - *updated_flag_ptr = 0; + *updated_flag_ptr = false; } if (p.updated_weights != nullptr) { diff --git a/orttraining/orttraining/training_ops/cpu/optimizer/gradient_control.cc b/orttraining/orttraining/training_ops/cpu/optimizer/gradient_control.cc index 7cbaeaedf274e..36eb836743c50 100644 --- a/orttraining/orttraining/training_ops/cpu/optimizer/gradient_control.cc +++ b/orttraining/orttraining/training_ops/cpu/optimizer/gradient_control.cc @@ -64,7 +64,7 @@ Status ZeroGradient::Compute(OpKernelContext* context) const { const Tensor& old_gradient = *context->Input(0); Tensor& zero_gradient = *context->Output(0, old_gradient.Shape()); - std::memset(zero_gradient.template MutableData(), 0, zero_gradient.Shape().Size() * sizeof(T)); + std::memset(zero_gradient.template MutableData(), 0, zero_gradient.SizeInBytes()); return Status::OK(); } diff --git a/orttraining/orttraining/training_ops/cpu/quantization/fake_quant.cc b/orttraining/orttraining/training_ops/cpu/quantization/fake_quant.cc index fec39da5b1355..5c4ab1c23b23f 100644 --- a/orttraining/orttraining/training_ops/cpu/quantization/fake_quant.cc +++ b/orttraining/orttraining/training_ops/cpu/quantization/fake_quant.cc @@ -2,6 +2,7 @@ // Licensed under the MIT License. #include "orttraining/training_ops/cpu/quantization/fake_quant.h" +#include "core/common/narrow.h" #include "core/providers/common.h" #include "core/providers/cpu/math/element_wise_ops.h" @@ -17,7 +18,7 @@ void FakeQuantPerTensor(OpKernelContext* ctx, const int64_t num_elements, const const auto zero_point_int = static_cast(quant_zero_point); auto* tp = ctx->GetOperatorThreadPool(); concurrency::ThreadPool::TryParallelFor( - tp, num_elements, /* 1 Read, 2 Writes, 4 Computes */ TensorOpCost{1.0, 2.0, 4.0}, + tp, narrow(num_elements), /* 1 Read, 2 Writes, 4 Computes */ TensorOpCost{1.0, 2.0, 4.0}, [quant_scale, zero_point_int, quant_min, quant_max, &input_data, &fake_quantized_data, &quantization_mask_data]( std::ptrdiff_t begin, std::ptrdiff_t end) { for (std::ptrdiff_t index = begin; index != end; ++index) { diff --git a/orttraining/orttraining/training_ops/cpu/rnn/gru.cc b/orttraining/orttraining/training_ops/cpu/rnn/gru.cc new file mode 100644 index 0000000000000..350c33e1d51bd --- /dev/null +++ b/orttraining/orttraining/training_ops/cpu/rnn/gru.cc @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "orttraining/training_ops/cpu/rnn/gru.h" + +#include "core/providers/cpu/rnn/deep_cpu_gru.h" + +namespace onnxruntime::contrib { + +#define REGISTER_GRUTRAINING_KERNEL_TYPED(T) \ + ONNX_OPERATOR_TYPED_KERNEL_EX( \ + GRUTraining, \ + kMSDomain, \ + 1, \ + T, \ + kCpuExecutionProvider, \ + (*KernelDefBuilder::Create()) \ + .TypeConstraint("T", DataTypeImpl::GetTensorType()), \ + GRUTraining); + +REGISTER_GRUTRAINING_KERNEL_TYPED(float) + +template +Status GRUTraining::Compute(OpKernelContext* context) const { + const auto gru_inputs = gru::GRUInputs(context, attributes_.num_directions, attributes_.hidden_size); + auto gru_outputs = gru::GRUOutputs(context, attributes_.num_directions, gru_inputs.shape.sequence_length, + gru_inputs.shape.batch_size, attributes_.hidden_size); + + AllocatorPtr alloc; + ORT_RETURN_IF_ERROR(context->GetTempSpaceAllocator(&alloc)); + detail::UniDirectionalGru gru(alloc, + gru_inputs.shape.sequence_length, + gru_inputs.shape.batch_size, + gru_inputs.shape.input_size, + attributes_.hidden_size, + attributes_.linear_before_reset, + attributes_.direction, + gru_inputs.bias, + gru_inputs.initial_hidden_state, + attributes_.activation_funcs.Entries()[0], + attributes_.activation_funcs.Entries()[1], + attributes_.clip, + context->GetOperatorThreadPool(), + true /*training_mode*/); + gru.Compute(gru_inputs.input, + gru_inputs.sequence_lengths, + attributes_.num_directions, + gru_inputs.weights, + gru_inputs.recurrence_weights_zr, + gru_inputs.recurrence_weights_h, + gru_outputs.all_hidden_states, + gru_outputs.final_hidden_state, + gru_outputs.zrh); + + return Status::OK(); +} + +} // namespace onnxruntime::contrib diff --git a/orttraining/orttraining/training_ops/cpu/rnn/gru.h b/orttraining/orttraining/training_ops/cpu/rnn/gru.h new file mode 100644 index 0000000000000..a47bda8ce468c --- /dev/null +++ b/orttraining/orttraining/training_ops/cpu/rnn/gru.h @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/framework/op_kernel.h" +#include "orttraining/training_ops/cpu/rnn/gru_io_utils.h" + +namespace onnxruntime::contrib { + +template +class GRUTraining final : public OpKernel { + public: + GRUTraining(const OpKernelInfo& info) : OpKernel(info), attributes_(info) { + } + + Status Compute(OpKernelContext* context) const override; + + private: + gru::GRUAttributes attributes_; +}; + +} // namespace onnxruntime::contrib diff --git a/orttraining/orttraining/training_ops/cpu/rnn/gru_grad.cc b/orttraining/orttraining/training_ops/cpu/rnn/gru_grad.cc new file mode 100644 index 0000000000000..d079c15e1e159 --- /dev/null +++ b/orttraining/orttraining/training_ops/cpu/rnn/gru_grad.cc @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "orttraining/training_ops/cpu/rnn/gru_grad.h" +#include "orttraining/training_ops/cpu/rnn/gru_grad_compute.h" + +namespace onnxruntime::contrib { + +#define REGISTER_GRUGRAD_KERNEL_TYPED(T) \ + ONNX_OPERATOR_TYPED_KERNEL_EX( \ + GRUGrad, \ + kMSDomain, \ + 1, \ + T, \ + kCpuExecutionProvider, \ + (*KernelDefBuilder::Create()) \ + .TypeConstraint("T", DataTypeImpl::GetTensorType()), \ + GRUGrad); + +REGISTER_GRUGRAD_KERNEL_TYPED(float) + +template +Status GRUGrad::Compute(OpKernelContext* context) const { + const auto grugrad_inputs = gru::GRUGradInputs(context, attributes_.num_directions, attributes_.hidden_size); + auto grugrad_outputs = gru::GRUGradOutputs(context, attributes_.num_directions, grugrad_inputs.shape.sequence_length, + grugrad_inputs.shape.batch_size, attributes_.hidden_size, + grugrad_inputs.shape.input_size); + + // Allocator in case we need to allocate memory for a nullptr input/output + AllocatorPtr alloc; + ORT_RETURN_IF_ERROR(context->GetTempSpaceAllocator(&alloc)); + + gru::GRUGradImpl gru_cell(grugrad_inputs.shape.sequence_length, + grugrad_inputs.shape.batch_size, + attributes_.hidden_size, + grugrad_inputs.shape.input_size, + attributes_.linear_before_reset, + context->GetOperatorThreadPool(), + alloc); + + gru_cell.ComputeGradient(grugrad_inputs, grugrad_outputs); + + return Status::OK(); +} + +} // namespace onnxruntime::contrib diff --git a/orttraining/orttraining/training_ops/cpu/rnn/gru_grad.h b/orttraining/orttraining/training_ops/cpu/rnn/gru_grad.h new file mode 100644 index 0000000000000..1de585ea8d5ab --- /dev/null +++ b/orttraining/orttraining/training_ops/cpu/rnn/gru_grad.h @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/framework/op_kernel.h" +#include "orttraining/training_ops/cpu/rnn/gru_io_utils.h" + +namespace onnxruntime::contrib { + +template +class GRUGrad final : public OpKernel { + public: + GRUGrad(const OpKernelInfo& info) : OpKernel(info), attributes_(info) { + } + + Status Compute(OpKernelContext* context) const override; + + private: + const gru::GRUAttributes attributes_; +}; + +} // namespace onnxruntime::contrib diff --git a/orttraining/orttraining/training_ops/cpu/rnn/gru_grad_compute.cc b/orttraining/orttraining/training_ops/cpu/rnn/gru_grad_compute.cc new file mode 100644 index 0000000000000..c883f5b5bbbb7 --- /dev/null +++ b/orttraining/orttraining/training_ops/cpu/rnn/gru_grad_compute.cc @@ -0,0 +1,443 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "orttraining/training_ops/cpu/rnn/gru_grad_compute.h" + +namespace onnxruntime::gru { + +namespace { + +void ElementwiseSub(const float* op1, const float* op2, float* dest, int size) { + for (int i = 0; i < size; i++) + dest[i] = op1[i] - op2[i]; +} + +void ElementwiseProduct(const float* op1, const float* op2, float* dest, int size) { + for (int i = 0; i < size; i++) + dest[i] = op1[i] * op2[i]; +} + +} // namespace + +template +GRUGradImpl::GRUGradImpl(int sequence_length, int batch_size, int hidden_size, int input_size, + bool linear_before_reset, concurrency::ThreadPool* thread_pool, + AllocatorPtr allocator) + : sequence_length_(sequence_length), + batch_size_(batch_size), + hidden_size_(hidden_size), + input_size_(input_size), + linear_before_reset_(linear_before_reset), + thread_pool_(thread_pool), + allocator_(allocator) { + const size_t hidden_size_x3 = 3U * static_cast(hidden_size_); + const size_t weight_size = 3U * static_cast(hidden_size_) * static_cast(input_size_); + const size_t recurrence_weight_size = 3U * static_cast(hidden_size_) * static_cast(hidden_size_); + grad_a_span_ = rnn::detail::Allocate(allocator_, hidden_size_x3, grad_a_ptr_, true, static_cast(0)); + rt_factor_span_ = rnn::detail::Allocate(allocator_, hidden_size_, rt_factor_ptr_, true, static_cast(0)); + grad_W_span_ = rnn::detail::Allocate(allocator_, weight_size, grad_W_ptr_, true, static_cast(0)); + grad_R_span_ = rnn::detail::Allocate(allocator_, recurrence_weight_size, grad_R_ptr_, true, static_cast(0)); +} + +template +void GRUGradImpl::ComputeGradient(const GRUGradInputs& inputs, GRUGradOutputs& outputs) { + using namespace rnn::detail; + + // A note on the memory layout of buffers used in this function: + // zrh buffer: + // ________________________________________________ + // | | | | | | | | | | | | | | | | | | | | | | + // |z|r|h|z|r|h|...|z|r|h|...|z|r|h|z|r|h|...|z|r|h| + // |_|_|_|_|_|_|___|_|_|_|___|_|_|_|_|_|_|___|_|_|_| + // ->|H|<- Each z, t, h block is of size hidden size + // <-B1-><-B2->....<-Bn->....<-B1-><-B2->....<-Bn-> Batch size is n + // <---------S1--------->....<---------St----------> Sequence length is t + // + // all hidden states buffer: + // ___________________________________________ + // | | | | | | |...| |...| | |...| | + // |B1|B2|...|Bn|B1|B2|...|Bn|...|B1|B2|...|Bn| + // |__|__|___|__|__|__|___|__|___|__|__|___|__| + // -->|H |<-- Each block is of size hidden size. Each B represents an index of the batch. So batch size is n + // <----S1-----><----S2----->....<----St-----> Sequence length is t + // Every buffer having a sequnence length dimension are structured as the above two. + // + // Weight buffers: + // ___________________________________ + // | | | | + // | Wz | Wr | Wh | + // |_________|___________|____________| + // <---HxI---> Each block is hidden size x input size long + // Each block represents either z, r, or h weights. + // Every weight buffer is similarly structured + + const size_t hidden_size_x3 = 3U * static_cast(hidden_size_); + const size_t hidden_size_x6 = 6U * static_cast(hidden_size_); + const size_t weight_size = 3U * static_cast(hidden_size_) * static_cast(input_size_); + const size_t recurrence_weight_size = 3U * static_cast(hidden_size_) * static_cast(hidden_size_); + const size_t hidden_sizexinput_size = static_cast(hidden_size_) * static_cast(input_size_); + const size_t hidden_sizexhidden_size = static_cast(hidden_size_) * static_cast(hidden_size_); + + const gsl::span& W = inputs.weights; + const float* Wz = SafeRawPointer(W.begin(), W.end(), weight_size); + const float* Wr = Wz + hidden_sizexinput_size; + const float* Wh = Wr + hidden_sizexinput_size; + + const gsl::span& R = inputs.recurrence_weights; + const float* Rz = SafeRawPointer(R.begin(), R.end(), recurrence_weight_size); + const float* Rr = Rz + hidden_sizexhidden_size; + const float* Rh = Rr + hidden_sizexhidden_size; + + const gsl::span& B = inputs.bias; + const float* Rbh = B.empty() + ? nullptr + : SafeRawPointer(B.begin() + 5U * static_cast(hidden_size_), + B.end(), hidden_size_); + + const bool grad_input_required = !outputs.grad_input.empty(); + const bool grad_weights_required = !outputs.grad_weights.empty(); + const bool grad_recurrence_weights_required = !outputs.grad_recurrence_weights.empty(); + const bool grad_bias_required = !outputs.grad_bias.empty(); + + auto& grad_W = outputs.grad_weights; + if (grad_weights_required) { + std::fill_n(grad_W.data(), grad_W.size(), static_cast(0)); + } + float* grad_Wz = grad_weights_required + ? SafeRawPointer(grad_W.begin(), grad_W.end(), weight_size) + : nullptr; + float* grad_Wr = grad_weights_required ? grad_Wz + hidden_sizexinput_size : nullptr; + float* grad_Wh = grad_weights_required ? grad_Wr + hidden_sizexinput_size : nullptr; + + auto& grad_R = outputs.grad_recurrence_weights; + if (grad_recurrence_weights_required) { + std::fill_n(grad_R.data(), grad_R.size(), static_cast(0)); + } + float* grad_Rz = grad_recurrence_weights_required + ? SafeRawPointer(grad_R.begin(), grad_R.end(), recurrence_weight_size) + : nullptr; + float* grad_Rr = grad_recurrence_weights_required ? grad_Rz + hidden_sizexhidden_size : nullptr; + float* grad_Rh = grad_recurrence_weights_required ? grad_Rr + hidden_sizexhidden_size : nullptr; + + // Fill grad bias with 0s since they are used as accumulators + auto& grad_B = outputs.grad_bias; + if (grad_bias_required) { + std::fill_n(grad_B.data(), grad_B.size(), static_cast(0)); + } + float* grad_Wbz = grad_bias_required ? SafeRawPointer(grad_B.begin(), grad_B.end(), hidden_size_x6) : nullptr; + float* grad_Wbr = grad_bias_required ? grad_Wbz + hidden_size_ : nullptr; + float* grad_Wbh = grad_bias_required ? grad_Wbr + hidden_size_ : nullptr; + float* grad_Rbz = grad_bias_required ? grad_Wbh + hidden_size_ : nullptr; + float* grad_Rbr = grad_bias_required ? grad_Rbz + hidden_size_ : nullptr; + float* grad_Rbh = grad_bias_required ? grad_Rbr + hidden_size_ : nullptr; + + constexpr float alpha = 1.0f; + constexpr float weight_beta = 0.0f; + + float* grad_az = SafeRawPointer(grad_a_span_.begin(), grad_a_span_.end(), hidden_size_x3); + float* grad_ar = grad_az + hidden_size_; + float* grad_ah = grad_ar + hidden_size_; + + float* grad_Wz_local = SafeRawPointer(grad_W_span_.begin(), grad_W_span_.end(), weight_size); + float* grad_Wr_local = grad_Wz_local + hidden_sizexinput_size; + float* grad_Wh_local = grad_Wr_local + hidden_sizexinput_size; + + float* grad_Rz_local = SafeRawPointer(grad_R_span_.begin(), grad_R_span_.end(), recurrence_weight_size); + float* grad_Rr_local = grad_Rz_local + hidden_sizexhidden_size; + float* grad_Rh_local = grad_Rr_local + hidden_sizexhidden_size; + + float* rt_factor = SafeRawPointer(rt_factor_span_.begin(), rt_factor_span_.end(), hidden_size_); + + std::fill_n(outputs.grad_initial_hidden_state.data(), outputs.grad_initial_hidden_state.size(), static_cast(0)); + + for (int idx = 0; idx < batch_size_; ++idx) { + const size_t hidden_sizexidx = static_cast(idx) * static_cast(hidden_size_); + float* grad_Ht = SafeRawPointer(outputs.grad_initial_hidden_state.begin() + hidden_sizexidx, + outputs.grad_initial_hidden_state.end(), hidden_size_); + const float* grad_Hfinal = inputs.grad_final_hidden_state.empty() + ? nullptr + : SafeRawPointer(inputs.grad_final_hidden_state.begin() + hidden_sizexidx, + inputs.grad_final_hidden_state.end(), hidden_size_); + + if (grad_Hfinal) + deepcpu::elementwise_sum1(grad_Hfinal, grad_Ht, hidden_size_); + + for (int t = sequence_length_ - 1; t >= 0; --t) { + const size_t zrh_offset = (static_cast(t) * static_cast(batch_size_) + + static_cast(idx)) * + hidden_size_x3; + auto zrh = inputs.zrh.begin() + zrh_offset; + const float* zt = SafeRawPointer(zrh, inputs.zrh.end(), hidden_size_x3); + const float* rt = zt + hidden_size_; + const float* ht = rt + hidden_size_; + + const size_t H_offset = (static_cast(t) * static_cast(batch_size_) + + static_cast(idx)) * + static_cast(hidden_size_); + const size_t Htminus1_offset = t > 0 ? ((static_cast(t) - 1U) * static_cast(batch_size_) + + static_cast(idx)) * + hidden_size_ + : 0U; + + const float* grad_Ht2 = inputs.grad_all_hidden_states.empty() + ? nullptr + : SafeRawPointer( + inputs.grad_all_hidden_states.begin() + H_offset, + inputs.grad_all_hidden_states.end(), hidden_size_); + + const float* Htminus1 = t > 0 ? SafeRawPointer( + inputs.all_hidden_states.begin() + Htminus1_offset, + inputs.all_hidden_states.end(), hidden_size_) + : SafeRawPointer( + inputs.initial_hidden_state.begin() + hidden_sizexidx, + inputs.initial_hidden_state.end(), hidden_size_); + + // Accumulate the gradient from the gradients of all hidden states for this sequence index and batch index. + if (grad_Ht2) + deepcpu::elementwise_sum1(grad_Ht2, grad_Ht, hidden_size_); + + // Ht = (1 - zt) (.) ht + zt (.) Ht-1H + // dL/dzt = dL/dHt (.) (Ht-1h - ht) ---------- (1) + ElementwiseSub(Htminus1, ht, grad_az, hidden_size_); + ElementwiseProduct(grad_az, grad_Ht, grad_az, hidden_size_); + + // zt = sigmoid(az) + // dL/daz = dL/dzt (.) zt (.) (1 - zt) ---------- (2) + for (int h = 0; h < hidden_size_; ++h) { + grad_az[h] = grad_az[h] * (zt[h] * (1 - zt[h])); + } + + // Ht = (1 - zt) (.) ht + zt (.) Ht-1H + // dL/dht = dL/dHt (.) (1 - zt) ---------- (3) + for (int h = 0; h < hidden_size_; ++h) { + grad_ah[h] = grad_Ht[h] * (1 - zt[h]); + } + + // ht = tanh(ah) + // dL/dah = dL/dht (.) (1 - ht^2) ---------- (4) + for (int h = 0; h < hidden_size_; ++h) { + grad_ah[h] = grad_ah[h] * (1 - ht[h] * ht[h]); + } + + if (!linear_before_reset_) { + // ah = Xth * Wh^T + (rt (.) Ht-1h) * Rh^T + Wbh + Rbh + // dL/drt = (dL/dah * Rh) (.) (Ht-1h) ---------- (5) + ::onnxruntime::math::Gemm(CblasNoTrans, CblasNoTrans, 1, hidden_size_, + hidden_size_, alpha, grad_ah, Rh, weight_beta, grad_ar, thread_pool_); + ElementwiseProduct(grad_ar, Htminus1, grad_ar, hidden_size_); + } else { + // ah = Xth * Wh^T + rt (.) (Ht-1h * Rh^T + Rbh) + Wbh + // dL/drt = dL/dah (.) (Ht-1h * Rh^T + Rbh) ---------- (5) + ::onnxruntime::math::Gemm(CblasNoTrans, CblasTrans, 1, hidden_size_, + hidden_size_, alpha, Htminus1, Rh, weight_beta, grad_ar, thread_pool_); + if (Rbh != nullptr) + deepcpu::elementwise_sum1(Rbh, grad_ar, hidden_size_); + ElementwiseProduct(grad_ar, grad_ah, grad_ar, hidden_size_); + } + + // rt = sigmoid(ar) + // dL/dar = dL/drt (.) rt (.) (1 - rt) ---------- (6) + for (int h = 0; h < hidden_size_; ++h) { + grad_ar[h] = grad_ar[h] * (rt[h] * (1 - rt[h])); + } + + if (grad_input_required) { + const size_t X_offset = (static_cast(t) * static_cast(batch_size_) + + static_cast(idx)) * + static_cast(input_size_); + // Xt -> multiplex gate -> Xtz + // -> Xtr + // -> Xth + // dL/dXt = dL/dXtz + dL/dXtr + dL/dXth ---------- (7) + float input_beta = 0.0f; + + // az = Xtz * Wz^T + Ht-1z * Rz^T + Wbz + Rbz + // dL/dXtz = dL/daz * Wz ---------- (8) + // [1, input_size_] = [1, hidden_size_] * [hidden_size_, input_size_] + // M = 1, N = input_size_, K = hidden_size_ + float* grad_Xt = SafeRawPointer(outputs.grad_input.begin() + X_offset, + outputs.grad_input.end(), input_size_); + ::onnxruntime::math::Gemm(CblasNoTrans, CblasNoTrans, 1, input_size_, + hidden_size_, alpha, grad_az, Wz, input_beta, grad_Xt, thread_pool_); + + // ar = Xtr * Wr^T + Ht-1r * Rr^T + Wbr + Rbr + // dL/dXtr = dL/dar * Wr ---------- (9) + // [1, input_size_] = [1, hidden_size_] * [hidden_size_, input_size_] + // M = 1, N = input_size_, K = hidden_size_ + input_beta = 1.0f; + ::onnxruntime::math::Gemm(CblasNoTrans, CblasNoTrans, 1, input_size_, + hidden_size_, alpha, grad_ar, Wr, input_beta, grad_Xt, thread_pool_); + + // ah = Xth * Wh^T + (rt (.) Ht-1h) * Rh^T + Wbh + Rbh + // dL/dXth = dL/dah * Wh ---------- (10) + // [1, input_size_] = [1, hidden_size_] * [hidden_size_, input_size_] + // M = 1, N = input_size_, K = hidden_size_ + ::onnxruntime::math::Gemm(CblasNoTrans, CblasNoTrans, 1, input_size_, + hidden_size_, alpha, grad_ah, Wh, input_beta, grad_Xt, thread_pool_); + } + + if (grad_weights_required) { + const size_t X_offset = (static_cast(t) * static_cast(batch_size_) + + static_cast(idx)) * + static_cast(input_size_); + // az = Xtz * Wz^T + Ht-1z * Rz^T + Wbz + Rbz + // dL/dWz = dL/daz^T * Xtz ---------- (11) + // [hidden_size_, input_size_] = [1, hidden_size_]^T * [1, input_size_] + // M = hidden_size_, N = input_size_, K = 1 + const float* Xt = SafeRawPointer(inputs.input.begin() + X_offset, + inputs.input.end(), input_size_); + ::onnxruntime::math::Gemm(CblasTrans, CblasNoTrans, hidden_size_, input_size_, + 1, alpha, grad_az, Xt, weight_beta, grad_Wz_local, thread_pool_); + // Note that the weight beta is always 0. So, we must accumulate ourselves. + deepcpu::elementwise_sum1(grad_Wz_local, grad_Wz, hidden_size_ * input_size_); + + // ar = Xtr * Wr^T + Ht-1r * Rr^T + Wbr + Rbr + // dL/dWr = dL/dar^T * Xtr ---------- (12) + // [hidden_size_, input_size_] = [1, hidden_size_]^T * [1, input_size_] + // M = hidden_size_, N = input_size_, K = 1 + ::onnxruntime::math::Gemm(CblasTrans, CblasNoTrans, hidden_size_, input_size_, + 1, alpha, grad_ar, Xt, weight_beta, grad_Wr_local, thread_pool_); + // Note that the weight beta is always 0. So, we must accumulate ourselves. + deepcpu::elementwise_sum1(grad_Wr_local, grad_Wr, hidden_size_ * input_size_); + + // ah = Xth * Wh^T + Ht-1h * Rh^T + Wbh + Rbh + // dL/dWh = dL/dah^T * Xth ---------- (13) + // [hidden_size_, input_size_] = [1, hidden_size_]^T * [1, input_size_] + // M = hidden_size_, N = input_size_, K = 1 + ::onnxruntime::math::Gemm(CblasTrans, CblasNoTrans, hidden_size_, input_size_, + 1, alpha, grad_ah, Xt, weight_beta, grad_Wh_local, thread_pool_); + // Note that the weight beta is always 0. So, we must accumulate ourselves. + deepcpu::elementwise_sum1(grad_Wh_local, grad_Wh, hidden_size_ * input_size_); + } + + if (grad_recurrence_weights_required) { + // az = Xtz * Wz^T + Ht-1z * Rz^T + Wbz + Rbz + // dL/dRz = dL/daz^T * Ht-1z ---------- (14) + // [hidden_size_, hidden_size_] = [1, hidden_size_]^T * [1, hidden_size_] + // M = hidden_size_, N = hidden_size_, K = 1 + ::onnxruntime::math::Gemm(CblasTrans, CblasNoTrans, hidden_size_, hidden_size_, + 1, alpha, grad_az, Htminus1, weight_beta, grad_Rz_local, thread_pool_); + // Note that the weight beta is always 0. So, we must accumulate ourselves. + deepcpu::elementwise_sum1(grad_Rz_local, grad_Rz, hidden_size_ * hidden_size_); + + // ar = Xtr * Wr^T + Ht-1r * Rr^T + Wbr + Rbr + // dL/dRr = dL/dar^T * Ht-1r ---------- (15) + // [hidden_size_, hidden_size_] = [1, hidden_size_]^T * [1, hidden_size_] + // M = hidden_size_, N = hidden_size_, K = 1 + ::onnxruntime::math::Gemm(CblasTrans, CblasNoTrans, hidden_size_, hidden_size_, + 1, alpha, grad_ar, Htminus1, weight_beta, grad_Rr_local, thread_pool_); + // Note that the weight beta is always 0. So, we must accumulate ourselves. + deepcpu::elementwise_sum1(grad_Rr_local, grad_Rr, hidden_size_ * hidden_size_); + + if (!linear_before_reset_) { + // ah = Xth * Wh^T + (rt (.) Ht-1h) * Rh^T + Wbh + Rbh + // dL/dRh = dL/dah^T * (rt (.) Ht-1h) ---------- (16) + // [hidden_size_, hidden_size_] = [1, hidden_size_]^T * [1, hidden_size_] + // M = hidden_size_, N = hidden_size_, K = 1 + ElementwiseProduct(rt, Htminus1, rt_factor, hidden_size_); + ::onnxruntime::math::Gemm(CblasTrans, CblasNoTrans, hidden_size_, hidden_size_, + 1, alpha, grad_ah, rt_factor, weight_beta, grad_Rh_local, thread_pool_); + // Note that the weight beta is always 0. So, we must accumulate ourselves. + deepcpu::elementwise_sum1(grad_Rh_local, grad_Rh, hidden_size_ * hidden_size_); + } else { + // ah = Xth * Wh^T + rt (.) (Ht-1h * Rh^T + Rbh) + Wbh + // dL/dah = G -> dL = G : dah -> dL = G (.) rt : d (Ht-1 * Rh^T) + // dL/dRh = (dL/dah (.) rt)^T * Ht-1h ---------- (16) + // [hidden_size_, hidden_size_] = [1, hidden_size_]^T * [1, hidden_size_] + // M = hidden_size_, N = hidden_size_, K = 1 + ElementwiseProduct(grad_ah, rt, rt_factor, hidden_size_); + ::onnxruntime::math::Gemm(CblasTrans, CblasNoTrans, hidden_size_, hidden_size_, + 1, alpha, rt_factor, Htminus1, weight_beta, grad_Rh_local, thread_pool_); + // Note that the weight beta is always 0. So, we must accumulate ourselves. + deepcpu::elementwise_sum1(grad_Rh_local, grad_Rh, hidden_size_ * hidden_size_); + } + } + + if (grad_bias_required) { + // az = Xtz * Wz^T + Ht-1z * Rz^T + Wbz + Rbz + // dL/dWbz = dL/daz ---------- (17) + deepcpu::elementwise_sum1(grad_az, grad_Wbz, hidden_size_); + + // az = Xtz * Wz^T + Ht-1z * Rz^T + Wbz + Rbz + // dL/dRbz = dL/daz ---------- (18) + deepcpu::elementwise_sum1(grad_az, grad_Rbz, hidden_size_); + + // ar = Xtr * Wr^T + Ht-1r * Rr^T + Wbr + Rbr + // dL/dWbr = dL/dar ---------- (19) + deepcpu::elementwise_sum1(grad_ar, grad_Wbr, hidden_size_); + + // ar = Xtr * Wr^T + Ht-1r * Rr^T + Wbr + Rbr + // dL/dRbr = dL/dar ---------- (20) + deepcpu::elementwise_sum1(grad_ar, grad_Rbr, hidden_size_); + + // ah = Xth * Wh^T + (rt (.) Ht-1h) * Rh^T + Wbh + Rbh + // dL/dWbh = dL/dah ---------- (21) + deepcpu::elementwise_sum1(grad_ah, grad_Wbh, hidden_size_); + + if (!linear_before_reset_) { + // ah = Xth * Wh^T + (rt (.) Ht-1h) * Rh^T + Wbh + Rbh + // dL/dRbh = dL/dah ---------- (22) + deepcpu::elementwise_sum1(grad_ah, grad_Rbh, hidden_size_); + } else { + // ah = Xth * Wh^T + rt (.) (Ht-1h * Rh^T + Rbh) + Wbh + // dL/dRbh = dL/dah (.) rt ---------- (22) + deepcpu::elementwise_product(grad_ah, rt, grad_Rbh, hidden_size_); + } + } + + // dL/dHt-1 + // Ht-1 -> multiplex gate -> Ht-1z + // -> Ht-1r + // -> Ht-1h + // -> Ht-1H + // dL/dHt-1 = dL/dHt-1z + dL/dHt-1r + dL/dHt-1h + dL/dHt-1H ---------- (23) + float recurrence_input_beta = 1.0f; + + // Ht = (1 - zt) (.) ht + zt (.) Ht-1H + // dL/dHt-1H = dL/dHt (.) zt ---------- (24) + ElementwiseProduct(grad_Ht, zt, grad_Ht, hidden_size_); + + // az = Xtz * Wz^T + Ht-1z * Rz^T + Wbz + Rbz + // dL/dHt-1z = dL/daz * Rz ---------- (25) + // [1, hidden_size_] = [1, hidden_size_] * [hidden_size_, hidden_size_] + // M = 1, N = hidden_size_, K = hidden_size_ + ::onnxruntime::math::Gemm(CblasNoTrans, CblasNoTrans, 1, hidden_size_, + hidden_size_, alpha, grad_az, Rz, recurrence_input_beta, grad_Ht, thread_pool_); + + // ar = Xtr * Wr^T + Ht-1r * Rr^T + Wbr + Rbr + // dL/dHt-1r = dL/dar * Rr ---------- (26) + // [1, hidden_size_] = [1, hidden_size_] * [hidden_size_, hidden_size_] + // M = 1, N = hidden_size_, K = hidden_size_ + ::onnxruntime::math::Gemm(CblasNoTrans, CblasNoTrans, 1, hidden_size_, + hidden_size_, alpha, grad_ar, Rr, recurrence_input_beta, grad_Ht, thread_pool_); + + if (!linear_before_reset_) { + // ah = Xth * Wh^T + (rt (.) Ht-1h) * Rh^T + Wbh + Rbh + // dL/dHt-1h = (dL/dah * Rh) (.) (rt) ---------- (27) + // [1, hidden_size_] = [1, hidden_size_] * [hidden_size_, hidden_size_] + // M = 1, N = hidden_size_, K = hidden_size_ + // We need a temporary buffer to store the result of (dL/dah * Rh). + // Since this is the last step, we can pick any buffer that is not needed anymore (for example grad_ar) + // to store the intermediate result (making sure to clear the results in grad_ar before writing to it). + recurrence_input_beta = 0.0f; + ::onnxruntime::math::Gemm(CblasNoTrans, CblasNoTrans, 1, hidden_size_, + hidden_size_, alpha, grad_ah, Rh, recurrence_input_beta, grad_ar, thread_pool_); + deepcpu::elementwise_product(grad_ar, rt, grad_Ht, hidden_size_); + } else { + // ah = Xth * Wh^T + rt (.) (Ht-1h * Rh^T + Rbh) + Wbh + // dL/dah = G -> dL = G : dah -> dL = G (.) rt : d (Ht-1h * Rh^T) + // dL/dHt-1h = (dL/dah (.) rt) * Rh ---------- (27) + // [1, hidden_size_] = [1, hidden_size_] * [hidden_size_, hidden_size_] + // M = 1, N = hidden_size_, K = hidden_size_ + recurrence_input_beta = 1.0f; + ElementwiseProduct(grad_ah, rt, rt_factor, hidden_size_); + ::onnxruntime::math::Gemm(CblasNoTrans, CblasNoTrans, 1, hidden_size_, + hidden_size_, alpha, rt_factor, Rh, recurrence_input_beta, grad_Ht, thread_pool_); + } + } + } +} + +template class GRUGradImpl; + +} // namespace onnxruntime::gru diff --git a/orttraining/orttraining/training_ops/cpu/rnn/gru_grad_compute.h b/orttraining/orttraining/training_ops/cpu/rnn/gru_grad_compute.h new file mode 100644 index 0000000000000..4a48778c35843 --- /dev/null +++ b/orttraining/orttraining/training_ops/cpu/rnn/gru_grad_compute.h @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "orttraining/training_ops/cpu/rnn/gru_io_utils.h" + +namespace onnxruntime::gru { + +template +class GRUGradImpl { + public: + GRUGradImpl(int sequence_length, int batch_size, int hidden_size, int input_size, + bool linear_before_reset, concurrency::ThreadPool* thread_pool, + AllocatorPtr allocator); + + void ComputeGradient(const GRUGradInputs& inputs, GRUGradOutputs& outputs); + + private: + const int sequence_length_; + const int batch_size_; + const int hidden_size_; + const int input_size_; + const bool linear_before_reset_; + concurrency::ThreadPool* thread_pool_; + const AllocatorPtr allocator_; + IAllocatorUniquePtr grad_a_ptr_; + gsl::span grad_a_span_; + IAllocatorUniquePtr rt_factor_ptr_; + gsl::span rt_factor_span_; + IAllocatorUniquePtr grad_W_ptr_; + gsl::span grad_W_span_; + IAllocatorUniquePtr grad_R_ptr_; + gsl::span grad_R_span_; +}; + +} // namespace onnxruntime::gru diff --git a/orttraining/orttraining/training_ops/cpu/rnn/gru_io_utils.cc b/orttraining/orttraining/training_ops/cpu/rnn/gru_io_utils.cc new file mode 100644 index 0000000000000..007c0284be189 --- /dev/null +++ b/orttraining/orttraining/training_ops/cpu/rnn/gru_io_utils.cc @@ -0,0 +1,297 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "orttraining/training_ops/cpu/rnn/gru_io_utils.h" + +namespace onnxruntime::gru { + +namespace { + +template +rnn::detail::GemmWeights LoadWeights(const Tensor* weights, const int index) { + // index represents the direction of the weight to be loaded. + // For example, + // in a uni-directional gru, index can only ever be 0. + // in a bi-directional gru, index 0 represents forward weights and index 1 represents backward weights + const auto& weights_shape = weights->Shape(); + const auto* weights_data = weights->Data(); + const size_t weights_size_per_direction = SafeInt(weights_shape[1]) * weights_shape[2]; + return rnn::detail::GemmWeights(index, weights_data, weights_size_per_direction, rnn::detail::PackedWeights()); +} + +void ValidateGRUInputs(const Tensor* X, const Tensor* W, const Tensor* R, const Tensor* B, + const Tensor* SL, const Tensor* H0, const int directions, const int hidden_size) { + const auto& X_shape = X->Shape(); + ORT_ENFORCE(X_shape.NumDimensions() == 3U, "Input X must have 3 dimensions only. Actual:", X_shape); + const int batch_size = narrow(X_shape[1]); + const int input_size = narrow(X_shape[2]); + + const auto& W_shape = W->Shape(); + ORT_ENFORCE(W_shape.NumDimensions() == 3U && + narrow(W_shape[0]) == directions && + narrow(W_shape[1]) == 3 * hidden_size && + narrow(W_shape[2]) == input_size, + "Input W must have shape {", directions, ", ", 3 * hidden_size, ", ", input_size, "}. Actual:", W_shape); + + const auto& R_shape = R->Shape(); + ORT_ENFORCE(R_shape.NumDimensions() == 3U && + narrow(R_shape[0]) == directions && + narrow(R_shape[1]) == 3 * hidden_size && + narrow(R_shape[2]) == hidden_size, + "Input R must have shape {", directions, ", ", 3 * hidden_size, ", ", hidden_size, "}. Actual:", R_shape); + + if (B != nullptr) { + const auto& B_shape = B->Shape(); + ORT_ENFORCE(B_shape.NumDimensions() == 2U && + narrow(B_shape[0]) == directions && + narrow(B_shape[1]) == 6 * hidden_size, + "Input B must have shape {", directions, ", ", 6 * hidden_size, "}. Actual:", B_shape); + } + + ORT_ENFORCE(!SL, + "Sequence lengths input tensor (implying varying length input sequence length) " + "is not supported for GRUTraining and GRUGrad. Fixed sequence length can be inferred from the " + "input tensor shape."); + + if (H0 != nullptr) { + const auto& H0_shape = H0->Shape(); + ORT_ENFORCE(H0_shape.NumDimensions() == 3U && + narrow(H0_shape[0]) == directions && + narrow(H0_shape[1]) == batch_size && + narrow(H0_shape[2]) == hidden_size, + "Input H0 must have shape {", directions, ", ", batch_size, ", ", hidden_size, "}. Actual:", H0_shape); + } +} + +void ValidateGRUGradInputs(const Tensor* X, const Tensor* HAll, const Tensor* ZRH, + const Tensor* grad_HAll, const Tensor* grad_Ht, + const int directions, const int hidden_size) { + const auto& X_shape = X->Shape(); + const int sequence_length = narrow(X_shape[0]); + const int batch_size = narrow(X_shape[1]); + + if (HAll != nullptr) { + const auto& HAll_shape = HAll->Shape(); + ORT_ENFORCE(HAll_shape.NumDimensions() == 4U && + narrow(HAll_shape[0]) == sequence_length && + narrow(HAll_shape[1]) == directions && + narrow(HAll_shape[2]) == batch_size && + narrow(HAll_shape[3]) == hidden_size, + "Input HAll must have shape {", sequence_length, ", ", directions, ", ", batch_size, ", ", hidden_size, "}. Actual:", HAll_shape); + } + + if (ZRH != nullptr) { + const auto& ZRH_shape = ZRH->Shape(); + ORT_ENFORCE(ZRH_shape.NumDimensions() == 4U && + narrow(ZRH_shape[0]) == sequence_length && + narrow(ZRH_shape[1]) == directions && + narrow(ZRH_shape[2]) == batch_size && + narrow(ZRH_shape[3]) == 3 * hidden_size, + "Input ZRH must have shape {", sequence_length, ", ", directions, ", ", batch_size, ", ", 3 * hidden_size, "}. Actual:", ZRH_shape); + } + + if (grad_HAll != nullptr) { + const auto& grad_HAll_shape = grad_HAll->Shape(); + ORT_ENFORCE(grad_HAll_shape.NumDimensions() == 4U && + narrow(grad_HAll_shape[0]) == sequence_length && + narrow(grad_HAll_shape[1]) == directions && + narrow(grad_HAll_shape[2]) == batch_size && + narrow(grad_HAll_shape[3]) == hidden_size, + "Input grad_HAll must have shape {", sequence_length, ", ", directions, ", ", batch_size, + ", ", hidden_size, "}. Actual:", grad_HAll_shape); + } + + if (grad_Ht != nullptr) { + const auto& grad_Ht_shape = grad_Ht->Shape(); + ORT_ENFORCE(grad_Ht_shape.NumDimensions() == 3U && + narrow(grad_Ht_shape[0]) == directions && + narrow(grad_Ht_shape[1]) == batch_size && + narrow(grad_Ht_shape[2]) == hidden_size, + "Input grad_Ht must have shape {", directions, ", ", batch_size, ", ", hidden_size, "}. Actual:", grad_Ht_shape); + } +} + +} // namespace + +GRUAttributes::GRUAttributes(const OpKernelInfo& info) { + std::string direction_str = info.GetAttrOrDefault("direction", "forward"); + direction = rnn::detail::MakeDirection(direction_str); + ORT_ENFORCE(direction == rnn::detail::Direction::kForward, + "GRUTraining and GRUGrad kernel only supports the forward direction for now. Provided direction: ", + direction); + num_directions = 1; + + std::vector activation_func_names = info.GetAttrsOrDefault("activations"); + const std::vector activation_func_alphas = info.GetAttrsOrDefault("activation_alpha"); + const std::vector activation_func_betas = info.GetAttrsOrDefault("activation_beta"); + if (activation_func_names.empty()) { + activation_func_names.emplace_back("sigmoid"); + activation_func_names.emplace_back("tanh"); + } + + ORT_ENFORCE(activation_func_names.size() == static_cast(num_directions) * 2U, + "Unexpected number of activation function names provided. Expected: ", num_directions * 2, " Actual: ", activation_func_names.size()); + + ORT_ENFORCE(activation_func_names[0] == "sigmoid", + "GRUTraining and GRUGrad only support the sigmoid function for the f activation parameter."); + ORT_ENFORCE(activation_func_names[1] == "tanh", + "GRUTraining and GRUGrad only support the tanh function for the g activation parameter."); + activation_funcs = rnn::detail::ActivationFuncs(activation_func_names, + activation_func_alphas, + activation_func_betas); + + clip = info.GetAttrOrDefault("clip", std::numeric_limits::max()); + ORT_ENFORCE(clip == std::numeric_limits::max(), "Clip is not supported for GRUTraining and GRUGrad yet."); + + linear_before_reset = info.GetAttrOrDefault("linear_before_reset", 0) == 1; + + int64_t hidden_size_int64_t; + ORT_ENFORCE(info.GetAttr("hidden_size", &hidden_size_int64_t).IsOK() && hidden_size_int64_t > 0); + hidden_size = narrow(hidden_size_int64_t); +} + +template +GRUInputs::GRUInputs(OpKernelContext* context, const int directions, const int hidden_size) { + const Tensor* X = context->Input(0); // input sequence [seq_length, batch_size, input_size] + const Tensor* W = context->Input(1); // weights [directions, 3 * hidden_size, input_size] + const Tensor* R = context->Input(2); // recurrence weights [directions, 3 * hidden_size, hidden_size] + const Tensor* B = context->Input(3); // bias [directions, 6 * hidden_size] + const Tensor* SL = context->Input(4); // sequence lengths [batch_size] + const Tensor* H0 = context->Input(5); // initial hidden state [directions, batch_size, hidden_size] + + ValidateGRUInputs(X, W, R, B, SL, H0, directions, hidden_size); + + input = X->DataAsSpan(); + shape = InputShape{ + narrow(X->Shape()[0]), // sequence length + narrow(X->Shape()[1]), // batch size + narrow(X->Shape()[2]), // input size + }; + + const size_t zr_size_per_direction = 2 * static_cast(hidden_size) * static_cast(hidden_size); + const size_t h_size_per_direction = static_cast(hidden_size) * static_cast(hidden_size); + + weights = LoadWeights(W, 0); + auto recurrence_weights = R->DataAsSpan(); + auto recurrence_weights_zr_span = recurrence_weights.subspan(0, zr_size_per_direction); + auto recurrence_weights_h_span = recurrence_weights.subspan(zr_size_per_direction, h_size_per_direction); + recurrence_weights_zr.Init(0, recurrence_weights_zr_span.data(), + recurrence_weights_zr_span.size(), + rnn::detail::PackedWeights(), nullptr); + recurrence_weights_h.Init(0, recurrence_weights_h_span.data(), + recurrence_weights_h_span.size(), + rnn::detail::PackedWeights(), nullptr); + bias = B ? B->DataAsSpan() : gsl::span(); + sequence_lengths = SL ? SL->DataAsSpan() : gsl::span(); + initial_hidden_state = H0 ? H0->DataAsSpan() : gsl::span(); +} + +template +GRUOutputs::GRUOutputs(OpKernelContext* context, const int directions, const int sequence_length, + const int batch_size, const int hidden_size) { + const TensorShape HAll_shape{sequence_length, directions, batch_size, hidden_size}; // [seq_length, directions, batch_size, hidden_size] + Tensor* HAll = context->Output(0, HAll_shape); // all hidden states + const TensorShape Ht_shape{directions, batch_size, hidden_size}; // [directions, batch_size, hidden_size] + Tensor* Ht = context->Output(1, Ht_shape); // final hidden state + const int64_t hidden_size_x3 = static_cast(3) * static_cast(hidden_size); + const TensorShape ZRH_shape{sequence_length, directions, batch_size, hidden_size_x3}; // [seq_length, directions, batch_size, 3 * hidden_size] + Tensor* ZRH = context->Output(2, ZRH_shape); // zrh gate computations + + AllocatorPtr alloc; + ORT_THROW_IF_ERROR(context->GetTempSpaceAllocator(&alloc)); + + ORT_ENFORCE(HAll, "All hidden states output is required for GRUTraining to compute gradients."); + all_hidden_states = HAll->MutableDataAsSpan(); + const size_t final_state_size = static_cast(directions) * static_cast(batch_size) * + static_cast(hidden_size); + final_hidden_state = Ht ? Ht->MutableDataAsSpan() + : rnn::detail::Allocate(alloc, final_state_size, + h_final_ptr_, true, static_cast(0)); + + ORT_ENFORCE(ZRH, "z, r, h gate computation output is required for GRUTraining to compute gradients."); + zrh = ZRH->MutableDataAsSpan(); +} + +template +GRUGradInputs::GRUGradInputs(OpKernelContext* context, const int directions, const int hidden_size) { + const Tensor* X = context->Input(0); // input sequence [seq_length, batch_size, input_size] + const Tensor* W = context->Input(1); // weights [directions, 3 * hidden_size, input_size] + const Tensor* R = context->Input(2); // recurrence weights [directions, 3 * hidden_size, hidden_size] + const Tensor* B = context->Input(3); // bias [directions, 6 * hidden_size] + const Tensor* SL = context->Input(4); // sequence lengths [batch_size] + const Tensor* H0 = context->Input(5); // initial hidden state [directions, batch_size, hidden_size] + const Tensor* HAll = context->Input(6); // all hidden states [seq_length, directions, batch_size, hidden_size] + const Tensor* ZRH = context->Input(7); // zrh gate computations [seq_length, directions, batch_size, 3 * hidden_size] + const Tensor* grad_HAll = context->Input(8); // grad w.r.t all hidden states [seq_length, directions, batch_size, hidden_size] + const Tensor* grad_Ht = context->Input(9); // grad w.r.t final hidden state [directions, batch_size, hidden_size] + + ValidateGRUInputs(X, W, R, B, SL, H0, directions, hidden_size); + ValidateGRUGradInputs(X, HAll, ZRH, grad_HAll, grad_Ht, directions, hidden_size); + + AllocatorPtr alloc; + ORT_THROW_IF_ERROR(context->GetTempSpaceAllocator(&alloc)); + + input = X->DataAsSpan(); + shape = InputShape{ + narrow(X->Shape()[0]), // sequence length + narrow(X->Shape()[1]), // batch size + narrow(X->Shape()[2]), // input size + }; + + weights = W->DataAsSpan(); + recurrence_weights = R->DataAsSpan(); + bias = B ? B->DataAsSpan() : gsl::span(); + sequence_lengths = SL ? SL->DataAsSpan() : gsl::span(); + const size_t initial_state_size = static_cast(directions) * static_cast(shape.batch_size) * + static_cast(hidden_size); + initial_hidden_state = H0 ? H0->DataAsSpan() + : rnn::detail::Allocate(alloc, initial_state_size, + initial_hidden_state_ptr_, true, static_cast(0)); + + ORT_ENFORCE(HAll, "All hidden states input to GRUGrad must exist to compute the gradients."); + all_hidden_states = HAll->DataAsSpan(); + + ORT_ENFORCE(ZRH, "z, r, h gate computation input to GRUGrad must exist to compute the gradients."); + zrh = ZRH->DataAsSpan(); + + grad_all_hidden_states = grad_HAll ? grad_HAll->DataAsSpan() : gsl::span(); + grad_final_hidden_state = grad_Ht ? grad_Ht->DataAsSpan() : gsl::span(); +} + +template +GRUGradOutputs::GRUGradOutputs(OpKernelContext* context, const int directions, const int sequence_length, + const int batch_size, const int hidden_size, const int input_size) { + // Outputs of the gradient kernel + const TensorShape dX_shape{sequence_length, batch_size, input_size}; // [seq_length, batch_size, input_size] + Tensor* dX = context->Output(0, dX_shape); // gradient w.r.t to the input X + const int64_t hidden_sizex3 = static_cast(3) * static_cast(hidden_size); + const TensorShape dW_shape{directions, hidden_sizex3, input_size}; // [directions, 3 * hidden_size, input_size] + Tensor* dW = context->Output(1, dW_shape); // gradient w.r.t to the input weights W + const TensorShape dR_shape{directions, hidden_sizex3, hidden_size}; // [directions, 3 * hidden_size, hidden_size] + Tensor* dR = context->Output(2, dR_shape); // gradient w.r.t to the recurrence weights R + const int64_t hidden_sizex6 = static_cast(6) * static_cast(hidden_size); + const TensorShape dB_shape{directions, hidden_sizex6}; // [directions, 6 * hidden_size] + Tensor* dB = context->Output(3, dB_shape); // gradient w.r.t to the bias + const TensorShape dH0_shape{directions, batch_size, hidden_size}; // [directions, batch_size, hidden_size] + Tensor* dH0 = context->Output(4, dH0_shape); // gradient w.r.t to the initial hidden state + + AllocatorPtr alloc; + ORT_THROW_IF_ERROR(context->GetTempSpaceAllocator(&alloc)); + + grad_input = dX ? dX->MutableDataAsSpan() : gsl::span(); + grad_weights = dW->MutableDataAsSpan(); + grad_recurrence_weights = dR->MutableDataAsSpan(); + grad_bias = dB ? dB->MutableDataAsSpan() : gsl::span(); + const size_t initial_state_size = static_cast(directions) * static_cast(batch_size) * + static_cast(hidden_size); + grad_initial_hidden_state = dH0 ? dH0->MutableDataAsSpan() + : rnn::detail::Allocate(alloc, initial_state_size, + grad_initial_hidden_state_ptr_, true, static_cast(0)); +} + +template struct GRUInputs; +template struct GRUOutputs; +template struct GRUGradInputs; +template struct GRUGradOutputs; + +} // namespace onnxruntime::gru diff --git a/orttraining/orttraining/training_ops/cpu/rnn/gru_io_utils.h b/orttraining/orttraining/training_ops/cpu/rnn/gru_io_utils.h new file mode 100644 index 0000000000000..0cb4cec3c1209 --- /dev/null +++ b/orttraining/orttraining/training_ops/cpu/rnn/gru_io_utils.h @@ -0,0 +1,103 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/framework/op_kernel.h" +#include "core/providers/cpu/rnn/rnn_helpers.h" + +namespace onnxruntime::gru { + +struct GRUAttributes { + GRUAttributes(const OpKernelInfo& info); + + GRUAttributes() = delete; + + rnn::detail::Direction direction; + int num_directions; + rnn::detail::ActivationFuncs activation_funcs; + float clip; + int linear_before_reset; + int hidden_size; +}; + +struct InputShape { + int sequence_length; + int batch_size; + int input_size; +}; + +template +struct GRUInputs { + GRUInputs(OpKernelContext* context, const int directions, const int hidden_size); + + GRUInputs() = delete; + + gsl::span input; + InputShape shape; + rnn::detail::GemmWeights weights; + rnn::detail::GemmWeights recurrence_weights_zr; + rnn::detail::GemmWeights recurrence_weights_h; + gsl::span bias; + gsl::span sequence_lengths; + gsl::span initial_hidden_state; +}; + +template +struct GRUOutputs { + GRUOutputs(OpKernelContext* context, const int directions, const int sequence_length, + const int batch_size, const int hidden_size); + + GRUOutputs() = delete; + + gsl::span all_hidden_states; + gsl::span final_hidden_state; + gsl::span zrh; + + private: + IAllocatorUniquePtr hall_ptr_; + IAllocatorUniquePtr h_final_ptr_; + IAllocatorUniquePtr zrh_ptr_; +}; + +template +struct GRUGradInputs { + GRUGradInputs(OpKernelContext* context, const int directions, const int hidden_size); + + GRUGradInputs() = delete; + + gsl::span input; + InputShape shape; + gsl::span weights; + gsl::span recurrence_weights; + gsl::span bias; + gsl::span sequence_lengths; + gsl::span initial_hidden_state; + gsl::span all_hidden_states; + gsl::span zrh; + gsl::span grad_all_hidden_states; + gsl::span grad_final_hidden_state; + + private: + IAllocatorUniquePtr initial_hidden_state_ptr_; + IAllocatorUniquePtr grad_final_hidden_state_ptr_; +}; + +template +struct GRUGradOutputs { + GRUGradOutputs(OpKernelContext* context, const int directions, const int sequence_length, + const int batch_size, const int hidden_size, const int input_size); + + GRUGradOutputs() = delete; + + gsl::span grad_input; + gsl::span grad_weights; + gsl::span grad_recurrence_weights; + gsl::span grad_bias; + gsl::span grad_initial_hidden_state; + + private: + IAllocatorUniquePtr grad_initial_hidden_state_ptr_; +}; + +} // namespace onnxruntime::gru diff --git a/orttraining/orttraining/training_ops/cpu/rnn/lstm_grad_compute.h b/orttraining/orttraining/training_ops/cpu/rnn/lstm_grad_compute.h index 2c66524a60028..ed73a0371223d 100644 --- a/orttraining/orttraining/training_ops/cpu/rnn/lstm_grad_compute.h +++ b/orttraining/orttraining/training_ops/cpu/rnn/lstm_grad_compute.h @@ -3,7 +3,6 @@ #pragma once -#include "core/providers/cpu/rnn/rnn_helpers.h" #include "orttraining/training_ops/cpu/rnn/lstm_io_utils.h" namespace onnxruntime::lstm { @@ -22,7 +21,7 @@ class LSTMGradImpl { const int hidden_size_; const int input_size_; concurrency::ThreadPool* thread_pool_; - AllocatorPtr allocator_; + const AllocatorPtr allocator_; IAllocatorUniquePtr grad_a_ptr_; gsl::span grad_a_span_; IAllocatorUniquePtr grad_Ct2_ptr_; diff --git a/orttraining/orttraining/training_ops/cpu/tensor/concat.cc b/orttraining/orttraining/training_ops/cpu/tensor/concat.cc index 4639adce67e6b..d58a0d261b1a5 100644 --- a/orttraining/orttraining/training_ops/cpu/tensor/concat.cc +++ b/orttraining/orttraining/training_ops/cpu/tensor/concat.cc @@ -2,6 +2,7 @@ // Licensed under the MIT License. #include "orttraining/training_ops/cpu/tensor/concat.h" +#include "core/common/narrow.h" #include "core/providers/common.h" #include "core/framework/TensorSeq.h" @@ -44,7 +45,7 @@ Status ConcatTraining::Compute(OpKernelContext* ctx) const { if (per_input_length_tensor) { int64_t* per_input_length = per_input_length_tensor->template MutableData(); for (int i = 0; i < input_count; ++i) { - per_input_length[i] = input_tensors[i]->Shape()[p.axis]; + per_input_length[i] = input_tensors[i]->Shape()[narrow(p.axis)]; } } // Compute values to be placed in the output tensor diff --git a/orttraining/orttraining/training_ops/cpu/tensor/gather_elements_grad.cc b/orttraining/orttraining/training_ops/cpu/tensor/gather_elements_grad.cc index fa62f6a0e125d..84346d2314db2 100644 --- a/orttraining/orttraining/training_ops/cpu/tensor/gather_elements_grad.cc +++ b/orttraining/orttraining/training_ops/cpu/tensor/gather_elements_grad.cc @@ -34,7 +34,7 @@ ONNX_OPERATOR_KERNEL_EX( Status GatherElementsGrad::Compute(OpKernelContext* context) const { const auto* dY = context->Input(0); const Tensor* shape = context->Input(1); - const TensorShape data_shape(shape->template Data(), shape->Shape().Size()); + const TensorShape data_shape(shape->template DataAsSpan()); const int axis = static_cast(HandleNegativeAxis(axis_, data_shape.NumDimensions())); diff --git a/orttraining/orttraining/training_ops/cpu/tensor/gather_grad.cc b/orttraining/orttraining/training_ops/cpu/tensor/gather_grad.cc index 44d72def52c9f..9e60a4725cb06 100644 --- a/orttraining/orttraining/training_ops/cpu/tensor/gather_grad.cc +++ b/orttraining/orttraining/training_ops/cpu/tensor/gather_grad.cc @@ -3,6 +3,7 @@ #include "orttraining/training_ops/cpu/tensor/gather_grad.h" #include "core/common/common.h" +#include "core/common/narrow.h" #include "core/platform/threadpool.h" namespace onnxruntime { @@ -37,7 +38,7 @@ Status GatherGrad::Compute(OpKernelContext* context) const { const Tensor& indices = *context->Input(1); const Tensor& grad = *context->Input(2); - const TensorShape data_shape(shape.template Data(), shape.Shape().Size()); + const TensorShape data_shape(shape.template DataAsSpan()); Tensor& output = *context->Output(0, data_shape); memset(output.MutableDataRaw(), 0, output.SizeInBytes()); @@ -56,13 +57,13 @@ Status GatherGrad::ComputeImpl(const TensorShape& data_shape, const Tensor& indi const T* grad_data = grad.template Data(); T* output_data = output.template MutableData(); - const int64_t axis = HandleNegativeAxis(axis_, data_shape.NumDimensions()); + const auto axis = narrow(HandleNegativeAxis(axis_, data_shape.NumDimensions())); const int64_t block_size = data_shape.SizeFromDimension(axis + 1); const int64_t N = indices.Shape().Size(); const int64_t input_block_size = data_shape.SizeFromDimension(axis); const int64_t output_block_size = N * block_size; const int64_t indices_max = data_shape[axis]; - const int64_t grad_size = grad.Shape().Size(); + const auto grad_size = narrow(grad.Shape().Size()); // Check the indices first in case there's a out of bound index. // All index values are expected to be within bounds [-s, s-1] along axis of size s. diff --git a/orttraining/orttraining/training_ops/cpu/tensor/gather_nd_grad.cc b/orttraining/orttraining/training_ops/cpu/tensor/gather_nd_grad.cc index ee4e3581d7201..0328772b4f5ec 100644 --- a/orttraining/orttraining/training_ops/cpu/tensor/gather_nd_grad.cc +++ b/orttraining/orttraining/training_ops/cpu/tensor/gather_nd_grad.cc @@ -24,12 +24,12 @@ ONNX_OPERATOR_KERNEL_EX(GatherNDGrad, kMSDomain, 1, kCpuExecutionProvider, template struct GatherNDGradComputeImpl { void operator()(GatherNDBase::Prepare& p, const Tensor* update_tensor) const { - const int64_t grad_size = update_tensor->Shape().Size(); - const int64_t slice_size = p.element_count_per_slice; + const size_t grad_size = narrow(update_tensor->Shape().Size()); + const size_t slice_size = narrow(p.element_count_per_slice); const InputT* input_base_casted = reinterpret_cast(p.input_base); InputT* output_base_casted = reinterpret_cast(p.output_base); - for (int64_t i = 0; i < grad_size; i++) { + for (size_t i = 0; i < grad_size; i++) { uint64_t slice_offset = p.slice_offsets[i / slice_size]; size_t j = i % slice_size; output_base_casted[slice_offset + j] += input_base_casted[i]; diff --git a/orttraining/orttraining/training_ops/cpu/tensor/slice_grad.cc b/orttraining/orttraining/training_ops/cpu/tensor/slice_grad.cc index 68e4110b2b9bd..79139a60f1779 100644 --- a/orttraining/orttraining/training_ops/cpu/tensor/slice_grad.cc +++ b/orttraining/orttraining/training_ops/cpu/tensor/slice_grad.cc @@ -24,7 +24,7 @@ ONNX_OPERATOR_KERNEL_EX( Status SliceGrad::Compute(OpKernelContext* context) const { const Tensor& grad = *context->Input(0); const Tensor& shape = *context->Input(1); - const TensorShape data_shape(shape.template Data(), shape.Shape().Size()); + const TensorShape data_shape(shape.template DataAsSpan()); Tensor& output = *context->Output(0, data_shape); memset(output.MutableDataRaw(), 0, output.SizeInBytes()); // Initialize the starts & ends to the actual tensor shape diff --git a/orttraining/orttraining/training_ops/cpu/tensor/split.cc b/orttraining/orttraining/training_ops/cpu/tensor/split.cc index fb31e6c3e52f2..d361f3ec64e39 100644 --- a/orttraining/orttraining/training_ops/cpu/tensor/split.cc +++ b/orttraining/orttraining/training_ops/cpu/tensor/split.cc @@ -26,15 +26,15 @@ Status PrepareForTrainingCompute(const TensorShape& input_shape, int num_outputs std::vector& split_sizes) { auto input_dims = input_shape.GetDims(); const auto num_dimensions = gsl::narrow_cast(input_shape.NumDimensions()); - int64_t axis_value = axis; - axis = HandleNegativeAxis(axis_value, num_dimensions); // handle negative and enforce axis is valid - const int64_t split_dim_size = input_dims[axis]; + const int64_t original_axis_value = axis; + axis = HandleNegativeAxis(original_axis_value, num_dimensions); // handle negative and enforce axis is valid + const int64_t split_dim_size = input_dims[gsl::narrow_cast(axis)]; - before_dims = narrow(input_shape.SizeToDimension(axis)); - after_dims_including_split_axis = narrow(input_shape.SizeFromDimension(axis)); + before_dims = narrow(input_shape.SizeToDimension(gsl::narrow_cast(axis))); + after_dims_including_split_axis = narrow(input_shape.SizeFromDimension(gsl::narrow_cast(axis))); after_dims_excluding_split = (axis + 1 == num_dimensions) ? 1 // we multiply by this value so must be 1 not 0 - : narrow(input_shape.SizeFromDimension(axis + 1)); + : narrow(input_shape.SizeFromDimension(gsl::narrow_cast(axis) + 1)); std::vector split_sizes_values(split_sizes); split_sizes.clear(); @@ -44,7 +44,7 @@ Status PrepareForTrainingCompute(const TensorShape& input_shape, int num_outputs // equal split based on number of outputs if (split_dim_size % static_cast(num_outputs) != 0) { return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Input cannot be split evenly on selected axis. Input shape=", input_shape, - " Axis=", axis_value, " NumOutputs=", num_outputs); + " Axis=", original_axis_value, " NumOutputs=", num_outputs); } // populate split_sizes with the same size for each output @@ -52,7 +52,7 @@ Status PrepareForTrainingCompute(const TensorShape& input_shape, int num_outputs } else { if (split_sizes_values.size() != static_cast(num_outputs) || split_size_sum != split_dim_size) { return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, - "Cannot split using values in 'split' input. Axis=", axis_value, + "Cannot split using values in 'split' input. Axis=", original_axis_value, " Input shape=", input_shape, " NumOutputs=", num_outputs, " Num entries in 'split' (must equal number of outputs) was ", split_sizes_values.size(), @@ -127,7 +127,7 @@ Status SplitTraining::ComputeImpl(OpKernelContext& context, const Tensor& input) for (int i = 0; i < num_outputs; ++i) { // update size of dimension for axis we're splitting on auto split_size = narrow(split_sizes[i]); - output_dimensions[axis] = split_size; + output_dimensions[gsl::narrow_cast(axis)] = split_size; Tensor* output = context.Output(i, TensorShape{output_dimensions}); T* output_data = output->template MutableData(); diff --git a/orttraining/orttraining/training_ops/cpu/torch/torch_custom_function_kernel_base.cc b/orttraining/orttraining/training_ops/cpu/torch/torch_custom_function_kernel_base.cc index faaee0cb3a2a5..e1d4be24861f5 100644 --- a/orttraining/orttraining/training_ops/cpu/torch/torch_custom_function_kernel_base.cc +++ b/orttraining/orttraining/training_ops/cpu/torch/torch_custom_function_kernel_base.cc @@ -2,6 +2,10 @@ // Licensed under the MIT License. #ifdef ENABLE_TRAINING_TORCH_INTEROP +#include +#include +#include + #include "orttraining/core/framework/torch/python_common.h" #ifndef SHARED_PROVIDER #include "core/framework/op_kernel_context_internal.h" @@ -15,19 +19,36 @@ using namespace onnxruntime::language_interop_ops::torch; namespace onnxruntime { namespace contrib { -std::vector CreateOrtValueArgs(OpKernelContext* context, - const size_t begin_index, - const size_t num_arg) { +namespace { + +std::string GetInvokeIdString(const void* ptr) { + const auto now = std::chrono::high_resolution_clock::now(); + std::ostringstream oss; + oss << std::this_thread::get_id() << "-" + << std::chrono::duration_cast(now.time_since_epoch()).count() + << "-" << std::rand() % 1000000 << "-" << reinterpret_cast(ptr); + return oss.str(); +} + +std::vector> CreateOrtValueArgs(OpKernelContext* context, + const int begin_index, + const int num_arg) { auto* ctx_internal = reinterpret_cast(context); - std::vector args; - for (size_t i = 0; i < num_arg; ++i) { - args.push_back(*ctx_internal->GetInputMLValue(static_cast(begin_index + i))); + std::vector> args; + for (int i = 0; i < num_arg; ++i) { + int input_index = begin_index + i; + if (context->Input(input_index)) { + args.push_back(*ctx_internal->GetInputMLValue(input_index)); + } else { // if the grad input is not provided. + args.push_back(std::nullopt); + } } return args; } +} // namespace void PythonOpBase::Init(const OpKernelInfo& info) { - ORT_THROW_IF_ERROR(info.GetAttr("name", &name_)); + ORT_THROW_IF_ERROR(info.GetAttr("func_name", &name_)); ORT_THROW_IF_ERROR(info.GetAttr("inplace", &inplace_)); is_training_mode_ = static_cast(info.GetAttrOrDefault("training_mode", static_cast(0))); @@ -41,6 +62,12 @@ void PythonOpBase::Init(const OpKernelInfo& info) { ORT_ENFORCE(input_tensor_types_.size() == info.node().InputDefs().size()); + // Input bool scalars. + input_bool_scalars_ = info.GetAttrsOrDefault("input_bool_scalars", std::vector()); + input_bool_scalar_positions_ = info.GetAttrsOrDefault("input_bool_scalar_positions", std::vector()); + + ORT_ENFORCE(input_bool_scalars_.size() == input_bool_scalar_positions_.size()); + // Input int scalars. input_int_scalars_ = info.GetAttrsOrDefault("input_int_scalars", std::vector()); input_int_scalar_positions_ = info.GetAttrsOrDefault("input_int_scalar_positions", std::vector()); @@ -53,6 +80,13 @@ void PythonOpBase::Init(const OpKernelInfo& info) { ORT_ENFORCE(input_float_scalars_.size() == input_float_scalar_positions_.size()); + // Input bool tuples. + input_bool_tuples_ = info.GetAttrsOrDefault("input_bool_tuples", std::vector()); + input_bool_tuple_positions_ = info.GetAttrsOrDefault("input_bool_tuple_positions", std::vector()); + input_bool_tuple_begins_ = info.GetAttrsOrDefault("input_bool_tuple_begins", std::vector()); + + ORT_ENFORCE(input_bool_tuple_positions_.size() == input_bool_tuple_begins_.size()); + // Input int tuples. input_int_tuples_ = info.GetAttrsOrDefault("input_int_tuples", std::vector()); input_int_tuple_positions_ = info.GetAttrsOrDefault("input_int_tuple_positions", std::vector()); @@ -71,8 +105,11 @@ void PythonOpBase::Init(const OpKernelInfo& info) { input_pointer_scalar_positions_ = info.GetAttrsOrDefault("input_pointer_scalar_positions", std::vector()); ORT_ENFORCE(input_pointer_scalars_.size() == input_pointer_scalar_positions_.size()); - auto non_tensor_input_count = input_int_scalars_.size() + input_float_scalars_.size() + - input_int_tuple_positions_.size() + input_float_tuple_positions_.size() + + auto non_tensor_input_count = input_bool_scalars_.size() + input_int_scalars_.size() + + input_float_scalars_.size() + + input_bool_tuple_positions_.size() + + input_int_tuple_positions_.size() + + input_float_tuple_positions_.size() + input_pointer_scalars_.size(); ORT_ENFORCE(non_tensor_input_count + input_tensor_types_.size() == input_convention_.size(), "Total input (tensor + non-tensor) count did not match."); @@ -82,6 +119,8 @@ void PythonOpBase::Init(const OpKernelInfo& info) { CreateConstArgs(); CreateArgPositions(); + + kernel_invoke_id_ = GetInvokeIdString(this); } void PythonOpBase::Clear() { @@ -99,7 +138,7 @@ void PythonOpBase::RunForward(OpKernelContext* context, std::vector& returned_ortvalues) const { // Create non-constant arguments for calling Python function. // Constant arguments are created in ctor. - std::vector args = CreateOrtValueArgs(context, 0, context->InputCount()); + std::vector> args = CreateOrtValueArgs(context, 0, context->InputCount()); // Invoke Python calls. TorchProxy::GetInstance().Forward( OrtTorchFunctionPool::GetInstance().GetForwardCore(name_), @@ -111,10 +150,14 @@ void PythonOpBase::RunForward(OpKernelContext* context, diff_ctx, returned_ortvalues, is_training_mode_, - inplace_ != 0); - - ORT_ENFORCE(1 + returned_ortvalues.size() == static_cast(context->OutputCount()), - "Output count mismatch for PythonOp run"); + inplace_ != 0, + kernel_invoke_id_); + + const size_t returned_output_count = 1 + returned_ortvalues.size(); + const size_t kernel_output_count = static_cast(context->OutputCount()); + ORT_ENFORCE(returned_output_count == kernel_output_count, "Output count mismatch for PythonOp run, ", + "returned_output_count: ", returned_output_count, ", expected kernel_output_count: ", + kernel_output_count); } void PythonOpBase::SetOutputs(OpKernelContext* context, void* diff_ctx, std::vector& returned_args) const { @@ -122,7 +165,11 @@ void PythonOpBase::SetOutputs(OpKernelContext* context, void* diff_ctx, std::vec SetOtherOutputs(context, returned_args); } -void PythonOpBase::AddIntScalarArgs() { +void PythonOpBase::AddPrimitiveTypeScalarArgs() { + for (size_t i = 0; i < input_bool_scalars_.size(); ++i) { + const_arg_set_.Add(input_bool_scalar_positions_.at(i), PyBool_FromLong(input_bool_scalars_.at(i)), true /*owned*/); + } + for (size_t i = 0; i < input_int_scalars_.size(); ++i) { const_arg_set_.Add(input_int_scalar_positions_.at(i), Py_BuildValue("L", static_cast(input_int_scalars_.at(i))), @@ -136,6 +183,22 @@ void PythonOpBase::AddIntScalarArgs() { } void PythonOpBase::AddInputTupleArgs() { + for (size_t i = 0; i < input_bool_tuple_begins_.size(); ++i) { + // Process i-th tuple. + // Starting index of i-th tuple in the concatenation buffer. + const size_t begin = input_bool_tuple_begins_.at(i); + // Endding (exclusive) index of i-th tuple in the concatenation buffer. + const size_t end = + (i + 1 == input_bool_tuple_begins_.size()) ? input_bool_tuples_.size() : input_bool_tuple_begins_.at(i + 1); + PyObject* tuple = PyTuple_New(end - begin); + for (size_t j = begin; j < end; ++j) { + PyObject* item = PyBool_FromLong(input_bool_tuples_.at(j)); + PyTuple_SetItem(tuple, j - begin, item); + } + + const_arg_set_.Add(input_bool_tuple_positions_.at(i), tuple, true /*owned*/); + } + for (size_t i = 0; i < input_int_tuple_begins_.size(); ++i) { // Process i-th tuple. // Starting index of i-th tuple in the concatenation buffer. @@ -183,7 +246,7 @@ void PythonOpBase::AddPointerScalarArgs() { void PythonOpBase::CreateConstArgs() { ORT_ENFORCE(const_arg_set_.Size() == 0); - AddIntScalarArgs(); + AddPrimitiveTypeScalarArgs(); AddInputTupleArgs(); AddFloatTupleArgs(); AddPointerScalarArgs(); @@ -234,7 +297,7 @@ void PythonOpBase::SetOtherOutputs(OpKernelContext* context, std::vector& returned_ortvalues) const { - auto args = CreateOrtValueArgs(context, 1, context->InputCount() - 1); + std::vector> args = CreateOrtValueArgs(context, 1, context->InputCount() - 1); // This is called "const" because that's how Pytorch calls all non-tensor inputs. const Tensor* context_id_tensor = context->Input(0); ORT_ENFORCE(context_id_tensor, "Context ID (first input) should not be null."); @@ -265,7 +330,8 @@ void PythonOpGradBase::RunBackward(OpKernelContext* context, const_args, const_arg_positions_, returned_ortvalues, - inplace_ != 0); + inplace_ != 0, + kernel_invoke_id_); OrtTorchFunctionPool::GetInstance().UnregisterContext(*context_index_ptr); } diff --git a/orttraining/orttraining/training_ops/cpu/torch/torch_custom_function_kernel_base.h b/orttraining/orttraining/training_ops/cpu/torch/torch_custom_function_kernel_base.h index a9cb4960b9240..1657bf49ea2e6 100644 --- a/orttraining/orttraining/training_ops/cpu/torch/torch_custom_function_kernel_base.h +++ b/orttraining/orttraining/training_ops/cpu/torch/torch_custom_function_kernel_base.h @@ -18,10 +18,6 @@ namespace onnxruntime { namespace contrib { -std::vector CreateOrtValueArgs(OpKernelContext* context, - const size_t begin_index, - const size_t num_arg); - class PythonOpBase { public: PythonOpBase(const OpKernelInfo& info) { @@ -120,14 +116,23 @@ class PythonOpBase { // Types. input_tensor_types_[i] is the element type of the i-th tensor. std::vector input_tensor_types_; - // Concatenation of all floats from apply(...) 's inputs. + // Concatenation of all bools from apply(...) 's inputs. + std::vector input_bool_scalars_; + std::vector input_bool_scalar_positions_; + + // Concatenation of all ints from apply(...) 's inputs. std::vector input_int_scalars_; std::vector input_int_scalar_positions_; - // Concatenation of all ints from apply(...) 's inputs. + // Concatenation of all floats from apply(...) 's inputs. std::vector input_float_scalars_; std::vector input_float_scalar_positions_; + // Concatenation of all bool tuples from apply(...) 's inputs. + std::vector input_bool_tuples_; + std::vector input_bool_tuple_positions_; + std::vector input_bool_tuple_begins_; + // Concatenation of all int tuples from apply(...) 's inputs. std::vector input_int_tuples_; std::vector input_int_tuple_positions_; @@ -145,7 +150,7 @@ class PythonOpBase { std::vector output_tensor_types_; private: - void AddIntScalarArgs(); + void AddPrimitiveTypeScalarArgs(); void AddInputTupleArgs(); void AddFloatTupleArgs(); void AddPointerScalarArgs(); @@ -154,6 +159,8 @@ class PythonOpBase { void SetContextOutput(OpKernelContext* context, void* diff_ctx) const; void SetOtherOutputs(OpKernelContext* context, std::vector& returned_args) const; + + std::string kernel_invoke_id_; }; class PythonOpGradBase { @@ -185,6 +192,8 @@ class PythonOpGradBase { private: void SetPositions(); + + std::string kernel_invoke_id_; }; } // namespace contrib diff --git a/orttraining/orttraining/training_ops/cpu/triton/triton_op.cc b/orttraining/orttraining/training_ops/cpu/triton/triton_op.cc new file mode 100644 index 0000000000000..28f4ff665f797 --- /dev/null +++ b/orttraining/orttraining/training_ops/cpu/triton/triton_op.cc @@ -0,0 +1,74 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifdef ENABLE_TRITON + +#include "orttraining/training_ops/cpu/triton/triton_op.h" + +#ifndef SHARED_PROVIDER +#include "core/framework/op_kernel_context_internal.h" +#endif +#include "orttraining/core/framework/triton/triton_op_executor.h" + +namespace onnxruntime { +namespace contrib { + +InlinedHashSet TritonOp::GetBoolOutputs(size_t output_size) const { + InlinedHashSet bool_outputs; + for (size_t i = 0; i < output_size; ++i) { + ORT_ENFORCE(i < Node().OutputDefs().size(), "Output index out of range."); + if (Node().OutputDefs()[i]->TypeAsProto()->tensor_type().elem_type() == + ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_BOOL) { + bool_outputs.insert(i); + } + } + return bool_outputs; +} + +Status TritonOp::Compute(OpKernelContext* context) const { + auto* p_ctx_internal = reinterpret_cast(context); + size_t input_size = static_cast(p_ctx_internal->InputCount()); + size_t output_size = static_cast(p_ctx_internal->OutputCount()); + InlinedVector inputs; + for (size_t i = 0; i < input_size; ++i) { + inputs.emplace_back(p_ctx_internal->GetInputMLValue(static_cast(i))); + } + InlinedVector outputs; + InlinedHashSet bool_outputs = GetBoolOutputs(output_size); + auto& executor = training::framework::triton::TritonOpExecutor::Instance(); + if (func_name_ != "") { + executor.ExecuteByFuncName(func_name_, inputs, outputs, bool_outputs); + } else { + executor.ExecuteByOnnx(onnx_key_, onnx_string_, inputs, outputs, bool_outputs); + } + ORT_ENFORCE(output_size == outputs.size()); + for (size_t i = 0; i < output_size; ++i) { + ORT_THROW_IF_ERROR(p_ctx_internal->SetOutputMLValue(static_cast(i), outputs[i])); + } + return Status::OK(); +} + +bool IsTritonOpExecutorInitialized() { + return training::framework::triton::TritonOpExecutor::Instance().IsInitialized(); +} + +Status ExecuteTritonOpByFuncName(OpKernelContext* p_ctx, const std::string& func_name, size_t input_count, + size_t output_count, + const InlinedHashMap>& kwargs) { + auto* p_ctx_internal = reinterpret_cast(p_ctx); + InlinedVector inputs; + for (size_t i = 0; i < input_count; ++i) { + inputs.emplace_back(p_ctx_internal->GetInputMLValue(static_cast(i))); + } + for (size_t i = 0; i < output_count; ++i) { + inputs.emplace_back(p_ctx_internal->GetOutputMLValue(static_cast(i))); + } + InlinedVector outputs; + training::framework::triton::TritonOpExecutor::Instance().ExecuteByFuncName(func_name, inputs, outputs, {}, kwargs); + return Status::OK(); +} + +} // namespace contrib +} // namespace onnxruntime + +#endif diff --git a/orttraining/orttraining/training_ops/cpu/triton/triton_op.h b/orttraining/orttraining/training_ops/cpu/triton/triton_op.h new file mode 100644 index 0000000000000..25e7b1f15ff6b --- /dev/null +++ b/orttraining/orttraining/training_ops/cpu/triton/triton_op.h @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifdef ENABLE_TRITON + +#pragma once + +#ifndef SHARED_PROVIDER +#include "core/framework/op_kernel.h" +#endif + +namespace onnxruntime { +namespace contrib { + +class TritonOp final : public OpKernel { + public: + TritonOp(const OpKernelInfo& info) : OpKernel(info) { + ORT_THROW_IF_ERROR(info.GetAttr("func_name", &func_name_)); + ORT_THROW_IF_ERROR(info.GetAttr("onnx_key", &onnx_key_)); + ORT_THROW_IF_ERROR(info.GetAttr("onnx_string", &onnx_string_)); + } + + Status Compute(OpKernelContext* context) const override; + + private: + InlinedHashSet GetBoolOutputs(size_t output_size) const; + + std::string func_name_; + int64_t onnx_key_; + std::string onnx_string_; +}; + +bool IsTritonOpExecutorInitialized(); +Status ExecuteTritonOpByFuncName(OpKernelContext* p_ctx, const std::string& func_name, size_t input_count, + size_t output_count, + const InlinedHashMap>& kwargs); + +} // namespace contrib +} // namespace onnxruntime + +#endif diff --git a/orttraining/orttraining/training_ops/cuda/activation/activations_grad.cc b/orttraining/orttraining/training_ops/cuda/activation/activations_grad.cc index 8dcfba33a9569..7fde69d758ca9 100644 --- a/orttraining/orttraining/training_ops/cuda/activation/activations_grad.cc +++ b/orttraining/orttraining/training_ops/cuda/activation/activations_grad.cc @@ -49,6 +49,7 @@ ACTIVATION_GRAD_OP_HFD(ReluGrad, 1, kMSDomain); ACTIVATION_GRAD_OP_HFD(SigmoidGrad, 1, kMSDomain); ACTIVATION_GRAD_OP_HFD(QuickGeluGrad, 1, kMSDomain); ACTIVATION_GRAD_OP_HFD(TanhGrad, 1, kMSDomain); +ACTIVATION_GRAD_OP_HFD(LeakyReluGrad, 1, kMSDomain); } // namespace cuda } // namespace onnxruntime diff --git a/orttraining/orttraining/training_ops/cuda/activation/activations_grad.h b/orttraining/orttraining/training_ops/cuda/activation/activations_grad.h index 34de4ef8bbb9e..2f60bc2cf2220 100644 --- a/orttraining/orttraining/training_ops/cuda/activation/activations_grad.h +++ b/orttraining/orttraining/training_ops/cuda/activation/activations_grad.h @@ -79,5 +79,20 @@ class TanhGrad final : public BinaryElementwise { private: MAKE_FUNC_CTX_NULL() }; + +template +class LeakyReluGrad final : public BinaryElementwise { + public: + LeakyReluGrad(const OpKernelInfo& info) : BinaryElementwise(info) { + alpha_ = info.GetAttrOrDefault("alpha", 0.01f); + } + + Status ComputeInternal(OpKernelContext* context) const override; + + private: + MAKE_FUNC_CTX_ALPHA() + float alpha_; +}; + } // namespace cuda } // namespace onnxruntime diff --git a/orttraining/orttraining/training_ops/cuda/activation/activations_grad_impl.cu b/orttraining/orttraining/training_ops/cuda/activation/activations_grad_impl.cu index 2c23a3ed87761..164aba866722e 100644 --- a/orttraining/orttraining/training_ops/cuda/activation/activations_grad_impl.cu +++ b/orttraining/orttraining/training_ops/cuda/activation/activations_grad_impl.cu @@ -64,6 +64,13 @@ struct OP_TanhGrad : public CtxTanhGrad { } }; +template +struct OP_LeakyReluGrad : public CtxLeakyReluGrad { + __device__ __inline__ T operator()(const T& dy, const T& y) const { + return dy * (y > T{0} ? T{1} : static_cast(alpha)); + } +}; + #define BINARY_ELEMENTWISE_IMPL(name) \ BINARY_ELEMENTWISE_IMPL_DECLARATION(name) { \ BinaryElementWiseNoBroadcastImpl(stream, \ diff --git a/orttraining/orttraining/training_ops/cuda/activation/activations_grad_impl.h b/orttraining/orttraining/training_ops/cuda/activation/activations_grad_impl.h index 8e925f0484c8d..0686dc4129026 100644 --- a/orttraining/orttraining/training_ops/cuda/activation/activations_grad_impl.h +++ b/orttraining/orttraining/training_ops/cuda/activation/activations_grad_impl.h @@ -13,6 +13,7 @@ typedef onnxruntime::cuda::CtxNull CtxReluGrad; typedef onnxruntime::cuda::CtxNull CtxSigmoidGrad; typedef onnxruntime::cuda::CtxAlpha CtxQuickGeluGrad; typedef onnxruntime::cuda::CtxNull CtxTanhGrad; +typedef onnxruntime::cuda::CtxAlpha CtxLeakyReluGrad; #define ACTIVATION_GRAD_OPS() \ ACTIVATION_GRAD_OP_NAME(GeluGrad) \ @@ -20,7 +21,8 @@ typedef onnxruntime::cuda::CtxNull CtxTanhGrad; ACTIVATION_GRAD_OP_NAME(ReluGrad) \ ACTIVATION_GRAD_OP_NAME(SigmoidGrad) \ ACTIVATION_GRAD_OP_NAME(QuickGeluGrad) \ - ACTIVATION_GRAD_OP_NAME(TanhGrad) + ACTIVATION_GRAD_OP_NAME(TanhGrad) \ + ACTIVATION_GRAD_OP_NAME(LeakyReluGrad) #define BINARY_ELEMENTWISE_IMPL_DECLARATION(name) \ template \ diff --git a/orttraining/orttraining/training_ops/cuda/activation/bias_gelu_grad_impl.cu b/orttraining/orttraining/training_ops/cuda/activation/bias_gelu_grad_impl.cu index c697d4cfd5412..1963fe0185211 100644 --- a/orttraining/orttraining/training_ops/cuda/activation/bias_gelu_grad_impl.cu +++ b/orttraining/orttraining/training_ops/cuda/activation/bias_gelu_grad_impl.cu @@ -54,6 +54,38 @@ __global__ void BiasGeluGradDxKernel(int64_t bias_size, const T* dY, const T* X, } } +template +__global__ void VectorizedBiasGeluGradDxKernel(int64_t bias_size, const T* dY, const T* X, const T* B, T* dX) { + const auto num_elements_per_block = num_elements_per_thread * blockDim.x; + const auto bias_idx = num_elements_per_block * blockIdx.y + num_elements_per_thread * threadIdx.x; + if (bias_idx >= bias_size) { + return; + } + + const auto input_idx = + bias_size * blockIdx.x + num_elements_per_block * blockIdx.y + num_elements_per_thread * threadIdx.x; + + using LoadT = aligned_vector; + + T reg_dY[num_elements_per_thread]; + T reg_X[num_elements_per_thread]; + T reg_B[num_elements_per_thread]; + T reg_dX[num_elements_per_thread]; + LoadT* value_dY = reinterpret_cast(®_dY); + LoadT* value_X = reinterpret_cast(®_X); + LoadT* value_B = reinterpret_cast(®_B); + *value_dY = *reinterpret_cast(&dY[input_idx]); + *value_X = *reinterpret_cast(&X[input_idx]); + *value_B = *reinterpret_cast(&B[bias_idx]); + +#pragma unroll + for (int element_idx = 0; element_idx < num_elements_per_thread; ++element_idx) { + reg_dX[element_idx] = + ComputeGeluGradScalar(reg_dY[element_idx], reg_X[element_idx] + reg_B[element_idx], GeluComputationMode{}); + } + *(reinterpret_cast(&dX[input_idx])) = *reinterpret_cast(®_dX[0]); +} + template void LaunchBiasGeluGradDxKernel( cudaStream_t stream, @@ -79,8 +111,16 @@ void LaunchBiasGeluGradDxKernel( const dim3 grid_dim{static_cast(grid_height), static_cast(grid_width)}; - BiasGeluGradDxKernel - <<>>(bias_size, dY, X, B, dX); + constexpr int vec_alignment = std::alignment_of>::value; + if (bias_size % num_elements_per_thread == 0 && reinterpret_cast(dY) % vec_alignment == 0 && + reinterpret_cast(X) % vec_alignment == 0 && reinterpret_cast(B) % vec_alignment == 0 && + reinterpret_cast(dX) % vec_alignment == 0) { + VectorizedBiasGeluGradDxKernel + <<>>(bias_size, dY, X, B, dX); + } else { + BiasGeluGradDxKernel + <<>>(bias_size, dY, X, B, dX); + } } // explicit instantiations diff --git a/orttraining/orttraining/training_ops/cuda/activation/gelu_grad_impl_common.cuh b/orttraining/orttraining/training_ops/cuda/activation/gelu_grad_impl_common.cuh index 38b9f67443707..eccf5edc853c8 100644 --- a/orttraining/orttraining/training_ops/cuda/activation/gelu_grad_impl_common.cuh +++ b/orttraining/orttraining/training_ops/cuda/activation/gelu_grad_impl_common.cuh @@ -15,6 +15,15 @@ __device__ __inline__ T ComputeGeluGradScalar(T dY, T X, gelu_computation_mode:: return dY * (_Normcdf(X) + X * kAlpha * _Exp(-T(0.5) * X * X)); } +template <> +__device__ __inline__ half ComputeGeluGradScalar(half dY, half X, gelu_computation_mode::Default) { + const half kHalf = half(0.5); + const half kOne = half(1.0); + const half kAlpha = half(M_SQRT1_2); + const half kBeta = half(M_2_SQRTPI) * kAlpha * kHalf; + return dY * (kHalf * (kOne + _Erf(kAlpha * X)) + X * kBeta * _Exp(-kHalf * X * X)); +} + template __device__ __inline__ T ComputeGeluGradScalar(T dY, T X, gelu_computation_mode::Approximation) { // copied and adapted from DeepSpeed: diff --git a/orttraining/orttraining/training_ops/cuda/cuda_training_kernels.cc b/orttraining/orttraining/training_ops/cuda/cuda_training_kernels.cc index ef8f9da6b2668..8e61dbee506f2 100644 --- a/orttraining/orttraining/training_ops/cuda/cuda_training_kernels.cc +++ b/orttraining/orttraining/training_ops/cuda/cuda_training_kernels.cc @@ -85,6 +85,9 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1 class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, float, ConvGrad); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, double, ConvGrad); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, MLFloat16, ConvGrad); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, float, ConvTransposeGrad); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, double, ConvTransposeGrad); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, MLFloat16, ConvTransposeGrad); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, GatherGrad); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, DropoutGrad); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, BitmaskDropoutGrad); @@ -123,6 +126,10 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1 class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, double, TanhGrad); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, MLFloat16, TanhGrad); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, float, LeakyReluGrad); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, double, LeakyReluGrad); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, MLFloat16, LeakyReluGrad); + class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, MLFloat16, IsFinite); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, float, IsFinite); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, double, IsFinite); @@ -197,6 +204,9 @@ class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, Inpl class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, float, FakeQuant); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, float, FakeQuantGrad); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, BatchScale); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, PadAndUnflatten); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, ScaledSum); // the kernels within the following ifdef are not included in a build with // --enable_training_ops but without --enable_training @@ -215,6 +225,10 @@ class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, Reco class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, WaitEvent); class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, YieldOp); +#ifdef ENABLE_TRITON +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, TritonOp); +#endif + class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, float, GistBinarizeEncoder); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, MLFloat16, GistBinarizeEncoder); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, double, GistBinarizeEncoder); @@ -250,6 +264,8 @@ class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCudaExecutionProvider, kMSDomain, 1, Mega Status RegisterCudaTrainingKernels(KernelRegistry& kernel_registry) { static const BuildKernelCreateInfoFn function_table[] = { + BuildKernelCreateInfo, // default entry to avoid the list become empty after ops-reducing + BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, @@ -335,6 +351,9 @@ Status RegisterCudaTrainingKernels(KernelRegistry& kernel_registry) { BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, @@ -359,6 +378,9 @@ Status RegisterCudaTrainingKernels(KernelRegistry& kernel_registry) { BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, @@ -435,7 +457,9 @@ Status RegisterCudaTrainingKernels(KernelRegistry& kernel_registry) { kCudaExecutionProvider, kMSDomain, 1, float, FakeQuant)>, BuildKernelCreateInfo, - + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, // the kernels within the following ifdef are not included in a build with // --enable_training_ops but without --enable_training #ifdef ENABLE_TRAINING @@ -453,6 +477,10 @@ Status RegisterCudaTrainingKernels(KernelRegistry& kernel_registry) { BuildKernelCreateInfo, BuildKernelCreateInfo, +#ifdef ENABLE_TRITON + BuildKernelCreateInfo, +#endif + BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, @@ -488,7 +516,10 @@ Status RegisterCudaTrainingKernels(KernelRegistry& kernel_registry) { }; for (auto& function_table_entry : function_table) { - ORT_RETURN_IF_ERROR(kernel_registry.Register(function_table_entry())); + KernelCreateInfo info = function_table_entry(); + if (info.kernel_def != nullptr) { // filter disabled entries where type is void + ORT_RETURN_IF_ERROR(kernel_registry.Register(std::move(info))); + } } return Status::OK(); diff --git a/orttraining/orttraining/training_ops/cuda/loss/softmax_cross_entropy_loss_impl.cc b/orttraining/orttraining/training_ops/cuda/loss/softmax_cross_entropy_loss_impl.cc index d0dec4fae6fe6..6b9f557e11928 100644 --- a/orttraining/orttraining/training_ops/cuda/loss/softmax_cross_entropy_loss_impl.cc +++ b/orttraining/orttraining/training_ops/cuda/loss/softmax_cross_entropy_loss_impl.cc @@ -110,7 +110,7 @@ Status SoftmaxCrossEntropyLoss::ComputeInternal(OpKernelContext } // Calculate logsoftmax - auto status = SoftMaxComputeHelper(Stream(ctx), logit_data, logit_reshape, log_prob_data, 1); + auto status = SoftMaxComputeHelper(ctx->GetComputeStream(), logit_data, logit_reshape, log_prob_data, 1); ORT_RETURN_IF_ERROR(status); const T* weight_data = nullptr; @@ -214,7 +214,7 @@ Status SoftmaxCrossEntropyLossGrad::ComputeInternal(OpKernelCon p_weight ? &p_weight->Shape() : nullptr); // N_D = N * D1 * D2...Dk - int64_t N_D, C; + int64_t N_D = 0, C = 0; onnxruntime::contrib::GetNDCFromLogitAndLabelShape(probability_shape, label_shape, N_D, C); Tensor* d_logit = ctx->Output(0, probability_shape); const T* dY_data = dY.Data(); @@ -295,8 +295,8 @@ Status SoftmaxCrossEntropyLossGrad::ComputeInternal(OpKernelCon onnxruntime::contrib::GetPermutationAndShape(false, logit_shape, new_shape, permutations); transpose_output.GetMutable()->Reshape(d_logit->Shape()); d_logit->Reshape(logit_shape); - ORT_RETURN_IF_ERROR(cuda::Transpose::DoTranspose(cuda::Transpose(info), ctx->GetComputeStream(), permutations, *d_logit, - *transpose_output.GetMutable())); + ORT_RETURN_IF_ERROR(cuda::Transpose::DoTranspose(cuda::Transpose(info), ctx->GetComputeStream(), permutations, + *d_logit, *transpose_output.GetMutable())); auto* transposed_data = (*transpose_output.GetMutable()).template Data(); CUDA_RETURN_IF_ERROR(cudaMemcpyAsync(d_logit_data, transposed_data, sizeof(TOut) * probability_shape.Size(), cudaMemcpyDeviceToDevice, Stream(ctx))); diff --git a/orttraining/orttraining/training_ops/cuda/loss/softmax_cross_entropy_loss_impl.cu b/orttraining/orttraining/training_ops/cuda/loss/softmax_cross_entropy_loss_impl.cu index e2afa69ec1d4c..ec575a39e2e88 100644 --- a/orttraining/orttraining/training_ops/cuda/loss/softmax_cross_entropy_loss_impl.cu +++ b/orttraining/orttraining/training_ops/cuda/loss/softmax_cross_entropy_loss_impl.cu @@ -7,12 +7,12 @@ namespace onnxruntime { namespace cuda { -template +template struct OpSoftmaxCrossEntropyWeights { OpSoftmaxCrossEntropyWeights(const TLabel* label_data, const T* weight_data, TLabel C, TLabel ignore_index) : label_data_(label_data), weight_data_(weight_data), C_(C), ignore_index_(ignore_index) {} - __device__ __inline__ TOut operator()(CUDA_LONG idx) const { + __device__ __inline__ TOut operator()(TIndex idx) const { if (label_data_[idx] != ignore_index_) { if (IsWeighted) { CUDA_KERNEL_ASSERT(label_data_[idx] >= 0 && label_data_[idx] < C_); @@ -33,13 +33,13 @@ template void ComputeSoftmaxCrossEntropyWeightsImpl(cudaStream_t stream, const TLabel* label, const T* weight, size_t count, size_t label_depth, int64_t ignore_index, TOut* weight_data_nd) { if (weight) { - OpSoftmaxCrossEntropyWeights op(label, weight, static_cast(label_depth), - static_cast(ignore_index)); - LaunchElementwiseKernel(stream, weight_data_nd, op, count); + typedef OpSoftmaxCrossEntropyWeights OP_Type; + OP_Type op(label, weight, static_cast(label_depth), static_cast(ignore_index)); + LaunchElementwiseKernel(stream, weight_data_nd, op, count); } else { - OpSoftmaxCrossEntropyWeights op(label, nullptr, static_cast(label_depth), - static_cast(ignore_index)); - LaunchElementwiseKernel(stream, weight_data_nd, op, count); + typedef OpSoftmaxCrossEntropyWeights OP_Type; + OP_Type op(label, nullptr, static_cast(label_depth), static_cast(ignore_index)); + LaunchElementwiseKernel(stream, weight_data_nd, op, count); } } @@ -57,7 +57,7 @@ INSTANTIATE_COMPUTE_SCE_WEIGHTS_IMPL(BFloat16, int64_t, BFloat16); #undef INSTANTIATE_COMPUTE_SCE_WEIGHTS_IMPL -template +template struct OpWeightedSoftmaxCrossEntropyLoss { OpWeightedSoftmaxCrossEntropyLoss(const T* log_prob_data, const TLabel* label_data, const T* weight_data, const TAcc* normalize_factor_data, TLabel C, TLabel ignore_index) @@ -68,11 +68,12 @@ struct OpWeightedSoftmaxCrossEntropyLoss { C_(C), ignore_index_(ignore_index) {} - __device__ __inline__ T operator()(CUDA_LONG idx) const { + __device__ __inline__ T operator()(TIndex idx) const { if (label_data_[idx] != ignore_index_) { CUDA_KERNEL_ASSERT(label_data_[idx] >= 0 && label_data_[idx] < C_); - return static_cast(static_cast(-log_prob_data_[idx * C_ + label_data_[idx]] * weight_data_[idx]) / - (*normalize_factor_data_)); + T ret = static_cast(static_cast(-log_prob_data_[idx * C_ + label_data_[idx]] * weight_data_[idx]) / + (*normalize_factor_data_)); + return ret; } return T(0.f); } @@ -89,12 +90,14 @@ template void SoftmaxCrossEntropyLossImpl(cudaStream_t stream, const T* log_prob, const TLabel* label, const T* weight, const TAcc* normalize_factor, size_t count, size_t label_depth, int64_t ignore_index, T* output_data) { - OpWeightedSoftmaxCrossEntropyLoss op(log_prob, label, weight, normalize_factor, - static_cast(label_depth), static_cast(ignore_index)); - LaunchElementwiseKernel(stream, output_data, op, count); + typedef OpWeightedSoftmaxCrossEntropyLoss OP_Type; + OP_Type op(log_prob, label, weight, normalize_factor, + static_cast(label_depth), + static_cast(ignore_index)); + LaunchElementwiseKernel(stream, output_data, op, count); } -template +template struct OpWeightedSoftmaxCrossEntropyLossGrad { OpWeightedSoftmaxCrossEntropyLossGrad(const T* dY_data, const T* log_prob_data, const TLabel* label_data, const T* weight_data, const TAcc* normalize_factor_data, const TOut* bias_data, @@ -106,15 +109,15 @@ struct OpWeightedSoftmaxCrossEntropyLossGrad { normalize_factor_data_(normalize_factor_data), bias_data_(bias_data), C_(C) { - C_fdm_ = fast_divmod(static_cast(C)); + C_fdm_ = DivMod(static_cast(C)); } - __device__ __inline__ TOut operator()(CUDA_LONG idx) const { + __device__ __inline__ TOut operator()(TIndex idx) const { // normalize_factor is sum of labels' weights. Because zero sum implies all weights are 0, the loss function should // be constant 0 and its corresponding gradient should be 0 as well. TAcc result = TAcc(0.f); if (*normalize_factor_data_ != TAcc(0.f)) { - int row, d; + TIndex row, d; C_fdm_.divmod(idx, row, d); CUDA_KERNEL_ASSERT(weight_data_[row] == T(0.f) || (label_data_[row] >= 0 && label_data_[row] < C_)); result = static_cast((IsReductionNone ? dY_data_[row] : *dY_data_) * weight_data_[row]) * @@ -131,17 +134,24 @@ struct OpWeightedSoftmaxCrossEntropyLossGrad { const TAcc* normalize_factor_data_; const TOut* bias_data_; TLabel C_; - fast_divmod C_fdm_; + DivMod C_fdm_; }; template void SoftmaxCrossEntropyLossGradImpl(cudaStream_t stream, const T* dY, const T* log_prob, const TLabel* label, const T* weight, const TAcc* normalize_factor, const TOut* bias_data, size_t count, size_t label_depth, bool reduction_none, TOut* output_data) { -#define LAUNCH_WEIGHTED_SOFTMAX_CROSS_ENTROPY_LOSS_GRAD_KERNEL(is_reduction_none, has_bias) \ - OpWeightedSoftmaxCrossEntropyLossGrad op( \ - dY, log_prob, label, weight, normalize_factor, bias_data, static_cast(label_depth)); \ - LaunchElementwiseKernel(stream, output_data, op, count * label_depth) +#define LAUNCH_WEIGHTED_SOFTMAX_CROSS_ENTROPY_LOSS_GRAD_KERNEL(is_reduction_none, has_bias) \ + uint64_t total_count = count * label_depth; \ + if (total_count <= static_cast(std::numeric_limits::max())) { \ + typedef OpWeightedSoftmaxCrossEntropyLossGrad OP_Type; \ + OP_Type op(dY, log_prob, label, weight, normalize_factor, bias_data, static_cast(label_depth)); \ + LaunchElementwiseKernel(stream, output_data, op, static_cast(total_count)); \ + } else { \ + typedef OpWeightedSoftmaxCrossEntropyLossGrad OP_Type; \ + OP_Type op(dY, log_prob, label, weight, normalize_factor, bias_data, static_cast(label_depth)); \ + LaunchElementwiseKernel(stream, output_data, op, total_count); \ + } if (reduction_none) { if (bias_data) { LAUNCH_WEIGHTED_SOFTMAX_CROSS_ENTROPY_LOSS_GRAD_KERNEL(true, true); diff --git a/orttraining/orttraining/training_ops/cuda/loss/softmaxcrossentropy_impl.cc b/orttraining/orttraining/training_ops/cuda/loss/softmaxcrossentropy_impl.cc index f6254e0c119bd..4f4cbb7444a68 100644 --- a/orttraining/orttraining/training_ops/cuda/loss/softmaxcrossentropy_impl.cc +++ b/orttraining/orttraining/training_ops/cuda/loss/softmaxcrossentropy_impl.cc @@ -49,7 +49,7 @@ Status SoftmaxCrossEntropy::ComputeInternal(OpKernelContext* ctx) const { T* log_prob_data = log_prob->template MutableData(); // calculate logsoftmax - auto status = SoftMaxComputeHelper(Stream(ctx), + auto status = SoftMaxComputeHelper(ctx->GetComputeStream(), logit_data, logit_reshape, log_prob_data, @@ -151,7 +151,7 @@ Status SparseSoftmaxCrossEntropy::ComputeInternal(OpKernelContext* ctx) T* log_prob_data = log_prob->template MutableData(); // calculate logsoftmax - auto status = SoftMaxComputeHelper(Stream(ctx), + auto status = SoftMaxComputeHelper(ctx->GetComputeStream(), logit_data, logit_reshape, log_prob_data, diff --git a/orttraining/orttraining/training_ops/cuda/loss/softmaxcrossentropy_impl.cu b/orttraining/orttraining/training_ops/cuda/loss/softmaxcrossentropy_impl.cu index 9f58073256181..c78a9f788d204 100644 --- a/orttraining/orttraining/training_ops/cuda/loss/softmaxcrossentropy_impl.cu +++ b/orttraining/orttraining/training_ops/cuda/loss/softmaxcrossentropy_impl.cu @@ -25,7 +25,7 @@ template void SoftMaxCrossEntropyImpl(cudaStream_t stream, const T* log_prob, const T* label, size_t normalize_factor, T* output_data, size_t count) { OpSoftmaxCrossEntropy op(log_prob, label, static_cast(normalize_factor)); - LaunchElementwiseKernel(stream, output_data, op, count); + LaunchElementwiseKernel(stream, output_data, op, static_cast(count)); } template void SoftMaxCrossEntropyImpl(cudaStream_t stream, const float* log_prob, const float* label, @@ -53,7 +53,7 @@ template void SoftMaxCrossEntropyGradImpl(cudaStream_t stream, const T* dY, const T* log_prob, const T* label, size_t normalize_factor, T* output_data, size_t count) { OpSoftmaxCrossEntropyGrad op(dY, log_prob, label, static_cast(normalize_factor)); - LaunchElementwiseKernel(stream, output_data, op, count); + LaunchElementwiseKernel(stream, output_data, op, static_cast(count)); } template void SoftMaxCrossEntropyGradImpl(cudaStream_t stream, const float* dY, const float* log_prob, @@ -92,11 +92,11 @@ void SparseSoftmaxCrossEntropyImpl(cudaStream_t stream, const T* log_prob, const if (weight) { OpSparseSoftmaxCrossEntropy op(log_prob, label, weight, normalize_factor, static_cast(label_depth)); - LaunchElementwiseKernel(stream, output_data, op, count); + LaunchElementwiseKernel(stream, output_data, op, static_cast(count)); } else { OpSparseSoftmaxCrossEntropy op(log_prob, label, nullptr, normalize_factor, static_cast(label_depth)); - LaunchElementwiseKernel(stream, output_data, op, count); + LaunchElementwiseKernel(stream, output_data, op, static_cast(count)); } } @@ -136,11 +136,13 @@ void SparseSoftmaxCrossEntropyGradImpl(cudaStream_t stream, const T* dY, const T if (weight) { OpSparseSoftmaxCrossEntropyGrad op(dY, log_prob, label, weight, normalize_factor, fast_divmod(static_cast(label_depth))); - LaunchElementwiseKernel(stream, output_data, op, count * label_depth); + LaunchElementwiseKernel(stream, output_data, op, + static_cast(count * label_depth)); } else { OpSparseSoftmaxCrossEntropyGrad op(dY, log_prob, label, nullptr, normalize_factor, fast_divmod(static_cast(label_depth))); - LaunchElementwiseKernel(stream, output_data, op, count * label_depth); + LaunchElementwiseKernel(stream, output_data, op, + static_cast(count * label_depth)); } } diff --git a/orttraining/orttraining/training_ops/cuda/math/batch_scale.cc b/orttraining/orttraining/training_ops/cuda/math/batch_scale.cc new file mode 100644 index 0000000000000..bfe2872efd58b --- /dev/null +++ b/orttraining/orttraining/training_ops/cuda/math/batch_scale.cc @@ -0,0 +1,68 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include + +#include "orttraining/training_ops/cuda/math/batch_scale.h" +#include "orttraining/training_ops/cuda/math/batch_scale_impl.h" + +namespace onnxruntime { +namespace cuda { + +ONNX_OPERATOR_KERNEL_EX( + BatchScale, + kMSDomain, + 1, + kCudaExecutionProvider, + (*KernelDefBuilder::Create()) + .TypeConstraint("T", BuildKernelDefConstraints()), + BatchScale); + +// Put implementation in the anonymous namespace to avoid name collision in the global namespace. +namespace { + +template +struct BatchScaleFunctor { + void operator()(cudaStream_t stream, + int64_t input_element_count, + const Tensor* input_tensor, + const std::vector& scales, + const std::vector& output_tensors) const { + typedef typename ToCudaType::MappedType CudaT; + + std::vector output_data_ptrs; + output_data_ptrs.reserve(output_tensors.size()); + for (Tensor* output_tensor : output_tensors) { + output_data_ptrs.push_back(reinterpret_cast(output_tensor->MutableData())); + } + + BatchScaleImpl(stream, input_element_count, reinterpret_cast(input_tensor->Data()), + scales, output_data_ptrs); + } +}; +} // namespace + +Status BatchScale::ComputeInternal(OpKernelContext* context) const { + const Tensor* input_tensor = context->Input(0); + + size_t output_count = scale2_.has_value() ? 3 : 2; + const auto& input_tensor_shape = input_tensor->Shape(); + std::vector output_tensors; + output_tensors.reserve(output_count); + for (size_t i = 0; i < output_count; ++i) { + output_tensors.push_back(context->Output(static_cast(i), input_tensor_shape)); + } + + std::vector scales{scale0_, scale1_}; + if (output_count == 3) { + scales.push_back(scale2_.value()); + } + + utils::MLTypeCallDispatcher t_disp(input_tensor->GetElementType()); + t_disp.Invoke(Stream(context), input_tensor_shape.Size(), + input_tensor, scales, output_tensors); + return Status::OK(); +} + +} // namespace cuda +} // namespace onnxruntime diff --git a/orttraining/orttraining/training_ops/cuda/math/batch_scale.h b/orttraining/orttraining/training_ops/cuda/math/batch_scale.h new file mode 100644 index 0000000000000..0fb1603506fea --- /dev/null +++ b/orttraining/orttraining/training_ops/cuda/math/batch_scale.h @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include + +#include "core/providers/cuda/cuda_kernel.h" + +namespace onnxruntime { +namespace cuda { + +class BatchScale final : public CudaKernel { + public: + BatchScale(const OpKernelInfo& info) : CudaKernel(info) { + ORT_ENFORCE(info.GetAttr("scale_0", &scale0_).IsOK()); + ORT_ENFORCE(info.GetAttr("scale_1", &scale1_).IsOK()); + + float scale2_tmp; + if (info.GetAttr("scale_2", &scale2_tmp).IsOK()) { + scale2_ = scale2_tmp; + } + } + + Status ComputeInternal(OpKernelContext* context) const override; + + private: + float scale0_; + float scale1_; + std::optional scale2_; +}; + +} // namespace cuda +} // namespace onnxruntime diff --git a/orttraining/orttraining/training_ops/cuda/math/batch_scale_impl.cu b/orttraining/orttraining/training_ops/cuda/math/batch_scale_impl.cu new file mode 100644 index 0000000000000..d6951fa51e61c --- /dev/null +++ b/orttraining/orttraining/training_ops/cuda/math/batch_scale_impl.cu @@ -0,0 +1,153 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include + +#include "core/providers/cuda/cu_inc/common.cuh" +#include "core/providers/cuda/cuda_common.h" +#include "orttraining/training_ops/cuda/math/batch_scale_impl.h" + +namespace onnxruntime { +namespace cuda { + +constexpr int kBlockSize = 256; +constexpr int kNumUnroll = 4; + +template +struct BatchScaleFunctor { + BatchScaleFunctor(const T* input, + const std::vector& scales, + int64_t N, + const std::vector& outputs) + : N_(static_cast(N)), + input_data_(input) { + for (int i = 0; i < OutputCount; i++) { + outputs_[i] = outputs[i]; + scales_[i] = scales[i]; + } + } + + __device__ __inline__ void operator()(CUDA_LONG idx) const { + CUDA_LONG id = idx * NumUnroll; + + if (id >= N_) { + return; + } + + using LoadT = aligned_vector; + + T input0_value[NumUnroll]; + if (IsVectorized) { + LoadT* input0_value_ptr = reinterpret_cast(&input0_value[0]); + *input0_value_ptr = *reinterpret_cast(&input_data_[id]); + } else { +#pragma unroll + for (int i = 0; i < NumUnroll; i++) { + CUDA_LONG li = id + i; + if (li < N_) { + input0_value[i] = input_data_[li]; + } + } + } + + if (IsVectorized) { + T output_values[OutputCount][NumUnroll]; +#pragma unroll + for (int i = 0; i < NumUnroll; i++) { + CUDA_LONG li = id + i; + if (li < N_) { + output_values[0][i] = static_cast(static_cast(input0_value[i]) * scales_[0]); + output_values[1][i] = static_cast(static_cast(input0_value[i]) * scales_[1]); + if (OutputCount == 3) + output_values[2][i] = static_cast(static_cast(input0_value[i]) * scales_[2]); + } + } + *reinterpret_cast(&outputs_[0][id]) = *reinterpret_cast(&output_values[0][0]); + *reinterpret_cast(&outputs_[1][id]) = *reinterpret_cast(&output_values[1][0]); + if (OutputCount == 3) + *reinterpret_cast(&outputs_[2][id]) = *reinterpret_cast(&output_values[2][0]); + + } else { +#pragma unroll + for (int i = 0; i < NumUnroll; i++) { + CUDA_LONG li = id + i; + if (li < N_) { + outputs_[0][li] = static_cast(static_cast(input0_value[i]) * scales_[0]); + outputs_[1][li] = static_cast(static_cast(input0_value[i]) * scales_[1]); + if (OutputCount == 3) + outputs_[2][li] = static_cast(static_cast(input0_value[i]) * scales_[2]); + } + } + } + } + + private: + T* outputs_[OutputCount]; + float scales_[OutputCount]; + const CUDA_LONG N_; + const T* input_data_; +}; + +template +__global__ void BatchScaleKernel(const FuncT functor) { + CUDA_LONG idx = blockDim.x * blockIdx.x + threadIdx.x; + functor(idx); +} + +template +void BatchScaleImpl(cudaStream_t stream, + int64_t input_element_count, + const T* input_data, + const std::vector& scales, + const std::vector& outputs) { + const int blocksPerGrid = static_cast(CeilDiv(input_element_count, kBlockSize * kNumUnroll)); + constexpr int vec_alignment = std::alignment_of>::value; + const bool use_vectorized = (input_element_count % kNumUnroll == 0) && + (reinterpret_cast(input_data) % vec_alignment == 0) && + (reinterpret_cast(outputs[0]) % vec_alignment == 0) && + (reinterpret_cast(outputs[1]) % vec_alignment == 0) && + (outputs.size() < 3 || (reinterpret_cast(outputs[2]) % vec_alignment == 0)); + + const int output_count = static_cast(outputs.size()); + using TwoOutputVectorizedFunctorType = BatchScaleFunctor; + using TwoOutputNonVectorizedFunctorType = BatchScaleFunctor; + using ThreeOutputVectorizedFunctorType = BatchScaleFunctor; + using ThreeOutputNonVectorizedFunctorType = BatchScaleFunctor; + + if (output_count == 2) { + if (use_vectorized) + BatchScaleKernel<<>>( + TwoOutputVectorizedFunctorType(input_data, scales, input_element_count, outputs)); + else + BatchScaleKernel<<>>( + TwoOutputNonVectorizedFunctorType(input_data, scales, input_element_count, outputs)); + } else if (output_count == 3) { + if (use_vectorized) { + BatchScaleKernel<<>>( + ThreeOutputVectorizedFunctorType(input_data, scales, input_element_count, outputs)); + } else { + BatchScaleKernel<<>>( + ThreeOutputNonVectorizedFunctorType(input_data, scales, input_element_count, outputs)); + } + + } else { + ORT_THROW("Unsupported output count: ", output_count); + } +} + +#define SPECIALIZE_BATCH_SCALE_IMPL(T) \ + template void BatchScaleImpl(cudaStream_t stream, \ + int64_t input_element_count, \ + const T* input_data, \ + const std::vector& scales, \ + const std::vector& outputs); + +SPECIALIZE_BATCH_SCALE_IMPL(half); +SPECIALIZE_BATCH_SCALE_IMPL(float); +SPECIALIZE_BATCH_SCALE_IMPL(double); +SPECIALIZE_BATCH_SCALE_IMPL(BFloat16); + +#undef SPECIALIZE_BATCH_SCALE_IMPL + +} // namespace cuda +} // namespace onnxruntime diff --git a/orttraining/orttraining/training_ops/cuda/math/batch_scale_impl.h b/orttraining/orttraining/training_ops/cuda/math/batch_scale_impl.h new file mode 100644 index 0000000000000..d3bc6f0ff0de9 --- /dev/null +++ b/orttraining/orttraining/training_ops/cuda/math/batch_scale_impl.h @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include + +namespace onnxruntime { +namespace cuda { + +template +void BatchScaleImpl(cudaStream_t stream, + int64_t input_element_count, + const T* input_data, + const std::vector& scales, + const std::vector& outputs); + +} // namespace cuda +} // namespace onnxruntime diff --git a/orttraining/orttraining/training_ops/cuda/math/scaled_sum.cc b/orttraining/orttraining/training_ops/cuda/math/scaled_sum.cc new file mode 100644 index 0000000000000..0115b05ba53df --- /dev/null +++ b/orttraining/orttraining/training_ops/cuda/math/scaled_sum.cc @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include + +#include "orttraining/training_ops/cuda/math/scaled_sum.h" +#include "orttraining/training_ops/cuda/math/scaled_sum_impl.h" + +namespace onnxruntime { +namespace cuda { + +ONNX_OPERATOR_KERNEL_EX( + ScaledSum, + kMSDomain, + 1, + kCudaExecutionProvider, + (*KernelDefBuilder::Create()) + .TypeConstraint("T", BuildKernelDefConstraints()), + ScaledSum); + +// Put implementation in the anonymous namespace to avoid name collision in the global namespace. +namespace { + +template +struct ScaledSumFunctor { + void operator()(cudaStream_t stream, + int64_t input_element_count, + const std::vector& input_tensors, + const std::vector& scales, + Tensor* output_tensor) const { + typedef typename ToCudaType::MappedType CudaT; + + std::vector input_data_ptrs; + input_data_ptrs.reserve(input_tensors.size()); + for (const Tensor* input_tensor : input_tensors) { + input_data_ptrs.push_back(reinterpret_cast(input_tensor->Data())); + } + + ScaledSumImpl(stream, input_element_count, input_data_ptrs, scales, + reinterpret_cast(output_tensor->MutableData())); + } +}; +} // namespace + +Status ScaledSum::ComputeInternal(OpKernelContext* context) const { + std::vector input_tensors; + input_tensors.reserve(3); + + for (size_t i = 0; i < 3; ++i) { + const Tensor* input_tensor = context->Input(static_cast(i)); + if (!input_tensor) + continue; + input_tensors.push_back(input_tensor); + } + + ORT_ENFORCE(input_tensors.size() > 1, "Number of input tensors must be greater than 1."); + + const auto& first_input_tensor_shape = input_tensors[0]->Shape(); + for (size_t i = 1; i < input_tensors.size(); ++i) { + ORT_ENFORCE(input_tensors[i]->Shape() == first_input_tensor_shape, + "Shape of input tensors must be the same."); + } + + std::vector scales{scale0_, scale1_}; + if (input_tensors.size() == 3) { + ORT_ENFORCE(scale2_.has_value(), "Scale 2 must be specified."); + scales.push_back(scale2_.value()); + } + + Tensor* output_tensor = context->Output(0, first_input_tensor_shape); + utils::MLTypeCallDispatcher t_disp(input_tensors[0]->GetElementType()); + + t_disp.Invoke(Stream(context), first_input_tensor_shape.Size(), + input_tensors, scales, output_tensor); + return Status::OK(); +} + +} // namespace cuda +} // namespace onnxruntime diff --git a/orttraining/orttraining/training_ops/cuda/math/scaled_sum.h b/orttraining/orttraining/training_ops/cuda/math/scaled_sum.h new file mode 100644 index 0000000000000..9902b5428d912 --- /dev/null +++ b/orttraining/orttraining/training_ops/cuda/math/scaled_sum.h @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include + +#include "core/providers/cuda/cuda_kernel.h" + +namespace onnxruntime { +namespace cuda { + +class ScaledSum final : public CudaKernel { + public: + ScaledSum(const OpKernelInfo& info) : CudaKernel(info) { + ORT_ENFORCE(info.GetAttr("scale_0", &scale0_).IsOK()); + ORT_ENFORCE(info.GetAttr("scale_1", &scale1_).IsOK()); + float scale2_tmp; + if (info.GetAttr("scale_2", &scale2_tmp).IsOK()) { + scale2_ = scale2_tmp; + } + } + + Status ComputeInternal(OpKernelContext* context) const override; + + private: + float scale0_; + float scale1_; + std::optional scale2_; +}; + +} // namespace cuda +} // namespace onnxruntime diff --git a/orttraining/orttraining/training_ops/cuda/math/scaled_sum_impl.cu b/orttraining/orttraining/training_ops/cuda/math/scaled_sum_impl.cu new file mode 100644 index 0000000000000..b4488aa25071b --- /dev/null +++ b/orttraining/orttraining/training_ops/cuda/math/scaled_sum_impl.cu @@ -0,0 +1,168 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "core/providers/cuda/cu_inc/common.cuh" +#include "core/providers/cuda/cuda_common.h" +#include "orttraining/training_ops/cuda/math/scaled_sum_impl.h" + +namespace onnxruntime { +namespace cuda { + +constexpr int kBlockSize = 256; +constexpr int kNumUnroll = 4; + +template +struct ScaledSumFunctor { + ScaledSumFunctor(const std::vector& inputs, + const std::vector& scales, + int64_t N, + T* output) { + output_data_ = output; + N_ = static_cast(N); + for (int i = 0; i < InputCount; i++) { + inputs_[i] = inputs[i]; + scales_[i] = scales[i]; + } + } + + __device__ __inline__ void operator()(CUDA_LONG idx) const { + CUDA_LONG id = idx * NumUnroll; + + if (id >= N_) { + return; + } + + using LoadT = aligned_vector; + T input_values[InputCount][NumUnroll]; + if (IsVectorized) { + LoadT* input0_value_ptr = reinterpret_cast(&input_values[0][0]); + *input0_value_ptr = *reinterpret_cast(&inputs_[0][id]); + + LoadT* input1_value_ptr = reinterpret_cast(&input_values[1][0]); + *input1_value_ptr = *reinterpret_cast(&inputs_[1][id]); + + if (InputCount == 3) { + LoadT* input2_value_ptr = reinterpret_cast(&input_values[2][0]); + *input2_value_ptr = *reinterpret_cast(&inputs_[2][id]); + } + + } else { +#pragma unroll + for (int i = 0; i < NumUnroll; i++) { + CUDA_LONG li = id + i; + if (li < N_) { + input_values[0][i] = inputs_[0][li]; + input_values[1][i] = inputs_[1][li]; + if (InputCount == 3) + input_values[2][i] = inputs_[2][li]; + } + } + } + + if (IsVectorized) { + T output_value[NumUnroll]; +#pragma unroll + for (int i = 0; i < NumUnroll; i++) { + CUDA_LONG li = id + i; + if (li < N_) { + if (InputCount == 3) + output_value[i] = input_values[0][i] * static_cast(scales_[0]) + + input_values[1][i] * static_cast(scales_[1]) + + input_values[2][i] * static_cast(scales_[2]); + else + output_value[i] = input_values[0][i] * static_cast(scales_[0]) + + input_values[1][i] * static_cast(scales_[1]); + } + } + + *reinterpret_cast(&output_data_[id]) = *reinterpret_cast(&output_value[0]); + } else { + T* output_value = output_data_ + id; +#pragma unroll + for (int i = 0; i < NumUnroll; i++) { + CUDA_LONG li = id + i; + if (li < N_) { + if (InputCount == 3) + output_value[i] = input_values[0][i] * static_cast(scales_[0]) + + input_values[1][i] * static_cast(scales_[1]) + + input_values[2][i] * static_cast(scales_[2]); + + else + output_value[i] = input_values[0][i] * static_cast(scales_[0]) + + input_values[1][i] * static_cast(scales_[1]); + } + } + } + } + + private: + const T* inputs_[InputCount]; + float scales_[InputCount]; + CUDA_LONG N_; + T* output_data_; +}; + +template +__global__ void ScaledSumKernel(const FuncT functor) { + CUDA_LONG idx = blockDim.x * blockIdx.x + threadIdx.x; + functor(idx); +} + +template +void ScaledSumImpl(cudaStream_t stream, + int64_t input_element_count, + const std::vector& inputs, + const std::vector& scales, + T* output_data) { + const int blocksPerGrid = static_cast(CeilDiv(input_element_count, kBlockSize * kNumUnroll)); + constexpr int vec_alignment = std::alignment_of>::value; + const bool use_vectorized = (input_element_count % kNumUnroll == 0) && + (reinterpret_cast(output_data) % vec_alignment == 0) && + (reinterpret_cast(inputs[0]) % vec_alignment == 0) && + (reinterpret_cast(inputs[1]) % vec_alignment == 0) && + (inputs.size() < 3 || (reinterpret_cast(inputs[2]) % vec_alignment == 0)); + + const int input_count = static_cast(inputs.size()); + using TwoInputTVectorizedFunctorType = ScaledSumFunctor; + using TwoInputTNonVectorizedFunctorType = ScaledSumFunctor; + using ThreeInputTVectorizedFunctorType = ScaledSumFunctor; + using ThreeInputTNonVectorizedFunctorType = ScaledSumFunctor; + + if (input_count == 2) { + if (use_vectorized) { + ScaledSumKernel<<>>( + TwoInputTVectorizedFunctorType(inputs, scales, input_element_count, output_data)); + } else { + ScaledSumKernel<<>>( + TwoInputTNonVectorizedFunctorType(inputs, scales, input_element_count, output_data)); + } + } else if (input_count == 3) { + if (use_vectorized) { + ScaledSumKernel<<>>( + ThreeInputTVectorizedFunctorType(inputs, scales, input_element_count, output_data)); + } else { + ScaledSumKernel<<>>( + ThreeInputTNonVectorizedFunctorType(inputs, scales, input_element_count, output_data)); + } + + } else { + ORT_THROW("Unsupported input count: ", input_count); + } +} + +#define SPECIALIZE_SCALED_SUM_IMPL(T) \ + template void ScaledSumImpl(cudaStream_t stream, \ + int64_t input_element_count, \ + const std::vector& inputs, \ + const std::vector& scales, \ + T* output_data); + +SPECIALIZE_SCALED_SUM_IMPL(half); +SPECIALIZE_SCALED_SUM_IMPL(float); +SPECIALIZE_SCALED_SUM_IMPL(double); +SPECIALIZE_SCALED_SUM_IMPL(BFloat16); + +#undef SPECIALIZE_SCALED_SUM_IMPL + +} // namespace cuda +} // namespace onnxruntime diff --git a/orttraining/orttraining/training_ops/cuda/math/scaled_sum_impl.h b/orttraining/orttraining/training_ops/cuda/math/scaled_sum_impl.h new file mode 100644 index 0000000000000..bf3ff0d1b8b40 --- /dev/null +++ b/orttraining/orttraining/training_ops/cuda/math/scaled_sum_impl.h @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include + +namespace onnxruntime { +namespace cuda { + +template +void ScaledSumImpl(cudaStream_t stream, + int64_t input_element_count, + const std::vector& inputs, + const std::vector& scales, + T* output_data); + +} // namespace cuda +} // namespace onnxruntime diff --git a/orttraining/orttraining/training_ops/cuda/math/softmax_grad_impl.cu b/orttraining/orttraining/training_ops/cuda/math/softmax_grad_impl.cu index 0bec959e14db3..48ec60017a3cd 100644 --- a/orttraining/orttraining/training_ops/cuda/math/softmax_grad_impl.cu +++ b/orttraining/orttraining/training_ops/cuda/math/softmax_grad_impl.cu @@ -268,7 +268,7 @@ Status SoftmaxGradImpl(cudaStream_t stream, cudnnHandle_t cudnn_handle, T* input #define CASE_LOG2_ELEMENTS(log2_elements_value) \ case log2_elements_value: { \ - if (log2_elements_value < start_to_use_register_efficient_func) { \ + if constexpr (log2_elements_value < start_to_use_register_efficient_func) { \ LAUNCH_KERNEL(log2_elements_value, softmax_warp_backward); \ } else { \ LAUNCH_KERNEL(log2_elements_value, softmax_warp_backward_register_efficicent); \ diff --git a/orttraining/orttraining/training_ops/cuda/nn/conv_grad.cc b/orttraining/orttraining/training_ops/cuda/nn/conv_grad.cc index 9802c5514f76f..f6c58445c0a5d 100644 --- a/orttraining/orttraining/training_ops/cuda/nn/conv_grad.cc +++ b/orttraining/orttraining/training_ops/cuda/nn/conv_grad.cc @@ -3,13 +3,6 @@ #include "orttraining/training_ops/cuda/nn/conv_grad.h" -#include "core/providers/common.h" -#include "core/providers/cuda/shared_inc/fpgeneric.h" -#include "core/platform/ort_mutex.h" - -// The AlgoPerfCache and AlgoSearch here for Conv/ConvGrad is referenced on PyTorch's implementation -// from aten/src/ATen/native/cudnn/Conv_v7.cpp. - namespace onnxruntime { namespace cuda { @@ -22,229 +15,6 @@ REGISTER_GRADIENT_KERNEL_TYPED(float) REGISTER_GRADIENT_KERNEL_TYPED(double) REGISTER_GRADIENT_KERNEL_TYPED(MLFloat16) -using T_BwdDataPerf = cudnnConvolutionBwdDataAlgoPerf_t; -using T_BwdDataAlgo = cudnnConvolutionBwdDataAlgo_t; -using T_BwdFilterPerf = cudnnConvolutionBwdFilterAlgoPerf_t; -using T_BwdFilterAlgo = cudnnConvolutionBwdFilterAlgo_t; - -cudnnStatus_t GetWorkspaceSize(const ConvArgs& args, T_BwdDataAlgo algo, size_t* workspace_size) { - return cudnnGetConvolutionBackwardDataWorkspaceSize(args.handle, args.w_desc, args.y_tensor, args.conv_desc, - args.x_tensor, algo, workspace_size); -} - -cudnnStatus_t GetWorkspaceSize(const ConvArgs& args, T_BwdFilterAlgo algo, size_t* workspace_size) { - return cudnnGetConvolutionBackwardFilterWorkspaceSize(args.handle, args.x_tensor, args.y_tensor, args.conv_desc, - args.w_desc, algo, workspace_size); -} - -template -size_t GetMaxWorkspaceSize(const ConvArgs& args, const T_Algo* algo, int n_algo) { - // Calling cudaMemGetInfo is not ideal, but our cuda allocator doesn't have a way to get this info. - size_t free, total; - CUDA_CALL_THROW(cudaMemGetInfo(&free, &total)); - // Assuming 10% of fragmentation. - free = static_cast(static_cast(free) * 0.9); - size_t max_workspace_size = 0; - for (int i = 0; i < n_algo; i++) { - cudnnStatus_t status; - size_t workspace_size; - status = GetWorkspaceSize(args, algo[i], &workspace_size); - if (CUDNN_STATUS_SUCCESS != status || workspace_size == 0 || workspace_size < max_workspace_size || - workspace_size > free) - continue; - max_workspace_size = workspace_size; - } - - return max_workspace_size; -} - -template -std::vector GetValidAlgorithms(const T_Perf* perf_results, int n_algo) { - std::vector result; - result.reserve(n_algo); - for (int i = 0; i < n_algo; i++) { - T_Perf perf = perf_results[i]; - if (perf.status == CUDNN_STATUS_SUCCESS) { - result.emplace_back(perf); - } - } - ORT_ENFORCE(result.size() > 0, "No valid convolution algorithms available in CuDNN"); - // TODO: This is a cuDNN bug that gave wrong results in certain strided convolution gradient setups - // when cuDNN version < 7.5. Need to add handling for such special case. - return result; -} - -struct ConvParamsHash { - // ConvParams must be a POD because we read out its memory constant as char* when hashing. - static_assert(std::is_pod::value, "ConvParams is not POD"); - size_t operator()(const ConvParams& conv_params) const { - auto ptr = reinterpret_cast(&conv_params); - uint32_t value = 0x811C9DC5; - for (int i = 0; i < static_cast(sizeof(ConvParams)); ++i) { - value ^= ptr[i]; - value *= 0x01000193; - } - return static_cast(value); - } -}; - -struct ConvParamsEqual { - // ConvParams must be a POD because we read out its memory constant as char* when hashing. - static_assert(std::is_pod::value, "ConvParams is not POD"); - bool operator()(const ConvParams& a, const ConvParams& b) const { - auto ptr1 = reinterpret_cast(&a); - auto ptr2 = reinterpret_cast(&b); - return memcmp(ptr1, ptr2, sizeof(ConvParams)) == 0; - } -}; - -template -struct AlgoPerfCache { - mutable OrtMutex mutex; - std::unordered_map map; - - bool Find(const ConvParams& params, T_Perf* result) { - std::lock_guard guard(mutex); - auto it = map.find(params); - if (it == map.end()) { - return false; - } - *result = it->second; - return true; - } - - void Insert(const ConvParams& params, const T_Perf& algo_perf) { - std::lock_guard guard(mutex); - map[params] = algo_perf; - } -}; - -// TODO: Currently we use global AlgoPerfCache for ConvGrad only. Conv's perf cache is till per node. -// Need to apply such global cache for Conv, and move some shared code from here to conv.h/cc. -AlgoPerfCache bwd_data_algos; -AlgoPerfCache bwd_filter_algos; - -template -struct AlgoSearch {}; - -template <> -struct AlgoSearch { - static constexpr auto DEFAULT_ALGO = CUDNN_CONVOLUTION_BWD_DATA_ALGO_1; - static AlgoPerfCache& Cache() { return bwd_data_algos; } - static Status FindAlgorithms(const ConvArgs& args, const CUDAExecutionProvider* provider, - std::vector& perf_results) { - static const T_BwdDataAlgo algos[] = { - CUDNN_CONVOLUTION_BWD_DATA_ALGO_0, CUDNN_CONVOLUTION_BWD_DATA_ALGO_1, - CUDNN_CONVOLUTION_BWD_DATA_ALGO_FFT, CUDNN_CONVOLUTION_BWD_DATA_ALGO_FFT_TILING, - CUDNN_CONVOLUTION_BWD_DATA_ALGO_WINOGRAD, CUDNN_CONVOLUTION_BWD_DATA_ALGO_WINOGRAD_NONFUSED}; - static constexpr int num_algos = CUDNN_CONVOLUTION_BWD_DATA_ALGO_COUNT; - ORT_ENFORCE(sizeof(algos) / sizeof(algos[0]) == num_algos, "Missing cuDNN convolution backward data algorithms."); - int perf_count; - std::unique_ptr candidates = std::make_unique(num_algos); - if (args.params.algo_mode == OrtCudnnConvAlgoSearchHeuristic) { - CUDNN_RETURN_IF_ERROR(cudnnGetConvolutionBackwardDataAlgorithm_v7(args.handle, args.w_desc, args.y_tensor, - args.conv_desc, args.x_tensor, num_algos, - &perf_count, candidates.get())); - } else if (args.params.algo_mode == OrtCudnnConvAlgoSearchExhaustive) { - size_t max_workspace_size = provider->GetCudnnConvUseMaxWorkspace() ? GetMaxWorkspaceSize(args, algos, num_algos) - : AlgoSearchWorkspaceSize; - // Use GetTransientScratchBuffer() so the workspace can be freed instead of cached. - // Because the benchmarking uses a huge amount of memory, e.g. a few GBs. - IAllocatorUniquePtr workspace = provider->GetTransientScratchBuffer(max_workspace_size); - CUDNN_RETURN_IF_ERROR(cudnnFindConvolutionBackwardDataAlgorithmEx( - args.handle, args.w_desc, args.w_data, args.y_tensor, args.dy_data, args.conv_desc, args.x_tensor, - args.dx_data, num_algos, &perf_count, candidates.get(), workspace.get(), max_workspace_size)); - } else { - ORT_ENFORCE(false, "Algo mode should be EXHAUSTIVE (0) or HEURISTIC (1), but got ", args.params.algo_mode); - } - perf_results = GetValidAlgorithms(candidates.get(), perf_count); - return Status::OK(); - } -}; - -template <> -struct AlgoSearch { - static constexpr auto DEFAULT_ALGO = CUDNN_CONVOLUTION_BWD_FILTER_ALGO_1; - static AlgoPerfCache& Cache() { return bwd_filter_algos; } - static Status FindAlgorithms(const ConvArgs& args, const CUDAExecutionProvider* provider, - std::vector& perf_results) { - static const T_BwdFilterAlgo algos[] = { - CUDNN_CONVOLUTION_BWD_FILTER_ALGO_0, - CUDNN_CONVOLUTION_BWD_FILTER_ALGO_1, - CUDNN_CONVOLUTION_BWD_FILTER_ALGO_FFT, - CUDNN_CONVOLUTION_BWD_FILTER_ALGO_3, - CUDNN_CONVOLUTION_BWD_FILTER_ALGO_WINOGRAD_NONFUSED, - CUDNN_CONVOLUTION_BWD_FILTER_ALGO_FFT_TILING, - }; - - // NOTE: - 1 because ALGO_WINOGRAD is not implemented. - static constexpr int num_algos = CUDNN_CONVOLUTION_BWD_FILTER_ALGO_COUNT - 1; - ORT_ENFORCE(sizeof(algos) / sizeof(algos[0]) == num_algos, "Missing cuDNN convolution backward filter algorithms."); - std::unique_ptr candidates = std::make_unique(num_algos); - int perf_count; - if (args.params.algo_mode == OrtCudnnConvAlgoSearchHeuristic) { - CUDNN_RETURN_IF_ERROR(cudnnGetConvolutionBackwardFilterAlgorithm_v7(args.handle, args.x_tensor, args.y_tensor, - args.conv_desc, args.w_desc, num_algos, - &perf_count, candidates.get())); - } else if (args.params.algo_mode == OrtCudnnConvAlgoSearchExhaustive) { - size_t max_workspace_size = provider->GetCudnnConvUseMaxWorkspace() ? GetMaxWorkspaceSize(args, algos, num_algos) - : AlgoSearchWorkspaceSize; - // Use GetTransientScratchBuffer() so the workspace can be freed instead of cached. - // Because the benchmarking uses a huge amount of memory, e.g. a few GBs. - IAllocatorUniquePtr workspace = provider->GetTransientScratchBuffer(max_workspace_size); - CUDNN_RETURN_IF_ERROR(cudnnFindConvolutionBackwardFilterAlgorithmEx( - args.handle, args.x_tensor, args.x_data, args.y_tensor, args.dy_data, args.conv_desc, args.w_desc, - args.dw_data, num_algos, &perf_count, candidates.get(), workspace.get(), max_workspace_size)); - } else { - ORT_ENFORCE(false, "Algo mode should be EXHAUSTIVE (0) or HEURISTIC (1), but got ", args.params.algo_mode); - } - perf_results = GetValidAlgorithms(candidates.get(), perf_count); - return Status::OK(); - } -}; - -template -class AlgoIterator { - public: - AlgoIterator(const ConvArgs& args) : args_(args) {} - - static Status OnlyDefaultAlgorithm(const ConvArgs& args, std::vector& perf_results) { - perf_results.resize(1); - perf_results[0].algo = AlgoSearch::DEFAULT_ALGO; - if (args.params.data_type == CUDNN_DATA_HALF) { - perf_results[0].mathType = CUDNN_TENSOR_OP_MATH; - } else { - perf_results[0].mathType = CUDNN_DEFAULT_MATH; - } - CUDNN_RETURN_IF_ERROR(GetWorkspaceSize(args, perf_results[0].algo, &(perf_results[0].memory))); - return Status::OK(); - } - - Status TryAll(const CUDAExecutionProvider* provider, cudaStream_t /*stream*/, std::function f) { - auto& cache = AlgoSearch::Cache(); - - if (T_Perf algo_perf; cache.Find(args_.params, &algo_perf) && f(algo_perf) == Status::OK()) { - return Status::OK(); - } - - std::vector perf_results; - ORT_RETURN_IF_ERROR(args_.params.algo_mode == OrtCudnnConvAlgoSearchDefault - ? OnlyDefaultAlgorithm(args_, perf_results) - : AlgoSearch::FindAlgorithms(args_, provider, perf_results)); - for (auto& algo_perf : perf_results) { - if (f(algo_perf) == Status::OK()) { - cache.Insert(args_.params, algo_perf); - return Status::OK(); - } - } - ORT_ENFORCE(false, "Unable to find a valid cuDNN algorithm to run convolution."); - return Status::OK(); - } - - private: - const ConvArgs& args_; -}; - template Status ConvGrad::PrepareArgs(const Tensor& x, const Tensor& dY, const Tensor& w, Tensor* dB, Tensor* dX, Tensor* dW, cudnnHandle_t cudnn_handle) const { @@ -375,10 +145,9 @@ Status ConvGrad::ComputeInternal(OpKernelContext* context) const { template Status ConvGrad::ComputeInputGradient(onnxruntime::Stream* stream) const { - cudaStream_t cuda_stream = stream ? static_cast(stream->GetHandle()) : nullptr; return AlgoIterator(args_).TryAll( static_cast(Info().GetExecutionProvider()), - cuda_stream, + Info().GetAllocator(OrtMemType::OrtMemTypeDefault), [&](const T_BwdDataPerf& algo_perf) -> Status { const auto one = Consts::One; const auto zero = Consts::Zero; @@ -393,10 +162,9 @@ Status ConvGrad::ComputeInputGradient(onnxruntime::Stream* stream) const { template Status ConvGrad::ComputeWeightGradient(onnxruntime::Stream* stream) const { - cudaStream_t cuda_stream = stream ? static_cast(stream->GetHandle()) : nullptr; return AlgoIterator(args_).TryAll( static_cast(Info().GetExecutionProvider()), - cuda_stream, + Info().GetAllocator(OrtMemType::OrtMemTypeDefault), [&](const T_BwdFilterPerf& algo_perf) -> Status { const auto one = Consts::One; const auto zero = Consts::Zero; diff --git a/orttraining/orttraining/training_ops/cuda/nn/conv_grad.h b/orttraining/orttraining/training_ops/cuda/nn/conv_grad.h index c0abe0012db39..9bbcd5b30d168 100644 --- a/orttraining/orttraining/training_ops/cuda/nn/conv_grad.h +++ b/orttraining/orttraining/training_ops/cuda/nn/conv_grad.h @@ -3,54 +3,18 @@ #pragma once -#include "core/providers/cuda/cudnn_common.h" -#include "core/providers/cpu/nn/conv_attributes.h" -#include "core/providers/cuda/nn/conv.h" +#include "orttraining/training_ops/cuda/nn/conv_shared.h" namespace onnxruntime { namespace cuda { -// cuDNN only takes 4D or 5D x tensor. -constexpr int MAX_DIM = 3; - -struct ConvParams { - int8_t device_id; - cudnnDataType_t data_type; - int input_size[2 + MAX_DIM]; - uint8_t input_dim; - int weight_size[2 + MAX_DIM]; - int padding[MAX_DIM * 2]; - int stride[MAX_DIM]; - int dilation[MAX_DIM]; - int64_t groups; - int algo_mode; -}; - -struct ConvArgs { - // Update needed if x or w's dims changed. - TensorShapeVector last_x_dims; - TensorShapeVector last_w_dims; - - cudnnHandle_t handle; - ConvParams params; - CudnnTensor x_tensor, y_tensor, b_tensor; - CudnnFilterDescriptor w_desc; - CudnnConvolutionDescriptor conv_desc; - const void* x_data; - const void* w_data; - const void* dy_data; - void* dx_data; - void* dw_data; - void* db_data; -}; - template class ConvGrad final : public CudaKernel { public: using CudaT = typename ToCudaType::MappedType; ConvGrad(const OpKernelInfo& info) : CudaKernel(info), conv_attrs_(info) { -#if (defined(CUDA_VERSION) && (CUDA_VERSION < 10000) || (defined(__CUDA_ARCH__) && (__CUDA_ARCH__ < 700))) +#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ < 700) ORT_THROW("ConvGrad CUDA kernel is not yet tested on __CUDA_ARCH__ lower than 700"); #endif auto pads_size = conv_attrs_.pads.size(); diff --git a/orttraining/orttraining/training_ops/cuda/nn/conv_shared.cc b/orttraining/orttraining/training_ops/cuda/nn/conv_shared.cc new file mode 100644 index 0000000000000..5dc16c68f6210 --- /dev/null +++ b/orttraining/orttraining/training_ops/cuda/nn/conv_shared.cc @@ -0,0 +1,275 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "orttraining/training_ops/cuda/nn/conv_shared.h" + +#include "core/platform/ort_mutex.h" +#include "core/providers/common.h" +#include "core/providers/cuda/cuda_kernel.h" + +namespace onnxruntime::cuda { + +namespace { + +cudnnStatus_t GetWorkspaceSize(const ConvArgs& args, T_BwdDataAlgo algo, size_t* workspace_size) { + return cudnnGetConvolutionBackwardDataWorkspaceSize(args.handle, args.w_desc, args.y_tensor, args.conv_desc, + args.x_tensor, algo, workspace_size); +} + +cudnnStatus_t GetWorkspaceSize(const ConvArgs& args, T_BwdFilterAlgo algo, size_t* workspace_size) { + return cudnnGetConvolutionBackwardFilterWorkspaceSize(args.handle, args.x_tensor, args.y_tensor, args.conv_desc, + args.w_desc, algo, workspace_size); +} + +cudnnStatus_t GetWorkspaceSize(const ConvArgs& args, T_FwdAlgo algo, size_t* workspace_size) { + return cudnnGetConvolutionForwardWorkspaceSize(args.handle, args.x_tensor, args.w_desc, args.conv_desc, + args.y_tensor, algo, workspace_size); +} + +template +size_t GetMaxWorkspaceSize(const ConvArgs& args, const T_Algo* algo, int n_algo) { + // Calling cudaMemGetInfo is not ideal, but our cuda allocator doesn't have a way to get this info. + size_t free, total; + CUDA_CALL_THROW(cudaMemGetInfo(&free, &total)); + // Assuming 10% of fragmentation. + free = static_cast(static_cast(free) * 0.9); + size_t max_workspace_size = 0; + for (int i = 0; i < n_algo; i++) { + cudnnStatus_t status; + size_t workspace_size; + status = GetWorkspaceSize(args, algo[i], &workspace_size); + if (CUDNN_STATUS_SUCCESS != status || workspace_size == 0 || workspace_size < max_workspace_size || + workspace_size > free) + continue; + max_workspace_size = workspace_size; + } + + return max_workspace_size; +} + +template +std::vector GetValidAlgorithms(const T_Perf* perf_results, int n_algo) { + std::vector result; + result.reserve(n_algo); + for (int i = 0; i < n_algo; i++) { + T_Perf perf = perf_results[i]; + if (perf.status == CUDNN_STATUS_SUCCESS) { + result.emplace_back(perf); + } + } + ORT_ENFORCE(result.size() > 0, "No valid convolution algorithms available in CuDNN"); + // TODO: This is a cuDNN bug that gave wrong results in certain strided convolution gradient setups + // when cuDNN version < 7.5. Need to add handling for such special case. + return result; +} + +template +struct AlgoPerfCache { + mutable OrtMutex mutex; + std::unordered_map map; + + bool Find(const ConvParams& params, T_Perf* result) { + std::lock_guard guard(mutex); + auto it = map.find(params); + if (it == map.end()) { + return false; + } + *result = it->second; + return true; + } + + void Insert(const ConvParams& params, const T_Perf& algo_perf) { + std::lock_guard guard(mutex); + map[params] = algo_perf; + } +}; + +// TODO: Currently we use global AlgoPerfCache for ConvGrad and ConvTransposeGrad only. +// Conv's perf cache is still per node. +// Need to apply such global cache for Conv, and move some shared code from here to conv.h/cc. +AlgoPerfCache bwd_data_algos; +AlgoPerfCache bwd_filter_algos; +AlgoPerfCache fwd_algos; + +template +struct AlgoSearch {}; + +template <> +struct AlgoSearch { + static constexpr auto DEFAULT_ALGO = CUDNN_CONVOLUTION_BWD_DATA_ALGO_1; + static AlgoPerfCache& Cache() { return bwd_data_algos; } + static Status FindAlgorithms(const ConvArgs& args, const CUDAExecutionProvider* provider, const AllocatorPtr& allocator, + std::vector& perf_results) { + static const T_BwdDataAlgo algos[] = { + CUDNN_CONVOLUTION_BWD_DATA_ALGO_0, CUDNN_CONVOLUTION_BWD_DATA_ALGO_1, + CUDNN_CONVOLUTION_BWD_DATA_ALGO_FFT, CUDNN_CONVOLUTION_BWD_DATA_ALGO_FFT_TILING, + CUDNN_CONVOLUTION_BWD_DATA_ALGO_WINOGRAD, CUDNN_CONVOLUTION_BWD_DATA_ALGO_WINOGRAD_NONFUSED}; + static constexpr int num_algos = CUDNN_CONVOLUTION_BWD_DATA_ALGO_COUNT; + ORT_ENFORCE(sizeof(algos) / sizeof(algos[0]) == num_algos, "Missing cuDNN convolution backward data algorithms."); + int perf_count; + std::unique_ptr candidates = std::make_unique(num_algos); + if (args.params.algo_mode == OrtCudnnConvAlgoSearchHeuristic) { + CUDNN_RETURN_IF_ERROR(cudnnGetConvolutionBackwardDataAlgorithm_v7(args.handle, args.w_desc, args.y_tensor, + args.conv_desc, args.x_tensor, num_algos, + &perf_count, candidates.get())); + } else if (args.params.algo_mode == OrtCudnnConvAlgoSearchExhaustive) { + size_t max_workspace_size = provider->GetCudnnConvUseMaxWorkspace() ? GetMaxWorkspaceSize(args, algos, num_algos) + : AlgoSearchWorkspaceSize; + // Use GetTransientScratchBuffer() so the workspace can be freed instead of cached. + // Because the benchmarking uses a huge amount of memory, e.g. a few GBs. + IAllocatorUniquePtr workspace = max_workspace_size == 0 ? nullptr : IAllocator::MakeUniquePtr(allocator, max_workspace_size, true); + CUDNN_RETURN_IF_ERROR(cudnnFindConvolutionBackwardDataAlgorithmEx( + args.handle, args.w_desc, args.w_data, args.y_tensor, args.dy_data, args.conv_desc, args.x_tensor, + args.dx_data, num_algos, &perf_count, candidates.get(), workspace.get(), max_workspace_size)); + } else { + ORT_ENFORCE(false, "Algo mode should be EXHAUSTIVE (0) or HEURISTIC (1), but got ", args.params.algo_mode); + } + perf_results = GetValidAlgorithms(candidates.get(), perf_count); + return Status::OK(); + } +}; + +template <> +struct AlgoSearch { + static constexpr auto DEFAULT_ALGO = CUDNN_CONVOLUTION_BWD_FILTER_ALGO_1; + static AlgoPerfCache& Cache() { return bwd_filter_algos; } + static Status FindAlgorithms(const ConvArgs& args, const CUDAExecutionProvider* provider, const AllocatorPtr& allocator, + std::vector& perf_results) { + static const T_BwdFilterAlgo algos[] = { + CUDNN_CONVOLUTION_BWD_FILTER_ALGO_0, + CUDNN_CONVOLUTION_BWD_FILTER_ALGO_1, + CUDNN_CONVOLUTION_BWD_FILTER_ALGO_FFT, + CUDNN_CONVOLUTION_BWD_FILTER_ALGO_3, + CUDNN_CONVOLUTION_BWD_FILTER_ALGO_WINOGRAD_NONFUSED, + CUDNN_CONVOLUTION_BWD_FILTER_ALGO_FFT_TILING, + }; + + // NOTE: - 1 because ALGO_WINOGRAD is not implemented. + static constexpr int num_algos = CUDNN_CONVOLUTION_BWD_FILTER_ALGO_COUNT - 1; + ORT_ENFORCE(sizeof(algos) / sizeof(algos[0]) == num_algos, "Missing cuDNN convolution backward filter algorithms."); + std::unique_ptr candidates = std::make_unique(num_algos); + int perf_count; + if (args.params.algo_mode == OrtCudnnConvAlgoSearchHeuristic) { + CUDNN_RETURN_IF_ERROR(cudnnGetConvolutionBackwardFilterAlgorithm_v7(args.handle, args.x_tensor, args.y_tensor, + args.conv_desc, args.w_desc, num_algos, + &perf_count, candidates.get())); + } else if (args.params.algo_mode == OrtCudnnConvAlgoSearchExhaustive) { + size_t max_workspace_size = provider->GetCudnnConvUseMaxWorkspace() ? GetMaxWorkspaceSize(args, algos, num_algos) + : AlgoSearchWorkspaceSize; + // Use GetTransientScratchBuffer() so the workspace can be freed instead of cached. + // Because the benchmarking uses a huge amount of memory, e.g. a few GBs. + IAllocatorUniquePtr workspace = max_workspace_size == 0 ? nullptr : IAllocator::MakeUniquePtr(allocator, max_workspace_size, true); + CUDNN_RETURN_IF_ERROR(cudnnFindConvolutionBackwardFilterAlgorithmEx( + args.handle, args.x_tensor, args.x_data, args.y_tensor, args.dy_data, args.conv_desc, args.w_desc, + args.dw_data, num_algos, &perf_count, candidates.get(), workspace.get(), max_workspace_size)); + } else { + ORT_ENFORCE(false, "Algo mode should be EXHAUSTIVE (0) or HEURISTIC (1), but got ", args.params.algo_mode); + } + perf_results = GetValidAlgorithms(candidates.get(), perf_count); + return Status::OK(); + } +}; + +template <> +struct AlgoSearch { + static constexpr auto DEFAULT_ALGO = CUDNN_CONVOLUTION_FWD_ALGO_IMPLICIT_PRECOMP_GEMM; + static AlgoPerfCache& Cache() { return fwd_algos; } + static Status FindAlgorithms(const ConvArgs& args, const CUDAExecutionProvider* provider, const AllocatorPtr& allocator, + std::vector& perf_results) { + static const T_FwdAlgo algos[] = { + CUDNN_CONVOLUTION_FWD_ALGO_GEMM, + CUDNN_CONVOLUTION_FWD_ALGO_FFT, + CUDNN_CONVOLUTION_FWD_ALGO_FFT_TILING, + CUDNN_CONVOLUTION_FWD_ALGO_IMPLICIT_GEMM, + CUDNN_CONVOLUTION_FWD_ALGO_IMPLICIT_PRECOMP_GEMM, + CUDNN_CONVOLUTION_FWD_ALGO_DIRECT, + CUDNN_CONVOLUTION_FWD_ALGO_WINOGRAD, + CUDNN_CONVOLUTION_FWD_ALGO_WINOGRAD_NONFUSED, + }; + + static constexpr int num_algos = CUDNN_CONVOLUTION_FWD_ALGO_COUNT; + ORT_ENFORCE(sizeof(algos) / sizeof(algos[0]) == num_algos, "Missing cuDNN convolution backward filter algorithms."); + std::unique_ptr candidates = std::make_unique(num_algos); + int perf_count; + if (args.params.algo_mode == OrtCudnnConvAlgoSearchHeuristic) { + CUDNN_RETURN_IF_ERROR(cudnnGetConvolutionForwardAlgorithm_v7(args.handle, args.x_tensor, args.w_desc, + args.conv_desc, args.y_tensor, num_algos, + &perf_count, candidates.get())); + } else if (args.params.algo_mode == OrtCudnnConvAlgoSearchExhaustive) { + size_t max_workspace_size = provider->GetCudnnConvUseMaxWorkspace() ? GetMaxWorkspaceSize(args, algos, num_algos) + : AlgoSearchWorkspaceSize; + // Use GetTransientScratchBuffer() so the workspace can be freed instead of cached. + // Because the benchmarking uses a huge amount of memory, e.g. a few GBs. + IAllocatorUniquePtr workspace = max_workspace_size == 0 + ? nullptr + : IAllocator::MakeUniquePtr(allocator, max_workspace_size, true); + CUDNN_RETURN_IF_ERROR(cudnnFindConvolutionForwardAlgorithmEx( + args.handle, args.x_tensor, args.x_data, args.w_desc, args.w_data, args.conv_desc, args.y_tensor, + args.y_data, num_algos, &perf_count, candidates.get(), workspace.get(), max_workspace_size)); + } else { + ORT_ENFORCE(false, "Algo mode should be EXHAUSTIVE (0) or HEURISTIC (1), but got ", args.params.algo_mode); + } + perf_results = GetValidAlgorithms(candidates.get(), perf_count); + return Status::OK(); + } +}; + +} // namespace + +size_t ConvParamsHash::operator()(const ConvParams& conv_params) const { + auto ptr = reinterpret_cast(&conv_params); + uint32_t value = 0x811C9DC5; + for (int i = 0; i < static_cast(sizeof(ConvParams)); ++i) { + value ^= ptr[i]; + value *= 0x01000193; + } + return static_cast(value); +} + +bool ConvParamsEqual::operator()(const ConvParams& a, const ConvParams& b) const { + auto ptr1 = reinterpret_cast(&a); + auto ptr2 = reinterpret_cast(&b); + return memcmp(ptr1, ptr2, sizeof(ConvParams)) == 0; +} + +template +Status AlgoIterator::OnlyDefaultAlgorithm(const ConvArgs& args, std::vector& perf_results) { + perf_results.resize(1); + perf_results[0].algo = AlgoSearch::DEFAULT_ALGO; + if (args.params.data_type == CUDNN_DATA_HALF) { + perf_results[0].mathType = CUDNN_TENSOR_OP_MATH; + } else { + perf_results[0].mathType = CUDNN_DEFAULT_MATH; + } + CUDNN_RETURN_IF_ERROR(GetWorkspaceSize(args, perf_results[0].algo, &(perf_results[0].memory))); + return Status::OK(); +} + +template +Status AlgoIterator::TryAll(const CUDAExecutionProvider* provider, const AllocatorPtr& allocator, + std::function f) { + auto& cache = AlgoSearch::Cache(); + + if (T_Perf algo_perf; cache.Find(args_.params, &algo_perf) && f(algo_perf) == Status::OK()) { + return Status::OK(); + } + + std::vector perf_results; + ORT_RETURN_IF_ERROR(args_.params.algo_mode == OrtCudnnConvAlgoSearchDefault + ? OnlyDefaultAlgorithm(args_, perf_results) + : AlgoSearch::FindAlgorithms(args_, provider, allocator, perf_results)); + for (auto& algo_perf : perf_results) { + if (f(algo_perf) == Status::OK()) { + cache.Insert(args_.params, algo_perf); + return Status::OK(); + } + } + ORT_ENFORCE(false, "Unable to find a valid cuDNN algorithm to run convolution."); + return Status::OK(); +} + +template class AlgoIterator; +template class AlgoIterator; +template class AlgoIterator; + +} // namespace onnxruntime::cuda diff --git a/orttraining/orttraining/training_ops/cuda/nn/conv_shared.h b/orttraining/orttraining/training_ops/cuda/nn/conv_shared.h new file mode 100644 index 0000000000000..a2d4bf3bdc006 --- /dev/null +++ b/orttraining/orttraining/training_ops/cuda/nn/conv_shared.h @@ -0,0 +1,84 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/providers/cuda/cudnn_common.h" +#include "core/providers/cuda/nn/conv.h" + +// The AlgoPerfCache and AlgoSearch here for Conv/ConvGrad/ConvTransposeGrad is adapted from PyTorch's implementation +// in aten/src/ATen/native/cudnn/Conv_v7.cpp. + +namespace onnxruntime::cuda { + +using T_BwdDataPerf = cudnnConvolutionBwdDataAlgoPerf_t; +using T_BwdDataAlgo = cudnnConvolutionBwdDataAlgo_t; +using T_BwdFilterPerf = cudnnConvolutionBwdFilterAlgoPerf_t; +using T_BwdFilterAlgo = cudnnConvolutionBwdFilterAlgo_t; +using T_FwdAlgo = cudnnConvolutionFwdAlgo_t; +using T_FwdPerf = cudnnConvolutionFwdAlgoPerf_t; + +// cuDNN only takes 4D or 5D x tensor. +static constexpr int MAX_DIM = 3; + +struct ConvParams { + int8_t device_id; + cudnnDataType_t data_type; + int input_size[2 + MAX_DIM]; + uint8_t input_dim; + int weight_size[2 + MAX_DIM]; + int padding[MAX_DIM * 2]; + int stride[MAX_DIM]; + int dilation[MAX_DIM]; + int64_t groups; + int algo_mode; +}; + +struct ConvArgs { + // Update needed if x or w's dims changed. + TensorShapeVector last_x_dims; // Input to the convolution + TensorShapeVector last_w_dims; // Weights of the convolution + + cudnnHandle_t handle; + ConvParams params; + CudnnTensor x_tensor, y_tensor, b_tensor; + CudnnFilterDescriptor w_desc; + CudnnConvolutionDescriptor conv_desc; + const void* x_data; + const void* w_data; + const void* dy_data; + void* y_data; + void* dx_data; + void* dw_data; + void* db_data; +}; + +struct ConvParamsHash { + // ConvParams must be a POD because we read out its memory constant as char* when hashing. + static_assert(std::is_pod::value, "ConvParams is not POD"); + + size_t operator()(const ConvParams& conv_params) const; +}; + +struct ConvParamsEqual { + // ConvParams must be a POD because we read out its memory constant as char* when hashing. + static_assert(std::is_pod::value, "ConvParams is not POD"); + + bool operator()(const ConvParams& a, const ConvParams& b) const; +}; + +template +class AlgoIterator { + public: + AlgoIterator(const ConvArgs& args) : args_(args) {} + + Status TryAll(const CUDAExecutionProvider* provider, const AllocatorPtr& allocator, + std::function f); + + static Status OnlyDefaultAlgorithm(const ConvArgs& args, std::vector& perf_results); + + private: + const ConvArgs& args_; +}; + +} // namespace onnxruntime::cuda diff --git a/orttraining/orttraining/training_ops/cuda/nn/conv_transpose_grad.cc b/orttraining/orttraining/training_ops/cuda/nn/conv_transpose_grad.cc new file mode 100644 index 0000000000000..5f7206fc121ec --- /dev/null +++ b/orttraining/orttraining/training_ops/cuda/nn/conv_transpose_grad.cc @@ -0,0 +1,308 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "orttraining/training_ops/cuda/nn/conv_transpose_grad.h" + +namespace onnxruntime::cuda { + +#define REGISTER_CONVTRANSPOSE_GRADIENT_KERNEL_TYPED(T) \ + ONNX_OPERATOR_TYPED_KERNEL_EX(ConvTransposeGrad, kMSDomain, 1, T, kCudaExecutionProvider, \ + (*KernelDefBuilder::Create()) \ + .TypeConstraint("T", DataTypeImpl::GetTensorType()), \ + ConvTransposeGrad); + +REGISTER_CONVTRANSPOSE_GRADIENT_KERNEL_TYPED(float) +REGISTER_CONVTRANSPOSE_GRADIENT_KERNEL_TYPED(double) +REGISTER_CONVTRANSPOSE_GRADIENT_KERNEL_TYPED(MLFloat16) + +template +Status ConvTransposeGrad::ComputeInternal(OpKernelContext* context) const { + const Tensor* dY = context->Input(0); + const Tensor* X = context->Input(1); + const Tensor* W = context->Input(2); + Tensor* dX = context->Output(0, X->Shape()); + Tensor* dW = context->Output(1, W->Shape()); + Tensor* dB = context->Output(2, {W->Shape()[1] * conv_attrs_.group}); + + if (dX) { + ORT_RETURN_IF_ERROR(PrepareConvForwardArgs(*dY, *W, *dX, GetCudnnHandle(context), args_dx_)); + ORT_RETURN_IF_ERROR(ComputeInputGradient(context->GetComputeStream(), args_dx_)); + } + + if (dW || dB) { + ORT_RETURN_IF_ERROR(PrepareConvBackwardFilterArgs(*dY, *W, *X, dW, dB, GetCudnnHandle(context), args_dw_)); + if (dW) ORT_RETURN_IF_ERROR(ComputeWeightGradient(context->GetComputeStream(), args_dw_)); + if (dB) ORT_RETURN_IF_ERROR(ComputeBiasGradient(args_dw_)); + } + + return Status::OK(); +} + +template +Status ConvTransposeGrad::ComputeInputGradient(onnxruntime::Stream* stream, const ConvArgs& args) const { + return AlgoIterator(args).TryAll( + static_cast(Info().GetExecutionProvider()), + Info().GetAllocator(OrtMemType::OrtMemTypeDefault), + [&](const T_FwdPerf& algo_perf) -> Status { + const auto one = Consts::One; + const auto zero = Consts::Zero; + IAllocatorUniquePtr workspace = GetScratchBuffer(algo_perf.memory, stream); + CUDNN_RETURN_IF_ERROR(cudnnSetConvolutionMathType(args.conv_desc, algo_perf.mathType)); + CUDNN_RETURN_IF_ERROR(cudnnConvolutionForward( + args.handle, &one, args.x_tensor, args.x_data, args.w_desc, args.w_data, args.conv_desc, + algo_perf.algo, workspace.get(), algo_perf.memory, &zero, args.y_tensor, args.y_data)); + return Status::OK(); + }); + return Status::OK(); +} + +template +Status ConvTransposeGrad::ComputeWeightGradient(onnxruntime::Stream* stream, const ConvArgs& args) const { + return AlgoIterator(args).TryAll( + static_cast(Info().GetExecutionProvider()), + Info().GetAllocator(OrtMemType::OrtMemTypeDefault), + [&](const T_BwdFilterPerf& algo_perf) -> Status { + const auto one = Consts::One; + const auto zero = Consts::Zero; + IAllocatorUniquePtr workspace = GetScratchBuffer(algo_perf.memory, stream); + CUDNN_RETURN_IF_ERROR(cudnnSetConvolutionMathType(args.conv_desc, algo_perf.mathType)); + CUDNN_RETURN_IF_ERROR(cudnnConvolutionBackwardFilter( + args.handle, &one, args.x_tensor, args.x_data, args.y_tensor, args.dy_data, args.conv_desc, + algo_perf.algo, workspace.get(), algo_perf.memory, &zero, args.w_desc, args.dw_data)); + return Status::OK(); + }); + return Status::OK(); +} + +template +Status ConvTransposeGrad::ComputeBiasGradient(const ConvArgs& args) const { + const auto one = Consts::One; + const auto zero = Consts::Zero; + CUDNN_RETURN_IF_ERROR(cudnnConvolutionBackwardBias(args.handle, &one, args.x_tensor, args.x_data, &zero, + args.b_tensor, args.db_data)); + return Status::OK(); +} + +template +Status ConvTransposeGrad::PrepareConvForwardArgs(const Tensor& X, const Tensor& W, + Tensor& Y, cudnnHandle_t cudnn_handle, + ConvArgs& args) const { + const TensorShape& x_shape = X.Shape(); + auto x_dims = x_shape.AsShapeVector(); + args.x_data = reinterpret_cast(X.template Data()); + + const TensorShape& w_shape = W.Shape(); + auto w_dims = w_shape.AsShapeVector(); + args.w_data = reinterpret_cast(W.template Data()); + + const TensorShape& y_shape = Y.Shape(); + auto y_dims = y_shape.AsShapeVector(); + args.y_data = reinterpret_cast(Y.template MutableData()); + + args.dy_data = nullptr; + args.db_data = nullptr; + args.dx_data = nullptr; + args.dw_data = nullptr; + + bool x_dims_changed = (args.last_x_dims != x_dims); + bool w_dims_changed = (args.last_w_dims != w_dims); + if (x_dims_changed || w_dims_changed) { + if (x_dims_changed) args.last_x_dims = x_dims; + if (w_dims_changed) args.last_w_dims = w_dims; + + ORT_RETURN_IF_ERROR(conv_attrs_.ValidateInputShape(&X, &W)); + + TensorShapeVector kernel_shape; + ORT_RETURN_IF_ERROR(conv_attrs_.ComputeKernelShape(w_shape, kernel_shape)); + auto rank = kernel_shape.size(); + + ConvPadVector pads(conv_attrs_.pads); + if (pads.empty()) { + pads.resize(rank * 2, 0); + } + + TensorShapeVector dilations(conv_attrs_.dilations); + if (dilations.empty()) { + dilations.resize(rank, 1); + } + + TensorShapeVector strides(conv_attrs_.strides); + if (strides.empty()) { + strides.resize(rank, 1); + } + + const CUDAExecutionProvider* cuda_ep = + static_cast(this->Info().GetExecutionProvider()); + + if (rank < 2) { + if (cuda_ep->GetCudnnConv1dPadToNc1d()) { + x_dims.insert(x_dims.begin() + 2, 1); + y_dims.insert(y_dims.begin() + 2, 1); + w_dims.insert(w_dims.begin() + 2, 1); + pads.insert(pads.begin() + rank, 0); + pads.insert(pads.begin(), 0); + kernel_shape.insert(kernel_shape.begin(), 1); + strides.insert(strides.begin(), 1); + dilations.insert(dilations.begin(), 1); + } else { + x_dims.push_back(1); + y_dims.push_back(1); + w_dims.push_back(1); + pads.insert(pads.begin() + rank, 0); + pads.insert(pads.end(), 0); + kernel_shape.push_back(1); + strides.push_back(1); + dilations.push_back(1); + } + } + + memset(&args.params, 0, sizeof(ConvParams)); + args.params.device_id = static_cast(cuda_ep->GetDeviceId()); + args.params.data_type = CudnnTensor::GetDataType(); + args.params.input_dim = static_cast(x_dims.size()); + for (size_t i = 0; i < x_dims.size(); i++) { + args.params.input_size[i] = static_cast(x_dims[i]); + args.params.weight_size[i] = static_cast(w_dims[i]); + } + for (size_t i = 0; i < rank; i++) { + args.params.padding[i] = static_cast(pads[i]); + args.params.padding[i + rank] = static_cast(pads[i + rank]); + args.params.stride[i] = static_cast(strides[i]); + args.params.dilation[i] = static_cast(dilations[i]); + } + args.params.groups = conv_attrs_.group; + int algo_mode = cuda_ep->GetCudnnConvAlgo(); + ORT_ENFORCE(algo_mode > -1 && algo_mode < 3, + "Algo mode should be EXHAUSTIVE (0), HEURISTIC (1) or DEFAULT (2), but got ", algo_mode); + args.params.algo_mode = algo_mode; + + args.handle = cudnn_handle; + ORT_RETURN_IF_ERROR(args.w_desc.Set(w_dims, args.params.data_type)); + ORT_RETURN_IF_ERROR(args.x_tensor.Set(x_dims, args.params.data_type)); + ORT_RETURN_IF_ERROR(args.y_tensor.Set(y_dims, args.params.data_type)); + ORT_RETURN_IF_ERROR(args.conv_desc.Set(kernel_shape.size(), pads, strides, dilations, + gsl::narrow_cast(conv_attrs_.group), CUDNN_CROSS_CORRELATION, + args.params.data_type)); + } + + return Status::OK(); +} + +template +Status ConvTransposeGrad::PrepareConvBackwardFilterArgs(const Tensor& X, const Tensor& W, const Tensor& dY, + Tensor* dW, Tensor* dB, cudnnHandle_t cudnn_handle, + ConvArgs& args) const { + const TensorShape& x_shape = X.Shape(); + auto x_dims = x_shape.AsShapeVector(); + args.x_data = reinterpret_cast(X.template Data()); + + const TensorShape& y_shape = dY.Shape(); + auto y_dims = y_shape.AsShapeVector(); + args.dy_data = reinterpret_cast(dY.template Data()); + + const TensorShape& w_shape = W.Shape(); + auto w_dims = w_shape.AsShapeVector(); + + args.y_data = nullptr; + args.dw_data = dW ? reinterpret_cast(dW->template MutableData()) : nullptr; + args.db_data = dB ? reinterpret_cast(dB->template MutableData()) : nullptr; + args.dx_data = nullptr; + args.w_data = nullptr; + + bool x_dims_changed = (args.last_x_dims != x_dims); + bool w_dims_changed = (args.last_w_dims != w_dims); + if (x_dims_changed || w_dims_changed) { + if (x_dims_changed) args.last_x_dims = x_dims; + if (w_dims_changed) args.last_w_dims = w_dims; + + ORT_RETURN_IF_ERROR(conv_attrs_.ValidateInputShape(&X, &W)); + + TensorShapeVector kernel_shape; + ORT_RETURN_IF_ERROR(conv_attrs_.ComputeKernelShape(w_shape, kernel_shape)); + auto rank = kernel_shape.size(); + + ConvPadVector pads(conv_attrs_.pads); + if (pads.empty()) { + pads.resize(rank * 2, 0); + } + + TensorShapeVector dilations(conv_attrs_.dilations); + if (dilations.empty()) { + dilations.resize(rank, 1); + } + + TensorShapeVector strides(conv_attrs_.strides); + if (strides.empty()) { + strides.resize(rank, 1); + } + + const CUDAExecutionProvider* cuda_ep = + static_cast(this->Info().GetExecutionProvider()); + + if (rank < 2) { + if (cuda_ep->GetCudnnConv1dPadToNc1d()) { + x_dims.insert(x_dims.begin() + 2, 1); + y_dims.insert(y_dims.begin() + 2, 1); + w_dims.insert(w_dims.begin() + 2, 1); + pads.insert(pads.begin() + rank, 0); + pads.insert(pads.begin(), 0); + kernel_shape.insert(kernel_shape.begin(), 1); + strides.insert(strides.begin(), 1); + dilations.insert(dilations.begin(), 1); + } else { + x_dims.push_back(1); + y_dims.push_back(1); + w_dims.push_back(1); + pads.insert(pads.begin() + rank, 0); + pads.insert(pads.end(), 0); + kernel_shape.push_back(1); + strides.push_back(1); + dilations.push_back(1); + } + } + + memset(&args.params, 0, sizeof(ConvParams)); + args.params.device_id = static_cast(cuda_ep->GetDeviceId()); + args.params.data_type = CudnnTensor::GetDataType(); + args.params.input_dim = static_cast(x_dims.size()); + for (size_t i = 0; i < x_dims.size(); i++) { + args.params.input_size[i] = static_cast(x_dims[i]); + args.params.weight_size[i] = static_cast(w_dims[i]); + } + for (size_t i = 0; i < rank; i++) { + args.params.padding[i] = static_cast(pads[i]); + args.params.padding[i + rank] = static_cast(pads[i + rank]); + args.params.stride[i] = static_cast(strides[i]); + args.params.dilation[i] = static_cast(dilations[i]); + } + args.params.groups = conv_attrs_.group; + int algo_mode = cuda_ep->GetCudnnConvAlgo(); + ORT_ENFORCE(algo_mode > -1 && algo_mode < 3, + "Algo mode should be EXHAUSTIVE (0), HEURISTIC (1) or DEFAULT (2), but got ", algo_mode); + args.params.algo_mode = algo_mode; + + args.handle = cudnn_handle; + ORT_RETURN_IF_ERROR(args.w_desc.Set(w_dims, args.params.data_type)); + ORT_RETURN_IF_ERROR(args.x_tensor.Set(x_dims, args.params.data_type)); + ORT_RETURN_IF_ERROR(args.y_tensor.Set(y_dims, args.params.data_type)); + ORT_RETURN_IF_ERROR(args.conv_desc.Set(kernel_shape.size(), pads, strides, dilations, + gsl::narrow_cast(conv_attrs_.group), CUDNN_CROSS_CORRELATION, + args.params.data_type)); + + if (dB) { + const auto& b_shape = dB->Shape(); + ORT_RETURN_IF_NOT(b_shape.NumDimensions() == 1, "bias should be 1D"); + TensorShapeVector b_dims(2 + kernel_shape.size()); + b_dims[0] = 1; // N + b_dims[1] = b_shape[0]; // C + for (size_t i = 0; i < kernel_shape.size(); i++) + b_dims[2 + i] = 1; + + ORT_RETURN_IF_ERROR(args.b_tensor.Set(b_dims, CudnnTensor::GetDataType())); + } + } + + return Status::OK(); +} + +} // namespace onnxruntime::cuda diff --git a/orttraining/orttraining/training_ops/cuda/nn/conv_transpose_grad.h b/orttraining/orttraining/training_ops/cuda/nn/conv_transpose_grad.h new file mode 100644 index 0000000000000..72426323fefab --- /dev/null +++ b/orttraining/orttraining/training_ops/cuda/nn/conv_transpose_grad.h @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/providers/cuda/cuda_kernel.h" + +#include "core/providers/cpu/nn/conv_attributes.h" +#include "orttraining/training_ops/cuda/nn/conv_shared.h" + +namespace onnxruntime::cuda { + +template +class ConvTransposeGrad final : public CudaKernel { + public: + using CudaT = typename ToCudaType::MappedType; + + ConvTransposeGrad(const OpKernelInfo& info) : CudaKernel(info), conv_attrs_(info) { + } + + Status ComputeInternal(OpKernelContext* context) const override; + + private: + Status ComputeWeightGradient(onnxruntime::Stream* stream, const ConvArgs& args) const; + Status ComputeInputGradient(onnxruntime::Stream* stream, const ConvArgs& args) const; + Status ComputeBiasGradient(const ConvArgs& args) const; + + Status PrepareConvForwardArgs(const Tensor& X, const Tensor& W, + Tensor& Y, cudnnHandle_t cudnn_handle, + ConvArgs& args) const; + + Status PrepareConvBackwardFilterArgs(const Tensor& X, const Tensor& W, const Tensor& dY, + Tensor* dW, Tensor* dB, cudnnHandle_t cudnn_handle, + ConvArgs& args) const; + + ConvAttributes conv_attrs_; + mutable ConvArgs args_dx_; + mutable ConvArgs args_dw_; +}; + +} // namespace onnxruntime::cuda diff --git a/orttraining/orttraining/training_ops/cuda/optimizer/adamw/adamw.cc b/orttraining/orttraining/training_ops/cuda/optimizer/adamw/adamw.cc index 855754f96113e..9ff54bfe7e9d6 100644 --- a/orttraining/orttraining/training_ops/cuda/optimizer/adamw/adamw.cc +++ b/orttraining/orttraining/training_ops/cuda/optimizer/adamw/adamw.cc @@ -35,7 +35,7 @@ Status AdamWOptimizer::ComputeInternal(OpKernelContext* ctx) const { AdamWOptimizerBase::Prepare p; ORT_RETURN_IF_ERROR(PrepareForCompute(ctx, p)); - int64_t* updated_flag_ptr = p.updated_flag->template MutableData(); + bool* updated_flag_ptr = p.updated_flag->template MutableData(); // Currently placed on CPU, need revisit when we had mixed precision training requirement. const Tensor* update_signal = ctx->Input(6); @@ -51,9 +51,9 @@ Status AdamWOptimizer::ComputeInternal(OpKernelContext* ctx) const { launch_multi_tensor_functor( Stream(ctx), MTA_ADAMW_CHUNK_SIZE, p.grouped_tensor_sizes, p.grouped_tensor_pointers, functor, alpha_, beta_, epsilon_, *lr_ptr, weight_decay_, adam_mode_, correct_bias_, *step_ptr); - *updated_flag_ptr = 1; + *updated_flag_ptr = true; } else { - *updated_flag_ptr = 0; + *updated_flag_ptr = false; } if (p.updated_weights != nullptr) { diff --git a/orttraining/orttraining/training_ops/cuda/optimizer/lamb.cc b/orttraining/orttraining/training_ops/cuda/optimizer/lamb.cc index a4f107ff0c6fb..501c48e687e98 100644 --- a/orttraining/orttraining/training_ops/cuda/optimizer/lamb.cc +++ b/orttraining/orttraining/training_ops/cuda/optimizer/lamb.cc @@ -348,6 +348,13 @@ Status launch_lamb_reduction( // Only launch multi-tensor function if we have at least one tensor in the buckets. if (tensor_sizes_in_buckets.size() > 0 && buckets.size() > 0) { + if (ctx->GetUseDeterministicCompute()) { + static std::once_flag log_warning; + std::call_once(log_warning, []() { + LOGS_DEFAULT(WARNING) << "Non-deterministic Lamb GPU kernel is called, its outputs may still be nondeterministic."; + }); + } + typedef LambMultiTensorReductionFunctor TReducer; TReducer reducer; launch_multi_tensor_functor( diff --git a/orttraining/orttraining/training_ops/cuda/quantization/fake_quant_impl.cu b/orttraining/orttraining/training_ops/cuda/quantization/fake_quant_impl.cu index d3d479664b5eb..46178dca69568 100644 --- a/orttraining/orttraining/training_ops/cuda/quantization/fake_quant_impl.cu +++ b/orttraining/orttraining/training_ops/cuda/quantization/fake_quant_impl.cu @@ -98,8 +98,8 @@ template void FakeQuantGradImpl(cudaStream_t stream, const int64_t num_elements, const T* dY_data, const bool* gradient_mask_data, T* dX_data) { FakeQuantGradFunctor fake_quant_grad_functor(dY_data, gradient_mask_data); - LaunchElementwiseKernel( - stream, dX_data, fake_quant_grad_functor, num_elements); + LaunchElementwiseKernel( + stream, dX_data, fake_quant_grad_functor, static_cast(num_elements)); } #define SPECIALIZED_FAKEQUANTGRAD_IMPL(T) \ diff --git a/orttraining/orttraining/training_ops/cuda/reduction/reduction_ops.cc b/orttraining/orttraining/training_ops/cuda/reduction/reduction_ops.cc index 86f5b11ba9a07..ff8f5f81e4e37 100644 --- a/orttraining/orttraining/training_ops/cuda/reduction/reduction_ops.cc +++ b/orttraining/orttraining/training_ops/cuda/reduction/reduction_ops.cc @@ -58,7 +58,7 @@ Status ReduceKernel::ComputeImplEx(OpKernelContext* ctx, cudnn Tensor* Y = ctx->Output(0, prepare_reduce_metadata.squeezed_output_dims); const bool fast_reduction = fast_reduction_ && !ctx->GetUseDeterministicCompute(); - return ReduceComputeCore(*cuda_ep_, *X, prepare_reduce_metadata, *Y, cudnn_reduce_op, axes, + return ReduceComputeCore(Info().GetAllocator(OrtMemType::OrtMemTypeDefault), *X, prepare_reduce_metadata, *Y, cudnn_reduce_op, axes, calculate_log_, calculate_sqt_, log_sum_exp_, fast_reduction, ctx->GetComputeStream()); } diff --git a/orttraining/orttraining/training_ops/cuda/tensor/gather_elements_grad.cc b/orttraining/orttraining/training_ops/cuda/tensor/gather_elements_grad.cc index f8a80ddd40fb5..20dcfc4fbdfcb 100644 --- a/orttraining/orttraining/training_ops/cuda/tensor/gather_elements_grad.cc +++ b/orttraining/orttraining/training_ops/cuda/tensor/gather_elements_grad.cc @@ -29,10 +29,11 @@ ONNX_OPERATOR_KERNEL_EX(GatherElementsGrad, kMSDomain, 1, kCudaExecutionProvider #undef CREATE_GATHER_ELEMENTS_GRAD_KERNEL_DEF -#define CASE_GATHER_ELEMENTS_GRAD_IMPL(type) \ - case sizeof(type): { \ - const type* indices_data = reinterpret_cast(indices_data_raw); \ - ORT_RETURN_IF_ERROR(GatherElementsGradImpl(stream, indices_data, updates_data, output_data, args)); \ +#define CASE_GATHER_ELEMENTS_GRAD_IMPL(type) \ + case sizeof(type): { \ + const type* indices_data = reinterpret_cast(indices_data_raw); \ + ORT_RETURN_IF_ERROR(GatherElementsGradNonDeterministicImpl(stream, indices_data, updates_data, \ + output_data, args)); \ } break template @@ -100,8 +101,16 @@ Status GatherElementsGrad::ComputeInternal(OpKernelContext* context) const { ORT_THROW("Unsupported element size by the GatherElementsGrad CUDA kernel"); } + if (context->GetUseDeterministicCompute()) { + static std::once_flag log_warning; + std::call_once(log_warning, []() { + LOGS_DEFAULT(WARNING) << "GatherElementsGrad has no deterministic GPU kernel, its outputs may still be nondeterministic."; + }); + } + utils::MLTypeCallDispatcher t_disp(dtype); - return t_disp.InvokeRet(Stream(context), dY->DataRaw(), indices_tensor->DataRaw(), dX->MutableDataRaw(), + return t_disp.InvokeRet(Stream(context), dY->DataRaw(), indices_tensor->DataRaw(), + dX->MutableDataRaw(), indices_tensor->DataType()->Size(), args); } diff --git a/orttraining/orttraining/training_ops/cuda/tensor/gather_elements_grad_impl.h b/orttraining/orttraining/training_ops/cuda/tensor/gather_elements_grad_impl.h index ec1625d58bcd9..909cc7de22fe1 100755 --- a/orttraining/orttraining/training_ops/cuda/tensor/gather_elements_grad_impl.h +++ b/orttraining/orttraining/training_ops/cuda/tensor/gather_elements_grad_impl.h @@ -12,8 +12,9 @@ namespace cuda { struct GatherScatterElementsArgs; template -Status GatherElementsGradImpl(cudaStream_t stream, const TIndex* indices_data, const T* updates_data, T* output_data, - const GatherScatterElementsArgs& args); +Status GatherElementsGradNonDeterministicImpl(cudaStream_t stream, const TIndex* indices_data, + const T* updates_data, T* output_data, + const GatherScatterElementsArgs& args); } // namespace cuda } // namespace onnxruntime diff --git a/orttraining/orttraining/training_ops/cuda/tensor/gather_nd_grad.cc b/orttraining/orttraining/training_ops/cuda/tensor/gather_nd_grad.cc index 50cdbca80b18f..a64abd2a8661c 100644 --- a/orttraining/orttraining/training_ops/cuda/tensor/gather_nd_grad.cc +++ b/orttraining/orttraining/training_ops/cuda/tensor/gather_nd_grad.cc @@ -80,6 +80,13 @@ Status GatherNDGrad::ComputeInternal(OpKernelContext* context) const { batch_dims_, input_shape, indices_shape, indices_tensor, num_slices, slice_size, input_slice_offsets_buffer)); + if (context->GetUseDeterministicCompute()) { + static std::once_flag log_warning; + std::call_once(log_warning, []() { + LOGS_DEFAULT(WARNING) << "GatherNDGrad has no deterministic GPU kernel, its outputs may still be nondeterministic."; + }); + } + const void* const kernel_input_data = update_tensor->DataRaw(); void* const kernel_output_data = output_tensor->MutableDataRaw(); utils::MLTypeCallDispatcher t_disp(update_tensor->GetElementType()); diff --git a/orttraining/orttraining/training_ops/cuda/tensor/pad_and_unflatten.cc b/orttraining/orttraining/training_ops/cuda/tensor/pad_and_unflatten.cc new file mode 100644 index 0000000000000..caf89ef840e0c --- /dev/null +++ b/orttraining/orttraining/training_ops/cuda/tensor/pad_and_unflatten.cc @@ -0,0 +1,99 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "orttraining/training_ops/cuda/tensor/pad_and_unflatten.h" +#include "orttraining/training_ops/cuda/tensor/pad_and_unflatten_impl.h" +#include "core/providers/cuda/shared_inc/cuda_utils.h" + +namespace onnxruntime { +namespace cuda { + +ONNX_OPERATOR_KERNEL_EX( + PadAndUnflatten, + kMSDomain, + 1, + kCudaExecutionProvider, + (*KernelDefBuilder::Create()) + .TypeConstraint("T", BuildKernelDefConstraints()) + .TypeConstraint("T_INT", DataTypeImpl::GetTensorType()) + .TypeConstraint("T_INDEX", DataTypeImpl::GetTensorType()) + .InputMemoryType(OrtMemTypeCPUInput, 2) + .OutputMemoryType(OrtMemTypeCPUOutput, 1), + PadAndUnflatten); + +// Put implementation in the anonymous namespace to avoid name collision in the global namespace. +namespace { + +template +struct PadAndUnflattenFunctor { + void operator()(cudaStream_t stream, + const int64_t input_element_count, + const fast_divmod output_element_stride_fdm, + const int64_t index_value_upper_bound, + const Tensor& input_tensor, + const Tensor& indices_tensor, + Tensor& output_tensor) const { + typedef typename ToCudaType::MappedType CudaT; + const CudaT* input_data = reinterpret_cast(input_tensor.Data()); + + CUDA_CALL_THROW(cudaMemset(output_tensor.MutableDataRaw(), 0, output_tensor.Shape().Size() * sizeof(CudaT))); + PadAndUnflattenImpl(stream, input_element_count, output_element_stride_fdm, index_value_upper_bound, + input_data, indices_tensor.Data(), + reinterpret_cast(output_tensor.MutableData())); + } +}; + +} // namespace + +Status PadAndUnflatten::ComputeInternal(OpKernelContext* context) const { + const Tensor* input_tensor = context->Input(0); + const Tensor* indices_tensor = context->Input(1); + const Tensor* unflatten_dims_tensor = context->Input(2); // Parse the 1-D shape tensor. + ORT_ENFORCE(unflatten_dims_tensor->Shape().NumDimensions() == 1, + "unflatten_dims_tensor tensor must be 1-D.", unflatten_dims_tensor->Shape().NumDimensions()); + ORT_ENFORCE(unflatten_dims_tensor->Shape().Size() == 2, + "unflatten_dims_tensor tensor must contain 2 values.", unflatten_dims_tensor->Shape().Size()); + + const int64_t* dims_ptr = unflatten_dims_tensor->Data(); + const auto& input_shape = input_tensor->Shape(); + ORT_ENFORCE(input_shape[0] == indices_tensor->Shape()[0], + "The first dimension of input and indices must be the same."); + + std::vector output_shape_vec; + output_shape_vec.push_back(dims_ptr[0]); + output_shape_vec.push_back(dims_ptr[1]); + + std::vector full_size_flatten_shape_vec; + const int64_t flatten_dim_factor = dims_ptr[0] * dims_ptr[1]; + full_size_flatten_shape_vec.push_back(flatten_dim_factor); + + int64_t element_stride = 1; + for (size_t i = 1; i < input_shape.NumDimensions(); ++i) { + output_shape_vec.push_back(input_shape[i]); + full_size_flatten_shape_vec.push_back(input_shape[i]); + element_stride *= input_shape[i]; + } + + fast_divmod output_element_stride_fdm(static_cast(element_stride)); + auto output_shape = TensorShape(output_shape_vec); + Tensor* output_tensor = context->Output(0, output_shape); + + utils::MLTypeCallDispatcher t_disp(input_tensor->GetElementType()); + t_disp.Invoke(Stream(context), + input_shape.Size(), + output_element_stride_fdm, + flatten_dim_factor, + *input_tensor, + *indices_tensor, + *output_tensor); + + // Set input shape output tensor. + size_t rank = full_size_flatten_shape_vec.size(); + Tensor* input_shape_tensor = context->Output(1, {static_cast(rank)}); + TensorShape(full_size_flatten_shape_vec).CopyDims(input_shape_tensor->MutableData(), rank); + + return Status::OK(); +} + +} // namespace cuda +} // namespace onnxruntime diff --git a/orttraining/orttraining/training_ops/cuda/tensor/pad_and_unflatten.h b/orttraining/orttraining/training_ops/cuda/tensor/pad_and_unflatten.h new file mode 100644 index 0000000000000..e86bf5e57490d --- /dev/null +++ b/orttraining/orttraining/training_ops/cuda/tensor/pad_and_unflatten.h @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "core/providers/cuda/cuda_kernel.h" +#include "core/providers/common.h" + +namespace onnxruntime { +namespace cuda { + +class PadAndUnflatten final : public CudaKernel { + public: + PadAndUnflatten(const OpKernelInfo& info) : CudaKernel(info) { + } + + Status ComputeInternal(OpKernelContext* context) const override; +}; + +} // namespace cuda +} // namespace onnxruntime diff --git a/orttraining/orttraining/training_ops/cuda/tensor/pad_and_unflatten_impl.cu b/orttraining/orttraining/training_ops/cuda/tensor/pad_and_unflatten_impl.cu new file mode 100644 index 0000000000000..22a4f518dfa47 --- /dev/null +++ b/orttraining/orttraining/training_ops/cuda/tensor/pad_and_unflatten_impl.cu @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "orttraining/training_ops/cuda/tensor/pad_and_unflatten_impl.h" +#include "core/providers/cuda/cu_inc/common.cuh" + +namespace onnxruntime { +namespace cuda { + +constexpr int kBlockSize = 256; +constexpr int kNumUnroll = 4; + +template +__global__ void FillOutputWithIndexKernel(const CUDA_LONG N, + const fast_divmod output_element_stride_fdm, + const int64_t index_value_upper_bound, + const T* input_data, + const int64_t* indices_data, + T* output_data) { + CUDA_LONG idx = blockDim.x * blockIdx.x + threadIdx.x; + CUDA_LONG id = idx * kNumUnroll; + + T input[kNumUnroll]; + if (id < N) { +#pragma unroll + for (int i = 0; i < kNumUnroll; ++i) { + CUDA_LONG li = id + i; + if (li < N) { + input[i] = input_data[li]; + } + } + } + +#pragma unroll + for (int i = 0; i < kNumUnroll; ++i) { + CUDA_LONG li = id + i; + if (li < N) { + int row_index, col_index; + output_element_stride_fdm.divmod(li, row_index, col_index); + assert(indices_data[row_index] < index_value_upper_bound); + output_data[indices_data[row_index] * output_element_stride_fdm.d_ + col_index] = input[i]; + } + } +} + +template +void PadAndUnflattenImpl(cudaStream_t stream, + const int64_t total_element_count, + const fast_divmod output_element_stride_fdm, + const int64_t index_value_upper_bound, + const T* input_data, + const int64_t* indices_data, + T* output_data) { + const int blocksPerGrid = static_cast(CeilDiv(total_element_count, kBlockSize * kNumUnroll)); + FillOutputWithIndexKernel<<>>( + static_cast(total_element_count), + output_element_stride_fdm, + index_value_upper_bound, + input_data, + indices_data, + output_data); +} + +#define SPECIALIZED_RESTORE_FROM_MASK_IMPL(T) \ + template void PadAndUnflattenImpl(cudaStream_t stream, \ + const int64_t total_element_count, \ + const fast_divmod output_element_stride_fdm, \ + const int64_t index_value_upper_bound, \ + const T* input_data, \ + const int64_t* indices_data, \ + T* output_data); + +SPECIALIZED_RESTORE_FROM_MASK_IMPL(float) +SPECIALIZED_RESTORE_FROM_MASK_IMPL(double) +SPECIALIZED_RESTORE_FROM_MASK_IMPL(half) +SPECIALIZED_RESTORE_FROM_MASK_IMPL(BFloat16) + +#undef SPECIALIZED_RESTORE_FROM_MASK_IMPL + +} // namespace cuda +} // namespace onnxruntime diff --git a/orttraining/orttraining/training_ops/cuda/tensor/pad_and_unflatten_impl.h b/orttraining/orttraining/training_ops/cuda/tensor/pad_and_unflatten_impl.h new file mode 100644 index 0000000000000..8b015179cebd0 --- /dev/null +++ b/orttraining/orttraining/training_ops/cuda/tensor/pad_and_unflatten_impl.h @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#ifdef USE_ROCM +#include "core/providers/rocm/shared_inc/rocm_utils.h" +#else +#include "core/providers/cuda/shared_inc/cuda_utils.h" +#endif + +namespace onnxruntime { +namespace cuda { + +template +void PadAndUnflattenImpl(cudaStream_t stream, + const int64_t total_element_count, + const fast_divmod output_element_stride_fdm, + const int64_t index_value_upper_bound, + const T* input_data, + const int64_t* indices_data, + T* output_data); + +} // namespace cuda +} // namespace onnxruntime diff --git a/orttraining/orttraining/training_ops/cuda/triton/triton_op.cc b/orttraining/orttraining/training_ops/cuda/triton/triton_op.cc new file mode 100644 index 0000000000000..9a4df64a935f6 --- /dev/null +++ b/orttraining/orttraining/training_ops/cuda/triton/triton_op.cc @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifdef ENABLE_TRITON + +#include "core/providers/shared_library/provider_api.h" +#include "orttraining/training_ops/cpu/triton/triton_op.h" +#include "core/providers/cuda/cuda_fwd.h" + +namespace onnxruntime { +namespace cuda { + +ONNX_OPERATOR_KERNEL_EX(TritonOp, kMSDomain, 1, kCudaExecutionProvider, + (*KernelDefBuilder::Create()).TypeConstraint("T", DataTypeImpl::AllFixedSizeTensorTypes()), + onnxruntime::contrib::TritonOp); + +} // namespace cuda +} // namespace onnxruntime + +#endif diff --git a/orttraining/orttraining/training_ops/rocm/nn/conv_grad.cc b/orttraining/orttraining/training_ops/rocm/nn/conv_grad.cc index 0f902a00568ee..9da0725274641 100644 --- a/orttraining/orttraining/training_ops/rocm/nn/conv_grad.cc +++ b/orttraining/orttraining/training_ops/rocm/nn/conv_grad.cc @@ -127,7 +127,7 @@ template <> struct AlgoSearch { static constexpr auto DEFAULT_ALGO = miopenConvolutionBwdDataAlgoGEMM; static AlgoPerfCache& Cache() { return bwd_data_algos; } - static Status FindAlgorithms(const ConvArgs& args, const ROCMExecutionProvider* provider, + static Status FindAlgorithms(const ConvArgs& args, const ROCMExecutionProvider* provider, const AllocatorPtr& allocator, std::vector& perf_results) { static const T_BwdDataAlgo algos[] = { miopenConvolutionBwdDataAlgoGEMM, @@ -144,7 +144,7 @@ struct AlgoSearch { : AlgoSearchWorkspaceSize; // Use GetTransientScratchBuffer() so the workspace can be freed instead of cached. // Because the benchmarking uses a huge amount of memory, e.g. a few GBs. - IAllocatorUniquePtr workspace = provider->GetTransientScratchBuffer(max_workspace_size); + IAllocatorUniquePtr workspace = max_workspace_size == 0 ? nullptr : IAllocator::MakeUniquePtr(allocator, max_workspace_size, true); MIOPEN_RETURN_IF_ERROR(miopenFindConvolutionBackwardDataAlgorithm( args.handle, args.y_tensor, args.dy_data, args.w_desc, args.w_data, args.conv_desc, args.x_tensor, args.dx_data, 1, &perf_count, candidates.get(), workspace.get(), max_workspace_size, false)); @@ -157,7 +157,7 @@ template <> struct AlgoSearch { static constexpr auto DEFAULT_ALGO = miopenConvolutionBwdWeightsAlgoGEMM; static AlgoPerfCache& Cache() { return bwd_filter_algos; } - static Status FindAlgorithms(const ConvArgs& args, const ROCMExecutionProvider* provider, + static Status FindAlgorithms(const ConvArgs& args, const ROCMExecutionProvider* provider, const AllocatorPtr& allocator, std::vector& perf_results) { static const T_BwdFilterAlgo algos[] = { miopenConvolutionBwdWeightsAlgoGEMM, @@ -173,7 +173,7 @@ struct AlgoSearch { : AlgoSearchWorkspaceSize; // Use GetTransientScratchBuffer() so the workspace can be freed instead of cached. // Because the benchmarking uses a huge amount of memory, e.g. a few GBs. - IAllocatorUniquePtr workspace = provider->GetTransientScratchBuffer(max_workspace_size); + IAllocatorUniquePtr workspace = max_workspace_size == 0 ? nullptr : IAllocator::MakeUniquePtr(allocator, max_workspace_size, true); MIOPEN_RETURN_IF_ERROR(miopenFindConvolutionBackwardWeightsAlgorithm( args.handle, args.y_tensor, args.dy_data, args.x_tensor, args.x_data, args.conv_desc, args.w_desc, args.dw_data, 1, &perf_count, candidates.get(), workspace.get(), max_workspace_size, false)); @@ -189,7 +189,7 @@ class AlgoIterator { Status OnlyDefaultAlgorithm(const ConvArgs& args, std::vector& perf_results); - Status TryAll(const ROCMExecutionProvider* provider, std::function f) { + Status TryAll(const ROCMExecutionProvider* provider, const AllocatorPtr& allocator, std::function f) { auto& cache = AlgoSearch::Cache(); miopenConvAlgoPerf_t algo_perf; if (cache.Find(args_.params, &algo_perf) && f(algo_perf) == Status::OK()) { @@ -197,7 +197,7 @@ class AlgoIterator { } std::vector perf_results; - ORT_RETURN_IF_ERROR(AlgoSearch::FindAlgorithms(args_, provider, perf_results)); + ORT_RETURN_IF_ERROR(AlgoSearch::FindAlgorithms(args_, provider, allocator, perf_results)); for (auto& algo_perf : perf_results) { if (f(algo_perf) == Status::OK()) { cache.Insert(args_.params, algo_perf); @@ -343,6 +343,7 @@ template Status ConvGrad::ComputeInputGradient(onnxruntime::Stream* stream) const { return AlgoIterator(args_).TryAll( static_cast(Info().GetExecutionProvider()), + Info().GetAllocator(OrtMemType::OrtMemTypeDefault), [&](const T_BwdDataPerf& algo_perf) -> Status { const auto one = Consts::One; const auto zero = Consts::Zero; @@ -358,6 +359,7 @@ template Status ConvGrad::ComputeWeightGradient(onnxruntime::Stream* stream) const { return AlgoIterator(args_).TryAll( static_cast(Info().GetExecutionProvider()), + Info().GetAllocator(OrtMemType::OrtMemTypeDefault), [&](const T_BwdFilterPerf& algo_perf) -> Status { const auto one = Consts::One; const auto zero = Consts::Zero; diff --git a/orttraining/orttraining/training_ops/rocm/reduction/reduction_ops.cc b/orttraining/orttraining/training_ops/rocm/reduction/reduction_ops.cc index 193f3ff7da370..23811744885e0 100644 --- a/orttraining/orttraining/training_ops/rocm/reduction/reduction_ops.cc +++ b/orttraining/orttraining/training_ops/rocm/reduction/reduction_ops.cc @@ -58,7 +58,7 @@ Status ReduceKernel::ComputeImplEx(OpKernelContext* ctx, miope Tensor* Y = ctx->Output(0, prepare_reduce_metadata.squeezed_output_dims); const bool fast_reduction = fast_reduction_ && !ctx->GetUseDeterministicCompute(); - return ReduceComputeCore(*rocm_ep_, *X, prepare_reduce_metadata, *Y, miopen_reduce_op, axes, + return ReduceComputeCore(Info().GetAllocator(OrtMemType::OrtMemTypeDefault), *X, prepare_reduce_metadata, *Y, miopen_reduce_op, axes, calculate_log_, calculate_sqt_, log_sum_exp_, fast_reduction, ctx->GetComputeStream()); } diff --git a/orttraining/orttraining/training_ops/rocm/rocm_training_kernels.cc b/orttraining/orttraining/training_ops/rocm/rocm_training_kernels.cc index daa43fdde99d7..2321aa23dd6eb 100644 --- a/orttraining/orttraining/training_ops/rocm/rocm_training_kernels.cc +++ b/orttraining/orttraining/training_ops/rocm/rocm_training_kernels.cc @@ -119,6 +119,10 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1 class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, double, TanhGrad); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, MLFloat16, TanhGrad); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, float, LeakyReluGrad); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, double, LeakyReluGrad); +class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, MLFloat16, LeakyReluGrad); + class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, MLFloat16, IsFinite); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, float, IsFinite); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, double, IsFinite); @@ -182,6 +186,7 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1 class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, BFloat16_float, ReduceAllL2); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, float_BFloat16, ReduceAllL2); class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, BFloat16_BFloat16, ReduceAllL2); +class ONNX_OPERATOR_KERNEL_CLASS_NAME(kRocmExecutionProvider, kMSDomain, 1, PadAndUnflatten); #if defined(ORT_USE_NCCL) || defined(USE_MPI) // P2P communication operators. @@ -315,6 +320,9 @@ Status RegisterRocmTrainingKernels(KernelRegistry& kernel_registry) { BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, + BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, @@ -378,6 +386,7 @@ Status RegisterRocmTrainingKernels(KernelRegistry& kernel_registry) { BuildKernelCreateInfo, BuildKernelCreateInfo, BuildKernelCreateInfo, + BuildKernelCreateInfo, // P2P communication operators. #if defined(ORT_USE_NCCL) || defined(USE_MPI) diff --git a/orttraining/pytorch_frontend_examples/mnist_training.py b/orttraining/pytorch_frontend_examples/mnist_training.py index 62de9c0f9c8c8..dc9b3f654400c 100644 --- a/orttraining/pytorch_frontend_examples/mnist_training.py +++ b/orttraining/pytorch_frontend_examples/mnist_training.py @@ -193,8 +193,6 @@ def main(): for epoch in range(1, args.epochs + 1): train_with_trainer(args, trainer, device, train_loader, epoch) - import pdb # noqa: F401 - test_with_trainer(args, trainer, device, test_loader) diff --git a/orttraining/tools/ci_test/compare_results.py b/orttraining/tools/ci_test/compare_results.py index 24854d6cf9c82..0ab0a1246a421 100644 --- a/orttraining/tools/ci_test/compare_results.py +++ b/orttraining/tools/ci_test/compare_results.py @@ -19,7 +19,7 @@ def eq(): def float_le(tolerance=None): actual_tolerance = 0.0 if tolerance is None else tolerance return Comparison( - name="less than or equal to" + (f" (tolerance: {str(actual_tolerance)})" if tolerance is not None else ""), + name="less than or equal to" + (f" (tolerance: {actual_tolerance!s})" if tolerance is not None else ""), fn=(lambda actual, expected: float(actual) <= float(expected) + actual_tolerance), ) diff --git a/orttraining/tools/ci_test/results/ci-mi100.huggingface.bert-large-rocm5.4.json b/orttraining/tools/ci_test/results/ci-mi100.huggingface.bert-large-rocm5.6.json similarity index 65% rename from orttraining/tools/ci_test/results/ci-mi100.huggingface.bert-large-rocm5.4.json rename to orttraining/tools/ci_test/results/ci-mi100.huggingface.bert-large-rocm5.6.json index ff5790f313e55..0aef350cf655e 100644 --- a/orttraining/tools/ci_test/results/ci-mi100.huggingface.bert-large-rocm5.4.json +++ b/orttraining/tools/ci_test/results/ci-mi100.huggingface.bert-large-rocm5.6.json @@ -2,55 +2,55 @@ "steps": [ { "step": 20, - "loss": 2.0638 + "loss": 2.0312 }, { "step": 40, - "loss": 1.8575 + "loss": 1.8506 }, { "step": 60, - "loss": 1.7383 + "loss": 1.7430 }, { "step": 80, - "loss": 1.6672 + "loss": 1.6562 }, { "step": 100, - "loss": 1.6656 + "loss": 1.6689 }, { "step": 120, - "loss": 1.6705 + "loss": 1.6786 }, { "step": 140, - "loss": 1.6273 + "loss": 1.6278 }, { "step": 160, - "loss": 1.6861 + "loss": 1.6780 }, { "step": 180, - "loss": 1.6111 + "loss": 1.6239 }, { "step": 200, - "loss": 1.625 + "loss": 1.6224 }, { "step": 220, - "loss": 1.6463 + "loss": 1.6468 }, { "step": 240, - "loss": 1.527 + "loss": 1.5370 }, { "step": 260, - "loss": 1.5424 + "loss": 1.5511 } ], "samples_per_second": 24.029 diff --git a/orttraining/tools/ci_test/results/ci-mi100.huggingface.distilbert-base-rocm5.4.json b/orttraining/tools/ci_test/results/ci-mi100.huggingface.distilbert-base-rocm5.5.json similarity index 67% rename from orttraining/tools/ci_test/results/ci-mi100.huggingface.distilbert-base-rocm5.4.json rename to orttraining/tools/ci_test/results/ci-mi100.huggingface.distilbert-base-rocm5.5.json index 276fd6f0446e2..c7f92542bb520 100644 --- a/orttraining/tools/ci_test/results/ci-mi100.huggingface.distilbert-base-rocm5.4.json +++ b/orttraining/tools/ci_test/results/ci-mi100.huggingface.distilbert-base-rocm5.5.json @@ -2,15 +2,15 @@ "steps": [ { "step": 20, - "loss": 2.4707 + "loss": 2.4705 }, { "step": 40, - "loss": 2.1768 + "loss": 2.1767 }, { "step": 60, - "loss": 2.0827 + "loss": 2.0828 }, { "step": 80, @@ -18,40 +18,40 @@ }, { "step": 100, - "loss": 2.0185 + "loss": 2.0184 }, { "step": 120, - "loss": 2.0503 + "loss": 2.0505 }, { "step": 140, - "loss": 2.0647 + "loss": 2.0649 }, { "step": 160, - "loss": 1.9912 + "loss": 1.9914 }, { "step": 180, - "loss": 1.998 + "loss": 1.9979 }, { "step": 200, - "loss": 1.9384 + "loss": 1.9386 }, { "step": 220, - "loss": 1.973 + "loss": 1.9731 }, { "step": 240, - "loss": 1.963 + "loss": 1.9630 }, { "step": 260, "loss": 1.9678 } ], - "samples_per_second": 154.103 + "samples_per_second": 157.404 } diff --git a/orttraining/tools/ci_test/results/ci-mi100.huggingface.gpt2-rocm5.5.json b/orttraining/tools/ci_test/results/ci-mi100.huggingface.gpt2-rocm5.5.json new file mode 100644 index 0000000000000..a76dbd05ba0b9 --- /dev/null +++ b/orttraining/tools/ci_test/results/ci-mi100.huggingface.gpt2-rocm5.5.json @@ -0,0 +1,57 @@ +{ + "steps": [ + { + "step": 20, + "loss": 4.5223 + }, + { + "step": 40, + "loss": 1.7494 + }, + { + "step": 60, + "loss": 1.6407 + }, + { + "step": 80, + "loss": 1.6060 + }, + { + "step": 100, + "loss": 1.5880 + }, + { + "step": 120, + "loss": 1.5776 + }, + { + "step": 140, + "loss": 1.5700 + }, + { + "step": 160, + "loss": 1.5634 + }, + { + "step": 180, + "loss": 1.5581 + }, + { + "step": 200, + "loss": 1.5555 + }, + { + "step": 220, + "loss": 1.5534 + }, + { + "step": 240, + "loss": 1.5523 + }, + { + "step": 260, + "loss": 1.5505 + } + ], + "samples_per_second": 27.793 +} diff --git a/orttraining/tools/ci_test/results/ci-mi100.huggingface.gpt2-rocm5.4.json b/orttraining/tools/ci_test/results/ci-mi200.huggingface.bert-large-rocm5.6.json similarity index 61% rename from orttraining/tools/ci_test/results/ci-mi100.huggingface.gpt2-rocm5.4.json rename to orttraining/tools/ci_test/results/ci-mi200.huggingface.bert-large-rocm5.6.json index 0e53e4a77dbd2..a4ac02b566848 100644 --- a/orttraining/tools/ci_test/results/ci-mi100.huggingface.gpt2-rocm5.4.json +++ b/orttraining/tools/ci_test/results/ci-mi200.huggingface.bert-large-rocm5.6.json @@ -2,56 +2,56 @@ "steps": [ { "step": 20, - "loss": 4.5144 + "loss": 2.0017 }, { "step": 40, - "loss": 1.7498 + "loss": 1.8337 }, { "step": 60, - "loss": 1.642 + "loss": 1.7538 }, { "step": 80, - "loss": 1.6069 + "loss": 1.6728 }, { "step": 100, - "loss": 1.5877 + "loss": 1.6656 }, { "step": 120, - "loss": 1.5781 + "loss": 1.6752 }, { "step": 140, - "loss": 1.5696 + "loss": 1.6335 }, { "step": 160, - "loss": 1.5635 + "loss": 1.6815 }, { "step": 180, - "loss": 1.5589 + "loss": 1.6155 }, { "step": 200, - "loss": 1.5554 + "loss": 1.6177 }, { "step": 220, - "loss": 1.5535 + "loss": 1.632 }, { "step": 240, - "loss": 1.5525 + "loss": 1.5161 }, { "step": 260, - "loss": 1.5512 + "loss": 1.5433 } ], - "samples_per_second": 27.246 + "samples_per_second": 32.335 } diff --git a/orttraining/tools/ci_test/run_batch_size_test.py b/orttraining/tools/ci_test/run_batch_size_test.py index cd93c44cf73b6..ba2be03618197 100755 --- a/orttraining/tools/ci_test/run_batch_size_test.py +++ b/orttraining/tools/ci_test/run_batch_size_test.py @@ -56,7 +56,7 @@ def main(): configs["MI100_32G"] = [ Config(True, 128, 192, 20, ""), Config(True, 512, 26, 80, ""), - Config(False, 128, 108, 20, ""), + Config(False, 128, 106, 20, ""), Config(False, 512, 16, 80, ""), ] diff --git a/orttraining/tools/scripts/layer_norm_transform.py b/orttraining/tools/scripts/layer_norm_transform.py index 2ccc947a58832..b397d1d26a456 100644 --- a/orttraining/tools/scripts/layer_norm_transform.py +++ b/orttraining/tools/scripts/layer_norm_transform.py @@ -144,7 +144,7 @@ def main(): all_nodes.append(node) for node in layer_norm_nodes: - all_nodes.append(node) + all_nodes.append(node) # noqa: PERF402 graph_proto.ClearField("node") graph_proto.node.extend(all_nodes) diff --git a/package/rpm/onnxruntime.spec b/package/rpm/onnxruntime.spec deleted file mode 100644 index d4efef8900432..0000000000000 --- a/package/rpm/onnxruntime.spec +++ /dev/null @@ -1,63 +0,0 @@ -Name: onnxruntime -Version: 1.15.0 -Release: 1%{?dist} -Summary: onnxruntime - -License: MIT -URL: https://onnx.ai -Source0: onnxruntime.tar - -BuildRequires: gcc -BuildRequires: gcc-c++ -BuildRequires: zlib-devel -BuildRequires: make -BuildRequires: git -BuildRequires: python3-devel -BuildRequires: python3-numpy -BuildRequires: python3-setuptools -BuildRequires: python3-wheel -BuildRequires: bzip2 -Requires: libstdc++ -Requires: glibc - -%description - - -%prep -%autosetup - - -%build -mkdir debug -cd debug -/opt/cmake/bin/cmake -Donnxruntime_DEV_MODE=OFF -DCMAKE_DEBUG_POSTFIX=_debug -DCMAKE_BUILD_TYPE=Debug -Deigen_SOURCE_PATH=/usr/include/eigen3 -Donnxruntime_USE_PREINSTALLED_EIGEN=ON -Donnxruntime_BUILD_SHARED_LIB=ON -DCMAKE_INSTALL_PREFIX=%{_prefix} ../cmake -%make_build -cd .. -mkdir release -cd release -/opt/cmake/bin/cmake -Donnxruntime_DEV_MODE=OFF -DCMAKE_BUILD_TYPE=RelWithDebInfo -Deigen_SOURCE_PATH=/usr/include/eigen3 -Donnxruntime_USE_PREINSTALLED_EIGEN=ON -Donnxruntime_BUILD_SHARED_LIB=ON -DCMAKE_INSTALL_PREFIX=%{_prefix} ../cmake -%make_build -cd .. - -%install -rm -rf $RPM_BUILD_ROOT -cd debug -%make_install -cd .. -cd release -%make_install -cd .. - -%files -%license LICENSE -%doc docs/* -%doc ThirdPartyNotices.txt -%{_bindir}/onnx_test_runner -%{_libdir}/libonnxruntime.so* -%{_libdir}/libonnxruntime_debug.so* -%{_includedir}/onnxruntime/* - - -%changelog -* Wed Oct 17 2018 ONNXRuntime Team -- Initial release diff --git a/packages.config b/packages.config index d679d2ceab970..da61a10adfa74 100644 --- a/packages.config +++ b/packages.config @@ -1,6 +1,6 @@  - + diff --git a/pyproject.toml b/pyproject.toml index 34dd42e5f09f5..89011a7944ab6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,20 +45,22 @@ reportMissingImports = false # NOTE: Do not create an exclude list. Edit .lintrunner.toml instead target-version = "py38" select = [ + "B", # flake8-bugbear "E", # pycodestyle "F", # Pyflakes - "W", # pycodestyle - "B", # flake8-bugbear - "N", # pep8-naming "ISC", # flake8-implicit-str-concat - "YTT", # flake8-2020 + "N", # pep8-naming + "NPY", # numpy + "PERF", # Perflint + "PLC", # pylint conventions + "PLE", # pylint errors + "PLW", # pylint warnings "RUF", # Ruff-specific rules "SIM", # flake8-simplify + "T10", # flake8-debugger "UP", # pyupgrade - "PLE", # pylint errors - "PLW", # pylint warnings - "PLC", # pylint conventions - "NPY", # numpy + "W", # pycodestyle + "YTT", # flake8-2020 ] # NOTE: Refrain from growing the ignore list unless for exceptional cases. # Always include a comment to explain why. @@ -69,6 +71,8 @@ ignore = [ "N812", # Allow import torch.nn.functional as F "N999", # Module names "NPY002", # np.random.Generator may not always fit our use cases + "PERF203", # "try-except-in-loop" only affects Python <3.11, and the improvement is minor; can have false positives + "PERF401", # List comprehensions are not always readable "SIM102", # We don't perfer always combining if branches "SIM108", # We don't encourage ternary operators "SIM114", # Don't combine if branches for debugability @@ -86,3 +90,5 @@ unfixable = [ # Eventually this list should become empty. "orttraining/orttraining/test/**" = ["N802"] # Function casing "tools/nuget/generate_nuspec_for_native_nuget.py" = ["ISC003"] # Too many errors to fix +"onnxruntime/test/python/quantization/test_op_gemm.py" = ["N806"] # use of A for a matrix +"onnxruntime/test/python/quantization/op_test_utils.py" = ["N806", "PERF203", "RUF012"] # use of A for a matrix diff --git a/requirements-lintrunner.txt b/requirements-lintrunner.txt index 0370e63a510aa..2068040443a20 100644 --- a/requirements-lintrunner.txt +++ b/requirements-lintrunner.txt @@ -1,11 +1,11 @@ # This file is auto updated by dependabot -lintrunner-adapters +lintrunner-adapters>=0.8.0 # RUFF, RUFF-FIX -ruff==0.0.261 +ruff==0.0.278 # BLACK-ISORT -black==23.3.0 +black==23.7.0 isort==5.12.0 # PYLINT pylint==2.17.2 # CLANGFORMAT -clang-format==16.0.1 +clang-format==16.0.6 diff --git a/rust/onnxruntime-sys/build.rs b/rust/onnxruntime-sys/build.rs index 82d1e4278015c..f59ee99fa29a7 100644 --- a/rust/onnxruntime-sys/build.rs +++ b/rust/onnxruntime-sys/build.rs @@ -105,7 +105,6 @@ fn generate_bindings(include_dir: &Path) { .expect("Unable to generate bindings"); let generated_file = PathBuf::from(env::var("OUT_DIR").unwrap()).join("bindings.rs"); - println!("cargo:rerun-if-changed={:?}", generated_file); bindings .write_to_file(&generated_file) .expect("Couldn't write bindings!"); diff --git a/setup.py b/setup.py index 9bbc759402669..7e6ab93194b0d 100644 --- a/setup.py +++ b/setup.py @@ -7,6 +7,7 @@ import datetime import logging import platform +import shlex import subprocess import sys from glob import glob, iglob @@ -81,7 +82,8 @@ def parse_arg_remove_string(argv, arg_name_equal): elif parse_arg_remove_boolean(sys.argv, "--use_cann"): package_name = "onnxruntime-cann" elif parse_arg_remove_boolean(sys.argv, "--use_azure"): - package_name = "onnxruntime-azure" + # keep the same name since AzureEP will release with CpuEP by default. + pass elif parse_arg_remove_boolean(sys.argv, "--use_qnn"): package_name = "onnxruntime-qnn" @@ -107,8 +109,8 @@ def parse_arg_remove_string(argv, arg_name_equal): "manylinux2014_ppc64", "manylinux2014_ppc64le", "manylinux2014_s390x", - "manylinux_2_27_x86_64", - "manylinux_2_27_aarch64", + "manylinux_2_28_x86_64", + "manylinux_2_28_aarch64", ] is_manylinux = environ.get("AUDITWHEEL_PLAT", None) in manylinux_tags @@ -176,129 +178,43 @@ def _rewrite_ld_preload_tensorrt(self, to_preload): f.write(" import os\n") f.write(' os.environ["ORT_TENSORRT_UNAVAILABLE"] = "1"\n') - def _rewrite_ld_preload_azure(self): - with open("onnxruntime/capi/_ld_preload.py", "a") as f: - f.write("import os\n") - f.write("from ctypes import CDLL, RTLD_GLOBAL, util\n") - f.write("def LoadLib(lib_name):\n") - f.write(" lib_path = util.find_library(lib_name)\n") - f.write(" if lib_path: _ = CDLL(lib_path, mode=RTLD_GLOBAL)\n") - f.write(" else: _ = CDLL(lib_name, mode=RTLD_GLOBAL)\n") - f.write('for lib_name in ["RE2", "ZLIB1"]:\n') - f.write(" try:\n") - f.write(" LoadLib(lib_name)\n") - f.write(" except OSError:\n") - f.write(' print("Could not load ort azure-ep dependency: " + lib_name)\n') - f.write(' os.environ["ORT_" + lib_name + "_UNAVAILABLE"] = "1"\n') - def run(self): if is_manylinux: source = "onnxruntime/capi/onnxruntime_pybind11_state.so" dest = "onnxruntime/capi/onnxruntime_pybind11_state_manylinux1.so" logger.info("copying %s -> %s", source, dest) copyfile(source, dest) - result = subprocess.run( - ["patchelf", "--print-needed", dest], check=True, stdout=subprocess.PIPE, text=True - ) - dependencies = [ - "librccl.so", - "libamdhip64.so", - "librocblas.so", - "libMIOpen.so", - "libhsa-runtime64.so", - "libhsakmt.so", - ] + to_preload = [] to_preload_cuda = [] to_preload_tensorrt = [] to_preload_cann = [] - cuda_dependencies = [] - args = ["patchelf", "--debug"] - for line in result.stdout.split("\n"): - for dependency in dependencies: - if dependency in line: - to_preload.append(line) - args.extend(["--remove-needed", line]) - args.append(dest) - if len(args) > 3: - subprocess.run(args, check=True, stdout=subprocess.PIPE) - - dest = "onnxruntime/capi/libonnxruntime_providers_" + ("rocm.so" if is_rocm else "cuda.so") - if path.isfile(dest): - result = subprocess.run( - ["patchelf", "--print-needed", dest], - check=True, - stdout=subprocess.PIPE, - text=True, - ) - cuda_dependencies = [ - "libcublas.so", - "libcublasLt.so", - "libcudnn.so", - "libcudart.so", - "libcurand.so", - "libcufft.so", - "libnvToolsExt.so", - "libcupti.so", - ] - rocm_dependencies = [ - "librccl.so", - "libamdhip64.so", - "librocblas.so", - "libMIOpen.so", - "libhsa-runtime64.so", - "libhsakmt.so", - ] - args = ["patchelf", "--debug"] - for line in result.stdout.split("\n"): - for dependency in cuda_dependencies + rocm_dependencies: - if dependency in line: - if dependency not in to_preload: - to_preload_cuda.append(line) - args.extend(["--remove-needed", line]) - args.append(dest) - if len(args) > 3: - subprocess.run(args, check=True, stdout=subprocess.PIPE) - - dest = "onnxruntime/capi/libonnxruntime_providers_" + ("migraphx.so" if is_rocm else "tensorrt.so") - if path.isfile(dest): - result = subprocess.run( - ["patchelf", "--print-needed", dest], - check=True, - stdout=subprocess.PIPE, - text=True, - ) - tensorrt_dependencies = ["libnvinfer.so", "libnvinfer_plugin.so", "libnvonnxparser.so"] - args = ["patchelf", "--debug"] - for line in result.stdout.split("\n"): - for dependency in cuda_dependencies + tensorrt_dependencies: - if dependency in line: - if dependency not in (to_preload + to_preload_cuda): - to_preload_tensorrt.append(line) - args.extend(["--remove-needed", line]) - args.append(dest) - if len(args) > 3: - subprocess.run(args, check=True, stdout=subprocess.PIPE) - - dest = "onnxruntime/capi/libonnxruntime_providers_cann.so" - if path.isfile(dest): - result = subprocess.run( - ["patchelf", "--print-needed", dest], - check=True, - stdout=subprocess.PIPE, - text=True, - ) - cann_dependencies = ["libascendcl.so", "libacl_op_compiler.so", "libfmk_onnx_parser.so"] - args = ["patchelf", "--debug"] - for line in result.stdout.split("\n"): - for dependency in cann_dependencies: - if dependency in line: - if dependency not in to_preload: - to_preload_cann.append(line) - args.extend(["--remove-needed", line]) - args.append(dest) - if len(args) > 3: - subprocess.run(args, check=True, stdout=subprocess.PIPE) + + cuda_dependencies = [ + "libcublas.so.11", + "libcublasLt.so.11", + "libcudnn.so.8", + "libcudart.so.11.0", + "libcurand.so.10", + "libcufft.so.10", + ] + rocm_dependencies = [ + "librccl.so.1", + "libnuma.so.1", + "libamd_comgr.so.2", + "libdrm.so.2", + "librocblas.so.0", + "libdrm_amdgpu.so.1", + "libamdhip64.so.5", + "libroctracer64.so.4", + "libMIOpen.so.1", + "libtinfo.so.6", + "libelf.so.1", + "librocm_smi64.so.5", + "libhsa-runtime64.so.1", + ] + + tensorrt_dependencies = ["libnvinfer.so.8", "libnvinfer_plugin.so.8", "libnvonnxparser.so.8"] dest = "onnxruntime/capi/libonnxruntime_providers_openvino.so" if path.isfile(dest): @@ -315,18 +231,19 @@ def run(self): self._rewrite_ld_preload(to_preload_cann) else: - if package_name == "onnxruntime-azure": - self._rewrite_ld_preload_azure() + pass _bdist_wheel.run(self) if is_manylinux and not disable_auditwheel_repair and not is_openvino: assert self.dist_dir is not None file = glob(path.join(self.dist_dir, "*linux*.whl"))[0] logger.info("repairing %s for manylinux1", file) + auditwheel_cmd = ["auditwheel", "-v", "repair", "-w", self.dist_dir, file] + for i in cuda_dependencies + rocm_dependencies + tensorrt_dependencies: + auditwheel_cmd += ["--exclude", i] + logger.info("Running {}".format(" ".join([shlex.quote(arg) for arg in auditwheel_cmd]))) try: - subprocess.run( - ["auditwheel", "repair", "-w", self.dist_dir, file], check=True, stdout=subprocess.PIPE - ) + subprocess.run(auditwheel_cmd, check=True, stdout=subprocess.PIPE) finally: logger.info("removing %s", file) remove(file) @@ -402,7 +319,6 @@ def finalize_options(self): ov_libs = [ "libopenvino_intel_cpu_plugin.so", "libopenvino_intel_gpu_plugin.so", - "libopenvino_intel_myriad_plugin.so", "libopenvino_auto_plugin.so", "libopenvino_hetero_plugin.so", "libtbb.so.2", @@ -486,9 +402,11 @@ def finalize_options(self): "onnxruntime.transformers.models.bart", "onnxruntime.transformers.models.bert", "onnxruntime.transformers.models.gpt2", + "onnxruntime.transformers.models.llama", "onnxruntime.transformers.models.longformer", "onnxruntime.transformers.models.t5", "onnxruntime.transformers.models.stable_diffusion", + "onnxruntime.transformers.models.whisper", ] package_data = {"onnxruntime.tools.mobile_helpers": ["*.md", "*.config"]} @@ -520,11 +438,11 @@ def finalize_options(self): "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Operating System :: Microsoft :: Windows", + "Operating System :: MacOS", ] -if not enable_training: - classifiers.extend(["Operating System :: Microsoft :: Windows", "Operating System :: MacOS"]) - if enable_training or enable_training_apis: packages.append("onnxruntime.training") if enable_training: @@ -544,8 +462,15 @@ def finalize_options(self): "onnxruntime.training.ortmodule.torch_cpp_extensions.cpu.torch_interop_utils", "onnxruntime.training.ortmodule.torch_cpp_extensions.cuda.torch_gpu_allocator", "onnxruntime.training.ortmodule.torch_cpp_extensions.cuda.fused_ops", + "onnxruntime.training.ort_triton", + "onnxruntime.training.ort_triton.kernel", + "onnxruntime.training.utils", "onnxruntime.training.utils.data", "onnxruntime.training.utils.hooks", + "onnxruntime.training.api", + "onnxruntime.training.onnxblock", + "onnxruntime.training.onnxblock.loss", + "onnxruntime.training.onnxblock.optim", ] ) @@ -559,15 +484,6 @@ def finalize_options(self): "*.h", ] - packages.extend( - [ - "onnxruntime.training.api", - "onnxruntime.training.onnxblock", - "onnxruntime.training.onnxblock.loss", - "onnxruntime.training.onnxblock.optim", - ] - ) - requirements_file = "requirements-training.txt" # with training, we want to follow this naming convention: # stable: @@ -599,6 +515,10 @@ def finalize_options(self): else: # cpu version for documentation local_version = "+cpu" + else: + if not (cuda_version or rocm_version): + # Training CPU package for ADO feeds is called onnxruntime-training-cpu + package_name = "onnxruntime-training-cpu" if package_name == "onnxruntime-tvm": packages += ["onnxruntime.providers.tvm"] diff --git a/tools/android_custom_build/Dockerfile b/tools/android_custom_build/Dockerfile index 1613e633511c4..bc50e4fb0a943 100644 --- a/tools/android_custom_build/Dockerfile +++ b/tools/android_custom_build/Dockerfile @@ -21,12 +21,12 @@ RUN apt-get update && apt-get install --yes --no-install-recommends \ python3-pip \ python3-setuptools \ python3-wheel \ - unzip + unzip lsb-release # cmake -RUN CMAKE_VERSION=3.25.2 && \ +RUN CMAKE_VERSION=3.27.3 && \ aria2c -q -d /tmp -o cmake-${CMAKE_VERSION}-linux-x86_64.tar.gz \ - --checksum=sha-256=783da74f132fd1fea91b8236d267efa4df5b91c5eec1dea0a87f0cf233748d99 \ + --checksum=sha-256=62e7819fe0867658b6ea765a711686d637dce76cdf6eb0a6b0f1b879e0344fa7 \ https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-linux-x86_64.tar.gz && \ tar -zxf /tmp/cmake-${CMAKE_VERSION}-linux-x86_64.tar.gz --strip=1 -C /usr diff --git a/tools/android_custom_build/build_custom_android_package.py b/tools/android_custom_build/build_custom_android_package.py index 2e1d092aa0d7f..aa57cf341942c 100755 --- a/tools/android_custom_build/build_custom_android_package.py +++ b/tools/android_custom_build/build_custom_android_package.py @@ -120,7 +120,8 @@ def main(): "--file", str(SCRIPT_DIR / "Dockerfile"), *docker_build_image_args, - ] + [str(SCRIPT_DIR)] + str(SCRIPT_DIR), + ] run(docker_build_image_cmd) @@ -154,7 +155,10 @@ def main(): # enable use of Ctrl-C to stop when running interactively docker_run_interactive_args = ["-it"] if sys.stdin.isatty() else [] - docker_container_build_cmd = [args.docker_path, "run", *docker_run_interactive_args] + [ + docker_container_build_cmd = [ + args.docker_path, + "run", + *docker_run_interactive_args, f"--name={args.docker_container_name}" if args.docker_container_name is not None else "--rm", f"--volume={working_dir}:/workspace/shared", args.docker_image_tag, diff --git a/tools/ci_build/build.py b/tools/ci_build/build.py index ea64485c55809..c4fb5499983cb 100644 --- a/tools/ci_build/build.py +++ b/tools/ci_build/build.py @@ -4,6 +4,7 @@ import argparse import contextlib +import json import os import platform import re @@ -13,13 +14,6 @@ import sys from pathlib import Path -try: - from packaging.version import Version as LooseVersion -except ImportError: - # This is deprecated and will be removed in Python 3.12. - # See https://docs.python.org/3/library/distutils.html. - from distutils.version import LooseVersion # pylint: disable=W4901 - SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__)) REPO_DIR = os.path.normpath(os.path.join(SCRIPT_DIR, "..", "..")) @@ -53,13 +47,12 @@ def __init__(self, message): def _check_python_version(): - # According to the BUILD.md, python 3.5+ is required: - # Python 2 is definitely not supported and it should be safer to consider - # it won't run with python 4: - if sys.version_info[0] != 3: # noqa: YTT201 - raise BuildError(f"Bad python major version: expecting python 3, found version '{sys.version}'") - if sys.version_info[1] < 6: # noqa: YTT203 - raise BuildError(f"Bad python minor version: expecting python 3.6+, found version '{sys.version}'") + required_minor_version = 7 + if (sys.version_info.major, sys.version_info.minor) < (3, required_minor_version): + raise UsageError( + f"Invalid Python version. At least Python 3.{required_minor_version} is required. " + f"Actual Python version: {sys.version}" + ) def _str_to_bool(s): @@ -73,16 +66,15 @@ def _str_to_bool(s): def _openvino_verify_device_type(device_read): - choices = ["CPU_FP32", "CPU_FP16", "GPU_FP32", "GPU_FP16", "VAD-M_FP16", "MYRIAD_FP16", "VAD-F_FP32"] + choices = ["CPU_FP32", "CPU_FP16", "GPU_FP32", "GPU_FP16", "VPUX_FP16", "VPUX_U8"] choices1 = [ "CPU_FP32_NO_PARTITION", "CPU_FP16_NO_PARTITION", "GPU_FP32_NO_PARTITION", "GPU_FP16_NO_PARTITION", - "VAD-M_FP16_NO_PARTITION", - "MYRIAD_FP16_NO_PARTITION", - "VAD-F_FP32_NO_PARTITION", + "VPUX_FP16_NO_PARTITION", + "VPUX_U8_NO_PARTITION", ] status_hetero = True res = False @@ -97,25 +89,25 @@ def _openvino_verify_device_type(device_read): if len(comma_separated_devices) < 2: print("At least two devices required in Hetero/Multi/Auto Mode") status_hetero = False - dev_options = ["CPU", "GPU", "MYRIAD", "FPGA", "HDDL"] + dev_options = ["CPU", "GPU", "VPUX"] for dev in comma_separated_devices: if dev not in dev_options: status_hetero = False break def invalid_hetero_build(): - print("\nIf trying to build Hetero/Multi/Auto, specifiy the supported devices along with it.\n") + print("\nIf trying to build Hetero/Multi/Auto, specify the supported devices along with it.\n") print("specify the keyword HETERO or MULTI or AUTO followed by the devices ") print("in the order of priority you want to build\n") print("The different hardware devices that can be added in HETERO or MULTI or AUTO") - print("are ['CPU','GPU','MYRIAD','FPGA','HDDL']\n") - print("An example of how to specify the hetero build type. Ex: HETERO:GPU,CPU\n") - print("An example of how to specify the MULTI build type. Ex: MULTI:MYRIAD,CPU\n") - print("An example of how to specify the AUTO build type. Ex: AUTO:GPU,CPU\n") + print("are ['CPU','GPU', 'VPUX'] \n") + print("An example of how to specify the hetero build type. Ex: HETERO:GPU,CPU \n") + print("An example of how to specify the MULTI build type. Ex: MULTI:GPU,CPU \n") + print("An example of how to specify the AUTO build type. Ex: AUTO:GPU,CPU \n") sys.exit("Wrong Build Type selected") if res is False: - print("\nYou have selcted wrong configuration for the build.") + print("\nYou have selected wrong configuration for the build.") print("pick the build type for specific Hardware Device from following options: ", choices) print("(or) from the following options with graph partitioning disabled: ", choices1) print("\n") @@ -174,6 +166,15 @@ def convert_arg_line_to_args(self, arg_line): help="Use parallel build. The optional value specifies the maximum number of parallel jobs. " "If the optional value is 0 or unspecified, it is interpreted as the number of CPUs.", ) + parser.add_argument( + "--nvcc_threads", + nargs="?", + default=-1, + type=int, + help="Maximum number of NVCC threads in each parallel job." + "If the value is unspecified, it will be computed based on available memory and number of parallel jobs.", + ) + parser.add_argument("--test", action="store_true", help="Run unit tests.") parser.add_argument("--skip_tests", action="store_true", help="Skip all tests.") parser.add_argument( @@ -274,6 +275,14 @@ def convert_arg_line_to_args(self, arg_line): "Currently only Windows and Linux platforms are supported.", ) + parser.add_argument( + "--msbuild_extra_options", + nargs="+", + action="append", + help="Extra properties to pass to msbuild during build. " + "These are just msbuild /p: options without the leading /p:.", + ) + # Java bindings parser.add_argument("--build_java", action="store_true", help="Build Java bindings.") @@ -330,6 +339,7 @@ def convert_arg_line_to_args(self, arg_line): "CMake setup. Delete CMakeCache.txt if needed", ) parser.add_argument("--msvc_toolset", help="MSVC toolset to use. e.g. 14.11") + parser.add_argument("--windows_sdk_version", help="Windows SDK version to use. e.g. 10.0.19041.0") parser.add_argument("--android", action="store_true", help="Build for Android") parser.add_argument( "--android_abi", @@ -375,7 +385,11 @@ def convert_arg_line_to_args(self, arg_line): "--xcode_code_signing_identity", default="", help="The development identity used for code signing in Xcode" ) parser.add_argument( - "--use_xcode", action="store_true", help="Use Xcode as cmake generator, this is only supported on MacOS." + "--use_xcode", + action="store_const", + const="Xcode", + dest="cmake_generator", + help="Use Xcode as cmake generator, this is only supported on MacOS. Equivalent to '--cmake_generator Xcode'.", ) parser.add_argument( "--osx_arch", @@ -397,7 +411,7 @@ 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="3.1.32", help="Specify version of emsdk") + parser.add_argument("--emsdk_version", default="3.1.44", help="Specify version of emsdk") parser.add_argument("--enable_wasm_simd", action="store_true", help="Enable WebAssembly SIMD") parser.add_argument("--enable_wasm_threads", action="store_true", help="Enable WebAssembly multi-threads support") @@ -417,7 +431,7 @@ def convert_arg_line_to_args(self, arg_line): parser.add_argument("--wasm_run_tests_in_browser", action="store_true", help="Run WebAssembly tests in browser") parser.add_argument( - "--enable_wasm_profiling", action="store_true", help="Enable WebAsselby profiling and preserve function names" + "--enable_wasm_profiling", action="store_true", help="Enable WebAssembly profiling and preserve function names" ) parser.add_argument( "--enable_wasm_debug_info", action="store_true", help="Build WebAssembly with DWARF format debug info" @@ -478,13 +492,14 @@ def convert_arg_line_to_args(self, arg_line): help="Build with OpenVINO for specific hardware.", ) parser.add_argument("--use_coreml", action="store_true", help="Build with CoreML support.") + parser.add_argument("--use_webnn", action="store_true", help="Build with WebNN support.") parser.add_argument("--use_snpe", action="store_true", help="Build with SNPE support.") parser.add_argument("--snpe_root", help="Path to SNPE SDK root.") parser.add_argument("--use_nnapi", action="store_true", help="Build with NNAPI support.") parser.add_argument( "--nnapi_min_api", type=int, help="Minimum Android API level to enable NNAPI, should be no less than 27" ) - parser.add_argument("--use_js", action="store_true", help="Build with JavaScript kernels.") + parser.add_argument("--use_jsep", action="store_true", help="Build with JavaScript kernels.") parser.add_argument("--use_qnn", action="store_true", help="Build with QNN support.") parser.add_argument("--qnn_home", help="Path to QNN SDK dir.") parser.add_argument("--use_rknpu", action="store_true", help="Build with RKNPU.") @@ -513,7 +528,7 @@ def convert_arg_line_to_args(self, arg_line): "--llvm_config", type=str, default="", - help="Path to llvm-config.exe for LLVM buit from sources. It is strongly needed for build on Windows", + help="Path to llvm-config.exe for LLVM built from sources. It is strongly needed for build on Windows", ) parser.add_argument( "--skip_onnx_tests", @@ -534,20 +549,15 @@ def convert_arg_line_to_args(self, arg_line): parser.add_argument( "--cmake_generator", choices=[ - "Visual Studio 16 2019", - "Visual Studio 17 2022", - "Ninja", "MinGW Makefiles", + "Ninja", "NMake Makefiles", + "Unix Makefiles", + "Visual Studio 17 2022", "Xcode", ], default=None, - help="Specify the generator that CMake invokes. ", - ) - parser.add_argument( - "--enable_multi_device_test", - action="store_true", - help="Test with multi-device. Mostly used for multi-device GPU", + help="Specify the generator that CMake invokes.", ) parser.add_argument("--use_dml", action="store_true", help="Build with DirectML.") parser.add_argument( @@ -625,6 +635,13 @@ def convert_arg_line_to_args(self, arg_line): ) # Please note in our CMakeLists.txt this is already default on. But in this file we reverse it to default OFF. parser.add_argument("--disable_rtti", action="store_true", help="Disable RTTI (reduces binary size)") + parser.add_argument( + "--disable_types", + nargs="+", + default=[], + choices=["float8", "optional", "sparsetensor"], + help="Disable selected data types (reduces binary size)", + ) parser.add_argument( "--disable_exceptions", action="store_true", @@ -678,6 +695,9 @@ def convert_arg_line_to_args(self, arg_line): parser.add_argument("--use_cache", action="store_true", help="Use compiler cache in CI") + parser.add_argument("--use_triton_kernel", action="store_true", help="Use triton compiled kernels") + parser.add_argument("--use_lock_free_queue", action="store_true", help="Use lock-free task queue for threadpool.") + if not is_windows(): parser.add_argument( "--allow_running_as_root", @@ -699,7 +719,7 @@ def convert_arg_line_to_args(self, arg_line): args.enable_wasm_exception_throwing_override = True if args.cmake_generator is None and is_windows(): - args.cmake_generator = "Ninja" if args.build_wasm else "Visual Studio 16 2019" + args.cmake_generator = "Ninja" if args.build_wasm else "Visual Studio 17 2022" return args @@ -855,6 +875,43 @@ def normalize_arg_list(nested_list): return [i for j in nested_list for i in j] if nested_list else [] +def number_of_parallel_jobs(args): + return os.cpu_count() if args.parallel == 0 else args.parallel + + +def number_of_nvcc_threads(args): + if args.nvcc_threads >= 0: + return args.nvcc_threads + + nvcc_threads = 1 + try: + import psutil + + available_memory = psutil.virtual_memory().available + if isinstance(available_memory, int) and available_memory > 0: + if available_memory > 60 * 1024 * 1024 * 1024: + # When available memory is large enough, chance of OOM is small. + nvcc_threads = 4 + else: + # NVCC need a lot of memory to compile 8 flash attention cu files in Linux or 4 cutlass fmha cu files in Windows. + # Here we select number of threads to ensure each thread has enough memory (>= 4 GB). For example, + # Standard_NC4as_T4_v3 has 4 CPUs and 28 GB memory. When parallel=4 and nvcc_threads=2, + # total nvcc threads is 4 * 2, which is barely able to build in 28 GB memory so we will use nvcc_threads=1. + memory_per_thread = 4 * 1024 * 1024 * 1024 + fmha_cu_files = 4 if is_windows() else 8 + fmha_parallel_jobs = min(fmha_cu_files, number_of_parallel_jobs(args)) + nvcc_threads = max(1, int(available_memory / (memory_per_thread * fmha_parallel_jobs))) + print( + f"nvcc_threads={nvcc_threads} to ensure memory per thread >= 4GB for available_memory={available_memory} and fmha_parallel_jobs={fmha_parallel_jobs}" + ) + except ImportError: + print( + "Failed to import psutil. Please `pip install psutil` for better estimation of nvcc threads. Use nvcc_threads=1" + ) + + return nvcc_threads + + def generate_build_tree( cmake_path, source_dir, @@ -885,6 +942,12 @@ def generate_build_tree( if not use_dev_mode(args): cmake_args += ["--compile-no-warning-as-error"] + types_to_disable = args.disable_types + # enable/disable float 8 types + disable_float8_types = args.use_rocm or args.android or ("float8" in types_to_disable) + disable_optional_type = "optional" in types_to_disable + disable_sparse_tensors = "sparsetensor" in types_to_disable + cmake_args += [ "-Donnxruntime_RUN_ONNX_TESTS=" + ("ON" if args.enable_onnx_tests else "OFF"), "-Donnxruntime_GENERATE_TEST_REPORTS=ON", @@ -947,7 +1010,7 @@ def generate_build_tree( "-Donnxruntime_USE_ARMNN=" + ("ON" if args.use_armnn else "OFF"), "-Donnxruntime_ARMNN_RELU_USE_CPU=" + ("OFF" if args.armnn_relu else "ON"), "-Donnxruntime_ARMNN_BN_USE_CPU=" + ("OFF" if args.armnn_bn else "ON"), - "-Donnxruntime_USE_JS=" + ("ON" if args.use_js else "OFF"), + "-Donnxruntime_USE_JSEP=" + ("ON" if args.use_jsep else "OFF"), # Training related flags "-Donnxruntime_ENABLE_NVTX_PROFILE=" + ("ON" if args.enable_nvtx_profile else "OFF"), "-Donnxruntime_ENABLE_TRAINING=" + ("ON" if args.enable_training else "OFF"), @@ -962,7 +1025,6 @@ def generate_build_tree( "-Donnxruntime_USE_MPI=" + ("ON" if args.use_mpi else "OFF"), "-Donnxruntime_ENABLE_MEMORY_PROFILE=" + ("ON" if args.enable_memory_profile else "OFF"), "-Donnxruntime_ENABLE_CUDA_LINE_NUMBER_INFO=" + ("ON" if args.enable_cuda_line_info else "OFF"), - "-Donnxruntime_BUILD_WEBASSEMBLY=" + ("ON" if args.build_wasm else "OFF"), "-Donnxruntime_BUILD_WEBASSEMBLY_STATIC_LIB=" + ("ON" if args.build_wasm_static_lib else "OFF"), "-Donnxruntime_ENABLE_WEBASSEMBLY_EXCEPTION_CATCHING=" + ("OFF" if args.disable_wasm_exception_catching else "ON"), @@ -980,7 +1042,12 @@ def generate_build_tree( "-Donnxruntime_ENABLE_CUDA_PROFILING=" + ("ON" if args.enable_cuda_profiling else "OFF"), "-Donnxruntime_ENABLE_ROCM_PROFILING=" + ("ON" if args.enable_rocm_profiling else "OFF"), "-Donnxruntime_USE_XNNPACK=" + ("ON" if args.use_xnnpack else "OFF"), + "-Donnxruntime_USE_WEBNN=" + ("ON" if args.use_webnn else "OFF"), "-Donnxruntime_USE_CANN=" + ("ON" if args.use_cann else "OFF"), + "-Donnxruntime_USE_TRITON_KERNEL=" + ("ON" if args.use_triton_kernel else "OFF"), + "-Donnxruntime_DISABLE_FLOAT8_TYPES=" + ("ON" if disable_float8_types else "OFF"), + "-Donnxruntime_DISABLE_SPARSE_TENSORS=" + ("ON" if disable_sparse_tensors else "OFF"), + "-Donnxruntime_DISABLE_OPTIONAL_TYPE=" + ("ON" if disable_optional_type else "OFF"), ] # By default on Windows we currently support only cross compiling for ARM/ARM64 @@ -1014,7 +1081,8 @@ def generate_build_tree( if args.use_migraphx: cmake_args.append("-Donnxruntime_MIGRAPHX_HOME=" + migraphx_home) if args.use_cuda: - cmake_args.append("-Donnxruntime_NVCC_THREADS=" + str(args.parallel)) + nvcc_threads = number_of_nvcc_threads(args) + cmake_args.append("-Donnxruntime_NVCC_THREADS=" + str(nvcc_threads)) if args.use_rocm: cmake_args.append("-Donnxruntime_ROCM_HOME=" + rocm_home) cmake_args.append("-Donnxruntime_ROCM_VERSION=" + args.rocm_version) @@ -1084,15 +1152,12 @@ def generate_build_tree( if args.use_openvino: cmake_args += [ "-Donnxruntime_USE_OPENVINO=ON", - "-Donnxruntime_USE_OPENVINO_MYRIAD=" + ("ON" if args.use_openvino == "MYRIAD_FP16" else "OFF"), "-Donnxruntime_USE_OPENVINO_GPU_FP32=" + ("ON" if args.use_openvino == "GPU_FP32" else "OFF"), "-Donnxruntime_USE_OPENVINO_GPU_FP16=" + ("ON" if args.use_openvino == "GPU_FP16" else "OFF"), "-Donnxruntime_USE_OPENVINO_CPU_FP32=" + ("ON" if args.use_openvino == "CPU_FP32" else "OFF"), "-Donnxruntime_USE_OPENVINO_CPU_FP16=" + ("ON" if args.use_openvino == "CPU_FP16" else "OFF"), - "-Donnxruntime_USE_OPENVINO_VAD_M=" + ("ON" if args.use_openvino == "VAD-M_FP16" else "OFF"), - "-Donnxruntime_USE_OPENVINO_VAD_F=" + ("ON" if args.use_openvino == "VAD-F_FP32" else "OFF"), - "-Donnxruntime_USE_OPENVINO_MYRIAD_NP=" - + ("ON" if args.use_openvino == "MYRIAD_FP16_NO_PARTITION" else "OFF"), + "-Donnxruntime_USE_OPENVINO_VPUX_FP16=" + ("ON" if args.use_openvino == "VPUX_FP16" else "OFF"), + "-Donnxruntime_USE_OPENVINO_VPUX_U8=" + ("ON" if args.use_openvino == "VPUX_U8" else "OFF"), "-Donnxruntime_USE_OPENVINO_GPU_FP32_NP=" + ("ON" if args.use_openvino == "GPU_FP32_NO_PARTITION" else "OFF"), "-Donnxruntime_USE_OPENVINO_GPU_FP16_NP=" @@ -1101,10 +1166,9 @@ def generate_build_tree( + ("ON" if args.use_openvino == "CPU_FP32_NO_PARTITION" else "OFF"), "-Donnxruntime_USE_OPENVINO_CPU_FP16_NP=" + ("ON" if args.use_openvino == "CPU_FP16_NO_PARTITION" else "OFF"), - "-Donnxruntime_USE_OPENVINO_VAD_M_NP=" - + ("ON" if args.use_openvino == "VAD-M_FP16_NO_PARTITION" else "OFF"), - "-Donnxruntime_USE_OPENVINO_VAD_F_NP=" - + ("ON" if args.use_openvino == "VAD-F_FP32_NO_PARTITION" else "OFF"), + "-Donnxruntime_USE_OPENVINO_VPUX_FP16_NP=" + + ("ON" if args.use_openvino == "VPUX_FP16_NP_PARTITION" else "OFF"), + "-Donnxruntime_USE_OPENVINO_VPUX_U8_NP=" + ("ON" if args.use_openvino == "VPUX_U8_NP_PARTITION" else "OFF"), "-Donnxruntime_USE_OPENVINO_HETERO=" + ("ON" if args.use_openvino.startswith("HETERO") else "OFF"), "-Donnxruntime_USE_OPENVINO_DEVICE=" + (args.use_openvino), "-Donnxruntime_USE_OPENVINO_MULTI=" + ("ON" if args.use_openvino.startswith("MULTI") else "OFF"), @@ -1170,19 +1234,6 @@ def generate_build_tree( if is_macOS() and not args.android: cmake_args += ["-DCMAKE_OSX_ARCHITECTURES=" + args.osx_arch] - if args.use_xcode: - cmake_ver = LooseVersion(subprocess.check_output(["cmake", "--version"]).decode("utf-8").split()[2]) - xcode_ver = LooseVersion( - subprocess.check_output(["xcrun", "xcodebuild", "-version"]).decode("utf-8").split()[1] - ) - # Requires Cmake 3.21.1+ for XCode 13+ - # The legacy build system is not longer supported on XCode 13+ - if xcode_ver >= LooseVersion("13") and cmake_ver < LooseVersion("3.21.1"): - raise BuildError("CMake 3.21.1+ required to use XCode 13+") - # Use legacy build system for old CMake [3.19, 3.21.1) which uses new build system by default - # CMake 3.18- use the legacy build system by default - if cmake_ver >= LooseVersion("3.19.0") and cmake_ver < LooseVersion("3.21.1"): - cmake_args += ["-T", "buildsystem=1"] if args.apple_deploy_target: cmake_args += ["-DCMAKE_OSX_DEPLOYMENT_TARGET=" + args.apple_deploy_target] # Code sign the binaries, if the code signing development identity and/or team id are provided @@ -1199,17 +1250,27 @@ def generate_build_tree( if args.use_coreml: cmake_args += ["-Donnxruntime_USE_COREML=ON"] + if args.use_webnn: + if not args.build_wasm: + raise BuildError("WebNN is only available for WebAssembly build.") + if args.disable_rtti: + # Avoid unboundTypeError for WebNN EP since unbound type names are illegal with RTTI disabled + # in Embind API, relevant issue: https://github.com/emscripten-core/emscripten/issues/16911 + raise BuildError("WebNN is not supported with RTTI disabled.") + cmake_args += ["-Donnxruntime_USE_WEBNN=ON"] + if args.use_snpe: cmake_args += ["-Donnxruntime_USE_SNPE=ON"] if args.ios: + if not args.cmake_generator == "Xcode": + raise BuildError("iOS build requires use of the Xcode CMake generator ('--cmake_generator Xcode').") + needed_args = [ - args.use_xcode, args.ios_sysroot, args.apple_deploy_target, ] arg_names = [ - "--use_xcode " + "", # noqa: ISC003 "--ios_sysroot " + "", # noqa: ISC003 "--apple_deploy_target " + "", # noqa: ISC003 ] @@ -1250,8 +1311,8 @@ def generate_build_tree( add_default_definition(emscripten_settings, "MALLOC", args.wasm_malloc) add_default_definition(emscripten_settings, "MALLOC", "dlmalloc") - # set -s STACK_SIZE=1048576 - add_default_definition(emscripten_settings, "STACK_SIZE", "1048576") + # set -s STACK_SIZE=5242880 + add_default_definition(emscripten_settings, "STACK_SIZE", "5242880") if emscripten_settings: cmake_args += [f"-Donnxruntime_EMSCRIPTEN_SETTINGS={';'.join(emscripten_settings)}"] @@ -1289,7 +1350,7 @@ def generate_build_tree( if not ( args.build_shared_lib and is_windows() - and args.cmake_generator == "Visual Studio 16 2019" + and args.cmake_generator == "Visual Studio 17 2022" and args.use_full_protobuf ): raise BuildError("Fuzz test has only be tested with build shared libs option using MSVC on windows") @@ -1299,13 +1360,6 @@ def generate_build_tree( "-Donnxruntime_USE_FULL_PROTOBUF=ON", ] - if args.gen_doc: - if args.enable_training: - raise BuildError("--gen_doc is not supported along with --enable_training") - add_default_definition(cmake_extra_defines, "onnxruntime_PYBIND_EXPORT_OPSCHEMA", "ON") - else: - add_default_definition(cmake_extra_defines, "onnxruntime_PYBIND_EXPORT_OPSCHEMA", "OFF") - if args.enable_lazy_tensor: import torch @@ -1315,6 +1369,9 @@ def generate_build_tree( if args.use_azure: add_default_definition(cmake_extra_defines, "onnxruntime_USE_AZURE", "ON") + if args.use_lock_free_queue: + add_default_definition(cmake_extra_defines, "onnxruntime_USE_LOCK_FREE_QUEUE", "ON") + cmake_args += [f"-D{define}" for define in cmake_extra_defines] cmake_args += cmake_extra_args @@ -1419,7 +1476,7 @@ def build_targets(args, cmake_path, build_dir, configs, num_parallel_jobs, targe "/nodeReuse:False", f"/p:CL_MPCount={num_parallel_jobs}", ] - elif is_macOS() and args.use_xcode: + elif args.cmake_generator == "Xcode": # CMake will generate correct build tool args for Xcode cmd_args += ["--parallel", str(num_parallel_jobs)] else: @@ -1616,6 +1673,10 @@ def run_adb_shell(cmd): adb_shell(f"chmod +x {device_dir}/onnx_test_runner") run_adb_shell(f"{device_dir}/onnxruntime_test_all") + # remove onnxruntime_test_all as it takes up a _lot_ of space and can cause insufficient storage errors + # when we try to copy the java app to the device. + adb_shell(f"rm {device_dir}/onnxruntime_test_all") + if args.build_java: # use the gradle wrapper under /java gradle_executable = os.path.join(source_dir, "java", "gradlew.bat" if is_windows() else "gradlew") @@ -1652,6 +1713,17 @@ def run_adb_shell(cmd): def run_ios_tests(args, source_dir, config, cwd): + simulator_device_info = subprocess.check_output( + [ + sys.executable, + os.path.join(source_dir, "tools", "ci_build", "github", "apple", "get_simulator_device_info.py"), + ], + text=True, + ).strip() + log.debug(f"Simulator device info:\n{simulator_device_info}") + + simulator_device_info = json.loads(simulator_device_info) + xc_test_schemes = [ "onnxruntime_test_all_xc", ] @@ -1674,7 +1746,7 @@ def run_ios_tests(args, source_dir, config, cwd): "-scheme", xc_test_scheme, "-destination", - "platform=iOS Simulator,OS=latest,name=iPhone SE (2nd generation)", + f"platform=iOS Simulator,id={simulator_device_info['device_udid']}", ], cwd=cwd, ) @@ -1735,11 +1807,10 @@ def run_onnxruntime_tests(args, source_dir, ctest_path, build_dir, configs): if args.build_shared_lib: executables.append("onnxruntime_shared_lib_test") executables.append("onnxruntime_global_thread_pools_test") - executables.append("onnxruntime_api_tests_without_env") executables.append("onnxruntime_customopregistration_test") for exe in executables: - run_subprocess([os.path.join(cwd, exe)], cwd=cwd, dll_path=dll_path) - + test_output = f"--gtest_output=xml:{cwd}/{exe}.{config}.results.xml" + run_subprocess([os.path.join(cwd, exe), test_output], cwd=cwd, dll_path=dll_path) else: ctest_cmd = [ctest_path, "--build-config", config, "--verbose", "--timeout", args.test_all_timeout] run_subprocess(ctest_cmd, cwd=cwd, dll_path=dll_path) @@ -1769,19 +1840,23 @@ def run_onnxruntime_tests(args, source_dir, ctest_path, build_dir, configs): [sys.executable, "onnxruntime_test_python_symbolic_shape_infer.py"], cwd=cwd, dll_path=dll_path ) - # For CUDA enabled builds test IOBinding feature - if args.use_cuda: - # We need to have Torch installed to test the IOBinding feature - # which currently uses Torch's allocator to allocate GPU memory for testing + # For CUDA or DML enabled builds test IOBinding feature + if args.use_cuda or args.use_dml: log.info("Testing IOBinding feature") run_subprocess([sys.executable, "onnxruntime_test_python_iobinding.py"], cwd=cwd, dll_path=dll_path) + 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) if not args.disable_ml_ops and not args.use_tensorrt: run_subprocess([sys.executable, "onnxruntime_test_python_mlops.py"], cwd=cwd, dll_path=dll_path) + if args.use_tensorrt: + run_subprocess( + [sys.executable, "onnxruntime_test_python_nested_control_flow_op.py"], cwd=cwd, dll_path=dll_path + ) + try: import onnx # noqa: F401 @@ -1962,17 +2037,21 @@ def derive_linux_build_property(): def build_nuget_package( + cmake_path, source_dir, build_dir, configs, use_cuda, + use_rocm, use_openvino, use_tensorrt, use_dnnl, use_tvm, use_winml, use_snpe, + use_qnn, enable_training_apis, + msbuild_extra_options, ): if not (is_windows() or is_linux()): raise BuildError( @@ -2012,12 +2091,19 @@ 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_rocm: + package_name = '/p:OrtPackageId="Microsoft.ML.OnnxRuntime.ROCm"' elif use_tvm: execution_provider = '/p:ExecutionProvider="tvm"' package_name = '/p:OrtPackageId="Microsoft.ML.OnnxRuntime.Tvm"' elif use_snpe: execution_provider = '/p:ExecutionProvider="snpe"' package_name = '/p:OrtPackageId="Microsoft.ML.OnnxRuntime.Snpe"' + elif use_qnn: + execution_provider = '/p:ExecutionProvider="qnn"' + package_name = '/p:OrtPackageId="Microsoft.ML.OnnxRuntime.QNN"' + elif any(map(lambda x: "OrtPackageId=" in x, msbuild_extra_options)): + pass else: # use the solution file that includes Xamarin mobile targets sln = "OnnxRuntime.CSharp.sln" @@ -2027,14 +2113,14 @@ def build_nuget_package( ort_build_dir = '/p:OnnxRuntimeBuildDirectory="' + native_dir + '"' # dotnet restore - cmd_args = ["dotnet", "restore", sln, "--configfile", "Nuget.CSharp.config"] + cmd_args = ["dotnet", "restore", sln, "--configfile", "NuGet.CSharp.config"] run_subprocess(cmd_args, cwd=csharp_build_dir) # build csharp bindings and create nuget package for each config for config in configs: if is_linux(): native_build_dir = os.path.join(native_dir, config) - cmd_args = ["make", "install", "DESTDIR=.//nuget-staging"] + cmd_args = [cmake_path, "-DCMAKE_INSTALL_PREFIX=./nuget-staging/usr/local", "-Pcmake_install.cmake"] run_subprocess(cmd_args, cwd=native_build_dir) configuration = '/p:Configuration="' + config + '"' @@ -2091,6 +2177,7 @@ def build_nuget_package( ort_build_dir, nuget_exe_arg, ] + cmd_args.extend(msbuild_extra_options) run_subprocess(cmd_args, cwd=csharp_build_dir) @@ -2145,69 +2232,6 @@ def is_cross_compiling_on_apple(args): return False -# RID is short for runtime identifier. If a nuget package has native binaries, -# the RID designates on which platforms the package can be restored. However, Google's -# protobuf package doesn't use standard RIDs from .NET RID catalog. This function is -# specific for "google.protobuf.tools" nuget package -# We do not care which CPU arch this ONNX Runtime build is targeting, we only care -# the "host" CPU type. -def get_protobuf_rid(): - cpu_arch = platform.architecture()[0] - if is_windows(): - if platform.machine() == "AMD64": - # Even if cpu_arch is "32bit", we still use a 64-bit protoc binary because the CPU can run it - return "windows_x64" - # No ARM32/ARM64 support yet - # If you ran a x64 python exe on a Windows ARM64 machine, it will fall into the "windows_x64" branch above. - # If you ran native ARM64 python exe, we use "windows_x64" protoc.exe instead. - if platform.machine() == "ARM64": - return "windows_x64" - return None - if is_linux(): - # TODO: exclude ARM - if cpu_arch == "64bit": - return "linux_x64" - if cpu_arch == "32bit": - return "linux_x86" - return None - if is_macOS(): - # TODO: exclude ARM - return "macosx_x64" - return None - - -def build_protoc_for_host(cmake_path, source_dir, build_dir, args): - if (args.arm or args.arm64 or args.arm64ec) and not (is_windows() or is_cross_compiling_on_apple(args)): - raise BuildError( - "Currently only support building protoc for Windows host while " - "cross-compiling for ARM/ARM64/Store and linux cross-compiling iOS" - ) - - rid = get_protobuf_rid() - if rid is None: - return None - run_subprocess( - [ - "nuget.exe" if is_windows() else "nuget", - "restore", - os.path.join(source_dir, "packages.config"), - "-ConfigFile", - os.path.join(source_dir, "NuGet.config"), - "-PackagesDirectory", - build_dir, - ] - ) - - protoc_path = list(Path(build_dir).glob("Google.Protobuf.Tools.*"))[0] / "tools" / rid - if is_windows(): - protoc_path = protoc_path / "protoc.exe" - else: - protoc_path = protoc_path / "protoc" - if not protoc_path.exists(): - return None - return protoc_path.absolute() - - def generate_documentation(source_dir, build_dir, configs, validate): # Randomly choose one build config config = next(iter(configs)) @@ -2273,6 +2297,8 @@ def main(): args = parse_arguments() + print(args) + if os.getenv("ORT_BUILD_WITH_CACHE") == "1": args.use_cache = True @@ -2307,7 +2333,7 @@ def main(): if args.use_migraphx: args.use_rocm = True - if args.build_wheel or args.gen_doc or args.use_tvm: + if args.build_wheel or args.gen_doc or args.use_tvm or args.enable_training: args.enable_pybind = True if args.build_csharp or args.build_nuget or args.build_java or args.build_nodejs: @@ -2355,12 +2381,7 @@ def main(): if args.gen_api_doc and len(args.config) != 1: raise BuildError("Using --get-api-doc requires a single build config") - # Disabling unit tests for VAD-F as FPGA only supports - # models with NCHW layout - if args.use_openvino == "VAD-F_FP32": - args.test = False - - # Disabling unit tests for GPU and MYRIAD on nuget creation + # Disabling unit tests for GPU on nuget creation if args.use_openvino != "CPU_FP32" and args.build_nuget: args.test = False @@ -2451,10 +2472,6 @@ def main(): ) cmake_extra_args = ["-G", args.cmake_generator] elif args.arm or args.arm64 or args.arm64ec: - # Cross-compiling for ARM(64) architecture - # First build protoc for host to use during cross-compilation - if path_to_protoc_exe is None: - path_to_protoc_exe = build_protoc_for_host(cmake_path, source_dir, build_dir, args) if args.arm: cmake_extra_args = ["-A", "ARM"] elif args.arm64: @@ -2488,20 +2505,27 @@ def main(): toolset = "host=" + host_arch if args.cuda_version: toolset += ",cuda=" + args.cuda_version + elif args.cuda_home: + toolset += ",cuda=" + args.cuda_home + if args.windows_sdk_version: + target_arch += ",version=" + args.windows_sdk_version cmake_extra_args = ["-A", target_arch, "-T", toolset, "-G", args.cmake_generator] if args.enable_wcos: cmake_extra_defines.append("CMAKE_USER_MAKE_RULES_OVERRIDE=wcos_rules_override.cmake") - elif args.cmake_generator is not None and not (is_macOS() and args.use_xcode): + elif args.cmake_generator is not None: cmake_extra_args += ["-G", args.cmake_generator] - elif is_macOS(): - if args.use_xcode: - cmake_extra_args += ["-G", "Xcode"] + + if is_macOS(): if not args.ios and not args.android and args.osx_arch == "arm64" and platform.machine() == "x86_64": if args.test: log.warning("Cannot test ARM64 build on X86_64. Will skip test running after build.") args.test = False if args.build_wasm: + if is_windows() and platform.architecture()[0] == "32bit": + raise BuildError("Please use a 64-bit python to run this script") + if args.build_wheel or args.enable_pybind: + raise BuildError("WASM does not support pybind") emsdk_version = args.emsdk_version emsdk_dir = os.path.join(source_dir, "cmake", "external", "emsdk") emsdk_file = os.path.join(emsdk_dir, "emsdk.bat") if is_windows() else os.path.join(emsdk_dir, "emsdk") @@ -2511,12 +2535,6 @@ def main(): log.info("Activating emsdk...") run_subprocess([emsdk_file, "activate", emsdk_version], cwd=emsdk_dir) - if ( - args.android or args.ios or args.build_wasm or is_cross_compiling_on_apple(args) - ) and args.path_to_protoc_exe is None: - # Cross-compiling for Android, iOS, and WebAssembly - path_to_protoc_exe = build_protoc_for_host(cmake_path, source_dir, build_dir, args) - if is_ubuntu_1604(): if args.arm or args.arm64: raise BuildError("Only Windows ARM(64) cross-compiled builds supported currently through this script") @@ -2526,12 +2544,6 @@ def main(): if args.enable_pybind and is_windows(): install_python_deps(args.numpy_version) - if args.use_cuda and args.cuda_version is None: - if is_windows(): - # cuda_version is used while generating version_info.py on Windows. - raise BuildError("cuda_version must be specified on Windows.") - else: - args.cuda_version = "" if args.use_rocm and args.rocm_version is None: args.rocm_version = "" @@ -2572,7 +2584,7 @@ def main(): if args.build: if args.parallel < 0: raise BuildError(f"Invalid parallel job count: {args.parallel}") - num_parallel_jobs = os.cpu_count() if args.parallel == 0 else args.parallel + num_parallel_jobs = number_of_parallel_jobs(args) build_targets(args, cmake_path, build_dir, configs, num_parallel_jobs, args.target) if args.test: @@ -2630,17 +2642,21 @@ def main(): ) if args.build_nuget: build_nuget_package( + cmake_path, source_dir, build_dir, configs, args.use_cuda, + args.use_rocm, args.use_openvino, args.use_tensorrt, args.use_dnnl, args.use_tvm, args.use_winml, args.use_snpe, + args.use_qnn, args.enable_training_apis, + normalize_arg_list(args.msbuild_extra_options), ) if args.test and args.build_nuget: diff --git a/tools/ci_build/compile_triton.py b/tools/ci_build/compile_triton.py new file mode 100644 index 0000000000000..c1119aad49ae8 --- /dev/null +++ b/tools/ci_build/compile_triton.py @@ -0,0 +1,174 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# -------------------------------------------------------------------------- + +import argparse +import importlib.util +import os +import shutil + +import triton + + +def compile(function_table, out_dir): + def compile_one(func, sig, **kwargs): + ret = triton.compile(func, signature=sig, **kwargs) + return ret + + metadata = [] + for func_desc in function_table: + name = func_desc["name"] + group = func_desc["group"] + sig = func_desc["sig"] + func = func_desc["func"] + kwargs = func_desc["kwargs"] + + # print("compile func: ", func_desc) + + ret = compile_one(func, sig, **kwargs) + + compile_res = {} + compile_res["name"] = name + compile_res["group"] = group + compile_res["func_name"] = ret.metadata["name"] + compile_res["num_warps"] = ret.metadata["num_warps"] + compile_res["shared"] = ret.metadata["shared"] + if "constants" in kwargs: + compile_res["constants"] = kwargs["constants"] + + # move tmp kernel file into current dir + if "hsaco_path" in ret.asm and os.path.exists(ret.asm["hsaco_path"]): + # is rocm + lib_name = f"{name}.hsaco" + shutil.copyfile(ret.asm["hsaco_path"], f"{out_dir}/{lib_name}") + elif "cubin" in ret.asm: + # is cuda + lib_name = f"{name}.cubin" + # need to write cubin into file + with open(f"{out_dir}/{lib_name}", "wb") as fp: + fp.write(ret.asm["cubin"]) + else: + raise Exception("not find rocm or cuda compiled kernel") + + compile_res["lib_file"] = lib_name + metadata.append(compile_res) + + return metadata + + +def convert_lib_to_obj(lib_file, out_dir): + obj_file = lib_file.split(".")[0] + ".o" + command = f"cd {out_dir}; objcopy -I binary -O elf64-x86-64 -B i386:x86-64 {lib_file} {obj_file}; cd -" + ret = os.system(command) + + if ret != 0: + raise Exception(f"exec convert command: {command} failed.") + # check file exist + if not os.path.exists(f"{out_dir}/{obj_file}"): + raise Exception(f"the output file not exist, after exec comamnd: {command}") + + return obj_file + + +def archive_obj_files(obj_files, out_dir, out_obj_file): + obj_files = " ".join(obj_files) + command = f"cd {out_dir}; ar rcs {out_obj_file} {obj_files}; cd -" + ret = os.system(command) + + if ret != 0: + raise Exception(f"exec convert command: {command} failed.") + # check file exist + if not os.path.exists(f"{out_dir}/{out_obj_file}"): + raise Exception(f"the output file not exist, after exec comamnd: {command}") + + +def convert_and_save(metadata, header_file, out_dir, out_obj_file): + c_metadata = [] + binary_files = [] + for m in metadata: + meta_ele = [] + obj_file = convert_lib_to_obj(m["lib_file"], out_dir) + binary_files.append(obj_file) + + lib_name = m["lib_file"].replace(".", "_") + meta_ele.append(f'"_binary_{lib_name}_start"') + meta_ele.append(f"\"{m['func_name']}\"") + meta_ele.append(f"\"{m['group']}\"") + meta_ele.append(f"\"{m['name']}\"") + meta_ele.append(str(m["num_warps"])) + meta_ele.append(str(m["shared"])) + + # convert constants + constants = [] + for k, v in m["constants"].items(): + constants.append(f'{{ "{k}", {v!s}}}') + meta_ele.append(f"{{ { ', '.join(constants) } }}") + + c_metadata.append(f"{{ { ', '.join(meta_ele) } }}") + + archive_obj_files(binary_files, out_dir, out_obj_file) + + code = f""" +#include + +struct _TritonKernelInfo {{ + const char* name_start; + const char* func_name; + const char* group_name; + const char* name; + int num_warps; + int shared; + std::unordered_map constants; +}}; + +const _TritonKernelInfo kernel_infos[] = {{ + { ', '.join(c_metadata) }, +}}; + """ + + with open(header_file, "w") as fp: + fp.write(code) + + +def main(args): + out_obj_file = args.obj_file + out_dir = os.path.dirname(out_obj_file) + out_obj_file = os.path.basename(out_obj_file) + if not os.path.exists(out_dir): + os.mkdir(out_dir) + + metadata = [] + print("[triton kernel] start compile triton kernel.") + for i, f in enumerate(args.script_files): + # import module in f, and call function + spec = importlib.util.spec_from_file_location(f"module_{i}", f) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + func_tb = module.get_function_table() + m = compile(func_tb, out_dir) + metadata.extend(m) + + print("[triton kernel] compile triton kernel done.") + + # save metadata into header file + convert_and_save(metadata, args.header, out_dir, out_obj_file) + print("[triton kernel] save into file done.") + + +def get_arges(): + parser = argparse.ArgumentParser(description="PyTorch Template Finetune Example") + parser.add_argument( + "--header", type=str, default="triton_kernel_infos.h", help="the header file that should be generated." + ) + parser.add_argument("--ort_root", type=str, default="onnxruntime", help="the root dir of onnxruntime.") + parser.add_argument("--script_files", type=str, nargs="+", help="the root dir of onnxruntime.") + parser.add_argument("--obj_file", type=str, default="triton_kernel_infos.a", help="output target object files.") + + args = parser.parse_args() + return args + + +if __name__ == "__main__": + args = get_arges() + main(args) diff --git a/tools/ci_build/gen_def.py b/tools/ci_build/gen_def.py index fcb9ae0a4ef01..9821f3a901c1a 100755 --- a/tools/ci_build/gen_def.py +++ b/tools/ci_build/gen_def.py @@ -67,7 +67,7 @@ def parse_arguments(): # external symbols are removed, xnnpack ep will be created via the standard ORT API. # https://github.com/microsoft/onnxruntime/pull/11798 - if c not in ("winml", "cuda", "migraphx", "qnn", "snpe", "xnnpack", "cann", "dnnl"): + if c not in ("vitisai", "winml", "cuda", "rocm", "migraphx", "qnn", "snpe", "xnnpack", "cann", "dnnl"): file.write(f"#include \n") file.write("void* GetFunctionEntryByName(const char* name){\n") for symbol in symbols: diff --git a/tools/ci_build/get_docker_image.py b/tools/ci_build/get_docker_image.py index 2bab9e61c7b06..2ce1764c96327 100755 --- a/tools/ci_build/get_docker_image.py +++ b/tools/ci_build/get_docker_image.py @@ -86,7 +86,7 @@ def main(): manylinux_build_scripts_folder = Path(args.manylinux_src) / "docker" / "build_scripts" dest = Path(args.context) / "build_scripts" if dest.exists(): - log.info(f"Deleting: {str(dest)}") + log.info(f"Deleting: {dest!s}") shutil.rmtree(str(dest)) shutil.copytree(str(manylinux_build_scripts_folder), str(dest)) src_entrypoint_file = str(Path(args.manylinux_src) / "docker" / "manylinux-entrypoint") diff --git a/tools/ci_build/github/Doxyfile_csharp.cfg b/tools/ci_build/github/Doxyfile_csharp.cfg index dccc15ed1137d..38e8a59736d82 100644 --- a/tools/ci_build/github/Doxyfile_csharp.cfg +++ b/tools/ci_build/github/Doxyfile_csharp.cfg @@ -524,7 +524,7 @@ EXTRACT_PACKAGE = NO # included in the documentation. # The default value is: NO. -EXTRACT_STATIC = NO +EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined # locally in source files will be included in the documentation. If set to NO, diff --git a/tools/ci_build/github/android/build_aar_package.py b/tools/ci_build/github/android/build_aar_package.py index 86f5dc1555f01..f9688a1453e12 100644 --- a/tools/ci_build/github/android/build_aar_package.py +++ b/tools/ci_build/github/android/build_aar_package.py @@ -95,42 +95,11 @@ def _build_aar(args): exe_dir = os.path.join(intermediates_dir, "executables", build_config) base_build_command = [sys.executable, BUILD_PY] + build_settings["build_params"] + ["--config=" + build_config] header_files_path = "" - # Build and install protoc - protobuf_installation_script = os.path.join( - REPO_DIR, - "tools", - "ci_build", - "github", - "linux", - "docker", - "inference", - "x64", - "python", - "cpu", - "scripts", - "install_protobuf.sh", - ) - subprocess.run( - [ - protobuf_installation_script, - "-p", - os.path.join(build_dir, "protobuf"), - "-d", - os.path.join(REPO_DIR, "cmake", "deps.txt"), - ], - shell=False, - check=True, - ) + # Build binary for each ABI, one by one for abi in build_settings["build_abis"]: abi_build_dir = os.path.join(intermediates_dir, abi) - abi_build_command = [ - *base_build_command, - "--android_abi=" + abi, - "--build_dir=" + abi_build_dir, - "--path_to_protoc_exe", - os.path.join(build_dir, "protobuf", "bin", "protoc"), - ] + abi_build_command = [*base_build_command, "--android_abi=" + abi, "--build_dir=" + abi_build_dir] if ops_config_path is not None: abi_build_command += ["--include_ops_by_config=" + ops_config_path] @@ -180,6 +149,9 @@ def _build_aar(args): "-DminSdkVer=" + str(build_settings["android_min_sdk_version"]), "-DtargetSdkVer=" + str(build_settings["android_target_sdk_version"]), "-DbuildVariant=" + str(build_settings["build_variant"]), + "-DENABLE_TRAINING_APIS=1" + if "--enable_training_apis" in build_settings["build_params"] + else "-DENABLE_TRAINING_APIS=0", ] # clean, build, and publish to a local directory diff --git a/tools/ci_build/github/android/nnapi_supported_ops.md b/tools/ci_build/github/android/nnapi_supported_ops.md index 25527a83f1be2..223a1e9106cb1 100644 --- a/tools/ci_build/github/android/nnapi_supported_ops.md +++ b/tools/ci_build/github/android/nnapi_supported_ops.md @@ -37,6 +37,7 @@ Keep in sync with doco generated from /docs/execution-providers/NNAPI-ExecutionP |ai.onnx:QLinearConv|Only 2D Conv is supported.
Weights and bias should be constant.
All quantization scales and zero points should be constant.| |ai.onnx:QLinearMatMul|All quantization scales and zero points should be constant.| |ai.onnx:QuantizeLinear|All quantization scales and zero points should be constant.| +|ai.onnx:ReduceMean|| |ai.onnx:Relu|| |ai.onnx:Reshape|| |ai.onnx:Resize|Only 2D Resize is supported.| diff --git a/tools/ci_build/github/android/training_full_aar_build_settings.json b/tools/ci_build/github/android/training_full_aar_build_settings.json new file mode 100644 index 0000000000000..76cb9f0b17a8c --- /dev/null +++ b/tools/ci_build/github/android/training_full_aar_build_settings.json @@ -0,0 +1,21 @@ +{ + "build_abis": [ + "armeabi-v7a", + "arm64-v8a", + "x86", + "x86_64" + ], + "android_min_sdk_version": 21, + "android_target_sdk_version": 24, + "build_params": [ + "--android", + "--parallel", + "--cmake_generator=Ninja", + "--build_java", + "--build_shared_lib", + "--use_nnapi", + "--use_xnnpack", + "--skip_tests", + "--enable_training_apis" + ] +} diff --git a/tools/ci_build/github/apple/assemble_ios_packaging_artifacts.sh b/tools/ci_build/github/apple/assemble_ios_packaging_artifacts.sh index e71ac75e6c3ab..317048506ac67 100755 --- a/tools/ci_build/github/apple/assemble_ios_packaging_artifacts.sh +++ b/tools/ci_build/github/apple/assemble_ios_packaging_artifacts.sh @@ -6,7 +6,7 @@ set -e set -x -USAGE_TEXT="Usage: ${0} " +USAGE_TEXT="Usage: ${0} " abspath() { local INPUT_PATH=${1:?"Expected path as the first argument."} @@ -17,39 +17,16 @@ abspath() { BINARIES_STAGING_DIR=$(abspath "${1:?${USAGE_TEXT}}") # staging directory for build artifacts (destination) ARTIFACTS_STAGING_DIR=$(abspath "${2:?${USAGE_TEXT}}") -ORT_POD_VERSION=${3:?${USAGE_TEXT}} -SHOULD_UPLOAD_ARCHIVES=${4:?${USAGE_TEXT}} +POD_NAME=${3:?${USAGE_TEXT}} +ORT_POD_VERSION=${4:?${USAGE_TEXT}} -STORAGE_ACCOUNT_NAME="onnxruntimepackages" -STORAGE_ACCOUNT_CONTAINER_NAME='$web' -STORAGE_URL_PREFIX=$(az storage account show --name ${STORAGE_ACCOUNT_NAME} --query "primaryEndpoints.web" --output tsv) +POD_ARCHIVE_BASENAME="pod-archive-${POD_NAME}-${ORT_POD_VERSION}.zip" +PODSPEC_BASENAME="${POD_NAME}.podspec" -assemble_and_upload_pod() { - local POD_NAME=${1:?"Expected pod name as first argument."} - local POD_ARCHIVE_BASENAME="pod-archive-${POD_NAME}-${ORT_POD_VERSION}.zip" - local PODSPEC_BASENAME="${POD_NAME}.podspec" +pushd "${BINARIES_STAGING_DIR}/${POD_NAME}" - pushd ${BINARIES_STAGING_DIR}/${POD_NAME} +# assemble the files in the artifacts staging directory +zip -r "${ARTIFACTS_STAGING_DIR}/${POD_ARCHIVE_BASENAME}" ./* --exclude "${PODSPEC_BASENAME}" +cp "${PODSPEC_BASENAME}" "${ARTIFACTS_STAGING_DIR}/${PODSPEC_BASENAME}" - # assemble the files in the artifacts staging directory - zip -r ${ARTIFACTS_STAGING_DIR}/${POD_ARCHIVE_BASENAME} * --exclude ${PODSPEC_BASENAME} - cp ${PODSPEC_BASENAME} ${ARTIFACTS_STAGING_DIR}/${PODSPEC_BASENAME} - - if [[ "${SHOULD_UPLOAD_ARCHIVES}" == "true" ]]; then - # upload the pod archive and set the podspec source to the pod archive URL - az storage blob upload \ - --account-name ${STORAGE_ACCOUNT_NAME} --container-name ${STORAGE_ACCOUNT_CONTAINER_NAME} \ - --file ${ARTIFACTS_STAGING_DIR}/${POD_ARCHIVE_BASENAME} --name ${POD_ARCHIVE_BASENAME} \ - --if-none-match "*" - - sed -i "" -e "s|file:///http_source_placeholder|${STORAGE_URL_PREFIX}${POD_ARCHIVE_BASENAME}|" \ - ${ARTIFACTS_STAGING_DIR}/${PODSPEC_BASENAME} - fi - - popd -} - -assemble_and_upload_pod "onnxruntime-mobile-c" -assemble_and_upload_pod "onnxruntime-mobile-objc" -assemble_and_upload_pod "onnxruntime-c" -assemble_and_upload_pod "onnxruntime-objc" +popd diff --git a/tools/ci_build/github/apple/c/assemble_c_pod_package.py b/tools/ci_build/github/apple/c/assemble_c_pod_package.py index dd80123c25591..14e7729610617 100644 --- a/tools/ci_build/github/apple/c/assemble_c_pod_package.py +++ b/tools/ci_build/github/apple/c/assemble_c_pod_package.py @@ -30,6 +30,8 @@ def get_pod_config_file(package_variant: PackageVariant): return _script_dir / "onnxruntime-mobile-c.config.json" elif package_variant == PackageVariant.Test: return _script_dir / "onnxruntime-test-c.config.json" + elif package_variant == PackageVariant.Training: + return _script_dir / "onnxruntime-training-c.config.json" else: raise ValueError(f"Unhandled package variant: {package_variant}") diff --git a/tools/ci_build/github/apple/c/onnxruntime-training-c.config.json b/tools/ci_build/github/apple/c/onnxruntime-training-c.config.json new file mode 100644 index 0000000000000..87011c216a50c --- /dev/null +++ b/tools/ci_build/github/apple/c/onnxruntime-training-c.config.json @@ -0,0 +1,5 @@ +{ + "name": "onnxruntime-training-c", + "summary": "ONNX Runtime Training C/C++ Pod", + "description": "A pod for the ONNX Runtime C/C++ library. This pod supports additional training features." +} diff --git a/tools/ci_build/github/apple/coreml_supported_ops.md b/tools/ci_build/github/apple/coreml_supported_ops.md index 95ac120dc7875..959177bcb4d7b 100644 --- a/tools/ci_build/github/apple/coreml_supported_ops.md +++ b/tools/ci_build/github/apple/coreml_supported_ops.md @@ -14,9 +14,11 @@ Keep in sync with doco generated from /docs/execution-providers/CoreML-Execution |ai.onnx:DepthToSpace|Only DCR mode DepthToSpace is supported.| |ai.onnx:Div|| |ai.onnx:Flatten|| +|ai.onnx:Gather|Input `indices` with scalar value is not supported.| |ai.onnx:Gemm|Input B should be constant.| |ai.onnx:GlobalAveragePool|Only 2D Pool is supported.| |ai.onnx:GlobalMaxPool|Only 2D Pool is supported.| +|ai.onnx:LeakyRelu|| |ai.onnx:LRN|| |ai.onnx:MatMul|Input B should be constant.| |ai.onnx:MaxPool|Only 2D Pool is supported.| @@ -24,11 +26,16 @@ Keep in sync with doco generated from /docs/execution-providers/CoreML-Execution |ai.onnx:Pad|Only constant mode and last two dim padding is supported.
Input pads and constant_value should be constant.
If provided, axes should be constant.| |ai.onnx:Pow|Only supports cases when both inputs are fp32.| |ai.onnx:PRelu|Input slope should be constant.
Input slope should either have shape [C, 1, 1] or have 1 element.| +|ai.onnx:Reciprocal|| +|ai.onnx.ReduceSum|| |ai.onnx:Relu|| |ai.onnx:Reshape|| |ai.onnx:Resize|| +|ai.onnx:Shape|Attribute `start` with non-default value is not supported.
Attribute `end` is not supported.| |ai.onnx:Sigmoid|| +|ai.onnx:Slice|Inputs `starts`, `ends`, `axes`, and `steps` should be constant. Empty slice is not supported.| |ai.onnx:Squeeze|| +|ai.onnx:Sqrt|| |ai.onnx:Sub|| |ai.onnx:Tanh|| |ai.onnx:Transpose|| 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 9a18e3bf9a29e..621af55fad7fa 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 @@ -14,9 +14,9 @@ "--use_xcode", "--build_apple_framework", "--use_coreml", + "--use_xnnpack", "--skip_tests", "--cmake_extra_defines=onnxruntime_BUILD_UNIT_TESTS=OFF", - "--apple_deploy_target=11.0", - "--use_xnnpack" + "--apple_deploy_target=12.0" ] } diff --git a/tools/ci_build/github/apple/default_mobile_ios_framework_build_settings.json b/tools/ci_build/github/apple/default_mobile_ios_framework_build_settings.json index afcee196acad6..2738a7ca7b009 100644 --- a/tools/ci_build/github/apple/default_mobile_ios_framework_build_settings.json +++ b/tools/ci_build/github/apple/default_mobile_ios_framework_build_settings.json @@ -21,6 +21,6 @@ "--use_coreml", "--skip_tests", "--cmake_extra_defines=onnxruntime_BUILD_UNIT_TESTS=OFF", - "--apple_deploy_target=11.0" + "--apple_deploy_target=12.0" ] } diff --git a/tools/ci_build/github/apple/default_training_ios_framework_build_settings.json b/tools/ci_build/github/apple/default_training_ios_framework_build_settings.json new file mode 100644 index 0000000000000..ec7fcafce04f2 --- /dev/null +++ b/tools/ci_build/github/apple/default_training_ios_framework_build_settings.json @@ -0,0 +1,23 @@ +{ + "build_osx_archs": { + "iphoneos": [ + "arm64" + ], + "iphonesimulator": [ + "arm64", + "x86_64" + ] + }, + "build_params": [ + "--ios", + "--parallel", + "--use_xcode", + "--enable_training_apis", + "--build_apple_framework", + "--use_coreml", + "--use_xnnpack", + "--skip_tests", + "--cmake_extra_defines=onnxruntime_BUILD_UNIT_TESTS=OFF", + "--apple_deploy_target=12.0" + ] +} diff --git a/tools/ci_build/github/apple/get_simulator_device_info.py b/tools/ci_build/github/apple/get_simulator_device_info.py new file mode 100755 index 0000000000000..2a36418bac9cb --- /dev/null +++ b/tools/ci_build/github/apple/get_simulator_device_info.py @@ -0,0 +1,154 @@ +#!/usr/bin/env python3 +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +from __future__ import annotations + +import argparse +import functools +import itertools +import json +import subprocess + + +@functools.total_ordering +class Version: + """ + A simple Version class. + We opt to use this instead of `packaging.version.Version` to avoid depending on the external `packaging` package. + It only supports integer version components. + """ + + def __init__(self, version_string: str): + self._components = tuple(int(component) for component in version_string.split(".")) + + def __eq__(self, other: Version) -> bool: + component_pairs = itertools.zip_longest(self._components, other._components, fillvalue=0) + return all(pair[0] == pair[1] for pair in component_pairs) + + def __lt__(self, other: Version) -> bool: + component_pairs = itertools.zip_longest(self._components, other._components, fillvalue=0) + for self_component, other_component in component_pairs: + if self_component != other_component: + return self_component < other_component + return False + + +def get_simulator_device_info( + requested_runtime_platform: str = "iOS", + requested_device_type_product_family: str = "iPhone", + max_runtime_version_str: str | None = None, +) -> dict[str, str]: + """ + Retrieves simulator device information from Xcode. + This simulator device should be appropriate for running tests on this machine. + + :param requested_runtime_platform: The runtime platform to select. + :param requested_device_type_product_family: The device type product family to select. + :param max_runtime_version_str: The maximum runtime version to allow. + + :return: A dictionary containing information about the selected simulator device. + """ + max_runtime_version = Version(max_runtime_version_str) if max_runtime_version_str is not None else None + + simctl_proc = subprocess.run( + ["xcrun", "simctl", "list", "--json", "--no-escape-slashes"], + text=True, + capture_output=True, + check=True, + ) + + simctl_json = json.loads(simctl_proc.stdout) + + # device type id -> device type structure + device_type_map = {device_type["identifier"]: device_type for device_type in simctl_json["devicetypes"]} + + # runtime id -> runtime structure + runtime_map = {runtime["identifier"]: runtime for runtime in simctl_json["runtimes"]} + + def runtime_filter(runtime) -> bool: + if not runtime["isAvailable"]: + return False + + if runtime["platform"] != requested_runtime_platform: + return False + + if max_runtime_version is not None and Version(runtime["version"]) > max_runtime_version: + return False + + return True + + def runtime_id_filter(runtime_id: str) -> bool: + runtime = runtime_map.get(runtime_id) + if runtime is None: + return False + return runtime_filter(runtime) + + def device_type_filter(device_type) -> bool: + if device_type["productFamily"] != requested_device_type_product_family: + return False + + return True + + def device_filter(device) -> bool: + if not device["isAvailable"]: + return False + + if not device_type_filter(device_type_map[device["deviceTypeIdentifier"]]): + return False + + return True + + # simctl_json["devices"] is a map of runtime id -> list of device structures + # expand this into a list of (runtime id, device structure) and filter out invalid entries + runtime_id_and_device_pairs = [] + for runtime_id, device_list in filter( + lambda runtime_id_and_device_list: runtime_id_filter(runtime_id_and_device_list[0]), + simctl_json["devices"].items(), + ): + runtime_id_and_device_pairs.extend((runtime_id, device) for device in filter(device_filter, device_list)) + + # sort key - tuple of (runtime version, device type min runtime version) + # the secondary device type min runtime version value is to treat more recent device types as greater + def runtime_id_and_device_pair_key(runtime_id_and_device_pair): + runtime_id, device = runtime_id_and_device_pair + + runtime = runtime_map[runtime_id] + device_type = device_type_map[device["deviceTypeIdentifier"]] + + return (Version(runtime["version"]), device_type["minRuntimeVersion"]) + + selected_runtime_id, selected_device = max(runtime_id_and_device_pairs, key=runtime_id_and_device_pair_key) + selected_runtime = runtime_map[selected_runtime_id] + selected_device_type = device_type_map[selected_device["deviceTypeIdentifier"]] + + result = { + "device_name": selected_device["name"], + "device_udid": selected_device["udid"], + "device_type_identifier": selected_device_type["identifier"], + "device_type_name": selected_device_type["name"], + "device_type_product_family": selected_device_type["productFamily"], + "runtime_identifier": selected_runtime["identifier"], + "runtime_platform": selected_runtime["platform"], + "runtime_version": selected_runtime["version"], + } + + return result + + +def main(): + parser = argparse.ArgumentParser(description="Gets simulator info from Xcode and prints it in JSON format.") + _ = parser.parse_args() # no args yet + + info = get_simulator_device_info( + # The macOS-13 hosted agent image has iOS 17 which is currently in beta. Limit it to 16.4 for now. + # See https://github.com/actions/runner-images/issues/8023 + # TODO Remove max_runtime_version limit. + max_runtime_version_str="16.4", + ) + + print(json.dumps(info, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/tools/ci_build/github/apple/objectivec/assemble_objc_pod_package.py b/tools/ci_build/github/apple/objectivec/assemble_objc_pod_package.py index b80c408e98204..135a55165beda 100755 --- a/tools/ci_build/github/apple/objectivec/assemble_objc_pod_package.py +++ b/tools/ci_build/github/apple/objectivec/assemble_objc_pod_package.py @@ -15,6 +15,7 @@ from package_assembly_utils import ( # noqa: E402 PackageVariant, copy_repo_relative_to_dir, + filter_files, gen_file_from_template, load_json_config, ) @@ -29,31 +30,71 @@ "objectivec", ] -# pod source files -source_files = [ - "objectivec/include/*.h", - "objectivec/*.h", - "objectivec/*.m", - "objectivec/*.mm", -] - -# pod public header files -# note: these are a subset of source_files -public_header_files = [ - "objectivec/include/*.h", -] - -# pod test source files -test_source_files = [ - "objectivec/test/*.h", - "objectivec/test/*.m", - "objectivec/test/*.mm", -] - -# pod test resource files -test_resource_files = [ - "objectivec/test/testdata/*.ort", -] +all_objc_files = { + "source_files": [ + "objectivec/include/*.h", + "objectivec/*.h", + "objectivec/*.m", + "objectivec/*.mm", + ], + "public_header_files": [ + "objectivec/include/*.h", + ], + "test_source_files": [ + "objectivec/test/*.h", + "objectivec/test/*.m", + "objectivec/test/*.mm", + ], + "test_resource_files": [ + "objectivec/test/testdata/*.ort", + "onnxruntime/test/testdata/training_api/*.onnx", + "onnxruntime/test/testdata/training_api/*.ckpt", + "onnxruntime/test/testdata/training_api/*.in", + "onnxruntime/test/testdata/training_api/*.out", + ], +} + +training_only_objc_files = { + "source_files": [ + "objectivec/include/onnxruntime_training.h", + "objectivec/include/ort_checkpoint.h", + "objectivec/include/ort_training_session.h", + "objectivec/ort_checkpoint.mm", + "objectivec/ort_checkpoint_internal.h", + "objectivec/ort_training_session_internal.h", + "objectivec/ort_training_session.mm", + ], + "public_header_files": [ + "objectivec/include/ort_checkpoint.h", + "objectivec/include/ort_training_session.h", + "objectivec/include/onnxruntime_training.h", + ], + "test_source_files": [ + "objectivec/test/ort_training_session_test.mm", + "objectivec/test/ort_checkpoint_test.mm", + "objectivec/test/ort_training_utils_test.mm", + ], + "test_resource_files": [ + "onnxruntime/test/testdata/training_api/*.onnx", + "onnxruntime/test/testdata/training_api/*.ckpt", + "onnxruntime/test/testdata/training_api/*.in", + "onnxruntime/test/testdata/training_api/*.out", + ], +} + + +def get_pod_files(package_variant: PackageVariant): + """ + Gets the source and header files for the given package variant. + """ + if package_variant == PackageVariant.Training: + return all_objc_files + else: + # return files that are in pod_files but not in training_only_objc_files + filtered_pod_files = {} + for key in all_objc_files: + filtered_pod_files[key] = filter_files(all_objc_files[key], training_only_objc_files[key]) + return filtered_pod_files def get_pod_config_file(package_variant: PackageVariant): @@ -64,6 +105,8 @@ def get_pod_config_file(package_variant: PackageVariant): return _script_dir / "onnxruntime-objc.config.json" elif package_variant == PackageVariant.Mobile: return _script_dir / "onnxruntime-mobile-objc.config.json" + elif package_variant == PackageVariant.Training: + return _script_dir / "onnxruntime-training-objc.config.json" else: raise ValueError(f"Unhandled package variant: {package_variant}") @@ -93,8 +136,13 @@ def assemble_objc_pod_package( if staging_dir.exists(): print("Warning: staging directory already exists", file=sys.stderr) + pod_files = get_pod_files(package_variant) + # copy the necessary files to the staging directory - copy_repo_relative_to_dir([license_file, *source_files, *test_source_files, *test_resource_files], staging_dir) + copy_repo_relative_to_dir( + [license_file, *pod_files["source_files"], *pod_files["test_source_files"], *pod_files["test_resource_files"]], + staging_dir, + ) # generate the podspec file from the template @@ -108,11 +156,11 @@ def path_patterns_as_variable_value(patterns: list[str]): "IOS_DEPLOYMENT_TARGET": framework_info["IOS_DEPLOYMENT_TARGET"], "LICENSE_FILE": license_file, "NAME": pod_name, - "PUBLIC_HEADER_FILE_LIST": path_patterns_as_variable_value(public_header_files), - "SOURCE_FILE_LIST": path_patterns_as_variable_value(source_files), + "PUBLIC_HEADER_FILE_LIST": path_patterns_as_variable_value(pod_files["public_header_files"]), + "SOURCE_FILE_LIST": path_patterns_as_variable_value(pod_files["source_files"]), "SUMMARY": pod_config["summary"], - "TEST_RESOURCE_FILE_LIST": path_patterns_as_variable_value(test_resource_files), - "TEST_SOURCE_FILE_LIST": path_patterns_as_variable_value(test_source_files), + "TEST_RESOURCE_FILE_LIST": path_patterns_as_variable_value(pod_files["test_resource_files"]), + "TEST_SOURCE_FILE_LIST": path_patterns_as_variable_value(pod_files["test_source_files"]), "VERSION": pod_version, } diff --git a/tools/ci_build/github/apple/objectivec/onnxruntime-training-objc.config.json b/tools/ci_build/github/apple/objectivec/onnxruntime-training-objc.config.json new file mode 100644 index 0000000000000..b1cc2d4aad5a8 --- /dev/null +++ b/tools/ci_build/github/apple/objectivec/onnxruntime-training-objc.config.json @@ -0,0 +1,5 @@ +{ + "name": "onnxruntime-training-objc", + "summary": "ONNX Runtime Objective-C Pod", + "description": "A pod for the ONNX Runtime Objective-C training API." +} diff --git a/tools/ci_build/github/apple/objectivec/static_analysis/requirements.txt b/tools/ci_build/github/apple/objectivec/static_analysis/requirements.txt deleted file mode 100644 index 528bdbbe906ac..0000000000000 --- a/tools/ci_build/github/apple/objectivec/static_analysis/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -ninja==1.10.2 diff --git a/tools/ci_build/github/apple/package_assembly_utils.py b/tools/ci_build/github/apple/package_assembly_utils.py index cb603fadc7371..e5940774c54f9 100644 --- a/tools/ci_build/github/apple/package_assembly_utils.py +++ b/tools/ci_build/github/apple/package_assembly_utils.py @@ -16,6 +16,7 @@ class PackageVariant(enum.Enum): Full = 0 # full ORT build with all opsets, ops, and types Mobile = 1 # minimal ORT build with reduced ops + Training = 2 # full ORT build with all opsets, ops, and types, plus training APIs Test = -1 # for testing purposes only @classmethod @@ -70,6 +71,27 @@ def replace_template_variable(match): output.write(content) +def filter_files(all_file_patterns: List[str], excluded_file_patterns: List[str]): + """ + Filters file paths based on inclusion and exclusion patterns + + :param all_file_patterns The list of file paths to filter. + :param excluded_file_patterns The list of exclusion patterns. + + :return The filtered list of file paths + """ + # get all files matching the patterns in all_file_patterns + all_files = [str(path.relative_to(repo_root)) for pattern in all_file_patterns for path in repo_root.glob(pattern)] + + # get all files matching the patterns in excluded_file_patterns + exclude_files = [ + str(path.relative_to(repo_root)) for pattern in excluded_file_patterns for path in repo_root.glob(pattern) + ] + + # return the difference + return list(set(all_files) - set(exclude_files)) + + def copy_repo_relative_to_dir(patterns: List[str], dest_dir: pathlib.Path): """ Copies file paths relative to the repo root to a directory. diff --git a/tools/ci_build/github/apple/test_ios_packages.py b/tools/ci_build/github/apple/test_ios_packages.py index 814307ab762fa..ff42e9615483a 100644 --- a/tools/ci_build/github/apple/test_ios_packages.py +++ b/tools/ci_build/github/apple/test_ios_packages.py @@ -4,10 +4,12 @@ import argparse import contextlib +import json import os import pathlib import shutil import subprocess +import sys import tempfile from c.assemble_c_pod_package import assemble_c_pod_package @@ -114,6 +116,17 @@ def _test_ios_packages(args): # run the tests if not args.prepare_test_project_only: + simulator_device_info = subprocess.check_output( + [ + sys.executable, + str(REPO_DIR / "tools" / "ci_build" / "github" / "apple" / "get_simulator_device_info.py"), + ], + text=True, + ).strip() + print(f"Simulator device info:\n{simulator_device_info}") + + simulator_device_info = json.loads(simulator_device_info) + subprocess.run( [ "xcrun", @@ -124,7 +137,7 @@ def _test_ios_packages(args): "-scheme", "ios_package_test", "-destination", - "platform=iOS Simulator,OS=latest,name=iPhone SE (2nd generation)", + f"platform=iOS Simulator,id={simulator_device_info['device_udid']}", ], shell=False, check=True, diff --git a/tools/ci_build/github/apple/upload_pod_archive_and_update_podspec.sh b/tools/ci_build/github/apple/upload_pod_archive_and_update_podspec.sh new file mode 100755 index 0000000000000..311519985f3ad --- /dev/null +++ b/tools/ci_build/github/apple/upload_pod_archive_and_update_podspec.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +# Note: This script is intended to be called from the iOS CocoaPods package release pipeline or a similar context. + +set -x + +IFS='' read -d '' -r USAGE_TEXT < + Example pod archive path glob pattern: "./pod-archive-*.zip" + Quote the pattern to avoid shell expansion. +USAGE + +set -e + +abspath() { + local INPUT_PATH=${1:?"Expected path as the first argument."} + echo "$(cd "$(dirname "${INPUT_PATH}")" && pwd)/$(basename "${INPUT_PATH}")" +} + +POD_ARCHIVE_PATH_PATTERN=${1:?${USAGE_TEXT}} +PODSPEC_PATH=$(abspath "${2:?${USAGE_TEXT}}") + +# expand pod archive path pattern to exactly one path +POD_ARCHIVE_PATHS=() +while IFS='' read -r line; do POD_ARCHIVE_PATHS+=("$line"); done < <( compgen -G "${POD_ARCHIVE_PATH_PATTERN}" ) +if [[ "${#POD_ARCHIVE_PATHS[@]}" -ne "1" ]]; then + echo "Did not find exactly one pod archive file." + exit 1 +fi + +POD_ARCHIVE_PATH=$(abspath "${POD_ARCHIVE_PATHS[0]}") +POD_ARCHIVE_BASENAME=$(basename "${POD_ARCHIVE_PATH}") + +STORAGE_ACCOUNT_NAME="onnxruntimepackages" +STORAGE_ACCOUNT_CONTAINER_NAME="\$web" +STORAGE_URL_PREFIX=$(az storage account show --name ${STORAGE_ACCOUNT_NAME} --query "primaryEndpoints.web" --output tsv) + +# upload the pod archive and set the podspec source to the pod archive URL +az storage blob upload \ + --account-name ${STORAGE_ACCOUNT_NAME} --container-name ${STORAGE_ACCOUNT_CONTAINER_NAME} \ + --file "${POD_ARCHIVE_PATH}" --name "${POD_ARCHIVE_BASENAME}" \ + --if-none-match "*" + +sed -i "" -e "s|file:///http_source_placeholder|${STORAGE_URL_PREFIX}${POD_ARCHIVE_BASENAME}|" "${PODSPEC_PATH}" 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 de743c07051dd..bbab9f3d85abb 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 @@ -1,12 +1,37 @@ -parameters: +##### start trigger Don't edit it manually, Please do edit 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: QnnSdk displayName: QNN SDK version type: string - default: qnn-v2.8.0.230223123141_52150 - values: - - qnn-v2.6.0.221227110525_42395 - - qnn-v2.8.0.230223123141_52150 + default: qnn-v2.14.1.230828 jobs: - job: Build_QNN_EP @@ -40,7 +65,9 @@ jobs: - script: | set -e -x - tools/ci_build/github/linux/docker/inference/x64/python/cpu/scripts/install_protobuf.sh -p $(Build.BinariesDirectory)/installed -d cmake/deps.txt + rm -rf /tmp/scripts + cp -r tools/ci_build/github/linux/docker/inference/x64/python/cpu/scripts /tmp + /tmp/scripts/install_protobuf.sh -p $(Build.BinariesDirectory)/installed -d cmake/deps.txt python3 tools/ci_build/build.py \ --config Release \ --android \ 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 index ed2ee1913379b..f6f6f52440534 100644 --- 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 @@ -1,3 +1,32 @@ +##### start trigger Don't edit it manually, Please do edit 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 @@ -17,7 +46,11 @@ parameters: default: 0 stages: -- stage: BUILD_STAGE +# 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_CPU_STAGE + variables: + Codeql.Enabled: false jobs: - job: Build_CPU_EP pool: onnxruntime-Linux-CPU-For-Android-CI @@ -46,14 +79,6 @@ stages: - template: "templates/use-android-ndk.yml" - # We build the host protoc to /protobuf_install - - script: | - /bin/bash $(Build.SourcesDirectory)/tools/ci_build/github/apple/build_host_protoc.sh \ - $(Build.SourcesDirectory) \ - $(Build.BinariesDirectory)/protobuf \ - $(Build.SourcesDirectory)/protobuf_install - displayName: Build Host Protoc - - script: | env | grep ANDROID displayName: View Android ENVs @@ -69,7 +94,6 @@ stages: --skip_submodule_sync \ --parallel \ --cmake_generator=Ninja \ - --path_to_protoc_exe $(Build.SourcesDirectory)/protobuf_install/bin/protoc \ --build_java \ --skip_tests displayName: CPU EP, Build @@ -104,9 +128,20 @@ stages: - template: templates/clean-agent-build-directory-step.yml +- stage: BUILD_NNAPI_STAGE + variables: + Codeql.ProjectConfigPath: .github/workflows + Codeql.Enabled: true + Codeql.Language: cpp + ${{ if variables['Codeql.Enabled'] }}: + JobsTimeout: 120 + ${{ else }}: + JobsTimeout: 60 + + jobs: - job: Build_NNAPI_EP pool: onnxruntime-Linux-CPU-For-Android-CI - timeoutInMinutes: 60 + timeoutInMinutes: ${{ variables.JobsTimeout }} workspace: clean: all condition: notIn(variables['Build.Reason'], 'IndividualCI', 'BatchedCI') @@ -128,14 +163,6 @@ stages: - template: "templates/use-android-ndk.yml" - # We build the host protoc to /protobuf_install - - script: | - /bin/bash $(Build.SourcesDirectory)/tools/ci_build/github/apple/build_host_protoc.sh \ - $(Build.SourcesDirectory) \ - $(Build.BinariesDirectory)/protobuf \ - $(Build.SourcesDirectory)/protobuf_install - displayName: Build Host Protoc - - script: | env | grep ANDROID displayName: View Android ENVs @@ -152,7 +179,6 @@ stages: --parallel \ --use_nnapi \ --cmake_generator=Ninja \ - --path_to_protoc_exe $(Build.SourcesDirectory)/protobuf_install/bin/protoc \ --build_java \ --skip_tests displayName: NNAPI EP, Build @@ -188,10 +214,12 @@ stages: - template: templates/clean-agent-build-directory-step.yml - stage: TEST_STAGE - dependsOn: BUILD_STAGE + dependsOn: [BUILD_CPU_STAGE, BUILD_NNAPI_STAGE] jobs: - job: Test_CPU_EP pool: + # We need macOS-12 to run the Android emulator for now. + # https://github.com/actions/runner-images/issues/7671 vmImage: 'macOS-12' workspace: clean: all @@ -261,6 +289,8 @@ stages: - job: Test_NNAPI_EP pool: + # We need macOS-12 to run the Android emulator for now. + # https://github.com/actions/runner-images/issues/7671 vmImage: 'macOS-12' timeoutInMinutes: 90 workspace: @@ -324,14 +354,6 @@ stages: - script: brew install coreutils ninja displayName: Install coreutils and ninja - # We build the host protoc to /protobuf_install - - script: | - /bin/bash $(Build.SourcesDirectory)/tools/ci_build/github/apple/build_host_protoc.sh \ - $(Build.SourcesDirectory) \ - $(Build.BinariesDirectory)/protobuf \ - $(Build.SourcesDirectory)/protobuf_install - displayName: Build Host Protoc - - 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 @@ -354,6 +376,8 @@ stages: jobs: - job: NNAPI_EP_MASTER pool: + # We need macOS-12 to run the Android emulator for now. + # https://github.com/actions/runner-images/issues/7671 vmImage: 'macOS-12' timeoutInMinutes: 180 workspace: @@ -412,7 +436,6 @@ stages: --use_nnapi \ --build_shared_lib \ --cmake_generator=Ninja \ - --path_to_protoc_exe $(Build.SourcesDirectory)/protobuf_install/bin/protoc \ --build_java \ --code_coverage displayName: NNAPI EP, Build, Test, CodeCoverage on Android Emulator diff --git a/tools/ci_build/github/azure-pipelines/binary-size-checks-pipeline.yml b/tools/ci_build/github/azure-pipelines/binary-size-checks-pipeline.yml index 980ae1534738a..e9762bc312455 100644 --- a/tools/ci_build/github/azure-pipelines/binary-size-checks-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/binary-size-checks-pipeline.yml @@ -10,7 +10,7 @@ resources: type: Github endpoint: Microsoft name: pypa/manylinux - ref: aead4d751c2101e23336aa73f2380df83e7a13f3 + ref: 5eda9aded5462201e6310105728d33016e637ea7 stages: diff --git a/tools/ci_build/github/azure-pipelines/build-perf-test-binaries-pipeline.yml b/tools/ci_build/github/azure-pipelines/build-perf-test-binaries-pipeline.yml index eb5446fb8036f..08330764ff5f7 100644 --- a/tools/ci_build/github/azure-pipelines/build-perf-test-binaries-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/build-perf-test-binaries-pipeline.yml @@ -12,7 +12,7 @@ resources: type: Github endpoint: Microsoft name: pypa/manylinux - ref: aead4d751c2101e23336aa73f2380df83e7a13f3 + ref: 5eda9aded5462201e6310105728d33016e637ea7 stages: @@ -28,7 +28,7 @@ stages: artifactName: 'onnxruntime-android-full-aar' job_name_suffix: 'Full' publish_executables: '1' - pool_name: 'aiinfra-Linux-CPU' + pool_name: 'onnxruntime-Ubuntu2004-AMD-CPU' # build Python packages # Linux GPU only @@ -36,7 +36,6 @@ stages: - template: templates/py-packaging-stage.yml parameters: enable_linux_gpu: true - enable_ubuntu_cpu: false enable_linux_cpu: false enable_windows_cpu: false enable_windows_gpu: false 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 17af0d9480711..fdd8c09333737 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 @@ -15,15 +15,51 @@ parameters: default: true - name: DoEsrp - displayName: Run code sign tasks? Must be true if you are doing an Onnx Runtime release. + 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. + 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' + +- name: AdditionalBuildFlag + displayName: Build flags to append to build command + type: string + default: '--use_azure' + resources: repositories: - repository: onnxruntime-inference-examples # The name used to reference this repository in the checkout step @@ -34,17 +70,66 @@ resources: type: Github endpoint: Microsoft name: pypa/manylinux - ref: aead4d751c2101e23336aa73f2380df83e7a13f3 + ref: 5eda9aded5462201e6310105728d33016e637ea7 + +variables: +- name: ReleaseVersionSuffix + value: '' stages: +- stage: Setup + jobs: + - job: Set_Variables + steps: + - checkout: none + - bash: | + # Do not output ##vso[] commands with `set -x` or they may be parsed again and include a trailing quote. + set +x + if [[ "${{ parameters.IsReleaseBuild }}" = True && "${{ parameters.PreReleaseVersionSuffixString }}" != "none" ]]; then + if [[ "${{ parameters.PreReleaseVersionSuffixNumber }}" -eq 0 ]]; then + echo "##vso[task.setvariable variable=ReleaseVersionSuffix;isOutput=true]-${{ parameters.PreReleaseVersionSuffixString }}" + else + echo "##vso[task.setvariable variable=ReleaseVersionSuffix;isOutput=true]-${{ parameters.PreReleaseVersionSuffixString }}.${{ parameters.PreReleaseVersionSuffixNumber }}" + fi + else + echo "##vso[task.setvariable variable=ReleaseVersionSuffix;isOutput=true]" + fi + name: Set_Release_Version_Suffix + +- stage: Debug + dependsOn: Setup + jobs: + - job: D1 + variables: + MyVar: $[stageDependencies.Setup.Set_Variables.outputs['Set_Release_Version_Suffix.ReleaseVersionSuffix']] + steps: + - checkout: none + - bash: echo $(MyVar) + - template: templates/c-api-cpu.yml parameters: RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} DoCompliance: ${{ parameters.DoCompliance }} DoEsrp: ${{ parameters.DoEsrp }} IsReleaseBuild: ${{ parameters.IsReleaseBuild }} - OrtNugetPackageId: 'Microsoft.ML.OnnxRuntime' + ${{ 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 }} + +- template: templates/ondevice-training-cpu-packaging-pipeline.yml + parameters: + RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} + DoCompliance: ${{ parameters.DoCompliance }} + DoEsrp: ${{ parameters.DoEsrp }} + IsReleaseBuild: ${{ parameters.IsReleaseBuild }} + OrtNugetPackageId: 'Microsoft.ML.OnnxRuntime.Training' + AdditionalBuildFlags: '--enable_training_apis' AdditionalWinBuildFlags: '--enable_onnx_tests --enable_wcos' BuildVariant: 'default' @@ -57,14 +142,14 @@ stages: timeoutInMinutes: 120 pool: 'Onnxruntime-Linux-GPU' variables: - CUDA_VERSION: '11.6' + CUDA_VERSION: '11.8' steps: - template: templates/set-version-number-variables-step.yml - template: templates/get-docker-image-steps.yml parameters: - Dockerfile: tools/ci_build/github/linux/docker/inference/x64/default/cpu/Dockerfile - Context: tools/ci_build/github/linux/docker/inference/x64/default/cpu - DockerBuildArgs: "--build-arg BUILD_UID=$( id -u ) --build-arg BASEIMAGE=nvidia/cuda:11.6.2-cudnn8-devel-centos7" + Dockerfile: tools/ci_build/github/linux/docker/inference/x64/default/gpu/Dockerfile + Context: tools/ci_build/github/linux/docker/inference/x64/default/gpu + DockerBuildArgs: "--build-arg BUILD_UID=$( id -u )" Repository: onnxruntimecuda11centosbuild - script: $(Build.SourcesDirectory)/tools/ci_build/github/linux/build_cuda_c_api_package.sh @@ -98,11 +183,13 @@ stages: artifactNameNoVersionString: 'onnxruntime-linux-x64-tensorrt' buildJava: true buildJavaOption: '--build_java' + buildNodejs: true + buildNodejsOption: '--build_nodejs' #CUDA without tensorrt - template: templates/win-ci.yml parameters: - ort_build_pool_name: 'onnxruntime-gpu-winbuild-T4' + ort_build_pool_name: 'onnxruntime-Win2022-GPU-T4' DoCompliance: ${{ parameters.DoCompliance }} DoEsrp: ${{ parameters.DoEsrp }} stage_name_suffix: gpu @@ -110,7 +197,7 @@ stages: buildArch: x64 msbuildPlatform: x64 packageName: x64-cuda - buildparameter: --use_cuda --cuda_version=11.8 --cuda_home="C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8" --enable_onnx_tests --enable_wcos --build_java --cmake_extra_defines "CMAKE_CUDA_ARCHITECTURES=52;60;61;70;75;80" + buildparameter: --use_cuda --cuda_version=11.8 --cuda_home=$(Agent.TempDirectory)\v11.8 --enable_onnx_tests --enable_wcos --build_java --cmake_extra_defines "CMAKE_CUDA_ARCHITECTURES=60;61;70;75;80" ${{parameters.AdditionalBuildFlag}} runTests: ${{ parameters.RunOnnxRuntimeTests }} buildJava: true java_artifact_id: onnxruntime_gpu @@ -118,7 +205,7 @@ stages: # CUDA with Tensorrt - template: templates/win-ci.yml parameters: - ort_build_pool_name: 'onnxruntime-gpu-tensorrt8-winbuild-t4' + ort_build_pool_name: 'onnxruntime-Win2022-GPU-T4' DoCompliance: ${{ parameters.DoCompliance }} DoEsrp: ${{ parameters.DoEsrp }} stage_name_suffix: tensorrt @@ -126,12 +213,78 @@ stages: buildArch: x64 msbuildPlatform: x64 packageName: x64-tensorrt - buildparameter: --use_tensorrt --use_tensorrt_builtin_parser --tensorrt_home="C:\local\TensorRT-8.6.0.12.Windows10.x86_64.cuda-11.8" --cuda_version=11.6 --cuda_home="C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.6" --enable_onnx_tests --enable_wcos --build_java --cmake_extra_defines "CMAKE_CUDA_ARCHITECTURES=52;60;61;70;75;80" + buildparameter: --use_tensorrt --tensorrt_home="C:\local\TensorRT-8.6.1.6.Windows10.x86_64.cuda-11.8" --cuda_version=11.8 --cuda_home="C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8" --enable_onnx_tests --enable_wcos --build_java --cmake_extra_defines "CMAKE_CUDA_ARCHITECTURES=60;61;70;75;80" runTests: ${{ parameters.RunOnnxRuntimeTests }} buildJava: true java_artifact_id: onnxruntime_gpu UseIncreasedTimeoutForTests: ${{ parameters.UseIncreasedTimeoutForTests }} +# ROCm +- stage: Linux_C_API_Packaging_ROCm_x64 + dependsOn: [] + jobs: + - job: + workspace: + clean: all + timeoutInMinutes: 120 + pool: onnxruntime-Ubuntu2004-AMD-CPU + variables: + RocmVersion: '5.6' + 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) + --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) + + - 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: Jar_Packaging_GPU dependsOn: - Linux_C_API_Packaging_GPU_x64 @@ -143,7 +296,7 @@ stages: - job: workspace: clean: all - pool: 'Win-CPU-2021' + pool: 'onnxruntime-Win-CPU-2022' steps: @@ -151,26 +304,29 @@ stages: submodules: false - template: templates/set-version-number-variables-step.yml - - task: DownloadPipelineArtifact@2 - displayName: 'Download Pipeline Artifact - Win x64' - inputs: - buildType: 'current' - artifactName: 'drop-onnxruntime-java-win-x64-tensorrt' - targetPath: '$(Build.BinariesDirectory)\java-artifact\onnxruntime-java-win-x64' + - template: templates/flex-downloadPipelineArtifact.yml + parameters: + StepName: 'Download Pipeline Artifact - Win x64' + ArtifactName: 'drop-onnxruntime-java-win-x64-tensorrt' + TargetPath: '$(Build.BinariesDirectory)\java-artifact\onnxruntime-java-win-x64' + SpecificArtifact: ${{ parameters.specificArtifact }} + BuildId: ${{ parameters.BuildId }} - - task: DownloadPipelineArtifact@2 - displayName: 'Download Pipeline Artifact - Linux x64' - inputs: - buildType: 'current' + - template: templates/flex-downloadPipelineArtifact.yml + parameters: + stepName: 'Download Pipeline Artifact - Linux x64' artifactName: 'drop-onnxruntime-java-linux-x64-cuda' targetPath: '$(Build.BinariesDirectory)\java-artifact\onnxruntime-java-linux-x64' + SpecificArtifact: ${{ parameters.specificArtifact }} + BuildId: ${{ parameters.BuildId }} - - task: DownloadPipelineArtifact@2 - displayName: 'Download Pipeline Artifact - Linux x64' - inputs: - buildType: 'current' - artifactName: 'drop-onnxruntime-java-linux-x64-tensorrt' + - template: templates/flex-downloadPipelineArtifact.yml + parameters: + StepName: 'Download Pipeline Artifact - Linux x64' + ArtifactName: 'drop-onnxruntime-java-linux-x64-tensorrt' targetPath: '$(Build.BinariesDirectory)\java-artifact\onnxruntime-java-linux-x64-tensorrt' + SpecificArtifact: ${{ parameters.specificArtifact }} + BuildId: ${{ parameters.BuildId }} - task: PowerShell@2 displayName: 'PowerShell Script' @@ -208,7 +364,7 @@ stages: - job: workspace: clean: all - pool: 'onnxruntime-gpu-winbuild-t4' + pool: 'onnxruntime-Win2022-GPU-T4' timeoutInMinutes: 60 variables: - name: runCodesignValidationInjection @@ -268,19 +424,32 @@ stages: - checkout: self submodules: false - template: templates/set-version-number-variables-step.yml - - task: DownloadPipelineArtifact@2 - displayName: 'Download Final Jar' - inputs: - buildType: 'current' - artifactName: 'onnxruntime-java-gpu' - targetPath: '$(Build.BinariesDirectory)/final-jar' - - task: Bash@3 + - template: templates/flex-downloadPipelineArtifact.yml + parameters: + StepName: 'Download Final Jar' + ArtifactName: onnxruntime-java-gpu + TargetPath: '$(Build.BinariesDirectory)/final-jar' + SpecificArtifact: ${{ parameters.specificArtifact }} + BuildId: ${{ parameters.BuildId }} + + - template: templates/get-docker-image-steps.yml + parameters: + Dockerfile: tools/ci_build/github/linux/docker/Dockerfile.package_ubi8_cuda11_8_tensorrt8_6 + Context: tools/ci_build/github/linux/docker/ + DockerBuildArgs: "--build-arg BUILD_UID=$( id -u )" + Repository: onnxruntimeubi8packagestest + UpdateDepsTxt: false + + - bash: | + docker run --rm \ + --gpus all \ + --volume $(Build.SourcesDirectory):/onnxruntime_src \ + --volume $(Build.BinariesDirectory):/build \ + --volume /data/models:/build/models:ro \ + onnxruntimeubi8packagestest \ + /bin/bash /onnxruntime_src/tools/ci_build/github/linux/java_linux_final_test.sh -r /build -v $(OnnxRuntimeVersion) displayName: 'Test' - inputs: - targetType: filePath - filePath: 'tools/ci_build/github/linux/java_linux_final_test.sh' - arguments: '-r $(Build.BinariesDirectory) -v $(OnnxRuntimeVersion)' - template: templates/component-governance-component-detection-steps.yml parameters: @@ -319,13 +488,13 @@ stages: Steps: - script: | tools/ci_build/get_docker_image.py \ - --dockerfile tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_cuda11_8_tensorrt8_6 \ + --dockerfile tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda11_8_tensorrt8_6 \ --context tools/ci_build/github/linux/docker \ - --docker-build-args "--network=host --build-arg POLICY=manylinux2014 --build-arg PLATFORM=x86_64 --build-arg DEVTOOLSET_ROOTPATH=/opt/rh/devtoolset-11/root --build-arg PREPEND_PATH=/opt/rh/devtoolset-11/root/usr/bin: --build-arg LD_LIBRARY_PATH_ARG=/opt/rh/devtoolset-11/root/usr/lib64:/opt/rh/devtoolset-11/root/usr/lib:/opt/rh/devtoolset-11/root/usr/lib64/dyninst:/opt/rh/devtoolset-11/root/usr/lib/dyninst:/usr/local/lib64 --build-arg BUILD_UID=$( id -u )" \ + --docker-build-args "--network=host --build-arg POLICY=manylinux_2_28 --build-arg PLATFORM=x86_64 --build-arg PREPEND_PATH=/usr/local/cuda/bin --build-arg LD_LIBRARY_PATH_ARG=/usr/local/lib64 --build-arg DEVTOOLSET_ROOTPATH=/usr --build-arg BUILD_UID=$( id -u ) --build-arg BUILD_UID=$( id -u )" \ --container-registry onnxruntimebuildcache \ --multiple_repos \ --repository onnxruntimecuda118xtrt86build - displayName: "Get onnxruntimecuda118xtrt86build image for tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_cuda11_8_tensorrt8_6" + displayName: "Get onnxruntimecuda118xtrt86build image for tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda11_8_tensorrt8_6" workingDirectory: $(Build.SourcesDirectory)/onnxruntime ContainerRegistry: onnxruntimebuildcache @@ -376,7 +545,7 @@ stages: displayName: 'Test C API application for GPU package' inputs: script: | - docker run --gpus all -e CC=/opt/rh/devtoolset-11/root/usr/bin/cc -e CXX=/opt/rh/devtoolset-11/root/usr/bin/c++ -e CFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all" -e CXXFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all" -e NVIDIA_VISIBLE_DEVICES=all --rm --volume $(Build.SourcesDirectory):/src_dir \ + docker run --gpus all -e CFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all" -e CXXFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all" -e NVIDIA_VISIBLE_DEVICES=all --rm --volume $(Build.SourcesDirectory):/src_dir \ --volume $(Build.ArtifactStagingDirectory):/artifact_src -e NIGHTLY_BUILD onnxruntimecuda118xtrt86build \ /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)' @@ -395,7 +564,7 @@ stages: - job: workspace: clean: all - pool: 'onnxruntime-gpu-tensorrt8-winbuild-t4' + pool: 'onnxruntime-Win2022-GPU-T4' steps: - checkout: self # due to checkout multiple repos, the root directory is $(Build.SourcesDirectory)/onnxruntime @@ -474,6 +643,7 @@ stages: - stage: NuGet_Packaging_GPU dependsOn: + - Setup - Windows_Packaging_gpu - Windows_Packaging_tensorrt - Linux_C_API_Packaging_GPU_x64 @@ -488,6 +658,7 @@ stages: pool: 'Azure-Pipelines-EO-Windows2022-aiinfra' variables: breakCodesignValidationInjection: ${{ parameters.DoEsrp }} + ReleaseVersionSuffix: $[stageDependencies.Setup.Set_Variables.outputs['Set_Release_Version_Suffix.ReleaseVersionSuffix']] steps: - checkout: self @@ -564,7 +735,7 @@ stages: # # 'Any CPU' is the default (first 'mixed' platform specified in the csproj) so this should be fine. script: | - dotnet build .\src\Microsoft.ML.OnnxRuntime\Microsoft.ML.OnnxRuntime.csproj -p:SelectedTargets=Net6 -p:Configuration=RelWithDebInfo -p:OnnxRuntimeBuildDirectory="$(Build.BinariesDirectory)" -p:OrtPackageId="Microsoft.ML.OnnxRuntime.Gpu" -p:IsReleaseBuild=${{ parameters.IsReleaseBuild }} + dotnet build .\src\Microsoft.ML.OnnxRuntime\Microsoft.ML.OnnxRuntime.csproj -p:SelectedTargets=Net6 -p:Configuration=RelWithDebInfo -p:OnnxRuntimeBuildDirectory="$(Build.BinariesDirectory)" -p:OrtPackageId="Microsoft.ML.OnnxRuntime.Gpu" -p:IsReleaseBuild=${{ parameters.IsReleaseBuild }} -p:ReleaseVersionSuffix=$(ReleaseVersionSuffix) workingDirectory: '$(Build.SourcesDirectory)\csharp' - task: MSBuild@1 @@ -582,7 +753,7 @@ stages: solution: '$(Build.SourcesDirectory)\csharp\OnnxRuntime.CSharp.sln' configuration: RelWithDebInfo platform: 'Any CPU' - msbuildArguments: '-p:SelectedTargets=PreNet6 -p:OnnxRuntimeBuildDirectory="$(Build.BinariesDirectory)" -p:OrtPackageId="Microsoft.ML.OnnxRuntime.Gpu" -p:IsReleaseBuild=${{ parameters.IsReleaseBuild }}' + msbuildArguments: '-p:SelectedTargets=PreNet6 -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 @@ -606,7 +777,7 @@ stages: 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 }}' + msbuildArguments: '-t:CreatePackage -p:OnnxRuntimeBuildDirectory="$(Build.BinariesDirectory)" -p:OrtPackageId=Microsoft.ML.OnnxRuntime.Gpu -p:IsReleaseBuild=${{ parameters.IsReleaseBuild }} -p:ReleaseVersionSuffix=$(ReleaseVersionSuffix)' workingDirectory: '$(Build.SourcesDirectory)\csharp' - task: BatchScript@1 @@ -682,26 +853,259 @@ stages: displayName: 'Clean Agent Directories' condition: always() +- stage: NuGet_Packaging_ROCm + dependsOn: + - Setup + - Linux_C_API_Packaging_ROCm_x64 + condition: succeeded() + jobs: + - job: + workspace: + clean: all + # we need to use the 2022 pool to create the nuget package with both pre-net6+Xamarin and net6 targets. + # VS2019 has no support for net6 and we need to use msbuild (from the VS install) to do the packing + pool: 'Azure-Pipelines-EO-Windows2022-aiinfra' + variables: + breakCodesignValidationInjection: ${{ parameters.DoEsrp }} + ReleaseVersionSuffix: $[stageDependencies.Setup.Set_Variables.outputs['Set_Release_Version_Suffix.ReleaseVersionSuffix']] + + 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.2.1 + inputs: + versionSpec: 6.2.1 + + - task: PowerShell@2 + displayName: Build .NET 6 targets using dotnet + inputs: + targetType: 'inline' + # we don't specify 'Any CPU' as the platform here because if we do it gets added to the output path + # e.g. csharp\src\Microsoft.ML.OnnxRuntime\bin\Any CPU\RelWithDebInfo\net6.0-ios\ + # which is inconsistent with the msbuild output path for the pre-.net6 targets + # e.g. csharp\src\Microsoft.ML.OnnxRuntime\bin\RelWithDebInfo\monoandroid11.0 + # and makes it harder to do the packing + # + # 'Any CPU' is the default (first 'mixed' platform specified in the csproj) so this should be fine. + script: | + dotnet build .\src\Microsoft.ML.OnnxRuntime\Microsoft.ML.OnnxRuntime.csproj ` + -p:SelectedTargets=Net6 ` + /p:Net6Targets=net6.0 ` + -p:Configuration=RelWithDebInfo ` + -p:OnnxRuntimeBuildDirectory="$(Build.BinariesDirectory)" ` + -p:OrtPackageId="Microsoft.ML.OnnxRuntime.ROCm" ` + -p:IsReleaseBuild=${{ parameters.IsReleaseBuild }} ` + -p:ReleaseVersionSuffix=$(ReleaseVersionSuffix) + workingDirectory: '$(Build.SourcesDirectory)\csharp' + + - task: MSBuild@1 + displayName: 'Restore NuGet Packages and create project.assets.json for pre-.net6 targets' + inputs: + solution: '$(Build.SourcesDirectory)\csharp\OnnxRuntime.CSharp.sln' + platform: 'Any CPU' + configuration: RelWithDebInfo + msbuildArguments: '-t:restore -p:SelectedTargets=PreNet6 -p:OrtPackageId="Microsoft.ML.OnnxRuntime.ROCm"' + workingDirectory: '$(Build.SourcesDirectory)\csharp' + + - task: MSBuild@1 + displayName: 'Build C# for pre-.net6 targets' + inputs: + solution: '$(Build.SourcesDirectory)\csharp\OnnxRuntime.CSharp.sln' + configuration: RelWithDebInfo + platform: 'Any CPU' + msbuildArguments: > + -p:SelectedTargets=PreNet6 + -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: MSBuild@1 + displayName: Update projects.assets.json with combined list of all target frameworks + inputs: + solution: '$(Build.SourcesDirectory)\csharp\src\Microsoft.ML.OnnxRuntime\Microsoft.ML.OnnxRuntime.csproj' + platform: 'Any CPU' + configuration: RelWithDebInfo + msbuildArguments: '-t:restore -p:SelectedTargets=All -p:OrtPackageId=Microsoft.ML.OnnxRuntime.ROCm' + workingDirectory: '$(Build.SourcesDirectory)\csharp' + + - 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)' + 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' + + - task: RoslynAnalyzers@2 + displayName: 'Run Roslyn Analyzers' + inputs: + userProvideBuildInfo: msBuildInfo + msBuildCommandline: > + "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\msbuild.exe" + $(Build.SourcesDirectory)\csharp\OnnxRuntime.CSharp.sln + -p:configuration="RelWithDebInfo" + -p:Platform="Any CPU" + -p:OnnxRuntimeBuildDirectory="$(Build.BinariesDirectory)" + -p:OrtPackageId=Microsoft.ML.OnnxRuntime.ROCm + -p:IsLinuxBuild=true + -p:IsWindowsBuild=false + -p:IsMacOSBuild=false + condition: and(succeeded(), eq('${{ parameters.DoCompliance }}', true)) + + - template: templates/component-governance-component-detection-steps.yml + parameters : + condition : 'succeeded' + + - task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3 + displayName: 'Clean Agent Directories' + condition: always() + - template: nuget/templates/test_win.yml parameters: - AgentPool : 'onnxruntime-gpu-tensorrt8-winbuild-t4' + AgentPool : 'onnxruntime-Win2022-GPU-T4' NugetPackageName : 'Microsoft.ML.OnnxRuntime.Gpu' ArtifactSuffix: 'GPU' + StageSuffix: 'GPU' Skipx86Tests: 'true' - template: nuget/templates/test_linux.yml parameters: AgentPool : Onnxruntime-Linux-GPU ArtifactSuffix: 'GPU' + StageSuffix: 'GPU' NugetPackageName : 'Microsoft.ML.OnnxRuntime.Gpu' + SpecificArtifact: ${{ parameters.specificArtifact }} + BuildId: ${{ parameters.BuildId }} -- template: nuget/templates/dml-vs-2019.yml +- 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 }} + +- template: nuget/templates/dml-vs-2022.yml parameters: - AgentPool : 'aiinfra-dml-winbuild' + AgentPool : 'onnxruntime-Win2022-GPU-dml-A10' 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 --use_winml --cmake_generator "Visual Studio 16 2019" + BuildCommand: --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --build_shared_lib --enable_onnx_tests --enable_wcos --use_telemetry --use_dml --use_winml --build_nodejs --cmake_generator "Visual Studio 17 2022" BuildArch: 'x64' msbuildArchitecture: 'amd64' EnvSetupScript: 'setup_env.bat' @@ -718,13 +1122,13 @@ stages: mkdir $(Build.ArtifactStagingDirectory)\testdata copy $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\custom_op_library.* $(Build.ArtifactStagingDirectory)\testdata -- template: nuget/templates/dml-vs-2019.yml +- template: nuget/templates/dml-vs-2022.yml parameters: - AgentPool : 'aiinfra-dml-winbuild' + AgentPool : 'onnxruntime-Win2022-GPU-dml-A10' 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 --use_winml --cmake_generator "Visual Studio 16 2019" + BuildCommand: --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --build_shared_lib --enable_onnx_tests --enable_wcos --use_telemetry --use_dml --use_winml --cmake_generator "Visual Studio 17 2022" BuildArch: 'x86' EnvSetupScript: 'setup_env_x86.bat' sln_platform: 'Win32' @@ -741,13 +1145,13 @@ stages: mkdir $(Build.ArtifactStagingDirectory)\testdata copy $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\custom_op_library.* $(Build.ArtifactStagingDirectory)\testdata -- template: nuget/templates/dml-vs-2019.yml +- template: nuget/templates/dml-vs-2022.yml parameters: - AgentPool : 'Win-CPU-2021' + AgentPool : 'onnxruntime-Win2022-GPU-dml-A10' 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 --use_winml --cmake_generator "Visual Studio 16 2019" + BuildCommand: --build_dir $(Build.BinariesDirectory) --arm64 --skip_submodule_sync --build_shared_lib --enable_onnx_tests --enable_wcos --use_telemetry --use_dml --use_winml --build_nodejs --cmake_generator "Visual Studio 17 2022" BuildArch: 'x64' EnvSetupScript: 'setup_env.bat' sln_platform: 'arm64' @@ -764,13 +1168,13 @@ stages: mkdir $(Build.ArtifactStagingDirectory)\testdata copy $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\custom_op_library.* $(Build.ArtifactStagingDirectory)\testdata -- template: nuget/templates/dml-vs-2019.yml +- template: nuget/templates/dml-vs-2022.yml parameters: - AgentPool : 'Win-CPU-2021' + AgentPool : 'onnxruntime-Win-CPU-2022' IsReleaseBuild: ${{ parameters.IsReleaseBuild }} ArtifactName: 'drop-win-dml-arm-zip' StageName: 'Windows_CI_GPU_DML_Dev_arm' - BuildCommand: --build_dir $(Build.BinariesDirectory) --arm --skip_submodule_sync --build_shared_lib --enable_onnx_tests --enable_wcos --use_telemetry --use_dml --use_winml --cmake_generator "Visual Studio 16 2019" + BuildCommand: --build_dir $(Build.BinariesDirectory) --arm --skip_submodule_sync --build_shared_lib --enable_onnx_tests --enable_wcos --use_telemetry --use_dml --use_winml --cmake_generator "Visual Studio 17 2022" BuildArch: 'x64' EnvSetupScript: 'setup_env.bat' sln_platform: 'arm' @@ -779,6 +1183,7 @@ stages: DoCompliance: ${{ parameters.DoCompliance }} DoEsrp: ${{ parameters.DoEsrp }} RunTests: 'false' + BuildNodejs: 'false' NuPackScript: | msbuild $(Build.SourcesDirectory)\csharp\OnnxRuntime.CSharp.proj /p:Configuration=RelWithDebInfo /p:TargetArchitecture=arm /t:CreatePackage /p:OrtPackageId=Microsoft.ML.OnnxRuntime.DirectML /p:IsReleaseBuild=${{ parameters.IsReleaseBuild }} cd $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\ @@ -798,7 +1203,7 @@ stages: - job: workspace: clean: all - pool: 'onnxruntime-gpu-winbuild-t4' + pool: 'onnxruntime-Win2022-GPU-T4' steps: @@ -839,31 +1244,31 @@ stages: 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 - + unzip win-dml-arm.zip -d win-arm mkdir %%~ni\runtimes\win-arm mkdir %%~ni\runtimes\win-arm\native - + move win-arm\runtimes\win-arm\native\onnxruntime.dll %%~ni\runtimes\win-arm\native\onnxruntime.dll move win-arm\runtimes\win-arm\native\onnxruntime.lib %%~ni\runtimes\win-arm\native\onnxruntime.lib move win-arm\runtimes\win-arm\native\onnxruntime.pdb %%~ni\runtimes\win-arm\native\onnxruntime.pdb - + pushd %%~ni zip -r ..\%%~ni.zip . popd diff --git a/tools/ci_build/github/azure-pipelines/linux-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/linux-ci-pipeline.yml index 98d1bdfdf585a..33fc9d94bac09 100644 --- a/tools/ci_build/github/azure-pipelines/linux-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/linux-ci-pipeline.yml @@ -1,10 +1,39 @@ +##### start trigger Don't edit it manually, Please do edit 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 #### + resources: repositories: - repository: manylinux # The name used to reference this repository in the checkout step type: Github endpoint: Microsoft name: pypa/manylinux - ref: aead4d751c2101e23336aa73f2380df83e7a13f3 + ref: 5eda9aded5462201e6310105728d33016e637ea7 stages: - stage: x64 dependsOn: [] @@ -17,7 +46,7 @@ stages: skipComponentGovernanceDetection: true ORT_CACHE_DIR: $(Agent.TempDirectory)/ort_ccache TODAY: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)] - pool: onnxruntime-Linux-CPU-2019 + pool: onnxruntime-Ubuntu2004-AMD-CPU steps: - task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3 displayName: 'Clean Agent Directories' @@ -38,9 +67,9 @@ stages: - template: templates/get-docker-image-steps.yml parameters: - Dockerfile: tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_cpu - Context: tools/ci_build/github/linux/docker - DockerBuildArgs: "--build-arg BUILD_UID=$( id -u )" + 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 ) --build-arg BASEIMAGE=registry.access.redhat.com/ubi8/ubi" Repository: onnxruntimecpubuild - template: templates/linux-build-step-with-cache.yml @@ -56,7 +85,6 @@ stages: inputs: script: | mkdir -p $HOME/.onnx - mkdir -p $(Pipeline.Workspace)/ccache docker run --rm \ --volume /data/onnx:/data/onnx:ro \ --volume $(Build.SourcesDirectory):/onnxruntime_src \ @@ -72,95 +100,80 @@ stages: set -ex; \ ccache -s; \ /opt/python/cp38-cp38/bin/python3 /onnxruntime_src/tools/ci_build/build.py \ - --build_dir /build --cmake_generator Ninja \ + --build_dir /build --cmake_generator 'Ninja' \ --config Debug Release \ --skip_submodule_sync \ --build_shared_lib \ --parallel \ --build_wheel \ + --build_csharp \ --enable_onnx_tests \ --enable_transformers_tool_test \ --use_cache \ - --build_java --build_nodejs --update --build --cmake_extra_defines onnxruntime_BUILD_BENCHMARKS=ON; \ + --update --build --cmake_extra_defines onnxruntime_BUILD_BENCHMARKS=ON; \ ccache -sv; \ ccache -z" workingDirectory: $(Build.SourcesDirectory) - - task: CmdLine@2 - displayName: 'Install python deps and run java tests' - inputs: - script: | - set -e -x - python3 -m pip uninstall -y ort-nightly-gpu ort-nightly onnxruntime onnxruntime-gpu onnxruntime-training onnxruntime-directml ort-nightly-directml onnx -qq - cp $(Build.SourcesDirectory)/tools/ci_build/github/linux/docker/scripts/manylinux/requirements.txt $(Build.BinariesDirectory)/requirements.txt - # Test ORT with the latest ONNX release. - sed -i "s/git+http:\/\/github\.com\/onnx\/onnx.*/onnx/" $(Build.BinariesDirectory)/requirements.txt - python3 -m pip install -r $(Build.BinariesDirectory)/requirements.txt - mkdir $(Build.BinariesDirectory)/requirements_torch_cpu/ - cp $(Build.SourcesDirectory)/tools/ci_build/github/linux/docker/scripts/training/ortmodule/stage1/requirements_torch_cpu/requirements.txt $(Build.BinariesDirectory)/requirements_torch_cpu/requirements.txt - python3 -m pip install -r $(Build.BinariesDirectory)/requirements_torch_cpu/requirements.txt - cd $(Build.SourcesDirectory)/java - $(Build.SourcesDirectory)/java/gradlew "cmakeCheck" "-DcmakeBuildDir=$(Build.BinariesDirectory)/Release" - - - task: CmdLine@2 - displayName: 'Install Release python package' - inputs: - script: | - rm -rf $(Build.BinariesDirectory)/Release/onnxruntime $(Build.BinariesDirectory)/Release/pybind11 - python3 -m pip install $(Build.BinariesDirectory)/Release/dist/*.whl - - - task: PythonScript@0 - displayName: 'Run Release unit tests' - inputs: - scriptPath: $(Build.SourcesDirectory)/tools/ci_build/build.py - workingDirectory: $(Build.BinariesDirectory)/Release - arguments: >- - --build_dir $(Build.BinariesDirectory) - --cmake_generator Ninja - --config Release - --test - --skip_submodule_sync - --build_shared_lib - --parallel - --build_wheel - --enable_onnx_tests - --enable_transformers_tool_test - --build_nodejs - --ctest_path "" + - script: | + ln -s /data/models $(Build.BinariesDirectory)/models + displayName: link model dir - - task: CmdLine@2 - displayName: 'Install Debug python package' - inputs: - script: | - set -e -x - rm -rf $(Build.BinariesDirectory)/Debug/onnxruntime $(Build.BinariesDirectory)/Debug/pybind11 - python3 -m pip uninstall -y ort-nightly-gpu ort-nightly onnxruntime onnxruntime-gpu onnxruntime-training onnxruntime-directml ort-nightly-directml -qq - python3 -m pip install $(Build.BinariesDirectory)/Debug/dist/*.whl + - bash: | + 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 \ + -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; \ + dotnet test /onnxruntime_src/csharp/OnnxRuntime.DesktopOnly.CSharp.sln -f net6.0 --no-build -l \"console;verbosity=normal\"; \ + popd + " + displayName: 'Dotnet build C# sln and Test' - - task: PythonScript@0 - displayName: 'Run Debug unit tests' - inputs: - scriptPath: $(Build.SourcesDirectory)/tools/ci_build/build.py - workingDirectory: $(Build.BinariesDirectory)/Debug - arguments: >- - --build_dir $(Build.BinariesDirectory) - --cmake_generator Ninja - --config Debug - --test - --skip_submodule_sync - --build_shared_lib - --parallel - --build_wheel - --enable_onnx_tests - --enable_transformers_tool_test - --build_nodejs - --ctest_path "" + - bash: | + 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 \ + -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' - - task: PythonScript@0 - displayName: 'Symbolic shape infer' - inputs: - scriptPath: $(Build.BinariesDirectory)/Release/onnxruntime_test_python_symbolic_shape_infer.py - workingDirectory: $(Build.BinariesDirectory)/Release + - bash: | + 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 \ + -e ALLOW_RELEASED_ONNX_OPSET_ONLY=0 \ + -e NIGHTLY_BUILD \ + -e BUILD_BUILDNUMBER \ + onnxruntimecpubuild \ + /bin/bash /onnxruntime_src/tools/scripts/python_test.sh /onnxruntime_src /build Debug + displayName: 'Run Debug tests' - task: PublishTestResults@2 displayName: 'Publish unit test results' @@ -170,7 +183,6 @@ stages: testRunTitle: 'Unit Test Run' condition: succeededOrFailed() - - stage: arm64_build dependsOn: [] jobs: @@ -178,17 +190,21 @@ stages: parameters: arch: 'aarch64' machine_pool: 'onnxruntime-linux-ARM64-CPU-2019' - base_image: 'arm64v8/centos:7' - devtoolset_rootpath: /opt/rh/devtoolset-10/root - ld_library_path_arg: /opt/rh/devtoolset-10/root/usr/lib64:/opt/rh/devtoolset-10/root/usr/lib:/opt/rh/devtoolset-10/root/usr/lib64/dyninst:/opt/rh/devtoolset-10/root/usr/lib/dyninst:/usr/local/lib64 - prepend_path: '/opt/rh/devtoolset-10/root/usr/bin:' + base_image: 'arm64v8/almalinux:8' + devtoolset_rootpath: /opt/rh/gcc-toolset-12/root + 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 + prepend_path: '/opt/rh/gcc-toolset-12/root/usr/bin:' with_cache: true + cmake_build_type: Release - stage: arm64_test dependsOn: ['arm64_build'] jobs: - - template: templates/py-packaging-linux-test.yml + - template: templates/py-packaging-linux-test-cpu.yml parameters: arch: 'aarch64' machine_pool: 'onnxruntime-linux-ARM64-CPU-2019' - device: 'CPU' + base_image: 'arm64v8/almalinux:8' + devtoolset_rootpath: /opt/rh/gcc-toolset-12/root + 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 + prepend_path: '/opt/rh/gcc-toolset-12/root/usr/bin:' diff --git a/tools/ci_build/github/azure-pipelines/linux-cpu-aten-pipeline.yml b/tools/ci_build/github/azure-pipelines/linux-cpu-aten-pipeline.yml index 5e715b9a61a90..2c5a69e216d14 100644 --- a/tools/ci_build/github/azure-pipelines/linux-cpu-aten-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/linux-cpu-aten-pipeline.yml @@ -1,10 +1,39 @@ +##### start trigger Don't edit it manually, Please do edit 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 #### + resources: repositories: - repository: manylinux type: Github endpoint: Microsoft name: pypa/manylinux - ref: aead4d751c2101e23336aa73f2380df83e7a13f3 + ref: 5eda9aded5462201e6310105728d33016e637ea7 jobs: - job: Linux_Build @@ -14,7 +43,7 @@ jobs: variables: CCACHE_DIR: $(Agent.TempDirectory)/ccache TODAY: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)] - pool: onnxruntime-Linux-CPU-2019 + pool: onnxruntime-Ubuntu2004-AMD-CPU steps: - task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3 displayName: 'Clean Agent Directories' diff --git a/tools/ci_build/github/azure-pipelines/linux-cpu-eager-pipeline.yml b/tools/ci_build/github/azure-pipelines/linux-cpu-eager-pipeline.yml index 0f9c863ac7b03..a5c08e95b7efc 100644 --- a/tools/ci_build/github/azure-pipelines/linux-cpu-eager-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/linux-cpu-eager-pipeline.yml @@ -1,10 +1,39 @@ +##### start trigger Don't edit it manually, Please do edit 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 #### + resources: repositories: - repository: manylinux type: Github endpoint: Microsoft name: pypa/manylinux - ref: aead4d751c2101e23336aa73f2380df83e7a13f3 + ref: 5eda9aded5462201e6310105728d33016e637ea7 jobs: # This pipeline builds the latest PyTorch commit from source @@ -22,7 +51,7 @@ jobs: timeoutInMinutes: 120 workspace: clean: all - pool: onnxruntime-Linux-CPU-2019 + pool: onnxruntime-Ubuntu2004-AMD-CPU steps: - checkout: self clean: true @@ -69,7 +98,8 @@ jobs: bash -c " export PYTHONPATH=/build/Release && \ /opt/python/cp39-cp39/bin/python3.9 -m pip install /build/Release/dist/*.whl && \ - /opt/python/cp39-cp39/bin/python3.9 /onnxruntime_src/orttraining/orttraining/test/python/orttraining_test_dort.py" + /opt/python/cp39-cp39/bin/python3.9 /onnxruntime_src/orttraining/orttraining/test/python/orttraining_test_dort.py && \ + cd /build/Release && /opt/python/cp39-cp39/bin/python3.9 /onnxruntime_src/orttraining/orttraining/test/python/orttraining_test_dort_custom_ops.py" workingDirectory: $(Build.SourcesDirectory) condition: succeededOrFailed() diff --git a/tools/ci_build/github/azure-pipelines/linux-cpu-minimal-build-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/linux-cpu-minimal-build-ci-pipeline.yml index 39c63ee386f91..3eb74f306951c 100644 --- a/tools/ci_build/github/azure-pipelines/linux-cpu-minimal-build-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/linux-cpu-minimal-build-ci-pipeline.yml @@ -20,21 +20,46 @@ # in an extended minimal build. # 7. Build extended minimal ORT with NNAPI, with exceptions/RTTI/ml_ops disabled, for Android(arm64-v8a), # this safe-guards the extended minimal build with NNAPI EP. - +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' resources: repositories: - repository: manylinux type: Github endpoint: Microsoft name: pypa/manylinux - ref: aead4d751c2101e23336aa73f2380df83e7a13f3 + ref: 5eda9aded5462201e6310105728d33016e637ea7 jobs: - job: Linux_CPU_Minimal_Build_E2E timeoutInMinutes: 120 workspace: clean: all - pool: onnxruntime-Linux-CPU-2019 + pool: onnxruntime-Linux-CPU-For-Android-CI variables: ORT_CACHE_DIR: $(Pipeline.Workspace)/ort_ccache TODAY: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)] @@ -51,7 +76,7 @@ jobs: - template: templates/get-docker-image-steps.yml parameters: - Dockerfile: tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_cpu + 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 @@ -222,10 +247,9 @@ jobs: --parallel \ --skip_tests \ --disable_ml_ops \ + --disable_types sparsetensor float8 optional \ --include_ops_by_config /home/onnxruntimedev/.test_data/include_no_operators.config \ - --cmake_extra_defines onnxruntime_DISABLE_SPARSE_TENSORS=ON \ - onnxruntime_DISABLE_OPTIONAL_TYPE=ON \ - onnxruntime_BUILD_UNIT_TESTS=OFF + --cmake_extra_defines onnxruntime_BUILD_UNIT_TESTS=OFF workingDirectory: $(Build.SourcesDirectory) - task: CmdLine@2 @@ -252,10 +276,9 @@ jobs: --disable_ml_ops \ --skip_tests \ --enable_reduced_operator_type_support \ + --disable_types sparsetensor optional float8 \ --include_ops_by_config /home/onnxruntimedev/.test_data/include_no_operators.config \ - --cmake_extra_defines onnxruntime_DISABLE_SPARSE_TENSORS=ON \ - onnxruntime_DISABLE_OPTIONAL_TYPE=ON \ - onnxruntime_BUILD_UNIT_TESTS=OFF + --cmake_extra_defines onnxruntime_BUILD_UNIT_TESTS=OFF workingDirectory: $(Build.SourcesDirectory) - task: CmdLine@2 @@ -282,10 +305,9 @@ jobs: --disable_ml_ops \ --skip_tests \ --enable_reduced_operator_type_support \ + --disable_types sparsetensor optional float8 \ --include_ops_by_config /home/onnxruntimedev/.test_data/include_no_operators.config \ - --cmake_extra_defines onnxruntime_DISABLE_SPARSE_TENSORS=ON \ - onnxruntime_DISABLE_OPTIONAL_TYPE=ON \ - onnxruntime_BUILD_UNIT_TESTS=OFF + --cmake_extra_defines onnxruntime_BUILD_UNIT_TESTS=OFF workingDirectory: $(Build.SourcesDirectory) - task: CmdLine@2 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 index ef1e3fb8f67d9..1c6d8bbfe7fbe 100644 --- a/tools/ci_build/github/azure-pipelines/linux-dnnl-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/linux-dnnl-ci-pipeline.yml @@ -1,10 +1,39 @@ +##### start trigger Don't edit it manually, Please do edit 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 #### + resources: repositories: - repository: manylinux type: Github endpoint: Microsoft name: pypa/manylinux - ref: aead4d751c2101e23336aa73f2380df83e7a13f3 + ref: 5eda9aded5462201e6310105728d33016e637ea7 jobs: - job: Linux_py_Wheels @@ -21,7 +50,7 @@ jobs: - template: templates/get-docker-image-steps.yml parameters: - Dockerfile: tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_cpu + 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 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 index 6234cf02f6e8f..981cbec4ef50f 100644 --- a/tools/ci_build/github/azure-pipelines/linux-gpu-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/linux-gpu-ci-pipeline.yml @@ -1,10 +1,42 @@ +##### start trigger Don't edit it manually, Please do edit 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 #### + resources: repositories: - repository: manylinux type: Github endpoint: Microsoft name: pypa/manylinux - ref: aead4d751c2101e23336aa73f2380df83e7a13f3 + ref: 5eda9aded5462201e6310105728d33016e637ea7 + +variables: + - template: templates/common-variables.yml jobs: - job: Linux_Build @@ -14,7 +46,7 @@ jobs: CCACHE_DIR: $(Pipeline.Workspace)/ccache workspace: clean: all - pool: onnxruntime-Linux-CPU-2019 + pool: onnxruntime-Ubuntu2004-AMD-CPU steps: - task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3 displayName: 'Clean Agent Directories' @@ -26,9 +58,9 @@ jobs: - template: templates/get-docker-image-steps.yml parameters: - Dockerfile: tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_cuda11 + Dockerfile: tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda11 Context: tools/ci_build/github/linux/docker - DockerBuildArgs: "--network=host --build-arg POLICY=manylinux2014 --build-arg PLATFORM=x86_64 --build-arg BASEIMAGE=nvidia/cuda:11.6.2-cudnn8-devel-centos7 --build-arg DEVTOOLSET_ROOTPATH=/opt/rh/devtoolset-11/root --build-arg PREPEND_PATH=/opt/rh/devtoolset-11/root/usr/bin: --build-arg LD_LIBRARY_PATH_ARG=/opt/rh/devtoolset-11/root/usr/lib64:/opt/rh/devtoolset-11/root/usr/lib:/opt/rh/devtoolset-11/root/usr/lib64/dyninst:/opt/rh/devtoolset-11/root/usr/lib/dyninst:/usr/local/lib64 --build-arg BUILD_UID=$( id -u )" + DockerBuildArgs: "--network=host --build-arg POLICY=manylinux_2_28 --build-arg PLATFORM=x86_64 --build-arg PREPEND_PATH=/usr/local/cuda/bin --build-arg LD_LIBRARY_PATH_ARG=/usr/local/lib64 --build-arg DEVTOOLSET_ROOTPATH=/usr --build-arg BUILD_UID=$( id -u )" Repository: onnxruntimecuda11build - task: Cache@2 @@ -50,7 +82,7 @@ jobs: inputs: script: | mkdir -p $HOME/.onnx - docker run -e CC=/opt/rh/devtoolset-11/root/usr/bin/cc -e CXX=/opt/rh/devtoolset-11/root/usr/bin/c++ -e CFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all" -e CXXFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all" --rm \ + docker run -e CFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all" -e CXXFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all" --rm \ --volume /data/onnx:/data/onnx:ro \ --volume $(Build.SourcesDirectory):/onnxruntime_src \ --volume $(Build.BinariesDirectory):/build \ @@ -73,11 +105,11 @@ jobs: --build_shared_lib \ --parallel \ --build_wheel \ - --enable_onnx_tests --use_cuda --cuda_version=11.6 --cuda_home=/usr/local/cuda-11.6 --cudnn_home=/usr/local/cuda-11.6 \ + --enable_onnx_tests --use_cuda --cuda_version=${{variables.common_cuda_version}} --cuda_home=/usr/local/cuda-${{variables.common_cuda_version}} --cudnn_home=/usr/local/cuda-${{variables.common_cuda_version}} \ --enable_cuda_profiling \ --enable_pybind --build_java \ --use_cache \ - --cmake_extra_defines CMAKE_CUDA_HOST_COMPILER=/opt/rh/devtoolset-11/root/usr/bin/cc CMAKE_CUDA_ARCHITECTURES=75; \ + --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=75; \ ccache -sv; \ ccache -z" workingDirectory: $(Build.SourcesDirectory) @@ -85,9 +117,9 @@ jobs: - task: CmdLine@2 inputs: script: | - rm -rf $(Build.BinariesDirectory)/Release/onnxruntime $(Build.BinariesDirectory)/Release/pybind11 $(Build.BinariesDirectory)/Release/_deps + rm -rf $(Build.BinariesDirectory)/Release/onnxruntime $(Build.BinariesDirectory)/Release/pybind11 rm -f $(Build.BinariesDirectory)/Release/models - rm -rf $(Build.BinariesDirectory)/Release/_deps + find $(Build.BinariesDirectory)/Release/_deps -mindepth 1 ! -regex '^$(Build.BinariesDirectory)/Release/_deps/onnx-src\(/.*\)?' -delete cd $(Build.BinariesDirectory)/Release find -executable -type f > $(Build.BinariesDirectory)/Release/perms.txt @@ -116,34 +148,41 @@ jobs: artifactName: 'drop-linux' targetPath: '$(Build.BinariesDirectory)/Release' + - checkout: self + clean: true + submodules: none + + - template: templates/get-docker-image-steps.yml + parameters: + Dockerfile: tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda11 + Context: tools/ci_build/github/linux/docker + DockerBuildArgs: "--network=host --build-arg POLICY=manylinux_2_28 --build-arg PLATFORM=x86_64 --build-arg PREPEND_PATH=/usr/local/cuda/bin --build-arg LD_LIBRARY_PATH_ARG=/usr/local/lib64 --build-arg DEVTOOLSET_ROOTPATH=/usr --build-arg BUILD_UID=$( id -u )" + Repository: onnxruntimecuda11build + - task: CmdLine@2 inputs: script: | - set -e -x - # We assume the machine doesn't have gcc and python development header files - sudo rm -f /build /onnxruntime_src - sudo ln -s $(Build.SourcesDirectory) /onnxruntime_src - python3 -m pip uninstall -y ort-nightly-gpu ort-nightly onnxruntime onnxruntime-gpu onnxruntime-training onnxruntime-directml ort-nightly-directml onnx -qq - cp $(Build.SourcesDirectory)/tools/ci_build/github/linux/docker/scripts/manylinux/requirements.txt $(Build.BinariesDirectory)/requirements.txt - # Test ORT with the latest ONNX release. - sed -i "s/git+http:\/\/github\.com\/onnx\/onnx.*/onnx/" $(Build.BinariesDirectory)/requirements.txt - python3 -m pip install -r $(Build.BinariesDirectory)/requirements.txt - python3 -m pip install $(Build.BinariesDirectory)/Release/dist/*.whl - ln -s /data/models $(Build.BinariesDirectory) - cd $(Build.BinariesDirectory)/Release - # Restore file permissions - xargs -a $(Build.BinariesDirectory)/Release/perms.txt chmod a+x - cd $(Build.SourcesDirectory)/java - $(Build.SourcesDirectory)/java/gradlew "cmakeCheck" "-DcmakeBuildDir=$(Build.BinariesDirectory)/Release" "-DUSE_CUDA=1" - cd /tmp - python3 $(Build.SourcesDirectory)/tools/ci_build/build.py \ - --build_dir $(Build.BinariesDirectory) --cmake_generator Ninja \ - --config Release --test \ - --skip_submodule_sync \ - --build_shared_lib \ - --parallel \ - --build_wheel \ - --enable_onnx_tests --use_cuda --cuda_version=11.6 --cuda_home=/usr/local/cuda-11.6 --cudnn_home=/usr/local/cuda-11.6 \ - --enable_pybind --build_java --ctest_path '' + 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 \ + onnxruntimecuda11build \ + /bin/bash -c " + set -ex; \ + cp /onnxruntime_src/tools/ci_build/github/linux/docker/scripts/manylinux/requirements.txt /tmp/requirements.txt; \ + ln -s /opt/python/cp38-cp38/bin/python3 /tmp/python3; \ + /tmp/python3 -m pip install -r /tmp/requirements.txt; \ + /tmp/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; \ + /tmp/python3 /onnxruntime_src/tools/ci_build/build.py \ + --build_dir /build --config Release --test --skip_submodule_sync --build_shared_lib --parallel --build_wheel --enable_onnx_tests \ + --use_cuda --cuda_version=${{variables.common_cuda_version}} --cuda_home=/usr/local/cuda --cudnn_home=/usr/local/cuda \ + --enable_pybind --build_java --ctest_path '' " - 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 index 96ca5a693bc3a..9450395f3cf79 100644 --- 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 @@ -1,10 +1,39 @@ +##### start trigger Don't edit it manually, Please do edit 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 #### + resources: repositories: - repository: manylinux type: Github endpoint: Microsoft name: pypa/manylinux - ref: aead4d751c2101e23336aa73f2380df83e7a13f3 + ref: 5eda9aded5462201e6310105728d33016e637ea7 jobs: - job: Linux_Build @@ -12,53 +41,66 @@ jobs: 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 + pool: onnxruntime-tensorrt-linuxbuild-T4 steps: + - task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3 + displayName: 'Clean Agent Directories' + condition: always() + - checkout: self clean: true submodules: none - template: templates/get-docker-image-steps.yml parameters: - Dockerfile: tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_cuda11_8_tensorrt8_6 + Dockerfile: tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda11_8_tensorrt8_6 Context: tools/ci_build/github/linux/docker - DockerBuildArgs: "--network=host --build-arg POLICY=manylinux2014 --build-arg PLATFORM=x86_64 --build-arg DEVTOOLSET_ROOTPATH=/opt/rh/devtoolset-11/root --build-arg PREPEND_PATH=/opt/rh/devtoolset-11/root/usr/bin: --build-arg LD_LIBRARY_PATH_ARG=/opt/rh/devtoolset-11/root/usr/lib64:/opt/rh/devtoolset-11/root/usr/lib:/opt/rh/devtoolset-11/root/usr/lib64/dyninst:/opt/rh/devtoolset-11/root/usr/lib/dyninst:/usr/local/lib64 --build-arg BUILD_UID=$( id -u )" + DockerBuildArgs: "--network=host --build-arg POLICY=manylinux_2_28 --build-arg PLATFORM=x86_64 --build-arg PREPEND_PATH=/usr/local/cuda/bin --build-arg LD_LIBRARY_PATH_ARG=/usr/local/lib64 --build-arg DEVTOOLSET_ROOTPATH=/usr --build-arg BUILD_UID=$( id -u )" Repository: onnxruntimetensorrt86gpubuild - - task: CmdLine@2 - inputs: - script: | - docker run --gpus all -e CC=/opt/rh/devtoolset-11/root/usr/bin/cc -e CXX=/opt/rh/devtoolset-11/root/usr/bin/c++ -e CFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all" -e CXXFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-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 \ - -e ALLOW_RELEASED_ONNX_OPSET_ONLY=0 \ - -e NIGHTLY_BUILD \ - -e BUILD_BUILDNUMBER \ - onnxruntimetensorrt86gpubuild \ - /opt/python/cp38-cp38/bin/python3 /onnxruntime_src/tools/ci_build/build.py \ - --build_dir /build --cmake_generator Ninja \ - --config Release \ - --skip_submodule_sync \ - --build_shared_lib \ - --parallel \ - --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_pybind --build_java \ - --use_tensorrt --tensorrt_home /usr \ - --cmake_extra_defines CMAKE_CUDA_HOST_COMPILER=/opt/rh/devtoolset-11/root/usr/bin/cc CMAKE_CUDA_ARCHITECTURES=75 - workingDirectory: $(Build.SourcesDirectory) - - - task: PublishTestResults@2 - displayName: 'Publish unit test results' - inputs: - testResultsFiles: '**/*.results.xml' - searchFolder: '$(Build.BinariesDirectory)' - testRunTitle: 'Unit Test Run' - condition: succeededOrFailed() + - 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 --gpus all -e CFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all" -e CXXFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-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 \ + onnxruntimetensorrt86gpubuild \ + /bin/bash -c " + set -ex; \ + ccache -s; \ + /opt/python/cp38-cp38/bin/python3 /onnxruntime_src/tools/ci_build/build.py \ + --build_dir /build --cmake_generator Ninja \ + --config Release \ + --skip_submodule_sync \ + --build_shared_lib \ + --parallel \ + --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_pybind --build_java \ + --use_tensorrt --tensorrt_home /usr \ + --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=75 \ + --use_cache; \ + ccache -sv; \ + ccache -z" + workingDirectory: $(Build.SourcesDirectory) - - template: templates/clean-agent-build-directory-step.yml + - template: templates/explicitly-defined-final-tasks.yml 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 ce34f902e67b5..47061965efe26 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,13 +8,11 @@ parameters: - name: TrtVersion displayName: TensorRT Version type: string - default: 8.6.0.12 + default: 8.6.1.6 values: - - 8.2.1.8 - - 8.0.1.6 - 8.4.1.5 - 8.5.1.1 - - 8.6.0.12 + - 8.6.1.6 - BIN - name: ModelGroups @@ -26,7 +24,7 @@ parameters: - name: MemTest displayName: Run Memory Test type: boolean - default: false + default: true - name: TrtEPOptions displayName: TensorRT EP options @@ -89,17 +87,17 @@ jobs: - script: 'python3 $(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/build/build_image.py -r $(Build.SourcesDirectory) -i $(image) -b $(branchName) -t $(trtVersion) -a 75' displayName: 'Build latest ORT Image' workingDirectory: '$(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/build' - - - ${{ each option in parameters.ModelGroups }}: - - script: '$(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/run_perf_docker.sh -d $(image) -p $(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf -v $(modelVolume) -b true -o ${{option}} -m $(${{option}}) -e "$(epList)" $(optional_arguments)' - displayName: '${{option}} perf' - workingDirectory: '$(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/' - ${{ if eq(parameters.MemTest, true) }}: - script: '$(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/mem_test/run_mem_test_docker.sh -d $(image) -p $(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/mem_test/ -w /code/ -l false' displayName: 'Run Memory Test' workingDirectory: '$(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/mem_test/' + - ${{ each option in parameters.ModelGroups }}: + - script: '$(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/run_perf_docker.sh -d $(image) -p $(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf -v $(modelVolume) -b true -o ${{option}} -m $(${{option}}) -e "$(epList)" $(optional_arguments)' + displayName: '${{option}} perf' + workingDirectory: '$(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/' + # Prepare and Publish Artifacts - script: 'mkdir $(Build.SourcesDirectory)/Artifact' diff --git a/tools/ci_build/github/azure-pipelines/linux-migraphx-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/linux-migraphx-ci-pipeline.yml index 2165737da07a1..352ee19a49108 100644 --- a/tools/ci_build/github/azure-pipelines/linux-migraphx-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/linux-migraphx-ci-pipeline.yml @@ -1,50 +1,102 @@ -trigger: none +##### start trigger Don't edit it manually, Please do edit 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 #### name: 'linux_ci_$(Date:yyyyMMdd)_$(Rev:r)' + +# gid of video and render group on gcramdrr1-mi100-085 and -86 +variables: + - name: video + value: 44 + - name: render + value: 109 + - name: RocmVersion + value: 5.6 + jobs: -- job: AMDMIGraphX_CI +- job: Linux_Build + variables: + skipComponentGovernanceDetection: true + CCACHE_DIR: $(Pipeline.Workspace)/ccache + TODAY: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)] workspace: clean: all - pool: 'AMD-GPU' - timeoutInMinutes: 180 - - # gid of video and render group on gcramdrr1-mi100-085 and -86 - variables: - - name: video - value: 44 - - name: render - value: 109 - - name: RocmVersion - value: 5.4 + pool: onnxruntime-Ubuntu2004-AMD-CPU + timeoutInMinutes: 120 steps: + - task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3 + displayName: 'Clean Agent Directories' + condition: always() + - checkout: self clean: true submodules: recursive + - template: templates/get-docker-image-steps.yml parameters: Dockerfile: tools/ci_build/github/linux/docker/migraphx-ci-pipeline-env.Dockerfile Context: tools/ci_build/github/linux/docker + DockerBuildArgs: "--build-arg ROCM_VERSION=$(RocmVersion)" Repository: onnxruntimetrainingmigraphx-cibuild-rocm$(RocmVersion) + - task: Cache@2 + inputs: + key: '"$(TODAY)" | "$(Build.SourceBranch)" | "$(Build.SourceVersion)"' + path: $(CCACHE_DIR) + cacheHitVar: CACHE_RESTORED + restoreKeys: | + "$(TODAY)" | "$(Build.SourceBranch)" + "$(TODAY)" | + displayName: Cache Task + + - script: mkdir -p $(CCACHE_DIR) + condition: ne(variables.CACHE_RESTORED, 'true') + displayName: Create Cache Dir + - task: CmdLine@2 inputs: script: | docker run --rm \ - -e HIP_VISIBLE_DEVICES \ - --privileged \ --security-opt seccomp=unconfined \ --shm-size=1024m \ - --device=/dev/kfd \ - --device=/dev/dri \ - --group-add $(video) \ - --group-add $(render) \ --user $UID:$(id -g $USER) \ --volume $(Build.SourcesDirectory):/onnxruntime_src \ --volume $(Build.BinariesDirectory):/build \ + --volume $(CCACHE_DIR):/cache \ + -e CCACHE_DIR=/cache \ --workdir /onnxruntime_src \ onnxruntimetrainingmigraphx-cibuild-rocm$(RocmVersion) \ + /bin/bash -c " + set -ex; \ + env; \ + ccache -s; \ python tools/ci_build/build.py \ --config Release \ --cmake_extra_defines \ @@ -59,23 +111,66 @@ jobs: --update \ --build_dir /build \ --build \ - --parallel 32 \ + --parallel \ --build_wheel \ --skip_submodule_sync \ - --skip_tests --cmake_path /usr/bin/cmake --ctest_path /usr/bin/ctest + --use_cache \ + --skip_tests --cmake_path /usr/bin/cmake --ctest_path /usr/bin/ctest; \ + ccache -sv; \ + ccache -z" workingDirectory: $(Build.SourcesDirectory) displayName: 'Build onnxruntime' + - task: CmdLine@2 + inputs: + script: | + cd $(Build.BinariesDirectory)/Release + find -executable -type f > $(Build.BinariesDirectory)/Release/perms.txt + displayName: 'Find Executable Files' + + - task: PublishPipelineArtifact@0 + displayName: 'Publish Pipeline Artifact' + inputs: + artifactName: 'drop-linux' + targetPath: '$(Build.BinariesDirectory)/Release' + + - template: templates/explicitly-defined-final-tasks.yml + +- job: Linux_Test + workspace: + clean: all + pool: AMD-GPU + dependsOn: + - Linux_Build + timeoutInMinutes: 120 + + steps: + - task: DownloadPipelineArtifact@2 + displayName: 'Download Pipeline Artifact' + inputs: + buildType: 'current' + artifactName: 'drop-linux' + targetPath: '$(Build.BinariesDirectory)/Release' + + - checkout: self + clean: true + submodules: recursive + + - template: templates/get-docker-image-steps.yml + parameters: + Dockerfile: tools/ci_build/github/linux/docker/migraphx-ci-pipeline-env.Dockerfile + Context: tools/ci_build/github/linux/docker + DockerBuildArgs: "--build-arg ROCM_VERSION=$(RocmVersion)" + Repository: onnxruntimetrainingmigraphx-cibuild-rocm$(RocmVersion) + - task: CmdLine@2 inputs: script: | docker run --rm \ - -e HIP_VISIBLE_DEVICES \ - --privileged \ --security-opt seccomp=unconfined \ --shm-size=1024m \ --device=/dev/kfd \ - --device=/dev/dri \ + --device=/dev/dri/renderD$DRIVER_RENDER \ --group-add $(video) \ --group-add $(render) \ --user $UID:$(id -g $USER) \ @@ -83,7 +178,10 @@ jobs: --volume $(Build.BinariesDirectory):/build \ --workdir /build/Release \ onnxruntimetrainingmigraphx-cibuild-rocm$(RocmVersion) \ - /onnxruntime_src/tools/ci_build/github/pai/migraphx_test_launcher.sh + /bin/bash -c " + set -ex; \ + cd /build/Release && xargs -a /build/Release/perms.txt chmod a+x; \ + bash /onnxruntime_src/tools/ci_build/github/pai/migraphx_test_launcher.sh" workingDirectory: $(Build.SourcesDirectory) displayName: 'Run onnxruntime unit tests' diff --git a/tools/ci_build/github/azure-pipelines/linux-multi-gpu-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/linux-multi-gpu-ci-pipeline.yml deleted file mode 100644 index c220d0f332712..0000000000000 --- a/tools/ci_build/github/azure-pipelines/linux-multi-gpu-ci-pipeline.yml +++ /dev/null @@ -1,67 +0,0 @@ -resources: - repositories: - - repository: manylinux # The name used to reference this repository in the checkout step - type: Github - endpoint: Microsoft - name: pypa/manylinux - ref: aead4d751c2101e23336aa73f2380df83e7a13f3 - -jobs: -- job: Linux_Build - timeoutInMinutes: 180 - workspace: - clean: all - pool: Linux-Multi-GPU - steps: - - checkout: self - clean: true - submodules: none - - - template: templates/get-docker-image-steps.yml - parameters: - Dockerfile: tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_cuda11 - Context: tools/ci_build/github/linux/docker - DockerBuildArgs: "--network=host --build-arg POLICY=manylinux2014 --build-arg PLATFORM=x86_64 --build-arg BASEIMAGE=nvidia/cuda:11.6.2-cudnn8-devel-centos7 --build-arg DEVTOOLSET_ROOTPATH=/opt/rh/devtoolset-11/root --build-arg PREPEND_PATH=/opt/rh/devtoolset-11/root/usr/bin: --build-arg LD_LIBRARY_PATH_ARG=/opt/rh/devtoolset-11/root/usr/lib64:/opt/rh/devtoolset-11/root/usr/lib:/opt/rh/devtoolset-11/root/usr/lib64/dyninst:/opt/rh/devtoolset-11/root/usr/lib/dyninst:/usr/local/lib64 --build-arg BUILD_UID=$( id -u )" - Repository: onnxruntimecuda11build - - - task: CmdLine@2 - inputs: - script: | - mkdir -p $HOME/.onnx - docker run --gpus all -e CC=/opt/rh/devtoolset-11/root/usr/bin/cc -e CXX=/opt/rh/devtoolset-11/root/usr/bin/c++ -e CFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all" -e CXXFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-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 \ - -e ALLOW_RELEASED_ONNX_OPSET_ONLY=0 \ - -e NIGHTLY_BUILD \ - -e BUILD_BUILDNUMBER \ - onnxruntimecuda11build \ - /opt/python/cp38-cp38/bin/python3.8 /onnxruntime_src/tools/ci_build/build.py \ - --build_dir /build --cmake_generator Ninja \ - --config Release \ - --skip_submodule_sync \ - --build_shared_lib \ - --parallel \ - --build_wheel \ - --enable_onnx_tests --use_cuda --cuda_version=11.6 --cuda_home=/usr/local/cuda-11.6 --cudnn_home=/usr/local/cuda-11.6 \ - --enable_pybind --build_java --build_nodejs --enable_multi_device_test \ - --cmake_extra_defines CMAKE_CUDA_HOST_COMPILER=/opt/rh/devtoolset-11/root/usr/bin/cc CMAKE_CUDA_ARCHITECTURES=52 - workingDirectory: $(Build.SourcesDirectory) - - - task: PublishTestResults@2 - displayName: 'Publish unit test results' - inputs: - testResultsFiles: '**/*.results.xml' - searchFolder: '$(Build.BinariesDirectory)' - testRunTitle: 'Unit Test Run' - condition: succeededOrFailed() - - - template: templates/component-governance-component-detection-steps.yml - parameters: - condition: 'succeeded' - - - task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3 - displayName: 'Clean Agent Directories' - condition: always() diff --git a/tools/ci_build/github/azure-pipelines/linux-multi-gpu-tensorrt-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/linux-multi-gpu-tensorrt-ci-pipeline.yml index f0e298073b6fa..0a7dc0e456a95 100644 --- a/tools/ci_build/github/azure-pipelines/linux-multi-gpu-tensorrt-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/linux-multi-gpu-tensorrt-ci-pipeline.yml @@ -1,3 +1,34 @@ +##### start trigger Don't edit it manually, Please do edit set-trigger-rules.py #### +trigger: + branches: + include: + - main + - rel-* + paths: + exclude: + - docs/** + - README.md + - CONTRIBUTING.md + - BUILD.md + - 'js/web' + - 'js/node' + - 'onnxruntime/core/providers/js' +pr: + branches: + include: + - main + - rel-* + paths: + exclude: + - docs/** + - README.md + - CONTRIBUTING.md + - BUILD.md + - 'js/web' + - 'js/node' + - 'onnxruntime/core/providers/js' +#### end trigger #### + jobs: - template: templates/linux-ci.yml parameters: 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 a1bbec12d1801..93ee17b4cc7e6 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 @@ -1,9 +1,38 @@ +##### start trigger Don't edit it manually, Please do edit 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: - template: templates/linux-ci.yml parameters: AgentPool : 'Linux-CPU-2019' JobName: 'Linux_CI_Dev' - RunDockerBuildArgs: '-o ubuntu20.04 -d openvino -v 2022.3.0 -x "--use_openvino CPU_FP32 --build_wheel"' + RunDockerBuildArgs: '-o ubuntu20.04 -d openvino -v 2023.0.0 -x "--use_openvino CPU_FP32 --build_wheel"' DoNugetPack: 'false' ArtifactName: 'drop-linux' TimeoutInMinutes: 120 diff --git a/tools/ci_build/github/azure-pipelines/linux-openvino-nightly-pipeline.yml b/tools/ci_build/github/azure-pipelines/linux-openvino-nightly-pipeline.yml deleted file mode 100644 index 689322ed36a2f..0000000000000 --- a/tools/ci_build/github/azure-pipelines/linux-openvino-nightly-pipeline.yml +++ /dev/null @@ -1,32 +0,0 @@ -jobs: -- job: Linux_OpenVINO_CI_Dev - timeoutInMinutes: 240 - pool: OpenVINO - steps: - - task: CmdLine@2 - displayName: 'Clean untagged docker images' - inputs: - script: | - docker rm $(docker ps -a | grep Exited | awk '{print $1;}') || true - docker images -q --filter "dangling=true" | xargs -n1 -r docker rmi - workingDirectory: $(Build.BinariesDirectory) - continueOnError: true - condition: always() - - - task: PythonScript@0 - displayName: 'Unzip test data' - inputs: - scriptPath: '$(Build.SourcesDirectory)/tools/ci_build/github/download_test_data.py' - arguments: --build_dir $(Build.BinariesDirectory) --edge_device - pythonInterpreter: '/usr/bin/python3' - workingDirectory: $(Build.BinariesDirectory) - - - template: templates/run-docker-build-steps.yml - parameters: - RunDockerBuildArgs: '-o ubuntu20.04 -d openvino -v 2020.2 -x "--use_openvino GPU_FP32 --build_wheel"' - - - template: templates/component-governance-component-detection-steps.yml - parameters : - condition : 'ci_only' - - - template: templates/clean-agent-build-directory-step.yml 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 8c638b2238709..f678b18ba9787 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 @@ -1,12 +1,38 @@ +##### start trigger Don't edit it manually, Please do edit 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: QnnSdk displayName: QNN SDK version type: string - default: qnn-v2.8.0.230223123141_52150 - values: - - qnn-v2.6.0.221227110525_42395 - - qnn-v2.8.0.230223123141_52150 + default: qnn-v2.14.1.230828 jobs: - job: Build_QNN_EP @@ -60,7 +86,7 @@ jobs: inputs: script: | ./build/Release/onnx_test_runner -e qnn \ - -v -j 1 -c 1 -i "backend_path|$(QNN_SDK_ROOT)/target/x86_64-linux-clang/lib/libQnnCpu.so" \ + -v -j 1 -c 1 -i "backend_path|$(QNN_SDK_ROOT)/lib/x86_64-linux-clang/libQnnCpu.so" \ cmake/external/onnx/onnx/backend/test/data/node - task: CmdLine@2 @@ -68,7 +94,7 @@ jobs: inputs: script: | ./build/Release/onnx_test_runner -e qnn \ - -v -j 1 -c 1 -i "backend_path|$(QNN_SDK_ROOT)/target/x86_64-linux-clang/lib/libQnnCpu.so" \ + -v -j 1 -c 1 -i "backend_path|$(QNN_SDK_ROOT)/lib/x86_64-linux-clang/libQnnCpu.so" \ /data/float32_models - task: CmdLine@2 @@ -76,6 +102,21 @@ jobs: inputs: script: | ./build/Release/onnx_test_runner -e qnn \ - -v -j 1 -c 1 -i "backend_path|$(QNN_SDK_ROOT)/target/x86_64-linux-clang/lib/libQnnHtp.so" \ + -v -j 1 -c 1 -i "backend_path|$(QNN_SDK_ROOT)/lib/x86_64-linux-clang/libQnnHtp.so" \ /data/qdq_models + - task: CmdLine@2 + displayName: Run QDQ model tests with context cache enabled + inputs: + script: | + ./build/Release/onnx_test_runner -e qnn \ + -v -j 1 -c 1 -i "backend_path|$(QNN_SDK_ROOT)/lib/x86_64-linux-clang/libQnnHtp.so qnn_context_cache_enable|1 qnn_context_cache_path|./build/Release/mobilenet_qdq.bin" \ + /data/qdq_models/mobilenetv2-1.0_add_transpose_quant + + - task: CmdLine@2 + displayName: Run QDQ model tests with load from cached context + inputs: + script: | + ./build/Release/onnx_test_runner -e qnn \ + -v -j 1 -c 1 -i "backend_path|$(QNN_SDK_ROOT)/lib/x86_64-linux-clang/libQnnHtp.so qnn_context_cache_enable|1 qnn_context_cache_path|./build/Release/mobilenet_qdq.bin" \ + /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 index f573ddf938737..5894631739ac8 100644 --- a/tools/ci_build/github/azure-pipelines/mac-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/mac-ci-pipeline.yml @@ -1,7 +1,36 @@ +##### start trigger Don't edit it manually, Please do edit 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 --enable_language_interop_ops --build_wheel + AdditionalBuildFlags: --build_objc --enable_language_interop_ops --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 index a359bbd83460a..60f2786bdd856 100644 --- a/tools/ci_build/github/azure-pipelines/mac-coreml-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/mac-coreml-ci-pipeline.yml @@ -1,9 +1,38 @@ +##### start trigger Don't edit it manually, Please do edit 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-12' + vmImage: 'macOS-13' variables: MACOSX_DEPLOYMENT_TARGET: '10.14' TODAY: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)] @@ -13,6 +42,8 @@ jobs: - 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 @@ -21,6 +52,7 @@ jobs: CacheDir: $(CCACHE_DIR) BuildStep: - script: | + set -e python3 tools/ci_build/build.py \ --build_dir build \ --skip_submodule_sync \ 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 index 7aaa713d8eaf6..b1d7ede2843c8 100644 --- a/tools/ci_build/github/azure-pipelines/mac-ios-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/mac-ios-ci-pipeline.yml @@ -1,29 +1,43 @@ +##### start trigger Don't edit it manually, Please do edit 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-12' + vmImage: 'macOS-13' variables: - MACOSX_DEPLOYMENT_TARGET: '10.14' PROTO_CACHE_DIR: $(Pipeline.Workspace)/proto_ccache ORT_CACHE_DIR: $(Pipeline.Workspace)/ort_ccache TODAY: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)] timeoutInMinutes: 150 steps: - - template: templates/mac-build-step-with-cache.yml - parameters: - WithCache: true - Today: $(TODAY) - AdditionalKey: ' protobuf | "$(Agent.OS)" | $(Build.SourcesDirectory)/cmake/deps.txt, $(Build.SourcesDirectory)/tools/ci_build/github/linux/docker/inference/x64/python/cpu/scripts/install_protobuf.sh' - CacheDir: $(PROTO_CACHE_DIR) - ChangeEveryCommit: false - BuildStep: - - script: | - $(Build.SourcesDirectory)/tools/ci_build/github/linux/docker/inference/x64/python/cpu/scripts/install_protobuf.sh \ - -p $(Build.BinariesDirectory)/protobuf_install -d $(Build.SourcesDirectory)/cmake/deps.txt - displayName: Install protobuf - env: - CCACHE_DIR: $(PROTO_CACHE_DIR) - + - template: templates/use-xcode-version.yml - template: templates/mac-build-step-with-cache.yml parameters: WithCache: true @@ -33,7 +47,6 @@ jobs: ChangeEveryCommit: true BuildStep: - script: | - sudo xcode-select --switch /Applications/Xcode_13.1.app/Contents/Developer python3 $(Build.SourcesDirectory)/tools/ci_build/build.py \ --skip_submodule_sync \ --build_dir $(Build.BinariesDirectory)/iOS \ @@ -43,11 +56,10 @@ jobs: --ios \ --ios_sysroot iphonesimulator \ --osx_arch x86_64 \ - --apple_deploy_target 11.0 \ + --apple_deploy_target 12.0 \ --use_xcode \ --config RelWithDebInfo \ --build_apple_framework \ - --path_to_protoc_exe $(Build.BinariesDirectory)/protobuf_install/bin/protoc \ --parallel displayName: (CPU, CoreML, XNNPACK EPs) Build onnxruntime for iOS x86_64 and run tests using simulator env: 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 1e1037f1d9b7a..20263974af24a 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 @@ -1,219 +1,149 @@ +##### start trigger Don't edit it manually, Please do edit 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: BuildType +- name: buildType displayName: |- Type of build. "release": A release build to be published for an official ONNX Runtime release. - "prerelease": A pre-release build to be published for validation prior to release. - "normal": A normal build not for publication. + "normal": A normal build. This can be published as a pre-release build for validation prior to release. type: string values: - release - - prerelease - normal default: normal name: "$(Date:yyyyMMdd)$(Rev:rrr)" # build number format -jobs: -- job: IosPackaging - displayName: "iOS Packaging" - - pool: - vmImage: "macOS-12" - - timeoutInMinutes: 300 - - steps: - - task: InstallAppleCertificate@2 - inputs: - certSecureFile: '$(ios_signing_certificate_name)' - certPwd: '$(ios_signing_certificate_password)' - keychain: 'temp' - deleteCert: true - displayName: 'Install ORT Mobile Test Signing Certificate' - - - task: InstallAppleProvisioningProfile@1 - inputs: - provProfileSecureFile: '$(ios_provision_profile_name)' - removeProfile: true - displayName: 'Install ORT Mobile Test Provisioning Profile' - - - task: UsePythonVersion@0 - inputs: - versionSpec: "3.9" - addToPath: true - architecture: "x64" - - - script: | - pip install -r tools/ci_build/github/apple/ios_packaging.requirements.txt - displayName: "Install Python requirements" - - - bash: | - BUILD_TYPE="${{ parameters.BuildType }}" - BASE_VERSION="$(cat ./VERSION_NUMBER)" - SHORT_COMMIT_HASH="$(git rev-parse --short HEAD)" - DEV_VERSION="${BASE_VERSION}-dev+$(Build.BuildNumber).${SHORT_COMMIT_HASH}" - - case "${BUILD_TYPE}" in - ("release") - VERSION="${BASE_VERSION}"; SHOULD_UPLOAD_ARCHIVES="true" ;; - ("prerelease") - VERSION="${DEV_VERSION}"; SHOULD_UPLOAD_ARCHIVES="true" ;; - ("normal") - VERSION="${DEV_VERSION}"; SHOULD_UPLOAD_ARCHIVES="false" ;; - (*) - echo "Invalid build type: ${BUILD_TYPE}"; exit 1 ;; - esac - - set_var() { - local VAR_NAME=${1:?} - local VAR_VALUE=${2:?} - echo "##vso[task.setvariable variable=${VAR_NAME}]${VAR_VALUE}" - echo "${VAR_NAME}: ${VAR_VALUE}" - } - - set_var "ORT_POD_VERSION" "${VERSION}" - set_var "ORT_SHOULD_UPLOAD_ARCHIVES" "${SHOULD_UPLOAD_ARCHIVES}" - displayName: "Set variables" - - - script: | - $(Build.SourcesDirectory)/tools/ci_build/github/linux/docker/inference/x64/python/cpu/scripts/install_protobuf.sh -p $(Build.BinariesDirectory)/protobuf_install -d $(Build.SourcesDirectory)/cmake/deps.txt - displayName: "Build Host Protoc" - - # create and test mobile pods - - script: | - python tools/ci_build/github/apple/build_and_assemble_ios_pods.py \ - --build-dir "$(Build.BinariesDirectory)/ios_framework_mobile" \ - --staging-dir "$(Build.BinariesDirectory)/staging" \ - --pod-version "${ORT_POD_VERSION}" \ - --test \ - --variant Mobile \ - --build-settings-file tools/ci_build/github/apple/default_mobile_ios_framework_build_settings.json \ - --include-ops-by-config tools/ci_build/github/android/mobile_package.required_operators.config \ - -b="--path_to_protoc_exe" -b "$(Build.BinariesDirectory)/protobuf_install/bin/protoc" - displayName: "[Mobile] Build iOS framework and assemble pod package files" - - - script: | - python tools/ci_build/github/apple/test_ios_packages.py \ - --fail_if_cocoapods_missing \ - --framework_info_file "$(Build.BinariesDirectory)/ios_framework_mobile/framework_info.json" \ - --c_framework_dir "$(Build.BinariesDirectory)/ios_framework_mobile/framework_out" \ - --variant Mobile \ - --test_project_stage_dir "$(Build.BinariesDirectory)/app_center_test_mobile" \ - --prepare_test_project_only - displayName: "[Mobile] Assemble test project for App Center" - - - task: Xcode@5 - inputs: - actions: 'build-for-testing' - configuration: 'Debug' - xcWorkspacePath: '$(Build.BinariesDirectory)/app_center_test_mobile/ios_package_test/ios_package_test.xcworkspace' - sdk: 'iphoneos' - scheme: 'ios_package_test' - signingOption: 'manual' - signingIdentity: '$(APPLE_CERTIFICATE_SIGNING_IDENTITY)' - provisioningProfileName: 'iOS Team Provisioning Profile' - args: '-derivedDataPath $(Build.BinariesDirectory)/app_center_test_mobile/ios_package_test/DerivedData' - workingDirectory: $(Build.BinariesDirectory)/app_center_test_mobile/ios_package_test/ - displayName: '[Mobile] Build iphone arm64 tests' - - - script: | - set -e -x - appcenter test run xcuitest \ - --app "AI-Frameworks/ORT-Mobile-iOS" \ - --devices $(app_center_test_devices) \ - --test-series "master" \ - --locale "en_US" \ - --build-dir $(Build.BinariesDirectory)/app_center_test_mobile/ios_package_test/DerivedData/Build/Products/Debug-iphoneos \ - --token $(app_center_api_token) - displayName: "[Mobile] Run E2E tests on App Center" - - # create and test full pods - - script: | - python tools/ci_build/github/apple/build_and_assemble_ios_pods.py \ - --build-dir "$(Build.BinariesDirectory)/ios_framework_full" \ - --staging-dir "$(Build.BinariesDirectory)/staging" \ - --pod-version "${ORT_POD_VERSION}" \ - --test \ - --variant Full \ - --build-settings-file tools/ci_build/github/apple/default_full_ios_framework_build_settings.json \ - -b="--path_to_protoc_exe" -b "$(Build.BinariesDirectory)/protobuf_install/bin/protoc" - displayName: "[Full] Build iOS framework and assemble pod package files" - - - script: | - python tools/ci_build/github/apple/test_ios_packages.py \ - --fail_if_cocoapods_missing \ - --framework_info_file "$(Build.BinariesDirectory)/ios_framework_full/framework_info.json" \ - --c_framework_dir "$(Build.BinariesDirectory)/ios_framework_full/framework_out" \ - --variant Full \ - --test_project_stage_dir "$(Build.BinariesDirectory)/app_center_test_full" \ - --prepare_test_project_only - displayName: "[Full] Assemble test project for App Center" - - - task: Xcode@5 - inputs: - actions: 'build-for-testing' - configuration: 'Debug' - xcWorkspacePath: '$(Build.BinariesDirectory)/app_center_test_full/ios_package_test/ios_package_test.xcworkspace' - sdk: 'iphoneos' - scheme: 'ios_package_test' - signingOption: 'manual' - signingIdentity: '$(APPLE_CERTIFICATE_SIGNING_IDENTITY)' - provisioningProfileName: 'iOS Team Provisioning Profile' - args: '-derivedDataPath $(Build.BinariesDirectory)/app_center_test_full/ios_package_test/DerivedData' - workingDirectory: $(Build.BinariesDirectory)/app_center_test_full/ios_package_test/ - displayName: '[Full] Build iphone arm64 tests' - - - script: | - set -e -x - appcenter test run xcuitest \ - --app "AI-Frameworks/ORT-Mobile-iOS" \ - --devices $(app_center_test_devices) \ - --test-series "master" \ - --locale "en_US" \ - --build-dir $(Build.BinariesDirectory)/app_center_test_full/ios_package_test/DerivedData/Build/Products/Debug-iphoneos \ - --token $(app_center_api_token) - displayName: "[Full] Run E2E tests on App Center" - - - task: AzureCLI@2 - inputs: - azureSubscription: 'AIInfraBuildOnnxRuntimeOSS' - scriptType: 'bash' - scriptLocation: 'scriptPath' - scriptPath: 'tools/ci_build/github/apple/assemble_ios_packaging_artifacts.sh' - arguments: >- - "$(Build.BinariesDirectory)/staging" - "$(Build.ArtifactStagingDirectory)" - "$(ORT_POD_VERSION)" - "$(ORT_SHOULD_UPLOAD_ARCHIVES)" - displayName: "Assemble artifacts" - - - script: | - set -e -x - ls -R "$(Build.ArtifactStagingDirectory)" - displayName: "List staged artifacts" - - - script: | - set -e -x - shasum -a 256 "$(Build.ArtifactStagingDirectory)/pod-archive-onnxruntime-c-${ORT_POD_VERSION}.zip" - displayName: "Print ORT iOS Pod checksum" - - - # copy the pod archive to a path relative to Package.swift and set the env var required by Package.swift to use that. - # xcodebuild will implicitly use Package.swift and build/run the .testTarget (tests in swift/onnxTests). - # once that's done cleanup the copy of the pod zip file - - script: | - set -e -x - cp "$(Build.ArtifactStagingDirectory)/pod-archive-onnxruntime-c-${ORT_POD_VERSION}.zip" swift/ - export ORT_IOS_POD_LOCAL_PATH="swift/pod-archive-onnxruntime-c-${ORT_POD_VERSION}.zip" - xcodebuild test -scheme onnxruntime -destination 'platform=iOS Simulator' - rm swift/pod-archive-onnxruntime-c-*.zip - displayName: "Test Package.swift usage" - - - publish: "$(Build.ArtifactStagingDirectory)" - artifact: ios_packaging_artifacts - displayName: "Publish artifacts" - - - template: templates/component-governance-component-detection-steps.yml - parameters : - condition : 'succeeded' +stages: +- stage: IosPackaging_SetCommonVariables + dependsOn: [] + + variables: + skipComponentGovernanceDetection: true + + jobs: + - job: j + displayName: "Set common variables" + + pool: + vmImage: "macOS-13" + + timeoutInMinutes: 5 + + steps: + - bash: | + set -e + + BUILD_TYPE="${{ parameters.buildType }}" + BASE_VERSION="$(cat ./VERSION_NUMBER)" + SHORT_COMMIT_HASH="$(git rev-parse --short HEAD)" + DEV_VERSION="${BASE_VERSION}-dev+$(Build.BuildNumber).${SHORT_COMMIT_HASH}" + + case "${BUILD_TYPE}" in + ("release") + VERSION="${BASE_VERSION}" ;; + ("normal") + VERSION="${DEV_VERSION}" ;; + (*) + echo "Invalid build type: ${BUILD_TYPE}"; exit 1 ;; + esac + + # Do not output ##vso[] commands with `set -x` or they may be parsed again and include a trailing quote. + set +x + + set_var() { + local VAR_NAME=${1:?} + local VAR_VALUE=${2:?} + echo "##vso[task.setvariable variable=${VAR_NAME};isoutput=true;isreadonly=true]${VAR_VALUE}" + echo "${VAR_NAME}: ${VAR_VALUE}" + } + + set_var "ORT_POD_VERSION" "${VERSION}" + displayName: "Set common variables" + name: SetCommonVariables + +- template: templates/stages/mac-ios-packaging-build-stage.yml + parameters: + packageVariant: Mobile + +- template: templates/stages/mac-ios-packaging-build-stage.yml + parameters: + packageVariant: Full + +- template: templates/stages/mac-ios-packaging-build-stage.yml + parameters: + packageVariant: Training + +- stage: IosPackaging_TestPackageSwift_Full + dependsOn: + - IosPackaging_SetCommonVariables + - IosPackaging_Build_Full + + jobs: + - job: j + displayName: "Test Package.swift with full package" + + pool: + vmImage: "macOS-13" + + variables: + xcodeVersion: "14.3" + ortPodVersion: $[stageDependencies.IosPackaging_SetCommonVariables.j.outputs['SetCommonVariables.ORT_POD_VERSION']] + skipComponentGovernanceDetection: true + + timeoutInMinutes: 10 + + steps: + - template: templates/use-xcode-version.yml + parameters: + xcodeVersion: ${{ variables.xcodeVersion }} + + - download: current + artifact: ios_packaging_artifacts_full + displayName: "Download full build artifacts" + + - script: | + set -e -x + shasum -a 256 "$(Pipeline.Workspace)/ios_packaging_artifacts_full/pod-archive-onnxruntime-c-$(ortPodVersion).zip" + displayName: "Print ORT iOS Pod checksum" + + # copy the pod archive to a path relative to Package.swift and set the env var required by Package.swift to use that. + # xcodebuild will implicitly use Package.swift and build/run the .testTarget (tests in swift/onnxTests). + # once that's done cleanup the copy of the pod zip file + - script: | + set -e -x + + SIMULATOR_DEVICE_ID=$(set -o pipefail; python3 tools/ci_build/github/apple/get_simulator_device_info.py | jq --raw-output '.device_udid') + + cp "$(Pipeline.Workspace)/ios_packaging_artifacts_full/pod-archive-onnxruntime-c-$(ortPodVersion).zip" swift/ + export ORT_IOS_POD_LOCAL_PATH="swift/pod-archive-onnxruntime-c-$(ortPodVersion).zip" + xcodebuild test -scheme onnxruntime -destination "platform=iOS Simulator,id=${SIMULATOR_DEVICE_ID}" + rm swift/pod-archive-onnxruntime-c-$(ortPodVersion).zip + displayName: "Test Package.swift usage" diff --git a/tools/ci_build/github/azure-pipelines/mac-objc-static-analysis-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/mac-objc-static-analysis-ci-pipeline.yml index 3fffec6159128..6893fb95cfec5 100644 --- a/tools/ci_build/github/azure-pipelines/mac-objc-static-analysis-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/mac-objc-static-analysis-ci-pipeline.yml @@ -2,7 +2,7 @@ jobs: - job: ObjCStaticAnalysis pool: - vmImage: 'macOS-12' + vmImage: 'macOS-13' timeoutInMinutes: 30 @@ -17,25 +17,27 @@ jobs: addToPath: true architecture: "x64" - - script: | - pip install -r tools/ci_build/github/apple/objectivec/static_analysis/requirements.txt - displayName: Install tools - - script: | python tools/ci_build/build.py \ --build_dir "$(Build.BinariesDirectory)" \ - --cmake_generator "Ninja" \ + --cmake_generator "Unix Makefiles" \ --config Debug \ --build_shared_lib --use_coreml --build_objc \ + --enable_training_apis \ --cmake_extra_defines CMAKE_EXPORT_COMPILE_COMMANDS=ON \ --update --skip_submodule_sync \ --build --parallel --target onnx_proto displayName: Generate compile_commands.json and ONNX protobuf files - script: | + set -e + + CLANG_TIDY_CHECKS="-*,clang-analyzer-*" + "$(brew --prefix llvm@15)/bin/clang-tidy" \ -p="$(Build.BinariesDirectory)/Debug" \ - --checks="-*,clang-analyzer-*" \ + --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 \ diff --git a/tools/ci_build/github/azure-pipelines/mac-react-native-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/mac-react-native-ci-pipeline.yml index 51d9d27566c2b..e8f4931d5ad9f 100644 --- a/tools/ci_build/github/azure-pipelines/mac-react-native-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/mac-react-native-ci-pipeline.yml @@ -1,3 +1,32 @@ +##### start trigger Don't edit it manually, Please do edit 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: NpmPublish displayName: 'NPM packages publish configuration' @@ -15,7 +44,7 @@ resources: type: Github endpoint: Microsoft name: pypa/manylinux - ref: aead4d751c2101e23336aa73f2380df83e7a13f3 + ref: 5eda9aded5462201e6310105728d33016e637ea7 variables: ${{ if eq(parameters.NpmPublish, 'nightly (@dev)') }}: @@ -32,4 +61,4 @@ stages: parameters: NpmPackagingMode: ${{ variables.NpmPackagingMode }} BuildConfig: 'Release' - PoolName: 'onnxruntime-Linux-CPU-2019' + PoolName: 'onnxruntime-Linux-CPU-For-Android-CI' 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 0400d2d03529e..238218e6fa97c 100644 --- a/tools/ci_build/github/azure-pipelines/nodejs/templates/test.yml +++ b/tools/ci_build/github/azure-pipelines/nodejs/templates/test.yml @@ -22,6 +22,8 @@ steps: displayName: 'Extract package file name (POSIX)' inputs: script: | + # Do not output ##vso[] commands with `set -x` or they may be parsed again and include a trailing quote. + set +x echo "##vso[task.setvariable variable=NpmPackageFilesForTest;]`ls $(Build.BinariesDirectory)/nodejs-artifact/*.tgz | tr '\n' ' '`" workingDirectory: '$(Build.BinariesDirectory)/e2e_test' 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 93b08513048d0..4563a79adb834 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 @@ -1,5 +1,5 @@ parameters: - AgentPool: 'aiinfra-Linux-CPU' + AgentPool: 'onnxruntime-Ubuntu2004-AMD-CPU' StageSuffix: '' stages: - stage: Nodejs_Test_${{ parameters.StageSuffix }} 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 467b5a59f8216..871d7894e5315 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,7 @@ stages: clean: all timeoutInMinutes: 120 pool: - vmImage: 'macOS-12' + vmImage: 'macOS-13' variables: - name: OnnxRuntimeBuildDirectory 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 ec295544df80e..2e7ac9508a41e 100644 --- a/tools/ci_build/github/azure-pipelines/npm-packaging-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/npm-packaging-pipeline.yml @@ -34,7 +34,7 @@ resources: type: Github endpoint: Microsoft name: pypa/manylinux - ref: aead4d751c2101e23336aa73f2380df83e7a13f3 + ref: 5eda9aded5462201e6310105728d33016e637ea7 stages: - template: templates/web-ci.yml @@ -49,9 +49,9 @@ stages: parameters: NpmPackagingMode: ${{ variables.NpmPackagingMode }} BuildConfig: 'Release' - PoolName: 'aiinfra-Linux-CPU' + PoolName: 'onnxruntime-Ubuntu2004-AMD-CPU' PackageName: 'onnxruntime-react-native' - BuildAndroidAARStageDependsOn: 'Extract_commit' + BuildAndroidAARStageDependsOn: 'Precheck_and_extract_commit' - stage: Download_Node_Package_And_Publish_Validation_Script dependsOn: @@ -73,7 +73,8 @@ stages: project: '530acbc4-21bc-487d-8cd8-348ff451d2ff' definition: '940' specificBuildWithTriggering: true - buildVersionToDownload: 'latest' + buildVersionToDownload: 'latestFromBranch' + branchName: 'refs/heads/main' artifactName: 'NPM_packages' targetPath: '$(Pipeline.Workspace)' displayName: 'Download onnxruntime-node Pipeline Artifact' diff --git a/tools/ci_build/github/azure-pipelines/nuget/templates/dml-vs-2019.yml b/tools/ci_build/github/azure-pipelines/nuget/templates/dml-vs-2022.yml similarity index 87% rename from tools/ci_build/github/azure-pipelines/nuget/templates/dml-vs-2019.yml rename to tools/ci_build/github/azure-pipelines/nuget/templates/dml-vs-2022.yml index cc9195f783565..b1e36e63e86ab 100644 --- a/tools/ci_build/github/azure-pipelines/nuget/templates/dml-vs-2019.yml +++ b/tools/ci_build/github/azure-pipelines/nuget/templates/dml-vs-2022.yml @@ -7,12 +7,13 @@ parameters: NuPackScript : '' ArtifactName: 'drop-nuget' DoNodejsPack: 'false' + BuildNodejs: 'true' DoEsrp: 'false' DoTestCoverage: 'false' BuildArch: 'x64' # Optional. Options: x86, x64 sln_platform: 'x64' # Options: Win32, x64, arm, arm64 EnvSetupScript: 'setup_env.bat' - AgentPool: 'Win-CPU-2021' + AgentPool: 'onnxruntime-Win-CPU-2022' AgentDemands: [] OrtPackageId: Microsoft.ML.OnnxRuntime BuildConfigurations: ['RelWithDebInfo'] # Options: Debug, RelWithDebInfo @@ -70,7 +71,13 @@ stages: - task: NodeTool@0 inputs: - versionSpec: '16.x' + versionSpec: '18.x' + + - task: onebranch.pipeline.tsaoptions@1 + displayName: 'OneBranch TSAOptions' + inputs: + tsaConfigFilePath: '$(Build.SourcesDirectory)\.config\tsaoptions.json' + appendSourceBranchName: false - task: UsePythonVersion@0 inputs: @@ -185,9 +192,9 @@ stages: # Nuget packaging if needed - ${{ if eq(parameters['DoNugetPack'], 'true') }}: - task: BatchScript@1 - displayName: 'Setup VS2019 env vars' + displayName: 'Setup VS2022 env vars' inputs: - filename: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat' + filename: 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat' arguments: ${{ parameters.BuildArch }} modifyEnvironment: true # Esrp signing @@ -227,9 +234,9 @@ stages: # Node.js Publish - ${{ if eq(parameters['DoNodejsPack'], 'true') }}: - task: BatchScript@1 - displayName: 'Setup VS2019 env vars' + displayName: 'Setup VS env vars' inputs: - filename: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat' + filename: 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat' arguments: ${{ parameters.BuildArch }} modifyEnvironment: true - template: ../../templates/win-esrp-dll.yml @@ -260,6 +267,24 @@ stages: displayName: 'Unzip package to test' workingDirectory: '$(Build.ArtifactStagingDirectory)' + - ${{ if eq(parameters.BuildNodejs, '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 }}' + - 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: '*.node' + - task: 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 : diff --git a/tools/ci_build/github/azure-pipelines/nuget/templates/get-nuget-package-version-as-variable.yml b/tools/ci_build/github/azure-pipelines/nuget/templates/get-nuget-package-version-as-variable.yml index ef55417d72245..4edf0d03aa5ad 100644 --- a/tools/ci_build/github/azure-pipelines/nuget/templates/get-nuget-package-version-as-variable.yml +++ b/tools/ci_build/github/azure-pipelines/nuget/templates/get-nuget-package-version-as-variable.yml @@ -37,4 +37,6 @@ steps: filenamewithext=$(ls Microsoft.ML.OnnxRuntime.Managed*nupkg) filename=${filenamewithext%.*} ortversion=${filename:33} + # Do not output ##vso[] commands with `set -x` or they may be parsed again and include a trailing quote. + set +x echo "##vso[task.setvariable variable=NuGetPackageVersionNumber;]$ortversion" 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 dc6f855328e25..64fa29f06553e 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,14 +1,17 @@ parameters: - AgentPool: 'aiinfra-Linux-CPU' + AgentPool: 'onnxruntime-Ubuntu2004-AMD-CPU' ArtifactSuffix: '' NugetPackageName : '' + StageSuffix: 'CPU' + NativePackagePrefix: 'onnxruntime' + SpecificArtifact: false + CustomOpArtifactName: 'onnxruntime-linux-x64' + BuildId: '0' stages: -- stage: NuGet_Test_Linux_${{ parameters.ArtifactSuffix }} +- stage: NuGet_Test_Linux_${{ parameters.StageSuffix }} dependsOn: - - NuGet_Packaging_${{ parameters.ArtifactSuffix }} - # For downloading Linux CustomOp TestData - - Linux_C_API_Packaging_CPU + - NuGet_Packaging_${{ parameters.StageSuffix }} condition: succeeded() jobs: - job: @@ -20,19 +23,23 @@ stages: variables: - name: OnnxRuntimeBuildDirectory value: '$(Build.BinariesDirectory)' - steps: - - task: DownloadPipelineArtifact@0 - displayName: 'Download Signed NuGet' - inputs: - artifactName: drop-signed-nuget-${{ parameters.ArtifactSuffix }} - targetPath: '$(Build.BinariesDirectory)/nuget-artifact' + steps: + - template: ../../templates/flex-downloadPipelineArtifact.yml + parameters: + StepName: 'Download Signed NuGet' + ArtifactName: drop-signed-nuget-${{ parameters.ArtifactSuffix }} + TargetPath: '$(Build.BinariesDirectory)/nuget-artifact' + SpecificArtifact: ${{ parameters.SpecificArtifact }} + BuildId: ${{ parameters.BuildId }} - - task: DownloadPipelineArtifact@0 - displayName: 'Download Linux CustomOp TestData' - inputs: - artifactName: 'onnxruntime-linux-x64' - targetPath: '$(Build.BinariesDirectory)/testdata' + - template: ../../templates/flex-downloadPipelineArtifact.yml + parameters: + StepName: 'Download Linux CustomOp TestData' + ArtifactName: ${{ parameters.CustomOpArtifactName }} + TargetPath: '$(Build.BinariesDirectory)/testdata' + SpecificArtifact: ${{ parameters.specificArtifact }} + BuildId: ${{ parameters.BuildId }} - template: get-nuget-package-version-as-variable.yml parameters: @@ -44,19 +51,52 @@ stages: 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 }} + - ${{if contains(parameters.StageSuffix , 'GPU') }}: + - template: ../../templates/get-docker-image-steps.yml + parameters: + Dockerfile: tools/ci_build/github/linux/docker/Dockerfile.package_ubuntu_cuda11_8_tensorrt8_6 + Context: tools/ci_build/github/linux/docker/ + DockerBuildArgs: "--build-arg BUILD_UID=$( id -u )" + Repository: onnxruntimepackagestest + - bash: | + docker run --rm \ + --gpus all \ + --volume $(Build.SourcesDirectory):/onnxruntime_src \ + --volume $(Build.BinariesDirectory):/build \ + --volume /data/models:/build/models:ro \ + -e BUILD_SOURCESDIRECTORY='/onnxruntime_src' \ + -e OnnxRuntimeBuildDirectory='/build' \ + -e DisableContribOps='$(DisableContribOps)' \ + -e DisableMlOps='$(DisableMlOps)' \ + -e IsReleaseBuild='$(IsReleaseBuild)' \ + -e PACKAGENAME='${{ parameters.NugetPackageName }}' \ + onnxruntimepackagestest \ + /bin/bash -c " + set -ex; \ + pushd /build; \ + bash /onnxruntime_src/csharp/test/Microsoft.ML.OnnxRuntime.EndToEndTests/runtest.sh /build/nuget-artifact $(NuGetPackageVersionNumber); \ + popd + " + 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: 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 2e4dfa2d43e91..de0520b97504f 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,7 @@ stages: workspace: clean: all pool: - vmImage: 'macOS-12' + vmImage: 'macOS-13' variables: - name: OnnxRuntimeBuildDirectory 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 94e4575357159..0b9ded10ddd3e 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 @@ -2,12 +2,17 @@ parameters: AgentPool : 'Win-CPU' NugetPackageName : '' ArtifactSuffix: '' + StageSuffix: 'CPU' + # For inference packages, the test data artifact name is drop-nuget and no suffix is required. + # For training packages, to differentiate the artifact name we add '-training' suffix. This needs to be passed from + # the parent pipeline. + TestDataArtifactSuffix: '' Skipx86Tests: 'false' stages: -- stage: NuGet_Test_Win_${{ parameters.ArtifactSuffix }} +- stage: NuGet_Test_Win_${{ parameters.StageSuffix }} dependsOn: - - NuGet_Packaging_${{ parameters.ArtifactSuffix }} + - NuGet_Packaging_${{ parameters.StageSuffix }} condition: succeeded() jobs: - job: @@ -43,9 +48,9 @@ stages: workingFolder: '$(Build.BinariesDirectory)' - task: BatchScript@1 - displayName: 'Setup VS2019 env vars' + displayName: 'Setup Visual Studio env vars' inputs: - filename: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat' + filename: 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat' arguments: 'amd64' modifyEnvironment: true @@ -58,7 +63,7 @@ stages: - task: DownloadPipelineArtifact@0 displayName: 'Download Pipeline Artifact - testdata' inputs: - artifactName: 'drop-nuget' + artifactName: 'drop-nuget${{ parameters.TestDataArtifactSuffix }}' targetPath: '$(Build.BinariesDirectory)\testdata' - template: get-nuget-package-version-as-variable.yml diff --git a/tools/ci_build/github/azure-pipelines/nuget/templates/windowsai.yml b/tools/ci_build/github/azure-pipelines/nuget/templates/windowsai.yml deleted file mode 100644 index 736b91cb4a777..0000000000000 --- a/tools/ci_build/github/azure-pipelines/nuget/templates/windowsai.yml +++ /dev/null @@ -1,557 +0,0 @@ -jobs: -- job: WindowsAI_DirectML_X64 - timeoutInMinutes: 120 - workspace: - clean: all - pool: - name: 'onnxruntime-gpu-winbuild-t4' - demands: [] - steps: - - template: ../../templates/windowsai-nuget-build.yml - parameters: - BuildArch: 'x64' - -- job: WindowsAI_DirectML_X86 - timeoutInMinutes: 120 - workspace: - clean: all - pool: - name: 'onnxruntime-gpu-winbuild-t4' - demands: [] - steps: - - template: ../../templates/windowsai-nuget-build.yml - parameters: - BuildArch: 'x86' - -- job: WindowsAI_DirectML_ARM64 - timeoutInMinutes: 120 - workspace: - clean: all - pool: - name: 'onnxruntime-gpu-winbuild-t4' - demands: [] - steps: - - template: ../../templates/windowsai-nuget-build.yml - parameters: - BuildArch: 'arm64' - -- job: WindowsAI_DirectML_ARM - timeoutInMinutes: 120 - workspace: - clean: all - pool: - name: 'onnxruntime-gpu-winbuild-t4' - demands: [] - steps: - - template: ../../templates/windowsai-nuget-build.yml - parameters: - BuildArch: 'arm' - -- job: WindowsAI_DirectML_X64_StaticRuntime - timeoutInMinutes: 120 - workspace: - clean: all - pool: - name: 'onnxruntime-gpu-winbuild-t4' - demands: [ ] - steps: - - template: ../../templates/windowsai-nuget-build.yml - parameters: - BuildArch: 'x64' - Runtime: 'static' - -- job: WindowsAI_DirectML_X86_StaticRuntime - timeoutInMinutes: 120 - workspace: - clean: all - pool: - name: 'onnxruntime-gpu-winbuild-t4' - demands: [ ] - steps: - - template: ../../templates/windowsai-nuget-build.yml - parameters: - BuildArch: 'x86' - Runtime: 'static' - -- job: WindowsAI_DirectML_ARM64_StaticRuntime - timeoutInMinutes: 120 - workspace: - clean: all - pool: - name: 'onnxruntime-gpu-winbuild-t4' - demands: [ ] - steps: - - template: ../../templates/windowsai-nuget-build.yml - parameters: - BuildArch: 'arm64' - Runtime: 'static' - -- job: WindowsAI_DirectML_ARM_StaticRuntime - timeoutInMinutes: 120 - workspace: - clean: all - pool: - name: 'onnxruntime-gpu-winbuild-t4' - demands: [ ] - steps: - - template: ../../templates/windowsai-nuget-build.yml - parameters: - BuildArch: 'arm' - Runtime: 'static' - -- job: NuGet_Packaging - workspace: - clean: all - pool: 'onnxruntime-gpu-winbuild-t4' - dependsOn: - - WindowsAI_DirectML_X64 - - WindowsAI_DirectML_X86 - - WindowsAI_DirectML_ARM64 - - WindowsAI_DirectML_ARM - - WindowsAI_DirectML_X64_StaticRuntime - - WindowsAI_DirectML_X86_StaticRuntime - - WindowsAI_DirectML_ARM64_StaticRuntime - - WindowsAI_DirectML_ARM_StaticRuntime - condition: succeeded() - steps: - - task: DownloadPipelineArtifact@0 - displayName: 'Download Pipeline Artifact - NuGet DirectML x64' - inputs: - artifactName: 'Microsoft.AI.MachineLearning.x64' - targetPath: '$(Build.BinariesDirectory)/nuget-artifact-x64' - - - task: DownloadPipelineArtifact@0 - displayName: 'Download Pipeline Artifact - NuGet DirectML x86' - inputs: - artifactName: 'Microsoft.AI.MachineLearning.x86' - targetPath: '$(Build.BinariesDirectory)/nuget-artifact-x86' - - - task: DownloadPipelineArtifact@0 - displayName: 'Download Pipeline Artifact - NuGet DirectML arm64' - inputs: - artifactName: 'Microsoft.AI.MachineLearning.arm64' - targetPath: '$(Build.BinariesDirectory)/nuget-artifact-arm64' - - - task: DownloadPipelineArtifact@0 - displayName: 'Download Pipeline Artifact - NuGet DirectML arm' - inputs: - artifactName: 'Microsoft.AI.MachineLearning.arm' - targetPath: '$(Build.BinariesDirectory)/nuget-artifact-arm' - - - task: DownloadPipelineArtifact@0 - displayName: 'Download Pipeline Artifact - NuGet DirectML x64 StaticRuntime' - inputs: - artifactName: 'Microsoft.AI.MachineLearning.x64.StaticRuntime' - targetPath: '$(Build.BinariesDirectory)/nuget-artifact-x64-static-runtime' - - - task: DownloadPipelineArtifact@0 - displayName: 'Download Pipeline Artifact - NuGet DirectML x86 StaticRuntime' - inputs: - artifactName: 'Microsoft.AI.MachineLearning.x86.StaticRuntime' - targetPath: '$(Build.BinariesDirectory)/nuget-artifact-x86-static-runtime' - - - task: DownloadPipelineArtifact@0 - displayName: 'Download Pipeline Artifact - NuGet DirectML arm64 StaticRuntime' - inputs: - artifactName: 'Microsoft.AI.MachineLearning.arm64.StaticRuntime' - targetPath: '$(Build.BinariesDirectory)/nuget-artifact-arm64-static-runtime' - - - task: DownloadPipelineArtifact@0 - displayName: 'Download Pipeline Artifact - NuGet DirectML arm StaticRuntime' - inputs: - artifactName: 'Microsoft.AI.MachineLearning.arm.StaticRuntime' - targetPath: '$(Build.BinariesDirectory)/nuget-artifact-arm-static-runtime' - - - task: PowerShell@2 - displayName: 'Bundle NuGet and other binaries' - inputs: - targetType: 'inline' - script: | - Add-Type -AssemblyName "System.IO.Compression.FileSystem" - - $nupkgs = (Get-ChildItem -Filter Microsoft.AI.MachineLearning*.nupkg -Recurse) - $x64_nuget_package_name = $nupkgs[0].Name - $x64_nuget_package = $nupkgs[0].FullName - $x64_nupkg_unzipped_directory_root = $nupkgs[0].Directory.FullName - $x64_nupkg_unzipped_directory = [System.IO.Path]::Combine($x64_nupkg_unzipped_directory_root, 'binaries', [System.IO.Path]::GetFileNameWithoutExtension($x64_nuget_package)) - [System.IO.Compression.ZipFile]::ExtractToDirectory($x64_nuget_package, $x64_nupkg_unzipped_directory) - - $nupkgs = (Get-ChildItem ..\nuget-artifact-x64-static-runtime -Filter Microsoft.AI.MachineLearning*.nupkg -Recurse) - $x64_static_runtime_nuget_package = $nupkgs[0].FullName - $x64_static_runtime_nupkg_unzipped_directory_root = $nupkgs[0].Directory.FullName - $x64_static_runtime_nupkg_unzipped_directory = [System.IO.Path]::Combine($x64_static_runtime_nupkg_unzipped_directory_root, 'binaries', [System.IO.Path]::GetFileNameWithoutExtension($x64_static_runtime_nuget_package)) - [System.IO.Compression.ZipFile]::ExtractToDirectory($x64_static_runtime_nuget_package, $x64_static_runtime_nupkg_unzipped_directory) - - $nupkgs = (Get-ChildItem ..\nuget-artifact-x86 -Filter Microsoft.AI.MachineLearning*.nupkg -Recurse) - $x86_nuget_package = $nupkgs[0].FullName - $x86_nupkg_unzipped_directory_root = $nupkgs[0].Directory.FullName - $x86_nupkg_unzipped_directory = [System.IO.Path]::Combine($x86_nupkg_unzipped_directory_root, 'binaries', [System.IO.Path]::GetFileNameWithoutExtension($x86_nuget_package)) - [System.IO.Compression.ZipFile]::ExtractToDirectory($x86_nuget_package, $x86_nupkg_unzipped_directory) - - $nupkgs = (Get-ChildItem ..\nuget-artifact-x86-static-runtime -Filter Microsoft.AI.MachineLearning*.nupkg -Recurse) - $x86_static_runtime_nuget_package = $nupkgs[0].FullName - $x86_static_runtime_nupkg_unzipped_directory_root = $nupkgs[0].Directory.FullName - $x86_static_runtime_nupkg_unzipped_directory = [System.IO.Path]::Combine($x86_static_runtime_nupkg_unzipped_directory_root, 'binaries', [System.IO.Path]::GetFileNameWithoutExtension($x86_static_runtime_nuget_package)) - [System.IO.Compression.ZipFile]::ExtractToDirectory($x86_static_runtime_nuget_package, $x86_static_runtime_nupkg_unzipped_directory) - - $nupkgs = (Get-ChildItem ..\nuget-artifact-arm64 -Filter Microsoft.AI.MachineLearning*.nupkg -Recurse) - $arm64_nuget_package = $nupkgs[0].FullName - $arm64_nupkg_unzipped_directory_root = $nupkgs[0].Directory.FullName - $arm64_nupkg_unzipped_directory = [System.IO.Path]::Combine($arm64_nupkg_unzipped_directory_root, 'binaries', [System.IO.Path]::GetFileNameWithoutExtension($arm64_nuget_package)) - [System.IO.Compression.ZipFile]::ExtractToDirectory($arm64_nuget_package, $arm64_nupkg_unzipped_directory) - - $nupkgs = (Get-ChildItem ..\nuget-artifact-arm64-static-runtime -Filter Microsoft.AI.MachineLearning*.nupkg -Recurse) - $arm64_static_runtime_nuget_package = $nupkgs[0].FullName - $arm64_static_runtime_nupkg_unzipped_directory_root = $nupkgs[0].Directory.FullName - $arm64_static_runtime_nupkg_unzipped_directory = [System.IO.Path]::Combine($arm64_static_runtime_nupkg_unzipped_directory_root, 'binaries', [System.IO.Path]::GetFileNameWithoutExtension($arm64_static_runtime_nuget_package)) - [System.IO.Compression.ZipFile]::ExtractToDirectory($arm64_static_runtime_nuget_package, $arm64_static_runtime_nupkg_unzipped_directory) - - $nupkgs = (Get-ChildItem ..\nuget-artifact-arm -Filter Microsoft.AI.MachineLearning*.nupkg -Recurse) - $arm_nuget_package = $nupkgs[0].FullName - $arm_nupkg_unzipped_directory_root = $nupkgs[0].Directory.FullName - $arm_nupkg_unzipped_directory = [System.IO.Path]::Combine($arm_nupkg_unzipped_directory_root, 'binaries', [System.IO.Path]::GetFileNameWithoutExtension($arm_nuget_package)) - [System.IO.Compression.ZipFile]::ExtractToDirectory($arm_nuget_package, $arm_nupkg_unzipped_directory) - - $nupkgs = (Get-ChildItem ..\nuget-artifact-arm-static-runtime -Filter Microsoft.AI.MachineLearning*.nupkg -Recurse) - $arm_static_runtime_nuget_package = $nupkgs[0].FullName - $arm_static_runtime_nupkg_unzipped_directory_root = $nupkgs[0].Directory.FullName - $arm_static_runtime_nupkg_unzipped_directory = [System.IO.Path]::Combine($arm_static_runtime_nupkg_unzipped_directory_root, 'binaries', [System.IO.Path]::GetFileNameWithoutExtension($arm_static_runtime_nuget_package)) - [System.IO.Compression.ZipFile]::ExtractToDirectory($arm_static_runtime_nuget_package, $arm_static_runtime_nupkg_unzipped_directory) - - $x64_static_runtime_path_old = [System.IO.Path]::Combine($x64_static_runtime_nupkg_unzipped_directory, 'runtimes', 'win-x64', '_native') - $x64_static_runtime_path_new = [System.IO.Path]::Combine($x64_nupkg_unzipped_directory, 'runtimes', 'win-x64', '_native', 'static') - $x86_runtime_path_old = [System.IO.Path]::Combine($x86_nupkg_unzipped_directory, 'runtimes', 'win-x86', '_native') - $x86_runtime_path_new = [System.IO.Path]::Combine($x64_nupkg_unzipped_directory, 'runtimes', 'win-x86', '_native') - $x86_static_runtime_path_old = [System.IO.Path]::Combine($x86_static_runtime_nupkg_unzipped_directory, 'runtimes', 'win-x86', '_native') - $x86_static_runtime_path_new = [System.IO.Path]::Combine($x64_nupkg_unzipped_directory, 'runtimes', 'win-x86', '_native', 'static') - $arm64_runtime_path_old = [System.IO.Path]::Combine($arm64_nupkg_unzipped_directory, 'runtimes', 'win-arm64', '_native') - $arm64_runtime_path_new = [System.IO.Path]::Combine($x64_nupkg_unzipped_directory, 'runtimes', 'win-arm64', '_native') - $arm64_static_runtime_path_old = [System.IO.Path]::Combine($arm64_static_runtime_nupkg_unzipped_directory, 'runtimes', 'win-arm64', '_native') - $arm64_static_runtime_path_new = [System.IO.Path]::Combine($x64_nupkg_unzipped_directory, 'runtimes', 'win-arm64', '_native', 'static') - $arm_runtime_path_old = [System.IO.Path]::Combine($arm_nupkg_unzipped_directory, 'runtimes', 'win-arm', '_native') - $arm_runtime_path_new = [System.IO.Path]::Combine($x64_nupkg_unzipped_directory, 'runtimes', 'win-arm', '_native') - $arm_static_runtime_path_old = [System.IO.Path]::Combine($arm_static_runtime_nupkg_unzipped_directory, 'runtimes', 'win-arm', '_native') - $arm_static_runtime_path_new = [System.IO.Path]::Combine($x64_nupkg_unzipped_directory, 'runtimes', 'win-arm', '_native', 'static') - $uap_build_path_old = [System.IO.Path]::Combine($x64_static_runtime_nupkg_unzipped_directory, 'build', 'native') - $uap_build_path_new = [System.IO.Path]::Combine($x64_nupkg_unzipped_directory, 'build', 'uap10.0') - - New-Item -Path $x64_static_runtime_path_new -ItemType Directory - New-Item -Path $x86_runtime_path_new -ItemType Directory - New-Item -Path $x86_static_runtime_path_new -ItemType Directory - New-Item -Path $arm64_runtime_path_new -ItemType Directory - New-Item -Path $arm64_static_runtime_path_new -ItemType Directory - New-Item -Path $arm_runtime_path_new -ItemType Directory - New-Item -Path $arm_static_runtime_path_new -ItemType Directory - - Copy-Item ([System.IO.Path]::Combine($x86_runtime_path_old, 'onnxruntime.dll')) $x86_runtime_path_new - Copy-Item ([System.IO.Path]::Combine($x86_runtime_path_old, 'onnxruntime.lib')) $x86_runtime_path_new - Copy-Item ([System.IO.Path]::Combine($x86_runtime_path_old, 'microsoft.ai.machinelearning.dll')) $x86_runtime_path_new - Copy-Item ([System.IO.Path]::Combine($x86_runtime_path_old, 'microsoft.ai.machinelearning.lib')) $x86_runtime_path_new - - Copy-Item ([System.IO.Path]::Combine($arm64_runtime_path_old, 'onnxruntime.dll')) $arm64_runtime_path_new - Copy-Item ([System.IO.Path]::Combine($arm64_runtime_path_old, 'onnxruntime.lib')) $arm64_runtime_path_new - Copy-Item ([System.IO.Path]::Combine($arm64_runtime_path_old, 'microsoft.ai.machinelearning.dll')) $arm64_runtime_path_new - Copy-Item ([System.IO.Path]::Combine($arm64_runtime_path_old, 'microsoft.ai.machinelearning.lib')) $arm64_runtime_path_new - - Copy-Item ([System.IO.Path]::Combine($arm_runtime_path_old, 'onnxruntime.dll')) $arm_runtime_path_new - Copy-Item ([System.IO.Path]::Combine($arm_runtime_path_old, 'onnxruntime.lib')) $arm_runtime_path_new - Copy-Item ([System.IO.Path]::Combine($arm_runtime_path_old, 'microsoft.ai.machinelearning.dll')) $arm_runtime_path_new - Copy-Item ([System.IO.Path]::Combine($arm_runtime_path_old, 'microsoft.ai.machinelearning.lib')) $arm_runtime_path_new - - Copy-Item ([System.IO.Path]::Combine($x64_static_runtime_path_old, 'onnxruntime.dll')) ([System.IO.Path]::Combine($x64_static_runtime_path_new, 'onnxruntime.dll')) - Copy-Item ([System.IO.Path]::Combine($x64_static_runtime_path_old, 'onnxruntime.lib')) ([System.IO.Path]::Combine($x64_static_runtime_path_new, 'onnxruntime.lib')) - Copy-Item ([System.IO.Path]::Combine($x64_static_runtime_path_old, 'microsoft.ai.machinelearning.dll')) ([System.IO.Path]::Combine($x64_static_runtime_path_new, 'microsoft.ai.machinelearning.dll')) - Copy-Item ([System.IO.Path]::Combine($x64_static_runtime_path_old, 'microsoft.ai.machinelearning.lib')) ([System.IO.Path]::Combine($x64_static_runtime_path_new, 'microsoft.ai.machinelearning.lib')) - - Copy-Item ([System.IO.Path]::Combine($x86_static_runtime_path_old, 'onnxruntime.dll')) ([System.IO.Path]::Combine($x86_static_runtime_path_new, 'onnxruntime.dll')) - Copy-Item ([System.IO.Path]::Combine($x86_static_runtime_path_old, 'onnxruntime.lib')) ([System.IO.Path]::Combine($x86_static_runtime_path_new, 'onnxruntime.lib')) - Copy-Item ([System.IO.Path]::Combine($x86_static_runtime_path_old, 'microsoft.ai.machinelearning.dll')) ([System.IO.Path]::Combine($x86_static_runtime_path_new, 'microsoft.ai.machinelearning.dll')) - Copy-Item ([System.IO.Path]::Combine($x86_static_runtime_path_old, 'microsoft.ai.machinelearning.lib')) ([System.IO.Path]::Combine($x86_static_runtime_path_new, 'microsoft.ai.machinelearning.lib')) - - Copy-Item ([System.IO.Path]::Combine($arm64_static_runtime_path_old, 'onnxruntime.dll')) ([System.IO.Path]::Combine($arm64_static_runtime_path_new, 'onnxruntime.dll')) - Copy-Item ([System.IO.Path]::Combine($arm64_static_runtime_path_old, 'onnxruntime.lib')) ([System.IO.Path]::Combine($arm64_static_runtime_path_new, 'onnxruntime.lib')) - Copy-Item ([System.IO.Path]::Combine($arm64_static_runtime_path_old, 'microsoft.ai.machinelearning.dll')) ([System.IO.Path]::Combine($arm64_static_runtime_path_new, 'microsoft.ai.machinelearning.dll')) - Copy-Item ([System.IO.Path]::Combine($arm64_static_runtime_path_old, 'microsoft.ai.machinelearning.lib')) ([System.IO.Path]::Combine($arm64_static_runtime_path_new, 'microsoft.ai.machinelearning.lib')) - - Copy-Item ([System.IO.Path]::Combine($arm_static_runtime_path_old, 'onnxruntime.dll')) ([System.IO.Path]::Combine($arm_static_runtime_path_new, 'onnxruntime.dll')) - Copy-Item ([System.IO.Path]::Combine($arm_static_runtime_path_old, 'onnxruntime.lib')) ([System.IO.Path]::Combine($arm_static_runtime_path_new, 'onnxruntime.lib')) - Copy-Item ([System.IO.Path]::Combine($arm_static_runtime_path_old, 'microsoft.ai.machinelearning.dll')) ([System.IO.Path]::Combine($arm_static_runtime_path_new, 'microsoft.ai.machinelearning.dll')) - Copy-Item ([System.IO.Path]::Combine($arm_static_runtime_path_old, 'microsoft.ai.machinelearning.lib')) ([System.IO.Path]::Combine($arm_static_runtime_path_new, 'microsoft.ai.machinelearning.lib')) - - Copy-Item -Recurse $uap_build_path_old $uap_build_path_new - - $merged_nuget_path = [System.IO.Path]::Combine($Env:BUILD_ARTIFACTSTAGINGDIRECTORY, 'merged') - if (!(Test-Path $merged_nuget_path)) { - New-Item -Path $merged_nuget_path -ItemType Directory - } - - $merged_nuget = [System.IO.Path]::Combine($merged_nuget_path, $x64_nuget_package_name) - $merged_nuget_as_zip = [System.IO.Path]::ChangeExtension($merged_nuget, '.zip') - - $zip_tool_directory = [System.IO.Path]::Combine($x64_nupkg_unzipped_directory_root, 'ziptool') - if (!(Test-Path $zip_tool_directory)) { - New-Item -Path $zip_tool_directory -ItemType Directory - } - - $zip_tool = [System.IO.Path]::Combine($zip_tool_directory, 'zip.exe') - - Invoke-WebRequest http://stahlworks.com/dev/zip.exe -OutFile $zip_tool - Start-Process -FilePath $zip_tool -ArgumentList "-r $merged_nuget ." -WorkingDirectory $x64_nupkg_unzipped_directory -NoNewWindow -Wait - - Copy-Item -Path $merged_nuget -Destination $merged_nuget_as_zip - workingDirectory: $(Build.BinariesDirectory)\nuget-artifact-x64 - - - task: PowerShell@2 - displayName: 'Bundle Symbols NuGet' - inputs: - targetType: 'inline' - script: | - Add-Type -AssemblyName "System.IO.Compression.FileSystem" - - $nupkgs = (Get-ChildItem -Filter Microsoft.AI.MachineLearning*.snupkg -Recurse) - $x64_nuget_package_name = $nupkgs[0].Name - $x64_nuget_package = $nupkgs[0].FullName - $x64_nupkg_unzipped_directory_root = $nupkgs[0].Directory.FullName - $x64_nupkg_unzipped_directory = [System.IO.Path]::Combine($x64_nupkg_unzipped_directory_root, 'symbols', [System.IO.Path]::GetFileNameWithoutExtension($x64_nuget_package)) - [System.IO.Compression.ZipFile]::ExtractToDirectory($x64_nuget_package, $x64_nupkg_unzipped_directory) - - $nupkgs = (Get-ChildItem ..\nuget-artifact-x86 -Filter Microsoft.AI.MachineLearning*.snupkg -Recurse) - $x86_nuget_package = $nupkgs[0].FullName - $x86_nupkg_unzipped_directory_root = $nupkgs[0].Directory.FullName - $x86_nupkg_unzipped_directory = [System.IO.Path]::Combine($x86_nupkg_unzipped_directory_root, 'symbols', [System.IO.Path]::GetFileNameWithoutExtension($x86_nuget_package)) - [System.IO.Compression.ZipFile]::ExtractToDirectory($x86_nuget_package, $x86_nupkg_unzipped_directory) - - $nupkgs = (Get-ChildItem ..\nuget-artifact-arm64 -Filter Microsoft.AI.MachineLearning*.snupkg -Recurse) - $arm64_nuget_package = $nupkgs[0].FullName - $arm64_nupkg_unzipped_directory_root = $nupkgs[0].Directory.FullName - $arm64_nupkg_unzipped_directory = [System.IO.Path]::Combine($arm64_nupkg_unzipped_directory_root, 'symbols', [System.IO.Path]::GetFileNameWithoutExtension($arm64_nuget_package)) - [System.IO.Compression.ZipFile]::ExtractToDirectory($arm64_nuget_package, $arm64_nupkg_unzipped_directory) - - $nupkgs = (Get-ChildItem ..\nuget-artifact-arm -Filter Microsoft.AI.MachineLearning*.snupkg -Recurse) - $arm_nuget_package = $nupkgs[0].FullName - $arm_nupkg_unzipped_directory_root = $nupkgs[0].Directory.FullName - $arm_nupkg_unzipped_directory = [System.IO.Path]::Combine($arm_nupkg_unzipped_directory_root, 'symbols', [System.IO.Path]::GetFileNameWithoutExtension($arm_nuget_package)) - [System.IO.Compression.ZipFile]::ExtractToDirectory($arm_nuget_package, $arm_nupkg_unzipped_directory) - - $x86_runtime_path_old = [System.IO.Path]::Combine($x86_nupkg_unzipped_directory, 'runtimes', 'win-x86', '_native') - $x86_runtime_path_new = [System.IO.Path]::Combine($x64_nupkg_unzipped_directory, 'runtimes', 'win-x86', '_native') - $arm64_runtime_path_old = [System.IO.Path]::Combine($arm64_nupkg_unzipped_directory, 'runtimes', 'win-arm64', '_native') - $arm64_runtime_path_new = [System.IO.Path]::Combine($x64_nupkg_unzipped_directory, 'runtimes', 'win-arm64', '_native') - $arm_runtime_path_old = [System.IO.Path]::Combine($arm_nupkg_unzipped_directory, 'runtimes', 'win-arm', '_native') - $arm_runtime_path_new = [System.IO.Path]::Combine($x64_nupkg_unzipped_directory, 'runtimes', 'win-arm', '_native') - - New-Item -Path $x86_runtime_path_new -ItemType Directory - New-Item -Path $arm64_runtime_path_new -ItemType Directory - New-Item -Path $arm_runtime_path_new -ItemType Directory - - Copy-Item ([System.IO.Path]::Combine($x86_runtime_path_old, 'onnxruntime.pdb')) $x86_runtime_path_new - Copy-Item ([System.IO.Path]::Combine($x86_runtime_path_old, 'microsoft.ai.machinelearning.pdb')) $x86_runtime_path_new - - Copy-Item ([System.IO.Path]::Combine($arm64_runtime_path_old, 'onnxruntime.pdb')) $arm64_runtime_path_new - Copy-Item ([System.IO.Path]::Combine($arm64_runtime_path_old, 'microsoft.ai.machinelearning.pdb')) $arm64_runtime_path_new - - Copy-Item ([System.IO.Path]::Combine($arm_runtime_path_old, 'onnxruntime.pdb')) $arm_runtime_path_new - Copy-Item ([System.IO.Path]::Combine($arm_runtime_path_old, 'microsoft.ai.machinelearning.pdb')) $arm_runtime_path_new - - $merged_nuget_path = [System.IO.Path]::Combine($Env:BUILD_ARTIFACTSTAGINGDIRECTORY, 'merged') - if (!(Test-Path $merged_nuget_path)) { - New-Item -Path $merged_nuget_path -ItemType Directory - } - - $merged_nuget = [System.IO.Path]::Combine($merged_nuget_path, $x64_nuget_package_name) - $merged_nuget_as_zip = [System.IO.Path]::ChangeExtension($merged_nuget, '.symbols.zip') - - $zip_tool_directory = [System.IO.Path]::Combine($x64_nupkg_unzipped_directory_root, 'ziptool') - if (!(Test-Path $zip_tool_directory)) { - New-Item -Path $zip_tool_directory -ItemType Directory - } - - $zip_tool = [System.IO.Path]::Combine($zip_tool_directory, 'zip.exe') - - Invoke-WebRequest http://stahlworks.com/dev/zip.exe -OutFile $zip_tool - Start-Process -FilePath $zip_tool -ArgumentList "-r $merged_nuget ." -WorkingDirectory $x64_nupkg_unzipped_directory -NoNewWindow -Wait - - Copy-Item -Path $merged_nuget -Destination $merged_nuget_as_zip - workingDirectory: $(Build.BinariesDirectory)\nuget-artifact-x64 - - - template: ../../templates/esrp_nuget.yml - parameters: - DisplayName: 'ESRP - sign NuGet package' - FolderPath: '$(Build.ArtifactStagingDirectory)/merged' - DoEsrp: 'true' - - - template: ../../templates/validate-package.yml - parameters: - PackageType: 'nuget' - PackagePath: '$(Build.ArtifactStagingDirectory)\merged' - PackageName: 'Microsoft.AI.MachineLearning*nupkg' - PlatformsSupported: 'win-x64,win-x86,win-arm64,win-arm' - VerifyNugetSigning: 'true' - - - task: BatchScript@1 - displayName: 'Setup VS2019 env vars' - inputs: - filename: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat' - arguments: x64 - modifyEnvironment: true - - - task: NuGetToolInstaller@0 - displayName: Use Nuget 5.7.0 - inputs: - versionSpec: 5.7.0 - - - task: PowerShell@2 - displayName: 'NuGet Tests: Restore Windows.AI.MachineLearning Nuget Package (CppWinRT)' - inputs: - targetType: 'inline' - script: | - Add-Type -AssemblyName "System.IO.Compression.FileSystem" - - $nupkgs = (Get-ChildItem -Filter Microsoft.AI.MachineLearning*) - $merged_nuget_package = $nupkgs[0] - $merged_nuget_package_name = $merged_nuget_package.Name - $matched_name = ($merged_nuget_package_name -match "Microsoft.AI.MachineLearning.(?.*).nupkg") - $package_version = $matches['version'] - - $src_root_dir = $Env:BUILD_SOURCESDIRECTORY; - $artifacts_staging_dir = $Env:BUILD_ARTIFACTSTAGINGDIRECTORY; - $merged_nuget_path = [System.IO.Path]::Combine($artifacts_staging_dir, 'merged') - $src_dir = [System.IO.Path]::Combine($src_root_dir, 'csharp', 'test', 'Microsoft.AI.MachineLearning.Tests') - $packages_dir = [System.IO.Path]::Combine($src_dir, 'packages') - $csproj = [System.IO.Path]::Combine($src_dir, 'Microsoft.AI.MachineLearning.Tests.vcxproj') - - $input_props = [System.IO.Path]::Combine($src_dir, 'Microsoft.AI.MachineLearning.Tests.props.pp') - $output_props = [System.IO.Path]::Combine($src_dir, 'Microsoft.AI.MachineLearning.Tests.props') - $input_props_content = Get-Content -Path $input_props - $output_props_content = $input_props_content -replace '\[PackageVersion\]', $package_version - Set-Content -Path $output_props -Value $output_props_content - - nuget restore -PackagesDirectory $packages_dir -Source https://api.nuget.org/v3/index.json -Source $merged_nuget_path $csproj - - $project_assets_json = [System.IO.Path]::Combine($src_dir, 'obj', 'project.assets.json') - Remove-Item -Force $project_assets_json - workingDirectory: $(Build.ArtifactStagingDirectory)\merged - - - task: PowerShell@2 - displayName: 'NuGet Tests: Build Tests (CppWinRT)' - inputs: - targetType: 'inline' - script: | - msbuild /p:Platform=x86 Microsoft.AI.MachineLearning.Tests.vcxproj - msbuild /p:Platform=x64 Microsoft.AI.MachineLearning.Tests.vcxproj - workingDirectory: $(Build.SourcesDirectory)\csharp\test\Microsoft.AI.MachineLearning.Tests - - - task: PowerShell@2 - displayName: 'NuGet Tests: Fix Nuget Package references (.NET 5.0)' - inputs: - targetType: 'inline' - script: | - Add-Type -AssemblyName "System.IO.Compression.FileSystem" - $src_root_dir = $Env:BUILD_SOURCESDIRECTORY; - $artifacts_staging_dir = $Env:BUILD_ARTIFACTSTAGINGDIRECTORY; - $merged_nuget_path = [System.IO.Path]::Combine($artifacts_staging_dir, 'merged') - $nupkgs = (Get-ChildItem -Filter Microsoft.AI.MachineLearning*) - $merged_nuget_package = $nupkgs[0] - $merged_nuget_package_name = $merged_nuget_package.Name - $matched_name = ($merged_nuget_package_name -match "Microsoft.AI.MachineLearning.(?.*).nupkg") - $package_version = $matches['version'] - $src_dir = [System.IO.Path]::Combine($src_root_dir, 'csharp', 'test', 'Microsoft.AI.MachineLearning.Tests.DotNet5_0') - $input_csproj = [System.IO.Path]::Combine($src_dir, 'Microsoft.AI.MachineLearning.Tests.DotNet5_0.csproj.pp') - $csproj = [System.IO.Path]::Combine($src_dir, 'Microsoft.AI.MachineLearning.Tests.DotNet5_0.csproj') - $input_csproj_content = Get-Content -Path $input_csproj - $csproj_content = $input_csproj_content -replace '\[PackageVersion\]', $package_version - Set-Content -Path $csproj -Value $csproj_content - $input_nuget_config = [System.IO.Path]::Combine($src_dir, 'NuGet.config.pp') - $nuget_config = [System.IO.Path]::Combine($src_dir, 'NuGet.config') - $input_nuget_config_content = Get-Content -Path $input_nuget_config - $nuget_config_content = $input_nuget_config_content -replace '\[BuildPackageSource\]', $merged_nuget_path - Set-Content -Path $nuget_config -Value $nuget_config_content - workingDirectory: $(Build.ArtifactStagingDirectory)\merged - - - task: PowerShell@2 - displayName: 'NuGet Tests: Build Tests (.NET 5.0)' - inputs: - targetType: 'inline' - script: | - msbuild Microsoft.AI.MachineLearning.Tests.DotNet5_0.csproj /p:Platform=x64 /t:Restore - msbuild Microsoft.AI.MachineLearning.Tests.DotNet5_0.csproj /p:Platform=x64 - msbuild Microsoft.AI.MachineLearning.Tests.DotNet5_0.csproj /p:Platform=AnyCpu /t:Restore - msbuild Microsoft.AI.MachineLearning.Tests.DotNet5_0.csproj /p:Platform=AnyCpu - workingDirectory: $(Build.SourcesDirectory)\csharp\test\Microsoft.AI.MachineLearning.Tests.DotNet5_0 - - - - task: PowerShell@2 - displayName: 'NuGet Tests: Fix Nuget Package references (C# UWP)' - inputs: - targetType: 'inline' - script: | - Add-Type -AssemblyName "System.IO.Compression.FileSystem" - $src_root_dir = $Env:BUILD_SOURCESDIRECTORY; - $artifacts_staging_dir = $Env:BUILD_ARTIFACTSTAGINGDIRECTORY; - $merged_nuget_path = [System.IO.Path]::Combine($artifacts_staging_dir, 'merged') - $nupkgs = (Get-ChildItem -Filter Microsoft.AI.MachineLearning*) - $merged_nuget_package = $nupkgs[0] - $merged_nuget_package_name = $merged_nuget_package.Name - $matched_name = ($merged_nuget_package_name -match "Microsoft.AI.MachineLearning.(?.*).nupkg") - $package_version = $matches['version'] - $src_dir = [System.IO.Path]::Combine($src_root_dir, 'csharp', 'test', 'Microsoft.AI.MachineLearning.Tests.Uwp') - $input_csproj = [System.IO.Path]::Combine($src_dir, 'Microsoft.AI.MachineLearning.Tests.Uwp.csproj.pp') - $csproj = [System.IO.Path]::Combine($src_dir, 'Microsoft.AI.MachineLearning.Tests.Uwp.csproj') - $input_csproj_content = Get-Content -Path $input_csproj - $csproj_content = $input_csproj_content -replace '\[PackageVersion\]', $package_version - Set-Content -Path $csproj -Value $csproj_content - $input_nuget_config = [System.IO.Path]::Combine($src_dir, 'NuGet.config.pp') - $nuget_config = [System.IO.Path]::Combine($src_dir, 'NuGet.config') - $input_nuget_config_content = Get-Content -Path $input_nuget_config - $nuget_config_content = $input_nuget_config_content -replace '\[BuildPackageSource\]', $merged_nuget_path - Set-Content -Path $nuget_config -Value $nuget_config_content - workingDirectory: $(Build.ArtifactStagingDirectory)\merged - - - task: PowerShell@2 - displayName: 'NuGet Tests: Build Tests (C# UWP)' - inputs: - targetType: 'inline' - script: | - msbuild Microsoft.AI.MachineLearning.Tests.Uwp.csproj /p:Platform=x64 /t:Restore - msbuild Microsoft.AI.MachineLearning.Tests.Uwp.csproj /p:Platform=x64 - msbuild Microsoft.AI.MachineLearning.Tests.Uwp.csproj /p:Platform=x86 /t:Restore - msbuild Microsoft.AI.MachineLearning.Tests.Uwp.csproj /p:Platform=x86 - msbuild Microsoft.AI.MachineLearning.Tests.Uwp.csproj /p:Platform=ARM /t:Restore - msbuild Microsoft.AI.MachineLearning.Tests.Uwp.csproj /p:Platform=ARM - msbuild Microsoft.AI.MachineLearning.Tests.Uwp.csproj /p:Platform=ARM64 /t:Restore - msbuild Microsoft.AI.MachineLearning.Tests.Uwp.csproj /p:Platform=ARM64 - workingDirectory: $(Build.SourcesDirectory)\csharp\test\Microsoft.AI.MachineLearning.Tests.Uwp - - - task: PowerShell@2 - displayName: 'NuGet Tests: Run Tests' - continueOnError: true - inputs: - targetType: 'inline' - script: | - Write-Host "Run Microsoft.AI.MachineLearning CppWinRT Tests (x86)" - pushd .\Microsoft.AI.MachineLearning.Tests\Debug - .\Microsoft.AI.MachineLearning.Tests.exe - popd - Write-Host "Run Microsoft.AI.MachineLearning CppWinRT Tests (x64)" - pushd .\Microsoft.AI.MachineLearning.Tests\x64\Debug - .\Microsoft.AI.MachineLearning.Tests.exe - popd - - Write-Host "Run Microsoft.AI.MachineLearning CSharp Tests (DotNet5_0)" - pushd .\Microsoft.AI.MachineLearning.Tests.DotNet5_0\bin\Debug\net5.0-windows10.0.17763.0 - .\Microsoft.AI.MachineLearning.Tests.DotNet5_0.exe - popd - - Write-Host "Run Microsoft.AI.MachineLearning CSharp Tests (AnyCpu)" - pushd .\Microsoft.AI.MachineLearning.Tests.DotNet5_0\bin\x64\Debug\net5.0-windows10.0.17763.0 - .\Microsoft.AI.MachineLearning.Tests.DotNet5_0.exe - popd - - Write-Host "Done!" - workingDirectory: $(Build.SourcesDirectory)\csharp\test - - - task: PublishPipelineArtifact@0 - displayName: 'Publish Pipeline NuGet Artifact' - inputs: - artifactName: 'drop-signed-nuget' - targetPath: '$(Build.ArtifactStagingDirectory)/merged' diff --git a/tools/ci_build/github/azure-pipelines/orttraining-linux-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/orttraining-linux-ci-pipeline.yml index f12dc28a19810..007630edb25be 100644 --- a/tools/ci_build/github/azure-pipelines/orttraining-linux-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/orttraining-linux-ci-pipeline.yml @@ -1,10 +1,39 @@ +##### start trigger Don't edit it manually, Please do edit 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 #### + resources: repositories: - repository: manylinux # The name used to reference this repository in the checkout step type: Github endpoint: Microsoft name: pypa/manylinux - ref: aead4d751c2101e23336aa73f2380df83e7a13f3 + ref: 5eda9aded5462201e6310105728d33016e637ea7 jobs: - job: Linux_Build @@ -36,10 +65,10 @@ jobs: - template: templates/get-docker-image-steps.yml parameters: - Dockerfile: tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_cpu - Context: tools/ci_build/github/linux/docker - DockerBuildArgs: "--build-arg BUILD_UID=$( id -u )" - Repository: onnxruntimecpubuild + Dockerfile: tools/ci_build/github/linux/docker/inference/x64/python/cpu/Dockerfile.manylinux2_28_cpu + Context: tools/ci_build/github/linux/docker/inference/x64/python/cpu + DockerBuildArgs: "--build-arg BUILD_UID=$( id -u ) --build-arg BASEIMAGE=registry.access.redhat.com/ubi8/ubi --build-arg PLATFORM=x86_64 --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 --build-arg DEVTOOLSET_ROOTPATH=/opt/rh/gcc-toolset-12/root" + Repository: onnxruntimecpubuildpythonx86_64 - task: Cache@2 inputs: @@ -67,12 +96,12 @@ jobs: -e NIGHTLY_BUILD \ -e BUILD_BUILDNUMBER \ -e CCACHE_DIR=/cache \ - onnxruntimecpubuild \ + onnxruntimecpubuildpythonx86_64 \ /bin/bash -c " set -ex; \ ccache -s; \ /opt/python/cp38-cp38/bin/python3 /onnxruntime_src/tools/ci_build/build.py \ - --build_dir /build --cmake_generator Ninja \ + --build_dir /build --cmake_generator 'Unix Makefiles' \ --config Release \ --skip_submodule_sync \ --build_shared_lib \ @@ -81,13 +110,13 @@ jobs: --enable_onnx_tests \ --enable_training \ --use_cache \ - --build_java --build_nodejs --update --build; \ + --update --build; \ ccache -sv; \ ccache -z" workingDirectory: $(Build.SourcesDirectory) - task: CmdLine@2 - displayName: 'Install python deps and run java tests' + displayName: 'Install python deps' inputs: script: | set -e -x @@ -99,8 +128,6 @@ jobs: mkdir $(Build.BinariesDirectory)/requirements_torch_cpu/ cp $(Build.SourcesDirectory)/tools/ci_build/github/linux/docker/scripts/training/ortmodule/stage1/requirements_torch_cpu/requirements.txt $(Build.BinariesDirectory)/requirements_torch_cpu/requirements.txt python3 -m pip install -r $(Build.BinariesDirectory)/requirements_torch_cpu/requirements.txt - cd $(Build.SourcesDirectory)/java - $(Build.SourcesDirectory)/java/gradlew "cmakeCheck" "-DcmakeBuildDir=$(Build.BinariesDirectory)/Release" - task: CmdLine@2 displayName: 'Install Release python package' @@ -125,7 +152,6 @@ jobs: --build_wheel --enable_onnx_tests --enable_training - --build_nodejs --ctest_path "" - task: PublishTestResults@2 diff --git a/tools/ci_build/github/azure-pipelines/orttraining-linux-external-custom-ops.yml b/tools/ci_build/github/azure-pipelines/orttraining-linux-external-custom-ops.yml deleted file mode 100644 index e614c90c91497..0000000000000 --- a/tools/ci_build/github/azure-pipelines/orttraining-linux-external-custom-ops.yml +++ /dev/null @@ -1,137 +0,0 @@ -resources: - repositories: - - repository: manylinux - type: Github - endpoint: Microsoft - name: pypa/manylinux - ref: aead4d751c2101e23336aa73f2380df83e7a13f3 - -jobs: -- job: Linux_Build - timeoutInMinutes: 120 - workspace: - clean: all - pool: onnxruntime-training-linux-ext-custom-ops - steps: - - checkout: self - clean: true - submodules: recursive - - - template: templates/get-docker-image-steps.yml - parameters: - Dockerfile: tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_eager_cpu - Context: tools/ci_build/github/linux/docker - DockerBuildArgs: "--build-arg BUILD_UID=$( id -u )" - Repository: onnxruntimecpubuild - - - task: CmdLine@2 - displayName: 'Create and start docker container' - inputs: - script: | - docker run -it -d \ - --name external_custom_ops_container \ - --volume /data/onnx:/data/onnx:ro \ - --volume $(Build.SourcesDirectory):/onnxruntime_src \ - --volume $(Build.BinariesDirectory):/build \ - --volume $HOME/.onnx:/home/onnxruntimedev/.onnx \ - onnxruntimecpubuild \ - /bin/bash - workingDirectory: $(Build.SourcesDirectory) - - - task: CmdLine@2 - displayName: 'ONNXRuntime build' - inputs: - script: | - mkdir -p $HOME/.onnx - docker exec -t \ - -e ALLOW_RELEASED_ONNX_OPSET_ONLY=0 \ - -e NIGHTLY_BUILD \ - -e BUILD_BUILDNUMBER \ - external_custom_ops_container \ - /opt/python/cp38-cp38/bin/python3 /onnxruntime_src/tools/ci_build/build.py \ - --build_dir /build \ - --config Debug Release \ - --parallel \ - --build_wheel \ - --skip_tests \ - --enable_training \ - --build_eager_mode \ - --enable_pybind \ - --enable_external_custom_op_schemas - workingDirectory: $(Build.SourcesDirectory) - - - task: CmdLine@2 - displayName: 'Install Release python package' - inputs: - script: | - rm -rf $(Build.BinariesDirectory)/Release/onnxruntime $(Build.BinariesDirectory)/Release/pybind11 - docker exec -t external_custom_ops_container \ - /bin/bash -c "/opt/python/cp38-cp38/bin/python3 -m pip install /build/Release/dist/*.whl" - workingDirectory: $(Build.BinariesDirectory) - - - task: CmdLine@2 - displayName: 'Install Pybind11' - inputs: - script: | - docker exec -t \ - -w /build/Debug/external_custom_ops \ - external_custom_ops_container \ - /opt/python/cp38-cp38/bin/python3 -m pip install pybind11 - workingDirectory: $(Build.BinariesDirectory) - - - task: CmdLine@2 - displayName: 'Build and Install custom ops python package' - inputs: - script: | - docker exec -t \ - -w /build/Debug/external_custom_ops \ - external_custom_ops_container \ - /opt/python/cp38-cp38/bin/python3 -m pip install . - workingDirectory: $(Build.BinariesDirectory) - - - task: CmdLine@2 - displayName: 'Test using external custom op module' - inputs: - script: | - docker exec -t \ - -w /build/Debug/external_custom_ops \ - external_custom_ops_container \ - /opt/python/cp38-cp38/bin/python3 test.py - workingDirectory: $(Build.BinariesDirectory) - - - - task: CmdLine@2 - displayName: 'Install Debug python package' - inputs: - script: | - rm -rf $(Build.BinariesDirectory)/Debug/onnxruntime $(Build.BinariesDirectory)/Debug/pybind11 - docker exec -t external_custom_ops_container \ - /bin/bash -c "/opt/python/cp38-cp38/bin/python3 -m pip install /build/Debug/dist/*.whl" - workingDirectory: $(Build.BinariesDirectory) - - - task: CmdLine@2 - displayName: 'Build and Install custom ops python package' - inputs: - script: | - docker exec -t \ - -w /build/Debug/external_custom_ops \ - external_custom_ops_container \ - /opt/python/cp38-cp38/bin/python3 -m pip install . - workingDirectory: $(Build.BinariesDirectory) - - - task: CmdLine@2 - displayName: 'Test using external custom op module' - inputs: - script: | - docker exec -t \ - -w /build/Debug/external_custom_ops \ - external_custom_ops_container \ - /opt/python/cp38-cp38/bin/python3 test.py - workingDirectory: $(Build.BinariesDirectory) - - - task: CmdLine@2 - displayName: 'Stop and remove docker container' - inputs: - script: | - docker stop external_custom_ops_container - docker rm external_custom_ops_container \ No newline at end of file diff --git a/tools/ci_build/github/azure-pipelines/orttraining-linux-gpu-amd-e2e-test-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/orttraining-linux-gpu-amd-e2e-test-ci-pipeline.yml deleted file mode 100644 index 8207a336880ff..0000000000000 --- a/tools/ci_build/github/azure-pipelines/orttraining-linux-gpu-amd-e2e-test-ci-pipeline.yml +++ /dev/null @@ -1,78 +0,0 @@ -trigger: none - -name: 'orttraining_amd_nightly_$(Date:yyyyMMdd)_$(Rev:r)' -pool: 'AMD-GPU' - -jobs: -- job: Onnxruntime_Linux_GPU_AMD_Training_E2E_Test - - timeoutInMinutes: 60 - - steps: - - checkout: self - clean: true - submodules: recursive - - - script: |- - echo "##vso[task.prependpath]/home/ciagent/conda/bin/" - echo "##vso[task.prependpath]/home/ciagent/pkg/openmpi-4.0.5/bin/" - echo '##vso[task.setvariable variable=LD_LIBRARY_PATH]/home/ciagent/pkg/openmpi-4.0.5/lib/' - eval "$('/home/ciagent/conda/bin/conda' 'shell.bash' 'hook' 2> /dev/null)" - echo "Selecting GPU based on HIP_VISIBLE_DEVICES=$HIP_VISIBLE_DEVICES" - displayName: 'Initialize environment' - - # update these if the E2E test data changes - - script: |- - export AZURE_BLOB_SAS_TOKEN="$(onnxruntimetestdata-storage-training-container-sas-token)" - python orttraining/tools/ci_test/download_azure_blob_archive.py \ - --azure_blob_url https://onnxruntimetestdata.blob.core.windows.net/training/onnxruntime_training_data.zip \ - --target_dir training_e2e_test_data \ - --archive_sha256_digest B01C169B6550D1A0A6F1B4E2F34AE2A8714B52DBB70AC04DA85D371F691BDFF9 - displayName: 'Download onnxruntime_training_data.zip data' - - - script: |- - python tools/ci_build/build.py \ - --config RelWithDebInfo \ - --enable_training \ - --mpi_home /home/ciagent/pkg/openmpi-4.0.5 \ - --use_rocm \ - --rocm_home /opt/rocm \ - --nccl_home /opt/rocm \ - --update \ - --build_dir ./build \ - --build \ - --parallel 8 \ - --build_wheel \ - --skip_tests - displayName: 'Build onnxruntime' - - - script: |- - cd ./build/RelWithDebInfo &&\ - ../../tools/ci_build/github/pai/pai_test_launcher.sh - displayName: 'Run onnxruntime unit tests' - - - script: |- - python orttraining/tools/ci_test/run_batch_size_test.py \ - --binary_dir build/RelWithDebInfo \ - --model_root training_e2e_test_data/models \ - --gpu_sku MI100_32G - displayName: 'Run C++ BERT-L batch size test' - condition: succeededOrFailed() # ensure all tests are run - - - script: |- - python orttraining/tools/ci_test/run_bert_perf_test.py \ - --binary_dir build/RelWithDebInfo \ - --model_root training_e2e_test_data/models \ - --training_data_root training_e2e_test_data/data \ - --gpu_sku MI100_32G - displayName: 'Run C++ BERT-L performance test' - condition: succeededOrFailed() # ensure all tests are run - - - script: |- - python orttraining/tools/ci_test/run_convergence_test.py \ - --binary_dir build/RelWithDebInfo \ - --model_root training_e2e_test_data/models \ - --training_data_root training_e2e_test_data/data \ - --gpu_sku MI100_32G - displayName: 'Run C++ BERT-L convergence test' - condition: succeededOrFailed() # ensure all tests are run diff --git a/tools/ci_build/github/azure-pipelines/orttraining-linux-gpu-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/orttraining-linux-gpu-ci-pipeline.yml index 89dd5cfe29f77..adf5695bd76eb 100644 --- a/tools/ci_build/github/azure-pipelines/orttraining-linux-gpu-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/orttraining-linux-gpu-ci-pipeline.yml @@ -1,4 +1,31 @@ -trigger: none +##### start trigger Don't edit it manually, Please do edit 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: - template: templates/linux-ci.yml @@ -21,7 +48,7 @@ jobs: " DoNugetPack: 'false' RunInjectedPipeline: 'true' - InjectedPipeline: 'orttraining-linux-gpu-ortmodule-test-ci-pipeline.yml' + InjectedPipeline: 'orttraining-linux-gpu-test-ci-pipeline.yml' DockerImageTag: 'onnxruntime_orttraining_ortmodule_tests_image' BuildConfig: $(buildConfig) ArtifactName: 'drop-linux' diff --git a/tools/ci_build/github/azure-pipelines/orttraining-linux-gpu-distributed-e2e-test-pipeline.yml b/tools/ci_build/github/azure-pipelines/orttraining-linux-gpu-distributed-e2e-test-pipeline.yml deleted file mode 100644 index 5f1cd9b21989c..0000000000000 --- a/tools/ci_build/github/azure-pipelines/orttraining-linux-gpu-distributed-e2e-test-pipeline.yml +++ /dev/null @@ -1,321 +0,0 @@ -trigger: none - -jobs: -- job: Orttraining_Linux_GPU_Distributed_E2E_Test - - timeoutInMinutes: 180 - pool: 'Onnxruntime-Linux-GPU-NC24sv3' - - steps: - - checkout: self - clean: true - submodules: recursive - - - template: templates/run-docker-build-steps.yml - parameters: - RunDockerBuildArgs: | - -o ubuntu20.04 -d gpu \ - -t onnxruntime_e2e_test_image \ - -x " \ - --config RelWithDebInfo \ - --enable_training \ - --update --build \ - --build_wheel --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=70 \ - " \ - -m - DisplayName: 'Build' - - # update these if the E2E test data changes - - script: | - orttraining/tools/ci_test/download_azure_blob_archive.py \ - --azure_blob_url https://onnxruntimetestdata.blob.core.windows.net/training/onnxruntime_training_data.zip?snapshot=2020-06-15T23:17:35.8314853Z \ - --target_dir $(Build.BinariesDirectory)/training_e2e_test_data \ - --archive_sha256_digest B01C169B6550D1A0A6F1B4E2F34AE2A8714B52DBB70AC04DA85D371F691BDFF9 - displayName: 'Download onnxruntime_training_data.zip data' - - - bash: tools/ci_build/github/linux/docker/scripts/training/azure_scale_set_vm_mount_test_data.sh -p $(orttrainingtestdatascus-storage-key) -s "//orttrainingtestdatascus.file.core.windows.net/bert-data" -d "/bert_data" - displayName: 'Mount bert-data' - condition: succeededOrFailed() - - - script: | - docker run \ - --gpus all \ - --shm-size=1024m \ - --rm \ - --volume $(Build.SourcesDirectory):/onnxruntime_src \ - --volume $(Build.BinariesDirectory):/build \ - onnxruntime_e2e_test_image \ - /build/RelWithDebInfo/launch_test.py \ - --cmd_line_with_args "python orttraining_distributed_tests.py" \ - --cwd /build/RelWithDebInfo \ - displayName: 'Run orttraining_distributed_tests.py' - condition: succeededOrFailed() - timeoutInMinutes: 120 - - - script: | - docker run \ - --gpus all \ - --shm-size=1024m \ - --rm \ - --volume $(Build.BinariesDirectory):/build \ - --volume /bert_data:/bert_data \ - onnxruntime_e2e_test_image \ - mpirun -n 4 \ - /build/RelWithDebInfo/onnxruntime_training_bert \ - --ort_log_severity 1 \ - --optimizer=Lamb \ - --learning_rate=3e-3 \ - --max_seq_length=128 \ - --max_predictions_per_seq=20 \ - --warmup_ratio=0.2843 \ - --warmup_mode=Poly \ - --model_name /bert_data/bert_models/nv/bert-large/bert-large-uncased_L_24_H_1024_A_16_V_30528_S_512_Dp_0.1_optimized_layer_norm_opset12 \ - --train_data_dir /bert_data/128/books_wiki_en_corpus/train \ - --test_data_dir /bert_data/128/books_wiki_en_corpus/test \ - --display_loss_steps 1 \ - --use_nccl \ - --use_mixed_precision \ - --allreduce_in_fp16 \ - --gradient_accumulation_steps 48 \ - --num_train_steps 96 \ - --train_batch_size 40 \ - --pipeline_parallel_size 4 \ - --cut_group_info 1149:407-1219/1341/1463/1585/1707/1829,1881:407-1951/2073/2195/2317/2439/2561,2613:407-2683/2805/2927/3049/3171/3293 - displayName: 'mpirun onnxruntime_training_bert --pipeline_parallel_size 4' - condition: succeededOrFailed() # ensure all tests are run - timeoutInMinutes: 10 - - - script: | - docker run \ - --gpus all \ - --shm-size=1024m \ - --rm \ - --volume $(Build.BinariesDirectory):/build \ - --volume /bert_data:/bert_data \ - onnxruntime_e2e_test_image \ - mpirun -n 4 \ - /build/RelWithDebInfo/onnxruntime_training_bert \ - --ort_log_severity 1 \ - --optimizer=Lamb \ - --learning_rate=3e-3 \ - --max_seq_length=128 \ - --max_predictions_per_seq=20 \ - --warmup_ratio=0.2843 \ - --warmup_mode=Poly \ - --model_name /bert_data/bert_models/nv/bert-large/bert-large-uncased_L_24_H_1024_A_16_V_30528_S_512_Dp_0.1_optimized_layer_norm_opset12 \ - --train_data_dir /bert_data/128/books_wiki_en_corpus/train \ - --test_data_dir /bert_data/128/books_wiki_en_corpus/test \ - --display_loss_steps 1 \ - --use_nccl \ - --use_mixed_precision \ - --allreduce_in_fp16 \ - --gradient_accumulation_steps 48 \ - --num_train_steps 96 \ - --train_batch_size 40 \ - --data_parallel_size 2 \ - --pipeline_parallel_size 2 \ - --cut_group_info 1881:407-1951/2073/2195/2317/2439/2561/2683/2805/2927/3049/3171/3293 - displayName: 'mpirun onnxruntime_training_bert --data_parallel_size 2 --pipeline_parallel_size 2' - condition: succeededOrFailed() # ensure all tests are run - timeoutInMinutes: 10 - - - script: | - docker run \ - --gpus all \ - --rm \ - --volume $(Build.SourcesDirectory):/onnxruntime_src \ - --volume $(Build.BinariesDirectory):/build \ - --volume $(Build.BinariesDirectory)/training_e2e_test_data:/training_e2e_test_data:ro \ - onnxruntime_e2e_test_image \ - /onnxruntime_src/orttraining/tools/ci_test/run_batch_size_test.py \ - --binary_dir /build/RelWithDebInfo \ - --model_root /training_e2e_test_data/models - displayName: 'Run batch size test' - condition: succeededOrFailed() # ensure all tests are run - - - script: | - docker run \ - --gpus all \ - --rm \ - --volume $(Build.SourcesDirectory):/onnxruntime_src \ - --volume $(Build.BinariesDirectory):/build \ - --volume $(Build.BinariesDirectory)/training_e2e_test_data:/training_e2e_test_data:ro \ - onnxruntime_e2e_test_image \ - /onnxruntime_src/orttraining/tools/ci_test/run_convergence_test.py \ - --binary_dir /build/RelWithDebInfo \ - --model_root /training_e2e_test_data/models \ - --training_data_root /training_e2e_test_data/data - displayName: 'Run convergence test' - condition: succeededOrFailed() # ensure all tests are run - - # migrated from frontend e2e pipeline - - script: | - docker run \ - --gpus all \ - --shm-size=1024m \ - --rm \ - --volume $(Build.SourcesDirectory):/onnxruntime_src \ - --volume $(Build.BinariesDirectory):/build \ - --volume /bert_data:/bert_data \ - onnxruntime_e2e_test_image \ - /build/RelWithDebInfo/launch_test.py \ - --cmd_line_with_args "python orttraining_run_frontend_batch_size_test.py -v" \ - --cwd /build/RelWithDebInfo \ - --env CUDA_VISIBLE_DEVICES 2 - displayName: 'Run orttraining_run_frontend_batch_size_test.py' - condition: succeededOrFailed() # ensure all tests are run - timeoutInMinutes: 30 - - - script: | - docker run \ - --gpus all \ - --shm-size=1024m \ - --rm \ - --volume $(Build.SourcesDirectory):/onnxruntime_src \ - --volume $(Build.BinariesDirectory):/build \ - --volume /bert_data:/bert_data \ - onnxruntime_e2e_test_image \ - /build/RelWithDebInfo/launch_test.py \ - --cmd_line_with_args "mpirun -n 4 -x NCCL_DEBUG=INFO python orttraining_run_glue.py" \ - --cwd /build/RelWithDebInfo - displayName: 'mpirun -n 4 -x NCCL_DEBUG=INFO python orttraining_run_glue.py' - condition: succeededOrFailed() # ensure all tests are run - timeoutInMinutes: 10 - - - script: | - docker run \ - --gpus all \ - --shm-size=1024m \ - --rm \ - --volume $(Build.SourcesDirectory):/onnxruntime_src \ - --volume $(Build.BinariesDirectory):/build \ - --volume /bert_data:/bert_data \ - onnxruntime_e2e_test_image \ - /build/RelWithDebInfo/launch_test.py \ - --cmd_line_with_args "python orttraining_run_glue.py ORTGlueTest.test_bert_with_mrpc -v" \ - --cwd /build/RelWithDebInfo \ - --env CUDA_VISIBLE_DEVICES 2 - displayName: 'Run orttraining_run_glue.py ORTGlueTest.test_bert_with_mrpc' - condition: succeededOrFailed() # ensure all tests are run - timeoutInMinutes: 10 - - - script: | - docker run \ - --gpus all \ - --shm-size=1024m \ - --rm \ - --volume $(Build.SourcesDirectory):/onnxruntime_src \ - --volume $(Build.BinariesDirectory):/build \ - --volume /bert_data:/bert_data \ - onnxruntime_e2e_test_image \ - /build/RelWithDebInfo/launch_test.py \ - --cmd_line_with_args "python orttraining_run_glue.py ORTGlueTest.test_bert_fp16_with_mrpc -v" \ - --cwd /build/RelWithDebInfo \ - --env CUDA_VISIBLE_DEVICES 2 - displayName: 'Run orttraining_run_glue.py ORTGlueTest.test_bert_fp16_with_mrpc' - condition: succeededOrFailed() # ensure all tests are run - timeoutInMinutes: 10 - - - script: | - docker run \ - --gpus all \ - --shm-size=1024m \ - --rm \ - --volume $(Build.SourcesDirectory):/onnxruntime_src \ - --volume $(Build.BinariesDirectory):/build \ - --volume /bert_data:/bert_data \ - onnxruntime_e2e_test_image \ - /build/RelWithDebInfo/launch_test.py \ - --cmd_line_with_args "python orttraining_run_glue.py ORTGlueTest.test_roberta_with_mrpc -v" \ - --cwd /build/RelWithDebInfo \ - --env CUDA_VISIBLE_DEVICES 2 - displayName: 'Run orttraining_run_glue.py ORTGlueTest.test_roberta_with_mrpc' - condition: succeededOrFailed() # ensure all tests are run - timeoutInMinutes: 10 - - - script: | - docker run \ - --gpus all \ - --shm-size=1024m \ - --rm \ - --volume $(Build.SourcesDirectory):/onnxruntime_src \ - --volume $(Build.BinariesDirectory):/build \ - --volume /bert_data:/bert_data \ - onnxruntime_e2e_test_image \ - /build/RelWithDebInfo/launch_test.py \ - --cmd_line_with_args "python orttraining_run_glue.py ORTGlueTest.test_roberta_fp16_with_mrpc -v" \ - --cwd /build/RelWithDebInfo \ - --env CUDA_VISIBLE_DEVICES 2 - displayName: 'Run orttraining_run_glue.py ORTGlueTest.test_roberta_fp16_with_mrpc' - condition: succeededOrFailed() # ensure all tests are run - timeoutInMinutes: 10 - - - script: | - docker run \ - --gpus all \ - --shm-size=1024m \ - --rm \ - --volume $(Build.SourcesDirectory):/onnxruntime_src \ - --volume $(Build.BinariesDirectory):/build \ - --volume /bert_data:/bert_data \ - onnxruntime_e2e_test_image \ - /build/RelWithDebInfo/launch_test.py \ - --cmd_line_with_args "python orttraining_run_multiple_choice.py ORTMultipleChoiceTest.test_bert_fp16_with_swag -v" \ - --cwd /build/RelWithDebInfo \ - --env CUDA_VISIBLE_DEVICES 2 - displayName: 'Run orttraining_run_multiple_choice.py ORTMultipleChoiceTest.test_bert_fp16_with_swag' - condition: succeededOrFailed() # ensure all tests are run - timeoutInMinutes: 30 - - - script: | - docker run \ - --gpus all \ - --shm-size=1024m \ - --rm \ - --volume $(Build.SourcesDirectory):/onnxruntime_src \ - --volume $(Build.BinariesDirectory):/build \ - --volume /bert_data:/bert_data \ - onnxruntime_e2e_test_image \ - /build/RelWithDebInfo/launch_test.py \ - --cmd_line_with_args "python onnxruntime_test_ort_trainer_with_mixed_precision.py -v" \ - --cwd /build/RelWithDebInfo - displayName: 'Run onnxruntime_test_ort_trainer_with_mixed_precision.py' - condition: succeededOrFailed() # ensure all tests are run - timeoutInMinutes: 10 - - - script: | - docker run \ - --gpus all \ - --rm \ - --volume $(Build.SourcesDirectory):/onnxruntime_src \ - --volume $(Build.BinariesDirectory):/build \ - --volume /bert_data:/bert_data \ - onnxruntime_e2e_test_image \ - /build/RelWithDebInfo/launch_test.py \ - --cmd_line_with_args "python orttraining_test_transformers.py BertModelTest.test_for_pretraining_mixed_precision -v" \ - --cwd /build/RelWithDebInfo - displayName: 'Run orttraining_test_transformers.py BertModelTest.test_for_pretraining_mixed_precision' - condition: succeededOrFailed() # ensure all tests are run - timeoutInMinutes: 10 - - - script: | - docker run \ - --gpus all \ - --shm-size=1024m \ - --rm \ - --volume $(Build.SourcesDirectory):/onnxruntime_src \ - --volume $(Build.BinariesDirectory):/build \ - --volume /bert_data:/bert_data \ - onnxruntime_e2e_test_image \ - /build/RelWithDebInfo/launch_test.py \ - --cmd_line_with_args "mpirun -n 4 -x NCCL_DEBUG=INFO python orttraining_run_bert_pretrain.py ORTBertPretrainTest.test_pretrain_convergence" \ - --cwd /build/RelWithDebInfo - displayName: 'Run orttraining_run_bert_pretrain.py ORTBertPretrainTest.test_pretrain_convergence' - condition: succeededOrFailed() # ensure all tests are run - timeoutInMinutes: 30 - - - template: templates/component-governance-component-detection-steps.yml - parameters: - condition: 'succeeded' - - - template: templates/clean-agent-build-directory-step.yml diff --git a/tools/ci_build/github/azure-pipelines/orttraining-linux-gpu-docker-release-pipeline.yml b/tools/ci_build/github/azure-pipelines/orttraining-linux-gpu-docker-release-pipeline.yml deleted file mode 100644 index d4a466639b322..0000000000000 --- a/tools/ci_build/github/azure-pipelines/orttraining-linux-gpu-docker-release-pipeline.yml +++ /dev/null @@ -1,76 +0,0 @@ -parameters: -- name: image_tag - displayName: Image Tag - type: string - default: latest - -variables: - docker_image_prefix: onnxruntime-training - linux_gpu_dockerfile: '$(Build.SourcesDirectory)/dockerfiles/Dockerfile.training' - docker_build_context: '$(Build.SourcesDirectory)/dockerfiles' - build_config: Release - -name: $(Date:yyyyMMdd)$(Rev:.r) -jobs: -- job: Linux_py_GPU_Build_Test_Release_Dockerfile - timeoutInMinutes: 110 - workspace: - clean: all - pool: Onnxruntime-Linux-GPU - steps: - - task: CmdLine@2 - displayName: Build builder stage of docker file - inputs: - script: | - docker build \ - --pull \ - -t ${{ variables.docker_image_prefix }}-manylinux-gpu-release-stage1 \ - --target builder \ - --no-cache \ - --build-arg COMMIT="$(Build.SourceVersion)" \ - --build-arg BUILD_CONFIG="${{ variables.build_config }}" \ - -f ${{ variables.linux_gpu_dockerfile }} \ - ${{ variables.docker_build_context }} - workingDirectory: $(Build.SourcesDirectory) - - - task: CmdLine@2 - displayName: Run tests - inputs: - script: | - docker run \ - --gpus all \ - --rm \ - ${{ variables.docker_image_prefix }}-manylinux-gpu-release-stage1 \ - python onnxruntime/tools/ci_build/build.py \ - --build_dir onnxruntime/build \ - --config ${{ variables.build_config }} \ - --test \ - --enable_onnx_tests - workingDirectory: $(Build.SourcesDirectory) - - - task: Docker@2 - displayName: Build entire docker file - inputs: - command: build - containerRegistry: 'ortrelease' - repository: 'onnxruntime-training' - arguments: --build-arg COMMIT="$(Build.SourceVersion)" --build-arg BUILD_CONFIG="${{ variables.build_config }}" - Dockerfile: '${{ variables.linux_gpu_dockerfile }}' - buildContext: '${{ variables.docker_build_context }}' - tags: | - $(Build.BuildNumber) - ${{ parameters.image_tag }} - - - task: Docker@2 - displayName: Push docker image - inputs: - command: push - containerRegistry: 'ortrelease' - repository: 'onnxruntime-training' - tags: | - $(Build.BuildNumber) - ${{ parameters.image_tag }} - - - template: templates/component-governance-component-detection-steps.yml - - - template: templates/clean-agent-build-directory-step.yml diff --git a/tools/ci_build/github/azure-pipelines/orttraining-linux-gpu-ortmodule-distributed-test-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/orttraining-linux-gpu-ortmodule-distributed-test-ci-pipeline.yml index cd6aeaf2daf62..f05d03bb54f9c 100644 --- a/tools/ci_build/github/azure-pipelines/orttraining-linux-gpu-ortmodule-distributed-test-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/orttraining-linux-gpu-ortmodule-distributed-test-ci-pipeline.yml @@ -1,4 +1,31 @@ -trigger: none +##### start trigger Don't edit it manually, Please do edit 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: ORTModuleDistributedTest diff --git a/tools/ci_build/github/azure-pipelines/orttraining-linux-gpu-ortmodule-test-clear-cache-pipeline.yml b/tools/ci_build/github/azure-pipelines/orttraining-linux-gpu-ortmodule-test-clear-cache-pipeline.yml deleted file mode 100644 index d99124bf573de..0000000000000 --- a/tools/ci_build/github/azure-pipelines/orttraining-linux-gpu-ortmodule-test-clear-cache-pipeline.yml +++ /dev/null @@ -1,25 +0,0 @@ -trigger: none - -jobs: -- job: Onnxruntime_Linux_GPU_ORTTraining_Clear_Cache - - timeoutInMinutes: 15 - pool: 'onnxruntime-Linux-CPU-2019' - - steps: - - checkout: self - clean: true - submodules: recursive - - - bash: tools/ci_build/github/linux/docker/scripts/training/azure_scale_set_vm_mount_test_data.sh -p $(orttrainingtestdatascus-storage-key) -s "//orttrainingtestdatascus.file.core.windows.net/hf-models-cache" -d "/hf_models_cache" - displayName: 'Mount hf-models-cache' - condition: succeededOrFailed() - - - bash: rm /hf_models_cache/huggingface/transformers/* - displayName: 'Clear huggingface transformers cache' - - - template: templates/component-governance-component-detection-steps.yml - parameters: - condition: 'succeeded' - - - template: templates/clean-agent-build-directory-step.yml diff --git a/tools/ci_build/github/azure-pipelines/orttraining-linux-gpu-training-apis.yml b/tools/ci_build/github/azure-pipelines/orttraining-linux-gpu-training-apis.yml deleted file mode 100644 index 96992dc7ca77d..0000000000000 --- a/tools/ci_build/github/azure-pipelines/orttraining-linux-gpu-training-apis.yml +++ /dev/null @@ -1,49 +0,0 @@ -trigger: none - -jobs: -- job: Onnxruntime_Linux_GPU_TrainingAPIs - - timeoutInMinutes: 120 - pool: 'Onnxruntime-Linux-GPU-NC6sv3' - - steps: - - checkout: self - clean: true - submodules: recursive - - - template: templates/run-docker-build-steps.yml - parameters: - RunDockerBuildArgs: | - -o ubuntu20.04 -d gpu -e \ - -t onnxruntime_training_apis_tests_image \ - -x " \ - --config RelWithDebInfo \ - --enable_training \ - --enable_training_apis \ - --use_cuda --cuda_version=11.8 --cuda_home=/usr/local/cuda-11.8 --cudnn_home=/usr/local/cuda-11.8 \ - --build_wheel \ - --build_java \ - --skip_tests \ - " \ - -u - DisplayName: 'Build onnxruntime' - - # Entry point for all ort training api tests - - script: | - docker run \ - --gpus all \ - --shm-size=1024m \ - --rm \ - --volume $(Build.SourcesDirectory):/onnxruntime_src \ - --volume $(Build.BinariesDirectory):/build \ - onnxruntime_training_apis_tests_image \ - /build/RelWithDebInfo/launch_test.py \ - --cwd /build/RelWithDebInfo --cmd_line_with_args "python orttraining_test_ort_apis.py --cwd /build/RelWithDebInfo" \ - displayName: 'Run ORT Training APIs Tests' - condition: succeededOrFailed() - timeoutInMinutes: 120 - - template: templates/component-governance-component-detection-steps.yml - parameters: - condition: 'succeeded' - - - template: templates/clean-agent-build-directory-step.yml diff --git a/tools/ci_build/github/azure-pipelines/orttraining-linux-nightly-ortmodule-test-pipeline.yml b/tools/ci_build/github/azure-pipelines/orttraining-linux-nightly-ortmodule-test-pipeline.yml index 39ae6f0160182..7824bf2203efe 100644 --- a/tools/ci_build/github/azure-pipelines/orttraining-linux-nightly-ortmodule-test-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/orttraining-linux-nightly-ortmodule-test-pipeline.yml @@ -13,12 +13,17 @@ jobs: # Entry point for all ortmodule training tests - script: | + COMMIT_ID=$(python3 -c "import onnxruntime; print(onnxruntime.get_build_info().split('git-commit-id=')[1].split(',')[0])") + cd $(Build.SourcesDirectory) + git checkout $COMMIT_ID + git branch + echo "Retrieved ONNX Runtime Commit ID: $COMMIT_ID" docker run \ --gpus all \ --rm \ --volume $(Build.SourcesDirectory)/orttraining/orttraining/test/python:/onnxruntime_src \ --volume $(Build.SourcesDirectory)/tools/ci_build/github/linux/docker/scripts/training/ortmodule/stage1/requirements_torch_nightly:/requirements_torch_nightly \ - ptebic.azurecr.io/internal/azureml/aifx/nightly-ubuntu2004-cu117-py38-torch200dev \ + ptebic.azurecr.io/internal/aifx/acpt/nightly-ubuntu-cuda-torch-dev \ bash -c "python3 -m pip install -r /requirements_torch_nightly/requirements.txt && python3 -m pytest -sv /onnxruntime_src/orttraining_test_ortmodule_api.py" displayName: 'Run ORTModule Tests' condition: succeededOrFailed() diff --git a/tools/ci_build/github/azure-pipelines/orttraining-mac-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/orttraining-mac-ci-pipeline.yml index 57e53ad2451d3..a04de65e3c37e 100644 --- a/tools/ci_build/github/azure-pipelines/orttraining-mac-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/orttraining-mac-ci-pipeline.yml @@ -1,7 +1,36 @@ +##### start trigger Don't edit it manually, Please do edit 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: --enable_training + AdditionalBuildFlags: --enable_training --build_objc WithCache: true diff --git a/tools/ci_build/github/azure-pipelines/orttraining-pai-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/orttraining-pai-ci-pipeline.yml index 3feaa6405c008..8dd1f0c5c6461 100644 --- a/tools/ci_build/github/azure-pipelines/orttraining-pai-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/orttraining-pai-ci-pipeline.yml @@ -1,55 +1,160 @@ trigger: none +pr: + branches: + include: + - main + - rel-* + paths: + exclude: + - 'js/web' + - 'onnxruntime/core/providers/js' name: 'orttraining_ci_$(Date:yyyyMMdd)_$(Rev:r)' + +resources: + repositories: + - repository: manylinux + type: Github + endpoint: Microsoft + name: pypa/manylinux + ref: 5eda9aded5462201e6310105728d33016e637ea7 + +variables: + - name: video + value: 44 + - name: render + value: 109 + - name: RocmVersion + value: 5.6 + - name: BuildConfig + value: Release + jobs: -- job: AMD_CI +- job: Linux_Build_manylinux + variables: + skipComponentGovernanceDetection: true + CCACHE_DIR: $(Pipeline.Workspace)/ccache + TODAY: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)] workspace: clean: all - pool: 'AMD-GPU' - timeoutInMinutes: 150 + pool: onnxruntime-Ubuntu2004-AMD-CPU + timeoutInMinutes: 120 + + steps: + - task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3 + displayName: 'Clean Agent Directories' + condition: always() + + - checkout: self + clean: true + submodules: recursive + + - 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 + --network=host --build-arg POLICY=manylinux_2_28 --build-arg PLATFORM=x86_64 + --build-arg BUILD_UID=$(id -u) + --build-arg ROCM_VERSION=$(RocmVersion) + --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: onnxruntimetrainingrocm-cibuild-rocm$(RocmVersion)-manylinux-build + + - task: Cache@2 + inputs: + key: '"manylinux" | "$(TODAY)" | "$(Build.SourceBranch)" | "$(Build.SourceVersion)"' + path: $(CCACHE_DIR) + cacheHitVar: CACHE_RESTORED + restoreKeys: | + "manylinux" | "$(TODAY)" | "$(Build.SourceBranch)" + "manylinux" | "$(TODAY)" | + displayName: Cache Task - # gid of video and render group on gcramdrr1-mi100-085 and -86 + - script: mkdir -p $(CCACHE_DIR) + condition: ne(variables.CACHE_RESTORED, 'true') + displayName: Create Cache Dir + + - task: CmdLine@2 + inputs: + script: |- + export ROCM_HOME=/opt/rocm + docker run --rm \ + --ipc=host \ + --network=host \ + --cap-add=SYS_PTRACE \ + --security-opt seccomp=unconfined \ + --shm-size=1024m \ + --user $UID:$(id -g $USER) \ + -e CC=/opt/rh/gcc-toolset-12/root/usr/bin/cc -e CXX=/opt/rh/gcc-toolset-12/root/usr/bin/c++ -e CFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all" -e CXXFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all" \ + -e CCACHE_DIR=/cache \ + --volume $(Build.SourcesDirectory):/onnxruntime_src \ + --volume $(Build.BinariesDirectory):/build \ + --volume $(CCACHE_DIR):/cache \ + --workdir /onnxruntime_src \ + onnxruntimetrainingrocm-cibuild-rocm$(RocmVersion)-manylinux-build \ + /bin/bash -c " + set -ex; \ + ccache -s; \ + /opt/python/cp38-cp38/bin/python3 tools/ci_build/build.py \ + --config $(BuildConfig) \ + --enable_training \ + --mpi_home /opt/ompi \ + --cmake_extra_defines \ + CMAKE_HIP_COMPILER=${ROCM_HOME}/llvm/bin/clang++ \ + onnxruntime_BUILD_UNIT_TESTS=OFF \ + FETCHCONTENT_TRY_FIND_PACKAGE_MODE=NEVER \ + --use_cache \ + --use_rocm \ + --rocm_version=$(RocmVersion) \ + --rocm_home ${ROCM_HOME} \ + --nccl_home ${ROCM_HOME}\ + --update \ + --build_dir /build \ + --build \ + --parallel \ + --build_wheel \ + --skip_submodule_sync \ + --skip_tests; \ + ccache -sv; \ + ccache -z" + displayName: 'Build onnxruntime' + + - template: templates/explicitly-defined-final-tasks.yml + +- job: Linux_Build_ubuntu variables: - - name: video - value: 44 - - name: render - value: 109 - - name: onnxruntimeBuildSucceeded - value: false - - name: RocmVersion - value: 5.4 - - name: CCACHE_DIR - value: $(Pipeline.Workspace)/ccache - - name: TODAY - value: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)] - - # generated from tools/ci_build/github/pai/rocm-ci-pipeline-env.Dockerfile - container: - image: onnxruntimecibuildenvironment.azurecr.io/rocm-ci-pipeline-env:rocm$(RocmVersion) - endpoint: onnxruntimecibuildenvironmentforamd - options: --privileged -e HIP_VISIBLE_DEVICES --security-opt seccomp=unconfined --shm-size=1024m --device=/dev/kfd --device=/dev/dri --group-add $(video) --group-add $(render) + skipComponentGovernanceDetection: true + CCACHE_DIR: $(Pipeline.Workspace)/ccache + TODAY: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)] + workspace: + clean: all + pool: onnxruntime-Ubuntu2004-AMD-CPU + timeoutInMinutes: 120 steps: + - task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3 + displayName: 'Clean Agent Directories' + condition: always() + - checkout: self clean: true + submodules: recursive - - script: |- - echo "Selecting GPU based on HIP_VISIBLE_DEVICES=$HIP_VISIBLE_DEVICES" - displayName: 'Initialize environment' + - template: templates/get-docker-image-steps.yml + parameters: + Dockerfile: tools/ci_build/github/pai/rocm-ci-pipeline-env.Dockerfile + Context: tools/ci_build/github/linux/docker + DockerBuildArgs: "--build-arg ROCM_VERSION=$(RocmVersion)" + Repository: onnxruntimetrainingrocm-cibuild-rocm$(RocmVersion)-build #- script: |- # sed -i 's|session_options.use_deterministic_compute = False|session_options.use_deterministic_compute = True|g' \ # orttraining/orttraining/python/training/ortmodule/_graph_execution_manager.py # displayName: 'Toggle ON deterministic compute mode for ORTModule' - - task: CmdLine@2 - displayName: 'Check ROCm Environment' - inputs: - script: |- - echo $(Agent.Name) - bash ./tools/ci_build/github/pai/pai_get_thread.sh $(Agent.Name) - target: host - - task: Cache@2 inputs: key: '"$(TODAY)" | "$(Build.SourceBranch)" | "$(Build.SourceVersion)"' @@ -64,344 +169,206 @@ jobs: condition: ne(variables.CACHE_RESTORED, 'true') displayName: Create Cache Dir - - script: ccache -s && ccache -z - displayName: Show Cache Stats Before Building - - task: CmdLine@2 inputs: script: |- export ROCM_HOME=/opt/rocm - python tools/ci_build/build.py \ - --config Release \ - --enable_training \ - --mpi_home /opt/ompi \ - --cmake_extra_defines \ - CMAKE_HIP_COMPILER=${ROCM_HOME}/llvm/bin/clang++ \ - onnxruntime_BUILD_KERNEL_EXPLORER=ON \ - --use_cache \ - --use_rocm \ - --rocm_version=$(RocmVersion) \ - --rocm_home ${ROCM_HOME} \ - --nccl_home ${ROCM_HOME}\ - --update \ - --build_dir ./build \ - --build \ - --parallel 32 \ - --build_wheel \ - --skip_tests + docker run --rm \ + --security-opt seccomp=unconfined \ + --shm-size=1024m \ + --user $UID:$(id -g $USER) \ + --volume $(Build.SourcesDirectory):/onnxruntime_src \ + --volume $(Build.BinariesDirectory):/build \ + --volume $(CCACHE_DIR):/cache \ + -e CCACHE_DIR=/cache \ + --workdir /onnxruntime_src \ + onnxruntimetrainingrocm-cibuild-rocm$(RocmVersion)-build \ + /bin/bash -c " + set -ex; \ + ccache -s; \ + python tools/ci_build/build.py \ + --config $(BuildConfig) \ + --enable_training \ + --mpi_home /opt/ompi \ + --cmake_extra_defines \ + CMAKE_HIP_COMPILER=${ROCM_HOME}/llvm/bin/clang++ \ + onnxruntime_BUILD_KERNEL_EXPLORER=ON \ + --use_cache \ + --use_rocm \ + --rocm_version=$(RocmVersion) \ + --rocm_home ${ROCM_HOME} \ + --nccl_home ${ROCM_HOME}\ + --update \ + --build_dir /build \ + --build \ + --parallel \ + --build_wheel \ + --skip_submodule_sync \ + --skip_tests; \ + ccache -sv; \ + ccache -z" displayName: 'Build onnxruntime' - - script: | - ccache -sv - ccache -z - displayName: Show Cache Stats After Building - - - bash: |- - echo "##vso[task.setvariable variable=onnxruntimeBuildSucceeded]true" - displayName: 'Set Onnxruntime Build Succeeded' - - - task: CmdLine@2 + - task: PublishPipelineArtifact@0 + displayName: 'Publish Pipeline Artifact' inputs: - script: |- - cd ./build/Release &&\ - ../../tools/ci_build/github/pai/pai_test_launcher.sh - displayName: 'Run onnxruntime unit tests' - - - task: CmdLine@2 - inputs: - script: |- - export KERNEL_EXPLORER_BUILD_DIR=./build/Release - pytest ./onnxruntime/python/tools/kernel_explorer/ -n 16 --reruns 1 - displayName: 'Run kernel explorer tests' - condition: and(succeededOrFailed(), eq(variables.onnxruntimeBuildSucceeded, 'true')) + artifactName: 'drop-linux' + targetPath: '$(Build.BinariesDirectory)/Release' - - task: CmdLine@2 - inputs: - script: |- - cd ./build/Release - export PYTHONPATH=$PWD - python -m onnxruntime.training.ortmodule.torch_cpp_extensions.install - displayName: 'Compile torch extensions into build directory' - condition: and(succeededOrFailed(), eq(variables.onnxruntimeBuildSucceeded, 'true')) # ensure all tests are run when the build successed + - template: templates/explicitly-defined-final-tasks.yml - - task: CmdLine@2 - inputs: - script: |- - cd ./build/Release - export PYTHONPATH=$PWD - export ORTMODULE_ONNX_OPSET_VERSION=15 - python \ - /stage/huggingface-transformers/examples/pytorch/language-modeling/run_mlm.py \ - --model_name_or_path bert-large-uncased \ - --dataset_name wikitext \ - --dataset_config_name wikitext-2-raw-v1 \ - --do_train \ - --max_steps 260 \ - --logging_steps 20 \ - --output_dir ./test-mlm-bbu \ - --overwrite_output_dir \ - --per_device_train_batch_size 8 \ - --fp16 \ - --dataloader_num_workers 1 \ - --ort \ - --skip_memory_metrics - python ../../orttraining/tools/ci_test/compare_huggingface.py \ - ci-pipeline-actual.json \ - ../../orttraining/tools/ci_test/results/ci-mi100.huggingface.bert-large-rocm$(RocmVersion).json - displayName: 'Run Python Hugging-Face BERT-L test' - retryCountOnTaskFailure: 1 - condition: and(succeededOrFailed(), eq(variables.onnxruntimeBuildSucceeded, 'true')) # ensure all tests are run when the build successed - - - task: CmdLine@2 - inputs: - script: |- - cd ./build/Release - export PYTHONPATH=$PWD - export ORTMODULE_ONNX_OPSET_VERSION=15 - python \ - /stage/huggingface-transformers/examples/pytorch/language-modeling/run_clm.py \ - --model_name_or_path gpt2 \ - --dataset_name wikitext \ - --dataset_config_name wikitext-2-raw-v1 \ - --do_train \ - --label_smoothing 0.1 \ - --max_steps 260 \ - --logging_steps 20 \ - --overwrite_output_dir \ - --output_dir ./test-clm \ - --per_device_train_batch_size 8 \ - --fp16 \ - --dataloader_num_workers 1 \ - --ort \ - --skip_memory_metrics - python ../../orttraining/tools/ci_test/compare_huggingface.py \ - ci-pipeline-actual.json \ - ../../orttraining/tools/ci_test/results/ci-mi100.huggingface.gpt2-rocm$(RocmVersion).json - displayName: 'Run Python Hugging-Face GPT2 test' - retryCountOnTaskFailure: 1 - condition: and(succeededOrFailed(), eq(variables.onnxruntimeBuildSucceeded, 'true')) # ensure all tests are run when the build successed - -# - script: |- -# cd ./build/Release -# export PYTHONPATH=$PWD -# python \ -# /stage/huggingface-transformers/examples/pytorch/translation/run_translation.py \ -# --dataset_name wmt16 \ -# --dataset_config ro-en \ -# --model_name_or_path facebook/bart-large \ -# --output_dir ./tst-translation \ -# --do_train \ -# --label_smoothing 0.1 \ -# --logging_steps 20 \ -# --overwrite_output_dir \ -# --per_device_train_batch_size 16 \ -# --predict_with_generate \ -# --source_lang en --target_lang ro \ -# --warmup_steps 5 \ -# --fp16 \ -# --max_steps 260 \ -# --dataloader_num_workers 1 \ -# --ort \ -# --skip_memory_metrics -# python ../../orttraining/tools/ci_test/compare_huggingface.py \ -# ci-pipeline-actual.json \ -# ../../orttraining/tools/ci_test/results/ci-mi100.huggingface.bart-large-rocm5.2.json -# displayName: 'Run Python Hugging-Face BART-L test' -# condition: succeededOrFailed() # ensure all tests are run - - # todo: investigate RoBERTa high run variability on ROCm 5.2 - #- script: |- - # cd ./build/Release - # export PYTHONPATH=$PWD - # python \ - # /stage/huggingface-transformers/examples/pytorch/question-answering/run_qa.py \ - # --model_name_or_path roberta-large \ - # --dataset_name squad \ - # --do_train \ - # --per_device_train_batch_size 16 \ - # --learning_rate 3e-5 \ - # --max_steps 260 \ - # --max_seq_length 384 \ - # --doc_stride 128 \ - # --output_dir ./roberta_res \ - # --overwrite_output_dir \ - # --logging_steps 20 \ - # --fp16 \ - # --dataloader_num_workers 1 \ - # --ort \ - # --skip_memory_metrics - # python ../../orttraining/tools/ci_test/compare_huggingface.py \ - # ci-pipeline-actual.json \ - # ../../orttraining/tools/ci_test/results/ci-mi100.huggingface.roberta-large-rocm5.2.json - # displayName: 'Run Python Hugging-Face RoBERTa-L test' - # condition: succeededOrFailed() # ensure all tests are run +- job: Linux_Test_ubuntu + workspace: + clean: all + pool: AMD-GPU + dependsOn: + - Linux_Build_ubuntu + timeoutInMinutes: 120 - - task: CmdLine@2 + steps: + - task: DownloadPipelineArtifact@2 + displayName: 'Download Pipeline Artifact' inputs: - script: |- - cd ./build/Release - export PYTHONPATH=$PWD - export ORTMODULE_ONNX_OPSET_VERSION=15 - python \ - /stage/huggingface-transformers/examples/pytorch/language-modeling/run_mlm.py \ - --model_name_or_path distilbert-base-uncased \ - --dataset_name wikitext \ - --dataset_config_name wikitext-2-raw-v1 \ - --do_train \ - --max_steps 260 \ - --logging_steps 20 \ - --output_dir ./test-mlm-bbu \ - --overwrite_output_dir \ - --per_device_train_batch_size 32 \ - --fp16 \ - --dataloader_num_workers 1 \ - --ort \ - --skip_memory_metrics - python ../../orttraining/tools/ci_test/compare_huggingface.py \ - ci-pipeline-actual.json \ - ../../orttraining/tools/ci_test/results/ci-mi100.huggingface.distilbert-base-rocm$(RocmVersion).json - displayName: 'Run Python Hugging-Face DistilBERT test' - retryCountOnTaskFailure: 1 - condition: and(succeededOrFailed(), eq(variables.onnxruntimeBuildSucceeded, 'true')) # ensure all tests are run when the build successed + buildType: 'current' + artifactName: 'drop-linux' + targetPath: '$(Build.BinariesDirectory)/Release' - #- script: |- - # cd ./build/Release - # export PYTHONPATH=$PWD - # python \ - # /stage/huggingface-transformers/examples/pytorch/text-classification/run_glue.py \ - # --model_name_or_path microsoft/deberta-v2-xxlarge \ - # --task_name MRPC \ - # --do_train \ - # --max_seq_length 128 \ - # --per_device_train_batch_size 4 \ - # --learning_rate 3e-6 \ - # --max_steps 260 \ - # --output_dir ./deberta_res \ - # --overwrite_output_dir \ - # --logging_steps 20 \ - # --fp16 \ - # --dataloader_num_workers 1 \ - # --ort \ - # --skip_memory_metrics - # displayName: 'Run Python Hugging-Face DeBERTa-XXL v2 test' - # condition: succeededOrFailed() # ensure all tests are run + - checkout: self + clean: true + submodules: recursive - #- script: |- - # cd ./build/Release - # export PYTHONPATH=$PWD - # python \ - # /stage/huggingface-transformers/examples/pytorch/translation/run_translation.py \ - # --source_prefix '"translate English to Romanian:"' \ - # --dataset_name wmt16 \ - # --dataset_config ro-en \ - # --model_name_or_path t5-large \ - # --output_dir ./tst-translation \ - # --do_train \ - # --label_smoothing 0.1 \ - # --logging_steps 20 \ - # --overwrite_output_dir \ - # --per_device_train_batch_size 16 \ - # --predict_with_generate \ - # --source_lang en \ - # --target_lang ro \ - # --warmup_steps 5 \ - # --fp16 \ - # --max_steps 260 \ - # --dataloader_num_workers 1 \ - # --ort \ - # --skip_memory_metrics - # python ../../orttraining/tools/ci_test/compare_huggingface.py \ - # ci-pipeline-actual.json \ - # ../../orttraining/tools/ci_test/results/ci-mi100.huggingface.t5-large.json - # displayName: 'Run Python Hugging-Face T5-L test' - # condition: succeededOrFailed() # ensure all tests are run + - template: templates/get-docker-image-steps.yml + parameters: + Dockerfile: tools/ci_build/github/pai/rocm-ci-pipeline-env.Dockerfile + Context: tools/ci_build/github/linux/docker + DockerBuildArgs: "--build-arg BUILD_UID=$( id -u ) --build-arg ROCM_VERSION=$(RocmVersion)" + Repository: onnxruntimetrainingrocm-cibuild-rocm$(RocmVersion)-test - - task: CmdLine@2 + - task: Bash@3 inputs: - script: |- - export AZURE_BLOB_SAS_TOKEN="$(onnxruntimetestdata-storage-training-container-sas-token)" - python orttraining/tools/ci_test/download_azure_blob_archive.py \ - --azure_blob_url https://onnxruntimetestdata.blob.core.windows.net/training/onnxruntime_training_data.zip \ - --target_dir training_e2e_test_data \ - --archive_sha256_digest B01C169B6550D1A0A6F1B4E2F34AE2A8714B52DBB70AC04DA85D371F691BDFF9 - condition: and(succeededOrFailed(), eq(variables.onnxruntimeBuildSucceeded, 'true')) # ensure all tests are run when the build successed - retryCountOnTaskFailure: 2 - displayName: 'Download onnxruntime_training_data.zip data' + targetType: filePath + filePath: $(Build.SourcesDirectory)/tools/ci_build/github/pai/pai_clean_device.sh + arguments: -n $(Agent.Name) -d $HIP_VISIBLE_DEVICES -r $DRIVER_RENDER + displayName: 'Check ROCm Environment' - task: CmdLine@2 inputs: script: |- - python orttraining/tools/ci_test/run_batch_size_test.py \ - --binary_dir build/Release \ - --model_root training_e2e_test_data/models \ - --gpu_sku MI100_32G - displayName: 'Run C++ BERT-L batch size test' - retryCountOnTaskFailure: 1 - condition: and(succeededOrFailed(), eq(variables.onnxruntimeBuildSucceeded, 'true')) # ensure all tests are run when the build successed + docker run --rm \ + --security-opt seccomp=unconfined \ + --shm-size=1024m \ + --device=/dev/kfd \ + --device=/dev/dri/renderD$DRIVER_RENDER \ + --group-add $(video) \ + --group-add $(render) \ + --user onnxruntimedev \ + --volume $(Build.SourcesDirectory):/onnxruntime_src \ + --volume $(Build.BinariesDirectory):/build \ + --workdir /build/$(BuildConfig) \ + onnxruntimetrainingrocm-cibuild-rocm$(RocmVersion)-test \ + /bin/bash -c " + set -ex; \ + chmod a+x /build/Release/onnxruntime_test_all; \ + /onnxruntime_src/tools/ci_build/github/pai/pai_test_launcher.sh" + workingDirectory: $(Build.SourcesDirectory) + displayName: 'Run onnxruntime unit tests' + condition: succeeded() - task: CmdLine@2 inputs: script: |- - python orttraining/tools/ci_test/run_bert_perf_test.py \ - --binary_dir build/Release \ - --model_root training_e2e_test_data/models \ - --training_data_root training_e2e_test_data/data \ - --gpu_sku MI100_32G - displayName: 'Run C++ BERT-L performance test' - retryCountOnTaskFailure: 1 - condition: and(succeededOrFailed(), eq(variables.onnxruntimeBuildSucceeded, 'true')) # ensure all tests are run when the build successed + docker run --rm \ + --security-opt seccomp=unconfined \ + --shm-size=1024m \ + --device=/dev/kfd \ + --device=/dev/dri/renderD$DRIVER_RENDER \ + --group-add $(video) \ + --group-add $(render) \ + --user onnxruntimedev \ + --volume $(Build.SourcesDirectory):/onnxruntime_src \ + --volume $(Build.BinariesDirectory):/build \ + -e OPENBLAS_NUM_THREADS=1 \ + -e OPENMP_NUM_THREADS=1 \ + -e MKL_NUM_THREADS=1 \ + -e KERNEL_EXPLORER_BUILD_DIR=/build/$(BuildConfig) \ + -e KERNEL_EXPLORER_BATCHED_GEMM_MAX_BATCH_SIZE=8 \ + -e KERNEL_EXPLORER_TEST_USE_CUPY=1 \ + onnxruntimetrainingrocm-cibuild-rocm$(RocmVersion)-test \ + pytest /onnxruntime_src/onnxruntime/python/tools/kernel_explorer/ -n 4 --reruns 1 --durations=100 + workingDirectory: $(Build.SourcesDirectory) + displayName: 'Run kernel explorer tests' + condition: succeededOrFailed() - task: CmdLine@2 inputs: script: |- - python orttraining/tools/ci_test/run_convergence_test.py \ - --binary_dir build/Release \ - --model_root training_e2e_test_data/models \ - --training_data_root training_e2e_test_data/data \ - --gpu_sku MI100_32G - displayName: 'Run C++ BERT-L convergence test' - retryCountOnTaskFailure: 1 - condition: and(succeededOrFailed(), eq(variables.onnxruntimeBuildSucceeded, 'true')) # ensure all tests are run when the build successed - - - script: | - sudo apt-get update - sudo apt install -y cifs-utils - displayName: 'Install filesystems util' - condition: and(succeededOrFailed(), eq(variables.onnxruntimeBuildSucceeded, 'true')) - - - bash: tools/ci_build/github/linux/docker/scripts/training/azure_scale_set_vm_mount_test_data.sh -p $(orttrainingtestdatascus-storage-key) -s "//orttrainingtestdatascus.file.core.windows.net/mnist" -d "/mnist" - displayName: 'Mount MNIST' - condition: and(succeededOrFailed(), eq(variables.onnxruntimeBuildSucceeded, 'true')) - - - bash: tools/ci_build/github/linux/docker/scripts/training/azure_scale_set_vm_mount_test_data.sh -p $(orttrainingtestdatascus-storage-key) -s "//orttrainingtestdatascus.file.core.windows.net/bert-data" -d "/bert_data" - displayName: 'Mount bert-data' - condition: and(succeededOrFailed(), eq(variables.onnxruntimeBuildSucceeded, 'true')) - - - bash: tools/ci_build/github/linux/docker/scripts/training/azure_scale_set_vm_mount_test_data.sh -p $(orttrainingtestdatascus-storage-key) -s "//orttrainingtestdatascus.file.core.windows.net/hf-models-cache" -d "/hf_models_cache" - displayName: 'Mount hf-models-cache' - condition: and(succeededOrFailed(), eq(variables.onnxruntimeBuildSucceeded, 'true')) + docker run --rm \ + --security-opt seccomp=unconfined \ + --shm-size=1024m \ + --device=/dev/kfd \ + --device=/dev/dri/renderD$DRIVER_RENDER \ + --group-add $(video) \ + --group-add $(render) \ + --user onnxruntimedev \ + --volume $(Build.SourcesDirectory):/onnxruntime_src \ + --volume $(Build.BinariesDirectory):/build \ + --workdir /build/$(BuildConfig) \ + onnxruntimetrainingrocm-cibuild-rocm$(RocmVersion)-test \ + /bin/bash -c " + set -ex; \ + export PYTHONPATH=/build/$(BuildConfig); \ + python -m onnxruntime.training.ortmodule.torch_cpp_extensions.install; \ + bash /onnxruntime_src/tools/ci_build/github/pai/pai_huggingface_bert_large_test.sh -v $(RocmVersion)" + workingDirectory: $(Build.SourcesDirectory) + displayName: 'Run Python Hugging-Face BERT-L test' + condition: succeededOrFailed() # Entry point for all ORTModule tests # The onnxruntime folder is deleted in the build directory # to enforce use of the onnxruntime wheel - # - # For every upgrade, we should enable it to test it once, and disable it. - # - # TODO - we may consider to cherry pick subset of the UTs to reduce the CI time. - # We can re-enable this part again when it's done. - - # - task: CmdLine@2 - # inputs: - # script: |- - # cd ./build/Release - # unset PYTHONPATH - # rm -rf onnxruntime - # pip install ./dist/onnxruntime*.whl - # python -m onnxruntime.training.ortmodule.torch_cpp_extensions.install - # python orttraining_ortmodule_tests.py \ - # --mnist /mnist \ - # --bert_data /bert_data/hf_data/glue_data/CoLA/original/raw \ - # --transformers_cache /hf_models_cache/huggingface/transformers - # displayName: 'Run orttraining_ortmodule_tests.py' - # condition: and(succeededOrFailed(), eq(variables.onnxruntimeBuildSucceeded, 'true')) + - task: CmdLine@2 + inputs: + script: |- + rm -rf $(Build.BinariesDirectory)/$(BuildConfig)/onnxruntime/ + files=($(Build.BinariesDirectory)/$(BuildConfig)/dist/*.whl) + echo ${files[0]} + whlfilename=$(basename ${files[0]}) + echo $whlfilename + docker run --rm \ + --security-opt seccomp=unconfined \ + --shm-size=1024m \ + --device=/dev/kfd \ + --device=/dev/dri/renderD$DRIVER_RENDER \ + --group-add $(video) \ + --group-add $(render) \ + --user onnxruntimedev \ + --volume $(Build.BinariesDirectory):/build \ + --volume $(Build.SourcesDirectory):/onnxruntime_src \ + --workdir /build/$(BuildConfig) \ + onnxruntimetrainingrocm-cibuild-rocm$(RocmVersion)-test \ + /bin/bash -c " + set -ex; \ + unset PYTHONPATH; \ + pip install /build/$(BuildConfig)/dist/$whlfilename; \ + python -m onnxruntime.training.ortmodule.torch_cpp_extensions.install; \ + mkdir /home/onnxruntimedev/mnist /home/onnxruntimedev/bert_data; \ + export ORTMODULE_DISABLE_CPU_TRAINING_TEST=1; \ + export ORTMODULE_ROCM_TEST=1; \ + python orttraining_ortmodule_tests.py \ + --mnist /home/onnxruntimedev/mnist \ + --bert_data /home/onnxruntimedev/bert_data/hf_data/glue_data/CoLA/original/raw" + workingDirectory: $(Build.SourcesDirectory) + displayName: 'Run orttraining_ortmodule_tests.py' + condition: succeededOrFailed() + + + - task: Bash@3 + inputs: + targetType: filePath + filePath: $(Build.SourcesDirectory)/tools/ci_build/github/pai/pai_clean_device.sh + arguments: -n $(Agent.Name) -d $HIP_VISIBLE_DEVICES -r $DRIVER_RENDER + displayName: 'Clean ROCm Environment' + condition: always() + + - template: templates/clean-agent-build-directory-step.yml diff --git a/tools/ci_build/github/azure-pipelines/orttraining-py-packaging-pipeline-cpu.yml b/tools/ci_build/github/azure-pipelines/orttraining-py-packaging-pipeline-cpu.yml index d470dcbfb7688..983143df3f046 100644 --- a/tools/ci_build/github/azure-pipelines/orttraining-py-packaging-pipeline-cpu.yml +++ b/tools/ci_build/github/azure-pipelines/orttraining-py-packaging-pipeline-cpu.yml @@ -1,31 +1,22 @@ trigger: none -variables: - - name: isMain - value: ${{ eq(variables['Build.SourceBranch'], 'refs/heads/main') }} - - name: finalStorage - ${{ if eq(variables['isMain'], 'true') }}: - value: '--final_storage' - ${{ else }}: - value: '' - resources: repositories: - repository: manylinux type: Github endpoint: Microsoft name: pypa/manylinux - ref: aead4d751c2101e23336aa73f2380df83e7a13f3 + ref: 5eda9aded5462201e6310105728d33016e637ea7 stages: -- stage: Python_Packaging +- stage: Python_Packaging_Linux_Trainin_CPU jobs: - job: Linux_Training_CPU_Wheels timeoutInMinutes: 120 workspace: clean: all - pool: aiinfra-Linux-CPU + pool: onnxruntime-Ubuntu2004-AMD-CPU strategy: matrix: @@ -39,14 +30,6 @@ stages: PythonVersion: '3.11' steps: - - task: CmdLine@2 - displayName: 'check variables' - inputs: - script: | - echo "Branch is "${{ variables['Build.SourceBranch'] }} && \ - echo "isMain is "${{ variables['isMain'] }} && \ - echo "final_storage is "${{ variables['finalStorage'] }} - - checkout: self clean: true submodules: recursive @@ -55,7 +38,7 @@ stages: - template: templates/get-docker-image-steps.yml parameters: - Dockerfile: tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_cpu + Dockerfile: tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cpu Context: tools/ci_build/github/linux/docker DockerBuildArgs: >- --build-arg PYTHON_VERSION=$(PythonVersion) @@ -76,6 +59,8 @@ stages: --volume $HOME/.onnx:/home/onnxruntimedev/.onnx \ -e NIGHTLY_BUILD \ -e BUILD_BUILDNUMBER \ + -e ORT_DISABLE_PYTHON_PACKAGE_LOCAL_VERSION \ + -e DEFAULT_TRAINING_PACKAGE_DEVICE \ onnxruntimetrainingcpubuild \ $(PythonManylinuxDir)/bin/python3 /onnxruntime_src/tools/ci_build/build.py \ --build_dir /build --cmake_generator Ninja \ @@ -85,7 +70,7 @@ stages: --parallel \ --build_wheel \ --enable_onnx_tests \ - --enable_pybind --build_java --build_nodejs --enable_training + --enable_pybind --enable_training workingDirectory: $(Build.SourcesDirectory) - task: CopyFiles@2 @@ -100,19 +85,19 @@ stages: inputs: ArtifactName: onnxruntime_training_cpu - - task: CmdLine@2 - condition: succeeded() - displayName: 'Upload wheel' - inputs: - script: | - files=($(Build.ArtifactStagingDirectory)/Release/dist/*.whl) && \ - echo ${files[0]} && \ - echo ${{ variables['finalStorage'] }} && \ - tools/ci_build/upload_python_package_to_azure_storage.py \ - --python_wheel_path ${files[0]} ${{ variables['finalStorage'] }} - - template: templates/component-governance-component-detection-steps.yml parameters: condition: 'succeeded' - template: templates/clean-agent-build-directory-step.yml + +- template: templates/py-packaging-stage.yml + parameters: + build_py_parameters: --enable_training + enable_linux_gpu: false + enable_linux_cpu: false + enable_windows_cpu: true + enable_windows_gpu: false + enable_mac_cpu: true + enable_mac_silicon: true + enable_linux_arm: false diff --git a/tools/ci_build/github/azure-pipelines/orttraining-py-packaging-pipeline-cuda.yml b/tools/ci_build/github/azure-pipelines/orttraining-py-packaging-pipeline-cuda.yml index 079051bec4538..b8dfb7f3c90a2 100644 --- a/tools/ci_build/github/azure-pipelines/orttraining-py-packaging-pipeline-cuda.yml +++ b/tools/ci_build/github/azure-pipelines/orttraining-py-packaging-pipeline-cuda.yml @@ -6,7 +6,7 @@ resources: type: Github endpoint: Microsoft name: pypa/manylinux - ref: aead4d751c2101e23336aa73f2380df83e7a13f3 + ref: 5eda9aded5462201e6310105728d33016e637ea7 stages: - template: templates/py-packaging-training-cuda-stage.yml @@ -15,34 +15,21 @@ stages: torch_version: '2.0.0' opset_version: '15' cuda_version: '11.8' - gcc_version: 11 - cmake_cuda_architectures: 50;52;60;61;70;75;80;86;87 - docker_file: Dockerfile.manylinux2014_training_cuda11_8 + cmake_cuda_architectures: 60;61;70;75;80;86;90 + docker_file: Dockerfile.manylinux2_28_training_cuda11_8 agent_pool: Onnxruntime-Linux-GPU upload_wheel: 'yes' debug_build: false +# Added for triton compiler team. Can be potentially removed. - template: templates/py-packaging-training-cuda-stage.yml parameters: build_py_parameters: --enable_training --update --build torch_version: '2.0.0' opset_version: '15' cuda_version: '11.8' - gcc_version: 11 - cmake_cuda_architectures: 50;52;60;61;70;75;80;86;87 - docker_file: Dockerfile.manylinux2014_training_cuda11_8 + cmake_cuda_architectures: 70;75;80;86 + docker_file: Dockerfile.manylinux2_28_training_cuda11_8 agent_pool: Onnxruntime-Linux-GPU upload_wheel: 'no' debug_build: true - -- template: templates/py-packaging-stage.yml - parameters: - build_py_parameters: --enable_training - enable_linux_gpu: false - enable_ubuntu_cpu: false - enable_linux_cpu: false - enable_windows_cpu: true - enable_windows_gpu: false - enable_mac_cpu: false - enable_mac_silicon: false - enable_linux_arm: false diff --git a/tools/ci_build/github/azure-pipelines/orttraining-py-packaging-pipeline-rocm.yml b/tools/ci_build/github/azure-pipelines/orttraining-py-packaging-pipeline-rocm.yml index 4b057eeb882d7..a45b7d57205d1 100644 --- a/tools/ci_build/github/azure-pipelines/orttraining-py-packaging-pipeline-rocm.yml +++ b/tools/ci_build/github/azure-pipelines/orttraining-py-packaging-pipeline-rocm.yml @@ -6,7 +6,7 @@ resources: type: Github endpoint: Microsoft name: pypa/manylinux - ref: aead4d751c2101e23336aa73f2380df83e7a13f3 + ref: 5eda9aded5462201e6310105728d33016e637ea7 stages: - stage: Python_Packaging @@ -14,63 +14,39 @@ stages: - template: templates/rocm.yml parameters: PythonVersion: '3.8' - RocmVersion: '5.2.3' + RocmVersion: '5.6' - template: templates/rocm.yml parameters: PythonVersion: '3.9' - RocmVersion: '5.2.3' + RocmVersion: '5.6' - template: templates/rocm.yml parameters: PythonVersion: '3.10' - RocmVersion: '5.2.3' + RocmVersion: '5.6' - template: templates/rocm.yml parameters: PythonVersion: '3.8' - RocmVersion: '5.3.2' + RocmVersion: '5.7' - template: templates/rocm.yml parameters: PythonVersion: '3.9' - RocmVersion: '5.3.2' + RocmVersion: '5.7' - template: templates/rocm.yml parameters: PythonVersion: '3.10' - RocmVersion: '5.3.2' + RocmVersion: '5.7' - template: templates/rocm.yml parameters: PythonVersion: '3.8' - RocmVersion: '5.4' - - template: templates/rocm.yml - parameters: - PythonVersion: '3.9' - RocmVersion: '5.4' - - template: templates/rocm.yml - parameters: - PythonVersion: '3.10' - RocmVersion: '5.4' - - template: templates/rocm.yml - parameters: - PythonVersion: '3.8' - RocmVersion: '5.4.2' - - template: templates/rocm.yml - parameters: - PythonVersion: '3.9' - RocmVersion: '5.4.2' - - template: templates/rocm.yml - parameters: - PythonVersion: '3.10' - RocmVersion: '5.4.2' - - template: templates/rocm.yml - parameters: - PythonVersion: '3.8' - RocmVersion: '5.4.2' + RocmVersion: '5.7' BuildConfig: 'RelWithDebInfo' - template: templates/rocm.yml parameters: PythonVersion: '3.9' - RocmVersion: '5.4.2' + RocmVersion: '5.7' BuildConfig: 'RelWithDebInfo' - template: templates/rocm.yml parameters: PythonVersion: '3.10' - RocmVersion: '5.4.2' + RocmVersion: '5.7' BuildConfig: 'RelWithDebInfo' 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 c6bde53d242da..61f9b37d4ce78 100644 --- a/tools/ci_build/github/azure-pipelines/post-merge-jobs.yml +++ b/tools/ci_build/github/azure-pipelines/post-merge-jobs.yml @@ -1,19 +1,3 @@ -variables: -- name: WIN_CPU_BUILD_MACHINE_POOL_NAME # name of a variable - # The public ADO project - ${{ if startsWith(variables['System.CollectionUri'], 'https://dev.azure.com/onnxruntime/') }}: - value: 'onnxruntime-Win-CPU-2019' - # The private ADO project - ${{ if or(startsWith(variables['System.CollectionUri'], 'https://dev.azure.com/aiinfra/'),startsWith(variables['System.CollectionUri'], 'https://aiinfra.visualstudio.com/')) }}: - value: 'Win-CPU-2021' -- name: LINUX_CPU_BUILD_MACHINE_POOL_NAME # name of a variable - # The public ADO project - ${{ if startsWith(variables['System.CollectionUri'], 'https://dev.azure.com/onnxruntime/') }}: - value: 'onnxruntime-Linux-CPU-2019' - # The private ADO project - ${{ if or(startsWith(variables['System.CollectionUri'], 'https://dev.azure.com/aiinfra/'),startsWith(variables['System.CollectionUri'], 'https://aiinfra.visualstudio.com/')) }}: - value: 'aiinfra-Linux-CPU' - stages: - ${{ if or(startsWith(variables['System.CollectionUri'], 'https://dev.azure.com/aiinfra/'),startsWith(variables['System.CollectionUri'], 'https://aiinfra.visualstudio.com/')) }}: - template: templates/web-ci.yml @@ -43,7 +27,7 @@ stages: runTests: true buildJava: false buildNodejs: false - ort_build_pool_name: ${{variables.WIN_CPU_BUILD_MACHINE_POOL_NAME}} + ort_build_pool_name: 'onnxruntime-Win-CPU-2022' - template: templates/win-ci.yml parameters: @@ -58,7 +42,7 @@ stages: runTests: false buildJava: false buildNodejs: true - ort_build_pool_name: ${{variables.WIN_CPU_BUILD_MACHINE_POOL_NAME}} + ort_build_pool_name: 'onnxruntime-Win-CPU-2022' - template: templates/win-ci.yml parameters: @@ -73,12 +57,52 @@ stages: runTests: true buildJava: true buildNodejs: true - ort_build_pool_name: ${{variables.WIN_CPU_BUILD_MACHINE_POOL_NAME}} + ort_build_pool_name: 'onnxruntime-Win-CPU-2022' + +- ${{ if or(startsWith(variables['System.CollectionUri'], 'https://dev.azure.com/aiinfra/'),startsWith(variables['System.CollectionUri'], 'https://aiinfra.visualstudio.com/')) }}: + # The settings below is the same as Windows GPU CI pipeline's CUDA job except here we set OnnxruntimeTestGpuDeviceId to 1 + - stage: cuda_multi_gpu + dependsOn: [] + jobs: + - template: templates/jobs/win-ci-vs-2022-job.yml + parameters: + BuildConfig: 'RelWithDebInfo' + EnvSetupScript: setup_env_cuda_11.bat + buildArch: x64 + additionalBuildFlags: --enable_pybind --build_java --build_nodejs --use_cuda --cuda_home="$(Agent.TempDirectory)\v11.8" --enable_cuda_profiling --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=86 + msbuildPlatform: x64 + isX86: false + job_name_suffix: x64_RelWithDebInfo + RunOnnxRuntimeTests: true + ORT_EP_NAME: CUDA + WITH_CACHE: true + MachinePool: onnxruntime-Win2022-GPU-MultiA10 + OnnxruntimeTestGpuDeviceId: 1 + +- ${{ if or(startsWith(variables['System.CollectionUri'], 'https://dev.azure.com/aiinfra/'),startsWith(variables['System.CollectionUri'], 'https://aiinfra.visualstudio.com/')) }}: + # The settings below is the same as Windows GPU CI pipeline's CUDA job except here we set OnnxruntimeTestGpuDeviceId to 1 + - stage: trt_multi_gpu + dependsOn: [] + jobs: + - template: templates/jobs/win-ci-vs-2022-job.yml + parameters: + BuildConfig: 'RelWithDebInfo' + EnvSetupScript: setup_env_trt.bat + buildArch: x64 + additionalBuildFlags: --enable_pybind --build_java --build_nodejs --use_cuda --cuda_home="$(Agent.TempDirectory)\v11.8" --enable_cuda_profiling --use_tensorrt --tensorrt_home="C:\local\TensorRT-8.6.1.6.Windows10.x86_64.cuda-11.8" --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=86 + msbuildPlatform: x64 + isX86: false + job_name_suffix: x64_RelWithDebInfo + RunOnnxRuntimeTests: true + ORT_EP_NAME: TRT + WITH_CACHE: true + MachinePool: onnxruntime-Win2022-GPU-MultiA10 + OnnxruntimeTestGpuDeviceId: 1 - stage: Mimalloc dependsOn: [ ] jobs: - - template: templates/win-ci-vs-2019.yml + - template: templates/jobs/win-ci-vs-2022-job.yml parameters: BuildConfig: 'Debug' EnvSetupScript: setup_env.bat @@ -88,37 +112,35 @@ stages: isX86: false job_name_suffix: x64_mimalloc RunOnnxRuntimeTests: true - RunStaticCodeAnalysis: false isTraining: false ORT_EP_NAME: CPU GenerateDocumentation: false EnablePython: false - MachinePool: ${{variables.WIN_CPU_BUILD_MACHINE_POOL_NAME}} + MachinePool: 'onnxruntime-Win-CPU-2022' -- stage: NoAbseil +- stage: MemoryProfiling dependsOn: [ ] jobs: - - template: templates/win-ci-vs-2019.yml + - template: templates/jobs/win-ci-vs-2022-job.yml parameters: BuildConfig: 'Debug' EnvSetupScript: setup_env.bat buildArch: x64 - additionalBuildFlags: --cmake_extra_defines onnxruntime_DISABLE_ABSEIL=ON + additionalBuildFlags: --cmake_extra_defines onnxruntime_ENABLE_MEMORY_PROFILE=ON msbuildPlatform: x64 isX86: false - job_name_suffix: x64_no_absl - RunOnnxRuntimeTests: true - RunStaticCodeAnalysis: false + job_name_suffix: x64_no_memory_profiling + RunOnnxRuntimeTests: false isTraining: false ORT_EP_NAME: CPU GenerateDocumentation: false EnablePython: false - MachinePool: ${{variables.WIN_CPU_BUILD_MACHINE_POOL_NAME}} + MachinePool: 'onnxruntime-Win-CPU-2022' - stage: MinimalBuildWithNoExceptions dependsOn: [ ] jobs: - - template: templates/win-ci-vs-2019.yml + - template: templates/jobs/win-ci-vs-2022-job.yml parameters: BuildConfig: 'Debug' EnvSetupScript: setup_env.bat @@ -128,17 +150,16 @@ stages: isX86: false job_name_suffix: x64_minimal_no_exception RunOnnxRuntimeTests: true - RunStaticCodeAnalysis: false isTraining: false ORT_EP_NAME: CPU GenerateDocumentation: false EnablePython: false - MachinePool: ${{variables.WIN_CPU_BUILD_MACHINE_POOL_NAME}} + MachinePool: 'onnxruntime-Win-CPU-2022' - stage: DebugNodeInputsOutputs dependsOn: [ ] jobs: - - template: templates/win-ci-vs-2019.yml + - template: templates/jobs/win-ci-vs-2022-job.yml parameters: BuildConfig: 'Debug' EnvSetupScript: setup_env.bat @@ -148,12 +169,11 @@ stages: isX86: false job_name_suffix: x64_debug_node_input_output RunOnnxRuntimeTests: true - RunStaticCodeAnalysis: false isTraining: false ORT_EP_NAME: CPU GenerateDocumentation: false EnablePython: false - MachinePool: ${{variables.WIN_CPU_BUILD_MACHINE_POOL_NAME}} + MachinePool: 'onnxruntime-Win-CPU-2022' #Generate test coverage report and publish the data to a Cloud database. Only runs daily. - stage: CodeCoverage @@ -165,7 +185,7 @@ stages: timeoutInMinutes: 150 variables: skipComponentGovernanceDetection: true - pool: ${{variables.LINUX_CPU_BUILD_MACHINE_POOL_NAME}} + pool: 'onnxruntime-Ubuntu2004-AMD-CPU' steps: - template: templates/set-version-number-variables-step.yml @@ -182,9 +202,9 @@ stages: #Merge the multiple prof data into a single indexed profile data file llvm-profdata merge -sparse -o ort.profdata *.profraw #Create coverage report, output the result to 'report.json' - llvm-cov export -summary-only -instr-profile=ort.profdata onnxruntime_test_all -object onnxruntime_mlas_test -object onnxruntime_api_tests_without_env -object onnx_test_runner -object onnxruntime_shared_lib_test -object onnxruntime_global_thread_pools_test -object onnxruntime_api_tests_without_env $(Build.SourcesDirectory)/include/onnxruntime $(Build.SourcesDirectory)/onnxruntime/core $(Build.SourcesDirectory)/onnxruntime/contrib_ops > $(Build.BinariesDirectory)/report.json + llvm-cov export -summary-only -instr-profile=ort.profdata onnxruntime_test_all -object onnxruntime_mlas_test -object onnx_test_runner -object onnxruntime_shared_lib_test -object onnxruntime_global_thread_pools_test $(Build.SourcesDirectory)/include/onnxruntime $(Build.SourcesDirectory)/onnxruntime/core $(Build.SourcesDirectory)/onnxruntime/contrib_ops > $(Build.BinariesDirectory)/report.json - llvm-cov show -instr-profile=ort.profdata onnxruntime_test_all -object onnxruntime_mlas_test -object onnxruntime_api_tests_without_env -object onnx_test_runner -object onnxruntime_shared_lib_test -object onnxruntime_global_thread_pools_test -object onnxruntime_api_tests_without_env $(Build.SourcesDirectory)/include/onnxruntime $(Build.SourcesDirectory)/onnxruntime/core $(Build.SourcesDirectory)/onnxruntime/contrib_ops --format=html -output-dir=$(Build.ArtifactStagingDirectory) + llvm-cov show -instr-profile=ort.profdata onnxruntime_test_all -object onnxruntime_mlas_test -object onnx_test_runner -object onnxruntime_shared_lib_test -object onnxruntime_global_thread_pools_test $(Build.SourcesDirectory)/include/onnxruntime $(Build.SourcesDirectory)/onnxruntime/core $(Build.SourcesDirectory)/onnxruntime/contrib_ops --format=html -output-dir=$(Build.ArtifactStagingDirectory) workingDirectory: $(Build.BinariesDirectory) - ${{ if or(startsWith(variables['System.CollectionUri'], 'https://dev.azure.com/aiinfra/'),startsWith(variables['System.CollectionUri'], 'https://aiinfra.visualstudio.com/')) }}: @@ -211,7 +231,7 @@ stages: - job: AndroidCustomBuildScript workspace: clean: all - pool: ${{variables.LINUX_CPU_BUILD_MACHINE_POOL_NAME}} + pool: 'onnxruntime-Ubuntu2004-AMD-CPU' variables: dockerImageTag: onnxruntime-android-custom-build steps: diff --git a/tools/ci_build/github/azure-pipelines/py-package-build-pipeline.yml b/tools/ci_build/github/azure-pipelines/py-package-build-pipeline.yml index 4ba1b93b14fef..4c80aedeb1f18 100644 --- a/tools/ci_build/github/azure-pipelines/py-package-build-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/py-package-build-pipeline.yml @@ -47,7 +47,7 @@ resources: type: Github endpoint: Microsoft name: pypa/manylinux - ref: aead4d751c2101e23336aa73f2380df83e7a13f3 + ref: 5eda9aded5462201e6310105728d33016e637ea7 stages: - template: templates/py-packaging-selectable-stage.yml 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 906b0ed65df59..2161a9205f22d 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 @@ -3,24 +3,38 @@ resources: - pipeline: build source: 'Python packaging pipeline' trigger: true + branch: main # branch to pick the artifact, Used only for manual triggered pipeline runs for testing the pipeline itself + #TODO: Remove the following dependency. Running python tests should not need to use manylinux. + repositories: + - repository: manylinux # The name used to reference this repository in the checkout step + type: Github + endpoint: Microsoft + name: pypa/manylinux + ref: 5eda9aded5462201e6310105728d33016e637ea7 stages: - stage: Linux_Test_CPU_x86_64_stage jobs: - - template: templates/py-packaging-linux-test.yml + - template: templates/py-packaging-linux-test-cpu.yml parameters: arch: 'x86_64' - machine_pool: 'aiinfra-Linux-CPU' - device: 'CPU' + machine_pool: 'onnxruntime-Ubuntu2004-AMD-CPU' + base_image: 'registry.access.redhat.com/ubi8/ubi' + devtoolset_rootpath: /opt/rh/gcc-toolset-12/root + 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 + prepend_path: '/opt/rh/gcc-toolset-12/root/usr/bin:' - stage: Linux_Test_CPU_aarch64_stage dependsOn: [] jobs: - - template: templates/py-packaging-linux-test.yml + - template: templates/py-packaging-linux-test-cpu.yml parameters: arch: 'aarch64' machine_pool: 'aiinfra-linux-ARM64-CPU-2019' - device: 'CPU' + base_image: 'arm64v8/almalinux:8' + devtoolset_rootpath: /opt/rh/gcc-toolset-12/root + 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 + prepend_path: '/opt/rh/gcc-toolset-12/root/usr/bin:' - stage: Packages_Somking_Test dependsOn: [] @@ -29,21 +43,8 @@ stages: parameters: job_name: Test_MAC_Wheels machine_pool: - vmImage: 'macOS-12' + vmImage: 'macOS-13' itemPattern: '*/*mac*x86_64.whl' - - template: templates/py-package-smoking-test.yml - parameters: - job_name: Test_WIN_64_Wheels - itemPattern: '*/*win_amd64.whl' - machine_pool: - vmImage: 'windows-2022' - - template: templates/py-package-smoking-test.yml - parameters: - job_name: Test_WIN_32_Wheels - itemPattern: '*/*win32.whl' - python_arch: 'x86' - machine_pool: - vmImage: 'windows-2022' - template: templates/py-package-smoking-test.yml parameters: job_name: Test_LINUX_x86_64_Wheels @@ -61,7 +62,7 @@ stages: - Linux_Test_CPU_aarch64_stage - Packages_Somking_Test jobs: - - template: templates/py-packaging-linux-test.yml + - template: templates/py-packaging-linux-test-cuda.yml parameters: arch: 'x86_64' machine_pool: 'Onnxruntime-Linux-GPU' 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 2eeefd33b0703..62f84a9bb185c 100644 --- a/tools/ci_build/github/azure-pipelines/py-packaging-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/py-packaging-pipeline.yml @@ -4,11 +4,6 @@ parameters: type: boolean default: true -- name: enable_ubuntu_cpu - displayName: 'Whether Ubuntu CPU (manylinux_2_27) package is built.' - type: boolean - default: true - - name: enable_linux_gpu displayName: 'Whether Linux GPU package is built.' type: boolean @@ -42,7 +37,18 @@ parameters: - name: build_py_parameters displayName: 'Specify extra build parameters' type: string - default: 'NONE' + default: '--use_azure' + +# TODO: Now the Windows jobs use a different cmake build type. Consider to merge it. +- name: cmake_build_type + type: string + displayName: 'Linux packages cmake build type. Linux Only.' + default: 'Release' + values: + - Debug + - Release + - RelWithDebInfo + - MinSizeRel trigger: none @@ -52,18 +58,17 @@ resources: type: Github endpoint: Microsoft name: pypa/manylinux - ref: aead4d751c2101e23336aa73f2380df83e7a13f3 + ref: 5eda9aded5462201e6310105728d33016e637ea7 stages: - template: templates/py-packaging-stage.yml parameters: enable_linux_gpu: ${{ parameters.enable_linux_gpu }} - enable_ubuntu_cpu: ${{ parameters.enable_ubuntu_cpu }} enable_linux_cpu: ${{ parameters.enable_linux_cpu }} enable_windows_cpu: ${{ parameters.enable_windows_cpu }} enable_windows_gpu: ${{ parameters.enable_windows_gpu }} enable_mac_cpu: ${{ parameters.enable_mac_cpu }} enable_mac_silicon: ${{ parameters.enable_mac_silicon }} enable_linux_arm: ${{ parameters.enable_linux_arm }} - ${{ if not(eq(parameters.build_py_parameters, 'NONE')) }}: - build_py_parameters: ${{ parameters.build_py_parameters }} \ No newline at end of file + build_py_parameters: ${{ parameters.build_py_parameters }} + cmake_build_type: ${{ parameters.cmake_build_type }} \ No newline at end of file diff --git a/tools/ci_build/github/azure-pipelines/snpe-ep-nuget-packaging-pipeline.yml b/tools/ci_build/github/azure-pipelines/qnn-ep-nuget-packaging-pipeline.yml similarity index 76% rename from tools/ci_build/github/azure-pipelines/snpe-ep-nuget-packaging-pipeline.yml rename to tools/ci_build/github/azure-pipelines/qnn-ep-nuget-packaging-pipeline.yml index 2ee043563741c..654ccad3af327 100644 --- a/tools/ci_build/github/azure-pipelines/snpe-ep-nuget-packaging-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/qnn-ep-nuget-packaging-pipeline.yml @@ -1,18 +1,18 @@ parameters: -- name: snpe_sdk_path_win - displayName: Snpe Windows SDK path +- name: qnn_sdk_path_win + displayName: QNN Windows SDK path type: string - default: C:\data\local\SNPE\snpe_win-1.61.46.3724 + default: C:\data\qnnsdk\qnn-v2.14.1.230828_win -- name: snpe_sdk_info - displayName: Snpe SDK Version Information +- name: qnn_sdk_info + displayName: QNN SDK Version Information type: string - default: snpe_win-1.61.46 - + default: qnn-v2.14.1.230828_win + - name: ort_package_version displayName: OnnxRuntime Nuget package version type: string - default: 1.13.1 + default: 1.15.0 - name: build_config displayName: Build Configuration @@ -29,12 +29,17 @@ parameters: type: boolean default: false +- name: runTests + displayName: Run ONNX Runtime unit tests? + type: boolean + default: true + jobs: - - job: OnnxRuntime_SnpeNuget_Win_x64 + - job: OnnxRuntime_QNNNuget_Win_x64 timeoutInMinutes: 120 - pool: 'Onnxruntime-SNPE-Windows-2022-CPU' + pool: 'Onnxruntime-QNNEP-Windows-2022-CPU' variables: MsbuildArguments: '-detailedsummary -maxcpucount -consoleloggerparameters:PerformanceSummary' OnnxRuntimeBuildDirectory: '$(Build.BinariesDirectory)' @@ -42,6 +47,7 @@ jobs: buildArch: x64 setVcvars: true ALLOW_RELEASED_ONNX_OPSET_ONLY: '1' + commonBuildArgs: '--compile_no_warning_as_error --disable_ml_ops --build_dir $(Build.BinariesDirectory)\Windows --skip_submodule_sync --build_shared_lib --cmake_generator "Visual Studio 17 2022" --config ${{ parameters.build_config }} --use_qnn --qnn_home ${{parameters.qnn_sdk_path_win}}' steps: - template: templates/set-version-number-variables-step.yml @@ -55,11 +61,24 @@ jobs: versionSpec: '3.8' addToPath: true + - task: CmdLine@2 + displayName: 'Check available QNN SDK versions' + inputs: + script: | + dir C:\data\qnnsdk\qnn* + - task: PythonScript@0 displayName: 'Build onnxruntime for x64' inputs: scriptPath: '$(Build.SourcesDirectory)\tools\ci_build\build.py' - arguments: '--disable_ml_ops --build_dir $(Build.BinariesDirectory)\Windows --skip_submodule_sync --build_shared_lib --cmake_generator "Visual Studio 17 2022" --config ${{ parameters.build_config }} --use_snpe --snpe_root=${{parameters.snpe_sdk_path_win}}' + arguments: '--skip_tests $(commonBuildArgs)' + + - task: PythonScript@0 + displayName: 'Run unit tests' + condition: and(succeeded(), eq('${{ parameters.runTests}}', true)) + inputs: + scriptPath: '$(Build.SourcesDirectory)\tools\ci_build\build.py' + arguments: '--test $(commonBuildArgs)' - template: templates/win-esrp-dll.yml parameters: @@ -71,8 +90,7 @@ jobs: displayName: 'Generating nuspec for the native Nuget package x64' inputs: script: | - copy $(Build.SourcesDirectory)\LICENSE $(Build.SourcesDirectory)\LICENSE.txt - python "$(Build.SourcesDirectory)\tools\nuget\generate_nuspec_for_native_nuget.py" --package_version ${{ parameters.ort_package_version }} --package_name Microsoft.ML.OnnxRuntime.Snpe --target_architecture x64 --build_config ${{ parameters.build_config }} --native_build_path=$(Build.BinariesDirectory)\Windows\${{ parameters.build_config }}\${{ parameters.build_config }} --packages_path $(Build.BinariesDirectory)\Windows\packages --ort_build_path $(Build.BinariesDirectory)\Windows --sources_path $(Build.SourcesDirectory) --commit_id $(OnnxRuntimeGitCommitHash) --is_release_build ${{ parameters.IsReleaseBuild }} --sdk_info ${{ parameters.snpe_sdk_info }} + python "$(Build.SourcesDirectory)\tools\nuget\generate_nuspec_for_native_nuget.py" --package_version ${{ parameters.ort_package_version }} --package_name Microsoft.ML.OnnxRuntime.QNN --target_architecture x64 --build_config ${{ parameters.build_config }} --native_build_path=$(Build.BinariesDirectory)\Windows\${{ parameters.build_config }}\${{ parameters.build_config }} --packages_path $(Build.BinariesDirectory)\Windows\packages --ort_build_path $(Build.BinariesDirectory)\Windows --sources_path $(Build.SourcesDirectory) --commit_id $(OnnxRuntimeGitCommitHash) --is_release_build ${{ parameters.IsReleaseBuild }} --sdk_info ${{ parameters.qnn_sdk_info }} cd $(Build.BinariesDirectory)\Windows\${{ parameters.build_config }}\${{ parameters.build_config }} nuget pack NativeNuget.nuspec mkdir $(Build.ArtifactStagingDirectory)\x64 @@ -84,10 +102,10 @@ jobs: artifactName: 'drop-winnuget-x64' targetPath: '$(Build.ArtifactStagingDirectory)/x64' - - job: OnnxRuntime_SnpeNuget_Win_Arm64 + - job: OnnxRuntime_QNNNuget_Win_Arm64 timeoutInMinutes: 120 - pool: 'Onnxruntime-SNPE-Windows-2022-CPU' + pool: 'Onnxruntime-QNNEP-Windows-2022-CPU' variables: MsbuildArguments: '-detailedsummary -maxcpucount -consoleloggerparameters:PerformanceSummary' OnnxRuntimeBuildDirectory: '$(Build.BinariesDirectory)' @@ -112,7 +130,7 @@ jobs: displayName: 'Generate CMake Configuration for arm64' inputs: scriptPath: '$(Build.SourcesDirectory)\tools\ci_build\build.py' - arguments: '--update --disable_ml_ops --build_dir $(Build.BinariesDirectory)\Win_arm64 --skip_submodule_sync --skip_tests --build_shared_lib --cmake_generator "Visual Studio 17 2022" --config ${{ parameters.build_config }} --arm64 --use_snpe --snpe_root=${{parameters.snpe_sdk_path_win}}' + arguments: '--update --arm64 --disable_ml_ops --build_dir $(Build.BinariesDirectory)\Win_arm64 --skip_submodule_sync --skip_tests --build_shared_lib --cmake_generator "Visual Studio 17 2022" --config ${{ parameters.build_config }} --use_qnn --qnn_home ${{parameters.qnn_sdk_path_win}}' - task: VSBuild@1 displayName: 'Build onnxruntime arm64' @@ -160,8 +178,7 @@ jobs: displayName: 'Generating nuspec for the native Nuget package arm64' inputs: script: | - copy $(Build.SourcesDirectory)\LICENSE $(Build.SourcesDirectory)\LICENSE.txt - python "$(Build.SourcesDirectory)\tools\nuget\generate_nuspec_for_native_nuget.py" --package_version ${{ parameters.ort_package_version }} --package_name Microsoft.ML.OnnxRuntime.Snpe --target_architecture arm64 --build_config ${{ parameters.build_config }} --native_build_path=$(Build.BinariesDirectory)\Win_arm64\${{ parameters.build_config }}\${{ parameters.build_config }} --packages_path $(Build.BinariesDirectory)\Win_arm64\packages --ort_build_path $(Build.BinariesDirectory)\Win_arm64 --sources_path $(Build.SourcesDirectory) --commit_id $(OnnxRuntimeGitCommitHash) --is_release_build ${{ parameters.IsReleaseBuild }} --sdk_info ${{ parameters.snpe_sdk_info }} + python "$(Build.SourcesDirectory)\tools\nuget\generate_nuspec_for_native_nuget.py" --package_version ${{ parameters.ort_package_version }} --package_name Microsoft.ML.OnnxRuntime.QNN --target_architecture arm64 --build_config ${{ parameters.build_config }} --native_build_path=$(Build.BinariesDirectory)\Win_arm64\${{ parameters.build_config }}\${{ parameters.build_config }} --packages_path $(Build.BinariesDirectory)\Win_arm64\packages --ort_build_path $(Build.BinariesDirectory)\Win_arm64 --sources_path $(Build.SourcesDirectory) --commit_id $(OnnxRuntimeGitCommitHash) --is_release_build ${{ parameters.IsReleaseBuild }} --sdk_info ${{ parameters.qnn_sdk_info }} cd $(Build.BinariesDirectory)\Win_arm64\${{ parameters.build_config }}\${{ parameters.build_config }} nuget pack NativeNuget.nuspec mkdir $(Build.ArtifactStagingDirectory)\arm64 @@ -173,24 +190,24 @@ jobs: artifactName: 'drop-winnuget-arm64' targetPath: '$(Build.ArtifactStagingDirectory)/arm64' - - job: NuGet_Packaging_Snpe + - job: NuGet_Packaging_QNN workspace: clean: all - pool: 'Onnxruntime-SNPE-Windows-2022-CPU' + pool: 'Onnxruntime-QNNEP-Windows-2022-CPU' dependsOn: - - OnnxRuntime_SnpeNuget_Win_x64 - - OnnxRuntime_SnpeNuget_Win_Arm64 + - OnnxRuntime_QNNNuget_Win_x64 + - OnnxRuntime_QNNNuget_Win_Arm64 condition: succeeded() steps: - task: DownloadPipelineArtifact@0 - displayName: 'Download Pipeline Artifact - Snpe NuGet x64' + displayName: 'Download Pipeline Artifact - QNN NuGet x64' inputs: artifactName: 'drop-winnuget-x64' targetPath: '$(Build.BinariesDirectory)/nuget-artifact-x64' - task: DownloadPipelineArtifact@0 - displayName: 'Download Pipeline Artifact - Snpe NuGet arm64' + displayName: 'Download Pipeline Artifact - QNN NuGet arm64' inputs: artifactName: 'drop-winnuget-arm64' targetPath: '$(Build.BinariesDirectory)/nuget-artifact-arm64' @@ -202,14 +219,14 @@ jobs: script: | Add-Type -AssemblyName "System.IO.Compression.FileSystem" - $nupkgs = (Get-ChildItem $(Build.BinariesDirectory)/nuget-artifact-x64 -Filter Microsoft.ML.OnnxRuntime.Snpe*.nupkg -Recurse) + $nupkgs = (Get-ChildItem $(Build.BinariesDirectory)/nuget-artifact-x64 -Filter Microsoft.ML.OnnxRuntime.QNN*.nupkg -Recurse) $x64_nuget_package_name = $nupkgs[0].Name $x64_nuget_package = $nupkgs[0].FullName $x64_nupkg_unzipped_directory_root = $nupkgs[0].Directory.FullName $x64_nupkg_unzipped_directory = [System.IO.Path]::Combine($x64_nupkg_unzipped_directory_root, 'binaries', [System.IO.Path]::GetFileNameWithoutExtension($x64_nuget_package)) [System.IO.Compression.ZipFile]::ExtractToDirectory($x64_nuget_package, $x64_nupkg_unzipped_directory) - $nupkgs = (Get-ChildItem $(Build.BinariesDirectory)/nuget-artifact-arm64 -Filter Microsoft.ML.OnnxRuntime.Snpe*.nupkg -Recurse) + $nupkgs = (Get-ChildItem $(Build.BinariesDirectory)/nuget-artifact-arm64 -Filter Microsoft.ML.OnnxRuntime.QNN*.nupkg -Recurse) $arm64_nuget_package = $nupkgs[0].FullName $arm64_nupkg_unzipped_directory_root = $nupkgs[0].Directory.FullName $arm64_nupkg_unzipped_directory = [System.IO.Path]::Combine($arm64_nupkg_unzipped_directory_root, 'binaries', [System.IO.Path]::GetFileNameWithoutExtension($arm64_nuget_package)) diff --git a/tools/ci_build/github/azure-pipelines/sign_ov_ep_binaries.yml b/tools/ci_build/github/azure-pipelines/sign_ov_ep_binaries.yml deleted file mode 100644 index f6f168e281b0d..0000000000000 --- a/tools/ci_build/github/azure-pipelines/sign_ov_ep_binaries.yml +++ /dev/null @@ -1,33 +0,0 @@ -jobs: -- job: 'Sign_OV_Files' - workspace: - clean: all - timeoutInMinutes: 15 - pool: 'onnxruntime-gpu-winbuild-t4' - - steps: - - task: DownloadSecureFile@1 - name: onnxruntimeDlls # The name with which to reference the secure file's path on the agent, like $(mySecureFile.secureFilePath) - inputs: - secureFile: '$(secureFile)' - - - script: 'mkdir $(Build.SourcesDirectory)\Artifact && copy $(onnxruntimeDlls.secureFilePath) $(Build.SourcesDirectory)\Artifact' - displayName: 'Copy dlls to sources directory' - - - script: 'unzip $(secureFile)' - displayName: 'Unzip dll files' - workingDirectory: '$(Build.SourcesDirectory)\Artifact' - - - template: templates/win-esrp-dll.yml - parameters: - DisplayName: 'ESRP - sign NuGet package' - FolderPath: '$(Build.SourcesDirectory)\Artifact' - DoEsrp: 'true' - Pattern: 'onnxruntime*.dll' - - - task: PublishBuildArtifacts@1 - inputs: - pathtoPublish: '$(Build.SourcesDirectory)\Artifact' - artifactName: 'Signed Dlls' - - - template: templates/clean-agent-build-directory-step.yml diff --git a/tools/ci_build/github/azure-pipelines/templates/android-binary-size-check-stage.yml b/tools/ci_build/github/azure-pipelines/templates/android-binary-size-check-stage.yml index 1005aaa715c42..733cafdeeb8c0 100644 --- a/tools/ci_build/github/azure-pipelines/templates/android-binary-size-check-stage.yml +++ b/tools/ci_build/github/azure-pipelines/templates/android-binary-size-check-stage.yml @@ -41,7 +41,7 @@ stages: - template: get-docker-image-steps.yml parameters: - Dockerfile: tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_cpu + 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 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 70385875a7dab..1263b21d4a03e 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 @@ -20,11 +20,13 @@ jobs: workspace: clean: all pool: + # We need macOS-12 to run the Android emulator for now. + # https://github.com/actions/runner-images/issues/7671 vmImage: 'macOS-12' variables: - name: runCodesignValidationInjection value: false - timeoutInMinutes: 60 + timeoutInMinutes: 90 dependsOn: - Android_Java_API_AAR_Packaging_${{ parameters.job_name_suffix }} steps: @@ -46,6 +48,8 @@ jobs: - template: use-android-ndk.yml + - template: install-appcenter.yml + - script: | python3 $(Build.SourcesDirectory)/tools/python/run_android_emulator.py \ --android-sdk-root ${ANDROID_SDK_ROOT} \ 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 05f9df9243d0a..5e61f88b4aa18 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 @@ -33,7 +33,7 @@ parameters: - name: pool_name displayName: Pool name type: string - default: 'aiinfra-Linux-CPU' + default: 'onnxruntime-Ubuntu2004-AMD-CPU' - name: packageName # now we can build onnxruntime or onnxruntime-mobile for Android, need specify it here @@ -66,7 +66,7 @@ jobs: - template: get-docker-image-steps.yml parameters: - Dockerfile: tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_cpu + 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 diff --git a/tools/ci_build/github/azure-pipelines/templates/build-linux-wasm-step.yml b/tools/ci_build/github/azure-pipelines/templates/build-linux-wasm-step.yml new file mode 100644 index 0000000000000..82a86e2ec8018 --- /dev/null +++ b/tools/ci_build/github/azure-pipelines/templates/build-linux-wasm-step.yml @@ -0,0 +1,74 @@ +parameters: +- name: WithCache + displayName: Build with Cache + type: boolean + default: false + +# if WithCahe is false, the following parameters are not used. +- name: Today + type: string + default: "" + +- name: AdditionalKey + type: string + default: "" + +- name: CacheDir + type: string + default: "" + +- name: Arguments + type: string + +- name: DisplayName + type: string + +steps: + - task: Cache@2 + inputs: + ${{if eq(variables['Build.SourceBranchName'], 'merge')}}: + key: ' "${{parameters.TODAY}}" | ${{parameters.AdditionalKey}} | merge ' + ${{else}}: + key: '"${{parameters.TODAY}}" | ${{parameters.AdditionalKey}} | $(Build.SourceVersion) ' + path: ${{parameters.CacheDir}} + restoreKeys: | + "${{parameters.TODAY}}" | ${{parameters.AdditionalKey}} + displayName: Cache Task + condition: eq('${{parameters.WithCache}}', true) + + - ${{if eq(parameters.WithCache, true)}}: + - script: | + pushd '$(Build.SourcesDirectory)/cmake/external/emsdk' + source ./emsdk_env.sh + export PATH=$(Build.SourcesDirectory)/cmake/external/emsdk/:$PATH + export PATH=$(Build.SourcesDirectory)/cmake/external/emsdk/ccache/git-emscripten_64bit/bin:$PATH + echo $PATH + ccache -s + ccache -z + export EM_CONFIG="$(Build.SourcesDirectory)/cmake/external/emsdk/.emscripten" + + popd + pushd '$(Build.BinariesDirectory)' + python3 '$(Build.SourcesDirectory)/tools/ci_build/build.py' ${{parameters.Arguments}} + ret=$? + if [ $ret -ne 0 ]; then + echo "Build failed with error code $ret" + exit 1 + fi + ccache -s + popd + displayName: ${{parameters.DisplayName}} + env: + CCACHE_SLOPPINESS: include_file_ctime,include_file_mtime,time_macros + CCACHE_DIR: ${{parameters.CacheDir}} + _EMCC_CCACHE: 1 + EM_COMPILER_WRAPPER: ccache + EM_DIR: '$(Build.SourcesDirectory)/cmake/external/emsdk/upstream/emscripten' + + - ${{if eq(parameters.WithCache, false)}}: + - task: PythonScript@0 + displayName: '${{parameters.DisplayName}}' + inputs: + scriptPath: '$(Build.SourcesDirectory)/tools/ci_build/build.py' + arguments: ${{parameters.Arguments}} + workingDirectory: '$(Build.BinariesDirectory)' 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 c8000f4065ec1..07aac08dac0b1 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 @@ -59,6 +59,7 @@ steps: copy $(Build.SourcesDirectory)\include\onnxruntime\core\framework\provider_options.h $(Build.BinariesDirectory)\${{parameters.artifactName}}\include copy $(Build.SourcesDirectory)\include\onnxruntime\core\providers\cpu\cpu_provider_factory.h $(Build.BinariesDirectory)\${{parameters.artifactName}}\include copy $(Build.SourcesDirectory)\include\onnxruntime\core\providers\tensorrt\tensorrt_provider_factory.h $(Build.BinariesDirectory)\${{parameters.artifactName}}\include + copy $(Build.SourcesDirectory)\orttraining\orttraining\training_api\include\onnxruntime_training*.h $(Build.BinariesDirectory)\${{parameters.artifactName}}\include REM copy the README, license and TPN copy $(Build.SourcesDirectory)\README.md $(Build.BinariesDirectory)\${{parameters.artifactName}}\README.md 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 7c22b1dfbec98..21cd3a44e8924 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 @@ -38,6 +38,16 @@ parameters: type: string default: 'default' +- name: SpecificArtifact + displayName: Use Specific Artifact + type: boolean + default: false + +- name: BuildId + displayName: Specific Artifact's BuildId + type: string + default: '0' + stages: - template: linux-cpu-packaging-pipeline.yml parameters: @@ -47,6 +57,9 @@ stages: parameters: AllowReleasedOpsetOnly: 1 BuildForAllArchs: true + SpecificArtifact: ${{ parameters.SpecificArtifact }} + BuildId: ${{ parameters.BuildId }} + DoEsrp: ${{ parameters.DoEsrp }} - stage: Android_Java_API_AAR_Packaging_Mobile dependsOn: [] @@ -88,11 +101,13 @@ stages: workspace: clean: all pool: - vmImage: 'macOS-12' + vmImage: 'macOS-13' timeoutInMinutes: 300 steps: - template: set-version-number-variables-step.yml + - template: use-xcode-version.yml + - script: | /bin/bash $(Build.SourcesDirectory)/tools/ci_build/github/apple/build_host_protoc.sh \ $(Build.SourcesDirectory) \ @@ -160,6 +175,7 @@ stages: runTests: false buildJava: false buildNodejs: false + ort_build_pool_name: onnxruntime-Win-CPU-2022 - template: win-ci.yml parameters: @@ -192,7 +208,7 @@ stages: - stage: Jar_Packaging dependsOn: - Linux_C_API_Packaging_CPU - - MacOS_C_API_Packaging_CPU + - MacOS_C_API_Package_Publish - Windows_Packaging_CPU_x86_${{ parameters.BuildVariant }} - Windows_Packaging_CPU_x64_${{ parameters.BuildVariant }} - Windows_Packaging_CPU_arm_${{ parameters.BuildVariant }} @@ -202,7 +218,7 @@ stages: - job: workspace: clean: all - pool: 'Win-CPU-2021' + pool: 'onnxruntime-Win-CPU-2022' steps: - checkout: self @@ -274,8 +290,9 @@ stages: - stage: NuGet_Packaging_CPU dependsOn: + - Setup - Linux_C_API_Packaging_CPU - - MacOS_C_API_Packaging_CPU + - MacOS_C_API_Package_Publish - Windows_Packaging_CPU_x86_${{ parameters.BuildVariant }} - Windows_Packaging_CPU_x64_${{ parameters.BuildVariant }} - Windows_Packaging_CPU_arm_${{ parameters.BuildVariant }} @@ -293,6 +310,7 @@ stages: variables: OrtPackageId: ${{ parameters.OrtNugetPackageId }} breakCodesignValidationInjection: ${{ parameters.DoEsrp }} + ReleaseVersionSuffix: $[stageDependencies.Setup.Set_Variables.outputs['Set_Release_Version_Suffix.ReleaseVersionSuffix']] steps: - checkout: self @@ -399,7 +417,7 @@ stages: # # 'Any CPU' is the default (first 'mixed' platform specified in the csproj) so this should be fine. script: | - dotnet build .\src\Microsoft.ML.OnnxRuntime\Microsoft.ML.OnnxRuntime.csproj -p:SelectedTargets=Net6 -p:Configuration=RelWithDebInfo -p:OnnxRuntimeBuildDirectory="$(Build.BinariesDirectory)" -p:OrtPackageId=$(OrtPackageId) -p:IsReleaseBuild=${{ parameters.IsReleaseBuild }} + dotnet build .\src\Microsoft.ML.OnnxRuntime\Microsoft.ML.OnnxRuntime.csproj -p:SelectedTargets=Net6 -p:Configuration=RelWithDebInfo -p:OnnxRuntimeBuildDirectory="$(Build.BinariesDirectory)" -p:OrtPackageId=$(OrtPackageId) -p:IsReleaseBuild=${{ parameters.IsReleaseBuild }} -p:ReleaseVersionSuffix=$(ReleaseVersionSuffix) workingDirectory: '$(Build.SourcesDirectory)\csharp' - task: MSBuild@1 @@ -417,7 +435,7 @@ stages: solution: '$(Build.SourcesDirectory)\csharp\OnnxRuntime.CSharp.sln' platform: 'Any CPU' configuration: RelWithDebInfo - msbuildArguments: '-p:SelectedTargets=PreNet6 -p:OnnxRuntimeBuildDirectory="$(Build.BinariesDirectory)" -p:OrtPackageId=$(OrtPackageId) -p:IsReleaseBuild=${{ parameters.IsReleaseBuild }}' + msbuildArguments: '-p:SelectedTargets=PreNet6 -p:OnnxRuntimeBuildDirectory="$(Build.BinariesDirectory)" -p:OrtPackageId=$(OrtPackageId) -p:IsReleaseBuild=${{ parameters.IsReleaseBuild }} -p:ReleaseVersionSuffix=$(ReleaseVersionSuffix)' workingDirectory: '$(Build.SourcesDirectory)\csharp' - ${{ if eq(parameters.DoEsrp, true) }}: @@ -442,7 +460,7 @@ stages: solution: '$(Build.SourcesDirectory)\csharp\OnnxRuntime.CSharp.proj' platform: 'Any CPU' configuration: RelWithDebInfo - msbuildArguments: '-t:CreatePackage -p:OnnxRuntimeBuildDirectory="$(Build.BinariesDirectory)" -p:OrtPackageId=$(OrtPackageId) -p:IsReleaseBuild=${{ parameters.IsReleaseBuild }}' + msbuildArguments: '-t:CreatePackage -p:OnnxRuntimeBuildDirectory="$(Build.BinariesDirectory)" -p:OrtPackageId=$(OrtPackageId) -p:IsReleaseBuild=${{ parameters.IsReleaseBuild }} -p:ReleaseVersionSuffix=$(ReleaseVersionSuffix)' workingDirectory: '$(Build.SourcesDirectory)\csharp' - task: CopyFiles@2 @@ -477,7 +495,7 @@ stages: PackageType: 'nuget' PackagePath: '$(Build.ArtifactStagingDirectory)' PackageName: 'Microsoft.ML.OnnxRuntime.*nupkg' - PlatformsSupported: 'win-x64,win-x86,linux-x64,linux-arm64,osx.10.14-x64' + PlatformsSupported: 'win-x64,win-x86,linux-x64,linux-arm64,osx-x64' VerifyNugetSigning: false - task: PublishPipelineArtifact@0 @@ -510,10 +528,11 @@ stages: - task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3 displayName: 'Clean Agent Directories' condition: always() + - stage: Nodejs_Packaging_CPU dependsOn: - Linux_C_API_Packaging_CPU - - MacOS_C_API_Packaging_CPU + - MacOS_C_API_Package_Publish - Windows_Packaging_CPU_x64_${{ parameters.BuildVariant }} - Windows_Packaging_CPU_arm64_${{ parameters.BuildVariant }} condition: succeeded() @@ -521,7 +540,7 @@ stages: - job: workspace: clean: all - pool: 'Win-CPU-2021' + pool: 'onnxruntime-Win-CPU-2022' variables: ${{ if eq(parameters.IsReleaseBuild, true) }}: NpmPackagingMode: 'release' @@ -760,30 +779,32 @@ stages: - template: ../nuget/templates/test_win.yml parameters: - AgentPool : 'Win-CPU-2021' + AgentPool : 'onnxruntime-Win-CPU-2022' Skipx86Tests : false NugetPackageName : 'Microsoft.ML.OnnxRuntime' ArtifactSuffix: 'CPU' - template: ../nuget/templates/test_linux.yml parameters: - AgentPool : aiinfra-Linux-CPU + AgentPool : onnxruntime-Ubuntu2004-AMD-CPU NugetPackageName : 'Microsoft.ML.OnnxRuntime' ArtifactSuffix: 'CPU' + SpecificArtifact: ${{ parameters.SpecificArtifact }} + BuildId: ${{ parameters.BuildId }} - template: ../nuget/templates/test_macos.yml parameters: - AgentPool : macOS-12 + AgentPool : macOS-13 ArtifactSuffix: 'CPU' - template: ../nodejs/templates/test_win.yml parameters: - AgentPool : 'Win-CPU-2021' + AgentPool : 'onnxruntime-Win-CPU-2022' StageSuffix : 'Win_CPU_x64' - template: ../nodejs/templates/test_linux.yml parameters: - AgentPool : 'aiinfra-Linux-CPU' + AgentPool : 'onnxruntime-Ubuntu2004-AMD-CPU' StageSuffix : 'Linux_CPU_x64' - template: ../nodejs/templates/test_macos.yml @@ -796,7 +817,7 @@ stages: - job: workspace: clean: all - pool: 'Win-CPU-2021' + pool: 'onnxruntime-Win-CPU-2022' timeoutInMinutes: 60 variables: - name: runCodesignValidationInjection @@ -837,7 +858,7 @@ stages: - job: workspace: clean: all - pool: 'aiinfra-Linux-CPU' + pool: 'onnxruntime-Ubuntu2004-AMD-CPU' variables: - name: runCodesignValidationInjection value: false @@ -881,7 +902,7 @@ stages: workspace: clean: all pool: - vmImage: 'macOS-12' + vmImage: 'macOS-13' variables: - name: runCodesignValidationInjection value: false @@ -896,6 +917,8 @@ stages: artifactName: 'onnxruntime-java' targetPath: '$(Build.BinariesDirectory)/final-jar' + - template: use-xcode-version.yml + - task: CmdLine@2 inputs: script: | @@ -907,7 +930,6 @@ stages: popd wget https://oss.sonatype.org/service/local/repositories/releases/content/org/junit/platform/junit-platform-console-standalone/1.6.2/junit-platform-console-standalone-1.6.2.jar -P ./ wget https://oss.sonatype.org/service/local/repositories/releases/content/com/google/protobuf/protobuf-java/3.21.7/protobuf-java-3.21.7.jar -P ./ - sudo xcode-select --switch /Applications/Xcode_13.1.app/Contents/Developer DYLD_LIBRARY_PATH=./test:${DYLD_LIBRARY_PATH} java -jar ./junit-platform-console-standalone-1.6.2.jar -cp .:./test:./protobuf-java-3.21.7.jar:./onnxruntime-$(OnnxRuntimeVersion).jar --scan-class-path --fail-if-no-tests --disable-banner workingDirectory: '$(Build.BinariesDirectory)/final-jar' @@ -918,5 +940,3 @@ stages: - task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3 displayName: 'Clean Agent Directories' condition: always() - - 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 3677e19e36e3a..15fcec0511741 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 @@ -5,28 +5,43 @@ parameters: type: string default: '' -- name: BaseImage +- name: BaseImage type: string -- name: OnnxruntimeArch +- name: OnnxruntimeArch type: string -- name: OnnxruntimeCFlags +- name: OnnxruntimeCFlags type: string -- name: OnnxruntimeCXXFlags +- name: OnnxruntimeCXXFlags type: string -- name: OnnxruntimeNodejsBindingArch +- name: OnnxruntimeNodejsBindingArch type: string + values: + - arm64 + - x64 - name: PoolName type: string - default: 'aiinfra-Linux-CPU' - + default: 'onnxruntime-Ubuntu2004-AMD-CPU' + +- name: ArtifactNamePrefix + type: string + default: "onnxruntime" + +- name: PackageJava + type: boolean + default: true + +- name: PackageNodejs + type: boolean + default: true + jobs: - job: Linux_C_API_Packaging_CPU_${{parameters.OnnxruntimeArch}} - + workspace: clean: all variables: @@ -44,7 +59,7 @@ jobs: Dockerfile: tools/ci_build/github/linux/docker/inference/${{parameters.OnnxruntimeArch}}/default/cpu/Dockerfile Context: tools/ci_build/github/linux/docker/inference/${{parameters.OnnxruntimeArch}}/default/cpu DockerBuildArgs: "--build-arg BUILD_UID=$( id -u ) --build-arg BASEIMAGE=${{parameters.BaseImage}}" - Repository: onnxruntimecpubuildcentos7${{parameters.OnnxruntimeArch}} + Repository: onnxruntimecpubuildcentos8${{parameters.OnnxruntimeArch}} ${{ if eq(parameters.OnnxruntimeArch, 'aarch64') }}: UpdateDepsTxt: false @@ -53,7 +68,7 @@ jobs: script: | mkdir -p $HOME/.onnx docker run --rm -e CFLAGS="${{parameters.OnnxruntimeCFlags}}" -e CXXFLAGS="${{parameters.OnnxruntimeCXXFlags}}" --volume /data/onnx:/data/onnx:ro --volume $(Build.SourcesDirectory):/onnxruntime_src --volume $(Build.BinariesDirectory):/build \ - --volume $HOME/.onnx:/home/onnxruntimedev/.onnx -e NIGHTLY_BUILD onnxruntimecpubuildcentos7${{parameters.OnnxruntimeArch}} /bin/bash -c "python3 \ + --volume $HOME/.onnx:/home/onnxruntimedev/.onnx -e NIGHTLY_BUILD onnxruntimecpubuildcentos8${{parameters.OnnxruntimeArch}} /bin/bash -c "python3.9 \ /onnxruntime_src/tools/ci_build/build.py --build_java --build_nodejs --build_dir /build --config Release \ --skip_submodule_sync --parallel --build_shared_lib ${{ parameters.AdditionalBuildFlags }} && cd /build/Release && make install DESTDIR=/build/linux-${{parameters.OnnxruntimeArch}}" workingDirectory: $(Build.SourcesDirectory) @@ -66,8 +81,9 @@ jobs: ls -al $(Build.ArtifactStagingDirectory) displayName: 'Create Artifacts' - - template: java-api-artifacts-package-and-publish-steps-posix.yml - parameters: + - ${{ 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}}' @@ -78,19 +94,21 @@ jobs: - template: c-api-artifacts-package-and-publish-steps-posix.yml parameters: buildConfig: 'Release' - artifactName: 'onnxruntime-linux-${{parameters.OnnxruntimeArch}}-$(OnnxRuntimeVersion)' - artifactNameNoVersionString: 'onnxruntime-linux-${{parameters.OnnxruntimeArch}}' + artifactName: '${{parameters.ArtifactNamePrefix}}-linux-${{parameters.OnnxruntimeArch}}-$(OnnxRuntimeVersion)' + artifactNameNoVersionString: '${{parameters.ArtifactNamePrefix}}-linux-${{parameters.OnnxruntimeArch}}' libraryName: 'libonnxruntime.so.$(OnnxRuntimeVersion)' - - template: nodejs-artifacts-package-and-publish-steps-posix.yml - parameters: + - ${{ 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}}' + - ${{ if not(eq(parameters.OnnxruntimeNodejsBindingArch, 'arm64')) }}: - template: component-governance-component-detection-steps.yml parameters: condition: 'succeeded' - task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3 displayName: 'Clean Agent Directories' - condition: always() \ No newline at end of file + condition: always() 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 6bc5201f7d130..6e212b1eed532 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 @@ -17,7 +17,12 @@ steps: displayName: 'Clean Agent Directories' condition: always() -- script: docker image prune -f +- script: | + if which docker >/dev/null; then + docker image prune -f + else + echo docker does not exist + fi displayName: Clean docker images condition: eq(variables['Agent.OS'], 'Linux') continueOnError: true diff --git a/tools/ci_build/github/azure-pipelines/templates/common-variables.yml b/tools/ci_build/github/azure-pipelines/templates/common-variables.yml new file mode 100644 index 0000000000000..e7f703fa592a3 --- /dev/null +++ b/tools/ci_build/github/azure-pipelines/templates/common-variables.yml @@ -0,0 +1,3 @@ +variables: + common_cuda_version: '11.8' + common_cuda_baseimg: 'nvidia/cuda:11.8.0-cudnn8-devel-ubi8' diff --git a/tools/ci_build/github/azure-pipelines/templates/compliance.yml b/tools/ci_build/github/azure-pipelines/templates/compliance.yml index 9f901ef3fbaf2..cc451425be42a 100644 --- a/tools/ci_build/github/azure-pipelines/templates/compliance.yml +++ b/tools/ci_build/github/azure-pipelines/templates/compliance.yml @@ -3,7 +3,7 @@ parameters: displayName: msbuildPlatform type: string default: x64 - + steps: - task: CredScan@2 displayName: 'Run CredScan' @@ -12,47 +12,25 @@ steps: debugMode: false continueOnError: true -- task: BinSkim@3 +- task: BinSkim@4 displayName: 'Run BinSkim' inputs: - arguments: 'analyze $(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\*.dll --recurse --verbose' - continueOnError: true - -- task: DeleteFiles@1 - displayName: 'Delete files from $(Build.BinariesDirectory)\RelWithDebInfo' - inputs: - SourceFolder: '$(Build.BinariesDirectory)\RelWithDebInfo' - Contents: | - **/*.obj - **/*.pdb - **/*.dll - -#Manually set msBuildCommandline so that we can also set CAExcludePath -- task: securedevelopmentteam.vss-secure-development-tools.build-task-prefast.SDLNativeRules@2 - displayName: 'Run the PREfast SDL Native Rules for MSBuild' - inputs: - userProvideBuildInfo: msBuildInfo - msBuildVersion: 16.0 - msBuildArchitecture: x64 - msBuildCommandline: '"C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\amd64\msbuild.exe" "$(Build.BinariesDirectory)\RelWithDebInfo\onnxruntime.sln" /p:platform="${{parameters.msbuildPlatform}}" /p:configuration="RelWithDebInfo" /p:CAExcludePath="$(Build.BinariesDirectory);$(Build.SourcesDirectory)\cmake;C:\program files (x86)" /p:VisualStudioVersion="16.0" /m /p:PreferredToolArchitecture=x64' + AnalyzeTargetGlob: '+:file|$(Build.ArtifactStagingDirectory)\**\*.dll;-:file|$(Build.ArtifactStagingDirectory)\**\DirectML.dll' continueOnError: true -- task: securedevelopmentteam.vss-secure-development-tools.build-task-report.SdtReport@1 +- task: SdtReport@2 displayName: 'Create Security Analysis Report' inputs: - BinSkim: true - BinSkimBreakOn: WarningAbove - CredScan: true SDLNativeRules: true -- task: securedevelopmentteam.vss-secure-development-tools.build-task-publishsecurityanalysislogs.PublishSecurityAnalysisLogs@2 +- task: PublishSecurityAnalysisLogs@3 displayName: 'Publish Security Analysis Logs' continueOnError: true -- task: securedevelopmentteam.vss-secure-development-tools.build-task-uploadtotsa.TSAUpload@1 +- task: TSAUpload@2 + displayName: 'TSA upload' condition: and (succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main')) - displayName: 'TSA Upload' inputs: - tsaVersion: TsaV2 - codeBaseName: 'onnxruntime_master' - continueOnError: true \ No newline at end of file + 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 index daea4998ea58f..c2ef565a6e9ee 100644 --- 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 @@ -6,6 +6,11 @@ parameters: steps: - ${{ if eq(variables['System.TeamProject'], 'Lotus') }}: + - task: DeleteFiles@1 + inputs: + contents: $(Build.BinariesDirectory)/* + displayName: 'Clean up build directory' + - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 displayName: 'Component Detection' condition: diff --git a/tools/ci_build/github/azure-pipelines/templates/download-deps.yml b/tools/ci_build/github/azure-pipelines/templates/download-deps.yml index d14a710632482..f17bc8de5739b 100644 --- a/tools/ci_build/github/azure-pipelines/templates/download-deps.yml +++ b/tools/ci_build/github/azure-pipelines/templates/download-deps.yml @@ -11,7 +11,7 @@ steps: packageType: upack feed: '/7424c8e4-5c62-490e-95c4-79446f31017c' definition: '517c4f6f-5437-4392-a70d-4f15ec5be2f0' - version: 1.0.46 + version: 1.0.81 downloadPath: $(Build.BinariesDirectory)/deps # The private ADO project @@ -22,7 +22,7 @@ steps: packageType: upack feed: '/4c7631f5-24c0-4307-8822-1aa8f180c325' definition: 'fd9dd5ad-b73e-4678-890e-edcf680dbc1a' - version: 1.0.46 + version: 1.0.81 downloadPath: $(Build.BinariesDirectory)/deps # You can add more ADO accounts at here. diff --git a/tools/ci_build/github/azure-pipelines/templates/flex-downloadPipelineArtifact.yml b/tools/ci_build/github/azure-pipelines/templates/flex-downloadPipelineArtifact.yml new file mode 100644 index 0000000000000..a83451a1b33d9 --- /dev/null +++ b/tools/ci_build/github/azure-pipelines/templates/flex-downloadPipelineArtifact.yml @@ -0,0 +1,32 @@ +parameters: + - name: StepName + type: string + + - name: ArtifactName + type: string + + - name: TargetPath + type: string + + - name: SpecificArtifact + type: boolean + default: false + + - name: BuildId + type: string + default: '0' + +steps: + - task: DownloadPipelineArtifact@2 + displayName: ${{ parameters.StepName }} + inputs: + artifactName: ${{ parameters.ArtifactName}} + targetPath: '${{ parameters.TargetPath }}' + ${{ if eq(parameters.SpecificArtifact, false)}}: + buildType: 'current' + ${{ else }}: + source: 'specific' + project: $(System.TeamProject) + pipeline: $(Build.DefinitionName) + runVersion: 'specific' + buildId: ${{ parameters.BuildId }} diff --git a/tools/ci_build/github/azure-pipelines/templates/install-appcenter.yml b/tools/ci_build/github/azure-pipelines/templates/install-appcenter.yml new file mode 100644 index 0000000000000..51be73d4c658a --- /dev/null +++ b/tools/ci_build/github/azure-pipelines/templates/install-appcenter.yml @@ -0,0 +1,12 @@ +# Install appcenter CLI + +parameters: +- name: appcenterVersion + type: string + default: "2.13.7" + +steps: +- bash: | + set -e -x + npm install -g appcenter-cli@${{ parameters.appcenterVersion }} + displayName: Install appcenter CLI ${{ parameters.appcenterVersion }} diff --git a/tools/ci_build/github/azure-pipelines/templates/java-api-artifacts-package-and-publish-steps-windows.yml b/tools/ci_build/github/azure-pipelines/templates/java-api-artifacts-package-and-publish-steps-windows.yml deleted file mode 100644 index 233e80b5e3b29..0000000000000 --- a/tools/ci_build/github/azure-pipelines/templates/java-api-artifacts-package-and-publish-steps-windows.yml +++ /dev/null @@ -1,60 +0,0 @@ -# sets up common build tools for the windows build machines before build - -parameters: - buildConfig: 'RelWithDebInfo' - artifactName: 'onnxruntime-java-win-x64' - version: '' - comitId: '' -steps: - - task: CmdLine@2 - inputs: - script: | - @echo on - set NATIVE_FOLDER=$(Build.BinariesDirectory)\${{parameters.artifactName}}\stage\ai\onnxruntime\native\win-x64 - mkdir %NATIVE_FOLDER% - echo "Directories created" - copy .\java\build\libs\*.jar $(Build.BinariesDirectory)\${{parameters.artifactName}} - pushd $(Build.BinariesDirectory)\${{parameters.artifactName}} - if ${{parameters.artifactName}} == onnxruntime-java-win-x64 ( - set artifact_id=onnxruntime - ) else ( - set artifact_id=onnxruntime_gpu - ) - jar xf onnxruntime-${{parameters.version}}.jar META-INF\maven\com.microsoft.onnxruntime\%artifact_id%\pom.xml - move META-INF\maven\com.microsoft.onnxruntime\%artifact_id%\pom.xml onnxruntime-${{parameters.version}}.pom - rd /s /q META-INF - popd - copy .\${{parameters.buildConfig}}\onnxruntime.pdb %NATIVE_FOLDER% - copy .\${{parameters.buildConfig}}\onnxruntime4j_jni.pdb %NATIVE_FOLDER% - copy $(Build.SourcesDirectory)\docs\Privacy.md $(Build.BinariesDirectory)\${{parameters.artifactName}}\stage\Privacy.md - copy $(Build.SourcesDirectory)\ThirdPartyNotices.txt $(Build.BinariesDirectory)\${{parameters.artifactName}}\stage\ThirdPartyNotices.txt - @echo ${{parameters.commitId}} > $(Build.BinariesDirectory)\${{parameters.artifactName}}\stage\GIT_COMMIT_ID - pushd $(Build.BinariesDirectory)\${{parameters.artifactName}}\stage - jar uf $(Build.BinariesDirectory)\${{parameters.artifactName}}\onnxruntime-${{parameters.version}}.jar ai\onnxruntime\native\win-x64\onnxruntime.pdb - jar uf $(Build.BinariesDirectory)\${{parameters.artifactName}}\onnxruntime-${{parameters.version}}.jar ai\onnxruntime\native\win-x64\onnxruntime4j_jni.pdb - jar uf $(Build.BinariesDirectory)\${{parameters.artifactName}}\onnxruntime-${{parameters.version}}.jar Privacy.md ThirdPartyNotices.txt GIT_COMMIT_ID - popd - pushd $(Build.SourcesDirectory)\java\build\classes\java\test - jar cvf $(Build.BinariesDirectory)\${{parameters.artifactName}}\testing.jar . - popd - pushd $(Build.SourcesDirectory)\java\build\resources\test - rd /s /q ai\onnxruntime\native - jar uvf $(Build.BinariesDirectory)\${{parameters.artifactName}}\testing.jar . - popd - rd /s /q $(Build.BinariesDirectory)\${{parameters.artifactName}}\stage - dir /s /b $(Build.BinariesDirectory)\${{parameters.artifactName}} - workingDirectory: '$(Build.BinariesDirectory)\${{parameters.buildConfig}}' - displayName: 'Add symbols and notices' - - - task: ArchiveFiles@2 - inputs: - rootFolderOrFile: '$(Build.BinariesDirectory)\${{parameters.artifactName}}' - includeRootFolder: true - archiveType: 'zip' # Options: zip, 7z, tar, wim - archiveFile: '$(Build.ArtifactStagingDirectory)\${{parameters.artifactName}}.zip' - replaceExistingArchive: true - - - task: PublishBuildArtifacts@1 - inputs: - pathtoPublish: '$(Build.ArtifactStagingDirectory)\${{parameters.artifactName}}.zip' - artifactName: 'drop-${{parameters.artifactName}}' 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 new file mode 100644 index 0000000000000..ca5a52fa61ed3 --- /dev/null +++ b/tools/ci_build/github/azure-pipelines/templates/jobs/set-winenv.yml @@ -0,0 +1,19 @@ +parameters: +- name: EnvSetupScript + type: string + +- name: DownloadCUDA + type: boolean + default: false + +steps: +- ${{ if eq(parameters.DownloadCUDA, 'true') }}: + - powershell: | + azcopy.exe cp --recursive "https://lotusscus.blob.core.windows.net/models/cuda_sdk/v11.8" $(Agent.TempDirectory) + +- task: BatchScript@1 + displayName: 'setup env' + inputs: + filename: '$(Build.SourcesDirectory)\tools\ci_build\github\windows\${{ parameters.EnvSetupScript }}' + modifyEnvironment: true + workingFolder: '$(Build.BinariesDirectory)' diff --git a/tools/ci_build/github/azure-pipelines/templates/jobs/win-ci-build-steps.yml b/tools/ci_build/github/azure-pipelines/templates/jobs/win-ci-build-steps.yml new file mode 100644 index 0000000000000..2f67398908d5d --- /dev/null +++ b/tools/ci_build/github/azure-pipelines/templates/jobs/win-ci-build-steps.yml @@ -0,0 +1,121 @@ +parameters: +- name: WithCache + displayName: Build with Cache + type: boolean + default: false + +- name: Today + type: string + default: "" + +- name: CacheDir + type: string + default: "$(Agent.TempDirectory)/ort_ccache" + +- name: DebugCache + type: boolean + default: false + +- name: AdditionalKey + type: string + default: "" + +# it is used to pass additional arguments to build.py +- name: BuildPyArguments + type: string + default: "" + +# it is used to pass msbuild arguments to VSBuild@1 +- name: MsbuildArguments + type: string + default: "" + +# it is used to pass platform arguments to VSBuild@1 +- name: Platform + type: string + default: "x64" + +# it is used to pass configuration arguments to VSBuild@1 +- name: BuildConfig + type: string + +# it is used to pass msbuildArchitecture arguments to VSBuild@1 +- name: BuildArch + type: string + +- name: CacheArg + type: string + default: '/p:CLToolExe=cl.exe /p:CLToolPath=C:\ProgramData\chocolatey\bin /p:TrackFileAccess=false /p:UseMultiToolTask=true /p:DebugInformationFormat=OldStyle' + +steps: + - ${{ if eq(parameters.WithCache, true) }}: + - powershell: | + if ([string]::IsNullOrEmpty((Get-Command ccache -errorAction SilentlyContinue))) + { + choco install ccache -y --version 4.7.4 + $ccache_path = (Get-Command ccache).Source + $ccache_parent_dir = (Split-Path -parent $ccache_path) + Copy-Item "C:\ProgramData\chocolatey\lib\ccache\tools\ccache-4.7.4-windows-x86_64\ccache.exe" -Destination "C:\ProgramData\chocolatey\bin\cl.exe" + Get-ChildItem $ccache_parent_dir + ccache --version + } + displayName: Install ccache + + - task: Cache@2 + inputs: + ${{if eq(variables['Build.SourceBranchName'], 'merge')}}: + key: ' "$(TODAY)" | ${{parameters.AdditionalKey}} | merge ' + ${{else}}: + key: '"$(TODAY)" | onnxruntime | ${{parameters.AdditionalKey}} | $(Build.SourceVersion) ' + path: ${{parameters.CacheDir}} + restoreKeys: | + "$(TODAY)" | onnxruntime | ${{parameters.AdditionalKey}} + displayName: Cache Task + + - task: PythonScript@0 + displayName: 'Generate cmake config' + inputs: + scriptPath: '$(Build.SourcesDirectory)\tools\ci_build\build.py' + ${{ if eq(parameters.WithCache, true) }}: + arguments: '${{parameters.BuildPyArguments}} --use_cache' + ${{ else }}: + arguments: '${{parameters.BuildPyArguments}}' + workingDirectory: '$(Build.BinariesDirectory)' + + - task: VSBuild@1 + displayName: 'Build' + inputs: + solution: '$(Build.BinariesDirectory)\${{parameters.BuildConfig}}\onnxruntime.sln' + platform: ${{parameters.Platform}} + configuration: ${{parameters.BuildConfig}} + ${{ if eq(parameters.WithCache, true) }}: + msbuildArgs: '${{parameters.MsbuildArguments}} ${{parameters.CacheArg}}' + ${{ else }}: + msbuildArgs: '${{parameters.MsbuildArguments}}' + msbuildArchitecture: ${{parameters.BuildArch}} + maximumCpuCount: true + logProjectEvents: false + workingFolder: '$(Build.BinariesDirectory)\${{parameters.BuildConfig}}' + createLogFile: true + env: + CCACHE_DIR: ${{parameters.CacheDir}} + CCACHE_SLOPPINESS: file_macro,time_macros,include_file_mtime,include_file_ctime + CCACHE_COMPILERCHECK: content + ${{if eq(parameters.DebugCache, true)}}: + CCACHE_DEBUG: 1 + CCACHE_DEBUGDIR: $(Agent.TempDirectory)/cache_debug + + - ${{ if eq(parameters.WithCache, true) }}: + - powershell: | + ccache -sv + ccache -z + displayName: cache stat + env: + CCACHE_DIR: ${{parameters.CacheDir}} + + - ${{if eq(parameters.DebugCache, true)}}: + - task: PublishPipelineArtifact@0 + displayName: 'publish cache log' + inputs: + artifactName: 'cache-log' + targetPath: $(Agent.TempDirectory)/cache_debug diff --git a/tools/ci_build/github/azure-pipelines/templates/jobs/win-ci-prebuild-steps.yml b/tools/ci_build/github/azure-pipelines/templates/jobs/win-ci-prebuild-steps.yml new file mode 100644 index 0000000000000..8868e671a5fa5 --- /dev/null +++ b/tools/ci_build/github/azure-pipelines/templates/jobs/win-ci-prebuild-steps.yml @@ -0,0 +1,95 @@ +parameters: +- name: EnvSetupScript + type: string + default: setup_env.bat + +- name: BuildConfig + type: string + +- name: BuildArch + type: string + +- name: DownloadCUDA + type: boolean + default: false + +- name: WITHCACHE + type: boolean + default: false + +- name: MachinePool + type: string + +- name: Today + type: string + +steps: +- task: UsePythonVersion@0 + inputs: + versionSpec: '3.8' + addToPath: true + architecture: ${{parameters.BuildArch}} + +- script: | + python -m pip install -q setuptools wheel numpy flatbuffers + workingDirectory: '$(Build.BinariesDirectory)' + displayName: 'Install python modules' + +- template: ../download-deps.yml + +- task: PythonScript@0 + displayName: 'Update deps.txt' + inputs: + scriptPath: $(Build.SourcesDirectory)/tools/ci_build/replace_urls_in_deps.py + arguments: --new_dir $(Build.BinariesDirectory)/deps + workingDirectory: $(Build.BinariesDirectory) + +- template: set-winenv.yml + parameters: + EnvSetupScript: ${{parameters.EnvSetupScript}} + DownloadCUDA: ${{parameters.DownloadCUDA}} + +- ${{ if eq(parameters.WITHCACHE, true) }}: + - powershell: | + if ([string]::IsNullOrEmpty((Get-Command ccache -errorAction SilentlyContinue))) + { + choco install ccache -y --version 4.7.4 + $ccache_path = (Get-Command ccache).Source + $ccache_parent_dir = (Split-Path -parent $ccache_path) + Copy-Item "C:\ProgramData\chocolatey\lib\ccache\tools\ccache-4.7.4-windows-x86_64\ccache.exe" -Destination "C:\ProgramData\chocolatey\bin\cl.exe" + Get-ChildItem $ccache_parent_dir + ccache --version + } + displayName: Install ccache and update PATH to use linked versions of gcc, cc, etc + + - ${{ if eq(parameters.WITHCACHE, true) }}: + - task: Cache@2 + # machinepool is used to ensure the compiler is same + inputs: + key: '"$(TODAY)" | ${{ parameters.buildArch }} | ${{ parameters.BuildConfig }} | ${{ parameters.MachinePool }} | $(Build.SourcesDirectory)/cmake/deps.txt, $(Build.SourcesDirectory)/tools/ci_build/github/windows/install_third_party_deps.ps1, $(Build.SourcesDirectory)/tools/ci_build/github/windows/helpers.ps1' + path: $(Agent.TempDirectory)/deps_ccache + restoreKeys: | + "$(TODAY)" | ${{ parameters.buildArch }} | ${{ parameters.BuildConfig }} | ${{ parameters.MachinePool }} + displayName: Cache Task + + - task: PowerShell@2 + displayName: 'Install ONNX' + inputs: + filePath: '$(Build.SourcesDirectory)/tools/ci_build/github/windows/install_third_party_deps.ps1' + workingDirectory: '$(Build.BinariesDirectory)' + ${{ if eq(parameters.WITHCACHE, true) }}: + arguments: -cpu_arch ${{ parameters.buildArch }} -install_prefix $(Build.BinariesDirectory)\${{ parameters.BuildConfig }}\installed -build_config ${{ parameters.BuildConfig }} -use_cache + ${{ else }}: + arguments: -cpu_arch ${{ parameters.buildArch }} -install_prefix $(Build.BinariesDirectory)\${{ parameters.BuildConfig }}\installed -build_config ${{ parameters.BuildConfig }} + ${{ if eq(parameters.WITHCACHE, true) }}: + env: + CCACHE_DIR: $(Agent.TempDirectory)/deps_ccache + CCACHE_COMPILERCHECK: content + + - ${{ if eq(parameters.WITHCACHE, true) }}: + - powershell: | + ccache -sv + ccache -z + displayName: cache stat + env: + CCACHE_DIR: $(Agent.TempDirectory)/deps_ccache diff --git a/tools/ci_build/github/azure-pipelines/templates/win-ci-vs-2019.yml b/tools/ci_build/github/azure-pipelines/templates/jobs/win-ci-vs-2022-job.yml similarity index 50% rename from tools/ci_build/github/azure-pipelines/templates/win-ci-vs-2019.yml rename to tools/ci_build/github/azure-pipelines/templates/jobs/win-ci-vs-2022-job.yml index 3a843e5361ba5..46f2ae7b97acc 100644 --- a/tools/ci_build/github/azure-pipelines/templates/win-ci-vs-2019.yml +++ b/tools/ci_build/github/azure-pipelines/templates/jobs/win-ci-vs-2022-job.yml @@ -34,11 +34,6 @@ parameters: type: boolean default: true -- name: RunStaticCodeAnalysis - displayName: Run Static Code Analysis - type: boolean - default: true - - name: ORT_EP_NAME type: string @@ -55,6 +50,11 @@ parameters: type: boolean default: false +- name: OnnxruntimeTestGpuDeviceId + type: number + default: 0 + + jobs: - job: build_${{ parameters.job_name_suffix }} variables: @@ -64,14 +64,15 @@ jobs: setVcvars: true ALLOW_RELEASED_ONNX_OPSET_ONLY: '0' DocUpdateNeeded: false # Set to true during document generation if there are diffs + NVIDIA_TF32_OVERRIDE: '0' skipComponentGovernanceDetection: true DEPS_CACHE_DIR: $(Agent.TempDirectory)/deps_ccache ORT_CACHE_DIR: $(Agent.TempDirectory)/ort_ccache TODAY: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)] + ONNXRUNTIME_TEST_GPU_DEVICE_ID: ${{ parameters.OnnxruntimeTestGpuDeviceId }} ${{ if eq(parameters.WITH_CACHE, true) }}: PS_CACHE_ARG: '-use_cache' PY_CACHE_ARG: '--use_cache' - MSBUILD_CACHE_ARG: '/p:CLToolExe=cl.exe /p:CLToolPath=C:\ProgramData\chocolatey\bin /p:TrackFileAccess=false /p:UseMultiToolTask=true /p:DebugInformationFormat=OldStyle' workspace: clean: all pool: ${{ parameters.MachinePool }} @@ -81,20 +82,18 @@ jobs: clean: true submodules: none - - task: UsePythonVersion@0 - inputs: - versionSpec: '3.8' - addToPath: true - architecture: ${{ parameters.buildArch }} - - - template: download-deps.yml - - - task: PythonScript@0 - displayName: 'Update deps.txt' - inputs: - scriptPath: $(Build.SourcesDirectory)/tools/ci_build/replace_urls_in_deps.py - arguments: --new_dir $(Build.BinariesDirectory)/deps - workingDirectory: $(Build.BinariesDirectory) + - template: win-ci-prebuild-steps.yml + parameters: + EnvSetupScript: ${{parameters.EnvSetupScript}} + ${{ if contains(parameters.additionalBuildFlags, 'use_cuda') }}: + DownloadCUDA: true + ${{ else }}: + DownloadCUDA: false + BuildArch: ${{parameters.buildArch}} + BuildConfig: ${{parameters.BuildConfig}} + MachinePool: ${{parameters.MachinePool}} + WithCache: ${{parameters.WITH_CACHE}} + Today: $(Today) - task: NodeTool@0 inputs: @@ -109,71 +108,15 @@ jobs: jdkArchitectureOption: ${{ parameters.buildArch }} jdkSourceOption: 'PreInstalled' - - task: BatchScript@1 - displayName: 'setup env' - inputs: - filename: '$(Build.SourcesDirectory)\tools\ci_build\github\windows\${{ parameters.EnvSetupScript }}' - modifyEnvironment: true - workingFolder: '$(Build.BinariesDirectory)' - - script: | set ORT_DOXY_SRC=$(Build.SourcesDirectory) set ORT_DOXY_OUT=$(Build.BinariesDirectory)\${{ parameters.BuildConfig }}\${{ parameters.BuildConfig }} mkdir %ORT_DOXY_SRC% mkdir %ORT_DOXY_OUT% "C:\Program Files\doxygen\bin\doxygen.exe" $(Build.SourcesDirectory)\tools\ci_build\github\Doxyfile_csharp.cfg - workingDirectory: '$(Build.SourcesDirectory)' displayName: 'API Documentation Check and generate' - - script: | - python -m pip install -q setuptools wheel numpy - workingDirectory: '$(Build.BinariesDirectory)' - displayName: 'Install python modules' - - - ${{ if eq(parameters.WITH_CACHE, true) }}: - - powershell: | - if ([string]::IsNullOrEmpty((Get-Command ccache -errorAction SilentlyContinue))) - { - choco install ccache -y --version 4.7.4 - $ccache_path = (Get-Command ccache).Source - $ccache_parent_dir = (Split-Path -parent $ccache_path) - Copy-Item "C:\ProgramData\chocolatey\lib\ccache\tools\ccache-4.7.4-windows-x86_64\ccache.exe" -Destination "C:\ProgramData\chocolatey\bin\cl.exe" - Get-ChildItem $ccache_parent_dir - ccache --version - } - displayName: Install ccache and update PATH to use linked versions of gcc, cc, etc - - - ${{ if or(eq(parameters.RunOnnxRuntimeTests, true), eq(parameters.GenerateDocumentation, true)) }}: - - ${{ if eq(parameters.WITH_CACHE, true) }}: - - task: Cache@2 - # machinepool is used to ensure the compiler is same - inputs: - key: '"$(TODAY)" | ${{ parameters.buildArch }} | ${{ parameters.BuildConfig }} | ${{ parameters.MachinePool }} | $(Build.SourcesDirectory)/cmake/deps.txt, $(Build.SourcesDirectory)/tools/ci_build/github/windows/install_third_party_deps.ps1, $(Build.SourcesDirectory)/tools/ci_build/github/windows/helpers.ps1' - path: $(DEPS_CACHE_DIR) - restoreKeys: | - "$(TODAY)" | ${{ parameters.buildArch }} | ${{ parameters.BuildConfig }} | ${{ parameters.MachinePool }} - displayName: Cache Task - - - task: PowerShell@2 - displayName: 'Install ONNX' - inputs: - filePath: '$(Build.SourcesDirectory)/tools/ci_build/github/windows/install_third_party_deps.ps1' - workingDirectory: '$(Build.BinariesDirectory)' - arguments: -cpu_arch ${{ parameters.buildArch }} -install_prefix $(Build.BinariesDirectory)\${{ parameters.BuildConfig }}\installed -build_config ${{ parameters.BuildConfig }} ${{ variables['PS_CACHE_ARG'] }} - ${{ if eq(parameters.WITH_CACHE, true) }}: - env: - CCACHE_DIR: $(DEPS_CACHE_DIR) - CCACHE_COMPILERCHECK: content - - - ${{ if eq(parameters.WITH_CACHE, true) }}: - - powershell: | - ccache -sv - ccache -z - displayName: cache stat - env: - CCACHE_DIR: $(DEPS_CACHE_DIR) - - task: NuGetToolInstaller@0 displayName: Use Nuget 5.7.0 inputs: @@ -188,51 +131,20 @@ jobs: nugetConfigPath: '$(Build.SourcesDirectory)\NuGet.config' restoreDirectory: '$(Build.BinariesDirectory)\${{ parameters.BuildConfig }}' - - ${{ if eq(parameters.WITH_CACHE, true) }}: - - task: Cache@2 - inputs: - ${{if eq(variables['Build.SourceBranchName'], 'merge')}}: - key: ' "$(TODAY)" | $(System.StageName) | ${{ parameters.BuildConfig }} | merge ' - ${{else}}: - key: '"$(TODAY)" | onnxruntime | $(System.StageName) | ${{ parameters.BuildConfig }} | $(Build.SourceVersion) ' - path: $(ORT_CACHE_DIR) - restoreKeys: | - "$(TODAY)" | onnxruntime | $(System.StageName) | ${{ parameters.BuildConfig }} - displayName: Cache Task - - - task: PythonScript@0 - displayName: 'Generate cmake config' - inputs: - scriptPath: '$(Build.SourcesDirectory)\tools\ci_build\build.py' - arguments: '--config ${{ parameters.BuildConfig }} --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --build_csharp --update --parallel --cmake_generator "Visual Studio 16 2019" --build_shared_lib --enable_onnx_tests ${{ variables.PY_CACHE_ARG }} ${{ parameters.additionalBuildFlags }}' - workingDirectory: '$(Build.BinariesDirectory)' - - - task: VSBuild@1 - displayName: 'Build' - inputs: - solution: '$(Build.BinariesDirectory)\${{ parameters.BuildConfig }}\onnxruntime.sln' - platform: ${{ parameters.msbuildPlatform }} - configuration: ${{ parameters.BuildConfig }} - msbuildArgs: '-maxcpucount ${{ variables.MSBUILD_CACHE_ARG }}' - msbuildArchitecture: ${{ parameters.buildArch }} - maximumCpuCount: true - logProjectEvents: false - workingFolder: '$(Build.BinariesDirectory)\${{ parameters.BuildConfig }}' - createLogFile: true - ${{ if eq(parameters.WITH_CACHE, true) }}: - env: - CCACHE_DIR: $(ORT_CACHE_DIR) - - - ${{ if eq(parameters.WITH_CACHE, true) }}: - - powershell: | - ccache -sv - ccache -z - displayName: cache stat - env: - CCACHE_DIR: $(ORT_CACHE_DIR) + - template: win-ci-build-steps.yml + parameters: + WithCache: ${{ parameters.WITH_CACHE }} + Today: $(TODAY) + CacheDir: $(ORT_CACHE_DIR) + AdditionalKey: " $(System.StageName) | ${{ parameters.BuildConfig }} " + BuildPyArguments: '--config ${{ parameters.BuildConfig }} --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --build_csharp --update --parallel --cmake_generator "Visual Studio 17 2022" --build_shared_lib --enable_onnx_tests ${{ parameters.additionalBuildFlags }}' + MsbuildArguments: '-maxcpucount' + BuildArch: ${{ parameters.buildArch }} + Platform: ${{ parameters.msbuildPlatform }} + BuildConfig: ${{ parameters.BuildConfig }} - powershell: | - Get-Volume D + Get-Volume $("$(Build.BinariesDirectory)")[0] displayName: check disk size - task: DeleteFiles@1 @@ -243,7 +155,7 @@ jobs: **/*.obj - powershell: | - Get-Volume D + Get-Volume $("$(Build.BinariesDirectory)")[0] displayName: check disk size - ${{ if eq(parameters.EnablePython, true) }}: @@ -298,54 +210,11 @@ jobs: - ${{ if eq(parameters.RunOnnxRuntimeTests, true) }}: - powershell: | - python $(Build.SourcesDirectory)\tools\ci_build\build.py --config ${{ parameters.BuildConfig }} --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --build_shared_lib --test --cmake_generator "Visual Studio 16 2019" --build_shared_lib --enable_onnx_tests ${{ parameters.additionalBuildFlags }} + python $(Build.SourcesDirectory)\tools\ci_build\build.py --config ${{ parameters.BuildConfig }} --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --build_shared_lib --test --cmake_generator "Visual Studio 17 2022" --build_shared_lib --enable_onnx_tests ${{ parameters.additionalBuildFlags }} workingDirectory: '$(Build.BinariesDirectory)\${{ parameters.BuildConfig }}\${{ parameters.BuildConfig }}' displayName: 'Run tests' - - - ${{ if eq(parameters.RunStaticCodeAnalysis, true) }}: - - task: DeleteFiles@1 - displayName: 'Delete binaries files from $(Build.BinariesDirectory)\RelWithDebInfo' - inputs: - SourceFolder: '$(Build.BinariesDirectory)\RelWithDebInfo' - Contents: | - **/*.obj - **/*.pdb - **/*.dll - - - # Manually set msBuildCommandline so that we can also set CAExcludePath - # build_dir must be a sub folder of $(Build.SourcesDirectory) - # TODO: move this step to a CPU-only machine to save GPU resources. - - task: SDLNativeRules@3 - displayName: 'Run the PREfast SDL Native Rules for MSBuild' - inputs: - msBuildArchitecture: amd64 - setupCommandlines: 'python $(Build.SourcesDirectory)\tools\ci_build\build.py --config RelWithDebInfo --build_dir $(Build.SourcesDirectory)\b --skip_submodule_sync --build_shared_lib --update --cmake_generator "Visual Studio 16 2019" --build_shared_lib --enable_onnx_tests ${{ parameters.additionalBuildFlags }} --cmake_extra_defines onnxruntime_ENABLE_STATIC_ANALYSIS=ON' - msBuildCommandline: '"C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\amd64\msbuild.exe" "$(Build.SourcesDirectory)\b\RelWithDebInfo\onnxruntime.sln" /p:RunCodeAnalysis=true /p:platform=${{ parameters.msbuildPlatform }} /p:configuration=RelWithDebInfo /p:VisualStudioVersion="16.0" /m /p:PreferredToolArchitecture=x64' - excludedPaths: '$(Build.SourcesDirectory)\b#$(Build.SourcesDirectory)\cmake#C:\program files#C:\program files (x86)' - rulesetName: Custom - customRuleset: $(Build.SourcesDirectory)\cmake\Sdl.ruleset - publishXML: true - - - task: SdtReport@2 - displayName: 'Create Security Analysis Report' - inputs: - SDLNativeRules: true - - - task: PublishSecurityAnalysisLogs@3 - displayName: 'Publish Security Analysis Logs' - continueOnError: true - - - task: PostAnalysis@2 - displayName: 'Guardian Break v2' - inputs: - GdnBreakGdnToolSDLNativeRulesSeverity: Note - GdnBreakGdnToolSDLNativeRules: true - - - - ${{ if eq(parameters.RunOnnxRuntimeTests, true) }}: - task: PublishTestResults@2 displayName: 'Publish unit test results' inputs: diff --git a/tools/ci_build/github/azure-pipelines/templates/linux-ci.yml b/tools/ci_build/github/azure-pipelines/templates/linux-ci.yml index 8e1a90cc06875..05b2dee77e689 100644 --- a/tools/ci_build/github/azure-pipelines/templates/linux-ci.yml +++ b/tools/ci_build/github/azure-pipelines/templates/linux-ci.yml @@ -1,5 +1,5 @@ parameters: - AgentPool : 'onnxruntime-Linux-CPU-2019' + AgentPool : 'onnxruntime-Ubuntu2004-AMD-CPU' StageName : 'Linux_CI_Dev' SubmoduleCheckoutMode: '' RunDockerBuildArgs: '-o ubuntu20.04 -d cpu -x "--build_wheel"' 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 04f805e671076..51d3a9ebc2187 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 @@ -4,25 +4,50 @@ parameters: type: string default: '' +- name: stage_name_suffix + displayName: Suffix for stage name as every stage name needs to be unique + type: string + default: 'CPU' + +- name: ArtifactNamePrefix + displayName: Prefix for artifact name + type: string + default: onnxruntime + +- name: PackageJava + type: boolean + default: true + +- name: PackageNodejs + type: boolean + default: true + stages: -- stage: Linux_C_API_Packaging_CPU +- stage: Linux_C_API_Packaging_${{ parameters.stage_name_suffix }} dependsOn: [ ] jobs: - template: c-api-linux-cpu.yml parameters: AdditionalBuildFlags: ${{ parameters.AdditionalBuildFlags }} - BaseImage: 'centos:7' + BaseImage: 'registry.access.redhat.com/ubi8/ubi' OnnxruntimeArch: 'x64' OnnxruntimeCFlags: '-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all' OnnxruntimeCXXFlags: '-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all' OnnxruntimeNodejsBindingArch: 'x64' - PoolName: 'aiinfra-Linux-CPU' + PoolName: 'onnxruntime-Ubuntu2004-AMD-CPU' + ArtifactNamePrefix: ${{ parameters.ArtifactNamePrefix }} + PackageJava: ${{ parameters.PackageJava }} + PackageNodeJS: ${{ parameters.PackageNodeJS }} + - template: c-api-linux-cpu.yml parameters: AdditionalBuildFlags: ${{ parameters.AdditionalBuildFlags }} - BaseImage: 'arm64v8/centos:7' + BaseImage: 'arm64v8/almalinux:8' OnnxruntimeArch: 'aarch64' OnnxruntimeCFlags: '-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -O3 -Wl,--strip-all' OnnxruntimeCXXFlags: '-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -O3 -Wl,--strip-all' OnnxruntimeNodejsBindingArch: 'arm64' - PoolName: 'aiinfra-linux-ARM64-CPU-2019' \ No newline at end of file + PoolName: 'aiinfra-linux-ARM64-CPU-2019' + ArtifactNamePrefix: ${{ parameters.ArtifactNamePrefix }} + PackageJava: ${{ parameters.PackageJava }} + PackageNodeJS: ${{ parameters.PackageNodeJS }} diff --git a/tools/ci_build/github/azure-pipelines/templates/linux-gpu-tensorrt-packaging-pipeline.yml b/tools/ci_build/github/azure-pipelines/templates/linux-gpu-tensorrt-packaging-pipeline.yml index 5b9ffac6fabb0..445f739e81c45 100644 --- a/tools/ci_build/github/azure-pipelines/templates/linux-gpu-tensorrt-packaging-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/templates/linux-gpu-tensorrt-packaging-pipeline.yml @@ -15,6 +15,17 @@ parameters: type: string default: '' +- name: buildNodejs + type: boolean + default: true + +- name: buildNodejsOption + type: string + default: '' + +# We only have CUDA/TRT on x64. We do not have a build for CUDA/TRT for ARM64. +# Therefore this file does not have an `OnnxruntimeNodejsBindingArch` parameter + stages: - stage: Linux_C_API_Packaging_GPU_TensorRT_x64 dependsOn: [] @@ -33,21 +44,15 @@ stages: submodules: recursive - template: get-docker-image-steps.yml parameters: - Dockerfile: tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_cuda11_8_tensorrt8_6 + Dockerfile: tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda11_8_tensorrt8_6 Context: tools/ci_build/github/linux/docker - DockerBuildArgs: "--network=host --build-arg POLICY=manylinux2014 --build-arg PLATFORM=x86_64 --build-arg DEVTOOLSET_ROOTPATH=/opt/rh/devtoolset-11/root --build-arg PREPEND_PATH=/opt/rh/devtoolset-11/root/usr/bin: --build-arg LD_LIBRARY_PATH_ARG=/opt/rh/devtoolset-11/root/usr/lib64:/opt/rh/devtoolset-11/root/usr/lib:/opt/rh/devtoolset-11/root/usr/lib64/dyninst:/opt/rh/devtoolset-11/root/usr/lib/dyninst:/usr/local/lib64 --build-arg BUILD_UID=$( id -u )" + DockerBuildArgs: "--build-arg POLICY=manylinux_2_28 --build-arg PLATFORM=x86_64 --build-arg PREPEND_PATH=/usr/local/cuda/bin --build-arg LD_LIBRARY_PATH_ARG=/usr/local/lib64 --build-arg DEVTOOLSET_ROOTPATH=/usr --build-arg BUILD_UID=$( id -u )" Repository: onnxruntimecuda118xtrt86build - template: set-version-number-variables-step.yml - - task: CmdLine@2 - inputs: - script: | - mkdir -p $HOME/.onnx - docker run --gpus all -e CC=/opt/rh/devtoolset-11/root/usr/bin/cc -e CXX=/opt/rh/devtoolset-11/root/usr/bin/c++ -e CFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all" -e CXXFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all" -e NVIDIA_VISIBLE_DEVICES=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 -e NIGHTLY_BUILD onnxruntimecuda118xtrt86build \ - /opt/python/cp38-cp38/bin/python3 /onnxruntime_src/tools/ci_build/build.py --build_dir /build --config Release \ - --skip_submodule_sync --parallel --build_shared_lib ${{ parameters.buildJavaOption }} --use_tensorrt --cuda_version=$(CUDA_VERSION) --cuda_home=/usr/local/cuda-$(CUDA_VERSION) --cudnn_home=/usr --tensorrt_home=/usr --cmake_extra_defines CMAKE_CUDA_HOST_COMPILER=/opt/rh/devtoolset-11/root/usr/bin/cc 'CMAKE_CUDA_ARCHITECTURES=52;60;61;70;75;80' - workingDirectory: $(Build.SourcesDirectory) + - script: $(Build.SourcesDirectory)/tools/ci_build/github/linux/build_tensorrt_c_api_package.sh + workingDirectory: $(Build.SourcesDirectory) + displayName: 'Build and Test' - ${{ if eq(parameters.buildJava, true) }}: - template: java-api-artifacts-package-and-publish-steps-posix.yml @@ -59,6 +64,13 @@ stages: libraryName: 'libonnxruntime.so' nativeLibraryName: 'libonnxruntime4j_jni.so' + - ${{ if eq(parameters.buildNodejs, 'true') }}: + - template: nodejs-artifacts-package-and-publish-steps-posix.yml + parameters: + arch: 'x64' + os: 'linux' + artifactName: 'drop-onnxruntime-nodejs-linux-x64-tensorrt' + - template: c-api-artifacts-package-and-publish-steps-posix.yml parameters: buildConfig: 'Release' diff --git a/tools/ci_build/github/azure-pipelines/templates/linux-set-variables-and-download.yml b/tools/ci_build/github/azure-pipelines/templates/linux-set-variables-and-download.yml deleted file mode 100644 index f9f6eae0fbb3f..0000000000000 --- a/tools/ci_build/github/azure-pipelines/templates/linux-set-variables-and-download.yml +++ /dev/null @@ -1,13 +0,0 @@ -steps: - -- task: CmdLine@2 - displayName: 'Clean untagged docker images' - inputs: - script: | - docker rm $(docker ps -a | grep Exited | awk '{print $1;}') || true - docker container prune -f - docker image prune -f - workingDirectory: $(Build.BinariesDirectory) - continueOnError: true - condition: always() - 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 new file mode 100644 index 0000000000000..0e584b550f562 --- /dev/null +++ b/tools/ci_build/github/azure-pipelines/templates/linux-wasm-ci.yml @@ -0,0 +1,225 @@ +parameters: +- name: CommitOverride + type: boolean + default: false + +- name: BuildConfig + type: string + default: 'Debug' + +- name: ExtraBuildArgs + type: string + default: '' + +- name: PoolName + type: string + default: 'onnxruntime-Ubuntu2004-AMD-CPU' + +- name: SkipPublish + type: boolean + default: false + +- name: TimeoutInMinutes + default: 180 + +- name: BuildJsep + type: boolean + default: false + +# In fact, it's only used on Linux for compiler cache. +- name: BuildStaticLib + type: boolean + default: false + +- name: BuildTraining + type: boolean + default: true + +- name: WithCache + type: boolean + default: false + +jobs: +- job: build_WASM + pool: + name: ${{ parameters.PoolName }} + variables: + EnvSetupScript: setup_env.bat + buildArch: x64 + CommonBuildArgs: '--parallel --config ${{ parameters.BuildConfig }} --skip_submodule_sync --build_wasm --use_xnnpack ${{ parameters.ExtraBuildArgs }}' + runCodesignValidationInjection: false + TODAY: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)] + ORT_CACHE_DIR: $(Agent.TempDirectory)/ort_ccache + timeoutInMinutes: ${{ parameters.TimeoutInMinutes }} + workspace: + clean: all + steps: + - task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3 + displayName: 'Clean Agent Directories' + condition: always() + - checkout: self + - task: DownloadPipelineArtifact@2 + inputs: + artifact: '__commit' + path: $(Pipeline.Workspace) + 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__ + workingDirectory: '$(Build.SourcesDirectory)' + displayName: 'Read commit SHA and checkout' + condition: eq('${{ parameters.CommitOverride }}', 'true') + - script: | + git submodule sync --recursive + git submodule update --init --recursive + workingDirectory: '$(Build.SourcesDirectory)' + displayName: 'Checkout submodules' + - task: UsePythonVersion@0 + inputs: + versionSpec: '3.8' + addToPath: true + architecture: $(buildArch) + - task: NodeTool@0 + inputs: + versionSpec: '16.x' + - template: download-deps.yml + + - task: PythonScript@0 + displayName: 'Update deps.txt' + inputs: + scriptPath: $(Build.SourcesDirectory)/tools/ci_build/replace_urls_in_deps.py + arguments: --new_dir $(Build.BinariesDirectory)/deps + workingDirectory: $(Build.BinariesDirectory) + + - script: | + set -ex + cd '$(Build.SourcesDirectory)/cmake/external/emsdk' + ./emsdk install 3.1.44 ccache-git-emscripten-64bit + ./emsdk activate 3.1.44 ccache-git-emscripten-64bit + ln -s $(Build.SourcesDirectory)/cmake/external/emsdk/ccache/git-emscripten_64bit/bin/ccache /usr/local/bin/ccache + displayName: 'emsdk install and activate ccache for emscripten' + condition: eq('${{ parameters.WithCache }}', 'true') + + - template: build-linux-wasm-step.yml + parameters: + Today: $(Today) + ${{ if eq(parameters.BuildStaticLib, true)}}: + AdditionalKey: wasm | ${{ parameters.BuildConfig }} | static + ${{ else }}: + AdditionalKey: wasm | ${{ parameters.BuildConfig }} + CacheDir: $(ORT_CACHE_DIR)/wasm + Arguments: '$(CommonBuildArgs) --build_dir $(Build.BinariesDirectory)/wasm' + DisplayName: 'Build and test (node)' + WithCache: ${{ parameters.WithCache }} + + - template: build-linux-wasm-step.yml + parameters: + Today: $(Today) + ${{ if eq(parameters.BuildStaticLib, true)}}: + AdditionalKey: wasm_threads | ${{ parameters.BuildConfig }} | static + ${{ else }}: + AdditionalKey: wasm_threads | ${{ parameters.BuildConfig }} + CacheDir: $(ORT_CACHE_DIR)/wasm_threads + Arguments: '$(CommonBuildArgs) --build_dir $(Build.BinariesDirectory)/wasm_threads --enable_wasm_threads' + DisplayName: 'Build and test (node) (threads)' + WithCache: ${{ parameters.WithCache }} + + - template: build-linux-wasm-step.yml + parameters: + Today: $(Today) + ${{ if eq(parameters.BuildStaticLib, true)}}: + AdditionalKey: wasm_simd_threads | ${{ parameters.BuildConfig }} | static + ${{ else }}: + AdditionalKey: wasm_simd_threads | ${{ parameters.BuildConfig }} + CacheDir: $(ORT_CACHE_DIR)/wasm_simd_threads + Arguments: '$(CommonBuildArgs) --build_dir $(Build.BinariesDirectory)/wasm_simd_threads --enable_wasm_simd --enable_wasm_threads --wasm_run_tests_in_browser' + DisplayName: 'Build and test (node) (simd + threads)' + WithCache: ${{ parameters.WithCache }} + + - template: build-linux-wasm-step.yml + parameters: + Today: $(Today) + ${{ if eq(parameters.BuildStaticLib, true)}}: + AdditionalKey: wasm_simd | ${{ parameters.BuildConfig }} | static + ${{ else }}: + AdditionalKey: wasm_simd | ${{ parameters.BuildConfig }} + CacheDir: $(ORT_CACHE_DIR)/wasm_simd + Arguments: '$(CommonBuildArgs) --build_dir $(Build.BinariesDirectory)/wasm_simd --enable_wasm_simd' + DisplayName: 'Build and test (node) (simd)' + WithCache: ${{ parameters.WithCache }} + + - ${{ if eq(parameters.BuildTraining, true) }}: + - template: build-linux-wasm-step.yml + parameters: + Today: $(Today) + ${{ if eq(parameters.BuildStaticLib, true)}}: + AdditionalKey: training_wasm_simd | ${{ parameters.BuildConfig }} | static + ${{ else }}: + AdditionalKey: training_wasm_simd | ${{ parameters.BuildConfig }} + CacheDir: $(ORT_CACHE_DIR)/training_wasm_simd + Arguments: '$(CommonBuildArgs) --build_dir $(Build.BinariesDirectory)/training_wasm_simd --enable_training_apis --enable_wasm_simd --target onnxruntime_webassembly --skip_tests' + DisplayName: 'Build (training + simd)' + WithCache: ${{ parameters.WithCache }} + + - ${{ if eq(parameters.BuildJsep, true) }}: + - template: build-linux-wasm-step.yml + parameters: + Today: $(Today) + ${{ if eq(parameters.BuildStaticLib, true)}}: + AdditionalKey: wasm_simd_jsep | ${{ parameters.BuildConfig }} | static + ${{ else }}: + AdditionalKey: wasm_simd_jsep | ${{ parameters.BuildConfig }} + CacheDir: $(ORT_CACHE_DIR)/wasm_simd_jsep + Arguments: '$(CommonBuildArgs) --build_dir $(Build.BinariesDirectory)/wasm_simd_jsep --enable_wasm_simd --use_jsep --target onnxruntime_webassembly --skip_tests' + DisplayName: 'Build (simd + JSEP)' + WithCache: ${{ parameters.WithCache }} + - template: build-linux-wasm-step.yml + parameters: + Today: $(Today) + ${{ if eq(parameters.BuildStaticLib, true)}}: + AdditionalKey: wasm_simd_threads_jsep | ${{ parameters.BuildConfig }} | static + ${{ else }}: + AdditionalKey: wasm_simd_threads_jsep | ${{ parameters.BuildConfig }} + CacheDir: $(ORT_CACHE_DIR)/wasm_simd_threads_jsep + Arguments: '$(CommonBuildArgs) --build_dir $(Build.BinariesDirectory)/wasm_simd_threads_jsep --enable_wasm_simd --enable_wasm_threads --use_jsep --target onnxruntime_webassembly --skip_tests' + DisplayName: 'Build (simd + threads + JSEP)' + WithCache: ${{ parameters.WithCache }} + + - ${{ if eq(parameters.SkipPublish, false) }}: + - script: | + cp $(Build.BinariesDirectory)/wasm/${{ parameters.BuildConfig }}/ort-wasm*.* $(Build.ArtifactStagingDirectory) + cp $(Build.BinariesDirectory)/wasm_threads/${{ parameters.BuildConfig }}/ort-wasm*.* $(Build.ArtifactStagingDirectory) + cp $(Build.BinariesDirectory)/wasm_simd_threads/${{ parameters.BuildConfig }}/ort-wasm*.* $(Build.ArtifactStagingDirectory) + cp $(Build.BinariesDirectory)/wasm_simd/${{ parameters.BuildConfig }}/ort-wasm*.* $(Build.ArtifactStagingDirectory) + if [ -d $(Build.BinariesDirectory)/wasm_simd_jsep ]; then + cp $(Build.BinariesDirectory)/wasm_simd_jsep/${{ parameters.BuildConfig }}/ort-wasm-simd.wasm $(Build.ArtifactStagingDirectory)/ort-wasm-simd.jsep.wasm + cp $(Build.BinariesDirectory)/wasm_simd_jsep/${{ parameters.BuildConfig }}/ort-wasm-simd.js $(Build.ArtifactStagingDirectory)/ort-wasm-simd.jsep.js + fi + if [ -d $(Build.BinariesDirectory)/wasm_simd_threads_jsep ]; then + cp $(Build.BinariesDirectory)/wasm_simd_threads_jsep/${{ parameters.BuildConfig }}/ort-wasm-simd-threaded.wasm $(Build.ArtifactStagingDirectory)/ort-wasm-simd-threaded.jsep.wasm + cp $(Build.BinariesDirectory)/wasm_simd_threads_jsep/${{ parameters.BuildConfig }}/ort-wasm-simd-threaded.js $(Build.ArtifactStagingDirectory)/ort-wasm-simd-threaded.jsep.js + cp $(Build.BinariesDirectory)/wasm_simd_threads_jsep/${{ parameters.BuildConfig }}/ort-wasm-simd-threaded.worker.js $(Build.ArtifactStagingDirectory)/ort-wasm-simd-threaded.jsep.worker.js + fi + if [ -d $(Build.BinariesDirectory)/training_wasm_simd ]; then + cp $(Build.BinariesDirectory)/training_wasm_simd/${{ parameters.BuildConfig }}/ort-training-wasm-simd.wasm $(Build.ArtifactStagingDirectory)/ort-training-wasm-simd.wasm + cp $(Build.BinariesDirectory)/training_wasm_simd/${{ parameters.BuildConfig }}/ort-training-wasm-simd.js $(Build.ArtifactStagingDirectory)/ort-training-wasm-simd.js + fi + displayName: 'Create Artifacts' + - ${{ if eq(parameters.SkipPublish, false) }}: + - task: PublishPipelineArtifact@0 + displayName: 'Publish Pipeline Artifact' + inputs: + artifactName: '${{ parameters.BuildConfig }}_wasm' + targetPath: '$(Build.ArtifactStagingDirectory)' + - task: PublishTestResults@2 + displayName: 'Publish unit test results' + inputs: + testResultsFiles: '**/*.results.xml' + 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/linux-web-init-and-check.yml b/tools/ci_build/github/azure-pipelines/templates/linux-web-init-and-check.yml new file mode 100644 index 0000000000000..abd8c94dabd91 --- /dev/null +++ b/tools/ci_build/github/azure-pipelines/templates/linux-web-init-and-check.yml @@ -0,0 +1,41 @@ +steps: +- script: | + npm ci + workingDirectory: '$(Build.SourcesDirectory)/js' + displayName: 'npm ci /js/' +- script: | + npm run lint + workingDirectory: '$(Build.SourcesDirectory)/js' + displayName: 'run ESLint without TS type populated' +- script: | + npm ci + workingDirectory: '$(Build.SourcesDirectory)/js/common' + displayName: 'npm ci /js/common/' +- script: | + npm test + workingDirectory: '$(Build.SourcesDirectory)/js/common' + displayName: 'run onnxruntime-common tests' +- script: | + npm ci + workingDirectory: '$(Build.SourcesDirectory)/js/web' + displayName: 'npm ci /js/web/' +- script: | + npm run lint + workingDirectory: '$(Build.SourcesDirectory)/js' + displayName: 'run ESLint' +- script: | + 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)" + workingDirectory: '$(Build.SourcesDirectory)/js' + displayName: 'Check unformatted files' +- script: | + 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)" + workingDirectory: '$(Build.SourcesDirectory)/js/web' + displayName: 'Check out of dated documents' diff --git a/tools/ci_build/github/azure-pipelines/templates/mac-build-step-with-cache.yml b/tools/ci_build/github/azure-pipelines/templates/mac-build-step-with-cache.yml index f1aa581b75c82..86afad27863a6 100644 --- a/tools/ci_build/github/azure-pipelines/templates/mac-build-step-with-cache.yml +++ b/tools/ci_build/github/azure-pipelines/templates/mac-build-step-with-cache.yml @@ -29,6 +29,8 @@ parameters: steps: - script: | which ccache || brew install ccache + # Do not output ##vso[] commands with `set -x` or they may be parsed again and include a trailing quote. + set +x echo "##vso[task.prependpath]/usr/local/opt/ccache/libexec" mkdir -p "${{ parameters.CacheDir }}" displayName: Install ccache and update PATH to use linked versions of gcc, cc, etc 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 803cf2ef30bc9..080079388a76c 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 @@ -22,78 +22,122 @@ parameters: type: boolean default: false +- name: DoESRP + displayName: Do ESRP + type: boolean + default: false + +# 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' + stages: - stage: MacOS_C_API_Packaging_CPU dependsOn: [] jobs: - - ${{ if eq(parameters.BuildForAllArchs, true) }}: - template: mac-cpu-packing-jobs.yml parameters: MacosArch: 'x86_64' AllowReleasedOpsetOnly: ${{ parameters.AllowReleasedOpsetOnly }} AdditionalBuildFlags: ${{ parameters.AdditionalBuildFlags }} WithCache: ${{ parameters.WithCache }} - - 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 }} - - job: MacOS_C_API_Package_Publish_All - dependsOn: - - MacOS_C_API_Packaging_CPU_x86_64 - - MacOS_C_API_Packaging_CPU_arm64 - - MacOS_C_API_Packaging_CPU_universal2 - pool: - vmImage: 'macOS-12' - steps: - - task: DownloadPipelineArtifact@2 - inputs: - artifact: 'onnxruntime-osx-x86_64' - targetPath: '$(Build.ArtifactStagingDirectory)' - - task: DownloadPipelineArtifact@2 - inputs: - artifact: 'onnxruntime-osx-arm64' - targetPath: '$(Build.ArtifactStagingDirectory)' - - task: DownloadPipelineArtifact@2 - inputs: - artifact: 'onnxruntime-osx-universal2' - targetPath: '$(Build.ArtifactStagingDirectory)' - - task: PublishPipelineArtifact@1 - inputs: - targetPath: '$(Build.ArtifactStagingDirectory)' - artifact: 'onnxruntime-osx' - condition: 'succeededOrFailed()' - - template: component-governance-component-detection-steps.yml + + - ${{ if eq(parameters.BuildForAllArchs, true) }}: + - template: mac-cpu-packing-jobs.yml parameters: - condition: 'succeeded' - - ${{ if ne(parameters.BuildForAllArchs, true) }}: - - template: mac-cpu-packing-jobs.yml - parameters: - MacosArch: 'x86_64' - AllowReleasedOpsetOnly: ${{ parameters.AllowReleasedOpsetOnly }} - AdditionalBuildFlags: ${{ parameters.AdditionalBuildFlags }} - WithCache: ${{ parameters.WithCache }} - - job: MacOS_C_API_Package_Publish_x86_64 - dependsOn: MacOS_C_API_Packaging_CPU_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 }} + +- stage: MacOS_C_API_Package_Publish + dependsOn: MacOS_C_API_Packaging_CPU + jobs: + - job: MacOS_C_API_Package_Publish pool: - vmImage: 'macOS-12' + ${{ if eq(parameters.DoESRP, true)}}: + vmImage: 'macOS-12' + ${{ else }}: + vmImage: 'macOS-13' steps: - - task: DownloadPipelineArtifact@2 - inputs: - artifact: 'onnxruntime-osx-x86_64' - targetPath: '$(Build.ArtifactStagingDirectory)' + - 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-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' + - task: PublishPipelineArtifact@1 inputs: targetPath: '$(Build.ArtifactStagingDirectory)' artifact: 'onnxruntime-osx' condition: 'succeededOrFailed()' + - template: component-governance-component-detection-steps.yml parameters: - condition: 'succeeded' \ No newline at end of file + condition: 'succeeded' 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 e4de00f2fc2d8..adfcd98e37230 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,7 @@ jobs: PROTO_CACHE_DIR: $(Pipeline.Workspace)/ccache_proto ORT_CACHE_DIR: $(Pipeline.Workspace)/ccache_ort pool: - vmImage: 'macOS-12' + vmImage: 'macOS-13' timeoutInMinutes: 300 steps: - checkout: self @@ -45,16 +45,17 @@ jobs: submodules: none - task: UsePythonVersion@0 - # Use python 3.8 to avoid build some of the required packages - displayName: Use Python 3.8 + displayName: Use Python 3.11 inputs: - versionSpec: 3.8 + versionSpec: 3.11 - task: NodeTool@0 inputs: versionSpec: '16.x' - template: set-version-number-variables-step.yml + - template: use-xcode-version.yml + - template: mac-build-step-with-cache.yml parameters: WithCache: ${{ parameters.WithCache }} @@ -72,7 +73,6 @@ jobs: export ONNX_ML=1 export CMAKE_ARGS="-DONNX_GEN_PB_TYPE_STUBS=OFF -DONNX_WERROR=OFF" python3 -m pip install -r '$(Build.SourcesDirectory)/tools/ci_build/github/linux/docker/scripts/requirements.txt' - sudo xcode-select --switch /Applications/Xcode_13.1.app/Contents/Developer displayName: 'Install dependencies' env: CCACHE_DIR: $(PROTO_CACHE_DIR) diff --git a/tools/ci_build/github/azure-pipelines/templates/mac-esrp-dll.yml b/tools/ci_build/github/azure-pipelines/templates/mac-esrp-dylib.yml similarity index 69% rename from tools/ci_build/github/azure-pipelines/templates/mac-esrp-dll.yml rename to tools/ci_build/github/azure-pipelines/templates/mac-esrp-dylib.yml index 008ab59e9163e..a9a0d87a30e38 100644 --- a/tools/ci_build/github/azure-pipelines/templates/mac-esrp-dll.yml +++ b/tools/ci_build/github/azure-pipelines/templates/mac-esrp-dylib.yml @@ -1,12 +1,24 @@ parameters: - FolderPath: '' - DisplayName: '' - DoEsrp: 'false' - Pattern: '*.dll' +- name: DoEsrp + type: boolean + default: true + +- name: FolderPath + type: string + default: '' + +- name: DisplayName + type: string + default: '' + +- name: Pattern + type: string + default: '*.zip' steps: -- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@2 +- task: EsrpCodeSigning@3 displayName: ${{ parameters.DisplayName }} + condition: and(succeeded(), eq('${{ parameters.DoEsrp }}', true)) inputs: ConnectedServiceName: 'OnnxRuntime CodeSign 20190817' FolderPath: ${{ parameters.FolderPath }} @@ -15,8 +27,8 @@ steps: inlineOperation: | [ { - "keyCode": "CP-230012", - "operationSetCode": "SigntoolSign", + "keyCode": "CP-401337-Apple", + "operationSetCode": "MacAppDeveloperSign", "parameters": [ { "parameterName": "OpusName", @@ -39,7 +51,7 @@ steps: "parameterValue": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256" } ], - "toolName": "signtool", - "toolVersion": "6.2.9304.0" + "toolName": "sign", + "toolVersion": "1.0" } ] 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 new file mode 100644 index 0000000000000..792e828c9a880 --- /dev/null +++ b/tools/ci_build/github/azure-pipelines/templates/ondevice-training-cpu-packaging-pipeline.yml @@ -0,0 +1,371 @@ +parameters: +- name: RunOnnxRuntimeTests + 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 + default: false + +- name: IsReleaseBuild + displayName: Is a release build? Set it to true if you are doing an Onnx Runtime release. + type: boolean + default: false + +- name: AdditionalBuildFlags + displayName: Additional build flags for build.py + type: string + default: '' + +- name: AdditionalWinBuildFlags + displayName: Additional build flags that just for Windows Builds + type: string + default: '' + +- name: OrtNugetPackageId + displayName: Package name for nuget + type: string + default: 'Microsoft.ML.OnnxRuntime.Training' + +- name: BuildVariant + type: string + default: 'default' + +stages: +- template: linux-cpu-packaging-pipeline.yml + parameters: + AdditionalBuildFlags: ${{ parameters.AdditionalBuildFlags }} + stage_name_suffix: Training_CPU + ArtifactNamePrefix: onnxruntime-training + PackageJava: false + PackageNodeJS: false + +- template: win-ci.yml + parameters: + DoCompliance: ${{ parameters.DoCompliance }} + DoEsrp: ${{ parameters.DoEsrp }} + stage_name_suffix: Training_CPU_x86_${{ parameters.BuildVariant }} + artifact_name_suffix: -training + EnvSetupScript: setup_env_x86.bat + buildArch: x86 + msbuildPlatform: Win32 + packageName: x86 + buildparameter: ${{ parameters.AdditionalBuildFlags }} ${{ parameters.AdditionalWinBuildFlags}} + runTests: ${{ parameters.RunOnnxRuntimeTests }} + buildJava: false + buildNodejs: false + +- template: win-ci.yml + parameters: + DoCompliance: ${{ parameters.DoCompliance }} + DoEsrp: ${{ parameters.DoEsrp }} + stage_name_suffix: Training_CPU_arm_${{ parameters.BuildVariant }} + artifact_name_suffix: -training + EnvSetupScript: setup_env.bat + buildArch: x64 + msbuildPlatform: arm + packageName: arm + buildparameter: --arm ${{ parameters.AdditionalBuildFlags }} ${{ parameters.AdditionalWinBuildFlags}} --path_to_protoc_exe $(Build.BinariesDirectory)\RelWithDebInfo\installed\bin\protoc.exe + runTests: false + buildJava: false + buildNodejs: false + ort_build_pool_name: onnxruntime-Win-CPU-2022 + +- template: win-ci.yml + parameters: + DoCompliance: ${{ parameters.DoCompliance }} + DoEsrp: ${{ parameters.DoEsrp }} + stage_name_suffix: Training_CPU_arm64_${{ parameters.BuildVariant }} + artifact_name_suffix: -training + EnvSetupScript: setup_env.bat + buildArch: x64 + msbuildPlatform: arm64 + packageName: arm64 + buildparameter: --arm64 ${{ parameters.AdditionalBuildFlags }} ${{ parameters.AdditionalWinBuildFlags}} --path_to_protoc_exe $(Build.BinariesDirectory)\RelWithDebInfo\installed\bin\protoc.exe + runTests: false + buildJava: false + buildNodejs: false + +- template: win-ci.yml + parameters: + DoCompliance: ${{ parameters.DoCompliance }} + DoEsrp: ${{ parameters.DoEsrp }} + stage_name_suffix: Training_CPU_x64_${{ parameters.BuildVariant }} + artifact_name_suffix: -training + EnvSetupScript: setup_env.bat + buildArch: x64 + msbuildPlatform: x64 + packageName: x64 + buildparameter: ${{ parameters.AdditionalBuildFlags }} ${{ parameters.AdditionalWinBuildFlags}} + runTests: ${{ parameters.RunOnnxRuntimeTests }} + buildJava: false + buildNodejs: false + +- stage: Android_Java_API_AAR_Packaging_Training_Full + dependsOn: [] + jobs: + - template: android-java-api-aar.yml + parameters: + buildConfig: 'Release' + buildSettings: '$(Build.SourcesDirectory)/tools/ci_build/github/android/training_full_aar_build_settings.json' + artifactName: 'onnxruntime-training-android-full-aar' + job_name_suffix: 'Training_Full' + publish_executables: '1' + packageName: onnxruntime-training-android + - template: android-java-api-aar-test.yml + parameters: + artifactName: 'onnxruntime-training-android-full-aar' + job_name_suffix: 'Training_Full' + packageName: onnxruntime-training-android + +- stage: NuGet_Packaging_Training_CPU + dependsOn: + - Setup + - Linux_C_API_Packaging_Training_CPU + - Windows_Packaging_Training_CPU_x86_${{ parameters.BuildVariant }} + - Windows_Packaging_Training_CPU_x64_${{ parameters.BuildVariant }} + - Windows_Packaging_Training_CPU_arm_${{ parameters.BuildVariant }} + - Windows_Packaging_Training_CPU_arm64_${{ parameters.BuildVariant }} + - Android_Java_API_AAR_Packaging_Training_Full + condition: succeeded() + jobs: + - job: + workspace: + clean: all + # we need to use the 2022 pool to create the nuget package with both pre-net6+Xamarin and net6 targets. + # VS2019 has no support for net6 and we need to use msbuild (from the VS install) to do the packing + pool: 'Azure-Pipelines-EO-Windows2022-aiinfra' + variables: + OrtPackageId: ${{ parameters.OrtNugetPackageId }} + breakCodesignValidationInjection: ${{ parameters.DoEsrp }} + ReleaseVersionSuffix: $[stageDependencies.Setup.Set_Variables.outputs['Set_Release_Version_Suffix.ReleaseVersionSuffix']] + + steps: + - checkout: self + submodules: true + - task: DownloadPipelineArtifact@0 + displayName: 'Download win-x64 Pipeline Artifact' + inputs: + artifactName: 'onnxruntime-training-win-x64' + targetPath: '$(Build.BinariesDirectory)/nuget-artifact' + + - task: DownloadPipelineArtifact@0 + displayName: 'Download win-x86 Pipeline Artifact' + inputs: + artifactName: 'onnxruntime-training-win-x86' + targetPath: '$(Build.BinariesDirectory)/nuget-artifact' + + - task: DownloadPipelineArtifact@0 + displayName: 'Download win-arm64 Pipeline Artifact' + inputs: + artifactName: 'onnxruntime-training-win-arm64' + targetPath: '$(Build.BinariesDirectory)/nuget-artifact' + + - task: DownloadPipelineArtifact@0 + displayName: 'Download win-arm Pipeline Artifact' + inputs: + artifactName: 'onnxruntime-training-win-arm' + targetPath: '$(Build.BinariesDirectory)/nuget-artifact' + + - task: DownloadPipelineArtifact@0 + displayName: 'Download linux-x64 Pipeline Artifact' + inputs: + artifactName: 'onnxruntime-training-linux-x64' + targetPath: '$(Build.BinariesDirectory)/nuget-artifact' + + - task: DownloadPipelineArtifact@0 + displayName: 'Download linux-aarch64 Pipeline Artifact - NuGet' + inputs: + artifactName: 'onnxruntime-training-linux-aarch64' + targetPath: '$(Build.BinariesDirectory)/nuget-artifact' + + - task: DownloadPipelineArtifact@2 + displayName: 'Download android-full-aar Pipeline Artifact' + inputs: + artifactName: 'onnxruntime-training-android-full-aar' + patterns: '**/*.aar' + targetPath: '$(Build.BinariesDirectory)/nuget-artifact' + + - task: DownloadPipelineArtifact@0 + displayName: 'Download drop-extra Pipeline Artifact' + inputs: + artifactName: 'drop-extra-training' + targetPath: '$(Build.BinariesDirectory)/extra-artifact' + + - script: | + dir + workingDirectory: '$(Build.BinariesDirectory)/nuget-artifact' + displayName: 'List artifacts' + + # Reconstruct the build dir + - task: PowerShell@2 + displayName: 'Extract native libraries for addition to nuget native package' + inputs: + targetType: filePath + filePath: $(Build.SourcesDirectory)\tools\ci_build\github\windows\extract_nuget_files.ps1 + + - script: | + mklink /D /J models C:\local\models + workingDirectory: '$(Build.BinariesDirectory)' + displayName: 'Create models link' + + - task: NuGetToolInstaller@0 + displayName: Use Nuget 6.2.1 + inputs: + versionSpec: 6.2.1 + + - task: PowerShell@2 + displayName: Install .NET 6 workloads + inputs: + targetType: 'inline' + script: | + dotnet workload install android + workingDirectory: '$(Build.SourcesDirectory)\csharp' + + - task: PowerShell@2 + displayName: Build Microsoft.ML.OnnxRuntime .NET 6 targets using dotnet + inputs: + targetType: 'inline' + # we don't specify 'Any CPU' as the platform here because if we do it gets added to the output path + # e.g. csharp\src\Microsoft.ML.OnnxRuntime\bin\Any CPU\RelWithDebInfo\net6.0-ios\ + # which is inconsistent with the msbuild output path for the pre-.net6 targets + # e.g. csharp\src\Microsoft.ML.OnnxRuntime\bin\RelWithDebInfo\monoandroid11.0 + # and makes it harder to do the packing + # + # 'Any CPU' is the default (first 'mixed' platform specified in the csproj) so this should be fine. + script: | + dotnet build .\src\Microsoft.ML.OnnxRuntime\Microsoft.ML.OnnxRuntime.csproj -p:SelectedTargets=Net6 -p:Configuration=RelWithDebInfo -p:OnnxRuntimeBuildDirectory="$(Build.BinariesDirectory)" -p:OrtPackageId=$(OrtPackageId) -p:IsReleaseBuild=${{ parameters.IsReleaseBuild }} -p:ReleaseVersionSuffix=$(ReleaseVersionSuffix) + workingDirectory: '$(Build.SourcesDirectory)\csharp' + + - task: MSBuild@1 + displayName: 'Restore NuGet Packages and create project.assets.json for pre-.net6 targets' + inputs: + solution: '$(Build.SourcesDirectory)\csharp\OnnxRuntime.CSharp.sln' + platform: 'Any CPU' + configuration: RelWithDebInfo + msbuildArguments: '-t:restore -p:SelectedTargets=PreNet6 -p:OrtPackageId=$(OrtPackageId)' + workingDirectory: '$(Build.SourcesDirectory)\csharp' + + - task: MSBuild@1 + displayName: 'Build C# for pre-.net6 targets' + inputs: + solution: '$(Build.SourcesDirectory)\csharp\OnnxRuntime.CSharp.sln' + platform: 'Any CPU' + configuration: RelWithDebInfo + msbuildArguments: '-p:SelectedTargets=PreNet6 -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\RelWithDebInfo' + DisplayName: 'ESRP - Sign C# dlls' + DoEsrp: ${{ parameters.DoEsrp }} + + - task: MSBuild@1 + displayName: Update projects.assets.json with combined list of all target frameworks + inputs: + solution: '$(Build.SourcesDirectory)\csharp\src\Microsoft.ML.OnnxRuntime\Microsoft.ML.OnnxRuntime.csproj' + platform: 'Any CPU' + configuration: RelWithDebInfo + msbuildArguments: '-t:restore -p:SelectedTargets=All -p:OrtPackageId=$(OrtPackageId)' + workingDirectory: '$(Build.SourcesDirectory)\csharp' + + - task: MSBuild@1 + displayName: 'Build Nuget Packages' + inputs: + solution: '$(Build.SourcesDirectory)\csharp\OnnxRuntime.CSharp.proj' + platform: 'Any CPU' + configuration: RelWithDebInfo + msbuildArguments: '-t:CreatePackage -p:OnnxRuntimeBuildDirectory="$(Build.BinariesDirectory)" -p:OrtPackageId=$(OrtPackageId) -p:IsReleaseBuild=${{ parameters.IsReleaseBuild }}' + workingDirectory: '$(Build.SourcesDirectory)\csharp' + + - task: CopyFiles@2 + displayName: 'Copy native nuget package to: $(Build.ArtifactStagingDirectory)' + inputs: + SourceFolder: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo' + Contents: '*.nupkg' + TargetFolder: '$(Build.ArtifactStagingDirectory)' + + - task: CopyFiles@2 + displayName: 'Copy native nuget symbols package to: $(Build.ArtifactStagingDirectory)' + inputs: + SourceFolder: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo' + Contents: '*.snupkg' + TargetFolder: '$(Build.ArtifactStagingDirectory)' + + - task: CopyFiles@2 + displayName: 'Copy managed nuget package to: $(Build.ArtifactStagingDirectory)' + inputs: + SourceFolder: '$(Build.SourcesDirectory)\csharp\src\Microsoft.ML.OnnxRuntime\bin\RelWithDebInfo' + Contents: '*.nupkg' + TargetFolder: '$(Build.ArtifactStagingDirectory)' + + - template: esrp_nuget.yml + parameters: + DisplayName: 'ESRP - sign NuGet package' + FolderPath: '$(Build.ArtifactStagingDirectory)' + DoEsrp: ${{ parameters.DoEsrp }} + + - template: validate-package.yml + parameters: + PackageType: 'nuget' + PackagePath: '$(Build.ArtifactStagingDirectory)' + PackageName: 'Microsoft.ML.OnnxRuntime.Training.*nupkg' + PlatformsSupported: 'win-x64,win-x86,linux-x64,linux-arm64' + VerifyNugetSigning: false + + - task: PublishPipelineArtifact@0 + displayName: 'Publish Pipeline NuGet Artifact' + inputs: + artifactName: 'drop-signed-nuget-Training-CPU' + 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=$(OrtPackageId)' + workingDirectory: '$(Build.SourcesDirectory)\csharp' + + - task: RoslynAnalyzers@2 + displayName: 'Run Roslyn Analyzers' + inputs: + userProvideBuildInfo: msBuildInfo + msBuildCommandline: '"C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\msbuild.exe" $(Build.SourcesDirectory)\csharp\OnnxRuntime.CSharp.sln -p:configuration="RelWithDebInfo" -p:Platform="Any CPU" -p:OnnxRuntimeBuildDirectory="$(Build.BinariesDirectory)" -p:OrtPackageId=$(OrtPackageId)' + condition: and(succeeded(), eq('${{ parameters.DoCompliance }}', true)) + + - template: component-governance-component-detection-steps.yml + parameters : + condition : 'succeeded' + + - task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3 + displayName: 'Clean Agent Directories' + condition: always() + +- template: ../nuget/templates/test_win.yml + parameters: + AgentPool : 'onnxruntime-Win-CPU-2022' + Skipx86Tests : false + NugetPackageName : 'Microsoft.ML.OnnxRuntime.Training' + ArtifactSuffix: 'Training-CPU' + StageSuffix: 'Training_CPU' + TestDataArtifactSuffix: '-training' + +- template: ../nuget/templates/test_linux.yml + parameters: + AgentPool : onnxruntime-Ubuntu2004-AMD-CPU + NugetPackageName : 'Microsoft.ML.OnnxRuntime.Training' + ArtifactSuffix: 'Training-CPU' + StageSuffix: 'Training_CPU' + NativePackagePrefix: 'onnxruntime-training' diff --git a/tools/ci_build/github/azure-pipelines/templates/orttraining-linux-gpu-ortmodule-test-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/templates/orttraining-linux-gpu-test-ci-pipeline.yml similarity index 75% rename from tools/ci_build/github/azure-pipelines/templates/orttraining-linux-gpu-ortmodule-test-ci-pipeline.yml rename to tools/ci_build/github/azure-pipelines/templates/orttraining-linux-gpu-test-ci-pipeline.yml index 68d6b4d4a3e72..5dc156e301357 100644 --- a/tools/ci_build/github/azure-pipelines/templates/orttraining-linux-gpu-ortmodule-test-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/templates/orttraining-linux-gpu-test-ci-pipeline.yml @@ -33,7 +33,21 @@ steps: --volume /bert_data:/bert_data \ --volume /hf_models_cache:/hf_models_cache \ ${{ parameters.DockerImageTag }} \ - bash -c "rm -rf /build/onnxruntime/ && python3 -m pip install /build/dist/onnxruntime*.whl && python3 -m onnxruntime.training.ortmodule.torch_cpp_extensions.install && /build/launch_test.py --cmd_line_with_args 'python orttraining_ortmodule_tests.py --mnist /mnist --bert_data /bert_data/hf_data/glue_data/CoLA/original/raw --transformers_cache /hf_models_cache/huggingface/transformers' --cwd /build" \ + bash -c "rm -rf /build/onnxruntime/ && python3 -m pip install /build/dist/onnxruntime*.whl && python3 -m onnxruntime.training.ortmodule.torch_cpp_extensions.install && /build/launch_test.py --cmd_line_with_args 'python orttraining_ortmodule_tests.py --mnist /mnist --bert_data /bert_data/hf_data/glue_data/CoLA/original/raw' --cwd /build" \ displayName: 'Run orttraining_ortmodule_tests.py' condition: succeededOrFailed() timeoutInMinutes: 60 + +# Entry point for all ort training api tests +- script: | + docker run \ + --gpus all \ + --shm-size=1024m \ + --rm \ + --volume $(Build.SourcesDirectory):/onnxruntime_src \ + --volume $(Build.BinariesDirectory)/${{ parameters.BuildConfig }}:/build \ + ${{ parameters.DockerImageTag }} \ + bash -c "rm -rf /build/onnxruntime/ && python3 -m pip install /build/dist/onnxruntime*.whl && /build/launch_test.py --cmd_line_with_args 'python orttraining_test_ort_apis.py --cwd /build' --cwd /build" \ + displayName: 'Run ORT Training APIs Tests' + condition: succeededOrFailed() + timeoutInMinutes: 120 diff --git a/tools/ci_build/github/azure-pipelines/templates/publish-nuget.yml b/tools/ci_build/github/azure-pipelines/templates/publish-nuget.yml index e3f3fdf808e8e..90020d217b800 100644 --- a/tools/ci_build/github/azure-pipelines/templates/publish-nuget.yml +++ b/tools/ci_build/github/azure-pipelines/templates/publish-nuget.yml @@ -11,8 +11,11 @@ stages: - NuGet_Test_Linux_CPU - NuGet_Test_Win_GPU - NuGet_Test_Linux_GPU + - NuGet_Test_Linux_ROCm - NuGet_Test_MacOS - NuGet_Packaging_DML + - NuGet_Test_Win_Training_CPU + - NuGet_Test_Linux_Training_CPU jobs: - job: workspace: @@ -20,7 +23,7 @@ stages: variables: - name: GDN_CODESIGN_TARGETDIRECTORY value: '$(Build.BinariesDirectory)/nuget-artifact/final-package' - pool: 'Win-CPU-2021' + pool: 'onnxruntime-Win-CPU-2022' steps: - checkout: self @@ -55,7 +58,7 @@ stages: 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.10.14-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\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 ) @@ -78,12 +81,24 @@ stages: artifactName: 'drop-signed-nuget-dml' targetPath: $(Build.BinariesDirectory)/nuget-artifact/final-package + - task: DownloadPipelineArtifact@0 + displayName: 'Download Pipeline Artifact - Signed NuGet Package' + inputs: + artifactName: 'drop-signed-nuget-Training-CPU' + targetPath: $(Build.BinariesDirectory)/nuget-artifact/final-package + - task: DownloadPipelineArtifact@0 displayName: 'Download Pipeline Artifact - Signed NuGet Package' inputs: artifactName: 'drop-signed-nuget-GPU' targetPath: $(Build.BinariesDirectory)/nuget-artifact/final-package + - task: DownloadPipelineArtifact@0 + displayName: 'Download Pipeline Artifact - Signed NuGet ROCm Package' + inputs: + artifactName: 'drop-signed-nuget-ROCm' + targetPath: $(Build.BinariesDirectory)/nuget-artifact/final-package + - task: NuGetCommand@2 displayName: 'Copy Signed Native NuGet Package to ORT-NIGHTLY' condition: ne(variables['IsReleaseBuild'], 'true') # release build has a different package naming scheme diff --git a/tools/ci_build/github/azure-pipelines/templates/py-linux-gpu.yml b/tools/ci_build/github/azure-pipelines/templates/py-linux-gpu.yml index d8a361975916d..3d5a71284fa6f 100644 --- a/tools/ci_build/github/azure-pipelines/templates/py-linux-gpu.yml +++ b/tools/ci_build/github/azure-pipelines/templates/py-linux-gpu.yml @@ -5,6 +5,19 @@ parameters: - name: machine_pool type: string +- name: extra_build_arg + type: string + default: '' + +- name: cmake_build_type + type: string + default: 'Release' + values: + - Debug + - Release + - RelWithDebInfo + - MinSizeRel + jobs: - job: Linux_py_GPU_Wheels_${{ parameters.arch }} timeoutInMinutes: 240 @@ -23,9 +36,9 @@ jobs: - template: get-docker-image-steps.yml parameters: - Dockerfile: tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_cuda11_8_tensorrt8_6 + Dockerfile: tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda11_8_tensorrt8_6 Context: tools/ci_build/github/linux/docker - DockerBuildArgs: "--network=host --build-arg POLICY=manylinux2014 --build-arg PLATFORM=x86_64 --build-arg DEVTOOLSET_ROOTPATH=/opt/rh/devtoolset-11/root --build-arg PREPEND_PATH=/opt/rh/devtoolset-11/root/usr/bin: --build-arg LD_LIBRARY_PATH_ARG=/opt/rh/devtoolset-11/root/usr/lib64:/opt/rh/devtoolset-11/root/usr/lib:/opt/rh/devtoolset-11/root/usr/lib64/dyninst:/opt/rh/devtoolset-11/root/usr/lib/dyninst:/usr/local/lib64 --build-arg BUILD_UID=$( id -u ) --build-arg PLATFORM=${{ parameters.arch }}" + DockerBuildArgs: "--network=host --build-arg POLICY=manylinux_2_28 --build-arg PLATFORM=x86_64 --build-arg PREPEND_PATH=/usr/local/cuda/bin --build-arg LD_LIBRARY_PATH_ARG=/usr/local/lib64 --build-arg DEVTOOLSET_ROOTPATH=/usr --build-arg BUILD_UID=$( id -u ) --build-arg PLATFORM=${{ parameters.arch }}" Repository: onnxruntimecuda118xtrt86build${{ parameters.arch }} @@ -35,7 +48,7 @@ jobs: targetType: filePath filePath: tools/ci_build/github/linux/run_python_dockerbuild.sh # please check ONNXRUNTIME_CUDA_VERSION in tools/ci_build/github/linux/build_linux_arm64_python_package.sh - arguments: -i onnxruntimecuda118xtrt86build${{ parameters.arch }} -x "-d GPU" + arguments: -i onnxruntimecuda118xtrt86build${{ parameters.arch }} -d "GPU" -c ${{ parameters.cmake_build_type }} -x "${{ parameters.extra_build_arg }}" - task: PublishBuildArtifacts@1 displayName: 'Publish Artifact: ONNXRuntime python wheel' diff --git a/tools/ci_build/github/azure-pipelines/templates/py-linux-ubuntu.yml b/tools/ci_build/github/azure-pipelines/templates/py-linux-ubuntu.yml deleted file mode 100644 index 9c457dfe192ef..0000000000000 --- a/tools/ci_build/github/azure-pipelines/templates/py-linux-ubuntu.yml +++ /dev/null @@ -1,62 +0,0 @@ -parameters: -- name: arch - type: string - -- name: machine_pool - type: string - -- name: base_image - type: string - -- name: device - type: string - default: '-d CPU' - -jobs: -- job: Linux_Ubuntu_CPU_py_Wheels_${{ parameters.arch }} - timeoutInMinutes: 240 - workspace: - clean: all - pool: ${{ parameters.machine_pool }} - variables: - # The build machine pool doesn't have dotnet, so it can't run CG. - skipComponentGovernanceDetection: true - 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/Dockerfile.manylinux_2_27_cpu - Context: tools/ci_build/github/linux/docker - DockerBuildArgs: "--build-arg BUILD_UID=$( id -u ) --build-arg BASEIMAGE=${{ parameters.base_image }} --build-arg PLATFORM=${{ parameters.arch }}" - Repository: onnxruntimecpubuildubuntu20python${{ parameters.arch }} - ${{ if eq(parameters.arch, 'aarch64') }}: - UpdateDepsTxt: false - - - task: Bash@3 - displayName: 'Build Python Wheel' - inputs: - targetType: filePath - filePath: tools/ci_build/github/linux/run_python_dockerbuild.sh - arguments: -i onnxruntimecpubuildubuntu20python${{ parameters.arch }} -x "${{ parameters.device }}" - - - task: PublishBuildArtifacts@1 - displayName: 'Publish Artifact: ONNXRuntime python wheel' - inputs: - PathtoPublish: '$(Build.BinariesDirectory)/dist' - ArtifactName: onnxruntime - - - task: PublishPipelineArtifact@0 - displayName: 'Publish Test Binaries' - inputs: - artifactName: 'drop-ubuntu-cpu-${{ parameters.arch }}' - targetPath: '$(Build.BinariesDirectory)/Release' - - - - task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3 - displayName: 'Clean Agent Directories' - condition: always() 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 3645b0730fa51..0774c3350b9b1 100644 --- a/tools/ci_build/github/azure-pipelines/templates/py-linux.yml +++ b/tools/ci_build/github/azure-pipelines/templates/py-linux.yml @@ -17,14 +17,27 @@ parameters: - name: prepend_path type: string +- name: cmake_build_type + type: string + default: 'Release' + values: + - Debug + - Release + - RelWithDebInfo + - MinSizeRel + - name: device type: string - default: '-d CPU' + default: 'CPU' - name: with_cache type: boolean default: false +- name: extra_build_arg + type: string + default: '' + jobs: - job: Linux_py_Wheels_${{ parameters.arch }} timeoutInMinutes: 240 @@ -49,10 +62,10 @@ jobs: - template: get-docker-image-steps.yml parameters: - Dockerfile: tools/ci_build/github/linux/docker/inference/x64/python/cpu/Dockerfile.manylinux2014_cpu + Dockerfile: tools/ci_build/github/linux/docker/inference/x64/python/cpu/Dockerfile.manylinux2_28_cpu Context: tools/ci_build/github/linux/docker/inference/x64/python/cpu - DockerBuildArgs: "--build-arg BUILD_UID=$( id -u ) --build-arg BASEIMAGE=${{ parameters.base_image }} --build-arg PLATFORM=${{ parameters.arch }} --build-arg PREPEND_PATH=${{ parameters.prepend_path }} --build-arg LD_LIBRARY_PATH_ARG=${{ parameters.ld_library_path_arg }} --build-arg DEVTOOLSET_ROOTPATH=${{ parameters.devtoolset_rootpath }}" - Repository: onnxruntimecpubuilpython${{ parameters.arch }} + DockerBuildArgs: "--build-arg POLICY=manylinux_2_28 --build-arg BUILD_UID=$( id -u ) --build-arg BASEIMAGE=${{ parameters.base_image }} --build-arg PLATFORM=${{ parameters.arch }} --build-arg PREPEND_PATH=${{ parameters.prepend_path }} --build-arg LD_LIBRARY_PATH_ARG=${{ parameters.ld_library_path_arg }} --build-arg DEVTOOLSET_ROOTPATH=${{ parameters.devtoolset_rootpath }}" + Repository: onnxruntimecpubuildpython${{ parameters.arch }} ${{ if eq(parameters.arch, 'aarch64') }}: UpdateDepsTxt: false @@ -69,7 +82,7 @@ jobs: inputs: targetType: filePath filePath: tools/ci_build/github/linux/run_python_dockerbuild.sh - arguments: -i onnxruntimecpubuilpython${{ parameters.arch }} -x "${{ parameters.device }}" + arguments: -i onnxruntimecpubuildpython${{ parameters.arch }} -d "${{ parameters.device }}" -c ${{ parameters.cmake_build_type }} -x "${{ parameters.extra_build_arg }}" ${{ 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" @@ -84,4 +97,4 @@ jobs: displayName: 'Publish Test Binaries' inputs: artifactName: 'drop-linux-cpu-${{ parameters.arch }}' - targetPath: '$(Build.BinariesDirectory)/Release' + targetPath: '$(Build.BinariesDirectory)/${{ parameters.cmake_build_type }}' 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 cee3bd9c9e968..8d5ca19a73535 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 @@ -39,36 +39,22 @@ jobs: versionSpec: $(PythonVersion) architecture: ${{ parameters.python_arch }} - - task: DownloadPipelineArtifact@2 - displayName: 'Download Pipeline Artifact' - inputs: - artifactName: 'onnxruntime' - targetPath: '$(Build.BinariesDirectory)/whl' - itemPattern: ${{parameters.itemPattern}} - # The public ADO project - ${{ if eq(variables['System.CollectionId'], 'f3ad12f2-e480-4533-baf2-635c95467d29') }}: - buildType: current - # The private ADO project - ${{ if eq(variables['System.CollectionId'], 'bc038106-a83b-4dab-9dd3-5a41bc58f34c') }}: - project: '530acbc4-21bc-487d-8cd8-348ff451d2ff' - definition: 841 - preferTriggeringPipeline: true - runVersion: 'latest' - buildType: specific + - download: build # pipeline resource identifier. + artifact: 'onnxruntime' - task: Bash@3 inputs: targetType: 'inline' script: | set -ex - files=(whl/*.whl) + files=(*.whl) 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 "$(Build.BinariesDirectory)/whl" $PYTHON_PACKAGE_NAME - pip show $PYTHON_PACKAGE_NAME - python -c "import onnxruntime as ort; print(ort.__version__)" - workingDirectory: $(Build.BinariesDirectory) + python3 -m pip install --find-links "$(Pipeline.Workspace)/build/onnxruntime" $PYTHON_PACKAGE_NAME + python3 -m pip show $PYTHON_PACKAGE_NAME + python3 -c "import onnxruntime as ort; print(ort.__version__)" + workingDirectory: $(Pipeline.Workspace)/build/onnxruntime displayName: Test Package Installation - task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3 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 new file mode 100644 index 0000000000000..cc90085e184dc --- /dev/null +++ b/tools/ci_build/github/azure-pipelines/templates/py-packaging-linux-test-cpu.yml @@ -0,0 +1,117 @@ +parameters: +- name: arch + type: string + +- name: base_image + type: string + +- name: devtoolset_rootpath + type: string + +- name: ld_library_path_arg + type: string + +- name: prepend_path + type: string + +- name: machine_pool + type: string + +- name: extra_job_id + type: string + default: '' + +- name: python_wheel_suffix + type: string + default: '' + + +# TODO: Ideally it should fetch information from the build that triggers it +- name: cmake_build_type + type: string + default: 'Release' + values: + - Debug + - Release + - RelWithDebInfo + - MinSizeRel + +- name: timeout + type: number + default: 120 + +jobs: +- job: Linux_Test_CPU${{ parameters.extra_job_id }}_${{ parameters.arch }} + timeoutInMinutes: ${{ parameters.timeout }} + variables: + skipComponentGovernanceDetection: true + workspace: + clean: all + pool: ${{ parameters.machine_pool }} + steps: + - checkout: self + clean: true + submodules: none + # The public ADO project + - ${{ if eq(variables['System.CollectionId'], 'f3ad12f2-e480-4533-baf2-635c95467d29') }}: + - download: current # pipeline resource identifier. + artifact: 'drop-linux-cpu-${{ parameters.arch }}' + + - download: current # pipeline resource identifier. + artifact: 'onnxruntime${{ parameters.python_wheel_suffix }}' + + - bash: | + set -e -x + mv "$(Pipeline.Workspace)/drop-linux-cpu-${{ parameters.arch }}" $(Build.BinariesDirectory)/${{parameters.cmake_build_type}} + mv "$(Pipeline.Workspace)/onnxruntime${{ parameters.python_wheel_suffix }}" "$(Build.BinariesDirectory)/whl" + cp -r "$(Build.BinariesDirectory)/whl" $(Build.BinariesDirectory)/tmp + find "$(Build.BinariesDirectory)/tmp" -name '*.whl' -exec bash -c 'unzip -d "${1%.*}" "$1"' _ {} \; + # 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 }}' + + - download: build # pipeline resource identifier. + artifact: 'onnxruntime${{ parameters.python_wheel_suffix }}' + + - bash: | + set -e -x + ls $(Pipeline.Workspace)/build + mv "$(Pipeline.Workspace)/build/drop-linux-cpu-${{ parameters.arch }}" $(Build.BinariesDirectory)/${{parameters.cmake_build_type}} + mv "$(Pipeline.Workspace)/build/onnxruntime${{ parameters.python_wheel_suffix }}" "$(Build.BinariesDirectory)/whl" + cp -r "$(Build.BinariesDirectory)/whl" $(Build.BinariesDirectory)/tmp + find "$(Build.BinariesDirectory)/tmp" -name '*.whl' -exec bash -c 'unzip -d "${1%.*}" "$1"' _ {} \; + + # The BinSkim task uses a dotnet program which doesn't support ARM CPUs yet + - ${{ if eq(parameters.arch, 'x86_64') }}: + - task: BinSkim@4 + displayName: 'Run BinSkim' + inputs: + AnalyzeTargetGlob: '$(Build.BinariesDirectory)/tmp/**/*.so' + continueOnError: true + + #- task: PostAnalysis@2 + # inputs: + # GdnBreakAllTools: true + # GdnBreakPolicy: M365 + # GdnBreakPolicyMinSev: Error + + - template: get-docker-image-steps.yml + parameters: + Dockerfile: tools/ci_build/github/linux/docker/inference/x64/python/cpu/Dockerfile.manylinux2_28_cpu + Context: tools/ci_build/github/linux/docker/inference/x64/python/cpu + DockerBuildArgs: "--build-arg POLICY=manylinux_2_28 --build-arg BUILD_UID=$( id -u ) --build-arg BASEIMAGE=${{ parameters.base_image }} --build-arg PLATFORM=${{ parameters.arch }} --build-arg PREPEND_PATH=${{ parameters.prepend_path }} --build-arg LD_LIBRARY_PATH_ARG=${{ parameters.ld_library_path_arg }} --build-arg DEVTOOLSET_ROOTPATH=${{ parameters.devtoolset_rootpath }}" + Repository: onnxruntimecpubuildpython${{ parameters.arch }} + ${{ if eq(parameters.arch, 'aarch64') }}: + UpdateDepsTxt: false + + - task: Bash@3 + displayName: 'Bash Script' + inputs: + targetType: filePath + filePath: tools/ci_build/github/linux/run_python_dockertest.sh + arguments: -d CPU -c ${{parameters.cmake_build_type}} -i onnxruntimecpubuildpython${{ parameters.arch }} + + - task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3 + displayName: 'Clean Agent Directories' + condition: always() 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 new file mode 100644 index 0000000000000..43ed0172825bc --- /dev/null +++ b/tools/ci_build/github/azure-pipelines/templates/py-packaging-linux-test-cuda.yml @@ -0,0 +1,98 @@ +parameters: +- name: arch + type: string + +- name: device + type: string + values: + - CPU + - GPU + +- name: machine_pool + type: string + +- name: extra_job_id + type: string + default: '' + +- name: python_wheel_suffix + type: string + default: '' + + +# TODO: Ideally it should fetch information from the build that triggers it +- name: cmake_build_type + type: string + default: 'Release' + values: + - Debug + - Release + - RelWithDebInfo + - MinSizeRel + +- name: timeout + type: number + default: 120 + +jobs: +- job: Linux_Test_GPU${{ parameters.extra_job_id }}_${{ parameters.arch }} + timeoutInMinutes: ${{ parameters.timeout }} + variables: + skipComponentGovernanceDetection: true + workspace: + clean: all + pool: ${{ parameters.machine_pool }} + steps: + - checkout: self + clean: true + submodules: none + # The public ADO project + # - ${{ if eq(variables['System.CollectionId'], 'f3ad12f2-e480-4533-baf2-635c95467d29') }}: + + # The private ADO project + - ${{ if eq(variables['System.CollectionId'], 'bc038106-a83b-4dab-9dd3-5a41bc58f34c') }}: + - download: build # pipeline resource identifier. + artifact: 'drop-linux-gpu-${{ parameters.arch }}' + + - download: build # pipeline resource identifier. + artifact: 'onnxruntime${{ parameters.python_wheel_suffix }}' + + - bash: | + set -e -x + ls $(Pipeline.Workspace)/build + mv "$(Pipeline.Workspace)/build/drop-linux-gpu-${{ parameters.arch }}" $(Build.BinariesDirectory)/${{parameters.cmake_build_type}} + mv "$(Pipeline.Workspace)/build/onnxruntime${{ parameters.python_wheel_suffix }}" "$(Build.BinariesDirectory)/whl" + cp -r "$(Build.BinariesDirectory)/whl" $(Build.BinariesDirectory)/tmp + find "$(Build.BinariesDirectory)/tmp" -name '*.whl' -exec bash -c 'unzip -d "${1%.*}" "$1"' _ {} \; + + # The BinSkim task uses a dotnet program which doesn't support ARM CPUs yet + - ${{ if eq(parameters.arch, 'x86_64') }}: + - task: BinSkim@4 + displayName: 'Run BinSkim' + inputs: + AnalyzeTargetGlob: '$(Build.BinariesDirectory)/tmp/**/*.so' + continueOnError: true + + #- task: PostAnalysis@2 + # inputs: + # GdnBreakAllTools: true + # GdnBreakPolicy: M365 + # GdnBreakPolicyMinSev: Error + + - template: get-docker-image-steps.yml + parameters: + Dockerfile: tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda11_8_tensorrt8_6 + Context: tools/ci_build/github/linux/docker + DockerBuildArgs: "--network=host --build-arg POLICY=manylinux_2_28 --build-arg PLATFORM=x86_64 --build-arg PREPEND_PATH=/usr/local/cuda/bin --build-arg LD_LIBRARY_PATH_ARG=/usr/local/lib64 --build-arg DEVTOOLSET_ROOTPATH=/usr --build-arg BUILD_UID=$( id -u ) --build-arg PLATFORM=${{ parameters.arch }}" + Repository: onnxruntimecuda118xtrt86build${{ parameters.arch }} + + - task: Bash@3 + displayName: 'Bash Script' + inputs: + targetType: filePath + filePath: tools/ci_build/github/linux/run_python_dockertest.sh + arguments: -d GPU -c ${{parameters.cmake_build_type}} -i onnxruntimecuda118xtrt86build${{ parameters.arch }} + + - task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3 + displayName: 'Clean Agent Directories' + condition: always() diff --git a/tools/ci_build/github/azure-pipelines/templates/py-packaging-linux-test.yml b/tools/ci_build/github/azure-pipelines/templates/py-packaging-linux-test.yml deleted file mode 100644 index 7868941e8a9d5..0000000000000 --- a/tools/ci_build/github/azure-pipelines/templates/py-packaging-linux-test.yml +++ /dev/null @@ -1,74 +0,0 @@ -parameters: -- name: arch - type: string - -- name: device - type: string - -- name: machine_pool - type: string - -- name: extra_job_id - type: string - default: '' - -- name: python_wheel_suffix - type: string - default: '' - -- name: timeout - type: number - default: 120 - -jobs: -- job: Linux_Test_${{ parameters.device }}${{ parameters.extra_job_id }}_${{ parameters.arch }} - timeoutInMinutes: ${{ parameters.timeout }} - variables: - skipComponentGovernanceDetection: true - workspace: - clean: all - pool: ${{ parameters.machine_pool }} - steps: - - task: DownloadPipelineArtifact@2 - displayName: 'Download Pipeline Artifact' - inputs: - artifactName: 'drop-linux-${{ lower(parameters.device) }}-${{ parameters.arch }}' - targetPath: '$(Build.BinariesDirectory)/Release' - # The public ADO project - ${{ if eq(variables['System.CollectionId'], 'f3ad12f2-e480-4533-baf2-635c95467d29') }}: - buildType: current - # The private ADO project - ${{ if eq(variables['System.CollectionId'], 'bc038106-a83b-4dab-9dd3-5a41bc58f34c') }}: - project: '530acbc4-21bc-487d-8cd8-348ff451d2ff' - definition: 841 - preferTriggeringPipeline: true - runVersion: 'latest' - buildType: specific - - - task: DownloadPipelineArtifact@2 - displayName: 'Download Pipeline Artifact' - inputs: - artifactName: 'onnxruntime${{ parameters.python_wheel_suffix }}' - targetPath: '$(Build.BinariesDirectory)/whl' - # The public ADO project - ${{ if eq(variables['System.CollectionId'], 'f3ad12f2-e480-4533-baf2-635c95467d29') }}: - buildType: current - # The private ADO project - ${{ if eq(variables['System.CollectionId'], 'bc038106-a83b-4dab-9dd3-5a41bc58f34c') }}: - project: '530acbc4-21bc-487d-8cd8-348ff451d2ff' - definition: 841 - preferTriggeringPipeline: true - runVersion: 'latest' - buildType: specific - - - - task: Bash@3 - displayName: 'Bash Script' - inputs: - targetType: filePath - filePath: tools/ci_build/github/linux/run_python_tests.sh - arguments: -d ${{ parameters.device }} - - - task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3 - displayName: 'Clean Agent Directories' - condition: always() diff --git a/tools/ci_build/github/azure-pipelines/templates/py-packaging-selectable-stage.yml b/tools/ci_build/github/azure-pipelines/templates/py-packaging-selectable-stage.yml index 1522d1041f480..6b5fba7785fe0 100644 --- a/tools/ci_build/github/azure-pipelines/templates/py-packaging-selectable-stage.yml +++ b/tools/ci_build/github/azure-pipelines/templates/py-packaging-selectable-stage.yml @@ -48,7 +48,7 @@ stages: timeoutInMinutes: 90 workspace: clean: all - pool: aiinfra-Linux-CPU + pool: onnxruntime-Ubuntu2004-AMD-CPU strategy: matrix: ${{ each PythonVersion in parameters.python_version }}: @@ -179,7 +179,7 @@ stages: --enable_lto --build_dir $(Build.BinariesDirectory) --skip_submodule_sync - --cmake_generator "Visual Studio 16 2019" + --cmake_generator "Visual Studio 17 2022" --enable_pybind --enable_onnx_tests ${{ parameters.cpu_build_py_parameters }} @@ -267,8 +267,8 @@ stages: condition: and (succeeded(), eq(variables['PythonVersion'], '3.8')) inputs: msBuildArchitecture: amd64 - setupCommandlines: 'python $(Build.SourcesDirectory)\tools\ci_build\build.py --config Debug --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --cmake_generator "Visual Studio 16 2019" --enable_pybind --enable_onnx_tests --parallel --update --cmake_extra_defines onnxruntime_ENABLE_STATIC_ANALYSIS=ON' - msBuildCommandline: '"C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\amd64\msbuild.exe" "$(Build.BinariesDirectory)\Debug\onnxruntime.sln" /p:platform="x64" /p:configuration=Debug /p:VisualStudioVersion="16.0" /m /p:PreferredToolArchitecture=x64' + setupCommandlines: 'python $(Build.SourcesDirectory)\tools\ci_build\build.py --config Debug --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --cmake_generator "Visual Studio 17 2022" --enable_pybind --enable_onnx_tests --parallel --update --cmake_extra_defines onnxruntime_ENABLE_STATIC_ANALYSIS=ON' + msBuildCommandline: '"C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\amd64\msbuild.exe" "$(Build.BinariesDirectory)\Debug\onnxruntime.sln" /p:platform="x64" /p:configuration=Debug /p:VisualStudioVersion="17.0" /m /p:PreferredToolArchitecture=x64' excludedPaths: '$(Build.BinariesDirectory)#$(Build.SourcesDirectory)\cmake#C:\program files (x86)' - task: TSAUpload@2 @@ -331,7 +331,7 @@ stages: --skip_submodule_sync \ --parallel \ --build_wheel \ - --enable_onnx_tests --use_tensorrt --use_tensorrt_builtin_parser --cuda_version=11.8 --tensorrt_home=/usr --cuda_home=/usr/local/cuda-11.8 --cudnn_home=/usr/local/cuda-11.8 \ + --enable_onnx_tests --use_tensorrt --cuda_version=11.8 --tensorrt_home=/usr --cuda_home=/usr/local/cuda-11.8 --cudnn_home=/usr/local/cuda-11.8 \ ${{ parameters.gpu_build_py_parameters }} \ --cmake_extra_defines CMAKE_CUDA_HOST_COMPILER=/opt/rh/devtoolset-11/root/usr/bin/cc 'CMAKE_CUDA_ARCHITECTURES=37;50;52;60;61;70;75;80' workingDirectory: $(Build.SourcesDirectory) @@ -361,7 +361,7 @@ stages: --skip_submodule_sync \ --parallel \ --build_wheel \ - --enable_onnx_tests --use_tensorrt --use_tensorrt_builtin_parser --cuda_version=11.4 --tensorrt_home=/usr --cuda_home=/usr/local/cuda-11.4 --cudnn_home=/usr/local/cuda-11.4 \ + --enable_onnx_tests --use_tensorrt --cuda_version=11.8 --tensorrt_home=/usr --cuda_home=/usr/local/cuda-11.8 --cudnn_home=/usr/local/cuda-11.8 \ ${{ parameters.gpu_build_py_parameters }} --ctest_path '' \ --cmake_extra_defines CMAKE_CUDA_HOST_COMPILER=/opt/rh/devtoolset-11/root/usr/bin/cc 'CMAKE_CUDA_ARCHITECTURES=37;50;52;60;61;70;75;80' @@ -387,14 +387,15 @@ stages: - job: Windows_py_GPU_Wheels workspace: clean: all - pool: 'onnxruntime-gpu-winbuild-t4' + pool: 'onnxruntime-Win2022-GPU-T4' timeoutInMinutes: 300 variables: - CUDA_VERSION: '11.6' + CUDA_VERSION: '11.8' buildArch: x64 - EpBuildFlags: --use_tensorrt --use_tensorrt_builtin_parser --tensorrt_home="C:\local\TensorRT-8.6.0.12.Windows10.x86_64.cuda-11.8" --cuda_version=$(CUDA_VERSION) --cuda_home="C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v$(CUDA_VERSION)" --cmake_extra_defines "CMAKE_CUDA_ARCHITECTURES=37;50;52;60;61;70;75;80" + EpBuildFlags: --use_tensorrt --tensorrt_home="C:\local\TensorRT-8.6.1.6.Windows10.x86_64.cuda-11.8" --cuda_version=$(CUDA_VERSION) --cuda_home="C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v$(CUDA_VERSION)" --cmake_extra_defines "CMAKE_CUDA_ARCHITECTURES=37;50;52;60;61;70;75;80" EnvSetupScript: setup_env_gpu.bat EP_NAME: gpu + VSGenerator: 'Visual Studio 17 2022' strategy: matrix: ${{ each PythonVersion in parameters.python_version }}: @@ -444,7 +445,7 @@ stages: --config RelWithDebInfo --build_dir $(Build.BinariesDirectory) --skip_submodule_sync - --cmake_generator "Visual Studio 16 2019" + --cmake_generator "$(VSGenerator)" --enable_pybind --enable_onnx_tests ${{ parameters.gpu_build_py_parameters }} @@ -531,8 +532,11 @@ stages: condition: and (succeeded(), eq(variables['PythonVersion'], '3.8')) inputs: msBuildArchitecture: amd64 - setupCommandlines: 'python $(Build.SourcesDirectory)\tools\ci_build\build.py --config RelWithDebInfo --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --cmake_generator "Visual Studio 16 2019" --enable_pybind --enable_onnx_tests ${{ parameters.gpu_build_py_parameters }} --parallel $(EpBuildFlags) --update --cmake_extra_defines onnxruntime_ENABLE_STATIC_ANALYSIS=ON' - msBuildCommandline: '"C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\amd64\msbuild.exe" "$(Build.BinariesDirectory)\RelWithDebInfo\onnxruntime.sln" /p:platform=x64 /p:configuration="RelWithDebInfo" /p:VisualStudioVersion="16.0" /m /p:PreferredToolArchitecture=x64' + setupCommandlines: 'python $(Build.SourcesDirectory)\tools\ci_build\build.py --config RelWithDebInfo --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --cmake_generator "$(VSGenerator)" --enable_pybind --enable_onnx_tests ${{ parameters.gpu_build_py_parameters }} --parallel $(EpBuildFlags) --update --cmake_extra_defines onnxruntime_ENABLE_STATIC_ANALYSIS=ON' + ${{if eq(variables.VSGenerator, 'Visual Studio 16 2019')}}: + msBuildCommandline: '"C:\Program Files\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\amd64\msbuild.exe" "$(Build.BinariesDirectory)\RelWithDebInfo\onnxruntime.sln" /p:platform=x64 /p:configuration="RelWithDebInfo" /p:VisualStudioVersion="16.0" /m /p:PreferredToolArchitecture=x64' + ${{else}}: + msBuildCommandline: '"C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\amd64\msbuild.exe" "$(Build.BinariesDirectory)\RelWithDebInfo\onnxruntime.sln" /p:platform=x64 /p:configuration="RelWithDebInfo" /p:VisualStudioVersion="17.0" /m /p:PreferredToolArchitecture=x64' excludedPaths: '$(Build.BinariesDirectory)#$(Build.SourcesDirectory)\cmake#C:\program files (x86)' - task: TSAUpload@2 diff --git a/tools/ci_build/github/azure-pipelines/templates/py-packaging-stage.yml b/tools/ci_build/github/azure-pipelines/templates/py-packaging-stage.yml index a0c2a8f7b65d5..1305f5ae21725 100644 --- a/tools/ci_build/github/azure-pipelines/templates/py-packaging-stage.yml +++ b/tools/ci_build/github/azure-pipelines/templates/py-packaging-stage.yml @@ -10,11 +10,6 @@ parameters: type: boolean default: true -- name: enable_ubuntu_cpu - displayName: 'Whether Ubuntu CPU (manylinux_2_27) package is built.' - type: boolean - default: true - - name: enable_linux_gpu displayName: 'Whether Linux GPU package is built.' type: boolean @@ -45,6 +40,17 @@ parameters: type: boolean default: true +# TODO: Now the Windows jobs use a different cmake build type. Consider to merge it. +- name: cmake_build_type + type: string + displayName: 'Linux packages cmake build type. Linux Only.' + default: 'Release' + values: + - Debug + - Release + - RelWithDebInfo + - MinSizeRel + stages: - stage: Python_Packaging dependsOn: [] @@ -52,7 +58,7 @@ stages: jobs: - ${{ if eq(parameters.enable_windows_cpu, true) }}: - job: Windows_py_Wheels - pool: 'Win-CPU-2021' + pool: 'onnxruntime-Win-CPU-2022' strategy: matrix: Python38_x64: @@ -113,10 +119,11 @@ stages: addToPath: true architecture: $(buildArch) - - task: PythonScript@0 - displayName: 'Run a Python script' + - task: onebranch.pipeline.tsaoptions@1 + displayName: 'OneBranch TSAOptions' inputs: - scriptPath: 'tools\ci_build\update_tsaoptions.py' + tsaConfigFilePath: '$(Build.SourcesDirectory)\.config\tsaoptions.json' + appendSourceBranchName: false - template: set-nightly-build-option-variable-step.yml @@ -163,7 +170,7 @@ stages: --enable_lto --build_dir $(Build.BinariesDirectory) --skip_submodule_sync - --cmake_generator "Visual Studio 16 2019" + --cmake_generator "Visual Studio 17 2022" --enable_pybind --enable_onnx_tests ${{ parameters.build_py_parameters }} @@ -239,18 +246,6 @@ stages: workingDirectory: '$(Build.BinariesDirectory)\$(BuildConfig)\$(BuildConfig)' displayName: 'Run Python Tests' - #Skip it for 32 bits x86 build. Currently the scan tool has a bug: it doesn't allow me use 64 bits link.exe - #in 32 bits Win32 build. I tried all the settings but they all don't work. - - task: SDLNativeRules@3 - displayName: 'Run the PREfast SDL Native Rules for MSBuild' - condition: and (succeeded(), and(eq(variables['buildArch'], 'x64'), eq(variables['PythonVersion'], '3.8'))) - inputs: - msBuildArchitecture: amd64 - setupCommandlines: 'python $(Build.SourcesDirectory)\tools\ci_build\build.py --config Debug --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --cmake_generator "Visual Studio 16 2019" --enable_pybind --enable_onnx_tests --parallel $(TelemetryOption) --update --cmake_extra_defines onnxruntime_ENABLE_STATIC_ANALYSIS=ON' - msBuildCommandline: '"C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\amd64\msbuild.exe" "$(Build.BinariesDirectory)\Debug\onnxruntime.sln" /p:platform="$(MsbuildPlatform)" /p:configuration=Debug /p:VisualStudioVersion="16.0" /m /p:PreferredToolArchitecture=x64' - excludedPaths: '$(Build.BinariesDirectory)#$(Build.SourcesDirectory)\cmake#C:\program files (x86)' - - - task: TSAUpload@2 displayName: 'TSA upload' condition: and(and (succeeded(), and(eq(variables['buildArch'], 'x64'), eq(variables['PythonVersion'], '3.8'))), eq(variables['Build.SourceBranch'], 'refs/heads/main')) @@ -270,39 +265,39 @@ stages: - ${{ if eq(parameters.enable_windows_gpu, true) }}: - template: py-win-gpu.yml parameters: - MACHINE_POOL: 'onnxruntime-gpu-winbuild-t4' + MACHINE_POOL: 'onnxruntime-Win2022-GPU-T4' PYTHON_VERSION: '3.8' - EP_BUILD_FLAGS: --use_tensorrt --use_tensorrt_builtin_parser --tensorrt_home="C:\local\TensorRT-8.6.0.12.Windows10.x86_64.cuda-11.8" --cuda_version=11.6 --cuda_home="C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.6" --cmake_extra_defines "CMAKE_CUDA_ARCHITECTURES=52;60;61;70;75;80" + EP_BUILD_FLAGS: --use_tensorrt --tensorrt_home="C:\local\TensorRT-8.6.1.6.Windows10.x86_64.cuda-11.8" --cuda_home="$(Agent.TempDirectory)\v11.8" --cmake_extra_defines "CMAKE_CUDA_ARCHITECTURES=52;60;61;70;75;80" ENV_SETUP_SCRIPT: setup_env_gpu.bat EP_NAME: gpu - template: py-win-gpu.yml parameters: - MACHINE_POOL: 'onnxruntime-gpu-winbuild-t4' + MACHINE_POOL: 'onnxruntime-Win2022-GPU-T4' PYTHON_VERSION: '3.9' - EP_BUILD_FLAGS: --use_tensorrt --use_tensorrt_builtin_parser --tensorrt_home="C:\local\TensorRT-8.6.0.12.Windows10.x86_64.cuda-11.8" --cuda_version=11.6 --cuda_home="C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.6" --cmake_extra_defines "CMAKE_CUDA_ARCHITECTURES=52;60;61;70;75;80" + EP_BUILD_FLAGS: --use_tensorrt --tensorrt_home="C:\local\TensorRT-8.6.1.6.Windows10.x86_64.cuda-11.8" --cuda_home="$(Agent.TempDirectory)\v11.8" --cmake_extra_defines "CMAKE_CUDA_ARCHITECTURES=52;60;61;70;75;80" ENV_SETUP_SCRIPT: setup_env_gpu.bat EP_NAME: gpu - template: py-win-gpu.yml parameters: - MACHINE_POOL: 'onnxruntime-gpu-winbuild-t4' + MACHINE_POOL: 'onnxruntime-Win2022-GPU-T4' PYTHON_VERSION: '3.10' - EP_BUILD_FLAGS: --use_tensorrt --use_tensorrt_builtin_parser --tensorrt_home="C:\local\TensorRT-8.6.0.12.Windows10.x86_64.cuda-11.8" --cuda_version=11.6 --cuda_home="C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.6" --cmake_extra_defines "CMAKE_CUDA_ARCHITECTURES=52;60;61;70;75;80" + EP_BUILD_FLAGS: --use_tensorrt --tensorrt_home="C:\local\TensorRT-8.6.1.6.Windows10.x86_64.cuda-11.8" --cuda_home="$(Agent.TempDirectory)\v11.8" --cmake_extra_defines "CMAKE_CUDA_ARCHITECTURES=52;60;61;70;75;80" ENV_SETUP_SCRIPT: setup_env_gpu.bat EP_NAME: gpu - template: py-win-gpu.yml parameters: - MACHINE_POOL: 'onnxruntime-gpu-winbuild-t4' + MACHINE_POOL: 'onnxruntime-Win2022-GPU-T4' PYTHON_VERSION: '3.11' - EP_BUILD_FLAGS: --use_tensorrt --tensorrt_home="C:\local\TensorRT-8.5.1.7.Windows10.x86_64.cuda-11.8.cudnn8.6" --cuda_version=11.6 --cuda_home="C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.6" --cmake_extra_defines "CMAKE_CUDA_ARCHITECTURES=52;60;61;70;75;80" + EP_BUILD_FLAGS: --use_tensorrt --tensorrt_home="C:\local\TensorRT-8.6.1.6.Windows10.x86_64.cuda-11.8" --cuda_home="$(Agent.TempDirectory)\v11.8" --cmake_extra_defines "CMAKE_CUDA_ARCHITECTURES=52;60;61;70;75;80" ENV_SETUP_SCRIPT: setup_env_gpu.bat EP_NAME: gpu - template: py-win-gpu.yml parameters: - MACHINE_POOL: 'aiinfra-dml-winbuild' + MACHINE_POOL: 'onnxruntime-Win2022-GPU-dml-A10' PYTHON_VERSION: '3.8' EP_BUILD_FLAGS: --use_dml --cmake_extra_defines CMAKE_SYSTEM_VERSION=10.0.18362.0 --enable_wcos ENV_SETUP_SCRIPT: setup_env.bat @@ -310,7 +305,7 @@ stages: - template: py-win-gpu.yml parameters: - MACHINE_POOL: 'aiinfra-dml-winbuild' + MACHINE_POOL: 'onnxruntime-Win2022-GPU-dml-A10' PYTHON_VERSION: '3.9' EP_BUILD_FLAGS: --use_dml --cmake_extra_defines CMAKE_SYSTEM_VERSION=10.0.18362.0 --enable_wcos ENV_SETUP_SCRIPT: setup_env.bat @@ -318,7 +313,7 @@ stages: - template: py-win-gpu.yml parameters: - MACHINE_POOL: 'aiinfra-dml-winbuild' + MACHINE_POOL: 'onnxruntime-Win2022-GPU-dml-A10' PYTHON_VERSION: '3.10' EP_BUILD_FLAGS: --use_dml --cmake_extra_defines CMAKE_SYSTEM_VERSION=10.0.18362.0 --enable_wcos ENV_SETUP_SCRIPT: setup_env.bat @@ -326,7 +321,7 @@ stages: - template: py-win-gpu.yml parameters: - MACHINE_POOL: 'aiinfra-dml-winbuild' + MACHINE_POOL: 'onnxruntime-Win2022-GPU-dml-A10' PYTHON_VERSION: '3.11' EP_BUILD_FLAGS: --use_dml --cmake_extra_defines CMAKE_SYSTEM_VERSION=10.0.18362.0 --enable_wcos ENV_SETUP_SCRIPT: setup_env.bat @@ -334,11 +329,11 @@ stages: - ${{ if eq(parameters.enable_mac_cpu, true) }}: - job: MacOS_py_Wheels - timeoutInMinutes: 90 + timeoutInMinutes: 120 workspace: clean: all pool: - vmImage: 'macOS-12' + vmImage: 'macOS-13' variables: MACOSX_DEPLOYMENT_TARGET: '10.15' strategy: @@ -361,6 +356,8 @@ stages: inputs: versionSpec: $(PythonVersion) + - template: use-xcode-version.yml + - script: | set -e -x pushd . @@ -374,7 +371,6 @@ stages: export CMAKE_ARGS="-DONNX_GEN_PB_TYPE_STUBS=OFF -DONNX_WERROR=OFF" export _PYTHON_HOST_PLATFORM=macosx-${{variables.MACOSX_DEPLOYMENT_TARGET}}-x86_64 python3 -m pip install -r '$(Build.SourcesDirectory)/tools/ci_build/github/linux/docker/scripts/requirements.txt' - sudo xcode-select --switch /Applications/Xcode_13.1.app/Contents/Developer python3 $(Build.SourcesDirectory)/tools/ci_build/build.py --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --parallel --config Release --skip_onnx_tests --build_wheel ${{ parameters.build_py_parameters }} displayName: 'Command Line Script' @@ -400,7 +396,7 @@ stages: workspace: clean: all pool: - vmImage: 'macOS-12' + vmImage: 'macOS-13' variables: MACOSX_DEPLOYMENT_TARGET: '11.0' strategy: @@ -431,6 +427,8 @@ stages: system_profiler SPSoftwareDataType SPHardwareDataType displayName: 'Mac machine info' + - template: use-xcode-version.yml + # Don't remove _PYTHON_HOST_PLATFORM, it's used to generate correct package name # Setting _PYTHON_HOST_PLATFORM overwrites the value return by get_platform() # Ref: https://wiki.debian.org/Python/MultiArch @@ -447,7 +445,6 @@ stages: export CMAKE_ARGS="-DONNX_GEN_PB_TYPE_STUBS=OFF -DONNX_WERROR=OFF" export _PYTHON_HOST_PLATFORM=macosx-${{variables.MACOSX_DEPLOYMENT_TARGET}}-arm64 python3 -m pip install -r '$(Build.SourcesDirectory)/tools/ci_build/github/linux/docker/scripts/requirements.txt' - sudo xcode-select --switch /Applications/Xcode_13.1.app/Contents/Developer python3 $(Build.SourcesDirectory)/tools/ci_build/build.py --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --parallel --config Release --skip_tests --cmake_extra_defines CMAKE_OSX_ARCHITECTURES=arm64 --build_wheel ${{ parameters.build_py_parameters }} displayName: 'Command Line Script' @@ -488,46 +485,30 @@ stages: parameters: arch: 'aarch64' machine_pool: 'aiinfra-linux-ARM64-CPU-2019' - base_image: 'arm64v8/centos:7' - devtoolset_rootpath: /opt/rh/devtoolset-10/root - ld_library_path_arg: /opt/rh/devtoolset-10/root/usr/lib64:/opt/rh/devtoolset-10/root/usr/lib:/opt/rh/devtoolset-10/root/usr/lib64/dyninst:/opt/rh/devtoolset-10/root/usr/lib/dyninst:/usr/local/lib64 - prepend_path: '/opt/rh/devtoolset-10/root/usr/bin:' - ${{ if contains(parameters.build_py_parameters, '--use_azure') }}: - device: '-d AZURE' + base_image: 'arm64v8/almalinux:8' + devtoolset_rootpath: /opt/rh/gcc-toolset-12/root + 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 + prepend_path: '/opt/rh/gcc-toolset-12/root/usr/bin:' + extra_build_arg: ${{ parameters.build_py_parameters }} + cmake_build_type: ${{ parameters.cmake_build_type }} - ${{ if eq(parameters.enable_linux_cpu, true) }}: - template: py-linux.yml parameters: arch: 'x86_64' - machine_pool: 'Azure-Pipelines-EO-Ubuntu-2004-aiinfra' - base_image: 'centos:7' - devtoolset_rootpath: /opt/rh/devtoolset-11/root - ld_library_path_arg: /opt/rh/devtoolset-11/root/usr/lib64:/opt/rh/devtoolset-11/root/usr/lib:/opt/rh/devtoolset-11/root/usr/lib64/dyninst:/opt/rh/devtoolset-11/root/usr/lib/dyninst:/usr/local/lib64 - prepend_path: '/opt/rh/devtoolset-11/root/usr/bin:' - ${{ if contains(parameters.build_py_parameters, '--use_azure') }}: - device: '-d AZURE' - - - ${{ if and(eq(parameters.enable_ubuntu_cpu, true), contains(parameters.build_py_parameters, '--use_azure'))}}: - - template: py-linux-ubuntu.yml - parameters: - arch: 'aarch64' - machine_pool: 'aiinfra-linux-ARM64-CPU-2019' - base_image: 'arm64v8/ubuntu:18.04' - device: '-d AZURE' + machine_pool: 'onnxruntime-Ubuntu2004-AMD-CPU' + base_image: 'registry.access.redhat.com/ubi8/ubi' + devtoolset_rootpath: /opt/rh/gcc-toolset-12/root + 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 + prepend_path: '/opt/rh/gcc-toolset-12/root/usr/bin:' + extra_build_arg: ${{ parameters.build_py_parameters }} + cmake_build_type: ${{ parameters.cmake_build_type }} - - ${{ if and(eq(parameters.enable_ubuntu_cpu, true), contains(parameters.build_py_parameters, '--use_azure'))}}: - - template: py-linux-ubuntu.yml - parameters: - arch: 'x86_64' - machine_pool: 'Linux-CPU' - base_image: 'ubuntu:18.04' - ${{ if contains(parameters.build_py_parameters, '--use_azure') }}: - device: '-d AZURE' - ${{ if eq(parameters.enable_linux_gpu, true) }}: - template: py-linux-gpu.yml parameters: arch: 'x86_64' - machine_pool: 'aiinfra-Linux-CPU' - ${{ if contains(parameters.build_py_parameters, '--use_azure') }}: - device: '-d AZURE' + machine_pool: 'onnxruntime-Ubuntu2004-AMD-CPU' + extra_build_arg: ${{ parameters.build_py_parameters }} + cmake_build_type: ${{ parameters.cmake_build_type }} diff --git a/tools/ci_build/github/azure-pipelines/templates/py-packaging-training-cuda-stage.yml b/tools/ci_build/github/azure-pipelines/templates/py-packaging-training-cuda-stage.yml index ee25ea0a08743..7fdd7e54e752d 100644 --- a/tools/ci_build/github/azure-pipelines/templates/py-packaging-training-cuda-stage.yml +++ b/tools/ci_build/github/azure-pipelines/templates/py-packaging-training-cuda-stage.yml @@ -25,11 +25,6 @@ parameters: cmake_cuda_architectures type: string -- name: gcc_version - displayName: > - gcc_version. - type: number - - name: docker_file displayName: > docker_file. @@ -84,28 +79,24 @@ stages: TorchVersion: ${{ parameters.torch_version }} OpsetVersion: ${{ parameters.opset_version }} CudaVersion: ${{ parameters.cuda_version }} - GccVersion: ${{ parameters.gcc_version }} UploadWheel: ${{ parameters.upload_wheel }} Python39: PythonVersion: '3.9' TorchVersion: ${{ parameters.torch_version }} OpsetVersion: ${{ parameters.opset_version }} CudaVersion: ${{ parameters.cuda_version }} - GccVersion: ${{ parameters.gcc_version }} UploadWheel: ${{ parameters.upload_wheel }} Python310: PythonVersion: '3.10' TorchVersion: ${{ parameters.torch_version }} OpsetVersion: ${{ parameters.opset_version }} CudaVersion: ${{ parameters.cuda_version }} - GccVersion: ${{ parameters.gcc_version }} UploadWheel: ${{ parameters.upload_wheel }} Python311: PythonVersion: '3.11' TorchVersion: ${{ parameters.torch_version }} OpsetVersion: ${{ parameters.opset_version }} CudaVersion: ${{ parameters.cuda_version }} - GccVersion: ${{ parameters.gcc_version }} UploadWheel: ${{ parameters.upload_wheel }} steps: @@ -133,10 +124,10 @@ stages: --build-arg PYTHON_VERSION=$(PythonVersion) --build-arg INSTALL_DEPS_EXTRA_ARGS=-tu --build-arg BUILD_UID=$(id -u) - --network=host --build-arg POLICY=manylinux2014 --build-arg PLATFORM=x86_64 - --build-arg DEVTOOLSET_ROOTPATH=/opt/rh/devtoolset-$(GccVersion)/root - --build-arg PREPEND_PATH=/opt/rh/devtoolset-$(GccVersion)/root/usr/bin: - --build-arg LD_LIBRARY_PATH_ARG=/opt/rh/devtoolset-$(GccVersion)/root/usr/lib64:/opt/rh/devtoolset-$(GccVersion)/root/usr/lib:/opt/rh/devtoolset-$(GccVersion)/root/usr/lib64/dyninst:/opt/rh/devtoolset-$(GccVersion)/root/usr/lib/dyninst:/usr/local/lib64 + --network=host --build-arg POLICY=manylinux_2_28 --build-arg PLATFORM=x86_64 + --build-arg DEVTOOLSET_ROOTPATH=/usr + --build-arg PREPEND_PATH=/usr/local/cuda/bin: + --build-arg LD_LIBRARY_PATH_ARG=/usr/local/lib64 Repository: onnxruntimetraininggpubuild - bash: tools/ci_build/github/linux/docker/scripts/training/azure_scale_set_vm_mount_test_data.sh -p $(orttrainingtestdatascus-storage-key) -s "//orttrainingtestdatascus.file.core.windows.net/mnist" -d "/mnist" @@ -155,8 +146,9 @@ stages: displayName: 'build onnxruntime' inputs: script: | + set -e -x mkdir -p $HOME/.onnx - docker run --rm -e CC=/opt/rh/devtoolset-$(GccVersion)/root/usr/bin/cc -e CXX=/opt/rh/devtoolset-$(GccVersion)/root/usr/bin/c++ -e CFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all" -e CXXFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all" \ + docker run --rm -e CFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all" -e CXXFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all" \ --volume /data/onnx:/data/onnx:ro \ --volume $(Build.SourcesDirectory):/onnxruntime_src \ --volume $(Build.BinariesDirectory):/build \ @@ -176,7 +168,7 @@ stages: --build_wheel \ --enable_onnx_tests \ ${{ parameters.build_py_parameters }} \ - --cmake_extra_defines CMAKE_CUDA_HOST_COMPILER=/opt/rh/devtoolset-$(GccVersion)/root/usr/bin/cc 'CMAKE_CUDA_ARCHITECTURES=${{ parameters.cmake_cuda_architectures }}' onnxruntime_BUILD_UNIT_TESTS=OFF \ + --cmake_extra_defines 'CMAKE_CUDA_ARCHITECTURES=${{ parameters.cmake_cuda_architectures }}' onnxruntime_BUILD_UNIT_TESTS=OFF \ --use_cuda --cuda_version=$(CudaVersion) --cuda_home=/usr/local/cuda-$(CudaVersion) --cudnn_home=/usr/local/cuda-$(CudaVersion) ; workingDirectory: $(Build.SourcesDirectory) diff --git a/tools/ci_build/github/azure-pipelines/templates/py-win-gpu.yml b/tools/ci_build/github/azure-pipelines/templates/py-win-gpu.yml index 3c0ec8041b3b4..919749cac15b6 100644 --- a/tools/ci_build/github/azure-pipelines/templates/py-win-gpu.yml +++ b/tools/ci_build/github/azure-pipelines/templates/py-win-gpu.yml @@ -8,25 +8,27 @@ parameters: - name: PYTHON_VERSION type: string - + - name: EP_BUILD_FLAGS type: string - + - name: ENV_SETUP_SCRIPT type: string - + - name: BUILD_PY_PARAMETERS displayName: > Extra parameters to pass to build.py. Don't put newlines in here. type: string default: '' - + jobs: - job: Win_py_${{ parameters.EP_NAME }}_Wheels_${{ replace(parameters.PYTHON_VERSION,'.','_') }} timeoutInMinutes: 240 workspace: clean: all pool: ${{ parameters.MACHINE_POOL }} + variables: + VSGenerator: 'Visual Studio 17 2022' steps: - checkout: self clean: true @@ -40,12 +42,11 @@ jobs: addToPath: true architecture: 'x64' - - task: BatchScript@1 - displayName: 'setup env' + - task: onebranch.pipeline.tsaoptions@1 + displayName: 'OneBranch TSAOptions' inputs: - filename: '$(Build.SourcesDirectory)\tools\ci_build\github\windows\${{ parameters.ENV_SETUP_SCRIPT }}' - modifyEnvironment: true - workingFolder: '$(Build.BinariesDirectory)' + tsaConfigFilePath: '$(Build.SourcesDirectory)\.config\tsaoptions.json' + appendSourceBranchName: false - task: PythonScript@0 inputs: @@ -60,6 +61,11 @@ jobs: - template: download-deps.yml + - template: jobs/set-winenv.yml + parameters: + EnvSetupScript: ${{ parameters.ENV_SETUP_SCRIPT }} + DownloadCUDA: true + - task: PythonScript@0 displayName: 'Update deps.txt' inputs: @@ -85,9 +91,9 @@ jobs: --config RelWithDebInfo --build_dir $(Build.BinariesDirectory) --skip_submodule_sync - --cmake_generator "Visual Studio 16 2019" + --cmake_generator "$(VSGenerator)" --enable_pybind - --enable_onnx_tests + --enable_onnx_tests --parallel --update $(TelemetryOption) ${{ parameters.BUILD_PY_PARAMETERS }} ${{ parameters.EP_BUILD_FLAGS }} workingDirectory: '$(Build.BinariesDirectory)' @@ -147,7 +153,6 @@ jobs: inputs: AnalyzeTargetGlob: '+:file|$(Build.ArtifactStagingDirectory)\**\*.dll;-:file|$(Build.ArtifactStagingDirectory)\**\DirectML.dll' - - powershell: | python -m pip uninstall -y ort-nightly-gpu ort-nightly onnxruntime onnxruntime-gpu -qq Get-ChildItem -Path $(Build.ArtifactStagingDirectory)/*.whl | foreach {pip --disable-pip-version-check install --upgrade $_.fullname tabulate} @@ -156,34 +161,13 @@ jobs: workingDirectory: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo' displayName: 'Run Python Tests' - - ${{ if eq(parameters.PYTHON_VERSION, '3.8') }}: - - task: DeleteFiles@1 - displayName: 'Delete files from $(Build.BinariesDirectory)\RelWithDebInfo' - condition: and (succeeded(), eq(variables['$'], '3.8')) - inputs: - SourceFolder: '$(Build.BinariesDirectory)\RelWithDebInfo' - Contents: | - **/*.obj - **/*.pdb - **/*.dll - - #Manually set msBuildCommandline so that we can also set CAExcludePath - - task: SDLNativeRules@3 - displayName: 'Run the PREfast SDL Native Rules for MSBuild' - inputs: - msBuildArchitecture: amd64 - setupCommandlines: 'python $(Build.SourcesDirectory)\tools\ci_build\build.py --config RelWithDebInfo --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --cmake_generator "Visual Studio 16 2019" --enable_pybind --enable_onnx_tests --parallel $(TelemetryOption) ${{ parameters.BUILD_PY_PARAMETERS }} ${{ parameters.EP_BUILD_FLAGS }} --update --cmake_extra_defines onnxruntime_ENABLE_STATIC_ANALYSIS=ON' - msBuildCommandline: '"C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\amd64\msbuild.exe" "$(Build.BinariesDirectory)\RelWithDebInfo\onnxruntime.sln" /p:platform=x64 /p:configuration="RelWithDebInfo" /p:VisualStudioVersion="16.0" /m /p:PreferredToolArchitecture=x64' - excludedPaths: '$(Build.BinariesDirectory)#$(Build.SourcesDirectory)\cmake#C:\program files (x86)' - - - 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 + - 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' \ No newline at end of file + condition: 'succeeded' 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 972231ce99f9e..8c54e71448992 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 @@ -50,13 +50,15 @@ stages: jobs: - job: ReactNative_CI pool: + # We need macOS-12 to run the Android emulator for now. + # https://github.com/actions/runner-images/issues/7671 vmImage: 'macOS-12' variables: runCodesignValidationInjection: false TODAY: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)] PROTO_CACHE_DIR: '$(Pipeline.Workspace)/ccache_proto' ORT_CACHE_DIR: '$(Pipeline.Workspace)/ccache_ort' - timeoutInMinutes: 150 + timeoutInMinutes: 180 steps: - task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3 displayName: Clean Agent Directories @@ -68,14 +70,14 @@ stages: versionSpec: "3.9" addToPath: true rchitecture: "x64" - + - task: JavaToolInstaller@0 displayName: Use jdk 11 inputs: versionSpec: '11' jdkArchitectureOption: 'x64' jdkSourceOption: 'PreInstalled' - + - task: NodeTool@0 inputs: versionSpec: '16.x' @@ -130,7 +132,7 @@ stages: --variant Full \ --build-settings-file $(Build.SourcesDirectory)/tools/ci_build/github/js/react_native_e2e_full_ios_framework_build_settings.json \ -b="--path_to_protoc_exe" -b "$(Build.BinariesDirectory)/installed/bin/protoc" - + # Mobile build: # python $(Build.SourcesDirectory)/tools/ci_build/github/apple/build_and_assemble_ios_pods.py \ # --build_dir $(Build.BinariesDirectory)/ios_framework_mobile \ @@ -167,7 +169,7 @@ stages: contents: onnxruntime-android-*.aar targetFolder: $(Build.SourcesDirectory)/js/react_native/android/libs displayName: Copy Android package to React Native directory - + - script: | npm ci workingDirectory: '$(Build.SourcesDirectory)/js' @@ -187,7 +189,7 @@ stages: python3 tools/python/run_android_emulator.py \ --android-sdk-root $(ANDROID_SDK_ROOT) \ --create-avd --system-image "system-images;android-30;default;x86_64" \ - --start --emulator-extra-args="-partition-size 4096" \ + --start --emulator-extra-args="-partition-size 4096 -verbose" \ --emulator-pid-file $(Build.BinariesDirectory)/emulator.pid displayName: Start Android Emulator @@ -266,6 +268,9 @@ stages: displayName: Bootstrap Android and iOS e2e tests - script: | + # Mobile build: + # ORT_MOBILE_C_LOCAL_POD_PATH=$(Build.BinariesDirectory)/staging/onnxruntime-mobile-c \ + ORT_C_LOCAL_POD_PATH=$(Build.BinariesDirectory)/staging/onnxruntime-c \ pod install workingDirectory: '$(Build.SourcesDirectory)/js/react_native/e2e/ios' displayName: Pod install for onnxruntime react native ios e2e tests @@ -295,13 +300,13 @@ stages: detox build --configuration android.emu.release workingDirectory: '$(Build.SourcesDirectory)/js/react_native/e2e' displayName: Build React Native Detox Android e2e Tests - + - script: | JEST_JUNIT_OUTPUT_FILE=$(Build.SourcesDirectory)/js/react_native/e2e/android-test-results.xml \ - detox test --record-logs all --configuration android.emu.release + detox test --record-logs all --configuration android.emu.release workingDirectory: '$(Build.SourcesDirectory)/js/react_native/e2e' displayName: Run React Native Detox Android e2e Tests - + - task: PublishTestResults@2 inputs: testResultsFiles: '$(Build.SourcesDirectory)/js/react_native/e2e/android-test-results.xml' @@ -309,12 +314,12 @@ stages: testRunTitle: 'React Native Detox Android e2e Test Results' condition: succeededOrFailed() displayName: Publish React Native Detox Android e2e Test Results - + - script: | detox build --configuration ios.sim.release workingDirectory: '$(Build.SourcesDirectory)/js/react_native/e2e' displayName: Build React Native Detox iOS e2e Tests - + - script: | JEST_JUNIT_OUTPUT_FILE=$(Build.SourcesDirectory)/js/react_native/e2e/ios-test-results.xml \ detox test --record-logs all --configuration ios.sim.release @@ -331,8 +336,10 @@ stages: - task: PublishPipelineArtifact@1 inputs: - targetPath: '$(Build.SourcesDirectory)/js/react_native/e2e/artifacts' - displayName: Publish React Native Detox E2E test artifacts + artifact: e2e_test_logs + targetPath: '$(Build.SourcesDirectory)/js/react_native/e2e/artifacts' + condition: succeededOrFailed() + displayName: Publish React Native Detox E2E test logs - script: | python3 tools/python/run_android_emulator.py \ diff --git a/tools/ci_build/github/azure-pipelines/templates/rocm.yml b/tools/ci_build/github/azure-pipelines/templates/rocm.yml index 3213a8aa1f9fa..d43029266b4b0 100644 --- a/tools/ci_build/github/azure-pipelines/templates/rocm.yml +++ b/tools/ci_build/github/azure-pipelines/templates/rocm.yml @@ -45,16 +45,16 @@ jobs: - template: set-python-manylinux-variables-step.yml - template: get-docker-image-steps.yml parameters: - Dockerfile: tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_rocm + 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=manylinux2014 --build-arg PLATFORM=x86_64 + --network=host --build-arg POLICY=manylinux_2_28 --build-arg PLATFORM=x86_64 + --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 --build-arg ROCM_VERSION=${{ parameters.RocmVersion }} - --build-arg DEVTOOLSET_ROOTPATH=/opt/rh/devtoolset-10/root - --build-arg PREPEND_PATH=/opt/rh/devtoolset-10/root/usr/bin: - --build-arg LD_LIBRARY_PATH_ARG=/opt/rh/devtoolset-10/root/usr/lib64:/opt/rh/devtoolset-10/root/usr/lib:/opt/rh/devtoolset-10/root/usr/lib64/dyninst:/opt/rh/devtoolset-10/root/usr/lib/dyninst:/usr/local/lib64:/usr/local/lib Repository: onnxruntimetrainingrocmbuild-rocm${{ parameters.RocmVersion }} - task: CmdLine@2 @@ -66,7 +66,7 @@ jobs: --network=host \ --cap-add=SYS_PTRACE \ --security-opt seccomp=unconfined \ - -e CC=/opt/rh/devtoolset-10/root/usr/bin/cc -e CXX=/opt/rh/devtoolset-10/root/usr/bin/c++ -e CFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all" -e CXXFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all" \ + -e CC=/opt/rh/gcc-toolset-12/root/usr/bin/cc -e CXX=/opt/rh/gcc-toolset-12/root/usr/bin/c++ -e CFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all" -e CXXFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all" \ --volume $(Build.SourcesDirectory):/onnxruntime_src \ --volume $(Build.BinariesDirectory):/build \ --workdir /onnxruntime_src \ @@ -90,7 +90,7 @@ jobs: --enable_training \ --cmake_extra_defines \ CMAKE_HIP_COMPILER=/opt/rocm/llvm/bin/clang++ \ - onnxruntime_BUILD_UNIT_TESTS=OFF \ + onnxruntime_BUILD_UNIT_TESTS=OFF FETCHCONTENT_TRY_FIND_PACKAGE_MODE=NEVER \ ${{ variables['EnableProfiling'] }} workingDirectory: $(Build.SourcesDirectory) displayName: 'Build onnxruntime (in container)' @@ -101,6 +101,8 @@ jobs: # To view the UTs disabled from this CI - see https://github.com/microsoft/onnxruntime/pull/11945 for examples - script: |- + # Do not output ##vso[] commands with `set -x` or they may be parsed again and include a trailing quote. + set +x echo "Tests will run using HIP_VISIBLES_DEVICES=$HIP_VISIBLE_DEVICES" video_gid=$(getent group | awk '/video/ {split($0,a,":"); print(a[3])}') echo "Found video_gid=$video_gid; attempting to set as pipeline variable" @@ -118,41 +120,6 @@ jobs: Contents: "${{ parameters.BuildConfig }}/dist/*.whl" TargetFolder: '$(Build.ArtifactStagingDirectory)' - - task: CmdLine@2 - displayName: 'Build Python Documentation' - condition: and(succeeded(), ne('${{ parameters.PythonVersion }}', '3.9'), eq('${{ parameters.BuildConfig }}', 'Release')) # tensorflow not available on python 3.9 - inputs: - script: | - mkdir -p $HOME/.onnx - docker run --rm \ - --device=/dev/kfd \ - --device=/dev/dri \ - --group-add $(video) \ - --group-add $(render) \ - --privileged \ - --ipc=host \ - --network=host \ - --cap-add=SYS_PTRACE \ - --security-opt seccomp=unconfined \ - --volume $(Build.SourcesDirectory):/onnxruntime_src \ - --volume $(Build.BinariesDirectory):/build \ - --entrypoint /bin/bash \ - -e HIP_VISIBLE_DEVICES \ - -e NIGHTLY_BUILD \ - -e BUILD_BUILDNUMBER \ - -e PythonManylinuxDir=$(PythonManylinuxdir) \ - onnxruntimetrainingrocmbuild-rocm${{ parameters.RocmVersion }} \ - /onnxruntime_src/tools/ci_build/github/pai/wrap_rocm_python_doc_publisher.sh - workingDirectory: $(Build.SourcesDirectory) - - - task: CopyFiles@2 - displayName: 'Copy Python Documentation to: $(Build.ArtifactStagingDirectory)' - condition: and(succeeded(), ne('${{ parameters.PythonVersion }}', '3.9'), eq('${{ parameters.BuildConfig }}', 'Release')) # tensorflow not available on python 3.9 - inputs: - SourceFolder: '$(Build.BinariesDirectory)/docs/training/html' - Contents: '**' - TargetFolder: '$(Build.ArtifactStagingDirectory)/training_html_doc' - - task: PublishBuildArtifacts@1 displayName: 'Upload Rocm wheel as build artifact' inputs: diff --git a/tools/ci_build/github/azure-pipelines/templates/set-test-data-variables-step.yml b/tools/ci_build/github/azure-pipelines/templates/set-test-data-variables-step.yml deleted file mode 100644 index abec88edb183f..0000000000000 --- a/tools/ci_build/github/azure-pipelines/templates/set-test-data-variables-step.yml +++ /dev/null @@ -1,11 +0,0 @@ -# sets variables $(TestDataUrl) - -parameters: - TestDataUrl: https://onnxruntimetestdata.blob.core.windows.net/models/20191107.zip - -steps: -- task: CmdLine@1 - displayName: 'Set TestDataUrl variable' - inputs: - filename: echo - arguments: '##vso[task.setvariable variable=TestDataUrl;]${{parameters.TestDataUrl}}' \ No newline at end of file diff --git a/tools/ci_build/github/azure-pipelines/templates/set-version-number-variables-step.yml b/tools/ci_build/github/azure-pipelines/templates/set-version-number-variables-step.yml index ba2f2bfca79ec..6abab8aabfbdf 100644 --- a/tools/ci_build/github/azure-pipelines/templates/set-version-number-variables-step.yml +++ b/tools/ci_build/github/azure-pipelines/templates/set-version-number-variables-step.yml @@ -10,9 +10,9 @@ steps: inputs: script: | SETLOCAL EnableDelayedExpansion - set /p _OnnxRuntimeVersion=<${{parameters.versionFileDirectory}}\VERSION_NUMBER + set /p _OnnxRuntimeVersion=<${{parameters.versionFileDirectory}}\VERSION_NUMBER @echo ##vso[task.setvariable variable=OnnxRuntimeVersion;]%_OnnxRuntimeVersion% - + FOR /F "tokens=* USEBACKQ" %%F IN (`git rev-parse HEAD`) DO ( @echo ##vso[task.setvariable variable=OnnxRuntimeGitCommitHash;]%%F ) @@ -20,22 +20,25 @@ steps: FOR /F "tokens=* USEBACKQ" %%F IN (`git rev-parse --short HEAD`) DO ( @echo ##vso[task.setvariable variable=OnnxRuntimeGitCommitHashShort;]%%F ) - - workingDirectory: ${{parameters.workingDirectory}} - condition: eq(variables['Agent.OS'], 'Windows_NT') + + workingDirectory: ${{parameters.workingDirectory}} + condition: eq(variables['Agent.OS'], 'Windows_NT') - task: CmdLine@2 displayName: 'Set version number variables for Unix' inputs: script: | - _OnnxRuntimeVersion=$(head -1 ${{parameters.versionFileDirectory}}/VERSION_NUMBER) + # Do not output ##vso[] commands with `set -x` or they may be parsed again and include a trailing quote. + set +x + + _OnnxRuntimeVersion=$(head -1 ${{parameters.versionFileDirectory}}/VERSION_NUMBER) echo "##vso[task.setvariable variable=OnnxRuntimeVersion;]$_OnnxRuntimeVersion" - + _OnnxRuntimeGitCommitHash=$(git rev-parse HEAD) echo "##vso[task.setvariable variable=OnnxRuntimeGitCommitHash;]$_OnnxRuntimeGitCommitHash" _OnnxRuntimeGitCommitHash=$(git rev-parse --short=8 HEAD) echo "##vso[task.setvariable variable=OnnxRuntimeGitCommitHashShort;]$_OnnxRuntimeGitCommitHash" - workingDirectory: ${{parameters.workingDirectory}} + workingDirectory: ${{parameters.workingDirectory}} condition: not(eq(variables['Agent.OS'], 'Windows_NT')) 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 new file mode 100644 index 0000000000000..81f17a26b16a6 --- /dev/null +++ b/tools/ci_build/github/azure-pipelines/templates/stages/mac-ios-packaging-build-stage.yml @@ -0,0 +1,164 @@ +parameters: +- name: packageVariant + type: string + values: + - Mobile + - Full + - Training + +stages: +- stage: IosPackaging_Build_${{ parameters.packageVariant }} + dependsOn: + - IosPackaging_SetCommonVariables + + jobs: + - job: j + displayName: "Build iOS package for variant: ${{ parameters.packageVariant}}" + + pool: + vmImage: "macOS-13" + + variables: + xcodeVersion: "14.3" + ortPodVersion: $[stageDependencies.IosPackaging_SetCommonVariables.j.outputs['SetCommonVariables.ORT_POD_VERSION']] + + ${{ if eq(parameters.packageVariant, 'Mobile') }}: + buildSettingsFile: "tools/ci_build/github/apple/default_mobile_ios_framework_build_settings.json" + optionalIncludeOpsByConfigOption: "--include-ops-by-config tools/ci_build/github/android/mobile_package.required_operators.config" + cPodName: onnxruntime-mobile-c + objcPodName: onnxruntime-mobile-objc + + ${{ if eq(parameters.packageVariant, 'Full') }}: + buildSettingsFile: "tools/ci_build/github/apple/default_full_ios_framework_build_settings.json" + cPodName: onnxruntime-c + objcPodName: onnxruntime-objc + + ${{ if eq(parameters.packageVariant, 'Training') }}: + buildSettingsFile: "tools/ci_build/github/apple/default_training_ios_framework_build_settings.json" + cPodName: onnxruntime-training-c + objcPodName: onnxruntime-training-objc + + timeoutInMinutes: 120 + + steps: + - script: | + if [[ -z "$(ortPodVersion)" ]]; then + echo "ORT pod version is unspecified. Make sure that the IosPackaging_SetCommonVariables stage has run." + exit 1 + fi + displayName: 'Ensure version is set' + + - task: InstallAppleCertificate@2 + inputs: + certSecureFile: '$(ios_signing_certificate_name)' + certPwd: '$(ios_signing_certificate_password)' + keychain: 'temp' + deleteCert: true + displayName: 'Install ORT Mobile Test Signing Certificate' + + - task: InstallAppleProvisioningProfile@1 + inputs: + provProfileSecureFile: '$(ios_provision_profile_name)' + removeProfile: true + displayName: 'Install ORT Mobile Test Provisioning Profile' + + - task: UsePythonVersion@0 + inputs: + versionSpec: "3.9" + addToPath: true + architecture: "x64" + + - template: ../use-xcode-version.yml + parameters: + xcodeVersion: ${{ variables.xcodeVersion }} + + - template: ../install-appcenter.yml + + - script: | + pip install -r tools/ci_build/github/apple/ios_packaging.requirements.txt + displayName: "Install Python requirements" + + - script: | + $(Build.SourcesDirectory)/tools/ci_build/github/linux/docker/inference/x64/python/cpu/scripts/install_protobuf.sh -p $(Build.BinariesDirectory)/protobuf_install -d $(Build.SourcesDirectory)/cmake/deps.txt + displayName: "Build Host Protoc" + + # create and test mobile pods + - script: | + python tools/ci_build/github/apple/build_and_assemble_ios_pods.py \ + --build-dir "$(Build.BinariesDirectory)/ios_framework" \ + --staging-dir "$(Build.BinariesDirectory)/staging" \ + --pod-version "$(ortPodVersion)" \ + --test \ + --variant ${{ parameters.packageVariant }} \ + --build-settings-file "${{ variables.buildSettingsFile }}" \ + ${{ variables.optionalIncludeOpsByConfigOption }} \ + -b="--path_to_protoc_exe=$(Build.BinariesDirectory)/protobuf_install/bin/protoc" + displayName: "Build iOS framework and assemble pod package files" + + - script: | + python tools/ci_build/github/apple/test_ios_packages.py \ + --fail_if_cocoapods_missing \ + --framework_info_file "$(Build.BinariesDirectory)/ios_framework/framework_info.json" \ + --c_framework_dir "$(Build.BinariesDirectory)/ios_framework/framework_out" \ + --variant ${{ parameters.packageVariant }} \ + --test_project_stage_dir "$(Build.BinariesDirectory)/app_center_test" \ + --prepare_test_project_only + displayName: "Assemble test project for App Center" + + - task: Xcode@5 + inputs: + actions: 'build-for-testing' + configuration: 'Debug' + xcWorkspacePath: '$(Build.BinariesDirectory)/app_center_test/ios_package_test/ios_package_test.xcworkspace' + sdk: 'iphoneos' + scheme: 'ios_package_test' + xcodeVersion: 'specifyPath' + xcodeDeveloperDir: '/Applications/Xcode_${{ variables.xcodeVersion }}.app/Contents/Developer' + signingOption: 'manual' + signingIdentity: '$(APPLE_CERTIFICATE_SIGNING_IDENTITY)' + provisioningProfileName: 'temporary *' # temporary name, change it back to the original below later + #provisioningProfileName: 'iOS Team Provisioning Profile' + args: '-derivedDataPath $(Build.BinariesDirectory)/app_center_test/ios_package_test/DerivedData' + workingDirectory: '$(Build.BinariesDirectory)/app_center_test/ios_package_test/' + useXcpretty: false # xcpretty can hide useful error output so we will disable it + displayName: 'Build App Center iPhone arm64 tests' + + - script: | + set -e -x + appcenter test run xcuitest \ + --app "AI-Frameworks/ORT-Mobile-iOS" \ + --devices $(app_center_test_devices) \ + --test-series "master" \ + --locale "en_US" \ + --build-dir $(Build.BinariesDirectory)/app_center_test/ios_package_test/DerivedData/Build/Products/Debug-iphoneos \ + --token $(app_center_api_token) + displayName: "Run E2E tests on App Center" + + - script: | + set -e -x + + for POD_NAME in "${{ variables.cPodName}}" "${{ variables.objcPodName }}"; + do + ./tools/ci_build/github/apple/assemble_ios_packaging_artifacts.sh \ + "$(Build.BinariesDirectory)/staging" \ + "$(Build.ArtifactStagingDirectory)" \ + "${POD_NAME}" \ + "$(ortPodVersion)" + done + + # copy over helper script for use in release pipeline + cp tools/ci_build/github/apple/upload_pod_archive_and_update_podspec.sh "$(Build.ArtifactStagingDirectory)" + displayName: "Assemble artifacts" + + - script: | + set -e -x + ls -R "$(Build.ArtifactStagingDirectory)" + displayName: "List staged artifacts" + + - publish: "$(Build.ArtifactStagingDirectory)" + artifact: "ios_packaging_artifacts_${{ lower(parameters.packageVariant) }}" + displayName: "Publish artifacts" + + - template: ../component-governance-component-detection-steps.yml + parameters : + condition : 'succeeded' diff --git a/tools/ci_build/github/azure-pipelines/templates/upload-code-coverage-data.yml b/tools/ci_build/github/azure-pipelines/templates/upload-code-coverage-data.yml index 0a94aa7b0f70b..c70c4e1ebe4d1 100644 --- a/tools/ci_build/github/azure-pipelines/templates/upload-code-coverage-data.yml +++ b/tools/ci_build/github/azure-pipelines/templates/upload-code-coverage-data.yml @@ -2,7 +2,7 @@ jobs: - job: Upload workspace: clean: all - pool: 'Win-CPU-2021' + pool: 'onnxruntime-Win-CPU-2022' variables: - name: runCodesignValidationInjection value: false 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 de188e08be871..0e034dff9d0b2 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 @@ -17,6 +17,9 @@ exit 1 fi + # Do not output ##vso[] commands with `set -x` or they may be parsed again and include a trailing quote. + set +x + set_var() { local VAR_NAME=${1:?} local VAR_VALUE=${2:?} 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 new file mode 100644 index 0000000000000..7d767b4f4fde6 --- /dev/null +++ b/tools/ci_build/github/azure-pipelines/templates/use-xcode-version.yml @@ -0,0 +1,14 @@ +# Specify use of a specific Xcode version. + +parameters: +- name: xcodeVersion + type: string + default: "14.3" + +steps: +- bash: | + set -e -x + XCODE_DEVELOPER_DIR="/Applications/Xcode_${{ parameters.xcodeVersion }}.app/Contents/Developer" + sudo xcode-select --switch "${XCODE_DEVELOPER_DIR}" + + displayName: Use Xcode ${{ parameters.xcodeVersion }} 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 1b3ec6af24109..0b7bd3f645442 100644 --- a/tools/ci_build/github/azure-pipelines/templates/web-ci.yml +++ b/tools/ci_build/github/azure-pipelines/templates/web-ci.yml @@ -10,7 +10,7 @@ parameters: - name: PoolName displayName: 'Agent pool name' type: string - default: 'onnxruntime-Win-CPU-2019' + default: 'onnxruntime-Win-CPU-2022' - name: PackageName displayName: 'Package name' type: string @@ -24,15 +24,39 @@ parameters: type: boolean default: true +- name: WASMTemplate + type: string + default: win-wasm-ci.yml +# parameter couldn't be compared by string, so add one boolean parameter. +- name: UseWebPoolName + type: boolean + default: false +- name: RunWebGpuTestsForReleaseBuild + type: boolean + default: false +- name: RunWebGpuTestsForDebugBuild + type: boolean + default: false +- name: WebGpuPoolName + type: string + default: '' +- name: WebCpuPoolName + type: string + default: '' + - name: ExtraBuildArgs displayName: 'Extra build command line arguments' type: string +- name: WithCache + displayName: Build with Cache + type: boolean + default: false stages: -- stage: Extract_commit +- stage: Precheck_and_extract_commit jobs: - - job: Extract_commit + - job: Precheck_and_extract_commit pool: ${{ parameters.PoolName }} variables: runCodesignValidationInjection: false @@ -40,27 +64,42 @@ stages: workspace: clean: all steps: - - checkout: none + - checkout: self fetchDepth: 1 submodules: false - script: | - echo.$(Build.SourceVersion) - echo.$(Build.SourceVersion)>$(Build.ArtifactStagingDirectory)\__commit.txt + git submodule sync -- cmake/external/onnx + git submodule update --init -- cmake/external/onnx + workingDirectory: '$(Build.SourcesDirectory)' + displayName: 'Checkout submodule onnx' + - task: NodeTool@0 + inputs: + versionSpec: '16.x' + - template: linux-web-init-and-check.yml + - task: Bash@3 + displayName: 'Extract commit SHA and save to __commit.txt' + inputs: + targetType: 'inline' + script: | + echo $(Build.SourceVersion) + echo $(Build.SourceVersion) > "$(Build.ArtifactStagingDirectory)"/__commit.txt - task: PublishPipelineArtifact@0 - displayName: 'Publish Pipeline Artifact' + displayName: 'Publish __commit.txt' inputs: artifactName: '__commit' targetPath: '$(Build.ArtifactStagingDirectory)' - stage: Build_wasm_Debug - dependsOn: Extract_commit + dependsOn: Precheck_and_extract_commit jobs: - - template: win-wasm-ci.yml + - template: ${{ parameters.WASMTemplate }} parameters: CommitOverride: true BuildConfig: 'Debug' ExtraBuildArgs: '--use_extensions --cmake_extra_defines onnxruntime_WEBASSEMBLY_DEFAULT_EXTENSION_FLAGS=ON ${{ parameters.ExtraBuildArgs }}' PoolName: ${{ parameters.PoolName }} + BuildJsep: ${{ parameters.BuildJsep }} + WithCache: ${{ parameters.WithCache }} - stage: Build_web_Debug dependsOn: Build_wasm_Debug @@ -70,25 +109,33 @@ stages: CommitOverride: true BuildConfig: 'Debug' NpmPackagingMode: ${{ parameters.NpmPackagingMode }} - PoolName: ${{ parameters.PoolName }} + ${{ if eq(parameters.UseWebPoolName, true)}}: + ${{ if eq(parameters.RunWebGpuTestsForDebugBuild, true)}}: + PoolName: ${{ parameters.WebGpuPoolName }} + ${{ else }}: + PoolName: ${{ parameters.WebCpuPoolName }} + ${{ else }}: + PoolName: ${{ parameters.PoolName }} PackageName: ${{ parameters.PackageName }} + RunWebGpuTests: ${{ parameters.RunWebGpuTestsForDebugBuild }} - stage: Build_wasm_Release - dependsOn: Extract_commit + dependsOn: Precheck_and_extract_commit jobs: - - template: win-wasm-ci.yml + - template: ${{ parameters.WASMTemplate }} parameters: CommitOverride: true BuildConfig: 'Release' - ExtraBuildArgs: '--skip_tests --enable_wasm_api_exception_catching --disable_rtti --use_extensions --cmake_extra_defines onnxruntime_WEBASSEMBLY_DEFAULT_EXTENSION_FLAGS=ON ${{ parameters.ExtraBuildArgs }}' + ExtraBuildArgs: '--target onnxruntime_webassembly --skip_tests --enable_wasm_api_exception_catching --disable_rtti --use_extensions --cmake_extra_defines onnxruntime_WEBASSEMBLY_DEFAULT_EXTENSION_FLAGS=ON ${{ parameters.ExtraBuildArgs }}' PoolName: ${{ parameters.PoolName }} BuildJsep: ${{ parameters.BuildJsep }} + WithCache: ${{ parameters.WithCache }} - ${{ if eq(parameters.BuildStaticLib, 'true') }}: - stage: Build_wasm_Release_static_library - dependsOn: Extract_commit + dependsOn: Precheck_and_extract_commit jobs: - - template: win-wasm-ci.yml + - template: ${{ parameters.WASMTemplate }} parameters: CommitOverride: true BuildConfig: 'Release' @@ -96,6 +143,8 @@ stages: PoolName: ${{ parameters.PoolName }} SkipPublish: true TimeoutInMinutes: 270 + BuildStaticLib: true + WithCache: ${{ parameters.WithCache }} - stage: Build_web_Release dependsOn: Build_wasm_Release @@ -105,16 +154,26 @@ stages: CommitOverride: true BuildConfig: 'Release' NpmPackagingMode: ${{ parameters.NpmPackagingMode }} - PoolName: ${{ parameters.PoolName }} + ${{ if eq(parameters.UseWebPoolName, true)}}: + ${{ if eq(parameters.RunWebGpuTestsForReleaseBuild, true)}}: + PoolName: ${{ parameters.WebGpuPoolName }} + ${{ else }}: + PoolName: ${{ parameters.WebCpuPoolName }} + ${{ else }}: + PoolName: ${{ parameters.PoolName }} PackageName: ${{ parameters.PackageName }} + RunWebGpuTests: ${{ parameters.RunWebGpuTestsForReleaseBuild }} -- ${{ if ne(parameters.IsReleasePipeline, true) }}: - - stage: Test_web_BrowserStack - dependsOn: Build_wasm_Release - jobs: - - template: web-browserstack-ci.yml - parameters: - CommitOverride: true +# Disable BrowserStack test +# TODO: fix and re-enable in PostMerge test +# +# - ${{ if ne(parameters.IsReleasePipeline, true) }}: +# - stage: Test_web_BrowserStack +# dependsOn: Build_wasm_Release +# jobs: +# - template: web-browserstack-ci.yml +# parameters: +# CommitOverride: true - ${{ if ne(parameters.IsReleasePipeline, true) }}: - stage: Test_web_MultiBrowsers 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 6620f4396e7a2..80d285f3fd3fb 100644 --- a/tools/ci_build/github/azure-pipelines/templates/win-ci.yml +++ b/tools/ci_build/github/azure-pipelines/templates/win-ci.yml @@ -43,9 +43,15 @@ parameters: type: string default: '' +# for inference packages '', for training packages '-training' +# used for drop-extra and c api artifacts (onnxruntime-win-* or onnxrutime-training-win-*) +- name: artifact_name_suffix + type: string + default: '' + - name: ort_build_pool_name type: string - default: 'Win-CPU-2021' + default: 'onnxruntime-Win-CPU-2022' #'onnxruntime' or 'onnxruntime_gpu' - name: java_artifact_id @@ -56,9 +62,12 @@ parameters: displayName: Increase timeout for tests? Set it to false if you are doing an Onnx Runtime release. type: boolean default: false + stages: - stage: Windows_Packaging_${{ parameters.stage_name_suffix }} dependsOn: [] + variables: + VSGenerator: 'Visual Studio 17 2022' jobs: - job: workspace: @@ -76,6 +85,13 @@ stages: - template: telemetry-steps.yml + - ${{ if eq(parameters['buildJava'], 'true') }}: + - task: JavaToolInstaller@0 + inputs: + versionSpec: "11" + jdkArchitectureOption: ${{ parameters.buildArch }} + jdkSourceOption: 'PreInstalled' + - task: UsePythonVersion@0 inputs: versionSpec: '3.8' @@ -87,12 +103,11 @@ stages: inputs: versionSpec: '16.x' - - task: BatchScript@1 - displayName: 'setup env' - inputs: - filename: '$(Build.SourcesDirectory)\tools\ci_build\github\windows\${{ parameters.EnvSetupScript }}' - modifyEnvironment: true - workingFolder: '$(Build.BinariesDirectory)' + - template: jobs/set-winenv.yml + parameters: + EnvSetupScript: ${{ parameters.EnvSetupScript }} + ${{ if contains(parameters.buildparameter, 'use_cuda') }}: + DownloadCUDA: true - template: download-deps.yml @@ -117,9 +132,9 @@ stages: inputs: scriptPath: '$(Build.SourcesDirectory)\tools\ci_build\build.py' ${{ if eq(parameters['UseIncreasedTimeoutForTests'], 'true') }}: - arguments: '--config RelWithDebInfo --enable_lto --disable_rtti --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --build_shared_lib --update --cmake_generator "Visual Studio 16 2019" --enable_onnx_tests $(TelemetryOption) ${{ parameters.buildparameter }} --test_all_timeout 72000' + arguments: '--config RelWithDebInfo --enable_lto --disable_rtti --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --build_shared_lib --update --cmake_generator "$(VSGenerator)" --enable_onnx_tests $(TelemetryOption) ${{ parameters.buildparameter }} --test_all_timeout 72000' ${{ else }}: - arguments: '--config RelWithDebInfo --enable_lto --disable_rtti --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --build_shared_lib --update --cmake_generator "Visual Studio 16 2019" --enable_onnx_tests $(TelemetryOption) ${{ parameters.buildparameter }} ' + arguments: '--config RelWithDebInfo --enable_lto --disable_rtti --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --build_shared_lib --update --cmake_generator "$(VSGenerator)" --enable_onnx_tests $(TelemetryOption) ${{ parameters.buildparameter }} ' workingDirectory: '$(Build.BinariesDirectory)' - task: VSBuild@1 @@ -139,7 +154,7 @@ stages: condition: and(succeeded(), eq('${{ parameters.runTests}}', true)) inputs: scriptPath: '$(Build.SourcesDirectory)\tools\ci_build\build.py' - arguments: '--config RelWithDebInfo --enable_lto --disable_rtti --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --build_shared_lib --test --cmake_generator "Visual Studio 16 2019" --enable_onnx_tests $(TelemetryOption) ${{ parameters.buildparameter }}' + arguments: '--config RelWithDebInfo --enable_lto --disable_rtti --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --build_shared_lib --test --cmake_generator "$(VSGenerator)" --enable_onnx_tests $(TelemetryOption) ${{ parameters.buildparameter }}' workingDirectory: '$(Build.BinariesDirectory)' - script: | @@ -151,8 +166,8 @@ stages: - template: c-api-artifacts-package-and-publish-steps-windows.yml parameters: buildConfig: RelWithDebInfo - artifactName: 'onnxruntime-win-${{ parameters.packageName }}-$(OnnxRuntimeVersion)' - artifactNameNoVersionString: 'onnxruntime-win-${{ parameters.packageName }}' + artifactName: 'onnxruntime${{ parameters.artifact_name_suffix }}-win-${{ parameters.packageName }}-$(OnnxRuntimeVersion)' + artifactNameNoVersionString: 'onnxruntime${{ parameters.artifact_name_suffix }}-win-${{ parameters.packageName }}' commitId: $(OnnxRuntimeGitCommitHash) DoEsrp: ${{ parameters.DoEsrp }} @@ -168,7 +183,7 @@ stages: condition: and(succeeded(), eq('${{ parameters.packageName}}', 'x64')) inputs: targetPath: '$(Build.BinariesDirectory)\RelWithDebInfo\installed\bin\protoc.exe' - artifactName: 'drop-extra' + artifactName: 'drop-extra${{ parameters.artifact_name_suffix }}' - task: CopyFiles@2 @@ -184,8 +199,7 @@ stages: condition: and(succeeded(), eq('${{ parameters.packageName}}', 'x64')) inputs: targetPath: '$(Build.BinariesDirectory)\RelWithDebInfo\installed\bin\protoc.exe' - artifactName: 'drop-nuget' - + artifactName: 'drop-nuget${{ parameters.artifact_name_suffix }}' - task: CmdLine@2 condition: and(succeeded(), eq('${{ parameters.buildJava}}', true)) @@ -237,18 +251,6 @@ stages: artifactName: 'drop-onnxruntime-java-win-${{ parameters.packageName }}' - ${{ if eq(parameters['DoCompliance'], 'true') }}: - - task: Semmle@0 - condition: and(succeeded(), eq('${{ parameters.buildJava}}', true)) - inputs: - sourceCodeDirectory: '$(Build.SourcesDirectory)\java' - language: 'java' - cleanupBuildCommands: '$(Build.SourcesDirectory)\java\gradlew.bat -Dorg.gradle.daemon=false clean' - buildCommands: '$(Build.SourcesDirectory)\java\gradlew.bat -Dorg.gradle.daemon=false jar' - querySuite: 'Recommended' - timeout: '7200' - ram: '16384' - addProjectDirToScanningExclusionList: true - - task: CredScan@3 displayName: 'Run CredScan' inputs: @@ -261,25 +263,6 @@ stages: AnalyzeTargetGlob: '$(Build.BinariesDirectory)\RelWithDebInfo\RelWithDebInfo\**\*.dll' continueOnError: true - - task: DeleteFiles@1 - displayName: 'Delete files from $(Build.BinariesDirectory)\RelWithDebInfo' - inputs: - SourceFolder: '$(Build.BinariesDirectory)\RelWithDebInfo' - Contents: | - **/*.obj - **/*.pdb - **/*.dll - - #Manually set msBuildCommandline so that we can also set CAExcludePath - - task: SDLNativeRules@3 - displayName: 'Run the PREfast SDL Native Rules for MSBuild' - condition: and (succeeded(), eq(variables['msbuildPlatform'], 'x64')) - inputs: - msBuildArchitecture: amd64 - setupCommandlines: 'python $(Build.SourcesDirectory)\tools\ci_build\build.py --config Debug --disable_rtti --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --build_shared_lib --update --cmake_generator "Visual Studio 16 2019" --enable_onnx_tests $(TelemetryOption) ${{ parameters.buildparameter }} --cmake_extra_defines onnxruntime_ENABLE_STATIC_ANALYSIS=ON' - msBuildCommandline: '"C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\amd64\msbuild.exe" "$(Build.BinariesDirectory)\Debug\onnxruntime.sln" /p:platform="$(MsbuildPlatform)" /p:configuration=Debug /p:VisualStudioVersion="16.0" /m /p:PreferredToolArchitecture=x64' - excludedPaths: '$(Build.BinariesDirectory)#$(Build.SourcesDirectory)\cmake#C:\program files (x86)' - - task: PostAnalysis@2 inputs: GdnBreakAllTools: false 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 4ec339bb0fb81..9d36e2dbe4944 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 @@ -13,7 +13,7 @@ parameters: - name: PoolName type: string - default: 'onnxruntime-Win-CPU-2019' + default: 'onnxruntime-Win-CPU-2022' - name: SkipPublish type: boolean @@ -26,6 +26,15 @@ parameters: type: boolean default: false +# In fact, it's only used on Linux for compiler cache. +- name: BuildStaticLib + type: boolean + default: false + +- name: WithCache + type: boolean + default: false + jobs: - job: build_WASM pool: ${{ parameters.PoolName }} @@ -33,7 +42,7 @@ jobs: variables: EnvSetupScript: setup_env.bat buildArch: x64 - CommonBuildArgs: '--parallel --config ${{ parameters.BuildConfig }} --skip_submodule_sync --cmake_generator "MinGW Makefiles" --build_wasm --use_xnnpack --emsdk_version releases-29ad1037cd6b99e5d8a1bd75bc188c1e9a6fda8d-64bit ${{ parameters.ExtraBuildArgs }}' + CommonBuildArgs: '--parallel --config ${{ parameters.BuildConfig }} --skip_submodule_sync --cmake_generator "MinGW Makefiles" --build_wasm --use_xnnpack ${{ parameters.ExtraBuildArgs }}' runCodesignValidationInjection: false timeoutInMinutes: ${{ parameters.TimeoutInMinutes }} workspace: @@ -88,10 +97,10 @@ jobs: arguments: '$(CommonBuildArgs) --build_dir $(Build.BinariesDirectory)\wasm_threads --enable_wasm_threads' workingDirectory: '$(Build.BinariesDirectory)' - task: PythonScript@0 - displayName: 'Build and test (node) (simd + threads)' + displayName: 'Build and test (browser) (simd + threads)' inputs: scriptPath: '$(Build.SourcesDirectory)\tools\ci_build\build.py' - arguments: '$(CommonBuildArgs) --build_dir $(Build.BinariesDirectory)\wasm_simd_threads --enable_wasm_simd --enable_wasm_threads' + arguments: '$(CommonBuildArgs) --build_dir $(Build.BinariesDirectory)\wasm_simd_threads --enable_wasm_simd --enable_wasm_threads --wasm_run_tests_in_browser' workingDirectory: '$(Build.BinariesDirectory)' - task: PythonScript@0 displayName: 'Build and test (node) (simd)' @@ -104,7 +113,14 @@ jobs: displayName: 'Build (simd + JSEP)' inputs: scriptPath: '$(Build.SourcesDirectory)\tools\ci_build\build.py' - arguments: '$(CommonBuildArgs) --build_dir $(Build.BinariesDirectory)\wasm_simd_jsep --enable_wasm_simd --use_js --target onnxruntime_webassembly' + arguments: '$(CommonBuildArgs) --build_dir $(Build.BinariesDirectory)\wasm_simd_jsep --enable_wasm_simd --use_jsep --target onnxruntime_webassembly --skip_tests' + workingDirectory: '$(Build.BinariesDirectory)' + - ${{ if eq(parameters.BuildJsep, true) }}: + - task: PythonScript@0 + displayName: 'Build (simd + threads + JSEP)' + inputs: + scriptPath: '$(Build.SourcesDirectory)\tools\ci_build\build.py' + arguments: '$(CommonBuildArgs) --build_dir $(Build.BinariesDirectory)\wasm_simd_threads_jsep --enable_wasm_simd --enable_wasm_threads --use_jsep --target onnxruntime_webassembly --skip_tests' workingDirectory: '$(Build.BinariesDirectory)' - ${{ if eq(parameters.SkipPublish, false) }}: - script: | @@ -116,6 +132,11 @@ jobs: copy $(Build.BinariesDirectory)\wasm_simd_jsep\${{ parameters.BuildConfig }}\ort-wasm-simd.wasm $(Build.ArtifactStagingDirectory)\ort-wasm-simd.jsep.wasm copy $(Build.BinariesDirectory)\wasm_simd_jsep\${{ parameters.BuildConfig }}\ort-wasm-simd.js $(Build.ArtifactStagingDirectory)\ort-wasm-simd.jsep.js ) + if exist $(Build.BinariesDirectory)\wasm_simd_threads_jsep ( + copy $(Build.BinariesDirectory)\wasm_simd_threads_jsep\${{ parameters.BuildConfig }}\ort-wasm-simd-threaded.wasm $(Build.ArtifactStagingDirectory)\ort-wasm-simd-threaded.jsep.wasm + copy $(Build.BinariesDirectory)\wasm_simd_threads_jsep\${{ parameters.BuildConfig }}\ort-wasm-simd-threaded.js $(Build.ArtifactStagingDirectory)\ort-wasm-simd-threaded.jsep.js + copy $(Build.BinariesDirectory)\wasm_simd_threads_jsep\${{ parameters.BuildConfig }}\ort-wasm-simd-threaded.worker.js $(Build.ArtifactStagingDirectory)\ort-wasm-simd-threaded.jsep.worker.js + ) displayName: 'Create Artifacts' - ${{ if eq(parameters.SkipPublish, false) }}: - task: PublishPipelineArtifact@0 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 af35792804522..bad7448715936 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 @@ -13,23 +13,30 @@ parameters: - name: PoolName type: string - default: 'onnxruntime-Win-CPU-2019' + default: 'onnxruntime-Win-CPU-2022' - name: PackageName displayName: 'Package name' type: string default: 'NPM_packages' +- name: RunWebGpuTests + type: boolean + default: false + jobs: - job: build_onnxruntime_web pool: ${{ parameters.PoolName }} variables: runCodesignValidationInjection: false - timeoutInMinutes: 30 + timeoutInMinutes: 60 workspace: clean: all steps: + - task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3 + displayName: 'Clean Agent Directories' + condition: always() - checkout: self submodules: false - task: DownloadPipelineArtifact@2 @@ -62,7 +69,7 @@ jobs: git checkout -- js/** git checkout -- .gitattributes workingDirectory: '$(Build.SourcesDirectory)' - displayName: 'Testing: force EOL to lf on windows for /js/**' + displayName: 'Testing: force EOL to lf on windows for /js/**' - task: NodeTool@0 inputs: versionSpec: '16.x' @@ -99,6 +106,10 @@ jobs: npm ci workingDirectory: '$(Build.SourcesDirectory)\js\common' displayName: 'npm ci /js/common/' + - script: | + npm test + workingDirectory: '$(Build.SourcesDirectory)\js\common' + displayName: 'run onnxruntime-common tests' - script: | npm ci workingDirectory: '$(Build.SourcesDirectory)\js\web' @@ -123,6 +134,20 @@ jobs: 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 + inputs: + key: onnxtestdata | $(Build.SourcesDirectory)\js\scripts\prepare-onnx-node-tests.ts + restoreKeys: | + onnxtestdata | $(Build.SourcesDirectory)\js\scripts\prepare-onnx-node-tests.ts + path: $(Build.SourcesDirectory)/js/test/ + cacheHitVar: CACHE_RESTORED + displayName: 'Cache ONNX node test data' + - task: Bash@3 + inputs: + targetType: 'inline' + script: find "$(Build.SourcesDirectory)/js/test/" -type f + condition: and(not(canceled()), eq(variables.CACHE_RESTORED, 'true')) + displayName: 'List ONNX node test data' - task: PowerShell@2 inputs: filePath: '$(Build.SourcesDirectory)\tools\ci_build\github\js\pack-npm-packages.ps1' @@ -131,19 +156,26 @@ jobs: errorActionPreference: stop displayName: 'Pack NPM packages' - script: | - npm test + npm test -- -e=edge -b=webgl,wasm,xnnpack + workingDirectory: '$(Build.SourcesDirectory)\js\web' + displayName: 'Run ort-web tests (wasm,webgl,xnnpack backend)' + condition: ne('${{ parameters.RunWebGpuTests }}', 'true') + - script: | + npm test -- -e=edge -b=webgl,wasm,xnnpack,webgpu --chromium-flags=--ignore-gpu-blocklist --chromium-flags=--gpu-vendor-id=0x10de workingDirectory: '$(Build.SourcesDirectory)\js\web' - displayName: 'Run ort-web tests' + displayName: 'Run ort-web tests (ALL backends)' + condition: ne('${{ parameters.RunWebGpuTests }}', 'false') - script: | - npm test -- --webgl-texture-pack-mode -b=webgl + npm test -- --webgl-texture-pack-mode -b=webgl -e=edge workingDirectory: '$(Build.SourcesDirectory)\js\web' displayName: 'Run ort-web tests - WebGL: packed mode' - script: | - npm test -- --wasm-enable-proxy -b=wasm + npm test -- --wasm-enable-proxy -b=wasm -e=edge workingDirectory: '$(Build.SourcesDirectory)\js\web' displayName: 'Run ort-web tests - WebAssembly: proxy' + condition: and(succeeded(), eq('${{ parameters.BuildConfig }}', 'Release')) - script: | - npm run test:e2e + npm run test:e2e -- --browser=Edge_default workingDirectory: '$(Build.SourcesDirectory)\js\web' displayName: 'E2E package consuming test' condition: and(succeeded(), eq('${{ parameters.BuildConfig }}', 'Release')) @@ -170,6 +202,3 @@ jobs: - template: component-governance-component-detection-steps.yml parameters : condition : 'succeeded' - - task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3 - displayName: 'Clean Agent Directories' - condition: always() 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 9601922a83820..723567389579d 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 @@ -68,15 +68,15 @@ jobs: workingDirectory: '$(Build.SourcesDirectory)\js\web' displayName: 'npm ci /js/web/' - script: | - npm test -- suite0 --wasm-init-timeout=30000 --file-cache + npm test -- suite0 -b=wasm,webgl,xnnpack --wasm-init-timeout=30000 --file-cache workingDirectory: '$(Build.SourcesDirectory)\js\web' displayName: 'npm test (Suite0, Chrome)' - script: | - npm test -- suite0 --env=firefox --wasm-init-timeout=30000 --file-cache + npm test -- suite0 -b=wasm,webgl,xnnpack --env=firefox --wasm-init-timeout=30000 --file-cache workingDirectory: '$(Build.SourcesDirectory)\js\web' displayName: 'npm test (Suite0, Firefox)' - script: | - npm test -- suite0 --env=edge --wasm-init-timeout=30000 --file-cache + npm test -- suite0 -b=wasm,webgl,xnnpack --env=edge --wasm-init-timeout=30000 --file-cache workingDirectory: '$(Build.SourcesDirectory)\js\web' displayName: 'npm test (Suite0, Edge)' - task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3 diff --git a/tools/ci_build/github/azure-pipelines/templates/windows-build-and-test-steps.yml b/tools/ci_build/github/azure-pipelines/templates/windows-build-and-test-steps.yml deleted file mode 100644 index aebc170e22986..0000000000000 --- a/tools/ci_build/github/azure-pipelines/templates/windows-build-and-test-steps.yml +++ /dev/null @@ -1,41 +0,0 @@ -# Runs various windows builds and tests, then publish test results - -parameters: - buildAdditionalParams: '' - msbuildPlatform: 'x64' - buildArch: 'x64' - buildConfig: 'RelWithDebInfo' - -steps: - - task: CmdLine@2 - displayName: 'Download test data and generate cmake config' - inputs: - script: | - $(Build.BinariesDirectory)\packages\python\python.exe $(Build.SourcesDirectory)\tools\ci_build\build.py --config ${{parameters.buildConfig}} --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --build_shared_lib --cmake_path $(Build.BinariesDirectory)\cmake\bin\cmake.exe --ctest_path $(Build.BinariesDirectory)\cmake\bin\ctest.exe --enable_onnx_tests --update ${{parameters.buildAdditionalParams}} - workingDirectory: '$(Build.BinariesDirectory)' - - - task: VSBuild@1 - displayName: 'Build ${{parameters.buildConfig}}' - inputs: - solution: '$(Build.BinariesDirectory)\${{parameters.buildConfig}}\onnxruntime.sln' - platform: '${{parameters.msbuildPlatform}}' - configuration: '${{parameters.buildConfig}}' - msbuildArgs: '/m' - msbuildArchitecture: $(buildArch) - logProjectEvents: true - workingFolder: '$(Build.BinariesDirectory)\${{parameters.buildConfig}}' - - - task: BatchScript@1 - displayName: 'Test ${{parameters.buildConfig}}' - inputs: - filename: '$(Build.BinariesDirectory)\packages\python\python.exe' - arguments: '$(Build.SourcesDirectory)\tools\ci_build\build.py --config ${{parameters.buildConfig}} --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --cmake_path $(Build.BinariesDirectory)\cmake\bin\cmake.exe --ctest_path $(Build.BinariesDirectory)\cmake\bin\ctest.exe --build_shared_lib --enable_onnx_tests --test ${{parameters.buildAdditionalParams}}' - workingFolder: '$(Build.BinariesDirectory)' - - - 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/templates/windows-build-tools-setup-steps.yml b/tools/ci_build/github/azure-pipelines/templates/windows-build-tools-setup-steps.yml deleted file mode 100644 index aa8e66f2fb7ea..0000000000000 --- a/tools/ci_build/github/azure-pipelines/templates/windows-build-tools-setup-steps.yml +++ /dev/null @@ -1,62 +0,0 @@ -# sets up common build tools for the windows build machines before build - -parameters: - EnvSetupScript: '' - DoDataDownload: true -steps: - - task: NuGetToolInstaller@0 - displayName: Use Nuget 5.7.0 - inputs: - versionSpec: 5.7.0 - # - task: UniversalPackages@0 - # displayName: 'Download python' - # inputs: - # command: download - # vstsFeed: '$(System.TeamProject)' - # vstsFeedPackage: 'miniconda3_win64' - # vstsPackageVersion: '4.5.11' - # downloadDirectory: '$(Build.BinariesDirectory)\python' - - # Temporary bypass of artifacts permission issue - - task: PowerShell@2 - displayName: 'Download AzCopy (used for download test data script)' - inputs: - targetType: 'inline' - script: | - Invoke-WebRequest -OutFile $(Build.BinariesDirectory)\azcopy.exe https://onnxruntimetestdata.blob.core.windows.net/models/azcopy.exe - - - task: CmdLine@1 - displayName: 'Download Python' - inputs: - filename: '$(Build.BinariesDirectory)\azcopy.exe' - arguments: 'copy https://onnxruntimetestdata.blob.core.windows.net/models/Miniconda3-4.7.10-Windows-x86_64.exe $(Build.BinariesDirectory)\Miniconda3-4.7.10-Windows-x86_64.exe' - timeoutInMinutes: 10 - - - task: CmdLine@1 - displayName: 'Run python installer' - inputs: - filename: '$(Build.BinariesDirectory)\Miniconda3-4.7.10-Windows-x86_64.exe' - arguments: '/S /NoRegistry=1 /AddToPath=0 /RegisterPython=0 /D=$(Build.BinariesDirectory)\packages\python' - timeoutInMinutes: 10 - - - task: BatchScript@1 - displayName: 'setup env' - inputs: - filename: '$(Build.SourcesDirectory)\tools\ci_build\github\windows\${{parameters.EnvSetupScript}}' - modifyEnvironment: true - workingFolder: '$(Build.BinariesDirectory)' - - task: CmdLine@1 - displayName: 'Install conda modules' - inputs: - filename: '$(Build.BinariesDirectory)\packages\python\scripts\conda.exe' - arguments: 'install -q -y setuptools wheel numpy' - timeoutInMinutes: 10 - - - - task: CmdLine@1 - continueOnError: true - displayName: 'Run OpenCPPCoverage installer' - condition: ${{parameters.DoDataDownload}} - inputs: - filename: '$(Build.BinariesDirectory)\installer\opencppcoverage\installer.exe' - arguments: '/SP- /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /DIR="$(Build.BinariesDirectory)\OpenCppCoverage"' diff --git a/tools/ci_build/github/azure-pipelines/triggers/skip-docs.yml b/tools/ci_build/github/azure-pipelines/triggers/skip-docs.yml new file mode 100644 index 0000000000000..ff4dc9d057000 --- /dev/null +++ b/tools/ci_build/github/azure-pipelines/triggers/skip-docs.yml @@ -0,0 +1,22 @@ +trigger: + branches: + include: + - main + - rel-* + paths: + exclude: + - docs/** + - README.md + - CONTRIBUTING.md + - BUILD.md +pr: + branches: + include: + - main + - rel-* + paths: + exclude: + - docs/** + - README.md + - CONTRIBUTING.md + - BUILD.md diff --git a/tools/ci_build/github/azure-pipelines/triggers/skip-js.yml b/tools/ci_build/github/azure-pipelines/triggers/skip-js.yml new file mode 100644 index 0000000000000..7ddc8e6e2b1e9 --- /dev/null +++ b/tools/ci_build/github/azure-pipelines/triggers/skip-js.yml @@ -0,0 +1,26 @@ +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' diff --git a/tools/ci_build/github/azure-pipelines/web-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/web-ci-pipeline.yml index dd3baa480d50c..63dabf5eab9d9 100644 --- a/tools/ci_build/github/azure-pipelines/web-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/web-ci-pipeline.yml @@ -1,3 +1,28 @@ +##### start trigger Don't edit it manually, Please do edit set-trigger-rules.py #### +trigger: + branches: + include: + - main + - rel-* + paths: + exclude: + - docs/** + - README.md + - CONTRIBUTING.md + - BUILD.md +pr: + branches: + include: + - main + - rel-* + paths: + exclude: + - docs/** + - README.md + - CONTRIBUTING.md + - BUILD.md +#### end trigger #### + parameters: - name: NpmPublish displayName: 'NPM packages publish configuration' @@ -28,6 +53,13 @@ stages: parameters: NpmPackagingMode: ${{ variables.NpmPackagingMode }} IsReleasePipeline: false - PoolName: 'onnxruntime-Win-CPU-2022-web' + PoolName: 'onnxruntime-Ubuntu2004-AMD-CPU' BuildStaticLib: true ExtraBuildArgs: $(ExtraBuildArgs) + WASMTemplate: linux-wasm-ci.yml + UseWebPoolName: true + RunWebGpuTestsForDebugBuild: false + RunWebGpuTestsForReleaseBuild: true + WebGpuPoolName: 'onnxruntime-Win2022-webgpu-A10' + WebCpuPoolName: 'onnxruntime-Win-CPU-2022-web' + WithCache: true diff --git a/tools/ci_build/github/azure-pipelines/web-packaging-pipeline.yml b/tools/ci_build/github/azure-pipelines/web-packaging-pipeline.yml deleted file mode 100644 index 236f5bda8913b..0000000000000 --- a/tools/ci_build/github/azure-pipelines/web-packaging-pipeline.yml +++ /dev/null @@ -1,31 +0,0 @@ -parameters: -- name: NpmPublish - displayName: 'NPM packages publish configuration' - type: string - values: - - 'nightly (@dev)' - - 'release candidate (@rc)' - - 'production (@latest)' - - 'custom' - default: 'nightly (@dev)' - -variables: - # pipeline should define the following varaibles - # ExtraBuildArgs - # VersionSuffix - - ${{ if eq(parameters.NpmPublish, 'nightly (@dev)') }}: - NpmPackagingMode: 'dev' - ${{ if eq(parameters.NpmPublish, 'release candidate (@rc)') }}: - NpmPackagingMode: 'rc' - ${{ if eq(parameters.NpmPublish, 'production (@latest)') }}: - NpmPackagingMode: 'release' - ${{ if eq(parameters.NpmPublish, 'custom') }}: - NpmPackagingMode: '$(VersionSuffix)' - -stages: -- template: templates/web-ci.yml - parameters: - NpmPackagingMode: ${{ variables.NpmPackagingMode }} - IsReleasePipeline: true - PoolName: 'Win-CPU-2021' \ No newline at end of file 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 fd83ae588470e..f3a5728d6519b 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 @@ -1,6 +1,6 @@ jobs: - job: 'build' - pool: 'Win-CPU-2021' + pool: 'onnxruntime-Win-CPU-2022' strategy: maxParallel: 2 matrix: @@ -15,39 +15,25 @@ jobs: buildArch: x64 setVcvars: true ALLOW_RELEASED_ONNX_OPSET_ONLY: '0' + TODAY: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)] timeoutInMinutes: 120 workspace: clean: all - steps: - - task: UsePythonVersion@0 - inputs: - versionSpec: '3.8' - addToPath: true - architecture: $(buildArch) + steps: + - template: win-ci-prebuild-steps.yml + parameters: + EnvSetupScript: $(EnvSetupScript) + DownloadCUDA: false + BuildArch: $(buildArch) + BuildConfig: $(BuildConfig) + MachinePool: 'onnxruntime-Win-CPU-2022' + WithCache: true + Today: $(Today) - task: NodeTool@0 inputs: versionSpec: '16.x' - - task: BatchScript@1 - displayName: 'setup env' - inputs: - filename: '$(Build.SourcesDirectory)\tools\ci_build\github\windows\$(EnvSetupScript)' - modifyEnvironment: true - workingFolder: '$(Build.BinariesDirectory)' - - - script: | - python -m pip install -q setuptools wheel numpy - workingDirectory: '$(Build.BinariesDirectory)' - displayName: 'Install python modules' - - - task: PowerShell@2 - displayName: 'Install ONNX' - inputs: - filePath: '$(Build.SourcesDirectory)/tools/ci_build/github/windows/install_third_party_deps.ps1' - workingDirectory: '$(Build.BinariesDirectory)' - arguments: -cpu_arch x64 -install_prefix $(Build.BinariesDirectory)\$(BuildConfig)\installed -build_config $(BuildConfig) - - task: NuGetToolInstaller@0 displayName: Use Nuget 5.7.0 inputs: @@ -57,7 +43,7 @@ jobs: displayName: 'Generate cmake config' inputs: scriptPath: '$(Build.SourcesDirectory)\tools\ci_build\build.py' - arguments: '--config $(BuildConfig) --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --build_shared_lib --update --cmake_generator "Visual Studio 16 2019" --use_full_protobuf --fuzz_testing' + arguments: '--config $(BuildConfig) --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --build_shared_lib --update --cmake_generator "Visual Studio 17 2022" --use_full_protobuf --fuzz_testing' workingDirectory: '$(Build.BinariesDirectory)' - task: VSBuild@1 diff --git a/tools/ci_build/github/azure-pipelines/win-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/win-ci-pipeline.yml index 2c42ad4693ef4..2a5622faf2905 100644 --- a/tools/ci_build/github/azure-pipelines/win-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/win-ci-pipeline.yml @@ -1,3 +1,32 @@ +##### start trigger Don't edit it manually, Please do edit 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? @@ -8,7 +37,7 @@ stages: - stage: x64_debug dependsOn: [] jobs: - - template: templates/win-ci-vs-2019.yml + - template: templates/jobs/win-ci-vs-2022-job.yml parameters: BuildConfig: 'Debug' EnvSetupScript: setup_env.bat @@ -18,17 +47,16 @@ stages: isX86: false job_name_suffix: x64_debug RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} - RunStaticCodeAnalysis: false isTraining: false ORT_EP_NAME: CPU GenerateDocumentation: false WITH_CACHE: true - MachinePool: 'onnxruntime-Win-CPU-2019' + MachinePool: 'onnxruntime-Win-CPU-2022' - stage: x64_release dependsOn: [] jobs: - - template: templates/win-ci-vs-2019.yml + - template: templates/jobs/win-ci-vs-2022-job.yml parameters: BuildConfig: 'RelWithDebInfo' EnvSetupScript: setup_env.bat @@ -40,17 +68,16 @@ stages: isX86: false job_name_suffix: x64_release RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} - RunStaticCodeAnalysis: false isTraining: false ORT_EP_NAME: CPU GenerateDocumentation: false WITH_CACHE: true - MachinePool: 'onnxruntime-Win-CPU-2019' + MachinePool: 'onnxruntime-Win-CPU-2022' - stage: x64_release_dnnl dependsOn: [] jobs: - - template: templates/win-ci-vs-2019.yml + - template: templates/jobs/win-ci-vs-2022-job.yml parameters: BuildConfig: 'RelWithDebInfo' EnvSetupScript: setup_env.bat @@ -60,19 +87,18 @@ stages: isX86: false job_name_suffix: x64_release RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} - RunStaticCodeAnalysis: false isTraining: false ORT_EP_NAME: DNNL GenerateDocumentation: false WITH_CACHE: true # Intel EPs require Intel CPUs - MachinePool: 'Win-CPU-2019' + MachinePool: 'onnxruntime-Win2022-Intel-CPU' # Tests doesn't work on AMD CPUs - stage: x64_release_xnnpack dependsOn: [] jobs: - - template: templates/win-ci-vs-2019.yml + - template: templates/jobs/win-ci-vs-2022-job.yml parameters: BuildConfig: 'RelWithDebInfo' EnvSetupScript: setup_env.bat @@ -81,40 +107,38 @@ stages: msbuildPlatform: x64 isX86: false job_name_suffix: x64_release - RunOnnxRuntimeTests: false - RunStaticCodeAnalysis: false + RunOnnxRuntimeTests: true isTraining: false ORT_EP_NAME: XNNPACK GenerateDocumentation: false WITH_CACHE: true - MachinePool: 'onnxruntime-Win-CPU-2019' + MachinePool: 'onnxruntime-Win-CPU-2022' - stage: x64_release_winml dependsOn: [] jobs: - - template: templates/win-ci-vs-2019.yml + - template: templates/jobs/win-ci-vs-2022-job.yml parameters: BuildConfig: 'RelWithDebInfo' EnvSetupScript: setup_env.bat buildArch: x64 - additionalBuildFlags: --use_winml --enable_wcos --disable_rtti + additionalBuildFlags: --use_winml --enable_wcos --disable_rtti --cmake_extra_defines CMAKE_SYSTEM_VERSION=10.0.22000.0 msbuildPlatform: x64 isX86: false job_name_suffix: x64_release_winml RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} # WinML has many warnings - RunStaticCodeAnalysis: false EnablePython: false isTraining: false ORT_EP_NAME: CPU GenerateDocumentation: false WITH_CACHE: true - MachinePool: 'onnxruntime-Win-CPU-2019' + MachinePool: 'onnxruntime-Win-CPU-2022' - stage: x86_release dependsOn: [] jobs: - - template: templates/win-ci-vs-2019.yml + - template: templates/jobs/win-ci-vs-2022-job.yml parameters: BuildConfig: 'RelWithDebInfo' EnvSetupScript: setup_env_x86.bat @@ -124,17 +148,16 @@ stages: isX86: true job_name_suffix: x86_release RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} - RunStaticCodeAnalysis: false isTraining: false ORT_EP_NAME: CPU GenerateDocumentation: false WITH_CACHE: true - MachinePool: 'onnxruntime-Win-CPU-2019' + MachinePool: 'onnxruntime-Win-CPU-2022' - stage: training_x64_debug dependsOn: [] jobs: - - template: templates/win-ci-vs-2019.yml + - template: templates/jobs/win-ci-vs-2022-job.yml parameters: BuildConfig: 'Debug' EnvSetupScript: setup_env.bat @@ -144,17 +167,16 @@ stages: isX86: false job_name_suffix: training_x64_debug RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} - RunStaticCodeAnalysis: false isTraining: true ORT_EP_NAME: CPU GenerateDocumentation: false WITH_CACHE: true - MachinePool: 'onnxruntime-Win2019-CPU-training' + MachinePool: 'onnxruntime-Win2022-CPU-training-AMD' - stage: training_x64_release dependsOn: [] jobs: - - template: templates/win-ci-vs-2019.yml + - template: templates/jobs/win-ci-vs-2022-job.yml parameters: BuildConfig: 'RelWithDebInfo' EnvSetupScript: setup_env.bat @@ -164,17 +186,16 @@ stages: isX86: false job_name_suffix: training_x64_release RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} - RunStaticCodeAnalysis: true isTraining: true ORT_EP_NAME: CPU GenerateDocumentation: false WITH_CACHE: true - MachinePool: 'onnxruntime-Win2019-CPU-training-AMD' + MachinePool: 'onnxruntime-Win2022-CPU-training-AMD' - stage: ort_training_apis_x64_release dependsOn: [] jobs: - - template: templates/win-ci-vs-2019.yml + - template: templates/jobs/win-ci-vs-2022-job.yml parameters: BuildConfig: 'RelWithDebInfo' EnvSetupScript: setup_env.bat @@ -184,10 +205,29 @@ stages: isX86: false job_name_suffix: ort_training_apis_x64_release RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} - RunStaticCodeAnalysis: false EnablePython: false isTraining: true ORT_EP_NAME: CPU GenerateDocumentation: false WITH_CACHE: true - MachinePool: 'onnxruntime-Win2019-CPU-training-AMD' \ No newline at end of file + MachinePool: 'onnxruntime-Win2022-CPU-training-AMD' + +- stage: x64_release_azure + dependsOn: [] + jobs: + - template: templates/jobs/win-ci-vs-2022-job.yml + parameters: + BuildConfig: 'RelWithDebInfo' + EnvSetupScript: setup_env_azure.bat + buildArch: x64 + additionalBuildFlags: --use_azure --use_lock_free_queue + 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: true + MachinePool: 'onnxruntime-Win-CPU-2022' diff --git a/tools/ci_build/github/azure-pipelines/win-gpu-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/win-gpu-ci-pipeline.yml index 8965dd849c32a..8796917afa37d 100644 --- a/tools/ci_build/github/azure-pipelines/win-gpu-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/win-gpu-ci-pipeline.yml @@ -1,3 +1,4 @@ +##### start trigger Don't edit it manually, Please do edit set-trigger-rules.py #### trigger: branches: include: @@ -9,6 +10,8 @@ trigger: - README.md - CONTRIBUTING.md - BUILD.md + - 'js/web' + - 'onnxruntime/core/providers/js' pr: branches: include: @@ -20,6 +23,9 @@ pr: - README.md - CONTRIBUTING.md - BUILD.md + - 'js/web' + - 'onnxruntime/core/providers/js' +#### end trigger #### parameters: - name: RunOnnxRuntimeTests @@ -31,44 +37,43 @@ stages: - stage: cuda dependsOn: [] jobs: - - template: templates/win-ci-vs-2019.yml + - template: templates/jobs/win-ci-vs-2022-job.yml parameters: BuildConfig: 'RelWithDebInfo' EnvSetupScript: setup_env_cuda_11.bat buildArch: x64 - additionalBuildFlags: --enable_pybind --build_java --build_nodejs --use_cuda --cuda_version=11.8 --cuda_home="C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8" --enable_cuda_profiling --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=75 + additionalBuildFlags: --enable_pybind --build_java --build_nodejs --use_cuda --cuda_home="$(Agent.TempDirectory)\v11.8" --enable_cuda_profiling --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=86 msbuildPlatform: x64 isX86: false job_name_suffix: x64_RelWithDebInfo RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} - RunStaticCodeAnalysis: false ORT_EP_NAME: CUDA WITH_CACHE: true - MachinePool: onnxruntime-Win2019-GPU-T4 + MachinePool: onnxruntime-Win2022-GPU-A10 - stage: training dependsOn: [] jobs: - - template: templates/win-ci-vs-2019.yml + - template: templates/jobs/win-ci-vs-2022-job.yml parameters: BuildConfig: 'RelWithDebInfo' EnvSetupScript: setup_env_cuda_11.bat buildArch: x64 - additionalBuildFlags: --enable_pybind --enable_training --use_cuda --cuda_version=11.8 --cuda_home="C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8" --skip_onnx_tests --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=75 + additionalBuildFlags: --enable_pybind --enable_training --use_cuda --cuda_home="$(Agent.TempDirectory)\v11.8" --skip_onnx_tests --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=75 msbuildPlatform: x64 isX86: false job_name_suffix: x64_RelWithDebInfo RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} - RunStaticCodeAnalysis: false ORT_EP_NAME: CUDA WITH_CACHE: true - MachinePool: onnxruntime-Win2019-GPU-training-T4 + # Some unit tests crash on A10 GPUs. So this job still needs to use T4. + MachinePool: onnxruntime-Win2022-GPU-T4 isTraining: true - stage: dml dependsOn: [] jobs: - - template: templates/win-ci-vs-2019.yml + - template: templates/jobs/win-ci-vs-2022-job.yml parameters: BuildConfig: 'RelWithDebInfo' EnvSetupScript: setup_env.bat @@ -78,28 +83,25 @@ stages: isX86: false job_name_suffix: x64_RelWithDebInfo RunOnnxRuntimeTests: ${{ parameters.RunOnnxRuntimeTests }} - RunStaticCodeAnalysis: false ORT_EP_NAME: DML WITH_CACHE: true - # DirectML cannot run on T4 GPUs. - MachinePool: onnxruntime-Win2019-GPU-dml-A10 + MachinePool: onnxruntime-Win2022-GPU-dml-A10 - stage: kernelDocumentation dependsOn: [] jobs: - - template: templates/win-ci-vs-2019.yml + - template: templates/jobs/win-ci-vs-2022-job.yml parameters: BuildConfig: 'RelWithDebInfo' EnvSetupScript: setup_env_cuda_11.bat buildArch: x64 # note: need to specify `--gen_doc` when creating the build config so it has to be in additionalBuildFlags - additionalBuildFlags: --gen_doc validate --skip_tests --enable_pybind --use_dml --use_cuda --cuda_version=11.8 --cuda_home="C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8" --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=75 --cmake_extra_defines onnxruntime_BUILD_UNIT_TESTS=OFF + additionalBuildFlags: --gen_doc validate --skip_tests --enable_pybind --use_dml --use_cuda --cuda_home="$(Agent.TempDirectory)\v11.8" --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=86 --cmake_extra_defines onnxruntime_BUILD_UNIT_TESTS=OFF msbuildPlatform: x64 isX86: false job_name_suffix: x64_RelWithDebInfo RunOnnxRuntimeTests: false - RunStaticCodeAnalysis: false GenerateDocumentation: true ORT_EP_NAME: CUDA # It doesn't really matter which EP is selected here since this stage is for documentation. WITH_CACHE: true - MachinePool: onnxruntime-Win2019-GPU-T4 + MachinePool: onnxruntime-Win2022-GPU-A10 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 f559d537f4ef0..b5db8a5201405 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 @@ -1,6 +1,6 @@ jobs: - job: 'build' - pool: 'Win-GPU-2019' + pool: 'onnxruntime-Win2022-GPU-T4' strategy: maxParallel: 2 matrix: @@ -9,50 +9,47 @@ jobs: minsizerel: BuildConfig: 'MinSizeRel' variables: - OrtPackageId: 'Microsoft.ML.OnnxRuntime' MsbuildArguments: '-detailedsummary -maxcpucount -consoleloggerparameters:PerformanceSummary' - OnnxRuntimeBuildDirectory: '$(Build.BinariesDirectory)' - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true EnvSetupScript: setup_env_cuda_11.bat buildArch: x64 - setVcvars: true + TODAY: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)] timeoutInMinutes: 120 workspace: clean: all steps: - - task: UsePythonVersion@0 - inputs: - versionSpec: '3.8' - addToPath: true - architecture: $(buildArch) + - template: templates/jobs/win-ci-prebuild-steps.yml + parameters: + EnvSetupScript: $(EnvSetupScript) + DownloadCUDA: true + BuildArch: $(buildArch) + BuildConfig: $(BuildConfig) + MachinePool: 'onnxruntime-Win2022-GPU-T4' + WithCache: true + Today: $(Today) - - task: BatchScript@1 - displayName: 'setup env' - inputs: - filename: '$(Build.SourcesDirectory)\tools\ci_build\github\windows\$(EnvSetupScript)' - modifyEnvironment: true - workingFolder: '$(Build.BinariesDirectory)' - - - script: | - python -m pip install -q setuptools wheel numpy flatbuffers - workingDirectory: '$(Build.BinariesDirectory)' - displayName: 'Install python modules' - - - task: PowerShell@2 - displayName: 'Install ONNX' - inputs: - filePath: '$(Build.SourcesDirectory)/tools/ci_build/github/windows/install_third_party_deps.ps1' - workingDirectory: '$(Build.BinariesDirectory)' - arguments: -cpu_arch x64 -install_prefix $(Build.BinariesDirectory)\$(BuildConfig)\installed -build_config $(BuildConfig) + - template: templates/jobs/win-ci-build-steps.yml + parameters: + WithCache: True + Today: $(TODAY) + AdditionalKey: "gpu-reduced-ops | $(BuildConfig)" + BuildPyArguments: '--config $(BuildConfig) --build_dir $(Build.BinariesDirectory) --update --skip_submodule_sync --cmake_generator "Visual Studio 17 2022" --build_wheel --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"' + MsbuildArguments: $(MsbuildArguments) + BuildArch: $(buildArch) + Platform: 'x64' + BuildConfig: $(BuildConfig) - task: PythonScript@0 - displayName: 'Build and test' + displayName: 'Build wheel' inputs: - scriptPath: '$(Build.SourcesDirectory)\tools\ci_build\build.py' - arguments: '--config $(BuildConfig) --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --cmake_generator "Visual Studio 16 2019" --build_wheel --use_cuda --cuda_version=11.6 --cuda_home="C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.6" --cmake_extra_defines CMAKE_SYSTEM_VERSION=10.0.18362.0 "CMAKE_CUDA_ARCHITECTURES=75" --include_ops_by_config="$(Build.SourcesDirectory)\onnxruntime\test\testdata\required_ops.config"' - workingDirectory: '$(Build.BinariesDirectory)' + scriptPath: '$(Build.SourcesDirectory)\setup.py' + arguments: 'bdist_wheel' + workingDirectory: '$(Build.BinariesDirectory)\$(BuildConfig)\$(BuildConfig)' + + - powershell: | + 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 index b46175a80ecfa..15a786516396c 100644 --- 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 @@ -1,74 +1,66 @@ +##### start trigger Don't edit it manually, Please do edit 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: 'build' - pool: 'onnxruntime-tensorrt8-winbuild-T4' + pool: 'onnxruntime-Win2022-GPU-T4' variables: - OrtPackageId: 'Microsoft.ML.OnnxRuntime' MsbuildArguments: '-detailedsummary -maxcpucount -consoleloggerparameters:PerformanceSummary' - OnnxRuntimeBuildDirectory: '$(Build.BinariesDirectory)' - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true EnvSetupScript: setup_env_trt.bat buildArch: x64 - setVcvars: true BuildConfig: 'RelWithDebInfo' - ALLOW_RELEASED_ONNX_OPSET_ONLY: '1' skipComponentGovernanceDetection: true + TODAY: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)] timeoutInMinutes: 150 workspace: clean: all steps: - - task: UsePythonVersion@0 - inputs: - versionSpec: '3.8' - addToPath: true - architecture: $(buildArch) + - template: templates/jobs/win-ci-prebuild-steps.yml + parameters: + EnvSetupScript: $(EnvSetupScript) + DownloadCUDA: true + BuildArch: $(buildArch) + BuildConfig: $(BuildConfig) + MachinePool: 'onnxruntime-Win2022-GPU-T4' + WithCache: true + Today: $(Today) - - task: BatchScript@1 - displayName: 'setup env' - inputs: - filename: '$(Build.SourcesDirectory)\tools\ci_build\github\windows\$(EnvSetupScript)' - modifyEnvironment: true - workingFolder: '$(Build.BinariesDirectory)' - - - script: | - python -m pip install -q setuptools wheel numpy - workingDirectory: '$(Build.BinariesDirectory)' - displayName: 'Install python modules' - - - template: templates/download-deps.yml - - - task: PythonScript@0 - displayName: 'Update deps.txt' - inputs: - scriptPath: $(Build.SourcesDirectory)/tools/ci_build/replace_urls_in_deps.py - arguments: --new_dir $(Build.BinariesDirectory)/deps - workingDirectory: $(Build.BinariesDirectory) - - - task: PowerShell@2 - displayName: 'Install ONNX' - inputs: - filePath: '$(Build.SourcesDirectory)/tools/ci_build/github/windows/install_third_party_deps.ps1' - workingDirectory: '$(Build.BinariesDirectory)' - arguments: -cpu_arch x64 -install_prefix $(Build.BinariesDirectory)\$(BuildConfig)\installed -build_config $(BuildConfig) - - - task: PythonScript@0 - displayName: 'Generate cmake config' - inputs: - scriptPath: '$(Build.SourcesDirectory)\tools\ci_build\build.py' - arguments: '--config $(BuildConfig) --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --build_shared_lib --update --cmake_generator "Visual Studio 16 2019" --build_wheel --enable_onnx_tests --use_tensorrt --tensorrt_home="C:\local\TensorRT-8.6.0.12.Windows10.x86_64.cuda-11.8" --cuda_version=11.6 --cuda_home="C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.6" --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=75' - workingDirectory: '$(Build.BinariesDirectory)' - - - task: VSBuild@1 - displayName: 'Build' - inputs: - solution: '$(Build.BinariesDirectory)\$(BuildConfig)\onnxruntime.sln' - platform: 'x64' - configuration: $(BuildConfig) - msbuildArgs: $(MsbuildArguments) - msbuildArchitecture: $(buildArch) - maximumCpuCount: true - logProjectEvents: false - workingFolder: '$(Build.BinariesDirectory)\$(BuildConfig)' - createLogFile: true + - template: templates/jobs/win-ci-build-steps.yml + parameters: + WithCache: True + Today: $(TODAY) + AdditionalKey: "gpu-tensorrt | $(BuildConfig)" + BuildPyArguments: '--config $(BuildConfig) --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="C:\local\TensorRT-8.6.1.6.Windows10.x86_64.cuda-11.8" --cuda_version=11.8 --cuda_home="$(Agent.TempDirectory)\v11.8" --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=75' + MsbuildArguments: $(MsbuildArguments) + BuildArch: $(buildArch) + Platform: 'x64' + BuildConfig: $(BuildConfig) - task: PythonScript@0 displayName: 'Build wheel' @@ -84,8 +76,7 @@ jobs: del wheel_filename_file python.exe -m pip install -q --upgrade %WHEEL_FILENAME% set PATH=$(Build.BinariesDirectory)\$(BuildConfig)\$(BuildConfig);%PATH% - 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 16 2019" --build_wheel --enable_onnx_tests --use_tensorrt --tensorrt_home="C:\local\TensorRT-8.6.0.12.Windows10.x86_64.cuda-11.8" --cuda_version=11.6 --cuda_home="C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.6" --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=75 + 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_wheel --enable_onnx_tests --use_tensorrt --tensorrt_home="C:\local\TensorRT-8.6.1.6.Windows10.x86_64.cuda-11.8" --cuda_version=11.8 --cuda_home="$(Agent.TempDirectory)\v11.8" --cmake_extra_defines CMAKE_CUDA_ARCHITECTURES=75 workingDirectory: '$(Build.BinariesDirectory)\$(BuildConfig)\$(BuildConfig)' displayName: 'Run tests' - 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 ecf668fef2fb7..b36a25034b19e 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 @@ -1,12 +1,38 @@ +##### start trigger Don't edit it manually, Please do edit 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: QnnSdk displayName: QNN SDK version type: string - default: qnn-v2.8.0.230223123141_52150_win - values: - - qnn-v2.6.0.221227161714_42395_win - - qnn-v2.8.0.230223123141_52150_win + default: qnn-v2.14.1.230828_win jobs: - job: 'build' @@ -44,7 +70,7 @@ jobs: - task: NuGetToolInstaller@1 inputs: versionSpec: 6.4.x - + - task: PythonScript@0 displayName: 'Build' inputs: @@ -58,17 +84,17 @@ jobs: displayName: 'Run unit tests' - script: | - .\$(BuildConfig)\onnx_test_runner -j 1 -c 1 -v -e qnn -i "backend_path|$(QNN_SDK_ROOT)\target\aarch64-windows-msvc\lib\QnnCpu.dll" $(Build.SourcesDirectory)\cmake\external\onnx\onnx\backend\test\data\node + .\$(BuildConfig)\onnx_test_runner -j 1 -c 1 -v -e qnn -i "backend_path|$(QNN_SDK_ROOT)\lib\aarch64-windows-msvc\QnnCpu.dll" $(Build.SourcesDirectory)\cmake\external\onnx\onnx\backend\test\data\node workingDirectory: '$(Build.BinariesDirectory)\$(BuildConfig)' displayName: 'Run ONNX Tests' - script: | - .\$(BuildConfig)\onnx_test_runner -j 1 -c 1 -v -e qnn -i "backend_path|$(QNN_SDK_ROOT)\target\aarch64-windows-msvc\lib\QnnCpu.dll" C:\data\float32_models + .\$(BuildConfig)\onnx_test_runner -j 1 -c 1 -v -e qnn -i "backend_path|$(QNN_SDK_ROOT)\lib\aarch64-windows-msvc\QnnCpu.dll" C:\data\float32_models workingDirectory: '$(Build.BinariesDirectory)\$(BuildConfig)' displayName: 'Run float32 model tests' - script: | - .\$(BuildConfig)\onnx_test_runner -j 1 -c 1 -v -e qnn -i "backend_path|$(QNN_SDK_ROOT)\target\aarch64-windows-msvc\lib\QnnHtp.dll" C:\data\qdq_models + .\$(BuildConfig)\onnx_test_runner -j 1 -c 1 -v -e qnn -i "backend_path|$(QNN_SDK_ROOT)\lib\aarch64-windows-msvc\QnnHtp.dll" C:\data\qdq_models workingDirectory: '$(Build.BinariesDirectory)\$(BuildConfig)' displayName: 'Run QDQ model tests' enabled: false 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 6d2f5f775ea2e..68e0d51480a63 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 @@ -1,12 +1,38 @@ +##### start trigger Don't edit it manually, Please do edit 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: QnnSdk displayName: QNN SDK version type: string - default: qnn-v2.8.0.230223123141_52150_win - values: - - qnn-v2.6.0.221227161714_42395_win - - qnn-v2.8.0.230223123141_52150_win + default: qnn-v2.14.1.230828_win jobs: - job: 'build' @@ -20,7 +46,8 @@ jobs: BuildConfig: 'RelWithDebInfo' ALLOW_RELEASED_ONNX_OPSET_ONLY: '1' QNN_SDK_ROOT: 'C:\data\qnnsdk\${{parameters.QnnSdk}}' - timeoutInMinutes: 150 + TODAY: $[format('{0:dd}{0:MM}{0:yyyy}', pipeline.startTime)] + timeoutInMinutes: 120 workspace: clean: all steps: @@ -31,39 +58,41 @@ jobs: addToPath: true architecture: $(buildArch) - - task: PythonScript@0 - displayName: 'Generate cmake config' - inputs: - scriptPath: '$(Build.SourcesDirectory)\tools\ci_build\build.py' - arguments: '--config $(BuildConfig) --build_dir $(Build.BinariesDirectory) --update --cmake_generator "Visual Studio 17 2022" --use_qnn --qnn_home $(QNN_SDK_ROOT) --parallel' - workingDirectory: '$(Build.BinariesDirectory)' - - - task: VSBuild@1 - displayName: 'Build' - inputs: - solution: '$(Build.BinariesDirectory)\$(BuildConfig)\onnxruntime.sln' - platform: 'x64' - configuration: $(BuildConfig) - msbuildArgs: $(MsbuildArguments) - msbuildArchitecture: $(buildArch) - maximumCpuCount: true - logProjectEvents: false - workingFolder: '$(Build.BinariesDirectory)\$(BuildConfig)' - createLogFile: true + # TODO: Remove --compile_no_warning_as_error once we update from MSVC Runtime library version 14.32 or we + # fix/silence the following warning from the STL header. This warning halts compilation due to + # the /external:templates- option, which allows warnings from external libs for template instantiations. + # Warning is not reported on version 14.35.32215 of the Runtime library. + # + # [warning]C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.32.31326\include\variant(1586,9) + # : Warning C4189: '_Size': local variable is initialized but not referenced + # (compiling source file D:\a\_work\1\s\onnxruntime\core\session\IOBinding.cc) + # + # MSVC\14.32.31326\include\variant(1633): message : see reference to function template instantiation + # '_Ret &std::_Visit_strategy<1>::_Visit2<_Ret,_ListOfIndexVectors,_Callable,const + # std::variant&>(size_t,_Callable &&, + # const std::variant &)' + - template: templates/jobs/win-ci-build-steps.yml + parameters: + WithCache: True + Today: $(TODAY) + AdditionalKey: "win-qnn | $(BuildConfig)" + BuildPyArguments: '--config $(BuildConfig) --build_dir $(Build.BinariesDirectory) --compile_no_warning_as_error --update --cmake_generator "Visual Studio 17 2022" --use_qnn --qnn_home $(QNN_SDK_ROOT) --parallel' + MsbuildArguments: $(MsbuildArguments) + BuildArch: $(buildArch) + Platform: 'x64' + BuildConfig: $(BuildConfig) - powershell: | python $(Build.SourcesDirectory)\tools\ci_build\build.py --config $(BuildConfig) --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --test --cmake_generator "Visual Studio 17 2022" --enable_onnx_tests - workingDirectory: '$(Build.BinariesDirectory)\$(BuildConfig)\$(BuildConfig)' displayName: 'Run unit tests' - script: | - .\$(BuildConfig)\onnx_test_runner -j 1 -c 1 -v -e qnn -i "backend_path|$(QNN_SDK_ROOT)\target\x86_64-windows-msvc\lib\QnnCpu.dll" $(Build.SourcesDirectory)\cmake\external\onnx\onnx\backend\test\data\node + .\$(BuildConfig)\onnx_test_runner -j 1 -c 1 -v -e qnn -i "backend_path|$(QNN_SDK_ROOT)\lib\x86_64-windows-msvc\QnnCpu.dll" $(Build.SourcesDirectory)\cmake\external\onnx\onnx\backend\test\data\node workingDirectory: '$(Build.BinariesDirectory)\$(BuildConfig)' displayName: 'Run ONNX Tests' - script: | - .\$(BuildConfig)\onnx_test_runner -j 1 -c 1 -v -e qnn -i "backend_path|$(QNN_SDK_ROOT)\target\x86_64-windows-msvc\lib\QnnCpu.dll" C:\data\float32_models + .\$(BuildConfig)\onnx_test_runner -j 1 -c 1 -v -e qnn -i "backend_path|$(QNN_SDK_ROOT)\lib\x86_64-windows-msvc\QnnCpu.dll" C:\data\float32_models workingDirectory: '$(Build.BinariesDirectory)\$(BuildConfig)' displayName: 'Run float32 model tests' - diff --git a/tools/ci_build/github/js/pack-npm-packages.ps1 b/tools/ci_build/github/js/pack-npm-packages.ps1 index fb14d456c36ee..64acd7bfc9751 100644 --- a/tools/ci_build/github/js/pack-npm-packages.ps1 +++ b/tools/ci_build/github/js/pack-npm-packages.ps1 @@ -31,7 +31,7 @@ $TARGET=$Args[2] # "node" or "web" or "react_native" Function Generate-Package-Version-Number { pushd $ORT_ROOT - $version_base=Get-Content .\VERSION_NUMBER + $version_base=Get-Content ./VERSION_NUMBER $version_timestamp=git show -s --format=%ct HEAD $version_commit=git rev-parse HEAD $version_commit_short=git rev-parse --short HEAD @@ -51,8 +51,8 @@ Function Generate-Package-Version-Number { return @{ version = $version_number; commit = $version_commit } } -$JS_COMMON_DIR=Join-Path -Path "$ORT_ROOT" -ChildPath "js\common" -$JS_TARGET_DIR=Join-Path -Path "$ORT_ROOT" -ChildPath "js\$TARGET" +$JS_COMMON_DIR=Join-Path -Path "$ORT_ROOT" -ChildPath "js/common" +$JS_TARGET_DIR=Join-Path -Path "$ORT_ROOT" -ChildPath "js/$TARGET" if ($MODE -eq "dev") { # For @dev builds, we compares the following 2 package versions for onnxruntime-common: @@ -73,7 +73,7 @@ if ($MODE -eq "dev") { # download package latest@dev Invoke-WebRequest $ort_common_latest_dist_tarball -OutFile ./latest.tgz - if ($(Get-FileHash -Algorithm SHA1 .\latest.tgz).Hash -ne "$ort_common_latest_dist_shasum") { + if ($(Get-FileHash -Algorithm SHA1 ./latest.tgz).Hash -ne "$ort_common_latest_dist_shasum") { throw "SHASUM mismatch" } Write-Host "Tarball downloaded" @@ -85,6 +85,11 @@ if ($MODE -eq "dev") { pushd $JS_COMMON_DIR npm version --allow-same-version $ort_common_latest_version echo $($version_number.commit) | Out-File -Encoding ascii -NoNewline -FilePath ./__commit.txt + # update version.ts of common + pushd .. + npm run update-version common + npm run format + popd npm pack popd @@ -114,8 +119,8 @@ if ($MODE -eq "dev") { npm install "dir-compare-cli@1.0.1" "json-diff@0.5.4" Write-Host "Compare package.json" - $latest_package_json=Join-Path -Path ".." -ChildPath "latest\package\package.json" - $current_package_json=Join-Path -Path ".." -ChildPath "current\package\package.json" + $latest_package_json=Join-Path -Path ".." -ChildPath "latest/package/package.json" + $current_package_json=Join-Path -Path ".." -ChildPath "current/package/package.json" npx json-diff $latest_package_json $current_package_json $use_latest=$? Write-Host "Result: $use_latest" @@ -123,8 +128,8 @@ if ($MODE -eq "dev") { # package.json matches. now check package contents. # do not compare commit number - $latest_package_commit=Join-Path -Path ".." -ChildPath "latest\package\__commit.txt" - $current_package_commit=Join-Path -Path ".." -ChildPath "current\package\__commit.txt" + $latest_package_commit=Join-Path -Path ".." -ChildPath "latest/package/__commit.txt" + $current_package_commit=Join-Path -Path ".." -ChildPath "current/package/__commit.txt" if (test-path $latest_package_commit) { rm $latest_package_commit } if (test-path $current_package_commit) { rm $current_package_commit } # skip package.json, we already checked them @@ -132,8 +137,8 @@ if ($MODE -eq "dev") { rm $current_package_json Write-Host "Compare package contents" - $latest_package_dir=Join-Path -Path ".." -ChildPath "latest\package" - $current_package_dir=Join-Path -Path ".." -ChildPath "current\package" + $latest_package_dir=Join-Path -Path ".." -ChildPath "latest/package" + $current_package_dir=Join-Path -Path ".." -ChildPath "current/package" npx dircompare -c $latest_package_dir $current_package_dir $use_latest=$? Write-Host "Result: $use_latest" @@ -147,6 +152,13 @@ if ($MODE -eq "dev") { pushd $JS_COMMON_DIR npm version --allow-same-version $($version_number.version) # file __commit.txt is already generated + + # update version.ts of common + pushd .. + npm run update-version common + npm run format + popd + npm pack popd } @@ -155,6 +167,13 @@ if ($MODE -eq "dev") { pushd $JS_TARGET_DIR npm version --allow-same-version $($version_number.version) echo $($version_number.commit) | Out-File -Encoding ascii -NoNewline -FilePath ./__commit.txt + + # update version.ts of TARGET + pushd .. + npm run update-version $TARGET + npm run format + popd + npm pack popd } elseif ($MODE -eq "release") { @@ -171,11 +190,25 @@ if ($MODE -eq "dev") { pushd $JS_COMMON_DIR npm version --allow-same-version $($version_number.version) + + # update version.ts of common + pushd .. + npm run update-version common + npm run format + popd + npm pack popd pushd $JS_TARGET_DIR npm version --allow-same-version $($version_number.version) + + # update version.ts of TARGET + pushd .. + npm run update-version $TARGET + npm run format + popd + npm pack popd } diff --git a/tools/ci_build/github/js/react_native_e2e_full_ios_framework_build_settings.json b/tools/ci_build/github/js/react_native_e2e_full_ios_framework_build_settings.json index 88d10b5f56701..d15326de41099 100644 --- a/tools/ci_build/github/js/react_native_e2e_full_ios_framework_build_settings.json +++ b/tools/ci_build/github/js/react_native_e2e_full_ios_framework_build_settings.json @@ -11,6 +11,6 @@ "--build_apple_framework", "--use_coreml", "--skip_tests", - "--apple_deploy_target=11.0" + "--apple_deploy_target=12.0" ] } diff --git a/tools/ci_build/github/js/react_native_e2e_mobile_ios_framework_build_settings.json b/tools/ci_build/github/js/react_native_e2e_mobile_ios_framework_build_settings.json index c2f1519ac0ffb..e733885399f72 100644 --- a/tools/ci_build/github/js/react_native_e2e_mobile_ios_framework_build_settings.json +++ b/tools/ci_build/github/js/react_native_e2e_mobile_ios_framework_build_settings.json @@ -16,6 +16,6 @@ "--enable_reduced_operator_type_support", "--use_coreml", "--skip_tests", - "--apple_deploy_target=11.0" + "--apple_deploy_target=12.0" ] } diff --git a/tools/ci_build/github/js/validate-npm-packages.py b/tools/ci_build/github/js/validate-npm-packages.py index f2118e825e8e9..b009330764973 100644 --- a/tools/ci_build/github/js/validate-npm-packages.py +++ b/tools/ci_build/github/js/validate-npm-packages.py @@ -110,7 +110,7 @@ print("====== output environment variables ======") print(f"##vso[task.setvariable variable=ORT_COMMON_FROM]{ort_common_from}") -if tag == "latest" or tag == "" or tag == "rc": # noqa: PLC1901 +if tag == "latest" or tag == "" or tag == "rc": if not RELEASE_NODE or not RELEASE_WEB or not RELEASE_REACT_NATIVE: raise Exception("@latest or @rc build must release all packages (node, web, react-native)") if count_ort_node_common_tgz != 1: @@ -137,7 +137,7 @@ print(f"ort_web_ver={ort_web_ver}") print(f"ort_react_native_ver={ort_react_native_ver}") -if tag == "latest" or tag == "": # noqa: PLC1901 +if tag == "latest" or tag == "": print("Publishing @latest ...") if not source_branch.startswith("refs/heads/rel-"): raise Exception('@latest build must publish from source branch "refs/heads/rel-*"') @@ -164,5 +164,5 @@ and "+" not in ort_web_ver.replace("-rev", "") and "+" not in ort_react_native_ver.replace("-rev", "") ): - if tag != "latest" and tag != "": # noqa: PLC1901 + if tag != "latest" and tag != "": raise Exception("default version without decorator can only be published in @latest tag") diff --git a/tools/ci_build/github/linux/build_cuda_c_api_package.sh b/tools/ci_build/github/linux/build_cuda_c_api_package.sh index 271f010a9d1c2..5cd1c8c243050 100755 --- a/tools/ci_build/github/linux/build_cuda_c_api_package.sh +++ b/tools/ci_build/github/linux/build_cuda_c_api_package.sh @@ -1,10 +1,11 @@ #!/bin/bash +set -e -x export CFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all" export CXXFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all" docker run --gpus all -e CFLAGS -e CXXFLAGS -e NVIDIA_VISIBLE_DEVICES=all --rm --volume \ $BUILD_SOURCESDIRECTORY:/onnxruntime_src --volume $BUILD_BINARIESDIRECTORY:/build \ --volume /data/models:/build/models:ro --volume /data/onnx:/data/onnx:ro -e NIGHTLY_BUILD onnxruntimecuda11centosbuild \ -python3 /onnxruntime_src/tools/ci_build/build.py --build_java --build_dir /build --config Release \ +/usr/bin/python3.9 /onnxruntime_src/tools/ci_build/build.py --build_java --build_nodejs --build_dir /build --config Release \ --skip_submodule_sync --parallel --build_shared_lib --use_cuda --cuda_version=$CUDA_VERSION \ --cuda_home=/usr/local/cuda-$CUDA_VERSION --cudnn_home=/usr/local/cuda-$CUDA_VERSION \ ---cmake_extra_defines 'CMAKE_CUDA_ARCHITECTURES=52;60;61;70;75;80' +--cmake_extra_defines 'CMAKE_CUDA_ARCHITECTURES=60;61;70;75;80' diff --git a/tools/ci_build/github/linux/build_linux_arm64_python_package.sh b/tools/ci_build/github/linux/build_linux_arm64_python_package.sh index 88ac111fd8100..516f320cd64c4 100755 --- a/tools/ci_build/github/linux/build_linux_arm64_python_package.sh +++ b/tools/ci_build/github/linux/build_linux_arm64_python_package.sh @@ -1,22 +1,37 @@ #!/bin/bash set -e -x + +# This script invokes build.py + mkdir -p /build/dist -CFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -O3 -pipe -Wl,--strip-all" -CXXFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -O3 -pipe -Wl,--strip-all" +EXTRA_ARG="" -BUILD_DEVICE="CPU" -BUILD_CONFIG="Release" -PYTHON_EXES=("/opt/python/cp38-cp38/bin/python3.8" "/opt/python/cp39-cp39/bin/python3.9" "/opt/python/cp310-cp310/bin/python3.10" "/opt/python/cp311-cp311/bin/python3.11") -while getopts "d:p:" parameter_Option +# Put 3.8 at the last because Ubuntu 20.04 use python 3.8 and we will upload the intermediate build files of this +# config to Azure DevOps Artifacts and download them to a Ubuntu 20.04 machine to run the tests. +PYTHON_EXES=("/opt/python/cp39-cp39/bin/python3.9" "/opt/python/cp310-cp310/bin/python3.10" "/opt/python/cp311-cp311/bin/python3.11" "/opt/python/cp38-cp38/bin/python3.8") +while getopts "d:p:x:c:" parameter_Option do case "${parameter_Option}" in #GPU or CPU. d) BUILD_DEVICE=${OPTARG};; p) PYTHON_EXES=(${OPTARG});; +x) EXTRA_ARG=(${OPTARG});; +c) BUILD_CONFIG=${OPTARG};; esac done +BUILD_ARGS=("--build_dir" "/build" "--config" "$BUILD_CONFIG" "--update" "--build" "--skip_submodule_sync" "--parallel" "--build_wheel") + +if [ "$BUILD_CONFIG" == "Debug" ]; then + CFLAGS="-ggdb3" + CXXFLAGS="-ggdb3" +else + CFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -O3 -pipe -Wl,--strip-all" + CXXFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -O3 -pipe -Wl,--strip-all" + BUILD_ARGS+=("--enable_lto") +fi + # Depending on how the compiler has been configured when it was built, sometimes "gcc -dumpversion" shows the full version. GCC_VERSION=$(gcc -dumpversion | cut -d . -f 1) #-fstack-clash-protection prevents attacks based on an overlapping heap and stack. @@ -32,8 +47,12 @@ if [ "$ARCH" == "x86_64" ] && [ "$GCC_VERSION" -ge 9 ]; then CXXFLAGS="$CXXFLAGS -fcf-protection" fi +echo "EXTRA_ARG:" +echo $EXTRA_ARG -BUILD_ARGS=("--build_dir" "/build" "--config" "$BUILD_CONFIG" "--update" "--build" "--skip_submodule_sync" "--parallel" "--enable_lto" "--build_wheel") +if [ "$EXTRA_ARG" != "" ]; then + BUILD_ARGS+=("$EXTRA_ARG") +fi if [ "$ARCH" == "x86_64" ]; then #ARM build machines do not have the test data yet. @@ -43,16 +62,7 @@ fi if [ "$BUILD_DEVICE" == "GPU" ]; then #Enable CUDA and TRT EPs. ONNXRUNTIME_CUDA_VERSION="11.8" - BUILD_ARGS+=("--use_cuda" "--use_tensorrt" "--cuda_version=$ONNXRUNTIME_CUDA_VERSION" "--tensorrt_home=/usr" "--cuda_home=/usr/local/cuda-$ONNXRUNTIME_CUDA_VERSION" "--cudnn_home=/usr/local/cuda-$ONNXRUNTIME_CUDA_VERSION" "--cmake_extra_defines" "CMAKE_CUDA_ARCHITECTURES=52;60;61;70;75;80") -elif [ "$BUILD_DEVICE" == "AZURE" ]; then - BUILD_ARGS+=("--use_azure") - if [ -f /etc/lsb-release ]; then - # for ubuntu - apt-get install -y libipc-system-simple-perl python3 libssl-dev - else - # for redhat - yum install -y perl-IPC-Cmd python3 openssl-devel - fi + BUILD_ARGS+=("--nvcc_threads=1" "--use_cuda" "--use_tensorrt" "--cuda_version=$ONNXRUNTIME_CUDA_VERSION" "--tensorrt_home=/usr" "--cuda_home=/usr/local/cuda-$ONNXRUNTIME_CUDA_VERSION" "--cudnn_home=/usr/local/cuda-$ONNXRUNTIME_CUDA_VERSION" "--cmake_extra_defines" "CMAKE_CUDA_ARCHITECTURES=52;60;61;70;75;80") fi export CFLAGS diff --git a/tools/ci_build/github/linux/build_rocm_c_api_package.sh b/tools/ci_build/github/linux/build_rocm_c_api_package.sh new file mode 100755 index 0000000000000..957f1f8a812a5 --- /dev/null +++ b/tools/ci_build/github/linux/build_rocm_c_api_package.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +set -e -u -x + +usage() { echo "Usage: $0 -S -B -V [-H ] " 1>&2; exit 1; } + +ROCM_HOME=/opt/rocm + +while getopts S:B:V:H:I:P: parameter_Option; do + case "${parameter_Option}" in + S) SOURCE_DIR=${OPTARG};; + B) BINARY_DIR=${OPTARG};; + V) ROCM_VERSION=${OPTARG};; + H) ROCM_HOME=${OPTARG};; + I) IMAGE=${OPTARG};; + P) PYTHON_BIN=${OPTARG};; + *) usage ;; + esac +done + +EXIT_CODE=1 + +docker run --rm \ + --security-opt seccomp=unconfined \ + --shm-size=1024m \ + --user $UID:$(id -g $USER) \ + -e CFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all" \ + -e CXXFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all" \ + -e NIGHTLY_BUILD \ + --volume $SOURCE_DIR:/onnxruntime_src \ + --volume $BINARY_DIR:/build \ + --volume /data/models:/build/models:ro \ + --volume /data/onnx:/data/onnx:ro \ + --workdir /onnxruntime_src \ + $IMAGE \ + ${PYTHON_BIN:-python} /onnxruntime_src/tools/ci_build/build.py \ + --config Release \ + --build_dir /build \ + --parallel \ + --use_rocm --rocm_version=$ROCM_VERSION --rocm_home $ROCM_HOME --nccl_home $ROCM_HOME \ + --build_shared_lib \ + --skip_submodule_sync \ + --skip_tests --cmake_extra_defines FETCHCONTENT_TRY_FIND_PACKAGE_MODE=NEVER + + +EXIT_CODE=$? + +set -e +exit $EXIT_CODE diff --git a/tools/ci_build/github/linux/build_tensorrt_c_api_package.sh b/tools/ci_build/github/linux/build_tensorrt_c_api_package.sh new file mode 100755 index 0000000000000..18a32e3599391 --- /dev/null +++ b/tools/ci_build/github/linux/build_tensorrt_c_api_package.sh @@ -0,0 +1,9 @@ +#!/bin/bash +set -e -x +export CFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all" +export CXXFLAGS="-Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -fstack-clash-protection -fcf-protection -O3 -Wl,--strip-all" +mkdir -p $HOME/.onnx +docker run --gpus all -e CFLAGS -e CXXFLAGS -e NVIDIA_VISIBLE_DEVICES=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 -e NIGHTLY_BUILD onnxruntimecuda118xtrt86build \ +/opt/python/cp38-cp38/bin/python3 /onnxruntime_src/tools/ci_build/build.py --build_dir /build --config Release \ +--skip_submodule_sync --parallel --build_shared_lib --build_java --build_nodejs --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;61;70;75;80' diff --git a/tools/ci_build/github/linux/copy_strip_binary.sh b/tools/ci_build/github/linux/copy_strip_binary.sh index da86205b52f61..63690b69fc91a 100755 --- a/tools/ci_build/github/linux/copy_strip_binary.sh +++ b/tools/ci_build/github/linux/copy_strip_binary.sh @@ -29,6 +29,10 @@ if [[ -f "$BINARY_DIR/$BUILD_CONFIG/libonnxruntime_providers_tensorrt.so" ]]; th cp $BINARY_DIR/$BUILD_CONFIG/libonnxruntime_providers_tensorrt.so $BINARY_DIR/$ARTIFACT_NAME/lib cp $SOURCE_DIR/include/onnxruntime/core/providers/tensorrt/tensorrt_provider_factory.h $BINARY_DIR/$ARTIFACT_NAME/include fi +if [[ -f "$BINARY_DIR/$BUILD_CONFIG/libonnxruntime_providers_rocm.so" ]]; then + cp $BINARY_DIR/$BUILD_CONFIG/libonnxruntime_providers_shared.so $BINARY_DIR/$ARTIFACT_NAME/lib + cp $BINARY_DIR/$BUILD_CONFIG/libonnxruntime_providers_rocm.so $BINARY_DIR/$ARTIFACT_NAME/lib +fi echo "Copy debug symbols in a separate file and strip the original binary." if [[ $LIB_NAME == *.dylib ]] then @@ -44,10 +48,14 @@ fi cp $SOURCE_DIR/include/onnxruntime/core/session/onnxruntime_c_api.h $BINARY_DIR/$ARTIFACT_NAME/include cp $SOURCE_DIR/include/onnxruntime/core/session/onnxruntime_cxx_api.h $BINARY_DIR/$ARTIFACT_NAME/include cp $SOURCE_DIR/include/onnxruntime/core/session/onnxruntime_cxx_inline.h $BINARY_DIR/$ARTIFACT_NAME/include +cp $SOURCE_DIR/include/onnxruntime/core/session/onnxruntime_float16.h $BINARY_DIR/$ARTIFACT_NAME/include cp $SOURCE_DIR/include/onnxruntime/core/providers/cpu/cpu_provider_factory.h $BINARY_DIR/$ARTIFACT_NAME/include cp $SOURCE_DIR/include/onnxruntime/core/session/onnxruntime_session_options_config_keys.h $BINARY_DIR/$ARTIFACT_NAME/include cp $SOURCE_DIR/include/onnxruntime/core/session/onnxruntime_run_options_config_keys.h $BINARY_DIR/$ARTIFACT_NAME/include cp $SOURCE_DIR/include/onnxruntime/core/framework/provider_options.h $BINARY_DIR/$ARTIFACT_NAME/include +cp $SOURCE_DIR/orttraining/orttraining/training_api/include/onnxruntime_training_c_api.h $BINARY_DIR/$ARTIFACT_NAME/include +cp $SOURCE_DIR/orttraining/orttraining/training_api/include/onnxruntime_training_cxx_api.h $BINARY_DIR/$ARTIFACT_NAME/include +cp $SOURCE_DIR/orttraining/orttraining/training_api/include/onnxruntime_training_cxx_inline.h $BINARY_DIR/$ARTIFACT_NAME/include # copy the README, licence and TPN cp $SOURCE_DIR/README.md $BINARY_DIR/$ARTIFACT_NAME/README.md diff --git a/tools/ci_build/github/linux/docker/Dockerfile.arm_yocto b/tools/ci_build/github/linux/docker/Dockerfile.arm_yocto deleted file mode 100644 index 93a5d282ef367..0000000000000 --- a/tools/ci_build/github/linux/docker/Dockerfile.arm_yocto +++ /dev/null @@ -1,21 +0,0 @@ -ARG OS_VERSION=20.04 -FROM ubuntu:${OS_VERSION} - -RUN apt-get update && apt-get install -y --no-install-recommends gawk wget git-core diffstat unzip vim \ - texinfo gcc-multilib build-essential chrpath socat libsdl1.2-dev python3-dev sudo cpio file ca-certificates bc locales \ - libsdl1.2-dev xterm sed cvs subversion coreutils texi2html docbook-utils python-pysqlite2 help2man gcc \ - g++ make desktop-file-utils libgl1-mesa-dev libglu1-mesa-dev \ - mercurial autoconf automake groff curl lzop asciidoc u-boot-tools - -RUN locale-gen en_US.UTF-8 - -ENV LC_ALL=en_US.UTF-8 -ENV LANG=en_US.UTF-8 - -ARG BUILD_UID=1000 -ARG BUILD_USER=ubuntu -RUN adduser --gecos 'yocto build user' --disabled-password $BUILD_USER --uid $BUILD_UID && \ - usermod -aG sudo ubuntu - -USER $BUILD_USER - diff --git a/tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_cpu b/tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_cpu deleted file mode 100644 index 033afde6aa93c..0000000000000 --- a/tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_cpu +++ /dev/null @@ -1,167 +0,0 @@ -ARG BASEIMAGE=centos:7 -ARG POLICY=manylinux2014 -ARG PLATFORM=x86_64 -ARG DEVTOOLSET_ROOTPATH=/opt/rh/devtoolset-11/root -ARG LD_LIBRARY_PATH_ARG=/opt/rh/devtoolset-11/root/usr/lib64:/opt/rh/devtoolset-11/root/usr/lib:/opt/rh/devtoolset-11/root/usr/lib64/dyninst:/opt/rh/devtoolset-11/root/usr/lib/dyninst:/usr/local/lib64 -ARG PREPEND_PATH=/opt/rh/devtoolset-11/root/usr/bin: - -#Build manylinux2014 docker image begin -FROM $BASEIMAGE AS runtime_base -ARG POLICY -ARG PLATFORM -ARG DEVTOOLSET_ROOTPATH -ARG LD_LIBRARY_PATH_ARG -ARG PREPEND_PATH -LABEL maintainer="The ManyLinux project" - -ENV AUDITWHEEL_POLICY=${POLICY} AUDITWHEEL_ARCH=${PLATFORM} AUDITWHEEL_PLAT=${POLICY}_${PLATFORM} -ENV LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 LANGUAGE=en_US.UTF-8 -ENV DEVTOOLSET_ROOTPATH=${DEVTOOLSET_ROOTPATH} -ENV LD_LIBRARY_PATH=${LD_LIBRARY_PATH_ARG} -ENV PATH=${PREPEND_PATH}${PATH} -ENV PKG_CONFIG_PATH=/usr/local/lib/pkgconfig - -# first copy the fixup mirrors script, keep the script around -COPY build_scripts/fixup-mirrors.sh /usr/local/sbin/fixup-mirrors - -# setup entrypoint, this will wrap commands with `linux32` with i686 images -COPY build_scripts/install-entrypoint.sh \ - build_scripts/update-system-packages.sh \ - build_scripts/build_utils.sh \ - /build_scripts/ - -RUN /build_scripts/install-entrypoint.sh && rm -rf /build_scripts -COPY manylinux-entrypoint /usr/local/bin/manylinux-entrypoint -ENTRYPOINT ["manylinux-entrypoint"] - -COPY build_scripts/install-runtime-packages.sh \ - build_scripts/update-system-packages.sh \ - build_scripts/build_utils.sh \ - /build_scripts/ -RUN manylinux-entrypoint /build_scripts/install-runtime-packages.sh && rm -rf /build_scripts/ - -COPY build_scripts/build_utils.sh /build_scripts/ - -COPY build_scripts/install-autoconf.sh /build_scripts/ -RUN export AUTOCONF_ROOT=autoconf-2.71 && \ - export AUTOCONF_HASH=431075ad0bf529ef13cb41e9042c542381103e80015686222b8a9d4abef42a1c && \ - export AUTOCONF_DOWNLOAD_URL=http://ftp.gnu.org/gnu/autoconf && \ - manylinux-entrypoint /build_scripts/install-autoconf.sh - -COPY build_scripts/install-automake.sh /build_scripts/ -RUN export AUTOMAKE_ROOT=automake-1.16.5 && \ - export AUTOMAKE_HASH=07bd24ad08a64bc17250ce09ec56e921d6343903943e99ccf63bbf0705e34605 && \ - export AUTOMAKE_DOWNLOAD_URL=http://ftp.gnu.org/gnu/automake && \ - manylinux-entrypoint /build_scripts/install-automake.sh - -COPY build_scripts/install-libtool.sh /build_scripts/ -RUN export LIBTOOL_ROOT=libtool-2.4.7 && \ - export LIBTOOL_HASH=04e96c2404ea70c590c546eba4202a4e12722c640016c12b9b2f1ce3d481e9a8 && \ - export LIBTOOL_DOWNLOAD_URL=http://ftp.gnu.org/gnu/libtool && \ - manylinux-entrypoint /build_scripts/install-libtool.sh - -COPY build_scripts/install-libxcrypt.sh /build_scripts/ -RUN export LIBXCRYPT_VERSION=4.4.28 && \ - export LIBXCRYPT_HASH=db7e37901969cb1d1e8020cb73a991ef81e48e31ea5b76a101862c806426b457 && \ - export LIBXCRYPT_DOWNLOAD_URL=https://github.com/besser82/libxcrypt/archive && \ - export PERL_ROOT=perl-5.34.0 && \ - export PERL_HASH=551efc818b968b05216024fb0b727ef2ad4c100f8cb6b43fab615fa78ae5be9a && \ - export PERL_DOWNLOAD_URL=https://www.cpan.org/src/5.0 && \ - manylinux-entrypoint /build_scripts/install-libxcrypt.sh - -FROM runtime_base AS build_base -COPY build_scripts/install-build-packages.sh /build_scripts/ -RUN manylinux-entrypoint /build_scripts/install-build-packages.sh - - -FROM build_base AS build_git -COPY build_scripts/build-git.sh /build_scripts/ -RUN export GIT_ROOT=git-2.36.2 && \ - export GIT_HASH=6dc2cdea5fb23d823ba4871cc23222c1db31dfbb6d6c6ff74c4128700df57c68 && \ - export GIT_DOWNLOAD_URL=https://www.kernel.org/pub/software/scm/git && \ - manylinux-entrypoint /build_scripts/build-git.sh - - -FROM build_base AS build_cpython -COPY build_scripts/build-sqlite3.sh /build_scripts/ -RUN export SQLITE_AUTOCONF_ROOT=sqlite-autoconf-3390200 && \ - export SQLITE_AUTOCONF_HASH=852be8a6183a17ba47cee0bbff7400b7aa5affd283bf3beefc34fcd088a239de && \ - export SQLITE_AUTOCONF_DOWNLOAD_URL=https://www.sqlite.org/2022 && \ - manylinux-entrypoint /build_scripts/build-sqlite3.sh - -COPY build_scripts/build-openssl.sh /build_scripts/ -RUN export OPENSSL_ROOT=openssl-1.1.1q && \ - export OPENSSL_HASH=d7939ce614029cdff0b6c20f0e2e5703158a489a72b2507b8bd51bf8c8fd10ca && \ - export OPENSSL_DOWNLOAD_URL=https://www.openssl.org/source && \ - manylinux-entrypoint /build_scripts/build-openssl.sh - -COPY build_scripts/build-cpython.sh /build_scripts/ - - - - -FROM build_cpython AS build_cpython38 -COPY build_scripts/ambv-pubkey.txt /build_scripts/cpython-pubkeys.txt -RUN manylinux-entrypoint /build_scripts/build-cpython.sh 3.8.13 - - -FROM build_cpython AS build_cpython39 -COPY build_scripts/ambv-pubkey.txt /build_scripts/cpython-pubkeys.txt -RUN manylinux-entrypoint /build_scripts/build-cpython.sh 3.9.13 - - -FROM build_cpython AS build_cpython310 -COPY build_scripts/cpython-pubkey-310-311.txt /build_scripts/cpython-pubkeys.txt -RUN manylinux-entrypoint /build_scripts/build-cpython.sh 3.10.5 - -FROM build_cpython AS build_cpython311 -COPY build_scripts/cpython-pubkey-310-311.txt /build_scripts/cpython-pubkeys.txt -RUN manylinux-entrypoint /build_scripts/build-cpython.sh 3.11.2 - -FROM build_cpython AS all_python -COPY build_scripts/install-pypy.sh \ - build_scripts/pypy.sha256 \ - build_scripts/finalize-python.sh \ - /build_scripts/ -RUN manylinux-entrypoint /build_scripts/install-pypy.sh 3.8 7.3.9 -RUN manylinux-entrypoint /build_scripts/install-pypy.sh 3.9 7.3.9 -COPY --from=build_cpython38 /opt/_internal /opt/_internal/ -COPY --from=build_cpython39 /opt/_internal /opt/_internal/ -COPY --from=build_cpython310 /opt/_internal /opt/_internal/ -COPY --from=build_cpython311 /opt/_internal /opt/_internal/ -RUN manylinux-entrypoint /build_scripts/finalize-python.sh - - -FROM runtime_base -COPY --from=build_git /manylinux-rootfs / -COPY --from=build_cpython /manylinux-rootfs / -COPY --from=all_python /opt/_internal /opt/_internal/ -COPY build_scripts/finalize.sh \ - build_scripts/update-system-packages.sh \ - build_scripts/python-tag-abi-tag.py \ - - build_scripts/requirements3.8.txt \ - build_scripts/requirements3.9.txt \ - build_scripts/requirements3.10.txt \ - build_scripts/requirements3.11.txt \ - build_scripts/requirements-base-tools.txt \ - /build_scripts/ -COPY build_scripts/requirements-tools/* /build_scripts/requirements-tools/ -RUN manylinux-entrypoint /build_scripts/finalize.sh && rm -rf /build_scripts - -ENV SSL_CERT_FILE=/opt/_internal/certs.pem - -CMD ["/bin/bash"] - -#Build manylinux2014 docker image end - -ENV PATH /opt/rh/devtoolset-11/root/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin - -ADD scripts /tmp/scripts -RUN cd /tmp/scripts && /tmp/scripts/manylinux/install_centos.sh && /tmp/scripts/manylinux/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/Dockerfile.manylinux2014_eager_cpu b/tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_eager_cpu deleted file mode 100644 index 036054903752a..0000000000000 --- a/tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_eager_cpu +++ /dev/null @@ -1,11 +0,0 @@ -FROM quay.io/pypa/manylinux2014_x86_64:latest - -ADD scripts /tmp/scripts -RUN cd /tmp/scripts && /tmp/scripts/manylinux/install_centos.sh && /tmp/scripts/manylinux/install_deps_eager.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/Dockerfile.manylinux_2_27_cpu b/tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cpu similarity index 89% rename from tools/ci_build/github/linux/docker/Dockerfile.manylinux_2_27_cpu rename to tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cpu index bcde8808d81ac..af87852561e0a 100644 --- a/tools/ci_build/github/linux/docker/Dockerfile.manylinux_2_27_cpu +++ b/tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cpu @@ -1,10 +1,9 @@ -ARG BASEIMAGE=ubuntu:18.04 -ARG POLICY=manylinux_2_27 +ARG BASEIMAGE=registry.access.redhat.com/ubi8/ubi +ARG POLICY=manylinux_2_28 ARG PLATFORM=x86_64 -ARG DEVTOOLSET_ROOTPATH= -ARG LD_LIBRARY_PATH_ARG= -ARG PREPEND_PATH= - +ARG DEVTOOLSET_ROOTPATH=/opt/rh/gcc-toolset-12/root +ARG LD_LIBRARY_PATH_ARG=${DEVTOOLSET_ROOTPATH}/usr/lib64:${DEVTOOLSET_ROOTPATH}/usr/lib:${DEVTOOLSET_ROOTPATH}/usr/lib64/dyninst:${DEVTOOLSET_ROOTPATH}/usr/lib/dyninst:/usr/local/lib64 +ARG PREPEND_PATH=/usr/lib/jvm/msopenjdk-11/bin:${DEVTOOLSET_ROOTPATH}/usr/bin: #Build manylinux2014 docker image begin FROM $BASEIMAGE AS runtime_base @@ -27,7 +26,6 @@ COPY build_scripts/fixup-mirrors.sh /usr/local/sbin/fixup-mirrors # setup entrypoint, this will wrap commands with `linux32` with i686 images COPY build_scripts/install-entrypoint.sh \ - build_scripts/update-system-packages.sh \ build_scripts/build_utils.sh \ /build_scripts/ @@ -36,7 +34,6 @@ COPY manylinux-entrypoint /usr/local/bin/manylinux-entrypoint ENTRYPOINT ["manylinux-entrypoint"] COPY build_scripts/install-runtime-packages.sh \ - build_scripts/update-system-packages.sh \ build_scripts/build_utils.sh \ /build_scripts/ RUN manylinux-entrypoint /build_scripts/install-runtime-packages.sh && rm -rf /build_scripts/ @@ -99,6 +96,8 @@ RUN export OPENSSL_ROOT=openssl-1.1.1q && \ COPY build_scripts/build-cpython.sh /build_scripts/ + + FROM build_cpython AS build_cpython38 COPY build_scripts/ambv-pubkey.txt /build_scripts/cpython-pubkeys.txt RUN manylinux-entrypoint /build_scripts/build-cpython.sh 3.8.13 @@ -136,7 +135,6 @@ COPY --from=build_git /manylinux-rootfs / COPY --from=build_cpython /manylinux-rootfs / COPY --from=all_python /opt/_internal /opt/_internal/ COPY build_scripts/finalize.sh \ - build_scripts/update-system-packages.sh \ build_scripts/python-tag-abi-tag.py \ build_scripts/requirements3.8.txt \ build_scripts/requirements3.9.txt \ @@ -151,16 +149,17 @@ ENV SSL_CERT_FILE=/opt/_internal/certs.pem CMD ["/bin/bash"] -#Build manylinux_2_27 docker image end +#Build manylinux2014 docker image end + +ENV PATH ${DEVTOOLSET_ROOTPATH}/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +ENV JAVA_HOME=/usr/lib/jvm/msopenjdk-11 -#Add our own dependencies ADD scripts /tmp/scripts -RUN chmod +x /tmp/scripts/manylinux/install_ubuntuos.sh -RUN cd /tmp/scripts && /tmp/scripts/manylinux/install_ubuntuos.sh && /tmp/scripts/manylinux/install_deps.sh && rm -rf /tmp/scripts +RUN cd /tmp/scripts && /tmp/scripts/manylinux/install_centos.sh +RUN cd /tmp/scripts && /tmp/scripts/manylinux/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 -ENV PATH /usr/local/dotnet:$PATH diff --git a/tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_cuda11 b/tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda11 similarity index 96% rename from tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_cuda11 rename to tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda11 index dc52fb51d6389..933b0211b0e6c 100644 --- a/tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_cuda11 +++ b/tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda11 @@ -1,5 +1,5 @@ -ARG BASEIMAGE=nvidia/cuda:11.4.2-cudnn8-devel-centos7 -ARG POLICY=manylinux2014 +ARG BASEIMAGE=nvidia/cuda:11.8.0-cudnn8-devel-ubi8 +ARG POLICY=manylinux_2_28 ARG PLATFORM=x86_64 ARG DEVTOOLSET_ROOTPATH= ARG LD_LIBRARY_PATH_ARG= @@ -31,7 +31,6 @@ COPY build_scripts/fixup-mirrors.sh /usr/local/sbin/fixup-mirrors # setup entrypoint, this will wrap commands with `linux32` with i686 images COPY build_scripts/install-entrypoint.sh \ - build_scripts/update-system-packages.sh \ build_scripts/build_utils.sh \ /build_scripts/ @@ -40,7 +39,6 @@ COPY manylinux-entrypoint /usr/local/bin/manylinux-entrypoint ENTRYPOINT ["manylinux-entrypoint"] COPY build_scripts/install-runtime-packages.sh \ - build_scripts/update-system-packages.sh \ build_scripts/build_utils.sh \ /build_scripts/ RUN manylinux-entrypoint /build_scripts/install-runtime-packages.sh && rm -rf /build_scripts/ @@ -140,7 +138,6 @@ COPY --from=build_git /manylinux-rootfs / COPY --from=build_cpython /manylinux-rootfs / COPY --from=all_python /opt/_internal /opt/_internal/ COPY build_scripts/finalize.sh \ - build_scripts/update-system-packages.sh \ build_scripts/python-tag-abi-tag.py \ build_scripts/requirements3.8.txt \ build_scripts/requirements3.9.txt \ @@ -156,7 +153,7 @@ ENV SSL_CERT_FILE=/opt/_internal/certs.pem CMD ["/bin/bash"] #Build manylinux2014 docker image end - +ENV JAVA_HOME=/usr/lib/jvm/msopenjdk-11 #Add our own dependencies ADD scripts /tmp/scripts RUN cd /tmp/scripts && /tmp/scripts/manylinux/install_centos.sh && /tmp/scripts/manylinux/install_deps.sh && rm -rf /tmp/scripts diff --git a/tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_cuda11_6_tensorrt8_4 b/tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda11_6_tensorrt8_4 similarity index 98% rename from tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_cuda11_6_tensorrt8_4 rename to tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda11_6_tensorrt8_4 index 303e83eb23bca..003bb2324c049 100644 --- a/tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_cuda11_6_tensorrt8_4 +++ b/tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda11_6_tensorrt8_4 @@ -31,7 +31,6 @@ COPY build_scripts/fixup-mirrors.sh /usr/local/sbin/fixup-mirrors # setup entrypoint, this will wrap commands with `linux32` with i686 images COPY build_scripts/install-entrypoint.sh \ - build_scripts/update-system-packages.sh \ build_scripts/build_utils.sh \ /build_scripts/ @@ -40,7 +39,6 @@ COPY manylinux-entrypoint /usr/local/bin/manylinux-entrypoint ENTRYPOINT ["manylinux-entrypoint"] COPY build_scripts/install-runtime-packages.sh \ - build_scripts/update-system-packages.sh \ build_scripts/build_utils.sh \ /build_scripts/ RUN manylinux-entrypoint /build_scripts/install-runtime-packages.sh && rm -rf /build_scripts/ @@ -140,7 +138,6 @@ COPY --from=build_git /manylinux-rootfs / COPY --from=build_cpython /manylinux-rootfs / COPY --from=all_python /opt/_internal /opt/_internal/ COPY build_scripts/finalize.sh \ - build_scripts/update-system-packages.sh \ build_scripts/python-tag-abi-tag.py \ build_scripts/requirements3.8.txt \ build_scripts/requirements3.9.txt \ @@ -163,7 +160,7 @@ RUN v="8.4.1-1.cuda11.6" &&\ yum-config-manager --add-repo https://developer.download.nvidia.com/compute/cuda/repos/rhel7/x86_64/cuda-rhel7.repo &&\ yum -y install libnvinfer8-${v} libnvparsers8-${v} libnvonnxparsers8-${v} libnvinfer-plugin8-${v} \ libnvinfer-devel-${v} libnvparsers-devel-${v} libnvonnxparsers-devel-${v} libnvinfer-plugin-devel-${v} - +ENV JAVA_HOME=/usr/lib/jvm/msopenjdk-11 #Add our own dependencies ADD scripts /tmp/scripts RUN cd /tmp/scripts && /tmp/scripts/manylinux/install_centos.sh && /tmp/scripts/manylinux/install_deps.sh && rm -rf /tmp/scripts diff --git a/tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_cuda11_6_tensorrt8_5 b/tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda11_6_tensorrt8_5 similarity index 98% rename from tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_cuda11_6_tensorrt8_5 rename to tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda11_6_tensorrt8_5 index d17e4b24582fe..0337ffc5e00a0 100644 --- a/tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_cuda11_6_tensorrt8_5 +++ b/tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda11_6_tensorrt8_5 @@ -31,7 +31,6 @@ COPY build_scripts/fixup-mirrors.sh /usr/local/sbin/fixup-mirrors # setup entrypoint, this will wrap commands with `linux32` with i686 images COPY build_scripts/install-entrypoint.sh \ - build_scripts/update-system-packages.sh \ build_scripts/build_utils.sh \ /build_scripts/ @@ -40,7 +39,6 @@ COPY manylinux-entrypoint /usr/local/bin/manylinux-entrypoint ENTRYPOINT ["manylinux-entrypoint"] COPY build_scripts/install-runtime-packages.sh \ - build_scripts/update-system-packages.sh \ build_scripts/build_utils.sh \ /build_scripts/ RUN manylinux-entrypoint /build_scripts/install-runtime-packages.sh && rm -rf /build_scripts/ @@ -140,7 +138,6 @@ COPY --from=build_git /manylinux-rootfs / COPY --from=build_cpython /manylinux-rootfs / COPY --from=all_python /opt/_internal /opt/_internal/ COPY build_scripts/finalize.sh \ - build_scripts/update-system-packages.sh \ build_scripts/python-tag-abi-tag.py \ build_scripts/requirements3.8.txt \ build_scripts/requirements3.9.txt \ @@ -163,7 +160,7 @@ RUN v="8.5.1-1.cuda11.8" &&\ yum-config-manager --add-repo https://developer.download.nvidia.com/compute/cuda/repos/rhel7/x86_64/cuda-rhel7.repo &&\ yum -y install libnvinfer8-${v} libnvparsers8-${v} libnvonnxparsers8-${v} libnvinfer-plugin8-${v} \ libnvinfer-devel-${v} libnvparsers-devel-${v} libnvonnxparsers-devel-${v} libnvinfer-plugin-devel-${v} - +ENV JAVA_HOME=/usr/lib/jvm/msopenjdk-11 #Add our own dependencies ADD scripts /tmp/scripts RUN cd /tmp/scripts && /tmp/scripts/manylinux/install_centos.sh && /tmp/scripts/manylinux/install_deps.sh && rm -rf /tmp/scripts diff --git a/tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_cuda11_8_tensorrt8_6 b/tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda11_8_tensorrt8_6 similarity index 95% rename from tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_cuda11_8_tensorrt8_6 rename to tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda11_8_tensorrt8_6 index 6f12da4497315..2c953a10cbf64 100644 --- a/tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_cuda11_8_tensorrt8_6 +++ b/tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_cuda11_8_tensorrt8_6 @@ -1,5 +1,5 @@ -ARG BASEIMAGE=nvidia/cuda:11.8.0-cudnn8-devel-centos7 -ARG POLICY=manylinux2014 +ARG BASEIMAGE=nvidia/cuda:11.8.0-cudnn8-devel-ubi8 +ARG POLICY=manylinux_2_28 ARG PLATFORM=x86_64 ARG DEVTOOLSET_ROOTPATH= ARG LD_LIBRARY_PATH_ARG= @@ -31,7 +31,6 @@ COPY build_scripts/fixup-mirrors.sh /usr/local/sbin/fixup-mirrors # setup entrypoint, this will wrap commands with `linux32` with i686 images COPY build_scripts/install-entrypoint.sh \ - build_scripts/update-system-packages.sh \ build_scripts/build_utils.sh \ /build_scripts/ @@ -40,7 +39,6 @@ COPY manylinux-entrypoint /usr/local/bin/manylinux-entrypoint ENTRYPOINT ["manylinux-entrypoint"] COPY build_scripts/install-runtime-packages.sh \ - build_scripts/update-system-packages.sh \ build_scripts/build_utils.sh \ /build_scripts/ RUN manylinux-entrypoint /build_scripts/install-runtime-packages.sh && rm -rf /build_scripts/ @@ -147,7 +145,6 @@ COPY --from=build_git /manylinux-rootfs / COPY --from=build_cpython /manylinux-rootfs / COPY --from=all_python /opt/_internal /opt/_internal/ COPY build_scripts/finalize.sh \ - build_scripts/update-system-packages.sh \ build_scripts/python-tag-abi-tag.py \ build_scripts/requirements3.7.txt \ build_scripts/requirements3.8.txt \ @@ -165,13 +162,13 @@ CMD ["/bin/bash"] #Build manylinux2014 docker image end -#Install TensorRT 8.6.0.12 +#Install TensorRT 8.6.1.6 #RUN yum install -y wget -RUN v="8.6.0.12-1.cuda11.8" &&\ - yum-config-manager --add-repo https://developer.download.nvidia.com/compute/cuda/repos/rhel7/x86_64/cuda-rhel7.repo &&\ +RUN v="8.6.1.6-1.cuda11.8" &&\ + yum-config-manager --add-repo https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/cuda-rhel8.repo &&\ yum -y install libnvinfer8-${v} libnvparsers8-${v} libnvonnxparsers8-${v} libnvinfer-plugin8-${v} libnvinfer-vc-plugin8-${v}\ - libnvinfer-devel-${v} libnvparsers-devel-${v} libnvonnxparsers-devel-${v} libnvinfer-plugin-devel-${v} libnvinfer-vc-plugin-devel-${v} - + libnvinfer-devel-${v} libnvparsers-devel-${v} libnvonnxparsers-devel-${v} libnvinfer-plugin-devel-${v} libnvinfer-vc-plugin-devel-${v} libnvinfer-headers-devel-${v} libnvinfer-headers-plugin-devel-${v} +ENV JAVA_HOME=/usr/lib/jvm/msopenjdk-11 #Add our own dependencies ADD scripts /tmp/scripts RUN cd /tmp/scripts && /tmp/scripts/manylinux/install_centos.sh && /tmp/scripts/manylinux/install_deps.sh && rm -rf /tmp/scripts @@ -181,4 +178,5 @@ ARG BUILD_USER=onnxruntimedev RUN adduser --uid $BUILD_UID $BUILD_USER WORKDIR /home/$BUILD_USER USER $BUILD_USER -ENV PATH /usr/local/dotnet:$PATH \ No newline at end of file +ENV PATH /usr/local/dotnet:$PATH +ENV CUDA_MODULE_LOADING "LAZY" diff --git a/tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_rocm b/tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_rocm similarity index 78% rename from tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_rocm rename to tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_rocm index ad914239a899b..19599c9f613d4 100644 --- a/tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_rocm +++ b/tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_rocm @@ -1,27 +1,16 @@ -ARG BASEIMAGE=centos:7 -ARG POLICY=manylinux2014 +ARG BASEIMAGE=amd64/almalinux:8 +ARG POLICY=manylinux_2_28 ARG PLATFORM=x86_64 -ARG DEVTOOLSET_ROOTPATH= -ARG LD_LIBRARY_PATH_ARG= -ARG PREPEND_PATH= +ARG DEVTOOLSET_ROOTPATH=/opt/rh/gcc-toolset-12/root +ARG LD_LIBRARY_PATH_ARG=${DEVTOOLSET_ROOTPATH}/usr/lib64:${DEVTOOLSET_ROOTPATH}/usr/lib:${DEVTOOLSET_ROOTPATH}/usr/lib64/dyninst:${DEVTOOLSET_ROOTPATH}/usr/lib/dyninst:/usr/local/lib64 +ARG PREPEND_PATH=${DEVTOOLSET_ROOTPATH}/usr/bin: FROM $BASEIMAGE AS base_image -ARG ROCM_VERSION=5.3.2 +ARG ROCM_VERSION=5.5 -# Enable epel-release repositories -RUN yum --enablerepo=extras install -y epel-release - -# Install the ROCm rpms -RUN yum clean all -RUN echo -e "[ROCm]\nname=ROCm\nbaseurl=https://repo.radeon.com/rocm/yum/$ROCM_VERSION/main\nenabled=1\ngpgcheck=0" >> /etc/yum.repos.d/rocm.repo - -# After ROCm5.2.3, amdgpu_version use the same version as rocm_version -RUN if [ "$ROCM_VERSION" = "5.2.3" ] ; \ - then echo -e "[amdgpu]\nname=amdgpu\nbaseurl=https://repo.radeon.com/amdgpu/22.20.3/rhel/7.9/main/x86_64\nenabled=1\ngpgcheck=0" >> /etc/yum.repos.d/amdgpu.repo; \ - else echo -e "[amdgpu]\nname=amdgpu\nbaseurl=https://repo.radeon.com/amdgpu/$ROCM_VERSION/rhel/7.9/main/x86_64\nenabled=1\ngpgcheck=0" >> /etc/yum.repos.d/amdgpu.repo; \ - fi - -RUN yum install -y rocm-dev +#Add our own dependencies +ADD scripts /tmp/scripts +RUN /tmp/scripts/setup_rocm_yum_repo.sh -r ${ROCM_VERSION} # Set ENV ENV PATH=/opt/rocm/hcc/bin:/opt/rocm/hip/bin:/opt/rocm/bin${PATH:+:${PATH}} @@ -39,12 +28,7 @@ LABEL maintainer="The ManyLinux project" # of the base docker image. Remove this line moving forward. RUN yum install -y hipify-clang -# CMake RUN yum -y install wget -ENV CMAKE_VERSION=3.24.3 -RUN cd /usr/local && \ - wget -q -O - https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz | tar zxf - -ENV PATH=/usr/local/cmake-${CMAKE_VERSION}-linux-x86_64/bin:${PATH} # rocm lib RUN yum install -y miopen-hip-devel rocblas-devel rocrand-devel rccl-devel hipsparse-devel hipfft-devel hipcub-devel hipblas-devel rocthrust-devel @@ -61,7 +45,6 @@ COPY build_scripts/fixup-mirrors.sh /usr/local/sbin/fixup-mirrors # setup entrypoint, this will wrap commands with `linux32` with i686 images COPY build_scripts/install-entrypoint.sh \ - build_scripts/update-system-packages.sh \ build_scripts/build_utils.sh \ /build_scripts/ @@ -70,7 +53,6 @@ COPY manylinux-entrypoint /usr/local/bin/manylinux-entrypoint ENTRYPOINT ["manylinux-entrypoint"] COPY build_scripts/install-runtime-packages.sh \ - build_scripts/update-system-packages.sh \ build_scripts/build_utils.sh \ /build_scripts/ RUN manylinux-entrypoint /build_scripts/install-runtime-packages.sh && rm -rf /build_scripts/ @@ -104,12 +86,6 @@ RUN export LIBXCRYPT_VERSION=4.4.28 && \ export PERL_DOWNLOAD_URL=https://www.cpan.org/src/5.0 && \ manylinux-entrypoint /build_scripts/install-libxcrypt.sh -COPY scripts/install-protobuf.sh /build_scripts/ -RUN export PROTOBUF_VERSION=3.17.3 && \ - export PROTOBUF_ROOT=protobuf-all-${PROTOBUF_VERSION} && \ - export PROTOBUF_HASH=77ad26d3f65222fd96ccc18b055632b0bfedf295cb748b712a98ba1ac0b704b2 && \ - export PROTOBUF_DOWNLOAD_URL=https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOBUF_VERSION} && \ - manylinux-entrypoint /build_scripts/install-protobuf.sh FROM runtime_base AS build_base COPY build_scripts/install-build-packages.sh /build_scripts/ @@ -179,7 +155,6 @@ COPY --from=build_git /manylinux-rootfs / COPY --from=build_cpython /manylinux-rootfs / COPY --from=all_python /opt/_internal /opt/_internal/ COPY build_scripts/finalize.sh \ - build_scripts/update-system-packages.sh \ build_scripts/python-tag-abi-tag.py \ build_scripts/requirements3.8.txt \ build_scripts/requirements3.9.txt \ @@ -200,8 +175,7 @@ ARG PYTHON_VERSION=3.8 ARG OPSET_VERSION=15 ARG INSTALL_DEPS_EXTRA_ARGS -#Add our own dependencies -ADD scripts /tmp/scripts + RUN cd /tmp/scripts && \ /tmp/scripts/manylinux/install_centos.sh && \ /tmp/scripts/install_os_deps.sh -d gpu $INSTALL_DEPS_EXTRA_ARGS && \ @@ -210,11 +184,13 @@ RUN cd /tmp/scripts && \ /tmp/scripts/install_python_deps.sh -d gpu -p 3.10 $INSTALL_DEPS_EXTRA_ARGS && \ rm -rf /tmp/scripts -# remove protobuf to prevent ambiguity which is used for onnxruntime build -RUN rm -fr /usr/local/bin/protoc \ - /usr/local/libproto* \ - /usr/local/include/google \ - /usr/local/lib/pkgconfig/protobuf* + +# Install ccache to reuse this dockerfile for CI +RUN mkdir -p /tmp/ccache && \ + cd /tmp/ccache && \ + wget -q -O - https://github.com/ccache/ccache/releases/download/v4.7.4/ccache-4.7.4-linux-x86_64.tar.xz | tar --strip 1 -J -xf - && \ + cp /tmp/ccache/ccache /usr/bin && \ + rm -rf /tmp/ccache ARG BUILD_UID=1001 ARG BUILD_USER=onnxruntimedev diff --git a/tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_training_cuda11_8 b/tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_training_cuda11_8 similarity index 97% rename from tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_training_cuda11_8 rename to tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_training_cuda11_8 index 5d774460073ed..09ab7951552a0 100644 --- a/tools/ci_build/github/linux/docker/Dockerfile.manylinux2014_training_cuda11_8 +++ b/tools/ci_build/github/linux/docker/Dockerfile.manylinux2_28_training_cuda11_8 @@ -1,4 +1,4 @@ -ARG BASEIMAGE=nvidia/cuda:11.8.0-cudnn8-devel-centos7 +ARG BASEIMAGE=nvidia/cuda:11.8.0-cudnn8-devel-ubi8 ARG POLICY=manylinux2014 ARG PLATFORM=x86_64 ARG DEVTOOLSET_ROOTPATH= @@ -31,7 +31,6 @@ COPY build_scripts/fixup-mirrors.sh /usr/local/sbin/fixup-mirrors # setup entrypoint, this will wrap commands with `linux32` with i686 images COPY build_scripts/install-entrypoint.sh \ - build_scripts/update-system-packages.sh \ build_scripts/build_utils.sh \ /build_scripts/ @@ -40,7 +39,6 @@ COPY manylinux-entrypoint /usr/local/bin/manylinux-entrypoint ENTRYPOINT ["manylinux-entrypoint"] COPY build_scripts/install-runtime-packages.sh \ - build_scripts/update-system-packages.sh \ build_scripts/build_utils.sh \ /build_scripts/ RUN manylinux-entrypoint /build_scripts/install-runtime-packages.sh && rm -rf /build_scripts/ @@ -140,7 +138,6 @@ COPY --from=build_git /manylinux-rootfs / COPY --from=build_cpython /manylinux-rootfs / COPY --from=all_python /opt/_internal /opt/_internal/ COPY build_scripts/finalize.sh \ - build_scripts/update-system-packages.sh \ build_scripts/python-tag-abi-tag.py \ build_scripts/requirements3.8.txt \ build_scripts/requirements3.9.txt \ 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 new file mode 100644 index 0000000000000..cdf504c8e3b03 --- /dev/null +++ b/tools/ci_build/github/linux/docker/Dockerfile.package_ubi8_cuda11_8_tensorrt8_6 @@ -0,0 +1,45 @@ +# -------------------------------------------------------------- +# 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 +FROM nvidia/cuda:11.8.0-cudnn8-devel-ubi8 AS base + +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.8 \ + python38-pip \ + python38-wheel &&\ + cd /usr/local/bin &&\ + ln -s /usr/bin/python3 python3.8 &&\ + ln -s /usr/bin/pip3 pip3.8; + +RUN pip3 install --upgrade pip +RUN pip3 install setuptools>=41.0.0 + +# Install TensorRT +RUN dnf install -y libnvinfer8 libnvonnxparsers8 libnvparsers8 libnvinfer-plugin8 libnvinfer-lean8 libnvinfer-vc-plugin8 libnvinfer-dispatch8 +RUN v="8.6.1.6-1+cuda11.8" &&\ + dnf downgrade -y libnvinfer8-${v} libnvinfer8-${v} libnvonnxparsers8-${v} libnvparsers8-${v} libnvinfer-plugin8-${v} libnvinfer-lean8-${v} libnvinfer-vc-plugin8-${v} libnvinfer-dispatch8-${v} &&\ + 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_ubuntu_cuda11_8_tensorrt8_6 b/tools/ci_build/github/linux/docker/Dockerfile.package_ubuntu_cuda11_8_tensorrt8_6 new file mode 100644 index 0000000000000..83a974469234f --- /dev/null +++ b/tools/ci_build/github/linux/docker/Dockerfile.package_ubuntu_cuda11_8_tensorrt8_6 @@ -0,0 +1,43 @@ +# -------------------------------------------------------------- +# 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-ubuntu20.04 AS base + +ENV PATH /usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/src/tensorrt/bin:${PATH} +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update &&\ + apt-get install -y git bash wget + +# Install python3 +RUN apt-get install -y --no-install-recommends \ + python3 \ + python3-pip \ + python3-dev \ + python3-wheel + + +RUN pip install --upgrade pip + +# Install TensorRT +RUN v="8.6.1.6-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 libnvinfer8=${v} libnvonnxparsers8=${v} libnvparsers8=${v} libnvinfer-plugin8=${v} libnvinfer-lean8=${v} libnvinfer-vc-plugin8=${v} libnvinfer-dispatch8=${v}\ + libnvinfer-headers-dev=${v} libnvinfer-headers-plugin-dev=${v} libnvinfer-dev=${v} libnvonnxparsers-dev=${v} libnvparsers-dev=${v} libnvinfer-plugin-dev=${v} libnvinfer-lean-dev=${v} libnvinfer-vc-plugin-dev=${v} libnvinfer-dispatch-dev=${v}\ + python3-libnvinfer=${v} libnvinfer-samples=${v} tensorrt-dev=${v} tensorrt-libs=${v} + +ADD scripts /tmp/scripts +RUN cd /tmp/scripts && /tmp/scripts/install_dotnet.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.ubuntu_cuda11_6_tensorrt8_4 b/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_cuda11_6_tensorrt8_4 index 9992986f657b5..10f404c7c6a85 100644 --- a/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_cuda11_6_tensorrt8_4 +++ b/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_cuda11_6_tensorrt8_4 @@ -12,7 +12,7 @@ ARG ONNXRUNTIME_REPO=https://github.com/Microsoft/onnxruntime ARG ONNXRUNTIME_BRANCH=main ARG CMAKE_CUDA_ARCHITECTURES=37;50;52;60;61;70;75;80 -ENV PATH /usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/src/tensorrt/bin:/code/cmake-3.24.3-linux-x86_64/bin:/opt/miniconda/bin:${PATH} +ENV PATH /usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/src/tensorrt/bin:/code/cmake-3.27.3-linux-x86_64/bin:/opt/miniconda/bin:${PATH} ENV DEBIAN_FRONTEND=noninteractive @@ -44,7 +44,15 @@ RUN v="8.4.1-1+cuda11.6" &&\ # Compile trtexec RUN cd /usr/src/tensorrt/samples/trtexec && make +# Install Valgrind +RUN apt-get install -y valgrind + +ARG BUILD_USER=onnxruntimedev +ARG BUILD_UID=1000 +RUN adduser --gecos 'onnxruntime Build User' --disabled-password $BUILD_USER --uid $BUILD_UID +USER $BUILD_USER WORKDIR /code +ENV CUDA_MODULE_LOADING "LAZY" # Prepare onnxruntime repository & build onnxruntime with TensorRT RUN git clone --single-branch --branch ${ONNXRUNTIME_BRANCH} --recursive ${ONNXRUNTIME_REPO} onnxruntime &&\ diff --git a/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_cuda11_8_tensorrt8_5 b/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_cuda11_8_tensorrt8_5 index 920dcf3102aef..cacc09f0c7455 100644 --- a/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_cuda11_8_tensorrt8_5 +++ b/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_cuda11_8_tensorrt8_5 @@ -10,7 +10,7 @@ FROM nvidia/cuda:11.8.0-cudnn8-devel-ubuntu20.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.24.3-linux-x86_64/bin:/opt/miniconda/bin:${PATH} +ENV PATH /usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/src/tensorrt/bin:${ONNXRUNTIME_LOCAL_CODE_DIR}/cmake-3.27.3-linux-x86_64/bin:/opt/miniconda/bin:${PATH} ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update &&\ @@ -41,9 +41,15 @@ RUN v="8.5.1-1+cuda11.8" &&\ # Compile trtexec RUN cd /usr/src/tensorrt/samples/trtexec && make +# 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 @@ -76,7 +82,11 @@ RUN if [ -z "$ONNXRUNTIME_COMMIT_ID" ] ; then echo "Building branch ${ONNXRUNTIM git reset --hard ${ONNXRUNTIME_COMMIT_ID} && git submodule update --recursive ; fi # Build ORT +ENV CUDA_MODULE_LOADING "LAZY" RUN /bin/sh build.sh --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 +RUN pip install ${ONNXRUNTIME_LOCAL_CODE_DIR}/onnxruntime/build/Linux/Release/dist/*.whl \ No newline at end of file diff --git a/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_cuda11_8_tensorrt8_6 b/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_cuda11_8_tensorrt8_6 index ecc532d3cb52f..0a4885e774047 100644 --- a/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_cuda11_8_tensorrt8_6 +++ b/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_cuda11_8_tensorrt8_6 @@ -10,7 +10,7 @@ FROM nvidia/cuda:11.8.0-cudnn8-devel-ubuntu20.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.24.3-linux-x86_64/bin:/opt/miniconda/bin:${PATH} +ENV PATH /usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/src/tensorrt/bin:${ONNXRUNTIME_LOCAL_CODE_DIR}/cmake-3.27.3-linux-x86_64/bin:/opt/miniconda/bin:${PATH} ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update &&\ @@ -31,19 +31,25 @@ RUN pip install --upgrade pip RUN pip install setuptools>=41.0.0 # Install TensorRT -RUN v="8.6.0.12-1+cuda11.8" &&\ +RUN v="8.6.1.6-1+cuda11.8" &&\ apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/7fa2af80.pub &&\ apt-get update &&\ - sudo apt-get install -y libnvinfer8=${v} libnvonnxparsers8=${v} libnvparsers8=${v} libnvinfer-plugin8=${v} libnvinfer-vc-plugin8=${v}\ - libnvinfer-dev=${v} libnvonnxparsers-dev=${v} libnvparsers-dev=${v} libnvinfer-plugin-dev=${v} libnvinfer-vc-plugin-dev=${v}\ - python3-libnvinfer=${v} libnvinfer-samples=${v} + sudo apt-get install -y libnvinfer8=${v} libnvonnxparsers8=${v} libnvparsers8=${v} libnvinfer-plugin8=${v} libnvinfer-lean8=${v} libnvinfer-vc-plugin8=${v} libnvinfer-dispatch8=${v}\ + libnvinfer-headers-dev=${v} libnvinfer-headers-plugin-dev=${v} libnvinfer-dev=${v} libnvonnxparsers-dev=${v} libnvparsers-dev=${v} libnvinfer-plugin-dev=${v} libnvinfer-lean-dev=${v} libnvinfer-vc-plugin-dev=${v} libnvinfer-dispatch-dev=${v}\ + python3-libnvinfer=${v} libnvinfer-samples=${v} tensorrt-dev=${v} tensorrt-libs=${v} # Compile trtexec RUN cd /usr/src/tensorrt/samples/trtexec && make +# 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 @@ -76,7 +82,11 @@ RUN if [ -z "$ONNXRUNTIME_COMMIT_ID" ] ; then echo "Building branch ${ONNXRUNTIM git reset --hard ${ONNXRUNTIME_COMMIT_ID} && git submodule update --recursive ; fi # Build ORT +ENV CUDA_MODULE_LOADING "LAZY" RUN /bin/sh build.sh --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 +RUN pip install ${ONNXRUNTIME_LOCAL_CODE_DIR}/onnxruntime/build/Linux/Release/dist/*.whl \ No newline at end of file diff --git a/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_for_arm b/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_for_arm deleted file mode 100644 index f754bf26fdc52..0000000000000 --- a/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_for_arm +++ /dev/null @@ -1,19 +0,0 @@ -ARG OS_VERSION=20.04 -FROM ubuntu:${OS_VERSION} - -ARG PYTHON_VERSION=3.8 -ADD scripts /tmp/scripts -RUN /tmp/scripts/install_ubuntu.sh -p $PYTHON_VERSION -d EdgeDevice && \ - /tmp/scripts/install_os_deps.sh -d EdgeDevice && \ - /tmp/scripts/install_python_deps.sh -p $PYTHON_VERSION -d EdgeDevice && \ - /tmp/scripts/install_protobuf.sh - -ARG TOOL_CHAIN="fsl-imx-xwayland-glibc-x86_64-fsl-image-qt5-aarch64-toolchain-4.19-warrior.sh" -RUN /tmp/scripts/$TOOL_CHAIN -y && rm -rf /tmp/scripts - -ARG BUILD_UID=1000 -ARG BUILD_USER=onnxruntimedev -RUN adduser --gecos 'onnxruntime Build User' --disabled-password $BUILD_USER --uid $BUILD_UID -WORKDIR /home/$BUILD_USER -USER $BUILD_USER - diff --git a/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_openvino b/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_openvino index a04075197ccaf..a0ba5ea232ca3 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=20.04 FROM ubuntu:${UBUNTU_VERSION} -ARG OPENVINO_VERSION=2022.3.0 +ARG OPENVINO_VERSION=2023.0.0 ARG PYTHON_VERSION=3.8 ADD scripts /tmp/scripts @@ -20,9 +20,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/2022.3/linux/l_openvino_toolkit_ubuntu20_2022.3.0.9052.9752fafe8eb_x86_64.tgz && \ - tar xzf l_openvino_toolkit_ubuntu20_2022.3.0.9052.9752fafe8eb_x86_64.tgz && rm -rf l_openvino_toolkit_ubuntu20_2022.3.0.9052.9752fafe8eb_x86_64.tgz && \ - mv l_openvino_toolkit_ubuntu20_2022.3.0.9052.9752fafe8eb_x86_64 openvino_2022.3.0 && \ + wget https://storage.openvinotoolkit.org/repositories/openvino/packages/2023.0/linux/l_openvino_toolkit_ubuntu20_2023.0.0.10926.b4452d56304_x86_64.tgz && \ + tar xzf l_openvino_toolkit_ubuntu20_2023.0.0.10926.b4452d56304_x86_64.tgz && rm -rf l_openvino_toolkit_ubuntu20_2023.0.0.10926.b4452d56304_x86_64.tgz && \ + mv l_openvino_toolkit_ubuntu20_2023.0.0.10926.b4452d56304_x86_64 openvino_2023.0.0 && \ cd $INTEL_OPENVINO_DIR/install_dependencies && ./install_openvino_dependencies.sh -y WORKDIR /root @@ -35,8 +35,8 @@ RUN wget "https://github.com/intel/compute-runtime/releases/download/21.48.21782 sudo dpkg -i *.deb && rm -rf *.deb RUN mkdir -p /opt/cmake/bin && \ - wget https://github.com/Kitware/CMake/releases/download/v3.24.3/cmake-3.24.3-linux-x86_64.tar.gz && \ - tar -xf cmake-3.24.3-linux-x86_64.tar.gz --strip 1 -C /opt/cmake && rm -rf /cmake-3.24.3-linux-x86_64.tar.gz && \ + wget https://github.com/Kitware/CMake/releases/download/v3.27.3/cmake-3.27.3-linux-x86_64.tar.gz && \ + tar -xf cmake-3.27.3-linux-x86_64.tar.gz --strip 1 -C /opt/cmake && rm -rf /cmake-3.27.3-linux-x86_64.tar.gz && \ ln -sf /opt/cmake/bin/* /usr/bin ARG BUILD_UID=1000 diff --git a/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_tensorrt b/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_tensorrt deleted file mode 100644 index c3b41afecbfa7..0000000000000 --- a/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_tensorrt +++ /dev/null @@ -1,36 +0,0 @@ -# Tag: nvidia/cuda:11.8.0-cudnn8-devel-ubuntu20.04 -# Label: com.nvidia.cuda.version: 11.8.0 -# Label: com.nvidia.cudnn.version: 8.7.0 -# Ubuntu 20.04 -FROM nvidia/cuda:11.8.0-cudnn8-devel-ubuntu20.04 - -ARG PYTHON_VERSION=3.8 -ARG DEBIAN_FRONTEND=noninteractive - -ADD scripts /tmp/scripts -RUN /tmp/scripts/install_ubuntu.sh -p $PYTHON_VERSION && /tmp/scripts/install_os_deps.sh && /tmp/scripts/install_python_deps.sh -p $PYTHON_VERSION && rm -rf /tmp/scripts - -# Install TensorRT -RUN v="8.6.0.12-1+cuda11.8" &&\ - apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/7fa2af80.pub &&\ - apt-get update &&\ - sudo apt-get install -y libnvinfer8=${v} libnvonnxparsers8=${v} libnvparsers8=${v} libnvinfer-plugin8=${v} libnvinfer-vc-plugin8=${v}\ - libnvinfer-dev=${v} libnvonnxparsers-dev=${v} libnvparsers-dev=${v} libnvinfer-plugin-dev=${v} libnvinfer-vc-plugin-dev=${v}\ - python3-libnvinfer=${v} libnvinfer-samples=${v} - -WORKDIR /root - -# Allow configure to pick up GDK and CuDNN where it expects it. -# (Note: $CUDNN_VERSION is defined by NVidia's base image) -RUN _CUDNN_VERSION=$(echo $CUDNN_VERSION | cut -d. -f1-2) && \ - mkdir -p /usr/local/cudnn-$_CUDNN_VERSION/cuda/include && \ - ln -s /usr/include/cudnn.h /usr/local/cudnn-$_CUDNN_VERSION/cuda/include/cudnn.h && \ - mkdir -p /usr/local/cudnn-$_CUDNN_VERSION/cuda/lib64 && \ - ln -s /etc/alternatives/libcudnn_so /usr/local/cudnn-$_CUDNN_VERSION/cuda/lib64/libcudnn.so && \ - ln -s /usr/local/cudnn{-$_CUDNN_VERSION,} - -ARG BUILD_USER=onnxruntimedev -ARG BUILD_UID=1000 -WORKDIR /home/$BUILD_USER -RUN adduser --gecos 'onnxruntime Build User' --disabled-password $BUILD_USER --uid $BUILD_UID -USER $BUILD_USER 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 fa545af4c9a45..c9308ade37396 100644 --- a/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_tensorrt_bin +++ b/tools/ci_build/github/linux/docker/Dockerfile.ubuntu_tensorrt_bin @@ -21,7 +21,7 @@ ARG TAR_CUDNN_VERSION # Directory containing TensorRT tar.gz installation package ARG TRT_BINS_DIR=. -ENV PATH /usr/local/nvidia/bin:/usr/local/cuda/bin:/code/cmake-3.24.3-linux-x86_64/bin:/opt/miniconda/bin:${PATH} +ENV PATH /usr/local/nvidia/bin:/usr/local/cuda/bin:/code/cmake-3.27.3-linux-x86_64/bin:/opt/miniconda/bin:${PATH} ENV DEBIAN_FRONTEND=noninteractive @@ -60,6 +60,6 @@ WORKDIR /code RUN git clone --single-branch --branch ${ONNXRUNTIME_BRANCH} --recursive ${ONNXRUNTIME_REPO} onnxruntime &&\ /bin/sh onnxruntime/dockerfiles/scripts/install_common_deps.sh &&\ cd onnxruntime &&\ - /bin/sh build.sh --parallel --build_shared_lib --cuda_home /usr/local/cuda --cudnn_home /usr/lib/x86_64-linux-gnu/ --use_tensorrt --use_tensorrt_builtin_parser --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}'"' &&\ + /bin/sh build.sh --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}'"' &&\ pip install /code/onnxruntime/build/Linux/Release/dist/*.whl &&\ cd .. diff --git a/tools/ci_build/github/linux/docker/inference/aarch64/default/cpu/Dockerfile b/tools/ci_build/github/linux/docker/inference/aarch64/default/cpu/Dockerfile index 7f55b891b4dae..2cd054e6246bc 100644 --- a/tools/ci_build/github/linux/docker/inference/aarch64/default/cpu/Dockerfile +++ b/tools/ci_build/github/linux/docker/inference/aarch64/default/cpu/Dockerfile @@ -2,12 +2,12 @@ # Licensed under the MIT License. # This file is used by Zip-Nuget Packaging NoContribOps Pipeline,Zip-Nuget-Java Packaging Pipeline -ARG BASEIMAGE=centos:7 +ARG BASEIMAGE=arm64v8/almalinux:8 FROM $BASEIMAGE -ENV PATH /opt/rh/devtoolset-10/root/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin -ENV LANG=en_US.utf8 -ENV LC_ALL=en_US.utf8 +ENV PATH /opt/rh/gcc-toolset-12/root/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +ENV LANG=en_US.UTF-8 +ENV LC_ALL=en_US.UTF-8 ADD scripts /tmp/scripts RUN cd /tmp/scripts && /tmp/scripts/install_centos.sh && /tmp/scripts/install_deps.sh && rm -rf /tmp/scripts diff --git a/tools/ci_build/github/linux/docker/inference/aarch64/default/cpu/scripts/install_centos.sh b/tools/ci_build/github/linux/docker/inference/aarch64/default/cpu/scripts/install_centos.sh index 65d020482b9f4..adb0464d6496a 100755 --- a/tools/ci_build/github/linux/docker/inference/aarch64/default/cpu/scripts/install_centos.sh +++ b/tools/ci_build/github/linux/docker/inference/aarch64/default/cpu/scripts/install_centos.sh @@ -1,11 +1,8 @@ #!/bin/bash set -e -x -os_major_version=$(cat /etc/redhat-release | tr -dc '0-9.'|cut -d \. -f1) +os_major_version=$(tr -dc '0-9.' < /etc/redhat-release |cut -d \. -f1) echo "installing for CentOS version : $os_major_version" -yum install -y centos-release-scl-rh -yum install -y which gdb redhat-lsb-core expat-devel tar unzip zlib-devel make libunwind bzip2 bzip2-devel java-11-openjdk-devel graphviz devtoolset-10-binutils devtoolset-10-gcc devtoolset-10-gcc-c++ devtoolset-10-gcc-gfortran python3 python3-pip - -pip3 install --upgrade pip -localedef -i en_US -f UTF-8 en_US.UTF-8 +dnf install -y python39-devel glibc-langpack-\* glibc-locale-source which redhat-lsb-core expat-devel tar unzip zlib-devel make bzip2 bzip2-devel java-11-openjdk-devel graphviz gcc-toolset-12-binutils gcc-toolset-12-gcc gcc-toolset-12-gcc-c++ gcc-toolset-12-gcc-gfortran +locale diff --git a/tools/ci_build/github/linux/docker/inference/aarch64/default/cpu/scripts/install_deps.sh b/tools/ci_build/github/linux/docker/inference/aarch64/default/cpu/scripts/install_deps.sh index 4fa65ddc930eb..7598ab0a7a536 100755 --- a/tools/ci_build/github/linux/docker/inference/aarch64/default/cpu/scripts/install_deps.sh +++ b/tools/ci_build/github/linux/docker/inference/aarch64/default/cpu/scripts/install_deps.sh @@ -14,20 +14,20 @@ function GetFile { echo "File '$path' already exists. Skipping download" return 0 else - rm -rf $path + rm -rf "$path" fi fi if [[ -f $uri ]]; then echo "'$uri' is a file path, copying file to '$path'" - cp $uri $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" + 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 @@ -38,20 +38,22 @@ mkdir -p /tmp/src cd /tmp/src +CPU_ARCH=$(uname -m) echo "Installing cmake" -GetFile https://github.com/Kitware/CMake/releases/download/v3.24.3/cmake-3.24.3-linux-`uname -m`.tar.gz /tmp/src/cmake-3.24.3-linux-`uname -m`.tar.gz -tar -zxf /tmp/src/cmake-3.24.3-linux-`uname -m`.tar.gz --strip=1 -C /usr +GetFile "https://github.com/Kitware/CMake/releases/download/v3.27.3/cmake-3.27.3-linux-$CPU_ARCH.tar.gz" "/tmp/src/cmake.tar.gz" +tar -zxf /tmp/src/cmake.tar.gz --strip=1 -C /usr echo "Installing Ninja" GetFile https://github.com/ninja-build/ninja/archive/v1.10.0.tar.gz /tmp/src/ninja-linux.tar.gz tar -zxf ninja-linux.tar.gz -cd ninja-1.10.0 +pushd ninja-1.10.0 cmake -Bbuild-cmake -H. cmake --build build-cmake mv ./build-cmake/ninja /usr/bin +popd echo "Installing Node.js" -CPU_ARCH=`uname -m` + if [[ "$CPU_ARCH" = "x86_64" ]]; then NODEJS_ARCH=x64 elif [[ "$CPU_ARCH" = "aarch64" ]]; then @@ -59,8 +61,9 @@ elif [[ "$CPU_ARCH" = "aarch64" ]]; then else NODEJS_ARCH=$CPU_ARCH fi -GetFile https://nodejs.org/dist/v16.14.2/node-v16.14.2-linux-${NODEJS_ARCH}.tar.gz /tmp/src/node-v16.14.2-linux-${NODEJS_ARCH}.tar.gz -tar --strip 1 -xf /tmp/src/node-v16.14.2-linux-${NODEJS_ARCH}.tar.gz -C /usr +# 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/x64/default/cpu/Dockerfile b/tools/ci_build/github/linux/docker/inference/x64/default/cpu/Dockerfile index c4aec05f8e540..caf9583807b62 100644 --- a/tools/ci_build/github/linux/docker/inference/x64/default/cpu/Dockerfile +++ b/tools/ci_build/github/linux/docker/inference/x64/default/cpu/Dockerfile @@ -2,13 +2,13 @@ # Licensed under the MIT License. # This file is used by Zip-Nuget Packaging NoContribOps Pipeline,Zip-Nuget-Java Packaging Pipeline -ARG BASEIMAGE=centos:7 +ARG BASEIMAGE=amd64/almalinux:8 FROM $BASEIMAGE -ENV PATH /opt/rh/devtoolset-11/root/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin -ENV LANG=en_US.utf8 -ENV LC_ALL=en_US.utf8 - +ENV PATH /usr/lib/jvm/msopenjdk-11/bin:/opt/rh/gcc-toolset-12/root/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +ENV LANG=en_US.UTF-8 +ENV LC_ALL=en_US.UTF-8 +ENV JAVA_HOME=/usr/lib/jvm/msopenjdk-11 ADD scripts /tmp/scripts RUN cd /tmp/scripts && /tmp/scripts/install_centos.sh && /tmp/scripts/install_deps.sh && rm -rf /tmp/scripts diff --git a/tools/ci_build/github/linux/docker/inference/x64/default/cpu/scripts/install_centos.sh b/tools/ci_build/github/linux/docker/inference/x64/default/cpu/scripts/install_centos.sh index b14ee8c628013..b5f8bf1a49a19 100755 --- a/tools/ci_build/github/linux/docker/inference/x64/default/cpu/scripts/install_centos.sh +++ b/tools/ci_build/github/linux/docker/inference/x64/default/cpu/scripts/install_centos.sh @@ -1,11 +1,9 @@ #!/bin/bash set -e -x -os_major_version=$(cat /etc/redhat-release | tr -dc '0-9.'|cut -d \. -f1) +os_major_version=$(tr -dc '0-9.' < /etc/redhat-release |cut -d \. -f1) echo "installing for CentOS version : $os_major_version" -yum install -y centos-release-scl-rh -yum install -y which gdb redhat-lsb-core expat-devel tar unzip zlib-devel make libunwind bzip2 bzip2-devel java-11-openjdk-devel graphviz devtoolset-11-binutils devtoolset-11-gcc devtoolset-11-gcc-c++ devtoolset-11-gcc-gfortran python3 python3-pip - -pip3 install --upgrade pip -localedef -i en_US -f UTF-8 en_US.UTF-8 +rpm -Uvh https://packages.microsoft.com/config/centos/$os_major_version/packages-microsoft-prod.rpm +dnf install -y python39-devel glibc-langpack-\* glibc-locale-source which redhat-lsb-core expat-devel tar unzip zlib-devel make bzip2 bzip2-devel msopenjdk-11 graphviz gcc-toolset-12-binutils gcc-toolset-12-gcc gcc-toolset-12-gcc-c++ gcc-toolset-12-gcc-gfortran +locale diff --git a/tools/ci_build/github/linux/docker/inference/x64/default/cpu/scripts/install_deps.sh b/tools/ci_build/github/linux/docker/inference/x64/default/cpu/scripts/install_deps.sh index 4fa65ddc930eb..3b05c6787ca3e 100755 --- a/tools/ci_build/github/linux/docker/inference/x64/default/cpu/scripts/install_deps.sh +++ b/tools/ci_build/github/linux/docker/inference/x64/default/cpu/scripts/install_deps.sh @@ -39,16 +39,17 @@ mkdir -p /tmp/src cd /tmp/src echo "Installing cmake" -GetFile https://github.com/Kitware/CMake/releases/download/v3.24.3/cmake-3.24.3-linux-`uname -m`.tar.gz /tmp/src/cmake-3.24.3-linux-`uname -m`.tar.gz -tar -zxf /tmp/src/cmake-3.24.3-linux-`uname -m`.tar.gz --strip=1 -C /usr +GetFile https://github.com/Kitware/CMake/releases/download/v3.27.3/cmake-3.27.3-linux-`uname -m`.tar.gz /tmp/src/cmake-3.27.3-linux-`uname -m`.tar.gz +tar -zxf /tmp/src/cmake-3.27.3-linux-`uname -m`.tar.gz --strip=1 -C /usr echo "Installing Ninja" GetFile https://github.com/ninja-build/ninja/archive/v1.10.0.tar.gz /tmp/src/ninja-linux.tar.gz tar -zxf ninja-linux.tar.gz -cd ninja-1.10.0 +pushd ninja-1.10.0 cmake -Bbuild-cmake -H. cmake --build build-cmake mv ./build-cmake/ninja /usr/bin +popd echo "Installing Node.js" CPU_ARCH=`uname -m` @@ -59,8 +60,9 @@ elif [[ "$CPU_ARCH" = "aarch64" ]]; then else NODEJS_ARCH=$CPU_ARCH fi -GetFile https://nodejs.org/dist/v16.14.2/node-v16.14.2-linux-${NODEJS_ARCH}.tar.gz /tmp/src/node-v16.14.2-linux-${NODEJS_ARCH}.tar.gz -tar --strip 1 -xf /tmp/src/node-v16.14.2-linux-${NODEJS_ARCH}.tar.gz -C /usr +# 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/x64/default/gpu/Dockerfile b/tools/ci_build/github/linux/docker/inference/x64/default/gpu/Dockerfile new file mode 100644 index 0000000000000..318791072f46d --- /dev/null +++ b/tools/ci_build/github/linux/docker/inference/x64/default/gpu/Dockerfile @@ -0,0 +1,19 @@ +# 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 nvidia/cuda:11.8.0-cudnn8-devel-ubi8 + +ENV PATH /usr/lib/jvm/msopenjdk-11/bin:/usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +ENV LANG=en_US.UTF-8 +ENV LC_ALL=en_US.UTF-8 +ENV JAVA_HOME=/usr/lib/jvm/msopenjdk-11 + +ADD scripts /tmp/scripts +RUN cd /tmp/scripts && /tmp/scripts/install_centos.sh && /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/x64/default/gpu/scripts/install_centos.sh b/tools/ci_build/github/linux/docker/inference/x64/default/gpu/scripts/install_centos.sh new file mode 100755 index 0000000000000..31e3e40f1b7ee --- /dev/null +++ b/tools/ci_build/github/linux/docker/inference/x64/default/gpu/scripts/install_centos.sh @@ -0,0 +1,9 @@ +#!/bin/bash +set -e -x + +os_major_version=$(tr -dc '0-9.' < /etc/redhat-release |cut -d \. -f1) + +echo "installing for CentOS version : $os_major_version" +rpm -Uvh https://packages.microsoft.com/config/centos/$os_major_version/packages-microsoft-prod.rpm +dnf install -y python39-devel glibc-langpack-\* glibc-locale-source which redhat-lsb-core expat-devel tar unzip zlib-devel make bzip2 bzip2-devel msopenjdk-11 +locale diff --git a/tools/ci_build/github/linux/docker/inference/x64/default/gpu/scripts/install_deps.sh b/tools/ci_build/github/linux/docker/inference/x64/default/gpu/scripts/install_deps.sh new file mode 100755 index 0000000000000..eb6d3315b97ef --- /dev/null +++ b/tools/ci_build/github/linux/docker/inference/x64/default/gpu/scripts/install_deps.sh @@ -0,0 +1,68 @@ +#!/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 cmake" +GetFile https://github.com/Kitware/CMake/releases/download/v3.26.3/cmake-3.26.3-linux-`uname -m`.tar.gz /tmp/src/cmake-3.26.3-linux-`uname -m`.tar.gz +tar -zxf /tmp/src/cmake-3.26.3-linux-`uname -m`.tar.gz --strip=1 -C /usr + +echo "Installing Ninja" +GetFile https://github.com/ninja-build/ninja/archive/v1.10.0.tar.gz /tmp/src/ninja-linux.tar.gz +tar -zxf ninja-linux.tar.gz +pushd ninja-1.10.0 +cmake -Bbuild-cmake -H. +cmake --build build-cmake +mv ./build-cmake/ninja /usr/bin +popd + +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/x64/python/cpu/Dockerfile.manylinux2014_cpu b/tools/ci_build/github/linux/docker/inference/x64/python/cpu/Dockerfile.manylinux2_28_cpu similarity index 92% rename from tools/ci_build/github/linux/docker/inference/x64/python/cpu/Dockerfile.manylinux2014_cpu rename to tools/ci_build/github/linux/docker/inference/x64/python/cpu/Dockerfile.manylinux2_28_cpu index 8869a789028e0..06e75ee1a39f6 100644 --- a/tools/ci_build/github/linux/docker/inference/x64/python/cpu/Dockerfile.manylinux2014_cpu +++ b/tools/ci_build/github/linux/docker/inference/x64/python/cpu/Dockerfile.manylinux2_28_cpu @@ -1,9 +1,9 @@ -ARG BASEIMAGE=centos:7 -ARG POLICY=manylinux2014 +ARG BASEIMAGE=amd64/almalinux:8 +ARG POLICY=manylinux_2_28 ARG PLATFORM=x86_64 -ARG DEVTOOLSET_ROOTPATH=/opt/rh/devtoolset-11/root -ARG LD_LIBRARY_PATH_ARG=/opt/rh/devtoolset-11/root/usr/lib64:/opt/rh/devtoolset-11/root/usr/lib:/opt/rh/devtoolset-11/root/usr/lib64/dyninst:/opt/rh/devtoolset-11/root/usr/lib/dyninst:/usr/local/lib64 -ARG PREPEND_PATH=/opt/rh/devtoolset-11/root/usr/bin: +ARG DEVTOOLSET_ROOTPATH=/opt/rh/gcc-toolset-12/root +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 +ARG PREPEND_PATH=/opt/rh/gcc-toolset-12/root/usr/bin: #Build manylinux2014 docker image begin FROM $BASEIMAGE AS runtime_base @@ -26,7 +26,6 @@ COPY build_scripts/fixup-mirrors.sh /usr/local/sbin/fixup-mirrors # setup entrypoint, this will wrap commands with `linux32` with i686 images COPY build_scripts/install-entrypoint.sh \ - build_scripts/update-system-packages.sh \ build_scripts/build_utils.sh \ /build_scripts/ @@ -35,7 +34,6 @@ COPY manylinux-entrypoint /usr/local/bin/manylinux-entrypoint ENTRYPOINT ["manylinux-entrypoint"] COPY build_scripts/install-runtime-packages.sh \ - build_scripts/update-system-packages.sh \ build_scripts/build_utils.sh \ /build_scripts/ RUN manylinux-entrypoint /build_scripts/install-runtime-packages.sh && rm -rf /build_scripts/ @@ -132,7 +130,6 @@ COPY --from=build_git /manylinux-rootfs / COPY --from=build_cpython /manylinux-rootfs / COPY --from=all_python /opt/_internal /opt/_internal/ COPY build_scripts/finalize.sh \ - build_scripts/update-system-packages.sh \ build_scripts/python-tag-abi-tag.py \ build_scripts/requirements3.8.txt \ build_scripts/requirements3.9.txt \ diff --git a/tools/ci_build/github/linux/docker/inference/x64/python/cpu/scripts/install_centos.sh b/tools/ci_build/github/linux/docker/inference/x64/python/cpu/scripts/install_centos.sh index db4b6177449a2..c81e57c60c9da 100755 --- a/tools/ci_build/github/linux/docker/inference/x64/python/cpu/scripts/install_centos.sh +++ b/tools/ci_build/github/linux/docker/inference/x64/python/cpu/scripts/install_centos.sh @@ -1,7 +1,20 @@ #!/bin/bash set -e -os_major_version=$(cat /etc/redhat-release | tr -dc '0-9.'|cut -d \. -f1) +os_major_version=$(tr -dc '0-9.' < /etc/redhat-release |cut -d \. -f1) echo "installing for os major version : $os_major_version" -yum install -y which gdb redhat-lsb-core expat-devel tar unzip zlib-devel make libunwind bzip2 bzip2-devel +dnf install -y glibc-langpack-\* +yum install -y which redhat-lsb-core expat-devel tar unzip zlib-devel make bzip2 bzip2-devel perl-IPC-Cmd openssl-devel wget + +# export PATH=/opt/python/cp38-cp38/bin:$PATH + +echo "installing rapidjson for AzureEP" +wget https://github.com/Tencent/rapidjson/archive/refs/tags/v1.1.0.tar.gz +tar zxvf v1.1.0.tar.gz +cd rapidjson-1.1.0 +mkdir build +cd build +cmake .. +cmake --install . +cd ../.. diff --git a/tools/ci_build/github/linux/docker/inference/x64/python/cpu/scripts/install_protobuf.sh b/tools/ci_build/github/linux/docker/inference/x64/python/cpu/scripts/install_protobuf.sh index b912b8e15bce7..31b5ca6f9e69b 100755 --- a/tools/ci_build/github/linux/docker/inference/x64/python/cpu/scripts/install_protobuf.sh +++ b/tools/ci_build/github/linux/docker/inference/x64/python/cpu/scripts/install_protobuf.sh @@ -11,39 +11,83 @@ d) DEP_FILE_PATH=${OPTARG};; esac done -EXTRA_CMAKE_ARGS="" + + +EXTRA_CMAKE_ARGS="-DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_CXX_STANDARD=17" case "$(uname -s)" in Darwin*) echo 'Building ONNX Runtime on Mac OS X' - EXTRA_CMAKE_ARGS="-DCMAKE_OSX_ARCHITECTURES=x86_64;arm64" + EXTRA_CMAKE_ARGS="$EXTRA_CMAKE_ARGS -DCMAKE_OSX_ARCHITECTURES=x86_64;arm64" + GCC_PATH=$(which clang) + GPLUSPLUS_PATH=$(which clang++) ;; Linux*) - # Depending on how the compiler has been configured when it was built, sometimes "gcc -dumpversion" shows the full version. - GCC_VERSION=$(gcc -dumpversion | cut -d . -f 1) - #-fstack-clash-protection prevents attacks based on an overlapping heap and stack. - if [ "$GCC_VERSION" -ge 8 ]; then + SYS_LONG_BIT=$(getconf LONG_BIT) + DISTRIBUTOR=$(lsb_release -i -s) + + if [[ ("$DISTRIBUTOR" = "CentOS" || "$DISTRIBUTOR" = "RedHatEnterprise") && $SYS_LONG_BIT = "64" ]]; then + LIBDIR="lib64" + else + LIBDIR="lib" + fi + EXTRA_CMAKE_ARGS="$EXTRA_CMAKE_ARGS -DCMAKE_INSTALL_LIBDIR=$LIBDIR" + # Depending on how the compiler has been configured when it was built, sometimes "gcc -dumpversion" shows the full version. + GCC_VERSION=$(gcc -dumpversion | cut -d . -f 1) + #-fstack-clash-protection prevents attacks based on an overlapping heap and stack. + if [ "$GCC_VERSION" -ge 8 ]; then CFLAGS="$CFLAGS -fstack-clash-protection" CXXFLAGS="$CXXFLAGS -fstack-clash-protection" - fi - ARCH=$(uname -m) - - if [ "$ARCH" == "x86_64" ] && [ "$GCC_VERSION" -ge 9 ]; then + fi + ARCH=$(uname -m) + GCC_PATH=$(which gcc) + GPLUSPLUS_PATH=$(which g++) + if [ "$ARCH" == "x86_64" ] && [ "$GCC_VERSION" -ge 9 ]; then CFLAGS="$CFLAGS -fcf-protection" CXXFLAGS="$CXXFLAGS -fcf-protection" - fi - export CFLAGS - export CXXFLAGS - ;; - *) + fi + export CFLAGS + export CXXFLAGS + ;; + *) exit 1 esac -mkdir -p $INSTALL_PREFIX +mkdir -p "$INSTALL_PREFIX" + +if [ -x "$(command -v ninja)" ]; then + EXTRA_CMAKE_ARGS="$EXTRA_CMAKE_ARGS -G Ninja" +fi +echo "Installing abseil ..." +pushd . +absl_url=$(grep '^abseil_cpp' "$DEP_FILE_PATH" | cut -d ';' -f 2 ) +if [[ "$absl_url" = https* ]]; then + absl_url=$(echo $absl_url | sed 's/\.zip$/\.tar.gz/') + curl -sSL --retry 5 --retry-delay 10 --create-dirs --fail -L -o absl_src.tar.gz $absl_url + mkdir abseil + cd abseil + tar -zxf ../absl_src.tar.gz --strip=1 +else + cp $absl_url absl_src.zip + unzip absl_src.zip + cd */ +fi + +CC=$GCC_PATH CXX=$GPLUSPLUS_PATH cmake "." "-DABSL_PROPAGATE_CXX_STD=ON" "-DCMAKE_BUILD_TYPE=Release" "-DBUILD_TESTING=OFF" "-DABSL_USE_EXTERNAL_GOOGLETEST=ON" "-DCMAKE_PREFIX_PATH=$INSTALL_PREFIX" "-DCMAKE_INSTALL_PREFIX=$INSTALL_PREFIX" $EXTRA_CMAKE_ARGS +if [ -x "$(command -v ninja)" ]; then + ninja + ninja install +else + make -j$(getconf _NPROCESSORS_ONLN) + make install +fi +popd + +pushd . echo "Installing protobuf ..." protobuf_url=$(grep '^protobuf' $DEP_FILE_PATH | cut -d ';' -f 2 ) if [[ "$protobuf_url" = https* ]]; then - protobuf_url=$(echo $protobuf_url | sed 's/\.zip$/\.tar.gz/') - curl -sSL --retry 5 --retry-delay 10 --create-dirs --fail -L -o protobuf_src.tar.gz $protobuf_url + protobuf_url=$(echo "$protobuf_url" | sed 's/\.zip$/\.tar.gz/') + curl -sSL --retry 5 --retry-delay 10 --create-dirs --fail -L -o protobuf_src.tar.gz "$protobuf_url" mkdir protobuf cd protobuf tar -zxf ../protobuf_src.tar.gz --strip=1 @@ -53,7 +97,12 @@ else cd protobuf-* fi -cmake . -DCMAKE_INSTALL_PREFIX=$INSTALL_PREFIX -DCMAKE_POSITION_INDEPENDENT_CODE=ON -Dprotobuf_BUILD_TESTS=OFF -DCMAKE_BUILD_TYPE=Release -Dprotobuf_WITH_ZLIB_DEFAULT=OFF -Dprotobuf_BUILD_SHARED_LIBS=OFF $EXTRA_CMAKE_ARGS -make -j$(getconf _NPROCESSORS_ONLN) -make install -cd .. \ No newline at end of file +CC=$GCC_PATH CXX=$GPLUSPLUS_PATH cmake . "-DCMAKE_INSTALL_PREFIX=$INSTALL_PREFIX" -DCMAKE_POSITION_INDEPENDENT_CODE=ON -Dprotobuf_BUILD_TESTS=OFF -DCMAKE_BUILD_TYPE=Release -Dprotobuf_WITH_ZLIB_DEFAULT=OFF -Dprotobuf_BUILD_SHARED_LIBS=OFF "-DCMAKE_PREFIX_PATH=$INSTALL_PREFIX" $EXTRA_CMAKE_ARGS -Dprotobuf_ABSL_PROVIDER=package +if [ -x "$(command -v ninja)" ]; then + ninja + ninja install +else + make -j$(getconf _NPROCESSORS_ONLN) + make install +fi +popd diff --git a/tools/ci_build/github/linux/docker/inference/x64/python/cpu/scripts/requirements.txt b/tools/ci_build/github/linux/docker/inference/x64/python/cpu/scripts/requirements.txt index 44a65f4b555b9..8a9c4dac1dd58 100644 --- a/tools/ci_build/github/linux/docker/inference/x64/python/cpu/scripts/requirements.txt +++ b/tools/ci_build/github/linux/docker/inference/x64/python/cpu/scripts/requirements.txt @@ -4,7 +4,7 @@ mypy pytest setuptools>=41.4.0 wheel -onnx==1.13.0 +git+http://github.com/onnx/onnx.git@e2525550194ce3d8a2c4a3af451c9d9b3ae6650e#egg=onnx protobuf==3.20.2 -sympy==1.10.1 +sympy==1.12 flatbuffers diff --git a/tools/ci_build/github/linux/docker/manylinux-entrypoint b/tools/ci_build/github/linux/docker/manylinux-entrypoint deleted file mode 100755 index 06ea40efa998f..0000000000000 --- a/tools/ci_build/github/linux/docker/manylinux-entrypoint +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -set -eu - -if [ "${AUDITWHEEL_ARCH}" == "i686" ]; then - linux32 "$@" -else - exec "$@" -fi diff --git a/tools/ci_build/github/linux/docker/manylinux.patch b/tools/ci_build/github/linux/docker/manylinux.patch index c2ee94d820327..75923e746f93c 100644 --- a/tools/ci_build/github/linux/docker/manylinux.patch +++ b/tools/ci_build/github/linux/docker/manylinux.patch @@ -23,7 +23,7 @@ index 9c0b02d..2e2919c 100755 +make -j$(nproc) install prefix=/usr/local NO_GETTEXT=1 NO_TCLTK=1 DESTDIR=/manylinux-rootfs CPPFLAGS="${MANYLINUX_CPPFLAGS}" CFLAGS="${MANYLINUX_CFLAGS}" CXXFLAGS="${MANYLINUX_CXXFLAGS}" LDFLAGS="${MANYLINUX_LDFLAGS}" popd rm -rf ${GIT_ROOT} ${GIT_ROOT}.tar.gz - + diff --git a/build-openssl.sh b/build-openssl.sh index 668deb6..5f3f5d5 100755 --- a/build-openssl.sh @@ -42,14 +42,43 @@ index 961e34d..55ae11b 100755 --- a/build_utils.sh +++ b/build_utils.sh @@ -52,7 +52,7 @@ function check_sha256sum { - + function do_standard_install { ./configure "$@" CPPFLAGS="${MANYLINUX_CPPFLAGS}" CFLAGS="${MANYLINUX_CFLAGS}" "CXXFLAGS=${MANYLINUX_CXXFLAGS}" LDFLAGS="${MANYLINUX_LDFLAGS}" > /dev/null - make > /dev/null + make -j$(nproc) > /dev/null make install > /dev/null } - + +diff --git a/finalize.sh b/finalize.sh +index 621eab9..4cbcf90 100755 +--- a/finalize.sh ++++ b/finalize.sh +@@ -86,6 +86,3 @@ clean_pyc /opt/_internal + rm -rf /root/.cache + + hardlink -cv /opt/_internal +- +-# update system packages +-LC_ALL=C ${MY_DIR}/update-system-packages.sh +diff --git a/install-build-packages.sh b/install-build-packages.sh +index 408bc33..b45ceba 100755 +--- a/install-build-packages.sh ++++ b/install-build-packages.sh +@@ -9,12 +9,11 @@ set -exuo pipefail + # make sure the corresponding library is added to RUNTIME_DEPS if applicable + + if [ "${AUDITWHEEL_POLICY}" == "manylinux2014" ] || [ "${AUDITWHEEL_POLICY}" == "manylinux_2_28" ]; then +- COMPILE_DEPS="bzip2-devel ncurses-devel readline-devel gdbm-devel libpcap-devel xz-devel openssl openssl-devel keyutils-libs-devel krb5-devel libcom_err-devel libidn-devel curl-devel uuid-devel libffi-devel kernel-headers libdb-devel" ++ COMPILE_DEPS="bzip2-devel ncurses-devel gdbm-devel xz-devel openssl openssl-devel keyutils-libs-devel krb5-devel libcom_err-devel curl-devel libffi-devel kernel-headers libdb-devel" + if [ "${AUDITWHEEL_POLICY}" == "manylinux2014" ]; then + PACKAGE_MANAGER=yum + else + PACKAGE_MANAGER=dnf +- COMPILE_DEPS="${COMPILE_DEPS} tk-devel" + fi + elif [ "${AUDITWHEEL_POLICY}" == "musllinux_1_1" ]; then + PACKAGE_MANAGER=apk diff --git a/install-entrypoint.sh b/install-entrypoint.sh index 9ef1e99..ec52833 100755 --- a/install-entrypoint.sh @@ -65,10 +94,28 @@ index 9ef1e99..ec52833 100755 +fi \ No newline at end of file diff --git a/install-runtime-packages.sh b/install-runtime-packages.sh -index 137d2e2..bd329f4 100755 +index 137d2e2..203b4bc 100755 --- a/install-runtime-packages.sh +++ b/install-runtime-packages.sh -@@ -73,9 +73,14 @@ if [ "${AUDITWHEEL_POLICY}" == "manylinux2014" ]; then +@@ -33,7 +33,7 @@ source $MY_DIR/build_utils.sh + + # MANYLINUX_DEPS: Install development packages (except for libgcc which is provided by gcc install) + if [ "${AUDITWHEEL_POLICY}" == "manylinux2014" ] || [ "${AUDITWHEEL_POLICY}" == "manylinux_2_28" ]; then +- MANYLINUX_DEPS="glibc-devel libstdc++-devel glib2-devel libX11-devel libXext-devel libXrender-devel mesa-libGL-devel libICE-devel libSM-devel zlib-devel expat-devel" ++ MANYLINUX_DEPS="glibc-devel libstdc++-devel glib2-devel zlib-devel expat-devel" + elif [ "${AUDITWHEEL_POLICY}" == "musllinux_1_1" ]; then + MANYLINUX_DEPS="musl-dev libstdc++ glib-dev libx11-dev libxext-dev libxrender-dev mesa-dev libice-dev libsm-dev zlib-dev expat-dev" + else +@@ -54,7 +54,7 @@ else + exit 1 + fi + +-BASETOOLS="autoconf automake bison bzip2 diffutils file make patch unzip" ++BASETOOLS="autoconf automake bzip2 diffutils file make patch unzip" + if [ "${AUDITWHEEL_POLICY}" == "manylinux2014" ]; then + PACKAGE_MANAGER=yum + BASETOOLS="${BASETOOLS} hardlink hostname which" +@@ -73,9 +73,11 @@ if [ "${AUDITWHEEL_POLICY}" == "manylinux2014" ]; then if [ "${AUDITWHEEL_ARCH}" == "x86_64" ]; then # Software collection (for devtoolset-10) yum -y install centos-release-scl-rh @@ -78,11 +125,49 @@ index 137d2e2..bd329f4 100755 + if [[ -d /opt/rocm ]]; then + TOOLCHAIN_DEPS="devtoolset-10-binutils devtoolset-10-gcc devtoolset-10-gcc-c++ devtoolset-10-gcc-gfortran" + else -+ # EPEL support (for yasm) -+ yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm + TOOLCHAIN_DEPS="devtoolset-11-binutils devtoolset-11-gcc devtoolset-11-gcc-c++ devtoolset-11-gcc-gfortran" + fi -+ TOOLCHAIN_DEPS="${TOOLCHAIN_DEPS} yasm" elif [ "${AUDITWHEEL_ARCH}" == "aarch64" ] || [ "${AUDITWHEEL_ARCH}" == "ppc64le" ] || [ "${AUDITWHEEL_ARCH}" == "s390x" ]; then # Software collection (for devtoolset-10) yum -y install centos-release-scl-rh +@@ -86,19 +88,21 @@ if [ "${AUDITWHEEL_POLICY}" == "manylinux2014" ]; then + fi + elif [ "${AUDITWHEEL_POLICY}" == "manylinux_2_28" ]; then + PACKAGE_MANAGER=dnf +- BASETOOLS="${BASETOOLS} curl glibc-locale-source glibc-langpack-en hardlink hostname libcurl libnsl libxcrypt which" ++ BASETOOLS="${BASETOOLS} yum-utils curl glibc-locale-source glibc-langpack-en hardlink hostname libcurl libxcrypt which" + # See https://unix.stackexchange.com/questions/41784/can-yum-express-a-preference-for-x86-64-over-i386-packages + echo "multilib_policy=best" >> /etc/yum.conf + # Error out if requested packages do not exist + echo "skip_missing_names_on_install=False" >> /etc/yum.conf + # Make sure that locale will not be removed + sed -i '/^override_install_langs=/d' /etc/yum.conf +- dnf -y upgrade + dnf -y install dnf-plugins-core +- dnf config-manager --set-enabled powertools # for yasm +- TOOLCHAIN_DEPS="gcc-toolset-12-binutils gcc-toolset-12-gcc gcc-toolset-12-gcc-c++ gcc-toolset-12-gcc-gfortran" +- if [ "${AUDITWHEEL_ARCH}" == "x86_64" ]; then +- TOOLCHAIN_DEPS="${TOOLCHAIN_DEPS} yasm" ++ if test -f "/etc/yum.repos.d/ubi.repo"; then ++ sed -i 's/enabled\s*=\s*1/enabled = 1\nexclude=dotnet* aspnet* netstandard*/g' /etc/yum.repos.d/ubi.repo ++ fi ++ if [[ -d /usr/local/cuda ]]; then ++ TOOLCHAIN_DEPS="gcc gcc-c++" ++ else ++ TOOLCHAIN_DEPS="gcc-toolset-12-binutils gcc-toolset-12-gcc gcc-toolset-12-gcc-c++ gcc-toolset-12-gcc-gfortran" + fi + elif [ "${AUDITWHEEL_POLICY}" == "musllinux_1_1" ]; then + TOOLCHAIN_DEPS="binutils gcc g++ gfortran" +@@ -121,12 +125,6 @@ else + exit 1 + fi + +-# update system packages, we already updated them but +-# the following script takes care of cleaning-up some things +-# and since it's also needed in the finalize step, everything's +-# centralized in this script to avoid code duplication +-LC_ALL=C ${MY_DIR}/update-system-packages.sh +- + if [ "${BASE_POLICY}" == "manylinux" ]; then + # we'll be removing libcrypt.so.1 later on + # this is needed to ensure the new one will be found diff --git a/tools/ci_build/github/linux/docker/migraphx-ci-pipeline-env.Dockerfile b/tools/ci_build/github/linux/docker/migraphx-ci-pipeline-env.Dockerfile index d9dcd1937658a..7d2c818d08920 100644 --- a/tools/ci_build/github/linux/docker/migraphx-ci-pipeline-env.Dockerfile +++ b/tools/ci_build/github/linux/docker/migraphx-ci-pipeline-env.Dockerfile @@ -1,12 +1,42 @@ -FROM rocm/pytorch:rocm5.4_ubuntu20.04_py3.7_pytorch_1.12.1 +# Refer to https://github.com/RadeonOpenCompute/ROCm-docker/blob/master/dev/Dockerfile-ubuntu-22.04-complete +FROM ubuntu:22.04 -# MIGraphX version should be the same as ROCm version -ARG MIGRAPHX_VERSION=rocm-5.4.0 +ARG ROCM_VERSION=5.6 +ARG AMDGPU_VERSION=${ROCM_VERSION} +ARG APT_PREF='Package: *\nPin: release o=repo.radeon.com\nPin-Priority: 600' + +CMD ["/bin/bash"] + +RUN echo "$APT_PREF" > /etc/apt/preferences.d/rocm-pin-600 ENV DEBIAN_FRONTEND noninteractive -ENV MIGRAPHX_DISABLE_FAST_GELU=1 -RUN apt-get clean && apt-get update && apt-get install -y locales unzip +RUN apt-get update && \ + apt-get install -y --no-install-recommends ca-certificates curl libnuma-dev gnupg && \ + curl -sL https://repo.radeon.com/rocm/rocm.gpg.key | apt-key add - &&\ + printf "deb [arch=amd64] https://repo.radeon.com/rocm/apt/$ROCM_VERSION/ jammy main" | tee /etc/apt/sources.list.d/rocm.list && \ + printf "deb [arch=amd64] https://repo.radeon.com/amdgpu/$AMDGPU_VERSION/ubuntu jammy main" | tee /etc/apt/sources.list.d/amdgpu.list && \ + apt-get update && apt-get install -y --no-install-recommends \ + sudo \ + libelf1 \ + kmod \ + file \ + python3 \ + python3-pip \ + rocm-dev \ + rocm-libs \ + build-essential && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +RUN groupadd -g 109 render + +# Upgrade to meet security requirements +RUN apt-get update -y && apt-get upgrade -y && apt-get autoremove -y && \ + apt-get install -y locales cifs-utils wget half libnuma-dev lsb-release && \ + apt-get clean -y + +ENV MIGRAPHX_DISABLE_FAST_GELU=1 RUN locale-gen en_US.UTF-8 RUN update-locale LANG=en_US.UTF-8 ENV LC_ALL C.UTF-8 @@ -14,25 +44,40 @@ ENV LANG C.UTF-8 WORKDIR /stage -ADD scripts /tmp/scripts -RUN /tmp/scripts/install_os_deps.sh +# Cmake +ENV CMAKE_VERSION=3.27.3 +RUN cd /usr/local && \ + wget -q https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz && \ + tar -zxf /usr/local/cmake-3.27.3-Linux-x86_64.tar.gz --strip=1 -C /usr + +# ccache +RUN mkdir -p /tmp/ccache && \ + cd /tmp/ccache && \ + wget -q -O - https://github.com/ccache/ccache/releases/download/v4.7.4/ccache-4.7.4-linux-x86_64.tar.xz | tar --strip 1 -J -xf - && \ + cp /tmp/ccache/ccache /usr/bin && \ + rm -rf /tmp/ccache + +# Install Conda +ENV PATH /opt/miniconda/bin:${PATH} +RUN wget --quiet https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda.sh --no-check-certificate && /bin/bash ~/miniconda.sh -b -p /opt/miniconda && \ + conda init bash && \ + conda config --set auto_activate_base false && \ + conda update --all && \ + rm ~/miniconda.sh && conda clean -ya + +# Conda base patch +RUN pip install cryptography==41.0.0 -# from rocm/pytorch's image, work around ucx's dlopen replacement conflicting with shared provider -RUN cd /opt/mpi_install/ucx/build &&\ - make clean &&\ - ../contrib/configure-release --prefix=/opt/ucx --without-rocm &&\ - make -j $(nproc) &&\ - make install +# Create migraphx-ci environment +ENV CONDA_ENVIRONMENT_PATH /opt/miniconda/envs/migraphx-ci +ENV CONDA_DEFAULT_ENV migraphx-ci +RUN conda create -y -n ${CONDA_DEFAULT_ENV} python=3.8 +ENV PATH ${CONDA_ENVIRONMENT_PATH}/bin:${PATH} -RUN apt-get update &&\ - apt-get install -y half libnuma-dev +# Enable migraphx-ci environment +SHELL ["conda", "run", "-n", "migraphx-ci", "/bin/bash", "-c"] -# Install rbuild -RUN pip3 install https://github.com/RadeonOpenCompute/rbuild/archive/master.tar.gz numpy yapf==0.28.0 +# Install migraphx +RUN apt update && apt install -y migraphx -# Install MIGraphX from source -RUN mkdir -p /migraphx -RUN cd /migraphx && git clone --depth=1 --branch ${MIGRAPHX_VERSION} https://github.com/ROCmSoftwarePlatform/AMDMIGraphX src -RUN cd /migraphx && rbuild package --cxx /opt/rocm/llvm/bin/clang++ -d /migraphx/deps -B /migraphx/build -S /migraphx/src/ -DPYTHON_EXECUTABLE=/usr/bin/python3 -RUN dpkg -i /migraphx/build/*.deb -RUN rm -rf /migraphx +RUN pip install numpy packaging diff --git a/tools/ci_build/github/linux/docker/scripts/install_dotnet.sh b/tools/ci_build/github/linux/docker/scripts/install_dotnet.sh new file mode 100755 index 0000000000000..c4689ed19c148 --- /dev/null +++ b/tools/ci_build/github/linux/docker/scripts/install_dotnet.sh @@ -0,0 +1,23 @@ +#!/bin/bash +set -e -x + +if [ -f /etc/redhat-release ]; then + # If you found the following command went successfully but dotnet command still reports no sdk was found, most likely + # it was because the dotnet packages were installed from more than one dnf repos. + dnf install -y dotnet-sdk-6.0 dotnet-runtime-6.0 +elif [ -f /etc/os-release ]; then + # Get Ubuntu version + declare repo_version + repo_version=$(if command -v lsb_release &> /dev/null; then lsb_release -r -s; else grep -oP '(?<=^VERSION_ID=).+' /etc/os-release | tr -d '"'; fi) + # Download Microsoft signing key and repository + wget "https://packages.microsoft.com/config/ubuntu/$repo_version/packages-microsoft-prod.deb" -O packages-microsoft-prod.deb + # Install Microsoft signing key and repository + dpkg -i packages-microsoft-prod.deb + # Clean up + rm packages-microsoft-prod.deb + # Update packages + apt-get update && apt-get install -y dotnet-sdk-6.0 +else + echo "Unsupported OS" + exit 1 +fi diff --git a/tools/ci_build/github/linux/docker/scripts/install_java.sh b/tools/ci_build/github/linux/docker/scripts/install_java.sh new file mode 100755 index 0000000000000..d11e29f693b8b --- /dev/null +++ b/tools/ci_build/github/linux/docker/scripts/install_java.sh @@ -0,0 +1,12 @@ +#!/bin/bash +set -e -x + +if [ -f /etc/redhat-release ]; then + dnf install -y java-11-openjdk-devel \ + && dnf clean dbcache +elif [ -f /etc/os-release ]; then + apt-get update && apt-get install -y openjdk-11-jdk +else + echo "Unsupported OS" + exit 1 +fi 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 a0f78de829878..3e872d17504a1 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 @@ -3,11 +3,11 @@ set -e -x SCRIPT_DIR="$( dirname "${BASH_SOURCE[0]}" )" INSTALL_DEPS_DISTRIBUTED_SETUP=false - +INSTALL_PREFIX='/usr' while getopts p:d:v:tmur parameter_Option do case "${parameter_Option}" in -p) echo "Python version is no longer accepted as an input to this script. Ignoring the input argument -p.";; +p) INSTALL_PREFIX=${OPTARG};; d) DEVICE_TYPE=${OPTARG};; v) echo "Cuda version is no longer accepted as an input to this script. Ignoring the input argument -v.";; t) echo "Installing python training dependencies argument is no longer accepted as an input to this script. Ignoring the input argument -t.";; @@ -59,7 +59,7 @@ GLIBC_VERSION=$(getconf GNU_LIBC_VERSION | cut -f 2 -d \.) DISTRIBUTOR=$(lsb_release -i -s) -if [[ "$DISTRIBUTOR" = "CentOS" && $SYS_LONG_BIT = "64" ]]; then +if [[ ("$DISTRIBUTOR" = "CentOS" || "$DISTRIBUTOR" = "RedHatEnterprise") && $SYS_LONG_BIT = "64" ]]; then LIBDIR="lib64" else LIBDIR="lib" @@ -71,17 +71,18 @@ if [[ $SYS_LONG_BIT = "64" && "$GLIBC_VERSION" -gt "9" ]]; then tar --strip 1 -xf /tmp/azcopy/azcopy.tar.gz -C /tmp/azcopy cp /tmp/azcopy/azcopy /usr/bin echo "Installing cmake" - GetFile https://github.com/Kitware/CMake/releases/download/v3.24.3/cmake-3.24.3-Linux-x86_64.tar.gz /tmp/src/cmake-3.24.3-Linux-x86_64.tar.gz - tar -zxf /tmp/src/cmake-3.24.3-Linux-x86_64.tar.gz --strip=1 -C /usr + GetFile https://github.com/Kitware/CMake/releases/download/v3.27.3/cmake-3.27.3-Linux-x86_64.tar.gz /tmp/src/cmake-3.27.3-Linux-x86_64.tar.gz + tar -zxf /tmp/src/cmake-3.27.3-Linux-x86_64.tar.gz --strip=1 -C /usr echo "Installing Node.js" - GetFile https://nodejs.org/dist/v16.14.2/node-v16.14.2-linux-x64.tar.xz /tmp/src/node-v16.14.2-linux-x64.tar.xz - tar -xf /tmp/src/node-v16.14.2-linux-x64.tar.xz --strip=1 -C /usr + # 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.xz /tmp/src/node-v18.17.1-linux-x64.tar.xz + tar -xf /tmp/src/node-v18.17.1-linux-x64.tar.xz --strip=1 -C /usr else echo "Installing cmake" - GetFile https://github.com/Kitware/CMake/releases/download/v3.24.3/cmake-3.24.3.tar.gz /tmp/src/cmake-3.24.3.tar.gz - tar -xf /tmp/src/cmake-3.24.3.tar.gz -C /tmp/src + GetFile https://github.com/Kitware/CMake/releases/download/v3.27.3/cmake-3.27.3.tar.gz /tmp/src/cmake-3.27.3.tar.gz + tar -xf /tmp/src/cmake-3.27.3.tar.gz -C /tmp/src pushd . - cd /tmp/src/cmake-3.24.3 + cd /tmp/src/cmake-3.27.3 ./bootstrap --prefix=/usr --parallel=$(getconf _NPROCESSORS_ONLN) --system-bzip2 --system-curl --system-zlib --system-expat make -j$(getconf _NPROCESSORS_ONLN) make install @@ -91,7 +92,7 @@ fi cd /tmp/src if ! [ -x "$(command -v protoc)" ]; then - source ${0/%install_os_deps\.sh/install_protobuf\.sh} + $SCRIPT_DIR/install_protobuf.sh -p $INSTALL_PREFIX fi if [ $DEVICE_TYPE = "gpu" ]; then diff --git a/tools/ci_build/github/linux/docker/scripts/install_protobuf.sh b/tools/ci_build/github/linux/docker/scripts/install_protobuf.sh index 1a8aa8c6d16a8..31b5ca6f9e69b 100755 --- a/tools/ci_build/github/linux/docker/scripts/install_protobuf.sh +++ b/tools/ci_build/github/linux/docker/scripts/install_protobuf.sh @@ -11,41 +11,98 @@ d) DEP_FILE_PATH=${OPTARG};; esac done -EXTRA_CMAKE_ARGS="" + + +EXTRA_CMAKE_ARGS="-DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_CXX_STANDARD=17" case "$(uname -s)" in Darwin*) echo 'Building ONNX Runtime on Mac OS X' - EXTRA_CMAKE_ARGS="-DCMAKE_OSX_ARCHITECTURES=x86_64;arm64" + EXTRA_CMAKE_ARGS="$EXTRA_CMAKE_ARGS -DCMAKE_OSX_ARCHITECTURES=x86_64;arm64" + GCC_PATH=$(which clang) + GPLUSPLUS_PATH=$(which clang++) ;; Linux*) - # Depending on how the compiler has been configured when it was built, sometimes "gcc -dumpversion" shows the full version. - GCC_VERSION=$(gcc -dumpversion | cut -d . -f 1) - #-fstack-clash-protection prevents attacks based on an overlapping heap and stack. - if [ "$GCC_VERSION" -ge 8 ]; then + SYS_LONG_BIT=$(getconf LONG_BIT) + DISTRIBUTOR=$(lsb_release -i -s) + + if [[ ("$DISTRIBUTOR" = "CentOS" || "$DISTRIBUTOR" = "RedHatEnterprise") && $SYS_LONG_BIT = "64" ]]; then + LIBDIR="lib64" + else + LIBDIR="lib" + fi + EXTRA_CMAKE_ARGS="$EXTRA_CMAKE_ARGS -DCMAKE_INSTALL_LIBDIR=$LIBDIR" + # Depending on how the compiler has been configured when it was built, sometimes "gcc -dumpversion" shows the full version. + GCC_VERSION=$(gcc -dumpversion | cut -d . -f 1) + #-fstack-clash-protection prevents attacks based on an overlapping heap and stack. + if [ "$GCC_VERSION" -ge 8 ]; then CFLAGS="$CFLAGS -fstack-clash-protection" CXXFLAGS="$CXXFLAGS -fstack-clash-protection" - fi - ARCH=$(uname -m) - - if [ "$ARCH" == "x86_64" ] && [ "$GCC_VERSION" -ge 9 ]; then + fi + ARCH=$(uname -m) + GCC_PATH=$(which gcc) + GPLUSPLUS_PATH=$(which g++) + if [ "$ARCH" == "x86_64" ] && [ "$GCC_VERSION" -ge 9 ]; then CFLAGS="$CFLAGS -fcf-protection" CXXFLAGS="$CXXFLAGS -fcf-protection" - fi - export CFLAGS - export CXXFLAGS - ;; - *) - exit -1 + fi + export CFLAGS + export CXXFLAGS + ;; + *) + exit 1 esac -mkdir -p $INSTALL_PREFIX +mkdir -p "$INSTALL_PREFIX" + +if [ -x "$(command -v ninja)" ]; then + EXTRA_CMAKE_ARGS="$EXTRA_CMAKE_ARGS -G Ninja" +fi +echo "Installing abseil ..." +pushd . +absl_url=$(grep '^abseil_cpp' "$DEP_FILE_PATH" | cut -d ';' -f 2 ) +if [[ "$absl_url" = https* ]]; then + absl_url=$(echo $absl_url | sed 's/\.zip$/\.tar.gz/') + curl -sSL --retry 5 --retry-delay 10 --create-dirs --fail -L -o absl_src.tar.gz $absl_url + mkdir abseil + cd abseil + tar -zxf ../absl_src.tar.gz --strip=1 +else + cp $absl_url absl_src.zip + unzip absl_src.zip + cd */ +fi + +CC=$GCC_PATH CXX=$GPLUSPLUS_PATH cmake "." "-DABSL_PROPAGATE_CXX_STD=ON" "-DCMAKE_BUILD_TYPE=Release" "-DBUILD_TESTING=OFF" "-DABSL_USE_EXTERNAL_GOOGLETEST=ON" "-DCMAKE_PREFIX_PATH=$INSTALL_PREFIX" "-DCMAKE_INSTALL_PREFIX=$INSTALL_PREFIX" $EXTRA_CMAKE_ARGS +if [ -x "$(command -v ninja)" ]; then + ninja + ninja install +else + make -j$(getconf _NPROCESSORS_ONLN) + make install +fi +popd + +pushd . echo "Installing protobuf ..." -protobuf_url=$(grep '^protobuf' $DEP_FILE_PATH | cut -d ';' -f 2 | sed 's/\.zip$/\.tar.gz/') -curl -sSL --retry 5 --retry-delay 10 --create-dirs --fail -L -o protobuf_src.tar.gz $protobuf_url -mkdir protobuf -cd protobuf -tar -zxf ../protobuf_src.tar.gz --strip=1 -cmake ./cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_PREFIX -DCMAKE_POSITION_INDEPENDENT_CODE=ON -Dprotobuf_BUILD_TESTS=OFF -DCMAKE_BUILD_TYPE=Release -Dprotobuf_WITH_ZLIB_DEFAULT=OFF -Dprotobuf_BUILD_SHARED_LIBS=OFF $EXTRA_CMAKE_ARGS -make -j$(getconf _NPROCESSORS_ONLN) -make install -cd .. +protobuf_url=$(grep '^protobuf' $DEP_FILE_PATH | cut -d ';' -f 2 ) +if [[ "$protobuf_url" = https* ]]; then + protobuf_url=$(echo "$protobuf_url" | sed 's/\.zip$/\.tar.gz/') + curl -sSL --retry 5 --retry-delay 10 --create-dirs --fail -L -o protobuf_src.tar.gz "$protobuf_url" + mkdir protobuf + cd protobuf + tar -zxf ../protobuf_src.tar.gz --strip=1 +else + cp $protobuf_url protobuf_src.zip + unzip protobuf_src.zip + cd protobuf-* +fi + +CC=$GCC_PATH CXX=$GPLUSPLUS_PATH cmake . "-DCMAKE_INSTALL_PREFIX=$INSTALL_PREFIX" -DCMAKE_POSITION_INDEPENDENT_CODE=ON -Dprotobuf_BUILD_TESTS=OFF -DCMAKE_BUILD_TYPE=Release -Dprotobuf_WITH_ZLIB_DEFAULT=OFF -Dprotobuf_BUILD_SHARED_LIBS=OFF "-DCMAKE_PREFIX_PATH=$INSTALL_PREFIX" $EXTRA_CMAKE_ARGS -Dprotobuf_ABSL_PROVIDER=package +if [ -x "$(command -v ninja)" ]; then + ninja + ninja install +else + make -j$(getconf _NPROCESSORS_ONLN) + make install +fi +popd diff --git a/tools/ci_build/github/linux/docker/scripts/manylinux/install_centos.sh b/tools/ci_build/github/linux/docker/scripts/manylinux/install_centos.sh index dc4eac230f1a0..63b953a95add6 100755 --- a/tools/ci_build/github/linux/docker/scripts/manylinux/install_centos.sh +++ b/tools/ci_build/github/linux/docker/scripts/manylinux/install_centos.sh @@ -1,12 +1,18 @@ #!/bin/bash set -e -os_major_version=$(cat /etc/redhat-release | tr -dc '0-9.'|cut -d \. -f1) +os_major_version=$(tr -dc '0-9.' < /etc/redhat-release |cut -d \. -f1) echo "installing for os major version : $os_major_version" -yum install -y which gdb redhat-lsb-core expat-devel tar unzip zlib-devel make libunwind bzip2 bzip2-devel - +if [ "$os_major_version" -gt 7 ]; then + PACKAGE_MANAGER="dnf" + $PACKAGE_MANAGER install -y which redhat-lsb-core expat-devel tar unzip zlib-devel make bzip2 bzip2-devel perl-IPC-Cmd openssl-devel wget +else + PACKAGE_MANAGER="yum" + $PACKAGE_MANAGER install -y which redhat-lsb-core expat-devel tar unzip zlib-devel make libunwind bzip2 bzip2-devel perl-IPC-Cmd openssl-devel wget +fi +rpm -Uvh https://packages.microsoft.com/config/centos/$os_major_version/packages-microsoft-prod.rpm # Install Java # Install automatic documentation generation dependencies -yum install -y java-11-openjdk-devel graphviz +$PACKAGE_MANAGER install -y msopenjdk-11 graphviz 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 c34abbd2ba873..8c79918120d8d 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 @@ -3,39 +3,38 @@ set -e -x # Development tools and libraries if [ -f /etc/redhat-release ]; then - yum update && yum -y install graphviz - os_major_version=$(cat /etc/redhat-release | tr -dc '0-9.'|cut -d \. -f1) + dnf -y install graphviz elif [ -f /etc/os-release ]; then apt-get update && apt-get install -y graphviz - os_major_version=$(cat /etc/os-release | tr -dc '0-9.'|cut -d \. -f1) else echo "Unsupported OS" exit 1 fi +# Install dotnet +LOCAL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &> /dev/null && pwd)" +PARENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." &> /dev/null && pwd)" +# ShellCheck is unable to follow dynamic paths, such as source "$somedir/file". +# shellcheck disable=SC1091 +source "$PARENT_DIR/install_dotnet.sh" + if [ ! -d "/opt/conda/bin" ]; then PYTHON_EXES=("/opt/python/cp38-cp38/bin/python3.8" "/opt/python/cp39-cp39/bin/python3.9" "/opt/python/cp310-cp310/bin/python3.10" "/opt/python/cp311-cp311/bin/python3.11") else PYTHON_EXES=("/opt/conda/bin/python") fi -SYS_LONG_BIT=$(getconf LONG_BIT) mkdir -p /tmp/src -GLIBC_VERSION=$(getconf GNU_LIBC_VERSION | cut -f 2 -d \.) - -if [[ $SYS_LONG_BIT = "64" ]]; then - LIBDIR="lib64" -else - LIBDIR="lib" -fi cd /tmp/src -source $(cd "$(dirname "${BASH_SOURCE[0]}")" &> /dev/null && pwd)/install_shared_deps.sh +# shellcheck disable=SC1091 +source "$LOCAL_DIR/install_shared_deps.sh" cd /tmp/src if ! [ -x "$(command -v protoc)" ]; then - source ${0/%install_deps.sh/..\/install_protobuf.sh} +# shellcheck disable=SC1091 + source "$PARENT_DIR/install_protobuf.sh" fi export ONNX_ML=1 @@ -43,7 +42,7 @@ export CMAKE_ARGS="-DONNX_GEN_PB_TYPE_STUBS=OFF -DONNX_WERROR=OFF" for PYTHON_EXE in "${PYTHON_EXES[@]}" do - ${PYTHON_EXE} -m pip install -r ${0/%install_deps\.sh/requirements\.txt} + ${PYTHON_EXE} -m pip install -r "${0/%install_deps\.sh/requirements\.txt}" done cd / diff --git a/tools/ci_build/github/linux/docker/scripts/manylinux/install_deps_aten.sh b/tools/ci_build/github/linux/docker/scripts/manylinux/install_deps_aten.sh index 08d6caa384472..1f85f72aef423 100755 --- a/tools/ci_build/github/linux/docker/scripts/manylinux/install_deps_aten.sh +++ b/tools/ci_build/github/linux/docker/scripts/manylinux/install_deps_aten.sh @@ -11,7 +11,7 @@ else PYTHON_EXES=("/opt/conda/bin/python") fi -os_major_version=$(cat /etc/redhat-release | tr -dc '0-9.'|cut -d \. -f1) +os_major_version=$(tr -dc '0-9.' < /etc/redhat-release |cut -d \. -f1) SYS_LONG_BIT=$(getconf LONG_BIT) mkdir -p /tmp/src @@ -19,7 +19,7 @@ GLIBC_VERSION=$(getconf GNU_LIBC_VERSION | cut -f 2 -d \.) DISTRIBUTOR=$(lsb_release -i -s) -if [[ "$DISTRIBUTOR" = "CentOS" && $SYS_LONG_BIT = "64" ]]; then +if [[ ("$DISTRIBUTOR" = "CentOS" || "$DISTRIBUTOR" = "RedHatEnterprise") && $SYS_LONG_BIT = "64" ]]; then LIBDIR="lib64" else LIBDIR="lib" diff --git a/tools/ci_build/github/linux/docker/scripts/manylinux/install_deps_eager.sh b/tools/ci_build/github/linux/docker/scripts/manylinux/install_deps_eager.sh index 04a038ca65997..ad3366b0bb3b6 100755 --- a/tools/ci_build/github/linux/docker/scripts/manylinux/install_deps_eager.sh +++ b/tools/ci_build/github/linux/docker/scripts/manylinux/install_deps_eager.sh @@ -11,7 +11,7 @@ else PYTHON_EXES=("/opt/conda/bin/python") fi -os_major_version=$(cat /etc/redhat-release | tr -dc '0-9.'|cut -d \. -f1) +os_major_version=$(tr -dc '0-9.' < /etc/redhat-release |cut -d \. -f1) SYS_LONG_BIT=$(getconf LONG_BIT) mkdir -p /tmp/src @@ -19,7 +19,7 @@ GLIBC_VERSION=$(getconf GNU_LIBC_VERSION | cut -f 2 -d \.) DISTRIBUTOR=$(lsb_release -i -s) -if [[ "$DISTRIBUTOR" = "CentOS" && $SYS_LONG_BIT = "64" ]]; then +if [[ ("$DISTRIBUTOR" = "CentOS" || "$DISTRIBUTOR" = "RedHatEnterprise") && $SYS_LONG_BIT = "64" ]]; then LIBDIR="lib64" else LIBDIR="lib" diff --git a/tools/ci_build/github/linux/docker/scripts/manylinux/install_deps_lort.sh b/tools/ci_build/github/linux/docker/scripts/manylinux/install_deps_lort.sh index e9f6f054b114e..3bca6413100a2 100755 --- a/tools/ci_build/github/linux/docker/scripts/manylinux/install_deps_lort.sh +++ b/tools/ci_build/github/linux/docker/scripts/manylinux/install_deps_lort.sh @@ -5,19 +5,7 @@ set -e -x yum -y install \ graphviz -os_major_version=$(cat /etc/redhat-release | tr -dc '0-9.'|cut -d \. -f1) - -SYS_LONG_BIT=$(getconf LONG_BIT) mkdir -p /tmp/src -GLIBC_VERSION=$(getconf GNU_LIBC_VERSION | cut -f 2 -d \.) - -DISTRIBUTOR=$(lsb_release -i -s) - -if [[ "$DISTRIBUTOR" = "CentOS" && $SYS_LONG_BIT = "64" ]]; then - LIBDIR="lib64" -else - LIBDIR="lib" -fi cd /tmp/src source $(cd "$(dirname "${BASH_SOURCE[0]}")" &> /dev/null && pwd)/install_shared_deps.sh @@ -31,6 +19,20 @@ fi export ONNX_ML=1 export CMAKE_ARGS="-DONNX_GEN_PB_TYPE_STUBS=OFF -DONNX_WERROR=OFF" +/opt/python/cp39-cp39/bin/python3.9 -m pip install transformers +# beartype is installed here so that onnxscript installation step won't +# install a version PyTorch doesn't like. Once beartype fixes this problem. +# We can remove this line. +/opt/python/cp39-cp39/bin/python3.9 -m pip install beartype==0.15.0 + +cd /usr/local/ +echo "Cloning ONNX Script" +git clone --recursive https://github.com/microsoft/onnxscript.git +cd onnxscript +/opt/python/cp39-cp39/bin/python3.9 -m pip install -r requirements-dev.txt +/opt/python/cp39-cp39/bin/python3.9 setup.py install +cd ~ && /opt/python/cp39-cp39/bin/python3.9 -c "import onnxscript; print(f'Installed ONNX Script: {onnxscript.__version__}')" + cd /usr/local echo "Cloning Pytorch" git clone --recursive https://github.com/pytorch/pytorch.git @@ -42,17 +44,5 @@ echo "Building and installing Pytorch" VERBOSE=1 BUILD_LAZY_TS_BACKEND=1 /opt/python/cp39-cp39/bin/python3.9 setup.py install cd ~ && /opt/python/cp39-cp39/bin/python3.9 -c "import torch; print(f'Installed Pytorch: {torch.__version__}')" -cd /usr/local/ -echo "Cloning TorchDynamo" -git clone --recursive https://github.com/pytorch/torchdynamo.git -cd torchdynamo -echo "Installing TorchDynamo requirements" -/opt/python/cp39-cp39/bin/python3.9 -m pip install transformers -/opt/python/cp39-cp39/bin/python3.9 -m pip install -r requirements.txt -echo "Installing TorchDynamo" -/opt/python/cp39-cp39/bin/python3.9 setup.py install -cd ~ && /opt/python/cp39-cp39/bin/python3.9 -c "import torch; print(f'Installed Pytorch: {torch.__version__}')" -cd ~ && /opt/python/cp39-cp39/bin/python3.9 -c "import torchdynamo; print(f'Installed TorchDynamo: {torchdynamo.__path__}')" - cd / rm -rf /tmp/src 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 old mode 100644 new mode 100755 index 92e1dfbe465fe..d641084631564 --- 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 @@ -53,8 +53,9 @@ cmake --build build-cmake mv ./build-cmake/ninja /usr/bin echo "Installing Node.js" -GetFile https://nodejs.org/dist/v16.14.2/node-v16.14.2-linux-x64.tar.gz /tmp/src/node-v16.14.2-linux-x64.tar.gz -tar --strip 1 -xf /tmp/src/node-v16.14.2-linux-x64.tar.gz -C /usr +# 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 +tar --strip 1 -xf /tmp/src/node-v18.17.1-linux-x64.tar.gz -C /usr echo "Installing CCache" mkdir -p /tmp/ccache diff --git a/tools/ci_build/github/linux/docker/scripts/manylinux/requirements.txt b/tools/ci_build/github/linux/docker/scripts/manylinux/requirements.txt index 33585504b4d12..6b8003c01c24d 100644 --- a/tools/ci_build/github/linux/docker/scripts/manylinux/requirements.txt +++ b/tools/ci_build/github/linux/docker/scripts/manylinux/requirements.txt @@ -4,7 +4,8 @@ mypy pytest setuptools>=41.4.0 wheel -onnx==1.13.1 +git+http://github.com/onnx/onnx.git@e2525550194ce3d8a2c4a3af451c9d9b3ae6650e#egg=onnx protobuf==3.20.2 -sympy==1.10.1 +sympy==1.12 flatbuffers +neural-compressor>=2.2.1 diff --git a/tools/ci_build/github/linux/docker/scripts/requirements.txt b/tools/ci_build/github/linux/docker/scripts/requirements.txt index 2f0b78821ab2d..9dbe856753faa 100644 --- a/tools/ci_build/github/linux/docker/scripts/requirements.txt +++ b/tools/ci_build/github/linux/docker/scripts/requirements.txt @@ -5,9 +5,9 @@ mypy pytest setuptools>=41.4.0 wheel>=0.35.1 -onnx==1.13.1 +git+http://github.com/onnx/onnx.git@e2525550194ce3d8a2c4a3af451c9d9b3ae6650e#egg=onnx argparse -sympy==1.10.1 +sympy==1.12 flatbuffers protobuf==3.20.2 packaging diff --git a/tools/ci_build/github/linux/docker/scripts/setup_rocm_yum_repo.sh b/tools/ci_build/github/linux/docker/scripts/setup_rocm_yum_repo.sh new file mode 100755 index 0000000000000..fcd9086061227 --- /dev/null +++ b/tools/ci_build/github/linux/docker/scripts/setup_rocm_yum_repo.sh @@ -0,0 +1,43 @@ +#!/bin/bash +set -e -x + +# version +ROCM_VERSION=5.6 + +while getopts "r:" parameter_Option +do case "${parameter_Option}" +in +r) ROCM_VERSION=${OPTARG};; +esac +done + +tee /etc/yum.repos.d/amdgpu.repo <=0.8.1 +pydantic<2.0.0 diff --git a/tools/ci_build/github/linux/ort_minimal/build_ort_and_check_binary_size.py b/tools/ci_build/github/linux/ort_minimal/build_ort_and_check_binary_size.py index 1ffdb33ee3a38..e8d8094c4968c 100644 --- a/tools/ci_build/github/linux/ort_minimal/build_ort_and_check_binary_size.py +++ b/tools/ci_build/github/linux/ort_minimal/build_ort_and_check_binary_size.py @@ -66,16 +66,7 @@ def main(): [sys.executable, str(REPO_ROOT / "tools/ci_build/build.py"), *build_params] + (["--cmake_extra_defines", "ADD_DEBUG_INFO_TO_MINIMAL_BUILD=ON"] if args.with_debug_info else []) # put the following options last so they don't get overridden by build_params - + [ - f"--build_dir={args.build_dir}", - f"--config={build_config}", - "--update", - "--build", - "--parallel", - "--test", - "--path_to_protoc_exe", - str(pathlib.Path(args.build_dir) / "installed" / "bin" / "protoc"), - ] + + [f"--build_dir={args.build_dir}", f"--config={build_config}", "--update", "--build", "--parallel", "--test"] ) subprocess.run(build_command, check=True) diff --git a/tools/ci_build/github/linux/ort_minimal/nnapi_minimal_build_minimal_ort_and_run_tests.sh b/tools/ci_build/github/linux/ort_minimal/nnapi_minimal_build_minimal_ort_and_run_tests.sh index 1bf0ec1c05247..02f89f4e91e5c 100755 --- a/tools/ci_build/github/linux/ort_minimal/nnapi_minimal_build_minimal_ort_and_run_tests.sh +++ b/tools/ci_build/github/linux/ort_minimal/nnapi_minimal_build_minimal_ort_and_run_tests.sh @@ -34,7 +34,6 @@ python3 $ORT_ROOT/tools/ci_build/build.py \ --disable_ml_ops \ --disable_exceptions \ --include_ops_by_config $ORT_ROOT/onnxruntime/test/testdata/required_ops_and_types.config \ - --path_to_protoc_exe $ORT_ROOT/protobuf_install/bin/protoc \ --skip_tests # Push onnxruntime_test_all and testdata to emulator diff --git a/tools/ci_build/github/linux/run_build.sh b/tools/ci_build/github/linux/run_build.sh index 75008ec773d3f..43e1543890e3e 100755 --- a/tools/ci_build/github/linux/run_build.sh +++ b/tools/ci_build/github/linux/run_build.sh @@ -56,7 +56,6 @@ else _CUDNN_VERSION=$(echo $CUDNN_VERSION | cut -d. -f1-2) python3 $SCRIPT_DIR/../../build.py --build_dir /build \ --config Release $COMMON_BUILD_ARGS \ - --tensorrt_placeholder_builder \ --use_tensorrt --tensorrt_home /usr/lib/x86_64-linux-gnu/ \ --cuda_home /usr/local/cuda \ --cudnn_home /usr/lib/x86_64-linux-gnu/ $BUILD_EXTR_PAR diff --git a/tools/ci_build/github/linux/run_dockerbuild.sh b/tools/ci_build/github/linux/run_dockerbuild.sh index 401ede6386792..440752bc819de 100755 --- a/tools/ci_build/github/linux/run_dockerbuild.sh +++ b/tools/ci_build/github/linux/run_dockerbuild.sh @@ -95,13 +95,6 @@ elif [ $BUILD_DEVICE = "gpu" ]; then $GET_DOCKER_IMAGE_CMD --repository "onnxruntime-$IMAGE" \ --docker-build-args="--build-arg BASEIMAGE=nvcr.io/nvidia/cuda:11.8.0-cudnn8-devel-${BUILD_OS} --build-arg BUILD_USER=onnxruntimedev --build-arg BUILD_UID=$(id -u) --build-arg PYTHON_VERSION=${PYTHON_VER} --build-arg INSTALL_DEPS_EXTRA_ARGS=\"${INSTALL_DEPS_EXTRA_ARGS}\" --build-arg USE_CONDA=${USE_CONDA} --network=host" \ --dockerfile Dockerfile.ubuntu_gpu_training --context . -elif [[ $BUILD_DEVICE = "tensorrt"* ]]; then - IMAGE="$BUILD_OS-cuda11.8-cudnn8.7-tensorrt8.6" - DOCKER_FILE=Dockerfile.ubuntu_tensorrt - - $GET_DOCKER_IMAGE_CMD --repository "onnxruntime-$IMAGE" \ - --docker-build-args="--build-arg BUILD_USER=onnxruntimedev --build-arg BUILD_UID=$(id -u) --build-arg PYTHON_VERSION=${PYTHON_VER}" \ - --dockerfile $DOCKER_FILE --context . elif [[ $BUILD_DEVICE = "openvino"* ]]; then BUILD_ARGS="--build-arg BUILD_USER=onnxruntimedev --build-arg BUILD_UID=$(id -u) --build-arg PYTHON_VERSION=3.8" IMAGE="$BUILD_OS-openvino" diff --git a/tools/ci_build/github/linux/run_python_dockerbuild.sh b/tools/ci_build/github/linux/run_python_dockerbuild.sh index a9c406a551cc9..18ac6482827f9 100755 --- a/tools/ci_build/github/linux/run_python_dockerbuild.sh +++ b/tools/ci_build/github/linux/run_python_dockerbuild.sh @@ -1,10 +1,14 @@ #!/bin/bash set -e -x -while getopts "x:i:" parameter_Option +BUILD_CONFIG="Release" + +while getopts "i:d:x:c:" parameter_Option do case "${parameter_Option}" in i) DOCKER_IMAGE=${OPTARG};; +d) DEVICE=${OPTARG};; x) BUILD_EXTR_PAR=${OPTARG};; +c) BUILD_CONFIG=${OPTARG};; esac done @@ -19,10 +23,10 @@ docker run --rm \ -e NIGHTLY_BUILD \ -e BUILD_BUILDNUMBER \ $ADDITIONAL_DOCKER_PARAMETER \ - $DOCKER_IMAGE tools/ci_build/github/linux/build_linux_arm64_python_package.sh $BUILD_EXTR_PAR + $DOCKER_IMAGE tools/ci_build/github/linux/build_linux_arm64_python_package.sh -d $DEVICE -c $BUILD_CONFIG -x $BUILD_EXTR_PAR -sudo rm -rf $BUILD_BINARIESDIRECTORY/Release/onnxruntime $BUILD_BINARIESDIRECTORY/Release/pybind11 \ - $BUILD_BINARIESDIRECTORY/Release/models $BUILD_BINARIESDIRECTORY/Release/_deps \ - $BUILD_BINARIESDIRECTORY/Release/CMakeFiles -cd $BUILD_BINARIESDIRECTORY/Release -find -executable -type f > $BUILD_BINARIESDIRECTORY/Release/perms.txt +sudo rm -rf $BUILD_BINARIESDIRECTORY/$BUILD_CONFIG/onnxruntime $BUILD_BINARIESDIRECTORY/$BUILD_CONFIG/pybind11 \ + $BUILD_BINARIESDIRECTORY/$BUILD_CONFIG/models $BUILD_BINARIESDIRECTORY/$BUILD_CONFIG/_deps \ + $BUILD_BINARIESDIRECTORY/$BUILD_CONFIG/CMakeFiles +cd $BUILD_BINARIESDIRECTORY/$BUILD_CONFIG +find -executable -type f > $BUILD_BINARIESDIRECTORY/$BUILD_CONFIG/perms.txt diff --git a/tools/ci_build/github/linux/run_python_dockertest.sh b/tools/ci_build/github/linux/run_python_dockertest.sh new file mode 100755 index 0000000000000..332dd9c7284c0 --- /dev/null +++ b/tools/ci_build/github/linux/run_python_dockertest.sh @@ -0,0 +1,29 @@ +#!/bin/bash +set -e -x +BUILD_CONFIG="Release" + +while getopts "i:d:x:c:" parameter_Option +do case "${parameter_Option}" +in +i) DOCKER_IMAGE=${OPTARG};; +d) DEVICE=${OPTARG};; +c) BUILD_CONFIG=${OPTARG};; +esac +done + +if [ $DEVICE = "GPU" ]; then + ADDITIONAL_DOCKER_PARAMETER="--gpus all" +fi + +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 \ + -w /onnxruntime_src \ + -e NIGHTLY_BUILD \ + -e BUILD_BUILDNUMBER \ + $ADDITIONAL_DOCKER_PARAMETER \ + $DOCKER_IMAGE tools/ci_build/github/linux/run_python_tests.sh -d $DEVICE -c $BUILD_CONFIG diff --git a/tools/ci_build/github/linux/run_python_tests.sh b/tools/ci_build/github/linux/run_python_tests.sh index d2a8a15e89269..f080c7e8c39d8 100755 --- a/tools/ci_build/github/linux/run_python_tests.sh +++ b/tools/ci_build/github/linux/run_python_tests.sh @@ -6,15 +6,17 @@ set -e -x BUILD_DEVICE="CPU" BUILD_CONFIG="Release" -while getopts "d:" parameter_Option +while getopts "d:c:" parameter_Option do case "${parameter_Option}" in #GPU or CPU. d) BUILD_DEVICE=${OPTARG};; +c) BUILD_CONFIG=${OPTARG};; esac done -cd $BUILD_BINARIESDIRECTORY +export PATH=/opt/python/cp38-cp38/bin:$PATH +cd /build files=(whl/*.whl) FILE_NAME="${files[0]}" FILE_NAME=$(basename $FILE_NAME) @@ -22,26 +24,27 @@ PYTHON_PACKAGE_NAME=$(echo "$FILE_NAME" | cut -f 1 -d '-') echo "Package name:$PYTHON_PACKAGE_NAME" -BUILD_ARGS="--build_dir $BUILD_BINARIESDIRECTORY --config $BUILD_CONFIG --test --skip_submodule_sync --parallel --enable_lto --build_wheel " +BUILD_ARGS="--build_dir /build --config $BUILD_CONFIG --test --skip_submodule_sync --parallel --enable_lto --build_wheel " + +ARCH=$(uname -m) if [ $ARCH == "x86_64" ]; then #ARM build machines do not have the test data yet. BUILD_ARGS="$BUILD_ARGS --enable_onnx_tests" fi if [ $BUILD_DEVICE == "GPU" ]; then - BUILD_ARGS="$BUILD_ARGS --use_cuda --use_tensorrt --cuda_version=11.6 --tensorrt_home=/usr --cuda_home=/usr/local/cuda-11.6 --cudnn_home=/usr/local/cuda-11.6" + BUILD_ARGS="$BUILD_ARGS --use_cuda --use_tensorrt --cuda_version=11.8 --tensorrt_home=/usr --cuda_home=/usr/local/cuda-11.8 --cudnn_home=/usr/local/cuda-11.8" fi # We assume the machine doesn't have gcc and python development header files, so we don't build onnxruntime from source -sudo rm -rf /build /onnxruntime_src -sudo ln -s $BUILD_SOURCESDIRECTORY /onnxruntime_src -python3 -m pip uninstall -y $PYTHON_PACKAGE_NAME ort-nightly-gpu ort-nightly onnxruntime onnxruntime-gpu onnxruntime-training onnxruntime-directml ort-nightly-directml onnx -qq -cp $BUILD_SOURCESDIRECTORY/tools/ci_build/github/linux/docker/scripts/manylinux/requirements.txt $BUILD_BINARIESDIRECTORY/requirements.txt -# Test ORT with the latest ONNX release. -sed -i "s/git+http:\/\/github\.com\/onnx\/onnx.*/onnx/" $BUILD_BINARIESDIRECTORY/requirements.txt -python3 -m pip install -r $BUILD_BINARIESDIRECTORY/requirements.txt -python3 -m pip install --find-links $BUILD_BINARIESDIRECTORY/whl $PYTHON_PACKAGE_NAME -ln -s /data/models $BUILD_BINARIESDIRECTORY -cd $BUILD_BINARIESDIRECTORY/$BUILD_CONFIG +python3 -m pip install --upgrade pip +# Install the packages that are needed for installing the onnxruntime python package +python3 -m pip install -r /build/$BUILD_CONFIG/requirements.txt +# Install the packages that are needed for running test scripts +python3 -m pip install pytest +# The "--no-index" flag is crucial. The local whl folder is just an additional source. Pypi's doc says "there is no +# ordering in the locations that are searched" if we don't disable the default one with "--no-index" +python3 -m pip install --no-index --find-links /build/whl $PYTHON_PACKAGE_NAME +cd /build/$BUILD_CONFIG # Restore file permissions -xargs -a $BUILD_BINARIESDIRECTORY/$BUILD_CONFIG/perms.txt chmod a+x -python3 $BUILD_SOURCESDIRECTORY/tools/ci_build/build.py $BUILD_ARGS --ctest_path '' +xargs -a perms.txt chmod a+x +python3 /onnxruntime_src/tools/ci_build/build.py $BUILD_ARGS --ctest_path '' diff --git a/tools/ci_build/github/linux/tvm/requirements.txt b/tools/ci_build/github/linux/tvm/requirements.txt index 2d7da4a2c22f3..52dccb5adbb6f 100644 --- a/tools/ci_build/github/linux/tvm/requirements.txt +++ b/tools/ci_build/github/linux/tvm/requirements.txt @@ -11,3 +11,4 @@ psutil xgboost cloudpickle pytest +attrs diff --git a/tools/ci_build/github/pai/pai_clean_device.sh b/tools/ci_build/github/pai/pai_clean_device.sh new file mode 100755 index 0000000000000..98b680d4f465c --- /dev/null +++ b/tools/ci_build/github/pai/pai_clean_device.sh @@ -0,0 +1,47 @@ +#!/bin/bash +set -ex + +usage() { echo "Usage: $0 [-n ] [-d ] [-r ]" 1>&2; exit 1; } + +while getopts "n:d:r:" parameter_Option +do case "${parameter_Option}" +in +n) AGENT_NAME=${OPTARG};; +d) TARGET_DEVICE=${OPTARG};; +r) DRIVER_RENDER=${OPTARG};; +*) usage ;; +esac +done + +echo "Agent Name: $AGENT_NAME, Target Device: $TARGET_DEVICE, Driver Render: $DRIVER_RENDER" + +echo -e "\n ---- Execute rocm-smi" +rocm-smi + +echo -e "\n ---- Execute rocm-smi --showpids" +rocm-smi --showpids + +echo -e "\n ---- Execute rocm-smi --showpidgpus" +rocm-smi --showpidgpus + +echo -e "\n ---- Execute rocm-smi --showpids detail" +rocm-smi --showpids | awk '$1 ~/[0-9]+/{if((NR>6)) {print $1}}' | xargs -I {} ps {} + +echo -e "\n ---- Execute rocm-smi --showmeminfo" +rocm-smi --showmeminfo vram vis_vram gtt + +echo -e "\n ---- Clean up processes that use the target device $TARGET_DEVICE" +GPU_USED_BY_PIDS=$(rocm-smi --showpidgpus) +PID_NUMBERS_LINES=$(echo "$GPU_USED_BY_PIDS" | grep -n "DRM device" | cut -d ":" -f 1) +PID_NUMBERS_LINES_ARRAY=($PID_NUMBERS_LINES) + +for ((i = 0; i < ${#PID_NUMBERS_LINES_ARRAY[@]}; i++)); do + PID_NUMBER_LINE=${PID_NUMBERS_LINES_ARRAY[$i]} + PID_NUMBER=$(echo "$GPU_USED_BY_PIDS" | awk '{print $2}' | sed -n "${PID_NUMBER_LINE}p") + GPU_USED_BY_PID_LINE=$((PID_NUMBER_LINE + 1)) + GPU_USED_BY_PID=$(echo "$GPU_USED_BY_PIDS" | sed -n "${GPU_USED_BY_PID_LINE}p" | sed -e 's/^[ ]*//g' | sed -e 's/[ ]*$//g') + if [ "$GPU_USED_BY_PID" == "$TARGET_DEVICE" ]; then + echo "kill pid: $PID_NUMBER, using gpu: $GPU_USED_BY_PID" + kill -9 "$PID_NUMBER" + fi +done diff --git a/tools/ci_build/github/pai/pai_get_thread.sh b/tools/ci_build/github/pai/pai_get_thread.sh deleted file mode 100755 index 5e2811d579b81..0000000000000 --- a/tools/ci_build/github/pai/pai_get_thread.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash - -agentName=$1 -finalCharacter=${agentName: -1} -echo "agent name $agentName" -echo "agent name final character : $finalCharacter" -targetRender=$((finalCharacter+128)) - -echo -e "\n ---- rocm-smi" -rocm-smi - -echo -e "\n ---- rocm-smi --showpids" -rocm-smi --showpids - -echo -e "\n ---- rocm-smi --showpidgpus" -rocm-smi --showpidgpus - -echo -e "\n ---- rocm-smi --showpids detail" -rocm-smi --showpids | awk '$1 ~/[0-9]+/{if((NR>6)) {print $1}}' | xargs -I {} ps {} - -echo -e "\n ---- rocm-smi --showmeminfo" -rocm-smi --showmeminfo vram vis_vram gtt - -echo -e "\n ---- show all renders" -lsof /dev/dri/renderD* - -echo -e "\n ---- show specific render" -lsof /dev/dri/renderD${targetRender} - -echo -e "\n ---- show specific render pids detail" -lsof /dev/dri/renderD${targetRender} | grep "mem" | awk '{print $2}' | xargs -I {} ps {} \ No newline at end of file diff --git a/tools/ci_build/github/pai/pai_huggingface_bert_large_test.sh b/tools/ci_build/github/pai/pai_huggingface_bert_large_test.sh new file mode 100755 index 0000000000000..fb4dbeb2e73d3 --- /dev/null +++ b/tools/ci_build/github/pai/pai_huggingface_bert_large_test.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +set -ex + +usage() { echo "Usage: $0 [-v ]" 1>&2; exit 1; } + +while getopts "v:" parameter_Option +do case "${parameter_Option}" +in +v) ROCM_VERSION=${OPTARG};; +*) usage ;; +esac +done + +MI200_DEVICE_NUMBERS=$(rocm-smi --showproductname | grep -c "MI250" | xargs) + +if [ "$MI200_DEVICE_NUMBERS" -gt "0" ]; then + RESULT_FILE=ci-mi200.huggingface.bert-large-rocm${ROCM_VERSION}.json +else + RESULT_FILE=ci-mi100.huggingface.bert-large-rocm${ROCM_VERSION}.json +fi + +python \ + /stage/huggingface-transformers/examples/pytorch/language-modeling/run_mlm.py \ + --model_name_or_path bert-large-uncased \ + --dataset_name wikitext \ + --dataset_config_name wikitext-2-raw-v1 \ + --do_train \ + --max_steps 260 \ + --logging_steps 20 \ + --output_dir ./test-mlm-bbu \ + --overwrite_output_dir \ + --per_device_train_batch_size 8 \ + --fp16 \ + --dataloader_num_workers 1 \ + --ort \ + --skip_memory_metrics + +cat ci-pipeline-actual.json + +python /onnxruntime_src/orttraining/tools/ci_test/compare_huggingface.py \ + ci-pipeline-actual.json \ + /onnxruntime_src/orttraining/tools/ci_test/results/"$RESULT_FILE" diff --git a/tools/ci_build/github/pai/requirements.txt b/tools/ci_build/github/pai/requirements.txt deleted file mode 100644 index a8ed785e41af0..0000000000000 --- a/tools/ci_build/github/pai/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -requests==2.26.0 diff --git a/tools/ci_build/github/pai/rocm-ci-pipeline-env.Dockerfile b/tools/ci_build/github/pai/rocm-ci-pipeline-env.Dockerfile index 605427ab7d4c2..89a7fe09c527f 100644 --- a/tools/ci_build/github/pai/rocm-ci-pipeline-env.Dockerfile +++ b/tools/ci_build/github/pai/rocm-ci-pipeline-env.Dockerfile @@ -1,16 +1,47 @@ -FROM rocm/pytorch:rocm5.4_ubuntu20.04_py3.7_pytorch_1.12.1 +# Refer to https://github.com/RadeonOpenCompute/ROCm-docker/blob/master/dev/Dockerfile-ubuntu-22.04-complete +FROM ubuntu:22.04 -WORKDIR /stage +ARG ROCM_VERSION=5.6 +ARG AMDGPU_VERSION=${ROCM_VERSION} +ARG APT_PREF='Package: *\nPin: release o=repo.radeon.com\nPin-Priority: 600' + +CMD ["/bin/bash"] + +RUN echo "$APT_PREF" > /etc/apt/preferences.d/rocm-pin-600 + +ENV DEBIAN_FRONTEND noninteractive + +RUN apt-get update && \ + apt-get install -y --no-install-recommends ca-certificates curl libnuma-dev gnupg && \ + curl -sL https://repo.radeon.com/rocm/rocm.gpg.key | apt-key add - &&\ + printf "deb [arch=amd64] https://repo.radeon.com/rocm/apt/$ROCM_VERSION/ jammy main" | tee /etc/apt/sources.list.d/rocm.list && \ + printf "deb [arch=amd64] https://repo.radeon.com/amdgpu/$AMDGPU_VERSION/ubuntu jammy main" | tee /etc/apt/sources.list.d/amdgpu.list && \ + apt-get update && apt-get install -y --no-install-recommends \ + sudo \ + libelf1 \ + kmod \ + file \ + python3 \ + python3-pip \ + rocm-dev \ + rocm-libs \ + build-essential && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* -# from rocm/pytorch's image, work around ucx's dlopen replacement conflicting with shared provider -RUN cd /opt/mpi_install/ucx/build &&\ - make clean &&\ - ../contrib/configure-release --prefix=/opt/ucx --without-rocm &&\ - make -j $(nproc) &&\ - make install +RUN groupadd -g 109 render + +RUN apt-get update -y && apt-get upgrade -y && apt-get autoremove -y libprotobuf\* protobuf-compiler\* && \ + rm -f /usr/local/bin/protoc && apt-get install -y locales unzip wget git && apt-get clean -y +RUN locale-gen en_US.UTF-8 +RUN update-locale LANG=en_US.UTF-8 +ENV LC_ALL C.UTF-8 +ENV LANG C.UTF-8 + +WORKDIR /stage # CMake -ENV CMAKE_VERSION=3.24.2 +ENV CMAKE_VERSION=3.27.3 RUN cd /usr/local && \ wget -q -O - https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz | tar zxf - ENV PATH=/usr/local/cmake-${CMAKE_VERSION}-linux-x86_64/bin:${PATH} @@ -22,31 +53,86 @@ RUN mkdir -p /tmp/ccache && \ cp /tmp/ccache/ccache /usr/bin && \ rm -rf /tmp/ccache +# Install Conda +ENV PATH /opt/miniconda/bin:${PATH} +RUN wget --quiet https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda.sh --no-check-certificate && /bin/bash ~/miniconda.sh -b -p /opt/miniconda && \ + conda init bash && \ + conda config --set auto_activate_base false && \ + conda update --all && \ + rm ~/miniconda.sh && conda clean -ya + +# Create rocm-ci environment +ENV CONDA_ENVIRONMENT_PATH /opt/miniconda/envs/rocm-ci +ENV CONDA_DEFAULT_ENV rocm-ci +RUN conda create -y -n ${CONDA_DEFAULT_ENV} python=3.8 +ENV PATH ${CONDA_ENVIRONMENT_PATH}/bin:${PATH} + +# Conda base patch +RUN pip install cryptography==41.0.0 + +# Enable rocm-ci environment +SHELL ["conda", "run", "-n", "rocm-ci", "/bin/bash", "-c"] + +# ln -sf is needed to make sure that version `GLIBCXX_3.4.30' is found +RUN ln -sf /usr/lib/x86_64-linux-gnu/libstdc++.so.6 ${CONDA_ENVIRONMENT_PATH}/bin/../lib/libstdc++.so.6 + +# Install Pytorch +RUN pip install install torch==2.0.1 torchvision==0.15.2 -f https://repo.radeon.com/rocm/manylinux/rocm-rel-${ROCM_VERSION}/ && \ + pip install torch-ort --no-dependencies + + +##### Install Cupy to decrease CPU utilization +# Install non dev openmpi +RUN wget https://download.open-mpi.org/release/open-mpi/v4.1/openmpi-4.1.5.tar.bz2 && \ + tar -jxf openmpi-4.1.5.tar.bz2 && \ + cd openmpi-4.1.5 && \ + ./configure --prefix=/opt/ompi && \ + make -j4 all && \ + make install && \ + cd ../ && \ + rm -r openmpi-4.1.5 && \ + rm openmpi-4.1.5.tar.bz2 + +# Install CuPy, No stable version is available +RUN git clone https://github.com/ROCmSoftwarePlatform/cupy && cd cupy && \ + git checkout fc251a808037f8a2270860c2a23a683bfc0de43e && \ + export CUPY_INSTALL_USE_HIP=1 && \ + export ROCM_HOME=/opt/rocm && \ + export HCC_AMDGPU_TARGET=gfx906,gfx908,gfx90a && \ + git submodule update --init && \ + pip install -e . --no-cache-dir -vvvv + +##### Install transformers to run tests # rocm-ci branch contains instrumentation needed for loss curves and perf RUN git clone https://github.com/microsoft/huggingface-transformers.git &&\ - cd huggingface-transformers &&\ - git checkout rocm-ci &&\ - pip install -e . + cd huggingface-transformers &&\ + git checkout rocm-ci &&\ + pip install -e . RUN pip install \ - numpy \ - onnx \ - cerberus \ - sympy \ - h5py \ - datasets==1.9.0 \ - requests \ - sacrebleu==1.5.1 \ - sacremoses \ - scipy \ - scikit-learn \ - tokenizers \ - sentencepiece \ - dill==0.3.4 \ - wget \ - pytorch_lightning==1.6.0 \ - pytest-xdist \ - pytest-rerunfailures - -RUN pip install torch-ort --no-dependencies + flatbuffers==2.0 \ + numpy==1.24.1 \ + onnx \ + cerberus \ + sympy \ + h5py \ + datasets==1.9.0 \ + requests \ + sacrebleu==1.5.1 \ + sacremoses \ + scipy==1.10.0 \ + scikit-learn \ + tokenizers \ + sentencepiece \ + wget \ + dill==0.3.4 \ + pytorch_lightning==1.6.0 \ + pytest-xdist \ + pytest-rerunfailures + ENV ORTMODULE_ONNX_OPSET_VERSION=15 + +ARG BUILD_UID=1001 +ARG BUILD_USER=onnxruntimedev +RUN adduser --uid $BUILD_UID $BUILD_USER +WORKDIR /home/$BUILD_USER diff --git a/tools/ci_build/github/pai/wrap_rocm_python_doc_publisher.sh b/tools/ci_build/github/pai/wrap_rocm_python_doc_publisher.sh deleted file mode 100755 index 6182bff85dca6..0000000000000 --- a/tools/ci_build/github/pai/wrap_rocm_python_doc_publisher.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -echo "HIP_VISIBLE_DEVICES=$HIP_VISIBLE_DEVICES" -echo "PythonManylinuxDir=$PythonManylinuxDir" - -$PythonManylinuxDir/bin/python3 -m pip install /build/Release/dist/*.whl -/onnxruntime_src/tools/ci_build/github/pai/buildtrainingdoc.sh $PythonManylinuxDir/bin/ /onnxruntime_src /build Release diff --git a/tools/ci_build/github/windows/extract_nuget_files.ps1 b/tools/ci_build/github/windows/extract_nuget_files.ps1 index cb53b79eb2033..68757e25b01f7 100644 --- a/tools/ci_build/github/windows/extract_nuget_files.ps1 +++ b/tools/ci_build/github/windows/extract_nuget_files.ps1 @@ -36,12 +36,15 @@ Foreach-Object { # copy android AAR. # for full build of onnxruntime Android AAR, there should only be one .aar file -# called onnxruntime-android-x.y.z.aar but sanity check that -$aars = Get-ChildItem $Env:BUILD_BINARIESDIRECTORY\nuget-artifact -Filter onnxruntime-android-*.aar - +# called onnxruntime-android-x.y.z.aar or onnxruntime-training-android-x.y.z.aar but sanity check that +$aars = Get-ChildItem $Env:BUILD_BINARIESDIRECTORY\nuget-artifact -Filter *.aar if ($aars.Count -eq 1) { $aar = $aars[0] - $target_dir = "$nuget_artifacts_dir\onnxruntime-android-aar" + $aar_prefix = "onnxruntime" + if ($aar -like "onnxruntime-training*") { + $aar_prefix = "onnxruntime-training" + } + $target_dir = "$nuget_artifacts_dir\$aar_prefix-android-aar" $target_file = "$target_dir\onnxruntime.aar" # remove '-mobile' and version info from filename New-Item -Path $target_dir -ItemType directory @@ -52,10 +55,24 @@ elseif ($aars.Count -gt 1) { Write-Error "Expected at most one Android .aar file but got: [$aars]" } - New-Item -Path $Env:BUILD_BINARIESDIRECTORY\RelWithDebInfo\_deps\protobuf-build\RelWithDebInfo -ItemType directory -Copy-Item -Path $nuget_artifacts_dir\onnxruntime-win-x64-*\lib\* -Destination $Env:BUILD_BINARIESDIRECTORY\RelWithDebInfo\RelWithDebInfo +# Check whether this is a training pipeline +$is_training_pipeline = $false +if (Test-Path -Path $nuget_artifacts_dir\onnxruntime-training-win-x64-*) { + $is_training_pipeline = $true + Write-Output "onnxruntime-training-win-x64-* dir exists. This is a training pipeline." +} + +# Copy onnxruntime and protoc binaries to the binaries dir as these are required +# by Microsoft.ML.OnnxRuntime.Tests.NetCoreApp +if ($is_training_pipeline) { + Copy-Item -Path $nuget_artifacts_dir\onnxruntime-training-win-x64-*\lib\* -Destination $Env:BUILD_BINARIESDIRECTORY\RelWithDebInfo\RelWithDebInfo +} +else { + Copy-Item -Path $nuget_artifacts_dir\onnxruntime-win-x64-*\lib\* -Destination $Env:BUILD_BINARIESDIRECTORY\RelWithDebInfo\RelWithDebInfo +} + Copy-Item -Path $Env:BUILD_BINARIESDIRECTORY\extra-artifact\protoc.exe $Env:BUILD_BINARIESDIRECTORY\RelWithDebInfo\_deps\protobuf-build\RelWithDebInfo "Get-ChildItem -Directory -Path $nuget_artifacts_dir\onnxruntime-*" @@ -71,4 +88,4 @@ foreach ($ort_dir in $ort_dirs) # List artifacts "Post copy artifacts" -Get-ChildItem -Recurse $nuget_artifacts_dir\ \ No newline at end of file +Get-ChildItem -Recurse $nuget_artifacts_dir\ diff --git a/tools/ci_build/github/windows/helpers.ps1 b/tools/ci_build/github/windows/helpers.ps1 index 30052ae93e1c8..6e81f901a8288 100644 --- a/tools/ci_build/github/windows/helpers.ps1 +++ b/tools/ci_build/github/windows/helpers.ps1 @@ -337,38 +337,173 @@ function Install-Pybind { cd build [string[]]$cmake_args = "..", "-DCMAKE_INSTALL_PREFIX=$install_prefix", "-DBUILD_TESTING=OFF" $cmake_args += $cmake_extra_args - $p = Start-Process -FilePath $cmake_path -ArgumentList $cmake_args -NoNewWindow -Wait -PassThru - $exitCode = $p.ExitCode - if ($exitCode -ne 0) { - Write-Host -Object "CMake command failed. Exitcode: $exitCode" - exit $exitCode + &$cmake_path $cmake_args + if ($lastExitCode -ne 0) { + Write-Host -Object "CMake command failed. Exitcode: $exitCode" + exit $lastExitCode } $msbuild_args = "-nodeReuse:false", "-nologo", "-nr:false", "-maxcpucount", "-p:UseMultiToolTask=true", "-p:configuration=`"$build_config`"" if ($use_cache) { - $msbuild_args += "/p:CLToolExe=cl.exe /p:CLToolPath=C:\ProgramData\chocolatey\bin /p:TrackFileAccess=false /p:UseMultiToolTask=true" + $msbuild_args += "/p:CLToolExe=cl.exe", "/p:CLToolPath=C:\ProgramData\chocolatey\bin", "/p:TrackFileAccess=false", "/p:UseMultiToolTask=true" } $final_args = $msbuild_args + "pybind11.sln" - Write-Host $final_args + &$msbuild_path $final_args + $final_args = $msbuild_args + "INSTALL.vcxproj" + &$msbuild_path $final_args + + Write-Host "Installing pybind finished." - $p = Start-Process -FilePath $msbuild_path -ArgumentList $final_args -NoNewWindow -Wait -PassThru - $exitCode = $p.ExitCode - if ($exitCode -ne 0) { - Write-Host -Object "Build pybind11.sln failed. Exitcode: $exitCode" - exit $exitCode + popd +} + +<# + .Description + The Install-Abseil function installs Google's abseil library from source. + + .PARAMETER cmake_path + The full path of cmake.exe + + .PARAMETER src_root + The full path of ONNX Runtime's top level source diretory + + .PARAMETER build_config + The value of CMAKE_BUILD_TYPE, can be Debug, Release, RelWithDebInfo or MinSizeRel. +#> +function Install-Abseil { + + param ( + [Parameter(Mandatory)][string]$cmake_path, + [Parameter(Mandatory)][string]$msbuild_path, + [Parameter(Mandatory)][string]$src_root, + [Parameter(Mandatory)][CMakeBuildType]$build_config, + [Parameter(Mandatory)][string[]]$cmake_extra_args + ) + + pushd . + $url=Get-DownloadURL -name abseil_cpp -src_root $src_root + Write-Host "Downloading abseil_cpp from $url" + $temp_dir = Get-TempDirectory + $absl_src_dir = Join-Path $temp_dir "abseil_cpp" + $download_finished = DownloadAndExtract -Uri $url -InstallDirectory $absl_src_dir -Force + if(-Not $download_finished){ + exit 1 + } + cd $absl_src_dir + cd * + + # Search patch.exe + $patch_path = 'C:\Program Files\Git\usr\bin\patch.exe' + if(-not (Test-Path $patch_path -PathType Leaf)){ + $git_command_path = (Get-Command -CommandType Application git)[0].Path + Write-Host "Git command path:$git_command_path" + $git_installation_folder = Split-Path -Path (Split-Path -Path $git_command_path) + $patch_path = Join-Path -Path $git_installation_folder "usr\bin\patch.exe" + } + if(Test-Path $patch_path -PathType Leaf){ + Write-Host "Patching abseil ..." + Get-Content $src_root\cmake\patches\abseil\absl_windows.patch | &$patch_path --ignore-whitespace -p1 + } else { + Write-Host "Skip patching abseil since we cannot find patch.exe at $patch_path" + } + + # Run cmake to generate Visual Studio sln file + [string[]]$cmake_args = ".", "-DABSL_PROPAGATE_CXX_STD=ON", "-DCMAKE_BUILD_TYPE=$build_config", "-DBUILD_TESTING=OFF", "-DABSL_USE_EXTERNAL_GOOGLETEST=ON", "-DCMAKE_PREFIX_PATH=$install_prefix", "-DCMAKE_INSTALL_PREFIX=$install_prefix" + $cmake_args += $cmake_extra_args + + &$cmake_path $cmake_args + if ($lastExitCode -ne 0) { + Write-Host -Object "CMake command failed. Exitcode: $exitCode" + exit $lastExitCode } + $msbuild_args = "-nodeReuse:false", "-nologo", "-nr:false", "-maxcpucount", "-p:UseMultiToolTask=true", "-p:configuration=`"$build_config`"" + + if ($use_cache) { + $msbuild_args += "/p:CLToolExe=cl.exe", "/p:CLToolPath=C:\ProgramData\chocolatey\bin", "/p:TrackFileAccess=false", "/p:UseMultiToolTask=true" + } + + + $final_args = $msbuild_args + "absl.sln" + &$msbuild_path $final_args + if ($lastExitCode -ne 0) { + exit $lastExitCode + } $final_args = $msbuild_args + "INSTALL.vcxproj" - $p = Start-Process -FilePath $msbuild_path -ArgumentList $final_args -NoNewWindow -Wait -PassThru - $exitCode = $p.ExitCode - if ($exitCode -ne 0) { - Write-Host -Object "Install pybind failed. Exitcode: $exitCode" - exit $exitCode + &$msbuild_path $final_args + if ($lastExitCode -ne 0) { + exit $lastExitCode + } + Write-Host "Installing absl finished." + popd +} + +<# + .Description + The Install-UTF8-Range function installs Google's utf8_range library from source. + utf8_range depends on Abseil. + + .PARAMETER cmake_path + The full path of cmake.exe + + .PARAMETER src_root + The full path of ONNX Runtime's top level source diretory + + .PARAMETER build_config + The value of CMAKE_BUILD_TYPE, can be Debug, Release, RelWithDebInfo or MinSizeRel. +#> +function Install-UTF8-Range { + + param ( + [Parameter(Mandatory)][string]$cmake_path, + [Parameter(Mandatory)][string]$msbuild_path, + [Parameter(Mandatory)][string]$src_root, + [Parameter(Mandatory)][CMakeBuildType]$build_config, + [Parameter(Mandatory)][string[]]$cmake_extra_args + ) + + pushd . + $url=Get-DownloadURL -name utf8_range -src_root $src_root + Write-Host "Downloading utf8_range from $url" + $temp_dir = Get-TempDirectory + $absl_src_dir = Join-Path $temp_dir "utf8_range" + $download_finished = DownloadAndExtract -Uri $url -InstallDirectory $absl_src_dir -Force + if(-Not $download_finished){ + exit 1 + } + cd $absl_src_dir + cd * + + # Run cmake to generate Visual Studio sln file + [string[]]$cmake_args = ".", "-Dutf8_range_ENABLE_TESTS=OFF", "-Dutf8_range_ENABLE_INSTALL=ON", "-DCMAKE_BUILD_TYPE=$build_config", "-DBUILD_TESTING=OFF", "-DCMAKE_PREFIX_PATH=$install_prefix", "-DCMAKE_INSTALL_PREFIX=$install_prefix" + $cmake_args += $cmake_extra_args + + &$cmake_path $cmake_args + if ($lastExitCode -ne 0) { + Write-Host -Object "CMake command failed. Exitcode: $exitCode" + exit $lastExitCode + } + + $msbuild_args = "-nodeReuse:false", "-nologo", "-nr:false", "-maxcpucount", "-p:UseMultiToolTask=true", "-p:configuration=`"$build_config`"" + + if ($use_cache) { + $msbuild_args += "/p:CLToolExe=cl.exe", "/p:CLToolPath=C:\ProgramData\chocolatey\bin", "/p:TrackFileAccess=false", "/p:UseMultiToolTask=true" } - Write-Host "Installing pybind finished." + + $final_args = $msbuild_args + "utf8_range.sln" + &$msbuild_path $final_args + if ($lastExitCode -ne 0) { + exit $lastExitCode + } + $final_args = $msbuild_args + "INSTALL.vcxproj" + &$msbuild_path $final_args + if ($lastExitCode -ne 0) { + exit $lastExitCode + } + Write-Host "Installing utf8_range finished." popd } @@ -408,14 +543,14 @@ function Install-Protobuf { } cd $protobuf_src_dir cd * - # Search patch.exe - $patch_path = 'C:\Program Files\Git\usr\bin\patch.exe' - if(-not (Test-Path $patch_path -PathType Leaf)){ + # Search patch.exe + $patch_path = 'C:\Program Files\Git\usr\bin\patch.exe' + if(-not (Test-Path $patch_path -PathType Leaf)){ $git_command_path = (Get-Command -CommandType Application git)[0].Path Write-Host "Git command path:$git_command_path" $git_installation_folder = Split-Path -Path (Split-Path -Path $git_command_path) $patch_path = Join-Path -Path $git_installation_folder "usr\bin\patch.exe" - } + } if(Test-Path $patch_path -PathType Leaf){ Write-Host "Patching protobuf ..." Get-Content $src_root\cmake\patches\protobuf\protobuf_cmake.patch | &$patch_path --ignore-whitespace -p1 @@ -424,38 +559,30 @@ function Install-Protobuf { } # Run cmake to generate Visual Studio sln file - [string[]]$cmake_args = ".", "-Dprotobuf_DISABLE_RTTI=ON", "-DCMAKE_BUILD_TYPE=$build_config", "-Dprotobuf_BUILD_TESTS=OFF", "-DBUILD_SHARED_LIBS=OFF", "-DCMAKE_PREFIX_PATH=$install_prefix", "-DCMAKE_INSTALL_PREFIX=$install_prefix", "-Dprotobuf_MSVC_STATIC_RUNTIME=OFF" + [string[]]$cmake_args = ".", "-Dprotobuf_DISABLE_RTTI=ON", "-DCMAKE_BUILD_TYPE=$build_config", "-Dprotobuf_BUILD_TESTS=OFF", "-Dprotobuf_USE_EXTERNAL_GTEST=ON", "-DBUILD_SHARED_LIBS=OFF", "-DCMAKE_PREFIX_PATH=$install_prefix", "-DCMAKE_INSTALL_PREFIX=$install_prefix", "-Dprotobuf_MSVC_STATIC_RUNTIME=OFF", "-Dprotobuf_ABSL_PROVIDER=package" $cmake_args += $cmake_extra_args - $p = Start-Process -FilePath $cmake_path -ArgumentList $cmake_args -NoNewWindow -Wait -PassThru - $exitCode = $p.ExitCode - if ($exitCode -ne 0) { - Write-Host -Object "CMake command failed. Exitcode: $exitCode" - exit $exitCode + &$cmake_path $cmake_args + if ($lastExitCode -ne 0) { + Write-Host -Object "CMake command failed. Exitcode: $exitCode" + exit $lastExitCode } - + $msbuild_args = "-nodeReuse:false", "-nologo", "-nr:false", "-maxcpucount", "-p:UseMultiToolTask=true", "-p:configuration=`"$build_config`"" if ($use_cache) { - $msbuild_args += "/p:CLToolExe=cl.exe /p:CLToolPath=C:\ProgramData\chocolatey\bin /p:TrackFileAccess=false /p:UseMultiToolTask=true" + $msbuild_args += "/p:CLToolExe=cl.exe", "/p:CLToolPath=C:\ProgramData\chocolatey\bin", "/p:TrackFileAccess=false", "/p:UseMultiToolTask=true" } $final_args = $msbuild_args + "protobuf.sln" - Write-Host $final_args - - $p = Start-Process -FilePath $msbuild_path -ArgumentList $final_args -NoNewWindow -Wait -PassThru - $exitCode = $p.ExitCode - if ($exitCode -ne 0) { - Write-Host -Object "Build protobuf.sln failed. Exitcode: $exitCode" - exit $exitCode + &$msbuild_path $final_args + if ($lastExitCode -ne 0) { + exit $lastExitCode } - $final_args = $msbuild_args + "INSTALL.vcxproj" - $p = Start-Process -FilePath $msbuild_path -ArgumentList $final_args -NoNewWindow -Wait -PassThru - $exitCode = $p.ExitCode - if ($exitCode -ne 0) { - Write-Host -Object "Install protobuf failed. Exitcode: $exitCode" - exit $exitCode + &$msbuild_path $final_args + if ($lastExitCode -ne 0) { + exit $lastExitCode } Write-Host "Installing protobuf finished." popd @@ -476,6 +603,9 @@ function Install-ONNX { pushd . + Write-Host "Uninstalling onnx and ignore errors if there is any..." + python.exe -m pip uninstall -y onnx -qq + Write-Host "Installing python packages..." $p = Start-Process -NoNewWindow -Wait -PassThru -FilePath "python.exe" -ArgumentList "-m", "pip", "install", "--disable-pip-version-check", "setuptools", "wheel", "numpy", "protobuf==$protobuf_version" $exitCode = $p.ExitCode @@ -493,6 +623,22 @@ function Install-ONNX { } cd $onnx_src_dir cd * + + # Search patch.exe + $patch_path = 'C:\Program Files\Git\usr\bin\patch.exe' + if(-not (Test-Path $patch_path -PathType Leaf)){ + $git_command_path = (Get-Command -CommandType Application git)[0].Path + Write-Host "Git command path:$git_command_path" + $git_installation_folder = Split-Path -Path (Split-Path -Path $git_command_path) + $patch_path = Join-Path -Path $git_installation_folder "usr\bin\patch.exe" + } + if(Test-Path $patch_path -PathType Leaf){ + Write-Host "Patching onnx ..." + Get-Content $src_root\cmake\patches\onnx\onnx.patch | &$patch_path --ignore-whitespace -p1 + } else { + Write-Host "Skip patching onnx since we cannot find patch.exe at $patch_path" + } + [String]$requirements_txt_content = "protobuf==$protobuf_version`n" foreach($line in Get-Content '.\requirements.txt') { if($line -match "^protobuf"){ @@ -509,16 +655,11 @@ function Install-ONNX { if($build_config -eq 'Debug'){ $Env:DEBUG='1' } - $Env:CMAKE_ARGS="-DONNX_USE_PROTOBUF_SHARED_LIBS=OFF -DProtobuf_USE_STATIC_LIBS=ON -DONNX_USE_LITE_PROTO=OFF" + $Env:CMAKE_ARGS="-DONNX_USE_PROTOBUF_SHARED_LIBS=OFF -DProtobuf_USE_STATIC_LIBS=ON -DONNX_USE_LITE_PROTO=OFF -DCMAKE_PREFIX_PATH=$install_prefix" - $p = Start-Process -NoNewWindow -Wait -PassThru -FilePath "python.exe" -ArgumentList "setup.py", "bdist_wheel" - $exitCode = $p.ExitCode - if ($exitCode -ne 0) { - Write-Host -Object "Generate wheel file failed. Exitcode: $exitCode" - exit $exitCode - } - Write-Host "Uninstalling onnx and ignore errors if there is any..." - python -m pip uninstall -y onnx -qq + python.exe "setup.py" "bdist_wheel" + + Write-Host "Installing the newly built ONNX python package" Get-ChildItem -Path dist/*.whl | foreach { $p = Start-Process -NoNewWindow -Wait -PassThru -FilePath "python.exe" -ArgumentList "-m", "pip", "--disable-pip-version-check", "install", "--upgrade", $_.fullname diff --git a/tools/ci_build/github/windows/install_protoc.ps1 b/tools/ci_build/github/windows/install_protoc.ps1 deleted file mode 100644 index ca506c49b78fa..0000000000000 --- a/tools/ci_build/github/windows/install_protoc.ps1 +++ /dev/null @@ -1,101 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -# This script depends on python.exe, cmake.exe and Visual C++ spectre-mitigated libs. -# Please setup AGENT_TEMPDIRECTORY env variable before running this script -# This file is very similar to install_third_party_deps.ps1 expect this one only installs protobuf. -# This file is mainly for cross-compiling use cases. - - param ( - [string]$cpu_arch = "x64", - [string]$build_config = "RelWithDebInfo", - [string]$install_prefix = ".", - [switch]$use_cache - ) - -. "$PSScriptRoot\helpers.ps1" - -$ort_src_root = (Get-Item $PSScriptRoot).parent.parent.parent.parent.FullName - -Write-Host "ONNX Runtime src root: $ort_src_root" - -$ErrorActionPreference = "Stop" - -$Env:Path = "$install_prefix\bin;" + $env:Path -$Env:MSBUILDDISABLENODEREUSE=1 - -New-Item -Path "$install_prefix" -ItemType Directory -Force - -# Setup compile flags -$compile_flags = @('/MP', '/guard:cf', '/Qspectre', '/DWIN32', '/D_WINDOWS', '/DWINVER=0x0A00', '/D_WIN32_WINNT=0x0A00', '/DNTDDI_VERSION=0x0A000000', '/W3') -$linker_flags=@('/guard:cf') - -if ($use_cache) { - $debug_info_format = "/Z7" -} -else { - $debug_info_format = "/Zi" -} - -if($build_config -eq 'Release'){ - $compile_flags += "/O2", "/Ob2", "/DNDEBUG", "/Gw", "/GL" -} elseif($build_config -eq 'RelWithDebInfo'){ - $compile_flags += "$debug_info_format", "/O2", "/Ob1", "/DNDEBUG", "/Gw", "/GL" -} elseif($build_config -eq 'Debug'){ - $compile_flags += "$debug_info_format", "/Ob0", "/Od", "/RTC1" -} elseif($build_config -eq 'MinSizeRel'){ - $compile_flags += "/O1", "/Ob1", "/DNDEBUG", "/Gw", "/GL" -} - - -# cmake args that applies to every 3rd-party library -[string[]]$cmake_extra_args="`"-DCMAKE_C_FLAGS=$compile_flags`"", "--compile-no-warning-as-error", "--fresh", "-Wno-dev" - - -if($cpu_arch -eq 'x86'){ - $cmake_extra_args += "-A", "Win32", "-T", "host=x64" - $compile_flags += '/Qspectre' - $linker_flags += '/machine:x86' -} elseif($cpu_arch -eq 'x64') { - $linker_flags += '/machine:x64' - $compile_flags += '/Qspectre' -} elseif($cpu_arch -eq 'arm') { - $linker_flags += '/machine:ARM' -} elseif($cpu_arch -eq 'arm64') { - $linker_flags += '/machine:ARM64' -} elseif($cpu_arch -eq 'arm64ec') { - $linker_flags += '/machine:ARM64EC' -} else { - throw "$cpu_arch is not supported" -} - -Write-Host $compile_flags - -$cmake_extra_args += "-DCMAKE_CXX_STANDARD=17", "`"-DCMAKE_CXX_FLAGS=$compile_flags /EHsc`"" - -if ($use_cache) { - if ($build_config -eq 'RelWithDebInfo') { - $cmake_extra_args += "-DCMAKE_CXX_FLAGS_RELWITHDEBINFO=`"/MD /Z7 /O2 /Ob1 /DNDEBUG`"" - } - elseif ($build_config -eq 'Debug') { - $cmake_extra_args += "-DCMAKE_CXX_FLAGS_DEBUG=`"/MDd /Z7 /Ob0 /Od /RTC1`"" - } -} - -$cmake_extra_args += "-DCMAKE_EXE_LINKER_FLAGS=`"$linker_flags`"" - -# Find the full path of cmake.exe -$cmake_command = (Get-Command -CommandType Application cmake)[0] -$cmake_path = $cmake_command.Path -$msbuild_path = "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\msbuild.exe" -if(-not (Test-Path $msbuild_path)){ - $vshwere_path = Join-Path -Path ${env:ProgramFiles(x86)} "Microsoft Visual Studio\Installer\vswhere.exe" - if(-not (Test-Path $vshwere_path -PathType Leaf)){ - $vshwere_path = Join-Path -Path ${env:ProgramFiles} "Microsoft Visual Studio\Installer\vswhere.exe" - } - $msbuild_path = &$vshwere_path -latest -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe | select-object -first 1 -} - -Write-Host "$msbuild_path" - -Install-Protobuf -cmake_path $cmake_path -src_root $ort_src_root -build_config $build_config -cmake_extra_args $cmake_extra_args -msbuild_path $msbuild_path diff --git a/tools/ci_build/github/windows/install_third_party_deps.ps1 b/tools/ci_build/github/windows/install_third_party_deps.ps1 index 4de5e0c0cc252..c30b576953114 100644 --- a/tools/ci_build/github/windows/install_third_party_deps.ps1 +++ b/tools/ci_build/github/windows/install_third_party_deps.ps1 @@ -95,9 +95,10 @@ $msbuild_path = &$vshwere_path -latest -requires Microsoft.Component.MSBuild -fi Install-Pybind -cmake_path $cmake_path -src_root $ort_src_root -build_config $build_config -cmake_extra_args $cmake_extra_args -msbuild_path $msbuild_path +Install-Abseil -cmake_path $cmake_path -src_root $ort_src_root -build_config $build_config -cmake_extra_args $cmake_extra_args -msbuild_path $msbuild_path + Install-Protobuf -cmake_path $cmake_path -src_root $ort_src_root -build_config $build_config -cmake_extra_args $cmake_extra_args -msbuild_path $msbuild_path -# This is the python Protobuf version, which is different than the C++ version that is in deps.txt $protobuf_version="4.21.12" # ONNX doesn't allow us to specify CMake's path diff --git a/tools/ci_build/github/windows/setup_env_cuda_11.bat b/tools/ci_build/github/windows/setup_env_cuda_11.bat index 489a9e297c548..1308e43a4f6db 100644 --- a/tools/ci_build/github/windows/setup_env_cuda_11.bat +++ b/tools/ci_build/github/windows/setup_env_cuda_11.bat @@ -1,5 +1,9 @@ REM Copyright (c) Microsoft Corporation. All rights reserved. REM Licensed under the MIT License. -set PATH=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8\bin;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8\extras\CUPTI\lib64;%PATH% +if exist PATH=%AGENT_TEMPDIRECTORY%\v11.8\ { + set PATH=%AGENT_TEMPDIRECTORY%\v11.8\bin;%AGENT_TEMPDIRECTORY%\v11.8\extras\CUPTI\lib64;%PATH% +} else { + set PATH=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8\bin;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8\extras\CUPTI\lib64;%PATH% +} set GRADLE_OPTS=-Dorg.gradle.daemon=false diff --git a/tools/ci_build/github/windows/setup_env_gpu.bat b/tools/ci_build/github/windows/setup_env_gpu.bat index 5f62f42d19038..4328c6eba1fe1 100644 --- a/tools/ci_build/github/windows/setup_env_gpu.bat +++ b/tools/ci_build/github/windows/setup_env_gpu.bat @@ -1,6 +1,11 @@ REM Copyright (c) Microsoft Corporation. All rights reserved. REM Licensed under the MIT License. -set PATH=C:\local\TensorRT-8.6.0.12.Windows10.x86_64.cuda-11.8\lib;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.6\bin;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.6\extras\CUPTI\lib64;C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin;%PATH% +if exist PATH=%AGENT_TEMPDIRECTORY%\v11.8\ { + set PATH=%AGENT_TEMPDIRECTORY%\v11.8\bin;%AGENT_TEMPDIRECTORY%\v11.8\extras\CUPTI\lib64;%PATH% +} else { + set PATH=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8\bin;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8\extras\CUPTI\lib64;%PATH% +} +set PATH=C:\local\TensorRT-8.6.1.6.Windows10.x86_64.cuda-11.8\lib;C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin;%PATH% set GRADLE_OPTS=-Dorg.gradle.daemon=false set CUDA_MODULE_LOADING=LAZY diff --git a/tools/ci_build/github/windows/setup_env_trt.bat b/tools/ci_build/github/windows/setup_env_trt.bat index faaa83fe8cbc7..d9b77c76fc324 100644 --- a/tools/ci_build/github/windows/setup_env_trt.bat +++ b/tools/ci_build/github/windows/setup_env_trt.bat @@ -1,2 +1,11 @@ -set PATH=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.6\bin;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.6\extras\CUPTI\lib64;%PATH% +REM Copyright (c) Microsoft Corporation. All rights reserved. +REM Licensed under the MIT License. + +if exist PATH=%AGENT_TEMPDIRECTORY%\v11.8\ { + set PATH=%AGENT_TEMPDIRECTORY%\v11.8\bin;%AGENT_TEMPDIRECTORY%\v11.8\extras\CUPTI\lib64;%PATH% +} else { + set PATH=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8\bin;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8\extras\CUPTI\lib64;%PATH% +} +set PATH=C:\local\TensorRT-8.6.1.6.Windows10.x86_64.cuda-11.8\lib;%PATH% set GRADLE_OPTS=-Dorg.gradle.daemon=false +set CUDA_MODULE_LOADING=LAZY \ No newline at end of file diff --git a/tools/ci_build/op_registration_utils.py b/tools/ci_build/op_registration_utils.py index b80cf33d16a7f..3fd01253a3e37 100644 --- a/tools/ci_build/op_registration_utils.py +++ b/tools/ci_build/op_registration_utils.py @@ -102,7 +102,7 @@ def process_registration( :param operator: Operator type :param start_version: Start version :param end_version: End version or None if unversioned registration - :param type: Type used in registration, if this is a typed registration + :param type: Type or types used in registration, if this is a typed registration """ pass @@ -137,6 +137,10 @@ def _process_lines(lines: typing.List[str], offset: int, registration_processor: onnx_versioned_op_len = len(onnx_versioned_op) onnx_versioned_typed_op = "ONNX_OPERATOR_VERSIONED_TYPED_KERNEL_CLASS_NAME" onnx_versioned_typed_op_len = len(onnx_versioned_typed_op) + onnx_two_typed_op = "ONNX_OPERATOR_TWO_TYPED_KERNEL_CLASS_NAME" + onnx_two_typed_op_len = len(onnx_two_typed_op) + onnx_versioned_two_typed_op = "ONNX_OPERATOR_VERSIONED_TWO_TYPED_KERNEL_CLASS_NAME" + onnx_versioned_two_typed_op_len = len(onnx_versioned_two_typed_op) end_marks = tuple([");", ")>", ")>,", ")>,};", ")>};"]) end_mark = "" @@ -204,6 +208,28 @@ def _process_lines(lines: typing.List[str], offset: int, registration_processor: lines_to_process, domain, op_type, int(start_version), int(end_version), type ) + elif onnx_two_typed_op in code_line: + # e.g. BuildKernelCreateInfo, + trim_at = code_line.index(onnx_two_typed_op) + onnx_two_typed_op_len + 1 + *_, domain, start_version, type1, type2, op_type = ( + arg.strip() for arg in code_line[trim_at : -len(end_mark)].split(",") + ) + registration_processor.process_registration( + lines_to_process, domain, op_type, int(start_version), None, type1 + ", " + type2 + ) + + elif onnx_versioned_two_typed_op in code_line: + # e.g. BuildKernelCreateInfo, + trim_at = code_line.index(onnx_versioned_two_typed_op) + onnx_versioned_two_typed_op_len + 1 + *_, domain, start_version, end_version, type1, type2, op_type = ( + arg.strip() for arg in code_line[trim_at : -len(end_mark)].split(",") + ) + registration_processor.process_registration( + lines_to_process, domain, op_type, int(start_version), int(end_version), type1 + ", " + type2 + ) + else: log.warning(f"Ignoring unhandled kernel registration variant: {code_line}") for line in lines_to_process: diff --git a/tools/ci_build/op_registration_validator.py b/tools/ci_build/op_registration_validator.py index a9ccb5c79d0c1..8222437f7b42e 100644 --- a/tools/ci_build/op_registration_validator.py +++ b/tools/ci_build/op_registration_validator.py @@ -6,6 +6,8 @@ """ import argparse +import dataclasses +import itertools import os import sys import typing @@ -30,10 +32,25 @@ } +@dataclasses.dataclass +class RegistrationInfo: + domain: str + operator: str + start_version: int + end_version: typing.Optional[int] + lines: typing.List[str] + + def domain_and_op_str(self): + return f"{self.domain}:{self.operator}" + + +def _log_registration_error(r: RegistrationInfo, message: str): + log.error("Invalid registration for {}. {}\n{}".format(r.domain_and_op_str(), message, "".join(r.lines))) + + class RegistrationValidator(op_registration_utils.RegistrationProcessor): def __init__(self): - self.last_op_registrations = {} - self.failed = False + self.all_registrations: typing.List[RegistrationInfo] = [] def process_registration( self, @@ -44,56 +61,130 @@ def process_registration( end_version: typing.Optional[int] = None, type: typing.Optional[str] = None, ): - key = domain + ":" + operator - prev_start, prev_end = self.last_op_registrations[key] if key in self.last_op_registrations else (None, None) - - if prev_start and start_version > prev_start: - # a typed registration where the to/from matches for each entry so nothing to update - if prev_start == start_version and prev_end == end_version: - return - - # previous registration was unversioned but should have been if we are seeing another registration - if not prev_end: - log.error( - "Invalid registration for {}. Registration for opset {} has no end version but was " - "superceeded by version {}.".format(key, prev_start, start_version) - ) - self.failed = True - return - - # previous registration end opset is not adjacent to the start of the next registration - if prev_end != start_version - 1: - log.error( - "Invalid registration for {}. Registration for opset {} should have end version of {}".format( - key, prev_start, start_version - 1 - ) - ) - self.failed = True - return - - self.last_op_registrations[key] = (start_version, end_version) + self.all_registrations.append( + RegistrationInfo( + domain=domain, operator=operator, start_version=start_version, end_version=end_version, lines=lines + ) + ) def ok(self): - return not self.failed - - def validate_last_registrations(self): + num_invalid_registrations = self._validate_all_registrations() + if num_invalid_registrations > 0: + log.error(f"Found {num_invalid_registrations} invalid registration(s).") + return False + + return True + + def _validate_all_registrations(self) -> int: + """ + Validates all registrations added by `process_registration()` and returns the number of invalid ones. + """ + + def registration_info_sort_key(r: RegistrationInfo): + return ( + r.domain, + r.operator, + r.start_version, + 1 if r.end_version is None else 0, # unspecified end_version > specified end_version + r.end_version, + ) + + def domain_and_op_key(r: RegistrationInfo): + return (r.domain, r.operator) + + sorted_registrations = sorted(self.all_registrations, key=registration_info_sort_key) + + num_invalid_registrations = 0 + for _, registration_group in itertools.groupby(sorted_registrations, key=domain_and_op_key): + num_invalid_registrations += self._validate_registrations_for_domain_and_op(registration_group) + + return num_invalid_registrations + + def _validate_registrations_for_domain_and_op(self, registrations: typing.Iterator[RegistrationInfo]) -> int: + """ + Validates registrations in sorted order for a single domain and op and returns the number of invalid ones. + """ + num_invalid_registrations = 0 + r = next(registrations, None) + while r is not None: + next_r = next(registrations, None) + if not self._validate_registration(r, next_r): + num_invalid_registrations += 1 + r = next_r + + return num_invalid_registrations + + def _validate_registration(self, r: RegistrationInfo, next_r: typing.Optional[RegistrationInfo]) -> bool: + """ + Validates a registration, `r`, with the next one in sorted order for a single domain and op, `next_r`, and + returns whether it is valid. + """ + if not (r.end_version is None or r.start_version <= r.end_version): + _log_registration_error( + r, f"Start version ({r.start_version}) is greater than end version ({r.end_version})." + ) + return False + + if next_r is None: + return self._validate_last_registration(r) + + # It is valid to match next registration start and end versions exactly. + # This is expected if there are multiple registrations for an opset (e.g., typed registrations). + if (r.start_version, r.end_version) == (next_r.start_version, next_r.end_version): + return True + + # This registration has no end version but it should have one if the next registration has different versions. + if r.end_version is None: + _log_registration_error( + r, + f"Registration for opset {r.start_version} has no end version but was superseded by version " + f"{next_r.start_version}.", + ) + return False + + # This registration's end version is not adjacent to the start version of the next registration. + if r.end_version != next_r.start_version - 1: + _log_registration_error( + r, + f"Registration end version is not adjacent to the next registration's start version. " + f"Current start and end versions: {(r.start_version, r.end_version)}. " + f"Next start and end versions: {(next_r.start_version, next_r.end_version)}.", + ) + return False + + return True + + def _validate_last_registration(self, last_r: RegistrationInfo) -> bool: + """ + Validates the last registration in sorted order for a single domain and op and returns whether it is valid. + """ # make sure we have an unversioned last entry for each operator unless it's deprecated - for entry in self.last_op_registrations.items(): - key, value = entry - opset_from, opset_to = value - allow_missing_unversioned_registration = key in deprecated_ops and opset_to == deprecated_ops[key] - 1 + # TODO If the operator is deprecated, validation is more lax. I.e., it doesn't require a versioned registration. + # This could be tightened up but we would need to handle the deprecated contrib ops registered in the ONNX + # domain that have newer registrations in a non-contrib op file differently. They should only be considered + # deprecated as contrib ops. + domain_and_op_str = last_r.domain_and_op_str() + deprecation_version = deprecated_ops.get(domain_and_op_str, None) - # special handling for ArgMin/ArgMax, which CUDA EP doesn't yet support for opset 12+ - # TODO remove once CUDA EP supports ArgMin/ArgMax for opset 12+ - ops_with_incomplete_support = ["kOnnxDomain:ArgMin", "kOnnxDomain:ArgMax"] - if key in ops_with_incomplete_support: - log.warn(f"Allowing missing unversioned registration for op with incomplete support: {key}") - allow_missing_unversioned_registration = True + allow_missing_unversioned_registration = ( + deprecation_version is not None and last_r.end_version == deprecation_version - 1 + ) - if opset_to and not allow_missing_unversioned_registration: - log.error(f"Missing unversioned registration for {key}") - self.failed = True + # special handling for ArgMin/ArgMax, which CUDA EP doesn't yet support for opset 12+ + # TODO remove once CUDA EP supports ArgMin/ArgMax for opset 12+ + ops_with_incomplete_support = ["kOnnxDomain:ArgMin", "kOnnxDomain:ArgMax"] + if domain_and_op_str in ops_with_incomplete_support: + log.warning( + f"Allowing missing unversioned registration for op with incomplete support: {domain_and_op_str}." + ) + allow_missing_unversioned_registration = True + + if last_r.end_version is not None and not allow_missing_unversioned_registration: + log.error(f"Missing unversioned registration for {domain_and_op_str}.") + return False + + return True if __name__ == "__main__": @@ -107,17 +198,24 @@ def validate_last_registrations(self): args = parser.parse_args() - ort_root = os.path.abspath(args.ort_root) if args.ort_root else "" + ort_root = os.path.abspath(args.ort_root) if args.ort_root else None include_cuda = True # validate CPU and CUDA EP registrations registration_files = op_registration_utils.get_kernel_registration_files(ort_root, include_cuda) - for file in registration_files: + def validate_registration_file(file: str) -> bool: log.info(f"Processing {file}") processor = RegistrationValidator() op_registration_utils.process_kernel_registration_file(file, processor) - processor.validate_last_registrations() - if not processor.ok(): - sys.exit(-1) + return processor.ok() + + validation_successful = all( + # Validate each file first by storing the validation results in a list. + # Otherwise, all() will exit early when it encounters the first invalid file. + list(map(validate_registration_file, registration_files)) + ) + + log.info(f"Op kernel registration validation {'succeeded' if validation_successful else 'failed'}.") + sys.exit(0 if validation_successful else 1) diff --git a/tools/ci_build/patch_manylinux.py b/tools/ci_build/patch_manylinux.py index 525f2b2f30c1e..0d1cb37cc40ac 100644 --- a/tools/ci_build/patch_manylinux.py +++ b/tools/ci_build/patch_manylinux.py @@ -41,7 +41,7 @@ def main(): manylinux_build_scripts_folder = Path(args.manylinux_src) / "docker" / "build_scripts" dest = Path(args.context) / "build_scripts" if dest.exists(): - log.info(f"Deleting: {str(dest)}") + log.info(f"Deleting: {dest!s}") shutil.rmtree(str(dest)) shutil.copytree(str(manylinux_build_scripts_folder), str(dest)) diff --git a/tools/ci_build/reduce_op_kernels.py b/tools/ci_build/reduce_op_kernels.py index 01be902acc866..6b73b1e063e58 100755 --- a/tools/ci_build/reduce_op_kernels.py +++ b/tools/ci_build/reduce_op_kernels.py @@ -39,7 +39,7 @@ def _adapt_filters_for_extended_minimal_build( # graph transformations in an extended minimal build require certain ops to be available extended_minimal_build_required_op_ids = set() # set of (domain, optype, opset) with open( - ORT_ROOT / "onnxruntime/core/optimizer/transpose_optimizer/layout_transformation_potentially_added_ops.h", + ORT_ROOT / "onnxruntime/core/optimizer/layout_transformation/layout_transformation_potentially_added_ops.h", ) as f: region_boundary_pattern = re.compile(r"@@region_(begin|end)\(extended_minimal_build_required_kernels\)@@") op_id_pattern = re.compile( diff --git a/tools/ci_build/requirements.txt b/tools/ci_build/requirements.txt index 5d8e56a70045c..96659d70af81f 100644 --- a/tools/ci_build/requirements.txt +++ b/tools/ci_build/requirements.txt @@ -1,7 +1,8 @@ -# packages used by transformers tool test +# packages used by transformers python unittest (only enabled in Linux CPU CI Pipeline) packaging protobuf==3.20.2 numpy==1.24.0 coloredlogs==15.0 -transformers==4.24.0 +transformers==4.30.0 psutil +einops \ No newline at end of file diff --git a/tools/ci_build/set-trigger-rules.py b/tools/ci_build/set-trigger-rules.py new file mode 100644 index 0000000000000..cdb75154ecd29 --- /dev/null +++ b/tools/ci_build/set-trigger-rules.py @@ -0,0 +1,85 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +# -------------------------------------------------------------------------- + +# This script is used to add trigger rules to the workflow files. + + +import multiprocessing +import os +from os.path import abspath, dirname + +skip_doc_changes = ["web-ci-pipeline.yml"] +skip_js_changes = [ + "android-arm64-v8a-QNN-crosscompile-ci-pipeline.yml", + "android-x86_64-crosscompile-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", + "linux-migraphx-ci-pipeline.yml", + "linux-openvino-ci-pipeline.yml", + "linux-qnn-ci-pipeline.yml", + "mac-ci-pipeline.yml", + "mac-coreml-ci-pipeline.yml", + "mac-ios-ci-pipeline.yml", + "mac-ios-packaging-pipeline.yml", + "mac-react-native-ci-pipeline.yml", + "orttraining-linux-ci-pipeline.yml", + "orttraining-linux-gpu-ci-pipeline.yml", + "orttraining-linux-gpu-ortmodule-distributed-test-ci-pipeline.yml", + "orttraining-linux-gpu-training-apis.yml", + "orttraining-mac-ci-pipeline.yml", + "win-ci-pipeline.yml", + "win-gpu-ci-pipeline.yml", + "win-gpu-tensorrt-ci-pipeline.yml", + "win-qnn-arm64-ci-pipeline.yml", + "win-qnn-ci-pipeline.yml", +] + + +def add_trigger_filter(file_name, trigger_lines): + # Open the file and read its lines + with open(file_name) as f: + lines = f.readlines() + + start_marker = f"##### start trigger Don't edit it manually, Please do edit {os.path.basename(__file__)} ####" + end_marker = "#### end trigger ####\n" + + if lines[0].startswith(start_marker): + for i in range(1, len(lines)): + if lines[i].startswith(end_marker): + lines[1:i] = trigger_lines + break + else: + trigger_lines.insert(0, start_marker + "\n") + trigger_lines.extend(end_marker + "\n") + lines[0:0] = trigger_lines + + with open(file_name, "w") as f: + f.writelines(lines) + print("Added trigger rules to file: " + file_name) + + +def main(): + working_dir = os.path.join(dirname(abspath(__file__)), "github/azure-pipelines") + os.chdir(working_dir) + + trigger_rules = {"skip-docs.yml": skip_doc_changes, "skip-js.yml": skip_js_changes} + for key in trigger_rules: + trigger_file = os.path.join(working_dir, "triggers", key) + with open(trigger_file) as f1: + trigger_lines = f1.readlines() + + skip_changes = trigger_rules[key] + pool = multiprocessing.Pool() + pool.starmap(add_trigger_filter, [(file, trigger_lines) for file in skip_changes]) + pool.close() + pool.join() + + +if __name__ == "__main__": + main() diff --git a/tools/doc/builddoc.sh b/tools/doc/builddoc.sh index e7e4346649f16..88d4fc5d409b1 100755 --- a/tools/doc/builddoc.sh +++ b/tools/doc/builddoc.sh @@ -17,12 +17,5 @@ export PYTHONPATH=$3/$4:$PYTHONPATH # Remove old docs rm -rf $3/docs/ -# Inference doc -$1/python -m sphinx -j1 -v -T -b html -d $3/docs/inference/_doctrees/html $2/docs/python/inference $3/docs/inference/html -$1/python -u $2/tools/doc/rename_folders.py $3/docs/inference/html -# (cd $3/docs/inference/html && zip -r $3/docs/python_inference_doc.zip .) - -# Training doc -$1/python -m sphinx -j1 -v -T -b html -d $3/docs/training/_doctrees/html $2/docs/python/training $3/docs/training/html -$1/python -u $2/tools/doc/rename_folders.py $3/docs/training/html -# (cd $3/docs/training/html && zip -r $3/docs/python_training_doc.zip .) +$1/python -m sphinx -v -T -b html -d $3/docs/_doctrees/html $2/docs/python/ $3/docs/html +$1/python -u $2/tools/doc/rename_folders.py $3/docs/html diff --git a/tools/nuget/generate_nuspec_for_native_nuget.py b/tools/nuget/generate_nuspec_for_native_nuget.py index c37adb33e5a07..2aefe794db2f5 100644 --- a/tools/nuget/generate_nuspec_for_native_nuget.py +++ b/tools/nuget/generate_nuspec_for_native_nuget.py @@ -11,22 +11,26 @@ # What does the names of our C API tarball/zip files looks like # os: win, linux, osx # ep: cuda, tensorrt, None -def get_package_name(os, cpu_arch, ep): - pkg_name = None +def get_package_name(os, cpu_arch, ep, is_training_package): + pkg_name = "onnxruntime-training" if is_training_package else "onnxruntime" if os == "win": - pkg_name = "onnxruntime-win-" + pkg_name += "-win-" pkg_name += cpu_arch if ep == "cuda": pkg_name += "-cuda" elif ep == "tensorrt": pkg_name += "-tensorrt" + elif ep == "rocm": + pkg_name += "-rocm" elif os == "linux": - pkg_name = "onnxruntime-linux-" + pkg_name += "-linux-" pkg_name += cpu_arch if ep == "cuda": pkg_name += "-cuda" elif ep == "tensorrt": pkg_name += "-tensorrt" + elif ep == "rocm": + pkg_name += "-rocm" elif os == "osx": pkg_name = "onnxruntime-osx-" + cpu_arch return pkg_name @@ -43,13 +47,13 @@ def is_this_file_needed(ep, filename): # ep: cuda, tensorrt, None # files_list: a list of xml string pieces to append # This function has no return value. It updates files_list directly -def generate_file_list_for_ep(nuget_artifacts_dir, ep, files_list, include_pdbs): +def generate_file_list_for_ep(nuget_artifacts_dir, ep, files_list, include_pdbs, is_training_package): for child in nuget_artifacts_dir.iterdir(): if not child.is_dir(): continue for cpu_arch in ["x86", "x64", "arm", "arm64"]: - if child.name == get_package_name("win", cpu_arch, ep): + if child.name == get_package_name("win", cpu_arch, ep, is_training_package): child = child / "lib" # noqa: PLW2901 for child_file in child.iterdir(): suffixes = [".dll", ".lib", ".pdb"] if include_pdbs else [".dll", ".lib"] @@ -58,7 +62,7 @@ def generate_file_list_for_ep(nuget_artifacts_dir, ep, files_list, include_pdbs) '' % cpu_arch ) for cpu_arch in ["x86_64", "arm64"]: - if child.name == get_package_name("osx", cpu_arch, ep): + if child.name == get_package_name("osx", cpu_arch, ep, is_training_package): child = child / "lib" # noqa: PLW2901 if cpu_arch == "x86_64": cpu_arch = "x64" # noqa: PLW2901 @@ -67,10 +71,10 @@ def generate_file_list_for_ep(nuget_artifacts_dir, ep, files_list, include_pdbs) is_versioned_dylib = re.match(r".*[\.\d+]+\.dylib$", child_file.name) if child_file.is_file() and child_file.suffix == ".dylib" and not is_versioned_dylib: files_list.append( - '' % cpu_arch + '' % cpu_arch ) for cpu_arch in ["x64", "aarch64"]: - if child.name == get_package_name("linux", cpu_arch, ep): + if child.name == get_package_name("linux", cpu_arch, ep, is_training_package): child = child / "lib" # noqa: PLW2901 if cpu_arch == "x86_64": cpu_arch = "x64" # noqa: PLW2901 @@ -84,7 +88,7 @@ def generate_file_list_for_ep(nuget_artifacts_dir, ep, files_list, include_pdbs) '' % cpu_arch ) - if child.name == "onnxruntime-android": + if child.name == "onnxruntime-android" or child.name == "onnxruntime-training-android": for child_file in child.iterdir(): if child_file.suffix in [".aar"]: files_list.append('') @@ -120,7 +124,7 @@ def parse_arguments(): required=False, default="None", type=str, - choices=["cuda", "dnnl", "openvino", "tensorrt", "snpe", "tvm", "None"], + choices=["cuda", "dnnl", "openvino", "tensorrt", "snpe", "tvm", "qnn", "None"], help="The selected execution provider for this build.", ) parser.add_argument("--sdk_info", required=False, default="", type=str, help="dependency SDK information.") @@ -149,6 +153,14 @@ def generate_description(line_list, package_name): if package_name == "Microsoft.AI.MachineLearning": description = "This package contains Windows ML binaries." + elif "Microsoft.ML.OnnxRuntime.Training" in package_name: # This is a Microsoft.ML.OnnxRuntime.Training.* package + description = ( + "The onnxruntime-training native shared library artifacts are designed to efficiently train and infer " + + "a wide range of ONNX models on edge devices, such as client machines, gaming consoles, and other " + + "portable devices with a focus on minimizing resource usage and maximizing accuracy." + + "See https://github.com/microsoft/onnxruntime-training-examples/tree/master/on_device_training for " + + "more details." + ) elif "Microsoft.ML.OnnxRuntime" in package_name: # This is a Microsoft.ML.OnnxRuntime.* package description = ( "This package contains native shared library artifacts for all supported platforms of ONNX Runtime." @@ -170,7 +182,7 @@ def generate_icon(line_list, icon_file): def generate_license(line_list): - line_list.append('LICENSE.txt') + line_list.append('LICENSE') def generate_project_url(line_list, project_url): @@ -182,7 +194,7 @@ def generate_repo_url(line_list, repo_url, commit_id): def generate_dependencies(xml_text, package_name, version): - dml_dependency = '' + dml_dependency = '' if package_name == "Microsoft.AI.MachineLearning": xml_text.append("") @@ -286,7 +298,11 @@ def generate_metadata(line_list, args): generate_owners(metadata_list, "Microsoft") generate_description(metadata_list, args.package_name) generate_copyright(metadata_list, "\xc2\xa9 " + "Microsoft Corporation. All rights reserved.") - generate_tags(metadata_list, "ONNX ONNX Runtime Machine Learning") + generate_tags( + metadata_list, "ONNX ONNX Runtime Machine Learning" + ) if "Microsoft.ML.OnnxRuntime.Training." in args.package_name else generate_tags( + metadata_list, "native ONNX ONNXRuntime-Training Learning-on-The-Edge On-Device-Training MachineLearning" + ) generate_icon(metadata_list, "ORT_icon_for_light_bg.png") generate_license(metadata_list) generate_project_url(metadata_list, "https://github.com/Microsoft/onnxruntime") @@ -301,12 +317,18 @@ def generate_metadata(line_list, args): def generate_files(line_list, args): files_list = [""] - is_cpu_package = args.package_name in ["Microsoft.ML.OnnxRuntime", "Microsoft.ML.OnnxRuntime.OpenMP"] + is_cpu_package = args.package_name in [ + "Microsoft.ML.OnnxRuntime", + "Microsoft.ML.OnnxRuntime.OpenMP", + "Microsoft.ML.OnnxRuntime.Training", + ] is_mklml_package = args.package_name == "Microsoft.ML.OnnxRuntime.MKLML" is_cuda_gpu_package = args.package_name == "Microsoft.ML.OnnxRuntime.Gpu" + is_rocm_gpu_package = args.package_name == "Microsoft.ML.OnnxRuntime.ROCm" is_dml_package = args.package_name == "Microsoft.ML.OnnxRuntime.DirectML" is_windowsai_package = args.package_name == "Microsoft.AI.MachineLearning" is_snpe_package = args.package_name == "Microsoft.ML.OnnxRuntime.Snpe" + is_qnn_package = args.package_name == "Microsoft.ML.OnnxRuntime.QNN" is_training_package = args.package_name in [ "Microsoft.ML.OnnxRuntime.Training", "Microsoft.ML.OnnxRuntime.Training.Gpu", @@ -351,6 +373,7 @@ def generate_files(line_list, args): "tensorrt_ep_shared_lib": "libonnxruntime_providers_tensorrt.so", "openvino_ep_shared_lib": "libonnxruntime_providers_openvino.so", "cuda_ep_shared_lib": "libonnxruntime_providers_cuda.so", + "rocm_ep_shared_lib": "libonnxruntime_providers_rocm.so", "onnxruntime_perf_test": "onnxruntime_perf_test", "onnx_test_runner": "onnx_test_runner", } @@ -390,7 +413,7 @@ def generate_files(line_list, args): "' ) @@ -496,7 +519,7 @@ def generate_files(line_list, args): + '" target="lib\\net5.0\\Microsoft.AI.MachineLearning.Interop.pdb" />' ) - if args.package_name == "Microsoft.ML.OnnxRuntime.Snpe": + if args.package_name == "Microsoft.ML.OnnxRuntime.Snpe" or args.package_name == "Microsoft.ML.OnnxRuntime.QNN": files_list.append( "" ) @@ -517,10 +540,12 @@ def generate_files(line_list, args): # downloaded from other build jobs if is_cuda_gpu_package: ep_list = ["tensorrt", "cuda", None] + elif is_rocm_gpu_package: + ep_list = ["rocm", None] else: ep_list = [None] for ep in ep_list: - generate_file_list_for_ep(nuget_artifacts_dir, ep, files_list, include_pdbs) + generate_file_list_for_ep(nuget_artifacts_dir, ep, files_list, include_pdbs, is_training_package) is_ado_packaging_build = True else: # Code path for local dev build @@ -650,6 +675,24 @@ def generate_files(line_list, args): # TODO(agladyshev): Add support for Linux. raise RuntimeError("Now only Windows is supported for TVM EP.") + if args.execution_provider == "rocm" or is_rocm_gpu_package and not is_ado_packaging_build: + files_list.append( + "' + ) + files_list.append( + "' + ) + if args.execution_provider == "openvino": openvino_path = get_env_var("INTEL_OPENVINO_DIR") files_list.append( @@ -844,7 +887,15 @@ def generate_files(line_list, args): files_list.append("') files_list.append("') - if is_cpu_package or is_cuda_gpu_package or is_dml_package or is_mklml_package or is_snpe_package: + if ( + is_cpu_package + or is_cuda_gpu_package + or is_rocm_gpu_package + or is_dml_package + or is_mklml_package + or is_snpe_package + or is_qnn_package + ): # Process props file source_props = os.path.join( args.sources_path, "csharp", "src", "Microsoft.ML.OnnxRuntime", "targets", "netstandard", "props.xml" @@ -860,7 +911,7 @@ def generate_files(line_list, args): ) os.system(copy_command + " " + source_props + " " + target_props) files_list.append("') - if not is_snpe_package: + if not is_snpe_package and not is_qnn_package: files_list.append("') files_list.append("') @@ -879,7 +930,7 @@ def generate_files(line_list, args): ) os.system(copy_command + " " + source_targets + " " + target_targets) files_list.append("') - if not is_snpe_package: + if not is_snpe_package and not is_qnn_package: files_list.append("') files_list.append("') @@ -995,8 +1046,66 @@ def generate_files(line_list, args): "' ) + # Process Training specific targets and props + if args.package_name == "Microsoft.ML.OnnxRuntime.Training": + monoandroid_source_targets = os.path.join( + args.sources_path, + "csharp", + "src", + "Microsoft.ML.OnnxRuntime", + "targets", + "monoandroid11.0", + "targets.xml", + ) + monoandroid_target_targets = os.path.join( + args.sources_path, + "csharp", + "src", + "Microsoft.ML.OnnxRuntime", + "targets", + "monoandroid11.0", + args.package_name + ".targets", + ) + + net6_android_source_targets = os.path.join( + args.sources_path, + "csharp", + "src", + "Microsoft.ML.OnnxRuntime", + "targets", + "net6.0-android", + "targets.xml", + ) + net6_android_target_targets = os.path.join( + args.sources_path, + "csharp", + "src", + "Microsoft.ML.OnnxRuntime", + "targets", + "net6.0-android", + args.package_name + ".targets", + ) + + os.system(copy_command + " " + monoandroid_source_targets + " " + monoandroid_target_targets) + os.system(copy_command + " " + net6_android_source_targets + " " + net6_android_target_targets) + + files_list.append("') + files_list.append( + "' + ) + + files_list.append( + "' + ) + files_list.append( + "' + ) + + # README + files_list.append("') + # Process License, ThirdPartyNotices, Privacy - files_list.append("') + files_list.append("') files_list.append( " Text def should_render_domain(domain, domain_filter): # type: (Text) -> bool - if domain in (ONNX_DOMAIN, ONNX_ML_DOMAIN) or domain == "" or domain == "ai.onnx.ml": # noqa: PLC1901 + if domain in (ONNX_DOMAIN, ONNX_ML_DOMAIN) or domain == "" or domain == "ai.onnx.ml": return False if domain_filter and domain not in domain_filter: diff --git a/tools/python/gen_opkernel_doc.py b/tools/python/gen_opkernel_doc.py index 1075ed8192fdd..2d0d16cf9a0de 100644 --- a/tools/python/gen_opkernel_doc.py +++ b/tools/python/gen_opkernel_doc.py @@ -150,7 +150,7 @@ def main(output_path: pathlib.Path, provider_filter: [str]): tnameindex += 1 tclist = [] for tc in sorted(tcset): - tclist.append(tc) + tclist.append(tc) # noqa: PERF402 fout.write("**" + tname + "** = " + format_type_constraints(tclist)) if tnameindex < len(typemap): fout.write("
") diff --git a/tools/python/onnx2tfevents.py b/tools/python/onnx2tfevents.py index adf6ded4b56b3..9dfde13090b07 100644 --- a/tools/python/onnx2tfevents.py +++ b/tools/python/onnx2tfevents.py @@ -154,7 +154,7 @@ class TransformerBase(ABC): the dependency between it and existing transformers. """ - _TRANSFORMERS = [] + _TRANSFORMERS = [] # noqa: RUF012 @classmethod def register_transformer(cls, klass): @@ -328,7 +328,7 @@ def transform(self, graph: GraphProto) -> None: if len([output for output in node.output if len(output) > 0]) > 1: idx = self.ops.get(node.op_type, 0) self.ops[node.op_type] = idx + 1 - new_output = f"{get_prefix(node.output[0])}{node.op_type}_{str(idx)}_output" + new_output = f"{get_prefix(node.output[0])}{node.op_type}_{idx!s}_output" for output in node.output: if len(output) > 0: new_nodes.append(helper.make_node("ListUnpack", [new_output], [output])) diff --git a/tools/python/onnx_test_data_utils.py b/tools/python/onnx_test_data_utils.py index 97c9db2c38653..56485bb78abbd 100644 --- a/tools/python/onnx_test_data_utils.py +++ b/tools/python/onnx_test_data_utils.py @@ -111,6 +111,8 @@ def get_arg_parser(): numpy_to_pb: Convert numpy array saved to a file with numpy.save() to a TensorProto, and serialize to a pb file. image_to_pb: Convert data from an image file into a TensorProto, and serialize to a pb file. random_to_pb: Create a TensorProto with random data, and serialize to a pb file. + raw_to_pb: Create a uint8 TensorProto with raw data from a file, and serialize to a pb file. + string_to_pb: Create a string TensorProto with the input string, and serialize to a pb file. update_name_in_pb: Update the TensorProto.name value in a pb file. Updates the input file unless --output is specified. """, @@ -120,15 +122,29 @@ def get_arg_parser(): parser.add_argument( "--action", help="Action to perform", - choices=["dump_pb", "numpy_to_pb", "image_to_pb", "random_to_pb", "update_name_in_pb"], + choices=[ + "dump_pb", + "numpy_to_pb", + "image_to_pb", + "random_to_pb", + "raw_to_pb", + "string_to_pb", + "update_name_in_pb", + ], required=True, ) - parser.add_argument("--input", help="The input filename or directory name") + parser.add_argument("--input", help="The input filename, directory name or string.") parser.add_argument("--name", help="The value to set TensorProto.name to if creating/updating one.") parser.add_argument("--output", help="Filename to serialize the TensorProto to.") image_to_pb_group = parser.add_argument_group("image_to_pb", "image_to_pb specific options") + image_to_pb_group.add_argument( + "--raw", + action="store_true", + help="Save raw image bytes for usage with a model that has the DecodeImage custom operator " + "from onnxruntime-extensions.", + ) image_to_pb_group.add_argument( "--resize", default=None, @@ -191,7 +207,11 @@ def get_arg_parser(): print("Missing argument. Need input, output, name to be specified.", file=sys.stderr) sys.exit(-1) - img_np = image_to_numpy(args.input, args.resize, args.channels_last, args.add_batch_dim) + if args.raw: + img_np = np.fromfile(args.input, np.ubyte) + else: + img_np = image_to_numpy(args.input, args.resize, args.channels_last, args.add_batch_dim) + numpy_to_pb(args.name, img_np, args.output) elif args.action == "random_to_pb": if not args.output or not args.shape or not args.datatype or not args.name: @@ -200,6 +220,21 @@ def get_arg_parser(): data = create_random_data(args.shape, args.datatype, args.min_value, args.max_value, args.seed) numpy_to_pb(args.name, data, args.output) + elif args.action == "raw_to_pb": + if not args.input or not args.output or not args.name: + print("Missing argument. Need input, output and name to be specified.", file=sys.stderr) + sys.exit(-1) + + data = np.fromfile(args.input, dtype=np.ubyte) + numpy_to_pb(args.name, data, args.output) + elif args.action == "string_to_pb": + if not args.input or not args.output or not args.name: + print("Missing argument. Need input, output and name to be specified.", file=sys.stderr) + sys.exit(-1) + + data = np.ndarray((1), dtype=object) + data[0] = args.input + numpy_to_pb(args.name, data, args.output) elif args.action == "update_name_in_pb": if not args.input or not args.name: print("Missing argument. Need input and name to be specified.", file=sys.stderr) diff --git a/tools/python/ort_test_dir_utils.py b/tools/python/ort_test_dir_utils.py index 417e8376c61d7..2fc4921a7bb67 100644 --- a/tools/python/ort_test_dir_utils.py +++ b/tools/python/ort_test_dir_utils.py @@ -5,7 +5,7 @@ import numpy as np import onnx import onnx_test_data_utils -from onnx import numpy_helper +from onnx import TensorProto, numpy_helper import onnxruntime as ort @@ -49,7 +49,7 @@ def _create_missing_input_data(model_inputs, name_input_map, symbolic_dim_values dims.append(dim.dim_value) elif dim_type == "dim_param": if dim.dim_param not in symbolic_dim_values_map: - raise ValueError(f"Value for symbolic dim {dim.dim_param} was not provided.") + raise ValueError(f"Value for symbolic dim '{dim.dim_param}' was not provided.") dims.append(symbolic_dim_values_map[dim.dim_param]) else: @@ -57,9 +57,16 @@ def _create_missing_input_data(model_inputs, name_input_map, symbolic_dim_values # shape for the input name instead. raise ValueError("Unsupported model. Unknown dim with no value or symbolic name.") - np_type = onnx.mapping.TENSOR_TYPE_TO_NP_TYPE[input.type.tensor_type.elem_type] - # create random data. give it range -10 to 10 so if we convert to an integer type it's not all 0s and 1s - data = (np.random.standard_normal(dims) * 10).astype(np_type) + onnx_type = input.type.tensor_type.elem_type + # create random data. + data = np.random.random_sample(dims) + # use range of [0, 1) for floating point data + # use range of [0, 256) for other data types + if onnx_type not in [TensorProto.FLOAT, TensorProto.BFLOAT16, TensorProto.DOUBLE, TensorProto.FLOAT16]: + data *= 256 + + np_type = onnx.mapping.TENSOR_TYPE_TO_NP_TYPE[onnx_type] + data = data.astype(np_type) name_input_map[input.name] = data @@ -139,7 +146,20 @@ def save_data(prefix, name_data_map, model_info): # save expected output data if provided. run model to create if not. if not name_output_map: output_names = [o.name for o in model_outputs] - sess = ort.InferenceSession(test_model_filename) + so = ort.SessionOptions() + + # try and enable onnxruntime-extensions if present + try: + import onnxruntime_extensions + + so.register_custom_ops_library(onnxruntime_extensions.get_library_path()) + + except ImportError: + # ignore if onnxruntime_extensions is not available. + # if the model uses custom ops from there it will fail to load. + pass + + sess = ort.InferenceSession(test_model_filename, so) outputs = sess.run(output_names, name_input_map) name_output_map = {} for name, data in zip(output_names, outputs): @@ -219,7 +239,7 @@ def run_test_dir(model_or_dir): output_names = list(expected_outputs.keys()) # handle case where there's a single expected output file but no name in it (empty string for name) # e.g. ONNX test models 20190729\opset8\tf_mobilenet_v2_1.4_224 - if len(output_names) == 1 and output_names[0] == "": # noqa: PLC1901 + if len(output_names) == 1 and output_names[0] == "": output_names = [o.name for o in sess.get_outputs()] assert len(output_names) == 1, "There should be single output_name." expected_outputs[output_names[0]] = expected_outputs[""] diff --git a/tools/python/run_CIs_for_external_pr.py b/tools/python/run_CIs_for_external_pr.py index 275faadc89ce5..dcc6a92d84ef2 100644 --- a/tools/python/run_CIs_for_external_pr.py +++ b/tools/python/run_CIs_for_external_pr.py @@ -25,9 +25,9 @@ def parse_args(): return args -def run_gh_pr_command(command: typing.List[str]): +def run_gh_pr_command(command: typing.List[str], check=True): try: - return subprocess.run(["gh", "pr", *command], capture_output=True, text=True, check=True) + return subprocess.run(["gh", "pr", *command], capture_output=True, text=True, check=check) except subprocess.CalledProcessError as cpe: print(cpe) print(cpe.stderr) @@ -51,11 +51,27 @@ def main(): print(f"PR {pr_id} is not OPEN. Currently in state {pieces[1]}.") sys.exit(-1) + print("Check passed pipelines") + gh_out = run_gh_pr_command(["checks", pr_id, "--required"], check=False) + # output format is a tab separated list of columns: + # (pipeline name) "\t" (status) "\t" (ran time) "\t" (url) + checked_pipelines = [ + columns[0] + for columns in (line.strip().split("\t") for line in gh_out.stdout.split("\n")) + if len(columns) == 4 and columns[1] == "pass" + ] + print("Adding azp run commands") # Current pipelines. These change semi-frequently and may need updating. + # + # Note: there is no easy way to get the list for azp "required" pipelines before they starts. + # we need to maintain this list manually. + # pipelines = [ # windows + "Windows ARM64 QNN CI Pipeline", + "Windows x64 QNN CI Pipeline", "Windows CPU CI Pipeline", "Windows GPU CI Pipeline", "Windows GPU TensorRT CI Pipeline", @@ -66,6 +82,7 @@ def main(): "Linux GPU CI Pipeline", "Linux GPU TensorRT CI Pipeline", "Linux OpenVINO CI Pipeline", + "Linux QNN CI Pipeline", # mac "MacOS CI Pipeline", # training @@ -78,6 +95,9 @@ def main(): "onnxruntime-binary-size-checks-ci-pipeline", ] + # remove pipelines that have already run successfully + pipelines = [p for p in pipelines if p not in checked_pipelines] + # azp run is limited to 10 pipelines at a time max_pipelines_per_comment = 10 start = 0 diff --git a/tools/python/update_version.py b/tools/python/update_version.py index 415f83b043bc2..f6e7acb646b69 100755 --- a/tools/python/update_version.py +++ b/tools/python/update_version.py @@ -64,22 +64,6 @@ def update_version(): f.write(line) lines = [] current_version = "" - file_path = os.path.join(cwd, "..", "..", "package", "rpm", "onnxruntime.spec") - with open(file_path) as f: - lines = f.readlines() - for line in lines: - if line.startswith("Version:"): - current_version = line.split(":")[1].strip() - break - if version != current_version: - with open(file_path, "w") as f: - for line in lines: - if line.startswith("Version:"): - f.write("Version: " + version + "\n") - continue - f.write(line) - lines = [] - current_version = "" file_path = os.path.join(cwd, "..", "..", "onnxruntime", "__init__.py") with open(file_path) as f: lines = f.readlines() @@ -127,6 +111,14 @@ def run(args, cwd): 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")) + # upgrade version.ts in each package + run(["npm", "ci"], cwd=js_root) + run(["npm", "run", "update-version", "common"], cwd=js_root) + run(["npm", "run", "update-version", "node"], cwd=js_root) + run(["npm", "run", "update-version", "web"], cwd=js_root) + run(["npm", "run", "update-version", "react_native"], cwd=js_root) + run(["npm", "run", "format"], cwd=js_root) + if __name__ == "__main__": update_version() diff --git a/tools/python/util/add_openvino_win_libs.py b/tools/python/util/add_openvino_win_libs.py new file mode 100644 index 0000000000000..0cd4c41c1742e --- /dev/null +++ b/tools/python/util/add_openvino_win_libs.py @@ -0,0 +1,35 @@ +# Copyright (C) 2022-2023 Intel Corporation +# Licensed under the MIT License + +import os +import site +import sys + + +def add_openvino_libs_to_path() -> None: + """Adds OpenVINO libraries to the PATH environment variable on Windows.""" + if sys.platform == "win32": + # Installer, pip installs openvino dlls to the different directories + # and those paths need to be visible to the openvino-ep modules + # + # If you're using a custom installation of openvino, + # add the location of openvino dlls to your system PATH. + openvino_libs = [] + # looking for the libs in the pip installation path. + if os.path.isdir(os.path.join(site.getsitepackages()[1], "openvino", "libs")): + openvino_libs.append(os.path.join(site.getsitepackages()[1], "openvino", "libs")) + else: + # setupvars.bat script set all libs paths to OPENVINO_LIB_PATHS environment variable. + openvino_libs_installer = os.getenv("OPENVINO_LIB_PATHS") + if openvino_libs_installer: + openvino_libs.extend(openvino_libs_installer.split(";")) + else: + sys.exit( + "Error: Please set the OPENVINO_LIB_PATHS environment variable. " + "If you use an install package, please, run setupvars.bat" + ) + for lib in openvino_libs: + lib_path = os.path.join(os.path.dirname(__file__), lib) + if os.path.isdir(lib_path): + os.environ["PATH"] = os.path.abspath(lib_path) + ";" + os.environ["PATH"] + os.add_dll_directory(os.path.abspath(lib_path)) diff --git a/tools/python/util/convert_onnx_models_to_ort.py b/tools/python/util/convert_onnx_models_to_ort.py index 2db974643c0f5..18bba78661796 100644 --- a/tools/python/util/convert_onnx_models_to_ort.py +++ b/tools/python/util/convert_onnx_models_to_ort.py @@ -2,13 +2,14 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. +from __future__ import annotations + import argparse import contextlib import enum import os import pathlib import tempfile -import typing import onnxruntime as ort @@ -32,7 +33,7 @@ def _optimization_suffix(optimization_level_str: str, optimization_style: Optimi def _create_config_file_path( model_path_or_dir: pathlib.Path, - output_dir: typing.Optional[pathlib.Path], + output_dir: pathlib.Path | None, optimization_level_str: str, optimization_style: OptimizationStyle, enable_type_reduction: bool, @@ -57,7 +58,7 @@ def _create_session_options( optimization_level: ort.GraphOptimizationLevel, output_model_path: pathlib.Path, custom_op_library: pathlib.Path, - session_options_config_entries: typing.Dict[str, str], + session_options_config_entries: dict[str, str], ): so = ort.SessionOptions() so.optimized_model_filepath = str(output_model_path) @@ -74,15 +75,15 @@ def _create_session_options( def _convert( model_path_or_dir: pathlib.Path, - output_dir: typing.Optional[pathlib.Path], + output_dir: pathlib.Path | None, optimization_level_str: str, optimization_style: OptimizationStyle, custom_op_library: pathlib.Path, create_optimized_onnx_model: bool, allow_conversion_failures: bool, target_platform: str, - session_options_config_entries: typing.Dict[str, str], -) -> typing.List[pathlib.Path]: + session_options_config_entries: dict[str, str], +) -> list[pathlib.Path]: model_dir = model_path_or_dir if model_path_or_dir.is_dir() else model_path_or_dir.parent output_dir = output_dir or model_dir @@ -258,24 +259,33 @@ def parse_args(): "processed.", ) - return parser.parse_args() + parsed_args = parser.parse_args() + parsed_args.optimization_style = [OptimizationStyle[style_str] for style_str in parsed_args.optimization_style] + return parsed_args -def convert_onnx_models_to_ort(): - args = parse_args() +def convert_onnx_models_to_ort( + model_path_or_dir: pathlib.Path, + output_dir: pathlib.Path | None = None, + optimization_styles: list[OptimizationStyle] | None = None, + custom_op_library_path: pathlib.Path | None = None, + target_platform: str | None = None, + save_optimized_onnx_model: bool = False, + allow_conversion_failures: bool = False, + enable_type_reduction: bool = False, +): + if output_dir is not None: + if not output_dir.is_dir(): + output_dir.mkdir(parents=True) + output_dir = output_dir.resolve(strict=True) - output_dir = None - if args.output_dir is not None: - if not args.output_dir.is_dir(): - args.output_dir.mkdir(parents=True) - output_dir = args.output_dir.resolve(strict=True) + optimization_styles = optimization_styles or [] - optimization_styles = [OptimizationStyle[style_str] for style_str in args.optimization_style] # setting optimization level is not expected to be needed by typical users, but it can be set with this # environment variable optimization_level_str = os.getenv("ORT_CONVERT_ONNX_MODELS_TO_ORT_OPTIMIZATION_LEVEL", "all") - model_path_or_dir = args.model_path_or_dir.resolve() - custom_op_library = args.custom_op_library.resolve() if args.custom_op_library else None + model_path_or_dir = model_path_or_dir.resolve() + custom_op_library = custom_op_library_path.resolve() if custom_op_library_path else None if not model_path_or_dir.is_dir() and not model_path_or_dir.is_file(): raise FileNotFoundError(f"Model path '{model_path_or_dir}' is not a file or directory.") @@ -285,7 +295,7 @@ def convert_onnx_models_to_ort(): session_options_config_entries = {} - if args.target_platform == "arm": + if target_platform is not None and target_platform == "arm": session_options_config_entries["session.qdqisint8allowed"] = "1" else: session_options_config_entries["session.qdqisint8allowed"] = "0" @@ -303,9 +313,9 @@ def convert_onnx_models_to_ort(): optimization_level_str=optimization_level_str, optimization_style=optimization_style, custom_op_library=custom_op_library, - create_optimized_onnx_model=args.save_optimized_onnx_model, - allow_conversion_failures=args.allow_conversion_failures, - target_platform=args.target_platform, + create_optimized_onnx_model=save_optimized_onnx_model, + allow_conversion_failures=allow_conversion_failures, + target_platform=target_platform, session_options_config_entries=session_options_config_entries, ) @@ -335,8 +345,8 @@ def convert_onnx_models_to_ort(): optimization_style=OptimizationStyle.Fixed, custom_op_library=custom_op_library, create_optimized_onnx_model=False, # not useful as they would be created in a temp directory - allow_conversion_failures=args.allow_conversion_failures, - target_platform=args.target_platform, + allow_conversion_failures=allow_conversion_failures, + target_platform=target_platform, session_options_config_entries=session_options_config_entries_for_second_conversion, ) @@ -351,11 +361,21 @@ def convert_onnx_models_to_ort(): output_dir, optimization_level_str, optimization_style, - args.enable_type_reduction, + enable_type_reduction, ) - create_config_from_models(converted_models, config_file, args.enable_type_reduction) + create_config_from_models(converted_models, config_file, enable_type_reduction) if __name__ == "__main__": - convert_onnx_models_to_ort() + args = parse_args() + convert_onnx_models_to_ort( + args.model_path_or_dir, + output_dir=args.output_dir, + optimization_styles=args.optimization_style, + custom_op_library_path=args.custom_op_library, + target_platform=args.target_platform, + save_optimized_onnx_model=args.save_optimized_onnx_model, + allow_conversion_failures=args.allow_conversion_failures, + enable_type_reduction=args.enable_type_reduction, + ) diff --git a/tools/python/util/logger.py b/tools/python/util/logger.py index 9deb4475721ee..15e04528ac7ac 100644 --- a/tools/python/util/logger.py +++ b/tools/python/util/logger.py @@ -5,6 +5,7 @@ def get_logger(name): - logging.basicConfig(format="%(asctime)s %(name)s [%(levelname)s] - %(message)s", level=logging.DEBUG) - - return logging.getLogger(name) + logging.basicConfig(format="%(asctime)s %(name)s [%(levelname)s] - %(message)s") + logger = logging.getLogger(name) + logger.setLevel(logging.DEBUG) + return logger diff --git a/tools/python/util/mobile_helpers/usability_checker.py b/tools/python/util/mobile_helpers/usability_checker.py index e93b4bd6986e0..f8b0bfe707ead 100644 --- a/tools/python/util/mobile_helpers/usability_checker.py +++ b/tools/python/util/mobile_helpers/usability_checker.py @@ -8,6 +8,7 @@ import tempfile from collections import deque from enum import IntEnum +from typing import Optional import onnx @@ -188,7 +189,7 @@ def check_partitioning( graph: onnx.GraphProto, supported_ops_checker: _SupportedOpsChecker, require_fixed_input_sizes: bool = False, - value_info: dict = None, + value_info: Optional[dict] = None, ): """ Estimate the partitions the graph will be split into for nodes that is_node_supported_fn returns true for. @@ -356,13 +357,13 @@ def close_group(): return info -def _check_ep_partitioning(model, supported_ops_config, value_info: dict = None): +def _check_ep_partitioning(model, supported_ops_config, value_info: Optional[dict] = None): supported_ops = _SupportedOpsChecker(supported_ops_config) partition_info = check_partitioning(model.graph, supported_ops, value_info is not None, value_info) return partition_info -def check_nnapi_partitions(model, value_info: dict = None): +def check_nnapi_partitions(model, value_info: Optional[dict] = None): # if we're running in the ORT python package the file should be local. otherwise assume we're running from the # ORT repo script_dir = pathlib.Path(__file__).parent @@ -376,7 +377,7 @@ def check_nnapi_partitions(model, value_info: dict = None): return _check_ep_partitioning(model, config_path, value_info) -def check_coreml_partitions(model, value_info: dict = None): +def check_coreml_partitions(model, value_info: Optional[dict] = None): # if we're running in the ORT python package the file should be local. otherwise assume we're running from the # ORT repo script_dir = pathlib.Path(__file__).parent @@ -390,7 +391,7 @@ def check_coreml_partitions(model, value_info: dict = None): return _check_ep_partitioning(model, config_path, value_info) -def check_shapes(graph: onnx.GraphProto, logger: logging.Logger = None): +def check_shapes(graph: onnx.GraphProto, logger: Optional[logging.Logger] = None): """ Check the shapes of graph inputs, values and graph outputs to determine if they have static or dynamic sizes. NNAPI and CoreML do not support dynamically sized values. @@ -522,7 +523,7 @@ def check_ep(ep_name, checker_func): return nnapi_suitability != PartitioningInfo.TryWithEP.NO or coreml_suitability != PartitioningInfo.TryWithEP.NO -def analyze_model(model_path: pathlib.Path, skip_optimize: bool = False, logger: logging.Logger = None): +def analyze_model(model_path: pathlib.Path, skip_optimize: bool = False, logger: Optional[logging.Logger] = None): """ Analyze the provided model to determine if it's likely to work well with the NNAPI or CoreML Execution Providers :param model_path: Model to analyze. diff --git a/tools/python/util/onnx_model_utils.py b/tools/python/util/onnx_model_utils.py index d2205385522e8..e662d1623f8bd 100644 --- a/tools/python/util/onnx_model_utils.py +++ b/tools/python/util/onnx_model_utils.py @@ -3,6 +3,7 @@ import logging import pathlib +from typing import Optional import onnx from onnx import version_converter @@ -59,7 +60,10 @@ def get_opsets_imported(model: onnx.ModelProto): def update_onnx_opset( - model_path: pathlib.Path, opset: int, out_path: pathlib.Path = None, logger: logging.Logger = None + model_path: pathlib.Path, + opset: int, + out_path: Optional[pathlib.Path] = None, + logger: Optional[logging.Logger] = None, ): """ Helper to update the opset of a model using onnx version_converter. Target opset must be greater than current opset. diff --git a/tools/python/util/optimize_onnx_model.py b/tools/python/util/optimize_onnx_model.py index 4cb9b862b37cb..b7ebb54b9c8fa 100644 --- a/tools/python/util/optimize_onnx_model.py +++ b/tools/python/util/optimize_onnx_model.py @@ -14,7 +14,7 @@ def optimize_model_helper(): f"{os.path.basename(__file__)}:{optimize_model_helper.__name__}", description=""" Optimize an ONNX model using ONNX Runtime to the specified level. - See https://onnxruntime.ai/docs/performance/graph-optimizations.html for more + See https://onnxruntime.ai/docs/performance/model-optimizations/graph-optimizations.html for more details of the optimization levels.""", ) diff --git a/tools/python/util/ort_format_model/operator_type_usage_processors.py b/tools/python/util/ort_format_model/operator_type_usage_processors.py index f38bdeae75974..5905000a14972 100644 --- a/tools/python/util/ort_format_model/operator_type_usage_processors.py +++ b/tools/python/util/ort_format_model/operator_type_usage_processors.py @@ -637,7 +637,7 @@ class GloballyAllowedTypesOpTypeImplFilter(OpTypeImplFilterInterface): Operator implementation filter which uses globally allowed types. """ - _valid_allowed_types = set(FbsTypeInfo.tensordatatype_to_string.values()) + _valid_allowed_types = set(FbsTypeInfo.tensordatatype_to_string.values()) # noqa: RUF012 def __init__(self, globally_allowed_types: typing.Set[str]): self._operator_processors = _create_operator_type_usage_processors() diff --git a/tools/python/util/ort_format_model/types.py b/tools/python/util/ort_format_model/types.py index 2b5407a503ccd..ffeda6b2e7607 100644 --- a/tools/python/util/ort_format_model/types.py +++ b/tools/python/util/ort_format_model/types.py @@ -6,7 +6,7 @@ class FbsTypeInfo: "Class to provide conversion between ORT flatbuffers schema values and C++ types" - tensordatatype_to_string = { + tensordatatype_to_string = { # noqa: RUF012 fbs.TensorDataType.TensorDataType.FLOAT: "float", fbs.TensorDataType.TensorDataType.UINT8: "uint8_t", fbs.TensorDataType.TensorDataType.INT8: "int8_t", @@ -23,6 +23,10 @@ class FbsTypeInfo: # fbs.TensorDataType.TensorDataType.COMPLEX64: 'complex64 is not supported', # fbs.TensorDataType.TensorDataType.COMPLEX128: 'complex128 is not supported', fbs.TensorDataType.TensorDataType.BFLOAT16: "BFloat16", + fbs.TensorDataType.TensorDataType.FLOAT8E4M3FN: "Float8E4M3FN", + fbs.TensorDataType.TensorDataType.FLOAT8E4M3FNUZ: "Float8E4M3FNUZ", + fbs.TensorDataType.TensorDataType.FLOAT8E5M2: "Float8E5M2", + fbs.TensorDataType.TensorDataType.FLOAT8E5M2FNUZ: "Float8E5M2FNUZ", } @staticmethod diff --git a/tools/scripts/python_test.sh b/tools/scripts/python_test.sh new file mode 100755 index 0000000000000..bfdd4663feede --- /dev/null +++ b/tools/scripts/python_test.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +set -ex + +export src_dir=$1 +export build_dir=$2 +export config=$3 + +# it's for manylinux image +export PATH=/opt/python/cp38-cp38/bin:$PATH + +echo Install Python Deps +cp $src_dir/tools/ci_build/github/linux/docker/scripts/manylinux/requirements.txt $build_dir/requirements.txt + +python3 -m pip install -r $build_dir/requirements.txt +mkdir -p $build_dir/requirements_torch_cpu/ +cp $src_dir/tools/ci_build/github/linux/docker/scripts/training/ortmodule/stage1/requirements_torch_cpu/requirements.txt $build_dir/requirements_torch_cpu/requirements.txt +python3 -m pip install -r $build_dir/requirements_torch_cpu/requirements.txt +python3 -m pip list | grep onnx + +echo Install $config python package +rm -rf $build_dir/$config/onnxruntime $build_dir/$config/pybind11 +python3 -m pip install $build_dir/$config/dist/*.whl + +echo Run $config unit tests +pushd $build_dir/$config/ +python3 $src_dir/tools/ci_build/build.py --build_dir $build_dir --cmake_generator Ninja --config $config --test --skip_submodule_sync --build_shared_lib --parallel --build_wheel --enable_onnx_tests --enable_transformers_tool_test --ctest_path "" +popd diff --git a/tools/scripts/symbolic_shape_infer_test.sh b/tools/scripts/symbolic_shape_infer_test.sh new file mode 100755 index 0000000000000..d8d50c5e3fa91 --- /dev/null +++ b/tools/scripts/symbolic_shape_infer_test.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +set -ex + +export build_dir=$1 + +# it's for manylinux image +export PATH=/opt/python/cp38-cp38/bin:$PATH + +echo Run symbolic shape infer test +pushd $build_dir/Release/ +python3 /build/Release/onnxruntime_test_python_symbolic_shape_infer.py +popd diff --git a/winml/.clang-format b/winml/.clang-format new file mode 100644 index 0000000000000..e723b3df39ca3 --- /dev/null +++ b/winml/.clang-format @@ -0,0 +1,253 @@ +# Use clang-format -dump-config -style=google to get the base configuration +--- +Language: Cpp +AccessModifierOffset: -1 +AlignAfterOpenBracket: BlockIndent +AlignArrayOfStructures: Right +AlignConsecutiveAssignments: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignConsecutiveBitFields: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignConsecutiveDeclarations: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignConsecutiveMacros: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignEscapedNewlines: Left +AlignOperands: DontAlign +AlignTrailingComments: + Kind: Always + OverEmptyLines: 0 +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortEnumsOnASingleLine: false +AllowShortFunctionsOnASingleLine: InlineOnly +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: Yes +AttributeMacros: + - __capability +BinPackArguments: false +BinPackParameters: false +BitFieldColonSpacing: Both +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterExternBlock: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakAfterAttributes: Never +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: Always +BreakBeforeBraces: Attach +BreakBeforeInlineASMColon: OnlyMultiline +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakInheritanceList: BeforeColon +BreakStringLiterals: false +ColumnLimit: 120 +CommentPragmas: "^ IWYU pragma:" +CompactNamespaces: false +ConstructorInitializerIndentWidth: 2 +ContinuationIndentWidth: 2 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^<.*\.h>' + Priority: 1 + SortPriority: 0 + CaseSensitive: false + - Regex: "^<.*" + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: ".*" + Priority: 3 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: "([-_](test|unittest))?$" +IncludeIsMainSourceRegex: "" +IndentAccessModifiers: false +IndentCaseBlocks: false +IndentCaseLabels: true +IndentExternBlock: AfterExternBlock +IndentGotoLabels: true +IndentPPDirectives: None +IndentRequiresClause: true +IndentWidth: 2 +IndentWrappedFunctionNames: false +InsertBraces: false +InsertNewlineAtEOF: true +InsertTrailingCommas: Wrapped +IntegerLiteralSeparator: + Binary: 0 + BinaryMinDigits: 0 + Decimal: 0 + DecimalMinDigits: 0 + Hex: 0 + HexMinDigits: 0 +KeepEmptyLinesAtTheStartOfBlocks: false +LambdaBodyIndentation: Signature +LineEnding: DeriveLF +MacroBlockBegin: "" +MacroBlockEnd: "" +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Never +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PackConstructorInitializers: CurrentLine +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyIndentedWhitespace: 0 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +PPIndentWidth: -1 +QualifierAlignment: Leave +RawStringFormats: + - Language: Cpp + Delimiters: + - cc + - CC + - cpp + - Cpp + - CPP + - "c++" + - "C++" + CanonicalDelimiter: "" + BasedOnStyle: google + - Language: TextProto + Delimiters: + - pb + - PB + - proto + - PROTO + EnclosingFunctions: + - EqualsProto + - EquivToProto + - PARSE_PARTIAL_TEXT_PROTO + - PARSE_TEST_PROTO + - PARSE_TEXT_PROTO + - ParseTextOrDie + - ParseTextProtoOrDie + - ParseTestProto + - ParsePartialTestProto + CanonicalDelimiter: pb + BasedOnStyle: google +ReferenceAlignment: Pointer +ReflowComments: false +RemoveBracesLLVM: false +RemoveSemicolon: false +RequiresClausePosition: OwnLine +RequiresExpressionIndentation: OuterScope +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SortIncludes: Never +SortJavaStaticImport: Before +SortUsingDeclarations: LexicographicNumeric +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceAroundPointerQualifiers: Default +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + AfterRequiresInClause: false + AfterRequiresInExpression: false + BeforeNonEmptyParentheses: false +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: Never +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Auto +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseTab: Never +WhitespaceSensitiveMacros: + - BOOST_PP_STRINGIZE + - CF_SWIFT_NAME + - NS_SWIFT_NAME + - PP_STRINGIZE + - STRINGIZE + - STRINGIFY + - XSTRINGIFY diff --git a/winml/adapter/abi_custom_registry_impl.cpp b/winml/adapter/abi_custom_registry_impl.cpp index 9fcc2485ef223..a3921d8a92fb7 100644 --- a/winml/adapter/abi_custom_registry_impl.cpp +++ b/winml/adapter/abi_custom_registry_impl.cpp @@ -10,75 +10,75 @@ namespace Windows::AI::MachineLearning::Adapter { HRESULT STDMETHODCALLTYPE AbiCustomRegistryImpl::RegisterOperatorSetSchema( - const MLOperatorSetId* opSetId, - int baseline_version, - const MLOperatorSchemaDescription* const* schema, - uint32_t schemaCount, - _In_opt_ IMLOperatorTypeInferrer* typeInferrer, - _In_opt_ IMLOperatorShapeInferrer* shapeInferrer) const noexcept try { + const MLOperatorSetId* opSetId, + int baseline_version, + const MLOperatorSchemaDescription* const* schema, + uint32_t schemaCount, + _In_opt_ IMLOperatorTypeInferrer* typeInferrer, + _In_opt_ IMLOperatorShapeInferrer* shapeInferrer +) const noexcept try { #ifdef LAYERING_DONE for (uint32_t i = 0; i < schemaCount; ++i) { telemetry_helper.RegisterOperatorSetSchema( - schema[i]->name, - schema[i]->inputCount, - schema[i]->outputCount, - schema[i]->typeConstraintCount, - schema[i]->attributeCount, - schema[i]->defaultAttributeCount); + schema[i]->name, + schema[i]->inputCount, + schema[i]->outputCount, + schema[i]->typeConstraintCount, + schema[i]->attributeCount, + schema[i]->defaultAttributeCount + ); } #endif // Delegate to base class return AbiCustomRegistry::RegisterOperatorSetSchema( - opSetId, - baseline_version, - schema, - schemaCount, - typeInferrer, - shapeInferrer); + opSetId, baseline_version, schema, schemaCount, typeInferrer, shapeInferrer + ); } CATCH_RETURN(); HRESULT STDMETHODCALLTYPE AbiCustomRegistryImpl::RegisterOperatorKernel( - const MLOperatorKernelDescription* opKernel, - IMLOperatorKernelFactory* operatorKernelFactory, - _In_opt_ IMLOperatorShapeInferrer* shapeInferrer) const noexcept { + const MLOperatorKernelDescription* opKernel, + IMLOperatorKernelFactory* operatorKernelFactory, + _In_opt_ IMLOperatorShapeInferrer* shapeInferrer +) const noexcept { return RegisterOperatorKernel(opKernel, operatorKernelFactory, shapeInferrer, nullptr, false, false, false); } HRESULT STDMETHODCALLTYPE AbiCustomRegistryImpl::RegisterOperatorKernel( - const MLOperatorKernelDescription* opKernel, - IMLOperatorKernelFactory* operatorKernelFactory, - _In_opt_ IMLOperatorShapeInferrer* shapeInferrer, - _In_opt_ IMLOperatorSupportQueryPrivate* supportQuery, - bool isInternalOperator, - bool canAliasFirstInput, - bool supportsGraph, - const uint32_t* requiredInputCountForGraph, - _In_reads_(constantCpuInputCount) const uint32_t* requiredConstantCpuInputs, - uint32_t constantCpuInputCount) const noexcept try { + const MLOperatorKernelDescription* opKernel, + IMLOperatorKernelFactory* operatorKernelFactory, + _In_opt_ IMLOperatorShapeInferrer* shapeInferrer, + _In_opt_ IMLOperatorSupportQueryPrivate* supportQuery, + bool isInternalOperator, + bool canAliasFirstInput, + bool supportsGraph, + const uint32_t* requiredInputCountForGraph, + _In_reads_(constantCpuInputCount) const uint32_t* requiredConstantCpuInputs, + uint32_t constantCpuInputCount +) const noexcept try { #ifdef LAYERING_DONE // Log a custom op telemetry if the operator is not a built-in DML operator if (!isInternalOperator) { telemetry_helper.LogRegisterOperatorKernel( - opKernel->name, - opKernel->domain, - static_cast(opKernel->executionType)); + opKernel->name, opKernel->domain, static_cast(opKernel->executionType) + ); } #endif // Delegate to base class return AbiCustomRegistry::RegisterOperatorKernel( - opKernel, - operatorKernelFactory, - shapeInferrer, - supportQuery, - isInternalOperator, - canAliasFirstInput, - supportsGraph, - requiredInputCountForGraph, - requiredConstantCpuInputs, - constantCpuInputCount); + opKernel, + operatorKernelFactory, + shapeInferrer, + supportQuery, + isInternalOperator, + canAliasFirstInput, + supportsGraph, + requiredInputCountForGraph, + requiredConstantCpuInputs, + constantCpuInputCount + ); } CATCH_RETURN(); diff --git a/winml/adapter/abi_custom_registry_impl.h b/winml/adapter/abi_custom_registry_impl.h index 67d6b9127ea31..1942a2e4f82f1 100644 --- a/winml/adapter/abi_custom_registry_impl.h +++ b/winml/adapter/abi_custom_registry_impl.h @@ -12,29 +12,32 @@ namespace Windows::AI::MachineLearning::Adapter { class AbiCustomRegistryImpl : public AbiCustomRegistry { public: HRESULT STDMETHODCALLTYPE RegisterOperatorSetSchema( - const MLOperatorSetId* op_set_id, - int baseline_version, - const MLOperatorSchemaDescription* const* schema, - uint32_t schema_count, - _In_opt_ IMLOperatorTypeInferrer* type_inferrer, - _In_opt_ IMLOperatorShapeInferrer* shape_inferrer) const noexcept override; + const MLOperatorSetId* op_set_id, + int baseline_version, + const MLOperatorSchemaDescription* const* schema, + uint32_t schema_count, + _In_opt_ IMLOperatorTypeInferrer* type_inferrer, + _In_opt_ IMLOperatorShapeInferrer* shape_inferrer + ) const noexcept override; HRESULT STDMETHODCALLTYPE RegisterOperatorKernel( - const MLOperatorKernelDescription* operator_kernel, - IMLOperatorKernelFactory* operator_kernel_factory, - _In_opt_ IMLOperatorShapeInferrer* shape_inferrer, - _In_opt_ IMLOperatorSupportQueryPrivate* supportQuery, - bool is_internal_operator, - bool can_alias_first_input, - bool supports_graph, - const uint32_t* required_input_count_for_graph = nullptr, - _In_reads_(constant_cpu_input_count) const uint32_t* required_constant_cpu_inputs = nullptr, - uint32_t constant_cpu_input_count = 0) const noexcept override; + const MLOperatorKernelDescription* operator_kernel, + IMLOperatorKernelFactory* operator_kernel_factory, + _In_opt_ IMLOperatorShapeInferrer* shape_inferrer, + _In_opt_ IMLOperatorSupportQueryPrivate* supportQuery, + bool is_internal_operator, + bool can_alias_first_input, + bool supports_graph, + const uint32_t* required_input_count_for_graph = nullptr, + _In_reads_(constant_cpu_input_count) const uint32_t* required_constant_cpu_inputs = nullptr, + uint32_t constant_cpu_input_count = 0 + ) const noexcept override; HRESULT STDMETHODCALLTYPE RegisterOperatorKernel( - const MLOperatorKernelDescription* op_kernel, - IMLOperatorKernelFactory* operator_kernel_factory, - _In_opt_ IMLOperatorShapeInferrer* shape_inferrer) const noexcept override; + const MLOperatorKernelDescription* op_kernel, + IMLOperatorKernelFactory* operator_kernel_factory, + _In_opt_ IMLOperatorShapeInferrer* shape_inferrer + ) const noexcept override; }; } // namespace Windows::AI::MachineLearning::Adapter diff --git a/winml/adapter/winml_adapter_apis.h b/winml/adapter/winml_adapter_apis.h index a4f115e9e96da..9542c3a03fefe 100644 --- a/winml/adapter/winml_adapter_apis.h +++ b/winml/adapter/winml_adapter_apis.h @@ -17,7 +17,16 @@ ORT_API(void, ReleaseExecutionProvider, OrtExecutionProvider*); ORT_API_STATUS(OverrideSchema); // OrtEnv methods -ORT_API_STATUS(EnvConfigureCustomLoggerAndProfiler, _In_ OrtEnv* env, OrtLoggingFunction logging_function, OrtProfilingFunction profiling_function, _In_opt_ void* logger_param, OrtLoggingLevel default_warning_level, _In_ const char* logid, _Outptr_ OrtEnv** out); +ORT_API_STATUS( + EnvConfigureCustomLoggerAndProfiler, + _In_ OrtEnv* env, + OrtLoggingFunction logging_function, + OrtProfilingFunction profiling_function, + _In_opt_ void* logger_param, + OrtLoggingLevel default_warning_level, + _In_ const char* logid, + _Outptr_ OrtEnv** out +); // OrtModel methods ORT_API_STATUS(CreateModelFromPath, _In_ const char* model_path, _In_ size_t size, _Outptr_ OrtModel** out); @@ -27,28 +36,69 @@ ORT_API_STATUS(ModelGetAuthor, _In_ const OrtModel* model, _Out_ const char** co ORT_API_STATUS(ModelGetName, _In_ const OrtModel* model, _Out_ const char** const name, _Out_ size_t* len); ORT_API_STATUS(ModelSetName, _In_ const OrtModel* model, _In_ const char* name); ORT_API_STATUS(ModelGetDomain, _In_ const OrtModel* model, _Out_ const char** const domain, _Out_ size_t* len); -ORT_API_STATUS(ModelGetDescription, _In_ const OrtModel* model, _Out_ const char** const description, _Out_ size_t* len); +ORT_API_STATUS( + ModelGetDescription, _In_ const OrtModel* model, _Out_ const char** const description, _Out_ size_t* len +); ORT_API_STATUS(ModelGetVersion, _In_ const OrtModel* model, _Out_ int64_t* version); ORT_API_STATUS(ModelGetInputCount, _In_ const OrtModel* model, _Out_ size_t* count); ORT_API_STATUS(ModelGetOutputCount, _In_ const OrtModel* model, _Out_ size_t* count); -ORT_API_STATUS(ModelGetInputName, _In_ const OrtModel* model, _In_ size_t index, _Out_ const char** input_name, _Out_ size_t* count); -ORT_API_STATUS(ModelGetOutputName, _In_ const OrtModel* model, _In_ size_t index, _Out_ const char** output_name, _Out_ size_t* count); -ORT_API_STATUS(ModelGetInputDescription, _In_ const OrtModel* model, _In_ size_t index, _Out_ const char** input_description, _Out_ size_t* count); -ORT_API_STATUS(ModelGetOutputDescription, _In_ const OrtModel* model, _In_ size_t index, _Out_ const char** output_description, _Out_ size_t* count); +ORT_API_STATUS( + ModelGetInputName, _In_ const OrtModel* model, _In_ size_t index, _Out_ const char** input_name, _Out_ size_t* count +); +ORT_API_STATUS( + ModelGetOutputName, _In_ const OrtModel* model, _In_ size_t index, _Out_ const char** output_name, _Out_ size_t* count +); +ORT_API_STATUS( + ModelGetInputDescription, + _In_ const OrtModel* model, + _In_ size_t index, + _Out_ const char** input_description, + _Out_ size_t* count +); +ORT_API_STATUS( + ModelGetOutputDescription, + _In_ const OrtModel* model, + _In_ size_t index, + _Out_ const char** output_description, + _Out_ size_t* count +); ORT_API_STATUS(ModelGetInputTypeInfo, _In_ const OrtModel* model, _In_ size_t index, _Outptr_ OrtTypeInfo** type_info); ORT_API_STATUS(ModelGetOutputTypeInfo, _In_ const OrtModel* model, _In_ size_t index, _Outptr_ OrtTypeInfo** type_info); ORT_API_STATUS(ModelGetMetadataCount, _In_ const OrtModel* model, _Out_ size_t* count); -ORT_API_STATUS(ModelGetMetadata, _In_ const OrtModel* model, _In_ size_t count, _Out_ const char** const key, _Out_ size_t* key_len, _Out_ const char** const value, _Out_ size_t* value_len); +ORT_API_STATUS( + ModelGetMetadata, + _In_ const OrtModel* model, + _In_ size_t count, + _Out_ const char** const key, + _Out_ size_t* key_len, + _Out_ const char** const value, + _Out_ size_t* value_len +); ORT_API_STATUS(ModelEnsureNoFloat16, _In_ const OrtModel* model); ORT_API_STATUS(SaveModel, _In_ const OrtModel* in, _In_ const wchar_t* const file_name, _In_ size_t len); -ORT_API_STATUS(OrtSessionOptionsAppendExecutionProviderEx_DML, _In_ OrtSessionOptions* options, _In_ ID3D12Device* d3d_device, _In_ ID3D12CommandQueue* cmd_queue, bool metacommands_enabled); +ORT_API_STATUS( + OrtSessionOptionsAppendExecutionProviderEx_DML, + _In_ OrtSessionOptions* options, + _In_ ID3D12Device* d3d_device, + _In_ ID3D12CommandQueue* cmd_queue, + bool metacommands_enabled +); // OrtSession methods -ORT_API_STATUS(CreateSessionWithoutModel, _In_ OrtEnv* env, _In_ const OrtSessionOptions* options, _In_ OrtThreadPool* inter_op_thread_pool, _In_ OrtThreadPool* intra_op_thread_pool, _Outptr_ OrtSession** session); +ORT_API_STATUS( + CreateSessionWithoutModel, + _In_ OrtEnv* env, + _In_ const OrtSessionOptions* options, + _In_ OrtThreadPool* inter_op_thread_pool, + _In_ OrtThreadPool* intra_op_thread_pool, + _Outptr_ OrtSession** session +); //Do not release provider... as there is no release method available -ORT_API_STATUS(SessionGetExecutionProvider, _In_ OrtSession* session, _In_ size_t index, _Out_ OrtExecutionProvider** provider); +ORT_API_STATUS( + SessionGetExecutionProvider, _In_ OrtSession* session, _In_ size_t index, _Out_ OrtExecutionProvider** provider +); ORT_API_STATUS(SessionInitialize, _In_ OrtSession* session); ORT_API_STATUS(SessionLoadAndPurloinModel, _In_ OrtSession* session, _In_ OrtModel* model); @@ -56,20 +106,31 @@ ORT_API_STATUS(SessionStartProfiling, _In_ OrtEnv* env, _In_ OrtSession* session ORT_API_STATUS(SessionEndProfiling, _In_ OrtSession* session); ORT_API_STATUS(SessionRegisterGraphTransformers, _In_ OrtSession* session); ORT_API_STATUS(SessionRegisterCustomRegistry, _In_ OrtSession* session, _In_ IMLOperatorRegistry* registry); -ORT_API_STATUS(SessionCopyOneInputAcrossDevices, _In_ OrtSession* session, _In_ const char* const input_name, _In_ OrtValue* orig_value, _Outptr_ OrtValue** new_value); +ORT_API_STATUS( + SessionCopyOneInputAcrossDevices, + _In_ OrtSession* session, + _In_ const char* const input_name, + _In_ OrtValue* orig_value, + _Outptr_ OrtValue** new_value +); ORT_API_STATUS(SessionGetNumberOfIntraOpThreads, _In_ OrtSession* session, _Out_ uint32_t* num_threads); ORT_API_STATUS(SessionGetIntraOpThreadSpinning, _In_ OrtSession* session, _Out_ bool* allow_spinning); -ORT_API_STATUS(SessionGetNamedDimensionsOverrides, _In_ OrtSession* session, _Out_ winrt::Windows::Foundation::Collections::IMapView& overrides); +ORT_API_STATUS( + SessionGetNamedDimensionsOverrides, + _In_ OrtSession* session, + _Out_ winrt::Windows::Foundation::Collections::IMapView& overrides +); // Dml methods (TODO need to figure out how these need to move to session somehow...) -ORT_API_STATUS(DmlExecutionProviderSetDefaultRoundingMode, _In_ OrtExecutionProvider* dml_provider, _In_ bool is_enabled); ORT_API_STATUS(DmlExecutionProviderFlushContext, _In_ OrtExecutionProvider* dml_provider); ORT_API_STATUS(DmlExecutionProviderReleaseCompletedReferences, _In_ OrtExecutionProvider* dml_provider); // note: this returns a weak ref ORT_API_STATUS(GetProviderMemoryInfo, _In_ OrtExecutionProvider* provider, OrtMemoryInfo** memory_info); -ORT_API_STATUS(GetProviderAllocator, _In_ OrtExecutionProvider* provider, OrtAllocator** allocator); +ORT_API_STATUS( + GetProviderAllocator, _In_ OrtSession* session, _In_ OrtExecutionProvider* provider, OrtAllocator** allocator +); ORT_API_STATUS(FreeProviderAllocator, _In_ OrtAllocator* allocator); // ExecutionProvider Methods @@ -78,67 +139,96 @@ ORT_API_STATUS(DmlCopyTensor, _In_ OrtExecutionProvider* provider, _In_ OrtValue ORT_API_STATUS(CreateCustomRegistry, _Out_ IMLOperatorRegistry** registry); ORT_API_STATUS(ValueGetDeviceId, _In_ OrtValue* ort_value, _Out_ int16_t* device_id); -ORT_API_STATUS(SessionGetInputRequiredDeviceId, _In_ OrtSession* session, _In_ const char* const input_name, _Out_ int16_t* device_id); +ORT_API_STATUS( + SessionGetInputRequiredDeviceId, _In_ OrtSession* session, _In_ const char* const input_name, _Out_ int16_t* device_id +); // Model Building -ORT_API_STATUS(CreateTensorTypeInfo, _In_ const int64_t* shape, size_t shape_len, ONNXTensorElementDataType type, _Out_ OrtTypeInfo** type_info); +ORT_API_STATUS( + CreateTensorTypeInfo, + _In_ const int64_t* shape, + size_t shape_len, + ONNXTensorElementDataType type, + _Out_ OrtTypeInfo** type_info +); ORT_API_STATUS(CreateSequenceTypeInfo, _Out_ OrtTypeInfo** type_info); ORT_API_STATUS(CreateMapTypeInfo, _Out_ OrtTypeInfo** type_info); ORT_API_STATUS(CreateModel, _In_ int64_t opset, _Outptr_ OrtModel** out); ORT_API_STATUS(ModelAddInput, _In_ OrtModel* model, _In_ const char* const input_name, _In_ OrtTypeInfo* info); -ORT_API_STATUS(ModelAddConstantInput, _In_ OrtModel* model, _In_ const char* const input_name, _In_ OrtTypeInfo* info, _In_ OrtValue* value); +ORT_API_STATUS( + ModelAddConstantInput, + _In_ OrtModel* model, + _In_ const char* const input_name, + _In_ OrtTypeInfo* info, + _In_ OrtValue* value +); ORT_API_STATUS(ModelAddOutput, _In_ OrtModel* model, _In_ const char* const output_name, _In_ OrtTypeInfo* info); -ORT_API_STATUS(ModelAddOperator, - _In_ OrtModel* model, - _In_ const char* const op_type, - _In_ const char* const op_name, - _In_ int64_t opset, - _In_ const char* const op_domain, - _In_ const char* const* input_names, _In_ size_t num_inputs, - _In_ const char* const* output_names, _In_ size_t num_outputs, - _In_ const char* const* attribute_names, _In_ OrtValue** attribute_values, _In_ size_t num_attributes); +ORT_API_STATUS( + ModelAddOperator, + _In_ OrtModel* model, + _In_ const char* const op_type, + _In_ const char* const op_name, + _In_ int64_t opset, + _In_ const char* const op_domain, + _In_ const char* const* input_names, + _In_ size_t num_inputs, + _In_ const char* const* output_names, + _In_ size_t num_outputs, + _In_ const char* const* attribute_names, + _In_ OrtValue** attribute_values, + _In_ size_t num_attributes +); ORT_API_STATUS(ModelGetOpsetVersion, _In_ OrtModel* model, _In_ const char* const domain, _Out_ int32_t* version); -ORT_API_STATUS(OperatorGetNumInputs, - _In_ const char* const op_type, - _In_ int64_t opset, - _In_ const char* const op_domain, - _Out_ size_t* num_inputs); - -ORT_API_STATUS(OperatorGetInputName, - _In_ const char* const op_type, - _In_ int64_t opset, - _In_ const char* const op_domain, - _In_ size_t index, - _Out_ const char** const name); - -ORT_API_STATUS(OperatorGetNumOutputs, - _In_ const char* const op_type, - _In_ int64_t opset, - _In_ const char* const op_domain, - _Out_ size_t* num_inputs); - -ORT_API_STATUS(OperatorGetOutputName, - _In_ const char* const op_type, - _In_ int64_t opset, - _In_ const char* const op_domain, - _In_ size_t index, - _Out_ const char** const name); - -ORT_API_STATUS(JoinModels, - _In_ OrtModel* first_model, - _In_ OrtModel* second_model, - _In_ const char* const* output_names, - _In_ const char* const* input_names, - size_t num_linkages, - bool promote_unlinked_outputs, - _In_ const char* const join_node_prefix); - -ORT_API_STATUS(CreateThreadPool, - _In_ ThreadPoolType type, - _In_ OrtThreadPoolOptions* params, - _Outptr_ OrtThreadPool** out); +ORT_API_STATUS( + OperatorGetNumInputs, + _In_ const char* const op_type, + _In_ int64_t opset, + _In_ const char* const op_domain, + _Out_ size_t* num_inputs +); + +ORT_API_STATUS( + OperatorGetInputName, + _In_ const char* const op_type, + _In_ int64_t opset, + _In_ const char* const op_domain, + _In_ size_t index, + _Out_ const char** const name +); + +ORT_API_STATUS( + OperatorGetNumOutputs, + _In_ const char* const op_type, + _In_ int64_t opset, + _In_ const char* const op_domain, + _Out_ size_t* num_inputs +); + +ORT_API_STATUS( + OperatorGetOutputName, + _In_ const char* const op_type, + _In_ int64_t opset, + _In_ const char* const op_domain, + _In_ size_t index, + _Out_ const char** const name +); + +ORT_API_STATUS( + JoinModels, + _In_ OrtModel* first_model, + _In_ OrtModel* second_model, + _In_ const char* const* output_names, + _In_ const char* const* input_names, + size_t num_linkages, + bool promote_unlinked_outputs, + _In_ const char* const join_node_prefix +); + +ORT_API_STATUS( + CreateThreadPool, _In_ ThreadPoolType type, _In_ OrtThreadPoolOptions* params, _Outptr_ OrtThreadPool** out +); // maps and sequences??? //ONNX_NAMESPACE::OpSchemaRegistry::DomainToVersionRange().Map().at(ONNX_NAMESPACE::ONNX_DOMAIN).second diff --git a/winml/adapter/winml_adapter_c_api.cpp b/winml/adapter/winml_adapter_c_api.cpp index a3e597fb88800..abfe41dd26749 100644 --- a/winml/adapter/winml_adapter_c_api.cpp +++ b/winml/adapter/winml_adapter_c_api.cpp @@ -14,89 +14,88 @@ const OrtApi* GetVersion1Api(); namespace winmla = Windows::AI::MachineLearning::Adapter; static constexpr WinmlAdapterApi winml_adapter_api_1 = { - // Schema override - &winmla::OverrideSchema, - - // OrtEnv methods - &winmla::EnvConfigureCustomLoggerAndProfiler, - - // OrtModel methods - &winmla::CreateModelFromPath, - &winmla::CreateModelFromData, - &winmla::CloneModel, - &winmla::ModelGetAuthor, - &winmla::ModelGetName, - &winmla::ModelSetName, - &winmla::ModelGetDomain, - &winmla::ModelGetDescription, - &winmla::ModelGetVersion, - &winmla::ModelGetInputCount, - &winmla::ModelGetOutputCount, - &winmla::ModelGetInputName, - &winmla::ModelGetOutputName, - &winmla::ModelGetInputDescription, - &winmla::ModelGetOutputDescription, - &winmla::ModelGetInputTypeInfo, - &winmla::ModelGetOutputTypeInfo, - &winmla::ModelGetMetadataCount, - &winmla::ModelGetMetadata, - &winmla::ModelEnsureNoFloat16, - &winmla::SaveModel, - - // OrtSessionOptions methods - &OrtSessionOptionsAppendExecutionProvider_CPU, - &winmla::OrtSessionOptionsAppendExecutionProviderEx_DML, - - // OrtSession methods - &winmla::CreateSessionWithoutModel, - &winmla::SessionGetExecutionProvider, - &winmla::SessionInitialize, - &winmla::SessionRegisterGraphTransformers, - &winmla::SessionRegisterCustomRegistry, - &winmla::SessionLoadAndPurloinModel, - &winmla::SessionStartProfiling, - &winmla::SessionEndProfiling, - &winmla::SessionCopyOneInputAcrossDevices, - &winmla::SessionGetNumberOfIntraOpThreads, - &winmla::SessionGetIntraOpThreadSpinning, - &winmla::SessionGetNamedDimensionsOverrides, - - // Dml methods (TODO need to figure out how these need to move to session somehow...) - &winmla::DmlExecutionProviderSetDefaultRoundingMode, - &winmla::DmlExecutionProviderFlushContext, - &winmla::DmlExecutionProviderReleaseCompletedReferences, - &winmla::DmlCopyTensor, - - &winmla::GetProviderMemoryInfo, - &winmla::GetProviderAllocator, - &winmla::FreeProviderAllocator, - - &winmla::ExecutionProviderSync, - - &winmla::CreateCustomRegistry, - - &winmla::ValueGetDeviceId, - &winmla::SessionGetInputRequiredDeviceId, - - &winmla::CreateTensorTypeInfo, - &winmla::CreateSequenceTypeInfo, - &winmla::CreateMapTypeInfo, - &winmla::CreateModel, - &winmla::ModelAddInput, - &winmla::ModelAddConstantInput, - &winmla::ModelAddOutput, - &winmla::ModelAddOperator, - &winmla::ModelGetOpsetVersion, - &winmla::OperatorGetNumInputs, - &winmla::OperatorGetInputName, - &winmla::OperatorGetNumOutputs, - &winmla::OperatorGetOutputName, - &winmla::JoinModels, - &winmla::CreateThreadPool, - - // Release - &winmla::ReleaseModel, - &winmla::ReleaseThreadPool, + // Schema override + &winmla::OverrideSchema, + + // OrtEnv methods + &winmla::EnvConfigureCustomLoggerAndProfiler, + + // OrtModel methods + &winmla::CreateModelFromPath, + &winmla::CreateModelFromData, + &winmla::CloneModel, + &winmla::ModelGetAuthor, + &winmla::ModelGetName, + &winmla::ModelSetName, + &winmla::ModelGetDomain, + &winmla::ModelGetDescription, + &winmla::ModelGetVersion, + &winmla::ModelGetInputCount, + &winmla::ModelGetOutputCount, + &winmla::ModelGetInputName, + &winmla::ModelGetOutputName, + &winmla::ModelGetInputDescription, + &winmla::ModelGetOutputDescription, + &winmla::ModelGetInputTypeInfo, + &winmla::ModelGetOutputTypeInfo, + &winmla::ModelGetMetadataCount, + &winmla::ModelGetMetadata, + &winmla::ModelEnsureNoFloat16, + &winmla::SaveModel, + + // OrtSessionOptions methods + &OrtSessionOptionsAppendExecutionProvider_CPU, + &winmla::OrtSessionOptionsAppendExecutionProviderEx_DML, + + // OrtSession methods + &winmla::CreateSessionWithoutModel, + &winmla::SessionGetExecutionProvider, + &winmla::SessionInitialize, + &winmla::SessionRegisterGraphTransformers, + &winmla::SessionRegisterCustomRegistry, + &winmla::SessionLoadAndPurloinModel, + &winmla::SessionStartProfiling, + &winmla::SessionEndProfiling, + &winmla::SessionCopyOneInputAcrossDevices, + &winmla::SessionGetNumberOfIntraOpThreads, + &winmla::SessionGetIntraOpThreadSpinning, + &winmla::SessionGetNamedDimensionsOverrides, + + // Dml methods (TODO need to figure out how these need to move to session somehow...) + &winmla::DmlExecutionProviderFlushContext, + &winmla::DmlExecutionProviderReleaseCompletedReferences, + &winmla::DmlCopyTensor, + + &winmla::GetProviderMemoryInfo, + &winmla::GetProviderAllocator, + &winmla::FreeProviderAllocator, + + &winmla::ExecutionProviderSync, + + &winmla::CreateCustomRegistry, + + &winmla::ValueGetDeviceId, + &winmla::SessionGetInputRequiredDeviceId, + + &winmla::CreateTensorTypeInfo, + &winmla::CreateSequenceTypeInfo, + &winmla::CreateMapTypeInfo, + &winmla::CreateModel, + &winmla::ModelAddInput, + &winmla::ModelAddConstantInput, + &winmla::ModelAddOutput, + &winmla::ModelAddOperator, + &winmla::ModelGetOpsetVersion, + &winmla::OperatorGetNumInputs, + &winmla::OperatorGetInputName, + &winmla::OperatorGetNumOutputs, + &winmla::OperatorGetOutputName, + &winmla::JoinModels, + &winmla::CreateThreadPool, + + // Release + &winmla::ReleaseModel, + &winmla::ReleaseThreadPool, }; const WinmlAdapterApi* ORT_API_CALL OrtGetWinMLAdapter(_In_ uint32_t ort_version) NO_EXCEPTION { @@ -105,4 +104,4 @@ const WinmlAdapterApi* ORT_API_CALL OrtGetWinMLAdapter(_In_ uint32_t ort_version } return nullptr; -} \ No newline at end of file +} diff --git a/winml/adapter/winml_adapter_c_api.h b/winml/adapter/winml_adapter_c_api.h index 7113b381880e4..6c77664b92c37 100644 --- a/winml/adapter/winml_adapter_c_api.h +++ b/winml/adapter/winml_adapter_c_api.h @@ -7,9 +7,9 @@ #include "winrt/windows.foundation.collections.h" /** - * All APIs exported by winml_adapter_c_api.h are part of the private interface dedicated to supporting the WinML API. - * This contract is subject to change based on the needs of the WinML API and is not intended for direct use by callers - * of the onnxruntime c-api and usage of APIs in this header are *not* supported by the onnxruntime product. + * All APIs exported by winml_adapter_c_api.h are part of the private interface dedicated to supporting the WinML API. + * This contract is subject to change based on the needs of the WinML API and is not intended for direct use by callers + * of the onnxruntime c-api and usage of APIs in this header are *not* supported by the onnxruntime product. */ ORT_RUNTIME_CLASS(Model); @@ -75,216 +75,263 @@ struct OrtThreadPoolOptions { struct WinmlAdapterApi { /** * OverrideSchema - * This api is used to override schema inference functions for a variety of ops across opsets. - * This exists because certain ops were failing to infer schemas and caused performance - * issues for DML as it was forced to create resources during evaluation. - * This can be removed when schema inference functions have been updated. + * This api is used to override schema inference functions for a variety of ops across opsets. + * This exists because certain ops were failing to infer schemas and caused performance + * issues for DML as it was forced to create resources during evaluation. + * This can be removed when schema inference functions have been updated. */ OrtStatus*(ORT_API_CALL* OverrideSchema)() NO_EXCEPTION; /** - * EnvConfigureCustomLoggerAndProfiler - * This api is used to add a custom logger and profiler to the ors environment. - * This exists because existing methods on the c-abi to create the environment only support a custom logger. - * Since WinML hooks the profiler events, we expose the profiler and an associated profiling function. + * EnvConfigureCustomLoggerAndProfiler + * This api is used to add a custom logger and profiler to the ors environment. + * This exists because existing methods on the c-abi to create the environment only support a custom logger. + * Since WinML hooks the profiler events, we expose the profiler and an associated profiling function. */ - OrtStatus*(ORT_API_CALL* EnvConfigureCustomLoggerAndProfiler)(_In_ OrtEnv* env, OrtLoggingFunction logging_function, OrtProfilingFunction profiling_function, _In_opt_ void* logger_param, OrtLoggingLevel default_warning_level, _In_ const char* logid, _Outptr_ OrtEnv** out)NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* EnvConfigureCustomLoggerAndProfiler)( + _In_ OrtEnv* env, + OrtLoggingFunction logging_function, + OrtProfilingFunction profiling_function, + _In_opt_ void* logger_param, + OrtLoggingLevel default_warning_level, + _In_ const char* logid, + _Outptr_ OrtEnv** out + )NO_EXCEPTION; // OrtModel methods /** * CreateModelFromPath - * This api creates an OrtModel based on a specified model path. - * There is no inferencing or evaluation setup performed. Only ONNX load is done to reflect on the model's inputs/outputs and other properties. - * This is used by WinML to support model reflection APIs. + * This api creates an OrtModel based on a specified model path. + * There is no inferencing or evaluation setup performed. Only ONNX load is done to reflect on the model's inputs/outputs and other properties. + * This is used by WinML to support model reflection APIs. */ - OrtStatus*(ORT_API_CALL* CreateModelFromPath)(_In_ const char* model_path, _In_ size_t size, _Outptr_ OrtModel** out)NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* CreateModelFromPath)(_In_ const char* model_path, _In_ size_t size, _Outptr_ OrtModel** out) + NO_EXCEPTION; /** * CreateModelFromData - * This api creates an OrtModel from a buffer. - * There is no inferencing or evaluation setup performed. Only ONNX load is done to reflect on the model's inputs/outputs and other properties. - * This is used by WinML to support model reflection APIs. + * This api creates an OrtModel from a buffer. + * There is no inferencing or evaluation setup performed. Only ONNX load is done to reflect on the model's inputs/outputs and other properties. + * This is used by WinML to support model reflection APIs. */ - OrtStatus*(ORT_API_CALL* CreateModelFromData)(_In_opt_ void* data, _In_ size_t size, _Outptr_ OrtModel** out)NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* CreateModelFromData)(_In_opt_ void* data, _In_ size_t size, _Outptr_ OrtModel** out) + NO_EXCEPTION; /** * CloneModel - * This api copies the OrtModel along with its internal proto buffer and cached metadata. - * The OrtSession type expects to own the model proto buffer. - * WinML uses this to yield copies of the model proto held by OrtModel to OrtSession. + * This api copies the OrtModel along with its internal proto buffer and cached metadata. + * The OrtSession type expects to own the model proto buffer. + * WinML uses this to yield copies of the model proto held by OrtModel to OrtSession. */ OrtStatus*(ORT_API_CALL* CloneModel)(_In_ const OrtModel* in, _Outptr_ OrtModel** out)NO_EXCEPTION; /** * ModelGetAuthor - * This api gets the model author from the OrtModel. - * This is used by WinML to support model reflection APIs. + * This api gets the model author from the OrtModel. + * This is used by WinML to support model reflection APIs. */ - OrtStatus*(ORT_API_CALL* ModelGetAuthor)(_In_ const OrtModel* model, _Out_ const char** const author, _Out_ size_t* len)NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* ModelGetAuthor)( + _In_ const OrtModel* model, _Out_ const char** const author, _Out_ size_t* len + )NO_EXCEPTION; /** * ModelGetName - * This api gets the model name from the OrtModel. - * This is used by WinML to support model reflection APIs. + * This api gets the model name from the OrtModel. + * This is used by WinML to support model reflection APIs. */ - OrtStatus*(ORT_API_CALL* ModelGetName)(_In_ const OrtModel* model, _Out_ const char** const name, _Out_ size_t* len)NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* ModelGetName)(_In_ const OrtModel* model, _Out_ const char** const name, _Out_ size_t* len) + NO_EXCEPTION; /** * ModelSetName - * This api set the model name from the OrtModel. - * This is used by the Windows ML Samples Gallery to change the model name for telemetry. + * This api set the model name from the OrtModel. + * This is used by the Windows ML Samples Gallery to change the model name for telemetry. */ OrtStatus*(ORT_API_CALL* ModelSetName)(_In_ const OrtModel* model, _In_ const char* name)NO_EXCEPTION; /** * ModelGetDomain - * This api gets the model domain from the OrtModel. - * This is used by WinML to support model reflection APIs. + * This api gets the model domain from the OrtModel. + * This is used by WinML to support model reflection APIs. */ - OrtStatus*(ORT_API_CALL* ModelGetDomain)(_In_ const OrtModel* model, _Out_ const char** const domain, _Out_ size_t* len)NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* ModelGetDomain)( + _In_ const OrtModel* model, _Out_ const char** const domain, _Out_ size_t* len + )NO_EXCEPTION; /** * ModelGetDescription - * This api gets the model description from the OrtModel. - * This is used by WinML to support model reflection APIs. + * This api gets the model description from the OrtModel. + * This is used by WinML to support model reflection APIs. */ - OrtStatus*(ORT_API_CALL* ModelGetDescription)(_In_ const OrtModel* model, _Out_ const char** const description, _Out_ size_t* len)NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* ModelGetDescription)( + _In_ const OrtModel* model, _Out_ const char** const description, _Out_ size_t* len + )NO_EXCEPTION; /** * ModelGetVersion - * This api gets the model version from the OrtModel. - * This is used by WinML to support model reflection APIs. + * This api gets the model version from the OrtModel. + * This is used by WinML to support model reflection APIs. */ OrtStatus*(ORT_API_CALL* ModelGetVersion)(_In_ const OrtModel* model, _Out_ int64_t* version)NO_EXCEPTION; /** * ModelGetInputCount - * This api gets the number of inputs from the OrtModel. It closely matches the API of a similar name similar name for retrieving model metadata from OrtSession. - * This is used by WinML to support model reflection APIs. + * This api gets the number of inputs from the OrtModel. It closely matches the API of a similar name similar name for retrieving model metadata from OrtSession. + * This is used by WinML to support model reflection APIs. */ OrtStatus*(ORT_API_CALL* ModelGetInputCount)(_In_ const OrtModel* model, _Out_ size_t* count)NO_EXCEPTION; /** * ModelGetOutputCount - * This api gets the number of outputs from the OrtModel. It closely matches the API of a similar name for retrieving model metadata from OrtSession. - * This is used by WinML to support model reflection APIs. + * This api gets the number of outputs from the OrtModel. It closely matches the API of a similar name for retrieving model metadata from OrtSession. + * This is used by WinML to support model reflection APIs. */ OrtStatus*(ORT_API_CALL* ModelGetOutputCount)(_In_ const OrtModel* model, _Out_ size_t* count)NO_EXCEPTION; /** * ModelGetInputName - * This api gets the input name from the OrtModel given an index. It closely matches the API of a similar name for retrieving model metadata from OrtSession. - * This is used by WinML to support model reflection APIs. + * This api gets the input name from the OrtModel given an index. It closely matches the API of a similar name for retrieving model metadata from OrtSession. + * This is used by WinML to support model reflection APIs. */ - OrtStatus*(ORT_API_CALL* ModelGetInputName)(_In_ const OrtModel* model, _In_ size_t index, _Out_ const char** input_name, _Out_ size_t* count)NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* ModelGetInputName)( + _In_ const OrtModel* model, _In_ size_t index, _Out_ const char** input_name, _Out_ size_t* count + )NO_EXCEPTION; /** * ModelGetOutputName - * This api gets the output name from the OrtModel given an index. It closely matches the API of a similar name for retrieving model metadata from OrtSession. - * This is used by WinML to support model reflection APIs. + * This api gets the output name from the OrtModel given an index. It closely matches the API of a similar name for retrieving model metadata from OrtSession. + * This is used by WinML to support model reflection APIs. */ - OrtStatus*(ORT_API_CALL* ModelGetOutputName)(_In_ const OrtModel* model, _In_ size_t index, _Out_ const char** output_name, _Out_ size_t* count)NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* ModelGetOutputName)( + _In_ const OrtModel* model, _In_ size_t index, _Out_ const char** output_name, _Out_ size_t* count + )NO_EXCEPTION; /** * ModelGetInputDescription - * This api gets the input description from the OrtModel given an index. It closely matches the API of a similar name for retrieving model metadata from OrtSession. - * This is used by WinML to support model reflection APIs. + * This api gets the input description from the OrtModel given an index. It closely matches the API of a similar name for retrieving model metadata from OrtSession. + * This is used by WinML to support model reflection APIs. */ - OrtStatus*(ORT_API_CALL* ModelGetInputDescription)(_In_ const OrtModel* model, _In_ size_t index, _Out_ const char** input_description, _Out_ size_t* count)NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* ModelGetInputDescription)( + _In_ const OrtModel* model, _In_ size_t index, _Out_ const char** input_description, _Out_ size_t* count + )NO_EXCEPTION; /** * ModelGetOutputDescription - * This api gets the output description from the OrtModel given an index. It closely matches the API of a similar name for retrieving model metadata from OrtSession. - * This is used by WinML to support model reflection APIs. + * This api gets the output description from the OrtModel given an index. It closely matches the API of a similar name for retrieving model metadata from OrtSession. + * This is used by WinML to support model reflection APIs. */ - OrtStatus*(ORT_API_CALL* ModelGetOutputDescription)(_In_ const OrtModel* model, _In_ size_t index, _Out_ const char** output_description, _Out_ size_t* count)NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* ModelGetOutputDescription)( + _In_ const OrtModel* model, _In_ size_t index, _Out_ const char** output_description, _Out_ size_t* count + )NO_EXCEPTION; /** * ModelGetInputTypeInfo - * This api gets the input OrtTypeInfo from the OrtModel given an index. It closely matches the API of a similar name for retrieving model metadata from OrtSession. - * This is used by WinML to support model reflection APIs. + * This api gets the input OrtTypeInfo from the OrtModel given an index. It closely matches the API of a similar name for retrieving model metadata from OrtSession. + * This is used by WinML to support model reflection APIs. */ - OrtStatus*(ORT_API_CALL* ModelGetInputTypeInfo)(_In_ const OrtModel* model, _In_ size_t index, _Outptr_ OrtTypeInfo** type_info)NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* ModelGetInputTypeInfo)( + _In_ const OrtModel* model, _In_ size_t index, _Outptr_ OrtTypeInfo** type_info + )NO_EXCEPTION; /** * ModelGetOutputTypeInfo - * This api gets the output OrtTypeInfo from the OrtModel given an index. It closely matches the API of a similar name for retrieving model metadata from OrtSession. - * This is used by WinML to support model reflection APIs. + * This api gets the output OrtTypeInfo from the OrtModel given an index. It closely matches the API of a similar name for retrieving model metadata from OrtSession. + * This is used by WinML to support model reflection APIs. */ - OrtStatus*(ORT_API_CALL* ModelGetOutputTypeInfo)(_In_ const OrtModel* model, _In_ size_t index, _Outptr_ OrtTypeInfo** type_info)NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* ModelGetOutputTypeInfo)( + _In_ const OrtModel* model, _In_ size_t index, _Outptr_ OrtTypeInfo** type_info + )NO_EXCEPTION; /** * ModelGetMetadataCount - * This api gets the number of metadata entries from the OrtModel. - * This is used by WinML to support model reflection APIs. + * This api gets the number of metadata entries from the OrtModel. + * This is used by WinML to support model reflection APIs. */ OrtStatus*(ORT_API_CALL* ModelGetMetadataCount)(_In_ const OrtModel* model, _Out_ size_t* count)NO_EXCEPTION; /** * ModelGetMetadata - * This api gets the model metadata from the OrtModel. - * This is used by WinML to deduce whether model input and output formats are supported by the WinML tensorization code paths. + * This api gets the model metadata from the OrtModel. + * This is used by WinML to deduce whether model input and output formats are supported by the WinML tensorization code paths. */ - OrtStatus*(ORT_API_CALL* ModelGetMetadata)(_In_ const OrtModel* model, _Out_ size_t count, _Out_ const char** const key, _Out_ size_t* key_len, _Out_ const char** const value, _Out_ size_t* value_len)NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* ModelGetMetadata)( + _In_ const OrtModel* model, + _Out_ size_t count, + _Out_ const char** const key, + _Out_ size_t* key_len, + _Out_ const char** const value, + _Out_ size_t* value_len + )NO_EXCEPTION; /** * ModelEnsureNoFloat16 - * This api checks whether the model requires float 16 support. - * This is used by WinML to fail gracefully when float 16 support is not available on the device. + * This api checks whether the model requires float 16 support. + * This is used by WinML to fail gracefully when float 16 support is not available on the device. * * Can this API be moved into the EP during session initialization. Currently we do an early fp16 check to avoid initialization when it is not supported. */ OrtStatus*(ORT_API_CALL* ModelEnsureNoFloat16)(_In_ const OrtModel* model)NO_EXCEPTION; /** - * SaveModel - * This api save the model to the fiven file - */ - OrtStatus*(ORT_API_CALL* SaveModel)(_In_ const OrtModel* in, _In_ const wchar_t* const file_name, _In_ size_t len)NO_EXCEPTION; + * SaveModel + * This api save the model to the fiven file + */ + OrtStatus*(ORT_API_CALL* SaveModel)(_In_ const OrtModel* in, _In_ const wchar_t* const file_name, _In_ size_t len) + NO_EXCEPTION; // OrtSessionOptions methods /** * OrtSessionOptionsAppendExecutionProvider_CPU - * This api is used to add the cpu EP to OrtSessionOptions so that WinML Gpu session are configures with CPU fallback. + * This api is used to add the cpu EP to OrtSessionOptions so that WinML Gpu session are configures with CPU fallback. */ - OrtStatus*(ORT_API_CALL* OrtSessionOptionsAppendExecutionProvider_CPU)(_In_ OrtSessionOptions* options, int use_arena)NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* OrtSessionOptionsAppendExecutionProvider_CPU)(_In_ OrtSessionOptions* options, int use_arena) + NO_EXCEPTION; /** * OrtSessionOptionsAppendExecutionProvider_DML - * This api is used to add the DML EP to OrtSessionOptions. + * This api is used to add the DML EP to OrtSessionOptions. */ - OrtStatus*(ORT_API_CALL* OrtSessionOptionsAppendExecutionProvider_DML)(_In_ OrtSessionOptions* options, ID3D12Device* device, ID3D12CommandQueue* queue, bool metacommands_enabled)NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* OrtSessionOptionsAppendExecutionProvider_DML)( + _In_ OrtSessionOptions* options, ID3D12Device* device, ID3D12CommandQueue* queue, bool metacommands_enabled + )NO_EXCEPTION; // OrtSession methods /** * CreateSessionWithoutModel - * This api is used to create a Session that is completely uninitialized. While there are other Session creation APIs in the + * This api is used to create a Session that is completely uninitialized. While there are other Session creation APIs in the * c-abi, WinML uses this so that it can perform optimizations prior to loading the model, and initializing. * Moreover, WinML needs a new api to support the OrtModel type, and prevent the parsing model protobufs again on session creation. */ - OrtStatus*(ORT_API_CALL* CreateSessionWithoutModel)(_In_ OrtEnv* env, _In_ const OrtSessionOptions* options, - _In_ OrtThreadPool* inter_op_thread_pool, _In_ OrtThreadPool* intra_op_thread_pool, _Outptr_ OrtSession** session)NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* CreateSessionWithoutModel)( + _In_ OrtEnv* env, + _In_ const OrtSessionOptions* options, + _In_ OrtThreadPool* inter_op_thread_pool, + _In_ OrtThreadPool* intra_op_thread_pool, + _Outptr_ OrtSession** session + )NO_EXCEPTION; /** * SessionGetExecutionProvider - * This api is used to get a handle to an OrtExecutionProvider. + * This api is used to get a handle to an OrtExecutionProvider. * Currently WinML uses this to talk directly to the DML EP and configure settings on it. */ - OrtStatus*(ORT_API_CALL* SessionGetExecutionProvider)(_In_ OrtSession* session, _In_ size_t index, _Out_ OrtExecutionProvider** provider)NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* SessionGetExecutionProvider)( + _In_ OrtSession* session, _In_ size_t index, _Out_ OrtExecutionProvider** provider + )NO_EXCEPTION; /** * SessionInitialize - * This api is used to initialize an OrtSession. This is one component of creating a usable OrtSession, and is a part of CreateSession in the c-abi. + * This api is used to initialize an OrtSession. This is one component of creating a usable OrtSession, and is a part of CreateSession in the c-abi. * Currently WinML uses this to finalize session creation, after configuring a variety of properties on the OrtSession. */ OrtStatus*(ORT_API_CALL* SessionInitialize)(_In_ OrtSession* session)NO_EXCEPTION; /** * SessionRegisterGraphTransformers - * This api is used to enable DML specific graph transformations on an OrtSession. + * This api is used to enable DML specific graph transformations on an OrtSession. * * Ideally these transformations should be configured by the contract between the runtime and the EP and not overridden by WinML. */ @@ -292,79 +339,82 @@ struct WinmlAdapterApi { /** * SessionRegisterCustomRegistry - * This api is used to support custom operators as they were shipped in WinML RS5. + * This api is used to support custom operators as they were shipped in WinML RS5. */ - OrtStatus*(ORT_API_CALL* SessionRegisterCustomRegistry)(_In_ OrtSession* session, _In_ IMLOperatorRegistry* registry)NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* SessionRegisterCustomRegistry)(_In_ OrtSession* session, _In_ IMLOperatorRegistry* registry) + NO_EXCEPTION; /** * SessionLoadAndPurloinModel - * This api is used to load an OrtModel into an OrtSession. + * This api is used to load an OrtModel into an OrtSession. * - * Don't free the 'out' value as this API will defunct and release the OrtModel internally. + * Don't free the 'out' value as this API will defunct and release the OrtModel internally. */ OrtStatus*(ORT_API_CALL* SessionLoadAndPurloinModel)(_In_ OrtSession* session, _In_ OrtModel* model)NO_EXCEPTION; /** * SessionStartProfiling - * This api is used to start profiling OrtSession. The existing mechanism only allows configuring profiling at session creation. + * This api is used to start profiling OrtSession. The existing mechanism only allows configuring profiling at session creation. * - * WinML uses this to toggle profilling on and off based on if a telemetry providers are being listened to. + * WinML uses this to toggle profilling on and off based on if a telemetry providers are being listened to. */ OrtStatus*(ORT_API_CALL* SessionStartProfiling)(_In_ OrtEnv* env, _In_ OrtSession* session)NO_EXCEPTION; /** * SessionEndProfiling - * This api is used to end profiling OrtSession. The existing mechanism only allows configuring profiling at session creation. + * This api is used to end profiling OrtSession. The existing mechanism only allows configuring profiling at session creation. * - * WinML uses this to toggle profilling on and off based on if a telemetry providers are being listened to. + * WinML uses this to toggle profilling on and off based on if a telemetry providers are being listened to. */ OrtStatus*(ORT_API_CALL* SessionEndProfiling)(_In_ OrtSession* session)NO_EXCEPTION; /** * SessionCopyOneInputAcrossDevices - * This api is used to copy and create an OrtValue input to prepare the input on the correct device. + * This api is used to copy and create an OrtValue input to prepare the input on the correct device. * - * WinML uses this to copy gpu device OrtValues to the CPU and vice-versa. + * WinML uses this to copy gpu device OrtValues to the CPU and vice-versa. */ - OrtStatus*(ORT_API_CALL* SessionCopyOneInputAcrossDevices)(_In_ OrtSession* session, _In_ const char* const input_name, _In_ OrtValue* orig_value, _Outptr_ OrtValue** new_value)NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* SessionCopyOneInputAcrossDevices)( + _In_ OrtSession* session, + _In_ const char* const input_name, + _In_ OrtValue* orig_value, + _Outptr_ OrtValue** new_value + )NO_EXCEPTION; // Dml methods (TODO need to figure out how these need to move to session somehow...) - /** + /** * SessionGetNumberOfIntraOpThreads - * This api returns the number of intra operator threads set on the OrtSession. + * This api returns the number of intra operator threads set on the OrtSession. * * WinML uses this to determine that the correct number of threads was set correctly through OrtSessionOptions. */ - OrtStatus*(ORT_API_CALL* SessionGetNumberOfIntraOpThreads)(_In_ OrtSession* session, _Out_ uint32_t* num_threads)NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* SessionGetNumberOfIntraOpThreads)(_In_ OrtSession* session, _Out_ uint32_t* num_threads) + NO_EXCEPTION; - /** + /** * SessionGetIntrapOpThreadSpinning - * This api returns false if the ort session options config entry "session.intra_op.allow_spinning" is set to "0", and true otherwise + * This api returns false if the ort session options config entry "session.intra_op.allow_spinning" is set to "0", and true otherwise * * WinML uses this to determine that the intra op thread spin policy was set correctly through OrtSessionOptions */ - OrtStatus*(ORT_API_CALL* SessionGetIntraOpThreadSpinning)(_In_ OrtSession* session, _Out_ bool* allow_spinning)NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* SessionGetIntraOpThreadSpinning)(_In_ OrtSession* session, _Out_ bool* allow_spinning) + NO_EXCEPTION; - /** + /** * SessionGetNamedDimensionsOverrides - * This api returns the named dimension overrides that are specified for this session + * This api returns the named dimension overrides that are specified for this session * * WinML uses this to determine that named dimension overrides were set correctly through OrtSessionOptions. */ - OrtStatus*(ORT_API_CALL* SessionGetNamedDimensionsOverrides)(_In_ OrtSession* session, _Out_ winrt::Windows::Foundation::Collections::IMapView& overrides)NO_EXCEPTION; - - /** - * DmlExecutionProviderSetDefaultRoundingMode - * This api is used to configure the DML EP to turn on/off rounding. - * - * WinML uses this to disable rounding during session initialization and then enables it again post initialization. - */ - OrtStatus*(ORT_API_CALL* DmlExecutionProviderSetDefaultRoundingMode)(_In_ OrtExecutionProvider* dml_provider, _In_ bool is_enabled)NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* SessionGetNamedDimensionsOverrides)( + _In_ OrtSession* session, + _Out_ winrt::Windows::Foundation::Collections::IMapView& overrides + )NO_EXCEPTION; /** * DmlExecutionProviderFlushContext - * This api is used to flush the DML EP. + * This api is used to flush the DML EP. * * WinML communicates directly with DML to perform this as an optimization. */ @@ -372,39 +422,44 @@ struct WinmlAdapterApi { /** * DmlExecutionProviderReleaseCompletedReferences - * This api is used to release completed references after first run the DML EP. + * This api is used to release completed references after first run the DML EP. * * WinML communicates directly with DML to perform this as an optimization. */ - OrtStatus*(ORT_API_CALL* DmlExecutionProviderReleaseCompletedReferences)(_In_ OrtExecutionProvider* dml_provider)NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* DmlExecutionProviderReleaseCompletedReferences)(_In_ OrtExecutionProvider* dml_provider + )NO_EXCEPTION; /** * DmlCopyTensor - * This api is used copy a tensor allocated by the DML EP Allocator to the CPU. + * This api is used copy a tensor allocated by the DML EP Allocator to the CPU. * * WinML uses this when graphs are evaluated with DML, and their outputs remain on the GPU but need to be copied back to the CPU. */ - OrtStatus*(ORT_API_CALL* DmlCopyTensor)(_In_ OrtExecutionProvider* provider, _In_ OrtValue* src, _In_ OrtValue* dst)NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* DmlCopyTensor)(_In_ OrtExecutionProvider* provider, _In_ OrtValue* src, _In_ OrtValue* dst) + NO_EXCEPTION; /** * GetProviderMemoryInfo - * This api gets the memory info object associated with an EP. + * This api gets the memory info object associated with an EP. * * WinML uses this to manage caller specified D3D12 inputs/outputs. It uses the memory info here to call DmlCreateGPUAllocationFromD3DResource. */ - OrtStatus*(ORT_API_CALL* GetProviderMemoryInfo)(_In_ OrtExecutionProvider* provider, OrtMemoryInfo** memory_info)NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* GetProviderMemoryInfo)(_In_ OrtExecutionProvider* provider, OrtMemoryInfo** memory_info) + NO_EXCEPTION; /** * GetProviderAllocator - * This api gets associated allocator used by a provider. + * This api gets associated allocator used by a provider. * * WinML uses this to create tensors, and needs to hold onto the allocator for the duration of the associated value's lifetime. */ - OrtStatus*(ORT_API_CALL* GetProviderAllocator)(_In_ OrtExecutionProvider* provider, OrtAllocator** allocator)NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* GetProviderAllocator)( + _In_ OrtSession* session, _In_ OrtExecutionProvider* provider, OrtAllocator** allocator + )NO_EXCEPTION; /** * FreeProviderAllocator - * This api frees an allocator. + * This api frees an allocator. * * WinML uses this to free the associated allocator for an ortvalue when creating tensors. * Internally this derefs a shared_ptr. @@ -413,7 +468,7 @@ struct WinmlAdapterApi { /** * ExecutionProviderSync - * This api syncs the EP. + * This api syncs the EP. * * WinML uses this to sync EP inputs/outputs directly. */ @@ -421,7 +476,7 @@ struct WinmlAdapterApi { /** * CreateCustomRegistry - * This api creates a custom registry that callers can populate with custom ops. + * This api creates a custom registry that callers can populate with custom ops. * * WinML uses this to support custom ops. */ @@ -429,7 +484,7 @@ struct WinmlAdapterApi { /** * ValueGetDeviceId - * This api returns the device id of the OrtValue. + * This api returns the device id of the OrtValue. * * WinML uses this to determine if an OrtValue is created on the needed device. */ @@ -437,73 +492,86 @@ struct WinmlAdapterApi { /** * SessionGetInputRequiredDeviceId - * This api returns the required device id for a model input. + * This api returns the required device id for a model input. * * WinML uses this to determine if an OrtValue is created on the needed device. */ - OrtStatus*(ORT_API_CALL* SessionGetInputRequiredDeviceId)(_In_ OrtSession* session, _In_ const char* const input_name, _Out_ int16_t* device_id)NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* SessionGetInputRequiredDeviceId)( + _In_ OrtSession* session, _In_ const char* const input_name, _Out_ int16_t* device_id + )NO_EXCEPTION; - OrtStatus*(ORT_API_CALL* CreateTensorTypeInfo)(_In_ const int64_t* shape, size_t shape_len, - ONNXTensorElementDataType type, _Out_ OrtTypeInfo** type_info)NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* CreateTensorTypeInfo)( + _In_ const int64_t* shape, size_t shape_len, ONNXTensorElementDataType type, _Out_ OrtTypeInfo** type_info + )NO_EXCEPTION; OrtStatus*(ORT_API_CALL* CreateSequenceTypeInfo)(_Out_ OrtTypeInfo** type_info)NO_EXCEPTION; OrtStatus*(ORT_API_CALL* CreateMapTypeInfo)(_Out_ OrtTypeInfo** type_info)NO_EXCEPTION; OrtStatus*(ORT_API_CALL* CreateModel)(_In_ int64_t opset, _Outptr_ OrtModel** out)NO_EXCEPTION; - OrtStatus*(ORT_API_CALL* ModelAddInput)(_In_ OrtModel* model, _In_ const char* const input_name, _In_ OrtTypeInfo* info)NO_EXCEPTION; - OrtStatus*(ORT_API_CALL* ModelAddConstantInput)(_In_ OrtModel* model, _In_ const char* const input_name, _In_ OrtTypeInfo* info, _In_ OrtValue* value)NO_EXCEPTION; - OrtStatus*(ORT_API_CALL* ModelAddOutput)(_In_ OrtModel* model, _In_ const char* const output_name, _In_ OrtTypeInfo* info)NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* ModelAddInput)( + _In_ OrtModel* model, _In_ const char* const input_name, _In_ OrtTypeInfo* info + )NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* ModelAddConstantInput)( + _In_ OrtModel* model, _In_ const char* const input_name, _In_ OrtTypeInfo* info, _In_ OrtValue* value + )NO_EXCEPTION; + OrtStatus*(ORT_API_CALL* ModelAddOutput)( + _In_ OrtModel* model, _In_ const char* const output_name, _In_ OrtTypeInfo* info + )NO_EXCEPTION; OrtStatus*(ORT_API_CALL* ModelAddOperator)( - _In_ OrtModel* model, - _In_ const char* const op_type, - _In_ const char* const op_name, - _In_ int64_t opset, - _In_ const char* const op_domain, - _In_ const char* const* input_names, _In_ size_t num_inputs, - _In_ const char* const* output_names, _In_ size_t num_outputs, - _In_ const char* const* attribute_names, _In_ OrtValue** attribute_values, _In_ size_t num_attributes)NO_EXCEPTION; - - OrtStatus*(ORT_API_CALL* ModelGetOpsetVersion)(_In_ OrtModel* model, _In_ const char* const domain, _Out_ int32_t* version)NO_EXCEPTION; + _In_ OrtModel* model, + _In_ const char* const op_type, + _In_ const char* const op_name, + _In_ int64_t opset, + _In_ const char* const op_domain, + _In_ const char* const* input_names, + _In_ size_t num_inputs, + _In_ const char* const* output_names, + _In_ size_t num_outputs, + _In_ const char* const* attribute_names, + _In_ OrtValue** attribute_values, + _In_ size_t num_attributes + )NO_EXCEPTION; + + OrtStatus*(ORT_API_CALL* ModelGetOpsetVersion)( + _In_ OrtModel* model, _In_ const char* const domain, _Out_ int32_t* version + )NO_EXCEPTION; OrtStatus*(ORT_API_CALL* OperatorGetNumInputs)( - _In_ const char* const op_type, - _In_ int64_t opset, - _In_ const char* const op_domain, - _Out_ size_t* num_inputs)NO_EXCEPTION; + _In_ const char* const op_type, _In_ int64_t opset, _In_ const char* const op_domain, _Out_ size_t* num_inputs + )NO_EXCEPTION; OrtStatus*(ORT_API_CALL* OperatorGetInputName)( - _In_ const char* const op_type, - _In_ int64_t opset, - _In_ const char* const op_domain, - _In_ size_t index, - _Out_ const char** const name - )NO_EXCEPTION; + _In_ const char* const op_type, + _In_ int64_t opset, + _In_ const char* const op_domain, + _In_ size_t index, + _Out_ const char** const name + )NO_EXCEPTION; OrtStatus*(ORT_API_CALL* OperatorGetNumOutputs)( - _In_ const char* const op_type, - _In_ int64_t opset, - _In_ const char* const op_domain, - _Out_ size_t* num_inputs)NO_EXCEPTION; + _In_ const char* const op_type, _In_ int64_t opset, _In_ const char* const op_domain, _Out_ size_t* num_inputs + )NO_EXCEPTION; OrtStatus*(ORT_API_CALL* OperatorGetOutputName)( - _In_ const char* const op_type, - _In_ int64_t opset, - _In_ const char* const op_domain, - _In_ size_t index, - _Out_ const char** const name)NO_EXCEPTION; + _In_ const char* const op_type, + _In_ int64_t opset, + _In_ const char* const op_domain, + _In_ size_t index, + _Out_ const char** const name + )NO_EXCEPTION; OrtStatus*(ORT_API_CALL* JoinModels)( - _In_ OrtModel* first_model, - _In_ OrtModel* second_model, - _In_ const char* const* output_names, - _In_ const char* const* input_names, - size_t num_linkages, - bool promote_unlinked_outputs, - _In_ const char* const join_node_prefix)NO_EXCEPTION; + _In_ OrtModel* first_model, + _In_ OrtModel* second_model, + _In_ const char* const* output_names, + _In_ const char* const* input_names, + size_t num_linkages, + bool promote_unlinked_outputs, + _In_ const char* const join_node_prefix + )NO_EXCEPTION; OrtStatus*(ORT_API_CALL* CreateThreadPool)( - _In_ ThreadPoolType type, - _In_ OrtThreadPoolOptions* params, - _Outptr_ OrtThreadPool** out)NO_EXCEPTION; + _In_ ThreadPoolType type, _In_ OrtThreadPoolOptions* params, _Outptr_ OrtThreadPool** out + )NO_EXCEPTION; ORT_CLASS_RELEASE(Model); ORT_CLASS_RELEASE(ThreadPool); diff --git a/winml/adapter/winml_adapter_dml.cpp b/winml/adapter/winml_adapter_dml.cpp index acda0d332b1cb..1b3ceed40cfad 100644 --- a/winml/adapter/winml_adapter_dml.cpp +++ b/winml/adapter/winml_adapter_dml.cpp @@ -23,18 +23,18 @@ namespace winmla = Windows::AI::MachineLearning::Adapter; EXTERN_C IMAGE_DOS_HEADER __ImageBase; static std::wstring CurrentModulePath() { - WCHAR path[MAX_PATH]; - FAIL_FAST_IF(0 == GetModuleFileNameW((HINSTANCE)&__ImageBase, path, _countof(path))); + WCHAR path[MAX_PATH]; + FAIL_FAST_IF(0 == GetModuleFileNameW((HINSTANCE)&__ImageBase, path, _countof(path))); - WCHAR absolute_path[MAX_PATH]; - WCHAR* name; - FAIL_FAST_IF(0 == GetFullPathNameW(path, _countof(path), absolute_path, &name)); + WCHAR absolute_path[MAX_PATH]; + WCHAR* name; + FAIL_FAST_IF(0 == GetFullPathNameW(path, _countof(path), absolute_path, &name)); - auto idx = std::distance(absolute_path, name); - auto out_path = std::wstring(absolute_path); - out_path.resize(idx); + auto idx = std::distance(absolute_path, name); + auto out_path = std::wstring(absolute_path); + out_path.resize(idx); - return out_path; + return out_path; } Microsoft::WRL::ComPtr CreateDmlDevice(ID3D12Device* d3d12Device) { @@ -43,8 +43,8 @@ Microsoft::WRL::ComPtr CreateDmlDevice(ID3D12Device* d3d12Device) { wil::unique_hmodule dmlDll(LoadLibraryExW(directml_dll.c_str(), nullptr, 0)); THROW_LAST_ERROR_IF(!dmlDll); - auto dmlCreateDevice1Fn = reinterpret_cast( - GetProcAddress(dmlDll.get(), "DMLCreateDevice1")); + auto dmlCreateDevice1Fn = + reinterpret_cast(GetProcAddress(dmlDll.get(), "DMLCreateDevice1")); THROW_LAST_ERROR_IF(!dmlCreateDevice1Fn); DML_CREATE_DEVICE_FLAGS dmlFlags = DML_CREATE_DEVICE_FLAG_NONE; @@ -68,14 +68,18 @@ Microsoft::WRL::ComPtr CreateDmlDevice(ID3D12Device* d3d12Device) { } namespace onnxruntime { -void DmlConfigureProviderFactoryDefaultRoundingMode(onnxruntime::IExecutionProviderFactory* factory, AllocatorRoundingMode rounding_mode); void DmlConfigureProviderFactoryMetacommandsEnabled(IExecutionProviderFactory* factory, bool metacommandsEnabled); -} +} // namespace onnxruntime #endif // USE_DML -ORT_API_STATUS_IMPL(winmla::OrtSessionOptionsAppendExecutionProviderEx_DML, _In_ OrtSessionOptions* options, - _In_ ID3D12Device* d3d_device, _In_ ID3D12CommandQueue* queue, bool metacommands_enabled) { +ORT_API_STATUS_IMPL( + winmla::OrtSessionOptionsAppendExecutionProviderEx_DML, + _In_ OrtSessionOptions* options, + _In_ ID3D12Device* d3d_device, + _In_ ID3D12CommandQueue* queue, + bool metacommands_enabled +) { API_IMPL_BEGIN #ifdef USE_DML auto dml_device = CreateDmlDevice(d3d_device); @@ -84,28 +88,12 @@ ORT_API_STATUS_IMPL(winmla::OrtSessionOptionsAppendExecutionProviderEx_DML, _In_ } auto factory = options->provider_factories.back().get(); - // OnnxRuntime uses the default rounding mode when calling the session's allocator. - // During initialization, OnnxRuntime allocates weights, which are permanent across session - // lifetime and can be large, so shouldn't be rounded. - // So we create the provider with rounding disabled, and expect the caller to enable it after. - onnxruntime::DmlConfigureProviderFactoryDefaultRoundingMode(factory, AllocatorRoundingMode::Disabled); - onnxruntime::DmlConfigureProviderFactoryMetacommandsEnabled(factory, metacommands_enabled); #endif // USE_DML return nullptr; API_IMPL_END } -ORT_API_STATUS_IMPL(winmla::DmlExecutionProviderSetDefaultRoundingMode, _In_ OrtExecutionProvider* dml_provider, _In_ bool is_enabled) { - API_IMPL_BEGIN -#ifdef USE_DML - auto dml_provider_internal = reinterpret_cast<::onnxruntime::IExecutionProvider*>(dml_provider); - Dml::SetDefaultRoundingMode(dml_provider_internal, is_enabled ? AllocatorRoundingMode::Enabled : AllocatorRoundingMode::Disabled); -#endif - return nullptr; - API_IMPL_END -} - ORT_API_STATUS_IMPL(winmla::DmlExecutionProviderFlushContext, _In_ OrtExecutionProvider* dml_provider) { API_IMPL_BEGIN #ifdef USE_DML @@ -126,11 +114,15 @@ ORT_API_STATUS_IMPL(winmla::DmlExecutionProviderReleaseCompletedReferences, _In_ API_IMPL_END } -ORT_API_STATUS_IMPL(winmla::DmlCopyTensor, _In_ OrtExecutionProvider* dml_provider, _In_ OrtValue* src, _In_ OrtValue* dst) { +ORT_API_STATUS_IMPL( + winmla::DmlCopyTensor, _In_ OrtExecutionProvider* dml_provider, _In_ OrtValue* src, _In_ OrtValue* dst +) { API_IMPL_BEGIN #ifdef USE_DML auto dml_provider_internal = reinterpret_cast<::onnxruntime::IExecutionProvider*>(dml_provider); - auto status = Dml::CopyTensor(dml_provider_internal, *(src->GetMutable()), *(dst->GetMutable())); + auto status = Dml::CopyTensor( + dml_provider_internal, *(src->GetMutable()), *(dst->GetMutable()) + ); if (!status.IsOK()) { return onnxruntime::ToOrtStatus(status); } diff --git a/winml/adapter/winml_adapter_environment.cpp b/winml/adapter/winml_adapter_environment.cpp index bb56a8f3a4ce8..43babdf43967e 100644 --- a/winml/adapter/winml_adapter_environment.cpp +++ b/winml/adapter/winml_adapter_environment.cpp @@ -20,9 +20,11 @@ namespace winmla = Windows::AI::MachineLearning::Adapter; class WinmlAdapterLoggingWrapper : public LoggingWrapper { public: - WinmlAdapterLoggingWrapper(OrtLoggingFunction logging_function, OrtProfilingFunction profiling_function, void* logger_param) : LoggingWrapper(logging_function, logger_param), - profiling_function_(profiling_function) { - } + WinmlAdapterLoggingWrapper( + OrtLoggingFunction logging_function, OrtProfilingFunction profiling_function, void* logger_param + ) + : LoggingWrapper(logging_function, logger_param), + profiling_function_(profiling_function) {} void SendProfileEvent(onnxruntime::profiling::EventRecord& event_record) const override { if (profiling_function_) { @@ -31,8 +33,12 @@ class WinmlAdapterLoggingWrapper : public LoggingWrapper { ort_event_record.category_name_ = onnxruntime::profiling::event_category_names_[event_record.cat]; ort_event_record.duration_ = event_record.dur; ort_event_record.event_name_ = event_record.name.c_str(); - ort_event_record.execution_provider_ = (event_record.cat == onnxruntime::profiling::EventCategory::NODE_EVENT) ? event_record.args["provider"].c_str() : nullptr; - ort_event_record.op_name_ = (event_record.cat == onnxruntime::profiling::EventCategory::NODE_EVENT) ? event_record.args["op_name"].c_str() : nullptr; + ort_event_record.execution_provider_ = (event_record.cat == onnxruntime::profiling::EventCategory::NODE_EVENT) + ? event_record.args["provider"].c_str() + : nullptr; + ort_event_record.op_name_ = (event_record.cat == onnxruntime::profiling::EventCategory::NODE_EVENT) + ? event_record.args["op_name"].c_str() + : nullptr; ort_event_record.process_id_ = event_record.pid; ort_event_record.thread_id_ = event_record.tid; ort_event_record.time_span_ = event_record.ts; @@ -45,21 +51,31 @@ class WinmlAdapterLoggingWrapper : public LoggingWrapper { OrtProfilingFunction profiling_function_{}; }; -ORT_API_STATUS_IMPL(winmla::EnvConfigureCustomLoggerAndProfiler, _In_ OrtEnv* env, OrtLoggingFunction logging_function, OrtProfilingFunction profiling_function, - _In_opt_ void* logger_param, OrtLoggingLevel default_warning_level, - _In_ const char* logid, _Outptr_ OrtEnv** out) { +ORT_API_STATUS_IMPL( + winmla::EnvConfigureCustomLoggerAndProfiler, + _In_ OrtEnv* env, + OrtLoggingFunction logging_function, + OrtProfilingFunction profiling_function, + _In_opt_ void* logger_param, + OrtLoggingLevel default_warning_level, + _In_ const char* logid, + _Outptr_ OrtEnv** out +) { API_IMPL_BEGIN std::string name = logid; - std::unique_ptr logger = std::make_unique(logging_function, profiling_function, logger_param); + std::unique_ptr logger = + std::make_unique(logging_function, profiling_function, logger_param); // Clear the logging manager, since only one default instance of logging manager can exist at a time. env->SetLoggingManager(nullptr); - auto winml_logging_manager = std::make_unique(std::move(logger), - static_cast(default_warning_level), - false, - onnxruntime::logging::LoggingManager::InstanceType::Default, - &name); + auto winml_logging_manager = std::make_unique( + std::move(logger), + static_cast(default_warning_level), + false, + onnxruntime::logging::LoggingManager::InstanceType::Default, + &name + ); // Set a new default logging manager env->SetLoggingManager(std::move(winml_logging_manager)); @@ -76,9 +92,7 @@ ORT_API_STATUS_IMPL(winmla::OverrideSchema) { API_IMPL_BEGIN #ifdef USE_DML static std::once_flag schema_override_once_flag; - std::call_once(schema_override_once_flag, []() { - SchemaInferenceOverrider::OverrideSchemaInferenceFunctions(); - }); + std::call_once(schema_override_once_flag, []() { SchemaInferenceOverrider::OverrideSchemaInferenceFunctions(); }); #endif USE_DML. return nullptr; API_IMPL_END diff --git a/winml/adapter/winml_adapter_execution_provider.cpp b/winml/adapter/winml_adapter_execution_provider.cpp index b2a0c6198d651..52dbf9710abc7 100644 --- a/winml/adapter/winml_adapter_execution_provider.cpp +++ b/winml/adapter/winml_adapter_execution_provider.cpp @@ -44,10 +44,16 @@ ORT_API_STATUS_IMPL(winmla::ExecutionProviderSync, _In_ OrtExecutionProvider* pr API_IMPL_END } -ORT_API_STATUS_IMPL(winmla::GetProviderAllocator, _In_ OrtExecutionProvider* provider, OrtAllocator** allocator) { +ORT_API_STATUS_IMPL( + winmla::GetProviderAllocator, _In_ OrtSession* session, _In_ OrtExecutionProvider* provider, OrtAllocator** allocator +) { API_IMPL_BEGIN + auto inference_session = reinterpret_cast<::onnxruntime::InferenceSession*>(session); const auto execution_provider = reinterpret_cast(provider); - auto allocator_ptr = execution_provider->GetAllocator(::OrtMemType::OrtMemTypeDefault); + OrtMemoryInfo mem_info( + "", OrtAllocatorType::OrtDeviceAllocator, execution_provider->GetOrtDeviceByMemType(::OrtMemType::OrtMemTypeDefault) + ); + auto allocator_ptr = inference_session->GetAllocator(mem_info); *allocator = new (std::nothrow) OrtAllocatorWrapper(allocator_ptr); if (*allocator == nullptr) { return OrtApis::CreateStatus(ORT_FAIL, "Out of memory"); @@ -60,10 +66,8 @@ ORT_API_STATUS_IMPL(winmla::GetProviderMemoryInfo, _In_ OrtExecutionProvider* pr API_IMPL_BEGIN const auto execution_provider = reinterpret_cast(provider); - auto allocator = execution_provider->GetAllocator(::OrtMemType::OrtMemTypeDefault); - - const auto& info = allocator->Info(); - *memory_info = new (std::nothrow) OrtMemoryInfo(info.name, info.alloc_type, info.device, info.id, info.mem_type); + auto device = execution_provider->GetOrtDeviceByMemType(::OrtMemType::OrtMemTypeDefault); + *memory_info = new (std::nothrow) OrtMemoryInfo("", ::OrtAllocatorType::OrtDeviceAllocator, device); if (*memory_info == nullptr) { return OrtApis::CreateStatus(ORT_FAIL, "Out of memory"); } diff --git a/winml/adapter/winml_adapter_model.cpp b/winml/adapter/winml_adapter_model.cpp index 8e198beaac850..ce224c1f6939e 100644 --- a/winml/adapter/winml_adapter_model.cpp +++ b/winml/adapter/winml_adapter_model.cpp @@ -35,7 +35,9 @@ static std::vector GetInitializers(const ONNX_NAMESPACE::ModelProto return initializers; } -static std::vector GetInputsWithoutInitializers(const ONNX_NAMESPACE::ModelProto& model_proto) { +static std::vector GetInputsWithoutInitializers( + const ONNX_NAMESPACE::ModelProto& model_proto +) { auto initializers = GetInitializers(model_proto); std::vector inputs_without_initializers; @@ -43,12 +45,9 @@ static std::vector GetInputsWithoutInitia auto& inputs = graph.input(); for (auto& input : inputs) { if (input.has_name() && input.has_type()) { - auto found_it = std::find_if( - std::begin(initializers), - std::end(initializers), - [&](auto& initializer) { - return std::strcmp(initializer, input.name().c_str()) == 0; - }); + auto found_it = std::find_if(std::begin(initializers), std::end(initializers), [&](auto& initializer) { + return std::strcmp(initializer, input.name().c_str()) == 0; + }); auto is_initializer = found_it != std::end(initializers); if (!is_initializer) { @@ -73,9 +72,7 @@ static std::vector GetOutputs(const ONNX_ class ModelInfo { public: - ModelInfo(const ONNX_NAMESPACE::ModelProto* model_proto) { - Initialize(model_proto); - } + ModelInfo(const ONNX_NAMESPACE::ModelProto* model_proto) { Initialize(model_proto); } public: // model metadata @@ -117,8 +114,9 @@ class ModelInfo { } }; -OrtModel::OrtModel(std::unique_ptr model_proto) : model_proto_(std::move(model_proto)), - model_info_(std::make_unique(model_proto_.get())) { +OrtModel::OrtModel(std::unique_ptr model_proto) + : model_proto_(std::move(model_proto)), + model_info_(std::make_unique(model_proto_.get())) { } // factory methods for creating an ort model from a path @@ -130,11 +128,8 @@ static OrtStatus* CreateModelProto(const char* path, std::unique_ptr&& model_proto, OrtModel** model) { +OrtStatus* OrtModel::CreateOrtModelFromProto( + std::unique_ptr&& model_proto, OrtModel** model +) { *model = new (std::nothrow) OrtModel(std::move(model_proto)); if (*model == nullptr) { return OrtApis::CreateStatus(ORT_ENGINE_ERROR, "Engine failed to create a model!"); @@ -217,7 +214,7 @@ void OrtModel::RefreshModelInfo() { auto new_info = std::make_unique(model_proto_.get()); model_info_->author_ = std::move(new_info->author_); model_info_->description_ = std::move(new_info->description_); - model_info_->domain_= std::move(new_info->domain_); + model_info_->domain_ = std::move(new_info->domain_); model_info_->input_features_ = std::move(new_info->input_features_); model_info_->model_metadata_ = std::move(new_info->model_metadata_); model_info_->name_ = std::move(new_info->name_); @@ -226,7 +223,9 @@ void OrtModel::RefreshModelInfo() { model_info_->version_ = std::move(new_info->version_); } -ORT_API_STATUS_IMPL(winmla::CreateModelFromPath, _In_ const char* model_path, _In_ size_t size, _Outptr_ OrtModel** out) { +ORT_API_STATUS_IMPL( + winmla::CreateModelFromPath, _In_ const char* model_path, _In_ size_t size, _Outptr_ OrtModel** out +) { API_IMPL_BEGIN if (auto status = OrtModel::CreateOrtModelFromPath(model_path, size, out)) { return status; @@ -274,7 +273,9 @@ ORT_API_STATUS_IMPL(winmla::SaveModel, _In_ const OrtModel* in, _In_ const wchar API_IMPL_END } -ORT_API_STATUS_IMPL(winmla::ModelGetAuthor, _In_ const OrtModel* model, _Out_ const char** const author, _Out_ size_t* len) { +ORT_API_STATUS_IMPL( + winmla::ModelGetAuthor, _In_ const OrtModel* model, _Out_ const char** const author, _Out_ size_t* len +) { API_IMPL_BEGIN *author = model->UseModelInfo()->author_.c_str(); *len = model->UseModelInfo()->author_.size(); @@ -282,7 +283,9 @@ ORT_API_STATUS_IMPL(winmla::ModelGetAuthor, _In_ const OrtModel* model, _Out_ co API_IMPL_END } -ORT_API_STATUS_IMPL(winmla::ModelGetName, _In_ const OrtModel* model, _Out_ const char** const name, _Out_ size_t* len) { +ORT_API_STATUS_IMPL( + winmla::ModelGetName, _In_ const OrtModel* model, _Out_ const char** const name, _Out_ size_t* len +) { API_IMPL_BEGIN *name = model->UseModelInfo()->name_.c_str(); *len = model->UseModelInfo()->name_.size(); @@ -299,7 +302,9 @@ ORT_API_STATUS_IMPL(winmla::ModelSetName, _In_ const OrtModel* model, _In_ const API_IMPL_END } -ORT_API_STATUS_IMPL(winmla::ModelGetDomain, _In_ const OrtModel* model, _Out_ const char** const domain, _Out_ size_t* len) { +ORT_API_STATUS_IMPL( + winmla::ModelGetDomain, _In_ const OrtModel* model, _Out_ const char** const domain, _Out_ size_t* len +) { API_IMPL_BEGIN *domain = model->UseModelInfo()->domain_.c_str(); *len = model->UseModelInfo()->domain_.size(); @@ -307,7 +312,9 @@ ORT_API_STATUS_IMPL(winmla::ModelGetDomain, _In_ const OrtModel* model, _Out_ co API_IMPL_END } -ORT_API_STATUS_IMPL(winmla::ModelGetDescription, _In_ const OrtModel* model, _Out_ const char** const description, _Out_ size_t* len) { +ORT_API_STATUS_IMPL( + winmla::ModelGetDescription, _In_ const OrtModel* model, _Out_ const char** const description, _Out_ size_t* len +) { API_IMPL_BEGIN *description = model->UseModelInfo()->description_.c_str(); *len = model->UseModelInfo()->description_.size(); @@ -329,8 +336,15 @@ ORT_API_STATUS_IMPL(winmla::ModelGetMetadataCount, _In_ const OrtModel* model, _ API_IMPL_END } -ORT_API_STATUS_IMPL(winmla::ModelGetMetadata, _In_ const OrtModel* model, _In_ size_t count, _Out_ const char** const key, - _Out_ size_t* key_len, _Out_ const char** const value, _Out_ size_t* value_len) { +ORT_API_STATUS_IMPL( + winmla::ModelGetMetadata, + _In_ const OrtModel* model, + _In_ size_t count, + _Out_ const char** const key, + _Out_ size_t* key_len, + _Out_ const char** const value, + _Out_ size_t* value_len +) { API_IMPL_BEGIN *key = model->UseModelInfo()->model_metadata_[count].first.c_str(); *key_len = model->UseModelInfo()->model_metadata_[count].first.size(); @@ -354,8 +368,13 @@ ORT_API_STATUS_IMPL(winmla::ModelGetOutputCount, _In_ const OrtModel* model, _Ou API_IMPL_END } -ORT_API_STATUS_IMPL(winmla::ModelGetInputName, _In_ const OrtModel* model, _In_ size_t index, - _Out_ const char** input_name, _Out_ size_t* count) { +ORT_API_STATUS_IMPL( + winmla::ModelGetInputName, + _In_ const OrtModel* model, + _In_ size_t index, + _Out_ const char** input_name, + _Out_ size_t* count +) { API_IMPL_BEGIN *input_name = model->UseModelInfo()->input_features_[index]->name().c_str(); *count = model->UseModelInfo()->input_features_[index]->name().size(); @@ -363,8 +382,13 @@ ORT_API_STATUS_IMPL(winmla::ModelGetInputName, _In_ const OrtModel* model, _In_ API_IMPL_END } -ORT_API_STATUS_IMPL(winmla::ModelGetOutputName, _In_ const OrtModel* model, _In_ size_t index, - _Out_ const char** output_name, _Out_ size_t* count) { +ORT_API_STATUS_IMPL( + winmla::ModelGetOutputName, + _In_ const OrtModel* model, + _In_ size_t index, + _Out_ const char** output_name, + _Out_ size_t* count +) { API_IMPL_BEGIN *output_name = model->UseModelInfo()->output_features_[index]->name().c_str(); *count = model->UseModelInfo()->output_features_[index]->name().size(); @@ -372,8 +396,13 @@ ORT_API_STATUS_IMPL(winmla::ModelGetOutputName, _In_ const OrtModel* model, _In_ API_IMPL_END } -ORT_API_STATUS_IMPL(winmla::ModelGetInputDescription, _In_ const OrtModel* model, _In_ size_t index, - _Out_ const char** input_description, _Out_ size_t* count) { +ORT_API_STATUS_IMPL( + winmla::ModelGetInputDescription, + _In_ const OrtModel* model, + _In_ size_t index, + _Out_ const char** input_description, + _Out_ size_t* count +) { API_IMPL_BEGIN *input_description = model->UseModelInfo()->input_features_[index]->doc_string().c_str(); *count = model->UseModelInfo()->input_features_[index]->doc_string().size(); @@ -381,8 +410,13 @@ ORT_API_STATUS_IMPL(winmla::ModelGetInputDescription, _In_ const OrtModel* model API_IMPL_END } -ORT_API_STATUS_IMPL(winmla::ModelGetOutputDescription, _In_ const OrtModel* model, _In_ size_t index, - _Out_ const char** output_description, _Out_ size_t* count) { +ORT_API_STATUS_IMPL( + winmla::ModelGetOutputDescription, + _In_ const OrtModel* model, + _In_ size_t index, + _Out_ const char** output_description, + _Out_ size_t* count +) { API_IMPL_BEGIN *output_description = model->UseModelInfo()->output_features_[index]->doc_string().c_str(); *count = model->UseModelInfo()->output_features_[index]->doc_string().size(); @@ -390,7 +424,9 @@ ORT_API_STATUS_IMPL(winmla::ModelGetOutputDescription, _In_ const OrtModel* mode API_IMPL_END } -ORT_API_STATUS_IMPL(winmla::ModelGetInputTypeInfo, _In_ const OrtModel* model, _In_ size_t index, _Outptr_ OrtTypeInfo** type_info) { +ORT_API_STATUS_IMPL( + winmla::ModelGetInputTypeInfo, _In_ const OrtModel* model, _In_ size_t index, _Outptr_ OrtTypeInfo** type_info +) { API_IMPL_BEGIN auto info = OrtTypeInfo::FromTypeProto(model->UseModelInfo()->input_features_[index]->type()); *type_info = info.release(); @@ -398,7 +434,9 @@ ORT_API_STATUS_IMPL(winmla::ModelGetInputTypeInfo, _In_ const OrtModel* model, _ API_IMPL_END } -ORT_API_STATUS_IMPL(winmla::ModelGetOutputTypeInfo, _In_ const OrtModel* model, _In_ size_t index, _Outptr_ OrtTypeInfo** type_info) { +ORT_API_STATUS_IMPL( + winmla::ModelGetOutputTypeInfo, _In_ const OrtModel* model, _In_ size_t index, _Outptr_ OrtTypeInfo** type_info +) { API_IMPL_BEGIN auto info = OrtTypeInfo::FromTypeProto(model->UseModelInfo()->output_features_[index]->type()); *type_info = info.release(); @@ -425,8 +463,7 @@ ORT_API_STATUS_IMPL(winmla::ModelEnsureNoFloat16, _In_ const OrtModel* model) { auto& tensor_type = type.tensor_type(); if (tensor_type.elem_type() == ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_BFLOAT16) { std::stringstream error_message; - error_message << "The model contains a 16-bit input (" - << input->name() + error_message << "The model contains a 16-bit input (" << input->name() << "), but the current device does not support 16-bit float."; return OrtApis::CreateStatus(ORT_INVALID_GRAPH, error_message.str().c_str()); } @@ -442,8 +479,7 @@ ORT_API_STATUS_IMPL(winmla::ModelEnsureNoFloat16, _In_ const OrtModel* model) { if (attribute.name() == "to") { if (attribute.i() == ONNX_NAMESPACE::TensorProto::DataType::TensorProto_DataType_FLOAT16) { std::stringstream error_message; - error_message << "The model contains a 16-bit input (" - << node.name().c_str() + error_message << "The model contains a 16-bit input (" << node.name().c_str() << "), but the current device does not support 16-bit float."; return OrtApis::CreateStatus(ORT_INVALID_GRAPH, error_message.str().c_str()); } @@ -458,8 +494,7 @@ ORT_API_STATUS_IMPL(winmla::ModelEnsureNoFloat16, _In_ const OrtModel* model) { auto initializer = graph.initializer(i); if (initializer.data_type() == ONNX_NAMESPACE::TensorProto::DataType::TensorProto_DataType_FLOAT16) { std::stringstream error_message; - error_message << "The model contains a 16-bit input (" - << initializer.name().c_str() + error_message << "The model contains a 16-bit input (" << initializer.name().c_str() << "), but the current device does not support 16-bit float."; return OrtApis::CreateStatus(ORT_INVALID_GRAPH, error_message.str().c_str()); } @@ -472,8 +507,7 @@ ORT_API_STATUS_IMPL(winmla::ModelEnsureNoFloat16, _In_ const OrtModel* model) { auto& tensor_type = type.tensor_type(); if (tensor_type.elem_type() == ONNX_NAMESPACE::TensorProto_DataType::TensorProto_DataType_BFLOAT16) { std::stringstream error_message; - error_message << "The model contains a 16-bit input (" - << output->name() + error_message << "The model contains a 16-bit input (" << output->name() << "), but the current device does not support 16-bit float."; return OrtApis::CreateStatus(ORT_INVALID_GRAPH, error_message.str().c_str()); } @@ -489,7 +523,9 @@ ORT_API_STATUS_IMPL(winmla::CreateModel, _In_ int64_t opset, _Outptr_ OrtModel** API_IMPL_END } -static ONNX_NAMESPACE::TensorProto_DataType ONNXTensorElementDataTypeToTensorProto_DataType(ONNXTensorElementDataType type) { +static ONNX_NAMESPACE::TensorProto_DataType ONNXTensorElementDataTypeToTensorProto_DataType( + ONNXTensorElementDataType type +) { switch (type) { case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT: return ONNX_NAMESPACE::TensorProto_DataType_FLOAT; @@ -522,8 +558,13 @@ static ONNX_NAMESPACE::TensorProto_DataType ONNXTensorElementDataTypeToTensorPro } } -static void CreateTypeProto_Tensor(ONNX_NAMESPACE::TypeProto_Tensor* mutable_tensor_type, const char* const name, - const int64_t* shape, size_t shape_len, ONNX_NAMESPACE::TensorProto_DataType data_type) { +static void CreateTypeProto_Tensor( + ONNX_NAMESPACE::TypeProto_Tensor* mutable_tensor_type, + const char* const name, + const int64_t* shape, + size_t shape_len, + ONNX_NAMESPACE::TensorProto_DataType data_type +) { mutable_tensor_type->set_elem_type(data_type); size_t dim_param = 0; @@ -542,8 +583,10 @@ static void CreateTypeProto_Tensor(ONNX_NAMESPACE::TypeProto_Tensor* mutable_ten } } -ORT_API_STATUS_IMPL(winmla::ModelAddInput, _In_ OrtModel* model, _In_ const char* const input_name, _In_ OrtTypeInfo* info) { - API_IMPL_BEGIN +ORT_API_STATUS_IMPL( + winmla::ModelAddInput, _In_ OrtModel* model, _In_ const char* const input_name, _In_ OrtTypeInfo* info +) { + API_IMPL_BEGIN auto model_proto = model->UseModelProto(); ONNX_NAMESPACE::GraphProto& graph = *model_proto->mutable_graph(); ONNX_NAMESPACE::ValueInfoProto& input = *graph.add_input(); @@ -552,17 +595,24 @@ ORT_API_STATUS_IMPL(winmla::ModelAddInput, _In_ OrtModel* model, _In_ const char if (info->type == ONNXType::ONNX_TYPE_TENSOR) { auto num_dims = info->data->shape.NumDimensions(); CreateTypeProto_Tensor( - input.mutable_type()->mutable_tensor_type(), - input_name, - (num_dims == 0) ? nullptr : &info->data->shape[0], - num_dims, - ONNXTensorElementDataTypeToTensorProto_DataType(info->data->type)); + input.mutable_type()->mutable_tensor_type(), + input_name, + (num_dims == 0) ? nullptr : &info->data->shape[0], + num_dims, + ONNXTensorElementDataTypeToTensorProto_DataType(info->data->type) + ); } return nullptr; API_IMPL_END } -ORT_API_STATUS_IMPL(winmla::ModelAddConstantInput, _In_ OrtModel* model, _In_ const char* const input_name, _In_ OrtTypeInfo* info, _In_ OrtValue* value) { +ORT_API_STATUS_IMPL( + winmla::ModelAddConstantInput, + _In_ OrtModel* model, + _In_ const char* const input_name, + _In_ OrtTypeInfo* info, + _In_ OrtValue* value +) { API_IMPL_BEGIN auto model_proto = model->UseModelProto(); ONNX_NAMESPACE::GraphProto& graph = *model_proto->mutable_graph(); @@ -582,7 +632,9 @@ ORT_API_STATUS_IMPL(winmla::ModelAddConstantInput, _In_ OrtModel* model, _In_ co API_IMPL_END } -ORT_API_STATUS_IMPL(winmla::ModelAddOutput, _In_ OrtModel* model, _In_ const char* const output_name, _In_ OrtTypeInfo* info) { +ORT_API_STATUS_IMPL( + winmla::ModelAddOutput, _In_ OrtModel* model, _In_ const char* const output_name, _In_ OrtTypeInfo* info +) { API_IMPL_BEGIN auto model_proto = model->UseModelProto(); ONNX_NAMESPACE::GraphProto& graph = *model_proto->mutable_graph(); @@ -595,7 +647,8 @@ ORT_API_STATUS_IMPL(winmla::ModelAddOutput, _In_ OrtModel* model, _In_ const cha output_name, &info->data->shape[0], info->data->shape.NumDimensions(), - ONNXTensorElementDataTypeToTensorProto_DataType(info->data->type)); + ONNXTensorElementDataTypeToTensorProto_DataType(info->data->type) + ); } return nullptr; API_IMPL_END @@ -611,15 +664,21 @@ static const onnx::OpSchema* GetSchema(const char* const op_type, int64_t opset, return registry->GetSchema(op_type, static_cast(opset), domain); } -ORT_API_STATUS_IMPL(winmla::ModelAddOperator, - _In_ OrtModel* model, - _In_ const char* const op_type, - _In_ const char* const op_name, - _In_ int64_t opset, - _In_ const char* const op_domain, - _In_ const char* const* input_names, _In_ size_t num_inputs, - _In_ const char* const* output_names, _In_ size_t num_outputs, - _In_ const char* const* attribute_names, _In_ OrtValue** attribute_values, _In_ size_t num_attributes) { +ORT_API_STATUS_IMPL( + winmla::ModelAddOperator, + _In_ OrtModel* model, + _In_ const char* const op_type, + _In_ const char* const op_name, + _In_ int64_t opset, + _In_ const char* const op_domain, + _In_ const char* const* input_names, + _In_ size_t num_inputs, + _In_ const char* const* output_names, + _In_ size_t num_outputs, + _In_ const char* const* attribute_names, + _In_ OrtValue** attribute_values, + _In_ size_t num_attributes +) { API_IMPL_BEGIN auto model_proto = model->UseModelProto(); ONNX_NAMESPACE::GraphProto& graph = *model_proto->mutable_graph(); @@ -667,7 +726,7 @@ ORT_API_STATUS_IMPL(winmla::ModelAddOperator, case onnx::AttributeProto_AttributeType_INTS: { auto raw_data = tensor->DataRaw(); for (int j = 0; j < tensor->Shape().Size(); j++) { - attr->add_ints(*(reinterpret_cast(raw_data)+j)); + attr->add_ints(*(reinterpret_cast(raw_data) + j)); } break; } @@ -704,8 +763,7 @@ ORT_API_STATUS_IMPL(winmla::ModelAddOperator, auto name = output_names[i]; if (name != nullptr) { node.add_output(name); - } - else { + } else { node.add_output("unused"); } } @@ -713,10 +771,9 @@ ORT_API_STATUS_IMPL(winmla::ModelAddOperator, API_IMPL_END } -ORT_API_STATUS_IMPL(winmla::ModelGetOpsetVersion, - _In_ OrtModel* model, - _In_ const char* const domain, - _Out_ int32_t* version) { +ORT_API_STATUS_IMPL( + winmla::ModelGetOpsetVersion, _In_ OrtModel* model, _In_ const char* const domain, _Out_ int32_t* version +) { API_IMPL_BEGIN auto model_proto = model->UseModelProto(); @@ -742,10 +799,16 @@ ORT_API(void, winmla::ReleaseModel, OrtModel* ptr) { #include "core/framework/onnxruntime_typeinfo.h" #include "core/framework/tensor_type_and_shape.h" -ORT_API_STATUS_IMPL(winmla::CreateTensorTypeInfo, _In_ const int64_t* dim_values, size_t dim_count, ONNXTensorElementDataType type, _Out_ OrtTypeInfo** ort_type_info) { +ORT_API_STATUS_IMPL( + winmla::CreateTensorTypeInfo, + _In_ const int64_t* dim_values, + size_t dim_count, + ONNXTensorElementDataType type, + _Out_ OrtTypeInfo** ort_type_info +) { API_IMPL_BEGIN auto tensor_shape = onnxruntime::TensorShape(dim_values, dim_count); - auto type_and_shape = OrtTensorTypeAndShapeInfo::GetTensorShapeAndTypeHelper(type, std::move(tensor_shape), nullptr); + auto type_and_shape = OrtTensorTypeAndShapeInfo::GetTensorShapeAndTypeHelper(type, std::move(tensor_shape), nullptr); *ort_type_info = OrtTypeInfo::MakePtr(ONNX_TYPE_TENSOR, std::move(type_and_shape)).release(); return nullptr; API_IMPL_END @@ -763,7 +826,13 @@ ORT_API_STATUS_IMPL(winmla::CreateMapTypeInfo, _Out_ OrtTypeInfo** type_info) { API_IMPL_END } -ORT_API_STATUS_IMPL(winmla::OperatorGetNumInputs, _In_ const char* const op_type, _In_ int64_t opset, _In_ const char* const op_domain, _Out_ size_t* num_inputs) { +ORT_API_STATUS_IMPL( + winmla::OperatorGetNumInputs, + _In_ const char* const op_type, + _In_ int64_t opset, + _In_ const char* const op_domain, + _Out_ size_t* num_inputs +) { API_IMPL_BEGIN auto schema = GetSchema(op_type, opset, op_domain); *num_inputs = schema->inputs().size(); @@ -771,7 +840,14 @@ ORT_API_STATUS_IMPL(winmla::OperatorGetNumInputs, _In_ const char* const op_type API_IMPL_END } -ORT_API_STATUS_IMPL(winmla::OperatorGetInputName, _In_ const char* const op_type, _In_ int64_t opset, _In_ const char* const op_domain, _In_ size_t index, _Out_ const char** const name) { +ORT_API_STATUS_IMPL( + winmla::OperatorGetInputName, + _In_ const char* const op_type, + _In_ int64_t opset, + _In_ const char* const op_domain, + _In_ size_t index, + _Out_ const char** const name +) { API_IMPL_BEGIN auto schema = GetSchema(op_type, opset, op_domain); *name = schema->inputs().at(index).GetName().c_str(); @@ -779,7 +855,13 @@ ORT_API_STATUS_IMPL(winmla::OperatorGetInputName, _In_ const char* const op_type API_IMPL_END } -ORT_API_STATUS_IMPL(winmla::OperatorGetNumOutputs, _In_ const char* const op_type, _In_ int64_t opset, _In_ const char* const op_domain, _Out_ size_t* num_outputs) { +ORT_API_STATUS_IMPL( + winmla::OperatorGetNumOutputs, + _In_ const char* const op_type, + _In_ int64_t opset, + _In_ const char* const op_domain, + _Out_ size_t* num_outputs +) { API_IMPL_BEGIN auto schema = GetSchema(op_type, opset, op_domain); *num_outputs = schema->outputs().size(); @@ -787,7 +869,14 @@ ORT_API_STATUS_IMPL(winmla::OperatorGetNumOutputs, _In_ const char* const op_typ API_IMPL_END } -ORT_API_STATUS_IMPL(winmla::OperatorGetOutputName, _In_ const char* const op_type, _In_ int64_t opset, _In_ const char* const op_domain, _In_ size_t index, _Out_ const char** const name) { +ORT_API_STATUS_IMPL( + winmla::OperatorGetOutputName, + _In_ const char* const op_type, + _In_ int64_t opset, + _In_ const char* const op_domain, + _In_ size_t index, + _Out_ const char** const name +) { API_IMPL_BEGIN auto schema = GetSchema(op_type, opset, op_domain); *name = schema->outputs().at(index).GetName().c_str(); @@ -797,10 +886,9 @@ ORT_API_STATUS_IMPL(winmla::OperatorGetOutputName, _In_ const char* const op_typ #include "core/platform/threadpool.h" #include "core/platform/env.h" -ORT_API_STATUS_IMPL(winmla::CreateThreadPool, - _In_ ThreadPoolType type, - _In_ OrtThreadPoolOptions* options, - _Outptr_ OrtThreadPool** out) { +ORT_API_STATUS_IMPL( + winmla::CreateThreadPool, _In_ ThreadPoolType type, _In_ OrtThreadPoolOptions* options, _Outptr_ OrtThreadPool** out +) { API_IMPL_BEGIN OrtThreadPoolParams params = {}; params.thread_pool_size = options->thread_pool_size; @@ -811,7 +899,9 @@ ORT_API_STATUS_IMPL(winmla::CreateThreadPool, params.name = options->name; params.set_denormal_as_zero = options->set_denormal_as_zero; - auto unique_tp = onnxruntime::concurrency::CreateThreadPool(&onnxruntime::Env::Default(), params, (onnxruntime::concurrency::ThreadPoolType)type); + auto unique_tp = onnxruntime::concurrency::CreateThreadPool( + &onnxruntime::Env::Default(), params, (onnxruntime::concurrency::ThreadPoolType)type + ); *out = reinterpret_cast(unique_tp.release()); return nullptr; API_IMPL_END @@ -821,14 +911,16 @@ ORT_API(void, winmla::ReleaseThreadPool, OrtThreadPool* ptr) { delete reinterpret_cast(ptr); } -ORT_API_STATUS_IMPL(winmla::JoinModels, +ORT_API_STATUS_IMPL( + winmla::JoinModels, _In_ OrtModel* first_model, _In_ OrtModel* second_model, _In_ const char* const* output_names, _In_ const char* const* input_names, size_t num_linkages, bool promote_unlinked_outputs, - _In_ const char* const join_node_prefix) { + _In_ const char* const join_node_prefix +) { API_IMPL_BEGIN std::string second_model_prefix = join_node_prefix; @@ -844,12 +936,13 @@ ORT_API_STATUS_IMPL(winmla::JoinModels, first_model_proto->mutable_graph()->mutable_output()->Clear(); // Add back output - for (int i = first_outputs.size() - 1; i >= 0 ; i--) { + for (int i = first_outputs.size() - 1; i >= 0; i--) { auto& output = first_outputs.at(i); auto output_name = output.name(); - auto found_it = std::find_if(output_names, output_names + num_linkages, - [output_name](auto& name) { return std::strcmp(name, output_name.c_str()) == 0; }); + auto found_it = std::find_if(output_names, output_names + num_linkages, [output_name](auto& name) { + return std::strcmp(name, output_name.c_str()) == 0; + }); if (found_it == (output_names + num_linkages)) { // if output.name() is not found in the linkages, it is unlinked, and it should be promoted auto& promoted_output = *first_model_proto->mutable_graph()->add_output(); @@ -875,9 +968,11 @@ ORT_API_STATUS_IMPL(winmla::JoinModels, auto old_name = other_input.name(); *other_input.mutable_name() = second_model_prefix + old_name; - auto found_it = std::find_if(input_names, input_names + num_linkages, - [old_name](auto& name) { return std::strcmp(name, old_name.c_str()) == 0; }); - bool is_linked = found_it != (input_names + num_linkages); // figure out if other_input.name() exists in the output_names mapped + auto found_it = std::find_if(input_names, input_names + num_linkages, [old_name](auto& name) { + return std::strcmp(name, old_name.c_str()) == 0; + }); + bool is_linked = + found_it != (input_names + num_linkages); // figure out if other_input.name() exists in the output_names mapped if (!is_linked) { auto& input = *first_model_proto->mutable_graph()->add_input(); input = std::move(other_input); @@ -917,12 +1012,14 @@ ORT_API_STATUS_IMPL(winmla::JoinModels, auto version = mutable_opset_import->version(); // does the domain exist in the first model? - auto found_it = std::find_if(first_model_proto->mutable_opset_import()->begin(), first_model_proto->mutable_opset_import()->end(), - [&domain](auto& mutable_opset_import) { - - auto first_model_domain = mutable_opset_import.has_domain() ? mutable_opset_import.domain() : std::string(""); - return 0 == strcmp(first_model_domain.c_str(), domain.c_str()); - }); + auto found_it = std::find_if( + first_model_proto->mutable_opset_import()->begin(), + first_model_proto->mutable_opset_import()->end(), + [&domain](auto& mutable_opset_import) { + auto first_model_domain = mutable_opset_import.has_domain() ? mutable_opset_import.domain() : std::string(""); + return 0 == strcmp(first_model_domain.c_str(), domain.c_str()); + } + ); if (found_it != first_model_proto->mutable_opset_import()->end()) { found_it->set_version(std::max(found_it->version(), version)); if (0 == strcmp(domain.c_str(), "")) { @@ -937,14 +1034,20 @@ ORT_API_STATUS_IMPL(winmla::JoinModels, const char* const op_output_name_const_str = op_output_name.c_str(); std::string name = "IdentityTo"; name += second_model_prefix + *(input_names + i); - ModelAddOperator(first_model, - "Identity", - name.c_str(), - opset, - "", - (output_names + i), 1, - &op_output_name_const_str, 1, - nullptr, nullptr, 0); + ModelAddOperator( + first_model, + "Identity", + name.c_str(), + opset, + "", + (output_names + i), + 1, + &op_output_name_const_str, + 1, + nullptr, + nullptr, + 0 + ); } first_model->RefreshModelInfo(); diff --git a/winml/adapter/winml_adapter_session.cpp b/winml/adapter/winml_adapter_session.cpp index 92aeddb633671..fa91978b564ba 100644 --- a/winml/adapter/winml_adapter_session.cpp +++ b/winml/adapter/winml_adapter_session.cpp @@ -28,27 +28,30 @@ namespace winmla = Windows::AI::MachineLearning::Adapter; // the protected methods used below. class InferenceSessionProtectedLoadAccessor : public onnxruntime::InferenceSession { public: - onnxruntime::common::Status - Load(std::unique_ptr p_model_proto) { + onnxruntime::common::Status Load(std::unique_ptr p_model_proto) { return onnxruntime::InferenceSession::LoadOnnxModel(std::move(p_model_proto)); } - const onnxruntime::SessionState& GetSessionState() { - return onnxruntime::InferenceSession::GetSessionState(); - } + const onnxruntime::SessionState& GetSessionState() { return onnxruntime::InferenceSession::GetSessionState(); } }; -ORT_API_STATUS_IMPL(winmla::CreateSessionWithoutModel, _In_ OrtEnv* env, _In_ const OrtSessionOptions* options, - _In_ OrtThreadPool* inter_op_thread_pool, _In_ OrtThreadPool* intra_op_thread_pool, _Outptr_ OrtSession** session) { +ORT_API_STATUS_IMPL( + winmla::CreateSessionWithoutModel, + _In_ OrtEnv* env, + _In_ const OrtSessionOptions* options, + _In_ OrtThreadPool* inter_op_thread_pool, + _In_ OrtThreadPool* intra_op_thread_pool, + _Outptr_ OrtSession** session +) { API_IMPL_BEGIN std::unique_ptr inference_session; try { // Create the inference session - inference_session = - std::make_unique( - options->value, - env->GetEnvironment(), - reinterpret_cast(intra_op_thread_pool), - reinterpret_cast(inter_op_thread_pool)); + inference_session = std::make_unique( + options->value, + env->GetEnvironment(), + reinterpret_cast(intra_op_thread_pool), + reinterpret_cast(inter_op_thread_pool) + ); } catch (const std::exception& e) { return OrtApis::CreateStatus(ORT_FAIL, e.what()); } @@ -63,10 +66,14 @@ ORT_API_STATUS_IMPL(winmla::CreateSessionWithoutModel, _In_ OrtEnv* env, _In_ co if (options->value.enable_mem_pattern) { // TODO Instead of returning an error, should we set mem pattern to false here and log a warning saying so? // Doing so would be inconsistent with the Python API that doesn't go through this code path. - return OrtApis::CreateStatus(ORT_INVALID_ARGUMENT, "Mem pattern should be disabled when using DML execution provider."); + return OrtApis::CreateStatus( + ORT_INVALID_ARGUMENT, "Mem pattern should be disabled when using DML execution provider." + ); } if (options->value.execution_mode != ExecutionMode::ORT_SEQUENTIAL) { - return OrtApis::CreateStatus(ORT_INVALID_ARGUMENT, "Sequential execution should be enabled when using DML execution provider."); + return OrtApis::CreateStatus( + ORT_INVALID_ARGUMENT, "Sequential execution should be enabled when using DML execution provider." + ); } } provider_list.push_back(std::move(provider)); @@ -95,11 +102,15 @@ ORT_API_STATUS_IMPL(winmla::CreateSessionWithoutModel, _In_ OrtEnv* env, _In_ co API_IMPL_END } -ORT_API_STATUS_IMPL(winmla::SessionGetExecutionProvider, _In_ OrtSession* session, _In_ size_t index, _Out_ OrtExecutionProvider** ort_provider) { +ORT_API_STATUS_IMPL( + winmla::SessionGetExecutionProvider, + _In_ OrtSession* session, + _In_ size_t index, + _Out_ OrtExecutionProvider** ort_provider +) { API_IMPL_BEGIN auto inference_session = reinterpret_cast<::onnxruntime::InferenceSession*>(session); - auto session_protected_load_accessor = - static_cast(inference_session); + auto session_protected_load_accessor = static_cast(inference_session); const auto& session_state = session_protected_load_accessor->GetSessionState(); auto& provider_id = session_state.GetExecutionProviders().GetIds().at(index); const auto& provider = session_state.GetExecutionProviders().Get(provider_id); @@ -123,8 +134,7 @@ ORT_API_STATUS_IMPL(winmla::SessionInitialize, _In_ OrtSession* session) { ORT_API_STATUS_IMPL(winmla::SessionLoadAndPurloinModel, _In_ OrtSession* session, _In_ OrtModel* model) { API_IMPL_BEGIN auto inference_session = reinterpret_cast<::onnxruntime::InferenceSession*>(session); - auto session_protected_load_accessor = - static_cast(inference_session); + auto session_protected_load_accessor = static_cast(inference_session); auto status = session_protected_load_accessor->Load(model->DetachModelProto()); @@ -165,15 +175,13 @@ ORT_API_STATUS_IMPL(winmla::SessionRegisterGraphTransformers, _In_ OrtSession* s API_IMPL_END } -inline std::list> -GetLotusCustomRegistries(IMLOperatorRegistry* registry) { +inline std::list> GetLotusCustomRegistries(IMLOperatorRegistry* registry) { if (registry != nullptr) { #ifdef USE_DML // Down-cast to the concrete type. // The only supported input is the AbiCustomRegistry type. // Other implementations of IMLOperatorRegistry are forbidden. - auto abi_custom_registry = - static_cast(registry); + auto abi_custom_registry = static_cast(registry); // Get the ORT registry return abi_custom_registry->GetRegistries(); @@ -182,7 +190,9 @@ GetLotusCustomRegistries(IMLOperatorRegistry* registry) { return {}; } -ORT_API_STATUS_IMPL(winmla::SessionRegisterCustomRegistry, _In_ OrtSession* session, _In_ IMLOperatorRegistry* registry) { +ORT_API_STATUS_IMPL( + winmla::SessionRegisterCustomRegistry, _In_ OrtSession* session, _In_ IMLOperatorRegistry* registry +) { API_IMPL_BEGIN auto inference_session = reinterpret_cast<::onnxruntime::InferenceSession*>(session); auto custom_registries = GetLotusCustomRegistries(registry); @@ -210,17 +220,21 @@ ORT_API_STATUS_IMPL(winmla::CreateCustomRegistry, _Out_ IMLOperatorRegistry** re static OrtDevice GetSessionGetInputDevice(_In_ OrtSession* session, _In_ const char* const input_name) { auto inference_session = reinterpret_cast<::onnxruntime::InferenceSession*>(session); - auto session_protected_load_accessor = - static_cast(inference_session); + auto session_protected_load_accessor = static_cast(inference_session); const onnxruntime::SessionState& session_state = session_protected_load_accessor->GetSessionState(); - onnxruntime::InlinedVectornode_info_vec; + onnxruntime::InlinedVector node_info_vec; ORT_THROW_IF_ERROR(session_state.GetInputNodeInfo(input_name, node_info_vec)); const auto& node_info = node_info_vec.front(); // all consumers of a feed have the same device so first entry is fine return *node_info.device; } -ORT_API_STATUS_IMPL(winmla::SessionGetInputRequiredDeviceId, _In_ OrtSession* session, _In_ const char* const input_name, _Out_ int16_t* device_id) { +ORT_API_STATUS_IMPL( + winmla::SessionGetInputRequiredDeviceId, + _In_ OrtSession* session, + _In_ const char* const input_name, + _Out_ int16_t* device_id +) { API_IMPL_BEGIN auto device = GetSessionGetInputDevice(session, input_name); *device_id = device.Id(); @@ -236,12 +250,16 @@ ORT_API_STATUS_IMPL(winmla::ValueGetDeviceId, _In_ OrtValue* ort_value, _Out_ in API_IMPL_END } -ORT_API_STATUS_IMPL(winmla::SessionCopyOneInputAcrossDevices, _In_ OrtSession* session, _In_ const char* const input_name, - _In_ OrtValue* orig_value, _Outptr_ OrtValue** new_value) { +ORT_API_STATUS_IMPL( + winmla::SessionCopyOneInputAcrossDevices, + _In_ OrtSession* session, + _In_ const char* const input_name, + _In_ OrtValue* orig_value, + _Outptr_ OrtValue** new_value +) { API_IMPL_BEGIN auto inference_session = reinterpret_cast<::onnxruntime::InferenceSession*>(session); - auto session_protected_load_accessor = - static_cast(inference_session); + auto session_protected_load_accessor = static_cast(inference_session); const onnxruntime::SessionState& session_state = session_protected_load_accessor->GetSessionState(); auto ort_value = std::make_unique(); @@ -261,9 +279,7 @@ ORT_API_STATUS_IMPL(winmla::SessionGetNumberOfIntraOpThreads, _In_ OrtSession* s struct ThreadPoolSessionInspector : public ::onnxruntime::InferenceSession { public: - onnxruntime::concurrency::ThreadPool* IntraOpThreadPool() const { - return GetIntraOpThreadPoolToUse(); - } + onnxruntime::concurrency::ThreadPool* IntraOpThreadPool() const { return GetIntraOpThreadPoolToUse(); } }; auto inference_session = reinterpret_cast(session); @@ -283,14 +299,21 @@ ORT_API_STATUS_IMPL(winmla::SessionGetIntraOpThreadSpinning, _In_ OrtSession* se API_IMPL_END } -ORT_API_STATUS_IMPL(winmla::SessionGetNamedDimensionsOverrides, _In_ OrtSession* session, _Out_ winrt::Windows::Foundation::Collections::IMapView& named_dimension_overrides) { +ORT_API_STATUS_IMPL( + winmla::SessionGetNamedDimensionsOverrides, + _In_ OrtSession* session, + _Out_ winrt::Windows::Foundation::Collections::IMapView& named_dimension_overrides +) { API_IMPL_BEGIN auto inference_session = reinterpret_cast<::onnxruntime::InferenceSession*>(session); auto session_options = inference_session->GetSessionOptions(); - winrt::Windows::Foundation::Collections::IMap override_map = winrt::single_threaded_map(); + winrt::Windows::Foundation::Collections::IMap override_map = + winrt::single_threaded_map(); for (auto freeDimOverride : session_options.free_dimension_overrides) { if (freeDimOverride.dim_identifer_type == onnxruntime::FreeDimensionOverrideType::Name) { - override_map.Insert(winrt::to_hstring(freeDimOverride.dim_identifier), static_cast(freeDimOverride.dim_value)); + override_map.Insert( + winrt::to_hstring(freeDimOverride.dim_identifier), static_cast(freeDimOverride.dim_value) + ); } } named_dimension_overrides = override_map.GetView(); diff --git a/winml/api/Microsoft.AI.MachineLearning.Experimental.idl b/winml/api/Microsoft.AI.MachineLearning.Experimental.idl index 3e7a33ebd1b9d..ad39a1ed7e684 100644 --- a/winml/api/Microsoft.AI.MachineLearning.Experimental.idl +++ b/winml/api/Microsoft.AI.MachineLearning.Experimental.idl @@ -27,7 +27,13 @@ namespace ROOT_NS.AI.MachineLearning.Experimental { [marshaling_behavior(agile)] [dualapipartition(1)] runtimeclass LearningModelSessionOptionsExperimental { + LearningModelSessionOptionsExperimental(ROOT_NS.AI.MachineLearning.LearningModelSessionOptions options); + + //! The GetNamedDimensionOverrides method retrieves the named dimension overrides configured on the session options. Windows.Foundation.Collections.IMapView GetNamedDimensionOverrides(); + + //! The RegisterCustomOpsLibrary method registers an onnxruntime custom operator library into session creation. + void RegisterCustomOpsLibrary(String path); } [threading(both)] @@ -139,7 +145,7 @@ namespace ROOT_NS.AI.MachineLearning.Experimental { //! The Save method serializes the model as an ONNX model to a specified path. void Save(String file_name); - //! The JoinModel fuses two models by linking outputs from the first model, to inupts of the second. + //! The JoinModel fuses two models by linking outputs from the first model, to inupts of the second. ROOT_NS.AI.MachineLearning.LearningModel JoinModel(ROOT_NS.AI.MachineLearning.LearningModel other, LearningModelJoinOptions options); //! The SetName function changes the model name to the specified string diff --git a/winml/api/dualapipartitionattribute.h b/winml/api/dualapipartitionattribute.h index 7dec68eb883b0..93fbef45944b6 100644 --- a/winml/api/dualapipartitionattribute.h +++ b/winml/api/dualapipartitionattribute.h @@ -3,7 +3,7 @@ * File built with Microsoft(R) MIDLRT Compiler Engine Version 10.00.0228 */ -#pragma warning( disable: 4049 ) /* more than 64k source lines */ +#pragma warning(disable : 4049) /* more than 64k source lines */ /* verify that the version is high enough to compile this file*/ #ifndef __REQUIRED_RPCNDR_H_VERSION__ @@ -31,46 +31,43 @@ #ifndef __dualapipartitionattribute_p_h__ #define __dualapipartitionattribute_p_h__ - #pragma once #pragma push_macro("MIDL_CONST_ID") #undef MIDL_CONST_ID #define MIDL_CONST_ID const __declspec(selectany) - // API Contract Inclusion Definitions #if !defined(SPECIFIC_API_CONTRACT_DEFINITIONS) #if !defined(WINDOWS_APPLICATIONMODEL_CALLS_CALLSPHONECONTRACT_VERSION) #define WINDOWS_APPLICATIONMODEL_CALLS_CALLSPHONECONTRACT_VERSION 0x50000 -#endif // defined(WINDOWS_APPLICATIONMODEL_CALLS_CALLSPHONECONTRACT_VERSION) +#endif // defined(WINDOWS_APPLICATIONMODEL_CALLS_CALLSPHONECONTRACT_VERSION) #if !defined(WINDOWS_FOUNDATION_FOUNDATIONCONTRACT_VERSION) #define WINDOWS_FOUNDATION_FOUNDATIONCONTRACT_VERSION 0x40000 -#endif // defined(WINDOWS_FOUNDATION_FOUNDATIONCONTRACT_VERSION) +#endif // defined(WINDOWS_FOUNDATION_FOUNDATIONCONTRACT_VERSION) #if !defined(WINDOWS_FOUNDATION_UNIVERSALAPICONTRACT_VERSION) #define WINDOWS_FOUNDATION_UNIVERSALAPICONTRACT_VERSION 0xa0000 -#endif // defined(WINDOWS_FOUNDATION_UNIVERSALAPICONTRACT_VERSION) +#endif // defined(WINDOWS_FOUNDATION_UNIVERSALAPICONTRACT_VERSION) #if !defined(WINDOWS_NETWORKING_SOCKETS_CONTROLCHANNELTRIGGERCONTRACT_VERSION) #define WINDOWS_NETWORKING_SOCKETS_CONTROLCHANNELTRIGGERCONTRACT_VERSION 0x30000 -#endif // defined(WINDOWS_NETWORKING_SOCKETS_CONTROLCHANNELTRIGGERCONTRACT_VERSION) +#endif // defined(WINDOWS_NETWORKING_SOCKETS_CONTROLCHANNELTRIGGERCONTRACT_VERSION) #if !defined(WINDOWS_PHONE_PHONECONTRACT_VERSION) #define WINDOWS_PHONE_PHONECONTRACT_VERSION 0x10000 -#endif // defined(WINDOWS_PHONE_PHONECONTRACT_VERSION) +#endif // defined(WINDOWS_PHONE_PHONECONTRACT_VERSION) #if !defined(WINDOWS_PHONE_PHONEINTERNALCONTRACT_VERSION) #define WINDOWS_PHONE_PHONEINTERNALCONTRACT_VERSION 0x10000 -#endif // defined(WINDOWS_PHONE_PHONEINTERNALCONTRACT_VERSION) +#endif // defined(WINDOWS_PHONE_PHONEINTERNALCONTRACT_VERSION) #if !defined(WINDOWS_UI_WEBUI_CORE_WEBUICOMMANDBARCONTRACT_VERSION) #define WINDOWS_UI_WEBUI_CORE_WEBUICOMMANDBARCONTRACT_VERSION 0x10000 -#endif // defined(WINDOWS_UI_WEBUI_CORE_WEBUICOMMANDBARCONTRACT_VERSION) - -#endif // defined(SPECIFIC_API_CONTRACT_DEFINITIONS) +#endif // defined(WINDOWS_UI_WEBUI_CORE_WEBUICOMMANDBARCONTRACT_VERSION) +#endif // defined(SPECIFIC_API_CONTRACT_DEFINITIONS) // Header files for imported files #include "Windows.Foundation.h" @@ -78,26 +75,23 @@ #if defined(__cplusplus) && !defined(CINTERFACE) /* Forward Declarations */ +#pragma warning(push) +#pragma warning(disable : 4668) +#pragma warning(disable : 4001) +#pragma once +#pragma warning(pop) -#pragma warning (push) -#pragma warning (disable:4668) -#pragma warning (disable:4001) -#pragma once -#pragma warning (pop) - - -#else // !defined(__cplusplus) +#else // !defined(__cplusplus) /* Forward Declarations */ -#pragma warning (push) -#pragma warning (disable:4668) -#pragma warning (disable:4001) -#pragma once -#pragma warning (pop) - +#pragma warning(push) +#pragma warning(disable : 4668) +#pragma warning(disable : 4001) +#pragma once +#pragma warning(pop) -#endif // defined(__cplusplus) +#endif // defined(__cplusplus) #pragma pop_macro("MIDL_CONST_ID") -#endif // __dualapipartitionattribute_p_h__ +#endif // __dualapipartitionattribute_p_h__ -#endif // __dualapipartitionattribute_h__ +#endif // __dualapipartitionattribute_h__ diff --git a/winml/dll/module.cpp b/winml/dll/module.cpp index 973376c01bbcf..d669f55d77f8b 100644 --- a/winml/dll/module.cpp +++ b/winml/dll/module.cpp @@ -64,8 +64,7 @@ extern "C" HRESULT WINAPI MLCreateOperatorRegistry(_COM_Outptr_ IMLOperatorRegis } CATCH_RETURN(); -__control_entrypoint(DllExport) -STDAPI DllCanUnloadNow() { +__control_entrypoint(DllExport) STDAPI DllCanUnloadNow() { // This dll should not be freed by // CoFreeUnusedLibraries since there can be outstanding COM object // references to many objects (AbiCustomRegistry, IMLOperatorKernelContext, @@ -97,14 +96,16 @@ STDAPI DllGetExperimentalActivationFactory(void* classId, void** factory) noexce }; std::wostringstream learning_model_builder_class; - learning_model_builder_class << XSTRINGIFY(WINML_ROOT_NS) << ".AI.MachineLearning.Experimental.LearningModelBuilder"; + learning_model_builder_class + << XSTRINGIFY(WINML_ROOT_NS) << ".AI.MachineLearning.Experimental.LearningModelBuilder"; if (requal(name, learning_model_builder_class.str())) { *factory = winrt::detach_abi(winrt::make()); return 0; } std::wostringstream learning_model_operator_class; - learning_model_operator_class << XSTRINGIFY(WINML_ROOT_NS) << ".AI.MachineLearning.Experimental.LearningModelOperator"; + learning_model_operator_class + << XSTRINGIFY(WINML_ROOT_NS) << ".AI.MachineLearning.Experimental.LearningModelOperator"; if (requal(name, learning_model_operator_class.str())) { *factory = winrt::detach_abi(winrt::make()); @@ -112,26 +113,41 @@ STDAPI DllGetExperimentalActivationFactory(void* classId, void** factory) noexce } std::wostringstream learning_model_session_experimental_class; - learning_model_session_experimental_class << XSTRINGIFY(WINML_ROOT_NS) << ".AI.MachineLearning.Experimental.LearningModelSessionExperimental"; + learning_model_session_experimental_class + << XSTRINGIFY(WINML_ROOT_NS) << ".AI.MachineLearning.Experimental.LearningModelSessionExperimental"; if (requal(name, learning_model_session_experimental_class.str())) { - *factory = winrt::detach_abi(winrt::make()); + *factory = + winrt::detach_abi(winrt::make()); return 0; } std::wostringstream learning_model_experimental_class; - learning_model_experimental_class << XSTRINGIFY(WINML_ROOT_NS) << ".AI.MachineLearning.Experimental.LearningModelExperimental"; + learning_model_experimental_class + << XSTRINGIFY(WINML_ROOT_NS) << ".AI.MachineLearning.Experimental.LearningModelExperimental"; if (requal(name, learning_model_experimental_class.str())) { - *factory = winrt::detach_abi(winrt::make()); + *factory = + winrt::detach_abi(winrt::make()); return 0; } std::wostringstream learning_model_join_options_class; - learning_model_join_options_class << XSTRINGIFY(WINML_ROOT_NS) << ".AI.MachineLearning.Experimental.LearningModelJoinOptions"; + learning_model_join_options_class + << XSTRINGIFY(WINML_ROOT_NS) << ".AI.MachineLearning.Experimental.LearningModelJoinOptions"; if (requal(name, learning_model_join_options_class.str())) { *factory = winrt::detach_abi(winrt::make()); return 0; } + std::wostringstream learning_model_session_options_experimental_class; + learning_model_session_options_experimental_class + << XSTRINGIFY(WINML_ROOT_NS) << ".AI.MachineLearning.Experimental.LearningModelSessionOptionsExperimental"; + if (requal(name, learning_model_session_options_experimental_class.str())) { + *factory = winrt::detach_abi( + winrt::make() + ); + return 0; + } + return winrt::hresult_class_not_available(name).to_abi(); } catch (...) { return winrt::to_hresult(); diff --git a/winml/lib/Api.Experimental/LearningModelBuilder.cpp b/winml/lib/Api.Experimental/LearningModelBuilder.cpp index 76cd5caebb9e9..c7b563b8125b6 100644 --- a/winml/lib/Api.Experimental/LearningModelBuilder.cpp +++ b/winml/lib/Api.Experimental/LearningModelBuilder.cpp @@ -10,7 +10,11 @@ namespace WINML_EXPERIMENTALP { -LearningModelBuilder::LearningModelBuilder(int64_t opset) : inert_session_(nullptr), inputs_(nullptr), outputs_(nullptr), operators_(nullptr) { +LearningModelBuilder::LearningModelBuilder(int64_t opset) + : inert_session_(nullptr), + inputs_(nullptr), + outputs_(nullptr), + operators_(nullptr) { telemetry_helper.LogApiUsage("LearningModelBuilder::LearningModelBuilder"); WINML_THROW_IF_FAILED(CreateOnnxruntimeEngineFactory(engine_factory_.put())); @@ -26,11 +30,11 @@ LearningModelBuilder::LearningModelBuilder(int64_t opset) : inert_session_(nullp inert_session_ = winmlp::LearningModelSession::CreateInertSession(engine.get()); } -LearningModelBuilder::LearningModelBuilder(LearningModelBuilder& builder) : inert_session_(nullptr), - inputs_(builder.inputs_), - outputs_(builder.outputs_), - operators_(builder.operators_) -{ +LearningModelBuilder::LearningModelBuilder(LearningModelBuilder& builder) + : inert_session_(nullptr), + inputs_(builder.inputs_), + outputs_(builder.outputs_), + operators_(builder.operators_) { } winml_experimental::LearningModelInputs LearningModelBuilder::Inputs() { @@ -64,17 +68,14 @@ winml_experimental::LearningModelBuilder LearningModelBuilder::Create(int32_t op } winml::TensorFeatureDescriptor LearningModelBuilder::CreateTensorFeatureDescriptor( - hstring const& name, - winml::TensorKind const& kind, - array_view shape) { + hstring const& name, winml::TensorKind const& kind, array_view shape +) { return winrt::make(name, L"", kind, shape); } winml::TensorFeatureDescriptor LearningModelBuilder::CreateTensorFeatureDescriptor( - hstring const& name, - hstring const& description, - winml::TensorKind const& kind, - array_view shape) { + hstring const& name, hstring const& description, winml::TensorKind const& kind, array_view shape +) { return winrt::make(name, description, kind, shape); } diff --git a/winml/lib/Api.Experimental/LearningModelBuilder.h b/winml/lib/Api.Experimental/LearningModelBuilder.h index 1987e3bbbec74..0ff23ac1efea6 100644 --- a/winml/lib/Api.Experimental/LearningModelBuilder.h +++ b/winml/lib/Api.Experimental/LearningModelBuilder.h @@ -19,21 +19,16 @@ struct LearningModelBuilder : LearningModelBuilderT { static winml_experimental::LearningModelBuilder Create(int32_t opset); static winml::TensorFeatureDescriptor CreateTensorFeatureDescriptor( - hstring const& name, - hstring const& description, - winml::TensorKind const& kind, - array_view shape); + hstring const& name, hstring const& description, winml::TensorKind const& kind, array_view shape + ); static winml::TensorFeatureDescriptor CreateTensorFeatureDescriptor( - hstring const& name, - winml::TensorKind const& kind, - array_view shape); + hstring const& name, winml::TensorKind const& kind, array_view shape + ); _winml::IModel* UseModel(); - - winml::LearningModelSession InertSession() { - return inert_session_; - } + + winml::LearningModelSession InertSession() { return inert_session_; } private: com_ptr<_winml::IEngineFactory> engine_factory_; @@ -44,9 +39,8 @@ struct LearningModelBuilder : LearningModelBuilderT { winml_experimental::LearningModelOutputs outputs_; winml_experimental::LearningModelOperatorSet operators_; }; -} // WINML_EXPERIMENTALP +} // namespace WINML_EXPERIMENTALP namespace WINML_EXPERIMENTAL::factory_implementation { -struct LearningModelBuilder : LearningModelBuilderT { -}; -} // namespace winrt::winml_experimental::factory_implementation +struct LearningModelBuilder : LearningModelBuilderT {}; +} // namespace WINML_EXPERIMENTAL::factory_implementation diff --git a/winml/lib/Api.Experimental/LearningModelExperimental.cpp b/winml/lib/Api.Experimental/LearningModelExperimental.cpp index e6c22bbb39cd9..00838318632c7 100644 --- a/winml/lib/Api.Experimental/LearningModelExperimental.cpp +++ b/winml/lib/Api.Experimental/LearningModelExperimental.cpp @@ -5,28 +5,33 @@ namespace WINML_EXPERIMENTALP { -LearningModelExperimental::LearningModelExperimental(Microsoft::AI::MachineLearning::LearningModel const& model) : model_(model) -{} +LearningModelExperimental::LearningModelExperimental(Microsoft::AI::MachineLearning::LearningModel const& model) + : model_(model) { +} -winml::LearningModel LearningModelExperimental::JoinModel(winml::LearningModel const& other, winml_experimental::LearningModelJoinOptions const& options) { - telemetry_helper.LogApiUsage("LearningModelExperimental::JoinModel"); +winml::LearningModel LearningModelExperimental::JoinModel( + winml::LearningModel const& other, winml_experimental::LearningModelJoinOptions const& options +) { + telemetry_helper.LogApiUsage("LearningModelExperimental::JoinModel"); - auto modelp = model_.as(); - auto optionsp = options.as(); + auto modelp = model_.as(); + auto optionsp = options.as(); - modelp->JoinModel(other, - optionsp->GetLinkages(), - optionsp->PromoteUnlinkedOutputsToFusedOutputs(), - optionsp->CloseModelOnJoin(), - optionsp->JoinedNodePrefix()); + modelp->JoinModel( + other, + optionsp->GetLinkages(), + optionsp->PromoteUnlinkedOutputsToFusedOutputs(), + optionsp->CloseModelOnJoin(), + optionsp->JoinedNodePrefix() + ); - return model_; + return model_; } void LearningModelExperimental::Save(hstring const& file_name) { - telemetry_helper.LogApiUsage("LearningModelExperimental::Save"); - auto modelp = model_.as(); - modelp->SaveToFile(file_name); + telemetry_helper.LogApiUsage("LearningModelExperimental::Save"); + auto modelp = model_.as(); + modelp->SaveToFile(file_name); } void LearningModelExperimental::SetName(hstring const& model_name) { @@ -34,4 +39,4 @@ void LearningModelExperimental::SetName(hstring const& model_name) { modelp->SetName(model_name); } -} +} // namespace WINML_EXPERIMENTALP diff --git a/winml/lib/Api.Experimental/LearningModelExperimental.h b/winml/lib/Api.Experimental/LearningModelExperimental.h index 1e43c73f4f232..39542de749ab9 100644 --- a/winml/lib/Api.Experimental/LearningModelExperimental.h +++ b/winml/lib/Api.Experimental/LearningModelExperimental.h @@ -3,27 +3,28 @@ namespace WINML_EXPERIMENTALP { -struct LearningModelExperimental : LearningModelExperimentalT -{ - LearningModelExperimental() = default; +struct LearningModelExperimental : LearningModelExperimentalT { + LearningModelExperimental() = default; - LearningModelExperimental(Microsoft::AI::MachineLearning::LearningModel const& model); - Microsoft::AI::MachineLearning::LearningModel JoinModel(Microsoft::AI::MachineLearning::LearningModel const& other, Microsoft::AI::MachineLearning::Experimental::LearningModelJoinOptions const& options); + LearningModelExperimental(Microsoft::AI::MachineLearning::LearningModel const& model); + Microsoft::AI::MachineLearning::LearningModel JoinModel( + Microsoft::AI::MachineLearning::LearningModel const& other, + Microsoft::AI::MachineLearning::Experimental::LearningModelJoinOptions const& options + ); - void Save(hstring const& file_name); + void Save(hstring const& file_name); - void SetName(hstring const& model_name); + void SetName(hstring const& model_name); -private: - Microsoft::AI::MachineLearning::LearningModel model_; + private: + Microsoft::AI::MachineLearning::LearningModel model_; }; -} +} // namespace WINML_EXPERIMENTALP namespace WINML_EXPERIMENTAL::factory_implementation { -struct LearningModelExperimental : LearningModelExperimentalT -{ -}; +struct LearningModelExperimental + : LearningModelExperimentalT {}; -} +} // namespace WINML_EXPERIMENTAL::factory_implementation diff --git a/winml/lib/Api.Experimental/LearningModelInputs.cpp b/winml/lib/Api.Experimental/LearningModelInputs.cpp index 5c962c3a2ef50..6227e42680a5d 100644 --- a/winml/lib/Api.Experimental/LearningModelInputs.cpp +++ b/winml/lib/Api.Experimental/LearningModelInputs.cpp @@ -9,14 +9,19 @@ namespace WINML_EXPERIMENTALP { -LearningModelInputs::LearningModelInputs(winml_experimental::LearningModelBuilder builder) : input_descriptors_(winrt::single_threaded_vector()), - input_default_values_(winrt::single_threaded_vector()), - constant_descriptors_(winrt::single_threaded_vector()), - constant_values_(winrt::single_threaded_vector()), - builder_(builder) { +LearningModelInputs::LearningModelInputs(winml_experimental::LearningModelBuilder builder) + : input_descriptors_(winrt::single_threaded_vector()), + input_default_values_(winrt::single_threaded_vector()), + constant_descriptors_(winrt::single_threaded_vector()), + constant_values_(winrt::single_threaded_vector()), + builder_(builder) { } -winml_experimental::LearningModelBuilder LearningModelInputs::AddInput(winml::ILearningModelFeatureDescriptor const& input, Windows::Foundation::IInspectable const& default_value, bool is_constant) { +winml_experimental::LearningModelBuilder LearningModelInputs::AddInput( + winml::ILearningModelFeatureDescriptor const& input, + Windows::Foundation::IInspectable const& default_value, + bool is_constant +) { // Perform model update inside the builder auto model = builder_.as()->UseModel(); auto descriptor_provider = input.as<_winml::IDescriptorInfoProvider>(); @@ -27,11 +32,11 @@ winml_experimental::LearningModelBuilder LearningModelInputs::AddInput(winml::IL auto default_value_value_provider = default_value.as<_winml::ILotusValueProviderPrivate>(); // Create the Binding Context to pass to the feature value _winml::BindingContext context{ - _winml::BindingType::kInput, - builder_.as()->InertSession(), - nullptr, - nullptr, - {} // SubresourceId is set by callee + _winml::BindingType::kInput, + builder_.as()->InertSession(), + nullptr, + nullptr, + {} // SubresourceId is set by callee }; default_value_value_provider->GetValue(context, default_value_ivalue.put()); } @@ -45,25 +50,32 @@ winml_experimental::LearningModelBuilder LearningModelInputs::Add(winml::ILearni return AddInput(input, nullptr, false); } -winml_experimental::LearningModelBuilder LearningModelInputs::Add(hstring const& input_name, hstring const& input_description, Windows::Foundation::IInspectable const& default_value) { +winml_experimental::LearningModelBuilder LearningModelInputs::Add( + hstring const& input_name, hstring const& input_description, Windows::Foundation::IInspectable const& default_value +) { if (auto tensor = default_value.try_as()) { auto shape = tensor.Shape(); std::vector shape_vector(begin(shape), end(shape)); - auto descriptor = winrt::make(input_name, input_description, tensor.TensorKind(), shape_vector); + auto descriptor = + winrt::make(input_name, input_description, tensor.TensorKind(), shape_vector); return AddInput(descriptor, default_value, false); } WINML_THROW_HR(E_UNEXPECTED); } -winml_experimental::LearningModelBuilder LearningModelInputs::AddConstant(hstring const& input_name, Windows::Foundation::IInspectable const& value) { +winml_experimental::LearningModelBuilder LearningModelInputs::AddConstant( + hstring const& input_name, Windows::Foundation::IInspectable const& value +) { if (auto tensor = value.try_as()) { winrt::hstring no_description_for_constants = L""; auto shape = tensor.Shape(); std::vector shape_vector(begin(shape), end(shape)); - auto descriptor = winrt::make(input_name, no_description_for_constants, tensor.TensorKind(), shape_vector); + auto descriptor = winrt::make( + input_name, no_description_for_constants, tensor.TensorKind(), shape_vector + ); return AddInput(descriptor, value, true); } WINML_THROW_HR(E_UNEXPECTED); } -} // namespace WINML_EXPERIMENTALP \ No newline at end of file +} // namespace WINML_EXPERIMENTALP diff --git a/winml/lib/Api.Experimental/LearningModelInputs.h b/winml/lib/Api.Experimental/LearningModelInputs.h index e6f4442eba3a7..80138d55fe9f4 100644 --- a/winml/lib/Api.Experimental/LearningModelInputs.h +++ b/winml/lib/Api.Experimental/LearningModelInputs.h @@ -9,9 +9,17 @@ struct LearningModelInputs : LearningModelInputsT { LearningModelInputs(winml_experimental::LearningModelBuilder builder); winml_experimental::LearningModelBuilder Add(winml::ILearningModelFeatureDescriptor const& input); - winml_experimental::LearningModelBuilder Add(hstring const& input_name, hstring const& input_description, Windows::Foundation::IInspectable const& default_value); - winml_experimental::LearningModelBuilder AddConstant(hstring const& input_name, Windows::Foundation::IInspectable const& value); - winml_experimental::LearningModelBuilder AddInput(winml::ILearningModelFeatureDescriptor const& input, Windows::Foundation::IInspectable const& default_value, bool is_constant); + winml_experimental::LearningModelBuilder Add( + hstring const& input_name, hstring const& input_description, Windows::Foundation::IInspectable const& default_value + ); + winml_experimental::LearningModelBuilder AddConstant( + hstring const& input_name, Windows::Foundation::IInspectable const& value + ); + winml_experimental::LearningModelBuilder AddInput( + winml::ILearningModelFeatureDescriptor const& input, + Windows::Foundation::IInspectable const& default_value, + bool is_constant + ); private: wfc::IVector input_descriptors_; @@ -20,4 +28,4 @@ struct LearningModelInputs : LearningModelInputsT { wfc::IVector constant_values_; winml_experimental::LearningModelBuilder builder_; }; -} // namespace WINML_EXPERIMENTALP \ No newline at end of file +} // namespace WINML_EXPERIMENTALP diff --git a/winml/lib/Api.Experimental/LearningModelJoinOptions.cpp b/winml/lib/Api.Experimental/LearningModelJoinOptions.cpp index a781f79a52aa5..bf6c65482530e 100644 --- a/winml/lib/Api.Experimental/LearningModelJoinOptions.cpp +++ b/winml/lib/Api.Experimental/LearningModelJoinOptions.cpp @@ -3,8 +3,7 @@ namespace WINML_EXPERIMENTALP { -LearningModelJoinOptions::LearningModelJoinOptions() -{ +LearningModelJoinOptions::LearningModelJoinOptions() { GUID guid; WINML_THROW_IF_FAILED(CoCreateGuid(&guid)); @@ -16,36 +15,29 @@ LearningModelJoinOptions::LearningModelJoinOptions() ::CoTaskMemFree(guidString); } -bool LearningModelJoinOptions::PromoteUnlinkedOutputsToFusedOutputs() -{ - return promote_unlinked_outputs_; +bool LearningModelJoinOptions::PromoteUnlinkedOutputsToFusedOutputs() { + return promote_unlinked_outputs_; } -void LearningModelJoinOptions::PromoteUnlinkedOutputsToFusedOutputs(bool value) -{ - promote_unlinked_outputs_ = value; +void LearningModelJoinOptions::PromoteUnlinkedOutputsToFusedOutputs(bool value) { + promote_unlinked_outputs_ = value; } -winrt::hstring LearningModelJoinOptions::JoinedNodePrefix() -{ +winrt::hstring LearningModelJoinOptions::JoinedNodePrefix() { return winrt::to_hstring(join_prefix_); } -void LearningModelJoinOptions::JoinedNodePrefix(hstring const& join_prefix) -{ +void LearningModelJoinOptions::JoinedNodePrefix(hstring const& join_prefix) { join_prefix_ = winrt::to_string(join_prefix); } -bool LearningModelJoinOptions::CloseModelOnJoin() -{ - return close_model_on_link_; +bool LearningModelJoinOptions::CloseModelOnJoin() { + return close_model_on_link_; } -void LearningModelJoinOptions::CloseModelOnJoin(bool value) -{ - close_model_on_link_ = value; +void LearningModelJoinOptions::CloseModelOnJoin(bool value) { + close_model_on_link_ = value; } -void LearningModelJoinOptions::Link(hstring const& firstModelOutput, hstring const& secondModelInput) -{ - linkages_[winrt::to_string(firstModelOutput)] = winrt::to_string(secondModelInput); +void LearningModelJoinOptions::Link(hstring const& firstModelOutput, hstring const& secondModelInput) { + linkages_[winrt::to_string(firstModelOutput)] = winrt::to_string(secondModelInput); } const std::unordered_map& LearningModelJoinOptions::GetLinkages() { - return linkages_; + return linkages_; } -} +} // namespace WINML_EXPERIMENTALP diff --git a/winml/lib/Api.Experimental/LearningModelJoinOptions.h b/winml/lib/Api.Experimental/LearningModelJoinOptions.h index ba675316ce17f..be8efbb4e35af 100644 --- a/winml/lib/Api.Experimental/LearningModelJoinOptions.h +++ b/winml/lib/Api.Experimental/LearningModelJoinOptions.h @@ -3,37 +3,34 @@ namespace WINML_EXPERIMENTALP { -struct LearningModelJoinOptions : LearningModelJoinOptionsT -{ - LearningModelJoinOptions(); - - bool PromoteUnlinkedOutputsToFusedOutputs(); - void PromoteUnlinkedOutputsToFusedOutputs(bool value); - winrt::hstring JoinedNodePrefix(); - void JoinedNodePrefix(hstring const& join_prefix); - - bool CloseModelOnJoin(); - void CloseModelOnJoin(bool value); - void Link(hstring const& firstModelOutput, hstring const& secondModelInput); - -public: - const std::unordered_map& GetLinkages(); - -private: - bool promote_unlinked_outputs_ = true; - bool promote_unlinked_inputs_ = true; - bool close_model_on_link_ = false; - - std::unordered_map linkages_; - std::string join_prefix_; +struct LearningModelJoinOptions : LearningModelJoinOptionsT { + LearningModelJoinOptions(); + bool PromoteUnlinkedOutputsToFusedOutputs(); + void PromoteUnlinkedOutputsToFusedOutputs(bool value); + winrt::hstring JoinedNodePrefix(); + void JoinedNodePrefix(hstring const& join_prefix); + + bool CloseModelOnJoin(); + void CloseModelOnJoin(bool value); + void Link(hstring const& firstModelOutput, hstring const& secondModelInput); + + public: + const std::unordered_map& GetLinkages(); + + private: + bool promote_unlinked_outputs_ = true; + bool promote_unlinked_inputs_ = true; + bool close_model_on_link_ = false; + + std::unordered_map linkages_; + std::string join_prefix_; }; } // namespace WINML_EXPERIMENTALP namespace WINML_EXPERIMENTAL::factory_implementation { -struct LearningModelJoinOptions : LearningModelJoinOptionsT -{ -}; +struct LearningModelJoinOptions + : LearningModelJoinOptionsT {}; -} +} // namespace WINML_EXPERIMENTAL::factory_implementation diff --git a/winml/lib/Api.Experimental/LearningModelOperator.cpp b/winml/lib/Api.Experimental/LearningModelOperator.cpp index 4c18b55db3426..e345252ff167d 100644 --- a/winml/lib/Api.Experimental/LearningModelOperator.cpp +++ b/winml/lib/Api.Experimental/LearningModelOperator.cpp @@ -5,12 +5,11 @@ namespace WINML_EXPERIMENTALP { static uint32_t c_operator_index = 0; -LearningModelOperator::LearningModelOperator(hstring const& type) : - LearningModelOperator(type, L"") -{} +LearningModelOperator::LearningModelOperator(hstring const& type) : LearningModelOperator(type, L"") { +} -LearningModelOperator::LearningModelOperator(hstring const& type, hstring const& domain) : - domain_(domain), +LearningModelOperator::LearningModelOperator(hstring const& type, hstring const& domain) + : domain_(domain), type_(type) { constant_input_mapping_ = winrt::single_threaded_map(); input_mapping_ = winrt::single_threaded_map(); @@ -32,15 +31,16 @@ winml_experimental::LearningModelOperator LearningModelOperator::SetName(hstring } winml_experimental::LearningModelOperator LearningModelOperator::SetInput( - hstring const& operator_input_name, hstring const& input_name) { - + hstring const& operator_input_name, hstring const& input_name +) { // TODO Validate against allowed operator input NAMES. The types are not deduced. input_mapping_.Insert(operator_input_name, input_name); return *this; } winml_experimental::LearningModelOperator LearningModelOperator::SetConstant( - hstring const& operator_input_name, wf::IInspectable const& value) { + hstring const& operator_input_name, wf::IInspectable const& value +) { // TODO Validate against allowed operator input NAMES. The types are not deduced. auto constant_name = name_ + L"." + operator_input_name; input_mapping_.Insert(operator_input_name, constant_name); @@ -49,14 +49,16 @@ winml_experimental::LearningModelOperator LearningModelOperator::SetConstant( } winml_experimental::LearningModelOperator LearningModelOperator::SetOutput( - hstring const& operator_output_name, hstring const& output_name) { + hstring const& operator_output_name, hstring const& output_name +) { // TODO Validate against allowed operator output NAMES. The types are not deduced. output_mapping_.Insert(operator_output_name, output_name); return *this; } winml_experimental::LearningModelOperator LearningModelOperator::SetAttribute( - hstring const& name, Windows::Foundation::IInspectable const& value) { + hstring const& name, Windows::Foundation::IInspectable const& value +) { attribute_values_.Insert(name, value); return *this; } @@ -73,7 +75,7 @@ hstring LearningModelOperator::Domain() { return domain_; } -wfc::IMap LearningModelOperator::InputMapping(){ +wfc::IMap LearningModelOperator::InputMapping() { return input_mapping_; } @@ -89,4 +91,4 @@ wfc::IMap LearningModelOperator::AttributeMap( return attribute_values_; } -} // namespace WINML_EXPERIMENTALP \ No newline at end of file +} // namespace WINML_EXPERIMENTALP diff --git a/winml/lib/Api.Experimental/LearningModelOperator.h b/winml/lib/Api.Experimental/LearningModelOperator.h index 69d2b5aa98615..411cf619535ab 100644 --- a/winml/lib/Api.Experimental/LearningModelOperator.h +++ b/winml/lib/Api.Experimental/LearningModelOperator.h @@ -8,43 +8,42 @@ namespace WINML_EXPERIMENTALP { -struct LearningModelOperator : LearningModelOperatorT -{ - LearningModelOperator() = delete; - LearningModelOperator(hstring const& type); - LearningModelOperator(hstring const& type, hstring const& domain); - - winml_experimental::LearningModelOperator SetName(hstring const& name); - winml_experimental::LearningModelOperator SetInput(hstring const& operator_input_name, hstring const& input_name); - winml_experimental::LearningModelOperator SetConstant(hstring const& operator_input_name, wf::IInspectable const& value); - winml_experimental::LearningModelOperator SetOutput(hstring const& operator_output_name, hstring const& output_name); - winml_experimental::LearningModelOperator SetAttribute(hstring const& name, wf::IInspectable const& value); - hstring Name(); - hstring Type(); - hstring Domain(); - - wfc::IMap InputMapping(); - wfc::IMap ConstantInputMapping(); - wfc::IMap OutputMapping(); - wfc::IMap AttributeMap(); - -private: - winrt::hstring name_; - winrt::hstring domain_; - winrt::hstring type_; - - wfc::IMap attribute_values_; - wfc::IMap constant_input_mapping_; - wfc::IMap input_mapping_; - wfc::IMap output_mapping_; +struct LearningModelOperator : LearningModelOperatorT { + LearningModelOperator() = delete; + LearningModelOperator(hstring const& type); + LearningModelOperator(hstring const& type, hstring const& domain); + + winml_experimental::LearningModelOperator SetName(hstring const& name); + winml_experimental::LearningModelOperator SetInput(hstring const& operator_input_name, hstring const& input_name); + winml_experimental::LearningModelOperator SetConstant( + hstring const& operator_input_name, wf::IInspectable const& value + ); + winml_experimental::LearningModelOperator SetOutput(hstring const& operator_output_name, hstring const& output_name); + winml_experimental::LearningModelOperator SetAttribute(hstring const& name, wf::IInspectable const& value); + hstring Name(); + hstring Type(); + hstring Domain(); + + wfc::IMap InputMapping(); + wfc::IMap ConstantInputMapping(); + wfc::IMap OutputMapping(); + wfc::IMap AttributeMap(); + + private: + winrt::hstring name_; + winrt::hstring domain_; + winrt::hstring type_; + + wfc::IMap attribute_values_; + wfc::IMap constant_input_mapping_; + wfc::IMap input_mapping_; + wfc::IMap output_mapping_; }; -} // namespace WINML_EXPERIMENTALP +} // namespace WINML_EXPERIMENTALP namespace WINML_EXPERIMENTAL::factory_implementation { -struct LearningModelOperator : LearningModelOperatorT -{ -}; +struct LearningModelOperator : LearningModelOperatorT {}; -} +} // namespace WINML_EXPERIMENTAL::factory_implementation diff --git a/winml/lib/Api.Experimental/LearningModelOperatorSet.cpp b/winml/lib/Api.Experimental/LearningModelOperatorSet.cpp index d47ae730a0cf5..0c8a4cc9c00cc 100644 --- a/winml/lib/Api.Experimental/LearningModelOperatorSet.cpp +++ b/winml/lib/Api.Experimental/LearningModelOperatorSet.cpp @@ -6,14 +6,14 @@ namespace WINML_EXPERIMENTALP { -LearningModelOperatorSet::LearningModelOperatorSet(winml_experimental::LearningModelBuilder builder) : - builder_(builder), - operators_(winrt::single_threaded_vector()) -{ +LearningModelOperatorSet::LearningModelOperatorSet(winml_experimental::LearningModelBuilder builder) + : builder_(builder), + operators_(winrt::single_threaded_vector()) { } -winml_experimental::LearningModelBuilder LearningModelOperatorSet::Add(winml_experimental::LearningModelOperator const& op) -{ +winml_experimental::LearningModelBuilder LearningModelOperatorSet::Add( + winml_experimental::LearningModelOperator const& op +) { auto operator_private = op.as(); auto constant_input_map = operator_private->ConstantInputMapping(); auto input_map = operator_private->InputMapping(); @@ -52,11 +52,11 @@ winml_experimental::LearningModelBuilder LearningModelOperatorSet::Add(winml_exp // Create the Binding Context to pass to the feature value _winml::BindingContext context{ - _winml::BindingType::kInput, - builder_.as()->InertSession(), - nullptr, - nullptr, - {} // SubresourceId is set by callee + _winml::BindingType::kInput, + builder_.as()->InertSession(), + nullptr, + nullptr, + {} // SubresourceId is set by callee }; std::vector attribute_names(attribute_map.Size()); @@ -76,12 +76,19 @@ winml_experimental::LearningModelBuilder LearningModelOperatorSet::Add(winml_exp auto builder = builder_.as(); WINML_THROW_IF_FAILED(builder->UseModel()->AddOperator( - operator_type.c_str(), - operator_name.c_str(), - operator_domain.c_str(), - raw_operator_input_names.data(), raw_actual_input_names.data(), input_map.Size(), - raw_operator_output_names.data(), raw_actual_output_names.data(), output_map.Size(), - raw_attribute_names.data(), raw_attribute_values.data(), attribute_map.Size())); + operator_type.c_str(), + operator_name.c_str(), + operator_domain.c_str(), + raw_operator_input_names.data(), + raw_actual_input_names.data(), + input_map.Size(), + raw_operator_output_names.data(), + raw_actual_output_names.data(), + output_map.Size(), + raw_attribute_names.data(), + raw_attribute_values.data(), + attribute_map.Size() + )); // Add constants for (auto kvp : constant_input_map) { @@ -91,4 +98,4 @@ winml_experimental::LearningModelBuilder LearningModelOperatorSet::Add(winml_exp return builder_; } -} +} // namespace WINML_EXPERIMENTALP diff --git a/winml/lib/Api.Experimental/LearningModelOperatorSet.h b/winml/lib/Api.Experimental/LearningModelOperatorSet.h index 8e6d842fb0b31..1c8332d67ee12 100644 --- a/winml/lib/Api.Experimental/LearningModelOperatorSet.h +++ b/winml/lib/Api.Experimental/LearningModelOperatorSet.h @@ -4,14 +4,13 @@ namespace WINML_EXPERIMENTALP { - struct LearningModelOperatorSet : LearningModelOperatorSetT - { - LearningModelOperatorSet(winml_experimental::LearningModelBuilder builder); +struct LearningModelOperatorSet : LearningModelOperatorSetT { + LearningModelOperatorSet(winml_experimental::LearningModelBuilder builder); - winml_experimental::LearningModelBuilder Add(winml_experimental::LearningModelOperator const& op); + winml_experimental::LearningModelBuilder Add(winml_experimental::LearningModelOperator const& op); - private: - winml_experimental::LearningModelBuilder builder_; - wfc::IVector operators_; - }; -} + private: + winml_experimental::LearningModelBuilder builder_; + wfc::IVector operators_; +}; +} // namespace WINML_EXPERIMENTALP diff --git a/winml/lib/Api.Experimental/LearningModelOutputs.cpp b/winml/lib/Api.Experimental/LearningModelOutputs.cpp index 27738987785b0..2c799b0e584ac 100644 --- a/winml/lib/Api.Experimental/LearningModelOutputs.cpp +++ b/winml/lib/Api.Experimental/LearningModelOutputs.cpp @@ -3,16 +3,15 @@ #include "LearningModelBuilder.h" #include "TensorFeatureDescriptor.h" -namespace WINML_EXPERIMENTALP -{ +namespace WINML_EXPERIMENTALP { -LearningModelOutputs::LearningModelOutputs(winml_experimental::LearningModelBuilder builder) : - output_descriptors_(winrt::single_threaded_vector()), +LearningModelOutputs::LearningModelOutputs(winml_experimental::LearningModelBuilder builder) + : output_descriptors_(winrt::single_threaded_vector()), builder_(builder) { } -winml_experimental::LearningModelBuilder LearningModelOutputs::Add(winml::ILearningModelFeatureDescriptor const& output) -{ +winml_experimental::LearningModelBuilder LearningModelOutputs::Add(winml::ILearningModelFeatureDescriptor const& output +) { // Perform model update inside the builder auto model = builder_.as()->UseModel(); auto descriptor_provider = output.as<_winml::IDescriptorInfoProvider>(); @@ -22,4 +21,4 @@ winml_experimental::LearningModelBuilder LearningModelOutputs::Add(winml::ILearn return builder_; } -} // namespace WINML_EXPERIMENTALP +} // namespace WINML_EXPERIMENTALP diff --git a/winml/lib/Api.Experimental/LearningModelOutputs.h b/winml/lib/Api.Experimental/LearningModelOutputs.h index c0d99a4412963..2841477df283e 100644 --- a/winml/lib/Api.Experimental/LearningModelOutputs.h +++ b/winml/lib/Api.Experimental/LearningModelOutputs.h @@ -4,16 +4,14 @@ namespace WINML_EXPERIMENTALP { -struct LearningModelOutputs : LearningModelOutputsT -{ - LearningModelOutputs(winml_experimental::LearningModelBuilder builder); +struct LearningModelOutputs : LearningModelOutputsT { + LearningModelOutputs(winml_experimental::LearningModelBuilder builder); - winml_experimental::LearningModelBuilder Add(winml::ILearningModelFeatureDescriptor const& output); - - private: - wfc::IVector output_descriptors_; - winml_experimental::LearningModelBuilder builder_; + winml_experimental::LearningModelBuilder Add(winml::ILearningModelFeatureDescriptor const& output); + private: + wfc::IVector output_descriptors_; + winml_experimental::LearningModelBuilder builder_; }; -} // namespace WINML_EXPERIMENTALP \ No newline at end of file +} // namespace WINML_EXPERIMENTALP diff --git a/winml/lib/Api.Experimental/LearningModelSessionExperimental.cpp b/winml/lib/Api.Experimental/LearningModelSessionExperimental.cpp index 29b017c43edca..3841d11cb6a74 100644 --- a/winml/lib/Api.Experimental/LearningModelSessionExperimental.cpp +++ b/winml/lib/Api.Experimental/LearningModelSessionExperimental.cpp @@ -5,12 +5,12 @@ namespace WINML_EXPERIMENTALP { -LearningModelSessionExperimental::LearningModelSessionExperimental(const winml::LearningModelSession& session) : - _session(session) { +LearningModelSessionExperimental::LearningModelSessionExperimental(const winml::LearningModelSession& session) + : _session(session) { } WINML_EXPERIMENTAL::LearningModelSessionOptionsExperimental LearningModelSessionExperimental::Options() { return winrt::make(_session); } -} // namespace WINML_EXPERIMENTALP \ No newline at end of file +} // namespace WINML_EXPERIMENTALP diff --git a/winml/lib/Api.Experimental/LearningModelSessionExperimental.h b/winml/lib/Api.Experimental/LearningModelSessionExperimental.h index ed09177fe28ae..a07272065cca9 100644 --- a/winml/lib/Api.Experimental/LearningModelSessionExperimental.h +++ b/winml/lib/Api.Experimental/LearningModelSessionExperimental.h @@ -9,7 +9,7 @@ struct LearningModelSessionExperimental : LearningModelSessionExperimentalT { -}; +struct LearningModelSessionExperimental : LearningModelSessionExperimentalT< + LearningModelSessionExperimental, + implementation::LearningModelSessionExperimental> {}; -} // namespace WINML_EXPERIMENTAL::factory_implementation \ No newline at end of file +} // namespace WINML_EXPERIMENTAL::factory_implementation diff --git a/winml/lib/Api.Experimental/LearningModelSessionOptionsExperimental.cpp b/winml/lib/Api.Experimental/LearningModelSessionOptionsExperimental.cpp index ee59e5b7a456e..14602448ac3d8 100644 --- a/winml/lib/Api.Experimental/LearningModelSessionOptionsExperimental.cpp +++ b/winml/lib/Api.Experimental/LearningModelSessionOptionsExperimental.cpp @@ -2,19 +2,36 @@ #include "LearningModelSessionOptionsExperimental.h" #include "winrt/Windows.Foundation.Collections.h" #include "LearningModelSession.h" +#include "LearningModelSessionOptions.h" #include "iengine.h" namespace WINML_EXPERIMENTALP { -LearningModelSessionOptionsExperimental::LearningModelSessionOptionsExperimental(const winml::LearningModelSession& session) { +LearningModelSessionOptionsExperimental::LearningModelSessionOptionsExperimental( + const winml::LearningModelSessionOptions& options +) + : options_(options) { +} + +LearningModelSessionOptionsExperimental::LearningModelSessionOptionsExperimental( + const winml::LearningModelSession& session +) + : options_(nullptr) { com_ptr session_impl = session.as(); + options_ = session_impl->Options(); + _winml::IEngine* engine = session_impl->GetEngine(); engine->GetNamedDimensionOverrides(overrides_); } wfc::IMapView LearningModelSessionOptionsExperimental::GetNamedDimensionOverrides() { telemetry_helper.LogApiUsage("LearningModelSessionOptionsExperimental::GetNamedDimensionOverrides"); - return overrides_; } -} // namespace WINML_EXPERIMENTALP \ No newline at end of file +void LearningModelSessionOptionsExperimental::RegisterCustomOpsLibrary(const hstring& path) { + telemetry_helper.LogApiUsage("LearningModelSessionOptionsExperimental::RegisterCustomOpsLibrary"); + com_ptr options_impl = options_.as(); + options_impl->RegisterCustomOpsLibrary(path); +} + +} // namespace WINML_EXPERIMENTALP diff --git a/winml/lib/Api.Experimental/LearningModelSessionOptionsExperimental.h b/winml/lib/Api.Experimental/LearningModelSessionOptionsExperimental.h index abeeb909fa8b4..299aa44df7145 100644 --- a/winml/lib/Api.Experimental/LearningModelSessionOptionsExperimental.h +++ b/winml/lib/Api.Experimental/LearningModelSessionOptionsExperimental.h @@ -4,14 +4,25 @@ namespace WINML_EXPERIMENTALP { -struct LearningModelSessionOptionsExperimental : LearningModelSessionOptionsExperimentalT -{ - LearningModelSessionOptionsExperimental(const winml::LearningModelSession& options); +struct LearningModelSessionOptionsExperimental + : LearningModelSessionOptionsExperimentalT { + LearningModelSessionOptionsExperimental(const winml::LearningModelSessionOptions& options); + LearningModelSessionOptionsExperimental(const winml::LearningModelSession& session); wfc::IMapView GetNamedDimensionOverrides(); + void RegisterCustomOpsLibrary(const hstring& path); private: wfc::IMapView overrides_; + winml::LearningModelSessionOptions options_; }; } // namespace WINML_EXPERIMENTALP + +namespace WINML_EXPERIMENTAL::factory_implementation { + +struct LearningModelSessionOptionsExperimental : LearningModelSessionOptionsExperimentalT< + LearningModelSessionOptionsExperimental, + implementation::LearningModelSessionOptionsExperimental> {}; + +} // namespace WINML_EXPERIMENTAL::factory_implementation diff --git a/winml/lib/Api.Experimental/pch/pch.h b/winml/lib/Api.Experimental/pch/pch.h index d5d2f48c76787..8c09085a993b5 100644 --- a/winml/lib/Api.Experimental/pch/pch.h +++ b/winml/lib/Api.Experimental/pch/pch.h @@ -13,4 +13,4 @@ #include "cppwinrt_onnx.h" #include "dx.h" -#pragma warning(pop) \ No newline at end of file +#pragma warning(pop) diff --git a/winml/lib/Api.Image/ConverterResourceStore.cpp b/winml/lib/Api.Image/ConverterResourceStore.cpp index 1c0f13797b8e4..ce49f6d0be8bb 100644 --- a/winml/lib/Api.Image/ConverterResourceStore.cpp +++ b/winml/lib/Api.Image/ConverterResourceStore.cpp @@ -12,10 +12,11 @@ using namespace _winml; -ConverterResources::ConverterResources(Pool& pool, ConverterResourceDescription& descriptor) : Descriptor(descriptor), - Tensorizer(std::make_unique()), - Detensorizer(std::make_unique()), - m_pool(pool) { +ConverterResources::ConverterResources(Pool& pool, ConverterResourceDescription& descriptor) + : Descriptor(descriptor), + Tensorizer(std::make_unique()), + Detensorizer(std::make_unique()), + m_pool(pool) { } void ConverterResources::ReturnToCache() { @@ -42,11 +43,9 @@ std::shared_ptr ConverterResourceStore::Fetch(ConverterResou std::shared_ptr ConverterResourceStore::FetchAndRemoveObject(ConverterResourceDescription& desc) { // Iterate through the resources and find all the resources which are completed and unallocate - auto foundIt = - std::find_if(std::begin(m_objects), std::end(m_objects), - [&](const auto& cachedObject) { - return desc == cachedObject.Resource->Descriptor; - }); + auto foundIt = std::find_if(std::begin(m_objects), std::end(m_objects), [&](const auto& cachedObject) { + return desc == cachedObject.Resource->Descriptor; + }); if (foundIt == std::end(m_objects)) { return nullptr; @@ -62,37 +61,29 @@ std::shared_ptr ConverterResourceStore::FetchAndRemoveObject void ConverterResourceStore::Store(std::shared_ptr object) { std::lock_guard lock(m_mutex); - auto foundIt = std::find_if(std::begin(m_objects), std::end(m_objects), - [&](const auto& cachedObject) { - return object == cachedObject.Resource; - }); + auto foundIt = std::find_if(std::begin(m_objects), std::end(m_objects), [&](const auto& cachedObject) { + return object == cachedObject.Resource; + }); if (foundIt == std::end(m_objects)) { // If the resource is not already cached if (m_objects.size() < m_cacheSize) { // If the cache has free slots, then use one - m_objects.push_back( - PoolObject{ - object, - storeId++}); + m_objects.push_back(PoolObject{object, storeId++}); } else { // If the cache has no free slots, then evict the oldest EvictOldestPoolObject(); - m_objects.push_back( - PoolObject{ - object, - storeId++}); + m_objects.push_back(PoolObject{object, storeId++}); } } } void ConverterResourceStore::EvictOldestPoolObject() { auto oldestIt = - std::min_element(std::begin(m_objects), std::end(m_objects), - [&](const auto& left, const auto& right) { - return left.StoreId < right.StoreId; - }); + std::min_element(std::begin(m_objects), std::end(m_objects), [&](const auto& left, const auto& right) { + return left.StoreId < right.StoreId; + }); // Remove the oldest item from the cache m_objects.erase(oldestIt); diff --git a/winml/lib/Api.Image/CpuDetensorizer.h b/winml/lib/Api.Image/CpuDetensorizer.h index dc5e76ef0dc7f..dbafeed72cda8 100644 --- a/winml/lib/Api.Image/CpuDetensorizer.h +++ b/winml/lib/Api.Image/CpuDetensorizer.h @@ -12,16 +12,18 @@ class CpuDetensorizer { public: template static HRESULT Detensorize( - _In_ ImageTensorChannelType formatFrom, - _In_ ImageTensorChannelType formatTo, - _In_ winml::LearningModelPixelRange pixelRange, - _In_ T* pCPUTensor, - _In_ uint32_t bufferWidth, - _In_ uint32_t tensorHeight, - _In_ uint32_t tensorWidth, - _Inout_ BYTE* pData) { + _In_ ImageTensorChannelType formatFrom, + _In_ ImageTensorChannelType formatTo, + _In_ winml::LearningModelPixelRange pixelRange, + _In_ T* pCPUTensor, + _In_ uint32_t bufferWidth, + _In_ uint32_t tensorHeight, + _In_ uint32_t tensorWidth, + _Inout_ BYTE* pData + ) { #pragma warning(push) -#pragma warning(disable : 26014) // warning about possible out of bounds accesing pData, but input is checked for BGRA8 format, so uiCapacity should be in multiples of 4 +#pragma warning(disable : 26014 \ +) // warning about possible out of bounds accesing pData, but input is checked for BGRA8 format, so uiCapacity should be in multiples of 4 \ // output is BGRA8: so blue at i, green is at i + 1, red is at i + 2 uint32_t bytesPerPixel = formatTo == kImageTensorChannelTypeGRAY8 ? 1 : 4; @@ -39,13 +41,14 @@ class CpuDetensorizer { BYTE* pPixel = pData; InterleaveRowFloatToByte( - pCPUTensor + i * tensorWidth, - pCPUTensor + tensorPlaneSize + i * tensorWidth, - pCPUTensor + tensorPlaneSize * 2 + i * tensorWidth, - tensorWidth, - pPixel, - bytesPerPixel, - nominalRangeConverter); + pCPUTensor + i * tensorWidth, + pCPUTensor + tensorPlaneSize + i * tensorWidth, + pCPUTensor + tensorPlaneSize * 2 + i * tensorWidth, + tensorWidth, + pPixel, + bytesPerPixel, + nominalRangeConverter + ); pData += bufferWidth; } @@ -54,13 +57,14 @@ class CpuDetensorizer { BYTE* pPixel = pData; InterleaveRowFloatToByte( - pCPUTensor + tensorPlaneSize * 2 + i * tensorWidth, - pCPUTensor + tensorPlaneSize + i * tensorWidth, - pCPUTensor + i * tensorWidth, - tensorWidth, - pPixel, - bytesPerPixel, - nominalRangeConverter); + pCPUTensor + tensorPlaneSize * 2 + i * tensorWidth, + pCPUTensor + tensorPlaneSize + i * tensorWidth, + pCPUTensor + i * tensorWidth, + tensorWidth, + pPixel, + bytesPerPixel, + nominalRangeConverter + ); pData += bufferWidth; } @@ -126,10 +130,9 @@ class CpuDetensorizer { template <> static float ReadTensor( - const DirectX::PackedVector::HALF* pCPUTensor, - const NominalRangeConverter& nominalRangeConverter) { - return nominalRangeConverter.Denormalize( - DirectX::PackedVector::XMConvertHalfToFloat(*pCPUTensor)); + const DirectX::PackedVector::HALF* pCPUTensor, const NominalRangeConverter& nominalRangeConverter + ) { + return nominalRangeConverter.Denormalize(DirectX::PackedVector::XMConvertHalfToFloat(*pCPUTensor)); } template @@ -139,13 +142,14 @@ class CpuDetensorizer { template static void InterleaveRowFloatToByte( - const T* xChannel, - const T* yChannel, - const T* zChannel, - uint32_t tensorWidth, - BYTE* pData, - uint32_t bytesPerPixel, - const NominalRangeConverter& nominalRangeConverter) { + const T* xChannel, + const T* yChannel, + const T* zChannel, + uint32_t tensorWidth, + BYTE* pData, + uint32_t bytesPerPixel, + const NominalRangeConverter& nominalRangeConverter + ) { BYTE* pPixel = pData; uint32_t tensorWidthRemaining = tensorWidth; @@ -166,14 +170,14 @@ class CpuDetensorizer { #if defined(_M_AMD64) || defined(_M_IX86) template <> static void InterleaveRowFloatToByte( - const float* xChannel, - const float* yChannel, - const float* zChannel, - uint32_t tensorWidth, - BYTE* pData, - uint32_t bytesPerPixel, - const NominalRangeConverter& nominalRangeConverter - ) { + const float* xChannel, + const float* yChannel, + const float* zChannel, + uint32_t tensorWidth, + BYTE* pData, + uint32_t bytesPerPixel, + const NominalRangeConverter& nominalRangeConverter + ) { BYTE* pPixel = pData; uint32_t tensorWidthRemaining = tensorWidth; @@ -188,21 +192,24 @@ class CpuDetensorizer { while (tensorWidthRemaining >= 8) { // Load, saturate, and convert to ints, 8 - 32 bit floats from X channel __m128i vXIntsLo = _mm_cvtps_epi32(_mm_min_ps(nominalRangeConverter.Denormalize(_mm_loadu_ps(xChannel)), maxv)); - __m128i vXIntsHi = _mm_cvtps_epi32(_mm_min_ps(nominalRangeConverter.Denormalize(_mm_loadu_ps(xChannel + 4)), maxv)); + __m128i vXIntsHi = + _mm_cvtps_epi32(_mm_min_ps(nominalRangeConverter.Denormalize(_mm_loadu_ps(xChannel + 4)), maxv)); // Pack 32 bit ints into 16 bit ints __m128i vXWords = _mm_packs_epi32(vXIntsLo, vXIntsHi); // Load, saturate, and convert to ints, 8 - 32 bit floats from Y channel __m128i vYIntsLo = _mm_cvtps_epi32(_mm_min_ps(nominalRangeConverter.Denormalize(_mm_loadu_ps(yChannel)), maxv)); - __m128i vYIntsHi = _mm_cvtps_epi32(_mm_min_ps(nominalRangeConverter.Denormalize(_mm_loadu_ps(yChannel + 4)), maxv)); + __m128i vYIntsHi = + _mm_cvtps_epi32(_mm_min_ps(nominalRangeConverter.Denormalize(_mm_loadu_ps(yChannel + 4)), maxv)); // Pack 32 bit ints into 16 bit ints __m128i vYWords = _mm_packs_epi32(vYIntsLo, vYIntsHi); // Load, saturate, and convert to ints, 8 - 32 bit floats from Z channel __m128i vZIntsLo = _mm_cvtps_epi32(_mm_min_ps(nominalRangeConverter.Denormalize(_mm_loadu_ps(zChannel)), maxv)); - __m128i vZIntsHi = _mm_cvtps_epi32(_mm_min_ps(nominalRangeConverter.Denormalize(_mm_loadu_ps(zChannel + 4)), maxv)); + __m128i vZIntsHi = + _mm_cvtps_epi32(_mm_min_ps(nominalRangeConverter.Denormalize(_mm_loadu_ps(zChannel + 4)), maxv)); // Pack 32 bit ints into 16 bit ints __m128i vZWords = _mm_packs_epi32(vZIntsLo, vZIntsHi); diff --git a/winml/lib/Api.Image/CpuTensorizer.h b/winml/lib/Api.Image/CpuTensorizer.h index 27a7f2f486c08..d4e26cde7a420 100644 --- a/winml/lib/Api.Image/CpuTensorizer.h +++ b/winml/lib/Api.Image/CpuTensorizer.h @@ -12,15 +12,17 @@ class CpuTensorizer { public: template static HRESULT TensorizeData( - _In_ ImageTensorChannelType formatFrom, - _In_ ImageTensorChannelType formatTo, - _In_ winml::LearningModelPixelRange pixelRange, - _In_ BYTE* pBuffer, - _In_ UINT32 bufferWidth, - _In_ const wgi::BitmapBounds& inputBounds, - _Inout_ T* pCPUTensor) { + _In_ ImageTensorChannelType formatFrom, + _In_ ImageTensorChannelType formatTo, + _In_ winml::LearningModelPixelRange pixelRange, + _In_ BYTE* pBuffer, + _In_ UINT32 bufferWidth, + _In_ const wgi::BitmapBounds& inputBounds, + _Inout_ T* pCPUTensor + ) { #pragma warning(push) -#pragma warning(disable : 26014) // warning about possible out of bounds accesing pData, but input is checked for BGRA8 format, so uiCapacity should be in multiples of 4 +#pragma warning(disable : 26014 \ +) // warning about possible out of bounds accesing pData, but input is checked for BGRA8 format, so uiCapacity should be in multiples of 4 \ // input is BGRA8: so blue at i, green is at i + 1, red is at i + 2 uint32_t bytesPerPixel = formatFrom == kImageTensorChannelTypeGRAY8 ? 1 : 4; @@ -41,25 +43,27 @@ class CpuTensorizer { // Convert BGR8 -> BGR8 or RGB8 -> RGB8 for (uint64_t y = 0; y < yElements; y++) { DeinterleaveRowByteToFloat( - pBuffer + y * bufferWidth + start, - pCPUTensor + y * inputBounds.Width, - pCPUTensor + (inputBounds.Height * inputBounds.Width) + y * inputBounds.Width, - pCPUTensor + (inputBounds.Height * inputBounds.Width) * 2 + y * inputBounds.Width, - xElements, - bytesPerPixel, - nominalRangeConverter); + pBuffer + y * bufferWidth + start, + pCPUTensor + y * inputBounds.Width, + pCPUTensor + (inputBounds.Height * inputBounds.Width) + y * inputBounds.Width, + pCPUTensor + (inputBounds.Height * inputBounds.Width) * 2 + y * inputBounds.Width, + xElements, + bytesPerPixel, + nominalRangeConverter + ); } } else if (formatFrom == kImageTensorChannelTypeBGR8 && formatTo == kImageTensorChannelTypeRGB8 || formatFrom == kImageTensorChannelTypeRGB8 && formatTo == kImageTensorChannelTypeBGR8) { // Convert RGB8 -> BGR8 or BGR8 -> RGB8 for (uint32_t y = 0; y < yElements; y++) { DeinterleaveRowByteToFloat( - pBuffer + y * bufferWidth + start, - pCPUTensor + (inputBounds.Height * inputBounds.Width) * 2 + y * inputBounds.Width, - pCPUTensor + (inputBounds.Height * inputBounds.Width) + y * inputBounds.Width, - pCPUTensor + y * inputBounds.Width, - xElements, - bytesPerPixel, - nominalRangeConverter); + pBuffer + y * bufferWidth + start, + pCPUTensor + (inputBounds.Height * inputBounds.Width) * 2 + y * inputBounds.Width, + pCPUTensor + (inputBounds.Height * inputBounds.Width) + y * inputBounds.Width, + pCPUTensor + y * inputBounds.Width, + xElements, + bytesPerPixel, + nominalRangeConverter + ); } } else if (formatTo == kImageTensorChannelTypeGRAY8 && (formatFrom == kImageTensorChannelTypeBGR8 || formatFrom == kImageTensorChannelTypeRGB8)) { // Convert BGR8 -> GRAY8 or RGB8 -> GRAY8 @@ -81,8 +85,10 @@ class CpuTensorizer { for (UINT32 i = start; i < end; i += bufferWidth) { for (UINT32 j = i; j < i + bytesPerRow; j += bytesPerPixel) { pCPUTensor[pixelInd] = ConvertByteToFloat(pBuffer[j], nominalRangeConverter); - pCPUTensor[(inputBounds.Height * inputBounds.Width) + pixelInd] = ConvertByteToFloat(pBuffer[j], nominalRangeConverter); - pCPUTensor[(inputBounds.Height * inputBounds.Width * 2) + pixelInd] = ConvertByteToFloat(pBuffer[j], nominalRangeConverter); + pCPUTensor[(inputBounds.Height * inputBounds.Width) + pixelInd] = + ConvertByteToFloat(pBuffer[j], nominalRangeConverter); + pCPUTensor[(inputBounds.Height * inputBounds.Width * 2) + pixelInd] = + ConvertByteToFloat(pBuffer[j], nominalRangeConverter); pixelInd++; } } @@ -103,7 +109,6 @@ class CpuTensorizer { } private: - template static T ConvertByteToFloat(const BYTE& input, const NominalRangeConverter& nominalRangeConverter); @@ -112,19 +117,22 @@ class CpuTensorizer { return nominalRangeConverter.Normalize(static_cast(input)); } template <> - static DirectX::PackedVector::HALF ConvertByteToFloat(const BYTE& input, const NominalRangeConverter& nominalRangeConverter) { + static DirectX::PackedVector::HALF ConvertByteToFloat( + const BYTE& input, const NominalRangeConverter& nominalRangeConverter + ) { return nominalRangeConverter.Normalize(DirectX::PackedVector::XMConvertFloatToHalf(input)); } template static void DeinterleaveRowByteToFloat( - _In_ BYTE* pBuffer, - _Inout_ T* xChannel, - _Inout_ T* yChannel, - _Inout_ T* zChannel, - uint32_t pixelElements, - uint32_t bytesPerPixel, - const NominalRangeConverter& nominalRangeConverter) { + _In_ BYTE* pBuffer, + _Inout_ T* xChannel, + _Inout_ T* yChannel, + _Inout_ T* zChannel, + uint32_t pixelElements, + uint32_t bytesPerPixel, + const NominalRangeConverter& nominalRangeConverter + ) { UINT32 j; for (j = 0; j < (pixelElements & 0xFFFFFFFC); j += 4) { @@ -154,13 +162,14 @@ class CpuTensorizer { #if defined(_M_AMD64) || defined(_M_IX86) template <> static void DeinterleaveRowByteToFloat( - _In_ BYTE* pBuffer, - _Inout_ float* xChannel, - _Inout_ float* yChannel, - _Inout_ float* zChannel, - uint32_t pixelElements, - uint32_t bytesPerPixel, - const NominalRangeConverter& nominalRangeConverter) { + _In_ BYTE* pBuffer, + _Inout_ float* xChannel, + _Inout_ float* yChannel, + _Inout_ float* zChannel, + uint32_t pixelElements, + uint32_t bytesPerPixel, + const NominalRangeConverter& nominalRangeConverter + ) { assert(bytesPerPixel == 4); __m128i ZeroVector = _mm_setzero_si128(); diff --git a/winml/lib/Api.Image/D3DDeviceCache.cpp b/winml/lib/Api.Image/D3DDeviceCache.cpp index 9a5b9c10a2289..977f2ba75216a 100644 --- a/winml/lib/Api.Image/D3DDeviceCache.cpp +++ b/winml/lib/Api.Image/D3DDeviceCache.cpp @@ -173,7 +173,9 @@ void D3DDeviceCache::InitializeCommandQueue(ID3D12Device1* device) { D3D12_COMMAND_QUEUE_DESC queueDesc = {}; queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_DISABLE_GPU_TIMEOUT; - WINML_THROW_IF_FAILED(device->CreateCommandQueue(&queueDesc, winrt::guid_of(), command_queue_.put_void())); + WINML_THROW_IF_FAILED( + device->CreateCommandQueue(&queueDesc, winrt::guid_of(), command_queue_.put_void()) + ); // If possible get the sharing context. If not leave nullptr; command_queue_->QueryInterface(IID_PPV_ARGS(sharing_contract_.put())); @@ -210,7 +212,9 @@ void D3DDeviceCache::EnsureD3D11FromD3D12() { WINML_THROW_IF_FAILED(device_11_->QueryInterface(IID_PPV_ARGS(spDXGIDevice.put()))); // Convert to Winrt wrapper. This doesn't actually make a new device. WINML_THROW_IF_FAILED(CreateDirect3D11DeviceFromDXGIDevice(spDXGIDevice.get(), spInspectable.put())); - WINML_THROW_IF_FAILED(spInspectable->QueryInterface(winrt::guid_of(), reinterpret_cast(winrt::put_abi(winrt_device_)))); + WINML_THROW_IF_FAILED(spInspectable->QueryInterface( + winrt::guid_of(), reinterpret_cast(winrt::put_abi(winrt_device_)) + )); } void D3DDeviceCache::EnsureD3D12Fence() { @@ -249,7 +253,8 @@ void D3DDeviceCache::EnsureSharedFences() { winrt::com_ptr spD3D12DeviceChild; d3d12_fence_.as(spD3D12DeviceChild); HANDLE hSharedFence; - WINML_THROW_IF_FAILED(device_->CreateSharedHandle(spD3D12DeviceChild.get(), NULL, GENERIC_ALL, nullptr, &hSharedFence)); + WINML_THROW_IF_FAILED(device_->CreateSharedHandle(spD3D12DeviceChild.get(), NULL, GENERIC_ALL, nullptr, &hSharedFence) + ); winrt::com_ptr spD3D11Device5; device_11_.as(spD3D11Device5); @@ -335,15 +340,16 @@ ID3D12RootSignature* D3DDeviceCache::GetTensorizeRootSignature() { winrt::com_ptr signature; winrt::com_ptr error; - WINML_THROW_IF_FAILED(D3DX12SerializeVersionedRootSignature(&computeRootSignatureDesc, featureData.HighestVersion, signature.put(), error.put())); - WINML_THROW_IF_FAILED(device_->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(newRootSignature.put()))); + WINML_THROW_IF_FAILED(D3DX12SerializeVersionedRootSignature( + &computeRootSignatureDesc, featureData.HighestVersion, signature.put(), error.put() + )); + WINML_THROW_IF_FAILED(device_->CreateRootSignature( + 0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(newRootSignature.put()) + )); newRootSignature->SetName(L"Tensorize Rootsignature"); } - if (InterlockedCompareExchangePointer( - tensorize_root_signature_.put_void(), - newRootSignature.get(), - nullptr) == nullptr) { + if (InterlockedCompareExchangePointer(tensorize_root_signature_.put_void(), newRootSignature.get(), nullptr) == nullptr) { // This thread won the race and just cached the PSO newRootSignature.detach(); } @@ -376,19 +382,26 @@ ID3D12RootSignature* D3DDeviceCache::GetDetensorizeRootSignature() { rootParameters[2].InitAsDescriptorTable(1, &ranges[1], D3D12_SHADER_VISIBILITY_ALL); CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc; - rootSignatureDesc.Init_1_1(_countof(rootParameters), rootParameters, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT); + rootSignatureDesc.Init_1_1( + _countof(rootParameters), + rootParameters, + 0, + nullptr, + D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT + ); winrt::com_ptr signature; winrt::com_ptr error; - WINML_THROW_IF_FAILED(D3DX12SerializeVersionedRootSignature(&rootSignatureDesc, featureData.HighestVersion, signature.put(), error.put())); - WINML_THROW_IF_FAILED(device_->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(newRootSignature.put()))); + WINML_THROW_IF_FAILED(D3DX12SerializeVersionedRootSignature( + &rootSignatureDesc, featureData.HighestVersion, signature.put(), error.put() + )); + WINML_THROW_IF_FAILED(device_->CreateRootSignature( + 0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(newRootSignature.put()) + )); newRootSignature->SetName(L"Detensorize Rootsignature"); } - if (InterlockedCompareExchangePointer( - detensorize_root_signature_.put_void(), - newRootSignature.get(), - nullptr) == nullptr) { + if (InterlockedCompareExchangePointer(detensorize_root_signature_.put_void(), newRootSignature.get(), nullptr) == nullptr) { // This thread won the race and just cached the PSO newRootSignature.detach(); } @@ -397,7 +410,12 @@ ID3D12RootSignature* D3DDeviceCache::GetDetensorizeRootSignature() { return detensorize_root_signature_.get(); } -ID3D12PipelineState* D3DDeviceCache::GetCachedPipelineState(PipelineStateCacheType type, PipelineStateCacheFormat formatFrom, PipelineStateCacheFormat formatTo, PipelineStateCacheOperation operation) { +ID3D12PipelineState* D3DDeviceCache::GetCachedPipelineState( + PipelineStateCacheType type, + PipelineStateCacheFormat formatFrom, + PipelineStateCacheFormat formatTo, + PipelineStateCacheOperation operation +) { if (cached_pipeline_state[static_cast(type)][static_cast(formatFrom)][static_cast(formatTo)][static_cast(operation)] == nullptr) { winrt::com_ptr newPSO; if (operation == PipelineStateCacheOperation::kTensorize) { @@ -407,19 +425,29 @@ ID3D12PipelineState* D3DDeviceCache::GetCachedPipelineState(PipelineStateCacheTy } if (InterlockedCompareExchangePointer( - cached_pipeline_state[static_cast(type)][static_cast(formatFrom)][static_cast(formatTo)][static_cast(operation)].put_void(), - newPSO.get(), - nullptr) == nullptr) { + cached_pipeline_state[static_cast(type)][static_cast(formatFrom)][static_cast(formatTo)] + [static_cast(operation)] + .put_void(), + newPSO.get(), + nullptr + ) == nullptr) { // This thread won the race and just cached the PSO newPSO.detach(); } } - return cached_pipeline_state[static_cast(type)][static_cast(formatFrom)][static_cast(formatTo)][static_cast(operation)].get(); + return cached_pipeline_state[static_cast(type)][static_cast(formatFrom)][static_cast(formatTo)] + [static_cast(operation)] + .get(); } -ID3D12PipelineState* D3DDeviceCache::CreateTensorizePipelineState(PipelineStateCacheType type, PipelineStateCacheFormat formatFrom, PipelineStateCacheFormat formatTo) { - static_assert(static_cast(PipelineStateCacheFormat::kCount) == 3, "PipelineStateCacheFormat changed, update D3DDeviceCache::CreateTensorizePipelineState()"); +ID3D12PipelineState* D3DDeviceCache::CreateTensorizePipelineState( + PipelineStateCacheType type, PipelineStateCacheFormat formatFrom, PipelineStateCacheFormat formatTo +) { + static_assert( + static_cast(PipelineStateCacheFormat::kCount) == 3, + "PipelineStateCacheFormat changed, update D3DDeviceCache::CreateTensorizePipelineState()" + ); const BYTE* shaderBytecode = nullptr; uint64_t shaderBytecodeSize = 0; @@ -495,8 +523,13 @@ ID3D12PipelineState* D3DDeviceCache::CreateTensorizePipelineState(PipelineStateC return pipelineState.detach(); } -ID3D12PipelineState* D3DDeviceCache::CreateDetensorizePipelineState(PipelineStateCacheType type, PipelineStateCacheFormat formatFrom, PipelineStateCacheFormat formatTo) { - static_assert(static_cast(PipelineStateCacheFormat::kCount) == 3, "PipelineStateCacheFormat changed, update D3DDeviceCache::CreateDetensorizePipelineState()"); +ID3D12PipelineState* D3DDeviceCache::CreateDetensorizePipelineState( + PipelineStateCacheType type, PipelineStateCacheFormat formatFrom, PipelineStateCacheFormat formatTo +) { + static_assert( + static_cast(PipelineStateCacheFormat::kCount) == 3, + "PipelineStateCacheFormat changed, update D3DDeviceCache::CreateDetensorizePipelineState()" + ); const BYTE* shaderBytecode = nullptr; uint64_t shaderBytecodeSize = 0; @@ -593,25 +626,25 @@ ID3D12Resource* D3DDeviceCache::GetDetensorizeVertexBuffer(_Out_ UINT* vertexBuf winrt::com_ptr newResource; // Create the vertex buffer. // 2 triangles for full screen - DirectX::XMFLOAT3 triangleVertices[] = - { - {-1.0f, 1.0f, 0.0f}, - {1.0f, 1.0f, 0.0f}, - {-1.0f, -1.0f, 0.0f}, - {1.0f, -1.0f, 0.0f}, - }; + DirectX::XMFLOAT3 triangleVertices[] = { + {-1.0f, 1.0f, 0.0f}, + { 1.0f, 1.0f, 0.0f}, + {-1.0f, -1.0f, 0.0f}, + { 1.0f, -1.0f, 0.0f}, + }; assert(sc_vertexBufferSize == sizeof(triangleVertices)); CD3DX12_HEAP_PROPERTIES heapProp(D3D12_HEAP_TYPE_UPLOAD); D3D12_RESOURCE_DESC resourceDiscription = CD3DX12_RESOURCE_DESC::Buffer(sc_vertexBufferSize); WINML_THROW_IF_FAILED(device_->CreateCommittedResource( - &heapProp, - D3D12_HEAP_FLAG_NONE, - &resourceDiscription, - D3D12_RESOURCE_STATE_GENERIC_READ, - nullptr, - IID_PPV_ARGS(newResource.put()))); + &heapProp, + D3D12_HEAP_FLAG_NONE, + &resourceDiscription, + D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, + IID_PPV_ARGS(newResource.put()) + )); // Copy the triangle data to the vertex buffer. UINT8* pVertexDataBegin; @@ -620,10 +653,7 @@ ID3D12Resource* D3DDeviceCache::GetDetensorizeVertexBuffer(_Out_ UINT* vertexBuf memcpy(pVertexDataBegin, triangleVertices, sizeof(triangleVertices)); newResource->Unmap(0, nullptr); - if (InterlockedCompareExchangePointer( - detensorize_vertex_buffer_.put_void(), - newResource.get(), - nullptr) == nullptr) { + if (InterlockedCompareExchangePointer(detensorize_vertex_buffer_.put_void(), newResource.get(), nullptr) == nullptr) { // This thread won the race and just cached the PSO newResource.detach(); } @@ -636,10 +666,14 @@ ID3D12Resource* D3DDeviceCache::GetDetensorizeVertexBuffer(_Out_ UINT* vertexBuf HANDLE D3DDeviceCache::GetConverterFenceHandle() { // Lazily create the fence since we may never need to use it if (!converter_fence_) { - WINML_THROW_IF_FAILED(device_->CreateFence(0, D3D12_FENCE_FLAG_SHARED | D3D12_FENCE_FLAG_SHARED_CROSS_ADAPTER, IID_PPV_ARGS(converter_fence_.put()))); + WINML_THROW_IF_FAILED(device_->CreateFence( + 0, D3D12_FENCE_FLAG_SHARED | D3D12_FENCE_FLAG_SHARED_CROSS_ADAPTER, IID_PPV_ARGS(converter_fence_.put()) + )); HANDLE hSharedFence; - WINML_THROW_IF_FAILED(device_->CreateSharedHandle(converter_fence_.get(), nullptr, GENERIC_ALL, nullptr, &hSharedFence)); + WINML_THROW_IF_FAILED( + device_->CreateSharedHandle(converter_fence_.get(), nullptr, GENERIC_ALL, nullptr, &hSharedFence) + ); converter_fence_handle_ = wil::unique_handle(hSharedFence); } diff --git a/winml/lib/Api.Image/DeviceHelpers.cpp b/winml/lib/Api.Image/DeviceHelpers.cpp index 48a8d9a902975..9af7dd2849577 100644 --- a/winml/lib/Api.Image/DeviceHelpers.cpp +++ b/winml/lib/Api.Image/DeviceHelpers.cpp @@ -25,15 +25,15 @@ HRESULT IsWarpAdapter(IDXGIAdapter1* pAdapter, bool* isWarpAdapter) { return S_OK; } -HRESULT _winml::GetDXGIHardwareAdapterWithPreference(DXGI_GPU_PREFERENCE preference, _COM_Outptr_ IDXGIAdapter1** ppAdapter) { - +HRESULT +_winml::GetDXGIHardwareAdapterWithPreference(DXGI_GPU_PREFERENCE preference, _COM_Outptr_ IDXGIAdapter1** ppAdapter) { winrt::com_ptr spAdapter; UINT i = 0; // Avoids using EnumAdapterByGpuPreference for standard GPU path to enable downlevel to RS3 if (preference == DXGI_GPU_PREFERENCE::DXGI_GPU_PREFERENCE_UNSPECIFIED) { winrt::com_ptr spFactory; RETURN_IF_FAILED(CreateDXGIFactory1(IID_PPV_ARGS(spFactory.put()))); - + while (spFactory->EnumAdapters1(i, spAdapter.put()) != DXGI_ERROR_NOT_FOUND) { bool isWarpAdapter = false; RETURN_IF_FAILED(IsWarpAdapter(spAdapter.get(), &isWarpAdapter)); @@ -44,12 +44,12 @@ HRESULT _winml::GetDXGIHardwareAdapterWithPreference(DXGI_GPU_PREFERENCE prefere spAdapter = nullptr; ++i; } - } - else { + } else { winrt::com_ptr spFactory; RETURN_IF_FAILED(CreateDXGIFactory1(IID_PPV_ARGS(spFactory.put()))); - while (spFactory->EnumAdapterByGpuPreference(i, preference, IID_PPV_ARGS(spAdapter.put())) != DXGI_ERROR_NOT_FOUND) { + while (spFactory->EnumAdapterByGpuPreference(i, preference, IID_PPV_ARGS(spAdapter.put())) != DXGI_ERROR_NOT_FOUND + ) { bool isWarpAdapter = false; RETURN_IF_FAILED(IsWarpAdapter(spAdapter.get(), &isWarpAdapter)); if (!isWarpAdapter) { @@ -67,7 +67,9 @@ HRESULT _winml::GetDXGIHardwareAdapterWithPreference(DXGI_GPU_PREFERENCE prefere // Return the first adapter that matches the preference: // DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE => DXCoreAdapterProperty::IsDetachable // DXGI_GPU_PREFERENCE_MINIMUM_POWER => DXCoreAdapterProperty::IsIntegrated -HRESULT _winml::GetDXCoreHardwareAdapterWithPreference(DXGI_GPU_PREFERENCE preference, _COM_Outptr_ IDXCoreAdapter** ppAdapter) { +HRESULT _winml::GetDXCoreHardwareAdapterWithPreference( + DXGI_GPU_PREFERENCE preference, _COM_Outptr_ IDXCoreAdapter** ppAdapter +) { winrt::com_ptr spFactory; RETURN_IF_FAILED(DXCoreCreateAdapterFactory(IID_PPV_ARGS(spFactory.put()))); @@ -124,17 +126,18 @@ HRESULT _winml::GetDXCoreHardwareAdapterWithPreference(DXGI_GPU_PREFERENCE prefe HRESULT _winml::CreateD3D11On12Device(ID3D12Device* device12, ID3D11Device** device11) { return CommonDeviceHelpers::RunDelayLoadedApi( - D3D11On12CreateDevice, - device12, // pointer to d3d12 device - D3D11_CREATE_DEVICE_BGRA_SUPPORT, // required in order to interop with Direct2D - nullptr, // feature level (defaults to d3d12) - 0, // size of feature levels in bytes - nullptr, // an array of unique command queues for D3D11On12 to use - 0, // size of the command queue array - 0, // D3D12 device node to use - device11, // d3d11 device out param - nullptr, // pointer to d3d11 device context (unused) - nullptr); // pointer to the returned feature level (unused) + D3D11On12CreateDevice, + device12, // pointer to d3d12 device + D3D11_CREATE_DEVICE_BGRA_SUPPORT, // required in order to interop with Direct2D + nullptr, // feature level (defaults to d3d12) + 0, // size of feature levels in bytes + nullptr, // an array of unique command queues for D3D11On12 to use + 0, // size of the command queue array + 0, // D3D12 device node to use + device11, // d3d11 device out param + nullptr, // pointer to d3d11 device context (unused) + nullptr + ); // pointer to the returned feature level (unused) } HRESULT _winml::GetGPUPreference(winml::LearningModelDeviceKind deviceKind, DXGI_GPU_PREFERENCE* preference) noexcept { diff --git a/winml/lib/Api.Image/DisjointBufferHelpers.cpp b/winml/lib/Api.Image/DisjointBufferHelpers.cpp index 834a9c39ba6d9..8f8f7aa5fabe6 100644 --- a/winml/lib/Api.Image/DisjointBufferHelpers.cpp +++ b/winml/lib/Api.Image/DisjointBufferHelpers.cpp @@ -4,10 +4,11 @@ namespace _winml { static void LoadOrStoreDisjointBuffers( - bool should_load_buffer, - size_t num_buffers, - std::function(size_t)> get_buffer, - gsl::span& buffer_span) { + bool should_load_buffer, + size_t num_buffers, + std::function(size_t)> get_buffer, + gsl::span& buffer_span +) { auto size_in_bytes = buffer_span.size_bytes(); auto buffer = buffer_span.data(); size_t offset_in_bytes = 0; @@ -32,17 +33,15 @@ static void LoadOrStoreDisjointBuffers( } void LoadSpanFromDisjointBuffers( - size_t num_buffers, - std::function(size_t)> get_buffer, - gsl::span& buffer_span) { + size_t num_buffers, std::function(size_t)> get_buffer, gsl::span& buffer_span +) { LoadOrStoreDisjointBuffers(true /*load into the span*/, num_buffers, get_buffer, buffer_span); } void StoreSpanIntoDisjointBuffers( - size_t num_buffers, - std::function(size_t)> get_buffer, - gsl::span& buffer_span) { + size_t num_buffers, std::function(size_t)> get_buffer, gsl::span& buffer_span +) { LoadOrStoreDisjointBuffers(false /*store into buffers*/, num_buffers, get_buffer, buffer_span); } -} // namespace _winml +} // namespace _winml diff --git a/winml/lib/Api.Image/EventTimer.h b/winml/lib/Api.Image/EventTimer.h index 4bd0995c967f7..3620a7a2c0ee1 100644 --- a/winml/lib/Api.Image/EventTimer.h +++ b/winml/lib/Api.Image/EventTimer.h @@ -1,14 +1,10 @@ #include "pch.h" -class EventTimer -{ -public: - bool Start() - { +class EventTimer { + public: + bool Start() { auto now = std::chrono::high_resolution_clock::now(); - if (!_started || - std::chrono::duration_cast(now - _startTime).count() > _kDurationBetweenSendingEvents) - { + if (!_started || std::chrono::duration_cast(now - _startTime).count() > _kDurationBetweenSendingEvents) { _started = true; _startTime = std::chrono::high_resolution_clock::now(); return true; @@ -17,9 +13,9 @@ class EventTimer return false; } -private: + private: bool _started = false; std::chrono::steady_clock::time_point _startTime; - constexpr static long long _kDurationBetweenSendingEvents = 1000 * 50; // duration in (us). send an Event every 50 ms; + constexpr static long long _kDurationBetweenSendingEvents = + 1000 * 50; // duration in (us). send an Event every 50 ms; }; - diff --git a/winml/lib/Api.Image/ImageConversionHelpers.cpp b/winml/lib/Api.Image/ImageConversionHelpers.cpp index a5ebac85792c7..11434c5fffb8e 100644 --- a/winml/lib/Api.Image/ImageConversionHelpers.cpp +++ b/winml/lib/Api.Image/ImageConversionHelpers.cpp @@ -28,11 +28,12 @@ static LUID GetLUIDFromDirect3DSurface(const wgdx::Direct3D11::IDirect3DSurface& } static HRESULT GetVideoFrameInfo( - _In_ const wm::IVideoFrame& inputVideoFrame, - _Out_ DWORD& format, - _Out_ int& width, - _Out_ int& height, - _Out_ LUID& luid) { + _In_ const wm::IVideoFrame& inputVideoFrame, + _Out_ DWORD& format, + _Out_ int& width, + _Out_ int& height, + _Out_ LUID& luid +) { wgdx::Direct3D11::IDirect3DSurface spInputSurface = inputVideoFrame.Direct3DSurface(); if (spInputSurface != nullptr) { wgdx::Direct3D11::Direct3DSurfaceDescription description; @@ -56,16 +57,13 @@ static HRESULT GetVideoFrameInfo( } void _winmli::ConvertVideoFrameToVideoFrame( - _In_ const wm::IVideoFrame& inputVideoFrame, - _In_ const wgi::BitmapBounds& inputBounds, - _In_ UINT32 outputWidth, - _In_ UINT32 outputHeight, - _Inout_ wm::VideoFrame& pOutputVideoFrame) { - wgi::BitmapBounds outputBounds = { - 0, - 0, - outputWidth, - outputHeight}; + _In_ const wm::IVideoFrame& inputVideoFrame, + _In_ const wgi::BitmapBounds& inputBounds, + _In_ UINT32 outputWidth, + _In_ UINT32 outputHeight, + _Inout_ wm::VideoFrame& pOutputVideoFrame +) { + wgi::BitmapBounds outputBounds = {0, 0, outputWidth, outputHeight}; wgi::SoftwareBitmap spInputSoftwareBitmap = inputVideoFrame.SoftwareBitmap(); wgdx::Direct3D11::IDirect3DSurface spInputDirect3DSurface = inputVideoFrame.Direct3DSurface(); @@ -120,11 +118,12 @@ bool _winmli::FormatSupportedForUAV(_In_ ID3D12Device1* device, _In_ DXGI_FORMAT // 3. (mapping softwarebitmap to softwarebitmap) OR (mapping from d3dsurface to d3dsurface AND the two surfaces are on the same device) // 4. the input is already in the desired format (BGRA8/B8G8R8X8UIntNormalized) bool _winmli::NeedsVideoFrameConversion( - _In_ const wm::IVideoFrame& inputVideoFrame, - _In_ LUID outputLuid, - _In_ const wgi::BitmapBounds& inputBounds, - _In_ UINT32 outputWidth, - _In_ UINT32 outputHeight) { + _In_ const wm::IVideoFrame& inputVideoFrame, + _In_ LUID outputLuid, + _In_ const wgi::BitmapBounds& inputBounds, + _In_ UINT32 outputWidth, + _In_ UINT32 outputHeight +) { bool bNeedConversion = false; HRESULT hr = S_OK; @@ -141,14 +140,11 @@ bool _winmli::NeedsVideoFrameConversion( (inputVideoFrame == nullptr)) // Check crop { bNeedConversion = true; - } else if (luid.HighPart != outputLuid.HighPart || - luid.LowPart != outputLuid.LowPart) { + } else if (luid.HighPart != outputLuid.HighPart || luid.LowPart != outputLuid.LowPart) { bNeedConversion = true; - } else if (static_cast(width) != outputWidth || - static_cast(height) != outputHeight) { + } else if (static_cast(width) != outputWidth || static_cast(height) != outputHeight) { bNeedConversion = true; - } else if (outputLuid.HighPart != 0 || - outputLuid.LowPart != 0) { + } else if (outputLuid.HighPart != 0 || outputLuid.LowPart != 0) { if (format != (DWORD)wgdx::DirectXPixelFormat::B8G8R8X8UIntNormalized) { bNeedConversion = true; } @@ -159,22 +155,23 @@ bool _winmli::NeedsVideoFrameConversion( } TraceLoggingWrite( - winml_trace_logging_provider, - "InputVideoFrame", - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), - TraceLoggingBool(bNeedConversion, "Convert"), - TraceLoggingHexInt32(hr, "HRESULT"), - TraceLoggingInt32(width, "iWidth"), - TraceLoggingInt32(outputWidth, "oWidth"), - TraceLoggingInt32(height, "iHeight"), - TraceLoggingInt32(outputWidth, "oHeight"), - TraceLoggingHexInt64(*((ULONGLONG*)&luid), "iLuid"), - TraceLoggingHexInt64(*((ULONGLONG*)&outputLuid), "oLuid"), - TraceLoggingHexInt32(format, "iFormat"), - TraceLoggingInt32(inputBounds.X, "rX"), - TraceLoggingInt32(inputBounds.Y, "rY"), - TraceLoggingInt32(inputBounds.Width, "rW"), - TraceLoggingInt32(inputBounds.Height, "rH")); + winml_trace_logging_provider, + "InputVideoFrame", + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), + TraceLoggingBool(bNeedConversion, "Convert"), + TraceLoggingHexInt32(hr, "HRESULT"), + TraceLoggingInt32(width, "iWidth"), + TraceLoggingInt32(outputWidth, "oWidth"), + TraceLoggingInt32(height, "iHeight"), + TraceLoggingInt32(outputWidth, "oHeight"), + TraceLoggingHexInt64(*((ULONGLONG*)&luid), "iLuid"), + TraceLoggingHexInt64(*((ULONGLONG*)&outputLuid), "oLuid"), + TraceLoggingHexInt32(format, "iFormat"), + TraceLoggingInt32(inputBounds.X, "rX"), + TraceLoggingInt32(inputBounds.Y, "rY"), + TraceLoggingInt32(inputBounds.Width, "rW"), + TraceLoggingInt32(inputBounds.Height, "rH") + ); return bNeedConversion; } @@ -208,7 +205,8 @@ wgi::BitmapPixelFormat _winmli::GetBitmapPixelFormatFromChannelType(_winml::Imag } _winml::ImageTensorChannelType _winmli::GetChannelTypeFromDirect3DSurface( - const wgdx::Direct3D11::IDirect3DSurface& direct3DSurface) { + const wgdx::Direct3D11::IDirect3DSurface& direct3DSurface +) { assert(direct3DSurface != nullptr); switch (direct3DSurface.Description().Format) { @@ -256,7 +254,8 @@ DXGI_FORMAT _winmli::GetDXGIFormatFromDirectXPixelFormat(_In_ wgdx::DirectXPixel WINML_THROW_HR(E_INVALIDARG); } -wgdx::DirectXPixelFormat _winmli::GetDirectXPixelFormatFromChannelType(_In_ _winml::ImageTensorChannelType channelType) { +wgdx::DirectXPixelFormat _winmli::GetDirectXPixelFormatFromChannelType(_In_ _winml::ImageTensorChannelType channelType +) { switch (channelType) { case _winml::kImageTensorChannelTypeBGR8: return wgdx::DirectXPixelFormat::B8G8R8A8UIntNormalized; @@ -269,7 +268,9 @@ wgdx::DirectXPixelFormat _winmli::GetDirectXPixelFormatFromChannelType(_In_ _win WINML_THROW_HR(E_INVALIDARG); } -wgdx::Direct3D11::IDirect3DDevice _winmli::GetDeviceFromDirect3DSurface(const wgdx::Direct3D11::IDirect3DSurface& d3dSurface) { +wgdx::Direct3D11::IDirect3DDevice _winmli::GetDeviceFromDirect3DSurface( + const wgdx::Direct3D11::IDirect3DSurface& d3dSurface +) { assert(d3dSurface != nullptr); ComPtr spDx11Texture2D; @@ -287,8 +288,8 @@ wgdx::Direct3D11::IDirect3DDevice _winmli::GetDeviceFromDirect3DSurface(const wg wgdx::Direct3D11::IDirect3DDevice d3dDevice; WINML_THROW_IF_FAILED(spInspectable->QueryInterface( - winrt::guid_of(), - reinterpret_cast(winrt::put_abi(d3dDevice)))); + winrt::guid_of(), reinterpret_cast(winrt::put_abi(d3dDevice)) + )); return d3dDevice; } @@ -350,4 +351,4 @@ bool _winmli::VideoFramesHaveSameDevice(const wm::IVideoFrame& videoFrame1, cons } return false; -} \ No newline at end of file +} diff --git a/winml/lib/Api.Image/ImageConverter.cpp b/winml/lib/Api.Image/ImageConverter.cpp index 0ca71c82d8742..bb97f0ec7ff34 100644 --- a/winml/lib/Api.Image/ImageConverter.cpp +++ b/winml/lib/Api.Image/ImageConverter.cpp @@ -42,7 +42,9 @@ void ImageConverter::SyncD3D12ToD3D11(_In_ D3DDeviceCache& device_cache, _In_ ID } } -ComPtr ImageConverter::FetchOrCreateFenceOnDevice(_In_ D3DDeviceCache& device_cache, _In_ ID3D11Device* pD3D11Device) { +ComPtr ImageConverter::FetchOrCreateFenceOnDevice( + _In_ D3DDeviceCache& device_cache, _In_ ID3D11Device* pD3D11Device +) { assert(pD3D11Device != nullptr); ComPtr fence; @@ -52,7 +54,8 @@ ComPtr ImageConverter::FetchOrCreateFenceOnDevice(_In_ D3DDeviceCac // There's no fence on the device, so create a new one ComPtr spD3D11Device5; WINML_THROW_IF_FAILED(pD3D11Device->QueryInterface(IID_PPV_ARGS(&spD3D11Device5))); - WINML_THROW_IF_FAILED(spD3D11Device5->OpenSharedFence(device_cache.GetConverterFenceHandle(), IID_PPV_ARGS(&fence))); + WINML_THROW_IF_FAILED(spD3D11Device5->OpenSharedFence(device_cache.GetConverterFenceHandle(), IID_PPV_ARGS(&fence)) + ); // Store the fence on the device WINML_THROW_IF_FAILED(spD3D11Device5->SetPrivateDataInterface(device_cache.GetFenceGuid(), fence.Get())); @@ -66,15 +69,16 @@ void ImageConverter::ResetCommandList(_In_ D3DDeviceCache& device_cache) { assert(command_allocator_ == nullptr); WINML_THROW_IF_FAILED(device_cache.GetD3D12Device()->CreateCommandAllocator( - device_cache.GetCommandQueue()->GetDesc().Type, - IID_PPV_ARGS(command_allocator_.ReleaseAndGetAddressOf()))); + device_cache.GetCommandQueue()->GetDesc().Type, IID_PPV_ARGS(command_allocator_.ReleaseAndGetAddressOf()) + )); WINML_THROW_IF_FAILED(device_cache.GetD3D12Device()->CreateCommandList( - 0, - device_cache.GetCommandQueue()->GetDesc().Type, - command_allocator_.Get(), - pipeline_state_.Get(), - IID_PPV_ARGS(command_list_.ReleaseAndGetAddressOf()))); + 0, + device_cache.GetCommandQueue()->GetDesc().Type, + command_allocator_.Get(), + pipeline_state_.Get(), + IID_PPV_ARGS(command_list_.ReleaseAndGetAddressOf()) + )); } else { command_list_->Reset(command_allocator_.Get(), pipeline_state_.Get()); } @@ -85,19 +89,21 @@ void ImageConverter::ResetAllocator() { } ComPtr ImageConverter::CreateTextureFromUnsupportedColorFormat( - const wm::IVideoFrame& videoFrame, - const wgi::BitmapBounds& inputBounds, - const wgi::BitmapBounds& outputBounds, - wgdx::DirectXPixelFormat newFormat) { + const wm::IVideoFrame& videoFrame, + const wgi::BitmapBounds& inputBounds, + const wgi::BitmapBounds& outputBounds, + wgdx::DirectXPixelFormat newFormat +) { assert(videoFrame != nullptr); // Make sure we create the new video frame on the same device. We don't want the VideoFrame pipeline to implicitly share the texture between // 2 devices since we will need to do it ourselves anyway. auto device = _winmli::GetDeviceFromDirect3DSurface(videoFrame.Direct3DSurface()); - auto spNewVideoFrame = wm::VideoFrame::CreateAsDirect3D11SurfaceBacked(newFormat, outputBounds.Width, outputBounds.Height, device); + auto spNewVideoFrame = + wm::VideoFrame::CreateAsDirect3D11SurfaceBacked(newFormat, outputBounds.Width, outputBounds.Height, device); videoFrame.as().CopyToAsync(spNewVideoFrame, inputBounds, outputBounds).get(); - + using namespace Windows::Graphics::DirectX::Direct3D11; auto spDxgiInterfaceAccess = spNewVideoFrame.Direct3DSurface().as(); @@ -107,8 +113,9 @@ ComPtr ImageConverter::CreateTextureFromUnsupportedColorFormat( return d3d11Texture; } -void ImageConverter::CopyTextureIntoTexture(_In_ ID3D11Texture2D* pTextureFrom, - _In_ const wgi::BitmapBounds& inputBounds, _Inout_ ID3D11Texture2D* pTextureTo) { +void ImageConverter::CopyTextureIntoTexture( + _In_ ID3D11Texture2D* pTextureFrom, _In_ const wgi::BitmapBounds& inputBounds, _Inout_ ID3D11Texture2D* pTextureTo +) { assert(pTextureFrom != nullptr); assert(pTextureTo != nullptr); @@ -130,10 +137,12 @@ void ImageConverter::CopyTextureIntoTexture(_In_ ID3D11Texture2D* pTextureFrom, if (textureFromDesc.Width != textureToDesc.Width || textureFromDesc.Height != textureToDesc.Height) { // We can't copy the whole resource, so we have to use the slower CopySubresource() function - D3D11_BOX cropBox = CD3D11_BOX(inputBounds.X, inputBounds.Y, 0, inputBounds.X + inputBounds.Width, inputBounds.Y + inputBounds.Height, 1); + D3D11_BOX cropBox = CD3D11_BOX( + inputBounds.X, inputBounds.Y, 0, inputBounds.X + inputBounds.Width, inputBounds.Y + inputBounds.Height, 1 + ); spDeviceContext->CopySubresourceRegion(pTextureTo, 0, 0, 0, 0, pTextureFrom, 0, &cropBox); } else { // Use the faster CopyResource() function since both textures have the same dimensions spDeviceContext->CopyResource(pTextureTo, pTextureFrom); } -} \ No newline at end of file +} diff --git a/winml/lib/Api.Image/NominalRangeConverter.cpp b/winml/lib/Api.Image/NominalRangeConverter.cpp index 63526c3edeb68..08d25b16d3e05 100644 --- a/winml/lib/Api.Image/NominalRangeConverter.cpp +++ b/winml/lib/Api.Image/NominalRangeConverter.cpp @@ -2,62 +2,60 @@ #include "inc/NominalRangeConverter.h" namespace _winml { - NominalRangeConverter::NominalRangeConverter(winml::LearningModelPixelRange pixelRange) { - // For Normalization: the formula is input_range[min, max] / scale - shift - // For DeNormalization: the formula is (input_range[min, max] + shift) * scale - if (pixelRange == winml::LearningModelPixelRange::ZeroTo255) { - scale = 1.f; - shift = 0; - } - else if (pixelRange == winml::LearningModelPixelRange::ZeroToOne) { - scale = 255.f; - shift = 0; - } - else if (pixelRange == winml::LearningModelPixelRange::MinusOneToOne) { - scale = (255.f / 2.f); - shift = 1; - } - }; - - // [0, 255] --> [0, 255] - // [0, 255] / 255 --> [0, 1] - // [0, 255] * 2 / 255 - 1 --> [-1, 1] - float NominalRangeConverter::Normalize(float val) const { - return val / scale - shift; +NominalRangeConverter::NominalRangeConverter(winml::LearningModelPixelRange pixelRange) { + // For Normalization: the formula is input_range[min, max] / scale - shift + // For DeNormalization: the formula is (input_range[min, max] + shift) * scale + if (pixelRange == winml::LearningModelPixelRange::ZeroTo255) { + scale = 1.f; + shift = 0; + } else if (pixelRange == winml::LearningModelPixelRange::ZeroToOne) { + scale = 255.f; + shift = 0; + } else if (pixelRange == winml::LearningModelPixelRange::MinusOneToOne) { + scale = (255.f / 2.f); + shift = 1; } +}; - DirectX::PackedVector::HALF NominalRangeConverter::Normalize(DirectX::PackedVector::HALF val) const { - return static_cast(val / scale - shift); - } +// [0, 255] --> [0, 255] +// [0, 255] / 255 --> [0, 1] +// [0, 255] * 2 / 255 - 1 --> [-1, 1] +float NominalRangeConverter::Normalize(float val) const { + return val / scale - shift; +} + +DirectX::PackedVector::HALF NominalRangeConverter::Normalize(DirectX::PackedVector::HALF val) const { + return static_cast(val / scale - shift); +} #if defined(_M_AMD64) || defined(_M_IX86) - __m128 NominalRangeConverter::Normalize(__m128 sse_data) const { - __m128 sse_shift = _mm_set1_ps(static_cast(shift)); - __m128 sse_scale = _mm_set1_ps(scale); +__m128 NominalRangeConverter::Normalize(__m128 sse_data) const { + __m128 sse_shift = _mm_set1_ps(static_cast(shift)); + __m128 sse_scale = _mm_set1_ps(scale); - auto sse_dived = _mm_div_ps(sse_data, sse_scale); - return _mm_sub_ps(sse_dived, sse_shift); - } + auto sse_dived = _mm_div_ps(sse_data, sse_scale); + return _mm_sub_ps(sse_dived, sse_shift); +} #endif - // [0, 255] --> [0, 255] - // ([0, 1] + 0 ) * 255 -> [0, 1] - // ([-1, 1] + 1) * 255 / 2 --> [-1, 1] - float NominalRangeConverter::Denormalize(float val) const { - return scale * (val + shift); - } +// [0, 255] --> [0, 255] +// ([0, 1] + 0 ) * 255 -> [0, 1] +// ([-1, 1] + 1) * 255 / 2 --> [-1, 1] +float NominalRangeConverter::Denormalize(float val) const { + return scale * (val + shift); +} - DirectX::PackedVector::HALF NominalRangeConverter::Denormalize(DirectX::PackedVector::HALF val) const { - return static_cast(scale * (val + shift)); - } +DirectX::PackedVector::HALF NominalRangeConverter::Denormalize(DirectX::PackedVector::HALF val) const { + return static_cast(scale * (val + shift)); +} #if defined(_M_AMD64) || defined(_M_IX86) - __m128 NominalRangeConverter::Denormalize(__m128 sse_data) const { - __m128 sse_shift = _mm_set1_ps(static_cast(shift)); - __m128 sse_scale = _mm_set1_ps(scale); +__m128 NominalRangeConverter::Denormalize(__m128 sse_data) const { + __m128 sse_shift = _mm_set1_ps(static_cast(shift)); + __m128 sse_scale = _mm_set1_ps(scale); - auto sse_added = _mm_add_ps(sse_data, sse_shift); - return _mm_mul_ps(sse_added, sse_scale); - } + auto sse_added = _mm_add_ps(sse_data, sse_shift); + return _mm_mul_ps(sse_added, sse_scale); +} #endif -} // namespace _winml +} // namespace _winml diff --git a/winml/lib/Api.Image/TensorToVideoFrameConverter.cpp b/winml/lib/Api.Image/TensorToVideoFrameConverter.cpp index 8431bfa7f043a..2654885d6bee8 100644 --- a/winml/lib/Api.Image/TensorToVideoFrameConverter.cpp +++ b/winml/lib/Api.Image/TensorToVideoFrameConverter.cpp @@ -30,30 +30,32 @@ class GPUTensorToDX12TextureTelemetryEvent { GPUTensorToDX12TextureTelemetryEvent(const ImageTensorDescription& tensorDesc) { runtime_session_id_ = telemetry_helper.GetRuntimeSessionId(); TraceLoggingWrite( - winml_trace_logging_provider, - "GPUTensorToDX12TextureStart", - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), - TraceLoggingHexInt32(tensorDesc.channelType, "Type"), - TraceLoggingInt64(tensorDesc.sizes[2], "Height"), - TraceLoggingInt64(tensorDesc.sizes[3], "Width"), - TraceLoggingInt32(runtime_session_id_, "runtimeSessionId"), - TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), - TraceLoggingBool(true, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)); + winml_trace_logging_provider, + "GPUTensorToDX12TextureStart", + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), + TraceLoggingHexInt32(tensorDesc.channelType, "Type"), + TraceLoggingInt64(tensorDesc.sizes[2], "Height"), + TraceLoggingInt64(tensorDesc.sizes[3], "Width"), + TraceLoggingInt32(runtime_session_id_, "runtimeSessionId"), + TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), + TraceLoggingBool(true, "UTCReplace_AppSessionGuid"), + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES) + ); } ~GPUTensorToDX12TextureTelemetryEvent() { TraceLoggingWrite( - winml_trace_logging_provider, - "GPUTensorToDX12TextureStop", - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), - TraceLoggingHexInt32(S_OK, "HRESULT"), - TraceLoggingInt32(runtime_session_id_, "runtimeSessionId"), - TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), - TraceLoggingBool(true, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)); + winml_trace_logging_provider, + "GPUTensorToDX12TextureStop", + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), + TraceLoggingHexInt32(S_OK, "HRESULT"), + TraceLoggingInt32(runtime_session_id_, "runtimeSessionId"), + TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), + TraceLoggingBool(true, "UTCReplace_AppSessionGuid"), + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES) + ); } -private: + private: int runtime_session_id_; }; @@ -62,30 +64,32 @@ class ConvertGPUTensorToSoftwareBitmapTelemetryEvent { ConvertGPUTensorToSoftwareBitmapTelemetryEvent(const ImageTensorDescription& tensorDesc) { runtime_session_id_ = telemetry_helper.GetRuntimeSessionId(); TraceLoggingWrite( - winml_trace_logging_provider, - "ConvertGPUTensorToSoftwareBitmapStart", - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), - TraceLoggingHexInt32(tensorDesc.channelType, "Type"), - TraceLoggingInt64(tensorDesc.sizes[2], "Height"), - TraceLoggingInt64(tensorDesc.sizes[3], "Width"), - TraceLoggingInt32(runtime_session_id_, "runtimeSessionId"), - TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), - TraceLoggingBool(true, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)); + winml_trace_logging_provider, + "ConvertGPUTensorToSoftwareBitmapStart", + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), + TraceLoggingHexInt32(tensorDesc.channelType, "Type"), + TraceLoggingInt64(tensorDesc.sizes[2], "Height"), + TraceLoggingInt64(tensorDesc.sizes[3], "Width"), + TraceLoggingInt32(runtime_session_id_, "runtimeSessionId"), + TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), + TraceLoggingBool(true, "UTCReplace_AppSessionGuid"), + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES) + ); } ~ConvertGPUTensorToSoftwareBitmapTelemetryEvent() { TraceLoggingWrite( - winml_trace_logging_provider, - "ConvertGPUTensorToSoftwareBitmapStop", - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), - TraceLoggingHexInt32(S_OK, "HRESULT"), - TraceLoggingInt32(runtime_session_id_, "runtimeSessionId"), - TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), - TraceLoggingBool(true, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)); + winml_trace_logging_provider, + "ConvertGPUTensorToSoftwareBitmapStop", + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), + TraceLoggingHexInt32(S_OK, "HRESULT"), + TraceLoggingInt32(runtime_session_id_, "runtimeSessionId"), + TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), + TraceLoggingBool(true, "UTCReplace_AppSessionGuid"), + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES) + ); } -private: + private: int runtime_session_id_; }; @@ -94,39 +98,42 @@ class ConvertCPUTensorToVideoFrameWithSoftwareBitmapTelemetryEvent { ConvertCPUTensorToVideoFrameWithSoftwareBitmapTelemetryEvent(const ImageTensorDescription& tensorDesc) { runtime_session_id_ = telemetry_helper.GetRuntimeSessionId(); TraceLoggingWrite( - winml_trace_logging_provider, - "ConvertCPUTensorToVideoFrameWithSoftwareBitmapStart", - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), - TraceLoggingHexInt32(tensorDesc.channelType, "Type"), - TraceLoggingInt64(tensorDesc.sizes[2], "Height"), - TraceLoggingInt64(tensorDesc.sizes[3], "Width"), - TraceLoggingInt32(runtime_session_id_, "runtimeSessionId"), - TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), - TraceLoggingBool(true, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)); + winml_trace_logging_provider, + "ConvertCPUTensorToVideoFrameWithSoftwareBitmapStart", + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), + TraceLoggingHexInt32(tensorDesc.channelType, "Type"), + TraceLoggingInt64(tensorDesc.sizes[2], "Height"), + TraceLoggingInt64(tensorDesc.sizes[3], "Width"), + TraceLoggingInt32(runtime_session_id_, "runtimeSessionId"), + TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), + TraceLoggingBool(true, "UTCReplace_AppSessionGuid"), + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES) + ); } ~ConvertCPUTensorToVideoFrameWithSoftwareBitmapTelemetryEvent() { TraceLoggingWrite( - winml_trace_logging_provider, - "ConvertCPUTensorToVideoFrameWithSoftwareBitmapStop", - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), - TraceLoggingHexInt32(S_OK, "HRESULT"), - TraceLoggingInt32(runtime_session_id_, "runtimeSessionId"), - TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), - TraceLoggingBool(true, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)); + winml_trace_logging_provider, + "ConvertCPUTensorToVideoFrameWithSoftwareBitmapStop", + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), + TraceLoggingHexInt32(S_OK, "HRESULT"), + TraceLoggingInt32(runtime_session_id_, "runtimeSessionId"), + TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), + TraceLoggingBool(true, "UTCReplace_AppSessionGuid"), + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES) + ); } -private: + private: int runtime_session_id_; }; void TensorToVideoFrameConverter::DX12TensorToVideoFrame( - _In_ UINT32 batchIdx, - _In_ winml::LearningModelSession& session, - _In_ ID3D12Resource* pInputTensor, - _In_ const _winml::ImageTensorDescription& tensorDesc, - _Inout_ wm::VideoFrame& destVideoFrame) { + _In_ UINT32 batchIdx, + _In_ winml::LearningModelSession& session, + _In_ ID3D12Resource* pInputTensor, + _In_ const _winml::ImageTensorDescription& tensorDesc, + _Inout_ wm::VideoFrame& destVideoFrame +) { CWinMLAutoLock lock(&lock_); auto spDevice = session.Device().as(); @@ -136,17 +143,19 @@ void TensorToVideoFrameConverter::DX12TensorToVideoFrame( wgi::SoftwareBitmap softwareBitmap = destVideoFrame.SoftwareBitmap(); if (softwareBitmap) { - ConvertGPUTensorToSoftwareBitmap(batchIdx, pInputTensor, *pDeviceCache, tensorDesc, softwareBitmap); + ConvertGPUTensorToSoftwareBitmap(batchIdx, pInputTensor, *pDeviceCache, tensorDesc, softwareBitmap); } else if (spDestDirect3DSurface) { bool isUAVSupportedFormat = _winmli::FormatSupportedForUAV( - pDeviceCache->GetD3D12Device(), - _winmli::GetDXGIFormatFromDirectXPixelFormat(spDestDirect3DSurface.Description().Format)); + pDeviceCache->GetD3D12Device(), + _winmli::GetDXGIFormatFromDirectXPixelFormat(spDestDirect3DSurface.Description().Format) + ); // UAV support for formats is device dependent if (!isUAVSupportedFormat) { ConvertDX12TensorToUnsupportedVideoFrameFormat(batchIdx, pInputTensor, *pDeviceCache, tensorDesc, destVideoFrame); } else { - ComPtr spVideoFrameTexture = _winmli::GetTextureFromDirect3DSurface(destVideoFrame.Direct3DSurface()); + ComPtr spVideoFrameTexture = + _winmli::GetTextureFromDirect3DSurface(destVideoFrame.Direct3DSurface()); D3D11_TEXTURE2D_DESC videoFrameTextureDesc; spVideoFrameTexture->GetDesc(&videoFrameTextureDesc); @@ -160,7 +169,9 @@ void TensorToVideoFrameConverter::DX12TensorToVideoFrame( } else { D3D12_RESOURCE_DESC cachedTextureDesc = output_resource_->GetDesc(); - if (cachedTextureDesc.Width != videoFrameTextureDesc.Width || cachedTextureDesc.Height != videoFrameTextureDesc.Height || cachedTextureDesc.Format != videoFrameTextureDesc.Format) { + if (cachedTextureDesc.Width != videoFrameTextureDesc.Width || + cachedTextureDesc.Height != videoFrameTextureDesc.Height || + cachedTextureDesc.Format != videoFrameTextureDesc.Format) { // The dimensions or format don't match, so we need to re-create our texture output_resource_ = CreateShareableD3D12Texture(videoFrameTextureDesc, pDeviceCache->GetD3D12Device()); D3D11_cached_texture_ = ShareD3D12Texture(output_resource_.Get(), pDeviceCache->GetD3D11Device()); @@ -185,14 +196,23 @@ void TensorToVideoFrameConverter::DX12TensorToVideoFrame( UINT comPtrSize = static_cast(sizeof(spSharedD3D11Texture.GetAddressOf())); UINT handleSize = static_cast(sizeof(sharedHandle)); - if ((FAILED(spVideoFrameTexture->GetPrivateData(_d3d11TextureGUID, &comPtrSize, spSharedD3D11Texture.GetAddressOf())) || !spSharedD3D11Texture.Get()) || (FAILED(spVideoFrameTexture->GetPrivateData(_handleGUID, &handleSize, &sharedHandle)) || sharedHandle != shared_handle_)) { + if ((FAILED(spVideoFrameTexture->GetPrivateData( + _d3d11TextureGUID, &comPtrSize, spSharedD3D11Texture.GetAddressOf() + )) || + !spSharedD3D11Texture.Get()) || + (FAILED(spVideoFrameTexture->GetPrivateData(_handleGUID, &handleSize, &sharedHandle)) || + sharedHandle != shared_handle_)) { // Create a new shared texture that we cache on the video frame texture output_resource_ = CreateShareableD3D12Texture(videoFrameTextureDesc, pDeviceCache->GetD3D12Device()); spSharedD3D11Texture = ShareD3D12Texture(output_resource_.Get(), spTextureDevice.Get()); // Cache the shared texture on the video frame texture in order to tie their lifetime together - WINML_THROW_IF_FAILED(spVideoFrameTexture->SetPrivateDataInterface(_d3d11TextureGUID, spSharedD3D11Texture.Get())); - WINML_THROW_IF_FAILED(spVideoFrameTexture->SetPrivateData(_handleGUID, sizeof(shared_handle_), &shared_handle_)); + WINML_THROW_IF_FAILED( + spVideoFrameTexture->SetPrivateDataInterface(_d3d11TextureGUID, spSharedD3D11Texture.Get()) + ); + WINML_THROW_IF_FAILED( + spVideoFrameTexture->SetPrivateData(_handleGUID, sizeof(shared_handle_), &shared_handle_) + ); } // Detensorize @@ -212,12 +232,12 @@ void TensorToVideoFrameConverter::DX12TensorToVideoFrame( } ComPtr TensorToVideoFrameConverter::CreateShareableD3D12Texture( - const D3D11_TEXTURE2D_DESC& d3d11Desc, - ID3D12Device* d3d12Device) { - D3D12_HEAP_PROPERTIES heapProps {}; + const D3D11_TEXTURE2D_DESC& d3d11Desc, ID3D12Device* d3d12Device +) { + D3D12_HEAP_PROPERTIES heapProps{}; heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; - D3D12_RESOURCE_DESC resDesc {}; + D3D12_RESOURCE_DESC resDesc{}; resDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; resDesc.Width = d3d11Desc.Width; resDesc.Height = d3d11Desc.Height; @@ -230,36 +250,37 @@ ComPtr TensorToVideoFrameConverter::CreateShareableD3D12Texture( ComPtr d3d12Resource; WINML_THROW_IF_FAILED(d3d12Device->CreateCommittedResource( - &heapProps, - D3D12_HEAP_FLAG_SHARED, - &resDesc, - D3D12_RESOURCE_STATE_COPY_DEST, - nullptr, - IID_PPV_ARGS(&d3d12Resource))); + &heapProps, D3D12_HEAP_FLAG_SHARED, &resDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&d3d12Resource) + )); return d3d12Resource; } void TensorToVideoFrameConverter::ConvertDX12TensorToUnsupportedVideoFrameFormat( - _In_ UINT32 batchIdx, - _In_ ID3D12Resource* pInputTensor, - _In_ _winml::D3DDeviceCache& device_cache, - _In_ const ImageTensorDescription& tensorDesc, - _Inout_ wm::VideoFrame& unsupportedVideoFrame) { + _In_ UINT32 batchIdx, + _In_ ID3D12Resource* pInputTensor, + _In_ _winml::D3DDeviceCache& device_cache, + _In_ const ImageTensorDescription& tensorDesc, + _Inout_ wm::VideoFrame& unsupportedVideoFrame +) { assert(pInputTensor != nullptr); // Find the first supported format and convert to it auto supportedFormatIter = std::find_if( - _winmli::supportedWinMLFormats.begin(), - _winmli::supportedWinMLFormats.end(), - [&device_cache](DXGI_FORMAT format) { return _winmli::FormatSupportedForUAV(device_cache.GetD3D12Device(), format); }); + _winmli::supportedWinMLFormats.begin(), + _winmli::supportedWinMLFormats.end(), + [&device_cache](DXGI_FORMAT format) { + return _winmli::FormatSupportedForUAV(device_cache.GetD3D12Device(), format); + } + ); WINML_THROW_HR_IF_FALSE_MSG( - E_INVALIDARG, - supportedFormatIter != _winmli::supportedWinMLFormats.end(), - "Detensorization for this format is unsupported on the current device."); + E_INVALIDARG, + supportedFormatIter != _winmli::supportedWinMLFormats.end(), + "Detensorization for this format is unsupported on the current device." + ); - D3D11_TEXTURE2D_DESC supportedDesc {}; + D3D11_TEXTURE2D_DESC supportedDesc{}; supportedDesc.Width = unsupportedVideoFrame.Direct3DSurface().Description().Width; supportedDesc.Height = unsupportedVideoFrame.Direct3DSurface().Description().Height; supportedDesc.MipLevels = 1; @@ -269,7 +290,8 @@ void TensorToVideoFrameConverter::ConvertDX12TensorToUnsupportedVideoFrameFormat supportedDesc.SampleDesc.Quality = 0; supportedDesc.Usage = D3D11_USAGE_DEFAULT; - ComPtr unsupportedTexture = _winmli::GetTextureFromDirect3DSurface(unsupportedVideoFrame.Direct3DSurface()); + ComPtr unsupportedTexture = + _winmli::GetTextureFromDirect3DSurface(unsupportedVideoFrame.Direct3DSurface()); ComPtr d3d11Device; unsupportedTexture->GetDevice(&d3d11Device); @@ -284,7 +306,9 @@ void TensorToVideoFrameConverter::ConvertDX12TensorToUnsupportedVideoFrameFormat WINML_THROW_IF_FAILED(CreateDirect3D11SurfaceFromDXGISurface(dxgiSurface.Get(), &inspectableSurface)); wgdx::Direct3D11::IDirect3DSurface surface; - WINML_THROW_IF_FAILED(inspectableSurface->QueryInterface(winrt::guid_of(), reinterpret_cast(winrt::put_abi(surface)))); + WINML_THROW_IF_FAILED(inspectableSurface->QueryInterface( + winrt::guid_of(), reinterpret_cast(winrt::put_abi(surface)) + )); converted_video_frame_ = wm::VideoFrame::CreateWithDirect3D11Surface(surface); // Detensorize @@ -297,35 +321,37 @@ void TensorToVideoFrameConverter::ConvertDX12TensorToUnsupportedVideoFrameFormat converted_video_frame_.CopyToAsync(unsupportedVideoFrame).get(); } -ComPtr TensorToVideoFrameConverter::ShareD3D12Texture(ID3D12Resource* pResource, ID3D11Device* pDevice) -{ - assert(pResource != nullptr); - assert(pDevice != nullptr); +ComPtr TensorToVideoFrameConverter::ShareD3D12Texture( + ID3D12Resource* pResource, ID3D11Device* pDevice +) { + assert(pResource != nullptr); + assert(pDevice != nullptr); - ComPtr d3d12Device; - WINML_THROW_IF_FAILED(pResource->GetDevice(IID_PPV_ARGS(&d3d12Device))); + ComPtr d3d12Device; + WINML_THROW_IF_FAILED(pResource->GetDevice(IID_PPV_ARGS(&d3d12Device))); - HANDLE hSharedTexture; - WINML_THROW_IF_FAILED(d3d12Device->CreateSharedHandle(pResource, nullptr, GENERIC_ALL, nullptr, &hSharedTexture)); + HANDLE hSharedTexture; + WINML_THROW_IF_FAILED(d3d12Device->CreateSharedHandle(pResource, nullptr, GENERIC_ALL, nullptr, &hSharedTexture)); - ComPtr device1; - WINML_THROW_IF_FAILED(pDevice->QueryInterface(IID_PPV_ARGS(&device1))); + ComPtr device1; + WINML_THROW_IF_FAILED(pDevice->QueryInterface(IID_PPV_ARGS(&device1))); - wil::unique_handle safeHandle(hSharedTexture); + wil::unique_handle safeHandle(hSharedTexture); - ComPtr d3d11Texture; - WINML_THROW_IF_FAILED(device1->OpenSharedResource1(safeHandle.get(), IID_PPV_ARGS(&d3d11Texture))); + ComPtr d3d11Texture; + WINML_THROW_IF_FAILED(device1->OpenSharedResource1(safeHandle.get(), IID_PPV_ARGS(&d3d11Texture))); - shared_handle_ = safeHandle.get(); + shared_handle_ = safeHandle.get(); - return d3d11Texture; + return d3d11Texture; } void TensorToVideoFrameConverter::SoftwareTensorToVideoFrame( - _In_ winml::LearningModelSession& session, - _In_ BYTE* pCPUTensorToConvert, - _In_ ImageTensorDescription tensorDesc, - _Inout_ wm::VideoFrame& pDestVideoFrame) { + _In_ winml::LearningModelSession& session, + _In_ BYTE* pCPUTensorToConvert, + _In_ ImageTensorDescription tensorDesc, + _Inout_ wm::VideoFrame& pDestVideoFrame +) { CWinMLAutoLock lock(&lock_); wm::IVideoFrame spTensorFrame; UINT32 outputWidth = 0; @@ -334,12 +360,7 @@ void TensorToVideoFrameConverter::SoftwareTensorToVideoFrame( UINT32 tensorHeight = static_cast(tensorDesc.sizes[2]); UINT32 tensorWidth = static_cast(tensorDesc.sizes[3]); // create a bitmap bounds for the whole image/tensor - wgi::BitmapBounds inputBounds = - { - 0, - 0, - tensorWidth, - tensorHeight}; + wgi::BitmapBounds inputBounds = {0, 0, tensorWidth, tensorHeight}; wgi::SoftwareBitmap spOutputSoftwareBitmap = pDestVideoFrame.SoftwareBitmap(); wgdx::Direct3D11::IDirect3DSurface spOutputSurface = pDestVideoFrame.Direct3DSurface(); @@ -358,11 +379,13 @@ void TensorToVideoFrameConverter::SoftwareTensorToVideoFrame( outputHeight = description.Height; } - if (_winmli::NeedsVideoFrameConversion(pDestVideoFrame, {}, {0, 0, (UINT32)tensorWidth, (UINT32)tensorHeight}, tensorWidth, tensorHeight)) { - if (converted_video_frame_ == nullptr || - _winmli::NeedsVideoFrameConversion(converted_video_frame_, {}, {0, 0, (UINT32)tensorWidth, (UINT32)tensorHeight}, tensorWidth, tensorHeight)) { + if (_winmli::NeedsVideoFrameConversion( + pDestVideoFrame, {}, {0, 0, (UINT32)tensorWidth, (UINT32)tensorHeight}, tensorWidth, tensorHeight + )) { + if (converted_video_frame_ == nullptr || _winmli::NeedsVideoFrameConversion(converted_video_frame_, {}, {0, 0, (UINT32)tensorWidth, (UINT32)tensorHeight}, tensorWidth, tensorHeight)) { converted_video_frame_ = wm::VideoFrame::CreateWithSoftwareBitmap( - wgi::SoftwareBitmap(wgi::BitmapPixelFormat::Bgra8, tensorWidth, tensorHeight)); + wgi::SoftwareBitmap(wgi::BitmapPixelFormat::Bgra8, tensorWidth, tensorHeight) + ); } spTensorFrame = converted_video_frame_; @@ -371,27 +394,22 @@ void TensorToVideoFrameConverter::SoftwareTensorToVideoFrame( converted_video_frame_ = nullptr; } auto bitmap = spTensorFrame.SoftwareBitmap(); - ConvertCPUTensorToSoftwareBitmap( - pCPUTensorToConvert, - tensorDesc, - bitmap); + ConvertCPUTensorToSoftwareBitmap(pCPUTensorToConvert, tensorDesc, bitmap); if (converted_video_frame_) { _winmli::ConvertVideoFrameToVideoFrame( - converted_video_frame_, - inputBounds, - outputWidth, - outputHeight, - pDestVideoFrame); + converted_video_frame_, inputBounds, outputWidth, outputHeight, pDestVideoFrame + ); } } void TensorToVideoFrameConverter::ConvertGPUTensorToDX12Texture( - _In_ UINT32 batchIdx, - _In_ ID3D12Resource* pInputResource, - _In_ _winml::D3DDeviceCache& device_cache, - _In_ const ImageTensorDescription& tensorDesc, - _Inout_ ID3D12Resource* pOutputResource) { + _In_ UINT32 batchIdx, + _In_ ID3D12Resource* pInputResource, + _In_ _winml::D3DDeviceCache& device_cache, + _In_ const ImageTensorDescription& tensorDesc, + _Inout_ ID3D12Resource* pOutputResource +) { assert(pInputResource != nullptr); assert(pOutputResource != nullptr); @@ -410,26 +428,68 @@ void TensorToVideoFrameConverter::ConvertGPUTensorToDX12Texture( } WINML_THROW_HR_IF_FALSE_MSG( - E_INVALIDARG, - outputDesc.Format == DXGI_FORMAT_B8G8R8A8_UNORM || outputDesc.Format == DXGI_FORMAT_R8G8B8A8_UNORM || outputDesc.Format == DXGI_FORMAT_R8_UNORM, - "Format was output image %d. Output image format must be Bgra8, Rgba8 or Gray8.", - outputDesc.Format); + E_INVALIDARG, + outputDesc.Format == DXGI_FORMAT_B8G8R8A8_UNORM || outputDesc.Format == DXGI_FORMAT_R8G8B8A8_UNORM || + outputDesc.Format == DXGI_FORMAT_R8_UNORM, + "Format was output image %d. Output image format must be Bgra8, Rgba8 or Gray8.", + outputDesc.Format + ); // Validate input description - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, inputDesc.Height != 0, "Invalid input image height provided. Height is set to zero."); - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, inputDesc.Width != 0, "Invalid input image height provided. Height is set to zero."); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, inputDesc.Height != 0, "Invalid input image height provided. Height is set to zero." + ); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, inputDesc.Width != 0, "Invalid input image height provided. Height is set to zero." + ); // Validate output description - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, outputDesc.Height != 0, "Invalid input image height provided. Height is set to zero."); - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, outputDesc.Width != 0, "Invalid input image height provided. Height is set to zero."); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, outputDesc.Height != 0, "Invalid input image height provided. Height is set to zero." + ); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, outputDesc.Width != 0, "Invalid input image height provided. Height is set to zero." + ); // Validate Tensor description - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, tensorDesc.dataType == kImageTensorDataTypeFloat32 || tensorDesc.dataType == kImageTensorDataTypeFloat16, "Target tensor description must either be kImageTensorDataTypeFloat32, or kImageTensorDataTypeFloat16. %d was supplied.", tensorDesc.dataType); - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, tensorDesc.channelType != kImageTensorChannelTypeRGB8 || tensorDesc.sizes[1] == 3, "Target tensor description expects kImageTensorChannelTypeRGB8, but has %lld channels specified instead of 3.", tensorDesc.sizes[1]); - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, tensorDesc.channelType != kImageTensorChannelTypeBGR8 || tensorDesc.sizes[1] == 3, "Target tensor description expects kImageTensorChannelTypeBGR8, but has %lld channels specified instead of 3.", tensorDesc.sizes[1]); - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, tensorDesc.channelType != kImageTensorChannelTypeGRAY8 || tensorDesc.sizes[1] == 1, "Target tensor description expects kImageTensorChannelTypeGRAY8, but has %lld channels specified instead of 1.", tensorDesc.sizes[1]); - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, tensorDesc.sizes[2] == outputDesc.Height, "Target tensor height (%lld) does not match input height (%lu).", tensorDesc.sizes[2], outputDesc.Height); - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, tensorDesc.sizes[3] == (UINT)outputDesc.Width, "Target tensor width (%lld) does not match input width (%lu).", tensorDesc.sizes[3], (UINT)outputDesc.Width); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, + tensorDesc.dataType == kImageTensorDataTypeFloat32 || tensorDesc.dataType == kImageTensorDataTypeFloat16, + "Target tensor description must either be kImageTensorDataTypeFloat32, or kImageTensorDataTypeFloat16. %d was supplied.", + tensorDesc.dataType + ); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, + tensorDesc.channelType != kImageTensorChannelTypeRGB8 || tensorDesc.sizes[1] == 3, + "Target tensor description expects kImageTensorChannelTypeRGB8, but has %lld channels specified instead of 3.", + tensorDesc.sizes[1] + ); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, + tensorDesc.channelType != kImageTensorChannelTypeBGR8 || tensorDesc.sizes[1] == 3, + "Target tensor description expects kImageTensorChannelTypeBGR8, but has %lld channels specified instead of 3.", + tensorDesc.sizes[1] + ); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, + tensorDesc.channelType != kImageTensorChannelTypeGRAY8 || tensorDesc.sizes[1] == 1, + "Target tensor description expects kImageTensorChannelTypeGRAY8, but has %lld channels specified instead of 1.", + tensorDesc.sizes[1] + ); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, + tensorDesc.sizes[2] == outputDesc.Height, + "Target tensor height (%lld) does not match input height (%lu).", + tensorDesc.sizes[2], + outputDesc.Height + ); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, + tensorDesc.sizes[3] == (UINT)outputDesc.Width, + "Target tensor width (%lld) does not match input width (%lu).", + tensorDesc.sizes[3], + (UINT)outputDesc.Width + ); // Create descriptor heaps UINT srvUavDescriptorSize = spDx12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); @@ -438,14 +498,16 @@ void TensorToVideoFrameConverter::ConvertGPUTensorToDX12Texture( D3D12_RESOURCE_DESC outputResourceDesc = output_resource_->GetDesc(); outputResourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; - if (!UAV_resource_ || outputDesc.Format != UAV_resource_->GetDesc().Format || outputDesc.Width != UAV_resource_->GetDesc().Width || outputDesc.Height != UAV_resource_->GetDesc().Height) { + if (!UAV_resource_ || outputDesc.Format != UAV_resource_->GetDesc().Format || + outputDesc.Width != UAV_resource_->GetDesc().Width || outputDesc.Height != UAV_resource_->GetDesc().Height) { WINML_THROW_IF_FAILED(device_cache.GetD3D12Device()->CreateCommittedResource( - &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), - D3D12_HEAP_FLAG_NONE, - &outputResourceDesc, - D3D12_RESOURCE_STATE_UNORDERED_ACCESS, - nullptr, - IID_PPV_ARGS(&UAV_resource_))); + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), + D3D12_HEAP_FLAG_NONE, + &outputResourceDesc, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS, + nullptr, + IID_PPV_ARGS(&UAV_resource_) + )); } if (descriptor_heap_ == nullptr) { @@ -461,13 +523,17 @@ void TensorToVideoFrameConverter::ConvertGPUTensorToDX12Texture( // Create SRV and UAV for input and output respectively { D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = CreateSRVDescriptor(batchIdx, inputDesc, tensorDesc); - CD3DX12_CPU_DESCRIPTOR_HANDLE srvHandle(descriptor_heap_->GetCPUDescriptorHandleForHeapStart(), SrvBufferIdx, srvUavDescriptorSize); + CD3DX12_CPU_DESCRIPTOR_HANDLE srvHandle( + descriptor_heap_->GetCPUDescriptorHandleForHeapStart(), SrvBufferIdx, srvUavDescriptorSize + ); spDx12Device->CreateShaderResourceView(pInputResource, &srvDesc, srvHandle); D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; uavDesc.Format = outputResourceDesc.Format; uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D; - CD3DX12_CPU_DESCRIPTOR_HANDLE uavHandle(descriptor_heap_->GetCPUDescriptorHandleForHeapStart(), UavBufferIdx, srvUavDescriptorSize); + CD3DX12_CPU_DESCRIPTOR_HANDLE uavHandle( + descriptor_heap_->GetCPUDescriptorHandleForHeapStart(), UavBufferIdx, srvUavDescriptorSize + ); spDx12Device->CreateUnorderedAccessView(UAV_resource_.Get(), nullptr, &uavDesc, uavHandle); } @@ -483,8 +549,7 @@ void TensorToVideoFrameConverter::ConvertGPUTensorToDX12Texture( PipelineStateCacheFormat formatFrom = PipelineStateCacheFormat::kBGR8; if (tensorDesc.channelType == kImageTensorChannelTypeRGB8) { formatFrom = PipelineStateCacheFormat::kRGB8; - } else if (inputDesc.Format == DXGI_FORMAT_R8_UNORM || - tensorDesc.channelType == kImageTensorChannelTypeGRAY8) { + } else if (inputDesc.Format == DXGI_FORMAT_R8_UNORM || tensorDesc.channelType == kImageTensorChannelTypeGRAY8) { formatFrom = PipelineStateCacheFormat::kGRAY8; } @@ -497,7 +562,8 @@ void TensorToVideoFrameConverter::ConvertGPUTensorToDX12Texture( } root_signature_ = device_cache.GetDetensorizeRootSignature(); - pipeline_state_ = device_cache.GetCachedPipelineState(type, formatFrom, formatTo, PipelineStateCacheOperation::kDetensorize); + pipeline_state_ = + device_cache.GetCachedPipelineState(type, formatFrom, formatTo, PipelineStateCacheOperation::kDetensorize); ResetCommandList(device_cache); @@ -509,13 +575,16 @@ void TensorToVideoFrameConverter::ConvertGPUTensorToDX12Texture( command_list_->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); // This code currently re-uses the same decriptors each execution, which is unsafe if previous executions are in flight. - if (fence_completion_value_ > 0) - { - device_cache.WaitForFenceValue(fence_completion_value_); + if (fence_completion_value_ > 0) { + device_cache.WaitForFenceValue(fence_completion_value_); } - CD3DX12_GPU_DESCRIPTOR_HANDLE srvHandle(descriptor_heap_->GetGPUDescriptorHandleForHeapStart(), SrvBufferIdx, srvUavDescriptorSize); - CD3DX12_GPU_DESCRIPTOR_HANDLE uavHandle(descriptor_heap_->GetGPUDescriptorHandleForHeapStart(), UavBufferIdx, srvUavDescriptorSize); + CD3DX12_GPU_DESCRIPTOR_HANDLE srvHandle( + descriptor_heap_->GetGPUDescriptorHandleForHeapStart(), SrvBufferIdx, srvUavDescriptorSize + ); + CD3DX12_GPU_DESCRIPTOR_HANDLE uavHandle( + descriptor_heap_->GetGPUDescriptorHandleForHeapStart(), UavBufferIdx, srvUavDescriptorSize + ); { ConstantBufferCS constantBufferCS = {}; constantBufferCS.height = static_cast(tensorDesc.sizes[2]); @@ -528,14 +597,34 @@ void TensorToVideoFrameConverter::ConvertGPUTensorToDX12Texture( auto dispatchWidth = static_cast((tensorDesc.sizes[3] - 1) / 16 + 1); auto dispatchHeight = static_cast((tensorDesc.sizes[2] - 1) / 4 + 1); - command_list_->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(pInputResource, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE)); + command_list_->ResourceBarrier( + 1, + &CD3DX12_RESOURCE_BARRIER::Transition( + pInputResource, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE + ) + ); command_list_->Dispatch(dispatchWidth, dispatchHeight, 1); - command_list_->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(pInputResource, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS)); + command_list_->ResourceBarrier( + 1, + &CD3DX12_RESOURCE_BARRIER::Transition( + pInputResource, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS + ) + ); // Copy the UAV data to the output resource after detensorization - command_list_->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(UAV_resource_.Get(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE)); + command_list_->ResourceBarrier( + 1, + &CD3DX12_RESOURCE_BARRIER::Transition( + UAV_resource_.Get(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE + ) + ); command_list_->CopyResource(pOutputResource, UAV_resource_.Get()); - command_list_->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(UAV_resource_.Get(), D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS)); + command_list_->ResourceBarrier( + 1, + &CD3DX12_RESOURCE_BARRIER::Transition( + UAV_resource_.Get(), D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS + ) + ); WINML_THROW_IF_FAILED(command_list_->Close()); ID3D12CommandList* pComputeToGPUCLs[] = {command_list_.Get()}; @@ -545,11 +634,12 @@ void TensorToVideoFrameConverter::ConvertGPUTensorToDX12Texture( } void TensorToVideoFrameConverter::ConvertGPUTensorToSoftwareBitmap( - _In_ UINT32 batchIdx, - _In_ ID3D12Resource* pInputTensor, - _In_ _winml::D3DDeviceCache& device_cache, - _In_ const ImageTensorDescription& tensorDesc, - _Inout_ wgi::SoftwareBitmap& softwareBitmap) { + _In_ UINT32 batchIdx, + _In_ ID3D12Resource* pInputTensor, + _In_ _winml::D3DDeviceCache& device_cache, + _In_ const ImageTensorDescription& tensorDesc, + _Inout_ wgi::SoftwareBitmap& softwareBitmap +) { assert(pInputTensor != nullptr); assert(softwareBitmap != nullptr); @@ -561,25 +651,35 @@ void TensorToVideoFrameConverter::ConvertGPUTensorToSoftwareBitmap( } uint32_t tensorElementSize = tensorDesc.dataType == kImageTensorDataTypeFloat32 ? 4 : 2; - uint32_t singleVideoFramebufferSize = static_cast(tensorDesc.sizes[1] * tensorDesc.sizes[2] * tensorDesc.sizes[3] * tensorElementSize); + uint32_t singleVideoFramebufferSize = + static_cast(tensorDesc.sizes[1] * tensorDesc.sizes[2] * tensorDesc.sizes[3] * tensorElementSize); // TODO: Make an allocator for readback heaps if (!readback_heap_ || readback_heap_->GetDesc().Width < singleVideoFramebufferSize) { WINML_THROW_IF_FAILED(device_cache.GetD3D12Device()->CreateCommittedResource( - &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK), - D3D12_HEAP_FLAG_NONE, - &CD3DX12_RESOURCE_DESC::Buffer(singleVideoFramebufferSize), - D3D12_RESOURCE_STATE_COPY_DEST, - nullptr, - IID_PPV_ARGS(&readback_heap_))); + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK), + D3D12_HEAP_FLAG_NONE, + &CD3DX12_RESOURCE_DESC::Buffer(singleVideoFramebufferSize), + D3D12_RESOURCE_STATE_COPY_DEST, + nullptr, + IID_PPV_ARGS(&readback_heap_) + )); } ResetCommandList(device_cache); - auto barrier = CD3DX12_RESOURCE_BARRIER::Transition(pInputTensor, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE); + auto barrier = CD3DX12_RESOURCE_BARRIER::Transition( + pInputTensor, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE + ); command_list_->ResourceBarrier(1, &barrier); - command_list_->CopyBufferRegion(readback_heap_.Get(), 0, pInputTensor, static_cast(singleVideoFramebufferSize) * batchIdx, singleVideoFramebufferSize); + command_list_->CopyBufferRegion( + readback_heap_.Get(), + 0, + pInputTensor, + static_cast(singleVideoFramebufferSize) * batchIdx, + singleVideoFramebufferSize + ); WINML_THROW_IF_FAILED(command_list_->Close()); ID3D12CommandList* ppCommandLists[] = {command_list_.Get()}; @@ -598,26 +698,30 @@ void TensorToVideoFrameConverter::ConvertGPUTensorToSoftwareBitmap( } void TensorToVideoFrameConverter::ConvertBatchedDX12TensorToBuffers( - _In_ ID3D12Resource* input_tensor, - _In_ size_t buffer_size_in_bytes, - _In_ _winml::D3DDeviceCache& device_cache, - _Inout_ const std::vector& buffers) { + _In_ ID3D12Resource* input_tensor, + _In_ size_t buffer_size_in_bytes, + _In_ _winml::D3DDeviceCache& device_cache, + _Inout_ const std::vector& buffers +) { assert(input_tensor != nullptr); // TODO: Make an allocator for readback heaps if (!readback_heap_ || readback_heap_->GetDesc().Width < buffer_size_in_bytes) { WINML_THROW_IF_FAILED(device_cache.GetD3D12Device()->CreateCommittedResource( - &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK), - D3D12_HEAP_FLAG_NONE, - &CD3DX12_RESOURCE_DESC::Buffer(buffer_size_in_bytes), - D3D12_RESOURCE_STATE_COPY_DEST, - nullptr, - IID_PPV_ARGS(&readback_heap_))); + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK), + D3D12_HEAP_FLAG_NONE, + &CD3DX12_RESOURCE_DESC::Buffer(buffer_size_in_bytes), + D3D12_RESOURCE_STATE_COPY_DEST, + nullptr, + IID_PPV_ARGS(&readback_heap_) + )); } ResetCommandList(device_cache); - auto barrier = CD3DX12_RESOURCE_BARRIER::Transition(input_tensor, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE); + auto barrier = CD3DX12_RESOURCE_BARRIER::Transition( + input_tensor, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE + ); command_list_->ResourceBarrier(1, &barrier); command_list_->CopyBufferRegion(readback_heap_.Get(), 0, input_tensor, 0, buffer_size_in_bytes); @@ -629,27 +733,28 @@ void TensorToVideoFrameConverter::ConvertBatchedDX12TensorToBuffers( device_cache.SyncD3D12ToCPU(); byte* readback_buffer = nullptr; - WINML_THROW_IF_FAILED(readback_heap_->Map(0, &CD3DX12_RANGE(0, buffer_size_in_bytes), reinterpret_cast(&readback_buffer))); + WINML_THROW_IF_FAILED( + readback_heap_->Map(0, &CD3DX12_RANGE(0, buffer_size_in_bytes), reinterpret_cast(&readback_buffer)) + ); auto readback_buffer_span = gsl::span(readback_buffer, buffer_size_in_bytes); _winml::StoreSpanIntoDisjointBuffers( - buffers.size(), - [&](size_t i) { - byte* buffer_start = nullptr; - auto byte_access = buffers[i].as(); - byte_access->Buffer(&buffer_start); - return gsl::span(buffer_start, static_cast(buffers[i].Capacity())); - }, - readback_buffer_span); + buffers.size(), + [&](size_t i) { + byte* buffer_start = nullptr; + auto byte_access = buffers[i].as(); + byte_access->Buffer(&buffer_start); + return gsl::span(buffer_start, static_cast(buffers[i].Capacity())); + }, + readback_buffer_span + ); readback_heap_->Unmap(0, &CD3DX12_RANGE(0, 0)); } D3D12_SHADER_RESOURCE_VIEW_DESC TensorToVideoFrameConverter::CreateSRVDescriptor( - const UINT32 batchIdx, - const D3D12_RESOURCE_DESC& resourceDesc, - const _winml::ImageTensorDescription& desc) { - UINT uiTensorElementSize = - desc.dataType == kImageTensorDataTypeFloat32 ? sizeof(UINT) : sizeof(uint16_t); + const UINT32 batchIdx, const D3D12_RESOURCE_DESC& resourceDesc, const _winml::ImageTensorDescription& desc +) { + UINT uiTensorElementSize = desc.dataType == kImageTensorDataTypeFloat32 ? sizeof(UINT) : sizeof(uint16_t); D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; @@ -672,19 +777,18 @@ D3D12_SHADER_RESOURCE_VIEW_DESC TensorToVideoFrameConverter::CreateSRVDescriptor srvDesc.Buffer.StructureByteStride = 0; } else { WINML_THROW_HR_IF_FALSE_MSG( - E_INVALIDARG, - false, - "Tensorization conversion is only supported to kImageTensorDataTypeFloat32, or kImageTensorDataTypeFloat16."); + E_INVALIDARG, + false, + "Tensorization conversion is only supported to kImageTensorDataTypeFloat32, or kImageTensorDataTypeFloat16." + ); } return srvDesc; } void TensorToVideoFrameConverter::ConvertCPUTensorToSoftwareBitmap( - _In_ void* pCPUTensor, - _In_ const ImageTensorDescription& tensorDesc, - _Inout_ wgi::SoftwareBitmap& softwareBitmap) { - + _In_ void* pCPUTensor, _In_ const ImageTensorDescription& tensorDesc, _Inout_ wgi::SoftwareBitmap& softwareBitmap +) { // we're inside a lock from the caller of this function, so it's ok to use this static static EventTimer eventTimer; std::optional telemetryLogger; @@ -698,27 +802,61 @@ void TensorToVideoFrameConverter::ConvertCPUTensorToSoftwareBitmap( // Validate input description WINML_THROW_HR_IF_FALSE_MSG( - E_INVALIDARG, - format == wgi::BitmapPixelFormat::Bgra8 || format == wgi::BitmapPixelFormat::Rgba8 || format == wgi::BitmapPixelFormat::Gray8, - "Format was input image %d. Input image format must Bgra8, Rgba8 or Gray8.", - format); + E_INVALIDARG, + format == wgi::BitmapPixelFormat::Bgra8 || format == wgi::BitmapPixelFormat::Rgba8 || + format == wgi::BitmapPixelFormat::Gray8, + "Format was input image %d. Input image format must Bgra8, Rgba8 or Gray8.", + format + ); WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, height > 0, "Output input image height provided. Height is set to zero."); WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, width > 0, "Output input image width provided. Width is set to zero."); // Validate Tensor description - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, tensorDesc.dataType == kImageTensorDataTypeFloat32 || tensorDesc.dataType == kImageTensorDataTypeFloat16, "Target tensor description must either be kImageTensorDataTypeFloat32, or kImageTensorDataTypeFloat16. %d was supplied.", tensorDesc.dataType); - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, tensorDesc.channelType != kImageTensorChannelTypeRGB8 || tensorDesc.sizes[1] == 3, "Target tensor description expects kImageTensorChannelTypeRGB8, but has %lld channels specified instead of 3.", tensorDesc.sizes[1]); - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, tensorDesc.channelType != kImageTensorChannelTypeBGR8 || tensorDesc.sizes[1] == 3, "Target tensor description expects kImageTensorChannelTypeBGR8, but has %lld channels specified instead of 3.", tensorDesc.sizes[1]); - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, tensorDesc.channelType != kImageTensorChannelTypeGRAY8 || tensorDesc.sizes[1] == 1, "Target tensor description expects kImageTensorChannelTypeGRAY8, but has %lld channels specified instead of 1.", tensorDesc.sizes[1]); WINML_THROW_HR_IF_FALSE_MSG( - E_INVALIDARG, - tensorDesc.channelType == kImageTensorChannelTypeGRAY8 || - tensorDesc.channelType == kImageTensorChannelTypeBGR8 || - tensorDesc.channelType == kImageTensorChannelTypeRGB8, - "Target tensor description expects kImageTensorChannelTypeGRAY8, kImageTensorChannelTypeBGR8, or kImageTensorChannelTypeRGB8 but has %d was specified.", - tensorDesc.channelType); - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, tensorDesc.sizes[2] == (UINT)height, "Target tensor height (%lld) does not match input height (%lu).", tensorDesc.sizes[2], (UINT)height); - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, tensorDesc.sizes[3] == (UINT)width, "Target tensor width (%lld) does not match input width (%lu).", tensorDesc.sizes[3], (UINT)width); + E_INVALIDARG, + tensorDesc.dataType == kImageTensorDataTypeFloat32 || tensorDesc.dataType == kImageTensorDataTypeFloat16, + "Target tensor description must either be kImageTensorDataTypeFloat32, or kImageTensorDataTypeFloat16. %d was supplied.", + tensorDesc.dataType + ); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, + tensorDesc.channelType != kImageTensorChannelTypeRGB8 || tensorDesc.sizes[1] == 3, + "Target tensor description expects kImageTensorChannelTypeRGB8, but has %lld channels specified instead of 3.", + tensorDesc.sizes[1] + ); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, + tensorDesc.channelType != kImageTensorChannelTypeBGR8 || tensorDesc.sizes[1] == 3, + "Target tensor description expects kImageTensorChannelTypeBGR8, but has %lld channels specified instead of 3.", + tensorDesc.sizes[1] + ); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, + tensorDesc.channelType != kImageTensorChannelTypeGRAY8 || tensorDesc.sizes[1] == 1, + "Target tensor description expects kImageTensorChannelTypeGRAY8, but has %lld channels specified instead of 1.", + tensorDesc.sizes[1] + ); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, + tensorDesc.channelType == kImageTensorChannelTypeGRAY8 || tensorDesc.channelType == kImageTensorChannelTypeBGR8 || + tensorDesc.channelType == kImageTensorChannelTypeRGB8, + "Target tensor description expects kImageTensorChannelTypeGRAY8, kImageTensorChannelTypeBGR8, or kImageTensorChannelTypeRGB8 but has %d was specified.", + tensorDesc.channelType + ); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, + tensorDesc.sizes[2] == (UINT)height, + "Target tensor height (%lld) does not match input height (%lu).", + tensorDesc.sizes[2], + (UINT)height + ); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, + tensorDesc.sizes[3] == (UINT)width, + "Target tensor width (%lld) does not match input width (%lu).", + tensorDesc.sizes[3], + (UINT)width + ); // get the byte buffer out of a softwarebitmap BYTE* pData = nullptr; @@ -736,13 +874,14 @@ void TensorToVideoFrameConverter::ConvertCPUTensorToSoftwareBitmap( if (tensorDesc.dataType == kImageTensorDataTypeFloat32) { WINML_THROW_IF_FAILED(CpuDetensorizer::Detensorize( tensorDesc.channelType, - targetChannelType, - tensorDesc.pixelRange, + targetChannelType, + tensorDesc.pixelRange, static_cast(pCPUTensor), - bufferWidth, + bufferWidth, height, width, - pData)); + pData + )); } else if (tensorDesc.dataType == kImageTensorDataTypeFloat16) { WINML_THROW_IF_FAILED(CpuDetensorizer::Detensorize( tensorDesc.channelType, @@ -752,6 +891,7 @@ void TensorToVideoFrameConverter::ConvertCPUTensorToSoftwareBitmap( bufferWidth, height, width, - pData)); + pData + )); } -} \ No newline at end of file +} diff --git a/winml/lib/Api.Image/VideoFrameToTensorConverter.cpp b/winml/lib/Api.Image/VideoFrameToTensorConverter.cpp index 19637018eea07..b856c6bdbfeca 100644 --- a/winml/lib/Api.Image/VideoFrameToTensorConverter.cpp +++ b/winml/lib/Api.Image/VideoFrameToTensorConverter.cpp @@ -29,30 +29,32 @@ class DX12TextureToGPUTensorTelemetryEvent { DX12TextureToGPUTensorTelemetryEvent(const ImageTensorDescription& tensorDesc) { runtime_session_id_ = telemetry_helper.GetRuntimeSessionId(); TraceLoggingWrite( - winml_trace_logging_provider, - "DX12TextureToGPUTensorStart", - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), - TraceLoggingHexInt32(tensorDesc.channelType, "Type"), - TraceLoggingInt64(tensorDesc.sizes[2], "Height"), - TraceLoggingInt64(tensorDesc.sizes[3], "Width"), - TraceLoggingInt32(runtime_session_id_, "runtimeSessionId"), - TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), - TraceLoggingBool(true, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)); + winml_trace_logging_provider, + "DX12TextureToGPUTensorStart", + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), + TraceLoggingHexInt32(tensorDesc.channelType, "Type"), + TraceLoggingInt64(tensorDesc.sizes[2], "Height"), + TraceLoggingInt64(tensorDesc.sizes[3], "Width"), + TraceLoggingInt32(runtime_session_id_, "runtimeSessionId"), + TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), + TraceLoggingBool(true, "UTCReplace_AppSessionGuid"), + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES) + ); } ~DX12TextureToGPUTensorTelemetryEvent() { TraceLoggingWrite( - winml_trace_logging_provider, - "DX12TextureToGPUTensorStop", - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), - TraceLoggingHexInt32(S_OK, "HRESULT"), - TraceLoggingInt32(runtime_session_id_, "runtimeSessionId"), - TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), - TraceLoggingBool(true, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)); + winml_trace_logging_provider, + "DX12TextureToGPUTensorStop", + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), + TraceLoggingHexInt32(S_OK, "HRESULT"), + TraceLoggingInt32(runtime_session_id_, "runtimeSessionId"), + TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), + TraceLoggingBool(true, "UTCReplace_AppSessionGuid"), + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES) + ); } -private: + private: int runtime_session_id_; }; @@ -61,30 +63,32 @@ class SoftwareBitmapToGPUTensorTelemetryEvent { SoftwareBitmapToGPUTensorTelemetryEvent(const ImageTensorDescription& tensorDesc) { runtime_session_id_ = telemetry_helper.GetRuntimeSessionId(); TraceLoggingWrite( - winml_trace_logging_provider, - "SoftwareBitmapToGPUTensorStart", - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), - TraceLoggingHexInt32(tensorDesc.channelType, "Type"), - TraceLoggingInt64(tensorDesc.sizes[2], "Height"), - TraceLoggingInt64(tensorDesc.sizes[3], "Width"), - TraceLoggingInt32(runtime_session_id_, "runtimeSessionId"), - TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), - TraceLoggingBool(true, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)); + winml_trace_logging_provider, + "SoftwareBitmapToGPUTensorStart", + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), + TraceLoggingHexInt32(tensorDesc.channelType, "Type"), + TraceLoggingInt64(tensorDesc.sizes[2], "Height"), + TraceLoggingInt64(tensorDesc.sizes[3], "Width"), + TraceLoggingInt32(runtime_session_id_, "runtimeSessionId"), + TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), + TraceLoggingBool(true, "UTCReplace_AppSessionGuid"), + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES) + ); } ~SoftwareBitmapToGPUTensorTelemetryEvent() { TraceLoggingWrite( - winml_trace_logging_provider, - "SoftwareBitmapToGPUTensorStop", - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), - TraceLoggingHexInt32(S_OK, "HRESULT"), - TraceLoggingInt32(runtime_session_id_, "runtimeSessionId"), - TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), - TraceLoggingBool(true, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)); + winml_trace_logging_provider, + "SoftwareBitmapToGPUTensorStop", + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), + TraceLoggingHexInt32(S_OK, "HRESULT"), + TraceLoggingInt32(runtime_session_id_, "runtimeSessionId"), + TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), + TraceLoggingBool(true, "UTCReplace_AppSessionGuid"), + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES) + ); } -private: + private: int runtime_session_id_; }; @@ -93,38 +97,41 @@ class ConvertVideoFrameWithSoftwareBitmapToCPUTensorTelemetryEvent { ConvertVideoFrameWithSoftwareBitmapToCPUTensorTelemetryEvent(const ImageTensorDescription& tensorDesc) { runtime_session_id_ = telemetry_helper.GetRuntimeSessionId(); TraceLoggingWrite( - winml_trace_logging_provider, - "ConvertVideoFrameWithSoftwareBitmapToCPUTensorStart", - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), - TraceLoggingHexInt32(tensorDesc.channelType, "Type"), - TraceLoggingInt64(tensorDesc.sizes[2], "Height"), - TraceLoggingInt64(tensorDesc.sizes[3], "Width"), - TraceLoggingInt32(runtime_session_id_, "runtimeSessionId"), - TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), - TraceLoggingBool(true, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)); + winml_trace_logging_provider, + "ConvertVideoFrameWithSoftwareBitmapToCPUTensorStart", + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), + TraceLoggingHexInt32(tensorDesc.channelType, "Type"), + TraceLoggingInt64(tensorDesc.sizes[2], "Height"), + TraceLoggingInt64(tensorDesc.sizes[3], "Width"), + TraceLoggingInt32(runtime_session_id_, "runtimeSessionId"), + TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), + TraceLoggingBool(true, "UTCReplace_AppSessionGuid"), + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES) + ); } ~ConvertVideoFrameWithSoftwareBitmapToCPUTensorTelemetryEvent() { TraceLoggingWrite( - winml_trace_logging_provider, - "ConvertVideoFrameWithSoftwareBitmapToCPUTensorStop", - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), - TraceLoggingHexInt32(S_OK, "HRESULT"), - TraceLoggingInt32(runtime_session_id_, "runtimeSessionId"), - TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), - TraceLoggingBool(true, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)); + winml_trace_logging_provider, + "ConvertVideoFrameWithSoftwareBitmapToCPUTensorStop", + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), + TraceLoggingHexInt32(S_OK, "HRESULT"), + TraceLoggingInt32(runtime_session_id_, "runtimeSessionId"), + TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), + TraceLoggingBool(true, "UTCReplace_AppSessionGuid"), + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES) + ); } -private: + private: int runtime_session_id_; }; void VideoFrameToTensorConverter::VideoFrameToSoftwareTensor( - _In_ const wm::IVideoFrame& inputVideoFrame, - _In_ const wgi::BitmapBounds& inputBounds, - _In_ const ImageTensorDescription& tensorDesc, - _Out_ BYTE* pOutputCPUTensor) { + _In_ const wm::IVideoFrame& inputVideoFrame, + _In_ const wgi::BitmapBounds& inputBounds, + _In_ const ImageTensorDescription& tensorDesc, + _Out_ BYTE* pOutputCPUTensor +) { CWinMLAutoLock lock(&lock_); wgi::SoftwareBitmap spInputSoftwareBitmap = inputVideoFrame.SoftwareBitmap(); @@ -138,36 +145,31 @@ void VideoFrameToTensorConverter::VideoFrameToSoftwareTensor( UINT32 tensorHeight = static_cast(tensorDesc.sizes[2]); UINT32 tensorWidth = static_cast(tensorDesc.sizes[3]); if (spInputSurface || _winmli::NeedsVideoFrameConversion(inputVideoFrame, {}, inputBounds, tensorWidth, tensorHeight)) { - if (converted_video_frame_ == nullptr || - _winmli::NeedsVideoFrameConversion(converted_video_frame_, {}, {0, 0, (UINT32)tensorWidth, (UINT32)tensorHeight}, tensorWidth, tensorHeight)) { + if (converted_video_frame_ == nullptr || _winmli::NeedsVideoFrameConversion(converted_video_frame_, {}, {0, 0, (UINT32)tensorWidth, (UINT32)tensorHeight}, tensorWidth, tensorHeight)) { converted_video_frame_ = wm::VideoFrame::CreateWithSoftwareBitmap( - wgi::SoftwareBitmap(wgi::BitmapPixelFormat::Bgra8, tensorWidth, tensorHeight)); + wgi::SoftwareBitmap(wgi::BitmapPixelFormat::Bgra8, tensorWidth, tensorHeight) + ); } // Resize the input VideoFrame to converted_video_frame_ _winmli::ConvertVideoFrameToVideoFrame( - inputVideoFrame, - inputBounds, - tensorWidth, - tensorHeight, - converted_video_frame_); + inputVideoFrame, inputBounds, tensorWidth, tensorHeight, converted_video_frame_ + ); ConvertSoftwareBitmapToCPUTensor( - converted_video_frame_.SoftwareBitmap(), - tensorDesc, - {0, 0, (UINT32)tensorWidth, (UINT32)tensorHeight}, - pOutputCPUTensor); + converted_video_frame_.SoftwareBitmap(), + tensorDesc, + {0, 0, (UINT32)tensorWidth, (UINT32)tensorHeight}, + pOutputCPUTensor + ); } else { - ConvertSoftwareBitmapToCPUTensor( - inputVideoFrame.SoftwareBitmap(), - tensorDesc, - inputBounds, - pOutputCPUTensor); + ConvertSoftwareBitmapToCPUTensor(inputVideoFrame.SoftwareBitmap(), tensorDesc, inputBounds, pOutputCPUTensor); } } -ComPtr VideoFrameToTensorConverter::ShareD3D11Texture(ID3D11Texture2D* pTexture, ID3D12Device* pDevice) -{ +ComPtr VideoFrameToTensorConverter::ShareD3D11Texture( + ID3D11Texture2D* pTexture, ID3D12Device* pDevice +) { assert(pTexture != nullptr); assert(pDevice != nullptr); @@ -188,17 +190,38 @@ ComPtr VideoFrameToTensorConverter::ShareD3D11Texture(ID3D11Text } void VideoFrameToTensorConverter::VideoFrameToDX12Tensor( - _In_ const UINT32 batchIdx, - _In_ winml::LearningModelSession& session, - _In_ const wm::IVideoFrame& inputVideoFrame, - _In_ const wgi::BitmapBounds& inputBounds, - _In_ const ImageTensorDescription& tensorDesc, - _Inout_ ID3D12Resource* pOutputTensor) { + _In_ const UINT32 batchIdx, + _In_ winml::LearningModelSession& session, + _In_ const wm::IVideoFrame& inputVideoFrame, + _In_ const wgi::BitmapBounds& inputBounds, + _In_ const ImageTensorDescription& tensorDesc, + _Inout_ ID3D12Resource* pOutputTensor +) { // Validate Tensor description - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, tensorDesc.dataType == kImageTensorDataTypeFloat32 || tensorDesc.dataType == kImageTensorDataTypeFloat16, "Target tensor description must either be kImageTensorDataTypeFloat32, or kImageTensorDataTypeFloat16. %d was supplied.", tensorDesc.dataType); - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, tensorDesc.channelType != kImageTensorChannelTypeRGB8 || tensorDesc.sizes[1] == 3, "Target tensor description expects kImageTensorChannelTypeRGB8, but has %lld channels specified instead of 3.", tensorDesc.sizes[1]); - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, tensorDesc.channelType != kImageTensorChannelTypeBGR8 || tensorDesc.sizes[1] == 3, "Target tensor description expects kImageTensorChannelTypeBGR8, but has %lld channels specified instead of 3.", tensorDesc.sizes[1]); - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, tensorDesc.channelType != kImageTensorChannelTypeGRAY8 || tensorDesc.sizes[1] == 1, "Target tensor description expects kImageTensorChannelTypeGRAY8, but has %lld channels specified instead of 1.", tensorDesc.sizes[1]); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, + tensorDesc.dataType == kImageTensorDataTypeFloat32 || tensorDesc.dataType == kImageTensorDataTypeFloat16, + "Target tensor description must either be kImageTensorDataTypeFloat32, or kImageTensorDataTypeFloat16. %d was supplied.", + tensorDesc.dataType + ); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, + tensorDesc.channelType != kImageTensorChannelTypeRGB8 || tensorDesc.sizes[1] == 3, + "Target tensor description expects kImageTensorChannelTypeRGB8, but has %lld channels specified instead of 3.", + tensorDesc.sizes[1] + ); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, + tensorDesc.channelType != kImageTensorChannelTypeBGR8 || tensorDesc.sizes[1] == 3, + "Target tensor description expects kImageTensorChannelTypeBGR8, but has %lld channels specified instead of 3.", + tensorDesc.sizes[1] + ); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, + tensorDesc.channelType != kImageTensorChannelTypeGRAY8 || tensorDesc.sizes[1] == 1, + "Target tensor description expects kImageTensorChannelTypeGRAY8, but has %lld channels specified instead of 1.", + tensorDesc.sizes[1] + ); CWinMLAutoLock lock(&lock_); auto device = session.Device().as(); @@ -212,17 +235,20 @@ void VideoFrameToTensorConverter::VideoFrameToDX12Tensor( wgi::BitmapBounds scaledBounds = inputBounds; // TODO: Scale during the tensorization phase instead of using the video frame pipeline when the input bounds are not the same size as the tensor - if (!_winmli::DirectXPixelFormatSupported(spDirect3DSurface.Description().Format) || static_cast(inputBounds.Width) != tensorDesc.sizes[3] || static_cast(inputBounds.Height) != tensorDesc.sizes[2]) { + if (!_winmli::DirectXPixelFormatSupported(spDirect3DSurface.Description().Format) || + static_cast(inputBounds.Width) != tensorDesc.sizes[3] || + static_cast(inputBounds.Height) != tensorDesc.sizes[2]) { // Force the VideoFrame to not do a conversion if the format is supported since we do it during the tensorization anyway wgdx::DirectXPixelFormat newFormat = _winmli::DirectXPixelFormatSupported(spDirect3DSurface.Description().Format) - ? spDirect3DSurface.Description().Format - : _winmli::GetDirectXPixelFormatFromChannelType(tensorDesc.channelType); + ? spDirect3DSurface.Description().Format + : _winmli::GetDirectXPixelFormatFromChannelType(tensorDesc.channelType); // Change the input bounds since the video frame pipeline already cropped the texture scaledBounds = {0, 0, static_cast(tensorDesc.sizes[3]), static_cast(tensorDesc.sizes[2])}; // Use the Video Frame pipeline if we don't have our own converter for this color format - spVideoFrameTexture = CreateTextureFromUnsupportedColorFormat(inputVideoFrame, inputBounds, scaledBounds, newFormat); + spVideoFrameTexture = + CreateTextureFromUnsupportedColorFormat(inputVideoFrame, inputBounds, scaledBounds, newFormat); } else { // If the color format is known or the input widths are not smaller than the tensor desc, just use the video frame as is spVideoFrameTexture = _winmli::GetTextureFromDirect3DSurface(spDirect3DSurface); @@ -234,15 +260,20 @@ void VideoFrameToTensorConverter::VideoFrameToDX12Tensor( if (_winmli::TextureIsOnDevice(spVideoFrameTexture.Get(), pDeviceCache->GetD3D11Device())) { // The texture is on our device, so we can just create own texture, share it and cache it if (!D3D11_cached_texture_) { - WINML_THROW_IF_FAILED(pDeviceCache->GetD3D11Device()->CreateTexture2D(&videoFrameTextureDesc, nullptr, &D3D11_cached_texture_)); + WINML_THROW_IF_FAILED( + pDeviceCache->GetD3D11Device()->CreateTexture2D(&videoFrameTextureDesc, nullptr, &D3D11_cached_texture_) + ); input_D3D12_resource_ = ShareD3D11Texture(D3D11_cached_texture_.Get(), pDeviceCache->GetD3D12Device()); } else { D3D11_TEXTURE2D_DESC cachedTextureDesc; D3D11_cached_texture_->GetDesc(&cachedTextureDesc); - if (cachedTextureDesc.Width != scaledBounds.Width || cachedTextureDesc.Height != scaledBounds.Height || cachedTextureDesc.Format != videoFrameTextureDesc.Format) { + if (cachedTextureDesc.Width != scaledBounds.Width || cachedTextureDesc.Height != scaledBounds.Height || + cachedTextureDesc.Format != videoFrameTextureDesc.Format) { // The dimensions or format don't match, so we need to re-create our texture - WINML_THROW_IF_FAILED(pDeviceCache->GetD3D11Device()->CreateTexture2D(&videoFrameTextureDesc, nullptr, &D3D11_cached_texture_)); + WINML_THROW_IF_FAILED( + pDeviceCache->GetD3D11Device()->CreateTexture2D(&videoFrameTextureDesc, nullptr, &D3D11_cached_texture_) + ); input_D3D12_resource_ = ShareD3D11Texture(D3D11_cached_texture_.Get(), pDeviceCache->GetD3D12Device()); } } @@ -258,15 +289,23 @@ void VideoFrameToTensorConverter::VideoFrameToDX12Tensor( UINT comPtrSize = static_cast(sizeof(spSharedD3D11Texture.GetAddressOf())); UINT handleSize = static_cast(sizeof(sharedHandle)); - if ((FAILED(spVideoFrameTexture->GetPrivateData(d3d11_texture_GUID_, &comPtrSize, spSharedD3D11Texture.GetAddressOf())) || !spSharedD3D11Texture.Get()) || (FAILED(spVideoFrameTexture->GetPrivateData(handle_GUID_, &handleSize, &sharedHandle)) || sharedHandle != shared_handle_)) { + if ((FAILED(spVideoFrameTexture->GetPrivateData( + d3d11_texture_GUID_, &comPtrSize, spSharedD3D11Texture.GetAddressOf() + )) || + !spSharedD3D11Texture.Get()) || + (FAILED(spVideoFrameTexture->GetPrivateData(handle_GUID_, &handleSize, &sharedHandle)) || + sharedHandle != shared_handle_)) { // Create a new shared texture that we cache on the video frame texture WINML_THROW_IF_FAILED(spTextureDevice->CreateTexture2D(&videoFrameTextureDesc, nullptr, &spSharedD3D11Texture)); input_D3D12_resource_ = ShareD3D11Texture(spSharedD3D11Texture.Get(), pDeviceCache->GetD3D12Device()); // Cache the shared texture on the video frame texture in order to tie their lifetime together - WINML_THROW_IF_FAILED(spVideoFrameTexture->SetPrivateDataInterface(d3d11_texture_GUID_, spSharedD3D11Texture.Get())); - WINML_THROW_IF_FAILED(spVideoFrameTexture->SetPrivateData(handle_GUID_, sizeof(shared_handle_), &shared_handle_)); + WINML_THROW_IF_FAILED( + spVideoFrameTexture->SetPrivateDataInterface(d3d11_texture_GUID_, spSharedD3D11Texture.Get()) + ); + WINML_THROW_IF_FAILED(spVideoFrameTexture->SetPrivateData(handle_GUID_, sizeof(shared_handle_), &shared_handle_) + ); } // Copy from the video frame texture to the shared texture @@ -286,11 +325,12 @@ void VideoFrameToTensorConverter::VideoFrameToDX12Tensor( } void VideoFrameToTensorConverter::ConvertDX12TextureToGPUTensor( - _In_ UINT32 batchIdx, - _In_ ID3D12Resource* pInputResource, - _In_ _winml::D3DDeviceCache& device_cache, - _In_ const ImageTensorDescription& tensorDesc, - _Inout_ ID3D12Resource* pOutputResource) { + _In_ UINT32 batchIdx, + _In_ ID3D12Resource* pInputResource, + _In_ _winml::D3DDeviceCache& device_cache, + _In_ const ImageTensorDescription& tensorDesc, + _Inout_ ID3D12Resource* pOutputResource +) { assert(pInputResource != nullptr); assert(pOutputResource != nullptr); @@ -308,21 +348,59 @@ void VideoFrameToTensorConverter::ConvertDX12TextureToGPUTensor( // Validate input description WINML_THROW_HR_IF_FALSE_MSG( - E_INVALIDARG, - inputDesc.Format == DXGI_FORMAT_B8G8R8X8_UNORM || inputDesc.Format == DXGI_FORMAT_B8G8R8A8_UNORM || inputDesc.Format == DXGI_FORMAT_R8G8B8A8_UNORM || inputDesc.Format == DXGI_FORMAT_R8_UNORM, - "Format was input image %d. Input image format must Bgra8, Rgba8 or Gray8.", - inputDesc.Format); + E_INVALIDARG, + inputDesc.Format == DXGI_FORMAT_B8G8R8X8_UNORM || inputDesc.Format == DXGI_FORMAT_B8G8R8A8_UNORM || + inputDesc.Format == DXGI_FORMAT_R8G8B8A8_UNORM || inputDesc.Format == DXGI_FORMAT_R8_UNORM, + "Format was input image %d. Input image format must Bgra8, Rgba8 or Gray8.", + inputDesc.Format + ); - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, inputDesc.Width != 0, "Invalid input image height provided. Width is set to zero."); - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, inputDesc.Height != 0, "Invalid input image height provided. Height is set to zero."); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, inputDesc.Width != 0, "Invalid input image height provided. Width is set to zero." + ); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, inputDesc.Height != 0, "Invalid input image height provided. Height is set to zero." + ); // Validate Tensor description - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, tensorDesc.dataType == kImageTensorDataTypeFloat32 || tensorDesc.dataType == kImageTensorDataTypeFloat16, "Target tensor description must either be kImageTensorDataTypeFloat32, or kImageTensorDataTypeFloat16. %d was supplied.", tensorDesc.dataType); - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, tensorDesc.channelType != kImageTensorChannelTypeRGB8 || tensorDesc.sizes[1] == 3, "Target tensor description expects kImageTensorChannelTypeRGB8, but has %lld channels specified instead of 3.", tensorDesc.sizes[1]); - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, tensorDesc.channelType != kImageTensorChannelTypeBGR8 || tensorDesc.sizes[1] == 3, "Target tensor description expects kImageTensorChannelTypeBGR8, but has %lld channels specified instead of 3.", tensorDesc.sizes[1]); - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, tensorDesc.channelType != kImageTensorChannelTypeGRAY8 || tensorDesc.sizes[1] == 1, "Target tensor description expects kImageTensorChannelTypeGRAY8, but has %lld channels specified instead of 1.", tensorDesc.sizes[1]); - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, tensorDesc.sizes[2] == inputDesc.Height, "Target tensor height (%lld) does not match input height (%lu).", tensorDesc.sizes[2], inputDesc.Height); - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, tensorDesc.sizes[3] == (UINT)inputDesc.Width, "Target tensor width (%lld) does not match input width (%lu).", tensorDesc.sizes[3], (UINT)inputDesc.Width); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, + tensorDesc.dataType == kImageTensorDataTypeFloat32 || tensorDesc.dataType == kImageTensorDataTypeFloat16, + "Target tensor description must either be kImageTensorDataTypeFloat32, or kImageTensorDataTypeFloat16. %d was supplied.", + tensorDesc.dataType + ); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, + tensorDesc.channelType != kImageTensorChannelTypeRGB8 || tensorDesc.sizes[1] == 3, + "Target tensor description expects kImageTensorChannelTypeRGB8, but has %lld channels specified instead of 3.", + tensorDesc.sizes[1] + ); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, + tensorDesc.channelType != kImageTensorChannelTypeBGR8 || tensorDesc.sizes[1] == 3, + "Target tensor description expects kImageTensorChannelTypeBGR8, but has %lld channels specified instead of 3.", + tensorDesc.sizes[1] + ); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, + tensorDesc.channelType != kImageTensorChannelTypeGRAY8 || tensorDesc.sizes[1] == 1, + "Target tensor description expects kImageTensorChannelTypeGRAY8, but has %lld channels specified instead of 1.", + tensorDesc.sizes[1] + ); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, + tensorDesc.sizes[2] == inputDesc.Height, + "Target tensor height (%lld) does not match input height (%lu).", + tensorDesc.sizes[2], + inputDesc.Height + ); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, + tensorDesc.sizes[3] == (UINT)inputDesc.Width, + "Target tensor width (%lld) does not match input width (%lu).", + tensorDesc.sizes[3], + (UINT)inputDesc.Width + ); UINT uiTensorElementSize = tensorDesc.dataType == kImageTensorDataTypeFloat32 ? sizeof(FLOAT) : sizeof(uint16_t); @@ -344,11 +422,10 @@ void VideoFrameToTensorConverter::ConvertDX12TextureToGPUTensor( UINT64 ullTensorSize = 0; WINML_THROW_IF_FAILED(ULongLongMult(ullNumElementsTensor, uiTensorElementSize, &ullTensorSize)); - if (outputDesc.Width < ullTensorSize || - outputDesc.Height != 1 || - outputDesc.Dimension != D3D12_RESOURCE_DIMENSION_BUFFER || - !(outputDesc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS) || - outputHeapProperties.Type != D3D12_HEAP_TYPE_DEFAULT) { + if (outputDesc.Width < ullTensorSize || outputDesc.Height != 1 || + outputDesc.Dimension != D3D12_RESOURCE_DIMENSION_BUFFER || + !(outputDesc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS) || + outputHeapProperties.Type != D3D12_HEAP_TYPE_DEFAULT) { WINML_THROW_IF_FAILED(E_INVALIDARG); } } @@ -384,11 +461,15 @@ void VideoFrameToTensorConverter::ConvertDX12TextureToGPUTensor( srvDesc.Format = inputDesc.Format; srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; srvDesc.Texture2D.MipLevels = 1; - CD3DX12_CPU_DESCRIPTOR_HANDLE srvHandle(descriptor_heap_->GetCPUDescriptorHandleForHeapStart(), SrvBufferIdx, srvUavDescriptorSize); + CD3DX12_CPU_DESCRIPTOR_HANDLE srvHandle( + descriptor_heap_->GetCPUDescriptorHandleForHeapStart(), SrvBufferIdx, srvUavDescriptorSize + ); spDx12Device->CreateShaderResourceView(pInputResource, &srvDesc, srvHandle); D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = CreateUAVDescription(batchIdx, outputDesc, tensorDesc); - CD3DX12_CPU_DESCRIPTOR_HANDLE uavHandle(descriptor_heap_->GetCPUDescriptorHandleForHeapStart(), UavBufferIdx, srvUavDescriptorSize); + CD3DX12_CPU_DESCRIPTOR_HANDLE uavHandle( + descriptor_heap_->GetCPUDescriptorHandleForHeapStart(), UavBufferIdx, srvUavDescriptorSize + ); spDx12Device->CreateUnorderedAccessView(pOutputResource, nullptr, &uavDesc, uavHandle); } @@ -417,7 +498,8 @@ void VideoFrameToTensorConverter::ConvertDX12TextureToGPUTensor( } root_signature_ = device_cache.GetTensorizeRootSignature(); - pipeline_state_ = device_cache.GetCachedPipelineState(type, formatFrom, formatTo, PipelineStateCacheOperation::kTensorize); + pipeline_state_ = + device_cache.GetCachedPipelineState(type, formatFrom, formatTo, PipelineStateCacheOperation::kTensorize); ResetCommandList(device_cache); @@ -429,13 +511,16 @@ void VideoFrameToTensorConverter::ConvertDX12TextureToGPUTensor( command_list_->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); // This code currently re-uses the same decriptors each execution, which is unsafe if previous executions are in flight. - if (fence_completion_value_ > 0) - { - device_cache.WaitForFenceValue(fence_completion_value_); + if (fence_completion_value_ > 0) { + device_cache.WaitForFenceValue(fence_completion_value_); } - CD3DX12_GPU_DESCRIPTOR_HANDLE srvHandle(descriptor_heap_->GetGPUDescriptorHandleForHeapStart(), SrvBufferIdx, srvUavDescriptorSize); - CD3DX12_GPU_DESCRIPTOR_HANDLE uavHandle(descriptor_heap_->GetGPUDescriptorHandleForHeapStart(), UavBufferIdx, srvUavDescriptorSize); + CD3DX12_GPU_DESCRIPTOR_HANDLE srvHandle( + descriptor_heap_->GetGPUDescriptorHandleForHeapStart(), SrvBufferIdx, srvUavDescriptorSize + ); + CD3DX12_GPU_DESCRIPTOR_HANDLE uavHandle( + descriptor_heap_->GetGPUDescriptorHandleForHeapStart(), UavBufferIdx, srvUavDescriptorSize + ); { ConstantBufferCS constantBufferCS = {}; constantBufferCS.height = inputDesc.Height; @@ -459,12 +544,13 @@ void VideoFrameToTensorConverter::ConvertDX12TextureToGPUTensor( } void VideoFrameToTensorConverter::ConvertSoftwareBitmapToGPUTensor( - _In_ UINT32 batchIdx, - _In_ const wm::IVideoFrame& videoFrame, - _In_ _winml::D3DDeviceCache& device_cache, - _In_ const wgi::BitmapBounds& inputBounds, - _In_ const ImageTensorDescription& tensorDesc, - _Inout_ ID3D12Resource* pOutputResource) { + _In_ UINT32 batchIdx, + _In_ const wm::IVideoFrame& videoFrame, + _In_ _winml::D3DDeviceCache& device_cache, + _In_ const wgi::BitmapBounds& inputBounds, + _In_ const ImageTensorDescription& tensorDesc, + _Inout_ ID3D12Resource* pOutputResource +) { assert(pOutputResource != nullptr); assert(videoFrame.SoftwareBitmap() != nullptr); @@ -484,16 +570,20 @@ void VideoFrameToTensorConverter::ConvertSoftwareBitmapToGPUTensor( // Force the VideoFrame to not do a conversion if the format is supported since we do it during the tensorization anyway wgi::BitmapPixelFormat newPixelFormat = _winmli::SoftwareBitmapFormatSupported(videoFrame.SoftwareBitmap()) - ? videoFrame.SoftwareBitmap().BitmapPixelFormat() - : _winmli::GetBitmapPixelFormatFromChannelType(tensorDesc.channelType); + ? videoFrame.SoftwareBitmap().BitmapPixelFormat() + : _winmli::GetBitmapPixelFormatFromChannelType(tensorDesc.channelType); - convertedSoftwareBitmap = wgi::SoftwareBitmap(newPixelFormat, static_cast(tensorDesc.sizes[3]), static_cast(tensorDesc.sizes[2])); + convertedSoftwareBitmap = wgi::SoftwareBitmap( + newPixelFormat, static_cast(tensorDesc.sizes[3]), static_cast(tensorDesc.sizes[2]) + ); wm::VideoFrame convertedVideoFrame = wm::VideoFrame::CreateWithSoftwareBitmap(convertedSoftwareBitmap); videoFrame.as().CopyToAsync(convertedVideoFrame, inputBounds, scaledBounds).get(); convertedSoftwareBitmap = convertedVideoFrame.SoftwareBitmap(); } else if (!_winmli::SoftwareBitmapFormatSupported(videoFrame.SoftwareBitmap())) { - convertedSoftwareBitmap = wgi::SoftwareBitmap::Convert(videoFrame.SoftwareBitmap(), _winmli::GetBitmapPixelFormatFromChannelType(tensorDesc.channelType)); + convertedSoftwareBitmap = wgi::SoftwareBitmap::Convert( + videoFrame.SoftwareBitmap(), _winmli::GetBitmapPixelFormatFromChannelType(tensorDesc.channelType) + ); } else { // We don't need a conversion convertedSoftwareBitmap = videoFrame.SoftwareBitmap(); @@ -504,17 +594,19 @@ void VideoFrameToTensorConverter::ConvertSoftwareBitmapToGPUTensor( D3D12_RESOURCE_DESC outputDesc = pOutputResource->GetDesc(); uint32_t tensorElementSize = tensorDesc.dataType == kImageTensorDataTypeFloat32 ? 4 : 2; - uint32_t bufferSize = static_cast(tensorDesc.sizes[1] * tensorDesc.sizes[2] * tensorDesc.sizes[3] * tensorElementSize); + uint32_t bufferSize = + static_cast(tensorDesc.sizes[1] * tensorDesc.sizes[2] * tensorDesc.sizes[3] * tensorElementSize); // TODO: Make an allocator for upload heaps if (!upload_heap_ || upload_heap_->GetDesc().Width < bufferSize) { WINML_THROW_IF_FAILED(device_cache.GetD3D12Device()->CreateCommittedResource( - &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), - D3D12_HEAP_FLAG_NONE, - &CD3DX12_RESOURCE_DESC::Buffer(bufferSize), - D3D12_RESOURCE_STATE_GENERIC_READ, - nullptr, - IID_PPV_ARGS(&upload_heap_))); + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), + D3D12_HEAP_FLAG_NONE, + &CD3DX12_RESOURCE_DESC::Buffer(bufferSize), + D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, + IID_PPV_ARGS(&upload_heap_) + )); } void* pCPUTensorBuffer = nullptr; @@ -529,30 +621,34 @@ void VideoFrameToTensorConverter::ConvertSoftwareBitmapToGPUTensor( ResetCommandList(device_cache); - auto barrier = CD3DX12_RESOURCE_BARRIER::Transition(pOutputResource, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_DEST); + auto barrier = CD3DX12_RESOURCE_BARRIER::Transition( + pOutputResource, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_DEST + ); command_list_->ResourceBarrier(1, &barrier); command_list_->CopyBufferRegion(pOutputResource, bufferSize * batchIdx, upload_heap_.Get(), 0, bufferSize); - + WINML_THROW_IF_FAILED(command_list_->Close()); ID3D12CommandList* ppCommandLists[] = {command_list_.Get()}; device_cache.GetCommandQueue()->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists); } void VideoFrameToTensorConverter::ConvertBuffersToBatchedGPUTensor( - _In_ const std::vector& buffers, - _In_ size_t buffer_size_in_bytes, - _In_ _winml::D3DDeviceCache& device_cache, - _Inout_ ID3D12Resource* output_resource) { + _In_ const std::vector& buffers, + _In_ size_t buffer_size_in_bytes, + _In_ _winml::D3DDeviceCache& device_cache, + _Inout_ ID3D12Resource* output_resource +) { // Copy the cpu memory into the gpu resource if (!upload_heap_ || upload_heap_->GetDesc().Width < buffer_size_in_bytes) { WINML_THROW_IF_FAILED(device_cache.GetD3D12Device()->CreateCommittedResource( - &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), - D3D12_HEAP_FLAG_NONE, - &CD3DX12_RESOURCE_DESC::Buffer(buffer_size_in_bytes), - D3D12_RESOURCE_STATE_GENERIC_READ, - nullptr, - IID_PPV_ARGS(&upload_heap_))); + &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), + D3D12_HEAP_FLAG_NONE, + &CD3DX12_RESOURCE_DESC::Buffer(buffer_size_in_bytes), + D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, + IID_PPV_ARGS(&upload_heap_) + )); } byte* gpu_buffer = nullptr; @@ -560,23 +656,27 @@ void VideoFrameToTensorConverter::ConvertBuffersToBatchedGPUTensor( auto gpu_buffer_span = gsl::span(gpu_buffer, buffer_size_in_bytes); _winml::LoadSpanFromDisjointBuffers( - buffers.size(), - [&](size_t i) { - byte* buffer_start = nullptr; - auto byte_access = buffers[i].as(); - byte_access->Buffer(&buffer_start); - return gsl::span(buffer_start, static_cast(buffers[i].Capacity())); - }, - gpu_buffer_span); + buffers.size(), + [&](size_t i) { + byte* buffer_start = nullptr; + auto byte_access = buffers[i].as(); + byte_access->Buffer(&buffer_start); + return gsl::span(buffer_start, static_cast(buffers[i].Capacity())); + }, + gpu_buffer_span + ); upload_heap_->Unmap(0, &CD3DX12_RANGE(0, buffer_size_in_bytes)); - + ResetCommandList(device_cache); - - auto barrier1 = CD3DX12_RESOURCE_BARRIER::Transition(output_resource, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_COPY_DEST); + + auto barrier1 = + CD3DX12_RESOURCE_BARRIER::Transition(output_resource, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_COPY_DEST); command_list_->ResourceBarrier(1, &barrier1); command_list_->CopyBufferRegion(output_resource, 0, upload_heap_.Get(), 0, buffer_size_in_bytes); - auto barrier2 = CD3DX12_RESOURCE_BARRIER::Transition(output_resource, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); + auto barrier2 = CD3DX12_RESOURCE_BARRIER::Transition( + output_resource, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_UNORDERED_ACCESS + ); command_list_->ResourceBarrier(1, &barrier2); WINML_THROW_IF_FAILED(command_list_->Close()); ID3D12CommandList* lists[] = {command_list_.Get()}; @@ -584,11 +684,9 @@ void VideoFrameToTensorConverter::ConvertBuffersToBatchedGPUTensor( } D3D12_UNORDERED_ACCESS_VIEW_DESC VideoFrameToTensorConverter::CreateUAVDescription( - const UINT32 batchIdx, - const D3D12_RESOURCE_DESC& resourceDesc, - const _winml::ImageTensorDescription& desc) { - UINT uiTensorElementSize = - desc.dataType == kImageTensorDataTypeFloat32 ? sizeof(UINT) : sizeof(uint16_t); + const UINT32 batchIdx, const D3D12_RESOURCE_DESC& resourceDesc, const _winml::ImageTensorDescription& desc +) { + UINT uiTensorElementSize = desc.dataType == kImageTensorDataTypeFloat32 ? sizeof(UINT) : sizeof(uint16_t); D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; @@ -611,19 +709,21 @@ D3D12_UNORDERED_ACCESS_VIEW_DESC VideoFrameToTensorConverter::CreateUAVDescripti uavDesc.Buffer.StructureByteStride = 0; } else { WINML_THROW_HR_IF_FALSE_MSG( - E_INVALIDARG, - false, - "Tensorization conversion is only supported to kImageTensorDataTypeFloat32, or kImageTensorDataTypeFloat16."); + E_INVALIDARG, + false, + "Tensorization conversion is only supported to kImageTensorDataTypeFloat32, or kImageTensorDataTypeFloat16." + ); } return uavDesc; } void VideoFrameToTensorConverter::ConvertSoftwareBitmapToCPUTensor( - _In_ const wgi::SoftwareBitmap& softwareBitmap, - _In_ const _winml::ImageTensorDescription& tensorDesc, - _In_ const wgi::BitmapBounds& inputBounds, - _Inout_ void* pCPUTensor) { + _In_ const wgi::SoftwareBitmap& softwareBitmap, + _In_ const _winml::ImageTensorDescription& tensorDesc, + _In_ const wgi::BitmapBounds& inputBounds, + _Inout_ void* pCPUTensor +) { assert(softwareBitmap != nullptr); // we're inside a lock from the caller of this function, so it's ok to use this static @@ -639,27 +739,61 @@ void VideoFrameToTensorConverter::ConvertSoftwareBitmapToCPUTensor( // Validate input description WINML_THROW_HR_IF_FALSE_MSG( - E_INVALIDARG, - format == wgi::BitmapPixelFormat::Bgra8 || format == wgi::BitmapPixelFormat::Rgba8 || format == wgi::BitmapPixelFormat::Gray8, - "Format was input image %d. Input image format must Bgra8, Rgba8 or Gray8.", - format); + E_INVALIDARG, + format == wgi::BitmapPixelFormat::Bgra8 || format == wgi::BitmapPixelFormat::Rgba8 || + format == wgi::BitmapPixelFormat::Gray8, + "Format was input image %d. Input image format must Bgra8, Rgba8 or Gray8.", + format + ); WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, height > 0, "Invalid input image height provided. Height is set to zero."); WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, width > 0, "Invalid input image width provided. Height is set to zero."); // Validate Tensor description - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, tensorDesc.dataType == kImageTensorDataTypeFloat32 || tensorDesc.dataType == kImageTensorDataTypeFloat16, "Target tensor description must either be kImageTensorDataTypeFloat32, or kImageTensorDataTypeFloat16. %d was supplied.", tensorDesc.dataType); - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, tensorDesc.channelType != kImageTensorChannelTypeRGB8 || tensorDesc.sizes[1] == 3, "Target tensor description expects kImageTensorChannelTypeRGB8, but has %lld channels specified instead of 3.", tensorDesc.sizes[1]); - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, tensorDesc.channelType != kImageTensorChannelTypeBGR8 || tensorDesc.sizes[1] == 3, "Target tensor description expects kImageTensorChannelTypeBGR8, but has %lld channels specified instead of 3.", tensorDesc.sizes[1]); - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, tensorDesc.channelType != kImageTensorChannelTypeGRAY8 || tensorDesc.sizes[1] == 1, "Target tensor description expects kImageTensorChannelTypeGRAY8, but has %lld channels specified instead of 1.", tensorDesc.sizes[1]); WINML_THROW_HR_IF_FALSE_MSG( - E_INVALIDARG, - tensorDesc.channelType == kImageTensorChannelTypeGRAY8 || - tensorDesc.channelType == kImageTensorChannelTypeBGR8 || - tensorDesc.channelType == kImageTensorChannelTypeRGB8, - "Target tensor description expects kImageTensorChannelTypeGRAY8, kImageTensorChannelTypeBGR8, or kImageTensorChannelTypeRGB8 but has %d was specified.", - tensorDesc.channelType); - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, tensorDesc.sizes[2] == (UINT)inputBounds.Height, "Target tensor height (%lld) does not match input height (%lu).", tensorDesc.sizes[2], inputBounds.Height); - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, tensorDesc.sizes[3] == (UINT)inputBounds.Width, "Target tensor width (%lld) does not match input width (%lu).", tensorDesc.sizes[3], inputBounds.Width); + E_INVALIDARG, + tensorDesc.dataType == kImageTensorDataTypeFloat32 || tensorDesc.dataType == kImageTensorDataTypeFloat16, + "Target tensor description must either be kImageTensorDataTypeFloat32, or kImageTensorDataTypeFloat16. %d was supplied.", + tensorDesc.dataType + ); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, + tensorDesc.channelType != kImageTensorChannelTypeRGB8 || tensorDesc.sizes[1] == 3, + "Target tensor description expects kImageTensorChannelTypeRGB8, but has %lld channels specified instead of 3.", + tensorDesc.sizes[1] + ); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, + tensorDesc.channelType != kImageTensorChannelTypeBGR8 || tensorDesc.sizes[1] == 3, + "Target tensor description expects kImageTensorChannelTypeBGR8, but has %lld channels specified instead of 3.", + tensorDesc.sizes[1] + ); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, + tensorDesc.channelType != kImageTensorChannelTypeGRAY8 || tensorDesc.sizes[1] == 1, + "Target tensor description expects kImageTensorChannelTypeGRAY8, but has %lld channels specified instead of 1.", + tensorDesc.sizes[1] + ); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, + tensorDesc.channelType == kImageTensorChannelTypeGRAY8 || tensorDesc.channelType == kImageTensorChannelTypeBGR8 || + tensorDesc.channelType == kImageTensorChannelTypeRGB8, + "Target tensor description expects kImageTensorChannelTypeGRAY8, kImageTensorChannelTypeBGR8, or kImageTensorChannelTypeRGB8 but has %d was specified.", + tensorDesc.channelType + ); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, + tensorDesc.sizes[2] == (UINT)inputBounds.Height, + "Target tensor height (%lld) does not match input height (%lu).", + tensorDesc.sizes[2], + inputBounds.Height + ); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, + tensorDesc.sizes[3] == (UINT)inputBounds.Width, + "Target tensor width (%lld) does not match input width (%lu).", + tensorDesc.sizes[3], + inputBounds.Width + ); // get the byte buffer out of a softwarebitmap BYTE* pData = nullptr; @@ -675,21 +809,23 @@ void VideoFrameToTensorConverter::ConvertSoftwareBitmapToCPUTensor( if (tensorDesc.dataType == _winml::kImageTensorDataTypeFloat32) { WINML_THROW_IF_FAILED(CpuTensorizer::TensorizeData( - channelType, - tensorDesc.channelType, - tensorDesc.pixelRange, - pData, - bufferWidth, - inputBounds, - reinterpret_cast(pCPUTensor))); + channelType, + tensorDesc.channelType, + tensorDesc.pixelRange, + pData, + bufferWidth, + inputBounds, + reinterpret_cast(pCPUTensor) + )); } else if (tensorDesc.dataType == _winml::kImageTensorDataTypeFloat16) { WINML_THROW_IF_FAILED(CpuTensorizer::TensorizeData( - channelType, - tensorDesc.channelType, - tensorDesc.pixelRange, - pData, - bufferWidth, - inputBounds, - reinterpret_cast(pCPUTensor))); + channelType, + tensorDesc.channelType, + tensorDesc.pixelRange, + pData, + bufferWidth, + inputBounds, + reinterpret_cast(pCPUTensor) + )); } -} \ No newline at end of file +} diff --git a/winml/lib/Api.Image/inc/ConverterResourceStore.h b/winml/lib/Api.Image/inc/ConverterResourceStore.h index 18c2eaf137530..ffb413e0b92f3 100644 --- a/winml/lib/Api.Image/inc/ConverterResourceStore.h +++ b/winml/lib/Api.Image/inc/ConverterResourceStore.h @@ -24,11 +24,8 @@ struct ConverterResourceDescription { // 1) the resources have different dimensions // 2) the resources are on different devices // 3) the resources have different pixel formats - if (desc.width != width || - desc.height != height || - desc.luid.HighPart != luid.HighPart || - desc.luid.LowPart != luid.LowPart || - desc.pixel_format != pixel_format) { + if (desc.width != width || desc.height != height || desc.luid.HighPart != luid.HighPart || + desc.luid.LowPart != luid.LowPart || desc.pixel_format != pixel_format) { return false; } @@ -99,8 +96,7 @@ class PoolObjectWrapper { return std::make_shared(std::forward(args)...); } - explicit PoolObjectWrapper(std::shared_ptr&& resources) : m_resources(resources) { - } + explicit PoolObjectWrapper(std::shared_ptr&& resources) : m_resources(resources) {} ~PoolObjectWrapper() { if (m_resources) { @@ -108,13 +104,10 @@ class PoolObjectWrapper { } } - std::shared_ptr Get() { - return m_resources; - } + std::shared_ptr Get() { return m_resources; } private: std::shared_ptr m_resources; }; } // namespace _winml - diff --git a/winml/lib/Api.Image/inc/D3DDeviceCache.h b/winml/lib/Api.Image/inc/D3DDeviceCache.h index d18b950d88ad0..13dd773ccd19d 100644 --- a/winml/lib/Api.Image/inc/D3DDeviceCache.h +++ b/winml/lib/Api.Image/inc/D3DDeviceCache.h @@ -52,7 +52,12 @@ class D3DDeviceCache { ID3D12RootSignature* GetTensorizeRootSignature(); ID3D12RootSignature* GetDetensorizeRootSignature(); - ID3D12PipelineState* GetCachedPipelineState(PipelineStateCacheType type, PipelineStateCacheFormat format_from, PipelineStateCacheFormat format_to, PipelineStateCacheOperation operation); + ID3D12PipelineState* GetCachedPipelineState( + PipelineStateCacheType type, + PipelineStateCacheFormat format_from, + PipelineStateCacheFormat format_to, + PipelineStateCacheOperation operation + ); ID3D12Resource* GetDetensorizeVertexBuffer(_Out_ UINT* vertex_buffer_size); @@ -81,8 +86,12 @@ class D3DDeviceCache { void EnsureSharedFences(); void InitializeCommandQueue(ID3D12Device1* device); - ID3D12PipelineState* CreateTensorizePipelineState(PipelineStateCacheType type, PipelineStateCacheFormat format_from, PipelineStateCacheFormat format_to); - ID3D12PipelineState* CreateDetensorizePipelineState(PipelineStateCacheType type, PipelineStateCacheFormat format_from, PipelineStateCacheFormat format_to); + ID3D12PipelineState* CreateTensorizePipelineState( + PipelineStateCacheType type, PipelineStateCacheFormat format_from, PipelineStateCacheFormat format_to + ); + ID3D12PipelineState* CreateDetensorizePipelineState( + PipelineStateCacheType type, PipelineStateCacheFormat format_from, PipelineStateCacheFormat format_to + ); winrt::com_ptr device_; winrt::com_ptr command_queue_; @@ -95,7 +104,9 @@ class D3DDeviceCache { winrt::com_ptr tensorize_root_signature_; winrt::com_ptr detensorize_root_signature_; - winrt::com_ptr cached_pipeline_state[PipelineStateCacheType::kCount][PipelineStateCacheFormat::kCount][PipelineStateCacheFormat::kCount][PipelineStateCacheOperation::kCount]; + winrt::com_ptr + cached_pipeline_state[PipelineStateCacheType::kCount][PipelineStateCacheFormat::kCount] + [PipelineStateCacheFormat::kCount][PipelineStateCacheOperation::kCount]; winrt::com_ptr detensorize_vertex_buffer_; @@ -116,4 +127,4 @@ class D3DDeviceCache { // initialization happen later, we need make it thread safe. CWinMLLock lock_; }; -} // namespace _winml \ No newline at end of file +} // namespace _winml diff --git a/winml/lib/Api.Image/inc/DisjointBufferHelpers.h b/winml/lib/Api.Image/inc/DisjointBufferHelpers.h index 9e6c354e43326..c83c8c80f7230 100644 --- a/winml/lib/Api.Image/inc/DisjointBufferHelpers.h +++ b/winml/lib/Api.Image/inc/DisjointBufferHelpers.h @@ -8,13 +8,11 @@ namespace _winml { void LoadSpanFromDisjointBuffers( - size_t num_buffers, - std::function(size_t)> get_buffer, - gsl::span& buffer_span); + size_t num_buffers, std::function(size_t)> get_buffer, gsl::span& buffer_span +); void StoreSpanIntoDisjointBuffers( - size_t num_buffers, - std::function(size_t)> get_buffer, - gsl::span& buffer_span); + size_t num_buffers, std::function(size_t)> get_buffer, gsl::span& buffer_span +); -} // namespace _winml \ No newline at end of file +} // namespace _winml diff --git a/winml/lib/Api.Image/inc/ImageConversionHelpers.h b/winml/lib/Api.Image/inc/ImageConversionHelpers.h index 7c0e96d017bf2..8e3dca2ae11e8 100644 --- a/winml/lib/Api.Image/inc/ImageConversionHelpers.h +++ b/winml/lib/Api.Image/inc/ImageConversionHelpers.h @@ -8,48 +8,49 @@ namespace _winml::Imaging { - // This API that takes a video frame and converts it to a video frame of desired format (DXGI_FORMAT_B8G8R8X8_UNORM/BitmapPixelFormat::Bgra8) and size (after any scale/crop operations). - // This should also cover any DX adapter hop (if needed in a multi GPU scenario) and CPU->GPU / GPU->CPU conversion - void ConvertVideoFrameToVideoFrame( - _In_ const wm::IVideoFrame& input_video_frame, - _In_ const wgi::BitmapBounds& input_bounds, - _In_ UINT32 output_width, - _In_ UINT32 output_height, - _Inout_ wm::VideoFrame& output_video_frame); - - // This helper method uses the input parameters do determine if a conversion is necessary - // A conversion is not necessary if - // 1. input bounds cover the entire input bitmap/surface - // 2. desired output size is equal to input size - // 3. (mapping softwarebitmap to softwarebitmap) OR (mapping from d3dsurface to d3dsurface AND the two surfaces are on the same device) - // 4. the input is already in the desired format (BGRA8/B8G8R8X8UIntNormalized) - bool NeedsVideoFrameConversion( - _In_ const wm::IVideoFrame& input_video_frame, - _In_ LUID output_luid, - _In_ const wgi::BitmapBounds& input_bounds, - _In_ UINT32 output_width, - _In_ UINT32 output_height); - - bool SoftwareBitmapFormatSupported(const wgi::SoftwareBitmap& software_bitmap); - bool DirectXPixelFormatSupported(wgdx::DirectXPixelFormat format); - bool FormatSupportedForUAV(_In_ ID3D12Device1* device, _In_ DXGI_FORMAT format); - ImageTensorChannelType GetChannelTypeFromSoftwareBitmap(const wgi::SoftwareBitmap& software_bitmap); - ImageTensorChannelType GetChannelTypeFromDirect3DSurface(const wgdx::Direct3D11::IDirect3DSurface& direct3D_surface); - wgi::BitmapPixelFormat GetBitmapPixelFormatFromChannelType(ImageTensorChannelType channel_type); - wgdx::DirectXPixelFormat GetDirectXPixelFormatFromDXGIFormat(DXGI_FORMAT dxgi_format); - DXGI_FORMAT GetDXGIFormatFromDirectXPixelFormat(_In_ wgdx::DirectXPixelFormat directX_pixel_format); - wgdx::DirectXPixelFormat GetDirectXPixelFormatFromChannelType(_In_ ImageTensorChannelType channel_type); - Microsoft::WRL::ComPtr GetTextureFromDirect3DSurface(const wgdx::Direct3D11::IDirect3DSurface& d3d_surface); - bool TexturesHaveSameDevice(_In_ ID3D11Texture2D* pTexture1, _In_ ID3D11Texture2D* texture2d); - bool TextureIsOnDevice(_In_ ID3D11Texture2D* pTexture, _In_ ID3D11Device* device); - bool VideoFramesHaveSameDimensions(const wm::IVideoFrame& video_frame_1, const wm::IVideoFrame& video_frame_2); - bool VideoFramesHaveSameDevice(const wm::IVideoFrame& video_frame_1, const wm::IVideoFrame& video_frame_2); - - wgdx::Direct3D11::IDirect3DDevice GetDeviceFromDirect3DSurface( - const wgdx::Direct3D11::IDirect3DSurface& d3dSurface); - - constexpr std::array supportedWinMLFormats = { - DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_B8G8R8A8_UNORM, - DXGI_FORMAT_B8G8R8X8_UNORM}; -} // namespace _winml \ No newline at end of file +// This API that takes a video frame and converts it to a video frame of desired format (DXGI_FORMAT_B8G8R8X8_UNORM/BitmapPixelFormat::Bgra8) and size (after any scale/crop operations). +// This should also cover any DX adapter hop (if needed in a multi GPU scenario) and CPU->GPU / GPU->CPU conversion +void ConvertVideoFrameToVideoFrame( + _In_ const wm::IVideoFrame& input_video_frame, + _In_ const wgi::BitmapBounds& input_bounds, + _In_ UINT32 output_width, + _In_ UINT32 output_height, + _Inout_ wm::VideoFrame& output_video_frame +); + +// This helper method uses the input parameters do determine if a conversion is necessary +// A conversion is not necessary if +// 1. input bounds cover the entire input bitmap/surface +// 2. desired output size is equal to input size +// 3. (mapping softwarebitmap to softwarebitmap) OR (mapping from d3dsurface to d3dsurface AND the two surfaces are on the same device) +// 4. the input is already in the desired format (BGRA8/B8G8R8X8UIntNormalized) +bool NeedsVideoFrameConversion( + _In_ const wm::IVideoFrame& input_video_frame, + _In_ LUID output_luid, + _In_ const wgi::BitmapBounds& input_bounds, + _In_ UINT32 output_width, + _In_ UINT32 output_height +); + +bool SoftwareBitmapFormatSupported(const wgi::SoftwareBitmap& software_bitmap); +bool DirectXPixelFormatSupported(wgdx::DirectXPixelFormat format); +bool FormatSupportedForUAV(_In_ ID3D12Device1* device, _In_ DXGI_FORMAT format); +ImageTensorChannelType GetChannelTypeFromSoftwareBitmap(const wgi::SoftwareBitmap& software_bitmap); +ImageTensorChannelType GetChannelTypeFromDirect3DSurface(const wgdx::Direct3D11::IDirect3DSurface& direct3D_surface); +wgi::BitmapPixelFormat GetBitmapPixelFormatFromChannelType(ImageTensorChannelType channel_type); +wgdx::DirectXPixelFormat GetDirectXPixelFormatFromDXGIFormat(DXGI_FORMAT dxgi_format); +DXGI_FORMAT GetDXGIFormatFromDirectXPixelFormat(_In_ wgdx::DirectXPixelFormat directX_pixel_format); +wgdx::DirectXPixelFormat GetDirectXPixelFormatFromChannelType(_In_ ImageTensorChannelType channel_type); +Microsoft::WRL::ComPtr GetTextureFromDirect3DSurface( + const wgdx::Direct3D11::IDirect3DSurface& d3d_surface +); +bool TexturesHaveSameDevice(_In_ ID3D11Texture2D* pTexture1, _In_ ID3D11Texture2D* texture2d); +bool TextureIsOnDevice(_In_ ID3D11Texture2D* pTexture, _In_ ID3D11Device* device); +bool VideoFramesHaveSameDimensions(const wm::IVideoFrame& video_frame_1, const wm::IVideoFrame& video_frame_2); +bool VideoFramesHaveSameDevice(const wm::IVideoFrame& video_frame_1, const wm::IVideoFrame& video_frame_2); + +wgdx::Direct3D11::IDirect3DDevice GetDeviceFromDirect3DSurface(const wgdx::Direct3D11::IDirect3DSurface& d3dSurface); + +constexpr std::array supportedWinMLFormats = { + DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8X8_UNORM}; +} // namespace _winml::Imaging diff --git a/winml/lib/Api.Image/inc/ImageConversionTypes.h b/winml/lib/Api.Image/inc/ImageConversionTypes.h index 5cf8f107343f2..0a67deab41317 100644 --- a/winml/lib/Api.Image/inc/ImageConversionTypes.h +++ b/winml/lib/Api.Image/inc/ImageConversionTypes.h @@ -31,4 +31,4 @@ struct ImageTensorDescription { winml::LearningModelPixelRange pixelRange; int64_t sizes[kImageTensorDimensionCountMax]; }; -} // namespace _winml \ No newline at end of file +} // namespace _winml diff --git a/winml/lib/Api.Image/inc/ImageConverter.h b/winml/lib/Api.Image/inc/ImageConverter.h index 42a28482a4431..686096bff76d9 100644 --- a/winml/lib/Api.Image/inc/ImageConverter.h +++ b/winml/lib/Api.Image/inc/ImageConverter.h @@ -61,17 +61,19 @@ class ImageConverter { void SyncD3D11ToD3D12(_In_ _winml::D3DDeviceCache& device_cache, _In_ ID3D11Texture2D* D3D11_texture); void SyncD3D12ToD3D11(_In_ _winml::D3DDeviceCache& device_cache, _In_ ID3D11Texture2D* texture); void ResetCommandList(_In_ _winml::D3DDeviceCache& device_cache); - Microsoft::WRL::ComPtr FetchOrCreateFenceOnDevice(_In_ _winml::D3DDeviceCache& device_cache, _In_ ID3D11Device* D3D11_device); + Microsoft::WRL::ComPtr FetchOrCreateFenceOnDevice( + _In_ _winml::D3DDeviceCache& device_cache, _In_ ID3D11Device* D3D11_device + ); Microsoft::WRL::ComPtr CreateTextureFromUnsupportedColorFormat( - const wm::IVideoFrame& video_frame, - const wgi::BitmapBounds& input_bounds, - const wgi::BitmapBounds& output_bounds, - wgdx::DirectXPixelFormat new_format); + const wm::IVideoFrame& video_frame, + const wgi::BitmapBounds& input_bounds, + const wgi::BitmapBounds& output_bounds, + wgdx::DirectXPixelFormat new_format + ); static void CopyTextureIntoTexture( - _In_ ID3D11Texture2D* texture_from, - _In_ const wgi::BitmapBounds& input_bounds, - _Inout_ ID3D11Texture2D* texture_to); + _In_ ID3D11Texture2D* texture_from, _In_ const wgi::BitmapBounds& input_bounds, _Inout_ ID3D11Texture2D* texture_to + ); }; -} // namespace _winml \ No newline at end of file +} // namespace _winml diff --git a/winml/lib/Api.Image/inc/NominalRangeConverter.h b/winml/lib/Api.Image/inc/NominalRangeConverter.h index 265b43e74a6b9..0215212ee2bc4 100644 --- a/winml/lib/Api.Image/inc/NominalRangeConverter.h +++ b/winml/lib/Api.Image/inc/NominalRangeConverter.h @@ -32,4 +32,4 @@ class NominalRangeConverter { float scale; int32_t shift; }; -} // namespace _winml \ No newline at end of file +} // namespace _winml diff --git a/winml/lib/Api.Image/inc/TensorToVideoFrameConverter.h b/winml/lib/Api.Image/inc/TensorToVideoFrameConverter.h index b7b8333313054..12f676459293b 100644 --- a/winml/lib/Api.Image/inc/TensorToVideoFrameConverter.h +++ b/winml/lib/Api.Image/inc/TensorToVideoFrameConverter.h @@ -15,29 +15,39 @@ class TensorToVideoFrameConverter : public ImageConverter { // Function takes in a tensor DX12 Resource all compute ops should be completed // converts it to a VideoFrame backed by either a SoftwareBitmap or D3DSurface void DX12TensorToVideoFrame( - _In_ UINT32 batch_index, - _In_ winml::LearningModelSession& session, - _In_ ID3D12Resource* input_tensor, - _In_ const ImageTensorDescription& tensor_description, - _Inout_ wm::VideoFrame& destination_video_frame); + _In_ UINT32 batch_index, + _In_ winml::LearningModelSession& session, + _In_ ID3D12Resource* input_tensor, + _In_ const ImageTensorDescription& tensor_description, + _Inout_ wm::VideoFrame& destination_video_frame + ); // Function takes in a byte pointer to a CPUTensor // converts it to VideoFrame backed by either a SoftwareBitmap or D3DSurface, void SoftwareTensorToVideoFrame( - _In_ winml::LearningModelSession& session, - _In_ BYTE* CPU_tensor_to_convert, - _In_ ImageTensorDescription tensor_description, - _Inout_ wm::VideoFrame& destination_video_frame); + _In_ winml::LearningModelSession& session, + _In_ BYTE* CPU_tensor_to_convert, + _In_ ImageTensorDescription tensor_description, + _Inout_ wm::VideoFrame& destination_video_frame + ); void ConvertBatchedDX12TensorToBuffers( - _In_ ID3D12Resource* input_tensor, - _In_ size_t buffer_size_in_bytes, - _In_ _winml::D3DDeviceCache& device_cache, - _Inout_ const std::vector& buffers); + _In_ ID3D12Resource* input_tensor, + _In_ size_t buffer_size_in_bytes, + _In_ _winml::D3DDeviceCache& device_cache, + _Inout_ const std::vector& buffers + ); private: - GUID _d3d11TextureGUID = {0x14bf1054, 0x6ce7, 0x4c00, {0xa1, 0x32, 0xb0, 0xf2, 0x11, 0x5D, 0xE0, 0x7f}}; // {14BF1054-6CE7-4C00-A132-B0F2115DE07F} - GUID _handleGUID = {0x700148fc, 0xc0cb, 0x4a7e, {0xa7, 0xc0, 0xe7, 0x43, 0xc1, 0x9, 0x9d, 0x62}}; + GUID _d3d11TextureGUID = { + 0x14bf1054, + 0x6ce7, + 0x4c00, + {0xa1, 0x32, 0xb0, 0xf2, 0x11, 0x5D, 0xE0, 0x7f} + }; // {14BF1054-6CE7-4C00-A132-B0F2115DE07F} + GUID _handleGUID = { + 0x700148fc, 0xc0cb, 0x4a7e, {0xa7, 0xc0, 0xe7, 0x43, 0xc1, 0x9, 0x9d, 0x62} + }; ; // {700148FC-C0CB-4A7E-A7C0-E743C1099D62} Microsoft::WRL::ComPtr readback_heap_; Microsoft::WRL::ComPtr output_resource_; @@ -47,38 +57,41 @@ class TensorToVideoFrameConverter : public ImageConverter { Microsoft::WRL::ComPtr ShareD3D12Texture(ID3D12Resource* pResource, ID3D11Device* pDevice); void ConvertGPUTensorToSoftwareBitmap( - _In_ UINT32 batch_index, - _In_ ID3D12Resource* input_tensor, - _In_ _winml::D3DDeviceCache& device_cache, - _In_ const ImageTensorDescription& tensor_description, - _Inout_ wgi::SoftwareBitmap& software_bitmap); + _In_ UINT32 batch_index, + _In_ ID3D12Resource* input_tensor, + _In_ _winml::D3DDeviceCache& device_cache, + _In_ const ImageTensorDescription& tensor_description, + _Inout_ wgi::SoftwareBitmap& software_bitmap + ); void ConvertGPUTensorToDX12Texture( - _In_ UINT32 batch_index, - _In_ ID3D12Resource* input_resource, - _In_ _winml::D3DDeviceCache& device_cache, - _In_ const ImageTensorDescription& tensor_description, - _Inout_ ID3D12Resource* output_resource); + _In_ UINT32 batch_index, + _In_ ID3D12Resource* input_resource, + _In_ _winml::D3DDeviceCache& device_cache, + _In_ const ImageTensorDescription& tensor_description, + _Inout_ ID3D12Resource* output_resource + ); void ConvertDX12TensorToUnsupportedVideoFrameFormat( - _In_ UINT32 batch_index, - _In_ ID3D12Resource* input_tensor, - _In_ _winml::D3DDeviceCache& device_cache, - _In_ const ImageTensorDescription& tensor_description, - _Inout_ wm::VideoFrame& unsupported_video_frame); + _In_ UINT32 batch_index, + _In_ ID3D12Resource* input_tensor, + _In_ _winml::D3DDeviceCache& device_cache, + _In_ const ImageTensorDescription& tensor_description, + _Inout_ wm::VideoFrame& unsupported_video_frame + ); static D3D12_SHADER_RESOURCE_VIEW_DESC TensorToVideoFrameConverter::CreateSRVDescriptor( - const UINT32 batch_index, - const D3D12_RESOURCE_DESC& resource_description, - const ImageTensorDescription& description); + const UINT32 batch_index, const D3D12_RESOURCE_DESC& resource_description, const ImageTensorDescription& description + ); static void ConvertCPUTensorToSoftwareBitmap( - _In_ void* CPU_tensor, - _In_ const ImageTensorDescription& tensor_description, - _Inout_ wgi::SoftwareBitmap& software_bitmap); + _In_ void* CPU_tensor, + _In_ const ImageTensorDescription& tensor_description, + _Inout_ wgi::SoftwareBitmap& software_bitmap + ); static Microsoft::WRL::ComPtr CreateShareableD3D12Texture( - const D3D11_TEXTURE2D_DESC& d3d11Desc, - ID3D12Device* d3d12Device); + const D3D11_TEXTURE2D_DESC& d3d11Desc, ID3D12Device* d3d12Device + ); }; -} // namespace _winml \ No newline at end of file +} // namespace _winml diff --git a/winml/lib/Api.Image/inc/VideoFrameToTensorConverter.h b/winml/lib/Api.Image/inc/VideoFrameToTensorConverter.h index 4f0a010cc367f..e34030bbd6833 100644 --- a/winml/lib/Api.Image/inc/VideoFrameToTensorConverter.h +++ b/winml/lib/Api.Image/inc/VideoFrameToTensorConverter.h @@ -21,12 +21,13 @@ class VideoFrameToTensorConverter : public ImageConverter { // {upperleft X, upperleft Y, width, height} to be turned into a tensor. // If the region of interest is the entire VideoFrame, the input BitmapBounds should describe the entire image. void VideoFrameToDX12Tensor( - _In_ const UINT32 batch_index, - _In_ winml::LearningModelSession& session, - _In_ const wm::IVideoFrame& input_video_frame, - _In_ const wgi::BitmapBounds& input_bounds, - _In_ const ImageTensorDescription& tensor_description, - _Inout_ ID3D12Resource* output_tensor); + _In_ const UINT32 batch_index, + _In_ winml::LearningModelSession& session, + _In_ const wm::IVideoFrame& input_video_frame, + _In_ const wgi::BitmapBounds& input_bounds, + _In_ const ImageTensorDescription& tensor_description, + _Inout_ ID3D12Resource* output_tensor + ); // Function takes in a VideoFrame backed by either a SoftwareBitmap or D3DSurface, // and converts to a tensor returned in a buffer. @@ -34,20 +35,29 @@ class VideoFrameToTensorConverter : public ImageConverter { // {upperleft X, upperleft Y, width, height} to be turned into a tensor. // If the region of interest is the entire VideoFrame, the input BitmapBounds should describe the entire image. void VideoFrameToSoftwareTensor( - _In_ const wm::IVideoFrame& input_video_frame, - _In_ const wgi::BitmapBounds& input_bounds, - _In_ const ImageTensorDescription& tensor_description, - _Out_ BYTE* output_CPU_tensor); + _In_ const wm::IVideoFrame& input_video_frame, + _In_ const wgi::BitmapBounds& input_bounds, + _In_ const ImageTensorDescription& tensor_description, + _Out_ BYTE* output_CPU_tensor + ); void ConvertBuffersToBatchedGPUTensor( - _In_ const std::vector& buffers, - _In_ size_t buffer_size_in_bytes, - _In_ _winml::D3DDeviceCache& device_cache, - _Inout_ ID3D12Resource* output_resource); + _In_ const std::vector& buffers, + _In_ size_t buffer_size_in_bytes, + _In_ _winml::D3DDeviceCache& device_cache, + _Inout_ ID3D12Resource* output_resource + ); private: - GUID d3d11_texture_GUID_ = {0x485e4bb3, 0x3fe8, 0x497b, {0x85, 0x9e, 0xc7, 0x5, 0x18, 0xdb, 0x11, 0x2a}}; // {485E4BB3-3FE8-497B-859E-C70518DB112A} - GUID handle_GUID_ = {0xce43264e, 0x41f7, 0x4882, {0x9e, 0x20, 0xfa, 0xa5, 0x1e, 0x37, 0x64, 0xfc}}; + GUID d3d11_texture_GUID_ = { + 0x485e4bb3, + 0x3fe8, + 0x497b, + {0x85, 0x9e, 0xc7, 0x5, 0x18, 0xdb, 0x11, 0x2a} + }; // {485E4BB3-3FE8-497B-859E-C70518DB112A} + GUID handle_GUID_ = { + 0xce43264e, 0x41f7, 0x4882, {0x9e, 0x20, 0xfa, 0xa5, 0x1e, 0x37, 0x64, 0xfc} + }; ; // CE43264E-41F7-4882-9E20-FAA51E3764FC Microsoft::WRL::ComPtr upload_heap_; Microsoft::WRL::ComPtr input_D3D12_resource_; @@ -56,29 +66,31 @@ class VideoFrameToTensorConverter : public ImageConverter { Microsoft::WRL::ComPtr ShareD3D11Texture(ID3D11Texture2D* pTexture, ID3D12Device* pDevice); void ConvertSoftwareBitmapToGPUTensor( - _In_ const UINT32 batch_index, - _In_ const wm::IVideoFrame& videoFrame, - _In_ _winml::D3DDeviceCache& device_cache, - _In_ const wgi::BitmapBounds& input_bounds, - _In_ const ImageTensorDescription& tensor_description, - _Inout_ ID3D12Resource* pOutputResource); + _In_ const UINT32 batch_index, + _In_ const wm::IVideoFrame& videoFrame, + _In_ _winml::D3DDeviceCache& device_cache, + _In_ const wgi::BitmapBounds& input_bounds, + _In_ const ImageTensorDescription& tensor_description, + _Inout_ ID3D12Resource* pOutputResource + ); void ConvertDX12TextureToGPUTensor( - _In_ const UINT32 batch_index, - _In_ ID3D12Resource* pInputResource, - _In_ _winml::D3DDeviceCache& device_cache, - _In_ const ImageTensorDescription& tensor_description, - _Inout_ ID3D12Resource* output_resource); + _In_ const UINT32 batch_index, + _In_ ID3D12Resource* pInputResource, + _In_ _winml::D3DDeviceCache& device_cache, + _In_ const ImageTensorDescription& tensor_description, + _Inout_ ID3D12Resource* output_resource + ); static D3D12_UNORDERED_ACCESS_VIEW_DESC CreateUAVDescription( - const UINT32 batch_index, - const D3D12_RESOURCE_DESC& resource_description, - const ImageTensorDescription& description); + const UINT32 batch_index, const D3D12_RESOURCE_DESC& resource_description, const ImageTensorDescription& description + ); static void VideoFrameToTensorConverter::ConvertSoftwareBitmapToCPUTensor( - _In_ const wgi::SoftwareBitmap& software_bitmap, - _In_ const ImageTensorDescription& tensor_description, - _In_ const wgi::BitmapBounds& input_bounds, - _Inout_ void* CPU_tensor); + _In_ const wgi::SoftwareBitmap& software_bitmap, + _In_ const ImageTensorDescription& tensor_description, + _In_ const wgi::BitmapBounds& input_bounds, + _Inout_ void* CPU_tensor + ); }; } // namespace _winml diff --git a/winml/lib/Api.Ort/OnnxruntimeCpuSessionBuilder.cpp b/winml/lib/Api.Ort/OnnxruntimeCpuSessionBuilder.cpp index 0668da1b1386e..e86a896ad5e1d 100644 --- a/winml/lib/Api.Ort/OnnxruntimeCpuSessionBuilder.cpp +++ b/winml/lib/Api.Ort/OnnxruntimeCpuSessionBuilder.cpp @@ -14,30 +14,30 @@ HRESULT OnnxruntimeCpuSessionBuilder::RuntimeClassInitialize(OnnxruntimeEngineFa } HRESULT -OnnxruntimeCpuSessionBuilder::CreateSessionOptions( - OrtSessionOptions** options) { +OnnxruntimeCpuSessionBuilder::CreateSessionOptions(OrtSessionOptions** options) { RETURN_HR_IF_NULL(E_POINTER, options); auto ort_api = engine_factory_->UseOrtApi(); auto winml_adapter_api = engine_factory_->UseWinmlAdapterApi(); OrtSessionOptions* ort_options; - RETURN_HR_IF_NOT_OK_MSG(ort_api->CreateSessionOptions(&ort_options), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->CreateSessionOptions(&ort_options), ort_api); auto session_options = UniqueOrtSessionOptions(ort_options, ort_api->ReleaseSessionOptions); // set the graph optimization level to all (used to be called level 3) - RETURN_HR_IF_NOT_OK_MSG(ort_api->SetSessionGraphOptimizationLevel(session_options.get(), GraphOptimizationLevel::ORT_ENABLE_ALL), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + ort_api->SetSessionGraphOptimizationLevel(session_options.get(), GraphOptimizationLevel::ORT_ENABLE_ALL), ort_api + ); #ifndef _WIN64 auto use_arena = false; #else auto use_arena = true; #endif - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->OrtSessionOptionsAppendExecutionProvider_CPU(session_options.get(), use_arena), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->OrtSessionOptionsAppendExecutionProvider_CPU(session_options.get(), use_arena), ort_api + ); // call release() so the underlying OrtSessionOptions object isn't freed *options = session_options.release(); @@ -47,10 +47,11 @@ OnnxruntimeCpuSessionBuilder::CreateSessionOptions( HRESULT OnnxruntimeCpuSessionBuilder::CreateSession( - OrtSessionOptions* options, - OrtThreadPool* inter_op_thread_pool, - OrtThreadPool* intra_op_thread_pool, - OrtSession** session) { + OrtSessionOptions* options, + OrtThreadPool* inter_op_thread_pool, + OrtThreadPool* intra_op_thread_pool, + OrtSession** session +) { RETURN_HR_IF_NULL(E_POINTER, session); auto ort_api = engine_factory_->UseOrtApi(); @@ -60,8 +61,12 @@ OnnxruntimeCpuSessionBuilder::CreateSession( RETURN_IF_FAILED(engine_factory_->GetOrtEnvironment(&ort_env)); OrtSession* ort_session_raw; - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->CreateSessionWithoutModel(ort_env, options, inter_op_thread_pool, intra_op_thread_pool, &ort_session_raw), - engine_factory_->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->CreateSessionWithoutModel( + ort_env, options, inter_op_thread_pool, intra_op_thread_pool, &ort_session_raw + ), + engine_factory_->UseOrtApi() + ); auto ort_session = UniqueOrtSession(ort_session_raw, ort_api->ReleaseSession); @@ -71,13 +76,11 @@ OnnxruntimeCpuSessionBuilder::CreateSession( } HRESULT -OnnxruntimeCpuSessionBuilder::Initialize( - OrtSession* session) { +OnnxruntimeCpuSessionBuilder::Initialize(OrtSession* session) { RETURN_HR_IF_NULL(E_INVALIDARG, session); auto winml_adapter_api = engine_factory_->UseWinmlAdapterApi(); - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->SessionInitialize(session), - engine_factory_->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->SessionInitialize(session), engine_factory_->UseOrtApi()); return S_OK; } diff --git a/winml/lib/Api.Ort/OnnxruntimeCpuSessionBuilder.h b/winml/lib/Api.Ort/OnnxruntimeCpuSessionBuilder.h index f6b0b64aaa60e..dc162fa49b258 100644 --- a/winml/lib/Api.Ort/OnnxruntimeCpuSessionBuilder.h +++ b/winml/lib/Api.Ort/OnnxruntimeCpuSessionBuilder.h @@ -9,26 +9,25 @@ namespace _winml { class OnnxruntimeEngineFactory; -class OnnxruntimeCpuSessionBuilder : public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags, - IOrtSessionBuilder> { +class OnnxruntimeCpuSessionBuilder + : public Microsoft::WRL:: + RuntimeClass, IOrtSessionBuilder> { public: HRESULT RuntimeClassInitialize(OnnxruntimeEngineFactory* engine_factory); - HRESULT STDMETHODCALLTYPE CreateSessionOptions( - OrtSessionOptions** options) override; + HRESULT STDMETHODCALLTYPE CreateSessionOptions(OrtSessionOptions** options) override; HRESULT STDMETHODCALLTYPE CreateSession( - OrtSessionOptions* options, - OrtThreadPool* inter_op_thread_pool, - OrtThreadPool* intra_op_thread_pool, - OrtSession** session) override; + OrtSessionOptions* options, + OrtThreadPool* inter_op_thread_pool, + OrtThreadPool* intra_op_thread_pool, + OrtSession** session + ) override; - HRESULT STDMETHODCALLTYPE Initialize( - OrtSession* session) override; + HRESULT STDMETHODCALLTYPE Initialize(OrtSession* session) override; private: Microsoft::WRL::ComPtr engine_factory_; }; -} // namespace _winml \ No newline at end of file +} // namespace _winml diff --git a/winml/lib/Api.Ort/OnnxruntimeDescriptorConverter.cpp b/winml/lib/Api.Ort/OnnxruntimeDescriptorConverter.cpp index 99bafb836e9ed..13ceac5be2070 100644 --- a/winml/lib/Api.Ort/OnnxruntimeDescriptorConverter.cpp +++ b/winml/lib/Api.Ort/OnnxruntimeDescriptorConverter.cpp @@ -20,11 +20,7 @@ // BitmapPixelFormat constants static const char* c_bitmap_pixel_format_key = "Image.BitmapPixelFormat"; -static const char* c_supported_pixel_formats[] = - { - "Gray8", - "Rgb8", - "Bgr8"}; +static const char* c_supported_pixel_formats[] = {"Gray8", "Rgb8", "Bgr8"}; // ColorSpaceGamma constants // Unlike the other supported value arrays, this is an UNSUPPORTED list. @@ -32,29 +28,22 @@ static const char* c_supported_pixel_formats[] = // color_space_gamma values (Linear), and did not allow the actual supported // values (SRGB). static const char* c_color_space_key = "Image.ColorSpaceGamma"; -static const char* c_unsupported_color_spaces[] = - { - "Linear"}; +static const char* c_unsupported_color_spaces[] = {"Linear"}; // NominalPixelRange constants static const char* c_nominal_range_key = "Image.NominalPixelRange"; -static const char* c_supported_nominal_ranges[] = - { - "NominalRange_0_255", - "Normalized_0_1", - "Normalized_1_1"}; +static const char* c_supported_nominal_ranges[] = {"NominalRange_0_255", "Normalized_0_1", "Normalized_1_1"}; namespace _winml { // Forward declare CreateFeatureDescriptor -static winml::ILearningModelFeatureDescriptor -CreateFeatureDescriptor( - OnnxruntimeEngineFactory* engine_factory, - const OnnxruntimeValueInfoWrapper* feature_descriptor, - const std::unordered_map& metadata); - -static winml::TensorKind -TensorKindFromONNXTensorElementDataType(ONNXTensorElementDataType dataType) { +static winml::ILearningModelFeatureDescriptor CreateFeatureDescriptor( + OnnxruntimeEngineFactory* engine_factory, + const OnnxruntimeValueInfoWrapper* feature_descriptor, + const std::unordered_map& metadata +); + +static winml::TensorKind TensorKindFromONNXTensorElementDataType(ONNXTensorElementDataType dataType) { switch (dataType) { case ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL: { return winml::TensorKind::Boolean; @@ -107,8 +96,7 @@ TensorKindFromONNXTensorElementDataType(ONNXTensorElementDataType dataType) { } } -static std::string -TensorKindToString(winml::TensorKind tensorKind) { +static std::string TensorKindToString(winml::TensorKind tensorKind) { switch (tensorKind) { case winml::TensorKind::Float: { return "float"; @@ -162,46 +150,39 @@ TensorKindToString(winml::TensorKind tensorKind) { } } -static const char* -FetchMetadataValueOrNull( - const std::unordered_map& metadata, - const char* metadata_key) { +static const char* FetchMetadataValueOrNull( + const std::unordered_map& metadata, const char* metadata_key +) { auto metadata_pair = metadata.find(metadata_key); auto metadata_exists = metadata_pair != metadata.end(); - return metadata_exists - ? metadata_pair->second.c_str() - : nullptr; + return metadata_exists ? metadata_pair->second.c_str() : nullptr; } template -static bool -IsValueInRange( - const char* value, - const char* (&range)[TNumSupportedValues]) { +static bool IsValueInRange(const char* value, const char* (&range)[TNumSupportedValues]) { if (value) { auto range_end = range + TNumSupportedValues; - auto found = std::find_if( - range, - range_end, - [&](auto& supported_value) { - return std::strcmp(supported_value, value) == 0; - }) != range_end; + auto found = std::find_if(range, range_end, [&](auto& supported_value) { + return std::strcmp(supported_value, value) == 0; + }) != range_end; return found; } return false; } -enum class RangeType { AllowedList, - BlockedList }; +enum class RangeType { + AllowedList, + BlockedList +}; template -static bool -CheckImageMetadataIsUnsupported( - const std::unordered_map& metadata, - const char* metadata_key, - const char* (&range)[TNumSupportedValues], - std::ostringstream& log_stream, - RangeType range_type = RangeType::AllowedList) { +static bool CheckImageMetadataIsUnsupported( + const std::unordered_map& metadata, + const char* metadata_key, + const char* (&range)[TNumSupportedValues], + std::ostringstream& log_stream, + RangeType range_type = RangeType::AllowedList +) { // Check is the model has pixel format metadata. // This is retrieved from the metadata (which is global to the model). // We only consider formats that are supported in the image converter. @@ -223,12 +204,7 @@ CheckImageMetadataIsUnsupported( // log if (is_unsupported) { - log_stream << "Unsupported " - << metadata_key - << ": " - << value - << " found." - << std::endl; + log_stream << "Unsupported " << metadata_key << ": " << value << " found." << std::endl; } return is_unsupported; @@ -238,12 +214,11 @@ CheckImageMetadataIsUnsupported( return false; } -static std::pair -CreateBitmapPixelFormatAndAlphaModeInfo( - const char* pixel_format) { +static std::pair CreateBitmapPixelFormatAndAlphaModeInfo( + const char* pixel_format +) { if (pixel_format) { - auto comparator = - std::bind(std::strcmp, pixel_format, std::placeholders::_1); + auto comparator = std::bind(std::strcmp, pixel_format, std::placeholders::_1); if (0 == comparator("Gray8")) { return {wgi::BitmapPixelFormat::Gray8, wgi::BitmapAlphaMode::Premultiplied}; @@ -262,11 +237,9 @@ CreateBitmapPixelFormatAndAlphaModeInfo( return {wgi::BitmapPixelFormat::Bgra8, wgi::BitmapAlphaMode::Premultiplied}; } -static winmlp::ImageColorSpaceGamma -CreateImageColorSpaceGamma(const char* color_space_gamma) { +static winmlp::ImageColorSpaceGamma CreateImageColorSpaceGamma(const char* color_space_gamma) { if (color_space_gamma) { - auto comparator = - std::bind(std::strcmp, color_space_gamma, std::placeholders::_1); + auto comparator = std::bind(std::strcmp, color_space_gamma, std::placeholders::_1); if (0 == comparator("Linear")) { return winmlp::ImageColorSpaceGamma::ImageColorSpaceGamma_Linear; @@ -279,11 +252,9 @@ CreateImageColorSpaceGamma(const char* color_space_gamma) { return winmlp::ImageColorSpaceGamma::ImageColorSpaceGamma_SRGB; } -static winml::LearningModelPixelRange -CreateImageNominalPixelRange(const char* nominal_range) { +static winml::LearningModelPixelRange CreateImageNominalPixelRange(const char* nominal_range) { if (nominal_range) { - auto comparator = - std::bind(std::strcmp, nominal_range, std::placeholders::_1); + auto comparator = std::bind(std::strcmp, nominal_range, std::placeholders::_1); if (0 == comparator("NominalRange_0_255")) { return winml::LearningModelPixelRange::ZeroTo255; @@ -298,19 +269,22 @@ CreateImageNominalPixelRange(const char* nominal_range) { return winml::LearningModelPixelRange::ZeroTo255; } -enum class TensorType { Tensor_Data, - Tensor_Image, - Tensor_Data_UnsupportedImageMetadata }; - -static TensorType -GetTensorType( - OnnxruntimeEngineFactory* engine_factory, - OrtTypeInfo* type_info, - const std::unordered_map& metadata) { +enum class TensorType { + Tensor_Data, + Tensor_Image, + Tensor_Data_UnsupportedImageMetadata +}; + +static TensorType GetTensorType( + OnnxruntimeEngineFactory* engine_factory, + OrtTypeInfo* type_info, + const std::unordered_map& metadata +) { const char* denotation; size_t len; - THROW_IF_NOT_OK_MSG(engine_factory->UseOrtApi()->GetDenotationFromTypeInfo(type_info, &denotation, &len), - engine_factory->UseOrtApi()); + THROW_IF_NOT_OK_MSG( + engine_factory->UseOrtApi()->GetDenotationFromTypeInfo(type_info, &denotation, &len), engine_factory->UseOrtApi() + ); constexpr char c_image[] = "IMAGE"; auto has_image_denotation = strncmp(denotation, c_image, _countof(c_image)) == 0; @@ -325,18 +299,20 @@ GetTensorType( // Check if the tensor value_info_proto is of type float. // IMAGE tensors MUST be of type float const OrtTensorTypeAndShapeInfo* tensor_info; - THROW_IF_NOT_OK_MSG(engine_factory->UseOrtApi()->CastTypeInfoToTensorInfo(type_info, &tensor_info), - engine_factory->UseOrtApi()); + THROW_IF_NOT_OK_MSG( + engine_factory->UseOrtApi()->CastTypeInfoToTensorInfo(type_info, &tensor_info), engine_factory->UseOrtApi() + ); ONNXTensorElementDataType tensor_element_data_type; - THROW_IF_NOT_OK_MSG(engine_factory->UseOrtApi()->GetTensorElementType(tensor_info, &tensor_element_data_type), - engine_factory->UseOrtApi()); + THROW_IF_NOT_OK_MSG( + engine_factory->UseOrtApi()->GetTensorElementType(tensor_info, &tensor_element_data_type), + engine_factory->UseOrtApi() + ); auto tensor_kind = _winml::TensorKindFromONNXTensorElementDataType(tensor_element_data_type); auto is_float_tensor = tensor_kind == winml::TensorKind::Float; if (!is_float_tensor) { - log_stream << "Unsupported image with " << TensorKindToString(tensor_kind) - << " found." << std::endl; + log_stream << "Unsupported image with " << TensorKindToString(tensor_kind) << " found." << std::endl; } // Check if the model has pixel format and color space metadata. @@ -344,11 +320,9 @@ GetTensorType( // We only consider formats that are supported in the image converter. // If not supported you MUST bind as a tensor. auto has_unsupported_pixel_format = - CheckImageMetadataIsUnsupported(metadata, c_bitmap_pixel_format_key, - c_supported_pixel_formats, log_stream); + CheckImageMetadataIsUnsupported(metadata, c_bitmap_pixel_format_key, c_supported_pixel_formats, log_stream); auto has_unsupported_nominal_range = - CheckImageMetadataIsUnsupported(metadata, c_nominal_range_key, - c_supported_nominal_ranges, log_stream); + CheckImageMetadataIsUnsupported(metadata, c_nominal_range_key, c_supported_nominal_ranges, log_stream); // Unfortunately, the original RS5 implementation blocked unsupported // color_space_gamma values (Linear), and did not allow the actual supported @@ -356,97 +330,103 @@ GetTensorType( // // So to keep parity with RS5, we continue to check against a list of // unsupported color spaces. - auto has_unsupported_color_space_gamma = - CheckImageMetadataIsUnsupported(metadata, c_color_space_key, - c_unsupported_color_spaces, log_stream, RangeType::BlockedList); + auto has_unsupported_color_space_gamma = CheckImageMetadataIsUnsupported( + metadata, c_color_space_key, c_unsupported_color_spaces, log_stream, RangeType::BlockedList + ); bool has_unsupported_image_metadata = - has_unsupported_pixel_format || - has_unsupported_color_space_gamma || - has_unsupported_nominal_range; + has_unsupported_pixel_format || has_unsupported_color_space_gamma || has_unsupported_nominal_range; auto is_tensor_improperly_annotated_as_image = - has_image_denotation && - (!is_float_tensor || - has_unsupported_image_metadata); + has_image_denotation && (!is_float_tensor || has_unsupported_image_metadata); if (is_tensor_improperly_annotated_as_image) { - TraceLoggingWrite(winml_trace_logging_provider, - "WinMLInputValidation", - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), - TraceLoggingLevel(WINEVENT_LEVEL_WARNING), - TraceLoggingOpcode(EVENT_TRACE_TYPE_INFO), - TraceLoggingString(log_stream.str().c_str())); + TraceLoggingWrite( + winml_trace_logging_provider, + "WinMLInputValidation", + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), + TraceLoggingLevel(WINEVENT_LEVEL_WARNING), + TraceLoggingOpcode(EVENT_TRACE_TYPE_INFO), + TraceLoggingString(log_stream.str().c_str()) + ); } - auto is_valid_image_tensor = - has_image_denotation && is_float_tensor && !has_unsupported_image_metadata; + auto is_valid_image_tensor = has_image_denotation && is_float_tensor && !has_unsupported_image_metadata; - return is_valid_image_tensor - ? TensorType::Tensor_Image - : has_unsupported_image_metadata - ? TensorType::Tensor_Data_UnsupportedImageMetadata - : TensorType::Tensor_Data; + return is_valid_image_tensor ? TensorType::Tensor_Image + : has_unsupported_image_metadata ? TensorType::Tensor_Data_UnsupportedImageMetadata + : TensorType::Tensor_Data; } -static winml::ILearningModelFeatureDescriptor -CreateTensorFeatureDescriptor( - OnnxruntimeEngineFactory* engine_factory, - const OnnxruntimeValueInfoWrapper* feature_descriptor, - const std::unordered_map& metadata, - bool has_unsupported_image_metadata) { +static winml::ILearningModelFeatureDescriptor CreateTensorFeatureDescriptor( + OnnxruntimeEngineFactory* engine_factory, + const OnnxruntimeValueInfoWrapper* feature_descriptor, + const std::unordered_map& metadata, + bool has_unsupported_image_metadata +) { auto type_info = feature_descriptor->type_info_.get(); const OrtTensorTypeAndShapeInfo* tensor_info; - THROW_IF_NOT_OK_MSG(engine_factory->UseOrtApi()->CastTypeInfoToTensorInfo(type_info, &tensor_info), - engine_factory->UseOrtApi()); + THROW_IF_NOT_OK_MSG( + engine_factory->UseOrtApi()->CastTypeInfoToTensorInfo(type_info, &tensor_info), engine_factory->UseOrtApi() + ); size_t num_dims; - THROW_IF_NOT_OK_MSG(engine_factory->UseOrtApi()->GetDimensionsCount(tensor_info, &num_dims), - engine_factory->UseOrtApi()); + THROW_IF_NOT_OK_MSG( + engine_factory->UseOrtApi()->GetDimensionsCount(tensor_info, &num_dims), engine_factory->UseOrtApi() + ); auto shape = std::vector(num_dims); - THROW_IF_NOT_OK_MSG(engine_factory->UseOrtApi()->GetDimensions(tensor_info, shape.data(), shape.size()), - engine_factory->UseOrtApi()); + THROW_IF_NOT_OK_MSG( + engine_factory->UseOrtApi()->GetDimensions(tensor_info, shape.data(), shape.size()), engine_factory->UseOrtApi() + ); ONNXTensorElementDataType tensor_element_data_type; - THROW_IF_NOT_OK_MSG(engine_factory->UseOrtApi()->GetTensorElementType(tensor_info, &tensor_element_data_type), - engine_factory->UseOrtApi()); + THROW_IF_NOT_OK_MSG( + engine_factory->UseOrtApi()->GetTensorElementType(tensor_info, &tensor_element_data_type), + engine_factory->UseOrtApi() + ); auto kind = _winml::TensorKindFromONNXTensorElementDataType(tensor_element_data_type); auto descriptor = winrt::make( - feature_descriptor->name_, - feature_descriptor->description_, // description - kind, - shape, - feature_descriptor->name_length_ > 0, // is_required - has_unsupported_image_metadata); + feature_descriptor->name_, + feature_descriptor->description_, // description + kind, + shape, + feature_descriptor->name_length_ > 0, // is_required + has_unsupported_image_metadata + ); return descriptor.as(); } -static winml::ILearningModelFeatureDescriptor -CreateImageFeatureDescriptor( - OnnxruntimeEngineFactory* engine_factory, - const OnnxruntimeValueInfoWrapper* feature_descriptor, - const std::unordered_map& metadata) { +static winml::ILearningModelFeatureDescriptor CreateImageFeatureDescriptor( + OnnxruntimeEngineFactory* engine_factory, + const OnnxruntimeValueInfoWrapper* feature_descriptor, + const std::unordered_map& metadata +) { auto type_info = feature_descriptor->type_info_.get(); const OrtTensorTypeAndShapeInfo* tensor_info; - THROW_IF_NOT_OK_MSG(engine_factory->UseOrtApi()->CastTypeInfoToTensorInfo(type_info, &tensor_info), - engine_factory->UseOrtApi()); + THROW_IF_NOT_OK_MSG( + engine_factory->UseOrtApi()->CastTypeInfoToTensorInfo(type_info, &tensor_info), engine_factory->UseOrtApi() + ); size_t num_dims; - THROW_IF_NOT_OK_MSG(engine_factory->UseOrtApi()->GetDimensionsCount(tensor_info, &num_dims), - engine_factory->UseOrtApi()); + THROW_IF_NOT_OK_MSG( + engine_factory->UseOrtApi()->GetDimensionsCount(tensor_info, &num_dims), engine_factory->UseOrtApi() + ); auto shape = std::vector(num_dims); - THROW_IF_NOT_OK_MSG(engine_factory->UseOrtApi()->GetDimensions(tensor_info, shape.data(), shape.size()), - engine_factory->UseOrtApi()); + THROW_IF_NOT_OK_MSG( + engine_factory->UseOrtApi()->GetDimensions(tensor_info, shape.data(), shape.size()), engine_factory->UseOrtApi() + ); ONNXTensorElementDataType tensor_element_data_type; - THROW_IF_NOT_OK_MSG(engine_factory->UseOrtApi()->GetTensorElementType(tensor_info, &tensor_element_data_type), - engine_factory->UseOrtApi()); + THROW_IF_NOT_OK_MSG( + engine_factory->UseOrtApi()->GetTensorElementType(tensor_info, &tensor_element_data_type), + engine_factory->UseOrtApi() + ); auto kind = _winml::TensorKindFromONNXTensorElementDataType(tensor_element_data_type); // pixel format and alpha @@ -470,41 +450,45 @@ CreateImageFeatureDescriptor( auto height = static_cast(shape[c_height_dimension]); auto width = static_cast(shape[c_width_dimension]); auto descriptor = winrt::make( - feature_descriptor->name_, - feature_descriptor->description_, - kind, - shape, - feature_descriptor->name_length_ > 0, // is_required - pixel_format, - alpha_mode, - width, - height, - nominal_range, - color_space_gamma); + feature_descriptor->name_, + feature_descriptor->description_, + kind, + shape, + feature_descriptor->name_length_ > 0, // is_required + pixel_format, + alpha_mode, + width, + height, + nominal_range, + color_space_gamma + ); return descriptor.as(); } -static winml::ILearningModelFeatureDescriptor -CreateMapFeatureDescriptor( - OnnxruntimeEngineFactory* engine_factory, - const OnnxruntimeValueInfoWrapper* feature_descriptor, - const std::unordered_map& metadata) { +static winml::ILearningModelFeatureDescriptor CreateMapFeatureDescriptor( + OnnxruntimeEngineFactory* engine_factory, + const OnnxruntimeValueInfoWrapper* feature_descriptor, + const std::unordered_map& metadata +) { auto type_info = feature_descriptor->type_info_.get(); const OrtMapTypeInfo* map_info; - THROW_IF_NOT_OK_MSG(engine_factory->UseOrtApi()->CastTypeInfoToMapTypeInfo(type_info, &map_info), - engine_factory->UseOrtApi()); + THROW_IF_NOT_OK_MSG( + engine_factory->UseOrtApi()->CastTypeInfoToMapTypeInfo(type_info, &map_info), engine_factory->UseOrtApi() + ); ONNXTensorElementDataType map_key_data_type; - THROW_IF_NOT_OK_MSG(engine_factory->UseOrtApi()->GetMapKeyType(map_info, &map_key_data_type), - engine_factory->UseOrtApi()); + THROW_IF_NOT_OK_MSG( + engine_factory->UseOrtApi()->GetMapKeyType(map_info, &map_key_data_type), engine_factory->UseOrtApi() + ); auto key_kind = _winml::TensorKindFromONNXTensorElementDataType(map_key_data_type); OrtTypeInfo* map_value_type_info; - THROW_IF_NOT_OK_MSG(engine_factory->UseOrtApi()->GetMapValueType(map_info, &map_value_type_info), - engine_factory->UseOrtApi()); + THROW_IF_NOT_OK_MSG( + engine_factory->UseOrtApi()->GetMapValueType(map_info, &map_value_type_info), engine_factory->UseOrtApi() + ); UniqueOrtTypeInfo unique_map_value_type_info(map_value_type_info, engine_factory->UseOrtApi()->ReleaseTypeInfo); @@ -515,34 +499,39 @@ CreateMapFeatureDescriptor( dummy_ort_value_info_wrapper.name_length_ = feature_descriptor->name_length_; dummy_ort_value_info_wrapper.type_info_ = std::move(unique_map_value_type_info); - auto value_descriptor = - CreateFeatureDescriptor(engine_factory, &dummy_ort_value_info_wrapper, metadata); + auto value_descriptor = CreateFeatureDescriptor(engine_factory, &dummy_ort_value_info_wrapper, metadata); auto descriptor = winrt::make( - feature_descriptor->name_, - feature_descriptor->description_, - feature_descriptor->name_length_ > 0, // is_required - key_kind, - value_descriptor); + feature_descriptor->name_, + feature_descriptor->description_, + feature_descriptor->name_length_ > 0, // is_required + key_kind, + value_descriptor + ); return descriptor.as(); } -static winml::ILearningModelFeatureDescriptor -CreateSequenceFeatureDescriptor( - OnnxruntimeEngineFactory* engine_factory, - const OnnxruntimeValueInfoWrapper* feature_descriptor, - const std::unordered_map& metadata) { +static winml::ILearningModelFeatureDescriptor CreateSequenceFeatureDescriptor( + OnnxruntimeEngineFactory* engine_factory, + const OnnxruntimeValueInfoWrapper* feature_descriptor, + const std::unordered_map& metadata +) { auto type_info = feature_descriptor->type_info_.get(); const OrtSequenceTypeInfo* sequence_info; - THROW_IF_NOT_OK_MSG(engine_factory->UseOrtApi()->CastTypeInfoToSequenceTypeInfo(type_info, &sequence_info), - engine_factory->UseOrtApi()); + THROW_IF_NOT_OK_MSG( + engine_factory->UseOrtApi()->CastTypeInfoToSequenceTypeInfo(type_info, &sequence_info), engine_factory->UseOrtApi() + ); OrtTypeInfo* sequence_element_type_info; - THROW_IF_NOT_OK_MSG(engine_factory->UseOrtApi()->GetSequenceElementType(sequence_info, &sequence_element_type_info), - engine_factory->UseOrtApi()); + THROW_IF_NOT_OK_MSG( + engine_factory->UseOrtApi()->GetSequenceElementType(sequence_info, &sequence_element_type_info), + engine_factory->UseOrtApi() + ); - UniqueOrtTypeInfo unique_sequence_element_type_info(sequence_element_type_info, engine_factory->UseOrtApi()->ReleaseTypeInfo); + UniqueOrtTypeInfo unique_sequence_element_type_info( + sequence_element_type_info, engine_factory->UseOrtApi()->ReleaseTypeInfo + ); OnnxruntimeValueInfoWrapper dummy_ort_value_info_wrapper; dummy_ort_value_info_wrapper.description_ = feature_descriptor->description_; @@ -551,58 +540,47 @@ CreateSequenceFeatureDescriptor( dummy_ort_value_info_wrapper.name_length_ = feature_descriptor->name_length_; dummy_ort_value_info_wrapper.type_info_ = std::move(unique_sequence_element_type_info); - auto element_descriptor = - CreateFeatureDescriptor(engine_factory, &dummy_ort_value_info_wrapper, metadata); + auto element_descriptor = CreateFeatureDescriptor(engine_factory, &dummy_ort_value_info_wrapper, metadata); auto descriptor = winrt::make( - feature_descriptor->name_, - feature_descriptor->description_, - feature_descriptor->name_length_ > 0, // is_required - element_descriptor); + feature_descriptor->name_, + feature_descriptor->description_, + feature_descriptor->name_length_ > 0, // is_required + element_descriptor + ); return descriptor.as(); } -static winml::ILearningModelFeatureDescriptor -CreateFeatureDescriptor( - OnnxruntimeEngineFactory* engine_factory, - const OnnxruntimeValueInfoWrapper* feature_descriptor, - const std::unordered_map& metadata) { +static winml::ILearningModelFeatureDescriptor CreateFeatureDescriptor( + OnnxruntimeEngineFactory* engine_factory, + const OnnxruntimeValueInfoWrapper* feature_descriptor, + const std::unordered_map& metadata +) { auto type_info = feature_descriptor->type_info_.get(); ONNXType onnx_type; - THROW_IF_NOT_OK_MSG(engine_factory->UseOrtApi()->GetOnnxTypeFromTypeInfo(type_info, &onnx_type), - engine_factory->UseOrtApi()); + THROW_IF_NOT_OK_MSG( + engine_factory->UseOrtApi()->GetOnnxTypeFromTypeInfo(type_info, &onnx_type), engine_factory->UseOrtApi() + ); switch (onnx_type) { case ONNXType::ONNX_TYPE_TENSOR: { auto tensor_type = GetTensorType(engine_factory, type_info, metadata); if (tensor_type == TensorType::Tensor_Image) { - return CreateImageFeatureDescriptor( - engine_factory, - feature_descriptor, - metadata); + return CreateImageFeatureDescriptor(engine_factory, feature_descriptor, metadata); } else { - auto has_unsupported_image_metadata = - tensor_type == TensorType::Tensor_Data_UnsupportedImageMetadata; + auto has_unsupported_image_metadata = tensor_type == TensorType::Tensor_Data_UnsupportedImageMetadata; return CreateTensorFeatureDescriptor( - engine_factory, - feature_descriptor, - metadata, - has_unsupported_image_metadata); + engine_factory, feature_descriptor, metadata, has_unsupported_image_metadata + ); } } case ONNXType::ONNX_TYPE_MAP: { - return CreateMapFeatureDescriptor( - engine_factory, - feature_descriptor, - metadata); + return CreateMapFeatureDescriptor(engine_factory, feature_descriptor, metadata); } case ONNXType::ONNX_TYPE_SEQUENCE: { - return CreateSequenceFeatureDescriptor( - engine_factory, - feature_descriptor, - metadata); + return CreateSequenceFeatureDescriptor(engine_factory, feature_descriptor, metadata); } default: throw winrt::hresult_not_implemented(); @@ -610,14 +588,18 @@ CreateFeatureDescriptor( } OnnxruntimeDescriptorConverter::OnnxruntimeDescriptorConverter( - OnnxruntimeEngineFactory* engine_factory, - const std::unordered_map& metadata) : engine_factory_(engine_factory), metadata_(metadata) {} + OnnxruntimeEngineFactory* engine_factory, const std::unordered_map& metadata +) + : engine_factory_(engine_factory), + metadata_(metadata) { +} -wfc::IVector -OnnxruntimeDescriptorConverter::ConvertToLearningModelDescriptors(const OnnxruntimeValueInfoWrapper* descriptors, size_t num_descriptors) { +wfc::IVector OnnxruntimeDescriptorConverter::ConvertToLearningModelDescriptors( + const OnnxruntimeValueInfoWrapper* descriptors, size_t num_descriptors +) { auto features = winrt::single_threaded_vector(); - for (size_t i = 0; i < num_descriptors; i++) { + for (size_t i = 0; i < num_descriptors; i++) { const auto& descriptor = descriptors[i]; auto learning_model_descriptor = _winml::CreateFeatureDescriptor(engine_factory_.Get(), &descriptor, metadata_); features.Append(learning_model_descriptor); diff --git a/winml/lib/Api.Ort/OnnxruntimeDescriptorConverter.h b/winml/lib/Api.Ort/OnnxruntimeDescriptorConverter.h index f16749b5ea88d..e532aa7e89a7e 100644 --- a/winml/lib/Api.Ort/OnnxruntimeDescriptorConverter.h +++ b/winml/lib/Api.Ort/OnnxruntimeDescriptorConverter.h @@ -19,15 +19,16 @@ class OnnxruntimeEngineFactory; struct OnnxruntimeDescriptorConverter { OnnxruntimeDescriptorConverter( - OnnxruntimeEngineFactory* engine_factory, - const std::unordered_map& model_metadata); + OnnxruntimeEngineFactory* engine_factory, const std::unordered_map& model_metadata + ); - wfc::IVector - ConvertToLearningModelDescriptors(const OnnxruntimeValueInfoWrapper* descriptors, size_t num_descriptors); + wfc::IVector ConvertToLearningModelDescriptors( + const OnnxruntimeValueInfoWrapper* descriptors, size_t num_descriptors + ); private: Microsoft::WRL::ComPtr engine_factory_; const std::unordered_map& metadata_; }; -} // namespace _winml \ No newline at end of file +} // namespace _winml diff --git a/winml/lib/Api.Ort/OnnxruntimeDmlSessionBuilder.cpp b/winml/lib/Api.Ort/OnnxruntimeDmlSessionBuilder.cpp index a02c6a0431ba6..4997e07b037c8 100644 --- a/winml/lib/Api.Ort/OnnxruntimeDmlSessionBuilder.cpp +++ b/winml/lib/Api.Ort/OnnxruntimeDmlSessionBuilder.cpp @@ -12,7 +12,9 @@ using namespace _winml; -HRESULT OnnxruntimeDmlSessionBuilder::RuntimeClassInitialize(OnnxruntimeEngineFactory* engine_factory, ID3D12Device* device, ID3D12CommandQueue* queue, bool metacommands_enabled) { +HRESULT OnnxruntimeDmlSessionBuilder::RuntimeClassInitialize( + OnnxruntimeEngineFactory* engine_factory, ID3D12Device* device, ID3D12CommandQueue* queue, bool metacommands_enabled +) { engine_factory_ = engine_factory; device_.copy_from(device); queue_.copy_from(queue); @@ -21,38 +23,41 @@ HRESULT OnnxruntimeDmlSessionBuilder::RuntimeClassInitialize(OnnxruntimeEngineFa } HRESULT -OnnxruntimeDmlSessionBuilder::CreateSessionOptions( - OrtSessionOptions** options) { +OnnxruntimeDmlSessionBuilder::CreateSessionOptions(OrtSessionOptions** options) { RETURN_HR_IF_NULL(E_POINTER, options); auto ort_api = engine_factory_->UseOrtApi(); auto winml_adapter_api = engine_factory_->UseWinmlAdapterApi(); OrtSessionOptions* ort_options; - RETURN_HR_IF_NOT_OK_MSG(ort_api->CreateSessionOptions(&ort_options), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->CreateSessionOptions(&ort_options), ort_api); auto session_options = UniqueOrtSessionOptions(ort_options, ort_api->ReleaseSessionOptions); // set the graph optimization level to all (used to be called level 3) - RETURN_HR_IF_NOT_OK_MSG(ort_api->SetSessionGraphOptimizationLevel(session_options.get(), GraphOptimizationLevel::ORT_ENABLE_ALL), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + ort_api->SetSessionGraphOptimizationLevel(session_options.get(), GraphOptimizationLevel::ORT_ENABLE_ALL), ort_api + ); // Disable the mem pattern session option for DML. It will cause problems with how memory is allocated. - RETURN_HR_IF_NOT_OK_MSG(ort_api->DisableMemPattern(session_options.get()), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->DisableMemPattern(session_options.get()), ort_api); // Request the dml ep - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->OrtSessionOptionsAppendExecutionProvider_DML(session_options.get(), device_.get(), queue_.get(), metacommands_enabled_), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->OrtSessionOptionsAppendExecutionProvider_DML( + session_options.get(), device_.get(), queue_.get(), metacommands_enabled_ + ), + ort_api + ); #ifndef _WIN64 auto use_arena = false; #else auto use_arena = true; #endif - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->OrtSessionOptionsAppendExecutionProvider_CPU(session_options.get(), use_arena), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->OrtSessionOptionsAppendExecutionProvider_CPU(session_options.get(), use_arena), ort_api + ); // call release() so the underlying OrtSessionOptions object isn't freed *options = session_options.release(); @@ -61,10 +66,11 @@ OnnxruntimeDmlSessionBuilder::CreateSessionOptions( } HRESULT OnnxruntimeDmlSessionBuilder::CreateSession( - OrtSessionOptions* options, - OrtThreadPool* inter_op_thread_pool, - OrtThreadPool* intra_op_thread_pool, - OrtSession** session) { + OrtSessionOptions* options, + OrtThreadPool* inter_op_thread_pool, + OrtThreadPool* intra_op_thread_pool, + OrtSession** session +) { RETURN_HR_IF_NULL(E_POINTER, session); auto ort_api = engine_factory_->UseOrtApi(); @@ -74,8 +80,12 @@ HRESULT OnnxruntimeDmlSessionBuilder::CreateSession( RETURN_IF_FAILED(engine_factory_->GetOrtEnvironment(&ort_env)); OrtSession* ort_session_raw; - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->CreateSessionWithoutModel(ort_env, options, inter_op_thread_pool, intra_op_thread_pool, &ort_session_raw), - engine_factory_->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->CreateSessionWithoutModel( + ort_env, options, inter_op_thread_pool, intra_op_thread_pool, &ort_session_raw + ), + engine_factory_->UseOrtApi() + ); auto ort_session = UniqueOrtSession(ort_session_raw, ort_api->ReleaseSession); *session = ort_session.release(); @@ -83,26 +93,23 @@ HRESULT OnnxruntimeDmlSessionBuilder::CreateSession( return S_OK; } -HRESULT OnnxruntimeDmlSessionBuilder::Initialize( - OrtSession* session) { +HRESULT OnnxruntimeDmlSessionBuilder::Initialize(OrtSession* session) { RETURN_HR_IF_NULL(E_INVALIDARG, session); auto winml_adapter_api = engine_factory_->UseWinmlAdapterApi(); - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->SessionInitialize(session), - engine_factory_->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->SessionInitialize(session), engine_factory_->UseOrtApi()); OrtExecutionProvider* ort_provider; - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->SessionGetExecutionProvider(session, 0, &ort_provider), - engine_factory_->UseOrtApi()); - - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->DmlExecutionProviderSetDefaultRoundingMode(ort_provider, true), - engine_factory_->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->SessionGetExecutionProvider(session, 0, &ort_provider), engine_factory_->UseOrtApi() + ); // Flush the D3D12 work from the DML execution provider - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->DmlExecutionProviderFlushContext(ort_provider), - engine_factory_->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->DmlExecutionProviderFlushContext(ort_provider), engine_factory_->UseOrtApi() + ); return S_OK; } -#endif USE_DML \ No newline at end of file +#endif USE_DML diff --git a/winml/lib/Api.Ort/OnnxruntimeDmlSessionBuilder.h b/winml/lib/Api.Ort/OnnxruntimeDmlSessionBuilder.h index 8ea4399ebfb35..ad9442fb98b83 100644 --- a/winml/lib/Api.Ort/OnnxruntimeDmlSessionBuilder.h +++ b/winml/lib/Api.Ort/OnnxruntimeDmlSessionBuilder.h @@ -9,23 +9,27 @@ namespace _winml { class OnnxruntimeEngineFactory; -class OnnxruntimeDmlSessionBuilder : public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags, - IOrtSessionBuilder> { +class OnnxruntimeDmlSessionBuilder + : public Microsoft::WRL:: + RuntimeClass, IOrtSessionBuilder> { public: - HRESULT RuntimeClassInitialize(OnnxruntimeEngineFactory* engine_factory, ID3D12Device* device, ID3D12CommandQueue* queue, bool metacommands_enabled_); + HRESULT RuntimeClassInitialize( + OnnxruntimeEngineFactory* engine_factory, + ID3D12Device* device, + ID3D12CommandQueue* queue, + bool metacommands_enabled_ + ); - HRESULT STDMETHODCALLTYPE CreateSessionOptions( - OrtSessionOptions** options) override; + HRESULT STDMETHODCALLTYPE CreateSessionOptions(OrtSessionOptions** options) override; HRESULT STDMETHODCALLTYPE CreateSession( - OrtSessionOptions* options, - OrtThreadPool* inter_op_thread_pool, - OrtThreadPool* intra_op_thread_pool, - OrtSession** session) override; + OrtSessionOptions* options, + OrtThreadPool* inter_op_thread_pool, + OrtThreadPool* intra_op_thread_pool, + OrtSession** session + ) override; - HRESULT STDMETHODCALLTYPE Initialize( - OrtSession* session) override; + HRESULT STDMETHODCALLTYPE Initialize(OrtSession* session) override; private: Microsoft::WRL::ComPtr engine_factory_; @@ -34,4 +38,4 @@ class OnnxruntimeDmlSessionBuilder : public Microsoft::WRL::RuntimeClass< bool metacommands_enabled_ = true; }; -} // namespace _winml \ No newline at end of file +} // namespace _winml diff --git a/winml/lib/Api.Ort/OnnxruntimeEngine.cpp b/winml/lib/Api.Ort/OnnxruntimeEngine.cpp index b492135de9f41..78b1a109d2da0 100644 --- a/winml/lib/Api.Ort/OnnxruntimeEngine.cpp +++ b/winml/lib/Api.Ort/OnnxruntimeEngine.cpp @@ -15,8 +15,7 @@ using namespace _winml; -static ONNXTensorElementDataType -ONNXTensorElementDataTypeFromTensorKind(winml::TensorKind kind) { +static ONNXTensorElementDataType ONNXTensorElementDataTypeFromTensorKind(winml::TensorKind kind) { switch (kind) { case winml::TensorKind::Boolean: { return ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL; @@ -69,14 +68,17 @@ ONNXTensorElementDataTypeFromTensorKind(winml::TensorKind kind) { } } -OnnxruntimeValue::OnnxruntimeValue() : value_(nullptr, nullptr), allocator_(nullptr, nullptr) {} +OnnxruntimeValue::OnnxruntimeValue() : value_(nullptr, nullptr), allocator_(nullptr, nullptr) { +} OnnxruntimeValue::~OnnxruntimeValue() { value_.reset(nullptr); allocator_.reset(nullptr); } -HRESULT OnnxruntimeValue::RuntimeClassInitialize(OnnxruntimeEngine* engine, UniqueOrtValue&& ort_value, UniqueOrtAllocator&& allocator) { +HRESULT OnnxruntimeValue::RuntimeClassInitialize( + OnnxruntimeEngine* engine, UniqueOrtValue&& ort_value, UniqueOrtAllocator&& allocator +) { engine_ = engine; value_ = std::move(ort_value); allocator_ = std::move(allocator); @@ -93,20 +95,15 @@ HRESULT OnnxruntimeValue::IsCpu(bool* out) { auto ort_api = engine_->GetEngineFactory()->UseOrtApi(); const OrtMemoryInfo* ort_memory_info; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetTensorMemoryInfo(value_.get(), &ort_memory_info), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->GetTensorMemoryInfo(value_.get(), &ort_memory_info), ort_api); const char* name; - RETURN_HR_IF_NOT_OK_MSG(ort_api->MemoryInfoGetName(ort_memory_info, &name), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->MemoryInfoGetName(ort_memory_info, &name), ort_api); OrtMemType type; - RETURN_HR_IF_NOT_OK_MSG(ort_api->MemoryInfoGetMemType(ort_memory_info, &type), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->MemoryInfoGetMemType(ort_memory_info, &type), ort_api); - *out = !strcmp(name, "Cpu") || - type == OrtMemType::OrtMemTypeCPUOutput || - type == OrtMemType::OrtMemTypeCPUInput; + *out = !strcmp(name, "Cpu") || type == OrtMemType::OrtMemTypeCPUOutput || type == OrtMemType::OrtMemTypeCPUInput; return S_OK; } @@ -122,33 +119,32 @@ static uint64_t ShapeSize(const int64_t* shape, size_t count) { return size; } -static auto GetStrings(const OrtApi* ort_api, const OrtValue* ort_value, - OrtTensorTypeAndShapeInfo* type_and_shape_info) { +static auto GetStrings( + const OrtApi* ort_api, const OrtValue* ort_value, OrtTensorTypeAndShapeInfo* type_and_shape_info +) { std::vector out; size_t size; - THROW_IF_NOT_OK_MSG(ort_api->GetDimensionsCount(type_and_shape_info, &size), - ort_api); + THROW_IF_NOT_OK_MSG(ort_api->GetDimensionsCount(type_and_shape_info, &size), ort_api); std::vector shape(size); if (size > 0) { - THROW_IF_NOT_OK_MSG(ort_api->GetDimensions(type_and_shape_info, &shape[0], size), - ort_api); + THROW_IF_NOT_OK_MSG(ort_api->GetDimensions(type_and_shape_info, &shape[0], size), ort_api); } auto length = ShapeSize(shape.data(), shape.size()); // make a big buffer to hold all the string data size_t buffer_length; - THROW_IF_NOT_OK_MSG(ort_api->GetStringTensorDataLength(ort_value, &buffer_length), - ort_api); + THROW_IF_NOT_OK_MSG(ort_api->GetStringTensorDataLength(ort_value, &buffer_length), ort_api); std::vector strings; std::unique_ptr buffer(new uint8_t[buffer_length]); std::vector offsets(static_cast(length)); - THROW_IF_NOT_OK_MSG(ort_api->GetStringTensorContent(ort_value, buffer.get(), buffer_length, offsets.data(), offsets.size()), - ort_api); + THROW_IF_NOT_OK_MSG( + ort_api->GetStringTensorContent(ort_value, buffer.get(), buffer_length, offsets.data(), offsets.size()), ort_api + ); // now go build all the strings for (size_t i = 0; i < length; ++i) { @@ -169,53 +165,56 @@ HRESULT OnnxruntimeValue::GetResource(_winml::Resource& out) { auto ort_api = engine_->GetEngineFactory()->UseOrtApi(); void* mutable_data = nullptr; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetTensorMutableData(value_.get(), &mutable_data), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->GetTensorMutableData(value_.get(), &mutable_data), ort_api); const OrtMemoryInfo* ort_memory_info; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetTensorMemoryInfo(value_.get(), &ort_memory_info), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->GetTensorMemoryInfo(value_.get(), &ort_memory_info), ort_api); bool is_cpu = false; if (SUCCEEDED(IsCpu(&is_cpu)) && !is_cpu) { const OrtDmlApi* ort_dml_api; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetExecutionProviderApi("DML", ORT_API_VERSION, reinterpret_cast(&ort_dml_api)), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + ort_api->GetExecutionProviderApi("DML", ORT_API_VERSION, reinterpret_cast(&ort_dml_api)), ort_api + ); OrtAllocator* ort_allocator; - RETURN_HR_IF_NOT_OK_MSG(ort_api->CreateAllocator(engine_->UseOrtSession(), ort_memory_info, &ort_allocator), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + ort_api->CreateAllocator(engine_->UseOrtSession(), ort_memory_info, &ort_allocator), ort_api + ); auto allocator = UniqueOrtAllocator(ort_allocator, ort_api->ReleaseAllocator); winrt::com_ptr resource; - RETURN_HR_IF_NOT_OK_MSG(ort_dml_api->GetD3D12ResourceFromAllocation(allocator.get(), mutable_data, - resource.put()), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + ort_dml_api->GetD3D12ResourceFromAllocation(allocator.get(), mutable_data, resource.put()), ort_api + ); out = _winml::Resource(resource.get(), [](void*) { /*do nothing, as this pointer is actually a com pointer! */ }); } else { int is_tensor; - RETURN_HR_IF_NOT_OK_MSG(ort_api->IsTensor(value_.get(), &is_tensor), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->IsTensor(value_.get(), &is_tensor), ort_api); if (is_tensor == 0) { - out = _winml::Resource(mutable_data, [](void*) { /*do nothing, as this pointer is actually owned elsewhere in ORT! */ }); + out = _winml::Resource( + mutable_data, [](void*) { /*do nothing, as this pointer is actually owned elsewhere in ORT! */ } + ); return S_OK; } OrtTensorTypeAndShapeInfo* info = nullptr; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetTensorTypeAndShape(value_.get(), &info), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->GetTensorTypeAndShape(value_.get(), &info), ort_api); auto type_and_shape_info = UniqueOrtTensorTypeAndShapeInfo(info, ort_api->ReleaseTensorTypeAndShapeInfo); ONNXTensorElementDataType data_type; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetTensorElementType(type_and_shape_info.get(), &data_type), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->GetTensorElementType(type_and_shape_info.get(), &data_type), ort_api); if (data_type == ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING) { auto strings = GetStrings(ort_api, value_.get(), info); auto string_data = strings->first.data(); - out = _winml::Resource(string_data, [capture_strings = strings](void*) { /*This deleter does nothing but capture the strings, which extends the lifetime of the returned strings.*/ }); + out = _winml::Resource(string_data, [capture_strings = strings](void*) { + /*This deleter does nothing but capture the strings, which extends the lifetime of the returned strings.*/ + }); } else { - out = _winml::Resource(mutable_data, [](void*) { /*do nothing, as this pointer is actually owned elsewhere in ORT! */ }); + out = _winml::Resource( + mutable_data, [](void*) { /*do nothing, as this pointer is actually owned elsewhere in ORT! */ } + ); } } return S_OK; @@ -225,8 +224,7 @@ HRESULT OnnxruntimeValue::IsTensor(bool* out) { auto ort_api = engine_->GetEngineFactory()->UseOrtApi(); ONNXType type = ONNXType::ONNX_TYPE_UNKNOWN; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetValueType(value_.get(), &type), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->GetValueType(value_.get(), &type), ort_api); *out = type == ONNXType::ONNX_TYPE_TENSOR; return S_OK; } @@ -234,13 +232,11 @@ HRESULT OnnxruntimeValue::IsTensor(bool* out) { HRESULT OnnxruntimeValue::IsOfTensorType(winml::TensorKind kind, bool* out) { auto ort_api = engine_->GetEngineFactory()->UseOrtApi(); OrtTensorTypeAndShapeInfo* info = nullptr; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetTensorTypeAndShape(value_.get(), &info), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->GetTensorTypeAndShape(value_.get(), &info), ort_api); auto type_and_shape_info = UniqueOrtTensorTypeAndShapeInfo(info, ort_api->ReleaseTensorTypeAndShapeInfo); ONNXTensorElementDataType data_type = ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetTensorElementType(type_and_shape_info.get(), &data_type), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->GetTensorElementType(type_and_shape_info.get(), &data_type), ort_api); *out = data_type == ONNXTensorElementDataTypeFromTensorKind(kind); return S_OK; @@ -249,30 +245,28 @@ HRESULT OnnxruntimeValue::IsOfTensorType(winml::TensorKind kind, bool* out) { HRESULT OnnxruntimeValue::GetTensorShape(std::vector& shape_vector) { auto ort_api = engine_->GetEngineFactory()->UseOrtApi(); OrtTensorTypeAndShapeInfo* info = nullptr; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetTensorTypeAndShape(value_.get(), &info), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->GetTensorTypeAndShape(value_.get(), &info), ort_api); auto type_and_shape_info = UniqueOrtTensorTypeAndShapeInfo(info, ort_api->ReleaseTensorTypeAndShapeInfo); size_t size; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetDimensionsCount(type_and_shape_info.get(), &size), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->GetDimensionsCount(type_and_shape_info.get(), &size), ort_api); std::vector shape(size); if (size > 0) { - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetDimensions(type_and_shape_info.get(), &shape[0], size), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->GetDimensions(type_and_shape_info.get(), &shape[0], size), ort_api); } shape_vector = std::move(shape); return S_OK; } -static bool EnsureMapTypeInfo(OnnxruntimeEngine* engine, OrtTypeInfo* type_info, winml::TensorKind key_kind, winml::TensorKind value_kind) { +static bool EnsureMapTypeInfo( + OnnxruntimeEngine* engine, OrtTypeInfo* type_info, winml::TensorKind key_kind, winml::TensorKind value_kind +) { auto ort_api = engine->GetEngineFactory()->UseOrtApi(); const OrtMapTypeInfo* map_info; - THROW_IF_NOT_OK_MSG(ort_api->CastTypeInfoToMapTypeInfo(type_info, &map_info), - ort_api); + THROW_IF_NOT_OK_MSG(ort_api->CastTypeInfoToMapTypeInfo(type_info, &map_info), ort_api); if (map_info == nullptr) { // It must be a seq> type @@ -280,28 +274,23 @@ static bool EnsureMapTypeInfo(OnnxruntimeEngine* engine, OrtTypeInfo* type_info, } ONNXTensorElementDataType map_key_type; - THROW_IF_NOT_OK_MSG(ort_api->GetMapKeyType(map_info, &map_key_type), - ort_api); + THROW_IF_NOT_OK_MSG(ort_api->GetMapKeyType(map_info, &map_key_type), ort_api); if (map_key_type == ONNXTensorElementDataTypeFromTensorKind(key_kind)) { OrtTypeInfo* value_info; - THROW_IF_NOT_OK_MSG(ort_api->GetMapValueType(map_info, &value_info), - ort_api); + THROW_IF_NOT_OK_MSG(ort_api->GetMapValueType(map_info, &value_info), ort_api); auto map_value_info = UniqueOrtTypeInfo(value_info, ort_api->ReleaseTypeInfo); const OrtTensorTypeAndShapeInfo* value_tensor_info = nullptr; - THROW_IF_NOT_OK_MSG(ort_api->CastTypeInfoToTensorInfo(map_value_info.get(), &value_tensor_info), - ort_api); + THROW_IF_NOT_OK_MSG(ort_api->CastTypeInfoToTensorInfo(map_value_info.get(), &value_tensor_info), ort_api); if (value_tensor_info) { ONNXTensorElementDataType map_value_tensor_type; - THROW_IF_NOT_OK_MSG(ort_api->GetTensorElementType(value_tensor_info, &map_value_tensor_type), - ort_api); + THROW_IF_NOT_OK_MSG(ort_api->GetTensorElementType(value_tensor_info, &map_value_tensor_type), ort_api); if (map_value_tensor_type == ONNXTensorElementDataTypeFromTensorKind(value_kind)) { size_t num_dims; - THROW_IF_NOT_OK_MSG(ort_api->GetDimensionsCount(value_tensor_info, &num_dims), - ort_api); + THROW_IF_NOT_OK_MSG(ort_api->GetDimensionsCount(value_tensor_info, &num_dims), ort_api); return num_dims == 0; } @@ -314,13 +303,11 @@ HRESULT OnnxruntimeValue::IsOfMapType(winml::TensorKind key_kind, winml::TensorK auto ort_api = engine_->GetEngineFactory()->UseOrtApi(); OrtTypeInfo* info = nullptr; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetTypeInfo(value_.get(), &info), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->GetTypeInfo(value_.get(), &info), ort_api); auto unique_type_info = UniqueOrtTypeInfo(info, ort_api->ReleaseTypeInfo); ONNXType type; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetOnnxTypeFromTypeInfo(unique_type_info.get(), &type), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->GetOnnxTypeFromTypeInfo(unique_type_info.get(), &type), ort_api); if (type == ONNXType::ONNX_TYPE_MAP) { *out = EnsureMapTypeInfo(engine_.Get(), unique_type_info.get(), key_kind, value_kind); @@ -335,22 +322,18 @@ HRESULT OnnxruntimeValue::IsOfVectorMapType(winml::TensorKind key_kind, winml::T auto ort_api = engine_->GetEngineFactory()->UseOrtApi(); OrtTypeInfo* info = nullptr; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetTypeInfo(value_.get(), &info), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->GetTypeInfo(value_.get(), &info), ort_api); auto unique_type_info = UniqueOrtTypeInfo(info, ort_api->ReleaseTypeInfo); ONNXType type; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetOnnxTypeFromTypeInfo(unique_type_info.get(), &type), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->GetOnnxTypeFromTypeInfo(unique_type_info.get(), &type), ort_api); if (type == ONNXType::ONNX_TYPE_SEQUENCE) { const OrtSequenceTypeInfo* sequence_info; - RETURN_HR_IF_NOT_OK_MSG(ort_api->CastTypeInfoToSequenceTypeInfo(unique_type_info.get(), &sequence_info), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->CastTypeInfoToSequenceTypeInfo(unique_type_info.get(), &sequence_info), ort_api); OrtTypeInfo* element_info; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetSequenceElementType(sequence_info, &element_info), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->GetSequenceElementType(sequence_info, &element_info), ort_api); auto unique_element_info = UniqueOrtTypeInfo(element_info, ort_api->ReleaseTypeInfo); *out = EnsureMapTypeInfo(engine_.Get(), unique_element_info.get(), key_kind, value_kind); @@ -364,37 +347,32 @@ HRESULT OnnxruntimeValue::IsOfVectorTensorType(winml::TensorKind kind, bool* out *out = false; OrtTypeInfo* info = nullptr; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetTypeInfo(value_.get(), &info), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->GetTypeInfo(value_.get(), &info), ort_api); auto unique_type_info = UniqueOrtTypeInfo(info, ort_api->ReleaseTypeInfo); ONNXType type; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetOnnxTypeFromTypeInfo(unique_type_info.get(), &type), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->GetOnnxTypeFromTypeInfo(unique_type_info.get(), &type), ort_api); if (type == ONNXType::ONNX_TYPE_SEQUENCE) { const OrtSequenceTypeInfo* sequence_info; - RETURN_HR_IF_NOT_OK_MSG(ort_api->CastTypeInfoToSequenceTypeInfo(unique_type_info.get(), &sequence_info), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->CastTypeInfoToSequenceTypeInfo(unique_type_info.get(), &sequence_info), ort_api); OrtTypeInfo* element_info; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetSequenceElementType(sequence_info, &element_info), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->GetSequenceElementType(sequence_info, &element_info), ort_api); auto unique_element_info = UniqueOrtTypeInfo(element_info, ort_api->ReleaseTypeInfo); ONNXType element_type; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetOnnxTypeFromTypeInfo(unique_element_info.get(), &element_type), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->GetOnnxTypeFromTypeInfo(unique_element_info.get(), &element_type), ort_api); if (element_type == ONNXType::ONNX_TYPE_TENSOR) { const OrtTensorTypeAndShapeInfo* element_tensor_info = nullptr; - RETURN_HR_IF_NOT_OK_MSG(ort_api->CastTypeInfoToTensorInfo(unique_element_info.get(), &element_tensor_info), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + ort_api->CastTypeInfoToTensorInfo(unique_element_info.get(), &element_tensor_info), ort_api + ); if (element_tensor_info) { ONNXTensorElementDataType element_tensor_type; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetTensorElementType(element_tensor_info, &element_tensor_type), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->GetTensorElementType(element_tensor_info, &element_tensor_type), ort_api); *out = element_tensor_type == ONNXTensorElementDataTypeFromTensorKind(kind); } } @@ -419,15 +397,26 @@ HRESULT OnnxruntimeValue::AssignOrtValue(OrtValue* in) { OnnxruntimeEngine::OnnxruntimeEngine() : session_(nullptr, nullptr) { } -HRESULT OnnxruntimeEngine::RuntimeClassInitialize(OnnxruntimeEngineFactory* engine_factory, - UniqueOrtSession&& session, - IOrtSessionBuilder* session_builder) { +HRESULT OnnxruntimeEngine::RuntimeClassInitialize( + OnnxruntimeEngineFactory* engine_factory, UniqueOrtSession&& session, IOrtSessionBuilder* session_builder +) { engine_factory_ = engine_factory; session_ = std::move(session); session_builder_ = session_builder; return S_OK; } +OnnxruntimeEngine::~OnnxruntimeEngine() { + for (auto& handle : custom_op_library_handles_) { + FreeLibrary(reinterpret_cast(handle)); + } +} + +HRESULT OnnxruntimeEngine::RegisterCustomOpLibraryHandles(const gsl::span handles) { + custom_op_library_handles_.insert(custom_op_library_handles_.end(), handles.begin(), handles.end()); + return S_OK; +} + HRESULT OnnxruntimeEngine::LoadModel(_In_ IModel* model) { Microsoft::WRL::ComPtr onnxruntime_model; RETURN_IF_FAILED(model->QueryInterface(IID_PPV_ARGS(&onnxruntime_model))); @@ -437,8 +426,9 @@ HRESULT OnnxruntimeEngine::LoadModel(_In_ IModel* model) { auto winml_adapter_api = engine_factory_->UseWinmlAdapterApi(); - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->SessionLoadAndPurloinModel(session_.get(), ort_model), - engine_factory_->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->SessionLoadAndPurloinModel(session_.get(), ort_model), engine_factory_->UseOrtApi() + ); return S_OK; } @@ -449,22 +439,23 @@ HRESULT OnnxruntimeEngine::Initialize() { HRESULT OnnxruntimeEngine::RegisterGraphTransformers() { auto winml_adapter_api = engine_factory_->UseWinmlAdapterApi(); - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->SessionRegisterGraphTransformers(session_.get()), - engine_factory_->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->SessionRegisterGraphTransformers(session_.get()), engine_factory_->UseOrtApi() + ); return S_OK; } HRESULT OnnxruntimeEngine::RegisterCustomRegistry(IMLOperatorRegistry* registry) { auto winml_adapter_api = engine_factory_->UseWinmlAdapterApi(); - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->SessionRegisterCustomRegistry(session_.get(), registry), - engine_factory_->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->SessionRegisterCustomRegistry(session_.get(), registry), engine_factory_->UseOrtApi() + ); return S_OK; } HRESULT OnnxruntimeEngine::EndProfiling() { auto winml_adapter_api = engine_factory_->UseWinmlAdapterApi(); - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->SessionEndProfiling(session_.get()), - engine_factory_->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->SessionEndProfiling(session_.get()), engine_factory_->UseOrtApi()); return S_OK; } @@ -474,8 +465,9 @@ HRESULT OnnxruntimeEngine::StartProfiling() { OrtEnv* ort_env; engine_factory_->GetOrtEnvironment(&ort_env); - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->SessionStartProfiling(ort_env, session_.get()), - engine_factory_->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->SessionStartProfiling(ort_env, session_.get()), engine_factory_->UseOrtApi() + ); return S_OK; } @@ -483,11 +475,13 @@ HRESULT OnnxruntimeEngine::FlushContext() { auto winml_adapter_api = engine_factory_->UseWinmlAdapterApi(); OrtExecutionProvider* ort_provider; - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->SessionGetExecutionProvider(session_.get(), 0, &ort_provider), - engine_factory_->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->SessionGetExecutionProvider(session_.get(), 0, &ort_provider), engine_factory_->UseOrtApi() + ); - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->DmlExecutionProviderFlushContext(ort_provider), - engine_factory_->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->DmlExecutionProviderFlushContext(ort_provider), engine_factory_->UseOrtApi() + ); return S_OK; } @@ -495,11 +489,13 @@ HRESULT OnnxruntimeEngine::ReleaseCompletedReferences() { auto winml_adapter_api = engine_factory_->UseWinmlAdapterApi(); OrtExecutionProvider* ort_provider; - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->SessionGetExecutionProvider(session_.get(), 0, &ort_provider), - engine_factory_->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->SessionGetExecutionProvider(session_.get(), 0, &ort_provider), engine_factory_->UseOrtApi() + ); - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->DmlExecutionProviderReleaseCompletedReferences(ort_provider), - engine_factory_->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->DmlExecutionProviderReleaseCompletedReferences(ort_provider), engine_factory_->UseOrtApi() + ); return S_OK; } @@ -508,8 +504,9 @@ HRESULT OnnxruntimeEngine::CopyValueAcrossDevices(IValue* src, IValue* dest) { auto winml_adapter_api = engine_factory_->UseWinmlAdapterApi(); OrtExecutionProvider* ort_provider; - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->SessionGetExecutionProvider(session_.get(), 0, &ort_provider), - engine_factory_->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->SessionGetExecutionProvider(session_.get(), 0, &ort_provider), engine_factory_->UseOrtApi() + ); auto src_value = static_cast(src); auto dest_value = static_cast(dest); @@ -521,8 +518,10 @@ HRESULT OnnxruntimeEngine::CopyValueAcrossDevices(IValue* src, IValue* dest) { auto has_null_dest = (SUCCEEDED(dest_value->IsEmpty(&is_empty)) && is_empty); RETURN_HR_IF(E_FAIL, has_null_dest); - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->DmlCopyTensor(ort_provider, src_value->UseOrtValue(), dest_value->UseOrtValue()), - engine_factory_->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->DmlCopyTensor(ort_provider, src_value->UseOrtValue(), dest_value->UseOrtValue()), + engine_factory_->UseOrtApi() + ); return S_OK; } @@ -531,11 +530,11 @@ HRESULT OnnxruntimeEngine::Sync() { auto winml_adapter_api = engine_factory_->UseWinmlAdapterApi(); OrtExecutionProvider* ort_provider; - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->SessionGetExecutionProvider(session_.get(), 0, &ort_provider), - engine_factory_->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->SessionGetExecutionProvider(session_.get(), 0, &ort_provider), engine_factory_->UseOrtApi() + ); - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->ExecutionProviderSync(ort_provider), - engine_factory_->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->ExecutionProviderSync(ort_provider), engine_factory_->UseOrtApi()); return S_OK; } @@ -552,17 +551,29 @@ OnnxruntimeEngineFactory* OnnxruntimeEngine::GetEngineFactory() { return engine_factory_.Get(); } -HRESULT OnnxruntimeEngine::CreateTensorValueFromDefaultAllocator(const int64_t* shape, size_t count, winml::TensorKind kind, _Out_ IValue** out) { +HRESULT OnnxruntimeEngine::CreateTensorValueFromDefaultAllocator( + const int64_t* shape, size_t count, winml::TensorKind kind, _Out_ IValue** out +) { + *out = nullptr; auto ort_api = engine_factory_->UseOrtApi(); OrtAllocator* ort_allocator; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetAllocatorWithDefaultOptions(&ort_allocator), ort_api); // This should not be freed as this owned by ort + RETURN_HR_IF_NOT_OK_MSG( + ort_api->GetAllocatorWithDefaultOptions(&ort_allocator), + ort_api + ); // This should not be freed as this owned by ort OrtValue* ort_value; - RETURN_HR_IF_NOT_OK_MSG(ort_api->CreateTensorAsOrtValue(ort_allocator, shape, count, ONNXTensorElementDataTypeFromTensorKind(kind), &ort_value), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + ort_api->CreateTensorAsOrtValue( + ort_allocator, shape, count, ONNXTensorElementDataTypeFromTensorKind(kind), &ort_value + ), + ort_api + ); auto unique_value = UniqueOrtValue(ort_value, ort_api->ReleaseValue); - RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize(out, this, std::move(unique_value), UniqueOrtAllocator(nullptr, nullptr))); + RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize( + out, this, std::move(unique_value), UniqueOrtAllocator(nullptr, nullptr) + )); return S_OK; } @@ -574,36 +585,42 @@ HRESULT OnnxruntimeEngine::CreateTensorValueFromDefaultAllocator(const int64_t* * its source location to the ort value. Since a copy is required, there is need to preserve the caller's memory locations. * We simply allocate memory with ORT and copy the tensorized values into it. */ -HRESULT OnnxruntimeEngine::CreateTensorValue(const int64_t* shape, size_t count, winml::TensorKind kind, _Out_ IValue** out) { +HRESULT +OnnxruntimeEngine::CreateTensorValue(const int64_t* shape, size_t count, winml::TensorKind kind, _Out_ IValue** out) { auto ort_api = engine_factory_->UseOrtApi(); auto winml_adapter_api = engine_factory_->UseWinmlAdapterApi(); OrtExecutionProvider* ort_provider; - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->SessionGetExecutionProvider(session_.get(), 0, &ort_provider), - engine_factory_->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->SessionGetExecutionProvider(session_.get(), 0, &ort_provider), engine_factory_->UseOrtApi() + ); OrtAllocator* ort_allocator; - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->GetProviderAllocator(ort_provider, &ort_allocator), - engine_factory_->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->GetProviderAllocator(session_.get(), ort_provider, &ort_allocator), engine_factory_->UseOrtApi() + ); - auto unique_allocator = UniqueOrtAllocator( - ort_allocator, - [](OrtAllocator* allocator) { - GetVersionedWinmlAdapterApi()->FreeProviderAllocator(allocator); - }); // the release here should probably not return anything + auto unique_allocator = UniqueOrtAllocator(ort_allocator, [](OrtAllocator* allocator) { + GetVersionedWinmlAdapterApi()->FreeProviderAllocator(allocator); + }); // the release here should probably not return anything OrtValue* ort_value; - RETURN_HR_IF_NOT_OK_MSG(ort_api->CreateTensorAsOrtValue(unique_allocator.get(), shape, count, ONNXTensorElementDataTypeFromTensorKind(kind), &ort_value), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + ort_api->CreateTensorAsOrtValue( + unique_allocator.get(), shape, count, ONNXTensorElementDataTypeFromTensorKind(kind), &ort_value + ), + ort_api + ); auto unique_value = UniqueOrtValue(ort_value, ort_api->ReleaseValue); - RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize(out, this, std::move(unique_value), std::move(unique_allocator))); + RETURN_IF_FAILED( + Microsoft::WRL::MakeAndInitialize(out, this, std::move(unique_value), std::move(unique_allocator)) + ); return S_OK; } using DmlAllocatorResource = std::unique_ptr; -class DmlAllocatorWrapper : public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags, - IUnknown> { +class DmlAllocatorWrapper + : public Microsoft::WRL::RuntimeClass, IUnknown> { public: DmlAllocatorWrapper() : dml_resource_(nullptr, nullptr) {} @@ -622,52 +639,64 @@ class DmlAllocatorWrapper : public Microsoft::WRL::RuntimeClass< * Used by callers like TensorBase to allocate a gpu OrtValue based on a called owned ID3D12Resource. * WinML cannot use ORT allocators here since they will allocate the ID3D12Resource and force a copy from the user provided value. */ -HRESULT OnnxruntimeEngine::CreateTensorValueFromExternalD3DResource(ID3D12Resource* d3d_resource, const int64_t* shape, size_t count, winml::TensorKind kind, _Out_ IValue** out) { +HRESULT OnnxruntimeEngine::CreateTensorValueFromExternalD3DResource( + ID3D12Resource* d3d_resource, const int64_t* shape, size_t count, winml::TensorKind kind, _Out_ IValue** out +) { auto ort_api = engine_factory_->UseOrtApi(); const OrtDmlApi* ort_dml_api; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetExecutionProviderApi("DML", ORT_API_VERSION, reinterpret_cast(&ort_dml_api)), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + ort_api->GetExecutionProviderApi("DML", ORT_API_VERSION, reinterpret_cast(&ort_dml_api)), ort_api + ); OrtMemoryInfo* ort_memory_info; - RETURN_HR_IF_NOT_OK_MSG(ort_api->CreateMemoryInfo("DML", OrtAllocatorType::OrtDeviceAllocator, 0, OrtMemType::OrtMemTypeDefault, &ort_memory_info), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + ort_api->CreateMemoryInfo( + "DML", OrtAllocatorType::OrtDeviceAllocator, 0, OrtMemType::OrtMemTypeDefault, &ort_memory_info + ), + ort_api + ); OrtAllocator* ort_allocator; - RETURN_HR_IF_NOT_OK_MSG(ort_api->CreateAllocator(session_.get(), ort_memory_info, &ort_allocator), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->CreateAllocator(session_.get(), ort_memory_info, &ort_allocator), ort_api); auto allocator = UniqueOrtAllocator(ort_allocator, ort_api->ReleaseAllocator); void* dml_allocator_resource; - RETURN_HR_IF_NOT_OK_MSG(ort_dml_api->CreateGPUAllocationFromD3DResource(d3d_resource, &dml_allocator_resource), - engine_factory_->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG( + ort_dml_api->CreateGPUAllocationFromD3DResource(d3d_resource, &dml_allocator_resource), engine_factory_->UseOrtApi() + ); - auto unique_dml_allocator_resource = - DmlAllocatorResource(dml_allocator_resource, - [](void* ptr) { - const OrtDmlApi* ort_dml_api; - GetVersionedOrtApi()->GetExecutionProviderApi("DML", ORT_API_VERSION, reinterpret_cast(&ort_dml_api)); - ort_dml_api->FreeGPUAllocation(ptr); - }); + auto unique_dml_allocator_resource = DmlAllocatorResource(dml_allocator_resource, [](void* ptr) { + const OrtDmlApi* ort_dml_api; + GetVersionedOrtApi()->GetExecutionProviderApi("DML", ORT_API_VERSION, reinterpret_cast(&ort_dml_api)); + ort_dml_api->FreeGPUAllocation(ptr); + }); // create the OrtValue as a tensor letting ort know that we own the data buffer OrtValue* ort_value; - RETURN_HR_IF_NOT_OK_MSG(ort_api->CreateTensorWithDataAsOrtValue( - ort_memory_info, - unique_dml_allocator_resource.get(), - static_cast(d3d_resource->GetDesc().Width), - shape, - count, - ONNXTensorElementDataTypeFromTensorKind(kind), - &ort_value), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + ort_api->CreateTensorWithDataAsOrtValue( + ort_memory_info, + unique_dml_allocator_resource.get(), + static_cast(d3d_resource->GetDesc().Width), + shape, + count, + ONNXTensorElementDataTypeFromTensorKind(kind), + &ort_value + ), + ort_api + ); auto unique_value = UniqueOrtValue(ort_value, ort_api->ReleaseValue); Microsoft::WRL::ComPtr out_value; - RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&out_value, this, std::move(unique_value), UniqueOrtAllocator(nullptr, nullptr))); + RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize( + &out_value, this, std::move(unique_value), UniqueOrtAllocator(nullptr, nullptr) + )); // Cache the allocator on the value so it destructs appropriately when the value is dropped Microsoft::WRL::ComPtr dml_allocator_resource_wrapper; - RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&dml_allocator_resource_wrapper, std::move(unique_dml_allocator_resource))); + RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize( + &dml_allocator_resource_wrapper, std::move(unique_dml_allocator_resource) + )); RETURN_IF_FAILED(out_value->SetParameter(dml_allocator_resource_wrapper.Get())); @@ -685,14 +714,17 @@ HRESULT OnnxruntimeEngine::CreateTensorValueFromExternalD3DResource(ID3D12Resour * In addition, strings have different APIs on the c-abi like FillStringTensor to populate the buffer, and so strings * have a different calling pattern than other Tensor types of simple data types. */ -HRESULT OnnxruntimeEngine::CreateStringTensorValueFromDataWithCopy(const char* const* data, size_t num_elements, const int64_t* shape, size_t count, _Out_ IValue** out) { +HRESULT OnnxruntimeEngine::CreateStringTensorValueFromDataWithCopy( + const char* const* data, size_t num_elements, const int64_t* shape, size_t count, _Out_ IValue** out +) { auto ort_api = engine_factory_->UseOrtApi(); RETURN_IF_FAILED(CreateTensorValueFromDefaultAllocator(shape, count, winml::TensorKind::String, out)); auto ort_value = reinterpret_cast<_winml::OnnxruntimeValue*>(*out)->UseOrtValue(); - RETURN_HR_IF_NOT_OK_MSG(ort_api->FillStringTensor(ort_value, reinterpret_cast(data), num_elements), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + ort_api->FillStringTensor(ort_value, reinterpret_cast(data), num_elements), ort_api + ); return S_OK; } @@ -701,7 +733,9 @@ HRESULT OnnxruntimeEngine::CreateStringTensorValueFromDataWithCopy(const char* c * * Used by callers like TensorBase to allocate a cpu OrtValue that is backed by caller owned memory. */ -HRESULT OnnxruntimeEngine::CreateTensorValueFromExternalBuffer(void* data, size_t size_in_bytes, const int64_t* shape, size_t count, winml::TensorKind kind, _Out_ IValue** out) { +HRESULT OnnxruntimeEngine::CreateTensorValueFromExternalBuffer( + void* data, size_t size_in_bytes, const int64_t* shape, size_t count, winml::TensorKind kind, _Out_ IValue** out +) { auto ort_api = engine_factory_->UseOrtApi(); if (kind == winml::TensorKind::String) { @@ -711,22 +745,20 @@ HRESULT OnnxruntimeEngine::CreateTensorValueFromExternalBuffer(void* data, size_ // TODO: what is the difference between the device allocator and the arena allocator? OrtMemoryInfo* cpu_memory; - RETURN_HR_IF_NOT_OK_MSG(ort_api->CreateCpuMemoryInfo(OrtDeviceAllocator, OrtMemTypeDefault, &cpu_memory), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->CreateCpuMemoryInfo(OrtDeviceAllocator, OrtMemTypeDefault, &cpu_memory), ort_api); OrtValue* ort_value; - RETURN_HR_IF_NOT_OK_MSG(ort_api->CreateTensorWithDataAsOrtValue( - cpu_memory, - data, - size_in_bytes, - shape, - count, - ONNXTensorElementDataTypeFromTensorKind(kind), - &ort_value), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + ort_api->CreateTensorWithDataAsOrtValue( + cpu_memory, data, size_in_bytes, shape, count, ONNXTensorElementDataTypeFromTensorKind(kind), &ort_value + ), + ort_api + ); auto unique_value = UniqueOrtValue(ort_value, ort_api->ReleaseValue); - RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize(out, this, std::move(unique_value), UniqueOrtAllocator(nullptr, nullptr))); + RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize( + out, this, std::move(unique_value), UniqueOrtAllocator(nullptr, nullptr) + )); return S_OK; } @@ -734,20 +766,19 @@ HRESULT OnnxruntimeEngine::CreateSequenceOfValuesValue(IValue** values, size_t s auto ort_api = engine_factory_->UseOrtApi(); std::vector sequence(size); - std::transform( - values, - values + size, - std::begin(sequence), - [](auto value) { - return static_cast(value)->UseOrtValue(); - }); + std::transform(values, values + size, std::begin(sequence), [](auto value) { + return static_cast(value)->UseOrtValue(); + }); OrtValue* ort_value; - RETURN_HR_IF_NOT_OK_MSG(ort_api->CreateValue(sequence.data(), size, ONNXType::ONNX_TYPE_SEQUENCE, &ort_value), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + ort_api->CreateValue(sequence.data(), size, ONNXType::ONNX_TYPE_SEQUENCE, &ort_value), ort_api + ); UniqueOrtValue unique_value(ort_value, ort_api->ReleaseValue); - RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize(out, this, std::move(unique_value), UniqueOrtAllocator(nullptr, nullptr))); + RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize( + out, this, std::move(unique_value), UniqueOrtAllocator(nullptr, nullptr) + )); return S_OK; } @@ -760,7 +791,9 @@ HRESULT OnnxruntimeEngine::CreateSequenceOfValuesValue(IValue** values, size_t s HRESULT OnnxruntimeEngine::CreateNullValue(_Out_ IValue** out) { auto ort_api = engine_factory_->UseOrtApi(); auto unique_value = UniqueOrtValue(nullptr, ort_api->ReleaseValue); - RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize(out, this, std::move(unique_value), UniqueOrtAllocator(nullptr, nullptr))); + RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize( + out, this, std::move(unique_value), UniqueOrtAllocator(nullptr, nullptr) + )); return S_OK; } @@ -826,14 +859,18 @@ auto CastToWinrtSequenceOfMaps(IInspectable* sequence_insp) { template struct FillMapTensors { - static HRESULT Run(const OrtApi* ort_api, IInspectable* map_insp, OrtValue* keys_ort_value, OrtValue* values_ort_value) { + static HRESULT Run( + const OrtApi* ort_api, IInspectable* map_insp, OrtValue* keys_ort_value, OrtValue* values_ort_value + ) { AbiTypeInfo::OrtType* keys_mutable_data; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetTensorMutableData(keys_ort_value, reinterpret_cast(&keys_mutable_data)), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + ort_api->GetTensorMutableData(keys_ort_value, reinterpret_cast(&keys_mutable_data)), ort_api + ); AbiTypeInfo::OrtType* values_mutable_data; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetTensorMutableData(values_ort_value, reinterpret_cast(&values_mutable_data)), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + ort_api->GetTensorMutableData(values_ort_value, reinterpret_cast(&values_mutable_data)), ort_api + ); auto map = CastToWinrtMap(map_insp); size_t index = 0; @@ -848,10 +885,13 @@ struct FillMapTensors { template struct FillMapTensors { - static HRESULT Run(const OrtApi* ort_api, IInspectable* map_insp, OrtValue* keys_ort_value, OrtValue* values_ort_value) { + static HRESULT Run( + const OrtApi* ort_api, IInspectable* map_insp, OrtValue* keys_ort_value, OrtValue* values_ort_value + ) { AbiTypeInfo::OrtType* values_mutable_data; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetTensorMutableData(values_ort_value, reinterpret_cast(&values_mutable_data)), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + ort_api->GetTensorMutableData(values_ort_value, reinterpret_cast(&values_mutable_data)), ort_api + ); auto map = CastToWinrtMap(map_insp); size_t index = 0; @@ -863,14 +903,9 @@ struct FillMapTensors { } std::vector raw_values; - std::transform( - keys.begin(), - keys.end(), - std::back_inserter(raw_values), - [&](auto& str) { return str.c_str(); }); + std::transform(keys.begin(), keys.end(), std::back_inserter(raw_values), [&](auto& str) { return str.c_str(); }); - RETURN_HR_IF_NOT_OK_MSG(ort_api->FillStringTensor(keys_ort_value, raw_values.data(), raw_values.size()), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->FillStringTensor(keys_ort_value, raw_values.data(), raw_values.size()), ort_api); return S_OK; } @@ -878,10 +913,13 @@ struct FillMapTensors { template struct FillMapTensors { - static HRESULT Run(const OrtApi* ort_api, IInspectable* map_insp, OrtValue* keys_ort_value, OrtValue* values_ort_value) { + static HRESULT Run( + const OrtApi* ort_api, IInspectable* map_insp, OrtValue* keys_ort_value, OrtValue* values_ort_value + ) { AbiTypeInfo::OrtType* keys_mutable_data; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetTensorMutableData(keys_ort_value, reinterpret_cast(&keys_mutable_data)), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + ort_api->GetTensorMutableData(keys_ort_value, reinterpret_cast(&keys_mutable_data)), ort_api + ); auto map = CastToWinrtMap(map_insp); size_t index = 0; @@ -893,21 +931,20 @@ struct FillMapTensors { } std::vector raw_values; - std::transform( - values.begin(), - values.end(), - std::back_inserter(raw_values), - [&](auto& str) { return str.c_str(); }); - - RETURN_HR_IF_NOT_OK_MSG(ort_api->FillStringTensor(keys_ort_value, raw_values.data(), raw_values.size()), - ort_api); + std::transform(values.begin(), values.end(), std::back_inserter(raw_values), [&](auto& str) { + return str.c_str(); + }); + + RETURN_HR_IF_NOT_OK_MSG(ort_api->FillStringTensor(keys_ort_value, raw_values.data(), raw_values.size()), ort_api); return S_OK; } }; template <> struct FillMapTensors { - static HRESULT Run(const OrtApi* ort_api, IInspectable* map_insp, OrtValue* keys_ort_value, OrtValue* values_ort_value) { + static HRESULT Run( + const OrtApi* ort_api, IInspectable* map_insp, OrtValue* keys_ort_value, OrtValue* values_ort_value + ) { auto map = CastToWinrtMap(map_insp); std::vector keys; std::vector values; @@ -917,39 +954,40 @@ struct FillMapTensors { } std::vector raw_keys; - std::transform( - keys.begin(), - keys.end(), - std::back_inserter(raw_keys), - [&](auto& str) { return str.c_str(); }); + std::transform(keys.begin(), keys.end(), std::back_inserter(raw_keys), [&](auto& str) { return str.c_str(); }); std::vector raw_values; - std::transform( - values.begin(), - values.end(), - std::back_inserter(raw_values), - [&](auto& str) { return str.c_str(); }); - - RETURN_HR_IF_NOT_OK_MSG(ort_api->FillStringTensor(keys_ort_value, raw_keys.data(), raw_keys.size()), - ort_api); - RETURN_HR_IF_NOT_OK_MSG(ort_api->FillStringTensor(values_ort_value, raw_values.data(), raw_values.size()), - ort_api); + std::transform(values.begin(), values.end(), std::back_inserter(raw_values), [&](auto& str) { + return str.c_str(); + }); + + RETURN_HR_IF_NOT_OK_MSG(ort_api->FillStringTensor(keys_ort_value, raw_keys.data(), raw_keys.size()), ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->FillStringTensor(values_ort_value, raw_values.data(), raw_values.size()), ort_api); return S_OK; } }; template -HRESULT CreateMapValue(OnnxruntimeEngine* engine, IInspectable* map_insp, winml::TensorKind key_kind, winml::TensorKind value_kind, _Out_ IValue** out) { +HRESULT CreateMapValue( + OnnxruntimeEngine* engine, + IInspectable* map_insp, + winml::TensorKind key_kind, + winml::TensorKind value_kind, + _Out_ IValue** out +) { auto ort_api = engine->UseOrtApi(); auto map = CastToWinrtMap(map_insp); std::vector shape = {static_cast(map.Size())}; winrt::com_ptr<_winml::IValue> key_value; - RETURN_IF_FAILED(engine->CreateTensorValueFromDefaultAllocator(shape.data(), shape.size(), key_kind, key_value.put())); + RETURN_IF_FAILED(engine->CreateTensorValueFromDefaultAllocator(shape.data(), shape.size(), key_kind, key_value.put()) + ); auto keys_ort_value = static_cast(key_value.get())->UseOrtValue(); winrt::com_ptr<_winml::IValue> value_value; - RETURN_IF_FAILED(engine->CreateTensorValueFromDefaultAllocator(shape.data(), shape.size(), value_kind, value_value.put())); + RETURN_IF_FAILED( + engine->CreateTensorValueFromDefaultAllocator(shape.data(), shape.size(), value_kind, value_value.put()) + ); auto values_ort_value = static_cast(value_value.get())->UseOrtValue(); auto hr = FillMapTensors::Run(ort_api, map_insp, keys_ort_value, values_ort_value); @@ -958,82 +996,120 @@ HRESULT CreateMapValue(OnnxruntimeEngine* engine, IInspectable* map_insp, winml: OrtValue* inputs[2] = {keys_ort_value, values_ort_value}; OrtValue* map_value; - RETURN_HR_IF_NOT_OK_MSG(ort_api->CreateValue(inputs, 2, ONNXType::ONNX_TYPE_MAP, &map_value), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->CreateValue(inputs, 2, ONNXType::ONNX_TYPE_MAP, &map_value), ort_api); auto unique_map_ort_value = UniqueOrtValue(map_value, ort_api->ReleaseValue); - RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize(out, engine, std::move(unique_map_ort_value), UniqueOrtAllocator(nullptr, nullptr))); + RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize( + out, engine, std::move(unique_map_ort_value), UniqueOrtAllocator(nullptr, nullptr) + )); return S_OK; } static auto GetMapValueCreator(OnnxruntimeEngine* engine, winml::TensorKind key_kind, winml::TensorKind value_kind) { using namespace std::placeholders; if (key_kind == winml::TensorKind::Int64 && value_kind == winml::TensorKind::Int64) { - return std::bind(&CreateMapValue, engine, _1, winml::TensorKind::Int64, winml::TensorKind::Int64, _2); + return std::bind( + &CreateMapValue, engine, _1, winml::TensorKind::Int64, winml::TensorKind::Int64, _2 + ); } else if (key_kind == winml::TensorKind::Int64 && value_kind == winml::TensorKind::Float) { - return std::bind(&CreateMapValue, engine, _1, winml::TensorKind::Int64, winml::TensorKind::Float, _2); + return std::bind( + &CreateMapValue, engine, _1, winml::TensorKind::Int64, winml::TensorKind::Float, _2 + ); } else if (key_kind == winml::TensorKind::Int64 && value_kind == winml::TensorKind::Double) { - return std::bind(&CreateMapValue, engine, _1, winml::TensorKind::Int64, winml::TensorKind::Double, _2); + return std::bind( + &CreateMapValue, engine, _1, winml::TensorKind::Int64, winml::TensorKind::Double, _2 + ); } else if (key_kind == winml::TensorKind::Int64 && value_kind == winml::TensorKind::String) { - return std::bind(&CreateMapValue, engine, _1, winml::TensorKind::Int64, winml::TensorKind::String, _2); + return std::bind( + &CreateMapValue, engine, _1, winml::TensorKind::Int64, winml::TensorKind::String, _2 + ); } else if (key_kind == winml::TensorKind::String && value_kind == winml::TensorKind::Int64) { - return std::bind(&CreateMapValue, engine, _1, winml::TensorKind::String, winml::TensorKind::Int64, _2); + return std::bind( + &CreateMapValue, engine, _1, winml::TensorKind::String, winml::TensorKind::Int64, _2 + ); } else if (key_kind == winml::TensorKind::String && value_kind == winml::TensorKind::Float) { - return std::bind(&CreateMapValue, engine, _1, winml::TensorKind::String, winml::TensorKind::Float, _2); + return std::bind( + &CreateMapValue, engine, _1, winml::TensorKind::String, winml::TensorKind::Float, _2 + ); } else if (key_kind == winml::TensorKind::String && value_kind == winml::TensorKind::Double) { - return std::bind(&CreateMapValue, engine, _1, winml::TensorKind::String, winml::TensorKind::Double, _2); + return std::bind( + &CreateMapValue, engine, _1, winml::TensorKind::String, winml::TensorKind::Double, _2 + ); } else if (key_kind == winml::TensorKind::String && value_kind == winml::TensorKind::String) { - return std::bind(&CreateMapValue, engine, _1, winml::TensorKind::String, winml::TensorKind::String, _2); + return std::bind( + &CreateMapValue, engine, _1, winml::TensorKind::String, winml::TensorKind::String, _2 + ); } THROW_HR(E_NOTIMPL); } -HRESULT OnnxruntimeEngine::CreateMapValue(IInspectable* map, winml::TensorKind key_kind, winml::TensorKind value_kind, _Out_ IValue** out) { +HRESULT OnnxruntimeEngine::CreateMapValue( + IInspectable* map, winml::TensorKind key_kind, winml::TensorKind value_kind, _Out_ IValue** out +) { return GetMapValueCreator(this, key_kind, value_kind)(map, out); } template -HRESULT CreateSequenceOfMapsValue(OnnxruntimeEngine* engine, IInspectable* sequence_insp, winml::TensorKind key_kind, winml::TensorKind value_kind, _Out_ IValue** out) { +HRESULT CreateSequenceOfMapsValue( + OnnxruntimeEngine* engine, + IInspectable* sequence_insp, + winml::TensorKind key_kind, + winml::TensorKind value_kind, + _Out_ IValue** out +) { auto ort_api = engine->UseOrtApi(); auto sequence = CastToWinrtSequenceOfMaps(sequence_insp); std::vector> element_values; for (auto element : sequence) { winrt::com_ptr<_winml::IValue> element_value; - engine->CreateMapValue(reinterpret_cast(winrt::get_abi(element)), key_kind, value_kind, element_value.put()); + engine->CreateMapValue( + reinterpret_cast(winrt::get_abi(element)), key_kind, value_kind, element_value.put() + ); element_values.push_back(element_value); } std::vector element_ort_values; - std::transform(element_values.begin(), - element_values.end(), - std::back_inserter(element_ort_values), - [](auto value) { return static_cast(value.get())->UseOrtValue(); }); + std::transform(element_values.begin(), element_values.end(), std::back_inserter(element_ort_values), [](auto value) { + return static_cast(value.get())->UseOrtValue(); + }); OrtValue* sequence_value; RETURN_HR_IF_NOT_OK_MSG( - ort_api->CreateValue(element_ort_values.data(), element_ort_values.size(), - ONNXType::ONNX_TYPE_SEQUENCE, &sequence_value), - ort_api); + ort_api->CreateValue( + element_ort_values.data(), element_ort_values.size(), ONNXType::ONNX_TYPE_SEQUENCE, &sequence_value + ), + ort_api + ); auto unique_sequence_ort_value = UniqueOrtValue(sequence_value, ort_api->ReleaseValue); - RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize(out, engine, std::move(unique_sequence_ort_value), UniqueOrtAllocator(nullptr, nullptr))); + RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize( + out, engine, std::move(unique_sequence_ort_value), UniqueOrtAllocator(nullptr, nullptr) + )); return S_OK; } -static auto GetSequenceOfMapsValueCreator(OnnxruntimeEngine* engine, winml::TensorKind key_kind, winml::TensorKind value_kind) { +static auto GetSequenceOfMapsValueCreator( + OnnxruntimeEngine* engine, winml::TensorKind key_kind, winml::TensorKind value_kind +) { using namespace std::placeholders; if (key_kind == winml::TensorKind::String && value_kind == winml::TensorKind::Float) { - return std::bind(&CreateSequenceOfMapsValue, engine, _1, winml::TensorKind::Int64, winml::TensorKind::Int64, _2); + return std::bind( + &CreateSequenceOfMapsValue, engine, _1, winml::TensorKind::Int64, winml::TensorKind::Int64, _2 + ); } else if (key_kind == winml::TensorKind::Int64 && value_kind == winml::TensorKind::Float) { - return std::bind(&CreateSequenceOfMapsValue, engine, _1, winml::TensorKind::Int64, winml::TensorKind::Float, _2); + return std::bind( + &CreateSequenceOfMapsValue, engine, _1, winml::TensorKind::Int64, winml::TensorKind::Float, _2 + ); } THROW_HR(E_NOTIMPL); } -HRESULT OnnxruntimeEngine::CreateSequenceOfMapsValue(IInspectable* sequence, winml::TensorKind key_kind, winml::TensorKind value_kind, _Out_ IValue** out) { +HRESULT OnnxruntimeEngine::CreateSequenceOfMapsValue( + IInspectable* sequence, winml::TensorKind key_kind, winml::TensorKind value_kind, _Out_ IValue** out +) { RETURN_IF_FAILED(GetSequenceOfMapsValueCreator(this, key_kind, value_kind)(sequence, out)); return S_OK; } @@ -1074,13 +1150,18 @@ static wf::IInspectable CreateMap(winml::TensorKind key_kind, winml::TensorKind return map_insp; } -HRESULT OnnxruntimeEngine::FillSequenceOfMapsValue(IInspectable* sequence, winml::TensorKind key_kind, winml::TensorKind value_kind, IValue* sequence_value) { +HRESULT OnnxruntimeEngine::FillSequenceOfMapsValue( + IInspectable* sequence, winml::TensorKind key_kind, winml::TensorKind value_kind, IValue* sequence_value +) { auto ort_api = engine_factory_->UseOrtApi(); auto onnxruntime_squence_value = static_cast(sequence_value); auto ort_sequence_value = onnxruntime_squence_value->UseOrtValue(); OrtAllocator* ort_allocator; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetAllocatorWithDefaultOptions(&ort_allocator), ort_api); // This should not be freed as this owned by ort + RETURN_HR_IF_NOT_OK_MSG( + ort_api->GetAllocatorWithDefaultOptions(&ort_allocator), + ort_api + ); // This should not be freed as this owned by ort size_t num_elements; RETURN_HR_IF_NOT_OK_MSG(ort_api->GetValueCount(ort_sequence_value, &num_elements), ort_api); @@ -1089,14 +1170,20 @@ HRESULT OnnxruntimeEngine::FillSequenceOfMapsValue(IInspectable* sequence, winml std::vector element_map_inspectables; for (size_t index = 0; index < num_elements; index++) { OrtValue* elements_ort_value = nullptr; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetValue(ort_sequence_value, static_cast(index), ort_allocator, &elements_ort_value), ort_api); + RETURN_HR_IF_NOT_OK_MSG( + ort_api->GetValue(ort_sequence_value, static_cast(index), ort_allocator, &elements_ort_value), ort_api + ); auto unique_element_value = UniqueOrtValue(elements_ort_value, ort_api->ReleaseValue); winrt::com_ptr element_value; - RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize(element_value.put(), this, std::move(unique_element_value), UniqueOrtAllocator(nullptr, nullptr))); + RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize( + element_value.put(), this, std::move(unique_element_value), UniqueOrtAllocator(nullptr, nullptr) + )); wf::IInspectable map_inspectable = CreateMap(key_kind, value_kind); - RETURN_IF_FAILED(FillFromMapValue(reinterpret_cast(winrt::get_abi(map_inspectable)), key_kind, value_kind, element_value.get())); + RETURN_IF_FAILED(FillFromMapValue( + reinterpret_cast(winrt::get_abi(map_inspectable)), key_kind, value_kind, element_value.get() + )); element_map_inspectables.push_back(map_inspectable); } @@ -1104,13 +1191,18 @@ HRESULT OnnxruntimeEngine::FillSequenceOfMapsValue(IInspectable* sequence, winml return S_OK; } -HRESULT OnnxruntimeEngine::GetSequenceOfTensorValues(_In_ _winml::IValue* sequence_value, _Out_ std::vector>& out_values) { +HRESULT OnnxruntimeEngine::GetSequenceOfTensorValues( + _In_ _winml::IValue* sequence_value, _Out_ std::vector>& out_values +) { auto ort_api = engine_factory_->UseOrtApi(); auto onnxruntime_squence_value = static_cast(sequence_value); auto ort_sequence_value = onnxruntime_squence_value->UseOrtValue(); OrtAllocator* ort_allocator; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetAllocatorWithDefaultOptions(&ort_allocator), ort_api); // This should not be freed as this owned by ort + RETURN_HR_IF_NOT_OK_MSG( + ort_api->GetAllocatorWithDefaultOptions(&ort_allocator), + ort_api + ); // This should not be freed as this owned by ort size_t num_elements; RETURN_HR_IF_NOT_OK_MSG(ort_api->GetValueCount(ort_sequence_value, &num_elements), ort_api); @@ -1119,19 +1211,22 @@ HRESULT OnnxruntimeEngine::GetSequenceOfTensorValues(_In_ _winml::IValue* sequen out_values.clear(); for (size_t index = 0; index < num_elements; index++) { OrtValue* elements_ort_value = nullptr; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetValue(ort_sequence_value, static_cast(index), ort_allocator, &elements_ort_value), ort_api); + RETURN_HR_IF_NOT_OK_MSG( + ort_api->GetValue(ort_sequence_value, static_cast(index), ort_allocator, &elements_ort_value), ort_api + ); auto unique_element_value = UniqueOrtValue(elements_ort_value, ort_api->ReleaseValue); winrt::com_ptr element_value; - RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize(element_value.put(), this, std::move(unique_element_value), UniqueOrtAllocator(nullptr, nullptr))); + RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize( + element_value.put(), this, std::move(unique_element_value), UniqueOrtAllocator(nullptr, nullptr) + )); out_values.push_back(element_value); } return S_OK; } -HRESULT OnnxruntimeEngine::GetNumberOfIntraOpThreads(uint32_t* num_threads) -{ +HRESULT OnnxruntimeEngine::GetNumberOfIntraOpThreads(uint32_t* num_threads) { auto ort_api = engine_factory_->UseOrtApi(); auto winml_adapter_api = engine_factory_->UseWinmlAdapterApi(); RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->SessionGetNumberOfIntraOpThreads(session_.get(), num_threads), ort_api); @@ -1145,7 +1240,6 @@ HRESULT OnnxruntimeEngine::GetIntraOpThreadSpinning(bool* allow_spinning) { return S_OK; } - HRESULT OnnxruntimeEngine::GetNamedDimensionOverrides(wfc::IMapView& overrides) { auto ort_api = engine_factory_->UseOrtApi(); auto winml_adapter_api = engine_factory_->UseWinmlAdapterApi(); @@ -1166,19 +1260,24 @@ HRESULT OnnxruntimeEngine::CreateOneInputAcrossDevices(const char* name, IValue* if (is_tensor && !is_empty) { int16_t source_location; int16_t input_required_location; - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->ValueGetDeviceId(src_value->UseOrtValue(), &source_location), - ort_api); - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->SessionGetInputRequiredDeviceId(session_.get(), name, &input_required_location), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->ValueGetDeviceId(src_value->UseOrtValue(), &source_location), ort_api); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->SessionGetInputRequiredDeviceId(session_.get(), name, &input_required_location), ort_api + ); if (source_location != input_required_location) { OrtValue* dest_ort_value = nullptr; - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->SessionCopyOneInputAcrossDevices(session_.get(), name, - src_value->UseOrtValue(), &dest_ort_value), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->SessionCopyOneInputAcrossDevices( + session_.get(), name, src_value->UseOrtValue(), &dest_ort_value + ), + ort_api + ); auto unique_dest_ort_value = UniqueOrtValue(dest_ort_value, ort_api->ReleaseValue); - RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize(out, this, std::move(unique_dest_ort_value), UniqueOrtAllocator(nullptr, nullptr))); + RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize( + out, this, std::move(unique_dest_ort_value), UniqueOrtAllocator(nullptr, nullptr) + )); return S_OK; } } @@ -1188,43 +1287,45 @@ HRESULT OnnxruntimeEngine::CreateOneInputAcrossDevices(const char* name, IValue* return S_OK; } -HRESULT OnnxruntimeEngine::Run(const char** input_names, IValue** inputs, size_t num_inputs, const char** output_names, IValue** outputs, size_t num_outputs) { +HRESULT OnnxruntimeEngine::Run( + const char** input_names, + IValue** inputs, + size_t num_inputs, + const char** output_names, + IValue** outputs, + size_t num_outputs +) { auto ort_api = engine_factory_->UseOrtApi(); OrtRunOptions* run_options; - RETURN_HR_IF_NOT_OK_MSG(ort_api->CreateRunOptions(&run_options), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->CreateRunOptions(&run_options), ort_api); auto unique_run_options = UniqueOrtRunOptions(run_options, ort_api->ReleaseRunOptions); std::vector input_ort_values; - std::transform( - inputs, - inputs + num_inputs, - std::back_inserter(input_ort_values), - [&](auto& input) { - auto input_value = static_cast(input); - return input_value->UseOrtValue(); - }); + std::transform(inputs, inputs + num_inputs, std::back_inserter(input_ort_values), [&](auto& input) { + auto input_value = static_cast(input); + return input_value->UseOrtValue(); + }); std::vector output_ort_values; - std::transform( - outputs, - outputs + num_outputs, - std::back_inserter(output_ort_values), - [&](auto& output) { - auto output_value = static_cast(output); - return output_value->UseOrtValue(); - }); + std::transform(outputs, outputs + num_outputs, std::back_inserter(output_ort_values), [&](auto& output) { + auto output_value = static_cast(output); + return output_value->UseOrtValue(); + }); - RETURN_HR_IF_NOT_OK_MSG(ort_api->Run(session_.get(), - unique_run_options.get(), - input_names, - input_ort_values.data(), - num_inputs, - output_names, - num_outputs, - output_ort_values.data()), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + ort_api->Run( + session_.get(), + unique_run_options.get(), + input_names, + input_ort_values.data(), + num_inputs, + output_names, + num_outputs, + output_ort_values.data() + ), + ort_api + ); for (size_t index = 0; index < num_outputs; index++) { auto output_value = static_cast(outputs[index]); @@ -1244,9 +1345,7 @@ HRESULT FillAbiMap(IInspectable* map_insp, size_t num_elements, void* keys_data, auto values = reinterpret_cast::ResourceType*>(values_data); for (size_t i = 0; i < num_elements; ++i) { - map.Insert( - ResourceTypeToCppwinrtType(keys[i]), - ResourceTypeToCppwinrtType(values[i])); + map.Insert(ResourceTypeToCppwinrtType(keys[i]), ResourceTypeToCppwinrtType(values[i])); } return S_OK; } @@ -1274,30 +1373,36 @@ static auto GetAbiMapFiller(winml::TensorKind key_kind, winml::TensorKind value_ THROW_HR(E_NOTIMPL); } -HRESULT OnnxruntimeEngine::FillFromMapValue(IInspectable* map, winml::TensorKind key_kind, winml::TensorKind value_kind, IValue* map_value) { +HRESULT OnnxruntimeEngine::FillFromMapValue( + IInspectable* map, winml::TensorKind key_kind, winml::TensorKind value_kind, IValue* map_value +) { auto ort_api = engine_factory_->UseOrtApi(); auto onnxruntime_map_value = static_cast(map_value); auto ort_map_value = onnxruntime_map_value->UseOrtValue(); OrtAllocator* ort_allocator; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetAllocatorWithDefaultOptions(&ort_allocator), - ort_api); // This should not be freed as this owned by ort + RETURN_HR_IF_NOT_OK_MSG( + ort_api->GetAllocatorWithDefaultOptions(&ort_allocator), + ort_api + ); // This should not be freed as this owned by ort // get the keys OrtValue* keys_ort_value = nullptr; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetValue(ort_map_value, 0, ort_allocator, &keys_ort_value), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->GetValue(ort_map_value, 0, ort_allocator, &keys_ort_value), ort_api); auto unique_keys_value = UniqueOrtValue(keys_ort_value, ort_api->ReleaseValue); winrt::com_ptr keys_value; - RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize(keys_value.put(), this, std::move(unique_keys_value), UniqueOrtAllocator(nullptr, nullptr))); + RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize( + keys_value.put(), this, std::move(unique_keys_value), UniqueOrtAllocator(nullptr, nullptr) + )); // get the keys OrtValue* values_ort_value = nullptr; - RETURN_HR_IF_NOT_OK_MSG(ort_api->GetValue(ort_map_value, 1, ort_allocator, &values_ort_value), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(ort_api->GetValue(ort_map_value, 1, ort_allocator, &values_ort_value), ort_api); auto unique_values_value = UniqueOrtValue(values_ort_value, ort_api->ReleaseValue); winrt::com_ptr values_value; - RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize(values_value.put(), this, std::move(unique_values_value), UniqueOrtAllocator(nullptr, nullptr))); + RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize( + values_value.put(), this, std::move(unique_values_value), UniqueOrtAllocator(nullptr, nullptr) + )); std::vector keys_shape; keys_value->GetTensorShape(keys_shape); @@ -1329,12 +1434,12 @@ HRESULT OnnxruntimeEngineFactory::EnsureEnvironment() { return S_OK; } -STDMETHODIMP OnnxruntimeEngineFactory::CreateModel(_In_ const char* model_path, _In_ size_t len, _Outptr_ IModel** out) { +STDMETHODIMP +OnnxruntimeEngineFactory::CreateModel(_In_ const char* model_path, _In_ size_t len, _Outptr_ IModel** out) { RETURN_IF_FAILED(EnsureEnvironment()); OrtModel* ort_model = nullptr; - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api_->CreateModelFromPath(model_path, len, &ort_model), - ort_api_); + RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api_->CreateModelFromPath(model_path, len, &ort_model), ort_api_); auto model = UniqueOrtModel(ort_model, winml_adapter_api_->ReleaseModel); RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize(out, this, std::move(model))); @@ -1394,8 +1499,7 @@ HRESULT OnnxruntimeEngineFactory::EnableDebugOutput(bool is_enabled) { } HRESULT OnnxruntimeEngineFactory::CreateCustomRegistry(_Out_ IMLOperatorRegistry** registry) { - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api_->CreateCustomRegistry(registry), - ort_api_); + RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api_->CreateCustomRegistry(registry), ort_api_); return S_OK; } @@ -1406,9 +1510,9 @@ STDAPI CreateOnnxruntimeEngineFactory(_Out_ _winml::IEngineFactory** engine_fact return S_OK; } struct OrtDescriptorInfo : public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags, - IDescriptorInfo, - IOrtTypeInfoProvider> { + Microsoft::WRL::RuntimeClassFlags, + IDescriptorInfo, + IOrtTypeInfoProvider> { OrtDescriptorInfo() : info_(nullptr, nullptr) {} HRESULT RuntimeClassInitialize(UniqueOrtTypeInfo info) { @@ -1421,18 +1525,19 @@ struct OrtDescriptorInfo : public Microsoft::WRL::RuntimeClass< return S_OK; } - OrtTypeInfo* UseOrtTypeInfo() { - return info_.get(); - } + OrtTypeInfo* UseOrtTypeInfo() { return info_.get(); } - private: + private: UniqueOrtTypeInfo info_; }; -HRESULT OnnxruntimeEngineFactory::CreateTensorDescriptorInfo(_In_ winml::TensorKind kind, _In_ int64_t* dims, - _In_ size_t num_dims, _Out_ IDescriptorInfo** tensor_info) { +HRESULT OnnxruntimeEngineFactory::CreateTensorDescriptorInfo( + _In_ winml::TensorKind kind, _In_ int64_t* dims, _In_ size_t num_dims, _Out_ IDescriptorInfo** tensor_info +) { OrtTypeInfo* tensor_type_info = nullptr; - winml_adapter_api_->CreateTensorTypeInfo(dims, num_dims, ONNXTensorElementDataTypeFromTensorKind(kind), &tensor_type_info); + winml_adapter_api_->CreateTensorTypeInfo( + dims, num_dims, ONNXTensorElementDataTypeFromTensorKind(kind), &tensor_type_info + ); UniqueOrtTypeInfo info(tensor_type_info, ort_api_->ReleaseTypeInfo); Microsoft::WRL::ComPtr descriptor_info; @@ -1463,7 +1568,9 @@ HRESULT OnnxruntimeEngineFactory::CreateMapDescriptorInfo(_Out_ IDescriptorInfo* return S_OK; } -HRESULT OnnxruntimeEngineFactory::CreateThreadPool(_In_ bool allow_spinning, _In_ uint32_t num_intra_op_threads, _Out_ IThreading** thread_pool) { +HRESULT OnnxruntimeEngineFactory::CreateThreadPool( + _In_ bool allow_spinning, _In_ uint32_t num_intra_op_threads, _Out_ IThreading** thread_pool +) { Microsoft::WRL::ComPtr threading; RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&threading, this)); @@ -1474,8 +1581,10 @@ HRESULT OnnxruntimeEngineFactory::CreateThreadPool(_In_ bool allow_spinning, _In intra_op_params.allow_spinning = allow_spinning; OrtThreadPool* ort_intra_op_thread_pool = nullptr; - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api_->CreateThreadPool(ThreadPoolType::INTRA_OP, &intra_op_params, &ort_intra_op_thread_pool), - ort_api_); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api_->CreateThreadPool(ThreadPoolType::INTRA_OP, &intra_op_params, &ort_intra_op_thread_pool), + ort_api_ + ); UniqueOrtThreadPool intra_op_pool(ort_intra_op_thread_pool, winml_adapter_api_->ReleaseThreadPool); threading->SetIntraOpThreadPool(std::move(intra_op_pool)); @@ -1485,10 +1594,10 @@ HRESULT OnnxruntimeEngineFactory::CreateThreadPool(_In_ bool allow_spinning, _In return S_OK; } -OnnxruntimeThreading::OnnxruntimeThreading() : - inter_op_ort_pool_(nullptr, nullptr), - intra_op_ort_pool_(nullptr, nullptr) -{} +OnnxruntimeThreading::OnnxruntimeThreading() + : inter_op_ort_pool_(nullptr, nullptr), + intra_op_ort_pool_(nullptr, nullptr) { +} OnnxruntimeThreading::~OnnxruntimeThreading() = default; HRESULT OnnxruntimeThreading::RuntimeClassInitialize(OnnxruntimeEngineFactory* engine_factory) { @@ -1509,12 +1618,10 @@ HRESULT OnnxruntimeThreading::SetInterOpThreadPool(UniqueOrtThreadPool&& inter_o return S_OK; } -OrtThreadPool* OnnxruntimeThreading::UseIntraOpThreadPool() -{ +OrtThreadPool* OnnxruntimeThreading::UseIntraOpThreadPool() { return intra_op_ort_pool_.get(); } -OrtThreadPool* OnnxruntimeThreading::UseInterOpThreadPool() -{ +OrtThreadPool* OnnxruntimeThreading::UseInterOpThreadPool() { return inter_op_ort_pool_.get(); } diff --git a/winml/lib/Api.Ort/OnnxruntimeEngine.h b/winml/lib/Api.Ort/OnnxruntimeEngine.h index 097941e78f1a5..eae7dc37941c7 100644 --- a/winml/lib/Api.Ort/OnnxruntimeEngine.h +++ b/winml/lib/Api.Ort/OnnxruntimeEngine.h @@ -3,6 +3,7 @@ #include "iengine.h" #include "UniqueOrtPtr.h" +#include "core/common/gsl.h" #include #include @@ -18,9 +19,8 @@ class OnnxruntimeThreading; struct IOrtSessionBuilder; -class OnnxruntimeValue : public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags, - IValue> { +class OnnxruntimeValue + : public Microsoft::WRL::RuntimeClass, IValue> { public: OnnxruntimeValue(); ~OnnxruntimeValue(); @@ -58,12 +58,15 @@ class OnnxruntimeValue : public Microsoft::WRL::RuntimeClass< UniqueOrtAllocator allocator_; }; -class OnnxruntimeEngine : public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags, - IEngine> { +class OnnxruntimeEngine + : public Microsoft::WRL::RuntimeClass, IEngine> { public: OnnxruntimeEngine(); - HRESULT RuntimeClassInitialize(OnnxruntimeEngineFactory* engine_factory, UniqueOrtSession&& session, IOrtSessionBuilder* session_builder); + ~OnnxruntimeEngine(); + + HRESULT RuntimeClassInitialize( + OnnxruntimeEngineFactory* engine_factory, UniqueOrtSession&& session, IOrtSessionBuilder* session_builder + ); STDMETHOD(LoadModel) (_In_ IModel* model) override; @@ -88,7 +91,8 @@ class OnnxruntimeEngine : public Microsoft::WRL::RuntimeClass< STDMETHOD(CreateTensorValueFromExternalD3DResource) (ID3D12Resource* resource, const int64_t* shape, size_t count, winml::TensorKind kind, _Out_ IValue** out) override; STDMETHOD(CreateTensorValueFromExternalBuffer) - (void* data, size_t size_in_bytes, const int64_t* shape, size_t count, winml::TensorKind kind, _Out_ IValue** out) override; + (void* data, size_t size_in_bytes, const int64_t* shape, size_t count, winml::TensorKind kind, _Out_ IValue** out + ) override; STDMETHOD(CreateStringTensorValueFromDataWithCopy) (const char* const* data, size_t num_elements, const int64_t* shape, size_t count, _Out_ IValue** out) override; STDMETHOD(CreateNullValue) @@ -98,21 +102,26 @@ class OnnxruntimeEngine : public Microsoft::WRL::RuntimeClass< STDMETHOD(CreateSequenceOfMapsValue) (IInspectable* map, winml::TensorKind key_kind, winml::TensorKind value_kind, _Out_ IValue** out) override; STDMETHOD(CreateSequenceOfValuesValue) - (IValue ** values, size_t size, IValue * *out) override; + (IValue** values, size_t size, IValue** out) override; STDMETHOD(CreateOneInputAcrossDevices) (const char* name, IValue* src, IValue** dest) override; STDMETHOD(CopyValueAcrossDevices) (IValue* src, IValue* dest) override; STDMETHOD(Run) - (const char** input_names, IValue** inputs, size_t num_inputs, const char** output_names, IValue** outputs, size_t num_outputs) override; + (const char** input_names, + IValue** inputs, + size_t num_inputs, + const char** output_names, + IValue** outputs, + size_t num_outputs) override; STDMETHOD(FillFromMapValue) (IInspectable* map, winml::TensorKind key_kind, winml::TensorKind value_kind, IValue* value) override; STDMETHOD(FillSequenceOfMapsValue) (IInspectable* sequence, winml::TensorKind key_kind, winml::TensorKind value_kind, IValue* value) override; STDMETHOD(GetSequenceOfTensorValues) - (_In_ _winml::IValue* sequence_value, _Out_ std::vector>& out_values) override; + (_In_ _winml::IValue* sequence_value, _Out_ std::vector>& out_values) override; STDMETHOD(GetNumberOfIntraOpThreads) (uint32_t* num_threads) override; @@ -126,17 +135,20 @@ class OnnxruntimeEngine : public Microsoft::WRL::RuntimeClass< OrtSession* UseOrtSession(); const OrtApi* UseOrtApi(); OnnxruntimeEngineFactory* GetEngineFactory(); - HRESULT CreateTensorValueFromDefaultAllocator(const int64_t* shape, size_t count, winml::TensorKind kind, _Out_ IValue** out); + HRESULT + CreateTensorValueFromDefaultAllocator(const int64_t* shape, size_t count, winml::TensorKind kind, _Out_ IValue** out); + + HRESULT RegisterCustomOpLibraryHandles(const gsl::span handles); private: Microsoft::WRL::ComPtr engine_factory_; Microsoft::WRL::ComPtr session_builder_; UniqueOrtSession session_; + std::vector custom_op_library_handles_; }; -class OnnxruntimeEngineFactory : public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags, - IEngineFactory> { +class OnnxruntimeEngineFactory + : public Microsoft::WRL::RuntimeClass, IEngineFactory> { public: HRESULT RuntimeClassInitialize(); STDMETHOD(CreateModel) @@ -176,10 +188,9 @@ class OnnxruntimeEngineFactory : public Microsoft::WRL::RuntimeClass< std::mutex mutex_; }; -class OnnxruntimeThreading : public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags, - IThreading> { -public: +class OnnxruntimeThreading + : public Microsoft::WRL::RuntimeClass, IThreading> { + public: OnnxruntimeThreading(); ~OnnxruntimeThreading(); @@ -190,11 +201,10 @@ class OnnxruntimeThreading : public Microsoft::WRL::RuntimeClass< OrtThreadPool* UseIntraOpThreadPool(); OrtThreadPool* UseInterOpThreadPool(); -private: + private: Microsoft::WRL::ComPtr engine_factory_ = nullptr; UniqueOrtThreadPool inter_op_ort_pool_; UniqueOrtThreadPool intra_op_ort_pool_; - }; } // namespace _winml diff --git a/winml/lib/Api.Ort/OnnxruntimeEngineBuilder.cpp b/winml/lib/Api.Ort/OnnxruntimeEngineBuilder.cpp index f98a98476d0e6..8ddcbe537ebd9 100644 --- a/winml/lib/Api.Ort/OnnxruntimeEngineBuilder.cpp +++ b/winml/lib/Api.Ort/OnnxruntimeEngineBuilder.cpp @@ -20,15 +20,20 @@ HRESULT OnnxruntimeEngineBuilder::RuntimeClassInitialize(_In_ OnnxruntimeEngineF } STDMETHODIMP OnnxruntimeEngineBuilder::CreateEngine(_Outptr_ _winml::IEngine** out) { + *out = nullptr; auto ort_api = engine_factory_->UseOrtApi(); Microsoft::WRL::ComPtr onnxruntime_session_builder; if (device_ == nullptr) { - RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&onnxruntime_session_builder, engine_factory_.Get())); + RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize( + &onnxruntime_session_builder, engine_factory_.Get() + )); } else { #ifdef USE_DML - RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&onnxruntime_session_builder, engine_factory_.Get(), device_.Get(), queue_.Get(), metacommands_enabled_)); + RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize( + &onnxruntime_session_builder, engine_factory_.Get(), device_.Get(), queue_.Get(), metacommands_enabled_ + )); #endif } @@ -38,8 +43,9 @@ STDMETHODIMP OnnxruntimeEngineBuilder::CreateEngine(_Outptr_ _winml::IEngine** o if (batch_size_override_.has_value()) { constexpr const char* DATA_BATCH = "DATA_BATCH"; - RETURN_HR_IF_NOT_OK_MSG(ort_api->AddFreeDimensionOverride(session_options.get(), DATA_BATCH, batch_size_override_.value()), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + ort_api->AddFreeDimensionOverride(session_options.get(), DATA_BATCH, batch_size_override_.value()), ort_api + ); } if (named_dimension_overrides_) { for (const auto& override : named_dimension_overrides_) { @@ -49,23 +55,38 @@ STDMETHODIMP OnnxruntimeEngineBuilder::CreateEngine(_Outptr_ _winml::IEngine** o } if (intra_op_num_threads_override_.has_value()) { - RETURN_HR_IF_NOT_OK_MSG(ort_api->SetIntraOpNumThreads(session_options.get(), intra_op_num_threads_override_.value()), ort_api); + RETURN_HR_IF_NOT_OK_MSG( + ort_api->SetIntraOpNumThreads(session_options.get(), intra_op_num_threads_override_.value()), ort_api + ); } if (!allow_thread_spinning_) { - ort_api->AddSessionConfigEntry(session_options.get(), "session.intra_op.allow_spinning", "0"); + RETURN_HR_IF_NOT_OK_MSG( + ort_api->AddSessionConfigEntry(session_options.get(), "session.intra_op.allow_spinning", "0"), ort_api + ); } - OrtThreadPool* inter_op_ort_pool = thread_pool_ ? static_cast(thread_pool_.Get())->UseInterOpThreadPool() : nullptr; - OrtThreadPool* intra_op_ort_pool = thread_pool_ ? static_cast(thread_pool_.Get())->UseIntraOpThreadPool() : nullptr; + std::vector handles; + for (const auto& path : custom_ops_lib_paths_) { + void* handle = nullptr; + RETURN_HR_IF_NOT_OK_MSG(ort_api->RegisterCustomOpsLibrary(session_options.get(), path.c_str(), &handle), ort_api); + handles.push_back(handle); + } + + OrtThreadPool* inter_op_ort_pool = + thread_pool_ ? static_cast(thread_pool_.Get())->UseInterOpThreadPool() : nullptr; + OrtThreadPool* intra_op_ort_pool = + thread_pool_ ? static_cast(thread_pool_.Get())->UseIntraOpThreadPool() : nullptr; OrtSession* ort_session = nullptr; onnxruntime_session_builder->CreateSession(session_options.get(), inter_op_ort_pool, intra_op_ort_pool, &ort_session); auto session = UniqueOrtSession(ort_session, ort_api->ReleaseSession); Microsoft::WRL::ComPtr onnxruntime_engine; - RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&onnxruntime_engine, - engine_factory_.Get(), std::move(session), onnxruntime_session_builder.Get())); + RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize( + &onnxruntime_engine, engine_factory_.Get(), std::move(session), onnxruntime_session_builder.Get() + )); + RETURN_IF_FAILED(onnxruntime_engine->RegisterCustomOpLibraryHandles(handles)); RETURN_IF_FAILED(onnxruntime_engine.CopyTo(out)); return S_OK; } @@ -96,16 +117,23 @@ STDMETHODIMP OnnxruntimeEngineBuilder::SetBatchSizeOverride(uint32_t batch_size_ return S_OK; } -STDMETHODIMP OnnxruntimeEngineBuilder::SetNamedDimensionOverrides(wfc::IMapView named_dimension_overrides) { +STDMETHODIMP OnnxruntimeEngineBuilder::SetNamedDimensionOverrides( + wfc::IMapView named_dimension_overrides +) { named_dimension_overrides_ = std::move(named_dimension_overrides); return S_OK; } - + STDMETHODIMP OnnxruntimeEngineBuilder::SetIntraOpNumThreadsOverride(uint32_t intra_op_num_threads) { intra_op_num_threads_override_ = intra_op_num_threads; return S_OK; } +STDMETHODIMP OnnxruntimeEngineBuilder::RegisterCustomOpsLibrary(const char* path) { + custom_ops_lib_paths_.push_back(path); + return S_OK; +} + STDMETHODIMP OnnxruntimeEngineBuilder::SetIntraOpThreadSpinning(bool allow_spinning) { allow_thread_spinning_ = allow_spinning; return S_OK; @@ -114,4 +142,4 @@ STDMETHODIMP OnnxruntimeEngineBuilder::SetIntraOpThreadSpinning(bool allow_spinn STDMETHODIMP OnnxruntimeEngineBuilder::SetThreadPool(IThreading* thread_pool) { thread_pool_ = thread_pool; return S_OK; -} \ No newline at end of file +} diff --git a/winml/lib/Api.Ort/OnnxruntimeEngineBuilder.h b/winml/lib/Api.Ort/OnnxruntimeEngineBuilder.h index 42cb57190e93f..99add42297f20 100644 --- a/winml/lib/Api.Ort/OnnxruntimeEngineBuilder.h +++ b/winml/lib/Api.Ort/OnnxruntimeEngineBuilder.h @@ -5,9 +5,8 @@ namespace _winml { -class OnnxruntimeEngineBuilder : public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags, - IEngineBuilder> { +class OnnxruntimeEngineBuilder + : public Microsoft::WRL::RuntimeClass, IEngineBuilder> { public: HRESULT RuntimeClassInitialize(_In_ OnnxruntimeEngineFactory* engine); @@ -38,6 +37,9 @@ class OnnxruntimeEngineBuilder : public Microsoft::WRL::RuntimeClass< STDMETHOD(SetThreadPool) (IThreading* thread_pool); + STDMETHOD(RegisterCustomOpsLibrary) + (const char* path); + STDMETHOD(CreateEngine) (_Outptr_ IEngine** out); @@ -51,6 +53,7 @@ class OnnxruntimeEngineBuilder : public Microsoft::WRL::RuntimeClass< wfc::IMapView named_dimension_overrides_; std::optional intra_op_num_threads_override_; bool allow_thread_spinning_ = true; + std::vector custom_ops_lib_paths_; }; -} // namespace _winml \ No newline at end of file +} // namespace _winml diff --git a/winml/lib/Api.Ort/OnnxruntimeEnvironment.cpp b/winml/lib/Api.Ort/OnnxruntimeEnvironment.cpp index b47d1c211bd63..56a360218fa1d 100644 --- a/winml/lib/Api.Ort/OnnxruntimeEnvironment.cpp +++ b/winml/lib/Api.Ort/OnnxruntimeEnvironment.cpp @@ -36,7 +36,7 @@ static HRESULT GetOnnxruntimeLibrary(HMODULE& module) { // Store + Redist (note that this is never built into the inbox dll) auto out_module = LoadPackagedLibrary(L"onnxruntime.dll", 0); #else - auto onnxruntime_dll = CurrentModulePath() + L"\\onnxruntime.dll"; + auto onnxruntime_dll = CurrentModulePath() + L"\\onnxruntime.dll"; auto out_module = LoadLibraryExW(onnxruntime_dll.c_str(), nullptr, 0); #endif @@ -52,7 +52,8 @@ const OrtApi* _winml::GetVersionedOrtApi() { FAIL_FAST_IF_FAILED(GetOnnxruntimeLibrary(onnxruntime_dll)); using OrtGetApiBaseSignature = decltype(OrtGetApiBase); - auto ort_get_api_base_fn = reinterpret_cast(GetProcAddress(onnxruntime_dll, "OrtGetApiBase")); + auto ort_get_api_base_fn = + reinterpret_cast(GetProcAddress(onnxruntime_dll, "OrtGetApiBase")); if (ort_get_api_base_fn == nullptr) { FAIL_FAST_HR(HRESULT_FROM_WIN32(GetLastError())); } @@ -66,7 +67,8 @@ static const WinmlAdapterApi* GetVersionedWinmlAdapterApi(const OrtApi* ort_api) FAIL_FAST_IF_FAILED(GetOnnxruntimeLibrary(onnxruntime_dll)); using OrtGetWinMLAdapterSignature = decltype(OrtGetWinMLAdapter); - auto ort_get_winml_adapter_fn = reinterpret_cast(GetProcAddress(onnxruntime_dll, "OrtGetWinMLAdapter")); + auto ort_get_winml_adapter_fn = + reinterpret_cast(GetProcAddress(onnxruntime_dll, "OrtGetWinMLAdapter")); if (ort_get_winml_adapter_fn == nullptr) { FAIL_FAST_HR(HRESULT_FROM_WIN32(GetLastError())); } @@ -78,77 +80,88 @@ const WinmlAdapterApi* _winml::GetVersionedWinmlAdapterApi() { return GetVersionedWinmlAdapterApi(GetVersionedOrtApi()); } -static void __stdcall WinmlOrtLoggingCallback(void* param, OrtLoggingLevel severity, const char* category, - const char* logger_id, const char* code_location, const char* message) noexcept { +static void __stdcall WinmlOrtLoggingCallback( + void* param, + OrtLoggingLevel severity, + const char* category, + const char* logger_id, + const char* code_location, + const char* message +) noexcept { UNREFERENCED_PARAMETER(param); UNREFERENCED_PARAMETER(logger_id); // ORT Fatal and Error Messages are logged as Telemetry, rest are non-telemetry. switch (severity) { case OrtLoggingLevel::ORT_LOGGING_LEVEL_FATAL: //Telemetry TraceLoggingWrite( - winml_trace_logging_provider, - "WinMLLogSink", - TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), - TraceLoggingLevel(WINEVENT_LEVEL_CRITICAL), - TraceLoggingOpcode(EVENT_TRACE_TYPE_INFO), - TraceLoggingString(category), - TraceLoggingUInt32((UINT32)severity), - TraceLoggingString(message), - TraceLoggingString(code_location), - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)); + winml_trace_logging_provider, + "WinMLLogSink", + TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), + TraceLoggingLevel(WINEVENT_LEVEL_CRITICAL), + TraceLoggingOpcode(EVENT_TRACE_TYPE_INFO), + TraceLoggingString(category), + TraceLoggingUInt32((UINT32)severity), + TraceLoggingString(message), + TraceLoggingString(code_location), + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES) + ); break; case OrtLoggingLevel::ORT_LOGGING_LEVEL_ERROR: //Telemetry TraceLoggingWrite( - winml_trace_logging_provider, - "WinMLLogSink", - TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), - TraceLoggingLevel(WINEVENT_LEVEL_ERROR), - TraceLoggingOpcode(EVENT_TRACE_TYPE_INFO), - TraceLoggingString(category), - TraceLoggingUInt32((UINT32)severity), - TraceLoggingString(message), - TraceLoggingString(code_location), - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)); + winml_trace_logging_provider, + "WinMLLogSink", + TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), + TraceLoggingLevel(WINEVENT_LEVEL_ERROR), + TraceLoggingOpcode(EVENT_TRACE_TYPE_INFO), + TraceLoggingString(category), + TraceLoggingUInt32((UINT32)severity), + TraceLoggingString(message), + TraceLoggingString(code_location), + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES) + ); break; case OrtLoggingLevel::ORT_LOGGING_LEVEL_WARNING: TraceLoggingWrite( - winml_trace_logging_provider, - "WinMLLogSink", - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), - TraceLoggingLevel(WINEVENT_LEVEL_WARNING), - TraceLoggingOpcode(EVENT_TRACE_TYPE_INFO), - TraceLoggingString(category), - TraceLoggingUInt32((UINT32)severity), - TraceLoggingString(message), - TraceLoggingString(code_location)); + winml_trace_logging_provider, + "WinMLLogSink", + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), + TraceLoggingLevel(WINEVENT_LEVEL_WARNING), + TraceLoggingOpcode(EVENT_TRACE_TYPE_INFO), + TraceLoggingString(category), + TraceLoggingUInt32((UINT32)severity), + TraceLoggingString(message), + TraceLoggingString(code_location) + ); break; case OrtLoggingLevel::ORT_LOGGING_LEVEL_INFO: TraceLoggingWrite( - winml_trace_logging_provider, - "WinMLLogSink", - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), - TraceLoggingLevel(WINEVENT_LEVEL_INFO), - TraceLoggingOpcode(EVENT_TRACE_TYPE_INFO), - TraceLoggingString(category), - TraceLoggingUInt32((UINT32)severity), - TraceLoggingString(message), - TraceLoggingString(code_location)); + winml_trace_logging_provider, + "WinMLLogSink", + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), + TraceLoggingLevel(WINEVENT_LEVEL_INFO), + TraceLoggingOpcode(EVENT_TRACE_TYPE_INFO), + TraceLoggingString(category), + TraceLoggingUInt32((UINT32)severity), + TraceLoggingString(message), + TraceLoggingString(code_location) + ); break; case OrtLoggingLevel::ORT_LOGGING_LEVEL_VERBOSE: __fallthrough; //Default is Verbose too. default: TraceLoggingWrite( - winml_trace_logging_provider, - "WinMLLogSink", - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), - TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE), - TraceLoggingOpcode(EVENT_TRACE_TYPE_INFO), - TraceLoggingString(category), - TraceLoggingUInt32((UINT32)severity), - TraceLoggingString(message), - TraceLoggingString(code_location)); + winml_trace_logging_provider, + "WinMLLogSink", + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), + TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE), + TraceLoggingOpcode(EVENT_TRACE_TYPE_INFO), + TraceLoggingString(category), + TraceLoggingUInt32((UINT32)severity), + TraceLoggingString(message), + TraceLoggingString(code_location) + ); } if (debug_output_) { @@ -159,42 +172,48 @@ static void __stdcall WinmlOrtLoggingCallback(void* param, OrtLoggingLevel sever static void __stdcall WinmlOrtProfileEventCallback(const OrtProfilerEventRecord* profiler_record) noexcept { if (profiler_record->category_ == OrtProfilerEventCategory::NODE_EVENT) { TraceLoggingWrite( - winml_trace_logging_provider, - "OnnxRuntimeProfiling", - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_LOTUS_PROFILING), - TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE), - TraceLoggingOpcode(EVENT_TRACE_TYPE_INFO), - TraceLoggingString(profiler_record->category_name_, "Category"), - TraceLoggingInt64(profiler_record->duration_, "Duration (us)"), - TraceLoggingInt64(profiler_record->time_span_, "Time Stamp (us)"), - TraceLoggingString(profiler_record->event_name_, "Event Name"), - TraceLoggingInt32(profiler_record->process_id_, "Process ID"), - TraceLoggingInt32(profiler_record->thread_id_, "Thread ID"), - TraceLoggingString(profiler_record->op_name_, "Operator Name"), - TraceLoggingString(profiler_record->execution_provider_, "Execution Provider")); + winml_trace_logging_provider, + "OnnxRuntimeProfiling", + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_LOTUS_PROFILING), + TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE), + TraceLoggingOpcode(EVENT_TRACE_TYPE_INFO), + TraceLoggingString(profiler_record->category_name_, "Category"), + TraceLoggingInt64(profiler_record->duration_, "Duration (us)"), + TraceLoggingInt64(profiler_record->time_span_, "Time Stamp (us)"), + TraceLoggingString(profiler_record->event_name_, "Event Name"), + TraceLoggingInt32(profiler_record->process_id_, "Process ID"), + TraceLoggingInt32(profiler_record->thread_id_, "Thread ID"), + TraceLoggingString(profiler_record->op_name_, "Operator Name"), + TraceLoggingString(profiler_record->execution_provider_, "Execution Provider") + ); } else { TraceLoggingWrite( - winml_trace_logging_provider, - "OnnxRuntimeProfiling", - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_LOTUS_PROFILING), - TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE), - TraceLoggingOpcode(EVENT_TRACE_TYPE_INFO), - TraceLoggingString(profiler_record->category_name_, "Category"), - TraceLoggingInt64(profiler_record->duration_, "Duration (us)"), - TraceLoggingInt64(profiler_record->time_span_, "Time Stamp (us)"), - TraceLoggingString(profiler_record->event_name_, "Event Name"), - TraceLoggingInt32(profiler_record->process_id_, "Process ID"), - TraceLoggingInt32(profiler_record->thread_id_, "Thread ID")); + winml_trace_logging_provider, + "OnnxRuntimeProfiling", + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_LOTUS_PROFILING), + TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE), + TraceLoggingOpcode(EVENT_TRACE_TYPE_INFO), + TraceLoggingString(profiler_record->category_name_, "Category"), + TraceLoggingInt64(profiler_record->duration_, "Duration (us)"), + TraceLoggingInt64(profiler_record->time_span_, "Time Stamp (us)"), + TraceLoggingString(profiler_record->event_name_, "Event Name"), + TraceLoggingInt32(profiler_record->process_id_, "Process ID"), + TraceLoggingInt32(profiler_record->thread_id_, "Thread ID") + ); } } -static void OnSuspending(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::ApplicationModel::SuspendingEventArgs const& args) { +static void OnSuspending( + winrt::Windows::Foundation::IInspectable const& sender, + winrt::Windows::ApplicationModel::SuspendingEventArgs const& args +) { telemetry_helper.LogWinMLSuspended(); } void OnnxruntimeEnvironment::RegisterSuspendHandler() { try { - auto suspend_event_handler = winrt::Windows::Foundation::EventHandler(&OnSuspending); + auto suspend_event_handler = + winrt::Windows::Foundation::EventHandler(&OnSuspending); suspend_token_ = winrt::Windows::ApplicationModel::Core::CoreApplication::Suspending(suspend_event_handler); } catch (...) { } //Catch in case CoreApplication cannot be found for non-UWP executions @@ -202,16 +221,23 @@ void OnnxruntimeEnvironment::RegisterSuspendHandler() { OnnxruntimeEnvironment::OnnxruntimeEnvironment(const OrtApi* ort_api) : ort_env_(nullptr, nullptr) { OrtEnv* ort_env = nullptr; - THROW_IF_NOT_OK_MSG(ort_api->CreateEnv(OrtLoggingLevel::ORT_LOGGING_LEVEL_VERBOSE, "Default", &ort_env), - ort_api); + THROW_IF_NOT_OK_MSG(ort_api->CreateEnv(OrtLoggingLevel::ORT_LOGGING_LEVEL_VERBOSE, "Default", &ort_env), ort_api); THROW_IF_NOT_OK_MSG(ort_api->SetLanguageProjection(ort_env, OrtLanguageProjection::ORT_PROJECTION_WINML), ort_api); ort_env_ = UniqueOrtEnv(ort_env, ort_api->ReleaseEnv); // Configure the environment with the winml logger auto winml_adapter_api = GetVersionedWinmlAdapterApi(ort_api); - THROW_IF_NOT_OK_MSG(winml_adapter_api->EnvConfigureCustomLoggerAndProfiler(ort_env_.get(), - &WinmlOrtLoggingCallback, &WinmlOrtProfileEventCallback, nullptr, - OrtLoggingLevel::ORT_LOGGING_LEVEL_VERBOSE, "Default", &ort_env), - ort_api); + THROW_IF_NOT_OK_MSG( + winml_adapter_api->EnvConfigureCustomLoggerAndProfiler( + ort_env_.get(), + &WinmlOrtLoggingCallback, + &WinmlOrtProfileEventCallback, + nullptr, + OrtLoggingLevel::ORT_LOGGING_LEVEL_VERBOSE, + "Default", + &ort_env + ), + ort_api + ); THROW_IF_NOT_OK_MSG(winml_adapter_api->OverrideSchema(), ort_api); diff --git a/winml/lib/Api.Ort/OnnxruntimeEnvironment.h b/winml/lib/Api.Ort/OnnxruntimeEnvironment.h index a1b965773777f..be6591b06484e 100644 --- a/winml/lib/Api.Ort/OnnxruntimeEnvironment.h +++ b/winml/lib/Api.Ort/OnnxruntimeEnvironment.h @@ -28,4 +28,4 @@ const WinmlAdapterApi* GetVersionedWinmlAdapterApi(); } // namespace _winml -#pragma warning(pop) \ No newline at end of file +#pragma warning(pop) diff --git a/winml/lib/Api.Ort/OnnxruntimeErrors.h b/winml/lib/Api.Ort/OnnxruntimeErrors.h index 8af3e23506924..0cbce1f529b06 100644 --- a/winml/lib/Api.Ort/OnnxruntimeErrors.h +++ b/winml/lib/Api.Ort/OnnxruntimeErrors.h @@ -46,7 +46,7 @@ inline HRESULT OrtErrorCodeToHRESULT(OrtErrorCode status) noexcept { auto error_message = ort_api->GetErrorMessage(_status); \ HRESULT hresult = OrtErrorCodeToHRESULT(error_code); \ telemetry_helper.LogRuntimeError(hresult, std::string(error_message), __FILE__, __FUNCTION__, __LINE__); \ - auto message = _winml::Strings::HStringFromUTF8(error_message); \ + auto message = _winml::Strings::HStringFromUTF8(error_message); \ RoOriginateError(hresult, reinterpret_cast(winrt::get_abi(message))); \ return hresult; \ } \ @@ -60,7 +60,7 @@ inline HRESULT OrtErrorCodeToHRESULT(OrtErrorCode status) noexcept { auto error_message = ort_api->GetErrorMessage(_status); \ HRESULT hresult = OrtErrorCodeToHRESULT(error_code); \ telemetry_helper.LogRuntimeError(hresult, std::string(error_message), __FILE__, __FUNCTION__, __LINE__); \ - auto message = _winml::Strings::HStringFromUTF8(error_message); \ + auto message = _winml::Strings::HStringFromUTF8(error_message); \ throw winrt::hresult_error(hresult, message); \ } \ } while (0) diff --git a/winml/lib/Api.Ort/OnnxruntimeModel.cpp b/winml/lib/Api.Ort/OnnxruntimeModel.cpp index 3af0d6e23e963..fb8413a897e75 100644 --- a/winml/lib/Api.Ort/OnnxruntimeModel.cpp +++ b/winml/lib/Api.Ort/OnnxruntimeModel.cpp @@ -20,25 +20,27 @@ struct winml_adapter_api_model_feature_helper { }; HRESULT CreateFeatureDescriptors( - OnnxruntimeEngineFactory* engine_factory, - const winml_adapter_api_model_feature_helper* feature_helpers, - OrtModel* ort_model, - std::vector& descriptors) { + OnnxruntimeEngineFactory* engine_factory, + const winml_adapter_api_model_feature_helper* feature_helpers, + OrtModel* ort_model, + std::vector& descriptors +) { const auto ort_api = engine_factory->UseOrtApi(); size_t count; - RETURN_HR_IF_NOT_OK_MSG(feature_helpers->GetCount(ort_model, &count), - engine_factory->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG(feature_helpers->GetCount(ort_model, &count), engine_factory->UseOrtApi()); for (size_t i = 0; i < count; i++) { OnnxruntimeValueInfoWrapper descriptor; - RETURN_HR_IF_NOT_OK_MSG(feature_helpers->GetName(ort_model, i, &descriptor.name_, &descriptor.name_length_), - engine_factory->UseOrtApi()); - RETURN_HR_IF_NOT_OK_MSG(feature_helpers->GetDescription(ort_model, i, &descriptor.description_, &descriptor.description_length_), - engine_factory->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG( + feature_helpers->GetName(ort_model, i, &descriptor.name_, &descriptor.name_length_), engine_factory->UseOrtApi() + ); + RETURN_HR_IF_NOT_OK_MSG( + feature_helpers->GetDescription(ort_model, i, &descriptor.description_, &descriptor.description_length_), + engine_factory->UseOrtApi() + ); OrtTypeInfo* type_info; - RETURN_HR_IF_NOT_OK_MSG(feature_helpers->GetTypeInfo(ort_model, i, &type_info), - engine_factory->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG(feature_helpers->GetTypeInfo(ort_model, i, &type_info), engine_factory->UseOrtApi()); descriptor.type_info_ = UniqueOrtTypeInfo(type_info, ort_api->ReleaseTypeInfo); @@ -54,29 +56,32 @@ HRESULT ModelInfo::RuntimeClassInitialize(_In_ OnnxruntimeEngineFactory* engine_ // Get Metadata size_t count; - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->ModelGetMetadataCount(ort_model, &count), - engine_factory->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->ModelGetMetadataCount(ort_model, &count), engine_factory->UseOrtApi()); const char* metadata_key; size_t metadata_key_len; const char* metadata_value; size_t metadata_value_len; for (size_t i = 0; i < count; i++) { - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->ModelGetMetadata(ort_model, i, &metadata_key, &metadata_key_len, &metadata_value, &metadata_value_len), - engine_factory->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->ModelGetMetadata( + ort_model, i, &metadata_key, &metadata_key_len, &metadata_value, &metadata_value_len + ), + engine_factory->UseOrtApi() + ); model_metadata_.insert_or_assign( - std::string(metadata_key, metadata_key_len), - std::string(metadata_value, metadata_value_len)); + std::string(metadata_key, metadata_key_len), std::string(metadata_value, metadata_value_len) + ); } _winml::OnnxruntimeDescriptorConverter converter(engine_factory, model_metadata_); static const winml_adapter_api_model_feature_helper input_helpers = { - winml_adapter_api->ModelGetInputCount, - winml_adapter_api->ModelGetInputName, - winml_adapter_api->ModelGetInputDescription, - winml_adapter_api->ModelGetInputTypeInfo}; + winml_adapter_api->ModelGetInputCount, + winml_adapter_api->ModelGetInputName, + winml_adapter_api->ModelGetInputDescription, + winml_adapter_api->ModelGetInputTypeInfo}; // Create inputs std::vector inputs; @@ -85,10 +90,10 @@ HRESULT ModelInfo::RuntimeClassInitialize(_In_ OnnxruntimeEngineFactory* engine_ // Create outputs static const winml_adapter_api_model_feature_helper output_helpers = { - winml_adapter_api->ModelGetOutputCount, - winml_adapter_api->ModelGetOutputName, - winml_adapter_api->ModelGetOutputDescription, - winml_adapter_api->ModelGetOutputTypeInfo}; + winml_adapter_api->ModelGetOutputCount, + winml_adapter_api->ModelGetOutputName, + winml_adapter_api->ModelGetOutputDescription, + winml_adapter_api->ModelGetOutputTypeInfo}; std::vector outputs; RETURN_IF_FAILED(CreateFeatureDescriptors(engine_factory, &output_helpers, ort_model, outputs)); @@ -97,24 +102,19 @@ HRESULT ModelInfo::RuntimeClassInitialize(_In_ OnnxruntimeEngineFactory* engine_ const char* out; size_t len; - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->ModelGetAuthor(ort_model, &out, &len), - engine_factory->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->ModelGetAuthor(ort_model, &out, &len), engine_factory->UseOrtApi()); author_ = std::string(out, len); - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->ModelGetName(ort_model, &out, &len), - engine_factory->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->ModelGetName(ort_model, &out, &len), engine_factory->UseOrtApi()); name_ = std::string(out, len); - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->ModelGetDomain(ort_model, &out, &len), - engine_factory->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->ModelGetDomain(ort_model, &out, &len), engine_factory->UseOrtApi()); domain_ = std::string(out, len); - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->ModelGetDescription(ort_model, &out, &len), - engine_factory->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->ModelGetDescription(ort_model, &out, &len), engine_factory->UseOrtApi()); description_ = std::string(out, len); - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->ModelGetVersion(ort_model, &version_), - engine_factory->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->ModelGetVersion(ort_model, &version_), engine_factory->UseOrtApi()); return S_OK; } @@ -165,10 +165,9 @@ struct CaseInsensitiveHash { struct CaseInsensitiveEqual { bool operator()(const winrt::hstring& left, const winrt::hstring& right) const { - return left.size() == right.size() && std::equal(left.begin(), left.end(), right.begin(), - [](wchar_t a, wchar_t b) { - return towlower(a) == towlower(b); - }); + return left.size() == right.size() && std::equal(left.begin(), left.end(), right.begin(), [](wchar_t a, wchar_t b) { + return towlower(a) == towlower(b); + }); } }; @@ -184,13 +183,17 @@ STDMETHODIMP ModelInfo::GetModelMetadata(ABI::Windows::Foundation::Collections:: return S_OK; } -STDMETHODIMP ModelInfo::GetInputFeatures(ABI::Windows::Foundation::Collections::IVectorView** features) { +STDMETHODIMP ModelInfo::GetInputFeatures( + ABI::Windows::Foundation::Collections::IVectorView** features +) { *features = nullptr; winrt::copy_to_abi(input_features_.GetView(), *(void**)features); return S_OK; } -STDMETHODIMP ModelInfo::GetOutputFeatures(ABI::Windows::Foundation::Collections::IVectorView** features) { +STDMETHODIMP ModelInfo::GetOutputFeatures( + ABI::Windows::Foundation::Collections::IVectorView** features +) { *features = nullptr; winrt::copy_to_abi(output_features_.GetView(), *(void**)features); return S_OK; @@ -230,8 +233,9 @@ STDMETHODIMP OnnruntimeModel::CloneModel(IModel** copy) { auto winml_adapter_api = engine_factory_->UseWinmlAdapterApi(); OrtModel* ort_model_copy; - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->CloneModel(ort_model_.get(), &ort_model_copy), - engine_factory_->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->CloneModel(ort_model_.get(), &ort_model_copy), engine_factory_->UseOrtApi() + ); auto model = UniqueOrtModel(ort_model_copy, winml_adapter_api->ReleaseModel); RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize(copy, engine_factory_.Get(), std::move(model))); @@ -242,15 +246,15 @@ STDMETHODIMP OnnruntimeModel::CloneModel(IModel** copy) { STDMETHODIMP OnnruntimeModel::SaveModel(_In_ const wchar_t* const file_name, _In_ unsigned size) { auto winml_adapter_api = engine_factory_->UseWinmlAdapterApi(); - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->SaveModel(ort_model_.get(), file_name, size), - engine_factory_->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->SaveModel(ort_model_.get(), file_name, size), engine_factory_->UseOrtApi() + ); return S_OK; } STDMETHODIMP OnnruntimeModel::SetName(const char* name) { auto winml_adapter_api = engine_factory_->UseWinmlAdapterApi(); - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->ModelSetName(ort_model_.get(), name), - engine_factory_->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->ModelSetName(ort_model_.get(), name), engine_factory_->UseOrtApi()); info_->SetName(name); return S_OK; } @@ -260,12 +264,15 @@ STDMETHODIMP OnnruntimeModel::DetachOrtModel(OrtModel** model) { return S_OK; } -HRESULT GetValue(const char* key, const char* const* keys, const char* const* values, - size_t num_values_in_dictionary, const char** value) { +HRESULT GetValue( + const char* key, + const char* const* keys, + const char* const* values, + size_t num_values_in_dictionary, + const char** value +) { auto found_it = - std::find_if(keys, keys + num_values_in_dictionary, [key](auto& key_name) { - return _stricmp(key, key_name) == 0; - }); + std::find_if(keys, keys + num_values_in_dictionary, [key](auto& key_name) { return _stricmp(key, key_name) == 0; }); if (found_it == (keys + num_values_in_dictionary)) { return S_FALSE; } @@ -274,33 +281,45 @@ HRESULT GetValue(const char* key, const char* const* keys, const char* const* va } STDMETHODIMP OnnruntimeModel::AddOperator( - _In_ const char* const op_type, _In_ const char* const op_name, _In_ const char* const op_domain, - _In_ const char* const* op_input_names, _In_ const char* const* actual_input_names, size_t num_inputs, - _In_ const char* const* op_output_names, _In_ const char* const* actual_output_names, size_t num_outputs, - _In_ const char* const* op_attribute_names, _In_ IValue** attribute_values, size_t num_attributes) { + _In_ const char* const op_type, + _In_ const char* const op_name, + _In_ const char* const op_domain, + _In_ const char* const* op_input_names, + _In_ const char* const* actual_input_names, + size_t num_inputs, + _In_ const char* const* op_output_names, + _In_ const char* const* actual_output_names, + size_t num_outputs, + _In_ const char* const* op_attribute_names, + _In_ IValue** attribute_values, + size_t num_attributes +) { auto winml_adapter_api = engine_factory_->UseWinmlAdapterApi(); auto ort_api = engine_factory_->UseOrtApi(); int32_t onnx_opset_version; - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->ModelGetOpsetVersion(ort_model_.get(), op_domain, &onnx_opset_version), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->ModelGetOpsetVersion(ort_model_.get(), op_domain, &onnx_opset_version), ort_api + ); size_t input_count; - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->OperatorGetNumInputs(op_type, onnx_opset_version, op_domain, &input_count), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->OperatorGetNumInputs(op_type, onnx_opset_version, op_domain, &input_count), ort_api + ); size_t output_count; - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->OperatorGetNumOutputs(op_type, onnx_opset_version, op_domain, &output_count), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->OperatorGetNumOutputs(op_type, onnx_opset_version, op_domain, &output_count), ort_api + ); std::vector input_names(input_count); for (size_t i = 0; i < input_count; i++) { const char* name; - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->OperatorGetInputName(op_type, onnx_opset_version, op_domain, i, &name), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->OperatorGetInputName(op_type, onnx_opset_version, op_domain, i, &name), ort_api + ); const char* actual_name; - if (S_OK == GetValue(name, op_input_names, actual_input_names, num_inputs, &actual_name)) - { + if (S_OK == GetValue(name, op_input_names, actual_input_names, num_inputs, &actual_name)) { input_names[i] = actual_name; } } @@ -308,11 +327,12 @@ STDMETHODIMP OnnruntimeModel::AddOperator( std::vector output_names(output_count); for (size_t i = 0; i < output_count; i++) { const char* name; - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->OperatorGetOutputName(op_type, onnx_opset_version, op_domain, i, &name), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->OperatorGetOutputName(op_type, onnx_opset_version, op_domain, i, &name), ort_api + ); const char* actual_name = nullptr; if (S_OK == GetValue(name, op_output_names, actual_output_names, num_outputs, &actual_name)) { - output_names[i] = actual_name; + output_names[i] = actual_name; } } @@ -321,13 +341,32 @@ STDMETHODIMP OnnruntimeModel::AddOperator( attributes.push_back(static_cast(*(attribute_values + i))->UseOrtValue()); } - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->ModelAddOperator( - ort_model_.get(), op_type, op_name, onnx_opset_version, op_domain, input_names.data(), input_count, output_names.data(), output_count, op_attribute_names, attributes.data(), num_attributes), - engine_factory_->UseOrtApi()); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->ModelAddOperator( + ort_model_.get(), + op_type, + op_name, + onnx_opset_version, + op_domain, + input_names.data(), + input_count, + output_names.data(), + output_count, + op_attribute_names, + attributes.data(), + num_attributes + ), + engine_factory_->UseOrtApi() + ); return S_OK; } -STDMETHODIMP OnnruntimeModel::AddModelInput(_In_ const char* const name, _In_ IDescriptorInfoProvider* descriptor_provider, bool is_constant, IValue* constant_value) { +STDMETHODIMP OnnruntimeModel::AddModelInput( + _In_ const char* const name, + _In_ IDescriptorInfoProvider* descriptor_provider, + bool is_constant, + IValue* constant_value +) { auto winml_adapter_api = engine_factory_->UseWinmlAdapterApi(); auto ort_api = engine_factory_->UseOrtApi(); @@ -339,17 +378,21 @@ STDMETHODIMP OnnruntimeModel::AddModelInput(_In_ const char* const name, _In_ ID ort_type_info_provider->GetTypeInfo(&type_info); if (is_constant) { - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->ModelAddConstantInput(ort_model_.get(), name, type_info, static_cast(constant_value)->UseOrtValue()), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->ModelAddConstantInput( + ort_model_.get(), name, type_info, static_cast(constant_value)->UseOrtValue() + ), + ort_api + ); } else { - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->ModelAddInput(ort_model_.get(), name, type_info), - ort_api); + RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->ModelAddInput(ort_model_.get(), name, type_info), ort_api); } return S_OK; } -STDMETHODIMP OnnruntimeModel::AddModelOutput(_In_ const char* const name, _In_ IDescriptorInfoProvider* descriptor_provider) { +STDMETHODIMP +OnnruntimeModel::AddModelOutput(_In_ const char* const name, _In_ IDescriptorInfoProvider* descriptor_provider) { auto winml_adapter_api = engine_factory_->UseWinmlAdapterApi(); auto ort_api = engine_factory_->UseOrtApi(); @@ -364,24 +407,29 @@ STDMETHODIMP OnnruntimeModel::AddModelOutput(_In_ const char* const name, _In_ I return S_OK; } - -STDMETHODIMP OnnruntimeModel::JoinModel(_In_ IModel* other_model, - _In_ const char* const* output_names, - _In_ const char* const* input_names, - size_t num_linkages, - bool promote_unlinked_outputs, - _In_ const char* const join_node_prefix) { +STDMETHODIMP OnnruntimeModel::JoinModel( + _In_ IModel* other_model, + _In_ const char* const* output_names, + _In_ const char* const* input_names, + size_t num_linkages, + bool promote_unlinked_outputs, + _In_ const char* const join_node_prefix +) { auto winml_adapter_api = engine_factory_->UseWinmlAdapterApi(); auto ort_api = engine_factory_->UseOrtApi(); - RETURN_HR_IF_NOT_OK_MSG(winml_adapter_api->JoinModels(ort_model_.get(), - static_cast(other_model)->ort_model_.get(), - output_names, - input_names, - num_linkages, - promote_unlinked_outputs, - join_node_prefix), - ort_api); + RETURN_HR_IF_NOT_OK_MSG( + winml_adapter_api->JoinModels( + ort_model_.get(), + static_cast(other_model)->ort_model_.get(), + output_names, + input_names, + num_linkages, + promote_unlinked_outputs, + join_node_prefix + ), + ort_api + ); // reset the info so that it is recreated with the new information lazily info_ = nullptr; return S_OK; diff --git a/winml/lib/Api.Ort/OnnxruntimeModel.h b/winml/lib/Api.Ort/OnnxruntimeModel.h index d3f65671da868..b393fd642149b 100644 --- a/winml/lib/Api.Ort/OnnxruntimeModel.h +++ b/winml/lib/Api.Ort/OnnxruntimeModel.h @@ -9,16 +9,19 @@ namespace _winml { class OnnxruntimeEngineFactory; +// clang-format off + // The IOrtSessionBuilder offers an abstraction over the creation of // InferenceSession, that enables the creation of the session based on a device (CPU/DML). MIDL_INTERFACE("92679cbf-7a9d-48bb-b97f-ef9fb447ce8e") IOnnxruntimeModel : IUnknown { - virtual HRESULT STDMETHODCALLTYPE DetachOrtModel(OrtModel * *model) PURE; + virtual HRESULT STDMETHODCALLTYPE DetachOrtModel(OrtModel** model) PURE; }; -class ModelInfo : public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags, - IModelInfo> { +// clang-format on + +class ModelInfo + : public Microsoft::WRL::RuntimeClass, IModelInfo> { public: HRESULT RuntimeClassInitialize(_In_ OnnxruntimeEngineFactory* engine, _In_ OrtModel* ort_model); @@ -52,10 +55,9 @@ class ModelInfo : public Microsoft::WRL::RuntimeClass< wfc::IVector output_features_; }; -class OnnruntimeModel : public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags, - IModel, - IOnnxruntimeModel> { +class OnnruntimeModel + : public Microsoft::WRL:: + RuntimeClass, IModel, IOnnxruntimeModel> { public: OnnruntimeModel(); @@ -68,28 +70,42 @@ class OnnruntimeModel : public Microsoft::WRL::RuntimeClass< STDMETHOD(CloneModel) (IModel** copy); STDMETHOD(SaveModel) - (_In_ const wchar_t* const file_name, - _In_ unsigned size); + (_In_ const wchar_t* const file_name, _In_ unsigned size); STDMETHOD(SetName) (const char* name); STDMETHOD(DetachOrtModel) (OrtModel** model); STDMETHOD(AddOperator) - (_In_ const char* const op_type, _In_ const char* const op_name, _In_ const char* const op_domain, - _In_ const char* const* op_input_names, _In_ const char* const* actual_input_names, size_t num_inputs, - _In_ const char* const* op_output_names, _In_ const char* const* actual_output_names, size_t num_outputs, - _In_ const char* const* op_attribute_names, _In_ IValue** constant_value, size_t num_attributes); - + (_In_ const char* const op_type, + _In_ const char* const op_name, + _In_ const char* const op_domain, + _In_ const char* const* op_input_names, + _In_ const char* const* actual_input_names, + size_t num_inputs, + _In_ const char* const* op_output_names, + _In_ const char* const* actual_output_names, + size_t num_outputs, + _In_ const char* const* op_attribute_names, + _In_ IValue** constant_value, + size_t num_attributes); + STDMETHOD(AddModelInput) - (_In_ const char* const name, _In_ IDescriptorInfoProvider* descriptor_provider, bool is_constant, IValue* default_value); + (_In_ const char* const name, + _In_ IDescriptorInfoProvider* descriptor_provider, + bool is_constant, + IValue* default_value); STDMETHOD(AddModelOutput) (_In_ const char* const name, _In_ IDescriptorInfoProvider* descriptor_provider); STDMETHOD(JoinModel) - (_In_ IModel* other_model, _In_ const char* const* output_names, _In_ const char* const* input_names, - size_t num_linkages, bool promote_unlinked_outputs, _In_ const char* const join_node_prefix); + (_In_ IModel* other_model, + _In_ const char* const* output_names, + _In_ const char* const* input_names, + size_t num_linkages, + bool promote_unlinked_outputs, + _In_ const char* const join_node_prefix); private: UniqueOrtModel ort_model_; @@ -100,4 +116,4 @@ class OnnruntimeModel : public Microsoft::WRL::RuntimeClass< std::optional> metadata_cache_; }; -} // namespace _winml \ No newline at end of file +} // namespace _winml diff --git a/winml/lib/Api.Ort/OnnxruntimeSessionBuilder.h b/winml/lib/Api.Ort/OnnxruntimeSessionBuilder.h index f8711663984bd..65debb3155e37 100644 --- a/winml/lib/Api.Ort/OnnxruntimeSessionBuilder.h +++ b/winml/lib/Api.Ort/OnnxruntimeSessionBuilder.h @@ -5,21 +5,25 @@ namespace _winml { +// clang-format off + // The IOrtSessionBuilder offers an abstraction over the creation of // InferenceSession, that enables the creation of the session based on a device (CPU/DML). MIDL_INTERFACE("2746f03a-7e08-4564-b5d0-c670fef116ee") IOrtSessionBuilder : IUnknown { virtual HRESULT STDMETHODCALLTYPE CreateSessionOptions( - OrtSessionOptions * *options) = 0; + OrtSessionOptions** options) = 0; virtual HRESULT STDMETHODCALLTYPE CreateSession( OrtSessionOptions * options, OrtThreadPool* inter_op_thread_pool, OrtThreadPool* intra_op_thread_pool, - OrtSession * *session) = 0; + OrtSession** session) = 0; virtual HRESULT STDMETHODCALLTYPE Initialize( OrtSession * session) = 0; }; -} // namespace _winml \ No newline at end of file +// clang-format on + +} // namespace _winml diff --git a/winml/lib/Api.Ort/UniqueOrtPtr.h b/winml/lib/Api.Ort/UniqueOrtPtr.h index 987af414e8c9c..c9aa56e2854a4 100644 --- a/winml/lib/Api.Ort/UniqueOrtPtr.h +++ b/winml/lib/Api.Ort/UniqueOrtPtr.h @@ -7,6 +7,9 @@ #include "adapter/winml_adapter_c_api.h" +// clang-format off +// preserve visually scannable types + using UniqueOrtModel = std::unique_ptr; using UniqueOrtThreadPool = std::unique_ptr; using UniqueOrtAllocator = std::unique_ptr; @@ -19,3 +22,4 @@ using UniqueOrtTensorTypeAndShapeInfo = std::unique_ptr; using UniqueOrtEnv = std::unique_ptr; +// clang-format on diff --git a/winml/lib/Api.Ort/inc/OnnxruntimeProvider.h b/winml/lib/Api.Ort/inc/OnnxruntimeProvider.h index e22864c1b47da..ccfa57da71f8f 100644 --- a/winml/lib/Api.Ort/inc/OnnxruntimeProvider.h +++ b/winml/lib/Api.Ort/inc/OnnxruntimeProvider.h @@ -5,4 +5,4 @@ #include "iengine.h" -STDAPI CreateOnnxruntimeEngineFactory(_Out_ _winml::IEngineFactory** engine_factory); \ No newline at end of file +STDAPI CreateOnnxruntimeEngineFactory(_Out_ _winml::IEngineFactory** engine_factory); diff --git a/winml/lib/Api/FeatureValues.h b/winml/lib/Api/FeatureValues.h index 78cd511a4c942..a330b244d40fc 100644 --- a/winml/lib/Api/FeatureValues.h +++ b/winml/lib/Api/FeatureValues.h @@ -32,23 +32,17 @@ #define CREATE_TENSOR(type, element_type, element_view_type) \ namespace WINMLP { \ struct type : public _winml::TensorBase< \ - element_type, \ - element_view_type, \ - type, \ - I##type, \ - type##T> { \ - using Base = \ - TensorBase< \ - element_type, \ - element_view_type, \ - type, \ - I##type, \ - type##T< \ - type, \ - ITensorNative, \ - _winml::ILotusValueProviderPrivate>>; \ + element_type, \ + element_view_type, \ + type, \ + I##type, \ + type##T> { \ + using Base = TensorBase< \ + element_type, \ + element_view_type, \ + type, \ + I##type, \ + type##T>; \ \ type() = default; \ \ @@ -59,7 +53,7 @@ type(std::vector const& shape, ID3D12Resource* pResource) : Base(shape, pResource){}; \ }; \ } \ - namespace WINML::factory_implementation { \ + namespace WINML::factory_implementation { \ struct type : type##T { \ STDMETHOD(CreateFromD3D12Resource) \ (ID3D12Resource * value, __int64* shape, int shapeSize, IUnknown** result) { \ @@ -86,14 +80,14 @@ CREATE_TENSOR(TensorInt64Bit, int64_t, int64_t) CREATE_TENSOR(TensorFloat16Bit, _winml::Half, float) #pragma warning(push) -#pragma warning(disable : 4702) // Unreachable code (one of TensorBase's constructor unconditionally throws for +#pragma warning(disable : 4702) // Unreachable code (one of TensorBase's constructor unconditionally throws for \ // std::string because it's not supported with D3D12 resources) CREATE_TENSOR(TensorString, std::string, winrt::hstring) #pragma warning(pop) // CREATE_MAP is used by map types to implement common functionality #define CREATE_MAP(type, key_type, value_type) \ - namespace WINMLP { \ + namespace WINMLP { \ struct type : public _winml::MapBase { \ type(wfc::IMap const& data) : MapBase(data){}; \ }; \ @@ -110,7 +104,7 @@ CREATE_MAP(MapStringToString, hstring, hstring) // CREATE_SEQUENCE is used by sequence types to implement common functionality #define CREATE_SEQUENCE(type, element_type, raw_type) \ - namespace WINMLP { \ + namespace WINMLP { \ struct type : public _winml::SequenceBase { \ type(wfc::IIterable const& data) : SequenceBase(data){}; \ }; \ @@ -135,15 +129,14 @@ CREATE_SEQUENCE(SequenceTensorInt64Bit, winml::TensorInt64Bit, int64_t) CREATE_SEQUENCE(SequenceTensorFloat16Bit, winml::TensorFloat16Bit, _winml::Half) CREATE_SEQUENCE(SequenceTensorString, winml::TensorString, std::string) - namespace _winml { template inline winml::ILearningModelFeatureValue CreateTensorValueFromInspectable( - _winml::BindingType bindingType, - const wf::IInspectable& inspectable, - const winml::ITensorFeatureDescriptor& descriptor) { - + _winml::BindingType bindingType, + const wf::IInspectable& inspectable, + const winml::ITensorFeatureDescriptor& descriptor +) { if (descriptor.TensorKind() == _winml::TensorKindFrom::Type) { if (auto vector = inspectable.try_as>()) { return TValueType::CreateFromIterable(descriptor.Shape(), vector); @@ -161,10 +154,10 @@ inline winml::ILearningModelFeatureValue CreateTensorValueFromInspectable( template <> inline winml::ILearningModelFeatureValue CreateTensorValueFromInspectable( - _winml::BindingType bindingType, - const wf::IInspectable& inspectable, - const winml::ITensorFeatureDescriptor& descriptor) { - + _winml::BindingType bindingType, + const wf::IInspectable& inspectable, + const winml::ITensorFeatureDescriptor& descriptor +) { if (descriptor.TensorKind() == winml::TensorKind::Int8) { if (auto vector = inspectable.try_as>()) { return winmlp::TensorInt8Bit::CreateFromIterable(descriptor.Shape(), vector); @@ -182,10 +175,10 @@ inline winml::ILearningModelFeatureValue CreateTensorValueFromInspectable inline winml::ILearningModelFeatureValue CreateTensorValueFromInspectable( - _winml::BindingType bindingType, - const wf::IInspectable& inspectable, - const winml::ITensorFeatureDescriptor& descriptor) { - + _winml::BindingType bindingType, + const wf::IInspectable& inspectable, + const winml::ITensorFeatureDescriptor& descriptor +) { if (descriptor.TensorKind() == winml::TensorKind::Float16) { if (auto vector = inspectable.try_as>()) { return winmlp::TensorFloat16Bit::CreateFromIterable(descriptor.Shape(), vector); @@ -202,10 +195,10 @@ inline winml::ILearningModelFeatureValue CreateTensorValueFromInspectable()) { return featureValue; @@ -280,7 +273,7 @@ inline winml::ILearningModelFeatureValue CreateFeatureValueFromInspectable( return winmlp::MapInt64BitToString::Create(map); } } - + if (descriptor.Kind() == winml::LearningModelFeatureKind::Sequence) { // SequenceFeatureValues Types are implicitly inferred from the iinspectable object if (auto sequence = inspectable.try_as>>()) { @@ -291,7 +284,7 @@ inline winml::ILearningModelFeatureValue CreateFeatureValueFromInspectable( } if (auto sequence = inspectable.try_as>()) { return winmlp::SequenceTensorFloat::Create(sequence); - } + } if (auto sequence = inspectable.try_as>()) { return winmlp::SequenceTensorBoolean::Create(sequence); } @@ -339,7 +332,7 @@ inline winml::ILearningModelFeatureValue CreateFeatureValueFromInspectable( } if (auto sequence = inspectable.try_as>()) { return winmlp::SequenceTensorFloat::Create(sequence); - } + } if (auto sequence = inspectable.try_as>()) { return winmlp::SequenceTensorBoolean::Create(sequence); } @@ -377,8 +370,7 @@ inline winml::ILearningModelFeatureValue CreateFeatureValueFromInspectable( return winmlp::SequenceTensorString::Create(sequence); } } - } - else if (descriptor.Kind() == winml::LearningModelFeatureKind::Tensor) { + } else if (descriptor.Kind() == winml::LearningModelFeatureKind::Tensor) { auto tensorDescriptor = descriptor.as(); // Vector of IBuffer Input should be copied into the appropriate Tensor @@ -424,26 +416,25 @@ inline winml::ILearningModelFeatureValue CreateFeatureValueFromInspectable( } } - - using TensorCreator = winml::ILearningModelFeatureValue (*)(BindingType, const wf::IInspectable& inspectable, const winml::ITensorFeatureDescriptor& descriptor); - constexpr std::array creators = - { - // Vector and VectorViews of float16 and int8 collide with float and uint8 respectively. - // They are omitted because of this ambiguity and are not constructible via raw winrt collections. - CreateTensorValueFromInspectable, - CreateTensorValueFromInspectable, - CreateTensorValueFromInspectable, - CreateTensorValueFromInspectable, - CreateTensorValueFromInspectable, - CreateTensorValueFromInspectable, - CreateTensorValueFromInspectable, - CreateTensorValueFromInspectable, - CreateTensorValueFromInspectable, - CreateTensorValueFromInspectable, - CreateTensorValueFromInspectable, - CreateTensorValueFromInspectable, - CreateTensorValueFromInspectable - }; + using TensorCreator = winml::ILearningModelFeatureValue (*)( + BindingType, const wf::IInspectable& inspectable, const winml::ITensorFeatureDescriptor& descriptor + ); + constexpr std::array creators = { + // Vector and VectorViews of float16 and int8 collide with float and uint8 respectively. + // They are omitted because of this ambiguity and are not constructible via raw winrt collections. + CreateTensorValueFromInspectable, + CreateTensorValueFromInspectable, + CreateTensorValueFromInspectable, + CreateTensorValueFromInspectable, + CreateTensorValueFromInspectable, + CreateTensorValueFromInspectable, + CreateTensorValueFromInspectable, + CreateTensorValueFromInspectable, + CreateTensorValueFromInspectable, + CreateTensorValueFromInspectable, + CreateTensorValueFromInspectable, + CreateTensorValueFromInspectable, + CreateTensorValueFromInspectable}; for (const auto& tensorCreator : creators) { if (auto createdTensor = tensorCreator(bindingType, inspectable, tensorDescriptor)) { @@ -451,7 +442,7 @@ inline winml::ILearningModelFeatureValue CreateFeatureValueFromInspectable( } } } - + return nullptr; } diff --git a/winml/lib/Api/ImageFeatureDescriptor.cpp b/winml/lib/Api/ImageFeatureDescriptor.cpp index abf7fded3445c..b81c8b9f0629d 100644 --- a/winml/lib/Api/ImageFeatureDescriptor.cpp +++ b/winml/lib/Api/ImageFeatureDescriptor.cpp @@ -9,123 +9,88 @@ namespace WINMLP { ImageFeatureDescriptor::ImageFeatureDescriptor( - const char* name, - const char* description, - winml::TensorKind tensor_kind, - const std::vector& shape, - bool is_required, - wgi::BitmapPixelFormat pixel_format, - wgi::BitmapAlphaMode alpha_mode, - uint32_t width, - uint32_t height, - winml::LearningModelPixelRange pixel_range, - ImageColorSpaceGamma color_space_gamma) : name_(_winml::Strings::HStringFromUTF8(name)), - description_(_winml::Strings::HStringFromUTF8(description)), - tensor_kind_(tensor_kind), - shape_(shape), - is_required_(is_required), - pixel_format_(pixel_format), - alpha_mode_(alpha_mode), - width_(width), - height_(height), - pixel_range_(pixel_range), - color_space_gamma_(color_space_gamma) { -} - -wgi::BitmapPixelFormat -ImageFeatureDescriptor::BitmapPixelFormat() try { - return pixel_format_; -} + const char* name, + const char* description, + winml::TensorKind tensor_kind, + const std::vector& shape, + bool is_required, + wgi::BitmapPixelFormat pixel_format, + wgi::BitmapAlphaMode alpha_mode, + uint32_t width, + uint32_t height, + winml::LearningModelPixelRange pixel_range, + ImageColorSpaceGamma color_space_gamma +) + : name_(_winml::Strings::HStringFromUTF8(name)), + description_(_winml::Strings::HStringFromUTF8(description)), + tensor_kind_(tensor_kind), + shape_(shape), + is_required_(is_required), + pixel_format_(pixel_format), + alpha_mode_(alpha_mode), + width_(width), + height_(height), + pixel_range_(pixel_range), + color_space_gamma_(color_space_gamma) { +} + +wgi::BitmapPixelFormat ImageFeatureDescriptor::BitmapPixelFormat() try { return pixel_format_; } WINML_CATCH_ALL -wgi::BitmapAlphaMode -ImageFeatureDescriptor::BitmapAlphaMode() try { - return alpha_mode_; -} +wgi::BitmapAlphaMode ImageFeatureDescriptor::BitmapAlphaMode() try { return alpha_mode_; } WINML_CATCH_ALL -uint32_t -ImageFeatureDescriptor::Width() try { - return width_; -} +uint32_t ImageFeatureDescriptor::Width() try { return width_; } WINML_CATCH_ALL -uint32_t -ImageFeatureDescriptor::Height() try { - return height_; -} +uint32_t ImageFeatureDescriptor::Height() try { return height_; } WINML_CATCH_ALL -hstring -ImageFeatureDescriptor::Name() try { - return name_; -} +hstring ImageFeatureDescriptor::Name() try { return name_; } WINML_CATCH_ALL -hstring -ImageFeatureDescriptor::Description() try { - return description_; -} +hstring ImageFeatureDescriptor::Description() try { return description_; } WINML_CATCH_ALL -winml::LearningModelFeatureKind -ImageFeatureDescriptor::Kind() try { - return LearningModelFeatureKind::Image; -} +winml::LearningModelFeatureKind ImageFeatureDescriptor::Kind() try { return LearningModelFeatureKind::Image; } WINML_CATCH_ALL -bool ImageFeatureDescriptor::IsRequired() try { - return is_required_; -} +bool ImageFeatureDescriptor::IsRequired() try { return is_required_; } WINML_CATCH_ALL -winml::TensorKind -ImageFeatureDescriptor::TensorKind() { +winml::TensorKind ImageFeatureDescriptor::TensorKind() { return tensor_kind_; } -wfc::IVectorView -ImageFeatureDescriptor::Shape() { - return winrt::single_threaded_vector( - std::vector( - std::begin(shape_), - std::end(shape_))) - .GetView(); +wfc::IVectorView ImageFeatureDescriptor::Shape() { + return winrt::single_threaded_vector(std::vector(std::begin(shape_), std::end(shape_))).GetView(); } HRESULT -ImageFeatureDescriptor::GetName( - const wchar_t** name, - uint32_t* cchName) { +ImageFeatureDescriptor::GetName(const wchar_t** name, uint32_t* cchName) { *name = name_.data(); *cchName = static_cast(name_.size()); return S_OK; } HRESULT -ImageFeatureDescriptor::GetDescription( - const wchar_t** description, - uint32_t* cchDescription) { +ImageFeatureDescriptor::GetDescription(const wchar_t** description, uint32_t* cchDescription) { *description = description_.data(); *cchDescription = static_cast(description_.size()); return S_OK; } -winml::LearningModelPixelRange -ImageFeatureDescriptor::PixelRange() { +winml::LearningModelPixelRange ImageFeatureDescriptor::PixelRange() { return pixel_range_; } -ImageColorSpaceGamma -ImageFeatureDescriptor::GetColorSpaceGamma() { +ImageColorSpaceGamma ImageFeatureDescriptor::GetColorSpaceGamma() { return color_space_gamma_; } HRESULT -ImageFeatureDescriptor::GetDescriptorInfo( - _winml::IEngineFactory* engine_factory, - _winml::IDescriptorInfo** info) { - // TODO: Need to add denotations here +ImageFeatureDescriptor::GetDescriptorInfo(_winml::IEngineFactory* engine_factory, _winml::IDescriptorInfo** info) { + // TODO: Need to add denotations here engine_factory->CreateTensorDescriptorInfo(tensor_kind_, shape_.data(), shape_.size(), info); return S_OK; } diff --git a/winml/lib/Api/ImageFeatureDescriptor.h b/winml/lib/Api/ImageFeatureDescriptor.h index 744702149cbd1..92d7ee3450149 100644 --- a/winml/lib/Api/ImageFeatureDescriptor.h +++ b/winml/lib/Api/ImageFeatureDescriptor.h @@ -14,73 +14,56 @@ enum class ImageColorSpaceGamma { }; struct ImageFeatureDescriptor : ImageFeatureDescriptorT< - ImageFeatureDescriptor, - ILearningModelFeatureDescriptorNative, - _winml::IDescriptorInfoProvider> { + ImageFeatureDescriptor, + ILearningModelFeatureDescriptorNative, + _winml::IDescriptorInfoProvider> { ImageFeatureDescriptor() = delete; ImageFeatureDescriptor( - const char* name, - const char* description, - winml::TensorKind tensor_kind, - const std::vector& shape, - bool is_required, - wgi::BitmapPixelFormat pixelformat, - wgi::BitmapAlphaMode alphamode, - uint32_t width, - uint32_t height, - winml::LearningModelPixelRange pixelRange, - ImageColorSpaceGamma colorSpaceGamma); + const char* name, + const char* description, + winml::TensorKind tensor_kind, + const std::vector& shape, + bool is_required, + wgi::BitmapPixelFormat pixelformat, + wgi::BitmapAlphaMode alphamode, + uint32_t width, + uint32_t height, + winml::LearningModelPixelRange pixelRange, + ImageColorSpaceGamma colorSpaceGamma + ); - wgi::BitmapPixelFormat - BitmapPixelFormat(); + wgi::BitmapPixelFormat BitmapPixelFormat(); - wgi::BitmapAlphaMode - BitmapAlphaMode(); + wgi::BitmapAlphaMode BitmapAlphaMode(); - uint32_t - Width(); + uint32_t Width(); - uint32_t - Height(); + uint32_t Height(); - hstring - Name(); + hstring Name(); - hstring - Description(); + hstring Description(); - winml::LearningModelFeatureKind - Kind(); + winml::LearningModelFeatureKind Kind(); - bool - IsRequired(); + bool IsRequired(); - winml::TensorKind - TensorKind(); + winml::TensorKind TensorKind(); - wfc::IVectorView - Shape(); + wfc::IVectorView Shape(); - winml::LearningModelPixelRange - PixelRange(); + winml::LearningModelPixelRange PixelRange(); - ImageColorSpaceGamma - GetColorSpaceGamma(); + ImageColorSpaceGamma GetColorSpaceGamma(); STDMETHOD(GetName) - ( - const wchar_t** name, - uint32_t* cchName) override; + (const wchar_t** name, uint32_t* cchName) override; STDMETHOD(GetDescription) - ( - const wchar_t** description, - uint32_t* cchDescription) override; + (const wchar_t** description, uint32_t* cchDescription) override; STDMETHOD(GetDescriptorInfo) - ( - _winml::IEngineFactory* engine_factory, - _winml::IDescriptorInfo** info) override; + (_winml::IEngineFactory* engine_factory, _winml::IDescriptorInfo** info) override; private: winrt::hstring name_; @@ -96,4 +79,4 @@ struct ImageFeatureDescriptor : ImageFeatureDescriptorT< ImageColorSpaceGamma color_space_gamma_; }; -} // namespace WINMLP \ No newline at end of file +} // namespace WINMLP diff --git a/winml/lib/Api/ImageFeatureValue.cpp b/winml/lib/Api/ImageFeatureValue.cpp index 1b8be103c0e5a..8628c578e5004 100644 --- a/winml/lib/Api/ImageFeatureValue.cpp +++ b/winml/lib/Api/ImageFeatureValue.cpp @@ -28,10 +28,8 @@ struct ImageFeatureValue::ImageResourceMetadata { }; winml::ImageFeatureValue ImageFeatureValue::Create( - uint32_t batchSize, - wgi::BitmapPixelFormat format, - uint32_t width, - uint32_t height) { + uint32_t batchSize, wgi::BitmapPixelFormat format, uint32_t width, uint32_t height +) { std::vector videoFrames = {}; for (uint32_t i = 0; i < batchSize; ++i) { wgi::SoftwareBitmap bitmap(format, width, height); @@ -87,11 +85,11 @@ static std::optional GetBitmapPixelFormatFromMetadata(co auto pixelFormatValue = pixelFormatInspectable.as(); auto pixelFormat = static_cast(pixelFormatValue.GetInt32()); WINML_THROW_HR_IF_FALSE_MSG( - WINML_ERR_INVALID_BINDING, - pixelFormat == wgi::BitmapPixelFormat::Rgba8 || - pixelFormat == wgi::BitmapPixelFormat::Bgra8 || - pixelFormat == wgi::BitmapPixelFormat::Gray8, - "BitmapPixelFormat must be either Rgba8, Bgra8, or Gray8"); + WINML_ERR_INVALID_BINDING, + pixelFormat == wgi::BitmapPixelFormat::Rgba8 || pixelFormat == wgi::BitmapPixelFormat::Bgra8 || + pixelFormat == wgi::BitmapPixelFormat::Gray8, + "BitmapPixelFormat must be either Rgba8, Bgra8, or Gray8" + ); return pixelFormat; } @@ -105,16 +103,18 @@ static std::optional GetBoundsFromMetadata(const wfc::IProper if (auto boundsInspectable = properties.Lookup(L"BitmapBounds")) { auto boundsPropertyValue = boundsInspectable.as(); WINML_THROW_HR_IF_FALSE_MSG( - WINML_ERR_INVALID_BINDING, - boundsPropertyValue.Type() == wf::PropertyType::UInt32Array, - "BitmapBounds must reference a property value with type UInt32Array with 4 elements."); + WINML_ERR_INVALID_BINDING, + boundsPropertyValue.Type() == wf::PropertyType::UInt32Array, + "BitmapBounds must reference a property value with type UInt32Array with 4 elements." + ); com_array bounds; boundsPropertyValue.GetUInt32Array(bounds); WINML_THROW_HR_IF_FALSE_MSG( - WINML_ERR_INVALID_BINDING, - bounds.size() == 4, - "BitmapBounds must reference a property value with type UInt32Array with 4 elements."); + WINML_ERR_INVALID_BINDING, + bounds.size() == 4, + "BitmapBounds must reference a property value with type UInt32Array with 4 elements." + ); return wgi::BitmapBounds{bounds[0], bounds[1], bounds[2], bounds[3]}; } @@ -123,17 +123,19 @@ static std::optional GetBoundsFromMetadata(const wfc::IProper return {}; } -static std::optional GetBitmapPixelRangeFromMetadata(const wfc::IPropertySet& properties) { +static std::optional GetBitmapPixelRangeFromMetadata(const wfc::IPropertySet& properties +) { if (properties != nullptr && properties.HasKey(L"PixelRange")) { if (auto pixelRangeInspectable = properties.Lookup(L"PixelRange")) { auto pixelRangeValue = pixelRangeInspectable.as(); auto pixelRange = static_cast(pixelRangeValue.GetInt32()); WINML_THROW_HR_IF_FALSE_MSG( - WINML_ERR_INVALID_BINDING, - pixelRange == winml::LearningModelPixelRange::ZeroTo255 || - pixelRange == winml::LearningModelPixelRange::ZeroToOne || - pixelRange == winml::LearningModelPixelRange::MinusOneToOne, - "LearningModelPixelRange must be either ZeroTo255, ZeroToOne, or MinusOneToOne"); + WINML_ERR_INVALID_BINDING, + pixelRange == winml::LearningModelPixelRange::ZeroTo255 || + pixelRange == winml::LearningModelPixelRange::ZeroToOne || + pixelRange == winml::LearningModelPixelRange::MinusOneToOne, + "LearningModelPixelRange must be either ZeroTo255, ZeroToOne, or MinusOneToOne" + ); return pixelRange; } @@ -142,10 +144,7 @@ static std::optional GetBitmapPixelRangeFromMeta return {}; } -wgi::BitmapBounds ImageFeatureValue::CenterAndCropBounds( - uint32_t idx, - uint32_t desiredWidth, - uint32_t desiredHeight) { +wgi::BitmapBounds ImageFeatureValue::CenterAndCropBounds(uint32_t idx, uint32_t desiredWidth, uint32_t desiredHeight) { wgi::BitmapBounds bounds = {}; float RequiredAspectRatio = static_cast(desiredWidth) / static_cast(desiredHeight); @@ -174,7 +173,9 @@ static _winml::ImageTensorDataType GetTensorDataTypeFromTensorKind(winml::Tensor case winml::TensorKind::Float16: return _winml::ImageTensorDataType::kImageTensorDataTypeFloat16; default: - WINML_THROW_HR_IF_FALSE_MSG(WINML_ERR_INVALID_BINDING, false, "Model image inputs must have tensor type of Float or Float16."); + WINML_THROW_HR_IF_FALSE_MSG( + WINML_ERR_INVALID_BINDING, false, "Model image inputs must have tensor type of Float or Float16." + ); } FAIL_FAST_HR(E_INVALIDARG); @@ -187,16 +188,22 @@ static unsigned GetSizeFromTensorDataType(_winml::ImageTensorDataType type) { case _winml::ImageTensorDataType::kImageTensorDataTypeFloat16: return sizeof(uint16_t); default: - WINML_THROW_HR_IF_FALSE_MSG(WINML_ERR_INVALID_BINDING, false, "Model image inputs must have tensor type of Float or Float16."); + WINML_THROW_HR_IF_FALSE_MSG( + WINML_ERR_INVALID_BINDING, false, "Model image inputs must have tensor type of Float or Float16." + ); } FAIL_FAST_HR(E_INVALIDARG); } -static _winml::ImageTensorDescription CreateImageTensorDescriptor(winml::TensorKind tensorKind, - wgi::BitmapPixelFormat pixelFormat, - winml::LearningModelPixelRange pixelRange, - uint32_t batchSize, uint32_t width, uint32_t height) { +static _winml::ImageTensorDescription CreateImageTensorDescriptor( + winml::TensorKind tensorKind, + wgi::BitmapPixelFormat pixelFormat, + winml::LearningModelPixelRange pixelRange, + uint32_t batchSize, + uint32_t width, + uint32_t height +) { _winml::ImageTensorDescription tensorDescription = {}; tensorDescription.dataType = GetTensorDataTypeFromTensorKind(tensorKind); tensorDescription.sizes[0] = batchSize; @@ -214,12 +221,10 @@ static _winml::ImageTensorDescription CreateImageTensorDescriptor(winml::TensorK THROW_HR(E_NOTIMPL); } - if (pixelRange != winml::LearningModelPixelRange::ZeroTo255 && - pixelRange != winml::LearningModelPixelRange::ZeroToOne && - pixelRange != winml::LearningModelPixelRange::MinusOneToOne) { + if (pixelRange != winml::LearningModelPixelRange::ZeroTo255 && pixelRange != winml::LearningModelPixelRange::ZeroToOne && pixelRange != winml::LearningModelPixelRange::MinusOneToOne) { THROW_HR(E_NOTIMPL); } - + tensorDescription.pixelRange = pixelRange; tensorDescription.sizes[2] = height; tensorDescription.sizes[3] = width; @@ -228,11 +233,12 @@ static _winml::ImageTensorDescription CreateImageTensorDescriptor(winml::TensorK } static void CPUTensorize( - wm::IVideoFrame videoFrame, - wgi::BitmapBounds bounds, - _winml::ImageTensorDescription tensorDescriptor, - com_ptr spSession, - void* pResource) { + wm::IVideoFrame videoFrame, + wgi::BitmapBounds bounds, + _winml::ImageTensorDescription tensorDescriptor, + com_ptr spSession, + void* pResource +) { auto spDevice = spSession->Device().as(); _winml::ConverterResourceDescription descriptor = {}; @@ -245,10 +251,8 @@ static void CPUTensorize( //apply tensorization pooledConverter->Get()->Tensorizer->VideoFrameToSoftwareTensor( - videoFrame, - bounds, - tensorDescriptor, - reinterpret_cast(pResource)); + videoFrame, bounds, tensorDescriptor, reinterpret_cast(pResource) + ); // Software tensorization doesnt need to hold onto any resources beyond its scope, so we can // return the converter to the pool on tensorization completion. @@ -256,12 +260,13 @@ static void CPUTensorize( } static void CPUTensorize( - wfc::IVector videoFrames, - std::vector bounds, - _winml::ImageTensorDescription tensorDescriptor, - com_ptr spSession, - BYTE* resource, - unsigned int singleFrameBufferSize) { + wfc::IVector videoFrames, + std::vector bounds, + _winml::ImageTensorDescription tensorDescriptor, + com_ptr spSession, + BYTE* resource, + unsigned int singleFrameBufferSize +) { // Tensorize video frames one by one without extra copy. for (uint32_t batchIdx = 0; batchIdx < videoFrames.Size(); ++batchIdx) { CPUTensorize(videoFrames.GetAt(batchIdx), bounds[batchIdx], tensorDescriptor, spSession, resource); @@ -270,12 +275,13 @@ static void CPUTensorize( } static void GPUTensorize( - wfc::IVector videoFrames, - std::vector bounds, - _winml::ImageTensorDescription tensorDescriptor, - com_ptr spSession, - ID3D12Resource* d3dResource, - _winml::BindingContext& context) { + wfc::IVector videoFrames, + std::vector bounds, + _winml::ImageTensorDescription tensorDescriptor, + com_ptr spSession, + ID3D12Resource* d3dResource, + _winml::BindingContext& context +) { auto spDevice = spSession->Device().as(); _winml::ConverterResourceDescription descriptor = {}; @@ -291,12 +297,8 @@ static void GPUTensorize( // Apply tensorization auto session = spSession.as(); pooledConverter->Get()->Tensorizer->VideoFrameToDX12Tensor( - batchIdx, - session, - videoFrames.GetAt(batchIdx), - bounds[batchIdx], - tensorDescriptor, - d3dResource); + batchIdx, session, videoFrames.GetAt(batchIdx), bounds[batchIdx], tensorDescriptor, d3dResource + ); // Tensorization to a GPU tensor will run asynchronously and associated resources // need to be kept alive until the gpu resources have been used in the queue. @@ -311,7 +313,9 @@ static void GPUTensorize( } } -std::optional ImageFeatureValue::GetInputMetadata(const _winml::BindingContext& context) { +std::optional ImageFeatureValue::GetInputMetadata( + const _winml::BindingContext& context +) { uint32_t descriptorWidth; uint32_t descriptorHeight; @@ -327,11 +331,12 @@ std::optional ImageFeatureValue::GetIn // The the widths and heights of input data must be the same. Or the // tensorDescriptor cannot describ the shape of the inputs. if (spImageDescriptor->Width() == MAXUINT32 && - !(std::adjacent_find(m_widths.begin(), m_widths.end(), std::not_equal_to()) == m_widths.end())) { + !(std::adjacent_find(m_widths.begin(), m_widths.end(), std::not_equal_to()) == m_widths.end())) { THROW_HR(E_INVALIDARG); } if (spImageDescriptor->Height() == MAXUINT32 && - !(std::adjacent_find(m_heights.begin(), m_heights.end(), std::not_equal_to()) == m_heights.end())) { + !(std::adjacent_find(m_heights.begin(), m_heights.end(), std::not_equal_to()) == m_heights.end() + )) { THROW_HR(E_INVALIDARG); } descriptorWidth = (spImageDescriptor->Width() == MAXUINT32) ? m_widths[0] : spImageDescriptor->Width(); @@ -349,11 +354,12 @@ std::optional ImageFeatureValue::GetIn return {}; } if (-1 == shape.GetAt(3) && - !(std::adjacent_find(m_widths.begin(), m_widths.end(), std::not_equal_to()) == m_widths.end())) { + !(std::adjacent_find(m_widths.begin(), m_widths.end(), std::not_equal_to()) == m_widths.end())) { THROW_HR(E_INVALIDARG); } if (-1 == shape.GetAt(2) && - !(std::adjacent_find(m_heights.begin(), m_heights.end(), std::not_equal_to()) == m_heights.end())) { + !(std::adjacent_find(m_heights.begin(), m_heights.end(), std::not_equal_to()) == m_heights.end() + )) { THROW_HR(E_INVALIDARG); } descriptorWidth = (-1 == shape.GetAt(3)) ? m_widths[0] : static_cast(shape.GetAt(3)); @@ -417,9 +423,11 @@ std::optional ImageFeatureValue::GetIn } else { THROW_HR(WINML_ERR_INVALID_BINDING); } - + //NCHW layout - auto imageTensorDescriptor = CreateImageTensorDescriptor(tensorKind, pixelFormat.value(), pixelRange.value(), m_batchSize, descriptorWidth, descriptorHeight); + auto imageTensorDescriptor = CreateImageTensorDescriptor( + tensorKind, pixelFormat.value(), pixelRange.value(), m_batchSize, descriptorWidth, descriptorHeight + ); return ImageResourceMetadata{bounds, imageTensorDescriptor}; } @@ -441,11 +449,13 @@ HRESULT ImageFeatureValue::GetValue(_winml::BindingContext& context, _winml::IVa // create the OrtValue winrt::com_ptr<_winml::IValue> value; RETURN_IF_FAILED(engine->CreateTensorValue( - resourceMetadata.TensorDescriptor.sizes, - sizeof(resourceMetadata.TensorDescriptor.sizes) / sizeof(resourceMetadata.TensorDescriptor.sizes[0]), - resourceMetadata.TensorDescriptor.dataType == _winml::ImageTensorDataType::kImageTensorDataTypeFloat32 ? - winml::TensorKind::Float : winml::TensorKind::Float16, - value.put())); + resourceMetadata.TensorDescriptor.sizes, + sizeof(resourceMetadata.TensorDescriptor.sizes) / sizeof(resourceMetadata.TensorDescriptor.sizes[0]), + resourceMetadata.TensorDescriptor.dataType == _winml::ImageTensorDataType::kImageTensorDataTypeFloat32 + ? winml::TensorKind::Float + : winml::TensorKind::Float16, + value.put() + )); // Get the tensor raw data _winml::Resource void_resource; @@ -453,15 +463,29 @@ HRESULT ImageFeatureValue::GetValue(_winml::BindingContext& context, _winml::IVa if (context.type == _winml::BindingType::kInput) { // Only tensorize inputs - auto bufferSize = std::accumulate(std::begin(resourceMetadata.TensorDescriptor.sizes), std::end(resourceMetadata.TensorDescriptor.sizes), static_cast(1), std::multiplies()); + auto bufferSize = std::accumulate( + std::begin(resourceMetadata.TensorDescriptor.sizes), + std::end(resourceMetadata.TensorDescriptor.sizes), + static_cast(1), + std::multiplies() + ); auto bufferByteSize = GetSizeFromTensorDataType(resourceMetadata.TensorDescriptor.dataType) * bufferSize; auto singleFrameBufferSize = bufferByteSize / m_batchSize; if (spDevice->IsCpuDevice()) { auto resource = reinterpret_cast(void_resource.get()); - CPUTensorize(m_videoFrames, resourceMetadata.Bounds, resourceMetadata.TensorDescriptor, spSession, resource, static_cast(singleFrameBufferSize)); + CPUTensorize( + m_videoFrames, + resourceMetadata.Bounds, + resourceMetadata.TensorDescriptor, + spSession, + resource, + static_cast(singleFrameBufferSize) + ); } else { auto resource = reinterpret_cast(void_resource.get()); - GPUTensorize(m_videoFrames, resourceMetadata.Bounds, resourceMetadata.TensorDescriptor, spSession, resource, context); + GPUTensorize( + m_videoFrames, resourceMetadata.Bounds, resourceMetadata.TensorDescriptor, spSession, resource, context + ); } } @@ -500,14 +524,22 @@ HRESULT ImageFeatureValue::UpdateSourceResourceData(_winml::BindingContext& cont auto pooledConverter = _winml::PoolObjectWrapper::Create(spDevice->DetensorizerStore()->Fetch(descriptor)); - auto bufferSize = std::accumulate(std::begin(resourceMetadata.TensorDescriptor.sizes), std::end(resourceMetadata.TensorDescriptor.sizes), static_cast(1), std::multiplies()); - auto bufferByteSize = GetSizeFromTensorDataType(resourceMetadata.TensorDescriptor.dataType) * bufferSize / m_batchSize; + auto bufferSize = std::accumulate( + std::begin(resourceMetadata.TensorDescriptor.sizes), + std::end(resourceMetadata.TensorDescriptor.sizes), + static_cast(1), + std::multiplies() + ); + auto bufferByteSize = + GetSizeFromTensorDataType(resourceMetadata.TensorDescriptor.dataType) * bufferSize / m_batchSize; BYTE* resource = reinterpret_cast(void_resource.get()); for (uint32_t batchIdx = 0; batchIdx < m_batchSize; ++batchIdx) { // Convert Software Tensor to VideoFrame one by one based on the buffer size. auto videoFrame = m_videoFrames.GetAt(batchIdx); - pooledConverter->Get()->Detensorizer->SoftwareTensorToVideoFrame(context.session, resource, resourceMetadata.TensorDescriptor, videoFrame); + pooledConverter->Get()->Detensorizer->SoftwareTensorToVideoFrame( + context.session, resource, resourceMetadata.TensorDescriptor, videoFrame + ); resource += bufferByteSize; } } else { @@ -521,11 +553,8 @@ HRESULT ImageFeatureValue::UpdateSourceResourceData(_winml::BindingContext& cont for (uint32_t batchIdx = 0; batchIdx < m_batchSize; ++batchIdx) { auto videoFrame = m_videoFrames.GetAt(batchIdx); pooledConverter->Get()->Detensorizer->DX12TensorToVideoFrame( - batchIdx, - context.session, - d3dResource, - resourceMetadata.TensorDescriptor, - videoFrame); + batchIdx, context.session, d3dResource, resourceMetadata.TensorDescriptor, videoFrame + ); // Reset the Allocator before return to the Cache. Must Sync this background thread to that completion before we do. spDevice->GetD3DDeviceCache()->SyncD3D12ToCPU(); @@ -544,23 +573,19 @@ HRESULT ImageFeatureValue::AbiRepresentation(wf::IInspectable& abiRepresentation m_videoFrames.as(abiRepresentation); } else { winml::ImageFeatureValue to = nullptr; - RETURN_IF_FAILED(this->QueryInterface( - winrt::guid_of(), - reinterpret_cast(winrt::put_abi(to)))); + RETURN_IF_FAILED( + this->QueryInterface(winrt::guid_of(), reinterpret_cast(winrt::put_abi(to))) + ); to.as(abiRepresentation); } return S_OK; } -winml::LearningModelFeatureKind ImageFeatureValue::Kind() try { - return winml::LearningModelFeatureKind::Image; -} +winml::LearningModelFeatureKind ImageFeatureValue::Kind() try { return winml::LearningModelFeatureKind::Image; } WINML_CATCH_ALL -wm::VideoFrame ImageFeatureValue::VideoFrame() try { - return m_videoFrames.GetAt(0); -} +wm::VideoFrame ImageFeatureValue::VideoFrame() try { return m_videoFrames.GetAt(0); } WINML_CATCH_ALL wfc::IIterable ImageFeatureValue::VideoFrames() try { diff --git a/winml/lib/Api/ImageFeatureValue.h b/winml/lib/Api/ImageFeatureValue.h index e7785283e4e50..83a21c8679cf3 100644 --- a/winml/lib/Api/ImageFeatureValue.h +++ b/winml/lib/Api/ImageFeatureValue.h @@ -24,10 +24,8 @@ struct ImageFeatureValue : ImageFeatureValueT GetInputMetadata(const _winml::BindingContext& context); @@ -53,15 +51,11 @@ struct ImageFeatureValue : ImageFeatureValueT { -}; -} // namespace WINMLP +struct ImageFeatureValue : ImageFeatureValueT {}; +} // namespace WINML::factory_implementation diff --git a/winml/lib/Api/LearningModel.cpp b/winml/lib/Api/LearningModel.cpp index 09ca3dcfdf94e..6d7c8317ce5f9 100644 --- a/winml/lib/Api/LearningModel.cpp +++ b/winml/lib/Api/LearningModel.cpp @@ -19,10 +19,8 @@ namespace WINMLP { // IBuffer implementation to avoid calling into WinTypes.dll to create wss::Buffer. // This will enable model creation on VTL1 without pulling in additional binaries on load. template -class STLVectorBackedBuffer : public winrt::implements< - STLVectorBackedBuffer, - wss::IBuffer, - ::Windows::Storage::Streams::IBufferByteAccess> { +class STLVectorBackedBuffer + : public winrt::implements, wss::IBuffer, ::Windows::Storage::Streams::IBufferByteAccess> { private: std::vector data_; size_t length_ = 0; @@ -44,7 +42,9 @@ class STLVectorBackedBuffer : public winrt::implements< void Length(uint32_t value) try { // Set the use buffer length in bytes - WINML_THROW_HR_IF_TRUE_MSG(E_INVALIDARG, value > Capacity(), "Parameter 'value' cannot be greater than the buffer's capacity."); + WINML_THROW_HR_IF_TRUE_MSG( + E_INVALIDARG, value > Capacity(), "Parameter 'value' cannot be greater than the buffer's capacity." + ); length_ = value; } WINML_CATCH_ALL @@ -58,59 +58,49 @@ class STLVectorBackedBuffer : public winrt::implements< } }; - -LearningModel::LearningModel( - const hstring& path, - const winml::ILearningModelOperatorProvider op_provider) try : operator_provider_(op_provider) { +LearningModel::LearningModel(const hstring& path, const winml::ILearningModelOperatorProvider op_provider) try + : operator_provider_(op_provider) { _winmlt::TelemetryEvent loadModel_event(_winmlt::EventCategory::kModelLoad); WINML_THROW_IF_FAILED(CreateOnnxruntimeEngineFactory(engine_factory_.put())); - wil::unique_handle file_handle{ + wil::unique_handle file_handle { #if WINVER >= _WIN32_WINNT_WIN8 - CreateFile2(path.c_str(), - GENERIC_READ, - FILE_SHARE_READ, - OPEN_EXISTING, - NULL)}; + CreateFile2(path.c_str(), GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, NULL) + }; #else - CreateFileW(path.c_str(), - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_READONLY, - NULL)}; + CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL) + }; #endif - WINML_THROW_HR_IF_TRUE_MSG(__HRESULT_FROM_WIN32(GetLastError()), - file_handle.get() == INVALID_HANDLE_VALUE, - "Model load failed!"); - - auto file_mapping = wil::unique_handle(CreateFileMappingW(file_handle.get(), // current file handle - NULL, // default security - PAGE_READONLY, // read/write permission - 0, // size of mapping object, high - 0, // size of mapping object, low - NULL)); // name of mapping object - - WINML_THROW_HR_IF_TRUE_MSG(__HRESULT_FROM_WIN32(GetLastError()), - file_mapping == nullptr, - "Model load failed!"); - - auto buffer = MapViewOfFile(file_mapping.get(), // handle to mapping object - FILE_MAP_READ, // read/write - 0, // high-order 32 bits of file offset - 0, // low-order 32 bits of file offset - 0); // number of bytes to map. 0 means read whole file. - - WINML_THROW_HR_IF_TRUE_MSG(__HRESULT_FROM_WIN32(GetLastError()), - buffer == nullptr, - "Model load failed!"); + WINML_THROW_HR_IF_TRUE_MSG( + __HRESULT_FROM_WIN32(GetLastError()), file_handle.get() == INVALID_HANDLE_VALUE, "Model load failed!" + ); + + auto file_mapping = wil::unique_handle(CreateFileMappingW( + file_handle.get(), // current file handle + NULL, // default security + PAGE_READONLY, // read/write permission + 0, // size of mapping object, high + 0, // size of mapping object, low + NULL + )); // name of mapping object + + WINML_THROW_HR_IF_TRUE_MSG(__HRESULT_FROM_WIN32(GetLastError()), file_mapping == nullptr, "Model load failed!"); + + auto buffer = MapViewOfFile( + file_mapping.get(), // handle to mapping object + FILE_MAP_READ, // read/write + 0, // high-order 32 bits of file offset + 0, // low-order 32 bits of file offset + 0 + ); // number of bytes to map. 0 means read whole file. + + WINML_THROW_HR_IF_TRUE_MSG(__HRESULT_FROM_WIN32(GetLastError()), buffer == nullptr, "Model load failed!"); LARGE_INTEGER file_size; - WINML_THROW_HR_IF_FALSE_MSG(__HRESULT_FROM_WIN32(GetLastError()), - GetFileSizeEx(file_handle.get(), &file_size), - "GetFileSizeEx"); + WINML_THROW_HR_IF_FALSE_MSG( + __HRESULT_FROM_WIN32(GetLastError()), GetFileSizeEx(file_handle.get(), &file_size), "GetFileSizeEx" + ); WINML_THROW_IF_FAILED(engine_factory_->CreateModel(buffer, static_cast(file_size.QuadPart), model_.put())); WINML_THROW_HR_IF_TRUE_MSG(E_UNEXPECTED, UnmapViewOfFile(buffer) == 0, "Could not unmap model file."); WINML_THROW_IF_FAILED(model_->GetModelInfo(model_info_.put())); @@ -118,10 +108,11 @@ LearningModel::LearningModel( WINML_CATCH_ALL LearningModel::LearningModel( - _winml::IEngineFactory* engine_factory, - _winml::IModel* model, - const winml::ILearningModelOperatorProvider operator_provider) try : - operator_provider_(operator_provider) { + _winml::IEngineFactory* engine_factory, + _winml::IModel* model, + const winml::ILearningModelOperatorProvider operator_provider +) try + : operator_provider_(operator_provider) { engine_factory_.copy_from(engine_factory); model_.copy_from(model); WINML_THROW_IF_FAILED(model_->GetModelInfo(model_info_.put())); @@ -129,22 +120,20 @@ LearningModel::LearningModel( WINML_CATCH_ALL static HRESULT CreateModelFromStream( - _winml::IEngineFactory* engine_factory, - const wss::IRandomAccessStreamReference stream, - _winml::IModel** model) { + _winml::IEngineFactory* engine_factory, const wss::IRandomAccessStreamReference stream, _winml::IModel** model +) { auto content = stream.OpenReadAsync().get(); auto buffer = winrt::make>(static_cast(content.Size())); - auto result = content.ReadAsync( - buffer, - buffer.Capacity(), - wss::InputStreamOptions::None).get(); + auto result = content.ReadAsync(buffer, buffer.Capacity(), wss::InputStreamOptions::None).get(); auto bytes = buffer.try_as<::Windows::Storage::Streams::IBufferByteAccess>(); WINML_THROW_HR_IF_NULL_MSG(E_UNEXPECTED, bytes, "Model stream is invalid."); void* data; - WINML_THROW_IF_FAILED_MSG(bytes->Buffer(reinterpret_cast(&data)), "Failed to acquire buffer from model stream."); + WINML_THROW_IF_FAILED_MSG( + bytes->Buffer(reinterpret_cast(&data)), "Failed to acquire buffer from model stream." + ); size_t len = static_cast(content.Size()); if (FAILED(engine_factory->CreateModel(data, len, model))) { @@ -155,8 +144,9 @@ static HRESULT CreateModelFromStream( } LearningModel::LearningModel( - const wss::IRandomAccessStreamReference stream, - const winml::ILearningModelOperatorProvider operator_provider) try : operator_provider_(operator_provider) { + const wss::IRandomAccessStreamReference stream, const winml::ILearningModelOperatorProvider operator_provider +) try + : operator_provider_(operator_provider) { _winmlt::TelemetryEvent loadModel_event(_winmlt::EventCategory::kModelLoad); WINML_THROW_IF_FAILED(CreateOnnxruntimeEngineFactory(engine_factory_.put())); @@ -165,8 +155,7 @@ LearningModel::LearningModel( } WINML_CATCH_ALL -hstring -LearningModel::Author() try { +hstring LearningModel::Author() try { const char* out; size_t len; WINML_THROW_IF_FAILED(model_info_->GetAuthor(&out, &len)); @@ -174,8 +163,7 @@ LearningModel::Author() try { } WINML_CATCH_ALL -hstring -LearningModel::Name() try { +hstring LearningModel::Name() try { const char* out; size_t len; WINML_THROW_IF_FAILED(model_info_->GetName(&out, &len)); @@ -183,8 +171,7 @@ LearningModel::Name() try { } WINML_CATCH_ALL -hstring -LearningModel::Domain() try { +hstring LearningModel::Domain() try { const char* out; size_t len; WINML_THROW_IF_FAILED(model_info_->GetDomain(&out, &len)); @@ -192,8 +179,7 @@ LearningModel::Domain() try { } WINML_CATCH_ALL -hstring -LearningModel::Description() try { +hstring LearningModel::Description() try { const char* out; size_t len; WINML_THROW_IF_FAILED(model_info_->GetDescription(&out, &len)); @@ -201,16 +187,14 @@ LearningModel::Description() try { } WINML_CATCH_ALL -int64_t -LearningModel::Version() try { +int64_t LearningModel::Version() try { int64_t version; WINML_THROW_IF_FAILED(model_info_->GetVersion(&version)); return version; } WINML_CATCH_ALL -wfc::IMapView -LearningModel::Metadata() try { +wfc::IMapView LearningModel::Metadata() try { ABI::Windows::Foundation::Collections::IMapView* metadata = nullptr; wfc::IMapView out; WINML_THROW_IF_FAILED(model_info_->GetModelMetadata(&metadata)); @@ -219,15 +203,13 @@ LearningModel::Metadata() try { } WINML_CATCH_ALL -IMLOperatorRegistry* -LearningModel::GetOperatorRegistry() { +IMLOperatorRegistry* LearningModel::GetOperatorRegistry() { if (operator_provider_ == nullptr) { return nullptr; } // Get the native winrt provider interface out of winrt operator provider. - auto operator_provider_native = - operator_provider_.as(); + auto operator_provider_native = operator_provider_.as(); IMLOperatorRegistry* registry = nullptr; // Retrieve the "operator abi" registry. @@ -235,8 +217,7 @@ LearningModel::GetOperatorRegistry() { return registry; } -wfc::IVectorView -LearningModel::InputFeatures() try { +wfc::IVectorView LearningModel::InputFeatures() try { ABI::Windows::Foundation::Collections::IVectorView* features = nullptr; wfc::IVectorView out; WINML_THROW_IF_FAILED(model_info_->GetInputFeatures(&features)); @@ -245,8 +226,7 @@ LearningModel::InputFeatures() try { } WINML_CATCH_ALL -wfc::IVectorView -LearningModel::OutputFeatures() try { +wfc::IVectorView LearningModel::OutputFeatures() try { ABI::Windows::Foundation::Collections::IVectorView* features = nullptr; wfc::IVectorView out; WINML_THROW_IF_FAILED(model_info_->GetOutputFeatures(&features)); @@ -272,66 +252,55 @@ bool LearningModel::IsDisposed() { return model_ == nullptr; } -wf::IAsyncOperation -LearningModel::LoadFromStorageFileAsync( - ws::IStorageFile const modelFile) { +wf::IAsyncOperation LearningModel::LoadFromStorageFileAsync(ws::IStorageFile const modelFile) { return LoadFromStorageFileAsync(modelFile, nullptr); } -wf::IAsyncOperation -LearningModel::LoadFromStorageFileAsync( - ws::IStorageFile const modelFile, - winml::ILearningModelOperatorProvider const provider) { +wf::IAsyncOperation LearningModel::LoadFromStorageFileAsync( + ws::IStorageFile const modelFile, winml::ILearningModelOperatorProvider const provider +) { co_await resume_background(); return make(modelFile, provider); } -wf::IAsyncOperation -LearningModel::LoadFromStreamAsync( - wss::IRandomAccessStreamReference const model_stream) { +wf::IAsyncOperation LearningModel::LoadFromStreamAsync( + wss::IRandomAccessStreamReference const model_stream +) { return LoadFromStreamAsync(model_stream, nullptr); } -wf::IAsyncOperation -LearningModel::LoadFromStreamAsync( - wss::IRandomAccessStreamReference const model_stream, - winml::ILearningModelOperatorProvider const provider) { +wf::IAsyncOperation LearningModel::LoadFromStreamAsync( + wss::IRandomAccessStreamReference const model_stream, winml::ILearningModelOperatorProvider const provider +) { co_await resume_background(); return make(model_stream, provider); } -winml::LearningModel -LearningModel::LoadFromFilePath( - hstring const& path) try { +winml::LearningModel LearningModel::LoadFromFilePath(hstring const& path) try { return LoadFromFilePath(path, nullptr); } WINML_CATCH_ALL -winml::LearningModel -LearningModel::LoadFromFilePath( - hstring const& path, - winml::ILearningModelOperatorProvider const provider) try { +winml::LearningModel LearningModel::LoadFromFilePath( + hstring const& path, winml::ILearningModelOperatorProvider const provider +) try { return make(path, provider); } WINML_CATCH_ALL -winml::LearningModel -LearningModel::LoadFromStream( - wss::IRandomAccessStreamReference const model_stream) try { +winml::LearningModel LearningModel::LoadFromStream(wss::IRandomAccessStreamReference const model_stream) try { return LoadFromStream(model_stream, nullptr); } WINML_CATCH_ALL -winml::LearningModel -LearningModel::LoadFromStream( - wss::IRandomAccessStreamReference const model_stream, - winml::ILearningModelOperatorProvider const provider) try { +winml::LearningModel LearningModel::LoadFromStream( + wss::IRandomAccessStreamReference const model_stream, winml::ILearningModelOperatorProvider const provider +) try { return make(model_stream, provider); } WINML_CATCH_ALL -_winml::IModel* -LearningModel::DetachModel() { +_winml::IModel* LearningModel::DetachModel() { com_ptr<_winml::IModel> detached_model; if (model_ != nullptr) { detached_model.attach(model_.detach()); @@ -342,8 +311,7 @@ LearningModel::DetachModel() { return detached_model.detach(); } -_winml::IModel* -LearningModel::CloneModel() { +_winml::IModel* LearningModel::CloneModel() { if (model_ == nullptr) { return nullptr; } @@ -354,8 +322,7 @@ LearningModel::CloneModel() { return model_copy.detach(); } -_winml::IEngineFactory* -LearningModel::GetEngineFactory() { +_winml::IEngineFactory* LearningModel::GetEngineFactory() { return engine_factory_.get(); } @@ -364,11 +331,12 @@ void LearningModel::SaveToFile(const hstring& file_name) { } void LearningModel::JoinModel( - winml::LearningModel other, - const std::unordered_map& linkages, - bool promote_unlinked_outputs, - bool close_model_on_join, - const winrt::hstring& join_node_prefix) { + winml::LearningModel other, + const std::unordered_map& linkages, + bool promote_unlinked_outputs, + bool close_model_on_join, + const winrt::hstring& join_node_prefix +) { auto otherp = other.as(); winrt::com_ptr<_winml::IModel> other_model; if (close_model_on_join) { @@ -379,18 +347,17 @@ void LearningModel::JoinModel( std::vector raw_outputs(linkages.size()); std::vector raw_inputs(linkages.size()); - std::transform(std::begin(linkages), std::end(linkages), std::begin(raw_outputs), - [](auto& pair) { return pair.first.c_str(); }); - std::transform(std::begin(linkages), std::end(linkages), std::begin(raw_inputs), - [](auto& pair) { return pair.second.c_str(); }); + std::transform(std::begin(linkages), std::end(linkages), std::begin(raw_outputs), [](auto& pair) { + return pair.first.c_str(); + }); + std::transform(std::begin(linkages), std::end(linkages), std::begin(raw_inputs), [](auto& pair) { + return pair.second.c_str(); + }); auto prefix = winrt::to_string(join_node_prefix); - WINML_THROW_IF_FAILED(model_->JoinModel(other_model.get(), - raw_outputs.data(), - raw_inputs.data(), - linkages.size(), - promote_unlinked_outputs, - prefix.c_str())); + WINML_THROW_IF_FAILED(model_->JoinModel( + other_model.get(), raw_outputs.data(), raw_inputs.data(), linkages.size(), promote_unlinked_outputs, prefix.c_str() + )); model_info_ = nullptr; WINML_THROW_IF_FAILED(model_->GetModelInfo(model_info_.put())); @@ -402,14 +369,17 @@ namespace WINML::factory_implementation { // copied from cppwinrt magic to create abi wrappers. Need to do it this way // since peeps underneath (like the constructor) will throw HRESULT -__stdcall LearningModel::Load( - const wchar_t* p_model_path, - uint32_t model_path_size, - IUnknown** pp_model_unk) { +__stdcall LearningModel::Load(const wchar_t* p_model_path, uint32_t model_path_size, IUnknown** pp_model_unk) { try { - WINML_THROW_HR_IF_NULL_MSG(E_INVALIDARG, p_model_path, "Failed to create LearningModel. Ivalid argument p_model_path."); - WINML_THROW_HR_IF_FALSE_MSG(E_INVALIDARG, model_path_size > 0, "Failed to create LearningModel. Ivalid argument model_path_size."); - WINML_THROW_HR_IF_NULL_MSG(E_INVALIDARG, pp_model_unk, "Failed to create LearningModel. Ivalid argument pp_model_unk."); + WINML_THROW_HR_IF_NULL_MSG( + E_INVALIDARG, p_model_path, "Failed to create LearningModel. Ivalid argument p_model_path." + ); + WINML_THROW_HR_IF_FALSE_MSG( + E_INVALIDARG, model_path_size > 0, "Failed to create LearningModel. Ivalid argument model_path_size." + ); + WINML_THROW_HR_IF_NULL_MSG( + E_INVALIDARG, pp_model_unk, "Failed to create LearningModel. Ivalid argument pp_model_unk." + ); winrt::hstring path(p_model_path, model_path_size); auto model = make(path, nullptr); diff --git a/winml/lib/Api/LearningModel.h b/winml/lib/Api/LearningModel.h index 762b65332abc4..b477889c885d2 100644 --- a/winml/lib/Api/LearningModel.h +++ b/winml/lib/Api/LearningModel.h @@ -17,43 +17,34 @@ struct LearningModel : LearningModelT { /* LearningModel constructors (MachineLearningContract 1). */ LearningModel() = default; - LearningModel( - const hstring& path, - const winml::ILearningModelOperatorProvider operator_provider); + LearningModel(const hstring& path, const winml::ILearningModelOperatorProvider operator_provider); LearningModel( - const wss::IRandomAccessStreamReference stream, - const winml::ILearningModelOperatorProvider operator_provider); + const wss::IRandomAccessStreamReference stream, const winml::ILearningModelOperatorProvider operator_provider + ); LearningModel( - _winml::IEngineFactory* engine_factory, - _winml::IModel* model, - const winml::ILearningModelOperatorProvider operator_provider); + _winml::IEngineFactory* engine_factory, + _winml::IModel* model, + const winml::ILearningModelOperatorProvider operator_provider + ); /* LearningModel properties (MachineLearningContract 1). */ - hstring - Author(); + hstring Author(); - hstring - Name(); + hstring Name(); - hstring - Domain(); + hstring Domain(); - hstring - Description(); + hstring Description(); - int64_t - Version(); + int64_t Version(); - wfc::IMapView - Metadata(); + wfc::IMapView Metadata(); - wfc::IVectorView - InputFeatures(); + wfc::IVectorView InputFeatures(); - wfc::IVectorView - OutputFeatures(); + wfc::IVectorView OutputFeatures(); void SetName(const hstring& name); @@ -61,41 +52,29 @@ struct LearningModel : LearningModelT { void Close(); /* LearningModel static methods (MachineLearningContract 1). */ - static wf::IAsyncOperation - LoadFromStorageFileAsync( - ws::IStorageFile const model_file); - - static wf::IAsyncOperation - LoadFromStorageFileAsync( - ws::IStorageFile const model_file, - winml::ILearningModelOperatorProvider const operator_provider); - - static wf::IAsyncOperation - LoadFromStreamAsync( - wss::IRandomAccessStreamReference const stream); - - static wf::IAsyncOperation - LoadFromStreamAsync( - wss::IRandomAccessStreamReference const stream, - winml::ILearningModelOperatorProvider const operator_provider); - - static winml::LearningModel - LoadFromFilePath( - hstring const& path); - - static winml::LearningModel - LoadFromFilePath( - hstring const& path, - winml::ILearningModelOperatorProvider const operator_provider); - - static winml::LearningModel - LoadFromStream( - wss::IRandomAccessStreamReference const stream); - - static winml::LearningModel - LoadFromStream( - wss::IRandomAccessStreamReference const stream, - winml::ILearningModelOperatorProvider const operator_provider); + static wf::IAsyncOperation LoadFromStorageFileAsync(ws::IStorageFile const model_file); + + static wf::IAsyncOperation LoadFromStorageFileAsync( + ws::IStorageFile const model_file, winml::ILearningModelOperatorProvider const operator_provider + ); + + static wf::IAsyncOperation LoadFromStreamAsync(wss::IRandomAccessStreamReference const stream); + + static wf::IAsyncOperation LoadFromStreamAsync( + wss::IRandomAccessStreamReference const stream, winml::ILearningModelOperatorProvider const operator_provider + ); + + static winml::LearningModel LoadFromFilePath(hstring const& path); + + static winml::LearningModel LoadFromFilePath( + hstring const& path, winml::ILearningModelOperatorProvider const operator_provider + ); + + static winml::LearningModel LoadFromStream(wss::IRandomAccessStreamReference const stream); + + static winml::LearningModel LoadFromStream( + wss::IRandomAccessStreamReference const stream, winml::ILearningModelOperatorProvider const operator_provider + ); public: /* Non-ABI methods */ @@ -106,11 +85,12 @@ struct LearningModel : LearningModelT { _winml::IEngineFactory* GetEngineFactory(); void SaveToFile(const hstring& file_name); void JoinModel( - winml::LearningModel other, - const std::unordered_map& linkages, - bool promote_unlinked_outputs, - bool close_model_on_join, - const winrt::hstring& join_node_prefix); + winml::LearningModel other, + const std::unordered_map& linkages, + bool promote_unlinked_outputs, + bool close_model_on_join, + const winrt::hstring& join_node_prefix + ); private: com_ptr<_winml::IEngineFactory> engine_factory_; diff --git a/winml/lib/Api/LearningModelBinding.cpp b/winml/lib/Api/LearningModelBinding.cpp index 0c79117a345dd..17440f6f0a561 100644 --- a/winml/lib/Api/LearningModelBinding.cpp +++ b/winml/lib/Api/LearningModelBinding.cpp @@ -11,20 +11,18 @@ #include "LearningModel.h" namespace WINMLP { -LearningModelBinding::~LearningModelBinding() -{ +LearningModelBinding::~LearningModelBinding() { Clear(); } -LearningModelBinding::LearningModelBinding( - winml::LearningModelSession const& session) try : m_session(session) { +LearningModelBinding::LearningModelBinding(winml::LearningModelSession const& session) try : m_session(session) { session.as()->CheckClosed(); } WINML_CATCH_ALL static winml::ILearningModelFeatureDescriptor FindValidBinding( - wfc::IIterable descriptors, - const std::wstring& name) { + wfc::IIterable descriptors, const std::wstring& name +) { for (auto descriptor : descriptors) { auto descriptor_native = descriptor.as(); @@ -42,9 +40,7 @@ static winml::ILearningModelFeatureDescriptor FindValidBinding( using NullableBindingPort = std::optional>; -static NullableBindingPort FindValidBinding( - winml::LearningModel model, - const std::wstring& name) { +static NullableBindingPort FindValidBinding(winml::LearningModel model, const std::wstring& name) { if (auto descriptor = FindValidBinding(model.InputFeatures(), name)) { return std::make_pair(descriptor, _winml::BindingType::kInput); } else if (auto output_descriptor = FindValidBinding(model.OutputFeatures(), name)) { @@ -54,25 +50,20 @@ static NullableBindingPort FindValidBinding( return {}; } -void LearningModelBinding::CacheProvider( - std::string name, - ProviderInfo& providerInfo) { +void LearningModelBinding::CacheProvider(std::string name, ProviderInfo& providerInfo) { m_providers[name] = providerInfo; } std::tuple, _winml::BindingType> LearningModelBinding::CreateBinding( - const std::string& name, - const wf::IInspectable& inspectable, - wfc::IPropertySet const& properties) { + const std::string& name, const wf::IInspectable& inspectable, wfc::IPropertySet const& properties +) { // Given a known type, validate against the model auto model = m_session.Model(); auto bindingPort = FindValidBinding(model, _winml::Strings::WStringFromString(name)); WINML_THROW_HR_IF_FALSE_MSG( - WINML_ERR_INVALID_BINDING, - bindingPort.has_value(), - "The model has no variable with name %s.", - name.c_str()); + WINML_ERR_INVALID_BINDING, bindingPort.has_value(), "The model has no variable with name %s.", name.c_str() + ); // Retrieve the descriptor and binding type auto descriptor = bindingPort->first; @@ -81,21 +72,18 @@ std::tuple, _winml::BindingType> Lea // Create a feature value from the iinspectable input auto featureValue = _winml::CreateFeatureValueFromInspectable(bindingType, inspectable, descriptor); WINML_THROW_HR_IF_NULL_MSG( - WINML_ERR_INVALID_BINDING, - featureValue, - "The model variable %s cannot be bound with the provided type.", - name.c_str()); + WINML_ERR_INVALID_BINDING, + featureValue, + "The model variable %s cannot be bound with the provided type.", + name.c_str() + ); // Validate that the feature value is compatible with the descriptor _winml::VerifyFeatureValueCompatibleWithDescriptor(featureValue, descriptor); // Create the Binding Context to pass to the feature value _winml::BindingContext context{ - bindingType, - m_session, - descriptor, - properties, - {} // SubresourceId is set by callee + bindingType, m_session, descriptor, properties, {} // SubresourceId is set by callee }; // Get the bound tensor @@ -122,15 +110,15 @@ std::tuple, _winml::BindingType> Lea if (!isPlaceHolder || shouldAlwaysTensorize) { // If not a placeholder, attempt to get the underlying resource WINML_THROW_IF_FAILED_MSG( - spLotusValueProvider->GetValue(context, value.put()), - "The model variable %s failed tensorization.", - name.c_str()); + spLotusValueProvider->GetValue(context, value.put()), "The model variable %s failed tensorization.", name.c_str() + ); } else { WINML_THROW_HR_IF_TRUE_MSG( - WINML_ERR_INVALID_BINDING, - isPlaceHolder && bindingType == _winml::BindingType::kInput, - "The model variable %s is an input, but has no associated resources to bind.", - name.c_str()); + WINML_ERR_INVALID_BINDING, + isPlaceHolder && bindingType == _winml::BindingType::kInput, + "The model variable %s is an input, but has no associated resources to bind.", + name.c_str() + ); WINML_THROW_IF_FAILED(spSession->GetEngine()->CreateNullValue(value.put())); } @@ -138,22 +126,18 @@ std::tuple, _winml::BindingType> Lea // Hold onto the input output providers so that our memory doesnt get destroyed! auto providerInfo = ProviderInfo{inspectable, spLotusValueProvider, context}; CacheProvider(name, providerInfo); - + return std::make_tuple(name, value, bindingType); } -void LearningModelBinding::Bind( - hstring const& name, - wf::IInspectable const& value) try { +void LearningModelBinding::Bind(hstring const& name, wf::IInspectable const& value) try { return Bind(name, value, nullptr /* no properties */); } WINML_CATCH_ALL void LearningModelBinding::Bind( - hstring const& name, - wf::IInspectable const& value, - wfc::IPropertySet const& properties) try { - + hstring const& name, wf::IInspectable const& value, wfc::IPropertySet const& properties +) try { // if this is being called on the GPU, grab the DML lock // the DML EP is not thread safe. auto session = m_session.as(); @@ -211,10 +195,11 @@ wf::IInspectable LearningModelBinding::Lookup(hstring const& key) { auto foundIt = m_providers.find(utf8_name); WINML_THROW_HR_IF_FALSE_MSG( - E_BOUNDS, - foundIt != std::end(m_providers), - "The binding collection does not contain a variable with name %s.", - utf8_name.c_str()); + E_BOUNDS, + foundIt != std::end(m_providers), + "The binding collection does not contain a variable with name %s.", + utf8_name.c_str() + ); auto providerInfo = foundIt->second; return providerInfo.CallerSpecifiedFeatureValue; @@ -230,8 +215,8 @@ bool LearningModelBinding::HasKey(hstring const& key) { } void LearningModelBinding::Split( - wfc::IMapView& first, - wfc::IMapView& second) { + wfc::IMapView& first, wfc::IMapView& second +) { // the winrt api guide states: // If the IMapView instance cannot be split, then both the first and second parameters are null when the method returns. first = nullptr; @@ -239,8 +224,8 @@ void LearningModelBinding::Split( } ILearningModelFeatureValue LearningModelBinding::CreateUnboundOuputFeatureValue( - const winrt::com_ptr<_winml::IValue> value, - ILearningModelFeatureDescriptor& descriptor) { + const winrt::com_ptr<_winml::IValue> value, ILearningModelFeatureDescriptor& descriptor +) { bool out; if (SUCCEEDED(value->IsTensor(&out)) && out) { if (SUCCEEDED(value->IsOfTensorType(TensorKind::Float, &out)) && out) { @@ -369,44 +354,45 @@ ILearningModelFeatureValue LearningModelBinding::CreateUnboundOuputFeatureValue( auto utf8_name = _winml::Strings::UTF8FromHString(descriptor.Name()); WINML_THROW_HR_IF_TRUE_MSG( - E_UNEXPECTED, - true, - "The engine produced an unexpected evaluation output for unbound output variable %s.", - utf8_name.c_str()); + E_UNEXPECTED, + true, + "The engine produced an unexpected evaluation output for unbound output variable %s.", + utf8_name.c_str() + ); return nullptr; } wf::IInspectable LearningModelBinding::CreateUnboundOutput( - const std::string& name, - winrt::com_ptr<_winml::IValue> value) { + const std::string& name, winrt::com_ptr<_winml::IValue> value +) { // Find valid binding port - auto bindingPort = FindValidBinding( - m_session.Model(), - _winml::Strings::WStringFromString(name)); + auto bindingPort = FindValidBinding(m_session.Model(), _winml::Strings::WStringFromString(name)); WINML_THROW_HR_IF_FALSE_MSG( - E_UNEXPECTED, - bindingPort.has_value(), - "The engine produced an unexpected evaluation output %s, that is not a model variable.", - name.c_str()); + E_UNEXPECTED, + bindingPort.has_value(), + "The engine produced an unexpected evaluation output %s, that is not a model variable.", + name.c_str() + ); // Retrieve the descriptor and binding type auto descriptor = bindingPort->first; auto bindingType = bindingPort->second; WINML_THROW_HR_IF_FALSE_MSG( - E_UNEXPECTED, - bindingType == _winml::BindingType::kOutput, - "The engine produced an unexpected evaluation output %s, that is not a model variable output.", - name.c_str()); + E_UNEXPECTED, + bindingType == _winml::BindingType::kOutput, + "The engine produced an unexpected evaluation output %s, that is not a model variable output.", + name.c_str() + ); // Create a binding context _winml::BindingContext context{ - bindingType, - m_session, - descriptor, - nullptr /* no binding properties for unbound outputs */, - {} // SubresourceId is set by callee + bindingType, + m_session, + descriptor, + nullptr /* no binding properties for unbound outputs */, + {} // SubresourceId is set by callee }; // Create empty feature value @@ -415,16 +401,18 @@ wf::IInspectable LearningModelBinding::CreateUnboundOutput( // Update feature value auto spLotusValueProvider = featureValue.as<_winml::ILotusValueProviderPrivate>(); WINML_THROW_IF_FAILED_MSG( - spLotusValueProvider->UpdateSourceResourceData(context, value.get()), - "Failed to update bound object for model variable output %s", - name.c_str()); + spLotusValueProvider->UpdateSourceResourceData(context, value.get()), + "Failed to update bound object for model variable output %s", + name.c_str() + ); // Get abi representation wf::IInspectable inspectable; WINML_THROW_IF_FAILED_MSG( - spLotusValueProvider->AbiRepresentation(inspectable), - "Failed to return bound object for model variable output %s", - name.c_str()); + spLotusValueProvider->AbiRepresentation(inspectable), + "Failed to return bound object for model variable output %s", + name.c_str() + ); return inspectable; } @@ -435,9 +423,8 @@ std::unordered_map LearningModelBinding::UpdatePr auto& output_names = GetOutputNames(); auto& output_values = GetOutputs(); WINML_THROW_HR_IF_FALSE_MSG( - E_UNEXPECTED, - output_names.size() == output_values.size(), - "Evaluation produced unexpected output variables."); + E_UNEXPECTED, output_names.size() == output_values.size(), "Evaluation produced unexpected output variables." + ); for (unsigned i = 0; i < output_names.size(); i++) { auto utf8_name = output_names[i]; @@ -448,9 +435,10 @@ std::unordered_map LearningModelBinding::UpdatePr auto provider = providerInfo.Provider; auto context = providerInfo.Context; WINML_THROW_IF_FAILED_MSG( - provider->UpdateSourceResourceData(context, value.get()), - "Failed to update bound object for model variable output %s", - utf8_name.c_str()); + provider->UpdateSourceResourceData(context, value.get()), + "Failed to update bound object for model variable output %s", + utf8_name.c_str() + ); outputs[utf8_name] = providerInfo.CallerSpecifiedFeatureValue; } else { @@ -470,26 +458,23 @@ std::unordered_map LearningModelBinding::UpdatePr return outputs; } -STDMETHODIMP LearningModelBinding::Bind( - const wchar_t* name, - UINT32 cchName, - IUnknown* value) { +STDMETHODIMP LearningModelBinding::Bind(const wchar_t* name, UINT32 cchName, IUnknown* value) { try { // if this is being called on the GPU, grab the DML lock // the DML EP is not thread safe. auto session = m_session.as(); auto device = m_session.Device().as(); CWinMLAutoLock lock(!device->IsCpuDevice() ? session->GetDMLEPLock() : nullptr); - + _winmlt::TelemetryEvent binding_event(_winmlt::EventCategory::kBinding); _winml::BindingType binding_type; std::string binding_name; winrt::com_ptr<_winml::IValue> binding_value; wf::IInspectable to; - RETURN_IF_FAILED(value->QueryInterface( - winrt::guid_of(), - reinterpret_cast(winrt::put_abi(to)))); + RETURN_IF_FAILED( + value->QueryInterface(winrt::guid_of(), reinterpret_cast(winrt::put_abi(to))) + ); auto featureName = _winml::Strings::UTF8FromUnicode(name, cchName); std::tie(binding_name, binding_value, binding_type) = CreateBinding(featureName, to, nullptr); @@ -524,7 +509,8 @@ HRESULT LearningModelBinding::BindInput(const std::string& name, winrt::com_ptr< auto engine = m_session.as()->GetEngine(); winrt::com_ptr<_winml::IValue> device_value; - WINML_THROW_IF_FAILED(engine->CreateOneInputAcrossDevices(name.c_str(), value.get(), device_value.put())); // an input will always be copied on device mismatch + WINML_THROW_IF_FAILED(engine->CreateOneInputAcrossDevices(name.c_str(), value.get(), device_value.put()) + ); // an input will always be copied on device mismatch if (exists) { inputs_[index] = device_value; @@ -569,39 +555,38 @@ const std::vector>& LearningModelBinding::GetInpu void LearningModelBinding::BindUnboundOutputs() { auto& bound_output_names = GetOutputNames(); - std::unordered_set bound_output_names_set( - bound_output_names.begin(), - bound_output_names.end()); + std::unordered_set bound_output_names_set(bound_output_names.begin(), bound_output_names.end()); // Get model output feature names auto model_impl = m_session.Model().as(); auto output_features = model_impl->OutputFeatures(); - std::vector output_descriptors( - begin(output_features), - end(output_features)); + std::vector output_descriptors(begin(output_features), end(output_features)); // Convert all output features to their feature names std::vector output_feature_names; std::transform( - std::begin(output_descriptors), - std::end(output_descriptors), - std::back_inserter(output_feature_names), - [&](auto& descriptor) { - auto descriptor_native = descriptor.as(); - const wchar_t* p_name; - uint32_t size; - WINML_THROW_IF_FAILED(descriptor_native->GetName(&p_name, &size)); - return _winml::Strings::UTF8FromUnicode(p_name, size); - }); + std::begin(output_descriptors), + std::end(output_descriptors), + std::back_inserter(output_feature_names), + [&](auto& descriptor) { + auto descriptor_native = descriptor.as(); + const wchar_t* p_name; + uint32_t size; + WINML_THROW_IF_FAILED(descriptor_native->GetName(&p_name, &size)); + return _winml::Strings::UTF8FromUnicode(p_name, size); + } + ); // Find the set difference to determine if there are any unbound output features std::vector unbound_output_names; std::copy_if( - std::begin(output_feature_names), std::end(output_feature_names), - std::inserter(unbound_output_names, std::begin(unbound_output_names)), - [&](const auto& outputFeatureName) { - return bound_output_names_set.find(outputFeatureName) == bound_output_names_set.end(); - }); + std::begin(output_feature_names), + std::end(output_feature_names), + std::inserter(unbound_output_names, std::begin(unbound_output_names)), + [&](const auto& outputFeatureName) { + return bound_output_names_set.find(outputFeatureName) == bound_output_names_set.end(); + } + ); // Add all unbound outputs to binding collection for (const auto& unbound_output : unbound_output_names) { @@ -613,4 +598,4 @@ void LearningModelBinding::BindUnboundOutputs() { } } -} // namespace WINMLP \ No newline at end of file +} // namespace WINMLP diff --git a/winml/lib/Api/LearningModelBinding.h b/winml/lib/Api/LearningModelBinding.h index ed425001dc899..5ac6e42d124dc 100644 --- a/winml/lib/Api/LearningModelBinding.h +++ b/winml/lib/Api/LearningModelBinding.h @@ -21,7 +21,7 @@ struct LearningModelBinding : LearningModelBindingT; ~LearningModelBinding(); - + LearningModelBinding() = delete; LearningModelBinding(winml::LearningModelSession const& session); @@ -34,14 +34,11 @@ struct LearningModelBinding : LearningModelBindingT& first, - wfc::IMapView& second); + void Split(wfc::IMapView& first, wfc::IMapView& second); std::tuple, _winml::BindingType> CreateBinding( - const std::string& name, - const wf::IInspectable& value, - wfc::IPropertySet const& properties); + const std::string& name, const wf::IInspectable& value, wfc::IPropertySet const& properties + ); std::unordered_map UpdateProviders(); @@ -49,10 +46,10 @@ struct LearningModelBinding : LearningModelBindingT& GetInputNames() const; const std::vector& GetOutputNames() const; - + const std::vector>& GetInputs() const; std::vector>& GetOutputs(); - + HRESULT BindOutput(const std::string& name, winrt::com_ptr<_winml::IValue> value); void BindUnboundOutputs(); @@ -60,8 +57,8 @@ struct LearningModelBinding : LearningModelBindingT value); ILearningModelFeatureValue CreateUnboundOuputFeatureValue( - const winrt::com_ptr<_winml::IValue> value, - ILearningModelFeatureDescriptor& descriptor); + const winrt::com_ptr<_winml::IValue> value, ILearningModelFeatureDescriptor& descriptor + ); HRESULT BindInput(const std::string& name, winrt::com_ptr<_winml::IValue> value); private: @@ -77,6 +74,5 @@ struct LearningModelBinding : LearningModelBindingT { -}; +struct LearningModelBinding : LearningModelBindingT {}; } // namespace WINML::factory_implementation diff --git a/winml/lib/Api/LearningModelDevice.cpp b/winml/lib/Api/LearningModelDevice.cpp index 3e471d7b55dc7..c9c6f5bc70ee2 100644 --- a/winml/lib/Api/LearningModelDevice.cpp +++ b/winml/lib/Api/LearningModelDevice.cpp @@ -23,7 +23,8 @@ wg::DisplayAdapterId LearningModelDevice::AdapterId() try { } WINML_CATCH_ALL -LearningModelDevice::LearningModelDevice(winml::LearningModelDeviceKind const& deviceKind) try : m_deviceCache(std::make_unique<_winml::D3DDeviceCache>(deviceKind)) { +LearningModelDevice::LearningModelDevice(winml::LearningModelDeviceKind const& deviceKind) try + : m_deviceCache(std::make_unique<_winml::D3DDeviceCache>(deviceKind)) { m_deviceKind = deviceKind; telemetry_helper.SetLearningModelDeviceKind(static_cast(deviceKind)); m_isCpuDevice = m_deviceKind == LearningModelDeviceKind::Cpu || m_deviceKind == LearningModelDeviceKind::Default; @@ -33,14 +34,16 @@ LearningModelDevice::LearningModelDevice(winml::LearningModelDeviceKind const& d } WINML_CATCH_ALL -LearningModelDevice::LearningModelDevice(wgdx::Direct3D11::IDirect3DDevice const& device) try : m_deviceCache(std::make_unique<_winml::D3DDeviceCache>(device)) { +LearningModelDevice::LearningModelDevice(wgdx::Direct3D11::IDirect3DDevice const& device) try + : m_deviceCache(std::make_unique<_winml::D3DDeviceCache>(device)) { m_deviceKind = LearningModelDeviceKind::DirectX; m_isCpuDevice = false; } WINML_CATCH_ALL -LearningModelDevice::LearningModelDevice(ID3D12CommandQueue* queue) try : m_deviceKind(LearningModelDeviceKind::DirectX), - m_deviceCache(std::make_unique<_winml::D3DDeviceCache>(queue)) { +LearningModelDevice::LearningModelDevice(ID3D12CommandQueue* queue) try + : m_deviceKind(LearningModelDeviceKind::DirectX), + m_deviceCache(std::make_unique<_winml::D3DDeviceCache>(queue)) { m_isCpuDevice = false; } WINML_CATCH_ALL @@ -49,23 +52,28 @@ LearningModelDevice::~LearningModelDevice() { // needed for shared ptr destruction } -winml::LearningModelDevice LearningModelDevice::CreateFromDirect3D11Device(wgdx::Direct3D11::IDirect3DDevice const& device) try { +winml::LearningModelDevice LearningModelDevice::CreateFromDirect3D11Device( + wgdx::Direct3D11::IDirect3DDevice const& device +) try { return make(device); } WINML_CATCH_ALL std::shared_ptr<_winml::ConverterResourceStore> LearningModelDevice::TensorizerStore() { - std::call_once(m_tensorizerStoreInitialized, [this]() { m_tensorizerStore = _winml::ConverterResourceStore::Create(5); }); + std::call_once(m_tensorizerStoreInitialized, [this]() { + m_tensorizerStore = _winml::ConverterResourceStore::Create(5); + }); return m_tensorizerStore; } std::shared_ptr<_winml::ConverterResourceStore> LearningModelDevice::DetensorizerStore() { - std::call_once(m_detensorizerStoreInitialized, [this]() { m_detensorizerStore = _winml::ConverterResourceStore::Create(5); }); + std::call_once(m_detensorizerStoreInitialized, [this]() { + m_detensorizerStore = _winml::ConverterResourceStore::Create(5); + }); return m_detensorizerStore; } -winml::LearningModelDeviceKind -LearningModelDevice::GetDeviceKind() { +winml::LearningModelDeviceKind LearningModelDevice::GetDeviceKind() { return m_deviceKind; } @@ -73,29 +81,24 @@ bool LearningModelDevice::IsCpuDevice() { return m_isCpuDevice; } -const LUID& -LearningModelDevice::GetDeviceLuid() { +const LUID& LearningModelDevice::GetDeviceLuid() { return m_deviceCache->GetDeviceLuid(); } -_winml::D3DDeviceCache* -LearningModelDevice::GetD3DDeviceCache() { +_winml::D3DDeviceCache* LearningModelDevice::GetD3DDeviceCache() { return m_deviceCache.get(); } -wgdx::Direct3D11::IDirect3DDevice -LearningModelDevice::Direct3D11Device() try { +wgdx::Direct3D11::IDirect3DDevice LearningModelDevice::Direct3D11Device() try { return m_deviceCache->GetWinrtDevice(); } WINML_CATCH_ALL -ID3D12Device* -LearningModelDevice::GetD3DDevice() { +ID3D12Device* LearningModelDevice::GetD3DDevice() { return m_deviceCache->GetD3D12Device(); } -ID3D12CommandQueue* -LearningModelDevice::GetDeviceQueue() { +ID3D12CommandQueue* LearningModelDevice::GetDeviceQueue() { return m_deviceCache->GetCommandQueue(); } @@ -147,15 +150,15 @@ bool LearningModelDevice::AllowSpinning() { } } -} // namespace WINMLP +} // namespace WINMLP namespace WINML::factory_implementation { // copied from cppwinrt magic to create abi wrappers. Need to do it this way // since peeps underneath (like the constructor) will throw HRESULT __stdcall LearningModelDevice::CreateFromD3D12CommandQueue( - ID3D12CommandQueue* queue, - IUnknown** device) noexcept { + ID3D12CommandQueue* queue, IUnknown** device +) noexcept { try { WINML_THROW_HR_IF_NULL_MSG(E_INVALIDARG, queue, "Failed to create LearningModelDevice. Invalid argument queue."); WINML_THROW_HR_IF_NULL_MSG(E_INVALIDARG, device, "Failed to create LearningModelDevice. Invalid argument device."); diff --git a/winml/lib/Api/LearningModelDevice.h b/winml/lib/Api/LearningModelDevice.h index 66d7308668b92..3e7ac4aaa6d1c 100644 --- a/winml/lib/Api/LearningModelDevice.h +++ b/winml/lib/Api/LearningModelDevice.h @@ -18,78 +18,57 @@ struct LearningModelDevice : LearningModelDeviceT - TensorizerStore(); + std::shared_ptr<_winml::ConverterResourceStore> TensorizerStore(); - std::shared_ptr<_winml::ConverterResourceStore> - DetensorizerStore(); + std::shared_ptr<_winml::ConverterResourceStore> DetensorizerStore(); - uint32_t - NumberOfIntraOpThreads(); + uint32_t NumberOfIntraOpThreads(); - bool - AllowSpinning(); + bool AllowSpinning(); private: // stores the device kind that was originally chosen in the constructor @@ -109,7 +88,8 @@ struct LearningModelDevice : LearningModelDeviceT { +struct LearningModelDevice + : LearningModelDeviceT { HRESULT __stdcall CreateFromD3D12CommandQueue(ID3D12CommandQueue* queue, IUnknown** device) noexcept final; }; } // namespace WINML::factory_implementation diff --git a/winml/lib/Api/LearningModelEvaluationResult.cpp b/winml/lib/Api/LearningModelEvaluationResult.cpp index c4a65af4e1ee9..190140665be91 100644 --- a/winml/lib/Api/LearningModelEvaluationResult.cpp +++ b/winml/lib/Api/LearningModelEvaluationResult.cpp @@ -5,34 +5,29 @@ #include "LearningModelEvaluationResult.h" namespace WINMLP { -hstring LearningModelEvaluationResult::CorrelationId() try { - return m_correlationId; -} +hstring LearningModelEvaluationResult::CorrelationId() try { return m_correlationId; } WINML_CATCH_ALL void LearningModelEvaluationResult::CorrelationId(const hstring& correlationId) { m_correlationId = correlationId; } -int32_t LearningModelEvaluationResult::ErrorStatus() try { - return m_errorStatus; -} +int32_t LearningModelEvaluationResult::ErrorStatus() try { return m_errorStatus; } WINML_CATCH_ALL void LearningModelEvaluationResult::ErrorStatus(int32_t errorStatus) { m_errorStatus = errorStatus; } -bool LearningModelEvaluationResult::Succeeded() try { - return m_succeeded; -} +bool LearningModelEvaluationResult::Succeeded() try { return m_succeeded; } WINML_CATCH_ALL void LearningModelEvaluationResult::Succeeded(bool succeeded) { m_succeeded = succeeded; } -Windows::Foundation::Collections::IMapView LearningModelEvaluationResult::Outputs() try { +Windows::Foundation::Collections::IMapView +LearningModelEvaluationResult::Outputs() try { std::unordered_map outputs; for (auto& output : m_outputs) { @@ -45,7 +40,9 @@ Windows::Foundation::Collections::IMapView outputs) { +void LearningModelEvaluationResult::Outputs( + Windows::Foundation::Collections::IMapView outputs +) { m_outputs.clear(); for (auto pair : outputs) { @@ -55,10 +52,7 @@ void LearningModelEvaluationResult::Outputs(Windows::Foundation::Collections::IM } } -HRESULT LearningModelEvaluationResult::GetOutput( - const wchar_t* name, - UINT32 cchName, - IUnknown** result) { +HRESULT LearningModelEvaluationResult::GetOutput(const wchar_t* name, UINT32 cchName, IUnknown** result) { *result = nullptr; auto outputName = _winml::Strings::UTF8FromUnicode(name, cchName); @@ -75,7 +69,8 @@ HRESULT LearningModelEvaluationResult::GetOutput( } HRESULT LearningModelEvaluationResult::SetOutputs( - std::unordered_map&& outputs) { + std::unordered_map&& outputs +) { m_outputs = std::move(outputs); return S_OK; } diff --git a/winml/lib/Api/LearningModelEvaluationResult.h b/winml/lib/Api/LearningModelEvaluationResult.h index b26c3fb0d8c8b..352a0c4c9da6b 100644 --- a/winml/lib/Api/LearningModelEvaluationResult.h +++ b/winml/lib/Api/LearningModelEvaluationResult.h @@ -6,9 +6,8 @@ #include "LearningModelEvaluationResult.g.h" namespace WINMLP { -struct LearningModelEvaluationResult : LearningModelEvaluationResultT< - LearningModelEvaluationResult, - ILearningModelEvaluationResultNative> { +struct LearningModelEvaluationResult + : LearningModelEvaluationResultT { LearningModelEvaluationResult() = default; hstring CorrelationId(); @@ -25,10 +24,7 @@ struct LearningModelEvaluationResult : LearningModelEvaluationResultT< // ILearningModelEvaluationResultNative STDMETHOD(GetOutput) - ( - const wchar_t* name, - UINT32 cchName, - IUnknown** result); + (const wchar_t* name, UINT32 cchName, IUnknown** result); HRESULT SetOutputs(std::unordered_map&& outputs); diff --git a/winml/lib/Api/LearningModelSession.cpp b/winml/lib/Api/LearningModelSession.cpp index f086f756ed990..011a4a718f82a 100644 --- a/winml/lib/Api/LearningModelSession.cpp +++ b/winml/lib/Api/LearningModelSession.cpp @@ -21,57 +21,53 @@ static const auto c_enable_debug_output = L"EnableDebugOutput"; namespace guid_details { // This GUID is to be used for delimiting ML-related categories of capturable work. // {D113B493-BBA2-4993-8608-D706A73B91CE} -struct __declspec(uuid("D113B493-BBA2-4993-8608-D706A73B91CE")) __declspec(novtable) WINML_PIX_EVAL_CAPTURABLE_WORK_GUID {}; +struct __declspec(uuid("D113B493-BBA2-4993-8608-D706A73B91CE")) __declspec(novtable +) WINML_PIX_EVAL_CAPTURABLE_WORK_GUID {}; } // namespace guid_details static const GUID WINML_PIX_EVAL_CAPTURABLE_WORK_GUID = __uuidof(guid_details::WINML_PIX_EVAL_CAPTURABLE_WORK_GUID); namespace WINMLP { -LearningModelSession::LearningModelSession(_winml::IEngine* engine) : operator_registry_(nullptr, nullptr), - model_(nullptr), - device_(LearningModelDeviceKind::Cpu), - session_options_(nullptr) -{ - engine_.copy_from(engine); +LearningModelSession::LearningModelSession(_winml::IEngine* engine) + : operator_registry_(nullptr, nullptr), + model_(nullptr), + device_(LearningModelDeviceKind::Cpu), + session_options_(nullptr) { + engine_.copy_from(engine); } - -LearningModelSession::LearningModelSession( - winml::LearningModel const& model) try : LearningModelSession(model, - make(LearningModelDeviceKind::Default)) {} +LearningModelSession::LearningModelSession(winml::LearningModel const& model) try + : LearningModelSession(model, make(LearningModelDeviceKind::Default)) {} WINML_CATCH_ALL LearningModelSession::LearningModelSession( - winml::LearningModel const& model, - winml::LearningModelDevice const& deviceToRunOn) try : LearningModelSession(model, - deviceToRunOn, - nullptr) {} + winml::LearningModel const& model, winml::LearningModelDevice const& deviceToRunOn +) try + : LearningModelSession(model, deviceToRunOn, nullptr) {} WINML_CATCH_ALL LearningModelSession::LearningModelSession( - winml::LearningModel const& model, - winml::LearningModelDevice const& deviceToRunOn, - winml::LearningModelSessionOptions const& learningModelSessionOptions) try : operator_registry_(nullptr, nullptr), - model_(model), - device_(deviceToRunOn), - session_options_(learningModelSessionOptions) { + winml::LearningModel const& model, + winml::LearningModelDevice const& deviceToRunOn, + winml::LearningModelSessionOptions const& learningModelSessionOptions +) try + : operator_registry_(nullptr, nullptr), + model_(model), + device_(deviceToRunOn), + session_options_(learningModelSessionOptions) { Initialize(); } WINML_CATCH_ALL -_winml::IModel* -LearningModelSession::GetOptimizedModel() { +_winml::IModel* LearningModelSession::GetOptimizedModel() { // Get the model proto - auto should_close_model = - session_options_ != nullptr && - session_options_.CloseModelOnSessionCreation(); + auto should_close_model = session_options_ != nullptr && session_options_.CloseModelOnSessionCreation(); return GetOptimizedModel(should_close_model); } -_winml::IModel* -LearningModelSession::GetOptimizedModel(bool should_close_model) { +_winml::IModel* LearningModelSession::GetOptimizedModel(bool should_close_model) { com_ptr<_winml::IModel> model; { @@ -81,12 +77,9 @@ LearningModelSession::GetOptimizedModel(bool should_close_model) { // Throw if the model has been disposed and is not capable of creating // new sessions. auto model_impl = model_.as(); - WINML_THROW_HR_IF_TRUE_MSG(E_INVALIDARG, model_impl->IsDisposed(), - "The model has been disposed."); + WINML_THROW_HR_IF_TRUE_MSG(E_INVALIDARG, model_impl->IsDisposed(), "The model has been disposed."); - model.attach(should_close_model - ? model_impl->DetachModel() - : model_impl->CloneModel()); + model.attach(should_close_model ? model_impl->DetachModel() : model_impl->CloneModel()); } // Ensure that the model is runnable on the device @@ -99,8 +92,7 @@ LearningModelSession::GetOptimizedModel(bool should_close_model) { void LearningModelSession::Initialize() { // Begin recording session creation telemetry - _winmlt::TelemetryEvent session_creation_event( - _winmlt::EventCategory::kSessionCreation); + _winmlt::TelemetryEvent session_creation_event(_winmlt::EventCategory::kSessionCreation); // Get the optimized model proto from the learning model com_ptr<_winml::IModel> model; model.attach(GetOptimizedModel()); @@ -115,7 +107,8 @@ void LearningModelSession::Initialize() { WINML_THROW_IF_FAILED(engine_factory_->CreateEngineBuilder(engine_builder.put())); if (device_impl->IsCpuDevice() == false) { - WINML_THROW_IF_FAILED(engine_builder->SetD3D12Resources(device_impl->GetD3DDevice(), device_impl->GetDeviceQueue())); + WINML_THROW_IF_FAILED(engine_builder->SetD3D12Resources(device_impl->GetD3DDevice(), device_impl->GetDeviceQueue()) + ); WINML_THROW_IF_FAILED(engine_builder->SetMetacommandsEnabled(device_impl->MetacommandsEnabled())); } @@ -127,27 +120,34 @@ void LearningModelSession::Initialize() { WINML_THROW_IF_FAILED(engine_builder->SetBatchSizeOverride(session_options_.BatchSizeOverride())); } - com_ptr session_options_impl = session_options_.as(); + com_ptr session_options_impl = + session_options_.as(); // Make onnxruntime apply named dimension overrides, if any if (session_options_impl && session_options_impl->NamedDimensionOverrides().Size() > 0) { - WINML_THROW_IF_FAILED(engine_builder->SetNamedDimensionOverrides(session_options_impl->NamedDimensionOverrides())); + WINML_THROW_IF_FAILED(engine_builder->SetNamedDimensionOverrides(session_options_impl->NamedDimensionOverrides()) + ); } allow_spinning = session_options_impl->GetIntraOpThreadSpinning(); num_intra_op_threads = session_options_impl->GetIntraOpNumThreads(); + + const auto& paths = session_options_impl->GetCustomOpLibraryPaths(); + for (const auto& path : paths) { + auto path_str = _winml::Strings::UTF8FromHString(path); + WINML_THROW_IF_FAILED(engine_builder->RegisterCustomOpsLibrary(path_str.c_str())); + } } - - bool create_local_thread_pool = allow_spinning != device_impl->AllowSpinning() || - num_intra_op_threads != device_impl->NumberOfIntraOpThreads(); + + bool create_local_thread_pool = + allow_spinning != device_impl->AllowSpinning() || num_intra_op_threads != device_impl->NumberOfIntraOpThreads(); if (create_local_thread_pool) { WINML_THROW_IF_FAILED(engine_builder->SetIntraOpThreadSpinning(allow_spinning)); WINML_THROW_IF_FAILED(engine_builder->SetIntraOpNumThreadsOverride(num_intra_op_threads)); } else { winrt::com_ptr<_winml::IThreading> thread_pool = nullptr; WINML_THROW_IF_FAILED(device_impl->GetThreadPool(thread_pool.put())); - if (thread_pool == nullptr) - { + if (thread_pool == nullptr) { WINML_THROW_IF_FAILED(engine_factory_->CreateThreadPool(allow_spinning, num_intra_op_threads, thread_pool.put())); WINML_THROW_IF_FAILED(device_impl->CacheThreadPool(thread_pool.get())); } @@ -158,7 +158,8 @@ void LearningModelSession::Initialize() { WINML_THROW_IF_FAILED(engine_builder->CreateEngine(engine.put())); // Register the custom operator registry - operator_registry_ = MLOperatorRegistry(model_impl->GetOperatorRegistry(), [](auto registry) { registry->Release(); }); + operator_registry_ = + MLOperatorRegistry(model_impl->GetOperatorRegistry(), [](auto registry) { registry->Release(); }); WINML_THROW_IF_FAILED(engine->RegisterCustomRegistry(operator_registry_.get())); // Register transformers - this should probably not be exposed on IEngine, but an internal call as this configuration step is ort specific. @@ -177,8 +178,7 @@ void LearningModelSession::Initialize() { engine_ = engine; } -wfc::IPropertySet -LearningModelSession::EvaluationProperties() try { +wfc::IPropertySet LearningModelSession::EvaluationProperties() try { if (evaluation_properties_ == nullptr) { evaluation_properties_ = wfc::PropertySet(); } @@ -186,21 +186,16 @@ LearningModelSession::EvaluationProperties() try { } WINML_CATCH_ALL -winml::LearningModel -LearningModelSession::Model() try { - return model_; -} +winml::LearningModel LearningModelSession::Model() try { return model_; } WINML_CATCH_ALL -winml::LearningModelDevice -LearningModelSession::Device() try { - return device_; -} +winml::LearningModelDevice LearningModelSession::Device() try { return device_; } +WINML_CATCH_ALL + +winml::LearningModelSessionOptions LearningModelSession::Options() try { return session_options_; } WINML_CATCH_ALL -auto CreateBinding( - LearningModelSession& session, - wfc::IMap const features) { +auto CreateBinding(LearningModelSession& session, wfc::IMap const features) { auto binding = winrt::make(session); for (auto feature : features.GetView()) { @@ -209,19 +204,17 @@ auto CreateBinding( return binding; } -winml::LearningModelEvaluationResult -LearningModelSession::EvaluateFeatures( - wfc::IMap const features, - hstring const correlation_id) try { +winml::LearningModelEvaluationResult LearningModelSession::EvaluateFeatures( + wfc::IMap const features, hstring const correlation_id +) try { auto binding = CreateBinding(*this, features); return Evaluate(binding, correlation_id); } WINML_CATCH_ALL -wf::IAsyncOperation -LearningModelSession::EvaluateFeaturesAsync( - wfc::IMap const features, - hstring const correlation_id) { +wf::IAsyncOperation LearningModelSession::EvaluateFeaturesAsync( + wfc::IMap const features, hstring const correlation_id +) { auto binding = CreateBinding(*this, features); return EvaluateAsync(binding, correlation_id); } @@ -238,42 +231,39 @@ uint64_t LearningModelSession::Run(winrt::com_ptr auto& input_names = binding_impl->GetInputNames(); std::vector input_names_raw; - std::transform( - std::begin(input_names), - std::end(input_names), - std::back_inserter(input_names_raw), - [&](auto& name) { return name.c_str(); }); + std::transform(std::begin(input_names), std::end(input_names), std::back_inserter(input_names_raw), [&](auto& name) { + return name.c_str(); + }); auto& inputs = binding_impl->GetInputs(); std::vector<_winml::IValue*> inputs_raw; - std::transform( - std::begin(inputs), - std::end(inputs), - std::back_inserter(inputs_raw), - [&](auto& input) { return input.get(); }); + std::transform(std::begin(inputs), std::end(inputs), std::back_inserter(inputs_raw), [&](auto& input) { + return input.get(); + }); auto& output_names = binding_impl->GetOutputNames(); std::vector output_names_raw; std::transform( - std::begin(output_names), - std::end(output_names), - std::back_inserter(output_names_raw), - [&](auto& name) { return name.c_str(); }); + std::begin(output_names), + std::end(output_names), + std::back_inserter(output_names_raw), + [&](auto& name) { return name.c_str(); } + ); auto outputs = binding_impl->GetOutputs(); std::vector<_winml::IValue*> outputs_raw; - std::transform( - std::begin(outputs), - std::end(outputs), - std::back_inserter(outputs_raw), - [&](auto& input) { return input.get(); }); - - WINML_THROW_IF_FAILED(engine_->Run(input_names_raw.data(), - inputs_raw.data(), - input_names_raw.size(), - output_names_raw.data(), - outputs_raw.data(), - output_names_raw.size())); + std::transform(std::begin(outputs), std::end(outputs), std::back_inserter(outputs_raw), [&](auto& input) { + return input.get(); + }); + + WINML_THROW_IF_FAILED(engine_->Run( + input_names_raw.data(), + inputs_raw.data(), + input_names_raw.size(), + output_names_raw.data(), + outputs_raw.data(), + output_names_raw.size() + )); if (!device->IsCpuDevice()) { // Flush the D3D12 work from the DML execution provider and queue a fence before we release the lock. @@ -286,11 +276,11 @@ uint64_t LearningModelSession::Run(winrt::com_ptr return 0; } -winml::LearningModelEvaluationResult -LearningModelSession::GetResults( - winrt::com_ptr binding_impl, - hstring const& correlation_id, - uint64_t evaluation_complete_fence) { +winml::LearningModelEvaluationResult LearningModelSession::GetResults( + winrt::com_ptr binding_impl, + hstring const& correlation_id, + uint64_t evaluation_complete_fence +) { // First wait on the fence value for the expected frame. This is passed in so that // the fence value is added to the queue in a thread safe manor. auto device = device_.as(); @@ -328,10 +318,9 @@ LearningModelSession::GetResults( return result; } -wf::IAsyncOperation -LearningModelSession::EvaluateAsync( - winml::LearningModelBinding binding, - hstring const correlation_id) { +wf::IAsyncOperation LearningModelSession::EvaluateAsync( + winml::LearningModelBinding binding, hstring const correlation_id +) { _winmlt::TelemetryEvent kEvaluateModel_event(_winmlt::EventCategory::kEvaluation); auto device = device_.as(); @@ -375,10 +364,9 @@ LearningModelSession::EvaluateAsync( co_return GetResults(binding_impl, correlation_id, evaluation_complete_fence); } -winml::LearningModelEvaluationResult -LearningModelSession::Evaluate( - winml::LearningModelBinding binding, - hstring const& correlation_id) try { +winml::LearningModelEvaluationResult LearningModelSession::Evaluate( + winml::LearningModelBinding binding, hstring const& correlation_id +) try { ToggleProfiler(); _winmlt::TelemetryEvent kEvaluateModel_event(_winmlt::EventCategory::kEvaluation); @@ -424,11 +412,9 @@ WINML_CATCH_ALL void LearningModelSession::ToggleProfiler() { CheckClosed(); - auto is_provider_enabled = - TraceLoggingProviderEnabled( - ::winml_trace_logging_provider, - WINEVENT_LEVEL_VERBOSE, - WINML_PROVIDER_KEYWORD_LOTUS_PROFILING); + auto is_provider_enabled = TraceLoggingProviderEnabled( + ::winml_trace_logging_provider, WINEVENT_LEVEL_VERBOSE, WINML_PROVIDER_KEYWORD_LOTUS_PROFILING + ); if (is_provider_enabled) { engine_->StartProfiling(); @@ -437,8 +423,7 @@ void LearningModelSession::ToggleProfiler() { } } -_winml::IEngine* -LearningModelSession::GetEngine() { +_winml::IEngine* LearningModelSession::GetEngine() { return engine_.get(); } @@ -448,8 +433,7 @@ void LearningModelSession::CheckClosed() { } } -STDMETHODIMP LearningModelSession::GetIntraOpNumThreads(uint32_t* numThreads) -{ +STDMETHODIMP LearningModelSession::GetIntraOpNumThreads(uint32_t* numThreads) { return engine_->GetNumberOfIntraOpThreads(numThreads); } @@ -464,4 +448,4 @@ winml::LearningModelSession LearningModelSession::CreateInertSession(_winml::IEn return winrt::make(engine); } -} // namespace WINMLP \ No newline at end of file +} // namespace WINMLP diff --git a/winml/lib/Api/LearningModelSession.h b/winml/lib/Api/LearningModelSession.h index f41babdf277da..8c0beecc94674 100644 --- a/winml/lib/Api/LearningModelSession.h +++ b/winml/lib/Api/LearningModelSession.h @@ -13,57 +13,46 @@ namespace WINMLP { -struct LearningModelSession : LearningModelSessionT { +struct LearningModelSession + : LearningModelSessionT { /* LearningModelSession constructors (MachineLearningContract 1). */ LearningModelSession(_winml::IEngine* engine); - LearningModelSession( - winml::LearningModel const& model); + LearningModelSession(winml::LearningModel const& model); - LearningModelSession( - winml::LearningModel const& model, - winml::LearningModelDevice const& deviceToRunOn); + LearningModelSession(winml::LearningModel const& model, winml::LearningModelDevice const& deviceToRunOn); /* LearningModelSession constructors (MachineLearningContract 2). */ LearningModelSession( - winml::LearningModel const& model, - winml::LearningModelDevice const& deviceToRunOn, - winml::LearningModelSessionOptions const& sessionOptions); + winml::LearningModel const& model, + winml::LearningModelDevice const& deviceToRunOn, + winml::LearningModelSessionOptions const& sessionOptions + ); /* IClosable methods. */ - void - Close(); + void Close(); /* LearningModelSession properties (MachineLearningContract 1). */ - wfc::IPropertySet - EvaluationProperties(); + wfc::IPropertySet EvaluationProperties(); - winml::LearningModel - Model(); + winml::LearningModel Model(); - winml::LearningModelDevice - Device(); + winml::LearningModelDevice Device(); /* LearningModelSession methods (MachineLearningContract 1). */ - winml::LearningModelEvaluationResult - Evaluate( - winml::LearningModelBinding binding, - hstring const& correlationId); - - wf::IAsyncOperation - EvaluateAsync( - winml::LearningModelBinding binding, - hstring const correlationId); - - winml::LearningModelEvaluationResult - EvaluateFeatures( - wfc::IMap const features, - hstring const correlationId); - - wf::IAsyncOperation - EvaluateFeaturesAsync( - wfc::IMap const features, - hstring const correlationId); + winml::LearningModelEvaluationResult Evaluate(winml::LearningModelBinding binding, hstring const& correlationId); + + wf::IAsyncOperation EvaluateAsync( + winml::LearningModelBinding binding, hstring const correlationId + ); + + winml::LearningModelEvaluationResult EvaluateFeatures( + wfc::IMap const features, hstring const correlationId + ); + + wf::IAsyncOperation EvaluateFeaturesAsync( + wfc::IMap const features, hstring const correlationId + ); STDMETHOD(GetIntraOpNumThreads) (uint32_t* numThreads); @@ -74,46 +63,33 @@ struct LearningModelSession : LearningModelSessionT bindingImpl); + uint64_t Run(winrt::com_ptr bindingImpl); - winml::LearningModelEvaluationResult - GetResults( - winrt::com_ptr bindingImpl, - hstring const& correlationId, - uint64_t fenceValueForDML); + winml::LearningModelEvaluationResult GetResults( + winrt::com_ptr bindingImpl, hstring const& correlationId, uint64_t fenceValueForDML + ); - void - ApplyEvaluationProperties(); + void ApplyEvaluationProperties(); - void - ToggleProfiler(); + void ToggleProfiler(); private: com_ptr<_winml::IEngineFactory> engine_factory_; @@ -136,7 +112,6 @@ struct LearningModelSession : LearningModelSessionT { -}; +struct LearningModelSession : LearningModelSessionT {}; } // namespace WINML::factory_implementation diff --git a/winml/lib/Api/LearningModelSessionOptions.cpp b/winml/lib/Api/LearningModelSessionOptions.cpp index d5cc327d4e827..2ff9c6d1d56d0 100644 --- a/winml/lib/Api/LearningModelSessionOptions.cpp +++ b/winml/lib/Api/LearningModelSessionOptions.cpp @@ -5,8 +5,10 @@ #include "LearningModelSessionOptions.h" namespace WINMLP { -LearningModelSessionOptions::LearningModelSessionOptions(const LearningModelSessionOptions& options) : batch_size_override_(options.batch_size_override_), - close_model_on_session_creation_(options.close_model_on_session_creation_) {} +LearningModelSessionOptions::LearningModelSessionOptions(const LearningModelSessionOptions& options) + : batch_size_override_(options.batch_size_override_), + close_model_on_session_creation_(options.close_model_on_session_creation_) { +} uint32_t LearningModelSessionOptions::BatchSizeOverride() { return batch_size_override_; @@ -52,4 +54,13 @@ STDMETHODIMP LearningModelSessionOptions::SetIntraOpThreadSpinning(boolean allow telemetry_helper.SetIntraOpThreadSpinning(allowSpinning != 0); return S_OK; } + +const gsl::span LearningModelSessionOptions::GetCustomOpLibraryPaths() noexcept { + return custom_ops_lib_paths_; +} + +void LearningModelSessionOptions::RegisterCustomOpsLibrary(const winrt::hstring& path) noexcept { + custom_ops_lib_paths_.push_back(path); +} + } // namespace WINMLP diff --git a/winml/lib/Api/LearningModelSessionOptions.h b/winml/lib/Api/LearningModelSessionOptions.h index bfb1ad5ba48b5..5fc7e54997403 100644 --- a/winml/lib/Api/LearningModelSessionOptions.h +++ b/winml/lib/Api/LearningModelSessionOptions.h @@ -7,7 +7,10 @@ #include namespace WINMLP { -struct LearningModelSessionOptions : LearningModelSessionOptionsT { +struct LearningModelSessionOptions : LearningModelSessionOptionsT< + LearningModelSessionOptions, + ILearningModelSessionOptionsNative, + ILearningModelSessionOptionsNative1> { LearningModelSessionOptions() = default; LearningModelSessionOptions(const LearningModelSessionOptions& options); @@ -17,7 +20,7 @@ struct LearningModelSessionOptions : LearningModelSessionOptionsT NamedDimensionOverrides(); void OverrideNamedDimension(winrt::hstring name, uint32_t value); @@ -31,6 +34,10 @@ struct LearningModelSessionOptions : LearningModelSessionOptionsT GetCustomOpLibraryPaths() noexcept; + + void RegisterCustomOpsLibrary(const winrt::hstring& path) noexcept; + private: // The batch size override property is used to inform the engine when the developer // wants to explicitly set the batch size of a model to a fixed batch size. @@ -55,7 +62,7 @@ struct LearningModelSessionOptions : LearningModelSessionOptionsT custom_ops_lib_paths_; }; } // namespace WINMLP namespace WINML::factory_implementation { -struct LearningModelSessionOptions : LearningModelSessionOptionsT { -}; +struct LearningModelSessionOptions + : LearningModelSessionOptionsT {}; } // namespace WINML::factory_implementation diff --git a/winml/lib/Api/MapFeatureDescriptor.cpp b/winml/lib/Api/MapFeatureDescriptor.cpp index a3334ec0563c9..f1757d01de120 100644 --- a/winml/lib/Api/MapFeatureDescriptor.cpp +++ b/winml/lib/Api/MapFeatureDescriptor.cpp @@ -7,76 +7,55 @@ namespace WINMLP { MapFeatureDescriptor::MapFeatureDescriptor( - const char* name, - const char* description, - bool is_required, - winml::TensorKind key_kind, - winml::ILearningModelFeatureDescriptor value_kind) : name_(_winml::Strings::HStringFromUTF8(name)), - description_(_winml::Strings::HStringFromUTF8(description)), - is_required_(is_required), - key_kind_(key_kind), - value_kind_(value_kind) { -} - -winml::TensorKind -MapFeatureDescriptor::KeyKind() try { - return key_kind_; -} + const char* name, + const char* description, + bool is_required, + winml::TensorKind key_kind, + winml::ILearningModelFeatureDescriptor value_kind +) + : name_(_winml::Strings::HStringFromUTF8(name)), + description_(_winml::Strings::HStringFromUTF8(description)), + is_required_(is_required), + key_kind_(key_kind), + value_kind_(value_kind) { +} + +winml::TensorKind MapFeatureDescriptor::KeyKind() try { return key_kind_; } WINML_CATCH_ALL -winml::ILearningModelFeatureDescriptor -MapFeatureDescriptor::ValueDescriptor() try { - return value_kind_; -} +winml::ILearningModelFeatureDescriptor MapFeatureDescriptor::ValueDescriptor() try { return value_kind_; } WINML_CATCH_ALL -hstring -MapFeatureDescriptor::Name() try { - return name_; -} +hstring MapFeatureDescriptor::Name() try { return name_; } WINML_CATCH_ALL -hstring -MapFeatureDescriptor::Description() try { - return description_; -} +hstring MapFeatureDescriptor::Description() try { return description_; } WINML_CATCH_ALL -winml::LearningModelFeatureKind -MapFeatureDescriptor::Kind() try { - return LearningModelFeatureKind::Map; -} +winml::LearningModelFeatureKind MapFeatureDescriptor::Kind() try { return LearningModelFeatureKind::Map; } WINML_CATCH_ALL -bool MapFeatureDescriptor::IsRequired() try { - return is_required_; -} +bool MapFeatureDescriptor::IsRequired() try { return is_required_; } WINML_CATCH_ALL HRESULT -MapFeatureDescriptor::GetName( - const wchar_t** name, - uint32_t* cchName) { +MapFeatureDescriptor::GetName(const wchar_t** name, uint32_t* cchName) { *name = name_.data(); *cchName = static_cast(name_.size()); return S_OK; } HRESULT -MapFeatureDescriptor::GetDescription( - const wchar_t** description, - uint32_t* cchDescription) { +MapFeatureDescriptor::GetDescription(const wchar_t** description, uint32_t* cchDescription) { *description = description_.data(); *cchDescription = static_cast(description_.size()); return S_OK; } HRESULT -MapFeatureDescriptor::GetDescriptorInfo( - _winml::IEngineFactory* engine_factory, - _winml::IDescriptorInfo** info) { +MapFeatureDescriptor::GetDescriptorInfo(_winml::IEngineFactory* engine_factory, _winml::IDescriptorInfo** info) { engine_factory->CreateMapDescriptorInfo(info); return S_OK; } -} // namespace WINMLP \ No newline at end of file +} // namespace WINMLP diff --git a/winml/lib/Api/MapFeatureDescriptor.h b/winml/lib/Api/MapFeatureDescriptor.h index c214eca55740f..05b81aaa558bd 100644 --- a/winml/lib/Api/MapFeatureDescriptor.h +++ b/winml/lib/Api/MapFeatureDescriptor.h @@ -8,52 +8,41 @@ namespace WINMLP { struct MapFeatureDescriptor : MapFeatureDescriptorT< - MapFeatureDescriptor, - ILearningModelFeatureDescriptorNative, - _winml::IDescriptorInfoProvider> { + MapFeatureDescriptor, + ILearningModelFeatureDescriptorNative, + _winml::IDescriptorInfoProvider> { MapFeatureDescriptor() = delete; MapFeatureDescriptor( - const char* name, - const char* description, - bool is_required, - winml::TensorKind keyKind, - winml::ILearningModelFeatureDescriptor valueKind); - + const char* name, + const char* description, + bool is_required, + winml::TensorKind keyKind, + winml::ILearningModelFeatureDescriptor valueKind + ); + // IMapDescriptor - winml::TensorKind - KeyKind(); + winml::TensorKind KeyKind(); - winml::ILearningModelFeatureDescriptor - ValueDescriptor(); + winml::ILearningModelFeatureDescriptor ValueDescriptor(); // IFeatureDescriptor - hstring - Name(); + hstring Name(); - hstring - Description(); + hstring Description(); - winml::LearningModelFeatureKind - Kind(); + winml::LearningModelFeatureKind Kind(); - bool - IsRequired(); + bool IsRequired(); STDMETHOD(GetName) - ( - const wchar_t** name, - uint32_t* cchName) override; + (const wchar_t** name, uint32_t* cchName) override; STDMETHOD(GetDescription) - ( - const wchar_t** description, - uint32_t* cchDescription) override; - + (const wchar_t** description, uint32_t* cchDescription) override; + STDMETHOD(GetDescriptorInfo) - ( - _winml::IEngineFactory* engine_factory, - _winml::IDescriptorInfo** info) override; + (_winml::IEngineFactory* engine_factory, _winml::IDescriptorInfo** info) override; private: winrt::hstring name_; @@ -62,4 +51,4 @@ struct MapFeatureDescriptor : MapFeatureDescriptorT< winml::TensorKind key_kind_; winml::ILearningModelFeatureDescriptor value_kind_; }; -} // namespace WINMLP \ No newline at end of file +} // namespace WINMLP diff --git a/winml/lib/Api/NumericData.cpp b/winml/lib/Api/NumericData.cpp index 955c4195fedd4..ae5f9155d425c 100644 --- a/winml/lib/Api/NumericData.cpp +++ b/winml/lib/Api/NumericData.cpp @@ -11,37 +11,35 @@ namespace _winml { std::shared_ptr<_winml::idata> numeric_data::create( - size_t num_elements, - size_t element_size_in_bytes, - wfc::IIterable const& buffers) { + size_t num_elements, size_t element_size_in_bytes, wfc::IIterable const& buffers +) { return std::make_shared(num_elements, element_size_in_bytes, buffers); } numeric_data::numeric_data( - size_t num_elements, size_t element_size_in_bytes, wfc::IIterable const& buffers) : - combined_buffer_(nullptr), - buffers_(), - num_elements_(num_elements), - element_size_in_bytes_(element_size_in_bytes) { + size_t num_elements, size_t element_size_in_bytes, wfc::IIterable const& buffers +) + : combined_buffer_(nullptr), + buffers_(), + num_elements_(num_elements), + element_size_in_bytes_(element_size_in_bytes) { if (buffers != nullptr) { - buffers_ = { begin(buffers), end(buffers) }; + buffers_ = {begin(buffers), end(buffers)}; } - + if (buffers_.size() == 0) { combined_buffer_ = winrt::make(num_elements * element_size_in_bytes); - buffers_ = { combined_buffer_ }; + buffers_ = {combined_buffer_}; auto buffer = buffer_at(0); - + // The initial release of WinML (RS5) shipped with behavior that would // zero-initialize uninitialized tensors. After measuring, the performance impact // of memsetting the memory buffer is quite small (<1ms for 3channel 720x720 TensorFloats). // To maintain parity with RS5 behavior, we always zero out the memory buffer. memset(buffer.data(), 0, buffer.size_bytes()); - } - else if (buffers_.size() == 1) { + } else if (buffers_.size() == 1) { combined_buffer_ = buffers_[0]; - } - else { + } else { // If there are many buffers, then the combined buffer will be a separately allocated value that combines all of the buffers. // This needs to be lazily done however, as the extra memory should not be allocated when not needed (GPU). } @@ -71,9 +69,8 @@ gsl::span numeric_data::buffer(bool should_sync_buffer) { auto span = combined_buffer(); if (should_sync_buffer) { _winml::LoadSpanFromDisjointBuffers( - buffers_.size(), - [this](size_t i) { return buffer_at(i); }, - span); + buffers_.size(), [this](size_t i) { return buffer_at(i); }, span + ); } return span; @@ -84,35 +81,32 @@ bool numeric_data::flush() { if (should_flush) { auto span = combined_buffer(); _winml::StoreSpanIntoDisjointBuffers( - buffers_.size(), - [this](size_t i) { return buffer_at(i); }, - span); + buffers_.size(), [this](size_t i) { return buffer_at(i); }, span + ); } return should_flush; } void numeric_data::set(size_t data_size, const byte* data) { WINML_THROW_HR_IF_FALSE_MSG( - E_INVALIDARG, - data_size <= (num_elements_ * element_size_in_bytes_), - "Argument size (%llu) exceeds the tensor size (%llu).", - static_cast(data_size), - static_cast(num_elements_ * element_size_in_bytes_)); - + E_INVALIDARG, + data_size <= (num_elements_ * element_size_in_bytes_), + "Argument size (%llu) exceeds the tensor size (%llu).", + static_cast(data_size), + static_cast(num_elements_ * element_size_in_bytes_) + ); + gsl::span span(const_cast(data), data_size); _winml::StoreSpanIntoDisjointBuffers( - buffers_.size(), - [this](size_t i) { return buffer_at(i); }, - span); + buffers_.size(), [this](size_t i) { return buffer_at(i); }, span + ); } static gsl::span get_span_from_ibuffer(wss::IBuffer buffer) { byte* current_data = nullptr; auto bufferByteAccess = buffer.as(); bufferByteAccess->Buffer(¤t_data); - return gsl::span( - current_data, - static_cast(buffer.Capacity())); + return gsl::span(current_data, static_cast(buffer.Capacity())); } gsl::span numeric_data::buffer_at(size_t index) { @@ -126,4 +120,4 @@ gsl::span numeric_data::combined_buffer() { return get_span_from_ibuffer(combined_buffer_); } -} // namespace _winml \ No newline at end of file +} // namespace _winml diff --git a/winml/lib/Api/SequenceFeatureDescriptor.cpp b/winml/lib/Api/SequenceFeatureDescriptor.cpp index c4a4456e1c5f6..1e28cd4c18ba4 100644 --- a/winml/lib/Api/SequenceFeatureDescriptor.cpp +++ b/winml/lib/Api/SequenceFeatureDescriptor.cpp @@ -7,69 +7,49 @@ namespace WINMLP { SequenceFeatureDescriptor::SequenceFeatureDescriptor( - const char* name, - const char* description, - bool is_required, - winml::ILearningModelFeatureDescriptor descriptor) : name_(_winml::Strings::HStringFromUTF8(name)), - description_(_winml::Strings::HStringFromUTF8(description)), - is_required_(is_required), - element_descriptor_(descriptor) {} - + const char* name, const char* description, bool is_required, winml::ILearningModelFeatureDescriptor descriptor +) + : name_(_winml::Strings::HStringFromUTF8(name)), + description_(_winml::Strings::HStringFromUTF8(description)), + is_required_(is_required), + element_descriptor_(descriptor) { +} -winml::ILearningModelFeatureDescriptor -SequenceFeatureDescriptor::ElementDescriptor() try { +winml::ILearningModelFeatureDescriptor SequenceFeatureDescriptor::ElementDescriptor() try { return element_descriptor_; } WINML_CATCH_ALL -hstring -SequenceFeatureDescriptor::Name() try { - return name_; -} +hstring SequenceFeatureDescriptor::Name() try { return name_; } WINML_CATCH_ALL -hstring -SequenceFeatureDescriptor::Description() try { - return description_; -} +hstring SequenceFeatureDescriptor::Description() try { return description_; } WINML_CATCH_ALL -winml::LearningModelFeatureKind -SequenceFeatureDescriptor::Kind() try { - return LearningModelFeatureKind::Sequence; -} +winml::LearningModelFeatureKind SequenceFeatureDescriptor::Kind() try { return LearningModelFeatureKind::Sequence; } WINML_CATCH_ALL -bool SequenceFeatureDescriptor::IsRequired() try { - return is_required_; -} +bool SequenceFeatureDescriptor::IsRequired() try { return is_required_; } WINML_CATCH_ALL HRESULT -SequenceFeatureDescriptor::GetName( - const wchar_t** name, - uint32_t* cchName) { +SequenceFeatureDescriptor::GetName(const wchar_t** name, uint32_t* cchName) { *name = name_.data(); *cchName = static_cast(name_.size()); return S_OK; } HRESULT -SequenceFeatureDescriptor::GetDescription( - const wchar_t** description, - uint32_t* cchDescription) { +SequenceFeatureDescriptor::GetDescription(const wchar_t** description, uint32_t* cchDescription) { *description = description_.data(); *cchDescription = static_cast(description_.size()); return S_OK; } HRESULT -SequenceFeatureDescriptor::GetDescriptorInfo( - _winml::IEngineFactory* engine_factory, - _winml::IDescriptorInfo** info) { +SequenceFeatureDescriptor::GetDescriptorInfo(_winml::IEngineFactory* engine_factory, _winml::IDescriptorInfo** info) { engine_factory->CreateSequenceDescriptorInfo(info); return S_OK; }; - -} // namespace WINMLP \ No newline at end of file +} // namespace WINMLP diff --git a/winml/lib/Api/SequenceFeatureDescriptor.h b/winml/lib/Api/SequenceFeatureDescriptor.h index cc4ad8c52f1de..e14b6af54a574 100644 --- a/winml/lib/Api/SequenceFeatureDescriptor.h +++ b/winml/lib/Api/SequenceFeatureDescriptor.h @@ -8,50 +8,41 @@ namespace WINMLP { struct SequenceFeatureDescriptor : SequenceFeatureDescriptorT< - SequenceFeatureDescriptor, - ILearningModelFeatureDescriptorNative, - _winml::IDescriptorInfoProvider> { + SequenceFeatureDescriptor, + ILearningModelFeatureDescriptorNative, + _winml::IDescriptorInfoProvider> { SequenceFeatureDescriptor() = delete; SequenceFeatureDescriptor( - const char* name, - const char* description, - bool is_required, - winml::ILearningModelFeatureDescriptor element_descriptor); + const char* name, + const char* description, + bool is_required, + winml::ILearningModelFeatureDescriptor element_descriptor + ); - winml::ILearningModelFeatureDescriptor - ElementDescriptor(); + winml::ILearningModelFeatureDescriptor ElementDescriptor(); // IFeatureDescriptor - hstring - Name(); + hstring Name(); - hstring - Description(); + hstring Description(); - winml::LearningModelFeatureKind - Kind(); + winml::LearningModelFeatureKind Kind(); - bool - IsRequired(); + bool IsRequired(); STDMETHOD(GetName) - ( - const wchar_t** name, - uint32_t* cchName) override; + (const wchar_t** name, uint32_t* cchName) override; STDMETHOD(GetDescription) - ( - const wchar_t** description, - uint32_t* cchDescription) override; + (const wchar_t** description, uint32_t* cchDescription) override; STDMETHOD(GetDescriptorInfo) - ( - _winml::IEngineFactory* engine_factory, - _winml::IDescriptorInfo** info) override; + (_winml::IEngineFactory* engine_factory, _winml::IDescriptorInfo** info) override; + private: winrt::hstring name_; winrt::hstring description_; bool is_required_; winml::ILearningModelFeatureDescriptor element_descriptor_; }; -} // namespace WINMLP \ No newline at end of file +} // namespace WINMLP diff --git a/winml/lib/Api/StringData.cpp b/winml/lib/Api/StringData.cpp index cbca428cb6890..73a65bd36eb04 100644 --- a/winml/lib/Api/StringData.cpp +++ b/winml/lib/Api/StringData.cpp @@ -7,8 +7,8 @@ namespace _winml { -string_data::string_data(size_t size) : - buffer_(size) {} +string_data::string_data(size_t size) : buffer_(size) { +} std::shared_ptr<_winml::idata> string_data::create(size_t size) { return std::make_shared(size); @@ -41,11 +41,12 @@ gsl::span string_data::buffer(bool /*should_sync_buffer*/) { void string_data::set(size_t num_elements, const std::string_view* data) { WINML_THROW_HR_IF_FALSE_MSG( - E_INVALIDARG, - num_elements <= buffer_.size(), - "Argument size (%d) exceeds the tensor size (%d).", - static_cast(num_elements), - static_cast(buffer_.size())); + E_INVALIDARG, + num_elements <= buffer_.size(), + "Argument size (%d) exceeds the tensor size (%d).", + static_cast(num_elements), + static_cast(buffer_.size()) + ); // Copy std::copy(data, data + num_elements, buffer_.begin()); @@ -59,4 +60,4 @@ std::vector& string_data::get_backing_vector() { return buffer_; } -} // namespace _winml \ No newline at end of file +} // namespace _winml diff --git a/winml/lib/Api/TensorFeatureDescriptor.cpp b/winml/lib/Api/TensorFeatureDescriptor.cpp index 3dcffa63991f5..a8b57de276981 100644 --- a/winml/lib/Api/TensorFeatureDescriptor.cpp +++ b/winml/lib/Api/TensorFeatureDescriptor.cpp @@ -9,98 +9,73 @@ namespace WINMLP { TensorFeatureDescriptor::TensorFeatureDescriptor( - const char* name, - const char* description, - winml::TensorKind tensor_kind, - const std::vector& shape, - bool is_required, - bool has_unsupported_image_metadata) : name_(_winml::Strings::HStringFromUTF8(name)), - description_(_winml::Strings::HStringFromUTF8(description)), - tensor_kind_(tensor_kind), - shape_(shape), - is_required_(is_required), - has_unsupported_image_metadata_(has_unsupported_image_metadata) { + const char* name, + const char* description, + winml::TensorKind tensor_kind, + const std::vector& shape, + bool is_required, + bool has_unsupported_image_metadata +) + : name_(_winml::Strings::HStringFromUTF8(name)), + description_(_winml::Strings::HStringFromUTF8(description)), + tensor_kind_(tensor_kind), + shape_(shape), + is_required_(is_required), + has_unsupported_image_metadata_(has_unsupported_image_metadata) { } TensorFeatureDescriptor::TensorFeatureDescriptor( - hstring const& name, - hstring const& description, - winml::TensorKind const& kind, - array_view shape) : name_(name), - description_(description), - tensor_kind_(kind), - shape_(shape.begin(), shape.end()), - is_required_(true), - has_unsupported_image_metadata_(false) { + hstring const& name, hstring const& description, winml::TensorKind const& kind, array_view shape +) + : name_(name), + description_(description), + tensor_kind_(kind), + shape_(shape.begin(), shape.end()), + is_required_(true), + has_unsupported_image_metadata_(false) { } -winml::TensorKind -TensorFeatureDescriptor::TensorKind() try { - return tensor_kind_; -} +winml::TensorKind TensorFeatureDescriptor::TensorKind() try { return tensor_kind_; } WINML_CATCH_ALL -wfc::IVectorView -TensorFeatureDescriptor::Shape() try { - return winrt::single_threaded_vector( - std::vector( - std::begin(shape_), - std::end(shape_))) - .GetView(); +wfc::IVectorView TensorFeatureDescriptor::Shape() try { + return winrt::single_threaded_vector(std::vector(std::begin(shape_), std::end(shape_))).GetView(); } WINML_CATCH_ALL -winrt::hstring -TensorFeatureDescriptor::Name() try { - return name_; -} +winrt::hstring TensorFeatureDescriptor::Name() try { return name_; } WINML_CATCH_ALL -winrt::hstring -TensorFeatureDescriptor::Description() try { - return description_; -} +winrt::hstring TensorFeatureDescriptor::Description() try { return description_; } WINML_CATCH_ALL -winml::LearningModelFeatureKind -TensorFeatureDescriptor::Kind() try { - return LearningModelFeatureKind::Tensor; -} +winml::LearningModelFeatureKind TensorFeatureDescriptor::Kind() try { return LearningModelFeatureKind::Tensor; } WINML_CATCH_ALL -bool TensorFeatureDescriptor::IsRequired() try { - return is_required_; -} +bool TensorFeatureDescriptor::IsRequired() try { return is_required_; } WINML_CATCH_ALL -bool TensorFeatureDescriptor::IsUnsupportedMetaData() try { - return has_unsupported_image_metadata_; -} +bool TensorFeatureDescriptor::IsUnsupportedMetaData() try { return has_unsupported_image_metadata_; } WINML_CATCH_ALL HRESULT -TensorFeatureDescriptor::GetName( - const wchar_t** name, - uint32_t* cchName) { +TensorFeatureDescriptor::GetName(const wchar_t** name, uint32_t* cchName) { *name = name_.data(); *cchName = static_cast(name_.size()); return S_OK; } HRESULT -TensorFeatureDescriptor::GetDescription( - const wchar_t** description, - uint32_t* cchDescription) { +TensorFeatureDescriptor::GetDescription(const wchar_t** description, uint32_t* cchDescription) { *description = description_.data(); *cchDescription = static_cast(description_.size()); return S_OK; } -HRESULT TensorFeatureDescriptor::GetDescriptorInfo( - _winml::IEngineFactory* engine_factory, - _winml::IDescriptorInfo** info){ +HRESULT +TensorFeatureDescriptor::GetDescriptorInfo(_winml::IEngineFactory* engine_factory, _winml::IDescriptorInfo** info) { engine_factory->CreateTensorDescriptorInfo(tensor_kind_, shape_.data(), shape_.size(), info); return S_OK; }; -} // namespace WINMLP \ No newline at end of file +} // namespace WINMLP diff --git a/winml/lib/Api/TensorFeatureDescriptor.h b/winml/lib/Api/TensorFeatureDescriptor.h index 4357ffe3dbc6a..7dc17dc9e264b 100644 --- a/winml/lib/Api/TensorFeatureDescriptor.h +++ b/winml/lib/Api/TensorFeatureDescriptor.h @@ -8,62 +8,47 @@ namespace WINMLP { struct TensorFeatureDescriptor : TensorFeatureDescriptorT< - TensorFeatureDescriptor, - ILearningModelFeatureDescriptorNative, - _winml::IDescriptorInfoProvider> { + TensorFeatureDescriptor, + ILearningModelFeatureDescriptorNative, + _winml::IDescriptorInfoProvider> { TensorFeatureDescriptor() = delete; TensorFeatureDescriptor( - const char* name, - const char* description, - winml::TensorKind tensor_kind, - const std::vector& shape, - bool is_required, - bool has_unsuppored_image_metadata); - + const char* name, + const char* description, + winml::TensorKind tensor_kind, + const std::vector& shape, + bool is_required, + bool has_unsuppored_image_metadata + ); + TensorFeatureDescriptor( - hstring const& name, - hstring const& description, - winml::TensorKind const& kind, - array_view shape); + hstring const& name, hstring const& description, winml::TensorKind const& kind, array_view shape + ); // ITensorDescriptor - winml::TensorKind - TensorKind(); + winml::TensorKind TensorKind(); - wfc::IVectorView - Shape(); + wfc::IVectorView Shape(); // IFeatureDescriptor - winrt::hstring - Name(); + winrt::hstring Name(); - winrt::hstring - Description(); + winrt::hstring Description(); - winml::LearningModelFeatureKind - Kind(); + winml::LearningModelFeatureKind Kind(); - bool - IsRequired(); + bool IsRequired(); - bool - IsUnsupportedMetaData(); + bool IsUnsupportedMetaData(); STDMETHOD(GetName) - ( - const wchar_t** name, - uint32_t* cchName) override; + (const wchar_t** name, uint32_t* cchName) override; STDMETHOD(GetDescription) - ( - const wchar_t** description, - uint32_t* cchDescription) override; + (const wchar_t** description, uint32_t* cchDescription) override; - STDMETHOD(GetDescriptorInfo) - ( - _winml::IEngineFactory* engine_factory, - _winml::IDescriptorInfo** info) override; + (_winml::IEngineFactory* engine_factory, _winml::IDescriptorInfo** info) override; private: winrt::hstring name_; @@ -73,4 +58,4 @@ struct TensorFeatureDescriptor : TensorFeatureDescriptorT< bool is_required_; bool has_unsupported_image_metadata_; }; -} // WINMLP \ No newline at end of file +} // namespace WINMLP diff --git a/winml/lib/Api/VectorBackedBuffer.cpp b/winml/lib/Api/VectorBackedBuffer.cpp index da2b6a2de4898..7608dc2c4f574 100644 --- a/winml/lib/Api/VectorBackedBuffer.cpp +++ b/winml/lib/Api/VectorBackedBuffer.cpp @@ -6,7 +6,8 @@ namespace _winml { -vector_backed_buffer::vector_backed_buffer(size_t size) : buffer_(size) {} +vector_backed_buffer::vector_backed_buffer(size_t size) : buffer_(size) { +} uint32_t vector_backed_buffer::Capacity() const { return static_cast(buffer_.size()); @@ -26,4 +27,4 @@ STDMETHODIMP vector_backed_buffer::Buffer(uint8_t** value) { return S_OK; } -} // namespace _winml \ No newline at end of file +} // namespace _winml diff --git a/winml/lib/Api/VectorBackedBuffer.h b/winml/lib/Api/VectorBackedBuffer.h index a12b26ffd719f..9407ee301b6f8 100644 --- a/winml/lib/Api/VectorBackedBuffer.h +++ b/winml/lib/Api/VectorBackedBuffer.h @@ -8,10 +8,8 @@ namespace _winml { -class vector_backed_buffer : public winrt::implements< - vector_backed_buffer, - wss::IBuffer, - Windows::Storage::Streams::IBufferByteAccess> { +class vector_backed_buffer + : public winrt::implements { public: vector_backed_buffer(size_t size); @@ -25,4 +23,4 @@ class vector_backed_buffer : public winrt::implements< std::vector buffer_; }; -} // namespace _winml \ No newline at end of file +} // namespace _winml diff --git a/winml/lib/Api/impl/FeatureCompatibility.h b/winml/lib/Api/impl/FeatureCompatibility.h index 014fe1c9b9a4a..3fff488be23f7 100644 --- a/winml/lib/Api/impl/FeatureCompatibility.h +++ b/winml/lib/Api/impl/FeatureCompatibility.h @@ -15,24 +15,23 @@ namespace _winml { namespace error_strings { // This must be kept in sync with the TensorKind enum in Windows.AI.MachineLearning.idl -__declspec(selectany) const char* SzTensorKind[] = - { - "Undefined", - "Float", - "UInt8", - "Int8", - "UInt16", - "Int16", - "Int32", - "Int64", - "String", - "Boolean", - "Float16", - "Double", - "UInt32", - "UInt64", - "Complex64", - "Complex128", +__declspec(selectany) const char* SzTensorKind[] = { + "Undefined", + "Float", + "UInt8", + "Int8", + "UInt16", + "Int16", + "Int32", + "Int64", + "String", + "Boolean", + "Float16", + "Double", + "UInt32", + "UInt64", + "Complex64", + "Complex128", }; static std::string ToString(winml::ILearningModelFeatureDescriptor descriptor); @@ -51,9 +50,7 @@ static std::string ToString(wfc::IVectorView shape) { return ToString(shapeVec); } -static std::string ToString( - winml::TensorKind kind, - wfc::IVectorView shape) { +static std::string ToString(winml::TensorKind kind, wfc::IVectorView shape) { // Any unrecognized data type is considered "Undefined". if (static_cast(kind) >= std::size(SzTensorKind)) { kind = winml::TensorKind::Undefined; @@ -176,16 +173,18 @@ namespace compatibility_details { using K = winml::LearningModelFeatureKind; -static void not_compatible_hr(HRESULT hr, winml::ILearningModelFeatureValue value, - winml::ILearningModelFeatureDescriptor descriptor) { +static void not_compatible_hr( + HRESULT hr, winml::ILearningModelFeatureValue value, winml::ILearningModelFeatureDescriptor descriptor +) { auto name = _winml::Strings::UTF8FromHString(descriptor.Name()); WINML_THROW_IF_FAILED_MSG( - hr, - "Model variable %s, expects %s, but binding was attempted with an incompatible type %s.", - name.c_str(), - error_strings::ToString(descriptor).c_str(), - error_strings::ToString(value).c_str()); + hr, + "Model variable %s, expects %s, but binding was attempted with an incompatible type %s.", + name.c_str(), + error_strings::ToString(descriptor).c_str(), + error_strings::ToString(value).c_str() + ); } static void not_compatible(winml::ILearningModelFeatureValue value, winml::ILearningModelFeatureDescriptor descriptor) { @@ -231,8 +230,8 @@ void verify(winml::ILearningModelFeatureValue value, winml::ILearningModelFeatur template <> void verify( - winml::ILearningModelFeatureValue value, - winml::ILearningModelFeatureDescriptor descriptor) { + winml::ILearningModelFeatureValue value, winml::ILearningModelFeatureDescriptor descriptor +) { thrower fail = std::bind(not_compatible_hr, std::placeholders::_1, value, descriptor); enforce check = std::bind(enforce_not_false, std::placeholders::_1, std::placeholders::_2, fail); @@ -262,8 +261,8 @@ void verify( template <> void verify( - winml::ILearningModelFeatureValue value, - winml::ILearningModelFeatureDescriptor descriptor) { + winml::ILearningModelFeatureValue value, winml::ILearningModelFeatureDescriptor descriptor +) { thrower fail = std::bind(not_compatible_hr, std::placeholders::_1, value, descriptor); enforce check = std::bind(enforce_not_false, std::placeholders::_1, std::placeholders::_2, fail); enforce_succeeded check_succeeded = std::bind(enforce_not_failed, std::placeholders::_1, fail); @@ -283,8 +282,8 @@ void verify( template <> void verify( - winml::ILearningModelFeatureValue value, - winml::ILearningModelFeatureDescriptor descriptor) { + winml::ILearningModelFeatureValue value, winml::ILearningModelFeatureDescriptor descriptor +) { thrower fail = std::bind(not_compatible_hr, std::placeholders::_1, value, descriptor); enforce_succeeded check_succeeded = std::bind(enforce_not_failed, std::placeholders::_1, fail); @@ -299,8 +298,8 @@ void verify( template <> void verify( - winml::ILearningModelFeatureValue value, - winml::ILearningModelFeatureDescriptor descriptor) { + winml::ILearningModelFeatureValue value, winml::ILearningModelFeatureDescriptor descriptor +) { // No check is needed here. Because: // For batchSize==1, no matter what shape the input has (smaller or larger), we support to bind it. // For batchSize > 1, @@ -313,8 +312,8 @@ void verify( template <> void verify( - winml::ILearningModelFeatureValue value, - winml::ILearningModelFeatureDescriptor descriptor) { + winml::ILearningModelFeatureValue value, winml::ILearningModelFeatureDescriptor descriptor +) { thrower fail = std::bind(not_compatible_hr, std::placeholders::_1, value, descriptor); enforce check = std::bind(enforce_not_false, std::placeholders::_1, std::placeholders::_2, fail); enforce_succeeded check_succeeded = std::bind(enforce_not_failed, std::placeholders::_1, fail); @@ -357,8 +356,8 @@ void verify( */ template <> void verify( - winml::ILearningModelFeatureValue value, - winml::ILearningModelFeatureDescriptor descriptor) { + winml::ILearningModelFeatureValue value, winml::ILearningModelFeatureDescriptor descriptor +) { thrower fail = std::bind(not_compatible_hr, std::placeholders::_1, value, descriptor); enforce check = std::bind(enforce_not_false, std::placeholders::_1, std::placeholders::_2, fail); @@ -371,23 +370,27 @@ void verify( check(WINML_ERR_SIZE_MISMATCH, 4 == tensorDescriptorShape.Size()); } -static void (*FeatureKindCompatibilityMatrix[4][4])(winml::ILearningModelFeatureValue, winml::ILearningModelFeatureDescriptor) = - { - // Tensor, Sequence, Map, Image - /* Tensor */ {verify, not_compatible, not_compatible, verify}, - /* Sequence */ {not_compatible, verify, not_compatible, not_compatible}, - /* Map */ {not_compatible, not_compatible, verify, not_compatible}, - /* Image */ {verify, not_compatible, not_compatible, verify}}; +static void (*FeatureKindCompatibilityMatrix[4][4])( + winml::ILearningModelFeatureValue, winml::ILearningModelFeatureDescriptor +) = { + // Tensor, Sequence, Map, Image + /* Tensor */ {verify, not_compatible, not_compatible, verify}, + /* Sequence */ + {not_compatible, verify, not_compatible, not_compatible}, + /* Map */ + {not_compatible, not_compatible, verify, not_compatible}, + /* Image */ + {verify, not_compatible, not_compatible, verify} +}; } // namespace compatibility_details inline void VerifyFeatureValueCompatibleWithDescriptor( - winml::ILearningModelFeatureValue value, - winml::ILearningModelFeatureDescriptor descriptor) { + winml::ILearningModelFeatureValue value, winml::ILearningModelFeatureDescriptor descriptor +) { using namespace compatibility_details; auto pfnAreKindsCompatible = - FeatureKindCompatibilityMatrix - [static_cast(value.Kind())][static_cast(descriptor.Kind())]; + FeatureKindCompatibilityMatrix[static_cast(value.Kind())][static_cast(descriptor.Kind())]; pfnAreKindsCompatible(value, descriptor); } diff --git a/winml/lib/Api/impl/IData.h b/winml/lib/Api/impl/IData.h index 0615e5fe50308..555b74b8bf74b 100644 --- a/winml/lib/Api/impl/IData.h +++ b/winml/lib/Api/impl/IData.h @@ -8,8 +8,8 @@ namespace _winml { struct idata { - virtual ~idata(){} - + virtual ~idata() {} + virtual size_t num_elements() = 0; virtual size_t size_in_bytes() = 0; virtual size_t num_buffers() = 0; @@ -19,4 +19,4 @@ struct idata { virtual void set(size_t data_size, const byte* data) = 0; }; -} // namespace _winml \ No newline at end of file +} // namespace _winml diff --git a/winml/lib/Api/impl/IMapFeatureValue.h b/winml/lib/Api/impl/IMapFeatureValue.h index 05d8cbfd45cf4..816bb90668cf4 100644 --- a/winml/lib/Api/impl/IMapFeatureValue.h +++ b/winml/lib/Api/impl/IMapFeatureValue.h @@ -5,15 +5,17 @@ namespace _winml { +// clang-format off /* [uuid("3e4d4350-0b61-4517-aa6d-79d49bf164b4"), feature, contract, object, exclusiveto] */ MIDL_INTERFACE("3e4d4350-0b61-4517-aa6d-79d49bf164b4") IMapFeatureValue : public ::IUnknown { public: /* [propget] */ virtual HRESULT STDMETHODCALLTYPE get_KeyKind( - /* [out, retval] */ winml::TensorKind * kind) = 0; + /* [out, retval] */ winml::TensorKind* kind) = 0; /* [propget] */ virtual HRESULT STDMETHODCALLTYPE get_ValueDescriptor( - /* [out, retval] */ winml::ILearningModelFeatureDescriptor * result) = 0; + /* [out, retval] */ winml::ILearningModelFeatureDescriptor* result) = 0; }; +// clang-format on -} // namespace _winml \ No newline at end of file +} // namespace _winml diff --git a/winml/lib/Api/impl/ISequenceFeatureValue.h b/winml/lib/Api/impl/ISequenceFeatureValue.h index 237bf0c5dae20..2cc995ae8234d 100644 --- a/winml/lib/Api/impl/ISequenceFeatureValue.h +++ b/winml/lib/Api/impl/ISequenceFeatureValue.h @@ -5,12 +5,14 @@ namespace _winml { +// clang-format off /* [uuid("529d0bca-4c6c-48c1-9bd3-e1ea2e816348"), feature, contract, object, exclusiveto] */ MIDL_INTERFACE("529d0bca-4c6c-48c1-9bd3-e1ea2e816348") ISequenceFeatureValue : public ::IUnknown { public: /* [propget] */ virtual HRESULT STDMETHODCALLTYPE get_ElementDescriptor( - /* [out, retval] */ winml::ILearningModelFeatureDescriptor * result) = 0; + /* [out, retval] */ winml::ILearningModelFeatureDescriptor* result) = 0; }; +// clang-format on -} // namespace _winml \ No newline at end of file +} // namespace _winml diff --git a/winml/lib/Api/impl/MapBase.h b/winml/lib/Api/impl/MapBase.h index ac689639a5687..4686d8a05ad9b 100644 --- a/winml/lib/Api/impl/MapBase.h +++ b/winml/lib/Api/impl/MapBase.h @@ -19,26 +19,22 @@ namespace _winml { // , , , // , , , // -template < - typename TDerived, - typename TKey, - typename TValue> +template struct MapBase : winrt::implements< - MapBase, - winml::ILearningModelFeatureValue, - _winml::IMapFeatureValue, - _winml::ILotusValueProviderPrivate> { + MapBase, + winml::ILearningModelFeatureValue, + _winml::IMapFeatureValue, + _winml::ILotusValueProviderPrivate> { static_assert( - std::is_same::value || - std::is_same::value, - "Map keys must be int64_t or winrt::hstring!"); + std::is_same::value || std::is_same::value, + "Map keys must be int64_t or winrt::hstring!" + ); static_assert( - std::is_same::value || - std::is_same::value || - std::is_same::value || - std::is_same::value, - "Map values must be int64_t, double, float, or winrt::hstring!"); + std::is_same::value || std::is_same::value || std::is_same::value || + std::is_same::value, + "Map values must be int64_t, double, float, or winrt::hstring!" + ); using ABIMap = wfc::IMap; using ABIMapView = wfc::IMapView; @@ -50,9 +46,7 @@ struct MapBase : winrt::implements< return winrt::make(abiMap); } - static winml::ILearningModelFeatureValue Create(const ABIMap& data) { - return winrt::make(data); - } + static winml::ILearningModelFeatureValue Create(const ABIMap& data) { return winrt::make(data); } static winml::ILearningModelFeatureValue Create(const ABIMapView& data) { auto abiMap = winrt::single_threaded_map(); @@ -65,9 +59,7 @@ struct MapBase : winrt::implements< return winrt::make(abiMap); } // ILearningModelFeatureValue implementation - winml::LearningModelFeatureKind Kind() { - return winml::LearningModelFeatureKind::Map; - } + winml::LearningModelFeatureKind Kind() { return winml::LearningModelFeatureKind::Map; } STDMETHOD(get_KeyKind) (winml::TensorKind* kind) { @@ -91,7 +83,12 @@ struct MapBase : winrt::implements< auto engine = session->GetEngine(); if (context.type == _winml::BindingType::kInput) { - RETURN_IF_FAILED(engine->CreateMapValue(reinterpret_cast<::IInspectable*>(winrt::get_abi(data_)), TensorKindFrom::Type, TensorKindFrom::Type, out)); + RETURN_IF_FAILED(engine->CreateMapValue( + reinterpret_cast<::IInspectable*>(winrt::get_abi(data_)), + TensorKindFrom::Type, + TensorKindFrom::Type, + out + )); } else { RETURN_IF_FAILED(engine->CreateNullValue(out)); } @@ -110,13 +107,17 @@ struct MapBase : winrt::implements< data_.Clear(); auto session = context.session.as(); auto engine = session->GetEngine(); - RETURN_IF_FAILED(engine->FillFromMapValue(reinterpret_cast<::IInspectable*>(winrt::get_abi(data_)), TensorKindFrom::Type, TensorKindFrom::Type, value)); + RETURN_IF_FAILED(engine->FillFromMapValue( + reinterpret_cast<::IInspectable*>(winrt::get_abi(data_)), + TensorKindFrom::Type, + TensorKindFrom::Type, + value + )); return S_OK; } STDMETHOD(AbiRepresentation) - ( - wf::IInspectable& abiRepresentation) { + (wf::IInspectable& abiRepresentation) { data_.as(abiRepresentation); return S_OK; } diff --git a/winml/lib/Api/impl/NumericData.h b/winml/lib/Api/impl/NumericData.h index 1921c2f422d2c..71c61b3c29f6f 100644 --- a/winml/lib/Api/impl/NumericData.h +++ b/winml/lib/Api/impl/NumericData.h @@ -12,9 +12,8 @@ namespace _winml { class numeric_data : public _winml::idata { public: static std::shared_ptr<_winml::idata> create( - size_t num_elements, - size_t element_size_in_bytes, - wfc::IIterable const& buffers); + size_t num_elements, size_t element_size_in_bytes, wfc::IIterable const& buffers + ); // Privte constructor as this type should be created as a shared_ptr numeric_data(size_t num_elements, size_t element_size_in_bytes, wfc::IIterable const& buffers); @@ -43,4 +42,4 @@ class numeric_data : public _winml::idata { size_t element_size_in_bytes_; }; -} // namespace _winml \ No newline at end of file +} // namespace _winml diff --git a/winml/lib/Api/impl/SequenceBase.h b/winml/lib/Api/impl/SequenceBase.h index fe5aee937d950..82ac6a439dae0 100644 --- a/winml/lib/Api/impl/SequenceBase.h +++ b/winml/lib/Api/impl/SequenceBase.h @@ -18,108 +18,84 @@ namespace _winml { // template struct SequenceBase : public winrt::implements< - SequenceBase, - winml::ILearningModelFeatureValue, - _winml::ISequenceFeatureValue, - _winml::ILotusValueProviderPrivate> { + SequenceBase, + winml::ILearningModelFeatureValue, + _winml::ISequenceFeatureValue, + _winml::ILotusValueProviderPrivate> { using ABISequence = wfc::IIterable; using AbiMapStringToFloat = wfc::IMap; using AbiMapInt64BitToFloat = wfc::IMap; static_assert( - std::is_same::value || - std::is_same::value || - std::is_same::value || - std::is_same::value || - std::is_same::value || - std::is_same::value || - std::is_same::value || - std::is_same::value || - std::is_same::value || - std::is_same::value || - std::is_same::value || - std::is_same::value || - std::is_same::value || - std::is_same::value || - std::is_same::value, - "Only sequences of of map, map and tensor are supported."); - - template struct SequenceAbiTypeInfo { + std::is_same::value || std::is_same::value || + std::is_same::value || std::is_same::value || std::is_same::value || + std::is_same::value || std::is_same::value || std::is_same::value || + std::is_same::value || std::is_same::value || std::is_same::value || + std::is_same::value || std::is_same::value || + std::is_same::value || std::is_same::value, + "Only sequences of of map, map and tensor are supported." + ); + + template + struct SequenceAbiTypeInfo { static constexpr winml::TensorKind Key = winml::TensorKind::Undefined; static constexpr winml::TensorKind Value = winml::TensorKind::Undefined; }; - template <> struct SequenceAbiTypeInfo { + template <> + struct SequenceAbiTypeInfo { static constexpr winml::TensorKind Key = winml::TensorKind::String; static constexpr winml::TensorKind Value = winml::TensorKind::Float; }; - template <> struct SequenceAbiTypeInfo { + template <> + struct SequenceAbiTypeInfo { static constexpr winml::TensorKind Key = winml::TensorKind::Int64; static constexpr winml::TensorKind Value = winml::TensorKind::Float; }; template - void - GetElementDescriptor(winml::ILearningModelFeatureDescriptor* result) { - + void GetElementDescriptor(winml::ILearningModelFeatureDescriptor* result) { *result = _winml::TensorFeatureDescriptorFrom::CreateAnonymous(std::vector{}); } template <> - void - GetElementDescriptor>( - winml::ILearningModelFeatureDescriptor* result) { + void GetElementDescriptor>(winml::ILearningModelFeatureDescriptor* result) { // zero dimensional tensor has empty shape - auto value_descriptor = - _winml::TensorFeatureDescriptorFrom::CreateAnonymous( - std::vector{}); - *result = - winrt::make( - nullptr /* set to null as values are name-less */, - nullptr /* set to null as values are description-less */, - false /* set to false as values dont have required annotations */, - winml::TensorKind::String /* key kind */, - value_descriptor /* value kind */); + auto value_descriptor = _winml::TensorFeatureDescriptorFrom::CreateAnonymous(std::vector{}); + *result = winrt::make( + nullptr /* set to null as values are name-less */, + nullptr /* set to null as values are description-less */, + false /* set to false as values dont have required annotations */, + winml::TensorKind::String /* key kind */, + value_descriptor /* value kind */ + ); } template <> - void - GetElementDescriptor>( - winml::ILearningModelFeatureDescriptor* result) { + void GetElementDescriptor>(winml::ILearningModelFeatureDescriptor* result) { // zero dimensional tensor has empty shape - auto value_descriptor = - _winml::TensorFeatureDescriptorFrom::CreateAnonymous( - std::vector{}); - *result = - winrt::make( - nullptr /* set to null as values are name-less */, - nullptr /* set to null as values are description-less */, - false /* set to false as values dont have required annotations */, - winml::TensorKind::Int64 /* key kind */, - value_descriptor /* value kind */); + auto value_descriptor = _winml::TensorFeatureDescriptorFrom::CreateAnonymous(std::vector{}); + *result = winrt::make( + nullptr /* set to null as values are name-less */, + nullptr /* set to null as values are description-less */, + false /* set to false as values dont have required annotations */, + winml::TensorKind::Int64 /* key kind */, + value_descriptor /* value kind */ + ); } SequenceBase(const ABISequence& data) : data_(data) {} - static winml::ILearningModelFeatureValue - Create() { + static winml::ILearningModelFeatureValue Create() { auto sequence = winrt::single_threaded_vector(); return winrt::make(sequence); } - static winml::ILearningModelFeatureValue - Create( - const ABISequence& data) { - return winrt::make(data); - } + static winml::ILearningModelFeatureValue Create(const ABISequence& data) { return winrt::make(data); } // ILearningModelFeatureValue implementation - winml::LearningModelFeatureKind - Kind() { - return winml::LearningModelFeatureKind::Sequence; - } + winml::LearningModelFeatureKind Kind() { return winml::LearningModelFeatureKind::Sequence; } - STDMETHOD(get_ElementDescriptor)( - winml::ILearningModelFeatureDescriptor* result) { + STDMETHOD(get_ElementDescriptor)(winml::ILearningModelFeatureDescriptor* result) { FAIL_FAST_IF_NULL(result); GetElementDescriptor(result); @@ -127,9 +103,7 @@ struct SequenceBase : public winrt::implements< return S_OK; } - STDMETHOD(GetValue)( - _winml::BindingContext& context, - IValue** out) { + STDMETHOD(GetValue)(_winml::BindingContext& context, IValue** out) { auto session = context.session.as(); auto engine = session->GetEngine(); @@ -140,10 +114,12 @@ struct SequenceBase : public winrt::implements< if (descriptor.Kind() == winml::LearningModelFeatureKind::Map) { // In opset 10 and earlier only seq> were supported RETURN_IF_FAILED(engine->CreateSequenceOfMapsValue( - reinterpret_cast<::IInspectable*>(winrt::get_abi(data_)), - SequenceAbiTypeInfo::Key, SequenceAbiTypeInfo::Value, out)); - } - else if (descriptor.Kind() == winml::LearningModelFeatureKind::Tensor) { + reinterpret_cast<::IInspectable*>(winrt::get_abi(data_)), + SequenceAbiTypeInfo::Key, + SequenceAbiTypeInfo::Value, + out + )); + } else if (descriptor.Kind() == winml::LearningModelFeatureKind::Tensor) { // In opset 11, operators that require seq> were added. // IVector -> std::vector @@ -164,13 +140,9 @@ struct SequenceBase : public winrt::implements< // The collection of IValues needs wrapped into a single IValue // which represents the sequence value. std::vector<_winml::IValue*> sequence_values; - std::transform( - std::begin(sequence), - std::end(sequence), - std::back_inserter(sequence_values), - [](auto value) { - return value.get(); - }); + std::transform(std::begin(sequence), std::end(sequence), std::back_inserter(sequence_values), [](auto value) { + return value.get(); + }); RETURN_IF_FAILED(engine->CreateSequenceOfValuesValue(sequence_values.data(), sequence_values.size(), out)); } else { @@ -185,35 +157,75 @@ struct SequenceBase : public winrt::implements< } STDMETHOD(IsPlaceholder) - ( - bool* p_is_placeholder) { + (bool* p_is_placeholder) { FAIL_FAST_IF_NULL(p_is_placeholder); *p_is_placeholder = false; return S_OK; } - template auto CreatePlaceholderTensor() { return TElement(nullptr); } - template <> auto CreatePlaceholderTensor() { return winmlp::TensorBoolean::Create(); } - template <> auto CreatePlaceholderTensor() { return winmlp::TensorFloat::Create(); } - template <> auto CreatePlaceholderTensor() { return winmlp::TensorDouble::Create(); } - template <> auto CreatePlaceholderTensor() { return winmlp::TensorInt8Bit::Create(); } - template <> auto CreatePlaceholderTensor() { return winmlp::TensorUInt8Bit::Create(); } - template <> auto CreatePlaceholderTensor() { return winmlp::TensorUInt16Bit::Create(); } - template <> auto CreatePlaceholderTensor() { return winmlp::TensorInt16Bit::Create(); } - template <> auto CreatePlaceholderTensor() { return winmlp::TensorUInt32Bit::Create(); } - template <> auto CreatePlaceholderTensor() { return winmlp::TensorInt32Bit::Create(); } - template <> auto CreatePlaceholderTensor() { return winmlp::TensorUInt64Bit::Create(); } - template <> auto CreatePlaceholderTensor() { return winmlp::TensorInt64Bit::Create(); } - template <> auto CreatePlaceholderTensor() { return winmlp::TensorFloat16Bit::Create(); } - template <> auto CreatePlaceholderTensor() { return winmlp::TensorString::Create(); } - - void AppendValue( - _winml::BindingContext& context, wfc::IVector data, winrt::com_ptr<_winml::IValue> value) { + template + auto CreatePlaceholderTensor() { + return TElement(nullptr); + } + template <> + auto CreatePlaceholderTensor() { + return winmlp::TensorBoolean::Create(); + } + template <> + auto CreatePlaceholderTensor() { + return winmlp::TensorFloat::Create(); + } + template <> + auto CreatePlaceholderTensor() { + return winmlp::TensorDouble::Create(); + } + template <> + auto CreatePlaceholderTensor() { + return winmlp::TensorInt8Bit::Create(); + } + template <> + auto CreatePlaceholderTensor() { + return winmlp::TensorUInt8Bit::Create(); + } + template <> + auto CreatePlaceholderTensor() { + return winmlp::TensorUInt16Bit::Create(); + } + template <> + auto CreatePlaceholderTensor() { + return winmlp::TensorInt16Bit::Create(); + } + template <> + auto CreatePlaceholderTensor() { + return winmlp::TensorUInt32Bit::Create(); + } + template <> + auto CreatePlaceholderTensor() { + return winmlp::TensorInt32Bit::Create(); + } + template <> + auto CreatePlaceholderTensor() { + return winmlp::TensorUInt64Bit::Create(); + } + template <> + auto CreatePlaceholderTensor() { + return winmlp::TensorInt64Bit::Create(); + } + template <> + auto CreatePlaceholderTensor() { + return winmlp::TensorFloat16Bit::Create(); + } + template <> + auto CreatePlaceholderTensor() { + return winmlp::TensorString::Create(); + } + + void AppendValue(_winml::BindingContext& context, wfc::IVector data, winrt::com_ptr<_winml::IValue> value) { auto tensor = CreatePlaceholderTensor(); auto value_provider = tensor.as<_winml::ILotusValueProviderPrivate>(); WINML_THROW_IF_FAILED(value_provider->UpdateSourceResourceData(context, value.get())); data.Append(tensor); - } + } STDMETHOD(UpdateSourceResourceData) (BindingContext& context, IValue* out) { @@ -228,7 +240,12 @@ struct SequenceBase : public winrt::implements< if (descriptor.Kind() == winml::LearningModelFeatureKind::Map) { // In opset 10 and earlier only seq> were supported - RETURN_IF_FAILED(engine->FillSequenceOfMapsValue(reinterpret_cast<::IInspectable*>(winrt::get_abi(data_)), SequenceAbiTypeInfo::Key, SequenceAbiTypeInfo::Value, out)); + RETURN_IF_FAILED(engine->FillSequenceOfMapsValue( + reinterpret_cast<::IInspectable*>(winrt::get_abi(data_)), + SequenceAbiTypeInfo::Key, + SequenceAbiTypeInfo::Value, + out + )); } else if (descriptor.Kind() == winml::LearningModelFeatureKind::Tensor) { // In opset 11, operators that require seq> were added. std::vector> tensor_values; @@ -244,8 +261,7 @@ struct SequenceBase : public winrt::implements< } STDMETHOD(AbiRepresentation) - ( - wf::IInspectable& abi_representation) { + (wf::IInspectable& abi_representation) { data_.as(abi_representation); return S_OK; } @@ -254,4 +270,4 @@ struct SequenceBase : public winrt::implements< ABISequence data_; }; -} // namespace _winml \ No newline at end of file +} // namespace _winml diff --git a/winml/lib/Api/impl/StringData.h b/winml/lib/Api/impl/StringData.h index 17c83d8be1fda..a03335b82875f 100644 --- a/winml/lib/Api/impl/StringData.h +++ b/winml/lib/Api/impl/StringData.h @@ -37,4 +37,4 @@ class string_data : public _winml::idata { std::vector buffer_; }; -} // namespace _winml \ No newline at end of file +} // namespace _winml diff --git a/winml/lib/Api/impl/Tensor.h b/winml/lib/Api/impl/Tensor.h index 98a6c6f66469a..d8b140f363845 100644 --- a/winml/lib/Api/impl/Tensor.h +++ b/winml/lib/Api/impl/Tensor.h @@ -14,27 +14,20 @@ namespace _winml { inline size_t compute_size_of_shape(const std::vector& shape) { - auto size_of_shape = - static_cast( - std::accumulate( - std::begin(shape), - std::end(shape), - static_cast(1), - std::multiplies())); + auto size_of_shape = static_cast( + std::accumulate(std::begin(shape), std::end(shape), static_cast(1), std::multiplies()) + ); return size_of_shape; } template -inline auto create_data( - const std::vector& shape, - const wfc::IIterable& buffers) { +inline auto create_data(const std::vector& shape, const wfc::IIterable& buffers) { return _winml::numeric_data::create(compute_size_of_shape(shape), sizeof(T), buffers); } template <> -inline auto create_data( - const std::vector& shape, - const wfc::IIterable& /*buffers*/) { +inline auto +create_data(const std::vector& shape, const wfc::IIterable& /*buffers*/) { return _winml::string_data::create(compute_size_of_shape(shape)); } @@ -48,48 +41,32 @@ class Tensor { Tensor() = delete; public: - Tensor(const std::vector& shape) : - data_(create_data(shape, nullptr)), - shape_(shape) {} - - Tensor( - const std::vector& shape, - const wfc::IIterable& buffers) : - data_(create_data(shape, buffers)), + Tensor(const std::vector& shape) : data_(create_data(shape, nullptr)), shape_(shape) {} + + Tensor(const std::vector& shape, const wfc::IIterable& buffers) + : data_(create_data(shape, buffers)), shape_(shape) {} - auto size_in_bytes() const { - return data_->size_in_bytes(); - } + auto size_in_bytes() const { return data_->size_in_bytes(); } - auto num_buffers() { - return data_->num_buffers(); - } + auto num_buffers() { return data_->num_buffers(); } - auto& buffers() { - return data_->buffers(); - } + auto& buffers() { return data_->buffers(); } gsl::span buffer(bool should_sync_buffer = true) { auto span = data_->buffer(should_sync_buffer); return gsl::span(reinterpret_cast(span.data()), data_->num_elements()); } - auto flush() { - return data_->flush(); - } + auto flush() { return data_->flush(); } void set(size_t size, const T* data) { auto size_in_bytes = size * sizeof(T); data_->set(size_in_bytes, reinterpret_cast(data)); } - const std::vector& shape() const { - return shape_; - } + const std::vector& shape() const { return shape_; } - auto get_data() { - return data_; - } + auto get_data() { return data_; } }; -} // namespace _winml \ No newline at end of file +} // namespace _winml diff --git a/winml/lib/Api/impl/TensorBase.h b/winml/lib/Api/impl/TensorBase.h index 0d210eb2d7694..c9299a00ddaa2 100644 --- a/winml/lib/Api/impl/TensorBase.h +++ b/winml/lib/Api/impl/TensorBase.h @@ -48,11 +48,13 @@ struct TensorBase : TBase { // since the api attempts copy the tensor memory of type T into a vector of type ElementType. // 2) the second template parameter matches the return type static_assert( - std::is_same::value, - "This API can only be called with template parameters that match its internal data type T."); + std::is_same::value, + "This API can only be called with template parameters that match its internal data type T." + ); static_assert( - std::is_same::value, - "This API can only be called with template parameters that match its internal data type T."); + std::is_same::value, + "This API can only be called with template parameters that match its internal data type T." + ); } template @@ -63,8 +65,9 @@ struct TensorBase : TBase { ASSERT_TEMPLATE_PARAMETERS(); static_assert( - std::is_same::value, - "This API can only be called with matching T and ViewT. Explicit specialization is required."); + std::is_same::value, + "This API can only be called with matching T and ViewT. Explicit specialization is required." + ); } /// On creation, tensors can either: @@ -79,26 +82,27 @@ struct TensorBase : TBase { /// b) TensorBase(winrt::Windows::Foundation::Collections::IIterable const& shape) /// 3) use provided backing gpu memory /// a) TensorBase(std::vector const& shape, ID3D12Resource* pResource) - TensorBase() : resources_(std::make_shared>()) { - } + TensorBase() : resources_(std::make_shared>()) {} - TensorBase(wfc::IIterable const& shape) : shape_(begin(shape), end(shape)), - resources_(std::make_shared>()) { + TensorBase(wfc::IIterable const& shape) + : shape_(begin(shape), end(shape)), + resources_(std::make_shared>()) { CpuTensor() = std::make_shared<_winml::Tensor>(shape_); } - TensorBase(std::vector const& shape) : shape_(shape), - resources_(std::make_shared>()) { + TensorBase(std::vector const& shape) : shape_(shape), resources_(std::make_shared>()) { CpuTensor() = std::make_shared<_winml::Tensor>(shape_); } - TensorBase(std::vector const& shape, ID3D12Resource* resource) : shape_(shape), - resources_(std::make_shared>()) { + TensorBase(std::vector const& shape, ID3D12Resource* resource) + : shape_(shape), + resources_(std::make_shared>()) { // This Api is not supported for TensorString WINML_THROW_HR_IF_TRUE_MSG( - E_ILLEGAL_METHOD_CALL, - (std::is_same::value), - "TensorString objects cannot be created from a ID3D12Resource!"); + E_ILLEGAL_METHOD_CALL, + (std::is_same::value), + "TensorString objects cannot be created from a ID3D12Resource!" + ); GpuTensor().copy_from(resource); } @@ -108,12 +112,14 @@ struct TensorBase : TBase { auto session = context.session.as(); auto device = session->Device().as(); - WINML_THROW_HR_IF_TRUE_MSG(WINML_ERR_INVALID_BINDING, - device->IsCpuDevice(), - "Cannot create GPU tensor on CPU device"); + WINML_THROW_HR_IF_TRUE_MSG( + WINML_ERR_INVALID_BINDING, device->IsCpuDevice(), "Cannot create GPU tensor on CPU device" + ); auto engine = session->GetEngine(); - RETURN_IF_FAILED(engine->CreateTensorValueFromExternalD3DResource(resource, shape_.data(), shape_.size(), TensorKind(), out)); + RETURN_IF_FAILED( + engine->CreateTensorValueFromExternalD3DResource(resource, shape_.data(), shape_.size(), TensorKind(), out) + ); return S_OK; } @@ -148,7 +154,7 @@ struct TensorBase : TBase { // If there is no matching gpu resource, then fallback to a cpu resource if (CpuTensor() != nullptr) { - auto num_backing_buffers = CpuTensor()->num_buffers(); + auto num_backing_buffers = CpuTensor()->num_buffers(); if (num_backing_buffers == 1) { // If we have a single backing cpu buffer, there is no need to create GPU resources. // The engine will use the buffer provided, and perform the needed copies into the GPU context as needed. @@ -171,10 +177,8 @@ struct TensorBase : TBase { context.converter = _winml::PoolObjectWrapper::Create(device->TensorizerStore()->Fetch(descriptor)); context.converter->Get()->Tensorizer->ConvertBuffersToBatchedGPUTensor( - CpuTensor()->buffers(), - CpuTensor()->size_in_bytes(), - *device->GetD3DDeviceCache(), - GpuTensor().get()); + CpuTensor()->buffers(), CpuTensor()->size_in_bytes(), *device->GetD3DDeviceCache(), GpuTensor().get() + ); return CreateGPUMLValue(GpuTensor().get(), context, out); @@ -203,7 +207,8 @@ struct TensorBase : TBase { winrt::com_ptr CreateD3D12Resource(winrt::com_ptr session) { // Try to allocate the backing memory for the caller - auto bufferSize = std::accumulate(std::begin(shape_), std::end(shape_), static_cast(1), std::multiplies()); + auto bufferSize = + std::accumulate(std::begin(shape_), std::end(shape_), static_cast(1), std::multiplies()); auto bufferByteSize = sizeof(T) * bufferSize; // DML needs the resources' sizes to be a multiple of 4 bytes @@ -212,55 +217,54 @@ struct TensorBase : TBase { } D3D12_HEAP_PROPERTIES heapProperties = { - D3D12_HEAP_TYPE_DEFAULT, - D3D12_CPU_PAGE_PROPERTY_UNKNOWN, - D3D12_MEMORY_POOL_UNKNOWN, - 0, - 0}; + D3D12_HEAP_TYPE_DEFAULT, D3D12_CPU_PAGE_PROPERTY_UNKNOWN, D3D12_MEMORY_POOL_UNKNOWN, 0, 0}; D3D12_RESOURCE_DESC resourceDesc = { - D3D12_RESOURCE_DIMENSION_BUFFER, - 0, - static_cast(bufferByteSize), - 1, - 1, - 1, - DXGI_FORMAT_UNKNOWN, - {1, 0}, - D3D12_TEXTURE_LAYOUT_ROW_MAJOR, - D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS}; + D3D12_RESOURCE_DIMENSION_BUFFER, + 0, + static_cast(bufferByteSize), + 1, + 1, + 1, + DXGI_FORMAT_UNKNOWN, + {1, 0}, + D3D12_TEXTURE_LAYOUT_ROW_MAJOR, + D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS + }; auto device = session->Device().as(); winrt::com_ptr gpu_resource = nullptr; device->GetD3DDevice()->CreateCommittedResource( - &heapProperties, - D3D12_HEAP_FLAG_NONE, - &resourceDesc, - D3D12_RESOURCE_STATE_COMMON, - nullptr, - __uuidof(ID3D12Resource), - gpu_resource.put_void()); + &heapProperties, + D3D12_HEAP_FLAG_NONE, + &resourceDesc, + D3D12_RESOURCE_STATE_COMMON, + nullptr, + __uuidof(ID3D12Resource), + gpu_resource.put_void() + ); return gpu_resource; } void EnsureBufferNotInUse() { - auto isBufferInUse = - std::any_of( - outstanding_references_.begin(), - outstanding_references_.end(), - [](auto weakRef) { return weakRef.get() != nullptr; }); + auto isBufferInUse = std::any_of(outstanding_references_.begin(), outstanding_references_.end(), [](auto weakRef) { + return weakRef.get() != nullptr; + }); - WINML_THROW_HR_IF_TRUE_MSG(WINML_ERR_INVALID_BINDING, isBufferInUse, "The tensor has outstanding memory buffer references that must be closed prior to evaluation!"); + WINML_THROW_HR_IF_TRUE_MSG( + WINML_ERR_INVALID_BINDING, + isBufferInUse, + "The tensor has outstanding memory buffer references that must be closed prior to evaluation!" + ); } // ILotusValueProviderPrivate::GetOrtValue STDMETHOD(GetValue) (_winml::BindingContext& context, IValue** out) { RETURN_HR_IF_NULL_MSG( - WINML_ERR_INVALID_BINDING, - resources_, - "The tensor has been closed and its resources have been detached!"); + WINML_ERR_INVALID_BINDING, resources_, "The tensor has been closed and its resources have been detached!" + ); EnsureBufferNotInUse(); @@ -312,15 +316,24 @@ struct TensorBase : TBase { // the conditions of ASSERT_TEMPLATE_PARAMETERS_EXACT() are met. ASSERT_TEMPLATE_PARAMETERS(); - RETURN_IF_FAILED_MSG(engine->CreateTensorValueFromExternalBuffer( - CpuTensor()->buffer(sync_buffer).data(), CpuTensor()->size_in_bytes(), CpuTensor()->shape().data(), - CpuTensor()->shape().size(), TensorKind(), value), - "Failed to prepare buffer for copy back from device resource."); + RETURN_IF_FAILED_MSG( + engine->CreateTensorValueFromExternalBuffer( + CpuTensor()->buffer(sync_buffer).data(), + CpuTensor()->size_in_bytes(), + CpuTensor()->shape().data(), + CpuTensor()->shape().size(), + TensorKind(), + value + ), + "Failed to prepare buffer for copy back from device resource." + ); return S_OK; } template <> - HRESULT CreateTensorValueFromExternalBuffer(_winml::IEngine* engine, bool /*sync_buffer*/, IValue** value) { + HRESULT CreateTensorValueFromExternalBuffer( + _winml::IEngine* engine, bool /*sync_buffer*/, IValue** value + ) { // Ensure that this call is being called with the correct template parameters ASSERT_TEMPLATE_PARAMETERS(); @@ -328,16 +341,16 @@ struct TensorBase : TBase { auto& string_vector = string_data->get_backing_vector(); std::vector raw_values; - std::transform( - std::begin(string_vector), - std::end(string_vector), - std::back_inserter(raw_values), - [&](auto& str) { return str.c_str(); }); - - RETURN_IF_FAILED_MSG(engine->CreateStringTensorValueFromDataWithCopy( - raw_values.data(), raw_values.size(), CpuTensor()->shape().data(), - CpuTensor()->shape().size(), value), - "Failed to prepare buffer for copy back from device resource."); + std::transform(std::begin(string_vector), std::end(string_vector), std::back_inserter(raw_values), [&](auto& str) { + return str.c_str(); + }); + + RETURN_IF_FAILED_MSG( + engine->CreateStringTensorValueFromDataWithCopy( + raw_values.data(), raw_values.size(), CpuTensor()->shape().data(), CpuTensor()->shape().size(), value + ), + "Failed to prepare buffer for copy back from device resource." + ); return S_OK; } @@ -356,9 +369,10 @@ struct TensorBase : TBase { STDMETHOD(UpdateSourceResourceData) (BindingContext& context, IValue* value) { RETURN_HR_IF_NULL_MSG( - E_ILLEGAL_METHOD_CALL, - resources_, - "The tensor has been closed and its resources have been detached during evaluation!"); + E_ILLEGAL_METHOD_CALL, + resources_, + "The tensor has been closed and its resources have been detached during evaluation!" + ); _winml::Resource updated_resource; RETURN_IF_FAILED(value->GetResource(updated_resource)); @@ -402,8 +416,10 @@ struct TensorBase : TBase { if (CpuTensor()->num_buffers() == 1) { winrt::com_ptr dest; - RETURN_IF_FAILED_MSG(CreateTensorValueFromExternalBuffer(engine, false, dest.put()), - "Failed to prepare buffer for copy back from device resource."); + RETURN_IF_FAILED_MSG( + CreateTensorValueFromExternalBuffer(engine, false, dest.put()), + "Failed to prepare buffer for copy back from device resource." + ); RETURN_IF_FAILED(engine->CopyValueAcrossDevices(value, dest.get())); } else { auto buffer_size_in_bytes = static_cast(ShapeSize(shape_)) * sizeof(T); @@ -415,10 +431,8 @@ struct TensorBase : TBase { auto pooled_converter = _winml::PoolObjectWrapper::Create(device->DetensorizerStore()->Fetch(descriptor)); auto d3dResource = reinterpret_cast(updated_resource.get()); pooled_converter->Get()->Detensorizer->ConvertBatchedDX12TensorToBuffers( - d3dResource, - buffer_size_in_bytes, - *device->GetD3DDeviceCache(), - CpuTensor()->buffers()); + d3dResource, buffer_size_in_bytes, *device->GetD3DDeviceCache(), CpuTensor()->buffers() + ); // Reset the Allocator before return to the Cache. Must Sync this background thread to that completion before we do. device->GetD3DDeviceCache()->SyncD3D12ToCPU(); @@ -437,14 +451,11 @@ struct TensorBase : TBase { /// // ITensor::Create - static typename TBase::class_type Create() try { - return winrt::make(); - } + static typename TBase::class_type Create() try { return winrt::make(); } WINML_CATCH_ALL // ITensor::Create - static typename TBase::class_type Create( - wfc::IIterable const& shape) try { + static typename TBase::class_type Create(wfc::IIterable const& shape) try { typename TBase::class_type tensorValue = winrt::make(); auto tensorValueImpl = tensorValue.as(); tensorValueImpl->shape_ = std::vector(begin(shape), end(shape)); @@ -454,8 +465,8 @@ struct TensorBase : TBase { // ITensor::CreateFromIterable static typename TBase::class_type CreateFromIterable( - wfc::IIterable shape, - wfc::IIterable const& data) try { + wfc::IIterable shape, wfc::IIterable const& data + ) try { std::vector vecShape(begin(shape), end(shape)); if (HasFreeDimensions(vecShape)) { // If the tensor is being created with a free dimension, the data needs to @@ -477,8 +488,8 @@ struct TensorBase : TBase { // ITensor::CreateFromArray static typename TBase::class_type CreateFromArray( - wfc::IIterable shape, - winrt::array_view data) try { + wfc::IIterable shape, winrt::array_view data + ) try { std::vector vecShape(begin(shape), end(shape)); return CreateFromArrayInternal(vecShape, data); } @@ -486,16 +497,16 @@ struct TensorBase : TBase { // ITensor::CreateFromShapeArrayAndDataArray static typename TBase::class_type CreateFromShapeArrayAndDataArray( - winrt::array_view shape, - winrt::array_view data) try { + winrt::array_view shape, winrt::array_view data + ) try { std::vector vecShape(shape.begin(), shape.end()); return CreateFromArrayInternal(vecShape, data); } WINML_CATCH_ALL static typename TBase::class_type CreateFromArrayInternal( - std::vector shape, - winrt::array_view data) { + std::vector shape, winrt::array_view data + ) { if (HasFreeDimensions(shape)) { shape = GetAdjustedShape(shape, data.size()); } @@ -508,8 +519,8 @@ struct TensorBase : TBase { // ITensor::CreateFromBuffer static typename TBase::class_type CreateFromBuffer( - winrt::array_view shape, - wss::IBuffer const& buffer) try { + winrt::array_view shape, wss::IBuffer const& buffer + ) try { std::vector vec_shape(std::begin(shape), std::end(shape)); auto buffers = winrt::single_threaded_vector(); buffers.Append(buffer); @@ -519,18 +530,17 @@ struct TensorBase : TBase { // ITensor::CreateFromBatchedBuffers static typename TBase::class_type CreateFromBatchedBuffers( - wfc::IIterable shape, - wfc::IIterable const& buffers) try { + wfc::IIterable shape, wfc::IIterable const& buffers + ) try { std::vector vec_shape(begin(shape), end(shape)); return TensorBase::CreateFromBatchedBuffersInternal(vec_shape, buffers); } WINML_CATCH_ALL - // ITensor::CreateFromBatchedBuffersInternal static typename TBase::class_type CreateFromBatchedBuffersInternal( - std::vector shape, - wfc::IIterable const& buffers) { + std::vector shape, wfc::IIterable const& buffers + ) { if (HasFreeDimensions(shape)) { // If the tensor is being created with a free dimension, the data needs to // provide its actual size so that the free dimension can be computed. @@ -553,11 +563,7 @@ struct TensorBase : TBase { } // ITensorNative::CreateFromD3D12Resource - static HRESULT CreateFromD3D12Resource( - ID3D12Resource* value, - __int64* shape, - int shapeCount, - IUnknown** result) { + static HRESULT CreateFromD3D12Resource(ID3D12Resource* value, __int64* shape, int shapeCount, IUnknown** result) { try { // make sure they gave us a valid shape THROW_HR_IF(E_INVALIDARG, shape == nullptr); @@ -589,17 +595,19 @@ struct TensorBase : TBase { WINML_CATCH_ALL_COM } - static std::vector GetAdjustedShape( - std::vector shape, - uint64_t actualSize) { - auto shapeSize = std::accumulate(std::begin(shape), std::end(shape), static_cast(1), - [](const auto& accumulatedValue, const auto& next) { - if (next == -1) { - return accumulatedValue; - } else { - return accumulatedValue * next; - } - }); + static std::vector GetAdjustedShape(std::vector shape, uint64_t actualSize) { + auto shapeSize = std::accumulate( + std::begin(shape), + std::end(shape), + static_cast(1), + [](const auto& accumulatedValue, const auto& next) { + if (next == -1) { + return accumulatedValue; + } else { + return accumulatedValue * next; + } + } + ); THROW_HR_IF(E_INVALIDARG, actualSize % shapeSize != 0); @@ -612,11 +620,7 @@ struct TensorBase : TBase { static bool HasFreeDimensions(std::vector const& shape) { // Ensure that all dimension values are either -1, or positive - auto unsupportedIt = - std::find_if(begin(shape), end(shape), - [](const auto& dim) { - return dim < -1; - }); + auto unsupportedIt = std::find_if(begin(shape), end(shape), [](const auto& dim) { return dim < -1; }); THROW_HR_IF(E_INVALIDARG, unsupportedIt != end(shape)); auto nFreeDimensions = std::count(begin(shape), end(shape), -1); @@ -637,8 +641,10 @@ struct TensorBase : TBase { wf::IMemoryBufferReference CreateReference() try { // Ensure that CreateReference is only called when there is 1 buffer. WINML_THROW_HR_IF_TRUE_MSG( - E_ILLEGAL_METHOD_CALL, - CpuTensor() != nullptr && CpuTensor()->num_buffers() != 1, "A single buffer reference cannot be retrieved when the tensor is backed by multiple buffers!"); + E_ILLEGAL_METHOD_CALL, + CpuTensor() != nullptr && CpuTensor()->num_buffers() != 1, + "A single buffer reference cannot be retrieved when the tensor is backed by multiple buffers!" + ); // Create a TensorMemoryBufferReference @@ -670,14 +676,12 @@ struct TensorBase : TBase { (BYTE** value, UINT32* capacity) { // This Api is not supported for TensorString RETURN_HR_IF_MSG( - ERROR_INVALID_FUNCTION, - (std::is_same_v), - "TensorString objects cannot return byte buffers!"); + ERROR_INVALID_FUNCTION, (std::is_same_v), "TensorString objects cannot return byte buffers!" + ); RETURN_HR_IF_NULL_MSG( - E_ILLEGAL_METHOD_CALL, - resources_, - "The tensor has been closed and its resources have been detached!"); + E_ILLEGAL_METHOD_CALL, resources_, "The tensor has been closed and its resources have been detached!" + ); return resources_->GetBuffer(shape_, value, capacity); } @@ -689,9 +693,8 @@ struct TensorBase : TBase { // This Api is not supported for TensorString RETURN_HR_IF(ERROR_INVALID_FUNCTION, (std::is_same::value)); RETURN_HR_IF_NULL_MSG( - E_ILLEGAL_METHOD_CALL, - resources_, - "The tensor has been closed and its resources have been detached!"); + E_ILLEGAL_METHOD_CALL, resources_, "The tensor has been closed and its resources have been detached!" + ); GpuTensor().copy_to(ppResource); return S_OK; @@ -735,11 +738,12 @@ struct TensorBase : TBase { // Copy the HALFs to floats std::vector float_value(buffer.size()); DirectX::PackedVector::XMConvertHalfToFloatStream( - float_value.data(), - sizeof(float) /* output stride */, - reinterpret_cast(element_data), - sizeof(_winml::Half) /* input stride */, - buffer.size()); + float_value.data(), + sizeof(float) /* output stride */, + reinterpret_cast(element_data), + sizeof(_winml::Half) /* input stride */, + buffer.size() + ); // Create IVectorView from copied data. return winrt::single_threaded_vector(std::move(float_value)).GetView(); @@ -756,12 +760,9 @@ struct TensorBase : TBase { auto& string_vector = string_data->get_backing_vector(); auto copy = std::vector(string_vector.size(), L""); - std::generate( - copy.begin(), - copy.end(), - [n = 0, &string_vector]() mutable { - return _winml::Strings::HStringFromUTF8(string_vector[n++]); - }); + std::generate(copy.begin(), copy.end(), [n = 0, &string_vector]() mutable { + return _winml::Strings::HStringFromUTF8(string_vector[n++]); + }); return winrt::single_threaded_vector(std::move(copy)).GetView(); } @@ -790,15 +791,11 @@ struct TensorBase : TBase { /// // ILearningModelFeatureValue implementation - winml::LearningModelFeatureKind Kind() try { - return winml::LearningModelFeatureKind::Tensor; - } + winml::LearningModelFeatureKind Kind() try { return winml::LearningModelFeatureKind::Tensor; } WINML_CATCH_ALL // ITensor::TensorKind - winml::TensorKind TensorKind() try { - return TensorKindFrom::Type; - } + winml::TensorKind TensorKind() try { return TensorKindFrom::Type; } WINML_CATCH_ALL // ITensor::Shape @@ -813,9 +810,7 @@ struct TensorBase : TBase { (wf::IInspectable& abiRepresentation) { using ABIType = typename TBase::class_type; ABIType to = nullptr; - RETURN_IF_FAILED(this->QueryInterface( - winrt::guid_of(), - reinterpret_cast(winrt::put_abi(to)))); + RETURN_IF_FAILED(this->QueryInterface(winrt::guid_of(), reinterpret_cast(winrt::put_abi(to)))); to.as(abiRepresentation); @@ -827,9 +822,8 @@ struct TensorBase : TBase { (bool* pIsPlaceHolder) { RETURN_HR_IF_NULL(E_POINTER, pIsPlaceHolder); RETURN_HR_IF_NULL_MSG( - E_ILLEGAL_METHOD_CALL, - resources_, - "The tensor has been closed and its resources have been detached!"); + E_ILLEGAL_METHOD_CALL, resources_, "The tensor has been closed and its resources have been detached!" + ); *pIsPlaceHolder = CpuTensor() == nullptr && GpuTensor() == nullptr; return S_OK; @@ -851,7 +845,8 @@ struct TensorBase : TBase { template <> void SetBufferFromIterableOfBuffers<_winml::Half, float>( - const std::vector& shape, wfc::IIterable const& buffers) { + const std::vector& shape, wfc::IIterable const& buffers + ) { // Ensure that this call is being called with the correct template parameters ASSERT_TEMPLATE_PARAMETERS<_winml::Half, float>(); @@ -861,7 +856,8 @@ struct TensorBase : TBase { template <> void SetBufferFromIterableOfBuffers( - const std::vector& shape, wfc::IIterable const& buffers) { + const std::vector& shape, wfc::IIterable const& buffers + ) { // Ensure that this call is being called with the correct template parameters ASSERT_TEMPLATE_PARAMETERS(); @@ -871,15 +867,17 @@ struct TensorBase : TBase { // Specialized version to convert hstring to string template <> - void SetBufferFromIterableOfBuffers( - const std::vector& /*shape*/, wfc::IIterable const& /*buffers*/) { + void SetBufferFromIterableOfBuffers< + std::string, + winrt::hstring>(const std::vector& /*shape*/, wfc::IIterable const& /*buffers*/) { // Ensure that this call is being called with the correct template parameters ASSERT_TEMPLATE_PARAMETERS(); WINML_THROW_HR_IF_TRUE_MSG( - E_ILLEGAL_METHOD_CALL, - std::is_same::value, - "TensorString objects cannot be created from IBuffers!"); + E_ILLEGAL_METHOD_CALL, + std::is_same::value, + "TensorString objects cannot be created from IBuffers!" + ); } /// @@ -918,11 +916,12 @@ struct TensorBase : TBase { THROW_HR_IF(E_UNEXPECTED, data.size() != buffer.size()); DirectX::PackedVector::XMConvertFloatToHalfStream( - reinterpret_cast(element_data), - sizeof(_winml::Half) /* output stride */, - data.data(), - sizeof(float) /* input stride */, - data.size()); + reinterpret_cast(element_data), + sizeof(_winml::Half) /* output stride */, + data.data(), + sizeof(float) /* input stride */, + data.size() + ); } // Specialized version to convert uint8_t to int8_t @@ -959,19 +958,16 @@ struct TensorBase : TBase { THROW_HR_IF(E_UNEXPECTED, data.size() > string_vector.size()); // Convert and copy into the underlying buffer - std::transform( - data.begin(), data.end(), std::begin(string_vector), - [](auto& element) mutable { - return _winml::Strings::UTF8FromHString(element); - }); + std::transform(data.begin(), data.end(), std::begin(string_vector), [](auto& element) mutable { + return _winml::Strings::UTF8FromHString(element); + }); } /// /// SetBufferFromIterable and parameterized specializations for MLFloat16, int8_t, and std::string /// template - void SetBufferFromIterable( - wfc::IIterable const& data) { + void SetBufferFromIterable(wfc::IIterable const& data) { // This adds compile time checks that ensure that the API can only be called when // the conditions of ASSERT_TEMPLATE_PARAMETERS_EXACT() are met. ASSERT_TEMPLATE_PARAMETERS_EXACT(); @@ -992,8 +988,7 @@ struct TensorBase : TBase { // Specialized version to convert floats to float16 template <> - void SetBufferFromIterable<_winml::Half, float>( - wfc::IIterable const& data) { + void SetBufferFromIterable<_winml::Half, float>(wfc::IIterable const& data) { // Ensure that this call is being called with the correct template parameters ASSERT_TEMPLATE_PARAMETERS<_winml::Half, float>(); @@ -1010,16 +1005,16 @@ struct TensorBase : TBase { // THROW_HR_IF(E_UNEXPECTED, data.Size() != size); std::transform( - begin(data), - end(data), - reinterpret_cast(element_data), - DirectX::PackedVector::XMConvertFloatToHalf); + begin(data), + end(data), + reinterpret_cast(element_data), + DirectX::PackedVector::XMConvertFloatToHalf + ); } // Specialized version to convert uint8_t to int8_t template <> - void SetBufferFromIterable( - wfc::IIterable const& data) { + void SetBufferFromIterable(wfc::IIterable const& data) { // Ensure that this call is being called with the correct template parameters ASSERT_TEMPLATE_PARAMETERS(); @@ -1035,8 +1030,7 @@ struct TensorBase : TBase { // Specialized version to convert hstring to string template <> - void SetBufferFromIterable( - wfc::IIterable const& data) { + void SetBufferFromIterable(wfc::IIterable const& data) { // Ensure that this call is being called with the correct template parameters ASSERT_TEMPLATE_PARAMETERS(); @@ -1056,18 +1050,16 @@ struct TensorBase : TBase { std::shared_ptr<_winml::Tensor>& CpuTensor() { WINML_THROW_HR_IF_NULL_MSG( - E_ILLEGAL_METHOD_CALL, - resources_, - "The tensor has been closed and its resources are detached!"); + E_ILLEGAL_METHOD_CALL, resources_, "The tensor has been closed and its resources are detached!" + ); return resources_->cpu_resource_; } winrt::com_ptr& GpuTensor() { WINML_THROW_HR_IF_NULL_MSG( - E_ILLEGAL_METHOD_CALL, - resources_, - "The tensor has been closed and its resources are detached!"); + E_ILLEGAL_METHOD_CALL, resources_, "The tensor has been closed and its resources are detached!" + ); return resources_->gpu_resource_; } diff --git a/winml/lib/Api/impl/TensorKindFrom.h b/winml/lib/Api/impl/TensorKindFrom.h index 4d67099aa61c7..f2b59ac9d70ec 100644 --- a/winml/lib/Api/impl/TensorKindFrom.h +++ b/winml/lib/Api/impl/TensorKindFrom.h @@ -14,74 +14,127 @@ struct Half { template struct TensorKindFrom {}; template <> -struct TensorKindFrom { static const winml::TensorKind Type = winml::TensorKind::Int8; }; +struct TensorKindFrom { + static const winml::TensorKind Type = winml::TensorKind::Int8; +}; template <> -struct TensorKindFrom { static const winml::TensorKind Type = winml::TensorKind::UInt8; }; +struct TensorKindFrom { + static const winml::TensorKind Type = winml::TensorKind::UInt8; +}; template <> -struct TensorKindFrom { static const winml::TensorKind Type = winml::TensorKind::UInt16; }; +struct TensorKindFrom { + static const winml::TensorKind Type = winml::TensorKind::UInt16; +}; template <> -struct TensorKindFrom { static const winml::TensorKind Type = winml::TensorKind::Int16; }; +struct TensorKindFrom { + static const winml::TensorKind Type = winml::TensorKind::Int16; +}; template <> -struct TensorKindFrom { static const winml::TensorKind Type = winml::TensorKind::UInt32; }; +struct TensorKindFrom { + static const winml::TensorKind Type = winml::TensorKind::UInt32; +}; template <> -struct TensorKindFrom { static const winml::TensorKind Type = winml::TensorKind::Int32; }; +struct TensorKindFrom { + static const winml::TensorKind Type = winml::TensorKind::Int32; +}; template <> -struct TensorKindFrom { static const winml::TensorKind Type = winml::TensorKind::UInt64; }; +struct TensorKindFrom { + static const winml::TensorKind Type = winml::TensorKind::UInt64; +}; template <> -struct TensorKindFrom { static const winml::TensorKind Type = winml::TensorKind::Int64; }; +struct TensorKindFrom { + static const winml::TensorKind Type = winml::TensorKind::Int64; +}; template <> -struct TensorKindFrom { static const winml::TensorKind Type = winml::TensorKind::Boolean; }; +struct TensorKindFrom { + static const winml::TensorKind Type = winml::TensorKind::Boolean; +}; template <> -struct TensorKindFrom { static const winml::TensorKind Type = winml::TensorKind::Double; }; +struct TensorKindFrom { + static const winml::TensorKind Type = winml::TensorKind::Double; +}; template <> -struct TensorKindFrom { static const winml::TensorKind Type = winml::TensorKind::Float; }; +struct TensorKindFrom { + static const winml::TensorKind Type = winml::TensorKind::Float; +}; template <> -struct TensorKindFrom { static const winml::TensorKind Type = winml::TensorKind::Float16; }; +struct TensorKindFrom { + static const winml::TensorKind Type = winml::TensorKind::Float16; +}; template <> -struct TensorKindFrom { static const winml::TensorKind Type = winml::TensorKind::String; }; +struct TensorKindFrom { + static const winml::TensorKind Type = winml::TensorKind::String; +}; template <> -struct TensorKindFrom { static const winml::TensorKind Type = winml::TensorKind::Int8; }; +struct TensorKindFrom { + static const winml::TensorKind Type = winml::TensorKind::Int8; +}; template <> -struct TensorKindFrom { static const winml::TensorKind Type = winml::TensorKind::UInt8; }; +struct TensorKindFrom { + static const winml::TensorKind Type = winml::TensorKind::UInt8; +}; template <> -struct TensorKindFrom { static const winml::TensorKind Type = winml::TensorKind::UInt16; }; +struct TensorKindFrom { + static const winml::TensorKind Type = winml::TensorKind::UInt16; +}; template <> -struct TensorKindFrom { static const winml::TensorKind Type = winml::TensorKind::Int16; }; +struct TensorKindFrom { + static const winml::TensorKind Type = winml::TensorKind::Int16; +}; template <> -struct TensorKindFrom { static const winml::TensorKind Type = winml::TensorKind::UInt32; }; +struct TensorKindFrom { + static const winml::TensorKind Type = winml::TensorKind::UInt32; +}; template <> -struct TensorKindFrom { static const winml::TensorKind Type = winml::TensorKind::Int32; }; +struct TensorKindFrom { + static const winml::TensorKind Type = winml::TensorKind::Int32; +}; template <> -struct TensorKindFrom { static const winml::TensorKind Type = winml::TensorKind::UInt64; }; +struct TensorKindFrom { + static const winml::TensorKind Type = winml::TensorKind::UInt64; +}; template <> -struct TensorKindFrom { static const winml::TensorKind Type = winml::TensorKind::Int64; }; +struct TensorKindFrom { + static const winml::TensorKind Type = winml::TensorKind::Int64; +}; template <> -struct TensorKindFrom { static const winml::TensorKind Type = winml::TensorKind::Boolean; }; +struct TensorKindFrom { + static const winml::TensorKind Type = winml::TensorKind::Boolean; +}; template <> -struct TensorKindFrom { static const winml::TensorKind Type = winml::TensorKind::Double; }; +struct TensorKindFrom { + static const winml::TensorKind Type = winml::TensorKind::Double; +}; template <> -struct TensorKindFrom { static const winml::TensorKind Type = winml::TensorKind::Float; }; +struct TensorKindFrom { + static const winml::TensorKind Type = winml::TensorKind::Float; +}; template <> -struct TensorKindFrom { static const winml::TensorKind Type = winml::TensorKind::String; }; +struct TensorKindFrom { + static const winml::TensorKind Type = winml::TensorKind::String; +}; template <> -struct TensorKindFrom { static const winml::TensorKind Type = winml::TensorKind::String; }; +struct TensorKindFrom { + static const winml::TensorKind Type = winml::TensorKind::String; +}; template <> -struct TensorKindFrom { static const winml::TensorKind Type = winml::TensorKind::Float16; }; +struct TensorKindFrom { + static const winml::TensorKind Type = winml::TensorKind::Float16; +}; template struct TensorFeatureDescriptorFrom { - static winml::ILearningModelFeatureDescriptor - CreateAnonymous( - std::vector shape) { + static winml::ILearningModelFeatureDescriptor CreateAnonymous(std::vector shape) { return winrt::make( - nullptr /* set to null as values are name-less */, - nullptr /* set to null as values are description-less */, - TensorKindFrom::Type, - shape, - false /* set to false as values dont have required annotations */, - false /* set to false as this is not a tensor of unsupported metadata */); + nullptr /* set to null as values are name-less */, + nullptr /* set to null as values are description-less */, + TensorKindFrom::Type, + shape, + false /* set to false as values dont have required annotations */, + false /* set to false as this is not a tensor of unsupported metadata */ + ); } }; -} // namespace _winml \ No newline at end of file +} // namespace _winml diff --git a/winml/lib/Api/impl/TensorMemoryBufferReference.h b/winml/lib/Api/impl/TensorMemoryBufferReference.h index 0bfdec49d9f80..639e2502f43f6 100644 --- a/winml/lib/Api/impl/TensorMemoryBufferReference.h +++ b/winml/lib/Api/impl/TensorMemoryBufferReference.h @@ -13,16 +13,13 @@ namespace _winml { template struct TensorResources { // ITensorNative::GetBuffer - STDMETHOD(GetBuffer) ( - std::vector shape, - BYTE** value, UINT32* capacity) { + STDMETHOD(GetBuffer)(std::vector shape, BYTE** value, UINT32* capacity) { RETURN_HR_IF_NULL(E_POINTER, value); RETURN_HR_IF_NULL(E_POINTER, capacity); RETURN_HR_IF_MSG( - ERROR_INVALID_FUNCTION, - (std::is_same_v), - "TensorString objects cannot return byte buffers!"); + ERROR_INVALID_FUNCTION, (std::is_same_v), "TensorString objects cannot return byte buffers!" + ); try { *value = nullptr; @@ -58,10 +55,10 @@ struct TensorResources { // The template parameter is used to determine the type type of the underlying cpu resource (float, int, etc...). template class TensorMemoryBufferReference : public winrt::implements< - TensorMemoryBufferReference, - wf::IMemoryBufferReference, - wf::IClosable, - Windows::Foundation::IMemoryBufferByteAccess> { + TensorMemoryBufferReference, + wf::IMemoryBufferReference, + wf::IClosable, + Windows::Foundation::IMemoryBufferByteAccess> { using ClosedDelegate = wf::TypedEventHandler; public: @@ -74,11 +71,10 @@ class TensorMemoryBufferReference : public winrt::implements< // This will be null when the source Tensor* object has already been closed. // When the source IMemoryBuffer is closed, the IMemoryBuffer spec requires the // successful creation of IMemoryBufferReferences in the closed state. - TensorMemoryBufferReference( - std::vector shape, - std::shared_ptr> tensorResources) : m_shape(shape), - m_tensorResources(tensorResources), - m_handlers() {} + TensorMemoryBufferReference(std::vector shape, std::shared_ptr> tensorResources) + : m_shape(shape), + m_tensorResources(tensorResources), + m_handlers() {} uint32_t Capacity() const try { uint32_t uCapacity = 0; @@ -102,9 +98,7 @@ class TensorMemoryBufferReference : public winrt::implements< } WINML_CATCH_ALL - void Closed(winrt::event_token const& cookie) try { - m_handlers.erase(cookie.value); - } + void Closed(winrt::event_token const& cookie) try { m_handlers.erase(cookie.value); } WINML_CATCH_ALL // Windows::Foundation::IClosable @@ -121,9 +115,7 @@ class TensorMemoryBufferReference : public winrt::implements< WINML_CATCH_ALL STDMETHOD(GetBuffer) - ( - _Outptr_result_buffer_(*capacity) BYTE** value, - _Out_ UINT32* capacity) try { + (_Outptr_result_buffer_(*capacity) BYTE** value, _Out_ UINT32* capacity) try { RETURN_HR_IF_NULL(E_POINTER, value); RETURN_HR_IF_NULL(E_POINTER, capacity); @@ -143,8 +135,8 @@ class TensorMemoryBufferReference : public winrt::implements< void FireClosed() { wf::IMemoryBufferReference memoryBufferReference = nullptr; WINML_THROW_IF_FAILED(this->QueryInterface( - winrt::guid_of(), - reinterpret_cast(winrt::put_abi(memoryBufferReference)))); + winrt::guid_of(), reinterpret_cast(winrt::put_abi(memoryBufferReference)) + )); for (auto handler : m_handlers) { handler.second(memoryBufferReference, nullptr); diff --git a/winml/lib/Api/inc/ILotusValueProviderPrivate.h b/winml/lib/Api/inc/ILotusValueProviderPrivate.h index 9bd855e306911..3d0ff9a5bc720 100644 --- a/winml/lib/Api/inc/ILotusValueProviderPrivate.h +++ b/winml/lib/Api/inc/ILotusValueProviderPrivate.h @@ -12,8 +12,10 @@ namespace _winml { class PoolObjectWrapper; -enum class BindingType { kInput, - kOutput }; +enum class BindingType { + kInput, + kOutput +}; struct BindingContext { BindingType type = BindingType::kInput; @@ -23,10 +25,11 @@ struct BindingContext { std::shared_ptr converter; }; -struct __declspec(uuid("27e2f437-0112-4693-849e-e04323a620fb")) __declspec(novtable) ILotusValueProviderPrivate : IUnknown { +struct __declspec(uuid("27e2f437-0112-4693-849e-e04323a620fb")) __declspec(novtable) ILotusValueProviderPrivate + : IUnknown { virtual HRESULT __stdcall GetValue(BindingContext& binding_context, _winml::IValue** out) = 0; virtual HRESULT __stdcall IsPlaceholder(bool* is_placeholder) = 0; virtual HRESULT __stdcall UpdateSourceResourceData(BindingContext& binding_context, _winml::IValue* value) = 0; virtual HRESULT __stdcall AbiRepresentation(wf::IInspectable& abi_representation) = 0; }; -} // namespace _winml \ No newline at end of file +} // namespace _winml diff --git a/winml/lib/Api/pch/pch.h b/winml/lib/Api/pch/pch.h index d5d2f48c76787..8c09085a993b5 100644 --- a/winml/lib/Api/pch/pch.h +++ b/winml/lib/Api/pch/pch.h @@ -13,4 +13,4 @@ #include "cppwinrt_onnx.h" #include "dx.h" -#pragma warning(pop) \ No newline at end of file +#pragma warning(pop) diff --git a/winml/lib/Common/CommonDeviceHelpers.cpp b/winml/lib/Common/CommonDeviceHelpers.cpp index c02902e254c47..01615005a8947 100644 --- a/winml/lib/Common/CommonDeviceHelpers.cpp +++ b/winml/lib/Common/CommonDeviceHelpers.cpp @@ -23,7 +23,8 @@ bool CheckAdapterFP16Blocked(bool isMcdmAdapter, uint32_t vendorId, uint32_t maj } // Check Intel GPU driver version - return (majorVersion < 25) || (majorVersion == 25 && minorVersion < 6574) || (majorVersion == 26 && minorVersion < 6572); + return (majorVersion < 25) || (majorVersion == 25 && minorVersion < 6574) || + (majorVersion == 26 && minorVersion < 6572); } } return false; @@ -34,7 +35,8 @@ void ParseDriverVersion(LARGE_INTEGER& version, uint32_t& majorVersion, uint32_t minorVersion = LOWORD(version.LowPart); } -HRESULT GetDXGIAdapterMetadata(ID3D12Device& device, uint32_t& vendorId, uint32_t& majorVersion, uint32_t& minorVersion) { +HRESULT +GetDXGIAdapterMetadata(ID3D12Device& device, uint32_t& vendorId, uint32_t& majorVersion, uint32_t& minorVersion) { winrt::com_ptr spFactory; RETURN_IF_FAILED(CreateDXGIFactory1(IID_PPV_ARGS(spFactory.put()))); @@ -53,7 +55,9 @@ HRESULT GetDXGIAdapterMetadata(ID3D12Device& device, uint32_t& vendorId, uint32_ } #ifdef ENABLE_DXCORE -HRESULT GetDXCoreAdapterMetadata(ID3D12Device& device, bool& isMcdmAdapter, uint32_t& vendorId, uint32_t& majorVersion, uint32_t& minorVersion) { +HRESULT GetDXCoreAdapterMetadata( + ID3D12Device& device, bool& isMcdmAdapter, uint32_t& vendorId, uint32_t& majorVersion, uint32_t& minorVersion +) { winrt::com_ptr spFactory; RETURN_IF_FAILED(DXCoreCreateAdapterFactory(IID_PPV_ARGS(spFactory.put()))); @@ -61,8 +65,8 @@ HRESULT GetDXCoreAdapterMetadata(ID3D12Device& device, bool& isMcdmAdapter, uint RETURN_IF_FAILED(spFactory->GetAdapterByLuid(device.GetAdapterLuid(), IID_PPV_ARGS(spAdapter.put()))); if (spAdapter->IsAttributeSupported(DXCORE_ADAPTER_ATTRIBUTE_D3D12_CORE_COMPUTE) && - (!(spAdapter->IsAttributeSupported(DXCORE_ADAPTER_ATTRIBUTE_D3D12_GRAPHICS) || - spAdapter->IsAttributeSupported(DXCORE_ADAPTER_ATTRIBUTE_D3D11_GRAPHICS)))) { + (!(spAdapter->IsAttributeSupported(DXCORE_ADAPTER_ATTRIBUTE_D3D12_GRAPHICS) || + spAdapter->IsAttributeSupported(DXCORE_ADAPTER_ATTRIBUTE_D3D11_GRAPHICS)))) { isMcdmAdapter = true; } else { isMcdmAdapter = false; @@ -130,7 +134,7 @@ HRESULT IsFloat16Blocked(ID3D12Device& device, bool* isBlocked) { *isBlocked = CheckAdapterFP16Blocked(isMcdmAdapter, vendorId, majorVersion, minorVersion); return S_OK; } -} +} // namespace namespace CommonDeviceHelpers { constexpr uint32_t c_intelVendorId = 0x8086; @@ -152,27 +156,21 @@ bool IsFloat16Supported(const winml::LearningModelDevice& device) { bool IsFloat16Supported(ID3D12Device* device) { #ifndef USE_DML - throw winrt::hresult_error(E_NOTIMPL, L"IsFloat16Supported is not implemented for WinML only build."); + throw winrt::hresult_error(E_NOTIMPL, L"IsFloat16Supported is not implemented for WinML only build."); #else bool isBlocked; if (FAILED(IsFloat16Blocked(*device, &isBlocked)) || isBlocked) { return false; } winrt::com_ptr dmlDevice; - winrt::check_hresult(DMLCreateDevice( - device, - DML_CREATE_DEVICE_FLAG_NONE, - IID_PPV_ARGS(dmlDevice.put()))); + winrt::check_hresult(DMLCreateDevice(device, DML_CREATE_DEVICE_FLAG_NONE, IID_PPV_ARGS(dmlDevice.put()))); DML_FEATURE_QUERY_TENSOR_DATA_TYPE_SUPPORT float16Query = {DML_TENSOR_DATA_TYPE_FLOAT16}; DML_FEATURE_DATA_TENSOR_DATA_TYPE_SUPPORT float16Data = {}; winrt::check_hresult(dmlDevice->CheckFeatureSupport( - DML_FEATURE_TENSOR_DATA_TYPE_SUPPORT, - sizeof(float16Query), - &float16Query, - sizeof(float16Data), - &float16Data)); + DML_FEATURE_TENSOR_DATA_TYPE_SUPPORT, sizeof(float16Query), &float16Query, sizeof(float16Data), &float16Data + )); return float16Data.IsSupported; #endif } diff --git a/winml/lib/Common/inc/CommonDeviceHelpers.h b/winml/lib/Common/inc/CommonDeviceHelpers.h index eb95eff2e736c..aa12d53857d77 100644 --- a/winml/lib/Common/inc/CommonDeviceHelpers.h +++ b/winml/lib/Common/inc/CommonDeviceHelpers.h @@ -45,7 +45,10 @@ template HRESULT RunDelayLoadedApi(TFunc& tfunc, TArgs&&... args) { __try { return tfunc(std::forward(args)...); - } __except (GetExceptionCode() == VcppException(ERROR_SEVERITY_ERROR, ERROR_MOD_NOT_FOUND) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { + } __except ( + GetExceptionCode() == VcppException(ERROR_SEVERITY_ERROR, ERROR_MOD_NOT_FOUND) ? EXCEPTION_EXECUTE_HANDLER + : EXCEPTION_CONTINUE_SEARCH + ) { // this could be ok, just let people know that it failed to load return HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND); } diff --git a/winml/lib/Common/inc/PheonixSingleton.h b/winml/lib/Common/inc/PheonixSingleton.h index 6361385ab6f63..09c373a49705b 100644 --- a/winml/lib/Common/inc/PheonixSingleton.h +++ b/winml/lib/Common/inc/PheonixSingleton.h @@ -16,4 +16,4 @@ std::shared_ptr PheonixSingleton(TArgs&&... args) { auto instance = std::make_shared(std::forward(args)...); instance_ = instance; return instance; -} \ No newline at end of file +} diff --git a/winml/lib/Common/inc/StringHelpers.h b/winml/lib/Common/inc/StringHelpers.h index 067b302a1c17a..f731412f96544 100644 --- a/winml/lib/Common/inc/StringHelpers.h +++ b/winml/lib/Common/inc/StringHelpers.h @@ -11,9 +11,7 @@ struct HStringBuilder { HStringBuilder(HStringBuilder const&) = delete; HStringBuilder& operator=(HStringBuilder const&) = delete; - explicit HStringBuilder(UINT32 size) { - winrt::check_hresult(WindowsPreallocateStringBuffer(size, &data_, &buffer_)); - } + explicit HStringBuilder(UINT32 size) { winrt::check_hresult(WindowsPreallocateStringBuffer(size, &data_, &buffer_)); } ~HStringBuilder() noexcept { if (buffer_ != nullptr) { @@ -21,9 +19,7 @@ struct HStringBuilder { } } - wchar_t* data() noexcept { - return data_; - } + wchar_t* data() noexcept { return data_; } winrt::hstring to_hstring() { winrt::hstring result; @@ -55,9 +51,7 @@ inline winrt::hstring HStringFromUTF8(const char* input, size_t input_length) { } inline winrt::hstring HStringFromUTF8(const char* input) { - return input != nullptr - ? HStringFromUTF8(input, strlen(input)) - : L""; + return input != nullptr ? HStringFromUTF8(input, strlen(input)) : L""; } inline winrt::hstring HStringFromUTF8(const std::string& input) { @@ -68,10 +62,13 @@ inline std::string UTF8FromUnicode(const wchar_t* input, size_t input_length) { if (input_length == 0) { return {}; } else if (input_length <= (std::numeric_limits::max)()) { - int output_length = WideCharToMultiByte(CP_UTF8, 0, input, static_cast(input_length), nullptr, 0, nullptr, nullptr); + int output_length = + WideCharToMultiByte(CP_UTF8, 0, input, static_cast(input_length), nullptr, 0, nullptr, nullptr); if (output_length > 0) { std::string output(output_length, 0); - WideCharToMultiByte(CP_UTF8, 0, input, static_cast(input_length), &output[0], output_length, nullptr, nullptr); + WideCharToMultiByte( + CP_UTF8, 0, input, static_cast(input_length), &output[0], output_length, nullptr, nullptr + ); return output; } else { winrt::throw_hresult(E_INVALIDARG); diff --git a/winml/lib/Common/inc/WinMLTelemetryHelper.h b/winml/lib/Common/inc/WinMLTelemetryHelper.h index 6e95061b01bbe..c0f6ef39d6744 100644 --- a/winml/lib/Common/inc/WinMLTelemetryHelper.h +++ b/winml/lib/Common/inc/WinMLTelemetryHelper.h @@ -40,11 +40,8 @@ class Profiler; #define WINML_TLM_NAMED_DIMENSION_OVERRIDE_VERSION 0 #define WINML_TLM_EXPERIMENTAL_API_VERSION 0 -#define WinMLTraceLoggingWrite(hProvider, EventName, ...) \ - TraceLoggingWrite(hProvider, \ - EventName, \ - TraceLoggingBool(true, "UTCReplace_AppSessionGuid"), \ - __VA_ARGS__) +#define WinMLTraceLoggingWrite(hProvider, EventName, ...) \ + TraceLoggingWrite(hProvider, EventName, TraceLoggingBool(true, "UTCReplace_AppSessionGuid"), __VA_ARGS__) // // WinMLRuntime Telemetry Support // @@ -66,7 +63,6 @@ class WinMLTelemetryHelper { WinMLTelemetryHelper(); virtual ~WinMLTelemetryHelper(); - // // Register telemetry provider and check success. Will only succeed if // client has opted in to sending MS telemetry. @@ -82,35 +78,26 @@ class WinMLTelemetryHelper { // // Un-Register telemetry provider to ignore events from a TraceLogging provider. // - void UnRegister() { - TraceLoggingUnregister(provider_); - } + void UnRegister() { TraceLoggingUnregister(provider_); } void LogApiUsage(const char* name); void LogWinMLShutDown(); void LogWinMLSuspended(); void LogRuntimeError(HRESULT hr, std::string message, PCSTR file, PCSTR function, int line); void LogRuntimeError(HRESULT hr, PCSTR message, PCSTR file, PCSTR function, int line); - void LogRegisterOperatorKernel( - const char* name, - const char* domain, - int execution_type); + void LogRegisterOperatorKernel(const char* name, const char* domain, int execution_type); void RegisterOperatorSetSchema( - const char* name, - uint32_t input_count, - uint32_t output_count, - uint32_t type_constraint_count, - uint32_t attribute_count, - uint32_t default_attribute_count); - void SetIntraOpNumThreadsOverride( - uint32_t num_threads); - void SetIntraOpThreadSpinning( - bool allow_spinning); - void SetNamedDimensionOverride( - winrt::hstring name, - uint32_t value); - void SetLearningModelDeviceKind( - int device_kind); + const char* name, + uint32_t input_count, + uint32_t output_count, + uint32_t type_constraint_count, + uint32_t attribute_count, + uint32_t default_attribute_count + ); + void SetIntraOpNumThreadsOverride(uint32_t num_threads); + void SetIntraOpThreadSpinning(bool allow_spinning); + void SetNamedDimensionOverride(winrt::hstring name, uint32_t value); + void SetLearningModelDeviceKind(int device_kind); void EndRuntimeSession() { ++runtime_session_id_; }; bool IsMeasureSampled(); int GetRuntimeSessionId() { return runtime_session_id_; } diff --git a/winml/lib/Common/inc/WinML_Lock.h b/winml/lib/Common/inc/WinML_Lock.h index b43d0bd550347..725c6010f62a6 100644 --- a/winml/lib/Common/inc/WinML_Lock.h +++ b/winml/lib/Common/inc/WinML_Lock.h @@ -16,42 +16,22 @@ class CWinMLLock { CRITICAL_SECTION critical_section_; public: - CWinMLLock() { - InitializeCriticalSection(&critical_section_); - }; + CWinMLLock() { InitializeCriticalSection(&critical_section_); }; - ~CWinMLLock() { - DeleteCriticalSection(&critical_section_); - }; + ~CWinMLLock() { DeleteCriticalSection(&critical_section_); }; - void Lock() { - EnterCriticalSection(&critical_section_); - }; - void Unlock() { - LeaveCriticalSection(&critical_section_); - }; - void LockExclusive() { - EnterCriticalSection(&critical_section_); - }; - void UnlockExclusive() { - LeaveCriticalSection(&critical_section_); - }; + void Lock() { EnterCriticalSection(&critical_section_); }; + void Unlock() { LeaveCriticalSection(&critical_section_); }; + void LockExclusive() { EnterCriticalSection(&critical_section_); }; + void UnlockExclusive() { LeaveCriticalSection(&critical_section_); }; BOOL IsLockHeldByCurrentThread() { return GetCurrentThreadId() == static_cast(reinterpret_cast(critical_section_.OwningThread)); }; - BOOL IsLockHeld() { - return critical_section_.OwningThread != 0; - }; - BOOL TryLock() { - return TryEnterCriticalSection(&critical_section_); - }; + BOOL IsLockHeld() { return critical_section_.OwningThread != 0; }; + BOOL TryLock() { return TryEnterCriticalSection(&critical_section_); }; // aliased methods to help code compat so that CriticalSections can be passed to ReaderWriter templates - void LockShared() { - EnterCriticalSection(&critical_section_); - }; - void UnlockShared() { - LeaveCriticalSection(&critical_section_); - }; + void LockShared() { EnterCriticalSection(&critical_section_); }; + void UnlockShared() { LeaveCriticalSection(&critical_section_); }; }; // locks a critical section, and unlocks it automatically diff --git a/winml/lib/Common/inc/common.h b/winml/lib/Common/inc/common.h index 96d3aaf2f6a5c..58549e6e52195 100644 --- a/winml/lib/Common/inc/common.h +++ b/winml/lib/Common/inc/common.h @@ -50,4 +50,4 @@ TRACELOGGING_DECLARE_PROVIDER(winml_trace_logging_provider); #include "errors.h" #include "NamespaceAliases.h" #include "StringHelpers.h" -#include "WinML_Lock.h" \ No newline at end of file +#include "WinML_Lock.h" diff --git a/winml/lib/Common/inc/errors.h b/winml/lib/Common/inc/errors.h index ec6222f85d0e3..45707ac570a55 100644 --- a/winml/lib/Common/inc/errors.h +++ b/winml/lib/Common/inc/errors.h @@ -11,7 +11,7 @@ if (!_status.IsOK()) { \ HRESULT hresult = StatusCodeToHRESULT(static_cast(_status.Code())); \ telemetry_helper.LogRuntimeError(hresult, _status.ErrorMessage(), __FILE__, __FUNCTION__, __LINE__); \ - winrt::hstring errorMessage(_winml::Strings::HStringFromUTF8(_status.ErrorMessage())); \ + winrt::hstring errorMessage(_winml::Strings::HStringFromUTF8(_status.ErrorMessage())); \ throw winrt::hresult_error(hresult, errorMessage); \ } \ } while (0) @@ -28,13 +28,15 @@ char msg[1024]; \ sprintf_s(msg, message, __VA_ARGS__); \ telemetry_helper.LogRuntimeError(_hr, msg, __FILE__, __FUNCTION__, __LINE__); \ - winrt::hstring errorMessage(_winml::Strings::HStringFromUTF8(msg)); \ + winrt::hstring errorMessage(_winml::Strings::HStringFromUTF8(msg)); \ throw winrt::hresult_error(_hr, errorMessage); \ } \ } while (0) -#define WINML_THROW_HR_IF_TRUE_MSG(hr, value, message, ...) WINML_THROW_HR_IF_FALSE_MSG(hr, !(value), message, __VA_ARGS__) -#define WINML_THROW_HR_IF_NULL_MSG(hr, value, message, ...) WINML_THROW_HR_IF_TRUE_MSG(hr, ((value) == nullptr), message, __VA_ARGS__) +#define WINML_THROW_HR_IF_TRUE_MSG(hr, value, message, ...) \ + WINML_THROW_HR_IF_FALSE_MSG(hr, !(value), message, __VA_ARGS__) +#define WINML_THROW_HR_IF_NULL_MSG(hr, value, message, ...) \ + WINML_THROW_HR_IF_TRUE_MSG(hr, ((value) == nullptr), message, __VA_ARGS__) // // WINML_THROW_IF_FAILED* Variants @@ -47,13 +49,13 @@ throw winrt::hresult_error(_result, winrt::hresult_error::from_abi); \ } -#define WINML_THROW_HR_MSG_NO_TELEMETRY_SENT(hr, message, ...) \ - do { \ - auto _hr = hr; \ - char msg[1024]; \ - sprintf_s(msg, message, __VA_ARGS__); \ - winrt::hstring errorMessage(_winml::Strings::HStringFromUTF8(msg)); \ - throw winrt::hresult_error(_hr, errorMessage); \ +#define WINML_THROW_HR_MSG_NO_TELEMETRY_SENT(hr, message, ...) \ + do { \ + auto _hr = hr; \ + char msg[1024]; \ + sprintf_s(msg, message, __VA_ARGS__); \ + winrt::hstring errorMessage(_winml::Strings::HStringFromUTF8(msg)); \ + throw winrt::hresult_error(_hr, errorMessage); \ } while (0) #define WINML_THROW_IF_FAILED(hr) \ @@ -122,4 +124,4 @@ inline __declspec(noinline) winrt::hresult_error _to_hresult() noexcept { #define WINML_CATCH_ALL_DONOTHING \ catch (...) { \ return; \ - } \ No newline at end of file + } diff --git a/winml/lib/Common/inc/iengine.h b/winml/lib/Common/inc/iengine.h index 1db8bc4568aac..b7dadcbdbc7ff 100644 --- a/winml/lib/Common/inc/iengine.h +++ b/winml/lib/Common/inc/iengine.h @@ -10,6 +10,8 @@ namespace _winml { interface IEngineFactory; using Resource = std::unique_ptr>; + +// clang-format off MIDL_INTERFACE("31f39226-cfe8-4758-af38-3d01b2a33ee1") IValue : IUnknown { STDMETHOD(IsEmpty) @@ -43,7 +45,7 @@ IValue : IUnknown { MIDL_INTERFACE("4637dfcb-fc19-45c3-a632-c84942d0cf8e") IOrtTypeInfoProvider : IUnknown { STDMETHOD(GetTypeInfo) - (OrtTypeInfo * *info) PURE; + (OrtTypeInfo** info) PURE; }; MIDL_INTERFACE("fe94665f-76cb-42a2-ab21-a06ae1c7f1ae") @@ -54,7 +56,7 @@ IDescriptorInfo : IUnknown{ MIDL_INTERFACE("e3feaec4-eb09-4b82-973c-781f1c230842") IDescriptorInfoProvider : IUnknown{ STDMETHOD(GetDescriptorInfo) - (IEngineFactory* engine_factory, IDescriptorInfo * *info) PURE; + (IEngineFactory* engine_factory, IDescriptorInfo** info) PURE; }; @@ -76,28 +78,28 @@ IModelInfo : IUnknown { (const char** out, size_t* len) PURE; STDMETHOD(GetVersion) - (int64_t * out) PURE; + (int64_t* out) PURE; STDMETHOD(GetModelMetadata) - (ABI::Windows::Foundation::Collections::IMapView **metadata) PURE; + (ABI::Windows::Foundation::Collections::IMapView** metadata) PURE; STDMETHOD(GetInputFeatures) - (ABI::Windows::Foundation::Collections::IVectorView **features) PURE; + (ABI::Windows::Foundation::Collections::IVectorView** features) PURE; STDMETHOD(GetOutputFeatures) - (ABI::Windows::Foundation::Collections::IVectorView **features) PURE; + (ABI::Windows::Foundation::Collections::IVectorView** features) PURE; }; MIDL_INTERFACE("1b198b76-5c44-480d-837c-8433ca6eaf99") IModel : IUnknown { STDMETHOD(GetModelInfo) - (IModelInfo **info) PURE; + (IModelInfo** info) PURE; STDMETHOD(ModelEnsureNoFloat16) () PURE; STDMETHOD(CloneModel) - (IModel **copy) PURE; + (IModel** copy) PURE; STDMETHOD(SaveModel) (_In_ const wchar_t* const file_name, @@ -120,7 +122,7 @@ IModel : IUnknown { STDMETHOD(JoinModel) (_In_ IModel* other_model, _In_ const char* const* output_names, _In_ const char* const* input_names, - size_t num_linkages, bool promote_unlinked_outputs, _In_ const char * const join_node_prefix) PURE; + size_t num_linkages, bool promote_unlinked_outputs, _In_ const char* const join_node_prefix) PURE; }; MIDL_INTERFACE("30c99886-38d2-41cb-a615-203fe7d7daac") @@ -135,7 +137,7 @@ IEngine : IUnknown { () PURE; STDMETHOD(RegisterCustomRegistry) - (IMLOperatorRegistry * registry) PURE; + (IMLOperatorRegistry* registry) PURE; STDMETHOD(EndProfiling) () PURE; @@ -156,7 +158,7 @@ IEngine : IUnknown { (const int64_t* shape, size_t count, winml::TensorKind kind, _Out_ IValue** out) PURE; STDMETHOD(CreateTensorValueFromExternalD3DResource) - (ID3D12Resource * resource, const int64_t* shape, size_t count, winml::TensorKind kind, _Out_ IValue** out) PURE; + (ID3D12Resource* resource, const int64_t* shape, size_t count, winml::TensorKind kind, _Out_ IValue** out) PURE; STDMETHOD(CreateTensorValueFromExternalBuffer) (void* data, size_t size_in_bytes, const int64_t* shape, size_t count, winml::TensorKind kind, _Out_ IValue** out) PURE; @@ -165,37 +167,37 @@ IEngine : IUnknown { (const char* const* data, size_t num_elements, const int64_t* shape, size_t count, _Out_ IValue** out) PURE; STDMETHOD(CreateNullValue) - (_Out_ IValue **out) PURE; + (_Out_ IValue** out) PURE; STDMETHOD(CreateMapValue) - (IInspectable * map, winml::TensorKind key_kind, winml::TensorKind value_kind, _Out_ IValue **out) PURE; + (IInspectable* map, winml::TensorKind key_kind, winml::TensorKind value_kind, _Out_ IValue** out) PURE; STDMETHOD(CreateSequenceOfMapsValue) - (IInspectable * sequence, winml::TensorKind key_kind, winml::TensorKind value_kind, _Out_ IValue **out) PURE; + (IInspectable* sequence, winml::TensorKind key_kind, winml::TensorKind value_kind, _Out_ IValue** out) PURE; STDMETHOD(CreateSequenceOfValuesValue) - (IValue ** values, size_t size, IValue **out) PURE; + (IValue** values, size_t size, IValue** out) PURE; STDMETHOD(CreateOneInputAcrossDevices) (const char* name, IValue* src, IValue** dest) PURE; STDMETHOD(CopyValueAcrossDevices) - (IValue * src, IValue * dest) PURE; + (IValue* src, IValue* dest) PURE; STDMETHOD(Run) (const char** input_names, IValue** inputs, size_t num_inputs, const char** output_names, IValue** outputs, size_t num_outputs) PURE; STDMETHOD(FillFromMapValue) - (IInspectable * map, winml::TensorKind key_kind, winml::TensorKind value_kind, IValue * value) PURE; + (IInspectable* map, winml::TensorKind key_kind, winml::TensorKind value_kind, IValue* value) PURE; STDMETHOD(FillSequenceOfMapsValue) - (IInspectable * sequence, winml::TensorKind key_kind, winml::TensorKind value_kind, IValue * value) PURE; + (IInspectable* sequence, winml::TensorKind key_kind, winml::TensorKind value_kind, IValue* value) PURE; STDMETHOD(GetSequenceOfTensorValues) (_In_ _winml::IValue* sequence_value, _Out_ std::vector>& out_values) PURE; STDMETHOD(GetNumberOfIntraOpThreads) - (uint32_t * num_threads) PURE; + (uint32_t* num_threads) PURE; STDMETHOD(GetIntraOpThreadSpinning) (bool* allow_spinning) PURE; @@ -212,16 +214,16 @@ IThreading : IUnknown { MIDL_INTERFACE("8ac0b6b9-4561-492b-b63d-a07bdd8292c6") IEngineBuilder : IUnknown { STDMETHOD(SetD3D12Resources) - (ID3D12Device * device, ID3D12CommandQueue * queue) PURE; + (ID3D12Device* device, ID3D12CommandQueue* queue) PURE; STDMETHOD(SetMetacommandsEnabled) (int enabled) PURE; STDMETHOD(GetD3D12Device) - (_Outptr_ ID3D12Device * *device) PURE; + (_Outptr_ ID3D12Device** device) PURE; STDMETHOD(GetID3D12CommandQueue) - (_Outptr_ ID3D12CommandQueue * *queue) PURE; + (_Outptr_ ID3D12CommandQueue** queue) PURE; STDMETHOD(SetBatchSizeOverride) (uint32_t batch_size_override) PURE; @@ -238,8 +240,11 @@ IEngineBuilder : IUnknown { STDMETHOD(SetThreadPool) (IThreading* thread_pool) PURE; + STDMETHOD(RegisterCustomOpsLibrary) + (const char* name) PURE; + STDMETHOD(CreateEngine) - (_Outptr_ IEngine * *out) PURE; + (_Outptr_ IEngine** out) PURE; }; @@ -252,32 +257,34 @@ IEngineFactory : IUnknown { (_In_opt_ void* data, _In_ size_t size, _Outptr_ IModel** out) PURE; STDMETHOD(CreateEmptyModel) - (_In_ int64_t opset, _Outptr_ IModel * *out) PURE; + (_In_ int64_t opset, _Outptr_ IModel** out) PURE; STDMETHOD(CreateEngineBuilder) - (_Outptr_ IEngineBuilder **engine_builder) PURE; + (_Outptr_ IEngineBuilder** engine_builder) PURE; STDMETHOD(EnableDebugOutput) (bool is_enabled) PURE; STDMETHOD(CreateCustomRegistry) - (_Out_ IMLOperatorRegistry **registry) PURE; + (_Out_ IMLOperatorRegistry** registry) PURE; STDMETHOD(CreateTensorDescriptorInfo) ( _In_ winml::TensorKind kind, _In_ int64_t* dims, _In_ size_t num_dims, - _Out_ IDescriptorInfo **info) PURE; + _Out_ IDescriptorInfo** info) PURE; STDMETHOD(CreateSequenceDescriptorInfo) - (_Out_ IDescriptorInfo **info) PURE; + (_Out_ IDescriptorInfo** info) PURE; STDMETHOD(CreateMapDescriptorInfo) - (_Out_ IDescriptorInfo **info) PURE; + (_Out_ IDescriptorInfo** info) PURE; STDMETHOD(CreateThreadPool) (_In_ bool allow_spinning, _In_ uint32_t num_intra_op_threads, _Out_ IThreading** thread_pool) PURE; }; +// clang-format on + } // namespace _winml diff --git a/winml/lib/Common/inc/onnx.h b/winml/lib/Common/inc/onnx.h index 1519bc294892d..b337ce31c6637 100644 --- a/winml/lib/Common/inc/onnx.h +++ b/winml/lib/Common/inc/onnx.h @@ -27,8 +27,8 @@ #endif USE_DML #include "core/framework/customregistry.h" -#include "core/framework/allocatormgr.h" +#include "core/framework/allocator_utils.h" #include "core/session/environment.h" #include "core/session/IOBinding.h" #include "core/common/logging/logging.h" -#include "core/common/logging/sinks/clog_sink.h" \ No newline at end of file +#include "core/common/logging/sinks/clog_sink.h" diff --git a/winml/lib/Common/inc/pch.h b/winml/lib/Common/inc/pch.h index bb3b4b663e697..5344c7ddd86e1 100644 --- a/winml/lib/Common/inc/pch.h +++ b/winml/lib/Common/inc/pch.h @@ -1,3 +1,3 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "winrt_headers.h" \ No newline at end of file +#include "winrt_headers.h" diff --git a/winml/lib/Common/inc/winrt_headers.h b/winml/lib/Common/inc/winrt_headers.h index 2791016be7b4c..f7b654d4eab3c 100644 --- a/winml/lib/Common/inc/winrt_headers.h +++ b/winml/lib/Common/inc/winrt_headers.h @@ -11,6 +11,7 @@ #include "winrt/windows.foundation.collections.h" #include "winrt/windows.storage.streams.h" +// clang-format off #define STRINGIFY(x) #x #define XSTRINGIFY(x) STRINGIFY(x) #define CPPWINRT_HEADER(root_ns) comp_generated/winrt/##root_ns##.AI.MachineLearning.h @@ -19,6 +20,7 @@ #define CREATE_CPPWINRT_COMPONENT_HEADER() XSTRINGIFY(CPPWINRT_HEADER(WINML_ROOT_NS)) #define CREATE_NATIVE_HEADER() XSTRINGIFY(NATIVE_HEADER(WINML_ROOT_NS)) #define CREATE_NATIVE_INTERNAL_HEADER() XSTRINGIFY(NATIVE_INTERNAL_HEADER(WINML_ROOT_NS)) +// clang-format on #include CREATE_CPPWINRT_COMPONENT_HEADER() diff --git a/winml/lib/Telemetry/Telemetry.cpp b/winml/lib/Telemetry/Telemetry.cpp index 26a23c6ec0f95..bf0cca1251b37 100644 --- a/winml/lib/Telemetry/Telemetry.cpp +++ b/winml/lib/Telemetry/Telemetry.cpp @@ -6,8 +6,5 @@ WinMLTelemetryHelper telemetry_helper; TRACELOGGING_DEFINE_PROVIDER( - winml_trace_logging_provider, - WINML_PROVIDER_DESC, - WINML_PROVIDER_GUID, - TraceLoggingOptionMicrosoftTelemetry()); - + winml_trace_logging_provider, WINML_PROVIDER_DESC, WINML_PROVIDER_GUID, TraceLoggingOptionMicrosoftTelemetry() +); diff --git a/winml/lib/Telemetry/TelemetryEvent.cpp b/winml/lib/Telemetry/TelemetryEvent.cpp index 64c4c56889380..5f1d3e4ee3342 100644 --- a/winml/lib/Telemetry/TelemetryEvent.cpp +++ b/winml/lib/Telemetry/TelemetryEvent.cpp @@ -9,9 +9,7 @@ using namespace _winmlt; static uint64_t s_event_id = 0; -static const char* -EventCategoryToString( - EventCategory category) { +static const char* EventCategoryToString(EventCategory category) { switch (category) { case EventCategory::kModelLoad: return "Model load"; @@ -26,34 +24,33 @@ EventCategoryToString( } } -TelemetryEvent::TelemetryEvent( - EventCategory category) { - auto is_provider_enabled = - TraceLoggingProviderEnabled( - winml_trace_logging_provider, - WINEVENT_LEVEL_VERBOSE, - WINML_PROVIDER_KEYWORD_START_STOP); +TelemetryEvent::TelemetryEvent(EventCategory category) { + auto is_provider_enabled = TraceLoggingProviderEnabled( + winml_trace_logging_provider, WINEVENT_LEVEL_VERBOSE, WINML_PROVIDER_KEYWORD_START_STOP + ); if (is_provider_enabled) { category_ = category; event_id_ = InterlockedIncrement(&s_event_id); WinMLTraceLoggingWrite( - winml_trace_logging_provider, - "started event", - TraceLoggingString(EventCategoryToString(category_), "event"), - TraceLoggingInt64(event_id_.value(), "eventId"), - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_START_STOP)); + winml_trace_logging_provider, + "started event", + TraceLoggingString(EventCategoryToString(category_), "event"), + TraceLoggingInt64(event_id_.value(), "eventId"), + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_START_STOP) + ); } } TelemetryEvent::~TelemetryEvent() { if (event_id_.has_value()) { WinMLTraceLoggingWrite( - winml_trace_logging_provider, - "stopped event", - TraceLoggingString(EventCategoryToString(category_), "event"), - TraceLoggingInt64(event_id_.value(), "eventId"), - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_START_STOP)); + winml_trace_logging_provider, + "stopped event", + TraceLoggingString(EventCategoryToString(category_), "event"), + TraceLoggingInt64(event_id_.value(), "eventId"), + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_START_STOP) + ); } } diff --git a/winml/lib/Telemetry/WinMLTelemetryHelper.cpp b/winml/lib/Telemetry/WinMLTelemetryHelper.cpp index 3efeea4ef1957..ee8ef617c4519 100644 --- a/winml/lib/Telemetry/WinMLTelemetryHelper.cpp +++ b/winml/lib/Telemetry/WinMLTelemetryHelper.cpp @@ -9,45 +9,46 @@ #include "lib/Telemetry/pch.h" -WinMLTelemetryHelper::WinMLTelemetryHelper() - : provider_(winml_trace_logging_provider) { +WinMLTelemetryHelper::WinMLTelemetryHelper() : provider_(winml_trace_logging_provider) { } WinMLTelemetryHelper::~WinMLTelemetryHelper() { } -void WinMLTelemetryHelper::LogApiUsage(const char* name){ +void WinMLTelemetryHelper::LogApiUsage(const char* name) { if (!telemetry_enabled_) return; WinMLTraceLoggingWrite( - provider_, - "ApiUsage", - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), - TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), - //Telemetry info - TraceLoggingUInt8(WINML_TLM_EXPERIMENTAL_API_VERSION, "experimentalSchemaVersion"), - // named dimension override info - TraceLoggingString(name, "name"), - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)); + provider_, + "ApiUsage", + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), + TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), + //Telemetry info + TraceLoggingUInt8(WINML_TLM_EXPERIMENTAL_API_VERSION, "experimentalSchemaVersion"), + // named dimension override info + TraceLoggingString(name, "name"), + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES) + ); } - void WinMLTelemetryHelper::LogWinMLShutDown() { std::string message = BINARY_NAME; message += " is unloaded"; WinMLTraceLoggingWrite( - provider_, - "WinMLShutDown", - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), - TraceLoggingString(message.c_str(), "message")); + provider_, + "WinMLShutDown", + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), + TraceLoggingString(message.c_str(), "message") + ); } void WinMLTelemetryHelper::LogWinMLSuspended() { WinMLTraceLoggingWrite( - provider_, - "WinMLSuspended", - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), - TraceLoggingInt32(runtime_session_id_, "runtimeSessionId")); + provider_, + "WinMLSuspended", + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), + TraceLoggingInt32(runtime_session_id_, "runtimeSessionId") + ); } void WinMLTelemetryHelper::LogRuntimeError(HRESULT hr, PCSTR message, PCSTR file, PCSTR function, int line) { @@ -55,20 +56,21 @@ void WinMLTelemetryHelper::LogRuntimeError(HRESULT hr, PCSTR message, PCSTR file return; WinMLTraceLoggingWrite( - provider_, - "RuntimeError", - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), - TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), - // Telemetry info - TraceLoggingUInt8(WINML_TLM_RUNTIME_ERROR_VERSION, "schemaVersion"), - // Error Info - TraceLoggingHResult(hr, "hResult"), - TraceLoggingString(message, "errormessage"), - TraceLoggingString(file, "file"), - TraceLoggingString(function, "function"), - TraceLoggingInt32(line, "line"), - TraceLoggingInt32(runtime_session_id_, "runtimeSessionId"), - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)); + provider_, + "RuntimeError", + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), + TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), + // Telemetry info + TraceLoggingUInt8(WINML_TLM_RUNTIME_ERROR_VERSION, "schemaVersion"), + // Error Info + TraceLoggingHResult(hr, "hResult"), + TraceLoggingString(message, "errormessage"), + TraceLoggingString(file, "file"), + TraceLoggingString(function, "function"), + TraceLoggingInt32(line, "line"), + TraceLoggingInt32(runtime_session_id_, "runtimeSessionId"), + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES) + ); } void WinMLTelemetryHelper::LogRuntimeError(HRESULT hr, std::string message, PCSTR file, PCSTR function, int line) { @@ -80,118 +82,118 @@ bool WinMLTelemetryHelper::IsMeasureSampled() { return TraceLoggingProviderEnabled(provider_, WINEVENT_LEVEL_LOG_ALWAYS, MICROSOFT_KEYWORD_MEASURES); } -void WinMLTelemetryHelper::LogRegisterOperatorKernel( - const char* name, - const char* domain, - int execution_type) { +void WinMLTelemetryHelper::LogRegisterOperatorKernel(const char* name, const char* domain, int execution_type) { if (!telemetry_enabled_) return; WinMLTraceLoggingWrite( - provider_, - "RegisterOperatorKernel", - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), - TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), - // Telemetry info - TraceLoggingUInt8(WINML_TLM_RUNTIME_ERROR_VERSION, "schemaVersion"), - //op kernel info - TraceLoggingString(name, "name"), - TraceLoggingString(domain, "domain"), - TraceLoggingInt32(execution_type, "executionType"), - TraceLoggingInt32(runtime_session_id_, "runtimeSessionId"), - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)); + provider_, + "RegisterOperatorKernel", + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), + TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), + // Telemetry info + TraceLoggingUInt8(WINML_TLM_RUNTIME_ERROR_VERSION, "schemaVersion"), + //op kernel info + TraceLoggingString(name, "name"), + TraceLoggingString(domain, "domain"), + TraceLoggingInt32(execution_type, "executionType"), + TraceLoggingInt32(runtime_session_id_, "runtimeSessionId"), + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES) + ); } void WinMLTelemetryHelper::RegisterOperatorSetSchema( - const char* name, - uint32_t input_count, - uint32_t output_count, - uint32_t type_constraint_count, - uint32_t attribute_count, - uint32_t default_attribute_count) { + const char* name, + uint32_t input_count, + uint32_t output_count, + uint32_t type_constraint_count, + uint32_t attribute_count, + uint32_t default_attribute_count +) { if (!telemetry_enabled_) return; WinMLTraceLoggingWrite( - provider_, - "RegisterOperatorSetSchema", - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), - TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), - // Telemetry info - TraceLoggingUInt8(WINML_TLM_RUNTIME_ERROR_VERSION, "schemaVersion"), - //op kernel info - TraceLoggingString(name, "name"), - TraceLoggingInt32(input_count, "inputCount"), //stats - TraceLoggingInt32(output_count, "outputCount"), - TraceLoggingInt32(type_constraint_count, "typeConstraintCount"), - TraceLoggingInt32(attribute_count, "attributeCount"), - TraceLoggingInt32(default_attribute_count, "defaultAttributeCount"), - TraceLoggingInt32(runtime_session_id_, "runtime_session_id_"), - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)); + provider_, + "RegisterOperatorSetSchema", + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), + TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), + // Telemetry info + TraceLoggingUInt8(WINML_TLM_RUNTIME_ERROR_VERSION, "schemaVersion"), + //op kernel info + TraceLoggingString(name, "name"), + TraceLoggingInt32(input_count, "inputCount"), //stats + TraceLoggingInt32(output_count, "outputCount"), + TraceLoggingInt32(type_constraint_count, "typeConstraintCount"), + TraceLoggingInt32(attribute_count, "attributeCount"), + TraceLoggingInt32(default_attribute_count, "defaultAttributeCount"), + TraceLoggingInt32(runtime_session_id_, "runtime_session_id_"), + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES) + ); } -void WinMLTelemetryHelper::SetIntraOpNumThreadsOverride( - uint32_t num_threads_override) { +void WinMLTelemetryHelper::SetIntraOpNumThreadsOverride(uint32_t num_threads_override) { if (!telemetry_enabled_) return; WinMLTraceLoggingWrite( - provider_, - "SetIntraOpNumThreadsOverride", - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), - TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), - //Telemetry info - TraceLoggingUInt8(WINML_TLM_NATIVE_API_INTRAOP_THREADS_VERSION, "schemaVersion"), - // num threads info - TraceLoggingInt32(num_threads_override, "numThreadsOverride"), - TraceLoggingInt32(std::thread::hardware_concurrency(), "maxThreadsOnMachine"), - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)); + provider_, + "SetIntraOpNumThreadsOverride", + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), + TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), + //Telemetry info + TraceLoggingUInt8(WINML_TLM_NATIVE_API_INTRAOP_THREADS_VERSION, "schemaVersion"), + // num threads info + TraceLoggingInt32(num_threads_override, "numThreadsOverride"), + TraceLoggingInt32(std::thread::hardware_concurrency(), "maxThreadsOnMachine"), + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES) + ); } -void WinMLTelemetryHelper::SetIntraOpThreadSpinning( - bool allow_spinning) { - if (!telemetry_enabled_) - return; - WinMLTraceLoggingWrite( - provider_, - "SetIntraOpThreadSpinning", - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), - TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), - //Telemetry info - TraceLoggingUInt8(WINML_TLM_NATIVE_API_INTRAOP_THREAD_SPINNING_VERSION, "schemaVersion"), - // thread spinning info - TraceLoggingBoolean(allow_spinning, "threadSpinningAllowed"), - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)); +void WinMLTelemetryHelper::SetIntraOpThreadSpinning(bool allow_spinning) { + if (!telemetry_enabled_) + return; + WinMLTraceLoggingWrite( + provider_, + "SetIntraOpThreadSpinning", + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), + TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), + //Telemetry info + TraceLoggingUInt8(WINML_TLM_NATIVE_API_INTRAOP_THREAD_SPINNING_VERSION, "schemaVersion"), + // thread spinning info + TraceLoggingBoolean(allow_spinning, "threadSpinningAllowed"), + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES) + ); } -void WinMLTelemetryHelper::SetNamedDimensionOverride( - winrt::hstring name, uint32_t value) { +void WinMLTelemetryHelper::SetNamedDimensionOverride(winrt::hstring name, uint32_t value) { if (!telemetry_enabled_) return; WinMLTraceLoggingWrite( - provider_, - "SetNamedDimensionOverride", - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), - TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), - //Telemetry info - TraceLoggingUInt8(WINML_TLM_NAMED_DIMENSION_OVERRIDE_VERSION, "schemaVersion"), - // named dimension override info - TraceLoggingWideString(name.c_str(), "dimensionName"), - TraceLoggingInt32(value, "overrideValue"), - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)); + provider_, + "SetNamedDimensionOverride", + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), + TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), + //Telemetry info + TraceLoggingUInt8(WINML_TLM_NAMED_DIMENSION_OVERRIDE_VERSION, "schemaVersion"), + // named dimension override info + TraceLoggingWideString(name.c_str(), "dimensionName"), + TraceLoggingInt32(value, "overrideValue"), + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES) + ); } -void WinMLTelemetryHelper::SetLearningModelDeviceKind( - int device_kind) { +void WinMLTelemetryHelper::SetLearningModelDeviceKind(int device_kind) { if (!telemetry_enabled_) return; WinMLTraceLoggingWrite( - provider_, - "SetLearningModelDevice", - TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), - TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), - //Telemetry info - TraceLoggingUInt8(WINML_TLM_DEVICE_KIND_VERSION, "schemaVersion"), - // learning model device info - TraceLoggingInt32(device_kind, "deviceKind"), - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)); -} \ No newline at end of file + provider_, + "SetLearningModelDevice", + TraceLoggingKeyword(WINML_PROVIDER_KEYWORD_DEFAULT), + TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage), + //Telemetry info + TraceLoggingUInt8(WINML_TLM_DEVICE_KIND_VERSION, "schemaVersion"), + // learning model device info + TraceLoggingInt32(device_kind, "deviceKind"), + TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES) + ); +} diff --git a/winml/lib/Telemetry/inc/TelemetryEvent.h b/winml/lib/Telemetry/inc/TelemetryEvent.h index ff52eb941dde5..8cf3aceed64da 100644 --- a/winml/lib/Telemetry/inc/TelemetryEvent.h +++ b/winml/lib/Telemetry/inc/TelemetryEvent.h @@ -14,8 +14,7 @@ enum class EventCategory { class TelemetryEvent { public: - TelemetryEvent( - EventCategory eventCategory); + TelemetryEvent(EventCategory eventCategory); ~TelemetryEvent(); @@ -24,4 +23,4 @@ class TelemetryEvent { std::optional event_id_; }; -} // namespace _winml::Telemetry \ No newline at end of file +} // namespace _winml::Telemetry diff --git a/winml/lib/Telemetry/pch.h b/winml/lib/Telemetry/pch.h index 976f62c7f97cf..cec3de1f4f8d1 100644 --- a/winml/lib/Telemetry/pch.h +++ b/winml/lib/Telemetry/pch.h @@ -5,4 +5,4 @@ #include "winrt_headers.h" #include "TraceLoggingConfig.h" -#include "NamespaceAliases.h" \ No newline at end of file +#include "NamespaceAliases.h" diff --git a/winml/test/adapter/AdapterDmlEpTest.cpp b/winml/test/adapter/AdapterDmlEpTest.cpp index 3069c618b1738..81437f9db2de3 100644 --- a/winml/test/adapter/AdapterDmlEpTest.cpp +++ b/winml/test/adapter/AdapterDmlEpTest.cpp @@ -26,7 +26,9 @@ void AdapterDmlEpTestSetup() { GPUTEST; winrt::init_apartment(); ort_api = OrtGetApiBase()->GetApi(ORT_API_VERSION); - THROW_IF_NOT_OK_MSG(ort_api->GetExecutionProviderApi("DML", ORT_API_VERSION, reinterpret_cast(&ort_dml_api)), ort_api); + THROW_IF_NOT_OK_MSG( + ort_api->GetExecutionProviderApi("DML", ORT_API_VERSION, reinterpret_cast(&ort_dml_api)), ort_api + ); winml_adapter_api = OrtGetWinMLAdapter(ORT_API_VERSION); THROW_IF_NOT_OK_MSG(ort_api->CreateEnv(OrtLoggingLevel::ORT_LOGGING_LEVEL_VERBOSE, "Default", &ort_env), ort_api); #ifdef BUILD_INBOX @@ -40,21 +42,25 @@ void AdapterDmlEpTestTeardown() { } UniqueOrtSessionOptions CreateUniqueOrtSessionOptions() { - OrtSessionOptions *options; + OrtSessionOptions* options; THROW_IF_NOT_OK_MSG(ort_api->CreateSessionOptions(&options), ort_api); return UniqueOrtSessionOptions(options, ort_api->ReleaseSessionOptions); } UniqueOrtSession CreateUniqueOrtSession(const UniqueOrtSessionOptions& session_options) { OrtSession* session; - THROW_IF_NOT_OK_MSG(winml_adapter_api->CreateSessionWithoutModel(ort_env, session_options.get(), nullptr, nullptr, &session), ort_api); + THROW_IF_NOT_OK_MSG( + winml_adapter_api->CreateSessionWithoutModel(ort_env, session_options.get(), nullptr, nullptr, &session), ort_api + ); return UniqueOrtSession(session, ort_api->ReleaseSession); } -UniqueOrtSession CreateUniqueOrtSession(const std::wstring& model_path, const UniqueOrtSessionOptions& session_options) { +UniqueOrtSession CreateUniqueOrtSession( + const std::wstring& model_path, const UniqueOrtSessionOptions& session_options +) { THROW_IF_NOT_OK_MSG(ort_api->SetIntraOpNumThreads(session_options.get(), 1), ort_api); THROW_IF_NOT_OK_MSG(ort_api->SetSessionGraphOptimizationLevel(session_options.get(), ORT_ENABLE_BASIC), ort_api); - OrtSession *session; + OrtSession* session; THROW_IF_NOT_OK_MSG(ort_api->CreateSession(ort_env, model_path.c_str(), session_options.get(), &session), ort_api); return UniqueOrtSession(session, ort_api->ReleaseSession); } @@ -64,14 +70,21 @@ UniqueOrtSession CreateDmlSession() { THROW_IF_NOT_OK_MSG(ort_api->DisableMemPattern(session_options.get()), ort_api); winrt::com_ptr device; - WINML_EXPECT_NO_THROW(D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(device.put()))); + WINML_EXPECT_NO_THROW( + D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(device.put())) + ); winrt::com_ptr queue; D3D12_COMMAND_QUEUE_DESC command_queue_desc = {}; command_queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; WINML_EXPECT_HRESULT_SUCCEEDED(device->CreateCommandQueue(&command_queue_desc, IID_PPV_ARGS(queue.put()))); - THROW_IF_NOT_OK_MSG(winml_adapter_api->OrtSessionOptionsAppendExecutionProvider_DML(session_options.get(), device.get(), queue.get(), false), ort_api); + THROW_IF_NOT_OK_MSG( + winml_adapter_api->OrtSessionOptionsAppendExecutionProvider_DML( + session_options.get(), device.get(), queue.get(), false + ), + ort_api + ); return CreateUniqueOrtSession(FileHelpers::GetModulePath() + L"fns-candy.onnx", session_options); } @@ -80,14 +93,6 @@ UniqueOrtSession CreateCpuSession() { return CreateUniqueOrtSession(FileHelpers::GetModulePath() + L"fns-candy.onnx", session_options); } -void DmlExecutionProviderSetDefaultRoundingMode() { - GPUTEST; - auto session = CreateDmlSession(); - OrtExecutionProvider* ort_provider; - THROW_IF_NOT_OK_MSG(winml_adapter_api->SessionGetExecutionProvider(session.get(), 0, &ort_provider), ort_api); - THROW_IF_NOT_OK_MSG(winml_adapter_api->DmlExecutionProviderSetDefaultRoundingMode(ort_provider, false), ort_api); -} - void DmlExecutionProviderFlushContext() { GPUTEST; auto session = CreateDmlSession(); @@ -111,51 +116,52 @@ std::array tensor_values = {}; winrt::com_ptr CreateD3D12Resource(ID3D12Device& device) { constexpr uint64_t buffer_size = tensor_size * sizeof(float); constexpr D3D12_HEAP_PROPERTIES heap_properties = { - D3D12_HEAP_TYPE_DEFAULT, - D3D12_CPU_PAGE_PROPERTY_UNKNOWN, - D3D12_MEMORY_POOL_UNKNOWN, - 0, - 0 - }; + D3D12_HEAP_TYPE_DEFAULT, D3D12_CPU_PAGE_PROPERTY_UNKNOWN, D3D12_MEMORY_POOL_UNKNOWN, 0, 0}; constexpr D3D12_RESOURCE_DESC resource_desc = { - D3D12_RESOURCE_DIMENSION_BUFFER, - 0, - buffer_size, - 1, - 1, - 1, - DXGI_FORMAT_UNKNOWN, - {1, 0}, - D3D12_TEXTURE_LAYOUT_ROW_MAJOR, - D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS + D3D12_RESOURCE_DIMENSION_BUFFER, + 0, + buffer_size, + 1, + 1, + 1, + DXGI_FORMAT_UNKNOWN, + {1, 0}, + D3D12_TEXTURE_LAYOUT_ROW_MAJOR, + D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS }; winrt::com_ptr d3d12_resource; WINML_EXPECT_HRESULT_SUCCEEDED(device.CreateCommittedResource( - &heap_properties, - D3D12_HEAP_FLAG_NONE, - &resource_desc, - D3D12_RESOURCE_STATE_COMMON, - nullptr, - IID_PPV_ARGS(d3d12_resource.put()))); + &heap_properties, + D3D12_HEAP_FLAG_NONE, + &resource_desc, + D3D12_RESOURCE_STATE_COMMON, + nullptr, + IID_PPV_ARGS(d3d12_resource.put()) + )); return d3d12_resource; } - void DmlCreateAndFreeGPUAllocationFromD3DResource() { GPUTEST; winrt::com_ptr device; - WINML_EXPECT_NO_THROW(D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(device.put()))); + WINML_EXPECT_NO_THROW( + D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(device.put())) + ); auto d3d12_resource = CreateD3D12Resource(*device); void* dml_allocator_resource; - THROW_IF_NOT_OK_MSG(ort_dml_api->CreateGPUAllocationFromD3DResource(d3d12_resource.get(), &dml_allocator_resource), ort_api); + THROW_IF_NOT_OK_MSG( + ort_dml_api->CreateGPUAllocationFromD3DResource(d3d12_resource.get(), &dml_allocator_resource), ort_api + ); THROW_IF_NOT_OK_MSG(ort_dml_api->FreeGPUAllocation(dml_allocator_resource), ort_api); } void DmlGetD3D12ResourceFromAllocation() { GPUTEST; winrt::com_ptr device; - WINML_EXPECT_NO_THROW(D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(device.put()))); + WINML_EXPECT_NO_THROW( + D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(device.put())) + ); auto d3d12_resource = CreateD3D12Resource(*device); void* gpu_allocation; @@ -164,14 +170,22 @@ void DmlGetD3D12ResourceFromAllocation() { auto session = CreateDmlSession(); OrtMemoryInfo* ort_memory_info; - THROW_IF_NOT_OK_MSG(ort_api->CreateMemoryInfo("DML", OrtAllocatorType::OrtDeviceAllocator, 0, OrtMemType::OrtMemTypeDefault, &ort_memory_info), ort_api); + THROW_IF_NOT_OK_MSG( + ort_api->CreateMemoryInfo( + "DML", OrtAllocatorType::OrtDeviceAllocator, 0, OrtMemType::OrtMemTypeDefault, &ort_memory_info + ), + ort_api + ); OrtAllocator* ort_allocator; THROW_IF_NOT_OK_MSG(ort_api->CreateAllocator(session.get(), ort_memory_info, &ort_allocator), ort_api); auto allocator = UniqueOrtAllocator(ort_allocator, ort_api->ReleaseAllocator); winrt::com_ptr d3d12_resource_from_allocation; - THROW_IF_NOT_OK_MSG(ort_dml_api->GetD3D12ResourceFromAllocation(allocator.get(), gpu_allocation, d3d12_resource_from_allocation.put()), ort_api); + THROW_IF_NOT_OK_MSG( + ort_dml_api->GetD3D12ResourceFromAllocation(allocator.get(), gpu_allocation, d3d12_resource_from_allocation.put()), + ort_api + ); // Ensure resource is the same WINML_EXPECT_EQUAL(d3d12_resource, d3d12_resource_from_allocation); @@ -180,7 +194,18 @@ void DmlGetD3D12ResourceFromAllocation() { UniqueOrtValue CreateTensorFromMemoryInfo(const OrtMemoryInfo* memory_info) { OrtValue* tensor; - THROW_IF_NOT_OK_MSG(ort_api->CreateTensorWithDataAsOrtValue(memory_info, tensor_values.data(), tensor_size * sizeof(float), dimensions.data(), dimensions.size(), ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, &tensor), ort_api); + THROW_IF_NOT_OK_MSG( + ort_api->CreateTensorWithDataAsOrtValue( + memory_info, + tensor_values.data(), + tensor_size * sizeof(float), + dimensions.data(), + dimensions.size(), + ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, + &tensor + ), + ort_api + ); return UniqueOrtValue(tensor, ort_api->ReleaseValue); } @@ -189,7 +214,12 @@ void GetTensorMemoryInfo() { auto session = CreateDmlSession(); OrtMemoryInfo* ort_memory_info; - THROW_IF_NOT_OK_MSG(ort_api->CreateMemoryInfo("DML", OrtAllocatorType::OrtDeviceAllocator, 0, OrtMemType::OrtMemTypeDefault, &ort_memory_info), ort_api); + THROW_IF_NOT_OK_MSG( + ort_api->CreateMemoryInfo( + "DML", OrtAllocatorType::OrtDeviceAllocator, 0, OrtMemType::OrtMemTypeDefault, &ort_memory_info + ), + ort_api + ); auto tensor = CreateTensorFromMemoryInfo(ort_memory_info); const OrtMemoryInfo* value_memory_info; @@ -211,14 +241,21 @@ void DmlCopyTensor() { THROW_IF_NOT_OK_MSG(ort_api->DisableMemPattern(session_options.get()), ort_api); winrt::com_ptr device; - WINML_EXPECT_NO_THROW(D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(device.put()))); + WINML_EXPECT_NO_THROW( + D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(device.put())) + ); winrt::com_ptr queue; D3D12_COMMAND_QUEUE_DESC command_queue_desc = {}; command_queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; WINML_EXPECT_HRESULT_SUCCEEDED(device->CreateCommandQueue(&command_queue_desc, IID_PPV_ARGS(queue.put()))); - THROW_IF_NOT_OK_MSG(winml_adapter_api->OrtSessionOptionsAppendExecutionProvider_DML(session_options.get(), device.get(), queue.get(), false), ort_api); + THROW_IF_NOT_OK_MSG( + winml_adapter_api->OrtSessionOptionsAppendExecutionProvider_DML( + session_options.get(), device.get(), queue.get(), false + ), + ort_api + ); auto session = CreateUniqueOrtSession(FileHelpers::GetModulePath() + L"fns-candy.onnx", session_options); OrtExecutionProvider* dml_provider; @@ -229,27 +266,39 @@ void DmlCopyTensor() { THROW_IF_NOT_OK_MSG(ort_api->CreateCpuMemoryInfo(OrtDeviceAllocator, OrtMemTypeDefault, &cpu_memory_info), ort_api); auto cpu_tensor = CreateTensorFromMemoryInfo(cpu_memory_info); auto dst_cpu_tensor = CreateTensorFromMemoryInfo(cpu_memory_info); - WINML_EXPECT_NOT_EQUAL(nullptr, winml_adapter_api->DmlCopyTensor(dml_provider, cpu_tensor.get(), dst_cpu_tensor.get())); + WINML_EXPECT_NOT_EQUAL( + nullptr, winml_adapter_api->DmlCopyTensor(dml_provider, cpu_tensor.get(), dst_cpu_tensor.get()) + ); // GPU to CPU OrtMemoryInfo* ort_memory_info; - THROW_IF_NOT_OK_MSG(ort_api->CreateMemoryInfo("DML", OrtAllocatorType::OrtDeviceAllocator, 0, OrtMemType::OrtMemTypeDefault, &ort_memory_info), ort_api); + THROW_IF_NOT_OK_MSG( + ort_api->CreateMemoryInfo( + "DML", OrtAllocatorType::OrtDeviceAllocator, 0, OrtMemType::OrtMemTypeDefault, &ort_memory_info + ), + ort_api + ); auto resource = CreateD3D12Resource(*device); void* dml_allocator_resource; - THROW_IF_NOT_OK_MSG(ort_dml_api->CreateGPUAllocationFromD3DResource(resource.get(), &dml_allocator_resource), ort_api); + THROW_IF_NOT_OK_MSG( + ort_dml_api->CreateGPUAllocationFromD3DResource(resource.get(), &dml_allocator_resource), ort_api + ); std::array shape = {720, 720, 3}; OrtValue* gpu_value; - THROW_IF_NOT_OK_MSG(ort_api->CreateTensorWithDataAsOrtValue( + THROW_IF_NOT_OK_MSG( + ort_api->CreateTensorWithDataAsOrtValue( ort_memory_info, dml_allocator_resource, static_cast(resource->GetDesc().Width), shape.data(), shape.size(), ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, - &gpu_value), - ort_api); + &gpu_value + ), + ort_api + ); dst_cpu_tensor = CreateTensorFromMemoryInfo(cpu_memory_info); THROW_IF_NOT_OK_MSG(winml_adapter_api->DmlCopyTensor(dml_provider, gpu_value, dst_cpu_tensor.get()), ort_api); @@ -268,7 +317,12 @@ void ValueGetDeviceId() { auto session = CreateDmlSession(); OrtMemoryInfo* ort_memory_info; - THROW_IF_NOT_OK_MSG(ort_api->CreateMemoryInfo("DML", OrtAllocatorType::OrtDeviceAllocator, 0, OrtMemType::OrtMemTypeDefault, &ort_memory_info), ort_api); + THROW_IF_NOT_OK_MSG( + ort_api->CreateMemoryInfo( + "DML", OrtAllocatorType::OrtDeviceAllocator, 0, OrtMemType::OrtMemTypeDefault, &ort_memory_info + ), + ort_api + ); auto gpu_tensor = CreateTensorFromMemoryInfo(ort_memory_info); int16_t device_id; @@ -286,20 +340,22 @@ void SessionGetInputRequiredDeviceId() { GPUTEST; auto session = CreateDmlSession(); int16_t device_id; - THROW_IF_NOT_OK_MSG(winml_adapter_api->SessionGetInputRequiredDeviceId(session.get(), "inputImage", &device_id), ort_api); + THROW_IF_NOT_OK_MSG( + winml_adapter_api->SessionGetInputRequiredDeviceId(session.get(), "inputImage", &device_id), ort_api + ); auto cpu_session = CreateCpuSession(); - THROW_IF_NOT_OK_MSG(winml_adapter_api->SessionGetInputRequiredDeviceId(cpu_session.get(), "inputImage", &device_id), ort_api); + THROW_IF_NOT_OK_MSG( + winml_adapter_api->SessionGetInputRequiredDeviceId(cpu_session.get(), "inputImage", &device_id), ort_api + ); WINML_EXPECT_EQUAL(0, device_id); } -} +} // namespace const AdapterDmlEpTestApi& getapi() { - static constexpr AdapterDmlEpTestApi api = - { + static constexpr AdapterDmlEpTestApi api = { AdapterDmlEpTestSetup, AdapterDmlEpTestTeardown, - DmlExecutionProviderSetDefaultRoundingMode, DmlExecutionProviderFlushContext, DmlExecutionProviderReleaseCompletedReferences, DmlCreateAndFreeGPUAllocationFromD3DResource, @@ -309,7 +365,6 @@ const AdapterDmlEpTestApi& getapi() { DmlCopyTensor, CreateCustomRegistry, ValueGetDeviceId, - SessionGetInputRequiredDeviceId - }; + SessionGetInputRequiredDeviceId}; return api; } diff --git a/winml/test/adapter/AdapterDmlEpTest.h b/winml/test/adapter/AdapterDmlEpTest.h index f08bcdc25a409..ecf48998a701d 100644 --- a/winml/test/adapter/AdapterDmlEpTest.h +++ b/winml/test/adapter/AdapterDmlEpTest.h @@ -2,11 +2,9 @@ // Licensed under the MIT License. #include "test.h" -struct AdapterDmlEpTestApi -{ +struct AdapterDmlEpTestApi { SetupTest AdapterDmlEpTestSetup; TeardownClass AdapterDmlEpTestTeardown; - VoidTest DmlExecutionProviderSetDefaultRoundingMode; VoidTest DmlExecutionProviderFlushContext; VoidTest DmlExecutionProviderReleaseCompletedReferences; VoidTest DmlCreateGPUAllocationFromD3DResource; @@ -24,7 +22,6 @@ WINML_TEST_CLASS_BEGIN(AdapterDmlEpTest) WINML_TEST_CLASS_SETUP_METHOD(AdapterDmlEpTestSetup) WINML_TEST_CLASS_TEARDOWN_METHOD(AdapterDmlEpTestTeardown) WINML_TEST_CLASS_BEGIN_TESTS -WINML_TEST(AdapterDmlEpTest, DmlExecutionProviderSetDefaultRoundingMode) WINML_TEST(AdapterDmlEpTest, DmlExecutionProviderFlushContext) WINML_TEST(AdapterDmlEpTest, DmlExecutionProviderReleaseCompletedReferences) WINML_TEST(AdapterDmlEpTest, DmlCreateGPUAllocationFromD3DResource) diff --git a/winml/test/adapter/AdapterSessionTest.cpp b/winml/test/adapter/AdapterSessionTest.cpp index 941157f4f9ecb..1b1a36004264c 100644 --- a/winml/test/adapter/AdapterSessionTest.cpp +++ b/winml/test/adapter/AdapterSessionTest.cpp @@ -37,7 +37,8 @@ void AdapterSessionTestSetup() { #ifdef BUILD_INBOX winrt_activation_handler = WINRT_RoGetActivationFactory; #endif - WINML_EXPECT_HRESULT_SUCCEEDED(Microsoft::WRL::MakeAndInitialize<_winml::OnnxruntimeEngineFactory>(engine_factory.put())); + WINML_EXPECT_HRESULT_SUCCEEDED(Microsoft::WRL::MakeAndInitialize<_winml::OnnxruntimeEngineFactory>(engine_factory.put( + ))); WINML_EXPECT_HRESULT_SUCCEEDED(engine_factory->GetOrtEnvironment(&ort_env)); WINML_EXPECT_NOT_EQUAL(nullptr, winml_adapter_api = engine_factory->UseWinmlAdapterApi()); WINML_EXPECT_NOT_EQUAL(nullptr, ort_api = engine_factory->UseOrtApi()); @@ -48,19 +49,23 @@ void AdapterSessionTestTeardown() { } UniqueOrtSessionOptions CreateUniqueOrtSessionOptions() { - OrtSessionOptions *options; + OrtSessionOptions* options; THROW_IF_NOT_OK_MSG(ort_api->CreateSessionOptions(&options), ort_api); return UniqueOrtSessionOptions(options, ort_api->ReleaseSessionOptions); } void AppendExecutionProvider_CPU() { const auto session_options = CreateUniqueOrtSessionOptions(); - THROW_IF_NOT_OK_MSG(winml_adapter_api->OrtSessionOptionsAppendExecutionProvider_CPU(session_options.get(), true), ort_api); + THROW_IF_NOT_OK_MSG( + winml_adapter_api->OrtSessionOptionsAppendExecutionProvider_CPU(session_options.get(), true), ort_api + ); } winrt::com_ptr CreateD3DDevice() { winrt::com_ptr device; - WINML_EXPECT_NO_THROW(D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(device.put()))); + WINML_EXPECT_NO_THROW( + D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(device.put())) + ); return device; } @@ -74,15 +79,21 @@ winrt::com_ptr CreateD3DQueue(ID3D12Device* device) { UniqueOrtSession CreateUniqueOrtSession(const UniqueOrtSessionOptions& session_options) { OrtSession* session; - THROW_IF_NOT_OK_MSG(winml_adapter_api->CreateSessionWithoutModel(ort_env, session_options.get(), nullptr, nullptr, &session), ort_api); + THROW_IF_NOT_OK_MSG( + winml_adapter_api->CreateSessionWithoutModel(ort_env, session_options.get(), nullptr, nullptr, &session), ort_api + ); return UniqueOrtSession(session, ort_api->ReleaseSession); } -UniqueOrtSession CreateUniqueOrtSession(const std::wstring& model_path, const UniqueOrtSessionOptions& session_options) { +UniqueOrtSession CreateUniqueOrtSession( + const std::wstring& model_path, const UniqueOrtSessionOptions& session_options +) { OrtSession* session; ort_api->SetIntraOpNumThreads(session_options.get(), 1); ort_api->SetSessionGraphOptimizationLevel(session_options.get(), ORT_ENABLE_BASIC); - THROW_IF_NOT_OK_MSG(winml_adapter_api->OrtSessionOptionsAppendExecutionProvider_CPU(session_options.get(), true), ort_api); + THROW_IF_NOT_OK_MSG( + winml_adapter_api->OrtSessionOptionsAppendExecutionProvider_CPU(session_options.get(), true), ort_api + ); THROW_IF_NOT_OK_MSG(ort_api->CreateSession(ort_env, model_path.c_str(), session_options.get(), &session), ort_api); return UniqueOrtSession(session, ort_api->ReleaseSession); } @@ -92,7 +103,12 @@ void AppendExecutionProvider_DML() { const auto device = CreateD3DDevice(); const auto queue = CreateD3DQueue(device.get()); - THROW_IF_NOT_OK_MSG(winml_adapter_api->OrtSessionOptionsAppendExecutionProvider_DML(session_options.get(), device.get(), queue.get(), true), ort_api); + THROW_IF_NOT_OK_MSG( + winml_adapter_api->OrtSessionOptionsAppendExecutionProvider_DML( + session_options.get(), device.get(), queue.get(), true + ), + ort_api + ); } void CreateWithoutModel() { @@ -114,7 +130,12 @@ void GetExecutionProvider_DML() { THROW_IF_NOT_OK_MSG(ort_api->DisableMemPattern(session_options.get()), ort_api); const auto device = CreateD3DDevice(); const auto queue = CreateD3DQueue(device.get()); - THROW_IF_NOT_OK_MSG(winml_adapter_api->OrtSessionOptionsAppendExecutionProvider_DML(session_options.get(), device.get(), queue.get(), true), ort_api); + THROW_IF_NOT_OK_MSG( + winml_adapter_api->OrtSessionOptionsAppendExecutionProvider_DML( + session_options.get(), device.get(), queue.get(), true + ), + ort_api + ); const auto model_path = FileHelpers::GetModulePath() + L"fns-candy.onnx"; auto session = CreateUniqueOrtSession(model_path, session_options); @@ -195,19 +216,20 @@ void Profiling() { const auto logging_callback = [](void*, OrtLoggingLevel, const char*, const char*, const char*, const char*) { logging_called = true; }; - const auto profile_callback = [](const OrtProfilerEventRecord*) { - profile_called = true; - }; + const auto profile_callback = [](const OrtProfilerEventRecord*) { profile_called = true; }; - THROW_IF_NOT_OK_MSG(winml_adapter_api->EnvConfigureCustomLoggerAndProfiler( + THROW_IF_NOT_OK_MSG( + winml_adapter_api->EnvConfigureCustomLoggerAndProfiler( ort_env, logging_callback, profile_callback, nullptr, OrtLoggingLevel::ORT_LOGGING_LEVEL_VERBOSE, "Default", - &ort_env), - ort_api); + &ort_env + ), + ort_api + ); const auto session_options = CreateUniqueOrtSessionOptions(); auto session = CreateUniqueOrtSession(session_options); @@ -229,20 +251,34 @@ void CopyInputAcrossDevices() { for (auto dim : dimensions) size *= static_cast(dim); return size; - } (); + }(); OrtMemoryInfo* memory_info; THROW_IF_NOT_OK_MSG(ort_api->CreateCpuMemoryInfo(OrtArenaAllocator, OrtMemTypeDefault, &memory_info), ort_api); std::vector input_tensor_values(input_tensor_size); OrtValue* input_tensor; - THROW_IF_NOT_OK_MSG(ort_api->CreateTensorWithDataAsOrtValue(memory_info, input_tensor_values.data(), input_tensor_size * sizeof(float), dimensions.data(), 4, ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, &input_tensor), ort_api); + THROW_IF_NOT_OK_MSG( + ort_api->CreateTensorWithDataAsOrtValue( + memory_info, + input_tensor_values.data(), + input_tensor_size * sizeof(float), + dimensions.data(), + 4, + ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, + &input_tensor + ), + ort_api + ); int is_tensor; THROW_IF_NOT_OK_MSG(ort_api->IsTensor(input_tensor, &is_tensor), ort_api); WINML_EXPECT_TRUE(is_tensor); OrtValue* dest_ort_value; - THROW_IF_NOT_OK_MSG(winml_adapter_api->SessionCopyOneInputAcrossDevices(session.get(), "inputImage", input_tensor, &dest_ort_value), ort_api); + THROW_IF_NOT_OK_MSG( + winml_adapter_api->SessionCopyOneInputAcrossDevices(session.get(), "inputImage", input_tensor, &dest_ort_value), + ort_api + ); ort_api->ReleaseValue(input_tensor); ort_api->ReleaseValue(dest_ort_value); @@ -254,7 +290,12 @@ void CopyInputAcrossDevices_DML() { THROW_IF_NOT_OK_MSG(ort_api->DisableMemPattern(session_options.get()), ort_api); const auto device = CreateD3DDevice(); const auto queue = CreateD3DQueue(device.get()); - THROW_IF_NOT_OK_MSG(winml_adapter_api->OrtSessionOptionsAppendExecutionProvider_DML(session_options.get(), device.get(), queue.get(), true), ort_api); + THROW_IF_NOT_OK_MSG( + winml_adapter_api->OrtSessionOptionsAppendExecutionProvider_DML( + session_options.get(), device.get(), queue.get(), true + ), + ort_api + ); auto session = CreateUniqueOrtSession(session_options); LoadAndPurloinModel(session, "fns-candy.onnx"); @@ -265,26 +306,40 @@ void CopyInputAcrossDevices_DML() { for (auto dim : dimensions) size *= static_cast(dim); return size; - } (); + }(); OrtMemoryInfo* memory_info; THROW_IF_NOT_OK_MSG(ort_api->CreateCpuMemoryInfo(OrtArenaAllocator, OrtMemTypeDefault, &memory_info), ort_api); std::vector input_tensor_values(input_tensor_size); OrtValue* input_tensor; - THROW_IF_NOT_OK_MSG(ort_api->CreateTensorWithDataAsOrtValue(memory_info, input_tensor_values.data(), input_tensor_size * sizeof(float), dimensions.data(), 4, ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, &input_tensor), ort_api); + THROW_IF_NOT_OK_MSG( + ort_api->CreateTensorWithDataAsOrtValue( + memory_info, + input_tensor_values.data(), + input_tensor_size * sizeof(float), + dimensions.data(), + 4, + ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, + &input_tensor + ), + ort_api + ); int is_tensor; THROW_IF_NOT_OK_MSG(ort_api->IsTensor(input_tensor, &is_tensor), ort_api); WINML_EXPECT_TRUE(is_tensor); OrtValue* dest_ort_value = nullptr; - THROW_IF_NOT_OK_MSG(winml_adapter_api->SessionCopyOneInputAcrossDevices(session.get(), "inputImage", input_tensor, &dest_ort_value), ort_api); + THROW_IF_NOT_OK_MSG( + winml_adapter_api->SessionCopyOneInputAcrossDevices(session.get(), "inputImage", input_tensor, &dest_ort_value), + ort_api + ); ort_api->ReleaseValue(input_tensor); ort_api->ReleaseMemoryInfo(memory_info); } -void GetNumberOfIntraOpThreads(){ +void GetNumberOfIntraOpThreads() { const auto session_options = CreateUniqueOrtSessionOptions(); uint32_t desired_num_threads = std::thread::hardware_concurrency() / 2; ort_api->SetIntraOpNumThreads(session_options.get(), desired_num_threads); @@ -293,11 +348,10 @@ void GetNumberOfIntraOpThreads(){ winml_adapter_api->SessionGetNumberOfIntraOpThreads(session.get(), &num_threads); WINML_EXPECT_EQUAL(num_threads, desired_num_threads); } -} +} // namespace const AdapterSessionTestAPI& getapi() { - static AdapterSessionTestAPI api = - { + static AdapterSessionTestAPI api = { AdapterSessionTestSetup, AdapterSessionTestTeardown, AppendExecutionProvider_CPU, @@ -314,8 +368,7 @@ const AdapterSessionTestAPI& getapi() { Profiling, CopyInputAcrossDevices, CopyInputAcrossDevices_DML, - GetNumberOfIntraOpThreads - }; + GetNumberOfIntraOpThreads}; if (SkipGpuTests()) { api.AppendExecutionProvider_DML = SkipTest; diff --git a/winml/test/adapter/AdapterSessionTest.h b/winml/test/adapter/AdapterSessionTest.h index 413005e249ae2..1e7581b7c84d1 100644 --- a/winml/test/adapter/AdapterSessionTest.h +++ b/winml/test/adapter/AdapterSessionTest.h @@ -2,8 +2,7 @@ // Licensed under the MIT License. #include "test.h" -struct AdapterSessionTestAPI -{ +struct AdapterSessionTestAPI { SetupClass AdapterSessionTestSetup; TeardownClass AdapterSessionTestTeardown; VoidTest AppendExecutionProvider_CPU; diff --git a/winml/test/adapter/adapter_test.cpp b/winml/test/adapter/adapter_test.cpp index 814db0fd12a5e..ebab160d40203 100644 --- a/winml/test/adapter/adapter_test.cpp +++ b/winml/test/adapter/adapter_test.cpp @@ -13,12 +13,16 @@ static void AdapterTestSetup() { #endif ort_api = OrtGetApiBase()->GetApi(ORT_API_VERSION); winml_adapter_api = OrtGetWinMLAdapter(ORT_API_VERSION); - + // for model tests std::wstring module_path = FileHelpers::GetModulePath(); - std::string squeezenet_path = std::wstring_convert>().to_bytes(module_path + L"squeezenet_modifiedforruntimestests.onnx"); - std::string metadata_path = std::wstring_convert>().to_bytes(module_path + L"modelWith2MetaData.onnx"); - std::string float16_path = std::wstring_convert>().to_bytes(module_path + L"starry-night-fp16.onnx"); + std::string squeezenet_path = std::wstring_convert>().to_bytes( + module_path + L"squeezenet_modifiedforruntimestests.onnx" + ); + std::string metadata_path = + std::wstring_convert>().to_bytes(module_path + L"modelWith2MetaData.onnx"); + std::string float16_path = + std::wstring_convert>().to_bytes(module_path + L"starry-night-fp16.onnx"); winml_adapter_api->CreateModelFromPath(squeezenet_path.c_str(), squeezenet_path.size(), &squeezenet_model); winml_adapter_api->CreateModelFromPath(metadata_path.c_str(), metadata_path.size(), &metadata_model); winml_adapter_api->CreateModelFromPath(float16_path.c_str(), float16_path.size(), &float16_Model); @@ -168,7 +172,7 @@ static void ModelGetInputTypeInfo() { ort_api->GetDimensionsCount(tensor_info, &dim_count); WINML_EXPECT_EQUAL(dim_count, 4u); - int64_t dim_values[4]; + int64_t dim_values[4]; ort_api->GetDimensions(tensor_info, dim_values, 4); WINML_EXPECT_EQUAL(dim_values[0], 1); WINML_EXPECT_EQUAL(dim_values[1], 3); @@ -219,13 +223,17 @@ static void ModelGetMetadata() { const char* metadata_value; size_t metadata_value_len; - winml_adapter_api->ModelGetMetadata(metadata_model, 0, &metadata_key, &metadata_key_len, &metadata_value, &metadata_value_len); + winml_adapter_api->ModelGetMetadata( + metadata_model, 0, &metadata_key, &metadata_key_len, &metadata_value, &metadata_value_len + ); WINML_EXPECT_EQUAL(std::string(metadata_key), "thisisalongkey"); WINML_EXPECT_EQUAL(metadata_key_len, 14u); WINML_EXPECT_EQUAL(std::string(metadata_value), "thisisalongvalue"); WINML_EXPECT_EQUAL(metadata_value_len, 16u); - winml_adapter_api->ModelGetMetadata(metadata_model, 1, &metadata_key, &metadata_key_len, &metadata_value, &metadata_value_len); + winml_adapter_api->ModelGetMetadata( + metadata_model, 1, &metadata_key, &metadata_key_len, &metadata_value, &metadata_value_len + ); WINML_EXPECT_EQUAL(std::string(metadata_key), "key2"); WINML_EXPECT_EQUAL(metadata_key_len, 4u); WINML_EXPECT_EQUAL(std::string(metadata_value), "val2"); @@ -243,8 +251,14 @@ static void ModelEnsureNoFloat16() { WINML_EXPECT_EQUAL(ort_api->GetErrorCode(float16_error_status), ORT_INVALID_GRAPH); } -static void __stdcall TestLoggingCallback(void* param, OrtLoggingLevel severity, const char* category, - const char* logger_id, const char* code_location, const char* message) noexcept { +static void __stdcall TestLoggingCallback( + void* param, + OrtLoggingLevel severity, + const char* category, + const char* logger_id, + const char* code_location, + const char* message +) noexcept { UNREFERENCED_PARAMETER(param); UNREFERENCED_PARAMETER(severity); UNREFERENCED_PARAMETER(category); @@ -262,9 +276,15 @@ static void __stdcall TestProfileEventCallback(const OrtProfilerEventRecord* pro static void EnvConfigureCustomLoggerAndProfiler() { OrtEnv* ort_env = nullptr; ort_api->CreateEnv(OrtLoggingLevel::ORT_LOGGING_LEVEL_VERBOSE, "Default", &ort_env); - winml_adapter_api->EnvConfigureCustomLoggerAndProfiler(ort_env, - &TestLoggingCallback, &TestProfileEventCallback, nullptr, - OrtLoggingLevel::ORT_LOGGING_LEVEL_VERBOSE, "Default", &ort_env); + winml_adapter_api->EnvConfigureCustomLoggerAndProfiler( + ort_env, + &TestLoggingCallback, + &TestProfileEventCallback, + nullptr, + OrtLoggingLevel::ORT_LOGGING_LEVEL_VERBOSE, + "Default", + &ort_env + ); logging_function_called = false; OrtSession* ort_session = nullptr; std::wstring squeezenet_path = FileHelpers::GetModulePath() + L"relu.onnx"; @@ -286,7 +306,15 @@ static void EnvConfigureCustomLoggerAndProfiler() { OrtMemoryInfo* memory_info; ort_api->CreateCpuMemoryInfo(OrtArenaAllocator, OrtMemTypeDefault, &memory_info); OrtValue* input_tensor = nullptr; - ort_api->CreateTensorWithDataAsOrtValue(memory_info, input_tensor_values.data(), input_tensor_size * sizeof(float), input_dimensions, 1, ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, &input_tensor); + ort_api->CreateTensorWithDataAsOrtValue( + memory_info, + input_tensor_values.data(), + input_tensor_size * sizeof(float), + input_dimensions, + 1, + ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, + &input_tensor + ); int is_tensor; ort_api->IsTensor(input_tensor, &is_tensor); assert(is_tensor); @@ -294,7 +322,16 @@ static void EnvConfigureCustomLoggerAndProfiler() { OrtValue* output_tensor = nullptr; winml_adapter_api->SessionStartProfiling(ort_env, ort_session); profiling_function_called = false; - ort_api->Run(ort_session, nullptr, input_node_names.data(), (const OrtValue* const*)&input_tensor, 1, output_node_names.data(), 1, &output_tensor); + ort_api->Run( + ort_session, + nullptr, + input_node_names.data(), + (const OrtValue* const*)&input_tensor, + 1, + output_node_names.data(), + 1, + &output_tensor + ); WINML_EXPECT_TRUE(profiling_function_called); winml_adapter_api->SessionEndProfiling(ort_session); @@ -305,30 +342,29 @@ static void EnvConfigureCustomLoggerAndProfiler() { } const AdapterTestApi& getapi() { - static constexpr AdapterTestApi api = - { - AdapterTestSetup, - AdapterTestTeardown, - CreateModelFromPath, - CreateModelFromData, - CloneModel, - ModelGetAuthor, - ModelGetName, - ModelGetDomain, - ModelGetDescription, - ModelGetVersion, - ModelGetInputCount, - ModelGetOutputCount, - ModelGetInputName, - ModelGetOutputName, - ModelGetInputDescription, - ModelGetOutputDescription, - ModelGetInputTypeInfo, - ModelGetOutputTypeInfo, - ModelGetMetadataCount, - ModelGetMetadata, - ModelEnsureNoFloat16, - EnvConfigureCustomLoggerAndProfiler, - }; + static constexpr AdapterTestApi api = { + AdapterTestSetup, + AdapterTestTeardown, + CreateModelFromPath, + CreateModelFromData, + CloneModel, + ModelGetAuthor, + ModelGetName, + ModelGetDomain, + ModelGetDescription, + ModelGetVersion, + ModelGetInputCount, + ModelGetOutputCount, + ModelGetInputName, + ModelGetOutputName, + ModelGetInputDescription, + ModelGetOutputDescription, + ModelGetInputTypeInfo, + ModelGetOutputTypeInfo, + ModelGetMetadataCount, + ModelGetMetadata, + ModelEnsureNoFloat16, + EnvConfigureCustomLoggerAndProfiler, + }; return api; } diff --git a/winml/test/adapter/adapter_test.h b/winml/test/adapter/adapter_test.h index f4814afa0db3e..cc6dce887bc87 100644 --- a/winml/test/adapter/adapter_test.h +++ b/winml/test/adapter/adapter_test.h @@ -5,8 +5,7 @@ #include "core/providers/winml/winml_provider_factory.h" #include "winml_adapter_c_api.h" -struct AdapterTestApi -{ +struct AdapterTestApi { SetupClass AdapterTestSetup; TeardownClass AdapterTestTeardown; VoidTest CreateModelFromPath; diff --git a/winml/test/api/APITest.h b/winml/test/api/APITest.h index e2f6b959c58fc..cd48c263fdaa4 100644 --- a/winml/test/api/APITest.h +++ b/winml/test/api/APITest.h @@ -7,8 +7,7 @@ #include "winrt_headers.h" namespace APITest { -static void LoadModel(const std::wstring& modelPath, - winml::LearningModel& learningModel) { +static void LoadModel(const std::wstring& modelPath, winml::LearningModel& learningModel) { std::wstring fullPath = FileHelpers::GetModulePath() + modelPath; learningModel = winml::LearningModel::LoadFromFilePath(fullPath); }; diff --git a/winml/test/api/LearningModelAPITest.cpp b/winml/test/api/LearningModelAPITest.cpp index 447b98137bb91..ab45e2414854d 100644 --- a/winml/test/api/LearningModelAPITest.cpp +++ b/winml/test/api/LearningModelAPITest.cpp @@ -27,7 +27,8 @@ static void CreateModelFromFilePath() { static void CreateModelFromUnicodeFilePath() { LearningModel learningModel = nullptr; - WINML_EXPECT_NO_THROW(APITest::LoadModel(L"UnicodePath\\\u3053\u3093\u306B\u3061\u306F maçã\\foo.onnx", learningModel)); + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"UnicodePath\\\u3053\u3093\u306B\u3061\u306F maçã\\foo.onnx", learningModel) + ); } static void CreateModelFileNotFound() { @@ -36,9 +37,8 @@ static void CreateModelFileNotFound() { WINML_EXPECT_THROW_SPECIFIC( APITest::LoadModel(L"missing_model.onnx", learningModel), winrt::hresult_error, - [](const winrt::hresult_error& e) -> bool { - return e.code() == __HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); - }); + [](const winrt::hresult_error& e) -> bool { return e.code() == __HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); } + ); } static void CreateCorruptModel() { @@ -47,9 +47,8 @@ static void CreateCorruptModel() { WINML_EXPECT_THROW_SPECIFIC( APITest::LoadModel(L"corrupt-model.onnx", learningModel), winrt::hresult_error, - [](const winrt::hresult_error& e) -> bool { - return e.code() == __HRESULT_FROM_WIN32(ERROR_FILE_CORRUPT); - }); + [](const winrt::hresult_error& e) -> bool { return e.code() == __HRESULT_FROM_WIN32(ERROR_FILE_CORRUPT); } + ); } static void CreateModelFromIStorage() { @@ -243,17 +242,14 @@ static void CloseModelCheckMetadata() { } static void CheckLearningModelPixelRange() { - std::vector modelPaths = { - // NominalRange_0_255 and image output - L"Add_ImageNet1920WithImageMetadataBgr8_SRGB_0_255.onnx", - // Normalized_0_1 and image output - L"Add_ImageNet1920WithImageMetadataBgr8_SRGB_0_1.onnx", - // Normalized_1_1 and image output - L"Add_ImageNet1920WithImageMetadataBgr8_SRGB_1_1.onnx"}; + std::vector modelPaths = {// NominalRange_0_255 and image output + L"Add_ImageNet1920WithImageMetadataBgr8_SRGB_0_255.onnx", + // Normalized_0_1 and image output + L"Add_ImageNet1920WithImageMetadataBgr8_SRGB_0_1.onnx", + // Normalized_1_1 and image output + L"Add_ImageNet1920WithImageMetadataBgr8_SRGB_1_1.onnx"}; std::vector pixelRanges = { - LearningModelPixelRange::ZeroTo255, - LearningModelPixelRange::ZeroToOne, - LearningModelPixelRange::MinusOneToOne}; + LearningModelPixelRange::ZeroTo255, LearningModelPixelRange::ZeroToOne, LearningModelPixelRange::MinusOneToOne}; for (uint32_t model_i = 0; model_i < modelPaths.size(); model_i++) { LearningModel learningModel = nullptr; WINML_EXPECT_NO_THROW(APITest::LoadModel(modelPaths[model_i], learningModel)); @@ -298,11 +294,10 @@ static void CloseModelNoNewSessions() { WINML_EXPECT_NO_THROW(learningModel.Close()); LearningModelSession session = nullptr; WINML_EXPECT_THROW_SPECIFIC( - session = LearningModelSession(learningModel), - winrt::hresult_error, - [](const winrt::hresult_error& e) -> bool { - return e.code() == E_INVALIDARG; - }); + session = LearningModelSession(learningModel), + winrt::hresult_error, + [](const winrt::hresult_error& e) -> bool { return e.code() == E_INVALIDARG; } + ); } static void CheckMetadataCaseInsensitive() { @@ -314,8 +309,7 @@ static void CheckMetadataCaseInsensitive() { } const LearningModelApiTestsApi& getapi() { - static LearningModelApiTestsApi api = - { + static LearningModelApiTestsApi api = { LearningModelAPITestsClassSetup, CreateModelFromFilePath, CreateModelFromUnicodeFilePath, @@ -335,8 +329,7 @@ const LearningModelApiTestsApi& getapi() { CloseModelCheckEval, CloseModelNoNewSessions, CheckMetadataCaseInsensitive, - CreateCorruptModel - }; + CreateCorruptModel}; if (RuntimeParameterExists(L"noVideoFrameTests")) { api.CloseModelCheckEval = SkipTest; diff --git a/winml/test/api/LearningModelAPITest.h b/winml/test/api/LearningModelAPITest.h index c87bdd6144511..478c3e784d068 100644 --- a/winml/test/api/LearningModelAPITest.h +++ b/winml/test/api/LearningModelAPITest.h @@ -2,8 +2,7 @@ // Licensed under the MIT License. #include "test.h" -struct LearningModelApiTestsApi -{ +struct LearningModelApiTestsApi { SetupClass LearningModelAPITestsClassSetup; VoidTest CreateModelFromFilePath; VoidTest CreateModelFromUnicodeFilePath; @@ -49,4 +48,4 @@ WINML_TEST(LearningModelAPITests, CloseModelNoNewSessions) WINML_TEST(LearningModelAPITests, CloseModelCheckEval) WINML_TEST(LearningModelAPITests, CheckMetadataCaseInsensitive) WINML_TEST(LearningModelAPITests, CreateCorruptModel) -WINML_TEST_CLASS_END() \ No newline at end of file +WINML_TEST_CLASS_END() diff --git a/winml/test/api/LearningModelBindingAPITest.cpp b/winml/test/api/LearningModelBindingAPITest.cpp index 82f1f2d6e54a9..b77421e191020 100644 --- a/winml/test/api/LearningModelBindingAPITest.cpp +++ b/winml/test/api/LearningModelBindingAPITest.cpp @@ -23,627 +23,559 @@ static void LearningModelBindingAPITestsClassSetup() { #endif } -static void CpuSqueezeNet() -{ - std::string cpuInstance("CPU"); - WINML_EXPECT_NO_THROW(WinML::Engine::Test::ModelValidator::SqueezeNet(cpuInstance, LearningModelDeviceKind::Cpu, /*dataTolerance*/ 0.00001f, false)); +static void CpuSqueezeNet() { + std::string cpuInstance("CPU"); + WINML_EXPECT_NO_THROW(WinML::Engine::Test::ModelValidator::SqueezeNet( + cpuInstance, + LearningModelDeviceKind::Cpu, + /*dataTolerance*/ 0.00001f, + false + )); } -static void CpuSqueezeNetEmptyOutputs() -{ - std::string cpuInstance("CPU"); - WINML_EXPECT_NO_THROW( - WinML::Engine::Test::ModelValidator::SqueezeNet( - cpuInstance, - LearningModelDeviceKind::Cpu, - /*dataTolerance*/ 0.00001f, - false, - OutputBindingStrategy::Empty); - ); +static void CpuSqueezeNetEmptyOutputs() { + std::string cpuInstance("CPU"); + WINML_EXPECT_NO_THROW(WinML::Engine::Test::ModelValidator::SqueezeNet( + cpuInstance, + LearningModelDeviceKind::Cpu, + /*dataTolerance*/ 0.00001f, + false, + OutputBindingStrategy::Empty + );); } -static void CpuSqueezeNetUnboundOutputs() -{ - std::string cpuInstance("CPU"); - WINML_EXPECT_NO_THROW( - WinML::Engine::Test::ModelValidator::SqueezeNet( - cpuInstance, - LearningModelDeviceKind::Cpu, - /*dataTolerance*/ 0.00001f, - false, - OutputBindingStrategy::Unbound); - ); +static void CpuSqueezeNetUnboundOutputs() { + std::string cpuInstance("CPU"); + WINML_EXPECT_NO_THROW(WinML::Engine::Test::ModelValidator::SqueezeNet( + cpuInstance, + LearningModelDeviceKind::Cpu, + /*dataTolerance*/ 0.00001f, + false, + OutputBindingStrategy::Unbound + );); } -static void CpuSqueezeNetBindInputTensorAsInspectable() -{ - std::string cpuInstance("CPU"); - WINML_EXPECT_NO_THROW( - WinML::Engine::Test::ModelValidator::SqueezeNet( - cpuInstance, - LearningModelDeviceKind::Cpu, - /*dataTolerance*/ 0.00001f, - false, - OutputBindingStrategy::Bound /* empty outputs */, - true /* bind inputs as inspectables */); - ); +static void CpuSqueezeNetBindInputTensorAsInspectable() { + std::string cpuInstance("CPU"); + WINML_EXPECT_NO_THROW(WinML::Engine::Test::ModelValidator::SqueezeNet( + cpuInstance, + LearningModelDeviceKind::Cpu, + /*dataTolerance*/ 0.00001f, + false, + OutputBindingStrategy::Bound /* empty outputs */, + true /* bind inputs as inspectables */ + );); } -static void CastMapInt64() -{ - WINML_EXPECT_NO_THROW(LearningModel::LoadFromFilePath(FileHelpers::GetModulePath() + L"castmap-int64.onnx")); - // TODO: Check Descriptor +static void CastMapInt64() { + WINML_EXPECT_NO_THROW(LearningModel::LoadFromFilePath(FileHelpers::GetModulePath() + L"castmap-int64.onnx")); + // TODO: Check Descriptor } -static void DictionaryVectorizerMapInt64() -{ - LearningModel learningModel = nullptr; - WINML_EXPECT_NO_THROW(APITest::LoadModel(L"dictvectorizer-int64.onnx", learningModel)); - - auto inputDescriptor = learningModel.InputFeatures().First().Current(); - WINML_EXPECT_TRUE(inputDescriptor.Kind() == LearningModelFeatureKind::Map); - auto mapDescriptor = inputDescriptor.as(); - WINML_EXPECT_TRUE(mapDescriptor.KeyKind() == TensorKind::Int64); - WINML_EXPECT_TRUE(mapDescriptor.ValueDescriptor().Kind() == LearningModelFeatureKind::Tensor); - auto tensorDescriptor = mapDescriptor.ValueDescriptor().as(); - // empty size means tensor of scalar value - WINML_EXPECT_TRUE(tensorDescriptor.Shape().Size() == 0); - WINML_EXPECT_TRUE(tensorDescriptor.TensorKind() == TensorKind::Float); - - LearningModelSession modelSession(learningModel); - LearningModelBinding binding(modelSession); - std::unordered_map map; - map[1] = 1.f; - map[10] = 10.f; - map[3] = 3.f; - - - auto mapInputName = inputDescriptor.Name(); - - // Bind as IMap - auto abiMap = winrt::single_threaded_map(std::move(map)); - binding.Bind(mapInputName, abiMap); - auto mapInputInspectable = abiMap.as(); - auto first = binding.First(); - WINML_EXPECT_TRUE(first.Current().Key() == mapInputName); - WINML_EXPECT_TRUE(first.Current().Value() == mapInputInspectable); - WINML_EXPECT_TRUE(binding.Lookup(mapInputName) == mapInputInspectable); - - // Bind as IMapView - auto mapView = abiMap.GetView(); - binding.Bind(mapInputName, mapView); - mapInputInspectable = mapView.as(); - first = binding.First(); - WINML_EXPECT_TRUE(first.Current().Key() == mapInputName); - WINML_EXPECT_TRUE(first.Current().Value() == mapView); - WINML_EXPECT_TRUE(binding.Lookup(mapInputName) == mapView); - +static void DictionaryVectorizerMapInt64() { + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"dictvectorizer-int64.onnx", learningModel)); + + auto inputDescriptor = learningModel.InputFeatures().First().Current(); + WINML_EXPECT_TRUE(inputDescriptor.Kind() == LearningModelFeatureKind::Map); + auto mapDescriptor = inputDescriptor.as(); + WINML_EXPECT_TRUE(mapDescriptor.KeyKind() == TensorKind::Int64); + WINML_EXPECT_TRUE(mapDescriptor.ValueDescriptor().Kind() == LearningModelFeatureKind::Tensor); + auto tensorDescriptor = mapDescriptor.ValueDescriptor().as(); + // empty size means tensor of scalar value + WINML_EXPECT_TRUE(tensorDescriptor.Shape().Size() == 0); + WINML_EXPECT_TRUE(tensorDescriptor.TensorKind() == TensorKind::Float); + + LearningModelSession modelSession(learningModel); + LearningModelBinding binding(modelSession); + std::unordered_map map; + map[1] = 1.f; + map[10] = 10.f; + map[3] = 3.f; + + auto mapInputName = inputDescriptor.Name(); + + // Bind as IMap + auto abiMap = winrt::single_threaded_map(std::move(map)); + binding.Bind(mapInputName, abiMap); + auto mapInputInspectable = abiMap.as(); + auto first = binding.First(); + WINML_EXPECT_TRUE(first.Current().Key() == mapInputName); + WINML_EXPECT_TRUE(first.Current().Value() == mapInputInspectable); + WINML_EXPECT_TRUE(binding.Lookup(mapInputName) == mapInputInspectable); + + // Bind as IMapView + auto mapView = abiMap.GetView(); + binding.Bind(mapInputName, mapView); + mapInputInspectable = mapView.as(); + first = binding.First(); + WINML_EXPECT_TRUE(first.Current().Key() == mapInputName); + WINML_EXPECT_TRUE(first.Current().Value() == mapView); + WINML_EXPECT_TRUE(binding.Lookup(mapInputName) == mapView); } -static void DictionaryVectorizerMapString() -{ - LearningModel learningModel = nullptr; - WINML_EXPECT_NO_THROW(APITest::LoadModel(L"dictvectorizer-string.onnx", learningModel)); - - auto inputDescriptor = learningModel.InputFeatures().First().Current(); - WINML_EXPECT_TRUE(inputDescriptor.Kind() == LearningModelFeatureKind::Map); - - auto mapDescriptor = inputDescriptor.as(); - WINML_EXPECT_TRUE(mapDescriptor.KeyKind() == TensorKind::String); - WINML_EXPECT_TRUE(mapDescriptor.ValueDescriptor().Kind() == LearningModelFeatureKind::Tensor); - - auto tensorDescriptor = mapDescriptor.ValueDescriptor().as(); - // empty size means tensor of scalar value - WINML_EXPECT_TRUE(tensorDescriptor.Shape().Size() == 0); - WINML_EXPECT_TRUE(tensorDescriptor.TensorKind() == TensorKind::Float); - - LearningModelSession modelSession(learningModel); - LearningModelBinding binding(modelSession); - std::unordered_map map; - map[L"1"] = 1.f; - map[L"10"] = 10.f; - map[L"2"] = 2.f; - - auto mapInputName = inputDescriptor.Name(); - auto abiMap = winrt::single_threaded_map(std::move(map)); - binding.Bind(mapInputName, abiMap); - - auto mapInputInspectable = abiMap.as(); - auto first = binding.First(); - WINML_EXPECT_TRUE(first.Current().Key() == mapInputName); - WINML_EXPECT_TRUE(first.Current().Value() == mapInputInspectable); - WINML_EXPECT_TRUE(binding.Lookup(mapInputName) == mapInputInspectable); - - modelSession.Evaluate(binding, L""); +static void DictionaryVectorizerMapString() { + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"dictvectorizer-string.onnx", learningModel)); + + auto inputDescriptor = learningModel.InputFeatures().First().Current(); + WINML_EXPECT_TRUE(inputDescriptor.Kind() == LearningModelFeatureKind::Map); + + auto mapDescriptor = inputDescriptor.as(); + WINML_EXPECT_TRUE(mapDescriptor.KeyKind() == TensorKind::String); + WINML_EXPECT_TRUE(mapDescriptor.ValueDescriptor().Kind() == LearningModelFeatureKind::Tensor); + + auto tensorDescriptor = mapDescriptor.ValueDescriptor().as(); + // empty size means tensor of scalar value + WINML_EXPECT_TRUE(tensorDescriptor.Shape().Size() == 0); + WINML_EXPECT_TRUE(tensorDescriptor.TensorKind() == TensorKind::Float); + + LearningModelSession modelSession(learningModel); + LearningModelBinding binding(modelSession); + std::unordered_map map; + map[L"1"] = 1.f; + map[L"10"] = 10.f; + map[L"2"] = 2.f; + + auto mapInputName = inputDescriptor.Name(); + auto abiMap = winrt::single_threaded_map(std::move(map)); + binding.Bind(mapInputName, abiMap); + + auto mapInputInspectable = abiMap.as(); + auto first = binding.First(); + WINML_EXPECT_TRUE(first.Current().Key() == mapInputName); + WINML_EXPECT_TRUE(first.Current().Value() == mapInputInspectable); + WINML_EXPECT_TRUE(binding.Lookup(mapInputName) == mapInputInspectable); + + modelSession.Evaluate(binding, L""); } -static void RunZipMapInt64( - winml::LearningModel model, - OutputBindingStrategy bindingStrategy) -{ - auto outputFeatures = model.OutputFeatures(); - auto outputDescriptor = outputFeatures.First().Current(); - WINML_EXPECT_TRUE(outputDescriptor.Kind() == LearningModelFeatureKind::Sequence); - - auto seqDescriptor = outputDescriptor.as(); - auto mapDescriptor = seqDescriptor.ElementDescriptor().as(); - WINML_EXPECT_TRUE(mapDescriptor.KeyKind() == TensorKind::Int64); - - WINML_EXPECT_TRUE(mapDescriptor.ValueDescriptor().Kind() == LearningModelFeatureKind::Tensor); - auto tensorDescriptor = mapDescriptor.ValueDescriptor().as(); - WINML_EXPECT_TRUE(tensorDescriptor.TensorKind() == TensorKind::Float); - - LearningModelSession session(model); - LearningModelBinding binding(session); - - std::vector inputs = { 0.5f, 0.25f, 0.125f }; - std::vector shape = { 1, 3 }; - - // Bind inputs - auto inputTensor = - TensorFloat::CreateFromArray( - shape, - winrt::array_view(std::move(inputs))); - binding.Bind(winrt::hstring(L"X"), inputTensor); - - typedef IMap ABIMap; - typedef IVector ABISequeneceOfMap; - - ABISequeneceOfMap abiOutput = nullptr; - // Bind outputs - if (bindingStrategy == OutputBindingStrategy::Bound) - { - abiOutput = winrt::single_threaded_vector(); - binding.Bind(winrt::hstring(L"Y"), abiOutput); - } +static void RunZipMapInt64(winml::LearningModel model, OutputBindingStrategy bindingStrategy) { + auto outputFeatures = model.OutputFeatures(); + auto outputDescriptor = outputFeatures.First().Current(); + WINML_EXPECT_TRUE(outputDescriptor.Kind() == LearningModelFeatureKind::Sequence); - // Evaluate - auto result = session.Evaluate(binding, L"0").Outputs(); - - if (bindingStrategy == OutputBindingStrategy::Bound) - { - // from output binding - const auto &out1 = abiOutput.GetAt(0); - const auto &out2 = result.Lookup(L"Y").as>().GetAt(0); - WINML_LOG_COMMENT((std::ostringstream() << "size: " << out1.Size()).str()); - // check outputs - auto iter1 = out1.First(); - auto iter2 = out2.First(); - for (uint32_t i = 0, size = (uint32_t)inputs.size(); i < size; ++i) - { - WINML_EXPECT_TRUE(iter1.HasCurrent()); - WINML_EXPECT_TRUE(iter2.HasCurrent()); - const auto &pair1 = iter1.Current(); - const auto &pair2 = iter2.Current(); - WINML_LOG_COMMENT((std::ostringstream() << "key: " << pair1.Key() << ", value: " << pair2.Value()).str()); - WINML_EXPECT_TRUE(pair1.Key() == i && pair2.Key() == i); - WINML_EXPECT_TRUE(pair1.Value() == inputs[i] && pair2.Value() == inputs[i]); - iter1.MoveNext(); - iter2.MoveNext(); - } - WINML_EXPECT_TRUE(!iter1.HasCurrent()); - WINML_EXPECT_TRUE(!iter2.HasCurrent()); - } - else - { - abiOutput = result.Lookup(L"Y").as(); - WINML_EXPECT_TRUE(abiOutput.Size() == 1); - ABIMap map = abiOutput.GetAt(0); - WINML_EXPECT_TRUE(map.Size() == 3); - WINML_EXPECT_TRUE(map.Lookup(0) == 0.5); - WINML_EXPECT_TRUE(map.Lookup(1) == .25); - WINML_EXPECT_TRUE(map.Lookup(2) == .125); - } -} + auto seqDescriptor = outputDescriptor.as(); + auto mapDescriptor = seqDescriptor.ElementDescriptor().as(); + WINML_EXPECT_TRUE(mapDescriptor.KeyKind() == TensorKind::Int64); -static void ZipMapInt64() -{ - LearningModel learningModel= nullptr; - WINML_EXPECT_NO_THROW(APITest::LoadModel(L"zipmap-int64.onnx", learningModel)); - RunZipMapInt64(learningModel, OutputBindingStrategy::Bound); -} + WINML_EXPECT_TRUE(mapDescriptor.ValueDescriptor().Kind() == LearningModelFeatureKind::Tensor); + auto tensorDescriptor = mapDescriptor.ValueDescriptor().as(); + WINML_EXPECT_TRUE(tensorDescriptor.TensorKind() == TensorKind::Float); -static void ZipMapInt64Unbound() -{ - LearningModel learningModel = nullptr; - WINML_EXPECT_NO_THROW(APITest::LoadModel(L"zipmap-int64.onnx", learningModel)); - RunZipMapInt64(learningModel, OutputBindingStrategy::Unbound); -} + LearningModelSession session(model); + LearningModelBinding binding(session); + + std::vector inputs = {0.5f, 0.25f, 0.125f}; + std::vector shape = {1, 3}; + + // Bind inputs + auto inputTensor = TensorFloat::CreateFromArray(shape, winrt::array_view(std::move(inputs))); + binding.Bind(winrt::hstring(L"X"), inputTensor); + + typedef IMap ABIMap; + typedef IVector ABISequeneceOfMap; -static void ZipMapString() -{ - // output constraint: "seq(map(string, float))" or "seq(map(int64, float))" - LearningModel learningModel = nullptr; - WINML_EXPECT_NO_THROW(APITest::LoadModel(L"zipmap-string.onnx", learningModel)); - auto outputs = learningModel.OutputFeatures(); - auto outputDescriptor = outputs.First().Current(); - WINML_EXPECT_TRUE(outputDescriptor.Kind() == LearningModelFeatureKind::Sequence); - auto mapDescriptor = outputDescriptor.as().ElementDescriptor().as(); - WINML_EXPECT_TRUE(mapDescriptor.KeyKind() == TensorKind::String); - WINML_EXPECT_TRUE(mapDescriptor.ValueDescriptor().Kind() == LearningModelFeatureKind::Tensor); - auto tensorDescriptor = mapDescriptor.ValueDescriptor().as(); - WINML_EXPECT_TRUE(tensorDescriptor.TensorKind() == TensorKind::Float); - - LearningModelSession session(learningModel); - LearningModelBinding binding(session); - - std::vector inputs = { 0.5f, 0.25f, 0.125f }; - std::vector shape = { 1, 3 }; - std::vector labels = { L"cat", L"dog", L"lion" }; - std::map mapData = { { L"cat", 0.0f }, { L"dog", 0.0f }, { L"lion", 0.0f } }; - typedef IMap ABIMap; - ABIMap abiMap = winrt::single_threaded_map(std::move(mapData)); - std::vector seqOutput = { abiMap }; - IVector ABIOutput = winrt::single_threaded_vector(std::move(seqOutput)); - - TensorFloat inputTensor = TensorFloat::CreateFromArray(shape, winrt::array_view(std::move(inputs))); - binding.Bind(winrt::hstring(L"X"), inputTensor); - binding.Bind(winrt::hstring(L"Y"), ABIOutput); - auto result = session.Evaluate(binding, L"0").Outputs(); + ABISequeneceOfMap abiOutput = nullptr; + // Bind outputs + if (bindingStrategy == OutputBindingStrategy::Bound) { + abiOutput = winrt::single_threaded_vector(); + binding.Bind(winrt::hstring(L"Y"), abiOutput); + } + + // Evaluate + auto result = session.Evaluate(binding, L"0").Outputs(); + + if (bindingStrategy == OutputBindingStrategy::Bound) { // from output binding - const auto &out1 = ABIOutput.GetAt(0); - const auto &out2 = result.Lookup(L"Y").as>().GetAt(0); + const auto& out1 = abiOutput.GetAt(0); + const auto& out2 = result.Lookup(L"Y").as>().GetAt(0); WINML_LOG_COMMENT((std::ostringstream() << "size: " << out1.Size()).str()); - // single key,value pair for each map + // check outputs auto iter1 = out1.First(); auto iter2 = out2.First(); - for (uint32_t i = 0, size = (uint32_t)inputs.size(); i < size; ++i) - { - WINML_EXPECT_TRUE(iter2.HasCurrent()); - const auto &pair1 = iter1.Current(); - const auto &pair2 = iter2.Current(); - WINML_LOG_COMMENT((std::ostringstream() << "key: " << pair1.Key().c_str() << ", value " << pair2.Value()).str()); - WINML_EXPECT_TRUE(std::wstring(pair1.Key().c_str()).compare(labels[i]) == 0); - WINML_EXPECT_TRUE(std::wstring(pair2.Key().c_str()).compare(labels[i]) == 0); - WINML_EXPECT_TRUE(pair1.Value() == inputs[i] && pair2.Value() == inputs[i]); - iter1.MoveNext(); - iter2.MoveNext(); + for (uint32_t i = 0, size = (uint32_t)inputs.size(); i < size; ++i) { + WINML_EXPECT_TRUE(iter1.HasCurrent()); + WINML_EXPECT_TRUE(iter2.HasCurrent()); + const auto& pair1 = iter1.Current(); + const auto& pair2 = iter2.Current(); + WINML_LOG_COMMENT((std::ostringstream() << "key: " << pair1.Key() << ", value: " << pair2.Value()).str()); + WINML_EXPECT_TRUE(pair1.Key() == i && pair2.Key() == i); + WINML_EXPECT_TRUE(pair1.Value() == inputs[i] && pair2.Value() == inputs[i]); + iter1.MoveNext(); + iter2.MoveNext(); } WINML_EXPECT_TRUE(!iter1.HasCurrent()); WINML_EXPECT_TRUE(!iter2.HasCurrent()); + } else { + abiOutput = result.Lookup(L"Y").as(); + WINML_EXPECT_TRUE(abiOutput.Size() == 1); + ABIMap map = abiOutput.GetAt(0); + WINML_EXPECT_TRUE(map.Size() == 3); + WINML_EXPECT_TRUE(map.Lookup(0) == 0.5); + WINML_EXPECT_TRUE(map.Lookup(1) == .25); + WINML_EXPECT_TRUE(map.Lookup(2) == .125); + } } -static void GpuSqueezeNet() -{ - std::string gpuInstance("GPU"); - WINML_EXPECT_NO_THROW( - WinML::Engine::Test::ModelValidator::SqueezeNet( - gpuInstance, - LearningModelDeviceKind::DirectX, - /*dataTolerance*/ 0.00001f); - ); +static void ZipMapInt64() { + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"zipmap-int64.onnx", learningModel)); + RunZipMapInt64(learningModel, OutputBindingStrategy::Bound); } -static void GpuSqueezeNetEmptyOutputs() -{ - std::string gpuInstance("GPU"); - WINML_EXPECT_NO_THROW( - WinML::Engine::Test::ModelValidator::SqueezeNet( - gpuInstance, - LearningModelDeviceKind::DirectX, - /*dataTolerance*/ 0.00001f, - false, - OutputBindingStrategy::Empty); - ); +static void ZipMapInt64Unbound() { + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"zipmap-int64.onnx", learningModel)); + RunZipMapInt64(learningModel, OutputBindingStrategy::Unbound); } -static void GpuSqueezeNetUnboundOutputs() -{ - std::string gpuInstance("GPU"); - WINML_EXPECT_NO_THROW( - WinML::Engine::Test::ModelValidator::SqueezeNet( - gpuInstance, - LearningModelDeviceKind::DirectX, - /*dataTolerance*/ 0.00001f, - false, - OutputBindingStrategy::Unbound); - ); +static void ZipMapString() { + // output constraint: "seq(map(string, float))" or "seq(map(int64, float))" + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"zipmap-string.onnx", learningModel)); + auto outputs = learningModel.OutputFeatures(); + auto outputDescriptor = outputs.First().Current(); + WINML_EXPECT_TRUE(outputDescriptor.Kind() == LearningModelFeatureKind::Sequence); + auto mapDescriptor = outputDescriptor.as().ElementDescriptor().as(); + WINML_EXPECT_TRUE(mapDescriptor.KeyKind() == TensorKind::String); + WINML_EXPECT_TRUE(mapDescriptor.ValueDescriptor().Kind() == LearningModelFeatureKind::Tensor); + auto tensorDescriptor = mapDescriptor.ValueDescriptor().as(); + WINML_EXPECT_TRUE(tensorDescriptor.TensorKind() == TensorKind::Float); + + LearningModelSession session(learningModel); + LearningModelBinding binding(session); + + std::vector inputs = {0.5f, 0.25f, 0.125f}; + std::vector shape = {1, 3}; + std::vector labels = {L"cat", L"dog", L"lion"}; + std::map mapData = { + { L"cat", 0.0f}, + { L"dog", 0.0f}, + {L"lion", 0.0f} + }; + typedef IMap ABIMap; + ABIMap abiMap = winrt::single_threaded_map(std::move(mapData)); + std::vector seqOutput = {abiMap}; + IVector ABIOutput = winrt::single_threaded_vector(std::move(seqOutput)); + + TensorFloat inputTensor = TensorFloat::CreateFromArray(shape, winrt::array_view(std::move(inputs))); + binding.Bind(winrt::hstring(L"X"), inputTensor); + binding.Bind(winrt::hstring(L"Y"), ABIOutput); + auto result = session.Evaluate(binding, L"0").Outputs(); + // from output binding + const auto& out1 = ABIOutput.GetAt(0); + const auto& out2 = result.Lookup(L"Y").as>().GetAt(0); + WINML_LOG_COMMENT((std::ostringstream() << "size: " << out1.Size()).str()); + // single key,value pair for each map + auto iter1 = out1.First(); + auto iter2 = out2.First(); + for (uint32_t i = 0, size = (uint32_t)inputs.size(); i < size; ++i) { + WINML_EXPECT_TRUE(iter2.HasCurrent()); + const auto& pair1 = iter1.Current(); + const auto& pair2 = iter2.Current(); + WINML_LOG_COMMENT((std::ostringstream() << "key: " << pair1.Key().c_str() << ", value " << pair2.Value()).str()); + WINML_EXPECT_TRUE(std::wstring(pair1.Key().c_str()).compare(labels[i]) == 0); + WINML_EXPECT_TRUE(std::wstring(pair2.Key().c_str()).compare(labels[i]) == 0); + WINML_EXPECT_TRUE(pair1.Value() == inputs[i] && pair2.Value() == inputs[i]); + iter1.MoveNext(); + iter2.MoveNext(); + } + WINML_EXPECT_TRUE(!iter1.HasCurrent()); + WINML_EXPECT_TRUE(!iter2.HasCurrent()); +} + +static void GpuSqueezeNet() { + std::string gpuInstance("GPU"); + WINML_EXPECT_NO_THROW(WinML::Engine::Test::ModelValidator::SqueezeNet( + gpuInstance, + LearningModelDeviceKind::DirectX, + /*dataTolerance*/ 0.00001f + );); +} + +static void GpuSqueezeNetEmptyOutputs() { + std::string gpuInstance("GPU"); + WINML_EXPECT_NO_THROW(WinML::Engine::Test::ModelValidator::SqueezeNet( + gpuInstance, + LearningModelDeviceKind::DirectX, + /*dataTolerance*/ 0.00001f, + false, + OutputBindingStrategy::Empty + );); +} + +static void GpuSqueezeNetUnboundOutputs() { + std::string gpuInstance("GPU"); + WINML_EXPECT_NO_THROW(WinML::Engine::Test::ModelValidator::SqueezeNet( + gpuInstance, + LearningModelDeviceKind::DirectX, + /*dataTolerance*/ 0.00001f, + false, + OutputBindingStrategy::Unbound + );); } // Validates that when the input image is the same as the model expects, the binding step is executed correctly. -static void ImageBindingDimensions() -{ - LearningModelBinding learningModelBinding = nullptr; - LearningModel learningModel = nullptr; - LearningModelSession learningModelSession = nullptr; - LearningModelDevice leraningModelDevice = nullptr; - std::wstring filePath = FileHelpers::GetModulePath() + L"model.onnx"; - // load a model with expected input size: 224 x 224 - WINML_EXPECT_NO_THROW(leraningModelDevice = LearningModelDevice(LearningModelDeviceKind::Default)); - WINML_EXPECT_NO_THROW(learningModel = LearningModel::LoadFromFilePath(filePath)); - WINML_EXPECT_TRUE(learningModel != nullptr); - WINML_EXPECT_NO_THROW(learningModelSession = LearningModelSession(learningModel, leraningModelDevice)); - WINML_EXPECT_NO_THROW(learningModelBinding = LearningModelBinding(learningModelSession)); - - // Create input images and execute bind - // Test Case 1: both width and height are larger than model expects - VideoFrame inputImage1(BitmapPixelFormat::Rgba8, 1000, 1000); - ImageFeatureValue inputTensor = ImageFeatureValue::CreateFromVideoFrame(inputImage1); - WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"data_0", inputTensor)); - - // Test Case 2: only height is larger, while width is smaller - VideoFrame inputImage2(BitmapPixelFormat::Rgba8, 20, 1000); - inputTensor = ImageFeatureValue::CreateFromVideoFrame(inputImage2); - WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"data_0", inputTensor)); - - // Test Case 3: only width is larger, while height is smaller - VideoFrame inputImage3(BitmapPixelFormat::Rgba8, 1000, 20); - inputTensor = ImageFeatureValue::CreateFromVideoFrame(inputImage3); - WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"data_0", inputTensor)); - - // Test Case 4: both width and height are smaller than model expects - VideoFrame inputImage4(BitmapPixelFormat::Rgba8, 20, 20); - inputTensor = ImageFeatureValue::CreateFromVideoFrame(inputImage4); - WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"data_0", inputTensor)); +static void ImageBindingDimensions() { + LearningModelBinding learningModelBinding = nullptr; + LearningModel learningModel = nullptr; + LearningModelSession learningModelSession = nullptr; + LearningModelDevice leraningModelDevice = nullptr; + std::wstring filePath = FileHelpers::GetModulePath() + L"model.onnx"; + // load a model with expected input size: 224 x 224 + WINML_EXPECT_NO_THROW(leraningModelDevice = LearningModelDevice(LearningModelDeviceKind::Default)); + WINML_EXPECT_NO_THROW(learningModel = LearningModel::LoadFromFilePath(filePath)); + WINML_EXPECT_TRUE(learningModel != nullptr); + WINML_EXPECT_NO_THROW(learningModelSession = LearningModelSession(learningModel, leraningModelDevice)); + WINML_EXPECT_NO_THROW(learningModelBinding = LearningModelBinding(learningModelSession)); + + // Create input images and execute bind + // Test Case 1: both width and height are larger than model expects + VideoFrame inputImage1(BitmapPixelFormat::Rgba8, 1000, 1000); + ImageFeatureValue inputTensor = ImageFeatureValue::CreateFromVideoFrame(inputImage1); + WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"data_0", inputTensor)); + + // Test Case 2: only height is larger, while width is smaller + VideoFrame inputImage2(BitmapPixelFormat::Rgba8, 20, 1000); + inputTensor = ImageFeatureValue::CreateFromVideoFrame(inputImage2); + WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"data_0", inputTensor)); + + // Test Case 3: only width is larger, while height is smaller + VideoFrame inputImage3(BitmapPixelFormat::Rgba8, 1000, 20); + inputTensor = ImageFeatureValue::CreateFromVideoFrame(inputImage3); + WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"data_0", inputTensor)); + + // Test Case 4: both width and height are smaller than model expects + VideoFrame inputImage4(BitmapPixelFormat::Rgba8, 20, 20); + inputTensor = ImageFeatureValue::CreateFromVideoFrame(inputImage4); + WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"data_0", inputTensor)); } -static void VerifyInvalidBindExceptions() -{ - LearningModel learningModel = nullptr; +static void VerifyInvalidBindExceptions() { + LearningModel learningModel = nullptr; WINML_EXPECT_NO_THROW(APITest::LoadModel(L"zipmap-int64.onnx", learningModel)); - LearningModelSession session(learningModel); - LearningModelBinding binding(session); + LearningModelSession session(learningModel); + LearningModelBinding binding(session); - std::vector inputs = { 0.5f, 0.25f, 0.125f }; - std::vector shape = { 1, 3 }; + std::vector inputs = {0.5f, 0.25f, 0.125f}; + std::vector shape = {1, 3}; - auto matchException = - [](const winrt::hresult_error& e, HRESULT hr) -> bool - { - return e.code() == hr; - }; + auto matchException = [](const winrt::hresult_error& e, HRESULT hr) -> bool { return e.code() == hr; }; - auto ensureWinmlSizeMismatch = std::bind(matchException, std::placeholders::_1, WINML_ERR_SIZE_MISMATCH); - auto ensureWinmlInvalidBinding = std::bind(matchException, std::placeholders::_1, WINML_ERR_INVALID_BINDING); + auto ensureWinmlSizeMismatch = std::bind(matchException, std::placeholders::_1, WINML_ERR_SIZE_MISMATCH); + auto ensureWinmlInvalidBinding = std::bind(matchException, std::placeholders::_1, WINML_ERR_INVALID_BINDING); - /* - Verify tensor bindings throw correct bind exceptions - */ + /* + Verify tensor bindings throw correct bind exceptions + */ - // Bind invalid image as tensorfloat input - auto image = FileHelpers::LoadImageFeatureValue(L"227x227.png"); - WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"X", image), winrt::hresult_error, ensureWinmlSizeMismatch); + // Bind invalid image as tensorfloat input + auto image = FileHelpers::LoadImageFeatureValue(L"227x227.png"); + WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"X", image), winrt::hresult_error, ensureWinmlSizeMismatch); - // Bind invalid map as tensorfloat input - std::unordered_map map; - auto abiMap = winrt::single_threaded_map(std::move(map)); - WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"X", abiMap), winrt::hresult_error, ensureWinmlInvalidBinding); + // Bind invalid map as tensorfloat input + std::unordered_map map; + auto abiMap = winrt::single_threaded_map(std::move(map)); + WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"X", abiMap), winrt::hresult_error, ensureWinmlInvalidBinding); - // Bind invalid sequence as tensorfloat input - std::vector sequence; - auto abiSequence = winrt::single_threaded_vector(std::move(sequence)); - WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"X", abiSequence), winrt::hresult_error, ensureWinmlInvalidBinding); + // Bind invalid sequence as tensorfloat input + std::vector sequence; + auto abiSequence = winrt::single_threaded_vector(std::move(sequence)); + WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"X", abiSequence), winrt::hresult_error, ensureWinmlInvalidBinding); - // Bind invalid tensor size as tensorfloat input - auto tensorBoolean = TensorBoolean::Create(); - WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"X", tensorBoolean), winrt::hresult_error, ensureWinmlInvalidBinding); + // Bind invalid tensor size as tensorfloat input + auto tensorBoolean = TensorBoolean::Create(); + WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"X", tensorBoolean), winrt::hresult_error, ensureWinmlInvalidBinding); - // Bind invalid tensor shape as tensorfloat input - auto tensorInvalidShape = TensorFloat::Create(std::vector { 2, 3, 4 }); - WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"X", tensorInvalidShape), winrt::hresult_error, ensureWinmlInvalidBinding); + // Bind invalid tensor shape as tensorfloat input + auto tensorInvalidShape = TensorFloat::Create(std::vector{2, 3, 4}); + WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"X", tensorInvalidShape), winrt::hresult_error, ensureWinmlInvalidBinding); - /* - Verify sequence bindings throw correct bind exceptions - */ + /* + Verify sequence bindings throw correct bind exceptions + */ - // Bind invalid image as sequence output - WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"Y", image), winrt::hresult_error, ensureWinmlInvalidBinding); + // Bind invalid image as sequence output + WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"Y", image), winrt::hresult_error, ensureWinmlInvalidBinding); - // Bind invalid map as sequence output - WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"Y", abiMap), winrt::hresult_error, ensureWinmlInvalidBinding); + // Bind invalid map as sequence output + WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"Y", abiMap), winrt::hresult_error, ensureWinmlInvalidBinding); - // Bind invalid sequence as sequence output - WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"Y", abiSequence), winrt::hresult_error, ensureWinmlInvalidBinding); + // Bind invalid sequence as sequence output + WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"Y", abiSequence), winrt::hresult_error, ensureWinmlInvalidBinding); - // Bind invalid tensor as sequence output - WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"Y", tensorBoolean), winrt::hresult_error, ensureWinmlInvalidBinding); + // Bind invalid tensor as sequence output + WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"Y", tensorBoolean), winrt::hresult_error, ensureWinmlInvalidBinding); - /* - Verify image bindings throw correct bind exceptions - */ + /* + Verify map bindings throw correct bind exceptions + */ + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"dictvectorizer-int64.onnx", learningModel)); - // WINML_EXPECT_NO_THROW(LoadModel(L"fns-candy.onnx")); + LearningModelSession mapSession(learningModel); + LearningModelBinding mapBinding(mapSession); - // LearningModelSession imageSession(m_model); - // LearningModelBinding imageBinding(imageSession); + auto inputName = learningModel.InputFeatures().First().Current().Name(); - // auto inputName = m_model.InputFeatures().First().Current().Name(); + // Bind invalid image as image input + auto smallImage = FileHelpers::LoadImageFeatureValue(L"100x100.png"); + WINML_EXPECT_THROW_SPECIFIC(mapBinding.Bind(inputName, smallImage), winrt::hresult_error, ensureWinmlInvalidBinding); - // // Bind invalid map as image input - // WINML_EXPECT_THROW_SPECIFIC(imageBinding.Bind(inputName, abiMap), winrt::hresult_error, ensureWinmlInvalidBinding); + // Bind invalid map as image input + WINML_EXPECT_THROW_SPECIFIC(mapBinding.Bind(inputName, abiMap), winrt::hresult_error, ensureWinmlInvalidBinding); - // // Bind invalid sequence as image input - // WINML_EXPECT_THROW_SPECIFIC(imageBinding.Bind(inputName, abiSequence), winrt::hresult_error, ensureWinmlInvalidBinding); + // Bind invalid sequence as image input + WINML_EXPECT_THROW_SPECIFIC(mapBinding.Bind(inputName, abiSequence), winrt::hresult_error, ensureWinmlInvalidBinding); - // // Bind invalid tensor type as image input - // WINML_EXPECT_THROW_SPECIFIC(imageBinding.Bind(inputName, tensorBoolean), winrt::hresult_error, ensureWinmlInvalidBinding); + // Bind invalid tensor type as image input + WINML_EXPECT_THROW_SPECIFIC( + mapBinding.Bind(inputName, tensorBoolean), winrt::hresult_error, ensureWinmlInvalidBinding + ); +} - // // Bind invalid tensor size as image input - // auto tensorFloat = TensorFloat::Create(std::vector { 1, 1, 100, 100 }); - // WINML_EXPECT_THROW_SPECIFIC(imageBinding.Bind(inputName, tensorFloat), winrt::hresult_error, ensureWinmlInvalidBinding); +// Verify that it throws an error when binding an invalid name. +static void BindInvalidInputName() { + LearningModel learningModel = nullptr; + LearningModelBinding learningModelBinding = nullptr; + LearningModelDevice learningModelDevice = nullptr; + LearningModelSession learningModelSession = nullptr; + std::wstring modelPath = FileHelpers::GetModulePath() + L"Add_ImageNet1920.onnx"; + WINML_EXPECT_NO_THROW(learningModel = LearningModel::LoadFromFilePath(modelPath)); + WINML_EXPECT_TRUE(learningModel != nullptr); + WINML_EXPECT_NO_THROW(learningModelDevice = LearningModelDevice(LearningModelDeviceKind::Default)); + WINML_EXPECT_NO_THROW(learningModelSession = LearningModelSession(learningModel, learningModelDevice)); + WINML_EXPECT_NO_THROW(learningModelBinding = LearningModelBinding(learningModelSession)); - // // Bind invalid tensor shape as image input - // WINML_EXPECT_THROW_SPECIFIC(imageBinding.Bind(inputName, tensorInvalidShape), winrt::hresult_error, ensureWinmlInvalidBinding); + VideoFrame iuputImage(BitmapPixelFormat::Rgba8, 1920, 1080); + ImageFeatureValue inputTensor = ImageFeatureValue::CreateFromVideoFrame(iuputImage); - /* - Verify map bindings throw correct bind exceptions - */ - WINML_EXPECT_NO_THROW(APITest::LoadModel(L"dictvectorizer-int64.onnx", learningModel)); + auto first = learningModel.InputFeatures().First(); + std::wstring testInvalidName = L"0"; - LearningModelSession mapSession(learningModel); - LearningModelBinding mapBinding(mapSession); + // Verify that testInvalidName is not in model's InputFeatures + while (first.HasCurrent()) { + WINML_EXPECT_NOT_EQUAL(testInvalidName, first.Current().Name()); + first.MoveNext(); + } - auto inputName = learningModel.InputFeatures().First().Current().Name(); + // Bind inputTensor to a valid input name + WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"input_39:0", inputTensor)); - // Bind invalid image as image input - auto smallImage = FileHelpers::LoadImageFeatureValue(L"100x100.png"); - WINML_EXPECT_THROW_SPECIFIC(mapBinding.Bind(inputName, smallImage), winrt::hresult_error, ensureWinmlInvalidBinding); + // Bind inputTensor to an invalid input name + WINML_EXPECT_THROW_SPECIFIC( + learningModelBinding.Bind(testInvalidName, inputTensor), + winrt::hresult_error, + [](const winrt::hresult_error& e) -> bool { return e.code() == WINML_ERR_INVALID_BINDING; } + ); +} - // Bind invalid map as image input - WINML_EXPECT_THROW_SPECIFIC(mapBinding.Bind(inputName, abiMap), winrt::hresult_error, ensureWinmlInvalidBinding); +static void VerifyOutputAfterEvaluateAsyncCalledTwice() { + LearningModel learningModel = nullptr; + LearningModelBinding learningModelBinding = nullptr; + LearningModelDevice learningModelDevice = nullptr; + LearningModelSession learningModelSession = nullptr; + std::wstring filePath = FileHelpers::GetModulePath() + L"relu.onnx"; + WINML_EXPECT_NO_THROW(learningModelDevice = LearningModelDevice(LearningModelDeviceKind::Default)); + WINML_EXPECT_NO_THROW(learningModel = LearningModel::LoadFromFilePath(filePath)); + WINML_EXPECT_TRUE(learningModel != nullptr); + WINML_EXPECT_NO_THROW(learningModelSession = LearningModelSession(learningModel, learningModelDevice)); + WINML_EXPECT_NO_THROW(learningModelBinding = LearningModelBinding(learningModelSession)); - // Bind invalid sequence as image input - WINML_EXPECT_THROW_SPECIFIC(mapBinding.Bind(inputName, abiSequence), winrt::hresult_error, ensureWinmlInvalidBinding); + auto inputShape = std::vector{5}; + auto inputData1 = std::vector{-50.f, -25.f, 0.f, 25.f, 50.f}; + auto inputValue1 = + TensorFloat::CreateFromIterable(inputShape, single_threaded_vector(std::move(inputData1)).GetView()); - // Bind invalid tensor type as image input - WINML_EXPECT_THROW_SPECIFIC(mapBinding.Bind(inputName, tensorBoolean), winrt::hresult_error, ensureWinmlInvalidBinding); -} + auto inputData2 = std::vector{50.f, 25.f, 0.f, -25.f, -50.f}; + auto inputValue2 = + TensorFloat::CreateFromIterable(inputShape, single_threaded_vector(std::move(inputData2)).GetView()); -// Verify that it throws an error when binding an invalid name. -static void BindInvalidInputName() -{ - LearningModel learningModel = nullptr; - LearningModelBinding learningModelBinding = nullptr; - LearningModelDevice learningModelDevice = nullptr; - LearningModelSession learningModelSession = nullptr; - std::wstring modelPath = FileHelpers::GetModulePath() + L"Add_ImageNet1920.onnx"; - WINML_EXPECT_NO_THROW(learningModel = LearningModel::LoadFromFilePath(modelPath)); - WINML_EXPECT_TRUE(learningModel != nullptr); - WINML_EXPECT_NO_THROW(learningModelDevice = LearningModelDevice(LearningModelDeviceKind::Default)); - WINML_EXPECT_NO_THROW(learningModelSession = LearningModelSession(learningModel, learningModelDevice)); - WINML_EXPECT_NO_THROW(learningModelBinding = LearningModelBinding(learningModelSession)); - - VideoFrame iuputImage(BitmapPixelFormat::Rgba8, 1920, 1080); - ImageFeatureValue inputTensor = ImageFeatureValue::CreateFromVideoFrame(iuputImage); - - auto first = learningModel.InputFeatures().First(); - std::wstring testInvalidName = L"0"; - - // Verify that testInvalidName is not in model's InputFeatures - while (first.HasCurrent()) - { - WINML_EXPECT_NOT_EQUAL(testInvalidName, first.Current().Name()); - first.MoveNext(); - } + WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"X", inputValue1)); - // Bind inputTensor to a valid input name - WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"input_39:0", inputTensor)); + auto outputValue = TensorFloat::Create(); + WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"Y", outputValue)); - // Bind inputTensor to an invalid input name - WINML_EXPECT_THROW_SPECIFIC(learningModelBinding.Bind(testInvalidName, inputTensor), - winrt::hresult_error, - [](const winrt::hresult_error& e) -> bool - { - return e.code() == WINML_ERR_INVALID_BINDING; - }); -} + WINML_EXPECT_NO_THROW(learningModelSession.Evaluate(learningModelBinding, L"")); -static void VerifyOutputAfterEvaluateAsyncCalledTwice() -{ - LearningModel learningModel = nullptr; - LearningModelBinding learningModelBinding = nullptr; - LearningModelDevice learningModelDevice = nullptr; - LearningModelSession learningModelSession = nullptr; - std::wstring filePath = FileHelpers::GetModulePath() + L"relu.onnx"; - WINML_EXPECT_NO_THROW(learningModelDevice = LearningModelDevice(LearningModelDeviceKind::Default)); - WINML_EXPECT_NO_THROW(learningModel = LearningModel::LoadFromFilePath(filePath)); - WINML_EXPECT_TRUE(learningModel != nullptr); - WINML_EXPECT_NO_THROW(learningModelSession = LearningModelSession(learningModel, learningModelDevice)); - WINML_EXPECT_NO_THROW(learningModelBinding = LearningModelBinding(learningModelSession)); - - auto inputShape = std::vector{ 5 }; - auto inputData1 = std::vector{ -50.f, -25.f, 0.f, 25.f, 50.f }; - auto inputValue1 = - TensorFloat::CreateFromIterable( - inputShape, - single_threaded_vector(std::move(inputData1)).GetView()); - - auto inputData2 = std::vector{ 50.f, 25.f, 0.f, -25.f, -50.f }; - auto inputValue2 = - TensorFloat::CreateFromIterable( - inputShape, - single_threaded_vector(std::move(inputData2)).GetView()); - - WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"X", inputValue1)); - - auto outputValue = TensorFloat::Create(); - WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"Y", outputValue)); - - WINML_EXPECT_NO_THROW(learningModelSession.Evaluate(learningModelBinding, L"")); - - auto buffer1 = outputValue.GetAsVectorView(); - WINML_EXPECT_TRUE(buffer1 != nullptr); - - // The second evaluation - // If we don't bind output again, the output value will not change - WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"X", inputValue2)); - WINML_EXPECT_NO_THROW(learningModelSession.Evaluate(learningModelBinding, L"")); - auto buffer2 = outputValue.GetAsVectorView(); - WINML_EXPECT_EQUAL(buffer1.Size(), buffer2.Size()); - bool isSame = true; - for (uint32_t i = 0; i < buffer1.Size(); ++i) - { - if (buffer1.GetAt(i) != buffer2.GetAt(i)) - { - isSame = false; - break; - } + auto buffer1 = outputValue.GetAsVectorView(); + WINML_EXPECT_TRUE(buffer1 != nullptr); + + // The second evaluation + // If we don't bind output again, the output value will not change + WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"X", inputValue2)); + WINML_EXPECT_NO_THROW(learningModelSession.Evaluate(learningModelBinding, L"")); + auto buffer2 = outputValue.GetAsVectorView(); + WINML_EXPECT_EQUAL(buffer1.Size(), buffer2.Size()); + bool isSame = true; + for (uint32_t i = 0; i < buffer1.Size(); ++i) { + if (buffer1.GetAt(i) != buffer2.GetAt(i)) { + isSame = false; + break; } - WINML_EXPECT_FALSE(isSame); + } + WINML_EXPECT_FALSE(isSame); } -static VideoFrame CreateVideoFrame(const wchar_t* path) -{ - auto imagefile = StorageFile::GetFileFromPathAsync(path).get(); - auto stream = imagefile.OpenAsync(FileAccessMode::Read).get(); - auto decoder = BitmapDecoder::CreateAsync(stream).get(); - auto softwareBitmap = decoder.GetSoftwareBitmapAsync().get(); - return VideoFrame::CreateWithSoftwareBitmap(softwareBitmap); +static VideoFrame CreateVideoFrame(const wchar_t* path) { + auto imagefile = StorageFile::GetFileFromPathAsync(path).get(); + auto stream = imagefile.OpenAsync(FileAccessMode::Read).get(); + auto decoder = BitmapDecoder::CreateAsync(stream).get(); + auto softwareBitmap = decoder.GetSoftwareBitmapAsync().get(); + return VideoFrame::CreateWithSoftwareBitmap(softwareBitmap); } -static void VerifyOutputAfterImageBindCalledTwice() -{ - std::wstring fullModelPath = FileHelpers::GetModulePath() + L"model.onnx"; - std::wstring fullImagePath1 = FileHelpers::GetModulePath() + L"kitten_224.png"; - std::wstring fullImagePath2 = FileHelpers::GetModulePath() + L"fish.png"; - - // winml model creation - LearningModel model = nullptr; - WINML_EXPECT_NO_THROW(model = LearningModel::LoadFromFilePath(fullModelPath)); - LearningModelSession modelSession = nullptr; - WINML_EXPECT_NO_THROW(modelSession = LearningModelSession(model, LearningModelDevice(LearningModelDeviceKind::Default))); - LearningModelBinding modelBinding(modelSession); - - // create the tensor for the actual output - auto output = TensorFloat::Create(); - modelBinding.Bind(L"softmaxout_1", output); - - // Bind image 1 and evaluate - auto frame = CreateVideoFrame(fullImagePath1.c_str()); - auto imageTensor = ImageFeatureValue::CreateFromVideoFrame(frame); - WINML_EXPECT_NO_THROW(modelBinding.Bind(L"data_0", imageTensor)); - WINML_EXPECT_NO_THROW(modelSession.Evaluate(modelBinding, L"")); - - // Store 1st result - auto outputVectorView1 = output.GetAsVectorView(); - - // Bind image 2 and evaluate - // In this scenario, the backing videoframe is updated, and the imagefeaturevalue is rebound. - // The expected result is that the videoframe will be re-tensorized at bind - auto frame2 = CreateVideoFrame(fullImagePath2.c_str()); - frame2.CopyToAsync(frame).get(); - WINML_EXPECT_NO_THROW(modelBinding.Bind(L"data_0", imageTensor)); - WINML_EXPECT_NO_THROW(modelSession.Evaluate(modelBinding, L"")); - - // Store 2nd result - auto outputVectorView2 = output.GetAsVectorView(); - - WINML_EXPECT_EQUAL(outputVectorView1.Size(), outputVectorView2.Size()); - bool isSame = true; - for (uint32_t i = 0; i < outputVectorView1.Size(); ++i) - { - if (outputVectorView1.GetAt(i) != outputVectorView2.GetAt(i)) - { - isSame = false; - break; - } +static void VerifyOutputAfterImageBindCalledTwice() { + std::wstring fullModelPath = FileHelpers::GetModulePath() + L"model.onnx"; + std::wstring fullImagePath1 = FileHelpers::GetModulePath() + L"kitten_224.png"; + std::wstring fullImagePath2 = FileHelpers::GetModulePath() + L"fish.png"; + + // winml model creation + LearningModel model = nullptr; + WINML_EXPECT_NO_THROW(model = LearningModel::LoadFromFilePath(fullModelPath)); + LearningModelSession modelSession = nullptr; + WINML_EXPECT_NO_THROW( + modelSession = LearningModelSession(model, LearningModelDevice(LearningModelDeviceKind::Default)) + ); + LearningModelBinding modelBinding(modelSession); + + // create the tensor for the actual output + auto output = TensorFloat::Create(); + modelBinding.Bind(L"softmaxout_1", output); + + // Bind image 1 and evaluate + auto frame = CreateVideoFrame(fullImagePath1.c_str()); + auto imageTensor = ImageFeatureValue::CreateFromVideoFrame(frame); + WINML_EXPECT_NO_THROW(modelBinding.Bind(L"data_0", imageTensor)); + WINML_EXPECT_NO_THROW(modelSession.Evaluate(modelBinding, L"")); + + // Store 1st result + auto outputVectorView1 = output.GetAsVectorView(); + + // Bind image 2 and evaluate + // In this scenario, the backing videoframe is updated, and the imagefeaturevalue is rebound. + // The expected result is that the videoframe will be re-tensorized at bind + auto frame2 = CreateVideoFrame(fullImagePath2.c_str()); + frame2.CopyToAsync(frame).get(); + WINML_EXPECT_NO_THROW(modelBinding.Bind(L"data_0", imageTensor)); + WINML_EXPECT_NO_THROW(modelSession.Evaluate(modelBinding, L"")); + + // Store 2nd result + auto outputVectorView2 = output.GetAsVectorView(); + + WINML_EXPECT_EQUAL(outputVectorView1.Size(), outputVectorView2.Size()); + bool isSame = true; + for (uint32_t i = 0; i < outputVectorView1.Size(); ++i) { + if (outputVectorView1.GetAt(i) != outputVectorView2.GetAt(i)) { + isSame = false; + break; } - WINML_EXPECT_FALSE(isSame); + } + WINML_EXPECT_FALSE(isSame); } -static void SequenceLengthTensorFloat() -{ +static void SequenceLengthTensorFloat() { // Tests sequence of tensor float as an input LearningModel learningModel = nullptr; LearningModelBinding learningModelBinding = nullptr; @@ -657,9 +589,11 @@ static void SequenceLengthTensorFloat() WINML_EXPECT_NO_THROW(learningModelBinding = LearningModelBinding(learningModelSession)); auto input = winrt::single_threaded_vector(); - for (int i = 0; i < 3; i++){ - std::vector shape = {5, 3*i + 1}; - std::vector data(static_cast(std::accumulate(shape.begin(), shape.end(), static_cast(1), std::multiplies()))); + for (int i = 0; i < 3; i++) { + std::vector shape = {5, 3 * i + 1}; + std::vector data( + static_cast(std::accumulate(shape.begin(), shape.end(), static_cast(1), std::multiplies())) + ); input.Append(TensorFloat::CreateFromShapeArrayAndDataArray(shape, data)); } @@ -669,8 +603,7 @@ static void SequenceLengthTensorFloat() WINML_EXPECT_EQUAL(3, results.Outputs().Lookup(L"Y").as().GetAsVectorView().GetAt(0)); } -static void SequenceConstructTensorString() -{ +static void SequenceConstructTensorString() { LearningModel learningModel = nullptr; LearningModelBinding learningModelBinding = nullptr; LearningModelDevice learningModelDevice = nullptr; @@ -683,10 +616,14 @@ static void SequenceConstructTensorString() WINML_EXPECT_NO_THROW(learningModelBinding = LearningModelBinding(learningModelSession)); std::vector shape1 = {2, 3}; - std::vector data1(static_cast(std::accumulate(shape1.begin(), shape1.end(), static_cast(1), std::multiplies()))); + std::vector data1( + static_cast(std::accumulate(shape1.begin(), shape1.end(), static_cast(1), std::multiplies())) + ); auto input1 = TensorInt64Bit::CreateFromShapeArrayAndDataArray(shape1, data1); std::vector shape2 = {2, 3}; - std::vector data2(static_cast(std::accumulate(shape2.begin(), shape2.end(), static_cast(1), std::multiplies()))); + std::vector data2( + static_cast(std::accumulate(shape2.begin(), shape2.end(), static_cast(1), std::multiplies())) + ); auto input2 = TensorInt64Bit::CreateFromShapeArrayAndDataArray(shape2, data2); WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"tensor1", input1)); @@ -700,7 +637,7 @@ static void SequenceConstructTensorString() WINML_EXPECT_EQUAL(2, output_sequence.GetAt(1).Shape().GetAt(0)); WINML_EXPECT_EQUAL(3, output_sequence.GetAt(1).Shape().GetAt(1)); - auto bound_output_sequence = winrt::single_threaded_vector (); + auto bound_output_sequence = winrt::single_threaded_vector(); WINML_EXPECT_NO_THROW(learningModelBinding.Bind(L"output_sequence", bound_output_sequence)); WINML_EXPECT_NO_THROW(learningModelSession.Evaluate(learningModelBinding, L"")); WINML_EXPECT_EQUAL(static_cast(2), bound_output_sequence.Size()); @@ -711,8 +648,7 @@ static void SequenceConstructTensorString() } const LearningModelBindingAPITestsApi& getapi() { - static LearningModelBindingAPITestsApi api = - { + static LearningModelBindingAPITestsApi api = { LearningModelBindingAPITestsClassSetup, CpuSqueezeNet, CpuSqueezeNetEmptyOutputs, @@ -733,8 +669,7 @@ const LearningModelBindingAPITestsApi& getapi() { VerifyOutputAfterEvaluateAsyncCalledTwice, VerifyOutputAfterImageBindCalledTwice, SequenceLengthTensorFloat, - SequenceConstructTensorString - }; + SequenceConstructTensorString}; if (SkipGpuTests()) { api.GpuSqueezeNet = SkipTest; diff --git a/winml/test/api/LearningModelBindingAPITest.h b/winml/test/api/LearningModelBindingAPITest.h index f3ae26dab47da..7011135696d6b 100644 --- a/winml/test/api/LearningModelBindingAPITest.h +++ b/winml/test/api/LearningModelBindingAPITest.h @@ -51,4 +51,4 @@ WINML_TEST(LearningModelBindingAPITests, GpuSqueezeNetUnboundOutputs) WINML_TEST(LearningModelBindingAPITests, ImageBindingDimensions) WINML_TEST(LearningModelBindingAPITests, VerifyInvalidBindExceptions) WINML_TEST(LearningModelBindingAPITests, BindInvalidInputName) -WINML_TEST_CLASS_END() \ No newline at end of file +WINML_TEST_CLASS_END() diff --git a/winml/test/api/LearningModelSessionAPITest.cpp b/winml/test/api/LearningModelSessionAPITest.cpp index 63bf9406709c0..21cdaa62bc898 100644 --- a/winml/test/api/LearningModelSessionAPITest.cpp +++ b/winml/test/api/LearningModelSessionAPITest.cpp @@ -40,11 +40,10 @@ static void LearningModelSessionAPITestsClassSetup() { #endif } -static void CreateSessionDeviceDefault() -{ - LearningModel learningModel = nullptr; - LearningModelDevice learningModelDevice = nullptr; - WINML_EXPECT_NO_THROW(APITest::LoadModel(L"model.onnx", learningModel)); +static void CreateSessionDeviceDefault() { + LearningModel learningModel = nullptr; + LearningModelDevice learningModelDevice = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"model.onnx", learningModel)); WINML_EXPECT_NO_THROW(learningModelDevice = LearningModelDevice(LearningModelDeviceKind::Default)); WINML_EXPECT_NO_THROW(LearningModelSession(learningModel, learningModelDevice)); @@ -65,8 +64,7 @@ static void CreateSessionDeviceCpu() { WINML_EXPECT_EQUAL(id.HighPart, 0); } -static void CreateSessionWithModelLoadedFromStream() -{ +static void CreateSessionWithModelLoadedFromStream() { LearningModel learningModel = nullptr; LearningModelDevice learningModelDevice = nullptr; std::wstring path = FileHelpers::GetModulePath() + L"model.onnx"; @@ -127,7 +125,9 @@ static void AdapterIdAndDevice() { learningModelDevice = LearningModelDevice(LearningModelDeviceKind::DirectXHighPerformance); adapter = nullptr; - WINML_EXPECT_HRESULT_SUCCEEDED(factory->EnumAdapterByGpuPreference(0, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, __uuidof(IDXGIAdapter), adapter.put_void())); + WINML_EXPECT_HRESULT_SUCCEEDED(factory->EnumAdapterByGpuPreference( + 0, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, __uuidof(IDXGIAdapter), adapter.put_void() + )); WINML_EXPECT_HRESULT_SUCCEEDED(adapter->GetDesc(&desc)); id.QuadPart = APITest::GetAdapterIdQuadPart(learningModelDevice); WINML_EXPECT_EQUAL(desc.AdapterLuid.LowPart, id.LowPart); @@ -136,7 +136,9 @@ static void AdapterIdAndDevice() { adapter = nullptr; learningModelDevice = LearningModelDevice(LearningModelDeviceKind::DirectXMinPower); - WINML_EXPECT_HRESULT_SUCCEEDED(factory->EnumAdapterByGpuPreference(0, DXGI_GPU_PREFERENCE_MINIMUM_POWER, __uuidof(IDXGIAdapter), adapter.put_void())); + WINML_EXPECT_HRESULT_SUCCEEDED(factory->EnumAdapterByGpuPreference( + 0, DXGI_GPU_PREFERENCE_MINIMUM_POWER, __uuidof(IDXGIAdapter), adapter.put_void() + )); WINML_EXPECT_HRESULT_SUCCEEDED(adapter->GetDesc(&desc)); id.QuadPart = APITest::GetAdapterIdQuadPart(learningModelDevice); WINML_EXPECT_EQUAL(desc.AdapterLuid.LowPart, id.LowPart); @@ -159,7 +161,8 @@ static void EvaluateFeatures() { // create from vector view auto dataCopy = data; tensor = TensorString::CreateFromIterable( - shape, winrt::single_threaded_vector(std::move(dataCopy)).GetView()); + shape, winrt::single_threaded_vector(std::move(dataCopy)).GetView() + ); WINML_EXPECT_EQUAL(tensor.GetAsVectorView().Size(), data.size()); WINML_EXPECT_TRUE(std::equal(data.cbegin(), data.cend(), begin(tensor.GetAsVectorView()))); @@ -192,7 +195,8 @@ static void EvaluateFeaturesAsync() { // create from vector view auto dataCopy = data; tensor = TensorString::CreateFromIterable( - shape, winrt::single_threaded_vector(std::move(dataCopy)).GetView()); + shape, winrt::single_threaded_vector(std::move(dataCopy)).GetView() + ); WINML_EXPECT_EQUAL(tensor.GetAsVectorView().Size(), data.size()); WINML_EXPECT_TRUE(std::equal(data.cbegin(), data.cend(), begin(tensor.GetAsVectorView()))); @@ -237,11 +241,10 @@ static LearningModelSession CreateSession(LearningModel model) { WINML_EXPECT_NO_THROW(session = LearningModelSession(model, device)); } else { WINML_EXPECT_THROW_SPECIFIC( - session = LearningModelSession(model, device), - winrt::hresult_error, - [](const winrt::hresult_error& e) -> bool { - return e.code() == DXGI_ERROR_UNSUPPORTED; - }); + session = LearningModelSession(model, device), + winrt::hresult_error, + [](const winrt::hresult_error& e) -> bool { return e.code() == DXGI_ERROR_UNSUPPORTED; } + ); } return session; @@ -255,18 +258,15 @@ static void CreateSessionWithCastToFloat16InModel() { CreateSession(learningModel); } -static void CreateSessionWithFloat16InitializersInModel() -{ - // load a model - LearningModel learningModel = nullptr; - WINML_EXPECT_NO_THROW(APITest::LoadModel(L"fp16-initializer.onnx", learningModel)); +static void CreateSessionWithFloat16InitializersInModel() { + // load a model + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"fp16-initializer.onnx", learningModel)); CreateSession(learningModel); } -static void EvaluateSessionAndCloseModelHelper( - LearningModelDeviceKind kind, - bool close_model_on_session_creation) { +static void EvaluateSessionAndCloseModelHelper(LearningModelDeviceKind kind, bool close_model_on_session_creation) { auto shape = std::vector{1, 1000}; auto model = ProtobufHelpers::CreateModel(TensorKind::Float, shape, 1000); @@ -294,11 +294,10 @@ static void EvaluateSessionAndCloseModelHelper( if (close_model_on_session_creation) { // ensure that the model has been closed WINML_EXPECT_THROW_SPECIFIC( - LearningModelSession(model, device, options), - winrt::hresult_error, - [](const winrt::hresult_error& e) -> bool { - return e.code() == E_INVALIDARG; - }); + LearningModelSession(model, device, options), + winrt::hresult_error, + [](const winrt::hresult_error& e) -> bool { return e.code() == E_INVALIDARG; } + ); } else { WINML_EXPECT_NO_THROW(LearningModelSession(model, device, options)); } @@ -309,8 +308,7 @@ static void EvaluateSessionAndCloseModel() { WINML_EXPECT_NO_THROW(::EvaluateSessionAndCloseModelHelper(LearningModelDeviceKind::Cpu, false)); } -static void NamedDimensionOverride() -{ +static void NamedDimensionOverride() { LearningModel model = nullptr; WINML_EXPECT_NO_THROW(APITest::LoadModel(L"fns-candy.onnx", model)); @@ -343,8 +341,8 @@ static void NamedDimensionOverride() ILearningModelFeatureDescriptor descriptor = model.InputFeatures().GetAt(0); TensorFeatureDescriptor tensorDescriptor = nullptr; descriptor.as(tensorDescriptor); - std::vector shape{n,c,h,w}; - int64_t size = n*c*h*w; + std::vector shape{n, c, h, w}; + int64_t size = n * c * h * w; std::vector buffer; buffer.resize(static_cast(size)); auto featureValue = TensorFloat::CreateFromIterable(shape, winrt::single_threaded_vector(std::move(buffer))); @@ -354,11 +352,10 @@ static void NamedDimensionOverride() WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); } -static void CloseSession() -{ - LearningModel learningModel = nullptr; - WINML_EXPECT_NO_THROW(APITest::LoadModel(L"model.onnx", learningModel)); - LearningModelSession session = nullptr; +static void CloseSession() { + LearningModel learningModel = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"model.onnx", learningModel)); + LearningModelSession session = nullptr; /* HANDLE currentProcessHandle = NULL; @@ -420,37 +417,33 @@ static void CloseSession() std::vector input(1 * 3 * 224 * 224, 0); std::vector shape = {1, 3, 224, 224}; auto tensor_input = TensorFloat::CreateFromArray(shape, input); - WINML_EXPECT_THROW_SPECIFIC(LearningModelBinding binding(session), - winrt::hresult_error, - [](const winrt::hresult_error& e) -> bool { - return e.code() == RO_E_CLOSED; - }); + WINML_EXPECT_THROW_SPECIFIC( + LearningModelBinding binding(session), + winrt::hresult_error, + [](const winrt::hresult_error& e) -> bool { return e.code() == RO_E_CLOSED; } + ); } #if !defined(BUILD_INBOX) -static void WindowFunction( - const wchar_t* window_operator_name, - TensorKind kind, - const std::vector& expected) { +static void WindowFunction(const wchar_t* window_operator_name, TensorKind kind, const std::vector& expected) { std::vector scalar_shape = {}; std::vector output_shape = {32}; auto double_data_type = TensorInt64Bit::CreateFromArray({}, {11}); - auto window_operator = - Operator(window_operator_name) - .SetInput(L"size", L"Input") - .SetOutput(L"output", L"Output"); + auto window_operator = Operator(window_operator_name).SetInput(L"size", L"Input").SetOutput(L"output", L"Output"); if (kind == TensorKind::Double) { window_operator.SetAttribute(L"output_datatype", double_data_type); } - auto model = - LearningModelBuilder::Create(17) - .Inputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Input", TensorKind::Int64, scalar_shape)) - .Outputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Output", kind, output_shape)) - .Operators().Add(window_operator) - .CreateModel(); + auto model = LearningModelBuilder::Create(17) + .Inputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Input", TensorKind::Int64, scalar_shape)) + .Outputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Output", kind, output_shape)) + .Operators() + .Add(window_operator) + .CreateModel(); LearningModelSession session(model); LearningModelBinding binding(session); @@ -477,23 +470,28 @@ static void WindowFunction( } } printf("\n"); - } #endif static void SaveSoftwareBitmap(const wchar_t* filename, winrt::Windows::Graphics::Imaging::SoftwareBitmap bitmap) { std::wstring modulePath = FileHelpers::GetModulePath(); - winrt::Windows::Storage::StorageFolder folder = winrt::Windows::Storage::StorageFolder::GetFolderFromPathAsync(modulePath).get(); - winrt::Windows::Storage::StorageFile file = folder.CreateFileAsync(filename, winrt::Windows::Storage::CreationCollisionOption::ReplaceExisting).get(); - winrt::Windows::Storage::Streams::IRandomAccessStream write_stream = file.OpenAsync(winrt::Windows::Storage::FileAccessMode::ReadWrite).get(); - winrt::Windows::Graphics::Imaging::BitmapEncoder encoder = winrt::Windows::Graphics::Imaging::BitmapEncoder::CreateAsync(winrt::Windows::Graphics::Imaging::BitmapEncoder::JpegEncoderId(), write_stream).get(); + winrt::Windows::Storage::StorageFolder folder = + winrt::Windows::Storage::StorageFolder::GetFolderFromPathAsync(modulePath).get(); + winrt::Windows::Storage::StorageFile file = + folder.CreateFileAsync(filename, winrt::Windows::Storage::CreationCollisionOption::ReplaceExisting).get(); + winrt::Windows::Storage::Streams::IRandomAccessStream write_stream = + file.OpenAsync(winrt::Windows::Storage::FileAccessMode::ReadWrite).get(); + winrt::Windows::Graphics::Imaging::BitmapEncoder encoder = + winrt::Windows::Graphics::Imaging::BitmapEncoder::CreateAsync( + winrt::Windows::Graphics::Imaging::BitmapEncoder::JpegEncoderId(), write_stream + ) + .get(); encoder.SetSoftwareBitmap(bitmap); encoder.FlushAsync().get(); } #if !defined(BUILD_INBOX) static void DiscreteFourierTransform_2D(LearningModelDeviceKind kind) { - using namespace winrt::Windows::Storage; using namespace winrt::Windows::Storage::Streams; using namespace winrt::Windows::Graphics::Imaging; @@ -505,11 +503,9 @@ static void DiscreteFourierTransform_2D(LearningModelDeviceKind kind) { SoftwareBitmap softwareBitmap = (BitmapDecoder::CreateAsync(stream).get()).GetSoftwareBitmapAsync().get(); VideoFrame frame = VideoFrame::CreateWithSoftwareBitmap(softwareBitmap); - auto corrected_image = - winrt::Windows::Media::VideoFrame( - winrt::Windows::Graphics::Imaging::BitmapPixelFormat::Bgra8, - INT32(256), - INT32(256)); + auto corrected_image = winrt::Windows::Media::VideoFrame( + winrt::Windows::Graphics::Imaging::BitmapPixelFormat::Bgra8, INT32(256), INT32(256) + ); frame.CopyToAsync(corrected_image).get(); @@ -534,63 +530,79 @@ static void DiscreteFourierTransform_2D(LearningModelDeviceKind kind) { printf("\n Is Onesided: false"); auto builder = - LearningModelBuilder::Create(17) - .Inputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Input.Signal", TensorKind::Float, input_shape)) - .Outputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Output.Spectra", TensorKind::Float, output_shape)) - .Outputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Output.Inverse", TensorKind::Float, output_shape)) - .Outputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Output.Error", TensorKind::Float, output_shape)) - .Operators().Add(Operator(L"Reshape") - .SetInput(L"data", L"Input.Signal") - .SetConstant(L"shape", TensorInt64Bit::CreateFromArray({4}, {INT64(1), INT64(height), INT64(width), INT64(1) })) - .SetOutput(L"reshaped", L"reshaped_output")) - .Operators().Add(Operator(L"DFT") - .SetInput(L"input", L"reshaped_output") - .SetAttribute(L"axis", TensorInt64Bit::CreateFromArray({}, {INT64(1)})) - .SetOutput(L"output", L"DFT.Output.1")) - .Operators().Add(Operator(L"DFT") - .SetInput(L"input", L"DFT.Output.1") - .SetAttribute(L"axis", TensorInt64Bit::CreateFromArray({}, {INT64(2)})) - .SetOutput(L"output", L"DFT.Output.2")) - .Operators().Add(Operator(L"DFT") - .SetInput(L"input", L"DFT.Output.2") - .SetAttribute(L"axis", TensorInt64Bit::CreateFromArray({}, {INT64(2)})) - .SetAttribute(L"inverse", TensorInt64Bit::CreateFromArray({}, {INT64(1)})) - .SetOutput(L"output", L"IDFT.Output.1")) - .Operators().Add(Operator(L"DFT") - .SetInput(L"input", L"IDFT.Output.1") - .SetAttribute(L"axis", TensorInt64Bit::CreateFromArray({}, {INT64(1)})) - .SetAttribute(L"inverse", TensorInt64Bit::CreateFromArray({}, {INT64(1)})) - .SetOutput(L"output", L"IDFT.Output.2")) - .Operators().Add(Operator(L"ReduceSumSquare") - .SetInput(L"data", L"DFT.Output.2") - .SetAttribute(L"axes", TensorInt64Bit::CreateFromArray({1}, {3})) - .SetAttribute(L"keepdims", TensorInt64Bit::CreateFromArray({}, {0})) - .SetOutput(L"reduced", L"magnitude_squared")) - .Operators().Add(Operator(L"Sqrt") - .SetInput(L"X", L"magnitude_squared") - .SetOutput(L"Y", L"sqrt_magnitude")) - .Operators().Add(Operator(L"ReduceSumSquare") - .SetInput(L"data", L"IDFT.Output.2") - .SetAttribute(L"axes", TensorInt64Bit::CreateFromArray({1}, {3})) - .SetAttribute(L"keepdims", TensorInt64Bit::CreateFromArray({}, {0})) - .SetOutput(L"reduced", L"magnitude_squared2")) - .Operators().Add(Operator(L"Sqrt") - .SetInput(L"X", L"magnitude_squared2") - .SetOutput(L"Y", L"sqrt_magnitude2")) - .Operators() - .Add(Operator(L"Reshape") - .SetInput(L"data", L"sqrt_magnitude") - .SetConstant(L"shape", TensorInt64Bit::CreateFromArray({4}, {INT64(1), INT64(1), INT64(height), INT64(width) })) - .SetOutput(L"reshaped", L"Output.Spectra")) - .Operators() - .Add(Operator(L"Reshape") - .SetInput(L"data", L"sqrt_magnitude2") - .SetConstant(L"shape", TensorInt64Bit::CreateFromArray({4}, {INT64(1), INT64(1), INT64(height), INT64(width) })) - .SetOutput(L"reshaped", L"Output.Inverse")) - .Operators().Add(Operator(L"Sub") - .SetInput(L"A", L"Input.Signal") - .SetInput(L"B", L"Output.Inverse") - .SetOutput(L"C", L"Output.Error")); + LearningModelBuilder::Create(17) + .Inputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Input.Signal", TensorKind::Float, input_shape)) + .Outputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Output.Spectra", TensorKind::Float, output_shape)) + .Outputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Output.Inverse", TensorKind::Float, output_shape)) + .Outputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Output.Error", TensorKind::Float, output_shape)) + .Operators() + .Add(Operator(L"Reshape") + .SetInput(L"data", L"Input.Signal") + .SetConstant( + L"shape", TensorInt64Bit::CreateFromArray({4}, {INT64(1), INT64(height), INT64(width), INT64(1)}) + ) + .SetOutput(L"reshaped", L"reshaped_output")) + .Operators() + .Add(Operator(L"DFT") + .SetInput(L"input", L"reshaped_output") + .SetAttribute(L"axis", TensorInt64Bit::CreateFromArray({}, {INT64(1)})) + .SetOutput(L"output", L"DFT.Output.1")) + .Operators() + .Add(Operator(L"DFT") + .SetInput(L"input", L"DFT.Output.1") + .SetAttribute(L"axis", TensorInt64Bit::CreateFromArray({}, {INT64(2)})) + .SetOutput(L"output", L"DFT.Output.2")) + .Operators() + .Add(Operator(L"DFT") + .SetInput(L"input", L"DFT.Output.2") + .SetAttribute(L"axis", TensorInt64Bit::CreateFromArray({}, {INT64(2)})) + .SetAttribute(L"inverse", TensorInt64Bit::CreateFromArray({}, {INT64(1)})) + .SetOutput(L"output", L"IDFT.Output.1")) + .Operators() + .Add(Operator(L"DFT") + .SetInput(L"input", L"IDFT.Output.1") + .SetAttribute(L"axis", TensorInt64Bit::CreateFromArray({}, {INT64(1)})) + .SetAttribute(L"inverse", TensorInt64Bit::CreateFromArray({}, {INT64(1)})) + .SetOutput(L"output", L"IDFT.Output.2")) + .Operators() + .Add(Operator(L"ReduceSumSquare") + .SetInput(L"data", L"DFT.Output.2") + .SetAttribute(L"axes", TensorInt64Bit::CreateFromArray({1}, {3})) + .SetAttribute(L"keepdims", TensorInt64Bit::CreateFromArray({}, {0})) + .SetOutput(L"reduced", L"magnitude_squared")) + .Operators() + .Add(Operator(L"Sqrt").SetInput(L"X", L"magnitude_squared").SetOutput(L"Y", L"sqrt_magnitude")) + .Operators() + .Add(Operator(L"ReduceSumSquare") + .SetInput(L"data", L"IDFT.Output.2") + .SetAttribute(L"axes", TensorInt64Bit::CreateFromArray({1}, {3})) + .SetAttribute(L"keepdims", TensorInt64Bit::CreateFromArray({}, {0})) + .SetOutput(L"reduced", L"magnitude_squared2")) + .Operators() + .Add(Operator(L"Sqrt").SetInput(L"X", L"magnitude_squared2").SetOutput(L"Y", L"sqrt_magnitude2")) + .Operators() + .Add(Operator(L"Reshape") + .SetInput(L"data", L"sqrt_magnitude") + .SetConstant( + L"shape", TensorInt64Bit::CreateFromArray({4}, {INT64(1), INT64(1), INT64(height), INT64(width)}) + ) + .SetOutput(L"reshaped", L"Output.Spectra")) + .Operators() + .Add(Operator(L"Reshape") + .SetInput(L"data", L"sqrt_magnitude2") + .SetConstant( + L"shape", TensorInt64Bit::CreateFromArray({4}, {INT64(1), INT64(1), INT64(height), INT64(width)}) + ) + .SetOutput(L"reshaped", L"Output.Inverse")) + .Operators() + .Add(Operator(L"Sub") + .SetInput(L"A", L"Input.Signal") + .SetInput(L"B", L"Output.Inverse") + .SetOutput(L"C", L"Output.Error")); auto model = builder.CreateModel(); auto device = LearningModelDevice(kind); @@ -632,13 +644,14 @@ static void DiscreteFourierTransform_2D(LearningModelDeviceKind kind) { template static void DiscreteFourierTransform( - LearningModelDeviceKind kind, - const std::vector& input, - const std::vector& input_shape, - const std::vector>& expected_output, - size_t axis, - size_t dft_length, - bool is_onesided = false) { + LearningModelDeviceKind kind, + const std::vector& input, + const std::vector& input_shape, + const std::vector>& expected_output, + size_t axis, + size_t dft_length, + bool is_onesided = false +) { // Calculate expected output shape auto output_shape = input_shape; if (output_shape.size() != 2) { @@ -668,15 +681,19 @@ static void DiscreteFourierTransform( auto model = LearningModelBuilder::Create(17) - .Inputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Input.Signal", TensorKind::Float, input_shape)) - .Inputs().AddConstant(L"Input.DFTLength", TensorInt64Bit::CreateFromArray({}, {INT64(dft_length)})) - .Outputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Output.Spectra", TensorKind::Float, output_shape)) - .Operators().Add(Operator(L"DFT") - .SetInput(L"input", L"Input.Signal") - .SetInput(L"dft_length", L"Input.DFTLength") - .SetAttribute(L"axis", TensorInt64Bit::CreateFromArray({}, {INT64(axis)})) - .SetAttribute(L"onesided", TensorInt64Bit::CreateFromArray({}, {is_onesided})) - .SetOutput(L"output", L"Output.Spectra")) + .Inputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Input.Signal", TensorKind::Float, input_shape)) + .Inputs() + .AddConstant(L"Input.DFTLength", TensorInt64Bit::CreateFromArray({}, {INT64(dft_length)})) + .Outputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Output.Spectra", TensorKind::Float, output_shape)) + .Operators() + .Add(Operator(L"DFT") + .SetInput(L"input", L"Input.Signal") + .SetInput(L"dft_length", L"Input.DFTLength") + .SetAttribute(L"axis", TensorInt64Bit::CreateFromArray({}, {INT64(axis)})) + .SetAttribute(L"onesided", TensorInt64Bit::CreateFromArray({}, {is_onesided})) + .SetOutput(L"output", L"Output.Spectra")) .CreateModel(); auto device = LearningModelDevice(kind); LearningModelSession session(model, device); @@ -703,8 +720,23 @@ static void DiscreteFourierTransform( for (uint32_t i = 0; i < y_ivv.Size(); i += 2) { // Check results constexpr float error_threshold = .001f; - WINML_EXPECT_TRUE(abs(y_ivv.GetAt(i) - expected_output[i / 2].real()) < error_threshold); - WINML_EXPECT_TRUE(abs(y_ivv.GetAt(i + 1) - expected_output[i / 2].imag()) < error_threshold); + + auto inRealRange = abs(y_ivv.GetAt(i) - expected_output[i / 2].real()) < error_threshold; + auto inImagRange = abs(y_ivv.GetAt(i + 1) - expected_output[i / 2].imag()) < error_threshold; + auto inRange = inRealRange && inImagRange; + + if (!inRange) { + printf( + "[%d] ACTUAL(%f + %fi) EXPECTED(%f + %fi)\n", + (int)i / 2, + y_ivv.GetAt(i), + y_ivv.GetAt(i + 1), + expected_output[i / 2].real(), + expected_output[i / 2].imag() + ); + } + + WINML_EXPECT_TRUE(inRange); } printf("\n\n"); } @@ -714,7 +746,7 @@ static void DiscreteFourierTransform( template static auto MakePureFrequency(float frequency_in_hertz, size_t signal_size, size_t sample_rate) { float amplitude = 4; - float angular_velocity = frequency_in_hertz * 2 * 3.1415f; + float angular_velocity = frequency_in_hertz * 2 * static_cast(M_PI); std::vector signal(signal_size); for (size_t i = 0; i < signal_size; i++) { T time = i / static_cast(sample_rate); @@ -747,45 +779,44 @@ static auto MakeThreeTones(size_t signal_size, size_t sample_rate) { auto c2 = MakeC2(signal_size, sample_rate); auto c4 = MakeC4(signal_size, sample_rate); for (size_t i = 0; i < signal_size; i++) { - middle_c[i] = (i < signal_size / 3) ? - middle_c[i] : - (i < 2*signal_size/3) ? - (middle_c[i] + c2[i]) : - (middle_c[i] + c2[i] + c4[i]); + middle_c[i] = (i < signal_size / 3) ? middle_c[i] + : (i < 2 * signal_size / 3) ? (middle_c[i] + c2[i]) + : (middle_c[i] + c2[i] + c4[i]); } return middle_c; } #if !defined(BUILD_INBOX) -static void STFT(size_t batch_size, size_t signal_size, size_t dft_size, - size_t hop_size, size_t sample_rate, bool is_onesided = false) { +static void STFT( + size_t batch_size, size_t signal_size, size_t dft_size, size_t hop_size, size_t sample_rate, bool is_onesided = false +) { auto n_dfts = static_cast(1 + floor((signal_size - dft_size) / hop_size)); auto input_shape = std::vector{1, INT64(signal_size)}; - auto output_shape = - std::vector{ - INT64(batch_size), - INT64(n_dfts), - is_onesided ? ((INT64(dft_size) >> 1) + 1) : INT64(dft_size), - 2 - }; + auto output_shape = std::vector{ + INT64(batch_size), INT64(n_dfts), is_onesided ? ((INT64(dft_size) >> 1) + 1) : INT64(dft_size), 2}; auto dft_length = TensorInt64Bit::CreateFromArray({}, {INT64(dft_size)}); auto model = - LearningModelBuilder::Create(17) - .Inputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Input.TimeSignal", TensorKind::Float, input_shape)) - .Outputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Output.STFT", TensorKind::Float, output_shape)) - .Outputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Output.HannWindow", TensorKind::Float, {INT64(dft_size)})) - .Operators().Add(Operator(L"HannWindow") - .SetConstant(L"size", dft_length) - .SetOutput(L"output", L"Output.HannWindow")) - .Operators().Add(Operator(L"STFT") - .SetAttribute(L"onesided", TensorInt64Bit::CreateFromArray({}, {INT64(is_onesided)})) - .SetInput(L"signal", L"Input.TimeSignal") - .SetInput(L"window", L"Output.HannWindow") - .SetConstant(L"frame_length", dft_length) - .SetConstant(L"frame_step", TensorInt64Bit::CreateFromArray({}, {INT64(hop_size)})) - .SetOutput(L"output", L"Output.STFT")) - .CreateModel(); + LearningModelBuilder::Create(17) + .Inputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Input.TimeSignal", TensorKind::Float, input_shape)) + .Outputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Output.STFT", TensorKind::Float, output_shape)) + .Outputs() + .Add( + LearningModelBuilder::CreateTensorFeatureDescriptor(L"Output.HannWindow", TensorKind::Float, {INT64(dft_size)}) + ) + .Operators() + .Add(Operator(L"HannWindow").SetConstant(L"size", dft_length).SetOutput(L"output", L"Output.HannWindow")) + .Operators() + .Add(Operator(L"STFT") + .SetAttribute(L"onesided", TensorInt64Bit::CreateFromArray({}, {INT64(is_onesided)})) + .SetInput(L"signal", L"Input.TimeSignal") + .SetInput(L"window", L"Output.HannWindow") + .SetConstant(L"frame_length", dft_length) + .SetConstant(L"frame_step", TensorInt64Bit::CreateFromArray({}, {INT64(hop_size)})) + .SetOutput(L"output", L"Output.STFT")) + .CreateModel(); LearningModelSession session(model); LearningModelBinding binding(session); @@ -835,16 +866,19 @@ static void STFT(size_t batch_size, size_t signal_size, size_t dft_size, static void ModelBuilding_MelWeightMatrix() { #if !defined(BUILD_INBOX) std::vector output_shape = {INT64(9), INT64(8)}; - auto builder = - LearningModelBuilder::Create(17) - .Outputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Output.MelWeightMatrix", TensorKind::Float, output_shape)) - .Operators().Add(Operator(L"MelWeightMatrix") - .SetConstant(L"num_mel_bins", TensorInt64Bit::CreateFromArray({}, {INT64(8)})) - .SetConstant(L"dft_length", TensorInt64Bit::CreateFromArray({}, {INT64(16)})) - .SetConstant(L"sample_rate", TensorInt64Bit::CreateFromArray({}, {INT64(8192)})) - .SetConstant(L"lower_edge_hertz", TensorFloat::CreateFromArray({}, {0})) - .SetConstant(L"upper_edge_hertz", TensorFloat::CreateFromArray({}, {8192 / 2.f})) - .SetOutput(L"output", L"Output.MelWeightMatrix")); + auto builder = LearningModelBuilder::Create(17) + .Outputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor( + L"Output.MelWeightMatrix", TensorKind::Float, output_shape + )) + .Operators() + .Add(Operator(L"MelWeightMatrix") + .SetConstant(L"num_mel_bins", TensorInt64Bit::CreateFromArray({}, {INT64(8)})) + .SetConstant(L"dft_length", TensorInt64Bit::CreateFromArray({}, {INT64(16)})) + .SetConstant(L"sample_rate", TensorInt64Bit::CreateFromArray({}, {INT64(8192)})) + .SetConstant(L"lower_edge_hertz", TensorFloat::CreateFromArray({}, {0})) + .SetConstant(L"upper_edge_hertz", TensorFloat::CreateFromArray({}, {8192 / 2.f})) + .SetOutput(L"output", L"Output.MelWeightMatrix")); auto model = builder.CreateModel(); LearningModelSession session(model); @@ -870,8 +904,14 @@ static void ModelBuilding_MelWeightMatrix() { #if !defined(BUILD_INBOX) static void MelSpectrogramOnThreeToneSignal( - size_t batch_size, size_t signal_size, size_t window_size, size_t dft_size, - size_t hop_size, size_t n_mel_bins, size_t sampling_rate) { + size_t batch_size, + size_t signal_size, + size_t window_size, + size_t dft_size, + size_t hop_size, + size_t n_mel_bins, + size_t sampling_rate +) { auto n_dfts = static_cast(1 + floor((signal_size - dft_size) / hop_size)); auto onesided_dft_size = (dft_size >> 1) + 1; std::vector signal_shape = {INT64(batch_size), INT64(signal_size)}; @@ -879,46 +919,60 @@ static void MelSpectrogramOnThreeToneSignal( auto builder = LearningModelBuilder::Create(17) - .Inputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Input.TimeSignal", TensorKind::Float, signal_shape)) - .Outputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Output.MelSpectrogram", TensorKind::Float, mel_spectrogram_shape)) - .Operators().Add(Operator(L"HannWindow") - .SetConstant(L"size", TensorInt64Bit::CreateFromArray({}, {INT64(window_size)})) - .SetOutput(L"output", L"hann_window")) - .Operators().Add(Operator(L"STFT") - .SetName(L"STFT_NAMED_NODE") - .SetInput(L"signal", L"Input.TimeSignal") - .SetInput(L"window", L"hann_window") - .SetConstant(L"frame_length", TensorInt64Bit::CreateFromArray({}, {INT64(dft_size)})) - .SetConstant(L"frame_step", TensorInt64Bit::CreateFromArray({}, {INT64(hop_size)})) - .SetOutput(L"output", L"stft_output")) - .Operators().Add(Operator(L"ReduceSumSquare") - .SetInput(L"data", L"stft_output") - .SetAttribute(L"axes", TensorInt64Bit::CreateFromArray({1}, {3})) - .SetAttribute(L"keepdims", TensorInt64Bit::CreateFromArray({}, {0})) - .SetOutput(L"reduced", L"magnitude_squared")) - .Operators().Add(Operator(L"Div") - .SetInput(L"A", L"magnitude_squared") - .SetConstant(L"B", TensorFloat::CreateFromArray({}, {static_cast(dft_size)})) - .SetOutput(L"C", L"power_frames")) - .Operators().Add(Operator(L"MelWeightMatrix") - .SetConstant(L"num_mel_bins", TensorInt64Bit::CreateFromArray({}, {INT64(n_mel_bins)})) - .SetConstant(L"dft_length", TensorInt64Bit::CreateFromArray({}, {INT64(dft_size)})) - .SetConstant(L"sample_rate", TensorInt64Bit::CreateFromArray({}, {INT64(sampling_rate)})) - .SetConstant(L"lower_edge_hertz", TensorFloat::CreateFromArray({}, {0})) - .SetConstant(L"upper_edge_hertz", TensorFloat::CreateFromArray({}, {sampling_rate / 2.f})) - .SetOutput(L"output", L"mel_weight_matrix")) - .Operators().Add(Operator(L"Reshape") - .SetInput(L"data", L"power_frames") - .SetConstant(L"shape", TensorInt64Bit::CreateFromArray({2}, {INT64(batch_size * n_dfts), INT64(onesided_dft_size)})) - .SetOutput(L"reshaped", L"reshaped_output")) - .Operators().Add(Operator(L"MatMul") - .SetInput(L"A", L"reshaped_output") - .SetInput(L"B", L"mel_weight_matrix") - .SetOutput(L"Y", L"mel_spectrogram")) - .Operators().Add(Operator(L"Reshape") - .SetInput(L"data", L"mel_spectrogram") - .SetConstant(L"shape", TensorInt64Bit::CreateFromArray({4}, mel_spectrogram_shape)) - .SetOutput(L"reshaped", L"Output.MelSpectrogram")); + .Inputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Input.TimeSignal", TensorKind::Float, signal_shape)) + .Outputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor( + L"Output.MelSpectrogram", TensorKind::Float, mel_spectrogram_shape + )) + .Operators() + .Add(Operator(L"HannWindow") + .SetConstant(L"size", TensorInt64Bit::CreateFromArray({}, {INT64(window_size)})) + .SetOutput(L"output", L"hann_window")) + .Operators() + .Add(Operator(L"STFT") + .SetName(L"STFT_NAMED_NODE") + .SetInput(L"signal", L"Input.TimeSignal") + .SetInput(L"window", L"hann_window") + .SetConstant(L"frame_length", TensorInt64Bit::CreateFromArray({}, {INT64(dft_size)})) + .SetConstant(L"frame_step", TensorInt64Bit::CreateFromArray({}, {INT64(hop_size)})) + .SetOutput(L"output", L"stft_output")) + .Operators() + .Add(Operator(L"ReduceSumSquare") + .SetInput(L"data", L"stft_output") + .SetAttribute(L"axes", TensorInt64Bit::CreateFromArray({1}, {3})) + .SetAttribute(L"keepdims", TensorInt64Bit::CreateFromArray({}, {0})) + .SetOutput(L"reduced", L"magnitude_squared")) + .Operators() + .Add(Operator(L"Div") + .SetInput(L"A", L"magnitude_squared") + .SetConstant(L"B", TensorFloat::CreateFromArray({}, {static_cast(dft_size)})) + .SetOutput(L"C", L"power_frames")) + .Operators() + .Add(Operator(L"MelWeightMatrix") + .SetConstant(L"num_mel_bins", TensorInt64Bit::CreateFromArray({}, {INT64(n_mel_bins)})) + .SetConstant(L"dft_length", TensorInt64Bit::CreateFromArray({}, {INT64(dft_size)})) + .SetConstant(L"sample_rate", TensorInt64Bit::CreateFromArray({}, {INT64(sampling_rate)})) + .SetConstant(L"lower_edge_hertz", TensorFloat::CreateFromArray({}, {0})) + .SetConstant(L"upper_edge_hertz", TensorFloat::CreateFromArray({}, {sampling_rate / 2.f})) + .SetOutput(L"output", L"mel_weight_matrix")) + .Operators() + .Add(Operator(L"Reshape") + .SetInput(L"data", L"power_frames") + .SetConstant( + L"shape", TensorInt64Bit::CreateFromArray({2}, {INT64(batch_size * n_dfts), INT64(onesided_dft_size)}) + ) + .SetOutput(L"reshaped", L"reshaped_output")) + .Operators() + .Add(Operator(L"MatMul") + .SetInput(L"A", L"reshaped_output") + .SetInput(L"B", L"mel_weight_matrix") + .SetOutput(L"Y", L"mel_spectrogram")) + .Operators() + .Add(Operator(L"Reshape") + .SetInput(L"data", L"mel_spectrogram") + .SetConstant(L"shape", TensorInt64Bit::CreateFromArray({4}, mel_spectrogram_shape)) + .SetOutput(L"reshaped", L"Output.MelSpectrogram")); auto model = builder.CreateModel(); LearningModelSession session(model); @@ -929,11 +983,9 @@ static void MelSpectrogramOnThreeToneSignal( binding.Bind(L"Input.TimeSignal", TensorFloat::CreateFromArray(signal_shape, signal)); // Bind output - auto output_image = - winrt::Windows::Media::VideoFrame( - winrt::Windows::Graphics::Imaging::BitmapPixelFormat::Bgra8, - INT32(n_mel_bins), - INT32(n_dfts)); + auto output_image = winrt::Windows::Media::VideoFrame( + winrt::Windows::Graphics::Imaging::BitmapPixelFormat::Bgra8, INT32(n_mel_bins), INT32(n_dfts) + ); binding.Bind(L"Output.MelSpectrogram", output_image); // Evaluate @@ -948,10 +1000,17 @@ static void MelSpectrogramOnThreeToneSignal( // Save the output std::wstring modulePath = FileHelpers::GetModulePath(); - winrt::Windows::Storage::StorageFolder folder = winrt::Windows::Storage::StorageFolder::GetFolderFromPathAsync(modulePath).get(); - winrt::Windows::Storage::StorageFile file = folder.CreateFileAsync(out_name, winrt::Windows::Storage::CreationCollisionOption::ReplaceExisting).get(); - winrt::Windows::Storage::Streams::IRandomAccessStream write_stream = file.OpenAsync(winrt::Windows::Storage::FileAccessMode::ReadWrite).get(); - winrt::Windows::Graphics::Imaging::BitmapEncoder encoder = winrt::Windows::Graphics::Imaging::BitmapEncoder::CreateAsync(winrt::Windows::Graphics::Imaging::BitmapEncoder::JpegEncoderId(), write_stream).get(); + winrt::Windows::Storage::StorageFolder folder = + winrt::Windows::Storage::StorageFolder::GetFolderFromPathAsync(modulePath).get(); + winrt::Windows::Storage::StorageFile file = + folder.CreateFileAsync(out_name, winrt::Windows::Storage::CreationCollisionOption::ReplaceExisting).get(); + winrt::Windows::Storage::Streams::IRandomAccessStream write_stream = + file.OpenAsync(winrt::Windows::Storage::FileAccessMode::ReadWrite).get(); + winrt::Windows::Graphics::Imaging::BitmapEncoder encoder = + winrt::Windows::Graphics::Imaging::BitmapEncoder::CreateAsync( + winrt::Windows::Graphics::Imaging::BitmapEncoder::JpegEncoderId(), write_stream + ) + .get(); encoder.SetSoftwareBitmap(output_image.SoftwareBitmap()); encoder.FlushAsync().get(); @@ -968,34 +1027,50 @@ static void ModelBuilding_StandardDeviationNormalization() { int64_t channels = 3; std::vector input_shape = {1, height, width, channels}; std::vector output_shape = {1, channels, height, width}; - auto sub_model = - LearningModelBuilder::Create(13) - .Inputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Input", L"The NHWC image", TensorKind::Float, input_shape)) - .Inputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Means", TensorKind::Float, {channels})) - .Outputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Output", L"The NCHW image normalized with mean and stddev.", TensorKind::Float, input_shape)) - .Operators().Add(Operator(L"Sub") - .SetInput(L"A", L"Input") - .SetInput(L"B", L"Means") - .SetOutput(L"C", L"Output")) - .CreateModel(); + auto sub_model = LearningModelBuilder::Create(13) + .Inputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor( + L"Input", L"The NHWC image", TensorKind::Float, input_shape + )) + .Inputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Means", TensorKind::Float, {channels})) + .Outputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor( + L"Output", L"The NCHW image normalized with mean and stddev.", TensorKind::Float, input_shape + )) + .Operators() + .Add(Operator(L"Sub").SetInput(L"A", L"Input").SetInput(L"B", L"Means").SetOutput(L"C", L"Output")) + .CreateModel(); auto div_model = LearningModelBuilder::Create(13) - .Inputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Input", L"The NHWC image", TensorKind::Float, input_shape)) - .Inputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"StdDevs", TensorKind::Float, {channels})) - .Outputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Output", L"The NCHW image normalized with mean and stddev.", TensorKind::Float, input_shape)) - .Operators().Add(Operator(L"Div") - .SetInput(L"A", L"Input") - .SetInput(L"B", L"StdDevs") - .SetOutput(L"C", L"Output")) + .Inputs() + .Add( + LearningModelBuilder::CreateTensorFeatureDescriptor(L"Input", L"The NHWC image", TensorKind::Float, input_shape) + ) + .Inputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"StdDevs", TensorKind::Float, {channels})) + .Outputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor( + L"Output", L"The NCHW image normalized with mean and stddev.", TensorKind::Float, input_shape + )) + .Operators() + .Add(Operator(L"Div").SetInput(L"A", L"Input").SetInput(L"B", L"StdDevs").SetOutput(L"C", L"Output")) .CreateModel(); auto transpose_model = LearningModelBuilder::Create(13) - .Inputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Input", L"The NHWC image", TensorKind::Float, input_shape)) - .Outputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Output", L"The NCHW image normalized with mean and stddev.", TensorKind::Float, output_shape)) - .Operators().Add(Operator(L"Transpose") - .SetInput(L"data", L"Input") - .SetAttribute(L"perm", TensorInt64Bit::CreateFromArray({4}, {0, 3, 1, 2})) - .SetOutput(L"transposed", L"Output")) + .Inputs() + .Add( + LearningModelBuilder::CreateTensorFeatureDescriptor(L"Input", L"The NHWC image", TensorKind::Float, input_shape) + ) + .Outputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor( + L"Output", L"The NCHW image normalized with mean and stddev.", TensorKind::Float, output_shape + )) + .Operators() + .Add(Operator(L"Transpose") + .SetInput(L"data", L"Input") + .SetAttribute(L"perm", TensorInt64Bit::CreateFromArray({4}, {0, 3, 1, 2})) + .SetOutput(L"transposed", L"Output")) .CreateModel(); auto sub_experimental = winml_experimental::LearningModelExperimental(sub_model); @@ -1006,7 +1081,9 @@ static void ModelBuilding_StandardDeviationNormalization() { auto joined_model_experimental = winml_experimental::LearningModelExperimental(joined_model); winml_experimental::LearningModelJoinOptions transpose_join_options; - transpose_join_options.Link(joined_model.OutputFeatures().GetAt(0).Name(), transpose_model.InputFeatures().GetAt(0).Name()); + transpose_join_options.Link( + joined_model.OutputFeatures().GetAt(0).Name(), transpose_model.InputFeatures().GetAt(0).Name() + ); transpose_join_options.JoinedNodePrefix(L"TransposeModel."); auto final_model = joined_model_experimental.JoinModel(transpose_model, transpose_join_options); @@ -1032,18 +1109,22 @@ static void ModelBuilding_StandardDeviationNormalization() { static void ModelBuilding_Gemm() { #ifndef BUILD_INBOX std::vector shape = {3, 3}; - auto model = - LearningModelBuilder::Create(13) - .Inputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"InputA", TensorKind::Float, shape)) - .Inputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"InputB", TensorKind::Float, shape)) - .Inputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"InputC", TensorKind::Float, shape)) - .Outputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"OutputY", TensorKind::Float, shape)) - .Operators().Add(Operator(L"Gemm") - .SetInput(L"A", L"InputA") - .SetInput(L"B", L"InputB") - .SetInput(L"C", L"InputC") - .SetOutput(L"Y", L"OutputY")) - .CreateModel(); + auto model = LearningModelBuilder::Create(13) + .Inputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"InputA", TensorKind::Float, shape)) + .Inputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"InputB", TensorKind::Float, shape)) + .Inputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"InputC", TensorKind::Float, shape)) + .Outputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"OutputY", TensorKind::Float, shape)) + .Operators() + .Add(Operator(L"Gemm") + .SetInput(L"A", L"InputA") + .SetInput(L"B", L"InputB") + .SetInput(L"C", L"InputC") + .SetOutput(L"Y", L"OutputY")) + .CreateModel(); #endif } @@ -1053,15 +1134,16 @@ static void ModelBuilding_DynamicMatmul() { std::vector b_shape = {129, 1024}; auto model = - LearningModelBuilder::Create(13) - .Inputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"InputA", TensorKind::Float, a_shape)) - .Inputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"InputB", TensorKind::Float, b_shape)) - .Outputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Output", TensorKind::Float, {a_shape[0], b_shape[1]})) - .Operators().Add(Operator(L"MatMul") - .SetInput(L"A", L"InputA") - .SetInput(L"B", L"InputB") - .SetOutput(L"Y", L"Output")) - .CreateModel(); + LearningModelBuilder::Create(13) + .Inputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"InputA", TensorKind::Float, a_shape)) + .Inputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"InputB", TensorKind::Float, b_shape)) + .Outputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Output", TensorKind::Float, {a_shape[0], b_shape[1]})) + .Operators() + .Add(Operator(L"MatMul").SetInput(L"A", L"InputA").SetInput(L"B", L"InputB").SetOutput(L"Y", L"Output")) + .CreateModel(); LearningModelSession session(model); LearningModelBinding binding(session); @@ -1092,12 +1174,17 @@ static void ModelBuilding_ConstantMatmul() { auto model = LearningModelBuilder::Create(13) - .Inputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"InputA", TensorKind::Float, a_shape)) - .Outputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Output", TensorKind::Float, {a_shape[0], b_shape[1]})) - .Operators().Add(Operator(L"MatMul") - .SetInput(L"A", L"InputA") - .SetConstant(L"B", TensorFloat::CreateFromArray(b_shape, std::vector(SIZET(b_shape[0] * b_shape[1]), 1))) - .SetOutput(L"Y", L"Output")) + .Inputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"InputA", TensorKind::Float, a_shape)) + .Outputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Output", TensorKind::Float, {a_shape[0], b_shape[1]})) + .Operators() + .Add(Operator(L"MatMul") + .SetInput(L"A", L"InputA") + .SetConstant( + L"B", TensorFloat::CreateFromArray(b_shape, std::vector(SIZET(b_shape[0] * b_shape[1]), 1)) + ) + .SetOutput(L"Y", L"Output")) .CreateModel(); LearningModelSession session(model); @@ -1117,148 +1204,810 @@ static void ModelBuilding_ConstantMatmul() { } #if !defined(BUILD_INBOX) + +enum class Mode : uint32_t { + Bilinear, + Nearest, + Bicubic, +}; + +enum class PaddingMode : uint32_t { + Zeros, + Border, + Reflection, +}; + +template +static void GridSample( + LearningModelDeviceKind kind, + const std::vector& input, + const std::vector& input_dims, + const std::vector& grid, + const std::vector& grid_dims, + bool align_corners, + Mode mode, + PaddingMode padding_mode +) { + const hstring modes[] = {L"bilinear", L"nearest", L"bicubic"}; + + const hstring padding_modes[] = {L"zeros", L"border", L"reflection"}; + + auto model = + LearningModelBuilder::Create(17) + .Inputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Input", TensorKind::Float, input_dims)) + .Inputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Grid", TensorKind::Float, grid_dims)) + .Outputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Output", TensorKind::Float, {-1, -1, -1, -1})) + .Operators() + .Add(Operator(L"GridSample") + .SetInput(L"X", L"Input") + .SetInput(L"grid", L"Grid") + .SetAttribute(L"align_corners", TensorInt64Bit::CreateFromArray({}, {INT64(align_corners)})) + .SetAttribute(L"mode", TensorString::CreateFromArray({}, {modes[static_cast(mode)]})) + .SetAttribute( + L"padding_mode", TensorString::CreateFromArray({}, {padding_modes[static_cast(padding_mode)]}) + ) + .SetOutput(L"Y", L"Output")) + .CreateModel(); + auto cpu_device = LearningModelDevice(LearningModelDeviceKind::Cpu); + auto device = LearningModelDevice(kind); + LearningModelSession device_session(model, device); + LearningModelBinding device_binding(device_session); + LearningModelSession cpu_session(model, cpu_device); + LearningModelBinding cpu_binding(cpu_session); + + device_binding.Bind(L"Input", TensorFloat::CreateFromShapeArrayAndDataArray(input_dims, input)); + device_binding.Bind(L"Grid", TensorFloat::CreateFromShapeArrayAndDataArray(grid_dims, grid)); + cpu_binding.Bind(L"Input", TensorFloat::CreateFromShapeArrayAndDataArray(input_dims, input)); + cpu_binding.Bind(L"Grid", TensorFloat::CreateFromShapeArrayAndDataArray(grid_dims, grid)); + + auto cpu_result = cpu_session.Evaluate(cpu_binding, L""); + + // Evaluate + auto start = std::chrono::high_resolution_clock::now(); + auto device_result = device_session.Evaluate(device_binding, L""); + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration evaluate_duration_in_microseconds = end - start; + printf( + "GridSample[Mode=%ls, PaddingMode=%ls, AlignCorners=%s] took %fus.\n", + modes[static_cast(mode)].c_str(), + padding_modes[static_cast(padding_mode)].c_str(), + align_corners ? "True" : "False", + evaluate_duration_in_microseconds.count() + ); + + // Check results + constexpr float error_threshold = .001f; + auto device_y_tensor = device_result.Outputs().Lookup(L"Output").as(); + auto device_y_ivv = device_y_tensor.GetAsVectorView(); + auto cpu_y_tensor = cpu_result.Outputs().Lookup(L"Output").as(); + auto cpu_y_ivv = cpu_y_tensor.GetAsVectorView(); + WINML_EXPECT_EQUAL(device_y_ivv.Size(), cpu_y_ivv.Size()); + for (uint32_t i = 0; i < device_y_ivv.Size(); i++) { + bool in_range = abs(device_y_ivv.GetAt(i) - cpu_y_ivv.GetAt(i)) < error_threshold; + if (!in_range) { + printf("[%d] ACTUAL(%f) EXPECTED(%f)\n", (int)i, device_y_ivv.GetAt(i), cpu_y_ivv.GetAt(i)); + } + WINML_EXPECT_TRUE(in_range); + } +} + +static void GridSampleRunner( + LearningModelDeviceKind kind, + const std::vector& input, + const std::vector& input_dims, + const std::vector& grid, + const std::vector& grid_dims +) { + GridSample(kind, input, input_dims, grid, grid_dims, false, Mode::Bilinear, PaddingMode::Zeros); + GridSample(kind, input, input_dims, grid, grid_dims, false, Mode::Bilinear, PaddingMode::Border); + GridSample(kind, input, input_dims, grid, grid_dims, false, Mode::Bilinear, PaddingMode::Reflection); + GridSample(kind, input, input_dims, grid, grid_dims, false, Mode::Nearest, PaddingMode::Zeros); + GridSample(kind, input, input_dims, grid, grid_dims, false, Mode::Nearest, PaddingMode::Border); + GridSample(kind, input, input_dims, grid, grid_dims, false, Mode::Nearest, PaddingMode::Reflection); + GridSample(kind, input, input_dims, grid, grid_dims, false, Mode::Bicubic, PaddingMode::Zeros); + GridSample(kind, input, input_dims, grid, grid_dims, false, Mode::Bicubic, PaddingMode::Border); + GridSample(kind, input, input_dims, grid, grid_dims, false, Mode::Bicubic, PaddingMode::Reflection); + + GridSample(kind, input, input_dims, grid, grid_dims, true, Mode::Bilinear, PaddingMode::Zeros); + GridSample(kind, input, input_dims, grid, grid_dims, true, Mode::Bilinear, PaddingMode::Border); + GridSample(kind, input, input_dims, grid, grid_dims, true, Mode::Bilinear, PaddingMode::Reflection); + GridSample(kind, input, input_dims, grid, grid_dims, true, Mode::Nearest, PaddingMode::Zeros); + GridSample(kind, input, input_dims, grid, grid_dims, true, Mode::Nearest, PaddingMode::Border); + GridSample(kind, input, input_dims, grid, grid_dims, true, Mode::Nearest, PaddingMode::Reflection); + GridSample(kind, input, input_dims, grid, grid_dims, true, Mode::Bicubic, PaddingMode::Zeros); + GridSample(kind, input, input_dims, grid, grid_dims, true, Mode::Bicubic, PaddingMode::Border); + GridSample(kind, input, input_dims, grid, grid_dims, true, Mode::Bicubic, PaddingMode::Reflection); +} + +static void ModelBuilding_GridSample_Internal(LearningModelDeviceKind kind) { + std::vector input = { + 0.00f, + 1.00f, + 2.00f, + 3.00f, + 4.00f, + 5.00f, + 6.00f, + 7.00f, + 8.00f, + 9.00f, + 10.00f, + 11.00f, + 12.00f, + 13.00f, + 14.00f, + 15.00f, + }; + + std::vector grid = { + 0.00f, 1.00f, 2.00f, 3.00f, 4.00f, 5.00f, 6.00f, 7.00f, 8.00f, 9.00f, 10.00f, 11.00f, 12.00f, + 13.00f, 14.00f, 15.00f, 16.00f, 17.00f, 18.00f, 19.00f, 20.00f, 21.00f, 22.00f, 23.00f, 24.00f, 25.00f, + 26.00f, 27.00f, 28.00f, 29.00f, 30.00f, 31.00f, 32.00f, 33.00f, 34.00f, 35.00f, 36.00f, 37.00f, 38.00f, + 39.00f, 40.00f, 41.00f, 42.00f, 43.00f, 44.00f, 45.00f, 46.00f, 47.00f, 48.00f, 49.00f, + }; + std::transform(grid.begin(), grid.end(), grid.begin(), [&](auto& in) { return in / grid.size(); }); + std::vector input_dims = {1, 1, 4, 4}; + std::vector grid_dims = {1, 5, 5, 2}; + + GridSampleRunner(kind, input, input_dims, grid, grid_dims); + + input = {0.0f, 1.0f, 2.0f, 3.0f, 4.0, 5.0f}; + grid = { + -10.0000f, + -10.0000f, + -5.0000f, + -5.0000f, + -0.2000f, + -0.2000f, + 10.0000f, + 10.0000f, + + 10.0000f, + 10.0000f, + -0.2000f, + -0.2000f, + 5.0000f, + 5.0000f, + 10.0000f, + 10.0000f}; + input_dims = {1, 1, 3, 2}; + grid_dims = {1, 2, 4, 2}; + + GridSampleRunner(kind, input, input_dims, grid, grid_dims); +} + static void ModelBuilding_DiscreteFourierTransform_Internal(LearningModelDeviceKind kind) { - bool isCPU = (kind == LearningModelDeviceKind::Default || kind == LearningModelDeviceKind::Cpu); - std::vector real_input = - { - 1.00f, 2.00, 3.00f, 4.00f, 5.00f, 6.00f, 7.00f, 8.00f, - 1.00f, 2.00, 3.00f, 4.00f, 5.00f, 6.00f, 7.00f, 8.00f, - 1.00f, 2.00, 3.00f, 4.00f, 5.00f, 6.00f, 7.00f, 8.00f, - 1.00f, 2.00, 3.00f, 4.00f, 5.00f, 6.00f, 7.00f, 8.00f, - 1.00f, 2.00, 3.00f, 4.00f, 5.00f, 6.00f, 7.00f, 8.00f, - }; + std::vector real_input = { + 1.00f, 2.00f, 3.00f, 4.00f, 5.00f, 6.00f, 7.00f, 8.00f, 1.00f, 2.00f, 3.00f, 4.00f, 5.00f, 6.00f, + 7.00f, 8.00f, 1.00f, 2.00f, 3.00f, 4.00f, 5.00f, 6.00f, 7.00f, 8.00f, 1.00f, 2.00f, 3.00f, 4.00f, + 5.00f, 6.00f, 7.00f, 8.00f, 1.00f, 2.00f, 3.00f, 4.00f, 5.00f, 6.00f, 7.00f, 8.00f, + }; std::vector> real_expected_axis_0_two_sided = { - {5.000f, 0.000f}, {10.000f, 0.000f}, {15.000f, 0.000f}, {20.000f, 0.000f}, {25.000f, 0.000f}, {30.000f, 0.000f}, {35.000f, 0.000f}, {40.000f, 0.000f}, - {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, - {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, - {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, - {-0.000f, 0.000f}, {-0.000f, 0.000f}, {-0.000f, 0.000f}, {-0.000f, 0.000f}, {-0.000f, 0.000f}, {-0.000f, 0.000f}, {-0.000f, 0.000f}, {-0.000f, 0.000f}, + { 5.000f, 0.000f}, + {10.000f, 0.000f}, + {15.000f, 0.000f}, + {20.000f, 0.000f}, + {25.000f, 0.000f}, + {30.000f, 0.000f}, + {35.000f, 0.000f}, + {40.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + {-0.000f, 0.000f}, + {-0.000f, 0.000f}, + {-0.000f, 0.000f}, + {-0.000f, 0.000f}, + {-0.000f, 0.000f}, + {-0.000f, 0.000f}, + {-0.000f, 0.000f}, + {-0.000f, 0.000f}, }; - if (isCPU) - { - // Only enabled for CPU, as GPU does not support non-power2 DFTs yet. - DiscreteFourierTransform(kind, real_input, {1, 5, 8, 1}, real_expected_axis_0_two_sided, 1, 5, false /*onesided*/); - } + DiscreteFourierTransform(kind, real_input, {1, 5, 8, 1}, real_expected_axis_0_two_sided, 1, 5, false /*onesided*/); std::vector> real_expected_axis_1_two_sided = { - {36.000f, 0.000f}, {-4.000f, 9.657f}, {-4.000f, 4.000f}, {-4.000f, 1.657f}, {-4.000f, 0.000f}, {-4.000f, -1.657f}, {-4.000f, -4.000f}, {-4.000f, -9.657f}, - {36.000f, 0.000f}, {-4.000f, 9.657f}, {-4.000f, 4.000f}, {-4.000f, 1.657f}, {-4.000f, 0.000f}, {-4.000f, -1.657f}, {-4.000f, -4.000f}, {-4.000f, -9.657f}, - {36.000f, 0.000f}, {-4.000f, 9.657f}, {-4.000f, 4.000f}, {-4.000f, 1.657f}, {-4.000f, 0.000f}, {-4.000f, -1.657f}, {-4.000f, -4.000f}, {-4.000f, -9.657f}, - {36.000f, 0.000f}, {-4.000f, 9.657f}, {-4.000f, 4.000f}, {-4.000f, 1.657f}, {-4.000f, 0.000f}, {-4.000f, -1.657f}, {-4.000f, -4.000f}, {-4.000f, -9.657f}, - {36.000f, 0.000f}, {-4.000f, 9.657f}, {-4.000f, 4.000f}, {-4.000f, 1.657f}, {-4.000f, 0.000f}, {-4.000f, -1.657f}, {-4.000f, -4.000f}, {-4.000f, -9.657f}, + {36.000f, 0.000f}, + {-4.000f, 9.657f}, + {-4.000f, 4.000f}, + {-4.000f, 1.657f}, + {-4.000f, 0.000f}, + {-4.000f, -1.657f}, + {-4.000f, -4.000f}, + {-4.000f, -9.657f}, + {36.000f, 0.000f}, + {-4.000f, 9.657f}, + {-4.000f, 4.000f}, + {-4.000f, 1.657f}, + {-4.000f, 0.000f}, + {-4.000f, -1.657f}, + {-4.000f, -4.000f}, + {-4.000f, -9.657f}, + {36.000f, 0.000f}, + {-4.000f, 9.657f}, + {-4.000f, 4.000f}, + {-4.000f, 1.657f}, + {-4.000f, 0.000f}, + {-4.000f, -1.657f}, + {-4.000f, -4.000f}, + {-4.000f, -9.657f}, + {36.000f, 0.000f}, + {-4.000f, 9.657f}, + {-4.000f, 4.000f}, + {-4.000f, 1.657f}, + {-4.000f, 0.000f}, + {-4.000f, -1.657f}, + {-4.000f, -4.000f}, + {-4.000f, -9.657f}, + {36.000f, 0.000f}, + {-4.000f, 9.657f}, + {-4.000f, 4.000f}, + {-4.000f, 1.657f}, + {-4.000f, 0.000f}, + {-4.000f, -1.657f}, + {-4.000f, -4.000f}, + {-4.000f, -9.657f}, }; DiscreteFourierTransform(kind, real_input, {1, 5, 8, 1}, real_expected_axis_1_two_sided, 2, 8, false /*onesided*/); - std::vector> input = - { - {1.00f, 0.00f}, {2.00, 0.00f}, {3.00f, 0.00f}, {4.00f, 0.00f}, {5.00f, 0.00f}, {6.00f, 0.00f}, {7.00f, 0.00f}, {8.00f, 0.00f}, - {1.00f, 0.00f}, {2.00, 0.00f}, {3.00f, 0.00f}, {4.00f, 0.00f}, {5.00f, 0.00f}, {6.00f, 0.00f}, {7.00f, 0.00f}, {8.00f, 0.00f}, - {1.00f, 0.00f}, {2.00, 0.00f}, {3.00f, 0.00f}, {4.00f, 0.00f}, {5.00f, 0.00f}, {6.00f, 0.00f}, {7.00f, 0.00f}, {8.00f, 0.00f}, - {1.00f, 0.00f}, {2.00, 0.00f}, {3.00f, 0.00f}, {4.00f, 0.00f}, {5.00f, 0.00f}, {6.00f, 0.00f}, {7.00f, 0.00f}, {8.00f, 0.00f}, - {1.00f, 0.00f}, {2.00, 0.00f}, {3.00f, 0.00f}, {4.00f, 0.00f}, {5.00f, 0.00f}, {6.00f, 0.00f}, {7.00f, 0.00f}, {8.00f, 0.00f}, - - {2.00f, 1.00f}, {4.00, 2.00f}, {6.00f, 3.00f}, {8.00f, 4.00f}, {10.00f, 5.00f}, {12.00f, 6.00f}, {14.00f, 7.00f}, {16.00f, 8.00f}, - {2.00f, 1.00f}, {4.00, 2.00f}, {6.00f, 3.00f}, {8.00f, 4.00f}, {10.00f, 5.00f}, {12.00f, 6.00f}, {14.00f, 7.00f}, {16.00f, 8.00f}, - {2.00f, 1.00f}, {4.00, 2.00f}, {6.00f, 3.00f}, {8.00f, 4.00f}, {10.00f, 5.00f}, {12.00f, 6.00f}, {14.00f, 7.00f}, {16.00f, 8.00f}, - {2.00f, 1.00f}, {4.00, 2.00f}, {6.00f, 3.00f}, {8.00f, 4.00f}, {10.00f, 5.00f}, {12.00f, 6.00f}, {14.00f, 7.00f}, {16.00f, 8.00f}, - {2.00f, 1.00f}, {4.00, 2.00f}, {6.00f, 3.00f}, {8.00f, 4.00f}, {10.00f, 5.00f}, {12.00f, 6.00f}, {14.00f, 7.00f}, {16.00f, 8.00f}, - }; + std::vector> input = { + { 1.00f, 0.00f}, + { 2.00f, 0.00f}, + { 3.00f, 0.00f}, + { 4.00f, 0.00f}, + { 5.00f, 0.00f}, + { 6.00f, 0.00f}, + { 7.00f, 0.00f}, + { 8.00f, 0.00f}, + { 1.00f, 0.00f}, + { 2.00f, 0.00f}, + { 3.00f, 0.00f}, + { 4.00f, 0.00f}, + { 5.00f, 0.00f}, + { 6.00f, 0.00f}, + { 7.00f, 0.00f}, + { 8.00f, 0.00f}, + { 1.00f, 0.00f}, + { 2.00f, 0.00f}, + { 3.00f, 0.00f}, + { 4.00f, 0.00f}, + { 5.00f, 0.00f}, + { 6.00f, 0.00f}, + { 7.00f, 0.00f}, + { 8.00f, 0.00f}, + { 1.00f, 0.00f}, + { 2.00f, 0.00f}, + { 3.00f, 0.00f}, + { 4.00f, 0.00f}, + { 5.00f, 0.00f}, + { 6.00f, 0.00f}, + { 7.00f, 0.00f}, + { 8.00f, 0.00f}, + { 1.00f, 0.00f}, + { 2.00f, 0.00f}, + { 3.00f, 0.00f}, + { 4.00f, 0.00f}, + { 5.00f, 0.00f}, + { 6.00f, 0.00f}, + { 7.00f, 0.00f}, + { 8.00f, 0.00f}, + + { 2.00f, 1.00f}, + { 4.00f, 2.00f}, + { 6.00f, 3.00f}, + { 8.00f, 4.00f}, + {10.00f, 5.00f}, + {12.00f, 6.00f}, + {14.00f, 7.00f}, + {16.00f, 8.00f}, + { 2.00f, 1.00f}, + { 4.00f, 2.00f}, + { 6.00f, 3.00f}, + { 8.00f, 4.00f}, + {10.00f, 5.00f}, + {12.00f, 6.00f}, + {14.00f, 7.00f}, + {16.00f, 8.00f}, + { 2.00f, 1.00f}, + { 4.00f, 2.00f}, + { 6.00f, 3.00f}, + { 8.00f, 4.00f}, + {10.00f, 5.00f}, + {12.00f, 6.00f}, + {14.00f, 7.00f}, + {16.00f, 8.00f}, + { 2.00f, 1.00f}, + { 4.00f, 2.00f}, + { 6.00f, 3.00f}, + { 8.00f, 4.00f}, + {10.00f, 5.00f}, + {12.00f, 6.00f}, + {14.00f, 7.00f}, + {16.00f, 8.00f}, + { 2.00f, 1.00f}, + { 4.00f, 2.00f}, + { 6.00f, 3.00f}, + { 8.00f, 4.00f}, + {10.00f, 5.00f}, + {12.00f, 6.00f}, + {14.00f, 7.00f}, + {16.00f, 8.00f}, + }; std::vector> expected_axis_0_two_sided = { - {5.000f, 0.000f}, {10.000f, 0.000f}, {15.000f, 0.000f}, {20.000f, 0.000f}, {25.000f, 0.000f}, {30.000f, 0.000f}, {35.000f, 0.000f}, {40.000f, 0.000f}, - {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, - {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, - {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, - {-0.000f, 0.000f}, {-0.000f, 0.000f}, {-0.000f, 0.000f}, {-0.000f, 0.000f}, {-0.000f, 0.000f}, {-0.000f, 0.000f}, {-0.000f, 0.000f}, {-0.000f, 0.000f}, - - {10.000f, 5.000f}, {20.000f, 10.000f}, {30.000f, 15.000f}, {40.000f, 20.000f}, {50.000f, 25.000f}, {60.000f, 30.000f}, {70.000f, 35.000f}, {80.000f, 40.000f}, - {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {-0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, - {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {-0.000f, 0.000f}, {0.000f, 0.000f}, {-0.000f, 0.000f}, {0.000f, 0.000f}, - {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, - {-0.000f, 0.000f}, {-0.000f, 0.000f}, {-0.000f, 0.000f}, {-0.000f, 0.000f}, {-0.000f, 0.000f}, {-0.000f, 0.000f}, {-0.000f, 0.000f}, {-0.000f, 0.000f} + { 5.000f, 0.000f}, + {10.000f, 0.000f}, + {15.000f, 0.000f}, + {20.000f, 0.000f}, + {25.000f, 0.000f}, + {30.000f, 0.000f}, + {35.000f, 0.000f}, + {40.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + {-0.000f, 0.000f}, + {-0.000f, 0.000f}, + {-0.000f, 0.000f}, + {-0.000f, 0.000f}, + {-0.000f, 0.000f}, + {-0.000f, 0.000f}, + {-0.000f, 0.000f}, + {-0.000f, 0.000f}, + + {10.000f, 5.000f}, + {20.000f, 10.000f}, + {30.000f, 15.000f}, + {40.000f, 20.000f}, + {50.000f, 25.000f}, + {60.000f, 30.000f}, + {70.000f, 35.000f}, + {80.000f, 40.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + {-0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + {-0.000f, 0.000f}, + { 0.000f, 0.000f}, + {-0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + {-0.000f, 0.000f}, + {-0.000f, 0.000f}, + {-0.000f, 0.000f}, + {-0.000f, 0.000f}, + {-0.000f, 0.000f}, + {-0.000f, 0.000f}, + {-0.000f, 0.000f}, + {-0.000f, 0.000f} }; - if (isCPU) - { - // Only enabled for CPU, as GPU does not support non-power2 DFTs yet. - DiscreteFourierTransform(kind, input, {2, 5, 8, 2}, expected_axis_0_two_sided, 1, 5, false /*onesided*/); - } + + DiscreteFourierTransform(kind, input, {2, 5, 8, 2}, expected_axis_0_two_sided, 1, 5, false /*onesided*/); std::vector> expected_axis_0_two_sided_small_dft_length = { - {4.000f, 0.000f}, {8.000f, 0.000f}, {12.000f, 0.000f}, {16.000f, 0.000f}, {20.000f, 0.000f}, {24.000f, 0.000f}, {28.000f, 0.000f}, {32.000f, 0.000f}, - {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, - {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, - {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, - - {8.000f, 4.000f}, {16.000f, 8.000f}, {24.000f, 12.000f}, {32.000f, 16.000f}, {40.000f, 20.000f}, {48.000f, 24.000f}, {56.000f, 28.000f}, {64.000f, 32.000f}, - {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {-0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, - {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {-0.000f, 0.000f}, {0.000f, 0.000f}, {-0.000f, 0.000f}, {0.000f, 0.000f}, - {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, + { 4.000f, 0.000f}, + { 8.000f, 0.000f}, + {12.000f, 0.000f}, + {16.000f, 0.000f}, + {20.000f, 0.000f}, + {24.000f, 0.000f}, + {28.000f, 0.000f}, + {32.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + + { 8.000f, 4.000f}, + {16.000f, 8.000f}, + {24.000f, 12.000f}, + {32.000f, 16.000f}, + {40.000f, 20.000f}, + {48.000f, 24.000f}, + {56.000f, 28.000f}, + {64.000f, 32.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + {-0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + {-0.000f, 0.000f}, + { 0.000f, 0.000f}, + {-0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, }; - DiscreteFourierTransform(kind, input, {2, 5, 8, 2}, expected_axis_0_two_sided_small_dft_length, 1, 4, false /*onesided*/); + DiscreteFourierTransform( + kind, input, {2, 5, 8, 2}, expected_axis_0_two_sided_small_dft_length, 1, 4, false /*onesided*/ + ); std::vector> expected_axis_0_two_sided_bigger_dft_length = { - {5.000000f, 0.000000f}, {10.000000f, 0.000000f}, {15.000000f, 0.000000f}, {20.000000f, 0.000000f}, {25.000000f, 0.000000f}, {30.000000f, 0.000000f}, {35.000000f, 0.000000f}, {40.000000f, 0.000000f}, - {-0.500000f, -0.866025f}, {-1.000000f, -1.732051f}, {-1.500000f, -2.598076f}, {-2.000000f, -3.464101f}, {-2.500000f, -4.330126f}, {-3.000000f, -5.196152f}, {-3.500000f, -6.062176f}, {-4.000000f, -6.928203f}, - {0.500000f, -0.866025f}, {1.000000f, -1.732051f}, {1.500000f, -2.598076f}, {1.999999f, -3.464102f}, {2.499999f, -4.330127f}, {2.999999f, -5.196152f}, {3.499999f, -6.062178f}, {3.999999f, -6.928203f}, - {1.000000f, -0.000000f}, {2.000000f, -0.000001f}, {3.000000f, -0.000001f}, {4.000000f, -0.000002f}, {5.000000f, -0.000002f}, {6.000000f, -0.000002f}, {7.000000f, -0.000003f}, {8.000000f, -0.000003f}, - {0.500000f, 0.866025f}, {1.000001f, 1.732051f}, {1.500001f, 2.598076f}, {2.000001f, 3.464102f}, {2.500002f, 4.330127f}, {3.000002f, 5.196153f}, {3.500002f, 6.062179f}, {4.000003f, 6.928204f}, - {-0.500000f, 0.866026f}, {-1.000000f, 1.732052f}, {-1.500000f, 2.598077f}, {-2.000000f, 3.464104f}, {-2.500000f, 4.330130f}, {-2.999999f, 5.196155f}, {-3.500000f, 6.062181f}, {-4.000000f, 6.928207f}, - - {10.000000f, 5.000000f}, {20.000000f, 10.000000f}, {30.000000f, 15.000000f}, {40.000000f, 20.000000f}, {50.000000f, 25.000000f}, {60.000000f, 30.000000f}, {70.000000f, 35.000000f}, {80.000000f, 40.000000f}, - {-0.133975f, -2.232050f}, {-0.267949f, -4.464101f}, {-0.401925f, -6.696153f}, {-0.535898f, -8.928202f}, {-0.669872f, -11.160252f}, {-0.803849f, -13.392305f}, {-0.937822f, -15.624352f}, {-1.071796f, -17.856403f}, - {1.866025f, -1.232051f}, {3.732050f, -2.464102f}, {5.598075f, -3.696153f}, {7.464101f, -4.928204f}, {9.330126f, -6.160254f}, {11.196151f, -7.392306f}, {13.062176f, -8.624355f}, {14.928202f, -9.856407f}, - {2.000000f, 0.999999f}, {4.000001f, 1.999998f}, {6.000001f, 2.999998f}, {8.000002f, 3.999997f}, {10.000003f, 4.999996f}, {12.000002f, 5.999995f}, {14.000003f, 6.999995f}, {16.000004f, 7.999993f}, - {0.133975f, 2.232051f}, {0.267951f, 4.464102f}, {0.401926f, 6.696153f}, {0.535901f, 8.928205f}, {0.669876f, 11.160257f}, {0.803851f, 13.392306f}, {0.937826f, 15.624360f}, {1.071802f, 17.856409f}, - {-1.866026f, 1.232052f}, {-3.732052f, 2.464104f}, {-5.598077f, 3.696155f}, {-7.464104f, 4.928207f}, {-9.330130f, 6.160261f}, {-11.196154f, 7.392309f}, {-13.062180f, 8.624363f}, {-14.928207f, 9.856415f}, + { 5.000000f, 0.000000f}, + { 10.000000f, 0.000000f}, + { 15.000000f, 0.000000f}, + { 20.000000f, 0.000000f}, + { 25.000000f, 0.000000f}, + { 30.000000f, 0.000000f}, + { 35.000000f, 0.000000f}, + { 40.000000f, 0.000000f}, + { -0.500000f, -0.866025f}, + { -1.000000f, -1.732051f}, + { -1.500000f, -2.598076f}, + { -2.000000f, -3.464101f}, + { -2.500000f, -4.330126f}, + { -3.000000f, -5.196152f}, + { -3.500000f, -6.062176f}, + { -4.000000f, -6.928203f}, + { 0.500000f, -0.866025f}, + { 1.000000f, -1.732051f}, + { 1.500000f, -2.598076f}, + { 1.999999f, -3.464102f}, + { 2.499999f, -4.330127f}, + { 2.999999f, -5.196152f}, + { 3.499999f, -6.062178f}, + { 3.999999f, -6.928203f}, + { 1.000000f, -0.000000f}, + { 2.000000f, -0.000001f}, + { 3.000000f, -0.000001f}, + { 4.000000f, -0.000002f}, + { 5.000000f, -0.000002f}, + { 6.000000f, -0.000002f}, + { 7.000000f, -0.000003f}, + { 8.000000f, -0.000003f}, + { 0.500000f, 0.866025f}, + { 1.000001f, 1.732051f}, + { 1.500001f, 2.598076f}, + { 2.000001f, 3.464102f}, + { 2.500002f, 4.330127f}, + { 3.000002f, 5.196153f}, + { 3.500002f, 6.062179f}, + { 4.000003f, 6.928204f}, + { -0.500000f, 0.866026f}, + { -1.000000f, 1.732052f}, + { -1.500000f, 2.598077f}, + { -2.000000f, 3.464104f}, + { -2.500000f, 4.330130f}, + { -2.999999f, 5.196155f}, + { -3.500000f, 6.062181f}, + { -4.000000f, 6.928207f}, + + { 10.000000f, 5.000000f}, + { 20.000000f, 10.000000f}, + { 30.000000f, 15.000000f}, + { 40.000000f, 20.000000f}, + { 50.000000f, 25.000000f}, + { 60.000000f, 30.000000f}, + { 70.000000f, 35.000000f}, + { 80.000000f, 40.000000f}, + { -0.133975f, -2.232050f}, + { -0.267949f, -4.464101f}, + { -0.401925f, -6.696153f}, + { -0.535898f, -8.928202f}, + { -0.669872f, -11.160252f}, + { -0.803849f, -13.392305f}, + { -0.937822f, -15.624352f}, + { -1.071796f, -17.856403f}, + { 1.866025f, -1.232051f}, + { 3.732050f, -2.464102f}, + { 5.598075f, -3.696153f}, + { 7.464101f, -4.928204f}, + { 9.330126f, -6.160254f}, + { 11.196151f, -7.392306f}, + { 13.062176f, -8.624355f}, + { 14.928202f, -9.856407f}, + { 2.000000f, 0.999999f}, + { 4.000001f, 1.999998f}, + { 6.000001f, 2.999998f}, + { 8.000002f, 3.999997f}, + { 10.000003f, 4.999996f}, + { 12.000002f, 5.999995f}, + { 14.000003f, 6.999995f}, + { 16.000004f, 7.999993f}, + { 0.133975f, 2.232051f}, + { 0.267951f, 4.464102f}, + { 0.401926f, 6.696153f}, + { 0.535901f, 8.928205f}, + { 0.669876f, 11.160257f}, + { 0.803851f, 13.392306f}, + { 0.937826f, 15.624360f}, + { 1.071802f, 17.856409f}, + { -1.866026f, 1.232052f}, + { -3.732052f, 2.464104f}, + { -5.598077f, 3.696155f}, + { -7.464104f, 4.928207f}, + { -9.330130f, 6.160261f}, + {-11.196154f, 7.392309f}, + {-13.062180f, 8.624363f}, + {-14.928207f, 9.856415f}, }; - if (isCPU) - { - // Only enabled for CPU, as GPU does not support non-power2 DFTs yet. - DiscreteFourierTransform(kind, input, {2, 5, 8, 2}, expected_axis_0_two_sided_bigger_dft_length, 1, 6, false /*onesided*/); - } - std::vector> expected_axis_0_one_sided = { - {5.000f, 0.000f}, {10.000f, 0.000f}, {15.000f, 0.000f}, {20.000f, 0.000f}, {25.000f, 0.000f}, {30.000f, 0.000f}, {35.000f, 0.000f}, {40.000f, 0.000f}, - {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, - {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, + DiscreteFourierTransform( + kind, input, {2, 5, 8, 2}, expected_axis_0_two_sided_bigger_dft_length, 1, 6, false /*onesided*/ + ); - {10.000f, 5.000f}, {20.000f, 10.000f}, {30.000f, 15.000f}, {40.000f, 20.000f}, {50.000f, 25.000f}, {60.000f, 30.000f}, {70.000f, 35.000f}, {80.000f, 40.000f}, - {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {-0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, - {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {0.000f, 0.000f}, {-0.000f, 0.000f}, {0.000f, 0.000f}, {-0.000f, 0.000f}, {0.000f, 0.000f}, + std::vector> expected_axis_0_one_sided = { + { 5.000f, 0.000f}, + {10.000f, 0.000f}, + {15.000f, 0.000f}, + {20.000f, 0.000f}, + {25.000f, 0.000f}, + {30.000f, 0.000f}, + {35.000f, 0.000f}, + {40.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + + {10.000f, 5.000f}, + {20.000f, 10.000f}, + {30.000f, 15.000f}, + {40.000f, 20.000f}, + {50.000f, 25.000f}, + {60.000f, 30.000f}, + {70.000f, 35.000f}, + {80.000f, 40.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + {-0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + { 0.000f, 0.000f}, + {-0.000f, 0.000f}, + { 0.000f, 0.000f}, + {-0.000f, 0.000f}, + { 0.000f, 0.000f}, }; - if (isCPU) - { - // Only enabled for CPU, as GPU does not support non-power2 DFTs yet. - DiscreteFourierTransform(kind, input, {2, 5, 8, 2}, expected_axis_0_one_sided, 1, 5, true /*onesided*/); - } + DiscreteFourierTransform(kind, input, {2, 5, 8, 2}, expected_axis_0_one_sided, 1, 5, true /*onesided*/); std::vector> expected_axis_1_two_sided = { - {36.000f, 0.000f}, {-4.000f, 9.657f}, {-4.000f, 4.000f}, {-4.000f, 1.657f}, {-4.000f, 0.000f}, {-4.000f, -1.657f}, {-4.000f, -4.000f}, {-4.000f, -9.657f}, - {36.000f, 0.000f}, {-4.000f, 9.657f}, {-4.000f, 4.000f}, {-4.000f, 1.657f}, {-4.000f, 0.000f}, {-4.000f, -1.657f}, {-4.000f, -4.000f}, {-4.000f, -9.657f}, - {36.000f, 0.000f}, {-4.000f, 9.657f}, {-4.000f, 4.000f}, {-4.000f, 1.657f}, {-4.000f, 0.000f}, {-4.000f, -1.657f}, {-4.000f, -4.000f}, {-4.000f, -9.657f}, - {36.000f, 0.000f}, {-4.000f, 9.657f}, {-4.000f, 4.000f}, {-4.000f, 1.657f}, {-4.000f, 0.000f}, {-4.000f, -1.657f}, {-4.000f, -4.000f}, {-4.000f, -9.657f}, - {36.000f, 0.000f}, {-4.000f, 9.657f}, {-4.000f, 4.000f}, {-4.000f, 1.657f}, {-4.000f, 0.000f}, {-4.000f, -1.657f}, {-4.000f, -4.000f}, {-4.000f, -9.657f}, - - {72.000f, 36.000f}, {-17.657f, 15.314f}, {-12.000f, 4.000f}, {-9.657f, -0.686f}, {-8.000f, -4.000f}, {-6.343f, -7.314f}, {-4.000f, -12.000f}, {1.657f, -23.314f}, - {72.000f, 36.000f}, {-17.657f, 15.314f}, {-12.000f, 4.000f}, {-9.657f, -0.686f}, {-8.000f, -4.000f}, {-6.343f, -7.314f}, {-4.000f, -12.000f}, {1.657f, -23.314f}, - {72.000f, 36.000f}, {-17.657f, 15.314f}, {-12.000f, 4.000f}, {-9.657f, -0.686f}, {-8.000f, -4.000f}, {-6.343f, -7.314f}, {-4.000f, -12.000f}, {1.657f, -23.314f}, - {72.000f, 36.000f}, {-17.657f, 15.314f}, {-12.000f, 4.000f}, {-9.657f, -0.686f}, {-8.000f, -4.000f}, {-6.343f, -7.314f}, {-4.000f, -12.000f}, {1.657f, -23.314f}, - {72.000f, 36.000f}, {-17.657f, 15.314f}, {-12.000f, 4.000f}, {-9.657f, -0.686f}, {-8.000f, -4.000f}, {-6.343f, -7.314f}, {-4.000f, -12.000f}, {1.657f, -23.314f}, + { 36.000f, 0.000f}, + { -4.000f, 9.657f}, + { -4.000f, 4.000f}, + { -4.000f, 1.657f}, + { -4.000f, 0.000f}, + { -4.000f, -1.657f}, + { -4.000f, -4.000f}, + { -4.000f, -9.657f}, + { 36.000f, 0.000f}, + { -4.000f, 9.657f}, + { -4.000f, 4.000f}, + { -4.000f, 1.657f}, + { -4.000f, 0.000f}, + { -4.000f, -1.657f}, + { -4.000f, -4.000f}, + { -4.000f, -9.657f}, + { 36.000f, 0.000f}, + { -4.000f, 9.657f}, + { -4.000f, 4.000f}, + { -4.000f, 1.657f}, + { -4.000f, 0.000f}, + { -4.000f, -1.657f}, + { -4.000f, -4.000f}, + { -4.000f, -9.657f}, + { 36.000f, 0.000f}, + { -4.000f, 9.657f}, + { -4.000f, 4.000f}, + { -4.000f, 1.657f}, + { -4.000f, 0.000f}, + { -4.000f, -1.657f}, + { -4.000f, -4.000f}, + { -4.000f, -9.657f}, + { 36.000f, 0.000f}, + { -4.000f, 9.657f}, + { -4.000f, 4.000f}, + { -4.000f, 1.657f}, + { -4.000f, 0.000f}, + { -4.000f, -1.657f}, + { -4.000f, -4.000f}, + { -4.000f, -9.657f}, + + { 72.000f, 36.000f}, + {-17.657f, 15.314f}, + {-12.000f, 4.000f}, + { -9.657f, -0.686f}, + { -8.000f, -4.000f}, + { -6.343f, -7.314f}, + { -4.000f, -12.000f}, + { 1.657f, -23.314f}, + { 72.000f, 36.000f}, + {-17.657f, 15.314f}, + {-12.000f, 4.000f}, + { -9.657f, -0.686f}, + { -8.000f, -4.000f}, + { -6.343f, -7.314f}, + { -4.000f, -12.000f}, + { 1.657f, -23.314f}, + { 72.000f, 36.000f}, + {-17.657f, 15.314f}, + {-12.000f, 4.000f}, + { -9.657f, -0.686f}, + { -8.000f, -4.000f}, + { -6.343f, -7.314f}, + { -4.000f, -12.000f}, + { 1.657f, -23.314f}, + { 72.000f, 36.000f}, + {-17.657f, 15.314f}, + {-12.000f, 4.000f}, + { -9.657f, -0.686f}, + { -8.000f, -4.000f}, + { -6.343f, -7.314f}, + { -4.000f, -12.000f}, + { 1.657f, -23.314f}, + { 72.000f, 36.000f}, + {-17.657f, 15.314f}, + {-12.000f, 4.000f}, + { -9.657f, -0.686f}, + { -8.000f, -4.000f}, + { -6.343f, -7.314f}, + { -4.000f, -12.000f}, + { 1.657f, -23.314f}, }; DiscreteFourierTransform(kind, input, {2, 5, 8, 2}, expected_axis_1_two_sided, 2, 8, false /*onesided*/); std::vector> expected_axis_1_one_sided = { - {36.000f, 0.000f}, {-4.000f, 9.657f}, {-4.000f, 4.000f}, {-4.000f, 1.657f}, {-4.000f, 0.000f}, - {36.000f, 0.000f}, {-4.000f, 9.657f}, {-4.000f, 4.000f}, {-4.000f, 1.657f}, {-4.000f, 0.000f}, - {36.000f, 0.000f}, {-4.000f, 9.657f}, {-4.000f, 4.000f}, {-4.000f, 1.657f}, {-4.000f, 0.000f}, - {36.000f, 0.000f}, {-4.000f, 9.657f}, {-4.000f, 4.000f}, {-4.000f, 1.657f}, {-4.000f, 0.000f}, - {36.000f, 0.000f}, {-4.000f, 9.657f}, {-4.000f, 4.000f}, {-4.000f, 1.657f}, {-4.000f, 0.000f}, - {72.000f, 36.000f}, {-17.657f, 15.314f}, {-12.000f, 4.000f}, {-9.657f, -0.686f}, {-8.000f, -4.000f}, - {72.000f, 36.000f}, {-17.657f, 15.314f}, {-12.000f, 4.000f}, {-9.657f, -0.686f}, {-8.000f, -4.000f}, - {72.000f, 36.000f}, {-17.657f, 15.314f}, {-12.000f, 4.000f}, {-9.657f, -0.686f}, {-8.000f, -4.000f}, - {72.000f, 36.000f}, {-17.657f, 15.314f}, {-12.000f, 4.000f}, {-9.657f, -0.686f}, {-8.000f, -4.000f}, - {72.000f, 36.000f}, {-17.657f, 15.314f}, {-12.000f, 4.000f}, {-9.657f, -0.686f}, {-8.000f, -4.000f}, + { 36.000f, 0.000f}, + { -4.000f, 9.657f}, + { -4.000f, 4.000f}, + { -4.000f, 1.657f}, + { -4.000f, 0.000f}, + { 36.000f, 0.000f}, + { -4.000f, 9.657f}, + { -4.000f, 4.000f}, + { -4.000f, 1.657f}, + { -4.000f, 0.000f}, + { 36.000f, 0.000f}, + { -4.000f, 9.657f}, + { -4.000f, 4.000f}, + { -4.000f, 1.657f}, + { -4.000f, 0.000f}, + { 36.000f, 0.000f}, + { -4.000f, 9.657f}, + { -4.000f, 4.000f}, + { -4.000f, 1.657f}, + { -4.000f, 0.000f}, + { 36.000f, 0.000f}, + { -4.000f, 9.657f}, + { -4.000f, 4.000f}, + { -4.000f, 1.657f}, + { -4.000f, 0.000f}, + { 72.000f, 36.000f}, + {-17.657f, 15.314f}, + {-12.000f, 4.000f}, + { -9.657f, -0.686f}, + { -8.000f, -4.000f}, + { 72.000f, 36.000f}, + {-17.657f, 15.314f}, + {-12.000f, 4.000f}, + { -9.657f, -0.686f}, + { -8.000f, -4.000f}, + { 72.000f, 36.000f}, + {-17.657f, 15.314f}, + {-12.000f, 4.000f}, + { -9.657f, -0.686f}, + { -8.000f, -4.000f}, + { 72.000f, 36.000f}, + {-17.657f, 15.314f}, + {-12.000f, 4.000f}, + { -9.657f, -0.686f}, + { -8.000f, -4.000f}, + { 72.000f, 36.000f}, + {-17.657f, 15.314f}, + {-12.000f, 4.000f}, + { -9.657f, -0.686f}, + { -8.000f, -4.000f}, }; DiscreteFourierTransform(kind, input, {2, 5, 8, 2}, expected_axis_1_one_sided, 2, 8, true /*onesided*/); @@ -1266,6 +2015,12 @@ static void ModelBuilding_DiscreteFourierTransform_Internal(LearningModelDeviceK } #endif +static void ModelBuilding_GridSampleDeviceDirectX() { +#if !defined(BUILD_INBOX) + ModelBuilding_GridSample_Internal(LearningModelDeviceKind::DirectX); +#endif +} + static void ModelBuilding_DiscreteFourierTransform() { #if !defined(BUILD_INBOX) ModelBuilding_DiscreteFourierTransform_Internal(LearningModelDeviceKind::Cpu); @@ -1284,45 +2039,39 @@ static void DiscreteFourierTransformInverse(size_t axis, LearningModelDeviceKind std::vector output_shape = {2, 5, 8, 2}; auto model = - LearningModelBuilder::Create(17) - .Inputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Input.TimeSignal", TensorKind::Float, shape)) - .Outputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Output.Spectra", TensorKind::Float, output_shape)) - .Outputs().Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Output.Inverse", TensorKind::Float, output_shape)) - .Operators().Add(Operator(L"DFT") - .SetInput(L"input", L"Input.TimeSignal") - .SetAttribute(L"axis", TensorInt64Bit::CreateFromArray({}, {INT64(axis)})) - .SetOutput(L"output", L"Output.Spectra")) - .Operators().Add(Operator(L"DFT") - .SetInput(L"input", L"Output.Spectra") - .SetAttribute(L"axis", TensorInt64Bit::CreateFromArray({}, {INT64(axis)})) - .SetAttribute(L"inverse", TensorInt64Bit::CreateFromArray({}, {INT64(1)})) - .SetOutput(L"output", L"Output.Inverse")) - .CreateModel(); + LearningModelBuilder::Create(17) + .Inputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Input.TimeSignal", TensorKind::Float, shape)) + .Outputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Output.Spectra", TensorKind::Float, output_shape)) + .Outputs() + .Add(LearningModelBuilder::CreateTensorFeatureDescriptor(L"Output.Inverse", TensorKind::Float, output_shape)) + .Operators() + .Add(Operator(L"DFT") + .SetInput(L"input", L"Input.TimeSignal") + .SetAttribute(L"axis", TensorInt64Bit::CreateFromArray({}, {INT64(axis)})) + .SetOutput(L"output", L"Output.Spectra")) + .Operators() + .Add(Operator(L"DFT") + .SetInput(L"input", L"Output.Spectra") + .SetAttribute(L"axis", TensorInt64Bit::CreateFromArray({}, {INT64(axis)})) + .SetAttribute(L"inverse", TensorInt64Bit::CreateFromArray({}, {INT64(1)})) + .SetOutput(L"output", L"Output.Inverse")) + .CreateModel(); auto device = LearningModelDevice(kind); LearningModelSession session(model, device); LearningModelBinding binding(session); - auto input_vector = - std::vector{ - 1, 2, 3, 4, 5, 6, 7, 8, - 1, 2, 3, 4, 5, 6, 7, 8, - 1, 2, 3, 4, 5, 6, 7, 8, - 1, 2, 3, 4, 5, 6, 7, 8, - 1, 2, 3, 4, 5, 6, 7, 8, - - 2, 4, 6, 8, 10, 12, 14, 16, - 2, 4, 6, 8, 10, 12, 14, 16, - 2, 4, 6, 8, 10, 12, 14, 16, - 2, 4, 6, 8, 10, 12, 14, 16, - 2, 4, 6, 8, 10, 12, 14, 16, - }; + auto input_vector = std::vector{ + 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, + 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, + + 2, 4, 6, 8, 10, 12, 14, 16, 2, 4, 6, 8, 10, 12, 14, 16, 2, 4, 6, 8, + 10, 12, 14, 16, 2, 4, 6, 8, 10, 12, 14, 16, 2, 4, 6, 8, 10, 12, 14, 16, + }; // Populate binding - binding.Bind( - L"Input.TimeSignal", - TensorFloat::CreateFromArray( - shape, - input_vector)); + binding.Bind(L"Input.TimeSignal", TensorFloat::CreateFromArray(shape, input_vector)); // Evaluate auto result = session.Evaluate(binding, L""); @@ -1355,15 +2104,11 @@ static void ModelBuilding_DiscreteFourierTransformInverseIdentityDeviceDirectX() static void ModelBuilding_HannWindow() { #if !defined(BUILD_INBOX) - auto expected = std::vector { - 0.000000f, 0.009607f, 0.038060f, 0.084265f, 0.146447f, - 0.222215f, 0.308658f, 0.402455f, 0.500000f, 0.597545f, - 0.691342f, 0.777785f, 0.853553f, 0.915735f, 0.961940f, - 0.990393f, 1.000000f, 0.990393f, 0.961940f, 0.915735f, - 0.853553f, 0.777785f, 0.691342f, 0.597545f, 0.500000f, - 0.402455f, 0.308658f, 0.222215f, 0.146447f, 0.084265f, - 0.038060f, 0.009607f - }; + auto expected = + std::vector{0.000000f, 0.009607f, 0.038060f, 0.084265f, 0.146447f, 0.222215f, 0.308658f, 0.402455f, + 0.500000f, 0.597545f, 0.691342f, 0.777785f, 0.853553f, 0.915735f, 0.961940f, 0.990393f, + 1.000000f, 0.990393f, 0.961940f, 0.915735f, 0.853553f, 0.777785f, 0.691342f, 0.597545f, + 0.500000f, 0.402455f, 0.308658f, 0.222215f, 0.146447f, 0.084265f, 0.038060f, 0.009607f}; WindowFunction(L"HannWindow", TensorKind::Float, expected); WindowFunction(L"HannWindow", TensorKind::Double, expected); #endif @@ -1371,15 +2116,11 @@ static void ModelBuilding_HannWindow() { static void ModelBuilding_HammingWindow() { #if !defined(BUILD_INBOX) - auto expected = std::vector { - 0.086957f, 0.095728f, 0.121707f, 0.163894f, 0.220669f, - 0.289848f, 0.368775f, 0.454415f, 0.543478f, 0.632541f, - 0.718182f, 0.797108f, 0.866288f, 0.923062f, 0.965249f, - 0.991228f, 1.000000f, 0.991228f, 0.965249f, 0.923062f, - 0.866288f, 0.797108f, 0.718182f, 0.632541f, 0.543478f, - 0.454415f, 0.368775f, 0.289848f, 0.220669f, 0.163894f, - 0.121707f, 0.095728f - }; + auto expected = + std::vector{0.086957f, 0.095728f, 0.121707f, 0.163894f, 0.220669f, 0.289848f, 0.368775f, 0.454415f, + 0.543478f, 0.632541f, 0.718182f, 0.797108f, 0.866288f, 0.923062f, 0.965249f, 0.991228f, + 1.000000f, 0.991228f, 0.965249f, 0.923062f, 0.866288f, 0.797108f, 0.718182f, 0.632541f, + 0.543478f, 0.454415f, 0.368775f, 0.289848f, 0.220669f, 0.163894f, 0.121707f, 0.095728f}; WindowFunction(L"HammingWindow", TensorKind::Float, expected); WindowFunction(L"HammingWindow", TensorKind::Double, expected); #endif @@ -1387,15 +2128,11 @@ static void ModelBuilding_HammingWindow() { static void ModelBuilding_BlackmanWindow() { #if !defined(BUILD_INBOX) - auto expected = std::vector { - 0.000000f, 0.003518f, 0.014629f, 0.034880f, 0.066447f, - 0.111600f, 0.172090f, 0.248544f, 0.340000f, 0.443635f, - 0.554773f, 0.667170f, 0.773553f, 0.866349f, 0.938508f, - 0.984303f, 1.000000f, 0.984303f, 0.938508f, 0.866349f, - 0.773553f, 0.667170f, 0.554773f, 0.443635f, 0.340000f, - 0.248544f, 0.172090f, 0.111600f, 0.066447f, 0.034880f, - 0.014629f, 0.003518f - }; + auto expected = + std::vector{0.000000f, 0.003518f, 0.014629f, 0.034880f, 0.066447f, 0.111600f, 0.172090f, 0.248544f, + 0.340000f, 0.443635f, 0.554773f, 0.667170f, 0.773553f, 0.866349f, 0.938508f, 0.984303f, + 1.000000f, 0.984303f, 0.938508f, 0.866349f, 0.773553f, 0.667170f, 0.554773f, 0.443635f, + 0.340000f, 0.248544f, 0.172090f, 0.111600f, 0.066447f, 0.034880f, 0.014629f, 0.003518f}; WindowFunction(L"BlackmanWindow", TensorKind::Float, expected); WindowFunction(L"BlackmanWindow", TensorKind::Double, expected); #endif @@ -1432,118 +2169,116 @@ static void ModelBuilding_MelSpectrogramOnThreeToneSignal() { } static void SetIntraOpNumThreads() { - auto shape = std::vector{1, 1000}; - auto model = ProtobufHelpers::CreateModel(TensorKind::Float, shape, 1000); - auto device = LearningModelDevice(LearningModelDeviceKind::Cpu); - auto options = LearningModelSessionOptions(); - auto nativeOptions = options.as(); - - // Set the number of intra op threads to half of logical cores. - uint32_t desiredThreads = std::thread::hardware_concurrency() / 2; - WINML_EXPECT_NO_THROW(nativeOptions->SetIntraOpNumThreadsOverride(desiredThreads)); - // Create session and grab the number of intra op threads to see if is set properly - LearningModelSession session = nullptr; - WINML_EXPECT_NO_THROW(session = LearningModelSession(model, device, options)); - auto nativeSession = session.as(); - uint32_t numIntraOpThreads; - WINML_EXPECT_NO_THROW(nativeSession->GetIntraOpNumThreads(&numIntraOpThreads)); - WINML_EXPECT_EQUAL(desiredThreads, numIntraOpThreads); - - // Check to see that bind and evaluate continue to work when setting the intra op thread count - std::vector input(1000); - std::iota(std::begin(input), std::end(input), 0.0f); - auto tensor_input = TensorFloat::CreateFromArray(shape, input); - auto binding = LearningModelBinding(session); - binding.Bind(L"input", tensor_input); - WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); - - // Check to verify that the default number of threads in LearningModelSession is equal to the number of logical cores. - session = LearningModelSession(model, device); - nativeSession = session.as(); - WINML_EXPECT_NO_THROW(nativeSession->GetIntraOpNumThreads(&numIntraOpThreads)); - WINML_EXPECT_EQUAL(std::thread::hardware_concurrency(), numIntraOpThreads); - } + auto shape = std::vector{1, 1000}; + auto model = ProtobufHelpers::CreateModel(TensorKind::Float, shape, 1000); + auto device = LearningModelDevice(LearningModelDeviceKind::Cpu); + auto options = LearningModelSessionOptions(); + auto nativeOptions = options.as(); + + // Set the number of intra op threads to half of logical cores. + uint32_t desiredThreads = std::thread::hardware_concurrency() / 2; + WINML_EXPECT_NO_THROW(nativeOptions->SetIntraOpNumThreadsOverride(desiredThreads)); + // Create session and grab the number of intra op threads to see if is set properly + LearningModelSession session = nullptr; + WINML_EXPECT_NO_THROW(session = LearningModelSession(model, device, options)); + auto nativeSession = session.as(); + uint32_t numIntraOpThreads; + WINML_EXPECT_NO_THROW(nativeSession->GetIntraOpNumThreads(&numIntraOpThreads)); + WINML_EXPECT_EQUAL(desiredThreads, numIntraOpThreads); + + // Check to see that bind and evaluate continue to work when setting the intra op thread count + std::vector input(1000); + std::iota(std::begin(input), std::end(input), 0.0f); + auto tensor_input = TensorFloat::CreateFromArray(shape, input); + auto binding = LearningModelBinding(session); + binding.Bind(L"input", tensor_input); + WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); + + // Check to verify that the default number of threads in LearningModelSession is equal to the number of logical cores. + session = LearningModelSession(model, device); + nativeSession = session.as(); + WINML_EXPECT_NO_THROW(nativeSession->GetIntraOpNumThreads(&numIntraOpThreads)); + WINML_EXPECT_EQUAL(std::thread::hardware_concurrency(), numIntraOpThreads); +} static void SetIntraOpThreadSpinning() { - auto device = LearningModelDevice(LearningModelDeviceKind::Cpu); - auto shape = std::vector{1, 1000}; - auto model = ProtobufHelpers::CreateModel(TensorKind::Float, shape, 1000); - - std::vector input(1000); - std::iota(std::begin(input), std::end(input), 0.0f); - auto tensor_input = TensorFloat::CreateFromArray(shape, input); - - auto spinDisabled = LearningModelSessionOptions(); - auto spinDisabledNative = spinDisabled.as(); - spinDisabledNative->SetIntraOpThreadSpinning(false); - - // ensure disabled thread spin is internally disabled and can evaluate without error - LearningModelSession sessionSpinDisabled = nullptr; - WINML_EXPECT_NO_THROW(sessionSpinDisabled = LearningModelSession(model, device, spinDisabled)); - auto nativeSessionSpinDisabled = sessionSpinDisabled.as(); - boolean allowSpinning = true; - nativeSessionSpinDisabled->GetIntraOpThreadSpinning(&allowSpinning); - WINML_EXPECT_FALSE(allowSpinning); - - auto binding = LearningModelBinding(sessionSpinDisabled); - binding.Bind(L"input", tensor_input); - WINML_EXPECT_NO_THROW(sessionSpinDisabled.Evaluate(binding, L"")); - - // ensure enabled thread spin is internally enabled and can evaluate without error - auto spinEnabled = LearningModelSessionOptions(); - auto spinEnabledNative = spinEnabled.as(); - spinEnabledNative->SetIntraOpThreadSpinning(true); - - LearningModelSession sessionSpinEnabled = nullptr; - WINML_EXPECT_NO_THROW(sessionSpinEnabled = LearningModelSession(model, device, spinEnabled)); - auto nativeSessionSpinEnabled = sessionSpinEnabled.as(); - nativeSessionSpinEnabled->GetIntraOpThreadSpinning(&allowSpinning); - WINML_EXPECT_TRUE(allowSpinning); - - binding = LearningModelBinding(sessionSpinEnabled); - binding.Bind(L"input", tensor_input); - WINML_EXPECT_NO_THROW(sessionSpinEnabled.Evaluate(binding, L"")); - - // ensure options by default allow spinning - auto spinDefault = LearningModelSessionOptions(); - LearningModelSession sessionSpinDefault = nullptr; - WINML_EXPECT_NO_THROW(sessionSpinDefault = LearningModelSession(model, device, spinDefault)); - auto nativeSessionSpinDefault = sessionSpinDefault.as(); - allowSpinning = false; - nativeSessionSpinDefault->GetIntraOpThreadSpinning(&allowSpinning); - WINML_EXPECT_TRUE(allowSpinning); - } - - static void SetName() { - #ifndef BUILD_INBOX - // load the model with name 'squeezenet_old' - LearningModel model = nullptr; - WINML_EXPECT_NO_THROW(APITest::LoadModel(L"model.onnx", model)); - auto model_name = model.Name(); - auto squeezenet_old = to_hstring("squeezenet_old"); - WINML_EXPECT_EQUAL(model_name, squeezenet_old); - - // ensure the model name can be changed to 'new name' - auto experimental_model = winml_experimental::LearningModelExperimental(model); - auto new_name = to_hstring("new name"); - experimental_model.SetName(new_name); - model_name = model.Name(); - WINML_EXPECT_EQUAL(model_name, new_name); - - // ensure the model protobuf was actually modified - std::wstring path = FileHelpers::GetModulePath() + L"model_name_changed.onnx"; - experimental_model.Save(path); - LearningModel model_name_changed = nullptr; - WINML_EXPECT_NO_THROW(APITest::LoadModel(L"model_name_changed.onnx", model_name_changed)); - model_name = model_name_changed.Name(); - WINML_EXPECT_EQUAL(model_name, new_name); - #endif - } + auto device = LearningModelDevice(LearningModelDeviceKind::Cpu); + auto shape = std::vector{1, 1000}; + auto model = ProtobufHelpers::CreateModel(TensorKind::Float, shape, 1000); + + std::vector input(1000); + std::iota(std::begin(input), std::end(input), 0.0f); + auto tensor_input = TensorFloat::CreateFromArray(shape, input); + + auto spinDisabled = LearningModelSessionOptions(); + auto spinDisabledNative = spinDisabled.as(); + spinDisabledNative->SetIntraOpThreadSpinning(false); + // ensure disabled thread spin is internally disabled and can evaluate without error + LearningModelSession sessionSpinDisabled = nullptr; + WINML_EXPECT_NO_THROW(sessionSpinDisabled = LearningModelSession(model, device, spinDisabled)); + auto nativeSessionSpinDisabled = sessionSpinDisabled.as(); + boolean allowSpinning = true; + nativeSessionSpinDisabled->GetIntraOpThreadSpinning(&allowSpinning); + WINML_EXPECT_FALSE(allowSpinning); + + auto binding = LearningModelBinding(sessionSpinDisabled); + binding.Bind(L"input", tensor_input); + WINML_EXPECT_NO_THROW(sessionSpinDisabled.Evaluate(binding, L"")); + + // ensure enabled thread spin is internally enabled and can evaluate without error + auto spinEnabled = LearningModelSessionOptions(); + auto spinEnabledNative = spinEnabled.as(); + spinEnabledNative->SetIntraOpThreadSpinning(true); + + LearningModelSession sessionSpinEnabled = nullptr; + WINML_EXPECT_NO_THROW(sessionSpinEnabled = LearningModelSession(model, device, spinEnabled)); + auto nativeSessionSpinEnabled = sessionSpinEnabled.as(); + nativeSessionSpinEnabled->GetIntraOpThreadSpinning(&allowSpinning); + WINML_EXPECT_TRUE(allowSpinning); + + binding = LearningModelBinding(sessionSpinEnabled); + binding.Bind(L"input", tensor_input); + WINML_EXPECT_NO_THROW(sessionSpinEnabled.Evaluate(binding, L"")); + + // ensure options by default allow spinning + auto spinDefault = LearningModelSessionOptions(); + LearningModelSession sessionSpinDefault = nullptr; + WINML_EXPECT_NO_THROW(sessionSpinDefault = LearningModelSession(model, device, spinDefault)); + auto nativeSessionSpinDefault = sessionSpinDefault.as(); + allowSpinning = false; + nativeSessionSpinDefault->GetIntraOpThreadSpinning(&allowSpinning); + WINML_EXPECT_TRUE(allowSpinning); +} + +static void SetName() { +#ifndef BUILD_INBOX + // load the model with name 'squeezenet_old' + LearningModel model = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"model.onnx", model)); + auto model_name = model.Name(); + auto squeezenet_old = to_hstring("squeezenet_old"); + WINML_EXPECT_EQUAL(model_name, squeezenet_old); + + // ensure the model name can be changed to 'new name' + auto experimental_model = winml_experimental::LearningModelExperimental(model); + auto new_name = to_hstring("new name"); + experimental_model.SetName(new_name); + model_name = model.Name(); + WINML_EXPECT_EQUAL(model_name, new_name); + + // ensure the model protobuf was actually modified + std::wstring path = FileHelpers::GetModulePath() + L"model_name_changed.onnx"; + experimental_model.Save(path); + LearningModel model_name_changed = nullptr; + WINML_EXPECT_NO_THROW(APITest::LoadModel(L"model_name_changed.onnx", model_name_changed)); + model_name = model_name_changed.Name(); + WINML_EXPECT_EQUAL(model_name, new_name); +#endif +} const LearningModelSessionAPITestsApi& getapi() { - static LearningModelSessionAPITestsApi api = - { + static LearningModelSessionAPITestsApi api = { LearningModelSessionAPITestsClassSetup, CreateSessionDeviceDefault, CreateSessionDeviceCpu, @@ -1570,14 +2305,14 @@ const LearningModelSessionAPITestsApi& getapi() { ModelBuilding_DiscreteFourierTransformInverseIdentity, ModelBuilding_DiscreteFourierTransformDeviceDirectX, ModelBuilding_DiscreteFourierTransformInverseIdentityDeviceDirectX, + ModelBuilding_GridSampleDeviceDirectX, ModelBuilding_HannWindow, ModelBuilding_HammingWindow, ModelBuilding_BlackmanWindow, ModelBuilding_STFT, ModelBuilding_MelSpectrogramOnThreeToneSignal, ModelBuilding_MelWeightMatrix, - SetName - }; + SetName}; if (SkipGpuTests()) { api.CreateSessionDeviceDirectX = SkipTest; @@ -1588,6 +2323,7 @@ const LearningModelSessionAPITestsApi& getapi() { api.AdapterIdAndDevice = SkipTest; api.ModelBuilding_DiscreteFourierTransformDeviceDirectX = SkipTest; api.ModelBuilding_DiscreteFourierTransformInverseIdentityDeviceDirectX = SkipTest; + api.ModelBuilding_GridSampleDeviceDirectX = SkipTest; } if (RuntimeParameterExists(L"EdgeCore")) { api.AdapterIdAndDevice = SkipTest; @@ -1598,7 +2334,7 @@ const LearningModelSessionAPITestsApi& getapi() { api.AdapterIdAndDevice = SkipTest; } if (SkipTestsImpactedByOpenMP()) { - api.SetIntraOpNumThreads = SkipTest; + api.SetIntraOpNumThreads = SkipTest; } - return api; + return api; } diff --git a/winml/test/api/LearningModelSessionAPITest.h b/winml/test/api/LearningModelSessionAPITest.h index 464edfbef155f..feb26d5ccecea 100644 --- a/winml/test/api/LearningModelSessionAPITest.h +++ b/winml/test/api/LearningModelSessionAPITest.h @@ -30,6 +30,7 @@ struct LearningModelSessionAPITestsApi { VoidTest ModelBuilding_DiscreteFourierTransformInverseIdentity; VoidTest ModelBuilding_DiscreteFourierTransformDeviceDirectX; VoidTest ModelBuilding_DiscreteFourierTransformInverseIdentityDeviceDirectX; + VoidTest ModelBuilding_GridSampleDeviceDirectX; VoidTest ModelBuilding_HannWindow; VoidTest ModelBuilding_HammingWindow; VoidTest ModelBuilding_BlackmanWindow; @@ -44,12 +45,12 @@ WINML_TEST_CLASS_BEGIN(LearningModelSessionAPITests) WINML_TEST_CLASS_SETUP_CLASS(LearningModelSessionAPITestsClassSetup) WINML_TEST_CLASS_BEGIN_TESTS WINML_TEST(LearningModelSessionAPITests, CreateSessionDeviceDefault) -WINML_TEST(LearningModelSessionAPITests,CreateSessionDeviceCpu) -WINML_TEST(LearningModelSessionAPITests,CreateSessionWithModelLoadedFromStream) -WINML_TEST(LearningModelSessionAPITests,EvaluateFeatures) -WINML_TEST(LearningModelSessionAPITests,EvaluateFeaturesAsync) -WINML_TEST(LearningModelSessionAPITests,EvaluationProperties) -WINML_TEST(LearningModelSessionAPITests,EvaluateSessionAndCloseModel) +WINML_TEST(LearningModelSessionAPITests, CreateSessionDeviceCpu) +WINML_TEST(LearningModelSessionAPITests, CreateSessionWithModelLoadedFromStream) +WINML_TEST(LearningModelSessionAPITests, EvaluateFeatures) +WINML_TEST(LearningModelSessionAPITests, EvaluateFeaturesAsync) +WINML_TEST(LearningModelSessionAPITests, EvaluationProperties) +WINML_TEST(LearningModelSessionAPITests, EvaluateSessionAndCloseModel) WINML_TEST(LearningModelSessionAPITests, CreateSessionDeviceDirectX) WINML_TEST(LearningModelSessionAPITests, CreateSessionDeviceDirectXHighPerformance) WINML_TEST(LearningModelSessionAPITests, CreateSessionDeviceDirectXMinimumPower) @@ -68,6 +69,7 @@ WINML_TEST(LearningModelSessionAPITests, ModelBuilding_DiscreteFourierTransform) WINML_TEST(LearningModelSessionAPITests, ModelBuilding_DiscreteFourierTransformInverseIdentity) WINML_TEST(LearningModelSessionAPITests, ModelBuilding_DiscreteFourierTransformDeviceDirectX) WINML_TEST(LearningModelSessionAPITests, ModelBuilding_DiscreteFourierTransformInverseIdentityDeviceDirectX) +WINML_TEST(LearningModelSessionAPITests, ModelBuilding_GridSampleDeviceDirectX) WINML_TEST(LearningModelSessionAPITests, ModelBuilding_HannWindow) WINML_TEST(LearningModelSessionAPITests, ModelBuilding_HammingWindow) WINML_TEST(LearningModelSessionAPITests, ModelBuilding_BlackmanWindow) diff --git a/winml/test/api/RawApiHelpers.cpp b/winml/test/api/RawApiHelpers.cpp index c11faeca3e688..b6f39f8e88224 100644 --- a/winml/test/api/RawApiHelpers.cpp +++ b/winml/test/api/RawApiHelpers.cpp @@ -8,70 +8,56 @@ namespace ml = Microsoft::AI::MachineLearning; void RunOnDevice(ml::learning_model& model, ml::learning_model_device& device, InputStrategy strategy) { - const wchar_t input_name[] = L"data_0"; - const wchar_t output_name[] = L"softmaxout_1"; - - std::unique_ptr session = nullptr; - WINML_EXPECT_NO_THROW(session = std::make_unique(model, device)); - - std::unique_ptr binding = nullptr; - WINML_EXPECT_NO_THROW(binding = std::make_unique(*session.get())); - - auto input_shape = std::vector{ 1, 3, 224, 224 }; - auto input_data = std::vector(1 * 3 * 224 * 224); - auto output_shape = std::vector{ 1, 1000, 1, 1 }; - - std::iota(begin(input_data), end(input_data), 0.f); - - if (strategy == InputStrategy::CopyInputs) - { - WINML_EXPECT_HRESULT_SUCCEEDED( - binding->bind( - input_name, _countof(input_name) - 1, - input_shape.data(), input_shape.size(), - input_data.data(), input_data.size())); - } else if (strategy == InputStrategy::BindAsReference) - { - WINML_EXPECT_HRESULT_SUCCEEDED( - binding->bind_as_reference( - input_name, _countof(input_name) - 1, - input_shape.data(), input_shape.size(), - input_data.data(), input_data.size())); - } else if (strategy == InputStrategy::BindWithMultipleReferences) { - size_t channel_size = 224 * 224; - auto channel_buffers_sizes = std::vector{ - channel_size, - channel_size, - channel_size - }; - - auto channel_buffers_pointers = std::vector{ - &input_data.at(0), - &input_data.at(0) + channel_buffers_sizes[0], - &input_data.at(0) + channel_buffers_sizes[0] + +channel_buffers_sizes[1] - }; - - WINML_EXPECT_HRESULT_SUCCEEDED( - binding->bind_as_references( - input_name, _countof(input_name) - 1, - channel_buffers_pointers.data(), channel_buffers_sizes.data(), - channel_buffers_sizes.size())); - } - - WINML_EXPECT_HRESULT_SUCCEEDED( - binding->bind( - output_name, _countof(output_name) - 1, - output_shape.data(), output_shape.size())); - - ml::learning_model_results results = session->evaluate(*binding.get()); - - float* p_buffer = nullptr; - size_t buffer_size = 0; - WINML_EXPECT_HRESULT_SUCCEEDED( - 0 == results.get_output( - output_name, - _countof(output_name) - 1, - reinterpret_cast(&p_buffer), - &buffer_size) - ); + const wchar_t input_name[] = L"data_0"; + const wchar_t output_name[] = L"softmaxout_1"; + + std::unique_ptr session = nullptr; + WINML_EXPECT_NO_THROW(session = std::make_unique(model, device)); + + std::unique_ptr binding = nullptr; + WINML_EXPECT_NO_THROW(binding = std::make_unique(*session.get())); + + auto input_shape = std::vector{1, 3, 224, 224}; + auto input_data = std::vector(1 * 3 * 224 * 224); + auto output_shape = std::vector{1, 1000, 1, 1}; + + std::iota(begin(input_data), end(input_data), 0.f); + + if (strategy == InputStrategy::CopyInputs) { + WINML_EXPECT_HRESULT_SUCCEEDED(binding->bind( + input_name, _countof(input_name) - 1, input_shape.data(), input_shape.size(), input_data.data(), input_data.size() + )); + } else if (strategy == InputStrategy::BindAsReference) { + WINML_EXPECT_HRESULT_SUCCEEDED(binding->bind_as_reference( + input_name, _countof(input_name) - 1, input_shape.data(), input_shape.size(), input_data.data(), input_data.size() + )); + } else if (strategy == InputStrategy::BindWithMultipleReferences) { + size_t channel_size = 224 * 224; + auto channel_buffers_sizes = std::vector{channel_size, channel_size, channel_size}; + + auto channel_buffers_pointers = std::vector{ + &input_data.at(0), + &input_data.at(0) + channel_buffers_sizes[0], + &input_data.at(0) + channel_buffers_sizes[0] + +channel_buffers_sizes[1]}; + + WINML_EXPECT_HRESULT_SUCCEEDED(binding->bind_as_references( + input_name, + _countof(input_name) - 1, + channel_buffers_pointers.data(), + channel_buffers_sizes.data(), + channel_buffers_sizes.size() + )); + } + + WINML_EXPECT_HRESULT_SUCCEEDED( + binding->bind(output_name, _countof(output_name) - 1, output_shape.data(), output_shape.size()) + ); + + ml::learning_model_results results = session->evaluate(*binding.get()); + + float* p_buffer = nullptr; + size_t buffer_size = 0; + WINML_EXPECT_HRESULT_SUCCEEDED( + 0 == results.get_output(output_name, _countof(output_name) - 1, reinterpret_cast(&p_buffer), &buffer_size) + ); } diff --git a/winml/test/api/RawApiHelpers.h b/winml/test/api/RawApiHelpers.h index 449f3516456fe..791b2b0a34ece 100644 --- a/winml/test/api/RawApiHelpers.h +++ b/winml/test/api/RawApiHelpers.h @@ -8,9 +8,13 @@ #include "raw/microsoft.ai.machinelearning.gpu.h" enum class InputStrategy { - CopyInputs, - BindAsReference, - BindWithMultipleReferences + CopyInputs, + BindAsReference, + BindWithMultipleReferences }; -void RunOnDevice(Microsoft::AI::MachineLearning::learning_model& model, Microsoft::AI::MachineLearning::learning_model_device& device, InputStrategy strategy); \ No newline at end of file +void RunOnDevice( + Microsoft::AI::MachineLearning::learning_model& model, + Microsoft::AI::MachineLearning::learning_model_device& device, + InputStrategy strategy +); diff --git a/winml/test/api/RawApiTests.cpp b/winml/test/api/RawApiTests.cpp index d0675453792a0..70f53c72f4d8d 100644 --- a/winml/test/api/RawApiTests.cpp +++ b/winml/test/api/RawApiTests.cpp @@ -11,16 +11,15 @@ namespace ml = Microsoft::AI::MachineLearning; -auto CreateModelAsBuffer(const wchar_t* model_path) -{ - std::ifstream input_stream(model_path, std::ios::binary | std::ios::ate); - std::streamsize size = input_stream.tellg(); - input_stream.seekg(0, std::ios::beg); +auto CreateModelAsBuffer(const wchar_t* model_path) { + std::ifstream input_stream(model_path, std::ios::binary | std::ios::ate); + std::streamsize size = input_stream.tellg(); + input_stream.seekg(0, std::ios::beg); - std::vector buffer(static_cast::size_type>(size)); - input_stream.read(buffer.data(), size); + std::vector buffer(static_cast::size_type>(size)); + input_stream.read(buffer.data(), size); - return std::make_pair(buffer, size); + return std::make_pair(buffer, size); } static void RawApiTestsApiTestsClassSetup() { @@ -96,13 +95,13 @@ static void EvaluateFromModelFromBuffer() { const RawApiTestsApi& getapi() { static constexpr RawApiTestsApi api = { - RawApiTestsApiTestsClassSetup, - CreateModelFromFilePath, - CreateCpuDevice, - Evaluate, - EvaluateNoInputCopy, - EvaluateManyBuffers, - EvaluateFromModelFromBuffer, + RawApiTestsApiTestsClassSetup, + CreateModelFromFilePath, + CreateCpuDevice, + Evaluate, + EvaluateNoInputCopy, + EvaluateManyBuffers, + EvaluateFromModelFromBuffer, }; return api; } diff --git a/winml/test/api/RawApiTests.h b/winml/test/api/RawApiTests.h index aa86c9abed65c..148e2fe2f1ac8 100644 --- a/winml/test/api/RawApiTests.h +++ b/winml/test/api/RawApiTests.h @@ -3,8 +3,7 @@ #include "test.h" -struct RawApiTestsApi -{ +struct RawApiTestsApi { SetupClass RawApiTestsApiTestsClassSetup; VoidTest CreateModelFromFilePath; VoidTest CreateCpuDevice; @@ -25,4 +24,4 @@ WINML_TEST(RawApiTests, Evaluate) WINML_TEST(RawApiTests, EvaluateNoInputCopy) WINML_TEST(RawApiTests, EvaluateManyBuffers) WINML_TEST(RawApiTests, EvaluateFromModelFromBuffer) -WINML_TEST_CLASS_END() \ No newline at end of file +WINML_TEST_CLASS_END() diff --git a/winml/test/api/RawApiTestsGpu.cpp b/winml/test/api/RawApiTestsGpu.cpp index 0be2a2bfbc452..9c1c06a01603f 100644 --- a/winml/test/api/RawApiTestsGpu.cpp +++ b/winml/test/api/RawApiTestsGpu.cpp @@ -14,90 +14,82 @@ namespace ml = Microsoft::AI::MachineLearning; -enum class DeviceType -{ - CPU, - DirectX, - D3D11Device, - D3D12CommandQueue, - DirectXHighPerformance, - DirectXMinPower, - Last +enum class DeviceType { + CPU, + DirectX, + D3D11Device, + D3D12CommandQueue, + DirectXHighPerformance, + DirectXMinPower, + Last }; - -ml::learning_model_device CreateDevice(DeviceType deviceType) -{ - switch (deviceType) - { +ml::learning_model_device CreateDevice(DeviceType deviceType) { + switch (deviceType) { case DeviceType::CPU: - return ml::learning_model_device(); + return ml::learning_model_device(); case DeviceType::DirectX: - return ml::gpu::directx_device(ml::gpu::directx_device_kind::directx); + return ml::gpu::directx_device(ml::gpu::directx_device_kind::directx); case DeviceType::DirectXHighPerformance: - return ml::gpu::directx_device(ml::gpu::directx_device_kind::directx_high_power); + return ml::gpu::directx_device(ml::gpu::directx_device_kind::directx_high_power); case DeviceType::DirectXMinPower: - return ml::gpu::directx_device(ml::gpu::directx_device_kind::directx_min_power); - case DeviceType::D3D11Device: - { - Microsoft::WRL::ComPtr d3d11Device; - Microsoft::WRL::ComPtr d3d11DeviceContext; - D3D_FEATURE_LEVEL d3dFeatureLevel; - auto result = D3D11CreateDevice( - nullptr, - D3D_DRIVER_TYPE::D3D_DRIVER_TYPE_HARDWARE, - nullptr, - 0, - nullptr, - 0, - D3D11_SDK_VERSION, - d3d11Device.GetAddressOf(), - &d3dFeatureLevel, - d3d11DeviceContext.GetAddressOf() - ); - if (FAILED(result)) - { - printf("Failed to create d3d11 device"); - exit(3); - } - - Microsoft::WRL::ComPtr dxgiDevice; - d3d11Device.Get()->QueryInterface(dxgiDevice.GetAddressOf()); - - Microsoft::WRL::ComPtr inspectable; - CreateDirect3D11DeviceFromDXGIDevice(dxgiDevice.Get(), inspectable.GetAddressOf()); - - Microsoft::WRL::ComPtr direct3dDevice; - inspectable.As(&direct3dDevice); - - return ml::gpu::directx_device(direct3dDevice.Get()); + return ml::gpu::directx_device(ml::gpu::directx_device_kind::directx_min_power); + case DeviceType::D3D11Device: { + Microsoft::WRL::ComPtr d3d11Device; + Microsoft::WRL::ComPtr d3d11DeviceContext; + D3D_FEATURE_LEVEL d3dFeatureLevel; + auto result = D3D11CreateDevice( + nullptr, + D3D_DRIVER_TYPE::D3D_DRIVER_TYPE_HARDWARE, + nullptr, + 0, + nullptr, + 0, + D3D11_SDK_VERSION, + d3d11Device.GetAddressOf(), + &d3dFeatureLevel, + d3d11DeviceContext.GetAddressOf() + ); + if (FAILED(result)) { + printf("Failed to create d3d11 device"); + exit(3); + } + + Microsoft::WRL::ComPtr dxgiDevice; + d3d11Device.Get()->QueryInterface(dxgiDevice.GetAddressOf()); + + Microsoft::WRL::ComPtr inspectable; + CreateDirect3D11DeviceFromDXGIDevice(dxgiDevice.Get(), inspectable.GetAddressOf()); + + Microsoft::WRL::ComPtr direct3dDevice; + inspectable.As(&direct3dDevice); + + return ml::gpu::directx_device(direct3dDevice.Get()); } - case DeviceType::D3D12CommandQueue: - { - Microsoft::WRL::ComPtr d3d12Device; - auto result = D3D12CreateDevice( - nullptr, - D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_12_0, - __uuidof(ID3D12Device), - reinterpret_cast(d3d12Device.GetAddressOf())); - if (FAILED(result)) - { - printf("Failed to create d3d12 device"); - exit(3); - } - Microsoft::WRL::ComPtr queue; - D3D12_COMMAND_QUEUE_DESC commandQueueDesc = {}; - commandQueueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; - d3d12Device->CreateCommandQueue( - &commandQueueDesc, - __uuidof(ID3D12CommandQueue), - reinterpret_cast(queue.GetAddressOf())); - - return ml::gpu::directx_device(queue.Get()); + case DeviceType::D3D12CommandQueue: { + Microsoft::WRL::ComPtr d3d12Device; + auto result = D3D12CreateDevice( + nullptr, + D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_12_0, + __uuidof(ID3D12Device), + reinterpret_cast(d3d12Device.GetAddressOf()) + ); + if (FAILED(result)) { + printf("Failed to create d3d12 device"); + exit(3); + } + Microsoft::WRL::ComPtr queue; + D3D12_COMMAND_QUEUE_DESC commandQueueDesc = {}; + commandQueueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; + d3d12Device->CreateCommandQueue( + &commandQueueDesc, __uuidof(ID3D12CommandQueue), reinterpret_cast(queue.GetAddressOf()) + ); + + return ml::gpu::directx_device(queue.Get()); } default: return ml::learning_model_device(); - } + } } static void RawApiTestsGpuApiTestsClassSetup() { @@ -165,16 +157,15 @@ static void EvaluateManyBuffers() { const RawApiTestsGpuApi& getapi() { static RawApiTestsGpuApi api = { - RawApiTestsGpuApiTestsClassSetup, - CreateDirectXDevice, - CreateD3D11DeviceDevice, - CreateD3D12CommandQueueDevice, - CreateDirectXHighPerformanceDevice, - CreateDirectXMinPowerDevice, - Evaluate, - EvaluateNoInputCopy, - EvaluateManyBuffers - }; + RawApiTestsGpuApiTestsClassSetup, + CreateDirectXDevice, + CreateD3D11DeviceDevice, + CreateD3D12CommandQueueDevice, + CreateDirectXHighPerformanceDevice, + CreateDirectXMinPowerDevice, + Evaluate, + EvaluateNoInputCopy, + EvaluateManyBuffers}; if (SkipGpuTests()) { api.CreateDirectXDevice = SkipTest; @@ -187,4 +178,4 @@ const RawApiTestsGpuApi& getapi() { api.EvaluateManyBuffers = SkipTest; } return api; -} \ No newline at end of file +} diff --git a/winml/test/api/RawApiTestsGpu.h b/winml/test/api/RawApiTestsGpu.h index 3212618a2dfd4..34bde02aac5e9 100644 --- a/winml/test/api/RawApiTestsGpu.h +++ b/winml/test/api/RawApiTestsGpu.h @@ -3,8 +3,7 @@ #include "test.h" -struct RawApiTestsGpuApi -{ +struct RawApiTestsGpuApi { SetupClass RawApiTestsGpuApiTestsClassSetup; VoidTest CreateDirectXDevice; VoidTest CreateD3D11DeviceDevice; diff --git a/winml/test/api/raw/buffer_backed_random_access_stream_reference.h b/winml/test/api/raw/buffer_backed_random_access_stream_reference.h index f1eb29a678c70..e9539c188e45a 100644 --- a/winml/test/api/raw/buffer_backed_random_access_stream_reference.h +++ b/winml/test/api/raw/buffer_backed_random_access_stream_reference.h @@ -15,349 +15,355 @@ namespace WinMLTest { struct BufferBackedRandomAccessStreamReadAsync - : public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags, - __FIAsyncOperationWithProgress_2_Windows__CStorage__CStreams__CIBuffer_UINT32, - ABI::Windows::Foundation::IAsyncInfo> { - - InspectableClass(L"WinMLTest.BufferBackedRandomAccessStreamReadAsync", BaseTrust) + : public Microsoft::WRL::RuntimeClass< + Microsoft::WRL::RuntimeClassFlags, + __FIAsyncOperationWithProgress_2_Windows__CStorage__CStreams__CIBuffer_UINT32, + ABI::Windows::Foundation::IAsyncInfo> { + InspectableClass(L"WinMLTest.BufferBackedRandomAccessStreamReadAsync", BaseTrust) Microsoft::WRL::ComPtr buffer_; - Microsoft::WRL::ComPtr> completed_handler_; - Microsoft::WRL::ComPtr> progress_handler_; - - AsyncStatus status_ = AsyncStatus::Started; - -public: - - virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Id( - /* [retval][out] */ __RPC__out unsigned __int32* id) override { - *id = 0; // Do we need to implement this? - return S_OK; - } - - virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Status( - /* [retval][out] */ __RPC__out AsyncStatus* status) override { - *status = status_; - return S_OK; - } - - virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_ErrorCode( - /* [retval][out] */ __RPC__out HRESULT* /*errorCode*/) override { - return E_NOTIMPL; - } - - virtual HRESULT STDMETHODCALLTYPE Cancel(void) override { - return E_NOTIMPL; - } - - virtual HRESULT STDMETHODCALLTYPE Close(void) override { - return E_NOTIMPL; - } - - - - HRESULT SetBuffer(ABI::Windows::Storage::Streams::IBuffer* buffer) { - buffer_ = buffer; - status_ = AsyncStatus::Completed; - if (buffer_ != nullptr) { - if (completed_handler_ != nullptr) { - completed_handler_->Invoke(this, ABI::Windows::Foundation::AsyncStatus::Completed); - } - } - return S_OK; - } - - virtual HRESULT STDMETHODCALLTYPE put_Progress( - ABI::Windows::Foundation::IAsyncOperationProgressHandler* handler) override { - progress_handler_ = handler; - return S_OK; - } - - virtual HRESULT STDMETHODCALLTYPE get_Progress(ABI::Windows::Foundation::IAsyncOperationProgressHandler** handler)override { - progress_handler_.CopyTo(handler); - return S_OK; - } - - virtual HRESULT STDMETHODCALLTYPE put_Completed(ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler* handler) override { - completed_handler_ = handler; - return S_OK; - } - - virtual HRESULT STDMETHODCALLTYPE get_Completed(ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler** handler) override { - completed_handler_.CopyTo(handler); - return S_OK; - } - - virtual HRESULT STDMETHODCALLTYPE GetResults(ABI::Windows::Storage::Streams::IBuffer** results) override { - if (buffer_ == nullptr) { - return E_FAIL; - } - - buffer_.CopyTo(results); - return S_OK; - } + Microsoft::WRL::ComPtr> + completed_handler_; + Microsoft::WRL::ComPtr< + ABI::Windows::Foundation::IAsyncOperationProgressHandler> + progress_handler_; + + AsyncStatus status_ = AsyncStatus::Started; + + public: + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Id( + /* [retval][out] */ __RPC__out unsigned __int32* id + ) override { + *id = 0; // Do we need to implement this? + return S_OK; + } + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Status( + /* [retval][out] */ __RPC__out AsyncStatus* status + ) override { + *status = status_; + return S_OK; + } + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_ErrorCode( + /* [retval][out] */ __RPC__out HRESULT* /*errorCode*/ + ) override { + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE Cancel(void) override { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE Close(void) override { return E_NOTIMPL; } + + HRESULT SetBuffer(ABI::Windows::Storage::Streams::IBuffer* buffer) { + buffer_ = buffer; + status_ = AsyncStatus::Completed; + if (buffer_ != nullptr) { + if (completed_handler_ != nullptr) { + completed_handler_->Invoke(this, ABI::Windows::Foundation::AsyncStatus::Completed); + } + } + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE put_Progress( + ABI::Windows::Foundation::IAsyncOperationProgressHandler* handler + ) override { + progress_handler_ = handler; + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE get_Progress( + ABI::Windows::Foundation::IAsyncOperationProgressHandler** handler + ) override { + progress_handler_.CopyTo(handler); + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE put_Completed(ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler< + ABI::Windows::Storage::Streams::IBuffer*, + UINT32>* handler) override { + completed_handler_ = handler; + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE get_Completed(ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler< + ABI::Windows::Storage::Streams::IBuffer*, + UINT32>** handler) override { + completed_handler_.CopyTo(handler); + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE GetResults(ABI::Windows::Storage::Streams::IBuffer** results) override { + if (buffer_ == nullptr) { + return E_FAIL; + } + + buffer_.CopyTo(results); + return S_OK; + } }; struct RandomAccessStream - : public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags, - ABI::Windows::Storage::Streams::IRandomAccessStreamWithContentType, - ABI::Windows::Storage::Streams::IContentTypeProvider, - ABI::Windows::Storage::Streams::IRandomAccessStream, - ABI::Windows::Storage::Streams::IInputStream, - ABI::Windows::Storage::Streams::IOutputStream, - ABI::Windows::Foundation::IClosable> { + : public Microsoft::WRL::RuntimeClass< + Microsoft::WRL::RuntimeClassFlags, + ABI::Windows::Storage::Streams::IRandomAccessStreamWithContentType, + ABI::Windows::Storage::Streams::IContentTypeProvider, + ABI::Windows::Storage::Streams::IRandomAccessStream, + ABI::Windows::Storage::Streams::IInputStream, + ABI::Windows::Storage::Streams::IOutputStream, + ABI::Windows::Foundation::IClosable> { InspectableClass(L"WinMLTest.RandomAccessStream", BaseTrust) -private: - Microsoft::WRL::ComPtr buffer_ = nullptr; - UINT64 position_ = 0; - -public: - HRESULT RuntimeClassInitialize(ABI::Windows::Storage::Streams::IBuffer* buffer) { - buffer_ = buffer; - position_ = 0; - return S_OK; - } - - HRESULT RuntimeClassInitialize(ABI::Windows::Storage::Streams::IBuffer* buffer, UINT64 position) { - buffer_ = buffer; - position_ = position; - return S_OK; - } - - // Content Provider - - /* [propget] */virtual HRESULT STDMETHODCALLTYPE get_ContentType( - /* [retval, out] */__RPC__deref_out_opt HSTRING* value - ) override { - return WindowsCreateString(nullptr, 0, value); - } - - // IRandomAccessStream - - /* [propget] */virtual HRESULT STDMETHODCALLTYPE get_Size( - /* [retval, out] */__RPC__out UINT64* value - ) override { - *value = 0; - uint32_t length; - buffer_->get_Length(&length); - *value = static_cast(length); - return S_OK; - } - - /* [propput] */virtual HRESULT STDMETHODCALLTYPE put_Size( - /* [in] */UINT64 /*value*/ - ) override { - return E_NOTIMPL; - } - - virtual HRESULT STDMETHODCALLTYPE GetInputStreamAt( - /* [in] */UINT64 position, - /* [retval, out] */__RPC__deref_out_opt ABI::Windows::Storage::Streams::IInputStream** stream - ) override { - return Microsoft::WRL::MakeAndInitialize(stream, buffer_.Get(), position); - } - - virtual HRESULT STDMETHODCALLTYPE GetOutputStreamAt( - /* [in] */UINT64 /*position*/, - /* [retval, out] */__RPC__deref_out_opt ABI::Windows::Storage::Streams::IOutputStream** /*stream*/ - ) override { - return E_NOTIMPL; - } - - /* [propget] */virtual HRESULT STDMETHODCALLTYPE get_Position( - /* [retval, out] */__RPC__out UINT64* value - ) override { - *value = position_; - return S_OK; - } - - virtual HRESULT STDMETHODCALLTYPE Seek( - /* [in] */UINT64 position - ) override { - position_ = position; - return S_OK; - } - - virtual HRESULT STDMETHODCALLTYPE CloneStream( - /* [retval, out] */__RPC__deref_out_opt ABI::Windows::Storage::Streams::IRandomAccessStream** stream - ) override { - return Microsoft::WRL::MakeAndInitialize(stream, buffer_.Get(), 0); - } - - /* [propget] */virtual HRESULT STDMETHODCALLTYPE get_CanRead( - /* [retval, out] */__RPC__out::boolean* value - ) override { - UINT32 length; - buffer_->get_Length(&length); - *value = buffer_ != nullptr && position_ < static_cast(length); - return S_OK; - } - - /* [propget] */virtual HRESULT STDMETHODCALLTYPE get_CanWrite( - /* [retval, out] */__RPC__out::boolean* value - ) override { - *value = false; - return S_OK; - } - - // IInputStream - virtual HRESULT STDMETHODCALLTYPE ReadAsync( - /* [in] */__RPC__in_opt ABI::Windows::Storage::Streams::IBuffer* buffer, - /* [in] */UINT32 count, - /* [in] */ABI::Windows::Storage::Streams::InputStreamOptions /*options*/, - /* [retval, out] */__RPC__deref_out_opt __FIAsyncOperationWithProgress_2_Windows__CStorage__CStreams__CIBuffer_UINT32** operation - ) override { - auto read_async = Microsoft::WRL::Make(); - read_async.CopyTo(operation); - - // perform the "async work" which is actually synchronous atm - Microsoft::WRL::ComPtr spBuffer = buffer; - Microsoft::WRL::ComPtr out_buffer_byte_access; - spBuffer.As(&out_buffer_byte_access); - byte* out_bytes = nullptr; - out_buffer_byte_access->Buffer(&out_bytes); - - Microsoft::WRL::ComPtr in_buffer_byte_access; - buffer_.As(&in_buffer_byte_access); - byte* in_bytes = nullptr; - in_buffer_byte_access->Buffer(&in_bytes); - - memcpy(out_bytes, in_bytes + static_cast(position_), count); - - read_async->SetBuffer(buffer); - - return S_OK; - } - - // IOutputStream - virtual HRESULT STDMETHODCALLTYPE WriteAsync( - /* [in] */__RPC__in_opt ABI::Windows::Storage::Streams::IBuffer* /*buffer*/, - /* [retval, out] */__RPC__deref_out_opt __FIAsyncOperationWithProgress_2_UINT32_UINT32** /*operation*/ - ) override { - return E_NOTIMPL; - } - - virtual HRESULT STDMETHODCALLTYPE FlushAsync( - /* [retval, out] */__RPC__deref_out_opt __FIAsyncOperation_1_boolean** /*operation*/ - ) override { - return E_NOTIMPL; - } - - // IClosable - virtual HRESULT STDMETHODCALLTYPE Close(void) override { - buffer_ = nullptr; - return S_OK; - } - + private : Microsoft::WRL::ComPtr buffer_ = nullptr; + UINT64 position_ = 0; + + public: + HRESULT RuntimeClassInitialize(ABI::Windows::Storage::Streams::IBuffer* buffer) { + buffer_ = buffer; + position_ = 0; + return S_OK; + } + + HRESULT RuntimeClassInitialize(ABI::Windows::Storage::Streams::IBuffer* buffer, UINT64 position) { + buffer_ = buffer; + position_ = position; + return S_OK; + } + + // Content Provider + + /* [propget] */ virtual HRESULT STDMETHODCALLTYPE get_ContentType( + /* [retval, out] */ __RPC__deref_out_opt HSTRING* value + ) override { + return WindowsCreateString(nullptr, 0, value); + } + + // IRandomAccessStream + + /* [propget] */ virtual HRESULT STDMETHODCALLTYPE get_Size( + /* [retval, out] */ __RPC__out UINT64* value + ) override { + *value = 0; + uint32_t length; + buffer_->get_Length(&length); + *value = static_cast(length); + return S_OK; + } + + /* [propput] */ virtual HRESULT STDMETHODCALLTYPE put_Size( + /* [in] */ UINT64 /*value*/ + ) override { + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE GetInputStreamAt( + /* [in] */ UINT64 position, + /* [retval, out] */ __RPC__deref_out_opt ABI::Windows::Storage::Streams::IInputStream** stream + ) override { + return Microsoft::WRL::MakeAndInitialize(stream, buffer_.Get(), position); + } + + virtual HRESULT STDMETHODCALLTYPE GetOutputStreamAt( + /* [in] */ UINT64 /*position*/, + /* [retval, out] */ __RPC__deref_out_opt ABI::Windows::Storage::Streams::IOutputStream** /*stream*/ + ) override { + return E_NOTIMPL; + } + + /* [propget] */ virtual HRESULT STDMETHODCALLTYPE get_Position( + /* [retval, out] */ __RPC__out UINT64* value + ) override { + *value = position_; + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE Seek( + /* [in] */ UINT64 position + ) override { + position_ = position; + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE CloneStream( + /* [retval, out] */ __RPC__deref_out_opt ABI::Windows::Storage::Streams::IRandomAccessStream** stream + ) override { + return Microsoft::WRL::MakeAndInitialize(stream, buffer_.Get(), 0); + } + + /* [propget] */ virtual HRESULT STDMETHODCALLTYPE get_CanRead( + /* [retval, out] */ __RPC__out::boolean* value + ) override { + UINT32 length; + buffer_->get_Length(&length); + *value = buffer_ != nullptr && position_ < static_cast(length); + return S_OK; + } + + /* [propget] */ virtual HRESULT STDMETHODCALLTYPE get_CanWrite( + /* [retval, out] */ __RPC__out::boolean* value + ) override { + *value = false; + return S_OK; + } + + // IInputStream + virtual HRESULT STDMETHODCALLTYPE ReadAsync( + /* [in] */ __RPC__in_opt ABI::Windows::Storage::Streams::IBuffer* buffer, + /* [in] */ UINT32 count, + /* [in] */ ABI::Windows::Storage::Streams::InputStreamOptions /*options*/, + /* [retval, out] */ + __RPC__deref_out_opt __FIAsyncOperationWithProgress_2_Windows__CStorage__CStreams__CIBuffer_UINT32** operation + ) override { + auto read_async = Microsoft::WRL::Make(); + read_async.CopyTo(operation); + + // perform the "async work" which is actually synchronous atm + Microsoft::WRL::ComPtr spBuffer = buffer; + Microsoft::WRL::ComPtr out_buffer_byte_access; + spBuffer.As(&out_buffer_byte_access); + byte* out_bytes = nullptr; + out_buffer_byte_access->Buffer(&out_bytes); + + Microsoft::WRL::ComPtr in_buffer_byte_access; + buffer_.As(&in_buffer_byte_access); + byte* in_bytes = nullptr; + in_buffer_byte_access->Buffer(&in_bytes); + + memcpy(out_bytes, in_bytes + static_cast(position_), count); + + read_async->SetBuffer(buffer); + + return S_OK; + } + + // IOutputStream + virtual HRESULT STDMETHODCALLTYPE WriteAsync( + /* [in] */ __RPC__in_opt ABI::Windows::Storage::Streams::IBuffer* /*buffer*/, + /* [retval, out] */ __RPC__deref_out_opt __FIAsyncOperationWithProgress_2_UINT32_UINT32** /*operation*/ + ) override { + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE FlushAsync( + /* [retval, out] */ __RPC__deref_out_opt __FIAsyncOperation_1_boolean** /*operation*/ + ) override { + return E_NOTIMPL; + } + + // IClosable + virtual HRESULT STDMETHODCALLTYPE Close(void) override { + buffer_ = nullptr; + return S_OK; + } }; struct BufferBackedRandomAccessStreamReferenceOpenReadAsync - : public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags, - __FIAsyncOperation_1_Windows__CStorage__CStreams__CIRandomAccessStreamWithContentType, - ABI::Windows::Foundation::IAsyncInfo> { - - InspectableClass(L"WinMLTest.BufferBackedRandomAccessStreamReferenceOpenReadAsync", BaseTrust) -public: - Microsoft::WRL::ComPtr ras_; - Microsoft::WRL::ComPtr> completed_handler_; - AsyncStatus status_ = AsyncStatus::Started; - - HRESULT SetRandomAccessStream(ABI::Windows::Storage::Streams::IRandomAccessStreamWithContentType* ras) { - ras_ = ras; - status_ = AsyncStatus::Completed; - if (ras_ != nullptr) { - if (completed_handler_ != nullptr) { - completed_handler_->Invoke(this, status_); - } - } - return S_OK; - } - - virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Id( - /* [retval][out] */ __RPC__out unsigned __int32* id) override { - *id = 0; // Do we need to implement this? - return S_OK; - } - - virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Status( - /* [retval][out] */ __RPC__out AsyncStatus* status) override { - *status = status_; - return S_OK; - } - - virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_ErrorCode( - /* [retval][out] */ __RPC__out HRESULT* /*errorCode*/) override { - return E_NOTIMPL; - } - - virtual HRESULT STDMETHODCALLTYPE Cancel(void) override { - return E_NOTIMPL; - } - - virtual HRESULT STDMETHODCALLTYPE Close(void) override { - return E_NOTIMPL; - } - - virtual HRESULT STDMETHODCALLTYPE put_Completed( - ABI::Windows::Foundation::IAsyncOperationCompletedHandler* handler) override - { - completed_handler_ = handler; - return S_OK; - } - - virtual HRESULT STDMETHODCALLTYPE get_Completed( - ABI::Windows::Foundation::IAsyncOperationCompletedHandler** handler) override { - completed_handler_.CopyTo(handler); - return S_OK; - } - - virtual HRESULT STDMETHODCALLTYPE GetResults( - ABI::Windows::Storage::Streams::IRandomAccessStreamWithContentType** results) override { - if (ras_ == nullptr) { - return E_FAIL; - } - ras_.CopyTo(results); - return S_OK; - } + : public Microsoft::WRL::RuntimeClass< + Microsoft::WRL::RuntimeClassFlags, + __FIAsyncOperation_1_Windows__CStorage__CStreams__CIRandomAccessStreamWithContentType, + ABI::Windows::Foundation::IAsyncInfo> { + InspectableClass(L"WinMLTest.BufferBackedRandomAccessStreamReferenceOpenReadAsync", BaseTrust) public + : Microsoft::WRL::ComPtr ras_; + Microsoft::WRL::ComPtr> + completed_handler_; + AsyncStatus status_ = AsyncStatus::Started; + + HRESULT SetRandomAccessStream(ABI::Windows::Storage::Streams::IRandomAccessStreamWithContentType* ras) { + ras_ = ras; + status_ = AsyncStatus::Completed; + if (ras_ != nullptr) { + if (completed_handler_ != nullptr) { + completed_handler_->Invoke(this, status_); + } + } + return S_OK; + } + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Id( + /* [retval][out] */ __RPC__out unsigned __int32* id + ) override { + *id = 0; // Do we need to implement this? + return S_OK; + } + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_Status( + /* [retval][out] */ __RPC__out AsyncStatus* status + ) override { + *status = status_; + return S_OK; + } + + virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_ErrorCode( + /* [retval][out] */ __RPC__out HRESULT* /*errorCode*/ + ) override { + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE Cancel(void) override { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE Close(void) override { return E_NOTIMPL; } + + virtual HRESULT STDMETHODCALLTYPE + put_Completed(ABI::Windows::Foundation::IAsyncOperationCompletedHandler< + ABI::Windows::Storage::Streams::IRandomAccessStreamWithContentType*>* handler) override { + completed_handler_ = handler; + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE + get_Completed(ABI::Windows::Foundation::IAsyncOperationCompletedHandler< + ABI::Windows::Storage::Streams::IRandomAccessStreamWithContentType*>** handler) override { + completed_handler_.CopyTo(handler); + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE + GetResults(ABI::Windows::Storage::Streams::IRandomAccessStreamWithContentType** results) override { + if (ras_ == nullptr) { + return E_FAIL; + } + ras_.CopyTo(results); + return S_OK; + } }; struct BufferBackedRandomAccessStreamReference - : public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags, - ABI::Windows::Storage::Streams::IRandomAccessStreamReference> { - InspectableClass(L"WinMLTest.BufferBackedRandomAccessStreamReference", BaseTrust) + : public Microsoft::WRL::RuntimeClass< + Microsoft::WRL::RuntimeClassFlags, + ABI::Windows::Storage::Streams::IRandomAccessStreamReference> { + InspectableClass(L"WinMLTest.BufferBackedRandomAccessStreamReference", BaseTrust) Microsoft::WRL::ComPtr buffer_ = nullptr; -public: - HRESULT RuntimeClassInitialize(ABI::Windows::Storage::Streams::IBuffer* buffer) { - buffer_ = buffer; - return S_OK; - } + public: + HRESULT RuntimeClassInitialize(ABI::Windows::Storage::Streams::IBuffer* buffer) { + buffer_ = buffer; + return S_OK; + } - virtual HRESULT STDMETHODCALLTYPE OpenReadAsync( - /* [retval, out] */__RPC__deref_out_opt __FIAsyncOperation_1_Windows__CStorage__CStreams__CIRandomAccessStreamWithContentType** operation - ) override { - auto open_read_async = Microsoft::WRL::Make(); - open_read_async.CopyTo(operation); + virtual HRESULT STDMETHODCALLTYPE OpenReadAsync( + /* [retval, out] */ __RPC__deref_out_opt + __FIAsyncOperation_1_Windows__CStorage__CStreams__CIRandomAccessStreamWithContentType** operation + ) override { + auto open_read_async = Microsoft::WRL::Make(); + open_read_async.CopyTo(operation); - Microsoft::WRL::ComPtr ras; - Microsoft::WRL::MakeAndInitialize(&ras, buffer_.Get()); + Microsoft::WRL::ComPtr ras; + Microsoft::WRL::MakeAndInitialize(&ras, buffer_.Get()); - Microsoft::WRL::ComPtr ras_interface = nullptr; - ras.As(&ras_interface); - - open_read_async.Get()->SetRandomAccessStream(ras_interface.Get()); - return S_OK; - } + Microsoft::WRL::ComPtr ras_interface = nullptr; + ras.As(&ras_interface); + open_read_async.Get()->SetRandomAccessStream(ras_interface.Get()); + return S_OK; + } }; -} // namespace WinMLTest +} // namespace WinMLTest -#endif // RANDOM_ACCESS_STREAM_H \ No newline at end of file +#endif // RANDOM_ACCESS_STREAM_H diff --git a/winml/test/api/raw/microsoft.ai.machinelearning.gpu.h b/winml/test/api/raw/microsoft.ai.machinelearning.gpu.h index ee8e008b25966..e5f111bbd220b 100644 --- a/winml/test/api/raw/microsoft.ai.machinelearning.gpu.h +++ b/winml/test/api/raw/microsoft.ai.machinelearning.gpu.h @@ -5,54 +5,53 @@ #include "microsoft.ai.machinelearning.h" -namespace Microsoft { namespace AI { namespace MachineLearning { namespace gpu { - -enum directx_device_kind { directx, directx_high_power, directx_min_power }; - -struct directx_device : public learning_model_device -{ - directx_device(directx_device_kind kind) : - learning_model_device(create_device(kind)) - {} - - directx_device(ABI::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice* d3dDevice) : - learning_model_device(create_device(d3dDevice)) - {} - - directx_device(ID3D12CommandQueue* queue) : - learning_model_device(create_device(queue)) - {} - -private: - static Details::learning_model_device create_device( - directx_device_kind kind) - { - switch (kind) - { - case directx_device_kind::directx: - return Details::learning_model_device::create_directx_device(); - case directx_device_kind::directx_high_power: - return Details::learning_model_device::create_directx_high_power_device(); - case directx_device_kind::directx_min_power: - return Details::learning_model_device::create_directx_min_power_device(); - }; - - return Details::learning_model_device(); - } - - static Details::learning_model_device create_device( - ABI::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice* d3dDevice) - { - return Details::learning_model_device::create_directx_device(d3dDevice); - } - - static Details::learning_model_device create_device( - ID3D12CommandQueue* queue) - { - return Details::learning_model_device::create_directx_device(queue); - } +namespace Microsoft { +namespace AI { +namespace MachineLearning { +namespace gpu { + +enum directx_device_kind { + directx, + directx_high_power, + directx_min_power }; -}}}} // namespace Microsoft::AI::MachineLearning::gpu +struct directx_device : public learning_model_device { + directx_device(directx_device_kind kind) : learning_model_device(create_device(kind)) {} + + directx_device(ABI::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice* d3dDevice) + : learning_model_device(create_device(d3dDevice)) {} + + directx_device(ID3D12CommandQueue* queue) : learning_model_device(create_device(queue)) {} + + private: + static Details::learning_model_device create_device(directx_device_kind kind) { + switch (kind) { + case directx_device_kind::directx: + return Details::learning_model_device::create_directx_device(); + case directx_device_kind::directx_high_power: + return Details::learning_model_device::create_directx_high_power_device(); + case directx_device_kind::directx_min_power: + return Details::learning_model_device::create_directx_min_power_device(); + }; + + return Details::learning_model_device(); + } + + static Details::learning_model_device create_device( + ABI::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice* d3dDevice + ) { + return Details::learning_model_device::create_directx_device(d3dDevice); + } + + static Details::learning_model_device create_device(ID3D12CommandQueue* queue) { + return Details::learning_model_device::create_directx_device(queue); + } +}; + +} // namespace gpu +} // namespace MachineLearning +} // namespace AI +} // namespace Microsoft -#endif // MICROSOFT_AI_MACHINELEARNING_GPU_H \ No newline at end of file +#endif // MICROSOFT_AI_MACHINELEARNING_GPU_H diff --git a/winml/test/api/raw/microsoft.ai.machinelearning.h b/winml/test/api/raw/microsoft.ai.machinelearning.h index 8df3f694b22ca..386cf6c1ab807 100644 --- a/winml/test/api/raw/microsoft.ai.machinelearning.h +++ b/winml/test/api/raw/microsoft.ai.machinelearning.h @@ -3,161 +3,151 @@ #ifndef MICROSOFT_AI_MACHINELEARNING_H_ #define MICROSOFT_AI_MACHINELEARNING_H_ -#define ML_FAIL_FAST_IF(condition) \ - do { \ - bool _cond = condition; \ - if (_cond) { \ - __fastfail(0); \ - } \ - } while(0) - -namespace Microsoft { namespace AI { namespace MachineLearning { - using tensor_shape_type = int64_t; -}}} // namespace Microsoft::AI::MachineLearning - +#define ML_FAIL_FAST_IF(condition) \ + do { \ + bool _cond = condition; \ + if (_cond) { \ + __fastfail(0); \ + } \ + } while (0) + +namespace Microsoft { +namespace AI { +namespace MachineLearning { +using tensor_shape_type = int64_t; +} +} // namespace AI +} // namespace Microsoft #include "winml_microsoft.h" -namespace Microsoft { namespace AI { namespace MachineLearning { namespace Details { - using learning_model = WinMLLearningModel; - using learning_model_device = WinMLLearningModelDevice; - using learning_model_session = WinMLLearningModelSession; - using learning_model_binding = WinMLLearningModelBinding; - using learning_model_results = WinMLLearningModelResults; -}}}} // namespace Microsoft::AI::MachineLearning::Details - -namespace Microsoft { namespace AI { namespace MachineLearning { - -struct learning_model -{ - friend struct learning_model_session; - - learning_model(const wchar_t* model_path, size_t size) : - m_model(model_path, size) - {} - - learning_model(const char* bytes, size_t size) : - m_model(bytes, size) - {} - -private: - Details::learning_model m_model; +namespace Microsoft { +namespace AI { +namespace MachineLearning { +namespace Details { +using learning_model = WinMLLearningModel; +using learning_model_device = WinMLLearningModelDevice; +using learning_model_session = WinMLLearningModelSession; +using learning_model_binding = WinMLLearningModelBinding; +using learning_model_results = WinMLLearningModelResults; +} // namespace Details +} // namespace MachineLearning +} // namespace AI +} // namespace Microsoft + +namespace Microsoft { +namespace AI { +namespace MachineLearning { + +struct learning_model { + friend struct learning_model_session; + + learning_model(const wchar_t* model_path, size_t size) : m_model(model_path, size) {} + + learning_model(const char* bytes, size_t size) : m_model(bytes, size) {} + + private: + Details::learning_model m_model; }; -struct learning_model_results -{ - friend struct learning_model_session; +struct learning_model_results { + friend struct learning_model_session; - int32_t get_output(const wchar_t* feature_name, size_t feature_name_size, void** pp_buffer, size_t* p_capacity) - { - return m_results.get_output(feature_name, feature_name_size, pp_buffer, p_capacity); - } + int32_t get_output(const wchar_t* feature_name, size_t feature_name_size, void** pp_buffer, size_t* p_capacity) { + return m_results.get_output(feature_name, feature_name_size, pp_buffer, p_capacity); + } -private: - learning_model_results(Details::learning_model_results results) : - m_results(results) {} + private: + learning_model_results(Details::learning_model_results results) : m_results(results) {} -private: - Details::learning_model_results m_results; + private: + Details::learning_model_results m_results; }; -struct learning_model_device -{ - friend struct learning_model_session; +struct learning_model_device { + friend struct learning_model_session; - learning_model_device() : m_device(){} + learning_model_device() : m_device() {} - learning_model_device(learning_model_device&& device) : - m_device(std::move(device.m_device)) - {} + learning_model_device(learning_model_device&& device) : m_device(std::move(device.m_device)) {} - learning_model_device(learning_model_device& device) : - m_device(device.m_device) - {} + learning_model_device(learning_model_device& device) : m_device(device.m_device) {} - void operator=(learning_model_device& device) - { - m_device = device.m_device; - } + void operator=(learning_model_device& device) { m_device = device.m_device; } -protected: - learning_model_device(Details::learning_model_device&& learning_model_device) : - m_device(std::move(learning_model_device)){} + protected: + learning_model_device(Details::learning_model_device&& learning_model_device) + : m_device(std::move(learning_model_device)) {} -private: - Details::learning_model_device m_device; + private: + Details::learning_model_device m_device; }; -struct learning_model_session -{ - friend struct learning_model_binding; - - learning_model_session(const learning_model& model) : - m_session(model.m_model) - {} +struct learning_model_session { + friend struct learning_model_binding; - learning_model_session(const learning_model& model, const learning_model_device& device) : - m_session(model.m_model, device.m_device) - {} + learning_model_session(const learning_model& model) : m_session(model.m_model) {} - inline learning_model_results evaluate(learning_model_binding& binding); + learning_model_session(const learning_model& model, const learning_model_device& device) + : m_session(model.m_model, device.m_device) {} -private: - Details::learning_model_session m_session; + inline learning_model_results evaluate(learning_model_binding& binding); + private: + Details::learning_model_session m_session; }; -struct learning_model_binding -{ - friend struct learning_model_session; - - learning_model_binding(const learning_model_session& session) : - m_binding(session.m_session) - {} - - template - int32_t bind_as_reference( - const wchar_t* feature_name, size_t feature_name_size, - tensor_shape_type* p_shape, size_t shape_size, - T* p_data, size_t data_size) - { - return m_binding.bind_as_reference(feature_name, feature_name_size, p_shape, shape_size, p_data, data_size); - } - - template - int32_t bind_as_references( - const wchar_t* feature_name, size_t feature_name_size, - T** p_data, size_t* data_sizes, - size_t num_buffers) { - return m_binding.bind_as_references(feature_name, feature_name_size, p_data, data_sizes, num_buffers); - } - - template - int32_t bind( - const wchar_t* feature_name, size_t feature_name_size, - tensor_shape_type* p_shape, size_t shape_size, - T* p_data, size_t data_size) - { - return m_binding.bind(feature_name, feature_name_size, p_shape, shape_size, p_data, data_size); - } - - template - int32_t bind( - const wchar_t* feature_name, size_t feature_name_size, - tensor_shape_type* p_shape, size_t shape_size) - { - return m_binding.bind(feature_name, feature_name_size, p_shape, shape_size); - } - -private: - Details::learning_model_binding m_binding; +struct learning_model_binding { + friend struct learning_model_session; + + learning_model_binding(const learning_model_session& session) : m_binding(session.m_session) {} + + template + int32_t bind_as_reference( + const wchar_t* feature_name, + size_t feature_name_size, + tensor_shape_type* p_shape, + size_t shape_size, + T* p_data, + size_t data_size + ) { + return m_binding.bind_as_reference(feature_name, feature_name_size, p_shape, shape_size, p_data, data_size); + } + + template + int32_t bind_as_references( + const wchar_t* feature_name, size_t feature_name_size, T** p_data, size_t* data_sizes, size_t num_buffers + ) { + return m_binding.bind_as_references(feature_name, feature_name_size, p_data, data_sizes, num_buffers); + } + + template + int32_t bind( + const wchar_t* feature_name, + size_t feature_name_size, + tensor_shape_type* p_shape, + size_t shape_size, + T* p_data, + size_t data_size + ) { + return m_binding.bind(feature_name, feature_name_size, p_shape, shape_size, p_data, data_size); + } + + template + int32_t bind(const wchar_t* feature_name, size_t feature_name_size, tensor_shape_type* p_shape, size_t shape_size) { + return m_binding.bind(feature_name, feature_name_size, p_shape, shape_size); + } + + private: + Details::learning_model_binding m_binding; }; -learning_model_results learning_model_session::evaluate(learning_model_binding& binding) -{ - return Details::learning_model_results(m_session.evaluate(binding.m_binding)); +learning_model_results learning_model_session::evaluate(learning_model_binding& binding) { + return Details::learning_model_results(m_session.evaluate(binding.m_binding)); } -}}} // namespace Microsoft::AI::MachineLearning::Details +} // namespace MachineLearning +} // namespace AI +} // namespace Microsoft -#endif // MICROSOFT_AI_MACHINELEARNING_H_ \ No newline at end of file +#endif // MICROSOFT_AI_MACHINELEARNING_H_ diff --git a/winml/test/api/raw/weak_buffer.h b/winml/test/api/raw/weak_buffer.h index a175273c4ec61..488ba0639cc18 100644 --- a/winml/test/api/raw/weak_buffer.h +++ b/winml/test/api/raw/weak_buffer.h @@ -14,62 +14,52 @@ namespace WinMLTest { template struct WeakBuffer - : public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags, - ABI::Windows::Storage::Streams::IBuffer, - Windows::Storage::Streams::IBufferByteAccess> { + : public Microsoft::WRL::RuntimeClass< + Microsoft::WRL::RuntimeClassFlags, + ABI::Windows::Storage::Streams::IBuffer, + Windows::Storage::Streams::IBufferByteAccess> { InspectableClass(L"WinMLTest.WeakBuffer", BaseTrust) -private: - const T* m_p_begin; - const T* m_p_end; + private : const T* m_p_begin; + const T* m_p_end; -public: - HRESULT RuntimeClassInitialize(_In_ const T* p_begin, _In_ const T* p_end) { - m_p_begin = p_begin; - m_p_end = p_end; + public: + HRESULT RuntimeClassInitialize(_In_ const T* p_begin, _In_ const T* p_end) { + m_p_begin = p_begin; + m_p_end = p_end; - return S_OK; - } - - virtual HRESULT STDMETHODCALLTYPE get_Capacity( - UINT32 * value) - { - if (value == nullptr) { - return E_POINTER; - } + return S_OK; + } - *value = static_cast(m_p_end - m_p_begin) * sizeof(T); - return S_OK; + virtual HRESULT STDMETHODCALLTYPE get_Capacity(UINT32* value) { + if (value == nullptr) { + return E_POINTER; } - virtual HRESULT STDMETHODCALLTYPE get_Length( - UINT32 * value) - { - if (value == nullptr) { - return E_POINTER; - } - *value = static_cast(m_p_end - m_p_begin) * sizeof(T); - return S_OK; - } + *value = static_cast(m_p_end - m_p_begin) * sizeof(T); + return S_OK; + } - virtual HRESULT STDMETHODCALLTYPE put_Length( - UINT32 /*value*/) - { - return E_NOTIMPL; + virtual HRESULT STDMETHODCALLTYPE get_Length(UINT32* value) { + if (value == nullptr) { + return E_POINTER; } + *value = static_cast(m_p_end - m_p_begin) * sizeof(T); + return S_OK; + } - STDMETHOD(Buffer)(uint8_t** value) - { - if (value == nullptr) { - return E_POINTER; - } + virtual HRESULT STDMETHODCALLTYPE put_Length(UINT32 /*value*/) { return E_NOTIMPL; } - *value = reinterpret_cast(const_cast(m_p_begin)); - return S_OK; + STDMETHOD(Buffer)(uint8_t** value) { + if (value == nullptr) { + return E_POINTER; } + + *value = reinterpret_cast(const_cast(m_p_begin)); + return S_OK; + } }; -} // namespace WinMLTest +} // namespace WinMLTest -#endif // WEAK_BUFFER_H +#endif // WEAK_BUFFER_H diff --git a/winml/test/api/raw/weak_single_threaded_iterable.h b/winml/test/api/raw/weak_single_threaded_iterable.h index 464e75f088bff..77579920a4af9 100644 --- a/winml/test/api/raw/weak_single_threaded_iterable.h +++ b/winml/test/api/raw/weak_single_threaded_iterable.h @@ -7,115 +7,111 @@ #include #include - -namespace Microsoft { namespace AI { namespace MachineLearning { namespace Details { +namespace Microsoft { +namespace AI { +namespace MachineLearning { +namespace Details { template struct weak_single_threaded_iterable - : public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags, - ABI::Windows::Foundation::Collections::IIterable> { -private: - const T* m_p_begin; - const T* m_p_end; - -public: - HRESULT RuntimeClassInitialize(_In_ const T* p_begin, _In_ const T* p_end) { - m_p_begin = p_begin; - m_p_end = p_end; - - return S_OK; + : public Microsoft::WRL::RuntimeClass< + Microsoft::WRL::RuntimeClassFlags, + ABI::Windows::Foundation::Collections::IIterable> { + private: + const T* m_p_begin; + const T* m_p_end; + + public: + HRESULT RuntimeClassInitialize(_In_ const T* p_begin, _In_ const T* p_end) { + m_p_begin = p_begin; + m_p_end = p_end; + + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE + First(_Outptr_result_maybenull_ ABI::Windows::Foundation::Collections::IIterator** first) { + if (first == nullptr) { + return E_POINTER; } - virtual HRESULT STDMETHODCALLTYPE First( - _Outptr_result_maybenull_ - ABI::Windows::Foundation::Collections::IIterator** first) { - if (first == nullptr) { - return E_POINTER; - } + Microsoft::WRL::ComPtr iterator; + auto hr = Microsoft::WRL::MakeAndInitialize(&iterator, this); - Microsoft::WRL::ComPtr iterator; - auto hr = Microsoft::WRL::MakeAndInitialize( - &iterator, this); + if (FAILED(hr)) { + return hr; + } - if (FAILED(hr)) { - return hr; - } + return iterator.CopyTo(first); + } - return iterator.CopyTo(first); + HRESULT Size(unsigned* p_size) { + if (p_size == nullptr) { + return E_POINTER; } - HRESULT Size(unsigned* p_size) { - if (p_size == nullptr) { - return E_POINTER; - } + *p_size = static_cast(m_p_end - m_p_begin); + return S_OK; + } - *p_size = static_cast(m_p_end - m_p_begin); - return S_OK; + HRESULT At(unsigned index, _Out_ T* p_current) { + if (p_current == nullptr) { + return E_POINTER; } - HRESULT At(unsigned index, _Out_ T* p_current) { - if (p_current == nullptr) { - return E_POINTER; - } + *p_current = *(m_p_begin + index); + return S_OK; + } - *p_current = *(m_p_begin + index); - return S_OK; + HRESULT Has(unsigned index, _Out_ boolean* p_has_current) { + if (p_has_current == nullptr) { + return E_POINTER; } + unsigned size; + auto hr = Size(&size); + if (FAILED(hr)) { + return hr; + } + + *p_has_current = index < size; + return S_OK; + } - HRESULT Has(unsigned index, _Out_ boolean* p_has_current) { - if (p_has_current == nullptr) { - return E_POINTER; - } - unsigned size; - auto hr = Size(&size); - if (FAILED(hr)) - { - return hr; - } - - *p_has_current = index < size; - return S_OK; + struct weak_single_threaded_iterator + : public Microsoft::WRL::RuntimeClass< + Microsoft::WRL::RuntimeClassFlags, + ABI::Windows::Foundation::Collections::IIterator> { + private: + Microsoft::WRL::ComPtr m_weak_single_threaded_iterable; + unsigned m_current = 0; + + public: + HRESULT RuntimeClassInitialize(_In_ weak_single_threaded_iterable* p_weak_single_threaded_iterable) { + m_weak_single_threaded_iterable = p_weak_single_threaded_iterable; + return S_OK; } - struct weak_single_threaded_iterator - : public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags, - ABI::Windows::Foundation::Collections::IIterator> { - private: - Microsoft::WRL::ComPtr - m_weak_single_threaded_iterable; - unsigned m_current = 0; - - public: - HRESULT RuntimeClassInitialize( - _In_ weak_single_threaded_iterable* p_weak_single_threaded_iterable) { - m_weak_single_threaded_iterable = p_weak_single_threaded_iterable; - return S_OK; - } - - virtual /* propget */ HRESULT STDMETHODCALLTYPE - get_Current(_Out_ T* current) { - return m_weak_single_threaded_iterable->At(m_current, current); - } - - virtual /* propget */ HRESULT STDMETHODCALLTYPE - get_HasCurrent(_Out_ boolean* hasCurrent) { - return m_weak_single_threaded_iterable->Has(m_current, hasCurrent); - } - - virtual HRESULT STDMETHODCALLTYPE MoveNext(_Out_ boolean* hasCurrent) { - if (SUCCEEDED( - m_weak_single_threaded_iterable->Has(m_current, hasCurrent)) && - *hasCurrent) { - m_current++; - return m_weak_single_threaded_iterable->Has(m_current, hasCurrent); - } - return S_OK; - } - }; + virtual /* propget */ HRESULT STDMETHODCALLTYPE get_Current(_Out_ T* current) { + return m_weak_single_threaded_iterable->At(m_current, current); + } + + virtual /* propget */ HRESULT STDMETHODCALLTYPE get_HasCurrent(_Out_ boolean* hasCurrent) { + return m_weak_single_threaded_iterable->Has(m_current, hasCurrent); + } + + virtual HRESULT STDMETHODCALLTYPE MoveNext(_Out_ boolean* hasCurrent) { + if (SUCCEEDED(m_weak_single_threaded_iterable->Has(m_current, hasCurrent)) && *hasCurrent) { + m_current++; + return m_weak_single_threaded_iterable->Has(m_current, hasCurrent); + } + return S_OK; + } + }; }; -}}}} // namespace Microsoft::AI::MachineLearning::Details +} // namespace Details +} // namespace MachineLearning +} // namespace AI +} // namespace Microsoft -#endif // WEAK_SINGLE_THREADED_ITERABLE_H_ +#endif // WEAK_SINGLE_THREADED_ITERABLE_H_ diff --git a/winml/test/api/raw/winml_microsoft.h b/winml/test/api/raw/winml_microsoft.h index a247303ca7a67..92094188793d5 100644 --- a/winml/test/api/raw/winml_microsoft.h +++ b/winml/test/api/raw/winml_microsoft.h @@ -7,31 +7,30 @@ #include "buffer_backed_random_access_stream_reference.h" #include "weak_single_threaded_iterable.h" -#define RETURN_HR_IF_FAILED(expression) \ - do { \ - auto _hr = expression; \ - if (FAILED(_hr)) \ - { \ - return static_cast(_hr); \ - } \ - } while (0) - - -#define FAIL_FAST_IF_HR_FAILED(expression) \ - do { \ - auto _hr = expression; \ - if (FAILED(_hr)) \ - { \ - __fastfail(static_cast(_hr)); \ - } \ - } while (0) - +#define RETURN_HR_IF_FAILED(expression) \ + do { \ + auto _hr = expression; \ + if (FAILED(_hr)) { \ + return static_cast(_hr); \ + } \ + } while (0) + +#define FAIL_FAST_IF_HR_FAILED(expression) \ + do { \ + auto _hr = expression; \ + if (FAILED(_hr)) { \ + __fastfail(static_cast(_hr)); \ + } \ + } while (0) struct float16 { - uint16_t value; + uint16_t value; }; -namespace Microsoft { namespace AI { namespace MachineLearning { namespace Details { +namespace Microsoft { +namespace AI { +namespace MachineLearning { +namespace Details { class WinMLLearningModel; class WinMLLearningModelBinding; @@ -40,703 +39,896 @@ class WinMLLearningModelResults; extern const __declspec(selectany) _Null_terminated_ wchar_t MachineLearningDll[] = L"microsoft.ai.machinelearning.dll"; -template struct Tensor { }; -template <> struct Tensor { using Type = ABI::Microsoft::AI::MachineLearning::ITensorFloat; }; -template <> struct Tensor { using Type = ABI::Microsoft::AI::MachineLearning::ITensorFloat16Bit;}; -template <> struct Tensor { using Type = ABI::Microsoft::AI::MachineLearning::ITensorInt8Bit; }; -template <> struct Tensor { using Type = ABI::Microsoft::AI::MachineLearning::ITensorUInt8Bit; }; -template <> struct Tensor { using Type = ABI::Microsoft::AI::MachineLearning::ITensorUInt16Bit; }; -template <> struct Tensor { using Type = ABI::Microsoft::AI::MachineLearning::ITensorInt16Bit; }; -template <> struct Tensor { using Type = ABI::Microsoft::AI::MachineLearning::ITensorUInt32Bit; }; -template <> struct Tensor { using Type = ABI::Microsoft::AI::MachineLearning::ITensorInt32Bit; }; -template <> struct Tensor { using Type = ABI::Microsoft::AI::MachineLearning::ITensorUInt64Bit; }; -template <> struct Tensor { using Type = ABI::Microsoft::AI::MachineLearning::ITensorInt64Bit; }; -template <> struct Tensor { using Type = ABI::Microsoft::AI::MachineLearning::ITensorBoolean; }; -template <> struct Tensor { using Type = ABI::Microsoft::AI::MachineLearning::ITensorDouble; }; - -template struct TensorRuntimeClassID { }; -template <> struct TensorRuntimeClassID { static const wchar_t* RuntimeClass_ID; }; -template <> struct TensorRuntimeClassID { static const wchar_t* RuntimeClass_ID; }; -template <> struct TensorRuntimeClassID { static const wchar_t* RuntimeClass_ID; }; -template <> struct TensorRuntimeClassID { static const wchar_t* RuntimeClass_ID; }; -template <> struct TensorRuntimeClassID { static const wchar_t* RuntimeClass_ID; }; -template <> struct TensorRuntimeClassID { static const wchar_t* RuntimeClass_ID; }; -template <> struct TensorRuntimeClassID { static const wchar_t* RuntimeClass_ID; }; -template <> struct TensorRuntimeClassID { static const wchar_t* RuntimeClass_ID; }; -template <> struct TensorRuntimeClassID { static const wchar_t* RuntimeClass_ID; }; -template <> struct TensorRuntimeClassID { static const wchar_t* RuntimeClass_ID; }; -template <> struct TensorRuntimeClassID { static const wchar_t* RuntimeClass_ID; }; -template <> struct TensorRuntimeClassID { static const wchar_t* RuntimeClass_ID; }; - -__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Microsoft_AI_MachineLearning_TensorFloat; -__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Microsoft_AI_MachineLearning_TensorFloat16Bit; -__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Microsoft_AI_MachineLearning_TensorInt8Bit; -__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Microsoft_AI_MachineLearning_TensorUInt8Bit; -__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Microsoft_AI_MachineLearning_TensorUInt16Bit; -__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Microsoft_AI_MachineLearning_TensorInt16Bit; -__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Microsoft_AI_MachineLearning_TensorUInt32Bit; -__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Microsoft_AI_MachineLearning_TensorInt32Bit; -__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Microsoft_AI_MachineLearning_TensorUInt64Bit; -__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Microsoft_AI_MachineLearning_TensorInt64Bit; -__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Microsoft_AI_MachineLearning_TensorBoolean; -__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Microsoft_AI_MachineLearning_TensorDouble; - -template struct TensorFactory { }; -template <> struct TensorFactory { using Factory = ABI::Microsoft::AI::MachineLearning::ITensorFloatStatics; }; -template <> struct TensorFactory { using Factory = ABI::Microsoft::AI::MachineLearning::ITensorFloat16BitStatics;}; -template <> struct TensorFactory { using Factory = ABI::Microsoft::AI::MachineLearning::ITensorInt8BitStatics; }; -template <> struct TensorFactory { using Factory = ABI::Microsoft::AI::MachineLearning::ITensorUInt8BitStatics; }; -template <> struct TensorFactory { using Factory = ABI::Microsoft::AI::MachineLearning::ITensorUInt16BitStatics; }; -template <> struct TensorFactory { using Factory = ABI::Microsoft::AI::MachineLearning::ITensorInt16BitStatics; }; -template <> struct TensorFactory { using Factory = ABI::Microsoft::AI::MachineLearning::ITensorUInt32BitStatics; }; -template <> struct TensorFactory { using Factory = ABI::Microsoft::AI::MachineLearning::ITensorInt32BitStatics; }; -template <> struct TensorFactory { using Factory = ABI::Microsoft::AI::MachineLearning::ITensorUInt64BitStatics; }; -template <> struct TensorFactory { using Factory = ABI::Microsoft::AI::MachineLearning::ITensorInt64BitStatics; }; -template <> struct TensorFactory { using Factory = ABI::Microsoft::AI::MachineLearning::ITensorBooleanStatics; }; -template <> struct TensorFactory { using Factory = ABI::Microsoft::AI::MachineLearning::ITensorDoubleStatics; }; - - -template struct TensorFactory2 { }; -template <> struct TensorFactory2 { using Factory = ABI::Microsoft::AI::MachineLearning::ITensorFloatStatics2; }; -template <> struct TensorFactory2 { using Factory = ABI::Microsoft::AI::MachineLearning::ITensorFloat16BitStatics2; }; -template <> struct TensorFactory2 { using Factory = ABI::Microsoft::AI::MachineLearning::ITensorInt8BitStatics2; }; -template <> struct TensorFactory2 { using Factory = ABI::Microsoft::AI::MachineLearning::ITensorUInt8BitStatics2; }; -template <> struct TensorFactory2 { using Factory = ABI::Microsoft::AI::MachineLearning::ITensorUInt16BitStatics2; }; -template <> struct TensorFactory2 { using Factory = ABI::Microsoft::AI::MachineLearning::ITensorInt16BitStatics2; }; -template <> struct TensorFactory2 { using Factory = ABI::Microsoft::AI::MachineLearning::ITensorUInt32BitStatics2; }; -template <> struct TensorFactory2 { using Factory = ABI::Microsoft::AI::MachineLearning::ITensorInt32BitStatics2; }; -template <> struct TensorFactory2 { using Factory = ABI::Microsoft::AI::MachineLearning::ITensorUInt64BitStatics2; }; -template <> struct TensorFactory2 { using Factory = ABI::Microsoft::AI::MachineLearning::ITensorInt64BitStatics2; }; -template <> struct TensorFactory2 { using Factory = ABI::Microsoft::AI::MachineLearning::ITensorBooleanStatics2; }; -template <> struct TensorFactory2 { using Factory = ABI::Microsoft::AI::MachineLearning::ITensorDoubleStatics2; }; - - - -template struct TensorFactoryIID { }; -template <> struct TensorFactoryIID { static const GUID IID; }; -template <> struct TensorFactoryIID { static const GUID IID; }; -template <> struct TensorFactoryIID { static const GUID IID; }; -template <> struct TensorFactoryIID { static const GUID IID; }; -template <> struct TensorFactoryIID { static const GUID IID; }; -template <> struct TensorFactoryIID { static const GUID IID; }; -template <> struct TensorFactoryIID { static const GUID IID; }; -template <> struct TensorFactoryIID { static const GUID IID; }; -template <> struct TensorFactoryIID { static const GUID IID; }; -template <> struct TensorFactoryIID { static const GUID IID; }; -template <> struct TensorFactoryIID { static const GUID IID; }; -template <> struct TensorFactoryIID { static const GUID IID; }; - -__declspec(selectany) const GUID TensorFactoryIID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorFloatStatics; -__declspec(selectany) const GUID TensorFactoryIID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorFloat16BitStatics; -__declspec(selectany) const GUID TensorFactoryIID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorInt8BitStatics; -__declspec(selectany) const GUID TensorFactoryIID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorUInt8BitStatics; -__declspec(selectany) const GUID TensorFactoryIID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorUInt16BitStatics; -__declspec(selectany) const GUID TensorFactoryIID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorInt16BitStatics; -__declspec(selectany) const GUID TensorFactoryIID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorUInt32BitStatics; -__declspec(selectany) const GUID TensorFactoryIID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorInt32BitStatics; -__declspec(selectany) const GUID TensorFactoryIID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorUInt64BitStatics; -__declspec(selectany) const GUID TensorFactoryIID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorInt64BitStatics; -__declspec(selectany) const GUID TensorFactoryIID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorBooleanStatics; -__declspec(selectany) const GUID TensorFactoryIID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorDoubleStatics; - -template struct TensorFactory2IID { }; -template <> struct TensorFactory2IID { static const GUID IID; }; -template <> struct TensorFactory2IID { static const GUID IID; }; -template <> struct TensorFactory2IID { static const GUID IID; }; -template <> struct TensorFactory2IID { static const GUID IID; }; -template <> struct TensorFactory2IID { static const GUID IID; }; -template <> struct TensorFactory2IID { static const GUID IID; }; -template <> struct TensorFactory2IID { static const GUID IID; }; -template <> struct TensorFactory2IID { static const GUID IID; }; -template <> struct TensorFactory2IID { static const GUID IID; }; -template <> struct TensorFactory2IID { static const GUID IID; }; -template <> struct TensorFactory2IID { static const GUID IID; }; -template <> struct TensorFactory2IID { static const GUID IID; }; - -__declspec(selectany) const GUID TensorFactory2IID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorFloatStatics2; -__declspec(selectany) const GUID TensorFactory2IID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorFloat16BitStatics2; -__declspec(selectany) const GUID TensorFactory2IID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorInt8BitStatics2; -__declspec(selectany) const GUID TensorFactory2IID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorUInt8BitStatics2; -__declspec(selectany) const GUID TensorFactory2IID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorUInt16BitStatics2; -__declspec(selectany) const GUID TensorFactory2IID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorInt16BitStatics2; -__declspec(selectany) const GUID TensorFactory2IID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorUInt32BitStatics2; -__declspec(selectany) const GUID TensorFactory2IID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorInt32BitStatics2; -__declspec(selectany) const GUID TensorFactory2IID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorUInt64BitStatics2; -__declspec(selectany) const GUID TensorFactory2IID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorInt64BitStatics2; -__declspec(selectany) const GUID TensorFactory2IID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorBooleanStatics2; -__declspec(selectany) const GUID TensorFactory2IID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorDoubleStatics2; - - -inline HRESULT GetActivationFactory( - const wchar_t* p_class_id, - const IID& iid, - void** factory) noexcept -{ - // Fallback to OS binary if the redistributable is not present! - auto library = LoadLibraryExW(MachineLearningDll, nullptr, 0); - if (library == nullptr) - { - return HRESULT_FROM_WIN32(GetLastError()); - } +template +struct Tensor {}; +template <> +struct Tensor { + using Type = ABI::Microsoft::AI::MachineLearning::ITensorFloat; +}; +template <> +struct Tensor { + using Type = ABI::Microsoft::AI::MachineLearning::ITensorFloat16Bit; +}; +template <> +struct Tensor { + using Type = ABI::Microsoft::AI::MachineLearning::ITensorInt8Bit; +}; +template <> +struct Tensor { + using Type = ABI::Microsoft::AI::MachineLearning::ITensorUInt8Bit; +}; +template <> +struct Tensor { + using Type = ABI::Microsoft::AI::MachineLearning::ITensorUInt16Bit; +}; +template <> +struct Tensor { + using Type = ABI::Microsoft::AI::MachineLearning::ITensorInt16Bit; +}; +template <> +struct Tensor { + using Type = ABI::Microsoft::AI::MachineLearning::ITensorUInt32Bit; +}; +template <> +struct Tensor { + using Type = ABI::Microsoft::AI::MachineLearning::ITensorInt32Bit; +}; +template <> +struct Tensor { + using Type = ABI::Microsoft::AI::MachineLearning::ITensorUInt64Bit; +}; +template <> +struct Tensor { + using Type = ABI::Microsoft::AI::MachineLearning::ITensorInt64Bit; +}; +template <> +struct Tensor { + using Type = ABI::Microsoft::AI::MachineLearning::ITensorBoolean; +}; +template <> +struct Tensor { + using Type = ABI::Microsoft::AI::MachineLearning::ITensorDouble; +}; - using DllGetActivationFactory = HRESULT __stdcall(HSTRING, void** factory); - auto call = reinterpret_cast(GetProcAddress(library, "DllGetActivationFactory")); - if (!call) - { - auto hr = HRESULT_FROM_WIN32(GetLastError()); - FreeLibrary(library); - return hr; - } +template +struct TensorRuntimeClassID {}; +template <> +struct TensorRuntimeClassID { + static const wchar_t* RuntimeClass_ID; +}; +template <> +struct TensorRuntimeClassID { + static const wchar_t* RuntimeClass_ID; +}; +template <> +struct TensorRuntimeClassID { + static const wchar_t* RuntimeClass_ID; +}; +template <> +struct TensorRuntimeClassID { + static const wchar_t* RuntimeClass_ID; +}; +template <> +struct TensorRuntimeClassID { + static const wchar_t* RuntimeClass_ID; +}; +template <> +struct TensorRuntimeClassID { + static const wchar_t* RuntimeClass_ID; +}; +template <> +struct TensorRuntimeClassID { + static const wchar_t* RuntimeClass_ID; +}; +template <> +struct TensorRuntimeClassID { + static const wchar_t* RuntimeClass_ID; +}; +template <> +struct TensorRuntimeClassID { + static const wchar_t* RuntimeClass_ID; +}; +template <> +struct TensorRuntimeClassID { + static const wchar_t* RuntimeClass_ID; +}; +template <> +struct TensorRuntimeClassID { + static const wchar_t* RuntimeClass_ID; +}; +template <> +struct TensorRuntimeClassID { + static const wchar_t* RuntimeClass_ID; +}; + +__declspec(selectany +) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Microsoft_AI_MachineLearning_TensorFloat; +__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = + RuntimeClass_Microsoft_AI_MachineLearning_TensorFloat16Bit; +__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = + RuntimeClass_Microsoft_AI_MachineLearning_TensorInt8Bit; +__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = + RuntimeClass_Microsoft_AI_MachineLearning_TensorUInt8Bit; +__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = + RuntimeClass_Microsoft_AI_MachineLearning_TensorUInt16Bit; +__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = + RuntimeClass_Microsoft_AI_MachineLearning_TensorInt16Bit; +__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = + RuntimeClass_Microsoft_AI_MachineLearning_TensorUInt32Bit; +__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = + RuntimeClass_Microsoft_AI_MachineLearning_TensorInt32Bit; +__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = + RuntimeClass_Microsoft_AI_MachineLearning_TensorUInt64Bit; +__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = + RuntimeClass_Microsoft_AI_MachineLearning_TensorInt64Bit; +__declspec(selectany +) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Microsoft_AI_MachineLearning_TensorBoolean; +__declspec(selectany +) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Microsoft_AI_MachineLearning_TensorDouble; + +template +struct TensorFactory {}; +template <> +struct TensorFactory { + using Factory = ABI::Microsoft::AI::MachineLearning::ITensorFloatStatics; +}; +template <> +struct TensorFactory { + using Factory = ABI::Microsoft::AI::MachineLearning::ITensorFloat16BitStatics; +}; +template <> +struct TensorFactory { + using Factory = ABI::Microsoft::AI::MachineLearning::ITensorInt8BitStatics; +}; +template <> +struct TensorFactory { + using Factory = ABI::Microsoft::AI::MachineLearning::ITensorUInt8BitStatics; +}; +template <> +struct TensorFactory { + using Factory = ABI::Microsoft::AI::MachineLearning::ITensorUInt16BitStatics; +}; +template <> +struct TensorFactory { + using Factory = ABI::Microsoft::AI::MachineLearning::ITensorInt16BitStatics; +}; +template <> +struct TensorFactory { + using Factory = ABI::Microsoft::AI::MachineLearning::ITensorUInt32BitStatics; +}; +template <> +struct TensorFactory { + using Factory = ABI::Microsoft::AI::MachineLearning::ITensorInt32BitStatics; +}; +template <> +struct TensorFactory { + using Factory = ABI::Microsoft::AI::MachineLearning::ITensorUInt64BitStatics; +}; +template <> +struct TensorFactory { + using Factory = ABI::Microsoft::AI::MachineLearning::ITensorInt64BitStatics; +}; +template <> +struct TensorFactory { + using Factory = ABI::Microsoft::AI::MachineLearning::ITensorBooleanStatics; +}; +template <> +struct TensorFactory { + using Factory = ABI::Microsoft::AI::MachineLearning::ITensorDoubleStatics; +}; + +template +struct TensorFactory2 {}; +template <> +struct TensorFactory2 { + using Factory = ABI::Microsoft::AI::MachineLearning::ITensorFloatStatics2; +}; +template <> +struct TensorFactory2 { + using Factory = ABI::Microsoft::AI::MachineLearning::ITensorFloat16BitStatics2; +}; +template <> +struct TensorFactory2 { + using Factory = ABI::Microsoft::AI::MachineLearning::ITensorInt8BitStatics2; +}; +template <> +struct TensorFactory2 { + using Factory = ABI::Microsoft::AI::MachineLearning::ITensorUInt8BitStatics2; +}; +template <> +struct TensorFactory2 { + using Factory = ABI::Microsoft::AI::MachineLearning::ITensorUInt16BitStatics2; +}; +template <> +struct TensorFactory2 { + using Factory = ABI::Microsoft::AI::MachineLearning::ITensorInt16BitStatics2; +}; +template <> +struct TensorFactory2 { + using Factory = ABI::Microsoft::AI::MachineLearning::ITensorUInt32BitStatics2; +}; +template <> +struct TensorFactory2 { + using Factory = ABI::Microsoft::AI::MachineLearning::ITensorInt32BitStatics2; +}; +template <> +struct TensorFactory2 { + using Factory = ABI::Microsoft::AI::MachineLearning::ITensorUInt64BitStatics2; +}; +template <> +struct TensorFactory2 { + using Factory = ABI::Microsoft::AI::MachineLearning::ITensorInt64BitStatics2; +}; +template <> +struct TensorFactory2 { + using Factory = ABI::Microsoft::AI::MachineLearning::ITensorBooleanStatics2; +}; +template <> +struct TensorFactory2 { + using Factory = ABI::Microsoft::AI::MachineLearning::ITensorDoubleStatics2; +}; - Microsoft::WRL::ComPtr activation_factory; - auto hr = call( - Microsoft::WRL::Wrappers::HStringReference(p_class_id, static_cast(wcslen(p_class_id))).Get(), - reinterpret_cast(activation_factory.GetAddressOf())); +template +struct TensorFactoryIID {}; +template <> +struct TensorFactoryIID { + static const GUID IID; +}; +template <> +struct TensorFactoryIID { + static const GUID IID; +}; +template <> +struct TensorFactoryIID { + static const GUID IID; +}; +template <> +struct TensorFactoryIID { + static const GUID IID; +}; +template <> +struct TensorFactoryIID { + static const GUID IID; +}; +template <> +struct TensorFactoryIID { + static const GUID IID; +}; +template <> +struct TensorFactoryIID { + static const GUID IID; +}; +template <> +struct TensorFactoryIID { + static const GUID IID; +}; +template <> +struct TensorFactoryIID { + static const GUID IID; +}; +template <> +struct TensorFactoryIID { + static const GUID IID; +}; +template <> +struct TensorFactoryIID { + static const GUID IID; +}; +template <> +struct TensorFactoryIID { + static const GUID IID; +}; - if (FAILED(hr)) - { - FreeLibrary(library); - return hr; - } +__declspec(selectany +) const GUID TensorFactoryIID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorFloatStatics; +__declspec(selectany +) const GUID TensorFactoryIID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorFloat16BitStatics; +__declspec(selectany +) const GUID TensorFactoryIID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorInt8BitStatics; +__declspec(selectany +) const GUID TensorFactoryIID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorUInt8BitStatics; +__declspec(selectany +) const GUID TensorFactoryIID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorUInt16BitStatics; +__declspec(selectany +) const GUID TensorFactoryIID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorInt16BitStatics; +__declspec(selectany +) const GUID TensorFactoryIID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorUInt32BitStatics; +__declspec(selectany +) const GUID TensorFactoryIID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorInt32BitStatics; +__declspec(selectany +) const GUID TensorFactoryIID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorUInt64BitStatics; +__declspec(selectany +) const GUID TensorFactoryIID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorInt64BitStatics; +__declspec(selectany +) const GUID TensorFactoryIID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorBooleanStatics; +__declspec(selectany +) const GUID TensorFactoryIID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorDoubleStatics; + +template +struct TensorFactory2IID {}; +template <> +struct TensorFactory2IID { + static const GUID IID; +}; +template <> +struct TensorFactory2IID { + static const GUID IID; +}; +template <> +struct TensorFactory2IID { + static const GUID IID; +}; +template <> +struct TensorFactory2IID { + static const GUID IID; +}; +template <> +struct TensorFactory2IID { + static const GUID IID; +}; +template <> +struct TensorFactory2IID { + static const GUID IID; +}; +template <> +struct TensorFactory2IID { + static const GUID IID; +}; +template <> +struct TensorFactory2IID { + static const GUID IID; +}; +template <> +struct TensorFactory2IID { + static const GUID IID; +}; +template <> +struct TensorFactory2IID { + static const GUID IID; +}; +template <> +struct TensorFactory2IID { + static const GUID IID; +}; +template <> +struct TensorFactory2IID { + static const GUID IID; +}; - return activation_factory->QueryInterface(iid, factory); +__declspec(selectany +) const GUID TensorFactory2IID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorFloatStatics2; +__declspec(selectany +) const GUID TensorFactory2IID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorFloat16BitStatics2; +__declspec(selectany +) const GUID TensorFactory2IID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorInt8BitStatics2; +__declspec(selectany +) const GUID TensorFactory2IID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorUInt8BitStatics2; +__declspec(selectany +) const GUID TensorFactory2IID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorUInt16BitStatics2; +__declspec(selectany +) const GUID TensorFactory2IID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorInt16BitStatics2; +__declspec(selectany +) const GUID TensorFactory2IID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorUInt32BitStatics2; +__declspec(selectany +) const GUID TensorFactory2IID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorInt32BitStatics2; +__declspec(selectany +) const GUID TensorFactory2IID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorUInt64BitStatics2; +__declspec(selectany +) const GUID TensorFactory2IID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorInt64BitStatics2; +__declspec(selectany +) const GUID TensorFactory2IID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorBooleanStatics2; +__declspec(selectany +) const GUID TensorFactory2IID::IID = ABI::Microsoft::AI::MachineLearning::IID_ITensorDoubleStatics2; + +inline HRESULT GetActivationFactory(const wchar_t* p_class_id, const IID& iid, void** factory) noexcept { + // Fallback to OS binary if the redistributable is not present! + auto library = LoadLibraryExW(MachineLearningDll, nullptr, 0); + if (library == nullptr) { + return HRESULT_FROM_WIN32(GetLastError()); + } + + using DllGetActivationFactory = HRESULT __stdcall(HSTRING, void** factory); + auto call = reinterpret_cast(GetProcAddress(library, "DllGetActivationFactory")); + if (!call) { + auto hr = HRESULT_FROM_WIN32(GetLastError()); + FreeLibrary(library); + return hr; + } + + Microsoft::WRL::ComPtr activation_factory; + auto hr = call( + Microsoft::WRL::Wrappers::HStringReference(p_class_id, static_cast(wcslen(p_class_id))).Get(), + reinterpret_cast(activation_factory.GetAddressOf()) + ); + + if (FAILED(hr)) { + FreeLibrary(library); + return hr; + } + + return activation_factory->QueryInterface(iid, factory); } -class WinMLLearningModel -{ - friend class WinMLLearningModelSession; +class WinMLLearningModel { + friend class WinMLLearningModelSession; + + public: + WinMLLearningModel(const wchar_t* model_path, size_t size) { ML_FAIL_FAST_IF(0 != Initialize(model_path, size)); } + + WinMLLearningModel(const char* bytes, size_t size) { + ML_FAIL_FAST_IF(0 != Initialize(bytes, size, false /*dont copy*/)); + } + + private: + int32_t Initialize(const wchar_t* model_path, size_t size) { + Microsoft::WRL::ComPtr learningModel; + RETURN_HR_IF_FAILED(GetActivationFactory( + RuntimeClass_Microsoft_AI_MachineLearning_LearningModel, + ABI::Microsoft::AI::MachineLearning::IID_ILearningModelStatics, + &learningModel + )); + + RETURN_HR_IF_FAILED(learningModel->LoadFromFilePath( + Microsoft::WRL::Wrappers::HStringReference(model_path, static_cast(size)).Get(), + m_learning_model.GetAddressOf() + )); + return 0; + } -public: - WinMLLearningModel(const wchar_t* model_path, size_t size) - { - ML_FAIL_FAST_IF(0 != Initialize(model_path, size)); - } + struct StoreCompleted : Microsoft::WRL::RuntimeClass< + Microsoft::WRL::RuntimeClassFlags, + ABI::Windows::Foundation::IAsyncOperationCompletedHandler> { + HANDLE completed_event_; - WinMLLearningModel(const char* bytes, size_t size) - { - ML_FAIL_FAST_IF(0 != Initialize(bytes, size, false /*dont copy*/)); - } + StoreCompleted() : completed_event_(CreateEvent(nullptr, true, false, nullptr)) {} -private: - int32_t Initialize(const wchar_t* model_path, size_t size) - { - Microsoft::WRL::ComPtr learningModel; - RETURN_HR_IF_FAILED( - GetActivationFactory( - RuntimeClass_Microsoft_AI_MachineLearning_LearningModel, - ABI::Microsoft::AI::MachineLearning::IID_ILearningModelStatics, - &learningModel)); - - RETURN_HR_IF_FAILED( - learningModel->LoadFromFilePath( - Microsoft::WRL::Wrappers::HStringReference(model_path, static_cast(size)).Get(), - m_learning_model.GetAddressOf())); - return 0; + ~StoreCompleted() { CloseHandle(completed_event_); } + + HRESULT STDMETHODCALLTYPE Invoke( + ABI::Windows::Foundation::IAsyncOperation* /*asyncInfo*/, + ABI::Windows::Foundation::AsyncStatus /*status*/ + ) { + SetEvent(completed_event_); + return S_OK; } - struct StoreCompleted : - Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags, - ABI::Windows::Foundation::IAsyncOperationCompletedHandler> - { - HANDLE completed_event_; - - StoreCompleted() : - completed_event_(CreateEvent(nullptr, true, false, nullptr)) - {} - - ~StoreCompleted() - { - CloseHandle(completed_event_); - } - - HRESULT STDMETHODCALLTYPE Invoke( - ABI::Windows::Foundation::IAsyncOperation * /*asyncInfo*/, - ABI::Windows::Foundation::AsyncStatus /*status*/) - { - SetEvent(completed_event_); - return S_OK; - } - - HRESULT Wait() - { - WaitForSingleObject(completed_event_, INFINITE); - return S_OK; - } - }; + HRESULT Wait() { + WaitForSingleObject(completed_event_, INFINITE); + return S_OK; + } + }; + + int32_t Initialize(const char* bytes, size_t size, bool with_copy = false) { + auto hr = RoInitialize(RO_INIT_TYPE::RO_INIT_SINGLETHREADED); + // https://docs.microsoft.com/en-us/windows/win32/api/roapi/nf-roapi-roinitialize#return-value + // RPC_E_CHANGED_MODE indicates already initialized as multithreaded + if (hr < 0 && hr != RPC_E_CHANGED_MODE) { + return static_cast(hr); + } - int32_t Initialize(const char* bytes, size_t size, bool with_copy = false) - { - auto hr = RoInitialize(RO_INIT_TYPE::RO_INIT_SINGLETHREADED); - // https://docs.microsoft.com/en-us/windows/win32/api/roapi/nf-roapi-roinitialize#return-value - // RPC_E_CHANGED_MODE indicates already initialized as multithreaded - if (hr < 0 && hr != RPC_E_CHANGED_MODE) { - return static_cast(hr); - } - - Microsoft::WRL::ComPtr random_access_stream_ref; - if (with_copy) { - // Create in memory stream - Microsoft::WRL::ComPtr in_memory_random_access_stream_insp; - RETURN_HR_IF_FAILED(RoActivateInstance( - Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_Storage_Streams_InMemoryRandomAccessStream).Get(), - in_memory_random_access_stream_insp.GetAddressOf())); - - // QI memory stream to output stream - Microsoft::WRL::ComPtr output_stream; - RETURN_HR_IF_FAILED(in_memory_random_access_stream_insp.As(&output_stream)); - - // Create data writer factory - Microsoft::WRL::ComPtr activation_factory; - RETURN_HR_IF_FAILED(RoGetActivationFactory( - Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_Storage_Streams_DataWriter).Get(), - IID_PPV_ARGS(activation_factory.GetAddressOf()))); - - // Create data writer object based on the in memory stream - Microsoft::WRL::ComPtr data_writer; - RETURN_HR_IF_FAILED(activation_factory->CreateDataWriter( - output_stream.Get(), - data_writer.GetAddressOf())); - - // Write the model to the data writer and thus to the stream - RETURN_HR_IF_FAILED( - data_writer->WriteBytes(static_cast(size), reinterpret_cast(const_cast(bytes)))); - - // QI the in memory stream to a random access stream - Microsoft::WRL::ComPtr random_access_stream; - RETURN_HR_IF_FAILED(in_memory_random_access_stream_insp.As(&random_access_stream)); - - // Create a random access stream reference factory - Microsoft::WRL::ComPtr random_access_stream_ref_statics; - RETURN_HR_IF_FAILED(RoGetActivationFactory( - Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_Storage_Streams_RandomAccessStreamReference).Get(), - IID_PPV_ARGS(random_access_stream_ref_statics.GetAddressOf()))); - - // Create a random access stream reference from the random access stream view on top of - // the in memory stream - RETURN_HR_IF_FAILED(random_access_stream_ref_statics->CreateFromStream( - random_access_stream.Get(), - random_access_stream_ref.GetAddressOf())); - - Microsoft::WRL::ComPtr> async_operation; - RETURN_HR_IF_FAILED(data_writer->StoreAsync(&async_operation)); - auto store_completed_handler = Microsoft::WRL::Make(); - RETURN_HR_IF_FAILED(async_operation->put_Completed(store_completed_handler.Get())); - RETURN_HR_IF_FAILED(store_completed_handler->Wait()); - - } else { - Microsoft::WRL::ComPtr> buffer; - RETURN_HR_IF_FAILED( - Microsoft::WRL::MakeAndInitialize>( - &buffer, bytes, bytes + size)); - - RETURN_HR_IF_FAILED( - Microsoft::WRL::MakeAndInitialize( - &random_access_stream_ref, buffer.Get())); - } - - // Create a learning model factory - Microsoft::WRL::ComPtr learning_model; + Microsoft::WRL::ComPtr random_access_stream_ref; + if (with_copy) { + // Create in memory stream + Microsoft::WRL::ComPtr in_memory_random_access_stream_insp; + RETURN_HR_IF_FAILED(RoActivateInstance( + Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_Storage_Streams_InMemoryRandomAccessStream) + .Get(), + in_memory_random_access_stream_insp.GetAddressOf() + )); + + // QI memory stream to output stream + Microsoft::WRL::ComPtr output_stream; + RETURN_HR_IF_FAILED(in_memory_random_access_stream_insp.As(&output_stream)); + + // Create data writer factory + Microsoft::WRL::ComPtr activation_factory; + RETURN_HR_IF_FAILED(RoGetActivationFactory( + Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_Storage_Streams_DataWriter).Get(), + IID_PPV_ARGS(activation_factory.GetAddressOf()) + )); + + // Create data writer object based on the in memory stream + Microsoft::WRL::ComPtr data_writer; + RETURN_HR_IF_FAILED(activation_factory->CreateDataWriter(output_stream.Get(), data_writer.GetAddressOf())); + + // Write the model to the data writer and thus to the stream RETURN_HR_IF_FAILED( - GetActivationFactory( - RuntimeClass_Microsoft_AI_MachineLearning_LearningModel, - ABI::Microsoft::AI::MachineLearning::IID_ILearningModelStatics, - &learning_model)); - - // Create a learning model from the factory with the random access stream reference that points - // to the random access stream view on top of the in memory stream copy of the model - RETURN_HR_IF_FAILED( - learning_model->LoadFromStream( - random_access_stream_ref.Get(), - m_learning_model.GetAddressOf())); - - return 0; + data_writer->WriteBytes(static_cast(size), reinterpret_cast(const_cast(bytes))) + ); + + // QI the in memory stream to a random access stream + Microsoft::WRL::ComPtr random_access_stream; + RETURN_HR_IF_FAILED(in_memory_random_access_stream_insp.As(&random_access_stream)); + + // Create a random access stream reference factory + Microsoft::WRL::ComPtr + random_access_stream_ref_statics; + RETURN_HR_IF_FAILED(RoGetActivationFactory( + Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_Storage_Streams_RandomAccessStreamReference) + .Get(), + IID_PPV_ARGS(random_access_stream_ref_statics.GetAddressOf()) + )); + + // Create a random access stream reference from the random access stream view on top of + // the in memory stream + RETURN_HR_IF_FAILED(random_access_stream_ref_statics->CreateFromStream( + random_access_stream.Get(), random_access_stream_ref.GetAddressOf() + )); + + Microsoft::WRL::ComPtr> async_operation; + RETURN_HR_IF_FAILED(data_writer->StoreAsync(&async_operation)); + auto store_completed_handler = Microsoft::WRL::Make(); + RETURN_HR_IF_FAILED(async_operation->put_Completed(store_completed_handler.Get())); + RETURN_HR_IF_FAILED(store_completed_handler->Wait()); + + } else { + Microsoft::WRL::ComPtr> buffer; + RETURN_HR_IF_FAILED(Microsoft::WRL::MakeAndInitialize>(&buffer, bytes, bytes + size)); + + RETURN_HR_IF_FAILED(Microsoft::WRL::MakeAndInitialize( + &random_access_stream_ref, buffer.Get() + )); } -private: - Microsoft::WRL::ComPtr m_learning_model; + // Create a learning model factory + Microsoft::WRL::ComPtr learning_model; + RETURN_HR_IF_FAILED(GetActivationFactory( + RuntimeClass_Microsoft_AI_MachineLearning_LearningModel, + ABI::Microsoft::AI::MachineLearning::IID_ILearningModelStatics, + &learning_model + )); + + // Create a learning model from the factory with the random access stream reference that points + // to the random access stream view on top of the in memory stream copy of the model + RETURN_HR_IF_FAILED(learning_model->LoadFromStream(random_access_stream_ref.Get(), m_learning_model.GetAddressOf()) + ); + + return 0; + } + + private: + Microsoft::WRL::ComPtr m_learning_model; }; -class WinMLLearningModelResults -{ - friend class WinMLLearningModelSession; +class WinMLLearningModelResults { + friend class WinMLLearningModelSession; -public: - int32_t get_output( - const wchar_t* feature_name, - size_t feature_name_size, - void** pp_buffer, - size_t* p_capacity) - { - Microsoft::WRL::ComPtr> output_map; - RETURN_HR_IF_FAILED(m_result->get_Outputs(&output_map)); + public: + int32_t get_output(const wchar_t* feature_name, size_t feature_name_size, void** pp_buffer, size_t* p_capacity) { + Microsoft::WRL::ComPtr> output_map; + RETURN_HR_IF_FAILED(m_result->get_Outputs(&output_map)); - Microsoft::WRL::ComPtr inspectable; - RETURN_HR_IF_FAILED(output_map->Lookup( - Microsoft::WRL::Wrappers::HStringReference(feature_name, static_cast(feature_name_size)).Get(), - inspectable.GetAddressOf())); + Microsoft::WRL::ComPtr inspectable; + RETURN_HR_IF_FAILED(output_map->Lookup( + Microsoft::WRL::Wrappers::HStringReference(feature_name, static_cast(feature_name_size)).Get(), + inspectable.GetAddressOf() + )); - Microsoft::WRL::ComPtr output_feature_value; - RETURN_HR_IF_FAILED(inspectable.As(&output_feature_value)); + Microsoft::WRL::ComPtr output_feature_value; + RETURN_HR_IF_FAILED(inspectable.As(&output_feature_value)); - Microsoft::WRL::ComPtr native_tensor_float_feature_value; - RETURN_HR_IF_FAILED(output_feature_value.As(&native_tensor_float_feature_value)); + Microsoft::WRL::ComPtr native_tensor_float_feature_value; + RETURN_HR_IF_FAILED(output_feature_value.As(&native_tensor_float_feature_value)); - uint32_t size; - RETURN_HR_IF_FAILED(native_tensor_float_feature_value->GetBuffer(reinterpret_cast(pp_buffer), &size)); - *p_capacity = size; + uint32_t size; + RETURN_HR_IF_FAILED(native_tensor_float_feature_value->GetBuffer(reinterpret_cast(pp_buffer), &size)); + *p_capacity = size; - return 0; - } + return 0; + } -private: - WinMLLearningModelResults(ABI::Microsoft::AI::MachineLearning::ILearningModelEvaluationResult* p_result) - { - m_result = p_result; - } + private: + WinMLLearningModelResults(ABI::Microsoft::AI::MachineLearning::ILearningModelEvaluationResult* p_result) { + m_result = p_result; + } -private: - Microsoft::WRL::ComPtr< ABI::Microsoft::AI::MachineLearning::ILearningModelEvaluationResult> m_result; + private: + Microsoft::WRL::ComPtr m_result; }; -class WinMLLearningModelBinding -{ - friend class WinMLLearningModelSession; +class WinMLLearningModelBinding { + friend class WinMLLearningModelSession; + + public: + WinMLLearningModelBinding(const WinMLLearningModelSession& session) { ML_FAIL_FAST_IF(0 != Initialize(session)); } + + template + int32_t bind( + const wchar_t* feature_name, + size_t feature_name_size, + tensor_shape_type* p_shape, + size_t shape_size, + T* p_data, + size_t data_size + ) { + using ITensor = typename Tensor::Type; + using ITensorFactory = typename TensorFactory::Factory; + + Microsoft::WRL::ComPtr tensor_factory; + RETURN_HR_IF_FAILED( + GetActivationFactory(TensorRuntimeClassID::RuntimeClass_ID, TensorFactoryIID::IID, &tensor_factory) + ); + + Microsoft::WRL::ComPtr> input_shape_iterable; + RETURN_HR_IF_FAILED(Microsoft::WRL::MakeAndInitialize>( + &input_shape_iterable, p_shape, p_shape + shape_size + )); + + Microsoft::WRL::ComPtr tensor; + RETURN_HR_IF_FAILED(tensor_factory->CreateFromArray( + input_shape_iterable.Get(), static_cast(data_size), p_data, tensor.GetAddressOf() + )); + + Microsoft::WRL::ComPtr inspectable_tensor; + RETURN_HR_IF_FAILED(tensor.As(&inspectable_tensor)); + + RETURN_HR_IF_FAILED(m_learning_model_binding->Bind( + Microsoft::WRL::Wrappers::HStringReference(feature_name, static_cast(feature_name_size)).Get(), + inspectable_tensor.Get() + )); + return 0; + } -public: - WinMLLearningModelBinding(const WinMLLearningModelSession& session) - { - ML_FAIL_FAST_IF(0 != Initialize(session)); - } + template + int32_t bind( + const wchar_t* /*feature_name*/, size_t /*feature_name_size*/, tensor_shape_type* /*p_shape*/, size_t /*shape_size*/ + ) { + return 0; + } + + template + int32_t bind_as_reference( + const wchar_t* feature_name, + size_t feature_name_size, + tensor_shape_type* p_shape, + size_t shape_size, + T* p_data, + size_t data_size + ) { + using ITensor = typename Tensor::Type; + using ITensorFactory = typename TensorFactory2::Factory; + + Microsoft::WRL::ComPtr tensor_factory; + RETURN_HR_IF_FAILED( + GetActivationFactory(TensorRuntimeClassID::RuntimeClass_ID, TensorFactory2IID::IID, &tensor_factory) + ); - template - int32_t bind( - const wchar_t* feature_name, size_t feature_name_size, - tensor_shape_type* p_shape, size_t shape_size, - T* p_data, size_t data_size) - { - using ITensor = typename Tensor::Type; - using ITensorFactory = typename TensorFactory::Factory; - - Microsoft::WRL::ComPtr tensor_factory; - RETURN_HR_IF_FAILED( - GetActivationFactory( - TensorRuntimeClassID::RuntimeClass_ID, - TensorFactoryIID::IID, - &tensor_factory)); - - Microsoft::WRL::ComPtr> input_shape_iterable; - RETURN_HR_IF_FAILED( - Microsoft::WRL::MakeAndInitialize>( - &input_shape_iterable, p_shape, p_shape + shape_size)); - - Microsoft::WRL::ComPtr tensor; - RETURN_HR_IF_FAILED( - tensor_factory->CreateFromArray( - input_shape_iterable.Get(), - static_cast(data_size), - p_data, - tensor.GetAddressOf())); - - Microsoft::WRL::ComPtr inspectable_tensor; - RETURN_HR_IF_FAILED(tensor.As(&inspectable_tensor)); - - RETURN_HR_IF_FAILED( - m_learning_model_binding->Bind( - Microsoft::WRL::Wrappers::HStringReference(feature_name, static_cast(feature_name_size)).Get(), - inspectable_tensor.Get())); - return 0; - } + Microsoft::WRL::ComPtr> buffer; + RETURN_HR_IF_FAILED(Microsoft::WRL::MakeAndInitialize>(&buffer, p_data, p_data + data_size) + ); - template - int32_t bind( - const wchar_t* /*feature_name*/, size_t /*feature_name_size*/, - tensor_shape_type* /*p_shape*/, size_t /*shape_size*/) - { - return 0; - } + Microsoft::WRL::ComPtr tensor; + RETURN_HR_IF_FAILED( + tensor_factory->CreateFromBuffer(static_cast(shape_size), p_shape, buffer.Get(), tensor.GetAddressOf()) + ); - template - int32_t bind_as_reference( - const wchar_t* feature_name, size_t feature_name_size, - tensor_shape_type* p_shape, size_t shape_size, - T* p_data, size_t data_size) - { - using ITensor = typename Tensor::Type; - using ITensorFactory = typename TensorFactory2::Factory; - - Microsoft::WRL::ComPtr tensor_factory; - RETURN_HR_IF_FAILED( - GetActivationFactory( - TensorRuntimeClassID::RuntimeClass_ID, - TensorFactory2IID::IID, - &tensor_factory)); - - Microsoft::WRL::ComPtr> buffer; - RETURN_HR_IF_FAILED( - Microsoft::WRL::MakeAndInitialize>( - &buffer, p_data, p_data + data_size)); - - Microsoft::WRL::ComPtr tensor; - RETURN_HR_IF_FAILED( - tensor_factory->CreateFromBuffer( - static_cast(shape_size), - p_shape, - buffer.Get(), - tensor.GetAddressOf())); - - Microsoft::WRL::ComPtr inspectable_tensor; - RETURN_HR_IF_FAILED(tensor.As(&inspectable_tensor)); - - RETURN_HR_IF_FAILED( - m_learning_model_binding->Bind( - Microsoft::WRL::Wrappers::HStringReference(feature_name, static_cast(feature_name_size)).Get(), - inspectable_tensor.Get())); - return 0; - } + Microsoft::WRL::ComPtr inspectable_tensor; + RETURN_HR_IF_FAILED(tensor.As(&inspectable_tensor)); - template - int32_t bind_as_references( - const wchar_t* feature_name, size_t feature_name_size, - T** p_data, size_t* data_sizes, - size_t num_buffers) { - using ITensor = typename Tensor::Type; - using ITensorFactory = typename TensorFactory2::Factory; - - std::vector> vec_buffers(num_buffers); - for (size_t i = 0; i < num_buffers; i++) { - RETURN_HR_IF_FAILED( - Microsoft::WRL::MakeAndInitialize>( - &vec_buffers.at(i), p_data[i], p_data[i] + data_sizes[i])); - } - - std::vector raw_buffers(num_buffers); - std::transform(std::begin(vec_buffers), std::end(vec_buffers), std::begin(raw_buffers), - [](auto buffer) { return buffer.Detach(); }); - - Microsoft::WRL::ComPtr> buffers; - RETURN_HR_IF_FAILED( - Microsoft::WRL::MakeAndInitialize>( - &buffers, raw_buffers.data(), raw_buffers.data() + num_buffers)); + RETURN_HR_IF_FAILED(m_learning_model_binding->Bind( + Microsoft::WRL::Wrappers::HStringReference(feature_name, static_cast(feature_name_size)).Get(), + inspectable_tensor.Get() + )); + return 0; + } + + template + int32_t bind_as_references( + const wchar_t* feature_name, size_t feature_name_size, T** p_data, size_t* data_sizes, size_t num_buffers + ) { + using ITensor = typename Tensor::Type; + using ITensorFactory = typename TensorFactory2::Factory; + + std::vector> vec_buffers(num_buffers); + for (size_t i = 0; i < num_buffers; i++) { + RETURN_HR_IF_FAILED(Microsoft::WRL::MakeAndInitialize>( + &vec_buffers.at(i), p_data[i], p_data[i] + data_sizes[i] + )); + } - Microsoft::WRL::ComPtr inspectable_tensor; - RETURN_HR_IF_FAILED(buffers.As(&inspectable_tensor)); + std::vector raw_buffers(num_buffers); + std::transform(std::begin(vec_buffers), std::end(vec_buffers), std::begin(raw_buffers), [](auto buffer) { + return buffer.Detach(); + }); - RETURN_HR_IF_FAILED( - m_learning_model_binding->Bind( - Microsoft::WRL::Wrappers::HStringReference(feature_name, static_cast(feature_name_size)).Get(), - inspectable_tensor.Get())); - return 0; - } + Microsoft::WRL::ComPtr> buffers; + RETURN_HR_IF_FAILED( + Microsoft::WRL::MakeAndInitialize>( + &buffers, raw_buffers.data(), raw_buffers.data() + num_buffers + ) + ); + + Microsoft::WRL::ComPtr inspectable_tensor; + RETURN_HR_IF_FAILED(buffers.As(&inspectable_tensor)); + + RETURN_HR_IF_FAILED(m_learning_model_binding->Bind( + Microsoft::WRL::Wrappers::HStringReference(feature_name, static_cast(feature_name_size)).Get(), + inspectable_tensor.Get() + )); + return 0; + } -private: - inline int32_t Initialize(const WinMLLearningModelSession& session); + private: + inline int32_t Initialize(const WinMLLearningModelSession& session); -private: - Microsoft::WRL::ComPtr m_learning_model_binding; + private: + Microsoft::WRL::ComPtr m_learning_model_binding; }; -class WinMLLearningModelDevice -{ - friend class WinMLLearningModelSession; +class WinMLLearningModelDevice { + friend class WinMLLearningModelSession; -public: - WinMLLearningModelDevice() : - WinMLLearningModelDevice(ABI::Microsoft::AI::MachineLearning::LearningModelDeviceKind_Default) - {} + public: + WinMLLearningModelDevice() + : WinMLLearningModelDevice(ABI::Microsoft::AI::MachineLearning::LearningModelDeviceKind_Default) {} - WinMLLearningModelDevice(WinMLLearningModelDevice&& device) : - m_learning_model_device(std::move(device.m_learning_model_device)) - {} + WinMLLearningModelDevice(WinMLLearningModelDevice&& device) + : m_learning_model_device(std::move(device.m_learning_model_device)) {} - WinMLLearningModelDevice(const WinMLLearningModelDevice& device) : - m_learning_model_device(device.m_learning_model_device) - {} + WinMLLearningModelDevice(const WinMLLearningModelDevice& device) + : m_learning_model_device(device.m_learning_model_device) {} - void operator=(const WinMLLearningModelDevice& device) - { - m_learning_model_device = device.m_learning_model_device; - } + void operator=(const WinMLLearningModelDevice& device) { m_learning_model_device = device.m_learning_model_device; } - WinMLLearningModelDevice(ABI::Microsoft::AI::MachineLearning::LearningModelDeviceKind kind) - { - ML_FAIL_FAST_IF(0 != Initialize(kind)); - } + WinMLLearningModelDevice(ABI::Microsoft::AI::MachineLearning::LearningModelDeviceKind kind) { + ML_FAIL_FAST_IF(0 != Initialize(kind)); + } - WinMLLearningModelDevice(ABI::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice* d3dDevice) - { - ML_FAIL_FAST_IF(0 != Initialize(d3dDevice)); - } + WinMLLearningModelDevice(ABI::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice* d3dDevice) { + ML_FAIL_FAST_IF(0 != Initialize(d3dDevice)); + } - WinMLLearningModelDevice(ID3D12CommandQueue* queue) - { - ML_FAIL_FAST_IF(0 != Initialize(queue)); - } + WinMLLearningModelDevice(ID3D12CommandQueue* queue) { ML_FAIL_FAST_IF(0 != Initialize(queue)); } - static WinMLLearningModelDevice create_cpu_device() - { - return WinMLLearningModelDevice(ABI::Microsoft::AI::MachineLearning::LearningModelDeviceKind_Cpu); - } + static WinMLLearningModelDevice create_cpu_device() { + return WinMLLearningModelDevice(ABI::Microsoft::AI::MachineLearning::LearningModelDeviceKind_Cpu); + } - static WinMLLearningModelDevice create_directx_device() - { - return WinMLLearningModelDevice(ABI::Microsoft::AI::MachineLearning::LearningModelDeviceKind_DirectX); - } + static WinMLLearningModelDevice create_directx_device() { + return WinMLLearningModelDevice(ABI::Microsoft::AI::MachineLearning::LearningModelDeviceKind_DirectX); + } - static WinMLLearningModelDevice create_directx_high_power_device() - { - return WinMLLearningModelDevice(ABI::Microsoft::AI::MachineLearning::LearningModelDeviceKind_DirectXHighPerformance); - } + static WinMLLearningModelDevice create_directx_high_power_device() { + return WinMLLearningModelDevice(ABI::Microsoft::AI::MachineLearning::LearningModelDeviceKind_DirectXHighPerformance + ); + } - static WinMLLearningModelDevice create_directx_min_power_device() - { - return WinMLLearningModelDevice(ABI::Microsoft::AI::MachineLearning::LearningModelDeviceKind_DirectXMinPower); - } + static WinMLLearningModelDevice create_directx_min_power_device() { + return WinMLLearningModelDevice(ABI::Microsoft::AI::MachineLearning::LearningModelDeviceKind_DirectXMinPower); + } - static WinMLLearningModelDevice create_directx_device(ABI::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice* d3dDevice) - { - return WinMLLearningModelDevice(d3dDevice); - } + static WinMLLearningModelDevice create_directx_device( + ABI::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice* d3dDevice + ) { + return WinMLLearningModelDevice(d3dDevice); + } - static WinMLLearningModelDevice create_directx_device(ID3D12CommandQueue* queue) - { - return WinMLLearningModelDevice(queue); - } + static WinMLLearningModelDevice create_directx_device(ID3D12CommandQueue* queue) { + return WinMLLearningModelDevice(queue); + } -private: - int32_t Initialize(ABI::Microsoft::AI::MachineLearning::LearningModelDeviceKind kind) - { - Microsoft::WRL::ComPtr - learning_model_device_factory; - RETURN_HR_IF_FAILED( - GetActivationFactory( - RuntimeClass_Microsoft_AI_MachineLearning_LearningModelDevice, - ABI::Microsoft::AI::MachineLearning::IID_ILearningModelDeviceFactory, - &learning_model_device_factory)); + private: + int32_t Initialize(ABI::Microsoft::AI::MachineLearning::LearningModelDeviceKind kind) { + Microsoft::WRL::ComPtr + learning_model_device_factory; + RETURN_HR_IF_FAILED(GetActivationFactory( + RuntimeClass_Microsoft_AI_MachineLearning_LearningModelDevice, + ABI::Microsoft::AI::MachineLearning::IID_ILearningModelDeviceFactory, + &learning_model_device_factory + )); - RETURN_HR_IF_FAILED(learning_model_device_factory->Create(kind, &m_learning_model_device)); + RETURN_HR_IF_FAILED(learning_model_device_factory->Create(kind, &m_learning_model_device)); - return 0; - } + return 0; + } - int32_t Initialize(ABI::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice* d3dDevice) - { - Microsoft::WRL::ComPtr - learning_model_device_factory; - RETURN_HR_IF_FAILED( - GetActivationFactory( - RuntimeClass_Microsoft_AI_MachineLearning_LearningModelDevice, - ABI::Microsoft::AI::MachineLearning::IID_ILearningModelDeviceStatics, - &learning_model_device_factory)); + int32_t Initialize(ABI::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice* d3dDevice) { + Microsoft::WRL::ComPtr + learning_model_device_factory; + RETURN_HR_IF_FAILED(GetActivationFactory( + RuntimeClass_Microsoft_AI_MachineLearning_LearningModelDevice, + ABI::Microsoft::AI::MachineLearning::IID_ILearningModelDeviceStatics, + &learning_model_device_factory + )); - RETURN_HR_IF_FAILED(learning_model_device_factory->CreateFromDirect3D11Device(d3dDevice, &m_learning_model_device)); + RETURN_HR_IF_FAILED(learning_model_device_factory->CreateFromDirect3D11Device(d3dDevice, &m_learning_model_device)); - return 0; - } + return 0; + } - int32_t Initialize(ID3D12CommandQueue* queue) - { - Microsoft::WRL::ComPtr - learning_model_device_factory; - RETURN_HR_IF_FAILED( - GetActivationFactory( - RuntimeClass_Microsoft_AI_MachineLearning_LearningModelDevice, - __uuidof(ILearningModelDeviceFactoryNative), - &learning_model_device_factory)); + int32_t Initialize(ID3D12CommandQueue* queue) { + Microsoft::WRL::ComPtr learning_model_device_factory; + RETURN_HR_IF_FAILED(GetActivationFactory( + RuntimeClass_Microsoft_AI_MachineLearning_LearningModelDevice, + __uuidof(ILearningModelDeviceFactoryNative), + &learning_model_device_factory + )); - RETURN_HR_IF_FAILED(learning_model_device_factory->CreateFromD3D12CommandQueue(queue, &m_learning_model_device)); + RETURN_HR_IF_FAILED(learning_model_device_factory->CreateFromD3D12CommandQueue(queue, &m_learning_model_device)); - return 0; - } + return 0; + } -private: - Microsoft::WRL::ComPtr m_learning_model_device; + private: + Microsoft::WRL::ComPtr m_learning_model_device; }; -class WinMLLearningModelSession -{ - friend class WinMLLearningModelBinding; +class WinMLLearningModelSession { + friend class WinMLLearningModelBinding; -public: - using Model = WinMLLearningModel; - using Device = WinMLLearningModelDevice; + public: + using Model = WinMLLearningModel; + using Device = WinMLLearningModelDevice; -public: - WinMLLearningModelSession(const Model& model) - { - ML_FAIL_FAST_IF(0 != Initialize(model, Device())); - } + public: + WinMLLearningModelSession(const Model& model) { ML_FAIL_FAST_IF(0 != Initialize(model, Device())); } - WinMLLearningModelSession(const Model& model, const Device& device) - { - ML_FAIL_FAST_IF(0 != Initialize(model, device)); - } + WinMLLearningModelSession(const Model& model, const Device& device) { + ML_FAIL_FAST_IF(0 != Initialize(model, device)); + } - WinMLLearningModelResults evaluate(WinMLLearningModelBinding& binding) - { - Microsoft::WRL::ComPtr - m_learning_model_evaluation_result; + WinMLLearningModelResults evaluate(WinMLLearningModelBinding& binding) { + Microsoft::WRL::ComPtr + m_learning_model_evaluation_result; - FAIL_FAST_IF_HR_FAILED( - m_learning_model_session->Evaluate( - binding.m_learning_model_binding.Get(), - nullptr, - m_learning_model_evaluation_result.GetAddressOf())); + FAIL_FAST_IF_HR_FAILED(m_learning_model_session->Evaluate( + binding.m_learning_model_binding.Get(), nullptr, m_learning_model_evaluation_result.GetAddressOf() + )); - return WinMLLearningModelResults(m_learning_model_evaluation_result.Get()); - } + return WinMLLearningModelResults(m_learning_model_evaluation_result.Get()); + } -private: - int32_t Initialize(const Model& model, const Device& device) - { - // {d7d86c54-d03d-5ae3-a958-fe952b640620} - static const GUID IID_ILearningModelSessionFactory = - { 0xd7d86c54, 0xd03d, 0x5ae3, { 0xa9, 0x58, 0xfe, 0x95, 0x2b, 0x64, 0x06, 0x20 } }; - - Microsoft::WRL::ComPtr - m_learning_model_session_factory; - RETURN_HR_IF_FAILED( - GetActivationFactory( - RuntimeClass_Microsoft_AI_MachineLearning_LearningModelSession, - IID_ILearningModelSessionFactory, - &m_learning_model_session_factory)); - - RETURN_HR_IF_FAILED( - m_learning_model_session_factory->CreateFromModelOnDevice( - model.m_learning_model.Get(), - device.m_learning_model_device.Get(), - m_learning_model_session.GetAddressOf())); - - return 0; - } + private: + int32_t Initialize(const Model& model, const Device& device) { + // {d7d86c54-d03d-5ae3-a958-fe952b640620} + static const GUID IID_ILearningModelSessionFactory = { + 0xd7d86c54, 0xd03d, 0x5ae3, {0xa9, 0x58, 0xfe, 0x95, 0x2b, 0x64, 0x06, 0x20} + }; + + Microsoft::WRL::ComPtr + m_learning_model_session_factory; + RETURN_HR_IF_FAILED(GetActivationFactory( + RuntimeClass_Microsoft_AI_MachineLearning_LearningModelSession, + IID_ILearningModelSessionFactory, + &m_learning_model_session_factory + )); + + RETURN_HR_IF_FAILED(m_learning_model_session_factory->CreateFromModelOnDevice( + model.m_learning_model.Get(), device.m_learning_model_device.Get(), m_learning_model_session.GetAddressOf() + )); + + return 0; + } -private: - Microsoft::WRL::ComPtr m_learning_model_session; + private: + Microsoft::WRL::ComPtr m_learning_model_session; }; -inline int32_t WinMLLearningModelBinding::Initialize(const WinMLLearningModelSession& session) -{ - // {ae2f1c97-2fd5-55b9-a05f-53b9dbb4f9e2} - static const GUID IID_ILearningModelBindingFactory = - { 0xae2f1c97, 0x2fd5, 0x55b9, { 0xa0, 0x5f, 0x53, 0xb9, 0xdb, 0xb4, 0xf9, 0xe2 } }; +inline int32_t WinMLLearningModelBinding::Initialize(const WinMLLearningModelSession& session) { + // {ae2f1c97-2fd5-55b9-a05f-53b9dbb4f9e2} + static const GUID IID_ILearningModelBindingFactory = { + 0xae2f1c97, 0x2fd5, 0x55b9, {0xa0, 0x5f, 0x53, 0xb9, 0xdb, 0xb4, 0xf9, 0xe2} + }; - Microsoft::WRL::ComPtr - learning_model_binding_factory; + Microsoft::WRL::ComPtr + learning_model_binding_factory; - RETURN_HR_IF_FAILED( - GetActivationFactory( - RuntimeClass_Microsoft_AI_MachineLearning_LearningModelBinding, - IID_ILearningModelBindingFactory, - &learning_model_binding_factory)); + RETURN_HR_IF_FAILED(GetActivationFactory( + RuntimeClass_Microsoft_AI_MachineLearning_LearningModelBinding, + IID_ILearningModelBindingFactory, + &learning_model_binding_factory + )); - RETURN_HR_IF_FAILED( - learning_model_binding_factory->CreateFromSession( - session.m_learning_model_session.Get(), - m_learning_model_binding.GetAddressOf())); + RETURN_HR_IF_FAILED(learning_model_binding_factory->CreateFromSession( + session.m_learning_model_session.Get(), m_learning_model_binding.GetAddressOf() + )); - return 0; + return 0; } -}}}} // namespace Microsoft::AI::MachineLearning::Details +} // namespace Details +} // namespace MachineLearning +} // namespace AI +} // namespace Microsoft -#endif // WINML_H_ \ No newline at end of file +#endif // WINML_H_ diff --git a/winml/test/api/raw/winml_windows.h b/winml/test/api/raw/winml_windows.h index 172d95850feb5..944daff6dd10a 100644 --- a/winml/test/api/raw/winml_windows.h +++ b/winml/test/api/raw/winml_windows.h @@ -7,31 +7,30 @@ #include "buffer_backed_random_access_stream_reference.h" #include "weak_single_threaded_iterable.h" -#define RETURN_HR_IF_FAILED(expression) \ - do { \ - auto _hr = expression; \ - if (FAILED(_hr)) \ - { \ - return static_cast(_hr); \ - } \ - } while (0) - - -#define FAIL_FAST_IF_HR_FAILED(expression) \ - do { \ - auto _hr = expression; \ - if (FAILED(_hr)) \ - { \ - __fastfail(static_cast(_hr)); \ - } \ - } while (0) - +#define RETURN_HR_IF_FAILED(expression) \ + do { \ + auto _hr = expression; \ + if (FAILED(_hr)) { \ + return static_cast(_hr); \ + } \ + } while (0) + +#define FAIL_FAST_IF_HR_FAILED(expression) \ + do { \ + auto _hr = expression; \ + if (FAILED(_hr)) { \ + __fastfail(static_cast(_hr)); \ + } \ + } while (0) struct float16 { - uint16_t value; + uint16_t value; }; -namespace Microsoft { namespace AI { namespace MachineLearning { namespace Details { +namespace Microsoft { +namespace AI { +namespace MachineLearning { +namespace Details { class WinMLLearningModel; class WinMLLearningModelBinding; @@ -40,694 +39,885 @@ class WinMLLearningModelResults; extern const __declspec(selectany) _Null_terminated_ wchar_t MachineLearningDll[] = L"windows.ai.machinelearning.dll"; -template struct Tensor { }; -template <> struct Tensor { using Type = ABI::Windows::AI::MachineLearning::ITensorFloat; }; -template <> struct Tensor { using Type = ABI::Windows::AI::MachineLearning::ITensorFloat16Bit;}; -template <> struct Tensor { using Type = ABI::Windows::AI::MachineLearning::ITensorInt8Bit; }; -template <> struct Tensor { using Type = ABI::Windows::AI::MachineLearning::ITensorUInt8Bit; }; -template <> struct Tensor { using Type = ABI::Windows::AI::MachineLearning::ITensorUInt16Bit; }; -template <> struct Tensor { using Type = ABI::Windows::AI::MachineLearning::ITensorInt16Bit; }; -template <> struct Tensor { using Type = ABI::Windows::AI::MachineLearning::ITensorUInt32Bit; }; -template <> struct Tensor { using Type = ABI::Windows::AI::MachineLearning::ITensorInt32Bit; }; -template <> struct Tensor { using Type = ABI::Windows::AI::MachineLearning::ITensorUInt64Bit; }; -template <> struct Tensor { using Type = ABI::Windows::AI::MachineLearning::ITensorInt64Bit; }; -template <> struct Tensor { using Type = ABI::Windows::AI::MachineLearning::ITensorBoolean; }; -template <> struct Tensor { using Type = ABI::Windows::AI::MachineLearning::ITensorDouble; }; - -template struct TensorRuntimeClassID { }; -template <> struct TensorRuntimeClassID { static const wchar_t* RuntimeClass_ID; }; -template <> struct TensorRuntimeClassID { static const wchar_t* RuntimeClass_ID; }; -template <> struct TensorRuntimeClassID { static const wchar_t* RuntimeClass_ID; }; -template <> struct TensorRuntimeClassID { static const wchar_t* RuntimeClass_ID; }; -template <> struct TensorRuntimeClassID { static const wchar_t* RuntimeClass_ID; }; -template <> struct TensorRuntimeClassID { static const wchar_t* RuntimeClass_ID; }; -template <> struct TensorRuntimeClassID { static const wchar_t* RuntimeClass_ID; }; -template <> struct TensorRuntimeClassID { static const wchar_t* RuntimeClass_ID; }; -template <> struct TensorRuntimeClassID { static const wchar_t* RuntimeClass_ID; }; -template <> struct TensorRuntimeClassID { static const wchar_t* RuntimeClass_ID; }; -template <> struct TensorRuntimeClassID { static const wchar_t* RuntimeClass_ID; }; -template <> struct TensorRuntimeClassID { static const wchar_t* RuntimeClass_ID; }; - -__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Windows_AI_MachineLearning_TensorFloat; -__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Windows_AI_MachineLearning_TensorFloat16Bit; -__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Windows_AI_MachineLearning_TensorInt8Bit; -__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Windows_AI_MachineLearning_TensorUInt8Bit; -__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Windows_AI_MachineLearning_TensorUInt16Bit; -__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Windows_AI_MachineLearning_TensorInt16Bit; -__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Windows_AI_MachineLearning_TensorUInt32Bit; -__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Windows_AI_MachineLearning_TensorInt32Bit; -__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Windows_AI_MachineLearning_TensorUInt64Bit; -__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Windows_AI_MachineLearning_TensorInt64Bit; -__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Windows_AI_MachineLearning_TensorBoolean; -__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Windows_AI_MachineLearning_TensorDouble; - -template struct TensorFactory { }; -template <> struct TensorFactory { using Factory = ABI::Windows::AI::MachineLearning::ITensorFloatStatics; }; -template <> struct TensorFactory { using Factory = ABI::Windows::AI::MachineLearning::ITensorFloat16BitStatics;}; -template <> struct TensorFactory { using Factory = ABI::Windows::AI::MachineLearning::ITensorInt8BitStatics; }; -template <> struct TensorFactory { using Factory = ABI::Windows::AI::MachineLearning::ITensorUInt8BitStatics; }; -template <> struct TensorFactory { using Factory = ABI::Windows::AI::MachineLearning::ITensorUInt16BitStatics; }; -template <> struct TensorFactory { using Factory = ABI::Windows::AI::MachineLearning::ITensorInt16BitStatics; }; -template <> struct TensorFactory { using Factory = ABI::Windows::AI::MachineLearning::ITensorUInt32BitStatics; }; -template <> struct TensorFactory { using Factory = ABI::Windows::AI::MachineLearning::ITensorInt32BitStatics; }; -template <> struct TensorFactory { using Factory = ABI::Windows::AI::MachineLearning::ITensorUInt64BitStatics; }; -template <> struct TensorFactory { using Factory = ABI::Windows::AI::MachineLearning::ITensorInt64BitStatics; }; -template <> struct TensorFactory { using Factory = ABI::Windows::AI::MachineLearning::ITensorBooleanStatics; }; -template <> struct TensorFactory { using Factory = ABI::Windows::AI::MachineLearning::ITensorDoubleStatics; }; - - -template struct TensorFactory2 { }; -template <> struct TensorFactory2 { using Factory = ABI::Windows::AI::MachineLearning::ITensorFloatStatics2; }; -template <> struct TensorFactory2 { using Factory = ABI::Windows::AI::MachineLearning::ITensorFloat16BitStatics2; }; -template <> struct TensorFactory2 { using Factory = ABI::Windows::AI::MachineLearning::ITensorInt8BitStatics2; }; -template <> struct TensorFactory2 { using Factory = ABI::Windows::AI::MachineLearning::ITensorUInt8BitStatics2; }; -template <> struct TensorFactory2 { using Factory = ABI::Windows::AI::MachineLearning::ITensorUInt16BitStatics2; }; -template <> struct TensorFactory2 { using Factory = ABI::Windows::AI::MachineLearning::ITensorInt16BitStatics2; }; -template <> struct TensorFactory2 { using Factory = ABI::Windows::AI::MachineLearning::ITensorUInt32BitStatics2; }; -template <> struct TensorFactory2 { using Factory = ABI::Windows::AI::MachineLearning::ITensorInt32BitStatics2; }; -template <> struct TensorFactory2 { using Factory = ABI::Windows::AI::MachineLearning::ITensorUInt64BitStatics2; }; -template <> struct TensorFactory2 { using Factory = ABI::Windows::AI::MachineLearning::ITensorInt64BitStatics2; }; -template <> struct TensorFactory2 { using Factory = ABI::Windows::AI::MachineLearning::ITensorBooleanStatics2; }; -template <> struct TensorFactory2 { using Factory = ABI::Windows::AI::MachineLearning::ITensorDoubleStatics2; }; - - - -template struct TensorFactoryIID { }; -template <> struct TensorFactoryIID { static const GUID IID; }; -template <> struct TensorFactoryIID { static const GUID IID; }; -template <> struct TensorFactoryIID { static const GUID IID; }; -template <> struct TensorFactoryIID { static const GUID IID; }; -template <> struct TensorFactoryIID { static const GUID IID; }; -template <> struct TensorFactoryIID { static const GUID IID; }; -template <> struct TensorFactoryIID { static const GUID IID; }; -template <> struct TensorFactoryIID { static const GUID IID; }; -template <> struct TensorFactoryIID { static const GUID IID; }; -template <> struct TensorFactoryIID { static const GUID IID; }; -template <> struct TensorFactoryIID { static const GUID IID; }; -template <> struct TensorFactoryIID { static const GUID IID; }; - -__declspec(selectany) const GUID TensorFactoryIID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorFloatStatics; -__declspec(selectany) const GUID TensorFactoryIID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorFloat16BitStatics; -__declspec(selectany) const GUID TensorFactoryIID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorInt8BitStatics; -__declspec(selectany) const GUID TensorFactoryIID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorUInt8BitStatics; -__declspec(selectany) const GUID TensorFactoryIID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorUInt16BitStatics; -__declspec(selectany) const GUID TensorFactoryIID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorInt16BitStatics; -__declspec(selectany) const GUID TensorFactoryIID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorUInt32BitStatics; -__declspec(selectany) const GUID TensorFactoryIID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorInt32BitStatics; -__declspec(selectany) const GUID TensorFactoryIID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorUInt64BitStatics; -__declspec(selectany) const GUID TensorFactoryIID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorInt64BitStatics; -__declspec(selectany) const GUID TensorFactoryIID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorBooleanStatics; -__declspec(selectany) const GUID TensorFactoryIID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorDoubleStatics; - -template struct TensorFactory2IID { }; -template <> struct TensorFactory2IID { static const GUID IID; }; -template <> struct TensorFactory2IID { static const GUID IID; }; -template <> struct TensorFactory2IID { static const GUID IID; }; -template <> struct TensorFactory2IID { static const GUID IID; }; -template <> struct TensorFactory2IID { static const GUID IID; }; -template <> struct TensorFactory2IID { static const GUID IID; }; -template <> struct TensorFactory2IID { static const GUID IID; }; -template <> struct TensorFactory2IID { static const GUID IID; }; -template <> struct TensorFactory2IID { static const GUID IID; }; -template <> struct TensorFactory2IID { static const GUID IID; }; -template <> struct TensorFactory2IID { static const GUID IID; }; -template <> struct TensorFactory2IID { static const GUID IID; }; - -__declspec(selectany) const GUID TensorFactory2IID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorFloatStatics2; -__declspec(selectany) const GUID TensorFactory2IID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorFloat16BitStatics2; -__declspec(selectany) const GUID TensorFactory2IID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorInt8BitStatics2; -__declspec(selectany) const GUID TensorFactory2IID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorUInt8BitStatics2; -__declspec(selectany) const GUID TensorFactory2IID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorUInt16BitStatics2; -__declspec(selectany) const GUID TensorFactory2IID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorInt16BitStatics2; -__declspec(selectany) const GUID TensorFactory2IID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorUInt32BitStatics2; -__declspec(selectany) const GUID TensorFactory2IID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorInt32BitStatics2; -__declspec(selectany) const GUID TensorFactory2IID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorUInt64BitStatics2; -__declspec(selectany) const GUID TensorFactory2IID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorInt64BitStatics2; -__declspec(selectany) const GUID TensorFactory2IID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorBooleanStatics2; -__declspec(selectany) const GUID TensorFactory2IID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorDoubleStatics2; - - -inline HRESULT GetActivationFactory( - const wchar_t* p_class_id, - const IID& iid, - void** factory) noexcept -{ - // Fallback to OS binary if the redistributable is not present! - auto library = LoadLibraryExW(MachineLearningDll, nullptr, 0); +template +struct Tensor {}; +template <> +struct Tensor { + using Type = ABI::Windows::AI::MachineLearning::ITensorFloat; +}; +template <> +struct Tensor { + using Type = ABI::Windows::AI::MachineLearning::ITensorFloat16Bit; +}; +template <> +struct Tensor { + using Type = ABI::Windows::AI::MachineLearning::ITensorInt8Bit; +}; +template <> +struct Tensor { + using Type = ABI::Windows::AI::MachineLearning::ITensorUInt8Bit; +}; +template <> +struct Tensor { + using Type = ABI::Windows::AI::MachineLearning::ITensorUInt16Bit; +}; +template <> +struct Tensor { + using Type = ABI::Windows::AI::MachineLearning::ITensorInt16Bit; +}; +template <> +struct Tensor { + using Type = ABI::Windows::AI::MachineLearning::ITensorUInt32Bit; +}; +template <> +struct Tensor { + using Type = ABI::Windows::AI::MachineLearning::ITensorInt32Bit; +}; +template <> +struct Tensor { + using Type = ABI::Windows::AI::MachineLearning::ITensorUInt64Bit; +}; +template <> +struct Tensor { + using Type = ABI::Windows::AI::MachineLearning::ITensorInt64Bit; +}; +template <> +struct Tensor { + using Type = ABI::Windows::AI::MachineLearning::ITensorBoolean; +}; +template <> +struct Tensor { + using Type = ABI::Windows::AI::MachineLearning::ITensorDouble; +}; - using DllGetActivationFactory = HRESULT __stdcall(HSTRING, void** factory); - auto call = reinterpret_cast(GetProcAddress(library, "DllGetActivationFactory")); - if (!call) - { - auto hr = HRESULT_FROM_WIN32(GetLastError()); - FreeLibrary(library); - return hr; - } +template +struct TensorRuntimeClassID {}; +template <> +struct TensorRuntimeClassID { + static const wchar_t* RuntimeClass_ID; +}; +template <> +struct TensorRuntimeClassID { + static const wchar_t* RuntimeClass_ID; +}; +template <> +struct TensorRuntimeClassID { + static const wchar_t* RuntimeClass_ID; +}; +template <> +struct TensorRuntimeClassID { + static const wchar_t* RuntimeClass_ID; +}; +template <> +struct TensorRuntimeClassID { + static const wchar_t* RuntimeClass_ID; +}; +template <> +struct TensorRuntimeClassID { + static const wchar_t* RuntimeClass_ID; +}; +template <> +struct TensorRuntimeClassID { + static const wchar_t* RuntimeClass_ID; +}; +template <> +struct TensorRuntimeClassID { + static const wchar_t* RuntimeClass_ID; +}; +template <> +struct TensorRuntimeClassID { + static const wchar_t* RuntimeClass_ID; +}; +template <> +struct TensorRuntimeClassID { + static const wchar_t* RuntimeClass_ID; +}; +template <> +struct TensorRuntimeClassID { + static const wchar_t* RuntimeClass_ID; +}; +template <> +struct TensorRuntimeClassID { + static const wchar_t* RuntimeClass_ID; +}; - Microsoft::WRL::ComPtr activation_factory; - auto hr = call( - Microsoft::WRL::Wrappers::HStringReference(p_class_id, static_cast(wcslen(p_class_id))).Get(), - reinterpret_cast(activation_factory.GetAddressOf())); +__declspec(selectany +) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Windows_AI_MachineLearning_TensorFloat; +__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = + RuntimeClass_Windows_AI_MachineLearning_TensorFloat16Bit; +__declspec(selectany +) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Windows_AI_MachineLearning_TensorInt8Bit; +__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = + RuntimeClass_Windows_AI_MachineLearning_TensorUInt8Bit; +__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = + RuntimeClass_Windows_AI_MachineLearning_TensorUInt16Bit; +__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = + RuntimeClass_Windows_AI_MachineLearning_TensorInt16Bit; +__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = + RuntimeClass_Windows_AI_MachineLearning_TensorUInt32Bit; +__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = + RuntimeClass_Windows_AI_MachineLearning_TensorInt32Bit; +__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = + RuntimeClass_Windows_AI_MachineLearning_TensorUInt64Bit; +__declspec(selectany) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = + RuntimeClass_Windows_AI_MachineLearning_TensorInt64Bit; +__declspec(selectany +) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Windows_AI_MachineLearning_TensorBoolean; +__declspec(selectany +) const wchar_t* TensorRuntimeClassID::RuntimeClass_ID = RuntimeClass_Windows_AI_MachineLearning_TensorDouble; + +template +struct TensorFactory {}; +template <> +struct TensorFactory { + using Factory = ABI::Windows::AI::MachineLearning::ITensorFloatStatics; +}; +template <> +struct TensorFactory { + using Factory = ABI::Windows::AI::MachineLearning::ITensorFloat16BitStatics; +}; +template <> +struct TensorFactory { + using Factory = ABI::Windows::AI::MachineLearning::ITensorInt8BitStatics; +}; +template <> +struct TensorFactory { + using Factory = ABI::Windows::AI::MachineLearning::ITensorUInt8BitStatics; +}; +template <> +struct TensorFactory { + using Factory = ABI::Windows::AI::MachineLearning::ITensorUInt16BitStatics; +}; +template <> +struct TensorFactory { + using Factory = ABI::Windows::AI::MachineLearning::ITensorInt16BitStatics; +}; +template <> +struct TensorFactory { + using Factory = ABI::Windows::AI::MachineLearning::ITensorUInt32BitStatics; +}; +template <> +struct TensorFactory { + using Factory = ABI::Windows::AI::MachineLearning::ITensorInt32BitStatics; +}; +template <> +struct TensorFactory { + using Factory = ABI::Windows::AI::MachineLearning::ITensorUInt64BitStatics; +}; +template <> +struct TensorFactory { + using Factory = ABI::Windows::AI::MachineLearning::ITensorInt64BitStatics; +}; +template <> +struct TensorFactory { + using Factory = ABI::Windows::AI::MachineLearning::ITensorBooleanStatics; +}; +template <> +struct TensorFactory { + using Factory = ABI::Windows::AI::MachineLearning::ITensorDoubleStatics; +}; - if (FAILED(hr)) - { - FreeLibrary(library); - return hr; - } +template +struct TensorFactory2 {}; +template <> +struct TensorFactory2 { + using Factory = ABI::Windows::AI::MachineLearning::ITensorFloatStatics2; +}; +template <> +struct TensorFactory2 { + using Factory = ABI::Windows::AI::MachineLearning::ITensorFloat16BitStatics2; +}; +template <> +struct TensorFactory2 { + using Factory = ABI::Windows::AI::MachineLearning::ITensorInt8BitStatics2; +}; +template <> +struct TensorFactory2 { + using Factory = ABI::Windows::AI::MachineLearning::ITensorUInt8BitStatics2; +}; +template <> +struct TensorFactory2 { + using Factory = ABI::Windows::AI::MachineLearning::ITensorUInt16BitStatics2; +}; +template <> +struct TensorFactory2 { + using Factory = ABI::Windows::AI::MachineLearning::ITensorInt16BitStatics2; +}; +template <> +struct TensorFactory2 { + using Factory = ABI::Windows::AI::MachineLearning::ITensorUInt32BitStatics2; +}; +template <> +struct TensorFactory2 { + using Factory = ABI::Windows::AI::MachineLearning::ITensorInt32BitStatics2; +}; +template <> +struct TensorFactory2 { + using Factory = ABI::Windows::AI::MachineLearning::ITensorUInt64BitStatics2; +}; +template <> +struct TensorFactory2 { + using Factory = ABI::Windows::AI::MachineLearning::ITensorInt64BitStatics2; +}; +template <> +struct TensorFactory2 { + using Factory = ABI::Windows::AI::MachineLearning::ITensorBooleanStatics2; +}; +template <> +struct TensorFactory2 { + using Factory = ABI::Windows::AI::MachineLearning::ITensorDoubleStatics2; +}; - return activation_factory->QueryInterface(iid, factory); +template +struct TensorFactoryIID {}; +template <> +struct TensorFactoryIID { + static const GUID IID; +}; +template <> +struct TensorFactoryIID { + static const GUID IID; +}; +template <> +struct TensorFactoryIID { + static const GUID IID; +}; +template <> +struct TensorFactoryIID { + static const GUID IID; +}; +template <> +struct TensorFactoryIID { + static const GUID IID; +}; +template <> +struct TensorFactoryIID { + static const GUID IID; +}; +template <> +struct TensorFactoryIID { + static const GUID IID; +}; +template <> +struct TensorFactoryIID { + static const GUID IID; +}; +template <> +struct TensorFactoryIID { + static const GUID IID; +}; +template <> +struct TensorFactoryIID { + static const GUID IID; +}; +template <> +struct TensorFactoryIID { + static const GUID IID; +}; +template <> +struct TensorFactoryIID { + static const GUID IID; +}; + +__declspec(selectany +) const GUID TensorFactoryIID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorFloatStatics; +__declspec(selectany +) const GUID TensorFactoryIID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorFloat16BitStatics; +__declspec(selectany +) const GUID TensorFactoryIID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorInt8BitStatics; +__declspec(selectany +) const GUID TensorFactoryIID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorUInt8BitStatics; +__declspec(selectany +) const GUID TensorFactoryIID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorUInt16BitStatics; +__declspec(selectany +) const GUID TensorFactoryIID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorInt16BitStatics; +__declspec(selectany +) const GUID TensorFactoryIID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorUInt32BitStatics; +__declspec(selectany +) const GUID TensorFactoryIID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorInt32BitStatics; +__declspec(selectany +) const GUID TensorFactoryIID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorUInt64BitStatics; +__declspec(selectany +) const GUID TensorFactoryIID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorInt64BitStatics; +__declspec(selectany +) const GUID TensorFactoryIID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorBooleanStatics; +__declspec(selectany +) const GUID TensorFactoryIID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorDoubleStatics; + +template +struct TensorFactory2IID {}; +template <> +struct TensorFactory2IID { + static const GUID IID; +}; +template <> +struct TensorFactory2IID { + static const GUID IID; +}; +template <> +struct TensorFactory2IID { + static const GUID IID; +}; +template <> +struct TensorFactory2IID { + static const GUID IID; +}; +template <> +struct TensorFactory2IID { + static const GUID IID; +}; +template <> +struct TensorFactory2IID { + static const GUID IID; +}; +template <> +struct TensorFactory2IID { + static const GUID IID; +}; +template <> +struct TensorFactory2IID { + static const GUID IID; +}; +template <> +struct TensorFactory2IID { + static const GUID IID; +}; +template <> +struct TensorFactory2IID { + static const GUID IID; +}; +template <> +struct TensorFactory2IID { + static const GUID IID; +}; +template <> +struct TensorFactory2IID { + static const GUID IID; +}; + +__declspec(selectany +) const GUID TensorFactory2IID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorFloatStatics2; +__declspec(selectany +) const GUID TensorFactory2IID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorFloat16BitStatics2; +__declspec(selectany +) const GUID TensorFactory2IID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorInt8BitStatics2; +__declspec(selectany +) const GUID TensorFactory2IID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorUInt8BitStatics2; +__declspec(selectany +) const GUID TensorFactory2IID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorUInt16BitStatics2; +__declspec(selectany +) const GUID TensorFactory2IID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorInt16BitStatics2; +__declspec(selectany +) const GUID TensorFactory2IID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorUInt32BitStatics2; +__declspec(selectany +) const GUID TensorFactory2IID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorInt32BitStatics2; +__declspec(selectany +) const GUID TensorFactory2IID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorUInt64BitStatics2; +__declspec(selectany +) const GUID TensorFactory2IID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorInt64BitStatics2; +__declspec(selectany +) const GUID TensorFactory2IID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorBooleanStatics2; +__declspec(selectany +) const GUID TensorFactory2IID::IID = ABI::Windows::AI::MachineLearning::IID_ITensorDoubleStatics2; + +inline HRESULT GetActivationFactory(const wchar_t* p_class_id, const IID& iid, void** factory) noexcept { + // Fallback to OS binary if the redistributable is not present! + auto library = LoadLibraryExW(MachineLearningDll, nullptr, 0); + + using DllGetActivationFactory = HRESULT __stdcall(HSTRING, void** factory); + auto call = reinterpret_cast(GetProcAddress(library, "DllGetActivationFactory")); + if (!call) { + auto hr = HRESULT_FROM_WIN32(GetLastError()); + FreeLibrary(library); + return hr; + } + + Microsoft::WRL::ComPtr activation_factory; + auto hr = call( + Microsoft::WRL::Wrappers::HStringReference(p_class_id, static_cast(wcslen(p_class_id))).Get(), + reinterpret_cast(activation_factory.GetAddressOf()) + ); + + if (FAILED(hr)) { + FreeLibrary(library); + return hr; + } + + return activation_factory->QueryInterface(iid, factory); } -class WinMLLearningModel -{ - friend class WinMLLearningModelSession; +class WinMLLearningModel { + friend class WinMLLearningModelSession; + + public: + WinMLLearningModel(const wchar_t* model_path, size_t size) { ML_FAIL_FAST_IF(0 != Initialize(model_path, size)); } + + WinMLLearningModel(const char* bytes, size_t size) { + ML_FAIL_FAST_IF(0 != Initialize(bytes, size, false /*with_copy*/)); + } + + private: + int32_t Initialize(const wchar_t* model_path, size_t size) { + Microsoft::WRL::ComPtr learningModel; + RETURN_HR_IF_FAILED(GetActivationFactory( + RuntimeClass_Windows_AI_MachineLearning_LearningModel, + ABI::Windows::AI::MachineLearning::IID_ILearningModelStatics, + &learningModel + )); + + RETURN_HR_IF_FAILED(learningModel->LoadFromFilePath( + Microsoft::WRL::Wrappers::HStringReference(model_path, static_cast(size)).Get(), + m_learning_model.GetAddressOf() + )); + return 0; + } -public: - WinMLLearningModel(const wchar_t* model_path, size_t size) - { - ML_FAIL_FAST_IF(0 != Initialize(model_path, size)); - } + struct StoreCompleted : Microsoft::WRL::RuntimeClass< + Microsoft::WRL::RuntimeClassFlags, + ABI::Windows::Foundation::IAsyncOperationCompletedHandler> { + HANDLE completed_event_; - WinMLLearningModel(const char* bytes, size_t size) - { - ML_FAIL_FAST_IF(0 != Initialize(bytes, size, false /*with_copy*/)); + StoreCompleted() : completed_event_(CreateEvent(nullptr, true, false, nullptr)) {} + + ~StoreCompleted() { CloseHandle(completed_event_); } + + HRESULT STDMETHODCALLTYPE Invoke( + ABI::Windows::Foundation::IAsyncOperation* asyncInfo, ABI::Windows::Foundation::AsyncStatus status + ) { + SetEvent(completed_event_); + return S_OK; } -private: - int32_t Initialize(const wchar_t* model_path, size_t size) - { - Microsoft::WRL::ComPtr learningModel; - RETURN_HR_IF_FAILED( - GetActivationFactory( - RuntimeClass_Windows_AI_MachineLearning_LearningModel, - ABI::Windows::AI::MachineLearning::IID_ILearningModelStatics, - &learningModel)); - - RETURN_HR_IF_FAILED( - learningModel->LoadFromFilePath( - Microsoft::WRL::Wrappers::HStringReference(model_path, static_cast(size)).Get(), - m_learning_model.GetAddressOf())); - return 0; + HRESULT Wait() { + WaitForSingleObject(completed_event_, INFINITE); + return S_OK; + } + }; + + int32_t Initialize(const char* bytes, size_t size, bool with_copy = false) { + RoInitialize(RO_INIT_TYPE::RO_INIT_SINGLETHREADED); + + Microsoft::WRL::ComPtr random_access_stream_ref; + if (with_copy) { + // Create in memory stream + Microsoft::WRL::ComPtr in_memory_random_access_stream_insp; + RETURN_HR_IF_FAILED(RoActivateInstance( + Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_Storage_Streams_InMemoryRandomAccessStream) + .Get(), + in_memory_random_access_stream_insp.GetAddressOf() + )); + + // QI memory stream to output stream + Microsoft::WRL::ComPtr output_stream; + RETURN_HR_IF_FAILED(in_memory_random_access_stream_insp.As(&output_stream)); + + // Create data writer factory + Microsoft::WRL::ComPtr activation_factory; + RETURN_HR_IF_FAILED(RoGetActivationFactory( + Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_Storage_Streams_DataWriter).Get(), + IID_PPV_ARGS(activation_factory.GetAddressOf()) + )); + + // Create data writer object based on the in memory stream + Microsoft::WRL::ComPtr data_writer; + RETURN_HR_IF_FAILED(activation_factory->CreateDataWriter(output_stream.Get(), data_writer.GetAddressOf())); + + // Write the model to the data writer and thus to the stream + RETURN_HR_IF_FAILED( + data_writer->WriteBytes(static_cast(size), reinterpret_cast(const_cast(bytes))) + ); + + // QI the in memory stream to a random access stream + Microsoft::WRL::ComPtr random_access_stream; + RETURN_HR_IF_FAILED(in_memory_random_access_stream_insp.As(&random_access_stream)); + + // Create a random access stream reference factory + Microsoft::WRL::ComPtr + random_access_stream_ref_statics; + RETURN_HR_IF_FAILED(RoGetActivationFactory( + Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_Storage_Streams_RandomAccessStreamReference) + .Get(), + IID_PPV_ARGS(random_access_stream_ref_statics.GetAddressOf()) + )); + + // Create a random access stream reference from the random access stream view on top of + // the in memory stream + RETURN_HR_IF_FAILED(random_access_stream_ref_statics->CreateFromStream( + random_access_stream.Get(), random_access_stream_ref.GetAddressOf() + )); + } else { + Microsoft::WRL::ComPtr> buffer; + RETURN_HR_IF_FAILED(Microsoft::WRL::MakeAndInitialize>(&buffer, bytes, bytes + size)); + + RETURN_HR_IF_FAILED(Microsoft::WRL::MakeAndInitialize( + &random_access_stream_ref, buffer.Get() + )); } - struct StoreCompleted : - Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags, - ABI::Windows::Foundation::IAsyncOperationCompletedHandler> - { - HANDLE completed_event_; - - StoreCompleted() : - completed_event_(CreateEvent(nullptr, true, false, nullptr)) - {} - - ~StoreCompleted() - { - CloseHandle(completed_event_); - } - - HRESULT STDMETHODCALLTYPE Invoke( - ABI::Windows::Foundation::IAsyncOperation *asyncInfo, - ABI::Windows::Foundation::AsyncStatus status) - { - SetEvent(completed_event_); - return S_OK; - } - - HRESULT Wait() - { - WaitForSingleObject(completed_event_, INFINITE); - return S_OK; - } - }; + // Create a learning model factory + Microsoft::WRL::ComPtr learning_model; + RETURN_HR_IF_FAILED(GetActivationFactory( + RuntimeClass_Windows_AI_MachineLearning_LearningModel, + ABI::Windows::AI::MachineLearning::IID_ILearningModelStatics, + &learning_model + )); + + Microsoft::WRL::ComPtr> async_operation; + RETURN_HR_IF_FAILED(data_writer->StoreAsync(&async_operation)); + auto store_completed_handler = Microsoft::WRL::Make(); + RETURN_HR_IF_FAILED(async_operation->put_Completed(store_completed_handler.Get())); + RETURN_HR_IF_FAILED(store_completed_handler->Wait()); + + // Create a learning model from the factory with the random access stream reference that points + // to the random access stream view on top of the in memory stream copy of the model + RETURN_HR_IF_FAILED(learning_model->LoadFromStream(random_access_stream_ref.Get(), m_learning_model.GetAddressOf()) + ); - int32_t Initialize(const char* bytes, size_t size, bool with_copy = false) - { - RoInitialize(RO_INIT_TYPE::RO_INIT_SINGLETHREADED); - - Microsoft::WRL::ComPtr random_access_stream_ref; - if (with_copy) { - // Create in memory stream - Microsoft::WRL::ComPtr in_memory_random_access_stream_insp; - RETURN_HR_IF_FAILED(RoActivateInstance( - Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_Storage_Streams_InMemoryRandomAccessStream).Get(), - in_memory_random_access_stream_insp.GetAddressOf())); - - // QI memory stream to output stream - Microsoft::WRL::ComPtr output_stream; - RETURN_HR_IF_FAILED(in_memory_random_access_stream_insp.As(&output_stream)); - - // Create data writer factory - Microsoft::WRL::ComPtr activation_factory; - RETURN_HR_IF_FAILED(RoGetActivationFactory( - Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_Storage_Streams_DataWriter).Get(), - IID_PPV_ARGS(activation_factory.GetAddressOf()))); - - // Create data writer object based on the in memory stream - Microsoft::WRL::ComPtr data_writer; - RETURN_HR_IF_FAILED(activation_factory->CreateDataWriter( - output_stream.Get(), - data_writer.GetAddressOf())); - - // Write the model to the data writer and thus to the stream - RETURN_HR_IF_FAILED( - data_writer->WriteBytes(static_cast(size), reinterpret_cast(const_cast(bytes)))); - - // QI the in memory stream to a random access stream - Microsoft::WRL::ComPtr random_access_stream; - RETURN_HR_IF_FAILED(in_memory_random_access_stream_insp.As(&random_access_stream)); - - // Create a random access stream reference factory - Microsoft::WRL::ComPtr random_access_stream_ref_statics; - RETURN_HR_IF_FAILED(RoGetActivationFactory( - Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_Storage_Streams_RandomAccessStreamReference).Get(), - IID_PPV_ARGS(random_access_stream_ref_statics.GetAddressOf()))); - - // Create a random access stream reference from the random access stream view on top of - // the in memory stream - RETURN_HR_IF_FAILED(random_access_stream_ref_statics->CreateFromStream( - random_access_stream.Get(), - random_access_stream_ref.GetAddressOf())); - } else { - Microsoft::WRL::ComPtr> buffer; - RETURN_HR_IF_FAILED( - Microsoft::WRL::MakeAndInitialize>( - &buffer, bytes, bytes + size)); - - RETURN_HR_IF_FAILED( - Microsoft::WRL::MakeAndInitialize( - &random_access_stream_ref, buffer.Get())); - } - - // Create a learning model factory - Microsoft::WRL::ComPtr learning_model; - RETURN_HR_IF_FAILED( - GetActivationFactory( - RuntimeClass_Windows_AI_MachineLearning_LearningModel, - ABI::Windows::AI::MachineLearning::IID_ILearningModelStatics, - &learning_model)); - - Microsoft::WRL::ComPtr> async_operation; - RETURN_HR_IF_FAILED(data_writer->StoreAsync(&async_operation)); - auto store_completed_handler = Microsoft::WRL::Make(); - RETURN_HR_IF_FAILED(async_operation->put_Completed(store_completed_handler.Get())); - RETURN_HR_IF_FAILED(store_completed_handler->Wait()); - - // Create a learning model from the factory with the random access stream reference that points - // to the random access stream view on top of the in memory stream copy of the model - RETURN_HR_IF_FAILED( - learning_model->LoadFromStream( - random_access_stream_ref.Get(), - m_learning_model.GetAddressOf())); - - return 0; - } + return 0; + } -private: - Microsoft::WRL::ComPtr m_learning_model; + private: + Microsoft::WRL::ComPtr m_learning_model; }; -class WinMLLearningModelResults -{ - friend class WinMLLearningModelSession; +class WinMLLearningModelResults { + friend class WinMLLearningModelSession; -public: - int32_t get_output( - const wchar_t* feature_name, - size_t feature_name_size, - void** pp_buffer, - size_t* p_capacity) - { - Microsoft::WRL::ComPtr> output_map; - RETURN_HR_IF_FAILED(m_result->get_Outputs(&output_map)); + public: + int32_t get_output(const wchar_t* feature_name, size_t feature_name_size, void** pp_buffer, size_t* p_capacity) { + Microsoft::WRL::ComPtr> output_map; + RETURN_HR_IF_FAILED(m_result->get_Outputs(&output_map)); - Microsoft::WRL::ComPtr inspectable; - RETURN_HR_IF_FAILED(output_map->Lookup( - Microsoft::WRL::Wrappers::HStringReference(feature_name, static_cast(feature_name_size)).Get(), - inspectable.GetAddressOf())); + Microsoft::WRL::ComPtr inspectable; + RETURN_HR_IF_FAILED(output_map->Lookup( + Microsoft::WRL::Wrappers::HStringReference(feature_name, static_cast(feature_name_size)).Get(), + inspectable.GetAddressOf() + )); - Microsoft::WRL::ComPtr output_feature_value; - RETURN_HR_IF_FAILED(inspectable.As(&output_feature_value)); + Microsoft::WRL::ComPtr output_feature_value; + RETURN_HR_IF_FAILED(inspectable.As(&output_feature_value)); - Microsoft::WRL::ComPtr native_tensor_float_feature_value; - RETURN_HR_IF_FAILED(output_feature_value.As(&native_tensor_float_feature_value)); + Microsoft::WRL::ComPtr native_tensor_float_feature_value; + RETURN_HR_IF_FAILED(output_feature_value.As(&native_tensor_float_feature_value)); - uint32_t size; - RETURN_HR_IF_FAILED(native_tensor_float_feature_value->GetBuffer(reinterpret_cast(pp_buffer), &size)); - *p_capacity = size; + uint32_t size; + RETURN_HR_IF_FAILED(native_tensor_float_feature_value->GetBuffer(reinterpret_cast(pp_buffer), &size)); + *p_capacity = size; - return 0; - } + return 0; + } -private: - WinMLLearningModelResults(ABI::Windows::AI::MachineLearning::ILearningModelEvaluationResult* p_result) - { - m_result = p_result; - } + private: + WinMLLearningModelResults(ABI::Windows::AI::MachineLearning::ILearningModelEvaluationResult* p_result) { + m_result = p_result; + } -private: - Microsoft::WRL::ComPtr< ABI::Windows::AI::MachineLearning::ILearningModelEvaluationResult> m_result; + private: + Microsoft::WRL::ComPtr m_result; }; -class WinMLLearningModelBinding -{ - friend class WinMLLearningModelSession; - -public: - WinMLLearningModelBinding(const WinMLLearningModelSession& session) - { - ML_FAIL_FAST_IF(0 != Initialize(session)); - } - - template - int32_t bind( - const wchar_t* feature_name, size_t feature_name_size, - tensor_shape_type* p_shape, size_t shape_size, - T* p_data, size_t data_size) - { - using ITensor = typename Tensor::Type; - using ITensorFactory = typename TensorFactory::Factory; - - Microsoft::WRL::ComPtr tensor_factory; - RETURN_HR_IF_FAILED( - GetActivationFactory( - TensorRuntimeClassID::RuntimeClass_ID, - TensorFactoryIID::IID, - &tensor_factory)); - - Microsoft::WRL::ComPtr> input_shape_iterable; - RETURN_HR_IF_FAILED( - Microsoft::WRL::MakeAndInitialize>( - &input_shape_iterable, p_shape, p_shape + shape_size)); - - Microsoft::WRL::ComPtr tensor; - RETURN_HR_IF_FAILED( - tensor_factory->CreateFromArray( - input_shape_iterable.Get(), - static_cast(data_size), - p_data, - tensor.GetAddressOf())); - - Microsoft::WRL::ComPtr inspectable_tensor; - RETURN_HR_IF_FAILED(tensor.As(&inspectable_tensor)); - - RETURN_HR_IF_FAILED( - m_learning_model_binding->Bind( - Microsoft::WRL::Wrappers::HStringReference(feature_name, static_cast(feature_name_size)).Get(), - inspectable_tensor.Get())); - return 0; - } +class WinMLLearningModelBinding { + friend class WinMLLearningModelSession; + + public: + WinMLLearningModelBinding(const WinMLLearningModelSession& session) { ML_FAIL_FAST_IF(0 != Initialize(session)); } + + template + int32_t bind( + const wchar_t* feature_name, + size_t feature_name_size, + tensor_shape_type* p_shape, + size_t shape_size, + T* p_data, + size_t data_size + ) { + using ITensor = typename Tensor::Type; + using ITensorFactory = typename TensorFactory::Factory; + + Microsoft::WRL::ComPtr tensor_factory; + RETURN_HR_IF_FAILED( + GetActivationFactory(TensorRuntimeClassID::RuntimeClass_ID, TensorFactoryIID::IID, &tensor_factory) + ); + + Microsoft::WRL::ComPtr> input_shape_iterable; + RETURN_HR_IF_FAILED(Microsoft::WRL::MakeAndInitialize>( + &input_shape_iterable, p_shape, p_shape + shape_size + )); + + Microsoft::WRL::ComPtr tensor; + RETURN_HR_IF_FAILED(tensor_factory->CreateFromArray( + input_shape_iterable.Get(), static_cast(data_size), p_data, tensor.GetAddressOf() + )); + + Microsoft::WRL::ComPtr inspectable_tensor; + RETURN_HR_IF_FAILED(tensor.As(&inspectable_tensor)); + + RETURN_HR_IF_FAILED(m_learning_model_binding->Bind( + Microsoft::WRL::Wrappers::HStringReference(feature_name, static_cast(feature_name_size)).Get(), + inspectable_tensor.Get() + )); + return 0; + } - template - int32_t bind( - const wchar_t* /*feature_name*/, size_t /*feature_name_size*/, - tensor_shape_type* /*p_shape*/, size_t /*shape_size*/) - { - return 0; - } + template + int32_t bind( + const wchar_t* /*feature_name*/, size_t /*feature_name_size*/, tensor_shape_type* /*p_shape*/, size_t /*shape_size*/ + ) { + return 0; + } + + template + int32_t bind_as_reference( + const wchar_t* feature_name, + size_t feature_name_size, + tensor_shape_type* p_shape, + size_t shape_size, + T* p_data, + size_t data_size + ) { + using ITensor = typename Tensor::Type; + using ITensorFactory = typename TensorFactory2::Factory; + + Microsoft::WRL::ComPtr tensor_factory; + RETURN_HR_IF_FAILED( + GetActivationFactory(TensorRuntimeClassID::RuntimeClass_ID, TensorFactory2IID::IID, &tensor_factory) + ); - template - int32_t bind_as_reference( - const wchar_t* feature_name, size_t feature_name_size, - tensor_shape_type* p_shape, size_t shape_size, - T* p_data, size_t data_size) - { - using ITensor = typename Tensor::Type; - using ITensorFactory = typename TensorFactory2::Factory; - - Microsoft::WRL::ComPtr tensor_factory; - RETURN_HR_IF_FAILED( - GetActivationFactory( - TensorRuntimeClassID::RuntimeClass_ID, - TensorFactory2IID::IID, - &tensor_factory)); - - Microsoft::WRL::ComPtr> buffer; - RETURN_HR_IF_FAILED( - Microsoft::WRL::MakeAndInitialize>( - &buffer, p_data, p_data + data_size)); - - Microsoft::WRL::ComPtr tensor; - RETURN_HR_IF_FAILED( - tensor_factory->CreateFromBuffer( - static_cast(shape_size), - p_shape, - buffer.Get(), - tensor.GetAddressOf())); - - Microsoft::WRL::ComPtr inspectable_tensor; - RETURN_HR_IF_FAILED(tensor.As(&inspectable_tensor)); - - RETURN_HR_IF_FAILED( - m_learning_model_binding->Bind( - Microsoft::WRL::Wrappers::HStringReference(feature_name, static_cast(feature_name_size)).Get(), - inspectable_tensor.Get())); - return 0; - } + Microsoft::WRL::ComPtr> buffer; + RETURN_HR_IF_FAILED(Microsoft::WRL::MakeAndInitialize>(&buffer, p_data, p_data + data_size) + ); - template - int32_t bind_as_references( - const wchar_t* feature_name, size_t feature_name_size, - T** p_data, size_t* data_sizes, - size_t num_buffers) { - using ITensor = typename Tensor::Type; - using ITensorFactory = typename TensorFactory2::Factory; - - std::vector> vec_buffers(num_buffers); - for (size_t i = 0; i < num_buffers; i++) { - RETURN_HR_IF_FAILED( - Microsoft::WRL::MakeAndInitialize>( - &vec_buffers.at(i), p_data[i], p_data[i] + data_sizes[i])); - } - - std::vector raw_buffers(num_buffers); - std::transform(std::begin(vec_buffers), std::end(vec_buffers), std::begin(raw_buffers), - [](auto buffer) { return buffer.Get(); }); - - Microsoft::WRL::ComPtr> buffers; - RETURN_HR_IF_FAILED( - Microsoft::WRL::MakeAndInitialize>( - &buffers, raw_buffers, raw_buffers + num_buffers)); + Microsoft::WRL::ComPtr tensor; + RETURN_HR_IF_FAILED( + tensor_factory->CreateFromBuffer(static_cast(shape_size), p_shape, buffer.Get(), tensor.GetAddressOf()) + ); - Microsoft::WRL::ComPtr inspectable_tensor; - RETURN_HR_IF_FAILED(buffers.As(&inspectable_tensor)); + Microsoft::WRL::ComPtr inspectable_tensor; + RETURN_HR_IF_FAILED(tensor.As(&inspectable_tensor)); - RETURN_HR_IF_FAILED( - m_learning_model_binding->Bind( - Microsoft::WRL::Wrappers::HStringReference(feature_name, static_cast(feature_name_size)).Get(), - inspectable_tensor.Get())); - return 0; + RETURN_HR_IF_FAILED(m_learning_model_binding->Bind( + Microsoft::WRL::Wrappers::HStringReference(feature_name, static_cast(feature_name_size)).Get(), + inspectable_tensor.Get() + )); + return 0; + } + + template + int32_t bind_as_references( + const wchar_t* feature_name, size_t feature_name_size, T** p_data, size_t* data_sizes, size_t num_buffers + ) { + using ITensor = typename Tensor::Type; + using ITensorFactory = typename TensorFactory2::Factory; + + std::vector> vec_buffers(num_buffers); + for (size_t i = 0; i < num_buffers; i++) { + RETURN_HR_IF_FAILED(Microsoft::WRL::MakeAndInitialize>( + &vec_buffers.at(i), p_data[i], p_data[i] + data_sizes[i] + )); } + std::vector raw_buffers(num_buffers); + std::transform(std::begin(vec_buffers), std::end(vec_buffers), std::begin(raw_buffers), [](auto buffer) { + return buffer.Get(); + }); -private: - inline int32_t Initialize(const WinMLLearningModelSession& session); + Microsoft::WRL::ComPtr> buffers; + RETURN_HR_IF_FAILED( + Microsoft::WRL::MakeAndInitialize>( + &buffers, raw_buffers, raw_buffers + num_buffers + ) + ); + + Microsoft::WRL::ComPtr inspectable_tensor; + RETURN_HR_IF_FAILED(buffers.As(&inspectable_tensor)); + + RETURN_HR_IF_FAILED(m_learning_model_binding->Bind( + Microsoft::WRL::Wrappers::HStringReference(feature_name, static_cast(feature_name_size)).Get(), + inspectable_tensor.Get() + )); + return 0; + } -private: - Microsoft::WRL::ComPtr m_learning_model_binding; + private: + inline int32_t Initialize(const WinMLLearningModelSession& session); + + private: + Microsoft::WRL::ComPtr m_learning_model_binding; }; -class WinMLLearningModelDevice -{ - friend class WinMLLearningModelSession; +class WinMLLearningModelDevice { + friend class WinMLLearningModelSession; -public: - WinMLLearningModelDevice() : - WinMLLearningModelDevice(ABI::Windows::AI::MachineLearning::LearningModelDeviceKind_Default) - {} + public: + WinMLLearningModelDevice() + : WinMLLearningModelDevice(ABI::Windows::AI::MachineLearning::LearningModelDeviceKind_Default) {} - WinMLLearningModelDevice(WinMLLearningModelDevice&& device) : - m_learning_model_device(std::move(device.m_learning_model_device)) - {} + WinMLLearningModelDevice(WinMLLearningModelDevice&& device) + : m_learning_model_device(std::move(device.m_learning_model_device)) {} - WinMLLearningModelDevice(const WinMLLearningModelDevice& device) : - m_learning_model_device(device.m_learning_model_device) - {} + WinMLLearningModelDevice(const WinMLLearningModelDevice& device) + : m_learning_model_device(device.m_learning_model_device) {} - void operator=(const WinMLLearningModelDevice& device) - { - m_learning_model_device = device.m_learning_model_device; - } + void operator=(const WinMLLearningModelDevice& device) { m_learning_model_device = device.m_learning_model_device; } - WinMLLearningModelDevice(ABI::Windows::AI::MachineLearning::LearningModelDeviceKind kind) - { - ML_FAIL_FAST_IF(0 != Initialize(kind)); - } + WinMLLearningModelDevice(ABI::Windows::AI::MachineLearning::LearningModelDeviceKind kind) { + ML_FAIL_FAST_IF(0 != Initialize(kind)); + } - WinMLLearningModelDevice(ABI::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice* d3dDevice) - { - ML_FAIL_FAST_IF(0 != Initialize(d3dDevice)); - } + WinMLLearningModelDevice(ABI::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice* d3dDevice) { + ML_FAIL_FAST_IF(0 != Initialize(d3dDevice)); + } - WinMLLearningModelDevice(ID3D12CommandQueue* queue) - { - ML_FAIL_FAST_IF(0 != Initialize(queue)); - } + WinMLLearningModelDevice(ID3D12CommandQueue* queue) { ML_FAIL_FAST_IF(0 != Initialize(queue)); } - static WinMLLearningModelDevice create_cpu_device() - { - return WinMLLearningModelDevice(ABI::Windows::AI::MachineLearning::LearningModelDeviceKind_Cpu); - } + static WinMLLearningModelDevice create_cpu_device() { + return WinMLLearningModelDevice(ABI::Windows::AI::MachineLearning::LearningModelDeviceKind_Cpu); + } - static WinMLLearningModelDevice create_directx_device() - { - return WinMLLearningModelDevice(ABI::Windows::AI::MachineLearning::LearningModelDeviceKind_DirectX); - } + static WinMLLearningModelDevice create_directx_device() { + return WinMLLearningModelDevice(ABI::Windows::AI::MachineLearning::LearningModelDeviceKind_DirectX); + } - static WinMLLearningModelDevice create_directx_high_power_device() - { - return WinMLLearningModelDevice(ABI::Windows::AI::MachineLearning::LearningModelDeviceKind_DirectXHighPerformance); - } + static WinMLLearningModelDevice create_directx_high_power_device() { + return WinMLLearningModelDevice(ABI::Windows::AI::MachineLearning::LearningModelDeviceKind_DirectXHighPerformance); + } - static WinMLLearningModelDevice create_directx_min_power_device() - { - return WinMLLearningModelDevice(ABI::Windows::AI::MachineLearning::LearningModelDeviceKind_DirectXMinPower); - } + static WinMLLearningModelDevice create_directx_min_power_device() { + return WinMLLearningModelDevice(ABI::Windows::AI::MachineLearning::LearningModelDeviceKind_DirectXMinPower); + } - static WinMLLearningModelDevice create_directx_device(ABI::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice* d3dDevice) - { - return WinMLLearningModelDevice(d3dDevice); - } + static WinMLLearningModelDevice create_directx_device( + ABI::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice* d3dDevice + ) { + return WinMLLearningModelDevice(d3dDevice); + } - static WinMLLearningModelDevice create_directx_device(ID3D12CommandQueue* queue) - { - return WinMLLearningModelDevice(queue); - } + static WinMLLearningModelDevice create_directx_device(ID3D12CommandQueue* queue) { + return WinMLLearningModelDevice(queue); + } -private: - int32_t Initialize(ABI::Windows::AI::MachineLearning::LearningModelDeviceKind kind) - { - Microsoft::WRL::ComPtr - learning_model_device_factory; - RETURN_HR_IF_FAILED( - GetActivationFactory( - RuntimeClass_Windows_AI_MachineLearning_LearningModelDevice, - ABI::Windows::AI::MachineLearning::IID_ILearningModelDeviceFactory, - &learning_model_device_factory)); + private: + int32_t Initialize(ABI::Windows::AI::MachineLearning::LearningModelDeviceKind kind) { + Microsoft::WRL::ComPtr + learning_model_device_factory; + RETURN_HR_IF_FAILED(GetActivationFactory( + RuntimeClass_Windows_AI_MachineLearning_LearningModelDevice, + ABI::Windows::AI::MachineLearning::IID_ILearningModelDeviceFactory, + &learning_model_device_factory + )); - RETURN_HR_IF_FAILED(learning_model_device_factory->Create(kind, &m_learning_model_device)); + RETURN_HR_IF_FAILED(learning_model_device_factory->Create(kind, &m_learning_model_device)); - return 0; - } + return 0; + } - int32_t Initialize(ABI::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice* d3dDevice) - { - Microsoft::WRL::ComPtr - learning_model_device_factory; - RETURN_HR_IF_FAILED( - GetActivationFactory( - RuntimeClass_Windows_AI_MachineLearning_LearningModelDevice, - ABI::Windows::AI::MachineLearning::IID_ILearningModelDeviceStatics, - &learning_model_device_factory)); + int32_t Initialize(ABI::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice* d3dDevice) { + Microsoft::WRL::ComPtr + learning_model_device_factory; + RETURN_HR_IF_FAILED(GetActivationFactory( + RuntimeClass_Windows_AI_MachineLearning_LearningModelDevice, + ABI::Windows::AI::MachineLearning::IID_ILearningModelDeviceStatics, + &learning_model_device_factory + )); - RETURN_HR_IF_FAILED(learning_model_device_factory->CreateFromDirect3D11Device(d3dDevice, &m_learning_model_device)); + RETURN_HR_IF_FAILED(learning_model_device_factory->CreateFromDirect3D11Device(d3dDevice, &m_learning_model_device)); - return 0; - } + return 0; + } - int32_t Initialize(ID3D12CommandQueue* queue) - { - Microsoft::WRL::ComPtr - learning_model_device_factory; - RETURN_HR_IF_FAILED( - GetActivationFactory( - RuntimeClass_Windows_AI_MachineLearning_LearningModelDevice, - __uuidof(ILearningModelDeviceFactoryNative), - &learning_model_device_factory)); + int32_t Initialize(ID3D12CommandQueue* queue) { + Microsoft::WRL::ComPtr learning_model_device_factory; + RETURN_HR_IF_FAILED(GetActivationFactory( + RuntimeClass_Windows_AI_MachineLearning_LearningModelDevice, + __uuidof(ILearningModelDeviceFactoryNative), + &learning_model_device_factory + )); - RETURN_HR_IF_FAILED(learning_model_device_factory->CreateFromD3D12CommandQueue(queue, &m_learning_model_device)); + RETURN_HR_IF_FAILED(learning_model_device_factory->CreateFromD3D12CommandQueue(queue, &m_learning_model_device)); - return 0; - } + return 0; + } -private: - Microsoft::WRL::ComPtr m_learning_model_device; + private: + Microsoft::WRL::ComPtr m_learning_model_device; }; -class WinMLLearningModelSession -{ - friend class WinMLLearningModelBinding; +class WinMLLearningModelSession { + friend class WinMLLearningModelBinding; -public: - using Model = WinMLLearningModel; - using Device = WinMLLearningModelDevice; + public: + using Model = WinMLLearningModel; + using Device = WinMLLearningModelDevice; -public: - WinMLLearningModelSession(const Model& model) - { - ML_FAIL_FAST_IF(0 != Initialize(model, Device())); - } + public: + WinMLLearningModelSession(const Model& model) { ML_FAIL_FAST_IF(0 != Initialize(model, Device())); } - WinMLLearningModelSession(const Model& model, const Device& device) - { - ML_FAIL_FAST_IF(0 != Initialize(model, device)); - } + WinMLLearningModelSession(const Model& model, const Device& device) { + ML_FAIL_FAST_IF(0 != Initialize(model, device)); + } - WinMLLearningModelResults evaluate(WinMLLearningModelBinding& binding) - { - Microsoft::WRL::ComPtr - m_learning_model_evaluation_result; + WinMLLearningModelResults evaluate(WinMLLearningModelBinding& binding) { + Microsoft::WRL::ComPtr + m_learning_model_evaluation_result; - FAIL_FAST_IF_HR_FAILED( - m_learning_model_session->Evaluate( - binding.m_learning_model_binding.Get(), - nullptr, - m_learning_model_evaluation_result.GetAddressOf())); + FAIL_FAST_IF_HR_FAILED(m_learning_model_session->Evaluate( + binding.m_learning_model_binding.Get(), nullptr, m_learning_model_evaluation_result.GetAddressOf() + )); - return WinMLLearningModelResults(m_learning_model_evaluation_result.Get()); - } + return WinMLLearningModelResults(m_learning_model_evaluation_result.Get()); + } -private: - int32_t Initialize(const Model& model, const Device& device) - { - // {0f6b881d-1c9b-47b6-bfe0-f1cf62a67579} - static const GUID IID_ILearningModelSessionFactory = - { 0x0f6b881d, 0x1c9b, 0x47b6, { 0xbf, 0xe0, 0xf1, 0xcf, 0x62, 0xa6, 0x75, 0x79 } }; - - Microsoft::WRL::ComPtr - m_learning_model_session_factory; - RETURN_HR_IF_FAILED( - GetActivationFactory( - RuntimeClass_Windows_AI_MachineLearning_LearningModelSession, - IID_ILearningModelSessionFactory, - &m_learning_model_session_factory)); - - RETURN_HR_IF_FAILED( - m_learning_model_session_factory->CreateFromModelOnDevice( - model.m_learning_model.Get(), - device.m_learning_model_device.Get(), - m_learning_model_session.GetAddressOf())); - - return 0; - } + private: + int32_t Initialize(const Model& model, const Device& device) { + // {0f6b881d-1c9b-47b6-bfe0-f1cf62a67579} + static const GUID IID_ILearningModelSessionFactory = { + 0x0f6b881d, 0x1c9b, 0x47b6, {0xbf, 0xe0, 0xf1, 0xcf, 0x62, 0xa6, 0x75, 0x79} + }; + + Microsoft::WRL::ComPtr + m_learning_model_session_factory; + RETURN_HR_IF_FAILED(GetActivationFactory( + RuntimeClass_Windows_AI_MachineLearning_LearningModelSession, + IID_ILearningModelSessionFactory, + &m_learning_model_session_factory + )); + + RETURN_HR_IF_FAILED(m_learning_model_session_factory->CreateFromModelOnDevice( + model.m_learning_model.Get(), device.m_learning_model_device.Get(), m_learning_model_session.GetAddressOf() + )); + + return 0; + } -private: - Microsoft::WRL::ComPtr m_learning_model_session; + private: + Microsoft::WRL::ComPtr m_learning_model_session; }; -inline int32_t WinMLLearningModelBinding::Initialize(const WinMLLearningModelSession& session) -{ - // {c95f7a7a-e788-475e-8917-23aa381faf0b} - static const GUID IID_ILearningModelBindingFactory = - { 0xc95f7a7a, 0xe788, 0x475e, { 0x89, 0x17, 0x23, 0xaa, 0x38, 0x1f, 0xaf, 0x0b } }; +inline int32_t WinMLLearningModelBinding::Initialize(const WinMLLearningModelSession& session) { + // {c95f7a7a-e788-475e-8917-23aa381faf0b} + static const GUID IID_ILearningModelBindingFactory = { + 0xc95f7a7a, 0xe788, 0x475e, {0x89, 0x17, 0x23, 0xaa, 0x38, 0x1f, 0xaf, 0x0b} + }; - Microsoft::WRL::ComPtr - learning_model_binding_factory; + Microsoft::WRL::ComPtr + learning_model_binding_factory; - RETURN_HR_IF_FAILED( - GetActivationFactory( - RuntimeClass_Windows_AI_MachineLearning_LearningModelBinding, - IID_ILearningModelBindingFactory, - &learning_model_binding_factory)); + RETURN_HR_IF_FAILED(GetActivationFactory( + RuntimeClass_Windows_AI_MachineLearning_LearningModelBinding, + IID_ILearningModelBindingFactory, + &learning_model_binding_factory + )); - RETURN_HR_IF_FAILED( - learning_model_binding_factory->CreateFromSession( - session.m_learning_model_session.Get(), - m_learning_model_binding.GetAddressOf())); + RETURN_HR_IF_FAILED(learning_model_binding_factory->CreateFromSession( + session.m_learning_model_session.Get(), m_learning_model_binding.GetAddressOf() + )); - return 0; + return 0; } -}}}} // namespace Microsoft::AI::MachineLearning::Details +} // namespace Details +} // namespace MachineLearning +} // namespace AI +} // namespace Microsoft -#endif // WINML_H_ \ No newline at end of file +#endif // WINML_H_ diff --git a/winml/test/common/SqueezeNetValidator.cpp b/winml/test/common/SqueezeNetValidator.cpp index 3c85ef2c351dc..623b05bd8923c 100644 --- a/winml/test/common/SqueezeNetValidator.cpp +++ b/winml/test/common/SqueezeNetValidator.cpp @@ -18,275 +18,236 @@ using namespace ws; using namespace wss; using namespace winml; -namespace WinML::Engine::Test{ +namespace WinML::Engine::Test { #define MAX_PROFILING_LOOP 100 - static void BindImage( - LearningModelBinding binding, - const wchar_t* name, - const wchar_t* fullImagePath, - bool bindAsInspectable = false) -{ - auto imagefile = StorageFile::GetFileFromPathAsync(fullImagePath).get(); - auto stream = imagefile.OpenAsync(FileAccessMode::Read).get(); - auto decoder = BitmapDecoder::CreateAsync(stream).get(); - auto softwareBitmap = decoder.GetSoftwareBitmapAsync().get(); - auto frame = VideoFrame::CreateWithSoftwareBitmap(softwareBitmap); - - if (bindAsInspectable) - { - binding.Bind(name, frame); - } - else - { - auto imagetensor = ImageFeatureValue::CreateFromVideoFrame(frame); - binding.Bind(name, imagetensor); - } + LearningModelBinding binding, const wchar_t* name, const wchar_t* fullImagePath, bool bindAsInspectable = false +) { + auto imagefile = StorageFile::GetFileFromPathAsync(fullImagePath).get(); + auto stream = imagefile.OpenAsync(FileAccessMode::Read).get(); + auto decoder = BitmapDecoder::CreateAsync(stream).get(); + auto softwareBitmap = decoder.GetSoftwareBitmapAsync().get(); + auto frame = VideoFrame::CreateWithSoftwareBitmap(softwareBitmap); + + if (bindAsInspectable) { + binding.Bind(name, frame); + } else { + auto imagetensor = ImageFeatureValue::CreateFromVideoFrame(frame); + binding.Bind(name, imagetensor); + } } static void BindTensor( - LearningModelBinding binding, - const wchar_t* name, - ITensor inputTensor, - bool bindAsInspectable = false) -{ - if (inputTensor == nullptr) - { - throw winrt::hresult_invalid_argument(L"input tensor provided to squeezenet is null."); - } - - if (bindAsInspectable) - { - binding.Bind(name, inputTensor.as().GetAsVectorView()); - } - else - { - binding.Bind(name, inputTensor); - } + LearningModelBinding binding, const wchar_t* name, ITensor inputTensor, bool bindAsInspectable = false +) { + if (inputTensor == nullptr) { + throw winrt::hresult_invalid_argument(L"input tensor provided to squeezenet is null."); + } + + if (bindAsInspectable) { + binding.Bind(name, inputTensor.as().GetAsVectorView()); + } else { + binding.Bind(name, inputTensor); + } } template ITensor BindOutput( - OutputBindingStrategy strategy, - LearningModelBinding binding, - const wchar_t* name, - const IVectorView shape = nullptr -) -{ - ITensor outputTensor = nullptr; - switch (strategy) - { + OutputBindingStrategy strategy, + LearningModelBinding binding, + const wchar_t* name, + const IVectorView shape = nullptr +) { + ITensor outputTensor = nullptr; + switch (strategy) { case OutputBindingStrategy::Bound: - outputTensor = T::Create(shape); - binding.Bind(name, outputTensor); - break; + outputTensor = T::Create(shape); + binding.Bind(name, outputTensor); + break; case OutputBindingStrategy::Empty: - outputTensor = T::Create(); - binding.Bind(name, outputTensor); - break; + outputTensor = T::Create(); + binding.Bind(name, outputTensor); + break; case OutputBindingStrategy::Unbound: - __fallthrough; + __fallthrough; default: - break; - } + break; + } - return outputTensor; + return outputTensor; } -ImageFeatureValue BindImageOutput( - OutputBindingStrategy strategy, - LearningModelBinding binding, - const wchar_t* name -) -{ - ImageFeatureValue outputTensor = nullptr; - switch (strategy) - { - case OutputBindingStrategy::Bound: - { - SoftwareBitmap bitmap(BitmapPixelFormat::Bgra8, 720, 720); - VideoFrame frame = VideoFrame::CreateWithSoftwareBitmap(bitmap); - outputTensor = ImageFeatureValue::CreateFromVideoFrame(frame); - binding.Bind(name, outputTensor); - break; +ImageFeatureValue BindImageOutput(OutputBindingStrategy strategy, LearningModelBinding binding, const wchar_t* name) { + ImageFeatureValue outputTensor = nullptr; + switch (strategy) { + case OutputBindingStrategy::Bound: { + SoftwareBitmap bitmap(BitmapPixelFormat::Bgra8, 720, 720); + VideoFrame frame = VideoFrame::CreateWithSoftwareBitmap(bitmap); + outputTensor = ImageFeatureValue::CreateFromVideoFrame(frame); + binding.Bind(name, outputTensor); + break; } case OutputBindingStrategy::Unbound: - __fallthrough; - } + __fallthrough; + } - return outputTensor; + return outputTensor; } - void ModelValidator::FnsCandy16( - const std::string& instance, - LearningModelDeviceKind deviceKind, - OutputBindingStrategy outputBindingStrategy, - bool bindInputsAsIInspectable, - float dataTolerance) -{ - ORT_UNUSED_PARAMETER(dataTolerance); - // file name strings - static wchar_t* modelFileName = L"winmlperf_coreml_FNS-Candy_prerelease_fp16.onnx"; - static wchar_t* inputDataImageFileName = L"fish_720.png"; - static wchar_t* outputDataFileName = L"output.png"; - static wchar_t* inputBindingName = L"inputImage"; - static const wchar_t* outputDataBindingName = L"outputImage"; - - auto modulePath = FileHelpers::GetModulePath(); - auto fullModelPath = modulePath + modelFileName; - auto outputFileName = modulePath + outputDataFileName; - - // WinML model creation - LearningModel model = nullptr; - model = LearningModel::LoadFromFilePath(fullModelPath); - - LearningModelSession modelSession = nullptr; - modelSession = LearningModelSession(model, LearningModelDevice(deviceKind)); - - LearningModelBinding modelBinding(modelSession); - auto fullImagePath = modulePath + inputDataImageFileName; - BindImage(modelBinding, inputBindingName, fullImagePath.c_str(), bindInputsAsIInspectable); - - // create the tensor for the actual output - auto output = model.OutputFeatures().First().Current(); - if (output.Kind() != LearningModelFeatureKind::Tensor) - { - throw winrt::hresult_invalid_argument(L"Model output kind is not type Tensor"); - } - - auto shape = winrt::single_threaded_vector(std::vector {1, 1}); - auto outputTensor = BindImageOutput(outputBindingStrategy, modelBinding, outputDataBindingName); - - // Evaluate the model - std::cout << "Calling EvaluateSync on instance" << instance << "\n"; - LearningModelEvaluationResult result = nullptr; - result = modelSession.Evaluate(modelBinding, {}); - - // Get results - if (outputBindingStrategy == OutputBindingStrategy::Unbound) - { - // When output binding strategy is unbound, the output tensor was not set on bind. - // Therefore, we need to retrieve it from the LearnignModelEvaluationResult - // TODO: is this right? outputTensorT is unused... - /*auto outputTensorT = */result.Outputs().Lookup(outputDataBindingName).as(); - } - else - { - if (result.Outputs().Lookup(outputDataBindingName) != outputTensor) - { - throw winrt::hresult_invalid_argument(L"Evaluation Results lookup don't match LearningModelBinding Output Tensor."); - } - - auto softwareBitmap = outputTensor.VideoFrame().SoftwareBitmap(); - - auto folder = StorageFolder::GetFolderFromPathAsync(modulePath.c_str()).get(); - auto imagefile = folder.CreateFileAsync(outputDataFileName, CreationCollisionOption::ReplaceExisting).get(); - auto stream = imagefile.OpenAsync(FileAccessMode::ReadWrite).get(); - auto encoder = BitmapEncoder::CreateAsync(BitmapEncoder::JpegEncoderId(), stream).get(); - encoder.SetSoftwareBitmap(softwareBitmap); - encoder.FlushAsync(); - - } + const std::string& instance, + LearningModelDeviceKind deviceKind, + OutputBindingStrategy outputBindingStrategy, + bool bindInputsAsIInspectable, + float dataTolerance +) { + ORT_UNUSED_PARAMETER(dataTolerance); + // file name strings + static wchar_t* modelFileName = L"winmlperf_coreml_FNS-Candy_prerelease_fp16.onnx"; + static wchar_t* inputDataImageFileName = L"fish_720.png"; + static wchar_t* outputDataFileName = L"output.png"; + static wchar_t* inputBindingName = L"inputImage"; + static const wchar_t* outputDataBindingName = L"outputImage"; + + auto modulePath = FileHelpers::GetModulePath(); + auto fullModelPath = modulePath + modelFileName; + auto outputFileName = modulePath + outputDataFileName; + + // WinML model creation + LearningModel model = nullptr; + model = LearningModel::LoadFromFilePath(fullModelPath); + + LearningModelSession modelSession = nullptr; + modelSession = LearningModelSession(model, LearningModelDevice(deviceKind)); + + LearningModelBinding modelBinding(modelSession); + auto fullImagePath = modulePath + inputDataImageFileName; + BindImage(modelBinding, inputBindingName, fullImagePath.c_str(), bindInputsAsIInspectable); + + // create the tensor for the actual output + auto output = model.OutputFeatures().First().Current(); + if (output.Kind() != LearningModelFeatureKind::Tensor) { + throw winrt::hresult_invalid_argument(L"Model output kind is not type Tensor"); + } + + auto shape = winrt::single_threaded_vector(std::vector{1, 1}); + auto outputTensor = BindImageOutput(outputBindingStrategy, modelBinding, outputDataBindingName); + + // Evaluate the model + std::cout << "Calling EvaluateSync on instance" << instance << "\n"; + LearningModelEvaluationResult result = nullptr; + result = modelSession.Evaluate(modelBinding, {}); + + // Get results + if (outputBindingStrategy == OutputBindingStrategy::Unbound) { + // When output binding strategy is unbound, the output tensor was not set on bind. + // Therefore, we need to retrieve it from the LearnignModelEvaluationResult + // TODO: is this right? outputTensorT is unused... + /*auto outputTensorT = */ result.Outputs().Lookup(outputDataBindingName).as(); + } else { + if (result.Outputs().Lookup(outputDataBindingName) != outputTensor) { + throw winrt::hresult_invalid_argument(L"Evaluation Results lookup don't match LearningModelBinding Output Tensor." + ); + } + + auto softwareBitmap = outputTensor.VideoFrame().SoftwareBitmap(); + + auto folder = StorageFolder::GetFolderFromPathAsync(modulePath.c_str()).get(); + auto imagefile = folder.CreateFileAsync(outputDataFileName, CreationCollisionOption::ReplaceExisting).get(); + auto stream = imagefile.OpenAsync(FileAccessMode::ReadWrite).get(); + auto encoder = BitmapEncoder::CreateAsync(BitmapEncoder::JpegEncoderId(), stream).get(); + encoder.SetSoftwareBitmap(softwareBitmap); + encoder.FlushAsync(); + } } void ModelValidator::SqueezeNet( - const std::string& instance, - LearningModelDeviceKind deviceKind, - float dataTolerance, - bool bindAsImage, - OutputBindingStrategy outputBindingStrategy, - bool bindInputsAsIInspectable) -{ - // file name strings - static wchar_t* modelFileName = L"model.onnx"; - static wchar_t* inputDataFileName = L"test_data_0_input.pb"; - static wchar_t* outputDataFileName = L"test_data_0_output.pb"; - static wchar_t* inputBindingName = L"data_0"; - static wchar_t* inputDataImageFileName = L"kitten_224.png"; - static const wchar_t* outputDataBindingName = L"softmaxout_1"; - - auto modulePath = FileHelpers::GetModulePath(); - auto fullModelPath = modulePath + modelFileName; - auto outputFileName = modulePath + outputDataFileName; - - // WinML model creation - LearningModel model = nullptr; - model = LearningModel::LoadFromFilePath(fullModelPath); - - LearningModelSession modelSession = nullptr; - modelSession = LearningModelSession(model, LearningModelDevice(deviceKind)); - - LearningModelBinding modelBinding(modelSession); - - if (bindAsImage) - { - std::wstring fullImagePath = modulePath + inputDataImageFileName; - BindImage(modelBinding, inputBindingName, fullImagePath.c_str(), bindInputsAsIInspectable); - } - else - { - auto inputDataPath = modulePath + inputDataFileName; - auto inputTensor = ProtobufHelpers::LoadTensorFromProtobufFile(inputDataPath, false); - BindTensor(modelBinding, inputBindingName, inputTensor, bindInputsAsIInspectable); - } - - // load up the expected output - auto expectedResultsTensor = ProtobufHelpers::LoadTensorFromProtobufFile(outputFileName, false); - if (expectedResultsTensor == nullptr) - { - throw winrt::hresult_invalid_argument(L"Expected Results from protobuf file are null."); - } - - // create the tensor for the actual output - auto output = model.OutputFeatures().First().Current(); - if (output.Kind() != LearningModelFeatureKind::Tensor) - { - throw winrt::hresult_invalid_argument(L"Expected output feature kind of model to be Tensor"); - } - - auto outputTensor = BindOutput( - outputBindingStrategy, modelBinding, outputDataBindingName, expectedResultsTensor.Shape()); - - // Evaluate the model - std::cout << "Calling EvaluateSync on instance " << instance << "\n"; - LearningModelEvaluationResult result = nullptr; - result = modelSession.Evaluate(modelBinding, {}); - - // Get results - if (outputBindingStrategy == OutputBindingStrategy::Unbound) - { - // When output binding strategy is unbound, the output tensor was not set on bind. - // Therefore, we need to retrieve it from the LearnignModelEvaluationResult - outputTensor = result.Outputs().Lookup(outputDataBindingName).as(); - } - else - { - if (result.Outputs().Lookup(outputDataBindingName) != outputTensor) - { - throw winrt::hresult_error(E_UNEXPECTED, L"Evaluation Results lookup don't match LearningModelBinding output tensor."); - } - } - - auto outDataExpected = expectedResultsTensor.as().GetAsVectorView(); - auto outDataActual = outputTensor.as().GetAsVectorView(); - - if (outDataActual.Size() != outDataExpected.Size()) - { - throw winrt::hresult_error(E_UNEXPECTED, L"Actual tensor data size doesn't match expected tensor data size."); - } - for (uint32_t i = 0; i < outDataActual.Size(); i++) - { - float delta = std::abs(outDataActual.GetAt(i) - outDataExpected.GetAt(i)); - if (delta > dataTolerance) - { - std::wstringstream ss; - ss << "EXPECTED: " << outDataExpected.GetAt(i) << " , ACTUAL: " << outDataActual.GetAt(i) - << "instance " << instance.c_str() << ", element " << i; - throw winrt::hresult_error(E_UNEXPECTED, ss.str()); - } - } -} + const std::string& instance, + LearningModelDeviceKind deviceKind, + float dataTolerance, + bool bindAsImage, + OutputBindingStrategy outputBindingStrategy, + bool bindInputsAsIInspectable +) { + // file name strings + static wchar_t* modelFileName = L"model.onnx"; + static wchar_t* inputDataFileName = L"test_data_0_input.pb"; + static wchar_t* outputDataFileName = L"test_data_0_output.pb"; + static wchar_t* inputBindingName = L"data_0"; + static wchar_t* inputDataImageFileName = L"kitten_224.png"; + static const wchar_t* outputDataBindingName = L"softmaxout_1"; + + auto modulePath = FileHelpers::GetModulePath(); + auto fullModelPath = modulePath + modelFileName; + auto outputFileName = modulePath + outputDataFileName; + + // WinML model creation + LearningModel model = nullptr; + model = LearningModel::LoadFromFilePath(fullModelPath); + + LearningModelSession modelSession = nullptr; + modelSession = LearningModelSession(model, LearningModelDevice(deviceKind)); + + LearningModelBinding modelBinding(modelSession); + + if (bindAsImage) { + std::wstring fullImagePath = modulePath + inputDataImageFileName; + BindImage(modelBinding, inputBindingName, fullImagePath.c_str(), bindInputsAsIInspectable); + } else { + auto inputDataPath = modulePath + inputDataFileName; + auto inputTensor = ProtobufHelpers::LoadTensorFromProtobufFile(inputDataPath, false); + BindTensor(modelBinding, inputBindingName, inputTensor, bindInputsAsIInspectable); + } + + // load up the expected output + auto expectedResultsTensor = ProtobufHelpers::LoadTensorFromProtobufFile(outputFileName, false); + if (expectedResultsTensor == nullptr) { + throw winrt::hresult_invalid_argument(L"Expected Results from protobuf file are null."); + } + + // create the tensor for the actual output + auto output = model.OutputFeatures().First().Current(); + if (output.Kind() != LearningModelFeatureKind::Tensor) { + throw winrt::hresult_invalid_argument(L"Expected output feature kind of model to be Tensor"); + } + + auto outputTensor = + BindOutput(outputBindingStrategy, modelBinding, outputDataBindingName, expectedResultsTensor.Shape()); + + // Evaluate the model + std::cout << "Calling EvaluateSync on instance " << instance << "\n"; + LearningModelEvaluationResult result = nullptr; + result = modelSession.Evaluate(modelBinding, {}); + + // Get results + if (outputBindingStrategy == OutputBindingStrategy::Unbound) { + // When output binding strategy is unbound, the output tensor was not set on bind. + // Therefore, we need to retrieve it from the LearnignModelEvaluationResult + outputTensor = result.Outputs().Lookup(outputDataBindingName).as(); + } else { + if (result.Outputs().Lookup(outputDataBindingName) != outputTensor) { + throw winrt::hresult_error( + E_UNEXPECTED, L"Evaluation Results lookup don't match LearningModelBinding output tensor." + ); + } + } + + auto outDataExpected = expectedResultsTensor.as().GetAsVectorView(); + auto outDataActual = outputTensor.as().GetAsVectorView(); + + if (outDataActual.Size() != outDataExpected.Size()) { + throw winrt::hresult_error(E_UNEXPECTED, L"Actual tensor data size doesn't match expected tensor data size."); + } + for (uint32_t i = 0; i < outDataActual.Size(); i++) { + float delta = std::abs(outDataActual.GetAt(i) - outDataExpected.GetAt(i)); + if (delta > dataTolerance) { + std::wstringstream ss; + ss << "EXPECTED: " << outDataExpected.GetAt(i) << " , ACTUAL: " << outDataActual.GetAt(i) << "instance " + << instance.c_str() << ", element " << i; + throw winrt::hresult_error(E_UNEXPECTED, ss.str()); + } + } } +} // namespace WinML::Engine::Test diff --git a/winml/test/common/SqueezeNetValidator.h b/winml/test/common/SqueezeNetValidator.h index df09641b3792d..c9c295cff239b 100644 --- a/winml/test/common/SqueezeNetValidator.h +++ b/winml/test/common/SqueezeNetValidator.h @@ -6,23 +6,27 @@ #include "std.h" #include "winrt_headers.h" -enum OutputBindingStrategy { Bound, Unbound, Empty }; +enum OutputBindingStrategy { + Bound, + Unbound, + Empty +}; -namespace WinML::Engine::Test::ModelValidator -{ - void FnsCandy16( - const std::string& instance, - winml::LearningModelDeviceKind deviceKind, - OutputBindingStrategy outputBindingStrategy, - bool bindInputsAsIInspectable, - float dataTolerance = false); +namespace WinML::Engine::Test::ModelValidator { +void FnsCandy16( + const std::string& instance, + winml::LearningModelDeviceKind deviceKind, + OutputBindingStrategy outputBindingStrategy, + bool bindInputsAsIInspectable, + float dataTolerance = false +); - void SqueezeNet( - const std::string& instance, - winml::LearningModelDeviceKind deviceKind, - float dataTolerance, - bool bindAsImage = false, - OutputBindingStrategy outputBindingStrategy = OutputBindingStrategy::Bound, - bool bindInputsAsIInspectable = false - ); -} +void SqueezeNet( + const std::string& instance, + winml::LearningModelDeviceKind deviceKind, + float dataTolerance, + bool bindAsImage = false, + OutputBindingStrategy outputBindingStrategy = OutputBindingStrategy::Bound, + bool bindInputsAsIInspectable = false +); +} // namespace WinML::Engine::Test::ModelValidator diff --git a/winml/test/common/dllload.cpp b/winml/test/common/dllload.cpp index 3d2f5270848a8..a3d5d159c842c 100644 --- a/winml/test/common/dllload.cpp +++ b/winml/test/common/dllload.cpp @@ -6,9 +6,8 @@ #include #include "dllload.h" -extern "C" -{ - HRESULT __stdcall OS_RoGetActivationFactory(HSTRING classId, GUID const& iid, void** factory) noexcept; +extern "C" { +HRESULT __stdcall OS_RoGetActivationFactory(HSTRING classId, GUID const& iid, void** factory) noexcept; } #ifdef _M_IX86 @@ -17,71 +16,61 @@ extern "C" #pragma comment(linker, "/alternatename:OS_RoGetActivationFactory=RoGetActivationFactory") #endif -bool starts_with(std::wstring_view value, std::wstring_view match) noexcept -{ - return 0 == value.compare(0, match.size(), match); +bool starts_with(std::wstring_view value, std::wstring_view match) noexcept { + return 0 == value.compare(0, match.size(), match); } -HRESULT __stdcall WINRT_RoGetActivationFactory(HSTRING classId_hstring, GUID const& iid, void** factory) noexcept -{ - *factory = nullptr; - std::wstring_view name{ WindowsGetStringRawBuffer(classId_hstring, nullptr), WindowsGetStringLen(classId_hstring) }; - HMODULE library{ nullptr }; +HRESULT __stdcall WINRT_RoGetActivationFactory(HSTRING classId_hstring, GUID const& iid, void** factory) noexcept { + *factory = nullptr; + std::wstring_view name{WindowsGetStringRawBuffer(classId_hstring, nullptr), WindowsGetStringLen(classId_hstring)}; + HMODULE library{nullptr}; - std::wostringstream dll; - dll << BINARY_NAME; + std::wostringstream dll; + dll << BINARY_NAME; - std::wstring winml_dll_name = dll.str(); - std::wstring winml_dll_path = FileHelpers::GetWinMLPath() + winml_dll_name; - std::wstring winml_dll_prefix = winml_dll_name.substr(0, winml_dll_name.size() - 3); - if (starts_with(name, winml_dll_prefix)) - { - const wchar_t* lib_path = winml_dll_path.c_str(); + std::wstring winml_dll_name = dll.str(); + std::wstring winml_dll_path = FileHelpers::GetWinMLPath() + winml_dll_name; + std::wstring winml_dll_prefix = winml_dll_name.substr(0, winml_dll_name.size() - 3); + if (starts_with(name, winml_dll_prefix)) { + const wchar_t* lib_path = winml_dll_path.c_str(); #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - library = LoadLibraryExW(lib_path, nullptr, 0); + library = LoadLibraryExW(lib_path, nullptr, 0); #else - library = LoadPackagedLibrary(lib_path, 0); + library = LoadPackagedLibrary(lib_path, 0); #endif - } - else - { - return OS_RoGetActivationFactory(classId_hstring, iid, factory); - } + } else { + return OS_RoGetActivationFactory(classId_hstring, iid, factory); + } - if (!library) - { - return HRESULT_FROM_WIN32(GetLastError()); - } + if (!library) { + return HRESULT_FROM_WIN32(GetLastError()); + } - using DllGetActivationFactory = HRESULT __stdcall(HSTRING classId, void** factory); - auto call = reinterpret_cast(GetProcAddress(library, "DllGetActivationFactory")); + using DllGetActivationFactory = HRESULT __stdcall(HSTRING classId, void** factory); + auto call = reinterpret_cast(GetProcAddress(library, "DllGetActivationFactory")); - if (!call) - { - HRESULT const hr = HRESULT_FROM_WIN32(GetLastError()); - WINRT_VERIFY(FreeLibrary(library)); - return hr; - } + if (!call) { + HRESULT const hr = HRESULT_FROM_WIN32(GetLastError()); + WINRT_VERIFY(FreeLibrary(library)); + return hr; + } - winrt::com_ptr activation_factory; - HRESULT const hr = call(classId_hstring, activation_factory.put_void()); + winrt::com_ptr activation_factory; + HRESULT const hr = call(classId_hstring, activation_factory.put_void()); - if (FAILED(hr)) - { - WINRT_VERIFY(FreeLibrary(library)); - return hr; - } + if (FAILED(hr)) { + WINRT_VERIFY(FreeLibrary(library)); + return hr; + } - if (winrt::guid(iid) != winrt::guid_of()) - { - return activation_factory->QueryInterface(iid, factory); - } + if (winrt::guid(iid) != winrt::guid_of()) { + return activation_factory->QueryInterface(iid, factory); + } - *factory = activation_factory.detach(); - return S_OK; + *factory = activation_factory.detach(); + return S_OK; } -int32_t __stdcall WINRT_RoGetActivationFactory(void* classId, winrt::guid const& iid, void** factory) noexcept -{ - return WINRT_RoGetActivationFactory((HSTRING)classId, (GUID)iid, factory); +int32_t __stdcall WINRT_RoGetActivationFactory(void* classId, winrt::guid const& iid, void** factory) noexcept { + return WINRT_RoGetActivationFactory((HSTRING)classId, (GUID)iid, factory); } diff --git a/winml/test/common/dllload.h b/winml/test/common/dllload.h index f9b593ff04994..2a5c38646213c 100644 --- a/winml/test/common/dllload.h +++ b/winml/test/common/dllload.h @@ -2,4 +2,4 @@ #include "Std.h" #include "winrt/base.h" -int32_t __stdcall WINRT_RoGetActivationFactory(void* classId, winrt::guid const& iid, void** factory) noexcept; \ No newline at end of file +int32_t __stdcall WINRT_RoGetActivationFactory(void* classId, winrt::guid const& iid, void** factory) noexcept; diff --git a/winml/test/common/fileHelpers.cpp b/winml/test/common/fileHelpers.cpp index d1129de9d0b69..998ca68da01d8 100644 --- a/winml/test/common/fileHelpers.cpp +++ b/winml/test/common/fileHelpers.cpp @@ -13,58 +13,54 @@ using namespace winml; using namespace wgi; using namespace ws; -namespace FileHelpers -{ - std::wstring GetModulePath() - { - std::wstring val; - wchar_t modulePath[MAX_PATH] = { 0 }; - GetModuleFileNameW((HINSTANCE)&__ImageBase, modulePath, _countof(modulePath)); - wchar_t drive[_MAX_DRIVE]; - wchar_t dir[_MAX_DIR]; - wchar_t filename[_MAX_FNAME]; - wchar_t ext[_MAX_EXT]; - _wsplitpath_s(modulePath, drive, _MAX_DRIVE, dir, _MAX_DIR, filename, _MAX_FNAME, ext, _MAX_EXT); +namespace FileHelpers { +std::wstring GetModulePath() { + std::wstring val; + wchar_t modulePath[MAX_PATH] = {0}; + GetModuleFileNameW((HINSTANCE)&__ImageBase, modulePath, _countof(modulePath)); + wchar_t drive[_MAX_DRIVE]; + wchar_t dir[_MAX_DIR]; + wchar_t filename[_MAX_FNAME]; + wchar_t ext[_MAX_EXT]; + _wsplitpath_s(modulePath, drive, _MAX_DRIVE, dir, _MAX_DIR, filename, _MAX_FNAME, ext, _MAX_EXT); - val = drive; - val += dir; + val = drive; + val += dir; - return val; - } - - std::wstring GetWinMLPath() - { - // bool inboxDll = false; - // TODO Add command line parsing - // if (SUCCEEDED(WEX::TestExecution::RuntimeParameters::TryGetValue(L"inbox", inboxDll)) && inboxDll) - // { - // return L""; - // } - return GetModulePath(); - } + return val; +} +std::wstring GetWinMLPath() { + // bool inboxDll = false; + // TODO Add command line parsing + // if (SUCCEEDED(WEX::TestExecution::RuntimeParameters::TryGetValue(L"inbox", inboxDll)) && inboxDll) + // { + // return L""; + // } + return GetModulePath(); +} - wgi::SoftwareBitmap GetSoftwareBitmapFromFile(const std::wstring& filePath) - { - auto storageFile = StorageFile::GetFileFromPathAsync(filePath).get(); - auto stream = storageFile.OpenAsync(FileAccessMode::Read).get(); - auto decoder = BitmapDecoder::CreateAsync(stream).get(); - IBitmapFrameWithSoftwareBitmap bitmapFrameWithSoftwareBitmap; - decoder.as(bitmapFrameWithSoftwareBitmap); - auto softwareBitmap = bitmapFrameWithSoftwareBitmap.GetSoftwareBitmapAsync( - BitmapPixelFormat::Bgra8, - BitmapAlphaMode::Ignore, - BitmapTransform::BitmapTransform(), - ExifOrientationMode::IgnoreExifOrientation, - ColorManagementMode::DoNotColorManage - ).get(); - return softwareBitmap; - } +wgi::SoftwareBitmap GetSoftwareBitmapFromFile(const std::wstring& filePath) { + auto storageFile = StorageFile::GetFileFromPathAsync(filePath).get(); + auto stream = storageFile.OpenAsync(FileAccessMode::Read).get(); + auto decoder = BitmapDecoder::CreateAsync(stream).get(); + IBitmapFrameWithSoftwareBitmap bitmapFrameWithSoftwareBitmap; + decoder.as(bitmapFrameWithSoftwareBitmap); + auto softwareBitmap = bitmapFrameWithSoftwareBitmap + .GetSoftwareBitmapAsync( + BitmapPixelFormat::Bgra8, + BitmapAlphaMode::Ignore, + BitmapTransform::BitmapTransform(), + ExifOrientationMode::IgnoreExifOrientation, + ColorManagementMode::DoNotColorManage + ) + .get(); + return softwareBitmap; +} - winml::ImageFeatureValue LoadImageFeatureValue(const std::wstring& imagePath) - { - auto softwareBitmap = FileHelpers::GetSoftwareBitmapFromFile(FileHelpers::GetModulePath() + imagePath); - auto videoFrame = wm::VideoFrame::CreateWithSoftwareBitmap(softwareBitmap); - return ImageFeatureValue::CreateFromVideoFrame(videoFrame); - } +winml::ImageFeatureValue LoadImageFeatureValue(const std::wstring& imagePath) { + auto softwareBitmap = FileHelpers::GetSoftwareBitmapFromFile(FileHelpers::GetModulePath() + imagePath); + auto videoFrame = wm::VideoFrame::CreateWithSoftwareBitmap(softwareBitmap); + return ImageFeatureValue::CreateFromVideoFrame(videoFrame); } +} // namespace FileHelpers diff --git a/winml/test/common/fileHelpers.h b/winml/test/common/fileHelpers.h index e8a246b50359e..91ad22ec4719c 100644 --- a/winml/test/common/fileHelpers.h +++ b/winml/test/common/fileHelpers.h @@ -8,11 +8,10 @@ #include "winrt/Windows.Graphics.Imaging.h" -namespace FileHelpers -{ - std::wstring GetModulePath(); - std::wstring GetWinMLPath(); +namespace FileHelpers { +std::wstring GetModulePath(); +std::wstring GetWinMLPath(); - wgi::SoftwareBitmap GetSoftwareBitmapFromFile(const std::wstring& filePath); - winml::ImageFeatureValue LoadImageFeatureValue(const std::wstring& imagePath); -} +wgi::SoftwareBitmap GetSoftwareBitmapFromFile(const std::wstring& filePath); +winml::ImageFeatureValue LoadImageFeatureValue(const std::wstring& imagePath); +} // namespace FileHelpers diff --git a/winml/test/common/googleTestMacros.h b/winml/test/common/googleTestMacros.h index 79a7f51ce5d77..2f493c9b6d6b9 100644 --- a/winml/test/common/googleTestMacros.h +++ b/winml/test/common/googleTestMacros.h @@ -14,59 +14,57 @@ #define WINML_TEST_CLASS_BEGIN(test_class_name) \ namespace { \ - class test_class_name : public ::testing::Test { - + class test_class_name : public ::testing::Test { #define WINML_TEST_CLASS_SETUP_CLASS(setup_class) \ - protected: \ - static void SetUpTestSuite() { \ - getapi().setup_class(); \ - } + protected: \ + static void SetUpTestSuite() { \ + getapi().setup_class(); \ + } #define WINML_TEST_CLASS_TEARDOWN_CLASS(teardown_class) \ - protected: \ - static void TearDownTestSuite() { \ - getapi().teardown_class(); \ - } + protected: \ + static void TearDownTestSuite() { \ + getapi().teardown_class(); \ + } #define WINML_TEST_CLASS_SETUP_METHOD(setup_method) \ - protected: \ - void SetUp() override { \ - getapi().setup_method(); \ - } + protected: \ + void SetUp() override { \ + getapi().setup_method(); \ + } #define WINML_TEST_CLASS_TEARDOWN_METHOD(teardown_method) \ - protected: \ - void TearDown() override { \ - getapi().teardown_method(); \ - } + protected: \ + void TearDown() override { \ + getapi().teardown_method(); \ + } -#define WINML_TEST_CLASS_BEGIN_TESTS }; +#define WINML_TEST_CLASS_BEGIN_TESTS \ + } \ + ; #define WINML_TEST_CLASS_END() } // For old versions of gtest without GTEST_SKIP, stream the message and return success instead #ifndef GTEST_SKIP -#define GTEST_SKIP_(message) \ - return GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess) +#define GTEST_SKIP_(message) return GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess) #define GTEST_SKIP GTEST_SKIP_("") #endif #define EXPECT_THROW_SPECIFIC(statement, exception, condition) \ - EXPECT_THROW( \ - try { \ - statement; \ - } catch (const exception& e) { \ - EXPECT_TRUE(condition(e)); \ - throw; \ - }, \ - exception); + EXPECT_THROW( \ + try { statement; } catch (const exception& e) { \ + EXPECT_TRUE(condition(e)); \ + throw; \ + }, \ + exception \ + ); #ifndef INSTANTIATE_TEST_SUITE_P // Use the old name, removed in newer versions of googletest #define INSTANTIATE_TEST_SUITE_P INSTANTIATE_TEST_CASE_P #endif -#define WINML_SKIP_TEST(message) \ - WINML_SUPRESS_UNREACHABLE_BELOW(GTEST_SKIP() << message) +#define WINML_SKIP_TEST(message) WINML_SUPRESS_UNREACHABLE_BELOW(GTEST_SKIP() << message) #define WINML_EXPECT_NO_THROW(statement) EXPECT_NO_THROW(statement) #define WINML_EXPECT_TRUE(statement) EXPECT_TRUE(statement) @@ -74,26 +72,23 @@ #define WINML_EXPECT_EQUAL(val1, val2) EXPECT_EQ(val1, val2) #define WINML_EXPECT_NOT_EQUAL(val1, val2) EXPECT_NE(val1, val2) -#define WINML_LOG_ERROR(message) \ - ADD_FAILURE() << message -#define WINML_LOG_COMMENT(message) \ - SCOPED_TRACE(message) +#define WINML_LOG_ERROR(message) ADD_FAILURE() << message +#define WINML_LOG_COMMENT(message) SCOPED_TRACE(message) #define WINML_EXPECT_HRESULT_SUCCEEDED(hresult_expression) EXPECT_HRESULT_SUCCEEDED(hresult_expression) #define WINML_EXPECT_HRESULT_FAILED(hresult_expression) EXPECT_HRESULT_FAILED(hresult_expression) -#define WINML_EXPECT_THROW_SPECIFIC(statement, exception, condition) EXPECT_THROW_SPECIFIC(statement, exception, condition) +#define WINML_EXPECT_THROW_SPECIFIC(statement, exception, condition) \ + EXPECT_THROW_SPECIFIC(statement, exception, condition) #pragma warning(push) -#pragma warning(disable:4505) // unreferenced local function has been removed +#pragma warning(disable : 4505) // unreferenced local function has been removed -static bool RuntimeParameterExists(std::wstring param) -{ +static bool RuntimeParameterExists(std::wstring param) { std::string narrowParam = std::wstring_convert>().to_bytes(param); auto no_gpu_tests = RuntimeParameters::Parameters.find(narrowParam); return no_gpu_tests != RuntimeParameters::Parameters.end() && no_gpu_tests->second != "0"; } -static bool SkipGpuTests() -{ +static bool SkipGpuTests() { #ifndef USE_DML return true; #else diff --git a/winml/test/common/googletest/main.cpp b/winml/test/common/googletest/main.cpp index 0a672dcd8ff79..72b85ec624d31 100644 --- a/winml/test/common/googletest/main.cpp +++ b/winml/test/common/googletest/main.cpp @@ -8,14 +8,13 @@ #include "runtimeParameters.h" namespace RuntimeParameters { -std::unordered_map Parameters; +std::unordered_map Parameters; } namespace { void usage(char** argv, int failedArgument) { std::cerr << "Unrecognized argument: " << argv[failedArgument] << "\n" - << "Usage:\n\t" - << argv[0] << " [/p:parameterName=parameterValue ...]\n"; + << "Usage:\n\t" << argv[0] << " [/p:parameterName=parameterValue ...]\n"; } bool parseArgument(const std::string& argument) { diff --git a/winml/test/common/protobufHelpers.cpp b/winml/test/common/protobufHelpers.cpp index 9a15da4df85e9..5bfeef0cb676b 100644 --- a/winml/test/common/protobufHelpers.cpp +++ b/winml/test/common/protobufHelpers.cpp @@ -6,7 +6,7 @@ #endif // LotusRT -#include "core/framework/allocatormgr.h" +#include "core/framework/allocator_utils.h" #include "core/common/logging/logging.h" #include "core/common/logging/sinks/clog_sink.h" #include "protobufHelpers.h" @@ -61,48 +61,41 @@ bool ProtobufHelpers::LoadOnnxTensorFromProtobufFile(onnx::TensorProto& tensor, } template -std::vector GetTypeSpecificDataFromTensorProto( - onnx::TensorProto /*tensorProto*/) { +std::vector GetTypeSpecificDataFromTensorProto(onnx::TensorProto /*tensorProto*/) { static_assert(false, "UNDEFINED! TensorProto methods aren't templated, so add a new template specialization."); } template <> -std::vector GetTypeSpecificDataFromTensorProto( - onnx::TensorProto tensorProto) { +std::vector GetTypeSpecificDataFromTensorProto(onnx::TensorProto tensorProto) { return std::vector(std::begin(tensorProto.float_data()), std::end(tensorProto.float_data())); } template <> -std::vector GetTypeSpecificDataFromTensorProto( - onnx::TensorProto tensorProto) { +std::vector GetTypeSpecificDataFromTensorProto(onnx::TensorProto tensorProto) { return std::vector(std::begin(tensorProto.int32_data()), std::end(tensorProto.int32_data())); } template <> -std::vector GetTypeSpecificDataFromTensorProto( - onnx::TensorProto tensorProto) { +std::vector GetTypeSpecificDataFromTensorProto(onnx::TensorProto tensorProto) { return std::vector(std::begin(tensorProto.int64_data()), std::end(tensorProto.int64_data())); } template <> -std::vector GetTypeSpecificDataFromTensorProto( - onnx::TensorProto tensorProto) { +std::vector GetTypeSpecificDataFromTensorProto(onnx::TensorProto tensorProto) { #pragma warning(push) -#pragma warning(disable:4244) // conversion with possible loss of data +#pragma warning(disable : 4244) // conversion with possible loss of data return std::vector(std::begin(tensorProto.int32_data()), std::end(tensorProto.int32_data())); #pragma warning(pop) } template <> -std::vector GetTypeSpecificDataFromTensorProto( - onnx::TensorProto tensorProto) { +std::vector GetTypeSpecificDataFromTensorProto(onnx::TensorProto tensorProto) { return std::vector(std::begin(tensorProto.double_data()), std::end(tensorProto.double_data())); } template -std::vector GetTensorDataFromTensorProto( - onnx::TensorProto tensorProto, - uint64_t elementCount) { +std::vector GetTensorDataFromTensorProto(onnx::TensorProto tensorProto, uint64_t elementCount) { if (tensorProto.has_raw_data()) { std::vector tensorData; auto& values = tensorProto.raw_data(); if (elementCount != values.size() / sizeof(DataType)) { - throw winrt::hresult_invalid_argument(L"TensorProto element count should match raw data buffer size in elements."); + throw winrt::hresult_invalid_argument(L"TensorProto element count should match raw data buffer size in elements." + ); } tensorData = std::vector(static_cast(elementCount)); @@ -114,48 +107,61 @@ std::vector GetTensorDataFromTensorProto( } static std::vector GetTensorStringDataFromTensorProto( - onnx::TensorProto tensorProto, - uint64_t elementCount) { - if(tensorProto.string_data_size() != elementCount) - { + onnx::TensorProto tensorProto, uint64_t elementCount +) { + if (tensorProto.string_data_size() != elementCount) { throw winrt::hresult_invalid_argument(L"Number of elements in TensorProto does not match expected element count."); } auto& values = tensorProto.string_data(); auto returnVector = std::vector(static_cast(elementCount)); - std::transform(std::begin(values), std::end(values), std::begin(returnVector), - [](auto& value) { return winrt::to_hstring(value); }); + std::transform(std::begin(values), std::end(values), std::begin(returnVector), [](auto& value) { + return winrt::to_hstring(value); + }); return returnVector; } -ITensor ProtobufHelpers::LoadTensorFromProtobufFile( - const std::wstring& filePath, - bool isFp16) { +ITensor ProtobufHelpers::LoadTensorFromProtobufFile(const std::wstring& filePath, bool isFp16) { // load from the file path into the onnx format onnx::TensorProto tensorProto; if (LoadOnnxTensorFromProtobufFile(tensorProto, filePath)) { std::vector tensorShape = std::vector(tensorProto.dims().begin(), tensorProto.dims().end()); int64_t initialValue = 1; - int64_t elementCount = std::accumulate(tensorShape.begin(), tensorShape.end(), initialValue, std::multiplies()); + int64_t elementCount = + std::accumulate(tensorShape.begin(), tensorShape.end(), initialValue, std::multiplies()); if (!tensorProto.has_data_type()) { std::cerr << "WARNING: Loading unknown TensorProto datatype.\n"; } if (isFp16) { - return TensorFloat16Bit::CreateFromIterable(tensorShape, GetTensorDataFromTensorProto(tensorProto, elementCount)); + return TensorFloat16Bit::CreateFromIterable( + tensorShape, GetTensorDataFromTensorProto(tensorProto, elementCount) + ); } switch (tensorProto.data_type()) { case (onnx::TensorProto::DataType::TensorProto_DataType_FLOAT): - return TensorFloat::CreateFromIterable(tensorShape, GetTensorDataFromTensorProto(tensorProto, elementCount)); + return TensorFloat::CreateFromIterable( + tensorShape, GetTensorDataFromTensorProto(tensorProto, elementCount) + ); case (onnx::TensorProto::DataType::TensorProto_DataType_INT32): - return TensorInt32Bit::CreateFromIterable(tensorShape, GetTensorDataFromTensorProto(tensorProto, elementCount)); + return TensorInt32Bit::CreateFromIterable( + tensorShape, GetTensorDataFromTensorProto(tensorProto, elementCount) + ); case (onnx::TensorProto::DataType::TensorProto_DataType_INT64): - return TensorInt64Bit::CreateFromIterable(tensorShape, GetTensorDataFromTensorProto(tensorProto, elementCount)); + return TensorInt64Bit::CreateFromIterable( + tensorShape, GetTensorDataFromTensorProto(tensorProto, elementCount) + ); case (onnx::TensorProto::DataType::TensorProto_DataType_STRING): - return TensorString::CreateFromIterable(tensorShape, GetTensorStringDataFromTensorProto(tensorProto, elementCount)); + return TensorString::CreateFromIterable( + tensorShape, GetTensorStringDataFromTensorProto(tensorProto, elementCount) + ); case (onnx::TensorProto::DataType::TensorProto_DataType_UINT8): - return TensorUInt8Bit::CreateFromIterable(tensorShape, GetTensorDataFromTensorProto(tensorProto, elementCount)); + return TensorUInt8Bit::CreateFromIterable( + tensorShape, GetTensorDataFromTensorProto(tensorProto, elementCount) + ); case (onnx::TensorProto::DataType::TensorProto_DataType_DOUBLE): - return TensorDouble::CreateFromIterable(tensorShape, GetTensorDataFromTensorProto(tensorProto, elementCount)); + return TensorDouble::CreateFromIterable( + tensorShape, GetTensorDataFromTensorProto(tensorProto, elementCount) + ); default: throw winrt::hresult_invalid_argument(L"Tensor type for creating tensor from protobuf file not supported."); break; @@ -164,20 +170,21 @@ ITensor ProtobufHelpers::LoadTensorFromProtobufFile( return nullptr; } -TensorFloat16Bit ProtobufHelpers::LoadTensorFloat16FromProtobufFile( - const std::wstring& filePath) { +TensorFloat16Bit ProtobufHelpers::LoadTensorFloat16FromProtobufFile(const std::wstring& filePath) { // load from the file path into the onnx format onnx::TensorProto tensorProto; if (LoadOnnxTensorFromProtobufFile(tensorProto, filePath)) { if (tensorProto.has_data_type()) { - if(onnx::TensorProto::DataType::TensorProto_DataType_FLOAT16 != tensorProto.data_type()) { + if (onnx::TensorProto::DataType::TensorProto_DataType_FLOAT16 != tensorProto.data_type()) { throw winrt::hresult_invalid_argument(L"TensorProto datatype isn't of type Float16."); } } else { std::cerr << "Loading unknown TensorProto datatype as TensorFloat16Bit.\n"; } - auto shape = winrt::single_threaded_vector(std::vector(tensorProto.dims().begin(), tensorProto.dims().end())); + auto shape = + winrt::single_threaded_vector(std::vector(tensorProto.dims().begin(), tensorProto.dims().end()) + ); TensorFloat16Bit singleTensorValue = TensorFloat16Bit::Create(shape.GetView()); uint16_t* data; @@ -186,8 +193,7 @@ TensorFloat16Bit ProtobufHelpers::LoadTensorFloat16FromProtobufFile( uint32_t sizeInBytes; spTensorValueNative->GetBuffer(reinterpret_cast(&data), &sizeInBytes); - if (!tensorProto.has_raw_data()) - { + if (!tensorProto.has_raw_data()) { throw winrt::hresult_invalid_argument(L"Float16 tensor proto buffers are expected to contain raw data."); } @@ -202,9 +208,8 @@ TensorFloat16Bit ProtobufHelpers::LoadTensorFloat16FromProtobufFile( } winml::LearningModel ProtobufHelpers::CreateModel( - winml::TensorKind kind, - const std::vector& shape, - uint32_t num_elements) { + winml::TensorKind kind, const std::vector& shape, uint32_t num_elements +) { onnx::ModelProto model; model.set_ir_version(onnx::Version::IR_VERSION); diff --git a/winml/test/common/protobufHelpers.h b/winml/test/common/protobufHelpers.h index 33b0b16f6a3d6..df26b1a97ee75 100644 --- a/winml/test/common/protobufHelpers.h +++ b/winml/test/common/protobufHelpers.h @@ -14,19 +14,15 @@ #include "onnx/onnx-ml.pb.h" #pragma warning(pop) -namespace ProtobufHelpers -{ - // LoadTensorFromProtobufFile take a path to a FP32 data file and loads it into a 32bit array or - // 16bit array based on isFp16 - winml::ITensor LoadTensorFromProtobufFile(const std::wstring& filePath, bool isFp16); - // LoadTensorFloat16FromProtobufFile takes a path to a FP16 data file and loads it into a 16bit array - winml::TensorFloat16Bit LoadTensorFloat16FromProtobufFile(const std::wstring& filePath); +namespace ProtobufHelpers { +// LoadTensorFromProtobufFile take a path to a FP32 data file and loads it into a 32bit array or +// 16bit array based on isFp16 +winml::ITensor LoadTensorFromProtobufFile(const std::wstring& filePath, bool isFp16); +// LoadTensorFloat16FromProtobufFile takes a path to a FP16 data file and loads it into a 16bit array +winml::TensorFloat16Bit LoadTensorFloat16FromProtobufFile(const std::wstring& filePath); - winml::LearningModel CreateModel( - winml::TensorKind kind, - const std::vector& shape, - uint32_t num_elements = 1); +winml::LearningModel CreateModel(winml::TensorKind kind, const std::vector& shape, uint32_t num_elements = 1); - // Populates TensorProto with tensor from protobuf file - bool LoadOnnxTensorFromProtobufFile(onnx::TensorProto& tensor, std::wstring filePath); -} +// Populates TensorProto with tensor from protobuf file +bool LoadOnnxTensorFromProtobufFile(onnx::TensorProto& tensor, std::wstring filePath); +} // namespace ProtobufHelpers diff --git a/winml/test/common/runtimeParameters.h b/winml/test/common/runtimeParameters.h index e2095959bf058..0ac4b1a004ed9 100644 --- a/winml/test/common/runtimeParameters.h +++ b/winml/test/common/runtimeParameters.h @@ -2,8 +2,7 @@ // Licensed under the MIT License. #pragma once -namespace RuntimeParameters -{ - // Runtime parameters passed through CLI arguments - extern std::unordered_map Parameters; -} \ No newline at end of file +namespace RuntimeParameters { +// Runtime parameters passed through CLI arguments +extern std::unordered_map Parameters; +} // namespace RuntimeParameters diff --git a/winml/test/common/taefTestMacros.h b/winml/test/common/taefTestMacros.h index 1956fecd76e69..48119ff293fc8 100644 --- a/winml/test/common/taefTestMacros.h +++ b/winml/test/common/taefTestMacros.h @@ -13,28 +13,28 @@ using namespace WEX::TestExecution; TEST_CLASS(test_class_name); #define WINML_TEST_CLASS_SETUP_CLASS(setup_class) \ - TEST_CLASS_SETUP(TestClassSetup) { \ - getapi().setup_class(); \ - return true; \ - } + TEST_CLASS_SETUP(TestClassSetup) { \ + getapi().setup_class(); \ + return true; \ + } #define WINML_TEST_CLASS_TEARDOWN_CLASS(teardown_class) \ - TEST_CLASS_CLEANUP(TestClassCleanup) { \ - getapi().teardown_class(); \ - return true; \ - } + TEST_CLASS_CLEANUP(TestClassCleanup) { \ + getapi().teardown_class(); \ + return true; \ + } #define WINML_TEST_CLASS_SETUP_METHOD(setup_method) \ - TEST_METHOD_SETUP(TestMethodSetup) { \ - getapi().setup_method(); \ - return true; \ - } + TEST_METHOD_SETUP(TestMethodSetup) { \ + getapi().setup_method(); \ + return true; \ + } #define WINML_TEST_CLASS_TEARDOWN_METHOD(teardown_method) \ - TEST_METHOD_CLEANUP(TestClassCleanup) { \ - getapi().teardown_method(); \ - return true; \ - } + TEST_METHOD_CLEANUP(TestClassCleanup) { \ + getapi().teardown_method(); \ + return true; \ + } #define WINML_TEST_CLASS_BEGIN_TESTS @@ -47,11 +47,11 @@ using namespace WEX::TestExecution; getapi().test_name(); \ } -#define WINML_SKIP_TEST(message) \ - WINML_SUPRESS_UNREACHABLE_BELOW( \ - Log::Result(TestResults::Skipped, \ - std::wstring_convert>().from_bytes(message).c_str()); \ - return;) +#define WINML_SKIP_TEST(message) \ + WINML_SUPRESS_UNREACHABLE_BELOW( \ + Log::Result(TestResults::Skipped, std::wstring_convert>().from_bytes(message).c_str()); \ + return; \ + ) #define WINML_EXPECT_NO_THROW(statement) VERIFY_NO_THROW(statement) #define WINML_EXPECT_TRUE(statement) VERIFY_IS_TRUE(statement) @@ -63,7 +63,8 @@ using namespace WEX::TestExecution; #define WINML_LOG_COMMENT(message) \ WEX::Logging::Log::Comment(std::wstring_convert>().from_bytes(message).c_str()) #define WINML_EXPECT_HRESULT_SUCCEEDED(hresult_expression) VERIFY_SUCCEEDED(hresult_expression) -#define WINML_EXPECT_THROW_SPECIFIC(statement, exception, condition) VERIFY_THROWS_SPECIFIC(statement, exception, condition) +#define WINML_EXPECT_THROW_SPECIFIC(statement, exception, condition) \ + VERIFY_THROWS_SPECIFIC(statement, exception, condition) #define WINML_EXPECT_HRESULT_FAILED(hresult_expression) VERIFY_FAILED(hresult_expression) static bool RuntimeParameterExists(std::wstring param) { @@ -90,4 +91,4 @@ static bool SkipTestsImpactedByOpenMP() { #else return false; #endif -} \ No newline at end of file +} diff --git a/winml/test/common/test.h b/winml/test/common/test.h index 3e8e023c0b23f..f5adce2b40602 100644 --- a/winml/test/common/test.h +++ b/winml/test/common/test.h @@ -10,16 +10,18 @@ using SetupTest = VoidTest; using TeardownTest = VoidTest; #pragma warning(push) -#pragma warning(disable:4505) // unreferenced local function has been removed +#pragma warning(disable : 4505) // unreferenced local function has been removed constexpr bool alwaysTrue() { - return true; + return true; } constexpr bool alwaysFalse() { - return false; + return false; } -#define WINML_SUPRESS_UNREACHABLE_BELOW(statement) \ - if (alwaysTrue()) { statement; } +#define WINML_SUPRESS_UNREACHABLE_BELOW(statement) \ + if (alwaysTrue()) { \ + statement; \ + } #ifdef BUILD_TAEF_TEST #include "taefTestMacros.h" diff --git a/winml/test/common/testPch.h b/winml/test/common/testPch.h index a89d87893ff01..8b09742b435c5 100644 --- a/winml/test/common/testPch.h +++ b/winml/test/common/testPch.h @@ -17,4 +17,4 @@ #include "fileHelpers.h" #include "dllload.h" -#include \ No newline at end of file +#include diff --git a/winml/test/common/winrt_headers.h b/winml/test/common/winrt_headers.h index 02fd398c78c5b..7c1eb489b5398 100644 --- a/winml/test/common/winrt_headers.h +++ b/winml/test/common/winrt_headers.h @@ -21,6 +21,7 @@ #include #include +// clang-format off #define STRINGIFY(x) #x #define XSTRINGIFY(x) STRINGIFY(x) #define CPPWINRT_HEADER(root_ns) comp_generated/winrt/##root_ns##.AI.MachineLearning.h @@ -31,6 +32,7 @@ #define CREATE_CPPWINRT_EXPERIMENTAL_COMPONENT_HEADER() XSTRINGIFY(CPPWINRT_EXPERIMENTAL_HEADER(WINML_ROOT_NS)) #define CREATE_NATIVE_HEADER() XSTRINGIFY(NATIVE_HEADER(WINML_ROOT_NS)) #define CREATE_NATIVE_INTERNAL_HEADER() XSTRINGIFY(NATIVE_INTERNAL_HEADER(WINML_ROOT_NS)) +// clang-format on #include CREATE_CPPWINRT_COMPONENT_HEADER() @@ -49,4 +51,4 @@ namespace wm = winrt::Windows::Media; namespace wgi = winrt::Windows::Graphics::Imaging; namespace wgdx = winrt::Windows::Graphics::DirectX; namespace ws = winrt::Windows::Storage; -namespace wss = winrt::Windows::Storage::Streams; \ No newline at end of file +namespace wss = winrt::Windows::Storage::Streams; diff --git a/winml/test/concurrency/ConcurrencyTests.cpp b/winml/test/concurrency/ConcurrencyTests.cpp index d84b46fcced52..46528ef70d377 100644 --- a/winml/test/concurrency/ConcurrencyTests.cpp +++ b/winml/test/concurrency/ConcurrencyTests.cpp @@ -15,318 +15,301 @@ using namespace winrt; namespace { void LoadBindEvalSqueezenetRealDataWithValidationConcurrently() { - WINML_SKIP_TEST("Skipping due to bug 21617097"); + WINML_SKIP_TEST("Skipping due to bug 21617097"); - constexpr auto load_test_model = [](const std::string& instance, LearningModelDeviceKind device) { - WinML::Engine::Test::ModelValidator::SqueezeNet(instance, device, 0.00001f, false); - }; + constexpr auto load_test_model = [](const std::string& instance, LearningModelDeviceKind device) { + WinML::Engine::Test::ModelValidator::SqueezeNet(instance, device, 0.00001f, false); + }; - std::vector threads; - for (const auto& instance : {"1", "2", "3", "4"}) { - threads.emplace_back(load_test_model, instance, LearningModelDeviceKind::Cpu); - } - if (SkipGpuTests()) {} else { - for (const auto& instance : {"GPU_1", "GPU_2", "GPU_3", "GPU_4"}) { - threads.emplace_back(load_test_model, instance, LearningModelDeviceKind::DirectX); - } + std::vector threads; + for (const auto& instance : {"1", "2", "3", "4"}) { + threads.emplace_back(load_test_model, instance, LearningModelDeviceKind::Cpu); + } + if (SkipGpuTests()) { + } else { + for (const auto& instance : {"GPU_1", "GPU_2", "GPU_3", "GPU_4"}) { + threads.emplace_back(load_test_model, instance, LearningModelDeviceKind::DirectX); } + } - for (auto& thread : threads) { - thread.join(); - } + for (auto& thread : threads) { + thread.join(); + } } void ConcurrencyTestsClassSetup() { - init_apartment(); - std::srand(static_cast(std::time(nullptr))); + init_apartment(); + std::srand(static_cast(std::time(nullptr))); #ifdef BUILD_INBOX - winrt_activation_handler = WINRT_RoGetActivationFactory; + winrt_activation_handler = WINRT_RoGetActivationFactory; #endif } struct EvaluationUnit { - LearningModel model; - LearningModelSession session; - LearningModelBinding binding; - wf::IAsyncOperation operation; - LearningModelEvaluationResult result; + LearningModel model; + LearningModelSession session; + LearningModelBinding binding; + wf::IAsyncOperation operation; + LearningModelEvaluationResult result; - EvaluationUnit() : model(nullptr), session(nullptr), binding(nullptr), result(nullptr) {} + EvaluationUnit() : model(nullptr), session(nullptr), binding(nullptr), result(nullptr) {} }; // Run EvalAsync for each unit concurrently and get results -void RunAsync(std::vector &evaluation_units) { - std::for_each(evaluation_units.begin(), evaluation_units.end(), [](EvaluationUnit &unit) { - unit.operation = unit.session.EvaluateAsync(unit.binding, L""); - }); - // get results - std::for_each(evaluation_units.begin(), evaluation_units.end(), [](EvaluationUnit &unit) { - unit.result = unit.operation.get(); - }); +void RunAsync(std::vector& evaluation_units) { + std::for_each(evaluation_units.begin(), evaluation_units.end(), [](EvaluationUnit& unit) { + unit.operation = unit.session.EvaluateAsync(unit.binding, L""); + }); + // get results + std::for_each(evaluation_units.begin(), evaluation_units.end(), [](EvaluationUnit& unit) { + unit.result = unit.operation.get(); + }); } -void VerifyEvaluation(const std::vector &evaluation_units, std::vector expected_indices) { - assert(evaluation_units.size() == expected_indices.size()); - for (size_t i = 0; i < evaluation_units.size(); ++i) { - auto unit = evaluation_units[i]; - auto expectedIndex = expected_indices[i]; - auto result = unit.result.Outputs().Lookup(L"softmaxout_1").as().GetAsVectorView(); - int64_t maxIndex = 0; - float maxValue = 0; - for (uint32_t j = 0; j < result.Size(); ++j) - { - float val = result.GetAt(j); - if (val > maxValue) - { - maxValue = val; - maxIndex = j; - } - } - WINML_EXPECT_TRUE(maxIndex == expectedIndex); +void VerifyEvaluation(const std::vector& evaluation_units, std::vector expected_indices) { + assert(evaluation_units.size() == expected_indices.size()); + for (size_t i = 0; i < evaluation_units.size(); ++i) { + auto unit = evaluation_units[i]; + auto expectedIndex = expected_indices[i]; + auto result = unit.result.Outputs().Lookup(L"softmaxout_1").as().GetAsVectorView(); + int64_t maxIndex = 0; + float maxValue = 0; + for (uint32_t j = 0; j < result.Size(); ++j) { + float val = result.GetAt(j); + if (val > maxValue) { + maxValue = val; + maxIndex = j; + } } + WINML_EXPECT_TRUE(maxIndex == expectedIndex); + } } void CopyLocalFile(LPCWSTR from, LPCWSTR to) { - using namespace std; - ifstream source(FileHelpers::GetModulePath() + from, ios::binary); - ofstream dest(FileHelpers::GetModulePath() + to, ios::binary); + using namespace std; + ifstream source(FileHelpers::GetModulePath() + from, ios::binary); + ofstream dest(FileHelpers::GetModulePath() + to, ios::binary); - dest << source.rdbuf(); + dest << source.rdbuf(); } // Run evaluations with different models void EvalAsyncDifferentModels() { - CopyLocalFile(L"model.onnx", L"model2.onnx"); + CopyLocalFile(L"model.onnx", L"model2.onnx"); - std::vector model_paths = { L"model.onnx", L"model2.onnx" }; - const unsigned int num_units = static_cast(model_paths.size()); - std::vector evaluation_units(num_units, EvaluationUnit()); + std::vector model_paths = {L"model.onnx", L"model2.onnx"}; + const unsigned int num_units = static_cast(model_paths.size()); + std::vector evaluation_units(num_units, EvaluationUnit()); - auto ifv = FileHelpers::LoadImageFeatureValue(L"kitten_224.png"); + auto ifv = FileHelpers::LoadImageFeatureValue(L"kitten_224.png"); - for (unsigned int i = 0; i < num_units; ++i) { - evaluation_units[i].model = LearningModel::LoadFromFilePath(FileHelpers::GetModulePath() + model_paths[i]); - evaluation_units[i].session = LearningModelSession(evaluation_units[i].model); - evaluation_units[i].binding = LearningModelBinding(evaluation_units[i].session); - evaluation_units[i].binding.Bind(L"data_0", ifv); - } + for (unsigned int i = 0; i < num_units; ++i) { + evaluation_units[i].model = LearningModel::LoadFromFilePath(FileHelpers::GetModulePath() + model_paths[i]); + evaluation_units[i].session = LearningModelSession(evaluation_units[i].model); + evaluation_units[i].binding = LearningModelBinding(evaluation_units[i].session); + evaluation_units[i].binding.Bind(L"data_0", ifv); + } - RunAsync(evaluation_units); - std::vector indices(num_units, TABBY_CAT_INDEX); - VerifyEvaluation(evaluation_units, indices); + RunAsync(evaluation_units); + std::vector indices(num_units, TABBY_CAT_INDEX); + VerifyEvaluation(evaluation_units, indices); } // Run evaluations with same model, different sessions void EvalAsyncDifferentSessions() { - unsigned int num_units = 3; - std::vector evaluation_units(num_units, EvaluationUnit()); - auto ifv = FileHelpers::LoadImageFeatureValue(L"kitten_224.png"); - - // same model, different session - auto model = LearningModel::LoadFromFilePath(FileHelpers::GetModulePath() + L"model.onnx"); - for (unsigned int i = 0; i < num_units; ++i) { - evaluation_units[i].model = model; - evaluation_units[i].session = LearningModelSession(evaluation_units[i].model); - evaluation_units[i].binding = LearningModelBinding(evaluation_units[i].session); - evaluation_units[i].binding.Bind(L"data_0", ifv); - } + unsigned int num_units = 3; + std::vector evaluation_units(num_units, EvaluationUnit()); + auto ifv = FileHelpers::LoadImageFeatureValue(L"kitten_224.png"); + + // same model, different session + auto model = LearningModel::LoadFromFilePath(FileHelpers::GetModulePath() + L"model.onnx"); + for (unsigned int i = 0; i < num_units; ++i) { + evaluation_units[i].model = model; + evaluation_units[i].session = LearningModelSession(evaluation_units[i].model); + evaluation_units[i].binding = LearningModelBinding(evaluation_units[i].session); + evaluation_units[i].binding.Bind(L"data_0", ifv); + } - RunAsync(evaluation_units); - std::vector indices(num_units, TABBY_CAT_INDEX); - VerifyEvaluation(evaluation_units, indices); + RunAsync(evaluation_units); + std::vector indices(num_units, TABBY_CAT_INDEX); + VerifyEvaluation(evaluation_units, indices); } // Run evaluations with same session (and model), with different bindings void EvalAsyncDifferentBindings() { - unsigned int num_units = 2; - std::vector evaluation_units(num_units, EvaluationUnit()); - - std::vector ifvs = {FileHelpers::LoadImageFeatureValue(L"kitten_224.png"), - FileHelpers::LoadImageFeatureValue(L"fish.png")}; - - // same session, different binding - auto model = LearningModel::LoadFromFilePath(FileHelpers::GetModulePath() + L"model.onnx"); - auto session = LearningModelSession(model); - for (unsigned int i = 0; i < num_units; ++i) { - evaluation_units[i].model = model; - evaluation_units[i].session = session; - evaluation_units[i].binding = LearningModelBinding(evaluation_units[i].session); - evaluation_units[i].binding.Bind(L"data_0", ifvs[i]); - } + unsigned int num_units = 2; + std::vector evaluation_units(num_units, EvaluationUnit()); + + std::vector ifvs = { + FileHelpers::LoadImageFeatureValue(L"kitten_224.png"), FileHelpers::LoadImageFeatureValue(L"fish.png")}; + + // same session, different binding + auto model = LearningModel::LoadFromFilePath(FileHelpers::GetModulePath() + L"model.onnx"); + auto session = LearningModelSession(model); + for (unsigned int i = 0; i < num_units; ++i) { + evaluation_units[i].model = model; + evaluation_units[i].session = session; + evaluation_units[i].binding = LearningModelBinding(evaluation_units[i].session); + evaluation_units[i].binding.Bind(L"data_0", ifvs[i]); + } - RunAsync(evaluation_units); - VerifyEvaluation(evaluation_units, { TABBY_CAT_INDEX, TENCH_INDEX }); + RunAsync(evaluation_units); + VerifyEvaluation(evaluation_units, {TABBY_CAT_INDEX, TENCH_INDEX}); } winml::ILearningModelFeatureDescriptor UnusedCreateFeatureDescriptor( - std::shared_ptr model, - const std::wstring& name, - const std::wstring& description, - bool is_required, - const ::onnx::TypeProto *type_proto); + std::shared_ptr model, + const std::wstring& name, + const std::wstring& description, + bool is_required, + const ::onnx::TypeProto* type_proto +); // Get random number in interval [1,max_number] unsigned int GetRandomNumber(unsigned int max_number) { - return std::rand() % max_number + 1; + return std::rand() % max_number + 1; } void MultiThreadLoadModel() { - // load same model - auto path = FileHelpers::GetModulePath() + L"model.onnx"; - ThreadPool pool(NUM_THREADS); - try { - for (unsigned int i = 0; i < NUM_THREADS; ++i) { - pool.SubmitWork([&path]() { - auto model = LearningModel::LoadFromFilePath(path); - std::wstring name(model.Name()); - WINML_EXPECT_EQUAL(name, L"squeezenet_old"); - }); - } - } - catch (...) { - WINML_LOG_ERROR("Failed to load model concurrently."); + // load same model + auto path = FileHelpers::GetModulePath() + L"model.onnx"; + ThreadPool pool(NUM_THREADS); + try { + for (unsigned int i = 0; i < NUM_THREADS; ++i) { + pool.SubmitWork([&path]() { + auto model = LearningModel::LoadFromFilePath(path); + std::wstring name(model.Name()); + WINML_EXPECT_EQUAL(name, L"squeezenet_old"); + }); } + } catch (...) { + WINML_LOG_ERROR("Failed to load model concurrently."); + } } void MultiThreadMultiSessionOnDevice(const LearningModelDevice& device) { - auto path = FileHelpers::GetModulePath() + L"model.onnx"; - auto model = LearningModel::LoadFromFilePath(path); - std::vector ivfs = { - FileHelpers::LoadImageFeatureValue(L"kitten_224.png"), - FileHelpers::LoadImageFeatureValue(L"fish.png") - }; - std::vector max_indices = { - 281, // tabby, tabby cat - 0 // tench, Tinca tinca - }; - std::vector max_values = { - 0.9314f, - 0.7385f - }; - float tolerance = 0.001f; - std::vector modelSessions(NUM_THREADS, nullptr); - ThreadPool pool(NUM_THREADS); - try { - device.as()->SetMetacommandsEnabled(false); - // create all the sessions - for (unsigned i = 0; i < NUM_THREADS; ++i) { - modelSessions[i] = LearningModelSession(model, device); - } - // start all the threads - for (unsigned i_thread = 0; i_thread < NUM_THREADS; ++i_thread) { - LearningModelSession &model_session = modelSessions[i_thread]; - pool.SubmitWork([&model_session,&ivfs,&max_indices,&max_values,tolerance,i_thread]() { - ULONGLONG start_time = GetTickCount64(); - while (((GetTickCount64() - start_time) / 1000) < NUM_SECONDS) { - auto j = i_thread % ivfs.size(); - auto input = ivfs[j]; - auto expected_index = max_indices[j]; - auto expected_value = max_values[j]; - LearningModelBinding bind(model_session); - bind.Bind(L"data_0", input); - auto result = model_session.Evaluate(bind, L"").Outputs(); - auto softmax = result.Lookup(L"softmaxout_1"); - if (auto tensor = softmax.try_as()) { - auto view = tensor.GetAsVectorView(); - float max_val = .0f; - int max_index = -1; - for (uint32_t i = 0; i < view.Size(); ++i) { - auto val = view.GetAt(i); - if (val > max_val) - { - max_index = i; - max_val = val; - } - } - WINML_EXPECT_EQUAL(expected_index, max_index); - WINML_EXPECT_TRUE(std::abs(expected_value - max_val) < tolerance); - } - } - }); - } + auto path = FileHelpers::GetModulePath() + L"model.onnx"; + auto model = LearningModel::LoadFromFilePath(path); + std::vector ivfs = { + FileHelpers::LoadImageFeatureValue(L"kitten_224.png"), FileHelpers::LoadImageFeatureValue(L"fish.png")}; + std::vector max_indices = { + 281, // tabby, tabby cat + 0 // tench, Tinca tinca + }; + std::vector max_values = {0.9314f, 0.7385f}; + float tolerance = 0.001f; + std::vector modelSessions(NUM_THREADS, nullptr); + ThreadPool pool(NUM_THREADS); + try { + device.as()->SetMetacommandsEnabled(false); + // create all the sessions + for (unsigned i = 0; i < NUM_THREADS; ++i) { + modelSessions[i] = LearningModelSession(model, device); } - catch (...) { - WINML_LOG_ERROR("Failed to create session concurrently."); + // start all the threads + for (unsigned i_thread = 0; i_thread < NUM_THREADS; ++i_thread) { + LearningModelSession& model_session = modelSessions[i_thread]; + pool.SubmitWork([&model_session, &ivfs, &max_indices, &max_values, tolerance, i_thread]() { + ULONGLONG start_time = GetTickCount64(); + while (((GetTickCount64() - start_time) / 1000) < NUM_SECONDS) { + auto j = i_thread % ivfs.size(); + auto input = ivfs[j]; + auto expected_index = max_indices[j]; + auto expected_value = max_values[j]; + LearningModelBinding bind(model_session); + bind.Bind(L"data_0", input); + auto result = model_session.Evaluate(bind, L"").Outputs(); + auto softmax = result.Lookup(L"softmaxout_1"); + if (auto tensor = softmax.try_as()) { + auto view = tensor.GetAsVectorView(); + float max_val = .0f; + int max_index = -1; + for (uint32_t i = 0; i < view.Size(); ++i) { + auto val = view.GetAt(i); + if (val > max_val) { + max_index = i; + max_val = val; + } + } + WINML_EXPECT_EQUAL(expected_index, max_index); + WINML_EXPECT_TRUE(std::abs(expected_value - max_val) < tolerance); + } + } + }); } + } catch (...) { + WINML_LOG_ERROR("Failed to create session concurrently."); + } } void MultiThreadMultiSession() { - MultiThreadMultiSessionOnDevice(LearningModelDevice(LearningModelDeviceKind::Cpu)); + MultiThreadMultiSessionOnDevice(LearningModelDevice(LearningModelDeviceKind::Cpu)); } void MultiThreadMultiSessionGpu() { - MultiThreadMultiSessionOnDevice(LearningModelDevice(LearningModelDeviceKind::DirectX)); + MultiThreadMultiSessionOnDevice(LearningModelDevice(LearningModelDeviceKind::DirectX)); } // Create different sessions for each thread, and evaluate void MultiThreadSingleSessionOnDevice(const LearningModelDevice& device) { - auto path = FileHelpers::GetModulePath() + L"model.onnx"; - auto model = LearningModel::LoadFromFilePath(path); - LearningModelSession model_session = nullptr; - WINML_EXPECT_NO_THROW(model_session = LearningModelSession(model, device)); - std::vector ivfs = { - FileHelpers::LoadImageFeatureValue(L"kitten_224.png"), - FileHelpers::LoadImageFeatureValue(L"fish.png") - }; - std::vector max_indices = { - 281, // tabby, tabby cat - 0 // tench, Tinca tinca - }; - std::vector max_values = { - 0.9314f, - 0.7385f - }; - float tolerance = 0.001f; - - ThreadPool pool(NUM_THREADS); - try { - for (unsigned i = 0; i < NUM_THREADS; ++i) { - pool.SubmitWork([&model_session, &ivfs, &max_indices, &max_values, tolerance, i]() { - ULONGLONG start_time = GetTickCount64(); - while (((GetTickCount64() - start_time) / 1000) < NUM_SECONDS) { - auto j = i % ivfs.size(); - auto input = ivfs[j]; - auto expected_index = max_indices[j]; - auto expected_value = max_values[j]; - std::wstring name(model_session.Model().Name()); - LearningModelBinding bind(model_session); - bind.Bind(L"data_0", input); - auto result = model_session.Evaluate(bind, L"").Outputs(); - auto softmax = result.Lookup(L"softmaxout_1"); - if (auto tensor = softmax.try_as()) - { - auto view = tensor.GetAsVectorView(); - float max_val = .0f; - int max_index = -1; - for (uint32_t k = 0; k < view.Size(); ++k) - { - auto val = view.GetAt(k); - if (val > max_val) - { - max_index = k; - max_val = val; - } - } - WINML_EXPECT_EQUAL(expected_index, max_index); - WINML_EXPECT_TRUE(std::abs(expected_value - max_val) < tolerance); - } - } - }); + auto path = FileHelpers::GetModulePath() + L"model.onnx"; + auto model = LearningModel::LoadFromFilePath(path); + LearningModelSession model_session = nullptr; + WINML_EXPECT_NO_THROW(model_session = LearningModelSession(model, device)); + std::vector ivfs = { + FileHelpers::LoadImageFeatureValue(L"kitten_224.png"), FileHelpers::LoadImageFeatureValue(L"fish.png")}; + std::vector max_indices = { + 281, // tabby, tabby cat + 0 // tench, Tinca tinca + }; + std::vector max_values = {0.9314f, 0.7385f}; + float tolerance = 0.001f; + + ThreadPool pool(NUM_THREADS); + try { + for (unsigned i = 0; i < NUM_THREADS; ++i) { + pool.SubmitWork([&model_session, &ivfs, &max_indices, &max_values, tolerance, i]() { + ULONGLONG start_time = GetTickCount64(); + while (((GetTickCount64() - start_time) / 1000) < NUM_SECONDS) { + auto j = i % ivfs.size(); + auto input = ivfs[j]; + auto expected_index = max_indices[j]; + auto expected_value = max_values[j]; + std::wstring name(model_session.Model().Name()); + LearningModelBinding bind(model_session); + bind.Bind(L"data_0", input); + auto result = model_session.Evaluate(bind, L"").Outputs(); + auto softmax = result.Lookup(L"softmaxout_1"); + if (auto tensor = softmax.try_as()) { + auto view = tensor.GetAsVectorView(); + float max_val = .0f; + int max_index = -1; + for (uint32_t k = 0; k < view.Size(); ++k) { + auto val = view.GetAt(k); + if (val > max_val) { + max_index = k; + max_val = val; + } + } + WINML_EXPECT_EQUAL(expected_index, max_index); + WINML_EXPECT_TRUE(std::abs(expected_value - max_val) < tolerance); + } } + }); } - catch (...) { - WINML_LOG_ERROR("Failed to create session concurrently."); - } + } catch (...) { + WINML_LOG_ERROR("Failed to create session concurrently."); + } } void MultiThreadSingleSession() { - MultiThreadSingleSessionOnDevice(LearningModelDevice(LearningModelDeviceKind::Cpu)); + MultiThreadSingleSessionOnDevice(LearningModelDevice(LearningModelDeviceKind::Cpu)); } void MultiThreadSingleSessionGpu() { - MultiThreadSingleSessionOnDevice(LearningModelDevice(LearningModelDeviceKind::DirectX)); -} + MultiThreadSingleSessionOnDevice(LearningModelDevice(LearningModelDeviceKind::DirectX)); } +} // namespace const ConcurrencyTestsApi& getapi() { static ConcurrencyTestsApi api = { @@ -339,8 +322,7 @@ const ConcurrencyTestsApi& getapi() { MultiThreadSingleSessionGpu, EvalAsyncDifferentModels, EvalAsyncDifferentSessions, - EvalAsyncDifferentBindings - }; + EvalAsyncDifferentBindings}; if (SkipGpuTests()) { api.MultiThreadMultiSessionGpu = SkipTest; diff --git a/winml/test/concurrency/ConcurrencyTests.h b/winml/test/concurrency/ConcurrencyTests.h index 46fb2813dcf92..bf9349942f50c 100644 --- a/winml/test/concurrency/ConcurrencyTests.h +++ b/winml/test/concurrency/ConcurrencyTests.h @@ -4,8 +4,7 @@ #pragma once #include "test.h" -struct ConcurrencyTestsApi -{ +struct ConcurrencyTestsApi { SetupClass ConcurrencyTestsClassSetup; VoidTest LoadBindEvalSqueezenetRealDataWithValidationConcurrently; VoidTest MultiThreadLoadModel; diff --git a/winml/test/concurrency/ThreadPool.cpp b/winml/test/concurrency/ThreadPool.cpp index 164129d12231b..895766e258295 100644 --- a/winml/test/concurrency/ThreadPool.cpp +++ b/winml/test/concurrency/ThreadPool.cpp @@ -3,32 +3,31 @@ #include ThreadPool::ThreadPool(unsigned int initial_pool_size) : m_destruct_pool(false), m_threads() { - for (unsigned int i = 0; i < initial_pool_size; i++) { - m_threads.emplace_back([this]() { - while (true) { - std::unique_lock lock(m_mutex); - // thread listening for event and acquire lock if event triggered - m_cond_var.wait(lock, [this] { return m_destruct_pool || !m_work_queue.empty(); }); - if (!m_work_queue.empty()) { - auto work = m_work_queue.front(); - m_work_queue.pop(); - lock.unlock(); - work(); - } - else { - // Work queue is empty but lock acquired - // This means we are destructing the pool - break; - } - } - }); - } + for (unsigned int i = 0; i < initial_pool_size; i++) { + m_threads.emplace_back([this]() { + while (true) { + std::unique_lock lock(m_mutex); + // thread listening for event and acquire lock if event triggered + m_cond_var.wait(lock, [this] { return m_destruct_pool || !m_work_queue.empty(); }); + if (!m_work_queue.empty()) { + auto work = m_work_queue.front(); + m_work_queue.pop(); + lock.unlock(); + work(); + } else { + // Work queue is empty but lock acquired + // This means we are destructing the pool + break; + } + } + }); + } } ThreadPool::~ThreadPool() { - m_destruct_pool = true; - m_cond_var.notify_all(); // notify destruction to threads - for (auto &thread : m_threads) { - thread.join(); - } + m_destruct_pool = true; + m_cond_var.notify_all(); // notify destruction to threads + for (auto& thread : m_threads) { + thread.join(); + } } diff --git a/winml/test/concurrency/ThreadPool.h b/winml/test/concurrency/ThreadPool.h index 96a279f53ce75..aa6f2e05bfe45 100644 --- a/winml/test/concurrency/ThreadPool.h +++ b/winml/test/concurrency/ThreadPool.h @@ -7,27 +7,27 @@ #include class ThreadPool { -private: - std::condition_variable m_cond_var; - bool m_destruct_pool; - std::mutex m_mutex; - std::vector m_threads; - std::queue> m_work_queue; + private: + std::condition_variable m_cond_var; + bool m_destruct_pool; + std::mutex m_mutex; + std::vector m_threads; + std::queue> m_work_queue; -public: - ThreadPool(unsigned int initial_pool_size); - ~ThreadPool(); - template - inline auto SubmitWork(F &&f, Args&&... args) -> std::future { - auto func = std::bind(std::forward(f), std::forward(args)...); - auto task = std::make_shared>(std::forward(func)); - { - std::lock_guard lock(m_mutex); - // wrap packed task into a void return function type so that it can be stored in queue - m_work_queue.push([task]() { (*task)(); }); - } - - m_cond_var.notify_one(); // unblocks one of the waiting threads - return task->get_future(); + public: + ThreadPool(unsigned int initial_pool_size); + ~ThreadPool(); + template + inline auto SubmitWork(F&& f, Args&&... args) -> std::future { + auto func = std::bind(std::forward(f), std::forward(args)...); + auto task = std::make_shared>(std::forward(func)); + { + std::lock_guard lock(m_mutex); + // wrap packed task into a void return function type so that it can be stored in queue + m_work_queue.push([task]() { (*task)(); }); } + + m_cond_var.notify_one(); // unblocks one of the waiting threads + return task->get_future(); + } }; diff --git a/winml/test/image/imageTestHelper.cpp b/winml/test/image/imageTestHelper.cpp index 5175a55db250c..b7c1eb42965f8 100644 --- a/winml/test/image/imageTestHelper.cpp +++ b/winml/test/image/imageTestHelper.cpp @@ -18,271 +18,257 @@ using namespace wm; using namespace wgi; namespace ImageTestHelper { - BitmapPixelFormat GetPixelFormat(const std::wstring& inputPixelFormat) { - // Return corresponding BitmapPixelFormat according to input string - if (L"Bgra8" == inputPixelFormat || L"Bgr8" == inputPixelFormat) { - return BitmapPixelFormat::Bgra8; - } else if (L"Rgba8" == inputPixelFormat || L"Rgb8" == inputPixelFormat) { - return BitmapPixelFormat::Rgba8; - } else if (L"Gray8" == inputPixelFormat) { - return BitmapPixelFormat::Gray8; - } else { - throw std::invalid_argument("Unsupported pixelFormat"); - } - } +BitmapPixelFormat GetPixelFormat(const std::wstring& inputPixelFormat) { + // Return corresponding BitmapPixelFormat according to input string + if (L"Bgra8" == inputPixelFormat || L"Bgr8" == inputPixelFormat) { + return BitmapPixelFormat::Bgra8; + } else if (L"Rgba8" == inputPixelFormat || L"Rgb8" == inputPixelFormat) { + return BitmapPixelFormat::Rgba8; + } else if (L"Gray8" == inputPixelFormat) { + return BitmapPixelFormat::Gray8; + } else { + throw std::invalid_argument("Unsupported pixelFormat"); + } +} - TensorFloat LoadInputImageFromCPU( - SoftwareBitmap softwareBitmap, - const std::wstring& modelPixelFormat) { - softwareBitmap = SoftwareBitmap::Convert(softwareBitmap, BitmapPixelFormat::Bgra8); - BYTE* pData = nullptr; - UINT32 size = 0; - wgi::BitmapBuffer spBitmapBuffer(softwareBitmap.LockBuffer(wgi::BitmapBufferAccessMode::Read)); - wf::IMemoryBufferReference reference = spBitmapBuffer.CreateReference(); - auto spByteAccess = reference.as<::Windows::Foundation::IMemoryBufferByteAccess>(); - spByteAccess->GetBuffer(&pData, &size); - uint32_t height = softwareBitmap.PixelHeight(); - uint32_t width = softwareBitmap.PixelWidth(); - - // TODO: Need modification for Gray8 - std::vector shape = { 1, 3, height , width }; - float* pCPUTensor; - uint32_t uCapacity; - TensorFloat tf = TensorFloat::Create(shape); - com_ptr itn = tf.as(); - itn->GetBuffer(reinterpret_cast(&pCPUTensor), &uCapacity); - if (BitmapPixelFormat::Bgra8 == GetPixelFormat(modelPixelFormat)) { - // loop condition is i < size - 2 to avoid potential for extending past the memory buffer - for (UINT32 i = 0; i < size - 2; i += 4) { - UINT32 pixelInd = i / 4; - pCPUTensor[pixelInd] = (float)pData[i]; - pCPUTensor[(height * width) + pixelInd] = (float)pData[i + 1]; - pCPUTensor[(height * width * 2) + pixelInd] = (float)pData[i + 2]; - } - } else if (BitmapPixelFormat::Rgba8 == GetPixelFormat(modelPixelFormat)) { - for (UINT32 i = 0; i < size - 2; i += 4) { - UINT32 pixelInd = i / 4; - pCPUTensor[pixelInd] = (float)pData[i + 2]; - pCPUTensor[(height * width) + pixelInd] = (float)pData[i + 1]; - pCPUTensor[(height * width * 2) + pixelInd] = (float)pData[i]; - } - } - // else if() - // TODO: for Gray8 - else { - std::cerr << "Unsupported pixelFormat"; - } - return tf; +TensorFloat LoadInputImageFromCPU(SoftwareBitmap softwareBitmap, const std::wstring& modelPixelFormat) { + softwareBitmap = SoftwareBitmap::Convert(softwareBitmap, BitmapPixelFormat::Bgra8); + BYTE* pData = nullptr; + UINT32 size = 0; + wgi::BitmapBuffer spBitmapBuffer(softwareBitmap.LockBuffer(wgi::BitmapBufferAccessMode::Read)); + wf::IMemoryBufferReference reference = spBitmapBuffer.CreateReference(); + auto spByteAccess = reference.as<::Windows::Foundation::IMemoryBufferByteAccess>(); + spByteAccess->GetBuffer(&pData, &size); + uint32_t height = softwareBitmap.PixelHeight(); + uint32_t width = softwareBitmap.PixelWidth(); + + // TODO: Need modification for Gray8 + std::vector shape = {1, 3, height, width}; + float* pCPUTensor; + uint32_t uCapacity; + TensorFloat tf = TensorFloat::Create(shape); + com_ptr itn = tf.as(); + itn->GetBuffer(reinterpret_cast(&pCPUTensor), &uCapacity); + if (BitmapPixelFormat::Bgra8 == GetPixelFormat(modelPixelFormat)) { + // loop condition is i < size - 2 to avoid potential for extending past the memory buffer + for (UINT32 i = 0; i < size - 2; i += 4) { + UINT32 pixelInd = i / 4; + pCPUTensor[pixelInd] = (float)pData[i]; + pCPUTensor[(height * width) + pixelInd] = (float)pData[i + 1]; + pCPUTensor[(height * width * 2) + pixelInd] = (float)pData[i + 2]; + } + } else if (BitmapPixelFormat::Rgba8 == GetPixelFormat(modelPixelFormat)) { + for (UINT32 i = 0; i < size - 2; i += 4) { + UINT32 pixelInd = i / 4; + pCPUTensor[pixelInd] = (float)pData[i + 2]; + pCPUTensor[(height * width) + pixelInd] = (float)pData[i + 1]; + pCPUTensor[(height * width * 2) + pixelInd] = (float)pData[i]; } + } + // else if() + // TODO: for Gray8 + else { + std::cerr << "Unsupported pixelFormat"; + } + return tf; +} - TensorFloat LoadInputImageFromGPU( - SoftwareBitmap softwareBitmap, - const std::wstring& modelPixelFormat) { - - softwareBitmap = SoftwareBitmap::Convert(softwareBitmap, BitmapPixelFormat::Bgra8); - BYTE* pData = nullptr; - UINT32 size = 0; - BitmapBuffer spBitmapBuffer(softwareBitmap.LockBuffer(wgi::BitmapBufferAccessMode::Read)); - wf::IMemoryBufferReference reference = spBitmapBuffer.CreateReference(); - com_ptr<::Windows::Foundation::IMemoryBufferByteAccess> spByteAccess = reference.as<::Windows::Foundation::IMemoryBufferByteAccess>(); - spByteAccess->GetBuffer(&pData, &size); - - std::vector shape = { 1, 3, softwareBitmap.PixelHeight() , softwareBitmap.PixelWidth() }; - float* pCPUTensor; - uint32_t uCapacity; - - // CPU tensor initialization - TensorFloat tf = TensorFloat::Create(shape); - com_ptr itn = tf.as(); - itn->GetBuffer(reinterpret_cast(&pCPUTensor), &uCapacity); - - uint32_t height = softwareBitmap.PixelHeight(); - uint32_t width = softwareBitmap.PixelWidth(); - if (BitmapPixelFormat::Bgra8 == GetPixelFormat(modelPixelFormat)) { - // loop condition is i < size - 2 to avoid potential for extending past the memory buffer - for (UINT32 i = 0; i < size - 2; i += 4) { - UINT32 pixelInd = i / 4; - pCPUTensor[pixelInd] = (float)pData[i]; - pCPUTensor[(height * width) + pixelInd] = (float)pData[i + 1]; - pCPUTensor[(height * width * 2) + pixelInd] = (float)pData[i + 2]; - } - } else if (BitmapPixelFormat::Rgba8 == GetPixelFormat(modelPixelFormat)) { - for (UINT32 i = 0; i < size - 2; i += 4) { - UINT32 pixelInd = i / 4; - pCPUTensor[pixelInd] = (float)pData[i + 2]; - pCPUTensor[(height * width) + pixelInd] = (float)pData[i + 1]; - pCPUTensor[(height * width * 2) + pixelInd] = (float)pData[i]; - } - } - // else if() - // TODO: for Gray8 - else { - std::cerr << "unsupported pixelFormat"; - } - - // create the d3d device. - com_ptr pD3D12Device = nullptr; - WINML_EXPECT_NO_THROW(D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), reinterpret_cast(&pD3D12Device))); - - // create the command queue. - com_ptr dxQueue = nullptr; - D3D12_COMMAND_QUEUE_DESC commandQueueDesc = {}; - commandQueueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; - pD3D12Device->CreateCommandQueue(&commandQueueDesc, __uuidof(ID3D12CommandQueue), reinterpret_cast(&dxQueue)); - com_ptr devicefactory = get_activation_factory(); - com_ptr tensorfactory = get_activation_factory(); - com_ptr<::IUnknown> spUnk; - devicefactory->CreateFromD3D12CommandQueue(dxQueue.get(), spUnk.put()); - - // Create ID3D12GraphicsCommandList and Allocator - D3D12_COMMAND_LIST_TYPE queuetype = dxQueue->GetDesc().Type; - com_ptr alloctor; - com_ptr cmdList; - - pD3D12Device->CreateCommandAllocator( - queuetype, - winrt::guid_of(), - alloctor.put_void()); - - pD3D12Device->CreateCommandList( - 0, - queuetype, - alloctor.get(), - nullptr, - winrt::guid_of(), - cmdList.put_void()); - - // Create Committed Resource - // 3 is number of channels we use. R G B without alpha. - UINT64 bufferbytesize = 3 * sizeof(float) * softwareBitmap.PixelWidth()*softwareBitmap.PixelHeight(); - D3D12_HEAP_PROPERTIES heapProperties = { - D3D12_HEAP_TYPE_DEFAULT, - D3D12_CPU_PAGE_PROPERTY_UNKNOWN, - D3D12_MEMORY_POOL_UNKNOWN, - 0, - 0 - }; - D3D12_RESOURCE_DESC resourceDesc = { - D3D12_RESOURCE_DIMENSION_BUFFER, - 0, - bufferbytesize, - 1, - 1, - 1, - DXGI_FORMAT_UNKNOWN, - { 1, 0 }, - D3D12_TEXTURE_LAYOUT_ROW_MAJOR, - D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS - }; - - com_ptr pGPUResource = nullptr; - com_ptr imageUploadHeap; - pD3D12Device->CreateCommittedResource( - &heapProperties, - D3D12_HEAP_FLAG_NONE, - &resourceDesc, - D3D12_RESOURCE_STATE_COMMON, - nullptr, - __uuidof(ID3D12Resource), - pGPUResource.put_void() - ); - - // Create the GPU upload buffer. - auto heap_properties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD); - auto buffer_desc = CD3DX12_RESOURCE_DESC::Buffer(bufferbytesize); - WINML_EXPECT_NO_THROW(pD3D12Device->CreateCommittedResource( - &heap_properties, - D3D12_HEAP_FLAG_NONE, - &buffer_desc, - D3D12_RESOURCE_STATE_GENERIC_READ, - nullptr, - __uuidof(ID3D12Resource), - imageUploadHeap.put_void())); - - // Copy from Cpu to GPU - D3D12_SUBRESOURCE_DATA CPUData = {}; - CPUData.pData = reinterpret_cast(pCPUTensor); - CPUData.RowPitch = static_cast(bufferbytesize); - CPUData.SlicePitch = static_cast(bufferbytesize); - UpdateSubresources(cmdList.get(), pGPUResource.get(), imageUploadHeap.get(), 0, 0, 1, &CPUData); - - // Close the command list and execute it to begin the initial GPU setup. - WINML_EXPECT_NO_THROW(cmdList->Close()); - ID3D12CommandList* ppCommandLists[] = { cmdList.get() }; - dxQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists); - - //Create Event - HANDLE directEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); - wil::unique_event hDirectEvent(directEvent); - - //Create Fence - ::Microsoft::WRL::ComPtr spDirectFence = nullptr; - WINML_EXPECT_HRESULT_SUCCEEDED(pD3D12Device->CreateFence( - 0, - D3D12_FENCE_FLAG_NONE, - IID_PPV_ARGS(spDirectFence.ReleaseAndGetAddressOf()))); - //Adds fence to queue - WINML_EXPECT_HRESULT_SUCCEEDED(dxQueue->Signal(spDirectFence.Get(), FENCE_SIGNAL_VALUE)); - WINML_EXPECT_HRESULT_SUCCEEDED(spDirectFence->SetEventOnCompletion(FENCE_SIGNAL_VALUE, hDirectEvent.get())); - - //Wait for signal - DWORD retVal = WaitForSingleObject(hDirectEvent.get(), INFINITE); - if (retVal != WAIT_OBJECT_0) { - WINML_EXPECT_HRESULT_SUCCEEDED(E_UNEXPECTED); - } - - // GPU tensorize - com_ptr<::IUnknown> spUnkTensor; - TensorFloat input1imagetensor(nullptr); - int64_t shapes[4] = { 1,3, softwareBitmap.PixelWidth(), softwareBitmap.PixelHeight() }; - tensorfactory->CreateFromD3D12Resource(pGPUResource.get(), shapes, 4, spUnkTensor.put()); - spUnkTensor.try_as(input1imagetensor); - - return input1imagetensor; +TensorFloat LoadInputImageFromGPU(SoftwareBitmap softwareBitmap, const std::wstring& modelPixelFormat) { + softwareBitmap = SoftwareBitmap::Convert(softwareBitmap, BitmapPixelFormat::Bgra8); + BYTE* pData = nullptr; + UINT32 size = 0; + BitmapBuffer spBitmapBuffer(softwareBitmap.LockBuffer(wgi::BitmapBufferAccessMode::Read)); + wf::IMemoryBufferReference reference = spBitmapBuffer.CreateReference(); + com_ptr<::Windows::Foundation::IMemoryBufferByteAccess> spByteAccess = + reference.as<::Windows::Foundation::IMemoryBufferByteAccess>(); + spByteAccess->GetBuffer(&pData, &size); + + std::vector shape = {1, 3, softwareBitmap.PixelHeight(), softwareBitmap.PixelWidth()}; + float* pCPUTensor; + uint32_t uCapacity; + + // CPU tensor initialization + TensorFloat tf = TensorFloat::Create(shape); + com_ptr itn = tf.as(); + itn->GetBuffer(reinterpret_cast(&pCPUTensor), &uCapacity); + + uint32_t height = softwareBitmap.PixelHeight(); + uint32_t width = softwareBitmap.PixelWidth(); + if (BitmapPixelFormat::Bgra8 == GetPixelFormat(modelPixelFormat)) { + // loop condition is i < size - 2 to avoid potential for extending past the memory buffer + for (UINT32 i = 0; i < size - 2; i += 4) { + UINT32 pixelInd = i / 4; + pCPUTensor[pixelInd] = (float)pData[i]; + pCPUTensor[(height * width) + pixelInd] = (float)pData[i + 1]; + pCPUTensor[(height * width * 2) + pixelInd] = (float)pData[i + 2]; + } + } else if (BitmapPixelFormat::Rgba8 == GetPixelFormat(modelPixelFormat)) { + for (UINT32 i = 0; i < size - 2; i += 4) { + UINT32 pixelInd = i / 4; + pCPUTensor[pixelInd] = (float)pData[i + 2]; + pCPUTensor[(height * width) + pixelInd] = (float)pData[i + 1]; + pCPUTensor[(height * width * 2) + pixelInd] = (float)pData[i]; } + } + // else if() + // TODO: for Gray8 + else { + std::cerr << "unsupported pixelFormat"; + } + + // create the d3d device. + com_ptr pD3D12Device = nullptr; + WINML_EXPECT_NO_THROW(D3D12CreateDevice( + nullptr, D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), reinterpret_cast(&pD3D12Device) + )); + + // create the command queue. + com_ptr dxQueue = nullptr; + D3D12_COMMAND_QUEUE_DESC commandQueueDesc = {}; + commandQueueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; + pD3D12Device->CreateCommandQueue(&commandQueueDesc, __uuidof(ID3D12CommandQueue), reinterpret_cast(&dxQueue)); + com_ptr devicefactory = + get_activation_factory(); + com_ptr tensorfactory = get_activation_factory(); + com_ptr<::IUnknown> spUnk; + devicefactory->CreateFromD3D12CommandQueue(dxQueue.get(), spUnk.put()); + + // Create ID3D12GraphicsCommandList and Allocator + D3D12_COMMAND_LIST_TYPE queuetype = dxQueue->GetDesc().Type; + com_ptr alloctor; + com_ptr cmdList; + + pD3D12Device->CreateCommandAllocator(queuetype, winrt::guid_of(), alloctor.put_void()); + + pD3D12Device->CreateCommandList( + 0, queuetype, alloctor.get(), nullptr, winrt::guid_of(), cmdList.put_void() + ); + + // Create Committed Resource + // 3 is number of channels we use. R G B without alpha. + UINT64 bufferbytesize = 3 * sizeof(float) * softwareBitmap.PixelWidth() * softwareBitmap.PixelHeight(); + D3D12_HEAP_PROPERTIES heapProperties = { + D3D12_HEAP_TYPE_DEFAULT, D3D12_CPU_PAGE_PROPERTY_UNKNOWN, D3D12_MEMORY_POOL_UNKNOWN, 0, 0}; + D3D12_RESOURCE_DESC resourceDesc = { + D3D12_RESOURCE_DIMENSION_BUFFER, + 0, + bufferbytesize, + 1, + 1, + 1, + DXGI_FORMAT_UNKNOWN, + {1, 0}, + D3D12_TEXTURE_LAYOUT_ROW_MAJOR, + D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS + }; + + com_ptr pGPUResource = nullptr; + com_ptr imageUploadHeap; + pD3D12Device->CreateCommittedResource( + &heapProperties, + D3D12_HEAP_FLAG_NONE, + &resourceDesc, + D3D12_RESOURCE_STATE_COMMON, + nullptr, + __uuidof(ID3D12Resource), + pGPUResource.put_void() + ); + + // Create the GPU upload buffer. + auto heap_properties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD); + auto buffer_desc = CD3DX12_RESOURCE_DESC::Buffer(bufferbytesize); + WINML_EXPECT_NO_THROW(pD3D12Device->CreateCommittedResource( + &heap_properties, + D3D12_HEAP_FLAG_NONE, + &buffer_desc, + D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, + __uuidof(ID3D12Resource), + imageUploadHeap.put_void() + )); + + // Copy from Cpu to GPU + D3D12_SUBRESOURCE_DATA CPUData = {}; + CPUData.pData = reinterpret_cast(pCPUTensor); + CPUData.RowPitch = static_cast(bufferbytesize); + CPUData.SlicePitch = static_cast(bufferbytesize); + UpdateSubresources(cmdList.get(), pGPUResource.get(), imageUploadHeap.get(), 0, 0, 1, &CPUData); + + // Close the command list and execute it to begin the initial GPU setup. + WINML_EXPECT_NO_THROW(cmdList->Close()); + ID3D12CommandList* ppCommandLists[] = {cmdList.get()}; + dxQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists); + + //Create Event + HANDLE directEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); + wil::unique_event hDirectEvent(directEvent); + + //Create Fence + ::Microsoft::WRL::ComPtr spDirectFence = nullptr; + WINML_EXPECT_HRESULT_SUCCEEDED( + pD3D12Device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(spDirectFence.ReleaseAndGetAddressOf())) + ); + //Adds fence to queue + WINML_EXPECT_HRESULT_SUCCEEDED(dxQueue->Signal(spDirectFence.Get(), FENCE_SIGNAL_VALUE)); + WINML_EXPECT_HRESULT_SUCCEEDED(spDirectFence->SetEventOnCompletion(FENCE_SIGNAL_VALUE, hDirectEvent.get())); + + //Wait for signal + DWORD retVal = WaitForSingleObject(hDirectEvent.get(), INFINITE); + if (retVal != WAIT_OBJECT_0) { + WINML_EXPECT_HRESULT_SUCCEEDED(E_UNEXPECTED); + } + + // GPU tensorize + com_ptr<::IUnknown> spUnkTensor; + TensorFloat input1imagetensor(nullptr); + int64_t shapes[4] = {1, 3, softwareBitmap.PixelWidth(), softwareBitmap.PixelHeight()}; + tensorfactory->CreateFromD3D12Resource(pGPUResource.get(), shapes, 4, spUnkTensor.put()); + spUnkTensor.try_as(input1imagetensor); + + return input1imagetensor; +} - bool VerifyHelper( - VideoFrame actual, - VideoFrame expected) { - // Verify two input ImageFeatureValues are identified. - auto softwareBitmapActual = actual.SoftwareBitmap(); - auto softwareBitmapExpected = expected.SoftwareBitmap(); - WINML_EXPECT_TRUE(softwareBitmapActual.PixelHeight() == softwareBitmapExpected.PixelHeight()); - WINML_EXPECT_TRUE(softwareBitmapActual.PixelWidth() == softwareBitmapExpected.PixelWidth()); - WINML_EXPECT_TRUE(softwareBitmapActual.BitmapPixelFormat() == softwareBitmapExpected.BitmapPixelFormat()); - - uint32_t size = 4 * softwareBitmapActual.PixelHeight() * softwareBitmapActual.PixelWidth(); - - ws::Streams::Buffer actualOutputBuffer(size); - ws::Streams::Buffer expectedOutputBuffer(size); - - softwareBitmapActual.CopyToBuffer(actualOutputBuffer); - softwareBitmapExpected.CopyToBuffer(expectedOutputBuffer); - - byte* actualBytes; - actualOutputBuffer.try_as<::Windows::Storage::Streams::IBufferByteAccess>()->Buffer(&actualBytes); - byte* expectedBytes; - expectedOutputBuffer.try_as<::Windows::Storage::Streams::IBufferByteAccess>()->Buffer(&expectedBytes); - - byte* pActualByte = actualBytes; - byte* pExpectedByte = expectedBytes; - - // hard code, might need to be modified later. - const float cMaxErrorRate = 0.4f; - int8_t epsilon = 20; - - // Even given two same ImageFeatureValues, the comparison cannot exactly match. - // So we use error rate. - UINT errors = 0; - for (uint32_t i = 0; i < size; i++, pActualByte++, pExpectedByte++) { - // Only the check the first three channels, which are (B, G, R) - if((i + 1) % 4 == 0) continue; - auto diff = (*pActualByte - *pExpectedByte); - if (diff > epsilon) { - errors++; - } - } - std::cerr << "total errors is " << errors << "/" << size << ", errors rate is " << (float)errors / size << std::endl; - return (float)errors / size < cMaxErrorRate; +bool VerifyHelper(VideoFrame actual, VideoFrame expected) { + // Verify two input ImageFeatureValues are identified. + auto softwareBitmapActual = actual.SoftwareBitmap(); + auto softwareBitmapExpected = expected.SoftwareBitmap(); + WINML_EXPECT_TRUE(softwareBitmapActual.PixelHeight() == softwareBitmapExpected.PixelHeight()); + WINML_EXPECT_TRUE(softwareBitmapActual.PixelWidth() == softwareBitmapExpected.PixelWidth()); + WINML_EXPECT_TRUE(softwareBitmapActual.BitmapPixelFormat() == softwareBitmapExpected.BitmapPixelFormat()); + + uint32_t size = 4 * softwareBitmapActual.PixelHeight() * softwareBitmapActual.PixelWidth(); + + ws::Streams::Buffer actualOutputBuffer(size); + ws::Streams::Buffer expectedOutputBuffer(size); + + softwareBitmapActual.CopyToBuffer(actualOutputBuffer); + softwareBitmapExpected.CopyToBuffer(expectedOutputBuffer); + + byte* actualBytes; + actualOutputBuffer.try_as<::Windows::Storage::Streams::IBufferByteAccess>()->Buffer(&actualBytes); + byte* expectedBytes; + expectedOutputBuffer.try_as<::Windows::Storage::Streams::IBufferByteAccess>()->Buffer(&expectedBytes); + + byte* pActualByte = actualBytes; + byte* pExpectedByte = expectedBytes; + + // hard code, might need to be modified later. + const float cMaxErrorRate = 0.4f; + int8_t epsilon = 20; + + // Even given two same ImageFeatureValues, the comparison cannot exactly match. + // So we use error rate. + UINT errors = 0; + for (uint32_t i = 0; i < size; i++, pActualByte++, pExpectedByte++) { + // Only the check the first three channels, which are (B, G, R) + if ((i + 1) % 4 == 0) + continue; + auto diff = (*pActualByte - *pExpectedByte); + if (diff > epsilon) { + errors++; } + } + std::cerr << "total errors is " << errors << "/" << size << ", errors rate is " << (float)errors / size << std::endl; + return (float)errors / size < cMaxErrorRate; } +} // namespace ImageTestHelper diff --git a/winml/test/image/imageTestHelper.h b/winml/test/image/imageTestHelper.h index f5c397aeba72d..922657a412d5c 100644 --- a/winml/test/image/imageTestHelper.h +++ b/winml/test/image/imageTestHelper.h @@ -9,26 +9,38 @@ #include #include -enum OutputBindingStrategy { Bound, Unbound, Empty }; -enum EvaluationStrategy { Async, Sync }; -enum ModelInputOutputType { Image, Tensor }; -enum InputImageSource { FromVideoFrame, FromImageFeatureValue, FromCPUResource, FromGPUResource }; -enum VideoFrameSource { FromSoftwareBitmap, FromDirect3DSurface, FromUnsupportedD3DSurface }; - -namespace ImageTestHelper -{ - wgi::BitmapPixelFormat GetPixelFormat(const std::wstring& inputPixelFormat); - - winml::TensorFloat LoadInputImageFromCPU( - wgi::SoftwareBitmap softwareBitmap, - const std::wstring& modelPixelFormat); - - winml::TensorFloat LoadInputImageFromGPU( - wgi::SoftwareBitmap softwareBitmap, - const std::wstring& modelPixelFormat); - - bool VerifyHelper( - wm::VideoFrame actual, - wm::VideoFrame expected); - -} +enum OutputBindingStrategy { + Bound, + Unbound, + Empty +}; +enum EvaluationStrategy { + Async, + Sync +}; +enum ModelInputOutputType { + Image, + Tensor +}; +enum InputImageSource { + FromVideoFrame, + FromImageFeatureValue, + FromCPUResource, + FromGPUResource +}; +enum VideoFrameSource { + FromSoftwareBitmap, + FromDirect3DSurface, + FromUnsupportedD3DSurface +}; + +namespace ImageTestHelper { +wgi::BitmapPixelFormat GetPixelFormat(const std::wstring& inputPixelFormat); + +winml::TensorFloat LoadInputImageFromCPU(wgi::SoftwareBitmap softwareBitmap, const std::wstring& modelPixelFormat); + +winml::TensorFloat LoadInputImageFromGPU(wgi::SoftwareBitmap softwareBitmap, const std::wstring& modelPixelFormat); + +bool VerifyHelper(wm::VideoFrame actual, wm::VideoFrame expected); + +} // namespace ImageTestHelper diff --git a/winml/test/image/imagetests.cpp b/winml/test/image/imagetests.cpp index 73b9e381c1da2..6157520ca96a3 100644 --- a/winml/test/image/imagetests.cpp +++ b/winml/test/image/imagetests.cpp @@ -23,1036 +23,1158 @@ using namespace ws; using namespace wss; enum BindingLocation { - CPU, - GPU + CPU, + GPU }; class ImageTests : public ::testing::Test { -protected: - winml::LearningModel m_model = nullptr; - winml::LearningModelDevice m_device = nullptr; - winml::LearningModelSession m_session = nullptr; - winml::LearningModelBinding m_model_binding = nullptr; - winml::LearningModelEvaluationResult m_result = nullptr; - - static void SetUpTestSuite() { - init_apartment(); + protected: + winml::LearningModel m_model = nullptr; + winml::LearningModelDevice m_device = nullptr; + winml::LearningModelSession m_session = nullptr; + winml::LearningModelBinding m_model_binding = nullptr; + winml::LearningModelEvaluationResult m_result = nullptr; + + static void SetUpTestSuite() { + init_apartment(); #ifdef BUILD_INBOX - winrt_activation_handler = WINRT_RoGetActivationFactory; + winrt_activation_handler = WINRT_RoGetActivationFactory; #endif + } + + void LoadModel(const std::wstring& model_path) { + std::wstring full_path = FileHelpers::GetModulePath() + model_path; + WINML_EXPECT_NO_THROW(m_model = LearningModel::LoadFromFilePath(full_path)); + } + + void ImageTests::PrepareModelSessionBinding( + const std::wstring& model_file_name, + LearningModelDeviceKind device_kind, + std::optional optimized_batch_size + ) { + LoadModel(std::wstring(model_file_name)); + WINML_EXPECT_NO_THROW(m_device = LearningModelDevice(device_kind)); + if (optimized_batch_size.has_value()) { + LearningModelSessionOptions options; + options.BatchSizeOverride(optimized_batch_size.value()); + WINML_EXPECT_NO_THROW(m_session = LearningModelSession(m_model, m_device, options)); + } else { + WINML_EXPECT_NO_THROW(m_session = LearningModelSession(m_model, m_device)); } - - void LoadModel(const std::wstring& model_path) { - std::wstring full_path = FileHelpers::GetModulePath() + model_path; - WINML_EXPECT_NO_THROW(m_model = LearningModel::LoadFromFilePath(full_path)); + WINML_EXPECT_NO_THROW(m_model_binding = LearningModelBinding(m_session)); + } + + bool BindInputValue( + const std::wstring& image_file_name, + const std::wstring& input_pixel_format, + const std::wstring& model_pixel_format, + InputImageSource input_image_source, + LearningModelDeviceKind device_kind + ) { + std::wstring full_image_path = FileHelpers::GetModulePath() + image_file_name; + StorageFile image_file = StorageFile::GetFileFromPathAsync(full_image_path).get(); + IRandomAccessStream stream = image_file.OpenAsync(FileAccessMode::Read).get(); + BitmapDecoder bitmap_decoder = BitmapDecoder::CreateAsync(stream).get(); + SoftwareBitmap software_bitmap = bitmap_decoder.GetSoftwareBitmapAsync().get(); + + // Convert the input image to PixelFormat specified + software_bitmap = SoftwareBitmap::Convert(software_bitmap, ImageTestHelper::GetPixelFormat(input_pixel_format)); + + auto input_feature = m_model.InputFeatures().First(); + if (InputImageSource::FromImageFeatureValue == input_image_source) { + VideoFrame frame = VideoFrame::CreateWithSoftwareBitmap(software_bitmap); + ImageFeatureValue image_input_tensor = ImageFeatureValue::CreateFromVideoFrame(frame); + WINML_EXPECT_NO_THROW(m_model_binding.Bind(input_feature.Current().Name(), image_input_tensor)); + } else if (InputImageSource::FromVideoFrame == input_image_source) { + VideoFrame frame = VideoFrame::CreateWithSoftwareBitmap(software_bitmap); + WINML_EXPECT_NO_THROW(m_model_binding.Bind(input_feature.Current().Name(), frame)); + } else if (InputImageSource::FromCPUResource == input_image_source) { + TensorFloat tensor_float = ImageTestHelper::LoadInputImageFromCPU(software_bitmap, model_pixel_format); + WINML_EXPECT_NO_THROW(m_model_binding.Bind(input_feature.Current().Name(), tensor_float)); + } else if (InputImageSource::FromGPUResource == input_image_source) { + TensorFloat tensor_float = ImageTestHelper::LoadInputImageFromGPU(software_bitmap, model_pixel_format); + if (LearningModelDeviceKind::Cpu == device_kind) { + WINML_EXPECT_THROW_SPECIFIC( + m_model_binding.Bind(input_feature.Current().Name(), tensor_float), + winrt::hresult_error, + [](const winrt::hresult_error& e) -> bool { return e.code() == WINML_ERR_INVALID_BINDING; } + ); + return false; + } + WINML_EXPECT_NO_THROW(m_model_binding.Bind(input_feature.Current().Name(), tensor_float)); } - - void ImageTests::PrepareModelSessionBinding( - const std::wstring& model_file_name, - LearningModelDeviceKind device_kind, - std::optional optimized_batch_size) { - LoadModel(std::wstring(model_file_name)); - WINML_EXPECT_NO_THROW(m_device = LearningModelDevice(device_kind)); - if (optimized_batch_size.has_value()) { - LearningModelSessionOptions options; - options.BatchSizeOverride(optimized_batch_size.value()); - WINML_EXPECT_NO_THROW(m_session = LearningModelSession(m_model, m_device, options)); - } - else { - WINML_EXPECT_NO_THROW(m_session = LearningModelSession(m_model, m_device)); - } - WINML_EXPECT_NO_THROW(m_model_binding = LearningModelBinding(m_session)); + return true; + } + + VideoFrame BindImageOutput( + ModelInputOutputType model_input_output_type, + OutputBindingStrategy output_binding_strategy, + const std::wstring& model_pixel_format + ) { + std::wstring output_data_binding_name = std::wstring(m_model.OutputFeatures().First().Current().Name()); + VideoFrame frame = nullptr; + if (OutputBindingStrategy::Bound == output_binding_strategy) { + if (ModelInputOutputType::Image == model_input_output_type) { + ImageFeatureDescriptor output_image_descriptor = nullptr; + WINML_EXPECT_NO_THROW(m_model.OutputFeatures().First().Current().as(output_image_descriptor)); + SoftwareBitmap bitmap( + ImageTestHelper::GetPixelFormat(model_pixel_format), + output_image_descriptor.Height(), + output_image_descriptor.Width() + ); + frame = VideoFrame::CreateWithSoftwareBitmap(bitmap); + + } else if (ModelInputOutputType::Tensor == model_input_output_type) { + TensorFeatureDescriptor output_tensor_descriptor = nullptr; + WINML_EXPECT_NO_THROW(m_model.OutputFeatures().First().Current().as(output_tensor_descriptor)); + auto output_tensor_shape = output_tensor_descriptor.Shape(); + SoftwareBitmap bitmap( + ImageTestHelper::GetPixelFormat(model_pixel_format), + static_cast(output_tensor_shape.GetAt(3)), + static_cast(output_tensor_shape.GetAt(2)) + ); + frame = VideoFrame::CreateWithSoftwareBitmap(bitmap); + } + auto output_tensor = ImageFeatureValue::CreateFromVideoFrame(frame); + WINML_EXPECT_NO_THROW(m_model_binding.Bind(output_data_binding_name, output_tensor)); } - bool BindInputValue( - const std::wstring& image_file_name, - const std::wstring& input_pixel_format, - const std::wstring& model_pixel_format, - InputImageSource input_image_source, - LearningModelDeviceKind device_kind - ) { - std::wstring full_image_path = FileHelpers::GetModulePath() + image_file_name; - StorageFile image_file = StorageFile::GetFileFromPathAsync(full_image_path).get(); - IRandomAccessStream stream = image_file.OpenAsync(FileAccessMode::Read).get(); - BitmapDecoder bitmap_decoder = BitmapDecoder::CreateAsync(stream).get(); - SoftwareBitmap software_bitmap = bitmap_decoder.GetSoftwareBitmapAsync().get(); - - // Convert the input image to PixelFormat specified - software_bitmap = SoftwareBitmap::Convert( - software_bitmap, - ImageTestHelper::GetPixelFormat(input_pixel_format)); - - auto input_feature = m_model.InputFeatures().First(); - if (InputImageSource::FromImageFeatureValue == input_image_source) { - VideoFrame frame = VideoFrame::CreateWithSoftwareBitmap(software_bitmap); - ImageFeatureValue image_input_tensor = ImageFeatureValue::CreateFromVideoFrame(frame); - WINML_EXPECT_NO_THROW(m_model_binding.Bind(input_feature.Current().Name(), image_input_tensor)); - } - else if (InputImageSource::FromVideoFrame == input_image_source) { - VideoFrame frame = VideoFrame::CreateWithSoftwareBitmap(software_bitmap); - WINML_EXPECT_NO_THROW(m_model_binding.Bind(input_feature.Current().Name(), frame)); - } - else if (InputImageSource::FromCPUResource == input_image_source) { - TensorFloat tensor_float = ImageTestHelper::LoadInputImageFromCPU(software_bitmap, model_pixel_format); - WINML_EXPECT_NO_THROW(m_model_binding.Bind(input_feature.Current().Name(), tensor_float)); - } - else if (InputImageSource::FromGPUResource == input_image_source) { - TensorFloat tensor_float = ImageTestHelper::LoadInputImageFromGPU(software_bitmap, model_pixel_format); - if (LearningModelDeviceKind::Cpu == device_kind) { - WINML_EXPECT_THROW_SPECIFIC(m_model_binding.Bind(input_feature.Current().Name(), tensor_float), - winrt::hresult_error, - [](const winrt::hresult_error& e) -> bool { - return e.code() == WINML_ERR_INVALID_BINDING; - }); - return false; - } - WINML_EXPECT_NO_THROW(m_model_binding.Bind(input_feature.Current().Name(), tensor_float)); - } - return true; + // Else for Unbound + return frame; + } + + IVector BindImageOutput( + ModelInputOutputType model_input_output_type, + OutputBindingStrategy output_binding_strategy, + VideoFrameSource output_video_frame_source, + const std::wstring& model_pixel_format, + const uint32_t& batch_size + ) { + std::wstring output_data_binding_name = std::wstring(m_model.OutputFeatures().First().Current().Name()); + uint32_t width = 0, height = 0; + if (ModelInputOutputType::Image == model_input_output_type) { + ImageFeatureDescriptor output_image_descriptor = nullptr; + WINML_EXPECT_NO_THROW(m_model.OutputFeatures().First().Current().as(output_image_descriptor)); + width = output_image_descriptor.Width(); + height = output_image_descriptor.Height(); + } else { + TensorFeatureDescriptor output_tensor_descriptor = nullptr; + WINML_EXPECT_NO_THROW(m_model.OutputFeatures().First().Current().as(output_tensor_descriptor)); + auto output_tensor_shape = output_tensor_descriptor.Shape(); + width = static_cast(output_tensor_shape.GetAt(3)); + height = static_cast(output_tensor_shape.GetAt(2)); } - - VideoFrame BindImageOutput( - ModelInputOutputType model_input_output_type, - OutputBindingStrategy output_binding_strategy, - const std::wstring& model_pixel_format) { - std::wstring output_data_binding_name = std::wstring(m_model.OutputFeatures().First().Current().Name()); - VideoFrame frame = nullptr; - if (OutputBindingStrategy::Bound == output_binding_strategy) { - if (ModelInputOutputType::Image == model_input_output_type) { - ImageFeatureDescriptor output_image_descriptor = nullptr; - WINML_EXPECT_NO_THROW(m_model.OutputFeatures().First().Current().as(output_image_descriptor)); - SoftwareBitmap bitmap( - ImageTestHelper::GetPixelFormat(model_pixel_format), - output_image_descriptor.Height(), - output_image_descriptor.Width()); - frame = VideoFrame::CreateWithSoftwareBitmap(bitmap); - - } - else if (ModelInputOutputType::Tensor == model_input_output_type) { - TensorFeatureDescriptor output_tensor_descriptor = nullptr; - WINML_EXPECT_NO_THROW(m_model.OutputFeatures().First().Current().as(output_tensor_descriptor)); - auto output_tensor_shape = output_tensor_descriptor.Shape(); - SoftwareBitmap bitmap( - ImageTestHelper::GetPixelFormat(model_pixel_format), - static_cast(output_tensor_shape.GetAt(3)), - static_cast(output_tensor_shape.GetAt(2))); - frame = VideoFrame::CreateWithSoftwareBitmap(bitmap); - } - auto output_tensor = ImageFeatureValue::CreateFromVideoFrame(frame); - WINML_EXPECT_NO_THROW(m_model_binding.Bind(output_data_binding_name, output_tensor)); + IVector output_video_frames; + if (OutputBindingStrategy::Bound == output_binding_strategy) { + std::vector output_frames = {}; + for (uint32_t i = 0; i < batch_size; ++i) { + VideoFrame video_frame = nullptr; + if (VideoFrameSource::FromSoftwareBitmap == output_video_frame_source) { + video_frame = VideoFrame::CreateWithSoftwareBitmap( + SoftwareBitmap(ImageTestHelper::GetPixelFormat(model_pixel_format), width, height) + ); + } else if (VideoFrameSource::FromDirect3DSurface == output_video_frame_source) { + video_frame = + VideoFrame::CreateAsDirect3D11SurfaceBacked(DirectXPixelFormat::B8G8R8A8UIntNormalized, width, height); + } else if (VideoFrameSource::FromUnsupportedD3DSurface == output_video_frame_source) { + video_frame = + VideoFrame::CreateAsDirect3D11SurfaceBacked(DirectXPixelFormat::B8G8R8X8UIntNormalized, width, height); } - - // Else for Unbound - return frame; + output_frames.emplace_back(video_frame); + } + output_video_frames = winrt::single_threaded_vector(std::move(output_frames)); + WINML_EXPECT_NO_THROW(m_model_binding.Bind(output_data_binding_name, output_video_frames)); } - IVector BindImageOutput( - ModelInputOutputType model_input_output_type, - OutputBindingStrategy output_binding_strategy, - VideoFrameSource output_video_frame_source, - const std::wstring& model_pixel_format, - const uint32_t& batch_size) { - std::wstring output_data_binding_name = std::wstring(m_model.OutputFeatures().First().Current().Name()); - uint32_t width = 0, height = 0; - if (ModelInputOutputType::Image == model_input_output_type) { - ImageFeatureDescriptor output_image_descriptor = nullptr; - WINML_EXPECT_NO_THROW(m_model.OutputFeatures().First().Current().as(output_image_descriptor)); - width = output_image_descriptor.Width(); - height = output_image_descriptor.Height(); - } else { - TensorFeatureDescriptor output_tensor_descriptor = nullptr; - WINML_EXPECT_NO_THROW(m_model.OutputFeatures().First().Current().as(output_tensor_descriptor)); - auto output_tensor_shape = output_tensor_descriptor.Shape(); - width = static_cast(output_tensor_shape.GetAt(3)); - height = static_cast(output_tensor_shape.GetAt(2)); - } - IVector output_video_frames; - if (OutputBindingStrategy::Bound == output_binding_strategy) { - std::vector output_frames = {}; - for (uint32_t i = 0; i < batch_size; ++i) { - VideoFrame video_frame = nullptr; - if (VideoFrameSource::FromSoftwareBitmap == output_video_frame_source) { - video_frame = VideoFrame::CreateWithSoftwareBitmap(SoftwareBitmap(ImageTestHelper::GetPixelFormat(model_pixel_format), width, height)); - } - else if (VideoFrameSource::FromDirect3DSurface == output_video_frame_source) { - video_frame = VideoFrame::CreateAsDirect3D11SurfaceBacked(DirectXPixelFormat::B8G8R8A8UIntNormalized, width, height); - } - else if (VideoFrameSource::FromUnsupportedD3DSurface == output_video_frame_source) { - video_frame = VideoFrame::CreateAsDirect3D11SurfaceBacked(DirectXPixelFormat::B8G8R8X8UIntNormalized, width, height); - } - output_frames.emplace_back(video_frame); - } - output_video_frames = winrt::single_threaded_vector(std::move(output_frames)); - WINML_EXPECT_NO_THROW(m_model_binding.Bind(output_data_binding_name, output_video_frames)); - - } - - // Else for Unbound - return output_video_frames; + // Else for Unbound + return output_video_frames; + } + + void VerifyResults( + VideoFrame output_tensor, const std::wstring& bm_image_path, const std::wstring& model_pixel_format + ) { + SoftwareBitmap bm_software_bitmap = FileHelpers::GetSoftwareBitmapFromFile(bm_image_path); + bm_software_bitmap = + SoftwareBitmap::Convert(bm_software_bitmap, ImageTestHelper::GetPixelFormat(model_pixel_format)); + VideoFrame bm_video_frame = VideoFrame::CreateWithSoftwareBitmap(bm_software_bitmap); + WINML_EXPECT_TRUE(ImageTestHelper::VerifyHelper(output_tensor, bm_video_frame)); + } + + void EvaluateTest(EvaluationStrategy strategy) { + if (EvaluationStrategy::Async == strategy) { + WINML_EXPECT_NO_THROW(m_result = m_session.EvaluateAsync(m_model_binding, L"").get()); + } else if (EvaluationStrategy::Sync == strategy) { + WINML_EXPECT_NO_THROW(m_result = m_session.Evaluate(m_model_binding, L"")); } - - void VerifyResults( - VideoFrame output_tensor, - const std::wstring& bm_image_path, - const std::wstring& model_pixel_format) { - SoftwareBitmap bm_software_bitmap = FileHelpers::GetSoftwareBitmapFromFile(bm_image_path); - bm_software_bitmap = SoftwareBitmap::Convert( - bm_software_bitmap, - ImageTestHelper::GetPixelFormat(model_pixel_format)); - VideoFrame bm_video_frame = VideoFrame::CreateWithSoftwareBitmap(bm_software_bitmap); - WINML_EXPECT_TRUE(ImageTestHelper::VerifyHelper(output_tensor, bm_video_frame)); + } + + bool ShouldSkip( + const std::wstring& model_file_name, const std::wstring& image_file_name, const InputImageSource input_image_source + ) { + // Case that the tensor's shape doesn't match model's shape should be skiped + if ((L"1080.jpg" == image_file_name || L"kitten_224.png" == image_file_name) && (InputImageSource::FromGPUResource == input_image_source || InputImageSource::FromCPUResource == input_image_source)) { + return true; } - void EvaluateTest(EvaluationStrategy strategy) { - if (EvaluationStrategy::Async == strategy) { - WINML_EXPECT_NO_THROW(m_result = m_session.EvaluateAsync(m_model_binding, L"").get()); - } - else if (EvaluationStrategy::Sync == strategy) { - WINML_EXPECT_NO_THROW(m_result = m_session.Evaluate(m_model_binding, L"")); - } + // Case that the images's shape doesn't match model's shape which expects free dimension should be skiped. + // Because the fns-candy is not real model that can handle free dimensional input + if ((L"1080.jpg" == image_file_name || L"kitten_224.png" == image_file_name) && L"fns-candy_Bgr8_freeDimInput.onnx" == model_file_name) { + return true; } - bool ShouldSkip( - const std::wstring& model_file_name, - const std::wstring& image_file_name, - const InputImageSource input_image_source - ) { - // Case that the tensor's shape doesn't match model's shape should be skiped - if ((L"1080.jpg" == image_file_name || L"kitten_224.png" == image_file_name) && - (InputImageSource::FromGPUResource == input_image_source || InputImageSource::FromCPUResource == input_image_source)) { - return true; - } + return false; + } - // Case that the images's shape doesn't match model's shape which expects free dimension should be skiped. - // Because the fns-candy is not real model that can handle free dimensional input - if ((L"1080.jpg" == image_file_name || L"kitten_224.png" == image_file_name) && - L"fns-candy_Bgr8_freeDimInput.onnx" == model_file_name) { - return true; - } + void ValidateOutputImageMetaData( + const std::wstring& path, BitmapAlphaMode expected_mode, BitmapPixelFormat expected_format, bool supported + ) { + WINML_EXPECT_NO_THROW(LoadModel(path)); + //input does not have image metadata and output does - return false; - } + WINML_EXPECT_TRUE(m_model.OutputFeatures().First().HasCurrent()); - void ValidateOutputImageMetaData(const std::wstring& path, BitmapAlphaMode expected_mode, BitmapPixelFormat expected_format, bool supported) { - WINML_EXPECT_NO_THROW(LoadModel(path)); - //input does not have image metadata and output does + std::wstring name(m_model.OutputFeatures().First().Current().Name()); + std::wstring expected_tensor_name = L"add_3"; + WINML_EXPECT_EQUAL(name, expected_tensor_name); - WINML_EXPECT_TRUE(m_model.OutputFeatures().First().HasCurrent()); + ImageFeatureDescriptor image_descriptor = nullptr; + if (supported) { + WINML_EXPECT_NO_THROW(m_model.OutputFeatures().First().Current().as(image_descriptor)); + WINML_EXPECT_TRUE(image_descriptor != nullptr); - std::wstring name(m_model.OutputFeatures().First().Current().Name()); - std::wstring expected_tensor_name = L"add_3"; - WINML_EXPECT_EQUAL(name, expected_tensor_name); + auto tensor_name = image_descriptor.Name(); + WINML_EXPECT_EQUAL(tensor_name, expected_tensor_name); - ImageFeatureDescriptor image_descriptor = nullptr; - if (supported) { - WINML_EXPECT_NO_THROW(m_model.OutputFeatures().First().Current().as(image_descriptor)); - WINML_EXPECT_TRUE(image_descriptor != nullptr); + auto model_data_kind = image_descriptor.Kind(); + WINML_EXPECT_EQUAL(model_data_kind, LearningModelFeatureKind::Image); - auto tensor_name = image_descriptor.Name(); - WINML_EXPECT_EQUAL(tensor_name, expected_tensor_name); + WINML_EXPECT_TRUE(image_descriptor.IsRequired()); - auto model_data_kind = image_descriptor.Kind(); - WINML_EXPECT_EQUAL(model_data_kind, LearningModelFeatureKind::Image); + WINML_EXPECT_EQUAL(image_descriptor.Width(), 1920u); + WINML_EXPECT_EQUAL(image_descriptor.Height(), 1080u); + WINML_EXPECT_EQUAL(image_descriptor.BitmapAlphaMode(), expected_mode); + WINML_EXPECT_EQUAL(image_descriptor.BitmapPixelFormat(), expected_format); + } else { + //not an image descriptor. a regular tensor + WINML_EXPECT_THROW_SPECIFIC( + m_model.OutputFeatures().First().Current().as(image_descriptor), + winrt::hresult_no_interface, + [](const winrt::hresult_no_interface& e) -> bool { return e.code() == E_NOINTERFACE; } + ); + TensorFeatureDescriptor tensor_descriptor = nullptr; + WINML_EXPECT_NO_THROW(m_model.OutputFeatures().First().Current().as(tensor_descriptor)); + + // Make sure we fail binding ImageFeatureValue + LearningModelSession session(m_model); + LearningModelBinding binding(session); + auto ifv = FileHelpers::LoadImageFeatureValue(L"1080.jpg"); + WINML_EXPECT_THROW_SPECIFIC( + binding.Bind(L"add_3", ifv), + winrt::hresult_error, + [](const winrt::hresult_error& e) -> bool { return e.code() == WINML_ERR_INVALID_BINDING; } + ); + } + } - WINML_EXPECT_TRUE(image_descriptor.IsRequired()); + void RunConsecutiveImageBindingOnGpu(ImageFeatureValue& image1, ImageFeatureValue& image2) { + static const wchar_t* model_file_name = L"Add_ImageNet1920.onnx"; + std::wstring module_path = FileHelpers::GetModulePath(); - WINML_EXPECT_EQUAL(image_descriptor.Width(), 1920u); - WINML_EXPECT_EQUAL(image_descriptor.Height(), 1080u); - WINML_EXPECT_EQUAL(image_descriptor.BitmapAlphaMode(), expected_mode); - WINML_EXPECT_EQUAL(image_descriptor.BitmapPixelFormat(), expected_format); - } - else { - //not an image descriptor. a regular tensor - WINML_EXPECT_THROW_SPECIFIC(m_model.OutputFeatures().First().Current().as(image_descriptor), - winrt::hresult_no_interface - , [](const winrt::hresult_no_interface& e) -> bool { - return e.code() == E_NOINTERFACE; - }); - TensorFeatureDescriptor tensor_descriptor = nullptr; - WINML_EXPECT_NO_THROW(m_model.OutputFeatures().First().Current().as(tensor_descriptor)); - - // Make sure we fail binding ImageFeatureValue - LearningModelSession session(m_model); - LearningModelBinding binding(session); - auto ifv = FileHelpers::LoadImageFeatureValue(L"1080.jpg"); - WINML_EXPECT_THROW_SPECIFIC(binding.Bind(L"add_3", ifv), - winrt::hresult_error, - [](const winrt::hresult_error& e) -> bool { - return e.code() == WINML_ERR_INVALID_BINDING; - } - ); - } - } + // WinML model creation + LearningModel model(nullptr); + std::wstring full_model_path = module_path + model_file_name; + WINML_EXPECT_NO_THROW(model = LearningModel::LoadFromFilePath(full_model_path)); + LearningModelDeviceKind device_kind = LearningModelDeviceKind::DirectX; + LearningModelSession model_session(model, LearningModelDevice(device_kind)); + LearningModelBinding model_binding(model_session); - void RunConsecutiveImageBindingOnGpu(ImageFeatureValue & image1, ImageFeatureValue & image2) { - static const wchar_t* model_file_name = L"Add_ImageNet1920.onnx"; - std::wstring module_path = FileHelpers::GetModulePath(); - - // WinML model creation - LearningModel model(nullptr); - std::wstring full_model_path = module_path + model_file_name; - WINML_EXPECT_NO_THROW(model = LearningModel::LoadFromFilePath(full_model_path)); - LearningModelDeviceKind device_kind = LearningModelDeviceKind::DirectX; - LearningModelSession model_session(model, LearningModelDevice(device_kind)); - LearningModelBinding model_binding(model_session); - - //Input Binding - auto feature = model.InputFeatures().First(); - WINML_EXPECT_NO_THROW(model_binding.Bind(feature.Current().Name(), image1)); - feature.MoveNext(); - WINML_EXPECT_NO_THROW(model_binding.Bind(feature.Current().Name(), image2)); - } + //Input Binding + auto feature = model.InputFeatures().First(); + WINML_EXPECT_NO_THROW(model_binding.Bind(feature.Current().Name(), image1)); + feature.MoveNext(); + WINML_EXPECT_NO_THROW(model_binding.Bind(feature.Current().Name(), image2)); + } - static ImageFeatureValue CreateImageFeatureValue(const std::wstring& full_image_path) { - StorageFile image_file = StorageFile::GetFileFromPathAsync(full_image_path).get(); - IRandomAccessStream stream = image_file.OpenAsync(FileAccessMode::Read).get(); - SoftwareBitmap software_bitmap = (BitmapDecoder::CreateAsync(stream).get()).GetSoftwareBitmapAsync().get(); - VideoFrame frame = VideoFrame::CreateWithSoftwareBitmap(software_bitmap); - ImageFeatureValue image_input_tensor = ImageFeatureValue::CreateFromVideoFrame(frame); - return image_input_tensor; - } + static ImageFeatureValue CreateImageFeatureValue(const std::wstring& full_image_path) { + StorageFile image_file = StorageFile::GetFileFromPathAsync(full_image_path).get(); + IRandomAccessStream stream = image_file.OpenAsync(FileAccessMode::Read).get(); + SoftwareBitmap software_bitmap = (BitmapDecoder::CreateAsync(stream).get()).GetSoftwareBitmapAsync().get(); + VideoFrame frame = VideoFrame::CreateWithSoftwareBitmap(software_bitmap); + ImageFeatureValue image_input_tensor = ImageFeatureValue::CreateFromVideoFrame(frame); + return image_input_tensor; + } }; // MNIST model expects 28x28 data with class MnistImageTest : public ImageTests, public testing::WithParamInterface> {}; TEST_P(MnistImageTest, Evaluates) { - GPUTEST; - - PrepareModelSessionBinding(L"mnist.onnx", LearningModelDeviceKind::Cpu, std::nullopt); - - std::wstring filename; - unsigned int label; - std::tie(filename, label) = GetParam(); - auto image_feature_value = FileHelpers::LoadImageFeatureValue(std::wstring(filename)); - m_model_binding.Bind(L"Input3", image_feature_value); - - auto result = m_session.EvaluateAsync(m_model_binding, L"0").get(); - auto vector = result.Outputs().Lookup(L"Plus214_Output_0").as().GetAsVectorView(); - - unsigned int max_label = 0; - float max_val = 0; - for (unsigned int i = 0; i < vector.Size(); ++i) { - float val = vector.GetAt(i); - if (val > max_val) { - max_val = val; - max_label = i; - } + GPUTEST; + + PrepareModelSessionBinding(L"mnist.onnx", LearningModelDeviceKind::Cpu, std::nullopt); + + std::wstring filename; + unsigned int label; + std::tie(filename, label) = GetParam(); + auto image_feature_value = FileHelpers::LoadImageFeatureValue(std::wstring(filename)); + m_model_binding.Bind(L"Input3", image_feature_value); + + auto result = m_session.EvaluateAsync(m_model_binding, L"0").get(); + auto vector = result.Outputs().Lookup(L"Plus214_Output_0").as().GetAsVectorView(); + + unsigned int max_label = 0; + float max_val = 0; + for (unsigned int i = 0; i < vector.Size(); ++i) { + float val = vector.GetAt(i); + if (val > max_val) { + max_val = val; + max_label = i; } - std::cerr << "Expected Label " << label; - std::cerr << "Evaluated Label " << max_label; - WINML_EXPECT_TRUE(max_label == label); + } + std::cerr << "Expected Label " << label; + std::cerr << "Evaluated Label " << max_label; + WINML_EXPECT_TRUE(max_label == label); } -INSTANTIATE_TEST_SUITE_P(MnistInputOutput, MnistImageTest, - testing::Values( - std::make_pair(L"vertical-crop.png", 5), - std::make_pair(L"horizontal-crop.png", 2), - std::make_pair(L"big.png", 8), - std::make_pair(L"RGB_5.png", 5) - )); +INSTANTIATE_TEST_SUITE_P( + MnistInputOutput, + MnistImageTest, + testing::Values( + std::make_pair(L"vertical-crop.png", 5), + std::make_pair(L"horizontal-crop.png", 2), + std::make_pair(L"big.png", 8), + std::make_pair(L"RGB_5.png", 5) + ) +); #if defined(NDEBUG) || defined(RUN_MODELTEST_IN_DEBUG_MODE) -typedef std::tuple, std::wstring, std::wstring, InputImageSource, EvaluationStrategy, OutputBindingStrategy, LearningModelDeviceKind> ImageTestParamTuple; +typedef std::tuple< + std::tuple, + std::wstring, + std::wstring, + InputImageSource, + EvaluationStrategy, + OutputBindingStrategy, + LearningModelDeviceKind> + ImageTestParamTuple; struct ImageTestParam { - std::wstring model_file_name, model_pixel_format, image_file_name, input_pixel_format; - ModelInputOutputType model_input_output_type; - InputImageSource input_image_source; - EvaluationStrategy evaluation_strategy; - OutputBindingStrategy output_binding_strategy; - LearningModelDeviceKind device_kind; - - ImageTestParam(ImageTestParamTuple param) { - std::tuple model_info; - tie(model_info, image_file_name, input_pixel_format, input_image_source, evaluation_strategy, output_binding_strategy, device_kind) = param; - tie(model_file_name, model_input_output_type, model_pixel_format) = model_info; - } + std::wstring model_file_name, model_pixel_format, image_file_name, input_pixel_format; + ModelInputOutputType model_input_output_type; + InputImageSource input_image_source; + EvaluationStrategy evaluation_strategy; + OutputBindingStrategy output_binding_strategy; + LearningModelDeviceKind device_kind; + + ImageTestParam(ImageTestParamTuple param) { + std::tuple model_info; + tie( + model_info, + image_file_name, + input_pixel_format, + input_image_source, + evaluation_strategy, + output_binding_strategy, + device_kind + ) = param; + tie(model_file_name, model_input_output_type, model_pixel_format) = model_info; + } }; class ImageTest : public ImageTests, public testing::WithParamInterface {}; TEST_P(ImageTest, ImageTest) { - const auto param = ImageTestParam(GetParam()); - if (ShouldSkip(param.model_file_name, param.image_file_name, param.input_image_source)) { - GTEST_SKIP() << "This test is disabled"; - } - - if (LearningModelDeviceKind::Cpu != param.device_kind || InputImageSource::FromGPUResource == param.input_image_source) { - GPUTEST; - } - - PrepareModelSessionBinding(param.model_file_name, param.device_kind, {}); - - bool toContinue = BindInputValue( - param.image_file_name, - param.input_pixel_format, - param.model_pixel_format, - param.input_image_source, - param.device_kind); - - if (!toContinue) return; - - VideoFrame output_video_frame = BindImageOutput( - param.model_input_output_type, - param.output_binding_strategy, - std::wstring(param.model_pixel_format)); - - EvaluateTest(param.evaluation_strategy); + const auto param = ImageTestParam(GetParam()); + if (ShouldSkip(param.model_file_name, param.image_file_name, param.input_image_source)) { + GTEST_SKIP() << "This test is disabled"; + } - // benchmark used to compare with the output from model - std::wstring benchmark_file_name = std::wstring( - param.model_pixel_format + L'_' + param.input_pixel_format + L'_' + param.image_file_name); - - // Verify the output by comparing with the benchmark image - std::wstring bm_image_path = FileHelpers::GetModulePath() + L"groundTruth\\" + benchmark_file_name; - if (OutputBindingStrategy::Unbound == param.output_binding_strategy) { - std::wstring output_data_binding_name = std::wstring(m_model.OutputFeatures().First().Current().Name()); - auto image_FV = m_result.Outputs().Lookup(output_data_binding_name).try_as(); - if (image_FV == nullptr) { - return; - } - output_video_frame = image_FV.VideoFrame(); + if (LearningModelDeviceKind::Cpu != param.device_kind || InputImageSource::FromGPUResource == param.input_image_source) { + GPUTEST; + } + + PrepareModelSessionBinding(param.model_file_name, param.device_kind, {}); + + bool toContinue = BindInputValue( + param.image_file_name, + param.input_pixel_format, + param.model_pixel_format, + param.input_image_source, + param.device_kind + ); + + if (!toContinue) + return; + + VideoFrame output_video_frame = BindImageOutput( + param.model_input_output_type, param.output_binding_strategy, std::wstring(param.model_pixel_format) + ); + + EvaluateTest(param.evaluation_strategy); + + // benchmark used to compare with the output from model + std::wstring benchmark_file_name = + std::wstring(param.model_pixel_format + L'_' + param.input_pixel_format + L'_' + param.image_file_name); + + // Verify the output by comparing with the benchmark image + std::wstring bm_image_path = FileHelpers::GetModulePath() + L"groundTruth\\" + benchmark_file_name; + if (OutputBindingStrategy::Unbound == param.output_binding_strategy) { + std::wstring output_data_binding_name = std::wstring(m_model.OutputFeatures().First().Current().Name()); + auto image_FV = m_result.Outputs().Lookup(output_data_binding_name).try_as(); + if (image_FV == nullptr) { + return; } - VerifyResults(output_video_frame, bm_image_path, param.model_pixel_format); + output_video_frame = image_FV.VideoFrame(); + } + VerifyResults(output_video_frame, bm_image_path, param.model_pixel_format); } -INSTANTIATE_TEST_SUITE_P(ImageTest, ImageTest, - testing::Combine( - testing::Values( - std::make_tuple(L"fns-candy_Bgr8.onnx", Image, L"Bgr8"), - std::make_tuple(L"fns-candy_Rgb8.onnx", Image, L"Rgb8"), - std::make_tuple(L"fns-candy_tensor.onnx", Tensor, L"Bgr8"), - std::make_tuple(L"fns-candy_Bgr8_freeDimInput.onnx", Image, L"Bgr8")), - testing::Values(L"1080.jpg", L"kitten_224.png", L"fish_720.png", L"fish_720_Gray.png"), - testing::Values(L"Bgra8", L"Rgba8", L"Gray8"), - testing::Values(FromVideoFrame, FromImageFeatureValue, FromCPUResource, FromGPUResource), - testing::Values(Async, Sync), - testing::Values(Bound, Unbound), - testing::Values(LearningModelDeviceKind::DirectX, LearningModelDeviceKind::Cpu) - )); - - -typedef std::tuple, int, bool>, OutputBindingStrategy, EvaluationStrategy, VideoFrameSource, VideoFrameSource, LearningModelDeviceKind> BatchTestParamTuple; +INSTANTIATE_TEST_SUITE_P( + ImageTest, + ImageTest, + testing::Combine( + testing::Values( + std::make_tuple(L"fns-candy_Bgr8.onnx", Image, L"Bgr8"), + std::make_tuple(L"fns-candy_Rgb8.onnx", Image, L"Rgb8"), + std::make_tuple(L"fns-candy_tensor.onnx", Tensor, L"Bgr8"), + std::make_tuple(L"fns-candy_Bgr8_freeDimInput.onnx", Image, L"Bgr8") + ), + testing::Values(L"1080.jpg", L"kitten_224.png", L"fish_720.png", L"fish_720_Gray.png"), + testing::Values(L"Bgra8", L"Rgba8", L"Gray8"), + testing::Values(FromVideoFrame, FromImageFeatureValue, FromCPUResource, FromGPUResource), + testing::Values(Async, Sync), + testing::Values(Bound, Unbound), + testing::Values(LearningModelDeviceKind::DirectX, LearningModelDeviceKind::Cpu) + ) +); + +typedef std::tuple< + std::tuple, int, bool>, + OutputBindingStrategy, + EvaluationStrategy, + VideoFrameSource, + VideoFrameSource, + LearningModelDeviceKind> + BatchTestParamTuple; struct BatchTestParam { - std::wstring model_file_name, model_pixel_format, image_file_name, input_pixel_format; - ModelInputOutputType model_input_output_type; - std::vector input_images; - int batch_size; - bool use_session_options; - OutputBindingStrategy output_binding_strategy; - EvaluationStrategy evaluation_strategy; - VideoFrameSource video_frame_source, output_video_frame_source; - LearningModelDeviceKind device_kind; - - BatchTestParam(BatchTestParamTuple param) { - std::tuple, int, bool> model_info; - tie(model_info, output_binding_strategy, evaluation_strategy, video_frame_source, output_video_frame_source, device_kind) = param; - tie(model_file_name, model_input_output_type, input_images, batch_size, use_session_options) = model_info; - } + std::wstring model_file_name, model_pixel_format, image_file_name, input_pixel_format; + ModelInputOutputType model_input_output_type; + std::vector input_images; + int batch_size; + bool use_session_options; + OutputBindingStrategy output_binding_strategy; + EvaluationStrategy evaluation_strategy; + VideoFrameSource video_frame_source, output_video_frame_source; + LearningModelDeviceKind device_kind; + + BatchTestParam(BatchTestParamTuple param) { + std::tuple, int, bool> model_info; + tie( + model_info, + output_binding_strategy, + evaluation_strategy, + video_frame_source, + output_video_frame_source, + device_kind + ) = param; + tie(model_file_name, model_input_output_type, input_images, batch_size, use_session_options) = model_info; + } }; class BatchTest : public ImageTests, public testing::WithParamInterface {}; TEST_P(BatchTest, BatchSupport) { - const auto param = BatchTestParam(GetParam()); - std::optional optimized_batch_size; - if (param.use_session_options) { - optimized_batch_size = param.use_session_options; - } - if (VideoFrameSource::FromDirect3DSurface == param.video_frame_source && LearningModelDeviceKind::Cpu == param.device_kind) { - return; - } - if (LearningModelDeviceKind::Cpu != param.device_kind || + const auto param = BatchTestParam(GetParam()); + std::optional optimized_batch_size; + if (param.use_session_options) { + optimized_batch_size = param.use_session_options; + } + if (VideoFrameSource::FromDirect3DSurface == param.video_frame_source && LearningModelDeviceKind::Cpu == param.device_kind) { + return; + } + if (LearningModelDeviceKind::Cpu != param.device_kind || VideoFrameSource::FromDirect3DSurface == param.video_frame_source || VideoFrameSource::FromDirect3DSurface == param.output_video_frame_source || VideoFrameSource::FromUnsupportedD3DSurface == param.output_video_frame_source) { - GPUTEST; - } - - // create model, device and session - PrepareModelSessionBinding(param.model_file_name, param.device_kind, optimized_batch_size); - - // create the input video_frames - std::vector input_frames = {}; - if (param.input_images.empty()) { - for (int i = 0; i < param.batch_size; ++i) { - if (VideoFrameSource::FromDirect3DSurface == param.video_frame_source) { - VideoFrame video_frame = VideoFrame::CreateAsDirect3D11SurfaceBacked(DirectXPixelFormat::B8G8R8X8UIntNormalized, 720, 720); - input_frames.emplace_back(video_frame); - } - else { - VideoFrame video_frame = VideoFrame::CreateWithSoftwareBitmap(SoftwareBitmap(BitmapPixelFormat::Bgra8, 720, 720)); - input_frames.emplace_back(video_frame); - } - } + GPUTEST; + } + + // create model, device and session + PrepareModelSessionBinding(param.model_file_name, param.device_kind, optimized_batch_size); + + // create the input video_frames + std::vector input_frames = {}; + if (param.input_images.empty()) { + for (int i = 0; i < param.batch_size; ++i) { + if (VideoFrameSource::FromDirect3DSurface == param.video_frame_source) { + VideoFrame video_frame = + VideoFrame::CreateAsDirect3D11SurfaceBacked(DirectXPixelFormat::B8G8R8X8UIntNormalized, 720, 720); + input_frames.emplace_back(video_frame); + } else { + VideoFrame video_frame = + VideoFrame::CreateWithSoftwareBitmap(SoftwareBitmap(BitmapPixelFormat::Bgra8, 720, 720)); + input_frames.emplace_back(video_frame); + } } - else { - for (int i = 0; i < param.batch_size; ++i) { - std::wstring full_image_path = FileHelpers::GetModulePath() + param.input_images[i]; - StorageFile image_file = StorageFile::GetFileFromPathAsync(full_image_path).get(); - IRandomAccessStream stream = image_file.OpenAsync(FileAccessMode::Read).get(); - SoftwareBitmap software_bitmap = (BitmapDecoder::CreateAsync(stream).get()).GetSoftwareBitmapAsync().get(); - VideoFrame frame = VideoFrame::CreateWithSoftwareBitmap(software_bitmap); - - if (VideoFrameSource::FromDirect3DSurface == param.video_frame_source) { - uint32_t width = software_bitmap.PixelWidth(); - uint32_t height = software_bitmap.PixelHeight(); - auto D3D_video_frame = VideoFrame::CreateAsDirect3D11SurfaceBacked(DirectXPixelFormat::B8G8R8X8UIntNormalized, width, height); - frame.CopyToAsync(D3D_video_frame); - input_frames.emplace_back(D3D_video_frame); - } - else { - input_frames.emplace_back(frame); - } - } + } else { + for (int i = 0; i < param.batch_size; ++i) { + std::wstring full_image_path = FileHelpers::GetModulePath() + param.input_images[i]; + StorageFile image_file = StorageFile::GetFileFromPathAsync(full_image_path).get(); + IRandomAccessStream stream = image_file.OpenAsync(FileAccessMode::Read).get(); + SoftwareBitmap software_bitmap = (BitmapDecoder::CreateAsync(stream).get()).GetSoftwareBitmapAsync().get(); + VideoFrame frame = VideoFrame::CreateWithSoftwareBitmap(software_bitmap); + + if (VideoFrameSource::FromDirect3DSurface == param.video_frame_source) { + uint32_t width = software_bitmap.PixelWidth(); + uint32_t height = software_bitmap.PixelHeight(); + auto D3D_video_frame = + VideoFrame::CreateAsDirect3D11SurfaceBacked(DirectXPixelFormat::B8G8R8X8UIntNormalized, width, height); + frame.CopyToAsync(D3D_video_frame); + input_frames.emplace_back(D3D_video_frame); + } else { + input_frames.emplace_back(frame); + } } - auto video_frames = winrt::single_threaded_vector(std::move(input_frames)); - - auto input_feature_descriptor = m_model.InputFeatures().First(); - WINML_EXPECT_NO_THROW(m_model_binding.Bind(input_feature_descriptor.Current().Name(), video_frames)); - - auto output_video_frames = BindImageOutput( - param.model_input_output_type, - param.output_binding_strategy, - param.output_video_frame_source, - L"Bgra8", - param.batch_size); - - EvaluateTest(param.evaluation_strategy); - - // benchmark used to compare with the output from model - if (OutputBindingStrategy::Unbound == param.output_binding_strategy) { - std::wstring output_data_binding_name = std::wstring(m_model.OutputFeatures().First().Current().Name()); - output_video_frames = m_result.Outputs().Lookup(output_data_binding_name).try_as>(); - if (output_video_frames == nullptr) { - return; - } + } + auto video_frames = winrt::single_threaded_vector(std::move(input_frames)); + + auto input_feature_descriptor = m_model.InputFeatures().First(); + WINML_EXPECT_NO_THROW(m_model_binding.Bind(input_feature_descriptor.Current().Name(), video_frames)); + + auto output_video_frames = BindImageOutput( + param.model_input_output_type, + param.output_binding_strategy, + param.output_video_frame_source, + L"Bgra8", + param.batch_size + ); + + EvaluateTest(param.evaluation_strategy); + + // benchmark used to compare with the output from model + if (OutputBindingStrategy::Unbound == param.output_binding_strategy) { + std::wstring output_data_binding_name = std::wstring(m_model.OutputFeatures().First().Current().Name()); + output_video_frames = m_result.Outputs().Lookup(output_data_binding_name).try_as>(); + if (output_video_frames == nullptr) { + return; } - if (!param.input_images.empty()) { - for (int i = 0; i < param.batch_size; ++i) { - std::wstring bm_image_path = FileHelpers::GetModulePath() + L"batchGroundTruth\\" + param.input_images[i]; - if (VideoFrameSource::FromSoftwareBitmap != param.output_video_frame_source && OutputBindingStrategy::Unbound != param.output_binding_strategy) { - VideoFrame D3D_video_frame = output_video_frames.GetAt(i); - VideoFrame SB_video_frame(BitmapPixelFormat::Bgra8, 720, 720); - D3D_video_frame.as().CopyToAsync(SB_video_frame).get(); - VerifyResults(SB_video_frame, bm_image_path, L"Bgra8"); - } - else { - VerifyResults(output_video_frames.GetAt(i), bm_image_path, L"Bgra8"); - } - } + } + if (!param.input_images.empty()) { + for (int i = 0; i < param.batch_size; ++i) { + std::wstring bm_image_path = FileHelpers::GetModulePath() + L"batchGroundTruth\\" + param.input_images[i]; + if (VideoFrameSource::FromSoftwareBitmap != param.output_video_frame_source && + OutputBindingStrategy::Unbound != param.output_binding_strategy) { + VideoFrame D3D_video_frame = output_video_frames.GetAt(i); + VideoFrame SB_video_frame(BitmapPixelFormat::Bgra8, 720, 720); + D3D_video_frame.as().CopyToAsync(SB_video_frame).get(); + VerifyResults(SB_video_frame, bm_image_path, L"Bgra8"); + } else { + VerifyResults(output_video_frames.GetAt(i), bm_image_path, L"Bgra8"); + } } + } } // TODO: Reenable failing tests (Bug 299) -INSTANTIATE_TEST_SUITE_P(BatchTest, BatchTest, - testing::Combine( - testing::Values( - std::make_tuple(L"fns-candy_Bgr8_Batch2.onnx", Image, std::vector({L"fish_720.png", L"fish_720.png"}), 2, false), - std::make_tuple(L"fns-candy_Bgr8_Batch2.onnx", Image, std::vector({L"1080.jpg", L"fish_720.png"}), 2, false), - std::make_tuple(L"fns-candy_Bgr8_Batch2.onnx", Image, std::vector({L"fish_720_Gray.png", L"fish_720.png"}), 2, false) - // std::make_tuple(L"fns-candy_Bgr8_Batch3.onnx", Image, std::vector({L"1080.jpg", L"fish_720_Gray.png", L"fish_720.png"}), 3, false), - // std::make_tuple(L"fns-candy_Bgr8_Batch3.onnx", Image, std::vector({L"1080.jpg", L"kitten_224.png", L"fish_720.png"}), 3, false), - // std::make_tuple(L"fns-candy_Bgr8_tensor_Batch3.onnx", Tensor, std::vector({L"1080.jpg", L"fish_720_Gray.png", L"fish_720.png"}), 3, false), - // std::make_tuple(L"fns-candy_Bgr8_freeDimInput_Batch10.onnx", Image, std::vector({}), 10, false), - // std::make_tuple(L"fns-candy_Bgr8.onnx", Image, std::vector({L"1080.jpg", L"fish_720_Gray.png", L"fish_720.png"}), 3, false), - // std::make_tuple(L"fns-candy_Bgr8.onnx", Image, std::vector({L"1080.jpg", L"fish_720_Gray.png", L"fish_720.png"}), 3, true) - ), - testing::Values(Bound, Unbound), - testing::Values(Async, Sync), - testing::Values(FromSoftwareBitmap, FromDirect3DSurface), - testing::Values(FromSoftwareBitmap, FromDirect3DSurface, FromUnsupportedD3DSurface), - testing::Values(LearningModelDeviceKind::DirectX, LearningModelDeviceKind::Cpu) - )); +INSTANTIATE_TEST_SUITE_P( + BatchTest, + BatchTest, + testing::Combine( + testing::Values( + std::make_tuple( + L"fns-candy_Bgr8_Batch2.onnx", Image, std::vector({L"fish_720.png", L"fish_720.png"}), 2, false + ), + std::make_tuple( + L"fns-candy_Bgr8_Batch2.onnx", Image, std::vector({L"1080.jpg", L"fish_720.png"}), 2, false + ), + std::make_tuple( + L"fns-candy_Bgr8_Batch2.onnx", + Image, + std::vector({L"fish_720_Gray.png", L"fish_720.png"}), + 2, + false + ) + // std::make_tuple(L"fns-candy_Bgr8_Batch3.onnx", Image, std::vector({L"1080.jpg", L"fish_720_Gray.png", L"fish_720.png"}), 3, false), + // std::make_tuple(L"fns-candy_Bgr8_Batch3.onnx", Image, std::vector({L"1080.jpg", L"kitten_224.png", L"fish_720.png"}), 3, false), + // std::make_tuple(L"fns-candy_Bgr8_tensor_Batch3.onnx", Tensor, std::vector({L"1080.jpg", L"fish_720_Gray.png", L"fish_720.png"}), 3, false), + // std::make_tuple(L"fns-candy_Bgr8_freeDimInput_Batch10.onnx", Image, std::vector({}), 10, false), + // std::make_tuple(L"fns-candy_Bgr8.onnx", Image, std::vector({L"1080.jpg", L"fish_720_Gray.png", L"fish_720.png"}), 3, false), + // std::make_tuple(L"fns-candy_Bgr8.onnx", Image, std::vector({L"1080.jpg", L"fish_720_Gray.png", L"fish_720.png"}), 3, true) + ), + testing::Values(Bound, Unbound), + testing::Values(Async, Sync), + testing::Values(FromSoftwareBitmap, FromDirect3DSurface), + testing::Values(FromSoftwareBitmap, FromDirect3DSurface, FromUnsupportedD3DSurface), + testing::Values(LearningModelDeviceKind::DirectX, LearningModelDeviceKind::Cpu) + ) +); #endif TEST_F(ImageTests, LoadBindEvalModelWithoutImageMetadata) { - GPUTEST; + GPUTEST; - LoadModel(L"squeezenet_tensor_input.onnx"); + LoadModel(L"squeezenet_tensor_input.onnx"); - auto feature_value = FileHelpers::LoadImageFeatureValue(L"227x227.png"); + auto feature_value = FileHelpers::LoadImageFeatureValue(L"227x227.png"); - LearningModelSession model_session(m_model); - LearningModelBinding model_binding(model_session); + LearningModelSession model_session(m_model); + LearningModelBinding model_binding(model_session); - model_binding.Bind(L"data", feature_value); - auto result = model_session.Evaluate(model_binding, L""); + model_binding.Bind(L"data", feature_value); + auto result = model_session.Evaluate(model_binding, L""); } - TEST_F(ImageTests, LoadBindModelWithoutImageMetadata) { - GPUTEST; + GPUTEST; - // Model expecting a tensor instead of an image - LoadModel(L"squeezenet_tensor_input.onnx"); + // Model expecting a tensor instead of an image + LoadModel(L"squeezenet_tensor_input.onnx"); - LearningModelSession model_session(m_model); - LearningModelBinding model_binding(model_session); + LearningModelSession model_session(m_model); + LearningModelBinding model_binding(model_session); - // Should work on images (by falling back to RGB8) - auto feature_value = FileHelpers::LoadImageFeatureValue(L"227x227.png"); - model_binding.Bind(L"data", feature_value); + // Should work on images (by falling back to RGB8) + auto feature_value = FileHelpers::LoadImageFeatureValue(L"227x227.png"); + model_binding.Bind(L"data", feature_value); - // Should work on tensors - auto tensor = TensorFloat::CreateFromIterable({ 1, 3, 227, 227 }, winrt::single_threaded_vector(std::vector(3 * 227 * 227))); - model_binding.Bind(L"data", tensor); + // Should work on tensors + auto tensor = TensorFloat::CreateFromIterable( + {1, 3, 227, 227}, winrt::single_threaded_vector(std::vector(3 * 227 * 227)) + ); + model_binding.Bind(L"data", tensor); } TEST_F(ImageTests, LoadInvalidBindModelWithoutImageMetadata) { - GPUTEST; - - LoadModel(L"squeezenet_tensor_input.onnx"); - - LearningModelSession model_session(m_model); - LearningModelBinding model_binding(model_session); - - // expect not fail if image dimensions are bigger than required - auto feature_value = FileHelpers::LoadImageFeatureValue(L"1080.jpg"); - WINML_EXPECT_NO_THROW(model_binding.Bind(L"data", feature_value)); - - // expect fail if tensor is of wrong type - auto tensor_uint8 = TensorUInt8Bit::CreateFromIterable({ 1, 3, 227, 227 }, winrt::single_threaded_vector(std::vector(3 * 227 * 227))); - WINML_EXPECT_THROW_SPECIFIC(model_binding.Bind(L"data", tensor_uint8), - winrt::hresult_error, - [](const winrt::hresult_error& e) -> bool { - return e.code() == WINML_ERR_INVALID_BINDING; - }); - - // Should fail if tensor has smaller dimensions/type - auto tensor = TensorFloat::CreateFromIterable({ 1, 3, 22, 22 }, winrt::single_threaded_vector(std::vector(3 * 22 * 22))); - WINML_EXPECT_THROW_SPECIFIC(model_binding.Bind(L"data", tensor), - winrt::hresult_error, - [](const winrt::hresult_error& e) -> bool { - return e.code() == WINML_ERR_SIZE_MISMATCH; - }); + GPUTEST; + + LoadModel(L"squeezenet_tensor_input.onnx"); + + LearningModelSession model_session(m_model); + LearningModelBinding model_binding(model_session); + + // expect not fail if image dimensions are bigger than required + auto feature_value = FileHelpers::LoadImageFeatureValue(L"1080.jpg"); + WINML_EXPECT_NO_THROW(model_binding.Bind(L"data", feature_value)); + + // expect fail if tensor is of wrong type + auto tensor_uint8 = TensorUInt8Bit::CreateFromIterable( + {1, 3, 227, 227}, winrt::single_threaded_vector(std::vector(3 * 227 * 227)) + ); + WINML_EXPECT_THROW_SPECIFIC( + model_binding.Bind(L"data", tensor_uint8), + winrt::hresult_error, + [](const winrt::hresult_error& e) -> bool { return e.code() == WINML_ERR_INVALID_BINDING; } + ); + + // Should fail if tensor has smaller dimensions/type + auto tensor = TensorFloat::CreateFromIterable( + {1, 3, 22, 22}, winrt::single_threaded_vector(std::vector(3 * 22 * 22)) + ); + WINML_EXPECT_THROW_SPECIFIC( + model_binding.Bind(L"data", tensor), + winrt::hresult_error, + [](const winrt::hresult_error& e) -> bool { return e.code() == WINML_ERR_SIZE_MISMATCH; } + ); } TEST_F(ImageTests, ImageMetaDataTest) { - // supported image metadata - ValidateOutputImageMetaData(L"Add_ImageNet1920WithImageMetadataBgr8_SRGB_0_255.onnx", BitmapAlphaMode::Premultiplied, BitmapPixelFormat::Bgra8, true); - ValidateOutputImageMetaData(L"Add_ImageNet1920WithImageMetadataRgb8_SRGB_0_255.onnx", BitmapAlphaMode::Premultiplied, BitmapPixelFormat::Rgba8, true); - ValidateOutputImageMetaData(L"Add_ImageNet1920WithImageMetadataBgr8_SRGB_0_1.onnx", BitmapAlphaMode::Premultiplied, BitmapPixelFormat::Bgra8, true); - ValidateOutputImageMetaData(L"Add_ImageNet1920WithImageMetadataBgr8_SRGB_1_1.onnx", BitmapAlphaMode::Premultiplied, BitmapPixelFormat::Bgra8, true); - - // unsupported image metadata - ValidateOutputImageMetaData(L"Add_ImageNet1920WithImageMetadataBgra8_SRGB_0_255.onnx", BitmapAlphaMode::Straight, BitmapPixelFormat::Bgra8, false); - ValidateOutputImageMetaData(L"Add_ImageNet1920WithImageMetadataRgba8_SRGB_0_255.onnx", BitmapAlphaMode::Straight, BitmapPixelFormat::Rgba8, false); - ValidateOutputImageMetaData(L"Add_ImageNet1920WithImageMetadataBgr8_SRGB_16_235.onnx", BitmapAlphaMode::Straight, BitmapPixelFormat::Bgra8, false); - ValidateOutputImageMetaData(L"Add_ImageNet1920WithImageMetadataBgr8_LINEAR_0_255.onnx", BitmapAlphaMode::Straight, BitmapPixelFormat::Bgra8, false); + // supported image metadata + ValidateOutputImageMetaData( + L"Add_ImageNet1920WithImageMetadataBgr8_SRGB_0_255.onnx", + BitmapAlphaMode::Premultiplied, + BitmapPixelFormat::Bgra8, + true + ); + ValidateOutputImageMetaData( + L"Add_ImageNet1920WithImageMetadataRgb8_SRGB_0_255.onnx", + BitmapAlphaMode::Premultiplied, + BitmapPixelFormat::Rgba8, + true + ); + ValidateOutputImageMetaData( + L"Add_ImageNet1920WithImageMetadataBgr8_SRGB_0_1.onnx", + BitmapAlphaMode::Premultiplied, + BitmapPixelFormat::Bgra8, + true + ); + ValidateOutputImageMetaData( + L"Add_ImageNet1920WithImageMetadataBgr8_SRGB_1_1.onnx", + BitmapAlphaMode::Premultiplied, + BitmapPixelFormat::Bgra8, + true + ); + + // unsupported image metadata + ValidateOutputImageMetaData( + L"Add_ImageNet1920WithImageMetadataBgra8_SRGB_0_255.onnx", + BitmapAlphaMode::Straight, + BitmapPixelFormat::Bgra8, + false + ); + ValidateOutputImageMetaData( + L"Add_ImageNet1920WithImageMetadataRgba8_SRGB_0_255.onnx", + BitmapAlphaMode::Straight, + BitmapPixelFormat::Rgba8, + false + ); + ValidateOutputImageMetaData( + L"Add_ImageNet1920WithImageMetadataBgr8_SRGB_16_235.onnx", + BitmapAlphaMode::Straight, + BitmapPixelFormat::Bgra8, + false + ); + ValidateOutputImageMetaData( + L"Add_ImageNet1920WithImageMetadataBgr8_LINEAR_0_255.onnx", + BitmapAlphaMode::Straight, + BitmapPixelFormat::Bgra8, + false + ); } //Tests if GPU will throw TDR if the same image feature value is binded back to back for two different inputs to a model TEST_F(ImageTests, ImageBindingTwiceSameFeatureValueOnGpu) { - GPUTEST; - std::wstring module_path = FileHelpers::GetModulePath(); - static const wchar_t* input_data_image_filename = L"1080.jpg"; + GPUTEST; + std::wstring module_path = FileHelpers::GetModulePath(); + static const wchar_t* input_data_image_filename = L"1080.jpg"; - std::wstring full_image_path = module_path + input_data_image_filename; - ImageFeatureValue input_norm = CreateImageFeatureValue(full_image_path); + std::wstring full_image_path = module_path + input_data_image_filename; + ImageFeatureValue input_norm = CreateImageFeatureValue(full_image_path); - RunConsecutiveImageBindingOnGpu(input_norm, input_norm); + RunConsecutiveImageBindingOnGpu(input_norm, input_norm); } //Tests if GPU will throw TDR if 2 different image feature values are binded back to back for two different inputs to a model TEST_F(ImageTests, ImageBindingTwiceDifferentFeatureValueOnGpu) { - GPUTEST; - std::wstring module_path = FileHelpers::GetModulePath(); - static const wchar_t* input_data_image_filename = L"1080.jpg"; + GPUTEST; + std::wstring module_path = FileHelpers::GetModulePath(); + static const wchar_t* input_data_image_filename = L"1080.jpg"; - std::wstring full_image_path = module_path + input_data_image_filename; - ImageFeatureValue input_norm = CreateImageFeatureValue(full_image_path); - ImageFeatureValue input_norm_1 = CreateImageFeatureValue(full_image_path); + std::wstring full_image_path = module_path + input_data_image_filename; + ImageFeatureValue input_norm = CreateImageFeatureValue(full_image_path); + ImageFeatureValue input_norm_1 = CreateImageFeatureValue(full_image_path); - RunConsecutiveImageBindingOnGpu(input_norm, input_norm_1); + RunConsecutiveImageBindingOnGpu(input_norm, input_norm_1); } static void RunImageBindingInputAndOutput(bool bindInputAsIInspectable) { - static const wchar_t* model_file_name = L"Add_ImageNet1920.onnx"; - std::wstring module_path = FileHelpers::GetModulePath(); - static const wchar_t* input_data_image_filename = L"1080.jpg"; - static const wchar_t* output_data_image_filename = L"out_Add_ImageNet_1080.jpg"; - - // WinML model creation - LearningModel model(nullptr); - std::wstring full_model_path = module_path + model_file_name; - WINML_EXPECT_NO_THROW(model = LearningModel::LoadFromFilePath(full_model_path)); - LearningModelDeviceKind device_kind = LearningModelDeviceKind::DirectX; - LearningModelSession model_session(model, LearningModelDevice(device_kind)); - LearningModelBinding model_binding(model_session); - - std::wstring full_image_path = module_path + input_data_image_filename; - - StorageFile image_file = StorageFile::GetFileFromPathAsync(full_image_path).get(); - IRandomAccessStream stream = image_file.OpenAsync(FileAccessMode::Read).get(); - SoftwareBitmap software_bitmap = (BitmapDecoder::CreateAsync(stream).get()).GetSoftwareBitmapAsync().get(); - VideoFrame frame = VideoFrame::CreateWithSoftwareBitmap(software_bitmap); - - if (bindInputAsIInspectable) { - auto feature = model.InputFeatures().First(); - WINML_EXPECT_NO_THROW(model_binding.Bind(feature.Current().Name(), frame)); - feature.MoveNext(); - WINML_EXPECT_NO_THROW(model_binding.Bind(feature.Current().Name(), frame)); - } - else { - ImageFeatureValue input_image_tensor = ImageFeatureValue::CreateFromVideoFrame(frame); - auto feature = model.InputFeatures().First(); - WINML_EXPECT_NO_THROW(model_binding.Bind(feature.Current().Name(), input_image_tensor)); - feature.MoveNext(); - WINML_EXPECT_NO_THROW(model_binding.Bind(feature.Current().Name(), input_image_tensor)); - } - - auto output_tensor_descriptor = model.OutputFeatures().First().Current().as(); - auto output_tensor_shape = output_tensor_descriptor.Shape(); - VideoFrame output_image(BitmapPixelFormat::Rgba8, static_cast(output_tensor_shape.GetAt(3)), static_cast(output_tensor_shape.GetAt(2))); - ImageFeatureValue output_tensor = ImageFeatureValue::CreateFromVideoFrame(output_image); - - WINML_EXPECT_NO_THROW(model_binding.Bind(model.OutputFeatures().First().Current().Name(), output_tensor)); - - // Evaluate the model - winrt::hstring correlation_id; - model_session.EvaluateAsync(model_binding, correlation_id).get(); - - //check the output video frame object - StorageFolder current_folder = StorageFolder::GetFolderFromPathAsync(module_path).get(); - StorageFile out_image_file = current_folder.CreateFileAsync(output_data_image_filename, CreationCollisionOption::ReplaceExisting).get(); - IRandomAccessStream write_stream = out_image_file.OpenAsync(FileAccessMode::ReadWrite).get(); - - BitmapEncoder encoder = BitmapEncoder::CreateAsync(BitmapEncoder::JpegEncoderId(), write_stream).get(); - // Set the software bitmap - encoder.SetSoftwareBitmap(output_image.SoftwareBitmap()); - - encoder.FlushAsync().get(); - - BYTE* data = nullptr; - UINT32 ui_capacity = 0; - wgi::BitmapBuffer bitmap_buffer(output_image.SoftwareBitmap().LockBuffer(wgi::BitmapBufferAccessMode::Read)); - wf::IMemoryBufferReference reference = bitmap_buffer.CreateReference(); - auto spByteAccess = reference.as<::Windows::Foundation::IMemoryBufferByteAccess>(); - WINML_EXPECT_HRESULT_SUCCEEDED(spByteAccess->GetBuffer(&data, &ui_capacity)); - WINML_EXPECT_NOT_EQUAL(data[0], 0); + static const wchar_t* model_file_name = L"Add_ImageNet1920.onnx"; + std::wstring module_path = FileHelpers::GetModulePath(); + static const wchar_t* input_data_image_filename = L"1080.jpg"; + static const wchar_t* output_data_image_filename = L"out_Add_ImageNet_1080.jpg"; + + // WinML model creation + LearningModel model(nullptr); + std::wstring full_model_path = module_path + model_file_name; + WINML_EXPECT_NO_THROW(model = LearningModel::LoadFromFilePath(full_model_path)); + LearningModelDeviceKind device_kind = LearningModelDeviceKind::DirectX; + LearningModelSession model_session(model, LearningModelDevice(device_kind)); + LearningModelBinding model_binding(model_session); + + std::wstring full_image_path = module_path + input_data_image_filename; + + StorageFile image_file = StorageFile::GetFileFromPathAsync(full_image_path).get(); + IRandomAccessStream stream = image_file.OpenAsync(FileAccessMode::Read).get(); + SoftwareBitmap software_bitmap = (BitmapDecoder::CreateAsync(stream).get()).GetSoftwareBitmapAsync().get(); + VideoFrame frame = VideoFrame::CreateWithSoftwareBitmap(software_bitmap); + + if (bindInputAsIInspectable) { + auto feature = model.InputFeatures().First(); + WINML_EXPECT_NO_THROW(model_binding.Bind(feature.Current().Name(), frame)); + feature.MoveNext(); + WINML_EXPECT_NO_THROW(model_binding.Bind(feature.Current().Name(), frame)); + } else { + ImageFeatureValue input_image_tensor = ImageFeatureValue::CreateFromVideoFrame(frame); + auto feature = model.InputFeatures().First(); + WINML_EXPECT_NO_THROW(model_binding.Bind(feature.Current().Name(), input_image_tensor)); + feature.MoveNext(); + WINML_EXPECT_NO_THROW(model_binding.Bind(feature.Current().Name(), input_image_tensor)); + } + + auto output_tensor_descriptor = model.OutputFeatures().First().Current().as(); + auto output_tensor_shape = output_tensor_descriptor.Shape(); + VideoFrame output_image( + BitmapPixelFormat::Rgba8, + static_cast(output_tensor_shape.GetAt(3)), + static_cast(output_tensor_shape.GetAt(2)) + ); + ImageFeatureValue output_tensor = ImageFeatureValue::CreateFromVideoFrame(output_image); + + WINML_EXPECT_NO_THROW(model_binding.Bind(model.OutputFeatures().First().Current().Name(), output_tensor)); + + // Evaluate the model + winrt::hstring correlation_id; + model_session.EvaluateAsync(model_binding, correlation_id).get(); + + //check the output video frame object + StorageFolder current_folder = StorageFolder::GetFolderFromPathAsync(module_path).get(); + StorageFile out_image_file = + current_folder.CreateFileAsync(output_data_image_filename, CreationCollisionOption::ReplaceExisting).get(); + IRandomAccessStream write_stream = out_image_file.OpenAsync(FileAccessMode::ReadWrite).get(); + + BitmapEncoder encoder = BitmapEncoder::CreateAsync(BitmapEncoder::JpegEncoderId(), write_stream).get(); + // Set the software bitmap + encoder.SetSoftwareBitmap(output_image.SoftwareBitmap()); + + encoder.FlushAsync().get(); + + BYTE* data = nullptr; + UINT32 ui_capacity = 0; + wgi::BitmapBuffer bitmap_buffer(output_image.SoftwareBitmap().LockBuffer(wgi::BitmapBufferAccessMode::Read)); + wf::IMemoryBufferReference reference = bitmap_buffer.CreateReference(); + auto spByteAccess = reference.as<::Windows::Foundation::IMemoryBufferByteAccess>(); + WINML_EXPECT_HRESULT_SUCCEEDED(spByteAccess->GetBuffer(&data, &ui_capacity)); + WINML_EXPECT_NOT_EQUAL(data[0], 0); } TEST_F(ImageTests, ImageBindingInputAndOutput) { - GPUTEST; - RunImageBindingInputAndOutput(false /*bindInputAsIInspectable*/); + GPUTEST; + RunImageBindingInputAndOutput(false /*bindInputAsIInspectable*/); } TEST_F(ImageTests, ImageBindingInputAndOutput_BindInputTensorAsInspectable) { - GPUTEST; - RunImageBindingInputAndOutput(true /*bindInputAsIInspectable*/); + GPUTEST; + RunImageBindingInputAndOutput(true /*bindInputAsIInspectable*/); } -static void TestImageBindingStyleTransfer(const wchar_t* model_file_name, const wchar_t* input_data_image_filename, wchar_t* output_data_image_filename) { - GPUTEST; - - //this test only checks that the operation completed successfully without crashing - - std::wstring module_path = FileHelpers::GetModulePath(); - - // WinML model creation - LearningModel model(nullptr); - std::wstring full_model_path = module_path + model_file_name; - WINML_EXPECT_NO_THROW(model = LearningModel::LoadFromFilePath(full_model_path)); - LearningModelDeviceKind device_kind = LearningModelDeviceKind::DirectX; - LearningModelDevice device = nullptr; - WINML_EXPECT_NO_THROW(device = LearningModelDevice(device_kind)); - LearningModelSession model_session = nullptr; - WINML_EXPECT_NO_THROW(model_session = LearningModelSession(model, device)); - LearningModelBinding model_binding = nullptr; - WINML_EXPECT_NO_THROW(model_binding = LearningModelBinding(model_session)); - - std::wstring full_image_path = module_path + input_data_image_filename; - - StorageFile image_file = StorageFile::GetFileFromPathAsync(full_image_path).get(); - IRandomAccessStream stream = image_file.OpenAsync(FileAccessMode::Read).get(); - SoftwareBitmap software_bitmap = (BitmapDecoder::CreateAsync(stream).get()).GetSoftwareBitmapAsync().get(); - VideoFrame frame = VideoFrame::CreateWithSoftwareBitmap(software_bitmap); - //aizBUG:3762 Cannot bind the same tensor to 2 different input. will deal with this in a later check in - ImageFeatureValue input_1_image_tensor = ImageFeatureValue::CreateFromVideoFrame(frame); - - auto feature = model.InputFeatures().First(); - WINML_EXPECT_NO_THROW(model_binding.Bind(feature.Current().Name(), input_1_image_tensor)); - - auto output_tensor_descriptor = model.OutputFeatures().First().Current().as(); - auto output_tensor_shape = output_tensor_descriptor.Shape(); - VideoFrame output_image(BitmapPixelFormat::Rgba8, static_cast(output_tensor_shape.GetAt(3)), static_cast(output_tensor_shape.GetAt(2))); - ImageFeatureValue output_tensor = ImageFeatureValue::CreateFromVideoFrame(output_image); - - WINML_EXPECT_NO_THROW(model_binding.Bind(model.OutputFeatures().First().Current().Name(), output_tensor)); - - // Evaluate the model - winrt::hstring correlation_id; - WINML_EXPECT_NO_THROW(model_session.EvaluateAsync(model_binding, correlation_id).get()); - - //check the output video frame object - StorageFolder current_folder = StorageFolder::GetFolderFromPathAsync(module_path).get(); - StorageFile out_image_file = current_folder.CreateFileAsync(output_data_image_filename, CreationCollisionOption::ReplaceExisting).get(); - IRandomAccessStream write_stream = out_image_file.OpenAsync(FileAccessMode::ReadWrite).get(); - - BitmapEncoder encoder = BitmapEncoder::CreateAsync(BitmapEncoder::JpegEncoderId(), write_stream).get(); - // Set the software bitmap - encoder.SetSoftwareBitmap(output_image.SoftwareBitmap()); - - encoder.FlushAsync().get(); - +static void TestImageBindingStyleTransfer( + const wchar_t* model_file_name, const wchar_t* input_data_image_filename, wchar_t* output_data_image_filename +) { + GPUTEST; + + //this test only checks that the operation completed successfully without crashing + + std::wstring module_path = FileHelpers::GetModulePath(); + + // WinML model creation + LearningModel model(nullptr); + std::wstring full_model_path = module_path + model_file_name; + WINML_EXPECT_NO_THROW(model = LearningModel::LoadFromFilePath(full_model_path)); + LearningModelDeviceKind device_kind = LearningModelDeviceKind::DirectX; + LearningModelDevice device = nullptr; + WINML_EXPECT_NO_THROW(device = LearningModelDevice(device_kind)); + LearningModelSession model_session = nullptr; + WINML_EXPECT_NO_THROW(model_session = LearningModelSession(model, device)); + LearningModelBinding model_binding = nullptr; + WINML_EXPECT_NO_THROW(model_binding = LearningModelBinding(model_session)); + + std::wstring full_image_path = module_path + input_data_image_filename; + + StorageFile image_file = StorageFile::GetFileFromPathAsync(full_image_path).get(); + IRandomAccessStream stream = image_file.OpenAsync(FileAccessMode::Read).get(); + SoftwareBitmap software_bitmap = (BitmapDecoder::CreateAsync(stream).get()).GetSoftwareBitmapAsync().get(); + VideoFrame frame = VideoFrame::CreateWithSoftwareBitmap(software_bitmap); + //aizBUG:3762 Cannot bind the same tensor to 2 different input. will deal with this in a later check in + ImageFeatureValue input_1_image_tensor = ImageFeatureValue::CreateFromVideoFrame(frame); + + auto feature = model.InputFeatures().First(); + WINML_EXPECT_NO_THROW(model_binding.Bind(feature.Current().Name(), input_1_image_tensor)); + + auto output_tensor_descriptor = model.OutputFeatures().First().Current().as(); + auto output_tensor_shape = output_tensor_descriptor.Shape(); + VideoFrame output_image( + BitmapPixelFormat::Rgba8, + static_cast(output_tensor_shape.GetAt(3)), + static_cast(output_tensor_shape.GetAt(2)) + ); + ImageFeatureValue output_tensor = ImageFeatureValue::CreateFromVideoFrame(output_image); + + WINML_EXPECT_NO_THROW(model_binding.Bind(model.OutputFeatures().First().Current().Name(), output_tensor)); + + // Evaluate the model + winrt::hstring correlation_id; + WINML_EXPECT_NO_THROW(model_session.EvaluateAsync(model_binding, correlation_id).get()); + + //check the output video frame object + StorageFolder current_folder = StorageFolder::GetFolderFromPathAsync(module_path).get(); + StorageFile out_image_file = + current_folder.CreateFileAsync(output_data_image_filename, CreationCollisionOption::ReplaceExisting).get(); + IRandomAccessStream write_stream = out_image_file.OpenAsync(FileAccessMode::ReadWrite).get(); + + BitmapEncoder encoder = BitmapEncoder::CreateAsync(BitmapEncoder::JpegEncoderId(), write_stream).get(); + // Set the software bitmap + encoder.SetSoftwareBitmap(output_image.SoftwareBitmap()); + + encoder.FlushAsync().get(); } TEST_F(ImageTests, ImageBindingStyleTransfer) { - //this test only checks that the operation completed successfully without crashing - TestImageBindingStyleTransfer(L"fns-candy.onnx", L"fish_720.png", L"out_fish_720_StyleTransfer.jpg"); + //this test only checks that the operation completed successfully without crashing + TestImageBindingStyleTransfer(L"fns-candy.onnx", L"fish_720.png", L"out_fish_720_StyleTransfer.jpg"); } TEST_F(ImageTests, ImageBindingAsGPUTensor) { - GPUTEST; - - static const wchar_t* model_file_name = L"fns-candy.onnx"; - std::wstring module_path = FileHelpers::GetModulePath(); - static const wchar_t* input_data_image_filename = L"fish_720.png"; - static const wchar_t* output_data_image_filename = L"out_fish_720_StyleTransfer.jpg"; - - // WinML model creation - LearningModel model(nullptr); - std::wstring full_model_path = module_path + model_file_name; - WINML_EXPECT_NO_THROW(model = LearningModel::LoadFromFilePath(full_model_path)); - - ID3D12Device* D3D12_device = nullptr; - WINML_EXPECT_NO_THROW(D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), reinterpret_cast(&D3D12_device))); - ID3D12CommandQueue* dx_queue = nullptr; - D3D12_COMMAND_QUEUE_DESC command_queue_desc = {}; - command_queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; - D3D12_device->CreateCommandQueue(&command_queue_desc, __uuidof(ID3D12CommandQueue), reinterpret_cast(&dx_queue)); - auto device_factory = get_activation_factory(); - auto tensor_factory = get_activation_factory(); - - - com_ptr<::IUnknown> p_unk; - device_factory->CreateFromD3D12CommandQueue(dx_queue, p_unk.put()); - - LearningModelDevice dml_device_custom = nullptr; - WINML_EXPECT_NO_THROW(p_unk.as(dml_device_custom)); - LearningModelSession dml_session_custom = nullptr; - WINML_EXPECT_NO_THROW(dml_session_custom = LearningModelSession(model, dml_device_custom)); - - LearningModelBinding model_binding(dml_session_custom); - - std::wstring full_image_path = module_path + input_data_image_filename; - - StorageFile image_file = StorageFile::GetFileFromPathAsync(full_image_path).get(); - IRandomAccessStream stream = image_file.OpenAsync(FileAccessMode::Read).get(); - SoftwareBitmap software_bitmap = (BitmapDecoder::CreateAsync(stream).get()).GetSoftwareBitmapAsync().get(); - - UINT64 buffer_byte_size = static_cast(software_bitmap.PixelWidth()) * software_bitmap.PixelHeight() * 3 * sizeof(float); - D3D12_HEAP_PROPERTIES heap_properties = { - D3D12_HEAP_TYPE_DEFAULT, - D3D12_CPU_PAGE_PROPERTY_UNKNOWN, - D3D12_MEMORY_POOL_UNKNOWN, - 0, - 0 - }; - D3D12_RESOURCE_DESC resource_desc = { - D3D12_RESOURCE_DIMENSION_BUFFER, - 0, - buffer_byte_size, - 1, - 1, - 1, - DXGI_FORMAT_UNKNOWN, - { 1, 0 }, - D3D12_TEXTURE_LAYOUT_ROW_MAJOR, - D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS - }; - - com_ptr GPU_resource = nullptr; - D3D12_device->CreateCommittedResource( - &heap_properties, - D3D12_HEAP_FLAG_NONE, - &resource_desc, - D3D12_RESOURCE_STATE_COMMON, - nullptr, - __uuidof(ID3D12Resource), - GPU_resource.put_void() - ); - com_ptr<::IUnknown> sp_unk_tensor; - TensorFloat input_1_image_tensor(nullptr); - __int64 shape[4] = { 1,3, software_bitmap.PixelWidth(), software_bitmap.PixelHeight() }; - tensor_factory->CreateFromD3D12Resource(GPU_resource.get(), shape, 4, sp_unk_tensor.put()); - sp_unk_tensor.try_as(input_1_image_tensor); - - auto feature = model.InputFeatures().First(); - WINML_EXPECT_NO_THROW(model_binding.Bind(feature.Current().Name(), input_1_image_tensor)); - - auto output_tensor_descriptor = model.OutputFeatures().First().Current().as(); - auto output_tensor_shape = output_tensor_descriptor.Shape(); - VideoFrame output_image(BitmapPixelFormat::Rgba8, static_cast(output_tensor_shape.GetAt(3)), static_cast(output_tensor_shape.GetAt(2))); - ImageFeatureValue output_tensor = ImageFeatureValue::CreateFromVideoFrame(output_image); - - WINML_EXPECT_NO_THROW(model_binding.Bind(model.OutputFeatures().First().Current().Name(), output_tensor)); - - // Evaluate the model - winrt::hstring correlation_id; - dml_session_custom.EvaluateAsync(model_binding, correlation_id).get(); - - //check the output video frame object - StorageFolder current_folder = StorageFolder::GetFolderFromPathAsync(module_path).get(); - StorageFile out_image_file = current_folder.CreateFileAsync(output_data_image_filename, CreationCollisionOption::ReplaceExisting).get(); - IRandomAccessStream write_stream = out_image_file.OpenAsync(FileAccessMode::ReadWrite).get(); - - BitmapEncoder encoder = BitmapEncoder::CreateAsync(BitmapEncoder::JpegEncoderId(), write_stream).get(); - // Set the software bitmap - encoder.SetSoftwareBitmap(output_image.SoftwareBitmap()); - - encoder.FlushAsync().get(); + GPUTEST; + + static const wchar_t* model_file_name = L"fns-candy.onnx"; + std::wstring module_path = FileHelpers::GetModulePath(); + static const wchar_t* input_data_image_filename = L"fish_720.png"; + static const wchar_t* output_data_image_filename = L"out_fish_720_StyleTransfer.jpg"; + + // WinML model creation + LearningModel model(nullptr); + std::wstring full_model_path = module_path + model_file_name; + WINML_EXPECT_NO_THROW(model = LearningModel::LoadFromFilePath(full_model_path)); + + ID3D12Device* D3D12_device = nullptr; + WINML_EXPECT_NO_THROW(D3D12CreateDevice( + nullptr, D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), reinterpret_cast(&D3D12_device) + )); + ID3D12CommandQueue* dx_queue = nullptr; + D3D12_COMMAND_QUEUE_DESC command_queue_desc = {}; + command_queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; + D3D12_device->CreateCommandQueue( + &command_queue_desc, __uuidof(ID3D12CommandQueue), reinterpret_cast(&dx_queue) + ); + auto device_factory = get_activation_factory(); + auto tensor_factory = get_activation_factory(); + + com_ptr<::IUnknown> p_unk; + device_factory->CreateFromD3D12CommandQueue(dx_queue, p_unk.put()); + + LearningModelDevice dml_device_custom = nullptr; + WINML_EXPECT_NO_THROW(p_unk.as(dml_device_custom)); + LearningModelSession dml_session_custom = nullptr; + WINML_EXPECT_NO_THROW(dml_session_custom = LearningModelSession(model, dml_device_custom)); + + LearningModelBinding model_binding(dml_session_custom); + + std::wstring full_image_path = module_path + input_data_image_filename; + + StorageFile image_file = StorageFile::GetFileFromPathAsync(full_image_path).get(); + IRandomAccessStream stream = image_file.OpenAsync(FileAccessMode::Read).get(); + SoftwareBitmap software_bitmap = (BitmapDecoder::CreateAsync(stream).get()).GetSoftwareBitmapAsync().get(); + + UINT64 buffer_byte_size = + static_cast(software_bitmap.PixelWidth()) * software_bitmap.PixelHeight() * 3 * sizeof(float); + D3D12_HEAP_PROPERTIES heap_properties = { + D3D12_HEAP_TYPE_DEFAULT, D3D12_CPU_PAGE_PROPERTY_UNKNOWN, D3D12_MEMORY_POOL_UNKNOWN, 0, 0}; + D3D12_RESOURCE_DESC resource_desc = { + D3D12_RESOURCE_DIMENSION_BUFFER, + 0, + buffer_byte_size, + 1, + 1, + 1, + DXGI_FORMAT_UNKNOWN, + {1, 0}, + D3D12_TEXTURE_LAYOUT_ROW_MAJOR, + D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS + }; + + com_ptr GPU_resource = nullptr; + D3D12_device->CreateCommittedResource( + &heap_properties, + D3D12_HEAP_FLAG_NONE, + &resource_desc, + D3D12_RESOURCE_STATE_COMMON, + nullptr, + __uuidof(ID3D12Resource), + GPU_resource.put_void() + ); + com_ptr<::IUnknown> sp_unk_tensor; + TensorFloat input_1_image_tensor(nullptr); + __int64 shape[4] = {1, 3, software_bitmap.PixelWidth(), software_bitmap.PixelHeight()}; + tensor_factory->CreateFromD3D12Resource(GPU_resource.get(), shape, 4, sp_unk_tensor.put()); + sp_unk_tensor.try_as(input_1_image_tensor); + + auto feature = model.InputFeatures().First(); + WINML_EXPECT_NO_THROW(model_binding.Bind(feature.Current().Name(), input_1_image_tensor)); + + auto output_tensor_descriptor = model.OutputFeatures().First().Current().as(); + auto output_tensor_shape = output_tensor_descriptor.Shape(); + VideoFrame output_image( + BitmapPixelFormat::Rgba8, + static_cast(output_tensor_shape.GetAt(3)), + static_cast(output_tensor_shape.GetAt(2)) + ); + ImageFeatureValue output_tensor = ImageFeatureValue::CreateFromVideoFrame(output_image); + + WINML_EXPECT_NO_THROW(model_binding.Bind(model.OutputFeatures().First().Current().Name(), output_tensor)); + + // Evaluate the model + winrt::hstring correlation_id; + dml_session_custom.EvaluateAsync(model_binding, correlation_id).get(); + + //check the output video frame object + StorageFolder current_folder = StorageFolder::GetFolderFromPathAsync(module_path).get(); + StorageFile out_image_file = + current_folder.CreateFileAsync(output_data_image_filename, CreationCollisionOption::ReplaceExisting).get(); + IRandomAccessStream write_stream = out_image_file.OpenAsync(FileAccessMode::ReadWrite).get(); + + BitmapEncoder encoder = BitmapEncoder::CreateAsync(BitmapEncoder::JpegEncoderId(), write_stream).get(); + // Set the software bitmap + encoder.SetSoftwareBitmap(output_image.SoftwareBitmap()); + + encoder.FlushAsync().get(); } -static void GetCleanSession(LearningModelDeviceKind device_kind, std::wstring modelFilePath, LearningModelDevice &device, LearningModelSession &session) { - LearningModel model(nullptr); - std::wstring full_model_path = modelFilePath; - WINML_EXPECT_NO_THROW(model = LearningModel::LoadFromFilePath(full_model_path)); - WINML_EXPECT_NO_THROW(device = LearningModelDevice(device_kind)); - WINML_EXPECT_NO_THROW(session = LearningModelSession(model, device)); +static void GetCleanSession( + LearningModelDeviceKind device_kind, + std::wstring modelFilePath, + LearningModelDevice& device, + LearningModelSession& session +) { + LearningModel model(nullptr); + std::wstring full_model_path = modelFilePath; + WINML_EXPECT_NO_THROW(model = LearningModel::LoadFromFilePath(full_model_path)); + WINML_EXPECT_NO_THROW(device = LearningModelDevice(device_kind)); + WINML_EXPECT_NO_THROW(session = LearningModelSession(model, device)); } -static void BindInputToSession(BindingLocation bind_location, std::wstring input_data_location, LearningModelSession& session, LearningModelBinding& binding) { - StorageFile image_file = StorageFile::GetFileFromPathAsync(input_data_location).get(); - IRandomAccessStream stream = image_file.OpenAsync(FileAccessMode::Read).get(); - SoftwareBitmap software_bitmap = (BitmapDecoder::CreateAsync(stream).get()).GetSoftwareBitmapAsync().get(); - VideoFrame cpu_video_frame = VideoFrame::CreateWithSoftwareBitmap(software_bitmap); - if (bind_location == BindingLocation::CPU) { - ImageFeatureValue input_image_feature_value = ImageFeatureValue::CreateFromVideoFrame(cpu_video_frame); - WINML_EXPECT_NO_THROW(binding.Bind(session.Model().InputFeatures().First().Current().Name(), input_image_feature_value)); - } else { - DirectXPixelFormat format = DirectXPixelFormat::B8G8R8X8UIntNormalized; - VideoFrame gpu_video_frame = VideoFrame::CreateAsDirect3D11SurfaceBacked(format, - software_bitmap.PixelWidth(), - software_bitmap.PixelHeight(), - session.Device().Direct3D11Device()); - cpu_video_frame.CopyToAsync(gpu_video_frame).get(); - ImageFeatureValue input_image_feature_value = ImageFeatureValue::CreateFromVideoFrame(gpu_video_frame); - WINML_EXPECT_NO_THROW(binding.Bind(session.Model().InputFeatures().First().Current().Name(), input_image_feature_value)); - } +static void BindInputToSession( + BindingLocation bind_location, + std::wstring input_data_location, + LearningModelSession& session, + LearningModelBinding& binding +) { + StorageFile image_file = StorageFile::GetFileFromPathAsync(input_data_location).get(); + IRandomAccessStream stream = image_file.OpenAsync(FileAccessMode::Read).get(); + SoftwareBitmap software_bitmap = (BitmapDecoder::CreateAsync(stream).get()).GetSoftwareBitmapAsync().get(); + VideoFrame cpu_video_frame = VideoFrame::CreateWithSoftwareBitmap(software_bitmap); + if (bind_location == BindingLocation::CPU) { + ImageFeatureValue input_image_feature_value = ImageFeatureValue::CreateFromVideoFrame(cpu_video_frame); + WINML_EXPECT_NO_THROW( + binding.Bind(session.Model().InputFeatures().First().Current().Name(), input_image_feature_value) + ); + } else { + DirectXPixelFormat format = DirectXPixelFormat::B8G8R8X8UIntNormalized; + VideoFrame gpu_video_frame = VideoFrame::CreateAsDirect3D11SurfaceBacked( + format, software_bitmap.PixelWidth(), software_bitmap.PixelHeight(), session.Device().Direct3D11Device() + ); + cpu_video_frame.CopyToAsync(gpu_video_frame).get(); + ImageFeatureValue input_image_feature_value = ImageFeatureValue::CreateFromVideoFrame(gpu_video_frame); + WINML_EXPECT_NO_THROW( + binding.Bind(session.Model().InputFeatures().First().Current().Name(), input_image_feature_value) + ); + } } -static void BindOutputToSession(BindingLocation bind_location, LearningModelSession& session, LearningModelBinding& binding) { - auto output_tensor_descriptor = session.Model().OutputFeatures().First().Current().as(); - auto output_tensor_shape = output_tensor_descriptor.Shape(); - if (bind_location == BindingLocation::CPU) { - VideoFrame output_image(BitmapPixelFormat::Rgba8, static_cast(output_tensor_shape.GetAt(3)), static_cast(output_tensor_shape.GetAt(2))); - ImageFeatureValue output_tensor = ImageFeatureValue::CreateFromVideoFrame(output_image); - WINML_EXPECT_NO_THROW(binding.Bind(session.Model().OutputFeatures().First().Current().Name(), output_tensor)); - } - else { - VideoFrame output_image = VideoFrame::CreateAsDirect3D11SurfaceBacked(DirectXPixelFormat::B8G8R8X8UIntNormalized, - static_cast(output_tensor_shape.GetAt(3)), - static_cast(output_tensor_shape.GetAt(2))); - ImageFeatureValue output_tensor = ImageFeatureValue::CreateFromVideoFrame(output_image); - WINML_EXPECT_NO_THROW(binding.Bind(session.Model().OutputFeatures().First().Current().Name(), output_tensor)); - } +static void BindOutputToSession( + BindingLocation bind_location, LearningModelSession& session, LearningModelBinding& binding +) { + auto output_tensor_descriptor = session.Model().OutputFeatures().First().Current().as(); + auto output_tensor_shape = output_tensor_descriptor.Shape(); + if (bind_location == BindingLocation::CPU) { + VideoFrame output_image( + BitmapPixelFormat::Rgba8, + static_cast(output_tensor_shape.GetAt(3)), + static_cast(output_tensor_shape.GetAt(2)) + ); + ImageFeatureValue output_tensor = ImageFeatureValue::CreateFromVideoFrame(output_image); + WINML_EXPECT_NO_THROW(binding.Bind(session.Model().OutputFeatures().First().Current().Name(), output_tensor)); + } else { + VideoFrame output_image = VideoFrame::CreateAsDirect3D11SurfaceBacked( + DirectXPixelFormat::B8G8R8X8UIntNormalized, + static_cast(output_tensor_shape.GetAt(3)), + static_cast(output_tensor_shape.GetAt(2)) + ); + ImageFeatureValue output_tensor = ImageFeatureValue::CreateFromVideoFrame(output_image); + WINML_EXPECT_NO_THROW(binding.Bind(session.Model().OutputFeatures().First().Current().Name(), output_tensor)); + } } static void SynchronizeGPUWorkloads(const wchar_t* model_file_name, const wchar_t* input_data_image_filename) { - //this test only checks that the operations complete successfully without crashing - GPUTEST; - std::wstring module_path = FileHelpers::GetModulePath(); - LearningModelDevice device = nullptr; - LearningModelSession session = nullptr; - LearningModelBinding binding = nullptr; - - /* + //this test only checks that the operations complete successfully without crashing + GPUTEST; + std::wstring module_path = FileHelpers::GetModulePath(); + LearningModelDevice device = nullptr; + LearningModelSession session = nullptr; + LearningModelBinding binding = nullptr; + + /* * lazy dx11 loading scenarios: */ - // Scenario 1 - GetCleanSession(LearningModelDeviceKind::DirectX, module_path + model_file_name, device, session); + // Scenario 1 + GetCleanSession(LearningModelDeviceKind::DirectX, module_path + model_file_name, device, session); - // input: CPU, output: CPU - WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); - BindInputToSession(BindingLocation::CPU, module_path + input_data_image_filename, session, binding); - BindOutputToSession(BindingLocation::CPU, session, binding); - WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); + // input: CPU, output: CPU + WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); + BindInputToSession(BindingLocation::CPU, module_path + input_data_image_filename, session, binding); + BindOutputToSession(BindingLocation::CPU, session, binding); + WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); - // ---> verify that 11 stack is not initialized - WINML_EXPECT_FALSE(device.as()->SharedHandleInitialized()); + // ---> verify that 11 stack is not initialized + WINML_EXPECT_FALSE(device.as()->SharedHandleInitialized()); - // input: CPU, output: GPU - WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); - BindInputToSession(BindingLocation::CPU, module_path + input_data_image_filename, session, binding); - BindOutputToSession(BindingLocation::GPU, session, binding); - WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); + // input: CPU, output: GPU + WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); + BindInputToSession(BindingLocation::CPU, module_path + input_data_image_filename, session, binding); + BindOutputToSession(BindingLocation::GPU, session, binding); + WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); - // Scenario 2 - GetCleanSession(LearningModelDeviceKind::DirectX, module_path + model_file_name, device, session); + // Scenario 2 + GetCleanSession(LearningModelDeviceKind::DirectX, module_path + model_file_name, device, session); - // input: CPU, output: CPU - WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); - BindInputToSession(BindingLocation::CPU, module_path + input_data_image_filename, session, binding); - BindOutputToSession(BindingLocation::CPU, session, binding); - WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); + // input: CPU, output: CPU + WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); + BindInputToSession(BindingLocation::CPU, module_path + input_data_image_filename, session, binding); + BindOutputToSession(BindingLocation::CPU, session, binding); + WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); - // ---> verify that 11 stack is not initialized - WINML_EXPECT_FALSE(device.as()->SharedHandleInitialized()); + // ---> verify that 11 stack is not initialized + WINML_EXPECT_FALSE(device.as()->SharedHandleInitialized()); - // input: GPU, output: CPU - WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); - BindInputToSession(BindingLocation::GPU, module_path + input_data_image_filename, session, binding); - BindOutputToSession(BindingLocation::CPU, session, binding); - WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); + // input: GPU, output: CPU + WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); + BindInputToSession(BindingLocation::GPU, module_path + input_data_image_filename, session, binding); + BindOutputToSession(BindingLocation::CPU, session, binding); + WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); - // ---> verify that 11 stack is initialized - WINML_EXPECT_TRUE(device.as()->SharedHandleInitialized()); + // ---> verify that 11 stack is initialized + WINML_EXPECT_TRUE(device.as()->SharedHandleInitialized()); - // Scenario 3 - GetCleanSession(LearningModelDeviceKind::DirectX, module_path + model_file_name, device, session); + // Scenario 3 + GetCleanSession(LearningModelDeviceKind::DirectX, module_path + model_file_name, device, session); - // input: CPU, output: CPU - WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); - BindInputToSession(BindingLocation::CPU, module_path + input_data_image_filename, session, binding); - BindOutputToSession(BindingLocation::CPU, session, binding); - WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); + // input: CPU, output: CPU + WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); + BindInputToSession(BindingLocation::CPU, module_path + input_data_image_filename, session, binding); + BindOutputToSession(BindingLocation::CPU, session, binding); + WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); - // ---> verify that 11 stack is not initialized - WINML_EXPECT_FALSE(device.as()->SharedHandleInitialized()); + // ---> verify that 11 stack is not initialized + WINML_EXPECT_FALSE(device.as()->SharedHandleInitialized()); - // input: GPU, output: GPU - WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); - BindInputToSession(BindingLocation::GPU, module_path + input_data_image_filename, session, binding); - BindOutputToSession(BindingLocation::GPU, session, binding); - WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); + // input: GPU, output: GPU + WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); + BindInputToSession(BindingLocation::GPU, module_path + input_data_image_filename, session, binding); + BindOutputToSession(BindingLocation::GPU, session, binding); + WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); - // ---> verify that 11 stack is initialized - WINML_EXPECT_TRUE(device.as()->SharedHandleInitialized()); + // ---> verify that 11 stack is initialized + WINML_EXPECT_TRUE(device.as()->SharedHandleInitialized()); - /* + /* * non lazy dx11 loading scenarios: */ - // Scenario 1 - GetCleanSession(LearningModelDeviceKind::DirectX, module_path + model_file_name, device, session); - - // input: GPU, output: CPU - WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); - BindInputToSession(BindingLocation::GPU, module_path + input_data_image_filename, session, binding); - BindOutputToSession(BindingLocation::CPU, session, binding); - WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); - - // ---> verify that 11 stack is initialized - WINML_EXPECT_TRUE(device.as()->SharedHandleInitialized()); - - // input : CPU, output : CPU - WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); - BindInputToSession(BindingLocation::CPU, module_path + input_data_image_filename, session, binding); - BindOutputToSession(BindingLocation::CPU, session, binding); - WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); - - // Scenario 2 - GetCleanSession(LearningModelDeviceKind::DirectX, module_path + model_file_name, device, session); - - // input: CPU, output: GPU - WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); - BindInputToSession(BindingLocation::CPU, module_path + input_data_image_filename, session, binding); - BindOutputToSession(BindingLocation::GPU, session, binding); - WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); - - // input : CPU, output : CPU - WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); - BindInputToSession(BindingLocation::CPU, module_path + input_data_image_filename, session, binding); - BindOutputToSession(BindingLocation::CPU, session, binding); - WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); + // Scenario 1 + GetCleanSession(LearningModelDeviceKind::DirectX, module_path + model_file_name, device, session); + + // input: GPU, output: CPU + WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); + BindInputToSession(BindingLocation::GPU, module_path + input_data_image_filename, session, binding); + BindOutputToSession(BindingLocation::CPU, session, binding); + WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); + + // ---> verify that 11 stack is initialized + WINML_EXPECT_TRUE(device.as()->SharedHandleInitialized()); + + // input : CPU, output : CPU + WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); + BindInputToSession(BindingLocation::CPU, module_path + input_data_image_filename, session, binding); + BindOutputToSession(BindingLocation::CPU, session, binding); + WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); + + // Scenario 2 + GetCleanSession(LearningModelDeviceKind::DirectX, module_path + model_file_name, device, session); + + // input: CPU, output: GPU + WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); + BindInputToSession(BindingLocation::CPU, module_path + input_data_image_filename, session, binding); + BindOutputToSession(BindingLocation::GPU, session, binding); + WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); + + // input : CPU, output : CPU + WINML_EXPECT_NO_THROW(binding = LearningModelBinding(session)); + BindInputToSession(BindingLocation::CPU, module_path + input_data_image_filename, session, binding); + BindOutputToSession(BindingLocation::CPU, session, binding); + WINML_EXPECT_NO_THROW(session.Evaluate(binding, L"")); } TEST_F(ImageTests, SynchronizeGPUWorkloads) { - SynchronizeGPUWorkloads(L"fns-candy.onnx", L"fish_720.png"); + SynchronizeGPUWorkloads(L"fns-candy.onnx", L"fish_720.png"); } diff --git a/winml/test/model/compare_feature_value.cpp b/winml/test/model/compare_feature_value.cpp index a87a4b5546ec6..30b16c4ad5f73 100644 --- a/winml/test/model/compare_feature_value.cpp +++ b/winml/test/model/compare_feature_value.cpp @@ -7,24 +7,29 @@ using namespace winrt::Windows::Foundation::Collections; using namespace winml; -namespace CompareFeatureValuesHelper{ +namespace CompareFeatureValuesHelper { template bool IsResultCloselyMatch(const T& outvalue, const T& expected_value, const double diff, const double tol) { - if (diff > tol) return false; - if (std::isnan(diff) && !(std::isnan(outvalue) && std::isnan(expected_value)) && - !(std::isinf(outvalue) && std::isinf(expected_value))) + if (diff > tol) + return false; + if (std::isnan(diff) && !(std::isnan(outvalue) && std::isnan(expected_value)) && !(std::isinf(outvalue) && std::isinf(expected_value))) return false; return true; } bool CompareSequenceOfMapsStringToFloat( - IVectorView> featureValue, - const Ort::Value& val, - double perSampleTolerance, - double relativePerSampleTolerance) { + IVectorView> featureValue, + const Ort::Value& val, + double perSampleTolerance, + double relativePerSampleTolerance +) { if (val.GetCount() != featureValue.Size()) { - printf("Map lengths are not the same! Got %d, expected %d\n", static_cast(featureValue.Size()), static_cast(val.GetCount())); + printf( + "Map lengths are not the same! Got %d, expected %d\n", + static_cast(featureValue.Size()), + static_cast(val.GetCount()) + ); } int expectedValSequenceIndex = 0; @@ -40,8 +45,10 @@ bool CompareSequenceOfMapsStringToFloat( WINML_EXPECT_NO_THROW(mapExpectedOutputKeys = mapExpectedOutput.GetValue(0, allocator)); WINML_EXPECT_NO_THROW(mapExpectedOutputValues = mapExpectedOutput.GetValue(1, allocator)); - auto expectedOutputKeys = OrtValueHelpers::LoadTensorFromOrtValue(mapExpectedOutputKeys).as().GetAsVectorView(); - auto expectedOutputValues = OrtValueHelpers::LoadTensorFromOrtValue(mapExpectedOutputValues).as().GetAsVectorView(); + auto expectedOutputKeys = + OrtValueHelpers::LoadTensorFromOrtValue(mapExpectedOutputKeys).as().GetAsVectorView(); + auto expectedOutputValues = + OrtValueHelpers::LoadTensorFromOrtValue(mapExpectedOutputValues).as().GetAsVectorView(); for (uint32_t i = 0; i < expectedOutputKeys.Size(); i++) { expectedKvp[expectedOutputKeys.GetAt(i)] = expectedOutputValues.GetAt(i); } @@ -67,4 +74,4 @@ bool CompareSequenceOfMapsStringToFloat( return true; } -} \ No newline at end of file +} // namespace CompareFeatureValuesHelper diff --git a/winml/test/model/compare_feature_value.h b/winml/test/model/compare_feature_value.h index 86924850e66aa..4733f3cbdc917 100644 --- a/winml/test/model/compare_feature_value.h +++ b/winml/test/model/compare_feature_value.h @@ -4,8 +4,10 @@ namespace CompareFeatureValuesHelper { bool CompareSequenceOfMapsStringToFloat( - winrt::Windows::Foundation::Collections::IVectorView> featureValue, - const Ort::Value& val, - double per_sample_tolerance, - double relative_per_sample_tolerance); -} \ No newline at end of file + winrt::Windows::Foundation::Collections::IVectorView< + winrt::Windows::Foundation::Collections::IMap> featureValue, + const Ort::Value& val, + double per_sample_tolerance, + double relative_per_sample_tolerance +); +} diff --git a/winml/test/model/model_tests.cpp b/winml/test/model/model_tests.cpp index 613032a96692b..0b4c10eac9142 100644 --- a/winml/test/model/model_tests.cpp +++ b/winml/test/model/model_tests.cpp @@ -1,4 +1,5 @@ #include "testPch.h" +#include #include "test/onnx/TestCase.h" #include "test/onnx/heap_buffer.h" #include "test/util/include/test/compare_ortvalue.h" @@ -68,10 +69,11 @@ class ModelTest : public testing::TestWithParam& expectedOutputFeeds, - const IVectorView& outputFeatureDescriptors) { + void CompareEvaluationResults( + LearningModelEvaluationResult& results, + std::unordered_map& expectedOutputFeeds, + const IVectorView& outputFeatureDescriptors + ) { for (const auto& [name, value] : expectedOutputFeeds) { // Extract the output buffer from the evaluation output std::wstring outputName = _winml::Strings::WStringFromString(name); @@ -92,16 +94,17 @@ class ModelTest : public testing::TestWithParam(); Ort::Value actualOutput = OrtValueHelpers::CreateOrtValueFromITensor(actualOutputTensorValue); // Use the expected and actual OrtValues to compare - std::pair ret = CompareOrtValue(*actualOutput, *value, m_absolutePerSampleTolerance, m_relativePerSampleTolerance, m_postProcessing); + std::pair ret = CompareOrtValue( + *actualOutput, *value, m_absolutePerSampleTolerance, m_relativePerSampleTolerance, m_postProcessing + ); WINML_EXPECT_EQUAL(COMPARE_RESULT::SUCCESS, ret.first) << ret.second; } else if (outputDescriptor.Kind() == LearningModelFeatureKind::Sequence) { - auto sequenceOfMapsStringToFloat = results.Outputs().Lookup(outputName).try_as>>(); + auto sequenceOfMapsStringToFloat = + results.Outputs().Lookup(outputName).try_as>>(); if (sequenceOfMapsStringToFloat != nullptr) { WINML_EXPECT_TRUE(CompareFeatureValuesHelper::CompareSequenceOfMapsStringToFloat( - sequenceOfMapsStringToFloat, - value, - m_absolutePerSampleTolerance, - m_relativePerSampleTolerance)); + sequenceOfMapsStringToFloat, value, m_absolutePerSampleTolerance, m_relativePerSampleTolerance + )); } else { throw winrt::hresult_not_implemented(L"This particular type of sequence output hasn't been handled yet."); } @@ -145,7 +148,8 @@ TEST_P(ModelTest, Run) { // Get the path of the model test collateral. Will return empty string if it doesn't exist. std::string GetTestDataPath() { std::string testDataPath(MAX_PATH, '\0'); - auto environmentVariableFetchSuceeded = GetEnvironmentVariableA("WINML_TEST_DATA_PATH", testDataPath.data(), MAX_PATH); + auto environmentVariableFetchSuceeded = + GetEnvironmentVariableA("WINML_TEST_DATA_PATH", testDataPath.data(), MAX_PATH); if (environmentVariableFetchSuceeded == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND || environmentVariableFetchSuceeded > MAX_PATH) { // if the WINML_TEST_DATA_PATH environment variable cannot be found, attempt to find the hardcoded models folder std::wstring modulePath = FileHelpers::GetModulePath(); @@ -155,18 +159,20 @@ std::string GetTestDataPath() { if (std::filesystem::exists(hardcodedModelPath) && hardcodedModelPath.length() <= MAX_PATH) { return hardcodedModelPath; } else { - std::string errorStr = "WINML_TEST_DATA_PATH environment variable path not found and \"models\" folder not found in same directory as test exe.\n"; + std::string errorStr = + "WINML_TEST_DATA_PATH environment variable path not found and \"models\" folder not found in same directory as test exe.\n"; std::cerr << errorStr; throw std::exception(errorStr.c_str()); } } const std::string testDataPathFolderName = "\\testData\\"; if (MAX_PATH - environmentVariableFetchSuceeded >= testDataPathFolderName.length()) { - testDataPath.replace(environmentVariableFetchSuceeded, - testDataPathFolderName.length(), - testDataPathFolderName); + testDataPath.replace(environmentVariableFetchSuceeded, testDataPathFolderName.length(), testDataPathFolderName); } else { - throw std::exception("WINML_TEST_DATA_PATH environment variable path needs to be shorter to accomodate the maximum path size of %d\n", MAX_PATH); + throw std::exception( + "WINML_TEST_DATA_PATH environment variable path needs to be shorter to accomodate the maximum path size of %d\n", + MAX_PATH + ); } return testDataPath; } @@ -178,7 +184,8 @@ static std::vector GetAllTestCases() { std::unordered_set> allDisabledTests; std::vector> dataDirs; auto testDataPath = GetTestDataPath(); - if (testDataPath == "") return tests; + if (testDataPath == "") + return tests; for (auto& p : std::filesystem::directory_iterator(testDataPath.c_str())) { if (p.is_directory()) { @@ -186,59 +193,61 @@ static std::vector GetAllTestCases() { } } - #if !defined(__amd64__) && !defined(_M_AMD64) +#if !defined(__amd64__) && !defined(_M_AMD64) // Should match "x86_disabled_tests" in onnxruntime/test/providers/cpu/model_tests.cc // However there are more tests skipped. TODO: bugs must be filed for difference in models. static const ORTCHAR_T* x86DisabledTests[] = { - ORT_TSTR("BERT_Squad"), - ORT_TSTR("bvlc_reference_rcnn_ilsvrc13"), - ORT_TSTR("bvlc_reference_caffenet"), - ORT_TSTR("bvlc_alexnet"), - ORT_TSTR("coreml_AgeNet_ImageNet"), - ORT_TSTR("coreml_Resnet50"), - ORT_TSTR("coreml_VGG16_ImageNet"), - ORT_TSTR("faster_rcnn"), - ORT_TSTR("fp16_test_tiny_yolov2"), - ORT_TSTR("GPT2"), - ORT_TSTR("GPT2_LM_HEAD"), - ORT_TSTR("keras_lotus_resnet3D"), - ORT_TSTR("keras2coreml_Dense_ImageNet"), - ORT_TSTR("mask_rcnn_keras"), - ORT_TSTR("mask_rcnn"), - ORT_TSTR("mlperf_ssd_resnet34_1200"), - ORT_TSTR("resnet50"), - ORT_TSTR("resnet50v2"), - ORT_TSTR("resnet152v2"), - ORT_TSTR("resnet101v2"), - ORT_TSTR("resnet34v2"), - ORT_TSTR("roberta_sequence_classification"), - ORT_TSTR("ssd"), - ORT_TSTR("tf_inception_resnet_v2"), - ORT_TSTR("tf_inception_v4"), - ORT_TSTR("tf_nasnet_large"), - ORT_TSTR("tf_pnasnet_large"), - ORT_TSTR("tf_resnet_v1_50"), - ORT_TSTR("tf_resnet_v1_101"), - ORT_TSTR("tf_resnet_v1_152"), - ORT_TSTR("tf_resnet_v2_50"), - ORT_TSTR("tf_resnet_v2_101"), - ORT_TSTR("tf_resnet_v2_152"), - ORT_TSTR("vgg19"), - ORT_TSTR("yolov3"), - ORT_TSTR("zfnet512") - }; + ORT_TSTR("BERT_Squad"), + ORT_TSTR("bvlc_reference_rcnn_ilsvrc13"), + ORT_TSTR("bvlc_reference_caffenet"), + ORT_TSTR("bvlc_alexnet"), + ORT_TSTR("coreml_AgeNet_ImageNet"), + ORT_TSTR("coreml_Resnet50"), + ORT_TSTR("coreml_VGG16_ImageNet"), + ORT_TSTR("faster_rcnn"), + ORT_TSTR("fp16_test_tiny_yolov2"), + ORT_TSTR("GPT2"), + ORT_TSTR("GPT2_LM_HEAD"), + ORT_TSTR("keras_lotus_resnet3D"), + ORT_TSTR("keras2coreml_Dense_ImageNet"), + ORT_TSTR("mask_rcnn_keras"), + ORT_TSTR("mask_rcnn"), + ORT_TSTR("mlperf_ssd_resnet34_1200"), + ORT_TSTR("resnet50"), + ORT_TSTR("resnet50v2"), + ORT_TSTR("resnet152v2"), + ORT_TSTR("resnet101v2"), + ORT_TSTR("resnet34v2"), + ORT_TSTR("roberta_sequence_classification"), + ORT_TSTR("ssd"), + ORT_TSTR("tf_inception_resnet_v2"), + ORT_TSTR("tf_inception_v4"), + ORT_TSTR("tf_nasnet_large"), + ORT_TSTR("tf_pnasnet_large"), + ORT_TSTR("tf_resnet_v1_50"), + ORT_TSTR("tf_resnet_v1_101"), + ORT_TSTR("tf_resnet_v1_152"), + ORT_TSTR("tf_resnet_v2_50"), + ORT_TSTR("tf_resnet_v2_101"), + ORT_TSTR("tf_resnet_v2_152"), + ORT_TSTR("vgg19"), + ORT_TSTR("yolov3"), + ORT_TSTR("zfnet512")}; allDisabledTests.insert(std::begin(x86DisabledTests), std::end(x86DisabledTests)); #endif -// Bad onnx test output caused by previously wrong SAME_UPPER/SAME_LOWER for ConvTranspose -allDisabledTests.insert(ORT_TSTR("cntk_simple_seg")); - - - WINML_EXPECT_NO_THROW(LoadTests(dataDirs, whitelistedTestCases, TestTolerances(1e-3, 1e-3, {}, {}), - allDisabledTests, - [&tests](std::unique_ptr l) { - tests.push_back(l.get()); - ownedTests.push_back(std::move(l)); - })); + // Bad onnx test output caused by previously wrong SAME_UPPER/SAME_LOWER for ConvTranspose + allDisabledTests.insert(ORT_TSTR("cntk_simple_seg")); + + WINML_EXPECT_NO_THROW(LoadTests( + dataDirs, + whitelistedTestCases, + TestTolerances(1e-3, 1e-3, {}, {}), + allDisabledTests, + [&tests](std::unique_ptr l) { + tests.push_back(l.get()); + ownedTests.push_back(std::move(l)); + } + )); return tests; } @@ -264,8 +273,9 @@ bool ShouldSkipTestOnGpuAdapterDxgi(std::string& testName) { std::string regex = disabledGpuAdapterTests[testName].first; std::wstring adapterDescription = pDesc.Description; return std::regex_search( - _winml::Strings::UTF8FromUnicode(adapterDescription.c_str(), adapterDescription.length()), - std::regex(regex, std::regex_constants::icase | std::regex_constants::nosubs)); + _winml::Strings::UTF8FromUnicode(adapterDescription.c_str(), adapterDescription.length()), + std::regex(regex, std::regex_constants::icase | std::regex_constants::nosubs) + ); } spAdapter = nullptr; i++; @@ -296,10 +306,12 @@ bool ShouldSkipTestOnGpuAdapterDxcore(std::string& testName) { // Found an adapter that is not WARP. This is the adapter that will be used by WinML. std::string regex = disabledGpuAdapterTests[testName].first; std::string adapterDescription; - WINML_EXPECT_HRESULT_SUCCEEDED(spCurrAdapter->GetProperty(DXCoreAdapterProperty::DriverDescription, &adapterDescription)); + WINML_EXPECT_HRESULT_SUCCEEDED( + spCurrAdapter->GetProperty(DXCoreAdapterProperty::DriverDescription, &adapterDescription) + ); return std::regex_search( - adapterDescription, - std::regex(regex, std::regex_constants::icase | std::regex_constants::nosubs)); + adapterDescription, std::regex(regex, std::regex_constants::icase | std::regex_constants::nosubs) + ); } } // If no adapters can be enumerated or none of them are hardware, might as well skip this test @@ -371,11 +383,13 @@ std::string GetFullNameOfTest(ITestCase* testCase, winml::LearningModelDeviceKin // To introduce models from model zoo, the model path is structured like this "///?.onnx" std::string source = tokenizedModelPath[tokenizedModelPath.size() - 4]; // `models` means the root of models, to be ompatible with the old structure, that is, the source name is empty. - if (source != "models"){ + if (source != "models") { name += "_" + source; } - std::replace_if(name.begin(), name.end(), [](char c) { return !google::protobuf::ascii_isalnum(c); }, '_'); + std::replace_if( + name.begin(), name.end(), [](char c) { return !absl::ascii_isalnum(c); }, '_' + ); // Determine if test should be skipped, using the generic name (no CPU or GPU suffix yet). bool isDisabled = ModifyNameIfDisabledTest(/*inout*/ name, deviceKind); @@ -387,8 +401,7 @@ std::string GetFullNameOfTest(ITestCase* testCase, winml::LearningModelDeviceKin } // Check once more with the full name, lest any GPU-specific/CPU-specific cases exist. - if (!isDisabled) - { + if (!isDisabled) { ModifyNameIfDisabledTest(/*inout*/ name, deviceKind); } @@ -400,6 +413,13 @@ static std::string GetNameOfTestFromTestParam(const testing::TestParamInfo(info.param), std::get<1>(info.param)); } -INSTANTIATE_TEST_SUITE_P(ModelTests, ModelTest, testing::Combine(testing::ValuesIn(GetAllTestCases()), testing::Values(winml::LearningModelDeviceKind::Cpu, winml::LearningModelDeviceKind::DirectX)), - GetNameOfTestFromTestParam); +INSTANTIATE_TEST_SUITE_P( + ModelTests, + ModelTest, + testing::Combine( + testing::ValuesIn(GetAllTestCases()), + testing::Values(winml::LearningModelDeviceKind::Cpu, winml::LearningModelDeviceKind::DirectX) + ), + GetNameOfTestFromTestParam +); } // namespace WinML diff --git a/winml/test/model/ort_value_helper.cpp b/winml/test/model/ort_value_helper.cpp index 3a2de243092c0..2586fadfbb4d9 100644 --- a/winml/test/model/ort_value_helper.cpp +++ b/winml/test/model/ort_value_helper.cpp @@ -6,8 +6,7 @@ using namespace winrt::Windows::Foundation::Collections; namespace OrtValueHelpers { template -winml::ITensor CreateTensorFromShape(std::vector& shape) -{ +winml::ITensor CreateTensorFromShape(std::vector& shape) { using WinMLTensorKind = typename ONNXTensorElementDataTypeToWinMLTensorKind::Type; ITensor tensor = nullptr; WINML_EXPECT_NO_THROW(tensor = WinMLTensorKind::Create(shape)); @@ -45,25 +44,24 @@ winml::ITensor CreateStringTensor(Ort::Value& val) { WINML_EXPECT_NO_THROW(val.GetStringTensorContent(buffer.get(), bufferLength, offsets.data(), offsets.size())); - // now go build all the strings + // now go build all the strings for (size_t i = 0; i < length; ++i) { size_t strLength = 0; // are we on the last one? if (i == (length - 1)) { strLength = bufferLength - offsets[i]; } else { - strLength = offsets[i+1] - offsets[i]; + strLength = offsets[i + 1] - offsets[i]; } auto strView = std::string_view(reinterpret_cast(buffer.get() + offsets[i]), strLength); strings.push_back(_winml::Strings::HStringFromUTF8(strView.data(), strLength)); } - TensorString tensor = nullptr; + TensorString tensor = nullptr; WINML_EXPECT_NO_THROW(tensor = TensorString::CreateFromShapeArrayAndDataArray(shape, strings)); return tensor; } - // This function takes in an Ort::Value and returns a copy of winml::ITensor // TODO: String types still need to be implemented. winml::ITensor LoadTensorFromOrtValue(Ort::Value& val) { @@ -138,7 +136,7 @@ winml::ITensor LoadTensorFromOrtValue(Ort::Value& val) { } static ONNXTensorElementDataType OnnxTensorTypeFromWinMLType(winml::TensorKind tensorKind) { - switch (tensorKind) { + switch (tensorKind) { case (TensorKind::Float): return ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT; case (TensorKind::UInt8): @@ -187,21 +185,22 @@ Ort::Value CreateOrtValueFromITensor(winml::ITensor winmlTensor) { uint32_t actualSizeInBytes; WINML_EXPECT_HRESULT_SUCCEEDED(winmlTensorNative->GetBuffer(&actualData, &actualSizeInBytes)); WINML_EXPECT_NO_THROW( - ortValueCreated = Ort::Value::CreateTensor( - memoryInfo, - actualData, - actualSizeInBytes, - shape.data(), - shape.size(), - OnnxTensorTypeFromWinMLType(winmlTensor.TensorKind()))); + ortValueCreated = Ort::Value::CreateTensor( + memoryInfo, + actualData, + actualSizeInBytes, + shape.data(), + shape.size(), + OnnxTensorTypeFromWinMLType(winmlTensor.TensorKind()) + ) + ); } else { Ort::AllocatorWithDefaultOptions allocator; WINML_EXPECT_NO_THROW( - ortValueCreated = Ort::Value::CreateTensor( - allocator, - shape.data(), - shape.size(), - ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING)); + ortValueCreated = Ort::Value::CreateTensor( + allocator, shape.data(), shape.size(), ONNXTensorElementDataType::ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING + ) + ); std::vector strData; std::vector utf8Strs; auto strValues = winmlTensor.as().GetAsVectorView(); @@ -213,4 +212,4 @@ Ort::Value CreateOrtValueFromITensor(winml::ITensor winmlTensor) { } return ortValueCreated; } -} // namespace OrtValueHelpers \ No newline at end of file +} // namespace OrtValueHelpers diff --git a/winml/test/model/ort_value_helper.h b/winml/test/model/ort_value_helper.h index fd96db9965107..b900a259c1694 100644 --- a/winml/test/model/ort_value_helper.h +++ b/winml/test/model/ort_value_helper.h @@ -5,7 +5,7 @@ namespace OrtValueHelpers { winml::ITensor LoadTensorFromOrtValue(Ort::Value& val); Ort::Value CreateOrtValueFromITensor(winml::ITensor winmlTensor); -} +} // namespace OrtValueHelpers template struct ONNXTensorElementDataTypeToWinMLTensorKind { @@ -81,4 +81,4 @@ struct ONNXTensorElementDataTypeToWinMLTensorKind struct ONNXTensorElementDataTypeToWinMLTensorKind { typedef winml::TensorFloat16Bit Type; -}; \ No newline at end of file +}; diff --git a/winml/test/model/skip_model_tests.h b/winml/test/model/skip_model_tests.h index cd0f34a204f2b..174f57143ee81 100644 --- a/winml/test/model/skip_model_tests.h +++ b/winml/test/model/skip_model_tests.h @@ -2,165 +2,169 @@ #include "common.h" //Need to file bugs for failing tests and add to reason. Before that happens, default reasons will be used. -static const std::string disabledTestDefaultReason = "Model not working on CPU and GPU. Please file bug and replace this reason message."; -static const std::string disabledGpuTestDefaultReason = "Model not working on GPU. Please file bug and replace this reason message."; +static const std::string disabledTestDefaultReason = + "Model not working on CPU and GPU. Please file bug and replace this reason message."; +static const std::string disabledGpuTestDefaultReason = + "Model not working on GPU. Please file bug and replace this reason message."; // {"model test name", "reason for why it is happening and bug filed for it."} -std::unordered_map disabledTests( - { - // Disabled cases common to both CPU&GPU (no _CPU/_GPU suffix): +std::unordered_map disabledTests({ + // Disabled cases common to both CPU&GPU (no _CPU/_GPU suffix): - // Tier 3 models - {"mxnet_arcface_opset8", disabledTestDefaultReason}, - {"XGBoost_XGClassifier_sklearn_load_wine_opset7", disabledTestDefaultReason}, - {"XGBoost_XGClassifier_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, - {"XGBoost_XGClassifier_OpenML_312_scene_opset7", disabledTestDefaultReason}, - {"XGBoost_XGClassifier_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, - {"scikit_SVC_sklearn_load_wine_opset7", disabledTestDefaultReason}, - {"scikit_SVC_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, - {"scikit_SVC_OpenML_312_scene_opset7", disabledTestDefaultReason}, - {"scikit_SVC_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, - {"scikit_Scaler_LogisticRegression_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, - {"scikit_Scaler_LogisticRegression_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, - {"scikit_RandomForestClassifier_sklearn_load_wine_opset7", disabledTestDefaultReason}, - {"scikit_RandomForestClassifier_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, - {"scikit_RandomForestClassifier_OpenML_312_scene_opset7", disabledTestDefaultReason}, - {"scikit_Nu_SVC_sklearn_load_wine_opset7", disabledTestDefaultReason}, - {"scikit_Nu_SVC_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, - {"scikit_Nu_SVC_OpenML_312_scene_opset7", disabledTestDefaultReason}, - {"scikit_Nu_SVC_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, - {"scikit_Normalizer_RandomForestClassifier_sklearn_load_wine_opset7", disabledTestDefaultReason}, - {"scikit_Normalizer_LinearSVC_sklearn_load_wine_opset7", disabledTestDefaultReason}, - {"scikit_LogisticRegression_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, - {"scikit_LogisticRegression_OpenML_31_credit_opset7", disabledTestDefaultReason}, - {"scikit_LogisticRegression_OpenML_312_scene_opset7", disabledTestDefaultReason}, - {"scikit_LogisticRegression_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, - {"scikit_LinearSVC_sklearn_load_wine_opset7", disabledTestDefaultReason}, - {"scikit_LabelEncoder_OpenML_3_chess_opset7", disabledTestDefaultReason}, - {"scikit_LabelEncoder_BikeSharing_opset7", disabledTestDefaultReason}, - {"scikit_Imputer_LogisticRegression_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, - {"scikit_Imputer_LogisticRegression_OpenML_1464_blood_transfusion_missing_opset7", disabledTestDefaultReason}, - {"scikit_Imputer_GradientBoostingClassifier_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, - {"scikit_Imputer_GradientBoostingClassifier_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, - {"scikit_GradientBoostingClassifier_sklearn_load_wine_opset7", disabledTestDefaultReason}, - {"scikit_GradientBoostingClassifier_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, - {"scikit_GradientBoostingClassifier_OpenML_312_scene_opset7", disabledTestDefaultReason}, - {"scikit_GradientBoostingClassifier_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, - {"scikit_DictVectorizer_sklearn_load_Iris_missing_opset7", disabledTestDefaultReason}, - {"scikit_DictVectorizer_sklearn_load_digits_opset7", disabledTestDefaultReason}, - {"scikit_DictVectorizer_sklearn_load_diabetes_missing_opset7", disabledTestDefaultReason}, - {"scikit_DictVectorizer_OpenML_31_credit_opset7", disabledTestDefaultReason}, - {"scikit_DictVectorizer_RandomForestRegressor_sklearn_load_diabetes_opset7", disabledTestDefaultReason}, - {"scikit_DictVectorizer_RandomForestClassifier_sklearn_load_wine_opset7", disabledTestDefaultReason}, - {"scikit_DictVectorizer_LinearSVC_sklearn_load_wine_opset7", disabledTestDefaultReason}, - {"scikit_DictVectorizer_LinearRegression_sklearn_load_diabetes_opset7", disabledTestDefaultReason}, - {"scikit_DictVectorizer_GradientBoostingRegressor_sklearn_load_boston_opset7", disabledTestDefaultReason}, - {"scikit_DecisionTreeClassifier_sklearn_load_wine_opset7", disabledTestDefaultReason}, - {"scikit_DecisionTreeClassifier_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, - {"scikit_DecisionTreeClassifier_OpenML_312_scene_opset7", disabledTestDefaultReason}, - {"scikit_DecisionTreeClassifier_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, - {"scikit_Binarization_DecisionTreeClassifier_OpenML_1492_plants_opset7", disabledTestDefaultReason}, - {"scikit_Binarization_DecisionTreeClassifier_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, - {"libsvm_Nu_SVC_sklearn_load_wine_opset7", disabledTestDefaultReason}, - {"libsvm_Nu_SVC_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, - {"libsvm_Nu_SVC_OpenML_312_scene_opset7", disabledTestDefaultReason}, - {"libsvm_Nu_SVC_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, - {"coreml_VGG16_ImageNet_opset7", disabledTestDefaultReason}, - {"coreml_SVC_sklearn_load_wine_opset7", disabledTestDefaultReason}, - {"coreml_SVC_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, - {"coreml_SVC_OpenML_312_scene_opset7", disabledTestDefaultReason}, - {"coreml_SVC_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, - {"coreml_SqueezeNet_ImageNet_opset7", disabledTestDefaultReason}, - {"coreml_Scaler_LogisticRegression_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, - {"coreml_Scaler_LogisticRegression_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, - {"coreml_Resnet50_ImageNet_opset7", disabledTestDefaultReason}, - {"coreml_RandomForestClassifier_sklearn_load_wine_opset7", disabledTestDefaultReason}, - {"coreml_RandomForestClassifier_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, - {"coreml_RandomForestClassifier_OpenML_312_scene_opset7", disabledTestDefaultReason}, - {"coreml_RandomForestClassifier_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, - {"coreml_Normalizer_RandomForestClassifier_sklearn_load_wine_opset7", disabledTestDefaultReason}, - {"coreml_Normalizer_LinearSVC_sklearn_load_wine_opset7", disabledTestDefaultReason}, - {"coreml_LogisticRegression_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, - {"coreml_LogisticRegression_OpenML_31_credit_opset7", disabledTestDefaultReason}, - {"coreml_LogisticRegression_OpenML_312_scene_opset7", disabledTestDefaultReason}, - {"coreml_LogisticRegression_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, - {"coreml_LinearSVC_sklearn_load_wine_opset7", disabledTestDefaultReason}, - {"coreml_LinearSVC_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, - {"coreml_LinearSVC_OpenML_312_scene_opset7", disabledTestDefaultReason}, - {"coreml_LinearSVC_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, - {"coreml_Inceptionv3_ImageNet_opset7", disabledTestDefaultReason}, - {"coreml_Imputer_LogisticRegression_OpenML_1464_blood_transfusion_missing_opset7", disabledTestDefaultReason}, - {"coreml_Imputer_GradientBoostingClassifier_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, - {"coreml_Imputer_GradientBoostingClassifier_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, - {"coreml_GradientBoostingClassifier_sklearn_load_wine_opset7", disabledTestDefaultReason}, - {"coreml_GradientBoostingClassifier_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, - {"coreml_GradientBoostingClassifier_OpenML_312_scene_opset7", disabledTestDefaultReason}, - {"coreml_GradientBoostingClassifier_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, - {"coreml_GradientBoostingClassifier_Criteo_opset7", disabledTestDefaultReason}, - {"coreml_GradientBoostingClassifier_BingClick_opset7", disabledTestDefaultReason}, - {"coreml_DictVectorizer_sklearn_load_Iris_missing_opset7", disabledTestDefaultReason}, - {"coreml_DictVectorizer_sklearn_load_digits_opset7", disabledTestDefaultReason}, - {"coreml_DictVectorizer_sklearn_load_diabetes_missing_opset7", disabledTestDefaultReason}, - {"coreml_DictVectorizer_OpenML_31_credit_opset7", disabledTestDefaultReason}, - {"coreml_DictVectorizer_RandomForestRegressor_sklearn_load_diabetes_opset7", disabledTestDefaultReason}, - {"coreml_DictVectorizer_RandomForestClassifier_sklearn_load_wine_opset7", disabledTestDefaultReason}, - {"coreml_DictVectorizer_LinearSVC_sklearn_load_wine_opset7", disabledTestDefaultReason}, - {"coreml_DictVectorizer_LinearRegression_sklearn_load_diabetes_opset7", disabledTestDefaultReason}, - {"coreml_DictVectorizer_GradientBoostingRegressor_sklearn_load_boston_opset7", disabledTestDefaultReason}, - {"coreml_DecisionTreeClassifier_sklearn_load_wine_opset7", disabledTestDefaultReason}, - {"coreml_DecisionTreeClassifier_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, - {"coreml_DecisionTreeClassifier_OpenML_312_scene_opset7", disabledTestDefaultReason}, - {"coreml_DecisionTreeClassifier_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, - {"coreml_AgeNet_ImageNet_opset7", disabledTestDefaultReason}, + // Tier 3 models + { "mxnet_arcface_opset8", disabledTestDefaultReason }, + { "XGBoost_XGClassifier_sklearn_load_wine_opset7", disabledTestDefaultReason}, + { "XGBoost_XGClassifier_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, + { "XGBoost_XGClassifier_OpenML_312_scene_opset7", disabledTestDefaultReason}, + { "XGBoost_XGClassifier_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, + { "scikit_SVC_sklearn_load_wine_opset7", disabledTestDefaultReason}, + { "scikit_SVC_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, + { "scikit_SVC_OpenML_312_scene_opset7", disabledTestDefaultReason}, + { "scikit_SVC_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, + { "scikit_Scaler_LogisticRegression_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, + { "scikit_Scaler_LogisticRegression_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, + { "scikit_RandomForestClassifier_sklearn_load_wine_opset7", disabledTestDefaultReason}, + { "scikit_RandomForestClassifier_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, + { "scikit_RandomForestClassifier_OpenML_312_scene_opset7", disabledTestDefaultReason}, + { "scikit_Nu_SVC_sklearn_load_wine_opset7", disabledTestDefaultReason}, + { "scikit_Nu_SVC_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, + { "scikit_Nu_SVC_OpenML_312_scene_opset7", disabledTestDefaultReason}, + { "scikit_Nu_SVC_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, + { "scikit_Normalizer_RandomForestClassifier_sklearn_load_wine_opset7", disabledTestDefaultReason}, + { "scikit_Normalizer_LinearSVC_sklearn_load_wine_opset7", disabledTestDefaultReason}, + { "scikit_LogisticRegression_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, + { "scikit_LogisticRegression_OpenML_31_credit_opset7", disabledTestDefaultReason}, + { "scikit_LogisticRegression_OpenML_312_scene_opset7", disabledTestDefaultReason}, + { "scikit_LogisticRegression_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, + { "scikit_LinearSVC_sklearn_load_wine_opset7", disabledTestDefaultReason}, + { "scikit_LabelEncoder_OpenML_3_chess_opset7", disabledTestDefaultReason}, + { "scikit_LabelEncoder_BikeSharing_opset7", disabledTestDefaultReason}, + { "scikit_Imputer_LogisticRegression_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, + { "scikit_Imputer_LogisticRegression_OpenML_1464_blood_transfusion_missing_opset7", disabledTestDefaultReason}, + { "scikit_Imputer_GradientBoostingClassifier_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, + { "scikit_Imputer_GradientBoostingClassifier_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, + { "scikit_GradientBoostingClassifier_sklearn_load_wine_opset7", disabledTestDefaultReason}, + { "scikit_GradientBoostingClassifier_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, + { "scikit_GradientBoostingClassifier_OpenML_312_scene_opset7", disabledTestDefaultReason}, + { "scikit_GradientBoostingClassifier_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, + { "scikit_DictVectorizer_sklearn_load_Iris_missing_opset7", disabledTestDefaultReason}, + { "scikit_DictVectorizer_sklearn_load_digits_opset7", disabledTestDefaultReason}, + { "scikit_DictVectorizer_sklearn_load_diabetes_missing_opset7", disabledTestDefaultReason}, + { "scikit_DictVectorizer_OpenML_31_credit_opset7", disabledTestDefaultReason}, + { "scikit_DictVectorizer_RandomForestRegressor_sklearn_load_diabetes_opset7", disabledTestDefaultReason}, + { "scikit_DictVectorizer_RandomForestClassifier_sklearn_load_wine_opset7", disabledTestDefaultReason}, + { "scikit_DictVectorizer_LinearSVC_sklearn_load_wine_opset7", disabledTestDefaultReason}, + { "scikit_DictVectorizer_LinearRegression_sklearn_load_diabetes_opset7", disabledTestDefaultReason}, + { "scikit_DictVectorizer_GradientBoostingRegressor_sklearn_load_boston_opset7", disabledTestDefaultReason}, + { "scikit_DecisionTreeClassifier_sklearn_load_wine_opset7", disabledTestDefaultReason}, + { "scikit_DecisionTreeClassifier_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, + { "scikit_DecisionTreeClassifier_OpenML_312_scene_opset7", disabledTestDefaultReason}, + { "scikit_DecisionTreeClassifier_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, + { "scikit_Binarization_DecisionTreeClassifier_OpenML_1492_plants_opset7", disabledTestDefaultReason}, + {"scikit_Binarization_DecisionTreeClassifier_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, + { "libsvm_Nu_SVC_sklearn_load_wine_opset7", disabledTestDefaultReason}, + { "libsvm_Nu_SVC_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, + { "libsvm_Nu_SVC_OpenML_312_scene_opset7", disabledTestDefaultReason}, + { "libsvm_Nu_SVC_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, + { "coreml_VGG16_ImageNet_opset7", disabledTestDefaultReason}, + { "coreml_SVC_sklearn_load_wine_opset7", disabledTestDefaultReason}, + { "coreml_SVC_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, + { "coreml_SVC_OpenML_312_scene_opset7", disabledTestDefaultReason}, + { "coreml_SVC_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, + { "coreml_SqueezeNet_ImageNet_opset7", disabledTestDefaultReason}, + { "coreml_Scaler_LogisticRegression_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, + { "coreml_Scaler_LogisticRegression_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, + { "coreml_Resnet50_ImageNet_opset7", disabledTestDefaultReason}, + { "coreml_RandomForestClassifier_sklearn_load_wine_opset7", disabledTestDefaultReason}, + { "coreml_RandomForestClassifier_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, + { "coreml_RandomForestClassifier_OpenML_312_scene_opset7", disabledTestDefaultReason}, + { "coreml_RandomForestClassifier_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, + { "coreml_Normalizer_RandomForestClassifier_sklearn_load_wine_opset7", disabledTestDefaultReason}, + { "coreml_Normalizer_LinearSVC_sklearn_load_wine_opset7", disabledTestDefaultReason}, + { "coreml_LogisticRegression_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, + { "coreml_LogisticRegression_OpenML_31_credit_opset7", disabledTestDefaultReason}, + { "coreml_LogisticRegression_OpenML_312_scene_opset7", disabledTestDefaultReason}, + { "coreml_LogisticRegression_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, + { "coreml_LinearSVC_sklearn_load_wine_opset7", disabledTestDefaultReason}, + { "coreml_LinearSVC_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, + { "coreml_LinearSVC_OpenML_312_scene_opset7", disabledTestDefaultReason}, + { "coreml_LinearSVC_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, + { "coreml_Inceptionv3_ImageNet_opset7", disabledTestDefaultReason}, + { "coreml_Imputer_LogisticRegression_OpenML_1464_blood_transfusion_missing_opset7", disabledTestDefaultReason}, + { "coreml_Imputer_GradientBoostingClassifier_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, + { "coreml_Imputer_GradientBoostingClassifier_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, + { "coreml_GradientBoostingClassifier_sklearn_load_wine_opset7", disabledTestDefaultReason}, + { "coreml_GradientBoostingClassifier_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, + { "coreml_GradientBoostingClassifier_OpenML_312_scene_opset7", disabledTestDefaultReason}, + { "coreml_GradientBoostingClassifier_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, + { "coreml_GradientBoostingClassifier_Criteo_opset7", disabledTestDefaultReason}, + { "coreml_GradientBoostingClassifier_BingClick_opset7", disabledTestDefaultReason}, + { "coreml_DictVectorizer_sklearn_load_Iris_missing_opset7", disabledTestDefaultReason}, + { "coreml_DictVectorizer_sklearn_load_digits_opset7", disabledTestDefaultReason}, + { "coreml_DictVectorizer_sklearn_load_diabetes_missing_opset7", disabledTestDefaultReason}, + { "coreml_DictVectorizer_OpenML_31_credit_opset7", disabledTestDefaultReason}, + { "coreml_DictVectorizer_RandomForestRegressor_sklearn_load_diabetes_opset7", disabledTestDefaultReason}, + { "coreml_DictVectorizer_RandomForestClassifier_sklearn_load_wine_opset7", disabledTestDefaultReason}, + { "coreml_DictVectorizer_LinearSVC_sklearn_load_wine_opset7", disabledTestDefaultReason}, + { "coreml_DictVectorizer_LinearRegression_sklearn_load_diabetes_opset7", disabledTestDefaultReason}, + { "coreml_DictVectorizer_GradientBoostingRegressor_sklearn_load_boston_opset7", disabledTestDefaultReason}, + { "coreml_DecisionTreeClassifier_sklearn_load_wine_opset7", disabledTestDefaultReason}, + { "coreml_DecisionTreeClassifier_sklearn_load_breast_cancer_opset7", disabledTestDefaultReason}, + { "coreml_DecisionTreeClassifier_OpenML_312_scene_opset7", disabledTestDefaultReason}, + { "coreml_DecisionTreeClassifier_OpenML_1464_blood_transfusion_opset7", disabledTestDefaultReason}, + { "coreml_AgeNet_ImageNet_opset7", disabledTestDefaultReason}, - // GPU specific cases: + // GPU specific cases: - // ONNX zoo models - {"mask_rcnn_opset10_GPU", "Bug 31005388: mask_rcnn opset 10 onnx zoo model fails to evaluate on DirectML https://microsoft.visualstudio.com/OS/_workitems/edit/31005388"}, - {"faster_rcnn_opset10_GPU", "Bug 31005511: Failed to extract tensor data from evaluate result of faster_rcnn opset 10 model in DirectML https://microsoft.visualstudio.com/OS/_workitems/edit/31005511"}, - // ONNX model zoo's int8/qdq models generally do not work on CPUs that lack 8-bit instructions. - {"YOLOv3_12_int8_opset12", disabledTestDefaultReason}, - {"VGG_16_int8_opset12", disabledTestDefaultReason}, - {"SSD_int8_opset12", disabledTestDefaultReason}, - {"ShuffleNet_v2_qdq_opset12", disabledTestDefaultReason}, - {"ShuffleNet_v2_int8_opset12", disabledTestDefaultReason}, - {"ResNet50_qdq_opset12", disabledTestDefaultReason}, - {"ResNet50_int8_opset12", disabledTestDefaultReason}, - {"MobileNet_v2_1_0_qdq_opset12", disabledTestDefaultReason}, - {"MobileNet_v2_1_0_int8_opset12", disabledTestDefaultReason}, - {"Inception_1_int8_opset12", disabledTestDefaultReason}, - {"Faster_R_CNN_R_50_FPN_int8_opset12", disabledTestDefaultReason}, - {"BERT_Squad_int8_opset12", disabledTestDefaultReason}, - {"EfficientNet_Lite4_qdq_opset11", disabledTestDefaultReason}, - {"EfficientNet_Lite4_int8_opset11", disabledTestDefaultReason}, + // ONNX zoo models + { "mask_rcnn_opset10_GPU", + "Bug 31005388: mask_rcnn opset 10 onnx zoo model fails to evaluate on DirectML https://microsoft.visualstudio.com/OS/_workitems/edit/31005388" }, + { "faster_rcnn_opset10_GPU", + "Bug 31005511: Failed to extract tensor data from evaluate result of faster_rcnn opset 10 model in DirectML https://microsoft.visualstudio.com/OS/_workitems/edit/31005511" }, + // ONNX model zoo's int8/qdq models generally do not work on CPUs that lack 8-bit instructions. + { "YOLOv3_12_int8_opset12", disabledTestDefaultReason}, + { "VGG_16_int8_opset12", disabledTestDefaultReason}, + { "SSD_int8_opset12", disabledTestDefaultReason}, + { "ShuffleNet_v2_qdq_opset12", disabledTestDefaultReason}, + { "ShuffleNet_v2_int8_opset12", disabledTestDefaultReason}, + { "ResNet50_qdq_opset12", disabledTestDefaultReason}, + { "ResNet50_int8_opset12", disabledTestDefaultReason}, + { "MobileNet_v2_1_0_qdq_opset12", disabledTestDefaultReason}, + { "MobileNet_v2_1_0_int8_opset12", disabledTestDefaultReason}, + { "Inception_1_int8_opset12", disabledTestDefaultReason}, + { "Faster_R_CNN_R_50_FPN_int8_opset12", disabledTestDefaultReason}, + { "BERT_Squad_int8_opset12", disabledTestDefaultReason}, + { "EfficientNet_Lite4_qdq_opset11", disabledTestDefaultReason}, + { "EfficientNet_Lite4_int8_opset11", disabledTestDefaultReason}, - // Tier 2 models - {"fp16_test_tiny_yolov2_opset7_GPU", "Bug 31005780: Result of fp16_test_tiny_yolov2_opset7 and fp16_coreml_FNS_Candy_opset7 models on DirectML aren't as accurate as on CPU https://microsoft.visualstudio.com/OS/_workitems/edit/31005780"}, - {"fp16_tiny_yolov2_opset8_GPU", "Bug 31005780: Result of fp16_test_tiny_yolov2_opset7 and fp16_coreml_FNS_Candy_opset7 models on DirectML aren't as accurate as on CPU https://microsoft.visualstudio.com/OS/_workitems/edit/31005780"}, - {"fp16_coreml_FNS_Candy_opset7_GPU", "Bug 31005780: Result of fp16_test_tiny_yolov2_opset7 and fp16_coreml_FNS_Candy_opset7 models on DirectML aren't as accurate as on CPU https://microsoft.visualstudio.com/OS/_workitems/edit/31005780"}, - {"mlperf_ssd_mobilenet_300_opset10_GPU", "Bug 31005624: mlperf_ssd_mobilenet_300 opset 10 model fails to evaluate in DirectML https://microsoft.visualstudio.com/OS/_workitems/edit/31005624"}, - } -); + // Tier 2 models + { "fp16_test_tiny_yolov2_opset7_GPU", + "Bug 31005780: Result of fp16_test_tiny_yolov2_opset7 and fp16_coreml_FNS_Candy_opset7 models on DirectML aren't as accurate as on CPU https://microsoft.visualstudio.com/OS/_workitems/edit/31005780"}, + { "fp16_tiny_yolov2_opset8_GPU", + "Bug 31005780: Result of fp16_test_tiny_yolov2_opset7 and fp16_coreml_FNS_Candy_opset7 models on DirectML aren't as accurate as on CPU https://microsoft.visualstudio.com/OS/_workitems/edit/31005780"}, + { "fp16_coreml_FNS_Candy_opset7_GPU", + "Bug 31005780: Result of fp16_test_tiny_yolov2_opset7 and fp16_coreml_FNS_Candy_opset7 models on DirectML aren't as accurate as on CPU https://microsoft.visualstudio.com/OS/_workitems/edit/31005780"}, + { "mlperf_ssd_mobilenet_300_opset10_GPU", + "Bug 31005624: mlperf_ssd_mobilenet_300 opset 10 model fails to evaluate in DirectML https://microsoft.visualstudio.com/OS/_workitems/edit/31005624" }, +}); /* model name -> (adapter name regex, skipped test reason) */ -std::unordered_map> disabledGpuAdapterTests( - { - // e.g. {"fp16_inception_v1_opset7_GPU", std::make_pair("NVIDIA", "Bug 31144419: Results of fp16_inception_v1 opset7 and opset8 aren't accurate enough on AMD Radeon VII & Intel(R) UHD Graphics 630 & NVIDIA https://microsoft.visualstudio.com/OS/_workitems/edit/31144419")}, - // {"candy_opset9", std::make_pair("(Intel\\(R\\) (UHD )?Graphics)|(Adreno)", "Bug 31652854: Results of candy_opset9 aren't accurate enough on Intel Graphics and Qualcomm Adreno 685 https://microsoft.visualstudio.com/OS/_workitems/edit/31652854")}, - } -); +std::unordered_map> disabledGpuAdapterTests({ + // e.g. {"fp16_inception_v1_opset7_GPU", std::make_pair("NVIDIA", "Bug 31144419: Results of fp16_inception_v1 opset7 and opset8 aren't accurate enough on AMD Radeon VII & Intel(R) UHD Graphics 630 & NVIDIA https://microsoft.visualstudio.com/OS/_workitems/edit/31144419")}, + // {"candy_opset9", std::make_pair("(Intel\\(R\\) (UHD )?Graphics)|(Adreno)", "Bug 31652854: Results of candy_opset9 aren't accurate enough on Intel Graphics and Qualcomm Adreno 685 https://microsoft.visualstudio.com/OS/_workitems/edit/31652854")}, +}); /* Override the default tolerances for these test cases (can be tailored to only CPU or GPU with suffix). test name -> absolute difference sampleTolerance */ -std::unordered_map sampleTolerancePerTests( - { - {"fp16_inception_v1_opset7_GPU", 0.005}, - {"fp16_inception_v1_opset8_GPU", 0.005}, - {"candy_opset9_GPU", 0.00150000}, // Intel(R) UHD Graphics 630 (29.20.100.9020) AP machine has inaccurate GPU results for FNS Candy opset 9 https://microsoft.visualstudio.com/OS/_workitems/edit/30696168/ - {"fp16_tiny_yolov2_opset8_GPU", 0.109000}, // Intel(R) UHD Graphics 630 (29.20.100.9020) AP machine has inaccurate GPU results for FNS Candy opset 9 https://microsoft.visualstudio.com/OS/_workitems/edit/30696168/ - } -); +std::unordered_map sampleTolerancePerTests({ + {"fp16_inception_v1_opset7_GPU",0.005 }, + {"fp16_inception_v1_opset8_GPU", 0.005}, + { "candy_opset9_GPU", + 0.00150000 }, // Intel(R) UHD Graphics 630 (29.20.100.9020) AP machine has inaccurate GPU results for FNS Candy opset 9 https://microsoft.visualstudio.com/OS/_workitems/edit/30696168/ + { "fp16_tiny_yolov2_opset8_GPU", + 0.109000 }, // Intel(R) UHD Graphics 630 (29.20.100.9020) AP machine has inaccurate GPU results for FNS Candy opset 9 https://microsoft.visualstudio.com/OS/_workitems/edit/30696168/ +}); diff --git a/winml/test/scenario/cppwinrt/CustomNullOp.h b/winml/test/scenario/cppwinrt/CustomNullOp.h index 94e32b862ff32..33709c5f72d3c 100644 --- a/winml/test/scenario/cppwinrt/CustomNullOp.h +++ b/winml/test/scenario/cppwinrt/CustomNullOp.h @@ -10,98 +10,85 @@ #include "test.h" template -struct NullShapeInferrer : winrt::implements, IMLOperatorShapeInferrer> -{ - STDMETHOD(InferOutputShapes)(IMLOperatorShapeInferenceContext* context) noexcept - { - WINML_EXPECT_NO_THROW(OperatorHelper::ShapeInferenceFunction(context)); - return S_OK; - } +struct NullShapeInferrer : winrt::implements, IMLOperatorShapeInferrer> { + STDMETHOD(InferOutputShapes)(IMLOperatorShapeInferenceContext* context) noexcept { + WINML_EXPECT_NO_THROW(OperatorHelper::ShapeInferenceFunction(context)); + return S_OK; + } }; -struct NullOperator : winrt::implements -{ - NullOperator(std::atomic* callCount) : m_callCount(callCount) {} +struct NullOperator : winrt::implements { + NullOperator(std::atomic* callCount) : m_callCount(callCount) {} - STDMETHOD(Compute)(IMLOperatorKernelContext* context) - { - winrt::com_ptr outputTensor; - WINML_EXPECT_HRESULT_SUCCEEDED(context->GetOutputTensor(0, outputTensor.put())); + STDMETHOD(Compute)(IMLOperatorKernelContext* context) { + winrt::com_ptr outputTensor; + WINML_EXPECT_HRESULT_SUCCEEDED(context->GetOutputTensor(0, outputTensor.put())); - ++(*m_callCount); - return S_OK; - } + ++(*m_callCount); + return S_OK; + } -private: - std::atomic* m_callCount; + private: + std::atomic* m_callCount; }; -struct NullOperatorFactory : winrt::implements -{ - NullOperatorFactory(std::atomic* callCount) : m_callCount(callCount) {} - - STDMETHOD(CreateKernel)( - IMLOperatorKernelCreationContext* context, - IMLOperatorKernel** kernel) - { - ORT_UNUSED_PARAMETER(context); - auto op = winrt::make(m_callCount); - op.copy_to(kernel); - return S_OK; - } - - static MLOperatorEdgeDescription CreateEdgeDescriptor(MLOperatorEdgeType type, MLOperatorTensorDataType dataType) - { - ORT_UNUSED_PARAMETER(type); - MLOperatorEdgeDescription desc; - desc.edgeType = MLOperatorEdgeType::Tensor; - desc.tensorDataType = dataType; - return desc; - } - - static void RegisterKernel( - const char* name, - const char* domain, - int versionSince, - winrt::com_ptr registry, - winrt::com_ptr shapeInferrer, - std::atomic* callCount) - { - MLOperatorKernelDescription kernelDescription; - kernelDescription.domain = domain; - kernelDescription.name = name; - kernelDescription.minimumOperatorSetVersion = versionSince; - kernelDescription.executionType = MLOperatorExecutionType::D3D12; - - MLOperatorEdgeTypeConstrant typeConstraint; - typeConstraint.typeLabel = "T"; - std::vector allowedEdges - { - CreateEdgeDescriptor(MLOperatorEdgeType::Tensor, MLOperatorTensorDataType::Double), - CreateEdgeDescriptor(MLOperatorEdgeType::Tensor, MLOperatorTensorDataType::Float), - CreateEdgeDescriptor(MLOperatorEdgeType::Tensor, MLOperatorTensorDataType::Float16) - }; - typeConstraint.allowedTypes = allowedEdges.data(); - typeConstraint.allowedTypeCount = static_cast(allowedEdges.size()); - - std::vector typeConstraints{ typeConstraint }; - kernelDescription.typeConstraints = typeConstraints.data(); - kernelDescription.typeConstraintCount = static_cast(typeConstraints.size()); - - kernelDescription.defaultAttributes = nullptr; - kernelDescription.defaultAttributeCount = 0; - kernelDescription.options = MLOperatorKernelOptions::None; - kernelDescription.executionOptions = 0; - - auto factory = winrt::make(callCount); - - WINML_EXPECT_HRESULT_SUCCEEDED(registry->RegisterOperatorKernel( - &kernelDescription, - factory.get(), - shapeInferrer.get() - )); - } - -private: - std::atomic* m_callCount; +struct NullOperatorFactory : winrt::implements { + NullOperatorFactory(std::atomic* callCount) : m_callCount(callCount) {} + + STDMETHOD(CreateKernel)(IMLOperatorKernelCreationContext* context, IMLOperatorKernel** kernel) { + ORT_UNUSED_PARAMETER(context); + auto op = winrt::make(m_callCount); + op.copy_to(kernel); + return S_OK; + } + + static MLOperatorEdgeDescription CreateEdgeDescriptor(MLOperatorEdgeType type, MLOperatorTensorDataType dataType) { + ORT_UNUSED_PARAMETER(type); + MLOperatorEdgeDescription desc; + desc.edgeType = MLOperatorEdgeType::Tensor; + desc.tensorDataType = dataType; + return desc; + } + + static void RegisterKernel( + const char* name, + const char* domain, + int versionSince, + winrt::com_ptr registry, + winrt::com_ptr shapeInferrer, + std::atomic* callCount + ) { + MLOperatorKernelDescription kernelDescription; + kernelDescription.domain = domain; + kernelDescription.name = name; + kernelDescription.minimumOperatorSetVersion = versionSince; + kernelDescription.executionType = MLOperatorExecutionType::D3D12; + + MLOperatorEdgeTypeConstrant typeConstraint; + typeConstraint.typeLabel = "T"; + std::vector allowedEdges{ + CreateEdgeDescriptor(MLOperatorEdgeType::Tensor, MLOperatorTensorDataType::Double), + CreateEdgeDescriptor(MLOperatorEdgeType::Tensor, MLOperatorTensorDataType::Float), + CreateEdgeDescriptor(MLOperatorEdgeType::Tensor, MLOperatorTensorDataType::Float16)}; + typeConstraint.allowedTypes = allowedEdges.data(); + typeConstraint.allowedTypeCount = static_cast(allowedEdges.size()); + + std::vector typeConstraints{typeConstraint}; + kernelDescription.typeConstraints = typeConstraints.data(); + kernelDescription.typeConstraintCount = static_cast(typeConstraints.size()); + + kernelDescription.defaultAttributes = nullptr; + kernelDescription.defaultAttributeCount = 0; + kernelDescription.options = MLOperatorKernelOptions::None; + kernelDescription.executionOptions = 0; + + auto factory = winrt::make(callCount); + + WINML_EXPECT_HRESULT_SUCCEEDED( + registry->RegisterOperatorKernel(&kernelDescription, factory.get(), shapeInferrer.get()) + ); + } + + private: + std::atomic* m_callCount; }; diff --git a/winml/test/scenario/cppwinrt/CustomOperatorProvider.h b/winml/test/scenario/cppwinrt/CustomOperatorProvider.h index eee93c5d318f3..e1053035df76e 100644 --- a/winml/test/scenario/cppwinrt/CustomOperatorProvider.h +++ b/winml/test/scenario/cppwinrt/CustomOperatorProvider.h @@ -7,61 +7,49 @@ #include "ReluCpu.h" #include -struct CustomOperatorProvider : - winrt::implements< - CustomOperatorProvider, - winml::ILearningModelOperatorProvider, - ILearningModelOperatorProviderNative> -{ - HMODULE m_library; - winrt::com_ptr m_registry; +struct CustomOperatorProvider + : winrt:: + implements { + HMODULE m_library; + winrt::com_ptr m_registry; - CustomOperatorProvider() - { - std::wostringstream dll; - dll << BINARY_NAME; - auto winml_dll_name = dll.str(); + CustomOperatorProvider() { + std::wostringstream dll; + dll << BINARY_NAME; + auto winml_dll_name = dll.str(); #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - m_library = LoadLibraryExW(winml_dll_name.c_str(), nullptr, 0); + m_library = LoadLibraryExW(winml_dll_name.c_str(), nullptr, 0); #elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PC_APP) - m_library = LoadPackagedLibrary(winml_dll_name.c_str(), 0 /*Reserved*/); + m_library = LoadPackagedLibrary(winml_dll_name.c_str(), 0 /*Reserved*/); #endif - WINML_EXPECT_TRUE(m_library != 0); + WINML_EXPECT_TRUE(m_library != 0); - using create_registry_delegate = HRESULT WINAPI (_COM_Outptr_ IMLOperatorRegistry** registry); - auto create_registry = reinterpret_cast(GetProcAddress(m_library, "MLCreateOperatorRegistry")); - if (FAILED(create_registry(m_registry.put()))) - { - __fastfail(0); - } + using create_registry_delegate = HRESULT WINAPI(_COM_Outptr_ IMLOperatorRegistry * *registry); + auto create_registry = + reinterpret_cast(GetProcAddress(m_library, "MLCreateOperatorRegistry")); + if (FAILED(create_registry(m_registry.put()))) { + __fastfail(0); + } - RegisterSchemas(); - RegisterKernels(); - } + RegisterSchemas(); + RegisterKernels(); + } - ~CustomOperatorProvider() - { - FreeLibrary(m_library); - } + ~CustomOperatorProvider() { FreeLibrary(m_library); } - void RegisterSchemas() - { - NoisyReluOperatorFactory::RegisterNoisyReluSchema(m_registry); - } + void RegisterSchemas() { NoisyReluOperatorFactory::RegisterNoisyReluSchema(m_registry); } - void RegisterKernels() - { - // Replace the Relu operator kernel - ReluOperatorFactory::RegisterReluKernel(m_registry); + void RegisterKernels() { + // Replace the Relu operator kernel + ReluOperatorFactory::RegisterReluKernel(m_registry); - // Add a new operator kernel for Relu - NoisyReluOperatorFactory::RegisterNoisyReluKernel(m_registry); - } + // Add a new operator kernel for Relu + NoisyReluOperatorFactory::RegisterNoisyReluKernel(m_registry); + } - STDMETHOD(GetRegistry)(IMLOperatorRegistry** ppOperatorRegistry) - { - m_registry.copy_to(ppOperatorRegistry); - return S_OK; - } -}; \ No newline at end of file + STDMETHOD(GetRegistry)(IMLOperatorRegistry** ppOperatorRegistry) { + m_registry.copy_to(ppOperatorRegistry); + return S_OK; + } +}; diff --git a/winml/test/scenario/cppwinrt/CustomOps.cpp b/winml/test/scenario/cppwinrt/CustomOps.cpp index 91606f6efb1bc..075bf5ed877a3 100644 --- a/winml/test/scenario/cppwinrt/CustomOps.cpp +++ b/winml/test/scenario/cppwinrt/CustomOps.cpp @@ -28,12 +28,11 @@ using namespace wgi; using namespace ws; using namespace wss; -static void CustomOpsScenarioTestsClassSetup() -{ +static void CustomOpsScenarioTestsClassSetup() { winrt::init_apartment(); - #ifdef BUILD_INBOX - winrt_activation_handler = WINRT_RoGetActivationFactory; - #endif +#ifdef BUILD_INBOX + winrt_activation_handler = WINRT_RoGetActivationFactory; +#endif } // Tests that the execution provider correctly fuses operators together when custom ops are involved. @@ -56,9 +55,9 @@ static void CustomOperatorFusion() { constexpr const uint32_t c_expectedConcatOps = 8; struct CallbackOperatorProvider : winrt::implements< - CallbackOperatorProvider, - winml::ILearningModelOperatorProvider, - ILearningModelOperatorProviderNative> { + CallbackOperatorProvider, + winml::ILearningModelOperatorProvider, + ILearningModelOperatorProviderNative> { struct CallCounts { std::atomic conv = 0; std::atomic relu = 0; @@ -71,16 +70,14 @@ static void CustomOperatorFusion() { std::atomic concat = 0; }; - const CallCounts& GetCallCounts() { - return m_callCounts; - } + const CallCounts& GetCallCounts() { return m_callCounts; } CallbackOperatorProvider() { using namespace OperatorHelper; std::wostringstream dll; dll << BINARY_NAME; - auto winml_dll_name = dll.str(); + auto winml_dll_name = dll.str(); #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) auto m_library = LoadLibraryExW(winml_dll_name.c_str(), nullptr, 0); @@ -88,28 +85,40 @@ static void CustomOperatorFusion() { auto m_library = LoadPackagedLibrary(winml_dll_name.c_str(), 0 /*Reserved*/); #endif using create_registry_delegate = HRESULT WINAPI(_COM_Outptr_ IMLOperatorRegistry * *registry); - auto create_registry = reinterpret_cast(GetProcAddress(m_library, "MLCreateOperatorRegistry")); + auto create_registry = + reinterpret_cast(GetProcAddress(m_library, "MLCreateOperatorRegistry")); WINML_EXPECT_HRESULT_SUCCEEDED(create_registry(m_registry.put())); #pragma push_macro("REGISTER_KERNEL") #define REGISTER_KERNEL(_name, _domain, _opSet, _shapeInferrer, _callCount) \ NullOperatorFactory::RegisterKernel( \ - #_name, \ - (_domain), \ - _opSet::sc_sinceVer_##_name, \ - m_registry, \ - winrt::make>(), \ - (_callCount)); + #_name, \ + (_domain), \ + _opSet::sc_sinceVer_##_name, \ + m_registry, \ + winrt::make>(), \ + (_callCount) \ + ); REGISTER_KERNEL(Conv, onnxruntime::kOnnxDomain, OnnxOperatorSet7, ConvHelper, &m_callCounts.conv); - REGISTER_KERNEL(Relu, onnxruntime::kOnnxDomain, OnnxOperatorSet7, GetOutputShapeAsInputShapeHelper, &m_callCounts.relu); + REGISTER_KERNEL( + Relu, onnxruntime::kOnnxDomain, OnnxOperatorSet7, GetOutputShapeAsInputShapeHelper, &m_callCounts.relu + ); REGISTER_KERNEL(DmlFusedConv, onnxruntime::kMSDmlDomain, MsftOperatorSet1, ConvHelper, &m_callCounts.fusedConv); REGISTER_KERNEL(Gemm, onnxruntime::kOnnxDomain, OnnxOperatorSet7, GemmHelper, &m_callCounts.gemm); - REGISTER_KERNEL(Sigmoid, onnxruntime::kOnnxDomain, OnnxOperatorSet7, GetOutputShapeAsInputShapeHelper, &m_callCounts.sigmoid); + REGISTER_KERNEL( + Sigmoid, onnxruntime::kOnnxDomain, OnnxOperatorSet7, GetOutputShapeAsInputShapeHelper, &m_callCounts.sigmoid + ); REGISTER_KERNEL(DmlFusedGemm, onnxruntime::kMSDmlDomain, MsftOperatorSet1, GemmHelper, &m_callCounts.fusedGemm); - REGISTER_KERNEL(BatchNormalization, onnxruntime::kOnnxDomain, OnnxOperatorSet7, GetOutputShapeAsInputShapeHelper, &m_callCounts.batchNorm); + REGISTER_KERNEL( + BatchNormalization, + onnxruntime::kOnnxDomain, + OnnxOperatorSet7, + GetOutputShapeAsInputShapeHelper, + &m_callCounts.batchNorm + ); REGISTER_KERNEL(MaxPool, onnxruntime::kOnnxDomain, OnnxOperatorSet7, PoolingHelper, &m_callCounts.maxPool); REGISTER_KERNEL(Concat, onnxruntime::kOnnxDomain, OnnxOperatorSet7, ConcatHelper, &m_callCounts.concat); @@ -163,14 +172,13 @@ static void CustomOperatorFusion() { } struct LocalCustomOperatorProvider : winrt::implements< - LocalCustomOperatorProvider, - winml::ILearningModelOperatorProvider, - ILearningModelOperatorProviderNative> { + LocalCustomOperatorProvider, + winml::ILearningModelOperatorProvider, + ILearningModelOperatorProviderNative> { LocalCustomOperatorProvider() { - std::wostringstream dll; dll << BINARY_NAME; - auto winml_dll_name = dll.str(); + auto winml_dll_name = dll.str(); #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) auto m_library = LoadLibraryExW(winml_dll_name.c_str(), nullptr, 0); @@ -178,7 +186,8 @@ struct LocalCustomOperatorProvider : winrt::implements< auto m_library = LoadPackagedLibrary(winml_dll_name.c_str(), 0 /*Reserved*/); #endif using create_registry_delegate = HRESULT WINAPI(_COM_Outptr_ IMLOperatorRegistry * *registry); - auto create_registry = reinterpret_cast(GetProcAddress(m_library, "MLCreateOperatorRegistry")); + auto create_registry = + reinterpret_cast(GetProcAddress(m_library, "MLCreateOperatorRegistry")); WINML_EXPECT_HRESULT_SUCCEEDED(create_registry(m_registry.put())); } @@ -192,9 +201,7 @@ struct LocalCustomOperatorProvider : winrt::implements< return S_OK; } - IMLOperatorRegistry* GetRegistry() { - return m_registry.get(); - } + IMLOperatorRegistry* GetRegistry() { return m_registry.get(); } protected: winrt::com_ptr m_registry; @@ -215,7 +222,9 @@ void VerifyTestAttributes(const MLOperatorAttributes& attrs) { WINML_EXPECT_EQUAL(1.0f, attrs.GetAttribute("DefaultedNonRequiredFloat")); WINML_EXPECT_EQUAL(std::vector({1, 2}), attrs.GetAttributeVector("DefaultedNonRequiredIntArray")); - WINML_EXPECT_EQUAL(std::vector({1.0f, 2.0f}), attrs.GetAttributeVector("DefaultedNonRequiredFloatArray")); + WINML_EXPECT_EQUAL( + std::vector({1.0f, 2.0f}), attrs.GetAttributeVector("DefaultedNonRequiredFloatArray") + ); } // Foo kernel which is doing Add and optionally truncates its output @@ -295,26 +304,24 @@ static void CustomKernelWithBuiltInSchema() { IMLOperatorRegistry* registry = operatorProvider.as()->GetRegistry(); // Register the kernel - MLOperatorEdgeDescription floatTensorType = - { - MLOperatorEdgeType::Tensor, - static_cast(MLOperatorTensorDataType::Float)}; + MLOperatorEdgeDescription floatTensorType = { + MLOperatorEdgeType::Tensor, static_cast(MLOperatorTensorDataType::Float)}; MLOperatorEdgeTypeConstrant constraint = {"T", &floatTensorType, 1}; - MLOperatorKernelDescription kernelDesc = - { - "", - "Mul", - 7, - MLOperatorExecutionType::Cpu, - &constraint, - 1, - nullptr, - 0, - MLOperatorKernelOptions::AllowDynamicInputShapes}; - - Microsoft::WRL::ComPtr factory = wil::MakeOrThrow(CreateABIFooKernel); + MLOperatorKernelDescription kernelDesc = { + "", + "Mul", + 7, + MLOperatorExecutionType::Cpu, + &constraint, + 1, + nullptr, + 0, + MLOperatorKernelOptions::AllowDynamicInputShapes}; + + Microsoft::WRL::ComPtr factory = + wil::MakeOrThrow(CreateABIFooKernel); WINML_EXPECT_HRESULT_SUCCEEDED(registry->RegisterOperatorKernel(&kernelDesc, factory.Get(), nullptr)); // Prepare inputs @@ -361,10 +368,12 @@ static void CustomKernelWithBuiltInSchema() { } // Similar to MLOperatorShapeInferrer, but using an std::function -class MLOperatorShapeInferrerFromFunc : public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags, IMLOperatorShapeInferrer> { +class MLOperatorShapeInferrerFromFunc + : public Microsoft::WRL:: + RuntimeClass, IMLOperatorShapeInferrer> { public: - MLOperatorShapeInferrerFromFunc(std::function shapeInferenceFn) : m_func(shapeInferenceFn) {} + MLOperatorShapeInferrerFromFunc(std::function shapeInferenceFn) + : m_func(shapeInferenceFn) {} HRESULT STDMETHODCALLTYPE InferOutputShapes(IMLOperatorShapeInferenceContext* context) noexcept override try { m_func(context); @@ -379,8 +388,7 @@ class MLOperatorShapeInferrerFromFunc : public Microsoft::WRL::RuntimeClass< // Test using a custom kernel and schema, while verifying attribute defaults, type mapping, and inference methods static void CustomKernelWithCustomSchema() { // Test cases - struct - { + struct { // Whether the Foo kernel should truncate its output bool truncateOutput; @@ -399,14 +407,13 @@ static void CustomKernelWithCustomSchema() { // Whether attribute defaults are provided in the schema, instead of the kernel bool attributeDefaultsInSchema; - } testCases[] = - { - {false, true, false, false, false, false}, - {false, false, false, false, false, false}, - {false, true, true, false, false, true}, - {true, false, false, false, true, false}, - {true, true, true, true, true, true}, - }; + } testCases[] = { + {false, true, false, false, false, false}, + {false, false, false, false, false, false}, + {false, true, true, false, false, true}, + { true, false, false, false, true, false}, + { true, true, true, true, true, true}, + }; for (size_t caseIndex = 0; caseIndex < std::size(testCases); ++caseIndex) { // Create the registry @@ -445,46 +452,44 @@ static void CustomKernelWithCustomSchema() { MLOperatorSchemaEdgeDescription inputs[] = {inputParam, inputParam}; - MLOperatorEdgeDescription edgeTypes[6] = - { - {MLOperatorEdgeType::Tensor, static_cast(MLOperatorTensorDataType::UInt32)}, - {MLOperatorEdgeType::Tensor, static_cast(MLOperatorTensorDataType::UInt64)}, - {MLOperatorEdgeType::Tensor, static_cast(MLOperatorTensorDataType::Int32)}, - {MLOperatorEdgeType::Tensor, static_cast(MLOperatorTensorDataType::Int64)}, - {MLOperatorEdgeType::Tensor, static_cast(MLOperatorTensorDataType::Float)}, - {MLOperatorEdgeType::Tensor, static_cast(MLOperatorTensorDataType::Double)}}; + MLOperatorEdgeDescription edgeTypes[6] = { + {MLOperatorEdgeType::Tensor, static_cast(MLOperatorTensorDataType::UInt32)}, + {MLOperatorEdgeType::Tensor, static_cast(MLOperatorTensorDataType::UInt64)}, + {MLOperatorEdgeType::Tensor, static_cast(MLOperatorTensorDataType::Int32)}, + {MLOperatorEdgeType::Tensor, static_cast(MLOperatorTensorDataType::Int64)}, + {MLOperatorEdgeType::Tensor, static_cast(MLOperatorTensorDataType::Float)}, + {MLOperatorEdgeType::Tensor, static_cast(MLOperatorTensorDataType::Double)} + }; // Type constraints. Only the first is used unless type inference is provided and // the kernel emits a different output type as "T2" - MLOperatorEdgeTypeConstrant constraints[] = - { - {"T1", edgeTypes, static_cast(std::size(edgeTypes))}, - {"T2", edgeTypes, static_cast(std::size(edgeTypes))}}; + MLOperatorEdgeTypeConstrant constraints[] = { + {"T1", edgeTypes, static_cast(std::size(edgeTypes))}, + {"T2", edgeTypes, static_cast(std::size(edgeTypes))} + }; // Test attributes - MLOperatorAttribute attributes[] = - { - {"DefaultedNonRequiredInt", MLOperatorAttributeType::Int, false}, - {"DefaultedNonRequiredFloat", MLOperatorAttributeType::Float, false}, - {"DefaultedNonRequiredString", MLOperatorAttributeType::String, false}, - {"DefaultedNonRequiredIntArray", MLOperatorAttributeType::IntArray, false}, - {"DefaultedNonRequiredFloatArray", MLOperatorAttributeType::FloatArray, false}, - {"DefaultedNonRequiredStringArray", MLOperatorAttributeType::StringArray, false}, - - {"NonDefaultedNonRequiredStringArray", MLOperatorAttributeType::StringArray, false}, - }; + MLOperatorAttribute attributes[] = { + { "DefaultedNonRequiredInt", MLOperatorAttributeType::Int, false}, + { "DefaultedNonRequiredFloat", MLOperatorAttributeType::Float, false}, + { "DefaultedNonRequiredString", MLOperatorAttributeType::String, false}, + { "DefaultedNonRequiredIntArray", MLOperatorAttributeType::IntArray, false}, + { "DefaultedNonRequiredFloatArray", MLOperatorAttributeType::FloatArray, false}, + { "DefaultedNonRequiredStringArray", MLOperatorAttributeType::StringArray, false}, + + {"NonDefaultedNonRequiredStringArray", MLOperatorAttributeType::StringArray, false}, + }; // Defaults. These are queried back during kernel creation, type and shape inference // and tested against the same values - MLOperatorAttributeNameValue defaultAttributes[] = - { - {"DefaultedNonRequiredInt", MLOperatorAttributeType::Int, 1}, - {"DefaultedNonRequiredFloat", MLOperatorAttributeType::Float, 1}, - {"DefaultedNonRequiredString", MLOperatorAttributeType::String, 1}, - {"DefaultedNonRequiredIntArray", MLOperatorAttributeType::IntArray, 2}, - {"DefaultedNonRequiredFloatArray", MLOperatorAttributeType::FloatArray, 2}, - {"DefaultedNonRequiredStringArray", MLOperatorAttributeType::StringArray, 2}, - }; + MLOperatorAttributeNameValue defaultAttributes[] = { + { "DefaultedNonRequiredInt", MLOperatorAttributeType::Int, 1}, + { "DefaultedNonRequiredFloat", MLOperatorAttributeType::Float, 1}, + { "DefaultedNonRequiredString", MLOperatorAttributeType::String, 1}, + { "DefaultedNonRequiredIntArray", MLOperatorAttributeType::IntArray, 2}, + { "DefaultedNonRequiredFloatArray", MLOperatorAttributeType::FloatArray, 2}, + {"DefaultedNonRequiredStringArray", MLOperatorAttributeType::StringArray, 2}, + }; int64_t defaultInts[] = {1, 2}; float defaultFloats[] = {1.0f, 2.0f}; @@ -538,23 +543,29 @@ static void CustomKernelWithCustomSchema() { // Shape inference is tested by truncating the output size bool truncateOutput = testCases[caseIndex].truncateOutput; if (truncateOutput) { - shapeInferrer = wil::MakeOrThrow([&shapeInferenceContext](IMLOperatorShapeInferenceContext* ctx) -> void { - VerifyTestAttributes(MLShapeInferenceContext(ctx)); - MLShapeInferenceContext(ctx).SetOutputTensorShape(0, {2, 2}); - shapeInferenceContext = ctx; - }); + shapeInferrer = wil::MakeOrThrow( + [&shapeInferenceContext](IMLOperatorShapeInferenceContext* ctx) -> void { + VerifyTestAttributes(MLShapeInferenceContext(ctx)); + MLShapeInferenceContext(ctx).SetOutputTensorShape(0, {2, 2}); + shapeInferenceContext = ctx; + } + ); } // Register the schema MLOperatorSetId opsetId = {"", 7}; MLOperatorSchemaDescription* opSchemaDescs = &schemaDesc; - WINML_EXPECT_EQUAL(S_OK, registry->RegisterOperatorSetSchema( - &opsetId, - 1, - &opSchemaDescs, - 1, - typeInferrer.Get(), - testCases[caseIndex].useShapeInferenceInSchema ? shapeInferrer.Get() : nullptr)); + WINML_EXPECT_EQUAL( + S_OK, + registry->RegisterOperatorSetSchema( + &opsetId, + 1, + &opSchemaDescs, + 1, + typeInferrer.Get(), + testCases[caseIndex].useShapeInferenceInSchema ? shapeInferrer.Get() : nullptr + ) + ); { // Register a future version of the schema in the same domain, while setting its @@ -564,13 +575,17 @@ static void CustomKernelWithCustomSchema() { MLOperatorSetId id = {"", 9}; MLOperatorSchemaDescription* schemaDescs = &futureSchemaDesc; - WINML_EXPECT_EQUAL(S_OK, registry->RegisterOperatorSetSchema( - &id, - 7, - &schemaDescs, - 1, - typeInferrer.Get(), - testCases[caseIndex].useShapeInferenceInSchema ? shapeInferrer.Get() : nullptr)); + WINML_EXPECT_EQUAL( + S_OK, + registry->RegisterOperatorSetSchema( + &id, + 7, + &schemaDescs, + 1, + typeInferrer.Get(), + testCases[caseIndex].useShapeInferenceInSchema ? shapeInferrer.Get() : nullptr + ) + ); } { // Register in another (unused) domain to the custom registry @@ -579,13 +594,17 @@ static void CustomKernelWithCustomSchema() { MLOperatorSetId id = {"otherDomain", 7}; MLOperatorSchemaDescription* schemaDescs = &otherSchemaDesc; - WINML_EXPECT_EQUAL(S_OK, registry->RegisterOperatorSetSchema( - &id, - 1, - &schemaDescs, - 1, - typeInferrer.Get(), - testCases[caseIndex].useShapeInferenceInSchema ? shapeInferrer.Get() : nullptr)); + WINML_EXPECT_EQUAL( + S_OK, + registry->RegisterOperatorSetSchema( + &id, + 1, + &schemaDescs, + 1, + typeInferrer.Get(), + testCases[caseIndex].useShapeInferenceInSchema ? shapeInferrer.Get() : nullptr + ) + ); } // Register the Foo kernel MLOperatorEdgeDescription floatTensorEdgeDesc = {}; @@ -594,14 +613,8 @@ static void CustomKernelWithCustomSchema() { MLOperatorEdgeTypeConstrant kernelConstraint = {"T1", &floatTensorEdgeDesc, 1}; - MLOperatorKernelDescription kernelDesc = - { - "", - "Foo", - 7, - MLOperatorExecutionType::Cpu, - &kernelConstraint, - testCases[caseIndex].useTypeLabel ? 1u : 0u}; + MLOperatorKernelDescription kernelDesc = { + "", "Foo", 7, MLOperatorExecutionType::Cpu, &kernelConstraint, testCases[caseIndex].useTypeLabel ? 1u : 0u}; if (!testCases[caseIndex].attributeDefaultsInSchema) { kernelDesc.defaultAttributes = defaultAttributes; @@ -610,15 +623,19 @@ static void CustomKernelWithCustomSchema() { if (!truncateOutput) { kernelDesc.options = MLOperatorKernelOptions::AllowDynamicInputShapes; - Microsoft::WRL::ComPtr factory = wil::MakeOrThrow(CreateABIFooKernel); + Microsoft::WRL::ComPtr factory = + wil::MakeOrThrow(CreateABIFooKernel); WINML_EXPECT_EQUAL(S_OK, registry->RegisterOperatorKernel(&kernelDesc, factory.Get(), nullptr)); } else { - Microsoft::WRL::ComPtr factory = wil::MakeOrThrow(CreateTruncatedABIFooKernel); - WINML_EXPECT_EQUAL(S_OK, registry->RegisterOperatorKernel( - &kernelDesc, - factory.Get(), - testCases[caseIndex].useShapeInferenceInKernel ? shapeInferrer.Get() : nullptr)); + Microsoft::WRL::ComPtr factory = + wil::MakeOrThrow(CreateTruncatedABIFooKernel); + WINML_EXPECT_EQUAL( + S_OK, + registry->RegisterOperatorKernel( + &kernelDesc, factory.Get(), testCases[caseIndex].useShapeInferenceInKernel ? shapeInferrer.Get() : nullptr + ) + ); } // Prepare inputs @@ -675,13 +692,11 @@ static void CustomKernelWithCustomSchema() { } const CustomOpsTestsApi& getapi() { - static CustomOpsTestsApi api = - { - CustomOpsScenarioTestsClassSetup, - CustomOperatorFusion, - CustomKernelWithBuiltInSchema, - CustomKernelWithCustomSchema - }; + static CustomOpsTestsApi api = { + CustomOpsScenarioTestsClassSetup, + CustomOperatorFusion, + CustomKernelWithBuiltInSchema, + CustomKernelWithCustomSchema}; if (SkipGpuTests()) { api.CustomOperatorFusion = SkipTest; @@ -690,4 +705,4 @@ const CustomOpsTestsApi& getapi() { api.CustomOperatorFusion = SkipTest; } return api; -} \ No newline at end of file +} diff --git a/winml/test/scenario/cppwinrt/CustomOps.h b/winml/test/scenario/cppwinrt/CustomOps.h index a117e2e9cd650..96ad15514bded 100644 --- a/winml/test/scenario/cppwinrt/CustomOps.h +++ b/winml/test/scenario/cppwinrt/CustomOps.h @@ -2,12 +2,11 @@ // Licensed under the MIT License. #include "test.h" -struct CustomOpsTestsApi -{ - SetupTest CustomOpsScenarioTestsClassSetup; - VoidTest CustomOperatorFusion; - VoidTest CustomKernelWithBuiltInSchema; - VoidTest CustomKernelWithCustomSchema; +struct CustomOpsTestsApi { + SetupTest CustomOpsScenarioTestsClassSetup; + VoidTest CustomOperatorFusion; + VoidTest CustomKernelWithBuiltInSchema; + VoidTest CustomKernelWithCustomSchema; }; const CustomOpsTestsApi& getapi(); @@ -17,4 +16,4 @@ WINML_TEST_CLASS_BEGIN_TESTS WINML_TEST(CustomOpsScenarioTests, CustomKernelWithBuiltInSchema) WINML_TEST(CustomOpsScenarioTests, CustomKernelWithCustomSchema) WINML_TEST(CustomOpsScenarioTests, CustomOperatorFusion) -WINML_TEST_CLASS_END() \ No newline at end of file +WINML_TEST_CLASS_END() diff --git a/winml/test/scenario/cppwinrt/NoisyReluCpu.h b/winml/test/scenario/cppwinrt/NoisyReluCpu.h index 771554cdb9b26..5f89b20beebb9 100644 --- a/winml/test/scenario/cppwinrt/NoisyReluCpu.h +++ b/winml/test/scenario/cppwinrt/NoisyReluCpu.h @@ -6,293 +6,248 @@ #include "core/providers/dml/DmlExecutionProvider/inc/MLOperatorAuthor.h" #include "core/common//common.h" -struct NoisyReluShapeInferrer : winrt::implements -{ - STDMETHOD(InferOutputShapes)(IMLOperatorShapeInferenceContext* context) noexcept - { - try - { - uint32_t inputDimsSize; - context->GetInputTensorDimensionCount(0, &inputDimsSize); - - uint32_t *inputDims = new uint32_t[inputDimsSize]; - context->GetInputTensorShape(0, inputDimsSize, inputDims); - - context->SetOutputTensorShape(0, inputDimsSize, inputDims); - return S_OK; - } - catch (...) - { - return winrt::to_hresult(); - } +struct NoisyReluShapeInferrer : winrt::implements { + STDMETHOD(InferOutputShapes)(IMLOperatorShapeInferenceContext* context) noexcept { + try { + uint32_t inputDimsSize; + context->GetInputTensorDimensionCount(0, &inputDimsSize); + + uint32_t* inputDims = new uint32_t[inputDimsSize]; + context->GetInputTensorShape(0, inputDimsSize, inputDims); + + context->SetOutputTensorShape(0, inputDimsSize, inputDims); + return S_OK; + } catch (...) { + return winrt::to_hresult(); } + } }; -struct NoisyReluOperator: winrt::implements -{ - float m_mean; - float m_variance; - - NoisyReluOperator(float mean, float variance) : - m_mean(mean), - m_variance(variance) - {} - - // Computes the outputs of the kernel. This may be called multiple times - // simultaneously within the same instance of the class. Implementations - // of this method must be thread-safe. - STDMETHOD(Compute)(IMLOperatorKernelContext* context) - { - try - { - // Get the input tensor - winrt::com_ptr inputTensor; - context->GetInputTensor(0, inputTensor.put()); - - // Get the output tensor - winrt::com_ptr outputTensor; - context->GetOutputTensor(0, outputTensor.put()); - - // Get the input and output shape sizes - uint32_t inputDimsSize = inputTensor->GetDimensionCount(); - uint32_t outputDimsSize = outputTensor->GetDimensionCount(); - if (inputDimsSize != outputDimsSize) - { - return E_UNEXPECTED; - } - - // Get the input shape - std::vector inputDims(inputDimsSize); - outputTensor->GetShape(inputDimsSize, inputDims.data()); - - // Get the output shape - std::vector outputDims(outputDimsSize); - outputTensor->GetShape(outputDimsSize, outputDims.data()); - - // For the number of total elements in the input and output shapes - auto outputDataSize = std::accumulate(outputDims.begin(), outputDims.end(), 1, std::multiplies()); - auto inputDataSize = std::accumulate(inputDims.begin(), inputDims.end(), 1, std::multiplies()); - if (outputDataSize != inputDataSize) - { - return E_UNEXPECTED; - } - - // If the tensor types are both float type - if (outputTensor->GetTensorDataType() == MLOperatorTensorDataType::Float && - inputTensor->GetTensorDataType() == MLOperatorTensorDataType::Float) - { - // For cpu data - if (outputTensor->IsCpuData() && inputTensor->IsCpuData()) - { - ComputeInternal(inputTensor.get(), outputTensor.get(), inputDataSize); - } - } - else if (outputTensor->GetTensorDataType() == MLOperatorTensorDataType::Double && - inputTensor->GetTensorDataType() == MLOperatorTensorDataType::Double) - { - // For cpu data - if (outputTensor->IsCpuData() && inputTensor->IsCpuData()) - { - ComputeInternal(inputTensor.get(), outputTensor.get(), inputDataSize); - } - } - - return S_OK; +struct NoisyReluOperator : winrt::implements { + float m_mean; + float m_variance; + + NoisyReluOperator(float mean, float variance) : m_mean(mean), m_variance(variance) {} + + // Computes the outputs of the kernel. This may be called multiple times + // simultaneously within the same instance of the class. Implementations + // of this method must be thread-safe. + STDMETHOD(Compute)(IMLOperatorKernelContext* context) { + try { + // Get the input tensor + winrt::com_ptr inputTensor; + context->GetInputTensor(0, inputTensor.put()); + + // Get the output tensor + winrt::com_ptr outputTensor; + context->GetOutputTensor(0, outputTensor.put()); + + // Get the input and output shape sizes + uint32_t inputDimsSize = inputTensor->GetDimensionCount(); + uint32_t outputDimsSize = outputTensor->GetDimensionCount(); + if (inputDimsSize != outputDimsSize) { + return E_UNEXPECTED; + } + + // Get the input shape + std::vector inputDims(inputDimsSize); + outputTensor->GetShape(inputDimsSize, inputDims.data()); + + // Get the output shape + std::vector outputDims(outputDimsSize); + outputTensor->GetShape(outputDimsSize, outputDims.data()); + + // For the number of total elements in the input and output shapes + auto outputDataSize = std::accumulate(outputDims.begin(), outputDims.end(), 1, std::multiplies()); + auto inputDataSize = std::accumulate(inputDims.begin(), inputDims.end(), 1, std::multiplies()); + if (outputDataSize != inputDataSize) { + return E_UNEXPECTED; + } + + // If the tensor types are both float type + if (outputTensor->GetTensorDataType() == MLOperatorTensorDataType::Float && inputTensor->GetTensorDataType() == MLOperatorTensorDataType::Float) { + // For cpu data + if (outputTensor->IsCpuData() && inputTensor->IsCpuData()) { + ComputeInternal(inputTensor.get(), outputTensor.get(), inputDataSize); } - catch (...) - { - return winrt::to_hresult(); + } else if (outputTensor->GetTensorDataType() == MLOperatorTensorDataType::Double && inputTensor->GetTensorDataType() == MLOperatorTensorDataType::Double) { + // For cpu data + if (outputTensor->IsCpuData() && inputTensor->IsCpuData()) { + ComputeInternal(inputTensor.get(), outputTensor.get(), inputDataSize); } - } + } - template - void ComputeInternal(IMLOperatorTensor* pInputTensor, IMLOperatorTensor* pOutputTensor, uint32_t size) - { - // Create a normal distribution - std::normal_distribution<> dist{ m_mean, m_variance }; - std::random_device rd{}; - std::mt19937 gen{ rd() }; - - auto inputData = static_cast(pInputTensor->GetData()); - auto outputData = static_cast(pOutputTensor->GetData()); - - for (uint32_t i = 0; i < size; i++) - { - outputData[i] = static_cast(std::max(0, static_cast(inputData[i] + dist(gen)))); - } + return S_OK; + } catch (...) { + return winrt::to_hresult(); } -}; + } -struct NoisyReluOperatorFactory : winrt::implements -{ - STDMETHOD(CreateKernel)( - IMLOperatorKernelCreationContext* context, - IMLOperatorKernel** kernel) - { - try - { - float mean; - context->GetAttribute("mean", MLOperatorAttributeType::Float, 1, sizeof(float), reinterpret_cast(&mean)); - float variance; - context->GetAttribute("variance", MLOperatorAttributeType::Float, 1, sizeof(float), reinterpret_cast(&variance)); - - auto noisyReluOperator = winrt::make(mean, variance); - noisyReluOperator.copy_to(kernel); - return S_OK; - } - catch (...) - { - return winrt::to_hresult(); - } - } + template + void ComputeInternal(IMLOperatorTensor* pInputTensor, IMLOperatorTensor* pOutputTensor, uint32_t size) { + // Create a normal distribution + std::normal_distribution<> dist{m_mean, m_variance}; + std::random_device rd{}; + std::mt19937 gen{rd()}; - static MLOperatorEdgeDescription CreateEdgeDescriptor(MLOperatorEdgeType type, MLOperatorTensorDataType dataType) - { - ORT_UNUSED_PARAMETER(type); - MLOperatorEdgeDescription desc; - desc.edgeType = MLOperatorEdgeType::Tensor; - desc.tensorDataType = dataType; - return desc; - } + auto inputData = static_cast(pInputTensor->GetData()); + auto outputData = static_cast(pOutputTensor->GetData()); - static void RegisterNoisyReluSchema(winrt::com_ptr registry) - { - MLOperatorSetId operatorSetId; - operatorSetId.domain = ""; - operatorSetId.version = 7; - - MLOperatorSchemaDescription noisyReluSchema; - noisyReluSchema.name = "NoisyRelu"; - noisyReluSchema.operatorSetVersionAtLastChange = 1; - - MLOperatorSchemaEdgeDescription noisyReluXInput; - noisyReluXInput.options = MLOperatorParameterOptions::Single; - noisyReluXInput.typeFormat = MLOperatorSchemaEdgeTypeFormat::Label; - noisyReluXInput.typeLabel = "T"; - - std::vector inputs { noisyReluXInput }; - noisyReluSchema.inputs = inputs.data(); - noisyReluSchema.inputCount = static_cast(inputs.size()); - - MLOperatorSchemaEdgeDescription noisyReluXOutput; - noisyReluXOutput.options = MLOperatorParameterOptions::Single; - noisyReluXOutput.typeFormat = MLOperatorSchemaEdgeTypeFormat::Label; - noisyReluXOutput.typeLabel = "T"; - - std::vector outputs{ noisyReluXOutput }; - noisyReluSchema.outputs = outputs.data(); - noisyReluSchema.outputCount = static_cast(outputs.size()); - - MLOperatorEdgeTypeConstrant typeConstraint; - typeConstraint.typeLabel = "T"; - std::vector allowedEdges - { - CreateEdgeDescriptor(MLOperatorEdgeType::Tensor, MLOperatorTensorDataType::Double), - CreateEdgeDescriptor(MLOperatorEdgeType::Tensor, MLOperatorTensorDataType::Float), - CreateEdgeDescriptor(MLOperatorEdgeType::Tensor, MLOperatorTensorDataType::Float16) - }; - typeConstraint.allowedTypes = allowedEdges.data(); - typeConstraint.allowedTypeCount = static_cast(allowedEdges.size()); - - std::vector typeConstraints { typeConstraint }; - noisyReluSchema.typeConstraints = typeConstraints.data(); - noisyReluSchema.typeConstraintCount = static_cast(typeConstraints.size()); - - - MLOperatorAttribute noisyReluMeanAttribute; - noisyReluMeanAttribute.name = "mean"; - noisyReluMeanAttribute.required = false; - noisyReluMeanAttribute.type = MLOperatorAttributeType::Float; - - MLOperatorAttribute noisyReluVarianceAttribute; - noisyReluVarianceAttribute.name = "variance"; - noisyReluVarianceAttribute.required = false; - noisyReluVarianceAttribute.type = MLOperatorAttributeType::Float; - - std::vector attributes { noisyReluMeanAttribute, noisyReluVarianceAttribute }; - noisyReluSchema.attributes = attributes.data(); - noisyReluSchema.attributeCount = static_cast(attributes.size()); - - MLOperatorAttributeNameValue noisyReluMeanAttributeValue; - noisyReluMeanAttributeValue.name = "mean"; - noisyReluMeanAttributeValue.type = MLOperatorAttributeType::Float; - noisyReluMeanAttributeValue.valueCount = 1; - static float defaultMeans[] = { 0.f }; - noisyReluMeanAttributeValue.floats = defaultMeans; - - MLOperatorAttributeNameValue noisyReluVarianceAttributeValue; - noisyReluVarianceAttributeValue.name = "variance"; - noisyReluVarianceAttributeValue.type = MLOperatorAttributeType::Float; - noisyReluVarianceAttributeValue.valueCount = 1; - static float defaultVariance[] = { 1.f }; - noisyReluVarianceAttributeValue.floats = defaultVariance; - - std::vector attributeDefaultValues { noisyReluMeanAttributeValue, noisyReluVarianceAttributeValue }; - noisyReluSchema.defaultAttributes = attributeDefaultValues.data(); - noisyReluSchema.defaultAttributeCount = static_cast(attributeDefaultValues.size()); - - std::vector schemas { &noisyReluSchema }; - registry->RegisterOperatorSetSchema( - &operatorSetId, - 6 /* baseline version */, - schemas.data(), - static_cast(schemas.size()), - nullptr, - nullptr - ); + for (uint32_t i = 0; i < size; i++) { + outputData[i] = static_cast(std::max(0, static_cast(inputData[i] + dist(gen)))); } + } +}; - static void RegisterNoisyReluKernel(winrt::com_ptr registry) - { - MLOperatorKernelDescription kernelDescription; - kernelDescription.domain = ""; - kernelDescription.name = "NoisyRelu"; - kernelDescription.minimumOperatorSetVersion = 1; - kernelDescription.executionType = MLOperatorExecutionType::Cpu; - - MLOperatorEdgeTypeConstrant typeConstraint; - typeConstraint.typeLabel = "T"; - std::vector allowedEdges - { - CreateEdgeDescriptor(MLOperatorEdgeType::Tensor, MLOperatorTensorDataType::Double), - CreateEdgeDescriptor(MLOperatorEdgeType::Tensor, MLOperatorTensorDataType::Float), - CreateEdgeDescriptor(MLOperatorEdgeType::Tensor, MLOperatorTensorDataType::Float16) - }; - typeConstraint.allowedTypes = allowedEdges.data(); - typeConstraint.allowedTypeCount = static_cast(allowedEdges.size()); - - std::vector typeConstraints{ typeConstraint }; - kernelDescription.typeConstraints = typeConstraints.data(); - kernelDescription.typeConstraintCount = static_cast(typeConstraints.size()); - - - MLOperatorAttributeNameValue noisyReluMeanAttributeValue; - noisyReluMeanAttributeValue.name = "mean"; - noisyReluMeanAttributeValue.type = MLOperatorAttributeType::Float; - noisyReluMeanAttributeValue.valueCount = 1; - static float defaultMeans[] = { 0.f }; - noisyReluMeanAttributeValue.floats = defaultMeans; - - MLOperatorAttributeNameValue noisyReluVarianceAttributeValue; - noisyReluVarianceAttributeValue.name = "variance"; - noisyReluVarianceAttributeValue.type = MLOperatorAttributeType::Float; - noisyReluVarianceAttributeValue.valueCount = 1; - static float defaultVariance[] = { 1.f }; - noisyReluVarianceAttributeValue.floats = defaultVariance; - - std::vector attributeDefaultValues{ noisyReluMeanAttributeValue, noisyReluVarianceAttributeValue }; - kernelDescription.defaultAttributes = attributeDefaultValues.data(); - kernelDescription.defaultAttributeCount = static_cast(attributeDefaultValues.size()); - kernelDescription.options = MLOperatorKernelOptions::None; - kernelDescription.executionOptions = 0; - - auto factory = winrt::make(); - auto shareInferrer = winrt::make(); - - registry->RegisterOperatorKernel( - &kernelDescription, - factory.get(), - shareInferrer.get() - ); +struct NoisyReluOperatorFactory : winrt::implements { + STDMETHOD(CreateKernel)(IMLOperatorKernelCreationContext* context, IMLOperatorKernel** kernel) { + try { + float mean; + context->GetAttribute("mean", MLOperatorAttributeType::Float, 1, sizeof(float), reinterpret_cast(&mean)); + float variance; + context->GetAttribute( + "variance", MLOperatorAttributeType::Float, 1, sizeof(float), reinterpret_cast(&variance) + ); + + auto noisyReluOperator = winrt::make(mean, variance); + noisyReluOperator.copy_to(kernel); + return S_OK; + } catch (...) { + return winrt::to_hresult(); } + } + + static MLOperatorEdgeDescription CreateEdgeDescriptor(MLOperatorEdgeType type, MLOperatorTensorDataType dataType) { + ORT_UNUSED_PARAMETER(type); + MLOperatorEdgeDescription desc; + desc.edgeType = MLOperatorEdgeType::Tensor; + desc.tensorDataType = dataType; + return desc; + } + + static void RegisterNoisyReluSchema(winrt::com_ptr registry) { + MLOperatorSetId operatorSetId; + operatorSetId.domain = ""; + operatorSetId.version = 7; + + MLOperatorSchemaDescription noisyReluSchema; + noisyReluSchema.name = "NoisyRelu"; + noisyReluSchema.operatorSetVersionAtLastChange = 1; + + MLOperatorSchemaEdgeDescription noisyReluXInput; + noisyReluXInput.options = MLOperatorParameterOptions::Single; + noisyReluXInput.typeFormat = MLOperatorSchemaEdgeTypeFormat::Label; + noisyReluXInput.typeLabel = "T"; + + std::vector inputs{noisyReluXInput}; + noisyReluSchema.inputs = inputs.data(); + noisyReluSchema.inputCount = static_cast(inputs.size()); + + MLOperatorSchemaEdgeDescription noisyReluXOutput; + noisyReluXOutput.options = MLOperatorParameterOptions::Single; + noisyReluXOutput.typeFormat = MLOperatorSchemaEdgeTypeFormat::Label; + noisyReluXOutput.typeLabel = "T"; + + std::vector outputs{noisyReluXOutput}; + noisyReluSchema.outputs = outputs.data(); + noisyReluSchema.outputCount = static_cast(outputs.size()); + + MLOperatorEdgeTypeConstrant typeConstraint; + typeConstraint.typeLabel = "T"; + std::vector allowedEdges{ + CreateEdgeDescriptor(MLOperatorEdgeType::Tensor, MLOperatorTensorDataType::Double), + CreateEdgeDescriptor(MLOperatorEdgeType::Tensor, MLOperatorTensorDataType::Float), + CreateEdgeDescriptor(MLOperatorEdgeType::Tensor, MLOperatorTensorDataType::Float16)}; + typeConstraint.allowedTypes = allowedEdges.data(); + typeConstraint.allowedTypeCount = static_cast(allowedEdges.size()); + + std::vector typeConstraints{typeConstraint}; + noisyReluSchema.typeConstraints = typeConstraints.data(); + noisyReluSchema.typeConstraintCount = static_cast(typeConstraints.size()); + + MLOperatorAttribute noisyReluMeanAttribute; + noisyReluMeanAttribute.name = "mean"; + noisyReluMeanAttribute.required = false; + noisyReluMeanAttribute.type = MLOperatorAttributeType::Float; + + MLOperatorAttribute noisyReluVarianceAttribute; + noisyReluVarianceAttribute.name = "variance"; + noisyReluVarianceAttribute.required = false; + noisyReluVarianceAttribute.type = MLOperatorAttributeType::Float; + + std::vector attributes{noisyReluMeanAttribute, noisyReluVarianceAttribute}; + noisyReluSchema.attributes = attributes.data(); + noisyReluSchema.attributeCount = static_cast(attributes.size()); + + MLOperatorAttributeNameValue noisyReluMeanAttributeValue; + noisyReluMeanAttributeValue.name = "mean"; + noisyReluMeanAttributeValue.type = MLOperatorAttributeType::Float; + noisyReluMeanAttributeValue.valueCount = 1; + static float defaultMeans[] = {0.f}; + noisyReluMeanAttributeValue.floats = defaultMeans; + + MLOperatorAttributeNameValue noisyReluVarianceAttributeValue; + noisyReluVarianceAttributeValue.name = "variance"; + noisyReluVarianceAttributeValue.type = MLOperatorAttributeType::Float; + noisyReluVarianceAttributeValue.valueCount = 1; + static float defaultVariance[] = {1.f}; + noisyReluVarianceAttributeValue.floats = defaultVariance; + + std::vector attributeDefaultValues{ + noisyReluMeanAttributeValue, noisyReluVarianceAttributeValue}; + noisyReluSchema.defaultAttributes = attributeDefaultValues.data(); + noisyReluSchema.defaultAttributeCount = static_cast(attributeDefaultValues.size()); + + std::vector schemas{&noisyReluSchema}; + registry->RegisterOperatorSetSchema( + &operatorSetId, 6 /* baseline version */, schemas.data(), static_cast(schemas.size()), nullptr, nullptr + ); + } + + static void RegisterNoisyReluKernel(winrt::com_ptr registry) { + MLOperatorKernelDescription kernelDescription; + kernelDescription.domain = ""; + kernelDescription.name = "NoisyRelu"; + kernelDescription.minimumOperatorSetVersion = 1; + kernelDescription.executionType = MLOperatorExecutionType::Cpu; + + MLOperatorEdgeTypeConstrant typeConstraint; + typeConstraint.typeLabel = "T"; + std::vector allowedEdges{ + CreateEdgeDescriptor(MLOperatorEdgeType::Tensor, MLOperatorTensorDataType::Double), + CreateEdgeDescriptor(MLOperatorEdgeType::Tensor, MLOperatorTensorDataType::Float), + CreateEdgeDescriptor(MLOperatorEdgeType::Tensor, MLOperatorTensorDataType::Float16)}; + typeConstraint.allowedTypes = allowedEdges.data(); + typeConstraint.allowedTypeCount = static_cast(allowedEdges.size()); + + std::vector typeConstraints{typeConstraint}; + kernelDescription.typeConstraints = typeConstraints.data(); + kernelDescription.typeConstraintCount = static_cast(typeConstraints.size()); + + MLOperatorAttributeNameValue noisyReluMeanAttributeValue; + noisyReluMeanAttributeValue.name = "mean"; + noisyReluMeanAttributeValue.type = MLOperatorAttributeType::Float; + noisyReluMeanAttributeValue.valueCount = 1; + static float defaultMeans[] = {0.f}; + noisyReluMeanAttributeValue.floats = defaultMeans; + + MLOperatorAttributeNameValue noisyReluVarianceAttributeValue; + noisyReluVarianceAttributeValue.name = "variance"; + noisyReluVarianceAttributeValue.type = MLOperatorAttributeType::Float; + noisyReluVarianceAttributeValue.valueCount = 1; + static float defaultVariance[] = {1.f}; + noisyReluVarianceAttributeValue.floats = defaultVariance; + + std::vector attributeDefaultValues{ + noisyReluMeanAttributeValue, noisyReluVarianceAttributeValue}; + kernelDescription.defaultAttributes = attributeDefaultValues.data(); + kernelDescription.defaultAttributeCount = static_cast(attributeDefaultValues.size()); + kernelDescription.options = MLOperatorKernelOptions::None; + kernelDescription.executionOptions = 0; + + auto factory = winrt::make(); + auto shareInferrer = winrt::make(); + + registry->RegisterOperatorKernel(&kernelDescription, factory.get(), shareInferrer.get()); + } }; diff --git a/winml/test/scenario/cppwinrt/ReluCpu.h b/winml/test/scenario/cppwinrt/ReluCpu.h index 778aa0362cac3..c72285a4de7fb 100644 --- a/winml/test/scenario/cppwinrt/ReluCpu.h +++ b/winml/test/scenario/cppwinrt/ReluCpu.h @@ -6,158 +6,130 @@ #include "core/providers/dml/DmlExecutionProvider/inc/MLOperatorAuthor.h" #include "core/common//common.h" -struct ReluShapeInferrer : winrt::implements -{ - STDMETHOD(InferOutputShapes)(IMLOperatorShapeInferenceContext* context) noexcept - { - uint32_t inputDimsSize; - context->GetInputTensorDimensionCount(0, &inputDimsSize); - - auto inputDims = new uint32_t[inputDimsSize]; - context->GetInputTensorShape(0, inputDimsSize, inputDims); - - context->SetOutputTensorShape(0, inputDimsSize, inputDims); - return S_OK; - } +struct ReluShapeInferrer : winrt::implements { + STDMETHOD(InferOutputShapes)(IMLOperatorShapeInferenceContext* context) noexcept { + uint32_t inputDimsSize; + context->GetInputTensorDimensionCount(0, &inputDimsSize); + + auto inputDims = new uint32_t[inputDimsSize]; + context->GetInputTensorShape(0, inputDimsSize, inputDims); + + context->SetOutputTensorShape(0, inputDimsSize, inputDims); + return S_OK; + } }; -struct ReluOperator: winrt::implements -{ - ReluOperator() {} - - // Computes the outputs of the kernel. In this case, the output will represent - // the Rectified Linear Unit (Relu) output. - // - // Based on the operators location in the model graph this operator may be called multiple times - // or simultaneously within the same instance of the class during evaluation. Implementations - // of this method must be thread-safe. - STDMETHOD(Compute)(IMLOperatorKernelContext* context) - { - // Get the input tensor - winrt::com_ptr inputTensor; - context->GetInputTensor(0, inputTensor.put()); - - // Get the output tensor - winrt::com_ptr outputTensor; - context->GetOutputTensor(0, outputTensor.put()); - - // Get the input and output shape sizes - uint32_t inputDimsSize = inputTensor->GetDimensionCount(); - uint32_t outputDimsSize = outputTensor->GetDimensionCount(); - if (inputDimsSize != outputDimsSize) - { - return E_UNEXPECTED; - } - - // Get the input shape - std::vector inputDims(inputDimsSize); - outputTensor->GetShape(inputDimsSize, inputDims.data()); - - // Get the output shape - std::vector outputDims(outputDimsSize); - outputTensor->GetShape(outputDimsSize, outputDims.data()); - - // For the number of total elements in the input and output shapes - auto outputDataSize = std::accumulate(outputDims.begin(), outputDims.end(), 1, std::multiplies()); - auto inputDataSize = std::accumulate(inputDims.begin(), inputDims.end(), 1, std::multiplies()); - if (outputDataSize != inputDataSize) - { - return E_UNEXPECTED; - } - - // If the tensor types are both float type - if (outputTensor->GetTensorDataType() == MLOperatorTensorDataType::Float && - inputTensor->GetTensorDataType() == MLOperatorTensorDataType::Float) - { - // For cpu data - if (outputTensor->IsCpuData() && inputTensor->IsCpuData()) - { - ComputeInternal(inputTensor.get(), outputTensor.get(), inputDataSize); - } - } - else if (outputTensor->GetTensorDataType() == MLOperatorTensorDataType::Double && - inputTensor->GetTensorDataType() == MLOperatorTensorDataType::Double) - { - // For cpu data - if (outputTensor->IsCpuData() && inputTensor->IsCpuData()) - { - ComputeInternal(inputTensor.get(), outputTensor.get(), inputDataSize); - } - } - - - return S_OK; +struct ReluOperator : winrt::implements { + ReluOperator() {} + + // Computes the outputs of the kernel. In this case, the output will represent + // the Rectified Linear Unit (Relu) output. + // + // Based on the operators location in the model graph this operator may be called multiple times + // or simultaneously within the same instance of the class during evaluation. Implementations + // of this method must be thread-safe. + STDMETHOD(Compute)(IMLOperatorKernelContext* context) { + // Get the input tensor + winrt::com_ptr inputTensor; + context->GetInputTensor(0, inputTensor.put()); + + // Get the output tensor + winrt::com_ptr outputTensor; + context->GetOutputTensor(0, outputTensor.put()); + + // Get the input and output shape sizes + uint32_t inputDimsSize = inputTensor->GetDimensionCount(); + uint32_t outputDimsSize = outputTensor->GetDimensionCount(); + if (inputDimsSize != outputDimsSize) { + return E_UNEXPECTED; } - template - void ComputeInternal(IMLOperatorTensor* pInputTensor, IMLOperatorTensor* pOutputTensor, uint32_t size) - { - auto inputData = static_cast(pInputTensor->GetData()); - auto outputData = static_cast(pOutputTensor->GetData()); + // Get the input shape + std::vector inputDims(inputDimsSize); + outputTensor->GetShape(inputDimsSize, inputDims.data()); - for (uint32_t i = 0; i < size; i++) - { - outputData[i] = static_cast(std::max(0, inputData[i])); - } - } -}; + // Get the output shape + std::vector outputDims(outputDimsSize); + outputTensor->GetShape(outputDimsSize, outputDims.data()); -struct ReluOperatorFactory : winrt::implements -{ - STDMETHOD(CreateKernel)( - IMLOperatorKernelCreationContext* context, - IMLOperatorKernel** kernel) - { - ORT_UNUSED_PARAMETER(context); - auto reluOperator = winrt::make(); - reluOperator.copy_to(kernel); - return S_OK; + // For the number of total elements in the input and output shapes + auto outputDataSize = std::accumulate(outputDims.begin(), outputDims.end(), 1, std::multiplies()); + auto inputDataSize = std::accumulate(inputDims.begin(), inputDims.end(), 1, std::multiplies()); + if (outputDataSize != inputDataSize) { + return E_UNEXPECTED; } - static MLOperatorEdgeDescription CreateEdgeDescriptor(MLOperatorEdgeType type, MLOperatorTensorDataType dataType) - { - ORT_UNUSED_PARAMETER(type); - MLOperatorEdgeDescription desc; - desc.edgeType = MLOperatorEdgeType::Tensor; - desc.tensorDataType = dataType; - return desc; + // If the tensor types are both float type + if (outputTensor->GetTensorDataType() == MLOperatorTensorDataType::Float && inputTensor->GetTensorDataType() == MLOperatorTensorDataType::Float) { + // For cpu data + if (outputTensor->IsCpuData() && inputTensor->IsCpuData()) { + ComputeInternal(inputTensor.get(), outputTensor.get(), inputDataSize); + } + } else if (outputTensor->GetTensorDataType() == MLOperatorTensorDataType::Double && inputTensor->GetTensorDataType() == MLOperatorTensorDataType::Double) { + // For cpu data + if (outputTensor->IsCpuData() && inputTensor->IsCpuData()) { + ComputeInternal(inputTensor.get(), outputTensor.get(), inputDataSize); + } } - static void RegisterReluKernel(winrt::com_ptr registry) - { - MLOperatorKernelDescription kernelDescription; - kernelDescription.domain = ""; - kernelDescription.name = "Relu"; - kernelDescription.minimumOperatorSetVersion = 1; - kernelDescription.executionType = MLOperatorExecutionType::Cpu; - - MLOperatorEdgeTypeConstrant typeConstraint; - typeConstraint.typeLabel = "T"; - std::vector allowedEdges - { - CreateEdgeDescriptor(MLOperatorEdgeType::Tensor, MLOperatorTensorDataType::Double), - CreateEdgeDescriptor(MLOperatorEdgeType::Tensor, MLOperatorTensorDataType::Float), - CreateEdgeDescriptor(MLOperatorEdgeType::Tensor, MLOperatorTensorDataType::Float16) - }; - typeConstraint.allowedTypes = allowedEdges.data(); - typeConstraint.allowedTypeCount = static_cast(allowedEdges.size()); - - std::vector typeConstraints{ typeConstraint }; - kernelDescription.typeConstraints = typeConstraints.data(); - kernelDescription.typeConstraintCount = static_cast(typeConstraints.size()); - - kernelDescription.defaultAttributes = nullptr; - kernelDescription.defaultAttributeCount = 0; - kernelDescription.options = MLOperatorKernelOptions::None; - kernelDescription.executionOptions = 0; - - auto factory = winrt::make(); - auto shareInferrer = winrt::make(); - - registry->RegisterOperatorKernel( - &kernelDescription, - factory.get(), - shareInferrer.get() - ); + return S_OK; + } + + template + void ComputeInternal(IMLOperatorTensor* pInputTensor, IMLOperatorTensor* pOutputTensor, uint32_t size) { + auto inputData = static_cast(pInputTensor->GetData()); + auto outputData = static_cast(pOutputTensor->GetData()); + + for (uint32_t i = 0; i < size; i++) { + outputData[i] = static_cast(std::max(0, inputData[i])); } + } +}; + +struct ReluOperatorFactory : winrt::implements { + STDMETHOD(CreateKernel)(IMLOperatorKernelCreationContext* context, IMLOperatorKernel** kernel) { + ORT_UNUSED_PARAMETER(context); + auto reluOperator = winrt::make(); + reluOperator.copy_to(kernel); + return S_OK; + } + + static MLOperatorEdgeDescription CreateEdgeDescriptor(MLOperatorEdgeType type, MLOperatorTensorDataType dataType) { + ORT_UNUSED_PARAMETER(type); + MLOperatorEdgeDescription desc; + desc.edgeType = MLOperatorEdgeType::Tensor; + desc.tensorDataType = dataType; + return desc; + } + + static void RegisterReluKernel(winrt::com_ptr registry) { + MLOperatorKernelDescription kernelDescription; + kernelDescription.domain = ""; + kernelDescription.name = "Relu"; + kernelDescription.minimumOperatorSetVersion = 1; + kernelDescription.executionType = MLOperatorExecutionType::Cpu; + + MLOperatorEdgeTypeConstrant typeConstraint; + typeConstraint.typeLabel = "T"; + std::vector allowedEdges{ + CreateEdgeDescriptor(MLOperatorEdgeType::Tensor, MLOperatorTensorDataType::Double), + CreateEdgeDescriptor(MLOperatorEdgeType::Tensor, MLOperatorTensorDataType::Float), + CreateEdgeDescriptor(MLOperatorEdgeType::Tensor, MLOperatorTensorDataType::Float16)}; + typeConstraint.allowedTypes = allowedEdges.data(); + typeConstraint.allowedTypeCount = static_cast(allowedEdges.size()); + + std::vector typeConstraints{typeConstraint}; + kernelDescription.typeConstraints = typeConstraints.data(); + kernelDescription.typeConstraintCount = static_cast(typeConstraints.size()); + + kernelDescription.defaultAttributes = nullptr; + kernelDescription.defaultAttributeCount = 0; + kernelDescription.options = MLOperatorKernelOptions::None; + kernelDescription.executionOptions = 0; + + auto factory = winrt::make(); + auto shareInferrer = winrt::make(); + + registry->RegisterOperatorKernel(&kernelDescription, factory.get(), shareInferrer.get()); + } }; diff --git a/winml/test/scenario/cppwinrt/scenariotestscppwinrt.cpp b/winml/test/scenario/cppwinrt/scenariotestscppwinrt.cpp index 5d3561076c6aa..9b389d014c953 100644 --- a/winml/test/scenario/cppwinrt/scenariotestscppwinrt.cpp +++ b/winml/test/scenario/cppwinrt/scenariotestscppwinrt.cpp @@ -64,7 +64,9 @@ ILearningModelFeatureValue MakeTensor(const ITensorFeatureDescriptor& descriptor std::vector shape; int64_t size = 1; for (auto&& dim : descriptor.Shape()) { - if (dim == -1) dim = 1; + if (dim == -1) { + dim = 1; + } shape.push_back(dim); size *= dim; } @@ -96,7 +98,9 @@ ILearningModelFeatureValue MakeImage(const IImageFeatureDescriptor& /*descriptor return imageValue; } -ILearningModelFeatureValue FeatureValueFromFeatureValueDescriptor(ILearningModelFeatureDescriptor descriptor, wf::IInspectable data = nullptr) { +ILearningModelFeatureValue FeatureValueFromFeatureValueDescriptor( + ILearningModelFeatureDescriptor descriptor, wf::IInspectable data = nullptr +) { auto kind = descriptor.Kind(); switch (kind) { case LearningModelFeatureKind::Image: { @@ -251,7 +255,8 @@ static void Scenario6BindWithProperties() { bounds.Height = 100; bounds.Width = 100; - auto bitmapsBoundsProperty = wf::PropertyValue::CreateUInt32Array({bounds.X, bounds.Y, bounds.Width, bounds.Height}); + auto bitmapsBoundsProperty = + wf::PropertyValue::CreateUInt32Array({bounds.X, bounds.Y, bounds.Width, bounds.Height}); // insert it in the property set propertySet.Insert(L"BitmapBounds", bitmapsBoundsProperty); @@ -354,7 +359,10 @@ static void Scenario8SetDeviceSampleMyCameraDevice() { std::wstring filePath = FileHelpers::GetModulePath() + L"model.onnx"; LearningModel model = LearningModel::LoadFromFilePath(filePath); - auto devices = winrt::Windows::Devices::Enumeration::DeviceInformation::FindAllAsync(winrt::Windows::Devices::Enumeration::DeviceClass::VideoCapture).get(); + auto devices = winrt::Windows::Devices::Enumeration::DeviceInformation::FindAllAsync( + winrt::Windows::Devices::Enumeration::DeviceClass::VideoCapture + ) + .get(); winrt::hstring deviceId; if (devices.Size() > 0) { auto device = devices.GetAt(0); @@ -385,8 +393,17 @@ static void Scenario8SetDeviceSampleD3D11Device() { winrt::com_ptr pContext = nullptr; D3D_FEATURE_LEVEL fl; HRESULT result = D3D11CreateDevice( - nullptr, D3D_DRIVER_TYPE::D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, nullptr, 0, - D3D11_SDK_VERSION, pD3D11Device.put(), &fl, pContext.put()); + nullptr, + D3D_DRIVER_TYPE::D3D_DRIVER_TYPE_HARDWARE, + nullptr, + 0, + nullptr, + 0, + D3D11_SDK_VERSION, + pD3D11Device.put(), + &fl, + pContext.put() + ); if (FAILED(result)) { WINML_SKIP_TEST("Test skipped because d3d11 device is missing"); } @@ -398,8 +415,8 @@ static void Scenario8SetDeviceSampleD3D11Device() { winrt::com_ptr<::IInspectable> pInspectable; CreateDirect3D11DeviceFromDXGIDevice(pDxgiDevice.get(), pInspectable.put()); - LearningModelDevice device = LearningModelDevice::CreateFromDirect3D11Device( - pInspectable.as()); + LearningModelDevice device = + LearningModelDevice::CreateFromDirect3D11Device(pInspectable.as()); LearningModelSession session(model, device); } @@ -417,7 +434,14 @@ static void Scenario8SetDeviceSampleCustomCommandQueue() { } HRESULT result = S_OK; if (support.has_dxgi) { - WINML_EXPECT_NO_THROW(result = D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_12_0, __uuidof(ID3D12Device), reinterpret_cast(pD3D12Device.put()))); + WINML_EXPECT_NO_THROW( + result = D3D12CreateDevice( + nullptr, + D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_12_0, + __uuidof(ID3D12Device), + reinterpret_cast(pD3D12Device.put()) + ) + ); } #ifdef ENABLE_DXCORE if (support.has_dxgi == false) { @@ -429,7 +453,14 @@ static void Scenario8SetDeviceSampleCustomCommandQueue() { winrt::com_ptr spAdapter; WINML_EXPECT_NO_THROW(spAdapterList->GetAdapter(0, IID_PPV_ARGS(spAdapter.put()))); ::IUnknown* pAdapter = spAdapter.get(); - WINML_EXPECT_NO_THROW(result = D3D12CreateDevice(pAdapter, D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_12_0, __uuidof(ID3D12Device), reinterpret_cast(pD3D12Device.put()))); + WINML_EXPECT_NO_THROW( + result = D3D12CreateDevice( + pAdapter, + D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_12_0, + __uuidof(ID3D12Device), + reinterpret_cast(pD3D12Device.put()) + ) + ); } #endif @@ -457,7 +488,9 @@ static void Scenario9LoadBindEvalInputTensorGPU() { LearningModel model = LearningModel::LoadFromFilePath(filePath); winrt::com_ptr pD3D12Device; - WINML_EXPECT_NO_THROW(D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), pD3D12Device.put_void())); + WINML_EXPECT_NO_THROW(D3D12CreateDevice( + nullptr, D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), pD3D12Device.put_void() + )); winrt::com_ptr dxQueue; D3D12_COMMAND_QUEUE_DESC commandQueueDesc = {}; commandQueueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; @@ -477,32 +510,30 @@ static void Scenario9LoadBindEvalInputTensorGPU() { UINT64 bufferbytesize = 720 * 720 * 3 * sizeof(float); D3D12_HEAP_PROPERTIES heapProperties = { - D3D12_HEAP_TYPE_DEFAULT, - D3D12_CPU_PAGE_PROPERTY_UNKNOWN, - D3D12_MEMORY_POOL_UNKNOWN, - 0, - 0}; + D3D12_HEAP_TYPE_DEFAULT, D3D12_CPU_PAGE_PROPERTY_UNKNOWN, D3D12_MEMORY_POOL_UNKNOWN, 0, 0}; D3D12_RESOURCE_DESC resourceDesc = { - D3D12_RESOURCE_DIMENSION_BUFFER, - 0, - bufferbytesize, - 1, - 1, - 1, - DXGI_FORMAT_UNKNOWN, - {1, 0}, - D3D12_TEXTURE_LAYOUT_ROW_MAJOR, - D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS}; + D3D12_RESOURCE_DIMENSION_BUFFER, + 0, + bufferbytesize, + 1, + 1, + 1, + DXGI_FORMAT_UNKNOWN, + {1, 0}, + D3D12_TEXTURE_LAYOUT_ROW_MAJOR, + D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS + }; winrt::com_ptr pGPUResource = nullptr; pD3D12Device->CreateCommittedResource( - &heapProperties, - D3D12_HEAP_FLAG_NONE, - &resourceDesc, - D3D12_RESOURCE_STATE_COMMON, - nullptr, - __uuidof(ID3D12Resource), - pGPUResource.put_void()); + &heapProperties, + D3D12_HEAP_FLAG_NONE, + &resourceDesc, + D3D12_RESOURCE_STATE_COMMON, + nullptr, + __uuidof(ID3D12Resource), + pGPUResource.put_void() + ); winrt::com_ptr<::IUnknown> spUnkTensor; TensorFloat input1imagetensor(nullptr); __int64 shape[4] = {1, 3, 720, 720}; @@ -515,9 +546,10 @@ static void Scenario9LoadBindEvalInputTensorGPU() { auto outputtensordescriptor = model.OutputFeatures().First().Current().as(); auto outputtensorshape = outputtensordescriptor.Shape(); VideoFrame outputimage( - BitmapPixelFormat::Rgba8, - static_cast(outputtensorshape.GetAt(3)), - static_cast(outputtensorshape.GetAt(2))); + BitmapPixelFormat::Rgba8, + static_cast(outputtensorshape.GetAt(3)), + static_cast(outputtensorshape.GetAt(2)) + ); ImageFeatureValue outputTensor = ImageFeatureValue::CreateFromVideoFrame(outputimage); WINML_EXPECT_NO_THROW(modelBinding.Bind(model.OutputFeatures().First().Current().Name(), outputTensor)); @@ -616,7 +648,8 @@ void SubmitEval(LearningModel model, SwapChainEntry* sessionBindings, int swapch sessionBindings[swapchaindex].binding.Bind(input.Name(), featureValue); } // submit an eval and wait for it to finish submitting work - sessionBindings[swapchaindex].activetask = sessionBindings[swapchaindex].session.EvaluateAsync(sessionBindings[swapchaindex].binding, L"0"); + sessionBindings[swapchaindex].activetask = + sessionBindings[swapchaindex].session.EvaluateAsync(sessionBindings[swapchaindex].binding, L"0"); // return without waiting for the submit to finish, setup the completion handler } @@ -662,9 +695,7 @@ static void LoadBindEval_CustomOperator_CPU(const wchar_t* fileName) { auto inputShape = std::vector{5}; auto inputData = std::vector{-50.f, -25.f, 0.f, 25.f, 50.f}; auto inputValue = - TensorFloat::CreateFromIterable( - inputShape, - winrt::single_threaded_vector(std::move(inputData)).GetView()); + TensorFloat::CreateFromIterable(inputShape, winrt::single_threaded_vector(std::move(inputData)).GetView()); WINML_EXPECT_NO_THROW(bindings.Bind(L"X", inputValue)); auto outputValue = TensorFloat::Create(); @@ -739,7 +770,7 @@ static void Scenario21RunModel2ChainZ() { std::vector shape = {1, 3, 720, 720}; auto outputValue = TensorFloat::Create(shape); // FeatureValueFromFeatureValueDescriptor(input, nullptr); - // now bind the(empty) output so we have a marker to chain with + // now bind the(empty) output so we have a marker to chain with PropertySet outputBindProperties; outputBindProperties.Insert(L"DisableTensorCpuSync", wf::PropertyValue::CreateBoolean(true)); binding1.Bind(output.Name(), outputValue, outputBindProperties); @@ -787,7 +818,8 @@ bool VerifyHelper(ImageFeatureValue actual, ImageFeatureValue expected) { UINT errors = 0; for (uint32_t i = 0; i < size; i++, pActualByte++, pExpectedByte++) { // Only the check the first three channels, which are (B, G, R) - if((i + 1) % 4 == 0) continue; + if ((i + 1) % 4 == 0) + continue; auto diff = std::abs(*pActualByte - *pExpectedByte); if (diff > epsilon) { errors++; @@ -844,9 +876,10 @@ static void Scenario22ImageBindingAsCPUTensor() { auto outputtensordescriptor = model.OutputFeatures().First().Current().as(); auto outputtensorshape = outputtensordescriptor.Shape(); VideoFrame outputimage( - BitmapPixelFormat::Bgra8, - static_cast(outputtensorshape.GetAt(3)), - static_cast(outputtensorshape.GetAt(2))); + BitmapPixelFormat::Bgra8, + static_cast(outputtensorshape.GetAt(3)), + static_cast(outputtensorshape.GetAt(2)) + ); ImageFeatureValue outputTensor = ImageFeatureValue::CreateFromVideoFrame(outputimage); WINML_EXPECT_NO_THROW(binding.Bind(model.OutputFeatures().First().Current().Name(), outputTensor)); @@ -864,7 +897,8 @@ static void Scenario22ImageBindingAsCPUTensor() { // check the output video frame object by saving output image to disk std::wstring outputDataImageFileName = L"out_cpu_tensor_fish_720.jpg"; StorageFolder currentfolder = StorageFolder::GetFolderFromPathAsync(modulePath).get(); - StorageFile outimagefile = currentfolder.CreateFileAsync(outputDataImageFileName, CreationCollisionOption::ReplaceExisting).get(); + StorageFile outimagefile = + currentfolder.CreateFileAsync(outputDataImageFileName, CreationCollisionOption::ReplaceExisting).get(); IRandomAccessStream writestream = outimagefile.OpenAsync(FileAccessMode::ReadWrite).get(); BitmapEncoder encoder = BitmapEncoder::CreateAsync(BitmapEncoder::JpegEncoderId(), writestream).get(); // Set the software bitmap @@ -911,7 +945,9 @@ static void Scenario22ImageBindingAsGPUTensor() { // create the d3d device. winrt::com_ptr pD3D12Device = nullptr; - WINML_EXPECT_NO_THROW(D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), reinterpret_cast(&pD3D12Device))); + WINML_EXPECT_NO_THROW(D3D12CreateDevice( + nullptr, D3D_FEATURE_LEVEL::D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), reinterpret_cast(&pD3D12Device) + )); // create the command queue. winrt::com_ptr dxQueue = nullptr; @@ -937,62 +973,54 @@ static void Scenario22ImageBindingAsGPUTensor() { winrt::com_ptr alloctor; winrt::com_ptr cmdList; - pD3D12Device->CreateCommandAllocator( - queuetype, - winrt::guid_of(), - alloctor.put_void()); + pD3D12Device->CreateCommandAllocator(queuetype, winrt::guid_of(), alloctor.put_void()); pD3D12Device->CreateCommandList( - 0, - queuetype, - alloctor.get(), - nullptr, - winrt::guid_of(), - cmdList.put_void()); + 0, queuetype, alloctor.get(), nullptr, winrt::guid_of(), cmdList.put_void() + ); // Create Committed Resource // 3 is number of channels we use. R G B without alpha. UINT64 bufferbytesize = 3 * sizeof(float) * softwareBitmap.PixelWidth() * softwareBitmap.PixelHeight(); D3D12_HEAP_PROPERTIES heapProperties = { - D3D12_HEAP_TYPE_DEFAULT, - D3D12_CPU_PAGE_PROPERTY_UNKNOWN, - D3D12_MEMORY_POOL_UNKNOWN, - 0, - 0}; + D3D12_HEAP_TYPE_DEFAULT, D3D12_CPU_PAGE_PROPERTY_UNKNOWN, D3D12_MEMORY_POOL_UNKNOWN, 0, 0}; D3D12_RESOURCE_DESC resourceDesc = { - D3D12_RESOURCE_DIMENSION_BUFFER, - 0, - bufferbytesize, - 1, - 1, - 1, - DXGI_FORMAT_UNKNOWN, - {1, 0}, - D3D12_TEXTURE_LAYOUT_ROW_MAJOR, - D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS}; + D3D12_RESOURCE_DIMENSION_BUFFER, + 0, + bufferbytesize, + 1, + 1, + 1, + DXGI_FORMAT_UNKNOWN, + {1, 0}, + D3D12_TEXTURE_LAYOUT_ROW_MAJOR, + D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS + }; winrt::com_ptr pGPUResource = nullptr; winrt::com_ptr imageUploadHeap; pD3D12Device->CreateCommittedResource( - &heapProperties, - D3D12_HEAP_FLAG_NONE, - &resourceDesc, - D3D12_RESOURCE_STATE_COMMON, - nullptr, - __uuidof(ID3D12Resource), - pGPUResource.put_void()); + &heapProperties, + D3D12_HEAP_FLAG_NONE, + &resourceDesc, + D3D12_RESOURCE_STATE_COMMON, + nullptr, + __uuidof(ID3D12Resource), + pGPUResource.put_void() + ); // Create the GPU upload buffer. CD3DX12_HEAP_PROPERTIES props(D3D12_HEAP_TYPE_UPLOAD); auto buffer = CD3DX12_RESOURCE_DESC::Buffer(bufferbytesize); WINML_EXPECT_NO_THROW(pD3D12Device->CreateCommittedResource( - &props, - D3D12_HEAP_FLAG_NONE, - &buffer, - D3D12_RESOURCE_STATE_GENERIC_READ, - nullptr, - __uuidof(ID3D12Resource), - imageUploadHeap.put_void())); + &props, + D3D12_HEAP_FLAG_NONE, + &buffer, + D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, + __uuidof(ID3D12Resource), + imageUploadHeap.put_void() + )); // Copy from Cpu to GPU D3D12_SUBRESOURCE_DATA CPUData = {}; @@ -1019,9 +1047,10 @@ static void Scenario22ImageBindingAsGPUTensor() { auto outputtensordescriptor = model.OutputFeatures().First().Current().as(); auto outputtensorshape = outputtensordescriptor.Shape(); VideoFrame outputimage( - BitmapPixelFormat::Rgba8, - static_cast(outputtensorshape.GetAt(3)), - static_cast(outputtensorshape.GetAt(2))); + BitmapPixelFormat::Rgba8, + static_cast(outputtensorshape.GetAt(3)), + static_cast(outputtensorshape.GetAt(2)) + ); ImageFeatureValue outputTensor = ImageFeatureValue::CreateFromVideoFrame(outputimage); WINML_EXPECT_NO_THROW(modelBinding.Bind(model.OutputFeatures().First().Current().Name(), outputTensor)); @@ -1039,7 +1068,8 @@ static void Scenario22ImageBindingAsGPUTensor() { //check the output video frame object StorageFolder currentfolder = StorageFolder::GetFolderFromPathAsync(modulePath).get(); - StorageFile outimagefile = currentfolder.CreateFileAsync(outputDataImageFileName, CreationCollisionOption::ReplaceExisting).get(); + StorageFile outimagefile = + currentfolder.CreateFileAsync(outputDataImageFileName, CreationCollisionOption::ReplaceExisting).get(); IRandomAccessStream writestream = outimagefile.OpenAsync(FileAccessMode::ReadWrite).get(); BitmapEncoder encoder = BitmapEncoder::CreateAsync(BitmapEncoder::JpegEncoderId(), writestream).get(); // Set the software bitmap @@ -1052,12 +1082,10 @@ static void Scenario23NominalPixelRange() { std::wstring inputImagePath = modulePath + L"1080.jpg"; // The following models have single op "add", with different metadata - std::vector modelPaths = { - // Normalized_0_1 and image output - modulePath + L"Add_ImageNet1920WithImageMetadataBgr8_SRGB_0_1.onnx", - // Normalized_1_1 and image output - modulePath + L"Add_ImageNet1920WithImageMetadataBgr8_SRGB_1_1.onnx" - }; + std::vector modelPaths = {// Normalized_0_1 and image output + modulePath + L"Add_ImageNet1920WithImageMetadataBgr8_SRGB_0_1.onnx", + // Normalized_1_1 and image output + modulePath + L"Add_ImageNet1920WithImageMetadataBgr8_SRGB_1_1.onnx"}; for (uint32_t model_i = 0; model_i < modelPaths.size(); model_i++) { // load model and create session @@ -1070,12 +1098,10 @@ static void Scenario23NominalPixelRange() { auto imageValue = ImageFeatureValue::CreateFromVideoFrame(videoFrame); // Create Zero tensor - auto inputShape = std::vector{ 1, 3, 1080, 1920 }; + auto inputShape = std::vector{1, 3, 1080, 1920}; auto inputData = std::vector(3 * 1080 * 1920, 0); auto zeroValue = - TensorFloat::CreateFromIterable( - inputShape, - winrt::single_threaded_vector(std::move(inputData)).GetView()); + TensorFloat::CreateFromIterable(inputShape, winrt::single_threaded_vector(std::move(inputData)).GetView()); // bind inputs binding.Bind(L"input_39", imageValue); binding.Bind(L"input_40", zeroValue); @@ -1161,9 +1187,10 @@ static void SyncVsAsync() { auto outputtensordescriptor = model.OutputFeatures().First().Current().as(); auto outputtensorshape = outputtensordescriptor.Shape(); VideoFrame outputimage( - BitmapPixelFormat::Rgba8, - static_cast(outputtensorshape.GetAt(3)), - static_cast(outputtensorshape.GetAt(2))); + BitmapPixelFormat::Rgba8, + static_cast(outputtensorshape.GetAt(3)), + static_cast(outputtensorshape.GetAt(2)) + ); ImageFeatureValue outputTensor = ImageFeatureValue::CreateFromVideoFrame(outputimage); WINML_EXPECT_NO_THROW(modelBinding.Bind(model.OutputFeatures().First().Current().Name(), outputTensor)); @@ -1172,7 +1199,8 @@ static void SyncVsAsync() { for (UINT i = 0; i < N; i++) { session.Evaluate(modelBinding, L""); } - auto syncTime = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - startSync); + auto syncTime = + std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - startSync); std::cout << "Synchronous time for " << N << " evaluations: " << syncTime.count() << " milliseconds\n"; // evaluate N times Asynchronously and time it @@ -1183,10 +1211,13 @@ static void SyncVsAsync() { bindings[i] = LearningModelBinding(session); bindings[i].Bind(inputFeatureDescriptor.Current().Name(), imagetensor); bindings[i].Bind( - model.OutputFeatures().First().Current().Name(), - VideoFrame(BitmapPixelFormat::Rgba8, - static_cast(outputtensorshape.GetAt(3)), - static_cast(outputtensorshape.GetAt(2)))); + model.OutputFeatures().First().Current().Name(), + VideoFrame( + BitmapPixelFormat::Rgba8, + static_cast(outputtensorshape.GetAt(3)), + static_cast(outputtensorshape.GetAt(2)) + ) + ); } auto startAsync = std::chrono::high_resolution_clock::now(); @@ -1197,7 +1228,8 @@ static void SyncVsAsync() { for (auto&& task : tasks) { task.get(); } - auto asyncTime = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - startAsync); + auto asyncTime = + std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - startAsync); std::cout << "Asynchronous time for " << N << " evaluations: " << asyncTime.count() << " milliseconds\n"; } @@ -1206,21 +1238,29 @@ static void CustomCommandQueueWithFence() { static const wchar_t* const inputDataImageFileName = L"fish_720.png"; winrt::com_ptr d3d12Device; - WINML_EXPECT_HRESULT_SUCCEEDED(D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), d3d12Device.put_void())); + WINML_EXPECT_HRESULT_SUCCEEDED( + D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), d3d12Device.put_void()) + ); D3D12_COMMAND_QUEUE_DESC queueDesc = {}; queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; winrt::com_ptr queue; - WINML_EXPECT_HRESULT_SUCCEEDED(d3d12Device->CreateCommandQueue(&queueDesc, __uuidof(ID3D12CommandQueue), queue.put_void())); + WINML_EXPECT_HRESULT_SUCCEEDED( + d3d12Device->CreateCommandQueue(&queueDesc, __uuidof(ID3D12CommandQueue), queue.put_void()) + ); winrt::com_ptr fence; - WINML_EXPECT_HRESULT_SUCCEEDED(d3d12Device->CreateFence(0, D3D12_FENCE_FLAG_NONE, __uuidof(ID3D12Fence), fence.put_void())); + WINML_EXPECT_HRESULT_SUCCEEDED( + d3d12Device->CreateFence(0, D3D12_FENCE_FLAG_NONE, __uuidof(ID3D12Fence), fence.put_void()) + ); auto devicefactory = winrt::get_activation_factory(); winrt::com_ptr<::IUnknown> learningModelDeviceUnknown; - WINML_EXPECT_HRESULT_SUCCEEDED(devicefactory->CreateFromD3D12CommandQueue(queue.get(), learningModelDeviceUnknown.put())); + WINML_EXPECT_HRESULT_SUCCEEDED( + devicefactory->CreateFromD3D12CommandQueue(queue.get(), learningModelDeviceUnknown.put()) + ); LearningModelDevice device = nullptr; WINML_EXPECT_NO_THROW(learningModelDeviceUnknown.as(device)); @@ -1250,9 +1290,10 @@ static void CustomCommandQueueWithFence() { auto outputtensordescriptor = model.OutputFeatures().First().Current().as(); auto outputtensorshape = outputtensordescriptor.Shape(); VideoFrame outputimage( - BitmapPixelFormat::Rgba8, - static_cast(outputtensorshape.GetAt(3)), - static_cast(outputtensorshape.GetAt(2))); + BitmapPixelFormat::Rgba8, + static_cast(outputtensorshape.GetAt(3)), + static_cast(outputtensorshape.GetAt(2)) + ); ImageFeatureValue outputTensor = ImageFeatureValue::CreateFromVideoFrame(outputimage); WINML_EXPECT_NO_THROW(modelBinding.Bind(model.OutputFeatures().First().Current().Name(), outputTensor)); @@ -1311,7 +1352,8 @@ static void ReuseVideoFrame() { if (videoFrameSource == "SoftwareBitmap") { reuseVideoFrame = VideoFrame::CreateWithSoftwareBitmap(SoftwareBitmap(BitmapPixelFormat::Bgra8, 720, 720)); } else { - reuseVideoFrame = VideoFrame::CreateAsDirect3D11SurfaceBacked(DirectXPixelFormat::B8G8R8X8UIntNormalized, 720, 720); + reuseVideoFrame = + VideoFrame::CreateAsDirect3D11SurfaceBacked(DirectXPixelFormat::B8G8R8X8UIntNormalized, 720, 720); } for (uint32_t i = 0; i < 3; ++i) { SoftwareBitmap softwareBitmap = FileHelpers::GetSoftwareBitmapFromFile(inputImagePath); @@ -1349,30 +1391,35 @@ static void EncryptedStream() { // encrypt auto algorithmName = winrt::Windows::Security::Cryptography::Core::SymmetricAlgorithmNames::AesCbcPkcs7(); - auto algorithm = winrt::Windows::Security::Cryptography::Core::SymmetricKeyAlgorithmProvider::OpenAlgorithm(algorithmName); + auto algorithm = + winrt::Windows::Security::Cryptography::Core::SymmetricKeyAlgorithmProvider::OpenAlgorithm(algorithmName); uint32_t keyLength = 32; auto keyBuffer = winrt::Windows::Security::Cryptography::CryptographicBuffer::GenerateRandom(keyLength); auto key = algorithm.CreateSymmetricKey(keyBuffer); auto iv = winrt::Windows::Security::Cryptography::CryptographicBuffer::GenerateRandom(algorithm.BlockLength()); - auto encryptedBuffer = winrt::Windows::Security::Cryptography::Core::CryptographicEngine::Encrypt(key, fileBuffer, iv); + auto encryptedBuffer = + winrt::Windows::Security::Cryptography::Core::CryptographicEngine::Encrypt(key, fileBuffer, iv); // verify loading the encrypted stream fails appropriately. auto encryptedStream = InMemoryRandomAccessStream(); encryptedStream.WriteAsync(encryptedBuffer).get(); - WINML_EXPECT_THROW_SPECIFIC(LearningModel::LoadFromStream(RandomAccessStreamReference::CreateFromStream(encryptedStream)), - winrt::hresult_error, - [](const winrt::hresult_error& e) -> bool { - return e.code() == E_INVALIDARG; - }); + WINML_EXPECT_THROW_SPECIFIC( + LearningModel::LoadFromStream(RandomAccessStreamReference::CreateFromStream(encryptedStream)), + winrt::hresult_error, + [](const winrt::hresult_error& e) -> bool { return e.code() == E_INVALIDARG; } + ); // now decrypt - auto decryptedBuffer = winrt::Windows::Security::Cryptography::Core::CryptographicEngine::Decrypt(key, encryptedBuffer, iv); + auto decryptedBuffer = + winrt::Windows::Security::Cryptography::Core::CryptographicEngine::Decrypt(key, encryptedBuffer, iv); auto decryptedStream = InMemoryRandomAccessStream(); decryptedStream.WriteAsync(decryptedBuffer).get(); // load! LearningModel model = nullptr; - WINML_EXPECT_NO_THROW(model = LearningModel::LoadFromStream(RandomAccessStreamReference::CreateFromStream(decryptedStream))); + WINML_EXPECT_NO_THROW( + model = LearningModel::LoadFromStream(RandomAccessStreamReference::CreateFromStream(decryptedStream)) + ); LearningModelSession session = nullptr; WINML_EXPECT_NO_THROW(session = LearningModelSession(model)); } @@ -1419,12 +1466,16 @@ static void D2DInterop() { LearningModel model = LearningModel::LoadFromFilePath(filePath); // create a dx12 device winrt::com_ptr device = nullptr; - WINML_EXPECT_HRESULT_SUCCEEDED(D3D12CreateDevice(NULL, D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device1), device.put_void())); + WINML_EXPECT_HRESULT_SUCCEEDED( + D3D12CreateDevice(NULL, D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device1), device.put_void()) + ); // now create a command queue from it winrt::com_ptr commandQueue = nullptr; D3D12_COMMAND_QUEUE_DESC queueDesc = {}; queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; - WINML_EXPECT_HRESULT_SUCCEEDED(device->CreateCommandQueue(&queueDesc, winrt::guid_of(), commandQueue.put_void())); + WINML_EXPECT_HRESULT_SUCCEEDED( + device->CreateCommandQueue(&queueDesc, winrt::guid_of(), commandQueue.put_void()) + ); // create a winml learning device based on that dx12 queue auto factory = winrt::get_activation_factory(); winrt::com_ptr<::IUnknown> spUnk; @@ -1434,28 +1485,25 @@ static void D2DInterop() { LearningModelSession session(model, learningDevice); // now lets try and do some XAML/d2d on that same device, first prealloc a VideoFrame VideoFrame frame = VideoFrame::CreateAsDirect3D11SurfaceBacked( - DirectXPixelFormat::B8G8R8A8UIntNormalized, - 224, - 224, - session.Device().Direct3D11Device()); + DirectXPixelFormat::B8G8R8A8UIntNormalized, 224, 224, session.Device().Direct3D11Device() + ); // create a D2D factory D2D1_FACTORY_OPTIONS options = {}; winrt::com_ptr d2dFactory; - WINML_EXPECT_HRESULT_SUCCEEDED(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory), &options, d2dFactory.put_void())); + WINML_EXPECT_HRESULT_SUCCEEDED( + D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory), &options, d2dFactory.put_void()) + ); // grab the dxgi surface back from our video frame winrt::com_ptr dxgiSurface; - winrt::com_ptr dxgiInterfaceAccess = frame.Direct3DSurface().as(); + winrt::com_ptr dxgiInterfaceAccess = + frame.Direct3DSurface().as(); WINML_EXPECT_HRESULT_SUCCEEDED(dxgiInterfaceAccess->GetInterface(__uuidof(IDXGISurface), dxgiSurface.put_void())); // and try and use our surface to create a render targer winrt::com_ptr renderTarget; D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(); - props.pixelFormat = D2D1::PixelFormat( - DXGI_FORMAT_B8G8R8A8_UNORM, - D2D1_ALPHA_MODE_IGNORE); - WINML_EXPECT_HRESULT_SUCCEEDED(d2dFactory->CreateDxgiSurfaceRenderTarget( - dxgiSurface.get(), - props, - renderTarget.put())); + props.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE); + WINML_EXPECT_HRESULT_SUCCEEDED(d2dFactory->CreateDxgiSurfaceRenderTarget(dxgiSurface.get(), props, renderTarget.put()) + ); } static void BindMultipleCPUBuffersAsInputs(LearningModelDeviceKind kind) { @@ -1525,7 +1573,7 @@ static void BindMultipleCPUBuffersAsInputs(LearningModelDeviceKind kind) { buffers.Append(wss::Buffer::CreateCopyFromMemoryBuffer(red)); buffers.Append(wss::Buffer::CreateCopyFromMemoryBuffer(green)); buffers.Append(wss::Buffer::CreateCopyFromMemoryBuffer(blue)); - + // Bind input binding.Bind(model.InputFeatures().First().Current().Name(), buffers); @@ -1533,13 +1581,11 @@ static void BindMultipleCPUBuffersAsInputs(LearningModelDeviceKind kind) { auto output_descriptor = model.OutputFeatures().First().Current().as(); auto output_shape = output_descriptor.Shape(); VideoFrame outputimage1( - BitmapPixelFormat::Bgra8, - static_cast(output_shape.GetAt(3)), - static_cast(output_shape.GetAt(2))); + BitmapPixelFormat::Bgra8, static_cast(output_shape.GetAt(3)), static_cast(output_shape.GetAt(2)) + ); VideoFrame outputimage2( - BitmapPixelFormat::Bgra8, - static_cast(output_shape.GetAt(3)), - static_cast(output_shape.GetAt(2))); + BitmapPixelFormat::Bgra8, static_cast(output_shape.GetAt(3)), static_cast(output_shape.GetAt(2)) + ); auto output_frames = winrt::single_threaded_vector(); output_frames.Append(outputimage1); @@ -1561,7 +1607,8 @@ static void BindMultipleCPUBuffersAsInputs(LearningModelDeviceKind kind) { // check the output video frame object by saving output image to disk std::wstring output_filename = L"out_cpu_tensor_fish_720.jpg"; StorageFolder current_folder = StorageFolder::GetFolderFromPathAsync(module_path).get(); - StorageFile output_file = current_folder.CreateFileAsync(output_filename, CreationCollisionOption::ReplaceExisting).get(); + StorageFile output_file = + current_folder.CreateFileAsync(output_filename, CreationCollisionOption::ReplaceExisting).get(); IRandomAccessStream output_stream = output_file.OpenAsync(FileAccessMode::ReadWrite).get(); BitmapEncoder encoder = BitmapEncoder::CreateAsync(BitmapEncoder::JpegEncoderId(), output_stream).get(); // Set the software bitmap @@ -1627,7 +1674,7 @@ static void BindMultipleCPUBuffersAsOutputs(LearningModelDeviceKind kind) { red_buffer.try_as<::Windows::Storage::Streams::IBufferByteAccess>()->Buffer(reinterpret_cast(&red_bytes)); green_buffer.try_as<::Windows::Storage::Streams::IBufferByteAccess>()->Buffer(reinterpret_cast(&green_bytes)); blue_buffer.try_as<::Windows::Storage::Streams::IBufferByteAccess>()->Buffer(reinterpret_cast(&blue_bytes)); - + // Verify the output by comparing with the benchmark image SoftwareBitmap benchmark_bitmap = FileHelpers::GetSoftwareBitmapFromFile(bmImagePath); benchmark_bitmap = SoftwareBitmap::Convert(benchmark_bitmap, BitmapPixelFormat::Bgra8); @@ -1638,12 +1685,12 @@ static void BindMultipleCPUBuffersAsOutputs(LearningModelDeviceKind kind) { wf::IMemoryBufferReference benchmark_reference = benchmark_bitmap_buffer.CreateReference(); auto benchmark_byte_access = benchmark_reference.as<::Windows::Foundation::IMemoryBufferByteAccess>(); benchmark_byte_access->GetBuffer(&benchmark_data, &benchmark_size); - + // hard code, might need to be modified later. const float cMaxErrorRate = 0.06f; byte epsilon = 20; UINT errors = 0; - for (UINT32 i = 0; i < height * width; i ++) { + for (UINT32 i = 0; i < height * width; i++) { if (std::abs(red_bytes[i] - benchmark_data[i * 4]) > epsilon) { errors++; } @@ -1655,15 +1702,16 @@ static void BindMultipleCPUBuffersAsOutputs(LearningModelDeviceKind kind) { } } auto total_size = height * width * 3; - std::cout << "total errors is " << errors << "/" << total_size << ", errors rate is " << (float)errors / total_size << "\n"; + std::cout << "total errors is " << errors << "/" << total_size << ", errors rate is " << (float)errors / total_size + << "\n"; WINML_EXPECT_TRUE((float)errors / total_size < cMaxErrorRate); - // check the output video frame object by saving output image to disk std::wstring outputDataImageFileName = L"out_cpu_tensor_fish_720.jpg"; StorageFolder currentfolder = StorageFolder::GetFolderFromPathAsync(modulePath).get(); - StorageFile outimagefile = currentfolder.CreateFileAsync(outputDataImageFileName, CreationCollisionOption::ReplaceExisting).get(); + StorageFile outimagefile = + currentfolder.CreateFileAsync(outputDataImageFileName, CreationCollisionOption::ReplaceExisting).get(); IRandomAccessStream writestream = outimagefile.OpenAsync(FileAccessMode::ReadWrite).get(); BitmapEncoder encoder = BitmapEncoder::CreateAsync(BitmapEncoder::JpegEncoderId(), writestream).get(); // Set the software bitmap @@ -1680,49 +1728,48 @@ static void BindMultipleCPUBuffersOutputsOnGpu() { } const ScenarioTestsApi& getapi() { - static ScenarioTestsApi api = - { - ScenarioCppWinrtTestsClassSetup, - Sample1, - Scenario1LoadBindEvalDefault, - Scenario2LoadModelFromStream, - Scenario5AsyncEval, - Scenario7EvalWithNoBind, - Scenario8SetDeviceSampleDefault, - Scenario8SetDeviceSampleCPU, - Scenario17DevDiagnostics, - Scenario22ImageBindingAsCPUTensor, - Scenario23NominalPixelRange, - QuantizedModels, - EncryptedStream, - Scenario3SoftwareBitmapInputBinding, - Scenario6BindWithProperties, - Scenario8SetDeviceSampleDefaultDirectX, - Scenario8SetDeviceSampleMinPower, - Scenario8SetDeviceSampleMaxPerf, - Scenario8SetDeviceSampleMyCameraDevice, - Scenario8SetDeviceSampleCustomCommandQueue, - Scenario9LoadBindEvalInputTensorGPU, - Scenario13SingleModelOnCPUandGPU, - Scenario11FreeDimensionsTensor, - Scenario11FreeDimensionsImage, - Scenario14RunModelSwapchain, - Scenario20aLoadBindEvalCustomOperatorCPU, - Scenario20bLoadBindEvalReplacementCustomOperatorCPU, - Scenario21RunModel2ChainZ, - Scenario22ImageBindingAsGPUTensor, - MsftQuantizedModels, - SyncVsAsync, - CustomCommandQueueWithFence, - ReuseVideoFrame, - DeviceLostRecovery, - Scenario8SetDeviceSampleD3D11Device, - D2DInterop, - BindMultipleCPUBuffersInputsOnCpu, - BindMultipleCPUBuffersInputsOnGpu, - BindMultipleCPUBuffersOutputsOnCpu, - BindMultipleCPUBuffersOutputsOnGpu, - }; + static ScenarioTestsApi api = { + ScenarioCppWinrtTestsClassSetup, + Sample1, + Scenario1LoadBindEvalDefault, + Scenario2LoadModelFromStream, + Scenario5AsyncEval, + Scenario7EvalWithNoBind, + Scenario8SetDeviceSampleDefault, + Scenario8SetDeviceSampleCPU, + Scenario17DevDiagnostics, + Scenario22ImageBindingAsCPUTensor, + Scenario23NominalPixelRange, + QuantizedModels, + EncryptedStream, + Scenario3SoftwareBitmapInputBinding, + Scenario6BindWithProperties, + Scenario8SetDeviceSampleDefaultDirectX, + Scenario8SetDeviceSampleMinPower, + Scenario8SetDeviceSampleMaxPerf, + Scenario8SetDeviceSampleMyCameraDevice, + Scenario8SetDeviceSampleCustomCommandQueue, + Scenario9LoadBindEvalInputTensorGPU, + Scenario13SingleModelOnCPUandGPU, + Scenario11FreeDimensionsTensor, + Scenario11FreeDimensionsImage, + Scenario14RunModelSwapchain, + Scenario20aLoadBindEvalCustomOperatorCPU, + Scenario20bLoadBindEvalReplacementCustomOperatorCPU, + Scenario21RunModel2ChainZ, + Scenario22ImageBindingAsGPUTensor, + MsftQuantizedModels, + SyncVsAsync, + CustomCommandQueueWithFence, + ReuseVideoFrame, + DeviceLostRecovery, + Scenario8SetDeviceSampleD3D11Device, + D2DInterop, + BindMultipleCPUBuffersInputsOnCpu, + BindMultipleCPUBuffersInputsOnGpu, + BindMultipleCPUBuffersOutputsOnCpu, + BindMultipleCPUBuffersOutputsOnGpu, + }; if (SkipGpuTests()) { api.Scenario6BindWithProperties = SkipTest; diff --git a/winml/test/scenario/cppwinrt/scenariotestscppwinrt.h b/winml/test/scenario/cppwinrt/scenariotestscppwinrt.h index d1220501b7e11..2b6778aeb8cf5 100644 --- a/winml/test/scenario/cppwinrt/scenariotestscppwinrt.h +++ b/winml/test/scenario/cppwinrt/scenariotestscppwinrt.h @@ -2,48 +2,47 @@ // Licensed under the MIT License. #include "test.h" -struct ScenarioTestsApi -{ - SetupClass ScenarioCppWinrtTestsClassSetup; - VoidTest Sample1; - VoidTest Scenario1LoadBindEvalDefault; - VoidTest Scenario2LoadModelFromStream; - VoidTest Scenario5AsyncEval; - VoidTest Scenario7EvalWithNoBind; - VoidTest Scenario8SetDeviceSampleDefault; - VoidTest Scenario8SetDeviceSampleCPU; - VoidTest Scenario17DevDiagnostics; - VoidTest Scenario22ImageBindingAsCPUTensor; - VoidTest Scenario23NominalPixelRange; - VoidTest QuantizedModels; - VoidTest EncryptedStream; - VoidTest Scenario3SoftwareBitmapInputBinding; - VoidTest Scenario6BindWithProperties; - VoidTest Scenario8SetDeviceSampleDefaultDirectX; - VoidTest Scenario8SetDeviceSampleMinPower; - VoidTest Scenario8SetDeviceSampleMaxPerf; - VoidTest Scenario8SetDeviceSampleMyCameraDevice; - VoidTest Scenario8SetDeviceSampleCustomCommandQueue; - VoidTest Scenario9LoadBindEvalInputTensorGPU; - VoidTest Scenario13SingleModelOnCPUandGPU; - VoidTest Scenario11FreeDimensionsTensor; - VoidTest Scenario11FreeDimensionsImage; - VoidTest Scenario14RunModelSwapchain; - VoidTest Scenario20aLoadBindEvalCustomOperatorCPU; - VoidTest Scenario20bLoadBindEvalReplacementCustomOperatorCPU; - VoidTest Scenario21RunModel2ChainZ; - VoidTest Scenario22ImageBindingAsGPUTensor; - VoidTest MsftQuantizedModels; - VoidTest SyncVsAsync; - VoidTest CustomCommandQueueWithFence; - VoidTest ReuseVideoFrame; - VoidTest DeviceLostRecovery; - VoidTest Scenario8SetDeviceSampleD3D11Device; - VoidTest D2DInterop; - VoidTest BindMultipleCPUBuffersInputsOnCpu; - VoidTest BindMultipleCPUBuffersInputsOnGpu; - VoidTest BindMultipleCPUBuffersOutputsOnCpu; - VoidTest BindMultipleCPUBuffersOutputsOnGpu; +struct ScenarioTestsApi { + SetupClass ScenarioCppWinrtTestsClassSetup; + VoidTest Sample1; + VoidTest Scenario1LoadBindEvalDefault; + VoidTest Scenario2LoadModelFromStream; + VoidTest Scenario5AsyncEval; + VoidTest Scenario7EvalWithNoBind; + VoidTest Scenario8SetDeviceSampleDefault; + VoidTest Scenario8SetDeviceSampleCPU; + VoidTest Scenario17DevDiagnostics; + VoidTest Scenario22ImageBindingAsCPUTensor; + VoidTest Scenario23NominalPixelRange; + VoidTest QuantizedModels; + VoidTest EncryptedStream; + VoidTest Scenario3SoftwareBitmapInputBinding; + VoidTest Scenario6BindWithProperties; + VoidTest Scenario8SetDeviceSampleDefaultDirectX; + VoidTest Scenario8SetDeviceSampleMinPower; + VoidTest Scenario8SetDeviceSampleMaxPerf; + VoidTest Scenario8SetDeviceSampleMyCameraDevice; + VoidTest Scenario8SetDeviceSampleCustomCommandQueue; + VoidTest Scenario9LoadBindEvalInputTensorGPU; + VoidTest Scenario13SingleModelOnCPUandGPU; + VoidTest Scenario11FreeDimensionsTensor; + VoidTest Scenario11FreeDimensionsImage; + VoidTest Scenario14RunModelSwapchain; + VoidTest Scenario20aLoadBindEvalCustomOperatorCPU; + VoidTest Scenario20bLoadBindEvalReplacementCustomOperatorCPU; + VoidTest Scenario21RunModel2ChainZ; + VoidTest Scenario22ImageBindingAsGPUTensor; + VoidTest MsftQuantizedModels; + VoidTest SyncVsAsync; + VoidTest CustomCommandQueueWithFence; + VoidTest ReuseVideoFrame; + VoidTest DeviceLostRecovery; + VoidTest Scenario8SetDeviceSampleD3D11Device; + VoidTest D2DInterop; + VoidTest BindMultipleCPUBuffersInputsOnCpu; + VoidTest BindMultipleCPUBuffersInputsOnGpu; + VoidTest BindMultipleCPUBuffersOutputsOnCpu; + VoidTest BindMultipleCPUBuffersOutputsOnGpu; }; const ScenarioTestsApi& getapi();